From d6d36b55a0f394a3895349285ed6980278809489 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Fri, 1 Feb 2019 13:15:41 -0700 Subject: drm/amd/display: Use memset to initialize variable in wait_for_training_aux_rd_interval Clang warns: drivers/gpu/drm/amd/amdgpu/../display/dc/core/dc_link_dp.c:50:57: warning: suggest braces around initialization of subobject [-Wmissing-braces] union training_aux_rd_interval training_rd_interval = {0}; ^ {} 1 warning generated. Previous efforts to fix this type of warning by adding or removing braces have been met with some pushback in favor of using memset [1][2]. Do that here, mirroring commit 05794eff1aa6 ("drm/amdgpu/gmc: fix compiler errors [-Werror,-Wmissing-braces] (V2)") in this tree. [1]: https://lore.kernel.org/lkml/022e41c0-8465-dc7a-a45c-64187ecd9684@amd.com/ [2]: https://lore.kernel.org/lkml/20181128.215241.702406654469517539.davem@davemloft.net/ Fixes: 3cec41769d21 ("drm/amd/display: Fix use of uninitialized union") Signed-off-by: Nathan Chancellor Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/amd/display') diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c index 92f565ca1260..5ee36d6e0512 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c @@ -47,7 +47,9 @@ static void wait_for_training_aux_rd_interval( struct dc_link *link, uint32_t default_wait_in_micro_secs) { - union training_aux_rd_interval training_rd_interval = {0}; + union training_aux_rd_interval training_rd_interval; + + memset(&training_rd_interval, 0, sizeof(training_rd_interval)); /* overwrite the delay if rev > 1.1*/ if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_12) { -- cgit v1.2.3 From 19afd79951e6303dbe0d15293a2f66ceb4c772f6 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Fri, 1 Feb 2019 13:14:28 -0700 Subject: drm/amd/display: Use memset to initialize variables in amdgpu_dm_atomic_commit_tail Clang warns: drivers/gpu/drm/amd/amdgpu/../display/amdgpu_dm/amdgpu_dm.c:5089:60: warning: suggest braces around initialization of subobject [-Wmissing-braces] struct dc_surface_update dummy_updates[MAX_SURFACES] = { 0 }; ^ {} Previous efforts to fix this type of warning by adding or removing braces have been met with some pushback in favor of using memset [1][2]. Do that here, mirroring commit 05794eff1aa6 ("drm/amdgpu/gmc: fix compiler errors [-Werror,-Wmissing-braces] (V2)") in this tree. [1]: https://lore.kernel.org/lkml/022e41c0-8465-dc7a-a45c-64187ecd9684@amd.com/ [2]: https://lore.kernel.org/lkml/20181128.215241.702406654469517539.davem@davemloft.net/ Fixes: 02d6a6fcdf68 ("drm/amd/display: Simplify underscan and ABM commit") Signed-off-by: Nathan Chancellor Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/amd/display') diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 1923f47d3dd6..640ac9d9f04f 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -5094,10 +5094,13 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) struct dm_connector_state *dm_new_con_state = to_dm_connector_state(new_con_state); struct dm_connector_state *dm_old_con_state = to_dm_connector_state(old_con_state); struct amdgpu_crtc *acrtc = to_amdgpu_crtc(dm_new_con_state->base.crtc); - struct dc_surface_update dummy_updates[MAX_SURFACES] = { 0 }; - struct dc_stream_update stream_update = { 0 }; + struct dc_surface_update dummy_updates[MAX_SURFACES]; + struct dc_stream_update stream_update; struct dc_stream_status *status = NULL; + memset(&dummy_updates, 0, sizeof(dummy_updates)); + memset(&stream_update, 0, sizeof(stream_update)); + if (acrtc) { new_crtc_state = drm_atomic_get_new_crtc_state(state, &acrtc->base); old_crtc_state = drm_atomic_get_old_crtc_state(state, &acrtc->base); -- cgit v1.2.3 From 8daa12182a7ab441a2b3eeb170f9d8a12b206d6c Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Fri, 1 Feb 2019 13:12:26 -0700 Subject: drm/amd/display: Use memset to initialize variables in fill_plane_dcc_attributes Clang warns: drivers/gpu/drm/amd/amdgpu/../display/amdgpu_dm/amdgpu_dm.c:2314:38: warning: suggest braces around initialization of subobject [-Wmissing-braces] struct dc_surface_dcc_cap output = {0}; ^ {} Previous efforts to fix this type of warning by adding or removing braces have been met with some pushback in favor of using memset [1][2]. Do that here, mirroring commit 05794eff1aa6 ("drm/amdgpu/gmc: fix compiler errors [-Werror,-Wmissing-braces] (V2)") in this tree. [1]: https://lore.kernel.org/lkml/022e41c0-8465-dc7a-a45c-64187ecd9684@amd.com/ [2]: https://lore.kernel.org/lkml/20181128.215241.702406654469517539.davem@davemloft.net/ Fixes: 7df7e505e82a ("drm/amd/display: Set requested plane state DCC params for GFX9") Signed-off-by: Nathan Chancellor Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/amd/display') diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 640ac9d9f04f..a08820f86f0f 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -2297,12 +2297,15 @@ static bool fill_plane_dcc_attributes(struct amdgpu_device *adev, uint64_t info) { struct dc *dc = adev->dm.dc; - struct dc_dcc_surface_param input = {0}; - struct dc_surface_dcc_cap output = {0}; + struct dc_dcc_surface_param input; + struct dc_surface_dcc_cap output; uint32_t offset = AMDGPU_TILING_GET(info, DCC_OFFSET_256B); uint32_t i64b = AMDGPU_TILING_GET(info, DCC_INDEPENDENT_64B) != 0; uint64_t dcc_address; + memset(&input, 0, sizeof(input)); + memset(&output, 0, sizeof(output)); + if (!offset) return false; -- cgit v1.2.3 From cc7e422d3db338bf00ac73b4575668d149a25a34 Mon Sep 17 00:00:00 2001 From: Nicholas Kazlauskas Date: Mon, 4 Feb 2019 09:32:07 -0500 Subject: drm/amd/display: Don't re-enable CRC when CONFIG_DEBUG_FS isn't defined [Why] When CONFIG_DEBUG_FS isn't defined then amdgpu_dm_crtc_set_crc_source is NULL. This causes a compilation error since it's being called unconditionally. [How] Guard the call based on CONFIG_DEBUG_FS - CRC capture isn't supported without this. Cc: Leo Li Cc: Harry Wentland Fixes: 43a6a02eb355 ("drm/amd/display: Re-enable CRC capture following modeset") Signed-off-by: Nicholas Kazlauskas Reviewed-by: Harry Wentland Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/gpu/drm/amd/display') diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index a08820f86f0f..0eea6c80864e 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -5180,9 +5180,11 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) manage_dm_interrupts(adev, acrtc, true); +#ifdef CONFIG_DEBUG_FS /* The stream has changed so CRC capture needs to re-enabled. */ if (dm_new_crtc_state->crc_enabled) amdgpu_dm_crtc_set_crc_source(crtc, "auto"); +#endif } /* update planes when needed per crtc*/ -- cgit v1.2.3 From 12a8bd8862ebd7d6e0f764120e2f322ddc077a11 Mon Sep 17 00:00:00 2001 From: Shirish S Date: Mon, 4 Feb 2019 14:24:25 +0530 Subject: drm/amd/display: Use context parameters to enable FBC [What] FBC fails to get enabled when switched between LINEAR(console/VT) and non-LINEAR(GUI) based rendering due to default value of tiling info stored in the current_state which is used for deciding whether or not to turn FBC on or off. [How] Use context structure's tiling information which is coherant with the screen updates. Signed-off-by: Shirish S Reviewed-by: Roman Li Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/amd/display') diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c index db0ef41eb91c..fd7cd5b5a17c 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c @@ -2535,7 +2535,7 @@ static void dce110_apply_ctx_for_surface( } if (dc->fbc_compressor) - enable_fbc(dc, dc->current_state); + enable_fbc(dc, context); } static void dce110_power_down_fe(struct dc *dc, struct pipe_ctx *pipe_ctx) -- cgit v1.2.3 From 9ca089925f0c318307881eadc0535e7c7a7b5e2d Mon Sep 17 00:00:00 2001 From: John Barberiz Date: Wed, 16 Jan 2019 17:21:31 -0500 Subject: drm/amd/display: Use udelay when waiting between aux retries [Why] "IRQ_HPD Pulse Length Test" DP compliance test fails. Test complains that certain DPCD registers are not read within 100 ms. [How] msleep is inaccurate for small values. Used udelay instead for accuracy. Signed-off-by: John Barberiz Reviewed-by: Wenjing Liu Acked-by: Bhawanpreet Lakha Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dce/dce_aux.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/amd/display') diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c b/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c index adbb22224e1a..4febf4ef7240 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c @@ -516,7 +516,7 @@ bool dce_aux_transfer_with_retries(struct ddc_service *ddc, } } - msleep(1); + udelay(1000); } return false; } -- cgit v1.2.3 From f3e3698d05454f2aeb9ef9969fc58a68090441ad Mon Sep 17 00:00:00 2001 From: Nicholas Kazlauskas Date: Wed, 9 Jan 2019 09:14:54 -0500 Subject: drm/amd/display: Apply all surface updates onto surfaces [Why] Most surface updates weren't propagated onto the surface during dc_commit_updates_for_stream. This makes it more difficult for DC to determine the actual surface update type required. [How] Use copy_surface_update_to_plane to propagate the changes. The FreeSync surface timing information update for BTR has been moved out of amdgpu_dm.c into this function as well. Signed-off-by: Nicholas Kazlauskas Reviewed-by: Sun peng Li Acked-by: Bhawanpreet Lakha Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 9 -- drivers/gpu/drm/amd/display/dc/core/dc.c | 104 ++++++++++++++++++++-- 2 files changed, 96 insertions(+), 17 deletions(-) (limited to 'drivers/gpu/drm/amd/display') diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 0eea6c80864e..f0baf358fb4e 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -4760,15 +4760,6 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, surface, flip->flip_addrs[flip_count].flip_timestamp_in_us); - /* Update surface timing information. */ - surface->time.time_elapsed_in_us[surface->time.index] = - flip->flip_addrs[flip_count].flip_timestamp_in_us - - surface->time.prev_update_time_in_us; - surface->time.prev_update_time_in_us = flip->flip_addrs[flip_count].flip_timestamp_in_us; - surface->time.index++; - if (surface->time.index >= DC_PLANE_UPDATE_TIMES_MAX) - surface->time.index = 0; - DRM_DEBUG_DRIVER("%s Flipping to hi: 0x%x, low: 0x%x\n", __func__, flip->flip_addrs[flip_count].address.grph.addr.high_part, diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index e22be0aefd1b..db8252ec3671 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -1440,6 +1440,101 @@ static struct dc_stream_status *stream_get_status( static const enum surface_update_type update_surface_trace_level = UPDATE_TYPE_FULL; +static void copy_surface_update_to_plane( + struct dc_plane_state *surface, + struct dc_surface_update *srf_update) +{ + if (srf_update->flip_addr) { + surface->address = srf_update->flip_addr->address; + surface->flip_immediate = + srf_update->flip_addr->flip_immediate; + surface->time.time_elapsed_in_us[surface->time.index] = + srf_update->flip_addr->flip_timestamp_in_us - + surface->time.prev_update_time_in_us; + surface->time.prev_update_time_in_us = + srf_update->flip_addr->flip_timestamp_in_us; + surface->time.index++; + if (surface->time.index >= DC_PLANE_UPDATE_TIMES_MAX) + surface->time.index = 0; + } + + if (srf_update->scaling_info) { + surface->scaling_quality = + srf_update->scaling_info->scaling_quality; + surface->dst_rect = + srf_update->scaling_info->dst_rect; + surface->src_rect = + srf_update->scaling_info->src_rect; + surface->clip_rect = + srf_update->scaling_info->clip_rect; + } + + if (srf_update->plane_info) { + surface->color_space = + srf_update->plane_info->color_space; + surface->format = + srf_update->plane_info->format; + surface->plane_size = + srf_update->plane_info->plane_size; + surface->rotation = + srf_update->plane_info->rotation; + surface->horizontal_mirror = + srf_update->plane_info->horizontal_mirror; + surface->stereo_format = + srf_update->plane_info->stereo_format; + surface->tiling_info = + srf_update->plane_info->tiling_info; + surface->visible = + srf_update->plane_info->visible; + surface->per_pixel_alpha = + srf_update->plane_info->per_pixel_alpha; + surface->global_alpha = + srf_update->plane_info->global_alpha; + surface->global_alpha_value = + srf_update->plane_info->global_alpha_value; + surface->dcc = + srf_update->plane_info->dcc; + surface->sdr_white_level = + srf_update->plane_info->sdr_white_level; + } + + if (srf_update->gamma && + (surface->gamma_correction != + srf_update->gamma)) { + memcpy(&surface->gamma_correction->entries, + &srf_update->gamma->entries, + sizeof(struct dc_gamma_entries)); + surface->gamma_correction->is_identity = + srf_update->gamma->is_identity; + surface->gamma_correction->num_entries = + srf_update->gamma->num_entries; + surface->gamma_correction->type = + srf_update->gamma->type; + } + + if (srf_update->in_transfer_func && + (surface->in_transfer_func != + srf_update->in_transfer_func)) { + surface->in_transfer_func->sdr_ref_white_level = + srf_update->in_transfer_func->sdr_ref_white_level; + surface->in_transfer_func->tf = + srf_update->in_transfer_func->tf; + surface->in_transfer_func->type = + srf_update->in_transfer_func->type; + memcpy(&surface->in_transfer_func->tf_pts, + &srf_update->in_transfer_func->tf_pts, + sizeof(struct dc_transfer_func_distributed_points)); + } + + if (srf_update->input_csc_color_matrix) + surface->input_csc_color_matrix = + *srf_update->input_csc_color_matrix; + + if (srf_update->coeff_reduction_factor) + surface->coeff_reduction_factor = + *srf_update->coeff_reduction_factor; +} + static void commit_planes_do_stream_update(struct dc *dc, struct dc_stream_state *stream, struct dc_stream_update *stream_update, @@ -1645,14 +1740,7 @@ void dc_commit_updates_for_stream(struct dc *dc, for (i = 0; i < surface_count; i++) { struct dc_plane_state *surface = srf_updates[i].surface; - /* TODO: On flip we don't build the state, so it still has the - * old address. Which is why we are updating the address here - */ - if (srf_updates[i].flip_addr) { - surface->address = srf_updates[i].flip_addr->address; - surface->flip_immediate = srf_updates[i].flip_addr->flip_immediate; - - } + copy_surface_update_to_plane(surface, &srf_updates[i]); if (update_type >= UPDATE_TYPE_MED) { for (j = 0; j < dc->res_pool->pipe_count; j++) { -- cgit v1.2.3 From c7af5f77aecdfe95633327cffc7f0c9dd1b64ab1 Mon Sep 17 00:00:00 2001 From: Nicholas Kazlauskas Date: Thu, 10 Jan 2019 09:51:54 -0500 Subject: drm/amd/display: Use the right surface for flip and FreeSync [Why] We were always passing the first surface on the stream status for flip updates when we should be using the surface associated with the plane. [How] Use the dc_plane_state from the plane that's being updated. FreeSync should also only keep track of updates from the primary plane, so the check needed to be updated. The acrtc->stream state doesn't need to be checked for NULL before updating FreeSync either since there needs to be a stream to be inside this function as a prerequisite. Signed-off-by: Nicholas Kazlauskas Reviewed-by: David Francis Acked-by: Bhawanpreet Lakha Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) (limited to 'drivers/gpu/drm/amd/display') diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index f0baf358fb4e..11c256c1dca7 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -4642,7 +4642,6 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, unsigned long flags; struct amdgpu_bo *abo; uint64_t tiling_flags, dcc_address; - struct dc_stream_status *stream_status; uint32_t target, target_vblank; struct { @@ -4673,7 +4672,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, struct drm_framebuffer *fb = new_plane_state->fb; struct amdgpu_framebuffer *afb = to_amdgpu_framebuffer(fb); bool pflip_needed; - struct dc_plane_state *surface, *dc_plane; + struct dc_plane_state *dc_plane; struct dm_plane_state *dm_new_plane_state = to_dm_plane_state(new_plane_state); if (plane->type == DRM_PLANE_TYPE_CURSOR) { @@ -4736,28 +4735,20 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, timestamp_ns = ktime_get_ns(); flip->flip_addrs[flip_count].flip_timestamp_in_us = div_u64(timestamp_ns, 1000); flip->surface_updates[flip_count].flip_addr = &flip->flip_addrs[flip_count]; + flip->surface_updates[flip_count].surface = dc_plane; - stream_status = dc_stream_get_status(acrtc_state->stream); - if (!stream_status) { - DRM_ERROR("No stream status for CRTC: id=%d\n", - acrtc_attach->crtc_id); - continue; - } - - surface = stream_status->plane_states[0]; - flip->surface_updates[flip_count].surface = surface; if (!flip->surface_updates[flip_count].surface) { DRM_ERROR("No surface for CRTC: id=%d\n", acrtc_attach->crtc_id); continue; } - if (acrtc_state->stream) + if (plane == pcrtc->primary) update_freesync_state_on_stream( dm, acrtc_state, acrtc_state->stream, - surface, + dc_plane, flip->flip_addrs[flip_count].flip_timestamp_in_us); DRM_DEBUG_DRIVER("%s Flipping to hi: 0x%x, low: 0x%x\n", -- cgit v1.2.3 From c744e974a22b0cf78ba581afb8244af1618f2649 Mon Sep 17 00:00:00 2001 From: Nicholas Kazlauskas Date: Thu, 10 Jan 2019 09:14:49 -0500 Subject: drm/amd/display: Reformat dm_determine_update_type_for_commit [Why] The indenting for this function is a few levels too deep and can be simplified a fair bit. This patch is in preparation for functional changes that fix update type determination to occur less frequently and more accurately. [How] Place checks early and exit/continue when possible. This isn't a functional change. Signed-off-by: Nicholas Kazlauskas Reviewed-by: David Francis Acked-by: Bhawanpreet Lakha Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 126 +++++++++++----------- 1 file changed, 65 insertions(+), 61 deletions(-) (limited to 'drivers/gpu/drm/amd/display') diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 11c256c1dca7..387f1ba39de4 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -5791,75 +5791,79 @@ dm_determine_update_type_for_commit(struct dc *dc, old_dm_crtc_state = to_dm_crtc_state(old_crtc_state); num_plane = 0; - if (new_dm_crtc_state->stream) { - - for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, j) { - new_plane_crtc = new_plane_state->crtc; - old_plane_crtc = old_plane_state->crtc; - new_dm_plane_state = to_dm_plane_state(new_plane_state); - old_dm_plane_state = to_dm_plane_state(old_plane_state); - - if (plane->type == DRM_PLANE_TYPE_CURSOR) - continue; - - if (!state->allow_modeset) - continue; - - if (crtc == new_plane_crtc) { - updates[num_plane].surface = &surface[num_plane]; - - if (new_crtc_state->mode_changed) { - updates[num_plane].surface->src_rect = - new_dm_plane_state->dc_state->src_rect; - updates[num_plane].surface->dst_rect = - new_dm_plane_state->dc_state->dst_rect; - updates[num_plane].surface->rotation = - new_dm_plane_state->dc_state->rotation; - updates[num_plane].surface->in_transfer_func = - new_dm_plane_state->dc_state->in_transfer_func; - stream_update.dst = new_dm_crtc_state->stream->dst; - stream_update.src = new_dm_crtc_state->stream->src; - } - - if (new_crtc_state->color_mgmt_changed) { - updates[num_plane].gamma = - new_dm_plane_state->dc_state->gamma_correction; - updates[num_plane].in_transfer_func = - new_dm_plane_state->dc_state->in_transfer_func; - stream_update.gamut_remap = - &new_dm_crtc_state->stream->gamut_remap_matrix; - stream_update.out_transfer_func = - new_dm_crtc_state->stream->out_transfer_func; - } - - num_plane++; - } + if (!new_dm_crtc_state->stream) { + if (!new_dm_crtc_state->stream && old_dm_crtc_state->stream) { + update_type = UPDATE_TYPE_FULL; + goto cleanup; } - if (num_plane > 0) { - ret = dm_atomic_get_state(state, &dm_state); - if (ret) - goto cleanup; + continue; + } - old_dm_state = dm_atomic_get_old_state(state); - if (!old_dm_state) { - ret = -EINVAL; - goto cleanup; - } + for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, j) { + new_plane_crtc = new_plane_state->crtc; + old_plane_crtc = old_plane_state->crtc; + new_dm_plane_state = to_dm_plane_state(new_plane_state); + old_dm_plane_state = to_dm_plane_state(old_plane_state); - status = dc_stream_get_status_from_state(old_dm_state->context, - new_dm_crtc_state->stream); + if (plane->type == DRM_PLANE_TYPE_CURSOR) + continue; - update_type = dc_check_update_surfaces_for_stream(dc, updates, num_plane, - &stream_update, status); + if (!state->allow_modeset) + continue; - if (update_type > UPDATE_TYPE_MED) { - update_type = UPDATE_TYPE_FULL; - goto cleanup; - } + if (crtc != new_plane_crtc) + continue; + + updates[num_plane].surface = &surface[num_plane]; + + if (new_crtc_state->mode_changed) { + updates[num_plane].surface->src_rect = + new_dm_plane_state->dc_state->src_rect; + updates[num_plane].surface->dst_rect = + new_dm_plane_state->dc_state->dst_rect; + updates[num_plane].surface->rotation = + new_dm_plane_state->dc_state->rotation; + updates[num_plane].surface->in_transfer_func = + new_dm_plane_state->dc_state->in_transfer_func; + stream_update.dst = new_dm_crtc_state->stream->dst; + stream_update.src = new_dm_crtc_state->stream->src; + } + + if (new_crtc_state->color_mgmt_changed) { + updates[num_plane].gamma = + new_dm_plane_state->dc_state->gamma_correction; + updates[num_plane].in_transfer_func = + new_dm_plane_state->dc_state->in_transfer_func; + stream_update.gamut_remap = + &new_dm_crtc_state->stream->gamut_remap_matrix; + stream_update.out_transfer_func = + new_dm_crtc_state->stream->out_transfer_func; } - } else if (!new_dm_crtc_state->stream && old_dm_crtc_state->stream) { + num_plane++; + } + + if (num_plane == 0) + continue; + + ret = dm_atomic_get_state(state, &dm_state); + if (ret) + goto cleanup; + + old_dm_state = dm_atomic_get_old_state(state); + if (!old_dm_state) { + ret = -EINVAL; + goto cleanup; + } + + status = dc_stream_get_status_from_state(old_dm_state->context, + new_dm_crtc_state->stream); + + update_type = dc_check_update_surfaces_for_stream(dc, updates, num_plane, + &stream_update, status); + + if (update_type > UPDATE_TYPE_MED) { update_type = UPDATE_TYPE_FULL; goto cleanup; } -- cgit v1.2.3 From c448a53aaf9ef69942a8a4d6a9b7b191839d90c1 Mon Sep 17 00:00:00 2001 From: Nicholas Kazlauskas Date: Thu, 10 Jan 2019 11:52:11 -0500 Subject: drm/amd/display: Initialize stream_update to zero [Why] The stream_update struct is left unitialized but DC will access its fields. This usually results in global state validation occur during any atomic commit with state->allow_modeset = true. [How] Initialize the struct to zero for every stream we check. Signed-off-by: Nicholas Kazlauskas Reviewed-by: David Francis Acked-by: Bhawanpreet Lakha Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/amd/display') diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 387f1ba39de4..824e177fba9b 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -5773,7 +5773,6 @@ dm_determine_update_type_for_commit(struct dc *dc, struct dc_surface_update *updates; struct dc_plane_state *surface; - struct dc_stream_update stream_update; enum surface_update_type update_type = UPDATE_TYPE_FAST; updates = kcalloc(MAX_SURFACES, sizeof(*updates), GFP_KERNEL); @@ -5787,6 +5786,8 @@ dm_determine_update_type_for_commit(struct dc *dc, } for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { + struct dc_stream_update stream_update = { 0 }; + new_dm_crtc_state = to_dm_crtc_state(new_crtc_state); old_dm_crtc_state = to_dm_crtc_state(old_crtc_state); num_plane = 0; -- cgit v1.2.3 From 385d7eeaf14752b9d8180feb4bc52730b6dc99ce Mon Sep 17 00:00:00 2001 From: Nicholas Kazlauskas Date: Thu, 10 Jan 2019 10:33:53 -0500 Subject: drm/amd/display: Remove FreeSync timing changed debug output [Why] This provides little debug value and creates a lot of dmesg noise. [How] Remove it. Signed-off-by: Nicholas Kazlauskas Reviewed-by: David Francis Acked-by: Bhawanpreet Lakha Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers/gpu/drm/amd/display') diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 824e177fba9b..41e3620bed4d 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -4613,12 +4613,6 @@ static void update_freesync_state_on_stream( new_crtc_state->base.crtc->base.id, (int)new_crtc_state->base.vrr_enabled, (int)vrr_params.state); - - if (new_crtc_state->freesync_timing_changed) - DRM_DEBUG_KMS("VRR timing update: crtc=%u min=%u max=%u\n", - new_crtc_state->base.crtc->base.id, - vrr_params.adjust.v_total_min, - vrr_params.adjust.v_total_max); } static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, -- cgit v1.2.3 From a4f1d2b8a543e136a0c945ca85d5d64ab471ac2a Mon Sep 17 00:00:00 2001 From: Xiaodong Yan Date: Thu, 17 Jan 2019 00:18:01 +0800 Subject: drm/amd/display: Add monitor patch for backlight off [Why] Different panel need different time from backlight disable to end of valid video data, if the time is too short, panel will flash when dpms off [How] Add monitor patch to control the time from backlight disable to end of valid video data, Signed-off-by: Xiaodong Yan Reviewed-by: Wenjing Liu Acked-by: Bhawanpreet Lakha Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c | 4 ++++ drivers/gpu/drm/amd/display/dc/dc_types.h | 1 + 2 files changed, 5 insertions(+) (limited to 'drivers/gpu/drm/amd/display') diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c index 16d441d3af8a..f7f7515f65f4 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c @@ -119,6 +119,10 @@ bool edp_receiver_ready_T9(struct dc_link *link) break; udelay(100); //MAx T9 } while (++tries < 50); + + if (link->local_sink->edid_caps.panel_patch.extra_delay_backlight_off > 0) + udelay(link->local_sink->edid_caps.panel_patch.extra_delay_backlight_off * 1000); + return result; } bool edp_receiver_ready_T7(struct dc_link *link) diff --git a/drivers/gpu/drm/amd/display/dc/dc_types.h b/drivers/gpu/drm/amd/display/dc/dc_types.h index 56e7f3dab15a..da2009a108cf 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_types.h @@ -201,6 +201,7 @@ union display_content_support { struct dc_panel_patch { unsigned int dppowerup_delay; unsigned int extra_t12_ms; + unsigned int extra_delay_backlight_off; }; struct dc_edid_caps { -- cgit v1.2.3 From b21e09d0558e4af7fa1a147be4e3da1a46ebbf77 Mon Sep 17 00:00:00 2001 From: Anthony Koo Date: Thu, 17 Jan 2019 10:57:23 -0500 Subject: drm/amd/display: fix issue with DC brightness low with VB [Why] The problem is that we accidentally stopped loading some of the IRAM bytes used for the backlight ramping mechanism. This happened when we started reserving some region of IRAM as DMCU FW write only. [How] This change will define a start+end region for the IRAM read only region. So the parameters needed for the backlight operation will be loaded since it will be defined outside of the read only region. Signed-off-by: Anthony Koo Reviewed-by: Aric Cyr Acked-by: Bhawanpreet Lakha Signed-off-by: Alex Deucher --- .../drm/amd/display/modules/power/power_helpers.c | 34 +++++++++++++++------- 1 file changed, 24 insertions(+), 10 deletions(-) (limited to 'drivers/gpu/drm/amd/display') diff --git a/drivers/gpu/drm/amd/display/modules/power/power_helpers.c b/drivers/gpu/drm/amd/display/modules/power/power_helpers.c index baab6c4ae191..27b8cf5460b5 100644 --- a/drivers/gpu/drm/amd/display/modules/power/power_helpers.c +++ b/drivers/gpu/drm/amd/display/modules/power/power_helpers.c @@ -67,9 +67,14 @@ static const unsigned char abm_config[abm_defines_max_config][abm_defines_max_le #define NUM_AGGR_LEVEL 4 #define NUM_POWER_FN_SEGS 8 #define NUM_BL_CURVE_SEGS 16 -#define IRAM_RESERVE_AREA_START 0xF0 // reserve 0xF0~0xFF are write by DMCU only #define IRAM_SIZE 256 +#define IRAM_RESERVE_AREA_START_V2 0xF0 // reserve 0xF0~0xF6 are write by DMCU only +#define IRAM_RESERVE_AREA_END_V2 0xF6 // reserve 0xF0~0xF6 are write by DMCU only + +#define IRAM_RESERVE_AREA_START_V2_2 0xF0 // reserve 0xF0~0xFF are write by DMCU only +#define IRAM_RESERVE_AREA_END_V2_2 0xFF // reserve 0xF0~0xFF are write by DMCU only + #pragma pack(push, 1) /* NOTE: iRAM is 256B in size */ struct iram_table_v_2 { @@ -148,8 +153,10 @@ struct iram_table_v_2_2 { uint16_t dmcu_version; /* 0xf4 */ uint8_t dmcu_state; /* 0xf6 */ - uint16_t blRampReduction; /* 0xf7 */ - uint16_t blRampStart; /* 0xf9 */ + uint8_t dummy1; /* 0xf7 */ + uint8_t dummy2; /* 0xf8 */ + uint8_t dummy3; /* 0xf9 */ + uint8_t dummy4; /* 0xfa */ uint8_t dummy5; /* 0xfb */ uint8_t dummy6; /* 0xfc */ uint8_t dummy7; /* 0xfd */ @@ -420,11 +427,6 @@ void fill_iram_v_2_2(struct iram_table_v_2_2 *ram_table, struct dmcu_iram_parame ram_table->deviation_gain[2] = 0xb3; ram_table->deviation_gain[3] = 0xb3; - ram_table->blRampReduction = - cpu_to_be16(params.backlight_ramping_reduction); - ram_table->blRampStart = - cpu_to_be16(params.backlight_ramping_start); - ram_table->min_reduction[0][0] = min_reduction_table_v_2_2[abm_config[set][0]]; ram_table->min_reduction[1][0] = min_reduction_table_v_2_2[abm_config[set][0]]; ram_table->min_reduction[2][0] = min_reduction_table_v_2_2[abm_config[set][0]]; @@ -561,6 +563,7 @@ bool dmcu_load_iram(struct dmcu *dmcu, struct dmcu_iram_parameters params) { unsigned char ram_table[IRAM_SIZE]; + bool result = false; if (dmcu == NULL) return false; @@ -572,10 +575,21 @@ bool dmcu_load_iram(struct dmcu *dmcu, if (dmcu->dmcu_version.abm_version == 0x22) { fill_iram_v_2_2((struct iram_table_v_2_2 *)ram_table, params); + + result = dmcu->funcs->load_iram( + dmcu, 0, (char *)(&ram_table), IRAM_RESERVE_AREA_START_V2_2); } else { fill_iram_v_2((struct iram_table_v_2 *)ram_table, params); + + result = dmcu->funcs->load_iram( + dmcu, 0, (char *)(&ram_table), IRAM_RESERVE_AREA_START_V2); + + if (result) + result = dmcu->funcs->load_iram( + dmcu, IRAM_RESERVE_AREA_END_V2 + 1, + (char *)(&ram_table) + IRAM_RESERVE_AREA_END_V2 + 1, + sizeof(ram_table) - IRAM_RESERVE_AREA_END_V2 - 1); } - return dmcu->funcs->load_iram( - dmcu, 0, (char *)(&ram_table), IRAM_RESERVE_AREA_START); + return result; } -- cgit v1.2.3 From 22d7663f47cc36704c319c58bc1b1da8d42d53eb Mon Sep 17 00:00:00 2001 From: Paul Hsieh Date: Thu, 17 Jan 2019 18:56:14 +0800 Subject: drm/amd/display: dmcu is blocking due to wrong disable ABM command [Why] Second screen to clone/extend mode, driver will send ABM pipe command to DMCU. Change mode from clone/extend to second screen only, driver send ABM level command to disable ABM but this command will not clear ABM pipe data. At this time, change second screen to PC screen only, driver will send first command "ABM_LEVEL", it will turn on ABM with incorrect ABM pile so that DMCU is blocking. [How] When driver try to disable ABM, change command from "ABM LEVEL" to "ABM PIPE" so that it will clear ABM pile data. Signed-off-by: Paul Hsieh Reviewed-by: Charlene Liu Acked-by: Bhawanpreet Lakha Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dce/dce_abm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/amd/display') diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_abm.c b/drivers/gpu/drm/amd/display/dc/dce/dce_abm.c index 2a342eae80fd..01e56f1a9f34 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_abm.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_abm.c @@ -314,8 +314,8 @@ static bool dce_abm_immediate_disable(struct abm *abm) /* setDMCUParam_ABMLevel */ REG_UPDATE_2(MASTER_COMM_CMD_REG, - MASTER_COMM_CMD_REG_BYTE0, MCP_ABM_LEVEL_SET, - MASTER_COMM_CMD_REG_BYTE2, MCP_DISABLE_ABM_IMMEDIATELY); + MASTER_COMM_CMD_REG_BYTE0, MCP_ABM_PIPE_SET, + MASTER_COMM_CMD_REG_BYTE1, MCP_DISABLE_ABM_IMMEDIATELY); /* notifyDMCUMsg */ REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1); -- cgit v1.2.3 From a057ec460ab1f43a85e0fbb9938c2c3460cb7445 Mon Sep 17 00:00:00 2001 From: Ilya Bakoulin Date: Thu, 17 Jan 2019 13:40:34 -0500 Subject: drm/amd/display: Check that vrefresh is in freesync range [Why] Setting monitor refresh rate below freesync range would cause the monitor to go blank indefinitely with freesync enabled [How] Set vrr_supported and ignore_msa_timing_param according to whether the refresh rate is above or below the minimum freesync frequency. Signed-off-by: Ilya Bakoulin Reviewed-by: Nicholas Kazlauskas Acked-by: Bhawanpreet Lakha Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/gpu/drm/amd/display') diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 41e3620bed4d..06fc7c58a7b1 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -3030,9 +3030,6 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, update_stream_signal(stream, sink); - if (dm_state && dm_state->freesync_capable) - stream->ignore_msa_timing_param = true; - finish: if (sink && sink->sink_signal == SIGNAL_TYPE_VIRTUAL && aconnector->base.force != DRM_FORCE_ON) dc_sink_release(sink); @@ -5356,10 +5353,13 @@ static void get_freesync_config_for_crtc( struct mod_freesync_config config = {0}; struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(new_con_state->base.connector); + struct drm_display_mode *mode = &new_crtc_state->base.mode; - new_crtc_state->vrr_supported = new_con_state->freesync_capable; + new_crtc_state->vrr_supported = new_con_state->freesync_capable && + aconnector->min_vfreq <= drm_mode_vrefresh(mode); - if (new_con_state->freesync_capable) { + if (new_crtc_state->vrr_supported) { + new_crtc_state->stream->ignore_msa_timing_param = true; config.state = new_crtc_state->base.vrr_enabled ? VRR_STATE_ACTIVE_VARIABLE : VRR_STATE_INACTIVE; -- cgit v1.2.3 From 8f0159122714d38f89140993eb0a070f8eeb2e9d Mon Sep 17 00:00:00 2001 From: Krunoslav Kovac Date: Thu, 17 Jan 2019 17:56:51 -0500 Subject: drm/amd/display: DGAM enabled for HDR [Why] On HW that doesn't have input LUT, we may combine degamma with OS ramp Problem here is that it assumes DGAM is inverse of PQ or SRGB. It doesn't handle linear case, it would default to sRGB and always enable DGAM.. [How] Add handling for linear case. Also check for null ramp and instead of blowing up, assume it's identity. Signed-off-by: Krunoslav Kovac Reviewed-by: Anthony Koo Acked-by: Bhawanpreet Lakha Signed-off-by: Alex Deucher --- .../drm/amd/display/modules/color/color_gamma.c | 89 +++++++++++++--------- 1 file changed, 52 insertions(+), 37 deletions(-) (limited to 'drivers/gpu/drm/amd/display') diff --git a/drivers/gpu/drm/amd/display/modules/color/color_gamma.c b/drivers/gpu/drm/amd/display/modules/color/color_gamma.c index eefb85928298..0fbc8fbc3541 100644 --- a/drivers/gpu/drm/amd/display/modules/color/color_gamma.c +++ b/drivers/gpu/drm/amd/display/modules/color/color_gamma.c @@ -1765,68 +1765,85 @@ bool mod_color_calculate_degamma_params(struct dc_transfer_func *input_tf, { struct dc_transfer_func_distributed_points *tf_pts = &input_tf->tf_pts; struct dividers dividers; - struct pwl_float_data *rgb_user = NULL; struct pwl_float_data_ex *curve = NULL; struct gamma_pixel *axis_x = NULL; struct pixel_gamma_point *coeff = NULL; enum dc_transfer_func_predefined tf = TRANSFER_FUNCTION_SRGB; + uint32_t i; bool ret = false; if (input_tf->type == TF_TYPE_BYPASS) return false; - /* we can use hardcoded curve for plain SRGB TF */ + /* we can use hardcoded curve for plain SRGB TF + * If linear, it's bypass if on user ramp + */ if (input_tf->type == TF_TYPE_PREDEFINED && - input_tf->tf == TRANSFER_FUNCTION_SRGB && - !mapUserRamp) + (input_tf->tf == TRANSFER_FUNCTION_SRGB || + input_tf->tf == TRANSFER_FUNCTION_LINEAR) && + !mapUserRamp) return true; input_tf->type = TF_TYPE_DISTRIBUTED_POINTS; - rgb_user = kvcalloc(ramp->num_entries + _EXTRA_POINTS, - sizeof(*rgb_user), - GFP_KERNEL); - if (!rgb_user) - goto rgb_user_alloc_fail; + if (mapUserRamp && ramp && ramp->type == GAMMA_RGB_256) { + rgb_user = kvcalloc(ramp->num_entries + _EXTRA_POINTS, + sizeof(*rgb_user), + GFP_KERNEL); + if (!rgb_user) + goto rgb_user_alloc_fail; + + axis_x = kvcalloc(ramp->num_entries + _EXTRA_POINTS, sizeof(*axis_x), + GFP_KERNEL); + if (!axis_x) + goto axis_x_alloc_fail; + + dividers.divider1 = dc_fixpt_from_fraction(3, 2); + dividers.divider2 = dc_fixpt_from_int(2); + dividers.divider3 = dc_fixpt_from_fraction(5, 2); + + build_evenly_distributed_points( + axis_x, + ramp->num_entries, + dividers); + + scale_gamma(rgb_user, ramp, dividers); + } + curve = kvcalloc(MAX_HW_POINTS + _EXTRA_POINTS, sizeof(*curve), - GFP_KERNEL); + GFP_KERNEL); if (!curve) goto curve_alloc_fail; - axis_x = kvcalloc(ramp->num_entries + _EXTRA_POINTS, sizeof(*axis_x), - GFP_KERNEL); - if (!axis_x) - goto axis_x_alloc_fail; + coeff = kvcalloc(MAX_HW_POINTS + _EXTRA_POINTS, sizeof(*coeff), - GFP_KERNEL); + GFP_KERNEL); if (!coeff) goto coeff_alloc_fail; - dividers.divider1 = dc_fixpt_from_fraction(3, 2); - dividers.divider2 = dc_fixpt_from_int(2); - dividers.divider3 = dc_fixpt_from_fraction(5, 2); - tf = input_tf->tf; - build_evenly_distributed_points( - axis_x, - ramp->num_entries, - dividers); - - if (ramp->type == GAMMA_RGB_256 && mapUserRamp) - scale_gamma(rgb_user, ramp, dividers); - else if (ramp->type == GAMMA_RGB_FLOAT_1024) - scale_gamma_dx(rgb_user, ramp, dividers); - if (tf == TRANSFER_FUNCTION_PQ) build_de_pq(curve, MAX_HW_POINTS, coordinates_x); - else + else if (tf == TRANSFER_FUNCTION_SRGB || + tf == TRANSFER_FUNCTION_BT709) build_degamma(curve, MAX_HW_POINTS, coordinates_x, - tf == TRANSFER_FUNCTION_SRGB ? true:false); + tf == TRANSFER_FUNCTION_SRGB ? true : false); + else if (tf == TRANSFER_FUNCTION_LINEAR) { + // just copy coordinates_x into curve + i = 0; + while (i != MAX_HW_POINTS + 1) { + curve[i].r = coordinates_x[i].x; + curve[i].g = curve[i].r; + curve[i].b = curve[i].r; + i++; + } + } else + goto invalid_tf_fail; tf_pts->end_exponent = 0; tf_pts->x_point_at_y1_red = 1; @@ -1836,23 +1853,21 @@ bool mod_color_calculate_degamma_params(struct dc_transfer_func *input_tf, map_regamma_hw_to_x_user(ramp, coeff, rgb_user, coordinates_x, axis_x, curve, MAX_HW_POINTS, tf_pts, - mapUserRamp && ramp->type != GAMMA_CUSTOM); - if (ramp->type == GAMMA_CUSTOM) - apply_lut_1d(ramp, MAX_HW_POINTS, tf_pts); + mapUserRamp && ramp && ramp->type == GAMMA_RGB_256); ret = true; +invalid_tf_fail: kvfree(coeff); coeff_alloc_fail: - kvfree(axis_x); -axis_x_alloc_fail: kvfree(curve); curve_alloc_fail: + kvfree(axis_x); +axis_x_alloc_fail: kvfree(rgb_user); rgb_user_alloc_fail: return ret; - } -- cgit v1.2.3 From 5fc0cbfad4564856ee0f323d3f88a7cff19cc3f1 Mon Sep 17 00:00:00 2001 From: Wenjing Liu Date: Fri, 18 Jan 2019 18:19:51 -0500 Subject: drm/amd/display: determine if a pipe is synced by plane state [why] is_blanked is not a general indicator of if a pipe is synced for all asics. plane state is more accurate and applicable for all asics. [how] Remove is_blanked call and add checking plane_state against NULL instead. Signed-off-by: Wenjing Liu Reviewed-by: Tony Cheng Acked-by: Bhawanpreet Lakha Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/gpu/drm/amd/display') diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index db8252ec3671..e0ac009f00ab 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -907,11 +907,11 @@ static void program_timing_sync( } } - /* set first unblanked pipe as master */ + /* set first pipe with plane as master */ for (j = 0; j < group_size; j++) { struct pipe_ctx *temp; - if (pipe_set[j]->stream_res.tg->funcs->is_blanked && !pipe_set[j]->stream_res.tg->funcs->is_blanked(pipe_set[j]->stream_res.tg)) { + if (pipe_set[j]->plane_state) { if (j == 0) break; @@ -922,9 +922,9 @@ static void program_timing_sync( } } - /* remove any other unblanked pipes as they have already been synced */ + /* remove any other pipes with plane as they have already been synced */ for (j = j + 1; j < group_size; j++) { - if (pipe_set[j]->stream_res.tg->funcs->is_blanked && !pipe_set[j]->stream_res.tg->funcs->is_blanked(pipe_set[j]->stream_res.tg)) { + if (pipe_set[j]->plane_state) { group_size--; pipe_set[j] = pipe_set[group_size]; j--; -- cgit v1.2.3 From cf7d98d254e9ffe565fc736e101299cc02bc0aa1 Mon Sep 17 00:00:00 2001 From: Steven Chiu Date: Fri, 18 Jan 2019 15:29:38 -0500 Subject: drm/amd/display: 3.2.16 Signed-off-by: Steven Chiu Reviewed-by: Aric Cyr Acked-by: Bhawanpreet Lakha Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/amd/display') diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 8391bc39b7a9..0b2ffc7cfffd 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -39,7 +39,7 @@ #include "inc/hw/dmcu.h" #include "dml/display_mode_lib.h" -#define DC_VER "3.2.15" +#define DC_VER "3.2.16" #define MAX_SURFACES 3 #define MAX_STREAMS 6 -- cgit v1.2.3 From ac627caf6b9275a3df4730be3b8637c3bc232979 Mon Sep 17 00:00:00 2001 From: Chiawen Huang Date: Fri, 18 Jan 2019 14:07:54 +0800 Subject: drm/amd/display: add gpio lock/unlock [Why] When querying HPD via GPIO flow, it will create a new gpio object then free in the end of query. There is a irql issue for HPD querying at ISR level. [How] Therefore, creating the HPD gpio object in dc_link and set it as unlcok in default. 1. reducing unnecessary malloc/free when HPD querying. 2. reducing init GPIO flow. 3. add lock/unlock to prevent multi gpio service running. Signed-off-by: Chiawen Huang Reviewed-by: Tony Cheng Acked-by: Bhawanpreet Lakha Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc_link.c | 47 ++++++++++------------ drivers/gpu/drm/amd/display/dc/dc_link.h | 1 + drivers/gpu/drm/amd/display/dc/gpio/gpio_base.c | 12 ++++++ drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c | 28 +++++++++++++ drivers/gpu/drm/amd/display/dc/gpio/gpio_service.h | 10 +++++ .../gpu/drm/amd/display/include/gpio_interface.h | 8 ++++ 6 files changed, 81 insertions(+), 25 deletions(-) (limited to 'drivers/gpu/drm/amd/display') diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c index 8ff5d42587c2..137d3c126632 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -76,6 +76,12 @@ static void destruct(struct dc_link *link) { int i; + if (link->hpd_gpio != NULL) { + dal_gpio_close(link->hpd_gpio); + dal_gpio_destroy_irq(&link->hpd_gpio); + link->hpd_gpio = NULL; + } + if (link->ddc) dal_ddc_service_destroy(&link->ddc); @@ -931,18 +937,11 @@ bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason) bool dc_link_get_hpd_state(struct dc_link *dc_link) { - struct gpio *hpd_pin; uint32_t state; - hpd_pin = get_hpd_gpio(dc_link->ctx->dc_bios, - dc_link->link_id, dc_link->ctx->gpio_service); - if (hpd_pin == NULL) - ASSERT(false); - - dal_gpio_open(hpd_pin, GPIO_MODE_INTERRUPT); - dal_gpio_get_value(hpd_pin, &state); - dal_gpio_close(hpd_pin); - dal_gpio_destroy_irq(&hpd_pin); + dal_gpio_lock_pin(dc_link->hpd_gpio); + dal_gpio_get_value(dc_link->hpd_gpio, &state); + dal_gpio_unlock_pin(dc_link->hpd_gpio); return state; } @@ -1098,7 +1097,6 @@ static bool construct( const struct link_init_data *init_params) { uint8_t i; - struct gpio *hpd_gpio = NULL; struct ddc_service_init_data ddc_service_init_data = { { 0 } }; struct dc_context *dc_ctx = init_params->ctx; struct encoder_init_data enc_init_data = { 0 }; @@ -1128,10 +1126,11 @@ static bool construct( if (link->dc->res_pool->funcs->link_init) link->dc->res_pool->funcs->link_init(link); - hpd_gpio = get_hpd_gpio(link->ctx->dc_bios, link->link_id, link->ctx->gpio_service); - - if (hpd_gpio != NULL) - link->irq_source_hpd = dal_irq_get_source(hpd_gpio); + link->hpd_gpio = get_hpd_gpio(link->ctx->dc_bios, link->link_id, link->ctx->gpio_service); + dal_gpio_open(link->hpd_gpio, GPIO_MODE_INTERRUPT); + dal_gpio_unlock_pin(link->hpd_gpio); + if (link->hpd_gpio != NULL) + link->irq_source_hpd = dal_irq_get_source(link->hpd_gpio); switch (link->link_id.id) { case CONNECTOR_ID_HDMI_TYPE_A: @@ -1149,18 +1148,18 @@ static bool construct( case CONNECTOR_ID_DISPLAY_PORT: link->connector_signal = SIGNAL_TYPE_DISPLAY_PORT; - if (hpd_gpio != NULL) + if (link->hpd_gpio != NULL) link->irq_source_hpd_rx = - dal_irq_get_rx_source(hpd_gpio); + dal_irq_get_rx_source(link->hpd_gpio); break; case CONNECTOR_ID_EDP: link->connector_signal = SIGNAL_TYPE_EDP; - if (hpd_gpio != NULL) { + if (link->hpd_gpio != NULL) { link->irq_source_hpd = DC_IRQ_SOURCE_INVALID; link->irq_source_hpd_rx = - dal_irq_get_rx_source(hpd_gpio); + dal_irq_get_rx_source(link->hpd_gpio); } break; case CONNECTOR_ID_LVDS: @@ -1171,10 +1170,7 @@ static bool construct( goto create_fail; } - if (hpd_gpio != NULL) { - dal_gpio_destroy_irq(&hpd_gpio); - hpd_gpio = NULL; - } + /* TODO: #DAL3 Implement id to str function.*/ LINK_INFO("Connector[%d] description:" @@ -1277,8 +1273,9 @@ link_enc_create_fail: ddc_create_fail: create_fail: - if (hpd_gpio != NULL) { - dal_gpio_destroy_irq(&hpd_gpio); + if (link->hpd_gpio != NULL) { + dal_gpio_destroy_irq(&link->hpd_gpio); + link->hpd_gpio = NULL; } return false; diff --git a/drivers/gpu/drm/amd/display/dc/dc_link.h b/drivers/gpu/drm/amd/display/dc/dc_link.h index f249ff9be2a7..d26bbda61ad2 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_link.h +++ b/drivers/gpu/drm/amd/display/dc/dc_link.h @@ -125,6 +125,7 @@ struct dc_link { struct dc_link_status link_status; struct link_trace link_trace; + struct gpio *hpd_gpio; }; const struct dc_link_status *dc_link_get_status(const struct dc_link *dc_link); diff --git a/drivers/gpu/drm/amd/display/dc/gpio/gpio_base.c b/drivers/gpu/drm/amd/display/dc/gpio/gpio_base.c index 1d1efd72b291..cf76ea2d9f5a 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/gpio_base.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/gpio_base.c @@ -101,6 +101,18 @@ enum gpio_mode dal_gpio_get_mode( return gpio->mode; } +enum gpio_result dal_gpio_lock_pin( + struct gpio *gpio) +{ + return dal_gpio_service_lock(gpio->service, gpio->id, gpio->en); +} + +enum gpio_result dal_gpio_unlock_pin( + struct gpio *gpio) +{ + return dal_gpio_service_unlock(gpio->service, gpio->id, gpio->en); +} + enum gpio_result dal_gpio_change_mode( struct gpio *gpio, enum gpio_mode mode) diff --git a/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c b/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c index dada04296025..3c63a3c04dbb 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c @@ -192,6 +192,34 @@ static void set_pin_free( service->busyness[id][en] = false; } +enum gpio_result dal_gpio_service_lock( + struct gpio_service *service, + enum gpio_id id, + uint32_t en) +{ + if (!service->busyness[id]) { + ASSERT_CRITICAL(false); + return GPIO_RESULT_OPEN_FAILED; + } + + set_pin_busy(service, id, en); + return GPIO_RESULT_OK; +} + +enum gpio_result dal_gpio_service_unlock( + struct gpio_service *service, + enum gpio_id id, + uint32_t en) +{ + if (!service->busyness[id]) { + ASSERT_CRITICAL(false); + return GPIO_RESULT_OPEN_FAILED; + } + + set_pin_free(service, id, en); + return GPIO_RESULT_OK; +} + enum gpio_result dal_gpio_service_open( struct gpio_service *service, enum gpio_id id, diff --git a/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.h b/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.h index 1d501a43d13b..0c678af75331 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.h +++ b/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.h @@ -52,4 +52,14 @@ void dal_gpio_service_close( struct gpio_service *service, struct hw_gpio_pin **ptr); +enum gpio_result dal_gpio_service_lock( + struct gpio_service *service, + enum gpio_id id, + uint32_t en); + +enum gpio_result dal_gpio_service_unlock( + struct gpio_service *service, + enum gpio_id id, + uint32_t en); + #endif diff --git a/drivers/gpu/drm/amd/display/include/gpio_interface.h b/drivers/gpu/drm/amd/display/include/gpio_interface.h index e4fd31024b92..7de64195dc33 100644 --- a/drivers/gpu/drm/amd/display/include/gpio_interface.h +++ b/drivers/gpu/drm/amd/display/include/gpio_interface.h @@ -59,6 +59,14 @@ enum gpio_result dal_gpio_change_mode( struct gpio *gpio, enum gpio_mode mode); +/* Lock Pin */ +enum gpio_result dal_gpio_lock_pin( + struct gpio *gpio); + +/* Unlock Pin */ +enum gpio_result dal_gpio_unlock_pin( + struct gpio *gpio); + /* Get the GPIO id */ enum gpio_id dal_gpio_get_id( const struct gpio *gpio); -- cgit v1.2.3 From 056f05f65bf42cb69c48bf1bb6e085c7a405a565 Mon Sep 17 00:00:00 2001 From: Yongqiang Sun Date: Fri, 18 Jan 2019 19:44:33 -0500 Subject: drm/amd/display: pass vline_config parameter by reference. Signed-off-by: Yongqiang Sun Reviewed-by: Aric Cyr Acked-by: Bhawanpreet Lakha Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc.c | 4 ++-- drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c | 8 ++++---- drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h | 2 +- drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/gpu/drm/amd/display') diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index e0ac009f00ab..d8579b207300 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -1560,11 +1560,11 @@ static void commit_planes_do_stream_update(struct dc *dc, if (stream_update->vline0_config && pipe_ctx->stream_res.tg->funcs->program_vline_interrupt) pipe_ctx->stream_res.tg->funcs->program_vline_interrupt( - pipe_ctx->stream_res.tg, VLINE0, stream->vline0_config); + pipe_ctx->stream_res.tg, VLINE0, &stream->vline0_config); if (stream_update->vline1_config && pipe_ctx->stream_res.tg->funcs->program_vline_interrupt) pipe_ctx->stream_res.tg->funcs->program_vline_interrupt( - pipe_ctx->stream_res.tg, VLINE1, stream->vline1_config); + pipe_ctx->stream_res.tg, VLINE1, &stream->vline1_config); if ((stream_update->hdr_static_metadata && !stream->use_dynamic_meta) || stream_update->vrr_infopacket || diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c index 1d4f9b48ed7d..cefa322df8a6 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c @@ -95,19 +95,19 @@ static void optc1_disable_stereo(struct timing_generator *optc) void optc1_program_vline_interrupt( struct timing_generator *optc, enum vline_select vline, - struct vline_config vline_config) + const struct vline_config *vline_config) { struct optc *optc1 = DCN10TG_FROM_TG(optc); switch (vline) { case VLINE0: REG_SET_2(OTG_VERTICAL_INTERRUPT0_POSITION, 0, - OTG_VERTICAL_INTERRUPT0_LINE_START, vline_config.start_line, - OTG_VERTICAL_INTERRUPT0_LINE_END, vline_config.end_line); + OTG_VERTICAL_INTERRUPT0_LINE_START, vline_config->start_line, + OTG_VERTICAL_INTERRUPT0_LINE_END, vline_config->end_line); break; case VLINE1: REG_SET(OTG_VERTICAL_INTERRUPT1_POSITION, 0, - OTG_VERTICAL_INTERRUPT1_LINE_START, vline_config.start_line); + OTG_VERTICAL_INTERRUPT1_LINE_START, vline_config->start_line); break; default: break; diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h index 8eb71c0160a7..b34c8a240598 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h @@ -485,7 +485,7 @@ void optc1_program_timing( void optc1_program_vline_interrupt(struct timing_generator *optc, enum vline_select vline, - struct vline_config vline_config); + const struct vline_config *vline_config); void optc1_program_global_sync( struct timing_generator *optc); diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h b/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h index df64cf73ceb9..d22a406c19c0 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h @@ -151,7 +151,7 @@ struct timing_generator_funcs { bool use_vbios); void (*program_vline_interrupt)(struct timing_generator *optc, enum vline_select vline, - struct vline_config vline_config); + const struct vline_config *vline_config); bool (*enable_crtc)(struct timing_generator *tg); bool (*disable_crtc)(struct timing_generator *tg); bool (*is_counter_moving)(struct timing_generator *tg); -- cgit v1.2.3 From 4f69bc8c16f02478717ab5708d106d86e6f9db68 Mon Sep 17 00:00:00 2001 From: Josip Pavic Date: Tue, 22 Jan 2019 13:50:45 -0500 Subject: drm/amd/display: Modify ABM 2.2 Max Reduction [Why] Reduced backlight for ABM 2.2 at levels 1 and 2 is desired for power savings. [How] Reduce the max reduction parameters for ABM 2.2 Signed-off-by: Josip Pavic Reviewed-by: Josip Pavic Acked-by: Bhawanpreet Lakha Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/modules/power/power_helpers.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/amd/display') diff --git a/drivers/gpu/drm/amd/display/modules/power/power_helpers.c b/drivers/gpu/drm/amd/display/modules/power/power_helpers.c index 27b8cf5460b5..3ba87b076287 100644 --- a/drivers/gpu/drm/amd/display/modules/power/power_helpers.c +++ b/drivers/gpu/drm/amd/display/modules/power/power_helpers.c @@ -47,10 +47,10 @@ static const unsigned char min_reduction_table_v_2_2[13] = { /* Possible ABM 2.2 Max Reduction configs from least aggressive to most aggressive * 0 1 2 3 4 5 6 7 8 9 10 11 12 - * 96.1 89.8 85.1 80.3 69.4 64.7 54.9 45.1 30.2 25.1 19.6 12.5 12.5 % + * 96.1 89.8 74.9 69.4 64.7 52.2 48.6 39.6 30.2 25.1 19.6 12.5 12.5 % */ static const unsigned char max_reduction_table_v_2_2[13] = { -0xf5, 0xe5, 0xd9, 0xcd, 0xb1, 0xa5, 0x8c, 0x73, 0x4d, 0x40, 0x32, 0x20, 0x20}; +0xf5, 0xe5, 0xbf, 0xb1, 0xa5, 0x85, 0x7c, 0x65, 0x4d, 0x40, 0x32, 0x20, 0x20}; /* Predefined ABM configuration sets. We may have different configuration sets * in order to satisfy different power/quality requirements. -- cgit v1.2.3 From 8dac4e7d89ea3b09695c0948d375a62df9443ca0 Mon Sep 17 00:00:00 2001 From: Su Sung Chung Date: Mon, 21 Jan 2019 12:01:53 -0500 Subject: drm/amd/display: store timing sync info in dc_stream_status in program_timing_sync, after all the pipes are grouped, store timing sync info in dc_stream_status Signed-off-by: Su Sung Chung Reviewed-by: Tony Cheng Acked-by: Bhawanpreet Lakha Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc.c | 16 +++++++++++++++- drivers/gpu/drm/amd/display/dc/dc_stream.h | 6 ++++++ 2 files changed, 21 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/amd/display') diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index d8579b207300..d9f62befd86a 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -869,8 +869,9 @@ static void program_timing_sync( struct dc *dc, struct dc_state *ctx) { - int i, j; + int i, j, k; int group_index = 0; + int num_group = 0; int pipe_count = dc->res_pool->pipe_count; struct pipe_ctx *unsynced_pipes[MAX_PIPES] = { NULL }; @@ -922,6 +923,18 @@ static void program_timing_sync( } } + + for (k = 0; k < group_size; k++) { + struct dc_stream_status *status = dc_stream_get_status_from_state(ctx, pipe_set[k]->stream); + + status->timing_sync_info.group_id = num_group; + status->timing_sync_info.group_size = group_size; + if (k == 0) + status->timing_sync_info.master = true; + else + status->timing_sync_info.master = false; + + } /* remove any other pipes with plane as they have already been synced */ for (j = j + 1; j < group_size; j++) { if (pipe_set[j]->plane_state) { @@ -936,6 +949,7 @@ static void program_timing_sync( dc, group_index, group_size, pipe_set); group_index++; } + num_group++; } } diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h b/drivers/gpu/drm/amd/display/dc/dc_stream.h index 0de6d7f377a6..2d1f2825de09 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_stream.h +++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h @@ -32,11 +32,17 @@ /******************************************************************************* * Stream Interfaces ******************************************************************************/ +struct timing_sync_info { + int group_id; + int group_size; + bool master; +}; struct dc_stream_status { int primary_otg_inst; int stream_enc_inst; int plane_count; + struct timing_sync_info timing_sync_info; struct dc_plane_state *plane_states[MAX_SURFACE_NUM]; }; -- cgit v1.2.3 From 49782c638f6a33992f5c1c69414a7ef5c08a0d31 Mon Sep 17 00:00:00 2001 From: Dmytro Laktyushkin Date: Wed, 5 Dec 2018 10:52:25 -0500 Subject: drm/amd/display: add a debug flag to force odm combine Adding a bit vector to allow forcing odm on specific otgs Signed-off-by: Dmytro Laktyushkin Reviewed-by: Charlene Liu Acked-by: Bhawanpreet Lakha Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dc.h | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/gpu/drm/amd/display') diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 0b2ffc7cfffd..ee2c7e5b6087 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -255,6 +255,7 @@ struct dc_debug_options { bool scl_reset_length10; bool hdmi20_disable; bool skip_detection_link_training; + unsigned int force_odm_combine; //bit vector based on otg inst unsigned int force_fclk_khz; }; -- cgit v1.2.3 From e3fa5c4cf1b93205d64e3d472d049fe5d8e88e94 Mon Sep 17 00:00:00 2001 From: "Jerry (Fangzhi) Zuo" Date: Wed, 23 Jan 2019 11:41:18 -0500 Subject: drm/amd/display: Apply fake sink back to MST sequence [Why] It fixes the failure to create stream for sink in the scenario when hotplug SST and MST in sequence, and disconnect MST. [How] Add the fake sink back after the majority of MST rework is done. Signed-off-by: Jerry (Fangzhi) Zuo Reviewed-by: Nicholas Kazlauskas Acked-by: Bhawanpreet Lakha Acked-by: Tony Cheng Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 8 +++----- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c | 3 +++ 2 files changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers/gpu/drm/amd/display') diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 06fc7c58a7b1..bcc906a4eb04 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -2959,11 +2959,9 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, drm_connector = &aconnector->base; if (!aconnector->dc_sink) { - if (!aconnector->mst_port) { - sink = create_fake_sink(aconnector); - if (!sink) - return stream; - } + sink = create_fake_sink(aconnector); + if (!sink) + return stream; } else { sink = aconnector->dc_sink; } diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c index 60da1222afaa..73f8e8fa6edb 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c @@ -173,6 +173,9 @@ static int dm_dp_mst_get_modes(struct drm_connector *connector) aconnector->edid = edid; } + if (aconnector->dc_sink && aconnector->dc_sink->sink_signal == SIGNAL_TYPE_VIRTUAL) + dc_sink_release(aconnector->dc_sink); + if (!aconnector->dc_sink) { struct dc_sink *dc_sink; struct dc_sink_init_data init_params = { -- cgit v1.2.3 From 77476360f173c127c191bfe8ca8113130ef283b8 Mon Sep 17 00:00:00 2001 From: Nicholas Kazlauskas Date: Wed, 23 Jan 2019 13:50:17 -0500 Subject: drm/amd/display: Disconnect mpcc when changing tg [Why] This fixes an mpc programming error for the following sequence of atomic commits when pipe split is enabled: Commit 1: CRTC0 (plane 4, plane 3) Pipe 0: old_plane_state = A0, new_plane_state = A1, new_tg = T0 Pipe 1: old_plane_state = B0, new_plane_state = B1, new_tg = T0 Pipe 2: old_plane_state = A0, new_plane_state = A1, new_tg = T0 Pipe 3: old_plane_state = B0, new_plane_state = B1, new_tg = T0 Commit 2: CRTC0 (plane 3), CRTC1 (plane 2) Pipe 0: old_plane_state = A1, new_plane_state = A2, new_tg = T0 Pipe 1: old_plane_state = B1, new_plane_state = B2, new_tg = T1 Pipe 2: old_plane_state = A1, new_plane_state = NULL, new_tg = NULL Pipe 3: old_plane_state = B1, new_plane_state = NULL, new_tg = NULL In the second commit the assertion for mpcc in use is hit because mpcc disconnect never occurs for pipe 1. This is because the stream changes for pipe 1 and the opp_list is empty. This sequence occurs when running the "igt@kms_plane_multiple@atomic-pipe-A-tiling-none" test with two displays connected. [How] Expand the reset condition to include: "old_pipe_ctx->stream_res.tg != new_pipe_ctx->stream_res.tg" ...but only when the plane state is non-NULL for both old and new. Signed-off-by: Nicholas Kazlauskas Reviewed-by: Dmytro Laktyushkin Reviewed-by: Tony Cheng Acked-by: Bhawanpreet Lakha Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/gpu/drm/amd/display') diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c index 9cde24dbdac8..9f23ea283838 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c @@ -2334,9 +2334,10 @@ static void dcn10_apply_ctx_for_surface( } } - if (!pipe_ctx->plane_state && - old_pipe_ctx->plane_state && - old_pipe_ctx->stream_res.tg == tg) { + if ((!pipe_ctx->plane_state || + pipe_ctx->stream_res.tg != old_pipe_ctx->stream_res.tg) && + old_pipe_ctx->plane_state && + old_pipe_ctx->stream_res.tg == tg) { dc->hwss.plane_atomic_disconnect(dc, old_pipe_ctx); removed_pipe[i] = true; -- cgit v1.2.3 From ba345a0242d7ca7fe841d1926ebc12f2ec3890d8 Mon Sep 17 00:00:00 2001 From: Pratik Vishwakarma Date: Mon, 31 Dec 2018 13:42:53 +0530 Subject: drm/amdgpu/display: fix compiler errors [-Werror,-Wparentheses-equality] Remove extraneous parentheses around the comparison to silence this warning Signed-off-by: Pratik Vishwakarma Reviewed-by: Harry Wentland Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/calcs/dcn_calc_auto.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/amd/display') diff --git a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calc_auto.c b/drivers/gpu/drm/amd/display/dc/calcs/dcn_calc_auto.c index 7d102ac0d61b..1ef0074302c5 100644 --- a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calc_auto.c +++ b/drivers/gpu/drm/amd/display/dc/calcs/dcn_calc_auto.c @@ -63,7 +63,7 @@ void scaler_settings_calculation(struct dcn_bw_internal_vars *v) if (v->interlace_output[k] == 1.0) { v->v_ratio[k] = 2.0 * v->v_ratio[k]; } - if ((v->underscan_output[k] == 1.0)) { + if (v->underscan_output[k] == 1.0) { v->h_ratio[k] = v->h_ratio[k] * v->under_scan_factor; v->v_ratio[k] = v->v_ratio[k] * v->under_scan_factor; } -- cgit v1.2.3 From 5062b797db4103218fa00ee254417b8ecaab7401 Mon Sep 17 00:00:00 2001 From: Nicholas Kazlauskas Date: Wed, 23 Jan 2019 14:55:58 -0500 Subject: drm/amd/display: Don't re-program planes for DPMS changes [Why] There are opt1c lock warnings and CRTC read timeouts when running the "igt@kms_plane@plane-position-hole-dpms-pipe-*" tests. These are caused by trying to reprogram planes that are not in the current context. DPMS off removes the stream from the context. In this case: new_crtc_state->active_changed = true new_crtc_state->mode_changed = false The planes are reprogrammed before the stream is removed from the context because stream_state->mode_changed = false. For DPMS adds the stream and planes back to the context: new_crtc_state->active_changed = true new_crtc_state->mode_changed = false The planes are also reprogrammed here before the stream is added to the context because stream_state->mode_changed = true. They were not previously in the current context so warnings occur here. [How] Set stream_state->mode_changed = true when new_crtc_state->active_changed = true too. This prevents reprogramming before the context is applied in DC. The programming will be done after the context is applied. Signed-off-by: Nicholas Kazlauskas Reviewed-by: Sun peng Li Acked-by: Bhawanpreet Lakha Acked-by: Tony Cheng Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/amd/display') diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index bcc906a4eb04..ad31d7b9912f 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -4876,7 +4876,8 @@ cleanup: static void amdgpu_dm_crtc_copy_transient_flags(struct drm_crtc_state *crtc_state, struct dc_stream_state *stream_state) { - stream_state->mode_changed = crtc_state->mode_changed; + stream_state->mode_changed = + crtc_state->mode_changed || crtc_state->active_changed; } static int amdgpu_dm_atomic_commit(struct drm_device *dev, -- cgit v1.2.3 From 3f01f098a4e2ef30ef628497c43a3d568e720376 Mon Sep 17 00:00:00 2001 From: "Jerry (Fangzhi) Zuo" Date: Thu, 24 Jan 2019 11:46:49 -0500 Subject: drm/amd/display: Clear dc_sink after it gets released [Why] The dc_sink was released but the pointer on the aconnector was not cleared. [How] Clear it. Signed-off-by: Jerry (Fangzhi) Zuo Reviewed-by: Nicholas Kazlauskas Acked-by: Bhawanpreet Lakha Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/amd/display') diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c index 73f8e8fa6edb..44c1a02e6452 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c @@ -173,8 +173,10 @@ static int dm_dp_mst_get_modes(struct drm_connector *connector) aconnector->edid = edid; } - if (aconnector->dc_sink && aconnector->dc_sink->sink_signal == SIGNAL_TYPE_VIRTUAL) + if (aconnector->dc_sink && aconnector->dc_sink->sink_signal == SIGNAL_TYPE_VIRTUAL) { dc_sink_release(aconnector->dc_sink); + aconnector->dc_sink = NULL; + } if (!aconnector->dc_sink) { struct dc_sink *dc_sink; -- cgit v1.2.3 From 810ece19ee74c5705190ef18ccb292e7930a2377 Mon Sep 17 00:00:00 2001 From: Yongqiang Sun Date: Thu, 24 Jan 2019 15:59:22 -0500 Subject: drm/amd/display: Calc vline position in dc. We need to calcualte vline position in DC for DCN. Signed-off-by: Yongqiang Sun Reviewed-by: Tony Cheng Acked-by: Bhawanpreet Lakha Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc.c | 8 +-- drivers/gpu/drm/amd/display/dc/dc_stream.h | 15 ++-- drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c | 80 ++++++++++++++++++++-- drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h | 6 +- .../drm/amd/display/dc/inc/hw/timing_generator.h | 8 ++- 5 files changed, 97 insertions(+), 20 deletions(-) (limited to 'drivers/gpu/drm/amd/display') diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index d9f62befd86a..409097cf58ed 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -1572,13 +1572,13 @@ static void commit_planes_do_stream_update(struct dc *dc, stream_update->adjust->v_total_min, stream_update->adjust->v_total_max); - if (stream_update->vline0_config && pipe_ctx->stream_res.tg->funcs->program_vline_interrupt) + if (stream_update->periodic_vsync_config && pipe_ctx->stream_res.tg->funcs->program_vline_interrupt) pipe_ctx->stream_res.tg->funcs->program_vline_interrupt( - pipe_ctx->stream_res.tg, VLINE0, &stream->vline0_config); + pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing, VLINE0, &stream->periodic_vsync_config); - if (stream_update->vline1_config && pipe_ctx->stream_res.tg->funcs->program_vline_interrupt) + if (stream_update->enhanced_sync_config && pipe_ctx->stream_res.tg->funcs->program_vline_interrupt) pipe_ctx->stream_res.tg->funcs->program_vline_interrupt( - pipe_ctx->stream_res.tg, VLINE1, &stream->vline1_config); + pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing, VLINE1, &stream->enhanced_sync_config); if ((stream_update->hdr_static_metadata && !stream->use_dynamic_meta) || stream_update->vrr_infopacket || diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h b/drivers/gpu/drm/amd/display/dc/dc_stream.h index 2d1f2825de09..90f019eb54b3 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_stream.h +++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h @@ -51,11 +51,12 @@ struct freesync_context { bool dummy; }; -struct vline_config { - unsigned int start_line; - unsigned int end_line; +union vline_config { + unsigned int line_number; + unsigned long long delta_in_ns; }; + struct dc_stream_state { // sink is deprecated, new code should not reference // this pointer @@ -105,8 +106,8 @@ struct dc_stream_state { /* DMCU info */ unsigned int abm_level; - struct vline_config vline0_config; - struct vline_config vline1_config; + union vline_config periodic_vsync_config; + union vline_config enhanced_sync_config; /* from core_stream struct */ struct dc_context *ctx; @@ -155,8 +156,8 @@ struct dc_stream_update { struct dc_info_packet *hdr_static_metadata; unsigned int *abm_level; - struct vline_config *vline0_config; - struct vline_config *vline1_config; + union vline_config *periodic_vsync_config; + union vline_config *enhanced_sync_config; struct dc_crtc_timing_adjust *adjust; struct dc_info_packet *vrr_infopacket; diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c index cefa322df8a6..0355dcb8554a 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c @@ -92,22 +92,94 @@ static void optc1_disable_stereo(struct timing_generator *optc) OTG_3D_STRUCTURE_STEREO_SEL_OVR, 0); } +static uint32_t get_start_vline(struct timing_generator *optc, const struct dc_crtc_timing *dc_crtc_timing) +{ + struct dc_crtc_timing patched_crtc_timing; + int vesa_sync_start; + int asic_blank_end; + int interlace_factor; + int vertical_line_start; + + patched_crtc_timing = *dc_crtc_timing; + optc1_apply_front_porch_workaround(optc, &patched_crtc_timing); + + vesa_sync_start = patched_crtc_timing.h_addressable + + patched_crtc_timing.h_border_right + + patched_crtc_timing.h_front_porch; + + asic_blank_end = patched_crtc_timing.h_total - + vesa_sync_start - + patched_crtc_timing.h_border_left; + + interlace_factor = patched_crtc_timing.flags.INTERLACE ? 2 : 1; + + vesa_sync_start = patched_crtc_timing.v_addressable + + patched_crtc_timing.v_border_bottom + + patched_crtc_timing.v_front_porch; + + asic_blank_end = (patched_crtc_timing.v_total - + vesa_sync_start - + patched_crtc_timing.v_border_top) + * interlace_factor; + + vertical_line_start = asic_blank_end - optc->dlg_otg_param.vstartup_start + 1; + if (vertical_line_start < 0) { + ASSERT(0); + vertical_line_start = 0; + } + + return vertical_line_start; +} + +static void calc_vline_position( + struct timing_generator *optc, + const struct dc_crtc_timing *dc_crtc_timing, + unsigned long long vsync_delta, + uint32_t *start_line, + uint32_t *end_line) +{ + unsigned long long req_delta_tens_of_usec = div64_u64((vsync_delta + 9999), 10000); + unsigned long long pix_clk_hundreds_khz = div64_u64((dc_crtc_timing->pix_clk_100hz + 999), 1000); + uint32_t req_delta_lines = (uint32_t) div64_u64( + (req_delta_tens_of_usec * pix_clk_hundreds_khz + dc_crtc_timing->h_total - 1), + dc_crtc_timing->h_total); + + uint32_t vsync_line = get_start_vline(optc, dc_crtc_timing); + + if (req_delta_lines != 0) + req_delta_lines--; + + if (req_delta_lines > vsync_line) + *start_line = dc_crtc_timing->v_total - (req_delta_lines - vsync_line) - 1; + else + *start_line = vsync_line - req_delta_lines; + + *end_line = *start_line + 2; + + if (*end_line >= dc_crtc_timing->v_total) + *end_line = 2; +} + void optc1_program_vline_interrupt( struct timing_generator *optc, + const struct dc_crtc_timing *dc_crtc_timing, enum vline_select vline, - const struct vline_config *vline_config) + const union vline_config *vline_config) { struct optc *optc1 = DCN10TG_FROM_TG(optc); + uint32_t start_line = 0; + uint32_t end_line = 0; switch (vline) { case VLINE0: + calc_vline_position(optc, dc_crtc_timing, vline_config->delta_in_ns, &start_line, &end_line); REG_SET_2(OTG_VERTICAL_INTERRUPT0_POSITION, 0, - OTG_VERTICAL_INTERRUPT0_LINE_START, vline_config->start_line, - OTG_VERTICAL_INTERRUPT0_LINE_END, vline_config->end_line); + OTG_VERTICAL_INTERRUPT0_LINE_START, start_line, + OTG_VERTICAL_INTERRUPT0_LINE_END, end_line); break; case VLINE1: REG_SET(OTG_VERTICAL_INTERRUPT1_POSITION, 0, - OTG_VERTICAL_INTERRUPT1_LINE_START, vline_config->start_line); + OTG_VERTICAL_INTERRUPT1_LINE_START, vline_config->line_number); break; default: break; diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h index b34c8a240598..8a4e3e37e894 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h @@ -483,9 +483,11 @@ void optc1_program_timing( const struct dc_crtc_timing *dc_crtc_timing, bool use_vbios); -void optc1_program_vline_interrupt(struct timing_generator *optc, +void optc1_program_vline_interrupt( + struct timing_generator *optc, + const struct dc_crtc_timing *dc_crtc_timing, enum vline_select vline, - const struct vline_config *vline_config); + const union vline_config *vline_config); void optc1_program_global_sync( struct timing_generator *optc); diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h b/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h index d22a406c19c0..39fec0186c10 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h @@ -134,7 +134,7 @@ struct dc_crtc_timing; struct drr_params; -struct vline_config; +union vline_config; enum vline_select { @@ -149,9 +149,11 @@ struct timing_generator_funcs { void (*program_timing)(struct timing_generator *tg, const struct dc_crtc_timing *timing, bool use_vbios); - void (*program_vline_interrupt)(struct timing_generator *optc, + void (*program_vline_interrupt)( + struct timing_generator *optc, + const struct dc_crtc_timing *dc_crtc_timing, enum vline_select vline, - const struct vline_config *vline_config); + const union vline_config *vline_config); bool (*enable_crtc)(struct timing_generator *tg); bool (*disable_crtc)(struct timing_generator *tg); bool (*is_counter_moving)(struct timing_generator *tg); -- cgit v1.2.3 From b9d4b33059b86147bcde8f53ad19b97792837f75 Mon Sep 17 00:00:00 2001 From: Wesley Chalmers Date: Tue, 22 Jan 2019 18:57:06 -0500 Subject: drm/amd/display: Disable Stutter for Stereo 3D [WHY] Bandwidth calculation formulas currently do not take Stereo 3D + Stutter properly into account. Disable stutter feature when we detect a Stereo 3D mode as a temporary workaround. Signed-off-by: Wesley Chalmers Reviewed-by: Tony Cheng Acked-by: Bhawanpreet Lakha Acked-by: Martin Leung Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c | 19 +++++++++++-------- drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h | 2 +- .../drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c | 20 +++++++++++++++++++- 3 files changed, 31 insertions(+), 10 deletions(-) (limited to 'drivers/gpu/drm/amd/display') diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c index 5a4614c371bc..e161ad836812 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c @@ -88,11 +88,18 @@ void hubbub1_wm_read_state(struct hubbub *hubbub, s->dram_clk_chanage = REG_READ(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D); } -void hubbub1_disable_allow_self_refresh(struct hubbub *hubbub) +void hubbub1_allow_self_refresh_control(struct hubbub *hubbub, bool allow) { struct dcn10_hubbub *hubbub1 = TO_DCN10_HUBBUB(hubbub); - REG_UPDATE(DCHUBBUB_ARB_DRAM_STATE_CNTL, - DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE, 0); + + /* + * DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE = 1 means do not allow stutter + * DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE = 0 means allow stutter + */ + + REG_UPDATE_2(DCHUBBUB_ARB_DRAM_STATE_CNTL, + DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_VALUE, 0, + DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE, !allow); } bool hububu1_is_allow_self_refresh_enabled(struct hubbub *hubbub) @@ -262,8 +269,6 @@ void hubbub1_program_watermarks( bool safe_to_lower) { struct dcn10_hubbub *hubbub1 = TO_DCN10_HUBBUB(hubbub); - - uint32_t force_en = hubbub1->base.ctx->dc->debug.disable_stutter ? 1 : 0; /* * Need to clamp to max of the register values (i.e. no wrap) * for dcn1, all wm registers are 21-bit wide @@ -537,9 +542,7 @@ void hubbub1_program_watermarks( REG_UPDATE(DCHUBBUB_ARB_DF_REQ_OUTSTAND, DCHUBBUB_ARB_MIN_REQ_OUTSTAND, 68); - REG_UPDATE_2(DCHUBBUB_ARB_DRAM_STATE_CNTL, - DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_VALUE, 0, - DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE, force_en); + hubbub1_allow_self_refresh_control(hubbub, !hubbub->ctx->dc->debug.disable_stutter); #if 0 REG_UPDATE_2(DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL, diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h index c681e1cc9290..9cd4a5194154 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h @@ -204,7 +204,7 @@ void hubbub1_program_watermarks( unsigned int refclk_mhz, bool safe_to_lower); -void hubbub1_disable_allow_self_refresh(struct hubbub *hubbub); +void hubbub1_allow_self_refresh_control(struct hubbub *hubbub, bool allow); bool hububu1_is_allow_self_refresh_enabled(struct hubbub *hubub); diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c index 9f23ea283838..7cead0398c15 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c @@ -1011,7 +1011,7 @@ static void dcn10_init_hw(struct dc *dc) */ if (allow_self_fresh_force_enable == false && hububu1_is_allow_self_refresh_enabled(dc->res_pool->hubbub)) - hubbub1_disable_allow_self_refresh(dc->res_pool->hubbub); + hubbub1_allow_self_refresh_control(dc->res_pool->hubbub, true); disable_vga(dc->hwseq); } @@ -2384,6 +2384,22 @@ static void dcn10_apply_ctx_for_surface( hubbub1_wm_change_req_wa(dc->res_pool->hubbub); } +static void dcn10_stereo_hw_frame_pack_wa(struct dc *dc, struct dc_state *context) +{ + uint8_t i; + + for (i = 0; i < context->stream_count; i++) { + if (context->streams[i]->timing.timing_3d_format + == TIMING_3D_FORMAT_HW_FRAME_PACKING) { + /* + * Disable stutter + */ + hubbub1_allow_self_refresh_control(dc->res_pool->hubbub, false); + break; + } + } +} + static void dcn10_prepare_bandwidth( struct dc *dc, struct dc_state *context) @@ -2405,6 +2421,7 @@ static void dcn10_prepare_bandwidth( &context->bw.dcn.watermarks, dc->res_pool->ref_clock_inKhz / 1000, true); + dcn10_stereo_hw_frame_pack_wa(dc, context); if (dc->debug.pplib_wm_report_mode == WM_REPORT_OVERRIDE) dcn_bw_notify_pplib_of_wm_ranges(dc); @@ -2434,6 +2451,7 @@ static void dcn10_optimize_bandwidth( &context->bw.dcn.watermarks, dc->res_pool->ref_clock_inKhz / 1000, true); + dcn10_stereo_hw_frame_pack_wa(dc, context); if (dc->debug.pplib_wm_report_mode == WM_REPORT_OVERRIDE) dcn_bw_notify_pplib_of_wm_ranges(dc); -- cgit v1.2.3 From 00fbeb4e2f9eda0ebd57eefdcf25e41958f98fa5 Mon Sep 17 00:00:00 2001 From: Eryk Brol Date: Mon, 21 Jan 2019 14:40:16 -0500 Subject: drm/amd/display: DC VM Fixes [Why] VM_helper needs to be intialized with the dc struct in order to fix an unallocated memory issue. System aperture settings should be initialized to 0 and guarded with a check to make sure vm_config is valid. [How] Allocate and free memory for vm_helper with other dc members. Check whether the vm_config valid bit is set before initializing aperture settings. Signed-off-by: Eryk Brol Reviewed-by: Jun Lei Acked-by: Bhawanpreet Lakha Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc.c | 1 - drivers/gpu/drm/amd/display/dc/core/dc_vm_helper.c | 18 +++++++----------- drivers/gpu/drm/amd/display/dc/dc.h | 1 - drivers/gpu/drm/amd/display/dc/inc/vm_helper.h | 7 ++++--- 4 files changed, 11 insertions(+), 16 deletions(-) (limited to 'drivers/gpu/drm/amd/display') diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 409097cf58ed..af5f486d24e0 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -621,7 +621,6 @@ static bool construct(struct dc *dc, #endif enum dce_version dc_version = DCE_VERSION_UNKNOWN; - dc_dceip = kzalloc(sizeof(*dc_dceip), GFP_KERNEL); if (!dc_dceip) { dm_error("%s: failed to create dceip\n", __func__); diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_vm_helper.c b/drivers/gpu/drm/amd/display/dc/core/dc_vm_helper.c index e54b8ac339b2..6ce87b682a32 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_vm_helper.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_vm_helper.c @@ -112,16 +112,12 @@ uint8_t get_vmid_for_ptb(struct vm_helper *vm_helper, int64_t ptb, uint8_t hubp_ return vmid; } -struct vm_helper init_vm_helper(unsigned int num_vmid, unsigned int num_hubp) +void init_vm_helper(struct vm_helper *vm_helper, unsigned int num_vmid, unsigned int num_hubp) { - static uint64_t ptb_assigned_to_vmid[MAX_VMID]; - static struct vmid_usage hubp_vmid_usage[MAX_HUBP]; - - return (struct vm_helper){ - .num_vmid = num_vmid, - .num_hubp = num_hubp, - .num_vmids_available = num_vmid - 1, - .ptb_assigned_to_vmid = ptb_assigned_to_vmid, - .hubp_vmid_usage = hubp_vmid_usage - }; + vm_helper->num_vmid = num_vmid; + vm_helper->num_hubp = num_hubp; + vm_helper->num_vmids_available = num_vmid - 1; + + memset(vm_helper->hubp_vmid_usage, 0, sizeof(vm_helper->hubp_vmid_usage[0]) * MAX_HUBP); + memset(vm_helper->ptb_assigned_to_vmid, 0, sizeof(vm_helper->ptb_assigned_to_vmid[0]) * MAX_VMID); } diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index ee2c7e5b6087..2224bba914ec 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -265,7 +265,6 @@ struct dc_debug_data { uint32_t auxErrorCount; }; - struct dc_state; struct resource_pool; struct dce_hwseq; diff --git a/drivers/gpu/drm/amd/display/dc/inc/vm_helper.h b/drivers/gpu/drm/amd/display/dc/inc/vm_helper.h index a202206e22a3..193407f76a80 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/vm_helper.h +++ b/drivers/gpu/drm/amd/display/dc/inc/vm_helper.h @@ -39,8 +39,8 @@ struct vm_helper { unsigned int num_vmid; unsigned int num_hubp; unsigned int num_vmids_available; - uint64_t *ptb_assigned_to_vmid; - struct vmid_usage *hubp_vmid_usage; + uint64_t ptb_assigned_to_vmid[MAX_VMID]; + struct vmid_usage hubp_vmid_usage[MAX_HUBP]; }; uint8_t get_vmid_for_ptb( @@ -48,7 +48,8 @@ uint8_t get_vmid_for_ptb( int64_t ptb, uint8_t pipe_idx); -struct vm_helper init_vm_helper( +void init_vm_helper( + struct vm_helper *vm_helper, unsigned int num_vmid, unsigned int num_hubp); -- cgit v1.2.3 From de00d253bc85978c1a7d3be888d675488d18a5dd Mon Sep 17 00:00:00 2001 From: Anthony Koo Date: Fri, 25 Jan 2019 11:50:31 -0500 Subject: drm/amd/display: link_rate_set should index into table [Why] Current implementation that maps link_rate_set value to actual link rate is incorrect. [How] Fix this implementation, such that link_rate_set indexes into the supported_link_rate table. Signed-off-by: Anthony Koo Reviewed-by: Harry Wentland Acked-by: Aric Cyr Acked-by: Bhawanpreet Lakha Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c | 35 +----------------------- 1 file changed, 1 insertion(+), 34 deletions(-) (limited to 'drivers/gpu/drm/amd/display') diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c index 5ee36d6e0512..09d301216076 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c @@ -2540,7 +2540,6 @@ void detect_edp_sink_caps(struct dc_link *link) uint32_t entry; uint32_t link_rate_in_khz; enum dc_link_rate link_rate = LINK_RATE_UNKNOWN; - uint8_t link_rate_set = 0; retrieve_link_cap(link); @@ -2560,39 +2559,7 @@ void detect_edp_sink_caps(struct dc_link *link) link_rate = linkRateInKHzToLinkRateMultiplier(link_rate_in_khz); if (link->reported_link_cap.link_rate < link_rate) { link->reported_link_cap.link_rate = link_rate; - - switch (link_rate) { - case LINK_RATE_LOW: - link_rate_set = 1; - break; - case LINK_RATE_RATE_2: - link_rate_set = 2; - break; - case LINK_RATE_RATE_3: - link_rate_set = 3; - break; - case LINK_RATE_HIGH: - link_rate_set = 4; - break; - case LINK_RATE_RBR2: - link_rate_set = 5; - break; - case LINK_RATE_RATE_6: - link_rate_set = 6; - break; - case LINK_RATE_HIGH2: - link_rate_set = 7; - break; - case LINK_RATE_HIGH3: - link_rate_set = 8; - break; - default: - link_rate_set = 0; - break; - } - - if (link->dpcd_caps.link_rate_set < link_rate_set) - link->dpcd_caps.link_rate_set = link_rate_set; + link->dpcd_caps.link_rate_set = entry; } } } -- cgit v1.2.3 From e6d2421343a78a3ef83d7839a8704dd2eb3c9a69 Mon Sep 17 00:00:00 2001 From: Murton Liu Date: Wed, 23 Jan 2019 17:37:57 -0500 Subject: drm/amd/display: PIP overlay corruption [Why] When moving mouse onto or off of pip plane, screen would flash briefly due to garbage negative pos values being programmed for cursor. Also, text flashes due to PIP flips taking too long. [How] When negative pos value seen, default to 0 and adjust by modifying cursor hotspot. For flip issue, only do post update when optimize required vs all the time. Signed-off-by: Murton Liu Reviewed-by: Aric Cyr Acked-by: Bhawanpreet Lakha Acked-by: Sivapiriyan Kumarasamy Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc.c | 3 +++ drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c | 23 +++++++++++++++++++++-- 2 files changed, 24 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/amd/display') diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index af5f486d24e0..77e1bd18b1dd 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -1125,6 +1125,9 @@ bool dc_post_update_surfaces_to_stream(struct dc *dc) int i; struct dc_state *context = dc->current_state; + if (dc->optimized_required == false) + return true; + post_surface_trace(dc); for (i = 0; i < dc->res_pool->pipe_count; i++) diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c index 0ba68d41b9c3..683829466a44 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c @@ -1150,9 +1150,28 @@ void hubp1_cursor_set_position( REG_UPDATE(CURSOR_CONTROL, CURSOR_ENABLE, cur_en); - REG_SET_2(CURSOR_POSITION, 0, - CURSOR_X_POSITION, pos->x, + //account for cases where we see negative offset relative to overlay plane + if (src_x_offset < 0 && src_y_offset < 0) { + REG_SET_2(CURSOR_POSITION, 0, + CURSOR_X_POSITION, 0, + CURSOR_Y_POSITION, 0); + x_hotspot -= src_x_offset; + y_hotspot -= src_y_offset; + } else if (src_x_offset < 0) { + REG_SET_2(CURSOR_POSITION, 0, + CURSOR_X_POSITION, 0, CURSOR_Y_POSITION, pos->y); + x_hotspot -= src_x_offset; + } else if (src_y_offset < 0) { + REG_SET_2(CURSOR_POSITION, 0, + CURSOR_X_POSITION, pos->x, + CURSOR_Y_POSITION, 0); + y_hotspot -= src_y_offset; + } else { + REG_SET_2(CURSOR_POSITION, 0, + CURSOR_X_POSITION, pos->x, + CURSOR_Y_POSITION, pos->y); + } REG_SET_2(CURSOR_HOT_SPOT, 0, CURSOR_HOT_SPOT_X, x_hotspot, -- cgit v1.2.3 From c00800c46e832ca27f4db489b8c28a56603f8d2c Mon Sep 17 00:00:00 2001 From: mark mcgarrity Date: Fri, 25 Jan 2019 14:38:34 -0500 Subject: drm/amd/display: 3.2.17 Signed-off-by: mark mcgarrity Reviewed-by: Aric Cyr Acked-by: Bhawanpreet Lakha Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/amd/display') diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 2224bba914ec..bade219d1268 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -39,7 +39,7 @@ #include "inc/hw/dmcu.h" #include "dml/display_mode_lib.h" -#define DC_VER "3.2.16" +#define DC_VER "3.2.17" #define MAX_SURFACES 3 #define MAX_STREAMS 6 -- cgit v1.2.3 From 68f1a00c23d443c9d940fbd512a195e9e6c08b11 Mon Sep 17 00:00:00 2001 From: Anthony Koo Date: Sun, 20 Jan 2019 01:08:02 -0500 Subject: drm/amd/display: interface to check if timing can be seamless [Why] Need to figure out whether a timing we want to commit matches something that GOP already programmed, in which case we can decide to some optimizations [How] 1. Add way to check for DIG FE 2. Add way to check for matching OTG timing 3. Add way to check for matching pixel clock (if possible) - Currently only support DP for pixel clock, since it is easy to calc Signed-off-by: Anthony Koo Reviewed-by: Aric Cyr Acked-by: Bhawanpreet Lakha Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc.c | 46 +++++++++++++++++ drivers/gpu/drm/amd/display/dc/dc.h | 4 ++ .../gpu/drm/amd/display/dc/dce/dce_clock_source.c | 28 +++++++++- .../drm/amd/display/dc/dcn10/dcn10_link_encoder.c | 10 ++++ .../drm/amd/display/dc/dcn10/dcn10_link_encoder.h | 2 + drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c | 59 ++++++++++++++++++++++ drivers/gpu/drm/amd/display/dc/inc/clock_source.h | 4 ++ .../gpu/drm/amd/display/dc/inc/hw/link_encoder.h | 1 + .../drm/amd/display/dc/inc/hw/timing_generator.h | 2 + 9 files changed, 154 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/amd/display') diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 77e1bd18b1dd..b620520771a7 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -969,6 +969,52 @@ static bool context_changed( return false; } +bool dc_validate_seamless_boot_timing(struct dc *dc, + const struct dc_sink *sink, + struct dc_crtc_timing *crtc_timing) +{ + struct timing_generator *tg; + struct dc_link *link = sink->link; + unsigned int inst; + + /* Check for enabled DIG to identify enabled display */ + if (!link->link_enc->funcs->is_dig_enabled(link->link_enc)) + return false; + + /* Check for which front end is used by this encoder. + * Note the inst is 1 indexed, where 0 is undefined. + * Note that DIG_FE can source from different OTG but our + * current implementation always map 1-to-1, so this code makes + * the same assumption and doesn't check OTG source. + */ + inst = link->link_enc->funcs->get_dig_frontend(link->link_enc) - 1; + + /* Instance should be within the range of the pool */ + if (inst >= dc->res_pool->pipe_count) + return false; + + tg = dc->res_pool->timing_generators[inst]; + + if (!tg->funcs->is_matching_timing) + return false; + + if (!tg->funcs->is_matching_timing(tg, crtc_timing)) + return false; + + if (dc_is_dp_signal(link->connector_signal)) { + unsigned int pix_clk_100hz; + + dc->res_pool->dp_clock_source->funcs->get_pixel_clk_frequency_100hz( + dc->res_pool->dp_clock_source, + inst, &pix_clk_100hz); + + if (crtc_timing->pix_clk_100hz != pix_clk_100hz) + return false; + } + + return true; +} + bool dc_enable_stereo( struct dc *dc, struct dc_state *context, diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index bade219d1268..1a7fd6aa77eb 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -594,6 +594,10 @@ struct dc_validation_set { uint8_t plane_count; }; +bool dc_validate_seamless_boot_timing(struct dc *dc, + const struct dc_sink *sink, + struct dc_crtc_timing *crtc_timing); + enum dc_status dc_validate_plane(struct dc *dc, const struct dc_plane_state *plane_state); void get_clock_requirements_for_state(struct dc_state *state, struct AsicStateEx *info); diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c index c67e90e5c339..71d5777de961 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c @@ -977,6 +977,28 @@ static bool dce110_clock_source_power_down( return bp_result == BP_RESULT_OK; } +static bool get_pixel_clk_frequency_100hz( + struct clock_source *clock_source, + unsigned int inst, + unsigned int *pixel_clk_khz) +{ + struct dce110_clk_src *clk_src = TO_DCE110_CLK_SRC(clock_source); + unsigned int clock_hz = 0; + + if (clock_source->id == CLOCK_SOURCE_ID_DP_DTO) { + clock_hz = REG_READ(PHASE[inst]); + + /* NOTE: There is agreement with VBIOS here that MODULO is + * programmed equal to DPREFCLK, in which case PHASE will be + * equivalent to pixel clock. + */ + *pixel_clk_khz = clock_hz / 100; + return true; + } + + return false; +} + /*****************************************/ /* Constructor */ /*****************************************/ @@ -984,12 +1006,14 @@ static bool dce110_clock_source_power_down( static const struct clock_source_funcs dce112_clk_src_funcs = { .cs_power_down = dce110_clock_source_power_down, .program_pix_clk = dce112_program_pix_clk, - .get_pix_clk_dividers = dce112_get_pix_clk_dividers + .get_pix_clk_dividers = dce112_get_pix_clk_dividers, + .get_pixel_clk_frequency_100hz = get_pixel_clk_frequency_100hz }; static const struct clock_source_funcs dce110_clk_src_funcs = { .cs_power_down = dce110_clock_source_power_down, .program_pix_clk = dce110_program_pix_clk, - .get_pix_clk_dividers = dce110_get_pix_clk_dividers + .get_pix_clk_dividers = dce110_get_pix_clk_dividers, + .get_pixel_clk_frequency_100hz = get_pixel_clk_frequency_100hz }; diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c index 771449f8984f..a9db372688ff 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c @@ -85,6 +85,7 @@ static const struct link_encoder_funcs dcn10_lnk_enc_funcs = { .enable_hpd = dcn10_link_encoder_enable_hpd, .disable_hpd = dcn10_link_encoder_disable_hpd, .is_dig_enabled = dcn10_is_dig_enabled, + .get_dig_frontend = dcn10_get_dig_frontend, .destroy = dcn10_link_encoder_destroy }; @@ -495,6 +496,15 @@ bool dcn10_is_dig_enabled(struct link_encoder *enc) return value; } +unsigned int dcn10_get_dig_frontend(struct link_encoder *enc) +{ + struct dcn10_link_encoder *enc10 = TO_DCN10_LINK_ENC(enc); + uint32_t value; + + REG_GET(DIG_BE_CNTL, DIG_FE_SOURCE_SELECT, &value); + return value; +} + static void link_encoder_disable(struct dcn10_link_encoder *enc10) { /* reset training pattern */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.h index 670b46e887ed..b74b80a247ec 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.h @@ -336,6 +336,8 @@ void dcn10_psr_program_secondary_packet(struct link_encoder *enc, bool dcn10_is_dig_enabled(struct link_encoder *enc); +unsigned int dcn10_get_dig_frontend(struct link_encoder *enc); + void dcn10_aux_initialize(struct dcn10_link_encoder *enc10); #endif /* __DC_LINK_ENCODER__DCN10_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c index 0355dcb8554a..51c98e99237e 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c @@ -1208,6 +1208,64 @@ bool optc1_is_stereo_left_eye(struct timing_generator *optc) return ret; } +bool optc1_is_matching_timing(struct timing_generator *tg, + const struct dc_crtc_timing *otg_timing) +{ + struct dc_crtc_timing hw_crtc_timing = {0}; + struct dcn_otg_state s = {0}; + + if (tg == NULL || otg_timing == NULL) + return false; + + optc1_read_otg_state(DCN10TG_FROM_TG(tg), &s); + + hw_crtc_timing.h_total = s.h_total + 1; + hw_crtc_timing.h_addressable = s.h_total - ((s.h_total - s.h_blank_start) + s.h_blank_end); + hw_crtc_timing.h_front_porch = s.h_total + 1 - s.h_blank_start; + hw_crtc_timing.h_sync_width = s.h_sync_a_end - s.h_sync_a_start; + + hw_crtc_timing.v_total = s.v_total + 1; + hw_crtc_timing.v_addressable = s.v_total - ((s.v_total - s.v_blank_start) + s.v_blank_end); + hw_crtc_timing.v_front_porch = s.v_total + 1 - s.v_blank_start; + hw_crtc_timing.v_sync_width = s.v_sync_a_end - s.v_sync_a_start; + + if (otg_timing->h_total != hw_crtc_timing.h_total) + return false; + + if (otg_timing->h_border_left != hw_crtc_timing.h_border_left) + return false; + + if (otg_timing->h_addressable != hw_crtc_timing.h_addressable) + return false; + + if (otg_timing->h_border_right != hw_crtc_timing.h_border_right) + return false; + + if (otg_timing->h_front_porch != hw_crtc_timing.h_front_porch) + return false; + + if (otg_timing->h_sync_width != hw_crtc_timing.h_sync_width) + return false; + + if (otg_timing->v_total != hw_crtc_timing.v_total) + return false; + + if (otg_timing->v_border_top != hw_crtc_timing.v_border_top) + return false; + + if (otg_timing->v_addressable != hw_crtc_timing.v_addressable) + return false; + + if (otg_timing->v_border_bottom != hw_crtc_timing.v_border_bottom) + return false; + + if (otg_timing->v_sync_width != hw_crtc_timing.v_sync_width) + return false; + + return true; +} + + void optc1_read_otg_state(struct optc *optc1, struct dcn_otg_state *s) { @@ -1404,6 +1462,7 @@ static const struct timing_generator_funcs dcn10_tg_funcs = { .get_frame_count = optc1_get_vblank_counter, .get_scanoutpos = optc1_get_crtc_scanoutpos, .get_otg_active_size = optc1_get_otg_active_size, + .is_matching_timing = optc1_is_matching_timing, .set_early_control = optc1_set_early_control, /* used by enable_timing_synchronization. Not need for FPGA */ .wait_for_state = optc1_wait_for_state, diff --git a/drivers/gpu/drm/amd/display/dc/inc/clock_source.h b/drivers/gpu/drm/amd/display/dc/inc/clock_source.h index 43d1fbd8ace5..fe6301cb8681 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/clock_source.h +++ b/drivers/gpu/drm/amd/display/dc/inc/clock_source.h @@ -166,6 +166,10 @@ struct clock_source_funcs { struct clock_source *, struct pixel_clk_params *, struct pll_settings *); + bool (*get_pixel_clk_frequency_100hz)( + struct clock_source *clock_source, + unsigned int inst, + unsigned int *pixel_clk_khz); }; struct clock_source { diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h b/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h index c20fdcaac53b..c9d3e37e9531 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h @@ -153,6 +153,7 @@ struct link_encoder_funcs { void (*enable_hpd)(struct link_encoder *enc); void (*disable_hpd)(struct link_encoder *enc); bool (*is_dig_enabled)(struct link_encoder *enc); + unsigned int (*get_dig_frontend)(struct link_encoder *enc); void (*destroy)(struct link_encoder **enc); }; diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h b/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h index 39fec0186c10..5d6cca7826f3 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h @@ -170,6 +170,8 @@ struct timing_generator_funcs { bool (*get_otg_active_size)(struct timing_generator *optc, uint32_t *otg_active_width, uint32_t *otg_active_height); + bool (*is_matching_timing)(struct timing_generator *tg, + const struct dc_crtc_timing *otg_timing); void (*set_early_control)(struct timing_generator *tg, uint32_t early_cntl); void (*wait_for_state)(struct timing_generator *tg, -- cgit v1.2.3 From a122b62d8ac484091c536ad04e1d0ea156ae6de7 Mon Sep 17 00:00:00 2001 From: Anthony Koo Date: Sun, 20 Jan 2019 01:13:42 -0500 Subject: drm/amd/display: refactor out programming of vupdate interrupt [Why] More clearly isolate the code that is involved in programming of vupdate interrupt [How] Add function for programming of vupdate interrupt. Call it after timing is programmed. Signed-off-by: Anthony Koo Reviewed-by: Aric Cyr Acked-by: Bhawanpreet Lakha Acked-by: Tony Cheng Signed-off-by: Alex Deucher --- .../amd/display/dc/dce110/dce110_hw_sequencer.c | 5 +++ drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c | 51 +++++++++++++++++----- .../drm/amd/display/dc/inc/hw/timing_generator.h | 3 ++ 3 files changed, 48 insertions(+), 11 deletions(-) (limited to 'drivers/gpu/drm/amd/display') diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c index fd7cd5b5a17c..e2d8362dd5b1 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c @@ -1341,6 +1341,11 @@ static enum dc_status apply_single_controller_ctx_to_hw( /* */ dc->hwss.enable_stream_timing(pipe_ctx, context, dc); + if (pipe_ctx->stream_res.tg->funcs->program_vupdate_interrupt) + pipe_ctx->stream_res.tg->funcs->program_vupdate_interrupt( + pipe_ctx->stream_res.tg, + &stream->timing); + if (pipe_ctx->stream->signal != SIGNAL_TYPE_VIRTUAL) pipe_ctx->stream_res.stream_enc->funcs->dig_connect_to_otg( pipe_ctx->stream_res.stream_enc, diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c index 51c98e99237e..1dbd1d3999e6 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c @@ -186,6 +186,42 @@ void optc1_program_vline_interrupt( } } +void optc1_program_vupdate_interrupt( + struct timing_generator *optc, + const struct dc_crtc_timing *dc_crtc_timing) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + int32_t vertical_line_start; + uint32_t asic_blank_end; + uint32_t vesa_sync_start; + struct dc_crtc_timing patched_crtc_timing; + + patched_crtc_timing = *dc_crtc_timing; + optc1_apply_front_porch_workaround(optc, &patched_crtc_timing); + + /* asic_h_blank_end = HsyncWidth + HbackPorch = + * vesa. usHorizontalTotal - vesa. usHorizontalSyncStart - + * vesa.h_left_border + */ + vesa_sync_start = patched_crtc_timing.h_addressable + + patched_crtc_timing.h_border_right + + patched_crtc_timing.h_front_porch; + + asic_blank_end = patched_crtc_timing.h_total - + vesa_sync_start - + patched_crtc_timing.h_border_left; + + /* Use OTG_VERTICAL_INTERRUPT2 replace VUPDATE interrupt, + * program the reg for interrupt postition. + */ + vertical_line_start = asic_blank_end - optc->dlg_otg_param.vstartup_start + 1; + if (vertical_line_start < 0) + vertical_line_start = 0; + + REG_SET(OTG_VERTICAL_INTERRUPT2_POSITION, 0, + OTG_VERTICAL_INTERRUPT2_LINE_START, vertical_line_start); +} + /** * program_timing_generator used by mode timing set * Program CRTC Timing Registers - OTG_H_*, OTG_V_*, Pixel repetition. @@ -288,22 +324,14 @@ void optc1_program_timing( patched_crtc_timing.v_addressable + patched_crtc_timing.v_border_bottom); - REG_UPDATE_2(OTG_V_BLANK_START_END, - OTG_V_BLANK_START, asic_blank_start, - OTG_V_BLANK_END, asic_blank_end); - - /* Use OTG_VERTICAL_INTERRUPT2 replace VUPDATE interrupt, - * program the reg for interrupt postition. - */ vertical_line_start = asic_blank_end - optc->dlg_otg_param.vstartup_start + 1; v_fp2 = 0; if (vertical_line_start < 0) v_fp2 = -vertical_line_start; - if (vertical_line_start < 0) - vertical_line_start = 0; - REG_SET(OTG_VERTICAL_INTERRUPT2_POSITION, 0, - OTG_VERTICAL_INTERRUPT2_LINE_START, vertical_line_start); + REG_UPDATE_2(OTG_V_BLANK_START_END, + OTG_V_BLANK_START, asic_blank_start, + OTG_V_BLANK_END, asic_blank_end); /* v_sync polarity */ v_sync_polarity = patched_crtc_timing.flags.VSYNC_POSITIVE_POLARITY ? @@ -1453,6 +1481,7 @@ static const struct timing_generator_funcs dcn10_tg_funcs = { .validate_timing = optc1_validate_timing, .program_timing = optc1_program_timing, .program_vline_interrupt = optc1_program_vline_interrupt, + .program_vupdate_interrupt = optc1_program_vupdate_interrupt, .program_global_sync = optc1_program_global_sync, .enable_crtc = optc1_enable_crtc, .disable_crtc = optc1_disable_crtc, diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h b/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h index 5d6cca7826f3..03ae941895f3 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h @@ -154,6 +154,9 @@ struct timing_generator_funcs { const struct dc_crtc_timing *dc_crtc_timing, enum vline_select vline, const union vline_config *vline_config); + + void (*program_vupdate_interrupt)(struct timing_generator *optc, + const struct dc_crtc_timing *dc_crtc_timing); bool (*enable_crtc)(struct timing_generator *tg); bool (*disable_crtc)(struct timing_generator *tg); bool (*is_counter_moving)(struct timing_generator *tg); -- cgit v1.2.3 From ff582b61466f14d61f3a2a54c3d673d85bcb3c76 Mon Sep 17 00:00:00 2001 From: Anthony Koo Date: Sun, 20 Jan 2019 01:32:55 -0500 Subject: drm/amd/display: add way to determine if link is active [Why] Need to understand whether link is active aside from stream state. This could be used to check what links are enabled by GOP. [How] Store link_active state in link status and initialize it by checking if the DIG is enabled. Keep it updated on every link enable and disable Signed-off-by: Anthony Koo Reviewed-by: Aric Cyr Acked-by: Bhawanpreet Lakha Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc_link.c | 4 ++++ drivers/gpu/drm/amd/display/dc/dc_link.h | 1 + drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c | 5 +++++ 3 files changed, 10 insertions(+) (limited to 'drivers/gpu/drm/amd/display') diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c index 137d3c126632..e2e7bf2ba84b 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -2612,6 +2612,8 @@ void core_link_enable_stream( } } + stream->link->link_status.link_active = true; + core_dc->hwss.enable_audio_stream(pipe_ctx); /* turn off otg test pattern if enable */ @@ -2646,6 +2648,8 @@ void core_link_disable_stream(struct pipe_ctx *pipe_ctx, int option) core_dc->hwss.disable_stream(pipe_ctx, option); disable_link(pipe_ctx->stream->link, pipe_ctx->stream->signal); + + pipe_ctx->stream->link->link_status.link_active = false; } void core_link_set_avmute(struct pipe_ctx *pipe_ctx, bool enable) diff --git a/drivers/gpu/drm/amd/display/dc/dc_link.h b/drivers/gpu/drm/amd/display/dc/dc_link.h index d26bbda61ad2..8fc223defed4 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_link.h +++ b/drivers/gpu/drm/amd/display/dc/dc_link.h @@ -30,6 +30,7 @@ #include "grph_object_defs.h" struct dc_link_status { + bool link_active; struct dpcd_caps *dpcd_caps; }; diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c index 7cead0398c15..7117144d48bd 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c @@ -1027,6 +1027,11 @@ static void dcn10_init_hw(struct dc *dc) dc->hwss.edp_power_control(link, true); link->link_enc->funcs->hw_init(link->link_enc); + + /* Check for enabled DIG to identify enabled display */ + if (link->link_enc->funcs->is_dig_enabled && + link->link_enc->funcs->is_dig_enabled(link->link_enc)) + link->link_status.link_active = true; } } -- cgit v1.2.3 From d2d7885f75b614a982a73383956570d95d79c23e Mon Sep 17 00:00:00 2001 From: Anthony Koo Date: Sun, 20 Jan 2019 01:41:44 -0500 Subject: drm/amd/display: add seamless boot flag to stream [Why] If we determine the stream we are trying to commit matches HW, we want to try to optimize. [How] Try to acquire the HW resources that are already enabled and optimize. Also skip backend reprogramming Signed-off-by: Anthony Koo Reviewed-by: Aric Cyr Acked-by: Bhawanpreet Lakha Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc.c | 3 ++ drivers/gpu/drm/amd/display/dc/core/dc_link.c | 14 +++++- drivers/gpu/drm/amd/display/dc/core/dc_resource.c | 56 +++++++++++++++++++++- drivers/gpu/drm/amd/display/dc/dc_stream.h | 4 +- .../amd/display/dc/dce110/dce110_hw_sequencer.c | 4 +- 5 files changed, 75 insertions(+), 6 deletions(-) (limited to 'drivers/gpu/drm/amd/display') diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index b620520771a7..52f838442e21 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -1096,6 +1096,9 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c const struct dc_link *link = context->streams[i]->link; struct dc_stream_status *status; + if (context->streams[i]->apply_seamless_boot_optimization) + context->streams[i]->apply_seamless_boot_optimization = false; + if (!context->streams[i]->mode_changed) continue; diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c index e2e7bf2ba84b..6d2cef05b4d7 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -2579,13 +2579,23 @@ void core_link_enable_stream( &stream->timing); if (!IS_FPGA_MAXIMUS_DC(core_dc->ctx->dce_environment)) { + bool apply_edp_fast_boot_optimization = + pipe_ctx->stream->apply_edp_fast_boot_optimization; + + pipe_ctx->stream->apply_edp_fast_boot_optimization = false; + resource_build_info_frame(pipe_ctx); core_dc->hwss.update_info_frame(pipe_ctx); + /* Do not touch link on seamless boot optimization. */ + if (pipe_ctx->stream->apply_seamless_boot_optimization) { + pipe_ctx->stream->dpms_off = false; + return; + } + /* eDP lit up by bios already, no need to enable again. */ if (pipe_ctx->stream->signal == SIGNAL_TYPE_EDP && - pipe_ctx->stream->apply_edp_fast_boot_optimization) { - pipe_ctx->stream->apply_edp_fast_boot_optimization = false; + apply_edp_fast_boot_optimization) { pipe_ctx->stream->dpms_off = false; return; } diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c index 9888bc7659f3..349ab8017776 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -1800,6 +1800,51 @@ static void calculate_phy_pix_clks(struct dc_stream_state *stream) stream->phy_pix_clk *= 2; } +static int acquire_resource_from_hw_enabled_state( + struct resource_context *res_ctx, + const struct resource_pool *pool, + struct dc_stream_state *stream) +{ + struct dc_link *link = stream->link; + unsigned int inst; + + /* Check for enabled DIG to identify enabled display */ + if (!link->link_enc->funcs->is_dig_enabled(link->link_enc)) + return -1; + + /* Check for which front end is used by this encoder. + * Note the inst is 1 indexed, where 0 is undefined. + * Note that DIG_FE can source from different OTG but our + * current implementation always map 1-to-1, so this code makes + * the same assumption and doesn't check OTG source. + */ + inst = link->link_enc->funcs->get_dig_frontend(link->link_enc) - 1; + + /* Instance should be within the range of the pool */ + if (inst >= pool->pipe_count) + return -1; + + if (!res_ctx->pipe_ctx[inst].stream) { + struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[inst]; + + pipe_ctx->stream_res.tg = pool->timing_generators[inst]; + pipe_ctx->plane_res.mi = pool->mis[inst]; + pipe_ctx->plane_res.hubp = pool->hubps[inst]; + pipe_ctx->plane_res.ipp = pool->ipps[inst]; + pipe_ctx->plane_res.xfm = pool->transforms[inst]; + pipe_ctx->plane_res.dpp = pool->dpps[inst]; + pipe_ctx->stream_res.opp = pool->opps[inst]; + if (pool->dpps[inst]) + pipe_ctx->plane_res.mpcc_inst = pool->dpps[inst]->inst; + pipe_ctx->pipe_idx = inst; + + pipe_ctx->stream = stream; + return inst; + } + + return -1; +} + enum dc_status resource_map_pool_resources( const struct dc *dc, struct dc_state *context, @@ -1824,8 +1869,15 @@ enum dc_status resource_map_pool_resources( calculate_phy_pix_clks(stream); - /* acquire new resources */ - pipe_idx = acquire_first_free_pipe(&context->res_ctx, pool, stream); + if (stream->apply_seamless_boot_optimization) + pipe_idx = acquire_resource_from_hw_enabled_state( + &context->res_ctx, + pool, + stream); + + if (pipe_idx < 0) + /* acquire new resources */ + pipe_idx = acquire_first_free_pipe(&context->res_ctx, pool, stream); #ifdef CONFIG_DRM_AMD_DC_DCN1_0 if (pipe_idx < 0) diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h b/drivers/gpu/drm/amd/display/dc/dc_stream.h index 90f019eb54b3..a798694992b9 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_stream.h +++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h @@ -119,7 +119,6 @@ struct dc_stream_state { int phy_pix_clk; enum signal_type signal; bool dpms_off; - bool apply_edp_fast_boot_optimization; void *dm_stream_context; @@ -146,6 +145,9 @@ struct dc_stream_state { uint8_t otg_offset; } out; + bool apply_edp_fast_boot_optimization; + bool apply_seamless_boot_optimization; + uint32_t stream_id; }; diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c index e2d8362dd5b1..21ceda410244 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c @@ -1339,7 +1339,9 @@ static enum dc_status apply_single_controller_ctx_to_hw( } /* */ - dc->hwss.enable_stream_timing(pipe_ctx, context, dc); + /* Do not touch stream timing on seamless boot optimization. */ + if (!pipe_ctx->stream->apply_seamless_boot_optimization) + dc->hwss.enable_stream_timing(pipe_ctx, context, dc); if (pipe_ctx->stream_res.tg->funcs->program_vupdate_interrupt) pipe_ctx->stream_res.tg->funcs->program_vupdate_interrupt( -- cgit v1.2.3 From 9c0fb8d45bfcf2e8f080489913db443c1fd241ed Mon Sep 17 00:00:00 2001 From: Anthony Koo Date: Sun, 20 Jan 2019 01:45:36 -0500 Subject: drm/amd/display: refactor programming of DRR [Why] Keep enable_stream_timing programming only timing related stuff. [How] Move DRR and static screen mask programming from enable_stream_timing to outside in apply_single_controller_ctx_to_hw Signed-off-by: Anthony Koo Reviewed-by: Aric Cyr Acked-by: Bhawanpreet Lakha Signed-off-by: Alex Deucher --- .../amd/display/dc/dce110/dce110_hw_sequencer.c | 31 +++++++++++----------- .../drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c | 15 ----------- 2 files changed, 15 insertions(+), 31 deletions(-) (limited to 'drivers/gpu/drm/amd/display') diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c index 21ceda410244..a4386348a981 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c @@ -1250,8 +1250,6 @@ static enum dc_status dce110_enable_stream_timing( struct pipe_ctx *pipe_ctx_old = &dc->current_state->res_ctx. pipe_ctx[pipe_ctx->pipe_idx]; struct tg_color black_color = {0}; - struct drr_params params = {0}; - unsigned int event_triggers = 0; if (!pipe_ctx_old->stream) { @@ -1280,20 +1278,6 @@ static enum dc_status dce110_enable_stream_timing( pipe_ctx->stream_res.tg, &stream->timing, true); - - params.vertical_total_min = stream->adjust.v_total_min; - params.vertical_total_max = stream->adjust.v_total_max; - if (pipe_ctx->stream_res.tg->funcs->set_drr) - pipe_ctx->stream_res.tg->funcs->set_drr( - pipe_ctx->stream_res.tg, ¶ms); - - // DRR should set trigger event to monitor surface update event - if (stream->adjust.v_total_min != 0 && - stream->adjust.v_total_max != 0) - event_triggers = 0x80; - if (pipe_ctx->stream_res.tg->funcs->set_static_screen_control) - pipe_ctx->stream_res.tg->funcs->set_static_screen_control( - pipe_ctx->stream_res.tg, event_triggers); } if (!pipe_ctx_old->stream) { @@ -1313,6 +1297,8 @@ static enum dc_status apply_single_controller_ctx_to_hw( struct dc *dc) { struct dc_stream_state *stream = pipe_ctx->stream; + struct drr_params params = {0}; + unsigned int event_triggers = 0; if (pipe_ctx->stream_res.audio != NULL) { struct audio_output audio_output; @@ -1348,6 +1334,19 @@ static enum dc_status apply_single_controller_ctx_to_hw( pipe_ctx->stream_res.tg, &stream->timing); + params.vertical_total_min = stream->adjust.v_total_min; + params.vertical_total_max = stream->adjust.v_total_max; + if (pipe_ctx->stream_res.tg->funcs->set_drr) + pipe_ctx->stream_res.tg->funcs->set_drr( + pipe_ctx->stream_res.tg, ¶ms); + + // DRR should set trigger event to monitor surface update event + if (stream->adjust.v_total_min != 0 && stream->adjust.v_total_max != 0) + event_triggers = 0x80; + if (pipe_ctx->stream_res.tg->funcs->set_static_screen_control) + pipe_ctx->stream_res.tg->funcs->set_static_screen_control( + pipe_ctx->stream_res.tg, event_triggers); + if (pipe_ctx->stream->signal != SIGNAL_TYPE_VIRTUAL) pipe_ctx->stream_res.stream_enc->funcs->dig_connect_to_otg( pipe_ctx->stream_res.stream_enc, diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c index 7117144d48bd..a03bbbf94d5d 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c @@ -636,8 +636,6 @@ static enum dc_status dcn10_enable_stream_timing( struct dc_stream_state *stream = pipe_ctx->stream; enum dc_color_space color_space; struct tg_color black_color = {0}; - struct drr_params params = {0}; - unsigned int event_triggers = 0; /* by upper caller loop, pipe0 is parent pipe and be called first. * back end is set up by for pipe0. Other children pipe share back end @@ -705,19 +703,6 @@ static enum dc_status dcn10_enable_stream_timing( return DC_ERROR_UNEXPECTED; } - params.vertical_total_min = stream->adjust.v_total_min; - params.vertical_total_max = stream->adjust.v_total_max; - if (pipe_ctx->stream_res.tg->funcs->set_drr) - pipe_ctx->stream_res.tg->funcs->set_drr( - pipe_ctx->stream_res.tg, ¶ms); - - // DRR should set trigger event to monitor surface update event - if (stream->adjust.v_total_min != 0 && stream->adjust.v_total_max != 0) - event_triggers = 0x80; - if (pipe_ctx->stream_res.tg->funcs->set_static_screen_control) - pipe_ctx->stream_res.tg->funcs->set_static_screen_control( - pipe_ctx->stream_res.tg, event_triggers); - /* TODO program crtc source select for non-virtual signal*/ /* TODO program FMT */ /* TODO setup link_enc */ -- cgit v1.2.3 From fb55546ea4b50f04ef41c196b8ac1824e26bc48c Mon Sep 17 00:00:00 2001 From: Anthony Koo Date: Sun, 20 Jan 2019 01:23:07 -0500 Subject: drm/amd/display: refactor init_hw to isolate pipe related init [Why] Pipe related init is possible to optimized if we know what we intend to program, and if we can determine it matches what is already programmed for the pipe. [How] First step is to isolate the pipe related init code Signed-off-by: Anthony Koo Reviewed-by: Aric Cyr Acked-by: Bhawanpreet Lakha Signed-off-by: Alex Deucher --- .../amd/display/dc/dce110/dce110_hw_sequencer.c | 6 + .../drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c | 159 ++++++++++----------- drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h | 2 + 3 files changed, 85 insertions(+), 82 deletions(-) (limited to 'drivers/gpu/drm/amd/display') diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c index a4386348a981..4df8a43b5018 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c @@ -2275,6 +2275,11 @@ static void dce110_enable_per_frame_crtc_position_reset( } +static void init_pipes(struct dc *dc, struct dc_state *context) +{ + // Do nothing +} + static void init_hw(struct dc *dc) { int i; @@ -2642,6 +2647,7 @@ static const struct hw_sequencer_funcs dce110_funcs = { .program_gamut_remap = program_gamut_remap, .program_output_csc = program_output_csc, .init_hw = init_hw, + .init_pipes = init_pipes, .apply_ctx_to_hw = dce110_apply_ctx_to_hw, .apply_ctx_for_surface = dce110_apply_ctx_for_surface, .update_plane_addr = update_plane_addr, diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c index a03bbbf94d5d..117d9d8227f7 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c @@ -956,97 +956,34 @@ static void dcn10_disable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx) pipe_ctx->pipe_idx); } -static void dcn10_init_hw(struct dc *dc) +static void dcn10_init_pipes(struct dc *dc, struct dc_state *context) { int i; - struct abm *abm = dc->res_pool->abm; - struct dmcu *dmcu = dc->res_pool->dmcu; - struct dce_hwseq *hws = dc->hwseq; - struct dc_bios *dcb = dc->ctx->dc_bios; - struct dc_state *context = dc->current_state; - - if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) { - REG_WRITE(REFCLK_CNTL, 0); - REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_ENABLE, 1); - REG_WRITE(DIO_MEM_PWR_CTRL, 0); - - if (!dc->debug.disable_clock_gate) { - /* enable all DCN clock gating */ - REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0); - - REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0); - - REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0); - } - - enable_power_gating_plane(dc->hwseq, true); - } else { - - if (!dcb->funcs->is_accelerated_mode(dcb)) { - bool allow_self_fresh_force_enable = - hububu1_is_allow_self_refresh_enabled(dc->res_pool->hubbub); - - bios_golden_init(dc); - - /* WA for making DF sleep when idle after resume from S0i3. - * DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE is set to 1 by - * command table, if DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE = 0 - * before calling command table and it changed to 1 after, - * it should be set back to 0. - */ - if (allow_self_fresh_force_enable == false && - hububu1_is_allow_self_refresh_enabled(dc->res_pool->hubbub)) - hubbub1_allow_self_refresh_control(dc->res_pool->hubbub, true); - - disable_vga(dc->hwseq); - } - - for (i = 0; i < dc->link_count; i++) { - /* Power up AND update implementation according to the - * required signal (which may be different from the - * default signal on connector). - */ - struct dc_link *link = dc->links[i]; - - if (link->link_enc->connector.id == CONNECTOR_ID_EDP) - dc->hwss.edp_power_control(link, true); - - link->link_enc->funcs->hw_init(link->link_enc); - - /* Check for enabled DIG to identify enabled display */ - if (link->link_enc->funcs->is_dig_enabled && - link->link_enc->funcs->is_dig_enabled(link->link_enc)) - link->link_status.link_active = true; - } - } for (i = 0; i < dc->res_pool->pipe_count; i++) { struct timing_generator *tg = dc->res_pool->timing_generators[i]; if (tg->funcs->is_tg_enabled(tg)) tg->funcs->lock(tg); - } - - /* Blank controller using driver code instead of - * command table. - */ - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct timing_generator *tg = dc->res_pool->timing_generators[i]; + /* Blank controller using driver code instead of + * command table. + */ if (tg->funcs->is_tg_enabled(tg)) { tg->funcs->set_blank(tg, true); hwss_wait_for_blank_complete(tg); } } - /* Reset all MPCC muxes */ dc->res_pool->mpc->funcs->mpc_init(dc->res_pool->mpc); - for (i = 0; i < dc->res_pool->timing_generator_count; i++) { + for (i = 0; i < dc->res_pool->pipe_count; i++) { struct timing_generator *tg = dc->res_pool->timing_generators[i]; - struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; struct hubp *hubp = dc->res_pool->hubps[i]; struct dpp *dpp = dc->res_pool->dpps[i]; + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + + dpp->funcs->dpp_reset(dpp); pipe_ctx->stream_res.tg = tg; pipe_ctx->pipe_idx = i; @@ -1064,18 +1001,9 @@ static void dcn10_init_hw(struct dc *dc) pipe_ctx->stream_res.opp = dc->res_pool->opps[i]; hwss1_plane_atomic_disconnect(dc, pipe_ctx); - } - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct timing_generator *tg = dc->res_pool->timing_generators[i]; if (tg->funcs->is_tg_enabled(tg)) tg->funcs->unlock(tg); - } - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct timing_generator *tg = dc->res_pool->timing_generators[i]; - struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; dcn10_disable_plane(dc, pipe_ctx); @@ -1084,10 +1012,73 @@ static void dcn10_init_hw(struct dc *dc) tg->funcs->tg_init(tg); } +} + +static void dcn10_init_hw(struct dc *dc) +{ + int i; + struct abm *abm = dc->res_pool->abm; + struct dmcu *dmcu = dc->res_pool->dmcu; + struct dce_hwseq *hws = dc->hwseq; + struct dc_bios *dcb = dc->ctx->dc_bios; + + if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) { + REG_WRITE(REFCLK_CNTL, 0); + REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_ENABLE, 1); + REG_WRITE(DIO_MEM_PWR_CTRL, 0); - /* end of FPGA. Below if real ASIC */ - if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) + if (!dc->debug.disable_clock_gate) { + /* enable all DCN clock gating */ + REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0); + + REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0); + + REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0); + } + + enable_power_gating_plane(dc->hwseq, true); + + /* end of FPGA. Below if real ASIC */ return; + } + + if (!dcb->funcs->is_accelerated_mode(dcb)) { + bool allow_self_fresh_force_enable = + hububu1_is_allow_self_refresh_enabled( + dc->res_pool->hubbub); + + bios_golden_init(dc); + + /* WA for making DF sleep when idle after resume from S0i3. + * DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE is set to 1 by + * command table, if DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE = 0 + * before calling command table and it changed to 1 after, + * it should be set back to 0. + */ + if (allow_self_fresh_force_enable == false && + hububu1_is_allow_self_refresh_enabled(dc->res_pool->hubbub)) + hubbub1_allow_self_refresh_control(dc->res_pool->hubbub, true); + + disable_vga(dc->hwseq); + } + + for (i = 0; i < dc->link_count; i++) { + /* Power up AND update implementation according to the + * required signal (which may be different from the + * default signal on connector). + */ + struct dc_link *link = dc->links[i]; + + if (link->link_enc->connector.id == CONNECTOR_ID_EDP) + dc->hwss.edp_power_control(link, true); + + link->link_enc->funcs->hw_init(link->link_enc); + + /* Check for enabled DIG to identify enabled display */ + if (link->link_enc->funcs->is_dig_enabled && + link->link_enc->funcs->is_dig_enabled(link->link_enc)) + link->link_status.link_active = true; + } for (i = 0; i < dc->res_pool->audio_count; i++) { struct audio *audio = dc->res_pool->audios[i]; @@ -1118,6 +1109,9 @@ static void dcn10_init_hw(struct dc *dc) enable_power_gating_plane(dc->hwseq, true); memset(&dc->res_pool->clk_mgr->clks, 0, sizeof(dc->res_pool->clk_mgr->clks)); + + if (dc->hwss.init_pipes) + dc->hwss.init_pipes(dc, dc->current_state); } static void reset_hw_ctx_wrap( @@ -2718,6 +2712,7 @@ static void dcn10_set_cursor_sdr_white_level(struct pipe_ctx *pipe_ctx) static const struct hw_sequencer_funcs dcn10_funcs = { .program_gamut_remap = program_gamut_remap, .init_hw = dcn10_init_hw, + .init_pipes = dcn10_init_pipes, .apply_ctx_to_hw = dce110_apply_ctx_to_hw, .apply_ctx_for_surface = dcn10_apply_ctx_for_surface, .update_plane_addr = dcn10_update_plane_addr, diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h index d6a85f48b6d1..341b4810288c 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h @@ -70,6 +70,8 @@ struct hw_sequencer_funcs { void (*init_hw)(struct dc *dc); + void (*init_pipes)(struct dc *dc, struct dc_state *context); + enum dc_status (*apply_ctx_to_hw)( struct dc *dc, struct dc_state *context); -- cgit v1.2.3 From 2c850b7b9e7d0fb36e0bd1ad1238ff55e5c4dcdc Mon Sep 17 00:00:00 2001 From: Dmytro Laktyushkin Date: Mon, 14 Jan 2019 15:19:44 -0500 Subject: drm/amd/display: add n_vid_mul and half pix_rate for odm Dp needs half container rate to properly support odm Signed-off-by: Dmytro Laktyushkin Reviewed-by: Nikola Cornij Acked-by: Bhawanpreet Lakha Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c | 4 ++-- drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c | 7 +++++-- drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) (limited to 'drivers/gpu/drm/amd/display') diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c index 4df8a43b5018..e1b285ea01ac 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c @@ -1032,8 +1032,7 @@ void dce110_unblank_stream(struct pipe_ctx *pipe_ctx, struct dc_link *link = stream->link; /* only 3 items below are used by unblank */ - params.pixel_clk_khz = - pipe_ctx->stream->timing.pix_clk_100hz / 10; + params.pixel_clk_khz = pipe_ctx->stream->timing.pix_clk_100hz / 10; params.link_settings.link_rate = link_settings->link_rate; if (dc_is_dp_signal(pipe_ctx->stream->signal)) @@ -1043,6 +1042,7 @@ void dce110_unblank_stream(struct pipe_ctx *pipe_ctx, link->dc->hwss.edp_backlight_control(link, true); } } + void dce110_blank_stream(struct pipe_ctx *pipe_ctx) { struct dc_stream_state *stream = pipe_ctx->stream; diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c index 1dbd1d3999e6..2f78a84f0dcb 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c @@ -390,7 +390,7 @@ void optc1_program_timing( h_div_2 = optc1_is_two_pixels_per_containter(&patched_crtc_timing); REG_UPDATE(OTG_H_TIMING_CNTL, - OTG_H_TIMING_DIV_BY2, h_div_2); + OTG_H_TIMING_DIV_BY2, h_div_2 || optc1->comb_opp_id != 0xf); } @@ -1531,10 +1531,13 @@ void dcn10_timing_generator_init(struct optc *optc1) optc1->min_v_blank_interlace = 5; optc1->min_h_sync_width = 8; optc1->min_v_sync_width = 1; + optc1->comb_opp_id = 0xf; } bool optc1_is_two_pixels_per_containter(const struct dc_crtc_timing *timing) { - return timing->pixel_encoding == PIXEL_ENCODING_YCBCR420; + bool two_pix = timing->pixel_encoding == PIXEL_ENCODING_YCBCR420; + + return two_pix; } diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h index 8a4e3e37e894..24452f11c598 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h @@ -435,7 +435,7 @@ struct optc { const struct dcn_optc_shift *tg_shift; const struct dcn_optc_mask *tg_mask; - enum controller_id controller_id; + int comb_opp_id; uint32_t max_h_total; uint32_t max_v_total; -- cgit v1.2.3 From 0461221316ec21e0a535a35fba3feb6ba75706e6 Mon Sep 17 00:00:00 2001 From: Harry Wentland Date: Thu, 7 Feb 2019 15:12:35 -0500 Subject: drm/amd/display: Check hpd_gpio for NULL before accessing it dal_gpio_open and dal_gpio_unlock_pin dereference hpd_gpio. Check for NULL before calling those functions. Fixes: ac627caf6b9275a ("drm/amd/display: add gpio lock/unlock") Reported-by: Przemek Socha CC: Chiawen Huang CC: Tony Cheng Acked-by: Alex Deucher Tested-by: Alex Deucher Signed-off-by: Harry Wentland Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc_link.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/gpu/drm/amd/display') diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c index 6d2cef05b4d7..7f5a947ad31d 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -1127,10 +1127,11 @@ static bool construct( link->dc->res_pool->funcs->link_init(link); link->hpd_gpio = get_hpd_gpio(link->ctx->dc_bios, link->link_id, link->ctx->gpio_service); - dal_gpio_open(link->hpd_gpio, GPIO_MODE_INTERRUPT); - dal_gpio_unlock_pin(link->hpd_gpio); - if (link->hpd_gpio != NULL) + if (link->hpd_gpio != NULL) { + dal_gpio_open(link->hpd_gpio, GPIO_MODE_INTERRUPT); + dal_gpio_unlock_pin(link->hpd_gpio); link->irq_source_hpd = dal_irq_get_source(link->hpd_gpio); + } switch (link->link_id.id) { case CONNECTOR_ID_HDMI_TYPE_A: -- cgit v1.2.3