enum dc_dither_option option)
{
struct bit_depth_reduction_params params;
- struct dc_link *link = stream->sink->link;
+ struct dc_link *link = stream->link;
struct pipe_ctx *pipes = NULL;
int i;
pipes,
stream->output_color_space,
stream->csc_color_matrix.matrix,
- pipes->plane_res.hubp->opp_id);
+ pipes->plane_res.hubp ? pipes->plane_res.hubp->opp_id : 0);
ret = true;
}
}
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->sink
- && pipe->stream->sink->link) {
- if (pipe->stream->sink->link == link)
+ if (pipe->stream && pipe->stream->link) {
+ if (pipe->stream->link == link)
break;
}
}
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);
if (dc->ctx->gpio_service)
dal_gpio_service_destroy(&dc->ctx->gpio_service);
- if (dc->ctx->i2caux)
- dal_i2caux_destroy(&dc->ctx->i2caux);
-
if (dc->ctx->created_bios)
dal_bios_parser_destroy(&dc->ctx->dc_bios);
#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) {
dc_ctx->dc = dc;
dc_ctx->asic_id = init_params->asic_id;
dc_ctx->dc_sink_id_count = 0;
+ dc_ctx->dc_stream_id_count = 0;
dc->ctx = dc_ctx;
dc->current_state = dc_create_state();
dc_ctx->created_bios = true;
}
- /* Create I2C AUX */
- dc_ctx->i2caux = dal_i2caux_create(dc_ctx);
-
- if (!dc_ctx->i2caux) {
- ASSERT_CRITICAL(false);
- goto fail;
- }
-
dc_ctx->perf_trace = dc_perf_trace_create();
if (!dc_ctx->perf_trace) {
ASSERT_CRITICAL(false);
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 NULL;
}
+void dc_init_callbacks(struct dc *dc,
+ const struct dc_callback_init *init_params)
+{
+}
+
void dc_destroy(struct dc **dc)
{
destruct(*dc);
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 };
}
}
- /* 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;
}
}
- /* remove any other unblanked pipes as they have already been synced */
+
+ 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]->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--;
dc, group_index, group_size, pipe_set);
group_index++;
}
+ num_group++;
}
}
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
/* Program all planes within new context*/
for (i = 0; i < context->stream_count; i++) {
- const struct dc_sink *sink = context->streams[i]->sink;
+ 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;
}
}
- CONN_MSG_MODE(sink->link, "{%dx%d, %dx%d@%dKhz}",
+ status = dc_stream_get_status_from_state(context, context->streams[i]);
+ context->streams[i]->out.otg_offset = status->primary_otg_inst;
+
+ CONN_MSG_MODE(link, "{%dx%d, %dx%d@%dKhz}",
context->streams[i]->timing.h_addressable,
context->streams[i]->timing.v_addressable,
context->streams[i]->timing.h_total,
context->streams[i]->timing.v_total,
- context->streams[i]->timing.pix_clk_khz);
+ context->streams[i]->timing.pix_clk_100hz / 10);
}
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++)
*/
update_flags->bits.bpp_change = 1;
+ if (u->plane_info->plane_size.grph.surface_pitch != u->surface->plane_size.grph.surface_pitch
+ || u->plane_info->plane_size.video.luma_pitch != u->surface->plane_size.video.luma_pitch
+ || u->plane_info->plane_size.video.chroma_pitch != u->surface->plane_size.video.chroma_pitch)
+ update_flags->bits.plane_size_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;
|| update_flags->bits.output_tf_change)
return UPDATE_TYPE_FULL;
- return UPDATE_TYPE_MED;
+ return update_flags->raw ? UPDATE_TYPE_MED : UPDATE_TYPE_FAST;
}
static enum surface_update_type get_scaling_info_update_type(
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,
stream_update->adjust->v_total_min,
stream_update->adjust->v_total_max);
- if (stream_update->periodic_fn_vsync_delta &&
- 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,
- pipe_ctx->stream->periodic_fn_vsync_delta);
+ if (stream_update->periodic_interrupt0 &&
+ dc->hwss.setup_periodic_interrupt)
+ dc->hwss.setup_periodic_interrupt(pipe_ctx, VLINE0);
+
+ 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);
}
int surface_count,
struct dc_stream_state *stream,
struct dc_stream_update *stream_update,
- struct dc_plane_state **plane_states,
struct dc_state *state)
{
const struct dc_stream_status *stream_status;
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++) {
core_link_resume(dc->links[i]);
}
+unsigned int dc_get_current_backlight_pwm(struct dc *dc)
+{
+ struct abm *abm = dc->res_pool->abm;
+
+ if (abm)
+ return abm->funcs->get_current_backlight(abm);
+
+ return 0;
+}
+
+unsigned int dc_get_target_backlight_pwm(struct dc *dc)
+{
+ struct abm *abm = dc->res_pool->abm;
+
+ if (abm)
+ return abm->funcs->get_target_backlight(abm);
+
+ return 0;
+}
+
bool dc_is_dmcu_initialized(struct dc *dc)
{
struct dmcu *dmcu = dc->res_pool->dmcu;