diff options
Diffstat (limited to 'drivers/gpu/drm/amd/display/dc/core/dc_resource.c')
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/core/dc_resource.c | 305 |
1 files changed, 144 insertions, 161 deletions
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 2ceaab4fb5de..8f70295179ff 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -52,6 +52,9 @@ #if defined(CONFIG_DRM_AMD_DC_DCN2_0) #include "dcn20/dcn20_resource.h" #endif +#if defined(CONFIG_DRM_AMD_DC_DCN2_1) +#include "dcn21/dcn21_resource.h" +#endif #include "dce120/dce120_resource.h" #define DC_LOGGER_INIT(logger) @@ -101,6 +104,10 @@ enum dce_version resource_parse_asic_id(struct hw_asic_id asic_id) dc_version = DCN_VERSION_1_0; if (ASICREV_IS_RAVEN2(asic_id.hw_internal_rev)) dc_version = DCN_VERSION_1_01; +#if defined(CONFIG_DRM_AMD_DC_DCN2_1) + if (ASICREV_IS_RENOIR(asic_id.hw_internal_rev)) + dc_version = DCN_VERSION_2_1; +#endif break; #endif @@ -168,17 +175,20 @@ struct resource_pool *dc_create_resource_pool(struct dc *dc, res_pool = dcn20_create_resource_pool(init_data, dc); break; #endif +#if defined(CONFIG_DRM_AMD_DC_DCN2_1) + case DCN_VERSION_2_1: + res_pool = dcn21_create_resource_pool(init_data, dc); + break; +#endif default: break; } - if (res_pool != NULL) { - struct dc_firmware_info fw_info = { { 0 } }; - if (dc->ctx->dc_bios->funcs->get_firmware_info(dc->ctx->dc_bios, - &fw_info) == BP_RESULT_OK) { + if (res_pool != NULL) { + if (dc->ctx->dc_bios->fw_info_valid) { res_pool->ref_clocks.xtalin_clock_inKhz = - fw_info.pll_info.crystal_frequency; + dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency; /* initialize with firmware data first, no all * ASIC have DCCG SW component. FPGA or * simulation need initialization of @@ -265,12 +275,10 @@ bool resource_construct( DC_ERR("DC: failed to create audio!\n"); return false; } - if (!aud->funcs->endpoint_valid(aud)) { aud->funcs->destroy(&aud); break; } - pool->audios[i] = aud; pool->audio_count++; } @@ -940,7 +948,14 @@ static void calculate_inits_and_adj_vp(struct pipe_ctx *pipe_ctx) data->inits.v_c_bot = dc_fixpt_add(data->inits.v_c, data->ratios.vert_c); } +static bool are_rect_integer_multiples(struct rect src, struct rect dest) +{ + if (dest.width >= src.width && dest.width % src.width == 0 && + dest.height >= src.height && dest.height % src.height == 0) + return true; + return false; +} bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx) { const struct dc_plane_state *plane_state = pipe_ctx->plane_state; @@ -983,6 +998,15 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx) if (pipe_ctx->plane_res.dpp != NULL) res = pipe_ctx->plane_res.dpp->funcs->dpp_get_optimal_number_of_taps( pipe_ctx->plane_res.dpp, &pipe_ctx->plane_res.scl_data, &plane_state->scaling_quality); + + if (res && + plane_state->scaling_quality.integer_scaling && + are_rect_integer_multiples(pipe_ctx->plane_res.scl_data.viewport, + pipe_ctx->plane_res.scl_data.recout)) { + pipe_ctx->plane_res.scl_data.taps.v_taps = 1; + pipe_ctx->plane_res.scl_data.taps.h_taps = 1; + } + if (!res) { /* Try 24 bpp linebuffer */ pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_24BPP; @@ -1103,25 +1127,21 @@ struct pipe_ctx *resource_get_head_pipe_for_stream( struct dc_stream_state *stream) { int i; + for (i = 0; i < MAX_PIPES; i++) { - if (res_ctx->pipe_ctx[i].stream == stream && - !res_ctx->pipe_ctx[i].top_pipe) { + if (res_ctx->pipe_ctx[i].stream == stream + && !res_ctx->pipe_ctx[i].top_pipe + && !res_ctx->pipe_ctx[i].prev_odm_pipe) return &res_ctx->pipe_ctx[i]; - break; - } } return NULL; } -static struct pipe_ctx *resource_get_tail_pipe_for_stream( +static struct pipe_ctx *resource_get_tail_pipe( struct resource_context *res_ctx, - struct dc_stream_state *stream) + struct pipe_ctx *head_pipe) { - struct pipe_ctx *head_pipe, *tail_pipe; - head_pipe = resource_get_head_pipe_for_stream(res_ctx, stream); - - if (!head_pipe) - return NULL; + struct pipe_ctx *tail_pipe; tail_pipe = head_pipe->bottom_pipe; @@ -1137,31 +1157,20 @@ static struct pipe_ctx *resource_get_tail_pipe_for_stream( * A free_pipe for a stream is defined here as a pipe * that has no surface attached yet */ -static struct pipe_ctx *acquire_free_pipe_for_stream( +static struct pipe_ctx *acquire_free_pipe_for_head( struct dc_state *context, const struct resource_pool *pool, - struct dc_stream_state *stream) + struct pipe_ctx *head_pipe) { int i; struct resource_context *res_ctx = &context->res_ctx; - struct pipe_ctx *head_pipe = NULL; - - /* Find head pipe, which has the back end set up*/ - - head_pipe = resource_get_head_pipe_for_stream(res_ctx, stream); - - if (!head_pipe) { - ASSERT(0); - return NULL; - } - if (!head_pipe->plane_state) return head_pipe; /* Re-use pipe already acquired for this stream if available*/ for (i = pool->pipe_count - 1; i >= 0; i--) { - if (res_ctx->pipe_ctx[i].stream == stream && + if (res_ctx->pipe_ctx[i].stream == head_pipe->stream && !res_ctx->pipe_ctx[i].plane_state) { return &res_ctx->pipe_ctx[i]; } @@ -1175,8 +1184,7 @@ static struct pipe_ctx *acquire_free_pipe_for_stream( if (!pool->funcs->acquire_idle_pipe_for_layer) return NULL; - return pool->funcs->acquire_idle_pipe_for_layer(context, pool, stream); - + return pool->funcs->acquire_idle_pipe_for_layer(context, pool, head_pipe->stream); } #if defined(CONFIG_DRM_AMD_DC_DCN1_0) @@ -1190,7 +1198,7 @@ static int acquire_first_split_pipe( for (i = 0; i < pool->pipe_count; i++) { struct pipe_ctx *split_pipe = &res_ctx->pipe_ctx[i]; - if (split_pipe->top_pipe && !dc_res_is_odm_head_pipe(split_pipe) && + if (split_pipe->top_pipe && split_pipe->top_pipe->plane_state == split_pipe->plane_state) { split_pipe->top_pipe->bottom_pipe = split_pipe->bottom_pipe; if (split_pipe->bottom_pipe) @@ -1251,39 +1259,41 @@ bool dc_add_plane_to_context( return false; } - tail_pipe = resource_get_tail_pipe_for_stream(&context->res_ctx, stream); - ASSERT(tail_pipe); + /* retain new surface, but only once per stream */ + dc_plane_state_retain(plane_state); - free_pipe = acquire_free_pipe_for_stream(context, pool, stream); + while (head_pipe) { + tail_pipe = resource_get_tail_pipe(&context->res_ctx, head_pipe); + ASSERT(tail_pipe); -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) - if (!free_pipe) { - int pipe_idx = acquire_first_split_pipe(&context->res_ctx, pool, stream); - if (pipe_idx >= 0) - free_pipe = &context->res_ctx.pipe_ctx[pipe_idx]; - } -#endif - if (!free_pipe) - return false; + free_pipe = acquire_free_pipe_for_head(context, pool, head_pipe); - /* retain new surfaces */ - dc_plane_state_retain(plane_state); - free_pipe->plane_state = plane_state; - - if (head_pipe != free_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; - free_pipe->clock_source = tail_pipe->clock_source; - free_pipe->top_pipe = tail_pipe; - tail_pipe->bottom_pipe = free_pipe; - } else if (free_pipe->bottom_pipe && free_pipe->bottom_pipe->plane_state == NULL) { - ASSERT(free_pipe->bottom_pipe->stream_res.opp != free_pipe->stream_res.opp); - free_pipe->bottom_pipe->plane_state = plane_state; - } + #if defined(CONFIG_DRM_AMD_DC_DCN1_0) + if (!free_pipe) { + int pipe_idx = acquire_first_split_pipe(&context->res_ctx, pool, stream); + if (pipe_idx >= 0) + free_pipe = &context->res_ctx.pipe_ctx[pipe_idx]; + } + #endif + if (!free_pipe) { + dc_plane_state_release(plane_state); + return false; + } + free_pipe->plane_state = plane_state; + + if (head_pipe != free_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; + free_pipe->clock_source = tail_pipe->clock_source; + free_pipe->top_pipe = tail_pipe; + tail_pipe->bottom_pipe = free_pipe; + } + head_pipe = head_pipe->next_odm_pipe; + } /* assign new surfaces*/ stream_status->plane_states[stream_status->plane_count] = plane_state; @@ -1292,35 +1302,6 @@ bool dc_add_plane_to_context( return true; } -struct pipe_ctx *dc_res_get_odm_bottom_pipe(struct pipe_ctx *pipe_ctx) -{ - struct pipe_ctx *bottom_pipe = pipe_ctx->bottom_pipe; - - /* ODM should only be updated once per otg */ - if (pipe_ctx->top_pipe) - return NULL; - - while (bottom_pipe) { - if (bottom_pipe->stream_res.opp != pipe_ctx->stream_res.opp) - break; - bottom_pipe = bottom_pipe->bottom_pipe; - } - - return bottom_pipe; -} - -bool dc_res_is_odm_head_pipe(struct pipe_ctx *pipe_ctx) -{ - struct pipe_ctx *top_pipe = pipe_ctx->top_pipe; - - if (!top_pipe) - return false; - if (top_pipe && top_pipe->stream_res.opp == pipe_ctx->stream_res.opp) - return false; - - return true; -} - bool dc_remove_plane_from_context( const struct dc *dc, struct dc_stream_state *stream, @@ -1347,12 +1328,6 @@ bool dc_remove_plane_from_context( struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; if (pipe_ctx->plane_state == plane_state) { - if (dc_res_is_odm_head_pipe(pipe_ctx)) { - pipe_ctx->plane_state = NULL; - pipe_ctx->bottom_pipe = NULL; - continue; - } - if (pipe_ctx->top_pipe) pipe_ctx->top_pipe->bottom_pipe = pipe_ctx->bottom_pipe; @@ -1367,13 +1342,10 @@ bool dc_remove_plane_from_context( * For head pipe detach surfaces from pipe for tail * pipe just zero it out */ - if (!pipe_ctx->top_pipe) { + if (!pipe_ctx->top_pipe) pipe_ctx->plane_state = NULL; - if (!dc_res_get_odm_bottom_pipe(pipe_ctx)) - pipe_ctx->bottom_pipe = NULL; - } else { + else memset(pipe_ctx, 0, sizeof(*pipe_ctx)); - } } } @@ -1659,24 +1631,25 @@ static struct audio *find_first_free_audio( const struct resource_pool *pool, enum engine_id id) { - int i; - for (i = 0; i < pool->audio_count; i++) { + int i, available_audio_count; + + available_audio_count = pool->audio_count; + + for (i = 0; i < available_audio_count; i++) { if ((res_ctx->is_audio_acquired[i] == false) && (res_ctx->is_stream_enc_acquired[i] == true)) { /*we have enough audio endpoint, find the matching inst*/ if (id != i) continue; - return pool->audios[i]; } } - /* use engine id to find free audio */ - if ((id < pool->audio_count) && (res_ctx->is_audio_acquired[id] == false)) { + /* use engine id to find free audio */ + if ((id < available_audio_count) && (res_ctx->is_audio_acquired[id] == false)) { return pool->audios[id]; } - /*not found the matching one, first come first serve*/ - for (i = 0; i < pool->audio_count; i++) { + for (i = 0; i < available_audio_count; i++) { if (res_ctx->is_audio_acquired[i] == false) { return pool->audios[i]; } @@ -1736,50 +1709,45 @@ enum dc_status dc_remove_stream_from_ctx( { int i; struct dc_context *dc_ctx = dc->ctx; - struct pipe_ctx *del_pipe = NULL; + struct pipe_ctx *del_pipe = resource_get_head_pipe_for_stream(&new_ctx->res_ctx, stream); + struct pipe_ctx *odm_pipe; - /* Release primary pipe */ - for (i = 0; i < MAX_PIPES; i++) { - if (new_ctx->res_ctx.pipe_ctx[i].stream == stream && - !new_ctx->res_ctx.pipe_ctx[i].top_pipe) { - struct pipe_ctx *odm_pipe = - dc_res_get_odm_bottom_pipe(&new_ctx->res_ctx.pipe_ctx[i]); + if (!del_pipe) { + DC_ERROR("Pipe not found for stream %p !\n", stream); + return DC_ERROR_UNEXPECTED; + } - del_pipe = &new_ctx->res_ctx.pipe_ctx[i]; + odm_pipe = del_pipe->next_odm_pipe; - ASSERT(del_pipe->stream_res.stream_enc); - update_stream_engine_usage( - &new_ctx->res_ctx, - dc->res_pool, - del_pipe->stream_res.stream_enc, - false); + /* Release primary pipe */ + ASSERT(del_pipe->stream_res.stream_enc); + update_stream_engine_usage( + &new_ctx->res_ctx, + dc->res_pool, + del_pipe->stream_res.stream_enc, + false); - if (del_pipe->stream_res.audio) - update_audio_usage( - &new_ctx->res_ctx, - dc->res_pool, - del_pipe->stream_res.audio, - false); + if (del_pipe->stream_res.audio) + update_audio_usage( + &new_ctx->res_ctx, + dc->res_pool, + del_pipe->stream_res.audio, + false); - resource_unreference_clock_source(&new_ctx->res_ctx, - dc->res_pool, - del_pipe->clock_source); + resource_unreference_clock_source(&new_ctx->res_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); + 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)); - if (odm_pipe) - memset(odm_pipe, 0, sizeof(*odm_pipe)); + while (odm_pipe) { + struct pipe_ctx *next_odm_pipe = odm_pipe->next_odm_pipe; - break; - } - } - - if (!del_pipe) { - DC_ERROR("Pipe not found for stream %p !\n", stream); - return DC_ERROR_UNEXPECTED; + memset(odm_pipe, 0, sizeof(*odm_pipe)); + odm_pipe = next_odm_pipe; } + memset(del_pipe, 0, sizeof(*del_pipe)); for (i = 0; i < new_ctx->stream_count; i++) if (new_ctx->streams[i] == stream) @@ -1880,7 +1848,7 @@ static int acquire_resource_from_hw_enabled_state( struct dc_stream_state *stream) { struct dc_link *link = stream->link; - unsigned int inst; + unsigned int inst, tg_inst; /* Check for enabled DIG to identify enabled display */ if (!link->link_enc->funcs->is_dig_enabled(link->link_enc)) @@ -1892,28 +1860,37 @@ static int acquire_resource_from_hw_enabled_state( * 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; + inst = link->link_enc->funcs->get_dig_frontend(link->link_enc); /* Instance should be within the range of the pool */ if (inst >= pool->pipe_count) return -1; - if (!res_ctx->pipe_ctx[inst].stream) { - struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[inst]; + if (inst >= pool->stream_enc_count) + return -1; + + tg_inst = pool->stream_enc[inst]->funcs->dig_source_otg(pool->stream_enc[inst]); - pipe_ctx->stream_res.tg = pool->timing_generators[inst]; - pipe_ctx->plane_res.mi = pool->mis[inst]; - pipe_ctx->plane_res.hubp = pool->hubps[inst]; - pipe_ctx->plane_res.ipp = pool->ipps[inst]; - pipe_ctx->plane_res.xfm = pool->transforms[inst]; - pipe_ctx->plane_res.dpp = pool->dpps[inst]; - pipe_ctx->stream_res.opp = pool->opps[inst]; - if (pool->dpps[inst]) - pipe_ctx->plane_res.mpcc_inst = pool->dpps[inst]->inst; - pipe_ctx->pipe_idx = inst; + if (tg_inst >= pool->timing_generator_count) + return false; + + if (!res_ctx->pipe_ctx[tg_inst].stream) { + struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[tg_inst]; + + pipe_ctx->stream_res.tg = pool->timing_generators[tg_inst]; + pipe_ctx->plane_res.mi = pool->mis[tg_inst]; + pipe_ctx->plane_res.hubp = pool->hubps[tg_inst]; + pipe_ctx->plane_res.ipp = pool->ipps[tg_inst]; + pipe_ctx->plane_res.xfm = pool->transforms[tg_inst]; + pipe_ctx->plane_res.dpp = pool->dpps[tg_inst]; + pipe_ctx->stream_res.opp = pool->opps[tg_inst]; + + if (pool->dpps[tg_inst]) + pipe_ctx->plane_res.mpcc_inst = pool->dpps[tg_inst]->inst; + pipe_ctx->pipe_idx = tg_inst; pipe_ctx->stream = stream; - return inst; + return tg_inst; } return -1; @@ -2475,6 +2452,12 @@ void dc_resource_state_copy_construct( if (cur_pipe->bottom_pipe) cur_pipe->bottom_pipe = &dst_ctx->res_ctx.pipe_ctx[cur_pipe->bottom_pipe->pipe_idx]; + + if (cur_pipe->next_odm_pipe) + cur_pipe->next_odm_pipe = &dst_ctx->res_ctx.pipe_ctx[cur_pipe->next_odm_pipe->pipe_idx]; + + if (cur_pipe->prev_odm_pipe) + cur_pipe->prev_odm_pipe = &dst_ctx->res_ctx.pipe_ctx[cur_pipe->prev_odm_pipe->pipe_idx]; } for (i = 0; i < dst_ctx->stream_count; i++) { |