1 /* 2 * Copyright 2016 Advanced Micro Devices, Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20 * OTHER DEALINGS IN THE SOFTWARE. 21 * 22 * Authors: AMD 23 * 24 */ 25 26 #include <linux/delay.h> 27 #include "dm_services.h" 28 #include "core_types.h" 29 #include "resource.h" 30 #include "custom_float.h" 31 #include "dcn10_hw_sequencer.h" 32 #include "dce110/dce110_hw_sequencer.h" 33 #include "dce/dce_hwseq.h" 34 #include "abm.h" 35 #include "dmcu.h" 36 #include "dcn10_optc.h" 37 #include "dcn10/dcn10_dpp.h" 38 #include "dcn10/dcn10_mpc.h" 39 #include "timing_generator.h" 40 #include "opp.h" 41 #include "ipp.h" 42 #include "mpc.h" 43 #include "reg_helper.h" 44 #include "custom_float.h" 45 #include "dcn10_hubp.h" 46 #include "dcn10_hubbub.h" 47 #include "dcn10_cm_common.h" 48 49 #define DC_LOGGER_INIT(logger) 50 51 #define CTX \ 52 hws->ctx 53 #define REG(reg)\ 54 hws->regs->reg 55 56 #undef FN 57 #define FN(reg_name, field_name) \ 58 hws->shifts->field_name, hws->masks->field_name 59 60 /*print is 17 wide, first two characters are spaces*/ 61 #define DTN_INFO_MICRO_SEC(ref_cycle) \ 62 print_microsec(dc_ctx, ref_cycle) 63 64 static 65 void print_microsec(struct dc_context *dc_ctx, uint32_t ref_cycle) 66 { 67 const uint32_t ref_clk_mhz = dc_ctx->dc->res_pool->ref_clock_inKhz / 1000; 68 static const unsigned int frac = 1000; 69 uint32_t us_x10 = (ref_cycle * frac) / ref_clk_mhz; 70 71 DTN_INFO(" %11d.%03d", 72 us_x10 / frac, 73 us_x10 % frac); 74 } 75 76 77 static void log_mpc_crc(struct dc *dc) 78 { 79 struct dc_context *dc_ctx = dc->ctx; 80 struct dce_hwseq *hws = dc->hwseq; 81 82 if (REG(MPC_CRC_RESULT_GB)) 83 DTN_INFO("MPC_CRC_RESULT_GB:%d MPC_CRC_RESULT_C:%d MPC_CRC_RESULT_AR:%d\n", 84 REG_READ(MPC_CRC_RESULT_GB), REG_READ(MPC_CRC_RESULT_C), REG_READ(MPC_CRC_RESULT_AR)); 85 if (REG(DPP_TOP0_DPP_CRC_VAL_B_A)) 86 DTN_INFO("DPP_TOP0_DPP_CRC_VAL_B_A:%d DPP_TOP0_DPP_CRC_VAL_R_G:%d\n", 87 REG_READ(DPP_TOP0_DPP_CRC_VAL_B_A), REG_READ(DPP_TOP0_DPP_CRC_VAL_R_G)); 88 } 89 90 static 91 void dcn10_log_hubbub_state(struct dc *dc) 92 { 93 struct dc_context *dc_ctx = dc->ctx; 94 struct dcn_hubbub_wm wm; 95 int i; 96 97 hubbub1_wm_read_state(dc->res_pool->hubbub, &wm); 98 99 DTN_INFO("HUBBUB WM: data_urgent pte_meta_urgent" 100 " sr_enter sr_exit dram_clk_change\n"); 101 102 for (i = 0; i < 4; i++) { 103 struct dcn_hubbub_wm_set *s; 104 105 s = &wm.sets[i]; 106 DTN_INFO("WM_Set[%d]:", s->wm_set); 107 DTN_INFO_MICRO_SEC(s->data_urgent); 108 DTN_INFO_MICRO_SEC(s->pte_meta_urgent); 109 DTN_INFO_MICRO_SEC(s->sr_enter); 110 DTN_INFO_MICRO_SEC(s->sr_exit); 111 DTN_INFO_MICRO_SEC(s->dram_clk_chanage); 112 DTN_INFO("\n"); 113 } 114 115 DTN_INFO("\n"); 116 } 117 118 static void dcn10_log_hubp_states(struct dc *dc) 119 { 120 struct dc_context *dc_ctx = dc->ctx; 121 struct resource_pool *pool = dc->res_pool; 122 int i; 123 124 DTN_INFO("HUBP: format addr_hi width height" 125 " rot mir sw_mode dcc_en blank_en ttu_dis underflow" 126 " min_ttu_vblank qos_low_wm qos_high_wm\n"); 127 for (i = 0; i < pool->pipe_count; i++) { 128 struct hubp *hubp = pool->hubps[i]; 129 struct dcn_hubp_state *s = &(TO_DCN10_HUBP(hubp)->state); 130 131 hubp->funcs->hubp_read_state(hubp); 132 133 if (!s->blank_en) { 134 DTN_INFO("[%2d]: %5xh %6xh %5d %6d %2xh %2xh %6xh" 135 " %6d %8d %7d %8xh", 136 hubp->inst, 137 s->pixel_format, 138 s->inuse_addr_hi, 139 s->viewport_width, 140 s->viewport_height, 141 s->rotation_angle, 142 s->h_mirror_en, 143 s->sw_mode, 144 s->dcc_en, 145 s->blank_en, 146 s->ttu_disable, 147 s->underflow_status); 148 DTN_INFO_MICRO_SEC(s->min_ttu_vblank); 149 DTN_INFO_MICRO_SEC(s->qos_level_low_wm); 150 DTN_INFO_MICRO_SEC(s->qos_level_high_wm); 151 DTN_INFO("\n"); 152 } 153 } 154 155 DTN_INFO("\n=========RQ========\n"); 156 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" 157 " min_m_c_s dpte_gr_s mpte_gr_s swath_hei pte_row_h C:chunk_s min_chu_s meta_ch_s" 158 " min_m_c_s dpte_gr_s mpte_gr_s swath_hei pte_row_h\n"); 159 for (i = 0; i < pool->pipe_count; i++) { 160 struct dcn_hubp_state *s = &(TO_DCN10_HUBP(pool->hubps[i])->state); 161 struct _vcs_dpi_display_rq_regs_st *rq_regs = &s->rq_regs; 162 163 if (!s->blank_en) 164 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", 165 pool->hubps[i]->inst, rq_regs->drq_expansion_mode, rq_regs->prq_expansion_mode, rq_regs->mrq_expansion_mode, 166 rq_regs->crq_expansion_mode, rq_regs->plane1_base_address, rq_regs->rq_regs_l.chunk_size, 167 rq_regs->rq_regs_l.min_chunk_size, rq_regs->rq_regs_l.meta_chunk_size, 168 rq_regs->rq_regs_l.min_meta_chunk_size, rq_regs->rq_regs_l.dpte_group_size, 169 rq_regs->rq_regs_l.mpte_group_size, rq_regs->rq_regs_l.swath_height, 170 rq_regs->rq_regs_l.pte_row_height_linear, rq_regs->rq_regs_c.chunk_size, rq_regs->rq_regs_c.min_chunk_size, 171 rq_regs->rq_regs_c.meta_chunk_size, rq_regs->rq_regs_c.min_meta_chunk_size, 172 rq_regs->rq_regs_c.dpte_group_size, rq_regs->rq_regs_c.mpte_group_size, 173 rq_regs->rq_regs_c.swath_height, rq_regs->rq_regs_c.pte_row_height_linear); 174 } 175 176 DTN_INFO("========DLG========\n"); 177 DTN_INFO("HUBP: rc_hbe dlg_vbe min_d_y_n rc_per_ht rc_x_a_s " 178 " dst_y_a_s dst_y_pf dst_y_vvb dst_y_rvb dst_y_vfl dst_y_rfl rf_pix_fq" 179 " vratio_pf vrat_pf_c rc_pg_vbl rc_pg_vbc rc_mc_vbl rc_mc_vbc rc_pg_fll" 180 " rc_pg_flc rc_mc_fll rc_mc_flc pr_nom_l pr_nom_c rc_pg_nl rc_pg_nc " 181 " mr_nom_l mr_nom_c rc_mc_nl rc_mc_nc rc_ld_pl rc_ld_pc rc_ld_l " 182 " rc_ld_c cha_cur0 ofst_cur1 cha_cur1 vr_af_vc0 ddrq_limt x_rt_dlay" 183 " x_rp_dlay x_rr_sfl\n"); 184 for (i = 0; i < pool->pipe_count; i++) { 185 struct dcn_hubp_state *s = &(TO_DCN10_HUBP(pool->hubps[i])->state); 186 struct _vcs_dpi_display_dlg_regs_st *dlg_regs = &s->dlg_attr; 187 188 if (!s->blank_en) 189 DTN_INFO("[%2d]: %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh" 190 "% 8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh" 191 " %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh\n", 192 pool->hubps[i]->inst, dlg_regs->refcyc_h_blank_end, dlg_regs->dlg_vblank_end, dlg_regs->min_dst_y_next_start, 193 dlg_regs->refcyc_per_htotal, dlg_regs->refcyc_x_after_scaler, dlg_regs->dst_y_after_scaler, 194 dlg_regs->dst_y_prefetch, dlg_regs->dst_y_per_vm_vblank, dlg_regs->dst_y_per_row_vblank, 195 dlg_regs->dst_y_per_vm_flip, dlg_regs->dst_y_per_row_flip, dlg_regs->ref_freq_to_pix_freq, 196 dlg_regs->vratio_prefetch, dlg_regs->vratio_prefetch_c, dlg_regs->refcyc_per_pte_group_vblank_l, 197 dlg_regs->refcyc_per_pte_group_vblank_c, dlg_regs->refcyc_per_meta_chunk_vblank_l, 198 dlg_regs->refcyc_per_meta_chunk_vblank_c, dlg_regs->refcyc_per_pte_group_flip_l, 199 dlg_regs->refcyc_per_pte_group_flip_c, dlg_regs->refcyc_per_meta_chunk_flip_l, 200 dlg_regs->refcyc_per_meta_chunk_flip_c, dlg_regs->dst_y_per_pte_row_nom_l, 201 dlg_regs->dst_y_per_pte_row_nom_c, dlg_regs->refcyc_per_pte_group_nom_l, 202 dlg_regs->refcyc_per_pte_group_nom_c, dlg_regs->dst_y_per_meta_row_nom_l, 203 dlg_regs->dst_y_per_meta_row_nom_c, dlg_regs->refcyc_per_meta_chunk_nom_l, 204 dlg_regs->refcyc_per_meta_chunk_nom_c, dlg_regs->refcyc_per_line_delivery_pre_l, 205 dlg_regs->refcyc_per_line_delivery_pre_c, dlg_regs->refcyc_per_line_delivery_l, 206 dlg_regs->refcyc_per_line_delivery_c, dlg_regs->chunk_hdl_adjust_cur0, dlg_regs->dst_y_offset_cur1, 207 dlg_regs->chunk_hdl_adjust_cur1, dlg_regs->vready_after_vcount0, dlg_regs->dst_y_delta_drq_limit, 208 dlg_regs->xfc_reg_transfer_delay, dlg_regs->xfc_reg_precharge_delay, 209 dlg_regs->xfc_reg_remote_surface_flip_latency); 210 } 211 212 DTN_INFO("========TTU========\n"); 213 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" 214 " rc_rd_c rc_rd_c0 rc_rd_pc0 rc_rd_c1 rc_rd_pc1 qos_lf_l qos_rds_l" 215 " qos_lf_c qos_rds_c qos_lf_c0 qos_rds_c0 qos_lf_c1 qos_rds_c1\n"); 216 for (i = 0; i < pool->pipe_count; i++) { 217 struct dcn_hubp_state *s = &(TO_DCN10_HUBP(pool->hubps[i])->state); 218 struct _vcs_dpi_display_ttu_regs_st *ttu_regs = &s->ttu_attr; 219 220 if (!s->blank_en) 221 DTN_INFO("[%2d]: %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh\n", 222 pool->hubps[i]->inst, ttu_regs->qos_level_low_wm, ttu_regs->qos_level_high_wm, ttu_regs->min_ttu_vblank, 223 ttu_regs->qos_level_flip, ttu_regs->refcyc_per_req_delivery_pre_l, ttu_regs->refcyc_per_req_delivery_l, 224 ttu_regs->refcyc_per_req_delivery_pre_c, ttu_regs->refcyc_per_req_delivery_c, ttu_regs->refcyc_per_req_delivery_cur0, 225 ttu_regs->refcyc_per_req_delivery_pre_cur0, ttu_regs->refcyc_per_req_delivery_cur1, 226 ttu_regs->refcyc_per_req_delivery_pre_cur1, ttu_regs->qos_level_fixed_l, ttu_regs->qos_ramp_disable_l, 227 ttu_regs->qos_level_fixed_c, ttu_regs->qos_ramp_disable_c, ttu_regs->qos_level_fixed_cur0, 228 ttu_regs->qos_ramp_disable_cur0, ttu_regs->qos_level_fixed_cur1, ttu_regs->qos_ramp_disable_cur1); 229 } 230 DTN_INFO("\n"); 231 } 232 233 static 234 void dcn10_log_hw_state(struct dc *dc) 235 { 236 struct dc_context *dc_ctx = dc->ctx; 237 struct resource_pool *pool = dc->res_pool; 238 int i; 239 240 DTN_INFO_BEGIN(); 241 242 dcn10_log_hubbub_state(dc); 243 244 dcn10_log_hubp_states(dc); 245 246 DTN_INFO("DPP: IGAM format IGAM mode DGAM mode RGAM mode" 247 " GAMUT mode C11 C12 C13 C14 C21 C22 C23 C24 " 248 "C31 C32 C33 C34\n"); 249 for (i = 0; i < pool->pipe_count; i++) { 250 struct dpp *dpp = pool->dpps[i]; 251 struct dcn_dpp_state s; 252 253 dpp->funcs->dpp_read_state(dpp, &s); 254 255 DTN_INFO("[%2d]: %11xh %-11s %-11s %-11s" 256 "%8x %08xh %08xh %08xh %08xh %08xh %08xh", 257 dpp->inst, 258 s.igam_input_format, 259 (s.igam_lut_mode == 0) ? "BypassFixed" : 260 ((s.igam_lut_mode == 1) ? "BypassFloat" : 261 ((s.igam_lut_mode == 2) ? "RAM" : 262 ((s.igam_lut_mode == 3) ? "RAM" : 263 "Unknown"))), 264 (s.dgam_lut_mode == 0) ? "Bypass" : 265 ((s.dgam_lut_mode == 1) ? "sRGB" : 266 ((s.dgam_lut_mode == 2) ? "Ycc" : 267 ((s.dgam_lut_mode == 3) ? "RAM" : 268 ((s.dgam_lut_mode == 4) ? "RAM" : 269 "Unknown")))), 270 (s.rgam_lut_mode == 0) ? "Bypass" : 271 ((s.rgam_lut_mode == 1) ? "sRGB" : 272 ((s.rgam_lut_mode == 2) ? "Ycc" : 273 ((s.rgam_lut_mode == 3) ? "RAM" : 274 ((s.rgam_lut_mode == 4) ? "RAM" : 275 "Unknown")))), 276 s.gamut_remap_mode, 277 s.gamut_remap_c11_c12, 278 s.gamut_remap_c13_c14, 279 s.gamut_remap_c21_c22, 280 s.gamut_remap_c23_c24, 281 s.gamut_remap_c31_c32, 282 s.gamut_remap_c33_c34); 283 DTN_INFO("\n"); 284 } 285 DTN_INFO("\n"); 286 287 DTN_INFO("MPCC: OPP DPP MPCCBOT MODE ALPHA_MODE PREMULT OVERLAP_ONLY IDLE\n"); 288 for (i = 0; i < pool->pipe_count; i++) { 289 struct mpcc_state s = {0}; 290 291 pool->mpc->funcs->read_mpcc_state(pool->mpc, i, &s); 292 if (s.opp_id != 0xf) 293 DTN_INFO("[%2d]: %2xh %2xh %6xh %4d %10d %7d %12d %4d\n", 294 i, s.opp_id, s.dpp_id, s.bot_mpcc_id, 295 s.mode, s.alpha_mode, s.pre_multiplied_alpha, s.overlap_only, 296 s.idle); 297 } 298 DTN_INFO("\n"); 299 300 DTN_INFO("OTG: v_bs v_be v_ss v_se vpol vmax vmin vmax_sel vmin_sel" 301 " h_bs h_be h_ss h_se hpol htot vtot underflow\n"); 302 303 for (i = 0; i < pool->timing_generator_count; i++) { 304 struct timing_generator *tg = pool->timing_generators[i]; 305 struct dcn_otg_state s = {0}; 306 307 optc1_read_otg_state(DCN10TG_FROM_TG(tg), &s); 308 309 //only print if OTG master is enabled 310 if ((s.otg_enabled & 1) == 0) 311 continue; 312 313 DTN_INFO("[%d]: %5d %5d %5d %5d %5d %5d %5d %9d %9d %5d %5d %5d" 314 " %5d %5d %5d %5d %9d\n", 315 tg->inst, 316 s.v_blank_start, 317 s.v_blank_end, 318 s.v_sync_a_start, 319 s.v_sync_a_end, 320 s.v_sync_a_pol, 321 s.v_total_max, 322 s.v_total_min, 323 s.v_total_max_sel, 324 s.v_total_min_sel, 325 s.h_blank_start, 326 s.h_blank_end, 327 s.h_sync_a_start, 328 s.h_sync_a_end, 329 s.h_sync_a_pol, 330 s.h_total, 331 s.v_total, 332 s.underflow_occurred_status); 333 334 // Clear underflow for debug purposes 335 // We want to keep underflow sticky bit on for the longevity tests outside of test environment. 336 // This function is called only from Windows or Diags test environment, hence it's safe to clear 337 // it from here without affecting the original intent. 338 tg->funcs->clear_optc_underflow(tg); 339 } 340 DTN_INFO("\n"); 341 342 DTN_INFO("\nCALCULATED Clocks: dcfclk_khz:%d dcfclk_deep_sleep_khz:%d dispclk_khz:%d\n" 343 "dppclk_khz:%d max_supported_dppclk_khz:%d fclk_khz:%d socclk_khz:%d\n\n", 344 dc->current_state->bw.dcn.clk.dcfclk_khz, 345 dc->current_state->bw.dcn.clk.dcfclk_deep_sleep_khz, 346 dc->current_state->bw.dcn.clk.dispclk_khz, 347 dc->current_state->bw.dcn.clk.dppclk_khz, 348 dc->current_state->bw.dcn.clk.max_supported_dppclk_khz, 349 dc->current_state->bw.dcn.clk.fclk_khz, 350 dc->current_state->bw.dcn.clk.socclk_khz); 351 352 log_mpc_crc(dc); 353 354 DTN_INFO_END(); 355 } 356 357 static void enable_power_gating_plane( 358 struct dce_hwseq *hws, 359 bool enable) 360 { 361 bool force_on = 1; /* disable power gating */ 362 363 if (enable) 364 force_on = 0; 365 366 /* DCHUBP0/1/2/3 */ 367 REG_UPDATE(DOMAIN0_PG_CONFIG, DOMAIN0_POWER_FORCEON, force_on); 368 REG_UPDATE(DOMAIN2_PG_CONFIG, DOMAIN2_POWER_FORCEON, force_on); 369 REG_UPDATE(DOMAIN4_PG_CONFIG, DOMAIN4_POWER_FORCEON, force_on); 370 REG_UPDATE(DOMAIN6_PG_CONFIG, DOMAIN6_POWER_FORCEON, force_on); 371 372 /* DPP0/1/2/3 */ 373 REG_UPDATE(DOMAIN1_PG_CONFIG, DOMAIN1_POWER_FORCEON, force_on); 374 REG_UPDATE(DOMAIN3_PG_CONFIG, DOMAIN3_POWER_FORCEON, force_on); 375 REG_UPDATE(DOMAIN5_PG_CONFIG, DOMAIN5_POWER_FORCEON, force_on); 376 REG_UPDATE(DOMAIN7_PG_CONFIG, DOMAIN7_POWER_FORCEON, force_on); 377 } 378 379 static void disable_vga( 380 struct dce_hwseq *hws) 381 { 382 unsigned int in_vga1_mode = 0; 383 unsigned int in_vga2_mode = 0; 384 unsigned int in_vga3_mode = 0; 385 unsigned int in_vga4_mode = 0; 386 387 REG_GET(D1VGA_CONTROL, D1VGA_MODE_ENABLE, &in_vga1_mode); 388 REG_GET(D2VGA_CONTROL, D2VGA_MODE_ENABLE, &in_vga2_mode); 389 REG_GET(D3VGA_CONTROL, D3VGA_MODE_ENABLE, &in_vga3_mode); 390 REG_GET(D4VGA_CONTROL, D4VGA_MODE_ENABLE, &in_vga4_mode); 391 392 if (in_vga1_mode == 0 && in_vga2_mode == 0 && 393 in_vga3_mode == 0 && in_vga4_mode == 0) 394 return; 395 396 REG_WRITE(D1VGA_CONTROL, 0); 397 REG_WRITE(D2VGA_CONTROL, 0); 398 REG_WRITE(D3VGA_CONTROL, 0); 399 REG_WRITE(D4VGA_CONTROL, 0); 400 401 /* HW Engineer's Notes: 402 * During switch from vga->extended, if we set the VGA_TEST_ENABLE and 403 * then hit the VGA_TEST_RENDER_START, then the DCHUBP timing gets updated correctly. 404 * 405 * Then vBIOS will have it poll for the VGA_TEST_RENDER_DONE and unset 406 * VGA_TEST_ENABLE, to leave it in the same state as before. 407 */ 408 REG_UPDATE(VGA_TEST_CONTROL, VGA_TEST_ENABLE, 1); 409 REG_UPDATE(VGA_TEST_CONTROL, VGA_TEST_RENDER_START, 1); 410 } 411 412 static void dpp_pg_control( 413 struct dce_hwseq *hws, 414 unsigned int dpp_inst, 415 bool power_on) 416 { 417 uint32_t power_gate = power_on ? 0 : 1; 418 uint32_t pwr_status = power_on ? 0 : 2; 419 420 if (hws->ctx->dc->debug.disable_dpp_power_gate) 421 return; 422 if (REG(DOMAIN1_PG_CONFIG) == 0) 423 return; 424 425 switch (dpp_inst) { 426 case 0: /* DPP0 */ 427 REG_UPDATE(DOMAIN1_PG_CONFIG, 428 DOMAIN1_POWER_GATE, power_gate); 429 430 REG_WAIT(DOMAIN1_PG_STATUS, 431 DOMAIN1_PGFSM_PWR_STATUS, pwr_status, 432 1, 1000); 433 break; 434 case 1: /* DPP1 */ 435 REG_UPDATE(DOMAIN3_PG_CONFIG, 436 DOMAIN3_POWER_GATE, power_gate); 437 438 REG_WAIT(DOMAIN3_PG_STATUS, 439 DOMAIN3_PGFSM_PWR_STATUS, pwr_status, 440 1, 1000); 441 break; 442 case 2: /* DPP2 */ 443 REG_UPDATE(DOMAIN5_PG_CONFIG, 444 DOMAIN5_POWER_GATE, power_gate); 445 446 REG_WAIT(DOMAIN5_PG_STATUS, 447 DOMAIN5_PGFSM_PWR_STATUS, pwr_status, 448 1, 1000); 449 break; 450 case 3: /* DPP3 */ 451 REG_UPDATE(DOMAIN7_PG_CONFIG, 452 DOMAIN7_POWER_GATE, power_gate); 453 454 REG_WAIT(DOMAIN7_PG_STATUS, 455 DOMAIN7_PGFSM_PWR_STATUS, pwr_status, 456 1, 1000); 457 break; 458 default: 459 BREAK_TO_DEBUGGER(); 460 break; 461 } 462 } 463 464 static void hubp_pg_control( 465 struct dce_hwseq *hws, 466 unsigned int hubp_inst, 467 bool power_on) 468 { 469 uint32_t power_gate = power_on ? 0 : 1; 470 uint32_t pwr_status = power_on ? 0 : 2; 471 472 if (hws->ctx->dc->debug.disable_hubp_power_gate) 473 return; 474 if (REG(DOMAIN0_PG_CONFIG) == 0) 475 return; 476 477 switch (hubp_inst) { 478 case 0: /* DCHUBP0 */ 479 REG_UPDATE(DOMAIN0_PG_CONFIG, 480 DOMAIN0_POWER_GATE, power_gate); 481 482 REG_WAIT(DOMAIN0_PG_STATUS, 483 DOMAIN0_PGFSM_PWR_STATUS, pwr_status, 484 1, 1000); 485 break; 486 case 1: /* DCHUBP1 */ 487 REG_UPDATE(DOMAIN2_PG_CONFIG, 488 DOMAIN2_POWER_GATE, power_gate); 489 490 REG_WAIT(DOMAIN2_PG_STATUS, 491 DOMAIN2_PGFSM_PWR_STATUS, pwr_status, 492 1, 1000); 493 break; 494 case 2: /* DCHUBP2 */ 495 REG_UPDATE(DOMAIN4_PG_CONFIG, 496 DOMAIN4_POWER_GATE, power_gate); 497 498 REG_WAIT(DOMAIN4_PG_STATUS, 499 DOMAIN4_PGFSM_PWR_STATUS, pwr_status, 500 1, 1000); 501 break; 502 case 3: /* DCHUBP3 */ 503 REG_UPDATE(DOMAIN6_PG_CONFIG, 504 DOMAIN6_POWER_GATE, power_gate); 505 506 REG_WAIT(DOMAIN6_PG_STATUS, 507 DOMAIN6_PGFSM_PWR_STATUS, pwr_status, 508 1, 1000); 509 break; 510 default: 511 BREAK_TO_DEBUGGER(); 512 break; 513 } 514 } 515 516 static void power_on_plane( 517 struct dce_hwseq *hws, 518 int plane_id) 519 { 520 DC_LOGGER_INIT(hws->ctx->logger); 521 if (REG(DC_IP_REQUEST_CNTL)) { 522 REG_SET(DC_IP_REQUEST_CNTL, 0, 523 IP_REQUEST_EN, 1); 524 dpp_pg_control(hws, plane_id, true); 525 hubp_pg_control(hws, plane_id, true); 526 REG_SET(DC_IP_REQUEST_CNTL, 0, 527 IP_REQUEST_EN, 0); 528 DC_LOG_DEBUG( 529 "Un-gated front end for pipe %d\n", plane_id); 530 } 531 } 532 533 static void undo_DEGVIDCN10_253_wa(struct dc *dc) 534 { 535 struct dce_hwseq *hws = dc->hwseq; 536 struct hubp *hubp = dc->res_pool->hubps[0]; 537 538 if (!hws->wa_state.DEGVIDCN10_253_applied) 539 return; 540 541 hubp->funcs->set_blank(hubp, true); 542 543 REG_SET(DC_IP_REQUEST_CNTL, 0, 544 IP_REQUEST_EN, 1); 545 546 hubp_pg_control(hws, 0, false); 547 REG_SET(DC_IP_REQUEST_CNTL, 0, 548 IP_REQUEST_EN, 0); 549 550 hws->wa_state.DEGVIDCN10_253_applied = false; 551 } 552 553 static void apply_DEGVIDCN10_253_wa(struct dc *dc) 554 { 555 struct dce_hwseq *hws = dc->hwseq; 556 struct hubp *hubp = dc->res_pool->hubps[0]; 557 int i; 558 559 if (dc->debug.disable_stutter) 560 return; 561 562 if (!hws->wa.DEGVIDCN10_253) 563 return; 564 565 for (i = 0; i < dc->res_pool->pipe_count; i++) { 566 if (!dc->res_pool->hubps[i]->power_gated) 567 return; 568 } 569 570 /* all pipe power gated, apply work around to enable stutter. */ 571 572 REG_SET(DC_IP_REQUEST_CNTL, 0, 573 IP_REQUEST_EN, 1); 574 575 hubp_pg_control(hws, 0, true); 576 REG_SET(DC_IP_REQUEST_CNTL, 0, 577 IP_REQUEST_EN, 0); 578 579 hubp->funcs->set_hubp_blank_en(hubp, false); 580 hws->wa_state.DEGVIDCN10_253_applied = true; 581 } 582 583 static void bios_golden_init(struct dc *dc) 584 { 585 struct dc_bios *bp = dc->ctx->dc_bios; 586 int i; 587 588 /* initialize dcn global */ 589 bp->funcs->enable_disp_power_gating(bp, 590 CONTROLLER_ID_D0, ASIC_PIPE_INIT); 591 592 for (i = 0; i < dc->res_pool->pipe_count; i++) { 593 /* initialize dcn per pipe */ 594 bp->funcs->enable_disp_power_gating(bp, 595 CONTROLLER_ID_D0 + i, ASIC_PIPE_DISABLE); 596 } 597 } 598 599 static void false_optc_underflow_wa( 600 struct dc *dc, 601 const struct dc_stream_state *stream, 602 struct timing_generator *tg) 603 { 604 int i; 605 bool underflow; 606 607 if (!dc->hwseq->wa.false_optc_underflow) 608 return; 609 610 underflow = tg->funcs->is_optc_underflow_occurred(tg); 611 612 for (i = 0; i < dc->res_pool->pipe_count; i++) { 613 struct pipe_ctx *old_pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i]; 614 615 if (old_pipe_ctx->stream != stream) 616 continue; 617 618 dc->hwss.wait_for_mpcc_disconnect(dc, dc->res_pool, old_pipe_ctx); 619 } 620 621 tg->funcs->set_blank_data_double_buffer(tg, true); 622 623 if (tg->funcs->is_optc_underflow_occurred(tg) && !underflow) 624 tg->funcs->clear_optc_underflow(tg); 625 } 626 627 static enum dc_status dcn10_enable_stream_timing( 628 struct pipe_ctx *pipe_ctx, 629 struct dc_state *context, 630 struct dc *dc) 631 { 632 struct dc_stream_state *stream = pipe_ctx->stream; 633 enum dc_color_space color_space; 634 struct tg_color black_color = {0}; 635 636 /* by upper caller loop, pipe0 is parent pipe and be called first. 637 * back end is set up by for pipe0. Other children pipe share back end 638 * with pipe 0. No program is needed. 639 */ 640 if (pipe_ctx->top_pipe != NULL) 641 return DC_OK; 642 643 /* TODO check if timing_changed, disable stream if timing changed */ 644 645 /* HW program guide assume display already disable 646 * by unplug sequence. OTG assume stop. 647 */ 648 pipe_ctx->stream_res.tg->funcs->enable_optc_clock(pipe_ctx->stream_res.tg, true); 649 650 if (false == pipe_ctx->clock_source->funcs->program_pix_clk( 651 pipe_ctx->clock_source, 652 &pipe_ctx->stream_res.pix_clk_params, 653 &pipe_ctx->pll_settings)) { 654 BREAK_TO_DEBUGGER(); 655 return DC_ERROR_UNEXPECTED; 656 } 657 pipe_ctx->stream_res.tg->dlg_otg_param.vready_offset = pipe_ctx->pipe_dlg_param.vready_offset; 658 pipe_ctx->stream_res.tg->dlg_otg_param.vstartup_start = pipe_ctx->pipe_dlg_param.vstartup_start; 659 pipe_ctx->stream_res.tg->dlg_otg_param.vupdate_offset = pipe_ctx->pipe_dlg_param.vupdate_offset; 660 pipe_ctx->stream_res.tg->dlg_otg_param.vupdate_width = pipe_ctx->pipe_dlg_param.vupdate_width; 661 662 pipe_ctx->stream_res.tg->dlg_otg_param.signal = pipe_ctx->stream->signal; 663 664 pipe_ctx->stream_res.tg->funcs->program_timing( 665 pipe_ctx->stream_res.tg, 666 &stream->timing, 667 true); 668 669 #if 0 /* move to after enable_crtc */ 670 /* TODO: OPP FMT, ABM. etc. should be done here. */ 671 /* or FPGA now. instance 0 only. TODO: move to opp.c */ 672 673 inst_offset = reg_offsets[pipe_ctx->stream_res.tg->inst].fmt; 674 675 pipe_ctx->stream_res.opp->funcs->opp_program_fmt( 676 pipe_ctx->stream_res.opp, 677 &stream->bit_depth_params, 678 &stream->clamping); 679 #endif 680 /* program otg blank color */ 681 color_space = stream->output_color_space; 682 color_space_to_black_color(dc, color_space, &black_color); 683 684 if (pipe_ctx->stream_res.tg->funcs->set_blank_color) 685 pipe_ctx->stream_res.tg->funcs->set_blank_color( 686 pipe_ctx->stream_res.tg, 687 &black_color); 688 689 if (pipe_ctx->stream_res.tg->funcs->is_blanked && 690 !pipe_ctx->stream_res.tg->funcs->is_blanked(pipe_ctx->stream_res.tg)) { 691 pipe_ctx->stream_res.tg->funcs->set_blank(pipe_ctx->stream_res.tg, true); 692 hwss_wait_for_blank_complete(pipe_ctx->stream_res.tg); 693 false_optc_underflow_wa(dc, pipe_ctx->stream, pipe_ctx->stream_res.tg); 694 } 695 696 /* VTG is within DCHUB command block. DCFCLK is always on */ 697 if (false == pipe_ctx->stream_res.tg->funcs->enable_crtc(pipe_ctx->stream_res.tg)) { 698 BREAK_TO_DEBUGGER(); 699 return DC_ERROR_UNEXPECTED; 700 } 701 702 /* TODO program crtc source select for non-virtual signal*/ 703 /* TODO program FMT */ 704 /* TODO setup link_enc */ 705 /* TODO set stream attributes */ 706 /* TODO program audio */ 707 /* TODO enable stream if timing changed */ 708 /* TODO unblank stream if DP */ 709 710 return DC_OK; 711 } 712 713 static void reset_back_end_for_pipe( 714 struct dc *dc, 715 struct pipe_ctx *pipe_ctx, 716 struct dc_state *context) 717 { 718 int i; 719 DC_LOGGER_INIT(dc->ctx->logger); 720 if (pipe_ctx->stream_res.stream_enc == NULL) { 721 pipe_ctx->stream = NULL; 722 return; 723 } 724 725 if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) { 726 /* DPMS may already disable */ 727 if (!pipe_ctx->stream->dpms_off) 728 core_link_disable_stream(pipe_ctx, FREE_ACQUIRED_RESOURCE); 729 else if (pipe_ctx->stream_res.audio) { 730 dc->hwss.disable_audio_stream(pipe_ctx, FREE_ACQUIRED_RESOURCE); 731 } 732 733 } 734 735 /* by upper caller loop, parent pipe: pipe0, will be reset last. 736 * back end share by all pipes and will be disable only when disable 737 * parent pipe. 738 */ 739 if (pipe_ctx->top_pipe == NULL) { 740 pipe_ctx->stream_res.tg->funcs->disable_crtc(pipe_ctx->stream_res.tg); 741 742 pipe_ctx->stream_res.tg->funcs->enable_optc_clock(pipe_ctx->stream_res.tg, false); 743 } 744 745 for (i = 0; i < dc->res_pool->pipe_count; i++) 746 if (&dc->current_state->res_ctx.pipe_ctx[i] == pipe_ctx) 747 break; 748 749 if (i == dc->res_pool->pipe_count) 750 return; 751 752 pipe_ctx->stream = NULL; 753 DC_LOG_DEBUG("Reset back end for pipe %d, tg:%d\n", 754 pipe_ctx->pipe_idx, pipe_ctx->stream_res.tg->inst); 755 } 756 757 static bool dcn10_hw_wa_force_recovery(struct dc *dc) 758 { 759 struct hubp *hubp ; 760 unsigned int i; 761 bool need_recover = true; 762 763 if (!dc->debug.recovery_enabled) 764 return false; 765 766 for (i = 0; i < dc->res_pool->pipe_count; i++) { 767 struct pipe_ctx *pipe_ctx = 768 &dc->current_state->res_ctx.pipe_ctx[i]; 769 if (pipe_ctx != NULL) { 770 hubp = pipe_ctx->plane_res.hubp; 771 if (hubp != NULL) { 772 if (hubp->funcs->hubp_get_underflow_status(hubp) != 0) { 773 /* one pipe underflow, we will reset all the pipes*/ 774 need_recover = true; 775 } 776 } 777 } 778 } 779 if (!need_recover) 780 return false; 781 /* 782 DCHUBP_CNTL:HUBP_BLANK_EN=1 783 DCHUBBUB_SOFT_RESET:DCHUBBUB_GLOBAL_SOFT_RESET=1 784 DCHUBP_CNTL:HUBP_DISABLE=1 785 DCHUBP_CNTL:HUBP_DISABLE=0 786 DCHUBBUB_SOFT_RESET:DCHUBBUB_GLOBAL_SOFT_RESET=0 787 DCSURF_PRIMARY_SURFACE_ADDRESS 788 DCHUBP_CNTL:HUBP_BLANK_EN=0 789 */ 790 791 for (i = 0; i < dc->res_pool->pipe_count; i++) { 792 struct pipe_ctx *pipe_ctx = 793 &dc->current_state->res_ctx.pipe_ctx[i]; 794 if (pipe_ctx != NULL) { 795 hubp = pipe_ctx->plane_res.hubp; 796 /*DCHUBP_CNTL:HUBP_BLANK_EN=1*/ 797 if (hubp != NULL) 798 hubp->funcs->set_hubp_blank_en(hubp, true); 799 } 800 } 801 /*DCHUBBUB_SOFT_RESET:DCHUBBUB_GLOBAL_SOFT_RESET=1*/ 802 hubbub1_soft_reset(dc->res_pool->hubbub, true); 803 804 for (i = 0; i < dc->res_pool->pipe_count; i++) { 805 struct pipe_ctx *pipe_ctx = 806 &dc->current_state->res_ctx.pipe_ctx[i]; 807 if (pipe_ctx != NULL) { 808 hubp = pipe_ctx->plane_res.hubp; 809 /*DCHUBP_CNTL:HUBP_DISABLE=1*/ 810 if (hubp != NULL) 811 hubp->funcs->hubp_disable_control(hubp, true); 812 } 813 } 814 for (i = 0; i < dc->res_pool->pipe_count; i++) { 815 struct pipe_ctx *pipe_ctx = 816 &dc->current_state->res_ctx.pipe_ctx[i]; 817 if (pipe_ctx != NULL) { 818 hubp = pipe_ctx->plane_res.hubp; 819 /*DCHUBP_CNTL:HUBP_DISABLE=0*/ 820 if (hubp != NULL) 821 hubp->funcs->hubp_disable_control(hubp, true); 822 } 823 } 824 /*DCHUBBUB_SOFT_RESET:DCHUBBUB_GLOBAL_SOFT_RESET=0*/ 825 hubbub1_soft_reset(dc->res_pool->hubbub, false); 826 for (i = 0; i < dc->res_pool->pipe_count; i++) { 827 struct pipe_ctx *pipe_ctx = 828 &dc->current_state->res_ctx.pipe_ctx[i]; 829 if (pipe_ctx != NULL) { 830 hubp = pipe_ctx->plane_res.hubp; 831 /*DCHUBP_CNTL:HUBP_BLANK_EN=0*/ 832 if (hubp != NULL) 833 hubp->funcs->set_hubp_blank_en(hubp, true); 834 } 835 } 836 return true; 837 838 } 839 840 841 void dcn10_verify_allow_pstate_change_high(struct dc *dc) 842 { 843 static bool should_log_hw_state; /* prevent hw state log by default */ 844 845 if (!hubbub1_verify_allow_pstate_change_high(dc->res_pool->hubbub)) { 846 if (should_log_hw_state) { 847 dcn10_log_hw_state(dc); 848 } 849 BREAK_TO_DEBUGGER(); 850 if (dcn10_hw_wa_force_recovery(dc)) { 851 /*check again*/ 852 if (!hubbub1_verify_allow_pstate_change_high(dc->res_pool->hubbub)) 853 BREAK_TO_DEBUGGER(); 854 } 855 } 856 } 857 858 /* trigger HW to start disconnect plane from stream on the next vsync */ 859 void hwss1_plane_atomic_disconnect(struct dc *dc, struct pipe_ctx *pipe_ctx) 860 { 861 struct hubp *hubp = pipe_ctx->plane_res.hubp; 862 int dpp_id = pipe_ctx->plane_res.dpp->inst; 863 struct mpc *mpc = dc->res_pool->mpc; 864 struct mpc_tree *mpc_tree_params; 865 struct mpcc *mpcc_to_remove = NULL; 866 struct output_pixel_processor *opp = pipe_ctx->stream_res.opp; 867 868 mpc_tree_params = &(opp->mpc_tree_params); 869 mpcc_to_remove = mpc->funcs->get_mpcc_for_dpp(mpc_tree_params, dpp_id); 870 871 /*Already reset*/ 872 if (mpcc_to_remove == NULL) 873 return; 874 875 mpc->funcs->remove_mpcc(mpc, mpc_tree_params, mpcc_to_remove); 876 if (opp != NULL) 877 opp->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true; 878 879 dc->optimized_required = true; 880 881 if (hubp->funcs->hubp_disconnect) 882 hubp->funcs->hubp_disconnect(hubp); 883 884 if (dc->debug.sanity_checks) 885 dcn10_verify_allow_pstate_change_high(dc); 886 } 887 888 static void plane_atomic_power_down(struct dc *dc, struct pipe_ctx *pipe_ctx) 889 { 890 struct dce_hwseq *hws = dc->hwseq; 891 struct dpp *dpp = pipe_ctx->plane_res.dpp; 892 DC_LOGGER_INIT(dc->ctx->logger); 893 894 if (REG(DC_IP_REQUEST_CNTL)) { 895 REG_SET(DC_IP_REQUEST_CNTL, 0, 896 IP_REQUEST_EN, 1); 897 dpp_pg_control(hws, dpp->inst, false); 898 hubp_pg_control(hws, pipe_ctx->plane_res.hubp->inst, false); 899 dpp->funcs->dpp_reset(dpp); 900 REG_SET(DC_IP_REQUEST_CNTL, 0, 901 IP_REQUEST_EN, 0); 902 DC_LOG_DEBUG( 903 "Power gated front end %d\n", pipe_ctx->pipe_idx); 904 } 905 } 906 907 /* disable HW used by plane. 908 * note: cannot disable until disconnect is complete 909 */ 910 static void plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx) 911 { 912 struct hubp *hubp = pipe_ctx->plane_res.hubp; 913 struct dpp *dpp = pipe_ctx->plane_res.dpp; 914 int opp_id = hubp->opp_id; 915 916 dc->hwss.wait_for_mpcc_disconnect(dc, dc->res_pool, pipe_ctx); 917 918 hubp->funcs->hubp_clk_cntl(hubp, false); 919 920 dpp->funcs->dpp_dppclk_control(dpp, false, false); 921 922 if (opp_id != 0xf && pipe_ctx->stream_res.opp->mpc_tree_params.opp_list == NULL) 923 pipe_ctx->stream_res.opp->funcs->opp_pipe_clock_control( 924 pipe_ctx->stream_res.opp, 925 false); 926 927 hubp->power_gated = true; 928 dc->optimized_required = false; /* We're powering off, no need to optimize */ 929 930 plane_atomic_power_down(dc, pipe_ctx); 931 932 pipe_ctx->stream = NULL; 933 memset(&pipe_ctx->stream_res, 0, sizeof(pipe_ctx->stream_res)); 934 memset(&pipe_ctx->plane_res, 0, sizeof(pipe_ctx->plane_res)); 935 pipe_ctx->top_pipe = NULL; 936 pipe_ctx->bottom_pipe = NULL; 937 pipe_ctx->plane_state = NULL; 938 } 939 940 static void dcn10_disable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx) 941 { 942 DC_LOGGER_INIT(dc->ctx->logger); 943 944 if (!pipe_ctx->plane_res.hubp || pipe_ctx->plane_res.hubp->power_gated) 945 return; 946 947 plane_atomic_disable(dc, pipe_ctx); 948 949 apply_DEGVIDCN10_253_wa(dc); 950 951 DC_LOG_DC("Power down front end %d\n", 952 pipe_ctx->pipe_idx); 953 } 954 955 static void dcn10_init_hw(struct dc *dc) 956 { 957 int i; 958 struct abm *abm = dc->res_pool->abm; 959 struct dmcu *dmcu = dc->res_pool->dmcu; 960 struct dce_hwseq *hws = dc->hwseq; 961 struct dc_bios *dcb = dc->ctx->dc_bios; 962 struct dc_state *context = dc->current_state; 963 964 if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) { 965 REG_WRITE(REFCLK_CNTL, 0); 966 REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_ENABLE, 1); 967 REG_WRITE(DIO_MEM_PWR_CTRL, 0); 968 969 if (!dc->debug.disable_clock_gate) { 970 /* enable all DCN clock gating */ 971 REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0); 972 973 REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0); 974 975 REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0); 976 } 977 978 enable_power_gating_plane(dc->hwseq, true); 979 } else { 980 981 if (!dcb->funcs->is_accelerated_mode(dcb)) { 982 bios_golden_init(dc); 983 disable_vga(dc->hwseq); 984 } 985 986 for (i = 0; i < dc->link_count; i++) { 987 /* Power up AND update implementation according to the 988 * required signal (which may be different from the 989 * default signal on connector). 990 */ 991 struct dc_link *link = dc->links[i]; 992 993 if (link->link_enc->connector.id == CONNECTOR_ID_EDP) 994 dc->hwss.edp_power_control(link, true); 995 996 link->link_enc->funcs->hw_init(link->link_enc); 997 } 998 } 999 1000 for (i = 0; i < dc->res_pool->pipe_count; i++) { 1001 struct timing_generator *tg = dc->res_pool->timing_generators[i]; 1002 1003 if (tg->funcs->is_tg_enabled(tg)) 1004 tg->funcs->lock(tg); 1005 } 1006 1007 /* Blank controller using driver code instead of 1008 * command table. 1009 */ 1010 for (i = 0; i < dc->res_pool->pipe_count; i++) { 1011 struct timing_generator *tg = dc->res_pool->timing_generators[i]; 1012 1013 if (tg->funcs->is_tg_enabled(tg)) { 1014 tg->funcs->set_blank(tg, true); 1015 hwss_wait_for_blank_complete(tg); 1016 } 1017 } 1018 1019 /* Reset all MPCC muxes */ 1020 dc->res_pool->mpc->funcs->mpc_init(dc->res_pool->mpc); 1021 1022 for (i = 0; i < dc->res_pool->timing_generator_count; i++) { 1023 struct timing_generator *tg = dc->res_pool->timing_generators[i]; 1024 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; 1025 struct hubp *hubp = dc->res_pool->hubps[i]; 1026 struct dpp *dpp = dc->res_pool->dpps[i]; 1027 1028 pipe_ctx->stream_res.tg = tg; 1029 pipe_ctx->pipe_idx = i; 1030 1031 pipe_ctx->plane_res.hubp = hubp; 1032 pipe_ctx->plane_res.dpp = dpp; 1033 pipe_ctx->plane_res.mpcc_inst = dpp->inst; 1034 hubp->mpcc_id = dpp->inst; 1035 hubp->opp_id = 0xf; 1036 hubp->power_gated = false; 1037 1038 dc->res_pool->opps[i]->mpc_tree_params.opp_id = dc->res_pool->opps[i]->inst; 1039 dc->res_pool->opps[i]->mpc_tree_params.opp_list = NULL; 1040 dc->res_pool->opps[i]->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true; 1041 pipe_ctx->stream_res.opp = dc->res_pool->opps[i]; 1042 1043 hwss1_plane_atomic_disconnect(dc, pipe_ctx); 1044 } 1045 1046 for (i = 0; i < dc->res_pool->pipe_count; i++) { 1047 struct timing_generator *tg = dc->res_pool->timing_generators[i]; 1048 1049 if (tg->funcs->is_tg_enabled(tg)) 1050 tg->funcs->unlock(tg); 1051 } 1052 1053 for (i = 0; i < dc->res_pool->pipe_count; i++) { 1054 struct timing_generator *tg = dc->res_pool->timing_generators[i]; 1055 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; 1056 1057 dcn10_disable_plane(dc, pipe_ctx); 1058 1059 pipe_ctx->stream_res.tg = NULL; 1060 pipe_ctx->plane_res.hubp = NULL; 1061 1062 tg->funcs->tg_init(tg); 1063 } 1064 1065 /* end of FPGA. Below if real ASIC */ 1066 if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) 1067 return; 1068 1069 for (i = 0; i < dc->res_pool->audio_count; i++) { 1070 struct audio *audio = dc->res_pool->audios[i]; 1071 1072 audio->funcs->hw_init(audio); 1073 } 1074 1075 if (abm != NULL) { 1076 abm->funcs->init_backlight(abm); 1077 abm->funcs->abm_init(abm); 1078 } 1079 1080 if (dmcu != NULL) 1081 dmcu->funcs->dmcu_init(dmcu); 1082 1083 /* power AFMT HDMI memory TODO: may move to dis/en output save power*/ 1084 REG_WRITE(DIO_MEM_PWR_CTRL, 0); 1085 1086 if (!dc->debug.disable_clock_gate) { 1087 /* enable all DCN clock gating */ 1088 REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0); 1089 1090 REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0); 1091 1092 REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0); 1093 } 1094 1095 enable_power_gating_plane(dc->hwseq, true); 1096 1097 memset(&dc->res_pool->dccg->clks, 0, sizeof(dc->res_pool->dccg->clks)); 1098 } 1099 1100 static void reset_hw_ctx_wrap( 1101 struct dc *dc, 1102 struct dc_state *context) 1103 { 1104 int i; 1105 1106 /* Reset Back End*/ 1107 for (i = dc->res_pool->pipe_count - 1; i >= 0 ; i--) { 1108 struct pipe_ctx *pipe_ctx_old = 1109 &dc->current_state->res_ctx.pipe_ctx[i]; 1110 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; 1111 1112 if (!pipe_ctx_old->stream) 1113 continue; 1114 1115 if (pipe_ctx_old->top_pipe) 1116 continue; 1117 1118 if (!pipe_ctx->stream || 1119 pipe_need_reprogram(pipe_ctx_old, pipe_ctx)) { 1120 struct clock_source *old_clk = pipe_ctx_old->clock_source; 1121 1122 reset_back_end_for_pipe(dc, pipe_ctx_old, dc->current_state); 1123 if (old_clk) 1124 old_clk->funcs->cs_power_down(old_clk); 1125 } 1126 } 1127 1128 } 1129 1130 static bool patch_address_for_sbs_tb_stereo( 1131 struct pipe_ctx *pipe_ctx, PHYSICAL_ADDRESS_LOC *addr) 1132 { 1133 struct dc_plane_state *plane_state = pipe_ctx->plane_state; 1134 bool sec_split = pipe_ctx->top_pipe && 1135 pipe_ctx->top_pipe->plane_state == pipe_ctx->plane_state; 1136 if (sec_split && plane_state->address.type == PLN_ADDR_TYPE_GRPH_STEREO && 1137 (pipe_ctx->stream->timing.timing_3d_format == 1138 TIMING_3D_FORMAT_SIDE_BY_SIDE || 1139 pipe_ctx->stream->timing.timing_3d_format == 1140 TIMING_3D_FORMAT_TOP_AND_BOTTOM)) { 1141 *addr = plane_state->address.grph_stereo.left_addr; 1142 plane_state->address.grph_stereo.left_addr = 1143 plane_state->address.grph_stereo.right_addr; 1144 return true; 1145 } else { 1146 if (pipe_ctx->stream->view_format != VIEW_3D_FORMAT_NONE && 1147 plane_state->address.type != PLN_ADDR_TYPE_GRPH_STEREO) { 1148 plane_state->address.type = PLN_ADDR_TYPE_GRPH_STEREO; 1149 plane_state->address.grph_stereo.right_addr = 1150 plane_state->address.grph_stereo.left_addr; 1151 } 1152 } 1153 return false; 1154 } 1155 1156 1157 1158 static void dcn10_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx) 1159 { 1160 bool addr_patched = false; 1161 PHYSICAL_ADDRESS_LOC addr; 1162 struct dc_plane_state *plane_state = pipe_ctx->plane_state; 1163 1164 if (plane_state == NULL) 1165 return; 1166 1167 addr_patched = patch_address_for_sbs_tb_stereo(pipe_ctx, &addr); 1168 1169 pipe_ctx->plane_res.hubp->funcs->hubp_program_surface_flip_and_addr( 1170 pipe_ctx->plane_res.hubp, 1171 &plane_state->address, 1172 plane_state->flip_immediate); 1173 1174 plane_state->status.requested_address = plane_state->address; 1175 1176 if (plane_state->flip_immediate) 1177 plane_state->status.current_address = plane_state->address; 1178 1179 if (addr_patched) 1180 pipe_ctx->plane_state->address.grph_stereo.left_addr = addr; 1181 } 1182 1183 static bool dcn10_set_input_transfer_func(struct pipe_ctx *pipe_ctx, 1184 const struct dc_plane_state *plane_state) 1185 { 1186 struct dpp *dpp_base = pipe_ctx->plane_res.dpp; 1187 const struct dc_transfer_func *tf = NULL; 1188 bool result = true; 1189 1190 if (dpp_base == NULL) 1191 return false; 1192 1193 if (plane_state->in_transfer_func) 1194 tf = plane_state->in_transfer_func; 1195 1196 if (plane_state->gamma_correction && 1197 !dpp_base->ctx->dc->debug.always_use_regamma 1198 && !plane_state->gamma_correction->is_identity 1199 && dce_use_lut(plane_state->format)) 1200 dpp_base->funcs->dpp_program_input_lut(dpp_base, plane_state->gamma_correction); 1201 1202 if (tf == NULL) 1203 dpp_base->funcs->dpp_set_degamma(dpp_base, IPP_DEGAMMA_MODE_BYPASS); 1204 else if (tf->type == TF_TYPE_PREDEFINED) { 1205 switch (tf->tf) { 1206 case TRANSFER_FUNCTION_SRGB: 1207 dpp_base->funcs->dpp_set_degamma(dpp_base, IPP_DEGAMMA_MODE_HW_sRGB); 1208 break; 1209 case TRANSFER_FUNCTION_BT709: 1210 dpp_base->funcs->dpp_set_degamma(dpp_base, IPP_DEGAMMA_MODE_HW_xvYCC); 1211 break; 1212 case TRANSFER_FUNCTION_LINEAR: 1213 dpp_base->funcs->dpp_set_degamma(dpp_base, IPP_DEGAMMA_MODE_BYPASS); 1214 break; 1215 case TRANSFER_FUNCTION_PQ: 1216 default: 1217 result = false; 1218 break; 1219 } 1220 } else if (tf->type == TF_TYPE_BYPASS) { 1221 dpp_base->funcs->dpp_set_degamma(dpp_base, IPP_DEGAMMA_MODE_BYPASS); 1222 } else { 1223 cm_helper_translate_curve_to_degamma_hw_format(tf, 1224 &dpp_base->degamma_params); 1225 dpp_base->funcs->dpp_program_degamma_pwl(dpp_base, 1226 &dpp_base->degamma_params); 1227 result = true; 1228 } 1229 1230 return result; 1231 } 1232 1233 1234 1235 1236 1237 static bool 1238 dcn10_set_output_transfer_func(struct pipe_ctx *pipe_ctx, 1239 const struct dc_stream_state *stream) 1240 { 1241 struct dpp *dpp = pipe_ctx->plane_res.dpp; 1242 1243 if (dpp == NULL) 1244 return false; 1245 1246 dpp->regamma_params.hw_points_num = GAMMA_HW_POINTS_NUM; 1247 1248 if (stream->out_transfer_func && 1249 stream->out_transfer_func->type == TF_TYPE_PREDEFINED && 1250 stream->out_transfer_func->tf == TRANSFER_FUNCTION_SRGB) 1251 dpp->funcs->dpp_program_regamma_pwl(dpp, NULL, OPP_REGAMMA_SRGB); 1252 1253 /* dcn10_translate_regamma_to_hw_format takes 750us, only do it when full 1254 * update. 1255 */ 1256 else if (cm_helper_translate_curve_to_hw_format( 1257 stream->out_transfer_func, 1258 &dpp->regamma_params, false)) { 1259 dpp->funcs->dpp_program_regamma_pwl( 1260 dpp, 1261 &dpp->regamma_params, OPP_REGAMMA_USER); 1262 } else 1263 dpp->funcs->dpp_program_regamma_pwl(dpp, NULL, OPP_REGAMMA_BYPASS); 1264 1265 return true; 1266 } 1267 1268 static void dcn10_pipe_control_lock( 1269 struct dc *dc, 1270 struct pipe_ctx *pipe, 1271 bool lock) 1272 { 1273 /* use TG master update lock to lock everything on the TG 1274 * therefore only top pipe need to lock 1275 */ 1276 if (pipe->top_pipe) 1277 return; 1278 1279 if (dc->debug.sanity_checks) 1280 dcn10_verify_allow_pstate_change_high(dc); 1281 1282 if (lock) 1283 pipe->stream_res.tg->funcs->lock(pipe->stream_res.tg); 1284 else 1285 pipe->stream_res.tg->funcs->unlock(pipe->stream_res.tg); 1286 1287 if (dc->debug.sanity_checks) 1288 dcn10_verify_allow_pstate_change_high(dc); 1289 } 1290 1291 static bool wait_for_reset_trigger_to_occur( 1292 struct dc_context *dc_ctx, 1293 struct timing_generator *tg) 1294 { 1295 bool rc = false; 1296 1297 /* To avoid endless loop we wait at most 1298 * frames_to_wait_on_triggered_reset frames for the reset to occur. */ 1299 const uint32_t frames_to_wait_on_triggered_reset = 10; 1300 int i; 1301 1302 for (i = 0; i < frames_to_wait_on_triggered_reset; i++) { 1303 1304 if (!tg->funcs->is_counter_moving(tg)) { 1305 DC_ERROR("TG counter is not moving!\n"); 1306 break; 1307 } 1308 1309 if (tg->funcs->did_triggered_reset_occur(tg)) { 1310 rc = true; 1311 /* usually occurs at i=1 */ 1312 DC_SYNC_INFO("GSL: reset occurred at wait count: %d\n", 1313 i); 1314 break; 1315 } 1316 1317 /* Wait for one frame. */ 1318 tg->funcs->wait_for_state(tg, CRTC_STATE_VACTIVE); 1319 tg->funcs->wait_for_state(tg, CRTC_STATE_VBLANK); 1320 } 1321 1322 if (false == rc) 1323 DC_ERROR("GSL: Timeout on reset trigger!\n"); 1324 1325 return rc; 1326 } 1327 1328 static void dcn10_enable_timing_synchronization( 1329 struct dc *dc, 1330 int group_index, 1331 int group_size, 1332 struct pipe_ctx *grouped_pipes[]) 1333 { 1334 struct dc_context *dc_ctx = dc->ctx; 1335 int i; 1336 1337 DC_SYNC_INFO("Setting up OTG reset trigger\n"); 1338 1339 for (i = 1; i < group_size; i++) 1340 grouped_pipes[i]->stream_res.tg->funcs->enable_reset_trigger( 1341 grouped_pipes[i]->stream_res.tg, 1342 grouped_pipes[0]->stream_res.tg->inst); 1343 1344 DC_SYNC_INFO("Waiting for trigger\n"); 1345 1346 /* Need to get only check 1 pipe for having reset as all the others are 1347 * synchronized. Look at last pipe programmed to reset. 1348 */ 1349 1350 wait_for_reset_trigger_to_occur(dc_ctx, grouped_pipes[1]->stream_res.tg); 1351 for (i = 1; i < group_size; i++) 1352 grouped_pipes[i]->stream_res.tg->funcs->disable_reset_trigger( 1353 grouped_pipes[i]->stream_res.tg); 1354 1355 DC_SYNC_INFO("Sync complete\n"); 1356 } 1357 1358 static void dcn10_enable_per_frame_crtc_position_reset( 1359 struct dc *dc, 1360 int group_size, 1361 struct pipe_ctx *grouped_pipes[]) 1362 { 1363 struct dc_context *dc_ctx = dc->ctx; 1364 int i; 1365 1366 DC_SYNC_INFO("Setting up\n"); 1367 for (i = 0; i < group_size; i++) 1368 if (grouped_pipes[i]->stream_res.tg->funcs->enable_crtc_reset) 1369 grouped_pipes[i]->stream_res.tg->funcs->enable_crtc_reset( 1370 grouped_pipes[i]->stream_res.tg, 1371 grouped_pipes[i]->stream->triggered_crtc_reset.event_source->status.primary_otg_inst, 1372 &grouped_pipes[i]->stream->triggered_crtc_reset); 1373 1374 DC_SYNC_INFO("Waiting for trigger\n"); 1375 1376 for (i = 0; i < group_size; i++) 1377 wait_for_reset_trigger_to_occur(dc_ctx, grouped_pipes[i]->stream_res.tg); 1378 1379 DC_SYNC_INFO("Multi-display sync is complete\n"); 1380 } 1381 1382 /*static void print_rq_dlg_ttu( 1383 struct dc *core_dc, 1384 struct pipe_ctx *pipe_ctx) 1385 { 1386 DC_LOG_BANDWIDTH_CALCS(core_dc->ctx->logger, 1387 "\n============== DML TTU Output parameters [%d] ==============\n" 1388 "qos_level_low_wm: %d, \n" 1389 "qos_level_high_wm: %d, \n" 1390 "min_ttu_vblank: %d, \n" 1391 "qos_level_flip: %d, \n" 1392 "refcyc_per_req_delivery_l: %d, \n" 1393 "qos_level_fixed_l: %d, \n" 1394 "qos_ramp_disable_l: %d, \n" 1395 "refcyc_per_req_delivery_pre_l: %d, \n" 1396 "refcyc_per_req_delivery_c: %d, \n" 1397 "qos_level_fixed_c: %d, \n" 1398 "qos_ramp_disable_c: %d, \n" 1399 "refcyc_per_req_delivery_pre_c: %d\n" 1400 "=============================================================\n", 1401 pipe_ctx->pipe_idx, 1402 pipe_ctx->ttu_regs.qos_level_low_wm, 1403 pipe_ctx->ttu_regs.qos_level_high_wm, 1404 pipe_ctx->ttu_regs.min_ttu_vblank, 1405 pipe_ctx->ttu_regs.qos_level_flip, 1406 pipe_ctx->ttu_regs.refcyc_per_req_delivery_l, 1407 pipe_ctx->ttu_regs.qos_level_fixed_l, 1408 pipe_ctx->ttu_regs.qos_ramp_disable_l, 1409 pipe_ctx->ttu_regs.refcyc_per_req_delivery_pre_l, 1410 pipe_ctx->ttu_regs.refcyc_per_req_delivery_c, 1411 pipe_ctx->ttu_regs.qos_level_fixed_c, 1412 pipe_ctx->ttu_regs.qos_ramp_disable_c, 1413 pipe_ctx->ttu_regs.refcyc_per_req_delivery_pre_c 1414 ); 1415 1416 DC_LOG_BANDWIDTH_CALCS(core_dc->ctx->logger, 1417 "\n============== DML DLG Output parameters [%d] ==============\n" 1418 "refcyc_h_blank_end: %d, \n" 1419 "dlg_vblank_end: %d, \n" 1420 "min_dst_y_next_start: %d, \n" 1421 "refcyc_per_htotal: %d, \n" 1422 "refcyc_x_after_scaler: %d, \n" 1423 "dst_y_after_scaler: %d, \n" 1424 "dst_y_prefetch: %d, \n" 1425 "dst_y_per_vm_vblank: %d, \n" 1426 "dst_y_per_row_vblank: %d, \n" 1427 "ref_freq_to_pix_freq: %d, \n" 1428 "vratio_prefetch: %d, \n" 1429 "refcyc_per_pte_group_vblank_l: %d, \n" 1430 "refcyc_per_meta_chunk_vblank_l: %d, \n" 1431 "dst_y_per_pte_row_nom_l: %d, \n" 1432 "refcyc_per_pte_group_nom_l: %d, \n", 1433 pipe_ctx->pipe_idx, 1434 pipe_ctx->dlg_regs.refcyc_h_blank_end, 1435 pipe_ctx->dlg_regs.dlg_vblank_end, 1436 pipe_ctx->dlg_regs.min_dst_y_next_start, 1437 pipe_ctx->dlg_regs.refcyc_per_htotal, 1438 pipe_ctx->dlg_regs.refcyc_x_after_scaler, 1439 pipe_ctx->dlg_regs.dst_y_after_scaler, 1440 pipe_ctx->dlg_regs.dst_y_prefetch, 1441 pipe_ctx->dlg_regs.dst_y_per_vm_vblank, 1442 pipe_ctx->dlg_regs.dst_y_per_row_vblank, 1443 pipe_ctx->dlg_regs.ref_freq_to_pix_freq, 1444 pipe_ctx->dlg_regs.vratio_prefetch, 1445 pipe_ctx->dlg_regs.refcyc_per_pte_group_vblank_l, 1446 pipe_ctx->dlg_regs.refcyc_per_meta_chunk_vblank_l, 1447 pipe_ctx->dlg_regs.dst_y_per_pte_row_nom_l, 1448 pipe_ctx->dlg_regs.refcyc_per_pte_group_nom_l 1449 ); 1450 1451 DC_LOG_BANDWIDTH_CALCS(core_dc->ctx->logger, 1452 "\ndst_y_per_meta_row_nom_l: %d, \n" 1453 "refcyc_per_meta_chunk_nom_l: %d, \n" 1454 "refcyc_per_line_delivery_pre_l: %d, \n" 1455 "refcyc_per_line_delivery_l: %d, \n" 1456 "vratio_prefetch_c: %d, \n" 1457 "refcyc_per_pte_group_vblank_c: %d, \n" 1458 "refcyc_per_meta_chunk_vblank_c: %d, \n" 1459 "dst_y_per_pte_row_nom_c: %d, \n" 1460 "refcyc_per_pte_group_nom_c: %d, \n" 1461 "dst_y_per_meta_row_nom_c: %d, \n" 1462 "refcyc_per_meta_chunk_nom_c: %d, \n" 1463 "refcyc_per_line_delivery_pre_c: %d, \n" 1464 "refcyc_per_line_delivery_c: %d \n" 1465 "========================================================\n", 1466 pipe_ctx->dlg_regs.dst_y_per_meta_row_nom_l, 1467 pipe_ctx->dlg_regs.refcyc_per_meta_chunk_nom_l, 1468 pipe_ctx->dlg_regs.refcyc_per_line_delivery_pre_l, 1469 pipe_ctx->dlg_regs.refcyc_per_line_delivery_l, 1470 pipe_ctx->dlg_regs.vratio_prefetch_c, 1471 pipe_ctx->dlg_regs.refcyc_per_pte_group_vblank_c, 1472 pipe_ctx->dlg_regs.refcyc_per_meta_chunk_vblank_c, 1473 pipe_ctx->dlg_regs.dst_y_per_pte_row_nom_c, 1474 pipe_ctx->dlg_regs.refcyc_per_pte_group_nom_c, 1475 pipe_ctx->dlg_regs.dst_y_per_meta_row_nom_c, 1476 pipe_ctx->dlg_regs.refcyc_per_meta_chunk_nom_c, 1477 pipe_ctx->dlg_regs.refcyc_per_line_delivery_pre_c, 1478 pipe_ctx->dlg_regs.refcyc_per_line_delivery_c 1479 ); 1480 1481 DC_LOG_BANDWIDTH_CALCS(core_dc->ctx->logger, 1482 "\n============== DML RQ Output parameters [%d] ==============\n" 1483 "chunk_size: %d \n" 1484 "min_chunk_size: %d \n" 1485 "meta_chunk_size: %d \n" 1486 "min_meta_chunk_size: %d \n" 1487 "dpte_group_size: %d \n" 1488 "mpte_group_size: %d \n" 1489 "swath_height: %d \n" 1490 "pte_row_height_linear: %d \n" 1491 "========================================================\n", 1492 pipe_ctx->pipe_idx, 1493 pipe_ctx->rq_regs.rq_regs_l.chunk_size, 1494 pipe_ctx->rq_regs.rq_regs_l.min_chunk_size, 1495 pipe_ctx->rq_regs.rq_regs_l.meta_chunk_size, 1496 pipe_ctx->rq_regs.rq_regs_l.min_meta_chunk_size, 1497 pipe_ctx->rq_regs.rq_regs_l.dpte_group_size, 1498 pipe_ctx->rq_regs.rq_regs_l.mpte_group_size, 1499 pipe_ctx->rq_regs.rq_regs_l.swath_height, 1500 pipe_ctx->rq_regs.rq_regs_l.pte_row_height_linear 1501 ); 1502 } 1503 */ 1504 1505 static void mmhub_read_vm_system_aperture_settings(struct dcn10_hubp *hubp1, 1506 struct vm_system_aperture_param *apt, 1507 struct dce_hwseq *hws) 1508 { 1509 PHYSICAL_ADDRESS_LOC physical_page_number; 1510 uint32_t logical_addr_low; 1511 uint32_t logical_addr_high; 1512 1513 REG_GET(MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB, 1514 PHYSICAL_PAGE_NUMBER_MSB, &physical_page_number.high_part); 1515 REG_GET(MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB, 1516 PHYSICAL_PAGE_NUMBER_LSB, &physical_page_number.low_part); 1517 1518 REG_GET(MC_VM_SYSTEM_APERTURE_LOW_ADDR, 1519 LOGICAL_ADDR, &logical_addr_low); 1520 1521 REG_GET(MC_VM_SYSTEM_APERTURE_HIGH_ADDR, 1522 LOGICAL_ADDR, &logical_addr_high); 1523 1524 apt->sys_default.quad_part = physical_page_number.quad_part << 12; 1525 apt->sys_low.quad_part = (int64_t)logical_addr_low << 18; 1526 apt->sys_high.quad_part = (int64_t)logical_addr_high << 18; 1527 } 1528 1529 /* Temporary read settings, future will get values from kmd directly */ 1530 static void mmhub_read_vm_context0_settings(struct dcn10_hubp *hubp1, 1531 struct vm_context0_param *vm0, 1532 struct dce_hwseq *hws) 1533 { 1534 PHYSICAL_ADDRESS_LOC fb_base; 1535 PHYSICAL_ADDRESS_LOC fb_offset; 1536 uint32_t fb_base_value; 1537 uint32_t fb_offset_value; 1538 1539 REG_GET(DCHUBBUB_SDPIF_FB_BASE, SDPIF_FB_BASE, &fb_base_value); 1540 REG_GET(DCHUBBUB_SDPIF_FB_OFFSET, SDPIF_FB_OFFSET, &fb_offset_value); 1541 1542 REG_GET(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32, 1543 PAGE_DIRECTORY_ENTRY_HI32, &vm0->pte_base.high_part); 1544 REG_GET(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LO32, 1545 PAGE_DIRECTORY_ENTRY_LO32, &vm0->pte_base.low_part); 1546 1547 REG_GET(VM_CONTEXT0_PAGE_TABLE_START_ADDR_HI32, 1548 LOGICAL_PAGE_NUMBER_HI4, &vm0->pte_start.high_part); 1549 REG_GET(VM_CONTEXT0_PAGE_TABLE_START_ADDR_LO32, 1550 LOGICAL_PAGE_NUMBER_LO32, &vm0->pte_start.low_part); 1551 1552 REG_GET(VM_CONTEXT0_PAGE_TABLE_END_ADDR_HI32, 1553 LOGICAL_PAGE_NUMBER_HI4, &vm0->pte_end.high_part); 1554 REG_GET(VM_CONTEXT0_PAGE_TABLE_END_ADDR_LO32, 1555 LOGICAL_PAGE_NUMBER_LO32, &vm0->pte_end.low_part); 1556 1557 REG_GET(VM_L2_PROTECTION_FAULT_DEFAULT_ADDR_HI32, 1558 PHYSICAL_PAGE_ADDR_HI4, &vm0->fault_default.high_part); 1559 REG_GET(VM_L2_PROTECTION_FAULT_DEFAULT_ADDR_LO32, 1560 PHYSICAL_PAGE_ADDR_LO32, &vm0->fault_default.low_part); 1561 1562 /* 1563 * The values in VM_CONTEXT0_PAGE_TABLE_BASE_ADDR is in UMA space. 1564 * Therefore we need to do 1565 * DCN_VM_CONTEXT0_PAGE_TABLE_BASE_ADDR = VM_CONTEXT0_PAGE_TABLE_BASE_ADDR 1566 * - DCHUBBUB_SDPIF_FB_OFFSET + DCHUBBUB_SDPIF_FB_BASE 1567 */ 1568 fb_base.quad_part = (uint64_t)fb_base_value << 24; 1569 fb_offset.quad_part = (uint64_t)fb_offset_value << 24; 1570 vm0->pte_base.quad_part += fb_base.quad_part; 1571 vm0->pte_base.quad_part -= fb_offset.quad_part; 1572 } 1573 1574 1575 static void dcn10_program_pte_vm(struct dce_hwseq *hws, struct hubp *hubp) 1576 { 1577 struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp); 1578 struct vm_system_aperture_param apt = { {{ 0 } } }; 1579 struct vm_context0_param vm0 = { { { 0 } } }; 1580 1581 mmhub_read_vm_system_aperture_settings(hubp1, &apt, hws); 1582 mmhub_read_vm_context0_settings(hubp1, &vm0, hws); 1583 1584 hubp->funcs->hubp_set_vm_system_aperture_settings(hubp, &apt); 1585 hubp->funcs->hubp_set_vm_context0_settings(hubp, &vm0); 1586 } 1587 1588 static void dcn10_enable_plane( 1589 struct dc *dc, 1590 struct pipe_ctx *pipe_ctx, 1591 struct dc_state *context) 1592 { 1593 struct dce_hwseq *hws = dc->hwseq; 1594 1595 if (dc->debug.sanity_checks) { 1596 dcn10_verify_allow_pstate_change_high(dc); 1597 } 1598 1599 undo_DEGVIDCN10_253_wa(dc); 1600 1601 power_on_plane(dc->hwseq, 1602 pipe_ctx->plane_res.hubp->inst); 1603 1604 /* enable DCFCLK current DCHUB */ 1605 pipe_ctx->plane_res.hubp->funcs->hubp_clk_cntl(pipe_ctx->plane_res.hubp, true); 1606 1607 /* make sure OPP_PIPE_CLOCK_EN = 1 */ 1608 pipe_ctx->stream_res.opp->funcs->opp_pipe_clock_control( 1609 pipe_ctx->stream_res.opp, 1610 true); 1611 1612 /* TODO: enable/disable in dm as per update type. 1613 if (plane_state) { 1614 DC_LOG_DC(dc->ctx->logger, 1615 "Pipe:%d 0x%x: addr hi:0x%x, " 1616 "addr low:0x%x, " 1617 "src: %d, %d, %d," 1618 " %d; dst: %d, %d, %d, %d;\n", 1619 pipe_ctx->pipe_idx, 1620 plane_state, 1621 plane_state->address.grph.addr.high_part, 1622 plane_state->address.grph.addr.low_part, 1623 plane_state->src_rect.x, 1624 plane_state->src_rect.y, 1625 plane_state->src_rect.width, 1626 plane_state->src_rect.height, 1627 plane_state->dst_rect.x, 1628 plane_state->dst_rect.y, 1629 plane_state->dst_rect.width, 1630 plane_state->dst_rect.height); 1631 1632 DC_LOG_DC(dc->ctx->logger, 1633 "Pipe %d: width, height, x, y format:%d\n" 1634 "viewport:%d, %d, %d, %d\n" 1635 "recout: %d, %d, %d, %d\n", 1636 pipe_ctx->pipe_idx, 1637 plane_state->format, 1638 pipe_ctx->plane_res.scl_data.viewport.width, 1639 pipe_ctx->plane_res.scl_data.viewport.height, 1640 pipe_ctx->plane_res.scl_data.viewport.x, 1641 pipe_ctx->plane_res.scl_data.viewport.y, 1642 pipe_ctx->plane_res.scl_data.recout.width, 1643 pipe_ctx->plane_res.scl_data.recout.height, 1644 pipe_ctx->plane_res.scl_data.recout.x, 1645 pipe_ctx->plane_res.scl_data.recout.y); 1646 print_rq_dlg_ttu(dc, pipe_ctx); 1647 } 1648 */ 1649 if (dc->config.gpu_vm_support) 1650 dcn10_program_pte_vm(hws, pipe_ctx->plane_res.hubp); 1651 1652 if (dc->debug.sanity_checks) { 1653 dcn10_verify_allow_pstate_change_high(dc); 1654 } 1655 } 1656 1657 static void program_gamut_remap(struct pipe_ctx *pipe_ctx) 1658 { 1659 int i = 0; 1660 struct dpp_grph_csc_adjustment adjust; 1661 memset(&adjust, 0, sizeof(adjust)); 1662 adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS; 1663 1664 1665 if (pipe_ctx->stream->gamut_remap_matrix.enable_remap == true) { 1666 adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW; 1667 for (i = 0; i < CSC_TEMPERATURE_MATRIX_SIZE; i++) 1668 adjust.temperature_matrix[i] = 1669 pipe_ctx->stream->gamut_remap_matrix.matrix[i]; 1670 } 1671 1672 pipe_ctx->plane_res.dpp->funcs->dpp_set_gamut_remap(pipe_ctx->plane_res.dpp, &adjust); 1673 } 1674 1675 1676 static void program_csc_matrix(struct pipe_ctx *pipe_ctx, 1677 enum dc_color_space colorspace, 1678 uint16_t *matrix) 1679 { 1680 if (pipe_ctx->stream->csc_color_matrix.enable_adjustment == true) { 1681 if (pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_adjustment != NULL) 1682 pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_adjustment(pipe_ctx->plane_res.dpp, matrix); 1683 } else { 1684 if (pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_default != NULL) 1685 pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_default(pipe_ctx->plane_res.dpp, colorspace); 1686 } 1687 } 1688 1689 static void dcn10_program_output_csc(struct dc *dc, 1690 struct pipe_ctx *pipe_ctx, 1691 enum dc_color_space colorspace, 1692 uint16_t *matrix, 1693 int opp_id) 1694 { 1695 if (pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_adjustment != NULL) 1696 program_csc_matrix(pipe_ctx, 1697 colorspace, 1698 matrix); 1699 } 1700 1701 static bool is_lower_pipe_tree_visible(struct pipe_ctx *pipe_ctx) 1702 { 1703 if (pipe_ctx->plane_state->visible) 1704 return true; 1705 if (pipe_ctx->bottom_pipe && is_lower_pipe_tree_visible(pipe_ctx->bottom_pipe)) 1706 return true; 1707 return false; 1708 } 1709 1710 static bool is_upper_pipe_tree_visible(struct pipe_ctx *pipe_ctx) 1711 { 1712 if (pipe_ctx->plane_state->visible) 1713 return true; 1714 if (pipe_ctx->top_pipe && is_upper_pipe_tree_visible(pipe_ctx->top_pipe)) 1715 return true; 1716 return false; 1717 } 1718 1719 static bool is_pipe_tree_visible(struct pipe_ctx *pipe_ctx) 1720 { 1721 if (pipe_ctx->plane_state->visible) 1722 return true; 1723 if (pipe_ctx->top_pipe && is_upper_pipe_tree_visible(pipe_ctx->top_pipe)) 1724 return true; 1725 if (pipe_ctx->bottom_pipe && is_lower_pipe_tree_visible(pipe_ctx->bottom_pipe)) 1726 return true; 1727 return false; 1728 } 1729 1730 bool is_rgb_cspace(enum dc_color_space output_color_space) 1731 { 1732 switch (output_color_space) { 1733 case COLOR_SPACE_SRGB: 1734 case COLOR_SPACE_SRGB_LIMITED: 1735 case COLOR_SPACE_2020_RGB_FULLRANGE: 1736 case COLOR_SPACE_2020_RGB_LIMITEDRANGE: 1737 case COLOR_SPACE_ADOBERGB: 1738 return true; 1739 case COLOR_SPACE_YCBCR601: 1740 case COLOR_SPACE_YCBCR709: 1741 case COLOR_SPACE_YCBCR601_LIMITED: 1742 case COLOR_SPACE_YCBCR709_LIMITED: 1743 case COLOR_SPACE_2020_YCBCR: 1744 return false; 1745 default: 1746 /* Add a case to switch */ 1747 BREAK_TO_DEBUGGER(); 1748 return false; 1749 } 1750 } 1751 1752 static void dcn10_get_surface_visual_confirm_color( 1753 const struct pipe_ctx *pipe_ctx, 1754 struct tg_color *color) 1755 { 1756 uint32_t color_value = MAX_TG_COLOR_VALUE; 1757 1758 switch (pipe_ctx->plane_res.scl_data.format) { 1759 case PIXEL_FORMAT_ARGB8888: 1760 /* set boarder color to red */ 1761 color->color_r_cr = color_value; 1762 break; 1763 1764 case PIXEL_FORMAT_ARGB2101010: 1765 /* set boarder color to blue */ 1766 color->color_b_cb = color_value; 1767 break; 1768 case PIXEL_FORMAT_420BPP8: 1769 /* set boarder color to green */ 1770 color->color_g_y = color_value; 1771 break; 1772 case PIXEL_FORMAT_420BPP10: 1773 /* set boarder color to yellow */ 1774 color->color_g_y = color_value; 1775 color->color_r_cr = color_value; 1776 break; 1777 case PIXEL_FORMAT_FP16: 1778 /* set boarder color to white */ 1779 color->color_r_cr = color_value; 1780 color->color_b_cb = color_value; 1781 color->color_g_y = color_value; 1782 break; 1783 default: 1784 break; 1785 } 1786 } 1787 1788 static void dcn10_get_hdr_visual_confirm_color( 1789 struct pipe_ctx *pipe_ctx, 1790 struct tg_color *color) 1791 { 1792 uint32_t color_value = MAX_TG_COLOR_VALUE; 1793 1794 // Determine the overscan color based on the top-most (desktop) plane's context 1795 struct pipe_ctx *top_pipe_ctx = pipe_ctx; 1796 1797 while (top_pipe_ctx->top_pipe != NULL) 1798 top_pipe_ctx = top_pipe_ctx->top_pipe; 1799 1800 switch (top_pipe_ctx->plane_res.scl_data.format) { 1801 case PIXEL_FORMAT_ARGB2101010: 1802 if (top_pipe_ctx->stream->out_transfer_func->tf == TRANSFER_FUNCTION_UNITY) { 1803 /* HDR10, ARGB2101010 - set boarder color to red */ 1804 color->color_r_cr = color_value; 1805 } 1806 break; 1807 case PIXEL_FORMAT_FP16: 1808 if (top_pipe_ctx->stream->out_transfer_func->tf == TRANSFER_FUNCTION_PQ) { 1809 /* HDR10, FP16 - set boarder color to blue */ 1810 color->color_b_cb = color_value; 1811 } else if (top_pipe_ctx->stream->out_transfer_func->tf == TRANSFER_FUNCTION_GAMMA22) { 1812 /* FreeSync 2 HDR - set boarder color to green */ 1813 color->color_g_y = color_value; 1814 } 1815 break; 1816 default: 1817 /* SDR - set boarder color to Gray */ 1818 color->color_r_cr = color_value/2; 1819 color->color_b_cb = color_value/2; 1820 color->color_g_y = color_value/2; 1821 break; 1822 } 1823 } 1824 1825 static uint16_t fixed_point_to_int_frac( 1826 struct fixed31_32 arg, 1827 uint8_t integer_bits, 1828 uint8_t fractional_bits) 1829 { 1830 int32_t numerator; 1831 int32_t divisor = 1 << fractional_bits; 1832 1833 uint16_t result; 1834 1835 uint16_t d = (uint16_t)dc_fixpt_floor( 1836 dc_fixpt_abs( 1837 arg)); 1838 1839 if (d <= (uint16_t)(1 << integer_bits) - (1 / (uint16_t)divisor)) 1840 numerator = (uint16_t)dc_fixpt_floor( 1841 dc_fixpt_mul_int( 1842 arg, 1843 divisor)); 1844 else { 1845 numerator = dc_fixpt_floor( 1846 dc_fixpt_sub( 1847 dc_fixpt_from_int( 1848 1LL << integer_bits), 1849 dc_fixpt_recip( 1850 dc_fixpt_from_int( 1851 divisor)))); 1852 } 1853 1854 if (numerator >= 0) 1855 result = (uint16_t)numerator; 1856 else 1857 result = (uint16_t)( 1858 (1 << (integer_bits + fractional_bits + 1)) + numerator); 1859 1860 if ((result != 0) && dc_fixpt_lt( 1861 arg, dc_fixpt_zero)) 1862 result |= 1 << (integer_bits + fractional_bits); 1863 1864 return result; 1865 } 1866 1867 static 1868 void build_prescale_params(struct dc_bias_and_scale *bias_and_scale, 1869 const struct dc_plane_state *plane_state) 1870 { 1871 if (plane_state->format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN 1872 && plane_state->format != SURFACE_PIXEL_FORMAT_INVALID 1873 && plane_state->input_csc_color_matrix.enable_adjustment 1874 && plane_state->coeff_reduction_factor.value != 0) { 1875 bias_and_scale->scale_blue = fixed_point_to_int_frac( 1876 dc_fixpt_mul(plane_state->coeff_reduction_factor, 1877 dc_fixpt_from_fraction(256, 255)), 1878 2, 1879 13); 1880 bias_and_scale->scale_red = bias_and_scale->scale_blue; 1881 bias_and_scale->scale_green = bias_and_scale->scale_blue; 1882 } else { 1883 bias_and_scale->scale_blue = 0x2000; 1884 bias_and_scale->scale_red = 0x2000; 1885 bias_and_scale->scale_green = 0x2000; 1886 } 1887 } 1888 1889 static void update_dpp(struct dpp *dpp, struct dc_plane_state *plane_state) 1890 { 1891 struct dc_bias_and_scale bns_params = {0}; 1892 1893 // program the input csc 1894 dpp->funcs->dpp_setup(dpp, 1895 plane_state->format, 1896 EXPANSION_MODE_ZERO, 1897 plane_state->input_csc_color_matrix, 1898 plane_state->color_space); 1899 1900 //set scale and bias registers 1901 build_prescale_params(&bns_params, plane_state); 1902 if (dpp->funcs->dpp_program_bias_and_scale) 1903 dpp->funcs->dpp_program_bias_and_scale(dpp, &bns_params); 1904 } 1905 1906 static void dcn10_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx) 1907 { 1908 struct hubp *hubp = pipe_ctx->plane_res.hubp; 1909 struct mpcc_blnd_cfg blnd_cfg = {0}; 1910 bool per_pixel_alpha = pipe_ctx->plane_state->per_pixel_alpha && pipe_ctx->bottom_pipe; 1911 int mpcc_id; 1912 struct mpcc *new_mpcc; 1913 struct mpc *mpc = dc->res_pool->mpc; 1914 struct mpc_tree *mpc_tree_params = &(pipe_ctx->stream_res.opp->mpc_tree_params); 1915 1916 1917 1918 /* TODO: proper fix once fpga works */ 1919 1920 if (dc->debug.visual_confirm == VISUAL_CONFIRM_HDR) { 1921 dcn10_get_hdr_visual_confirm_color( 1922 pipe_ctx, &blnd_cfg.black_color); 1923 } else if (dc->debug.visual_confirm == VISUAL_CONFIRM_SURFACE) { 1924 dcn10_get_surface_visual_confirm_color( 1925 pipe_ctx, &blnd_cfg.black_color); 1926 } else { 1927 color_space_to_black_color( 1928 dc, pipe_ctx->stream->output_color_space, 1929 &blnd_cfg.black_color); 1930 } 1931 1932 if (per_pixel_alpha) 1933 blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA; 1934 else 1935 blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_GLOBAL_ALPHA; 1936 1937 blnd_cfg.overlap_only = false; 1938 blnd_cfg.global_alpha = 0xff; 1939 blnd_cfg.global_gain = 0xff; 1940 1941 /* DCN1.0 has output CM before MPC which seems to screw with 1942 * pre-multiplied alpha. 1943 */ 1944 blnd_cfg.pre_multiplied_alpha = is_rgb_cspace( 1945 pipe_ctx->stream->output_color_space) 1946 && per_pixel_alpha; 1947 1948 1949 /* 1950 * TODO: remove hack 1951 * Note: currently there is a bug in init_hw such that 1952 * on resume from hibernate, BIOS sets up MPCC0, and 1953 * we do mpcc_remove but the mpcc cannot go to idle 1954 * after remove. This cause us to pick mpcc1 here, 1955 * which causes a pstate hang for yet unknown reason. 1956 */ 1957 mpcc_id = hubp->inst; 1958 1959 /* If there is no full update, don't need to touch MPC tree*/ 1960 if (!pipe_ctx->plane_state->update_flags.bits.full_update) { 1961 mpc->funcs->update_blending(mpc, &blnd_cfg, mpcc_id); 1962 return; 1963 } 1964 1965 /* check if this MPCC is already being used */ 1966 new_mpcc = mpc->funcs->get_mpcc_for_dpp(mpc_tree_params, mpcc_id); 1967 /* remove MPCC if being used */ 1968 if (new_mpcc != NULL) 1969 mpc->funcs->remove_mpcc(mpc, mpc_tree_params, new_mpcc); 1970 else 1971 if (dc->debug.sanity_checks) 1972 mpc->funcs->assert_mpcc_idle_before_connect( 1973 dc->res_pool->mpc, mpcc_id); 1974 1975 /* Call MPC to insert new plane */ 1976 new_mpcc = mpc->funcs->insert_plane(dc->res_pool->mpc, 1977 mpc_tree_params, 1978 &blnd_cfg, 1979 NULL, 1980 NULL, 1981 hubp->inst, 1982 mpcc_id); 1983 1984 ASSERT(new_mpcc != NULL); 1985 1986 hubp->opp_id = pipe_ctx->stream_res.opp->inst; 1987 hubp->mpcc_id = mpcc_id; 1988 } 1989 1990 static void update_scaler(struct pipe_ctx *pipe_ctx) 1991 { 1992 bool per_pixel_alpha = 1993 pipe_ctx->plane_state->per_pixel_alpha && pipe_ctx->bottom_pipe; 1994 1995 /* TODO: proper fix once fpga works */ 1996 1997 pipe_ctx->plane_res.scl_data.lb_params.alpha_en = per_pixel_alpha; 1998 pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_30BPP; 1999 /* scaler configuration */ 2000 pipe_ctx->plane_res.dpp->funcs->dpp_set_scaler( 2001 pipe_ctx->plane_res.dpp, &pipe_ctx->plane_res.scl_data); 2002 } 2003 2004 static void update_dchubp_dpp( 2005 struct dc *dc, 2006 struct pipe_ctx *pipe_ctx, 2007 struct dc_state *context) 2008 { 2009 struct hubp *hubp = pipe_ctx->plane_res.hubp; 2010 struct dpp *dpp = pipe_ctx->plane_res.dpp; 2011 struct dc_plane_state *plane_state = pipe_ctx->plane_state; 2012 union plane_size size = plane_state->plane_size; 2013 2014 /* depends on DML calculation, DPP clock value may change dynamically */ 2015 /* If request max dpp clk is lower than current dispclk, no need to 2016 * divided by 2 2017 */ 2018 if (plane_state->update_flags.bits.full_update) { 2019 bool should_divided_by_2 = context->bw.dcn.clk.dppclk_khz <= 2020 dc->res_pool->dccg->clks.dispclk_khz / 2; 2021 2022 dpp->funcs->dpp_dppclk_control( 2023 dpp, 2024 should_divided_by_2, 2025 true); 2026 2027 dc->res_pool->dccg->clks.dppclk_khz = should_divided_by_2 ? 2028 dc->res_pool->dccg->clks.dispclk_khz / 2 : 2029 dc->res_pool->dccg->clks.dispclk_khz; 2030 } 2031 2032 /* TODO: Need input parameter to tell current DCHUB pipe tie to which OTG 2033 * VTG is within DCHUBBUB which is commond block share by each pipe HUBP. 2034 * VTG is 1:1 mapping with OTG. Each pipe HUBP will select which VTG 2035 */ 2036 if (plane_state->update_flags.bits.full_update) { 2037 hubp->funcs->hubp_vtg_sel(hubp, pipe_ctx->stream_res.tg->inst); 2038 2039 hubp->funcs->hubp_setup( 2040 hubp, 2041 &pipe_ctx->dlg_regs, 2042 &pipe_ctx->ttu_regs, 2043 &pipe_ctx->rq_regs, 2044 &pipe_ctx->pipe_dlg_param); 2045 } 2046 2047 size.grph.surface_size = pipe_ctx->plane_res.scl_data.viewport; 2048 2049 if (plane_state->update_flags.bits.full_update || 2050 plane_state->update_flags.bits.bpp_change) 2051 update_dpp(dpp, plane_state); 2052 2053 if (plane_state->update_flags.bits.full_update || 2054 plane_state->update_flags.bits.per_pixel_alpha_change) 2055 dc->hwss.update_mpcc(dc, pipe_ctx); 2056 2057 if (plane_state->update_flags.bits.full_update || 2058 plane_state->update_flags.bits.per_pixel_alpha_change || 2059 plane_state->update_flags.bits.scaling_change || 2060 plane_state->update_flags.bits.position_change) { 2061 update_scaler(pipe_ctx); 2062 } 2063 2064 if (plane_state->update_flags.bits.full_update || 2065 plane_state->update_flags.bits.scaling_change || 2066 plane_state->update_flags.bits.position_change) { 2067 hubp->funcs->mem_program_viewport( 2068 hubp, 2069 &pipe_ctx->plane_res.scl_data.viewport, 2070 &pipe_ctx->plane_res.scl_data.viewport_c); 2071 } 2072 2073 if (pipe_ctx->stream->cursor_attributes.address.quad_part != 0) { 2074 dc->hwss.set_cursor_position(pipe_ctx); 2075 dc->hwss.set_cursor_attribute(pipe_ctx); 2076 } 2077 2078 if (plane_state->update_flags.bits.full_update) { 2079 /*gamut remap*/ 2080 program_gamut_remap(pipe_ctx); 2081 2082 dc->hwss.program_output_csc(dc, 2083 pipe_ctx, 2084 pipe_ctx->stream->output_color_space, 2085 pipe_ctx->stream->csc_color_matrix.matrix, 2086 hubp->opp_id); 2087 } 2088 2089 if (plane_state->update_flags.bits.full_update || 2090 plane_state->update_flags.bits.pixel_format_change || 2091 plane_state->update_flags.bits.horizontal_mirror_change || 2092 plane_state->update_flags.bits.rotation_change || 2093 plane_state->update_flags.bits.swizzle_change || 2094 plane_state->update_flags.bits.dcc_change || 2095 plane_state->update_flags.bits.bpp_change || 2096 plane_state->update_flags.bits.scaling_change) { 2097 hubp->funcs->hubp_program_surface_config( 2098 hubp, 2099 plane_state->format, 2100 &plane_state->tiling_info, 2101 &size, 2102 plane_state->rotation, 2103 &plane_state->dcc, 2104 plane_state->horizontal_mirror); 2105 } 2106 2107 hubp->power_gated = false; 2108 2109 dc->hwss.update_plane_addr(dc, pipe_ctx); 2110 2111 if (is_pipe_tree_visible(pipe_ctx)) 2112 hubp->funcs->set_blank(hubp, false); 2113 } 2114 2115 static void dcn10_blank_pixel_data( 2116 struct dc *dc, 2117 struct pipe_ctx *pipe_ctx, 2118 bool blank) 2119 { 2120 enum dc_color_space color_space; 2121 struct tg_color black_color = {0}; 2122 struct stream_resource *stream_res = &pipe_ctx->stream_res; 2123 struct dc_stream_state *stream = pipe_ctx->stream; 2124 2125 /* program otg blank color */ 2126 color_space = stream->output_color_space; 2127 color_space_to_black_color(dc, color_space, &black_color); 2128 2129 /* 2130 * The way 420 is packed, 2 channels carry Y component, 1 channel 2131 * alternate between Cb and Cr, so both channels need the pixel 2132 * value for Y 2133 */ 2134 if (stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR420) 2135 black_color.color_r_cr = black_color.color_g_y; 2136 2137 2138 if (stream_res->tg->funcs->set_blank_color) 2139 stream_res->tg->funcs->set_blank_color( 2140 stream_res->tg, 2141 &black_color); 2142 2143 if (!blank) { 2144 if (stream_res->tg->funcs->set_blank) 2145 stream_res->tg->funcs->set_blank(stream_res->tg, blank); 2146 if (stream_res->abm) 2147 stream_res->abm->funcs->set_abm_level(stream_res->abm, stream->abm_level); 2148 } else if (blank) { 2149 if (stream_res->abm) 2150 stream_res->abm->funcs->set_abm_immediate_disable(stream_res->abm); 2151 if (stream_res->tg->funcs->set_blank) 2152 stream_res->tg->funcs->set_blank(stream_res->tg, blank); 2153 } 2154 } 2155 2156 static void set_hdr_multiplier(struct pipe_ctx *pipe_ctx) 2157 { 2158 struct fixed31_32 multiplier = dc_fixpt_from_fraction( 2159 pipe_ctx->plane_state->sdr_white_level, 80); 2160 uint32_t hw_mult = 0x1f000; // 1.0 default multiplier 2161 struct custom_float_format fmt; 2162 2163 fmt.exponenta_bits = 6; 2164 fmt.mantissa_bits = 12; 2165 fmt.sign = true; 2166 2167 if (pipe_ctx->plane_state->sdr_white_level > 80) 2168 convert_to_custom_float_format(multiplier, &fmt, &hw_mult); 2169 2170 pipe_ctx->plane_res.dpp->funcs->dpp_set_hdr_multiplier( 2171 pipe_ctx->plane_res.dpp, hw_mult); 2172 } 2173 2174 void dcn10_program_pipe( 2175 struct dc *dc, 2176 struct pipe_ctx *pipe_ctx, 2177 struct dc_state *context) 2178 { 2179 if (pipe_ctx->plane_state->update_flags.bits.full_update) 2180 dcn10_enable_plane(dc, pipe_ctx, context); 2181 2182 update_dchubp_dpp(dc, pipe_ctx, context); 2183 2184 set_hdr_multiplier(pipe_ctx); 2185 2186 if (pipe_ctx->plane_state->update_flags.bits.full_update || 2187 pipe_ctx->plane_state->update_flags.bits.in_transfer_func_change || 2188 pipe_ctx->plane_state->update_flags.bits.gamma_change) 2189 dc->hwss.set_input_transfer_func(pipe_ctx, pipe_ctx->plane_state); 2190 2191 /* dcn10_translate_regamma_to_hw_format takes 750us to finish 2192 * only do gamma programming for full update. 2193 * TODO: This can be further optimized/cleaned up 2194 * Always call this for now since it does memcmp inside before 2195 * doing heavy calculation and programming 2196 */ 2197 if (pipe_ctx->plane_state->update_flags.bits.full_update) 2198 dc->hwss.set_output_transfer_func(pipe_ctx, pipe_ctx->stream); 2199 } 2200 2201 static void program_all_pipe_in_tree( 2202 struct dc *dc, 2203 struct pipe_ctx *pipe_ctx, 2204 struct dc_state *context) 2205 { 2206 if (pipe_ctx->top_pipe == NULL) { 2207 bool blank = !is_pipe_tree_visible(pipe_ctx); 2208 2209 pipe_ctx->stream_res.tg->dlg_otg_param.vready_offset = pipe_ctx->pipe_dlg_param.vready_offset; 2210 pipe_ctx->stream_res.tg->dlg_otg_param.vstartup_start = pipe_ctx->pipe_dlg_param.vstartup_start; 2211 pipe_ctx->stream_res.tg->dlg_otg_param.vupdate_offset = pipe_ctx->pipe_dlg_param.vupdate_offset; 2212 pipe_ctx->stream_res.tg->dlg_otg_param.vupdate_width = pipe_ctx->pipe_dlg_param.vupdate_width; 2213 pipe_ctx->stream_res.tg->dlg_otg_param.signal = pipe_ctx->stream->signal; 2214 2215 pipe_ctx->stream_res.tg->funcs->program_global_sync( 2216 pipe_ctx->stream_res.tg); 2217 2218 dc->hwss.blank_pixel_data(dc, pipe_ctx, blank); 2219 2220 } 2221 2222 if (pipe_ctx->plane_state != NULL) { 2223 dcn10_program_pipe(dc, pipe_ctx, context); 2224 } 2225 2226 if (pipe_ctx->bottom_pipe != NULL && pipe_ctx->bottom_pipe != pipe_ctx) { 2227 program_all_pipe_in_tree(dc, pipe_ctx->bottom_pipe, context); 2228 } 2229 } 2230 2231 static void dcn10_pplib_apply_display_requirements( 2232 struct dc *dc, 2233 struct dc_state *context) 2234 { 2235 struct dm_pp_display_configuration *pp_display_cfg = &context->pp_display_cfg; 2236 2237 pp_display_cfg->min_engine_clock_khz = dc->res_pool->dccg->clks.dcfclk_khz; 2238 pp_display_cfg->min_memory_clock_khz = dc->res_pool->dccg->clks.fclk_khz; 2239 pp_display_cfg->min_engine_clock_deep_sleep_khz = dc->res_pool->dccg->clks.dcfclk_deep_sleep_khz; 2240 pp_display_cfg->min_dcfc_deep_sleep_clock_khz = dc->res_pool->dccg->clks.dcfclk_deep_sleep_khz; 2241 pp_display_cfg->min_dcfclock_khz = dc->res_pool->dccg->clks.dcfclk_khz; 2242 pp_display_cfg->disp_clk_khz = dc->res_pool->dccg->clks.dispclk_khz; 2243 dce110_fill_display_configs(context, pp_display_cfg); 2244 2245 if (memcmp(&dc->prev_display_config, pp_display_cfg, sizeof( 2246 struct dm_pp_display_configuration)) != 0) 2247 dm_pp_apply_display_requirements(dc->ctx, pp_display_cfg); 2248 2249 dc->prev_display_config = *pp_display_cfg; 2250 } 2251 2252 static void optimize_shared_resources(struct dc *dc) 2253 { 2254 if (dc->current_state->stream_count == 0) { 2255 /* S0i2 message */ 2256 dcn10_pplib_apply_display_requirements(dc, dc->current_state); 2257 } 2258 2259 if (dc->debug.pplib_wm_report_mode == WM_REPORT_OVERRIDE) 2260 dcn_bw_notify_pplib_of_wm_ranges(dc); 2261 } 2262 2263 static void ready_shared_resources(struct dc *dc, struct dc_state *context) 2264 { 2265 /* S0i2 message */ 2266 if (dc->current_state->stream_count == 0 && 2267 context->stream_count != 0) 2268 dcn10_pplib_apply_display_requirements(dc, context); 2269 } 2270 2271 static struct pipe_ctx *find_top_pipe_for_stream( 2272 struct dc *dc, 2273 struct dc_state *context, 2274 const struct dc_stream_state *stream) 2275 { 2276 int i; 2277 2278 for (i = 0; i < dc->res_pool->pipe_count; i++) { 2279 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; 2280 struct pipe_ctx *old_pipe_ctx = 2281 &dc->current_state->res_ctx.pipe_ctx[i]; 2282 2283 if (!pipe_ctx->plane_state && !old_pipe_ctx->plane_state) 2284 continue; 2285 2286 if (pipe_ctx->stream != stream) 2287 continue; 2288 2289 if (!pipe_ctx->top_pipe) 2290 return pipe_ctx; 2291 } 2292 return NULL; 2293 } 2294 2295 static void dcn10_apply_ctx_for_surface( 2296 struct dc *dc, 2297 const struct dc_stream_state *stream, 2298 int num_planes, 2299 struct dc_state *context) 2300 { 2301 int i; 2302 struct timing_generator *tg; 2303 bool removed_pipe[4] = { false }; 2304 struct pipe_ctx *top_pipe_to_program = 2305 find_top_pipe_for_stream(dc, context, stream); 2306 DC_LOGGER_INIT(dc->ctx->logger); 2307 2308 if (!top_pipe_to_program) 2309 return; 2310 2311 tg = top_pipe_to_program->stream_res.tg; 2312 2313 dcn10_pipe_control_lock(dc, top_pipe_to_program, true); 2314 2315 if (num_planes == 0) { 2316 /* OTG blank before remove all front end */ 2317 dc->hwss.blank_pixel_data(dc, top_pipe_to_program, true); 2318 } 2319 2320 /* Disconnect unused mpcc */ 2321 for (i = 0; i < dc->res_pool->pipe_count; i++) { 2322 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; 2323 struct pipe_ctx *old_pipe_ctx = 2324 &dc->current_state->res_ctx.pipe_ctx[i]; 2325 /* 2326 * Powergate reused pipes that are not powergated 2327 * fairly hacky right now, using opp_id as indicator 2328 * TODO: After move dc_post to dc_update, this will 2329 * be removed. 2330 */ 2331 if (pipe_ctx->plane_state && !old_pipe_ctx->plane_state) { 2332 if (old_pipe_ctx->stream_res.tg == tg && 2333 old_pipe_ctx->plane_res.hubp && 2334 old_pipe_ctx->plane_res.hubp->opp_id != 0xf) { 2335 dcn10_disable_plane(dc, old_pipe_ctx); 2336 /* 2337 * power down fe will unlock when calling reset, need 2338 * to lock it back here. Messy, need rework. 2339 */ 2340 pipe_ctx->stream_res.tg->funcs->lock(pipe_ctx->stream_res.tg); 2341 } 2342 } 2343 2344 if ((!pipe_ctx->plane_state || 2345 pipe_ctx->stream_res.tg != old_pipe_ctx->stream_res.tg) && 2346 old_pipe_ctx->plane_state && 2347 old_pipe_ctx->stream_res.tg == tg) { 2348 2349 dc->hwss.plane_atomic_disconnect(dc, old_pipe_ctx); 2350 removed_pipe[i] = true; 2351 2352 DC_LOG_DC("Reset mpcc for pipe %d\n", 2353 old_pipe_ctx->pipe_idx); 2354 } 2355 } 2356 2357 if (num_planes > 0) 2358 program_all_pipe_in_tree(dc, top_pipe_to_program, context); 2359 2360 dcn10_pipe_control_lock(dc, top_pipe_to_program, false); 2361 2362 if (num_planes == 0) 2363 false_optc_underflow_wa(dc, stream, tg); 2364 2365 for (i = 0; i < dc->res_pool->pipe_count; i++) 2366 if (removed_pipe[i]) 2367 dcn10_disable_plane(dc, &dc->current_state->res_ctx.pipe_ctx[i]); 2368 2369 if (dc->hwseq->wa.DEGVIDCN10_254) 2370 hubbub1_wm_change_req_wa(dc->res_pool->hubbub); 2371 } 2372 2373 static void dcn10_set_bandwidth( 2374 struct dc *dc, 2375 struct dc_state *context, 2376 bool safe_to_lower) 2377 { 2378 if (dc->debug.sanity_checks) 2379 dcn10_verify_allow_pstate_change_high(dc); 2380 2381 if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) { 2382 if (context->stream_count == 0) 2383 context->bw.dcn.clk.phyclk_khz = 0; 2384 2385 dc->res_pool->dccg->funcs->update_clocks( 2386 dc->res_pool->dccg, 2387 &context->bw.dcn.clk, 2388 safe_to_lower); 2389 2390 dcn10_pplib_apply_display_requirements(dc, context); 2391 } 2392 2393 hubbub1_program_watermarks(dc->res_pool->hubbub, 2394 &context->bw.dcn.watermarks, 2395 dc->res_pool->ref_clock_inKhz / 1000, 2396 true); 2397 2398 if (dc->debug.sanity_checks) 2399 dcn10_verify_allow_pstate_change_high(dc); 2400 } 2401 2402 static void set_drr(struct pipe_ctx **pipe_ctx, 2403 int num_pipes, int vmin, int vmax) 2404 { 2405 int i = 0; 2406 struct drr_params params = {0}; 2407 2408 params.vertical_total_max = vmax; 2409 params.vertical_total_min = vmin; 2410 2411 /* TODO: If multiple pipes are to be supported, you need 2412 * some GSL stuff 2413 */ 2414 for (i = 0; i < num_pipes; i++) { 2415 pipe_ctx[i]->stream_res.tg->funcs->set_drr(pipe_ctx[i]->stream_res.tg, ¶ms); 2416 } 2417 } 2418 2419 static void get_position(struct pipe_ctx **pipe_ctx, 2420 int num_pipes, 2421 struct crtc_position *position) 2422 { 2423 int i = 0; 2424 2425 /* TODO: handle pipes > 1 2426 */ 2427 for (i = 0; i < num_pipes; i++) 2428 pipe_ctx[i]->stream_res.tg->funcs->get_position(pipe_ctx[i]->stream_res.tg, position); 2429 } 2430 2431 static void set_static_screen_control(struct pipe_ctx **pipe_ctx, 2432 int num_pipes, const struct dc_static_screen_events *events) 2433 { 2434 unsigned int i; 2435 unsigned int value = 0; 2436 2437 if (events->surface_update) 2438 value |= 0x80; 2439 if (events->cursor_update) 2440 value |= 0x2; 2441 if (events->force_trigger) 2442 value |= 0x1; 2443 2444 for (i = 0; i < num_pipes; i++) 2445 pipe_ctx[i]->stream_res.tg->funcs-> 2446 set_static_screen_control(pipe_ctx[i]->stream_res.tg, value); 2447 } 2448 2449 static void dcn10_config_stereo_parameters( 2450 struct dc_stream_state *stream, struct crtc_stereo_flags *flags) 2451 { 2452 enum view_3d_format view_format = stream->view_format; 2453 enum dc_timing_3d_format timing_3d_format =\ 2454 stream->timing.timing_3d_format; 2455 bool non_stereo_timing = false; 2456 2457 if (timing_3d_format == TIMING_3D_FORMAT_NONE || 2458 timing_3d_format == TIMING_3D_FORMAT_SIDE_BY_SIDE || 2459 timing_3d_format == TIMING_3D_FORMAT_TOP_AND_BOTTOM) 2460 non_stereo_timing = true; 2461 2462 if (non_stereo_timing == false && 2463 view_format == VIEW_3D_FORMAT_FRAME_SEQUENTIAL) { 2464 2465 flags->PROGRAM_STEREO = 1; 2466 flags->PROGRAM_POLARITY = 1; 2467 if (timing_3d_format == TIMING_3D_FORMAT_INBAND_FA || 2468 timing_3d_format == TIMING_3D_FORMAT_DP_HDMI_INBAND_FA || 2469 timing_3d_format == TIMING_3D_FORMAT_SIDEBAND_FA) { 2470 enum display_dongle_type dongle = \ 2471 stream->sink->link->ddc->dongle_type; 2472 if (dongle == DISPLAY_DONGLE_DP_VGA_CONVERTER || 2473 dongle == DISPLAY_DONGLE_DP_DVI_CONVERTER || 2474 dongle == DISPLAY_DONGLE_DP_HDMI_CONVERTER) 2475 flags->DISABLE_STEREO_DP_SYNC = 1; 2476 } 2477 flags->RIGHT_EYE_POLARITY =\ 2478 stream->timing.flags.RIGHT_EYE_3D_POLARITY; 2479 if (timing_3d_format == TIMING_3D_FORMAT_HW_FRAME_PACKING) 2480 flags->FRAME_PACKED = 1; 2481 } 2482 2483 return; 2484 } 2485 2486 static void dcn10_setup_stereo(struct pipe_ctx *pipe_ctx, struct dc *dc) 2487 { 2488 struct crtc_stereo_flags flags = { 0 }; 2489 struct dc_stream_state *stream = pipe_ctx->stream; 2490 2491 dcn10_config_stereo_parameters(stream, &flags); 2492 2493 pipe_ctx->stream_res.opp->funcs->opp_program_stereo( 2494 pipe_ctx->stream_res.opp, 2495 flags.PROGRAM_STEREO == 1 ? true:false, 2496 &stream->timing); 2497 2498 pipe_ctx->stream_res.tg->funcs->program_stereo( 2499 pipe_ctx->stream_res.tg, 2500 &stream->timing, 2501 &flags); 2502 2503 return; 2504 } 2505 2506 static struct hubp *get_hubp_by_inst(struct resource_pool *res_pool, int mpcc_inst) 2507 { 2508 int i; 2509 2510 for (i = 0; i < res_pool->pipe_count; i++) { 2511 if (res_pool->hubps[i]->inst == mpcc_inst) 2512 return res_pool->hubps[i]; 2513 } 2514 ASSERT(false); 2515 return NULL; 2516 } 2517 2518 static void dcn10_wait_for_mpcc_disconnect( 2519 struct dc *dc, 2520 struct resource_pool *res_pool, 2521 struct pipe_ctx *pipe_ctx) 2522 { 2523 int mpcc_inst; 2524 2525 if (dc->debug.sanity_checks) { 2526 dcn10_verify_allow_pstate_change_high(dc); 2527 } 2528 2529 if (!pipe_ctx->stream_res.opp) 2530 return; 2531 2532 for (mpcc_inst = 0; mpcc_inst < MAX_PIPES; mpcc_inst++) { 2533 if (pipe_ctx->stream_res.opp->mpcc_disconnect_pending[mpcc_inst]) { 2534 struct hubp *hubp = get_hubp_by_inst(res_pool, mpcc_inst); 2535 2536 res_pool->mpc->funcs->wait_for_idle(res_pool->mpc, mpcc_inst); 2537 pipe_ctx->stream_res.opp->mpcc_disconnect_pending[mpcc_inst] = false; 2538 hubp->funcs->set_blank(hubp, true); 2539 /*DC_LOG_ERROR(dc->ctx->logger, 2540 "[debug_mpo: wait_for_mpcc finished waiting on mpcc %d]\n", 2541 i);*/ 2542 } 2543 } 2544 2545 if (dc->debug.sanity_checks) { 2546 dcn10_verify_allow_pstate_change_high(dc); 2547 } 2548 2549 } 2550 2551 static bool dcn10_dummy_display_power_gating( 2552 struct dc *dc, 2553 uint8_t controller_id, 2554 struct dc_bios *dcb, 2555 enum pipe_gating_control power_gating) 2556 { 2557 return true; 2558 } 2559 2560 static void dcn10_update_pending_status(struct pipe_ctx *pipe_ctx) 2561 { 2562 struct dc_plane_state *plane_state = pipe_ctx->plane_state; 2563 struct timing_generator *tg = pipe_ctx->stream_res.tg; 2564 bool flip_pending; 2565 2566 if (plane_state == NULL) 2567 return; 2568 2569 flip_pending = pipe_ctx->plane_res.hubp->funcs->hubp_is_flip_pending( 2570 pipe_ctx->plane_res.hubp); 2571 2572 plane_state->status.is_flip_pending = flip_pending; 2573 2574 if (!flip_pending) 2575 plane_state->status.current_address = plane_state->status.requested_address; 2576 2577 if (plane_state->status.current_address.type == PLN_ADDR_TYPE_GRPH_STEREO && 2578 tg->funcs->is_stereo_left_eye) { 2579 plane_state->status.is_right_eye = 2580 !tg->funcs->is_stereo_left_eye(pipe_ctx->stream_res.tg); 2581 } 2582 } 2583 2584 static void dcn10_update_dchub(struct dce_hwseq *hws, struct dchub_init_data *dh_data) 2585 { 2586 if (hws->ctx->dc->res_pool->hubbub != NULL) { 2587 struct hubp *hubp = hws->ctx->dc->res_pool->hubps[0]; 2588 2589 if (hubp->funcs->hubp_update_dchub) 2590 hubp->funcs->hubp_update_dchub(hubp, dh_data); 2591 else 2592 hubbub1_update_dchub(hws->ctx->dc->res_pool->hubbub, dh_data); 2593 } 2594 } 2595 2596 static void dcn10_set_cursor_position(struct pipe_ctx *pipe_ctx) 2597 { 2598 struct dc_cursor_position pos_cpy = pipe_ctx->stream->cursor_position; 2599 struct hubp *hubp = pipe_ctx->plane_res.hubp; 2600 struct dpp *dpp = pipe_ctx->plane_res.dpp; 2601 struct dc_cursor_mi_param param = { 2602 .pixel_clk_khz = pipe_ctx->stream->timing.pix_clk_khz, 2603 .ref_clk_khz = pipe_ctx->stream->ctx->dc->res_pool->ref_clock_inKhz, 2604 .viewport = pipe_ctx->plane_res.scl_data.viewport, 2605 .h_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.horz, 2606 .v_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.vert, 2607 .rotation = pipe_ctx->plane_state->rotation, 2608 .mirror = pipe_ctx->plane_state->horizontal_mirror 2609 }; 2610 2611 if (pipe_ctx->plane_state->address.type 2612 == PLN_ADDR_TYPE_VIDEO_PROGRESSIVE) 2613 pos_cpy.enable = false; 2614 2615 if (pipe_ctx->top_pipe && pipe_ctx->plane_state != pipe_ctx->top_pipe->plane_state) 2616 pos_cpy.enable = false; 2617 2618 hubp->funcs->set_cursor_position(hubp, &pos_cpy, ¶m); 2619 dpp->funcs->set_cursor_position(dpp, &pos_cpy, ¶m, hubp->curs_attr.width); 2620 } 2621 2622 static void dcn10_set_cursor_attribute(struct pipe_ctx *pipe_ctx) 2623 { 2624 struct dc_cursor_attributes *attributes = &pipe_ctx->stream->cursor_attributes; 2625 2626 pipe_ctx->plane_res.hubp->funcs->set_cursor_attributes( 2627 pipe_ctx->plane_res.hubp, attributes); 2628 pipe_ctx->plane_res.dpp->funcs->set_cursor_attributes( 2629 pipe_ctx->plane_res.dpp, attributes->color_format); 2630 } 2631 2632 static void dcn10_set_cursor_sdr_white_level(struct pipe_ctx *pipe_ctx) 2633 { 2634 uint32_t sdr_white_level = pipe_ctx->stream->cursor_attributes.sdr_white_level; 2635 struct fixed31_32 multiplier; 2636 struct dpp_cursor_attributes opt_attr = { 0 }; 2637 uint32_t hw_scale = 0x3c00; // 1.0 default multiplier 2638 struct custom_float_format fmt; 2639 2640 if (!pipe_ctx->plane_res.dpp->funcs->set_optional_cursor_attributes) 2641 return; 2642 2643 fmt.exponenta_bits = 5; 2644 fmt.mantissa_bits = 10; 2645 fmt.sign = true; 2646 2647 if (sdr_white_level > 80) { 2648 multiplier = dc_fixpt_from_fraction(sdr_white_level, 80); 2649 convert_to_custom_float_format(multiplier, &fmt, &hw_scale); 2650 } 2651 2652 opt_attr.scale = hw_scale; 2653 opt_attr.bias = 0; 2654 2655 pipe_ctx->plane_res.dpp->funcs->set_optional_cursor_attributes( 2656 pipe_ctx->plane_res.dpp, &opt_attr); 2657 } 2658 2659 static const struct hw_sequencer_funcs dcn10_funcs = { 2660 .program_gamut_remap = program_gamut_remap, 2661 .program_csc_matrix = program_csc_matrix, 2662 .init_hw = dcn10_init_hw, 2663 .apply_ctx_to_hw = dce110_apply_ctx_to_hw, 2664 .apply_ctx_for_surface = dcn10_apply_ctx_for_surface, 2665 .update_plane_addr = dcn10_update_plane_addr, 2666 .plane_atomic_disconnect = hwss1_plane_atomic_disconnect, 2667 .update_dchub = dcn10_update_dchub, 2668 .update_mpcc = dcn10_update_mpcc, 2669 .update_pending_status = dcn10_update_pending_status, 2670 .set_input_transfer_func = dcn10_set_input_transfer_func, 2671 .set_output_transfer_func = dcn10_set_output_transfer_func, 2672 .program_output_csc = dcn10_program_output_csc, 2673 .power_down = dce110_power_down, 2674 .enable_accelerated_mode = dce110_enable_accelerated_mode, 2675 .enable_timing_synchronization = dcn10_enable_timing_synchronization, 2676 .enable_per_frame_crtc_position_reset = dcn10_enable_per_frame_crtc_position_reset, 2677 .update_info_frame = dce110_update_info_frame, 2678 .enable_stream = dce110_enable_stream, 2679 .disable_stream = dce110_disable_stream, 2680 .unblank_stream = dce110_unblank_stream, 2681 .blank_stream = dce110_blank_stream, 2682 .enable_audio_stream = dce110_enable_audio_stream, 2683 .disable_audio_stream = dce110_disable_audio_stream, 2684 .enable_display_power_gating = dcn10_dummy_display_power_gating, 2685 .disable_plane = dcn10_disable_plane, 2686 .blank_pixel_data = dcn10_blank_pixel_data, 2687 .pipe_control_lock = dcn10_pipe_control_lock, 2688 .set_bandwidth = dcn10_set_bandwidth, 2689 .reset_hw_ctx_wrap = reset_hw_ctx_wrap, 2690 .enable_stream_timing = dcn10_enable_stream_timing, 2691 .set_drr = set_drr, 2692 .get_position = get_position, 2693 .set_static_screen_control = set_static_screen_control, 2694 .setup_stereo = dcn10_setup_stereo, 2695 .set_avmute = dce110_set_avmute, 2696 .log_hw_state = dcn10_log_hw_state, 2697 .wait_for_mpcc_disconnect = dcn10_wait_for_mpcc_disconnect, 2698 .ready_shared_resources = ready_shared_resources, 2699 .optimize_shared_resources = optimize_shared_resources, 2700 .pplib_apply_display_requirements = 2701 dcn10_pplib_apply_display_requirements, 2702 .edp_backlight_control = hwss_edp_backlight_control, 2703 .edp_power_control = hwss_edp_power_control, 2704 .edp_wait_for_hpd_ready = hwss_edp_wait_for_hpd_ready, 2705 .set_cursor_position = dcn10_set_cursor_position, 2706 .set_cursor_attribute = dcn10_set_cursor_attribute, 2707 .set_cursor_sdr_white_level = dcn10_set_cursor_sdr_white_level 2708 }; 2709 2710 2711 void dcn10_hw_sequencer_construct(struct dc *dc) 2712 { 2713 dc->hwss = dcn10_funcs; 2714 } 2715 2716