OSDN Git Service

drm/amd/display: Pass init_data into DCN resource creation
[tomoyo/tomoyo-test1.git] / drivers / gpu / drm / amd / display / dc / core / dc.c
index 5fd5209..c741577 100644 (file)
@@ -384,7 +384,7 @@ 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->sink->link;
+       struct dc_link *link = stream->link;
        struct pipe_ctx *pipes = NULL;
        int i;
 
@@ -451,7 +451,7 @@ bool dc_stream_program_csc_matrix(struct dc *dc, struct dc_stream_state *stream)
                                        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;
                }
        }
@@ -524,11 +524,18 @@ void dc_link_set_preferred_link_settings(struct dc *dc,
        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;
                }
        }
@@ -539,7 +546,10 @@ void dc_link_set_preferred_link_settings(struct dc *dc,
 
        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);
 
@@ -586,9 +596,6 @@ static void destruct(struct dc *dc)
        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);
 
@@ -625,6 +632,7 @@ static bool construct(struct dc *dc,
 #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) {
@@ -670,6 +678,7 @@ static bool construct(struct dc *dc,
        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();
@@ -709,14 +718,6 @@ static bool construct(struct dc *dc,
                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);
@@ -734,11 +735,7 @@ static bool construct(struct dc *dc,
                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;
 
@@ -840,6 +837,11 @@ alloc_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);
@@ -875,8 +877,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 };
 
@@ -913,11 +916,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;
 
@@ -928,9 +931,21 @@ static void program_timing_sync(
                        }
                }
 
-               /* 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--;
@@ -942,6 +957,7 @@ static void program_timing_sync(
                                dc, group_index, group_size, pipe_set);
                        group_index++;
                }
+               num_group++;
        }
 }
 
@@ -962,6 +978,52 @@ static bool context_changed(
        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,
@@ -1007,7 +1069,13 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c
        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
@@ -1040,7 +1108,11 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c
 
        /* 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;
@@ -1065,18 +1137,27 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c
                        }
                }
 
-               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);
 
@@ -1114,6 +1195,9 @@ bool dc_post_update_surfaces_to_stream(struct dc *dc)
        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++)
@@ -1215,6 +1299,12 @@ static enum surface_update_type get_plane_info_update_type(const struct dc_surfa
                 */
                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;
@@ -1236,7 +1326,7 @@ static enum surface_update_type get_plane_info_update_type(const struct dc_surfa
                        || 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(
@@ -1436,6 +1526,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,
@@ -1459,11 +1644,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->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 ||
@@ -1492,6 +1679,7 @@ static void commit_planes_do_stream_update(struct dc *dc,
                                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);
@@ -1499,6 +1687,7 @@ static void commit_planes_do_stream_update(struct dc *dc,
                                        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) {
@@ -1526,7 +1715,16 @@ static void commit_planes_for_stream(struct dc *dc,
        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);
        }
@@ -1605,7 +1803,6 @@ void dc_commit_updates_for_stream(struct dc *dc,
                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;
@@ -1640,14 +1837,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++) {
@@ -1764,6 +1954,26 @@ void dc_resume(struct dc *dc)
                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;