FILE
dcn10_hwseq.c
File preview with syntax highlighting.
linux-6.19.14/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c
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 "basics/dc_common.h" 29#include "core_types.h" 30#include "resource.h" 31#include "custom_float.h" 32#include "dcn10_hwseq.h" 33#include "dcn10/dcn10_hw_sequencer_debug.h" 34#include "dce/dce_hwseq.h" 35#include "abm.h" 36#include "dmcu.h" 37#include "dcn10/dcn10_optc.h" 38#include "dcn10/dcn10_dpp.h" 39#include "dcn10/dcn10_mpc.h" 40#include "timing_generator.h" 41#include "opp.h" 42#include "ipp.h" 43#include "mpc.h" 44#include "reg_helper.h" 45#include "dcn10/dcn10_hubp.h" 46#include "dcn10/dcn10_hubbub.h" 47#include "dcn10/dcn10_cm_common.h" 48#include "dccg.h" 49#include "clk_mgr.h" 50#include "link_hwss.h" 51#include "dpcd_defs.h" 52#include "dsc.h" 53#include "dce/dmub_psr.h" 54#include "dc_dmub_srv.h" 55#include "dce/dmub_hw_lock_mgr.h" 56#include "dc_trace.h" 57#include "dce/dmub_outbox.h" 58#include "link_service.h" 59#include "dc_state_priv.h" 60 61#define DC_LOGGER \ 62 dc_logger 63#define DC_LOGGER_INIT(logger) \ 64 struct dal_logger *dc_logger = logger 65 66#define CTX \ 67 hws->ctx 68#define REG(reg)\ 69 hws->regs->reg 70 71#undef FN 72#define FN(reg_name, field_name) \ 73 hws->shifts->field_name, hws->masks->field_name 74 75/*print is 17 wide, first two characters are spaces*/ 76#define DTN_INFO_MICRO_SEC(ref_cycle) \ 77 print_microsec(dc_ctx, log_ctx, ref_cycle) 78 79#define GAMMA_HW_POINTS_NUM 256 80 81#define PGFSM_POWER_ON 0 82#define PGFSM_POWER_OFF 2 83 84static void print_microsec(struct dc_context *dc_ctx, 85 struct dc_log_buffer_ctx *log_ctx, 86 uint32_t ref_cycle) 87{ 88 const uint32_t ref_clk_mhz = dc_ctx->dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000; 89 static const unsigned int frac = 1000; 90 uint32_t us_x10 = (ref_cycle * frac) / ref_clk_mhz; 91 92 DTN_INFO(" %11d.%03d", 93 us_x10 / frac, 94 us_x10 % frac); 95} 96 97/* 98 * Delay until we passed busy-until-point to which we can 99 * do necessary locking/programming on consecutive full updates 100 */ 101void dcn10_wait_for_pipe_update_if_needed(struct dc *dc, struct pipe_ctx *pipe_ctx, bool is_surface_update_only) 102{ 103 struct crtc_position position; 104 struct dc_stream_state *stream = pipe_ctx->stream; 105 unsigned int vpos, frame_count; 106 uint32_t vupdate_start, vupdate_end, vblank_start; 107 unsigned int lines_to_vupdate, us_to_vupdate; 108 unsigned int us_per_line, us_vupdate; 109 110 if (!pipe_ctx->stream || 111 !pipe_ctx->stream_res.tg || 112 !pipe_ctx->stream_res.stream_enc) 113 return; 114 115 if (pipe_ctx->prev_odm_pipe && 116 pipe_ctx->stream) 117 return; 118 119 if (!pipe_ctx->wait_is_required) 120 return; 121 122 struct timing_generator *tg = pipe_ctx->stream_res.tg; 123 124 if (tg->funcs->is_tg_enabled && !tg->funcs->is_tg_enabled(tg)) 125 return; 126 127 dc->hwss.calc_vupdate_position(dc, pipe_ctx, &vupdate_start, 128 &vupdate_end); 129 130 dc->hwss.get_position(&pipe_ctx, 1, &position); 131 vpos = position.vertical_count; 132 133 frame_count = tg->funcs->get_frame_count(tg); 134 135 if (frame_count - pipe_ctx->wait_frame_count > 2) 136 return; 137 138 vblank_start = pipe_ctx->pipe_dlg_param.vblank_start; 139 140 if (vpos >= vupdate_start && vupdate_start >= vblank_start) 141 lines_to_vupdate = stream->timing.v_total - vpos + vupdate_start; 142 else 143 lines_to_vupdate = vupdate_start - vpos; 144 145 us_per_line = 146 stream->timing.h_total * 10000u / stream->timing.pix_clk_100hz; 147 us_to_vupdate = lines_to_vupdate * us_per_line; 148 149 if (vupdate_end < vupdate_start) 150 vupdate_end += stream->timing.v_total; 151 152 if (lines_to_vupdate > stream->timing.v_total - vupdate_end + vupdate_start) 153 us_to_vupdate = 0; 154 155 us_vupdate = (vupdate_end - vupdate_start + 1) * us_per_line; 156 157 if (is_surface_update_only && us_to_vupdate + us_vupdate > 200) { 158 //surface updates come in at high irql 159 pipe_ctx->wait_is_required = true; 160 return; 161 } 162 163 fsleep(us_to_vupdate + us_vupdate); 164 165 //clear 166 pipe_ctx->next_vupdate = 0; 167 pipe_ctx->wait_frame_count = 0; 168 pipe_ctx->wait_is_required = false; 169} 170 171/* 172 * On pipe unlock and programming, indicate pipe will be busy 173 * until some frame and line (vupdate), this is required for consecutive 174 * full updates, need to wait for updates 175 * to latch to try and program the next update 176 */ 177void dcn10_set_wait_for_update_needed_for_pipe(struct dc *dc, struct pipe_ctx *pipe_ctx) 178{ 179 uint32_t vupdate_start, vupdate_end; 180 struct crtc_position position; 181 unsigned int vpos, cur_frame; 182 183 if (!pipe_ctx->stream || 184 !pipe_ctx->stream_res.tg || 185 !pipe_ctx->stream_res.stream_enc) 186 return; 187 188 dc->hwss.get_position(&pipe_ctx, 1, &position); 189 vpos = position.vertical_count; 190 191 dc->hwss.calc_vupdate_position(dc, pipe_ctx, &vupdate_start, 192 &vupdate_end); 193 194 struct timing_generator *tg = pipe_ctx->stream_res.tg; 195 196 struct optc *optc1 = DCN10TG_FROM_TG(tg); 197 198 ASSERT(optc1->max_frame_count != 0); 199 200 if (tg->funcs->is_tg_enabled && !tg->funcs->is_tg_enabled(tg)) 201 return; 202 203 pipe_ctx->next_vupdate = vupdate_start; 204 205 cur_frame = tg->funcs->get_frame_count(tg); 206 207 if (vpos < vupdate_start) { 208 pipe_ctx->wait_frame_count = cur_frame; 209 } else { 210 if (cur_frame + 1 > optc1->max_frame_count) 211 pipe_ctx->wait_frame_count = cur_frame + 1 - optc1->max_frame_count; 212 else 213 pipe_ctx->wait_frame_count = cur_frame + 1; 214 } 215 216 pipe_ctx->wait_is_required = true; 217} 218 219void dcn10_lock_all_pipes(struct dc *dc, 220 struct dc_state *context, 221 bool lock) 222{ 223 struct pipe_ctx *pipe_ctx; 224 struct pipe_ctx *old_pipe_ctx; 225 struct timing_generator *tg; 226 int i; 227 228 for (i = 0; i < dc->res_pool->pipe_count; i++) { 229 old_pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i]; 230 pipe_ctx = &context->res_ctx.pipe_ctx[i]; 231 tg = pipe_ctx->stream_res.tg; 232 233 /* 234 * Only lock the top pipe's tg to prevent redundant 235 * (un)locking. Also skip if pipe is disabled. 236 */ 237 if (pipe_ctx->top_pipe || 238 !pipe_ctx->stream || 239 (!pipe_ctx->plane_state && !old_pipe_ctx->plane_state) || 240 !tg->funcs->is_tg_enabled(tg) || 241 dc_state_get_pipe_subvp_type(context, pipe_ctx) == SUBVP_PHANTOM) 242 continue; 243 244 if (lock) 245 dc->hwss.pipe_control_lock(dc, pipe_ctx, true); 246 else 247 dc->hwss.pipe_control_lock(dc, pipe_ctx, false); 248 } 249} 250 251static void log_mpc_crc(struct dc *dc, 252 struct dc_log_buffer_ctx *log_ctx) 253{ 254 struct dc_context *dc_ctx = dc->ctx; 255 struct dce_hwseq *hws = dc->hwseq; 256 257 if (REG(MPC_CRC_RESULT_GB)) 258 DTN_INFO("MPC_CRC_RESULT_GB:%d MPC_CRC_RESULT_C:%d MPC_CRC_RESULT_AR:%d\n", 259 REG_READ(MPC_CRC_RESULT_GB), REG_READ(MPC_CRC_RESULT_C), REG_READ(MPC_CRC_RESULT_AR)); 260 if (REG(DPP_TOP0_DPP_CRC_VAL_B_A)) 261 DTN_INFO("DPP_TOP0_DPP_CRC_VAL_B_A:%d DPP_TOP0_DPP_CRC_VAL_R_G:%d\n", 262 REG_READ(DPP_TOP0_DPP_CRC_VAL_B_A), REG_READ(DPP_TOP0_DPP_CRC_VAL_R_G)); 263} 264 265static void dcn10_log_hubbub_state(struct dc *dc, 266 struct dc_log_buffer_ctx *log_ctx) 267{ 268 struct dc_context *dc_ctx = dc->ctx; 269 struct dcn_hubbub_wm wm; 270 int i; 271 272 memset(&wm, 0, sizeof(struct dcn_hubbub_wm)); 273 dc->res_pool->hubbub->funcs->wm_read_state(dc->res_pool->hubbub, &wm); 274 275 DTN_INFO("HUBBUB WM: data_urgent pte_meta_urgent" 276 " sr_enter sr_exit dram_clk_change\n"); 277 278 for (i = 0; i < 4; i++) { 279 struct dcn_hubbub_wm_set *s; 280 281 s = &wm.sets[i]; 282 DTN_INFO("WM_Set[%d]:", s->wm_set); 283 DTN_INFO_MICRO_SEC(s->data_urgent); 284 DTN_INFO_MICRO_SEC(s->pte_meta_urgent); 285 DTN_INFO_MICRO_SEC(s->sr_enter); 286 DTN_INFO_MICRO_SEC(s->sr_exit); 287 DTN_INFO_MICRO_SEC(s->dram_clk_change); 288 DTN_INFO("\n"); 289 } 290 291 DTN_INFO("\n"); 292} 293 294static void dcn10_log_hubp_states(struct dc *dc, void *log_ctx) 295{ 296 struct dc_context *dc_ctx = dc->ctx; 297 struct resource_pool *pool = dc->res_pool; 298 int i; 299 300 DTN_INFO( 301 "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"); 302 for (i = 0; i < pool->pipe_count; i++) { 303 struct hubp *hubp = pool->hubps[i]; 304 struct dcn_hubp_state *s = &(TO_DCN10_HUBP(hubp)->state); 305 306 hubp->funcs->hubp_read_state(hubp); 307 308 if (!s->blank_en) { 309 DTN_INFO("[%2d]: %5xh %6xh %5d %6d %2xh %2xh %6xh %6d %8d %8d %7d %8xh", 310 hubp->inst, 311 s->pixel_format, 312 s->inuse_addr_hi, 313 s->viewport_width, 314 s->viewport_height, 315 s->rotation_angle, 316 s->h_mirror_en, 317 s->sw_mode, 318 s->dcc_en, 319 s->blank_en, 320 s->clock_en, 321 s->ttu_disable, 322 s->underflow_status); 323 DTN_INFO_MICRO_SEC(s->min_ttu_vblank); 324 DTN_INFO_MICRO_SEC(s->qos_level_low_wm); 325 DTN_INFO_MICRO_SEC(s->qos_level_high_wm); 326 DTN_INFO("\n"); 327 } 328 } 329 330 DTN_INFO("\n=======HUBP FL======\n"); 331 static const char * const pLabels[] = { 332 "inst", "Enabled ", "Done ", "adr_mode ", "width ", "mpc_width ", 333 "tmz", "xbar_sel_R", "xbar_sel_G", "xbar_sel_B", "adr_hi ", 334 "adr_low", "REFCYC", "Bias", "Scale", "Mode", 335 "Format", "prefetch"}; 336 337 for (i = 0; i < pool->pipe_count; i++) { 338 struct dcn_hubp_state *s = &(TO_DCN10_HUBP(pool->hubps[i])->state); 339 struct dcn_fl_regs_st *fl_regs = &s->fl_regs; 340 struct _vcs_dpi_display_dlg_regs_st *dlg_regs = &s->dlg_attr; 341 342 if (!s->blank_en) { 343 uint32_t values[] = { 344 pool->hubps[i]->inst, 345 fl_regs->lut_enable, 346 fl_regs->lut_done, 347 fl_regs->lut_addr_mode, 348 fl_regs->lut_width, 349 fl_regs->lut_mpc_width, 350 fl_regs->lut_tmz, 351 fl_regs->lut_crossbar_sel_r, 352 fl_regs->lut_crossbar_sel_g, 353 fl_regs->lut_crossbar_sel_b, 354 fl_regs->lut_addr_hi, 355 fl_regs->lut_addr_lo, 356 fl_regs->refcyc_3dlut_group, 357 fl_regs->lut_fl_bias, 358 fl_regs->lut_fl_scale, 359 fl_regs->lut_fl_mode, 360 fl_regs->lut_fl_format, 361 dlg_regs->dst_y_prefetch}; 362 363 int num_elements = 18; 364 365 for (int j = 0; j < num_elements; j++) 366 DTN_INFO("%s \t %8xh\n", pLabels[j], values[j]); 367 } 368 } 369 370 DTN_INFO("\n=========RQ========\n"); 371 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" 372 " min_m_c_s dpte_gr_s mpte_gr_s swath_hei pte_row_h C:chunk_s min_chu_s meta_ch_s" 373 " min_m_c_s dpte_gr_s mpte_gr_s swath_hei pte_row_h\n"); 374 for (i = 0; i < pool->pipe_count; i++) { 375 struct dcn_hubp_state *s = &(TO_DCN10_HUBP(pool->hubps[i])->state); 376 struct _vcs_dpi_display_rq_regs_st *rq_regs = &s->rq_regs; 377 378 if (!s->blank_en) 379 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", 380 pool->hubps[i]->inst, rq_regs->drq_expansion_mode, rq_regs->prq_expansion_mode, rq_regs->mrq_expansion_mode, 381 rq_regs->crq_expansion_mode, rq_regs->plane1_base_address, rq_regs->rq_regs_l.chunk_size, 382 rq_regs->rq_regs_l.min_chunk_size, rq_regs->rq_regs_l.meta_chunk_size, 383 rq_regs->rq_regs_l.min_meta_chunk_size, rq_regs->rq_regs_l.dpte_group_size, 384 rq_regs->rq_regs_l.mpte_group_size, rq_regs->rq_regs_l.swath_height, 385 rq_regs->rq_regs_l.pte_row_height_linear, rq_regs->rq_regs_c.chunk_size, rq_regs->rq_regs_c.min_chunk_size, 386 rq_regs->rq_regs_c.meta_chunk_size, rq_regs->rq_regs_c.min_meta_chunk_size, 387 rq_regs->rq_regs_c.dpte_group_size, rq_regs->rq_regs_c.mpte_group_size, 388 rq_regs->rq_regs_c.swath_height, rq_regs->rq_regs_c.pte_row_height_linear); 389 } 390 391 DTN_INFO("========DLG========\n"); 392 DTN_INFO("HUBP: rc_hbe dlg_vbe min_d_y_n rc_per_ht rc_x_a_s " 393 " dst_y_a_s dst_y_pf dst_y_vvb dst_y_rvb dst_y_vfl dst_y_rfl rf_pix_fq" 394 " vratio_pf vrat_pf_c rc_pg_vbl rc_pg_vbc rc_mc_vbl rc_mc_vbc rc_pg_fll" 395 " rc_pg_flc rc_mc_fll rc_mc_flc pr_nom_l pr_nom_c rc_pg_nl rc_pg_nc " 396 " mr_nom_l mr_nom_c rc_mc_nl rc_mc_nc rc_ld_pl rc_ld_pc rc_ld_l " 397 " rc_ld_c cha_cur0 ofst_cur1 cha_cur1 vr_af_vc0 ddrq_limt x_rt_dlay" 398 " x_rp_dlay x_rr_sfl rc_td_grp\n"); 399 400 for (i = 0; i < pool->pipe_count; i++) { 401 struct dcn_hubp_state *s = &(TO_DCN10_HUBP(pool->hubps[i])->state); 402 struct _vcs_dpi_display_dlg_regs_st *dlg_regs = &s->dlg_attr; 403 404 if (!s->blank_en) 405 DTN_INFO("[%2d]: %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh" 406 " %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh" 407 " %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %xh\n", 408 pool->hubps[i]->inst, dlg_regs->refcyc_h_blank_end, dlg_regs->dlg_vblank_end, dlg_regs->min_dst_y_next_start, 409 dlg_regs->refcyc_per_htotal, dlg_regs->refcyc_x_after_scaler, dlg_regs->dst_y_after_scaler, 410 dlg_regs->dst_y_prefetch, dlg_regs->dst_y_per_vm_vblank, dlg_regs->dst_y_per_row_vblank, 411 dlg_regs->dst_y_per_vm_flip, dlg_regs->dst_y_per_row_flip, dlg_regs->ref_freq_to_pix_freq, 412 dlg_regs->vratio_prefetch, dlg_regs->vratio_prefetch_c, dlg_regs->refcyc_per_pte_group_vblank_l, 413 dlg_regs->refcyc_per_pte_group_vblank_c, dlg_regs->refcyc_per_meta_chunk_vblank_l, 414 dlg_regs->refcyc_per_meta_chunk_vblank_c, dlg_regs->refcyc_per_pte_group_flip_l, 415 dlg_regs->refcyc_per_pte_group_flip_c, dlg_regs->refcyc_per_meta_chunk_flip_l, 416 dlg_regs->refcyc_per_meta_chunk_flip_c, dlg_regs->dst_y_per_pte_row_nom_l, 417 dlg_regs->dst_y_per_pte_row_nom_c, dlg_regs->refcyc_per_pte_group_nom_l, 418 dlg_regs->refcyc_per_pte_group_nom_c, dlg_regs->dst_y_per_meta_row_nom_l, 419 dlg_regs->dst_y_per_meta_row_nom_c, dlg_regs->refcyc_per_meta_chunk_nom_l, 420 dlg_regs->refcyc_per_meta_chunk_nom_c, dlg_regs->refcyc_per_line_delivery_pre_l, 421 dlg_regs->refcyc_per_line_delivery_pre_c, dlg_regs->refcyc_per_line_delivery_l, 422 dlg_regs->refcyc_per_line_delivery_c, dlg_regs->chunk_hdl_adjust_cur0, dlg_regs->dst_y_offset_cur1, 423 dlg_regs->chunk_hdl_adjust_cur1, dlg_regs->vready_after_vcount0, dlg_regs->dst_y_delta_drq_limit, 424 dlg_regs->xfc_reg_transfer_delay, dlg_regs->xfc_reg_precharge_delay, 425 dlg_regs->xfc_reg_remote_surface_flip_latency, dlg_regs->refcyc_per_tdlut_group); 426 } 427 428 DTN_INFO("========TTU========\n"); 429 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" 430 " rc_rd_c rc_rd_c0 rc_rd_pc0 rc_rd_c1 rc_rd_pc1 qos_lf_l qos_rds_l" 431 " qos_lf_c qos_rds_c qos_lf_c0 qos_rds_c0 qos_lf_c1 qos_rds_c1\n"); 432 for (i = 0; i < pool->pipe_count; i++) { 433 struct dcn_hubp_state *s = &(TO_DCN10_HUBP(pool->hubps[i])->state); 434 struct _vcs_dpi_display_ttu_regs_st *ttu_regs = &s->ttu_attr; 435 436 if (!s->blank_en) 437 DTN_INFO("[%2d]: %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh\n", 438 pool->hubps[i]->inst, ttu_regs->qos_level_low_wm, ttu_regs->qos_level_high_wm, ttu_regs->min_ttu_vblank, 439 ttu_regs->qos_level_flip, ttu_regs->refcyc_per_req_delivery_pre_l, ttu_regs->refcyc_per_req_delivery_l, 440 ttu_regs->refcyc_per_req_delivery_pre_c, ttu_regs->refcyc_per_req_delivery_c, ttu_regs->refcyc_per_req_delivery_cur0, 441 ttu_regs->refcyc_per_req_delivery_pre_cur0, ttu_regs->refcyc_per_req_delivery_cur1, 442 ttu_regs->refcyc_per_req_delivery_pre_cur1, ttu_regs->qos_level_fixed_l, ttu_regs->qos_ramp_disable_l, 443 ttu_regs->qos_level_fixed_c, ttu_regs->qos_ramp_disable_c, ttu_regs->qos_level_fixed_cur0, 444 ttu_regs->qos_ramp_disable_cur0, ttu_regs->qos_level_fixed_cur1, ttu_regs->qos_ramp_disable_cur1); 445 } 446 DTN_INFO("\n"); 447} 448 449static void dcn10_log_color_state(struct dc *dc, 450 struct dc_log_buffer_ctx *log_ctx) 451{ 452 struct dc_context *dc_ctx = dc->ctx; 453 struct resource_pool *pool = dc->res_pool; 454 bool is_gamut_remap_available = false; 455 int i; 456 457 DTN_INFO("DPP: IGAM format IGAM mode DGAM mode RGAM mode" 458 " GAMUT adjust " 459 "C11 C12 C13 C14 " 460 "C21 C22 C23 C24 " 461 "C31 C32 C33 C34 \n"); 462 for (i = 0; i < pool->pipe_count; i++) { 463 struct dpp *dpp = pool->dpps[i]; 464 struct dcn_dpp_state s = {0}; 465 466 dpp->funcs->dpp_read_state(dpp, &s); 467 if (dpp->funcs->dpp_get_gamut_remap) { 468 dpp->funcs->dpp_get_gamut_remap(dpp, &s.gamut_remap); 469 is_gamut_remap_available = true; 470 } 471 472 if (!s.is_enabled) 473 continue; 474 475 DTN_INFO("[%2d]: %11xh %11s %9s %9s", 476 dpp->inst, 477 s.igam_input_format, 478 (s.igam_lut_mode == 0) ? "BypassFixed" : 479 ((s.igam_lut_mode == 1) ? "BypassFloat" : 480 ((s.igam_lut_mode == 2) ? "RAM" : 481 ((s.igam_lut_mode == 3) ? "RAM" : 482 "Unknown"))), 483 (s.dgam_lut_mode == 0) ? "Bypass" : 484 ((s.dgam_lut_mode == 1) ? "sRGB" : 485 ((s.dgam_lut_mode == 2) ? "Ycc" : 486 ((s.dgam_lut_mode == 3) ? "RAM" : 487 ((s.dgam_lut_mode == 4) ? "RAM" : 488 "Unknown")))), 489 (s.rgam_lut_mode == 0) ? "Bypass" : 490 ((s.rgam_lut_mode == 1) ? "sRGB" : 491 ((s.rgam_lut_mode == 2) ? "Ycc" : 492 ((s.rgam_lut_mode == 3) ? "RAM" : 493 ((s.rgam_lut_mode == 4) ? "RAM" : 494 "Unknown"))))); 495 if (is_gamut_remap_available) 496 DTN_INFO(" %12s " 497 "%010lld %010lld %010lld %010lld " 498 "%010lld %010lld %010lld %010lld " 499 "%010lld %010lld %010lld %010lld", 500 (s.gamut_remap.gamut_adjust_type == 0) ? "Bypass" : 501 ((s.gamut_remap.gamut_adjust_type == 1) ? "HW" : "SW"), 502 s.gamut_remap.temperature_matrix[0].value, 503 s.gamut_remap.temperature_matrix[1].value, 504 s.gamut_remap.temperature_matrix[2].value, 505 s.gamut_remap.temperature_matrix[3].value, 506 s.gamut_remap.temperature_matrix[4].value, 507 s.gamut_remap.temperature_matrix[5].value, 508 s.gamut_remap.temperature_matrix[6].value, 509 s.gamut_remap.temperature_matrix[7].value, 510 s.gamut_remap.temperature_matrix[8].value, 511 s.gamut_remap.temperature_matrix[9].value, 512 s.gamut_remap.temperature_matrix[10].value, 513 s.gamut_remap.temperature_matrix[11].value); 514 515 DTN_INFO("\n"); 516 } 517 DTN_INFO("\n"); 518 DTN_INFO("DPP Color Caps: input_lut_shared:%d icsc:%d" 519 " dgam_ram:%d dgam_rom: srgb:%d,bt2020:%d,gamma2_2:%d,pq:%d,hlg:%d" 520 " post_csc:%d gamcor:%d dgam_rom_for_yuv:%d 3d_lut:%d" 521 " blnd_lut:%d oscs:%d\n\n", 522 dc->caps.color.dpp.input_lut_shared, 523 dc->caps.color.dpp.icsc, 524 dc->caps.color.dpp.dgam_ram, 525 dc->caps.color.dpp.dgam_rom_caps.srgb, 526 dc->caps.color.dpp.dgam_rom_caps.bt2020, 527 dc->caps.color.dpp.dgam_rom_caps.gamma2_2, 528 dc->caps.color.dpp.dgam_rom_caps.pq, 529 dc->caps.color.dpp.dgam_rom_caps.hlg, 530 dc->caps.color.dpp.post_csc, 531 dc->caps.color.dpp.gamma_corr, 532 dc->caps.color.dpp.dgam_rom_for_yuv, 533 dc->caps.color.dpp.hw_3d_lut, 534 dc->caps.color.dpp.ogam_ram, 535 dc->caps.color.dpp.ocsc); 536 537 DTN_INFO("MPCC: OPP DPP MPCCBOT MODE ALPHA_MODE PREMULT OVERLAP_ONLY IDLE\n"); 538 for (i = 0; i < pool->mpcc_count; i++) { 539 struct mpcc_state s = {0}; 540 541 pool->mpc->funcs->read_mpcc_state(pool->mpc, i, &s); 542 if (s.opp_id != 0xf) 543 DTN_INFO("[%2d]: %2xh %2xh %6xh %4d %10d %7d %12d %4d\n", 544 i, s.opp_id, s.dpp_id, s.bot_mpcc_id, 545 s.mode, s.alpha_mode, s.pre_multiplied_alpha, s.overlap_only, 546 s.idle); 547 } 548 DTN_INFO("\n"); 549 DTN_INFO("MPC Color Caps: gamut_remap:%d, 3dlut:%d, ogam_ram:%d, ocsc:%d\n\n", 550 dc->caps.color.mpc.gamut_remap, 551 dc->caps.color.mpc.num_3dluts, 552 dc->caps.color.mpc.ogam_ram, 553 dc->caps.color.mpc.ocsc); 554 DTN_INFO("===== MPC RMCM 3DLUT =====\n"); 555 static const char * const pLabels[] = { 556 "MPCC", "SIZE", "MODE", "MODE_CUR", "RD_SEL", 557 "30BIT_EN", "WR_EN_MASK", "RAM_SEL", "OUT_NORM_FACTOR", "FL_SEL", 558 "OUT_OFFSET", "OUT_SCALE", "FL_DONE", "SOFT_UNDERFLOW", "HARD_UNDERFLOW", 559 "MEM_PWR_ST", "FORCE", "DIS", "MODE"}; 560 561 for (i = 0; i < pool->mpcc_count; i++) { 562 struct mpcc_state s = {0}; 563 564 pool->mpc->funcs->read_mpcc_state(pool->mpc, i, &s); 565 if (s.opp_id != 0xf) { 566 uint32_t values[] = { 567 i, 568 s.rmcm_regs.rmcm_3dlut_size, 569 s.rmcm_regs.rmcm_3dlut_mode, 570 s.rmcm_regs.rmcm_3dlut_mode_cur, 571 s.rmcm_regs.rmcm_3dlut_read_sel, 572 s.rmcm_regs.rmcm_3dlut_30bit_en, 573 s.rmcm_regs.rmcm_3dlut_wr_en_mask, 574 s.rmcm_regs.rmcm_3dlut_ram_sel, 575 s.rmcm_regs.rmcm_3dlut_out_norm_factor, 576 s.rmcm_regs.rmcm_3dlut_fl_sel, 577 s.rmcm_regs.rmcm_3dlut_out_offset_r, 578 s.rmcm_regs.rmcm_3dlut_out_scale_r, 579 s.rmcm_regs.rmcm_3dlut_fl_done, 580 s.rmcm_regs.rmcm_3dlut_fl_soft_underflow, 581 s.rmcm_regs.rmcm_3dlut_fl_hard_underflow, 582 s.rmcm_regs.rmcm_3dlut_mem_pwr_state, 583 s.rmcm_regs.rmcm_3dlut_mem_pwr_force, 584 s.rmcm_regs.rmcm_3dlut_mem_pwr_dis, 585 s.rmcm_regs.rmcm_3dlut_mem_pwr_mode}; 586 587 int num_elements = 19; 588 589 for (int j = 0; j < num_elements; j++) 590 DTN_INFO("%s \t %8xh\n", pLabels[j], values[j]); 591 } 592 } 593 DTN_INFO("\n"); 594 DTN_INFO("===== MPC RMCM Shaper =====\n"); 595 DTN_INFO("MPCC: CNTL LUT_MODE MODE_CUR WR_EN_MASK WR_SEL OFFSET SCALE START_B START_SEG_B END_B END_BASE_B MEM_PWR_ST FORCE DIS MODE\n"); 596 for (i = 0; i < pool->mpcc_count; i++) { 597 struct mpcc_state s = {0}; 598 599 pool->mpc->funcs->read_mpcc_state(pool->mpc, i, &s); 600 if (s.opp_id != 0xf) 601 DTN_INFO("[%2d]: %4xh %4xh %6xh %4x %4x %4x %4x %4x %4xh %4xh %6xh %4x %4x %4x %4x\n", 602 i, s.rmcm_regs.rmcm_cntl, s.rmcm_regs.rmcm_shaper_lut_mode, s.rmcm_regs.rmcm_shaper_mode_cur, 603 s.rmcm_regs.rmcm_shaper_lut_write_en_mask, s.rmcm_regs.rmcm_shaper_lut_write_sel, s.rmcm_regs.rmcm_shaper_offset_b, 604 s.rmcm_regs.rmcm_shaper_scale_b, s.rmcm_regs.rmcm_shaper_rama_exp_region_start_b, s.rmcm_regs.rmcm_shaper_rama_exp_region_start_seg_b, 605 s.rmcm_regs.rmcm_shaper_rama_exp_region_end_b, s.rmcm_regs.rmcm_shaper_rama_exp_region_end_base_b, s.rmcm_regs.rmcm_shaper_mem_pwr_state, 606 s.rmcm_regs.rmcm_shaper_mem_pwr_force, s.rmcm_regs.rmcm_shaper_mem_pwr_dis, s.rmcm_regs.rmcm_shaper_mem_pwr_mode); 607 } 608} 609 610void dcn10_log_hw_state(struct dc *dc, 611 struct dc_log_buffer_ctx *log_ctx) 612{ 613 struct dc_context *dc_ctx = dc->ctx; 614 struct resource_pool *pool = dc->res_pool; 615 int i; 616 617 DTN_INFO_BEGIN(); 618 619 dcn10_log_hubbub_state(dc, log_ctx); 620 621 dcn10_log_hubp_states(dc, log_ctx); 622 623 if (dc->hwss.log_color_state) 624 dc->hwss.log_color_state(dc, log_ctx); 625 else 626 dcn10_log_color_state(dc, log_ctx); 627 628 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"); 629 630 for (i = 0; i < pool->timing_generator_count; i++) { 631 struct timing_generator *tg = pool->timing_generators[i]; 632 struct dcn_otg_state s = {0}; 633 /* Read shared OTG state registers for all DCNx */ 634 if (tg->funcs->read_otg_state) 635 tg->funcs->read_otg_state(tg, &s); 636 637 /* 638 * For DCN2 and greater, a register on the OPP is used to 639 * determine if the CRTC is blanked instead of the OTG. So use 640 * dpg_is_blanked() if exists, otherwise fallback on otg. 641 * 642 * TODO: Implement DCN-specific read_otg_state hooks. 643 */ 644 if (pool->opps[i]->funcs->dpg_is_blanked) 645 s.blank_enabled = pool->opps[i]->funcs->dpg_is_blanked(pool->opps[i]); 646 else 647 s.blank_enabled = tg->funcs->is_blanked(tg); 648 649 //only print if OTG master is enabled 650 if ((s.otg_enabled & 1) == 0) 651 continue; 652 653 DTN_INFO("[%d]: %5d %5d %5d %5d %5d %5d %5d %9d %9d %5d %5d %5d %5d %5d %5d %5d %9d %8d\n", 654 tg->inst, 655 s.v_blank_start, 656 s.v_blank_end, 657 s.v_sync_a_start, 658 s.v_sync_a_end, 659 s.v_sync_a_pol, 660 s.v_total_max, 661 s.v_total_min, 662 s.v_total_max_sel, 663 s.v_total_min_sel, 664 s.h_blank_start, 665 s.h_blank_end, 666 s.h_sync_a_start, 667 s.h_sync_a_end, 668 s.h_sync_a_pol, 669 s.h_total, 670 s.v_total, 671 s.underflow_occurred_status, 672 s.blank_enabled); 673 674 // Clear underflow for debug purposes 675 // We want to keep underflow sticky bit on for the longevity tests outside of test environment. 676 // This function is called only from Windows or Diags test environment, hence it's safe to clear 677 // it from here without affecting the original intent. 678 tg->funcs->clear_optc_underflow(tg); 679 } 680 DTN_INFO("\n"); 681 682 // dcn_dsc_state struct field bytes_per_pixel was renamed to bits_per_pixel 683 // TODO: Update golden log header to reflect this name change 684 DTN_INFO("DSC: CLOCK_EN SLICE_WIDTH Bytes_pp\n"); 685 for (i = 0; i < pool->res_cap->num_dsc; i++) { 686 struct display_stream_compressor *dsc = pool->dscs[i]; 687 struct dcn_dsc_state s = {0}; 688 689 dsc->funcs->dsc_read_state(dsc, &s); 690 DTN_INFO("[%d]: %-9d %-12d %-10d\n", 691 dsc->inst, 692 s.dsc_clock_en, 693 s.dsc_slice_width, 694 s.dsc_bits_per_pixel); 695 DTN_INFO("\n"); 696 } 697 DTN_INFO("\n"); 698 699 DTN_INFO("S_ENC: DSC_MODE SEC_GSP7_LINE_NUM" 700 " VBID6_LINE_REFERENCE VBID6_LINE_NUM SEC_GSP7_ENABLE SEC_STREAM_ENABLE\n"); 701 for (i = 0; i < pool->stream_enc_count; i++) { 702 struct stream_encoder *enc = pool->stream_enc[i]; 703 struct enc_state s = {0}; 704 705 if (enc->funcs->enc_read_state) { 706 enc->funcs->enc_read_state(enc, &s); 707 DTN_INFO("[%-3d]: %-9d %-18d %-21d %-15d %-16d %-17d\n", 708 enc->id, 709 s.dsc_mode, 710 s.sec_gsp_pps_line_num, 711 s.vbid6_line_reference, 712 s.vbid6_line_num, 713 s.sec_gsp_pps_enable, 714 s.sec_stream_enable); 715 DTN_INFO("\n"); 716 } 717 } 718 DTN_INFO("\n"); 719 720 DTN_INFO("L_ENC: DPHY_FEC_EN DPHY_FEC_READY_SHADOW DPHY_FEC_ACTIVE_STATUS DP_LINK_TRAINING_COMPLETE\n"); 721 for (i = 0; i < dc->link_count; i++) { 722 struct link_encoder *lenc = dc->links[i]->link_enc; 723 724 struct link_enc_state s = {0}; 725 726 if (lenc && lenc->funcs->read_state) { 727 lenc->funcs->read_state(lenc, &s); 728 DTN_INFO("[%-3d]: %-12d %-22d %-22d %-25d\n", 729 i, 730 s.dphy_fec_en, 731 s.dphy_fec_ready_shadow, 732 s.dphy_fec_active_status, 733 s.dp_link_training_complete); 734 DTN_INFO("\n"); 735 } 736 } 737 DTN_INFO("\n"); 738 739 DTN_INFO("\nCALCULATED Clocks: dcfclk_khz:%d dcfclk_deep_sleep_khz:%d dispclk_khz:%d\n" 740 "dppclk_khz:%d max_supported_dppclk_khz:%d fclk_khz:%d socclk_khz:%d\n\n", 741 dc->current_state->bw_ctx.bw.dcn.clk.dcfclk_khz, 742 dc->current_state->bw_ctx.bw.dcn.clk.dcfclk_deep_sleep_khz, 743 dc->current_state->bw_ctx.bw.dcn.clk.dispclk_khz, 744 dc->current_state->bw_ctx.bw.dcn.clk.dppclk_khz, 745 dc->current_state->bw_ctx.bw.dcn.clk.max_supported_dppclk_khz, 746 dc->current_state->bw_ctx.bw.dcn.clk.fclk_khz, 747 dc->current_state->bw_ctx.bw.dcn.clk.socclk_khz); 748 749 log_mpc_crc(dc, log_ctx); 750 751 { 752 if (pool->hpo_dp_stream_enc_count > 0) { 753 DTN_INFO("DP HPO S_ENC: Enabled OTG Format Depth Vid SDP Compressed Link\n"); 754 for (i = 0; i < pool->hpo_dp_stream_enc_count; i++) { 755 struct hpo_dp_stream_encoder_state hpo_dp_se_state = {0}; 756 struct hpo_dp_stream_encoder *hpo_dp_stream_enc = pool->hpo_dp_stream_enc[i]; 757 758 if (hpo_dp_stream_enc && hpo_dp_stream_enc->funcs->read_state) { 759 hpo_dp_stream_enc->funcs->read_state(hpo_dp_stream_enc, &hpo_dp_se_state); 760 761 DTN_INFO("[%d]: %d %d %6s %d %d %d %d %d\n", 762 hpo_dp_stream_enc->id - ENGINE_ID_HPO_DP_0, 763 hpo_dp_se_state.stream_enc_enabled, 764 hpo_dp_se_state.otg_inst, 765 (hpo_dp_se_state.pixel_encoding == 0) ? "4:4:4" : 766 ((hpo_dp_se_state.pixel_encoding == 1) ? "4:2:2" : 767 (hpo_dp_se_state.pixel_encoding == 2) ? "4:2:0" : "Y-Only"), 768 (hpo_dp_se_state.component_depth == 0) ? 6 : 769 ((hpo_dp_se_state.component_depth == 1) ? 8 : 770 (hpo_dp_se_state.component_depth == 2) ? 10 : 12), 771 hpo_dp_se_state.vid_stream_enabled, 772 hpo_dp_se_state.sdp_enabled, 773 hpo_dp_se_state.compressed_format, 774 hpo_dp_se_state.mapped_to_link_enc); 775 } 776 } 777 778 DTN_INFO("\n"); 779 } 780 781 /* log DP HPO L_ENC section if any hpo_dp_link_enc exists */ 782 if (pool->hpo_dp_link_enc_count) { 783 DTN_INFO("DP HPO L_ENC: Enabled Mode Lanes Stream Slots VC Rate X VC Rate Y\n"); 784 785 for (i = 0; i < pool->hpo_dp_link_enc_count; i++) { 786 struct hpo_dp_link_encoder *hpo_dp_link_enc = pool->hpo_dp_link_enc[i]; 787 struct hpo_dp_link_enc_state hpo_dp_le_state = {0}; 788 789 if (hpo_dp_link_enc->funcs->read_state) { 790 hpo_dp_link_enc->funcs->read_state(hpo_dp_link_enc, &hpo_dp_le_state); 791 DTN_INFO("[%d]: %d %6s %d %d %d %d %d\n", 792 hpo_dp_link_enc->inst, 793 hpo_dp_le_state.link_enc_enabled, 794 (hpo_dp_le_state.link_mode == 0) ? "TPS1" : 795 (hpo_dp_le_state.link_mode == 1) ? "TPS2" : 796 (hpo_dp_le_state.link_mode == 2) ? "ACTIVE" : "TEST", 797 hpo_dp_le_state.lane_count, 798 hpo_dp_le_state.stream_src[0], 799 hpo_dp_le_state.slot_count[0], 800 hpo_dp_le_state.vc_rate_x[0], 801 hpo_dp_le_state.vc_rate_y[0]); 802 DTN_INFO("\n"); 803 } 804 } 805 806 DTN_INFO("\n"); 807 } 808 } 809 810 DTN_INFO_END(); 811} 812 813bool dcn10_did_underflow_occur(struct dc *dc, struct pipe_ctx *pipe_ctx) 814{ 815 struct hubp *hubp = pipe_ctx->plane_res.hubp; 816 struct timing_generator *tg = pipe_ctx->stream_res.tg; 817 818 if (tg->funcs->is_optc_underflow_occurred(tg)) { 819 tg->funcs->clear_optc_underflow(tg); 820 return true; 821 } 822 823 if (hubp->funcs->hubp_get_underflow_status(hubp)) { 824 hubp->funcs->hubp_clear_underflow(hubp); 825 return true; 826 } 827 return false; 828} 829 830void dcn10_enable_power_gating_plane( 831 struct dce_hwseq *hws, 832 bool enable) 833{ 834 bool force_on = true; /* disable power gating */ 835 836 if (enable) 837 force_on = false; 838 839 /* DCHUBP0/1/2/3 */ 840 REG_UPDATE(DOMAIN0_PG_CONFIG, DOMAIN0_POWER_FORCEON, force_on); 841 REG_UPDATE(DOMAIN2_PG_CONFIG, DOMAIN2_POWER_FORCEON, force_on); 842 REG_UPDATE(DOMAIN4_PG_CONFIG, DOMAIN4_POWER_FORCEON, force_on); 843 REG_UPDATE(DOMAIN6_PG_CONFIG, DOMAIN6_POWER_FORCEON, force_on); 844 845 /* DPP0/1/2/3 */ 846 REG_UPDATE(DOMAIN1_PG_CONFIG, DOMAIN1_POWER_FORCEON, force_on); 847 REG_UPDATE(DOMAIN3_PG_CONFIG, DOMAIN3_POWER_FORCEON, force_on); 848 REG_UPDATE(DOMAIN5_PG_CONFIG, DOMAIN5_POWER_FORCEON, force_on); 849 REG_UPDATE(DOMAIN7_PG_CONFIG, DOMAIN7_POWER_FORCEON, force_on); 850} 851 852void dcn10_disable_vga( 853 struct dce_hwseq *hws) 854{ 855 unsigned int in_vga1_mode = 0; 856 unsigned int in_vga2_mode = 0; 857 unsigned int in_vga3_mode = 0; 858 unsigned int in_vga4_mode = 0; 859 860 REG_GET(D1VGA_CONTROL, D1VGA_MODE_ENABLE, &in_vga1_mode); 861 REG_GET(D2VGA_CONTROL, D2VGA_MODE_ENABLE, &in_vga2_mode); 862 REG_GET(D3VGA_CONTROL, D3VGA_MODE_ENABLE, &in_vga3_mode); 863 REG_GET(D4VGA_CONTROL, D4VGA_MODE_ENABLE, &in_vga4_mode); 864 865 if (in_vga1_mode == 0 && in_vga2_mode == 0 && 866 in_vga3_mode == 0 && in_vga4_mode == 0) 867 return; 868 869 REG_WRITE(D1VGA_CONTROL, 0); 870 REG_WRITE(D2VGA_CONTROL, 0); 871 REG_WRITE(D3VGA_CONTROL, 0); 872 REG_WRITE(D4VGA_CONTROL, 0); 873 874 /* HW Engineer's Notes: 875 * During switch from vga->extended, if we set the VGA_TEST_ENABLE and 876 * then hit the VGA_TEST_RENDER_START, then the DCHUBP timing gets updated correctly. 877 * 878 * Then vBIOS will have it poll for the VGA_TEST_RENDER_DONE and unset 879 * VGA_TEST_ENABLE, to leave it in the same state as before. 880 */ 881 REG_UPDATE(VGA_TEST_CONTROL, VGA_TEST_ENABLE, 1); 882 REG_UPDATE(VGA_TEST_CONTROL, VGA_TEST_RENDER_START, 1); 883} 884 885/** 886 * dcn10_dpp_pg_control - DPP power gate control. 887 * 888 * @hws: dce_hwseq reference. 889 * @dpp_inst: DPP instance reference. 890 * @power_on: true if we want to enable power gate, false otherwise. 891 * 892 * Enable or disable power gate in the specific DPP instance. 893 */ 894void dcn10_dpp_pg_control( 895 struct dce_hwseq *hws, 896 unsigned int dpp_inst, 897 bool power_on) 898{ 899 uint32_t power_gate = power_on ? 0 : 1; 900 uint32_t pwr_status = power_on ? PGFSM_POWER_ON : PGFSM_POWER_OFF; 901 902 if (hws->ctx->dc->debug.disable_dpp_power_gate) 903 return; 904 if (REG(DOMAIN1_PG_CONFIG) == 0) 905 return; 906 907 switch (dpp_inst) { 908 case 0: /* DPP0 */ 909 REG_UPDATE(DOMAIN1_PG_CONFIG, 910 DOMAIN1_POWER_GATE, power_gate); 911 912 REG_WAIT(DOMAIN1_PG_STATUS, 913 DOMAIN1_PGFSM_PWR_STATUS, pwr_status, 914 1, 1000); 915 break; 916 case 1: /* DPP1 */ 917 REG_UPDATE(DOMAIN3_PG_CONFIG, 918 DOMAIN3_POWER_GATE, power_gate); 919 920 REG_WAIT(DOMAIN3_PG_STATUS, 921 DOMAIN3_PGFSM_PWR_STATUS, pwr_status, 922 1, 1000); 923 break; 924 case 2: /* DPP2 */ 925 REG_UPDATE(DOMAIN5_PG_CONFIG, 926 DOMAIN5_POWER_GATE, power_gate); 927 928 REG_WAIT(DOMAIN5_PG_STATUS, 929 DOMAIN5_PGFSM_PWR_STATUS, pwr_status, 930 1, 1000); 931 break; 932 case 3: /* DPP3 */ 933 REG_UPDATE(DOMAIN7_PG_CONFIG, 934 DOMAIN7_POWER_GATE, power_gate); 935 936 REG_WAIT(DOMAIN7_PG_STATUS, 937 DOMAIN7_PGFSM_PWR_STATUS, pwr_status, 938 1, 1000); 939 break; 940 default: 941 BREAK_TO_DEBUGGER(); 942 break; 943 } 944} 945 946/** 947 * dcn10_hubp_pg_control - HUBP power gate control. 948 * 949 * @hws: dce_hwseq reference. 950 * @hubp_inst: DPP instance reference. 951 * @power_on: true if we want to enable power gate, false otherwise. 952 * 953 * Enable or disable power gate in the specific HUBP instance. 954 */ 955void dcn10_hubp_pg_control( 956 struct dce_hwseq *hws, 957 unsigned int hubp_inst, 958 bool power_on) 959{ 960 uint32_t power_gate = power_on ? 0 : 1; 961 uint32_t pwr_status = power_on ? PGFSM_POWER_ON : PGFSM_POWER_OFF; 962 963 if (hws->ctx->dc->debug.disable_hubp_power_gate) 964 return; 965 if (REG(DOMAIN0_PG_CONFIG) == 0) 966 return; 967 968 switch (hubp_inst) { 969 case 0: /* DCHUBP0 */ 970 REG_UPDATE(DOMAIN0_PG_CONFIG, 971 DOMAIN0_POWER_GATE, power_gate); 972 973 REG_WAIT(DOMAIN0_PG_STATUS, 974 DOMAIN0_PGFSM_PWR_STATUS, pwr_status, 975 1, 1000); 976 break; 977 case 1: /* DCHUBP1 */ 978 REG_UPDATE(DOMAIN2_PG_CONFIG, 979 DOMAIN2_POWER_GATE, power_gate); 980 981 REG_WAIT(DOMAIN2_PG_STATUS, 982 DOMAIN2_PGFSM_PWR_STATUS, pwr_status, 983 1, 1000); 984 break; 985 case 2: /* DCHUBP2 */ 986 REG_UPDATE(DOMAIN4_PG_CONFIG, 987 DOMAIN4_POWER_GATE, power_gate); 988 989 REG_WAIT(DOMAIN4_PG_STATUS, 990 DOMAIN4_PGFSM_PWR_STATUS, pwr_status, 991 1, 1000); 992 break; 993 case 3: /* DCHUBP3 */ 994 REG_UPDATE(DOMAIN6_PG_CONFIG, 995 DOMAIN6_POWER_GATE, power_gate); 996 997 REG_WAIT(DOMAIN6_PG_STATUS, 998 DOMAIN6_PGFSM_PWR_STATUS, pwr_status, 999 1, 1000); 1000 break; 1001 default: 1002 BREAK_TO_DEBUGGER(); 1003 break; 1004 } 1005} 1006 1007static void power_on_plane_resources( 1008 struct dce_hwseq *hws, 1009 int plane_id) 1010{ 1011 DC_LOGGER_INIT(hws->ctx->logger); 1012 1013 if (hws->funcs.dpp_root_clock_control) 1014 hws->funcs.dpp_root_clock_control(hws, plane_id, true); 1015 1016 if (REG(DC_IP_REQUEST_CNTL)) { 1017 REG_SET(DC_IP_REQUEST_CNTL, 0, 1018 IP_REQUEST_EN, 1); 1019 1020 if (hws->funcs.dpp_pg_control) 1021 hws->funcs.dpp_pg_control(hws, plane_id, true); 1022 1023 if (hws->funcs.hubp_pg_control) 1024 hws->funcs.hubp_pg_control(hws, plane_id, true); 1025 1026 REG_SET(DC_IP_REQUEST_CNTL, 0, 1027 IP_REQUEST_EN, 0); 1028 DC_LOG_DEBUG( 1029 "Un-gated front end for pipe %d\n", plane_id); 1030 } 1031} 1032 1033static void undo_DEGVIDCN10_253_wa(struct dc *dc) 1034{ 1035 struct dce_hwseq *hws = dc->hwseq; 1036 struct hubp *hubp = dc->res_pool->hubps[0]; 1037 1038 if (!hws->wa_state.DEGVIDCN10_253_applied) 1039 return; 1040 1041 hubp->funcs->set_blank(hubp, true); 1042 1043 REG_SET(DC_IP_REQUEST_CNTL, 0, 1044 IP_REQUEST_EN, 1); 1045 1046 hws->funcs.hubp_pg_control(hws, 0, false); 1047 REG_SET(DC_IP_REQUEST_CNTL, 0, 1048 IP_REQUEST_EN, 0); 1049 1050 hws->wa_state.DEGVIDCN10_253_applied = false; 1051} 1052 1053static void apply_DEGVIDCN10_253_wa(struct dc *dc) 1054{ 1055 struct dce_hwseq *hws = dc->hwseq; 1056 struct hubp *hubp = dc->res_pool->hubps[0]; 1057 int i; 1058 1059 if (dc->debug.disable_stutter) 1060 return; 1061 1062 if (!hws->wa.DEGVIDCN10_253) 1063 return; 1064 1065 for (i = 0; i < dc->res_pool->pipe_count; i++) { 1066 if (!dc->res_pool->hubps[i]->power_gated) 1067 return; 1068 } 1069 1070 /* all pipe power gated, apply work around to enable stutter. */ 1071 1072 REG_SET(DC_IP_REQUEST_CNTL, 0, 1073 IP_REQUEST_EN, 1); 1074 1075 hws->funcs.hubp_pg_control(hws, 0, true); 1076 REG_SET(DC_IP_REQUEST_CNTL, 0, 1077 IP_REQUEST_EN, 0); 1078 1079 hubp->funcs->set_hubp_blank_en(hubp, false); 1080 hws->wa_state.DEGVIDCN10_253_applied = true; 1081} 1082 1083void dcn10_bios_golden_init(struct dc *dc) 1084{ 1085 struct dce_hwseq *hws = dc->hwseq; 1086 struct dc_bios *bp = dc->ctx->dc_bios; 1087 int i; 1088 bool allow_self_fresh_force_enable = true; 1089 1090 if (hws->funcs.s0i3_golden_init_wa && hws->funcs.s0i3_golden_init_wa(dc)) 1091 return; 1092 1093 if (dc->res_pool->hubbub->funcs->is_allow_self_refresh_enabled) 1094 allow_self_fresh_force_enable = 1095 dc->res_pool->hubbub->funcs->is_allow_self_refresh_enabled(dc->res_pool->hubbub); 1096 1097 1098 /* WA for making DF sleep when idle after resume from S0i3. 1099 * DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE is set to 1 by 1100 * command table, if DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE = 0 1101 * before calling command table and it changed to 1 after, 1102 * it should be set back to 0. 1103 */ 1104 1105 /* initialize dcn global */ 1106 bp->funcs->enable_disp_power_gating(bp, 1107 CONTROLLER_ID_D0, ASIC_PIPE_INIT); 1108 1109 for (i = 0; i < dc->res_pool->pipe_count; i++) { 1110 /* initialize dcn per pipe */ 1111 bp->funcs->enable_disp_power_gating(bp, 1112 CONTROLLER_ID_D0 + i, ASIC_PIPE_DISABLE); 1113 } 1114 1115 if (dc->res_pool->hubbub->funcs->allow_self_refresh_control) 1116 if (allow_self_fresh_force_enable == false && 1117 dc->res_pool->hubbub->funcs->is_allow_self_refresh_enabled(dc->res_pool->hubbub)) 1118 dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub, 1119 !dc->res_pool->hubbub->ctx->dc->debug.disable_stutter); 1120 1121} 1122 1123static void false_optc_underflow_wa( 1124 struct dc *dc, 1125 const struct dc_stream_state *stream, 1126 struct timing_generator *tg) 1127{ 1128 int i; 1129 bool underflow; 1130 1131 if (!dc->hwseq->wa.false_optc_underflow) 1132 return; 1133 1134 underflow = tg->funcs->is_optc_underflow_occurred(tg); 1135 1136 for (i = 0; i < dc->res_pool->pipe_count; i++) { 1137 struct pipe_ctx *old_pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i]; 1138 1139 if (old_pipe_ctx->stream != stream) 1140 continue; 1141 1142 dc->hwss.wait_for_mpcc_disconnect(dc, dc->res_pool, old_pipe_ctx); 1143 } 1144 1145 if (tg->funcs->set_blank_data_double_buffer) 1146 tg->funcs->set_blank_data_double_buffer(tg, true); 1147 1148 if (tg->funcs->is_optc_underflow_occurred(tg) && !underflow) 1149 tg->funcs->clear_optc_underflow(tg); 1150} 1151 1152static int calculate_vready_offset_for_group(struct pipe_ctx *pipe) 1153{ 1154 struct pipe_ctx *other_pipe; 1155 int vready_offset = pipe->pipe_dlg_param.vready_offset; 1156 1157 /* Always use the largest vready_offset of all connected pipes */ 1158 for (other_pipe = pipe->bottom_pipe; other_pipe != NULL; other_pipe = other_pipe->bottom_pipe) { 1159 if (other_pipe->pipe_dlg_param.vready_offset > vready_offset) 1160 vready_offset = other_pipe->pipe_dlg_param.vready_offset; 1161 } 1162 for (other_pipe = pipe->top_pipe; other_pipe != NULL; other_pipe = other_pipe->top_pipe) { 1163 if (other_pipe->pipe_dlg_param.vready_offset > vready_offset) 1164 vready_offset = other_pipe->pipe_dlg_param.vready_offset; 1165 } 1166 for (other_pipe = pipe->next_odm_pipe; other_pipe != NULL; other_pipe = other_pipe->next_odm_pipe) { 1167 if (other_pipe->pipe_dlg_param.vready_offset > vready_offset) 1168 vready_offset = other_pipe->pipe_dlg_param.vready_offset; 1169 } 1170 for (other_pipe = pipe->prev_odm_pipe; other_pipe != NULL; other_pipe = other_pipe->prev_odm_pipe) { 1171 if (other_pipe->pipe_dlg_param.vready_offset > vready_offset) 1172 vready_offset = other_pipe->pipe_dlg_param.vready_offset; 1173 } 1174 1175 return vready_offset; 1176} 1177 1178enum dc_status dcn10_enable_stream_timing( 1179 struct pipe_ctx *pipe_ctx, 1180 struct dc_state *context, 1181 struct dc *dc) 1182{ 1183 struct dc_stream_state *stream = pipe_ctx->stream; 1184 enum dc_color_space color_space; 1185 struct tg_color black_color = {0}; 1186 1187 /* by upper caller loop, pipe0 is parent pipe and be called first. 1188 * back end is set up by for pipe0. Other children pipe share back end 1189 * with pipe 0. No program is needed. 1190 */ 1191 if (pipe_ctx->top_pipe != NULL) 1192 return DC_OK; 1193 1194 /* TODO check if timing_changed, disable stream if timing changed */ 1195 1196 /* HW program guide assume display already disable 1197 * by unplug sequence. OTG assume stop. 1198 */ 1199 pipe_ctx->stream_res.tg->funcs->enable_optc_clock(pipe_ctx->stream_res.tg, true); 1200 1201 if (false == pipe_ctx->clock_source->funcs->program_pix_clk( 1202 pipe_ctx->clock_source, 1203 &pipe_ctx->stream_res.pix_clk_params, 1204 dc->link_srv->dp_get_encoding_format(&pipe_ctx->link_config.dp_link_settings), 1205 &pipe_ctx->pll_settings)) { 1206 BREAK_TO_DEBUGGER(); 1207 return DC_ERROR_UNEXPECTED; 1208 } 1209 1210 if (dc_is_hdmi_tmds_signal(stream->signal)) { 1211 stream->link->phy_state.symclk_ref_cnts.otg = 1; 1212 if (stream->link->phy_state.symclk_state == SYMCLK_OFF_TX_OFF) 1213 stream->link->phy_state.symclk_state = SYMCLK_ON_TX_OFF; 1214 else 1215 stream->link->phy_state.symclk_state = SYMCLK_ON_TX_ON; 1216 } 1217 1218 pipe_ctx->stream_res.tg->funcs->program_timing( 1219 pipe_ctx->stream_res.tg, 1220 &stream->timing, 1221 calculate_vready_offset_for_group(pipe_ctx), 1222 pipe_ctx->pipe_dlg_param.vstartup_start, 1223 pipe_ctx->pipe_dlg_param.vupdate_offset, 1224 pipe_ctx->pipe_dlg_param.vupdate_width, 1225 pipe_ctx->pipe_dlg_param.pstate_keepout, 1226 pipe_ctx->stream->signal, 1227 true); 1228 1229#if 0 /* move to after enable_crtc */ 1230 /* TODO: OPP FMT, ABM. etc. should be done here. */ 1231 /* or FPGA now. instance 0 only. TODO: move to opp.c */ 1232 1233 inst_offset = reg_offsets[pipe_ctx->stream_res.tg->inst].fmt; 1234 1235 pipe_ctx->stream_res.opp->funcs->opp_program_fmt( 1236 pipe_ctx->stream_res.opp, 1237 &stream->bit_depth_params, 1238 &stream->clamping); 1239#endif 1240 /* program otg blank color */ 1241 color_space = stream->output_color_space; 1242 color_space_to_black_color(dc, color_space, &black_color); 1243 1244 /* 1245 * The way 420 is packed, 2 channels carry Y component, 1 channel 1246 * alternate between Cb and Cr, so both channels need the pixel 1247 * value for Y 1248 */ 1249 if (stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR420) 1250 black_color.color_r_cr = black_color.color_g_y; 1251 1252 if (pipe_ctx->stream_res.tg->funcs->set_blank_color) 1253 pipe_ctx->stream_res.tg->funcs->set_blank_color( 1254 pipe_ctx->stream_res.tg, 1255 &black_color); 1256 1257 if (pipe_ctx->stream_res.tg->funcs->is_blanked && 1258 !pipe_ctx->stream_res.tg->funcs->is_blanked(pipe_ctx->stream_res.tg)) { 1259 pipe_ctx->stream_res.tg->funcs->set_blank(pipe_ctx->stream_res.tg, true); 1260 hwss_wait_for_blank_complete(pipe_ctx->stream_res.tg); 1261 false_optc_underflow_wa(dc, pipe_ctx->stream, pipe_ctx->stream_res.tg); 1262 } 1263 1264 /* VTG is within DCHUB command block. DCFCLK is always on */ 1265 if (false == pipe_ctx->stream_res.tg->funcs->enable_crtc(pipe_ctx->stream_res.tg)) { 1266 BREAK_TO_DEBUGGER(); 1267 return DC_ERROR_UNEXPECTED; 1268 } 1269 1270 /* TODO program crtc source select for non-virtual signal*/ 1271 /* TODO program FMT */ 1272 /* TODO setup link_enc */ 1273 /* TODO set stream attributes */ 1274 /* TODO program audio */ 1275 /* TODO enable stream if timing changed */ 1276 /* TODO unblank stream if DP */ 1277 1278 return DC_OK; 1279} 1280 1281static void dcn10_reset_back_end_for_pipe( 1282 struct dc *dc, 1283 struct pipe_ctx *pipe_ctx, 1284 struct dc_state *context) 1285{ 1286 int i; 1287 struct dc_link *link; 1288 DC_LOGGER_INIT(dc->ctx->logger); 1289 if (pipe_ctx->stream_res.stream_enc == NULL) { 1290 pipe_ctx->stream = NULL; 1291 return; 1292 } 1293 1294 link = pipe_ctx->stream->link; 1295 /* DPMS may already disable or */ 1296 /* dpms_off status is incorrect due to fastboot 1297 * feature. When system resume from S4 with second 1298 * screen only, the dpms_off would be true but 1299 * VBIOS lit up eDP, so check link status too. 1300 */ 1301 if (!pipe_ctx->stream->dpms_off || link->link_status.link_active) 1302 dc->link_srv->set_dpms_off(pipe_ctx); 1303 else if (pipe_ctx->stream_res.audio) 1304 dc->hwss.disable_audio_stream(pipe_ctx); 1305 1306 if (pipe_ctx->stream_res.audio) { 1307 /*disable az_endpoint*/ 1308 pipe_ctx->stream_res.audio->funcs->az_disable(pipe_ctx->stream_res.audio); 1309 1310 /*free audio*/ 1311 if (dc->caps.dynamic_audio == true) { 1312 /*we have to dynamic arbitrate the audio endpoints*/ 1313 /*we free the resource, need reset is_audio_acquired*/ 1314 update_audio_usage(&dc->current_state->res_ctx, dc->res_pool, 1315 pipe_ctx->stream_res.audio, false); 1316 pipe_ctx->stream_res.audio = NULL; 1317 } 1318 } 1319 1320 /* by upper caller loop, parent pipe: pipe0, will be reset last. 1321 * back end share by all pipes and will be disable only when disable 1322 * parent pipe. 1323 */ 1324 if (pipe_ctx->top_pipe == NULL) { 1325 1326 if (pipe_ctx->stream_res.abm) 1327 dc->hwss.set_abm_immediate_disable(pipe_ctx); 1328 1329 pipe_ctx->stream_res.tg->funcs->disable_crtc(pipe_ctx->stream_res.tg); 1330 1331 pipe_ctx->stream_res.tg->funcs->enable_optc_clock(pipe_ctx->stream_res.tg, false); 1332 set_drr_and_clear_adjust_pending(pipe_ctx, pipe_ctx->stream, NULL); 1333 if (dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal)) 1334 pipe_ctx->stream->link->phy_state.symclk_ref_cnts.otg = 0; 1335 } 1336 1337 for (i = 0; i < dc->res_pool->pipe_count; i++) 1338 if (&dc->current_state->res_ctx.pipe_ctx[i] == pipe_ctx) 1339 break; 1340 1341 if (i == dc->res_pool->pipe_count) 1342 return; 1343 1344 pipe_ctx->stream = NULL; 1345 DC_LOG_DEBUG("Reset back end for pipe %d, tg:%d\n", 1346 pipe_ctx->pipe_idx, pipe_ctx->stream_res.tg->inst); 1347} 1348 1349static bool dcn10_hw_wa_force_recovery(struct dc *dc) 1350{ 1351 struct hubp *hubp ; 1352 unsigned int i; 1353 1354 if (!dc->debug.recovery_enabled) 1355 return false; 1356 /* 1357 DCHUBP_CNTL:HUBP_BLANK_EN=1 1358 DCHUBBUB_SOFT_RESET:DCHUBBUB_GLOBAL_SOFT_RESET=1 1359 DCHUBP_CNTL:HUBP_DISABLE=1 1360 DCHUBP_CNTL:HUBP_DISABLE=0 1361 DCHUBBUB_SOFT_RESET:DCHUBBUB_GLOBAL_SOFT_RESET=0 1362 DCSURF_PRIMARY_SURFACE_ADDRESS 1363 DCHUBP_CNTL:HUBP_BLANK_EN=0 1364 */ 1365 1366 for (i = 0; i < dc->res_pool->pipe_count; i++) { 1367 struct pipe_ctx *pipe_ctx = 1368 &dc->current_state->res_ctx.pipe_ctx[i]; 1369 if (pipe_ctx != NULL) { 1370 hubp = pipe_ctx->plane_res.hubp; 1371 /*DCHUBP_CNTL:HUBP_BLANK_EN=1*/ 1372 if (hubp != NULL && hubp->funcs->set_hubp_blank_en) 1373 hubp->funcs->set_hubp_blank_en(hubp, true); 1374 } 1375 } 1376 /*DCHUBBUB_SOFT_RESET:DCHUBBUB_GLOBAL_SOFT_RESET=1*/ 1377 hubbub1_soft_reset(dc->res_pool->hubbub, true); 1378 1379 for (i = 0; i < dc->res_pool->pipe_count; i++) { 1380 struct pipe_ctx *pipe_ctx = 1381 &dc->current_state->res_ctx.pipe_ctx[i]; 1382 if (pipe_ctx != NULL) { 1383 hubp = pipe_ctx->plane_res.hubp; 1384 /*DCHUBP_CNTL:HUBP_DISABLE=1*/ 1385 if (hubp != NULL && hubp->funcs->hubp_disable_control) 1386 hubp->funcs->hubp_disable_control(hubp, true); 1387 } 1388 } 1389 for (i = 0; i < dc->res_pool->pipe_count; i++) { 1390 struct pipe_ctx *pipe_ctx = 1391 &dc->current_state->res_ctx.pipe_ctx[i]; 1392 if (pipe_ctx != NULL) { 1393 hubp = pipe_ctx->plane_res.hubp; 1394 /*DCHUBP_CNTL:HUBP_DISABLE=0*/ 1395 if (hubp != NULL && hubp->funcs->hubp_disable_control) 1396 hubp->funcs->hubp_disable_control(hubp, true); 1397 } 1398 } 1399 /*DCHUBBUB_SOFT_RESET:DCHUBBUB_GLOBAL_SOFT_RESET=0*/ 1400 hubbub1_soft_reset(dc->res_pool->hubbub, false); 1401 for (i = 0; i < dc->res_pool->pipe_count; i++) { 1402 struct pipe_ctx *pipe_ctx = 1403 &dc->current_state->res_ctx.pipe_ctx[i]; 1404 if (pipe_ctx != NULL) { 1405 hubp = pipe_ctx->plane_res.hubp; 1406 /*DCHUBP_CNTL:HUBP_BLANK_EN=0*/ 1407 if (hubp != NULL && hubp->funcs->set_hubp_blank_en) 1408 hubp->funcs->set_hubp_blank_en(hubp, true); 1409 } 1410 } 1411 return true; 1412 1413} 1414 1415void dcn10_verify_allow_pstate_change_high(struct dc *dc) 1416{ 1417 struct hubbub *hubbub = dc->res_pool->hubbub; 1418 static bool should_log_hw_state; /* prevent hw state log by default */ 1419 1420 if (!hubbub->funcs->verify_allow_pstate_change_high) 1421 return; 1422 1423 if (!hubbub->funcs->verify_allow_pstate_change_high(hubbub)) { 1424 int i = 0; 1425 1426 if (should_log_hw_state) 1427 dcn10_log_hw_state(dc, NULL); 1428 1429 TRACE_DC_PIPE_STATE(pipe_ctx, i, MAX_PIPES); 1430 BREAK_TO_DEBUGGER(); 1431 if (dcn10_hw_wa_force_recovery(dc)) { 1432 /*check again*/ 1433 if (!hubbub->funcs->verify_allow_pstate_change_high(hubbub)) 1434 BREAK_TO_DEBUGGER(); 1435 } 1436 } 1437} 1438 1439/* trigger HW to start disconnect plane from stream on the next vsync */ 1440void dcn10_plane_atomic_disconnect(struct dc *dc, 1441 struct dc_state *state, 1442 struct pipe_ctx *pipe_ctx) 1443{ 1444 struct dce_hwseq *hws = dc->hwseq; 1445 struct hubp *hubp = pipe_ctx->plane_res.hubp; 1446 int dpp_id = pipe_ctx->plane_res.dpp->inst; 1447 struct mpc *mpc = dc->res_pool->mpc; 1448 struct mpc_tree *mpc_tree_params; 1449 struct mpcc *mpcc_to_remove = NULL; 1450 struct output_pixel_processor *opp = pipe_ctx->stream_res.opp; 1451 1452 mpc_tree_params = &(opp->mpc_tree_params); 1453 mpcc_to_remove = mpc->funcs->get_mpcc_for_dpp(mpc_tree_params, dpp_id); 1454 1455 /*Already reset*/ 1456 if (mpcc_to_remove == NULL) 1457 return; 1458 1459 mpc->funcs->remove_mpcc(mpc, mpc_tree_params, mpcc_to_remove); 1460 // Phantom pipes have OTG disabled by default, so MPCC_STATUS will never assert idle, 1461 // so don't wait for MPCC_IDLE in the programming sequence 1462 if (dc_state_get_pipe_subvp_type(state, pipe_ctx) != SUBVP_PHANTOM) 1463 opp->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true; 1464 1465 dc->optimized_required = true; 1466 1467 if (hubp->funcs->hubp_disconnect) 1468 hubp->funcs->hubp_disconnect(hubp); 1469 1470 if (dc->debug.sanity_checks) 1471 hws->funcs.verify_allow_pstate_change_high(dc); 1472} 1473 1474/** 1475 * dcn10_plane_atomic_power_down - Power down plane components. 1476 * 1477 * @dc: dc struct reference. used for grab hwseq. 1478 * @dpp: dpp struct reference. 1479 * @hubp: hubp struct reference. 1480 * 1481 * Keep in mind that this operation requires a power gate configuration; 1482 * however, requests for switch power gate are precisely controlled to avoid 1483 * problems. For this reason, power gate request is usually disabled. This 1484 * function first needs to enable the power gate request before disabling DPP 1485 * and HUBP. Finally, it disables the power gate request again. 1486 */ 1487void dcn10_plane_atomic_power_down(struct dc *dc, 1488 struct dpp *dpp, 1489 struct hubp *hubp) 1490{ 1491 struct dce_hwseq *hws = dc->hwseq; 1492 DC_LOGGER_INIT(dc->ctx->logger); 1493 1494 if (REG(DC_IP_REQUEST_CNTL)) { 1495 REG_SET(DC_IP_REQUEST_CNTL, 0, 1496 IP_REQUEST_EN, 1); 1497 1498 if (hws->funcs.dpp_pg_control) 1499 hws->funcs.dpp_pg_control(hws, dpp->inst, false); 1500 1501 if (hws->funcs.hubp_pg_control) 1502 hws->funcs.hubp_pg_control(hws, hubp->inst, false); 1503 1504 hubp->funcs->hubp_reset(hubp); 1505 dpp->funcs->dpp_reset(dpp); 1506 1507 REG_SET(DC_IP_REQUEST_CNTL, 0, 1508 IP_REQUEST_EN, 0); 1509 DC_LOG_DEBUG( 1510 "Power gated front end %d\n", hubp->inst); 1511 } 1512 1513 if (hws->funcs.dpp_root_clock_control) 1514 hws->funcs.dpp_root_clock_control(hws, dpp->inst, false); 1515} 1516 1517/* disable HW used by plane. 1518 * note: cannot disable until disconnect is complete 1519 */ 1520void dcn10_plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx) 1521{ 1522 struct dce_hwseq *hws = dc->hwseq; 1523 struct hubp *hubp = pipe_ctx->plane_res.hubp; 1524 struct dpp *dpp = pipe_ctx->plane_res.dpp; 1525 int opp_id = hubp->opp_id; 1526 1527 dc->hwss.wait_for_mpcc_disconnect(dc, dc->res_pool, pipe_ctx); 1528 1529 hubp->funcs->hubp_clk_cntl(hubp, false); 1530 1531 dpp->funcs->dpp_dppclk_control(dpp, false, false); 1532 1533 if (opp_id != 0xf && pipe_ctx->stream_res.opp->mpc_tree_params.opp_list == NULL) 1534 pipe_ctx->stream_res.opp->funcs->opp_pipe_clock_control( 1535 pipe_ctx->stream_res.opp, 1536 false); 1537 1538 hubp->power_gated = true; 1539 dc->optimized_required = false; /* We're powering off, no need to optimize */ 1540 1541 hws->funcs.plane_atomic_power_down(dc, 1542 pipe_ctx->plane_res.dpp, 1543 pipe_ctx->plane_res.hubp); 1544 1545 pipe_ctx->stream = NULL; 1546 memset(&pipe_ctx->stream_res, 0, sizeof(pipe_ctx->stream_res)); 1547 memset(&pipe_ctx->plane_res, 0, sizeof(pipe_ctx->plane_res)); 1548 pipe_ctx->top_pipe = NULL; 1549 pipe_ctx->bottom_pipe = NULL; 1550 pipe_ctx->plane_state = NULL; 1551} 1552 1553void dcn10_disable_plane(struct dc *dc, struct dc_state *state, struct pipe_ctx *pipe_ctx) 1554{ 1555 struct dce_hwseq *hws = dc->hwseq; 1556 DC_LOGGER_INIT(dc->ctx->logger); 1557 1558 if (!pipe_ctx->plane_res.hubp || pipe_ctx->plane_res.hubp->power_gated) 1559 return; 1560 1561 hws->funcs.plane_atomic_disable(dc, pipe_ctx); 1562 1563 apply_DEGVIDCN10_253_wa(dc); 1564 1565 DC_LOG_DC("Power down front end %d\n", 1566 pipe_ctx->pipe_idx); 1567} 1568 1569void dcn10_init_pipes(struct dc *dc, struct dc_state *context) 1570{ 1571 int i; 1572 struct dce_hwseq *hws = dc->hwseq; 1573 struct hubbub *hubbub = dc->res_pool->hubbub; 1574 bool can_apply_seamless_boot = false; 1575 bool tg_enabled[MAX_PIPES] = {false}; 1576 1577 for (i = 0; i < context->stream_count; i++) { 1578 if (context->streams[i]->apply_seamless_boot_optimization) { 1579 can_apply_seamless_boot = true; 1580 break; 1581 } 1582 } 1583 1584 for (i = 0; i < dc->res_pool->pipe_count; i++) { 1585 struct timing_generator *tg = dc->res_pool->timing_generators[i]; 1586 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; 1587 1588 /* There is assumption that pipe_ctx is not mapping irregularly 1589 * to non-preferred front end. If pipe_ctx->stream is not NULL, 1590 * we will use the pipe, so don't disable 1591 */ 1592 if (pipe_ctx->stream != NULL && can_apply_seamless_boot) 1593 continue; 1594 1595 /* Blank controller using driver code instead of 1596 * command table. 1597 */ 1598 if (tg->funcs->is_tg_enabled(tg)) { 1599 if (hws->funcs.init_blank != NULL) { 1600 hws->funcs.init_blank(dc, tg); 1601 tg->funcs->lock(tg); 1602 } else { 1603 tg->funcs->lock(tg); 1604 tg->funcs->set_blank(tg, true); 1605 hwss_wait_for_blank_complete(tg); 1606 } 1607 } 1608 } 1609 1610 /* Reset det size */ 1611 for (i = 0; i < dc->res_pool->pipe_count; i++) { 1612 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; 1613 struct hubp *hubp = dc->res_pool->hubps[i]; 1614 1615 /* Do not need to reset for seamless boot */ 1616 if (pipe_ctx->stream != NULL && can_apply_seamless_boot) 1617 continue; 1618 1619 if (hubbub && hubp) { 1620 if (hubbub->funcs->program_det_size) 1621 hubbub->funcs->program_det_size(hubbub, hubp->inst, 0); 1622 if (hubbub->funcs->program_det_segments) 1623 hubbub->funcs->program_det_segments(hubbub, hubp->inst, 0); 1624 } 1625 } 1626 1627 /* num_opp will be equal to number of mpcc */ 1628 for (i = 0; i < dc->res_pool->res_cap->num_opp; i++) { 1629 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; 1630 1631 /* Cannot reset the MPC mux if seamless boot */ 1632 if (pipe_ctx->stream != NULL && can_apply_seamless_boot) 1633 continue; 1634 1635 dc->res_pool->mpc->funcs->mpc_init_single_inst( 1636 dc->res_pool->mpc, i); 1637 } 1638 1639 for (i = 0; i < dc->res_pool->pipe_count; i++) { 1640 struct timing_generator *tg = dc->res_pool->timing_generators[i]; 1641 struct hubp *hubp = dc->res_pool->hubps[i]; 1642 struct dpp *dpp = dc->res_pool->dpps[i]; 1643 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; 1644 1645 /* There is assumption that pipe_ctx is not mapping irregularly 1646 * to non-preferred front end. If pipe_ctx->stream is not NULL, 1647 * we will use the pipe, so don't disable 1648 */ 1649 if (can_apply_seamless_boot && 1650 pipe_ctx->stream != NULL && 1651 pipe_ctx->stream_res.tg->funcs->is_tg_enabled( 1652 pipe_ctx->stream_res.tg)) { 1653 // Enable double buffering for OTG_BLANK no matter if 1654 // seamless boot is enabled or not to suppress global sync 1655 // signals when OTG blanked. This is to prevent pipe from 1656 // requesting data while in PSR. 1657 tg->funcs->tg_init(tg); 1658 hubp->power_gated = true; 1659 tg_enabled[i] = true; 1660 continue; 1661 } 1662 1663 /* Disable on the current state so the new one isn't cleared. */ 1664 pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i]; 1665 1666 hubp->funcs->hubp_reset(hubp); 1667 dpp->funcs->dpp_reset(dpp); 1668 1669 pipe_ctx->stream_res.tg = tg; 1670 pipe_ctx->pipe_idx = i; 1671 1672 pipe_ctx->plane_res.hubp = hubp; 1673 pipe_ctx->plane_res.dpp = dpp; 1674 pipe_ctx->plane_res.mpcc_inst = dpp->inst; 1675 hubp->mpcc_id = dpp->inst; 1676 hubp->opp_id = OPP_ID_INVALID; 1677 hubp->power_gated = false; 1678 1679 dc->res_pool->opps[i]->mpc_tree_params.opp_id = dc->res_pool->opps[i]->inst; 1680 dc->res_pool->opps[i]->mpc_tree_params.opp_list = NULL; 1681 dc->res_pool->opps[i]->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true; 1682 pipe_ctx->stream_res.opp = dc->res_pool->opps[i]; 1683 1684 hws->funcs.plane_atomic_disconnect(dc, context, pipe_ctx); 1685 1686 if (tg->funcs->is_tg_enabled(tg)) 1687 tg->funcs->unlock(tg); 1688 1689 dc->hwss.disable_plane(dc, context, pipe_ctx); 1690 1691 pipe_ctx->stream_res.tg = NULL; 1692 pipe_ctx->plane_res.hubp = NULL; 1693 1694 if (tg->funcs->is_tg_enabled(tg)) { 1695 if (tg->funcs->init_odm) 1696 tg->funcs->init_odm(tg); 1697 } 1698 1699 tg->funcs->tg_init(tg); 1700 } 1701 1702 /* Clean up MPC tree */ 1703 for (i = 0; i < dc->res_pool->pipe_count; i++) { 1704 if (tg_enabled[i]) { 1705 if (dc->res_pool->opps[i]->mpc_tree_params.opp_list) { 1706 if (dc->res_pool->opps[i]->mpc_tree_params.opp_list->mpcc_bot) { 1707 int bot_id = dc->res_pool->opps[i]->mpc_tree_params.opp_list->mpcc_bot->mpcc_id; 1708 1709 if ((bot_id < MAX_MPCC) && (bot_id < MAX_PIPES) && (!tg_enabled[bot_id])) 1710 dc->res_pool->opps[i]->mpc_tree_params.opp_list = NULL; 1711 } 1712 } 1713 } 1714 } 1715 1716 /* Power gate DSCs */ 1717 if (hws->funcs.dsc_pg_control != NULL) { 1718 uint32_t num_opps = 0; 1719 uint32_t opp_id_src0 = OPP_ID_INVALID; 1720 uint32_t opp_id_src1 = OPP_ID_INVALID; 1721 1722 // Step 1: To find out which OPTC is running & OPTC DSC is ON 1723 // We can't use res_pool->res_cap->num_timing_generator to check 1724 // Because it records display pipes default setting built in driver, 1725 // not display pipes of the current chip. 1726 // Some ASICs would be fused display pipes less than the default setting. 1727 // In dcnxx_resource_construct function, driver would obatin real information. 1728 for (i = 0; i < dc->res_pool->timing_generator_count; i++) { 1729 uint32_t optc_dsc_state = 0; 1730 struct timing_generator *tg = dc->res_pool->timing_generators[i]; 1731 1732 if (tg->funcs->is_tg_enabled(tg)) { 1733 if (tg->funcs->get_dsc_status) 1734 tg->funcs->get_dsc_status(tg, &optc_dsc_state); 1735 // Only one OPTC with DSC is ON, so if we got one result, we would exit this block. 1736 // non-zero value is DSC enabled 1737 if (optc_dsc_state != 0) { 1738 tg->funcs->get_optc_source(tg, &num_opps, &opp_id_src0, &opp_id_src1); 1739 break; 1740 } 1741 } 1742 } 1743 1744 // Step 2: To power down DSC but skip DSC of running OPTC 1745 for (i = 0; i < dc->res_pool->res_cap->num_dsc; i++) { 1746 struct dcn_dsc_state s = {0}; 1747 1748 dc->res_pool->dscs[i]->funcs->dsc_read_state(dc->res_pool->dscs[i], &s); 1749 1750 if ((s.dsc_opp_source == opp_id_src0 || s.dsc_opp_source == opp_id_src1) && 1751 s.dsc_clock_en && s.dsc_fw_en) 1752 continue; 1753 1754 hws->funcs.dsc_pg_control(hws, dc->res_pool->dscs[i]->inst, false); 1755 } 1756 } 1757} 1758 1759void dcn10_init_hw(struct dc *dc) 1760{ 1761 int i; 1762 struct abm *abm = dc->res_pool->abm; 1763 struct dmcu *dmcu = dc->res_pool->dmcu; 1764 struct dce_hwseq *hws = dc->hwseq; 1765 struct dc_bios *dcb = dc->ctx->dc_bios; 1766 struct resource_pool *res_pool = dc->res_pool; 1767 uint32_t backlight = MAX_BACKLIGHT_LEVEL; 1768 uint32_t user_level = MAX_BACKLIGHT_LEVEL; 1769 bool is_optimized_init_done = false; 1770 1771 if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks) 1772 dc->clk_mgr->funcs->init_clocks(dc->clk_mgr); 1773 1774 /* Align bw context with hw config when system resume. */ 1775 if (dc->clk_mgr && dc->clk_mgr->clks.dispclk_khz != 0 && dc->clk_mgr->clks.dppclk_khz != 0) { 1776 dc->current_state->bw_ctx.bw.dcn.clk.dispclk_khz = dc->clk_mgr->clks.dispclk_khz; 1777 dc->current_state->bw_ctx.bw.dcn.clk.dppclk_khz = dc->clk_mgr->clks.dppclk_khz; 1778 } 1779 1780 // Initialize the dccg 1781 if (dc->res_pool->dccg && dc->res_pool->dccg->funcs->dccg_init) 1782 dc->res_pool->dccg->funcs->dccg_init(res_pool->dccg); 1783 1784 if (!dcb->funcs->is_accelerated_mode(dcb)) 1785 hws->funcs.disable_vga(dc->hwseq); 1786 1787 if (!dc_dmub_srv_optimized_init_done(dc->ctx->dmub_srv)) 1788 hws->funcs.bios_golden_init(dc); 1789 1790 1791 if (dc->ctx->dc_bios->fw_info_valid) { 1792 res_pool->ref_clocks.xtalin_clock_inKhz = 1793 dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency; 1794 1795 if (res_pool->dccg && res_pool->hubbub) { 1796 1797 (res_pool->dccg->funcs->get_dccg_ref_freq)(res_pool->dccg, 1798 dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency, 1799 &res_pool->ref_clocks.dccg_ref_clock_inKhz); 1800 1801 (res_pool->hubbub->funcs->get_dchub_ref_freq)(res_pool->hubbub, 1802 res_pool->ref_clocks.dccg_ref_clock_inKhz, 1803 &res_pool->ref_clocks.dchub_ref_clock_inKhz); 1804 } else { 1805 // Not all ASICs have DCCG sw component 1806 res_pool->ref_clocks.dccg_ref_clock_inKhz = 1807 res_pool->ref_clocks.xtalin_clock_inKhz; 1808 res_pool->ref_clocks.dchub_ref_clock_inKhz = 1809 res_pool->ref_clocks.xtalin_clock_inKhz; 1810 } 1811 } else 1812 ASSERT_CRITICAL(false); 1813 1814 for (i = 0; i < dc->link_count; i++) { 1815 /* Power up AND update implementation according to the 1816 * required signal (which may be different from the 1817 * default signal on connector). 1818 */ 1819 struct dc_link *link = dc->links[i]; 1820 1821 if (!is_optimized_init_done) 1822 link->link_enc->funcs->hw_init(link->link_enc); 1823 1824 /* Check for enabled DIG to identify enabled display */ 1825 if (link->link_enc->funcs->is_dig_enabled && 1826 link->link_enc->funcs->is_dig_enabled(link->link_enc)) { 1827 link->link_status.link_active = true; 1828 if (link->link_enc->funcs->fec_is_active && 1829 link->link_enc->funcs->fec_is_active(link->link_enc)) 1830 link->fec_state = dc_link_fec_enabled; 1831 } 1832 } 1833 1834 /* we want to turn off all dp displays before doing detection */ 1835 dc->link_srv->blank_all_dp_displays(dc); 1836 1837 if (hws->funcs.enable_power_gating_plane) 1838 hws->funcs.enable_power_gating_plane(dc->hwseq, true); 1839 1840 /* If taking control over from VBIOS, we may want to optimize our first 1841 * mode set, so we need to skip powering down pipes until we know which 1842 * pipes we want to use. 1843 * Otherwise, if taking control is not possible, we need to power 1844 * everything down. 1845 */ 1846 if (dcb->funcs->is_accelerated_mode(dcb) || !dc->config.seamless_boot_edp_requested) { 1847 if (!is_optimized_init_done) { 1848 hws->funcs.init_pipes(dc, dc->current_state); 1849 if (dc->res_pool->hubbub->funcs->allow_self_refresh_control) 1850 dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub, 1851 !dc->res_pool->hubbub->ctx->dc->debug.disable_stutter); 1852 } 1853 } 1854 1855 if (!is_optimized_init_done) { 1856 1857 for (i = 0; i < res_pool->audio_count; i++) { 1858 struct audio *audio = res_pool->audios[i]; 1859 1860 audio->funcs->hw_init(audio); 1861 } 1862 1863 for (i = 0; i < dc->link_count; i++) { 1864 struct dc_link *link = dc->links[i]; 1865 1866 if (link->panel_cntl) { 1867 backlight = link->panel_cntl->funcs->hw_init(link->panel_cntl); 1868 user_level = link->panel_cntl->stored_backlight_registers.USER_LEVEL; 1869 } 1870 } 1871 1872 if (abm != NULL) 1873 abm->funcs->abm_init(abm, backlight, user_level); 1874 1875 if (dmcu != NULL && !dmcu->auto_load_dmcu) 1876 dmcu->funcs->dmcu_init(dmcu); 1877 } 1878 1879 if (abm != NULL && dmcu != NULL) 1880 abm->dmcu_is_running = dmcu->funcs->is_dmcu_initialized(dmcu); 1881 1882 /* power AFMT HDMI memory TODO: may move to dis/en output save power*/ 1883 if (!is_optimized_init_done) 1884 REG_WRITE(DIO_MEM_PWR_CTRL, 0); 1885 1886 if (!dc->debug.disable_clock_gate) { 1887 /* enable all DCN clock gating */ 1888 REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0); 1889 1890 REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0); 1891 1892 REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0); 1893 } 1894 1895 if (dc->clk_mgr && dc->clk_mgr->funcs->notify_wm_ranges) 1896 dc->clk_mgr->funcs->notify_wm_ranges(dc->clk_mgr); 1897} 1898 1899/* In headless boot cases, DIG may be turned 1900 * on which causes HW/SW discrepancies. 1901 * To avoid this, power down hardware on boot 1902 * if DIG is turned on 1903 */ 1904void dcn10_power_down_on_boot(struct dc *dc) 1905{ 1906 struct dc_link *edp_links[MAX_NUM_EDP]; 1907 struct dc_link *edp_link = NULL; 1908 int edp_num; 1909 int i = 0; 1910 1911 dc_get_edp_links(dc, edp_links, &edp_num); 1912 if (edp_num) 1913 edp_link = edp_links[0]; 1914 1915 if (edp_link && edp_link->link_enc->funcs->is_dig_enabled && 1916 edp_link->link_enc->funcs->is_dig_enabled(edp_link->link_enc) && 1917 dc->hwseq->funcs.edp_backlight_control && 1918 dc->hwseq->funcs.power_down && 1919 dc->hwss.edp_power_control) { 1920 dc->hwseq->funcs.edp_backlight_control(edp_link, false); 1921 dc->hwseq->funcs.power_down(dc); 1922 dc->hwss.edp_power_control(edp_link, false); 1923 } else { 1924 for (i = 0; i < dc->link_count; i++) { 1925 struct dc_link *link = dc->links[i]; 1926 1927 if (link->link_enc && link->link_enc->funcs->is_dig_enabled && 1928 link->link_enc->funcs->is_dig_enabled(link->link_enc) && 1929 dc->hwseq->funcs.power_down) { 1930 dc->hwseq->funcs.power_down(dc); 1931 break; 1932 } 1933 1934 } 1935 } 1936 1937 /* 1938 * Call update_clocks with empty context 1939 * to send DISPLAY_OFF 1940 * Otherwise DISPLAY_OFF may not be asserted 1941 */ 1942 if (dc->clk_mgr->funcs->set_low_power_state) 1943 dc->clk_mgr->funcs->set_low_power_state(dc->clk_mgr); 1944} 1945 1946void dcn10_reset_hw_ctx_wrap( 1947 struct dc *dc, 1948 struct dc_state *context) 1949{ 1950 int i; 1951 struct dce_hwseq *hws = dc->hwseq; 1952 1953 /* Reset Back End*/ 1954 for (i = dc->res_pool->pipe_count - 1; i >= 0 ; i--) { 1955 struct pipe_ctx *pipe_ctx_old = 1956 &dc->current_state->res_ctx.pipe_ctx[i]; 1957 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; 1958 1959 if (!pipe_ctx_old->stream) 1960 continue; 1961 1962 if (pipe_ctx_old->top_pipe) 1963 continue; 1964 1965 if (!pipe_ctx->stream || 1966 pipe_need_reprogram(pipe_ctx_old, pipe_ctx)) { 1967 struct clock_source *old_clk = pipe_ctx_old->clock_source; 1968 1969 dcn10_reset_back_end_for_pipe(dc, pipe_ctx_old, dc->current_state); 1970 if (hws->funcs.enable_stream_gating) 1971 hws->funcs.enable_stream_gating(dc, pipe_ctx_old); 1972 if (old_clk) 1973 old_clk->funcs->cs_power_down(old_clk); 1974 } 1975 } 1976} 1977 1978static bool patch_address_for_sbs_tb_stereo( 1979 struct pipe_ctx *pipe_ctx, PHYSICAL_ADDRESS_LOC *addr) 1980{ 1981 struct dc_plane_state *plane_state = pipe_ctx->plane_state; 1982 bool sec_split = pipe_ctx->top_pipe && 1983 pipe_ctx->top_pipe->plane_state == pipe_ctx->plane_state; 1984 if (sec_split && plane_state->address.type == PLN_ADDR_TYPE_GRPH_STEREO && 1985 (pipe_ctx->stream->timing.timing_3d_format == 1986 TIMING_3D_FORMAT_SIDE_BY_SIDE || 1987 pipe_ctx->stream->timing.timing_3d_format == 1988 TIMING_3D_FORMAT_TOP_AND_BOTTOM)) { 1989 *addr = plane_state->address.grph_stereo.left_addr; 1990 plane_state->address.grph_stereo.left_addr = 1991 plane_state->address.grph_stereo.right_addr; 1992 return true; 1993 } else { 1994 if (pipe_ctx->stream->view_format != VIEW_3D_FORMAT_NONE && 1995 plane_state->address.type != PLN_ADDR_TYPE_GRPH_STEREO) { 1996 plane_state->address.type = PLN_ADDR_TYPE_GRPH_STEREO; 1997 plane_state->address.grph_stereo.right_addr = 1998 plane_state->address.grph_stereo.left_addr; 1999 plane_state->address.grph_stereo.right_meta_addr = 2000 plane_state->address.grph_stereo.left_meta_addr; 2001 } 2002 } 2003 return false; 2004} 2005 2006void dcn10_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx) 2007{ 2008 bool addr_patched = false; 2009 PHYSICAL_ADDRESS_LOC addr; 2010 struct dc_plane_state *plane_state = pipe_ctx->plane_state; 2011 2012 if (plane_state == NULL) 2013 return; 2014 2015 addr_patched = patch_address_for_sbs_tb_stereo(pipe_ctx, &addr); 2016 2017 pipe_ctx->plane_res.hubp->funcs->hubp_program_surface_flip_and_addr( 2018 pipe_ctx->plane_res.hubp, 2019 &plane_state->address, 2020 plane_state->flip_immediate); 2021 2022 plane_state->status.requested_address = plane_state->address; 2023 2024 if (plane_state->flip_immediate) 2025 plane_state->status.current_address = plane_state->address; 2026 2027 if (addr_patched) 2028 pipe_ctx->plane_state->address.grph_stereo.left_addr = addr; 2029} 2030 2031bool dcn10_set_input_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx, 2032 const struct dc_plane_state *plane_state) 2033{ 2034 struct dpp *dpp_base = pipe_ctx->plane_res.dpp; 2035 const struct dc_transfer_func *tf = NULL; 2036 bool result = true; 2037 2038 if (dpp_base == NULL) 2039 return false; 2040 2041 tf = &plane_state->in_transfer_func; 2042 2043 if (!dpp_base->ctx->dc->debug.always_use_regamma 2044 && !plane_state->gamma_correction.is_identity 2045 && dce_use_lut(plane_state->format)) 2046 dpp_base->funcs->dpp_program_input_lut(dpp_base, &plane_state->gamma_correction); 2047 2048 if (tf->type == TF_TYPE_PREDEFINED) { 2049 switch (tf->tf) { 2050 case TRANSFER_FUNCTION_SRGB: 2051 dpp_base->funcs->dpp_set_degamma(dpp_base, IPP_DEGAMMA_MODE_HW_sRGB); 2052 break; 2053 case TRANSFER_FUNCTION_BT709: 2054 dpp_base->funcs->dpp_set_degamma(dpp_base, IPP_DEGAMMA_MODE_HW_xvYCC); 2055 break; 2056 case TRANSFER_FUNCTION_LINEAR: 2057 dpp_base->funcs->dpp_set_degamma(dpp_base, IPP_DEGAMMA_MODE_BYPASS); 2058 break; 2059 case TRANSFER_FUNCTION_PQ: 2060 dpp_base->funcs->dpp_set_degamma(dpp_base, IPP_DEGAMMA_MODE_USER_PWL); 2061 cm_helper_translate_curve_to_degamma_hw_format(tf, &dpp_base->degamma_params); 2062 dpp_base->funcs->dpp_program_degamma_pwl(dpp_base, &dpp_base->degamma_params); 2063 result = true; 2064 break; 2065 default: 2066 result = false; 2067 break; 2068 } 2069 } else if (tf->type == TF_TYPE_BYPASS) { 2070 dpp_base->funcs->dpp_set_degamma(dpp_base, IPP_DEGAMMA_MODE_BYPASS); 2071 } else { 2072 cm_helper_translate_curve_to_degamma_hw_format(tf, 2073 &dpp_base->degamma_params); 2074 dpp_base->funcs->dpp_program_degamma_pwl(dpp_base, 2075 &dpp_base->degamma_params); 2076 result = true; 2077 } 2078 2079 return result; 2080} 2081 2082#define MAX_NUM_HW_POINTS 0x200 2083 2084static void log_tf(struct dc_context *ctx, 2085 const struct dc_transfer_func *tf, uint32_t hw_points_num) 2086{ 2087 // DC_LOG_GAMMA is default logging of all hw points 2088 // DC_LOG_ALL_GAMMA logs all points, not only hw points 2089 // DC_LOG_ALL_TF_POINTS logs all channels of the tf 2090 int i = 0; 2091 2092 DC_LOG_GAMMA("Gamma Correction TF"); 2093 DC_LOG_ALL_GAMMA("Logging all tf points..."); 2094 DC_LOG_ALL_TF_CHANNELS("Logging all channels..."); 2095 2096 for (i = 0; i < hw_points_num; i++) { 2097 DC_LOG_GAMMA("R\t%d\t%llu", i, tf->tf_pts.red[i].value); 2098 DC_LOG_ALL_TF_CHANNELS("G\t%d\t%llu", i, tf->tf_pts.green[i].value); 2099 DC_LOG_ALL_TF_CHANNELS("B\t%d\t%llu", i, tf->tf_pts.blue[i].value); 2100 } 2101 2102 for (i = hw_points_num; i < MAX_NUM_HW_POINTS; i++) { 2103 DC_LOG_ALL_GAMMA("R\t%d\t%llu", i, tf->tf_pts.red[i].value); 2104 DC_LOG_ALL_TF_CHANNELS("G\t%d\t%llu", i, tf->tf_pts.green[i].value); 2105 DC_LOG_ALL_TF_CHANNELS("B\t%d\t%llu", i, tf->tf_pts.blue[i].value); 2106 } 2107} 2108 2109bool dcn10_set_output_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx, 2110 const struct dc_stream_state *stream) 2111{ 2112 struct dpp *dpp = pipe_ctx->plane_res.dpp; 2113 2114 if (!stream) 2115 return false; 2116 2117 if (dpp == NULL) 2118 return false; 2119 2120 dpp->regamma_params.hw_points_num = GAMMA_HW_POINTS_NUM; 2121 2122 if (stream->out_transfer_func.type == TF_TYPE_PREDEFINED && 2123 stream->out_transfer_func.tf == TRANSFER_FUNCTION_SRGB) 2124 dpp->funcs->dpp_program_regamma_pwl(dpp, NULL, OPP_REGAMMA_SRGB); 2125 2126 /* dcn10_translate_regamma_to_hw_format takes 750us, only do it when full 2127 * update. 2128 */ 2129 else if (cm_helper_translate_curve_to_hw_format(dc->ctx, 2130 &stream->out_transfer_func, 2131 &dpp->regamma_params, false)) { 2132 dpp->funcs->dpp_program_regamma_pwl( 2133 dpp, 2134 &dpp->regamma_params, OPP_REGAMMA_USER); 2135 } else 2136 dpp->funcs->dpp_program_regamma_pwl(dpp, NULL, OPP_REGAMMA_BYPASS); 2137 2138 if (stream->ctx) { 2139 log_tf(stream->ctx, 2140 &stream->out_transfer_func, 2141 dpp->regamma_params.hw_points_num); 2142 } 2143 2144 return true; 2145} 2146 2147void dcn10_pipe_control_lock( 2148 struct dc *dc, 2149 struct pipe_ctx *pipe, 2150 bool lock) 2151{ 2152 struct dce_hwseq *hws = dc->hwseq; 2153 2154 /* use TG master update lock to lock everything on the TG 2155 * therefore only top pipe need to lock 2156 */ 2157 if (!pipe || pipe->top_pipe) 2158 return; 2159 2160 if (dc->debug.sanity_checks) 2161 hws->funcs.verify_allow_pstate_change_high(dc); 2162 2163 if (lock) 2164 pipe->stream_res.tg->funcs->lock(pipe->stream_res.tg); 2165 else 2166 pipe->stream_res.tg->funcs->unlock(pipe->stream_res.tg); 2167 2168 if (dc->debug.sanity_checks) 2169 hws->funcs.verify_allow_pstate_change_high(dc); 2170} 2171 2172/** 2173 * delay_cursor_until_vupdate() - Delay cursor update if too close to VUPDATE. 2174 * 2175 * Software keepout workaround to prevent cursor update locking from stalling 2176 * out cursor updates indefinitely or from old values from being retained in 2177 * the case where the viewport changes in the same frame as the cursor. 2178 * 2179 * The idea is to calculate the remaining time from VPOS to VUPDATE. If it's 2180 * too close to VUPDATE, then stall out until VUPDATE finishes. 2181 * 2182 * TODO: Optimize cursor programming to be once per frame before VUPDATE 2183 * to avoid the need for this workaround. 2184 * 2185 * @dc: Current DC state 2186 * @pipe_ctx: Pipe_ctx pointer for delayed cursor update 2187 * 2188 * Return: void 2189 */ 2190static void delay_cursor_until_vupdate(struct dc *dc, struct pipe_ctx *pipe_ctx) 2191{ 2192 struct dc_stream_state *stream = pipe_ctx->stream; 2193 struct crtc_position position; 2194 uint32_t vupdate_start, vupdate_end; 2195 unsigned int lines_to_vupdate, us_to_vupdate, vpos; 2196 unsigned int us_per_line, us_vupdate; 2197 2198 if (!dc->hwss.calc_vupdate_position || !dc->hwss.get_position) 2199 return; 2200 2201 if (!pipe_ctx->stream_res.stream_enc || !pipe_ctx->stream_res.tg) 2202 return; 2203 2204 dc->hwss.calc_vupdate_position(dc, pipe_ctx, &vupdate_start, 2205 &vupdate_end); 2206 2207 dc->hwss.get_position(&pipe_ctx, 1, &position); 2208 vpos = position.vertical_count; 2209 2210 if (vpos <= vupdate_start) { 2211 /* VPOS is in VACTIVE or back porch. */ 2212 lines_to_vupdate = vupdate_start - vpos; 2213 } else { 2214 lines_to_vupdate = stream->timing.v_total - vpos + vupdate_start; 2215 } 2216 2217 /* Calculate time until VUPDATE in microseconds. */ 2218 us_per_line = 2219 stream->timing.h_total * 10000u / stream->timing.pix_clk_100hz; 2220 us_to_vupdate = lines_to_vupdate * us_per_line; 2221 2222 /* Stall out until the cursor update completes. */ 2223 if (vupdate_end < vupdate_start) 2224 vupdate_end += stream->timing.v_total; 2225 2226 /* Position is in the range of vupdate start and end*/ 2227 if (lines_to_vupdate > stream->timing.v_total - vupdate_end + vupdate_start) 2228 us_to_vupdate = 0; 2229 2230 /* 70 us is a conservative estimate of cursor update time*/ 2231 if (us_to_vupdate > 70) 2232 return; 2233 2234 us_vupdate = (vupdate_end - vupdate_start + 1) * us_per_line; 2235 udelay(us_to_vupdate + us_vupdate); 2236} 2237 2238void dcn10_cursor_lock(struct dc *dc, struct pipe_ctx *pipe, bool lock) 2239{ 2240 /* cursor lock is per MPCC tree, so only need to lock one pipe per stream */ 2241 if (!pipe || pipe->top_pipe) 2242 return; 2243 2244 /* Prevent cursor lock from stalling out cursor updates. */ 2245 if (lock) 2246 delay_cursor_until_vupdate(dc, pipe); 2247 2248 if (pipe->stream && should_use_dmub_inbox1_lock(dc, pipe->stream->link)) { 2249 union dmub_hw_lock_flags hw_locks = { 0 }; 2250 struct dmub_hw_lock_inst_flags inst_flags = { 0 }; 2251 2252 hw_locks.bits.lock_cursor = 1; 2253 inst_flags.opp_inst = pipe->stream_res.opp->inst; 2254 2255 dmub_hw_lock_mgr_cmd(dc->ctx->dmub_srv, 2256 lock, 2257 &hw_locks, 2258 &inst_flags); 2259 } else 2260 dc->res_pool->mpc->funcs->cursor_lock(dc->res_pool->mpc, 2261 pipe->stream_res.opp->inst, lock); 2262} 2263 2264static bool wait_for_reset_trigger_to_occur( 2265 struct dc_context *dc_ctx, 2266 struct timing_generator *tg) 2267{ 2268 bool rc = false; 2269 2270 DC_LOGGER_INIT(dc_ctx->logger); 2271 2272 /* To avoid endless loop we wait at most 2273 * frames_to_wait_on_triggered_reset frames for the reset to occur. */ 2274 const uint32_t frames_to_wait_on_triggered_reset = 10; 2275 int i; 2276 2277 for (i = 0; i < frames_to_wait_on_triggered_reset; i++) { 2278 2279 if (!tg->funcs->is_counter_moving(tg)) { 2280 DC_ERROR("TG counter is not moving!\n"); 2281 break; 2282 } 2283 2284 if (tg->funcs->did_triggered_reset_occur(tg)) { 2285 rc = true; 2286 /* usually occurs at i=1 */ 2287 DC_SYNC_INFO("GSL: reset occurred at wait count: %d\n", 2288 i); 2289 break; 2290 } 2291 2292 /* Wait for one frame. */ 2293 tg->funcs->wait_for_state(tg, CRTC_STATE_VACTIVE); 2294 tg->funcs->wait_for_state(tg, CRTC_STATE_VBLANK); 2295 } 2296 2297 if (false == rc) 2298 DC_ERROR("GSL: Timeout on reset trigger!\n"); 2299 2300 return rc; 2301} 2302 2303static uint64_t reduceSizeAndFraction(uint64_t *numerator, 2304 uint64_t *denominator, 2305 bool checkUint32Bounary) 2306{ 2307 int i; 2308 bool ret = checkUint32Bounary == false; 2309 uint64_t max_int32 = 0xffffffff; 2310 uint64_t num, denom; 2311 static const uint16_t prime_numbers[] = { 2312 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 2313 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 2314 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 2315 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 2316 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 2317 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 2318 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 2319 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 2320 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 2321 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 2322 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 2323 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 2324 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 2325 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 2326 941, 947, 953, 967, 971, 977, 983, 991, 997}; 2327 int count = ARRAY_SIZE(prime_numbers); 2328 2329 num = *numerator; 2330 denom = *denominator; 2331 for (i = 0; i < count; i++) { 2332 uint32_t num_remainder, denom_remainder; 2333 uint64_t num_result, denom_result; 2334 if (checkUint32Bounary && 2335 num <= max_int32 && denom <= max_int32) { 2336 ret = true; 2337 break; 2338 } 2339 do { 2340 num_result = div_u64_rem(num, prime_numbers[i], &num_remainder); 2341 denom_result = div_u64_rem(denom, prime_numbers[i], &denom_remainder); 2342 if (num_remainder == 0 && denom_remainder == 0) { 2343 num = num_result; 2344 denom = denom_result; 2345 } 2346 } while (num_remainder == 0 && denom_remainder == 0); 2347 } 2348 *numerator = num; 2349 *denominator = denom; 2350 return ret; 2351} 2352 2353static bool is_low_refresh_rate(struct pipe_ctx *pipe) 2354{ 2355 uint32_t master_pipe_refresh_rate = 2356 pipe->stream->timing.pix_clk_100hz * 100 / 2357 pipe->stream->timing.h_total / 2358 pipe->stream->timing.v_total; 2359 return master_pipe_refresh_rate <= 30; 2360} 2361 2362static uint8_t get_clock_divider(struct pipe_ctx *pipe, 2363 bool account_low_refresh_rate) 2364{ 2365 uint32_t clock_divider = 1; 2366 uint32_t numpipes = 1; 2367 2368 if (account_low_refresh_rate && is_low_refresh_rate(pipe)) 2369 clock_divider *= 2; 2370 2371 if (pipe->stream_res.pix_clk_params.pixel_encoding == PIXEL_ENCODING_YCBCR420) 2372 clock_divider *= 2; 2373 2374 while (pipe->next_odm_pipe) { 2375 pipe = pipe->next_odm_pipe; 2376 numpipes++; 2377 } 2378 clock_divider *= numpipes; 2379 2380 return clock_divider; 2381} 2382 2383static int dcn10_align_pixel_clocks(struct dc *dc, int group_size, 2384 struct pipe_ctx *grouped_pipes[]) 2385{ 2386 struct dc_context *dc_ctx = dc->ctx; 2387 int i, master = -1, embedded = -1; 2388 struct dc_crtc_timing *hw_crtc_timing; 2389 uint64_t phase[MAX_PIPES]; 2390 uint64_t modulo[MAX_PIPES]; 2391 unsigned int pclk = 0; 2392 2393 uint32_t embedded_pix_clk_100hz; 2394 uint16_t embedded_h_total; 2395 uint16_t embedded_v_total; 2396 uint32_t dp_ref_clk_100hz = 2397 dc->res_pool->dp_clock_source->ctx->dc->clk_mgr->dprefclk_khz*10; 2398 2399 DC_LOGGER_INIT(dc_ctx->logger); 2400 2401 hw_crtc_timing = kcalloc(MAX_PIPES, sizeof(*hw_crtc_timing), GFP_KERNEL); 2402 if (!hw_crtc_timing) 2403 return master; 2404 2405 if (dc->config.vblank_alignment_dto_params && 2406 dc->res_pool->dp_clock_source->funcs->override_dp_pix_clk) { 2407 embedded_h_total = 2408 (dc->config.vblank_alignment_dto_params >> 32) & 0x7FFF; 2409 embedded_v_total = 2410 (dc->config.vblank_alignment_dto_params >> 48) & 0x7FFF; 2411 embedded_pix_clk_100hz = 2412 dc->config.vblank_alignment_dto_params & 0xFFFFFFFF; 2413 2414 for (i = 0; i < group_size; i++) { 2415 grouped_pipes[i]->stream_res.tg->funcs->get_hw_timing( 2416 grouped_pipes[i]->stream_res.tg, 2417 &hw_crtc_timing[i]); 2418 dc->res_pool->dp_clock_source->funcs->get_pixel_clk_frequency_100hz( 2419 dc->res_pool->dp_clock_source, 2420 grouped_pipes[i]->stream_res.tg->inst, 2421 &pclk); 2422 hw_crtc_timing[i].pix_clk_100hz = pclk; 2423 if (dc_is_embedded_signal( 2424 grouped_pipes[i]->stream->signal)) { 2425 embedded = i; 2426 master = i; 2427 phase[i] = embedded_pix_clk_100hz*(uint64_t)100; 2428 modulo[i] = dp_ref_clk_100hz*100; 2429 } else { 2430 2431 phase[i] = (uint64_t)embedded_pix_clk_100hz* 2432 hw_crtc_timing[i].h_total* 2433 hw_crtc_timing[i].v_total; 2434 phase[i] = div_u64(phase[i], get_clock_divider(grouped_pipes[i], true)); 2435 modulo[i] = (uint64_t)dp_ref_clk_100hz* 2436 embedded_h_total* 2437 embedded_v_total; 2438 2439 if (reduceSizeAndFraction(&phase[i], 2440 &modulo[i], true) == false) { 2441 /* 2442 * this will help to stop reporting 2443 * this timing synchronizable 2444 */ 2445 DC_SYNC_INFO("Failed to reduce DTO parameters\n"); 2446 grouped_pipes[i]->stream->has_non_synchronizable_pclk = true; 2447 } 2448 } 2449 } 2450 2451 for (i = 0; i < group_size; i++) { 2452 if (i != embedded && !grouped_pipes[i]->stream->has_non_synchronizable_pclk) { 2453 dc->res_pool->dp_clock_source->funcs->override_dp_pix_clk( 2454 dc->res_pool->dp_clock_source, 2455 grouped_pipes[i]->stream_res.tg->inst, 2456 phase[i], modulo[i]); 2457 dc->res_pool->dp_clock_source->funcs->get_pixel_clk_frequency_100hz( 2458 dc->res_pool->dp_clock_source, 2459 grouped_pipes[i]->stream_res.tg->inst, &pclk); 2460 grouped_pipes[i]->stream->timing.pix_clk_100hz = 2461 pclk*get_clock_divider(grouped_pipes[i], false); 2462 if (master == -1) 2463 master = i; 2464 } 2465 } 2466 2467 } 2468 2469 kfree(hw_crtc_timing); 2470 return master; 2471} 2472 2473void dcn10_enable_vblanks_synchronization( 2474 struct dc *dc, 2475 int group_index, 2476 int group_size, 2477 struct pipe_ctx *grouped_pipes[]) 2478{ 2479 struct dc_context *dc_ctx = dc->ctx; 2480 struct output_pixel_processor *opp; 2481 struct timing_generator *tg; 2482 int i, width = 0, height = 0, master; 2483 2484 DC_LOGGER_INIT(dc_ctx->logger); 2485 2486 for (i = 1; i < group_size; i++) { 2487 opp = grouped_pipes[i]->stream_res.opp; 2488 tg = grouped_pipes[i]->stream_res.tg; 2489 tg->funcs->get_otg_active_size(tg, &width, &height); 2490 2491 if (!tg->funcs->is_tg_enabled(tg)) { 2492 DC_SYNC_INFO("Skipping timing sync on disabled OTG\n"); 2493 return; 2494 } 2495 2496 if (opp->funcs->opp_program_dpg_dimensions) 2497 opp->funcs->opp_program_dpg_dimensions(opp, width, 2*(height) + 1); 2498 } 2499 2500 for (i = 0; i < group_size; i++) { 2501 if (grouped_pipes[i]->stream == NULL) 2502 continue; 2503 grouped_pipes[i]->stream->vblank_synchronized = false; 2504 grouped_pipes[i]->stream->has_non_synchronizable_pclk = false; 2505 } 2506 2507 DC_SYNC_INFO("Aligning DP DTOs\n"); 2508 2509 master = dcn10_align_pixel_clocks(dc, group_size, grouped_pipes); 2510 2511 DC_SYNC_INFO("Synchronizing VBlanks\n"); 2512 2513 if (master >= 0) { 2514 for (i = 0; i < group_size; i++) { 2515 if (i != master && !grouped_pipes[i]->stream->has_non_synchronizable_pclk) 2516 grouped_pipes[i]->stream_res.tg->funcs->align_vblanks( 2517 grouped_pipes[master]->stream_res.tg, 2518 grouped_pipes[i]->stream_res.tg, 2519 grouped_pipes[master]->stream->timing.pix_clk_100hz, 2520 grouped_pipes[i]->stream->timing.pix_clk_100hz, 2521 get_clock_divider(grouped_pipes[master], false), 2522 get_clock_divider(grouped_pipes[i], false)); 2523 grouped_pipes[i]->stream->vblank_synchronized = true; 2524 } 2525 grouped_pipes[master]->stream->vblank_synchronized = true; 2526 DC_SYNC_INFO("Sync complete\n"); 2527 } 2528 2529 for (i = 1; i < group_size; i++) { 2530 opp = grouped_pipes[i]->stream_res.opp; 2531 tg = grouped_pipes[i]->stream_res.tg; 2532 tg->funcs->get_otg_active_size(tg, &width, &height); 2533 if (opp->funcs->opp_program_dpg_dimensions) 2534 opp->funcs->opp_program_dpg_dimensions(opp, width, height); 2535 } 2536} 2537 2538void dcn10_enable_timing_synchronization( 2539 struct dc *dc, 2540 struct dc_state *state, 2541 int group_index, 2542 int group_size, 2543 struct pipe_ctx *grouped_pipes[]) 2544{ 2545 struct dc_context *dc_ctx = dc->ctx; 2546 struct output_pixel_processor *opp; 2547 struct timing_generator *tg; 2548 int i, width = 0, height = 0; 2549 2550 DC_LOGGER_INIT(dc_ctx->logger); 2551 2552 DC_SYNC_INFO("Setting up OTG reset trigger\n"); 2553 2554 for (i = 1; i < group_size; i++) { 2555 if (grouped_pipes[i]->stream && dc_state_get_pipe_subvp_type(state, grouped_pipes[i]) == SUBVP_PHANTOM) 2556 continue; 2557 2558 opp = grouped_pipes[i]->stream_res.opp; 2559 tg = grouped_pipes[i]->stream_res.tg; 2560 tg->funcs->get_otg_active_size(tg, &width, &height); 2561 2562 if (!tg->funcs->is_tg_enabled(tg)) { 2563 DC_SYNC_INFO("Skipping timing sync on disabled OTG\n"); 2564 return; 2565 } 2566 2567 if (opp->funcs->opp_program_dpg_dimensions) 2568 opp->funcs->opp_program_dpg_dimensions(opp, width, 2*(height) + 1); 2569 } 2570 2571 for (i = 0; i < group_size; i++) { 2572 if (grouped_pipes[i]->stream == NULL) 2573 continue; 2574 2575 if (grouped_pipes[i]->stream && dc_state_get_pipe_subvp_type(state, grouped_pipes[i]) == SUBVP_PHANTOM) 2576 continue; 2577 2578 grouped_pipes[i]->stream->vblank_synchronized = false; 2579 } 2580 2581 for (i = 1; i < group_size; i++) { 2582 if (grouped_pipes[i]->stream && dc_state_get_pipe_subvp_type(state, grouped_pipes[i]) == SUBVP_PHANTOM) 2583 continue; 2584 2585 grouped_pipes[i]->stream_res.tg->funcs->enable_reset_trigger( 2586 grouped_pipes[i]->stream_res.tg, 2587 grouped_pipes[0]->stream_res.tg->inst); 2588 } 2589 2590 DC_SYNC_INFO("Waiting for trigger\n"); 2591 2592 /* Need to get only check 1 pipe for having reset as all the others are 2593 * synchronized. Look at last pipe programmed to reset. 2594 */ 2595 2596 if (grouped_pipes[1]->stream && dc_state_get_pipe_subvp_type(state, grouped_pipes[1]) != SUBVP_PHANTOM) 2597 wait_for_reset_trigger_to_occur(dc_ctx, grouped_pipes[1]->stream_res.tg); 2598 2599 for (i = 1; i < group_size; i++) { 2600 if (grouped_pipes[i]->stream && dc_state_get_pipe_subvp_type(state, grouped_pipes[i]) == SUBVP_PHANTOM) 2601 continue; 2602 2603 grouped_pipes[i]->stream_res.tg->funcs->disable_reset_trigger( 2604 grouped_pipes[i]->stream_res.tg); 2605 } 2606 2607 for (i = 1; i < group_size; i++) { 2608 if (dc_state_get_pipe_subvp_type(state, grouped_pipes[i]) == SUBVP_PHANTOM) 2609 continue; 2610 2611 opp = grouped_pipes[i]->stream_res.opp; 2612 tg = grouped_pipes[i]->stream_res.tg; 2613 tg->funcs->get_otg_active_size(tg, &width, &height); 2614 if (opp->funcs->opp_program_dpg_dimensions) 2615 opp->funcs->opp_program_dpg_dimensions(opp, width, height); 2616 } 2617 2618 DC_SYNC_INFO("Sync complete\n"); 2619} 2620 2621void dcn10_enable_per_frame_crtc_position_reset( 2622 struct dc *dc, 2623 int group_size, 2624 struct pipe_ctx *grouped_pipes[]) 2625{ 2626 struct dc_context *dc_ctx = dc->ctx; 2627 int i; 2628 2629 DC_LOGGER_INIT(dc_ctx->logger); 2630 2631 DC_SYNC_INFO("Setting up\n"); 2632 for (i = 0; i < group_size; i++) 2633 if (grouped_pipes[i]->stream_res.tg->funcs->enable_crtc_reset) 2634 grouped_pipes[i]->stream_res.tg->funcs->enable_crtc_reset( 2635 grouped_pipes[i]->stream_res.tg, 2636 0, 2637 &grouped_pipes[i]->stream->triggered_crtc_reset); 2638 2639 DC_SYNC_INFO("Waiting for trigger\n"); 2640 2641 for (i = 0; i < group_size; i++) 2642 wait_for_reset_trigger_to_occur(dc_ctx, grouped_pipes[i]->stream_res.tg); 2643 2644 DC_SYNC_INFO("Multi-display sync is complete\n"); 2645} 2646 2647static void mmhub_read_vm_system_aperture_settings(struct dcn10_hubp *hubp1, 2648 struct vm_system_aperture_param *apt, 2649 struct dce_hwseq *hws) 2650{ 2651 PHYSICAL_ADDRESS_LOC physical_page_number; 2652 uint32_t logical_addr_low; 2653 uint32_t logical_addr_high; 2654 2655 REG_GET(MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB, 2656 PHYSICAL_PAGE_NUMBER_MSB, &physical_page_number.high_part); 2657 REG_GET(MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB, 2658 PHYSICAL_PAGE_NUMBER_LSB, &physical_page_number.low_part); 2659 2660 REG_GET(MC_VM_SYSTEM_APERTURE_LOW_ADDR, 2661 LOGICAL_ADDR, &logical_addr_low); 2662 2663 REG_GET(MC_VM_SYSTEM_APERTURE_HIGH_ADDR, 2664 LOGICAL_ADDR, &logical_addr_high); 2665 2666 apt->sys_default.quad_part = physical_page_number.quad_part << 12; 2667 apt->sys_low.quad_part = (int64_t)logical_addr_low << 18; 2668 apt->sys_high.quad_part = (int64_t)logical_addr_high << 18; 2669} 2670 2671/* Temporary read settings, future will get values from kmd directly */ 2672static void mmhub_read_vm_context0_settings(struct dcn10_hubp *hubp1, 2673 struct vm_context0_param *vm0, 2674 struct dce_hwseq *hws) 2675{ 2676 PHYSICAL_ADDRESS_LOC fb_base; 2677 PHYSICAL_ADDRESS_LOC fb_offset; 2678 uint32_t fb_base_value; 2679 uint32_t fb_offset_value; 2680 2681 REG_GET(DCHUBBUB_SDPIF_FB_BASE, SDPIF_FB_BASE, &fb_base_value); 2682 REG_GET(DCHUBBUB_SDPIF_FB_OFFSET, SDPIF_FB_OFFSET, &fb_offset_value); 2683 2684 REG_GET(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32, 2685 PAGE_DIRECTORY_ENTRY_HI32, &vm0->pte_base.high_part); 2686 REG_GET(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LO32, 2687 PAGE_DIRECTORY_ENTRY_LO32, &vm0->pte_base.low_part); 2688 2689 REG_GET(VM_CONTEXT0_PAGE_TABLE_START_ADDR_HI32, 2690 LOGICAL_PAGE_NUMBER_HI4, &vm0->pte_start.high_part); 2691 REG_GET(VM_CONTEXT0_PAGE_TABLE_START_ADDR_LO32, 2692 LOGICAL_PAGE_NUMBER_LO32, &vm0->pte_start.low_part); 2693 2694 REG_GET(VM_CONTEXT0_PAGE_TABLE_END_ADDR_HI32, 2695 LOGICAL_PAGE_NUMBER_HI4, &vm0->pte_end.high_part); 2696 REG_GET(VM_CONTEXT0_PAGE_TABLE_END_ADDR_LO32, 2697 LOGICAL_PAGE_NUMBER_LO32, &vm0->pte_end.low_part); 2698 2699 REG_GET(VM_L2_PROTECTION_FAULT_DEFAULT_ADDR_HI32, 2700 PHYSICAL_PAGE_ADDR_HI4, &vm0->fault_default.high_part); 2701 REG_GET(VM_L2_PROTECTION_FAULT_DEFAULT_ADDR_LO32, 2702 PHYSICAL_PAGE_ADDR_LO32, &vm0->fault_default.low_part); 2703 2704 /* 2705 * The values in VM_CONTEXT0_PAGE_TABLE_BASE_ADDR is in UMA space. 2706 * Therefore we need to do 2707 * DCN_VM_CONTEXT0_PAGE_TABLE_BASE_ADDR = VM_CONTEXT0_PAGE_TABLE_BASE_ADDR 2708 * - DCHUBBUB_SDPIF_FB_OFFSET + DCHUBBUB_SDPIF_FB_BASE 2709 */ 2710 fb_base.quad_part = (uint64_t)fb_base_value << 24; 2711 fb_offset.quad_part = (uint64_t)fb_offset_value << 24; 2712 vm0->pte_base.quad_part += fb_base.quad_part; 2713 vm0->pte_base.quad_part -= fb_offset.quad_part; 2714} 2715 2716 2717static void dcn10_program_pte_vm(struct dce_hwseq *hws, struct hubp *hubp) 2718{ 2719 struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp); 2720 struct vm_system_aperture_param apt = {0}; 2721 struct vm_context0_param vm0 = {0}; 2722 2723 mmhub_read_vm_system_aperture_settings(hubp1, &apt, hws); 2724 mmhub_read_vm_context0_settings(hubp1, &vm0, hws); 2725 2726 hubp->funcs->hubp_set_vm_system_aperture_settings(hubp, &apt); 2727 hubp->funcs->hubp_set_vm_context0_settings(hubp, &vm0); 2728} 2729 2730static void dcn10_enable_plane( 2731 struct dc *dc, 2732 struct pipe_ctx *pipe_ctx, 2733 struct dc_state *context) 2734{ 2735 struct dce_hwseq *hws = dc->hwseq; 2736 2737 if (dc->debug.sanity_checks) { 2738 hws->funcs.verify_allow_pstate_change_high(dc); 2739 } 2740 2741 undo_DEGVIDCN10_253_wa(dc); 2742 2743 power_on_plane_resources(dc->hwseq, 2744 pipe_ctx->plane_res.hubp->inst); 2745 2746 /* enable DCFCLK current DCHUB */ 2747 pipe_ctx->plane_res.hubp->funcs->hubp_clk_cntl(pipe_ctx->plane_res.hubp, true); 2748 2749 /* make sure OPP_PIPE_CLOCK_EN = 1 */ 2750 pipe_ctx->stream_res.opp->funcs->opp_pipe_clock_control( 2751 pipe_ctx->stream_res.opp, 2752 true); 2753 2754 if (dc->config.gpu_vm_support) 2755 dcn10_program_pte_vm(hws, pipe_ctx->plane_res.hubp); 2756 2757 if (dc->debug.sanity_checks) { 2758 hws->funcs.verify_allow_pstate_change_high(dc); 2759 } 2760 2761 if (!pipe_ctx->top_pipe 2762 && pipe_ctx->plane_state 2763 && pipe_ctx->plane_state->flip_int_enabled 2764 && pipe_ctx->plane_res.hubp->funcs->hubp_set_flip_int) 2765 pipe_ctx->plane_res.hubp->funcs->hubp_set_flip_int(pipe_ctx->plane_res.hubp); 2766 2767} 2768 2769void dcn10_program_gamut_remap(struct pipe_ctx *pipe_ctx) 2770{ 2771 int i = 0; 2772 struct dpp_grph_csc_adjustment adjust; 2773 memset(&adjust, 0, sizeof(adjust)); 2774 adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS; 2775 2776 2777 if (pipe_ctx->stream->gamut_remap_matrix.enable_remap == true) { 2778 adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW; 2779 for (i = 0; i < CSC_TEMPERATURE_MATRIX_SIZE; i++) 2780 adjust.temperature_matrix[i] = 2781 pipe_ctx->stream->gamut_remap_matrix.matrix[i]; 2782 } else if (pipe_ctx->plane_state && 2783 pipe_ctx->plane_state->gamut_remap_matrix.enable_remap == true) { 2784 adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW; 2785 for (i = 0; i < CSC_TEMPERATURE_MATRIX_SIZE; i++) 2786 adjust.temperature_matrix[i] = 2787 pipe_ctx->plane_state->gamut_remap_matrix.matrix[i]; 2788 } 2789 2790 pipe_ctx->plane_res.dpp->funcs->dpp_set_gamut_remap(pipe_ctx->plane_res.dpp, &adjust); 2791} 2792 2793 2794static bool dcn10_is_rear_mpo_fix_required(struct pipe_ctx *pipe_ctx, enum dc_color_space colorspace) 2795{ 2796 if (pipe_ctx->plane_state && pipe_ctx->plane_state->layer_index > 0 && is_rgb_cspace(colorspace)) { 2797 if (pipe_ctx->top_pipe) { 2798 struct pipe_ctx *top = pipe_ctx->top_pipe; 2799 2800 while (top->top_pipe) 2801 top = top->top_pipe; // Traverse to top pipe_ctx 2802 if (top->plane_state && top->plane_state->layer_index == 0 && !top->plane_state->global_alpha) 2803 // Global alpha used by top plane for PIP overlay 2804 // Pre-multiplied/per-pixel alpha used by MPO 2805 // Check top plane's global alpha to ensure layer_index > 0 not caused by PIP 2806 return true; // MPO in use and front plane not hidden 2807 } 2808 } 2809 return false; 2810} 2811 2812static void dcn10_set_csc_adjustment_rgb_mpo_fix(struct pipe_ctx *pipe_ctx, uint16_t *matrix) 2813{ 2814 // Override rear plane RGB bias to fix MPO brightness 2815 uint16_t rgb_bias = matrix[3]; 2816 2817 matrix[3] = 0; 2818 matrix[7] = 0; 2819 matrix[11] = 0; 2820 pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_adjustment(pipe_ctx->plane_res.dpp, matrix); 2821 matrix[3] = rgb_bias; 2822 matrix[7] = rgb_bias; 2823 matrix[11] = rgb_bias; 2824} 2825 2826void dcn10_program_output_csc(struct dc *dc, 2827 struct pipe_ctx *pipe_ctx, 2828 enum dc_color_space colorspace, 2829 uint16_t *matrix, 2830 int opp_id) 2831{ 2832 if (pipe_ctx->stream->csc_color_matrix.enable_adjustment == true) { 2833 if (pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_adjustment != NULL) { 2834 2835 /* MPO is broken with RGB colorspaces when OCSC matrix 2836 * brightness offset >= 0 on DCN1 due to OCSC before MPC 2837 * Blending adds offsets from front + rear to rear plane 2838 * 2839 * Fix is to set RGB bias to 0 on rear plane, top plane 2840 * black value pixels add offset instead of rear + front 2841 */ 2842 2843 int16_t rgb_bias = matrix[3]; 2844 // matrix[3/7/11] are all the same offset value 2845 2846 if (rgb_bias > 0 && dcn10_is_rear_mpo_fix_required(pipe_ctx, colorspace)) { 2847 dcn10_set_csc_adjustment_rgb_mpo_fix(pipe_ctx, matrix); 2848 } else { 2849 pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_adjustment(pipe_ctx->plane_res.dpp, matrix); 2850 } 2851 } 2852 } else { 2853 if (pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_default != NULL) 2854 pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_default(pipe_ctx->plane_res.dpp, colorspace); 2855 } 2856} 2857 2858static void dcn10_update_dpp(struct dpp *dpp, struct dc_plane_state *plane_state) 2859{ 2860 struct dc_bias_and_scale bns_params = {0}; 2861 2862 // program the input csc 2863 dpp->funcs->dpp_setup(dpp, 2864 plane_state->format, 2865 EXPANSION_MODE_ZERO, 2866 plane_state->input_csc_color_matrix, 2867 plane_state->color_space, 2868 NULL); 2869 2870 //set scale and bias registers 2871 build_prescale_params(&bns_params, plane_state); 2872 if (dpp->funcs->dpp_program_bias_and_scale) 2873 dpp->funcs->dpp_program_bias_and_scale(dpp, &bns_params); 2874} 2875 2876void dcn10_update_visual_confirm_color(struct dc *dc, 2877 struct pipe_ctx *pipe_ctx, 2878 int mpcc_id) 2879{ 2880 struct mpc *mpc = dc->res_pool->mpc; 2881 2882 if (mpc->funcs->set_bg_color) { 2883 mpc->funcs->set_bg_color(mpc, &(pipe_ctx->visual_confirm_color), mpcc_id); 2884 } 2885} 2886 2887void dcn10_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx) 2888{ 2889 struct hubp *hubp = pipe_ctx->plane_res.hubp; 2890 struct mpcc_blnd_cfg blnd_cfg = {0}; 2891 bool per_pixel_alpha = pipe_ctx->plane_state->per_pixel_alpha && pipe_ctx->bottom_pipe; 2892 int mpcc_id; 2893 struct mpcc *new_mpcc; 2894 struct mpc *mpc = dc->res_pool->mpc; 2895 struct mpc_tree *mpc_tree_params = &(pipe_ctx->stream_res.opp->mpc_tree_params); 2896 2897 blnd_cfg.overlap_only = false; 2898 blnd_cfg.global_gain = 0xff; 2899 2900 if (per_pixel_alpha) { 2901 /* DCN1.0 has output CM before MPC which seems to screw with 2902 * pre-multiplied alpha. 2903 */ 2904 blnd_cfg.pre_multiplied_alpha = (is_rgb_cspace( 2905 pipe_ctx->stream->output_color_space) 2906 && pipe_ctx->plane_state->pre_multiplied_alpha); 2907 if (pipe_ctx->plane_state->global_alpha) { 2908 blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA_COMBINED_GLOBAL_GAIN; 2909 blnd_cfg.global_gain = pipe_ctx->plane_state->global_alpha_value; 2910 } else { 2911 blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA; 2912 } 2913 } else { 2914 blnd_cfg.pre_multiplied_alpha = false; 2915 blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_GLOBAL_ALPHA; 2916 } 2917 2918 if (pipe_ctx->plane_state->global_alpha) 2919 blnd_cfg.global_alpha = pipe_ctx->plane_state->global_alpha_value; 2920 else 2921 blnd_cfg.global_alpha = 0xff; 2922 2923 /* 2924 * TODO: remove hack 2925 * Note: currently there is a bug in init_hw such that 2926 * on resume from hibernate, BIOS sets up MPCC0, and 2927 * we do mpcc_remove but the mpcc cannot go to idle 2928 * after remove. This cause us to pick mpcc1 here, 2929 * which causes a pstate hang for yet unknown reason. 2930 */ 2931 mpcc_id = hubp->inst; 2932 2933 /* If there is no full update, don't need to touch MPC tree*/ 2934 if (!pipe_ctx->plane_state->update_flags.bits.full_update) { 2935 mpc->funcs->update_blending(mpc, &blnd_cfg, mpcc_id); 2936 dc->hwss.update_visual_confirm_color(dc, pipe_ctx, mpcc_id); 2937 return; 2938 } 2939 2940 /* check if this MPCC is already being used */ 2941 new_mpcc = mpc->funcs->get_mpcc_for_dpp(mpc_tree_params, mpcc_id); 2942 /* remove MPCC if being used */ 2943 if (new_mpcc != NULL) 2944 mpc->funcs->remove_mpcc(mpc, mpc_tree_params, new_mpcc); 2945 else 2946 if (dc->debug.sanity_checks) 2947 mpc->funcs->assert_mpcc_idle_before_connect( 2948 dc->res_pool->mpc, mpcc_id); 2949 2950 /* Call MPC to insert new plane */ 2951 new_mpcc = mpc->funcs->insert_plane(dc->res_pool->mpc, 2952 mpc_tree_params, 2953 &blnd_cfg, 2954 NULL, 2955 NULL, 2956 hubp->inst, 2957 mpcc_id); 2958 dc->hwss.update_visual_confirm_color(dc, pipe_ctx, mpcc_id); 2959 2960 ASSERT(new_mpcc != NULL); 2961 hubp->opp_id = pipe_ctx->stream_res.opp->inst; 2962 hubp->mpcc_id = mpcc_id; 2963} 2964 2965static void update_scaler(struct pipe_ctx *pipe_ctx) 2966{ 2967 bool per_pixel_alpha = 2968 pipe_ctx->plane_state->per_pixel_alpha && pipe_ctx->bottom_pipe; 2969 2970 pipe_ctx->plane_res.scl_data.lb_params.alpha_en = per_pixel_alpha; 2971 pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_36BPP; 2972 /* scaler configuration */ 2973 pipe_ctx->plane_res.dpp->funcs->dpp_set_scaler( 2974 pipe_ctx->plane_res.dpp, &pipe_ctx->plane_res.scl_data); 2975} 2976 2977static void dcn10_update_dchubp_dpp( 2978 struct dc *dc, 2979 struct pipe_ctx *pipe_ctx, 2980 struct dc_state *context) 2981{ 2982 struct dce_hwseq *hws = dc->hwseq; 2983 struct hubp *hubp = pipe_ctx->plane_res.hubp; 2984 struct dpp *dpp = pipe_ctx->plane_res.dpp; 2985 struct dc_plane_state *plane_state = pipe_ctx->plane_state; 2986 struct plane_size size = plane_state->plane_size; 2987 unsigned int compat_level = 0; 2988 bool should_divided_by_2 = false; 2989 2990 /* depends on DML calculation, DPP clock value may change dynamically */ 2991 /* If request max dpp clk is lower than current dispclk, no need to 2992 * divided by 2 2993 */ 2994 if (plane_state->update_flags.bits.full_update) { 2995 2996 /* new calculated dispclk, dppclk are stored in 2997 * context->bw_ctx.bw.dcn.clk.dispclk_khz / dppclk_khz. current 2998 * dispclk, dppclk are from dc->clk_mgr->clks.dispclk_khz. 2999 * dcn10_validate_bandwidth compute new dispclk, dppclk. 3000 * dispclk will put in use after optimize_bandwidth when 3001 * ramp_up_dispclk_with_dpp is called. 3002 * there are two places for dppclk be put in use. One location 3003 * is the same as the location as dispclk. Another is within 3004 * update_dchubp_dpp which happens between pre_bandwidth and 3005 * optimize_bandwidth. 3006 * dppclk updated within update_dchubp_dpp will cause new 3007 * clock values of dispclk and dppclk not be in use at the same 3008 * time. when clocks are decreased, this may cause dppclk is 3009 * lower than previous configuration and let pipe stuck. 3010 * for example, eDP + external dp, change resolution of DP from 3011 * 1920x1080x144hz to 1280x960x60hz. 3012 * before change: dispclk = 337889 dppclk = 337889 3013 * change mode, dcn10_validate_bandwidth calculate 3014 * dispclk = 143122 dppclk = 143122 3015 * update_dchubp_dpp be executed before dispclk be updated, 3016 * dispclk = 337889, but dppclk use new value dispclk /2 = 3017 * 168944. this will cause pipe pstate warning issue. 3018 * solution: between pre_bandwidth and optimize_bandwidth, while 3019 * dispclk is going to be decreased, keep dppclk = dispclk 3020 **/ 3021 if (context->bw_ctx.bw.dcn.clk.dispclk_khz < 3022 dc->clk_mgr->clks.dispclk_khz) 3023 should_divided_by_2 = false; 3024 else 3025 should_divided_by_2 = 3026 context->bw_ctx.bw.dcn.clk.dppclk_khz <= 3027 dc->clk_mgr->clks.dispclk_khz / 2; 3028 3029 dpp->funcs->dpp_dppclk_control( 3030 dpp, 3031 should_divided_by_2, 3032 true); 3033 3034 if (dc->res_pool->dccg) 3035 dc->res_pool->dccg->funcs->update_dpp_dto( 3036 dc->res_pool->dccg, 3037 dpp->inst, 3038 pipe_ctx->plane_res.bw.dppclk_khz); 3039 else 3040 dc->clk_mgr->clks.dppclk_khz = should_divided_by_2 ? 3041 dc->clk_mgr->clks.dispclk_khz / 2 : 3042 dc->clk_mgr->clks.dispclk_khz; 3043 } 3044 3045 /* TODO: Need input parameter to tell current DCHUB pipe tie to which OTG 3046 * VTG is within DCHUBBUB which is commond block share by each pipe HUBP. 3047 * VTG is 1:1 mapping with OTG. Each pipe HUBP will select which VTG 3048 */ 3049 if (plane_state->update_flags.bits.full_update) { 3050 hubp->funcs->hubp_vtg_sel(hubp, pipe_ctx->stream_res.tg->inst); 3051 3052 hubp->funcs->hubp_setup( 3053 hubp, 3054 &pipe_ctx->dlg_regs, 3055 &pipe_ctx->ttu_regs, 3056 &pipe_ctx->rq_regs, 3057 &pipe_ctx->pipe_dlg_param); 3058 hubp->funcs->hubp_setup_interdependent( 3059 hubp, 3060 &pipe_ctx->dlg_regs, 3061 &pipe_ctx->ttu_regs); 3062 } 3063 3064 size.surface_size = pipe_ctx->plane_res.scl_data.viewport; 3065 3066 if (plane_state->update_flags.bits.full_update || 3067 plane_state->update_flags.bits.bpp_change) 3068 dcn10_update_dpp(dpp, plane_state); 3069 3070 if (plane_state->update_flags.bits.full_update || 3071 plane_state->update_flags.bits.per_pixel_alpha_change || 3072 plane_state->update_flags.bits.global_alpha_change) 3073 hws->funcs.update_mpcc(dc, pipe_ctx); 3074 3075 if (plane_state->update_flags.bits.full_update || 3076 plane_state->update_flags.bits.per_pixel_alpha_change || 3077 plane_state->update_flags.bits.global_alpha_change || 3078 plane_state->update_flags.bits.scaling_change || 3079 plane_state->update_flags.bits.position_change) { 3080 update_scaler(pipe_ctx); 3081 } 3082 3083 if (plane_state->update_flags.bits.full_update || 3084 plane_state->update_flags.bits.scaling_change || 3085 plane_state->update_flags.bits.position_change) { 3086 hubp->funcs->mem_program_viewport( 3087 hubp, 3088 &pipe_ctx->plane_res.scl_data.viewport, 3089 &pipe_ctx->plane_res.scl_data.viewport_c); 3090 } 3091 3092 if (pipe_ctx->stream->cursor_attributes.address.quad_part != 0) { 3093 if (dc->hwss.abort_cursor_offload_update) 3094 dc->hwss.abort_cursor_offload_update(dc, pipe_ctx); 3095 3096 dc->hwss.set_cursor_attribute(pipe_ctx); 3097 dc->hwss.set_cursor_position(pipe_ctx); 3098 3099 if (dc->hwss.set_cursor_sdr_white_level) 3100 dc->hwss.set_cursor_sdr_white_level(pipe_ctx); 3101 } 3102 3103 if (plane_state->update_flags.bits.full_update) { 3104 /*gamut remap*/ 3105 dc->hwss.program_gamut_remap(pipe_ctx); 3106 3107 dc->hwss.program_output_csc(dc, 3108 pipe_ctx, 3109 pipe_ctx->stream->output_color_space, 3110 pipe_ctx->stream->csc_color_matrix.matrix, 3111 pipe_ctx->stream_res.opp->inst); 3112 } 3113 3114 if (plane_state->update_flags.bits.full_update || 3115 plane_state->update_flags.bits.pixel_format_change || 3116 plane_state->update_flags.bits.horizontal_mirror_change || 3117 plane_state->update_flags.bits.rotation_change || 3118 plane_state->update_flags.bits.swizzle_change || 3119 plane_state->update_flags.bits.dcc_change || 3120 plane_state->update_flags.bits.bpp_change || 3121 plane_state->update_flags.bits.scaling_change || 3122 plane_state->update_flags.bits.plane_size_change) { 3123 hubp->funcs->hubp_program_surface_config( 3124 hubp, 3125 plane_state->format, 3126 &plane_state->tiling_info, 3127 &size, 3128 plane_state->rotation, 3129 &plane_state->dcc, 3130 plane_state->horizontal_mirror, 3131 compat_level); 3132 } 3133 3134 hubp->power_gated = false; 3135 3136 dc->hwss.update_plane_addr(dc, pipe_ctx); 3137 3138 if (is_pipe_tree_visible(pipe_ctx)) 3139 hubp->funcs->set_blank(hubp, false); 3140} 3141 3142void dcn10_blank_pixel_data( 3143 struct dc *dc, 3144 struct pipe_ctx *pipe_ctx, 3145 bool blank) 3146{ 3147 enum dc_color_space color_space; 3148 struct tg_color black_color = {0}; 3149 struct stream_resource *stream_res = &pipe_ctx->stream_res; 3150 struct dc_stream_state *stream = pipe_ctx->stream; 3151 3152 /* program otg blank color */ 3153 color_space = stream->output_color_space; 3154 color_space_to_black_color(dc, color_space, &black_color); 3155 3156 /* 3157 * The way 420 is packed, 2 channels carry Y component, 1 channel 3158 * alternate between Cb and Cr, so both channels need the pixel 3159 * value for Y 3160 */ 3161 if (stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR420) 3162 black_color.color_r_cr = black_color.color_g_y; 3163 3164 3165 if (stream_res->tg->funcs->set_blank_color) 3166 stream_res->tg->funcs->set_blank_color( 3167 stream_res->tg, 3168 &black_color); 3169 3170 if (!blank) { 3171 if (stream_res->tg->funcs->set_blank) 3172 stream_res->tg->funcs->set_blank(stream_res->tg, blank); 3173 if (stream_res->abm) { 3174 dc->hwss.set_pipe(pipe_ctx); 3175 stream_res->abm->funcs->set_abm_level(stream_res->abm, stream->abm_level); 3176 } 3177 } else { 3178 dc->hwss.set_abm_immediate_disable(pipe_ctx); 3179 if (stream_res->tg->funcs->set_blank) { 3180 stream_res->tg->funcs->wait_for_state(stream_res->tg, CRTC_STATE_VBLANK); 3181 stream_res->tg->funcs->set_blank(stream_res->tg, blank); 3182 } 3183 } 3184} 3185 3186void dcn10_set_hdr_multiplier(struct pipe_ctx *pipe_ctx) 3187{ 3188 struct fixed31_32 multiplier = pipe_ctx->plane_state->hdr_mult; 3189 uint32_t hw_mult = 0x1f000; // 1.0 default multiplier 3190 struct custom_float_format fmt; 3191 3192 fmt.exponenta_bits = 6; 3193 fmt.mantissa_bits = 12; 3194 fmt.sign = true; 3195 3196 3197 if (!dc_fixpt_eq(multiplier, dc_fixpt_from_int(0))) // check != 0 3198 convert_to_custom_float_format(multiplier, &fmt, &hw_mult); 3199 3200 pipe_ctx->plane_res.dpp->funcs->dpp_set_hdr_multiplier( 3201 pipe_ctx->plane_res.dpp, hw_mult); 3202} 3203 3204void dcn10_program_pipe( 3205 struct dc *dc, 3206 struct pipe_ctx *pipe_ctx, 3207 struct dc_state *context) 3208{ 3209 struct dce_hwseq *hws = dc->hwseq; 3210 3211 if (pipe_ctx->top_pipe == NULL) { 3212 bool blank = !is_pipe_tree_visible(pipe_ctx); 3213 3214 pipe_ctx->stream_res.tg->funcs->program_global_sync( 3215 pipe_ctx->stream_res.tg, 3216 calculate_vready_offset_for_group(pipe_ctx), 3217 pipe_ctx->pipe_dlg_param.vstartup_start, 3218 pipe_ctx->pipe_dlg_param.vupdate_offset, 3219 pipe_ctx->pipe_dlg_param.vupdate_width, 3220 pipe_ctx->pipe_dlg_param.pstate_keepout); 3221 3222 pipe_ctx->stream_res.tg->funcs->set_vtg_params( 3223 pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing, true); 3224 3225 if (hws->funcs.setup_vupdate_interrupt) 3226 hws->funcs.setup_vupdate_interrupt(dc, pipe_ctx); 3227 3228 hws->funcs.blank_pixel_data(dc, pipe_ctx, blank); 3229 } 3230 3231 if (pipe_ctx->plane_state->update_flags.bits.full_update) 3232 dcn10_enable_plane(dc, pipe_ctx, context); 3233 3234 dcn10_update_dchubp_dpp(dc, pipe_ctx, context); 3235 3236 hws->funcs.set_hdr_multiplier(pipe_ctx); 3237 3238 if (pipe_ctx->plane_state->update_flags.bits.full_update || 3239 pipe_ctx->plane_state->update_flags.bits.in_transfer_func_change || 3240 pipe_ctx->plane_state->update_flags.bits.gamma_change) 3241 hws->funcs.set_input_transfer_func(dc, pipe_ctx, pipe_ctx->plane_state); 3242 3243 /* dcn10_translate_regamma_to_hw_format takes 750us to finish 3244 * only do gamma programming for full update. 3245 * TODO: This can be further optimized/cleaned up 3246 * Always call this for now since it does memcmp inside before 3247 * doing heavy calculation and programming 3248 */ 3249 if (pipe_ctx->plane_state->update_flags.bits.full_update) 3250 hws->funcs.set_output_transfer_func(dc, pipe_ctx, pipe_ctx->stream); 3251} 3252 3253void dcn10_wait_for_pending_cleared(struct dc *dc, 3254 struct dc_state *context) 3255{ 3256 struct pipe_ctx *pipe_ctx; 3257 struct timing_generator *tg; 3258 int i; 3259 3260 for (i = 0; i < dc->res_pool->pipe_count; i++) { 3261 pipe_ctx = &context->res_ctx.pipe_ctx[i]; 3262 tg = pipe_ctx->stream_res.tg; 3263 3264 /* 3265 * Only wait for top pipe's tg penindg bit 3266 * Also skip if pipe is disabled. 3267 */ 3268 if (pipe_ctx->top_pipe || 3269 !pipe_ctx->stream || !pipe_ctx->plane_state || 3270 !tg->funcs->is_tg_enabled(tg)) 3271 continue; 3272 3273 /* 3274 * Wait for VBLANK then VACTIVE to ensure we get VUPDATE. 3275 * For some reason waiting for OTG_UPDATE_PENDING cleared 3276 * seems to not trigger the update right away, and if we 3277 * lock again before VUPDATE then we don't get a separated 3278 * operation. 3279 */ 3280 pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VBLANK); 3281 pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VACTIVE); 3282 } 3283} 3284 3285void dcn10_post_unlock_program_front_end( 3286 struct dc *dc, 3287 struct dc_state *context) 3288{ 3289 int i; 3290 3291 for (i = 0; i < dc->res_pool->pipe_count; i++) { 3292 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; 3293 3294 if (!pipe_ctx->top_pipe && 3295 !pipe_ctx->prev_odm_pipe && 3296 pipe_ctx->stream) { 3297 struct timing_generator *tg = pipe_ctx->stream_res.tg; 3298 3299 if (context->stream_status[i].plane_count == 0) 3300 false_optc_underflow_wa(dc, pipe_ctx->stream, tg); 3301 } 3302 } 3303 3304 for (i = 0; i < dc->res_pool->pipe_count; i++) 3305 if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable) 3306 dc->hwss.disable_plane(dc, dc->current_state, &dc->current_state->res_ctx.pipe_ctx[i]); 3307 3308 for (i = 0; i < dc->res_pool->pipe_count; i++) 3309 if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable) { 3310 dc->hwss.optimize_bandwidth(dc, context); 3311 break; 3312 } 3313 3314 if (dc->hwseq->wa.DEGVIDCN10_254) 3315 hubbub1_wm_change_req_wa(dc->res_pool->hubbub); 3316} 3317 3318static void dcn10_stereo_hw_frame_pack_wa(struct dc *dc, struct dc_state *context) 3319{ 3320 uint8_t i; 3321 3322 for (i = 0; i < context->stream_count; i++) { 3323 if (context->streams[i]->timing.timing_3d_format 3324 == TIMING_3D_FORMAT_HW_FRAME_PACKING) { 3325 /* 3326 * Disable stutter 3327 */ 3328 hubbub1_allow_self_refresh_control(dc->res_pool->hubbub, false); 3329 break; 3330 } 3331 } 3332} 3333 3334void dcn10_prepare_bandwidth( 3335 struct dc *dc, 3336 struct dc_state *context) 3337{ 3338 struct dce_hwseq *hws = dc->hwseq; 3339 struct hubbub *hubbub = dc->res_pool->hubbub; 3340 int min_fclk_khz, min_dcfclk_khz, socclk_khz; 3341 3342 if (dc->debug.sanity_checks) 3343 hws->funcs.verify_allow_pstate_change_high(dc); 3344 3345 if (context->stream_count == 0) 3346 context->bw_ctx.bw.dcn.clk.phyclk_khz = 0; 3347 3348 dc->clk_mgr->funcs->update_clocks( 3349 dc->clk_mgr, 3350 context, 3351 false); 3352 3353 dc->optimized_required = hubbub->funcs->program_watermarks(hubbub, 3354 &context->bw_ctx.bw.dcn.watermarks, 3355 dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000, 3356 true); 3357 dcn10_stereo_hw_frame_pack_wa(dc, context); 3358 3359 if (dc->debug.pplib_wm_report_mode == WM_REPORT_OVERRIDE) { 3360 DC_FP_START(); 3361 dcn_get_soc_clks( 3362 dc, &min_fclk_khz, &min_dcfclk_khz, &socclk_khz); 3363 DC_FP_END(); 3364 dcn_bw_notify_pplib_of_wm_ranges( 3365 dc, min_fclk_khz, min_dcfclk_khz, socclk_khz); 3366 } 3367 3368 if (dc->debug.sanity_checks) 3369 hws->funcs.verify_allow_pstate_change_high(dc); 3370} 3371 3372void dcn10_optimize_bandwidth( 3373 struct dc *dc, 3374 struct dc_state *context) 3375{ 3376 struct dce_hwseq *hws = dc->hwseq; 3377 struct hubbub *hubbub = dc->res_pool->hubbub; 3378 int min_fclk_khz, min_dcfclk_khz, socclk_khz; 3379 3380 if (dc->debug.sanity_checks) 3381 hws->funcs.verify_allow_pstate_change_high(dc); 3382 3383 if (context->stream_count == 0) 3384 context->bw_ctx.bw.dcn.clk.phyclk_khz = 0; 3385 3386 dc->clk_mgr->funcs->update_clocks( 3387 dc->clk_mgr, 3388 context, 3389 true); 3390 3391 hubbub->funcs->program_watermarks(hubbub, 3392 &context->bw_ctx.bw.dcn.watermarks, 3393 dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000, 3394 true); 3395 3396 dcn10_stereo_hw_frame_pack_wa(dc, context); 3397 3398 if (dc->debug.pplib_wm_report_mode == WM_REPORT_OVERRIDE) { 3399 DC_FP_START(); 3400 dcn_get_soc_clks( 3401 dc, &min_fclk_khz, &min_dcfclk_khz, &socclk_khz); 3402 DC_FP_END(); 3403 dcn_bw_notify_pplib_of_wm_ranges( 3404 dc, min_fclk_khz, min_dcfclk_khz, socclk_khz); 3405 } 3406 3407 if (dc->debug.sanity_checks) 3408 hws->funcs.verify_allow_pstate_change_high(dc); 3409} 3410 3411void dcn10_set_drr(struct pipe_ctx **pipe_ctx, 3412 int num_pipes, struct dc_crtc_timing_adjust adjust) 3413{ 3414 int i = 0; 3415 struct drr_params params = {0}; 3416 // DRR set trigger event mapped to OTG_TRIG_A (bit 11) for manual control flow 3417 unsigned int event_triggers = 0x800; 3418 // Note DRR trigger events are generated regardless of whether num frames met. 3419 unsigned int num_frames = 2; 3420 3421 params.vertical_total_max = adjust.v_total_max; 3422 params.vertical_total_min = adjust.v_total_min; 3423 params.vertical_total_mid = adjust.v_total_mid; 3424 params.vertical_total_mid_frame_num = adjust.v_total_mid_frame_num; 3425 /* TODO: If multiple pipes are to be supported, you need 3426 * some GSL stuff. Static screen triggers may be programmed differently 3427 * as well. 3428 */ 3429 for (i = 0; i < num_pipes; i++) { 3430 /* dc_state_destruct() might null the stream resources, so fetch tg 3431 * here first to avoid a race condition. The lifetime of the pointee 3432 * itself (the timing_generator object) is not a problem here. 3433 */ 3434 struct timing_generator *tg = pipe_ctx[i]->stream_res.tg; 3435 3436 if ((tg != NULL) && tg->funcs) { 3437 set_drr_and_clear_adjust_pending(pipe_ctx[i], pipe_ctx[i]->stream, ¶ms); 3438 if (adjust.v_total_max != 0 && adjust.v_total_min != 0) 3439 if (tg->funcs->set_static_screen_control) 3440 tg->funcs->set_static_screen_control( 3441 tg, event_triggers, num_frames); 3442 } 3443 } 3444} 3445 3446void dcn10_get_position(struct pipe_ctx **pipe_ctx, 3447 int num_pipes, 3448 struct crtc_position *position) 3449{ 3450 int i = 0; 3451 3452 /* TODO: handle pipes > 1 3453 */ 3454 for (i = 0; i < num_pipes; i++) 3455 pipe_ctx[i]->stream_res.tg->funcs->get_position(pipe_ctx[i]->stream_res.tg, position); 3456} 3457 3458void dcn10_set_static_screen_control(struct pipe_ctx **pipe_ctx, 3459 int num_pipes, const struct dc_static_screen_params *params) 3460{ 3461 unsigned int i; 3462 unsigned int triggers = 0; 3463 3464 if (params->triggers.surface_update) 3465 triggers |= 0x80; 3466 if (params->triggers.cursor_update) 3467 triggers |= 0x2; 3468 if (params->triggers.force_trigger) 3469 triggers |= 0x1; 3470 3471 for (i = 0; i < num_pipes; i++) 3472 pipe_ctx[i]->stream_res.tg->funcs-> 3473 set_static_screen_control(pipe_ctx[i]->stream_res.tg, 3474 triggers, params->num_frames); 3475} 3476 3477static void dcn10_config_stereo_parameters( 3478 struct dc_stream_state *stream, struct crtc_stereo_flags *flags) 3479{ 3480 enum view_3d_format view_format = stream->view_format; 3481 enum dc_timing_3d_format timing_3d_format =\ 3482 stream->timing.timing_3d_format; 3483 bool non_stereo_timing = false; 3484 3485 if (timing_3d_format == TIMING_3D_FORMAT_NONE || 3486 timing_3d_format == TIMING_3D_FORMAT_SIDE_BY_SIDE || 3487 timing_3d_format == TIMING_3D_FORMAT_TOP_AND_BOTTOM) 3488 non_stereo_timing = true; 3489 3490 if (non_stereo_timing == false && 3491 view_format == VIEW_3D_FORMAT_FRAME_SEQUENTIAL) { 3492 3493 flags->PROGRAM_STEREO = 1; 3494 flags->PROGRAM_POLARITY = 1; 3495 if (timing_3d_format == TIMING_3D_FORMAT_FRAME_ALTERNATE || 3496 timing_3d_format == TIMING_3D_FORMAT_INBAND_FA || 3497 timing_3d_format == TIMING_3D_FORMAT_DP_HDMI_INBAND_FA || 3498 timing_3d_format == TIMING_3D_FORMAT_SIDEBAND_FA) { 3499 3500 if (stream->link && stream->link->ddc) { 3501 enum display_dongle_type dongle = \ 3502 stream->link->ddc->dongle_type; 3503 3504 if (dongle == DISPLAY_DONGLE_DP_VGA_CONVERTER || 3505 dongle == DISPLAY_DONGLE_DP_DVI_CONVERTER || 3506 dongle == DISPLAY_DONGLE_DP_HDMI_CONVERTER) 3507 flags->DISABLE_STEREO_DP_SYNC = 1; 3508 } 3509 } 3510 flags->RIGHT_EYE_POLARITY =\ 3511 stream->timing.flags.RIGHT_EYE_3D_POLARITY; 3512 if (timing_3d_format == TIMING_3D_FORMAT_HW_FRAME_PACKING) 3513 flags->FRAME_PACKED = 1; 3514 } 3515 3516 return; 3517} 3518 3519void dcn10_setup_stereo(struct pipe_ctx *pipe_ctx, struct dc *dc) 3520{ 3521 struct crtc_stereo_flags flags = { 0 }; 3522 struct dc_stream_state *stream = pipe_ctx->stream; 3523 3524 dcn10_config_stereo_parameters(stream, &flags); 3525 3526 if (stream->timing.timing_3d_format == TIMING_3D_FORMAT_SIDEBAND_FA) { 3527 if (!dc_set_generic_gpio_for_stereo(true, dc->ctx->gpio_service)) 3528 dc_set_generic_gpio_for_stereo(false, dc->ctx->gpio_service); 3529 } else { 3530 dc_set_generic_gpio_for_stereo(false, dc->ctx->gpio_service); 3531 } 3532 3533 pipe_ctx->stream_res.opp->funcs->opp_program_stereo( 3534 pipe_ctx->stream_res.opp, 3535 flags.PROGRAM_STEREO == 1, 3536 &stream->timing); 3537 3538 pipe_ctx->stream_res.tg->funcs->program_stereo( 3539 pipe_ctx->stream_res.tg, 3540 &stream->timing, 3541 &flags); 3542 3543 return; 3544} 3545 3546static struct hubp *get_hubp_by_inst(struct resource_pool *res_pool, int mpcc_inst) 3547{ 3548 int i; 3549 3550 for (i = 0; i < res_pool->pipe_count; i++) { 3551 if (res_pool->hubps[i]->inst == mpcc_inst) 3552 return res_pool->hubps[i]; 3553 } 3554 ASSERT(false); 3555 return NULL; 3556} 3557 3558void dcn10_wait_for_mpcc_disconnect( 3559 struct dc *dc, 3560 struct resource_pool *res_pool, 3561 struct pipe_ctx *pipe_ctx) 3562{ 3563 struct dce_hwseq *hws = dc->hwseq; 3564 int mpcc_inst; 3565 3566 if (dc->debug.sanity_checks) { 3567 hws->funcs.verify_allow_pstate_change_high(dc); 3568 } 3569 3570 if (!pipe_ctx->stream_res.opp) 3571 return; 3572 3573 for (mpcc_inst = 0; mpcc_inst < MAX_PIPES; mpcc_inst++) { 3574 if (pipe_ctx->stream_res.opp->mpcc_disconnect_pending[mpcc_inst]) { 3575 struct hubp *hubp = get_hubp_by_inst(res_pool, mpcc_inst); 3576 3577 if (pipe_ctx->stream_res.tg && 3578 pipe_ctx->stream_res.tg->funcs->is_tg_enabled(pipe_ctx->stream_res.tg)) 3579 res_pool->mpc->funcs->wait_for_idle(res_pool->mpc, mpcc_inst); 3580 pipe_ctx->stream_res.opp->mpcc_disconnect_pending[mpcc_inst] = false; 3581 hubp->funcs->set_blank(hubp, true); 3582 } 3583 } 3584 3585 if (dc->debug.sanity_checks) { 3586 hws->funcs.verify_allow_pstate_change_high(dc); 3587 } 3588 3589} 3590 3591bool dcn10_dummy_display_power_gating( 3592 struct dc *dc, 3593 uint8_t controller_id, 3594 struct dc_bios *dcb, 3595 enum pipe_gating_control power_gating) 3596{ 3597 return true; 3598} 3599 3600void dcn10_update_pending_status(struct pipe_ctx *pipe_ctx) 3601{ 3602 struct dc_plane_state *plane_state = pipe_ctx->plane_state; 3603 struct timing_generator *tg = pipe_ctx->stream_res.tg; 3604 bool flip_pending; 3605 struct dc *dc = pipe_ctx->stream->ctx->dc; 3606 3607 if (plane_state == NULL) 3608 return; 3609 3610 flip_pending = pipe_ctx->plane_res.hubp->funcs->hubp_is_flip_pending( 3611 pipe_ctx->plane_res.hubp); 3612 3613 plane_state->status.is_flip_pending = plane_state->status.is_flip_pending || flip_pending; 3614 3615 if (!flip_pending) 3616 plane_state->status.current_address = plane_state->status.requested_address; 3617 3618 if (plane_state->status.current_address.type == PLN_ADDR_TYPE_GRPH_STEREO && 3619 tg->funcs->is_stereo_left_eye) { 3620 plane_state->status.is_right_eye = 3621 !tg->funcs->is_stereo_left_eye(pipe_ctx->stream_res.tg); 3622 } 3623 3624 if (dc->hwseq->wa_state.disallow_self_refresh_during_multi_plane_transition_applied) { 3625 struct dce_hwseq *hwseq = dc->hwseq; 3626 struct timing_generator *tg = dc->res_pool->timing_generators[0]; 3627 unsigned int cur_frame = tg->funcs->get_frame_count(tg); 3628 3629 if (cur_frame != hwseq->wa_state.disallow_self_refresh_during_multi_plane_transition_applied_on_frame) { 3630 struct hubbub *hubbub = dc->res_pool->hubbub; 3631 3632 hubbub->funcs->allow_self_refresh_control(hubbub, !dc->debug.disable_stutter); 3633 hwseq->wa_state.disallow_self_refresh_during_multi_plane_transition_applied = false; 3634 } 3635 } 3636} 3637 3638void dcn10_update_dchub(struct dce_hwseq *hws, struct dchub_init_data *dh_data) 3639{ 3640 struct hubbub *hubbub = hws->ctx->dc->res_pool->hubbub; 3641 3642 /* In DCN, this programming sequence is owned by the hubbub */ 3643 hubbub->funcs->update_dchub(hubbub, dh_data); 3644} 3645 3646void dcn10_set_cursor_position(struct pipe_ctx *pipe_ctx) 3647{ 3648 struct dc_cursor_position pos_cpy = pipe_ctx->stream->cursor_position; 3649 struct hubp *hubp = pipe_ctx->plane_res.hubp; 3650 struct dpp *dpp = pipe_ctx->plane_res.dpp; 3651 struct dc_cursor_mi_param param = { 3652 .pixel_clk_khz = pipe_ctx->stream->timing.pix_clk_100hz / 10, 3653 .ref_clk_khz = pipe_ctx->stream->ctx->dc->res_pool->ref_clocks.dchub_ref_clock_inKhz, 3654 .viewport = pipe_ctx->plane_res.scl_data.viewport, 3655 .h_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.horz, 3656 .v_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.vert, 3657 .rotation = pipe_ctx->plane_state->rotation, 3658 .mirror = pipe_ctx->plane_state->horizontal_mirror, 3659 .stream = pipe_ctx->stream, 3660 }; 3661 bool pipe_split_on = false; 3662 bool odm_combine_on = (pipe_ctx->next_odm_pipe != NULL) || 3663 (pipe_ctx->prev_odm_pipe != NULL); 3664 3665 int x_plane = pipe_ctx->plane_state->dst_rect.x; 3666 int y_plane = pipe_ctx->plane_state->dst_rect.y; 3667 int x_pos = pos_cpy.x; 3668 int y_pos = pos_cpy.y; 3669 int clip_x = pipe_ctx->plane_state->clip_rect.x; 3670 int clip_width = pipe_ctx->plane_state->clip_rect.width; 3671 3672 if ((pipe_ctx->top_pipe != NULL) || (pipe_ctx->bottom_pipe != NULL)) { 3673 if ((pipe_ctx->plane_state->src_rect.width != pipe_ctx->plane_res.scl_data.viewport.width) || 3674 (pipe_ctx->plane_state->src_rect.height != pipe_ctx->plane_res.scl_data.viewport.height)) { 3675 pipe_split_on = true; 3676 } 3677 } 3678 3679 /** 3680 * DC cursor is stream space, HW cursor is plane space and drawn 3681 * as part of the framebuffer. 3682 * 3683 * Cursor position can't be negative, but hotspot can be used to 3684 * shift cursor out of the plane bounds. Hotspot must be smaller 3685 * than the cursor size. 3686 */ 3687 3688 /** 3689 * Translate cursor and clip offset from stream space to plane space. 3690 * 3691 * If the cursor is scaled then we need to scale the position 3692 * to be in the approximately correct place. We can't do anything 3693 * about the actual size being incorrect, that's a limitation of 3694 * the hardware. 3695 */ 3696 if (param.rotation == ROTATION_ANGLE_90 || param.rotation == ROTATION_ANGLE_270) { 3697 x_pos = (x_pos - x_plane) * pipe_ctx->plane_state->src_rect.height / 3698 pipe_ctx->plane_state->dst_rect.width; 3699 y_pos = (y_pos - y_plane) * pipe_ctx->plane_state->src_rect.width / 3700 pipe_ctx->plane_state->dst_rect.height; 3701 } else { 3702 x_pos = (x_pos - x_plane) * pipe_ctx->plane_state->src_rect.width / 3703 pipe_ctx->plane_state->dst_rect.width; 3704 y_pos = (y_pos - y_plane) * pipe_ctx->plane_state->src_rect.height / 3705 pipe_ctx->plane_state->dst_rect.height; 3706 clip_x = (clip_x - x_plane) * pipe_ctx->plane_state->src_rect.width / 3707 pipe_ctx->plane_state->dst_rect.width; 3708 clip_width = clip_width * pipe_ctx->plane_state->src_rect.width / 3709 pipe_ctx->plane_state->dst_rect.width; 3710 } 3711 3712 /** 3713 * If the cursor's source viewport is clipped then we need to 3714 * translate the cursor to appear in the correct position on 3715 * the screen. 3716 * 3717 * This translation isn't affected by scaling so it needs to be 3718 * done *after* we adjust the position for the scale factor. 3719 * 3720 * This is only done by opt-in for now since there are still 3721 * some usecases like tiled display that might enable the 3722 * cursor on both streams while expecting dc to clip it. 3723 */ 3724 if (pos_cpy.translate_by_source) { 3725 x_pos += pipe_ctx->plane_state->src_rect.x; 3726 y_pos += pipe_ctx->plane_state->src_rect.y; 3727 } 3728 3729 /** 3730 * If the position is negative then we need to add to the hotspot 3731 * to shift the cursor outside the plane. 3732 */ 3733 3734 if (x_pos < 0) { 3735 pos_cpy.x_hotspot -= x_pos; 3736 x_pos = 0; 3737 } 3738 3739 if (y_pos < 0) { 3740 pos_cpy.y_hotspot -= y_pos; 3741 y_pos = 0; 3742 } 3743 3744 pos_cpy.x = (uint32_t)x_pos; 3745 pos_cpy.y = (uint32_t)y_pos; 3746 3747 if (pipe_ctx->plane_state->address.type 3748 == PLN_ADDR_TYPE_VIDEO_PROGRESSIVE) 3749 pos_cpy.enable = false; 3750 3751 if (pos_cpy.enable && resource_can_pipe_disable_cursor(pipe_ctx)) 3752 pos_cpy.enable = false; 3753 3754 3755 if (param.rotation == ROTATION_ANGLE_0) { 3756 3757 if (param.mirror) { 3758 /* 3759 * The plane is split into multiple viewports. 3760 * The combination of all viewports span the 3761 * entirety of the clip rect. 3762 * 3763 * For no pipe_split, viewport_width is represents 3764 * the full width of the clip_rect, so we can just 3765 * mirror it. 3766 */ 3767 pos_cpy.x = clip_width - pos_cpy.x + 2 * clip_x; 3768 } 3769 } 3770 // Swap axis and mirror horizontally 3771 else if (param.rotation == ROTATION_ANGLE_90) { 3772 uint32_t temp_x = pos_cpy.x; 3773 3774 pos_cpy.x = pipe_ctx->plane_res.scl_data.viewport.width - 3775 (pos_cpy.y - pipe_ctx->plane_res.scl_data.viewport.x) + pipe_ctx->plane_res.scl_data.viewport.x; 3776 pos_cpy.y = temp_x; 3777 } 3778 // Swap axis and mirror vertically 3779 else if (param.rotation == ROTATION_ANGLE_270) { 3780 uint32_t temp_y = pos_cpy.y; 3781 int viewport_height = 3782 pipe_ctx->plane_res.scl_data.viewport.height; 3783 int viewport_y = 3784 pipe_ctx->plane_res.scl_data.viewport.y; 3785 3786 /** 3787 * Display groups that are 1xnY, have pos_cpy.x > 2 * viewport.height 3788 * For pipe split cases: 3789 * - apply offset of viewport.y to normalize pos_cpy.x 3790 * - calculate the pos_cpy.y as before 3791 * - shift pos_cpy.y back by same offset to get final value 3792 * - since we iterate through both pipes, use the lower 3793 * viewport.y for offset 3794 * For non pipe split cases, use the same calculation for 3795 * pos_cpy.y as the 180 degree rotation case below, 3796 * but use pos_cpy.x as our input because we are rotating 3797 * 270 degrees 3798 */ 3799 if (pipe_split_on || odm_combine_on) { 3800 int pos_cpy_x_offset; 3801 int other_pipe_viewport_y; 3802 3803 if (pipe_split_on) { 3804 if (pipe_ctx->bottom_pipe) { 3805 other_pipe_viewport_y = 3806 pipe_ctx->bottom_pipe->plane_res.scl_data.viewport.y; 3807 } else { 3808 other_pipe_viewport_y = 3809 pipe_ctx->top_pipe->plane_res.scl_data.viewport.y; 3810 } 3811 } else { 3812 if (pipe_ctx->next_odm_pipe) { 3813 other_pipe_viewport_y = 3814 pipe_ctx->next_odm_pipe->plane_res.scl_data.viewport.y; 3815 } else { 3816 other_pipe_viewport_y = 3817 pipe_ctx->prev_odm_pipe->plane_res.scl_data.viewport.y; 3818 } 3819 } 3820 pos_cpy_x_offset = (viewport_y > other_pipe_viewport_y) ? 3821 other_pipe_viewport_y : viewport_y; 3822 pos_cpy.x -= pos_cpy_x_offset; 3823 if (pos_cpy.x > viewport_height) { 3824 pos_cpy.x = pos_cpy.x - viewport_height; 3825 pos_cpy.y = viewport_height - pos_cpy.x; 3826 } else { 3827 pos_cpy.y = 2 * viewport_height - pos_cpy.x; 3828 } 3829 pos_cpy.y += pos_cpy_x_offset; 3830 } else { 3831 pos_cpy.y = (2 * viewport_y) + viewport_height - pos_cpy.x; 3832 } 3833 pos_cpy.x = temp_y; 3834 } 3835 // Mirror horizontally and vertically 3836 else if (param.rotation == ROTATION_ANGLE_180) { 3837 if (!param.mirror) { 3838 /* 3839 * The plane is split into multiple viewports. 3840 * The combination of all viewports span the 3841 * entirety of the clip rect. 3842 * 3843 * For no pipe_split, viewport_width is represents 3844 * the full width of the clip_rect, so we can just 3845 * mirror it. 3846 */ 3847 pos_cpy.x = clip_width - pos_cpy.x + 2 * clip_x; 3848 } 3849 3850 /** 3851 * Display groups that are 1xnY, have pos_cpy.y > viewport.height 3852 * Calculation: 3853 * delta_from_bottom = viewport.y + viewport.height - pos_cpy.y 3854 * pos_cpy.y_new = viewport.y + delta_from_bottom 3855 * Simplify it as: 3856 * pos_cpy.y = viewport.y * 2 + viewport.height - pos_cpy.y 3857 */ 3858 pos_cpy.y = (2 * pipe_ctx->plane_res.scl_data.viewport.y) + 3859 pipe_ctx->plane_res.scl_data.viewport.height - pos_cpy.y; 3860 } 3861 3862 hubp->funcs->set_cursor_position(hubp, &pos_cpy, ¶m); 3863 dpp->funcs->set_cursor_position(dpp, &pos_cpy, ¶m, hubp->curs_attr.width, hubp->curs_attr.height); 3864} 3865 3866void dcn10_set_cursor_attribute(struct pipe_ctx *pipe_ctx) 3867{ 3868 struct dc_cursor_attributes *attributes = &pipe_ctx->stream->cursor_attributes; 3869 3870 pipe_ctx->plane_res.hubp->funcs->set_cursor_attributes( 3871 pipe_ctx->plane_res.hubp, attributes); 3872 pipe_ctx->plane_res.dpp->funcs->set_cursor_attributes( 3873 pipe_ctx->plane_res.dpp, attributes); 3874} 3875 3876void dcn10_set_cursor_sdr_white_level(struct pipe_ctx *pipe_ctx) 3877{ 3878 uint32_t sdr_white_level = pipe_ctx->stream->cursor_attributes.sdr_white_level; 3879 struct fixed31_32 multiplier; 3880 struct dpp_cursor_attributes opt_attr = { 0 }; 3881 uint32_t hw_scale = 0x3c00; // 1.0 default multiplier 3882 struct custom_float_format fmt; 3883 3884 if (!pipe_ctx->plane_res.dpp->funcs->set_optional_cursor_attributes) 3885 return; 3886 3887 fmt.exponenta_bits = 5; 3888 fmt.mantissa_bits = 10; 3889 fmt.sign = true; 3890 3891 if (sdr_white_level > 80) { 3892 multiplier = dc_fixpt_from_fraction(sdr_white_level, 80); 3893 convert_to_custom_float_format(multiplier, &fmt, &hw_scale); 3894 } 3895 3896 opt_attr.scale = hw_scale; 3897 opt_attr.bias = 0; 3898 3899 pipe_ctx->plane_res.dpp->funcs->set_optional_cursor_attributes( 3900 pipe_ctx->plane_res.dpp, &opt_attr); 3901} 3902 3903/* 3904 * apply_front_porch_workaround TODO FPGA still need? 3905 * 3906 * This is a workaround for a bug that has existed since R5xx and has not been 3907 * fixed keep Front porch at minimum 2 for Interlaced mode or 1 for progressive. 3908 */ 3909static void apply_front_porch_workaround( 3910 struct dc_crtc_timing *timing) 3911{ 3912 if (timing->flags.INTERLACE == 1) { 3913 if (timing->v_front_porch < 2) 3914 timing->v_front_porch = 2; 3915 } else { 3916 if (timing->v_front_porch < 1) 3917 timing->v_front_porch = 1; 3918 } 3919} 3920 3921int dcn10_get_vupdate_offset_from_vsync(struct pipe_ctx *pipe_ctx) 3922{ 3923 const struct dc_crtc_timing *dc_crtc_timing = &pipe_ctx->stream->timing; 3924 struct dc_crtc_timing patched_crtc_timing; 3925 int vesa_sync_start; 3926 int asic_blank_end; 3927 int interlace_factor; 3928 3929 patched_crtc_timing = *dc_crtc_timing; 3930 apply_front_porch_workaround(&patched_crtc_timing); 3931 3932 interlace_factor = patched_crtc_timing.flags.INTERLACE ? 2 : 1; 3933 3934 vesa_sync_start = patched_crtc_timing.v_addressable + 3935 patched_crtc_timing.v_border_bottom + 3936 patched_crtc_timing.v_front_porch; 3937 3938 asic_blank_end = (patched_crtc_timing.v_total - 3939 vesa_sync_start - 3940 patched_crtc_timing.v_border_top) 3941 * interlace_factor; 3942 3943 return asic_blank_end - 3944 pipe_ctx->pipe_dlg_param.vstartup_start + 1; 3945} 3946 3947void dcn10_calc_vupdate_position( 3948 struct dc *dc, 3949 struct pipe_ctx *pipe_ctx, 3950 uint32_t *start_line, 3951 uint32_t *end_line) 3952{ 3953 const struct dc_crtc_timing *timing = &pipe_ctx->stream->timing; 3954 int vupdate_pos = dc->hwss.get_vupdate_offset_from_vsync(pipe_ctx); 3955 3956 if (vupdate_pos >= 0) 3957 *start_line = vupdate_pos - ((vupdate_pos / timing->v_total) * timing->v_total); 3958 else 3959 *start_line = vupdate_pos + ((-vupdate_pos / timing->v_total) + 1) * timing->v_total - 1; 3960 *end_line = (*start_line + 2) % timing->v_total; 3961} 3962 3963static void dcn10_cal_vline_position( 3964 struct dc *dc, 3965 struct pipe_ctx *pipe_ctx, 3966 uint32_t *start_line, 3967 uint32_t *end_line) 3968{ 3969 const struct dc_crtc_timing *timing = &pipe_ctx->stream->timing; 3970 int vline_pos = pipe_ctx->stream->periodic_interrupt.lines_offset; 3971 3972 if (pipe_ctx->stream->periodic_interrupt.ref_point == START_V_UPDATE) { 3973 if (vline_pos > 0) 3974 vline_pos--; 3975 else if (vline_pos < 0) 3976 vline_pos++; 3977 3978 vline_pos += dc->hwss.get_vupdate_offset_from_vsync(pipe_ctx); 3979 if (vline_pos >= 0) 3980 *start_line = vline_pos - ((vline_pos / timing->v_total) * timing->v_total); 3981 else 3982 *start_line = vline_pos + ((-vline_pos / timing->v_total) + 1) * timing->v_total - 1; 3983 *end_line = (*start_line + 2) % timing->v_total; 3984 } else if (pipe_ctx->stream->periodic_interrupt.ref_point == START_V_SYNC) { 3985 // vsync is line 0 so start_line is just the requested line offset 3986 *start_line = vline_pos; 3987 *end_line = (*start_line + 2) % timing->v_total; 3988 } else 3989 ASSERT(0); 3990} 3991 3992void dcn10_setup_periodic_interrupt( 3993 struct dc *dc, 3994 struct pipe_ctx *pipe_ctx) 3995{ 3996 struct timing_generator *tg = pipe_ctx->stream_res.tg; 3997 uint32_t start_line = 0; 3998 uint32_t end_line = 0; 3999 4000 dcn10_cal_vline_position(dc, pipe_ctx, &start_line, &end_line); 4001 4002 tg->funcs->setup_vertical_interrupt0(tg, start_line, end_line); 4003} 4004 4005void dcn10_setup_vupdate_interrupt(struct dc *dc, struct pipe_ctx *pipe_ctx) 4006{ 4007 struct timing_generator *tg = pipe_ctx->stream_res.tg; 4008 int start_line = dc->hwss.get_vupdate_offset_from_vsync(pipe_ctx); 4009 4010 if (start_line < 0) { 4011 ASSERT(0); 4012 start_line = 0; 4013 } 4014 4015 if (tg->funcs->setup_vertical_interrupt2) 4016 tg->funcs->setup_vertical_interrupt2(tg, start_line); 4017} 4018 4019void dcn10_unblank_stream(struct pipe_ctx *pipe_ctx, 4020 struct dc_link_settings *link_settings) 4021{ 4022 struct encoder_unblank_param params = {0}; 4023 struct dc_stream_state *stream = pipe_ctx->stream; 4024 struct dc_link *link = stream->link; 4025 struct dce_hwseq *hws = link->dc->hwseq; 4026 4027 /* only 3 items below are used by unblank */ 4028 params.timing = pipe_ctx->stream->timing; 4029 4030 params.link_settings.link_rate = link_settings->link_rate; 4031 4032 if (dc_is_dp_signal(pipe_ctx->stream->signal)) { 4033 if (params.timing.pixel_encoding == PIXEL_ENCODING_YCBCR420) 4034 params.timing.pix_clk_100hz /= 2; 4035 pipe_ctx->stream_res.stream_enc->funcs->dp_unblank(link, pipe_ctx->stream_res.stream_enc, ¶ms); 4036 } 4037 4038 if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP) { 4039 hws->funcs.edp_backlight_control(link, true); 4040 } 4041} 4042 4043void dcn10_send_immediate_sdp_message(struct pipe_ctx *pipe_ctx, 4044 const uint8_t *custom_sdp_message, 4045 unsigned int sdp_message_size) 4046{ 4047 if (dc_is_dp_signal(pipe_ctx->stream->signal)) { 4048 pipe_ctx->stream_res.stream_enc->funcs->send_immediate_sdp_message( 4049 pipe_ctx->stream_res.stream_enc, 4050 custom_sdp_message, 4051 sdp_message_size); 4052 } 4053} 4054enum dc_status dcn10_set_clock(struct dc *dc, 4055 enum dc_clock_type clock_type, 4056 uint32_t clk_khz, 4057 uint32_t stepping) 4058{ 4059 struct dc_state *context = dc->current_state; 4060 struct dc_clock_config clock_cfg = {0}; 4061 struct dc_clocks *current_clocks = &context->bw_ctx.bw.dcn.clk; 4062 4063 if (!dc->clk_mgr || !dc->clk_mgr->funcs->get_clock) 4064 return DC_FAIL_UNSUPPORTED_1; 4065 4066 dc->clk_mgr->funcs->get_clock(dc->clk_mgr, 4067 context, clock_type, &clock_cfg); 4068 4069 if (clk_khz > clock_cfg.max_clock_khz) 4070 return DC_FAIL_CLK_EXCEED_MAX; 4071 4072 if (clk_khz < clock_cfg.min_clock_khz) 4073 return DC_FAIL_CLK_BELOW_MIN; 4074 4075 if (clk_khz < clock_cfg.bw_requirequired_clock_khz) 4076 return DC_FAIL_CLK_BELOW_CFG_REQUIRED; 4077 4078 /*update internal request clock for update clock use*/ 4079 if (clock_type == DC_CLOCK_TYPE_DISPCLK) 4080 current_clocks->dispclk_khz = clk_khz; 4081 else if (clock_type == DC_CLOCK_TYPE_DPPCLK) 4082 current_clocks->dppclk_khz = clk_khz; 4083 else 4084 return DC_ERROR_UNEXPECTED; 4085 4086 if (dc->clk_mgr->funcs->update_clocks) 4087 dc->clk_mgr->funcs->update_clocks(dc->clk_mgr, 4088 context, true); 4089 return DC_OK; 4090 4091} 4092 4093void dcn10_get_clock(struct dc *dc, 4094 enum dc_clock_type clock_type, 4095 struct dc_clock_config *clock_cfg) 4096{ 4097 struct dc_state *context = dc->current_state; 4098 4099 if (dc->clk_mgr && dc->clk_mgr->funcs->get_clock) 4100 dc->clk_mgr->funcs->get_clock(dc->clk_mgr, context, clock_type, clock_cfg); 4101 4102} 4103 4104void dcn10_get_dcc_en_bits(struct dc *dc, int *dcc_en_bits) 4105{ 4106 struct resource_pool *pool = dc->res_pool; 4107 int i; 4108 4109 for (i = 0; i < pool->pipe_count; i++) { 4110 struct hubp *hubp = pool->hubps[i]; 4111 struct dcn_hubp_state *s = &(TO_DCN10_HUBP(hubp)->state); 4112 4113 hubp->funcs->hubp_read_state(hubp); 4114 4115 if (!s->blank_en) 4116 dcc_en_bits[i] = s->dcc_en ? 1 : 0; 4117 } 4118} 4119 4120/** 4121 * dcn10_reset_surface_dcc_and_tiling - Set DCC and tiling in DCN to their disable mode. 4122 * 4123 * @pipe_ctx: Pointer to the pipe context structure. 4124 * @plane_state: Surface state 4125 * @clear_tiling: If true set tiling to Linear, otherwise does not change tiling 4126 * 4127 * This function is responsible for call the HUBP block to disable DCC and set 4128 * tiling to the linear mode. 4129 */ 4130void dcn10_reset_surface_dcc_and_tiling(struct pipe_ctx *pipe_ctx, 4131 struct dc_plane_state *plane_state, 4132 bool clear_tiling) 4133{ 4134 struct hubp *hubp = pipe_ctx->plane_res.hubp; 4135 4136 if (!hubp) 4137 return; 4138 4139 /* if framebuffer is tiled, disable tiling */ 4140 if (clear_tiling && hubp->funcs->hubp_clear_tiling) 4141 hubp->funcs->hubp_clear_tiling(hubp); 4142 4143 /* force page flip to see the new content of the framebuffer */ 4144 hubp->funcs->hubp_program_surface_flip_and_addr(hubp, 4145 &plane_state->address, 4146 true); 4147}
~/
Read-only file preview.