struct dc_stream_state *link_stream;
struct dc_link_settings store_settings = *link_setting;
+ link->preferred_link_setting = store_settings;
+
+ /* Retrain with preferred link settings only relevant for
+ * DP signal type
+ */
+ if (!dc_is_dp_signal(link->connector_signal))
+ return;
+
for (i = 0; i < MAX_PIPES; i++) {
pipe = &dc->current_state->res_ctx.pipe_ctx[i];
if (pipe->stream && pipe->stream->link) {
link_stream = link->dc->current_state->res_ctx.pipe_ctx[i].stream;
- link->preferred_link_setting = store_settings;
+ /* Cannot retrain link if backend is off */
+ if (link_stream->dpms_off)
+ return;
+
if (link_stream)
decide_link_settings(link_stream, &store_settings);
#endif
enum dce_version dc_version = DCE_VERSION_UNKNOWN;
+ memcpy(&dc->bb_overrides, &init_params->bb_overrides, sizeof(dc->bb_overrides));
dc_dceip = kzalloc(sizeof(*dc_dceip), GFP_KERNEL);
if (!dc_dceip) {
goto fail;
}
- dc->res_pool = dc_create_resource_pool(
- dc,
- init_params->num_virtual_links,
- dc_version,
- init_params->asic_id);
+ dc->res_pool = dc_create_resource_pool(dc, init_params, dc_version);
if (!dc->res_pool)
goto fail;
return false;
}
+bool dc_validate_seamless_boot_timing(const 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,
if (!dcb->funcs->is_accelerated_mode(dcb))
dc->hwss.enable_accelerated_mode(dc, context);
- dc->hwss.prepare_bandwidth(dc, context);
+ for (i = 0; i < context->stream_count; i++) {
+ if (context->streams[i]->apply_seamless_boot_optimization)
+ dc->optimize_seamless_boot = true;
+ }
+
+ if (!dc->optimize_seamless_boot)
+ dc->hwss.prepare_bandwidth(dc, context);
/* re-program planes for existing stream, in case we need to
* free up plane resource for later use
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;
dc_enable_stereo(dc, context, dc_streams, context->stream_count);
- /* pplib is notified if disp_num changed */
- dc->hwss.optimize_bandwidth(dc, context);
+ if (!dc->optimize_seamless_boot)
+ /* pplib is notified if disp_num changed */
+ dc->hwss.optimize_bandwidth(dc, context);
+
+ for (i = 0; i < context->stream_count; i++)
+ context->streams[i]->mode_changed = false;
+
+ memset(&context->commit_hints, 0, sizeof(context->commit_hints));
dc_release_state(dc->current_state);
int i;
struct dc_state *context = dc->current_state;
+ if (!dc->optimized_required || dc->optimize_seamless_boot)
+ return true;
+
post_surface_trace(dc);
for (i = 0; i < dc->res_pool->pipe_count; i++)
stream_update->adjust->v_total_min,
stream_update->adjust->v_total_max);
- 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, &pipe_ctx->stream->timing, VLINE0, &stream->periodic_vsync_config);
+ if (stream_update->periodic_interrupt0 &&
+ dc->hwss.setup_periodic_interrupt)
+ dc->hwss.setup_periodic_interrupt(pipe_ctx, VLINE0);
- 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, &pipe_ctx->stream->timing, VLINE1, &stream->enhanced_sync_config);
+ if (stream_update->periodic_interrupt1 &&
+ dc->hwss.setup_periodic_interrupt)
+ dc->hwss.setup_periodic_interrupt(pipe_ctx, VLINE1);
if ((stream_update->hdr_static_metadata && !stream->use_dynamic_meta) ||
stream_update->vrr_infopacket ||
continue;
if (stream_update->dpms_off) {
+ dc->hwss.pipe_control_lock(dc, pipe_ctx, true);
if (*stream_update->dpms_off) {
core_link_disable_stream(pipe_ctx, KEEP_ACQUIRED_RESOURCE);
dc->hwss.optimize_bandwidth(dc, dc->current_state);
dc->hwss.prepare_bandwidth(dc, dc->current_state);
core_link_enable_stream(dc->current_state, pipe_ctx);
}
+ dc->hwss.pipe_control_lock(dc, pipe_ctx, false);
}
if (stream_update->abm_level && pipe_ctx->stream_res.abm) {
int i, j;
struct pipe_ctx *top_pipe_to_program = NULL;
- if (update_type == UPDATE_TYPE_FULL) {
+ if (dc->optimize_seamless_boot && surface_count > 0) {
+ /* Optimize seamless boot flag keeps clocks and watermarks high until
+ * first flip. After first flip, optimization is required to lower
+ * bandwidth.
+ */
+ dc->optimize_seamless_boot = false;
+ dc->optimized_required = true;
+ }
+
+ if (update_type == UPDATE_TYPE_FULL && !dc->optimize_seamless_boot) {
dc->hwss.prepare_bandwidth(dc, context);
context_clock_trace(dc, context);
}