diff options
author | Sean Paul <seanpaul@chromium.org> | 2018-03-21 09:40:55 -0400 |
---|---|---|
committer | Sean Paul <seanpaul@chromium.org> | 2018-03-21 09:40:55 -0400 |
commit | 1c7095d2836baafd84e596dd34ba1a1293a4faa9 (patch) | |
tree | 498f529809b9c0a3c75c8b8bb1098ed4f71233db /drivers/gpu/drm/amd/display/dc/core | |
parent | 2793c1d77aa8876e5674e901d051c79570e99db2 (diff) | |
parent | 78230c46ec0a91dd4256c9e54934b3c7095a7ee3 (diff) |
Merge airlied/drm-next into drm-misc-nextdrm-misc-next-2018-03-21
Refresh -misc-next
Signed-off-by: Sean Paul <seanpaul@chromium.org>
Diffstat (limited to 'drivers/gpu/drm/amd/display/dc/core')
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/core/dc.c | 247 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/core/dc_debug.c | 35 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/core/dc_link.c | 159 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c | 7 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c | 179 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c | 26 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/core/dc_resource.c | 33 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/core/dc_stream.c | 81 |
8 files changed, 509 insertions, 258 deletions
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 35e84ed031de..63a3d468939a 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -29,6 +29,7 @@ #include "core_status.h" #include "core_types.h" #include "hw_sequencer.h" +#include "dce/dce_hwseq.h" #include "resource.h" @@ -38,8 +39,10 @@ #include "bios_parser_interface.h" #include "include/irq_service_interface.h" #include "transform.h" +#include "dmcu.h" #include "dpp.h" #include "timing_generator.h" +#include "abm.h" #include "virtual/virtual_link_encoder.h" #include "link_hwss.h" @@ -49,6 +52,8 @@ #include "dm_helpers.h" #include "mem_input.h" #include "hubp.h" +#define DC_LOGGER \ + dc->ctx->logger /******************************************************************************* @@ -214,6 +219,130 @@ bool dc_stream_get_crtc_position(struct dc *dc, return ret; } +/** + * dc_stream_configure_crc: Configure CRC capture for the given stream. + * @dc: DC Object + * @stream: The stream to configure CRC on. + * @enable: Enable CRC if true, disable otherwise. + * @continuous: Capture CRC on every frame if true. Otherwise, only capture + * once. + * + * By default, only CRC0 is configured, and the entire frame is used to + * calculate the crc. + */ +bool dc_stream_configure_crc(struct dc *dc, struct dc_stream_state *stream, + bool enable, bool continuous) +{ + int i; + struct pipe_ctx *pipe; + struct crc_params param; + struct timing_generator *tg; + + for (i = 0; i < MAX_PIPES; i++) { + pipe = &dc->current_state->res_ctx.pipe_ctx[i]; + if (pipe->stream == stream) + break; + } + /* Stream not found */ + if (i == MAX_PIPES) + return false; + + /* Always capture the full frame */ + param.windowa_x_start = 0; + param.windowa_y_start = 0; + param.windowa_x_end = pipe->stream->timing.h_addressable; + param.windowa_y_end = pipe->stream->timing.v_addressable; + param.windowb_x_start = 0; + param.windowb_y_start = 0; + param.windowb_x_end = pipe->stream->timing.h_addressable; + param.windowb_y_end = pipe->stream->timing.v_addressable; + + /* Default to the union of both windows */ + param.selection = UNION_WINDOW_A_B; + param.continuous_mode = continuous; + param.enable = enable; + + tg = pipe->stream_res.tg; + + /* Only call if supported */ + if (tg->funcs->configure_crc) + return tg->funcs->configure_crc(tg, ¶m); + DC_LOG_WARNING("CRC capture not supported."); + return false; +} + +/** + * dc_stream_get_crc: Get CRC values for the given stream. + * @dc: DC object + * @stream: The DC stream state of the stream to get CRCs from. + * @r_cr, g_y, b_cb: CRC values for the three channels are stored here. + * + * dc_stream_configure_crc needs to be called beforehand to enable CRCs. + * Return false if stream is not found, or if CRCs are not enabled. + */ +bool dc_stream_get_crc(struct dc *dc, struct dc_stream_state *stream, + uint32_t *r_cr, uint32_t *g_y, uint32_t *b_cb) +{ + int i; + struct pipe_ctx *pipe; + struct timing_generator *tg; + + for (i = 0; i < MAX_PIPES; i++) { + pipe = &dc->current_state->res_ctx.pipe_ctx[i]; + if (pipe->stream == stream) + break; + } + /* Stream not found */ + if (i == MAX_PIPES) + return false; + + tg = pipe->stream_res.tg; + + if (tg->funcs->get_crc) + return tg->funcs->get_crc(tg, r_cr, g_y, b_cb); + DC_LOG_WARNING("CRC capture not supported."); + return false; +} + +void dc_stream_set_dither_option(struct dc_stream_state *stream, + enum dc_dither_option option) +{ + struct bit_depth_reduction_params params; + struct dc_link *link = stream->status.link; + struct pipe_ctx *pipes = NULL; + int i; + + for (i = 0; i < MAX_PIPES; i++) { + if (link->dc->current_state->res_ctx.pipe_ctx[i].stream == + stream) { + pipes = &link->dc->current_state->res_ctx.pipe_ctx[i]; + break; + } + } + + if (!pipes) + return; + if (option > DITHER_OPTION_MAX) + return; + + stream->dither_option = option; + + memset(¶ms, 0, sizeof(params)); + resource_build_bit_depth_reduction_params(stream, ¶ms); + stream->bit_depth_params = params; + + if (pipes->plane_res.xfm && + pipes->plane_res.xfm->funcs->transform_set_pixel_storage_depth) { + pipes->plane_res.xfm->funcs->transform_set_pixel_storage_depth( + pipes->plane_res.xfm, + pipes->plane_res.scl_data.lb_params.depth, + &stream->bit_depth_params); + } + + pipes->stream_res.opp->funcs-> + opp_program_bit_depth_reduction(pipes->stream_res.opp, ¶ms); +} + void dc_stream_set_static_screen_events(struct dc *dc, struct dc_stream_state **streams, int num_streams, @@ -359,9 +488,6 @@ static bool construct(struct dc *dc, dc_version = resource_parse_asic_id(init_params->asic_id); dc_ctx->dce_version = dc_version; -#if defined(CONFIG_DRM_AMD_DC_FBC) - dc->ctx->fbc_gpu_addr = init_params->fbc_gpu_addr; -#endif /* Resource should construct all asic specific resources. * This should be the only place where we need to parse the asic id */ @@ -487,10 +613,15 @@ struct dc *dc_create(const struct dc_init_data *init_params) dc->caps.max_audios = dc->res_pool->audio_count; dc->caps.linear_pitch_alignment = 64; + /* Populate versioning information */ + dc->versions.dc_ver = DC_VER; + + if (dc->res_pool->dmcu != NULL) + dc->versions.dmcu_version = dc->res_pool->dmcu->dmcu_version; + dc->config = init_params->flags; - dm_logger_write(dc->ctx->logger, LOG_DC, - "Display Core initialized\n"); + DC_LOG_DC("Display Core initialized\n"); /* TODO: missing feature to be enabled */ @@ -524,11 +655,13 @@ static void enable_timing_multisync( if (!ctx->res_ctx.pipe_ctx[i].stream || !ctx->res_ctx.pipe_ctx[i].stream->triggered_crtc_reset.enabled) continue; + if (ctx->res_ctx.pipe_ctx[i].stream == ctx->res_ctx.pipe_ctx[i].stream->triggered_crtc_reset.event_source) + continue; multisync_pipes[multisync_count] = &ctx->res_ctx.pipe_ctx[i]; multisync_count++; } - if (multisync_count > 1) { + if (multisync_count > 0) { dc->hwss.enable_per_frame_crtc_position_reset( dc, multisync_count, multisync_pipes); } @@ -650,7 +783,6 @@ bool dc_enable_stereo( return ret; } - /* * Applies given context to HW and copy it into current context. * It's up to the user to release the src context afterwards. @@ -669,7 +801,9 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c dc_streams[i] = context->streams[i]; if (!dcb->funcs->is_accelerated_mode(dcb)) - dc->hwss.enable_accelerated_mode(dc); + dc->hwss.enable_accelerated_mode(dc, context); + + dc->hwss.set_bandwidth(dc, context, false); /* re-program planes for existing stream, in case we need to * free up plane resource for later use @@ -739,6 +873,9 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c dc_enable_stereo(dc, context, dc_streams, context->stream_count); + /* pplib is notified if disp_num changed */ + dc->hwss.set_bandwidth(dc, context, true); + dc_release_state(dc->current_state); dc->current_state = context; @@ -758,7 +895,7 @@ bool dc_commit_state(struct dc *dc, struct dc_state *context) if (false == context_changed(dc, context)) return DC_OK; - dm_logger_write(dc->ctx->logger, LOG_DC, "%s: %d streams\n", + DC_LOG_DC("%s: %d streams\n", __func__, context->stream_count); for (i = 0; i < context->stream_count; i++) { @@ -979,6 +1116,9 @@ static enum surface_update_type get_plane_info_update_type(const struct dc_surfa if (u->plane_info->rotation != u->surface->rotation) update_flags->bits.rotation_change = 1; + if (u->plane_info->format != u->surface->format) + update_flags->bits.pixel_format_change = 1; + if (u->plane_info->stereo_format != u->surface->stereo_format) update_flags->bits.stereo_format_change = 1; @@ -997,6 +1137,9 @@ static enum surface_update_type get_plane_info_update_type(const struct dc_surfa */ update_flags->bits.bpp_change = 1; + if (u->gamma && dce_use_lut(u->plane_info->format)) + update_flags->bits.gamma_change = 1; + if (memcmp(&u->plane_info->tiling_info, &u->surface->tiling_info, sizeof(union dc_tiling_info)) != 0) { update_flags->bits.swizzle_change = 1; @@ -1012,8 +1155,11 @@ static enum surface_update_type get_plane_info_update_type(const struct dc_surfa if (update_flags->bits.rotation_change || update_flags->bits.stereo_format_change + || update_flags->bits.pixel_format_change + || update_flags->bits.gamma_change || update_flags->bits.bpp_change - || update_flags->bits.bandwidth_change) + || update_flags->bits.bandwidth_change + || update_flags->bits.output_tf_change) return UPDATE_TYPE_FULL; return UPDATE_TYPE_MED; @@ -1092,12 +1238,12 @@ static enum surface_update_type det_surface_update(const struct dc *dc, elevate_update_type(&overall_type, type); if (u->in_transfer_func) - update_flags->bits.in_transfer_func = 1; + update_flags->bits.in_transfer_func_change = 1; if (u->input_csc_color_matrix) update_flags->bits.input_csc_change = 1; - if (update_flags->bits.in_transfer_func + if (update_flags->bits.in_transfer_func_change || update_flags->bits.input_csc_change) { type = UPDATE_TYPE_MED; elevate_update_type(&overall_type, type); @@ -1183,6 +1329,7 @@ static void commit_planes_for_stream(struct dc *dc, struct dc_state *context) { int i, j; + struct pipe_ctx *top_pipe_to_program = NULL; if (update_type == UPDATE_TYPE_FULL) { dc->hwss.set_bandwidth(dc, context, false); @@ -1202,39 +1349,64 @@ static void commit_planes_for_stream(struct dc *dc, for (j = 0; j < dc->res_pool->pipe_count; j++) { struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j]; - if (update_type == UPDATE_TYPE_FAST || !pipe_ctx->plane_state) - continue; - if (!pipe_ctx->top_pipe && - pipe_ctx->stream && - pipe_ctx->stream == stream) { - struct dc_stream_status *stream_status = + pipe_ctx->stream && + pipe_ctx->stream == stream) { + struct dc_stream_status *stream_status = NULL; + + top_pipe_to_program = pipe_ctx; + + if (update_type == UPDATE_TYPE_FAST || !pipe_ctx->plane_state) + continue; + + stream_status = stream_get_status(context, pipe_ctx->stream); dc->hwss.apply_ctx_for_surface( dc, pipe_ctx->stream, stream_status->plane_count, context); + + if (stream_update && stream_update->abm_level && pipe_ctx->stream_res.abm) { + if (pipe_ctx->stream_res.tg->funcs->is_blanked) { + // if otg funcs defined check if blanked before programming + if (!pipe_ctx->stream_res.tg->funcs->is_blanked(pipe_ctx->stream_res.tg)) + pipe_ctx->stream_res.abm->funcs->set_abm_level( + pipe_ctx->stream_res.abm, stream->abm_level); + } else + pipe_ctx->stream_res.abm->funcs->set_abm_level( + pipe_ctx->stream_res.abm, stream->abm_level); + } } } if (update_type == UPDATE_TYPE_FULL) context_timing_trace(dc, &context->res_ctx); - /* Perform requested Updates */ - for (i = 0; i < surface_count; i++) { - struct dc_plane_state *plane_state = srf_updates[i].surface; + /* Lock the top pipe while updating plane addrs, since freesync requires + * plane addr update event triggers to be synchronized. + * top_pipe_to_program is expected to never be NULL + */ + if (update_type == UPDATE_TYPE_FAST) { + dc->hwss.pipe_control_lock(dc, top_pipe_to_program, true); - for (j = 0; j < dc->res_pool->pipe_count; j++) { - struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j]; + /* Perform requested Updates */ + for (i = 0; i < surface_count; i++) { + struct dc_plane_state *plane_state = srf_updates[i].surface; - if (pipe_ctx->stream != stream) - continue; + for (j = 0; j < dc->res_pool->pipe_count; j++) { + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j]; - if (pipe_ctx->plane_state != plane_state) - continue; + if (pipe_ctx->stream != stream) + continue; + + if (pipe_ctx->plane_state != plane_state) + continue; - if (update_type == UPDATE_TYPE_FAST && srf_updates[i].flip_addr) + if (srf_updates[i].flip_addr) dc->hwss.update_plane_addr(dc, pipe_ctx); + } } + + dc->hwss.pipe_control_lock(dc, top_pipe_to_program, false); } if (stream && stream_update && update_type > UPDATE_TYPE_FAST) @@ -1358,13 +1530,13 @@ enum dc_irq_source dc_interrupt_to_irq_source( return dal_irq_service_to_irq_source(dc->res_pool->irqs, src_id, ext_id); } -void dc_interrupt_set(struct dc *dc, enum dc_irq_source src, bool enable) +bool dc_interrupt_set(struct dc *dc, enum dc_irq_source src, bool enable) { if (dc == NULL) - return; + return false; - dal_irq_service_set(dc->res_pool->irqs, src, enable); + return dal_irq_service_set(dc->res_pool->irqs, src, enable); } void dc_interrupt_ack(struct dc *dc, enum dc_irq_source src) @@ -1487,12 +1659,17 @@ struct dc_sink *dc_link_add_remote_sink( &dc_sink->dc_edid, &dc_sink->edid_caps); - if (edid_status != EDID_OK) - goto fail; + /* + * Treat device as no EDID device if EDID + * parsing fails + */ + if (edid_status != EDID_OK) { + dc_sink->dc_edid.length = 0; + dm_error("Bad EDID, status%d!\n", edid_status); + } return dc_sink; -fail: - dc_link_remove_remote_sink(link, dc_sink); + fail_add_sink: dc_sink_release(dc_sink); return NULL; diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_debug.c b/drivers/gpu/drm/amd/display/dc/core/dc_debug.c index 1babac07bcc9..5a552cb3f8a7 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_debug.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_debug.c @@ -36,26 +36,22 @@ #include "hw_sequencer.h" #include "resource.h" +#define DC_LOGGER \ + logger #define SURFACE_TRACE(...) do {\ if (dc->debug.surface_trace) \ - dm_logger_write(logger, \ - LOG_IF_TRACE, \ - ##__VA_ARGS__); \ + DC_LOG_IF_TRACE(__VA_ARGS__); \ } while (0) #define TIMING_TRACE(...) do {\ if (dc->debug.timing_trace) \ - dm_logger_write(logger, \ - LOG_SYNC, \ - ##__VA_ARGS__); \ + DC_LOG_SYNC(__VA_ARGS__); \ } while (0) #define CLOCK_TRACE(...) do {\ if (dc->debug.clock_trace) \ - dm_logger_write(logger, \ - LOG_BANDWIDTH_CALCS, \ - ##__VA_ARGS__); \ + DC_LOG_BANDWIDTH_CALCS(__VA_ARGS__); \ } while (0) void pre_surface_trace( @@ -361,25 +357,20 @@ void context_clock_trace( struct dc *core_dc = dc; struct dal_logger *logger = core_dc->ctx->logger; - CLOCK_TRACE("Current: dispclk_khz:%d dppclk_div:%d dcfclk_khz:%d\n" - "dcfclk_deep_sleep_khz:%d fclk_khz:%d\n" - "dram_ccm_us:%d min_active_dram_ccm_us:%d\n", + CLOCK_TRACE("Current: dispclk_khz:%d max_dppclk_khz:%d dcfclk_khz:%d\n" + "dcfclk_deep_sleep_khz:%d fclk_khz:%d socclk_khz:%d\n", context->bw.dcn.calc_clk.dispclk_khz, - context->bw.dcn.calc_clk.dppclk_div, + context->bw.dcn.calc_clk.dppclk_khz, context->bw.dcn.calc_clk.dcfclk_khz, context->bw.dcn.calc_clk.dcfclk_deep_sleep_khz, context->bw.dcn.calc_clk.fclk_khz, - context->bw.dcn.calc_clk.dram_ccm_us, - context->bw.dcn.calc_clk.min_active_dram_ccm_us); - CLOCK_TRACE("Calculated: dispclk_khz:%d dppclk_div:%d dcfclk_khz:%d\n" - "dcfclk_deep_sleep_khz:%d fclk_khz:%d\n" - "dram_ccm_us:%d min_active_dram_ccm_us:%d\n", + context->bw.dcn.calc_clk.socclk_khz); + CLOCK_TRACE("Calculated: dispclk_khz:%d max_dppclk_khz:%d dcfclk_khz:%d\n" + "dcfclk_deep_sleep_khz:%d fclk_khz:%d socclk_khz:%d\n", context->bw.dcn.calc_clk.dispclk_khz, - context->bw.dcn.calc_clk.dppclk_div, + context->bw.dcn.calc_clk.dppclk_khz, context->bw.dcn.calc_clk.dcfclk_khz, context->bw.dcn.calc_clk.dcfclk_deep_sleep_khz, - context->bw.dcn.calc_clk.fclk_khz, - context->bw.dcn.calc_clk.dram_ccm_us, - context->bw.dcn.calc_clk.min_active_dram_ccm_us); + context->bw.dcn.calc_clk.fclk_khz); #endif } 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 a37428271573..eeb04471b2f5 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -45,9 +45,11 @@ #include "dce/dce_11_0_d.h" #include "dce/dce_11_0_enum.h" #include "dce/dce_11_0_sh_mask.h" +#define DC_LOGGER \ + dc_ctx->logger #define LINK_INFO(...) \ - dm_logger_write(dc_ctx->logger, LOG_HW_HOTPLUG, \ + DC_LOG_HW_HOTPLUG( \ __VA_ARGS__) /******************************************************************************* @@ -126,6 +128,8 @@ static bool program_hpd_filter( int delay_on_connect_in_ms = 0; int delay_on_disconnect_in_ms = 0; + if (link->is_hpd_filter_disabled) + return false; /* Verify feature is supported */ switch (link->connector_signal) { case SIGNAL_TYPE_DVI_SINGLE_LINK: @@ -464,7 +468,7 @@ static void link_disconnect_sink(struct dc_link *link) link->dpcd_sink_count = 0; } -static void detect_dp( +static bool detect_dp( struct dc_link *link, struct display_sink_capability *sink_caps, bool *converter_disable_audio, @@ -478,7 +482,8 @@ static void detect_dp( if (sink_caps->transaction_type == DDC_TRANSACTION_TYPE_I2C_OVER_AUX) { sink_caps->signal = SIGNAL_TYPE_DISPLAY_PORT; - detect_dp_sink_caps(link); + if (!detect_dp_sink_caps(link)) + return false; if (is_mst_supported(link)) { sink_caps->signal = SIGNAL_TYPE_DISPLAY_PORT_MST; @@ -529,7 +534,7 @@ static void detect_dp( * active dongle unplug processing for short irq */ link_disconnect_sink(link); - return; + return true; } if (link->dpcd_caps.dongle_type != DISPLAY_DONGLE_DP_HDMI_CONVERTER) @@ -541,6 +546,8 @@ static void detect_dp( sink_caps, audio_support); } + + return true; } bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason) @@ -604,11 +611,12 @@ bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason) } case SIGNAL_TYPE_DISPLAY_PORT: { - detect_dp( + if (!detect_dp( link, &sink_caps, &converter_disable_audio, - aud_support, reason); + aud_support, reason)) + return false; /* Active dongle downstream unplug */ if (link->type == dc_connection_active_dongle @@ -671,14 +679,10 @@ bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason) switch (edid_status) { case EDID_BAD_CHECKSUM: - dm_logger_write(link->ctx->logger, LOG_ERROR, - "EDID checksum invalid.\n"); + DC_LOG_ERROR("EDID checksum invalid.\n"); break; case EDID_NO_RESPONSE: - dm_logger_write(link->ctx->logger, LOG_ERROR, - "No EDID read.\n"); - return false; - + DC_LOG_ERROR("No EDID read.\n"); default: break; } @@ -708,8 +712,7 @@ bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason) "%s: [Block %d] ", sink->edid_caps.display_name, i); } - dm_logger_write(link->ctx->logger, LOG_DETECTION_EDID_PARSER, - "%s: " + DC_LOG_DETECTION_EDID_PARSER("%s: " "manufacturer_id = %X, " "product_id = %X, " "serial_number = %X, " @@ -729,8 +732,7 @@ bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason) sink->edid_caps.audio_mode_count); for (i = 0; i < sink->edid_caps.audio_mode_count; i++) { - dm_logger_write(link->ctx->logger, LOG_DETECTION_EDID_PARSER, - "%s: mode number = %d, " + DC_LOG_DETECTION_EDID_PARSER("%s: mode number = %d, " "format_code = %d, " "channel_count = %d, " "sample_rate = %d, " @@ -980,8 +982,7 @@ static bool construct( } break; default: - dm_logger_write(dc_ctx->logger, LOG_WARNING, - "Unsupported Connector type:%d!\n", link->link_id.id); + DC_LOG_WARNING("Unsupported Connector type:%d!\n", link->link_id.id); goto create_fail; } @@ -1134,7 +1135,7 @@ static void dpcd_configure_panel_mode( { union dpcd_edp_config edp_config_set; bool panel_mode_edp = false; - + struct dc_context *dc_ctx = link->ctx; memset(&edp_config_set, '\0', sizeof(union dpcd_edp_config)); if (DP_PANEL_MODE_DEFAULT != panel_mode) { @@ -1171,8 +1172,7 @@ static void dpcd_configure_panel_mode( ASSERT(result == DDC_RESULT_SUCESSFULL); } } - dm_logger_write(link->ctx->logger, LOG_DETECTION_DP_CAPS, - "Link: %d eDP panel mode supported: %d " + DC_LOG_DETECTION_DP_CAPS("Link: %d eDP panel mode supported: %d " "eDP panel mode enabled: %d \n", link->link_index, link->dpcd_caps.panel_mode_edp, @@ -1248,6 +1248,12 @@ static enum dc_status enable_link_dp( pipe_ctx->clock_source->id, &link_settings); + if (stream->sink->edid_caps.panel_patch.dppowerup_delay > 0) { + int delay_dp_power_up_in_ms = stream->sink->edid_caps.panel_patch.dppowerup_delay; + + msleep(delay_dp_power_up_in_ms); + } + panel_mode = dp_get_panel_mode(link); dpcd_configure_panel_mode(link, panel_mode); @@ -1279,13 +1285,12 @@ static enum dc_status enable_link_edp( enum dc_status status; struct dc_stream_state *stream = pipe_ctx->stream; struct dc_link *link = stream->sink->link; - + /*in case it is not on*/ link->dc->hwss.edp_power_control(link, true); link->dc->hwss.edp_wait_for_hpd_ready(link, true); status = enable_link_dp(state, pipe_ctx); - link->dc->hwss.edp_backlight_control(link, true); return status; } @@ -1302,6 +1307,9 @@ static enum dc_status enable_link_dp_mst( if (link->cur_link_settings.lane_count != LANE_COUNT_UNKNOWN) return DC_OK; + /* clear payload table */ + dm_helpers_dp_mst_clear_payload_allocation_table(link->ctx, link); + /* set the sink to MST mode before enabling the link */ dp_enable_mst_on_sink(link, true); @@ -1749,8 +1757,7 @@ static void enable_link_hdmi(struct pipe_ctx *pipe_ctx) link->link_enc, pipe_ctx->clock_source->id, display_color_depth, - pipe_ctx->stream->signal == SIGNAL_TYPE_HDMI_TYPE_A, - pipe_ctx->stream->signal == SIGNAL_TYPE_DVI_DUAL_LINK, + pipe_ctx->stream->signal, stream->phy_pix_clk); if (pipe_ctx->stream->signal == SIGNAL_TYPE_HDMI_TYPE_A) @@ -1788,9 +1795,21 @@ static enum dc_status enable_link( } if (pipe_ctx->stream_res.audio && status == DC_OK) { + struct dc *core_dc = pipe_ctx->stream->ctx->dc; /* notify audio driver for audio modes of monitor */ + struct pp_smu_funcs_rv *pp_smu = core_dc->res_pool->pp_smu; + unsigned int i, num_audio = 1; + for (i = 0; i < MAX_PIPES; i++) { + /*current_state not updated yet*/ + if (core_dc->current_state->res_ctx.pipe_ctx[i].stream_res.audio != NULL) + num_audio++; + } + pipe_ctx->stream_res.audio->funcs->az_enable(pipe_ctx->stream_res.audio); + if (num_audio == 1 && pp_smu != NULL && pp_smu->set_pme_wa_enable != NULL) + /*this is the first audio. apply the PME w/a in order to wake AZ from D3*/ + pp_smu->set_pme_wa_enable(&pp_smu->pp_smu); /* un-mute audio */ /* TODO: audio should be per stream rather than per link */ pipe_ctx->stream_res.stream_enc->funcs->audio_mute_control( @@ -1931,6 +1950,7 @@ bool dc_link_set_backlight_level(const struct dc_link *link, uint32_t level, struct dc *core_dc = link->ctx->dc; struct abm *abm = core_dc->res_pool->abm; struct dmcu *dmcu = core_dc->res_pool->dmcu; + struct dc_context *dc_ctx = link->ctx; unsigned int controller_id = 0; bool use_smooth_brightness = true; int i; @@ -1940,10 +1960,16 @@ bool dc_link_set_backlight_level(const struct dc_link *link, uint32_t level, (abm->funcs->set_backlight_level == NULL)) return false; + if (stream) { + if (stream->bl_pwm_level == 0) + frame_ramp = 0; + + ((struct dc_stream_state *)stream)->bl_pwm_level = level; + } + use_smooth_brightness = dmcu->funcs->is_dmcu_initialized(dmcu); - dm_logger_write(link->ctx->logger, LOG_BACKLIGHT, - "New Backlight level: %d (0x%X)\n", level, level); + DC_LOG_BACKLIGHT("New Backlight level: %d (0x%X)\n", level, level); if (dc_is_embedded_signal(link->connector_signal)) { if (stream != NULL) { @@ -2110,6 +2136,7 @@ static enum dc_status allocate_mst_payload(struct pipe_ctx *pipe_ctx) struct fixed31_32 avg_time_slots_per_mtp; struct fixed31_32 pbn; struct fixed31_32 pbn_per_slot; + struct dc_context *dc_ctx = link->ctx; uint8_t i; /* enable_link_dp_mst already check link->enabled_stream_count @@ -2127,21 +2154,18 @@ static enum dc_status allocate_mst_payload(struct pipe_ctx *pipe_ctx) link, pipe_ctx->stream_res.stream_enc, &proposed_table); } else - dm_logger_write(link->ctx->logger, LOG_WARNING, - "Failed to update" + DC_LOG_WARNING("Failed to update" "MST allocation table for" "pipe idx:%d\n", pipe_ctx->pipe_idx); - dm_logger_write(link->ctx->logger, LOG_MST, - "%s " + DC_LOG_MST("%s " "stream_count: %d: \n ", __func__, link->mst_stream_alloc_table.stream_count); for (i = 0; i < MAX_CONTROLLER_NUM; i++) { - dm_logger_write(link->ctx->logger, LOG_MST, - "stream_enc[%d]: 0x%x " + DC_LOG_MST("stream_enc[%d]: 0x%x " "stream[%d].vcp_id: %d " "stream[%d].slot_count: %d\n", i, @@ -2192,6 +2216,7 @@ static enum dc_status deallocate_mst_payload(struct pipe_ctx *pipe_ctx) struct fixed31_32 avg_time_slots_per_mtp = dal_fixed31_32_from_int(0); uint8_t i; bool mst_mode = (link->type == dc_connection_mst_branch); + struct dc_context *dc_ctx = link->ctx; /* deallocate_mst_payload is called before disable link. When mode or * disable/enable monitor, new stream is created which is not in link @@ -2217,23 +2242,20 @@ static enum dc_status deallocate_mst_payload(struct pipe_ctx *pipe_ctx) link, pipe_ctx->stream_res.stream_enc, &proposed_table); } else { - dm_logger_write(link->ctx->logger, LOG_WARNING, - "Failed to update" + DC_LOG_WARNING("Failed to update" "MST allocation table for" "pipe idx:%d\n", pipe_ctx->pipe_idx); } } - dm_logger_write(link->ctx->logger, LOG_MST, - "%s" + DC_LOG_MST("%s" "stream_count: %d: ", __func__, link->mst_stream_alloc_table.stream_count); for (i = 0; i < MAX_CONTROLLER_NUM; i++) { - dm_logger_write(link->ctx->logger, LOG_MST, - "stream_enc[%d]: 0x%x " + DC_LOG_MST("stream_enc[%d]: 0x%x " "stream[%d].vcp_id: %d " "stream[%d].slot_count: %d\n", i, @@ -2267,12 +2289,24 @@ void core_link_enable_stream( struct pipe_ctx *pipe_ctx) { struct dc *core_dc = pipe_ctx->stream->ctx->dc; + struct dc_context *dc_ctx = pipe_ctx->stream->ctx; + enum dc_status status; + + /* eDP lit up by bios already, no need to enable again. */ + if (pipe_ctx->stream->signal == SIGNAL_TYPE_EDP && + core_dc->apply_edp_fast_boot_optimization) { + core_dc->apply_edp_fast_boot_optimization = false; + pipe_ctx->stream->dpms_off = false; + return; + } + + if (pipe_ctx->stream->dpms_off) + return; - enum dc_status status = enable_link(state, pipe_ctx); + status = enable_link(state, pipe_ctx); if (status != DC_OK) { - dm_logger_write(pipe_ctx->stream->ctx->logger, - LOG_WARNING, "enabling link %u failed: %d\n", + DC_LOG_WARNING("enabling link %u failed: %d\n", pipe_ctx->stream->sink->link->link_index, status); @@ -2298,9 +2332,8 @@ void core_link_enable_stream( if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) allocate_mst_payload(pipe_ctx); - if (dc_is_dp_signal(pipe_ctx->stream->signal)) - core_dc->hwss.unblank_stream(pipe_ctx, - &pipe_ctx->stream->sink->link->cur_link_settings); + core_dc->hwss.unblank_stream(pipe_ctx, + &pipe_ctx->stream->sink->link->cur_link_settings); } void core_link_disable_stream(struct pipe_ctx *pipe_ctx, int option) @@ -2310,8 +2343,7 @@ void core_link_disable_stream(struct pipe_ctx *pipe_ctx, int option) if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) deallocate_mst_payload(pipe_ctx); - if (pipe_ctx->stream->signal == SIGNAL_TYPE_EDP) - core_dc->hwss.edp_backlight_control(pipe_ctx->stream->sink->link, false); + core_dc->hwss.blank_stream(pipe_ctx); core_dc->hwss.disable_stream(pipe_ctx, option); @@ -2328,3 +2360,36 @@ void core_link_set_avmute(struct pipe_ctx *pipe_ctx, bool enable) core_dc->hwss.set_avmute(pipe_ctx, enable); } +void dc_link_enable_hpd_filter(struct dc_link *link, bool enable) +{ + struct gpio *hpd; + + if (enable) { + link->is_hpd_filter_disabled = false; + program_hpd_filter(link); + } else { + link->is_hpd_filter_disabled = true; + /* Obtain HPD handle */ + hpd = get_hpd_gpio(link->ctx->dc_bios, link->link_id, link->ctx->gpio_service); + + if (!hpd) + return; + + /* Setup HPD filtering */ + if (dal_gpio_open(hpd, GPIO_MODE_INTERRUPT) == GPIO_RESULT_OK) { + struct gpio_hpd_config config; + + config.delay_on_connect = 0; + config.delay_on_disconnect = 0; + + dal_irq_setup_hpd_filter(hpd, &config); + + dal_gpio_close(hpd); + } else { + ASSERT_CRITICAL(false); + } + /* Release HPD handle */ + dal_gpio_destroy_irq(&hpd); + } +} + diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c index d5294798b0a5..49c2face1e7a 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c @@ -629,7 +629,7 @@ bool dal_ddc_service_query_ddc_data( return ret; } -enum ddc_result dal_ddc_service_read_dpcd_data( +ssize_t dal_ddc_service_read_dpcd_data( struct ddc_service *ddc, bool i2c, enum i2c_mot_mode mot, @@ -660,8 +660,9 @@ enum ddc_result dal_ddc_service_read_dpcd_data( if (dal_i2caux_submit_aux_command( ddc->ctx->i2caux, ddc->ddc_pin, - &command)) - return DDC_RESULT_SUCESSFULL; + &command)) { + return (ssize_t)command.payloads->length; + } return DDC_RESULT_FAILED_OPERATION; } 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 61e8c3e02d16..3b5053570229 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 @@ -11,6 +11,8 @@ #include "dpcd_defs.h" #include "resource.h" +#define DC_LOGGER \ + link->ctx->logger /* maximum pre emphasis level allowed for each voltage swing level*/ static const enum dc_pre_emphasis voltage_swing_to_pre_emphasis[] = { @@ -63,8 +65,7 @@ static void wait_for_training_aux_rd_interval( udelay(default_wait_in_micro_secs); - dm_logger_write(link->ctx->logger, LOG_HW_LINK_TRAINING, - "%s:\n wait = %d\n", + DC_LOG_HW_LINK_TRAINING("%s:\n wait = %d\n", __func__, default_wait_in_micro_secs); } @@ -79,8 +80,7 @@ static void dpcd_set_training_pattern( &dpcd_pattern.raw, 1); - dm_logger_write(link->ctx->logger, LOG_HW_LINK_TRAINING, - "%s\n %x pattern = %x\n", + DC_LOG_HW_LINK_TRAINING("%s\n %x pattern = %x\n", __func__, DP_TRAINING_PATTERN_SET, dpcd_pattern.v1_4.TRAINING_PATTERN_SET); @@ -116,8 +116,7 @@ static void dpcd_set_link_settings( core_link_write_dpcd(link, DP_DOWNSPREAD_CTRL, &downspread.raw, sizeof(downspread)); - dm_logger_write(link->ctx->logger, LOG_HW_LINK_TRAINING, - "%s\n %x rate = %x\n %x lane = %x\n %x spread = %x\n", + DC_LOG_HW_LINK_TRAINING("%s\n %x rate = %x\n %x lane = %x\n %x spread = %x\n", __func__, DP_LINK_BW_SET, lt_settings->link_settings.link_rate, @@ -151,8 +150,7 @@ static enum dpcd_training_patterns break; default: ASSERT(0); - dm_logger_write(link->ctx->logger, LOG_HW_LINK_TRAINING, - "%s: Invalid HW Training pattern: %d\n", + DC_LOG_HW_LINK_TRAINING("%s: Invalid HW Training pattern: %d\n", __func__, pattern); break; } @@ -184,8 +182,7 @@ static void dpcd_set_lt_pattern_and_lane_settings( dpcd_lt_buffer[DP_TRAINING_PATTERN_SET - dpcd_base_lt_offset] = dpcd_pattern.raw; - dm_logger_write(link->ctx->logger, LOG_HW_LINK_TRAINING, - "%s\n %x pattern = %x\n", + DC_LOG_HW_LINK_TRAINING("%s\n %x pattern = %x\n", __func__, DP_TRAINING_PATTERN_SET, dpcd_pattern.v1_4.TRAINING_PATTERN_SET); @@ -219,8 +216,7 @@ static void dpcd_set_lt_pattern_and_lane_settings( dpcd_lane, size_in_bytes); - dm_logger_write(link->ctx->logger, LOG_HW_LINK_TRAINING, - "%s:\n %x VS set = %x PE set = %x max VS Reached = %x max PE Reached = %x\n", + DC_LOG_HW_LINK_TRAINING("%s:\n %x VS set = %x PE set = %x max VS Reached = %x max PE Reached = %x\n", __func__, DP_TRAINING_LANE0_SET, dpcd_lane[0].bits.VOLTAGE_SWING_SET, @@ -456,14 +452,12 @@ static void get_lane_status_and_drive_settings( ln_status_updated->raw = dpcd_buf[2]; - dm_logger_write(link->ctx->logger, LOG_HW_LINK_TRAINING, - "%s:\n%x Lane01Status = %x\n %x Lane23Status = %x\n ", + DC_LOG_HW_LINK_TRAINING("%s:\n%x Lane01Status = %x\n %x Lane23Status = %x\n ", __func__, DP_LANE0_1_STATUS, dpcd_buf[0], DP_LANE2_3_STATUS, dpcd_buf[1]); - dm_logger_write(link->ctx->logger, LOG_HW_LINK_TRAINING, - "%s:\n %x Lane01AdjustRequest = %x\n %x Lane23AdjustRequest = %x\n", + DC_LOG_HW_LINK_TRAINING("%s:\n %x Lane01AdjustRequest = %x\n %x Lane23AdjustRequest = %x\n", __func__, DP_ADJUST_REQUEST_LANE0_1, dpcd_buf[4], @@ -556,8 +550,7 @@ static void dpcd_set_lane_settings( } */ - dm_logger_write(link->ctx->logger, LOG_HW_LINK_TRAINING, - "%s\n %x VS set = %x PE set = %x max VS Reached = %x max PE Reached = %x\n", + DC_LOG_HW_LINK_TRAINING("%s\n %x VS set = %x PE set = %x max VS Reached = %x max PE Reached = %x\n", __func__, DP_TRAINING_LANE0_SET, dpcd_lane[0].bits.VOLTAGE_SWING_SET, @@ -669,16 +662,14 @@ static bool perform_post_lt_adj_req_sequence( } if (!req_drv_setting_changed) { - dm_logger_write(link->ctx->logger, LOG_WARNING, - "%s: Post Link Training Adjust Request Timed out\n", + DC_LOG_WARNING("%s: Post Link Training Adjust Request Timed out\n", __func__); ASSERT(0); return true; } } - dm_logger_write(link->ctx->logger, LOG_WARNING, - "%s: Post Link Training Adjust Request limit reached\n", + DC_LOG_WARNING("%s: Post Link Training Adjust Request limit reached\n", __func__); ASSERT(0); @@ -709,6 +700,22 @@ static enum hw_dp_training_pattern get_supported_tp(struct dc_link *link) return HW_DP_TRAINING_PATTERN_2; } +static enum link_training_result get_cr_failure(enum dc_lane_count ln_count, + union lane_status *dpcd_lane_status) +{ + enum link_training_result result = LINK_TRAINING_SUCCESS; + + if (ln_count >= LANE_COUNT_ONE && !dpcd_lane_status[0].bits.CR_DONE_0) + result = LINK_TRAINING_CR_FAIL_LANE0; + else if (ln_count >= LANE_COUNT_TWO && !dpcd_lane_status[1].bits.CR_DONE_0) + result = LINK_TRAINING_CR_FAIL_LANE1; + else if (ln_count >= LANE_COUNT_FOUR && !dpcd_lane_status[2].bits.CR_DONE_0) + result = LINK_TRAINING_CR_FAIL_LANE23; + else if (ln_count >= LANE_COUNT_FOUR && !dpcd_lane_status[3].bits.CR_DONE_0) + result = LINK_TRAINING_CR_FAIL_LANE23; + return result; +} + static enum link_training_result perform_channel_equalization_sequence( struct dc_link *link, struct link_training_settings *lt_settings) @@ -718,7 +725,7 @@ static enum link_training_result perform_channel_equalization_sequence( uint32_t retries_ch_eq; enum dc_lane_count lane_count = lt_settings->link_settings.lane_count; union lane_align_status_updated dpcd_lane_status_updated = {{0}}; - union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {{{0}}};; + union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {{{0}}}; hw_tr_pattern = get_supported_tp(link); @@ -771,7 +778,7 @@ static enum link_training_result perform_channel_equalization_sequence( } -static bool perform_clock_recovery_sequence( +static enum link_training_result perform_clock_recovery_sequence( struct dc_link *link, struct link_training_settings *lt_settings) { @@ -846,11 +853,11 @@ static bool perform_clock_recovery_sequence( /* 5. check CR done*/ if (is_cr_done(lane_count, dpcd_lane_status)) - return true; + return LINK_TRAINING_SUCCESS; /* 6. max VS reached*/ if (is_max_vs_reached(lt_settings)) - return false; + break; /* 7. same voltage*/ /* Note: VS same for all lanes, @@ -869,20 +876,19 @@ static bool perform_clock_recovery_sequence( if (retry_count >= LINK_TRAINING_MAX_CR_RETRY) { ASSERT(0); - dm_logger_write(link->ctx->logger, LOG_ERROR, - "%s: Link Training Error, could not get CR after %d tries. Possibly voltage swing issue", + DC_LOG_ERROR("%s: Link Training Error, could not get CR after %d tries. Possibly voltage swing issue", __func__, LINK_TRAINING_MAX_CR_RETRY); } - return false; + return get_cr_failure(lane_count, dpcd_lane_status); } -static inline bool perform_link_training_int( +static inline enum link_training_result perform_link_training_int( struct dc_link *link, struct link_training_settings *lt_settings, - bool status) + enum link_training_result status) { union lane_count_set lane_count_set = { {0} }; union dpcd_training_pattern dpcd_pattern = { {0} }; @@ -903,9 +909,9 @@ static inline bool perform_link_training_int( get_supported_tp(link) == HW_DP_TRAINING_PATTERN_4) return status; - if (status && + if (status == LINK_TRAINING_SUCCESS && perform_post_lt_adj_req_sequence(link, lt_settings) == false) - status = false; + status = LINK_TRAINING_LQA_FAIL; lane_count_set.bits.LANE_COUNT_SET = lt_settings->link_settings.lane_count; lane_count_set.bits.ENHANCED_FRAMING = 1; @@ -928,6 +934,8 @@ enum link_training_result dc_link_dp_perform_link_training( enum link_training_result status = LINK_TRAINING_SUCCESS; char *link_rate = "Unknown"; + char *lt_result = "Unknown"; + struct link_training_settings lt_settings; memset(<_settings, '\0', sizeof(lt_settings)); @@ -951,22 +959,16 @@ enum link_training_result dc_link_dp_perform_link_training( /* 2. perform link training (set link training done * to false is done as well)*/ - if (!perform_clock_recovery_sequence(link, <_settings)) { - status = LINK_TRAINING_CR_FAIL; - } else { + status = perform_clock_recovery_sequence(link, <_settings); + if (status == LINK_TRAINING_SUCCESS) { status = perform_channel_equalization_sequence(link, <_settings); } if ((status == LINK_TRAINING_SUCCESS) || !skip_video_pattern) { - if (!perform_link_training_int(link, + status = perform_link_training_int(link, <_settings, - status == LINK_TRAINING_SUCCESS)) { - /* the next link training setting in this case - * would be the same as CR failure case. - */ - status = LINK_TRAINING_CR_FAIL; - } + status); } /* 6. print status message*/ @@ -991,13 +993,37 @@ enum link_training_result dc_link_dp_perform_link_training( break; } + switch (status) { + case LINK_TRAINING_SUCCESS: + lt_result = "pass"; + break; + case LINK_TRAINING_CR_FAIL_LANE0: + lt_result = "CR failed lane0"; + break; + case LINK_TRAINING_CR_FAIL_LANE1: + lt_result = "CR failed lane1"; + break; + case LINK_TRAINING_CR_FAIL_LANE23: + lt_result = "CR failed lane23"; + break; + case LINK_TRAINING_EQ_FAIL_CR: + lt_result = "CR failed in EQ"; + break; + case LINK_TRAINING_EQ_FAIL_EQ: + lt_result = "EQ failed"; + break; + case LINK_TRAINING_LQA_FAIL: + lt_result = "LQA failed"; + break; + default: + break; + } + /* Connectivity log: link training */ CONN_MSG_LT(link, "%sx%d %s VS=%d, PE=%d", link_rate, lt_settings.link_settings.lane_count, - (status == LINK_TRAINING_SUCCESS) ? "pass" : - ((status == LINK_TRAINING_CR_FAIL) ? "CR failed" : - "EQ failed"), + lt_result, lt_settings.lane_settings[0].VOLTAGE_SWING, lt_settings.lane_settings[0].PRE_EMPHASIS); @@ -1115,6 +1141,7 @@ bool dp_hbr_verify_link_cap( dp_cs_id, cur); + if (skip_link_training) success = true; else { @@ -1279,7 +1306,10 @@ static bool decide_fallback_link_setting( return false; switch (training_result) { - case LINK_TRAINING_CR_FAIL: + case LINK_TRAINING_CR_FAIL_LANE0: + case LINK_TRAINING_CR_FAIL_LANE1: + case LINK_TRAINING_CR_FAIL_LANE23: + case LINK_TRAINING_LQA_FAIL: { if (!reached_minimum_link_rate (current_link_setting->link_rate)) { @@ -1290,8 +1320,18 @@ static bool decide_fallback_link_setting( (current_link_setting->lane_count)) { current_link_setting->link_rate = initial_link_settings.link_rate; - current_link_setting->lane_count = - reduce_lane_count( + if (training_result == LINK_TRAINING_CR_FAIL_LANE0) + return false; + else if (training_result == LINK_TRAINING_CR_FAIL_LANE1) + current_link_setting->lane_count = + LANE_COUNT_ONE; + else if (training_result == + LINK_TRAINING_CR_FAIL_LANE23) + current_link_setting->lane_count = + LANE_COUNT_TWO; + else + current_link_setting->lane_count = + reduce_lane_count( current_link_setting->lane_count); } else { return false; @@ -1465,7 +1505,7 @@ void decide_link_settings(struct dc_stream_state *stream, /* MST doesn't perform link training for now * TODO: add MST specific link training routine */ - if (is_mst_supported(link)) { + if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) { *link_setting = link->verified_link_cap; return; } @@ -1556,8 +1596,7 @@ static bool hpd_rx_irq_check_link_loss_status( if (sink_status_changed || !hpd_irq_dpcd_data->bytes.lane_status_updated.bits.INTERLANE_ALIGN_DONE) { - dm_logger_write(link->ctx->logger, LOG_HW_HPD_IRQ, - "%s: Link Status changed.\n", __func__); + DC_LOG_HW_HPD_IRQ("%s: Link Status changed.\n", __func__); return_code = true; @@ -1570,8 +1609,7 @@ static bool hpd_rx_irq_check_link_loss_status( sizeof(irq_reg_rx_power_state)); if (dpcd_result != DC_OK) { - dm_logger_write(link->ctx->logger, LOG_HW_HPD_IRQ, - "%s: DPCD read failed to obtain power state.\n", + DC_LOG_HW_HPD_IRQ("%s: DPCD read failed to obtain power state.\n", __func__); } else { if (irq_reg_rx_power_state != DP_SET_POWER_D0) @@ -1932,8 +1970,7 @@ bool dc_link_handle_hpd_rx_irq(struct dc_link *link, union hpd_irq_data *out_hpd * PSR and device auto test, refer to function handle_sst_hpd_irq * in DAL2.1*/ - dm_logger_write(link->ctx->logger, LOG_HW_HPD_IRQ, - "%s: Got short pulse HPD on link %d\n", + DC_LOG_HW_HPD_IRQ("%s: Got short pulse HPD on link %d\n", __func__, link->link_index); @@ -1947,8 +1984,7 @@ bool dc_link_handle_hpd_rx_irq(struct dc_link *link, union hpd_irq_data *out_hpd *out_hpd_irq_dpcd_data = hpd_irq_dpcd_data; if (result != DC_OK) { - dm_logger_write(link->ctx->logger, LOG_HW_HPD_IRQ, - "%s: DPCD read failed to obtain irq data\n", + DC_LOG_HW_HPD_IRQ("%s: DPCD read failed to obtain irq data\n", __func__); return false; } @@ -1966,8 +2002,7 @@ bool dc_link_handle_hpd_rx_irq(struct dc_link *link, union hpd_irq_data *out_hpd } if (!allow_hpd_rx_irq(link)) { - dm_logger_write(link->ctx->logger, LOG_HW_HPD_IRQ, - "%s: skipping HPD handling on %d\n", + DC_LOG_HW_HPD_IRQ("%s: skipping HPD handling on %d\n", __func__, link->link_index); return false; } @@ -2235,13 +2270,14 @@ static void dp_wa_power_up_0010FA(struct dc_link *link, uint8_t *dpcd_data, link->wa_flags.dp_keep_receiver_powered = false; } -static void retrieve_link_cap(struct dc_link *link) +static bool retrieve_link_cap(struct dc_link *link) { uint8_t dpcd_data[DP_TRAINING_AUX_RD_INTERVAL - DP_DPCD_REV + 1]; union down_stream_port_count down_strm_port_count; union edp_configuration_cap edp_config_cap; union dp_downstream_port_present ds_port = { 0 }; + enum dc_status status = DC_ERROR_UNEXPECTED; memset(dpcd_data, '\0', sizeof(dpcd_data)); memset(&down_strm_port_count, @@ -2249,11 +2285,16 @@ static void retrieve_link_cap(struct dc_link *link) memset(&edp_config_cap, '\0', sizeof(union edp_configuration_cap)); - core_link_read_dpcd( - link, - DP_DPCD_REV, - dpcd_data, - sizeof(dpcd_data)); + status = core_link_read_dpcd( + link, + DP_DPCD_REV, + dpcd_data, + sizeof(dpcd_data)); + + if (status != DC_OK) { + dm_error("%s: Read dpcd data failed.\n", __func__); + return false; + } { union training_aux_rd_interval aux_rd_interval; @@ -2315,11 +2356,13 @@ static void retrieve_link_cap(struct dc_link *link) /* Connectivity log: detection */ CONN_DATA_DETECT(link, dpcd_data, sizeof(dpcd_data), "Rx Caps: "); + + return true; } -void detect_dp_sink_caps(struct dc_link *link) +bool detect_dp_sink_caps(struct dc_link *link) { - retrieve_link_cap(link); + return retrieve_link_cap(link); /* dc init_hw has power encoder using default * signal for connector. For native DP, no 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 2096f2a179f2..7c866a7d5e77 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 @@ -102,7 +102,7 @@ void dp_enable_link_phy( dp_receiver_power_ctrl(link, true); } -static bool edp_receiver_ready_T9(struct dc_link *link) +bool edp_receiver_ready_T9(struct dc_link *link) { unsigned int tries = 0; unsigned char sinkstatus = 0; @@ -123,6 +123,28 @@ static bool edp_receiver_ready_T9(struct dc_link *link) } while (++tries < 50); return result; } +bool edp_receiver_ready_T7(struct dc_link *link) +{ + unsigned int tries = 0; + unsigned char sinkstatus = 0; + unsigned char edpRev = 0; + enum dc_status result = DC_OK; + + result = core_link_read_dpcd(link, DP_EDP_DPCD_REV, &edpRev, sizeof(edpRev)); + if (result == DC_OK && edpRev < DP_EDP_12) + return true; + /* start from eDP version 1.2, SINK_STAUS indicate the sink is ready.*/ + do { + sinkstatus = 0; + result = core_link_read_dpcd(link, DP_SINK_STATUS, &sinkstatus, sizeof(sinkstatus)); + if (sinkstatus == 1) + break; + if (result != DC_OK) + break; + udelay(25); //MAx T7 is 50ms + } while (++tries < 300); + return result; +} void dp_disable_link_phy(struct dc_link *link, enum signal_type signal) { @@ -130,7 +152,6 @@ void dp_disable_link_phy(struct dc_link *link, enum signal_type signal) dp_receiver_power_ctrl(link, false); if (signal == SIGNAL_TYPE_EDP) { - edp_receiver_ready_T9(link); link->link_enc->funcs->disable_output(link->link_enc, signal); link->dc->hwss.edp_power_control(link, false); } else @@ -258,6 +279,7 @@ void dp_retrain_link_dp_test(struct dc_link *link, for (i = 0; i < MAX_PIPES; i++) { if (pipes[i].stream != NULL && + !pipes[i].top_pipe && pipes[i].stream->sink != NULL && pipes[i].stream->sink->link != NULL && pipes[i].stream_res.stream_enc != NULL && 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 95b8dd0e53c6..ba3487e97361 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -35,6 +35,7 @@ #include "core_types.h" #include "set_mode_types.h" #include "virtual/virtual_stream_encoder.h" +#include "dpcd_defs.h" #include "dce80/dce80_resource.h" #include "dce100/dce100_resource.h" @@ -44,7 +45,8 @@ #include "dcn10/dcn10_resource.h" #endif #include "dce120/dce120_resource.h" - +#define DC_LOGGER \ + ctx->logger enum dce_version resource_parse_asic_id(struct hw_asic_id asic_id) { enum dce_version dc_version = DCE_VERSION_UNKNOWN; @@ -696,7 +698,7 @@ static void calculate_inits_and_adj_vp(struct pipe_ctx *pipe_ctx, struct view *r /* Adjust for viewport end clip-off */ - if ((data->viewport.x + data->viewport.width) < (src.x + src.width)) { + if ((data->viewport.x + data->viewport.width) < (src.x + src.width) && !flip_horz_scan_dir) { int vp_clip = src.x + src.width - data->viewport.width - data->viewport.x; int int_part = dal_fixed31_32_floor( dal_fixed31_32_sub(data->inits.h, data->ratios.horz)); @@ -704,7 +706,7 @@ static void calculate_inits_and_adj_vp(struct pipe_ctx *pipe_ctx, struct view *r int_part = int_part > 0 ? int_part : 0; data->viewport.width += int_part < vp_clip ? int_part : vp_clip; } - if ((data->viewport.y + data->viewport.height) < (src.y + src.height)) { + if ((data->viewport.y + data->viewport.height) < (src.y + src.height) && !flip_vert_scan_dir) { int vp_clip = src.y + src.height - data->viewport.height - data->viewport.y; int int_part = dal_fixed31_32_floor( dal_fixed31_32_sub(data->inits.v, data->ratios.vert)); @@ -712,7 +714,7 @@ static void calculate_inits_and_adj_vp(struct pipe_ctx *pipe_ctx, struct view *r int_part = int_part > 0 ? int_part : 0; data->viewport.height += int_part < vp_clip ? int_part : vp_clip; } - if ((data->viewport_c.x + data->viewport_c.width) < (src.x + src.width) / vpc_div) { + if ((data->viewport_c.x + data->viewport_c.width) < (src.x + src.width) / vpc_div && !flip_horz_scan_dir) { int vp_clip = (src.x + src.width) / vpc_div - data->viewport_c.width - data->viewport_c.x; int int_part = dal_fixed31_32_floor( @@ -721,7 +723,7 @@ static void calculate_inits_and_adj_vp(struct pipe_ctx *pipe_ctx, struct view *r int_part = int_part > 0 ? int_part : 0; data->viewport_c.width += int_part < vp_clip ? int_part : vp_clip; } - if ((data->viewport_c.y + data->viewport_c.height) < (src.y + src.height) / vpc_div) { + if ((data->viewport_c.y + data->viewport_c.height) < (src.y + src.height) / vpc_div && !flip_vert_scan_dir) { int vp_clip = (src.y + src.height) / vpc_div - data->viewport_c.height - data->viewport_c.y; int int_part = dal_fixed31_32_floor( @@ -833,7 +835,7 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx) struct dc_crtc_timing *timing = &pipe_ctx->stream->timing; struct view recout_skip = { 0 }; bool res = false; - + struct dc_context *ctx = pipe_ctx->stream->ctx; /* Important: scaling ratio calculation requires pixel format, * lb depth calculation requires recout and taps require scaling ratios. * Inits require viewport, taps, ratios and recout of split pipe @@ -892,7 +894,7 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx) /* May need to re-check lb size after this in some obscure scenario */ calculate_inits_and_adj_vp(pipe_ctx, &recout_skip); - dm_logger_write(pipe_ctx->stream->ctx->logger, LOG_SCALER, + DC_LOG_SCALER( "%s: Viewport:\nheight:%d width:%d x:%d " "y:%d\n dst_rect:\nheight:%d width:%d x:%d " "y:%d\n", @@ -1054,6 +1056,7 @@ static int acquire_first_split_pipe( pipe_ctx->plane_res.ipp = pool->ipps[i]; pipe_ctx->plane_res.dpp = pool->dpps[i]; pipe_ctx->stream_res.opp = pool->opps[i]; + pipe_ctx->plane_res.mpcc_inst = pool->dpps[i]->inst; pipe_ctx->pipe_idx = i; pipe_ctx->stream = stream; @@ -1121,6 +1124,7 @@ bool dc_add_plane_to_context( ASSERT(tail_pipe); free_pipe->stream_res.tg = tail_pipe->stream_res.tg; + free_pipe->stream_res.abm = tail_pipe->stream_res.abm; free_pipe->stream_res.opp = tail_pipe->stream_res.opp; free_pipe->stream_res.stream_enc = tail_pipe->stream_res.stream_enc; free_pipe->stream_res.audio = tail_pipe->stream_res.audio; @@ -1360,9 +1364,6 @@ bool dc_is_stream_scaling_unchanged( return true; } -/* Maximum TMDS single link pixel clock 165MHz */ -#define TMDS_MAX_PIXEL_CLOCK_IN_KHZ 165000 - static void update_stream_engine_usage( struct resource_context *res_ctx, const struct resource_pool *pool, @@ -1409,6 +1410,8 @@ static int acquire_first_free_pipe( pipe_ctx->plane_res.xfm = pool->transforms[i]; pipe_ctx->plane_res.dpp = pool->dpps[i]; pipe_ctx->stream_res.opp = pool->opps[i]; + if (pool->dpps[i]) + pipe_ctx->plane_res.mpcc_inst = pool->dpps[i]->inst; pipe_ctx->pipe_idx = i; @@ -1555,6 +1558,9 @@ enum dc_status dc_remove_stream_from_ctx( dc->res_pool, del_pipe->clock_source); + if (dc->res_pool->funcs->remove_stream_from_ctx) + dc->res_pool->funcs->remove_stream_from_ctx(dc, new_ctx, stream); + memset(del_pipe, 0, sizeof(*del_pipe)); break; @@ -1731,6 +1737,10 @@ enum dc_status resource_map_pool_resources( pipe_ctx->stream_res.audio, true); } + /* Add ABM to the resource if on EDP */ + if (pipe_ctx->stream && dc_is_embedded_signal(pipe_ctx->stream->signal)) + pipe_ctx->stream_res.abm = pool->abm; + for (i = 0; i < context->stream_count; i++) if (context->streams[i] == stream) { context->stream_status[i].primary_otg_inst = pipe_ctx->stream_res.tg->inst; @@ -2431,7 +2441,8 @@ static void set_vsc_info_packet( unsigned int vscPacketRevision = 0; unsigned int i; - if (stream->sink->link->psr_enabled) { + /*VSC packet set to 2 when DP revision >= 1.2*/ + if (stream->psr_version != 0) { vscPacketRevision = 2; } diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c index 261811e0c094..ce0747ed0f00 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c @@ -33,8 +33,7 @@ /******************************************************************************* * Private functions ******************************************************************************/ -#define TMDS_MAX_PIXEL_CLOCK_IN_KHZ_UPMOST 297000 -static void update_stream_signal(struct dc_stream_state *stream) +void update_stream_signal(struct dc_stream_state *stream) { struct dc_sink *dc_sink = stream->sink; @@ -45,8 +44,9 @@ static void update_stream_signal(struct dc_stream_state *stream) stream->signal = dc_sink->sink_signal; if (dc_is_dvi_signal(stream->signal)) { - if (stream->timing.pix_clk_khz > TMDS_MAX_PIXEL_CLOCK_IN_KHZ_UPMOST && - stream->sink->sink_signal != SIGNAL_TYPE_DVI_SINGLE_LINK) + if (stream->ctx->dc->caps.dual_link_dvi && + stream->timing.pix_clk_khz > TMDS_MAX_PIXEL_CLOCK && + stream->sink->sink_signal != SIGNAL_TYPE_DVI_SINGLE_LINK) stream->signal = SIGNAL_TYPE_DVI_DUAL_LINK; else stream->signal = SIGNAL_TYPE_DVI_SINGLE_LINK; @@ -193,44 +193,19 @@ bool dc_stream_set_cursor_attributes( core_dc = stream->ctx->dc; res_ctx = &core_dc->current_state->res_ctx; + stream->cursor_attributes = *attributes; for (i = 0; i < MAX_PIPES; i++) { struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[i]; - if (pipe_ctx->stream != stream || (!pipe_ctx->plane_res.xfm && !pipe_ctx->plane_res.dpp)) + if (pipe_ctx->stream != stream) continue; if (pipe_ctx->top_pipe && pipe_ctx->plane_state != pipe_ctx->top_pipe->plane_state) continue; - if (pipe_ctx->plane_res.ipp->funcs->ipp_cursor_set_attributes != NULL) - pipe_ctx->plane_res.ipp->funcs->ipp_cursor_set_attributes( - pipe_ctx->plane_res.ipp, attributes); - - if (pipe_ctx->plane_res.hubp != NULL && - pipe_ctx->plane_res.hubp->funcs->set_cursor_attributes != NULL) - pipe_ctx->plane_res.hubp->funcs->set_cursor_attributes( - pipe_ctx->plane_res.hubp, attributes); - - if (pipe_ctx->plane_res.mi != NULL && - pipe_ctx->plane_res.mi->funcs->set_cursor_attributes != NULL) - pipe_ctx->plane_res.mi->funcs->set_cursor_attributes( - pipe_ctx->plane_res.mi, attributes); - - - if (pipe_ctx->plane_res.xfm != NULL && - pipe_ctx->plane_res.xfm->funcs->set_cursor_attributes != NULL) - pipe_ctx->plane_res.xfm->funcs->set_cursor_attributes( - pipe_ctx->plane_res.xfm, attributes); - - if (pipe_ctx->plane_res.dpp != NULL && - pipe_ctx->plane_res.dpp->funcs->set_cursor_attributes != NULL) - pipe_ctx->plane_res.dpp->funcs->set_cursor_attributes( - pipe_ctx->plane_res.dpp, attributes->color_format); + core_dc->hwss.set_cursor_attribute(pipe_ctx); } - - stream->cursor_attributes = *attributes; - return true; } @@ -254,55 +229,21 @@ bool dc_stream_set_cursor_position( core_dc = stream->ctx->dc; res_ctx = &core_dc->current_state->res_ctx; + stream->cursor_position = *position; for (i = 0; i < MAX_PIPES; i++) { struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[i]; - struct input_pixel_processor *ipp = pipe_ctx->plane_res.ipp; - struct mem_input *mi = pipe_ctx->plane_res.mi; - struct hubp *hubp = pipe_ctx->plane_res.hubp; - struct dpp *dpp = pipe_ctx->plane_res.dpp; - struct dc_cursor_position pos_cpy = *position; - struct dc_cursor_mi_param param = { - .pixel_clk_khz = stream->timing.pix_clk_khz, - .ref_clk_khz = core_dc->res_pool->ref_clock_inKhz, - .viewport_x_start = pipe_ctx->plane_res.scl_data.viewport.x, - .viewport_width = pipe_ctx->plane_res.scl_data.viewport.width, - .h_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.horz - }; if (pipe_ctx->stream != stream || (!pipe_ctx->plane_res.mi && !pipe_ctx->plane_res.hubp) || !pipe_ctx->plane_state || - (!pipe_ctx->plane_res.xfm && !pipe_ctx->plane_res.dpp)) - continue; - - if (pipe_ctx->plane_state->address.type - == PLN_ADDR_TYPE_VIDEO_PROGRESSIVE) - pos_cpy.enable = false; - - if (pipe_ctx->top_pipe && pipe_ctx->plane_state != pipe_ctx->top_pipe->plane_state) - pos_cpy.enable = false; - - - if (ipp != NULL && ipp->funcs->ipp_cursor_set_position != NULL) - ipp->funcs->ipp_cursor_set_position(ipp, &pos_cpy, ¶m); - - if (mi != NULL && mi->funcs->set_cursor_position != NULL) - mi->funcs->set_cursor_position(mi, &pos_cpy, ¶m); - - if (!hubp) + (!pipe_ctx->plane_res.xfm && !pipe_ctx->plane_res.dpp) || + !pipe_ctx->plane_res.ipp) continue; - if (hubp->funcs->set_cursor_position != NULL) - hubp->funcs->set_cursor_position(hubp, &pos_cpy, ¶m); - - if (dpp != NULL && dpp->funcs->set_cursor_position != NULL) - dpp->funcs->set_cursor_position(dpp, &pos_cpy, ¶m, hubp->curs_attr.width); - + core_dc->hwss.set_cursor_position(pipe_ctx); } - stream->cursor_position = *position; - return true; } |