| /* |
| * Copyright 2020 Mauro Rossi <issor.oruam@gmail.com> |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a |
| * copy of this software and associated documentation files (the "Software"), |
| * to deal in the Software without restriction, including without limitation |
| * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| * and/or sell copies of the Software, and to permit persons to whom the |
| * Software is furnished to do so, subject to the following conditions: |
| * |
| * The above copyright notice and this permission notice shall be included in |
| * all copies or substantial portions of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
| * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
| * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
| * OTHER DEALINGS IN THE SOFTWARE. |
| * |
| * Authors: AMD |
| * |
| */ |
| |
| #include "dm_services.h" |
| #include "dc.h" |
| #include "core_types.h" |
| #include "dce60_hw_sequencer.h" |
| |
| #include "dce/dce_hwseq.h" |
| #include "dce110/dce110_hwseq.h" |
| #include "dce100/dce100_hwseq.h" |
| |
| /* include DCE6 register header files */ |
| #include "dce/dce_6_0_d.h" |
| #include "dce/dce_6_0_sh_mask.h" |
| |
| #define DC_LOGGER_INIT() |
| |
| /******************************************************************************* |
| * Private definitions |
| ******************************************************************************/ |
| |
| /***************************PIPE_CONTROL***********************************/ |
| |
| /* |
| * Check if FBC can be enabled |
| */ |
| static bool dce60_should_enable_fbc(struct dc *dc, |
| struct dc_state *context, |
| uint32_t *pipe_idx) |
| { |
| uint32_t i; |
| struct pipe_ctx *pipe_ctx = NULL; |
| struct resource_context *res_ctx = &context->res_ctx; |
| unsigned int underlay_idx = dc->res_pool->underlay_pipe_index; |
| |
| |
| ASSERT(dc->fbc_compressor); |
| |
| /* FBC memory should be allocated */ |
| if (!dc->ctx->fbc_gpu_addr) |
| return false; |
| |
| /* Only supports single display */ |
| if (context->stream_count != 1) |
| return false; |
| |
| for (i = 0; i < dc->res_pool->pipe_count; i++) { |
| if (res_ctx->pipe_ctx[i].stream) { |
| |
| pipe_ctx = &res_ctx->pipe_ctx[i]; |
| |
| if (!pipe_ctx) |
| continue; |
| |
| /* fbc not applicable on underlay pipe */ |
| if (pipe_ctx->pipe_idx != underlay_idx) { |
| *pipe_idx = i; |
| break; |
| } |
| } |
| } |
| |
| if (i == dc->res_pool->pipe_count) |
| return false; |
| |
| if (!pipe_ctx->stream->link) |
| return false; |
| |
| /* Only supports eDP */ |
| if (pipe_ctx->stream->link->connector_signal != SIGNAL_TYPE_EDP) |
| return false; |
| |
| /* PSR should not be enabled */ |
| if (pipe_ctx->stream->link->psr_settings.psr_feature_enabled) |
| return false; |
| |
| /* Nothing to compress */ |
| if (!pipe_ctx->plane_state) |
| return false; |
| |
| /* Only for non-linear tiling */ |
| if (pipe_ctx->plane_state->tiling_info.gfx8.array_mode == DC_ARRAY_LINEAR_GENERAL) |
| return false; |
| |
| return true; |
| } |
| |
| /* |
| * Enable FBC |
| */ |
| static void dce60_enable_fbc( |
| struct dc *dc, |
| struct dc_state *context) |
| { |
| uint32_t pipe_idx = 0; |
| |
| if (dce60_should_enable_fbc(dc, context, &pipe_idx)) { |
| /* Program GRPH COMPRESSED ADDRESS and PITCH */ |
| struct compr_addr_and_pitch_params params = {0, 0, 0}; |
| struct compressor *compr = dc->fbc_compressor; |
| struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[pipe_idx]; |
| |
| params.source_view_width = pipe_ctx->stream->timing.h_addressable; |
| params.source_view_height = pipe_ctx->stream->timing.v_addressable; |
| params.inst = pipe_ctx->stream_res.tg->inst; |
| compr->compr_surface_address.quad_part = dc->ctx->fbc_gpu_addr; |
| |
| compr->funcs->surface_address_and_pitch(compr, ¶ms); |
| compr->funcs->set_fbc_invalidation_triggers(compr, 1); |
| |
| compr->funcs->enable_fbc(compr, ¶ms); |
| } |
| } |
| |
| |
| /******************************************************************************* |
| * Front End programming |
| ******************************************************************************/ |
| |
| static void dce60_set_default_colors(struct pipe_ctx *pipe_ctx) |
| { |
| struct default_adjustment default_adjust = { 0 }; |
| |
| default_adjust.force_hw_default = false; |
| default_adjust.in_color_space = pipe_ctx->plane_state->color_space; |
| default_adjust.out_color_space = pipe_ctx->stream->output_color_space; |
| default_adjust.csc_adjust_type = GRAPHICS_CSC_ADJUST_TYPE_SW; |
| default_adjust.surface_pixel_format = pipe_ctx->plane_res.scl_data.format; |
| |
| /* display color depth */ |
| default_adjust.color_depth = |
| pipe_ctx->stream->timing.display_color_depth; |
| |
| /* Lb color depth */ |
| default_adjust.lb_color_depth = pipe_ctx->plane_res.scl_data.lb_params.depth; |
| |
| pipe_ctx->plane_res.xfm->funcs->opp_set_csc_default( |
| pipe_ctx->plane_res.xfm, &default_adjust); |
| } |
| |
| /******************************************************************************* |
| * In order to turn on surface we will program |
| * CRTC |
| * |
| * DCE6 has no bottom_pipe and no Blender HW |
| * We need to set 'blank_target' to false in order to turn on the display |
| * |
| * |-----------|------------|---------| |
| * |curr pipe | set_blank | | |
| * |Surface |blank_target| CRCT | |
| * |visibility | argument | | |
| * |-----------|------------|---------| |
| * | off | true | blank | |
| * | on | false | unblank | |
| * |-----------|------------|---------| |
| * |
| ******************************************************************************/ |
| static void dce60_program_surface_visibility(const struct dc *dc, |
| struct pipe_ctx *pipe_ctx) |
| { |
| bool blank_target = false; |
| |
| /* DCE6 has no bottom_pipe and no Blender HW */ |
| |
| if (!pipe_ctx->plane_state->visible) |
| blank_target = true; |
| |
| /* DCE6 skip dce_set_blender_mode() but then proceed to 'unblank' CRTC */ |
| pipe_ctx->stream_res.tg->funcs->set_blank(pipe_ctx->stream_res.tg, blank_target); |
| |
| } |
| |
| |
| static void dce60_get_surface_visual_confirm_color(const struct pipe_ctx *pipe_ctx, |
| struct tg_color *color) |
| { |
| uint32_t color_value = MAX_TG_COLOR_VALUE * (4 - pipe_ctx->stream_res.tg->inst) / 4; |
| |
| switch (pipe_ctx->plane_res.scl_data.format) { |
| case PIXEL_FORMAT_ARGB8888: |
| /* set boarder color to red */ |
| color->color_r_cr = color_value; |
| break; |
| |
| case PIXEL_FORMAT_ARGB2101010: |
| /* set boarder color to blue */ |
| color->color_b_cb = color_value; |
| break; |
| case PIXEL_FORMAT_420BPP8: |
| /* set boarder color to green */ |
| color->color_g_y = color_value; |
| break; |
| case PIXEL_FORMAT_420BPP10: |
| /* set boarder color to yellow */ |
| color->color_g_y = color_value; |
| color->color_r_cr = color_value; |
| break; |
| case PIXEL_FORMAT_FP16: |
| /* set boarder color to white */ |
| color->color_r_cr = color_value; |
| color->color_b_cb = color_value; |
| color->color_g_y = color_value; |
| break; |
| default: |
| break; |
| } |
| } |
| |
| static void dce60_program_scaler(const struct dc *dc, |
| const struct pipe_ctx *pipe_ctx) |
| { |
| struct tg_color color = {0}; |
| |
| /* DCE6 skips DCN TOFPGA check for transform_set_pixel_storage_depth == NULL */ |
| |
| if (dc->debug.visual_confirm == VISUAL_CONFIRM_SURFACE) |
| dce60_get_surface_visual_confirm_color(pipe_ctx, &color); |
| else |
| color_space_to_black_color(dc, |
| pipe_ctx->stream->output_color_space, |
| &color); |
| |
| pipe_ctx->plane_res.xfm->funcs->transform_set_pixel_storage_depth( |
| pipe_ctx->plane_res.xfm, |
| pipe_ctx->plane_res.scl_data.lb_params.depth, |
| &pipe_ctx->stream->bit_depth_params); |
| |
| if (pipe_ctx->stream_res.tg->funcs->set_overscan_blank_color) { |
| /* |
| * The way 420 is packed, 2 channels carry Y component, 1 channel |
| * alternate between Cb and Cr, so both channels need the pixel |
| * value for Y |
| */ |
| if (pipe_ctx->stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR420) |
| color.color_r_cr = color.color_g_y; |
| |
| pipe_ctx->stream_res.tg->funcs->set_overscan_blank_color( |
| pipe_ctx->stream_res.tg, |
| &color); |
| } |
| |
| pipe_ctx->plane_res.xfm->funcs->transform_set_scaler(pipe_ctx->plane_res.xfm, |
| &pipe_ctx->plane_res.scl_data); |
| } |
| |
| static void |
| dce60_program_front_end_for_pipe( |
| struct dc *dc, struct pipe_ctx *pipe_ctx) |
| { |
| struct mem_input *mi = pipe_ctx->plane_res.mi; |
| struct dc_plane_state *plane_state = pipe_ctx->plane_state; |
| struct xfm_grph_csc_adjustment adjust; |
| struct out_csc_color_matrix tbl_entry; |
| unsigned int i; |
| struct dce_hwseq *hws = dc->hwseq; |
| |
| DC_LOGGER_INIT(); |
| memset(&tbl_entry, 0, sizeof(tbl_entry)); |
| |
| memset(&adjust, 0, sizeof(adjust)); |
| adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS; |
| |
| dce_enable_fe_clock(dc->hwseq, mi->inst, true); |
| |
| dce60_set_default_colors(pipe_ctx); |
| if (pipe_ctx->stream->csc_color_matrix.enable_adjustment |
| == true) { |
| tbl_entry.color_space = |
| pipe_ctx->stream->output_color_space; |
| |
| for (i = 0; i < 12; i++) |
| tbl_entry.regval[i] = |
| pipe_ctx->stream->csc_color_matrix.matrix[i]; |
| |
| pipe_ctx->plane_res.xfm->funcs->opp_set_csc_adjustment |
| (pipe_ctx->plane_res.xfm, &tbl_entry); |
| } |
| |
| if (pipe_ctx->stream->gamut_remap_matrix.enable_remap == true) { |
| adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW; |
| |
| for (i = 0; i < CSC_TEMPERATURE_MATRIX_SIZE; i++) |
| adjust.temperature_matrix[i] = |
| pipe_ctx->stream->gamut_remap_matrix.matrix[i]; |
| } |
| |
| pipe_ctx->plane_res.xfm->funcs->transform_set_gamut_remap(pipe_ctx->plane_res.xfm, &adjust); |
| |
| pipe_ctx->plane_res.scl_data.lb_params.alpha_en = pipe_ctx->bottom_pipe != 0; |
| |
| dce60_program_scaler(dc, pipe_ctx); |
| |
| mi->funcs->mem_input_program_surface_config( |
| mi, |
| plane_state->format, |
| &plane_state->tiling_info, |
| &plane_state->plane_size, |
| plane_state->rotation, |
| NULL, |
| false); |
| if (mi->funcs->set_blank) |
| mi->funcs->set_blank(mi, pipe_ctx->plane_state->visible); |
| |
| if (dc->config.gpu_vm_support) |
| mi->funcs->mem_input_program_pte_vm( |
| pipe_ctx->plane_res.mi, |
| plane_state->format, |
| &plane_state->tiling_info, |
| plane_state->rotation); |
| |
| /* Moved programming gamma from dc to hwss */ |
| if (pipe_ctx->plane_state->update_flags.bits.full_update || |
| pipe_ctx->plane_state->update_flags.bits.in_transfer_func_change || |
| pipe_ctx->plane_state->update_flags.bits.gamma_change) |
| hws->funcs.set_input_transfer_func(dc, pipe_ctx, pipe_ctx->plane_state); |
| |
| if (pipe_ctx->plane_state->update_flags.bits.full_update) |
| hws->funcs.set_output_transfer_func(dc, pipe_ctx, pipe_ctx->stream); |
| |
| DC_LOG_SURFACE( |
| "Pipe:%d %p: addr hi:0x%x, " |
| "addr low:0x%x, " |
| "src: %d, %d, %d," |
| " %d; dst: %d, %d, %d, %d;" |
| "clip: %d, %d, %d, %d\n", |
| pipe_ctx->pipe_idx, |
| (void *) pipe_ctx->plane_state, |
| pipe_ctx->plane_state->address.grph.addr.high_part, |
| pipe_ctx->plane_state->address.grph.addr.low_part, |
| pipe_ctx->plane_state->src_rect.x, |
| pipe_ctx->plane_state->src_rect.y, |
| pipe_ctx->plane_state->src_rect.width, |
| pipe_ctx->plane_state->src_rect.height, |
| pipe_ctx->plane_state->dst_rect.x, |
| pipe_ctx->plane_state->dst_rect.y, |
| pipe_ctx->plane_state->dst_rect.width, |
| pipe_ctx->plane_state->dst_rect.height, |
| pipe_ctx->plane_state->clip_rect.x, |
| pipe_ctx->plane_state->clip_rect.y, |
| pipe_ctx->plane_state->clip_rect.width, |
| pipe_ctx->plane_state->clip_rect.height); |
| |
| DC_LOG_SURFACE( |
| "Pipe %d: width, height, x, y\n" |
| "viewport:%d, %d, %d, %d\n" |
| "recout: %d, %d, %d, %d\n", |
| pipe_ctx->pipe_idx, |
| pipe_ctx->plane_res.scl_data.viewport.width, |
| pipe_ctx->plane_res.scl_data.viewport.height, |
| pipe_ctx->plane_res.scl_data.viewport.x, |
| pipe_ctx->plane_res.scl_data.viewport.y, |
| pipe_ctx->plane_res.scl_data.recout.width, |
| pipe_ctx->plane_res.scl_data.recout.height, |
| pipe_ctx->plane_res.scl_data.recout.x, |
| pipe_ctx->plane_res.scl_data.recout.y); |
| } |
| |
| static void dce60_apply_ctx_for_surface( |
| struct dc *dc, |
| const struct dc_stream_state *stream, |
| int num_planes, |
| struct dc_state *context) |
| { |
| int i; |
| |
| if (num_planes == 0) |
| return; |
| |
| if (dc->fbc_compressor) |
| dc->fbc_compressor->funcs->disable_fbc(dc->fbc_compressor); |
| |
| for (i = 0; i < dc->res_pool->pipe_count; i++) { |
| struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; |
| |
| if (pipe_ctx->stream != stream) |
| continue; |
| |
| /* Need to allocate mem before program front end for Fiji */ |
| pipe_ctx->plane_res.mi->funcs->allocate_mem_input( |
| pipe_ctx->plane_res.mi, |
| pipe_ctx->stream->timing.h_total, |
| pipe_ctx->stream->timing.v_total, |
| pipe_ctx->stream->timing.pix_clk_100hz / 10, |
| context->stream_count); |
| |
| dce60_program_front_end_for_pipe(dc, pipe_ctx); |
| |
| dc->hwss.update_plane_addr(dc, pipe_ctx); |
| |
| dce60_program_surface_visibility(dc, pipe_ctx); |
| |
| } |
| |
| if (dc->fbc_compressor) |
| dce60_enable_fbc(dc, context); |
| } |
| |
| void dce60_hw_sequencer_construct(struct dc *dc) |
| { |
| dce110_hw_sequencer_construct(dc); |
| |
| dc->hwseq->funcs.enable_display_power_gating = dce100_enable_display_power_gating; |
| dc->hwss.apply_ctx_for_surface = dce60_apply_ctx_for_surface; |
| dc->hwss.cursor_lock = dce60_pipe_control_lock; |
| dc->hwss.pipe_control_lock = dce60_pipe_control_lock; |
| dc->hwss.prepare_bandwidth = dce100_prepare_bandwidth; |
| dc->hwss.optimize_bandwidth = dce100_optimize_bandwidth; |
| } |
| |