From aff437667b93c3d65576b02628885687c72e1b3b Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Fri, 24 Oct 2014 12:42:33 +0100 Subject: drm/i915: Move flags describing VMA mappings into the VMA If these flags are on the object level it will be more difficult to allow for multiple VMAs per object. v2: Simplification and cleanup after code review comments (Chris Wilson). Signed-off-by: Tvrtko Ursulin Cc: Chris Wilson Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 2 +- drivers/gpu/drm/i915/i915_drv.h | 2 -- drivers/gpu/drm/i915/i915_gem.c | 4 ++-- drivers/gpu/drm/i915/i915_gem_context.c | 10 +++++----- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 9 +++------ drivers/gpu/drm/i915/i915_gem_gtt.c | 24 ++++++++++++------------ drivers/gpu/drm/i915/i915_gem_gtt.h | 8 ++++++-- drivers/gpu/drm/i915/i915_gem_stolen.c | 2 +- drivers/gpu/drm/i915/i915_gpu_error.c | 10 ++++++---- 9 files changed, 36 insertions(+), 35 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index e60d5c2f4a35..61ea8da93c3b 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -116,7 +116,7 @@ static const char *get_tiling_flag(struct drm_i915_gem_object *obj) static inline const char *get_global_flag(struct drm_i915_gem_object *obj) { - return obj->has_global_gtt_mapping ? "g" : " "; + return i915_gem_obj_to_ggtt(obj) ? "g" : " "; } static void diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 583c97debeb7..627b7e71f168 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1856,8 +1856,6 @@ struct drm_i915_gem_object { unsigned long gt_ro:1; unsigned int cache_level:3; - unsigned int has_aliasing_ppgtt_mapping:1; - unsigned int has_global_gtt_mapping:1; unsigned int has_dma_mapping:1; unsigned int frontbuffer_bits:INTEL_FRONTBUFFER_BITS; diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 827edb589883..7e919784b112 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3701,7 +3701,7 @@ int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj, list_for_each_entry(vma, &obj->vma_list, vma_link) if (drm_mm_node_allocated(&vma->node)) vma->bind_vma(vma, cache_level, - obj->has_global_gtt_mapping ? GLOBAL_BIND : 0); + vma->bound & GLOBAL_BIND); } list_for_each_entry(vma, &obj->vma_list, vma_link) @@ -4097,7 +4097,7 @@ i915_gem_object_pin(struct drm_i915_gem_object *obj, return PTR_ERR(vma); } - if (flags & PIN_GLOBAL && !obj->has_global_gtt_mapping) + if (flags & PIN_GLOBAL && !(vma->bound & GLOBAL_BIND)) vma->bind_vma(vma, obj->cache_level, GLOBAL_BIND); vma->pin_count++; diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index a5221d8f1580..7d3257111737 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -522,6 +522,7 @@ static int do_switch(struct intel_engine_cs *ring, struct intel_context *from = ring->last_context; u32 hw_flags = 0; bool uninitialized = false; + struct i915_vma *vma; int ret, i; if (from != NULL && ring == &dev_priv->ring[RCS]) { @@ -571,11 +572,10 @@ static int do_switch(struct intel_engine_cs *ring, if (ret) goto unpin_out; - if (!to->legacy_hw_ctx.rcs_state->has_global_gtt_mapping) { - struct i915_vma *vma = i915_gem_obj_to_vma(to->legacy_hw_ctx.rcs_state, - &dev_priv->gtt.base); - vma->bind_vma(vma, to->legacy_hw_ctx.rcs_state->cache_level, GLOBAL_BIND); - } + vma = i915_gem_obj_to_ggtt(to->legacy_hw_ctx.rcs_state); + if (!(vma->bound & GLOBAL_BIND)) + vma->bind_vma(vma, to->legacy_hw_ctx.rcs_state->cache_level, + GLOBAL_BIND); if (!to->legacy_hw_ctx.initialized || i915_gem_context_is_default(to)) hw_flags |= MI_RESTORE_INHIBIT; diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 1a0611bb576b..c70b329b07cd 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -357,12 +357,9 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj, * through the ppgtt for non_secure batchbuffers. */ if (unlikely(IS_GEN6(dev) && reloc->write_domain == I915_GEM_DOMAIN_INSTRUCTION && - !target_i915_obj->has_global_gtt_mapping)) { - struct i915_vma *vma = - list_first_entry(&target_i915_obj->vma_list, - typeof(*vma), vma_link); - vma->bind_vma(vma, target_i915_obj->cache_level, GLOBAL_BIND); - } + !(target_vma->bound & GLOBAL_BIND))) + target_vma->bind_vma(target_vma, target_i915_obj->cache_level, + GLOBAL_BIND); /* Validate that the target is in a valid r/w GPU domain */ if (unlikely(reloc->write_domain & (reloc->write_domain - 1))) { diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index ae82ef5e7df4..cb7adabc4e44 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -1336,7 +1336,7 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev) * Unfortunately above, we've just wiped out the mappings * without telling our object about it. So we need to fake it. */ - obj->has_global_gtt_mapping = 0; + vma->bound &= ~GLOBAL_BIND; vma->bind_vma(vma, obj->cache_level, GLOBAL_BIND); } @@ -1533,7 +1533,7 @@ static void i915_ggtt_bind_vma(struct i915_vma *vma, BUG_ON(!i915_is_ggtt(vma->vm)); intel_gtt_insert_sg_entries(vma->obj->pages, entry, flags); - vma->obj->has_global_gtt_mapping = 1; + vma->bound = GLOBAL_BIND; } static void i915_ggtt_clear_range(struct i915_address_space *vm, @@ -1552,7 +1552,7 @@ static void i915_ggtt_unbind_vma(struct i915_vma *vma) const unsigned int size = vma->obj->base.size >> PAGE_SHIFT; BUG_ON(!i915_is_ggtt(vma->vm)); - vma->obj->has_global_gtt_mapping = 0; + vma->bound = 0; intel_gtt_clear_range(first, size); } @@ -1580,24 +1580,24 @@ static void ggtt_bind_vma(struct i915_vma *vma, * flags. At all other times, the GPU will use the aliasing PPGTT. */ if (!dev_priv->mm.aliasing_ppgtt || flags & GLOBAL_BIND) { - if (!obj->has_global_gtt_mapping || + if (!(vma->bound & GLOBAL_BIND) || (cache_level != obj->cache_level)) { vma->vm->insert_entries(vma->vm, obj->pages, vma->node.start, cache_level, flags); - obj->has_global_gtt_mapping = 1; + vma->bound |= GLOBAL_BIND; } } if (dev_priv->mm.aliasing_ppgtt && - (!obj->has_aliasing_ppgtt_mapping || + (!(vma->bound & LOCAL_BIND) || (cache_level != obj->cache_level))) { struct i915_hw_ppgtt *appgtt = dev_priv->mm.aliasing_ppgtt; appgtt->base.insert_entries(&appgtt->base, vma->obj->pages, vma->node.start, cache_level, flags); - vma->obj->has_aliasing_ppgtt_mapping = 1; + vma->bound |= LOCAL_BIND; } } @@ -1607,21 +1607,21 @@ static void ggtt_unbind_vma(struct i915_vma *vma) struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj = vma->obj; - if (obj->has_global_gtt_mapping) { + if (vma->bound & GLOBAL_BIND) { vma->vm->clear_range(vma->vm, vma->node.start, obj->base.size, true); - obj->has_global_gtt_mapping = 0; + vma->bound &= ~GLOBAL_BIND; } - if (obj->has_aliasing_ppgtt_mapping) { + if (vma->bound & LOCAL_BIND) { struct i915_hw_ppgtt *appgtt = dev_priv->mm.aliasing_ppgtt; appgtt->base.clear_range(&appgtt->base, vma->node.start, obj->base.size, true); - obj->has_aliasing_ppgtt_mapping = 0; + vma->bound &= ~LOCAL_BIND; } } @@ -1699,7 +1699,7 @@ int i915_gem_setup_global_gtt(struct drm_device *dev, DRM_DEBUG_KMS("Reservation failed: %i\n", ret); return ret; } - obj->has_global_gtt_mapping = 1; + vma->bound |= GLOBAL_BIND; } dev_priv->gtt.base.start = start; diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h index d5c14af51e99..d0562d0ef6ec 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.h +++ b/drivers/gpu/drm/i915/i915_gem_gtt.h @@ -123,6 +123,12 @@ struct i915_vma { struct drm_i915_gem_object *obj; struct i915_address_space *vm; + /** Flags and address space this VMA is bound to */ +#define GLOBAL_BIND (1<<0) +#define LOCAL_BIND (1<<1) +#define PTE_READ_ONLY (1<<2) + unsigned int bound : 4; + /** This object's place on the active/inactive lists */ struct list_head mm_list; @@ -155,8 +161,6 @@ struct i915_vma { * setting the valid PTE entries to a reserved scratch page. */ void (*unbind_vma)(struct i915_vma *vma); /* Map an object into an address space with the given cache flags. */ -#define GLOBAL_BIND (1<<0) -#define PTE_READ_ONLY (1<<1) void (*bind_vma)(struct i915_vma *vma, enum i915_cache_level cache_level, u32 flags); diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c b/drivers/gpu/drm/i915/i915_gem_stolen.c index 85fda6b803e4..c38891892547 100644 --- a/drivers/gpu/drm/i915/i915_gem_stolen.c +++ b/drivers/gpu/drm/i915/i915_gem_stolen.c @@ -533,7 +533,7 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev, } } - obj->has_global_gtt_mapping = 1; + vma->bound |= GLOBAL_BIND; list_add_tail(&obj->global_list, &dev_priv->mm.bound_list); list_add_tail(&vma->mm_list, &ggtt->inactive_list); diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index e664599de6e7..d17360bc1cd1 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -565,6 +565,7 @@ i915_error_object_create(struct drm_i915_private *dev_priv, struct i915_address_space *vm) { struct drm_i915_error_object *dst; + struct i915_vma *vma = NULL; int num_pages; bool use_ggtt; int i = 0; @@ -585,16 +586,17 @@ i915_error_object_create(struct drm_i915_private *dev_priv, dst->gtt_offset = -1; reloc_offset = dst->gtt_offset; + if (i915_is_ggtt(vm)) + vma = i915_gem_obj_to_ggtt(src); use_ggtt = (src->cache_level == I915_CACHE_NONE && - i915_is_ggtt(vm) && - src->has_global_gtt_mapping && - reloc_offset + num_pages * PAGE_SIZE <= dev_priv->gtt.mappable_end); + vma && (vma->bound & GLOBAL_BIND) && + reloc_offset + num_pages * PAGE_SIZE <= dev_priv->gtt.mappable_end); /* Cannot access stolen address directly, try to use the aperture */ if (src->stolen) { use_ggtt = true; - if (!src->has_global_gtt_mapping) + if (!(vma && vma->bound & GLOBAL_BIND)) goto unwind; reloc_offset = i915_gem_obj_ggtt_offset(src); -- cgit v1.2.3 From a919db9015832d7e4140a38e20ddc1c305c95cb2 Mon Sep 17 00:00:00 2001 From: Sonika Jindal Date: Thu, 23 Oct 2014 07:41:33 -0700 Subject: drm/i915: Update plane parameters for cursor plane (v2) This allows the cursor plane to be updated the same way as primary and sprites, and same set_property handler is used for all of these planes. v2 (by Matt Roper): Rework to apply to latest di-nightly codebase. The switch to split check/commit plane programming changed the code flow enough that the original patch could no longer be applied. Signed-off-by: Sonika Jindal Reviewed-by: Matt Roper Tested-by (IVB): Matt Roper Signed-off-by: Matt Roper Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 1d2fa7f4523e..910e8a4603fa 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11955,12 +11955,24 @@ intel_commit_cursor_plane(struct drm_plane *plane, struct drm_crtc *crtc = state->crtc; struct drm_framebuffer *fb = state->fb; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_plane *intel_plane = to_intel_plane(plane); struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); struct drm_i915_gem_object *obj = intel_fb->obj; int crtc_w, crtc_h; 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); + intel_plane->obj = obj; + if (fb != crtc->cursor->fb) { crtc_w = drm_rect_width(&state->orig_dst); crtc_h = drm_rect_height(&state->orig_dst); -- cgit v1.2.3 From 42c7156af94783ff42edba6a3b07a51d35552c60 Mon Sep 17 00:00:00 2001 From: Brad Volkin Date: Thu, 16 Oct 2014 12:24:42 -0700 Subject: drm/i915: Abort command parsing for chained batches libva uses chained batch buffers in a way that the command parser can't generally handle. Fortunately, libva doesn't need to write registers from batch buffers in the way that mesa does, so this patch causes the driver to fall back to non-secure dispatch if the parser detects a chained batch buffer. Note: The 2nd hunk to munge the error code of the parser looks a bit superflous. At least until we have the batch copy code ready and can run the cmd parser in granting mode. But it isn't since we still need to let existing libva buffers pass (though not with elevated privs ofc!). Testcase: igt/gem_exec_parse/chained-batch Signed-off-by: Brad Volkin [danvet: Add note - this confused me in review and Brad clarified things (after a few mails ...).] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_cmd_parser.c | 18 +++++++++++++++++- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 24 +++++++++++++----------- 2 files changed, 30 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c index 86b3ae0934a7..ef38915075a1 100644 --- a/drivers/gpu/drm/i915/i915_cmd_parser.c +++ b/drivers/gpu/drm/i915/i915_cmd_parser.c @@ -138,6 +138,11 @@ static const struct drm_i915_cmd_descriptor common_cmds[] = { .mask = MI_GLOBAL_GTT, .expected = 0, }}, ), + /* + * MI_BATCH_BUFFER_START requires some special handling. It's not + * really a 'skip' action but it doesn't seem like it's worth adding + * a new action. See i915_parse_cmds(). + */ CMD( MI_BATCH_BUFFER_START, SMI, !F, 0xFF, S ), }; @@ -955,7 +960,8 @@ static bool check_cmd(const struct intel_engine_cs *ring, * Parses the specified batch buffer looking for privilege violations as * described in the overview. * - * Return: non-zero if the parser finds violations or otherwise fails + * Return: non-zero if the parser finds violations or otherwise fails; -EACCES + * if the batch appears legal but should use hardware parsing */ int i915_parse_cmds(struct intel_engine_cs *ring, struct drm_i915_gem_object *batch_obj, @@ -1002,6 +1008,16 @@ int i915_parse_cmds(struct intel_engine_cs *ring, break; } + /* + * If the batch buffer contains a chained batch, return an + * error that tells the caller to abort and dispatch the + * workload as a non-secure batch. + */ + if (desc->cmd.value == MI_BATCH_BUFFER_START) { + ret = -EACCES; + break; + } + if (desc->flags & CMD_DESC_FIXED) length = desc->length.fixed; else diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index c70b329b07cd..4b7f5c104ce0 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1365,17 +1365,19 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, batch_obj, args->batch_start_offset, file->is_master); - if (ret) - goto err; - - /* - * XXX: Actually do this when enabling batch copy... - * - * Set the DISPATCH_SECURE bit to remove the NON_SECURE bit - * from MI_BATCH_BUFFER_START commands issued in the - * dispatch_execbuffer implementations. We specifically don't - * want that set when the command parser is enabled. - */ + if (ret) { + if (ret != -EACCES) + goto err; + } else { + /* + * XXX: Actually do this when enabling batch copy... + * + * Set the DISPATCH_SECURE bit to remove the NON_SECURE bit + * from MI_BATCH_BUFFER_START commands issued in the + * dispatch_execbuffer implementations. We specifically don't + * want that set when the command parser is enabled. + */ + } } /* snb/ivb/vlv conflate the "batch in ppgtt" bit with the "non-secure -- cgit v1.2.3 From 655b5391ca5ef4095110c0b3f82f10e337f0a736 Mon Sep 17 00:00:00 2001 From: Armin Reese Date: Thu, 23 Oct 2014 08:34:27 -0700 Subject: drm/i915 Update Gen8 golden context batch buffer The file drivers/gpu/drm/i915/intel_renderstate_gen8.c is updated to the version created by IGT null_state_gen Signed-off-by: Armin Reese Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_renderstate_gen8.c | 802 ++++++++++++++++++++------ 1 file changed, 640 insertions(+), 162 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_renderstate_gen8.c b/drivers/gpu/drm/i915/intel_renderstate_gen8.c index 75ef1b5de45c..78011d73fa9f 100644 --- a/drivers/gpu/drm/i915/intel_renderstate_gen8.c +++ b/drivers/gpu/drm/i915/intel_renderstate_gen8.c @@ -1,70 +1,575 @@ #include "intel_renderstate.h" static const u32 gen8_null_state_relocs[] = { - 0x00000048, - 0x00000050, - 0x00000060, - 0x000003ec, + 0x00000798, + 0x000007a4, + 0x000007ac, + 0x000007bc, -1, }; static const u32 gen8_null_state_batch[] = { + 0x7a000004, + 0x01000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, 0x69040000, - 0x61020001, + 0x78140000, + 0x04000000, + 0x7820000a, + 0x00000000, + 0x00000000, + 0x80000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x78130002, + 0x00000000, + 0x00000000, + 0x02001808, + 0x781f0002, + 0x00000000, + 0x00000000, + 0x00000000, + 0x78510009, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x78100007, + 0x00000000, + 0x00000000, + 0x00010000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x781b0007, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000800, + 0x00000000, + 0x78110008, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x781e0003, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x781d0007, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x78120002, + 0x00000000, + 0x00000000, + 0x00000000, + 0x78500003, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x781c0002, + 0x00000000, + 0x00000000, + 0x00000000, + 0x780c0000, + 0x00000000, + 0x78520003, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x78300000, + 0x08010040, + 0x78310000, + 0x1e000000, + 0x78320000, + 0x1e000000, + 0x78330000, + 0x1e000000, + 0x79190002, + 0x00000000, + 0x00000000, + 0x00000000, + 0x791a0002, + 0x00000000, + 0x00000000, + 0x00000000, + 0x791b0002, + 0x00000000, + 0x00000000, + 0x00000000, + 0x79120000, + 0x00000000, + 0x79130000, + 0x00000000, + 0x79140000, + 0x00000000, + 0x79150000, + 0x00000000, + 0x79160000, + 0x00000000, + 0x78150009, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x78190009, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x781a0009, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x78160009, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x78170009, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x78490001, + 0x00000000, + 0x00000000, + 0x784a0000, + 0x00000000, + 0x784b0000, + 0x00000004, + 0x79170101, + 0x00000000, + 0x00000080, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, 0x00000000, 0x00000000, - 0x79120000, 0x00000000, - 0x79130000, 0x00000000, - 0x79140000, 0x00000000, - 0x79150000, 0x00000000, - 0x79160000, 0x00000000, - 0x6101000e, - 0x00000001, 0x00000000, - 0x00000001, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x79180006, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x79180006, + 0x20000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x79180006, + 0x40000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x79180006, + 0x60000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x6101000e, 0x00000001, /* reloc */ 0x00000000, + 0x00000000, 0x00000001, /* reloc */ 0x00000000, + 0x00000001, /* reloc */ 0x00000000, + 0x00000001, 0x00000000, 0x00000001, /* reloc */ 0x00000000, - 0xfffff001, 0x00001001, - 0xfffff001, 0x00001001, - 0x78230000, - 0x000006e0, - 0x78210000, - 0x00000700, - 0x78300000, - 0x08010040, - 0x78330000, - 0x08000000, - 0x78310000, - 0x08000000, - 0x78320000, - 0x08000000, - 0x78240000, - 0x00000641, - 0x780e0000, - 0x00000601, + 0x00000001, + 0x00001001, + 0x61020001, + 0x00000000, + 0x00000000, + 0x79000002, + 0x00000000, + 0x00000000, + 0x00000000, + 0x78050006, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x79040002, + 0x00000000, + 0x00000000, + 0x00000000, + 0x79040002, + 0x40000000, + 0x00000000, + 0x00000000, + 0x79040002, + 0x80000000, + 0x00000000, + 0x00000000, + 0x79040002, + 0xc0000000, + 0x00000000, + 0x00000000, + 0x79080001, + 0x00000000, + 0x00000000, + 0x790a0001, + 0x00000000, + 0x00000000, + 0x78060003, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x78070003, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x78040001, + 0x00000000, + 0x00000000, + 0x79110000, + 0x00000000, 0x780d0000, 0x00000000, - 0x78180000, - 0x00000001, - 0x78520003, + 0x79060000, 0x00000000, + 0x7907001f, 0x00000000, 0x00000000, 0x00000000, - 0x78190009, 0x00000000, 0x00000000, 0x00000000, @@ -75,7 +580,6 @@ static const u32 gen8_null_state_batch[] = { 0x00000000, 0x00000000, 0x00000000, - 0x781b0007, 0x00000000, 0x00000000, 0x00000000, @@ -84,26 +588,22 @@ static const u32 gen8_null_state_batch[] = { 0x00000000, 0x00000000, 0x00000000, - 0x78270000, 0x00000000, - 0x782c0000, 0x00000000, - 0x781c0002, 0x00000000, 0x00000000, 0x00000000, - 0x78160009, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x7902000f, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x78110008, 0x00000000, 0x00000000, 0x00000000, @@ -113,12 +613,10 @@ static const u32 gen8_null_state_batch[] = { 0x00000000, 0x00000000, 0x00000000, - 0x78290000, 0x00000000, - 0x782e0000, 0x00000000, - 0x781a0009, 0x00000000, + 0x790c000f, 0x00000000, 0x00000000, 0x00000000, @@ -128,7 +626,6 @@ static const u32 gen8_null_state_batch[] = { 0x00000000, 0x00000000, 0x00000000, - 0x781d0007, 0x00000000, 0x00000000, 0x00000000, @@ -136,153 +633,153 @@ static const u32 gen8_null_state_batch[] = { 0x00000000, 0x00000000, 0x00000000, + 0x780a0003, 0x00000000, - 0x78280000, 0x00000000, - 0x782d0000, 0x00000000, - 0x78260000, 0x00000000, - 0x782b0000, + 0x78080083, + 0x00004000, 0x00000000, - 0x78150009, 0x00000000, 0x00000000, + 0x04004000, 0x00000000, 0x00000000, 0x00000000, + 0x08004000, 0x00000000, 0x00000000, 0x00000000, + 0x0c004000, 0x00000000, 0x00000000, - 0x78100007, 0x00000000, + 0x10004000, 0x00000000, 0x00000000, 0x00000000, + 0x14004000, 0x00000000, 0x00000000, 0x00000000, + 0x18004000, 0x00000000, - 0x781e0003, 0x00000000, 0x00000000, + 0x1c004000, 0x00000000, 0x00000000, - 0x78120002, 0x00000000, + 0x20004000, 0x00000000, 0x00000000, - 0x781f0002, - 0x30400820, 0x00000000, + 0x24004000, 0x00000000, - 0x78510009, 0x00000000, 0x00000000, + 0x28004000, 0x00000000, 0x00000000, 0x00000000, + 0x2c004000, 0x00000000, 0x00000000, 0x00000000, + 0x30004000, 0x00000000, 0x00000000, - 0x78500003, - 0x00210000, 0x00000000, + 0x34004000, 0x00000000, 0x00000000, - 0x78130002, 0x00000000, + 0x38004000, 0x00000000, 0x00000000, - 0x782a0000, - 0x00000480, - 0x782f0000, - 0x00000540, - 0x78140000, - 0x00000800, - 0x78170009, 0x00000000, + 0x3c004000, 0x00000000, 0x00000000, 0x00000000, + 0x40004000, 0x00000000, 0x00000000, 0x00000000, + 0x44004000, 0x00000000, 0x00000000, 0x00000000, - 0x7820000a, - 0x00000580, + 0x48004000, 0x00000000, - 0x08080000, 0x00000000, 0x00000000, - 0x1f000002, - 0x00060000, + 0x4c004000, 0x00000000, 0x00000000, 0x00000000, + 0x50004000, 0x00000000, - 0x784d0000, - 0x40000000, - 0x784f0000, - 0x80000100, - 0x780f0000, - 0x00000740, - 0x78050006, 0x00000000, 0x00000000, + 0x54004000, 0x00000000, 0x00000000, 0x00000000, + 0x58004000, 0x00000000, 0x00000000, - 0x78070003, 0x00000000, + 0x5c004000, 0x00000000, 0x00000000, 0x00000000, - 0x78060003, + 0x60004000, 0x00000000, 0x00000000, 0x00000000, + 0x64004000, 0x00000000, - 0x78040001, 0x00000000, - 0x00000001, - 0x79000002, - 0xffffffff, + 0x00000000, + 0x68004000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x6c004000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x70004000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x74004000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x78004000, + 0x00000000, 0x00000000, 0x00000000, - 0x78080003, - 0x00006000, - 0x000005e0, /* reloc */ + 0x7c004000, 0x00000000, 0x00000000, - 0x78090005, + 0x00000000, + 0x80004000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x78090043, 0x02000000, 0x22220000, - 0x02f60000, - 0x11230000, - 0x02850004, - 0x11230000, - 0x784b0000, - 0x0000000f, - 0x78490001, 0x00000000, 0x00000000, - 0x7b000005, 0x00000000, - 0x00000003, 0x00000000, - 0x00000001, 0x00000000, 0x00000000, - 0x05000000, /* cmds end */ 0x00000000, 0x00000000, 0x00000000, @@ -297,8 +794,6 @@ static const u32 gen8_null_state_batch[] = { 0x00000000, 0x00000000, 0x00000000, - 0x000004c0, /* state start */ - 0x00000500, 0x00000000, 0x00000000, 0x00000000, @@ -345,46 +840,65 @@ static const u32 gen8_null_state_batch[] = { 0x00000000, 0x00000000, 0x00000000, + 0x680b0001, + 0x78260000, + 0x00000000, + 0x78270000, + 0x00000000, + 0x78280000, + 0x00000000, + 0x78290000, + 0x00000000, + 0x782a0000, + 0x00000000, + 0x780e0000, + 0x00000dc1, + 0x78240000, + 0x00000e01, + 0x784f0000, + 0x80000100, + 0x784d0000, + 0x40000000, + 0x782b0000, + 0x00000000, + 0x782c0000, + 0x00000000, + 0x782d0000, + 0x00000000, + 0x782e0000, + 0x00000000, + 0x782f0000, + 0x00000000, + 0x780f0000, 0x00000000, + 0x78230000, + 0x00000e60, + 0x78210000, + 0x00000e80, + 0x7b000005, + 0x00000004, + 0x00000001, 0x00000000, + 0x00000001, 0x00000000, - 0x00000092, 0x00000000, + 0x05000000, /* cmds end */ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, /* state start */ 0x00000000, + 0x3f800000, + 0x3f800000, + 0x3f800000, + 0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x0060005a, - 0x21403ae8, - 0x3a0000c0, - 0x008d0040, - 0x0060005a, - 0x21603ae8, - 0x3a0000c0, - 0x008d0080, - 0x0060005a, - 0x21803ae8, - 0x3a0000d0, - 0x008d0040, - 0x0060005a, - 0x21a03ae8, - 0x3a0000d0, - 0x008d0080, - 0x02800031, - 0x2e0022e8, - 0x0e000140, - 0x08840001, - 0x05800031, - 0x200022e0, - 0x0e000e00, - 0x90031000, 0x00000000, 0x00000000, 0x00000000, @@ -410,38 +924,6 @@ static const u32 gen8_null_state_batch[] = { 0x00000000, 0x00000000, 0x00000000, - 0x06200000, - 0x00000002, - 0x06200000, - 0x00000002, - 0x06200000, - 0x00000002, - 0x06200000, - 0x00000002, - 0x06200000, - 0x00000002, - 0x06200000, - 0x00000002, - 0x06200000, - 0x00000002, - 0x06200000, - 0x00000002, - 0x06200000, - 0x00000002, - 0x06200000, - 0x00000002, - 0x06200000, - 0x00000002, - 0x06200000, - 0x00000002, - 0x06200000, - 0x00000002, - 0x06200000, - 0x00000002, - 0x06200000, - 0x00000002, - 0x06200000, - 0x00000002, 0x00000000, 0x00000000, 0x00000000, @@ -449,8 +931,6 @@ static const u32 gen8_null_state_batch[] = { 0x00000000, 0x00000000, 0x00000000, - 0xf99a130c, - 0x799a130c, 0x00000000, 0x00000000, 0x00000000, @@ -466,9 +946,7 @@ static const u32 gen8_null_state_batch[] = { 0x00000000, 0x00000000, 0x00000000, - 0x3f800000, 0x00000000, - 0x3f800000, 0x00000000, 0x00000000, 0x00000000, -- cgit v1.2.3 From ff7a60f28fa2e018ecd91dc00cbb91d07ff1eb91 Mon Sep 17 00:00:00 2001 From: Armin Reese Date: Thu, 23 Oct 2014 08:34:28 -0700 Subject: drm/i915 Add golden context support for Gen9 This patch includes the Gen9 batch buffer to generate a 'golden context' for that product family. Signed-off-by: Armin Reese Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/Makefile | 3 +- drivers/gpu/drm/i915/i915_gem_render_state.c | 2 + drivers/gpu/drm/i915/intel_renderstate.h | 1 + drivers/gpu/drm/i915/intel_renderstate_gen9.c | 974 ++++++++++++++++++++++++++ 4 files changed, 979 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/i915/intel_renderstate_gen9.c diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 75fd7de9bf4b..9c646c66fa58 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -40,7 +40,8 @@ i915-y += i915_cmd_parser.o \ # autogenerated null render state i915-y += intel_renderstate_gen6.o \ intel_renderstate_gen7.o \ - intel_renderstate_gen8.o + intel_renderstate_gen8.o \ + intel_renderstate_gen9.o # modesetting core code i915-y += intel_bios.o \ diff --git a/drivers/gpu/drm/i915/i915_gem_render_state.c b/drivers/gpu/drm/i915/i915_gem_render_state.c index a9a62d75aa57..98dcd94acba8 100644 --- a/drivers/gpu/drm/i915/i915_gem_render_state.c +++ b/drivers/gpu/drm/i915/i915_gem_render_state.c @@ -38,6 +38,8 @@ render_state_get_rodata(struct drm_device *dev, const int gen) return &gen7_null_state; case 8: return &gen8_null_state; + case 9: + return &gen9_null_state; } return NULL; diff --git a/drivers/gpu/drm/i915/intel_renderstate.h b/drivers/gpu/drm/i915/intel_renderstate.h index 6c792d3a9c9c..5bd69852752c 100644 --- a/drivers/gpu/drm/i915/intel_renderstate.h +++ b/drivers/gpu/drm/i915/intel_renderstate.h @@ -29,6 +29,7 @@ extern const struct intel_renderstate_rodata gen6_null_state; extern const struct intel_renderstate_rodata gen7_null_state; extern const struct intel_renderstate_rodata gen8_null_state; +extern const struct intel_renderstate_rodata gen9_null_state; #define RO_RENDERSTATE(_g) \ const struct intel_renderstate_rodata gen ## _g ## _null_state = { \ diff --git a/drivers/gpu/drm/i915/intel_renderstate_gen9.c b/drivers/gpu/drm/i915/intel_renderstate_gen9.c new file mode 100644 index 000000000000..875075373807 --- /dev/null +++ b/drivers/gpu/drm/i915/intel_renderstate_gen9.c @@ -0,0 +1,974 @@ +#include "intel_renderstate.h" + +static const u32 gen9_null_state_relocs[] = { + 0x000007a8, + 0x000007b4, + 0x000007bc, + 0x000007cc, + -1, +}; + +static const u32 gen9_null_state_batch[] = { + 0x7a000004, + 0x01000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x69040300, + 0x78140000, + 0x04000000, + 0x7820000a, + 0x00000000, + 0x00000000, + 0x80000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x78130002, + 0x00000000, + 0x00000000, + 0x02001808, + 0x781f0004, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x78510009, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x78100007, + 0x00000000, + 0x00000000, + 0x00010000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x781b0007, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000800, + 0x00000000, + 0x78110008, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x781e0003, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x781d0009, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x78120002, + 0x00000000, + 0x00000000, + 0x00000000, + 0x78500003, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x781c0002, + 0x00000000, + 0x00000000, + 0x00000000, + 0x780c0000, + 0x00000000, + 0x78520003, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x78300000, + 0x08010040, + 0x78310000, + 0x1e000000, + 0x78320000, + 0x1e000000, + 0x78330000, + 0x1e000000, + 0x79190002, + 0x00000000, + 0x00000000, + 0x00000000, + 0x791a0002, + 0x00000000, + 0x00000000, + 0x00000000, + 0x791b0002, + 0x00000000, + 0x00000000, + 0x00000000, + 0x79120000, + 0x00000000, + 0x79130000, + 0x00000000, + 0x79140000, + 0x00000000, + 0x79150000, + 0x00000000, + 0x79160000, + 0x00000000, + 0x78150009, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x78190009, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x781a0009, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x78160009, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x78170009, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x78490001, + 0x00000000, + 0x00000000, + 0x784a0000, + 0x00000000, + 0x784b0000, + 0x00000004, + 0x79170101, + 0x00000000, + 0x00000080, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x79180006, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x79180006, + 0x20000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x79180006, + 0x40000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x79180006, + 0x60000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x61010011, + 0x00000001, /* reloc */ + 0x00000000, + 0x00000000, + 0x00000001, /* reloc */ + 0x00000000, + 0x00000001, /* reloc */ + 0x00000000, + 0x00000001, + 0x00000000, + 0x00000001, /* reloc */ + 0x00000000, + 0x00001001, + 0x00001001, + 0x00000001, + 0x00001001, + 0x00000000, + 0x00000000, + 0x00000000, + 0x61020001, + 0x00000000, + 0x00000000, + 0x79000002, + 0x00000000, + 0x00000000, + 0x00000000, + 0x78050006, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x79040002, + 0x00000000, + 0x00000000, + 0x00000000, + 0x79040002, + 0x40000000, + 0x00000000, + 0x00000000, + 0x79040002, + 0x80000000, + 0x00000000, + 0x00000000, + 0x79040002, + 0xc0000000, + 0x00000000, + 0x00000000, + 0x79080001, + 0x00000000, + 0x00000000, + 0x790a0001, + 0x00000000, + 0x00000000, + 0x78060003, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x78070003, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x78040001, + 0x00000000, + 0x00000000, + 0x79110000, + 0x00000000, + 0x780d0000, + 0x00000000, + 0x79060000, + 0x00000000, + 0x7907001f, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x7902000f, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x790c000f, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x780a0003, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x78080083, + 0x00004000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x04004000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x08004000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0c004000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x10004000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x14004000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x18004000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x1c004000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x20004000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x24004000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x28004000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x2c004000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x30004000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x34004000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x38004000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x3c004000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x40004000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x44004000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x48004000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x4c004000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x50004000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x54004000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x58004000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x5c004000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x60004000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x64004000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x68004000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x6c004000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x70004000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x74004000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x78004000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x7c004000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x80004000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x78090043, + 0x02000000, + 0x22220000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x78550003, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x680b0001, + 0x780e0000, + 0x00000e01, + 0x78240000, + 0x00000e41, + 0x784f0000, + 0x80000100, + 0x784d0000, + 0x40000000, + 0x782b0000, + 0x00000000, + 0x782c0000, + 0x00000000, + 0x782d0000, + 0x00000000, + 0x782e0000, + 0x00000000, + 0x782f0000, + 0x00000000, + 0x780f0000, + 0x00000000, + 0x78230000, + 0x00000ea0, + 0x78210000, + 0x00000ec0, + 0x78260000, + 0x00000000, + 0x78270000, + 0x00000000, + 0x78280000, + 0x00000000, + 0x78290000, + 0x00000000, + 0x782a0000, + 0x00000000, + 0x7b000005, + 0x00000004, + 0x00000001, + 0x00000000, + 0x00000001, + 0x00000000, + 0x00000000, + 0x05000000, /* cmds end */ + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, /* state start */ + 0x00000000, + 0x3f800000, + 0x3f800000, + 0x3f800000, + 0x3f800000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, /* state end */ +}; + +RO_RENDERSTATE(9); -- cgit v1.2.3 From 3f20df98870236b288a90fc3b65f593d3db05b17 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Fri, 24 Oct 2014 14:51:34 +0100 Subject: drm/i915: only flip frontbuffer if crtc is active MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is no point in flipping a buffer for a disabled crtc. Signed-off-by: Gustavo Padovan Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 910e8a4603fa..140bbefaac8d 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8544,9 +8544,9 @@ static int intel_crtc_cursor_set_obj(struct drm_crtc *crtc, if (old_width != width) intel_update_watermarks(crtc); intel_crtc_update_cursor(crtc, intel_crtc->cursor_bo != NULL); - } - intel_frontbuffer_flip(dev, INTEL_FRONTBUFFER_CURSOR(pipe)); + intel_frontbuffer_flip(dev, INTEL_FRONTBUFFER_CURSOR(pipe)); + } return 0; fail_unpin: -- cgit v1.2.3 From c5d974728fafc151e740638b4cf492958be78b5b Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Sat, 25 Oct 2014 00:11:11 +0100 Subject: drm/i915: Remove unnecessary test on the gen in intel_do_mmio_flip() use_mmio_flip() makes sure we only enable MMIO flips on gen5+. So we don't need to take into account older devices. Signed-off-by: Damien Lespiau Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 140bbefaac8d..46224c6307cb 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -9567,12 +9567,11 @@ static void intel_do_mmio_flip(struct intel_crtc *intel_crtc) reg = DSPCNTR(intel_crtc->plane); dspcntr = I915_READ(reg); - if (INTEL_INFO(dev)->gen >= 4) { - if (obj->tiling_mode != I915_TILING_NONE) - dspcntr |= DISPPLANE_TILED; - else - dspcntr &= ~DISPPLANE_TILED; - } + if (obj->tiling_mode != I915_TILING_NONE) + dspcntr |= DISPPLANE_TILED; + else + dspcntr &= ~DISPPLANE_TILED; + I915_WRITE(reg, dspcntr); I915_WRITE(DSPSURF(intel_crtc->plane), -- cgit v1.2.3 From 083fe3b035d286d79071fd77d2a2c5abfdef495b Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Fri, 24 Oct 2014 19:00:17 +0100 Subject: drm: make sure visible is set to false if fb is null MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We can't let visible set true while the fb is null, some places of the code only check for visible to base its decisions. Signed-off-by: Gustavo Padovan Reviewed-by: Ville Syrjälä Acked-by: Dave Airlie Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_plane_helper.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c index 827ec1a3040b..fe4d1fb2376c 100644 --- a/drivers/gpu/drm/drm_plane_helper.c +++ b/drivers/gpu/drm/drm_plane_helper.c @@ -127,6 +127,11 @@ int drm_plane_helper_check_update(struct drm_plane *plane, return -ERANGE; } + if (!fb) { + *visible = false; + return 0; + } + *visible = drm_rect_clip_scaled(src, dest, clip, hscale, vscale); if (!*visible) /* -- cgit v1.2.3 From 3ead8bb26e1e3a8b35f41a0eb65a1bd571b0204e Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Fri, 24 Oct 2014 19:00:18 +0100 Subject: drm/i915: remove unneeded visible check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The fb check introduced to drm_plane_helper_check_update() just make this check impossible to branch in. Signed-off-by: Gustavo Padovan Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 46224c6307cb..6e9d4e16d60f 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11639,23 +11639,12 @@ intel_check_primary_plane(struct drm_plane *plane, struct drm_rect *dest = &state->dst; struct drm_rect *src = &state->src; const struct drm_rect *clip = &state->clip; - int ret; - - ret = drm_plane_helper_check_update(plane, crtc, fb, - src, dest, clip, - DRM_PLANE_HELPER_NO_SCALING, - DRM_PLANE_HELPER_NO_SCALING, - false, true, &state->visible); - if (ret) - return ret; - /* no fb bound */ - if (state->visible && !fb) { - DRM_ERROR("No FB bound\n"); - return -EINVAL; - } - - return 0; + return drm_plane_helper_check_update(plane, crtc, fb, + src, dest, clip, + DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_HELPER_NO_SCALING, + false, true, &state->visible); } static int -- cgit v1.2.3 From 7c10a2b5876e014b3986d7e20b2a2894a757b138 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 27 Oct 2014 16:26:43 +0200 Subject: drm/i915: add new intel audio file to group DP/HDMI audio In preparation for some additional cleanup. No functional changes. Signed-off-by: Jani Nikula Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/Makefile | 3 +- drivers/gpu/drm/i915/intel_audio.c | 357 +++++++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_display.c | 323 +------------------------------ drivers/gpu/drm/i915/intel_drv.h | 8 +- 4 files changed, 368 insertions(+), 323 deletions(-) create mode 100644 drivers/gpu/drm/i915/intel_audio.c diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 9c646c66fa58..891e584e97ea 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -44,7 +44,8 @@ i915-y += intel_renderstate_gen6.o \ intel_renderstate_gen9.o # modesetting core code -i915-y += intel_bios.o \ +i915-y += intel_audio.o \ + intel_bios.o \ intel_display.o \ intel_fifo_underrun.o \ intel_frontbuffer.o \ diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c new file mode 100644 index 000000000000..167903b5e3ff --- /dev/null +++ b/drivers/gpu/drm/i915/intel_audio.c @@ -0,0 +1,357 @@ +/* + * 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. + */ + +#include + +#include +#include +#include "intel_drv.h" +#include "i915_drv.h" + +static struct { + int clock; + u32 config; +} hdmi_audio_clock[] = { + { DIV_ROUND_UP(25200 * 1000, 1001), AUD_CONFIG_PIXEL_CLOCK_HDMI_25175 }, + { 25200, AUD_CONFIG_PIXEL_CLOCK_HDMI_25200 }, /* default per bspec */ + { 27000, AUD_CONFIG_PIXEL_CLOCK_HDMI_27000 }, + { 27000 * 1001 / 1000, AUD_CONFIG_PIXEL_CLOCK_HDMI_27027 }, + { 54000, AUD_CONFIG_PIXEL_CLOCK_HDMI_54000 }, + { 54000 * 1001 / 1000, AUD_CONFIG_PIXEL_CLOCK_HDMI_54054 }, + { DIV_ROUND_UP(74250 * 1000, 1001), AUD_CONFIG_PIXEL_CLOCK_HDMI_74176 }, + { 74250, AUD_CONFIG_PIXEL_CLOCK_HDMI_74250 }, + { DIV_ROUND_UP(148500 * 1000, 1001), AUD_CONFIG_PIXEL_CLOCK_HDMI_148352 }, + { 148500, AUD_CONFIG_PIXEL_CLOCK_HDMI_148500 }, +}; + +/* get AUD_CONFIG_PIXEL_CLOCK_HDMI_* value for mode */ +static u32 audio_config_hdmi_pixel_clock(struct drm_display_mode *mode) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(hdmi_audio_clock); i++) { + if (mode->clock == hdmi_audio_clock[i].clock) + break; + } + + if (i == ARRAY_SIZE(hdmi_audio_clock)) { + DRM_DEBUG_KMS("HDMI audio pixel clock setting for %d not found, falling back to defaults\n", mode->clock); + i = 1; + } + + DRM_DEBUG_KMS("Configuring HDMI audio for pixel clock %d (0x%08x)\n", + hdmi_audio_clock[i].clock, + hdmi_audio_clock[i].config); + + return hdmi_audio_clock[i].config; +} + +static bool intel_eld_uptodate(struct drm_connector *connector, + int reg_eldv, uint32_t bits_eldv, + int reg_elda, uint32_t bits_elda, + int reg_edid) +{ + struct drm_i915_private *dev_priv = connector->dev->dev_private; + uint8_t *eld = connector->eld; + uint32_t i; + + i = I915_READ(reg_eldv); + i &= bits_eldv; + + if (!eld[0]) + return !i; + + if (!i) + return false; + + i = I915_READ(reg_elda); + i &= ~bits_elda; + I915_WRITE(reg_elda, i); + + for (i = 0; i < eld[2]; i++) + if (I915_READ(reg_edid) != *((uint32_t *)eld + i)) + return false; + + return true; +} + +static void g4x_write_eld(struct drm_connector *connector, + struct drm_crtc *crtc, + struct drm_display_mode *mode) +{ + struct drm_i915_private *dev_priv = connector->dev->dev_private; + uint8_t *eld = connector->eld; + uint32_t eldv; + uint32_t len; + uint32_t i; + + i = I915_READ(G4X_AUD_VID_DID); + + if (i == INTEL_AUDIO_DEVBLC || i == INTEL_AUDIO_DEVCL) + eldv = G4X_ELDV_DEVCL_DEVBLC; + else + eldv = G4X_ELDV_DEVCTG; + + if (intel_eld_uptodate(connector, + G4X_AUD_CNTL_ST, eldv, + G4X_AUD_CNTL_ST, G4X_ELD_ADDR, + G4X_HDMIW_HDMIEDID)) + return; + + i = I915_READ(G4X_AUD_CNTL_ST); + i &= ~(eldv | G4X_ELD_ADDR); + len = (i >> 9) & 0x1f; /* ELD buffer size */ + I915_WRITE(G4X_AUD_CNTL_ST, i); + + if (!eld[0]) + return; + + len = min_t(uint8_t, eld[2], len); + DRM_DEBUG_DRIVER("ELD size %d\n", len); + for (i = 0; i < len; i++) + I915_WRITE(G4X_HDMIW_HDMIEDID, *((uint32_t *)eld + i)); + + i = I915_READ(G4X_AUD_CNTL_ST); + i |= eldv; + I915_WRITE(G4X_AUD_CNTL_ST, i); +} + +static void haswell_write_eld(struct drm_connector *connector, + struct drm_crtc *crtc, + struct drm_display_mode *mode) +{ + struct drm_i915_private *dev_priv = connector->dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + uint8_t *eld = connector->eld; + uint32_t eldv; + uint32_t i; + int len; + int pipe = to_intel_crtc(crtc)->pipe; + int tmp; + + int hdmiw_hdmiedid = HSW_AUD_EDID_DATA(pipe); + int aud_cntl_st = HSW_AUD_DIP_ELD_CTRL(pipe); + int aud_config = HSW_AUD_CFG(pipe); + int aud_cntrl_st2 = HSW_AUD_PIN_ELD_CP_VLD; + + /* Audio output enable */ + DRM_DEBUG_DRIVER("HDMI audio: enable codec\n"); + tmp = I915_READ(aud_cntrl_st2); + tmp |= (AUDIO_OUTPUT_ENABLE_A << (pipe * 4)); + I915_WRITE(aud_cntrl_st2, tmp); + POSTING_READ(aud_cntrl_st2); + + assert_pipe_disabled(dev_priv, to_intel_crtc(crtc)->pipe); + + /* Set ELD valid state */ + tmp = I915_READ(aud_cntrl_st2); + DRM_DEBUG_DRIVER("HDMI audio: pin eld vld status=0x%08x\n", tmp); + tmp |= (AUDIO_ELD_VALID_A << (pipe * 4)); + I915_WRITE(aud_cntrl_st2, tmp); + tmp = I915_READ(aud_cntrl_st2); + DRM_DEBUG_DRIVER("HDMI audio: eld vld status=0x%08x\n", tmp); + + /* Enable HDMI mode */ + tmp = I915_READ(aud_config); + DRM_DEBUG_DRIVER("HDMI audio: audio conf: 0x%08x\n", tmp); + /* clear N_programing_enable and N_value_index */ + tmp &= ~(AUD_CONFIG_N_VALUE_INDEX | AUD_CONFIG_N_PROG_ENABLE); + I915_WRITE(aud_config, tmp); + + DRM_DEBUG_DRIVER("ELD on pipe %c\n", pipe_name(pipe)); + + eldv = AUDIO_ELD_VALID_A << (pipe * 4); + + if (intel_pipe_has_type(intel_crtc, INTEL_OUTPUT_DISPLAYPORT)) { + DRM_DEBUG_DRIVER("ELD: DisplayPort detected\n"); + eld[5] |= (1 << 2); /* Conn_Type, 0x1 = DisplayPort */ + I915_WRITE(aud_config, AUD_CONFIG_N_VALUE_INDEX); /* 0x1 = DP */ + } else { + I915_WRITE(aud_config, audio_config_hdmi_pixel_clock(mode)); + } + + if (intel_eld_uptodate(connector, + aud_cntrl_st2, eldv, + aud_cntl_st, IBX_ELD_ADDRESS, + hdmiw_hdmiedid)) + return; + + i = I915_READ(aud_cntrl_st2); + i &= ~eldv; + I915_WRITE(aud_cntrl_st2, i); + + if (!eld[0]) + return; + + i = I915_READ(aud_cntl_st); + i &= ~IBX_ELD_ADDRESS; + I915_WRITE(aud_cntl_st, i); + i = (i >> 29) & DIP_PORT_SEL_MASK; /* DIP_Port_Select, 0x1 = PortB */ + DRM_DEBUG_DRIVER("port num:%d\n", i); + + len = min_t(uint8_t, eld[2], 21); /* 84 bytes of hw ELD buffer */ + DRM_DEBUG_DRIVER("ELD size %d\n", len); + for (i = 0; i < len; i++) + I915_WRITE(hdmiw_hdmiedid, *((uint32_t *)eld + i)); + + i = I915_READ(aud_cntrl_st2); + i |= eldv; + I915_WRITE(aud_cntrl_st2, i); + +} + +static void ironlake_write_eld(struct drm_connector *connector, + struct drm_crtc *crtc, + struct drm_display_mode *mode) +{ + struct drm_i915_private *dev_priv = connector->dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + uint8_t *eld = connector->eld; + uint32_t eldv; + uint32_t i; + int len; + int hdmiw_hdmiedid; + int aud_config; + int aud_cntl_st; + int aud_cntrl_st2; + int pipe = to_intel_crtc(crtc)->pipe; + + if (HAS_PCH_IBX(connector->dev)) { + hdmiw_hdmiedid = IBX_HDMIW_HDMIEDID(pipe); + aud_config = IBX_AUD_CFG(pipe); + aud_cntl_st = IBX_AUD_CNTL_ST(pipe); + aud_cntrl_st2 = IBX_AUD_CNTL_ST2; + } else if (IS_VALLEYVIEW(connector->dev)) { + hdmiw_hdmiedid = VLV_HDMIW_HDMIEDID(pipe); + aud_config = VLV_AUD_CFG(pipe); + aud_cntl_st = VLV_AUD_CNTL_ST(pipe); + aud_cntrl_st2 = VLV_AUD_CNTL_ST2; + } else { + hdmiw_hdmiedid = CPT_HDMIW_HDMIEDID(pipe); + aud_config = CPT_AUD_CFG(pipe); + aud_cntl_st = CPT_AUD_CNTL_ST(pipe); + aud_cntrl_st2 = CPT_AUD_CNTRL_ST2; + } + + DRM_DEBUG_DRIVER("ELD on pipe %c\n", pipe_name(pipe)); + + if (IS_VALLEYVIEW(connector->dev)) { + struct intel_encoder *intel_encoder; + struct intel_digital_port *intel_dig_port; + + intel_encoder = intel_attached_encoder(connector); + intel_dig_port = enc_to_dig_port(&intel_encoder->base); + i = intel_dig_port->port; + } else { + i = I915_READ(aud_cntl_st); + i = (i >> 29) & DIP_PORT_SEL_MASK; + /* DIP_Port_Select, 0x1 = PortB */ + } + + if (!i) { + DRM_DEBUG_DRIVER("Audio directed to unknown port\n"); + /* operate blindly on all ports */ + eldv = IBX_ELD_VALIDB; + eldv |= IBX_ELD_VALIDB << 4; + eldv |= IBX_ELD_VALIDB << 8; + } else { + DRM_DEBUG_DRIVER("ELD on port %c\n", port_name(i)); + eldv = IBX_ELD_VALIDB << ((i - 1) * 4); + } + + if (intel_pipe_has_type(intel_crtc, INTEL_OUTPUT_DISPLAYPORT)) { + DRM_DEBUG_DRIVER("ELD: DisplayPort detected\n"); + eld[5] |= (1 << 2); /* Conn_Type, 0x1 = DisplayPort */ + I915_WRITE(aud_config, AUD_CONFIG_N_VALUE_INDEX); /* 0x1 = DP */ + } else { + I915_WRITE(aud_config, audio_config_hdmi_pixel_clock(mode)); + } + + if (intel_eld_uptodate(connector, + aud_cntrl_st2, eldv, + aud_cntl_st, IBX_ELD_ADDRESS, + hdmiw_hdmiedid)) + return; + + i = I915_READ(aud_cntrl_st2); + i &= ~eldv; + I915_WRITE(aud_cntrl_st2, i); + + if (!eld[0]) + return; + + i = I915_READ(aud_cntl_st); + i &= ~IBX_ELD_ADDRESS; + I915_WRITE(aud_cntl_st, i); + + len = min_t(uint8_t, eld[2], 21); /* 84 bytes of hw ELD buffer */ + DRM_DEBUG_DRIVER("ELD size %d\n", len); + for (i = 0; i < len; i++) + I915_WRITE(hdmiw_hdmiedid, *((uint32_t *)eld + i)); + + i = I915_READ(aud_cntrl_st2); + i |= eldv; + I915_WRITE(aud_cntrl_st2, i); +} + +void intel_write_eld(struct drm_encoder *encoder, + struct drm_display_mode *mode) +{ + struct drm_crtc *crtc = encoder->crtc; + struct drm_connector *connector; + struct drm_device *dev = encoder->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + + connector = drm_select_eld(encoder, mode); + if (!connector) + return; + + DRM_DEBUG_DRIVER("ELD on [CONNECTOR:%d:%s], [ENCODER:%d:%s]\n", + connector->base.id, + connector->name, + connector->encoder->base.id, + connector->encoder->name); + + connector->eld[6] = drm_av_sync_delay(connector, mode) / 2; + + if (dev_priv->display.write_eld) + dev_priv->display.write_eld(connector, crtc, mode); +} + +/** + * intel_init_audio - Set up chip specific audio functions + * @dev: drm device + */ +void intel_init_audio(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (IS_G4X(dev)) + dev_priv->display.write_eld = g4x_write_eld; + else if (IS_VALLEYVIEW(dev)) + dev_priv->display.write_eld = ironlake_write_eld; + else if (IS_HASWELL(dev) || INTEL_INFO(dev)->gen >= 8) + dev_priv->display.write_eld = haswell_write_eld; + else if (HAS_PCH_SPLIT(dev)) + dev_priv->display.write_eld = ironlake_write_eld; +} diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 6e9d4e16d60f..aeda09dcfb72 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -406,7 +406,7 @@ static void vlv_clock(int refclk, intel_clock_t *clock) /** * Returns whether any output on the specified pipe is of the specified type */ -static bool intel_pipe_has_type(struct intel_crtc *crtc, int type) +bool intel_pipe_has_type(struct intel_crtc *crtc, int type) { struct drm_device *dev = crtc->base.dev; struct intel_encoder *encoder; @@ -7940,316 +7940,6 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc, return true; } -static struct { - int clock; - u32 config; -} hdmi_audio_clock[] = { - { DIV_ROUND_UP(25200 * 1000, 1001), AUD_CONFIG_PIXEL_CLOCK_HDMI_25175 }, - { 25200, AUD_CONFIG_PIXEL_CLOCK_HDMI_25200 }, /* default per bspec */ - { 27000, AUD_CONFIG_PIXEL_CLOCK_HDMI_27000 }, - { 27000 * 1001 / 1000, AUD_CONFIG_PIXEL_CLOCK_HDMI_27027 }, - { 54000, AUD_CONFIG_PIXEL_CLOCK_HDMI_54000 }, - { 54000 * 1001 / 1000, AUD_CONFIG_PIXEL_CLOCK_HDMI_54054 }, - { DIV_ROUND_UP(74250 * 1000, 1001), AUD_CONFIG_PIXEL_CLOCK_HDMI_74176 }, - { 74250, AUD_CONFIG_PIXEL_CLOCK_HDMI_74250 }, - { DIV_ROUND_UP(148500 * 1000, 1001), AUD_CONFIG_PIXEL_CLOCK_HDMI_148352 }, - { 148500, AUD_CONFIG_PIXEL_CLOCK_HDMI_148500 }, -}; - -/* get AUD_CONFIG_PIXEL_CLOCK_HDMI_* value for mode */ -static u32 audio_config_hdmi_pixel_clock(struct drm_display_mode *mode) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(hdmi_audio_clock); i++) { - if (mode->clock == hdmi_audio_clock[i].clock) - break; - } - - if (i == ARRAY_SIZE(hdmi_audio_clock)) { - DRM_DEBUG_KMS("HDMI audio pixel clock setting for %d not found, falling back to defaults\n", mode->clock); - i = 1; - } - - DRM_DEBUG_KMS("Configuring HDMI audio for pixel clock %d (0x%08x)\n", - hdmi_audio_clock[i].clock, - hdmi_audio_clock[i].config); - - return hdmi_audio_clock[i].config; -} - -static bool intel_eld_uptodate(struct drm_connector *connector, - int reg_eldv, uint32_t bits_eldv, - int reg_elda, uint32_t bits_elda, - int reg_edid) -{ - struct drm_i915_private *dev_priv = connector->dev->dev_private; - uint8_t *eld = connector->eld; - uint32_t i; - - i = I915_READ(reg_eldv); - i &= bits_eldv; - - if (!eld[0]) - return !i; - - if (!i) - return false; - - i = I915_READ(reg_elda); - i &= ~bits_elda; - I915_WRITE(reg_elda, i); - - for (i = 0; i < eld[2]; i++) - if (I915_READ(reg_edid) != *((uint32_t *)eld + i)) - return false; - - return true; -} - -static void g4x_write_eld(struct drm_connector *connector, - struct drm_crtc *crtc, - struct drm_display_mode *mode) -{ - struct drm_i915_private *dev_priv = connector->dev->dev_private; - uint8_t *eld = connector->eld; - uint32_t eldv; - uint32_t len; - uint32_t i; - - i = I915_READ(G4X_AUD_VID_DID); - - if (i == INTEL_AUDIO_DEVBLC || i == INTEL_AUDIO_DEVCL) - eldv = G4X_ELDV_DEVCL_DEVBLC; - else - eldv = G4X_ELDV_DEVCTG; - - if (intel_eld_uptodate(connector, - G4X_AUD_CNTL_ST, eldv, - G4X_AUD_CNTL_ST, G4X_ELD_ADDR, - G4X_HDMIW_HDMIEDID)) - return; - - i = I915_READ(G4X_AUD_CNTL_ST); - i &= ~(eldv | G4X_ELD_ADDR); - len = (i >> 9) & 0x1f; /* ELD buffer size */ - I915_WRITE(G4X_AUD_CNTL_ST, i); - - if (!eld[0]) - return; - - len = min_t(uint8_t, eld[2], len); - DRM_DEBUG_DRIVER("ELD size %d\n", len); - for (i = 0; i < len; i++) - I915_WRITE(G4X_HDMIW_HDMIEDID, *((uint32_t *)eld + i)); - - i = I915_READ(G4X_AUD_CNTL_ST); - i |= eldv; - I915_WRITE(G4X_AUD_CNTL_ST, i); -} - -static void haswell_write_eld(struct drm_connector *connector, - struct drm_crtc *crtc, - struct drm_display_mode *mode) -{ - struct drm_i915_private *dev_priv = connector->dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - uint8_t *eld = connector->eld; - uint32_t eldv; - uint32_t i; - int len; - int pipe = to_intel_crtc(crtc)->pipe; - int tmp; - - int hdmiw_hdmiedid = HSW_AUD_EDID_DATA(pipe); - int aud_cntl_st = HSW_AUD_DIP_ELD_CTRL(pipe); - int aud_config = HSW_AUD_CFG(pipe); - int aud_cntrl_st2 = HSW_AUD_PIN_ELD_CP_VLD; - - /* Audio output enable */ - DRM_DEBUG_DRIVER("HDMI audio: enable codec\n"); - tmp = I915_READ(aud_cntrl_st2); - tmp |= (AUDIO_OUTPUT_ENABLE_A << (pipe * 4)); - I915_WRITE(aud_cntrl_st2, tmp); - POSTING_READ(aud_cntrl_st2); - - assert_pipe_disabled(dev_priv, to_intel_crtc(crtc)->pipe); - - /* Set ELD valid state */ - tmp = I915_READ(aud_cntrl_st2); - DRM_DEBUG_DRIVER("HDMI audio: pin eld vld status=0x%08x\n", tmp); - tmp |= (AUDIO_ELD_VALID_A << (pipe * 4)); - I915_WRITE(aud_cntrl_st2, tmp); - tmp = I915_READ(aud_cntrl_st2); - DRM_DEBUG_DRIVER("HDMI audio: eld vld status=0x%08x\n", tmp); - - /* Enable HDMI mode */ - tmp = I915_READ(aud_config); - DRM_DEBUG_DRIVER("HDMI audio: audio conf: 0x%08x\n", tmp); - /* clear N_programing_enable and N_value_index */ - tmp &= ~(AUD_CONFIG_N_VALUE_INDEX | AUD_CONFIG_N_PROG_ENABLE); - I915_WRITE(aud_config, tmp); - - DRM_DEBUG_DRIVER("ELD on pipe %c\n", pipe_name(pipe)); - - eldv = AUDIO_ELD_VALID_A << (pipe * 4); - - if (intel_pipe_has_type(intel_crtc, INTEL_OUTPUT_DISPLAYPORT)) { - DRM_DEBUG_DRIVER("ELD: DisplayPort detected\n"); - eld[5] |= (1 << 2); /* Conn_Type, 0x1 = DisplayPort */ - I915_WRITE(aud_config, AUD_CONFIG_N_VALUE_INDEX); /* 0x1 = DP */ - } else { - I915_WRITE(aud_config, audio_config_hdmi_pixel_clock(mode)); - } - - if (intel_eld_uptodate(connector, - aud_cntrl_st2, eldv, - aud_cntl_st, IBX_ELD_ADDRESS, - hdmiw_hdmiedid)) - return; - - i = I915_READ(aud_cntrl_st2); - i &= ~eldv; - I915_WRITE(aud_cntrl_st2, i); - - if (!eld[0]) - return; - - i = I915_READ(aud_cntl_st); - i &= ~IBX_ELD_ADDRESS; - I915_WRITE(aud_cntl_st, i); - i = (i >> 29) & DIP_PORT_SEL_MASK; /* DIP_Port_Select, 0x1 = PortB */ - DRM_DEBUG_DRIVER("port num:%d\n", i); - - len = min_t(uint8_t, eld[2], 21); /* 84 bytes of hw ELD buffer */ - DRM_DEBUG_DRIVER("ELD size %d\n", len); - for (i = 0; i < len; i++) - I915_WRITE(hdmiw_hdmiedid, *((uint32_t *)eld + i)); - - i = I915_READ(aud_cntrl_st2); - i |= eldv; - I915_WRITE(aud_cntrl_st2, i); - -} - -static void ironlake_write_eld(struct drm_connector *connector, - struct drm_crtc *crtc, - struct drm_display_mode *mode) -{ - struct drm_i915_private *dev_priv = connector->dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - uint8_t *eld = connector->eld; - uint32_t eldv; - uint32_t i; - int len; - int hdmiw_hdmiedid; - int aud_config; - int aud_cntl_st; - int aud_cntrl_st2; - int pipe = to_intel_crtc(crtc)->pipe; - - if (HAS_PCH_IBX(connector->dev)) { - hdmiw_hdmiedid = IBX_HDMIW_HDMIEDID(pipe); - aud_config = IBX_AUD_CFG(pipe); - aud_cntl_st = IBX_AUD_CNTL_ST(pipe); - aud_cntrl_st2 = IBX_AUD_CNTL_ST2; - } else if (IS_VALLEYVIEW(connector->dev)) { - hdmiw_hdmiedid = VLV_HDMIW_HDMIEDID(pipe); - aud_config = VLV_AUD_CFG(pipe); - aud_cntl_st = VLV_AUD_CNTL_ST(pipe); - aud_cntrl_st2 = VLV_AUD_CNTL_ST2; - } else { - hdmiw_hdmiedid = CPT_HDMIW_HDMIEDID(pipe); - aud_config = CPT_AUD_CFG(pipe); - aud_cntl_st = CPT_AUD_CNTL_ST(pipe); - aud_cntrl_st2 = CPT_AUD_CNTRL_ST2; - } - - DRM_DEBUG_DRIVER("ELD on pipe %c\n", pipe_name(pipe)); - - if (IS_VALLEYVIEW(connector->dev)) { - struct intel_encoder *intel_encoder; - struct intel_digital_port *intel_dig_port; - - intel_encoder = intel_attached_encoder(connector); - intel_dig_port = enc_to_dig_port(&intel_encoder->base); - i = intel_dig_port->port; - } else { - i = I915_READ(aud_cntl_st); - i = (i >> 29) & DIP_PORT_SEL_MASK; - /* DIP_Port_Select, 0x1 = PortB */ - } - - if (!i) { - DRM_DEBUG_DRIVER("Audio directed to unknown port\n"); - /* operate blindly on all ports */ - eldv = IBX_ELD_VALIDB; - eldv |= IBX_ELD_VALIDB << 4; - eldv |= IBX_ELD_VALIDB << 8; - } else { - DRM_DEBUG_DRIVER("ELD on port %c\n", port_name(i)); - eldv = IBX_ELD_VALIDB << ((i - 1) * 4); - } - - if (intel_pipe_has_type(intel_crtc, INTEL_OUTPUT_DISPLAYPORT)) { - DRM_DEBUG_DRIVER("ELD: DisplayPort detected\n"); - eld[5] |= (1 << 2); /* Conn_Type, 0x1 = DisplayPort */ - I915_WRITE(aud_config, AUD_CONFIG_N_VALUE_INDEX); /* 0x1 = DP */ - } else { - I915_WRITE(aud_config, audio_config_hdmi_pixel_clock(mode)); - } - - if (intel_eld_uptodate(connector, - aud_cntrl_st2, eldv, - aud_cntl_st, IBX_ELD_ADDRESS, - hdmiw_hdmiedid)) - return; - - i = I915_READ(aud_cntrl_st2); - i &= ~eldv; - I915_WRITE(aud_cntrl_st2, i); - - if (!eld[0]) - return; - - i = I915_READ(aud_cntl_st); - i &= ~IBX_ELD_ADDRESS; - I915_WRITE(aud_cntl_st, i); - - len = min_t(uint8_t, eld[2], 21); /* 84 bytes of hw ELD buffer */ - DRM_DEBUG_DRIVER("ELD size %d\n", len); - for (i = 0; i < len; i++) - I915_WRITE(hdmiw_hdmiedid, *((uint32_t *)eld + i)); - - i = I915_READ(aud_cntrl_st2); - i |= eldv; - I915_WRITE(aud_cntrl_st2, i); -} - -void intel_write_eld(struct drm_encoder *encoder, - struct drm_display_mode *mode) -{ - struct drm_crtc *crtc = encoder->crtc; - struct drm_connector *connector; - struct drm_device *dev = encoder->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - - connector = drm_select_eld(encoder, mode); - if (!connector) - return; - - DRM_DEBUG_DRIVER("ELD on [CONNECTOR:%d:%s], [ENCODER:%d:%s]\n", - connector->base.id, - connector->name, - connector->encoder->base.id, - connector->encoder->name); - - connector->eld[6] = drm_av_sync_delay(connector, mode) / 2; - - if (dev_priv->display.write_eld) - dev_priv->display.write_eld(connector, crtc, mode); -} - static void i845_update_cursor(struct drm_crtc *crtc, u32 base) { struct drm_device *dev = crtc->dev; @@ -12638,33 +12328,25 @@ static void intel_init_display(struct drm_device *dev) dev_priv->display.get_display_clock_speed = i830_get_display_clock_speed; - if (IS_G4X(dev)) { - dev_priv->display.write_eld = g4x_write_eld; - } else if (IS_GEN5(dev)) { + if (IS_GEN5(dev)) { dev_priv->display.fdi_link_train = ironlake_fdi_link_train; - dev_priv->display.write_eld = ironlake_write_eld; } else if (IS_GEN6(dev)) { dev_priv->display.fdi_link_train = gen6_fdi_link_train; - dev_priv->display.write_eld = ironlake_write_eld; dev_priv->display.modeset_global_resources = snb_modeset_global_resources; } else if (IS_IVYBRIDGE(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) || IS_BROADWELL(dev)) { dev_priv->display.fdi_link_train = hsw_fdi_link_train; - dev_priv->display.write_eld = haswell_write_eld; dev_priv->display.modeset_global_resources = haswell_modeset_global_resources; } else if (IS_VALLEYVIEW(dev)) { dev_priv->display.modeset_global_resources = valleyview_modeset_global_resources; - dev_priv->display.write_eld = ironlake_write_eld; } else if (INTEL_INFO(dev)->gen >= 9) { - dev_priv->display.write_eld = haswell_write_eld; dev_priv->display.modeset_global_resources = haswell_modeset_global_resources; } @@ -12919,6 +12601,7 @@ void intel_modeset_init(struct drm_device *dev) return; intel_init_display(dev); + intel_init_audio(dev); if (IS_GEN2(dev)) { dev->mode_config.max_width = 2048; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 5ab813c6091e..3bbc4fe817ff 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -848,6 +848,11 @@ void intel_frontbuffer_flip(struct drm_device *dev, void intel_fb_obj_flush(struct drm_i915_gem_object *obj, bool retire); +/* intel_audio.c */ +void intel_init_audio(struct drm_device *dev); +void intel_write_eld(struct drm_encoder *encoder, + struct drm_display_mode *mode); + /* intel_display.c */ const char *intel_output_name(int output); bool intel_has_pending_fb_unpin(struct drm_device *dev); @@ -873,6 +878,7 @@ int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data, struct drm_file *file_priv); enum transcoder intel_pipe_to_cpu_transcoder(struct drm_i915_private *dev_priv, enum pipe pipe); +bool intel_pipe_has_type(struct intel_crtc *crtc, int type); static inline void intel_wait_for_vblank(struct drm_device *dev, int pipe) { @@ -924,8 +930,6 @@ void assert_fdi_rx_pll(struct drm_i915_private *dev_priv, void assert_pipe(struct drm_i915_private *dev_priv, enum pipe pipe, bool state); #define assert_pipe_enabled(d, p) assert_pipe(d, p, true) #define assert_pipe_disabled(d, p) assert_pipe(d, p, false) -void intel_write_eld(struct drm_encoder *encoder, - struct drm_display_mode *mode); unsigned long intel_gen4_compute_page_offset(int *x, int *y, unsigned int tiling_mode, unsigned int bpp, -- cgit v1.2.3 From 87fcb2ad4582c6fb8fb661a943670485df0a1810 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 27 Oct 2014 16:26:44 +0200 Subject: drm/i915/audio: constify hdmi audio clock struct Const is good. Signed-off-by: Jani Nikula Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_audio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c index 167903b5e3ff..e761f2c8d1ae 100644 --- a/drivers/gpu/drm/i915/intel_audio.c +++ b/drivers/gpu/drm/i915/intel_audio.c @@ -28,7 +28,7 @@ #include "intel_drv.h" #include "i915_drv.h" -static struct { +static const struct { int clock; u32 config; } hdmi_audio_clock[] = { -- cgit v1.2.3 From f9f682ae3530f9287379dd91d1b7deaef4abf391 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 27 Oct 2014 16:26:45 +0200 Subject: drm/i915/audio: beat some sense into the variable types and names Most importantly, "i" need not be the universal variable used for everything. No functional changes. Signed-off-by: Jani Nikula Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_audio.c | 115 ++++++++++++++++++------------------- 1 file changed, 57 insertions(+), 58 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c index e761f2c8d1ae..00e9bfcd1e8d 100644 --- a/drivers/gpu/drm/i915/intel_audio.c +++ b/drivers/gpu/drm/i915/intel_audio.c @@ -73,20 +73,21 @@ static bool intel_eld_uptodate(struct drm_connector *connector, { struct drm_i915_private *dev_priv = connector->dev->dev_private; uint8_t *eld = connector->eld; - uint32_t i; + uint32_t tmp; + int i; - i = I915_READ(reg_eldv); - i &= bits_eldv; + tmp = I915_READ(reg_eldv); + tmp &= bits_eldv; if (!eld[0]) - return !i; + return !tmp; - if (!i) + if (!tmp) return false; - i = I915_READ(reg_elda); - i &= ~bits_elda; - I915_WRITE(reg_elda, i); + tmp = I915_READ(reg_elda); + tmp &= ~bits_elda; + I915_WRITE(reg_elda, tmp); for (i = 0; i < eld[2]; i++) if (I915_READ(reg_edid) != *((uint32_t *)eld + i)) @@ -102,12 +103,11 @@ static void g4x_write_eld(struct drm_connector *connector, struct drm_i915_private *dev_priv = connector->dev->dev_private; uint8_t *eld = connector->eld; uint32_t eldv; - uint32_t len; - uint32_t i; - - i = I915_READ(G4X_AUD_VID_DID); + uint32_t tmp; + int len, i; - if (i == INTEL_AUDIO_DEVBLC || i == INTEL_AUDIO_DEVCL) + tmp = I915_READ(G4X_AUD_VID_DID); + if (tmp == INTEL_AUDIO_DEVBLC || tmp == INTEL_AUDIO_DEVCL) eldv = G4X_ELDV_DEVCL_DEVBLC; else eldv = G4X_ELDV_DEVCTG; @@ -118,22 +118,22 @@ static void g4x_write_eld(struct drm_connector *connector, G4X_HDMIW_HDMIEDID)) return; - i = I915_READ(G4X_AUD_CNTL_ST); - i &= ~(eldv | G4X_ELD_ADDR); - len = (i >> 9) & 0x1f; /* ELD buffer size */ - I915_WRITE(G4X_AUD_CNTL_ST, i); + tmp = I915_READ(G4X_AUD_CNTL_ST); + tmp &= ~(eldv | G4X_ELD_ADDR); + len = (tmp >> 9) & 0x1f; /* ELD buffer size */ + I915_WRITE(G4X_AUD_CNTL_ST, tmp); if (!eld[0]) return; - len = min_t(uint8_t, eld[2], len); + len = min_t(int, eld[2], len); DRM_DEBUG_DRIVER("ELD size %d\n", len); for (i = 0; i < len; i++) I915_WRITE(G4X_HDMIW_HDMIEDID, *((uint32_t *)eld + i)); - i = I915_READ(G4X_AUD_CNTL_ST); - i |= eldv; - I915_WRITE(G4X_AUD_CNTL_ST, i); + tmp = I915_READ(G4X_AUD_CNTL_ST); + tmp |= eldv; + I915_WRITE(G4X_AUD_CNTL_ST, tmp); } static void haswell_write_eld(struct drm_connector *connector, @@ -144,11 +144,10 @@ static void haswell_write_eld(struct drm_connector *connector, struct intel_crtc *intel_crtc = to_intel_crtc(crtc); uint8_t *eld = connector->eld; uint32_t eldv; - uint32_t i; - int len; - int pipe = to_intel_crtc(crtc)->pipe; - int tmp; - + uint32_t tmp; + int len, i; + enum pipe pipe = to_intel_crtc(crtc)->pipe; + enum port port; int hdmiw_hdmiedid = HSW_AUD_EDID_DATA(pipe); int aud_cntl_st = HSW_AUD_DIP_ELD_CTRL(pipe); int aud_config = HSW_AUD_CFG(pipe); @@ -196,28 +195,27 @@ static void haswell_write_eld(struct drm_connector *connector, hdmiw_hdmiedid)) return; - i = I915_READ(aud_cntrl_st2); - i &= ~eldv; - I915_WRITE(aud_cntrl_st2, i); + tmp = I915_READ(aud_cntrl_st2); + tmp &= ~eldv; + I915_WRITE(aud_cntrl_st2, tmp); if (!eld[0]) return; - i = I915_READ(aud_cntl_st); - i &= ~IBX_ELD_ADDRESS; - I915_WRITE(aud_cntl_st, i); - i = (i >> 29) & DIP_PORT_SEL_MASK; /* DIP_Port_Select, 0x1 = PortB */ - DRM_DEBUG_DRIVER("port num:%d\n", i); + tmp = I915_READ(aud_cntl_st); + tmp &= ~IBX_ELD_ADDRESS; + I915_WRITE(aud_cntl_st, tmp); + port = (tmp >> 29) & DIP_PORT_SEL_MASK; /* DIP_Port_Select, 0x1 = PortB */ + DRM_DEBUG_DRIVER("port num:%d\n", port); - len = min_t(uint8_t, eld[2], 21); /* 84 bytes of hw ELD buffer */ + len = min_t(int, eld[2], 21); /* 84 bytes of hw ELD buffer */ DRM_DEBUG_DRIVER("ELD size %d\n", len); for (i = 0; i < len; i++) I915_WRITE(hdmiw_hdmiedid, *((uint32_t *)eld + i)); - i = I915_READ(aud_cntrl_st2); - i |= eldv; - I915_WRITE(aud_cntrl_st2, i); - + tmp = I915_READ(aud_cntrl_st2); + tmp |= eldv; + I915_WRITE(aud_cntrl_st2, tmp); } static void ironlake_write_eld(struct drm_connector *connector, @@ -228,13 +226,14 @@ static void ironlake_write_eld(struct drm_connector *connector, struct intel_crtc *intel_crtc = to_intel_crtc(crtc); uint8_t *eld = connector->eld; uint32_t eldv; - uint32_t i; - int len; + uint32_t tmp; + int len, i; int hdmiw_hdmiedid; int aud_config; int aud_cntl_st; int aud_cntrl_st2; - int pipe = to_intel_crtc(crtc)->pipe; + enum pipe pipe = to_intel_crtc(crtc)->pipe; + enum port port; if (HAS_PCH_IBX(connector->dev)) { hdmiw_hdmiedid = IBX_HDMIW_HDMIEDID(pipe); @@ -261,22 +260,22 @@ static void ironlake_write_eld(struct drm_connector *connector, intel_encoder = intel_attached_encoder(connector); intel_dig_port = enc_to_dig_port(&intel_encoder->base); - i = intel_dig_port->port; + port = intel_dig_port->port; } else { - i = I915_READ(aud_cntl_st); - i = (i >> 29) & DIP_PORT_SEL_MASK; + tmp = I915_READ(aud_cntl_st); + port = (tmp >> 29) & DIP_PORT_SEL_MASK; /* DIP_Port_Select, 0x1 = PortB */ } - if (!i) { + if (!port) { DRM_DEBUG_DRIVER("Audio directed to unknown port\n"); /* operate blindly on all ports */ eldv = IBX_ELD_VALIDB; eldv |= IBX_ELD_VALIDB << 4; eldv |= IBX_ELD_VALIDB << 8; } else { - DRM_DEBUG_DRIVER("ELD on port %c\n", port_name(i)); - eldv = IBX_ELD_VALIDB << ((i - 1) * 4); + DRM_DEBUG_DRIVER("ELD on port %c\n", port_name(port)); + eldv = IBX_ELD_VALIDB << ((port - 1) * 4); } if (intel_pipe_has_type(intel_crtc, INTEL_OUTPUT_DISPLAYPORT)) { @@ -293,25 +292,25 @@ static void ironlake_write_eld(struct drm_connector *connector, hdmiw_hdmiedid)) return; - i = I915_READ(aud_cntrl_st2); - i &= ~eldv; - I915_WRITE(aud_cntrl_st2, i); + tmp = I915_READ(aud_cntrl_st2); + tmp &= ~eldv; + I915_WRITE(aud_cntrl_st2, tmp); if (!eld[0]) return; - i = I915_READ(aud_cntl_st); - i &= ~IBX_ELD_ADDRESS; - I915_WRITE(aud_cntl_st, i); + tmp = I915_READ(aud_cntl_st); + tmp &= ~IBX_ELD_ADDRESS; + I915_WRITE(aud_cntl_st, tmp); - len = min_t(uint8_t, eld[2], 21); /* 84 bytes of hw ELD buffer */ + len = min_t(int, eld[2], 21); /* 84 bytes of hw ELD buffer */ DRM_DEBUG_DRIVER("ELD size %d\n", len); for (i = 0; i < len; i++) I915_WRITE(hdmiw_hdmiedid, *((uint32_t *)eld + i)); - i = I915_READ(aud_cntrl_st2); - i |= eldv; - I915_WRITE(aud_cntrl_st2, i); + tmp = I915_READ(aud_cntrl_st2); + tmp |= eldv; + I915_WRITE(aud_cntrl_st2, tmp); } void intel_write_eld(struct drm_encoder *encoder, -- cgit v1.2.3 From 33d1e7c6f41656b62a0736a9f0eb977f5f1ff88f Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 27 Oct 2014 16:26:46 +0200 Subject: drm/i915: pass intel_encoder to intel_write_eld Everything else can be derived from that. No functional changes. Signed-off-by: Jani Nikula Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_audio.c | 9 +++++---- drivers/gpu/drm/i915/intel_ddi.c | 2 +- drivers/gpu/drm/i915/intel_dp.c | 2 +- drivers/gpu/drm/i915/intel_drv.h | 3 +-- drivers/gpu/drm/i915/intel_hdmi.c | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c index 00e9bfcd1e8d..829afd5305d1 100644 --- a/drivers/gpu/drm/i915/intel_audio.c +++ b/drivers/gpu/drm/i915/intel_audio.c @@ -313,10 +313,11 @@ static void ironlake_write_eld(struct drm_connector *connector, I915_WRITE(aud_cntrl_st2, tmp); } -void intel_write_eld(struct drm_encoder *encoder, - struct drm_display_mode *mode) +void intel_write_eld(struct intel_encoder *intel_encoder) { - struct drm_crtc *crtc = encoder->crtc; + struct drm_encoder *encoder = &intel_encoder->base; + struct intel_crtc *crtc = to_intel_crtc(encoder->crtc); + struct drm_display_mode *mode = &crtc->config.adjusted_mode; struct drm_connector *connector; struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -334,7 +335,7 @@ void intel_write_eld(struct drm_encoder *encoder, connector->eld[6] = drm_av_sync_delay(connector, mode) / 2; if (dev_priv->display.write_eld) - dev_priv->display.write_eld(connector, crtc, mode); + dev_priv->display.write_eld(connector, encoder->crtc, mode); } /** diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index cb5367c6f95a..2688bc940879 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1126,7 +1126,7 @@ static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder) /* write eld */ DRM_DEBUG_DRIVER("DDI audio: write eld information\n"); - intel_write_eld(encoder, &crtc->config.adjusted_mode); + intel_write_eld(intel_encoder); } if (type == INTEL_OUTPUT_EDP) { diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 64c8e047891d..b474a29d00d5 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1250,7 +1250,7 @@ static void intel_dp_prepare(struct intel_encoder *encoder) DRM_DEBUG_DRIVER("Enabling DP audio on pipe %c\n", pipe_name(crtc->pipe)); intel_dp->DP |= DP_AUDIO_OUTPUT_ENABLE; - intel_write_eld(&encoder->base, adjusted_mode); + intel_write_eld(encoder); } /* Split out the IBX/CPU vs CPT settings */ diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 3bbc4fe817ff..bf72a9201a15 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -850,8 +850,7 @@ void intel_fb_obj_flush(struct drm_i915_gem_object *obj, bool retire); /* intel_audio.c */ void intel_init_audio(struct drm_device *dev); -void intel_write_eld(struct drm_encoder *encoder, - struct drm_display_mode *mode); +void intel_write_eld(struct intel_encoder *encoder); /* intel_display.c */ const char *intel_output_name(int output); diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 8b5f3aa027f3..07b5ebd65d41 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -666,7 +666,7 @@ static void intel_hdmi_prepare(struct intel_encoder *encoder) DRM_DEBUG_DRIVER("Enabling HDMI audio on pipe %c\n", pipe_name(crtc->pipe)); hdmi_val |= SDVO_AUDIO_ENABLE; - intel_write_eld(&encoder->base, adjusted_mode); + intel_write_eld(encoder); } if (HAS_PCH_CPT(dev)) -- cgit v1.2.3 From 820d2d77482810702758381808bdbb64595298e2 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 27 Oct 2014 16:26:47 +0200 Subject: drm/i915/audio: pass intel_encoder on to platform specific ELD functions This will simplify things later on. No functional changes. Signed-off-by: Jani Nikula Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 4 ++-- drivers/gpu/drm/i915/intel_audio.c | 22 ++++++++++------------ 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 627b7e71f168..6a73803482cb 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -434,6 +434,7 @@ struct drm_i915_error_state { }; struct intel_connector; +struct intel_encoder; struct intel_crtc_config; struct intel_plane_config; struct intel_crtc; @@ -483,7 +484,7 @@ struct drm_i915_display_funcs { void (*crtc_disable)(struct drm_crtc *crtc); void (*off)(struct drm_crtc *crtc); void (*write_eld)(struct drm_connector *connector, - struct drm_crtc *crtc, + struct intel_encoder *encoder, struct drm_display_mode *mode); void (*fdi_link_train)(struct drm_crtc *crtc); void (*init_clock_gating)(struct drm_device *dev); @@ -2798,7 +2799,6 @@ static inline bool intel_gmbus_is_forced_bit(struct i2c_adapter *adapter) extern void intel_i2c_reset(struct drm_device *dev); /* intel_opregion.c */ -struct intel_encoder; #ifdef CONFIG_ACPI extern int intel_opregion_setup(struct drm_device *dev); extern void intel_opregion_init(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c index 829afd5305d1..4a384d780b20 100644 --- a/drivers/gpu/drm/i915/intel_audio.c +++ b/drivers/gpu/drm/i915/intel_audio.c @@ -97,7 +97,7 @@ static bool intel_eld_uptodate(struct drm_connector *connector, } static void g4x_write_eld(struct drm_connector *connector, - struct drm_crtc *crtc, + struct intel_encoder *encoder, struct drm_display_mode *mode) { struct drm_i915_private *dev_priv = connector->dev->dev_private; @@ -137,16 +137,16 @@ static void g4x_write_eld(struct drm_connector *connector, } static void haswell_write_eld(struct drm_connector *connector, - struct drm_crtc *crtc, + struct intel_encoder *encoder, struct drm_display_mode *mode) { struct drm_i915_private *dev_priv = connector->dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); uint8_t *eld = connector->eld; uint32_t eldv; uint32_t tmp; int len, i; - enum pipe pipe = to_intel_crtc(crtc)->pipe; + enum pipe pipe = intel_crtc->pipe; enum port port; int hdmiw_hdmiedid = HSW_AUD_EDID_DATA(pipe); int aud_cntl_st = HSW_AUD_DIP_ELD_CTRL(pipe); @@ -160,7 +160,7 @@ static void haswell_write_eld(struct drm_connector *connector, I915_WRITE(aud_cntrl_st2, tmp); POSTING_READ(aud_cntrl_st2); - assert_pipe_disabled(dev_priv, to_intel_crtc(crtc)->pipe); + assert_pipe_disabled(dev_priv, pipe); /* Set ELD valid state */ tmp = I915_READ(aud_cntrl_st2); @@ -219,11 +219,11 @@ static void haswell_write_eld(struct drm_connector *connector, } static void ironlake_write_eld(struct drm_connector *connector, - struct drm_crtc *crtc, + struct intel_encoder *encoder, struct drm_display_mode *mode) { struct drm_i915_private *dev_priv = connector->dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); uint8_t *eld = connector->eld; uint32_t eldv; uint32_t tmp; @@ -232,7 +232,7 @@ static void ironlake_write_eld(struct drm_connector *connector, int aud_config; int aud_cntl_st; int aud_cntrl_st2; - enum pipe pipe = to_intel_crtc(crtc)->pipe; + enum pipe pipe = intel_crtc->pipe; enum port port; if (HAS_PCH_IBX(connector->dev)) { @@ -255,11 +255,9 @@ static void ironlake_write_eld(struct drm_connector *connector, DRM_DEBUG_DRIVER("ELD on pipe %c\n", pipe_name(pipe)); if (IS_VALLEYVIEW(connector->dev)) { - struct intel_encoder *intel_encoder; struct intel_digital_port *intel_dig_port; - intel_encoder = intel_attached_encoder(connector); - intel_dig_port = enc_to_dig_port(&intel_encoder->base); + intel_dig_port = enc_to_dig_port(&encoder->base); port = intel_dig_port->port; } else { tmp = I915_READ(aud_cntl_st); @@ -335,7 +333,7 @@ void intel_write_eld(struct intel_encoder *intel_encoder) connector->eld[6] = drm_av_sync_delay(connector, mode) / 2; if (dev_priv->display.write_eld) - dev_priv->display.write_eld(connector, encoder->crtc, mode); + dev_priv->display.write_eld(connector, intel_encoder, mode); } /** -- cgit v1.2.3 From 6847d71bfc9b2855fb5fd0517309fb1adf9203ff Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Mon, 27 Oct 2014 17:47:52 -0200 Subject: drm/i915: transform INTEL_OUTPUT_* into an enum Because I got annoyed that I had to document what values "int ddi_personality" is supposed to hold. A good side-effect of this change is that now the compilers can do some additional checks on our code, which may prevent some bugs in the future. A bad side-effect of this change is that now the compilers do some additional checks on our code and complain when a switch statement doesn't check for all possible values, so we need to add "default" cases to all those switches. Hopefully, this may help preventing confusions against DRM_MODE_CONNECTOR_* and DRM_MODE_ENCODER_*. I guess that just by looking at the patch, some people will think this change is not worth its benefits. In this case, I don't really mind dropping the patch. Also, there's probably still a few more places where we can s/int/enum intel_output_type/, but we can change that later, when we spot the places. Signed-off-by: Paulo Zanoni [danvet: Resolve conflict due to reordered patches.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 2 ++ drivers/gpu/drm/i915/intel_display.c | 10 ++++++++++ drivers/gpu/drm/i915/intel_drv.h | 28 +++++++++++++++------------- 3 files changed, 27 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 61ea8da93c3b..a79f83ce9c84 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2971,6 +2971,8 @@ static int i9xx_pipe_crc_auto_source(struct drm_device *dev, enum pipe pipe, break; } break; + default: + break; } } drm_modeset_unlock_all(dev); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index aeda09dcfb72..ee982f5412d6 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6269,6 +6269,8 @@ static int i9xx_crtc_mode_set(struct intel_crtc *crtc, case INTEL_OUTPUT_DSI: is_dsi = true; break; + default: + break; } num_connectors++; @@ -6597,6 +6599,8 @@ static void ironlake_init_pch_refclk(struct drm_device *dev) if (enc_to_dig_port(&encoder->base)->port == PORT_A) has_cpu_edp = true; break; + default: + break; } } @@ -6901,6 +6905,8 @@ static void lpt_init_pch_refclk(struct drm_device *dev) case INTEL_OUTPUT_ANALOG: has_vga = true; break; + default: + break; } } @@ -6934,6 +6940,8 @@ static int ironlake_get_refclk(struct drm_crtc *crtc) case INTEL_OUTPUT_LVDS: is_lvds = true; break; + default: + break; } num_connectors++; } @@ -7188,6 +7196,8 @@ static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc, case INTEL_OUTPUT_HDMI: is_sdvo = true; break; + default: + break; } num_connectors++; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index bf72a9201a15..1e58e64aaecc 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -94,18 +94,20 @@ /* these are outputs from the chip - integrated only external chips are via DVO or SDVO output */ -#define INTEL_OUTPUT_UNUSED 0 -#define INTEL_OUTPUT_ANALOG 1 -#define INTEL_OUTPUT_DVO 2 -#define INTEL_OUTPUT_SDVO 3 -#define INTEL_OUTPUT_LVDS 4 -#define INTEL_OUTPUT_TVOUT 5 -#define INTEL_OUTPUT_HDMI 6 -#define INTEL_OUTPUT_DISPLAYPORT 7 -#define INTEL_OUTPUT_EDP 8 -#define INTEL_OUTPUT_DSI 9 -#define INTEL_OUTPUT_UNKNOWN 10 -#define INTEL_OUTPUT_DP_MST 11 +enum intel_output_type { + INTEL_OUTPUT_UNUSED = 0, + INTEL_OUTPUT_ANALOG = 1, + INTEL_OUTPUT_DVO = 2, + INTEL_OUTPUT_SDVO = 3, + INTEL_OUTPUT_LVDS = 4, + INTEL_OUTPUT_TVOUT = 5, + INTEL_OUTPUT_HDMI = 6, + INTEL_OUTPUT_DISPLAYPORT = 7, + INTEL_OUTPUT_EDP = 8, + INTEL_OUTPUT_DSI = 9, + INTEL_OUTPUT_UNKNOWN = 10, + INTEL_OUTPUT_DP_MST = 11, +}; #define INTEL_DVO_CHIP_NONE 0 #define INTEL_DVO_CHIP_LVDS 1 @@ -136,7 +138,7 @@ struct intel_encoder { */ struct intel_crtc *new_crtc; - int type; + enum intel_output_type type; unsigned int cloneable; bool connectors_active; void (*hot_plug)(struct intel_encoder *); -- cgit v1.2.3 From c17ed5b5a46ec715620b0548a187d3ed98f4cf0b Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Thu, 16 Oct 2014 21:27:27 +0300 Subject: drm/i915: Warn if trying to register eDP on port != B/C on vlv/chv MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only ports B and C have the power sequencer and backlight controls, so complain if we ever try to register an eDP connector on some other port. Signed-off-by: Ville Syrjälä Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index b474a29d00d5..3f1858065a1c 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -5203,6 +5203,11 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, if (type == DRM_MODE_CONNECTOR_eDP) intel_encoder->type = INTEL_OUTPUT_EDP; + /* eDP only on port B and/or C on vlv/chv */ + if (WARN_ON(IS_VALLEYVIEW(dev) && is_edp(intel_dp) && + port != PORT_B && port != PORT_C)) + return false; + DRM_DEBUG_KMS("Adding %s connector on port %c\n", type == DRM_MODE_CONNECTOR_eDP ? "eDP" : "DP", port_name(port)); -- cgit v1.2.3 From 7a66800e035bb6a64c2d0f8cb315edabbef819b9 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Thu, 16 Oct 2014 21:27:29 +0300 Subject: drm/i915: Remove high level intel_edp_vdd_{on, off}() from hpd/detect MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit want_panel_vdd is a bool so it can't cope with interleaving on/off calls from multiple threads. If we want to make that possible we'd need to convert want_panel_vdd into a proper ref count. But an easier fix is to remove the high level vdd on/off calls from detect/hpd code paths and just rely on the delayed vdd off to avoid needless vdd on<->off ping pong. After this change only the encoder enable/disable paths use the high level functions, which is fine since both the on and off low level edp vdd calls from intel_dp_aux_ch() happen without dropping pps_mutex in between and so want_panel_vdd can't change in between. Signed-off-by: Ville Syrjälä Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 3f1858065a1c..9076e9a04f82 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -3846,8 +3846,6 @@ intel_dp_probe_oui(struct intel_dp *intel_dp) if (!(intel_dp->dpcd[DP_DOWN_STREAM_PORT_COUNT] & DP_OUI_SUPPORT)) return; - intel_edp_panel_vdd_on(intel_dp); - if (intel_dp_dpcd_read_wake(&intel_dp->aux, DP_SINK_OUI, buf, 3) == 3) DRM_DEBUG_KMS("Sink OUI: %02hx%02hx%02hx\n", buf[0], buf[1], buf[2]); @@ -3855,8 +3853,6 @@ intel_dp_probe_oui(struct intel_dp *intel_dp) if (intel_dp_dpcd_read_wake(&intel_dp->aux, DP_BRANCH_OUI, buf, 3) == 3) DRM_DEBUG_KMS("Branch OUI: %02hx%02hx%02hx\n", buf[0], buf[1], buf[2]); - - intel_edp_panel_vdd_off(intel_dp, false); } static bool @@ -3870,7 +3866,6 @@ intel_dp_probe_mst(struct intel_dp *intel_dp) if (intel_dp->dpcd[DP_DPCD_REV] < 0x12) return false; - intel_edp_panel_vdd_on(intel_dp); if (intel_dp_dpcd_read_wake(&intel_dp->aux, DP_MSTM_CAP, buf, 1)) { if (buf[0] & DP_MST_CAP) { DRM_DEBUG_KMS("Sink is MST capable\n"); @@ -3880,7 +3875,6 @@ intel_dp_probe_mst(struct intel_dp *intel_dp) intel_dp->is_mst = false; } } - intel_edp_panel_vdd_off(intel_dp, false); drm_dp_mst_topology_mgr_set_mst(&intel_dp->mst_mgr, intel_dp->is_mst); return intel_dp->is_mst; @@ -5086,9 +5080,7 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp, intel_edp_panel_vdd_sanitize(intel_encoder); /* Cache DPCD and EDID for edp. */ - intel_edp_panel_vdd_on(intel_dp); has_dpcd = intel_dp_get_dpcd(intel_dp); - intel_edp_panel_vdd_off(intel_dp, false); if (has_dpcd) { if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11) -- cgit v1.2.3 From 36b5f425dd560d37f5633cf317818377c1db70de Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Thu, 16 Oct 2014 21:27:30 +0300 Subject: drm/i915: Store power sequencer delays in intel_dp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The power seqeuncer delays are fixed for a given panel, so we can keep them around once computed. Not that on VLV/CHV we still re-compute them every time we initialize the power seqeuncer registers, but that will change soon enough. Signed-off-by: Ville Syrjälä Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 52 +++++++++++++++------------------------- drivers/gpu/drm/i915/intel_drv.h | 1 + 2 files changed, 20 insertions(+), 33 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 9076e9a04f82..269403154751 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -283,12 +283,10 @@ intel_hrawclk(struct drm_device *dev) static void intel_dp_init_panel_power_sequencer(struct drm_device *dev, - struct intel_dp *intel_dp, - struct edp_power_seq *out); + struct intel_dp *intel_dp); static void intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev, - struct intel_dp *intel_dp, - struct edp_power_seq *out); + struct intel_dp *intel_dp); static void pps_lock(struct intel_dp *intel_dp) { @@ -330,7 +328,6 @@ vlv_power_sequencer_pipe(struct intel_dp *intel_dp) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_encoder *encoder; unsigned int pipes = (1 << PIPE_A) | (1 << PIPE_B); - struct edp_power_seq power_seq; lockdep_assert_held(&dev_priv->pps_mutex); @@ -368,9 +365,8 @@ vlv_power_sequencer_pipe(struct intel_dp *intel_dp) port_name(intel_dig_port->port)); /* init power sequencer on this pipe and port */ - intel_dp_init_panel_power_sequencer(dev, intel_dp, &power_seq); - intel_dp_init_panel_power_sequencer_registers(dev, intel_dp, - &power_seq); + intel_dp_init_panel_power_sequencer(dev, intel_dp); + intel_dp_init_panel_power_sequencer_registers(dev, intel_dp); return intel_dp->pps_pipe; } @@ -425,7 +421,6 @@ vlv_initial_power_sequencer_setup(struct intel_dp *intel_dp) 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; - struct edp_power_seq power_seq; enum port port = intel_dig_port->port; lockdep_assert_held(&dev_priv->pps_mutex); @@ -453,9 +448,8 @@ vlv_initial_power_sequencer_setup(struct intel_dp *intel_dp) DRM_DEBUG_KMS("initial power sequencer for port %c: pipe %c\n", port_name(port), pipe_name(intel_dp->pps_pipe)); - intel_dp_init_panel_power_sequencer(dev, intel_dp, &power_seq); - intel_dp_init_panel_power_sequencer_registers(dev, intel_dp, - &power_seq); + intel_dp_init_panel_power_sequencer(dev, intel_dp); + intel_dp_init_panel_power_sequencer_registers(dev, intel_dp); } void vlv_power_sequencer_reset(struct drm_i915_private *dev_priv) @@ -2620,7 +2614,6 @@ static void vlv_init_panel_power_sequencer(struct intel_dp *intel_dp) struct drm_device *dev = encoder->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc); - struct edp_power_seq power_seq; lockdep_assert_held(&dev_priv->pps_mutex); @@ -2648,9 +2641,8 @@ static void vlv_init_panel_power_sequencer(struct intel_dp *intel_dp) pipe_name(intel_dp->pps_pipe), port_name(intel_dig_port->port)); /* init power sequencer on this pipe and port */ - intel_dp_init_panel_power_sequencer(dev, intel_dp, &power_seq); - intel_dp_init_panel_power_sequencer_registers(dev, intel_dp, - &power_seq); + intel_dp_init_panel_power_sequencer(dev, intel_dp); + intel_dp_init_panel_power_sequencer_registers(dev, intel_dp); } static void vlv_pre_enable_dp(struct intel_encoder *encoder) @@ -4731,11 +4723,11 @@ static void intel_dp_init_panel_power_timestamps(struct intel_dp *intel_dp) static void intel_dp_init_panel_power_sequencer(struct drm_device *dev, - struct intel_dp *intel_dp, - struct edp_power_seq *out) + struct intel_dp *intel_dp) { struct drm_i915_private *dev_priv = dev->dev_private; - struct edp_power_seq cur, vbt, spec, final; + struct edp_power_seq cur, vbt, spec, + *final = &intel_dp->pps_delays; u32 pp_on, pp_off, pp_div, pp; int pp_ctrl_reg, pp_on_reg, pp_off_reg, pp_div_reg; @@ -4802,7 +4794,7 @@ intel_dp_init_panel_power_sequencer(struct drm_device *dev, /* 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 ? \ +#define assign_final(field) final->field = (max(cur.field, vbt.field) == 0 ? \ spec.field : \ max(cur.field, vbt.field)) assign_final(t1_t3); @@ -4812,7 +4804,7 @@ intel_dp_init_panel_power_sequencer(struct drm_device *dev, assign_final(t11_t12); #undef assign_final -#define get_delay(field) (DIV_ROUND_UP(final.field, 10)) +#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); @@ -4826,21 +4818,18 @@ intel_dp_init_panel_power_sequencer(struct drm_device *dev, DRM_DEBUG_KMS("backlight on delay %d, off delay %d\n", intel_dp->backlight_on_delay, intel_dp->backlight_off_delay); - - if (out) - *out = final; } static void intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev, - struct intel_dp *intel_dp, - struct edp_power_seq *seq) + struct intel_dp *intel_dp) { struct drm_i915_private *dev_priv = dev->dev_private; u32 pp_on, pp_off, pp_div, port_sel = 0; int div = HAS_PCH_SPLIT(dev) ? intel_pch_rawclk(dev) : intel_hrawclk(dev); int pp_on_reg, pp_off_reg, pp_div_reg; enum port port = dp_to_dig_port(intel_dp)->port; + const struct edp_power_seq *seq = &intel_dp->pps_delays; lockdep_assert_held(&dev_priv->pps_mutex); @@ -5058,8 +5047,7 @@ void intel_edp_panel_vdd_sanitize(struct intel_encoder *intel_encoder) } static bool intel_edp_init_connector(struct intel_dp *intel_dp, - struct intel_connector *intel_connector, - struct edp_power_seq *power_seq) + struct intel_connector *intel_connector) { struct drm_connector *connector = &intel_connector->base; struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); @@ -5095,7 +5083,7 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp, /* We now know it's not a ghost, init power sequence regs. */ pps_lock(intel_dp); - intel_dp_init_panel_power_sequencer_registers(dev, intel_dp, power_seq); + intel_dp_init_panel_power_sequencer_registers(dev, intel_dp); pps_unlock(intel_dp); mutex_lock(&dev->mode_config.mutex); @@ -5156,7 +5144,6 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, struct drm_device *dev = intel_encoder->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; enum port port = intel_dig_port->port; - struct edp_power_seq power_seq = { 0 }; int type; intel_dp->pps_pipe = INVALID_PIPE; @@ -5246,8 +5233,7 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, vlv_initial_power_sequencer_setup(intel_dp); } else { intel_dp_init_panel_power_timestamps(intel_dp); - intel_dp_init_panel_power_sequencer(dev, intel_dp, - &power_seq); + intel_dp_init_panel_power_sequencer(dev, intel_dp); } pps_unlock(intel_dp); } @@ -5262,7 +5248,7 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, } } - if (!intel_edp_init_connector(intel_dp, intel_connector, &power_seq)) { + if (!intel_edp_init_connector(intel_dp, intel_connector)) { drm_dp_aux_unregister(&intel_dp->aux); if (is_edp(intel_dp)) { cancel_delayed_work_sync(&intel_dp->panel_vdd_work); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 1e58e64aaecc..b323c9b01c40 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -592,6 +592,7 @@ struct intel_dp { * this port. Only relevant on VLV/CHV. */ enum pipe pps_pipe; + struct edp_power_seq pps_delays; bool use_tps3; bool can_mst; /* this port supports mst */ -- cgit v1.2.3 From 81ddbc69992a1f29aeb2a5b183e5228cc7c49caf Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Thu, 16 Oct 2014 21:27:31 +0300 Subject: drm/i915: Don't initialize power seqeuencer delays more than once MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since we read the current power seqeuncer delays from the registers (as well as looking at the vbt and spec values) we may end up corrupting delays we already initialized when we switch to another pipe and the power seqeuncer there has different values currently in the registers. So make sure we only initialize the delays once even if intel_dp_init_panel_power_sequencer() gets called multiple times. There was some discussion in the review about when exactly we need to unlock the pps. Quoting Bspec: "If this bit is not a zero, it activates the register write protect and writes to those registers will be ignored unless the write protect key value is set in the panel sequencing control register." Signed-off-by: Ville Syrjälä Reviewed-by: Imre Deak [danvet: Add Bspec quote per review discussion between Imre and Ville.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 269403154751..e1894cea44cc 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -4733,6 +4733,10 @@ intel_dp_init_panel_power_sequencer(struct drm_device *dev, lockdep_assert_held(&dev_priv->pps_mutex); + /* already initialized? */ + if (final->t11_t12 != 0) + return; + if (HAS_PCH_SPLIT(dev)) { pp_ctrl_reg = PCH_PP_CONTROL; pp_on_reg = PCH_PP_ON_DELAYS; -- cgit v1.2.3 From 9f0fb5bec73e4afd84d4dec040a9d54a971620ae Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Thu, 16 Oct 2014 21:27:32 +0300 Subject: drm/i915: Split power sequencer panel on/off functions to locked and unlocked variants MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We'll be needing to the call the power seqeuencer functions while already holding pps_mutex, so split the locking out to small wrapper functions. Signed-off-by: Ville Syrjälä Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index e1894cea44cc..c97bb5c8c62a 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1555,23 +1555,23 @@ static void intel_edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync) pps_unlock(intel_dp); } -void intel_edp_panel_on(struct intel_dp *intel_dp) +static void edp_panel_on(struct intel_dp *intel_dp) { struct drm_device *dev = intel_dp_to_dev(intel_dp); struct drm_i915_private *dev_priv = dev->dev_private; u32 pp; u32 pp_ctrl_reg; + lockdep_assert_held(&dev_priv->pps_mutex); + if (!is_edp(intel_dp)) return; DRM_DEBUG_KMS("Turn eDP power on\n"); - pps_lock(intel_dp); - if (edp_have_panel_power(intel_dp)) { DRM_DEBUG_KMS("eDP power already on\n"); - goto out; + return; } wait_panel_power_cycle(intel_dp); @@ -1600,12 +1600,20 @@ void intel_edp_panel_on(struct intel_dp *intel_dp) I915_WRITE(pp_ctrl_reg, pp); POSTING_READ(pp_ctrl_reg); } +} - out: +void intel_edp_panel_on(struct intel_dp *intel_dp) +{ + if (!is_edp(intel_dp)) + return; + + pps_lock(intel_dp); + edp_panel_on(intel_dp); pps_unlock(intel_dp); } -void intel_edp_panel_off(struct intel_dp *intel_dp) + +static void edp_panel_off(struct intel_dp *intel_dp) { struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); struct intel_encoder *intel_encoder = &intel_dig_port->base; @@ -1615,13 +1623,13 @@ void intel_edp_panel_off(struct intel_dp *intel_dp) u32 pp; u32 pp_ctrl_reg; + lockdep_assert_held(&dev_priv->pps_mutex); + if (!is_edp(intel_dp)) return; DRM_DEBUG_KMS("Turn eDP power off\n"); - pps_lock(intel_dp); - WARN(!intel_dp->want_panel_vdd, "Need VDD to turn off panel\n"); pp = ironlake_get_pp_control(intel_dp); @@ -1643,7 +1651,15 @@ void intel_edp_panel_off(struct intel_dp *intel_dp) /* We got a reference when we enabled the VDD. */ power_domain = intel_display_port_power_domain(intel_encoder); intel_display_power_put(dev_priv, power_domain); +} +void intel_edp_panel_off(struct intel_dp *intel_dp) +{ + if (!is_edp(intel_dp)) + return; + + pps_lock(intel_dp); + edp_panel_off(intel_dp); pps_unlock(intel_dp); } -- cgit v1.2.3 From 093e3f134e2eff13503f708b81aecc2501e7aecb Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Thu, 16 Oct 2014 21:27:33 +0300 Subject: drm/i915: Hold the pps mutex across the whole panel power enable sequence MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Just grab the pps_mutex once and do all the pps panel startup operations while holding the mutex instead of grabbing the mutex separately for each individual step. Signed-off-by: Ville Syrjälä Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 47 ++++++++++++++--------------------------- 1 file changed, 16 insertions(+), 31 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index c97bb5c8c62a..cad4e112cfaa 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -113,6 +113,7 @@ static struct intel_dp *intel_attached_dp(struct drm_connector *connector) static void intel_dp_link_down(struct intel_dp *intel_dp); static bool edp_panel_vdd_on(struct intel_dp *intel_dp); static void edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync); +static void vlv_init_panel_power_sequencer(struct intel_dp *intel_dp); int intel_dp_max_link_bw(struct intel_dp *intel_dp) @@ -1539,22 +1540,6 @@ static void edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync) edp_panel_vdd_schedule_off(intel_dp); } -/* - * Must be paired with intel_edp_panel_vdd_on(). - * Nested calls to these functions are not allowed since - * we drop the lock. Caller must use some higher level - * locking to prevent nested calls from other threads. - */ -static void intel_edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync) -{ - if (!is_edp(intel_dp)) - return; - - pps_lock(intel_dp); - edp_panel_vdd_off(intel_dp, sync); - pps_unlock(intel_dp); -} - static void edp_panel_on(struct intel_dp *intel_dp) { struct drm_device *dev = intel_dp_to_dev(intel_dp); @@ -2552,10 +2537,19 @@ static void intel_enable_dp(struct intel_encoder *encoder) if (WARN_ON(dp_reg & DP_PORT_EN)) return; + pps_lock(intel_dp); + + if (IS_VALLEYVIEW(dev)) + vlv_init_panel_power_sequencer(intel_dp); + intel_dp_enable_port(intel_dp); - intel_edp_panel_vdd_on(intel_dp); - intel_edp_panel_on(intel_dp); - intel_edp_panel_vdd_off(intel_dp, true); + + edp_panel_vdd_on(intel_dp); + edp_panel_on(intel_dp); + edp_panel_vdd_off(intel_dp, true); + + pps_unlock(intel_dp); + intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON); intel_dp_start_link_train(intel_dp); intel_dp_complete_link_train(intel_dp); @@ -2633,6 +2627,9 @@ static void vlv_init_panel_power_sequencer(struct intel_dp *intel_dp) lockdep_assert_held(&dev_priv->pps_mutex); + if (!is_edp(intel_dp)) + return; + if (intel_dp->pps_pipe == crtc->pipe) return; @@ -2687,12 +2684,6 @@ static void vlv_pre_enable_dp(struct intel_encoder *encoder) mutex_unlock(&dev_priv->dpio_lock); - if (is_edp(intel_dp)) { - pps_lock(intel_dp); - vlv_init_panel_power_sequencer(intel_dp); - pps_unlock(intel_dp); - } - intel_enable_dp(encoder); vlv_wait_port_ready(dev_priv, dport); @@ -2787,12 +2778,6 @@ static void chv_pre_enable_dp(struct intel_encoder *encoder) mutex_unlock(&dev_priv->dpio_lock); - if (is_edp(intel_dp)) { - pps_lock(intel_dp); - vlv_init_panel_power_sequencer(intel_dp); - pps_unlock(intel_dp); - } - intel_enable_dp(encoder); vlv_wait_port_ready(dev_priv, dport); -- cgit v1.2.3 From 61234fa5e5232c35f87d44d9d596af4b10eac255 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Thu, 16 Oct 2014 21:27:34 +0300 Subject: drm/i915: Wait for PHY port ready before link training on VLV/CHV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There's no point in checking if the data lanes came out of reset after link training. If the data lanes aren't ready link training will fail anyway. Suggested-by: Todd Previte Cc: Todd Previte Signed-off-by: Ville Syrjälä Reviewed-by: Imre Deak Acked-by: Todd Previte Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index cad4e112cfaa..f3b6cd5057ea 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -2550,6 +2550,9 @@ static void intel_enable_dp(struct intel_encoder *encoder) pps_unlock(intel_dp); + if (IS_VALLEYVIEW(dev)) + vlv_wait_port_ready(dev_priv, dp_to_dig_port(intel_dp)); + intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON); intel_dp_start_link_train(intel_dp); intel_dp_complete_link_train(intel_dp); @@ -2685,8 +2688,6 @@ static void vlv_pre_enable_dp(struct intel_encoder *encoder) mutex_unlock(&dev_priv->dpio_lock); intel_enable_dp(encoder); - - vlv_wait_port_ready(dev_priv, dport); } static void vlv_dp_pre_pll_enable(struct intel_encoder *encoder) @@ -2779,8 +2780,6 @@ static void chv_pre_enable_dp(struct intel_encoder *encoder) mutex_unlock(&dev_priv->dpio_lock); intel_enable_dp(encoder); - - vlv_wait_port_ready(dev_priv, dport); } static void chv_dp_pre_pll_enable(struct intel_encoder *encoder) -- cgit v1.2.3 From 7b713f50d78b68c04c86eb21e59faf7247aa2cd1 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Thu, 16 Oct 2014 21:27:35 +0300 Subject: drm/i915: Fix eDP link training when switching pipes on VLV/CHV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When switching from one pipe to another, the power sequencer of the new pipe seems to need a bit of kicking to lock into the port. Even the vdd force bit doesn't work before the power sequencer has been sufficiently kicked, so this must be done before any AUX transactions are attempted. After extensive experimentation I've determined that it's sufficient to first write the port register with the correct values except the port must remain disabled, then we can do a second write to enable the port, after which the power sequencer is operational and allows the port to start up properly. Contrary to my earlier theories we don't need to enable the port with the idle pattern, so let's just use training pattern 1 as that's what other platforms use here. v2: Refine the kick procedure Signed-off-by: Ville Syrjälä Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index f3b6cd5057ea..823355705a5e 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -2517,14 +2517,23 @@ static void intel_dp_enable_port(struct intel_dp *intel_dp) struct drm_device *dev = intel_dp_to_dev(intel_dp); struct drm_i915_private *dev_priv = dev->dev_private; - intel_dp->DP |= DP_PORT_EN; - /* enable with pattern 1 (as per spec) */ _intel_dp_set_link_train(intel_dp, &intel_dp->DP, DP_TRAINING_PATTERN_1); I915_WRITE(intel_dp->output_reg, intel_dp->DP); POSTING_READ(intel_dp->output_reg); + + /* + * Magic for VLV/CHV. We _must_ first set up the register + * without actually enabling the port, and then do another + * write to enable the port. Otherwise link training will + * fail when the power sequencer is freshly used for this port. + */ + intel_dp->DP |= DP_PORT_EN; + + I915_WRITE(intel_dp->output_reg, intel_dp->DP); + POSTING_READ(intel_dp->output_reg); } static void intel_enable_dp(struct intel_encoder *encoder) -- cgit v1.2.3 From 961a0db00977ff98ff99d942ae4c046423e1aebc Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Thu, 16 Oct 2014 21:29:42 +0300 Subject: drm/i915: Kick the power sequencer before AUX transactions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When we pick a new power sequencer for the port but we're not doing a full modeset, the power sequencer may have locked on to another port (or no port). So kick it a bit to make sure it controls the port we want. Again just like when we attempt to actually enable the DP port, we must first write the port register with the approriate value except the enable bit, and then we must enable the port to make the power sequencer happy. In this case since we don't want the port actually enabled we just toggle it on and immediately back off. Going forward the power sequencer will keep working on that specific port until again moved to another port. v2: Refine the kick procedure Signed-off-by: Ville Syrjälä Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 52 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 823355705a5e..4f7df371c098 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -321,6 +321,52 @@ static void pps_unlock(struct intel_dp *intel_dp) intel_display_power_put(dev_priv, power_domain); } +static void +vlv_power_sequencer_kick(struct intel_dp *intel_dp) +{ + 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 pipe pipe = intel_dp->pps_pipe; + uint32_t DP; + + if (WARN(I915_READ(intel_dp->output_reg) & DP_PORT_EN, + "skipping pipe %c power seqeuncer kick due to port %c being active\n", + pipe_name(pipe), port_name(intel_dig_port->port))) + return; + + DRM_DEBUG_KMS("kicking pipe %c power sequencer for port %c\n", + pipe_name(pipe), port_name(intel_dig_port->port)); + + /* Preserve the BIOS-computed detected bit. This is + * supposed to be read-only. + */ + DP = I915_READ(intel_dp->output_reg) & DP_DETECTED; + DP |= DP_VOLTAGE_0_4 | DP_PRE_EMPHASIS_0; + DP |= DP_PORT_WIDTH(1); + DP |= DP_LINK_TRAIN_PAT_1; + + if (IS_CHERRYVIEW(dev)) + DP |= DP_PIPE_SELECT_CHV(pipe); + else if (pipe == PIPE_B) + DP |= DP_PIPEB_SELECT; + + /* + * Similar magic as in intel_dp_enable_port(). + * We _must_ do this port enable + disable trick + * to make this power seqeuencer lock onto the port. + * Otherwise even VDD force bit won't work. + */ + I915_WRITE(intel_dp->output_reg, DP); + POSTING_READ(intel_dp->output_reg); + + I915_WRITE(intel_dp->output_reg, DP | DP_PORT_EN); + POSTING_READ(intel_dp->output_reg); + + I915_WRITE(intel_dp->output_reg, DP & ~DP_PORT_EN); + POSTING_READ(intel_dp->output_reg); +} + static enum pipe vlv_power_sequencer_pipe(struct intel_dp *intel_dp) { @@ -369,6 +415,12 @@ vlv_power_sequencer_pipe(struct intel_dp *intel_dp) intel_dp_init_panel_power_sequencer(dev, intel_dp); intel_dp_init_panel_power_sequencer_registers(dev, intel_dp); + /* + * Even vdd force doesn't work until we've made + * the power sequencer lock in on the port. + */ + vlv_power_sequencer_kick(intel_dp); + return intel_dp->pps_pipe; } -- cgit v1.2.3 From 9a42356b964dee6418d8b812109298658cc8dc38 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Thu, 16 Oct 2014 21:29:48 +0300 Subject: drm/i915: Don't kick the power seqeuncer just to check if we have vdd/panel power MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If there's no power sequencer assigned to the port currently we can't very well have vdd or panel power enabled either. If we would try to check that from the pps registers we'd need to pick a power seqeuncer and kick it. So let's skip the register read and the kick. Note that there's still a bit an issue about correctly recovering pps state from resume if the bios is nasty: With this check we'll always assume that the pps is off. But that's better done in a follow-up patch and it shouldn't be too harmful - at most we waste time enabling the pps if it's on already. Signed-off-by: Ville Syrjälä Reviewed-by: Imre Deak [danvet: Add note about resume issues Imre spotted.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 4f7df371c098..451dd253b5d6 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -597,6 +597,10 @@ static bool edp_have_panel_power(struct intel_dp *intel_dp) lockdep_assert_held(&dev_priv->pps_mutex); + if (IS_VALLEYVIEW(dev) && + intel_dp->pps_pipe == INVALID_PIPE) + return false; + return (I915_READ(_pp_stat_reg(intel_dp)) & PP_ON) != 0; } @@ -607,6 +611,10 @@ static bool edp_have_panel_vdd(struct intel_dp *intel_dp) lockdep_assert_held(&dev_priv->pps_mutex); + if (IS_VALLEYVIEW(dev) && + intel_dp->pps_pipe == INVALID_PIPE) + return false; + return I915_READ(_pp_ctrl_reg(intel_dp)) & EDP_FORCE_VDD; } -- cgit v1.2.3 From 83b8459756659ce55446e3eb97d64b966c60bfb9 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Thu, 16 Oct 2014 21:29:51 +0300 Subject: drm/i915: Clear PPS port select when giving up the power sequencer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit VLV gets confused if two power sequencers have the same port selected. It would seem the port doesn't start up properly in the is case and vlv_wait_port_ready() will fail as will the link training. Clearing the port select in the PP_ON_DELAYS register fixes this problem. CHV doesn't seem to need this, but it doesn't seem to hurt either so let's just do it for both to keep the code between the platforms as uniform as possible. Signed-off-by: Ville Syrjälä Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 451dd253b5d6..04d7bc730995 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -2657,6 +2657,32 @@ static void g4x_pre_enable_dp(struct intel_encoder *encoder) } } +static void vlv_detach_power_sequencer(struct intel_dp *intel_dp) +{ + struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); + struct drm_i915_private *dev_priv = intel_dig_port->base.base.dev->dev_private; + enum pipe pipe = intel_dp->pps_pipe; + int pp_on_reg = VLV_PIPE_PP_ON_DELAYS(pipe); + + edp_panel_vdd_off_sync(intel_dp); + + /* + * VLV seems to get confused when multiple power seqeuencers + * have the same port selected (even if only one has power/vdd + * enabled). The failure manifests as vlv_wait_port_ready() failing + * CHV on the other hand doesn't seem to mind having the same port + * selected in multiple power seqeuencers, but let's clear the + * port select always when logically disconnecting a power sequencer + * from a port. + */ + DRM_DEBUG_KMS("detaching pipe %c power sequencer from port %c\n", + pipe_name(pipe), port_name(intel_dig_port->port)); + I915_WRITE(pp_on_reg, 0); + POSTING_READ(pp_on_reg); + + intel_dp->pps_pipe = INVALID_PIPE; +} + static void vlv_steal_power_sequencer(struct drm_device *dev, enum pipe pipe) { @@ -2683,9 +2709,7 @@ static void vlv_steal_power_sequencer(struct drm_device *dev, pipe_name(pipe), port_name(port)); /* make sure vdd is off before we steal it */ - edp_panel_vdd_off_sync(intel_dp); - - intel_dp->pps_pipe = INVALID_PIPE; + vlv_detach_power_sequencer(intel_dp); } } @@ -2711,7 +2735,7 @@ static void vlv_init_panel_power_sequencer(struct intel_dp *intel_dp) * we still have control of it. */ if (intel_dp->pps_pipe != INVALID_PIPE) - edp_panel_vdd_off_sync(intel_dp); + vlv_detach_power_sequencer(intel_dp); /* * We may be stealing the power -- cgit v1.2.3 From ac3c12e4e5a31b75b2621f8f23336bebbe3dbff4 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Thu, 16 Oct 2014 21:29:56 +0300 Subject: drm/i915: Warn if stealing non pipe A/B power sequencer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There's no power sequencer on pipe C on VLV/CHV so scream a bit if we try to steal one from pipes other than A and B. Signed-off-by: Ville Syrjälä Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 04d7bc730995..7df024c63bff 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -2691,6 +2691,9 @@ static void vlv_steal_power_sequencer(struct drm_device *dev, lockdep_assert_held(&dev_priv->pps_mutex); + if (WARN_ON(pipe != PIPE_A && pipe != PIPE_B)) + return; + list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) { struct intel_dp *intel_dp; -- cgit v1.2.3 From a8c3344e069e9c483b1fd328e14fbc6235073649 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Thu, 16 Oct 2014 21:29:59 +0300 Subject: drm/i915: Steal power sequencer in vlv_power_sequencer_pipe() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In case we fumble something and end up picking an already used power seqeuencer in vlv_power_sequencer_pipe() at least try to steal it gracefully. In theory this should never happen though. Signed-off-by: Ville Syrjälä Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 7df024c63bff..1900c4d48376 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -114,6 +114,8 @@ static void intel_dp_link_down(struct intel_dp *intel_dp); static bool edp_panel_vdd_on(struct intel_dp *intel_dp); static void edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync); static void vlv_init_panel_power_sequencer(struct intel_dp *intel_dp); +static void vlv_steal_power_sequencer(struct drm_device *dev, + enum pipe pipe); int intel_dp_max_link_bw(struct intel_dp *intel_dp) @@ -375,9 +377,13 @@ vlv_power_sequencer_pipe(struct intel_dp *intel_dp) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_encoder *encoder; unsigned int pipes = (1 << PIPE_A) | (1 << PIPE_B); + enum pipe pipe; lockdep_assert_held(&dev_priv->pps_mutex); + /* We should never land here with regular DP ports */ + WARN_ON(!is_edp(intel_dp)); + if (intel_dp->pps_pipe != INVALID_PIPE) return intel_dp->pps_pipe; @@ -403,9 +409,12 @@ vlv_power_sequencer_pipe(struct intel_dp *intel_dp) * are two power sequencers and up to two eDP ports. */ if (WARN_ON(pipes == 0)) - return PIPE_A; + pipe = PIPE_A; + else + pipe = ffs(pipes) - 1; - intel_dp->pps_pipe = ffs(pipes) - 1; + vlv_steal_power_sequencer(dev, pipe); + intel_dp->pps_pipe = pipe; DRM_DEBUG_KMS("picked pipe %c power sequencer for port %c\n", pipe_name(intel_dp->pps_pipe), -- cgit v1.2.3 From 3936fcf453af4de87303f42bb34ef5e3eb13c139 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Thu, 16 Oct 2014 21:30:02 +0300 Subject: drm/i915: Improve VDD/PPS debugs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Print the port name in the VDD/PPS debugs messages. Signed-off-by: Ville Syrjälä Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 1900c4d48376..21fb42241b2f 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1473,7 +1473,8 @@ static bool edp_panel_vdd_on(struct intel_dp *intel_dp) power_domain = intel_display_port_power_domain(intel_encoder); intel_display_power_get(dev_priv, power_domain); - DRM_DEBUG_KMS("Turning eDP VDD on\n"); + DRM_DEBUG_KMS("Turning eDP port %c VDD on\n", + port_name(intel_dig_port->port)); if (!edp_have_panel_power(intel_dp)) wait_panel_power_cycle(intel_dp); @@ -1492,7 +1493,8 @@ static bool edp_panel_vdd_on(struct intel_dp *intel_dp) * If the panel wasn't on, delay before accessing aux channel */ if (!edp_have_panel_power(intel_dp)) { - DRM_DEBUG_KMS("eDP was not running\n"); + DRM_DEBUG_KMS("eDP port %c panel power wasn't enabled\n", + port_name(intel_dig_port->port)); msleep(intel_dp->panel_power_up_delay); } @@ -1517,7 +1519,8 @@ void intel_edp_panel_vdd_on(struct intel_dp *intel_dp) vdd = edp_panel_vdd_on(intel_dp); pps_unlock(intel_dp); - WARN(!vdd, "eDP VDD already requested on\n"); + WARN(!vdd, "eDP port %c VDD already requested on\n", + port_name(dp_to_dig_port(intel_dp)->port)); } static void edp_panel_vdd_off_sync(struct intel_dp *intel_dp) @@ -1538,7 +1541,8 @@ static void edp_panel_vdd_off_sync(struct intel_dp *intel_dp) if (!edp_have_panel_vdd(intel_dp)) return; - DRM_DEBUG_KMS("Turning eDP VDD off\n"); + DRM_DEBUG_KMS("Turning eDP port %c VDD off\n", + port_name(intel_dig_port->port)); pp = ironlake_get_pp_control(intel_dp); pp &= ~EDP_FORCE_VDD; @@ -1599,7 +1603,8 @@ static void edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync) if (!is_edp(intel_dp)) return; - WARN(!intel_dp->want_panel_vdd, "eDP VDD not forced on"); + WARN(!intel_dp->want_panel_vdd, "eDP port %c VDD not forced on", + port_name(dp_to_dig_port(intel_dp)->port)); intel_dp->want_panel_vdd = false; @@ -1621,7 +1626,8 @@ static void edp_panel_on(struct intel_dp *intel_dp) if (!is_edp(intel_dp)) return; - DRM_DEBUG_KMS("Turn eDP power on\n"); + DRM_DEBUG_KMS("Turn eDP port %c panel power on\n", + port_name(dp_to_dig_port(intel_dp)->port)); if (edp_have_panel_power(intel_dp)) { DRM_DEBUG_KMS("eDP power already on\n"); @@ -1682,9 +1688,11 @@ static void edp_panel_off(struct intel_dp *intel_dp) if (!is_edp(intel_dp)) return; - DRM_DEBUG_KMS("Turn eDP power off\n"); + DRM_DEBUG_KMS("Turn eDP port %c panel power off\n", + port_name(dp_to_dig_port(intel_dp)->port)); - WARN(!intel_dp->want_panel_vdd, "Need VDD to turn off panel\n"); + WARN(!intel_dp->want_panel_vdd, "Need eDP port %c VDD to turn off panel\n", + port_name(dp_to_dig_port(intel_dp)->port)); pp = ironlake_get_pp_control(intel_dp); /* We need to switch off panel power _and_ force vdd, for otherwise some -- cgit v1.2.3 From e7a89acea863ffdffa66f4c6cda272eebd893c51 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Thu, 16 Oct 2014 21:30:07 +0300 Subject: drm/i915: Warn if panel power is already on when enabling it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We should never enable the panel power twice. That would indicate a bug somewhere else as we would need to enable the port twice without disabling it in between. Also print the port name. Signed-off-by: Ville Syrjälä Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 21fb42241b2f..9db977b475f8 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1629,10 +1629,10 @@ static void edp_panel_on(struct intel_dp *intel_dp) DRM_DEBUG_KMS("Turn eDP port %c panel power on\n", port_name(dp_to_dig_port(intel_dp)->port)); - if (edp_have_panel_power(intel_dp)) { - DRM_DEBUG_KMS("eDP power already on\n"); + if (WARN(edp_have_panel_power(intel_dp), + "eDP port %c panel power already on\n", + port_name(dp_to_dig_port(intel_dp)->port))) return; - } wait_panel_power_cycle(intel_dp); -- cgit v1.2.3 From 034e43c6c0dc7e70a6edc96987758237cb92f0cd Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Thu, 16 Oct 2014 21:27:28 +0300 Subject: drm/i915: Warn if stealing power sequencer from an active eDP port MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit eDP ports need the power seqeuncer whenever the port is active. Warn if we accidentally steal the power sequener from an active eDP port. This should not happen unless there's a bug somewhere else, but it's best to scream loudly if it happens to help with debugging. Note that this only checks for active pipes and not for enabled pipes which are turned off with dpms. Which means we might run the risk that the pps might get stolen and we can't reacquire one when enabling the pipe again with dpms on. But on current platforms that's impossible since we only support two edp ports with just two panel power sequencers. So a more elaborate scheme which reserves the pps even when the pipe is inactive isn't required. Signed-off-by: Ville Syrjälä Reviewed-by: Imre Deak [danvet: Summarize my discussion with Ville about dpms on/off issues.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 9db977b475f8..90d752d5d6ea 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -2728,6 +2728,10 @@ static void vlv_steal_power_sequencer(struct drm_device *dev, DRM_DEBUG_KMS("stealing pipe %c power sequencer from port %c\n", pipe_name(pipe), port_name(port)); + WARN(encoder->connectors_active, + "stealing pipe %c power sequencer from active eDP port %c\n", + pipe_name(pipe), port_name(port)); + /* make sure vdd is off before we steal it */ vlv_detach_power_sequencer(intel_dp); } -- cgit v1.2.3 From d288f65fe9472501929eb8d63c2b248813b92056 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 28 Oct 2014 13:20:22 +0200 Subject: drm/i915: Make sure DPLL is enabled when kicking the power sequencer on VLV/CHV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The power seqeuencer kick procedure requires the DPLL to be running in order to complete successfully. In case the DPLL isn't currently running when we need to kick the power seqeuncer enable it temporarily. This can happen eg. during ->detect() when the pipe is not already active. To avoid needlessly duplicating the DPLL programming re-use the already existing functions by passing a temporary pipe config to them instead of having them consult the current pipe config at crtc->config. v2: Introduce vlv_force_pll_{on,off}() (Daniel) v3: Rebase due to drm_crtc vs. intel_crtc changes Fix a typo in commit msg (checkpatch) Signed-off-by: Ville Syrjälä Reviewed-by: Imre Deak (v1) [danvet: Appease checkpatch.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 131 +++++++++++++++++++++++++---------- drivers/gpu/drm/i915/intel_dp.c | 14 ++++ drivers/gpu/drm/i915/intel_drv.h | 4 ++ 3 files changed, 111 insertions(+), 38 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index ee982f5412d6..848f330a931f 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -94,8 +94,10 @@ static void intel_cpu_transcoder_set_m_n(struct intel_crtc *crtc, static void ironlake_set_pipeconf(struct drm_crtc *crtc); static void haswell_set_pipeconf(struct drm_crtc *crtc); static void intel_set_pipe_csc(struct drm_crtc *crtc); -static void vlv_prepare_pll(struct intel_crtc *crtc); -static void chv_prepare_pll(struct intel_crtc *crtc); +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 struct intel_encoder *intel_find_encoder(struct intel_connector *connector, int pipe) { @@ -1484,12 +1486,13 @@ static void intel_init_dpio(struct drm_device *dev) } } -static void vlv_enable_pll(struct intel_crtc *crtc) +static void vlv_enable_pll(struct intel_crtc *crtc, + const struct intel_crtc_config *pipe_config) { struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; int reg = DPLL(crtc->pipe); - u32 dpll = crtc->config.dpll_hw_state.dpll; + u32 dpll = pipe_config->dpll_hw_state.dpll; assert_pipe_disabled(dev_priv, crtc->pipe); @@ -1507,7 +1510,7 @@ static void vlv_enable_pll(struct intel_crtc *crtc) if (wait_for(((I915_READ(reg) & DPLL_LOCK_VLV) == DPLL_LOCK_VLV), 1)) DRM_ERROR("DPLL %d failed to lock\n", crtc->pipe); - I915_WRITE(DPLL_MD(crtc->pipe), crtc->config.dpll_hw_state.dpll_md); + I915_WRITE(DPLL_MD(crtc->pipe), pipe_config->dpll_hw_state.dpll_md); POSTING_READ(DPLL_MD(crtc->pipe)); /* We do this three times for luck */ @@ -1522,7 +1525,8 @@ static void vlv_enable_pll(struct intel_crtc *crtc) udelay(150); /* wait for warmup */ } -static void chv_enable_pll(struct intel_crtc *crtc) +static void chv_enable_pll(struct intel_crtc *crtc, + const struct intel_crtc_config *pipe_config) { struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -1547,14 +1551,14 @@ static void chv_enable_pll(struct intel_crtc *crtc) udelay(1); /* Enable PLL */ - I915_WRITE(DPLL(pipe), crtc->config.dpll_hw_state.dpll); + I915_WRITE(DPLL(pipe), pipe_config->dpll_hw_state.dpll); /* Check PLL is locked */ if (wait_for(((I915_READ(DPLL(pipe)) & DPLL_LOCK_VLV) == DPLL_LOCK_VLV), 1)) DRM_ERROR("PLL %d failed to lock\n", pipe); /* not sure when this should be written */ - I915_WRITE(DPLL_MD(pipe), crtc->config.dpll_hw_state.dpll_md); + I915_WRITE(DPLL_MD(pipe), pipe_config->dpll_hw_state.dpll_md); POSTING_READ(DPLL_MD(pipe)); mutex_unlock(&dev_priv->dpio_lock); @@ -4842,9 +4846,9 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc) if (!is_dsi) { if (IS_CHERRYVIEW(dev)) - chv_prepare_pll(intel_crtc); + chv_prepare_pll(intel_crtc, &intel_crtc->config); else - vlv_prepare_pll(intel_crtc); + vlv_prepare_pll(intel_crtc, &intel_crtc->config); } if (intel_crtc->config.has_dp_encoder) @@ -4864,9 +4868,9 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc) if (!is_dsi) { if (IS_CHERRYVIEW(dev)) - chv_enable_pll(intel_crtc); + chv_enable_pll(intel_crtc, &intel_crtc->config); else - vlv_enable_pll(intel_crtc); + vlv_enable_pll(intel_crtc, &intel_crtc->config); } for_each_encoder_on_crtc(dev, crtc, encoder) @@ -5747,7 +5751,8 @@ void intel_dp_set_m_n(struct intel_crtc *crtc) &crtc->config.dp_m2_n2); } -static void vlv_update_pll(struct intel_crtc *crtc) +static void vlv_update_pll(struct intel_crtc *crtc, + struct intel_crtc_config *pipe_config) { u32 dpll, dpll_md; @@ -5762,14 +5767,15 @@ static void vlv_update_pll(struct intel_crtc *crtc) if (crtc->pipe == PIPE_B) dpll |= DPLL_INTEGRATED_CRI_CLK_VLV; dpll |= DPLL_VCO_ENABLE; - crtc->config.dpll_hw_state.dpll = dpll; + pipe_config->dpll_hw_state.dpll = dpll; - dpll_md = (crtc->config.pixel_multiplier - 1) + dpll_md = (pipe_config->pixel_multiplier - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT; - crtc->config.dpll_hw_state.dpll_md = dpll_md; + pipe_config->dpll_hw_state.dpll_md = dpll_md; } -static void vlv_prepare_pll(struct intel_crtc *crtc) +static void vlv_prepare_pll(struct intel_crtc *crtc, + const struct intel_crtc_config *pipe_config) { struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -5780,11 +5786,11 @@ static void vlv_prepare_pll(struct intel_crtc *crtc) mutex_lock(&dev_priv->dpio_lock); - bestn = crtc->config.dpll.n; - bestm1 = crtc->config.dpll.m1; - bestm2 = crtc->config.dpll.m2; - bestp1 = crtc->config.dpll.p1; - bestp2 = crtc->config.dpll.p2; + bestn = pipe_config->dpll.n; + bestm1 = pipe_config->dpll.m1; + bestm2 = pipe_config->dpll.m2; + bestp1 = pipe_config->dpll.p1; + bestp2 = pipe_config->dpll.p2; /* See eDP HDMI DPIO driver vbios notes doc */ @@ -5821,7 +5827,7 @@ static void vlv_prepare_pll(struct intel_crtc *crtc) vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW3(pipe), mdiv); /* Set HBR and RBR LPF coefficients */ - if (crtc->config.port_clock == 162000 || + if (pipe_config->port_clock == 162000 || intel_pipe_has_type(crtc, INTEL_OUTPUT_ANALOG) || intel_pipe_has_type(crtc, INTEL_OUTPUT_HDMI)) vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW10(pipe), @@ -5860,19 +5866,21 @@ static void vlv_prepare_pll(struct intel_crtc *crtc) mutex_unlock(&dev_priv->dpio_lock); } -static void chv_update_pll(struct intel_crtc *crtc) +static void chv_update_pll(struct intel_crtc *crtc, + struct intel_crtc_config *pipe_config) { - crtc->config.dpll_hw_state.dpll = DPLL_SSC_REF_CLOCK_CHV | + pipe_config->dpll_hw_state.dpll = DPLL_SSC_REF_CLOCK_CHV | DPLL_REFA_CLK_ENABLE_VLV | DPLL_VGA_MODE_DIS | DPLL_VCO_ENABLE; if (crtc->pipe != PIPE_A) - crtc->config.dpll_hw_state.dpll |= DPLL_INTEGRATED_CRI_CLK_VLV; + pipe_config->dpll_hw_state.dpll |= DPLL_INTEGRATED_CRI_CLK_VLV; - crtc->config.dpll_hw_state.dpll_md = - (crtc->config.pixel_multiplier - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT; + pipe_config->dpll_hw_state.dpll_md = + (pipe_config->pixel_multiplier - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT; } -static void chv_prepare_pll(struct intel_crtc *crtc) +static void chv_prepare_pll(struct intel_crtc *crtc, + const struct intel_crtc_config *pipe_config) { struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -5883,18 +5891,18 @@ static void chv_prepare_pll(struct intel_crtc *crtc) u32 bestn, bestm1, bestm2, bestp1, bestp2, bestm2_frac; int refclk; - bestn = crtc->config.dpll.n; - bestm2_frac = crtc->config.dpll.m2 & 0x3fffff; - bestm1 = crtc->config.dpll.m1; - bestm2 = crtc->config.dpll.m2 >> 22; - bestp1 = crtc->config.dpll.p1; - bestp2 = crtc->config.dpll.p2; + bestn = pipe_config->dpll.n; + bestm2_frac = pipe_config->dpll.m2 & 0x3fffff; + bestm1 = pipe_config->dpll.m1; + bestm2 = pipe_config->dpll.m2 >> 22; + bestp1 = pipe_config->dpll.p1; + bestp2 = pipe_config->dpll.p2; /* * Enable Refclk and SSC */ I915_WRITE(dpll_reg, - crtc->config.dpll_hw_state.dpll & ~DPLL_VCO_ENABLE); + pipe_config->dpll_hw_state.dpll & ~DPLL_VCO_ENABLE); mutex_lock(&dev_priv->dpio_lock); @@ -5942,6 +5950,53 @@ static void chv_prepare_pll(struct intel_crtc *crtc) mutex_unlock(&dev_priv->dpio_lock); } +/** + * vlv_force_pll_on - forcibly enable just the PLL + * @dev_priv: i915 private structure + * @pipe: pipe PLL to enable + * @dpll: PLL configuration + * + * Enable the PLL for @pipe using the supplied @dpll config. To be used + * in cases where we need the PLL enabled even when @pipe is not going to + * be enabled. + */ +void vlv_force_pll_on(struct drm_device *dev, enum pipe pipe, + const struct dpll *dpll) +{ + struct intel_crtc *crtc = + to_intel_crtc(intel_get_crtc_for_pipe(dev, pipe)); + struct intel_crtc_config pipe_config = { + .pixel_multiplier = 1, + .dpll = *dpll, + }; + + if (IS_CHERRYVIEW(dev)) { + chv_update_pll(crtc, &pipe_config); + chv_prepare_pll(crtc, &pipe_config); + chv_enable_pll(crtc, &pipe_config); + } else { + vlv_update_pll(crtc, &pipe_config); + vlv_prepare_pll(crtc, &pipe_config); + vlv_enable_pll(crtc, &pipe_config); + } +} + +/** + * vlv_force_pll_off - forcibly disable just the PLL + * @dev_priv: i915 private structure + * @pipe: pipe PLL to disable + * + * Disable the PLL for @pipe. To be used in cases where we need + * the PLL enabled even when @pipe is not going to be enabled. + */ +void vlv_force_pll_off(struct drm_device *dev, enum pipe pipe) +{ + if (IS_CHERRYVIEW(dev)) + chv_disable_pll(to_i915(dev), pipe); + else + vlv_disable_pll(to_i915(dev), pipe); +} + static void i9xx_update_pll(struct intel_crtc *crtc, intel_clock_t *reduced_clock, int num_connectors) @@ -6323,9 +6378,9 @@ static int i9xx_crtc_mode_set(struct intel_crtc *crtc, has_reduced_clock ? &reduced_clock : NULL, num_connectors); } else if (IS_CHERRYVIEW(dev)) { - chv_update_pll(crtc); + chv_update_pll(crtc, &crtc->config); } else if (IS_VALLEYVIEW(dev)) { - vlv_update_pll(crtc); + vlv_update_pll(crtc, &crtc->config); } else { i9xx_update_pll(crtc, has_reduced_clock ? &reduced_clock : NULL, diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 90d752d5d6ea..ccc690e2e906 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -330,6 +330,7 @@ vlv_power_sequencer_kick(struct intel_dp *intel_dp) struct drm_device *dev = intel_dig_port->base.base.dev; struct drm_i915_private *dev_priv = dev->dev_private; enum pipe pipe = intel_dp->pps_pipe; + bool pll_enabled; uint32_t DP; if (WARN(I915_READ(intel_dp->output_reg) & DP_PORT_EN, @@ -353,6 +354,16 @@ vlv_power_sequencer_kick(struct intel_dp *intel_dp) else if (pipe == PIPE_B) DP |= DP_PIPEB_SELECT; + pll_enabled = I915_READ(DPLL(pipe)) & DPLL_VCO_ENABLE; + + /* + * The DPLL for the pipe must be enabled for this to work. + * So enable temporarily it if it's not already enabled. + */ + if (!pll_enabled) + vlv_force_pll_on(dev, pipe, IS_CHERRYVIEW(dev) ? + &chv_dpll[0].dpll : &vlv_dpll[0].dpll); + /* * Similar magic as in intel_dp_enable_port(). * We _must_ do this port enable + disable trick @@ -367,6 +378,9 @@ vlv_power_sequencer_kick(struct intel_dp *intel_dp) I915_WRITE(intel_dp->output_reg, DP & ~DP_PORT_EN); POSTING_READ(intel_dp->output_reg); + + if (!pll_enabled) + vlv_force_pll_off(dev, pipe); } static enum pipe diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index b323c9b01c40..d53ac23cb127 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -918,6 +918,10 @@ void assert_shared_dpll(struct drm_i915_private *dev_priv, struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc); void intel_put_shared_dpll(struct intel_crtc *crtc); +void vlv_force_pll_on(struct drm_device *dev, enum pipe pipe, + const struct dpll *dpll); +void vlv_force_pll_off(struct drm_device *dev, enum pipe pipe); + /* modesetting asserts */ void assert_panel_unlocked(struct drm_i915_private *dev_priv, enum pipe pipe); -- cgit v1.2.3 From 14af293f060cbf2a508463b01dc4e124bd3c6e15 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Fri, 24 Oct 2014 14:51:31 +0100 Subject: drm/i915: create a prepare step for primary planes updates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Take out the pin_fb code so commit phase can't fail anymore. Signed-off-by: Gustavo Padovan Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 848f330a931f..d678bc0c8184 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11403,20 +11403,16 @@ intel_check_primary_plane(struct drm_plane *plane, } static int -intel_commit_primary_plane(struct drm_plane *plane, - struct intel_plane_state *state) +intel_prepare_primary_plane(struct drm_plane *plane, + struct intel_plane_state *state) { struct drm_crtc *crtc = state->crtc; struct drm_framebuffer *fb = state->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); enum pipe pipe = intel_crtc->pipe; - struct drm_framebuffer *old_fb = plane->fb; struct drm_i915_gem_object *obj = intel_fb_obj(fb); struct drm_i915_gem_object *old_obj = intel_fb_obj(plane->fb); - struct intel_plane *intel_plane = to_intel_plane(plane); - struct drm_rect *src = &state->src; int ret; intel_crtc_wait_for_pending_flips(crtc); @@ -11426,7 +11422,7 @@ intel_commit_primary_plane(struct drm_plane *plane, return -EBUSY; } - if (plane->fb != fb) { + if (old_obj != obj) { mutex_lock(&dev->struct_mutex); ret = intel_pin_and_fence_fb_obj(dev, obj, NULL); if (ret == 0) @@ -11439,6 +11435,25 @@ intel_commit_primary_plane(struct drm_plane *plane, } } + return 0; +} + +static void +intel_commit_primary_plane(struct drm_plane *plane, + struct intel_plane_state *state) +{ + struct drm_crtc *crtc = state->crtc; + struct drm_framebuffer *fb = state->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); + enum pipe pipe = intel_crtc->pipe; + struct drm_framebuffer *old_fb = plane->fb; + struct drm_i915_gem_object *obj = intel_fb_obj(fb); + struct drm_i915_gem_object *old_obj = intel_fb_obj(plane->fb); + struct intel_plane *intel_plane = to_intel_plane(plane); + struct drm_rect *src = &state->src; + crtc->primary->fb = fb; crtc->x = src->x1; crtc->y = src->y1; @@ -11515,8 +11530,6 @@ intel_commit_primary_plane(struct drm_plane *plane, intel_unpin_fb_obj(old_obj); mutex_unlock(&dev->struct_mutex); } - - return 0; } static int @@ -11557,6 +11570,10 @@ intel_primary_plane_setplane(struct drm_plane *plane, struct drm_crtc *crtc, if (ret) return ret; + ret = intel_prepare_primary_plane(plane, &state); + if (ret) + return ret; + intel_commit_primary_plane(plane, &state); return 0; -- cgit v1.2.3 From 34aa50a976c58697ad4050674b272892efea865c Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Fri, 24 Oct 2014 14:51:32 +0100 Subject: drm/i915: create a prepare phase for sprite plane updates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit take out pin_fb code so the commit phase can't fail anymore. Signed-off-by: Gustavo Padovan Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_sprite.c | 63 +++++++++++++++++++++++-------------- 1 file changed, 40 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 2c060addea29..3631b0ef4d2e 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -1192,34 +1192,18 @@ intel_check_sprite_plane(struct drm_plane *plane, } static int -intel_commit_sprite_plane(struct drm_plane *plane, - struct intel_plane_state *state) +intel_prepare_sprite_plane(struct drm_plane *plane, + struct intel_plane_state *state) { struct drm_device *dev = plane->dev; struct drm_crtc *crtc = state->crtc; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - struct intel_plane *intel_plane = to_intel_plane(plane); enum pipe pipe = intel_crtc->pipe; struct drm_framebuffer *fb = state->fb; - struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); - struct drm_i915_gem_object *obj = intel_fb->obj; - struct drm_i915_gem_object *old_obj = intel_plane->obj; - 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; + struct drm_i915_gem_object *obj = intel_fb_obj(fb); + struct drm_i915_gem_object *old_obj = intel_fb_obj(plane->fb); int ret; - /* - * 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); - - if (old_obj != obj) { mutex_lock(&dev->struct_mutex); @@ -1238,6 +1222,36 @@ intel_commit_sprite_plane(struct drm_plane *plane, return ret; } + return 0; +} + +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->crtc; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_plane *intel_plane = to_intel_plane(plane); + enum pipe pipe = intel_crtc->pipe; + struct drm_framebuffer *fb = state->fb; + struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); + struct drm_i915_gem_object *obj = intel_fb->obj; + struct drm_i915_gem_object *old_obj = intel_plane->obj; + 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; + + /* + * 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); @@ -1298,8 +1312,6 @@ intel_commit_sprite_plane(struct drm_plane *plane, intel_unpin_fb_obj(old_obj); mutex_unlock(&dev->struct_mutex); } - - return 0; } static int @@ -1339,7 +1351,12 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, if (ret) return ret; - return intel_commit_sprite_plane(plane, &state); + ret = intel_prepare_sprite_plane(plane, &state); + if (ret) + return ret; + + intel_commit_sprite_plane(plane, &state); + return 0; } static int -- cgit v1.2.3 From 77cde95217484e845743818691df026cec2534f4 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Fri, 24 Oct 2014 14:51:33 +0100 Subject: drm/i915: use intel_fb_obj() macros to assign gem objects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the macros makes the code cleaner and it also checks for a NULL fb. Signed-off-by: Gustavo Padovan Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_sprite.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 3631b0ef4d2e..8b80d68619af 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -1032,8 +1032,7 @@ intel_check_sprite_plane(struct drm_plane *plane, struct intel_crtc *intel_crtc = to_intel_crtc(state->crtc); struct intel_plane *intel_plane = to_intel_plane(plane); struct drm_framebuffer *fb = state->fb; - struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); - struct drm_i915_gem_object *obj = intel_fb->obj; + 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; @@ -1235,9 +1234,8 @@ intel_commit_sprite_plane(struct drm_plane *plane, struct intel_plane *intel_plane = to_intel_plane(plane); enum pipe pipe = intel_crtc->pipe; struct drm_framebuffer *fb = state->fb; - struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); - struct drm_i915_gem_object *obj = intel_fb->obj; - struct drm_i915_gem_object *old_obj = intel_plane->obj; + struct drm_i915_gem_object *obj = intel_fb_obj(fb); + struct drm_i915_gem_object *old_obj = intel_fb_obj(plane->fb); int crtc_x, crtc_y; unsigned int crtc_w, crtc_h; uint32_t src_x, src_y, src_w, src_h; -- cgit v1.2.3 From 5d93a6e5a9d225d9c38a63d2e0164ddc4228b354 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Thu, 16 Oct 2014 20:52:33 +0300 Subject: drm/i915: Do vlv cmnlane toggle w/a in more cases MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In case the cmnlane power well is down but cmnreset isn't asserted we would currently skip the off+on toggle for the power well. That could leave cmnreset deasserted while cmnlane is powered down which might lead to problems with the PHY. To avoid such issues skip the cmnlane toggle only if both cmnlane and disp2d wells are up and cmnreset is already deasserted. In all other cases power down the cmnlane well which will also make sure cmnreset gets asserted correctly while cmnlane is powered down. Signed-off-by: Ville Syrjälä Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_runtime_pm.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index 39c33e0a753c..59ca54fc2487 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -1137,12 +1137,9 @@ static void vlv_cmnlane_wa(struct drm_i915_private *dev_priv) struct i915_power_well *disp2d = lookup_power_well(dev_priv, PUNIT_POWER_WELL_DISP2D); - /* nothing to do if common lane is already off */ - if (!cmn->ops->is_enabled(dev_priv, cmn)) - return; - /* If the display might be already active skip this */ - if (disp2d->ops->is_enabled(dev_priv, disp2d) && + if (cmn->ops->is_enabled(dev_priv, cmn) && + disp2d->ops->is_enabled(dev_priv, disp2d) && I915_READ(DPIO_CTL) & DPIO_CMNRST) return; -- cgit v1.2.3 From c14b048521ed3413df939ec6cc5dd450ff618120 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Thu, 16 Oct 2014 20:52:34 +0300 Subject: drm/i915: Initialize new chv primary plane and pipe blender registers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CHV adds a bunch of new registers for primary plane size/position and pipe blender setup. Initialize all those registers to avoid nasty surprises. PRIMSIZE is especially important as without programming it the outout will be garbled whenever the primary plane size would not match what the BIOS set up. Also program the sprite constant alpha register to disable the constant alpha blending factor. This applies to vlv as well as chv. Signed-off-by: Ville Syrjälä Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 25 ++++++++++++++++++++++++- drivers/gpu/drm/i915/intel_display.c | 13 +++++++++++++ drivers/gpu/drm/i915/intel_sprite.c | 2 ++ 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index ea84e1ec5e5f..a9a861798ff5 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -4272,9 +4272,11 @@ enum punit_power_well { #define DISPPLANE_NO_LINE_DOUBLE 0 #define DISPPLANE_STEREO_POLARITY_FIRST 0 #define DISPPLANE_STEREO_POLARITY_SECOND (1<<18) -#define DISPPLANE_ROTATE_180 (1<<15) +#define DISPPLANE_ALPHA_PREMULTIPLY (1<<16) /* CHV pipe B */ +#define DISPPLANE_ROTATE_180 (1<<15) #define DISPPLANE_TRICKLE_FEED_DISABLE (1<<14) /* Ironlake */ #define DISPPLANE_TILED (1<<10) +#define DISPPLANE_MIRROR (1<<8) /* CHV pipe B */ #define _DSPAADDR 0x70184 #define _DSPASTRIDE 0x70188 #define _DSPAPOS 0x7018C /* reserved */ @@ -4295,6 +4297,24 @@ enum punit_power_well { #define DSPOFFSET(plane) _PIPE2(plane, _DSPAOFFSET) #define DSPSURFLIVE(plane) _PIPE2(plane, _DSPASURFLIVE) +/* CHV pipe B blender and primary plane */ +#define _CHV_BLEND_A 0x60a00 +#define CHV_BLEND_LEGACY (0<<30) +#define CHV_BLEND_ANDROID (1<<30) +#define CHV_BLEND_MPO (2<<30) +#define CHV_BLEND_MASK (3<<30) +#define _CHV_CANVAS_A 0x60a04 +#define _PRIMPOS_A 0x60a08 +#define _PRIMSIZE_A 0x60a0c +#define _PRIMCNSTALPHA_A 0x60a10 +#define PRIM_CONST_ALPHA_ENABLE (1<<31) + +#define CHV_BLEND(pipe) _TRANSCODER2(pipe, _CHV_BLEND_A) +#define CHV_CANVAS(pipe) _TRANSCODER2(pipe, _CHV_CANVAS_A) +#define PRIMPOS(plane) _TRANSCODER2(plane, _PRIMPOS_A) +#define PRIMSIZE(plane) _TRANSCODER2(plane, _PRIMSIZE_A) +#define PRIMCNSTALPHA(plane) _TRANSCODER2(plane, _PRIMCNSTALPHA_A) + /* Display/Sprite base address macros */ #define DISP_BASEADDR_MASK (0xfffff000) #define I915_LO_DISPBASE(val) (val & ~DISP_BASEADDR_MASK) @@ -4496,6 +4516,7 @@ enum punit_power_well { #define SP_FORMAT_RGBA1010102 (9<<26) #define SP_FORMAT_RGBX8888 (0xe<<26) #define SP_FORMAT_RGBA8888 (0xf<<26) +#define SP_ALPHA_PREMULTIPLY (1<<23) /* CHV pipe B */ #define SP_SOURCE_KEY (1<<22) #define SP_YUV_BYTE_ORDER_MASK (3<<16) #define SP_YUV_ORDER_YUYV (0<<16) @@ -4504,6 +4525,7 @@ enum punit_power_well { #define SP_YUV_ORDER_VYUY (3<<16) #define SP_ROTATE_180 (1<<15) #define SP_TILED (1<<10) +#define SP_MIRROR (1<<8) /* CHV pipe B */ #define _SPALINOFF (VLV_DISPLAY_BASE + 0x72184) #define _SPASTRIDE (VLV_DISPLAY_BASE + 0x72188) #define _SPAPOS (VLV_DISPLAY_BASE + 0x7218c) @@ -4514,6 +4536,7 @@ enum punit_power_well { #define _SPAKEYMAXVAL (VLV_DISPLAY_BASE + 0x721a0) #define _SPATILEOFF (VLV_DISPLAY_BASE + 0x721a4) #define _SPACONSTALPHA (VLV_DISPLAY_BASE + 0x721a8) +#define SP_CONST_ALPHA_ENABLE (1<<31) #define _SPAGAMC (VLV_DISPLAY_BASE + 0x721f4) #define _SPBCNTR (VLV_DISPLAY_BASE + 0x72280) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index d678bc0c8184..c17ec502b087 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2451,6 +2451,12 @@ static void i9xx_update_primary_plane(struct drm_crtc *crtc, ((intel_crtc->config.pipe_src_h - 1) << 16) | (intel_crtc->config.pipe_src_w - 1)); I915_WRITE(DSPPOS(plane), 0); + } else if (IS_CHERRYVIEW(dev) && plane == PLANE_B) { + I915_WRITE(PRIMSIZE(plane), + ((intel_crtc->config.pipe_src_h - 1) << 16) | + (intel_crtc->config.pipe_src_w - 1)); + I915_WRITE(PRIMPOS(plane), 0); + I915_WRITE(PRIMCNSTALPHA(plane), 0); } switch (fb->pixel_format) { @@ -4856,6 +4862,13 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc) intel_set_pipe_timings(intel_crtc); + if (IS_CHERRYVIEW(dev) && pipe == PIPE_B) { + struct drm_i915_private *dev_priv = dev->dev_private; + + I915_WRITE(CHV_BLEND(pipe), CHV_BLEND_LEGACY); + I915_WRITE(CHV_CANVAS(pipe), 0); + } + i9xx_set_pipeconf(intel_crtc); intel_crtc->active = true; diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 8b80d68619af..4912161c95b3 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -438,6 +438,8 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc, else I915_WRITE(SPLINOFF(pipe, plane), linear_offset); + I915_WRITE(SPCONSTALPHA(pipe, plane), 0); + I915_WRITE(SPSIZE(pipe, plane), (crtc_h << 16) | crtc_w); I915_WRITE(SPCNTR(pipe, plane), sprctl); I915_WRITE(SPSURF(pipe, plane), i915_gem_obj_ggtt_offset(obj) + -- cgit v1.2.3 From 1a5df187172a92ffdf8dc89988154d512d66a896 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Mon, 27 Oct 2014 17:54:32 -0200 Subject: drm/i915: kill intel_resume_prepare() Because, really, the abstraction is not working for us. It is nice for VLV, but doesn't add anything useful on SNB/HSW/BDW. We want to change this code due to a recently-discovered bug, but we can't seem to find a nice solution that repects the current abstraction. So let's kill intel_resume_prepare() and its friends, and add an equivalent implementation to both its callers. Also, look at the diffstat! v2: - Rebase. Signed-off-by: Paulo Zanoni Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 63 ++++++++++------------------------------- 1 file changed, 15 insertions(+), 48 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 035ec94ca3c7..33b6fc49dda7 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -551,8 +551,8 @@ static void intel_suspend_encoders(struct drm_i915_private *dev_priv) } static int intel_suspend_complete(struct drm_i915_private *dev_priv); -static int intel_resume_prepare(struct drm_i915_private *dev_priv, - bool rpm_resume); +static int vlv_resume_prepare(struct drm_i915_private *dev_priv, + bool rpm_resume); static int i915_drm_suspend(struct drm_device *dev) { @@ -744,7 +744,7 @@ static int i915_drm_resume(struct drm_device *dev) static int i915_drm_resume_early(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - int ret; + int ret = 0; /* * We have a resume ordering issue with the snd-hda driver also @@ -760,7 +760,10 @@ static int i915_drm_resume_early(struct drm_device *dev) pci_set_master(dev->pdev); - ret = intel_resume_prepare(dev_priv, false); + if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) + hsw_disable_pc8(dev_priv); + else if (IS_VALLEYVIEW(dev_priv)) + ret = vlv_resume_prepare(dev_priv, false); if (ret) DRM_ERROR("Resume prepare failed: %d,Continuing resume\n", ret); @@ -986,25 +989,6 @@ static int hsw_suspend_complete(struct drm_i915_private *dev_priv) return 0; } -static int snb_resume_prepare(struct drm_i915_private *dev_priv, - bool rpm_resume) -{ - struct drm_device *dev = dev_priv->dev; - - if (rpm_resume) - intel_init_pch_refclk(dev); - - return 0; -} - -static int hsw_resume_prepare(struct drm_i915_private *dev_priv, - bool rpm_resume) -{ - hsw_disable_pc8(dev_priv); - - return 0; -} - /* * Save all Gunit registers that may be lost after a D3 and a subsequent * S0i[R123] transition. The list of registers needing a save/restore is @@ -1462,7 +1446,7 @@ static int intel_runtime_resume(struct device *device) struct pci_dev *pdev = to_pci_dev(device); struct drm_device *dev = pci_get_drvdata(pdev); struct drm_i915_private *dev_priv = dev->dev_private; - int ret; + int ret = 0; if (WARN_ON_ONCE(!HAS_RUNTIME_PM(dev))) return -ENODEV; @@ -1472,7 +1456,13 @@ static int intel_runtime_resume(struct device *device) intel_opregion_notify_adapter(dev, PCI_D0); dev_priv->pm.suspended = false; - ret = intel_resume_prepare(dev_priv, true); + if (IS_GEN6(dev_priv)) + intel_init_pch_refclk(dev); + else if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) + hsw_disable_pc8(dev_priv); + else if (IS_VALLEYVIEW(dev_priv)) + ret = vlv_resume_prepare(dev_priv, true); + /* * No point of rolling back things in case of an error, as the best * we can do is to hope that things will still work (and disable RPM). @@ -1510,29 +1500,6 @@ static int intel_suspend_complete(struct drm_i915_private *dev_priv) return ret; } -/* - * This function implements common functionality of runtime and system - * resume sequence. Variable rpm_resume used for implementing different - * code paths. - */ -static int intel_resume_prepare(struct drm_i915_private *dev_priv, - bool rpm_resume) -{ - struct drm_device *dev = dev_priv->dev; - int ret; - - if (IS_GEN6(dev)) - ret = snb_resume_prepare(dev_priv, rpm_resume); - else if (IS_HASWELL(dev) || IS_BROADWELL(dev)) - ret = hsw_resume_prepare(dev_priv, rpm_resume); - else if (IS_VALLEYVIEW(dev)) - ret = vlv_resume_prepare(dev_priv, rpm_resume); - else - ret = 0; - - return ret; -} - static const struct dev_pm_ops i915_pm_ops = { /* * S0ix (via system suspend) and S3 event handlers [PMSG_SUSPEND, -- cgit v1.2.3 From efee833a2d0a69dfa2c4ec28377b00803a0f9a60 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Mon, 27 Oct 2014 17:54:33 -0200 Subject: drm/i915: run hsw_disable_pc8() later on resume We want to run intel_uncore_early_sanitize() before we touch any registers, because on BDW, when we resume, the FPGA_DBG_RM_NOCLAIM bit is set, so we need to clear it - through intel_uncore_early_sanitize() - before we do anything else. With the current code, we don't clear the bit before our first register access, so we print a WARN complaining about an unclaimed register error. v1: Was called "drm/i915: run intel_uncore_early_sanitize earlier on resume" v2: Was called "drm/i915: run intel_uncore_early_sanitize earlier on resume on non-VLV" v3: This one, on top of the intel_resume_prepare() rework. v4: Rebase. Signed-off-by: Paulo Zanoni Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 33b6fc49dda7..0c7cf480e854 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -760,14 +760,16 @@ static int i915_drm_resume_early(struct drm_device *dev) pci_set_master(dev->pdev); - if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) - hsw_disable_pc8(dev_priv); - else if (IS_VALLEYVIEW(dev_priv)) + if (IS_VALLEYVIEW(dev_priv)) ret = vlv_resume_prepare(dev_priv, false); if (ret) DRM_ERROR("Resume prepare failed: %d,Continuing resume\n", ret); intel_uncore_early_sanitize(dev, true); + + if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) + hsw_disable_pc8(dev_priv); + intel_uncore_sanitize(dev); intel_power_domains_init_hw(dev_priv); -- cgit v1.2.3 From 6ca2aeb27b4a8451052baa61c11c33bd5de8a71c Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Mon, 20 Oct 2014 19:47:53 +0300 Subject: drm/i915: Add support for CHV pipe B sprite CSC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CHV has a programmable CSC unit on the pipe B sprites. Program the unit appropriately for BT.601 limited range YCbCr to full range RGB color conversion. This matches the programming we currently do for sprites on the other pipes and on other platforms. It seems the CSC only works when the input data is YCbCr. For RGB pixel formats it doesn't matter what we program into the CSC registers. Doesn't make much sense to me especially since the register names give the impression that RGB input data would also work. But that's how it behaves here. In the review discussions there's been some nice math to explain the values obtained here. First about the YCbCr->RGB matrix: "I had the RGB->YCbCr matrix, inverted it and the values came out. But they should match the wikipedia article. Also keep in mind that the coefficients are in .12 in fixed point format, hence we need a 1<<12 factor. So let's try it: Kb=.114 Kr=.299 (1<<12) * 255/219 ~= 4769 -(1<<12) * 255/112*(1-Kb)*Kb/(1-Kb-Kr) ~= -1605 -(1<<12) * 255/112*(1-Kr)*Kr/(1-Kb-Kr) ~= -3330 (1<<12) * 255/112*(1-Kr) ~= 6537 (1<<12) * 255/112*(1-Kb) ~= 8263 "Looks like the same values to me." And then about the limits used for clamping: "> where did you get these min/max? "The hardware apparently deals in 10bit values, so we need to multiply everything by 4 when we start with the 8bit min/max values. Y = [16:235] * 4 = [64:940] CbCr = ([16:240] - 128) * 4 = [-112:112] * 4 = [-448:448] "The -128 being the -0.5 bias that the hardware already applied before the data entered the CSC unit." Raw data is also supplied in 10bpc in the registers. Signed-off-by: Ville Syrjälä Reviewed-by Rodrigo Vivi [danvet: Copypaste explanations&math from the review discussion.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 33 +++++++++++++++++ drivers/gpu/drm/i915/intel_sprite.c | 70 +++++++++++++++++++++++++++++-------- 2 files changed, 89 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index a9a861798ff5..2a4bdd56c4e0 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -4565,6 +4565,39 @@ enum punit_power_well { #define SPCONSTALPHA(pipe, plane) _PIPE(pipe * 2 + plane, _SPACONSTALPHA, _SPBCONSTALPHA) #define SPGAMC(pipe, plane) _PIPE(pipe * 2 + plane, _SPAGAMC, _SPBGAMC) +/* + * CHV pipe B sprite CSC + * + * |cr| |c0 c1 c2| |cr + cr_ioff| |cr_ooff| + * |yg| = |c3 c4 c5| x |yg + yg_ioff| + |yg_ooff| + * |cb| |c6 c7 c8| |cb + cr_ioff| |cb_ooff| + */ +#define SPCSCYGOFF(sprite) (VLV_DISPLAY_BASE + 0x6d900 + (sprite) * 0x1000) +#define SPCSCCBOFF(sprite) (VLV_DISPLAY_BASE + 0x6d904 + (sprite) * 0x1000) +#define SPCSCCROFF(sprite) (VLV_DISPLAY_BASE + 0x6d908 + (sprite) * 0x1000) +#define SPCSC_OOFF(x) (((x) & 0x7ff) << 16) /* s11 */ +#define SPCSC_IOFF(x) (((x) & 0x7ff) << 0) /* s11 */ + +#define SPCSCC01(sprite) (VLV_DISPLAY_BASE + 0x6d90c + (sprite) * 0x1000) +#define SPCSCC23(sprite) (VLV_DISPLAY_BASE + 0x6d910 + (sprite) * 0x1000) +#define SPCSCC45(sprite) (VLV_DISPLAY_BASE + 0x6d914 + (sprite) * 0x1000) +#define SPCSCC67(sprite) (VLV_DISPLAY_BASE + 0x6d918 + (sprite) * 0x1000) +#define SPCSCC8(sprite) (VLV_DISPLAY_BASE + 0x6d91c + (sprite) * 0x1000) +#define SPCSC_C1(x) (((x) & 0x7fff) << 16) /* s3.12 */ +#define SPCSC_C0(x) (((x) & 0x7fff) << 0) /* s3.12 */ + +#define SPCSCYGICLAMP(sprite) (VLV_DISPLAY_BASE + 0x6d920 + (sprite) * 0x1000) +#define SPCSCCBICLAMP(sprite) (VLV_DISPLAY_BASE + 0x6d924 + (sprite) * 0x1000) +#define SPCSCCRICLAMP(sprite) (VLV_DISPLAY_BASE + 0x6d928 + (sprite) * 0x1000) +#define SPCSC_IMAX(x) (((x) & 0x7ff) << 16) /* s11 */ +#define SPCSC_IMIN(x) (((x) & 0x7ff) << 0) /* s11 */ + +#define SPCSCYGOCLAMP(sprite) (VLV_DISPLAY_BASE + 0x6d92c + (sprite) * 0x1000) +#define SPCSCCBOCLAMP(sprite) (VLV_DISPLAY_BASE + 0x6d930 + (sprite) * 0x1000) +#define SPCSCCROCLAMP(sprite) (VLV_DISPLAY_BASE + 0x6d934 + (sprite) * 0x1000) +#define SPCSC_OMAX(x) ((x) << 16) /* u10 */ +#define SPCSC_OMIN(x) ((x) << 0) /* u10 */ + /* Skylake plane registers */ #define _PLANE_CTL_1_A 0x70180 diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 4912161c95b3..bf1eb158e624 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -37,6 +37,20 @@ #include #include "i915_drv.h" +static bool +format_is_yuv(uint32_t format) +{ + switch (format) { + case DRM_FORMAT_YUYV: + case DRM_FORMAT_UYVY: + case DRM_FORMAT_VYUY: + case DRM_FORMAT_YVYU: + return true; + default: + return false; + } +} + static int usecs_to_scanlines(const struct drm_display_mode *mode, int usecs) { /* paranoia */ @@ -319,6 +333,45 @@ skl_get_colorkey(struct drm_plane *drm_plane, } } +static void +chv_update_csc(struct intel_plane *intel_plane, uint32_t format) +{ + struct drm_i915_private *dev_priv = intel_plane->base.dev->dev_private; + int plane = intel_plane->plane; + + /* Seems RGB data bypasses the CSC always */ + if (!format_is_yuv(format)) + return; + + /* + * BT.601 limited range YCbCr -> full range RGB + * + * |r| | 6537 4769 0| |cr | + * |g| = |-3330 4769 -1605| x |y-64| + * |b| | 0 4769 8263| |cb | + * + * Cb and Cr apparently come in as signed already, so no + * need for any offset. For Y we need to remove the offset. + */ + I915_WRITE(SPCSCYGOFF(plane), SPCSC_OOFF(0) | SPCSC_IOFF(-64)); + I915_WRITE(SPCSCCBOFF(plane), SPCSC_OOFF(0) | SPCSC_IOFF(0)); + I915_WRITE(SPCSCCROFF(plane), SPCSC_OOFF(0) | SPCSC_IOFF(0)); + + I915_WRITE(SPCSCC01(plane), SPCSC_C1(4769) | SPCSC_C0(6537)); + I915_WRITE(SPCSCC23(plane), SPCSC_C1(-3330) | SPCSC_C0(0)); + I915_WRITE(SPCSCC45(plane), SPCSC_C1(-1605) | SPCSC_C0(4769)); + I915_WRITE(SPCSCC67(plane), SPCSC_C1(4769) | SPCSC_C0(0)); + I915_WRITE(SPCSCC8(plane), SPCSC_C0(8263)); + + I915_WRITE(SPCSCYGICLAMP(plane), SPCSC_IMAX(940) | SPCSC_IMIN(64)); + I915_WRITE(SPCSCCBICLAMP(plane), SPCSC_IMAX(448) | SPCSC_IMIN(-448)); + I915_WRITE(SPCSCCRICLAMP(plane), SPCSC_IMAX(448) | SPCSC_IMIN(-448)); + + I915_WRITE(SPCSCYGOCLAMP(plane), SPCSC_OMAX(1023) | SPCSC_OMIN(0)); + I915_WRITE(SPCSCCBOCLAMP(plane), SPCSC_OMAX(1023) | SPCSC_OMIN(0)); + I915_WRITE(SPCSCCROCLAMP(plane), SPCSC_OMAX(1023) | SPCSC_OMIN(0)); +} + static void vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc, struct drm_framebuffer *fb, @@ -430,6 +483,9 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc, intel_update_primary_plane(intel_crtc); + if (IS_CHERRYVIEW(dev) && pipe == PIPE_B) + chv_update_csc(intel_plane, fb->pixel_format); + I915_WRITE(SPSTRIDE(pipe, plane), fb->pitches[0]); I915_WRITE(SPPOS(pipe, plane), (crtc_y << 16) | crtc_x); @@ -1004,20 +1060,6 @@ ilk_get_colorkey(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key) key->flags = I915_SET_COLORKEY_NONE; } -static bool -format_is_yuv(uint32_t format) -{ - switch (format) { - case DRM_FORMAT_YUYV: - case DRM_FORMAT_UYVY: - case DRM_FORMAT_VYUY: - case DRM_FORMAT_YVYU: - return true; - default: - return false; - } -} - static bool colorkey_enabled(struct intel_plane *intel_plane) { struct drm_intel_sprite_colorkey key; -- cgit v1.2.3 From baa4e575d6a18dcd6f2e622784aa16ab24024f09 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Mon, 27 Oct 2014 16:07:32 +0200 Subject: drm/i915: Enable pipe-a power well on chv MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It seems that the pipe-a power well has replaced the disp2d power well on chv. At least that's the case with the current punit firmware. So enable the pipe-a power and expand its domains to cover everything the disp2d well ought to cover. The other power wells (apart from the cmnlane wells) still seem awol in the current punit firmware. So leave them disabled in the code. This fixes a hilarious oops during resume on bsw where intel_hdmi_get_config() would read the port register and get back 0xffffffff and thus think the port is enabled on pipe D. It would then go and index the pipe_to_crtc_mapping[] array with PIPE_D and blow up when intel_hdmi_get_config() tries to write to crtc->config. Someone really ought to replace all naked pipe_to_crtc_mapping[] uses with the appropriate function call so we could add a warning there if the pipe doesn't actually exist... We must also call the power seqeuencer state reset function from the pipe-a well disable just like we do from disp2d on vlv. Otherwise the eDP panel won't recover at resume time since the PPS has lost its hold on the port. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=84903 Signed-off-by: Ville Syrjälä Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_runtime_pm.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index 59ca54fc2487..dcbecffc6b5f 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -587,6 +587,9 @@ static void chv_pipe_power_well_disable(struct drm_i915_private *dev_priv, power_well->data != PIPE_C); chv_set_pipe_power_well(dev_priv, power_well, false); + + if (power_well->data == PIPE_A) + vlv_power_sequencer_reset(dev_priv); } static void check_power_well_state(struct drm_i915_private *dev_priv, @@ -938,12 +941,20 @@ static struct i915_power_well chv_power_wells[] = { .data = PUNIT_POWER_WELL_DISP2D, .ops = &vlv_display_power_well_ops, }, +#endif { .name = "pipe-a", - .domains = CHV_PIPE_A_POWER_DOMAINS, + /* + * FIXME: pipe A power well seems to be the new disp2d well. + * At least all registers seem to be housed there. Figure + * out if this a a temporary situation in pre-production + * hardware or a permanent state of affairs. + */ + .domains = CHV_PIPE_A_POWER_DOMAINS | VLV_DISPLAY_POWER_DOMAINS, .data = PIPE_A, .ops = &chv_pipe_power_well_ops, }, +#if 0 { .name = "pipe-b", .domains = CHV_PIPE_B_POWER_DOMAINS, -- cgit v1.2.3 From 6189b0369c67f5bc6687ee957b3c1317dbb78922 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 28 Oct 2014 13:53:01 +0200 Subject: drm/i915/audio: set ELD Conn_Type at one place Keep the driver modifications to ELD together. This also sets the Conn_Type for G4X DP which wasn't done before. Clean up the debugs while at it; this is all obvious from the connector name. v3: add missing ~ (Rodrigo) Signed-off-by: Jani Nikula Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_audio.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c index 4a384d780b20..537f6d8927f1 100644 --- a/drivers/gpu/drm/i915/intel_audio.c +++ b/drivers/gpu/drm/i915/intel_audio.c @@ -181,13 +181,10 @@ static void haswell_write_eld(struct drm_connector *connector, eldv = AUDIO_ELD_VALID_A << (pipe * 4); - if (intel_pipe_has_type(intel_crtc, INTEL_OUTPUT_DISPLAYPORT)) { - DRM_DEBUG_DRIVER("ELD: DisplayPort detected\n"); - eld[5] |= (1 << 2); /* Conn_Type, 0x1 = DisplayPort */ + if (intel_pipe_has_type(intel_crtc, INTEL_OUTPUT_DISPLAYPORT)) I915_WRITE(aud_config, AUD_CONFIG_N_VALUE_INDEX); /* 0x1 = DP */ - } else { + else I915_WRITE(aud_config, audio_config_hdmi_pixel_clock(mode)); - } if (intel_eld_uptodate(connector, aud_cntrl_st2, eldv, @@ -276,13 +273,10 @@ static void ironlake_write_eld(struct drm_connector *connector, eldv = IBX_ELD_VALIDB << ((port - 1) * 4); } - if (intel_pipe_has_type(intel_crtc, INTEL_OUTPUT_DISPLAYPORT)) { - DRM_DEBUG_DRIVER("ELD: DisplayPort detected\n"); - eld[5] |= (1 << 2); /* Conn_Type, 0x1 = DisplayPort */ + if (intel_pipe_has_type(intel_crtc, INTEL_OUTPUT_DISPLAYPORT)) I915_WRITE(aud_config, AUD_CONFIG_N_VALUE_INDEX); /* 0x1 = DP */ - } else { + else I915_WRITE(aud_config, audio_config_hdmi_pixel_clock(mode)); - } if (intel_eld_uptodate(connector, aud_cntrl_st2, eldv, @@ -330,6 +324,11 @@ void intel_write_eld(struct intel_encoder *intel_encoder) connector->encoder->base.id, connector->encoder->name); + /* ELD Conn_Type */ + connector->eld[5] &= ~(3 << 2); + if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) + connector->eld[5] |= (1 << 2); + connector->eld[6] = drm_av_sync_delay(connector, mode) / 2; if (dev_priv->display.write_eld) -- cgit v1.2.3 From 2aa0de39fa071129fdd952a0d99828db8434d88f Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 27 Oct 2014 16:26:49 +0200 Subject: drm/i915/ddi: write ELD where it's supposed to be done The audio programming sequence states that the ELD must be written and enabled after the pipe is ready. Indeed, this should clarify the situation with commit c79057922ed6c2c6df1214e6ab4414fea1b23db2 Author: Daniel Vetter Date: Wed Apr 16 16:56:09 2014 +0200 drm/i915: Remove vblank wait from haswell_write_eld and Ville's review of it [1]. Moreover, we should not touch the relevant registers before we get the audio power domain. [1] http://mid.gmane.org/20140416155309.GK18465@intel.com Signed-off-by: Jani Nikula Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_audio.c | 2 -- drivers/gpu/drm/i915/intel_ddi.c | 11 ++--------- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c index 537f6d8927f1..158ad60a6e21 100644 --- a/drivers/gpu/drm/i915/intel_audio.c +++ b/drivers/gpu/drm/i915/intel_audio.c @@ -160,8 +160,6 @@ static void haswell_write_eld(struct drm_connector *connector, I915_WRITE(aud_cntrl_st2, tmp); POSTING_READ(aud_cntrl_st2); - assert_pipe_disabled(dev_priv, pipe); - /* Set ELD valid state */ tmp = I915_READ(aud_cntrl_st2); DRM_DEBUG_DRIVER("HDMI audio: pin eld vld status=0x%08x\n", tmp); diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 2688bc940879..56e7cb1ddc75 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1120,15 +1120,6 @@ static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder) enum port port = intel_ddi_get_encoder_port(intel_encoder); int type = intel_encoder->type; - if (crtc->config.has_audio) { - DRM_DEBUG_DRIVER("Audio on pipe %c on DDI\n", - pipe_name(crtc->pipe)); - - /* write eld */ - DRM_DEBUG_DRIVER("DDI audio: write eld information\n"); - intel_write_eld(intel_encoder); - } - if (type == INTEL_OUTPUT_EDP) { struct intel_dp *intel_dp = enc_to_intel_dp(encoder); intel_edp_panel_on(intel_dp); @@ -1225,6 +1216,8 @@ static void intel_enable_ddi(struct intel_encoder *intel_encoder) if (intel_crtc->config.has_audio) { intel_display_power_get(dev_priv, POWER_DOMAIN_AUDIO); + intel_write_eld(intel_encoder); + tmp = I915_READ(HSW_AUD_PIN_ELD_CP_VLD); tmp |= ((AUDIO_OUTPUT_ENABLE_A | AUDIO_ELD_VALID_A) << (pipe * 4)); I915_WRITE(HSW_AUD_PIN_ELD_CP_VLD, tmp); -- cgit v1.2.3 From 69bfe1a9b4dffca482c6cd7f1e218f24a1128dcc Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 27 Oct 2014 16:26:50 +0200 Subject: drm/i915: introduce intel_audio_codec_{enable, disable} Introduce functions to enable/disable the audio codec, incorporating the ELD setup within enable. The disable is initially limited to HSW, covering exactly what was done previously. The only functional difference is that ELD valid is no longer set if there is no connector with ELD, which should be the right thing to do anyway. Otherwise the sequence remains the same, with warts and all, in preparation for applying more sanity. v2: add kernel doc. Signed-off-by: Jani Nikula Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 7 ++-- drivers/gpu/drm/i915/intel_audio.c | 83 +++++++++++++++++++++++++++++--------- drivers/gpu/drm/i915/intel_ddi.c | 17 +------- drivers/gpu/drm/i915/intel_dp.c | 2 +- drivers/gpu/drm/i915/intel_drv.h | 3 +- drivers/gpu/drm/i915/intel_hdmi.c | 2 +- 6 files changed, 73 insertions(+), 41 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 6a73803482cb..0344fd561789 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -483,9 +483,10 @@ struct drm_i915_display_funcs { void (*crtc_enable)(struct drm_crtc *crtc); void (*crtc_disable)(struct drm_crtc *crtc); void (*off)(struct drm_crtc *crtc); - void (*write_eld)(struct drm_connector *connector, - struct intel_encoder *encoder, - struct drm_display_mode *mode); + void (*audio_codec_enable)(struct drm_connector *connector, + struct intel_encoder *encoder, + struct drm_display_mode *mode); + void (*audio_codec_disable)(struct intel_encoder *encoder); void (*fdi_link_train)(struct drm_crtc *crtc); void (*init_clock_gating)(struct drm_device *dev); int (*queue_flip)(struct drm_device *dev, struct drm_crtc *crtc, diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c index 158ad60a6e21..f291efc8b229 100644 --- a/drivers/gpu/drm/i915/intel_audio.c +++ b/drivers/gpu/drm/i915/intel_audio.c @@ -96,9 +96,9 @@ static bool intel_eld_uptodate(struct drm_connector *connector, return true; } -static void g4x_write_eld(struct drm_connector *connector, - struct intel_encoder *encoder, - struct drm_display_mode *mode) +static void g4x_audio_codec_enable(struct drm_connector *connector, + struct intel_encoder *encoder, + struct drm_display_mode *mode) { struct drm_i915_private *dev_priv = connector->dev->dev_private; uint8_t *eld = connector->eld; @@ -136,9 +136,22 @@ static void g4x_write_eld(struct drm_connector *connector, I915_WRITE(G4X_AUD_CNTL_ST, tmp); } -static void haswell_write_eld(struct drm_connector *connector, - struct intel_encoder *encoder, - struct drm_display_mode *mode) +static void hsw_audio_codec_disable(struct intel_encoder *encoder) +{ + struct drm_device *dev = encoder->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_crtc *crtc = encoder->base.crtc; + enum pipe pipe = to_intel_crtc(crtc)->pipe; + uint32_t tmp; + + tmp = I915_READ(HSW_AUD_PIN_ELD_CP_VLD); + tmp &= ~((AUDIO_OUTPUT_ENABLE_A | AUDIO_ELD_VALID_A) << (pipe * 4)); + I915_WRITE(HSW_AUD_PIN_ELD_CP_VLD, tmp); +} + +static void hsw_audio_codec_enable(struct drm_connector *connector, + struct intel_encoder *encoder, + struct drm_display_mode *mode) { struct drm_i915_private *dev_priv = connector->dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); @@ -211,11 +224,16 @@ static void haswell_write_eld(struct drm_connector *connector, tmp = I915_READ(aud_cntrl_st2); tmp |= eldv; I915_WRITE(aud_cntrl_st2, tmp); + + /* XXX: Transitional */ + tmp = I915_READ(HSW_AUD_PIN_ELD_CP_VLD); + tmp |= ((AUDIO_OUTPUT_ENABLE_A | AUDIO_ELD_VALID_A) << (pipe * 4)); + I915_WRITE(HSW_AUD_PIN_ELD_CP_VLD, tmp); } -static void ironlake_write_eld(struct drm_connector *connector, - struct intel_encoder *encoder, - struct drm_display_mode *mode) +static void ilk_audio_codec_enable(struct drm_connector *connector, + struct intel_encoder *encoder, + struct drm_display_mode *mode) { struct drm_i915_private *dev_priv = connector->dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); @@ -303,7 +321,14 @@ static void ironlake_write_eld(struct drm_connector *connector, I915_WRITE(aud_cntrl_st2, tmp); } -void intel_write_eld(struct intel_encoder *intel_encoder) +/** + * intel_audio_codec_enable - Enable the audio codec for HD audio + * @intel_encoder: encoder on which to enable audio + * + * The enable sequences may only be performed after enabling the transcoder and + * port, and after completed link training. + */ +void intel_audio_codec_enable(struct intel_encoder *intel_encoder) { struct drm_encoder *encoder = &intel_encoder->base; struct intel_crtc *crtc = to_intel_crtc(encoder->crtc); @@ -329,8 +354,24 @@ void intel_write_eld(struct intel_encoder *intel_encoder) connector->eld[6] = drm_av_sync_delay(connector, mode) / 2; - if (dev_priv->display.write_eld) - dev_priv->display.write_eld(connector, intel_encoder, mode); + if (dev_priv->display.audio_codec_enable) + dev_priv->display.audio_codec_enable(connector, intel_encoder, mode); +} + +/** + * intel_audio_codec_disable - Disable the audio codec for HD audio + * @encoder: encoder on which to disable audio + * + * The disable sequences must be performed before disabling the transcoder or + * port. + */ +void intel_audio_codec_disable(struct intel_encoder *encoder) +{ + struct drm_device *dev = encoder->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + + if (dev_priv->display.audio_codec_disable) + dev_priv->display.audio_codec_disable(encoder); } /** @@ -341,12 +382,14 @@ void intel_init_audio(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - if (IS_G4X(dev)) - dev_priv->display.write_eld = g4x_write_eld; - else if (IS_VALLEYVIEW(dev)) - dev_priv->display.write_eld = ironlake_write_eld; - else if (IS_HASWELL(dev) || INTEL_INFO(dev)->gen >= 8) - dev_priv->display.write_eld = haswell_write_eld; - else if (HAS_PCH_SPLIT(dev)) - dev_priv->display.write_eld = ironlake_write_eld; + if (IS_G4X(dev)) { + dev_priv->display.audio_codec_enable = g4x_audio_codec_enable; + } else if (IS_VALLEYVIEW(dev)) { + dev_priv->display.audio_codec_enable = ilk_audio_codec_enable; + } else if (IS_HASWELL(dev) || INTEL_INFO(dev)->gen >= 8) { + dev_priv->display.audio_codec_enable = hsw_audio_codec_enable; + dev_priv->display.audio_codec_disable = hsw_audio_codec_disable; + } else if (HAS_PCH_SPLIT(dev)) { + dev_priv->display.audio_codec_enable = ilk_audio_codec_enable; + } } diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 56e7cb1ddc75..b182b9b80461 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1186,12 +1186,10 @@ static void intel_enable_ddi(struct intel_encoder *intel_encoder) struct drm_encoder *encoder = &intel_encoder->base; struct drm_crtc *crtc = encoder->crtc; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - int pipe = intel_crtc->pipe; struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; enum port port = intel_ddi_get_encoder_port(intel_encoder); int type = intel_encoder->type; - uint32_t tmp; if (type == INTEL_OUTPUT_HDMI) { struct intel_digital_port *intel_dig_port = @@ -1216,11 +1214,7 @@ static void intel_enable_ddi(struct intel_encoder *intel_encoder) if (intel_crtc->config.has_audio) { intel_display_power_get(dev_priv, POWER_DOMAIN_AUDIO); - intel_write_eld(intel_encoder); - - tmp = I915_READ(HSW_AUD_PIN_ELD_CP_VLD); - tmp |= ((AUDIO_OUTPUT_ENABLE_A | AUDIO_ELD_VALID_A) << (pipe * 4)); - I915_WRITE(HSW_AUD_PIN_ELD_CP_VLD, tmp); + intel_audio_codec_enable(intel_encoder); } } @@ -1229,19 +1223,12 @@ static void intel_disable_ddi(struct intel_encoder *intel_encoder) struct drm_encoder *encoder = &intel_encoder->base; struct drm_crtc *crtc = encoder->crtc; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - int pipe = intel_crtc->pipe; int type = intel_encoder->type; struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; - uint32_t tmp; - /* We can't touch HSW_AUD_PIN_ELD_CP_VLD uncionditionally because this - * register is part of the power well on Haswell. */ if (intel_crtc->config.has_audio) { - tmp = I915_READ(HSW_AUD_PIN_ELD_CP_VLD); - tmp &= ~((AUDIO_OUTPUT_ENABLE_A | AUDIO_ELD_VALID_A) << - (pipe * 4)); - I915_WRITE(HSW_AUD_PIN_ELD_CP_VLD, tmp); + intel_audio_codec_disable(intel_encoder); intel_display_power_put(dev_priv, POWER_DOMAIN_AUDIO); } diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index ccc690e2e906..f1a5fe26a9c8 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1328,7 +1328,7 @@ static void intel_dp_prepare(struct intel_encoder *encoder) DRM_DEBUG_DRIVER("Enabling DP audio on pipe %c\n", pipe_name(crtc->pipe)); intel_dp->DP |= DP_AUDIO_OUTPUT_ENABLE; - intel_write_eld(encoder); + intel_audio_codec_enable(encoder); } /* Split out the IBX/CPU vs CPT settings */ diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index d53ac23cb127..134ab083fd01 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -853,7 +853,8 @@ void intel_fb_obj_flush(struct drm_i915_gem_object *obj, bool retire); /* intel_audio.c */ void intel_init_audio(struct drm_device *dev); -void intel_write_eld(struct intel_encoder *encoder); +void intel_audio_codec_enable(struct intel_encoder *encoder); +void intel_audio_codec_disable(struct intel_encoder *encoder); /* intel_display.c */ const char *intel_output_name(int output); diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 07b5ebd65d41..f29026a1157d 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -666,7 +666,7 @@ static void intel_hdmi_prepare(struct intel_encoder *encoder) DRM_DEBUG_DRIVER("Enabling HDMI audio on pipe %c\n", pipe_name(crtc->pipe)); hdmi_val |= SDVO_AUDIO_ENABLE; - intel_write_eld(encoder); + intel_audio_codec_enable(encoder); } if (HAS_PCH_CPT(dev)) -- cgit v1.2.3 From d806fbf5d38f23fc1b259fee181b749665d72735 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 27 Oct 2014 16:26:51 +0200 Subject: drm/i915/audio: remove misleading checks for !eld[0] We'll never end up in the hooks with eld[0] unset, as that's checked by drm_select_eld(). Signed-off-by: Jani Nikula Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_audio.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c index f291efc8b229..7580b3823e30 100644 --- a/drivers/gpu/drm/i915/intel_audio.c +++ b/drivers/gpu/drm/i915/intel_audio.c @@ -79,9 +79,6 @@ static bool intel_eld_uptodate(struct drm_connector *connector, tmp = I915_READ(reg_eldv); tmp &= bits_eldv; - if (!eld[0]) - return !tmp; - if (!tmp) return false; @@ -123,9 +120,6 @@ static void g4x_audio_codec_enable(struct drm_connector *connector, len = (tmp >> 9) & 0x1f; /* ELD buffer size */ I915_WRITE(G4X_AUD_CNTL_ST, tmp); - if (!eld[0]) - return; - len = min_t(int, eld[2], len); DRM_DEBUG_DRIVER("ELD size %d\n", len); for (i = 0; i < len; i++) @@ -207,9 +201,6 @@ static void hsw_audio_codec_enable(struct drm_connector *connector, tmp &= ~eldv; I915_WRITE(aud_cntrl_st2, tmp); - if (!eld[0]) - return; - tmp = I915_READ(aud_cntl_st); tmp &= ~IBX_ELD_ADDRESS; I915_WRITE(aud_cntl_st, tmp); @@ -304,9 +295,6 @@ static void ilk_audio_codec_enable(struct drm_connector *connector, tmp &= ~eldv; I915_WRITE(aud_cntrl_st2, tmp); - if (!eld[0]) - return; - tmp = I915_READ(aud_cntl_st); tmp &= ~IBX_ELD_ADDRESS; I915_WRITE(aud_cntl_st, tmp); -- cgit v1.2.3 From 1e74a324465e5a4f8e3ee7c423aef92c54de8a72 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 28 Oct 2014 16:15:51 +0200 Subject: drm/i915: Initialize PPS timestamps on vlv/chv MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The pps timestamp initialization was accidentally lost on vlv/chv in commit a4a5d2f8a96e09844a91469e889f15bd5e927399 Author: Ville Syrjälä Date: Thu Sep 4 14:54:20 2014 +0300 drm/i915: Track which port is using which pipe's power sequencer Restore it so that we avoid introducing random delays into the pps operations during/after driver init time. Cc: Imre Deak Reported-by: Imre Deak Signed-off-by: Ville Syrjälä Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index f1a5fe26a9c8..45c0a6636030 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -5364,12 +5364,11 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, if (is_edp(intel_dp)) { pps_lock(intel_dp); - if (IS_VALLEYVIEW(dev)) { + intel_dp_init_panel_power_timestamps(intel_dp); + if (IS_VALLEYVIEW(dev)) vlv_initial_power_sequencer_setup(intel_dp); - } else { - intel_dp_init_panel_power_timestamps(intel_dp); + else intel_dp_init_panel_power_sequencer(dev, intel_dp); - } pps_unlock(intel_dp); } -- cgit v1.2.3 From 49e6bc51bc9e22c8a433ba32a4e45a5818de3850 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 28 Oct 2014 16:15:52 +0200 Subject: drm/i915: Read out the power sequencer port assignment on resume on vlv/chv MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When we suspend we turn everything off so the pps should be idle, and we also (or at least should) disable all power wells which will reset the power sequencer port assignment. So when we resume all power sequencers should be in their reset state. However it's at least theoretically possible that the BIOS would touch the power seuqencer(s), so to be safe we ought to read out the current port assignment like we do at driver init time. To do that we can simply call vlv_initial_power_sequencer_setup() from the encoder ->reset() hook before calling intel_edp_panel_vdd_sanitize(). There's no danger or clobbering the pps delays since we now have those stored within intel_dp and we don't change them once initialized. This will make sure that the vdd state gets correctly tracked post-resume in case the BIOS enabled it. We need to shuffle things around a bit to get the locking right, and while at it, make intel_edp_panel_vdd_sanitize() static and move it around a bit to avoid a forward declaration. Cc: Imre Deak Signed-off-by: Ville Syrjälä Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 80 +++++++++++++++++++++++----------------- drivers/gpu/drm/i915/intel_drv.h | 1 - 2 files changed, 47 insertions(+), 34 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 45c0a6636030..ec80e828240e 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -4677,9 +4677,52 @@ static void intel_dp_encoder_suspend(struct intel_encoder *intel_encoder) pps_unlock(intel_dp); } +static void intel_edp_panel_vdd_sanitize(struct intel_dp *intel_dp) +{ + 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 intel_display_power_domain power_domain; + + lockdep_assert_held(&dev_priv->pps_mutex); + + if (!edp_have_panel_vdd(intel_dp)) + return; + + /* + * The VDD bit needs a power domain reference, so if the bit is + * already enabled when we boot or resume, grab this reference and + * schedule a vdd off, so we don't hold on to the reference + * indefinitely. + */ + DRM_DEBUG_KMS("VDD left on by BIOS, adjusting state tracking\n"); + power_domain = intel_display_port_power_domain(&intel_dig_port->base); + intel_display_power_get(dev_priv, power_domain); + + edp_panel_vdd_schedule_off(intel_dp); +} + static void intel_dp_encoder_reset(struct drm_encoder *encoder) { - intel_edp_panel_vdd_sanitize(to_intel_encoder(encoder)); + struct intel_dp *intel_dp; + + if (to_intel_encoder(encoder)->type != INTEL_OUTPUT_EDP) + return; + + intel_dp = enc_to_intel_dp(encoder); + + pps_lock(intel_dp); + + /* + * Read out the current power sequencer assignment, + * in case the BIOS did something with it. + */ + if (IS_VALLEYVIEW(encoder->dev)) + vlv_initial_power_sequencer_setup(intel_dp); + + intel_edp_panel_vdd_sanitize(intel_dp); + + pps_unlock(intel_dp); } static const struct drm_connector_funcs intel_dp_connector_funcs = { @@ -5150,37 +5193,6 @@ intel_dp_drrs_init(struct intel_digital_port *intel_dig_port, return downclock_mode; } -void intel_edp_panel_vdd_sanitize(struct intel_encoder *intel_encoder) -{ - struct drm_device *dev = intel_encoder->base.dev; - struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_dp *intel_dp; - enum intel_display_power_domain power_domain; - - if (intel_encoder->type != INTEL_OUTPUT_EDP) - return; - - intel_dp = enc_to_intel_dp(&intel_encoder->base); - - pps_lock(intel_dp); - - if (!edp_have_panel_vdd(intel_dp)) - goto out; - /* - * The VDD bit needs a power domain reference, so if the bit is - * already enabled when we boot or resume, grab this reference and - * schedule a vdd off, so we don't hold on to the reference - * indefinitely. - */ - DRM_DEBUG_KMS("VDD left on by BIOS, adjusting state tracking\n"); - power_domain = intel_display_port_power_domain(intel_encoder); - intel_display_power_get(dev_priv, power_domain); - - edp_panel_vdd_schedule_off(intel_dp); - out: - pps_unlock(intel_dp); -} - static bool intel_edp_init_connector(struct intel_dp *intel_dp, struct intel_connector *intel_connector) { @@ -5200,7 +5212,9 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp, if (!is_edp(intel_dp)) return true; - intel_edp_panel_vdd_sanitize(intel_encoder); + pps_lock(intel_dp); + intel_edp_panel_vdd_sanitize(intel_dp); + pps_unlock(intel_dp); /* Cache DPCD and EDID for edp. */ has_dpcd = intel_dp_get_dpcd(intel_dp); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 134ab083fd01..82d89167cd2f 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -981,7 +981,6 @@ bool intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, void intel_edp_backlight_on(struct intel_dp *intel_dp); void intel_edp_backlight_off(struct intel_dp *intel_dp); void intel_edp_panel_vdd_on(struct intel_dp *intel_dp); -void intel_edp_panel_vdd_sanitize(struct intel_encoder *intel_encoder); void intel_edp_panel_on(struct intel_dp *intel_dp); void intel_edp_panel_off(struct intel_dp *intel_dp); void intel_edp_psr_enable(struct intel_dp *intel_dp); -- cgit v1.2.3 From c883ef1b1c998d2d66866772fd0fc34afa45641e Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Tue, 28 Oct 2014 17:32:30 +0200 Subject: drm/i915: Redefine WARN_ON to include the condition When looking at the bug report logs with triggered WARN_ON, the person doing bug triaging will have to find exact kernel source and match file/line. Attach the condition that triggered the WARN_ON to kernel log. In most cases the context is self evident and this way we can save developer time. The drawback is ~16kbytes bigger i915.ko Signed-off-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 0344fd561789..0e12c6ac2be5 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -57,6 +57,9 @@ #define DRIVER_DESC "Intel Graphics" #define DRIVER_DATE "20141024" +#undef WARN_ON +#define WARN_ON(x) WARN(x, "WARN_ON(" #x ")") + enum pipe { INVALID_PIPE = -1, PIPE_A = 0, -- cgit v1.2.3 From 6402c330a62685c77c32d1bdfa882759c9f8e8a7 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 31 Oct 2014 12:00:26 +0000 Subject: drm/i915: Fix null pointer dereference in ring cleanup code If a ring failed to initialise for any reason then the error path would try to clean up all rings including those that had not yet been allocated. The ring clean up code did a check that the ring was valid before starting its work. Unfortunately, that was after it had already dereferenced the ring to obtain a dev_private pointer. Signed-off-by: John Harrison Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 4 +++- drivers/gpu/drm/i915/intel_ringbuffer.c | 7 +++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 803fc38664c4..d7525bd6d810 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1214,11 +1214,13 @@ static int gen8_emit_request(struct intel_ringbuffer *ringbuf) */ void intel_logical_ring_cleanup(struct intel_engine_cs *ring) { - struct drm_i915_private *dev_priv = ring->dev->dev_private; + struct drm_i915_private *dev_priv; if (!intel_ring_initialized(ring)) return; + dev_priv = ring->dev->dev_private; + intel_logical_ring_stop(ring); WARN_ON((I915_READ_MODE(ring) & MODE_IDLE) == 0); ring->preallocated_lazy_request = NULL; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index a8f72e8d64e3..f457146ff6a4 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1845,12 +1845,15 @@ error: void intel_cleanup_ring_buffer(struct intel_engine_cs *ring) { - struct drm_i915_private *dev_priv = to_i915(ring->dev); - struct intel_ringbuffer *ringbuf = ring->buffer; + struct drm_i915_private *dev_priv; + struct intel_ringbuffer *ringbuf; if (!intel_ring_initialized(ring)) return; + dev_priv = to_i915(ring->dev); + ringbuf = ring->buffer; + intel_stop_ring_buffer(ring); WARN_ON(!IS_GEN2(ring->dev) && (I915_READ_MODE(ring) & MODE_IDLE) == 0); -- cgit v1.2.3 From cd0707cb1dbdd96b0358e5b10eba89c3bbe5a690 Mon Sep 17 00:00:00 2001 From: Dave Gordon Date: Thu, 30 Oct 2014 15:41:56 +0000 Subject: drm/i915: Remove redundant return value and WARN_ON execlists_submit_context() always returns 0, which is redundant. And its name is inaccurate, since it actually submits (up to) TWO contextS. So we rename it, change it to "void", and remove the WARN_ON() testing its return value. Change-Id: Ie225b0eca7754c6093c8b8bd15550b251b6feb82 Signed-off-by: Dave Gordon Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index d7525bd6d810..70a6c63f3b9a 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -356,9 +356,9 @@ static int execlists_ctx_write_tail(struct drm_i915_gem_object *ctx_obj, u32 tai return 0; } -static int execlists_submit_context(struct intel_engine_cs *ring, - struct intel_context *to0, u32 tail0, - struct intel_context *to1, u32 tail1) +static void execlists_submit_contexts(struct intel_engine_cs *ring, + struct intel_context *to0, u32 tail0, + struct intel_context *to1, u32 tail1) { struct drm_i915_gem_object *ctx_obj0; struct drm_i915_gem_object *ctx_obj1 = NULL; @@ -378,8 +378,6 @@ static int execlists_submit_context(struct intel_engine_cs *ring, } execlists_elsp_write(ring, ctx_obj0, ctx_obj1); - - return 0; } static void execlists_context_unqueue(struct intel_engine_cs *ring) @@ -413,9 +411,9 @@ static void execlists_context_unqueue(struct intel_engine_cs *ring) WARN_ON(req1 && req1->elsp_submitted); - WARN_ON(execlists_submit_context(ring, req0->ctx, req0->tail, - req1 ? req1->ctx : NULL, - req1 ? req1->tail : 0)); + execlists_submit_contexts(ring, req0->ctx, req0->tail, + req1 ? req1->ctx : NULL, + req1 ? req1->tail : 0); req0->elsp_submitted++; if (req1) -- cgit v1.2.3 From d0737e1d5944f570d5151ae6213952058c18a903 Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Wed, 29 Oct 2014 11:32:30 +0200 Subject: drm/i915: Make *_crtc_mode_set work on new_config This shouldn't change the behavior of those functions, since they are called after the new_config is made effective and that points to the current config. In a follow up patch, the mode set sequence will be changed so this is called before disabling crtcs, and in that case those functions should work on the staged config. Signed-off-by: Ander Conselvan de Oliveira [danvet: Flatten if by moving the check into the WARN.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 31 +++++-- drivers/gpu/drm/i915/intel_display.c | 153 ++++++++++++++++++++--------------- 2 files changed, 116 insertions(+), 68 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index b182b9b80461..d41768846f18 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -459,6 +459,27 @@ intel_ddi_get_crtc_encoder(struct drm_crtc *crtc) return ret; } +static struct intel_encoder * +intel_ddi_get_crtc_new_encoder(struct intel_crtc *crtc) +{ + struct drm_device *dev = crtc->base.dev; + struct intel_encoder *intel_encoder, *ret = NULL; + int num_encoders = 0; + + for_each_intel_encoder(dev, intel_encoder) { + if (intel_encoder->new_crtc == crtc) { + ret = intel_encoder; + num_encoders++; + } + } + + WARN(num_encoders != 1, "%d encoders on crtc for pipe %c\n", num_encoders, + pipe_name(crtc->pipe)); + + BUG_ON(ret == NULL); + return ret; +} + #define LC_FREQ 2700 #define LC_FREQ_2K U64_C(LC_FREQ * 2000) @@ -792,7 +813,7 @@ hsw_ddi_pll_select(struct intel_crtc *intel_crtc, WRPLL_DIVIDER_REFERENCE(r2) | WRPLL_DIVIDER_FEEDBACK(n2) | WRPLL_DIVIDER_POST(p); - intel_crtc->config.dpll_hw_state.wrpll = val; + intel_crtc->new_config->dpll_hw_state.wrpll = val; pll = intel_get_shared_dpll(intel_crtc); if (pll == NULL) { @@ -801,7 +822,7 @@ hsw_ddi_pll_select(struct intel_crtc *intel_crtc, return false; } - intel_crtc->config.ddi_pll_sel = PORT_CLK_SEL_WRPLL(pll->id); + intel_crtc->new_config->ddi_pll_sel = PORT_CLK_SEL_WRPLL(pll->id); } return true; @@ -817,9 +838,9 @@ hsw_ddi_pll_select(struct intel_crtc *intel_crtc, */ bool intel_ddi_pll_select(struct intel_crtc *intel_crtc) { - struct drm_crtc *crtc = &intel_crtc->base; - struct intel_encoder *intel_encoder = intel_ddi_get_crtc_encoder(crtc); - int clock = intel_crtc->config.port_clock; + struct intel_encoder *intel_encoder = + intel_ddi_get_crtc_new_encoder(intel_crtc); + int clock = intel_crtc->new_config->port_clock; intel_put_shared_dpll(intel_crtc); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index c17ec502b087..6bd290d902df 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -420,13 +420,31 @@ bool intel_pipe_has_type(struct intel_crtc *crtc, int type) return false; } +/** + * Returns whether any output on the specified pipe will have the specified + * type after a staged modeset is complete, i.e., the same as + * intel_pipe_has_type() but looking at encoder->new_crtc instead of + * encoder->crtc. + */ +static bool intel_pipe_will_have_type(struct intel_crtc *crtc, int type) +{ + struct drm_device *dev = crtc->base.dev; + struct intel_encoder *encoder; + + for_each_intel_encoder(dev, encoder) + if (encoder->new_crtc == crtc && encoder->type == type) + return true; + + return false; +} + static const intel_limit_t *intel_ironlake_limit(struct intel_crtc *crtc, int refclk) { struct drm_device *dev = crtc->base.dev; const intel_limit_t *limit; - if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { + if (intel_pipe_will_have_type(crtc, INTEL_OUTPUT_LVDS)) { if (intel_is_dual_link_lvds(dev)) { if (refclk == 100000) limit = &intel_limits_ironlake_dual_lvds_100m; @@ -449,15 +467,15 @@ static const intel_limit_t *intel_g4x_limit(struct intel_crtc *crtc) struct drm_device *dev = crtc->base.dev; const intel_limit_t *limit; - if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { + if (intel_pipe_will_have_type(crtc, INTEL_OUTPUT_LVDS)) { if (intel_is_dual_link_lvds(dev)) limit = &intel_limits_g4x_dual_channel_lvds; else limit = &intel_limits_g4x_single_channel_lvds; - } else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_HDMI) || - intel_pipe_has_type(crtc, INTEL_OUTPUT_ANALOG)) { + } else if (intel_pipe_will_have_type(crtc, INTEL_OUTPUT_HDMI) || + intel_pipe_will_have_type(crtc, INTEL_OUTPUT_ANALOG)) { limit = &intel_limits_g4x_hdmi; - } else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_SDVO)) { + } else if (intel_pipe_will_have_type(crtc, INTEL_OUTPUT_SDVO)) { limit = &intel_limits_g4x_sdvo; } else /* The option is for other outputs */ limit = &intel_limits_i9xx_sdvo; @@ -475,7 +493,7 @@ static const intel_limit_t *intel_limit(struct intel_crtc *crtc, int refclk) else if (IS_G4X(dev)) { limit = intel_g4x_limit(crtc); } else if (IS_PINEVIEW(dev)) { - if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) + if (intel_pipe_will_have_type(crtc, INTEL_OUTPUT_LVDS)) limit = &intel_limits_pineview_lvds; else limit = &intel_limits_pineview_sdvo; @@ -484,14 +502,14 @@ static const intel_limit_t *intel_limit(struct intel_crtc *crtc, int refclk) } else if (IS_VALLEYVIEW(dev)) { limit = &intel_limits_vlv; } else if (!IS_GEN2(dev)) { - if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) + if (intel_pipe_will_have_type(crtc, INTEL_OUTPUT_LVDS)) limit = &intel_limits_i9xx_lvds; else limit = &intel_limits_i9xx_sdvo; } else { - if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) + if (intel_pipe_will_have_type(crtc, INTEL_OUTPUT_LVDS)) limit = &intel_limits_i8xx_lvds; - else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DVO)) + else if (intel_pipe_will_have_type(crtc, INTEL_OUTPUT_DVO)) limit = &intel_limits_i8xx_dvo; else limit = &intel_limits_i8xx_dac; @@ -586,7 +604,7 @@ i9xx_find_best_dpll(const intel_limit_t *limit, struct intel_crtc *crtc, intel_clock_t clock; int err = target; - if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { + if (intel_pipe_will_have_type(crtc, INTEL_OUTPUT_LVDS)) { /* * For LVDS just rely on its current settings for dual-channel. * We haven't figured out how to reliably set up different @@ -647,7 +665,7 @@ pnv_find_best_dpll(const intel_limit_t *limit, struct intel_crtc *crtc, intel_clock_t clock; int err = target; - if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { + if (intel_pipe_will_have_type(crtc, INTEL_OUTPUT_LVDS)) { /* * For LVDS just rely on its current settings for dual-channel. * We haven't figured out how to reliably set up different @@ -710,7 +728,7 @@ g4x_find_best_dpll(const intel_limit_t *limit, struct intel_crtc *crtc, int err_most = (target >> 8) + (target >> 9); found = false; - if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { + if (intel_pipe_will_have_type(crtc, INTEL_OUTPUT_LVDS)) { if (intel_is_dual_link_lvds(dev)) clock.p2 = limit->p2.p2_fast; else @@ -5628,7 +5646,7 @@ static int i9xx_get_refclk(struct intel_crtc *crtc, int num_connectors) if (IS_VALLEYVIEW(dev)) { refclk = 100000; - } else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) && + } else if (intel_pipe_will_have_type(crtc, INTEL_OUTPUT_LVDS) && intel_panel_use_ssc(dev_priv) && num_connectors < 2) { refclk = dev_priv->vbt.lvds_ssc_freq; DRM_DEBUG_KMS("using SSC reference clock of %d kHz\n", refclk); @@ -6018,29 +6036,29 @@ static void i9xx_update_pll(struct intel_crtc *crtc, struct drm_i915_private *dev_priv = dev->dev_private; u32 dpll; bool is_sdvo; - struct dpll *clock = &crtc->config.dpll; + struct dpll *clock = &crtc->new_config->dpll; i9xx_update_pll_dividers(crtc, reduced_clock); - is_sdvo = intel_pipe_has_type(crtc, INTEL_OUTPUT_SDVO) || - intel_pipe_has_type(crtc, INTEL_OUTPUT_HDMI); + is_sdvo = intel_pipe_will_have_type(crtc, INTEL_OUTPUT_SDVO) || + intel_pipe_will_have_type(crtc, INTEL_OUTPUT_HDMI); dpll = DPLL_VGA_MODE_DIS; - if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) + if (intel_pipe_will_have_type(crtc, INTEL_OUTPUT_LVDS)) dpll |= DPLLB_MODE_LVDS; else dpll |= DPLLB_MODE_DAC_SERIAL; if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) { - dpll |= (crtc->config.pixel_multiplier - 1) + dpll |= (crtc->new_config->pixel_multiplier - 1) << SDVO_MULTIPLIER_SHIFT_HIRES; } if (is_sdvo) dpll |= DPLL_SDVO_HIGH_SPEED; - if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) + if (intel_pipe_will_have_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) dpll |= DPLL_SDVO_HIGH_SPEED; /* compute bitmask from p1 value */ @@ -6068,21 +6086,21 @@ static void i9xx_update_pll(struct intel_crtc *crtc, if (INTEL_INFO(dev)->gen >= 4) dpll |= (6 << PLL_LOAD_PULSE_PHASE_SHIFT); - if (crtc->config.sdvo_tv_clock) + if (crtc->new_config->sdvo_tv_clock) dpll |= PLL_REF_INPUT_TVCLKINBC; - else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) && + else if (intel_pipe_will_have_type(crtc, INTEL_OUTPUT_LVDS) && intel_panel_use_ssc(dev_priv) && num_connectors < 2) dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN; else dpll |= PLL_REF_INPUT_DREFCLK; dpll |= DPLL_VCO_ENABLE; - crtc->config.dpll_hw_state.dpll = dpll; + crtc->new_config->dpll_hw_state.dpll = dpll; if (INTEL_INFO(dev)->gen >= 4) { - u32 dpll_md = (crtc->config.pixel_multiplier - 1) + u32 dpll_md = (crtc->new_config->pixel_multiplier - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT; - crtc->config.dpll_hw_state.dpll_md = dpll_md; + crtc->new_config->dpll_hw_state.dpll_md = dpll_md; } } @@ -6093,13 +6111,13 @@ static void i8xx_update_pll(struct intel_crtc *crtc, struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; u32 dpll; - struct dpll *clock = &crtc->config.dpll; + struct dpll *clock = &crtc->new_config->dpll; i9xx_update_pll_dividers(crtc, reduced_clock); dpll = DPLL_VGA_MODE_DIS; - if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { + if (intel_pipe_will_have_type(crtc, INTEL_OUTPUT_LVDS)) { dpll |= (1 << (clock->p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT; } else { if (clock->p1 == 2) @@ -6110,17 +6128,17 @@ static void i8xx_update_pll(struct intel_crtc *crtc, dpll |= PLL_P2_DIVIDE_BY_4; } - if (!IS_I830(dev) && intel_pipe_has_type(crtc, INTEL_OUTPUT_DVO)) + if (!IS_I830(dev) && intel_pipe_will_have_type(crtc, INTEL_OUTPUT_DVO)) dpll |= DPLL_DVO_2X_MODE; - if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) && + if (intel_pipe_will_have_type(crtc, INTEL_OUTPUT_LVDS) && intel_panel_use_ssc(dev_priv) && num_connectors < 2) dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN; else dpll |= PLL_REF_INPUT_DREFCLK; dpll |= DPLL_VCO_ENABLE; - crtc->config.dpll_hw_state.dpll = dpll; + crtc->new_config->dpll_hw_state.dpll = dpll; } static void intel_set_pipe_timings(struct intel_crtc *intel_crtc) @@ -6329,7 +6347,10 @@ static int i9xx_crtc_mode_set(struct intel_crtc *crtc, struct intel_encoder *encoder; const intel_limit_t *limit; - for_each_encoder_on_crtc(dev, &crtc->base, encoder) { + for_each_intel_encoder(dev, encoder) { + if (encoder->new_crtc != crtc) + continue; + switch (encoder->type) { case INTEL_OUTPUT_LVDS: is_lvds = true; @@ -6347,7 +6368,7 @@ static int i9xx_crtc_mode_set(struct intel_crtc *crtc, if (is_dsi) return 0; - if (!crtc->config.clock_set) { + if (!crtc->new_config->clock_set) { refclk = i9xx_get_refclk(crtc, num_connectors); /* @@ -6358,7 +6379,7 @@ static int i9xx_crtc_mode_set(struct intel_crtc *crtc, */ limit = intel_limit(crtc, refclk); ok = dev_priv->display.find_dpll(limit, crtc, - crtc->config.port_clock, + crtc->new_config->port_clock, refclk, NULL, &clock); if (!ok) { DRM_ERROR("Couldn't find PLL settings for mode!\n"); @@ -6379,11 +6400,11 @@ static int i9xx_crtc_mode_set(struct intel_crtc *crtc, &reduced_clock); } /* Compat-code for transition, will disappear. */ - crtc->config.dpll.n = clock.n; - crtc->config.dpll.m1 = clock.m1; - crtc->config.dpll.m2 = clock.m2; - crtc->config.dpll.p1 = clock.p1; - crtc->config.dpll.p2 = clock.p2; + crtc->new_config->dpll.n = clock.n; + crtc->new_config->dpll.m1 = clock.m1; + crtc->new_config->dpll.m2 = clock.m2; + crtc->new_config->dpll.p1 = clock.p1; + crtc->new_config->dpll.p2 = clock.p2; } if (IS_GEN2(dev)) { @@ -6391,9 +6412,9 @@ static int i9xx_crtc_mode_set(struct intel_crtc *crtc, has_reduced_clock ? &reduced_clock : NULL, num_connectors); } else if (IS_CHERRYVIEW(dev)) { - chv_update_pll(crtc, &crtc->config); + chv_update_pll(crtc, crtc->new_config); } else if (IS_VALLEYVIEW(dev)) { - vlv_update_pll(crtc, &crtc->config); + vlv_update_pll(crtc, crtc->new_config); } else { i9xx_update_pll(crtc, has_reduced_clock ? &reduced_clock : NULL, @@ -7003,7 +7024,10 @@ static int ironlake_get_refclk(struct drm_crtc *crtc) int num_connectors = 0; bool is_lvds = false; - for_each_encoder_on_crtc(dev, crtc, encoder) { + for_each_intel_encoder(dev, encoder) { + if (encoder->new_crtc != to_intel_crtc(crtc)) + continue; + switch (encoder->type) { case INTEL_OUTPUT_LVDS: is_lvds = true; @@ -7194,7 +7218,7 @@ static bool ironlake_compute_clocks(struct drm_crtc *crtc, const intel_limit_t *limit; bool ret, is_lvds = false; - is_lvds = intel_pipe_has_type(intel_crtc, INTEL_OUTPUT_LVDS); + is_lvds = intel_pipe_will_have_type(intel_crtc, INTEL_OUTPUT_LVDS); refclk = ironlake_get_refclk(crtc); @@ -7205,7 +7229,7 @@ static bool ironlake_compute_clocks(struct drm_crtc *crtc, */ limit = intel_limit(intel_crtc, refclk); ret = dev_priv->display.find_dpll(limit, intel_crtc, - intel_crtc->config.port_clock, + intel_crtc->new_config->port_clock, refclk, NULL, clock); if (!ret) return false; @@ -7255,7 +7279,10 @@ static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc, int factor, num_connectors = 0; bool is_lvds = false, is_sdvo = false; - for_each_encoder_on_crtc(dev, crtc, intel_encoder) { + for_each_intel_encoder(dev, intel_encoder) { + if (intel_encoder->new_crtc != to_intel_crtc(crtc)) + continue; + switch (intel_encoder->type) { case INTEL_OUTPUT_LVDS: is_lvds = true; @@ -7278,10 +7305,10 @@ static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc, dev_priv->vbt.lvds_ssc_freq == 100000) || (HAS_PCH_IBX(dev) && intel_is_dual_link_lvds(dev))) factor = 25; - } else if (intel_crtc->config.sdvo_tv_clock) + } else if (intel_crtc->new_config->sdvo_tv_clock) factor = 20; - if (ironlake_needs_fb_cb_tune(&intel_crtc->config.dpll, factor)) + if (ironlake_needs_fb_cb_tune(&intel_crtc->new_config->dpll, factor)) *fp |= FP_CB_TUNE; if (fp2 && (reduced_clock->m < factor * reduced_clock->n)) @@ -7294,20 +7321,20 @@ static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc, else dpll |= DPLLB_MODE_DAC_SERIAL; - dpll |= (intel_crtc->config.pixel_multiplier - 1) + dpll |= (intel_crtc->new_config->pixel_multiplier - 1) << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT; if (is_sdvo) dpll |= DPLL_SDVO_HIGH_SPEED; - if (intel_crtc->config.has_dp_encoder) + if (intel_crtc->new_config->has_dp_encoder) dpll |= DPLL_SDVO_HIGH_SPEED; /* compute bitmask from p1 value */ - dpll |= (1 << (intel_crtc->config.dpll.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT; + dpll |= (1 << (intel_crtc->new_config->dpll.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT; /* also FPA1 */ - dpll |= (1 << (intel_crtc->config.dpll.p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT; + dpll |= (1 << (intel_crtc->new_config->dpll.p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT; - switch (intel_crtc->config.dpll.p2) { + switch (intel_crtc->new_config->dpll.p2) { case 5: dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_5; break; @@ -7348,22 +7375,22 @@ static int ironlake_crtc_mode_set(struct intel_crtc *crtc, ok = ironlake_compute_clocks(&crtc->base, &clock, &has_reduced_clock, &reduced_clock); - if (!ok && !crtc->config.clock_set) { + if (!ok && !crtc->new_config->clock_set) { DRM_ERROR("Couldn't find PLL settings for mode!\n"); return -EINVAL; } /* Compat-code for transition, will disappear. */ - if (!crtc->config.clock_set) { - crtc->config.dpll.n = clock.n; - crtc->config.dpll.m1 = clock.m1; - crtc->config.dpll.m2 = clock.m2; - crtc->config.dpll.p1 = clock.p1; - crtc->config.dpll.p2 = clock.p2; + if (!crtc->new_config->clock_set) { + crtc->new_config->dpll.n = clock.n; + crtc->new_config->dpll.m1 = clock.m1; + crtc->new_config->dpll.m2 = clock.m2; + crtc->new_config->dpll.p1 = clock.p1; + crtc->new_config->dpll.p2 = clock.p2; } /* CPU eDP is the only output that doesn't need a PCH PLL of its own. */ - if (crtc->config.has_pch_encoder) { - fp = i9xx_dpll_compute_fp(&crtc->config.dpll); + if (crtc->new_config->has_pch_encoder) { + fp = i9xx_dpll_compute_fp(&crtc->new_config->dpll); if (has_reduced_clock) fp2 = i9xx_dpll_compute_fp(&reduced_clock); @@ -7371,12 +7398,12 @@ static int ironlake_crtc_mode_set(struct intel_crtc *crtc, &fp, &reduced_clock, has_reduced_clock ? &fp2 : NULL); - crtc->config.dpll_hw_state.dpll = dpll; - crtc->config.dpll_hw_state.fp0 = fp; + crtc->new_config->dpll_hw_state.dpll = dpll; + crtc->new_config->dpll_hw_state.fp0 = fp; if (has_reduced_clock) - crtc->config.dpll_hw_state.fp1 = fp2; + crtc->new_config->dpll_hw_state.fp1 = fp2; else - crtc->config.dpll_hw_state.fp1 = fp; + crtc->new_config->dpll_hw_state.fp1 = fp; pll = intel_get_shared_dpll(crtc); if (pll == NULL) { -- cgit v1.2.3 From 0a88818d093b4d5746d7b3af3acc2b2bddd59808 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 3 Nov 2014 14:37:38 +0100 Subject: drm/i915: Check pipe_config.has_dp_encoder instead of encoder types More concise. Noticed while reviewing Ander's patch which touched a lot of the pipe_has_type checks. v2: Use new_config in one place Ander spotted. Cc: Ander Conselvan de Oliveira Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 6bd290d902df..96663eb37533 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3786,9 +3786,7 @@ static void ironlake_pch_enable(struct drm_crtc *crtc) intel_fdi_normal_train(crtc); /* For PCH DP, enable TRANS_DP_CTL */ - if (HAS_PCH_CPT(dev) && - (intel_pipe_has_type(intel_crtc, INTEL_OUTPUT_DISPLAYPORT) || - intel_pipe_has_type(intel_crtc, INTEL_OUTPUT_EDP))) { + if (HAS_PCH_CPT(dev) && intel_crtc->config.has_dp_encoder) { u32 bpc = (I915_READ(PIPECONF(pipe)) & PIPECONF_BPC_MASK) >> 5; reg = TRANS_DP_CTL(pipe); temp = I915_READ(reg); @@ -5867,8 +5865,7 @@ static void vlv_prepare_pll(struct intel_crtc *crtc, vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW10(pipe), 0x00d0000f); - if (intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP) || - intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) { + if (crtc->config.has_dp_encoder) { /* Use SSC source */ if (pipe == PIPE_A) vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW5(pipe), @@ -6058,7 +6055,7 @@ static void i9xx_update_pll(struct intel_crtc *crtc, if (is_sdvo) dpll |= DPLL_SDVO_HIGH_SPEED; - if (intel_pipe_will_have_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) + if (crtc->new_config->has_dp_encoder) dpll |= DPLL_SDVO_HIGH_SPEED; /* compute bitmask from p1 value */ -- cgit v1.2.3 From 1e6f2ddc88fec990ef4fb1aa3b7cb9941df0321b Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Wed, 29 Oct 2014 11:32:31 +0200 Subject: drm/i915: Convert shared dpll reference count to a crtc mask This will be used in a follow up patch to properly release shared DPLLs without relying on the shared_dpll field in pipe_config. v2: Fix white space error (Ville) Use hweight32() (Ville) Signed-off-by: Ander Conselvan de Oliveira Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 4 +-- drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/intel_display.c | 50 +++++++++++++++++++----------------- 3 files changed, 30 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index a79f83ce9c84..ce32ae788c3c 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2630,8 +2630,8 @@ static int i915_shared_dplls_info(struct seq_file *m, void *unused) struct intel_shared_dpll *pll = &dev_priv->shared_dplls[i]; seq_printf(m, "DPLL%i: %s, id: %i\n", i, pll->name, pll->id); - seq_printf(m, " refcount: %i, active: %i, on: %s\n", pll->refcount, - pll->active, yesno(pll->on)); + seq_printf(m, " crtc_mask: 0x%08x, active: %d, on: %s\n", + pll->crtc_mask, pll->active, yesno(pll->on)); seq_printf(m, " tracked hardware state:\n"); seq_printf(m, " dpll: 0x%08x\n", pll->hw_state.dpll); seq_printf(m, " dpll_md: 0x%08x\n", pll->hw_state.dpll_md); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 0e12c6ac2be5..4f4eef701ce0 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -230,7 +230,7 @@ struct intel_dpll_hw_state { }; struct intel_shared_dpll { - int refcount; /* count of number of CRTCs sharing this PLL */ + unsigned crtc_mask; /* mask of CRTCs sharing this PLL */ int active; /* count of number of active CRTCs (i.e. DPMS on) */ bool on; /* is the PLL actually active? Disabled during modeset */ const char *name; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 96663eb37533..5219b29719ad 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1779,7 +1779,7 @@ static void intel_prepare_shared_dpll(struct intel_crtc *crtc) if (WARN_ON(pll == NULL)) return; - WARN_ON(!pll->refcount); + WARN_ON(!pll->crtc_mask); if (pll->active == 0) { DRM_DEBUG_DRIVER("setting up %s\n", pll->name); WARN_ON(pll->on); @@ -1806,7 +1806,7 @@ static void intel_enable_shared_dpll(struct intel_crtc *crtc) if (WARN_ON(pll == NULL)) return; - if (WARN_ON(pll->refcount == 0)) + if (WARN_ON(pll->crtc_mask == 0)) return; DRM_DEBUG_KMS("enable %s (active %d, on? %d) for crtc %d\n", @@ -1838,7 +1838,7 @@ static void intel_disable_shared_dpll(struct intel_crtc *crtc) if (WARN_ON(pll == NULL)) return; - if (WARN_ON(pll->refcount == 0)) + if (WARN_ON(pll->crtc_mask == 0)) return; DRM_DEBUG_KMS("disable %s (active %d, on? %d) for crtc %d\n", @@ -3846,12 +3846,13 @@ void intel_put_shared_dpll(struct intel_crtc *crtc) if (pll == NULL) return; - if (pll->refcount == 0) { - WARN(1, "bad %s refcount\n", pll->name); + if (!(pll->crtc_mask & (1 << crtc->pipe))) { + WARN(1, "bad %s crtc mask\n", pll->name); return; } - if (--pll->refcount == 0) { + pll->crtc_mask &= ~(1 << crtc->pipe); + if (pll->crtc_mask == 0) { WARN_ON(pll->on); WARN_ON(pll->active); } @@ -3879,7 +3880,7 @@ struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc) DRM_DEBUG_KMS("CRTC:%d using pre-allocated %s\n", crtc->base.base.id, pll->name); - WARN_ON(pll->refcount); + WARN_ON(pll->crtc_mask); goto found; } @@ -3888,14 +3889,15 @@ struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc) pll = &dev_priv->shared_dplls[i]; /* Only want to check enabled timings first */ - if (pll->refcount == 0) + if (pll->crtc_mask == 0) continue; if (memcmp(&crtc->config.dpll_hw_state, &pll->hw_state, sizeof(pll->hw_state)) == 0) { - DRM_DEBUG_KMS("CRTC:%d sharing existing %s (refcount %d, ative %d)\n", - crtc->base.base.id, - pll->name, pll->refcount, pll->active); + DRM_DEBUG_KMS("CRTC:%d sharing existing %s " + "(crtc_mask 0x%08x, active %d)\n", + crtc->base.base.id, pll->name, + pll->crtc_mask, pll->active); goto found; } @@ -3904,7 +3906,7 @@ struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc) /* Ok no matching timings, maybe there's a free one? */ for (i = 0; i < dev_priv->num_shared_dpll; i++) { pll = &dev_priv->shared_dplls[i]; - if (pll->refcount == 0) { + if (pll->crtc_mask == 0) { DRM_DEBUG_KMS("CRTC:%d allocated %s\n", crtc->base.base.id, pll->name); goto found; @@ -3914,14 +3916,14 @@ struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc) return NULL; found: - if (pll->refcount == 0) + if (pll->crtc_mask == 0) pll->hw_state = crtc->config.dpll_hw_state; crtc->config.shared_dpll = i; DRM_DEBUG_DRIVER("using %s for pipe %c\n", pll->name, pipe_name(crtc->pipe)); - pll->refcount++; + pll->crtc_mask |= 1 << crtc->pipe; return pll; } @@ -10604,9 +10606,9 @@ check_shared_dpll_state(struct drm_device *dev) active = pll->get_hw_state(dev_priv, pll, &dpll_hw_state); - WARN(pll->active > pll->refcount, + WARN(pll->active > hweight32(pll->crtc_mask), "more active pll users than references: %i vs %i\n", - pll->active, pll->refcount); + pll->active, hweight32(pll->crtc_mask)); WARN(pll->active && !pll->on, "pll in active use but not on in sw tracking\n"); WARN(pll->on && !pll->active, @@ -10624,9 +10626,9 @@ check_shared_dpll_state(struct drm_device *dev) WARN(pll->active != active_crtcs, "pll active crtcs mismatch (expected %i, found %i)\n", pll->active, active_crtcs); - WARN(pll->refcount != enabled_crtcs, + WARN(hweight32(pll->crtc_mask) != enabled_crtcs, "pll enabled crtcs mismatch (expected %i, found %i)\n", - pll->refcount, enabled_crtcs); + hweight32(pll->crtc_mask), enabled_crtcs); WARN(pll->on && memcmp(&pll->hw_state, &dpll_hw_state, sizeof(dpll_hw_state)), @@ -13077,16 +13079,18 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev) pll->on = pll->get_hw_state(dev_priv, pll, &pll->hw_state); pll->active = 0; + pll->crtc_mask = 0; for_each_intel_crtc(dev, crtc) { - if (crtc->active && intel_crtc_to_shared_dpll(crtc) == pll) + if (crtc->active && intel_crtc_to_shared_dpll(crtc) == pll) { pll->active++; + pll->crtc_mask |= 1 << crtc->pipe; + } } - pll->refcount = pll->active; - DRM_DEBUG_KMS("%s hw state readout: refcount %i, on %i\n", - pll->name, pll->refcount, pll->on); + DRM_DEBUG_KMS("%s hw state readout: crtc_mask 0x%08x, on %i\n", + pll->name, pll->crtc_mask, pll->on); - if (pll->refcount) + if (pll->crtc_mask) intel_display_power_get(dev_priv, POWER_DOMAIN_PLLS); } -- cgit v1.2.3 From 3e369b76ceb625dffabef6f1c52e32fc0998843e Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Wed, 29 Oct 2014 11:32:32 +0200 Subject: drm/i915: Move dpll crtc_mask and hw_state fields into separate struct The new struct will be used in a follow up patch to allow a current and a staged config to exist for the same shared DPLL. v2: Rebase on by mask_to_refcount()->hweight32() change. (Damien) Signed-off-by: Ander Conselvan de Oliveira Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 13 ++++---- drivers/gpu/drm/i915/i915_drv.h | 8 +++-- drivers/gpu/drm/i915/intel_ddi.c | 2 +- drivers/gpu/drm/i915/intel_display.c | 60 +++++++++++++++++++----------------- 4 files changed, 45 insertions(+), 38 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index ce32ae788c3c..0a6981399642 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2631,13 +2631,14 @@ static int i915_shared_dplls_info(struct seq_file *m, void *unused) seq_printf(m, "DPLL%i: %s, id: %i\n", i, pll->name, pll->id); seq_printf(m, " crtc_mask: 0x%08x, active: %d, on: %s\n", - pll->crtc_mask, pll->active, yesno(pll->on)); + pll->config.crtc_mask, pll->active, yesno(pll->on)); seq_printf(m, " tracked hardware state:\n"); - seq_printf(m, " dpll: 0x%08x\n", pll->hw_state.dpll); - seq_printf(m, " dpll_md: 0x%08x\n", pll->hw_state.dpll_md); - seq_printf(m, " fp0: 0x%08x\n", pll->hw_state.fp0); - seq_printf(m, " fp1: 0x%08x\n", pll->hw_state.fp1); - seq_printf(m, " wrpll: 0x%08x\n", pll->hw_state.wrpll); + seq_printf(m, " dpll: 0x%08x\n", pll->config.hw_state.dpll); + seq_printf(m, " dpll_md: 0x%08x\n", + pll->config.hw_state.dpll_md); + seq_printf(m, " fp0: 0x%08x\n", pll->config.hw_state.fp0); + seq_printf(m, " fp1: 0x%08x\n", pll->config.hw_state.fp1); + seq_printf(m, " wrpll: 0x%08x\n", pll->config.hw_state.wrpll); } drm_modeset_unlock_all(dev); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 4f4eef701ce0..62a8e058d7db 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -229,14 +229,18 @@ struct intel_dpll_hw_state { uint32_t wrpll; }; -struct intel_shared_dpll { +struct intel_shared_dpll_config { unsigned crtc_mask; /* mask of CRTCs sharing this PLL */ + struct intel_dpll_hw_state hw_state; +}; + +struct intel_shared_dpll { + struct intel_shared_dpll_config config; int active; /* count of number of active CRTCs (i.e. DPMS on) */ bool on; /* is the PLL actually active? Disabled during modeset */ const char *name; /* should match the index in the dev_priv->shared_dplls array */ enum intel_dpll_id id; - struct intel_dpll_hw_state hw_state; /* The mode_set hook is optional and should be used together with the * intel_prepare_shared_dpll function. */ void (*mode_set)(struct drm_i915_private *dev_priv, diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index d41768846f18..6f9712bba210 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1312,7 +1312,7 @@ int intel_ddi_get_cdclk_freq(struct drm_i915_private *dev_priv) static void hsw_ddi_pll_enable(struct drm_i915_private *dev_priv, struct intel_shared_dpll *pll) { - I915_WRITE(WRPLL_CTL(pll->id), pll->hw_state.wrpll); + I915_WRITE(WRPLL_CTL(pll->id), pll->config.hw_state.wrpll); POSTING_READ(WRPLL_CTL(pll->id)); udelay(20); } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 5219b29719ad..5eb475409657 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1779,7 +1779,7 @@ static void intel_prepare_shared_dpll(struct intel_crtc *crtc) if (WARN_ON(pll == NULL)) return; - WARN_ON(!pll->crtc_mask); + WARN_ON(!pll->config.crtc_mask); if (pll->active == 0) { DRM_DEBUG_DRIVER("setting up %s\n", pll->name); WARN_ON(pll->on); @@ -1806,7 +1806,7 @@ static void intel_enable_shared_dpll(struct intel_crtc *crtc) if (WARN_ON(pll == NULL)) return; - if (WARN_ON(pll->crtc_mask == 0)) + if (WARN_ON(pll->config.crtc_mask == 0)) return; DRM_DEBUG_KMS("enable %s (active %d, on? %d) for crtc %d\n", @@ -1838,7 +1838,7 @@ static void intel_disable_shared_dpll(struct intel_crtc *crtc) if (WARN_ON(pll == NULL)) return; - if (WARN_ON(pll->crtc_mask == 0)) + if (WARN_ON(pll->config.crtc_mask == 0)) return; DRM_DEBUG_KMS("disable %s (active %d, on? %d) for crtc %d\n", @@ -3846,13 +3846,13 @@ void intel_put_shared_dpll(struct intel_crtc *crtc) if (pll == NULL) return; - if (!(pll->crtc_mask & (1 << crtc->pipe))) { + if (!(pll->config.crtc_mask & (1 << crtc->pipe))) { WARN(1, "bad %s crtc mask\n", pll->name); return; } - pll->crtc_mask &= ~(1 << crtc->pipe); - if (pll->crtc_mask == 0) { + pll->config.crtc_mask &= ~(1 << crtc->pipe); + if (pll->config.crtc_mask == 0) { WARN_ON(pll->on); WARN_ON(pll->active); } @@ -3880,7 +3880,7 @@ struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc) DRM_DEBUG_KMS("CRTC:%d using pre-allocated %s\n", crtc->base.base.id, pll->name); - WARN_ON(pll->crtc_mask); + WARN_ON(pll->config.crtc_mask); goto found; } @@ -3889,15 +3889,16 @@ struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc) pll = &dev_priv->shared_dplls[i]; /* Only want to check enabled timings first */ - if (pll->crtc_mask == 0) + if (pll->config.crtc_mask == 0) continue; - if (memcmp(&crtc->config.dpll_hw_state, &pll->hw_state, - sizeof(pll->hw_state)) == 0) { + if (memcmp(&crtc->config.dpll_hw_state, + &pll->config.hw_state, + sizeof(pll->config.hw_state)) == 0) { DRM_DEBUG_KMS("CRTC:%d sharing existing %s " "(crtc_mask 0x%08x, active %d)\n", crtc->base.base.id, pll->name, - pll->crtc_mask, pll->active); + pll->config.crtc_mask, pll->active); goto found; } @@ -3906,7 +3907,7 @@ struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc) /* Ok no matching timings, maybe there's a free one? */ for (i = 0; i < dev_priv->num_shared_dpll; i++) { pll = &dev_priv->shared_dplls[i]; - if (pll->crtc_mask == 0) { + if (pll->config.crtc_mask == 0) { DRM_DEBUG_KMS("CRTC:%d allocated %s\n", crtc->base.base.id, pll->name); goto found; @@ -3916,14 +3917,14 @@ struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc) return NULL; found: - if (pll->crtc_mask == 0) - pll->hw_state = crtc->config.dpll_hw_state; + if (pll->config.crtc_mask == 0) + pll->config.hw_state = crtc->config.dpll_hw_state; crtc->config.shared_dpll = i; DRM_DEBUG_DRIVER("using %s for pipe %c\n", pll->name, pipe_name(crtc->pipe)); - pll->crtc_mask |= 1 << crtc->pipe; + pll->config.crtc_mask |= 1 << crtc->pipe; return pll; } @@ -10606,9 +10607,9 @@ check_shared_dpll_state(struct drm_device *dev) active = pll->get_hw_state(dev_priv, pll, &dpll_hw_state); - WARN(pll->active > hweight32(pll->crtc_mask), + WARN(pll->active > hweight32(pll->config.crtc_mask), "more active pll users than references: %i vs %i\n", - pll->active, hweight32(pll->crtc_mask)); + pll->active, hweight32(pll->config.crtc_mask)); WARN(pll->active && !pll->on, "pll in active use but not on in sw tracking\n"); WARN(pll->on && !pll->active, @@ -10626,11 +10627,11 @@ check_shared_dpll_state(struct drm_device *dev) WARN(pll->active != active_crtcs, "pll active crtcs mismatch (expected %i, found %i)\n", pll->active, active_crtcs); - WARN(hweight32(pll->crtc_mask) != enabled_crtcs, + WARN(hweight32(pll->config.crtc_mask) != enabled_crtcs, "pll enabled crtcs mismatch (expected %i, found %i)\n", - hweight32(pll->crtc_mask), enabled_crtcs); + hweight32(pll->config.crtc_mask), enabled_crtcs); - WARN(pll->on && memcmp(&pll->hw_state, &dpll_hw_state, + WARN(pll->on && memcmp(&pll->config.hw_state, &dpll_hw_state, sizeof(dpll_hw_state)), "pll hw state mismatch\n"); } @@ -11305,8 +11306,8 @@ static bool ibx_pch_dpll_get_hw_state(struct drm_i915_private *dev_priv, static void ibx_pch_dpll_mode_set(struct drm_i915_private *dev_priv, struct intel_shared_dpll *pll) { - I915_WRITE(PCH_FP0(pll->id), pll->hw_state.fp0); - I915_WRITE(PCH_FP1(pll->id), pll->hw_state.fp1); + I915_WRITE(PCH_FP0(pll->id), pll->config.hw_state.fp0); + I915_WRITE(PCH_FP1(pll->id), pll->config.hw_state.fp1); } static void ibx_pch_dpll_enable(struct drm_i915_private *dev_priv, @@ -11315,7 +11316,7 @@ static void ibx_pch_dpll_enable(struct drm_i915_private *dev_priv, /* PCH refclock must be enabled first */ ibx_assert_pch_refclk_enabled(dev_priv); - I915_WRITE(PCH_DPLL(pll->id), pll->hw_state.dpll); + I915_WRITE(PCH_DPLL(pll->id), pll->config.hw_state.dpll); /* Wait for the clocks to stabilize. */ POSTING_READ(PCH_DPLL(pll->id)); @@ -11326,7 +11327,7 @@ static void ibx_pch_dpll_enable(struct drm_i915_private *dev_priv, * * So write it again. */ - I915_WRITE(PCH_DPLL(pll->id), pll->hw_state.dpll); + I915_WRITE(PCH_DPLL(pll->id), pll->config.hw_state.dpll); POSTING_READ(PCH_DPLL(pll->id)); udelay(200); } @@ -13077,20 +13078,21 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev) for (i = 0; i < dev_priv->num_shared_dpll; i++) { struct intel_shared_dpll *pll = &dev_priv->shared_dplls[i]; - pll->on = pll->get_hw_state(dev_priv, pll, &pll->hw_state); + pll->on = pll->get_hw_state(dev_priv, pll, + &pll->config.hw_state); pll->active = 0; - pll->crtc_mask = 0; + pll->config.crtc_mask = 0; for_each_intel_crtc(dev, crtc) { if (crtc->active && intel_crtc_to_shared_dpll(crtc) == pll) { pll->active++; - pll->crtc_mask |= 1 << crtc->pipe; + pll->config.crtc_mask |= 1 << crtc->pipe; } } DRM_DEBUG_KMS("%s hw state readout: crtc_mask 0x%08x, on %i\n", - pll->name, pll->crtc_mask, pll->on); + pll->name, pll->config.crtc_mask, pll->on); - if (pll->crtc_mask) + if (pll->config.crtc_mask) intel_display_power_get(dev_priv, POWER_DOMAIN_PLLS); } -- cgit v1.2.3 From 8bd31e67c9f737216cb25bcc008fed172b8a4375 Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Wed, 29 Oct 2014 11:32:33 +0200 Subject: drm/i915: Add infrastructure for choosing DPLLs before disabling crtcs It is possible for a mode set to fail if there aren't shared DPLLS that match the new configuration requirement or other errors in clock computation. If that step is executed after disabling crtcs, in the failure case the hardware configuration is changed and needs to be restored. Doing those things early will allow the mode set to fail before actually touching the hardware. Follow up patches will convert different platforms to use the new infrastructure. v2: Keep pll->new_config valid only during mode set (Ville) Use kmemdup() in i915_shared_dpll_start_config() (Ville) Restore old pll config if something fails before commit (Ville) Don't set compute_clock hooks since dev_priv is kzalloc()'d (Ville) Signed-off-by: Ander Conselvan de Oliveira Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 3 + drivers/gpu/drm/i915/intel_display.c | 142 ++++++++++++++++++++++++++++------- 2 files changed, 117 insertions(+), 28 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 62a8e058d7db..4fb93e28b5ac 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -236,6 +236,8 @@ struct intel_shared_dpll_config { struct intel_shared_dpll { struct intel_shared_dpll_config config; + struct intel_shared_dpll_config *new_config; + int active; /* count of number of active CRTCs (i.e. DPMS on) */ bool on; /* is the PLL actually active? Disabled during modeset */ const char *name; @@ -484,6 +486,7 @@ struct drm_i915_display_funcs { struct intel_crtc_config *); void (*get_plane_config)(struct intel_crtc *, struct intel_plane_config *); + int (*crtc_compute_clock)(struct intel_crtc *crtc); int (*crtc_mode_set)(struct intel_crtc *crtc, int x, int y, struct drm_framebuffer *old_fb); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 5eb475409657..4253f1288e73 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3863,15 +3863,9 @@ void intel_put_shared_dpll(struct intel_crtc *crtc) struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc) { struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; - struct intel_shared_dpll *pll = intel_crtc_to_shared_dpll(crtc); + struct intel_shared_dpll *pll; enum intel_dpll_id i; - if (pll) { - DRM_DEBUG_KMS("CRTC:%d dropping existing %s\n", - crtc->base.base.id, pll->name); - intel_put_shared_dpll(crtc); - } - if (HAS_PCH_IBX(dev_priv->dev)) { /* Ironlake PCH has a fixed PLL->PCH pipe mapping. */ i = (enum intel_dpll_id) crtc->pipe; @@ -3880,7 +3874,7 @@ struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc) DRM_DEBUG_KMS("CRTC:%d using pre-allocated %s\n", crtc->base.base.id, pll->name); - WARN_ON(pll->config.crtc_mask); + WARN_ON(pll->new_config->crtc_mask); goto found; } @@ -3889,17 +3883,16 @@ struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc) pll = &dev_priv->shared_dplls[i]; /* Only want to check enabled timings first */ - if (pll->config.crtc_mask == 0) + if (pll->new_config->crtc_mask == 0) continue; - if (memcmp(&crtc->config.dpll_hw_state, - &pll->config.hw_state, - sizeof(pll->config.hw_state)) == 0) { - DRM_DEBUG_KMS("CRTC:%d sharing existing %s " - "(crtc_mask 0x%08x, active %d)\n", + if (memcmp(&crtc->new_config->dpll_hw_state, + &pll->new_config->hw_state, + sizeof(pll->new_config->hw_state)) == 0) { + DRM_DEBUG_KMS("CRTC:%d sharing existing %s (crtc mask 0x%08x, ative %d)\n", crtc->base.base.id, pll->name, - pll->config.crtc_mask, pll->active); - + pll->new_config->crtc_mask, + pll->active); goto found; } } @@ -3907,7 +3900,7 @@ struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc) /* Ok no matching timings, maybe there's a free one? */ for (i = 0; i < dev_priv->num_shared_dpll; i++) { pll = &dev_priv->shared_dplls[i]; - if (pll->config.crtc_mask == 0) { + if (pll->new_config->crtc_mask == 0) { DRM_DEBUG_KMS("CRTC:%d allocated %s\n", crtc->base.base.id, pll->name); goto found; @@ -3917,18 +3910,85 @@ struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc) return NULL; found: - if (pll->config.crtc_mask == 0) - pll->config.hw_state = crtc->config.dpll_hw_state; + if (pll->new_config->crtc_mask == 0) + pll->new_config->hw_state = crtc->new_config->dpll_hw_state; - crtc->config.shared_dpll = i; + crtc->new_config->shared_dpll = i; DRM_DEBUG_DRIVER("using %s for pipe %c\n", pll->name, pipe_name(crtc->pipe)); - pll->config.crtc_mask |= 1 << crtc->pipe; + pll->new_config->crtc_mask |= 1 << crtc->pipe; return pll; } +/** + * intel_shared_dpll_start_config - start a new PLL staged config + * @dev_priv: DRM device + * @clear_pipes: mask of pipes that will have their PLLs freed + * + * Starts a new PLL staged config, copying the current config but + * releasing the references of pipes specified in clear_pipes. + */ +static int intel_shared_dpll_start_config(struct drm_i915_private *dev_priv, + unsigned clear_pipes) +{ + struct intel_shared_dpll *pll; + enum intel_dpll_id i; + + for (i = 0; i < dev_priv->num_shared_dpll; i++) { + pll = &dev_priv->shared_dplls[i]; + + pll->new_config = kmemdup(&pll->config, sizeof pll->config, + GFP_KERNEL); + if (!pll->new_config) + goto cleanup; + + pll->new_config->crtc_mask &= ~clear_pipes; + } + + return 0; + +cleanup: + while (--i >= 0) { + pll = &dev_priv->shared_dplls[i]; + pll->new_config = NULL; + } + + return -ENOMEM; +} + +static void intel_shared_dpll_commit(struct drm_i915_private *dev_priv) +{ + struct intel_shared_dpll *pll; + enum intel_dpll_id i; + + for (i = 0; i < dev_priv->num_shared_dpll; i++) { + pll = &dev_priv->shared_dplls[i]; + + WARN_ON(pll->new_config == &pll->config); + + pll->config = *pll->new_config; + kfree(pll->new_config); + pll->new_config = NULL; + } +} + +static void intel_shared_dpll_abort_config(struct drm_i915_private *dev_priv) +{ + struct intel_shared_dpll *pll; + enum intel_dpll_id i; + + for (i = 0; i < dev_priv->num_shared_dpll; i++) { + pll = &dev_priv->shared_dplls[i]; + + WARN_ON(pll->new_config == &pll->config); + + kfree(pll->new_config); + pll->new_config = NULL; + } +} + static void cpt_verify_modeset(struct drm_device *dev, int pipe) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -5420,11 +5480,11 @@ static int intel_crtc_compute_config(struct intel_crtc *crtc, struct intel_crtc_config *pipe_config) { struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; /* FIXME should check pixel clock limits on all platforms */ if (INTEL_INFO(dev)->gen < 4) { - struct drm_i915_private *dev_priv = dev->dev_private; int clock_limit = dev_priv->display.get_display_clock_speed(dev); @@ -5474,10 +5534,11 @@ static int intel_crtc_compute_config(struct intel_crtc *crtc, hsw_compute_ips_config(crtc, pipe_config); /* - * XXX: PCH/WRPLL clock sharing is done in ->mode_set, so make sure the - * old clock survives for now. + * XXX: PCH/WRPLL clock sharing is done in ->mode_set if ->compute_clock is not + * set, so make sure the old clock survives for now. */ - if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev) || HAS_DDI(dev)) + if (dev_priv->display.crtc_compute_clock == NULL && + (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev) || HAS_DDI(dev))) pipe_config->shared_dpll = crtc->config.shared_dpll; if (pipe_config->has_pch_encoder) @@ -7405,6 +7466,9 @@ static int ironlake_crtc_mode_set(struct intel_crtc *crtc, else crtc->new_config->dpll_hw_state.fp1 = fp; + if (intel_crtc_to_shared_dpll(crtc)) + intel_put_shared_dpll(crtc); + pll = intel_get_shared_dpll(crtc); if (pll == NULL) { DRM_DEBUG_DRIVER("failed to find PLL for pipe %c\n", @@ -10749,6 +10813,22 @@ static int __intel_set_mode(struct drm_crtc *crtc, prepare_pipes &= ~disable_pipes; } + if (dev_priv->display.crtc_compute_clock) { + unsigned clear_pipes = modeset_pipes | disable_pipes; + + ret = intel_shared_dpll_start_config(dev_priv, clear_pipes); + if (ret) + goto done; + + for_each_intel_crtc_masked(dev, modeset_pipes, intel_crtc) { + ret = dev_priv->display.crtc_compute_clock(intel_crtc); + if (ret) { + intel_shared_dpll_abort_config(dev_priv); + goto done; + } + } + } + for_each_intel_crtc_masked(dev, disable_pipes, intel_crtc) intel_crtc_disable(&intel_crtc->base); @@ -10776,6 +10856,9 @@ static int __intel_set_mode(struct drm_crtc *crtc, &pipe_config->adjusted_mode); } + if (dev_priv->display.crtc_compute_clock) + intel_shared_dpll_commit(dev_priv); + /* Only after disabling all output pipelines that will be changed can we * update the the output configuration. */ intel_modeset_update_state(dev, prepare_pipes); @@ -10810,9 +10893,12 @@ static int __intel_set_mode(struct drm_crtc *crtc, crtc->x = x; crtc->y = y; - ret = dev_priv->display.crtc_mode_set(intel_crtc, x, y, fb); - if (ret) - goto done; + if (dev_priv->display.crtc_mode_set) { + ret = dev_priv->display.crtc_mode_set(intel_crtc, + x, y, fb); + if (ret) + goto done; + } } /* Now enable the clocks, plane, pipe, and connectors that we set up. */ -- cgit v1.2.3 From 797d02592304b15359f407bd0e52fa5143cb4c9f Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Wed, 29 Oct 2014 11:32:34 +0200 Subject: drm/i915: Covert HSW+ to choose DPLLS before disabling CRTCs Use the infrastructure added in a previous patch to choose shared DPLLs and calculate clocks before touching the hardware. v2: Don't set mode_set hooks since dev_priv is kzalloc()'d (Ville) Signed-off-by: Ander Conselvan de Oliveira Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 2 -- drivers/gpu/drm/i915/intel_display.c | 7 +++---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 6f9712bba210..a50df351d558 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -842,8 +842,6 @@ bool intel_ddi_pll_select(struct intel_crtc *intel_crtc) intel_ddi_get_crtc_new_encoder(intel_crtc); int clock = intel_crtc->new_config->port_clock; - intel_put_shared_dpll(intel_crtc); - return hsw_ddi_pll_select(intel_crtc, intel_encoder, clock); } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 4253f1288e73..e4bff0b8740f 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -7975,9 +7975,7 @@ static void haswell_modeset_global_resources(struct drm_device *dev) modeset_update_crtc_power_domains(dev); } -static int haswell_crtc_mode_set(struct intel_crtc *crtc, - int x, int y, - struct drm_framebuffer *fb) +static int haswell_crtc_compute_clock(struct intel_crtc *crtc) { if (!intel_ddi_pll_select(crtc)) return -EINVAL; @@ -12468,7 +12466,8 @@ static void intel_init_display(struct drm_device *dev) if (HAS_DDI(dev)) { dev_priv->display.get_pipe_config = haswell_get_pipe_config; dev_priv->display.get_plane_config = ironlake_get_plane_config; - dev_priv->display.crtc_mode_set = haswell_crtc_mode_set; + dev_priv->display.crtc_compute_clock = + haswell_crtc_compute_clock; dev_priv->display.crtc_enable = haswell_crtc_enable; dev_priv->display.crtc_disable = haswell_crtc_disable; dev_priv->display.off = ironlake_crtc_off; -- cgit v1.2.3 From 3fb37703683543725dec3d8bc5c5b3a930325d04 Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Wed, 29 Oct 2014 11:32:35 +0200 Subject: drm/i915: Covert ILK-IVB to choose DPLLS before disabling CRTCs Use the infrastructure added in a previous patch to choose shared DPLLs and calculate clocks before touching the hardware. v2: Don't set mode_set hooks since dev_priv is kzalloc()'d (Ville) Signed-off-by: Ander Conselvan de Oliveira Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index e4bff0b8740f..ee5eba78334d 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -7418,9 +7418,7 @@ static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc, return dpll | DPLL_VCO_ENABLE; } -static int ironlake_crtc_mode_set(struct intel_crtc *crtc, - int x, int y, - struct drm_framebuffer *fb) +static int ironlake_crtc_compute_clock(struct intel_crtc *crtc) { struct drm_device *dev = crtc->base.dev; intel_clock_t clock, reduced_clock; @@ -7466,17 +7464,13 @@ static int ironlake_crtc_mode_set(struct intel_crtc *crtc, else crtc->new_config->dpll_hw_state.fp1 = fp; - if (intel_crtc_to_shared_dpll(crtc)) - intel_put_shared_dpll(crtc); - pll = intel_get_shared_dpll(crtc); if (pll == NULL) { DRM_DEBUG_DRIVER("failed to find PLL for pipe %c\n", pipe_name(crtc->pipe)); return -EINVAL; } - } else - intel_put_shared_dpll(crtc); + } if (is_lvds && has_reduced_clock && i915.powersave) crtc->lowfreq_avail = true; @@ -12480,7 +12474,8 @@ static void intel_init_display(struct drm_device *dev) } else if (HAS_PCH_SPLIT(dev)) { dev_priv->display.get_pipe_config = ironlake_get_pipe_config; dev_priv->display.get_plane_config = ironlake_get_plane_config; - dev_priv->display.crtc_mode_set = ironlake_crtc_mode_set; + dev_priv->display.crtc_compute_clock = + ironlake_crtc_compute_clock; dev_priv->display.crtc_enable = ironlake_crtc_enable; dev_priv->display.crtc_disable = ironlake_crtc_disable; dev_priv->display.off = ironlake_crtc_off; -- cgit v1.2.3 From d6dfee7a038ed1d160a557de50926b04dbcfbb6a Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Wed, 29 Oct 2014 11:32:36 +0200 Subject: drm/i915: Covert remaining platforms to choose DPLLS before disabling CRTCs Use the infrastructure added in a previous patch to choose shared DPLLs and calculate clocks before touching the hardware. v2: Don't set mode_set hooks since dev_priv is kzalloc()'d (Ville) Signed-off-by: Ander Conselvan de Oliveira Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index ee5eba78334d..5af00c489980 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6395,9 +6395,7 @@ static void i9xx_set_pipeconf(struct intel_crtc *intel_crtc) POSTING_READ(PIPECONF(intel_crtc->pipe)); } -static int i9xx_crtc_mode_set(struct intel_crtc *crtc, - int x, int y, - struct drm_framebuffer *fb) +static int i9xx_crtc_compute_clock(struct intel_crtc *crtc) { struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -12484,7 +12482,7 @@ static void intel_init_display(struct drm_device *dev) } else if (IS_VALLEYVIEW(dev)) { dev_priv->display.get_pipe_config = i9xx_get_pipe_config; dev_priv->display.get_plane_config = i9xx_get_plane_config; - dev_priv->display.crtc_mode_set = i9xx_crtc_mode_set; + dev_priv->display.crtc_compute_clock = i9xx_crtc_compute_clock; dev_priv->display.crtc_enable = valleyview_crtc_enable; dev_priv->display.crtc_disable = i9xx_crtc_disable; dev_priv->display.off = i9xx_crtc_off; @@ -12493,7 +12491,7 @@ static void intel_init_display(struct drm_device *dev) } else { dev_priv->display.get_pipe_config = i9xx_get_pipe_config; dev_priv->display.get_plane_config = i9xx_get_plane_config; - dev_priv->display.crtc_mode_set = i9xx_crtc_mode_set; + dev_priv->display.crtc_compute_clock = i9xx_crtc_compute_clock; dev_priv->display.crtc_enable = i9xx_crtc_enable; dev_priv->display.crtc_disable = i9xx_crtc_disable; dev_priv->display.off = i9xx_crtc_off; -- cgit v1.2.3 From f3019a4d92f08b2dd92443a4b567a066a51c6ec0 Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Wed, 29 Oct 2014 11:32:37 +0200 Subject: drm/i915: Remove crtc_mode_set() hook There's no users left after the conversion to calculate clocks before disabling crtcs during mode set. Signed-off-by: Ander Conselvan de Oliveira Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 3 --- drivers/gpu/drm/i915/intel_display.c | 7 ------- 2 files changed, 10 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 4fb93e28b5ac..03be342400bd 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -487,9 +487,6 @@ struct drm_i915_display_funcs { void (*get_plane_config)(struct intel_crtc *, struct intel_plane_config *); int (*crtc_compute_clock)(struct intel_crtc *crtc); - int (*crtc_mode_set)(struct intel_crtc *crtc, - int x, int y, - struct drm_framebuffer *old_fb); void (*crtc_enable)(struct drm_crtc *crtc); void (*crtc_disable)(struct drm_crtc *crtc); void (*off)(struct drm_crtc *crtc); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 5af00c489980..200fcb163a2d 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -10882,13 +10882,6 @@ static int __intel_set_mode(struct drm_crtc *crtc, crtc->primary->fb = fb; crtc->x = x; crtc->y = y; - - if (dev_priv->display.crtc_mode_set) { - ret = dev_priv->display.crtc_mode_set(intel_crtc, - x, y, fb); - if (ret) - goto done; - } } /* Now enable the clocks, plane, pipe, and connectors that we set up. */ -- cgit v1.2.3 From e9f1af393477bd4a60e23531b579b325cf1918da Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Wed, 29 Oct 2014 11:32:38 +0200 Subject: drm/i915: Don't store current shared DPLL in the new pipe_config Now that shared DPLLs configuration is staged, there's no need to track the current ones in the new pipe_config since those are released before making the new pipe_config effective. Signed-off-by: Ander Conselvan de Oliveira Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 200fcb163a2d..be596178dca4 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5533,14 +5533,6 @@ static int intel_crtc_compute_config(struct intel_crtc *crtc, if (HAS_IPS(dev)) hsw_compute_ips_config(crtc, pipe_config); - /* - * XXX: PCH/WRPLL clock sharing is done in ->mode_set if ->compute_clock is not - * set, so make sure the old clock survives for now. - */ - if (dev_priv->display.crtc_compute_clock == NULL && - (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev) || HAS_DDI(dev))) - pipe_config->shared_dpll = crtc->config.shared_dpll; - if (pipe_config->has_pch_encoder) return ironlake_fdi_compute_config(crtc, pipe_config); -- cgit v1.2.3 From ba41c0dec7786ca2d5f630d0f364c5f5331b34c1 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 3 Nov 2014 15:04:55 +0100 Subject: drm/i915: Move pll state commit into intel_modeset_update_state It's really part of the "push all new_* state into current state pointers" done in that function. So let's move it there to make this clear. Also, with the conversion done the num_shared_dpll check the function does in it's loop is enough, so we can drop the check for the dpll compute callback, too. Cc: Ander Conselvan de Oliveira Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index be596178dca4..a05a8573f1a3 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -10231,10 +10231,13 @@ static bool intel_crtc_in_use(struct drm_crtc *crtc) static void intel_modeset_update_state(struct drm_device *dev, unsigned prepare_pipes) { + struct drm_i915_private *dev_priv = dev->dev_private; struct intel_encoder *intel_encoder; struct intel_crtc *intel_crtc; struct drm_connector *connector; + intel_shared_dpll_commit(dev_priv); + for_each_intel_encoder(dev, intel_encoder) { if (!intel_encoder->base.crtc) continue; @@ -10838,9 +10841,6 @@ static int __intel_set_mode(struct drm_crtc *crtc, &pipe_config->adjusted_mode); } - if (dev_priv->display.crtc_compute_clock) - intel_shared_dpll_commit(dev_priv); - /* Only after disabling all output pipelines that will be changed can we * update the the output configuration. */ intel_modeset_update_state(dev, prepare_pipes); -- cgit v1.2.3 From 4093561b70adccec7d3c8fbb19a80d636fe0f562 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Wed, 29 Oct 2014 11:16:59 +0000 Subject: drm/i915: Make intel_pipe_has_type() take an output type enum As Paulo said when introducing the enum, having more types is really good to document what should go where (int foo(int, int, bool, bool). Cc: Paulo Zanoni Signed-off-by: Damien Lespiau Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 2 +- drivers/gpu/drm/i915/intel_drv.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index a05a8573f1a3..d7951426f347 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -408,7 +408,7 @@ static void vlv_clock(int refclk, intel_clock_t *clock) /** * Returns whether any output on the specified pipe is of the specified type */ -bool intel_pipe_has_type(struct intel_crtc *crtc, int type) +bool intel_pipe_has_type(struct intel_crtc *crtc, enum intel_output_type type) { struct drm_device *dev = crtc->base.dev; struct intel_encoder *encoder; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 82d89167cd2f..7fab2d808a40 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -881,7 +881,7 @@ int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data, struct drm_file *file_priv); enum transcoder intel_pipe_to_cpu_transcoder(struct drm_i915_private *dev_priv, enum pipe pipe); -bool intel_pipe_has_type(struct intel_crtc *crtc, int type); +bool intel_pipe_has_type(struct intel_crtc *crtc, enum intel_output_type type); static inline void intel_wait_for_vblank(struct drm_device *dev, int pipe) { -- cgit v1.2.3 From 7637b6bd4e20b877f77a4e0bd1ac48b1b1b064e1 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Wed, 29 Oct 2014 12:03:45 +0000 Subject: drm/i915: Remove unused WATCH_GTT define Chris removed the code using it in: commit be2d599b5da3936ca92e0187ff50b34b6b8ff997 Author: Chris Wilson Date: Wed Sep 10 19:52:18 2014 +0100 drm/i915: Remove dead code, i915_gem_verify_gtt Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 03be342400bd..f4c2db458ddc 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -284,7 +284,6 @@ void intel_link_compute_m_n(int bpp, int nlanes, #define DRIVER_PATCHLEVEL 0 #define WATCH_LISTS 0 -#define WATCH_GTT 0 struct opregion_header; struct opregion_acpi; -- cgit v1.2.3 From d6faadb7a2e9b56cf83e45205a97dde17aab71af Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 3 Nov 2014 11:39:24 +0100 Subject: drm/i915/dp: Don't stop the link when retraining On pre-ddi platforms we don't shut down the link when changing link training parameters. Except when clock recovery fails too hard and we restart with channel eq training. Which doesn't make a lot of sense really, since just stopping/restarting the DP port at this point violates the modeset sequence documented in the Bspec. So let's tempt fate and try this. This patch is motivated by a WARN_ON triggered by commit bc76e320f21f8bd790a72bd5dc06909617432352 Author: Daniel Vetter Date: Tue May 20 22:46:50 2014 +0200 drm/i915: Drop now misleading DDI comment from dp_link_down References: https://bugs.freedesktop.org/show_bug.cgi?id=85670 Signed-off-by: Daniel Vetter Acked-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index ec80e828240e..5f2c206aef13 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -3812,7 +3812,6 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp) /* Try 5 times, then try clock recovery if that fails */ if (tries > 5) { - intel_dp_link_down(intel_dp); intel_dp_start_link_train(intel_dp); intel_dp_set_link_train(intel_dp, &DP, training_pattern | -- cgit v1.2.3 From 816a360489b08ccba323fa0d02fc03f85bd70321 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Sat, 1 Nov 2014 05:05:56 +0000 Subject: drm/i915: Removed orphaned prototype intel_dp_handle_hpd_irq() The function was removed in: commit 0e32b39ceed665bfa4a77a4bc307b6652b991632 Author: Dave Airlie Date: Fri May 2 14:02:48 2014 +1000 drm/i915: add DP 1.2 MST support (v0.7) Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_drv.h | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 7fab2d808a40..dc53cfe949af 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -992,7 +992,6 @@ void intel_edp_psr_flush(struct drm_device *dev, unsigned frontbuffer_bits); void intel_edp_psr_init(struct drm_device *dev); -int intel_dp_handle_hpd_irq(struct intel_digital_port *digport, bool long_hpd); void intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connector); void intel_dp_mst_suspend(struct drm_device *dev); void intel_dp_mst_resume(struct drm_device *dev); -- cgit v1.2.3 From 7f518dd09e246e96603533167d13b2ede27c20f7 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Sat, 1 Nov 2014 05:05:57 +0000 Subject: drm/i915: Remove orphaned prototype gen6_set_pm_mask() The function was removed in: commit 037bde19a43e299d30f0490bba9be32ab355975c Author: Chris Wilson Date: Thu Mar 27 08:24:19 2014 +0000 Revert "drm/i915: Disable/Enable PM Intrrupts based on the current freq." Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index f4c2db458ddc..54691bcf1822 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2298,8 +2298,6 @@ __printf(3, 4) void i915_handle_error(struct drm_device *dev, bool wedged, const char *fmt, ...); -void gen6_set_pm_mask(struct drm_i915_private *dev_priv, u32 pm_iir, - int new_delay); extern void intel_irq_init(struct drm_i915_private *dev_priv); extern void intel_hpd_init(struct drm_i915_private *dev_priv); int intel_irq_install(struct drm_i915_private *dev_priv); -- cgit v1.2.3 From 1df06b75f0235c6c4f836e5c03fb499ba70a54bd Mon Sep 17 00:00:00 2001 From: Thomas Daniel Date: Wed, 29 Oct 2014 09:52:51 +0000 Subject: drm/i915/bdw: Setup global hardware status page in execlists mode Write HWS_PGA address even in execlists mode as the global hardware status page is still required. This address was previously uninitialized and HWSP writes would clobber whatever buffer happened to reside at GGTT address 0. v2: Break out hardware status page setup into a separate function. Issue: VIZ-2020 Signed-off-by: Thomas Daniel Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 70a6c63f3b9a..292beb0fa1dc 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1649,6 +1649,27 @@ static uint32_t get_lr_context_size(struct intel_engine_cs *ring) return ret; } +static int lrc_setup_hardware_status_page(struct intel_engine_cs *ring, + struct drm_i915_gem_object *default_ctx_obj) +{ + struct drm_i915_private *dev_priv = ring->dev->dev_private; + + /* The status page is offset 0 from the default context object + * in LRC mode. */ + ring->status_page.gfx_addr = i915_gem_obj_ggtt_offset(default_ctx_obj); + ring->status_page.page_addr = + kmap(sg_page(default_ctx_obj->pages->sgl)); + if (ring->status_page.page_addr == NULL) + return -ENOMEM; + ring->status_page.obj = default_ctx_obj; + + I915_WRITE(RING_HWS_PGA(ring->mmio_base), + (u32)ring->status_page.gfx_addr); + POSTING_READ(RING_HWS_PGA(ring->mmio_base)); + + return 0; +} + /** * intel_lr_context_deferred_create() - create the LRC specific bits of a context * @ctx: LR context to create. @@ -1734,14 +1755,11 @@ int intel_lr_context_deferred_create(struct intel_context *ctx, ctx->engine[ring->id].state = ctx_obj; if (ctx == ring->default_context) { - /* The status page is offset 0 from the default context object - * in LRC mode. */ - ring->status_page.gfx_addr = i915_gem_obj_ggtt_offset(ctx_obj); - ring->status_page.page_addr = - kmap(sg_page(ctx_obj->pages->sgl)); - if (ring->status_page.page_addr == NULL) - return -ENOMEM; - ring->status_page.obj = ctx_obj; + ret = lrc_setup_hardware_status_page(ring, ctx_obj); + if (ret) { + DRM_ERROR("Failed to setup hardware status page\n"); + goto error; + } } if (ring->id == RCS && !ctx->rcs_initialized) { -- cgit v1.2.3 From 850c4cdc6c223d02748f20c8ee1b677fb42da1aa Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Thu, 30 Oct 2014 16:39:38 +0000 Subject: drm/i915: Make intel_pin_and_fence_fb_obj take plane and framebuffer It will help future code if this function knows something about of the context of the display setup object is being pinned for. Signed-off-by: Tvrtko Ursulin Cc: Daniel Vetter Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 23 ++++++++++++----------- drivers/gpu/drm/i915/intel_drv.h | 4 ++-- drivers/gpu/drm/i915/intel_fbdev.c | 20 ++++++++++---------- drivers/gpu/drm/i915/intel_sprite.c | 2 +- 4 files changed, 25 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index d7951426f347..44060fb020a8 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2194,11 +2194,13 @@ static int intel_align_height(struct drm_device *dev, int height, bool tiled) } int -intel_pin_and_fence_fb_obj(struct drm_device *dev, - struct drm_i915_gem_object *obj, +intel_pin_and_fence_fb_obj(struct drm_plane *plane, + struct drm_framebuffer *fb, struct intel_engine_cs *pipelined) { + struct drm_device *dev = fb->dev; struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_gem_object *obj = intel_fb_obj(fb); u32 alignment; int ret; @@ -2897,7 +2899,6 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, struct intel_crtc *intel_crtc = to_intel_crtc(crtc); enum pipe pipe = intel_crtc->pipe; struct drm_framebuffer *old_fb = crtc->primary->fb; - struct drm_i915_gem_object *obj = intel_fb_obj(fb); struct drm_i915_gem_object *old_obj = intel_fb_obj(old_fb); int ret; @@ -2920,9 +2921,9 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, } mutex_lock(&dev->struct_mutex); - ret = intel_pin_and_fence_fb_obj(dev, obj, NULL); + ret = intel_pin_and_fence_fb_obj(crtc->primary, fb, NULL); if (ret == 0) - i915_gem_track_fb(old_obj, obj, + i915_gem_track_fb(old_obj, intel_fb_obj(fb), INTEL_FRONTBUFFER_PRIMARY(pipe)); mutex_unlock(&dev->struct_mutex); if (ret != 0) { @@ -9689,7 +9690,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, ring = &dev_priv->ring[RCS]; } - ret = intel_pin_and_fence_fb_obj(dev, obj, ring); + ret = intel_pin_and_fence_fb_obj(crtc->primary, fb, ring); if (ret) goto cleanup_pending; @@ -10857,9 +10858,7 @@ static int __intel_set_mode(struct drm_crtc *crtc, struct drm_i915_gem_object *obj = intel_fb_obj(fb); mutex_lock(&dev->struct_mutex); - ret = intel_pin_and_fence_fb_obj(dev, - obj, - NULL); + ret = intel_pin_and_fence_fb_obj(crtc->primary, fb, NULL); if (ret != 0) { DRM_ERROR("pin & fence failed\n"); mutex_unlock(&dev->struct_mutex); @@ -11525,7 +11524,7 @@ intel_prepare_primary_plane(struct drm_plane *plane, if (old_obj != obj) { mutex_lock(&dev->struct_mutex); - ret = intel_pin_and_fence_fb_obj(dev, obj, NULL); + ret = intel_pin_and_fence_fb_obj(plane, fb, NULL); if (ret == 0) i915_gem_track_fb(old_obj, obj, INTEL_FRONTBUFFER_PRIMARY(pipe)); @@ -13293,7 +13292,9 @@ void intel_modeset_gem_init(struct drm_device *dev) if (obj == NULL) continue; - if (intel_pin_and_fence_fb_obj(dev, obj, NULL)) { + if (intel_pin_and_fence_fb_obj(c->primary, + c->primary->fb, + NULL)) { DRM_ERROR("failed to pin boot fb on pipe %d\n", to_intel_crtc(c)->pipe); drm_framebuffer_unreference(c->primary->fb); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index dc53cfe949af..ae75b9950f01 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -896,8 +896,8 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector, struct drm_modeset_acquire_ctx *ctx); void intel_release_load_detect_pipe(struct drm_connector *connector, struct intel_load_detect_pipe *old); -int intel_pin_and_fence_fb_obj(struct drm_device *dev, - struct drm_i915_gem_object *obj, +int intel_pin_and_fence_fb_obj(struct drm_plane *plane, + struct drm_framebuffer *fb, struct intel_engine_cs *pipelined); void intel_unpin_fb_obj(struct drm_i915_gem_object *obj); struct drm_framebuffer * diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c index 9b584f3fbb99..f2183b554cbc 100644 --- a/drivers/gpu/drm/i915/intel_fbdev.c +++ b/drivers/gpu/drm/i915/intel_fbdev.c @@ -119,25 +119,25 @@ static int intelfb_alloc(struct drm_fb_helper *helper, goto out; } - /* Flush everything out, we'll be doing GTT only from now on */ - ret = intel_pin_and_fence_fb_obj(dev, obj, NULL); - if (ret) { - DRM_ERROR("failed to pin obj: %d\n", ret); - goto out_unref; - } - fb = __intel_framebuffer_create(dev, &mode_cmd, obj); if (IS_ERR(fb)) { ret = PTR_ERR(fb); - goto out_unpin; + goto out_unref; + } + + /* Flush everything out, we'll be doing GTT only from now on */ + ret = intel_pin_and_fence_fb_obj(NULL, fb, NULL); + if (ret) { + DRM_ERROR("failed to pin obj: %d\n", ret); + goto out_fb; } ifbdev->fb = to_intel_framebuffer(fb); return 0; -out_unpin: - i915_gem_object_ggtt_unpin(obj); +out_fb: + drm_framebuffer_remove(fb); out_unref: drm_gem_object_unreference(&obj->base); out: diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index bf1eb158e624..8c70c54e048d 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -1256,7 +1256,7 @@ intel_prepare_sprite_plane(struct drm_plane *plane, * the sprite planes only require 128KiB alignment and 32 PTE * padding. */ - ret = intel_pin_and_fence_fb_obj(dev, obj, NULL); + ret = intel_pin_and_fence_fb_obj(plane, fb, NULL); if (ret == 0) i915_gem_track_fb(old_obj, obj, INTEL_FRONTBUFFER_SPRITE(pipe)); -- cgit v1.2.3 From 7d1bd53931e5afe5b2549c045ed4afad71ee6e8f Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Thu, 30 Oct 2014 19:42:50 +0200 Subject: drm/i915: Apply some ocd for IMR vs. IER order during irq enable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When disabling interrupts we do the writes in this order: IMR,IER,IIR,IIR. But when enabling interrupts we don't do use the mirrored order, and instead do IIR,IIR,IMR,IER. I like consistency unless there's a good reason against it, which I can't think of here, so change the enable order to IIR,IIR,IER,IMR. Signed-off-by: Ville Syrjälä Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index a2b013d97fb6..98a8d650768b 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -126,16 +126,16 @@ static const u32 hpd_status_i915[] = { /* i915 and valleyview are the same */ #define GEN8_IRQ_INIT_NDX(type, which, imr_val, ier_val) do { \ GEN5_ASSERT_IIR_IS_ZERO(GEN8_##type##_IIR(which)); \ - I915_WRITE(GEN8_##type##_IMR(which), (imr_val)); \ I915_WRITE(GEN8_##type##_IER(which), (ier_val)); \ - POSTING_READ(GEN8_##type##_IER(which)); \ + I915_WRITE(GEN8_##type##_IMR(which), (imr_val)); \ + POSTING_READ(GEN8_##type##_IMR(which)); \ } while (0) #define GEN5_IRQ_INIT(type, imr_val, ier_val) do { \ GEN5_ASSERT_IIR_IS_ZERO(type##IIR); \ - I915_WRITE(type##IMR, (imr_val)); \ I915_WRITE(type##IER, (ier_val)); \ - POSTING_READ(type##IER); \ + I915_WRITE(type##IMR, (imr_val)); \ + POSTING_READ(type##IMR); \ } while (0) /* For display hotplug interrupt */ -- cgit v1.2.3 From 7c4cde39684cffc6aaae4f34f2bcd987a86befe6 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Thu, 30 Oct 2014 19:42:51 +0200 Subject: drm/i915: Use DPINVGTT_STATUS_MASK MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some has given a name for the DPINVGTT status bitmask, so let's use it instead of the magic number. Looks more like the chv code now. Signed-off-by: Ville Syrjälä Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 98a8d650768b..e41272da67c9 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -3122,7 +3122,7 @@ static void valleyview_irq_preinstall(struct drm_device *dev) gen5_gt_irq_reset(dev); - I915_WRITE(DPINVGTT, 0xff); + I915_WRITE(DPINVGTT, DPINVGTT_STATUS_MASK); I915_WRITE(PORT_HOTPLUG_EN, 0); I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); -- cgit v1.2.3 From a2c30fbafceb937eb3c3535a21810d4458628e62 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Thu, 30 Oct 2014 19:42:52 +0200 Subject: drm/i915: Use gen8_gt_irq_reset() in cherryview_irq_uninstall() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the hand rolled macros with gen8_gt_irq_reset() and GEN5_IRQ_RESET() in cherryview_irq_uninstall(). Signed-off-by: Ville Syrjälä Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 28 ++-------------------------- 1 file changed, 2 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index e41272da67c9..1ec4ebbb89f3 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -3625,33 +3625,9 @@ static void cherryview_irq_uninstall(struct drm_device *dev) I915_WRITE(GEN8_MASTER_IRQ, 0); POSTING_READ(GEN8_MASTER_IRQ); -#define GEN8_IRQ_FINI_NDX(type, which) \ -do { \ - I915_WRITE(GEN8_##type##_IMR(which), 0xffffffff); \ - I915_WRITE(GEN8_##type##_IER(which), 0); \ - I915_WRITE(GEN8_##type##_IIR(which), 0xffffffff); \ - POSTING_READ(GEN8_##type##_IIR(which)); \ - I915_WRITE(GEN8_##type##_IIR(which), 0xffffffff); \ -} while (0) - -#define GEN8_IRQ_FINI(type) \ -do { \ - I915_WRITE(GEN8_##type##_IMR, 0xffffffff); \ - I915_WRITE(GEN8_##type##_IER, 0); \ - I915_WRITE(GEN8_##type##_IIR, 0xffffffff); \ - POSTING_READ(GEN8_##type##_IIR); \ - I915_WRITE(GEN8_##type##_IIR, 0xffffffff); \ -} while (0) - - GEN8_IRQ_FINI_NDX(GT, 0); - GEN8_IRQ_FINI_NDX(GT, 1); - GEN8_IRQ_FINI_NDX(GT, 2); - GEN8_IRQ_FINI_NDX(GT, 3); - - GEN8_IRQ_FINI(PCU); + gen8_gt_irq_reset(dev_priv); -#undef GEN8_IRQ_FINI -#undef GEN8_IRQ_FINI_NDX + GEN5_IRQ_RESET(GEN8_PCU_); I915_WRITE(PORT_HOTPLUG_EN, 0); I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); -- cgit v1.2.3 From 8e20599ae1327ef3f0cf6a080fc3a39c882f4718 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Thu, 30 Oct 2014 19:42:53 +0200 Subject: drm/i915: Drop the extra GEN8_PCU_IIR posting read from cherryview_irq_preinstall() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Looks like a leftover POSTING_READ(GEN8_PCU_IIR) in cherryview_irq_preinstall() from some earlier age. GEN5_IRQ_RESET() already does the posting read so this changes nothing, so kill it. Signed-off-by: Ville Syrjälä Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 1ec4ebbb89f3..1e4062d09616 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -3188,8 +3188,6 @@ static void cherryview_irq_preinstall(struct drm_device *dev) GEN5_IRQ_RESET(GEN8_PCU_); - POSTING_READ(GEN8_PCU_IIR); - I915_WRITE(DPINVGTT, DPINVGTT_STATUS_MASK_CHV); I915_WRITE(PORT_HOTPLUG_EN, 0); -- cgit v1.2.3 From 76e418605448597159c5decf4e060d41d3618831 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Thu, 30 Oct 2014 19:42:54 +0200 Subject: drm/i915: Use a consistent order between IIR, IER, IMR writes on vlv/chv MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Follow the same ordering rules for the IIR,IER,IMR writes on vlv/chv that we do on other gen5+ platforms. Signed-off-by: Ville Syrjälä Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 1e4062d09616..589ae51de8dd 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -3128,10 +3128,11 @@ static void valleyview_irq_preinstall(struct drm_device *dev) I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); for_each_pipe(dev_priv, pipe) I915_WRITE(PIPESTAT(pipe), 0xffff); - I915_WRITE(VLV_IIR, 0xffffffff); I915_WRITE(VLV_IMR, 0xffffffff); I915_WRITE(VLV_IER, 0x0); - POSTING_READ(VLV_IER); + I915_WRITE(VLV_IIR, 0xffffffff); + I915_WRITE(VLV_IIR, 0xffffffff); + POSTING_READ(VLV_IIR); } static void gen8_gt_irq_reset(struct drm_i915_private *dev_priv) @@ -3199,6 +3200,7 @@ static void cherryview_irq_preinstall(struct drm_device *dev) I915_WRITE(VLV_IMR, 0xffffffff); I915_WRITE(VLV_IER, 0x0); I915_WRITE(VLV_IIR, 0xffffffff); + I915_WRITE(VLV_IIR, 0xffffffff); POSTING_READ(VLV_IIR); } @@ -3362,9 +3364,9 @@ static void valleyview_display_irqs_install(struct drm_i915_private *dev_priv) I915_WRITE(VLV_IIR, iir_mask); I915_WRITE(VLV_IIR, iir_mask); - I915_WRITE(VLV_IMR, dev_priv->irq_mask); I915_WRITE(VLV_IER, ~dev_priv->irq_mask); - POSTING_READ(VLV_IER); + I915_WRITE(VLV_IMR, dev_priv->irq_mask); + POSTING_READ(VLV_IMR); } static void valleyview_display_irqs_uninstall(struct drm_i915_private *dev_priv) @@ -3377,8 +3379,8 @@ static void valleyview_display_irqs_uninstall(struct drm_i915_private *dev_priv) I915_DISPLAY_PIPE_B_EVENT_INTERRUPT; dev_priv->irq_mask |= iir_mask; - I915_WRITE(VLV_IER, ~dev_priv->irq_mask); I915_WRITE(VLV_IMR, dev_priv->irq_mask); + I915_WRITE(VLV_IER, ~dev_priv->irq_mask); I915_WRITE(VLV_IIR, iir_mask); I915_WRITE(VLV_IIR, iir_mask); POSTING_READ(VLV_IIR); @@ -3432,10 +3434,11 @@ static int valleyview_irq_postinstall(struct drm_device *dev) I915_WRITE(PORT_HOTPLUG_EN, 0); POSTING_READ(PORT_HOTPLUG_EN); - I915_WRITE(VLV_IMR, dev_priv->irq_mask); - I915_WRITE(VLV_IER, ~dev_priv->irq_mask); I915_WRITE(VLV_IIR, 0xffffffff); - POSTING_READ(VLV_IER); + I915_WRITE(VLV_IIR, 0xffffffff); + I915_WRITE(VLV_IER, ~dev_priv->irq_mask); + I915_WRITE(VLV_IMR, dev_priv->irq_mask); + POSTING_READ(VLV_IMR); /* Interrupt setup is already guaranteed to be single-threaded, this is * just to make the assert_spin_locked check happy. */ @@ -3559,8 +3562,10 @@ static int cherryview_irq_postinstall(struct drm_device *dev) spin_unlock_irq(&dev_priv->irq_lock); I915_WRITE(VLV_IIR, 0xffffffff); - I915_WRITE(VLV_IMR, dev_priv->irq_mask); + I915_WRITE(VLV_IIR, 0xffffffff); I915_WRITE(VLV_IER, enable_mask); + I915_WRITE(VLV_IMR, dev_priv->irq_mask); + POSTING_READ(VLV_IMR); gen8_gt_irq_postinstall(dev_priv); @@ -3606,10 +3611,11 @@ static void valleyview_irq_uninstall(struct drm_device *dev) dev_priv->irq_mask = 0; - I915_WRITE(VLV_IIR, 0xffffffff); I915_WRITE(VLV_IMR, 0xffffffff); I915_WRITE(VLV_IER, 0x0); - POSTING_READ(VLV_IER); + I915_WRITE(VLV_IIR, 0xffffffff); + I915_WRITE(VLV_IIR, 0xffffffff); + POSTING_READ(VLV_IIR); } static void cherryview_irq_uninstall(struct drm_device *dev) @@ -3636,6 +3642,7 @@ static void cherryview_irq_uninstall(struct drm_device *dev) I915_WRITE(VLV_IMR, 0xffffffff); I915_WRITE(VLV_IER, 0x0); I915_WRITE(VLV_IIR, 0xffffffff); + I915_WRITE(VLV_IIR, 0xffffffff); POSTING_READ(VLV_IIR); } -- cgit v1.2.3 From 23a09c76cc37c132844345cec94abc1edf570b53 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Thu, 30 Oct 2014 19:42:55 +0200 Subject: drm/i915: Use GEN5_IRQ_RESET() on vlv/chv MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the hand rolled IIR,IER,IMR disable sequences with GEN5_IRQ_RESET(). Signed-off-by: Ville Syrjälä Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 25 +++++-------------------- 1 file changed, 5 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 589ae51de8dd..c106bba3f97c 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -3128,11 +3128,8 @@ static void valleyview_irq_preinstall(struct drm_device *dev) I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); for_each_pipe(dev_priv, pipe) I915_WRITE(PIPESTAT(pipe), 0xffff); - I915_WRITE(VLV_IMR, 0xffffffff); - I915_WRITE(VLV_IER, 0x0); - I915_WRITE(VLV_IIR, 0xffffffff); - I915_WRITE(VLV_IIR, 0xffffffff); - POSTING_READ(VLV_IIR); + + GEN5_IRQ_RESET(VLV_); } static void gen8_gt_irq_reset(struct drm_i915_private *dev_priv) @@ -3197,11 +3194,7 @@ static void cherryview_irq_preinstall(struct drm_device *dev) for_each_pipe(dev_priv, pipe) I915_WRITE(PIPESTAT(pipe), 0xffff); - I915_WRITE(VLV_IMR, 0xffffffff); - I915_WRITE(VLV_IER, 0x0); - I915_WRITE(VLV_IIR, 0xffffffff); - I915_WRITE(VLV_IIR, 0xffffffff); - POSTING_READ(VLV_IIR); + GEN5_IRQ_RESET(VLV_); } static void ibx_hpd_irq_setup(struct drm_device *dev) @@ -3611,11 +3604,7 @@ static void valleyview_irq_uninstall(struct drm_device *dev) dev_priv->irq_mask = 0; - I915_WRITE(VLV_IMR, 0xffffffff); - I915_WRITE(VLV_IER, 0x0); - I915_WRITE(VLV_IIR, 0xffffffff); - I915_WRITE(VLV_IIR, 0xffffffff); - POSTING_READ(VLV_IIR); + GEN5_IRQ_RESET(VLV_); } static void cherryview_irq_uninstall(struct drm_device *dev) @@ -3639,11 +3628,7 @@ static void cherryview_irq_uninstall(struct drm_device *dev) for_each_pipe(dev_priv, pipe) I915_WRITE(PIPESTAT(pipe), 0xffff); - I915_WRITE(VLV_IMR, 0xffffffff); - I915_WRITE(VLV_IER, 0x0); - I915_WRITE(VLV_IIR, 0xffffffff); - I915_WRITE(VLV_IIR, 0xffffffff); - POSTING_READ(VLV_IIR); + GEN5_IRQ_RESET(VLV_); } static void ironlake_irq_uninstall(struct drm_device *dev) -- cgit v1.2.3 From 893fce8edae9feabb5515b982285e5af72fcfa95 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Thu, 30 Oct 2014 19:42:56 +0200 Subject: drm/i915: Call gen5_gt_irq_reset() from valleyview_irq_uninstall() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Looks like we forgot to call gen5_gt_irq_reset() for vlv in the uninstall phase. Do so. Signed-off-by: Ville Syrjälä Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index c106bba3f97c..67c046b8ce0d 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -3588,6 +3588,8 @@ static void valleyview_irq_uninstall(struct drm_device *dev) I915_WRITE(VLV_MASTER_IER, 0); + gen5_gt_irq_reset(dev); + for_each_pipe(dev_priv, pipe) I915_WRITE(PIPESTAT(pipe), 0xffff); -- cgit v1.2.3 From 120dda4f638fe65d69674a674c3c1d639b31b4f1 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Thu, 30 Oct 2014 19:42:57 +0200 Subject: drm/i915: Make valleyview_display_irqs_(un)install() work for chv MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Genralize valleyview_display_irqs_install() and valleyview_display_irqs_uninstall() enough so that they work on chv. The only difference to vlv here being the third pipe that chv brings. Signed-off-by: Ville Syrjälä Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 67c046b8ce0d..50431f68a84d 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -3335,24 +3335,27 @@ static void valleyview_display_irqs_install(struct drm_i915_private *dev_priv) { u32 pipestat_mask; u32 iir_mask; + enum pipe pipe; pipestat_mask = PIPESTAT_INT_STATUS_MASK | PIPE_FIFO_UNDERRUN_STATUS; - I915_WRITE(PIPESTAT(PIPE_A), pipestat_mask); - I915_WRITE(PIPESTAT(PIPE_B), pipestat_mask); + for_each_pipe(dev_priv, pipe) + I915_WRITE(PIPESTAT(pipe), pipestat_mask); POSTING_READ(PIPESTAT(PIPE_A)); pipestat_mask = PLANE_FLIP_DONE_INT_STATUS_VLV | PIPE_CRC_DONE_INTERRUPT_STATUS; - i915_enable_pipestat(dev_priv, PIPE_A, pipestat_mask | - PIPE_GMBUS_INTERRUPT_STATUS); - i915_enable_pipestat(dev_priv, PIPE_B, pipestat_mask); + i915_enable_pipestat(dev_priv, PIPE_A, PIPE_GMBUS_INTERRUPT_STATUS); + for_each_pipe(dev_priv, pipe) + i915_enable_pipestat(dev_priv, pipe, pipestat_mask); iir_mask = I915_DISPLAY_PORT_INTERRUPT | I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | I915_DISPLAY_PIPE_B_EVENT_INTERRUPT; + if (IS_CHERRYVIEW(dev_priv)) + iir_mask |= I915_DISPLAY_PIPE_C_EVENT_INTERRUPT; dev_priv->irq_mask &= ~iir_mask; I915_WRITE(VLV_IIR, iir_mask); @@ -3366,10 +3369,13 @@ static void valleyview_display_irqs_uninstall(struct drm_i915_private *dev_priv) { u32 pipestat_mask; u32 iir_mask; + enum pipe pipe; iir_mask = I915_DISPLAY_PORT_INTERRUPT | I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | I915_DISPLAY_PIPE_B_EVENT_INTERRUPT; + if (IS_CHERRYVIEW(dev_priv)) + iir_mask |= I915_DISPLAY_PIPE_C_EVENT_INTERRUPT; dev_priv->irq_mask |= iir_mask; I915_WRITE(VLV_IMR, dev_priv->irq_mask); @@ -3381,14 +3387,15 @@ static void valleyview_display_irqs_uninstall(struct drm_i915_private *dev_priv) pipestat_mask = PLANE_FLIP_DONE_INT_STATUS_VLV | PIPE_CRC_DONE_INTERRUPT_STATUS; - i915_disable_pipestat(dev_priv, PIPE_A, pipestat_mask | - PIPE_GMBUS_INTERRUPT_STATUS); - i915_disable_pipestat(dev_priv, PIPE_B, pipestat_mask); + i915_disable_pipestat(dev_priv, PIPE_A, PIPE_GMBUS_INTERRUPT_STATUS); + for_each_pipe(dev_priv, pipe) + i915_disable_pipestat(dev_priv, pipe, pipestat_mask); pipestat_mask = PIPESTAT_INT_STATUS_MASK | PIPE_FIFO_UNDERRUN_STATUS; - I915_WRITE(PIPESTAT(PIPE_A), pipestat_mask); - I915_WRITE(PIPESTAT(PIPE_B), pipestat_mask); + + for_each_pipe(dev_priv, pipe) + I915_WRITE(PIPESTAT(pipe), pipestat_mask); POSTING_READ(PIPESTAT(PIPE_A)); } -- cgit v1.2.3 From 70591a4101a4e5c1b89dc98a706406368a23c8ec Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Thu, 30 Oct 2014 19:42:58 +0200 Subject: drm/i915: Refactor vlv_display_irq_reset() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pull the vlv display irq reset code to a new functions. The aim is to share the code with chv. Signed-off-by: Ville Syrjälä Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 40 +++++++++++++++++----------------------- 1 file changed, 17 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 50431f68a84d..38e57dd0db1a 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -3105,10 +3105,22 @@ static void ironlake_irq_reset(struct drm_device *dev) ibx_irq_reset(dev); } +static void vlv_display_irq_reset(struct drm_i915_private *dev_priv) +{ + enum pipe pipe; + + I915_WRITE(PORT_HOTPLUG_EN, 0); + I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); + + for_each_pipe(dev_priv, pipe) + I915_WRITE(PIPESTAT(pipe), 0xffff); + + GEN5_IRQ_RESET(VLV_); +} + static void valleyview_irq_preinstall(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - int pipe; /* VLV magic */ I915_WRITE(VLV_IMR, 0); @@ -3124,12 +3136,7 @@ static void valleyview_irq_preinstall(struct drm_device *dev) I915_WRITE(DPINVGTT, DPINVGTT_STATUS_MASK); - I915_WRITE(PORT_HOTPLUG_EN, 0); - I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); - for_each_pipe(dev_priv, pipe) - I915_WRITE(PIPESTAT(pipe), 0xffff); - - GEN5_IRQ_RESET(VLV_); + vlv_display_irq_reset(dev_priv); } static void gen8_gt_irq_reset(struct drm_i915_private *dev_priv) @@ -3177,7 +3184,6 @@ void gen8_irq_power_well_post_enable(struct drm_i915_private *dev_priv) static void cherryview_irq_preinstall(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - int pipe; I915_WRITE(GEN8_MASTER_IRQ, 0); POSTING_READ(GEN8_MASTER_IRQ); @@ -3188,13 +3194,7 @@ static void cherryview_irq_preinstall(struct drm_device *dev) I915_WRITE(DPINVGTT, DPINVGTT_STATUS_MASK_CHV); - I915_WRITE(PORT_HOTPLUG_EN, 0); - I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); - - for_each_pipe(dev_priv, pipe) - I915_WRITE(PIPESTAT(pipe), 0xffff); - - GEN5_IRQ_RESET(VLV_); + vlv_display_irq_reset(dev_priv); } static void ibx_hpd_irq_setup(struct drm_device *dev) @@ -3588,7 +3588,6 @@ static void gen8_irq_uninstall(struct drm_device *dev) static void valleyview_irq_uninstall(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - int pipe; if (!dev_priv) return; @@ -3597,12 +3596,7 @@ static void valleyview_irq_uninstall(struct drm_device *dev) gen5_gt_irq_reset(dev); - for_each_pipe(dev_priv, pipe) - I915_WRITE(PIPESTAT(pipe), 0xffff); - I915_WRITE(HWSTAM, 0xffffffff); - I915_WRITE(PORT_HOTPLUG_EN, 0); - I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); /* Interrupt setup is already guaranteed to be single-threaded, this is * just to make the assert_spin_locked check happy. */ @@ -3611,9 +3605,9 @@ static void valleyview_irq_uninstall(struct drm_device *dev) valleyview_display_irqs_uninstall(dev_priv); spin_unlock_irq(&dev_priv->irq_lock); - dev_priv->irq_mask = 0; + vlv_display_irq_reset(dev_priv); - GEN5_IRQ_RESET(VLV_); + dev_priv->irq_mask = 0; } static void cherryview_irq_uninstall(struct drm_device *dev) -- cgit v1.2.3 From 0e6c9a9eb85b1cb38a7194630cb14c293614da8d Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Thu, 30 Oct 2014 19:43:00 +0200 Subject: drm/i914: Refactor vlv_display_irq_postinstall() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Split the vlv display irq postinstall code to a separate function so that we can share it with chv. Signed-off-by: Ville Syrjälä Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 38e57dd0db1a..297c9b1246da 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -3425,10 +3425,8 @@ void valleyview_disable_display_irqs(struct drm_i915_private *dev_priv) valleyview_display_irqs_uninstall(dev_priv); } -static int valleyview_irq_postinstall(struct drm_device *dev) +static void vlv_display_irq_postinstall(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = dev->dev_private; - dev_priv->irq_mask = ~0; I915_WRITE(PORT_HOTPLUG_EN, 0); @@ -3449,6 +3447,13 @@ static int valleyview_irq_postinstall(struct drm_device *dev) I915_WRITE(VLV_IIR, 0xffffffff); I915_WRITE(VLV_IIR, 0xffffffff); +} + +static int valleyview_irq_postinstall(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + vlv_display_irq_postinstall(dev_priv); gen5_gt_irq_postinstall(dev); -- cgit v1.2.3 From 9b2e8c9411a81daf4772fbe30e0953f781f9b440 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Thu, 30 Oct 2014 19:43:01 +0200 Subject: drm/i915: Drop useless VLV_IIR writes from vlv_display_irq_postinstall() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The extra VLV_IIR writes at the end of vlv_display_irq_postinstall() serve no purpose. Remove them. The VLV_IMR/IER/IIR setup at the start of the function also seems a bit pointless since it doesn't unmask/enable anything. But leave it be for now. Signed-off-by: Ville Syrjälä Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 297c9b1246da..f2a45f14ab44 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -3444,9 +3444,6 @@ static void vlv_display_irq_postinstall(struct drm_i915_private *dev_priv) if (dev_priv->display_irqs_enabled) valleyview_display_irqs_install(dev_priv); spin_unlock_irq(&dev_priv->irq_lock); - - I915_WRITE(VLV_IIR, 0xffffffff); - I915_WRITE(VLV_IIR, 0xffffffff); } static int valleyview_irq_postinstall(struct drm_device *dev) -- cgit v1.2.3 From 5eba929d1bb8fb662594b44d02f54fbaa7557a3b Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Fri, 31 Oct 2014 11:53:06 +0200 Subject: drm/i915: Kill leftover GTIIR writes from valleyview_irq_preinstall() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are two leftover GTIIR writes in valleyview_irq_preinstall(). Looks like the were originally left behind by: commit d18ea1b58a5003eb6fca03aff03c4c01321e6cb1 Author: Daniel Vetter Date: Fri Jul 12 22:43:25 2013 +0200 drm/i915: unify PM interrupt preinstall sequence and then the GTIIR reset was added back here: commit f86f3fb005d0c907285fa8685badcb24ec31ee59 Author: Paulo Zanoni Date: Tue Apr 1 15:37:14 2014 -0300 drm/i915: properly clear IIR at irq_uninstall on Gen5+ so we can kill the leftovers from the vlv code. Cc: Paulo Zanoni Suggested-by: Paulo Zanoni Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index f2a45f14ab44..318a6a0724d0 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -3128,10 +3128,6 @@ static void valleyview_irq_preinstall(struct drm_device *dev) I915_WRITE(RING_IMR(GEN6_BSD_RING_BASE), 0); I915_WRITE(RING_IMR(BLT_RING_BASE), 0); - /* and GT */ - I915_WRITE(GTIIR, I915_READ(GTIIR)); - I915_WRITE(GTIIR, I915_READ(GTIIR)); - gen5_gt_irq_reset(dev); I915_WRITE(DPINVGTT, DPINVGTT_STATUS_MASK); -- cgit v1.2.3 From 59a5d2907f652249209453af9748a8ca8ccf8655 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Thu, 30 Oct 2014 15:52:45 -0200 Subject: drm/i915: fix "Unexpected fault" error message line break Fix the message, not the fault :) This is what I see: [ 282.108597] [drm:i915_check_and_clear_faults] Unexpected fault [ 282.108597] Addr: 0x00000000\n Address space: PPGTT [ 282.108597] Source ID: 24 [ 282.108597] Type: 0 Signed-off-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index cb7adabc4e44..de12017c809b 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -1266,7 +1266,7 @@ void i915_check_and_clear_faults(struct drm_device *dev) fault_reg = I915_READ(RING_FAULT_REG(ring)); if (fault_reg & RING_FAULT_VALID) { DRM_DEBUG_DRIVER("Unexpected fault\n" - "\tAddr: 0x%08lx\\n" + "\tAddr: 0x%08lx\n" "\tAddress space: %s\n" "\tSource ID: %d\n" "\tType: %d\n", -- cgit v1.2.3 From fac6adb06a530ead523a60c975bae633e44335ca Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Thu, 30 Oct 2014 15:59:31 -0200 Subject: drm/i915: fix RPS on runtime suspend With this patch, the RPS sequence for runtime suspend/resume is exactly like the sequence for S3 suspend/resume: - flush_delayed_work(&dev_priv->rps.delayed_resume_work) - intel_runtime_pm_disable_interrupts() - intel_suspend_gt_powersave() (suspended) - intel_runtime_pm_enable_interrupts() - intel_enable_gt_powersave() With this, we get rid of WARNs that are currently intermittently triggered by the system-suspend-execbuf subtest of runtime PM. Notice that these WARNs could also be triggered in other ways that involved doing lots of RPM suspend/resume cycles just after a system S3 resume. Testcase: igt/pm_rpm/system-suspend-execbuf Signed-off-by: Paulo Zanoni Reference: https://bugs.freedesktop.org/show_bug.cgi?id=82939 Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 0c7cf480e854..2404b2baa01e 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -1395,13 +1395,9 @@ static int intel_runtime_suspend(struct device *device) i915_gem_release_all_mmaps(dev_priv); mutex_unlock(&dev->struct_mutex); - /* - * rps.work can't be rearmed here, since we get here only after making - * sure the GPU is idle and the RPS freq is set to the minimum. See - * intel_mark_idle(). - */ - cancel_work_sync(&dev_priv->rps.work); + flush_delayed_work(&dev_priv->rps.delayed_resume_work); intel_runtime_pm_disable_interrupts(dev_priv); + intel_suspend_gt_powersave(dev); ret = intel_suspend_complete(dev_priv); if (ret) { @@ -1473,7 +1469,7 @@ static int intel_runtime_resume(struct device *device) gen6_update_ring_freq(dev); intel_runtime_pm_enable_interrupts(dev_priv); - intel_reset_gt_powersave(dev); + intel_enable_gt_powersave(dev); if (ret) DRM_ERROR("Runtime resume failed, disabling it (%d)\n", ret); -- cgit v1.2.3 From 8e63954903779f0f70b4564d5cb0accb4b065c64 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Thu, 30 Oct 2014 18:40:53 +0000 Subject: drm/i915: Remove redundant parameter to i915_gem_object_wait_rendering__tail() An earlier commit (c8725f3dc0911d4354315a65150aecd8b7d0d74a: Do not call retire_requests from wait_for_rendering) removed the use of the ring parameter within wait_rendering__tail() but did not remove the parameter itself. As the plan is to remove obj->ring which is where this parameter comes from, it is simpler to just remove the parameter completely than to update it with a new source. For: VIZ-4377 Signed-off-by: John Harrison CC: Chris Wilson CC: Brad Volkin Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 7e919784b112..c2456c2be732 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1281,8 +1281,7 @@ i915_wait_seqno(struct intel_engine_cs *ring, uint32_t seqno) } static int -i915_gem_object_wait_rendering__tail(struct drm_i915_gem_object *obj, - struct intel_engine_cs *ring) +i915_gem_object_wait_rendering__tail(struct drm_i915_gem_object *obj) { if (!obj->active) return 0; @@ -1319,7 +1318,7 @@ i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj, if (ret) return ret; - return i915_gem_object_wait_rendering__tail(obj, ring); + return i915_gem_object_wait_rendering__tail(obj); } /* A nonblocking variant of the above wait. This is a highly dangerous routine @@ -1359,7 +1358,7 @@ i915_gem_object_wait_rendering__nonblocking(struct drm_i915_gem_object *obj, if (ret) return ret; - return i915_gem_object_wait_rendering__tail(obj, ring); + return i915_gem_object_wait_rendering__tail(obj); } /** -- cgit v1.2.3 From 26ff2762108010976e2785c605cdc7ac6882da11 Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Tue, 28 Oct 2014 15:10:12 +0200 Subject: drm/i915: Add kerneldoc for intel_pipe_update_{start, end} Note that a later patch will use these functions in some other file and drop the static. Hence the kerneldoc looks appropriate. Signed-off-by: Ander Conselvan de Oliveira Reviewed-by: Paulo Zanoni [danvet: Add comment that the functions will become non-static shortly.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_sprite.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 8c70c54e048d..c692adea4332 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -60,6 +60,22 @@ static int usecs_to_scanlines(const struct drm_display_mode *mode, int usecs) return DIV_ROUND_UP(usecs * mode->crtc_clock, 1000 * mode->crtc_htotal); } +/** + * intel_pipe_update_start() - start update of a set of display registers + * @crtc: the crtc of which the registers are going to be updated + * @start_vbl_count: vblank counter return pointer used for error checking + * + * Mark the start of an update to pipe registers that should be updated + * atomically regarding vblank. If the next vblank will happens within + * the next 100 us, this function waits until the vblank passes. + * + * After a successful call to this function, interrupts will be disabled + * until a subsequent call to intel_pipe_update_end(). That is done to + * avoid random delays. The value written to @start_vbl_count should be + * supplied to intel_pipe_update_end() for error checking. + * + * Return: true if the call was successful + */ static bool intel_pipe_update_start(struct intel_crtc *crtc, uint32_t *start_vbl_count) { struct drm_device *dev = crtc->base.dev; @@ -126,6 +142,15 @@ static bool intel_pipe_update_start(struct intel_crtc *crtc, uint32_t *start_vbl return true; } +/** + * intel_pipe_update_end() - end update of a set of display registers + * @crtc: the crtc of which the registers were updated + * @start_vbl_count: start vblank counter (used for error checking) + * + * Mark the end of an update started with intel_pipe_update_start(). This + * re-enables interrupts and verifies the update was actually completed + * before a vblank using the value of @start_vbl_count. + */ static void intel_pipe_update_end(struct intel_crtc *crtc, u32 start_vbl_count) { struct drm_device *dev = crtc->base.dev; -- cgit v1.2.3 From 0594a3d9c0072f198462e8dbc56cb64b7d872d90 Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Tue, 28 Oct 2014 15:10:13 +0200 Subject: drm/i915: Remove modeset lock check from intel_pipe_update_start() A follow up patch will call this funcion from a work context for the mmio flip, in which case we cannot acquire the modeset locks. That's not a problem though, since the check is there to protect vblank and the mode, but the code that changes that waits for pending flips first. Signed-off-by: Ander Conselvan de Oliveira Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_sprite.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index c692adea4332..0068fefd952e 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -86,8 +86,6 @@ static bool intel_pipe_update_start(struct intel_crtc *crtc, uint32_t *start_vbl wait_queue_head_t *wq = drm_crtc_vblank_waitqueue(&crtc->base); DEFINE_WAIT(wait); - WARN_ON(!drm_modeset_is_locked(&crtc->base.mutex)); - vblank_start = mode->crtc_vblank_start; if (mode->flags & DRM_MODE_FLAG_INTERLACE) vblank_start = DIV_ROUND_UP(vblank_start, 2); -- cgit v1.2.3 From 9362c7c576d39ebca81f82e931ab109c065d42be Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Tue, 28 Oct 2014 15:10:14 +0200 Subject: drm/i915: Use vblank evade mechanism in mmio_flip Currently we program just DPSCNTR and DSPSTRIDE directly from the ring interrupt handler, which is fine since the hardware guarantees that those are update atomically. When we have atomic page flips we'll want to be able to update also the offset registers, and then we need to use the vblank evade mechanism to guarantee atomicity. Since that mechanism introduces a wait, we need to do the actual register write from a work when it is triggered by the ring interrupt. v2: Explain the need for mmio_flip.work in the commit message (Paulo) Initialize the mmio_flip work in intel_crtc_init() (Paulo) Prevent new flips the previous flip work finishes (Paulo) Don't acquire modeset locks for mmio flip work Note: Paulo had reservations about the work item leaking over a plane disable. But insofar as we do lack these checks that issue is already present with the existing code. Signed-off-by: Ander Conselvan de Oliveira Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 30 ++++++++++++++++++++++++++---- drivers/gpu/drm/i915/intel_drv.h | 12 +++++++++++- drivers/gpu/drm/i915/intel_sprite.c | 4 ++-- 3 files changed, 39 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 44060fb020a8..84f4f0504bbb 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -9401,11 +9401,15 @@ static void intel_do_mmio_flip(struct intel_crtc *intel_crtc) struct intel_framebuffer *intel_fb = to_intel_framebuffer(intel_crtc->base.primary->fb); struct drm_i915_gem_object *obj = intel_fb->obj; + bool atomic_update; + u32 start_vbl_count; u32 dspcntr; u32 reg; intel_mark_page_flip_active(intel_crtc); + atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count); + reg = DSPCNTR(intel_crtc->plane); dspcntr = I915_READ(reg); @@ -9419,6 +9423,21 @@ static void intel_do_mmio_flip(struct intel_crtc *intel_crtc) I915_WRITE(DSPSURF(intel_crtc->plane), intel_crtc->unpin_work->gtt_offset); POSTING_READ(DSPSURF(intel_crtc->plane)); + + if (atomic_update) + intel_pipe_update_end(intel_crtc, start_vbl_count); + + spin_lock_irq(&dev_priv->mmio_flip_lock); + intel_crtc->mmio_flip.status = INTEL_MMIO_FLIP_IDLE; + spin_unlock_irq(&dev_priv->mmio_flip_lock); +} + +static void intel_mmio_flip_work_func(struct work_struct *work) +{ + struct intel_crtc *intel_crtc = + container_of(work, struct intel_crtc, mmio_flip.work); + + intel_do_mmio_flip(intel_crtc); } static int intel_postpone_flip(struct drm_i915_gem_object *obj) @@ -9461,15 +9480,15 @@ void intel_notify_mmio_flip(struct intel_engine_cs *ring) struct intel_mmio_flip *mmio_flip; mmio_flip = &intel_crtc->mmio_flip; - if (mmio_flip->seqno == 0) + if (mmio_flip->status != INTEL_MMIO_FLIP_WAIT_RING) continue; if (ring->id != mmio_flip->ring_id) continue; if (i915_seqno_passed(seqno, mmio_flip->seqno)) { - intel_do_mmio_flip(intel_crtc); - mmio_flip->seqno = 0; + schedule_work(&intel_crtc->mmio_flip.work); + mmio_flip->status = INTEL_MMIO_FLIP_WORK_SCHEDULED; ring->irq_put(ring); } } @@ -9487,7 +9506,7 @@ static int intel_queue_mmio_flip(struct drm_device *dev, struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int ret; - if (WARN_ON(intel_crtc->mmio_flip.seqno)) + if (WARN_ON(intel_crtc->mmio_flip.status != INTEL_MMIO_FLIP_IDLE)) return -EBUSY; ret = intel_postpone_flip(obj); @@ -9499,6 +9518,7 @@ static int intel_queue_mmio_flip(struct drm_device *dev, } spin_lock_irq(&dev_priv->mmio_flip_lock); + intel_crtc->mmio_flip.status = INTEL_MMIO_FLIP_WAIT_RING; intel_crtc->mmio_flip.seqno = obj->last_write_seqno; intel_crtc->mmio_flip.ring_id = obj->ring->id; spin_unlock_irq(&dev_priv->mmio_flip_lock); @@ -11983,6 +12003,8 @@ static void intel_crtc_init(struct drm_device *dev, int pipe) dev_priv->plane_to_crtc_mapping[intel_crtc->plane] = &intel_crtc->base; dev_priv->pipe_to_crtc_mapping[intel_crtc->pipe] = &intel_crtc->base; + INIT_WORK(&intel_crtc->mmio_flip.work, intel_mmio_flip_work_func); + drm_crtc_helper_add(&intel_crtc->base, &intel_helper_funcs); WARN_ON(drm_crtc_index(&intel_crtc->base) != intel_crtc->pipe); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index ae75b9950f01..c8ddde68a24e 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -399,9 +399,17 @@ struct intel_pipe_wm { bool sprites_scaled; }; +enum intel_mmio_flip_status { + INTEL_MMIO_FLIP_IDLE = 0, + INTEL_MMIO_FLIP_WAIT_RING, + INTEL_MMIO_FLIP_WORK_SCHEDULED, +}; + struct intel_mmio_flip { u32 seqno; u32 ring_id; + enum intel_mmio_flip_status status; + struct work_struct work; }; struct intel_crtc { @@ -1167,7 +1175,9 @@ int intel_sprite_set_colorkey(struct drm_device *dev, void *data, struct drm_file *file_priv); int intel_sprite_get_colorkey(struct drm_device *dev, void *data, struct drm_file *file_priv); - +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); /* intel_tv.c */ void intel_tv_init(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 0068fefd952e..64076555153a 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -76,7 +76,7 @@ static int usecs_to_scanlines(const struct drm_display_mode *mode, int usecs) * * Return: true if the call was successful */ -static bool intel_pipe_update_start(struct intel_crtc *crtc, uint32_t *start_vbl_count) +bool intel_pipe_update_start(struct intel_crtc *crtc, uint32_t *start_vbl_count) { struct drm_device *dev = crtc->base.dev; const struct drm_display_mode *mode = &crtc->config.adjusted_mode; @@ -149,7 +149,7 @@ static bool intel_pipe_update_start(struct intel_crtc *crtc, uint32_t *start_vbl * re-enables interrupts and verifies the update was actually completed * before a vblank using the value of @start_vbl_count. */ -static void intel_pipe_update_end(struct intel_crtc *crtc, u32 start_vbl_count) +void intel_pipe_update_end(struct intel_crtc *crtc, u32 start_vbl_count) { struct drm_device *dev = crtc->base.dev; enum pipe pipe = crtc->pipe; -- cgit v1.2.3 From ef79e17ccef32599f3cec3842f81d70117181291 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 31 Oct 2014 13:53:52 +0000 Subject: drm/i915: Only mark as map-and-fenceable when bound into the GGTT We use the obj->map_and_fenceable hint for when we already have a valid mapping of this object in the aperture. This hint can only apply to the GGTT and not to the aliasing-ppGTT. One user of the hint is execbuffer relocation, which began to fail when it tried to follow the hint and perform the relocate through the non-existent GGTT mapping. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=85671 Signed-off-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 39 +++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index c2456c2be732..0c6ef667d256 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3476,20 +3476,6 @@ search_free: list_move_tail(&obj->global_list, &dev_priv->mm.bound_list); list_add_tail(&vma->mm_list, &vm->inactive_list); - if (i915_is_ggtt(vm)) { - bool mappable, fenceable; - - fenceable = (vma->node.size == fence_size && - (vma->node.start & (fence_alignment - 1)) == 0); - - mappable = (vma->node.start + obj->base.size <= - dev_priv->gtt.mappable_end); - - obj->map_and_fenceable = mappable && fenceable; - } - - WARN_ON(flags & PIN_MAPPABLE && !obj->map_and_fenceable); - trace_i915_vma_bind(vma, flags); vma->bind_vma(vma, obj->cache_level, flags & (PIN_MAPPABLE | PIN_GLOBAL) ? GLOBAL_BIND : 0); @@ -4061,6 +4047,7 @@ i915_gem_object_pin(struct drm_i915_gem_object *obj, { struct drm_i915_private *dev_priv = obj->base.dev->dev_private; struct i915_vma *vma; + unsigned bound; int ret; if (WARN_ON(vm == &dev_priv->mm.aliasing_ppgtt->base)) @@ -4090,6 +4077,7 @@ i915_gem_object_pin(struct drm_i915_gem_object *obj, } } + bound = vma ? vma->bound : 0; if (vma == NULL || !drm_mm_node_allocated(&vma->node)) { vma = i915_gem_object_bind_to_vm(obj, vm, alignment, flags); if (IS_ERR(vma)) @@ -4099,6 +4087,29 @@ i915_gem_object_pin(struct drm_i915_gem_object *obj, if (flags & PIN_GLOBAL && !(vma->bound & GLOBAL_BIND)) vma->bind_vma(vma, obj->cache_level, GLOBAL_BIND); + if ((bound ^ vma->bound) & GLOBAL_BIND) { + bool mappable, fenceable; + u32 fence_size, fence_alignment; + + fence_size = i915_gem_get_gtt_size(obj->base.dev, + obj->base.size, + obj->tiling_mode); + fence_alignment = i915_gem_get_gtt_alignment(obj->base.dev, + obj->base.size, + obj->tiling_mode, + true); + + fenceable = (vma->node.size == fence_size && + (vma->node.start & (fence_alignment - 1)) == 0); + + mappable = (vma->node.start + obj->base.size <= + dev_priv->gtt.mappable_end); + + obj->map_and_fenceable = mappable && fenceable; + } + + WARN_ON(flags & PIN_MAPPABLE && !obj->map_and_fenceable); + vma->pin_count++; if (flags & PIN_MAPPABLE) obj->pin_mappable |= true; -- cgit v1.2.3 From c826c4493851913e57dd47a7fbfe07156ac9f91d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 31 Oct 2014 13:53:53 +0000 Subject: drm/i915: Request PIN_GLOBAL when pinning a vma for GTT relocations Always require PIN_GLOBAL when we want a mappable offset (PIN_MAPPABLE). This causes the pin to fixup the global binding in cases were the vma was already bound (and due to the proceeding bug, we considered it to be already mappable). References: https://bugs.freedesktop.org/show_bug.cgi?id=85671 Signed-off-by: Chris Wilson [danvet: Add WARN_ON to check that PIN_MAP implies PIN_GLOBAL as discussed on irc.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 5 ++++- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 0c6ef667d256..1de94cc63517 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3478,7 +3478,7 @@ search_free: trace_i915_vma_bind(vma, flags); vma->bind_vma(vma, obj->cache_level, - flags & (PIN_MAPPABLE | PIN_GLOBAL) ? GLOBAL_BIND : 0); + flags & PIN_GLOBAL ? GLOBAL_BIND : 0); return vma; @@ -4056,6 +4056,9 @@ i915_gem_object_pin(struct drm_i915_gem_object *obj, if (WARN_ON(flags & (PIN_GLOBAL | PIN_MAPPABLE) && !i915_is_ggtt(vm))) return -EINVAL; + if (WARN_ON((flags & (PIN_MAPPABLE | PIN_GLOBAL)) == PIN_MAPPABLE)) + return -EINVAL; + vma = i915_gem_obj_to_vma(obj, vm); if (vma) { if (WARN_ON(vma->pin_count == DRM_I915_GEM_OBJECT_MAX_PIN_COUNT)) diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 4b7f5c104ce0..e1ed85a6dc6d 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -528,7 +528,7 @@ i915_gem_execbuffer_reserve_vma(struct i915_vma *vma, flags = 0; if (entry->flags & __EXEC_OBJECT_NEEDS_MAP) - flags |= PIN_MAPPABLE; + flags |= PIN_GLOBAL | PIN_MAPPABLE; if (entry->flags & EXEC_OBJECT_NEEDS_GTT) flags |= PIN_GLOBAL; if (entry->flags & __EXEC_OBJECT_NEEDS_BIAS) -- cgit v1.2.3 From 70f2f5c70440feff01d9ba7c8b4432eb72bd69eb Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 24 Oct 2014 12:11:11 +0100 Subject: drm/i915: Report the actual swizzling back to userspace Userspace cares about whether or not swizzling depends on the page address for its direct access into bound objects. Extend the get_tiling ioctl to report the physical swizzling value in addition to the logical swizzling value so that userspace can accurately determine when it is possible for manual detiling. Signed-off-by: Chris Wilson Cc: Akash Goel Cc: Daniel Vetter Testcase: igt/gem_tiled_wc Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_tiling.c | 1 + include/uapi/drm/i915_drm.h | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c index d1e7a3e088aa..749ab485569e 100644 --- a/drivers/gpu/drm/i915/i915_gem_tiling.c +++ b/drivers/gpu/drm/i915/i915_gem_tiling.c @@ -458,6 +458,7 @@ i915_gem_get_tiling(struct drm_device *dev, void *data, } /* Hide bit 17 from the user -- see comment in i915_gem_set_tiling */ + args->phys_swizzle_mode = args->swizzle_mode; if (args->swizzle_mode == I915_BIT_6_SWIZZLE_9_17) args->swizzle_mode = I915_BIT_6_SWIZZLE_9; if (args->swizzle_mode == I915_BIT_6_SWIZZLE_9_10_17) diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h index ff57f07c3249..2ec0efcaa719 100644 --- a/include/uapi/drm/i915_drm.h +++ b/include/uapi/drm/i915_drm.h @@ -876,6 +876,12 @@ struct drm_i915_gem_get_tiling { * mmap mapping. */ __u32 swizzle_mode; + + /** + * Returned address bit 6 swizzling required for CPU access through + * mmap mapping whilst bound. + */ + __u32 phys_swizzle_mode; }; struct drm_i915_gem_get_aperture { -- cgit v1.2.3 From c46f111f5171b63572fae3f79bcfe578bc96c603 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 27 Oct 2014 16:26:52 +0200 Subject: drm/i915: clean up and clarify audio related register defines Make audio related register defines conform to existing style: Add _MASK where relevant, indent the defines for register contents, don't indent the defines for register addresses, prefix pipe specific register address defines with underscores, drop self explanatory comments. No functional changes. Signed-off-by: Jani Nikula Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 165 +++++++++++++++++++------------------ drivers/gpu/drm/i915/intel_audio.c | 12 +-- 2 files changed, 89 insertions(+), 88 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 2a4bdd56c4e0..cfc6554f762b 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -6011,57 +6011,58 @@ enum punit_power_well { #define GEN8_CENTROID_PIXEL_OPT_DIS (1<<8) #define GEN8_SAMPLER_POWER_BYPASS_DIS (1<<1) +/* Audio */ #define G4X_AUD_VID_DID (dev_priv->info.display_mmio_offset + 0x62020) -#define INTEL_AUDIO_DEVCL 0x808629FB -#define INTEL_AUDIO_DEVBLC 0x80862801 -#define INTEL_AUDIO_DEVCTG 0x80862802 +#define INTEL_AUDIO_DEVCL 0x808629FB +#define INTEL_AUDIO_DEVBLC 0x80862801 +#define INTEL_AUDIO_DEVCTG 0x80862802 #define G4X_AUD_CNTL_ST 0x620B4 -#define G4X_ELDV_DEVCL_DEVBLC (1 << 13) -#define G4X_ELDV_DEVCTG (1 << 14) -#define G4X_ELD_ADDR (0xf << 5) -#define G4X_ELD_ACK (1 << 4) +#define G4X_ELDV_DEVCL_DEVBLC (1 << 13) +#define G4X_ELDV_DEVCTG (1 << 14) +#define G4X_ELD_ADDR_MASK (0xf << 5) +#define G4X_ELD_ACK (1 << 4) #define G4X_HDMIW_HDMIEDID 0x6210C -#define IBX_HDMIW_HDMIEDID_A 0xE2050 -#define IBX_HDMIW_HDMIEDID_B 0xE2150 +#define _IBX_HDMIW_HDMIEDID_A 0xE2050 +#define _IBX_HDMIW_HDMIEDID_B 0xE2150 #define IBX_HDMIW_HDMIEDID(pipe) _PIPE(pipe, \ - IBX_HDMIW_HDMIEDID_A, \ - IBX_HDMIW_HDMIEDID_B) -#define IBX_AUD_CNTL_ST_A 0xE20B4 -#define IBX_AUD_CNTL_ST_B 0xE21B4 + _IBX_HDMIW_HDMIEDID_A, \ + _IBX_HDMIW_HDMIEDID_B) +#define _IBX_AUD_CNTL_ST_A 0xE20B4 +#define _IBX_AUD_CNTL_ST_B 0xE21B4 #define IBX_AUD_CNTL_ST(pipe) _PIPE(pipe, \ - IBX_AUD_CNTL_ST_A, \ - IBX_AUD_CNTL_ST_B) -#define IBX_ELD_BUFFER_SIZE (0x1f << 10) -#define IBX_ELD_ADDRESS (0x1f << 5) -#define IBX_ELD_ACK (1 << 4) + _IBX_AUD_CNTL_ST_A, \ + _IBX_AUD_CNTL_ST_B) +#define IBX_ELD_BUFFER_SIZE_MASK (0x1f << 10) +#define IBX_ELD_ADDRESS_MASK (0x1f << 5) +#define IBX_ELD_ACK (1 << 4) #define IBX_AUD_CNTL_ST2 0xE20C0 -#define IBX_ELD_VALIDB (1 << 0) -#define IBX_CP_READYB (1 << 1) +#define IBX_ELD_VALIDB (1 << 0) +#define IBX_CP_READYB (1 << 1) -#define CPT_HDMIW_HDMIEDID_A 0xE5050 -#define CPT_HDMIW_HDMIEDID_B 0xE5150 +#define _CPT_HDMIW_HDMIEDID_A 0xE5050 +#define _CPT_HDMIW_HDMIEDID_B 0xE5150 #define CPT_HDMIW_HDMIEDID(pipe) _PIPE(pipe, \ - CPT_HDMIW_HDMIEDID_A, \ - CPT_HDMIW_HDMIEDID_B) -#define CPT_AUD_CNTL_ST_A 0xE50B4 -#define CPT_AUD_CNTL_ST_B 0xE51B4 + _CPT_HDMIW_HDMIEDID_A, \ + _CPT_HDMIW_HDMIEDID_B) +#define _CPT_AUD_CNTL_ST_A 0xE50B4 +#define _CPT_AUD_CNTL_ST_B 0xE51B4 #define CPT_AUD_CNTL_ST(pipe) _PIPE(pipe, \ - CPT_AUD_CNTL_ST_A, \ - CPT_AUD_CNTL_ST_B) + _CPT_AUD_CNTL_ST_A, \ + _CPT_AUD_CNTL_ST_B) #define CPT_AUD_CNTRL_ST2 0xE50C0 -#define VLV_HDMIW_HDMIEDID_A (VLV_DISPLAY_BASE + 0x62050) -#define VLV_HDMIW_HDMIEDID_B (VLV_DISPLAY_BASE + 0x62150) +#define _VLV_HDMIW_HDMIEDID_A (VLV_DISPLAY_BASE + 0x62050) +#define _VLV_HDMIW_HDMIEDID_B (VLV_DISPLAY_BASE + 0x62150) #define VLV_HDMIW_HDMIEDID(pipe) _PIPE(pipe, \ - VLV_HDMIW_HDMIEDID_A, \ - VLV_HDMIW_HDMIEDID_B) -#define VLV_AUD_CNTL_ST_A (VLV_DISPLAY_BASE + 0x620B4) -#define VLV_AUD_CNTL_ST_B (VLV_DISPLAY_BASE + 0x621B4) + _VLV_HDMIW_HDMIEDID_A, \ + _VLV_HDMIW_HDMIEDID_B) +#define _VLV_AUD_CNTL_ST_A (VLV_DISPLAY_BASE + 0x620B4) +#define _VLV_AUD_CNTL_ST_B (VLV_DISPLAY_BASE + 0x621B4) #define VLV_AUD_CNTL_ST(pipe) _PIPE(pipe, \ - VLV_AUD_CNTL_ST_A, \ - VLV_AUD_CNTL_ST_B) + _VLV_AUD_CNTL_ST_A, \ + _VLV_AUD_CNTL_ST_B) #define VLV_AUD_CNTL_ST2 (VLV_DISPLAY_BASE + 0x620C0) /* These are the 4 32-bit write offset registers for each stream @@ -6070,28 +6071,28 @@ enum punit_power_well { */ #define GEN7_SO_WRITE_OFFSET(n) (0x5280 + (n) * 4) -#define IBX_AUD_CONFIG_A 0xe2000 -#define IBX_AUD_CONFIG_B 0xe2100 +#define _IBX_AUD_CONFIG_A 0xe2000 +#define _IBX_AUD_CONFIG_B 0xe2100 #define IBX_AUD_CFG(pipe) _PIPE(pipe, \ - IBX_AUD_CONFIG_A, \ - IBX_AUD_CONFIG_B) -#define CPT_AUD_CONFIG_A 0xe5000 -#define CPT_AUD_CONFIG_B 0xe5100 + _IBX_AUD_CONFIG_A, \ + _IBX_AUD_CONFIG_B) +#define _CPT_AUD_CONFIG_A 0xe5000 +#define _CPT_AUD_CONFIG_B 0xe5100 #define CPT_AUD_CFG(pipe) _PIPE(pipe, \ - CPT_AUD_CONFIG_A, \ - CPT_AUD_CONFIG_B) -#define VLV_AUD_CONFIG_A (VLV_DISPLAY_BASE + 0x62000) -#define VLV_AUD_CONFIG_B (VLV_DISPLAY_BASE + 0x62100) + _CPT_AUD_CONFIG_A, \ + _CPT_AUD_CONFIG_B) +#define _VLV_AUD_CONFIG_A (VLV_DISPLAY_BASE + 0x62000) +#define _VLV_AUD_CONFIG_B (VLV_DISPLAY_BASE + 0x62100) #define VLV_AUD_CFG(pipe) _PIPE(pipe, \ - VLV_AUD_CONFIG_A, \ - VLV_AUD_CONFIG_B) + _VLV_AUD_CONFIG_A, \ + _VLV_AUD_CONFIG_B) #define AUD_CONFIG_N_VALUE_INDEX (1 << 29) #define AUD_CONFIG_N_PROG_ENABLE (1 << 28) #define AUD_CONFIG_UPPER_N_SHIFT 20 -#define AUD_CONFIG_UPPER_N_VALUE (0xff << 20) +#define AUD_CONFIG_UPPER_N_MASK (0xff << 20) #define AUD_CONFIG_LOWER_N_SHIFT 4 -#define AUD_CONFIG_LOWER_N_VALUE (0xfff << 4) +#define AUD_CONFIG_LOWER_N_MASK (0xfff << 4) #define AUD_CONFIG_PIXEL_CLOCK_HDMI_SHIFT 16 #define AUD_CONFIG_PIXEL_CLOCK_HDMI_MASK (0xf << 16) #define AUD_CONFIG_PIXEL_CLOCK_HDMI_25175 (0 << 16) @@ -6107,40 +6108,40 @@ enum punit_power_well { #define AUD_CONFIG_DISABLE_NCTS (1 << 3) /* HSW Audio */ -#define HSW_AUD_CONFIG_A 0x65000 /* Audio Configuration Transcoder A */ -#define HSW_AUD_CONFIG_B 0x65100 /* Audio Configuration Transcoder B */ -#define HSW_AUD_CFG(pipe) _PIPE(pipe, \ - HSW_AUD_CONFIG_A, \ - HSW_AUD_CONFIG_B) - -#define HSW_AUD_MISC_CTRL_A 0x65010 /* Audio Misc Control Convert 1 */ -#define HSW_AUD_MISC_CTRL_B 0x65110 /* Audio Misc Control Convert 2 */ -#define HSW_AUD_MISC_CTRL(pipe) _PIPE(pipe, \ - HSW_AUD_MISC_CTRL_A, \ - HSW_AUD_MISC_CTRL_B) - -#define HSW_AUD_DIP_ELD_CTRL_ST_A 0x650b4 /* Audio DIP and ELD Control State Transcoder A */ -#define HSW_AUD_DIP_ELD_CTRL_ST_B 0x651b4 /* Audio DIP and ELD Control State Transcoder B */ -#define HSW_AUD_DIP_ELD_CTRL(pipe) _PIPE(pipe, \ - HSW_AUD_DIP_ELD_CTRL_ST_A, \ - HSW_AUD_DIP_ELD_CTRL_ST_B) +#define _HSW_AUD_CONFIG_A 0x65000 +#define _HSW_AUD_CONFIG_B 0x65100 +#define HSW_AUD_CFG(pipe) _PIPE(pipe, \ + _HSW_AUD_CONFIG_A, \ + _HSW_AUD_CONFIG_B) + +#define _HSW_AUD_MISC_CTRL_A 0x65010 +#define _HSW_AUD_MISC_CTRL_B 0x65110 +#define HSW_AUD_MISC_CTRL(pipe) _PIPE(pipe, \ + _HSW_AUD_MISC_CTRL_A, \ + _HSW_AUD_MISC_CTRL_B) + +#define _HSW_AUD_DIP_ELD_CTRL_ST_A 0x650b4 +#define _HSW_AUD_DIP_ELD_CTRL_ST_B 0x651b4 +#define HSW_AUD_DIP_ELD_CTRL(pipe) _PIPE(pipe, \ + _HSW_AUD_DIP_ELD_CTRL_ST_A, \ + _HSW_AUD_DIP_ELD_CTRL_ST_B) /* Audio Digital Converter */ -#define HSW_AUD_DIG_CNVT_1 0x65080 /* Audio Converter 1 */ -#define HSW_AUD_DIG_CNVT_2 0x65180 /* Audio Converter 1 */ -#define AUD_DIG_CNVT(pipe) _PIPE(pipe, \ - HSW_AUD_DIG_CNVT_1, \ - HSW_AUD_DIG_CNVT_2) -#define DIP_PORT_SEL_MASK 0x3 - -#define HSW_AUD_EDID_DATA_A 0x65050 -#define HSW_AUD_EDID_DATA_B 0x65150 -#define HSW_AUD_EDID_DATA(pipe) _PIPE(pipe, \ - HSW_AUD_EDID_DATA_A, \ - HSW_AUD_EDID_DATA_B) - -#define HSW_AUD_PIPE_CONV_CFG 0x6507c /* Audio pipe and converter configs */ -#define HSW_AUD_PIN_ELD_CP_VLD 0x650c0 /* Audio ELD and CP Ready Status */ +#define _HSW_AUD_DIG_CNVT_1 0x65080 +#define _HSW_AUD_DIG_CNVT_2 0x65180 +#define AUD_DIG_CNVT(pipe) _PIPE(pipe, \ + _HSW_AUD_DIG_CNVT_1, \ + _HSW_AUD_DIG_CNVT_2) +#define DIP_PORT_SEL_MASK 0x3 + +#define _HSW_AUD_EDID_DATA_A 0x65050 +#define _HSW_AUD_EDID_DATA_B 0x65150 +#define HSW_AUD_EDID_DATA(pipe) _PIPE(pipe, \ + _HSW_AUD_EDID_DATA_A, \ + _HSW_AUD_EDID_DATA_B) + +#define HSW_AUD_PIPE_CONV_CFG 0x6507c +#define HSW_AUD_PIN_ELD_CP_VLD 0x650c0 #define AUDIO_INACTIVE_C (1<<11) #define AUDIO_INACTIVE_B (1<<7) #define AUDIO_INACTIVE_A (1<<3) diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c index 7580b3823e30..821514c95229 100644 --- a/drivers/gpu/drm/i915/intel_audio.c +++ b/drivers/gpu/drm/i915/intel_audio.c @@ -111,12 +111,12 @@ static void g4x_audio_codec_enable(struct drm_connector *connector, if (intel_eld_uptodate(connector, G4X_AUD_CNTL_ST, eldv, - G4X_AUD_CNTL_ST, G4X_ELD_ADDR, + G4X_AUD_CNTL_ST, G4X_ELD_ADDR_MASK, G4X_HDMIW_HDMIEDID)) return; tmp = I915_READ(G4X_AUD_CNTL_ST); - tmp &= ~(eldv | G4X_ELD_ADDR); + tmp &= ~(eldv | G4X_ELD_ADDR_MASK); len = (tmp >> 9) & 0x1f; /* ELD buffer size */ I915_WRITE(G4X_AUD_CNTL_ST, tmp); @@ -193,7 +193,7 @@ static void hsw_audio_codec_enable(struct drm_connector *connector, if (intel_eld_uptodate(connector, aud_cntrl_st2, eldv, - aud_cntl_st, IBX_ELD_ADDRESS, + aud_cntl_st, IBX_ELD_ADDRESS_MASK, hdmiw_hdmiedid)) return; @@ -202,7 +202,7 @@ static void hsw_audio_codec_enable(struct drm_connector *connector, I915_WRITE(aud_cntrl_st2, tmp); tmp = I915_READ(aud_cntl_st); - tmp &= ~IBX_ELD_ADDRESS; + tmp &= ~IBX_ELD_ADDRESS_MASK; I915_WRITE(aud_cntl_st, tmp); port = (tmp >> 29) & DIP_PORT_SEL_MASK; /* DIP_Port_Select, 0x1 = PortB */ DRM_DEBUG_DRIVER("port num:%d\n", port); @@ -287,7 +287,7 @@ static void ilk_audio_codec_enable(struct drm_connector *connector, if (intel_eld_uptodate(connector, aud_cntrl_st2, eldv, - aud_cntl_st, IBX_ELD_ADDRESS, + aud_cntl_st, IBX_ELD_ADDRESS_MASK, hdmiw_hdmiedid)) return; @@ -296,7 +296,7 @@ static void ilk_audio_codec_enable(struct drm_connector *connector, I915_WRITE(aud_cntrl_st2, tmp); tmp = I915_READ(aud_cntl_st); - tmp &= ~IBX_ELD_ADDRESS; + tmp &= ~IBX_ELD_ADDRESS_MASK; I915_WRITE(aud_cntl_st, tmp); len = min_t(int, eld[2], 21); /* 84 bytes of hw ELD buffer */ -- cgit v1.2.3 From 5fad84a7530f8e7664cdc6f490cb90653fed1266 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 4 Nov 2014 10:30:23 +0200 Subject: drm/i915: rewrite hsw/bdw audio codec enable/disable sequences There's some serious confusion regarding ELD valid bit that gets set and cleared back and forth etc. Rewrite it all based on the documented audio codec enable/disable sequences. v3: replace vblank wait with a comment v4: expand the comment on what should be done with the vblank wait Signed-off-by: Jani Nikula Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_audio.c | 115 ++++++++++++++++--------------------- 1 file changed, 51 insertions(+), 64 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c index 821514c95229..4dcfc46d5725 100644 --- a/drivers/gpu/drm/i915/intel_audio.c +++ b/drivers/gpu/drm/i915/intel_audio.c @@ -132,14 +132,26 @@ static void g4x_audio_codec_enable(struct drm_connector *connector, static void hsw_audio_codec_disable(struct intel_encoder *encoder) { - struct drm_device *dev = encoder->base.dev; - struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_crtc *crtc = encoder->base.crtc; - enum pipe pipe = to_intel_crtc(crtc)->pipe; + struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); + enum pipe pipe = intel_crtc->pipe; uint32_t tmp; + DRM_DEBUG_KMS("Disable audio codec on pipe %c\n", pipe_name(pipe)); + + /* Disable timestamps */ + tmp = I915_READ(HSW_AUD_CFG(pipe)); + tmp &= ~AUD_CONFIG_N_VALUE_INDEX; + tmp |= AUD_CONFIG_N_PROG_ENABLE; + tmp &= ~AUD_CONFIG_UPPER_N_MASK; + tmp &= ~AUD_CONFIG_LOWER_N_MASK; + if (intel_pipe_has_type(intel_crtc, INTEL_OUTPUT_DISPLAYPORT)) + tmp |= AUD_CONFIG_N_VALUE_INDEX; + I915_WRITE(HSW_AUD_CFG(pipe), tmp); + + /* Invalidate ELD */ tmp = I915_READ(HSW_AUD_PIN_ELD_CP_VLD); - tmp &= ~((AUDIO_OUTPUT_ENABLE_A | AUDIO_ELD_VALID_A) << (pipe * 4)); + tmp &= ~(AUDIO_ELD_VALID_A << (pipe * 4)); I915_WRITE(HSW_AUD_PIN_ELD_CP_VLD, tmp); } @@ -149,77 +161,52 @@ static void hsw_audio_codec_enable(struct drm_connector *connector, { struct drm_i915_private *dev_priv = connector->dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); - uint8_t *eld = connector->eld; - uint32_t eldv; + enum pipe pipe = intel_crtc->pipe; + const uint8_t *eld = connector->eld; uint32_t tmp; int len, i; - enum pipe pipe = intel_crtc->pipe; - enum port port; - int hdmiw_hdmiedid = HSW_AUD_EDID_DATA(pipe); - int aud_cntl_st = HSW_AUD_DIP_ELD_CTRL(pipe); - int aud_config = HSW_AUD_CFG(pipe); - int aud_cntrl_st2 = HSW_AUD_PIN_ELD_CP_VLD; - /* Audio output enable */ - DRM_DEBUG_DRIVER("HDMI audio: enable codec\n"); - tmp = I915_READ(aud_cntrl_st2); - tmp |= (AUDIO_OUTPUT_ENABLE_A << (pipe * 4)); - I915_WRITE(aud_cntrl_st2, tmp); - POSTING_READ(aud_cntrl_st2); - - /* Set ELD valid state */ - tmp = I915_READ(aud_cntrl_st2); - DRM_DEBUG_DRIVER("HDMI audio: pin eld vld status=0x%08x\n", tmp); - tmp |= (AUDIO_ELD_VALID_A << (pipe * 4)); - I915_WRITE(aud_cntrl_st2, tmp); - tmp = I915_READ(aud_cntrl_st2); - DRM_DEBUG_DRIVER("HDMI audio: eld vld status=0x%08x\n", tmp); - - /* Enable HDMI mode */ - tmp = I915_READ(aud_config); - DRM_DEBUG_DRIVER("HDMI audio: audio conf: 0x%08x\n", tmp); - /* clear N_programing_enable and N_value_index */ - tmp &= ~(AUD_CONFIG_N_VALUE_INDEX | AUD_CONFIG_N_PROG_ENABLE); - I915_WRITE(aud_config, tmp); + DRM_DEBUG_KMS("Enable audio codec on pipe %c, %u bytes ELD\n", + pipe_name(pipe), eld[2]); - DRM_DEBUG_DRIVER("ELD on pipe %c\n", pipe_name(pipe)); - - eldv = AUDIO_ELD_VALID_A << (pipe * 4); - - if (intel_pipe_has_type(intel_crtc, INTEL_OUTPUT_DISPLAYPORT)) - I915_WRITE(aud_config, AUD_CONFIG_N_VALUE_INDEX); /* 0x1 = DP */ - else - I915_WRITE(aud_config, audio_config_hdmi_pixel_clock(mode)); - - if (intel_eld_uptodate(connector, - aud_cntrl_st2, eldv, - aud_cntl_st, IBX_ELD_ADDRESS_MASK, - hdmiw_hdmiedid)) - return; + /* Enable audio presence detect, invalidate ELD */ + tmp = I915_READ(HSW_AUD_PIN_ELD_CP_VLD); + tmp |= AUDIO_OUTPUT_ENABLE_A << (pipe * 4); + tmp &= ~(AUDIO_ELD_VALID_A << (pipe * 4)); + I915_WRITE(HSW_AUD_PIN_ELD_CP_VLD, tmp); - tmp = I915_READ(aud_cntrl_st2); - tmp &= ~eldv; - I915_WRITE(aud_cntrl_st2, tmp); + /* + * FIXME: We're supposed to wait for vblank here, but we have vblanks + * disabled during the mode set. The proper fix would be to push the + * rest of the setup into a vblank work item, queued here, but the + * infrastructure is not there yet. + */ - tmp = I915_READ(aud_cntl_st); + /* Reset ELD write address */ + tmp = I915_READ(HSW_AUD_DIP_ELD_CTRL(pipe)); tmp &= ~IBX_ELD_ADDRESS_MASK; - I915_WRITE(aud_cntl_st, tmp); - port = (tmp >> 29) & DIP_PORT_SEL_MASK; /* DIP_Port_Select, 0x1 = PortB */ - DRM_DEBUG_DRIVER("port num:%d\n", port); + I915_WRITE(HSW_AUD_DIP_ELD_CTRL(pipe), tmp); - len = min_t(int, eld[2], 21); /* 84 bytes of hw ELD buffer */ - DRM_DEBUG_DRIVER("ELD size %d\n", len); + /* Up to 84 bytes of hw ELD buffer */ + len = min_t(int, eld[2], 21); for (i = 0; i < len; i++) - I915_WRITE(hdmiw_hdmiedid, *((uint32_t *)eld + i)); - - tmp = I915_READ(aud_cntrl_st2); - tmp |= eldv; - I915_WRITE(aud_cntrl_st2, tmp); + I915_WRITE(HSW_AUD_EDID_DATA(pipe), *((uint32_t *)eld + i)); - /* XXX: Transitional */ + /* ELD valid */ tmp = I915_READ(HSW_AUD_PIN_ELD_CP_VLD); - tmp |= ((AUDIO_OUTPUT_ENABLE_A | AUDIO_ELD_VALID_A) << (pipe * 4)); + tmp |= AUDIO_ELD_VALID_A << (pipe * 4); I915_WRITE(HSW_AUD_PIN_ELD_CP_VLD, tmp); + + /* Enable timestamps */ + tmp = I915_READ(HSW_AUD_CFG(pipe)); + tmp &= ~AUD_CONFIG_N_VALUE_INDEX; + tmp &= ~AUD_CONFIG_N_PROG_ENABLE; + tmp &= ~AUD_CONFIG_PIXEL_CLOCK_HDMI_MASK; + if (intel_pipe_has_type(intel_crtc, INTEL_OUTPUT_DISPLAYPORT)) + tmp |= AUD_CONFIG_N_VALUE_INDEX; + else + tmp |= audio_config_hdmi_pixel_clock(mode); + I915_WRITE(HSW_AUD_CFG(pipe), tmp); } static void ilk_audio_codec_enable(struct drm_connector *connector, -- cgit v1.2.3 From 2af30a5c40bff540f13106961662d000b1bc8cd7 Mon Sep 17 00:00:00 2001 From: Pradeep Bhat Date: Tue, 4 Nov 2014 17:06:38 +0000 Subject: drm/i915/skl: Read the Memory Latency Values for WM computation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch reads the memory latency values for all the 8 levels for SKL. These values are needed for the Watermark computation. v2: Incorporated the review comments from Damien on register indentation. v3: Updated the code to use the sandybridge_pcode_read for reading memory latencies for GEN9. v4: Don't put gen 9 in the middle of an ordered list of ifs (Damien) v5: take the rps.hw_lock around sandybridge_pcode_read() (Damien) v6: Use gen >= 9 in the pcode_read() function for data1. Move the defines near the gen6 ones and prefix them with PCODE. Remove unused timeout define (the pcode_read() code has a larger timeout already). Reviewed-by: Ville Syrjälä Signed-off-by: Pradeep Bhat Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 6 ++++ drivers/gpu/drm/i915/i915_reg.h | 7 ++++ drivers/gpu/drm/i915/intel_pm.c | 76 +++++++++++++++++++++++++++++++++++++---- 3 files changed, 83 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 54691bcf1822..05fcbe5c6e38 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1678,6 +1678,12 @@ struct drm_i915_private { uint16_t spr_latency[5]; /* cursor */ uint16_t cur_latency[5]; + /* + * Raw watermark memory latency values + * for SKL for all 8 levels + * in 1us units. + */ + uint16_t skl_latency[8]; /* current hardware state */ struct ilk_wm_values hw; diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index cfc6554f762b..db7d8fd5b7f5 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -5957,6 +5957,13 @@ enum punit_power_well { #define GEN6_PCODE_FREQ_IA_RATIO_SHIFT 8 #define GEN6_PCODE_FREQ_RING_RATIO_SHIFT 16 +#define GEN9_PCODE_DATA1 0x13812C +#define GEN9_PCODE_READ_MEM_LATENCY 0x6 +#define GEN9_MEM_LATENCY_LEVEL_MASK 0xFF +#define GEN9_MEM_LATENCY_LEVEL_1_5_SHIFT 8 +#define GEN9_MEM_LATENCY_LEVEL_2_6_SHIFT 16 +#define GEN9_MEM_LATENCY_LEVEL_3_7_SHIFT 24 + #define GEN6_GT_CORE_STATUS 0x138060 #define GEN6_CORE_CPD_STATE_MASK (7<<4) #define GEN6_RCn_MASK 7 diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 7a69eba533c7..761c884211c5 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2271,11 +2271,56 @@ hsw_compute_linetime_wm(struct drm_device *dev, struct drm_crtc *crtc) PIPE_WM_LINETIME_TIME(linetime); } -static void intel_read_wm_latency(struct drm_device *dev, uint16_t wm[5]) +static void intel_read_wm_latency(struct drm_device *dev, uint16_t wm[8]) { struct drm_i915_private *dev_priv = dev->dev_private; - if (IS_HASWELL(dev) || IS_BROADWELL(dev)) { + if (IS_GEN9(dev)) { + uint32_t val; + int ret; + + /* read the first set of memory latencies[0:3] */ + val = 0; /* data0 to be programmed to 0 for first set */ + mutex_lock(&dev_priv->rps.hw_lock); + ret = sandybridge_pcode_read(dev_priv, + GEN9_PCODE_READ_MEM_LATENCY, + &val); + mutex_unlock(&dev_priv->rps.hw_lock); + + if (ret) { + DRM_ERROR("SKL Mailbox read error = %d\n", ret); + return; + } + + wm[0] = val & GEN9_MEM_LATENCY_LEVEL_MASK; + wm[1] = (val >> GEN9_MEM_LATENCY_LEVEL_1_5_SHIFT) & + GEN9_MEM_LATENCY_LEVEL_MASK; + wm[2] = (val >> GEN9_MEM_LATENCY_LEVEL_2_6_SHIFT) & + GEN9_MEM_LATENCY_LEVEL_MASK; + wm[3] = (val >> GEN9_MEM_LATENCY_LEVEL_3_7_SHIFT) & + GEN9_MEM_LATENCY_LEVEL_MASK; + + /* read the second set of memory latencies[4:7] */ + val = 1; /* data0 to be programmed to 1 for second set */ + mutex_lock(&dev_priv->rps.hw_lock); + ret = sandybridge_pcode_read(dev_priv, + GEN9_PCODE_READ_MEM_LATENCY, + &val); + mutex_unlock(&dev_priv->rps.hw_lock); + if (ret) { + DRM_ERROR("SKL Mailbox read error = %d\n", ret); + return; + } + + wm[4] = val & GEN9_MEM_LATENCY_LEVEL_MASK; + wm[5] = (val >> GEN9_MEM_LATENCY_LEVEL_1_5_SHIFT) & + GEN9_MEM_LATENCY_LEVEL_MASK; + wm[6] = (val >> GEN9_MEM_LATENCY_LEVEL_2_6_SHIFT) & + GEN9_MEM_LATENCY_LEVEL_MASK; + wm[7] = (val >> GEN9_MEM_LATENCY_LEVEL_3_7_SHIFT) & + GEN9_MEM_LATENCY_LEVEL_MASK; + + } else if (IS_HASWELL(dev) || IS_BROADWELL(dev)) { uint64_t sskpd = I915_READ64(MCH_SSKPD); wm[0] = (sskpd >> 56) & 0xFF; @@ -2323,7 +2368,9 @@ static void intel_fixup_cur_wm_latency(struct drm_device *dev, uint16_t wm[5]) int ilk_wm_max_level(const struct drm_device *dev) { /* how many WM levels are we expecting */ - if (IS_HASWELL(dev) || IS_BROADWELL(dev)) + if (IS_GEN9(dev)) + return 7; + else if (IS_HASWELL(dev) || IS_BROADWELL(dev)) return 4; else if (INTEL_INFO(dev)->gen >= 6) return 3; @@ -2333,7 +2380,7 @@ int ilk_wm_max_level(const struct drm_device *dev) static void intel_print_wm_latency(struct drm_device *dev, const char *name, - const uint16_t wm[5]) + const uint16_t wm[8]) { int level, max_level = ilk_wm_max_level(dev); @@ -2346,8 +2393,13 @@ static void intel_print_wm_latency(struct drm_device *dev, continue; } - /* WM1+ latency values in 0.5us units */ - if (level > 0) + /* + * - latencies are in us on gen9. + * - before then, WM1+ latency values are in 0.5us units + */ + if (IS_GEN9(dev)) + latency *= 10; + else if (level > 0) latency *= 5; DRM_DEBUG_KMS("%s WM%d latency %u (%u.%u usec)\n", @@ -2415,6 +2467,14 @@ static void ilk_setup_wm_latency(struct drm_device *dev) snb_wm_latency_quirk(dev); } +static void skl_setup_wm_latency(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + intel_read_wm_latency(dev, dev_priv->wm.skl_latency); + intel_print_wm_latency(dev, "Gen9 Plane", dev_priv->wm.skl_latency); +} + static void ilk_compute_wm_parameters(struct drm_crtc *crtc, struct ilk_pipe_wm_parameters *p) { @@ -6127,6 +6187,8 @@ void intel_init_pm(struct drm_device *dev) /* For FIFO watermark updates */ if (IS_GEN9(dev)) { + skl_setup_wm_latency(dev); + dev_priv->display.init_clock_gating = gen9_init_clock_gating; } else if (HAS_PCH_SPLIT(dev)) { ilk_setup_wm_latency(dev); @@ -6219,6 +6281,8 @@ int sandybridge_pcode_read(struct drm_i915_private *dev_priv, u8 mbox, u32 *val) } I915_WRITE(GEN6_PCODE_DATA, *val); + if (INTEL_INFO(dev_priv)->gen >= 9) + I915_WRITE(GEN9_PCODE_DATA1, 0); I915_WRITE(GEN6_PCODE_MAILBOX, GEN6_PCODE_READY | mbox); if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0, -- cgit v1.2.3 From fae1267df8a14140544204c65258867d72f287bb Mon Sep 17 00:00:00 2001 From: Pradeep Bhat Date: Tue, 4 Nov 2014 17:06:39 +0000 Subject: drm/i915/skl: Register definitions and macros for SKL Watermark regs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch defines SKL specific PLANE_WM Watermark registers. It also defines macros to get the addresses of different LP levels within a pipe. v2: Reworked the register definitions and associated macros to make it more generic and be able to use for_each_pipe in values computation. Incorporated Damien's review comments and indentation. v3: Added default values for lines and blocks. Provided mask for blocks. v4: Prefix intermedidate (internal-only) macros with _ (Ville) v5: Remove the lines and block defaults value (Ville) Reviewed-by: Ville Syrjälä (v4) Signed-off-by: Pradeep Bhat Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index db7d8fd5b7f5..ccbaeb35d695 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -4102,6 +4102,41 @@ enum punit_power_well { #define I965_CURSOR_MAX_WM 32 #define I965_CURSOR_DFT_WM 8 +/* Watermark register definitions for SKL */ +#define CUR_WM_A_0 0x70140 +#define CUR_WM_B_0 0x71140 +#define PLANE_WM_1_A_0 0x70240 +#define PLANE_WM_1_B_0 0x71240 +#define PLANE_WM_2_A_0 0x70340 +#define PLANE_WM_2_B_0 0x71340 +#define PLANE_WM_TRANS_1_A_0 0x70268 +#define PLANE_WM_TRANS_1_B_0 0x71268 +#define PLANE_WM_TRANS_2_A_0 0x70368 +#define PLANE_WM_TRANS_2_B_0 0x71368 +#define CUR_WM_TRANS_A_0 0x70168 +#define CUR_WM_TRANS_B_0 0x71168 +#define PLANE_WM_EN (1 << 31) +#define PLANE_WM_LINES_SHIFT 14 +#define PLANE_WM_LINES_MASK 0x1f +#define PLANE_WM_BLOCKS_MASK 0x3ff + +#define CUR_WM_0(pipe) _PIPE(pipe, CUR_WM_A_0, CUR_WM_B_0) +#define CUR_WM(pipe, level) (CUR_WM_0(pipe) + ((4) * (level))) +#define CUR_WM_TRANS(pipe) _PIPE(pipe, CUR_WM_TRANS_A_0, CUR_WM_TRANS_B_0) + +#define _PLANE_WM_1(pipe) _PIPE(pipe, PLANE_WM_1_A_0, PLANE_WM_1_B_0) +#define _PLANE_WM_2(pipe) _PIPE(pipe, PLANE_WM_2_A_0, PLANE_WM_2_B_0) +#define _PLANE_WM_BASE(pipe, plane) \ + _PLANE(plane, _PLANE_WM_1(pipe), _PLANE_WM_2(pipe)) +#define PLANE_WM(pipe, plane, level) \ + (_PLANE_WM_BASE(pipe, plane) + ((4) * (level))) +#define _PLANE_WM_TRANS_1(pipe) \ + _PIPE(pipe, PLANE_WM_TRANS_1_A_0, PLANE_WM_TRANS_1_B_0) +#define _PLANE_WM_TRANS_2(pipe) \ + _PIPE(pipe, PLANE_WM_TRANS_2_A_0, PLANE_WM_TRANS_2_B_0) +#define PLANE_WM_TRANS(pipe, plane) \ + _PLANE(plane, _PLANE_WM_TRANS_1(pipe), _PLANE_WM_TRANS_2(pipe)) + /* define the Watermark register on Ironlake */ #define WM0_PIPEA_ILK 0x45100 #define WM0_PIPE_PLANE_MASK (0xffff<<16) -- cgit v1.2.3 From 2ac96d2a6e102ec64a568a470a6d9c50b9c02e59 Mon Sep 17 00:00:00 2001 From: Pradeep Bhat Date: Tue, 4 Nov 2014 17:06:40 +0000 Subject: drm/i915/skl: Definition of SKL WM param structs for pipe/plane MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch defines the structures needed for computation of watermarks of pipes and planes for SKL. v2: Incorporated Damien's review comments and removed unused fields in structs for future features like rotation, drrs and scaling. The skl_wm_values struct is now made more generic across planes and cursor planes for all pipes. v3: implemented the plane/cursor split. v4: Change the wm union back to a structure (Ville, Daniel) Reviewed-by: Ville Syrjälä Signed-off-by: Pradeep Bhat Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 18 ++++++++++++++++++ drivers/gpu/drm/i915/intel_drv.h | 8 ++++++++ drivers/gpu/drm/i915/intel_pm.c | 8 ++++++++ 3 files changed, 34 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 05fcbe5c6e38..19bc2d057a87 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1387,6 +1387,24 @@ struct ilk_wm_values { enum intel_ddb_partitioning partitioning; }; +struct skl_wm_values { + bool dirty[I915_MAX_PIPES]; + uint32_t wm_linetime[I915_MAX_PIPES]; + uint32_t plane[I915_MAX_PIPES][I915_MAX_PLANES][8]; + uint32_t cursor[I915_MAX_PIPES][8]; + uint32_t plane_trans[I915_MAX_PIPES][I915_MAX_PLANES]; + uint32_t cursor_trans[I915_MAX_PIPES]; +}; + +struct skl_wm_level { + bool plane_en[I915_MAX_PLANES]; + uint16_t plane_res_b[I915_MAX_PLANES]; + uint8_t plane_res_l[I915_MAX_PLANES]; + bool cursor_en; + uint16_t cursor_res_b; + uint8_t cursor_res_l; +}; + /* * This struct helps tracking the state needed for runtime PM, which puts the * device in PCI D3 state. Notice that when this happens, nothing on the diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index c8ddde68a24e..446be27ce76f 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -412,6 +412,12 @@ struct intel_mmio_flip { struct work_struct work; }; +struct skl_pipe_wm { + struct skl_wm_level wm[8]; + struct skl_wm_level trans_wm; + uint32_t linetime; +}; + struct intel_crtc { struct drm_crtc base; enum pipe pipe; @@ -459,6 +465,8 @@ struct intel_crtc { struct { /* watermarks currently being used */ struct intel_pipe_wm active; + /* SKL wm values currently in use */ + struct skl_pipe_wm skl_active; } wm; int scanline_offset; diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 761c884211c5..ca2080bf486f 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -1960,6 +1960,14 @@ static uint32_t ilk_wm_fbc(uint32_t pri_val, uint32_t horiz_pixels, return DIV_ROUND_UP(pri_val * 64, horiz_pixels * bytes_per_pixel) + 2; } +struct skl_pipe_wm_parameters { + bool active; + uint32_t pipe_htotal; + uint32_t pixel_rate; /* in KHz */ + struct intel_plane_wm_parameters plane[I915_MAX_PLANES]; + struct intel_plane_wm_parameters cursor; +}; + struct ilk_pipe_wm_parameters { bool active; uint32_t pipe_htotal; -- cgit v1.2.3 From c193924e9cef42995cbd204253520efc9d8ad1ba Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Tue, 4 Nov 2014 17:06:41 +0000 Subject: drm/i915/skl: Add DDB allocation management structures MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We now need to allocate space in the DDB for planes being scanned out ourselves. The data structure to represent an allocation mirrors what we'll need to write in the registers later on: (start, end). We add that allocation datat to the skl_wm_values structure as part of the values to program the hardware with. v2: Split planes and cursor for consistency. v3: Make the skl_ddb_entry_size() parameter const Reviewed-by: Ville Syrjälä Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 19bc2d057a87..aa8607a9e49c 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1387,8 +1387,27 @@ struct ilk_wm_values { enum intel_ddb_partitioning partitioning; }; +struct skl_ddb_entry { + uint16_t start, end; /* in number of blocks */ +}; + +static inline uint16_t skl_ddb_entry_size(const struct skl_ddb_entry *entry) +{ + /* end not set, clearly no allocation here. start can be 0 though */ + if (entry->end == 0) + return 0; + + return entry->end - entry->start + 1; +} + +struct skl_ddb_allocation { + struct skl_ddb_entry plane[I915_MAX_PIPES][I915_MAX_PLANES]; + struct skl_ddb_entry cursor[I915_MAX_PIPES]; +}; + struct skl_wm_values { bool dirty[I915_MAX_PIPES]; + struct skl_ddb_allocation ddb; uint32_t wm_linetime[I915_MAX_PIPES]; uint32_t plane[I915_MAX_PIPES][I915_MAX_PLANES][8]; uint32_t cursor[I915_MAX_PIPES][8]; -- cgit v1.2.3 From 2d41c0b59afcdd87d689212cdb929709ffc27d08 Mon Sep 17 00:00:00 2001 From: Pradeep Bhat Date: Tue, 4 Nov 2014 17:06:42 +0000 Subject: drm/i915/skl: SKL Watermark Computation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch implements the watermark algorithm and its necessary functions. Two function pointers skl_update_wm and skl_update_sprite_wm are provided. The skl_update_wm will update the watermarks for the crtc provided as an argument and then checks for change in DDB allocation for other active pipes and recomputes the watermarks for those Pipes and planes as well. Finally it does the register programming for all dirty pipes. The trigger of the Watermark double buffer registers will have to be once the plane configurations are done by the caller. v2: fixed the divide-by-0 error in the results computation func. Also reworked the PLANE_WM register values computation func to make it more compact. Incorporated all other review comments from Damien. v3: Changed the skl_compute_plane_wm function to now return success or failure. Also the result blocks and lines are computed here instead of in skl_compute_wm_results function. v4: Adjust skl_ddb_alloc_changed() to the new planes/cursor split (Damien) v5: Reworked the affected functions to implement new plane/cursor split. v6: Rework the logic that triggers the DDB allocation and WM computation of skl_update_other_pipe_wm() to not depend on non-computed DDB values. Always give a valid cursor_width (at boot it's 0) to keep the invariant that we consider the cursor plane always enabled. Otherwise we end up dividing by 0 in skl_compute_plane_wm() (Damien Lespiau) v7: Spell out allocation skl_ddb_ functions should have the ddb as first argument Make the skl_ddb_alloc_changed() parameters const (Damien) v8: Rebase on top of the crtc->primary changes v9: Split the staging results structure to not exceed the 1Kb stack allocation in skl_update_wm() v10: Make skl_pipe_pixel_rate() take a pointer to the pipe config Add a comment about overflow considerations for skl_wm_method1() Various additions of const Various use of sizeof(variable) instead of sizeof(type) Various move of variable definitons to a narrower scope Zero initialize some stack allocated structures to make sure we don't have garbage in case we don't write all the values (Ville) v11: Remove non-necessary default number of blocks/lines when the plane is disabled (Ville) Reviewed-by: Ville Syrjälä Signed-off-by: Pradeep Bhat Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 12 +- drivers/gpu/drm/i915/intel_pm.c | 422 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 433 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index aa8607a9e49c..fbe18aed254d 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1722,8 +1722,18 @@ struct drm_i915_private { */ uint16_t skl_latency[8]; + /* + * The skl_wm_values structure is a bit too big for stack + * allocation, so we keep the staging struct where we store + * intermediate results here instead. + */ + struct skl_wm_values skl_results; + /* current hardware state */ - struct ilk_wm_values hw; + union { + struct ilk_wm_values hw; + struct skl_wm_values skl_hw; + }; } wm; struct i915_runtime_pm pm; diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index ca2080bf486f..5500c5343e0e 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2973,6 +2973,426 @@ static bool ilk_disable_lp_wm(struct drm_device *dev) return _ilk_disable_lp_wm(dev_priv, WM_DIRTY_LP_ALL); } +static uint32_t skl_pipe_pixel_rate(const struct intel_crtc_config *config) +{ + /* TODO: Take into account the scalers once we support them */ + return config->adjusted_mode.crtc_clock; +} + +/* + * The max latency should be 257 (max the punit can code is 255 and we add 2us + * for the read latency) and bytes_per_pixel should always be <= 8, so that + * should allow pixel_rate up to ~2 GHz which seems sufficient since max + * 2xcdclk is 1350 MHz and the pixel rate should never exceed that. +*/ +static uint32_t skl_wm_method1(uint32_t pixel_rate, uint8_t bytes_per_pixel, + uint32_t latency) +{ + uint32_t wm_intermediate_val, ret; + + if (latency == 0) + return UINT_MAX; + + wm_intermediate_val = latency * pixel_rate * bytes_per_pixel; + ret = DIV_ROUND_UP(wm_intermediate_val, 1000); + + return ret; +} + +static uint32_t skl_wm_method2(uint32_t pixel_rate, uint32_t pipe_htotal, + uint32_t horiz_pixels, uint8_t bytes_per_pixel, + uint32_t latency) +{ + uint32_t ret, plane_bytes_per_line, wm_intermediate_val; + + if (latency == 0) + return UINT_MAX; + + plane_bytes_per_line = horiz_pixels * bytes_per_pixel; + wm_intermediate_val = latency * pixel_rate; + ret = DIV_ROUND_UP(wm_intermediate_val, pipe_htotal * 1000) * + plane_bytes_per_line; + + return ret; +} + +static void skl_compute_transition_wm(struct drm_crtc *crtc, + struct skl_pipe_wm_parameters *params, + struct skl_pipe_wm *pipe_wm) +{ + /* + * For now it is suggested to use the LP0 wm val of corresponding + * plane as transition wm val. This is done while computing results. + */ + if (!params->active) + return; +} + +static uint32_t +skl_compute_linetime_wm(struct drm_crtc *crtc, struct skl_pipe_wm_parameters *p) +{ + if (!intel_crtc_active(crtc)) + return 0; + + return DIV_ROUND_UP(8 * p->pipe_htotal * 1000, p->pixel_rate); + +} + +static bool skl_ddb_allocation_changed(const struct skl_ddb_allocation *new_ddb, + const struct intel_crtc *intel_crtc) +{ + struct drm_device *dev = intel_crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + const struct skl_ddb_allocation *cur_ddb = &dev_priv->wm.skl_hw.ddb; + enum pipe pipe = intel_crtc->pipe; + + if (memcmp(new_ddb->plane[pipe], cur_ddb->plane[pipe], + sizeof(new_ddb->plane[pipe]))) + return true; + + if (memcmp(&new_ddb->cursor[pipe], &cur_ddb->cursor[pipe], + sizeof(new_ddb->cursor[pipe]))) + return true; + + return false; +} + +static void skl_compute_wm_global_parameters(struct drm_device *dev, + struct intel_wm_config *config) +{ + struct drm_crtc *crtc; + struct drm_plane *plane; + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) + config->num_pipes_active += intel_crtc_active(crtc); + + /* FIXME: I don't think we need those two global parameters on SKL */ + list_for_each_entry(plane, &dev->mode_config.plane_list, head) { + struct intel_plane *intel_plane = to_intel_plane(plane); + + config->sprites_enabled |= intel_plane->wm.enabled; + config->sprites_scaled |= intel_plane->wm.scaled; + } +} + +static void skl_compute_wm_pipe_parameters(struct drm_crtc *crtc, + struct skl_pipe_wm_parameters *p) +{ + struct drm_device *dev = crtc->dev; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + enum pipe pipe = intel_crtc->pipe; + struct drm_plane *plane; + int i = 1; /* Index for sprite planes start */ + + p->active = intel_crtc_active(crtc); + if (p->active) { + p->pipe_htotal = intel_crtc->config.adjusted_mode.crtc_htotal; + p->pixel_rate = skl_pipe_pixel_rate(&intel_crtc->config); + + /* + * For now, assume primary and cursor planes are always enabled. + */ + p->plane[0].enabled = true; + p->plane[0].bytes_per_pixel = + crtc->primary->fb->bits_per_pixel / 8; + p->plane[0].horiz_pixels = intel_crtc->config.pipe_src_w; + p->plane[0].vert_pixels = intel_crtc->config.pipe_src_h; + + p->cursor.enabled = true; + p->cursor.bytes_per_pixel = 4; + p->cursor.horiz_pixels = intel_crtc->cursor_width ? + intel_crtc->cursor_width : 64; + } + + list_for_each_entry(plane, &dev->mode_config.plane_list, head) { + struct intel_plane *intel_plane = to_intel_plane(plane); + + if (intel_plane->pipe == pipe) + p->plane[i++] = intel_plane->wm; + } +} + +static bool skl_compute_plane_wm(struct skl_pipe_wm_parameters *p, + struct intel_plane_wm_parameters *p_params, + uint16_t max_page_buff_alloc, + uint32_t mem_value, + uint16_t *res_blocks, /* out */ + uint8_t *res_lines /* out */) +{ + uint32_t method1, method2, plane_bytes_per_line; + uint32_t result_bytes; + + if (!p->active || !p_params->enabled) + return false; + + method1 = skl_wm_method1(p->pixel_rate, + p_params->bytes_per_pixel, + mem_value); + method2 = skl_wm_method2(p->pixel_rate, + p->pipe_htotal, + p_params->horiz_pixels, + p_params->bytes_per_pixel, + mem_value); + + plane_bytes_per_line = p_params->horiz_pixels * + p_params->bytes_per_pixel; + + /* For now xtile and linear */ + if (((max_page_buff_alloc * 512) / plane_bytes_per_line) >= 1) + result_bytes = min(method1, method2); + else + result_bytes = method1; + + *res_blocks = DIV_ROUND_UP(result_bytes, 512) + 1; + *res_lines = DIV_ROUND_UP(result_bytes, plane_bytes_per_line); + + return true; +} + +static void skl_compute_wm_level(const struct drm_i915_private *dev_priv, + struct skl_ddb_allocation *ddb, + struct skl_pipe_wm_parameters *p, + enum pipe pipe, + int level, + int num_planes, + struct skl_wm_level *result) +{ + uint16_t latency = dev_priv->wm.skl_latency[level]; + uint16_t ddb_blocks; + int i; + + for (i = 0; i < num_planes; i++) { + ddb_blocks = skl_ddb_entry_size(&ddb->plane[pipe][i]); + + result->plane_en[i] = skl_compute_plane_wm(p, &p->plane[i], + ddb_blocks, + latency, + &result->plane_res_b[i], + &result->plane_res_l[i]); + } + + ddb_blocks = skl_ddb_entry_size(&ddb->cursor[pipe]); + result->cursor_en = skl_compute_plane_wm(p, &p->cursor, ddb_blocks, + latency, &result->cursor_res_b, + &result->cursor_res_l); +} + +static void skl_compute_pipe_wm(struct drm_crtc *crtc, + struct skl_ddb_allocation *ddb, + struct skl_pipe_wm_parameters *params, + struct skl_pipe_wm *pipe_wm) +{ + struct drm_device *dev = crtc->dev; + const struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int level, max_level = ilk_wm_max_level(dev); + + for (level = 0; level <= max_level; level++) { + skl_compute_wm_level(dev_priv, ddb, params, intel_crtc->pipe, + level, intel_num_planes(intel_crtc), + &pipe_wm->wm[level]); + } + pipe_wm->linetime = skl_compute_linetime_wm(crtc, params); + + skl_compute_transition_wm(crtc, params, pipe_wm); +} + +static void skl_compute_wm_results(struct drm_device *dev, + struct skl_pipe_wm_parameters *p, + struct skl_pipe_wm *p_wm, + struct skl_wm_values *r, + struct intel_crtc *intel_crtc) +{ + int level, max_level = ilk_wm_max_level(dev); + enum pipe pipe = intel_crtc->pipe; + + for (level = 0; level <= max_level; level++) { + uint16_t ddb_blocks; + uint32_t temp; + int i; + + for (i = 0; i < intel_num_planes(intel_crtc); i++) { + temp = 0; + ddb_blocks = skl_ddb_entry_size(&r->ddb.plane[pipe][i]); + + if ((p_wm->wm[level].plane_res_b[i] > ddb_blocks) || + (p_wm->wm[level].plane_res_l[i] > 31)) + p_wm->wm[level].plane_en[i] = false; + + temp |= p_wm->wm[level].plane_res_l[i] << + PLANE_WM_LINES_SHIFT; + temp |= p_wm->wm[level].plane_res_b[i]; + if (p_wm->wm[level].plane_en[i]) + temp |= PLANE_WM_EN; + + r->plane[pipe][i][level] = temp; + /* Use the LP0 WM value for transition WM for now. */ + if (level == 0) + r->plane_trans[pipe][i] = temp; + } + + temp = 0; + ddb_blocks = skl_ddb_entry_size(&r->ddb.cursor[pipe]); + + if ((p_wm->wm[level].cursor_res_b > ddb_blocks) || + (p_wm->wm[level].cursor_res_l > 31)) + p_wm->wm[level].cursor_en = false; + + temp |= p_wm->wm[level].cursor_res_l << PLANE_WM_LINES_SHIFT; + temp |= p_wm->wm[level].cursor_res_b; + + if (p_wm->wm[level].cursor_en) + temp |= PLANE_WM_EN; + + r->cursor[pipe][level] = temp; + /* Use the LP0 WM value for transition WM for now. */ + if (level == 0) + r->cursor_trans[pipe] = temp; + + } + + r->wm_linetime[pipe] = p_wm->linetime; +} + +static void skl_write_wm_values(struct drm_i915_private *dev_priv, + const struct skl_wm_values *new) +{ + struct drm_device *dev = dev_priv->dev; + struct intel_crtc *crtc; + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head) { + int i, level, max_level = ilk_wm_max_level(dev); + enum pipe pipe = crtc->pipe; + + if (new->dirty[pipe]) { + I915_WRITE(PIPE_WM_LINETIME(pipe), + new->wm_linetime[pipe]); + + for (level = 0; level <= max_level; level++) { + for (i = 0; i < intel_num_planes(crtc); i++) + I915_WRITE(PLANE_WM(pipe, i, level), + new->plane[pipe][i][level]); + I915_WRITE(CUR_WM(pipe, level), + new->cursor[pipe][level]); + } + for (i = 0; i < intel_num_planes(crtc); i++) + I915_WRITE(PLANE_WM_TRANS(pipe, i), + new->plane_trans[pipe][i]); + I915_WRITE(CUR_WM_TRANS(pipe), new->cursor_trans[pipe]); + } + } + + dev_priv->wm.skl_hw = *new; +} + +static bool skl_update_pipe_wm(struct drm_crtc *crtc, + struct skl_pipe_wm_parameters *params, + struct intel_wm_config *config, + struct skl_ddb_allocation *ddb, /* out */ + struct skl_pipe_wm *pipe_wm /* out */) +{ + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + + skl_compute_wm_pipe_parameters(crtc, params); + skl_compute_pipe_wm(crtc, ddb, params, pipe_wm); + + if (!memcmp(&intel_crtc->wm.skl_active, pipe_wm, sizeof(*pipe_wm))) + return false; + + intel_crtc->wm.skl_active = *pipe_wm; + return true; +} + +static void skl_update_other_pipe_wm(struct drm_device *dev, + struct drm_crtc *crtc, + struct intel_wm_config *config, + struct skl_wm_values *r) +{ + struct intel_crtc *intel_crtc; + struct intel_crtc *this_crtc = to_intel_crtc(crtc); + + /* + * If the WM update hasn't changed the allocation for this_crtc (the + * crtc we are currently computing the new WM values for), other + * enabled crtcs will keep the same allocation and we don't need to + * recompute anything for them. + */ + if (!skl_ddb_allocation_changed(&r->ddb, this_crtc)) + return; + + /* + * Otherwise, because of this_crtc being freshly enabled/disabled, the + * other active pipes need new DDB allocation and WM values. + */ + list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list, + base.head) { + struct skl_pipe_wm_parameters params = {}; + struct skl_pipe_wm pipe_wm = {}; + bool wm_changed; + + if (this_crtc->pipe == intel_crtc->pipe) + continue; + + if (!intel_crtc->active) + continue; + + wm_changed = skl_update_pipe_wm(&intel_crtc->base, + ¶ms, config, + &r->ddb, &pipe_wm); + + /* + * If we end up re-computing the other pipe WM values, it's + * because it was really needed, so we expect the WM values to + * be different. + */ + WARN_ON(!wm_changed); + + skl_compute_wm_results(dev, ¶ms, &pipe_wm, r, intel_crtc); + r->dirty[intel_crtc->pipe] = true; + } +} + +static void skl_update_wm(struct drm_crtc *crtc) +{ + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct skl_pipe_wm_parameters params = {}; + struct skl_wm_values *results = &dev_priv->wm.skl_results; + struct skl_pipe_wm pipe_wm = {}; + struct intel_wm_config config = {}; + + memset(results, 0, sizeof(*results)); + + skl_compute_wm_global_parameters(dev, &config); + + if (!skl_update_pipe_wm(crtc, ¶ms, &config, + &results->ddb, &pipe_wm)) + return; + + skl_compute_wm_results(dev, ¶ms, &pipe_wm, results, intel_crtc); + results->dirty[intel_crtc->pipe] = true; + + skl_update_other_pipe_wm(dev, crtc, &config, results); + skl_write_wm_values(dev_priv, results); +} + +static void +skl_update_sprite_wm(struct drm_plane *plane, struct drm_crtc *crtc, + uint32_t sprite_width, uint32_t sprite_height, + int pixel_size, bool enabled, bool scaled) +{ + struct intel_plane *intel_plane = to_intel_plane(plane); + + intel_plane->wm.enabled = enabled; + intel_plane->wm.scaled = scaled; + intel_plane->wm.horiz_pixels = sprite_width; + intel_plane->wm.vert_pixels = sprite_height; + intel_plane->wm.bytes_per_pixel = pixel_size; + + skl_update_wm(crtc); +} + static void ilk_update_wm(struct drm_crtc *crtc) { struct intel_crtc *intel_crtc = to_intel_crtc(crtc); @@ -6198,6 +6618,8 @@ void intel_init_pm(struct drm_device *dev) skl_setup_wm_latency(dev); dev_priv->display.init_clock_gating = gen9_init_clock_gating; + dev_priv->display.update_wm = skl_update_wm; + dev_priv->display.update_sprite_wm = skl_update_sprite_wm; } else if (HAS_PCH_SPLIT(dev)) { ilk_setup_wm_latency(dev); -- cgit v1.2.3 From b9cec07585cf1f554810097b8088b8e1f3f5137b Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Tue, 4 Nov 2014 17:06:43 +0000 Subject: drm/i915/skl: Allocate DDB portions for display planes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit v2: Fix the 3rd plane/cursor logic (Pradeep Bhat) v3: Fix one-by-one error in the DDB allocation code v4: Rebase on top of the skl_pipe_pixel_rate() argument change v5: Replace the available/start/end output parameters of skl_ddb_get_pipe_allocation_limits() by a single ddb entry constify a few arguments Make nth_active_pipe 0 indexed Use sizeof(variable) instead of sizeof(type) (Ville) v6: Use the for_each_crtc() macro instead of list_for_each_entry() Reviewed-by: Ville Syrjälä Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 148 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 5500c5343e0e..b5c7c4b4c091 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2973,6 +2973,153 @@ static bool ilk_disable_lp_wm(struct drm_device *dev) return _ilk_disable_lp_wm(dev_priv, WM_DIRTY_LP_ALL); } +/* + * On gen9, we need to allocate Display Data Buffer (DDB) portions to the + * different active planes. + */ + +#define SKL_DDB_SIZE 896 /* in blocks */ + +static void +skl_ddb_get_pipe_allocation_limits(struct drm_device *dev, + struct drm_crtc *for_crtc, + const struct intel_wm_config *config, + const struct skl_pipe_wm_parameters *params, + struct skl_ddb_entry *alloc /* out */) +{ + struct drm_crtc *crtc; + unsigned int pipe_size, ddb_size; + int nth_active_pipe; + + if (!params->active) { + alloc->start = 0; + alloc->end = 0; + return; + } + + ddb_size = SKL_DDB_SIZE; + + ddb_size -= 4; /* 4 blocks for bypass path allocation */ + + nth_active_pipe = 0; + for_each_crtc(dev, crtc) { + if (!intel_crtc_active(crtc)) + continue; + + if (crtc == for_crtc) + break; + + nth_active_pipe++; + } + + pipe_size = ddb_size / config->num_pipes_active; + alloc->start = nth_active_pipe * ddb_size / config->num_pipes_active; + alloc->end = alloc->start + pipe_size - 1; +} + +static unsigned int skl_cursor_allocation(const struct intel_wm_config *config) +{ + if (config->num_pipes_active == 1) + return 32; + + return 8; +} + +static unsigned int +skl_plane_relative_data_rate(const struct intel_plane_wm_parameters *p) +{ + return p->horiz_pixels * p->vert_pixels * p->bytes_per_pixel; +} + +/* + * We don't overflow 32 bits. Worst case is 3 planes enabled, each fetching + * a 8192x4096@32bpp framebuffer: + * 3 * 4096 * 8192 * 4 < 2^32 + */ +static unsigned int +skl_get_total_relative_data_rate(struct intel_crtc *intel_crtc, + const struct skl_pipe_wm_parameters *params) +{ + unsigned int total_data_rate = 0; + int plane; + + for (plane = 0; plane < intel_num_planes(intel_crtc); plane++) { + const struct intel_plane_wm_parameters *p; + + p = ¶ms->plane[plane]; + if (!p->enabled) + continue; + + total_data_rate += skl_plane_relative_data_rate(p); + } + + return total_data_rate; +} + +static void +skl_allocate_pipe_ddb(struct drm_crtc *crtc, + const struct intel_wm_config *config, + const struct skl_pipe_wm_parameters *params, + struct skl_ddb_allocation *ddb /* out */) +{ + struct drm_device *dev = crtc->dev; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + enum pipe pipe = intel_crtc->pipe; + struct skl_ddb_entry alloc; + uint16_t alloc_size, start, cursor_blocks; + unsigned int total_data_rate; + int plane; + + skl_ddb_get_pipe_allocation_limits(dev, crtc, config, params, &alloc); + alloc_size = skl_ddb_entry_size(&alloc); + if (alloc_size == 0) { + memset(ddb->plane[pipe], 0, sizeof(ddb->plane[pipe])); + memset(&ddb->cursor[pipe], 0, sizeof(ddb->cursor[pipe])); + return; + } + + cursor_blocks = skl_cursor_allocation(config); + ddb->cursor[pipe].start = alloc.end - cursor_blocks + 1; + ddb->cursor[pipe].end = alloc.end; + + alloc_size -= cursor_blocks; + alloc.end -= cursor_blocks; + + /* + * Each active plane get a portion of the remaining space, in + * proportion to the amount of data they need to fetch from memory. + * + * FIXME: we may not allocate every single block here. + */ + total_data_rate = skl_get_total_relative_data_rate(intel_crtc, params); + + start = alloc.start; + for (plane = 0; plane < intel_num_planes(intel_crtc); plane++) { + const struct intel_plane_wm_parameters *p; + unsigned int data_rate; + uint16_t plane_blocks; + + p = ¶ms->plane[plane]; + if (!p->enabled) + continue; + + data_rate = skl_plane_relative_data_rate(p); + + /* + * promote the expression to 64 bits to avoid overflowing, the + * result is < available as data_rate / total_data_rate < 1 + */ + plane_blocks = div_u64((uint64_t)alloc_size * data_rate, + total_data_rate); + + ddb->plane[pipe][plane].start = start; + ddb->plane[pipe][plane].end = start + plane_blocks - 1; + + start += plane_blocks; + } + +} + static uint32_t skl_pipe_pixel_rate(const struct intel_crtc_config *config) { /* TODO: Take into account the scalers once we support them */ @@ -3294,6 +3441,7 @@ static bool skl_update_pipe_wm(struct drm_crtc *crtc, struct intel_crtc *intel_crtc = to_intel_crtc(crtc); skl_compute_wm_pipe_parameters(crtc, params); + skl_allocate_pipe_ddb(crtc, config, params, ddb); skl_compute_pipe_wm(crtc, ddb, params, pipe_wm); if (!memcmp(&intel_crtc->wm.skl_active, pipe_wm, sizeof(*pipe_wm))) -- cgit v1.2.3 From 8211bd5bdf5e1cf860616138ed71600a24a827bd Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Tue, 4 Nov 2014 17:06:44 +0000 Subject: drm/i915/skl: Program the DDB allocation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit v2: Adapt to the planes/cursor split Reviewed-by: Ville Syrjälä Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 16 ++++++++++++++++ drivers/gpu/drm/i915/intel_pm.c | 9 +++++++++ 2 files changed, 25 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index ccbaeb35d695..ea22e09bd4c5 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -4696,6 +4696,8 @@ enum punit_power_well { #define _PLANE_KEYMSK_2_A 0x70298 #define _PLANE_KEYMAX_1_A 0x701a0 #define _PLANE_KEYMAX_2_A 0x702a0 +#define _PLANE_BUF_CFG_1_A 0x7027c +#define _PLANE_BUF_CFG_2_A 0x7037c #define _PLANE_CTL_1_B 0x71180 #define _PLANE_CTL_2_B 0x71280 @@ -4773,6 +4775,20 @@ enum punit_power_well { #define PLANE_KEYMAX(pipe, plane) \ _PLANE(plane, _PLANE_KEYMAX_1(pipe), _PLANE_KEYMAX_2(pipe)) +#define _PLANE_BUF_CFG_1_B 0x7127c +#define _PLANE_BUF_CFG_2_B 0x7137c +#define _PLANE_BUF_CFG_1(pipe) \ + _PIPE(pipe, _PLANE_BUF_CFG_1_A, _PLANE_BUF_CFG_1_B) +#define _PLANE_BUF_CFG_2(pipe) \ + _PIPE(pipe, _PLANE_BUF_CFG_2_A, _PLANE_BUF_CFG_2_B) +#define PLANE_BUF_CFG(pipe, plane) \ + _PLANE(plane, _PLANE_BUF_CFG_1(pipe), _PLANE_BUF_CFG_2(pipe)) + +/* SKL new cursor registers */ +#define _CUR_BUF_CFG_A 0x7017c +#define _CUR_BUF_CFG_B 0x7117c +#define CUR_BUF_CFG(pipe) _PIPE(pipe, _CUR_BUF_CFG_A, _CUR_BUF_CFG_B) + /* VBIOS regs */ #define VGACNTRL 0x71400 # define VGA_DISP_DISABLE (1 << 31) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index b5c7c4b4c091..c2f1441138be 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3426,6 +3426,15 @@ static void skl_write_wm_values(struct drm_i915_private *dev_priv, I915_WRITE(PLANE_WM_TRANS(pipe, i), new->plane_trans[pipe][i]); I915_WRITE(CUR_WM_TRANS(pipe), new->cursor_trans[pipe]); + + for (i = 0; i < intel_num_planes(crtc); i++) + I915_WRITE(PLANE_BUF_CFG(pipe, i), + new->ddb.plane[pipe][i].end << 16 | + new->ddb.plane[pipe][i].start); + + I915_WRITE(CUR_BUF_CFG(pipe), + new->ddb.cursor[pipe].end << 16 | + new->ddb.cursor[pipe].start); } } -- cgit v1.2.3 From 3078999f2a4ee4aaabf9df2166e4e43581bb357a Mon Sep 17 00:00:00 2001 From: Pradeep Bhat Date: Tue, 4 Nov 2014 17:06:45 +0000 Subject: drm/i915/skl: Read the pipe WM HW state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch provides the implementation for reading the pipe wm HW state. v2: Incorporated Damien's review comments and also made modifications to incorporate the plane/cursor split. v3: No need to ident a line that was fitting 80 chars Return early instead of indenting the remaining of a function (Damien) v4: Rebase on top of nightly (minor conflict in intel_drv.h) v5: Rebase on top of nightly (minor conflict in intel_drv.h) v6: Rebase on top of nightly (minor conflict in intel_drv.h) Reviewed-by: Ville Syrjälä Signed-off-by: Pradeep Bhat Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 4 +- drivers/gpu/drm/i915/intel_drv.h | 1 + drivers/gpu/drm/i915/intel_pm.c | 104 +++++++++++++++++++++++++++++++++++ 3 files changed, 108 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 84f4f0504bbb..01bc55850070 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -13266,7 +13266,9 @@ void intel_modeset_setup_hw_state(struct drm_device *dev, pll->on = false; } - if (HAS_PCH_SPLIT(dev)) + if (IS_GEN9(dev)) + skl_wm_get_hw_state(dev); + else if (HAS_PCH_SPLIT(dev)) ilk_wm_get_hw_state(dev); if (force_restore) { diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 446be27ce76f..1cdd6f95a445 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1164,6 +1164,7 @@ void gen6_update_ring_freq(struct drm_device *dev); void gen6_rps_idle(struct drm_i915_private *dev_priv); void gen6_rps_boost(struct drm_i915_private *dev_priv); void ilk_wm_get_hw_state(struct drm_device *dev); +void skl_wm_get_hw_state(struct drm_device *dev); /* intel_sdvo.c */ diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index c2f1441138be..09a81b3a754d 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3624,6 +3624,110 @@ ilk_update_sprite_wm(struct drm_plane *plane, ilk_update_wm(crtc); } +static void skl_pipe_wm_active_state(uint32_t val, + struct skl_pipe_wm *active, + bool is_transwm, + bool is_cursor, + int i, + int level) +{ + bool is_enabled = (val & PLANE_WM_EN) != 0; + + if (!is_transwm) { + if (!is_cursor) { + active->wm[level].plane_en[i] = is_enabled; + active->wm[level].plane_res_b[i] = + val & PLANE_WM_BLOCKS_MASK; + active->wm[level].plane_res_l[i] = + (val >> PLANE_WM_LINES_SHIFT) & + PLANE_WM_LINES_MASK; + } else { + active->wm[level].cursor_en = is_enabled; + active->wm[level].cursor_res_b = + val & PLANE_WM_BLOCKS_MASK; + active->wm[level].cursor_res_l = + (val >> PLANE_WM_LINES_SHIFT) & + PLANE_WM_LINES_MASK; + } + } else { + if (!is_cursor) { + active->trans_wm.plane_en[i] = is_enabled; + active->trans_wm.plane_res_b[i] = + val & PLANE_WM_BLOCKS_MASK; + active->trans_wm.plane_res_l[i] = + (val >> PLANE_WM_LINES_SHIFT) & + PLANE_WM_LINES_MASK; + } else { + active->trans_wm.cursor_en = is_enabled; + active->trans_wm.cursor_res_b = + val & PLANE_WM_BLOCKS_MASK; + active->trans_wm.cursor_res_l = + (val >> PLANE_WM_LINES_SHIFT) & + PLANE_WM_LINES_MASK; + } + } +} + +static void skl_pipe_wm_get_hw_state(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct skl_wm_values *hw = &dev_priv->wm.skl_hw; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct skl_pipe_wm *active = &intel_crtc->wm.skl_active; + enum pipe pipe = intel_crtc->pipe; + int level, i, max_level; + uint32_t temp; + + max_level = ilk_wm_max_level(dev); + + hw->wm_linetime[pipe] = I915_READ(PIPE_WM_LINETIME(pipe)); + + for (level = 0; level <= max_level; level++) { + for (i = 0; i < intel_num_planes(intel_crtc); i++) + hw->plane[pipe][i][level] = + I915_READ(PLANE_WM(pipe, i, level)); + hw->cursor[pipe][level] = I915_READ(CUR_WM(pipe, level)); + } + + for (i = 0; i < intel_num_planes(intel_crtc); i++) + hw->plane_trans[pipe][i] = I915_READ(PLANE_WM_TRANS(pipe, i)); + hw->cursor_trans[pipe] = I915_READ(CUR_WM_TRANS(pipe)); + + if (!intel_crtc_active(crtc)) + return; + + hw->dirty[pipe] = true; + + active->linetime = hw->wm_linetime[pipe]; + + for (level = 0; level <= max_level; level++) { + for (i = 0; i < intel_num_planes(intel_crtc); i++) { + temp = hw->plane[pipe][i][level]; + skl_pipe_wm_active_state(temp, active, false, + false, i, level); + } + temp = hw->cursor[pipe][level]; + skl_pipe_wm_active_state(temp, active, false, true, i, level); + } + + for (i = 0; i < intel_num_planes(intel_crtc); i++) { + temp = hw->plane_trans[pipe][i]; + skl_pipe_wm_active_state(temp, active, true, false, i, 0); + } + + temp = hw->cursor_trans[pipe]; + skl_pipe_wm_active_state(temp, active, true, true, i, 0); +} + +void skl_wm_get_hw_state(struct drm_device *dev) +{ + struct drm_crtc *crtc; + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) + skl_pipe_wm_get_hw_state(crtc); +} + static void ilk_pipe_wm_get_hw_state(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; -- cgit v1.2.3 From 367294be7c257dd4d8d8f0e296aa9824eae18568 Mon Sep 17 00:00:00 2001 From: Vandana Kannan Date: Tue, 4 Nov 2014 17:06:46 +0000 Subject: drm/i915/gen9: Add 2us read latency to WM level MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to the updated Bspec, The mailbox response data is not currently accounting for memory read latency. Add 2 microseconds to the result for each level. This patch adds 2us to latency of level 0 for all cases and for all other levels (1-7) only if latency[level] > 0. v2: Slightly rework the patch and add a big comment (Damien) v3: Rebase on top of the renames of the memory latency defines Signed-off-by: Vandana Kannan (v1) Signed-off-by: Damien Lespiau Reviewed-by: Ville Syrjälä (v2) Reviewed-by: M, Satheeshakrishna (v1) Cc: Lespiau, Damien Cc: M, Satheeshakrishna Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 09a81b3a754d..44fecfc3fc52 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2286,6 +2286,7 @@ static void intel_read_wm_latency(struct drm_device *dev, uint16_t wm[8]) if (IS_GEN9(dev)) { uint32_t val; int ret; + int level, max_level = ilk_wm_max_level(dev); /* read the first set of memory latencies[0:3] */ val = 0; /* data0 to be programmed to 0 for first set */ @@ -2328,6 +2329,21 @@ static void intel_read_wm_latency(struct drm_device *dev, uint16_t wm[8]) wm[7] = (val >> GEN9_MEM_LATENCY_LEVEL_3_7_SHIFT) & GEN9_MEM_LATENCY_LEVEL_MASK; + /* + * punit doesn't take into account the read latency so we need + * to add 2us to the various latency levels we retrieve from + * the punit. + * - W0 is a bit special in that it's the only level that + * can't be disabled if we want to have display working, so + * we always add 2us there. + * - For levels >=1, punit returns 0us latency when they are + * disabled, so we respect that and don't add 2us then + */ + wm[0] += 2; + for (level = 1; level <= max_level; level++) + if (wm[level] != 0) + wm[level] += 2; + } else if (IS_HASWELL(dev) || IS_BROADWELL(dev)) { uint64_t sskpd = I915_READ64(MCH_SSKPD); -- cgit v1.2.3 From 4f94738674b813fe0ef8e7dbef8a24aeb8c2271a Mon Sep 17 00:00:00 2001 From: Vandana Kannan Date: Tue, 4 Nov 2014 17:06:47 +0000 Subject: drm/i915/gen9: Disable WM if corresponding latency is 0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to updated BSpec, If level 1 or any higher level has a value of 0x00, that level and any higher levels are unused and the associated watermark registers must not be enabled. This patch checks for latency 0 for level >=1 and does not enable WM corresponding to level m | m>=n, if level n (n != 0) has a 0us latency. v2: Satheesh's review comments - zero-out latency values (for all higher levels if latency of given level is zero ) in read_wm_latency() function itself v3: removed redundant check as per Satheesh's observation. v4: rebase on top before merging (Damien) v5: Rebase on top of the default value removal (Ville) Reviewed-by: Satheeshakrishna M (v3) Reviewed-by: Ville Syrjälä Signed-off-by: Damien Lespiau Signed-off-by: Vandana Kannan Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 44fecfc3fc52..bf2cd650880e 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2285,7 +2285,7 @@ static void intel_read_wm_latency(struct drm_device *dev, uint16_t wm[8]) if (IS_GEN9(dev)) { uint32_t val; - int ret; + int ret, i; int level, max_level = ilk_wm_max_level(dev); /* read the first set of memory latencies[0:3] */ @@ -2338,12 +2338,22 @@ static void intel_read_wm_latency(struct drm_device *dev, uint16_t wm[8]) * we always add 2us there. * - For levels >=1, punit returns 0us latency when they are * disabled, so we respect that and don't add 2us then + * + * Additionally, if a level n (n > 1) has a 0us latency, all + * levels m (m >= n) need to be disabled. We make sure to + * sanitize the values out of the punit to satisfy this + * requirement. */ wm[0] += 2; for (level = 1; level <= max_level; level++) if (wm[level] != 0) wm[level] += 2; + else { + for (i = level + 1; i <= max_level; i++) + wm[i] = 0; + break; + } } else if (IS_HASWELL(dev) || IS_BROADWELL(dev)) { uint64_t sskpd = I915_READ64(MCH_SSKPD); @@ -3285,7 +3295,7 @@ static bool skl_compute_plane_wm(struct skl_pipe_wm_parameters *p, uint32_t method1, method2, plane_bytes_per_line; uint32_t result_bytes; - if (!p->active || !p_params->enabled) + if (mem_value == 0 || !p->active || !p_params->enabled) return false; method1 = skl_wm_method1(p->pixel_rate, -- cgit v1.2.3 From 53b0deb4cba206c6f8cf9225080ac49e02183376 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Tue, 4 Nov 2014 17:06:48 +0000 Subject: drm/i915/skl: Store the new WM state at the very end of the update MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We're going to add a new step, let's not hide the copy of the new WM state inside one inner function, but as a 1st level operation in the WM update. v2: Split the staging results structure to not exceed the 1Kb stack allocation in skl_update_wm() Reviewed-by: Ville Syrjälä Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index bf2cd650880e..a4294b1b93ca 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3463,8 +3463,6 @@ static void skl_write_wm_values(struct drm_i915_private *dev_priv, new->ddb.cursor[pipe].start); } } - - dev_priv->wm.skl_hw = *new; } static bool skl_update_pipe_wm(struct drm_crtc *crtc, @@ -3558,6 +3556,9 @@ static void skl_update_wm(struct drm_crtc *crtc) skl_update_other_pipe_wm(dev, crtc, &config, results); skl_write_wm_values(dev_priv, results); + + /* store the new configuration */ + dev_priv->wm.skl_hw = *results; } static void -- cgit v1.2.3 From a269c5839bc4e3a997228314cb2efbddc9da604a Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Tue, 4 Nov 2014 17:06:49 +0000 Subject: drm/i915/skl: Read back the DDB allocation hw state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This logically belongs to the WM state, so do it there. Reviewed-by: Ville Syrjälä Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index a4294b1b93ca..8b7abc7c5604 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3051,6 +3051,32 @@ static unsigned int skl_cursor_allocation(const struct intel_wm_config *config) return 8; } +static void skl_ddb_entry_init_from_hw(struct skl_ddb_entry *entry, u32 reg) +{ + entry->start = reg & 0x3ff; + entry->end = (reg >> 16) & 0x3ff; +} + +static void skl_ddb_get_hw_state(struct drm_i915_private *dev_priv, + struct skl_ddb_allocation *ddb /* out */) +{ + struct drm_device *dev = dev_priv->dev; + enum pipe pipe; + int plane; + u32 val; + + for_each_pipe(dev_priv, pipe) { + for_each_plane(pipe, plane) { + val = I915_READ(PLANE_BUF_CFG(pipe, plane)); + skl_ddb_entry_init_from_hw(&ddb->plane[pipe][plane], + val); + } + + val = I915_READ(CUR_BUF_CFG(pipe)); + skl_ddb_entry_init_from_hw(&ddb->cursor[pipe], val); + } +} + static unsigned int skl_plane_relative_data_rate(const struct intel_plane_wm_parameters *p) { @@ -3749,8 +3775,11 @@ static void skl_pipe_wm_get_hw_state(struct drm_crtc *crtc) void skl_wm_get_hw_state(struct drm_device *dev) { + struct drm_i915_private *dev_priv = dev->dev_private; + struct skl_ddb_allocation *ddb = &dev_priv->wm.skl_hw.ddb; struct drm_crtc *crtc; + skl_ddb_get_hw_state(dev_priv, ddb); list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) skl_pipe_wm_get_hw_state(crtc); } -- cgit v1.2.3 From 97e94b22ed4fe116beadbdbe4667f2a2f9aa9fd0 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Tue, 4 Nov 2014 17:06:50 +0000 Subject: drm/i915/skl: Augment the latency debugfs files for SKL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit v2: Use the gen >= 9 in the debugfs file condition (Ville) Reviewed-by: Ville Syrjälä Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 76 ++++++++++++++++++++++++++++++------- 1 file changed, 62 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 0a6981399642..b1cbfbf84fe1 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -3523,7 +3523,7 @@ static const struct file_operations i915_display_crc_ctl_fops = { .write = display_crc_ctl_write }; -static void wm_latency_show(struct seq_file *m, const uint16_t wm[5]) +static void wm_latency_show(struct seq_file *m, const uint16_t wm[8]) { struct drm_device *dev = m->private; int num_levels = ilk_wm_max_level(dev) + 1; @@ -3534,13 +3534,17 @@ static void wm_latency_show(struct seq_file *m, const uint16_t wm[5]) for (level = 0; level < num_levels; level++) { unsigned int latency = wm[level]; - /* WM1+ latency values in 0.5us units */ - if (level > 0) + /* + * - WM1+ latency values in 0.5us units + * - latencies are in us on gen9 + */ + if (INTEL_INFO(dev)->gen >= 9) + latency *= 10; + else if (level > 0) latency *= 5; seq_printf(m, "WM%d %u (%u.%u usec)\n", - level, wm[level], - latency / 10, latency % 10); + level, wm[level], latency / 10, latency % 10); } drm_modeset_unlock_all(dev); @@ -3549,8 +3553,15 @@ static void wm_latency_show(struct seq_file *m, const uint16_t wm[5]) static int pri_wm_latency_show(struct seq_file *m, void *data) { struct drm_device *dev = m->private; + struct drm_i915_private *dev_priv = dev->dev_private; + const uint16_t *latencies; + + if (INTEL_INFO(dev)->gen >= 9) + latencies = dev_priv->wm.skl_latency; + else + latencies = to_i915(dev)->wm.pri_latency; - wm_latency_show(m, to_i915(dev)->wm.pri_latency); + wm_latency_show(m, latencies); return 0; } @@ -3558,8 +3569,15 @@ static int pri_wm_latency_show(struct seq_file *m, void *data) static int spr_wm_latency_show(struct seq_file *m, void *data) { struct drm_device *dev = m->private; + struct drm_i915_private *dev_priv = dev->dev_private; + const uint16_t *latencies; + + if (INTEL_INFO(dev)->gen >= 9) + latencies = dev_priv->wm.skl_latency; + else + latencies = to_i915(dev)->wm.spr_latency; - wm_latency_show(m, to_i915(dev)->wm.spr_latency); + wm_latency_show(m, latencies); return 0; } @@ -3567,8 +3585,15 @@ static int spr_wm_latency_show(struct seq_file *m, void *data) static int cur_wm_latency_show(struct seq_file *m, void *data) { struct drm_device *dev = m->private; + struct drm_i915_private *dev_priv = dev->dev_private; + const uint16_t *latencies; + + if (INTEL_INFO(dev)->gen >= 9) + latencies = dev_priv->wm.skl_latency; + else + latencies = to_i915(dev)->wm.cur_latency; - wm_latency_show(m, to_i915(dev)->wm.cur_latency); + wm_latency_show(m, latencies); return 0; } @@ -3604,11 +3629,11 @@ static int cur_wm_latency_open(struct inode *inode, struct file *file) } static ssize_t wm_latency_write(struct file *file, const char __user *ubuf, - size_t len, loff_t *offp, uint16_t wm[5]) + size_t len, loff_t *offp, uint16_t wm[8]) { struct seq_file *m = file->private_data; struct drm_device *dev = m->private; - uint16_t new[5] = { 0 }; + uint16_t new[8] = { 0 }; int num_levels = ilk_wm_max_level(dev) + 1; int level; int ret; @@ -3622,7 +3647,9 @@ static ssize_t wm_latency_write(struct file *file, const char __user *ubuf, tmp[len] = '\0'; - ret = sscanf(tmp, "%hu %hu %hu %hu %hu", &new[0], &new[1], &new[2], &new[3], &new[4]); + ret = sscanf(tmp, "%hu %hu %hu %hu %hu %hu %hu %hu", + &new[0], &new[1], &new[2], &new[3], + &new[4], &new[5], &new[6], &new[7]); if (ret != num_levels) return -EINVAL; @@ -3642,8 +3669,15 @@ static ssize_t pri_wm_latency_write(struct file *file, const char __user *ubuf, { struct seq_file *m = file->private_data; struct drm_device *dev = m->private; + struct drm_i915_private *dev_priv = dev->dev_private; + uint16_t *latencies; - return wm_latency_write(file, ubuf, len, offp, to_i915(dev)->wm.pri_latency); + if (INTEL_INFO(dev)->gen >= 9) + latencies = dev_priv->wm.skl_latency; + else + latencies = to_i915(dev)->wm.pri_latency; + + return wm_latency_write(file, ubuf, len, offp, latencies); } static ssize_t spr_wm_latency_write(struct file *file, const char __user *ubuf, @@ -3651,8 +3685,15 @@ static ssize_t spr_wm_latency_write(struct file *file, const char __user *ubuf, { struct seq_file *m = file->private_data; struct drm_device *dev = m->private; + struct drm_i915_private *dev_priv = dev->dev_private; + uint16_t *latencies; - return wm_latency_write(file, ubuf, len, offp, to_i915(dev)->wm.spr_latency); + if (INTEL_INFO(dev)->gen >= 9) + latencies = dev_priv->wm.skl_latency; + else + latencies = to_i915(dev)->wm.spr_latency; + + return wm_latency_write(file, ubuf, len, offp, latencies); } static ssize_t cur_wm_latency_write(struct file *file, const char __user *ubuf, @@ -3660,8 +3701,15 @@ static ssize_t cur_wm_latency_write(struct file *file, const char __user *ubuf, { struct seq_file *m = file->private_data; struct drm_device *dev = m->private; + struct drm_i915_private *dev_priv = dev->dev_private; + uint16_t *latencies; + + if (INTEL_INFO(dev)->gen >= 9) + latencies = dev_priv->wm.skl_latency; + else + latencies = to_i915(dev)->wm.cur_latency; - return wm_latency_write(file, ubuf, len, offp, to_i915(dev)->wm.cur_latency); + return wm_latency_write(file, ubuf, len, offp, latencies); } static const struct file_operations i915_pri_wm_latency_fops = { -- cgit v1.2.3 From c5511e44e8a643cf6400e8dbf9e4f6d348786112 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Tue, 4 Nov 2014 17:06:51 +0000 Subject: drm/i915/skl: Add a debugfs file to dump the DDB allocation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit v2: minor conflict in i915_debugfs.c v3: Rebase on top of the for_each_pipe() change adding dev_priv as first argument. v4: minor conflict in the i915_debugfs_files array v5: minor conflict in the i915_debugfs_files array Reviewed-by: Ville Syrjälä Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index b1cbfbf84fe1..319da61354b0 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2679,6 +2679,42 @@ static int i915_wa_registers(struct seq_file *m, void *unused) return 0; } +static int i915_ddb_info(struct seq_file *m, void *unused) +{ + struct drm_info_node *node = m->private; + struct drm_device *dev = node->minor->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct skl_ddb_allocation *ddb; + struct skl_ddb_entry *entry; + enum pipe pipe; + int plane; + + drm_modeset_lock_all(dev); + + ddb = &dev_priv->wm.skl_hw.ddb; + + seq_printf(m, "%-15s%8s%8s%8s\n", "", "Start", "End", "Size"); + + for_each_pipe(dev_priv, pipe) { + seq_printf(m, "Pipe %c\n", pipe_name(pipe)); + + for_each_plane(pipe, plane) { + entry = &ddb->plane[pipe][plane]; + seq_printf(m, " Plane%-8d%8u%8u%8u\n", plane + 1, + entry->start, entry->end, + skl_ddb_entry_size(entry)); + } + + entry = &ddb->cursor[pipe]; + seq_printf(m, " %-13s%8u%8u%8u\n", "Cursor", entry->start, + entry->end, skl_ddb_entry_size(entry)); + } + + drm_modeset_unlock_all(dev); + + return 0; +} + struct pipe_crc_info { const char *name; struct drm_device *dev; @@ -4252,6 +4288,7 @@ static const struct drm_info_list i915_debugfs_list[] = { {"i915_shared_dplls_info", i915_shared_dplls_info, 0}, {"i915_dp_mst_info", i915_dp_mst_info, 0}, {"i915_wa_registers", i915_wa_registers, 0}, + {"i915_ddb_info", i915_ddb_info, 0}, }; #define I915_DEBUGFS_ENTRIES ARRAY_SIZE(i915_debugfs_list) -- cgit v1.2.3 From 08db665203d5e587efc391afc405a9317d29fe17 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Tue, 4 Nov 2014 17:06:52 +0000 Subject: drm/i915/skl: Check the DDB state at modeset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit v2: Don't check DDB on pre-SKL platforms Don't check DDB state on disabled pipes v3: Squash "Expose skl_ddb_get_hw_state()" Reviewed-by: Ville Syrjälä Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 9 +++++++ drivers/gpu/drm/i915/intel_display.c | 51 ++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_drv.h | 2 ++ drivers/gpu/drm/i915/intel_pm.c | 4 +-- 4 files changed, 64 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index fbe18aed254d..ee744a2c2085 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1400,6 +1400,15 @@ static inline uint16_t skl_ddb_entry_size(const struct skl_ddb_entry *entry) return entry->end - entry->start + 1; } +static inline bool skl_ddb_entry_equal(const struct skl_ddb_entry *e1, + const struct skl_ddb_entry *e2) +{ + if (e1->start == e2->start && e1->end == e2->end) + return true; + + return false; +} + struct skl_ddb_allocation { struct skl_ddb_entry plane[I915_MAX_PIPES][I915_MAX_PLANES]; struct skl_ddb_entry cursor[I915_MAX_PIPES]; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 01bc55850070..07fb0ff66f5d 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -10511,6 +10511,56 @@ intel_pipe_config_compare(struct drm_device *dev, return true; } +static void check_wm_state(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct skl_ddb_allocation hw_ddb, *sw_ddb; + struct intel_crtc *intel_crtc; + int plane; + + if (INTEL_INFO(dev)->gen < 9) + return; + + skl_ddb_get_hw_state(dev_priv, &hw_ddb); + sw_ddb = &dev_priv->wm.skl_hw.ddb; + + for_each_intel_crtc(dev, intel_crtc) { + struct skl_ddb_entry *hw_entry, *sw_entry; + const enum pipe pipe = intel_crtc->pipe; + + if (!intel_crtc->active) + continue; + + /* planes */ + for_each_plane(pipe, plane) { + hw_entry = &hw_ddb.plane[pipe][plane]; + sw_entry = &sw_ddb->plane[pipe][plane]; + + if (skl_ddb_entry_equal(hw_entry, sw_entry)) + continue; + + DRM_ERROR("mismatch in DDB state pipe %c plane %d " + "(expected (%u,%u), found (%u,%u))\n", + pipe_name(pipe), plane + 1, + sw_entry->start, sw_entry->end, + hw_entry->start, hw_entry->end); + } + + /* cursor */ + hw_entry = &hw_ddb.cursor[pipe]; + sw_entry = &sw_ddb->cursor[pipe]; + + if (skl_ddb_entry_equal(hw_entry, sw_entry)) + continue; + + DRM_ERROR("mismatch in DDB state pipe %c cursor " + "(expected (%u,%u), found (%u,%u))\n", + pipe_name(pipe), + sw_entry->start, sw_entry->end, + hw_entry->start, hw_entry->end); + } +} + static void check_connector_state(struct drm_device *dev) { @@ -10710,6 +10760,7 @@ check_shared_dpll_state(struct drm_device *dev) void intel_modeset_check_state(struct drm_device *dev) { + check_wm_state(dev); check_connector_state(dev); check_encoder_state(dev); check_crtc_state(dev); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 1cdd6f95a445..cb0e9dbf1c96 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1165,6 +1165,8 @@ void gen6_rps_idle(struct drm_i915_private *dev_priv); void gen6_rps_boost(struct drm_i915_private *dev_priv); void ilk_wm_get_hw_state(struct drm_device *dev); void skl_wm_get_hw_state(struct drm_device *dev); +void skl_ddb_get_hw_state(struct drm_i915_private *dev_priv, + struct skl_ddb_allocation *ddb /* out */); /* intel_sdvo.c */ diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 8b7abc7c5604..159c2e083e54 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3057,8 +3057,8 @@ static void skl_ddb_entry_init_from_hw(struct skl_ddb_entry *entry, u32 reg) entry->end = (reg >> 16) & 0x3ff; } -static void skl_ddb_get_hw_state(struct drm_i915_private *dev_priv, - struct skl_ddb_allocation *ddb /* out */) +void skl_ddb_get_hw_state(struct drm_i915_private *dev_priv, + struct skl_ddb_allocation *ddb /* out */) { struct drm_device *dev = dev_priv->dev; enum pipe pipe; -- cgit v1.2.3 From 16160e3dd32343de9d6115353408728adecdecfb Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Tue, 4 Nov 2014 17:06:53 +0000 Subject: drm/i915/skl: Make 'end' of the DDB allocation entry exclusive MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ville suggested that we should use the same semantics as C arrays to reduce the number of those pesky +1/-1 in the allocation code. This patch leaves the debugfs file as is, showing the internal DDB allocation structure, not the values written in the registers. v2: Remove the test on ->end in skl_ddb_entry_size() (Ville) Reviewed-by: Ville Syrjälä Suggested-by: Ville Syrjälä Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 8 ++------ drivers/gpu/drm/i915/intel_pm.c | 28 +++++++++++++++++++--------- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index ee744a2c2085..84e8cdb1c571 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1388,16 +1388,12 @@ struct ilk_wm_values { }; struct skl_ddb_entry { - uint16_t start, end; /* in number of blocks */ + uint16_t start, end; /* in number of blocks, 'end' is exclusive */ }; static inline uint16_t skl_ddb_entry_size(const struct skl_ddb_entry *entry) { - /* end not set, clearly no allocation here. start can be 0 though */ - if (entry->end == 0) - return 0; - - return entry->end - entry->start + 1; + return entry->end - entry->start; } static inline bool skl_ddb_entry_equal(const struct skl_ddb_entry *e1, diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 159c2e083e54..e417a6a301d1 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3040,7 +3040,7 @@ skl_ddb_get_pipe_allocation_limits(struct drm_device *dev, pipe_size = ddb_size / config->num_pipes_active; alloc->start = nth_active_pipe * ddb_size / config->num_pipes_active; - alloc->end = alloc->start + pipe_size - 1; + alloc->end = alloc->start + pipe_size; } static unsigned int skl_cursor_allocation(const struct intel_wm_config *config) @@ -3055,6 +3055,8 @@ static void skl_ddb_entry_init_from_hw(struct skl_ddb_entry *entry, u32 reg) { entry->start = reg & 0x3ff; entry->end = (reg >> 16) & 0x3ff; + if (entry->end) + entry->end += 1; } void skl_ddb_get_hw_state(struct drm_i915_private *dev_priv, @@ -3131,7 +3133,7 @@ skl_allocate_pipe_ddb(struct drm_crtc *crtc, } cursor_blocks = skl_cursor_allocation(config); - ddb->cursor[pipe].start = alloc.end - cursor_blocks + 1; + ddb->cursor[pipe].start = alloc.end - cursor_blocks; ddb->cursor[pipe].end = alloc.end; alloc_size -= cursor_blocks; @@ -3165,7 +3167,7 @@ skl_allocate_pipe_ddb(struct drm_crtc *crtc, total_data_rate); ddb->plane[pipe][plane].start = start; - ddb->plane[pipe][plane].end = start + plane_blocks - 1; + ddb->plane[pipe][plane].end = start + plane_blocks; start += plane_blocks; } @@ -3453,6 +3455,15 @@ static void skl_compute_wm_results(struct drm_device *dev, r->wm_linetime[pipe] = p_wm->linetime; } +static void skl_ddb_entry_write(struct drm_i915_private *dev_priv, uint32_t reg, + const struct skl_ddb_entry *entry) +{ + if (entry->end) + I915_WRITE(reg, (entry->end - 1) << 16 | entry->start); + else + I915_WRITE(reg, 0); +} + static void skl_write_wm_values(struct drm_i915_private *dev_priv, const struct skl_wm_values *new) { @@ -3480,13 +3491,12 @@ static void skl_write_wm_values(struct drm_i915_private *dev_priv, I915_WRITE(CUR_WM_TRANS(pipe), new->cursor_trans[pipe]); for (i = 0; i < intel_num_planes(crtc); i++) - I915_WRITE(PLANE_BUF_CFG(pipe, i), - new->ddb.plane[pipe][i].end << 16 | - new->ddb.plane[pipe][i].start); + skl_ddb_entry_write(dev_priv, + PLANE_BUF_CFG(pipe, i), + &new->ddb.plane[pipe][i]); - I915_WRITE(CUR_BUF_CFG(pipe), - new->ddb.cursor[pipe].end << 16 | - new->ddb.cursor[pipe].start); + skl_ddb_entry_write(dev_priv, CUR_BUF_CFG(pipe), + &new->ddb.cursor[pipe]); } } } -- cgit v1.2.3 From 21fca258bc09b951b66ff5c501a37b56be4d4310 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Tue, 4 Nov 2014 17:06:54 +0000 Subject: drm/i915/skl: Use a more descriptive parameter name in skl_compute_plane_wm() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit What we're talking about here is the DDB allocation (in blocks). That's more descriptive than 'max_page_buff_alloc'. Reviewed-by: Ville Syrjälä Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index e417a6a301d1..0142ad146224 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3315,7 +3315,7 @@ static void skl_compute_wm_pipe_parameters(struct drm_crtc *crtc, static bool skl_compute_plane_wm(struct skl_pipe_wm_parameters *p, struct intel_plane_wm_parameters *p_params, - uint16_t max_page_buff_alloc, + uint16_t ddb_allocation, uint32_t mem_value, uint16_t *res_blocks, /* out */ uint8_t *res_lines /* out */) @@ -3339,7 +3339,7 @@ static bool skl_compute_plane_wm(struct skl_pipe_wm_parameters *p, p_params->bytes_per_pixel; /* For now xtile and linear */ - if (((max_page_buff_alloc * 512) / plane_bytes_per_line) >= 1) + if (((ddb_allocation * 512) / plane_bytes_per_line) >= 1) result_bytes = min(method1, method2); else result_bytes = method1; -- cgit v1.2.3 From e6d6617152def4f9d46fb9c5cba3e322bedc27c2 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Tue, 4 Nov 2014 17:06:55 +0000 Subject: drm/i915/skl: Make res_blocks/lines intermediate values 32 bits MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To align with the ilk WM code and because it makes sense to test against the upper bounds as soon as possible on variables that are bigger than the number of bits in the register, let's move the maximum checks from skl_compute_wm_results() to skl_compute_plane_wm(). v2: Leave the result values to 0 when overflowing the limits (Ville) Use 32 bits intermediate variables (Damien) Instead of using the 16 and 8 bits space we have in the result structure, use 32 bits local variables until we're sure they fit into the constraints. Suggested-by: Ville Syrjälä Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 0142ad146224..858029878d38 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3317,10 +3317,10 @@ static bool skl_compute_plane_wm(struct skl_pipe_wm_parameters *p, struct intel_plane_wm_parameters *p_params, uint16_t ddb_allocation, uint32_t mem_value, - uint16_t *res_blocks, /* out */ - uint8_t *res_lines /* out */) + uint16_t *out_blocks, /* out */ + uint8_t *out_lines /* out */) { - uint32_t method1, method2, plane_bytes_per_line; + uint32_t method1, method2, plane_bytes_per_line, res_blocks, res_lines; uint32_t result_bytes; if (mem_value == 0 || !p->active || !p_params->enabled) @@ -3344,8 +3344,14 @@ static bool skl_compute_plane_wm(struct skl_pipe_wm_parameters *p, else result_bytes = method1; - *res_blocks = DIV_ROUND_UP(result_bytes, 512) + 1; - *res_lines = DIV_ROUND_UP(result_bytes, plane_bytes_per_line); + res_blocks = DIV_ROUND_UP(result_bytes, 512) + 1; + res_lines = DIV_ROUND_UP(result_bytes, plane_bytes_per_line); + + if (res_blocks > ddb_allocation || res_lines > 31) + return false; + + *out_blocks = res_blocks; + *out_lines = res_lines; return true; } @@ -3408,17 +3414,11 @@ static void skl_compute_wm_results(struct drm_device *dev, enum pipe pipe = intel_crtc->pipe; for (level = 0; level <= max_level; level++) { - uint16_t ddb_blocks; uint32_t temp; int i; for (i = 0; i < intel_num_planes(intel_crtc); i++) { temp = 0; - ddb_blocks = skl_ddb_entry_size(&r->ddb.plane[pipe][i]); - - if ((p_wm->wm[level].plane_res_b[i] > ddb_blocks) || - (p_wm->wm[level].plane_res_l[i] > 31)) - p_wm->wm[level].plane_en[i] = false; temp |= p_wm->wm[level].plane_res_l[i] << PLANE_WM_LINES_SHIFT; @@ -3433,11 +3433,6 @@ static void skl_compute_wm_results(struct drm_device *dev, } temp = 0; - ddb_blocks = skl_ddb_entry_size(&r->ddb.cursor[pipe]); - - if ((p_wm->wm[level].cursor_res_b > ddb_blocks) || - (p_wm->wm[level].cursor_res_l > 31)) - p_wm->wm[level].cursor_en = false; temp |= p_wm->wm[level].cursor_res_l << PLANE_WM_LINES_SHIFT; temp |= p_wm->wm[level].cursor_res_b; -- cgit v1.2.3 From b99f58dabb9dae18c97a9e3812ba9961b207fd45 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Tue, 4 Nov 2014 17:06:56 +0000 Subject: drm/i915/skl: Reduce the number of holes in struct skl_wm_level MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Ville Syrjälä Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 84e8cdb1c571..cf84b6d30eae 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1422,9 +1422,9 @@ struct skl_wm_values { struct skl_wm_level { bool plane_en[I915_MAX_PLANES]; + bool cursor_en; uint16_t plane_res_b[I915_MAX_PLANES]; uint8_t plane_res_l[I915_MAX_PLANES]; - bool cursor_en; uint16_t cursor_res_b; uint8_t cursor_res_l; }; -- cgit v1.2.3 From 407b50f31ba19317cdc30530d30220182e42fa3d Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Tue, 4 Nov 2014 17:06:57 +0000 Subject: drm/i915/skl: Move all the WM compute functions in one place MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The DDB allocation code managed to split in two the compute functions. Bring back skl_compute_transition_wm() and skl_compute_linetime_wm() with their little friends. Reviewed-by: Ville Syrjälä Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 44 ++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 858029878d38..66f142bcbee4 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3217,28 +3217,6 @@ static uint32_t skl_wm_method2(uint32_t pixel_rate, uint32_t pipe_htotal, return ret; } -static void skl_compute_transition_wm(struct drm_crtc *crtc, - struct skl_pipe_wm_parameters *params, - struct skl_pipe_wm *pipe_wm) -{ - /* - * For now it is suggested to use the LP0 wm val of corresponding - * plane as transition wm val. This is done while computing results. - */ - if (!params->active) - return; -} - -static uint32_t -skl_compute_linetime_wm(struct drm_crtc *crtc, struct skl_pipe_wm_parameters *p) -{ - if (!intel_crtc_active(crtc)) - return 0; - - return DIV_ROUND_UP(8 * p->pipe_htotal * 1000, p->pixel_rate); - -} - static bool skl_ddb_allocation_changed(const struct skl_ddb_allocation *new_ddb, const struct intel_crtc *intel_crtc) { @@ -3384,6 +3362,28 @@ static void skl_compute_wm_level(const struct drm_i915_private *dev_priv, &result->cursor_res_l); } +static uint32_t +skl_compute_linetime_wm(struct drm_crtc *crtc, struct skl_pipe_wm_parameters *p) +{ + if (!intel_crtc_active(crtc)) + return 0; + + return DIV_ROUND_UP(8 * p->pipe_htotal * 1000, p->pixel_rate); + +} + +static void skl_compute_transition_wm(struct drm_crtc *crtc, + struct skl_pipe_wm_parameters *params, + struct skl_pipe_wm *pipe_wm) +{ + /* + * For now it is suggested to use the LP0 wm val of corresponding + * plane as transition wm val. + */ + if (!params->active) + return; +} + static void skl_compute_pipe_wm(struct drm_crtc *crtc, struct skl_ddb_allocation *ddb, struct skl_pipe_wm_parameters *params, -- cgit v1.2.3 From 9414f563f3857018d87e480b7cd13636b0c00ce6 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Tue, 4 Nov 2014 17:06:58 +0000 Subject: drm/i915/skl: Rework when the transition WMs are computed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The transition WMs code was doing a shortcut and the values were copied from the WM0 ones at compute_wm_results() time. Going forward, we want to compute them like the other WMs and resolve their final register values in the same way as well. This patch does just that and isolate the transtion WM compute code in skl_compute_transition_wm() while skl_compute_wm_results() takes care of the register values. We also take the opportunity to disable the transition WMs for now. We've noticed underruns and they seem to be the culprit. Reviewed-by: Ville Syrjälä Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 46 +++++++++++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 66f142bcbee4..41cfb2624cdc 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3374,14 +3374,18 @@ skl_compute_linetime_wm(struct drm_crtc *crtc, struct skl_pipe_wm_parameters *p) static void skl_compute_transition_wm(struct drm_crtc *crtc, struct skl_pipe_wm_parameters *params, - struct skl_pipe_wm *pipe_wm) + struct skl_wm_level *trans_wm /* out */) { - /* - * For now it is suggested to use the LP0 wm val of corresponding - * plane as transition wm val. - */ + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int i; + if (!params->active) return; + + /* Until we know more, just disable transition WMs */ + for (i = 0; i < intel_num_planes(intel_crtc); i++) + trans_wm->plane_en[i] = false; + trans_wm->cursor_en = false; } static void skl_compute_pipe_wm(struct drm_crtc *crtc, @@ -3401,7 +3405,7 @@ static void skl_compute_pipe_wm(struct drm_crtc *crtc, } pipe_wm->linetime = skl_compute_linetime_wm(crtc, params); - skl_compute_transition_wm(crtc, params, pipe_wm); + skl_compute_transition_wm(crtc, params, &pipe_wm->trans_wm); } static void skl_compute_wm_results(struct drm_device *dev, @@ -3412,11 +3416,10 @@ static void skl_compute_wm_results(struct drm_device *dev, { int level, max_level = ilk_wm_max_level(dev); enum pipe pipe = intel_crtc->pipe; + uint32_t temp; + int i; for (level = 0; level <= max_level; level++) { - uint32_t temp; - int i; - for (i = 0; i < intel_num_planes(intel_crtc); i++) { temp = 0; @@ -3427,9 +3430,6 @@ static void skl_compute_wm_results(struct drm_device *dev, temp |= PLANE_WM_EN; r->plane[pipe][i][level] = temp; - /* Use the LP0 WM value for transition WM for now. */ - if (level == 0) - r->plane_trans[pipe][i] = temp; } temp = 0; @@ -3441,12 +3441,28 @@ static void skl_compute_wm_results(struct drm_device *dev, temp |= PLANE_WM_EN; r->cursor[pipe][level] = temp; - /* Use the LP0 WM value for transition WM for now. */ - if (level == 0) - r->cursor_trans[pipe] = temp; } + /* transition WMs */ + for (i = 0; i < intel_num_planes(intel_crtc); i++) { + temp = 0; + temp |= p_wm->trans_wm.plane_res_l[i] << PLANE_WM_LINES_SHIFT; + temp |= p_wm->trans_wm.plane_res_b[i]; + if (p_wm->trans_wm.plane_en[i]) + temp |= PLANE_WM_EN; + + r->plane_trans[pipe][i] = temp; + } + + temp = 0; + temp |= p_wm->trans_wm.cursor_res_l << PLANE_WM_LINES_SHIFT; + temp |= p_wm->trans_wm.cursor_res_b; + if (p_wm->trans_wm.cursor_en) + temp |= PLANE_WM_EN; + + r->cursor_trans[pipe] = temp; + r->wm_linetime[pipe] = p_wm->linetime; } -- cgit v1.2.3 From afb024aa656b7d13392430a254b341728806c540 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Tue, 4 Nov 2014 17:06:59 +0000 Subject: drm/i915/skl: Correctly align skl_compute_plane_wm() arguments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Ville Syrjälä Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 41cfb2624cdc..176e9ef9b266 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3292,11 +3292,11 @@ static void skl_compute_wm_pipe_parameters(struct drm_crtc *crtc, } static bool skl_compute_plane_wm(struct skl_pipe_wm_parameters *p, - struct intel_plane_wm_parameters *p_params, - uint16_t ddb_allocation, - uint32_t mem_value, - uint16_t *out_blocks, /* out */ - uint8_t *out_lines /* out */) + struct intel_plane_wm_parameters *p_params, + uint16_t ddb_allocation, + uint32_t mem_value, + uint16_t *out_blocks, /* out */ + uint8_t *out_lines /* out */) { uint32_t method1, method2, plane_bytes_per_line, res_blocks, res_lines; uint32_t result_bytes; -- cgit v1.2.3 From 5d374d9638924ff8c91a87f55dc895be7ab163f8 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Tue, 4 Nov 2014 17:07:00 +0000 Subject: drm/i915/skl: Reduce the indentation level in skl_write_wm_values() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We can reduce the indentation level by continuing early. Reviewed-by: Ville Syrjälä Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 42 ++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 176e9ef9b266..7fdccba93385 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3485,30 +3485,30 @@ static void skl_write_wm_values(struct drm_i915_private *dev_priv, int i, level, max_level = ilk_wm_max_level(dev); enum pipe pipe = crtc->pipe; - if (new->dirty[pipe]) { - I915_WRITE(PIPE_WM_LINETIME(pipe), - new->wm_linetime[pipe]); - - for (level = 0; level <= max_level; level++) { - for (i = 0; i < intel_num_planes(crtc); i++) - I915_WRITE(PLANE_WM(pipe, i, level), - new->plane[pipe][i][level]); - I915_WRITE(CUR_WM(pipe, level), - new->cursor[pipe][level]); - } - for (i = 0; i < intel_num_planes(crtc); i++) - I915_WRITE(PLANE_WM_TRANS(pipe, i), - new->plane_trans[pipe][i]); - I915_WRITE(CUR_WM_TRANS(pipe), new->cursor_trans[pipe]); + if (!new->dirty[pipe]) + continue; - for (i = 0; i < intel_num_planes(crtc); i++) - skl_ddb_entry_write(dev_priv, - PLANE_BUF_CFG(pipe, i), - &new->ddb.plane[pipe][i]); + I915_WRITE(PIPE_WM_LINETIME(pipe), new->wm_linetime[pipe]); - skl_ddb_entry_write(dev_priv, CUR_BUF_CFG(pipe), - &new->ddb.cursor[pipe]); + for (level = 0; level <= max_level; level++) { + for (i = 0; i < intel_num_planes(crtc); i++) + I915_WRITE(PLANE_WM(pipe, i, level), + new->plane[pipe][i][level]); + I915_WRITE(CUR_WM(pipe, level), + new->cursor[pipe][level]); } + for (i = 0; i < intel_num_planes(crtc); i++) + I915_WRITE(PLANE_WM_TRANS(pipe, i), + new->plane_trans[pipe][i]); + I915_WRITE(CUR_WM_TRANS(pipe), new->cursor_trans[pipe]); + + for (i = 0; i < intel_num_planes(crtc); i++) + skl_ddb_entry_write(dev_priv, + PLANE_BUF_CFG(pipe, i), + &new->ddb.plane[pipe][i]); + + skl_ddb_entry_write(dev_priv, CUR_BUF_CFG(pipe), + &new->ddb.cursor[pipe]); } } -- cgit v1.2.3 From 34bb56af7fae9d4d6a33bf6f5f915e75a4023e02 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Tue, 4 Nov 2014 17:07:01 +0000 Subject: drm/i915/skl: Stage the pipe DDB allocation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To correctly flush the new DDB allocation we need to know about the pipe allocation layout inside the DDB in order to sequence the re-allocation to not cause a newly allocated pipe to fetch from a space that was previously allocated to another pipe. This patch preserves the per-pipe (start,end) allocation to be used in the flush. Reviewed-by: Ville Syrjälä Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/intel_pm.c | 14 +++++++------- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index cf84b6d30eae..01d741d37a85 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1406,6 +1406,7 @@ static inline bool skl_ddb_entry_equal(const struct skl_ddb_entry *e1, } struct skl_ddb_allocation { + struct skl_ddb_entry pipe[I915_MAX_PIPES]; struct skl_ddb_entry plane[I915_MAX_PIPES][I915_MAX_PLANES]; struct skl_ddb_entry cursor[I915_MAX_PIPES]; }; diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 7fdccba93385..cd2b3351ff45 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3119,13 +3119,13 @@ skl_allocate_pipe_ddb(struct drm_crtc *crtc, struct drm_device *dev = crtc->dev; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); enum pipe pipe = intel_crtc->pipe; - struct skl_ddb_entry alloc; + struct skl_ddb_entry *alloc = &ddb->pipe[pipe]; uint16_t alloc_size, start, cursor_blocks; unsigned int total_data_rate; int plane; - skl_ddb_get_pipe_allocation_limits(dev, crtc, config, params, &alloc); - alloc_size = skl_ddb_entry_size(&alloc); + skl_ddb_get_pipe_allocation_limits(dev, crtc, config, params, alloc); + alloc_size = skl_ddb_entry_size(alloc); if (alloc_size == 0) { memset(ddb->plane[pipe], 0, sizeof(ddb->plane[pipe])); memset(&ddb->cursor[pipe], 0, sizeof(ddb->cursor[pipe])); @@ -3133,11 +3133,11 @@ skl_allocate_pipe_ddb(struct drm_crtc *crtc, } cursor_blocks = skl_cursor_allocation(config); - ddb->cursor[pipe].start = alloc.end - cursor_blocks; - ddb->cursor[pipe].end = alloc.end; + ddb->cursor[pipe].start = alloc->end - cursor_blocks; + ddb->cursor[pipe].end = alloc->end; alloc_size -= cursor_blocks; - alloc.end -= cursor_blocks; + alloc->end -= cursor_blocks; /* * Each active plane get a portion of the remaining space, in @@ -3147,7 +3147,7 @@ skl_allocate_pipe_ddb(struct drm_crtc *crtc, */ total_data_rate = skl_get_total_relative_data_rate(intel_crtc, params); - start = alloc.start; + start = alloc->start; for (plane = 0; plane < intel_num_planes(intel_crtc); plane++) { const struct intel_plane_wm_parameters *p; unsigned int data_rate; -- cgit v1.2.3 From 0e8fb7ba7ca5410b2a8adc7f19eeb229ed01a32e Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Tue, 4 Nov 2014 17:07:02 +0000 Subject: drm/i915/skl: Flush the WM configuration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When we write new values for the DDB allocation and WM parameters, we now need to trigger the double buffer update for the pipe to take the new configuration into account. As the DDB is a global resource shared between planes, enabling or disabling one plane will result in changes for all planes that are currently in use, thus the need write PLANE_SURF/CUR_BASE for more than the plane we're touching. v2: Don't wait for pipes that are off v3: Split the staging results structure to not exceed the 1Kb stack allocation in skl_update_wm() v4: Rework and document the algorithm after Ville found that it was all wrong. Reviewed-by: Ville Syrjälä Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 135 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 135 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index cd2b3351ff45..ec7b86bfe701 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3512,6 +3512,140 @@ static void skl_write_wm_values(struct drm_i915_private *dev_priv, } } +/* + * When setting up a new DDB allocation arrangement, we need to correctly + * sequence the times at which the new allocations for the pipes are taken into + * account or we'll have pipes fetching from space previously allocated to + * another pipe. + * + * Roughly the sequence looks like: + * 1. re-allocate the pipe(s) with the allocation being reduced and not + * overlapping with a previous light-up pipe (another way to put it is: + * pipes with their new allocation strickly included into their old ones). + * 2. re-allocate the other pipes that get their allocation reduced + * 3. allocate the pipes having their allocation increased + * + * Steps 1. and 2. are here to take care of the following case: + * - Initially DDB looks like this: + * | B | C | + * - enable pipe A. + * - pipe B has a reduced DDB allocation that overlaps with the old pipe C + * allocation + * | A | B | C | + * + * We need to sequence the re-allocation: C, B, A (and not B, C, A). + */ + +static void skl_wm_flush_pipe(struct drm_i915_private *dev_priv, enum pipe pipe) +{ + struct drm_device *dev = dev_priv->dev; + int plane; + + for_each_plane(pipe, plane) { + I915_WRITE(PLANE_SURF(pipe, plane), + I915_READ(PLANE_SURF(pipe, plane))); + } + I915_WRITE(CURBASE(pipe), I915_READ(CURBASE(pipe))); +} + +static bool +skl_ddb_allocation_included(const struct skl_ddb_allocation *old, + const struct skl_ddb_allocation *new, + enum pipe pipe) +{ + uint16_t old_size, new_size; + + old_size = skl_ddb_entry_size(&old->pipe[pipe]); + new_size = skl_ddb_entry_size(&new->pipe[pipe]); + + return old_size != new_size && + new->pipe[pipe].start >= old->pipe[pipe].start && + new->pipe[pipe].end <= old->pipe[pipe].end; +} + +static void skl_flush_wm_values(struct drm_i915_private *dev_priv, + struct skl_wm_values *new_values) +{ + struct drm_device *dev = dev_priv->dev; + struct skl_ddb_allocation *cur_ddb, *new_ddb; + bool reallocated[I915_MAX_PIPES] = {false, false, false}; + struct intel_crtc *crtc; + enum pipe pipe; + + new_ddb = &new_values->ddb; + cur_ddb = &dev_priv->wm.skl_hw.ddb; + + /* + * First pass: flush the pipes with the new allocation contained into + * the old space. + * + * We'll wait for the vblank on those pipes to ensure we can safely + * re-allocate the freed space without this pipe fetching from it. + */ + for_each_intel_crtc(dev, crtc) { + if (!crtc->active) + continue; + + pipe = crtc->pipe; + + if (!skl_ddb_allocation_included(cur_ddb, new_ddb, pipe)) + continue; + + skl_wm_flush_pipe(dev_priv, pipe); + intel_wait_for_vblank(dev, pipe); + + reallocated[pipe] = true; + } + + + /* + * Second pass: flush the pipes that are having their allocation + * reduced, but overlapping with a previous allocation. + * + * Here as well we need to wait for the vblank to make sure the freed + * space is not used anymore. + */ + for_each_intel_crtc(dev, crtc) { + if (!crtc->active) + continue; + + pipe = crtc->pipe; + + if (reallocated[pipe]) + continue; + + if (skl_ddb_entry_size(&new_ddb->pipe[pipe]) < + skl_ddb_entry_size(&cur_ddb->pipe[pipe])) { + skl_wm_flush_pipe(dev_priv, pipe); + intel_wait_for_vblank(dev, pipe); + } + + reallocated[pipe] = true; + } + + /* + * Third pass: flush the pipes that got more space allocated. + * + * We don't need to actively wait for the update here, next vblank + * will just get more DDB space with the correct WM values. + */ + for_each_intel_crtc(dev, crtc) { + if (!crtc->active) + continue; + + pipe = crtc->pipe; + + /* + * At this point, only the pipes more space than before are + * left to re-allocate. + */ + if (reallocated[pipe]) + continue; + + skl_wm_flush_pipe(dev_priv, pipe); + } +} + static bool skl_update_pipe_wm(struct drm_crtc *crtc, struct skl_pipe_wm_parameters *params, struct intel_wm_config *config, @@ -3603,6 +3737,7 @@ static void skl_update_wm(struct drm_crtc *crtc) skl_update_other_pipe_wm(dev, crtc, &config, results); skl_write_wm_values(dev_priv, results); + skl_flush_wm_values(dev_priv, results); /* store the new configuration */ dev_priv->wm.skl_hw = *results; -- cgit v1.2.3 From d21b795c419a7f59b4921b1ab5ff40d9a5eef05a Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Tue, 4 Nov 2014 17:07:03 +0000 Subject: drm/i915/skl: Log the order in which we flush the pipes in the WM code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Ville Syrjälä Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index ec7b86bfe701..d0dbd656eecb 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3536,11 +3536,14 @@ static void skl_write_wm_values(struct drm_i915_private *dev_priv, * We need to sequence the re-allocation: C, B, A (and not B, C, A). */ -static void skl_wm_flush_pipe(struct drm_i915_private *dev_priv, enum pipe pipe) +static void +skl_wm_flush_pipe(struct drm_i915_private *dev_priv, enum pipe pipe, int pass) { struct drm_device *dev = dev_priv->dev; int plane; + DRM_DEBUG_KMS("flush pipe %c (pass %d)\n", pipe_name(pipe), pass); + for_each_plane(pipe, plane) { I915_WRITE(PLANE_SURF(pipe, plane), I915_READ(PLANE_SURF(pipe, plane))); @@ -3591,7 +3594,7 @@ static void skl_flush_wm_values(struct drm_i915_private *dev_priv, if (!skl_ddb_allocation_included(cur_ddb, new_ddb, pipe)) continue; - skl_wm_flush_pipe(dev_priv, pipe); + skl_wm_flush_pipe(dev_priv, pipe, 1); intel_wait_for_vblank(dev, pipe); reallocated[pipe] = true; @@ -3616,7 +3619,7 @@ static void skl_flush_wm_values(struct drm_i915_private *dev_priv, if (skl_ddb_entry_size(&new_ddb->pipe[pipe]) < skl_ddb_entry_size(&cur_ddb->pipe[pipe])) { - skl_wm_flush_pipe(dev_priv, pipe); + skl_wm_flush_pipe(dev_priv, pipe, 2); intel_wait_for_vblank(dev, pipe); } @@ -3642,7 +3645,7 @@ static void skl_flush_wm_values(struct drm_i915_private *dev_priv, if (reallocated[pipe]) continue; - skl_wm_flush_pipe(dev_priv, pipe); + skl_wm_flush_pipe(dev_priv, pipe, 3); } } -- cgit v1.2.3 From 38cff0b15756dae3c7452618e6673f77d87e7220 Mon Sep 17 00:00:00 2001 From: Zhe Wang Date: Tue, 4 Nov 2014 17:07:04 +0000 Subject: drm/i915/skl: Gen9 Forcewake Implement common forcewake functions shared by Gen9 features. v2: Make the focewake_{get,put} functions static (Mika) Small coding style fix in the function definition (Damien) Reviewed-by: Mika Kuoppala Signed-off-by: Zhe Wang (v1) Signed-off-by: Damien Lespiau (v2) Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 5 +- drivers/gpu/drm/i915/i915_reg.h | 6 ++ drivers/gpu/drm/i915/intel_uncore.c | 175 +++++++++++++++++++++++++++++++++++- 3 files changed, 184 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 01d741d37a85..0f00e5830625 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -549,6 +549,7 @@ struct intel_uncore { unsigned fw_rendercount; unsigned fw_mediacount; + unsigned fw_blittercount; struct timer_list force_wake_timer; }; @@ -2979,7 +2980,9 @@ int vlv_freq_opcode(struct drm_i915_private *dev_priv, int val); #define FORCEWAKE_RENDER (1 << 0) #define FORCEWAKE_MEDIA (1 << 1) -#define FORCEWAKE_ALL (FORCEWAKE_RENDER | FORCEWAKE_MEDIA) +#define FORCEWAKE_BLITTER (1 << 2) +#define FORCEWAKE_ALL (FORCEWAKE_RENDER | FORCEWAKE_MEDIA | \ + FORCEWAKE_BLITTER) #define I915_READ8(reg) dev_priv->uncore.funcs.mmio_readb(dev_priv, (reg), true) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index ea22e09bd4c5..77461cec70fa 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -5833,6 +5833,12 @@ enum punit_power_well { #define VLV_GTLC_PW_MEDIA_STATUS_MASK (1 << 5) #define VLV_GTLC_PW_RENDER_STATUS_MASK (1 << 7) #define FORCEWAKE_MT 0xa188 /* multi-threaded */ +#define FORCEWAKE_MEDIA_GEN9 0xa270 +#define FORCEWAKE_RENDER_GEN9 0xa278 +#define FORCEWAKE_BLITTER_GEN9 0xa188 +#define FORCEWAKE_ACK_MEDIA_GEN9 0x0D88 +#define FORCEWAKE_ACK_RENDER_GEN9 0x0D84 +#define FORCEWAKE_ACK_BLITTER_GEN9 0x130044 #define FORCEWAKE_KERNEL 0x1 #define FORCEWAKE_USER 0x2 #define FORCEWAKE_MT_ACK 0x130040 diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index 94276419c13f..68e722b780a1 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -296,6 +296,154 @@ static void vlv_force_wake_put(struct drm_i915_private *dev_priv, int fw_engine) spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); } +static void __gen9_gt_force_wake_mt_reset(struct drm_i915_private *dev_priv) +{ + __raw_i915_write32(dev_priv, FORCEWAKE_RENDER_GEN9, + _MASKED_BIT_DISABLE(0xffff)); + + __raw_i915_write32(dev_priv, FORCEWAKE_MEDIA_GEN9, + _MASKED_BIT_DISABLE(0xffff)); + + __raw_i915_write32(dev_priv, FORCEWAKE_BLITTER_GEN9, + _MASKED_BIT_DISABLE(0xffff)); +} + +static void +__gen9_force_wake_get(struct drm_i915_private *dev_priv, int fw_engine) +{ + /* Check for Render Engine */ + if (FORCEWAKE_RENDER & fw_engine) { + if (wait_for_atomic((__raw_i915_read32(dev_priv, + FORCEWAKE_ACK_RENDER_GEN9) & + FORCEWAKE_KERNEL) == 0, + FORCEWAKE_ACK_TIMEOUT_MS)) + DRM_ERROR("Timed out: Render forcewake old ack to clear.\n"); + + __raw_i915_write32(dev_priv, FORCEWAKE_RENDER_GEN9, + _MASKED_BIT_ENABLE(FORCEWAKE_KERNEL)); + + if (wait_for_atomic((__raw_i915_read32(dev_priv, + FORCEWAKE_ACK_RENDER_GEN9) & + FORCEWAKE_KERNEL), + FORCEWAKE_ACK_TIMEOUT_MS)) + DRM_ERROR("Timed out: waiting for Render to ack.\n"); + } + + /* Check for Media Engine */ + if (FORCEWAKE_MEDIA & fw_engine) { + if (wait_for_atomic((__raw_i915_read32(dev_priv, + FORCEWAKE_ACK_MEDIA_GEN9) & + FORCEWAKE_KERNEL) == 0, + FORCEWAKE_ACK_TIMEOUT_MS)) + DRM_ERROR("Timed out: Media forcewake old ack to clear.\n"); + + __raw_i915_write32(dev_priv, FORCEWAKE_MEDIA_GEN9, + _MASKED_BIT_ENABLE(FORCEWAKE_KERNEL)); + + if (wait_for_atomic((__raw_i915_read32(dev_priv, + FORCEWAKE_ACK_MEDIA_GEN9) & + FORCEWAKE_KERNEL), + FORCEWAKE_ACK_TIMEOUT_MS)) + DRM_ERROR("Timed out: waiting for Media to ack.\n"); + } + + /* Check for Blitter Engine */ + if (FORCEWAKE_BLITTER & fw_engine) { + if (wait_for_atomic((__raw_i915_read32(dev_priv, + FORCEWAKE_ACK_BLITTER_GEN9) & + FORCEWAKE_KERNEL) == 0, + FORCEWAKE_ACK_TIMEOUT_MS)) + DRM_ERROR("Timed out: Blitter forcewake old ack to clear.\n"); + + __raw_i915_write32(dev_priv, FORCEWAKE_BLITTER_GEN9, + _MASKED_BIT_ENABLE(FORCEWAKE_KERNEL)); + + if (wait_for_atomic((__raw_i915_read32(dev_priv, + FORCEWAKE_ACK_BLITTER_GEN9) & + FORCEWAKE_KERNEL), + FORCEWAKE_ACK_TIMEOUT_MS)) + DRM_ERROR("Timed out: waiting for Blitter to ack.\n"); + } +} + +static void +__gen9_force_wake_put(struct drm_i915_private *dev_priv, int fw_engine) +{ + /* Check for Render Engine */ + if (FORCEWAKE_RENDER & fw_engine) + __raw_i915_write32(dev_priv, FORCEWAKE_RENDER_GEN9, + _MASKED_BIT_DISABLE(FORCEWAKE_KERNEL)); + + /* Check for Media Engine */ + if (FORCEWAKE_MEDIA & fw_engine) + __raw_i915_write32(dev_priv, FORCEWAKE_MEDIA_GEN9, + _MASKED_BIT_DISABLE(FORCEWAKE_KERNEL)); + + /* Check for Blitter Engine */ + if (FORCEWAKE_BLITTER & fw_engine) + __raw_i915_write32(dev_priv, FORCEWAKE_BLITTER_GEN9, + _MASKED_BIT_DISABLE(FORCEWAKE_KERNEL)); +} + +static void +gen9_force_wake_get(struct drm_i915_private *dev_priv, int fw_engine) +{ + unsigned long irqflags; + + spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); + + if (FORCEWAKE_RENDER & fw_engine) { + if (dev_priv->uncore.fw_rendercount++ == 0) + dev_priv->uncore.funcs.force_wake_get(dev_priv, + FORCEWAKE_RENDER); + } + + if (FORCEWAKE_MEDIA & fw_engine) { + if (dev_priv->uncore.fw_mediacount++ == 0) + dev_priv->uncore.funcs.force_wake_get(dev_priv, + FORCEWAKE_MEDIA); + } + + if (FORCEWAKE_BLITTER & fw_engine) { + if (dev_priv->uncore.fw_blittercount++ == 0) + dev_priv->uncore.funcs.force_wake_get(dev_priv, + FORCEWAKE_BLITTER); + } + + spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); +} + +static void +gen9_force_wake_put(struct drm_i915_private *dev_priv, int fw_engine) +{ + unsigned long irqflags; + + spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); + + if (FORCEWAKE_RENDER & fw_engine) { + WARN_ON(dev_priv->uncore.fw_rendercount == 0); + if (--dev_priv->uncore.fw_rendercount == 0) + dev_priv->uncore.funcs.force_wake_put(dev_priv, + FORCEWAKE_RENDER); + } + + if (FORCEWAKE_MEDIA & fw_engine) { + WARN_ON(dev_priv->uncore.fw_mediacount == 0); + if (--dev_priv->uncore.fw_mediacount == 0) + dev_priv->uncore.funcs.force_wake_put(dev_priv, + FORCEWAKE_MEDIA); + } + + if (FORCEWAKE_BLITTER & fw_engine) { + WARN_ON(dev_priv->uncore.fw_blittercount == 0); + if (--dev_priv->uncore.fw_blittercount == 0) + dev_priv->uncore.funcs.force_wake_put(dev_priv, + FORCEWAKE_BLITTER); + } + + spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); +} + static void gen6_force_wake_timer(unsigned long arg) { struct drm_i915_private *dev_priv = (void *)arg; @@ -334,6 +482,9 @@ void intel_uncore_forcewake_reset(struct drm_device *dev, bool restore) if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev) || IS_BROADWELL(dev)) __gen7_gt_force_wake_mt_reset(dev_priv); + if (IS_GEN9(dev)) + __gen9_gt_force_wake_mt_reset(dev_priv); + if (restore) { /* If reset with a user forcewake, try to restore */ unsigned fw = 0; @@ -343,6 +494,15 @@ void intel_uncore_forcewake_reset(struct drm_device *dev, bool restore) if (dev_priv->uncore.fw_mediacount) fw |= FORCEWAKE_MEDIA; + } else if (IS_GEN9(dev)) { + if (dev_priv->uncore.fw_rendercount) + fw |= FORCEWAKE_RENDER; + + if (dev_priv->uncore.fw_mediacount) + fw |= FORCEWAKE_MEDIA; + + if (dev_priv->uncore.fw_blittercount) + fw |= FORCEWAKE_BLITTER; } else { if (dev_priv->uncore.forcewake_count) fw = FORCEWAKE_ALL; @@ -414,6 +574,10 @@ void gen6_gt_force_wake_get(struct drm_i915_private *dev_priv, int fw_engine) intel_runtime_pm_get(dev_priv); + /* Redirect to Gen9 specific routine */ + if (IS_GEN9(dev_priv->dev)) + return gen9_force_wake_get(dev_priv, fw_engine); + /* Redirect to VLV specific routine */ if (IS_VALLEYVIEW(dev_priv->dev)) return vlv_force_wake_get(dev_priv, fw_engine); @@ -435,6 +599,12 @@ void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv, int fw_engine) if (!dev_priv->uncore.funcs.force_wake_put) return; + /* Redirect to Gen9 specific routine */ + if (IS_GEN9(dev_priv->dev)) { + gen9_force_wake_put(dev_priv, fw_engine); + goto out; + } + /* Redirect to VLV specific routine */ if (IS_VALLEYVIEW(dev_priv->dev)) { vlv_force_wake_put(dev_priv, fw_engine); @@ -855,7 +1025,10 @@ void intel_uncore_init(struct drm_device *dev) __intel_uncore_early_sanitize(dev, false); - if (IS_VALLEYVIEW(dev)) { + if (IS_GEN9(dev)) { + dev_priv->uncore.funcs.force_wake_get = __gen9_force_wake_get; + dev_priv->uncore.funcs.force_wake_put = __gen9_force_wake_put; + } else if (IS_VALLEYVIEW(dev)) { dev_priv->uncore.funcs.force_wake_get = __vlv_force_wake_get; dev_priv->uncore.funcs.force_wake_put = __vlv_force_wake_put; } else if (IS_HASWELL(dev) || IS_BROADWELL(dev)) { -- cgit v1.2.3 From 20e4936693ea8a727e35d0f2b840670a0576b706 Mon Sep 17 00:00:00 2001 From: Zhe Wang Date: Tue, 4 Nov 2014 17:07:05 +0000 Subject: drm/i915/skl: Enable Gen9 RC6 Configure and enable RC6 for Gen9. v2: Rebase on top of BDW rc6 support (Damien) Reviewed-by: Mika Kuoppala Signed-off-by: Zhe Wang Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 52 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index d0dbd656eecb..300d7e503f96 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4539,6 +4539,13 @@ static void gen8_disable_rps_interrupts(struct drm_device *dev) I915_WRITE(GEN8_GT_IIR(2), dev_priv->pm_rps_events); } +static void gen9_disable_rps(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + I915_WRITE(GEN6_RC_CONTROL, 0); +} + static void gen6_disable_rps_interrupts(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -4699,6 +4706,45 @@ static void parse_rp_state_cap(struct drm_i915_private *dev_priv, u32 rp_state_c dev_priv->rps.min_freq_softlimit = dev_priv->rps.min_freq; } +static void gen9_enable_rps(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_engine_cs *ring; + uint32_t rc6_mask = 0; + int unused; + + /* 1a: Software RC state - RC0 */ + I915_WRITE(GEN6_RC_STATE, 0); + + /* 1b: Get forcewake during program sequence. Although the driver + * hasn't enabled a state yet where we need forcewake, BIOS may have.*/ + gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL); + + /* 2a: Disable RC states. */ + I915_WRITE(GEN6_RC_CONTROL, 0); + + /* 2b: Program RC6 thresholds.*/ + I915_WRITE(GEN6_RC6_WAKE_RATE_LIMIT, 54 << 16); + I915_WRITE(GEN6_RC_EVALUATION_INTERVAL, 125000); /* 12500 * 1280ns */ + I915_WRITE(GEN6_RC_IDLE_HYSTERSIS, 25); /* 25 * 1280ns */ + for_each_ring(ring, dev_priv, unused) + I915_WRITE(RING_MAX_IDLE(ring->mmio_base), 10); + I915_WRITE(GEN6_RC_SLEEP, 0); + I915_WRITE(GEN6_RC6_THRESHOLD, 37500); /* 37.5/125ms per EI */ + + /* 3a: Enable RC6 */ + if (intel_enable_rc6(dev) & INTEL_RC6_ENABLE) + rc6_mask = GEN6_RC_CTL_RC6_ENABLE; + DRM_INFO("RC6 %s\n", (rc6_mask & GEN6_RC_CTL_RC6_ENABLE) ? + "on" : "off"); + I915_WRITE(GEN6_RC_CONTROL, GEN6_RC_CTL_HW_ENABLE | + GEN6_RC_CTL_EI_MODE(1) | + rc6_mask); + + gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL); + +} + static void gen8_enable_rps(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -6233,7 +6279,9 @@ void intel_disable_gt_powersave(struct drm_device *dev) intel_suspend_gt_powersave(dev); mutex_lock(&dev_priv->rps.hw_lock); - if (IS_CHERRYVIEW(dev)) + if (INTEL_INFO(dev)->gen >= 9) + gen9_disable_rps(dev); + else if (IS_CHERRYVIEW(dev)) cherryview_disable_rps(dev); else if (IS_VALLEYVIEW(dev)) valleyview_disable_rps(dev); @@ -6257,6 +6305,8 @@ static void intel_gen6_powersave_work(struct work_struct *work) cherryview_enable_rps(dev); } else if (IS_VALLEYVIEW(dev)) { valleyview_enable_rps(dev); + } else if (INTEL_INFO(dev)->gen >= 9) { + gen9_enable_rps(dev); } else if (IS_BROADWELL(dev)) { gen8_enable_rps(dev); __gen6_update_ring_freq(dev); -- cgit v1.2.3 From c6bde93b922586245ba1083c35b1139d6498eabb Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 4 Nov 2014 10:31:28 +0200 Subject: drm/i915/audio: rewrite vlv/chv and gen 5-7 audio codec enable sequence Similar to the hsw/bdw enable sequence rewrite. v3: replace vblank wait with a comment v4: expand the comment on what should be done with the vblank wait Signed-off-by: Jani Nikula Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_audio.c | 63 +++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 32 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c index 4dcfc46d5725..8759fc509783 100644 --- a/drivers/gpu/drm/i915/intel_audio.c +++ b/drivers/gpu/drm/i915/intel_audio.c @@ -215,6 +215,10 @@ static void ilk_audio_codec_enable(struct drm_connector *connector, { struct drm_i915_private *dev_priv = connector->dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); + struct intel_digital_port *intel_dig_port = + enc_to_dig_port(&encoder->base); + enum port port = intel_dig_port->port; + enum pipe pipe = intel_crtc->pipe; uint8_t *eld = connector->eld; uint32_t eldv; uint32_t tmp; @@ -223,8 +227,16 @@ static void ilk_audio_codec_enable(struct drm_connector *connector, int aud_config; int aud_cntl_st; int aud_cntrl_st2; - enum pipe pipe = intel_crtc->pipe; - enum port port; + + DRM_DEBUG_KMS("Enable audio codec on port %c, pipe %c, %u bytes ELD\n", + port_name(port), pipe_name(pipe), eld[2]); + + /* + * FIXME: We're supposed to wait for vblank here, but we have vblanks + * disabled during the mode set. The proper fix would be to push the + * rest of the setup into a vblank work item, queued here, but the + * infrastructure is not there yet. + */ if (HAS_PCH_IBX(connector->dev)) { hdmiw_hdmiedid = IBX_HDMIW_HDMIEDID(pipe); @@ -243,57 +255,44 @@ static void ilk_audio_codec_enable(struct drm_connector *connector, aud_cntrl_st2 = CPT_AUD_CNTRL_ST2; } - DRM_DEBUG_DRIVER("ELD on pipe %c\n", pipe_name(pipe)); - - if (IS_VALLEYVIEW(connector->dev)) { - struct intel_digital_port *intel_dig_port; - - intel_dig_port = enc_to_dig_port(&encoder->base); - port = intel_dig_port->port; - } else { - tmp = I915_READ(aud_cntl_st); - port = (tmp >> 29) & DIP_PORT_SEL_MASK; - /* DIP_Port_Select, 0x1 = PortB */ - } - - if (!port) { - DRM_DEBUG_DRIVER("Audio directed to unknown port\n"); - /* operate blindly on all ports */ + if (WARN_ON(!port)) { eldv = IBX_ELD_VALIDB; eldv |= IBX_ELD_VALIDB << 4; eldv |= IBX_ELD_VALIDB << 8; } else { - DRM_DEBUG_DRIVER("ELD on port %c\n", port_name(port)); eldv = IBX_ELD_VALIDB << ((port - 1) * 4); } - if (intel_pipe_has_type(intel_crtc, INTEL_OUTPUT_DISPLAYPORT)) - I915_WRITE(aud_config, AUD_CONFIG_N_VALUE_INDEX); /* 0x1 = DP */ - else - I915_WRITE(aud_config, audio_config_hdmi_pixel_clock(mode)); - - if (intel_eld_uptodate(connector, - aud_cntrl_st2, eldv, - aud_cntl_st, IBX_ELD_ADDRESS_MASK, - hdmiw_hdmiedid)) - return; - + /* Invalidate ELD */ tmp = I915_READ(aud_cntrl_st2); tmp &= ~eldv; I915_WRITE(aud_cntrl_st2, tmp); + /* Reset ELD write address */ tmp = I915_READ(aud_cntl_st); tmp &= ~IBX_ELD_ADDRESS_MASK; I915_WRITE(aud_cntl_st, tmp); - len = min_t(int, eld[2], 21); /* 84 bytes of hw ELD buffer */ - DRM_DEBUG_DRIVER("ELD size %d\n", len); + /* Up to 84 bytes of hw ELD buffer */ + len = min_t(int, eld[2], 21); for (i = 0; i < len; i++) I915_WRITE(hdmiw_hdmiedid, *((uint32_t *)eld + i)); + /* ELD valid */ tmp = I915_READ(aud_cntrl_st2); tmp |= eldv; I915_WRITE(aud_cntrl_st2, tmp); + + /* Enable timestamps */ + tmp = I915_READ(aud_config); + tmp &= ~AUD_CONFIG_N_VALUE_INDEX; + tmp &= ~AUD_CONFIG_N_PROG_ENABLE; + tmp &= ~AUD_CONFIG_PIXEL_CLOCK_HDMI_MASK; + if (intel_pipe_has_type(intel_crtc, INTEL_OUTPUT_DISPLAYPORT)) + tmp |= AUD_CONFIG_N_VALUE_INDEX; + else + tmp |= audio_config_hdmi_pixel_clock(mode); + I915_WRITE(aud_config, tmp); } /** -- cgit v1.2.3 From 495a5bb81d3469495d81dbec6290dbb1dfebd673 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 27 Oct 2014 16:26:55 +0200 Subject: drm/i915/audio: add vlv/chv/gen5-7 audio codec disable sequence Add support for disabling the audio codec on vlv/chv/gen5-7, similar to hsw/bdw. Signed-off-by: Jani Nikula Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_audio.c | 52 ++++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_dp.c | 4 +++ drivers/gpu/drm/i915/intel_hdmi.c | 4 +++ 3 files changed, 60 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c index 8759fc509783..5c2d06c71ae7 100644 --- a/drivers/gpu/drm/i915/intel_audio.c +++ b/drivers/gpu/drm/i915/intel_audio.c @@ -209,6 +209,56 @@ static void hsw_audio_codec_enable(struct drm_connector *connector, I915_WRITE(HSW_AUD_CFG(pipe), tmp); } +static void ilk_audio_codec_disable(struct intel_encoder *encoder) +{ + struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); + struct intel_digital_port *intel_dig_port = + enc_to_dig_port(&encoder->base); + enum port port = intel_dig_port->port; + enum pipe pipe = intel_crtc->pipe; + uint32_t tmp, eldv; + int aud_config; + int aud_cntrl_st2; + + DRM_DEBUG_KMS("Disable audio codec on port %c, pipe %c\n", + port_name(port), pipe_name(pipe)); + + if (HAS_PCH_IBX(dev_priv->dev)) { + aud_config = IBX_AUD_CFG(pipe); + aud_cntrl_st2 = IBX_AUD_CNTL_ST2; + } else if (IS_VALLEYVIEW(dev_priv)) { + aud_config = VLV_AUD_CFG(pipe); + aud_cntrl_st2 = VLV_AUD_CNTL_ST2; + } else { + aud_config = CPT_AUD_CFG(pipe); + aud_cntrl_st2 = CPT_AUD_CNTRL_ST2; + } + + /* Disable timestamps */ + tmp = I915_READ(aud_config); + tmp &= ~AUD_CONFIG_N_VALUE_INDEX; + tmp |= AUD_CONFIG_N_PROG_ENABLE; + tmp &= ~AUD_CONFIG_UPPER_N_MASK; + tmp &= ~AUD_CONFIG_LOWER_N_MASK; + if (intel_pipe_has_type(intel_crtc, INTEL_OUTPUT_DISPLAYPORT)) + tmp |= AUD_CONFIG_N_VALUE_INDEX; + I915_WRITE(aud_config, tmp); + + if (WARN_ON(!port)) { + eldv = IBX_ELD_VALIDB; + eldv |= IBX_ELD_VALIDB << 4; + eldv |= IBX_ELD_VALIDB << 8; + } else { + eldv = IBX_ELD_VALIDB << ((port - 1) * 4); + } + + /* Invalidate ELD */ + tmp = I915_READ(aud_cntrl_st2); + tmp &= ~eldv; + I915_WRITE(aud_cntrl_st2, tmp); +} + static void ilk_audio_codec_enable(struct drm_connector *connector, struct intel_encoder *encoder, struct drm_display_mode *mode) @@ -360,10 +410,12 @@ void intel_init_audio(struct drm_device *dev) dev_priv->display.audio_codec_enable = g4x_audio_codec_enable; } else if (IS_VALLEYVIEW(dev)) { dev_priv->display.audio_codec_enable = ilk_audio_codec_enable; + dev_priv->display.audio_codec_disable = ilk_audio_codec_disable; } else if (IS_HASWELL(dev) || INTEL_INFO(dev)->gen >= 8) { dev_priv->display.audio_codec_enable = hsw_audio_codec_enable; dev_priv->display.audio_codec_disable = hsw_audio_codec_disable; } else if (HAS_PCH_SPLIT(dev)) { dev_priv->display.audio_codec_enable = ilk_audio_codec_enable; + dev_priv->display.audio_codec_disable = ilk_audio_codec_disable; } } diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 5f2c206aef13..f48a1aae2b65 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -2454,6 +2454,10 @@ static void intel_disable_dp(struct intel_encoder *encoder) { struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base); struct drm_device *dev = encoder->base.dev; + struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc); + + if (crtc->config.has_audio) + intel_audio_codec_disable(encoder); /* Make sure the panel is off before trying to change the mode. But also * ensure that we have vdd while we switch off the panel. */ diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index f29026a1157d..f89f71e1f2ce 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -802,9 +802,13 @@ static void intel_disable_hdmi(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); + struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc); u32 temp; u32 enable_bits = SDVO_ENABLE | SDVO_AUDIO_ENABLE; + if (crtc->config.has_audio) + intel_audio_codec_disable(encoder); + temp = I915_READ(intel_hdmi->hdmi_reg); /* HW workaround for IBX, we need to move the port to transcoder A -- cgit v1.2.3 From c1dec79aaee69042986247658ffdf51ee81017c2 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 27 Oct 2014 16:26:56 +0200 Subject: drm/i915: enable audio codec after port As per spec, and similar to DDI. Signed-off-by: Jani Nikula Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 13 ++++++++----- drivers/gpu/drm/i915/intel_hdmi.c | 15 +++++++-------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index f48a1aae2b65..464eea0f7136 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1324,12 +1324,8 @@ static void intel_dp_prepare(struct intel_encoder *encoder) intel_dp->DP |= DP_VOLTAGE_0_4 | DP_PRE_EMPHASIS_0; intel_dp->DP |= DP_PORT_WIDTH(intel_dp->lane_count); - if (crtc->config.has_audio) { - DRM_DEBUG_DRIVER("Enabling DP audio on pipe %c\n", - pipe_name(crtc->pipe)); + if (crtc->config.has_audio) intel_dp->DP |= DP_AUDIO_OUTPUT_ENABLE; - intel_audio_codec_enable(encoder); - } /* Split out the IBX/CPU vs CPT settings */ @@ -2636,6 +2632,7 @@ static void intel_enable_dp(struct intel_encoder *encoder) struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base); struct drm_device *dev = encoder->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc); uint32_t dp_reg = I915_READ(intel_dp->output_reg); if (WARN_ON(dp_reg & DP_PORT_EN)) @@ -2661,6 +2658,12 @@ static void intel_enable_dp(struct intel_encoder *encoder) intel_dp_start_link_train(intel_dp); intel_dp_complete_link_train(intel_dp); intel_dp_stop_link_train(intel_dp); + + if (crtc->config.has_audio) { + DRM_DEBUG_DRIVER("Enabling DP audio on pipe %c\n", + pipe_name(crtc->pipe)); + intel_audio_codec_enable(encoder); + } } static void g4x_enable_dp(struct intel_encoder *encoder) diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index f89f71e1f2ce..29baa53aef90 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -661,14 +661,6 @@ static void intel_hdmi_prepare(struct intel_encoder *encoder) if (crtc->config.has_hdmi_sink) hdmi_val |= HDMI_MODE_SELECT_HDMI; - if (crtc->config.has_audio) { - WARN_ON(!crtc->config.has_hdmi_sink); - DRM_DEBUG_DRIVER("Enabling HDMI audio on pipe %c\n", - pipe_name(crtc->pipe)); - hdmi_val |= SDVO_AUDIO_ENABLE; - intel_audio_codec_enable(encoder); - } - if (HAS_PCH_CPT(dev)) hdmi_val |= SDVO_PIPE_SEL_CPT(crtc->pipe); else if (IS_CHERRYVIEW(dev)) @@ -791,6 +783,13 @@ static void intel_enable_hdmi(struct intel_encoder *encoder) I915_WRITE(intel_hdmi->hdmi_reg, temp); POSTING_READ(intel_hdmi->hdmi_reg); } + + if (intel_crtc->config.has_audio) { + WARN_ON(!intel_crtc->config.has_hdmi_sink); + DRM_DEBUG_DRIVER("Enabling HDMI audio on pipe %c\n", + pipe_name(intel_crtc->pipe)); + intel_audio_codec_enable(encoder); + } } static void vlv_enable_hdmi(struct intel_encoder *encoder) -- cgit v1.2.3 From 76d8d3e5b57d7938613e4018eddbf0a16913338a Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 27 Oct 2014 16:26:57 +0200 Subject: drm/i915/audio: add audio codec disable on g4x This not based on any documentation... Signed-off-by: Jani Nikula Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_audio.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c index 5c2d06c71ae7..fa0eecf6a792 100644 --- a/drivers/gpu/drm/i915/intel_audio.c +++ b/drivers/gpu/drm/i915/intel_audio.c @@ -93,6 +93,25 @@ static bool intel_eld_uptodate(struct drm_connector *connector, return true; } +static void g4x_audio_codec_disable(struct intel_encoder *encoder) +{ + struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; + uint32_t eldv, tmp; + + DRM_DEBUG_KMS("Disable audio codec\n"); + + tmp = I915_READ(G4X_AUD_VID_DID); + if (tmp == INTEL_AUDIO_DEVBLC || tmp == INTEL_AUDIO_DEVCL) + eldv = G4X_ELDV_DEVCL_DEVBLC; + else + eldv = G4X_ELDV_DEVCTG; + + /* Invalidate ELD */ + tmp = I915_READ(G4X_AUD_CNTL_ST); + tmp &= ~eldv; + I915_WRITE(G4X_AUD_CNTL_ST, tmp); +} + static void g4x_audio_codec_enable(struct drm_connector *connector, struct intel_encoder *encoder, struct drm_display_mode *mode) @@ -408,6 +427,7 @@ void intel_init_audio(struct drm_device *dev) if (IS_G4X(dev)) { dev_priv->display.audio_codec_enable = g4x_audio_codec_enable; + dev_priv->display.audio_codec_disable = g4x_audio_codec_disable; } else if (IS_VALLEYVIEW(dev)) { dev_priv->display.audio_codec_enable = ilk_audio_codec_enable; dev_priv->display.audio_codec_disable = ilk_audio_codec_disable; -- cgit v1.2.3 From d5ee08de1bbeac867818c37b5b8413f68c742703 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 27 Oct 2014 16:26:58 +0200 Subject: drm/i915/audio: add audio codec enable debug log for g4x Signed-off-by: Jani Nikula Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_audio.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c index fa0eecf6a792..c4c036a86d75 100644 --- a/drivers/gpu/drm/i915/intel_audio.c +++ b/drivers/gpu/drm/i915/intel_audio.c @@ -122,6 +122,8 @@ static void g4x_audio_codec_enable(struct drm_connector *connector, uint32_t tmp; int len, i; + DRM_DEBUG_KMS("Enable audio codec, %u bytes ELD\n", eld[2]); + tmp = I915_READ(G4X_AUD_VID_DID); if (tmp == INTEL_AUDIO_DEVBLC || tmp == INTEL_AUDIO_DEVCL) eldv = G4X_ELDV_DEVCL_DEVBLC; -- cgit v1.2.3 From 82910ac6d575d4ce4bd4dcefb61923623b263e00 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 27 Oct 2014 16:26:59 +0200 Subject: drm/i915: make pipe/port based audio valid accessors easier to use Signed-off-by: Jani Nikula Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 20 ++++++-------------- drivers/gpu/drm/i915/intel_audio.c | 22 ++++++++++------------ drivers/gpu/drm/i915/intel_ddi.c | 2 +- 3 files changed, 17 insertions(+), 27 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 77461cec70fa..b250d96ab7a1 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -6102,8 +6102,8 @@ enum punit_power_well { #define IBX_ELD_ADDRESS_MASK (0x1f << 5) #define IBX_ELD_ACK (1 << 4) #define IBX_AUD_CNTL_ST2 0xE20C0 -#define IBX_ELD_VALIDB (1 << 0) -#define IBX_CP_READYB (1 << 1) +#define IBX_CP_READY(port) ((1 << 1) << (((port) - 1) * 4)) +#define IBX_ELD_VALID(port) ((1 << 0) << (((port) - 1) * 4)) #define _CPT_HDMIW_HDMIEDID_A 0xE5050 #define _CPT_HDMIW_HDMIEDID_B 0xE5150 @@ -6206,18 +6206,10 @@ enum punit_power_well { #define HSW_AUD_PIPE_CONV_CFG 0x6507c #define HSW_AUD_PIN_ELD_CP_VLD 0x650c0 -#define AUDIO_INACTIVE_C (1<<11) -#define AUDIO_INACTIVE_B (1<<7) -#define AUDIO_INACTIVE_A (1<<3) -#define AUDIO_OUTPUT_ENABLE_A (1<<2) -#define AUDIO_OUTPUT_ENABLE_B (1<<6) -#define AUDIO_OUTPUT_ENABLE_C (1<<10) -#define AUDIO_ELD_VALID_A (1<<0) -#define AUDIO_ELD_VALID_B (1<<4) -#define AUDIO_ELD_VALID_C (1<<8) -#define AUDIO_CP_READY_A (1<<1) -#define AUDIO_CP_READY_B (1<<5) -#define AUDIO_CP_READY_C (1<<9) +#define AUDIO_INACTIVE(trans) ((1 << 3) << ((trans) * 4)) +#define AUDIO_OUTPUT_ENABLE(trans) ((1 << 2) << ((trans) * 4)) +#define AUDIO_CP_READY(trans) ((1 << 1) << ((trans) * 4)) +#define AUDIO_ELD_VALID(trans) ((1 << 0) << ((trans) * 4)) /* HSW Power Wells */ #define HSW_PWR_WELL_BIOS 0x45400 /* CTL1 */ diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c index c4c036a86d75..9181b85d86c4 100644 --- a/drivers/gpu/drm/i915/intel_audio.c +++ b/drivers/gpu/drm/i915/intel_audio.c @@ -172,7 +172,7 @@ static void hsw_audio_codec_disable(struct intel_encoder *encoder) /* Invalidate ELD */ tmp = I915_READ(HSW_AUD_PIN_ELD_CP_VLD); - tmp &= ~(AUDIO_ELD_VALID_A << (pipe * 4)); + tmp &= ~AUDIO_ELD_VALID(pipe); I915_WRITE(HSW_AUD_PIN_ELD_CP_VLD, tmp); } @@ -192,8 +192,8 @@ static void hsw_audio_codec_enable(struct drm_connector *connector, /* Enable audio presence detect, invalidate ELD */ tmp = I915_READ(HSW_AUD_PIN_ELD_CP_VLD); - tmp |= AUDIO_OUTPUT_ENABLE_A << (pipe * 4); - tmp &= ~(AUDIO_ELD_VALID_A << (pipe * 4)); + tmp |= AUDIO_OUTPUT_ENABLE(pipe); + tmp &= ~AUDIO_ELD_VALID(pipe); I915_WRITE(HSW_AUD_PIN_ELD_CP_VLD, tmp); /* @@ -215,7 +215,7 @@ static void hsw_audio_codec_enable(struct drm_connector *connector, /* ELD valid */ tmp = I915_READ(HSW_AUD_PIN_ELD_CP_VLD); - tmp |= AUDIO_ELD_VALID_A << (pipe * 4); + tmp |= AUDIO_ELD_VALID(pipe); I915_WRITE(HSW_AUD_PIN_ELD_CP_VLD, tmp); /* Enable timestamps */ @@ -267,11 +267,10 @@ static void ilk_audio_codec_disable(struct intel_encoder *encoder) I915_WRITE(aud_config, tmp); if (WARN_ON(!port)) { - eldv = IBX_ELD_VALIDB; - eldv |= IBX_ELD_VALIDB << 4; - eldv |= IBX_ELD_VALIDB << 8; + eldv = IBX_ELD_VALID(PORT_B) | IBX_ELD_VALID(PORT_C) | + IBX_ELD_VALID(PORT_D); } else { - eldv = IBX_ELD_VALIDB << ((port - 1) * 4); + eldv = IBX_ELD_VALID(port); } /* Invalidate ELD */ @@ -327,11 +326,10 @@ static void ilk_audio_codec_enable(struct drm_connector *connector, } if (WARN_ON(!port)) { - eldv = IBX_ELD_VALIDB; - eldv |= IBX_ELD_VALIDB << 4; - eldv |= IBX_ELD_VALIDB << 8; + eldv = IBX_ELD_VALID(PORT_B) | IBX_ELD_VALID(PORT_C) | + IBX_ELD_VALID(PORT_D); } else { - eldv = IBX_ELD_VALIDB << ((port - 1) * 4); + eldv = IBX_ELD_VALID(port); } /* Invalidate ELD */ diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index a50df351d558..68703cecdefc 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1523,7 +1523,7 @@ void intel_ddi_get_config(struct intel_encoder *encoder, if (intel_display_power_is_enabled(dev_priv, POWER_DOMAIN_AUDIO)) { temp = I915_READ(HSW_AUD_PIN_ELD_CP_VLD); - if (temp & (AUDIO_OUTPUT_ENABLE_A << (intel_crtc->pipe * 4))) + if (temp & AUDIO_OUTPUT_ENABLE(intel_crtc->pipe)) pipe_config->has_audio = true; } -- cgit v1.2.3 From 28855d2ac349b3fbb285c38493429dd1aa503523 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 27 Oct 2014 16:27:00 +0200 Subject: drm/i915/audio: add DOC comment describing HDA over HDMI/DP v2: include the section in the drm docbook. Signed-off-by: Jani Nikula Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- Documentation/DocBook/drm.tmpl | 5 +++++ drivers/gpu/drm/i915/intel_audio.c | 21 +++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index f6a9d7b21380..01b8ca5f1a3d 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -3854,6 +3854,11 @@ int num_ioctls; probing, so those sections fully apply. + + High Definition Audio +!Pdrivers/gpu/drm/i915/intel_audio.c High Definition Audio over HDMI and Display Port +!Idrivers/gpu/drm/i915/intel_audio.c + DPIO !Pdrivers/gpu/drm/i915/i915_reg.h DPIO diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c index 9181b85d86c4..44c49dfe1096 100644 --- a/drivers/gpu/drm/i915/intel_audio.c +++ b/drivers/gpu/drm/i915/intel_audio.c @@ -28,6 +28,27 @@ #include "intel_drv.h" #include "i915_drv.h" +/** + * DOC: High Definition Audio over HDMI and Display Port + * + * The graphics and audio drivers together support High Definition Audio over + * HDMI and Display Port. The audio programming sequences are divided into audio + * codec and controller enable and disable sequences. The graphics driver + * handles the audio codec sequences, while the audio driver handles the audio + * controller sequences. + * + * The disable sequences must be performed before disabling the transcoder or + * port. The enable sequences may only be performed after enabling the + * transcoder and port, and after completed link training. + * + * The codec and controller sequences could be done either parallel or serial, + * but generally the ELDV/PD change in the codec sequence indicates to the audio + * driver that the controller sequence should start. Indeed, most of the + * co-operation between the graphics and audio drivers is handled via audio + * related registers. (The notable exception is the power management, not + * covered here.) + */ + static const struct { int clock; u32 config; -- cgit v1.2.3 From 50f6e502718fd187f8e11a7b5048b21f85ac77e4 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Thu, 6 Nov 2014 14:49:12 +0200 Subject: drm/i915: Move the .global_resources() hook call into modeset_update_crtc_power_domains() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We may need to access various hardware bits in the .global_resources() hook, so move the call to occur after enabling all the newly required power wells, but before disabling all the now unneeded wells. This should guarantee that we have all the sufficient hardware resources available during the .global_resources() call. And if not, any additional resources must be explicitly acquired by the .global_resorces() hook. For instance on VLV/CHV we need to access the gunit mailbox so that we can talk to punit/cck over sideband. In addition some PFI credit reprogramming may need to be addes as well, which may require the disp2d well. This should also make the power domain refcounts consistent on platforms which don't have a .global_resource() hook since now they too will call modeset_update_crtc_power_domains() which will drop the init power. Previously init power was just left enabled for such platforms. Cc: Imre Deak Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 25 ++++--------------------- 1 file changed, 4 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 07fb0ff66f5d..18ad2bc8550b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4683,6 +4683,9 @@ static void modeset_update_crtc_power_domains(struct drm_device *dev) intel_display_power_get(dev_priv, domain); } + if (dev_priv->display.modeset_global_resources) + dev_priv->display.modeset_global_resources(dev); + for_each_intel_crtc(dev, crtc) { enum intel_display_power_domain domain; @@ -4910,8 +4913,6 @@ static void valleyview_modeset_global_resources(struct drm_device *dev) else valleyview_set_cdclk(dev, req_cdclk); } - - modeset_update_crtc_power_domains(dev); } static void valleyview_crtc_enable(struct drm_crtc *crtc) @@ -7950,16 +7951,6 @@ void hsw_disable_pc8(struct drm_i915_private *dev_priv) intel_prepare_ddi(dev); } -static void snb_modeset_global_resources(struct drm_device *dev) -{ - modeset_update_crtc_power_domains(dev); -} - -static void haswell_modeset_global_resources(struct drm_device *dev) -{ - modeset_update_crtc_power_domains(dev); -} - static int haswell_crtc_compute_clock(struct intel_crtc *crtc) { if (!intel_ddi_pll_select(crtc)) @@ -10917,8 +10908,7 @@ static int __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); + modeset_update_crtc_power_domains(dev); /* Set up the DPLL and any encoders state that needs to adjust or depend * on the DPLL. @@ -12589,8 +12579,6 @@ static void intel_init_display(struct drm_device *dev) dev_priv->display.fdi_link_train = ironlake_fdi_link_train; } else if (IS_GEN6(dev)) { dev_priv->display.fdi_link_train = gen6_fdi_link_train; - dev_priv->display.modeset_global_resources = - snb_modeset_global_resources; } else if (IS_IVYBRIDGE(dev)) { /* FIXME: detect B0+ stepping and use auto training */ dev_priv->display.fdi_link_train = ivb_manual_fdi_link_train; @@ -12598,14 +12586,9 @@ static void intel_init_display(struct drm_device *dev) ivb_modeset_global_resources; } else if (IS_HASWELL(dev) || IS_BROADWELL(dev)) { dev_priv->display.fdi_link_train = hsw_fdi_link_train; - dev_priv->display.modeset_global_resources = - haswell_modeset_global_resources; } else if (IS_VALLEYVIEW(dev)) { dev_priv->display.modeset_global_resources = valleyview_modeset_global_resources; - } else if (INTEL_INFO(dev)->gen >= 9) { - dev_priv->display.modeset_global_resources = - haswell_modeset_global_resources; } /* Default just returns -ENODEV to indicate unsupported */ -- cgit v1.2.3 From 16e9a21f33cda9d48b70ff54e1ed2e4a77497bc6 Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Thu, 6 Nov 2014 09:26:38 +0200 Subject: drm/i915: Make __wait_seqno non-static and rename to __i915_wait_seqno So that it can be used by the flip code to wait for rendering without holding any locks. Signed-off-by: Ander Conselvan de Oliveira Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 5 +++++ drivers/gpu/drm/i915/i915_gem.c | 20 +++++++++++--------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 0f00e5830625..2dc888ca3394 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2595,6 +2595,11 @@ int __i915_add_request(struct intel_engine_cs *ring, u32 *seqno); #define i915_add_request(ring, seqno) \ __i915_add_request(ring, NULL, NULL, seqno) +int __i915_wait_seqno(struct intel_engine_cs *ring, u32 seqno, + unsigned reset_counter, + bool interruptible, + s64 *timeout, + struct drm_i915_file_private *file_priv); int __must_check i915_wait_seqno(struct intel_engine_cs *ring, uint32_t seqno); int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 1de94cc63517..3e0cabe9b544 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1134,7 +1134,7 @@ static bool can_wait_boost(struct drm_i915_file_private *file_priv) } /** - * __wait_seqno - wait until execution of seqno has finished + * __i915_wait_seqno - wait until execution of seqno has finished * @ring: the ring expected to report seqno * @seqno: duh! * @reset_counter: reset sequence associated with the given seqno @@ -1151,7 +1151,7 @@ static bool can_wait_boost(struct drm_i915_file_private *file_priv) * Returns 0 if the seqno was found within the alloted time. Else returns the * errno with remaining time filled in timeout argument. */ -static int __wait_seqno(struct intel_engine_cs *ring, u32 seqno, +int __i915_wait_seqno(struct intel_engine_cs *ring, u32 seqno, unsigned reset_counter, bool interruptible, s64 *timeout, @@ -1262,6 +1262,7 @@ i915_wait_seqno(struct intel_engine_cs *ring, uint32_t seqno) struct drm_device *dev = ring->dev; struct drm_i915_private *dev_priv = dev->dev_private; bool interruptible = dev_priv->mm.interruptible; + unsigned reset_counter; int ret; BUG_ON(!mutex_is_locked(&dev->struct_mutex)); @@ -1275,9 +1276,9 @@ i915_wait_seqno(struct intel_engine_cs *ring, uint32_t seqno) if (ret) return ret; - return __wait_seqno(ring, seqno, - atomic_read(&dev_priv->gpu_error.reset_counter), - interruptible, NULL, NULL); + reset_counter = atomic_read(&dev_priv->gpu_error.reset_counter); + return __i915_wait_seqno(ring, seqno, reset_counter, interruptible, + NULL, NULL); } static int @@ -1353,7 +1354,8 @@ i915_gem_object_wait_rendering__nonblocking(struct drm_i915_gem_object *obj, reset_counter = atomic_read(&dev_priv->gpu_error.reset_counter); mutex_unlock(&dev->struct_mutex); - ret = __wait_seqno(ring, seqno, reset_counter, true, NULL, file_priv); + ret = __i915_wait_seqno(ring, seqno, reset_counter, true, NULL, + file_priv); mutex_lock(&dev->struct_mutex); if (ret) return ret; @@ -2847,8 +2849,8 @@ i915_gem_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file) reset_counter = atomic_read(&dev_priv->gpu_error.reset_counter); mutex_unlock(&dev->struct_mutex); - return __wait_seqno(ring, seqno, reset_counter, true, &args->timeout_ns, - file->driver_priv); + return __i915_wait_seqno(ring, seqno, reset_counter, true, + &args->timeout_ns, file->driver_priv); out: drm_gem_object_unreference(&obj->base); @@ -4013,7 +4015,7 @@ i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file) if (seqno == 0) return 0; - ret = __wait_seqno(ring, seqno, reset_counter, true, NULL, NULL); + ret = __i915_wait_seqno(ring, seqno, reset_counter, true, NULL, NULL); if (ret == 0) queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, 0); -- cgit v1.2.3 From 536f5b5e86b225dab94c7ff8061ae482b6077387 Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Thu, 6 Nov 2014 11:03:40 +0200 Subject: drm/i915: Make mmio flip wait for seqno in the work function This simplifies the code quite a bit compared to iterating over all rings during the ring interrupt. Also, it allows us to drop the mmio_flip spinlock, since the mmio_flip struct is only accessed in two places. The first is when the flip is queued and the other when the mmio writes are done. Since a flip cannot be queued while there is a pending flip, the two paths shouldn't ever run in parallel. We might need to revisit that if support for replacing flips is implemented though. v2: Don't hold dev->struct_mutext while waiting (Chris) v3: Make the wait uninterruptable (Chris) Signed-off-by: Ander Conselvan de Oliveira Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 3 -- drivers/gpu/drm/i915/intel_display.c | 90 +++++------------------------------- drivers/gpu/drm/i915/intel_drv.h | 9 +--- 3 files changed, 12 insertions(+), 90 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 318a6a0724d0..5fff2870a17b 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -979,9 +979,6 @@ static void notify_ring(struct drm_device *dev, trace_i915_gem_request_complete(ring); - if (drm_core_check_feature(dev, DRIVER_MODESET)) - intel_notify_mmio_flip(ring); - wake_up_all(&ring->irq_queue); i915_queue_hangcheck(dev); } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 18ad2bc8550b..cb0f32fd3b5c 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -9417,73 +9417,24 @@ static void intel_do_mmio_flip(struct intel_crtc *intel_crtc) if (atomic_update) intel_pipe_update_end(intel_crtc, start_vbl_count); - - spin_lock_irq(&dev_priv->mmio_flip_lock); - intel_crtc->mmio_flip.status = INTEL_MMIO_FLIP_IDLE; - spin_unlock_irq(&dev_priv->mmio_flip_lock); } static void intel_mmio_flip_work_func(struct work_struct *work) { struct intel_crtc *intel_crtc = container_of(work, struct intel_crtc, mmio_flip.work); - - intel_do_mmio_flip(intel_crtc); -} - -static int intel_postpone_flip(struct drm_i915_gem_object *obj) -{ struct intel_engine_cs *ring; - int ret; - - lockdep_assert_held(&obj->base.dev->struct_mutex); - - if (!obj->last_write_seqno) - return 0; - - ring = obj->ring; - - if (i915_seqno_passed(ring->get_seqno(ring, true), - obj->last_write_seqno)) - return 0; - - ret = i915_gem_check_olr(ring, obj->last_write_seqno); - if (ret) - return ret; - - if (WARN_ON(!ring->irq_get(ring))) - return 0; - - return 1; -} + uint32_t seqno; -void intel_notify_mmio_flip(struct intel_engine_cs *ring) -{ - struct drm_i915_private *dev_priv = to_i915(ring->dev); - struct intel_crtc *intel_crtc; - unsigned long irq_flags; - u32 seqno; - - seqno = ring->get_seqno(ring, false); + seqno = intel_crtc->mmio_flip.seqno; + ring = intel_crtc->mmio_flip.ring; - spin_lock_irqsave(&dev_priv->mmio_flip_lock, irq_flags); - for_each_intel_crtc(ring->dev, intel_crtc) { - struct intel_mmio_flip *mmio_flip; + if (seqno) + WARN_ON(__i915_wait_seqno(ring, seqno, + intel_crtc->reset_counter, + false, NULL, NULL) != 0); - mmio_flip = &intel_crtc->mmio_flip; - if (mmio_flip->status != INTEL_MMIO_FLIP_WAIT_RING) - continue; - - if (ring->id != mmio_flip->ring_id) - continue; - - if (i915_seqno_passed(seqno, mmio_flip->seqno)) { - schedule_work(&intel_crtc->mmio_flip.work); - mmio_flip->status = INTEL_MMIO_FLIP_WORK_SCHEDULED; - ring->irq_put(ring); - } - } - spin_unlock_irqrestore(&dev_priv->mmio_flip_lock, irq_flags); + intel_do_mmio_flip(intel_crtc); } static int intel_queue_mmio_flip(struct drm_device *dev, @@ -9493,32 +9444,13 @@ static int intel_queue_mmio_flip(struct drm_device *dev, struct intel_engine_cs *ring, uint32_t flags) { - struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - int ret; - - if (WARN_ON(intel_crtc->mmio_flip.status != INTEL_MMIO_FLIP_IDLE)) - return -EBUSY; - - ret = intel_postpone_flip(obj); - if (ret < 0) - return ret; - if (ret == 0) { - intel_do_mmio_flip(intel_crtc); - return 0; - } - spin_lock_irq(&dev_priv->mmio_flip_lock); - intel_crtc->mmio_flip.status = INTEL_MMIO_FLIP_WAIT_RING; intel_crtc->mmio_flip.seqno = obj->last_write_seqno; - intel_crtc->mmio_flip.ring_id = obj->ring->id; - spin_unlock_irq(&dev_priv->mmio_flip_lock); + intel_crtc->mmio_flip.ring = obj->ring; + + schedule_work(&intel_crtc->mmio_flip.work); - /* - * Double check to catch cases where irq fired before - * mmio flip data was ready - */ - intel_notify_mmio_flip(obj->ring); return 0; } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index cb0e9dbf1c96..5c622ad2e9aa 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -399,16 +399,9 @@ struct intel_pipe_wm { bool sprites_scaled; }; -enum intel_mmio_flip_status { - INTEL_MMIO_FLIP_IDLE = 0, - INTEL_MMIO_FLIP_WAIT_RING, - INTEL_MMIO_FLIP_WORK_SCHEDULED, -}; - struct intel_mmio_flip { u32 seqno; - u32 ring_id; - enum intel_mmio_flip_status status; + struct intel_engine_cs *ring; struct work_struct work; }; -- cgit v1.2.3 From 9500986159d9017f9277f9e42a1f9b13b5e0e666 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Wed, 5 Nov 2014 17:30:52 +0200 Subject: Revert "drm/i915/vlv: Remove check for Old Ack during forcewake" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 5cb13c07dae73380d8b3ddc792740487b8742938. While the relevance for WaRsDontPollForAckOnClearingFWBits is under investigation, revert this as regression. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=85684 Tested-by: Tested-by: lu hua Cc: Chris Wilson Cc: Ville Syrjälä Cc: S, Deepak Signed-off-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_uncore.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index 68e722b780a1..6a0c3fb2cbf0 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -194,15 +194,13 @@ static void vlv_force_wake_reset(struct drm_i915_private *dev_priv) static void __vlv_force_wake_get(struct drm_i915_private *dev_priv, int fw_engine) { - /* - * WaRsDontPollForAckOnClearingFWBits:vlv - * Hardware clears ack bits lazily (only when all ack - * bits become 0) so don't poll for individiual ack - * bits to be clear here like on other platforms. - */ - /* Check for Render Engine */ if (FORCEWAKE_RENDER & fw_engine) { + if (wait_for_atomic((__raw_i915_read32(dev_priv, + FORCEWAKE_ACK_VLV) & + FORCEWAKE_KERNEL) == 0, + FORCEWAKE_ACK_TIMEOUT_MS)) + DRM_ERROR("Timed out: Render forcewake old ack to clear.\n"); __raw_i915_write32(dev_priv, FORCEWAKE_VLV, _MASKED_BIT_ENABLE(FORCEWAKE_KERNEL)); @@ -216,6 +214,11 @@ static void __vlv_force_wake_get(struct drm_i915_private *dev_priv, /* Check for Media Engine */ if (FORCEWAKE_MEDIA & fw_engine) { + if (wait_for_atomic((__raw_i915_read32(dev_priv, + FORCEWAKE_ACK_MEDIA_VLV) & + FORCEWAKE_KERNEL) == 0, + FORCEWAKE_ACK_TIMEOUT_MS)) + DRM_ERROR("Timed out: Media forcewake old ack to clear.\n"); __raw_i915_write32(dev_priv, FORCEWAKE_MEDIA_VLV, _MASKED_BIT_ENABLE(FORCEWAKE_KERNEL)); -- cgit v1.2.3 From 6bcda4f0dfcbe78349b5b283af892913299c8b2a Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 7 Oct 2014 17:41:22 +0300 Subject: drm/i915: Cache HPLL frequency on VLV/CHV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We need the HPLL frequency when calculating cdclk. Currently we read that out from the hardware every single time, which isn't going to fly very well if the device is runtime suspended. So cache the HPLL frequency in dev_priv and use the cached value. Signed-off-by: Ville Syrjälä Reference: https://bugs.freedesktop.org/show_bug.cgi?id=82939 Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/intel_display.c | 14 +++++++------- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 2dc888ca3394..8fb8eba08dc6 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1613,6 +1613,7 @@ struct drm_i915_private { unsigned int fsb_freq, mem_freq, is_ddr3; unsigned int vlv_cdclk_freq; + unsigned int hpll_freq; /** * wq - Driver workqueue for GEM. diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index cb0f32fd3b5c..3f4a5b83bea4 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4756,10 +4756,9 @@ static void valleyview_set_cdclk(struct drm_device *dev, int cdclk) mutex_unlock(&dev_priv->rps.hw_lock); if (cdclk == 400000) { - u32 divider, vco; + u32 divider; - vco = valleyview_get_vco(dev_priv); - divider = DIV_ROUND_CLOSEST(vco << 1, cdclk) - 1; + divider = DIV_ROUND_CLOSEST(dev_priv->hpll_freq << 1, cdclk) - 1; mutex_lock(&dev_priv->dpio_lock); /* adjust cdclk divider */ @@ -4838,8 +4837,7 @@ static void cherryview_set_cdclk(struct drm_device *dev, int cdclk) static int valleyview_calc_cdclk(struct drm_i915_private *dev_priv, int max_pixclk) { - int vco = valleyview_get_vco(dev_priv); - int freq_320 = (vco << 1) % 320000 != 0 ? 333333 : 320000; + int freq_320 = (dev_priv->hpll_freq << 1) % 320000 != 0 ? 333333 : 320000; /* FIXME: Punit isn't quite ready yet */ if (IS_CHERRYVIEW(dev_priv->dev)) @@ -5544,7 +5542,6 @@ static int intel_crtc_compute_config(struct intel_crtc *crtc, static int valleyview_get_display_clock_speed(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - int vco = valleyview_get_vco(dev_priv); u32 val; int divider; @@ -5552,6 +5549,9 @@ static int valleyview_get_display_clock_speed(struct drm_device *dev) if (IS_CHERRYVIEW(dev)) return 400000; + if (dev_priv->hpll_freq == 0) + dev_priv->hpll_freq = valleyview_get_vco(dev_priv); + mutex_lock(&dev_priv->dpio_lock); val = vlv_cck_read(dev_priv, CCK_DISPLAY_CLOCK_CONTROL); mutex_unlock(&dev_priv->dpio_lock); @@ -5562,7 +5562,7 @@ static int valleyview_get_display_clock_speed(struct drm_device *dev) (divider << DISPLAY_FREQUENCY_STATUS_SHIFT), "cdclk change in progress\n"); - return DIV_ROUND_CLOSEST(vco << 1, divider + 1); + return DIV_ROUND_CLOSEST(dev_priv->hpll_freq << 1, divider + 1); } static int i945_get_display_clock_speed(struct drm_device *dev) -- cgit v1.2.3 From 0b5492d6b53251acab99b1906a328fac56e08be3 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Thu, 6 Nov 2014 13:03:46 +0200 Subject: drm/i915: Add gen to the gpu hang ecode for the Brothers in Triage Signed-off-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gpu_error.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index d17360bc1cd1..89a2f3dbf956 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -1242,7 +1242,8 @@ static void i915_error_capture_msg(struct drm_device *dev, ecode = i915_error_generate_code(dev_priv, error, &ring_id); len = scnprintf(error->error_msg, sizeof(error->error_msg), - "GPU HANG: ecode %d:0x%08x", ring_id, ecode); + "GPU HANG: ecode %d:%d:0x%08x", + INTEL_INFO(dev)->gen, ring_id, ecode); if (ring_id != -1 && error->ring[ring_id].pid != -1) len += scnprintf(error->error_msg + len, -- cgit v1.2.3 From 69f627f56fac212c1e49cd0d285e3f8cd264dd0c Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 7 Nov 2014 19:03:19 +0100 Subject: drm/i915: Update DRIVER_DATE to 20141107 Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 8fb8eba08dc6..f830596faa9e 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 "20141024" +#define DRIVER_DATE "20141107" #undef WARN_ON #define WARN_ON(x) WARN(x, "WARN_ON(" #x ")") -- cgit v1.2.3 From f354d733f680ec9f9afed0d0fa6429ed259f0a52 Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Fri, 7 Nov 2014 14:07:41 +0200 Subject: drm/i915: Plug memory leak in intel_shared_dpll_start_config() The cleanup path would reset pll->new_config to NULL but wouldn't free the allocated memory. Signed-off-by: Ander Conselvan de Oliveira Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 3f4a5b83bea4..ea607f340c76 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3953,6 +3953,7 @@ static int intel_shared_dpll_start_config(struct drm_i915_private *dev_priv, cleanup: while (--i >= 0) { pll = &dev_priv->shared_dplls[i]; + kfree(pll->new_config); pll->new_config = NULL; } -- cgit v1.2.3 From e1f234bde6edb2bcdb763c90076b9484e4c71a33 Mon Sep 17 00:00:00 2001 From: Bob Paauwe Date: Tue, 11 Nov 2014 09:29:18 -0800 Subject: drm/i915: Use correct pipe config to update pll dividers. V2 Use the new pipe config values to calculate the updated pll dividers. This regression was introduced in commit 0dbdf89f27b17ae1eceed6782c2917f74cbb5d59 Author: Ander Conselvan de Oliveira Date: Wed Oct 29 11:32:33 2014 +0200 drm/i915: Add infrastructure for choosing DPLLs before disabling crtcs and commit 00d958817dd3daaa452c221387ddaf23d1e4c06f Author: Ander Conselvan de Oliveira Date: Wed Oct 29 11:32:36 2014 +0200 drm/i915: Covert remaining platforms to choose DPLLS before disabling CRTCs v2: Use intel_pipe_will_have_type() to look at new configuration - Ander Signed-off-by: Bob Paauwe CC: Ander Conselvan de Oliveira Tested-by: Jesse Barnes Reviewed-by: Ander Conselvan de Oliveira Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index ea607f340c76..9480a6173d78 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5733,24 +5733,24 @@ static void i9xx_update_pll_dividers(struct intel_crtc *crtc, u32 fp, fp2 = 0; if (IS_PINEVIEW(dev)) { - fp = pnv_dpll_compute_fp(&crtc->config.dpll); + fp = pnv_dpll_compute_fp(&crtc->new_config->dpll); if (reduced_clock) fp2 = pnv_dpll_compute_fp(reduced_clock); } else { - fp = i9xx_dpll_compute_fp(&crtc->config.dpll); + fp = i9xx_dpll_compute_fp(&crtc->new_config->dpll); if (reduced_clock) fp2 = i9xx_dpll_compute_fp(reduced_clock); } - crtc->config.dpll_hw_state.fp0 = fp; + crtc->new_config->dpll_hw_state.fp0 = fp; crtc->lowfreq_avail = false; - if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) && + if (intel_pipe_will_have_type(crtc, INTEL_OUTPUT_LVDS) && reduced_clock && i915.powersave) { - crtc->config.dpll_hw_state.fp1 = fp2; + crtc->new_config->dpll_hw_state.fp1 = fp2; crtc->lowfreq_avail = true; } else { - crtc->config.dpll_hw_state.fp1 = fp; + crtc->new_config->dpll_hw_state.fp1 = fp; } } -- cgit v1.2.3