diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-18 17:39:57 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-18 17:39:57 +0000 |
commit | dc50eab76b709d68175a358d6e23a5a3890764d3 (patch) | |
tree | c754d0390db060af0213ff994f0ac310e4cfd6e9 /drivers/gpu/drm/amd/display/dc/dcn10 | |
parent | Adding debian version 6.6.15-2. (diff) | |
download | linux-dc50eab76b709d68175a358d6e23a5a3890764d3.tar.xz linux-dc50eab76b709d68175a358d6e23a5a3890764d3.zip |
Merging upstream version 6.7.7.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'drivers/gpu/drm/amd/display/dc/dcn10')
10 files changed, 104 insertions, 4292 deletions
diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/Makefile b/drivers/gpu/drm/amd/display/dc/dcn10/Makefile index 62ad1a11bf..2d2007c3e2 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dcn10/Makefile @@ -22,7 +22,7 @@ # # Makefile for DCN. -DCN10 = dcn10_init.o dcn10_resource.o dcn10_ipp.o dcn10_hw_sequencer.o \ +DCN10 = dcn10_init.o dcn10_resource.o dcn10_ipp.o \ dcn10_hw_sequencer_debug.o \ dcn10_dpp.o dcn10_opp.o dcn10_optc.o \ dcn10_hubp.o dcn10_mpc.o \ diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h index e875207757..4201b76270 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h @@ -171,11 +171,13 @@ struct dcn_hubbub_registers { uint32_t DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_B; uint32_t DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_C; uint32_t DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_D; + uint32_t DCHUBBUB_ARB_MALL_CNTL; uint32_t SDPIF_REQUEST_RATE_LIMIT; uint32_t DCHUBBUB_SDPIF_CFG0; uint32_t DCHUBBUB_SDPIF_CFG1; uint32_t DCHUBBUB_CLOCK_CNTL; uint32_t DCHUBBUB_MEM_PWR_MODE_CTRL; + uint32_t DCHUBBUB_ARB_QOS_FORCE; }; #define HUBBUB_REG_FIELD_LIST_DCN32(type) \ @@ -194,7 +196,13 @@ struct dcn_hubbub_registers { type DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_A;\ type DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_B;\ type DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_C;\ - type DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_D + type DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_D;\ + type MALL_PREFETCH_COMPLETE;\ + type MALL_IN_USE + + #define HUBBUB_REG_FIELD_LIST_DCN35(type) \ + type DCHUBBUB_FGCG_REP_DIS;\ + type DCHUBBUB_ARB_ALLOW_CSTATE_DEEPSLEEP_LEGACY_MODE /* set field name */ #define HUBBUB_SF(reg_name, field_name, post_fix)\ @@ -381,6 +389,7 @@ struct dcn_hubbub_shift { HUBBUB_HVM_REG_FIELD_LIST(uint8_t); HUBBUB_RET_REG_FIELD_LIST(uint8_t); HUBBUB_REG_FIELD_LIST_DCN32(uint8_t); + HUBBUB_REG_FIELD_LIST_DCN35(uint8_t); }; struct dcn_hubbub_mask { @@ -389,6 +398,7 @@ struct dcn_hubbub_mask { HUBBUB_HVM_REG_FIELD_LIST(uint32_t); HUBBUB_RET_REG_FIELD_LIST(uint32_t); HUBBUB_REG_FIELD_LIST_DCN32(uint32_t); + HUBBUB_REG_FIELD_LIST_DCN35(uint32_t); }; struct dc; diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c deleted file mode 100644 index 13ccb57379..0000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c +++ /dev/null @@ -1,3889 +0,0 @@ -/* - * Copyright 2016 Advanced Micro Devices, Inc. - * - * 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 <linux/delay.h> -#include "dm_services.h" -#include "basics/dc_common.h" -#include "core_types.h" -#include "resource.h" -#include "custom_float.h" -#include "dcn10_hw_sequencer.h" -#include "dcn10_hw_sequencer_debug.h" -#include "dce/dce_hwseq.h" -#include "abm.h" -#include "dmcu.h" -#include "dcn10_optc.h" -#include "dcn10_dpp.h" -#include "dcn10_mpc.h" -#include "timing_generator.h" -#include "opp.h" -#include "ipp.h" -#include "mpc.h" -#include "reg_helper.h" -#include "dcn10_hubp.h" -#include "dcn10_hubbub.h" -#include "dcn10_cm_common.h" -#include "dccg.h" -#include "clk_mgr.h" -#include "link_hwss.h" -#include "dpcd_defs.h" -#include "dsc.h" -#include "dce/dmub_psr.h" -#include "dc_dmub_srv.h" -#include "dce/dmub_hw_lock_mgr.h" -#include "dc_trace.h" -#include "dce/dmub_outbox.h" -#include "link.h" - -#define DC_LOGGER_INIT(logger) - -#define CTX \ - hws->ctx -#define REG(reg)\ - hws->regs->reg - -#undef FN -#define FN(reg_name, field_name) \ - hws->shifts->field_name, hws->masks->field_name - -/*print is 17 wide, first two characters are spaces*/ -#define DTN_INFO_MICRO_SEC(ref_cycle) \ - print_microsec(dc_ctx, log_ctx, ref_cycle) - -#define GAMMA_HW_POINTS_NUM 256 - -#define PGFSM_POWER_ON 0 -#define PGFSM_POWER_OFF 2 - -static void print_microsec(struct dc_context *dc_ctx, - struct dc_log_buffer_ctx *log_ctx, - uint32_t ref_cycle) -{ - const uint32_t ref_clk_mhz = dc_ctx->dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000; - static const unsigned int frac = 1000; - uint32_t us_x10 = (ref_cycle * frac) / ref_clk_mhz; - - DTN_INFO(" %11d.%03d", - us_x10 / frac, - us_x10 % frac); -} - -void dcn10_lock_all_pipes(struct dc *dc, - struct dc_state *context, - bool lock) -{ - struct pipe_ctx *pipe_ctx; - struct pipe_ctx *old_pipe_ctx; - struct timing_generator *tg; - int i; - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - old_pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i]; - pipe_ctx = &context->res_ctx.pipe_ctx[i]; - tg = pipe_ctx->stream_res.tg; - - /* - * Only lock the top pipe's tg to prevent redundant - * (un)locking. Also skip if pipe is disabled. - */ - if (pipe_ctx->top_pipe || - !pipe_ctx->stream || - (!pipe_ctx->plane_state && !old_pipe_ctx->plane_state) || - !tg->funcs->is_tg_enabled(tg) || - pipe_ctx->stream->mall_stream_config.type == SUBVP_PHANTOM) - continue; - - if (lock) - dc->hwss.pipe_control_lock(dc, pipe_ctx, true); - else - dc->hwss.pipe_control_lock(dc, pipe_ctx, false); - } -} - -static void log_mpc_crc(struct dc *dc, - struct dc_log_buffer_ctx *log_ctx) -{ - struct dc_context *dc_ctx = dc->ctx; - struct dce_hwseq *hws = dc->hwseq; - - if (REG(MPC_CRC_RESULT_GB)) - DTN_INFO("MPC_CRC_RESULT_GB:%d MPC_CRC_RESULT_C:%d MPC_CRC_RESULT_AR:%d\n", - REG_READ(MPC_CRC_RESULT_GB), REG_READ(MPC_CRC_RESULT_C), REG_READ(MPC_CRC_RESULT_AR)); - if (REG(DPP_TOP0_DPP_CRC_VAL_B_A)) - DTN_INFO("DPP_TOP0_DPP_CRC_VAL_B_A:%d DPP_TOP0_DPP_CRC_VAL_R_G:%d\n", - REG_READ(DPP_TOP0_DPP_CRC_VAL_B_A), REG_READ(DPP_TOP0_DPP_CRC_VAL_R_G)); -} - -static void dcn10_log_hubbub_state(struct dc *dc, - struct dc_log_buffer_ctx *log_ctx) -{ - struct dc_context *dc_ctx = dc->ctx; - struct dcn_hubbub_wm wm; - int i; - - memset(&wm, 0, sizeof(struct dcn_hubbub_wm)); - dc->res_pool->hubbub->funcs->wm_read_state(dc->res_pool->hubbub, &wm); - - DTN_INFO("HUBBUB WM: data_urgent pte_meta_urgent" - " sr_enter sr_exit dram_clk_change\n"); - - for (i = 0; i < 4; i++) { - struct dcn_hubbub_wm_set *s; - - s = &wm.sets[i]; - DTN_INFO("WM_Set[%d]:", s->wm_set); - DTN_INFO_MICRO_SEC(s->data_urgent); - DTN_INFO_MICRO_SEC(s->pte_meta_urgent); - DTN_INFO_MICRO_SEC(s->sr_enter); - DTN_INFO_MICRO_SEC(s->sr_exit); - DTN_INFO_MICRO_SEC(s->dram_clk_change); - DTN_INFO("\n"); - } - - DTN_INFO("\n"); -} - -static void dcn10_log_hubp_states(struct dc *dc, void *log_ctx) -{ - struct dc_context *dc_ctx = dc->ctx; - struct resource_pool *pool = dc->res_pool; - int i; - - DTN_INFO( - "HUBP: format addr_hi width height rot mir sw_mode dcc_en blank_en clock_en ttu_dis underflow min_ttu_vblank qos_low_wm qos_high_wm\n"); - for (i = 0; i < pool->pipe_count; i++) { - struct hubp *hubp = pool->hubps[i]; - struct dcn_hubp_state *s = &(TO_DCN10_HUBP(hubp)->state); - - hubp->funcs->hubp_read_state(hubp); - - if (!s->blank_en) { - DTN_INFO("[%2d]: %5xh %6xh %5d %6d %2xh %2xh %6xh %6d %8d %8d %7d %8xh", - hubp->inst, - s->pixel_format, - s->inuse_addr_hi, - s->viewport_width, - s->viewport_height, - s->rotation_angle, - s->h_mirror_en, - s->sw_mode, - s->dcc_en, - s->blank_en, - s->clock_en, - s->ttu_disable, - s->underflow_status); - DTN_INFO_MICRO_SEC(s->min_ttu_vblank); - DTN_INFO_MICRO_SEC(s->qos_level_low_wm); - DTN_INFO_MICRO_SEC(s->qos_level_high_wm); - DTN_INFO("\n"); - } - } - - DTN_INFO("\n=========RQ========\n"); - DTN_INFO("HUBP: drq_exp_m prq_exp_m mrq_exp_m crq_exp_m plane1_ba L:chunk_s min_chu_s meta_ch_s" - " min_m_c_s dpte_gr_s mpte_gr_s swath_hei pte_row_h C:chunk_s min_chu_s meta_ch_s" - " min_m_c_s dpte_gr_s mpte_gr_s swath_hei pte_row_h\n"); - for (i = 0; i < pool->pipe_count; i++) { - struct dcn_hubp_state *s = &(TO_DCN10_HUBP(pool->hubps[i])->state); - struct _vcs_dpi_display_rq_regs_st *rq_regs = &s->rq_regs; - - if (!s->blank_en) - DTN_INFO("[%2d]: %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh\n", - pool->hubps[i]->inst, rq_regs->drq_expansion_mode, rq_regs->prq_expansion_mode, rq_regs->mrq_expansion_mode, - rq_regs->crq_expansion_mode, rq_regs->plane1_base_address, rq_regs->rq_regs_l.chunk_size, - rq_regs->rq_regs_l.min_chunk_size, rq_regs->rq_regs_l.meta_chunk_size, - rq_regs->rq_regs_l.min_meta_chunk_size, rq_regs->rq_regs_l.dpte_group_size, - rq_regs->rq_regs_l.mpte_group_size, rq_regs->rq_regs_l.swath_height, - rq_regs->rq_regs_l.pte_row_height_linear, rq_regs->rq_regs_c.chunk_size, rq_regs->rq_regs_c.min_chunk_size, - rq_regs->rq_regs_c.meta_chunk_size, rq_regs->rq_regs_c.min_meta_chunk_size, - rq_regs->rq_regs_c.dpte_group_size, rq_regs->rq_regs_c.mpte_group_size, - rq_regs->rq_regs_c.swath_height, rq_regs->rq_regs_c.pte_row_height_linear); - } - - DTN_INFO("========DLG========\n"); - DTN_INFO("HUBP: rc_hbe dlg_vbe min_d_y_n rc_per_ht rc_x_a_s " - " dst_y_a_s dst_y_pf dst_y_vvb dst_y_rvb dst_y_vfl dst_y_rfl rf_pix_fq" - " vratio_pf vrat_pf_c rc_pg_vbl rc_pg_vbc rc_mc_vbl rc_mc_vbc rc_pg_fll" - " rc_pg_flc rc_mc_fll rc_mc_flc pr_nom_l pr_nom_c rc_pg_nl rc_pg_nc " - " mr_nom_l mr_nom_c rc_mc_nl rc_mc_nc rc_ld_pl rc_ld_pc rc_ld_l " - " rc_ld_c cha_cur0 ofst_cur1 cha_cur1 vr_af_vc0 ddrq_limt x_rt_dlay" - " x_rp_dlay x_rr_sfl\n"); - for (i = 0; i < pool->pipe_count; i++) { - struct dcn_hubp_state *s = &(TO_DCN10_HUBP(pool->hubps[i])->state); - struct _vcs_dpi_display_dlg_regs_st *dlg_regs = &s->dlg_attr; - - if (!s->blank_en) - DTN_INFO("[%2d]: %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh" - " %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh" - " %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh\n", - pool->hubps[i]->inst, dlg_regs->refcyc_h_blank_end, dlg_regs->dlg_vblank_end, dlg_regs->min_dst_y_next_start, - dlg_regs->refcyc_per_htotal, dlg_regs->refcyc_x_after_scaler, dlg_regs->dst_y_after_scaler, - dlg_regs->dst_y_prefetch, dlg_regs->dst_y_per_vm_vblank, dlg_regs->dst_y_per_row_vblank, - dlg_regs->dst_y_per_vm_flip, dlg_regs->dst_y_per_row_flip, dlg_regs->ref_freq_to_pix_freq, - dlg_regs->vratio_prefetch, dlg_regs->vratio_prefetch_c, dlg_regs->refcyc_per_pte_group_vblank_l, - dlg_regs->refcyc_per_pte_group_vblank_c, dlg_regs->refcyc_per_meta_chunk_vblank_l, - dlg_regs->refcyc_per_meta_chunk_vblank_c, dlg_regs->refcyc_per_pte_group_flip_l, - dlg_regs->refcyc_per_pte_group_flip_c, dlg_regs->refcyc_per_meta_chunk_flip_l, - dlg_regs->refcyc_per_meta_chunk_flip_c, dlg_regs->dst_y_per_pte_row_nom_l, - dlg_regs->dst_y_per_pte_row_nom_c, dlg_regs->refcyc_per_pte_group_nom_l, - dlg_regs->refcyc_per_pte_group_nom_c, dlg_regs->dst_y_per_meta_row_nom_l, - dlg_regs->dst_y_per_meta_row_nom_c, dlg_regs->refcyc_per_meta_chunk_nom_l, - dlg_regs->refcyc_per_meta_chunk_nom_c, dlg_regs->refcyc_per_line_delivery_pre_l, - dlg_regs->refcyc_per_line_delivery_pre_c, dlg_regs->refcyc_per_line_delivery_l, - dlg_regs->refcyc_per_line_delivery_c, dlg_regs->chunk_hdl_adjust_cur0, dlg_regs->dst_y_offset_cur1, - dlg_regs->chunk_hdl_adjust_cur1, dlg_regs->vready_after_vcount0, dlg_regs->dst_y_delta_drq_limit, - dlg_regs->xfc_reg_transfer_delay, dlg_regs->xfc_reg_precharge_delay, - dlg_regs->xfc_reg_remote_surface_flip_latency); - } - - DTN_INFO("========TTU========\n"); - DTN_INFO("HUBP: qos_ll_wm qos_lh_wm mn_ttu_vb qos_l_flp rc_rd_p_l rc_rd_l rc_rd_p_c" - " rc_rd_c rc_rd_c0 rc_rd_pc0 rc_rd_c1 rc_rd_pc1 qos_lf_l qos_rds_l" - " qos_lf_c qos_rds_c qos_lf_c0 qos_rds_c0 qos_lf_c1 qos_rds_c1\n"); - for (i = 0; i < pool->pipe_count; i++) { - struct dcn_hubp_state *s = &(TO_DCN10_HUBP(pool->hubps[i])->state); - struct _vcs_dpi_display_ttu_regs_st *ttu_regs = &s->ttu_attr; - - if (!s->blank_en) - DTN_INFO("[%2d]: %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh\n", - pool->hubps[i]->inst, ttu_regs->qos_level_low_wm, ttu_regs->qos_level_high_wm, ttu_regs->min_ttu_vblank, - ttu_regs->qos_level_flip, ttu_regs->refcyc_per_req_delivery_pre_l, ttu_regs->refcyc_per_req_delivery_l, - ttu_regs->refcyc_per_req_delivery_pre_c, ttu_regs->refcyc_per_req_delivery_c, ttu_regs->refcyc_per_req_delivery_cur0, - ttu_regs->refcyc_per_req_delivery_pre_cur0, ttu_regs->refcyc_per_req_delivery_cur1, - ttu_regs->refcyc_per_req_delivery_pre_cur1, ttu_regs->qos_level_fixed_l, ttu_regs->qos_ramp_disable_l, - ttu_regs->qos_level_fixed_c, ttu_regs->qos_ramp_disable_c, ttu_regs->qos_level_fixed_cur0, - ttu_regs->qos_ramp_disable_cur0, ttu_regs->qos_level_fixed_cur1, ttu_regs->qos_ramp_disable_cur1); - } - DTN_INFO("\n"); -} - -void dcn10_log_hw_state(struct dc *dc, - struct dc_log_buffer_ctx *log_ctx) -{ - struct dc_context *dc_ctx = dc->ctx; - struct resource_pool *pool = dc->res_pool; - int i; - - DTN_INFO_BEGIN(); - - dcn10_log_hubbub_state(dc, log_ctx); - - dcn10_log_hubp_states(dc, log_ctx); - - DTN_INFO("DPP: IGAM format IGAM mode DGAM mode RGAM mode" - " GAMUT mode C11 C12 C13 C14 C21 C22 C23 C24 " - "C31 C32 C33 C34\n"); - for (i = 0; i < pool->pipe_count; i++) { - struct dpp *dpp = pool->dpps[i]; - struct dcn_dpp_state s = {0}; - - dpp->funcs->dpp_read_state(dpp, &s); - - if (!s.is_enabled) - continue; - - DTN_INFO("[%2d]: %11xh %-11s %-11s %-11s" - "%8x %08xh %08xh %08xh %08xh %08xh %08xh", - dpp->inst, - s.igam_input_format, - (s.igam_lut_mode == 0) ? "BypassFixed" : - ((s.igam_lut_mode == 1) ? "BypassFloat" : - ((s.igam_lut_mode == 2) ? "RAM" : - ((s.igam_lut_mode == 3) ? "RAM" : - "Unknown"))), - (s.dgam_lut_mode == 0) ? "Bypass" : - ((s.dgam_lut_mode == 1) ? "sRGB" : - ((s.dgam_lut_mode == 2) ? "Ycc" : - ((s.dgam_lut_mode == 3) ? "RAM" : - ((s.dgam_lut_mode == 4) ? "RAM" : - "Unknown")))), - (s.rgam_lut_mode == 0) ? "Bypass" : - ((s.rgam_lut_mode == 1) ? "sRGB" : - ((s.rgam_lut_mode == 2) ? "Ycc" : - ((s.rgam_lut_mode == 3) ? "RAM" : - ((s.rgam_lut_mode == 4) ? "RAM" : - "Unknown")))), - s.gamut_remap_mode, - s.gamut_remap_c11_c12, - s.gamut_remap_c13_c14, - s.gamut_remap_c21_c22, - s.gamut_remap_c23_c24, - s.gamut_remap_c31_c32, - s.gamut_remap_c33_c34); - DTN_INFO("\n"); - } - DTN_INFO("\n"); - - DTN_INFO("MPCC: OPP DPP MPCCBOT MODE ALPHA_MODE PREMULT OVERLAP_ONLY IDLE\n"); - for (i = 0; i < pool->pipe_count; i++) { - struct mpcc_state s = {0}; - - pool->mpc->funcs->read_mpcc_state(pool->mpc, i, &s); - if (s.opp_id != 0xf) - DTN_INFO("[%2d]: %2xh %2xh %6xh %4d %10d %7d %12d %4d\n", - i, s.opp_id, s.dpp_id, s.bot_mpcc_id, - s.mode, s.alpha_mode, s.pre_multiplied_alpha, s.overlap_only, - s.idle); - } - DTN_INFO("\n"); - - DTN_INFO("OTG: v_bs v_be v_ss v_se vpol vmax vmin vmax_sel vmin_sel h_bs h_be h_ss h_se hpol htot vtot underflow blank_en\n"); - - for (i = 0; i < pool->timing_generator_count; i++) { - struct timing_generator *tg = pool->timing_generators[i]; - struct dcn_otg_state s = {0}; - /* Read shared OTG state registers for all DCNx */ - optc1_read_otg_state(DCN10TG_FROM_TG(tg), &s); - - /* - * For DCN2 and greater, a register on the OPP is used to - * determine if the CRTC is blanked instead of the OTG. So use - * dpg_is_blanked() if exists, otherwise fallback on otg. - * - * TODO: Implement DCN-specific read_otg_state hooks. - */ - if (pool->opps[i]->funcs->dpg_is_blanked) - s.blank_enabled = pool->opps[i]->funcs->dpg_is_blanked(pool->opps[i]); - else - s.blank_enabled = tg->funcs->is_blanked(tg); - - //only print if OTG master is enabled - if ((s.otg_enabled & 1) == 0) - continue; - - DTN_INFO("[%d]: %5d %5d %5d %5d %5d %5d %5d %9d %9d %5d %5d %5d %5d %5d %5d %5d %9d %8d\n", - tg->inst, - s.v_blank_start, - s.v_blank_end, - s.v_sync_a_start, - s.v_sync_a_end, - s.v_sync_a_pol, - s.v_total_max, - s.v_total_min, - s.v_total_max_sel, - s.v_total_min_sel, - s.h_blank_start, - s.h_blank_end, - s.h_sync_a_start, - s.h_sync_a_end, - s.h_sync_a_pol, - s.h_total, - s.v_total, - s.underflow_occurred_status, - s.blank_enabled); - - // Clear underflow for debug purposes - // We want to keep underflow sticky bit on for the longevity tests outside of test environment. - // This function is called only from Windows or Diags test environment, hence it's safe to clear - // it from here without affecting the original intent. - tg->funcs->clear_optc_underflow(tg); - } - DTN_INFO("\n"); - - // dcn_dsc_state struct field bytes_per_pixel was renamed to bits_per_pixel - // TODO: Update golden log header to reflect this name change - DTN_INFO("DSC: CLOCK_EN SLICE_WIDTH Bytes_pp\n"); - for (i = 0; i < pool->res_cap->num_dsc; i++) { - struct display_stream_compressor *dsc = pool->dscs[i]; - struct dcn_dsc_state s = {0}; - - dsc->funcs->dsc_read_state(dsc, &s); - DTN_INFO("[%d]: %-9d %-12d %-10d\n", - dsc->inst, - s.dsc_clock_en, - s.dsc_slice_width, - s.dsc_bits_per_pixel); - DTN_INFO("\n"); - } - DTN_INFO("\n"); - - DTN_INFO("S_ENC: DSC_MODE SEC_GSP7_LINE_NUM" - " VBID6_LINE_REFERENCE VBID6_LINE_NUM SEC_GSP7_ENABLE SEC_STREAM_ENABLE\n"); - for (i = 0; i < pool->stream_enc_count; i++) { - struct stream_encoder *enc = pool->stream_enc[i]; - struct enc_state s = {0}; - - if (enc->funcs->enc_read_state) { - enc->funcs->enc_read_state(enc, &s); - DTN_INFO("[%-3d]: %-9d %-18d %-21d %-15d %-16d %-17d\n", - enc->id, - s.dsc_mode, - s.sec_gsp_pps_line_num, - s.vbid6_line_reference, - s.vbid6_line_num, - s.sec_gsp_pps_enable, - s.sec_stream_enable); - DTN_INFO("\n"); - } - } - DTN_INFO("\n"); - - DTN_INFO("L_ENC: DPHY_FEC_EN DPHY_FEC_READY_SHADOW DPHY_FEC_ACTIVE_STATUS DP_LINK_TRAINING_COMPLETE\n"); - for (i = 0; i < dc->link_count; i++) { - struct link_encoder *lenc = dc->links[i]->link_enc; - - struct link_enc_state s = {0}; - - if (lenc && lenc->funcs->read_state) { - lenc->funcs->read_state(lenc, &s); - DTN_INFO("[%-3d]: %-12d %-22d %-22d %-25d\n", - i, - s.dphy_fec_en, - s.dphy_fec_ready_shadow, - s.dphy_fec_active_status, - s.dp_link_training_complete); - DTN_INFO("\n"); - } - } - DTN_INFO("\n"); - - DTN_INFO("\nCALCULATED Clocks: dcfclk_khz:%d dcfclk_deep_sleep_khz:%d dispclk_khz:%d\n" - "dppclk_khz:%d max_supported_dppclk_khz:%d fclk_khz:%d socclk_khz:%d\n\n", - dc->current_state->bw_ctx.bw.dcn.clk.dcfclk_khz, - dc->current_state->bw_ctx.bw.dcn.clk.dcfclk_deep_sleep_khz, - dc->current_state->bw_ctx.bw.dcn.clk.dispclk_khz, - dc->current_state->bw_ctx.bw.dcn.clk.dppclk_khz, - dc->current_state->bw_ctx.bw.dcn.clk.max_supported_dppclk_khz, - dc->current_state->bw_ctx.bw.dcn.clk.fclk_khz, - dc->current_state->bw_ctx.bw.dcn.clk.socclk_khz); - - log_mpc_crc(dc, log_ctx); - - { - if (pool->hpo_dp_stream_enc_count > 0) { - DTN_INFO("DP HPO S_ENC: Enabled OTG Format Depth Vid SDP Compressed Link\n"); - for (i = 0; i < pool->hpo_dp_stream_enc_count; i++) { - struct hpo_dp_stream_encoder_state hpo_dp_se_state = {0}; - struct hpo_dp_stream_encoder *hpo_dp_stream_enc = pool->hpo_dp_stream_enc[i]; - - if (hpo_dp_stream_enc && hpo_dp_stream_enc->funcs->read_state) { - hpo_dp_stream_enc->funcs->read_state(hpo_dp_stream_enc, &hpo_dp_se_state); - - DTN_INFO("[%d]: %d %d %6s %d %d %d %d %d\n", - hpo_dp_stream_enc->id - ENGINE_ID_HPO_DP_0, - hpo_dp_se_state.stream_enc_enabled, - hpo_dp_se_state.otg_inst, - (hpo_dp_se_state.pixel_encoding == 0) ? "4:4:4" : - ((hpo_dp_se_state.pixel_encoding == 1) ? "4:2:2" : - (hpo_dp_se_state.pixel_encoding == 2) ? "4:2:0" : "Y-Only"), - (hpo_dp_se_state.component_depth == 0) ? 6 : - ((hpo_dp_se_state.component_depth == 1) ? 8 : - (hpo_dp_se_state.component_depth == 2) ? 10 : 12), - hpo_dp_se_state.vid_stream_enabled, - hpo_dp_se_state.sdp_enabled, - hpo_dp_se_state.compressed_format, - hpo_dp_se_state.mapped_to_link_enc); - } - } - - DTN_INFO("\n"); - } - - /* log DP HPO L_ENC section if any hpo_dp_link_enc exists */ - if (pool->hpo_dp_link_enc_count) { - DTN_INFO("DP HPO L_ENC: Enabled Mode Lanes Stream Slots VC Rate X VC Rate Y\n"); - - for (i = 0; i < pool->hpo_dp_link_enc_count; i++) { - struct hpo_dp_link_encoder *hpo_dp_link_enc = pool->hpo_dp_link_enc[i]; - struct hpo_dp_link_enc_state hpo_dp_le_state = {0}; - - if (hpo_dp_link_enc->funcs->read_state) { - hpo_dp_link_enc->funcs->read_state(hpo_dp_link_enc, &hpo_dp_le_state); - DTN_INFO("[%d]: %d %6s %d %d %d %d %d\n", - hpo_dp_link_enc->inst, - hpo_dp_le_state.link_enc_enabled, - (hpo_dp_le_state.link_mode == 0) ? "TPS1" : - (hpo_dp_le_state.link_mode == 1) ? "TPS2" : - (hpo_dp_le_state.link_mode == 2) ? "ACTIVE" : "TEST", - hpo_dp_le_state.lane_count, - hpo_dp_le_state.stream_src[0], - hpo_dp_le_state.slot_count[0], - hpo_dp_le_state.vc_rate_x[0], - hpo_dp_le_state.vc_rate_y[0]); - DTN_INFO("\n"); - } - } - - DTN_INFO("\n"); - } - } - - DTN_INFO_END(); -} - -bool dcn10_did_underflow_occur(struct dc *dc, struct pipe_ctx *pipe_ctx) -{ - struct hubp *hubp = pipe_ctx->plane_res.hubp; - struct timing_generator *tg = pipe_ctx->stream_res.tg; - - if (tg->funcs->is_optc_underflow_occurred(tg)) { - tg->funcs->clear_optc_underflow(tg); - return true; - } - - if (hubp->funcs->hubp_get_underflow_status(hubp)) { - hubp->funcs->hubp_clear_underflow(hubp); - return true; - } - return false; -} - -void dcn10_enable_power_gating_plane( - struct dce_hwseq *hws, - bool enable) -{ - bool force_on = true; /* disable power gating */ - - if (enable) - force_on = false; - - /* DCHUBP0/1/2/3 */ - REG_UPDATE(DOMAIN0_PG_CONFIG, DOMAIN0_POWER_FORCEON, force_on); - REG_UPDATE(DOMAIN2_PG_CONFIG, DOMAIN2_POWER_FORCEON, force_on); - REG_UPDATE(DOMAIN4_PG_CONFIG, DOMAIN4_POWER_FORCEON, force_on); - REG_UPDATE(DOMAIN6_PG_CONFIG, DOMAIN6_POWER_FORCEON, force_on); - - /* DPP0/1/2/3 */ - REG_UPDATE(DOMAIN1_PG_CONFIG, DOMAIN1_POWER_FORCEON, force_on); - REG_UPDATE(DOMAIN3_PG_CONFIG, DOMAIN3_POWER_FORCEON, force_on); - REG_UPDATE(DOMAIN5_PG_CONFIG, DOMAIN5_POWER_FORCEON, force_on); - REG_UPDATE(DOMAIN7_PG_CONFIG, DOMAIN7_POWER_FORCEON, force_on); -} - -void dcn10_disable_vga( - struct dce_hwseq *hws) -{ - unsigned int in_vga1_mode = 0; - unsigned int in_vga2_mode = 0; - unsigned int in_vga3_mode = 0; - unsigned int in_vga4_mode = 0; - - REG_GET(D1VGA_CONTROL, D1VGA_MODE_ENABLE, &in_vga1_mode); - REG_GET(D2VGA_CONTROL, D2VGA_MODE_ENABLE, &in_vga2_mode); - REG_GET(D3VGA_CONTROL, D3VGA_MODE_ENABLE, &in_vga3_mode); - REG_GET(D4VGA_CONTROL, D4VGA_MODE_ENABLE, &in_vga4_mode); - - if (in_vga1_mode == 0 && in_vga2_mode == 0 && - in_vga3_mode == 0 && in_vga4_mode == 0) - return; - - REG_WRITE(D1VGA_CONTROL, 0); - REG_WRITE(D2VGA_CONTROL, 0); - REG_WRITE(D3VGA_CONTROL, 0); - REG_WRITE(D4VGA_CONTROL, 0); - - /* HW Engineer's Notes: - * During switch from vga->extended, if we set the VGA_TEST_ENABLE and - * then hit the VGA_TEST_RENDER_START, then the DCHUBP timing gets updated correctly. - * - * Then vBIOS will have it poll for the VGA_TEST_RENDER_DONE and unset - * VGA_TEST_ENABLE, to leave it in the same state as before. - */ - REG_UPDATE(VGA_TEST_CONTROL, VGA_TEST_ENABLE, 1); - REG_UPDATE(VGA_TEST_CONTROL, VGA_TEST_RENDER_START, 1); -} - -/** - * dcn10_dpp_pg_control - DPP power gate control. - * - * @hws: dce_hwseq reference. - * @dpp_inst: DPP instance reference. - * @power_on: true if we want to enable power gate, false otherwise. - * - * Enable or disable power gate in the specific DPP instance. - */ -void dcn10_dpp_pg_control( - struct dce_hwseq *hws, - unsigned int dpp_inst, - bool power_on) -{ - uint32_t power_gate = power_on ? 0 : 1; - uint32_t pwr_status = power_on ? PGFSM_POWER_ON : PGFSM_POWER_OFF; - - if (hws->ctx->dc->debug.disable_dpp_power_gate) - return; - if (REG(DOMAIN1_PG_CONFIG) == 0) - return; - - switch (dpp_inst) { - case 0: /* DPP0 */ - REG_UPDATE(DOMAIN1_PG_CONFIG, - DOMAIN1_POWER_GATE, power_gate); - - REG_WAIT(DOMAIN1_PG_STATUS, - DOMAIN1_PGFSM_PWR_STATUS, pwr_status, - 1, 1000); - break; - case 1: /* DPP1 */ - REG_UPDATE(DOMAIN3_PG_CONFIG, - DOMAIN3_POWER_GATE, power_gate); - - REG_WAIT(DOMAIN3_PG_STATUS, - DOMAIN3_PGFSM_PWR_STATUS, pwr_status, - 1, 1000); - break; - case 2: /* DPP2 */ - REG_UPDATE(DOMAIN5_PG_CONFIG, - DOMAIN5_POWER_GATE, power_gate); - - REG_WAIT(DOMAIN5_PG_STATUS, - DOMAIN5_PGFSM_PWR_STATUS, pwr_status, - 1, 1000); - break; - case 3: /* DPP3 */ - REG_UPDATE(DOMAIN7_PG_CONFIG, - DOMAIN7_POWER_GATE, power_gate); - - REG_WAIT(DOMAIN7_PG_STATUS, - DOMAIN7_PGFSM_PWR_STATUS, pwr_status, - 1, 1000); - break; - default: - BREAK_TO_DEBUGGER(); - break; - } -} - -/** - * dcn10_hubp_pg_control - HUBP power gate control. - * - * @hws: dce_hwseq reference. - * @hubp_inst: DPP instance reference. - * @power_on: true if we want to enable power gate, false otherwise. - * - * Enable or disable power gate in the specific HUBP instance. - */ -void dcn10_hubp_pg_control( - struct dce_hwseq *hws, - unsigned int hubp_inst, - bool power_on) -{ - uint32_t power_gate = power_on ? 0 : 1; - uint32_t pwr_status = power_on ? PGFSM_POWER_ON : PGFSM_POWER_OFF; - - if (hws->ctx->dc->debug.disable_hubp_power_gate) - return; - if (REG(DOMAIN0_PG_CONFIG) == 0) - return; - - switch (hubp_inst) { - case 0: /* DCHUBP0 */ - REG_UPDATE(DOMAIN0_PG_CONFIG, - DOMAIN0_POWER_GATE, power_gate); - - REG_WAIT(DOMAIN0_PG_STATUS, - DOMAIN0_PGFSM_PWR_STATUS, pwr_status, - 1, 1000); - break; - case 1: /* DCHUBP1 */ - REG_UPDATE(DOMAIN2_PG_CONFIG, - DOMAIN2_POWER_GATE, power_gate); - - REG_WAIT(DOMAIN2_PG_STATUS, - DOMAIN2_PGFSM_PWR_STATUS, pwr_status, - 1, 1000); - break; - case 2: /* DCHUBP2 */ - REG_UPDATE(DOMAIN4_PG_CONFIG, - DOMAIN4_POWER_GATE, power_gate); - - REG_WAIT(DOMAIN4_PG_STATUS, - DOMAIN4_PGFSM_PWR_STATUS, pwr_status, - 1, 1000); - break; - case 3: /* DCHUBP3 */ - REG_UPDATE(DOMAIN6_PG_CONFIG, - DOMAIN6_POWER_GATE, power_gate); - - REG_WAIT(DOMAIN6_PG_STATUS, - DOMAIN6_PGFSM_PWR_STATUS, pwr_status, - 1, 1000); - break; - default: - BREAK_TO_DEBUGGER(); - break; - } -} - -static void power_on_plane_resources( - struct dce_hwseq *hws, - int plane_id) -{ - DC_LOGGER_INIT(hws->ctx->logger); - - if (hws->funcs.dpp_root_clock_control) - hws->funcs.dpp_root_clock_control(hws, plane_id, true); - - if (REG(DC_IP_REQUEST_CNTL)) { - REG_SET(DC_IP_REQUEST_CNTL, 0, - IP_REQUEST_EN, 1); - - if (hws->funcs.dpp_pg_control) - hws->funcs.dpp_pg_control(hws, plane_id, true); - - if (hws->funcs.hubp_pg_control) - hws->funcs.hubp_pg_control(hws, plane_id, true); - - REG_SET(DC_IP_REQUEST_CNTL, 0, - IP_REQUEST_EN, 0); - DC_LOG_DEBUG( - "Un-gated front end for pipe %d\n", plane_id); - } -} - -static void undo_DEGVIDCN10_253_wa(struct dc *dc) -{ - struct dce_hwseq *hws = dc->hwseq; - struct hubp *hubp = dc->res_pool->hubps[0]; - - if (!hws->wa_state.DEGVIDCN10_253_applied) - return; - - hubp->funcs->set_blank(hubp, true); - - REG_SET(DC_IP_REQUEST_CNTL, 0, - IP_REQUEST_EN, 1); - - hws->funcs.hubp_pg_control(hws, 0, false); - REG_SET(DC_IP_REQUEST_CNTL, 0, - IP_REQUEST_EN, 0); - - hws->wa_state.DEGVIDCN10_253_applied = false; -} - -static void apply_DEGVIDCN10_253_wa(struct dc *dc) -{ - struct dce_hwseq *hws = dc->hwseq; - struct hubp *hubp = dc->res_pool->hubps[0]; - int i; - - if (dc->debug.disable_stutter) - return; - - if (!hws->wa.DEGVIDCN10_253) - return; - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - if (!dc->res_pool->hubps[i]->power_gated) - return; - } - - /* all pipe power gated, apply work around to enable stutter. */ - - REG_SET(DC_IP_REQUEST_CNTL, 0, - IP_REQUEST_EN, 1); - - hws->funcs.hubp_pg_control(hws, 0, true); - REG_SET(DC_IP_REQUEST_CNTL, 0, - IP_REQUEST_EN, 0); - - hubp->funcs->set_hubp_blank_en(hubp, false); - hws->wa_state.DEGVIDCN10_253_applied = true; -} - -void dcn10_bios_golden_init(struct dc *dc) -{ - struct dce_hwseq *hws = dc->hwseq; - struct dc_bios *bp = dc->ctx->dc_bios; - int i; - bool allow_self_fresh_force_enable = true; - - if (hws->funcs.s0i3_golden_init_wa && hws->funcs.s0i3_golden_init_wa(dc)) - return; - - if (dc->res_pool->hubbub->funcs->is_allow_self_refresh_enabled) - allow_self_fresh_force_enable = - dc->res_pool->hubbub->funcs->is_allow_self_refresh_enabled(dc->res_pool->hubbub); - - - /* WA for making DF sleep when idle after resume from S0i3. - * DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE is set to 1 by - * command table, if DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE = 0 - * before calling command table and it changed to 1 after, - * it should be set back to 0. - */ - - /* initialize dcn global */ - bp->funcs->enable_disp_power_gating(bp, - CONTROLLER_ID_D0, ASIC_PIPE_INIT); - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - /* initialize dcn per pipe */ - bp->funcs->enable_disp_power_gating(bp, - CONTROLLER_ID_D0 + i, ASIC_PIPE_DISABLE); - } - - if (dc->res_pool->hubbub->funcs->allow_self_refresh_control) - if (allow_self_fresh_force_enable == false && - dc->res_pool->hubbub->funcs->is_allow_self_refresh_enabled(dc->res_pool->hubbub)) - dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub, - !dc->res_pool->hubbub->ctx->dc->debug.disable_stutter); - -} - -static void false_optc_underflow_wa( - struct dc *dc, - const struct dc_stream_state *stream, - struct timing_generator *tg) -{ - int i; - bool underflow; - - if (!dc->hwseq->wa.false_optc_underflow) - return; - - underflow = tg->funcs->is_optc_underflow_occurred(tg); - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *old_pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i]; - - if (old_pipe_ctx->stream != stream) - continue; - - dc->hwss.wait_for_mpcc_disconnect(dc, dc->res_pool, old_pipe_ctx); - } - - if (tg->funcs->set_blank_data_double_buffer) - tg->funcs->set_blank_data_double_buffer(tg, true); - - if (tg->funcs->is_optc_underflow_occurred(tg) && !underflow) - tg->funcs->clear_optc_underflow(tg); -} - -static int calculate_vready_offset_for_group(struct pipe_ctx *pipe) -{ - struct pipe_ctx *other_pipe; - int vready_offset = pipe->pipe_dlg_param.vready_offset; - - /* Always use the largest vready_offset of all connected pipes */ - for (other_pipe = pipe->bottom_pipe; other_pipe != NULL; other_pipe = other_pipe->bottom_pipe) { - if (other_pipe->pipe_dlg_param.vready_offset > vready_offset) - vready_offset = other_pipe->pipe_dlg_param.vready_offset; - } - for (other_pipe = pipe->top_pipe; other_pipe != NULL; other_pipe = other_pipe->top_pipe) { - if (other_pipe->pipe_dlg_param.vready_offset > vready_offset) - vready_offset = other_pipe->pipe_dlg_param.vready_offset; - } - for (other_pipe = pipe->next_odm_pipe; other_pipe != NULL; other_pipe = other_pipe->next_odm_pipe) { - if (other_pipe->pipe_dlg_param.vready_offset > vready_offset) - vready_offset = other_pipe->pipe_dlg_param.vready_offset; - } - for (other_pipe = pipe->prev_odm_pipe; other_pipe != NULL; other_pipe = other_pipe->prev_odm_pipe) { - if (other_pipe->pipe_dlg_param.vready_offset > vready_offset) - vready_offset = other_pipe->pipe_dlg_param.vready_offset; - } - - return vready_offset; -} - -enum dc_status dcn10_enable_stream_timing( - struct pipe_ctx *pipe_ctx, - struct dc_state *context, - struct dc *dc) -{ - struct dc_stream_state *stream = pipe_ctx->stream; - enum dc_color_space color_space; - struct tg_color black_color = {0}; - - /* by upper caller loop, pipe0 is parent pipe and be called first. - * back end is set up by for pipe0. Other children pipe share back end - * with pipe 0. No program is needed. - */ - if (pipe_ctx->top_pipe != NULL) - return DC_OK; - - /* TODO check if timing_changed, disable stream if timing changed */ - - /* HW program guide assume display already disable - * by unplug sequence. OTG assume stop. - */ - pipe_ctx->stream_res.tg->funcs->enable_optc_clock(pipe_ctx->stream_res.tg, true); - - if (false == pipe_ctx->clock_source->funcs->program_pix_clk( - pipe_ctx->clock_source, - &pipe_ctx->stream_res.pix_clk_params, - dc->link_srv->dp_get_encoding_format(&pipe_ctx->link_config.dp_link_settings), - &pipe_ctx->pll_settings)) { - BREAK_TO_DEBUGGER(); - return DC_ERROR_UNEXPECTED; - } - - if (dc_is_hdmi_tmds_signal(stream->signal)) { - stream->link->phy_state.symclk_ref_cnts.otg = 1; - if (stream->link->phy_state.symclk_state == SYMCLK_OFF_TX_OFF) - stream->link->phy_state.symclk_state = SYMCLK_ON_TX_OFF; - else - stream->link->phy_state.symclk_state = SYMCLK_ON_TX_ON; - } - - pipe_ctx->stream_res.tg->funcs->program_timing( - pipe_ctx->stream_res.tg, - &stream->timing, - calculate_vready_offset_for_group(pipe_ctx), - pipe_ctx->pipe_dlg_param.vstartup_start, - pipe_ctx->pipe_dlg_param.vupdate_offset, - pipe_ctx->pipe_dlg_param.vupdate_width, - pipe_ctx->stream->signal, - true); - -#if 0 /* move to after enable_crtc */ - /* TODO: OPP FMT, ABM. etc. should be done here. */ - /* or FPGA now. instance 0 only. TODO: move to opp.c */ - - inst_offset = reg_offsets[pipe_ctx->stream_res.tg->inst].fmt; - - pipe_ctx->stream_res.opp->funcs->opp_program_fmt( - pipe_ctx->stream_res.opp, - &stream->bit_depth_params, - &stream->clamping); -#endif - /* program otg blank color */ - color_space = stream->output_color_space; - color_space_to_black_color(dc, color_space, &black_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 (stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR420) - black_color.color_r_cr = black_color.color_g_y; - - if (pipe_ctx->stream_res.tg->funcs->set_blank_color) - pipe_ctx->stream_res.tg->funcs->set_blank_color( - pipe_ctx->stream_res.tg, - &black_color); - - if (pipe_ctx->stream_res.tg->funcs->is_blanked && - !pipe_ctx->stream_res.tg->funcs->is_blanked(pipe_ctx->stream_res.tg)) { - pipe_ctx->stream_res.tg->funcs->set_blank(pipe_ctx->stream_res.tg, true); - hwss_wait_for_blank_complete(pipe_ctx->stream_res.tg); - false_optc_underflow_wa(dc, pipe_ctx->stream, pipe_ctx->stream_res.tg); - } - - /* VTG is within DCHUB command block. DCFCLK is always on */ - if (false == pipe_ctx->stream_res.tg->funcs->enable_crtc(pipe_ctx->stream_res.tg)) { - BREAK_TO_DEBUGGER(); - return DC_ERROR_UNEXPECTED; - } - - /* TODO program crtc source select for non-virtual signal*/ - /* TODO program FMT */ - /* TODO setup link_enc */ - /* TODO set stream attributes */ - /* TODO program audio */ - /* TODO enable stream if timing changed */ - /* TODO unblank stream if DP */ - - return DC_OK; -} - -static void dcn10_reset_back_end_for_pipe( - struct dc *dc, - struct pipe_ctx *pipe_ctx, - struct dc_state *context) -{ - int i; - struct dc_link *link; - DC_LOGGER_INIT(dc->ctx->logger); - if (pipe_ctx->stream_res.stream_enc == NULL) { - pipe_ctx->stream = NULL; - return; - } - - link = pipe_ctx->stream->link; - /* DPMS may already disable or */ - /* dpms_off status is incorrect due to fastboot - * feature. When system resume from S4 with second - * screen only, the dpms_off would be true but - * VBIOS lit up eDP, so check link status too. - */ - if (!pipe_ctx->stream->dpms_off || link->link_status.link_active) - dc->link_srv->set_dpms_off(pipe_ctx); - else if (pipe_ctx->stream_res.audio) - dc->hwss.disable_audio_stream(pipe_ctx); - - if (pipe_ctx->stream_res.audio) { - /*disable az_endpoint*/ - pipe_ctx->stream_res.audio->funcs->az_disable(pipe_ctx->stream_res.audio); - - /*free audio*/ - if (dc->caps.dynamic_audio == true) { - /*we have to dynamic arbitrate the audio endpoints*/ - /*we free the resource, need reset is_audio_acquired*/ - update_audio_usage(&dc->current_state->res_ctx, dc->res_pool, - pipe_ctx->stream_res.audio, false); - pipe_ctx->stream_res.audio = NULL; - } - } - - /* by upper caller loop, parent pipe: pipe0, will be reset last. - * back end share by all pipes and will be disable only when disable - * parent pipe. - */ - if (pipe_ctx->top_pipe == NULL) { - - if (pipe_ctx->stream_res.abm) - dc->hwss.set_abm_immediate_disable(pipe_ctx); - - pipe_ctx->stream_res.tg->funcs->disable_crtc(pipe_ctx->stream_res.tg); - - pipe_ctx->stream_res.tg->funcs->enable_optc_clock(pipe_ctx->stream_res.tg, false); - if (pipe_ctx->stream_res.tg->funcs->set_drr) - pipe_ctx->stream_res.tg->funcs->set_drr( - pipe_ctx->stream_res.tg, NULL); - pipe_ctx->stream->link->phy_state.symclk_ref_cnts.otg = 0; - } - - for (i = 0; i < dc->res_pool->pipe_count; i++) - if (&dc->current_state->res_ctx.pipe_ctx[i] == pipe_ctx) - break; - - if (i == dc->res_pool->pipe_count) - return; - - pipe_ctx->stream = NULL; - DC_LOG_DEBUG("Reset back end for pipe %d, tg:%d\n", - pipe_ctx->pipe_idx, pipe_ctx->stream_res.tg->inst); -} - -static bool dcn10_hw_wa_force_recovery(struct dc *dc) -{ - struct hubp *hubp ; - unsigned int i; - bool need_recover = true; - - if (!dc->debug.recovery_enabled) - return false; - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe_ctx = - &dc->current_state->res_ctx.pipe_ctx[i]; - if (pipe_ctx != NULL) { - hubp = pipe_ctx->plane_res.hubp; - if (hubp != NULL && hubp->funcs->hubp_get_underflow_status) { - if (hubp->funcs->hubp_get_underflow_status(hubp) != 0) { - /* one pipe underflow, we will reset all the pipes*/ - need_recover = true; - } - } - } - } - if (!need_recover) - return false; - /* - DCHUBP_CNTL:HUBP_BLANK_EN=1 - DCHUBBUB_SOFT_RESET:DCHUBBUB_GLOBAL_SOFT_RESET=1 - DCHUBP_CNTL:HUBP_DISABLE=1 - DCHUBP_CNTL:HUBP_DISABLE=0 - DCHUBBUB_SOFT_RESET:DCHUBBUB_GLOBAL_SOFT_RESET=0 - DCSURF_PRIMARY_SURFACE_ADDRESS - DCHUBP_CNTL:HUBP_BLANK_EN=0 - */ - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe_ctx = - &dc->current_state->res_ctx.pipe_ctx[i]; - if (pipe_ctx != NULL) { - hubp = pipe_ctx->plane_res.hubp; - /*DCHUBP_CNTL:HUBP_BLANK_EN=1*/ - if (hubp != NULL && hubp->funcs->set_hubp_blank_en) - hubp->funcs->set_hubp_blank_en(hubp, true); - } - } - /*DCHUBBUB_SOFT_RESET:DCHUBBUB_GLOBAL_SOFT_RESET=1*/ - hubbub1_soft_reset(dc->res_pool->hubbub, true); - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe_ctx = - &dc->current_state->res_ctx.pipe_ctx[i]; - if (pipe_ctx != NULL) { - hubp = pipe_ctx->plane_res.hubp; - /*DCHUBP_CNTL:HUBP_DISABLE=1*/ - if (hubp != NULL && hubp->funcs->hubp_disable_control) - hubp->funcs->hubp_disable_control(hubp, true); - } - } - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe_ctx = - &dc->current_state->res_ctx.pipe_ctx[i]; - if (pipe_ctx != NULL) { - hubp = pipe_ctx->plane_res.hubp; - /*DCHUBP_CNTL:HUBP_DISABLE=0*/ - if (hubp != NULL && hubp->funcs->hubp_disable_control) - hubp->funcs->hubp_disable_control(hubp, true); - } - } - /*DCHUBBUB_SOFT_RESET:DCHUBBUB_GLOBAL_SOFT_RESET=0*/ - hubbub1_soft_reset(dc->res_pool->hubbub, false); - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe_ctx = - &dc->current_state->res_ctx.pipe_ctx[i]; - if (pipe_ctx != NULL) { - hubp = pipe_ctx->plane_res.hubp; - /*DCHUBP_CNTL:HUBP_BLANK_EN=0*/ - if (hubp != NULL && hubp->funcs->set_hubp_blank_en) - hubp->funcs->set_hubp_blank_en(hubp, true); - } - } - return true; - -} - -void dcn10_verify_allow_pstate_change_high(struct dc *dc) -{ - struct hubbub *hubbub = dc->res_pool->hubbub; - static bool should_log_hw_state; /* prevent hw state log by default */ - - if (!hubbub->funcs->verify_allow_pstate_change_high) - return; - - if (!hubbub->funcs->verify_allow_pstate_change_high(hubbub)) { - int i = 0; - - if (should_log_hw_state) - dcn10_log_hw_state(dc, NULL); - - TRACE_DC_PIPE_STATE(pipe_ctx, i, MAX_PIPES); - BREAK_TO_DEBUGGER(); - if (dcn10_hw_wa_force_recovery(dc)) { - /*check again*/ - if (!hubbub->funcs->verify_allow_pstate_change_high(hubbub)) - BREAK_TO_DEBUGGER(); - } - } -} - -/* trigger HW to start disconnect plane from stream on the next vsync */ -void dcn10_plane_atomic_disconnect(struct dc *dc, struct pipe_ctx *pipe_ctx) -{ - struct dce_hwseq *hws = dc->hwseq; - struct hubp *hubp = pipe_ctx->plane_res.hubp; - int dpp_id = pipe_ctx->plane_res.dpp->inst; - struct mpc *mpc = dc->res_pool->mpc; - struct mpc_tree *mpc_tree_params; - struct mpcc *mpcc_to_remove = NULL; - struct output_pixel_processor *opp = pipe_ctx->stream_res.opp; - - mpc_tree_params = &(opp->mpc_tree_params); - mpcc_to_remove = mpc->funcs->get_mpcc_for_dpp(mpc_tree_params, dpp_id); - - /*Already reset*/ - if (mpcc_to_remove == NULL) - return; - - mpc->funcs->remove_mpcc(mpc, mpc_tree_params, mpcc_to_remove); - // Phantom pipes have OTG disabled by default, so MPCC_STATUS will never assert idle, - // so don't wait for MPCC_IDLE in the programming sequence - if (opp != NULL && !pipe_ctx->plane_state->is_phantom) - opp->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true; - - dc->optimized_required = true; - - if (hubp->funcs->hubp_disconnect) - hubp->funcs->hubp_disconnect(hubp); - - if (dc->debug.sanity_checks) - hws->funcs.verify_allow_pstate_change_high(dc); -} - -/** - * dcn10_plane_atomic_power_down - Power down plane components. - * - * @dc: dc struct reference. used for grab hwseq. - * @dpp: dpp struct reference. - * @hubp: hubp struct reference. - * - * Keep in mind that this operation requires a power gate configuration; - * however, requests for switch power gate are precisely controlled to avoid - * problems. For this reason, power gate request is usually disabled. This - * function first needs to enable the power gate request before disabling DPP - * and HUBP. Finally, it disables the power gate request again. - */ -void dcn10_plane_atomic_power_down(struct dc *dc, - struct dpp *dpp, - struct hubp *hubp) -{ - struct dce_hwseq *hws = dc->hwseq; - DC_LOGGER_INIT(dc->ctx->logger); - - if (REG(DC_IP_REQUEST_CNTL)) { - REG_SET(DC_IP_REQUEST_CNTL, 0, - IP_REQUEST_EN, 1); - - if (hws->funcs.dpp_pg_control) - hws->funcs.dpp_pg_control(hws, dpp->inst, false); - - if (hws->funcs.hubp_pg_control) - hws->funcs.hubp_pg_control(hws, hubp->inst, false); - - dpp->funcs->dpp_reset(dpp); - - REG_SET(DC_IP_REQUEST_CNTL, 0, - IP_REQUEST_EN, 0); - DC_LOG_DEBUG( - "Power gated front end %d\n", hubp->inst); - } - - if (hws->funcs.dpp_root_clock_control) - hws->funcs.dpp_root_clock_control(hws, dpp->inst, false); -} - -/* disable HW used by plane. - * note: cannot disable until disconnect is complete - */ -void dcn10_plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx) -{ - struct dce_hwseq *hws = dc->hwseq; - struct hubp *hubp = pipe_ctx->plane_res.hubp; - struct dpp *dpp = pipe_ctx->plane_res.dpp; - int opp_id = hubp->opp_id; - - dc->hwss.wait_for_mpcc_disconnect(dc, dc->res_pool, pipe_ctx); - - hubp->funcs->hubp_clk_cntl(hubp, false); - - dpp->funcs->dpp_dppclk_control(dpp, false, false); - - if (opp_id != 0xf && pipe_ctx->stream_res.opp->mpc_tree_params.opp_list == NULL) - pipe_ctx->stream_res.opp->funcs->opp_pipe_clock_control( - pipe_ctx->stream_res.opp, - false); - - hubp->power_gated = true; - dc->optimized_required = false; /* We're powering off, no need to optimize */ - - hws->funcs.plane_atomic_power_down(dc, - pipe_ctx->plane_res.dpp, - pipe_ctx->plane_res.hubp); - - pipe_ctx->stream = NULL; - memset(&pipe_ctx->stream_res, 0, sizeof(pipe_ctx->stream_res)); - memset(&pipe_ctx->plane_res, 0, sizeof(pipe_ctx->plane_res)); - pipe_ctx->top_pipe = NULL; - pipe_ctx->bottom_pipe = NULL; - pipe_ctx->plane_state = NULL; -} - -void dcn10_disable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx) -{ - struct dce_hwseq *hws = dc->hwseq; - DC_LOGGER_INIT(dc->ctx->logger); - - if (!pipe_ctx->plane_res.hubp || pipe_ctx->plane_res.hubp->power_gated) - return; - - hws->funcs.plane_atomic_disable(dc, pipe_ctx); - - apply_DEGVIDCN10_253_wa(dc); - - DC_LOG_DC("Power down front end %d\n", - pipe_ctx->pipe_idx); -} - -void dcn10_init_pipes(struct dc *dc, struct dc_state *context) -{ - int i; - struct dce_hwseq *hws = dc->hwseq; - struct hubbub *hubbub = dc->res_pool->hubbub; - bool can_apply_seamless_boot = false; - - for (i = 0; i < context->stream_count; i++) { - if (context->streams[i]->apply_seamless_boot_optimization) { - can_apply_seamless_boot = true; - break; - } - } - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct timing_generator *tg = dc->res_pool->timing_generators[i]; - struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; - - /* There is assumption that pipe_ctx is not mapping irregularly - * to non-preferred front end. If pipe_ctx->stream is not NULL, - * we will use the pipe, so don't disable - */ - if (pipe_ctx->stream != NULL && can_apply_seamless_boot) - continue; - - /* Blank controller using driver code instead of - * command table. - */ - if (tg->funcs->is_tg_enabled(tg)) { - if (hws->funcs.init_blank != NULL) { - hws->funcs.init_blank(dc, tg); - tg->funcs->lock(tg); - } else { - tg->funcs->lock(tg); - tg->funcs->set_blank(tg, true); - hwss_wait_for_blank_complete(tg); - } - } - } - - /* Reset det size */ - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; - struct hubp *hubp = dc->res_pool->hubps[i]; - - /* Do not need to reset for seamless boot */ - if (pipe_ctx->stream != NULL && can_apply_seamless_boot) - continue; - - if (hubbub && hubp) { - if (hubbub->funcs->program_det_size) - hubbub->funcs->program_det_size(hubbub, hubp->inst, 0); - } - } - - /* num_opp will be equal to number of mpcc */ - for (i = 0; i < dc->res_pool->res_cap->num_opp; i++) { - struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; - - /* Cannot reset the MPC mux if seamless boot */ - if (pipe_ctx->stream != NULL && can_apply_seamless_boot) - continue; - - dc->res_pool->mpc->funcs->mpc_init_single_inst( - dc->res_pool->mpc, i); - } - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct timing_generator *tg = dc->res_pool->timing_generators[i]; - struct hubp *hubp = dc->res_pool->hubps[i]; - struct dpp *dpp = dc->res_pool->dpps[i]; - struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; - - /* There is assumption that pipe_ctx is not mapping irregularly - * to non-preferred front end. If pipe_ctx->stream is not NULL, - * we will use the pipe, so don't disable - */ - if (can_apply_seamless_boot && - pipe_ctx->stream != NULL && - pipe_ctx->stream_res.tg->funcs->is_tg_enabled( - pipe_ctx->stream_res.tg)) { - // Enable double buffering for OTG_BLANK no matter if - // seamless boot is enabled or not to suppress global sync - // signals when OTG blanked. This is to prevent pipe from - // requesting data while in PSR. - tg->funcs->tg_init(tg); - hubp->power_gated = true; - continue; - } - - /* Disable on the current state so the new one isn't cleared. */ - pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i]; - - dpp->funcs->dpp_reset(dpp); - - pipe_ctx->stream_res.tg = tg; - pipe_ctx->pipe_idx = i; - - pipe_ctx->plane_res.hubp = hubp; - pipe_ctx->plane_res.dpp = dpp; - pipe_ctx->plane_res.mpcc_inst = dpp->inst; - hubp->mpcc_id = dpp->inst; - hubp->opp_id = OPP_ID_INVALID; - hubp->power_gated = false; - - dc->res_pool->opps[i]->mpc_tree_params.opp_id = dc->res_pool->opps[i]->inst; - dc->res_pool->opps[i]->mpc_tree_params.opp_list = NULL; - dc->res_pool->opps[i]->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true; - pipe_ctx->stream_res.opp = dc->res_pool->opps[i]; - - hws->funcs.plane_atomic_disconnect(dc, pipe_ctx); - - if (tg->funcs->is_tg_enabled(tg)) - tg->funcs->unlock(tg); - - dc->hwss.disable_plane(dc, pipe_ctx); - - pipe_ctx->stream_res.tg = NULL; - pipe_ctx->plane_res.hubp = NULL; - - if (tg->funcs->is_tg_enabled(tg)) { - if (tg->funcs->init_odm) - tg->funcs->init_odm(tg); - } - - tg->funcs->tg_init(tg); - } - - /* Power gate DSCs */ - if (hws->funcs.dsc_pg_control != NULL) { - uint32_t num_opps = 0; - uint32_t opp_id_src0 = OPP_ID_INVALID; - uint32_t opp_id_src1 = OPP_ID_INVALID; - - // Step 1: To find out which OPTC is running & OPTC DSC is ON - // We can't use res_pool->res_cap->num_timing_generator to check - // Because it records display pipes default setting built in driver, - // not display pipes of the current chip. - // Some ASICs would be fused display pipes less than the default setting. - // In dcnxx_resource_construct function, driver would obatin real information. - for (i = 0; i < dc->res_pool->timing_generator_count; i++) { - uint32_t optc_dsc_state = 0; - struct timing_generator *tg = dc->res_pool->timing_generators[i]; - - if (tg->funcs->is_tg_enabled(tg)) { - if (tg->funcs->get_dsc_status) - tg->funcs->get_dsc_status(tg, &optc_dsc_state); - // Only one OPTC with DSC is ON, so if we got one result, we would exit this block. - // non-zero value is DSC enabled - if (optc_dsc_state != 0) { - tg->funcs->get_optc_source(tg, &num_opps, &opp_id_src0, &opp_id_src1); - break; - } - } - } - - // Step 2: To power down DSC but skip DSC of running OPTC - for (i = 0; i < dc->res_pool->res_cap->num_dsc; i++) { - struct dcn_dsc_state s = {0}; - - dc->res_pool->dscs[i]->funcs->dsc_read_state(dc->res_pool->dscs[i], &s); - - if ((s.dsc_opp_source == opp_id_src0 || s.dsc_opp_source == opp_id_src1) && - s.dsc_clock_en && s.dsc_fw_en) - continue; - - hws->funcs.dsc_pg_control(hws, dc->res_pool->dscs[i]->inst, false); - } - } -} - -void dcn10_init_hw(struct dc *dc) -{ - int i; - struct abm *abm = dc->res_pool->abm; - struct dmcu *dmcu = dc->res_pool->dmcu; - struct dce_hwseq *hws = dc->hwseq; - struct dc_bios *dcb = dc->ctx->dc_bios; - struct resource_pool *res_pool = dc->res_pool; - uint32_t backlight = MAX_BACKLIGHT_LEVEL; - bool is_optimized_init_done = false; - - if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks) - dc->clk_mgr->funcs->init_clocks(dc->clk_mgr); - - /* Align bw context with hw config when system resume. */ - if (dc->clk_mgr->clks.dispclk_khz != 0 && dc->clk_mgr->clks.dppclk_khz != 0) { - dc->current_state->bw_ctx.bw.dcn.clk.dispclk_khz = dc->clk_mgr->clks.dispclk_khz; - dc->current_state->bw_ctx.bw.dcn.clk.dppclk_khz = dc->clk_mgr->clks.dppclk_khz; - } - - // Initialize the dccg - if (dc->res_pool->dccg && dc->res_pool->dccg->funcs->dccg_init) - dc->res_pool->dccg->funcs->dccg_init(res_pool->dccg); - - if (!dcb->funcs->is_accelerated_mode(dcb)) - hws->funcs.disable_vga(dc->hwseq); - - if (!dc_dmub_srv_optimized_init_done(dc->ctx->dmub_srv)) - hws->funcs.bios_golden_init(dc); - - - if (dc->ctx->dc_bios->fw_info_valid) { - res_pool->ref_clocks.xtalin_clock_inKhz = - dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency; - - if (res_pool->dccg && res_pool->hubbub) { - - (res_pool->dccg->funcs->get_dccg_ref_freq)(res_pool->dccg, - dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency, - &res_pool->ref_clocks.dccg_ref_clock_inKhz); - - (res_pool->hubbub->funcs->get_dchub_ref_freq)(res_pool->hubbub, - res_pool->ref_clocks.dccg_ref_clock_inKhz, - &res_pool->ref_clocks.dchub_ref_clock_inKhz); - } else { - // Not all ASICs have DCCG sw component - res_pool->ref_clocks.dccg_ref_clock_inKhz = - res_pool->ref_clocks.xtalin_clock_inKhz; - res_pool->ref_clocks.dchub_ref_clock_inKhz = - res_pool->ref_clocks.xtalin_clock_inKhz; - } - } else - ASSERT_CRITICAL(false); - - for (i = 0; i < dc->link_count; i++) { - /* Power up AND update implementation according to the - * required signal (which may be different from the - * default signal on connector). - */ - struct dc_link *link = dc->links[i]; - - if (!is_optimized_init_done) - link->link_enc->funcs->hw_init(link->link_enc); - - /* Check for enabled DIG to identify enabled display */ - if (link->link_enc->funcs->is_dig_enabled && - link->link_enc->funcs->is_dig_enabled(link->link_enc)) { - link->link_status.link_active = true; - if (link->link_enc->funcs->fec_is_active && - link->link_enc->funcs->fec_is_active(link->link_enc)) - link->fec_state = dc_link_fec_enabled; - } - } - - /* we want to turn off all dp displays before doing detection */ - dc->link_srv->blank_all_dp_displays(dc); - - if (hws->funcs.enable_power_gating_plane) - hws->funcs.enable_power_gating_plane(dc->hwseq, true); - - /* If taking control over from VBIOS, we may want to optimize our first - * mode set, so we need to skip powering down pipes until we know which - * pipes we want to use. - * Otherwise, if taking control is not possible, we need to power - * everything down. - */ - if (dcb->funcs->is_accelerated_mode(dcb) || !dc->config.seamless_boot_edp_requested) { - if (!is_optimized_init_done) { - hws->funcs.init_pipes(dc, dc->current_state); - if (dc->res_pool->hubbub->funcs->allow_self_refresh_control) - dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub, - !dc->res_pool->hubbub->ctx->dc->debug.disable_stutter); - } - } - - if (!is_optimized_init_done) { - - for (i = 0; i < res_pool->audio_count; i++) { - struct audio *audio = res_pool->audios[i]; - - audio->funcs->hw_init(audio); - } - - for (i = 0; i < dc->link_count; i++) { - struct dc_link *link = dc->links[i]; - - if (link->panel_cntl) - backlight = link->panel_cntl->funcs->hw_init(link->panel_cntl); - } - - if (abm != NULL) - abm->funcs->abm_init(abm, backlight); - - if (dmcu != NULL && !dmcu->auto_load_dmcu) - dmcu->funcs->dmcu_init(dmcu); - } - - if (abm != NULL && dmcu != NULL) - abm->dmcu_is_running = dmcu->funcs->is_dmcu_initialized(dmcu); - - /* power AFMT HDMI memory TODO: may move to dis/en output save power*/ - if (!is_optimized_init_done) - REG_WRITE(DIO_MEM_PWR_CTRL, 0); - - if (!dc->debug.disable_clock_gate) { - /* enable all DCN clock gating */ - REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0); - - REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0); - - REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0); - } - - if (dc->clk_mgr->funcs->notify_wm_ranges) - dc->clk_mgr->funcs->notify_wm_ranges(dc->clk_mgr); -} - -/* In headless boot cases, DIG may be turned - * on which causes HW/SW discrepancies. - * To avoid this, power down hardware on boot - * if DIG is turned on - */ -void dcn10_power_down_on_boot(struct dc *dc) -{ - struct dc_link *edp_links[MAX_NUM_EDP]; - struct dc_link *edp_link = NULL; - int edp_num; - int i = 0; - - dc_get_edp_links(dc, edp_links, &edp_num); - if (edp_num) - edp_link = edp_links[0]; - - if (edp_link && edp_link->link_enc->funcs->is_dig_enabled && - edp_link->link_enc->funcs->is_dig_enabled(edp_link->link_enc) && - dc->hwseq->funcs.edp_backlight_control && - dc->hwss.power_down && - dc->hwss.edp_power_control) { - dc->hwseq->funcs.edp_backlight_control(edp_link, false); - dc->hwss.power_down(dc); - dc->hwss.edp_power_control(edp_link, false); - } else { - for (i = 0; i < dc->link_count; i++) { - struct dc_link *link = dc->links[i]; - - if (link->link_enc && link->link_enc->funcs->is_dig_enabled && - link->link_enc->funcs->is_dig_enabled(link->link_enc) && - dc->hwss.power_down) { - dc->hwss.power_down(dc); - break; - } - - } - } - - /* - * Call update_clocks with empty context - * to send DISPLAY_OFF - * Otherwise DISPLAY_OFF may not be asserted - */ - if (dc->clk_mgr->funcs->set_low_power_state) - dc->clk_mgr->funcs->set_low_power_state(dc->clk_mgr); -} - -void dcn10_reset_hw_ctx_wrap( - struct dc *dc, - struct dc_state *context) -{ - int i; - struct dce_hwseq *hws = dc->hwseq; - - /* Reset Back End*/ - for (i = dc->res_pool->pipe_count - 1; i >= 0 ; i--) { - struct pipe_ctx *pipe_ctx_old = - &dc->current_state->res_ctx.pipe_ctx[i]; - struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; - - if (!pipe_ctx_old->stream) - continue; - - if (pipe_ctx_old->top_pipe) - continue; - - if (!pipe_ctx->stream || - pipe_need_reprogram(pipe_ctx_old, pipe_ctx)) { - struct clock_source *old_clk = pipe_ctx_old->clock_source; - - dcn10_reset_back_end_for_pipe(dc, pipe_ctx_old, dc->current_state); - if (hws->funcs.enable_stream_gating) - hws->funcs.enable_stream_gating(dc, pipe_ctx_old); - if (old_clk) - old_clk->funcs->cs_power_down(old_clk); - } - } -} - -static bool patch_address_for_sbs_tb_stereo( - struct pipe_ctx *pipe_ctx, PHYSICAL_ADDRESS_LOC *addr) -{ - struct dc_plane_state *plane_state = pipe_ctx->plane_state; - bool sec_split = pipe_ctx->top_pipe && - pipe_ctx->top_pipe->plane_state == pipe_ctx->plane_state; - if (sec_split && plane_state->address.type == PLN_ADDR_TYPE_GRPH_STEREO && - (pipe_ctx->stream->timing.timing_3d_format == - TIMING_3D_FORMAT_SIDE_BY_SIDE || - pipe_ctx->stream->timing.timing_3d_format == - TIMING_3D_FORMAT_TOP_AND_BOTTOM)) { - *addr = plane_state->address.grph_stereo.left_addr; - plane_state->address.grph_stereo.left_addr = - plane_state->address.grph_stereo.right_addr; - return true; - } else { - if (pipe_ctx->stream->view_format != VIEW_3D_FORMAT_NONE && - plane_state->address.type != PLN_ADDR_TYPE_GRPH_STEREO) { - plane_state->address.type = PLN_ADDR_TYPE_GRPH_STEREO; - plane_state->address.grph_stereo.right_addr = - plane_state->address.grph_stereo.left_addr; - plane_state->address.grph_stereo.right_meta_addr = - plane_state->address.grph_stereo.left_meta_addr; - } - } - return false; -} - -void dcn10_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx) -{ - bool addr_patched = false; - PHYSICAL_ADDRESS_LOC addr; - struct dc_plane_state *plane_state = pipe_ctx->plane_state; - - if (plane_state == NULL) - return; - - addr_patched = patch_address_for_sbs_tb_stereo(pipe_ctx, &addr); - - pipe_ctx->plane_res.hubp->funcs->hubp_program_surface_flip_and_addr( - pipe_ctx->plane_res.hubp, - &plane_state->address, - plane_state->flip_immediate); - - plane_state->status.requested_address = plane_state->address; - - if (plane_state->flip_immediate) - plane_state->status.current_address = plane_state->address; - - if (addr_patched) - pipe_ctx->plane_state->address.grph_stereo.left_addr = addr; -} - -bool dcn10_set_input_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx, - const struct dc_plane_state *plane_state) -{ - struct dpp *dpp_base = pipe_ctx->plane_res.dpp; - const struct dc_transfer_func *tf = NULL; - bool result = true; - - if (dpp_base == NULL) - return false; - - if (plane_state->in_transfer_func) - tf = plane_state->in_transfer_func; - - if (plane_state->gamma_correction && - !dpp_base->ctx->dc->debug.always_use_regamma - && !plane_state->gamma_correction->is_identity - && dce_use_lut(plane_state->format)) - dpp_base->funcs->dpp_program_input_lut(dpp_base, plane_state->gamma_correction); - - if (tf == NULL) - dpp_base->funcs->dpp_set_degamma(dpp_base, IPP_DEGAMMA_MODE_BYPASS); - else if (tf->type == TF_TYPE_PREDEFINED) { - switch (tf->tf) { - case TRANSFER_FUNCTION_SRGB: - dpp_base->funcs->dpp_set_degamma(dpp_base, IPP_DEGAMMA_MODE_HW_sRGB); - break; - case TRANSFER_FUNCTION_BT709: - dpp_base->funcs->dpp_set_degamma(dpp_base, IPP_DEGAMMA_MODE_HW_xvYCC); - break; - case TRANSFER_FUNCTION_LINEAR: - dpp_base->funcs->dpp_set_degamma(dpp_base, IPP_DEGAMMA_MODE_BYPASS); - break; - case TRANSFER_FUNCTION_PQ: - dpp_base->funcs->dpp_set_degamma(dpp_base, IPP_DEGAMMA_MODE_USER_PWL); - cm_helper_translate_curve_to_degamma_hw_format(tf, &dpp_base->degamma_params); - dpp_base->funcs->dpp_program_degamma_pwl(dpp_base, &dpp_base->degamma_params); - result = true; - break; - default: - result = false; - break; - } - } else if (tf->type == TF_TYPE_BYPASS) { - dpp_base->funcs->dpp_set_degamma(dpp_base, IPP_DEGAMMA_MODE_BYPASS); - } else { - cm_helper_translate_curve_to_degamma_hw_format(tf, - &dpp_base->degamma_params); - dpp_base->funcs->dpp_program_degamma_pwl(dpp_base, - &dpp_base->degamma_params); - result = true; - } - - return result; -} - -#define MAX_NUM_HW_POINTS 0x200 - -static void log_tf(struct dc_context *ctx, - struct dc_transfer_func *tf, uint32_t hw_points_num) -{ - // DC_LOG_GAMMA is default logging of all hw points - // DC_LOG_ALL_GAMMA logs all points, not only hw points - // DC_LOG_ALL_TF_POINTS logs all channels of the tf - int i = 0; - - DC_LOGGER_INIT(ctx->logger); - DC_LOG_GAMMA("Gamma Correction TF"); - DC_LOG_ALL_GAMMA("Logging all tf points..."); - DC_LOG_ALL_TF_CHANNELS("Logging all channels..."); - - for (i = 0; i < hw_points_num; i++) { - DC_LOG_GAMMA("R\t%d\t%llu", i, tf->tf_pts.red[i].value); - DC_LOG_ALL_TF_CHANNELS("G\t%d\t%llu", i, tf->tf_pts.green[i].value); - DC_LOG_ALL_TF_CHANNELS("B\t%d\t%llu", i, tf->tf_pts.blue[i].value); - } - - for (i = hw_points_num; i < MAX_NUM_HW_POINTS; i++) { - DC_LOG_ALL_GAMMA("R\t%d\t%llu", i, tf->tf_pts.red[i].value); - DC_LOG_ALL_TF_CHANNELS("G\t%d\t%llu", i, tf->tf_pts.green[i].value); - DC_LOG_ALL_TF_CHANNELS("B\t%d\t%llu", i, tf->tf_pts.blue[i].value); - } -} - -bool dcn10_set_output_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx, - const struct dc_stream_state *stream) -{ - struct dpp *dpp = pipe_ctx->plane_res.dpp; - - if (dpp == NULL) - return false; - - dpp->regamma_params.hw_points_num = GAMMA_HW_POINTS_NUM; - - if (stream->out_transfer_func && - stream->out_transfer_func->type == TF_TYPE_PREDEFINED && - stream->out_transfer_func->tf == TRANSFER_FUNCTION_SRGB) - dpp->funcs->dpp_program_regamma_pwl(dpp, NULL, OPP_REGAMMA_SRGB); - - /* dcn10_translate_regamma_to_hw_format takes 750us, only do it when full - * update. - */ - else if (cm_helper_translate_curve_to_hw_format(dc->ctx, - stream->out_transfer_func, - &dpp->regamma_params, false)) { - dpp->funcs->dpp_program_regamma_pwl( - dpp, - &dpp->regamma_params, OPP_REGAMMA_USER); - } else - dpp->funcs->dpp_program_regamma_pwl(dpp, NULL, OPP_REGAMMA_BYPASS); - - if (stream != NULL && stream->ctx != NULL && - stream->out_transfer_func != NULL) { - log_tf(stream->ctx, - stream->out_transfer_func, - dpp->regamma_params.hw_points_num); - } - - return true; -} - -void dcn10_pipe_control_lock( - struct dc *dc, - struct pipe_ctx *pipe, - bool lock) -{ - struct dce_hwseq *hws = dc->hwseq; - - /* use TG master update lock to lock everything on the TG - * therefore only top pipe need to lock - */ - if (!pipe || pipe->top_pipe) - return; - - if (dc->debug.sanity_checks) - hws->funcs.verify_allow_pstate_change_high(dc); - - if (lock) - pipe->stream_res.tg->funcs->lock(pipe->stream_res.tg); - else - pipe->stream_res.tg->funcs->unlock(pipe->stream_res.tg); - - if (dc->debug.sanity_checks) - hws->funcs.verify_allow_pstate_change_high(dc); -} - -/** - * delay_cursor_until_vupdate() - Delay cursor update if too close to VUPDATE. - * - * Software keepout workaround to prevent cursor update locking from stalling - * out cursor updates indefinitely or from old values from being retained in - * the case where the viewport changes in the same frame as the cursor. - * - * The idea is to calculate the remaining time from VPOS to VUPDATE. If it's - * too close to VUPDATE, then stall out until VUPDATE finishes. - * - * TODO: Optimize cursor programming to be once per frame before VUPDATE - * to avoid the need for this workaround. - * - * @dc: Current DC state - * @pipe_ctx: Pipe_ctx pointer for delayed cursor update - * - * Return: void - */ -static void delay_cursor_until_vupdate(struct dc *dc, struct pipe_ctx *pipe_ctx) -{ - struct dc_stream_state *stream = pipe_ctx->stream; - struct crtc_position position; - uint32_t vupdate_start, vupdate_end; - unsigned int lines_to_vupdate, us_to_vupdate, vpos; - unsigned int us_per_line, us_vupdate; - - if (!dc->hwss.calc_vupdate_position || !dc->hwss.get_position) - return; - - if (!pipe_ctx->stream_res.stream_enc || !pipe_ctx->stream_res.tg) - return; - - dc->hwss.calc_vupdate_position(dc, pipe_ctx, &vupdate_start, - &vupdate_end); - - dc->hwss.get_position(&pipe_ctx, 1, &position); - vpos = position.vertical_count; - - /* Avoid wraparound calculation issues */ - vupdate_start += stream->timing.v_total; - vupdate_end += stream->timing.v_total; - vpos += stream->timing.v_total; - - if (vpos <= vupdate_start) { - /* VPOS is in VACTIVE or back porch. */ - lines_to_vupdate = vupdate_start - vpos; - } else if (vpos > vupdate_end) { - /* VPOS is in the front porch. */ - return; - } else { - /* VPOS is in VUPDATE. */ - lines_to_vupdate = 0; - } - - /* Calculate time until VUPDATE in microseconds. */ - us_per_line = - stream->timing.h_total * 10000u / stream->timing.pix_clk_100hz; - us_to_vupdate = lines_to_vupdate * us_per_line; - - /* 70 us is a conservative estimate of cursor update time*/ - if (us_to_vupdate > 70) - return; - - /* Stall out until the cursor update completes. */ - if (vupdate_end < vupdate_start) - vupdate_end += stream->timing.v_total; - us_vupdate = (vupdate_end - vupdate_start + 1) * us_per_line; - udelay(us_to_vupdate + us_vupdate); -} - -void dcn10_cursor_lock(struct dc *dc, struct pipe_ctx *pipe, bool lock) -{ - /* cursor lock is per MPCC tree, so only need to lock one pipe per stream */ - if (!pipe || pipe->top_pipe) - return; - - /* Prevent cursor lock from stalling out cursor updates. */ - if (lock) - delay_cursor_until_vupdate(dc, pipe); - - if (pipe->stream && should_use_dmub_lock(pipe->stream->link)) { - union dmub_hw_lock_flags hw_locks = { 0 }; - struct dmub_hw_lock_inst_flags inst_flags = { 0 }; - - hw_locks.bits.lock_cursor = 1; - inst_flags.opp_inst = pipe->stream_res.opp->inst; - - dmub_hw_lock_mgr_cmd(dc->ctx->dmub_srv, - lock, - &hw_locks, - &inst_flags); - } else - dc->res_pool->mpc->funcs->cursor_lock(dc->res_pool->mpc, - pipe->stream_res.opp->inst, lock); -} - -static bool wait_for_reset_trigger_to_occur( - struct dc_context *dc_ctx, - struct timing_generator *tg) -{ - bool rc = false; - - /* To avoid endless loop we wait at most - * frames_to_wait_on_triggered_reset frames for the reset to occur. */ - const uint32_t frames_to_wait_on_triggered_reset = 10; - int i; - - for (i = 0; i < frames_to_wait_on_triggered_reset; i++) { - - if (!tg->funcs->is_counter_moving(tg)) { - DC_ERROR("TG counter is not moving!\n"); - break; - } - - if (tg->funcs->did_triggered_reset_occur(tg)) { - rc = true; - /* usually occurs at i=1 */ - DC_SYNC_INFO("GSL: reset occurred at wait count: %d\n", - i); - break; - } - - /* Wait for one frame. */ - tg->funcs->wait_for_state(tg, CRTC_STATE_VACTIVE); - tg->funcs->wait_for_state(tg, CRTC_STATE_VBLANK); - } - - if (false == rc) - DC_ERROR("GSL: Timeout on reset trigger!\n"); - - return rc; -} - -static uint64_t reduceSizeAndFraction(uint64_t *numerator, - uint64_t *denominator, - bool checkUint32Bounary) -{ - int i; - bool ret = checkUint32Bounary == false; - uint64_t max_int32 = 0xffffffff; - uint64_t num, denom; - static const uint16_t prime_numbers[] = { - 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, - 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, - 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, - 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, - 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, - 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, - 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, - 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, - 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, - 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, - 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, - 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, - 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, - 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, - 941, 947, 953, 967, 971, 977, 983, 991, 997}; - int count = ARRAY_SIZE(prime_numbers); - - num = *numerator; - denom = *denominator; - for (i = 0; i < count; i++) { - uint32_t num_remainder, denom_remainder; - uint64_t num_result, denom_result; - if (checkUint32Bounary && - num <= max_int32 && denom <= max_int32) { - ret = true; - break; - } - do { - num_result = div_u64_rem(num, prime_numbers[i], &num_remainder); - denom_result = div_u64_rem(denom, prime_numbers[i], &denom_remainder); - if (num_remainder == 0 && denom_remainder == 0) { - num = num_result; - denom = denom_result; - } - } while (num_remainder == 0 && denom_remainder == 0); - } - *numerator = num; - *denominator = denom; - return ret; -} - -static bool is_low_refresh_rate(struct pipe_ctx *pipe) -{ - uint32_t master_pipe_refresh_rate = - pipe->stream->timing.pix_clk_100hz * 100 / - pipe->stream->timing.h_total / - pipe->stream->timing.v_total; - return master_pipe_refresh_rate <= 30; -} - -static uint8_t get_clock_divider(struct pipe_ctx *pipe, - bool account_low_refresh_rate) -{ - uint32_t clock_divider = 1; - uint32_t numpipes = 1; - - if (account_low_refresh_rate && is_low_refresh_rate(pipe)) - clock_divider *= 2; - - if (pipe->stream_res.pix_clk_params.pixel_encoding == PIXEL_ENCODING_YCBCR420) - clock_divider *= 2; - - while (pipe->next_odm_pipe) { - pipe = pipe->next_odm_pipe; - numpipes++; - } - clock_divider *= numpipes; - - return clock_divider; -} - -static int dcn10_align_pixel_clocks(struct dc *dc, int group_size, - struct pipe_ctx *grouped_pipes[]) -{ - struct dc_context *dc_ctx = dc->ctx; - int i, master = -1, embedded = -1; - struct dc_crtc_timing *hw_crtc_timing; - uint64_t phase[MAX_PIPES]; - uint64_t modulo[MAX_PIPES]; - unsigned int pclk; - - uint32_t embedded_pix_clk_100hz; - uint16_t embedded_h_total; - uint16_t embedded_v_total; - uint32_t dp_ref_clk_100hz = - dc->res_pool->dp_clock_source->ctx->dc->clk_mgr->dprefclk_khz*10; - - hw_crtc_timing = kcalloc(MAX_PIPES, sizeof(*hw_crtc_timing), GFP_KERNEL); - if (!hw_crtc_timing) - return master; - - if (dc->config.vblank_alignment_dto_params && - dc->res_pool->dp_clock_source->funcs->override_dp_pix_clk) { - embedded_h_total = - (dc->config.vblank_alignment_dto_params >> 32) & 0x7FFF; - embedded_v_total = - (dc->config.vblank_alignment_dto_params >> 48) & 0x7FFF; - embedded_pix_clk_100hz = - dc->config.vblank_alignment_dto_params & 0xFFFFFFFF; - - for (i = 0; i < group_size; i++) { - grouped_pipes[i]->stream_res.tg->funcs->get_hw_timing( - grouped_pipes[i]->stream_res.tg, - &hw_crtc_timing[i]); - dc->res_pool->dp_clock_source->funcs->get_pixel_clk_frequency_100hz( - dc->res_pool->dp_clock_source, - grouped_pipes[i]->stream_res.tg->inst, - &pclk); - hw_crtc_timing[i].pix_clk_100hz = pclk; - if (dc_is_embedded_signal( - grouped_pipes[i]->stream->signal)) { - embedded = i; - master = i; - phase[i] = embedded_pix_clk_100hz*100; - modulo[i] = dp_ref_clk_100hz*100; - } else { - - phase[i] = (uint64_t)embedded_pix_clk_100hz* - hw_crtc_timing[i].h_total* - hw_crtc_timing[i].v_total; - phase[i] = div_u64(phase[i], get_clock_divider(grouped_pipes[i], true)); - modulo[i] = (uint64_t)dp_ref_clk_100hz* - embedded_h_total* - embedded_v_total; - - if (reduceSizeAndFraction(&phase[i], - &modulo[i], true) == false) { - /* - * this will help to stop reporting - * this timing synchronizable - */ - DC_SYNC_INFO("Failed to reduce DTO parameters\n"); - grouped_pipes[i]->stream->has_non_synchronizable_pclk = true; - } - } - } - - for (i = 0; i < group_size; i++) { - if (i != embedded && !grouped_pipes[i]->stream->has_non_synchronizable_pclk) { - dc->res_pool->dp_clock_source->funcs->override_dp_pix_clk( - dc->res_pool->dp_clock_source, - grouped_pipes[i]->stream_res.tg->inst, - phase[i], modulo[i]); - dc->res_pool->dp_clock_source->funcs->get_pixel_clk_frequency_100hz( - dc->res_pool->dp_clock_source, - grouped_pipes[i]->stream_res.tg->inst, &pclk); - grouped_pipes[i]->stream->timing.pix_clk_100hz = - pclk*get_clock_divider(grouped_pipes[i], false); - if (master == -1) - master = i; - } - } - - } - - kfree(hw_crtc_timing); - return master; -} - -void dcn10_enable_vblanks_synchronization( - struct dc *dc, - int group_index, - int group_size, - struct pipe_ctx *grouped_pipes[]) -{ - struct dc_context *dc_ctx = dc->ctx; - struct output_pixel_processor *opp; - struct timing_generator *tg; - int i, width, height, master; - - for (i = 1; i < group_size; i++) { - opp = grouped_pipes[i]->stream_res.opp; - tg = grouped_pipes[i]->stream_res.tg; - tg->funcs->get_otg_active_size(tg, &width, &height); - - if (!tg->funcs->is_tg_enabled(tg)) { - DC_SYNC_INFO("Skipping timing sync on disabled OTG\n"); - return; - } - - if (opp->funcs->opp_program_dpg_dimensions) - opp->funcs->opp_program_dpg_dimensions(opp, width, 2*(height) + 1); - } - - for (i = 0; i < group_size; i++) { - if (grouped_pipes[i]->stream == NULL) - continue; - grouped_pipes[i]->stream->vblank_synchronized = false; - grouped_pipes[i]->stream->has_non_synchronizable_pclk = false; - } - - DC_SYNC_INFO("Aligning DP DTOs\n"); - - master = dcn10_align_pixel_clocks(dc, group_size, grouped_pipes); - - DC_SYNC_INFO("Synchronizing VBlanks\n"); - - if (master >= 0) { - for (i = 0; i < group_size; i++) { - if (i != master && !grouped_pipes[i]->stream->has_non_synchronizable_pclk) - grouped_pipes[i]->stream_res.tg->funcs->align_vblanks( - grouped_pipes[master]->stream_res.tg, - grouped_pipes[i]->stream_res.tg, - grouped_pipes[master]->stream->timing.pix_clk_100hz, - grouped_pipes[i]->stream->timing.pix_clk_100hz, - get_clock_divider(grouped_pipes[master], false), - get_clock_divider(grouped_pipes[i], false)); - grouped_pipes[i]->stream->vblank_synchronized = true; - } - grouped_pipes[master]->stream->vblank_synchronized = true; - DC_SYNC_INFO("Sync complete\n"); - } - - for (i = 1; i < group_size; i++) { - opp = grouped_pipes[i]->stream_res.opp; - tg = grouped_pipes[i]->stream_res.tg; - tg->funcs->get_otg_active_size(tg, &width, &height); - if (opp->funcs->opp_program_dpg_dimensions) - opp->funcs->opp_program_dpg_dimensions(opp, width, height); - } -} - -void dcn10_enable_timing_synchronization( - struct dc *dc, - int group_index, - int group_size, - struct pipe_ctx *grouped_pipes[]) -{ - struct dc_context *dc_ctx = dc->ctx; - struct output_pixel_processor *opp; - struct timing_generator *tg; - int i, width, height; - - DC_SYNC_INFO("Setting up OTG reset trigger\n"); - - for (i = 1; i < group_size; i++) { - if (grouped_pipes[i]->stream && grouped_pipes[i]->stream->mall_stream_config.type == SUBVP_PHANTOM) - continue; - - opp = grouped_pipes[i]->stream_res.opp; - tg = grouped_pipes[i]->stream_res.tg; - tg->funcs->get_otg_active_size(tg, &width, &height); - - if (!tg->funcs->is_tg_enabled(tg)) { - DC_SYNC_INFO("Skipping timing sync on disabled OTG\n"); - return; - } - - if (opp->funcs->opp_program_dpg_dimensions) - opp->funcs->opp_program_dpg_dimensions(opp, width, 2*(height) + 1); - } - - for (i = 0; i < group_size; i++) { - if (grouped_pipes[i]->stream == NULL) - continue; - - if (grouped_pipes[i]->stream && grouped_pipes[i]->stream->mall_stream_config.type == SUBVP_PHANTOM) - continue; - - grouped_pipes[i]->stream->vblank_synchronized = false; - } - - for (i = 1; i < group_size; i++) { - if (grouped_pipes[i]->stream && grouped_pipes[i]->stream->mall_stream_config.type == SUBVP_PHANTOM) - continue; - - grouped_pipes[i]->stream_res.tg->funcs->enable_reset_trigger( - grouped_pipes[i]->stream_res.tg, - grouped_pipes[0]->stream_res.tg->inst); - } - - DC_SYNC_INFO("Waiting for trigger\n"); - - /* Need to get only check 1 pipe for having reset as all the others are - * synchronized. Look at last pipe programmed to reset. - */ - - if (grouped_pipes[1]->stream && grouped_pipes[1]->stream->mall_stream_config.type != SUBVP_PHANTOM) - wait_for_reset_trigger_to_occur(dc_ctx, grouped_pipes[1]->stream_res.tg); - - for (i = 1; i < group_size; i++) { - if (grouped_pipes[i]->stream && grouped_pipes[i]->stream->mall_stream_config.type == SUBVP_PHANTOM) - continue; - - grouped_pipes[i]->stream_res.tg->funcs->disable_reset_trigger( - grouped_pipes[i]->stream_res.tg); - } - - for (i = 1; i < group_size; i++) { - if (grouped_pipes[i]->stream && grouped_pipes[i]->stream->mall_stream_config.type == SUBVP_PHANTOM) - continue; - - opp = grouped_pipes[i]->stream_res.opp; - tg = grouped_pipes[i]->stream_res.tg; - tg->funcs->get_otg_active_size(tg, &width, &height); - if (opp->funcs->opp_program_dpg_dimensions) - opp->funcs->opp_program_dpg_dimensions(opp, width, height); - } - - DC_SYNC_INFO("Sync complete\n"); -} - -void dcn10_enable_per_frame_crtc_position_reset( - struct dc *dc, - int group_size, - struct pipe_ctx *grouped_pipes[]) -{ - struct dc_context *dc_ctx = dc->ctx; - int i; - - DC_SYNC_INFO("Setting up\n"); - for (i = 0; i < group_size; i++) - if (grouped_pipes[i]->stream_res.tg->funcs->enable_crtc_reset) - grouped_pipes[i]->stream_res.tg->funcs->enable_crtc_reset( - grouped_pipes[i]->stream_res.tg, - 0, - &grouped_pipes[i]->stream->triggered_crtc_reset); - - DC_SYNC_INFO("Waiting for trigger\n"); - - for (i = 0; i < group_size; i++) - wait_for_reset_trigger_to_occur(dc_ctx, grouped_pipes[i]->stream_res.tg); - - DC_SYNC_INFO("Multi-display sync is complete\n"); -} - -static void mmhub_read_vm_system_aperture_settings(struct dcn10_hubp *hubp1, - struct vm_system_aperture_param *apt, - struct dce_hwseq *hws) -{ - PHYSICAL_ADDRESS_LOC physical_page_number; - uint32_t logical_addr_low; - uint32_t logical_addr_high; - - REG_GET(MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB, - PHYSICAL_PAGE_NUMBER_MSB, &physical_page_number.high_part); - REG_GET(MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB, - PHYSICAL_PAGE_NUMBER_LSB, &physical_page_number.low_part); - - REG_GET(MC_VM_SYSTEM_APERTURE_LOW_ADDR, - LOGICAL_ADDR, &logical_addr_low); - - REG_GET(MC_VM_SYSTEM_APERTURE_HIGH_ADDR, - LOGICAL_ADDR, &logical_addr_high); - - apt->sys_default.quad_part = physical_page_number.quad_part << 12; - apt->sys_low.quad_part = (int64_t)logical_addr_low << 18; - apt->sys_high.quad_part = (int64_t)logical_addr_high << 18; -} - -/* Temporary read settings, future will get values from kmd directly */ -static void mmhub_read_vm_context0_settings(struct dcn10_hubp *hubp1, - struct vm_context0_param *vm0, - struct dce_hwseq *hws) -{ - PHYSICAL_ADDRESS_LOC fb_base; - PHYSICAL_ADDRESS_LOC fb_offset; - uint32_t fb_base_value; - uint32_t fb_offset_value; - - REG_GET(DCHUBBUB_SDPIF_FB_BASE, SDPIF_FB_BASE, &fb_base_value); - REG_GET(DCHUBBUB_SDPIF_FB_OFFSET, SDPIF_FB_OFFSET, &fb_offset_value); - - REG_GET(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32, - PAGE_DIRECTORY_ENTRY_HI32, &vm0->pte_base.high_part); - REG_GET(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LO32, - PAGE_DIRECTORY_ENTRY_LO32, &vm0->pte_base.low_part); - - REG_GET(VM_CONTEXT0_PAGE_TABLE_START_ADDR_HI32, - LOGICAL_PAGE_NUMBER_HI4, &vm0->pte_start.high_part); - REG_GET(VM_CONTEXT0_PAGE_TABLE_START_ADDR_LO32, - LOGICAL_PAGE_NUMBER_LO32, &vm0->pte_start.low_part); - - REG_GET(VM_CONTEXT0_PAGE_TABLE_END_ADDR_HI32, - LOGICAL_PAGE_NUMBER_HI4, &vm0->pte_end.high_part); - REG_GET(VM_CONTEXT0_PAGE_TABLE_END_ADDR_LO32, - LOGICAL_PAGE_NUMBER_LO32, &vm0->pte_end.low_part); - - REG_GET(VM_L2_PROTECTION_FAULT_DEFAULT_ADDR_HI32, - PHYSICAL_PAGE_ADDR_HI4, &vm0->fault_default.high_part); - REG_GET(VM_L2_PROTECTION_FAULT_DEFAULT_ADDR_LO32, - PHYSICAL_PAGE_ADDR_LO32, &vm0->fault_default.low_part); - - /* - * The values in VM_CONTEXT0_PAGE_TABLE_BASE_ADDR is in UMA space. - * Therefore we need to do - * DCN_VM_CONTEXT0_PAGE_TABLE_BASE_ADDR = VM_CONTEXT0_PAGE_TABLE_BASE_ADDR - * - DCHUBBUB_SDPIF_FB_OFFSET + DCHUBBUB_SDPIF_FB_BASE - */ - fb_base.quad_part = (uint64_t)fb_base_value << 24; - fb_offset.quad_part = (uint64_t)fb_offset_value << 24; - vm0->pte_base.quad_part += fb_base.quad_part; - vm0->pte_base.quad_part -= fb_offset.quad_part; -} - - -static void dcn10_program_pte_vm(struct dce_hwseq *hws, struct hubp *hubp) -{ - struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp); - struct vm_system_aperture_param apt = {0}; - struct vm_context0_param vm0 = {0}; - - mmhub_read_vm_system_aperture_settings(hubp1, &apt, hws); - mmhub_read_vm_context0_settings(hubp1, &vm0, hws); - - hubp->funcs->hubp_set_vm_system_aperture_settings(hubp, &apt); - hubp->funcs->hubp_set_vm_context0_settings(hubp, &vm0); -} - -static void dcn10_enable_plane( - struct dc *dc, - struct pipe_ctx *pipe_ctx, - struct dc_state *context) -{ - struct dce_hwseq *hws = dc->hwseq; - - if (dc->debug.sanity_checks) { - hws->funcs.verify_allow_pstate_change_high(dc); - } - - undo_DEGVIDCN10_253_wa(dc); - - power_on_plane_resources(dc->hwseq, - pipe_ctx->plane_res.hubp->inst); - - /* enable DCFCLK current DCHUB */ - pipe_ctx->plane_res.hubp->funcs->hubp_clk_cntl(pipe_ctx->plane_res.hubp, true); - - /* make sure OPP_PIPE_CLOCK_EN = 1 */ - pipe_ctx->stream_res.opp->funcs->opp_pipe_clock_control( - pipe_ctx->stream_res.opp, - true); - - if (dc->config.gpu_vm_support) - dcn10_program_pte_vm(hws, pipe_ctx->plane_res.hubp); - - if (dc->debug.sanity_checks) { - hws->funcs.verify_allow_pstate_change_high(dc); - } - - if (!pipe_ctx->top_pipe - && pipe_ctx->plane_state - && pipe_ctx->plane_state->flip_int_enabled - && pipe_ctx->plane_res.hubp->funcs->hubp_set_flip_int) - pipe_ctx->plane_res.hubp->funcs->hubp_set_flip_int(pipe_ctx->plane_res.hubp); - -} - -void dcn10_program_gamut_remap(struct pipe_ctx *pipe_ctx) -{ - int i = 0; - struct dpp_grph_csc_adjustment adjust; - memset(&adjust, 0, sizeof(adjust)); - adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS; - - - 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]; - } else if (pipe_ctx->plane_state && - pipe_ctx->plane_state->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->plane_state->gamut_remap_matrix.matrix[i]; - } - - pipe_ctx->plane_res.dpp->funcs->dpp_set_gamut_remap(pipe_ctx->plane_res.dpp, &adjust); -} - - -static bool dcn10_is_rear_mpo_fix_required(struct pipe_ctx *pipe_ctx, enum dc_color_space colorspace) -{ - if (pipe_ctx->plane_state && pipe_ctx->plane_state->layer_index > 0 && is_rgb_cspace(colorspace)) { - if (pipe_ctx->top_pipe) { - struct pipe_ctx *top = pipe_ctx->top_pipe; - - while (top->top_pipe) - top = top->top_pipe; // Traverse to top pipe_ctx - if (top->plane_state && top->plane_state->layer_index == 0) - return true; // Front MPO plane not hidden - } - } - return false; -} - -static void dcn10_set_csc_adjustment_rgb_mpo_fix(struct pipe_ctx *pipe_ctx, uint16_t *matrix) -{ - // Override rear plane RGB bias to fix MPO brightness - uint16_t rgb_bias = matrix[3]; - - matrix[3] = 0; - matrix[7] = 0; - matrix[11] = 0; - pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_adjustment(pipe_ctx->plane_res.dpp, matrix); - matrix[3] = rgb_bias; - matrix[7] = rgb_bias; - matrix[11] = rgb_bias; -} - -void dcn10_program_output_csc(struct dc *dc, - struct pipe_ctx *pipe_ctx, - enum dc_color_space colorspace, - uint16_t *matrix, - int opp_id) -{ - if (pipe_ctx->stream->csc_color_matrix.enable_adjustment == true) { - if (pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_adjustment != NULL) { - - /* MPO is broken with RGB colorspaces when OCSC matrix - * brightness offset >= 0 on DCN1 due to OCSC before MPC - * Blending adds offsets from front + rear to rear plane - * - * Fix is to set RGB bias to 0 on rear plane, top plane - * black value pixels add offset instead of rear + front - */ - - int16_t rgb_bias = matrix[3]; - // matrix[3/7/11] are all the same offset value - - if (rgb_bias > 0 && dcn10_is_rear_mpo_fix_required(pipe_ctx, colorspace)) { - dcn10_set_csc_adjustment_rgb_mpo_fix(pipe_ctx, matrix); - } else { - pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_adjustment(pipe_ctx->plane_res.dpp, matrix); - } - } - } else { - if (pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_default != NULL) - pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_default(pipe_ctx->plane_res.dpp, colorspace); - } -} - -static void dcn10_update_dpp(struct dpp *dpp, struct dc_plane_state *plane_state) -{ - struct dc_bias_and_scale bns_params = {0}; - - // program the input csc - dpp->funcs->dpp_setup(dpp, - plane_state->format, - EXPANSION_MODE_ZERO, - plane_state->input_csc_color_matrix, - plane_state->color_space, - NULL); - - //set scale and bias registers - build_prescale_params(&bns_params, plane_state); - if (dpp->funcs->dpp_program_bias_and_scale) - dpp->funcs->dpp_program_bias_and_scale(dpp, &bns_params); -} - -void dcn10_update_visual_confirm_color(struct dc *dc, - struct pipe_ctx *pipe_ctx, - int mpcc_id) -{ - struct mpc *mpc = dc->res_pool->mpc; - - if (mpc->funcs->set_bg_color) { - memcpy(&pipe_ctx->plane_state->visual_confirm_color, &(pipe_ctx->visual_confirm_color), sizeof(struct tg_color)); - mpc->funcs->set_bg_color(mpc, &(pipe_ctx->visual_confirm_color), mpcc_id); - } -} - -void dcn10_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx) -{ - struct hubp *hubp = pipe_ctx->plane_res.hubp; - struct mpcc_blnd_cfg blnd_cfg = {0}; - bool per_pixel_alpha = pipe_ctx->plane_state->per_pixel_alpha && pipe_ctx->bottom_pipe; - int mpcc_id; - struct mpcc *new_mpcc; - struct mpc *mpc = dc->res_pool->mpc; - struct mpc_tree *mpc_tree_params = &(pipe_ctx->stream_res.opp->mpc_tree_params); - - blnd_cfg.overlap_only = false; - blnd_cfg.global_gain = 0xff; - - if (per_pixel_alpha) { - /* DCN1.0 has output CM before MPC which seems to screw with - * pre-multiplied alpha. - */ - blnd_cfg.pre_multiplied_alpha = (is_rgb_cspace( - pipe_ctx->stream->output_color_space) - && pipe_ctx->plane_state->pre_multiplied_alpha); - if (pipe_ctx->plane_state->global_alpha) { - blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA_COMBINED_GLOBAL_GAIN; - blnd_cfg.global_gain = pipe_ctx->plane_state->global_alpha_value; - } else { - blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA; - } - } else { - blnd_cfg.pre_multiplied_alpha = false; - blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_GLOBAL_ALPHA; - } - - if (pipe_ctx->plane_state->global_alpha) - blnd_cfg.global_alpha = pipe_ctx->plane_state->global_alpha_value; - else - blnd_cfg.global_alpha = 0xff; - - /* - * TODO: remove hack - * Note: currently there is a bug in init_hw such that - * on resume from hibernate, BIOS sets up MPCC0, and - * we do mpcc_remove but the mpcc cannot go to idle - * after remove. This cause us to pick mpcc1 here, - * which causes a pstate hang for yet unknown reason. - */ - mpcc_id = hubp->inst; - - /* If there is no full update, don't need to touch MPC tree*/ - if (!pipe_ctx->plane_state->update_flags.bits.full_update) { - mpc->funcs->update_blending(mpc, &blnd_cfg, mpcc_id); - dc->hwss.update_visual_confirm_color(dc, pipe_ctx, mpcc_id); - return; - } - - /* check if this MPCC is already being used */ - new_mpcc = mpc->funcs->get_mpcc_for_dpp(mpc_tree_params, mpcc_id); - /* remove MPCC if being used */ - if (new_mpcc != NULL) - mpc->funcs->remove_mpcc(mpc, mpc_tree_params, new_mpcc); - else - if (dc->debug.sanity_checks) - mpc->funcs->assert_mpcc_idle_before_connect( - dc->res_pool->mpc, mpcc_id); - - /* Call MPC to insert new plane */ - new_mpcc = mpc->funcs->insert_plane(dc->res_pool->mpc, - mpc_tree_params, - &blnd_cfg, - NULL, - NULL, - hubp->inst, - mpcc_id); - dc->hwss.update_visual_confirm_color(dc, pipe_ctx, mpcc_id); - - ASSERT(new_mpcc != NULL); - hubp->opp_id = pipe_ctx->stream_res.opp->inst; - hubp->mpcc_id = mpcc_id; -} - -static void update_scaler(struct pipe_ctx *pipe_ctx) -{ - bool per_pixel_alpha = - pipe_ctx->plane_state->per_pixel_alpha && pipe_ctx->bottom_pipe; - - pipe_ctx->plane_res.scl_data.lb_params.alpha_en = per_pixel_alpha; - pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_36BPP; - /* scaler configuration */ - pipe_ctx->plane_res.dpp->funcs->dpp_set_scaler( - pipe_ctx->plane_res.dpp, &pipe_ctx->plane_res.scl_data); -} - -static void dcn10_update_dchubp_dpp( - struct dc *dc, - struct pipe_ctx *pipe_ctx, - struct dc_state *context) -{ - struct dce_hwseq *hws = dc->hwseq; - struct hubp *hubp = pipe_ctx->plane_res.hubp; - struct dpp *dpp = pipe_ctx->plane_res.dpp; - struct dc_plane_state *plane_state = pipe_ctx->plane_state; - struct plane_size size = plane_state->plane_size; - unsigned int compat_level = 0; - bool should_divided_by_2 = false; - - /* depends on DML calculation, DPP clock value may change dynamically */ - /* If request max dpp clk is lower than current dispclk, no need to - * divided by 2 - */ - if (plane_state->update_flags.bits.full_update) { - - /* new calculated dispclk, dppclk are stored in - * context->bw_ctx.bw.dcn.clk.dispclk_khz / dppclk_khz. current - * dispclk, dppclk are from dc->clk_mgr->clks.dispclk_khz. - * dcn10_validate_bandwidth compute new dispclk, dppclk. - * dispclk will put in use after optimize_bandwidth when - * ramp_up_dispclk_with_dpp is called. - * there are two places for dppclk be put in use. One location - * is the same as the location as dispclk. Another is within - * update_dchubp_dpp which happens between pre_bandwidth and - * optimize_bandwidth. - * dppclk updated within update_dchubp_dpp will cause new - * clock values of dispclk and dppclk not be in use at the same - * time. when clocks are decreased, this may cause dppclk is - * lower than previous configuration and let pipe stuck. - * for example, eDP + external dp, change resolution of DP from - * 1920x1080x144hz to 1280x960x60hz. - * before change: dispclk = 337889 dppclk = 337889 - * change mode, dcn10_validate_bandwidth calculate - * dispclk = 143122 dppclk = 143122 - * update_dchubp_dpp be executed before dispclk be updated, - * dispclk = 337889, but dppclk use new value dispclk /2 = - * 168944. this will cause pipe pstate warning issue. - * solution: between pre_bandwidth and optimize_bandwidth, while - * dispclk is going to be decreased, keep dppclk = dispclk - **/ - if (context->bw_ctx.bw.dcn.clk.dispclk_khz < - dc->clk_mgr->clks.dispclk_khz) - should_divided_by_2 = false; - else - should_divided_by_2 = - context->bw_ctx.bw.dcn.clk.dppclk_khz <= - dc->clk_mgr->clks.dispclk_khz / 2; - - dpp->funcs->dpp_dppclk_control( - dpp, - should_divided_by_2, - true); - - if (dc->res_pool->dccg) - dc->res_pool->dccg->funcs->update_dpp_dto( - dc->res_pool->dccg, - dpp->inst, - pipe_ctx->plane_res.bw.dppclk_khz); - else - dc->clk_mgr->clks.dppclk_khz = should_divided_by_2 ? - dc->clk_mgr->clks.dispclk_khz / 2 : - dc->clk_mgr->clks.dispclk_khz; - } - - /* TODO: Need input parameter to tell current DCHUB pipe tie to which OTG - * VTG is within DCHUBBUB which is commond block share by each pipe HUBP. - * VTG is 1:1 mapping with OTG. Each pipe HUBP will select which VTG - */ - if (plane_state->update_flags.bits.full_update) { - hubp->funcs->hubp_vtg_sel(hubp, pipe_ctx->stream_res.tg->inst); - - hubp->funcs->hubp_setup( - hubp, - &pipe_ctx->dlg_regs, - &pipe_ctx->ttu_regs, - &pipe_ctx->rq_regs, - &pipe_ctx->pipe_dlg_param); - hubp->funcs->hubp_setup_interdependent( - hubp, - &pipe_ctx->dlg_regs, - &pipe_ctx->ttu_regs); - } - - size.surface_size = pipe_ctx->plane_res.scl_data.viewport; - - if (plane_state->update_flags.bits.full_update || - plane_state->update_flags.bits.bpp_change) - dcn10_update_dpp(dpp, plane_state); - - if (plane_state->update_flags.bits.full_update || - plane_state->update_flags.bits.per_pixel_alpha_change || - plane_state->update_flags.bits.global_alpha_change) - hws->funcs.update_mpcc(dc, pipe_ctx); - - if (plane_state->update_flags.bits.full_update || - plane_state->update_flags.bits.per_pixel_alpha_change || - plane_state->update_flags.bits.global_alpha_change || - plane_state->update_flags.bits.scaling_change || - plane_state->update_flags.bits.position_change) { - update_scaler(pipe_ctx); - } - - if (plane_state->update_flags.bits.full_update || - plane_state->update_flags.bits.scaling_change || - plane_state->update_flags.bits.position_change) { - hubp->funcs->mem_program_viewport( - hubp, - &pipe_ctx->plane_res.scl_data.viewport, - &pipe_ctx->plane_res.scl_data.viewport_c); - } - - if (pipe_ctx->stream->cursor_attributes.address.quad_part != 0) { - dc->hwss.set_cursor_position(pipe_ctx); - dc->hwss.set_cursor_attribute(pipe_ctx); - - if (dc->hwss.set_cursor_sdr_white_level) - dc->hwss.set_cursor_sdr_white_level(pipe_ctx); - } - - if (plane_state->update_flags.bits.full_update) { - /*gamut remap*/ - dc->hwss.program_gamut_remap(pipe_ctx); - - dc->hwss.program_output_csc(dc, - pipe_ctx, - pipe_ctx->stream->output_color_space, - pipe_ctx->stream->csc_color_matrix.matrix, - pipe_ctx->stream_res.opp->inst); - } - - if (plane_state->update_flags.bits.full_update || - plane_state->update_flags.bits.pixel_format_change || - plane_state->update_flags.bits.horizontal_mirror_change || - plane_state->update_flags.bits.rotation_change || - plane_state->update_flags.bits.swizzle_change || - plane_state->update_flags.bits.dcc_change || - plane_state->update_flags.bits.bpp_change || - plane_state->update_flags.bits.scaling_change || - plane_state->update_flags.bits.plane_size_change) { - hubp->funcs->hubp_program_surface_config( - hubp, - plane_state->format, - &plane_state->tiling_info, - &size, - plane_state->rotation, - &plane_state->dcc, - plane_state->horizontal_mirror, - compat_level); - } - - hubp->power_gated = false; - - hws->funcs.update_plane_addr(dc, pipe_ctx); - - if (is_pipe_tree_visible(pipe_ctx)) - hubp->funcs->set_blank(hubp, false); -} - -void dcn10_blank_pixel_data( - struct dc *dc, - struct pipe_ctx *pipe_ctx, - bool blank) -{ - enum dc_color_space color_space; - struct tg_color black_color = {0}; - struct stream_resource *stream_res = &pipe_ctx->stream_res; - struct dc_stream_state *stream = pipe_ctx->stream; - - /* program otg blank color */ - color_space = stream->output_color_space; - color_space_to_black_color(dc, color_space, &black_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 (stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR420) - black_color.color_r_cr = black_color.color_g_y; - - - if (stream_res->tg->funcs->set_blank_color) - stream_res->tg->funcs->set_blank_color( - stream_res->tg, - &black_color); - - if (!blank) { - if (stream_res->tg->funcs->set_blank) - stream_res->tg->funcs->set_blank(stream_res->tg, blank); - if (stream_res->abm) { - dc->hwss.set_pipe(pipe_ctx); - stream_res->abm->funcs->set_abm_level(stream_res->abm, stream->abm_level); - } - } else { - dc->hwss.set_abm_immediate_disable(pipe_ctx); - if (stream_res->tg->funcs->set_blank) { - stream_res->tg->funcs->wait_for_state(stream_res->tg, CRTC_STATE_VBLANK); - stream_res->tg->funcs->set_blank(stream_res->tg, blank); - } - } -} - -void dcn10_set_hdr_multiplier(struct pipe_ctx *pipe_ctx) -{ - struct fixed31_32 multiplier = pipe_ctx->plane_state->hdr_mult; - uint32_t hw_mult = 0x1f000; // 1.0 default multiplier - struct custom_float_format fmt; - - fmt.exponenta_bits = 6; - fmt.mantissa_bits = 12; - fmt.sign = true; - - - if (!dc_fixpt_eq(multiplier, dc_fixpt_from_int(0))) // check != 0 - convert_to_custom_float_format(multiplier, &fmt, &hw_mult); - - pipe_ctx->plane_res.dpp->funcs->dpp_set_hdr_multiplier( - pipe_ctx->plane_res.dpp, hw_mult); -} - -void dcn10_program_pipe( - struct dc *dc, - struct pipe_ctx *pipe_ctx, - struct dc_state *context) -{ - struct dce_hwseq *hws = dc->hwseq; - - if (pipe_ctx->top_pipe == NULL) { - bool blank = !is_pipe_tree_visible(pipe_ctx); - - pipe_ctx->stream_res.tg->funcs->program_global_sync( - pipe_ctx->stream_res.tg, - calculate_vready_offset_for_group(pipe_ctx), - pipe_ctx->pipe_dlg_param.vstartup_start, - pipe_ctx->pipe_dlg_param.vupdate_offset, - pipe_ctx->pipe_dlg_param.vupdate_width); - - pipe_ctx->stream_res.tg->funcs->set_vtg_params( - pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing, true); - - if (hws->funcs.setup_vupdate_interrupt) - hws->funcs.setup_vupdate_interrupt(dc, pipe_ctx); - - hws->funcs.blank_pixel_data(dc, pipe_ctx, blank); - } - - if (pipe_ctx->plane_state->update_flags.bits.full_update) - dcn10_enable_plane(dc, pipe_ctx, context); - - dcn10_update_dchubp_dpp(dc, pipe_ctx, context); - - hws->funcs.set_hdr_multiplier(pipe_ctx); - - 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); - - /* dcn10_translate_regamma_to_hw_format takes 750us to finish - * only do gamma programming for full update. - * TODO: This can be further optimized/cleaned up - * Always call this for now since it does memcmp inside before - * doing heavy calculation and programming - */ - if (pipe_ctx->plane_state->update_flags.bits.full_update) - hws->funcs.set_output_transfer_func(dc, pipe_ctx, pipe_ctx->stream); -} - -void dcn10_wait_for_pending_cleared(struct dc *dc, - struct dc_state *context) -{ - struct pipe_ctx *pipe_ctx; - struct timing_generator *tg; - int i; - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - pipe_ctx = &context->res_ctx.pipe_ctx[i]; - tg = pipe_ctx->stream_res.tg; - - /* - * Only wait for top pipe's tg penindg bit - * Also skip if pipe is disabled. - */ - if (pipe_ctx->top_pipe || - !pipe_ctx->stream || !pipe_ctx->plane_state || - !tg->funcs->is_tg_enabled(tg)) - continue; - - /* - * Wait for VBLANK then VACTIVE to ensure we get VUPDATE. - * For some reason waiting for OTG_UPDATE_PENDING cleared - * seems to not trigger the update right away, and if we - * lock again before VUPDATE then we don't get a separated - * operation. - */ - pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VBLANK); - pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VACTIVE); - } -} - -void dcn10_post_unlock_program_front_end( - struct dc *dc, - struct dc_state *context) -{ - int i; - - DC_LOGGER_INIT(dc->ctx->logger); - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; - - if (!pipe_ctx->top_pipe && - !pipe_ctx->prev_odm_pipe && - pipe_ctx->stream) { - struct timing_generator *tg = pipe_ctx->stream_res.tg; - - if (context->stream_status[i].plane_count == 0) - false_optc_underflow_wa(dc, pipe_ctx->stream, tg); - } - } - - for (i = 0; i < dc->res_pool->pipe_count; i++) - if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable) - dc->hwss.disable_plane(dc, &dc->current_state->res_ctx.pipe_ctx[i]); - - for (i = 0; i < dc->res_pool->pipe_count; i++) - if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable) { - dc->hwss.optimize_bandwidth(dc, context); - break; - } - - if (dc->hwseq->wa.DEGVIDCN10_254) - hubbub1_wm_change_req_wa(dc->res_pool->hubbub); -} - -static void dcn10_stereo_hw_frame_pack_wa(struct dc *dc, struct dc_state *context) -{ - uint8_t i; - - for (i = 0; i < context->stream_count; i++) { - if (context->streams[i]->timing.timing_3d_format - == TIMING_3D_FORMAT_HW_FRAME_PACKING) { - /* - * Disable stutter - */ - hubbub1_allow_self_refresh_control(dc->res_pool->hubbub, false); - break; - } - } -} - -void dcn10_prepare_bandwidth( - struct dc *dc, - struct dc_state *context) -{ - struct dce_hwseq *hws = dc->hwseq; - struct hubbub *hubbub = dc->res_pool->hubbub; - int min_fclk_khz, min_dcfclk_khz, socclk_khz; - - if (dc->debug.sanity_checks) - hws->funcs.verify_allow_pstate_change_high(dc); - - if (context->stream_count == 0) - context->bw_ctx.bw.dcn.clk.phyclk_khz = 0; - - dc->clk_mgr->funcs->update_clocks( - dc->clk_mgr, - context, - false); - - dc->wm_optimized_required = hubbub->funcs->program_watermarks(hubbub, - &context->bw_ctx.bw.dcn.watermarks, - dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000, - true); - dcn10_stereo_hw_frame_pack_wa(dc, context); - - if (dc->debug.pplib_wm_report_mode == WM_REPORT_OVERRIDE) { - DC_FP_START(); - dcn_get_soc_clks( - dc, &min_fclk_khz, &min_dcfclk_khz, &socclk_khz); - DC_FP_END(); - dcn_bw_notify_pplib_of_wm_ranges( - dc, min_fclk_khz, min_dcfclk_khz, socclk_khz); - } - - if (dc->debug.sanity_checks) - hws->funcs.verify_allow_pstate_change_high(dc); -} - -void dcn10_optimize_bandwidth( - struct dc *dc, - struct dc_state *context) -{ - struct dce_hwseq *hws = dc->hwseq; - struct hubbub *hubbub = dc->res_pool->hubbub; - int min_fclk_khz, min_dcfclk_khz, socclk_khz; - - if (dc->debug.sanity_checks) - hws->funcs.verify_allow_pstate_change_high(dc); - - if (context->stream_count == 0) - context->bw_ctx.bw.dcn.clk.phyclk_khz = 0; - - dc->clk_mgr->funcs->update_clocks( - dc->clk_mgr, - context, - true); - - hubbub->funcs->program_watermarks(hubbub, - &context->bw_ctx.bw.dcn.watermarks, - dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000, - true); - - dcn10_stereo_hw_frame_pack_wa(dc, context); - - if (dc->debug.pplib_wm_report_mode == WM_REPORT_OVERRIDE) { - DC_FP_START(); - dcn_get_soc_clks( - dc, &min_fclk_khz, &min_dcfclk_khz, &socclk_khz); - DC_FP_END(); - dcn_bw_notify_pplib_of_wm_ranges( - dc, min_fclk_khz, min_dcfclk_khz, socclk_khz); - } - - if (dc->debug.sanity_checks) - hws->funcs.verify_allow_pstate_change_high(dc); -} - -void dcn10_set_drr(struct pipe_ctx **pipe_ctx, - int num_pipes, struct dc_crtc_timing_adjust adjust) -{ - int i = 0; - struct drr_params params = {0}; - // DRR set trigger event mapped to OTG_TRIG_A (bit 11) for manual control flow - unsigned int event_triggers = 0x800; - // Note DRR trigger events are generated regardless of whether num frames met. - unsigned int num_frames = 2; - - params.vertical_total_max = adjust.v_total_max; - params.vertical_total_min = adjust.v_total_min; - params.vertical_total_mid = adjust.v_total_mid; - params.vertical_total_mid_frame_num = adjust.v_total_mid_frame_num; - /* TODO: If multiple pipes are to be supported, you need - * some GSL stuff. Static screen triggers may be programmed differently - * as well. - */ - for (i = 0; i < num_pipes; i++) { - if ((pipe_ctx[i]->stream_res.tg != NULL) && pipe_ctx[i]->stream_res.tg->funcs) { - if (pipe_ctx[i]->stream_res.tg->funcs->set_drr) - pipe_ctx[i]->stream_res.tg->funcs->set_drr( - pipe_ctx[i]->stream_res.tg, ¶ms); - if (adjust.v_total_max != 0 && adjust.v_total_min != 0) - if (pipe_ctx[i]->stream_res.tg->funcs->set_static_screen_control) - pipe_ctx[i]->stream_res.tg->funcs->set_static_screen_control( - pipe_ctx[i]->stream_res.tg, - event_triggers, num_frames); - } - } -} - -void dcn10_get_position(struct pipe_ctx **pipe_ctx, - int num_pipes, - struct crtc_position *position) -{ - int i = 0; - - /* TODO: handle pipes > 1 - */ - for (i = 0; i < num_pipes; i++) - pipe_ctx[i]->stream_res.tg->funcs->get_position(pipe_ctx[i]->stream_res.tg, position); -} - -void dcn10_set_static_screen_control(struct pipe_ctx **pipe_ctx, - int num_pipes, const struct dc_static_screen_params *params) -{ - unsigned int i; - unsigned int triggers = 0; - - if (params->triggers.surface_update) - triggers |= 0x80; - if (params->triggers.cursor_update) - triggers |= 0x2; - if (params->triggers.force_trigger) - triggers |= 0x1; - - for (i = 0; i < num_pipes; i++) - pipe_ctx[i]->stream_res.tg->funcs-> - set_static_screen_control(pipe_ctx[i]->stream_res.tg, - triggers, params->num_frames); -} - -static void dcn10_config_stereo_parameters( - struct dc_stream_state *stream, struct crtc_stereo_flags *flags) -{ - enum view_3d_format view_format = stream->view_format; - enum dc_timing_3d_format timing_3d_format =\ - stream->timing.timing_3d_format; - bool non_stereo_timing = false; - - if (timing_3d_format == TIMING_3D_FORMAT_NONE || - timing_3d_format == TIMING_3D_FORMAT_SIDE_BY_SIDE || - timing_3d_format == TIMING_3D_FORMAT_TOP_AND_BOTTOM) - non_stereo_timing = true; - - if (non_stereo_timing == false && - view_format == VIEW_3D_FORMAT_FRAME_SEQUENTIAL) { - - flags->PROGRAM_STEREO = 1; - flags->PROGRAM_POLARITY = 1; - if (timing_3d_format == TIMING_3D_FORMAT_FRAME_ALTERNATE || - timing_3d_format == TIMING_3D_FORMAT_INBAND_FA || - timing_3d_format == TIMING_3D_FORMAT_DP_HDMI_INBAND_FA || - timing_3d_format == TIMING_3D_FORMAT_SIDEBAND_FA) { - - if (stream->link && stream->link->ddc) { - enum display_dongle_type dongle = \ - stream->link->ddc->dongle_type; - - if (dongle == DISPLAY_DONGLE_DP_VGA_CONVERTER || - dongle == DISPLAY_DONGLE_DP_DVI_CONVERTER || - dongle == DISPLAY_DONGLE_DP_HDMI_CONVERTER) - flags->DISABLE_STEREO_DP_SYNC = 1; - } - } - flags->RIGHT_EYE_POLARITY =\ - stream->timing.flags.RIGHT_EYE_3D_POLARITY; - if (timing_3d_format == TIMING_3D_FORMAT_HW_FRAME_PACKING) - flags->FRAME_PACKED = 1; - } - - return; -} - -void dcn10_setup_stereo(struct pipe_ctx *pipe_ctx, struct dc *dc) -{ - struct crtc_stereo_flags flags = { 0 }; - struct dc_stream_state *stream = pipe_ctx->stream; - - dcn10_config_stereo_parameters(stream, &flags); - - if (stream->timing.timing_3d_format == TIMING_3D_FORMAT_SIDEBAND_FA) { - if (!dc_set_generic_gpio_for_stereo(true, dc->ctx->gpio_service)) - dc_set_generic_gpio_for_stereo(false, dc->ctx->gpio_service); - } else { - dc_set_generic_gpio_for_stereo(false, dc->ctx->gpio_service); - } - - pipe_ctx->stream_res.opp->funcs->opp_program_stereo( - pipe_ctx->stream_res.opp, - flags.PROGRAM_STEREO == 1, - &stream->timing); - - pipe_ctx->stream_res.tg->funcs->program_stereo( - pipe_ctx->stream_res.tg, - &stream->timing, - &flags); - - return; -} - -static struct hubp *get_hubp_by_inst(struct resource_pool *res_pool, int mpcc_inst) -{ - int i; - - for (i = 0; i < res_pool->pipe_count; i++) { - if (res_pool->hubps[i]->inst == mpcc_inst) - return res_pool->hubps[i]; - } - ASSERT(false); - return NULL; -} - -void dcn10_wait_for_mpcc_disconnect( - struct dc *dc, - struct resource_pool *res_pool, - struct pipe_ctx *pipe_ctx) -{ - struct dce_hwseq *hws = dc->hwseq; - int mpcc_inst; - - if (dc->debug.sanity_checks) { - hws->funcs.verify_allow_pstate_change_high(dc); - } - - if (!pipe_ctx->stream_res.opp) - return; - - for (mpcc_inst = 0; mpcc_inst < MAX_PIPES; mpcc_inst++) { - if (pipe_ctx->stream_res.opp->mpcc_disconnect_pending[mpcc_inst]) { - struct hubp *hubp = get_hubp_by_inst(res_pool, mpcc_inst); - - if (pipe_ctx->stream_res.tg && - pipe_ctx->stream_res.tg->funcs->is_tg_enabled(pipe_ctx->stream_res.tg)) - res_pool->mpc->funcs->wait_for_idle(res_pool->mpc, mpcc_inst); - pipe_ctx->stream_res.opp->mpcc_disconnect_pending[mpcc_inst] = false; - hubp->funcs->set_blank(hubp, true); - } - } - - if (dc->debug.sanity_checks) { - hws->funcs.verify_allow_pstate_change_high(dc); - } - -} - -bool dcn10_dummy_display_power_gating( - struct dc *dc, - uint8_t controller_id, - struct dc_bios *dcb, - enum pipe_gating_control power_gating) -{ - return true; -} - -void dcn10_update_pending_status(struct pipe_ctx *pipe_ctx) -{ - struct dc_plane_state *plane_state = pipe_ctx->plane_state; - struct timing_generator *tg = pipe_ctx->stream_res.tg; - bool flip_pending; - struct dc *dc = pipe_ctx->stream->ctx->dc; - - if (plane_state == NULL) - return; - - flip_pending = pipe_ctx->plane_res.hubp->funcs->hubp_is_flip_pending( - pipe_ctx->plane_res.hubp); - - plane_state->status.is_flip_pending = plane_state->status.is_flip_pending || flip_pending; - - if (!flip_pending) - plane_state->status.current_address = plane_state->status.requested_address; - - if (plane_state->status.current_address.type == PLN_ADDR_TYPE_GRPH_STEREO && - tg->funcs->is_stereo_left_eye) { - plane_state->status.is_right_eye = - !tg->funcs->is_stereo_left_eye(pipe_ctx->stream_res.tg); - } - - if (dc->hwseq->wa_state.disallow_self_refresh_during_multi_plane_transition_applied) { - struct dce_hwseq *hwseq = dc->hwseq; - struct timing_generator *tg = dc->res_pool->timing_generators[0]; - unsigned int cur_frame = tg->funcs->get_frame_count(tg); - - if (cur_frame != hwseq->wa_state.disallow_self_refresh_during_multi_plane_transition_applied_on_frame) { - struct hubbub *hubbub = dc->res_pool->hubbub; - - hubbub->funcs->allow_self_refresh_control(hubbub, !dc->debug.disable_stutter); - hwseq->wa_state.disallow_self_refresh_during_multi_plane_transition_applied = false; - } - } -} - -void dcn10_update_dchub(struct dce_hwseq *hws, struct dchub_init_data *dh_data) -{ - struct hubbub *hubbub = hws->ctx->dc->res_pool->hubbub; - - /* In DCN, this programming sequence is owned by the hubbub */ - hubbub->funcs->update_dchub(hubbub, dh_data); -} - -static bool dcn10_can_pipe_disable_cursor(struct pipe_ctx *pipe_ctx) -{ - struct pipe_ctx *test_pipe, *split_pipe; - const struct scaler_data *scl_data = &pipe_ctx->plane_res.scl_data; - struct rect r1 = scl_data->recout, r2, r2_half; - int r1_r = r1.x + r1.width, r1_b = r1.y + r1.height, r2_r, r2_b; - int cur_layer = pipe_ctx->plane_state->layer_index; - - /** - * Disable the cursor if there's another pipe above this with a - * plane that contains this pipe's viewport to prevent double cursor - * and incorrect scaling artifacts. - */ - for (test_pipe = pipe_ctx->top_pipe; test_pipe; - test_pipe = test_pipe->top_pipe) { - // Skip invisible layer and pipe-split plane on same layer - if (!test_pipe->plane_state || - !test_pipe->plane_state->visible || - test_pipe->plane_state->layer_index == cur_layer) - continue; - - r2 = test_pipe->plane_res.scl_data.recout; - r2_r = r2.x + r2.width; - r2_b = r2.y + r2.height; - split_pipe = test_pipe; - - /** - * There is another half plane on same layer because of - * pipe-split, merge together per same height. - */ - for (split_pipe = pipe_ctx->top_pipe; split_pipe; - split_pipe = split_pipe->top_pipe) - if (split_pipe->plane_state->layer_index == test_pipe->plane_state->layer_index) { - r2_half = split_pipe->plane_res.scl_data.recout; - r2.x = (r2_half.x < r2.x) ? r2_half.x : r2.x; - r2.width = r2.width + r2_half.width; - r2_r = r2.x + r2.width; - break; - } - - if (r1.x >= r2.x && r1.y >= r2.y && r1_r <= r2_r && r1_b <= r2_b) - return true; - } - - return false; -} - -void dcn10_set_cursor_position(struct pipe_ctx *pipe_ctx) -{ - struct dc_cursor_position pos_cpy = pipe_ctx->stream->cursor_position; - struct hubp *hubp = pipe_ctx->plane_res.hubp; - struct dpp *dpp = pipe_ctx->plane_res.dpp; - struct dc_cursor_mi_param param = { - .pixel_clk_khz = pipe_ctx->stream->timing.pix_clk_100hz / 10, - .ref_clk_khz = pipe_ctx->stream->ctx->dc->res_pool->ref_clocks.dchub_ref_clock_inKhz, - .viewport = pipe_ctx->plane_res.scl_data.viewport, - .h_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.horz, - .v_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.vert, - .rotation = pipe_ctx->plane_state->rotation, - .mirror = pipe_ctx->plane_state->horizontal_mirror, - .stream = pipe_ctx->stream, - }; - bool pipe_split_on = false; - bool odm_combine_on = (pipe_ctx->next_odm_pipe != NULL) || - (pipe_ctx->prev_odm_pipe != NULL); - - int x_plane = pipe_ctx->plane_state->dst_rect.x; - int y_plane = pipe_ctx->plane_state->dst_rect.y; - int x_pos = pos_cpy.x; - int y_pos = pos_cpy.y; - - if ((pipe_ctx->top_pipe != NULL) || (pipe_ctx->bottom_pipe != NULL)) { - if ((pipe_ctx->plane_state->src_rect.width != pipe_ctx->plane_res.scl_data.viewport.width) || - (pipe_ctx->plane_state->src_rect.height != pipe_ctx->plane_res.scl_data.viewport.height)) { - pipe_split_on = true; - } - } - - /** - * DC cursor is stream space, HW cursor is plane space and drawn - * as part of the framebuffer. - * - * Cursor position can't be negative, but hotspot can be used to - * shift cursor out of the plane bounds. Hotspot must be smaller - * than the cursor size. - */ - - /** - * Translate cursor from stream space to plane space. - * - * If the cursor is scaled then we need to scale the position - * to be in the approximately correct place. We can't do anything - * about the actual size being incorrect, that's a limitation of - * the hardware. - */ - if (param.rotation == ROTATION_ANGLE_90 || param.rotation == ROTATION_ANGLE_270) { - x_pos = (x_pos - x_plane) * pipe_ctx->plane_state->src_rect.height / - pipe_ctx->plane_state->dst_rect.width; - y_pos = (y_pos - y_plane) * pipe_ctx->plane_state->src_rect.width / - pipe_ctx->plane_state->dst_rect.height; - } else { - x_pos = (x_pos - x_plane) * pipe_ctx->plane_state->src_rect.width / - pipe_ctx->plane_state->dst_rect.width; - y_pos = (y_pos - y_plane) * pipe_ctx->plane_state->src_rect.height / - pipe_ctx->plane_state->dst_rect.height; - } - - /** - * If the cursor's source viewport is clipped then we need to - * translate the cursor to appear in the correct position on - * the screen. - * - * This translation isn't affected by scaling so it needs to be - * done *after* we adjust the position for the scale factor. - * - * This is only done by opt-in for now since there are still - * some usecases like tiled display that might enable the - * cursor on both streams while expecting dc to clip it. - */ - if (pos_cpy.translate_by_source) { - x_pos += pipe_ctx->plane_state->src_rect.x; - y_pos += pipe_ctx->plane_state->src_rect.y; - } - - /** - * If the position is negative then we need to add to the hotspot - * to shift the cursor outside the plane. - */ - - if (x_pos < 0) { - pos_cpy.x_hotspot -= x_pos; - x_pos = 0; - } - - if (y_pos < 0) { - pos_cpy.y_hotspot -= y_pos; - y_pos = 0; - } - - pos_cpy.x = (uint32_t)x_pos; - pos_cpy.y = (uint32_t)y_pos; - - if (pipe_ctx->plane_state->address.type - == PLN_ADDR_TYPE_VIDEO_PROGRESSIVE) - pos_cpy.enable = false; - - if (pos_cpy.enable && dcn10_can_pipe_disable_cursor(pipe_ctx)) - pos_cpy.enable = false; - - - if (param.rotation == ROTATION_ANGLE_0) { - int viewport_width = - pipe_ctx->plane_res.scl_data.viewport.width; - int viewport_x = - pipe_ctx->plane_res.scl_data.viewport.x; - - if (param.mirror) { - if (pipe_split_on || odm_combine_on) { - if (pos_cpy.x >= viewport_width + viewport_x) { - pos_cpy.x = 2 * viewport_width - - pos_cpy.x + 2 * viewport_x; - } else { - uint32_t temp_x = pos_cpy.x; - - pos_cpy.x = 2 * viewport_x - pos_cpy.x; - if (temp_x >= viewport_x + - (int)hubp->curs_attr.width || pos_cpy.x - <= (int)hubp->curs_attr.width + - pipe_ctx->plane_state->src_rect.x) { - pos_cpy.x = temp_x + viewport_width; - } - } - } else { - pos_cpy.x = viewport_width - pos_cpy.x + 2 * viewport_x; - } - } - } - // Swap axis and mirror horizontally - else if (param.rotation == ROTATION_ANGLE_90) { - uint32_t temp_x = pos_cpy.x; - - pos_cpy.x = pipe_ctx->plane_res.scl_data.viewport.width - - (pos_cpy.y - pipe_ctx->plane_res.scl_data.viewport.x) + pipe_ctx->plane_res.scl_data.viewport.x; - pos_cpy.y = temp_x; - } - // Swap axis and mirror vertically - else if (param.rotation == ROTATION_ANGLE_270) { - uint32_t temp_y = pos_cpy.y; - int viewport_height = - pipe_ctx->plane_res.scl_data.viewport.height; - int viewport_y = - pipe_ctx->plane_res.scl_data.viewport.y; - - /** - * Display groups that are 1xnY, have pos_cpy.x > 2 * viewport.height - * For pipe split cases: - * - apply offset of viewport.y to normalize pos_cpy.x - * - calculate the pos_cpy.y as before - * - shift pos_cpy.y back by same offset to get final value - * - since we iterate through both pipes, use the lower - * viewport.y for offset - * For non pipe split cases, use the same calculation for - * pos_cpy.y as the 180 degree rotation case below, - * but use pos_cpy.x as our input because we are rotating - * 270 degrees - */ - if (pipe_split_on || odm_combine_on) { - int pos_cpy_x_offset; - int other_pipe_viewport_y; - - if (pipe_split_on) { - if (pipe_ctx->bottom_pipe) { - other_pipe_viewport_y = - pipe_ctx->bottom_pipe->plane_res.scl_data.viewport.y; - } else { - other_pipe_viewport_y = - pipe_ctx->top_pipe->plane_res.scl_data.viewport.y; - } - } else { - if (pipe_ctx->next_odm_pipe) { - other_pipe_viewport_y = - pipe_ctx->next_odm_pipe->plane_res.scl_data.viewport.y; - } else { - other_pipe_viewport_y = - pipe_ctx->prev_odm_pipe->plane_res.scl_data.viewport.y; - } - } - pos_cpy_x_offset = (viewport_y > other_pipe_viewport_y) ? - other_pipe_viewport_y : viewport_y; - pos_cpy.x -= pos_cpy_x_offset; - if (pos_cpy.x > viewport_height) { - pos_cpy.x = pos_cpy.x - viewport_height; - pos_cpy.y = viewport_height - pos_cpy.x; - } else { - pos_cpy.y = 2 * viewport_height - pos_cpy.x; - } - pos_cpy.y += pos_cpy_x_offset; - } else { - pos_cpy.y = (2 * viewport_y) + viewport_height - pos_cpy.x; - } - pos_cpy.x = temp_y; - } - // Mirror horizontally and vertically - else if (param.rotation == ROTATION_ANGLE_180) { - int viewport_width = - pipe_ctx->plane_res.scl_data.viewport.width; - int viewport_x = - pipe_ctx->plane_res.scl_data.viewport.x; - - if (!param.mirror) { - if (pipe_split_on || odm_combine_on) { - if (pos_cpy.x >= viewport_width + viewport_x) { - pos_cpy.x = 2 * viewport_width - - pos_cpy.x + 2 * viewport_x; - } else { - uint32_t temp_x = pos_cpy.x; - - pos_cpy.x = 2 * viewport_x - pos_cpy.x; - if (temp_x >= viewport_x + - (int)hubp->curs_attr.width || pos_cpy.x - <= (int)hubp->curs_attr.width + - pipe_ctx->plane_state->src_rect.x) { - pos_cpy.x = 2 * viewport_width - temp_x; - } - } - } else { - pos_cpy.x = viewport_width - pos_cpy.x + 2 * viewport_x; - } - } - - /** - * Display groups that are 1xnY, have pos_cpy.y > viewport.height - * Calculation: - * delta_from_bottom = viewport.y + viewport.height - pos_cpy.y - * pos_cpy.y_new = viewport.y + delta_from_bottom - * Simplify it as: - * pos_cpy.y = viewport.y * 2 + viewport.height - pos_cpy.y - */ - pos_cpy.y = (2 * pipe_ctx->plane_res.scl_data.viewport.y) + - pipe_ctx->plane_res.scl_data.viewport.height - pos_cpy.y; - } - - hubp->funcs->set_cursor_position(hubp, &pos_cpy, ¶m); - dpp->funcs->set_cursor_position(dpp, &pos_cpy, ¶m, hubp->curs_attr.width, hubp->curs_attr.height); -} - -void dcn10_set_cursor_attribute(struct pipe_ctx *pipe_ctx) -{ - struct dc_cursor_attributes *attributes = &pipe_ctx->stream->cursor_attributes; - - pipe_ctx->plane_res.hubp->funcs->set_cursor_attributes( - pipe_ctx->plane_res.hubp, attributes); - pipe_ctx->plane_res.dpp->funcs->set_cursor_attributes( - pipe_ctx->plane_res.dpp, attributes); -} - -void dcn10_set_cursor_sdr_white_level(struct pipe_ctx *pipe_ctx) -{ - uint32_t sdr_white_level = pipe_ctx->stream->cursor_attributes.sdr_white_level; - struct fixed31_32 multiplier; - struct dpp_cursor_attributes opt_attr = { 0 }; - uint32_t hw_scale = 0x3c00; // 1.0 default multiplier - struct custom_float_format fmt; - - if (!pipe_ctx->plane_res.dpp->funcs->set_optional_cursor_attributes) - return; - - fmt.exponenta_bits = 5; - fmt.mantissa_bits = 10; - fmt.sign = true; - - if (sdr_white_level > 80) { - multiplier = dc_fixpt_from_fraction(sdr_white_level, 80); - convert_to_custom_float_format(multiplier, &fmt, &hw_scale); - } - - opt_attr.scale = hw_scale; - opt_attr.bias = 0; - - pipe_ctx->plane_res.dpp->funcs->set_optional_cursor_attributes( - pipe_ctx->plane_res.dpp, &opt_attr); -} - -/* - * apply_front_porch_workaround TODO FPGA still need? - * - * This is a workaround for a bug that has existed since R5xx and has not been - * fixed keep Front porch at minimum 2 for Interlaced mode or 1 for progressive. - */ -static void apply_front_porch_workaround( - struct dc_crtc_timing *timing) -{ - if (timing->flags.INTERLACE == 1) { - if (timing->v_front_porch < 2) - timing->v_front_porch = 2; - } else { - if (timing->v_front_porch < 1) - timing->v_front_porch = 1; - } -} - -int dcn10_get_vupdate_offset_from_vsync(struct pipe_ctx *pipe_ctx) -{ - const struct dc_crtc_timing *dc_crtc_timing = &pipe_ctx->stream->timing; - struct dc_crtc_timing patched_crtc_timing; - int vesa_sync_start; - int asic_blank_end; - int interlace_factor; - - patched_crtc_timing = *dc_crtc_timing; - apply_front_porch_workaround(&patched_crtc_timing); - - interlace_factor = patched_crtc_timing.flags.INTERLACE ? 2 : 1; - - vesa_sync_start = patched_crtc_timing.v_addressable + - patched_crtc_timing.v_border_bottom + - patched_crtc_timing.v_front_porch; - - asic_blank_end = (patched_crtc_timing.v_total - - vesa_sync_start - - patched_crtc_timing.v_border_top) - * interlace_factor; - - return asic_blank_end - - pipe_ctx->pipe_dlg_param.vstartup_start + 1; -} - -void dcn10_calc_vupdate_position( - struct dc *dc, - struct pipe_ctx *pipe_ctx, - uint32_t *start_line, - uint32_t *end_line) -{ - const struct dc_crtc_timing *timing = &pipe_ctx->stream->timing; - int vupdate_pos = dc->hwss.get_vupdate_offset_from_vsync(pipe_ctx); - - if (vupdate_pos >= 0) - *start_line = vupdate_pos - ((vupdate_pos / timing->v_total) * timing->v_total); - else - *start_line = vupdate_pos + ((-vupdate_pos / timing->v_total) + 1) * timing->v_total - 1; - *end_line = (*start_line + 2) % timing->v_total; -} - -static void dcn10_cal_vline_position( - struct dc *dc, - struct pipe_ctx *pipe_ctx, - uint32_t *start_line, - uint32_t *end_line) -{ - const struct dc_crtc_timing *timing = &pipe_ctx->stream->timing; - int vline_pos = pipe_ctx->stream->periodic_interrupt.lines_offset; - - if (pipe_ctx->stream->periodic_interrupt.ref_point == START_V_UPDATE) { - if (vline_pos > 0) - vline_pos--; - else if (vline_pos < 0) - vline_pos++; - - vline_pos += dc->hwss.get_vupdate_offset_from_vsync(pipe_ctx); - if (vline_pos >= 0) - *start_line = vline_pos - ((vline_pos / timing->v_total) * timing->v_total); - else - *start_line = vline_pos + ((-vline_pos / timing->v_total) + 1) * timing->v_total - 1; - *end_line = (*start_line + 2) % timing->v_total; - } else if (pipe_ctx->stream->periodic_interrupt.ref_point == START_V_SYNC) { - // vsync is line 0 so start_line is just the requested line offset - *start_line = vline_pos; - *end_line = (*start_line + 2) % timing->v_total; - } else - ASSERT(0); -} - -void dcn10_setup_periodic_interrupt( - struct dc *dc, - struct pipe_ctx *pipe_ctx) -{ - struct timing_generator *tg = pipe_ctx->stream_res.tg; - uint32_t start_line = 0; - uint32_t end_line = 0; - - dcn10_cal_vline_position(dc, pipe_ctx, &start_line, &end_line); - - tg->funcs->setup_vertical_interrupt0(tg, start_line, end_line); -} - -void dcn10_setup_vupdate_interrupt(struct dc *dc, struct pipe_ctx *pipe_ctx) -{ - struct timing_generator *tg = pipe_ctx->stream_res.tg; - int start_line = dc->hwss.get_vupdate_offset_from_vsync(pipe_ctx); - - if (start_line < 0) { - ASSERT(0); - start_line = 0; - } - - if (tg->funcs->setup_vertical_interrupt2) - tg->funcs->setup_vertical_interrupt2(tg, start_line); -} - -void dcn10_unblank_stream(struct pipe_ctx *pipe_ctx, - struct dc_link_settings *link_settings) -{ - struct encoder_unblank_param params = {0}; - struct dc_stream_state *stream = pipe_ctx->stream; - struct dc_link *link = stream->link; - struct dce_hwseq *hws = link->dc->hwseq; - - /* only 3 items below are used by unblank */ - params.timing = pipe_ctx->stream->timing; - - params.link_settings.link_rate = link_settings->link_rate; - - if (dc_is_dp_signal(pipe_ctx->stream->signal)) { - if (params.timing.pixel_encoding == PIXEL_ENCODING_YCBCR420) - params.timing.pix_clk_100hz /= 2; - pipe_ctx->stream_res.stream_enc->funcs->dp_unblank(link, pipe_ctx->stream_res.stream_enc, ¶ms); - } - - if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP) { - hws->funcs.edp_backlight_control(link, true); - } -} - -void dcn10_send_immediate_sdp_message(struct pipe_ctx *pipe_ctx, - const uint8_t *custom_sdp_message, - unsigned int sdp_message_size) -{ - if (dc_is_dp_signal(pipe_ctx->stream->signal)) { - pipe_ctx->stream_res.stream_enc->funcs->send_immediate_sdp_message( - pipe_ctx->stream_res.stream_enc, - custom_sdp_message, - sdp_message_size); - } -} -enum dc_status dcn10_set_clock(struct dc *dc, - enum dc_clock_type clock_type, - uint32_t clk_khz, - uint32_t stepping) -{ - struct dc_state *context = dc->current_state; - struct dc_clock_config clock_cfg = {0}; - struct dc_clocks *current_clocks = &context->bw_ctx.bw.dcn.clk; - - if (!dc->clk_mgr || !dc->clk_mgr->funcs->get_clock) - return DC_FAIL_UNSUPPORTED_1; - - dc->clk_mgr->funcs->get_clock(dc->clk_mgr, - context, clock_type, &clock_cfg); - - if (clk_khz > clock_cfg.max_clock_khz) - return DC_FAIL_CLK_EXCEED_MAX; - - if (clk_khz < clock_cfg.min_clock_khz) - return DC_FAIL_CLK_BELOW_MIN; - - if (clk_khz < clock_cfg.bw_requirequired_clock_khz) - return DC_FAIL_CLK_BELOW_CFG_REQUIRED; - - /*update internal request clock for update clock use*/ - if (clock_type == DC_CLOCK_TYPE_DISPCLK) - current_clocks->dispclk_khz = clk_khz; - else if (clock_type == DC_CLOCK_TYPE_DPPCLK) - current_clocks->dppclk_khz = clk_khz; - else - return DC_ERROR_UNEXPECTED; - - if (dc->clk_mgr->funcs->update_clocks) - dc->clk_mgr->funcs->update_clocks(dc->clk_mgr, - context, true); - return DC_OK; - -} - -void dcn10_get_clock(struct dc *dc, - enum dc_clock_type clock_type, - struct dc_clock_config *clock_cfg) -{ - struct dc_state *context = dc->current_state; - - if (dc->clk_mgr && dc->clk_mgr->funcs->get_clock) - dc->clk_mgr->funcs->get_clock(dc->clk_mgr, context, clock_type, clock_cfg); - -} - -void dcn10_get_dcc_en_bits(struct dc *dc, int *dcc_en_bits) -{ - struct resource_pool *pool = dc->res_pool; - int i; - - for (i = 0; i < pool->pipe_count; i++) { - struct hubp *hubp = pool->hubps[i]; - struct dcn_hubp_state *s = &(TO_DCN10_HUBP(hubp)->state); - - hubp->funcs->hubp_read_state(hubp); - - if (!s->blank_en) - dcc_en_bits[i] = s->dcc_en ? 1 : 0; - } -} diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.h deleted file mode 100644 index ef6d56da41..0000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.h +++ /dev/null @@ -1,207 +0,0 @@ -/* -* Copyright 2016-2020 Advanced Micro Devices, Inc. - * - * 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 - * - */ - -#ifndef __DC_HWSS_DCN10_H__ -#define __DC_HWSS_DCN10_H__ - -#include "core_types.h" -#include "hw_sequencer_private.h" - -struct dc; - -void dcn10_hw_sequencer_construct(struct dc *dc); - -int dcn10_get_vupdate_offset_from_vsync(struct pipe_ctx *pipe_ctx); -void dcn10_calc_vupdate_position( - struct dc *dc, - struct pipe_ctx *pipe_ctx, - uint32_t *start_line, - uint32_t *end_line); -void dcn10_setup_vupdate_interrupt(struct dc *dc, struct pipe_ctx *pipe_ctx); -enum dc_status dcn10_enable_stream_timing( - struct pipe_ctx *pipe_ctx, - struct dc_state *context, - struct dc *dc); -void dcn10_optimize_bandwidth( - struct dc *dc, - struct dc_state *context); -void dcn10_prepare_bandwidth( - struct dc *dc, - struct dc_state *context); -void dcn10_pipe_control_lock( - struct dc *dc, - struct pipe_ctx *pipe, - bool lock); -void dcn10_cursor_lock(struct dc *dc, struct pipe_ctx *pipe, bool lock); -void dcn10_blank_pixel_data( - struct dc *dc, - struct pipe_ctx *pipe_ctx, - bool blank); -void dcn10_unblank_stream(struct pipe_ctx *pipe_ctx, - struct dc_link_settings *link_settings); -void dcn10_program_output_csc(struct dc *dc, - struct pipe_ctx *pipe_ctx, - enum dc_color_space colorspace, - uint16_t *matrix, - int opp_id); -bool dcn10_set_output_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx, - const struct dc_stream_state *stream); -bool dcn10_set_input_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx, - const struct dc_plane_state *plane_state); -void dcn10_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx); -void dcn10_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx); -void dcn10_reset_hw_ctx_wrap( - struct dc *dc, - struct dc_state *context); -void dcn10_disable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx); -void dcn10_lock_all_pipes( - struct dc *dc, - struct dc_state *context, - bool lock); -void dcn10_post_unlock_program_front_end( - struct dc *dc, - struct dc_state *context); -void dcn10_hubp_pg_control( - struct dce_hwseq *hws, - unsigned int hubp_inst, - bool power_on); -void dcn10_dpp_pg_control( - struct dce_hwseq *hws, - unsigned int dpp_inst, - bool power_on); -void dcn10_enable_power_gating_plane( - struct dce_hwseq *hws, - bool enable); -void dcn10_plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx); -void dcn10_disable_vga( - struct dce_hwseq *hws); -void dcn10_program_pipe( - struct dc *dc, - struct pipe_ctx *pipe_ctx, - struct dc_state *context); -void dcn10_program_gamut_remap(struct pipe_ctx *pipe_ctx); -void dcn10_init_hw(struct dc *dc); -void dcn10_init_pipes(struct dc *dc, struct dc_state *context); -void dcn10_power_down_on_boot(struct dc *dc); -enum dc_status dce110_apply_ctx_to_hw( - struct dc *dc, - struct dc_state *context); -void dcn10_plane_atomic_disconnect(struct dc *dc, struct pipe_ctx *pipe_ctx); -void dcn10_update_dchub(struct dce_hwseq *hws, struct dchub_init_data *dh_data); -void dcn10_update_pending_status(struct pipe_ctx *pipe_ctx); -void dce110_power_down(struct dc *dc); -void dce110_enable_accelerated_mode(struct dc *dc, struct dc_state *context); -void dcn10_enable_timing_synchronization( - struct dc *dc, - int group_index, - int group_size, - struct pipe_ctx *grouped_pipes[]); -void dcn10_enable_vblanks_synchronization( - struct dc *dc, - int group_index, - int group_size, - struct pipe_ctx *grouped_pipes[]); -void dcn10_enable_per_frame_crtc_position_reset( - struct dc *dc, - int group_size, - struct pipe_ctx *grouped_pipes[]); -void dce110_update_info_frame(struct pipe_ctx *pipe_ctx); -void dcn10_send_immediate_sdp_message(struct pipe_ctx *pipe_ctx, - const uint8_t *custom_sdp_message, - unsigned int sdp_message_size); -void dce110_blank_stream(struct pipe_ctx *pipe_ctx); -void dce110_enable_audio_stream(struct pipe_ctx *pipe_ctx); -void dce110_disable_audio_stream(struct pipe_ctx *pipe_ctx); -bool dcn10_dummy_display_power_gating( - struct dc *dc, - uint8_t controller_id, - struct dc_bios *dcb, - enum pipe_gating_control power_gating); -void dcn10_set_drr(struct pipe_ctx **pipe_ctx, - int num_pipes, struct dc_crtc_timing_adjust adjust); -void dcn10_get_position(struct pipe_ctx **pipe_ctx, - int num_pipes, - struct crtc_position *position); -void dcn10_set_static_screen_control(struct pipe_ctx **pipe_ctx, - int num_pipes, const struct dc_static_screen_params *params); -void dcn10_setup_stereo(struct pipe_ctx *pipe_ctx, struct dc *dc); -void dce110_set_avmute(struct pipe_ctx *pipe_ctx, bool enable); -void dcn10_log_hw_state(struct dc *dc, - struct dc_log_buffer_ctx *log_ctx); -void dcn10_get_hw_state(struct dc *dc, - char *pBuf, - unsigned int bufSize, - unsigned int mask); -void dcn10_clear_status_bits(struct dc *dc, unsigned int mask); -void dcn10_wait_for_mpcc_disconnect( - struct dc *dc, - struct resource_pool *res_pool, - struct pipe_ctx *pipe_ctx); -void dce110_edp_backlight_control( - struct dc_link *link, - bool enable); -void dce110_edp_wait_for_T12( - struct dc_link *link); -void dce110_edp_power_control( - struct dc_link *link, - bool power_up); -void dce110_edp_wait_for_hpd_ready( - struct dc_link *link, - bool power_up); -void dcn10_set_cursor_position(struct pipe_ctx *pipe_ctx); -void dcn10_set_cursor_attribute(struct pipe_ctx *pipe_ctx); -void dcn10_set_cursor_sdr_white_level(struct pipe_ctx *pipe_ctx); -void dcn10_setup_periodic_interrupt( - struct dc *dc, - struct pipe_ctx *pipe_ctx); -enum dc_status dcn10_set_clock(struct dc *dc, - enum dc_clock_type clock_type, - uint32_t clk_khz, - uint32_t stepping); -void dcn10_get_clock(struct dc *dc, - enum dc_clock_type clock_type, - struct dc_clock_config *clock_cfg); -bool dcn10_did_underflow_occur(struct dc *dc, struct pipe_ctx *pipe_ctx); -void dcn10_bios_golden_init(struct dc *dc); -void dcn10_plane_atomic_power_down(struct dc *dc, - struct dpp *dpp, - struct hubp *hubp); -bool dcn10_disconnect_pipes( - struct dc *dc, - struct dc_state *context); - -void dcn10_wait_for_pending_cleared(struct dc *dc, - struct dc_state *context); -void dcn10_set_hdr_multiplier(struct pipe_ctx *pipe_ctx); -void dcn10_verify_allow_pstate_change_high(struct dc *dc); - -void dcn10_get_dcc_en_bits(struct dc *dc, int *dcc_en_bits); - -void dcn10_update_visual_confirm_color( - struct dc *dc, - struct pipe_ctx *pipe_ctx, - int mpcc_id); - -#endif /* __DC_HWSS_DCN10_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.c index 46a2ebcabd..92fdab731f 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.c @@ -27,8 +27,8 @@ #include "core_types.h" #include "resource.h" #include "custom_float.h" -#include "dcn10_hw_sequencer.h" -#include "dce110/dce110_hw_sequencer.h" +#include "dcn10/dcn10_hwseq.h" +#include "dce110/dce110_hwseq.h" #include "dce/dce_hwseq.h" #include "abm.h" #include "dmcu.h" diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_init.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_init.c index f2371c9488..a5bdac79a7 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_init.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_init.c @@ -24,8 +24,8 @@ */ #include "hw_sequencer_private.h" -#include "dce110/dce110_hw_sequencer.h" -#include "dcn10_hw_sequencer.h" +#include "dce110/dce110_hwseq.h" +#include "dcn10/dcn10_hwseq.h" #include "dcn20/dcn20_hwseq.h" static const struct hw_sequencer_funcs dcn10_funcs = { diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.h index 773380ef49..d980e6bd6c 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.h @@ -168,6 +168,8 @@ struct dcn10_link_enc_registers { uint32_t DIO_LINKE_CNTL; uint32_t DIO_LINKF_CNTL; uint32_t DIG_FIFO_CTRL0; + uint32_t DIO_CLK_CNTL; + uint32_t DIG_BE_CLK_CNTL; }; #define LE_SF(reg_name, field_name, post_fix)\ @@ -476,12 +478,42 @@ struct dcn10_link_enc_registers { #define DCN32_LINK_ENCODER_REG_FIELD_LIST(type) \ type DIG_FIFO_OUTPUT_PIXEL_MODE +#define DCN35_LINK_ENCODER_REG_FIELD_LIST(type) \ + type DIG_BE_ENABLE;\ + type DIG_RB_SWITCH_EN;\ + type DIG_BE_MODE;\ + type DIG_BE_CLK_EN;\ + type DIG_BE_SOFT_RESET;\ + type HDCP_SOFT_RESET;\ + type DIG_BE_SYMCLK_G_CLOCK_ON;\ + type DIG_BE_SYMCLK_G_HDCP_CLOCK_ON;\ + type DIG_BE_SYMCLK_G_TMDS_CLOCK_ON;\ + type DISPCLK_R_GATE_DIS;\ + type DISPCLK_G_GATE_DIS;\ + type REFCLK_R_GATE_DIS;\ + type REFCLK_G_GATE_DIS;\ + type SOCCLK_G_GATE_DIS;\ + type SYMCLK_FE_R_GATE_DIS;\ + type SYMCLK_FE_G_GATE_DIS;\ + type SYMCLK_R_GATE_DIS;\ + type SYMCLK_G_GATE_DIS;\ + type DIO_FGCG_REP_DIS;\ + type DISPCLK_G_HDCP_GATE_DIS;\ + type SYMCLKA_G_HDCP_GATE_DIS;\ + type SYMCLKB_G_HDCP_GATE_DIS;\ + type SYMCLKC_G_HDCP_GATE_DIS;\ + type SYMCLKD_G_HDCP_GATE_DIS;\ + type SYMCLKE_G_HDCP_GATE_DIS;\ + type SYMCLKF_G_HDCP_GATE_DIS;\ + type SYMCLKG_G_HDCP_GATE_DIS + struct dcn10_link_enc_shift { DCN_LINK_ENCODER_REG_FIELD_LIST(uint8_t); DCN20_LINK_ENCODER_REG_FIELD_LIST(uint8_t); DCN30_LINK_ENCODER_REG_FIELD_LIST(uint8_t); DCN31_LINK_ENCODER_REG_FIELD_LIST(uint8_t); DCN32_LINK_ENCODER_REG_FIELD_LIST(uint8_t); + DCN35_LINK_ENCODER_REG_FIELD_LIST(uint8_t); }; struct dcn10_link_enc_mask { @@ -490,6 +522,7 @@ struct dcn10_link_enc_mask { DCN30_LINK_ENCODER_REG_FIELD_LIST(uint32_t); DCN31_LINK_ENCODER_REG_FIELD_LIST(uint32_t); DCN32_LINK_ENCODER_REG_FIELD_LIST(uint32_t); + DCN35_LINK_ENCODER_REG_FIELD_LIST(uint32_t); }; struct dcn10_link_encoder { diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h index db766689af..ab81594a7f 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h @@ -26,7 +26,7 @@ #ifndef __DC_TIMING_GENERATOR_DCN10_H__ #define __DC_TIMING_GENERATOR_DCN10_H__ -#include "timing_generator.h" +#include "optc.h" #define DCN10TG_FROM_TG(tg)\ container_of(tg, struct optc, base) @@ -189,6 +189,15 @@ struct dcn_optc_registers { uint32_t OTG_M_CONST_DTO1; uint32_t OTG_DRR_V_TOTAL_CHANGE; uint32_t OTG_GLOBAL_CONTROL4; + uint32_t OTG_CRC0_WINDOWA_X_CONTROL_READBACK; + uint32_t OTG_CRC0_WINDOWA_Y_CONTROL_READBACK; + uint32_t OTG_CRC0_WINDOWB_X_CONTROL_READBACK; + uint32_t OTG_CRC0_WINDOWB_Y_CONTROL_READBACK; + uint32_t OTG_CRC1_WINDOWA_X_CONTROL_READBACK; + uint32_t OTG_CRC1_WINDOWA_Y_CONTROL_READBACK; + uint32_t OTG_CRC1_WINDOWB_X_CONTROL_READBACK; + uint32_t OTG_CRC1_WINDOWB_Y_CONTROL_READBACK; + uint32_t OPTC_CLOCK_CONTROL; }; #define TG_COMMON_MASK_SH_LIST_DCN(mask_sh)\ @@ -554,200 +563,37 @@ struct dcn_optc_registers { type OTG_H_TIMING_DIV_MODE_MANUAL; +#define TG_REG_FIELD_LIST_DCN3_5(type) \ + type OTG_CRC0_WINDOWA_X_START_READBACK;\ + type OTG_CRC0_WINDOWA_X_END_READBACK;\ + type OTG_CRC0_WINDOWA_Y_START_READBACK;\ + type OTG_CRC0_WINDOWA_Y_END_READBACK;\ + type OTG_CRC0_WINDOWB_X_START_READBACK;\ + type OTG_CRC0_WINDOWB_X_END_READBACK;\ + type OTG_CRC0_WINDOWB_Y_START_READBACK;\ + type OTG_CRC0_WINDOWB_Y_END_READBACK; \ + type OTG_CRC1_WINDOWA_X_START_READBACK;\ + type OTG_CRC1_WINDOWA_X_END_READBACK;\ + type OTG_CRC1_WINDOWA_Y_START_READBACK;\ + type OTG_CRC1_WINDOWA_Y_END_READBACK;\ + type OTG_CRC1_WINDOWB_X_START_READBACK;\ + type OTG_CRC1_WINDOWB_X_END_READBACK;\ + type OTG_CRC1_WINDOWB_Y_START_READBACK;\ + type OTG_CRC1_WINDOWB_Y_END_READBACK;\ + type OPTC_FGCG_REP_DIS; + struct dcn_optc_shift { TG_REG_FIELD_LIST(uint8_t) TG_REG_FIELD_LIST_DCN3_2(uint8_t) + TG_REG_FIELD_LIST_DCN3_5(uint8_t) }; struct dcn_optc_mask { TG_REG_FIELD_LIST(uint32_t) TG_REG_FIELD_LIST_DCN3_2(uint32_t) -}; - -struct optc { - struct timing_generator base; - - const struct dcn_optc_registers *tg_regs; - const struct dcn_optc_shift *tg_shift; - const struct dcn_optc_mask *tg_mask; - - int opp_count; - - uint32_t max_h_total; - uint32_t max_v_total; - - uint32_t min_h_blank; - - uint32_t min_h_sync_width; - uint32_t min_v_sync_width; - uint32_t min_v_blank; - uint32_t min_v_blank_interlace; - - int vstartup_start; - int vupdate_offset; - int vupdate_width; - int vready_offset; - struct dc_crtc_timing orginal_patched_timing; - enum signal_type signal; + TG_REG_FIELD_LIST_DCN3_5(uint32_t) }; void dcn10_timing_generator_init(struct optc *optc); -struct dcn_otg_state { - uint32_t v_blank_start; - uint32_t v_blank_end; - uint32_t v_sync_a_pol; - uint32_t v_total; - uint32_t v_total_max; - uint32_t v_total_min; - uint32_t v_total_min_sel; - uint32_t v_total_max_sel; - uint32_t v_sync_a_start; - uint32_t v_sync_a_end; - uint32_t h_blank_start; - uint32_t h_blank_end; - uint32_t h_sync_a_start; - uint32_t h_sync_a_end; - uint32_t h_sync_a_pol; - uint32_t h_total; - uint32_t underflow_occurred_status; - uint32_t otg_enabled; - uint32_t blank_enabled; - uint32_t vertical_interrupt1_en; - uint32_t vertical_interrupt1_line; - uint32_t vertical_interrupt2_en; - uint32_t vertical_interrupt2_line; -}; - -void optc1_read_otg_state(struct optc *optc1, - struct dcn_otg_state *s); - -bool optc1_get_hw_timing(struct timing_generator *tg, - struct dc_crtc_timing *hw_crtc_timing); - -bool optc1_validate_timing( - struct timing_generator *optc, - const struct dc_crtc_timing *timing); - -void optc1_program_timing( - struct timing_generator *optc, - const struct dc_crtc_timing *dc_crtc_timing, - int vready_offset, - int vstartup_start, - int vupdate_offset, - int vupdate_width, - const enum signal_type signal, - bool use_vbios); - -void optc1_setup_vertical_interrupt0( - struct timing_generator *optc, - uint32_t start_line, - uint32_t end_line); -void optc1_setup_vertical_interrupt1( - struct timing_generator *optc, - uint32_t start_line); -void optc1_setup_vertical_interrupt2( - struct timing_generator *optc, - uint32_t start_line); - -void optc1_program_global_sync( - struct timing_generator *optc, - int vready_offset, - int vstartup_start, - int vupdate_offset, - int vupdate_width); - -bool optc1_disable_crtc(struct timing_generator *optc); - -bool optc1_is_counter_moving(struct timing_generator *optc); - -void optc1_get_position(struct timing_generator *optc, - struct crtc_position *position); - -uint32_t optc1_get_vblank_counter(struct timing_generator *optc); - -void optc1_get_crtc_scanoutpos( - struct timing_generator *optc, - uint32_t *v_blank_start, - uint32_t *v_blank_end, - uint32_t *h_position, - uint32_t *v_position); - -void optc1_set_early_control( - struct timing_generator *optc, - uint32_t early_cntl); - -void optc1_wait_for_state(struct timing_generator *optc, - enum crtc_state state); - -void optc1_set_blank(struct timing_generator *optc, - bool enable_blanking); - -bool optc1_is_blanked(struct timing_generator *optc); - -void optc1_program_blank_color( - struct timing_generator *optc, - const struct tg_color *black_color); - -bool optc1_did_triggered_reset_occur( - struct timing_generator *optc); - -void optc1_enable_reset_trigger(struct timing_generator *optc, int source_tg_inst); - -void optc1_disable_reset_trigger(struct timing_generator *optc); - -void optc1_lock(struct timing_generator *optc); - -void optc1_unlock(struct timing_generator *optc); - -void optc1_enable_optc_clock(struct timing_generator *optc, bool enable); - -void optc1_set_drr( - struct timing_generator *optc, - const struct drr_params *params); - -void optc1_set_vtotal_min_max(struct timing_generator *optc, int vtotal_min, int vtotal_max); - -void optc1_set_static_screen_control( - struct timing_generator *optc, - uint32_t event_triggers, - uint32_t num_frames); - -void optc1_program_stereo(struct timing_generator *optc, - const struct dc_crtc_timing *timing, struct crtc_stereo_flags *flags); - -bool optc1_is_stereo_left_eye(struct timing_generator *optc); - -void optc1_clear_optc_underflow(struct timing_generator *optc); - -void optc1_tg_init(struct timing_generator *optc); - -bool optc1_is_tg_enabled(struct timing_generator *optc); - -bool optc1_is_optc_underflow_occurred(struct timing_generator *optc); - -void optc1_set_blank_data_double_buffer(struct timing_generator *optc, bool enable); - -void optc1_set_timing_double_buffer(struct timing_generator *optc, bool enable); - -bool optc1_get_otg_active_size(struct timing_generator *optc, - uint32_t *otg_active_width, - uint32_t *otg_active_height); - -void optc1_enable_crtc_reset( - struct timing_generator *optc, - int source_tg_inst, - struct crtc_trigger_info *crtc_tp); - -bool optc1_configure_crc(struct timing_generator *optc, - const struct crc_params *params); - -bool optc1_get_crc(struct timing_generator *optc, - uint32_t *r_cr, uint32_t *g_y, uint32_t *b_cb); - -bool optc1_is_two_pixels_per_containter(const struct dc_crtc_timing *timing); - -void optc1_set_vtg_params(struct timing_generator *optc, - const struct dc_crtc_timing *dc_crtc_timing, bool program_fp2); - #endif /* __DC_TIMING_GENERATOR_DCN10_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c index 9f9145742f..b94c5c97ee 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c @@ -36,8 +36,8 @@ #include "irq/dcn10/irq_service_dcn10.h" #include "dcn10_dpp.h" #include "dcn10_optc.h" -#include "dcn10_hw_sequencer.h" -#include "dce110/dce110_hw_sequencer.h" +#include "dcn10/dcn10_hwseq.h" +#include "dce110/dce110_hwseq.h" #include "dcn10_opp.h" #include "dcn10_link_encoder.h" #include "dcn10_stream_encoder.h" @@ -554,6 +554,7 @@ static const struct dc_debug_options debug_defaults_drv = { .max_downscale_src_width = 3840, .underflow_assert_delay_us = 0xFFFFFFFF, .enable_legacy_fast_update = true, + .using_dml2 = false, }; static const struct dc_debug_options debug_defaults_diags = { diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.h index 9d5e2a7848..c429590f12 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.h @@ -188,6 +188,9 @@ struct dcn10_stream_enc_registers { uint32_t HDMI_GENERIC_PACKET_CONTROL10; uint32_t DIG_CLOCK_PATTERN; uint32_t DIG_FIFO_CTRL0; + uint32_t DIG_FE_CLK_CNTL; + uint32_t DIG_FE_EN_CNTL; + uint32_t STREAM_MAPPER_CONTROL; }; @@ -574,7 +577,22 @@ struct dcn10_stream_enc_registers { type DIG_FIFO_READ_START_LEVEL;\ type DIG_FIFO_ENABLE;\ type DIG_FIFO_RESET;\ - type DIG_FIFO_RESET_DONE + type DIG_FIFO_RESET_DONE;\ + type PIXEL_ENCODING_TYPE;\ + type UNCOMPRESSED_PIXEL_FORMAT;\ + type UNCOMPRESSED_COMPONENT_DEPTH + +#define SE_REG_FIELD_LIST_DCN3_5_COMMON(type) \ + type DIG_FE_CLK_EN;\ + type DIG_FE_MODE;\ + type DIG_FE_SOFT_RESET;\ + type DIG_FE_ENABLE;\ + type DIG_FE_SYMCLK_FE_G_CLOCK_ON;\ + type DIG_FE_DISPCLK_G_CLOCK_ON;\ + type DIG_FE_SYMCLK_FE_G_AFMT_CLOCK_ON;\ + type DIG_FE_SYMCLK_FE_G_TMDS_CLOCK_ON;\ + type DIG_FE_SOCCLK_G_AFMT_CLOCK_ON;\ + type DIG_STREAM_LINK_TARGET struct dcn10_stream_encoder_shift { SE_REG_FIELD_LIST_DCN1_0(uint8_t); @@ -582,7 +600,7 @@ struct dcn10_stream_encoder_shift { SE_REG_FIELD_LIST_DCN2_0(uint8_t); SE_REG_FIELD_LIST_DCN3_0(uint8_t); SE_REG_FIELD_LIST_DCN3_2(uint8_t); - + SE_REG_FIELD_LIST_DCN3_5_COMMON(uint8_t); }; struct dcn10_stream_encoder_mask { @@ -591,7 +609,7 @@ struct dcn10_stream_encoder_mask { SE_REG_FIELD_LIST_DCN2_0(uint32_t); SE_REG_FIELD_LIST_DCN3_0(uint32_t); SE_REG_FIELD_LIST_DCN3_2(uint32_t); - + SE_REG_FIELD_LIST_DCN3_5_COMMON(uint32_t); }; struct dcn10_stream_encoder { |