.. | .. |
---|
25 | 25 | |
---|
26 | 26 | #include <linux/delay.h> |
---|
27 | 27 | #include "dm_services.h" |
---|
| 28 | +#include "basics/dc_common.h" |
---|
28 | 29 | #include "core_types.h" |
---|
29 | 30 | #include "resource.h" |
---|
30 | 31 | #include "custom_float.h" |
---|
31 | 32 | #include "dcn10_hw_sequencer.h" |
---|
32 | | -#include "dce110/dce110_hw_sequencer.h" |
---|
| 33 | +#include "dcn10_hw_sequencer_debug.h" |
---|
33 | 34 | #include "dce/dce_hwseq.h" |
---|
34 | 35 | #include "abm.h" |
---|
35 | 36 | #include "dmcu.h" |
---|
36 | 37 | #include "dcn10_optc.h" |
---|
37 | | -#include "dcn10/dcn10_dpp.h" |
---|
38 | | -#include "dcn10/dcn10_mpc.h" |
---|
| 38 | +#include "dcn10_dpp.h" |
---|
| 39 | +#include "dcn10_mpc.h" |
---|
39 | 40 | #include "timing_generator.h" |
---|
40 | 41 | #include "opp.h" |
---|
41 | 42 | #include "ipp.h" |
---|
42 | 43 | #include "mpc.h" |
---|
43 | 44 | #include "reg_helper.h" |
---|
44 | | -#include "custom_float.h" |
---|
45 | 45 | #include "dcn10_hubp.h" |
---|
46 | 46 | #include "dcn10_hubbub.h" |
---|
47 | 47 | #include "dcn10_cm_common.h" |
---|
| 48 | +#include "dc_link_dp.h" |
---|
| 49 | +#include "dccg.h" |
---|
| 50 | +#include "clk_mgr.h" |
---|
| 51 | +#include "link_hwss.h" |
---|
| 52 | +#include "dpcd_defs.h" |
---|
| 53 | +#include "dsc.h" |
---|
| 54 | +#include "dce/dmub_hw_lock_mgr.h" |
---|
48 | 55 | |
---|
49 | 56 | #define DC_LOGGER_INIT(logger) |
---|
50 | 57 | |
---|
.. | .. |
---|
59 | 66 | |
---|
60 | 67 | /*print is 17 wide, first two characters are spaces*/ |
---|
61 | 68 | #define DTN_INFO_MICRO_SEC(ref_cycle) \ |
---|
62 | | - print_microsec(dc_ctx, ref_cycle) |
---|
| 69 | + print_microsec(dc_ctx, log_ctx, ref_cycle) |
---|
63 | 70 | |
---|
64 | | -void print_microsec(struct dc_context *dc_ctx, uint32_t ref_cycle) |
---|
| 71 | +#define GAMMA_HW_POINTS_NUM 256 |
---|
| 72 | + |
---|
| 73 | +void print_microsec(struct dc_context *dc_ctx, |
---|
| 74 | + struct dc_log_buffer_ctx *log_ctx, |
---|
| 75 | + uint32_t ref_cycle) |
---|
65 | 76 | { |
---|
66 | | - const uint32_t ref_clk_mhz = dc_ctx->dc->res_pool->ref_clock_inKhz / 1000; |
---|
| 77 | + const uint32_t ref_clk_mhz = dc_ctx->dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000; |
---|
67 | 78 | static const unsigned int frac = 1000; |
---|
68 | 79 | uint32_t us_x10 = (ref_cycle * frac) / ref_clk_mhz; |
---|
69 | 80 | |
---|
.. | .. |
---|
72 | 83 | us_x10 % frac); |
---|
73 | 84 | } |
---|
74 | 85 | |
---|
| 86 | +void dcn10_lock_all_pipes(struct dc *dc, |
---|
| 87 | + struct dc_state *context, |
---|
| 88 | + bool lock) |
---|
| 89 | +{ |
---|
| 90 | + struct pipe_ctx *pipe_ctx; |
---|
| 91 | + struct timing_generator *tg; |
---|
| 92 | + int i; |
---|
75 | 93 | |
---|
76 | | -static void log_mpc_crc(struct dc *dc) |
---|
| 94 | + for (i = 0; i < dc->res_pool->pipe_count; i++) { |
---|
| 95 | + pipe_ctx = &context->res_ctx.pipe_ctx[i]; |
---|
| 96 | + tg = pipe_ctx->stream_res.tg; |
---|
| 97 | + |
---|
| 98 | + /* |
---|
| 99 | + * Only lock the top pipe's tg to prevent redundant |
---|
| 100 | + * (un)locking. Also skip if pipe is disabled. |
---|
| 101 | + */ |
---|
| 102 | + if (pipe_ctx->top_pipe || |
---|
| 103 | + !pipe_ctx->stream || !pipe_ctx->plane_state || |
---|
| 104 | + !tg->funcs->is_tg_enabled(tg)) |
---|
| 105 | + continue; |
---|
| 106 | + |
---|
| 107 | + if (lock) |
---|
| 108 | + dc->hwss.pipe_control_lock(dc, pipe_ctx, true); |
---|
| 109 | + else |
---|
| 110 | + dc->hwss.pipe_control_lock(dc, pipe_ctx, false); |
---|
| 111 | + } |
---|
| 112 | +} |
---|
| 113 | + |
---|
| 114 | +static void log_mpc_crc(struct dc *dc, |
---|
| 115 | + struct dc_log_buffer_ctx *log_ctx) |
---|
77 | 116 | { |
---|
78 | 117 | struct dc_context *dc_ctx = dc->ctx; |
---|
79 | 118 | struct dce_hwseq *hws = dc->hwseq; |
---|
.. | .. |
---|
86 | 125 | REG_READ(DPP_TOP0_DPP_CRC_VAL_B_A), REG_READ(DPP_TOP0_DPP_CRC_VAL_R_G)); |
---|
87 | 126 | } |
---|
88 | 127 | |
---|
89 | | -void dcn10_log_hubbub_state(struct dc *dc) |
---|
| 128 | +void dcn10_log_hubbub_state(struct dc *dc, struct dc_log_buffer_ctx *log_ctx) |
---|
90 | 129 | { |
---|
91 | 130 | struct dc_context *dc_ctx = dc->ctx; |
---|
92 | 131 | struct dcn_hubbub_wm wm; |
---|
93 | 132 | int i; |
---|
94 | 133 | |
---|
95 | | - hubbub1_wm_read_state(dc->res_pool->hubbub, &wm); |
---|
| 134 | + memset(&wm, 0, sizeof(struct dcn_hubbub_wm)); |
---|
| 135 | + dc->res_pool->hubbub->funcs->wm_read_state(dc->res_pool->hubbub, &wm); |
---|
96 | 136 | |
---|
97 | 137 | DTN_INFO("HUBBUB WM: data_urgent pte_meta_urgent" |
---|
98 | 138 | " sr_enter sr_exit dram_clk_change\n"); |
---|
.. | .. |
---|
113 | 153 | DTN_INFO("\n"); |
---|
114 | 154 | } |
---|
115 | 155 | |
---|
116 | | -static void dcn10_log_hubp_states(struct dc *dc) |
---|
| 156 | +static void dcn10_log_hubp_states(struct dc *dc, void *log_ctx) |
---|
117 | 157 | { |
---|
118 | 158 | struct dc_context *dc_ctx = dc->ctx; |
---|
119 | 159 | struct resource_pool *pool = dc->res_pool; |
---|
120 | 160 | int i; |
---|
121 | 161 | |
---|
122 | | - DTN_INFO("HUBP: format addr_hi width height" |
---|
123 | | - " rot mir sw_mode dcc_en blank_en ttu_dis underflow" |
---|
124 | | - " min_ttu_vblank qos_low_wm qos_high_wm\n"); |
---|
| 162 | + DTN_INFO( |
---|
| 163 | + "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"); |
---|
125 | 164 | for (i = 0; i < pool->pipe_count; i++) { |
---|
126 | 165 | struct hubp *hubp = pool->hubps[i]; |
---|
127 | 166 | struct dcn_hubp_state *s = &(TO_DCN10_HUBP(hubp)->state); |
---|
.. | .. |
---|
129 | 168 | hubp->funcs->hubp_read_state(hubp); |
---|
130 | 169 | |
---|
131 | 170 | if (!s->blank_en) { |
---|
132 | | - DTN_INFO("[%2d]: %5xh %6xh %5d %6d %2xh %2xh %6xh" |
---|
133 | | - " %6d %8d %7d %8xh", |
---|
| 171 | + DTN_INFO("[%2d]: %5xh %6xh %5d %6d %2xh %2xh %6xh %6d %8d %8d %7d %8xh", |
---|
134 | 172 | hubp->inst, |
---|
135 | 173 | s->pixel_format, |
---|
136 | 174 | s->inuse_addr_hi, |
---|
.. | .. |
---|
141 | 179 | s->sw_mode, |
---|
142 | 180 | s->dcc_en, |
---|
143 | 181 | s->blank_en, |
---|
| 182 | + s->clock_en, |
---|
144 | 183 | s->ttu_disable, |
---|
145 | 184 | s->underflow_status); |
---|
146 | 185 | DTN_INFO_MICRO_SEC(s->min_ttu_vblank); |
---|
.. | .. |
---|
228 | 267 | DTN_INFO("\n"); |
---|
229 | 268 | } |
---|
230 | 269 | |
---|
231 | | -void dcn10_log_hw_state(struct dc *dc) |
---|
| 270 | +void dcn10_log_hw_state(struct dc *dc, |
---|
| 271 | + struct dc_log_buffer_ctx *log_ctx) |
---|
232 | 272 | { |
---|
233 | 273 | struct dc_context *dc_ctx = dc->ctx; |
---|
234 | 274 | struct resource_pool *pool = dc->res_pool; |
---|
.. | .. |
---|
236 | 276 | |
---|
237 | 277 | DTN_INFO_BEGIN(); |
---|
238 | 278 | |
---|
239 | | - dcn10_log_hubbub_state(dc); |
---|
| 279 | + dcn10_log_hubbub_state(dc, log_ctx); |
---|
240 | 280 | |
---|
241 | | - dcn10_log_hubp_states(dc); |
---|
| 281 | + dcn10_log_hubp_states(dc, log_ctx); |
---|
242 | 282 | |
---|
243 | 283 | DTN_INFO("DPP: IGAM format IGAM mode DGAM mode RGAM mode" |
---|
244 | 284 | " GAMUT mode C11 C12 C13 C14 C21 C22 C23 C24 " |
---|
245 | 285 | "C31 C32 C33 C34\n"); |
---|
246 | 286 | for (i = 0; i < pool->pipe_count; i++) { |
---|
247 | 287 | struct dpp *dpp = pool->dpps[i]; |
---|
248 | | - struct dcn_dpp_state s; |
---|
| 288 | + struct dcn_dpp_state s = {0}; |
---|
249 | 289 | |
---|
250 | 290 | dpp->funcs->dpp_read_state(dpp, &s); |
---|
| 291 | + |
---|
| 292 | + if (!s.is_enabled) |
---|
| 293 | + continue; |
---|
251 | 294 | |
---|
252 | 295 | DTN_INFO("[%2d]: %11xh %-11s %-11s %-11s" |
---|
253 | 296 | "%8x %08xh %08xh %08xh %08xh %08xh %08xh", |
---|
.. | .. |
---|
294 | 337 | } |
---|
295 | 338 | DTN_INFO("\n"); |
---|
296 | 339 | |
---|
297 | | - DTN_INFO("OTG: v_bs v_be v_ss v_se vpol vmax vmin vmax_sel vmin_sel" |
---|
298 | | - " h_bs h_be h_ss h_se hpol htot vtot underflow\n"); |
---|
| 340 | + 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"); |
---|
299 | 341 | |
---|
300 | 342 | for (i = 0; i < pool->timing_generator_count; i++) { |
---|
301 | 343 | struct timing_generator *tg = pool->timing_generators[i]; |
---|
302 | 344 | struct dcn_otg_state s = {0}; |
---|
303 | | - |
---|
| 345 | + /* Read shared OTG state registers for all DCNx */ |
---|
304 | 346 | optc1_read_otg_state(DCN10TG_FROM_TG(tg), &s); |
---|
| 347 | + |
---|
| 348 | + /* |
---|
| 349 | + * For DCN2 and greater, a register on the OPP is used to |
---|
| 350 | + * determine if the CRTC is blanked instead of the OTG. So use |
---|
| 351 | + * dpg_is_blanked() if exists, otherwise fallback on otg. |
---|
| 352 | + * |
---|
| 353 | + * TODO: Implement DCN-specific read_otg_state hooks. |
---|
| 354 | + */ |
---|
| 355 | + if (pool->opps[i]->funcs->dpg_is_blanked) |
---|
| 356 | + s.blank_enabled = pool->opps[i]->funcs->dpg_is_blanked(pool->opps[i]); |
---|
| 357 | + else |
---|
| 358 | + s.blank_enabled = tg->funcs->is_blanked(tg); |
---|
305 | 359 | |
---|
306 | 360 | //only print if OTG master is enabled |
---|
307 | 361 | if ((s.otg_enabled & 1) == 0) |
---|
308 | 362 | continue; |
---|
309 | 363 | |
---|
310 | | - DTN_INFO("[%d]: %5d %5d %5d %5d %5d %5d %5d %9d %9d %5d %5d %5d" |
---|
311 | | - " %5d %5d %5d %5d %9d\n", |
---|
| 364 | + DTN_INFO("[%d]: %5d %5d %5d %5d %5d %5d %5d %9d %9d %5d %5d %5d %5d %5d %5d %5d %9d %8d\n", |
---|
312 | 365 | tg->inst, |
---|
313 | 366 | s.v_blank_start, |
---|
314 | 367 | s.v_blank_end, |
---|
.. | .. |
---|
326 | 379 | s.h_sync_a_pol, |
---|
327 | 380 | s.h_total, |
---|
328 | 381 | s.v_total, |
---|
329 | | - s.underflow_occurred_status); |
---|
| 382 | + s.underflow_occurred_status, |
---|
| 383 | + s.blank_enabled); |
---|
330 | 384 | |
---|
331 | 385 | // Clear underflow for debug purposes |
---|
332 | 386 | // We want to keep underflow sticky bit on for the longevity tests outside of test environment. |
---|
.. | .. |
---|
336 | 390 | } |
---|
337 | 391 | DTN_INFO("\n"); |
---|
338 | 392 | |
---|
| 393 | + // dcn_dsc_state struct field bytes_per_pixel was renamed to bits_per_pixel |
---|
| 394 | + // TODO: Update golden log header to reflect this name change |
---|
| 395 | + DTN_INFO("DSC: CLOCK_EN SLICE_WIDTH Bytes_pp\n"); |
---|
| 396 | + for (i = 0; i < pool->res_cap->num_dsc; i++) { |
---|
| 397 | + struct display_stream_compressor *dsc = pool->dscs[i]; |
---|
| 398 | + struct dcn_dsc_state s = {0}; |
---|
| 399 | + |
---|
| 400 | + dsc->funcs->dsc_read_state(dsc, &s); |
---|
| 401 | + DTN_INFO("[%d]: %-9d %-12d %-10d\n", |
---|
| 402 | + dsc->inst, |
---|
| 403 | + s.dsc_clock_en, |
---|
| 404 | + s.dsc_slice_width, |
---|
| 405 | + s.dsc_bits_per_pixel); |
---|
| 406 | + DTN_INFO("\n"); |
---|
| 407 | + } |
---|
| 408 | + DTN_INFO("\n"); |
---|
| 409 | + |
---|
| 410 | + DTN_INFO("S_ENC: DSC_MODE SEC_GSP7_LINE_NUM" |
---|
| 411 | + " VBID6_LINE_REFERENCE VBID6_LINE_NUM SEC_GSP7_ENABLE SEC_STREAM_ENABLE\n"); |
---|
| 412 | + for (i = 0; i < pool->stream_enc_count; i++) { |
---|
| 413 | + struct stream_encoder *enc = pool->stream_enc[i]; |
---|
| 414 | + struct enc_state s = {0}; |
---|
| 415 | + |
---|
| 416 | + if (enc->funcs->enc_read_state) { |
---|
| 417 | + enc->funcs->enc_read_state(enc, &s); |
---|
| 418 | + DTN_INFO("[%-3d]: %-9d %-18d %-21d %-15d %-16d %-17d\n", |
---|
| 419 | + enc->id, |
---|
| 420 | + s.dsc_mode, |
---|
| 421 | + s.sec_gsp_pps_line_num, |
---|
| 422 | + s.vbid6_line_reference, |
---|
| 423 | + s.vbid6_line_num, |
---|
| 424 | + s.sec_gsp_pps_enable, |
---|
| 425 | + s.sec_stream_enable); |
---|
| 426 | + DTN_INFO("\n"); |
---|
| 427 | + } |
---|
| 428 | + } |
---|
| 429 | + DTN_INFO("\n"); |
---|
| 430 | + |
---|
| 431 | + DTN_INFO("L_ENC: DPHY_FEC_EN DPHY_FEC_READY_SHADOW DPHY_FEC_ACTIVE_STATUS DP_LINK_TRAINING_COMPLETE\n"); |
---|
| 432 | + for (i = 0; i < dc->link_count; i++) { |
---|
| 433 | + struct link_encoder *lenc = dc->links[i]->link_enc; |
---|
| 434 | + |
---|
| 435 | + struct link_enc_state s = {0}; |
---|
| 436 | + |
---|
| 437 | + if (lenc->funcs->read_state) { |
---|
| 438 | + lenc->funcs->read_state(lenc, &s); |
---|
| 439 | + DTN_INFO("[%-3d]: %-12d %-22d %-22d %-25d\n", |
---|
| 440 | + i, |
---|
| 441 | + s.dphy_fec_en, |
---|
| 442 | + s.dphy_fec_ready_shadow, |
---|
| 443 | + s.dphy_fec_active_status, |
---|
| 444 | + s.dp_link_training_complete); |
---|
| 445 | + DTN_INFO("\n"); |
---|
| 446 | + } |
---|
| 447 | + } |
---|
| 448 | + DTN_INFO("\n"); |
---|
| 449 | + |
---|
339 | 450 | DTN_INFO("\nCALCULATED Clocks: dcfclk_khz:%d dcfclk_deep_sleep_khz:%d dispclk_khz:%d\n" |
---|
340 | 451 | "dppclk_khz:%d max_supported_dppclk_khz:%d fclk_khz:%d socclk_khz:%d\n\n", |
---|
341 | | - dc->current_state->bw.dcn.clk.dcfclk_khz, |
---|
342 | | - dc->current_state->bw.dcn.clk.dcfclk_deep_sleep_khz, |
---|
343 | | - dc->current_state->bw.dcn.clk.dispclk_khz, |
---|
344 | | - dc->current_state->bw.dcn.clk.dppclk_khz, |
---|
345 | | - dc->current_state->bw.dcn.clk.max_supported_dppclk_khz, |
---|
346 | | - dc->current_state->bw.dcn.clk.fclk_khz, |
---|
347 | | - dc->current_state->bw.dcn.clk.socclk_khz); |
---|
| 452 | + dc->current_state->bw_ctx.bw.dcn.clk.dcfclk_khz, |
---|
| 453 | + dc->current_state->bw_ctx.bw.dcn.clk.dcfclk_deep_sleep_khz, |
---|
| 454 | + dc->current_state->bw_ctx.bw.dcn.clk.dispclk_khz, |
---|
| 455 | + dc->current_state->bw_ctx.bw.dcn.clk.dppclk_khz, |
---|
| 456 | + dc->current_state->bw_ctx.bw.dcn.clk.max_supported_dppclk_khz, |
---|
| 457 | + dc->current_state->bw_ctx.bw.dcn.clk.fclk_khz, |
---|
| 458 | + dc->current_state->bw_ctx.bw.dcn.clk.socclk_khz); |
---|
348 | 459 | |
---|
349 | | - log_mpc_crc(dc); |
---|
| 460 | + log_mpc_crc(dc, log_ctx); |
---|
350 | 461 | |
---|
351 | 462 | DTN_INFO_END(); |
---|
352 | 463 | } |
---|
353 | 464 | |
---|
354 | | -static void enable_power_gating_plane( |
---|
| 465 | +bool dcn10_did_underflow_occur(struct dc *dc, struct pipe_ctx *pipe_ctx) |
---|
| 466 | +{ |
---|
| 467 | + struct hubp *hubp = pipe_ctx->plane_res.hubp; |
---|
| 468 | + struct timing_generator *tg = pipe_ctx->stream_res.tg; |
---|
| 469 | + |
---|
| 470 | + if (tg->funcs->is_optc_underflow_occurred(tg)) { |
---|
| 471 | + tg->funcs->clear_optc_underflow(tg); |
---|
| 472 | + return true; |
---|
| 473 | + } |
---|
| 474 | + |
---|
| 475 | + if (hubp->funcs->hubp_get_underflow_status(hubp)) { |
---|
| 476 | + hubp->funcs->hubp_clear_underflow(hubp); |
---|
| 477 | + return true; |
---|
| 478 | + } |
---|
| 479 | + return false; |
---|
| 480 | +} |
---|
| 481 | + |
---|
| 482 | +void dcn10_enable_power_gating_plane( |
---|
355 | 483 | struct dce_hwseq *hws, |
---|
356 | 484 | bool enable) |
---|
357 | 485 | { |
---|
358 | | - bool force_on = 1; /* disable power gating */ |
---|
| 486 | + bool force_on = true; /* disable power gating */ |
---|
359 | 487 | |
---|
360 | 488 | if (enable) |
---|
361 | | - force_on = 0; |
---|
| 489 | + force_on = false; |
---|
362 | 490 | |
---|
363 | 491 | /* DCHUBP0/1/2/3 */ |
---|
364 | 492 | REG_UPDATE(DOMAIN0_PG_CONFIG, DOMAIN0_POWER_FORCEON, force_on); |
---|
.. | .. |
---|
373 | 501 | REG_UPDATE(DOMAIN7_PG_CONFIG, DOMAIN7_POWER_FORCEON, force_on); |
---|
374 | 502 | } |
---|
375 | 503 | |
---|
376 | | -static void disable_vga( |
---|
| 504 | +void dcn10_disable_vga( |
---|
377 | 505 | struct dce_hwseq *hws) |
---|
378 | 506 | { |
---|
379 | 507 | unsigned int in_vga1_mode = 0; |
---|
.. | .. |
---|
406 | 534 | REG_UPDATE(VGA_TEST_CONTROL, VGA_TEST_RENDER_START, 1); |
---|
407 | 535 | } |
---|
408 | 536 | |
---|
409 | | -static void dpp_pg_control( |
---|
| 537 | +void dcn10_dpp_pg_control( |
---|
410 | 538 | struct dce_hwseq *hws, |
---|
411 | 539 | unsigned int dpp_inst, |
---|
412 | 540 | bool power_on) |
---|
.. | .. |
---|
458 | 586 | } |
---|
459 | 587 | } |
---|
460 | 588 | |
---|
461 | | -static void hubp_pg_control( |
---|
| 589 | +void dcn10_hubp_pg_control( |
---|
462 | 590 | struct dce_hwseq *hws, |
---|
463 | 591 | unsigned int hubp_inst, |
---|
464 | 592 | bool power_on) |
---|
.. | .. |
---|
518 | 646 | if (REG(DC_IP_REQUEST_CNTL)) { |
---|
519 | 647 | REG_SET(DC_IP_REQUEST_CNTL, 0, |
---|
520 | 648 | IP_REQUEST_EN, 1); |
---|
521 | | - dpp_pg_control(hws, plane_id, true); |
---|
522 | | - hubp_pg_control(hws, plane_id, true); |
---|
| 649 | + |
---|
| 650 | + if (hws->funcs.dpp_pg_control) |
---|
| 651 | + hws->funcs.dpp_pg_control(hws, plane_id, true); |
---|
| 652 | + |
---|
| 653 | + if (hws->funcs.hubp_pg_control) |
---|
| 654 | + hws->funcs.hubp_pg_control(hws, plane_id, true); |
---|
| 655 | + |
---|
523 | 656 | REG_SET(DC_IP_REQUEST_CNTL, 0, |
---|
524 | 657 | IP_REQUEST_EN, 0); |
---|
525 | 658 | DC_LOG_DEBUG( |
---|
.. | .. |
---|
540 | 673 | REG_SET(DC_IP_REQUEST_CNTL, 0, |
---|
541 | 674 | IP_REQUEST_EN, 1); |
---|
542 | 675 | |
---|
543 | | - hubp_pg_control(hws, 0, false); |
---|
| 676 | + hws->funcs.hubp_pg_control(hws, 0, false); |
---|
544 | 677 | REG_SET(DC_IP_REQUEST_CNTL, 0, |
---|
545 | 678 | IP_REQUEST_EN, 0); |
---|
546 | 679 | |
---|
.. | .. |
---|
569 | 702 | REG_SET(DC_IP_REQUEST_CNTL, 0, |
---|
570 | 703 | IP_REQUEST_EN, 1); |
---|
571 | 704 | |
---|
572 | | - hubp_pg_control(hws, 0, true); |
---|
| 705 | + hws->funcs.hubp_pg_control(hws, 0, true); |
---|
573 | 706 | REG_SET(DC_IP_REQUEST_CNTL, 0, |
---|
574 | 707 | IP_REQUEST_EN, 0); |
---|
575 | 708 | |
---|
.. | .. |
---|
577 | 710 | hws->wa_state.DEGVIDCN10_253_applied = true; |
---|
578 | 711 | } |
---|
579 | 712 | |
---|
580 | | -static void bios_golden_init(struct dc *dc) |
---|
| 713 | +void dcn10_bios_golden_init(struct dc *dc) |
---|
581 | 714 | { |
---|
| 715 | + struct dce_hwseq *hws = dc->hwseq; |
---|
582 | 716 | struct dc_bios *bp = dc->ctx->dc_bios; |
---|
583 | 717 | int i; |
---|
| 718 | + bool allow_self_fresh_force_enable = true; |
---|
| 719 | + |
---|
| 720 | + if (hws->funcs.s0i3_golden_init_wa && hws->funcs.s0i3_golden_init_wa(dc)) |
---|
| 721 | + return; |
---|
| 722 | + |
---|
| 723 | + if (dc->res_pool->hubbub->funcs->is_allow_self_refresh_enabled) |
---|
| 724 | + allow_self_fresh_force_enable = |
---|
| 725 | + dc->res_pool->hubbub->funcs->is_allow_self_refresh_enabled(dc->res_pool->hubbub); |
---|
| 726 | + |
---|
| 727 | + |
---|
| 728 | + /* WA for making DF sleep when idle after resume from S0i3. |
---|
| 729 | + * DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE is set to 1 by |
---|
| 730 | + * command table, if DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE = 0 |
---|
| 731 | + * before calling command table and it changed to 1 after, |
---|
| 732 | + * it should be set back to 0. |
---|
| 733 | + */ |
---|
584 | 734 | |
---|
585 | 735 | /* initialize dcn global */ |
---|
586 | 736 | bp->funcs->enable_disp_power_gating(bp, |
---|
.. | .. |
---|
591 | 741 | bp->funcs->enable_disp_power_gating(bp, |
---|
592 | 742 | CONTROLLER_ID_D0 + i, ASIC_PIPE_DISABLE); |
---|
593 | 743 | } |
---|
| 744 | + |
---|
| 745 | + if (dc->res_pool->hubbub->funcs->allow_self_refresh_control) |
---|
| 746 | + if (allow_self_fresh_force_enable == false && |
---|
| 747 | + dc->res_pool->hubbub->funcs->is_allow_self_refresh_enabled(dc->res_pool->hubbub)) |
---|
| 748 | + dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub, |
---|
| 749 | + !dc->res_pool->hubbub->ctx->dc->debug.disable_stutter); |
---|
| 750 | + |
---|
594 | 751 | } |
---|
595 | 752 | |
---|
596 | 753 | static void false_optc_underflow_wa( |
---|
.. | .. |
---|
615 | 772 | dc->hwss.wait_for_mpcc_disconnect(dc, dc->res_pool, old_pipe_ctx); |
---|
616 | 773 | } |
---|
617 | 774 | |
---|
618 | | - tg->funcs->set_blank_data_double_buffer(tg, true); |
---|
| 775 | + if (tg->funcs->set_blank_data_double_buffer) |
---|
| 776 | + tg->funcs->set_blank_data_double_buffer(tg, true); |
---|
619 | 777 | |
---|
620 | 778 | if (tg->funcs->is_optc_underflow_occurred(tg) && !underflow) |
---|
621 | 779 | tg->funcs->clear_optc_underflow(tg); |
---|
622 | 780 | } |
---|
623 | 781 | |
---|
624 | | -static enum dc_status dcn10_enable_stream_timing( |
---|
| 782 | +enum dc_status dcn10_enable_stream_timing( |
---|
625 | 783 | struct pipe_ctx *pipe_ctx, |
---|
626 | 784 | struct dc_state *context, |
---|
627 | 785 | struct dc *dc) |
---|
.. | .. |
---|
651 | 809 | BREAK_TO_DEBUGGER(); |
---|
652 | 810 | return DC_ERROR_UNEXPECTED; |
---|
653 | 811 | } |
---|
654 | | - pipe_ctx->stream_res.tg->dlg_otg_param.vready_offset = pipe_ctx->pipe_dlg_param.vready_offset; |
---|
655 | | - pipe_ctx->stream_res.tg->dlg_otg_param.vstartup_start = pipe_ctx->pipe_dlg_param.vstartup_start; |
---|
656 | | - pipe_ctx->stream_res.tg->dlg_otg_param.vupdate_offset = pipe_ctx->pipe_dlg_param.vupdate_offset; |
---|
657 | | - pipe_ctx->stream_res.tg->dlg_otg_param.vupdate_width = pipe_ctx->pipe_dlg_param.vupdate_width; |
---|
658 | | - |
---|
659 | | - pipe_ctx->stream_res.tg->dlg_otg_param.signal = pipe_ctx->stream->signal; |
---|
660 | 812 | |
---|
661 | 813 | pipe_ctx->stream_res.tg->funcs->program_timing( |
---|
662 | 814 | pipe_ctx->stream_res.tg, |
---|
663 | 815 | &stream->timing, |
---|
| 816 | + pipe_ctx->pipe_dlg_param.vready_offset, |
---|
| 817 | + pipe_ctx->pipe_dlg_param.vstartup_start, |
---|
| 818 | + pipe_ctx->pipe_dlg_param.vupdate_offset, |
---|
| 819 | + pipe_ctx->pipe_dlg_param.vupdate_width, |
---|
| 820 | + pipe_ctx->stream->signal, |
---|
664 | 821 | true); |
---|
665 | 822 | |
---|
666 | 823 | #if 0 /* move to after enable_crtc */ |
---|
.. | .. |
---|
677 | 834 | /* program otg blank color */ |
---|
678 | 835 | color_space = stream->output_color_space; |
---|
679 | 836 | color_space_to_black_color(dc, color_space, &black_color); |
---|
| 837 | + |
---|
| 838 | + /* |
---|
| 839 | + * The way 420 is packed, 2 channels carry Y component, 1 channel |
---|
| 840 | + * alternate between Cb and Cr, so both channels need the pixel |
---|
| 841 | + * value for Y |
---|
| 842 | + */ |
---|
| 843 | + if (stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR420) |
---|
| 844 | + black_color.color_r_cr = black_color.color_g_y; |
---|
680 | 845 | |
---|
681 | 846 | if (pipe_ctx->stream_res.tg->funcs->set_blank_color) |
---|
682 | 847 | pipe_ctx->stream_res.tg->funcs->set_blank_color( |
---|
.. | .. |
---|
707 | 872 | return DC_OK; |
---|
708 | 873 | } |
---|
709 | 874 | |
---|
710 | | -static void reset_back_end_for_pipe( |
---|
| 875 | +static void dcn10_reset_back_end_for_pipe( |
---|
711 | 876 | struct dc *dc, |
---|
712 | 877 | struct pipe_ctx *pipe_ctx, |
---|
713 | 878 | struct dc_state *context) |
---|
714 | 879 | { |
---|
715 | 880 | int i; |
---|
| 881 | + struct dc_link *link; |
---|
716 | 882 | DC_LOGGER_INIT(dc->ctx->logger); |
---|
717 | 883 | if (pipe_ctx->stream_res.stream_enc == NULL) { |
---|
718 | 884 | pipe_ctx->stream = NULL; |
---|
.. | .. |
---|
720 | 886 | } |
---|
721 | 887 | |
---|
722 | 888 | if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) { |
---|
723 | | - /* DPMS may already disable */ |
---|
724 | | - if (!pipe_ctx->stream->dpms_off) |
---|
725 | | - core_link_disable_stream(pipe_ctx, FREE_ACQUIRED_RESOURCE); |
---|
726 | | - else if (pipe_ctx->stream_res.audio) { |
---|
727 | | - dc->hwss.disable_audio_stream(pipe_ctx, FREE_ACQUIRED_RESOURCE); |
---|
728 | | - } |
---|
| 889 | + link = pipe_ctx->stream->link; |
---|
| 890 | + /* DPMS may already disable or */ |
---|
| 891 | + /* dpms_off status is incorrect due to fastboot |
---|
| 892 | + * feature. When system resume from S4 with second |
---|
| 893 | + * screen only, the dpms_off would be true but |
---|
| 894 | + * VBIOS lit up eDP, so check link status too. |
---|
| 895 | + */ |
---|
| 896 | + if (!pipe_ctx->stream->dpms_off || link->link_status.link_active) |
---|
| 897 | + core_link_disable_stream(pipe_ctx); |
---|
| 898 | + else if (pipe_ctx->stream_res.audio) |
---|
| 899 | + dc->hwss.disable_audio_stream(pipe_ctx); |
---|
729 | 900 | |
---|
| 901 | + if (pipe_ctx->stream_res.audio) { |
---|
| 902 | + /*disable az_endpoint*/ |
---|
| 903 | + pipe_ctx->stream_res.audio->funcs->az_disable(pipe_ctx->stream_res.audio); |
---|
| 904 | + |
---|
| 905 | + /*free audio*/ |
---|
| 906 | + if (dc->caps.dynamic_audio == true) { |
---|
| 907 | + /*we have to dynamic arbitrate the audio endpoints*/ |
---|
| 908 | + /*we free the resource, need reset is_audio_acquired*/ |
---|
| 909 | + update_audio_usage(&dc->current_state->res_ctx, dc->res_pool, |
---|
| 910 | + pipe_ctx->stream_res.audio, false); |
---|
| 911 | + pipe_ctx->stream_res.audio = NULL; |
---|
| 912 | + } |
---|
| 913 | + } |
---|
730 | 914 | } |
---|
731 | 915 | |
---|
732 | 916 | /* by upper caller loop, parent pipe: pipe0, will be reset last. |
---|
.. | .. |
---|
734 | 918 | * parent pipe. |
---|
735 | 919 | */ |
---|
736 | 920 | if (pipe_ctx->top_pipe == NULL) { |
---|
| 921 | + |
---|
| 922 | + if (pipe_ctx->stream_res.abm) |
---|
| 923 | + dc->hwss.set_abm_immediate_disable(pipe_ctx); |
---|
| 924 | + |
---|
737 | 925 | pipe_ctx->stream_res.tg->funcs->disable_crtc(pipe_ctx->stream_res.tg); |
---|
738 | 926 | |
---|
739 | 927 | pipe_ctx->stream_res.tg->funcs->enable_optc_clock(pipe_ctx->stream_res.tg, false); |
---|
| 928 | + if (pipe_ctx->stream_res.tg->funcs->set_drr) |
---|
| 929 | + pipe_ctx->stream_res.tg->funcs->set_drr( |
---|
| 930 | + pipe_ctx->stream_res.tg, NULL); |
---|
740 | 931 | } |
---|
741 | 932 | |
---|
742 | 933 | for (i = 0; i < dc->res_pool->pipe_count; i++) |
---|
.. | .. |
---|
765 | 956 | &dc->current_state->res_ctx.pipe_ctx[i]; |
---|
766 | 957 | if (pipe_ctx != NULL) { |
---|
767 | 958 | hubp = pipe_ctx->plane_res.hubp; |
---|
768 | | - if (hubp != NULL) { |
---|
| 959 | + if (hubp != NULL && hubp->funcs->hubp_get_underflow_status) { |
---|
769 | 960 | if (hubp->funcs->hubp_get_underflow_status(hubp) != 0) { |
---|
770 | 961 | /* one pipe underflow, we will reset all the pipes*/ |
---|
771 | 962 | need_recover = true; |
---|
.. | .. |
---|
791 | 982 | if (pipe_ctx != NULL) { |
---|
792 | 983 | hubp = pipe_ctx->plane_res.hubp; |
---|
793 | 984 | /*DCHUBP_CNTL:HUBP_BLANK_EN=1*/ |
---|
794 | | - if (hubp != NULL) |
---|
| 985 | + if (hubp != NULL && hubp->funcs->set_hubp_blank_en) |
---|
795 | 986 | hubp->funcs->set_hubp_blank_en(hubp, true); |
---|
796 | 987 | } |
---|
797 | 988 | } |
---|
.. | .. |
---|
804 | 995 | if (pipe_ctx != NULL) { |
---|
805 | 996 | hubp = pipe_ctx->plane_res.hubp; |
---|
806 | 997 | /*DCHUBP_CNTL:HUBP_DISABLE=1*/ |
---|
807 | | - if (hubp != NULL) |
---|
| 998 | + if (hubp != NULL && hubp->funcs->hubp_disable_control) |
---|
808 | 999 | hubp->funcs->hubp_disable_control(hubp, true); |
---|
809 | 1000 | } |
---|
810 | 1001 | } |
---|
.. | .. |
---|
814 | 1005 | if (pipe_ctx != NULL) { |
---|
815 | 1006 | hubp = pipe_ctx->plane_res.hubp; |
---|
816 | 1007 | /*DCHUBP_CNTL:HUBP_DISABLE=0*/ |
---|
817 | | - if (hubp != NULL) |
---|
| 1008 | + if (hubp != NULL && hubp->funcs->hubp_disable_control) |
---|
818 | 1009 | hubp->funcs->hubp_disable_control(hubp, true); |
---|
819 | 1010 | } |
---|
820 | 1011 | } |
---|
.. | .. |
---|
826 | 1017 | if (pipe_ctx != NULL) { |
---|
827 | 1018 | hubp = pipe_ctx->plane_res.hubp; |
---|
828 | 1019 | /*DCHUBP_CNTL:HUBP_BLANK_EN=0*/ |
---|
829 | | - if (hubp != NULL) |
---|
| 1020 | + if (hubp != NULL && hubp->funcs->set_hubp_blank_en) |
---|
830 | 1021 | hubp->funcs->set_hubp_blank_en(hubp, true); |
---|
831 | 1022 | } |
---|
832 | 1023 | } |
---|
.. | .. |
---|
841 | 1032 | |
---|
842 | 1033 | if (!hubbub1_verify_allow_pstate_change_high(dc->res_pool->hubbub)) { |
---|
843 | 1034 | if (should_log_hw_state) { |
---|
844 | | - dcn10_log_hw_state(dc); |
---|
| 1035 | + dcn10_log_hw_state(dc, NULL); |
---|
845 | 1036 | } |
---|
846 | 1037 | BREAK_TO_DEBUGGER(); |
---|
847 | 1038 | if (dcn10_hw_wa_force_recovery(dc)) { |
---|
.. | .. |
---|
853 | 1044 | } |
---|
854 | 1045 | |
---|
855 | 1046 | /* trigger HW to start disconnect plane from stream on the next vsync */ |
---|
856 | | -void hwss1_plane_atomic_disconnect(struct dc *dc, struct pipe_ctx *pipe_ctx) |
---|
| 1047 | +void dcn10_plane_atomic_disconnect(struct dc *dc, struct pipe_ctx *pipe_ctx) |
---|
857 | 1048 | { |
---|
| 1049 | + struct dce_hwseq *hws = dc->hwseq; |
---|
858 | 1050 | struct hubp *hubp = pipe_ctx->plane_res.hubp; |
---|
859 | 1051 | int dpp_id = pipe_ctx->plane_res.dpp->inst; |
---|
860 | 1052 | struct mpc *mpc = dc->res_pool->mpc; |
---|
.. | .. |
---|
879 | 1071 | hubp->funcs->hubp_disconnect(hubp); |
---|
880 | 1072 | |
---|
881 | 1073 | if (dc->debug.sanity_checks) |
---|
882 | | - dcn10_verify_allow_pstate_change_high(dc); |
---|
| 1074 | + hws->funcs.verify_allow_pstate_change_high(dc); |
---|
883 | 1075 | } |
---|
884 | 1076 | |
---|
885 | | -static void plane_atomic_power_down(struct dc *dc, struct pipe_ctx *pipe_ctx) |
---|
| 1077 | +void dcn10_plane_atomic_power_down(struct dc *dc, |
---|
| 1078 | + struct dpp *dpp, |
---|
| 1079 | + struct hubp *hubp) |
---|
886 | 1080 | { |
---|
887 | 1081 | struct dce_hwseq *hws = dc->hwseq; |
---|
888 | | - struct dpp *dpp = pipe_ctx->plane_res.dpp; |
---|
889 | 1082 | DC_LOGGER_INIT(dc->ctx->logger); |
---|
890 | 1083 | |
---|
891 | 1084 | if (REG(DC_IP_REQUEST_CNTL)) { |
---|
892 | 1085 | REG_SET(DC_IP_REQUEST_CNTL, 0, |
---|
893 | 1086 | IP_REQUEST_EN, 1); |
---|
894 | | - dpp_pg_control(hws, dpp->inst, false); |
---|
895 | | - hubp_pg_control(hws, pipe_ctx->plane_res.hubp->inst, false); |
---|
| 1087 | + |
---|
| 1088 | + if (hws->funcs.dpp_pg_control) |
---|
| 1089 | + hws->funcs.dpp_pg_control(hws, dpp->inst, false); |
---|
| 1090 | + |
---|
| 1091 | + if (hws->funcs.hubp_pg_control) |
---|
| 1092 | + hws->funcs.hubp_pg_control(hws, hubp->inst, false); |
---|
| 1093 | + |
---|
896 | 1094 | dpp->funcs->dpp_reset(dpp); |
---|
897 | 1095 | REG_SET(DC_IP_REQUEST_CNTL, 0, |
---|
898 | 1096 | IP_REQUEST_EN, 0); |
---|
899 | 1097 | DC_LOG_DEBUG( |
---|
900 | | - "Power gated front end %d\n", pipe_ctx->pipe_idx); |
---|
| 1098 | + "Power gated front end %d\n", hubp->inst); |
---|
901 | 1099 | } |
---|
902 | 1100 | } |
---|
903 | 1101 | |
---|
904 | 1102 | /* disable HW used by plane. |
---|
905 | 1103 | * note: cannot disable until disconnect is complete |
---|
906 | 1104 | */ |
---|
907 | | -static void plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx) |
---|
| 1105 | +void dcn10_plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx) |
---|
908 | 1106 | { |
---|
| 1107 | + struct dce_hwseq *hws = dc->hwseq; |
---|
909 | 1108 | struct hubp *hubp = pipe_ctx->plane_res.hubp; |
---|
910 | 1109 | struct dpp *dpp = pipe_ctx->plane_res.dpp; |
---|
911 | 1110 | int opp_id = hubp->opp_id; |
---|
.. | .. |
---|
924 | 1123 | hubp->power_gated = true; |
---|
925 | 1124 | dc->optimized_required = false; /* We're powering off, no need to optimize */ |
---|
926 | 1125 | |
---|
927 | | - plane_atomic_power_down(dc, pipe_ctx); |
---|
| 1126 | + hws->funcs.plane_atomic_power_down(dc, |
---|
| 1127 | + pipe_ctx->plane_res.dpp, |
---|
| 1128 | + pipe_ctx->plane_res.hubp); |
---|
928 | 1129 | |
---|
929 | 1130 | pipe_ctx->stream = NULL; |
---|
930 | 1131 | memset(&pipe_ctx->stream_res, 0, sizeof(pipe_ctx->stream_res)); |
---|
.. | .. |
---|
934 | 1135 | pipe_ctx->plane_state = NULL; |
---|
935 | 1136 | } |
---|
936 | 1137 | |
---|
937 | | -static void dcn10_disable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx) |
---|
| 1138 | +void dcn10_disable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx) |
---|
938 | 1139 | { |
---|
| 1140 | + struct dce_hwseq *hws = dc->hwseq; |
---|
939 | 1141 | DC_LOGGER_INIT(dc->ctx->logger); |
---|
940 | 1142 | |
---|
941 | 1143 | if (!pipe_ctx->plane_res.hubp || pipe_ctx->plane_res.hubp->power_gated) |
---|
942 | 1144 | return; |
---|
943 | 1145 | |
---|
944 | | - plane_atomic_disable(dc, pipe_ctx); |
---|
| 1146 | + hws->funcs.plane_atomic_disable(dc, pipe_ctx); |
---|
945 | 1147 | |
---|
946 | 1148 | apply_DEGVIDCN10_253_wa(dc); |
---|
947 | 1149 | |
---|
.. | .. |
---|
949 | 1151 | pipe_ctx->pipe_idx); |
---|
950 | 1152 | } |
---|
951 | 1153 | |
---|
952 | | -static void dcn10_init_hw(struct dc *dc) |
---|
| 1154 | +void dcn10_init_pipes(struct dc *dc, struct dc_state *context) |
---|
953 | 1155 | { |
---|
954 | 1156 | int i; |
---|
| 1157 | + struct dce_hwseq *hws = dc->hwseq; |
---|
| 1158 | + bool can_apply_seamless_boot = false; |
---|
| 1159 | + |
---|
| 1160 | + for (i = 0; i < context->stream_count; i++) { |
---|
| 1161 | + if (context->streams[i]->apply_seamless_boot_optimization) { |
---|
| 1162 | + can_apply_seamless_boot = true; |
---|
| 1163 | + break; |
---|
| 1164 | + } |
---|
| 1165 | + } |
---|
| 1166 | + |
---|
| 1167 | + for (i = 0; i < dc->res_pool->pipe_count; i++) { |
---|
| 1168 | + struct timing_generator *tg = dc->res_pool->timing_generators[i]; |
---|
| 1169 | + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; |
---|
| 1170 | + |
---|
| 1171 | + /* There is assumption that pipe_ctx is not mapping irregularly |
---|
| 1172 | + * to non-preferred front end. If pipe_ctx->stream is not NULL, |
---|
| 1173 | + * we will use the pipe, so don't disable |
---|
| 1174 | + */ |
---|
| 1175 | + if (pipe_ctx->stream != NULL && can_apply_seamless_boot) |
---|
| 1176 | + continue; |
---|
| 1177 | + |
---|
| 1178 | + /* Blank controller using driver code instead of |
---|
| 1179 | + * command table. |
---|
| 1180 | + */ |
---|
| 1181 | + if (tg->funcs->is_tg_enabled(tg)) { |
---|
| 1182 | + if (hws->funcs.init_blank != NULL) { |
---|
| 1183 | + hws->funcs.init_blank(dc, tg); |
---|
| 1184 | + tg->funcs->lock(tg); |
---|
| 1185 | + } else { |
---|
| 1186 | + tg->funcs->lock(tg); |
---|
| 1187 | + tg->funcs->set_blank(tg, true); |
---|
| 1188 | + hwss_wait_for_blank_complete(tg); |
---|
| 1189 | + } |
---|
| 1190 | + } |
---|
| 1191 | + } |
---|
| 1192 | + |
---|
| 1193 | + /* num_opp will be equal to number of mpcc */ |
---|
| 1194 | + for (i = 0; i < dc->res_pool->res_cap->num_opp; i++) { |
---|
| 1195 | + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; |
---|
| 1196 | + |
---|
| 1197 | + /* Cannot reset the MPC mux if seamless boot */ |
---|
| 1198 | + if (pipe_ctx->stream != NULL && can_apply_seamless_boot) |
---|
| 1199 | + continue; |
---|
| 1200 | + |
---|
| 1201 | + dc->res_pool->mpc->funcs->mpc_init_single_inst( |
---|
| 1202 | + dc->res_pool->mpc, i); |
---|
| 1203 | + } |
---|
| 1204 | + |
---|
| 1205 | + for (i = 0; i < dc->res_pool->pipe_count; i++) { |
---|
| 1206 | + struct timing_generator *tg = dc->res_pool->timing_generators[i]; |
---|
| 1207 | + struct hubp *hubp = dc->res_pool->hubps[i]; |
---|
| 1208 | + struct dpp *dpp = dc->res_pool->dpps[i]; |
---|
| 1209 | + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; |
---|
| 1210 | + |
---|
| 1211 | + /* There is assumption that pipe_ctx is not mapping irregularly |
---|
| 1212 | + * to non-preferred front end. If pipe_ctx->stream is not NULL, |
---|
| 1213 | + * we will use the pipe, so don't disable |
---|
| 1214 | + */ |
---|
| 1215 | + if (can_apply_seamless_boot && |
---|
| 1216 | + pipe_ctx->stream != NULL && |
---|
| 1217 | + pipe_ctx->stream_res.tg->funcs->is_tg_enabled( |
---|
| 1218 | + pipe_ctx->stream_res.tg)) { |
---|
| 1219 | + // Enable double buffering for OTG_BLANK no matter if |
---|
| 1220 | + // seamless boot is enabled or not to suppress global sync |
---|
| 1221 | + // signals when OTG blanked. This is to prevent pipe from |
---|
| 1222 | + // requesting data while in PSR. |
---|
| 1223 | + tg->funcs->tg_init(tg); |
---|
| 1224 | + continue; |
---|
| 1225 | + } |
---|
| 1226 | + |
---|
| 1227 | + /* Disable on the current state so the new one isn't cleared. */ |
---|
| 1228 | + pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i]; |
---|
| 1229 | + |
---|
| 1230 | + dpp->funcs->dpp_reset(dpp); |
---|
| 1231 | + |
---|
| 1232 | + pipe_ctx->stream_res.tg = tg; |
---|
| 1233 | + pipe_ctx->pipe_idx = i; |
---|
| 1234 | + |
---|
| 1235 | + pipe_ctx->plane_res.hubp = hubp; |
---|
| 1236 | + pipe_ctx->plane_res.dpp = dpp; |
---|
| 1237 | + pipe_ctx->plane_res.mpcc_inst = dpp->inst; |
---|
| 1238 | + hubp->mpcc_id = dpp->inst; |
---|
| 1239 | + hubp->opp_id = OPP_ID_INVALID; |
---|
| 1240 | + hubp->power_gated = false; |
---|
| 1241 | + |
---|
| 1242 | + dc->res_pool->opps[i]->mpc_tree_params.opp_id = dc->res_pool->opps[i]->inst; |
---|
| 1243 | + dc->res_pool->opps[i]->mpc_tree_params.opp_list = NULL; |
---|
| 1244 | + dc->res_pool->opps[i]->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true; |
---|
| 1245 | + pipe_ctx->stream_res.opp = dc->res_pool->opps[i]; |
---|
| 1246 | + |
---|
| 1247 | + hws->funcs.plane_atomic_disconnect(dc, pipe_ctx); |
---|
| 1248 | + |
---|
| 1249 | + if (tg->funcs->is_tg_enabled(tg)) |
---|
| 1250 | + tg->funcs->unlock(tg); |
---|
| 1251 | + |
---|
| 1252 | + dc->hwss.disable_plane(dc, pipe_ctx); |
---|
| 1253 | + |
---|
| 1254 | + pipe_ctx->stream_res.tg = NULL; |
---|
| 1255 | + pipe_ctx->plane_res.hubp = NULL; |
---|
| 1256 | + |
---|
| 1257 | + tg->funcs->tg_init(tg); |
---|
| 1258 | + } |
---|
| 1259 | +} |
---|
| 1260 | + |
---|
| 1261 | +void dcn10_init_hw(struct dc *dc) |
---|
| 1262 | +{ |
---|
| 1263 | + int i, j; |
---|
955 | 1264 | struct abm *abm = dc->res_pool->abm; |
---|
956 | 1265 | struct dmcu *dmcu = dc->res_pool->dmcu; |
---|
957 | 1266 | struct dce_hwseq *hws = dc->hwseq; |
---|
958 | 1267 | struct dc_bios *dcb = dc->ctx->dc_bios; |
---|
959 | | - struct dc_state *context = dc->current_state; |
---|
| 1268 | + struct resource_pool *res_pool = dc->res_pool; |
---|
| 1269 | + uint32_t backlight = MAX_BACKLIGHT_LEVEL; |
---|
| 1270 | + bool is_optimized_init_done = false; |
---|
| 1271 | + |
---|
| 1272 | + if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks) |
---|
| 1273 | + dc->clk_mgr->funcs->init_clocks(dc->clk_mgr); |
---|
| 1274 | + |
---|
| 1275 | + // Initialize the dccg |
---|
| 1276 | + if (dc->res_pool->dccg && dc->res_pool->dccg->funcs->dccg_init) |
---|
| 1277 | + dc->res_pool->dccg->funcs->dccg_init(res_pool->dccg); |
---|
960 | 1278 | |
---|
961 | 1279 | if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) { |
---|
| 1280 | + |
---|
962 | 1281 | REG_WRITE(REFCLK_CNTL, 0); |
---|
963 | 1282 | REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_ENABLE, 1); |
---|
964 | 1283 | REG_WRITE(DIO_MEM_PWR_CTRL, 0); |
---|
.. | .. |
---|
972 | 1291 | REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0); |
---|
973 | 1292 | } |
---|
974 | 1293 | |
---|
975 | | - enable_power_gating_plane(dc->hwseq, true); |
---|
976 | | - } else { |
---|
| 1294 | + //Enable ability to power gate / don't force power on permanently |
---|
| 1295 | + if (hws->funcs.enable_power_gating_plane) |
---|
| 1296 | + hws->funcs.enable_power_gating_plane(hws, true); |
---|
977 | 1297 | |
---|
978 | | - if (!dcb->funcs->is_accelerated_mode(dcb)) { |
---|
979 | | - bios_golden_init(dc); |
---|
980 | | - disable_vga(dc->hwseq); |
---|
| 1298 | + return; |
---|
| 1299 | + } |
---|
| 1300 | + |
---|
| 1301 | + if (!dcb->funcs->is_accelerated_mode(dcb)) |
---|
| 1302 | + hws->funcs.disable_vga(dc->hwseq); |
---|
| 1303 | + |
---|
| 1304 | + hws->funcs.bios_golden_init(dc); |
---|
| 1305 | + |
---|
| 1306 | + if (dc->ctx->dc_bios->fw_info_valid) { |
---|
| 1307 | + res_pool->ref_clocks.xtalin_clock_inKhz = |
---|
| 1308 | + dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency; |
---|
| 1309 | + |
---|
| 1310 | + if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) { |
---|
| 1311 | + if (res_pool->dccg && res_pool->hubbub) { |
---|
| 1312 | + |
---|
| 1313 | + (res_pool->dccg->funcs->get_dccg_ref_freq)(res_pool->dccg, |
---|
| 1314 | + dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency, |
---|
| 1315 | + &res_pool->ref_clocks.dccg_ref_clock_inKhz); |
---|
| 1316 | + |
---|
| 1317 | + (res_pool->hubbub->funcs->get_dchub_ref_freq)(res_pool->hubbub, |
---|
| 1318 | + res_pool->ref_clocks.dccg_ref_clock_inKhz, |
---|
| 1319 | + &res_pool->ref_clocks.dchub_ref_clock_inKhz); |
---|
| 1320 | + } else { |
---|
| 1321 | + // Not all ASICs have DCCG sw component |
---|
| 1322 | + res_pool->ref_clocks.dccg_ref_clock_inKhz = |
---|
| 1323 | + res_pool->ref_clocks.xtalin_clock_inKhz; |
---|
| 1324 | + res_pool->ref_clocks.dchub_ref_clock_inKhz = |
---|
| 1325 | + res_pool->ref_clocks.xtalin_clock_inKhz; |
---|
| 1326 | + } |
---|
| 1327 | + } |
---|
| 1328 | + } else |
---|
| 1329 | + ASSERT_CRITICAL(false); |
---|
| 1330 | + |
---|
| 1331 | + for (i = 0; i < dc->link_count; i++) { |
---|
| 1332 | + /* Power up AND update implementation according to the |
---|
| 1333 | + * required signal (which may be different from the |
---|
| 1334 | + * default signal on connector). |
---|
| 1335 | + */ |
---|
| 1336 | + struct dc_link *link = dc->links[i]; |
---|
| 1337 | + |
---|
| 1338 | + if (!is_optimized_init_done) |
---|
| 1339 | + link->link_enc->funcs->hw_init(link->link_enc); |
---|
| 1340 | + |
---|
| 1341 | + /* Check for enabled DIG to identify enabled display */ |
---|
| 1342 | + if (link->link_enc->funcs->is_dig_enabled && |
---|
| 1343 | + link->link_enc->funcs->is_dig_enabled(link->link_enc)) |
---|
| 1344 | + link->link_status.link_active = true; |
---|
| 1345 | + } |
---|
| 1346 | + |
---|
| 1347 | + /* Power gate DSCs */ |
---|
| 1348 | + if (!is_optimized_init_done) { |
---|
| 1349 | + for (i = 0; i < res_pool->res_cap->num_dsc; i++) |
---|
| 1350 | + if (hws->funcs.dsc_pg_control != NULL) |
---|
| 1351 | + hws->funcs.dsc_pg_control(hws, res_pool->dscs[i]->inst, false); |
---|
| 1352 | + } |
---|
| 1353 | + |
---|
| 1354 | + /* we want to turn off all dp displays before doing detection */ |
---|
| 1355 | + if (dc->config.power_down_display_on_boot) { |
---|
| 1356 | + uint8_t dpcd_power_state = '\0'; |
---|
| 1357 | + enum dc_status status = DC_ERROR_UNEXPECTED; |
---|
| 1358 | + |
---|
| 1359 | + for (i = 0; i < dc->link_count; i++) { |
---|
| 1360 | + if (dc->links[i]->connector_signal != SIGNAL_TYPE_DISPLAY_PORT) |
---|
| 1361 | + continue; |
---|
| 1362 | + |
---|
| 1363 | + /* |
---|
| 1364 | + * If any of the displays are lit up turn them off. |
---|
| 1365 | + * The reason is that some MST hubs cannot be turned off |
---|
| 1366 | + * completely until we tell them to do so. |
---|
| 1367 | + * If not turned off, then displays connected to MST hub |
---|
| 1368 | + * won't light up. |
---|
| 1369 | + */ |
---|
| 1370 | + status = core_link_read_dpcd(dc->links[i], DP_SET_POWER, |
---|
| 1371 | + &dpcd_power_state, sizeof(dpcd_power_state)); |
---|
| 1372 | + if (status == DC_OK && dpcd_power_state == DP_POWER_STATE_D0) { |
---|
| 1373 | + /* blank dp stream before power off receiver*/ |
---|
| 1374 | + if (dc->links[i]->link_enc->funcs->get_dig_frontend) { |
---|
| 1375 | + unsigned int fe = dc->links[i]->link_enc->funcs->get_dig_frontend(dc->links[i]->link_enc); |
---|
| 1376 | + |
---|
| 1377 | + for (j = 0; j < dc->res_pool->stream_enc_count; j++) { |
---|
| 1378 | + if (fe == dc->res_pool->stream_enc[j]->id) { |
---|
| 1379 | + dc->res_pool->stream_enc[j]->funcs->dp_blank( |
---|
| 1380 | + dc->res_pool->stream_enc[j]); |
---|
| 1381 | + break; |
---|
| 1382 | + } |
---|
| 1383 | + } |
---|
| 1384 | + } |
---|
| 1385 | + dp_receiver_power_ctrl(dc->links[i], false); |
---|
| 1386 | + } |
---|
| 1387 | + } |
---|
| 1388 | + } |
---|
| 1389 | + |
---|
| 1390 | + /* If taking control over from VBIOS, we may want to optimize our first |
---|
| 1391 | + * mode set, so we need to skip powering down pipes until we know which |
---|
| 1392 | + * pipes we want to use. |
---|
| 1393 | + * Otherwise, if taking control is not possible, we need to power |
---|
| 1394 | + * everything down. |
---|
| 1395 | + */ |
---|
| 1396 | + if (dcb->funcs->is_accelerated_mode(dcb) || dc->config.power_down_display_on_boot) { |
---|
| 1397 | + if (!is_optimized_init_done) { |
---|
| 1398 | + hws->funcs.init_pipes(dc, dc->current_state); |
---|
| 1399 | + if (dc->res_pool->hubbub->funcs->allow_self_refresh_control) |
---|
| 1400 | + dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub, |
---|
| 1401 | + !dc->res_pool->hubbub->ctx->dc->debug.disable_stutter); |
---|
| 1402 | + } |
---|
| 1403 | + } |
---|
| 1404 | + |
---|
| 1405 | + if (!is_optimized_init_done) { |
---|
| 1406 | + |
---|
| 1407 | + for (i = 0; i < res_pool->audio_count; i++) { |
---|
| 1408 | + struct audio *audio = res_pool->audios[i]; |
---|
| 1409 | + |
---|
| 1410 | + audio->funcs->hw_init(audio); |
---|
981 | 1411 | } |
---|
982 | 1412 | |
---|
983 | 1413 | for (i = 0; i < dc->link_count; i++) { |
---|
984 | | - /* Power up AND update implementation according to the |
---|
985 | | - * required signal (which may be different from the |
---|
986 | | - * default signal on connector). |
---|
987 | | - */ |
---|
988 | 1414 | struct dc_link *link = dc->links[i]; |
---|
989 | 1415 | |
---|
990 | | - if (link->link_enc->connector.id == CONNECTOR_ID_EDP) |
---|
991 | | - dc->hwss.edp_power_control(link, true); |
---|
992 | | - |
---|
993 | | - link->link_enc->funcs->hw_init(link->link_enc); |
---|
| 1416 | + if (link->panel_cntl) |
---|
| 1417 | + backlight = link->panel_cntl->funcs->hw_init(link->panel_cntl); |
---|
994 | 1418 | } |
---|
| 1419 | + |
---|
| 1420 | + if (abm != NULL) |
---|
| 1421 | + abm->funcs->abm_init(abm, backlight); |
---|
| 1422 | + |
---|
| 1423 | + if (dmcu != NULL && !dmcu->auto_load_dmcu) |
---|
| 1424 | + dmcu->funcs->dmcu_init(dmcu); |
---|
995 | 1425 | } |
---|
996 | 1426 | |
---|
997 | | - for (i = 0; i < dc->res_pool->pipe_count; i++) { |
---|
998 | | - struct timing_generator *tg = dc->res_pool->timing_generators[i]; |
---|
999 | | - |
---|
1000 | | - if (tg->funcs->is_tg_enabled(tg)) |
---|
1001 | | - tg->funcs->lock(tg); |
---|
1002 | | - } |
---|
1003 | | - |
---|
1004 | | - /* Blank controller using driver code instead of |
---|
1005 | | - * command table. |
---|
1006 | | - */ |
---|
1007 | | - for (i = 0; i < dc->res_pool->pipe_count; i++) { |
---|
1008 | | - struct timing_generator *tg = dc->res_pool->timing_generators[i]; |
---|
1009 | | - |
---|
1010 | | - if (tg->funcs->is_tg_enabled(tg)) { |
---|
1011 | | - tg->funcs->set_blank(tg, true); |
---|
1012 | | - hwss_wait_for_blank_complete(tg); |
---|
1013 | | - } |
---|
1014 | | - } |
---|
1015 | | - |
---|
1016 | | - /* Reset all MPCC muxes */ |
---|
1017 | | - dc->res_pool->mpc->funcs->mpc_init(dc->res_pool->mpc); |
---|
1018 | | - |
---|
1019 | | - for (i = 0; i < dc->res_pool->timing_generator_count; i++) { |
---|
1020 | | - struct timing_generator *tg = dc->res_pool->timing_generators[i]; |
---|
1021 | | - struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; |
---|
1022 | | - struct hubp *hubp = dc->res_pool->hubps[i]; |
---|
1023 | | - struct dpp *dpp = dc->res_pool->dpps[i]; |
---|
1024 | | - |
---|
1025 | | - pipe_ctx->stream_res.tg = tg; |
---|
1026 | | - pipe_ctx->pipe_idx = i; |
---|
1027 | | - |
---|
1028 | | - pipe_ctx->plane_res.hubp = hubp; |
---|
1029 | | - pipe_ctx->plane_res.dpp = dpp; |
---|
1030 | | - pipe_ctx->plane_res.mpcc_inst = dpp->inst; |
---|
1031 | | - hubp->mpcc_id = dpp->inst; |
---|
1032 | | - hubp->opp_id = 0xf; |
---|
1033 | | - hubp->power_gated = false; |
---|
1034 | | - |
---|
1035 | | - dc->res_pool->opps[i]->mpc_tree_params.opp_id = dc->res_pool->opps[i]->inst; |
---|
1036 | | - dc->res_pool->opps[i]->mpc_tree_params.opp_list = NULL; |
---|
1037 | | - dc->res_pool->opps[i]->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true; |
---|
1038 | | - pipe_ctx->stream_res.opp = dc->res_pool->opps[i]; |
---|
1039 | | - |
---|
1040 | | - hwss1_plane_atomic_disconnect(dc, pipe_ctx); |
---|
1041 | | - } |
---|
1042 | | - |
---|
1043 | | - for (i = 0; i < dc->res_pool->pipe_count; i++) { |
---|
1044 | | - struct timing_generator *tg = dc->res_pool->timing_generators[i]; |
---|
1045 | | - |
---|
1046 | | - if (tg->funcs->is_tg_enabled(tg)) |
---|
1047 | | - tg->funcs->unlock(tg); |
---|
1048 | | - } |
---|
1049 | | - |
---|
1050 | | - for (i = 0; i < dc->res_pool->pipe_count; i++) { |
---|
1051 | | - struct timing_generator *tg = dc->res_pool->timing_generators[i]; |
---|
1052 | | - struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; |
---|
1053 | | - |
---|
1054 | | - dcn10_disable_plane(dc, pipe_ctx); |
---|
1055 | | - |
---|
1056 | | - pipe_ctx->stream_res.tg = NULL; |
---|
1057 | | - pipe_ctx->plane_res.hubp = NULL; |
---|
1058 | | - |
---|
1059 | | - tg->funcs->tg_init(tg); |
---|
1060 | | - } |
---|
1061 | | - |
---|
1062 | | - /* end of FPGA. Below if real ASIC */ |
---|
1063 | | - if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) |
---|
1064 | | - return; |
---|
1065 | | - |
---|
1066 | | - for (i = 0; i < dc->res_pool->audio_count; i++) { |
---|
1067 | | - struct audio *audio = dc->res_pool->audios[i]; |
---|
1068 | | - |
---|
1069 | | - audio->funcs->hw_init(audio); |
---|
1070 | | - } |
---|
1071 | | - |
---|
1072 | | - if (abm != NULL) { |
---|
1073 | | - abm->funcs->init_backlight(abm); |
---|
1074 | | - abm->funcs->abm_init(abm); |
---|
1075 | | - } |
---|
1076 | | - |
---|
1077 | | - if (dmcu != NULL) |
---|
1078 | | - dmcu->funcs->dmcu_init(dmcu); |
---|
| 1427 | + if (abm != NULL && dmcu != NULL) |
---|
| 1428 | + abm->dmcu_is_running = dmcu->funcs->is_dmcu_initialized(dmcu); |
---|
1079 | 1429 | |
---|
1080 | 1430 | /* power AFMT HDMI memory TODO: may move to dis/en output save power*/ |
---|
1081 | | - REG_WRITE(DIO_MEM_PWR_CTRL, 0); |
---|
| 1431 | + if (!is_optimized_init_done) |
---|
| 1432 | + REG_WRITE(DIO_MEM_PWR_CTRL, 0); |
---|
1082 | 1433 | |
---|
1083 | 1434 | if (!dc->debug.disable_clock_gate) { |
---|
1084 | 1435 | /* enable all DCN clock gating */ |
---|
.. | .. |
---|
1088 | 1439 | |
---|
1089 | 1440 | REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0); |
---|
1090 | 1441 | } |
---|
| 1442 | + if (hws->funcs.enable_power_gating_plane) |
---|
| 1443 | + hws->funcs.enable_power_gating_plane(dc->hwseq, true); |
---|
1091 | 1444 | |
---|
1092 | | - enable_power_gating_plane(dc->hwseq, true); |
---|
| 1445 | + if (dc->clk_mgr->funcs->notify_wm_ranges) |
---|
| 1446 | + dc->clk_mgr->funcs->notify_wm_ranges(dc->clk_mgr); |
---|
1093 | 1447 | |
---|
1094 | | - memset(&dc->res_pool->dccg->clks, 0, sizeof(dc->res_pool->dccg->clks)); |
---|
| 1448 | +#ifdef CONFIG_DRM_AMD_DC_DCN3_0 |
---|
| 1449 | + if (dc->clk_mgr->funcs->set_hard_max_memclk) |
---|
| 1450 | + dc->clk_mgr->funcs->set_hard_max_memclk(dc->clk_mgr); |
---|
| 1451 | +#endif |
---|
| 1452 | + |
---|
1095 | 1453 | } |
---|
1096 | 1454 | |
---|
1097 | | -static void reset_hw_ctx_wrap( |
---|
| 1455 | +/* In headless boot cases, DIG may be turned |
---|
| 1456 | + * on which causes HW/SW discrepancies. |
---|
| 1457 | + * To avoid this, power down hardware on boot |
---|
| 1458 | + * if DIG is turned on and seamless boot not enabled |
---|
| 1459 | + */ |
---|
| 1460 | +void dcn10_power_down_on_boot(struct dc *dc) |
---|
| 1461 | +{ |
---|
| 1462 | + int i = 0; |
---|
| 1463 | + struct dc_link *edp_link; |
---|
| 1464 | + |
---|
| 1465 | + if (!dc->config.power_down_display_on_boot) |
---|
| 1466 | + return; |
---|
| 1467 | + |
---|
| 1468 | + edp_link = get_edp_link(dc); |
---|
| 1469 | + if (edp_link && |
---|
| 1470 | + edp_link->link_enc->funcs->is_dig_enabled && |
---|
| 1471 | + edp_link->link_enc->funcs->is_dig_enabled(edp_link->link_enc) && |
---|
| 1472 | + dc->hwseq->funcs.edp_backlight_control && |
---|
| 1473 | + dc->hwss.power_down && |
---|
| 1474 | + dc->hwss.edp_power_control) { |
---|
| 1475 | + dc->hwseq->funcs.edp_backlight_control(edp_link, false); |
---|
| 1476 | + dc->hwss.power_down(dc); |
---|
| 1477 | + dc->hwss.edp_power_control(edp_link, false); |
---|
| 1478 | + } else { |
---|
| 1479 | + for (i = 0; i < dc->link_count; i++) { |
---|
| 1480 | + struct dc_link *link = dc->links[i]; |
---|
| 1481 | + |
---|
| 1482 | + if (link->link_enc->funcs->is_dig_enabled && |
---|
| 1483 | + link->link_enc->funcs->is_dig_enabled(link->link_enc) && |
---|
| 1484 | + dc->hwss.power_down) { |
---|
| 1485 | + dc->hwss.power_down(dc); |
---|
| 1486 | + break; |
---|
| 1487 | + } |
---|
| 1488 | + |
---|
| 1489 | + } |
---|
| 1490 | + } |
---|
| 1491 | + |
---|
| 1492 | + /* |
---|
| 1493 | + * Call update_clocks with empty context |
---|
| 1494 | + * to send DISPLAY_OFF |
---|
| 1495 | + * Otherwise DISPLAY_OFF may not be asserted |
---|
| 1496 | + */ |
---|
| 1497 | + if (dc->clk_mgr->funcs->set_low_power_state) |
---|
| 1498 | + dc->clk_mgr->funcs->set_low_power_state(dc->clk_mgr); |
---|
| 1499 | +} |
---|
| 1500 | + |
---|
| 1501 | +void dcn10_reset_hw_ctx_wrap( |
---|
1098 | 1502 | struct dc *dc, |
---|
1099 | 1503 | struct dc_state *context) |
---|
1100 | 1504 | { |
---|
1101 | 1505 | int i; |
---|
| 1506 | + struct dce_hwseq *hws = dc->hwseq; |
---|
1102 | 1507 | |
---|
1103 | 1508 | /* Reset Back End*/ |
---|
1104 | 1509 | for (i = dc->res_pool->pipe_count - 1; i >= 0 ; i--) { |
---|
.. | .. |
---|
1116 | 1521 | pipe_need_reprogram(pipe_ctx_old, pipe_ctx)) { |
---|
1117 | 1522 | struct clock_source *old_clk = pipe_ctx_old->clock_source; |
---|
1118 | 1523 | |
---|
1119 | | - reset_back_end_for_pipe(dc, pipe_ctx_old, dc->current_state); |
---|
| 1524 | + dcn10_reset_back_end_for_pipe(dc, pipe_ctx_old, dc->current_state); |
---|
| 1525 | + if (hws->funcs.enable_stream_gating) |
---|
| 1526 | + hws->funcs.enable_stream_gating(dc, pipe_ctx); |
---|
1120 | 1527 | if (old_clk) |
---|
1121 | 1528 | old_clk->funcs->cs_power_down(old_clk); |
---|
1122 | 1529 | } |
---|
1123 | 1530 | } |
---|
1124 | | - |
---|
1125 | 1531 | } |
---|
1126 | 1532 | |
---|
1127 | 1533 | static bool patch_address_for_sbs_tb_stereo( |
---|
.. | .. |
---|
1150 | 1556 | return false; |
---|
1151 | 1557 | } |
---|
1152 | 1558 | |
---|
1153 | | - |
---|
1154 | | - |
---|
1155 | | -static void dcn10_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx) |
---|
| 1559 | +void dcn10_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx) |
---|
1156 | 1560 | { |
---|
1157 | 1561 | bool addr_patched = false; |
---|
1158 | 1562 | PHYSICAL_ADDRESS_LOC addr; |
---|
.. | .. |
---|
1177 | 1581 | pipe_ctx->plane_state->address.grph_stereo.left_addr = addr; |
---|
1178 | 1582 | } |
---|
1179 | 1583 | |
---|
1180 | | -static bool dcn10_set_input_transfer_func(struct pipe_ctx *pipe_ctx, |
---|
1181 | | - const struct dc_plane_state *plane_state) |
---|
| 1584 | +bool dcn10_set_input_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx, |
---|
| 1585 | + const struct dc_plane_state *plane_state) |
---|
1182 | 1586 | { |
---|
1183 | 1587 | struct dpp *dpp_base = pipe_ctx->plane_res.dpp; |
---|
1184 | 1588 | const struct dc_transfer_func *tf = NULL; |
---|
.. | .. |
---|
1210 | 1614 | dpp_base->funcs->dpp_set_degamma(dpp_base, IPP_DEGAMMA_MODE_BYPASS); |
---|
1211 | 1615 | break; |
---|
1212 | 1616 | case TRANSFER_FUNCTION_PQ: |
---|
| 1617 | + dpp_base->funcs->dpp_set_degamma(dpp_base, IPP_DEGAMMA_MODE_USER_PWL); |
---|
| 1618 | + cm_helper_translate_curve_to_degamma_hw_format(tf, &dpp_base->degamma_params); |
---|
| 1619 | + dpp_base->funcs->dpp_program_degamma_pwl(dpp_base, &dpp_base->degamma_params); |
---|
| 1620 | + result = true; |
---|
| 1621 | + break; |
---|
1213 | 1622 | default: |
---|
1214 | 1623 | result = false; |
---|
1215 | 1624 | break; |
---|
.. | .. |
---|
1227 | 1636 | return result; |
---|
1228 | 1637 | } |
---|
1229 | 1638 | |
---|
| 1639 | +#define MAX_NUM_HW_POINTS 0x200 |
---|
1230 | 1640 | |
---|
| 1641 | +static void log_tf(struct dc_context *ctx, |
---|
| 1642 | + struct dc_transfer_func *tf, uint32_t hw_points_num) |
---|
| 1643 | +{ |
---|
| 1644 | + // DC_LOG_GAMMA is default logging of all hw points |
---|
| 1645 | + // DC_LOG_ALL_GAMMA logs all points, not only hw points |
---|
| 1646 | + // DC_LOG_ALL_TF_POINTS logs all channels of the tf |
---|
| 1647 | + int i = 0; |
---|
1231 | 1648 | |
---|
| 1649 | + DC_LOGGER_INIT(ctx->logger); |
---|
| 1650 | + DC_LOG_GAMMA("Gamma Correction TF"); |
---|
| 1651 | + DC_LOG_ALL_GAMMA("Logging all tf points..."); |
---|
| 1652 | + DC_LOG_ALL_TF_CHANNELS("Logging all channels..."); |
---|
1232 | 1653 | |
---|
| 1654 | + for (i = 0; i < hw_points_num; i++) { |
---|
| 1655 | + DC_LOG_GAMMA("R\t%d\t%llu", i, tf->tf_pts.red[i].value); |
---|
| 1656 | + DC_LOG_ALL_TF_CHANNELS("G\t%d\t%llu", i, tf->tf_pts.green[i].value); |
---|
| 1657 | + DC_LOG_ALL_TF_CHANNELS("B\t%d\t%llu", i, tf->tf_pts.blue[i].value); |
---|
| 1658 | + } |
---|
1233 | 1659 | |
---|
1234 | | -static bool |
---|
1235 | | -dcn10_set_output_transfer_func(struct pipe_ctx *pipe_ctx, |
---|
1236 | | - const struct dc_stream_state *stream) |
---|
| 1660 | + for (i = hw_points_num; i < MAX_NUM_HW_POINTS; i++) { |
---|
| 1661 | + DC_LOG_ALL_GAMMA("R\t%d\t%llu", i, tf->tf_pts.red[i].value); |
---|
| 1662 | + DC_LOG_ALL_TF_CHANNELS("G\t%d\t%llu", i, tf->tf_pts.green[i].value); |
---|
| 1663 | + DC_LOG_ALL_TF_CHANNELS("B\t%d\t%llu", i, tf->tf_pts.blue[i].value); |
---|
| 1664 | + } |
---|
| 1665 | +} |
---|
| 1666 | + |
---|
| 1667 | +bool dcn10_set_output_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx, |
---|
| 1668 | + const struct dc_stream_state *stream) |
---|
1237 | 1669 | { |
---|
1238 | 1670 | struct dpp *dpp = pipe_ctx->plane_res.dpp; |
---|
1239 | 1671 | |
---|
.. | .. |
---|
1259 | 1691 | } else |
---|
1260 | 1692 | dpp->funcs->dpp_program_regamma_pwl(dpp, NULL, OPP_REGAMMA_BYPASS); |
---|
1261 | 1693 | |
---|
| 1694 | + if (stream != NULL && stream->ctx != NULL && |
---|
| 1695 | + stream->out_transfer_func != NULL) { |
---|
| 1696 | + log_tf(stream->ctx, |
---|
| 1697 | + stream->out_transfer_func, |
---|
| 1698 | + dpp->regamma_params.hw_points_num); |
---|
| 1699 | + } |
---|
| 1700 | + |
---|
1262 | 1701 | return true; |
---|
1263 | 1702 | } |
---|
1264 | 1703 | |
---|
1265 | | -static void dcn10_pipe_control_lock( |
---|
| 1704 | +void dcn10_pipe_control_lock( |
---|
1266 | 1705 | struct dc *dc, |
---|
1267 | 1706 | struct pipe_ctx *pipe, |
---|
1268 | 1707 | bool lock) |
---|
1269 | 1708 | { |
---|
| 1709 | + struct dce_hwseq *hws = dc->hwseq; |
---|
| 1710 | + |
---|
1270 | 1711 | /* use TG master update lock to lock everything on the TG |
---|
1271 | 1712 | * therefore only top pipe need to lock |
---|
1272 | 1713 | */ |
---|
1273 | | - if (pipe->top_pipe) |
---|
| 1714 | + if (!pipe || pipe->top_pipe) |
---|
1274 | 1715 | return; |
---|
1275 | 1716 | |
---|
1276 | 1717 | if (dc->debug.sanity_checks) |
---|
1277 | | - dcn10_verify_allow_pstate_change_high(dc); |
---|
| 1718 | + hws->funcs.verify_allow_pstate_change_high(dc); |
---|
1278 | 1719 | |
---|
1279 | 1720 | if (lock) |
---|
1280 | 1721 | pipe->stream_res.tg->funcs->lock(pipe->stream_res.tg); |
---|
.. | .. |
---|
1282 | 1723 | pipe->stream_res.tg->funcs->unlock(pipe->stream_res.tg); |
---|
1283 | 1724 | |
---|
1284 | 1725 | if (dc->debug.sanity_checks) |
---|
1285 | | - dcn10_verify_allow_pstate_change_high(dc); |
---|
| 1726 | + hws->funcs.verify_allow_pstate_change_high(dc); |
---|
| 1727 | +} |
---|
| 1728 | + |
---|
| 1729 | +/** |
---|
| 1730 | + * delay_cursor_until_vupdate() - Delay cursor update if too close to VUPDATE. |
---|
| 1731 | + * |
---|
| 1732 | + * Software keepout workaround to prevent cursor update locking from stalling |
---|
| 1733 | + * out cursor updates indefinitely or from old values from being retained in |
---|
| 1734 | + * the case where the viewport changes in the same frame as the cursor. |
---|
| 1735 | + * |
---|
| 1736 | + * The idea is to calculate the remaining time from VPOS to VUPDATE. If it's |
---|
| 1737 | + * too close to VUPDATE, then stall out until VUPDATE finishes. |
---|
| 1738 | + * |
---|
| 1739 | + * TODO: Optimize cursor programming to be once per frame before VUPDATE |
---|
| 1740 | + * to avoid the need for this workaround. |
---|
| 1741 | + */ |
---|
| 1742 | +static void delay_cursor_until_vupdate(struct dc *dc, struct pipe_ctx *pipe_ctx) |
---|
| 1743 | +{ |
---|
| 1744 | + struct dc_stream_state *stream = pipe_ctx->stream; |
---|
| 1745 | + struct crtc_position position; |
---|
| 1746 | + uint32_t vupdate_start, vupdate_end; |
---|
| 1747 | + unsigned int lines_to_vupdate, us_to_vupdate, vpos; |
---|
| 1748 | + unsigned int us_per_line, us_vupdate; |
---|
| 1749 | + |
---|
| 1750 | + if (!dc->hwss.calc_vupdate_position || !dc->hwss.get_position) |
---|
| 1751 | + return; |
---|
| 1752 | + |
---|
| 1753 | + if (!pipe_ctx->stream_res.stream_enc || !pipe_ctx->stream_res.tg) |
---|
| 1754 | + return; |
---|
| 1755 | + |
---|
| 1756 | + dc->hwss.calc_vupdate_position(dc, pipe_ctx, &vupdate_start, |
---|
| 1757 | + &vupdate_end); |
---|
| 1758 | + |
---|
| 1759 | + dc->hwss.get_position(&pipe_ctx, 1, &position); |
---|
| 1760 | + vpos = position.vertical_count; |
---|
| 1761 | + |
---|
| 1762 | + /* Avoid wraparound calculation issues */ |
---|
| 1763 | + vupdate_start += stream->timing.v_total; |
---|
| 1764 | + vupdate_end += stream->timing.v_total; |
---|
| 1765 | + vpos += stream->timing.v_total; |
---|
| 1766 | + |
---|
| 1767 | + if (vpos <= vupdate_start) { |
---|
| 1768 | + /* VPOS is in VACTIVE or back porch. */ |
---|
| 1769 | + lines_to_vupdate = vupdate_start - vpos; |
---|
| 1770 | + } else if (vpos > vupdate_end) { |
---|
| 1771 | + /* VPOS is in the front porch. */ |
---|
| 1772 | + return; |
---|
| 1773 | + } else { |
---|
| 1774 | + /* VPOS is in VUPDATE. */ |
---|
| 1775 | + lines_to_vupdate = 0; |
---|
| 1776 | + } |
---|
| 1777 | + |
---|
| 1778 | + /* Calculate time until VUPDATE in microseconds. */ |
---|
| 1779 | + us_per_line = |
---|
| 1780 | + stream->timing.h_total * 10000u / stream->timing.pix_clk_100hz; |
---|
| 1781 | + us_to_vupdate = lines_to_vupdate * us_per_line; |
---|
| 1782 | + |
---|
| 1783 | + /* 70 us is a conservative estimate of cursor update time*/ |
---|
| 1784 | + if (us_to_vupdate > 70) |
---|
| 1785 | + return; |
---|
| 1786 | + |
---|
| 1787 | + /* Stall out until the cursor update completes. */ |
---|
| 1788 | + if (vupdate_end < vupdate_start) |
---|
| 1789 | + vupdate_end += stream->timing.v_total; |
---|
| 1790 | + us_vupdate = (vupdate_end - vupdate_start + 1) * us_per_line; |
---|
| 1791 | + udelay(us_to_vupdate + us_vupdate); |
---|
| 1792 | +} |
---|
| 1793 | + |
---|
| 1794 | +void dcn10_cursor_lock(struct dc *dc, struct pipe_ctx *pipe, bool lock) |
---|
| 1795 | +{ |
---|
| 1796 | + /* cursor lock is per MPCC tree, so only need to lock one pipe per stream */ |
---|
| 1797 | + if (!pipe || pipe->top_pipe) |
---|
| 1798 | + return; |
---|
| 1799 | + |
---|
| 1800 | + /* Prevent cursor lock from stalling out cursor updates. */ |
---|
| 1801 | + if (lock) |
---|
| 1802 | + delay_cursor_until_vupdate(dc, pipe); |
---|
| 1803 | + |
---|
| 1804 | + if (pipe->stream && should_use_dmub_lock(pipe->stream->link)) { |
---|
| 1805 | + union dmub_hw_lock_flags hw_locks = { 0 }; |
---|
| 1806 | + struct dmub_hw_lock_inst_flags inst_flags = { 0 }; |
---|
| 1807 | + |
---|
| 1808 | + hw_locks.bits.lock_cursor = 1; |
---|
| 1809 | + inst_flags.opp_inst = pipe->stream_res.opp->inst; |
---|
| 1810 | + |
---|
| 1811 | + dmub_hw_lock_mgr_cmd(dc->ctx->dmub_srv, |
---|
| 1812 | + lock, |
---|
| 1813 | + &hw_locks, |
---|
| 1814 | + &inst_flags); |
---|
| 1815 | + } else |
---|
| 1816 | + dc->res_pool->mpc->funcs->cursor_lock(dc->res_pool->mpc, |
---|
| 1817 | + pipe->stream_res.opp->inst, lock); |
---|
1286 | 1818 | } |
---|
1287 | 1819 | |
---|
1288 | 1820 | static bool wait_for_reset_trigger_to_occur( |
---|
.. | .. |
---|
1322 | 1854 | return rc; |
---|
1323 | 1855 | } |
---|
1324 | 1856 | |
---|
1325 | | -static void dcn10_enable_timing_synchronization( |
---|
| 1857 | +void dcn10_enable_timing_synchronization( |
---|
1326 | 1858 | struct dc *dc, |
---|
1327 | 1859 | int group_index, |
---|
1328 | 1860 | int group_size, |
---|
.. | .. |
---|
1352 | 1884 | DC_SYNC_INFO("Sync complete\n"); |
---|
1353 | 1885 | } |
---|
1354 | 1886 | |
---|
1355 | | -static void dcn10_enable_per_frame_crtc_position_reset( |
---|
| 1887 | +void dcn10_enable_per_frame_crtc_position_reset( |
---|
1356 | 1888 | struct dc *dc, |
---|
1357 | 1889 | int group_size, |
---|
1358 | 1890 | struct pipe_ctx *grouped_pipes[]) |
---|
.. | .. |
---|
1365 | 1897 | if (grouped_pipes[i]->stream_res.tg->funcs->enable_crtc_reset) |
---|
1366 | 1898 | grouped_pipes[i]->stream_res.tg->funcs->enable_crtc_reset( |
---|
1367 | 1899 | grouped_pipes[i]->stream_res.tg, |
---|
1368 | | - grouped_pipes[i]->stream->triggered_crtc_reset.event_source->status.primary_otg_inst, |
---|
| 1900 | + 0, |
---|
1369 | 1901 | &grouped_pipes[i]->stream->triggered_crtc_reset); |
---|
1370 | 1902 | |
---|
1371 | 1903 | DC_SYNC_INFO("Waiting for trigger\n"); |
---|
.. | .. |
---|
1377 | 1909 | } |
---|
1378 | 1910 | |
---|
1379 | 1911 | /*static void print_rq_dlg_ttu( |
---|
1380 | | - struct dc *core_dc, |
---|
| 1912 | + struct dc *dc, |
---|
1381 | 1913 | struct pipe_ctx *pipe_ctx) |
---|
1382 | 1914 | { |
---|
1383 | | - DC_LOG_BANDWIDTH_CALCS(core_dc->ctx->logger, |
---|
| 1915 | + DC_LOG_BANDWIDTH_CALCS(dc->ctx->logger, |
---|
1384 | 1916 | "\n============== DML TTU Output parameters [%d] ==============\n" |
---|
1385 | 1917 | "qos_level_low_wm: %d, \n" |
---|
1386 | 1918 | "qos_level_high_wm: %d, \n" |
---|
.. | .. |
---|
1410 | 1942 | pipe_ctx->ttu_regs.refcyc_per_req_delivery_pre_c |
---|
1411 | 1943 | ); |
---|
1412 | 1944 | |
---|
1413 | | - DC_LOG_BANDWIDTH_CALCS(core_dc->ctx->logger, |
---|
| 1945 | + DC_LOG_BANDWIDTH_CALCS(dc->ctx->logger, |
---|
1414 | 1946 | "\n============== DML DLG Output parameters [%d] ==============\n" |
---|
1415 | 1947 | "refcyc_h_blank_end: %d, \n" |
---|
1416 | 1948 | "dlg_vblank_end: %d, \n" |
---|
.. | .. |
---|
1445 | 1977 | pipe_ctx->dlg_regs.refcyc_per_pte_group_nom_l |
---|
1446 | 1978 | ); |
---|
1447 | 1979 | |
---|
1448 | | - DC_LOG_BANDWIDTH_CALCS(core_dc->ctx->logger, |
---|
| 1980 | + DC_LOG_BANDWIDTH_CALCS(dc->ctx->logger, |
---|
1449 | 1981 | "\ndst_y_per_meta_row_nom_l: %d, \n" |
---|
1450 | 1982 | "refcyc_per_meta_chunk_nom_l: %d, \n" |
---|
1451 | 1983 | "refcyc_per_line_delivery_pre_l: %d, \n" |
---|
.. | .. |
---|
1475 | 2007 | pipe_ctx->dlg_regs.refcyc_per_line_delivery_c |
---|
1476 | 2008 | ); |
---|
1477 | 2009 | |
---|
1478 | | - DC_LOG_BANDWIDTH_CALCS(core_dc->ctx->logger, |
---|
| 2010 | + DC_LOG_BANDWIDTH_CALCS(dc->ctx->logger, |
---|
1479 | 2011 | "\n============== DML RQ Output parameters [%d] ==============\n" |
---|
1480 | 2012 | "chunk_size: %d \n" |
---|
1481 | 2013 | "min_chunk_size: %d \n" |
---|
.. | .. |
---|
1569 | 2101 | } |
---|
1570 | 2102 | |
---|
1571 | 2103 | |
---|
1572 | | -static void dcn10_program_pte_vm(struct dce_hwseq *hws, struct hubp *hubp) |
---|
| 2104 | +void dcn10_program_pte_vm(struct dce_hwseq *hws, struct hubp *hubp) |
---|
1573 | 2105 | { |
---|
1574 | 2106 | struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp); |
---|
1575 | 2107 | struct vm_system_aperture_param apt = { {{ 0 } } }; |
---|
.. | .. |
---|
1590 | 2122 | struct dce_hwseq *hws = dc->hwseq; |
---|
1591 | 2123 | |
---|
1592 | 2124 | if (dc->debug.sanity_checks) { |
---|
1593 | | - dcn10_verify_allow_pstate_change_high(dc); |
---|
| 2125 | + hws->funcs.verify_allow_pstate_change_high(dc); |
---|
1594 | 2126 | } |
---|
1595 | 2127 | |
---|
1596 | 2128 | undo_DEGVIDCN10_253_wa(dc); |
---|
.. | .. |
---|
1647 | 2179 | dcn10_program_pte_vm(hws, pipe_ctx->plane_res.hubp); |
---|
1648 | 2180 | |
---|
1649 | 2181 | if (dc->debug.sanity_checks) { |
---|
1650 | | - dcn10_verify_allow_pstate_change_high(dc); |
---|
| 2182 | + hws->funcs.verify_allow_pstate_change_high(dc); |
---|
1651 | 2183 | } |
---|
1652 | 2184 | } |
---|
1653 | 2185 | |
---|
1654 | | -static void program_gamut_remap(struct pipe_ctx *pipe_ctx) |
---|
| 2186 | +void dcn10_program_gamut_remap(struct pipe_ctx *pipe_ctx) |
---|
1655 | 2187 | { |
---|
1656 | 2188 | int i = 0; |
---|
1657 | 2189 | struct dpp_grph_csc_adjustment adjust; |
---|
.. | .. |
---|
1664 | 2196 | for (i = 0; i < CSC_TEMPERATURE_MATRIX_SIZE; i++) |
---|
1665 | 2197 | adjust.temperature_matrix[i] = |
---|
1666 | 2198 | pipe_ctx->stream->gamut_remap_matrix.matrix[i]; |
---|
| 2199 | + } else if (pipe_ctx->plane_state && |
---|
| 2200 | + pipe_ctx->plane_state->gamut_remap_matrix.enable_remap == true) { |
---|
| 2201 | + adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW; |
---|
| 2202 | + for (i = 0; i < CSC_TEMPERATURE_MATRIX_SIZE; i++) |
---|
| 2203 | + adjust.temperature_matrix[i] = |
---|
| 2204 | + pipe_ctx->plane_state->gamut_remap_matrix.matrix[i]; |
---|
1667 | 2205 | } |
---|
1668 | 2206 | |
---|
1669 | 2207 | pipe_ctx->plane_res.dpp->funcs->dpp_set_gamut_remap(pipe_ctx->plane_res.dpp, &adjust); |
---|
1670 | 2208 | } |
---|
1671 | 2209 | |
---|
1672 | 2210 | |
---|
1673 | | -static void program_csc_matrix(struct pipe_ctx *pipe_ctx, |
---|
| 2211 | +static bool dcn10_is_rear_mpo_fix_required(struct pipe_ctx *pipe_ctx, enum dc_color_space colorspace) |
---|
| 2212 | +{ |
---|
| 2213 | + if (pipe_ctx->plane_state && pipe_ctx->plane_state->layer_index > 0 && is_rgb_cspace(colorspace)) { |
---|
| 2214 | + if (pipe_ctx->top_pipe) { |
---|
| 2215 | + struct pipe_ctx *top = pipe_ctx->top_pipe; |
---|
| 2216 | + |
---|
| 2217 | + while (top->top_pipe) |
---|
| 2218 | + top = top->top_pipe; // Traverse to top pipe_ctx |
---|
| 2219 | + if (top->plane_state && top->plane_state->layer_index == 0) |
---|
| 2220 | + return true; // Front MPO plane not hidden |
---|
| 2221 | + } |
---|
| 2222 | + } |
---|
| 2223 | + return false; |
---|
| 2224 | +} |
---|
| 2225 | + |
---|
| 2226 | +static void dcn10_set_csc_adjustment_rgb_mpo_fix(struct pipe_ctx *pipe_ctx, uint16_t *matrix) |
---|
| 2227 | +{ |
---|
| 2228 | + // Override rear plane RGB bias to fix MPO brightness |
---|
| 2229 | + uint16_t rgb_bias = matrix[3]; |
---|
| 2230 | + |
---|
| 2231 | + matrix[3] = 0; |
---|
| 2232 | + matrix[7] = 0; |
---|
| 2233 | + matrix[11] = 0; |
---|
| 2234 | + pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_adjustment(pipe_ctx->plane_res.dpp, matrix); |
---|
| 2235 | + matrix[3] = rgb_bias; |
---|
| 2236 | + matrix[7] = rgb_bias; |
---|
| 2237 | + matrix[11] = rgb_bias; |
---|
| 2238 | +} |
---|
| 2239 | + |
---|
| 2240 | +void dcn10_program_output_csc(struct dc *dc, |
---|
| 2241 | + struct pipe_ctx *pipe_ctx, |
---|
1674 | 2242 | enum dc_color_space colorspace, |
---|
1675 | | - uint16_t *matrix) |
---|
| 2243 | + uint16_t *matrix, |
---|
| 2244 | + int opp_id) |
---|
1676 | 2245 | { |
---|
1677 | 2246 | if (pipe_ctx->stream->csc_color_matrix.enable_adjustment == true) { |
---|
1678 | | - if (pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_adjustment != NULL) |
---|
| 2247 | + if (pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_adjustment != NULL) { |
---|
| 2248 | + |
---|
| 2249 | + /* MPO is broken with RGB colorspaces when OCSC matrix |
---|
| 2250 | + * brightness offset >= 0 on DCN1 due to OCSC before MPC |
---|
| 2251 | + * Blending adds offsets from front + rear to rear plane |
---|
| 2252 | + * |
---|
| 2253 | + * Fix is to set RGB bias to 0 on rear plane, top plane |
---|
| 2254 | + * black value pixels add offset instead of rear + front |
---|
| 2255 | + */ |
---|
| 2256 | + |
---|
| 2257 | + int16_t rgb_bias = matrix[3]; |
---|
| 2258 | + // matrix[3/7/11] are all the same offset value |
---|
| 2259 | + |
---|
| 2260 | + if (rgb_bias > 0 && dcn10_is_rear_mpo_fix_required(pipe_ctx, colorspace)) { |
---|
| 2261 | + dcn10_set_csc_adjustment_rgb_mpo_fix(pipe_ctx, matrix); |
---|
| 2262 | + } else { |
---|
1679 | 2263 | pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_adjustment(pipe_ctx->plane_res.dpp, matrix); |
---|
| 2264 | + } |
---|
| 2265 | + } |
---|
1680 | 2266 | } else { |
---|
1681 | 2267 | if (pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_default != NULL) |
---|
1682 | 2268 | pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_default(pipe_ctx->plane_res.dpp, colorspace); |
---|
1683 | 2269 | } |
---|
1684 | 2270 | } |
---|
1685 | 2271 | |
---|
1686 | | -static void dcn10_program_output_csc(struct dc *dc, |
---|
1687 | | - struct pipe_ctx *pipe_ctx, |
---|
1688 | | - enum dc_color_space colorspace, |
---|
1689 | | - uint16_t *matrix, |
---|
1690 | | - int opp_id) |
---|
1691 | | -{ |
---|
1692 | | - if (pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_adjustment != NULL) |
---|
1693 | | - program_csc_matrix(pipe_ctx, |
---|
1694 | | - colorspace, |
---|
1695 | | - matrix); |
---|
1696 | | -} |
---|
1697 | | - |
---|
1698 | | -static bool is_lower_pipe_tree_visible(struct pipe_ctx *pipe_ctx) |
---|
1699 | | -{ |
---|
1700 | | - if (pipe_ctx->plane_state->visible) |
---|
1701 | | - return true; |
---|
1702 | | - if (pipe_ctx->bottom_pipe && is_lower_pipe_tree_visible(pipe_ctx->bottom_pipe)) |
---|
1703 | | - return true; |
---|
1704 | | - return false; |
---|
1705 | | -} |
---|
1706 | | - |
---|
1707 | | -static bool is_upper_pipe_tree_visible(struct pipe_ctx *pipe_ctx) |
---|
1708 | | -{ |
---|
1709 | | - if (pipe_ctx->plane_state->visible) |
---|
1710 | | - return true; |
---|
1711 | | - if (pipe_ctx->top_pipe && is_upper_pipe_tree_visible(pipe_ctx->top_pipe)) |
---|
1712 | | - return true; |
---|
1713 | | - return false; |
---|
1714 | | -} |
---|
1715 | | - |
---|
1716 | | -static bool is_pipe_tree_visible(struct pipe_ctx *pipe_ctx) |
---|
1717 | | -{ |
---|
1718 | | - if (pipe_ctx->plane_state->visible) |
---|
1719 | | - return true; |
---|
1720 | | - if (pipe_ctx->top_pipe && is_upper_pipe_tree_visible(pipe_ctx->top_pipe)) |
---|
1721 | | - return true; |
---|
1722 | | - if (pipe_ctx->bottom_pipe && is_lower_pipe_tree_visible(pipe_ctx->bottom_pipe)) |
---|
1723 | | - return true; |
---|
1724 | | - return false; |
---|
1725 | | -} |
---|
1726 | | - |
---|
1727 | | -bool is_rgb_cspace(enum dc_color_space output_color_space) |
---|
1728 | | -{ |
---|
1729 | | - switch (output_color_space) { |
---|
1730 | | - case COLOR_SPACE_SRGB: |
---|
1731 | | - case COLOR_SPACE_SRGB_LIMITED: |
---|
1732 | | - case COLOR_SPACE_2020_RGB_FULLRANGE: |
---|
1733 | | - case COLOR_SPACE_2020_RGB_LIMITEDRANGE: |
---|
1734 | | - case COLOR_SPACE_ADOBERGB: |
---|
1735 | | - return true; |
---|
1736 | | - case COLOR_SPACE_YCBCR601: |
---|
1737 | | - case COLOR_SPACE_YCBCR709: |
---|
1738 | | - case COLOR_SPACE_YCBCR601_LIMITED: |
---|
1739 | | - case COLOR_SPACE_YCBCR709_LIMITED: |
---|
1740 | | - case COLOR_SPACE_2020_YCBCR: |
---|
1741 | | - return false; |
---|
1742 | | - default: |
---|
1743 | | - /* Add a case to switch */ |
---|
1744 | | - BREAK_TO_DEBUGGER(); |
---|
1745 | | - return false; |
---|
1746 | | - } |
---|
1747 | | -} |
---|
1748 | | - |
---|
1749 | | -static void dcn10_get_surface_visual_confirm_color( |
---|
| 2272 | +void dcn10_get_surface_visual_confirm_color( |
---|
1750 | 2273 | const struct pipe_ctx *pipe_ctx, |
---|
1751 | 2274 | struct tg_color *color) |
---|
1752 | 2275 | { |
---|
.. | .. |
---|
1754 | 2277 | |
---|
1755 | 2278 | switch (pipe_ctx->plane_res.scl_data.format) { |
---|
1756 | 2279 | case PIXEL_FORMAT_ARGB8888: |
---|
1757 | | - /* set boarder color to red */ |
---|
| 2280 | + /* set border color to red */ |
---|
1758 | 2281 | color->color_r_cr = color_value; |
---|
1759 | 2282 | break; |
---|
1760 | 2283 | |
---|
1761 | 2284 | case PIXEL_FORMAT_ARGB2101010: |
---|
1762 | | - /* set boarder color to blue */ |
---|
| 2285 | + /* set border color to blue */ |
---|
1763 | 2286 | color->color_b_cb = color_value; |
---|
1764 | 2287 | break; |
---|
1765 | 2288 | case PIXEL_FORMAT_420BPP8: |
---|
1766 | | - /* set boarder color to green */ |
---|
| 2289 | + /* set border color to green */ |
---|
1767 | 2290 | color->color_g_y = color_value; |
---|
1768 | 2291 | break; |
---|
1769 | 2292 | case PIXEL_FORMAT_420BPP10: |
---|
1770 | | - /* set boarder color to yellow */ |
---|
| 2293 | + /* set border color to yellow */ |
---|
1771 | 2294 | color->color_g_y = color_value; |
---|
1772 | 2295 | color->color_r_cr = color_value; |
---|
1773 | 2296 | break; |
---|
1774 | 2297 | case PIXEL_FORMAT_FP16: |
---|
1775 | | - /* set boarder color to white */ |
---|
| 2298 | + /* set border color to white */ |
---|
1776 | 2299 | color->color_r_cr = color_value; |
---|
1777 | 2300 | color->color_b_cb = color_value; |
---|
1778 | 2301 | color->color_g_y = color_value; |
---|
.. | .. |
---|
1782 | 2305 | } |
---|
1783 | 2306 | } |
---|
1784 | 2307 | |
---|
1785 | | -static void dcn10_get_hdr_visual_confirm_color( |
---|
| 2308 | +void dcn10_get_hdr_visual_confirm_color( |
---|
1786 | 2309 | struct pipe_ctx *pipe_ctx, |
---|
1787 | 2310 | struct tg_color *color) |
---|
1788 | 2311 | { |
---|
.. | .. |
---|
1796 | 2319 | |
---|
1797 | 2320 | switch (top_pipe_ctx->plane_res.scl_data.format) { |
---|
1798 | 2321 | case PIXEL_FORMAT_ARGB2101010: |
---|
1799 | | - if (top_pipe_ctx->stream->out_transfer_func->tf == TRANSFER_FUNCTION_UNITY) { |
---|
1800 | | - /* HDR10, ARGB2101010 - set boarder color to red */ |
---|
| 2322 | + if (top_pipe_ctx->stream->out_transfer_func->tf == TRANSFER_FUNCTION_PQ) { |
---|
| 2323 | + /* HDR10, ARGB2101010 - set border color to red */ |
---|
1801 | 2324 | color->color_r_cr = color_value; |
---|
| 2325 | + } else if (top_pipe_ctx->stream->out_transfer_func->tf == TRANSFER_FUNCTION_GAMMA22) { |
---|
| 2326 | + /* FreeSync 2 ARGB2101010 - set border color to pink */ |
---|
| 2327 | + color->color_r_cr = color_value; |
---|
| 2328 | + color->color_b_cb = color_value; |
---|
1802 | 2329 | } |
---|
1803 | 2330 | break; |
---|
1804 | 2331 | case PIXEL_FORMAT_FP16: |
---|
1805 | 2332 | if (top_pipe_ctx->stream->out_transfer_func->tf == TRANSFER_FUNCTION_PQ) { |
---|
1806 | | - /* HDR10, FP16 - set boarder color to blue */ |
---|
| 2333 | + /* HDR10, FP16 - set border color to blue */ |
---|
1807 | 2334 | color->color_b_cb = color_value; |
---|
1808 | 2335 | } else if (top_pipe_ctx->stream->out_transfer_func->tf == TRANSFER_FUNCTION_GAMMA22) { |
---|
1809 | | - /* FreeSync 2 HDR - set boarder color to green */ |
---|
| 2336 | + /* FreeSync 2 HDR - set border color to green */ |
---|
1810 | 2337 | color->color_g_y = color_value; |
---|
1811 | 2338 | } |
---|
1812 | 2339 | break; |
---|
1813 | 2340 | default: |
---|
1814 | | - /* SDR - set boarder color to Gray */ |
---|
| 2341 | + /* SDR - set border color to Gray */ |
---|
1815 | 2342 | color->color_r_cr = color_value/2; |
---|
1816 | 2343 | color->color_b_cb = color_value/2; |
---|
1817 | 2344 | color->color_g_y = color_value/2; |
---|
.. | .. |
---|
1819 | 2346 | } |
---|
1820 | 2347 | } |
---|
1821 | 2348 | |
---|
1822 | | -static uint16_t fixed_point_to_int_frac( |
---|
1823 | | - struct fixed31_32 arg, |
---|
1824 | | - uint8_t integer_bits, |
---|
1825 | | - uint8_t fractional_bits) |
---|
1826 | | -{ |
---|
1827 | | - int32_t numerator; |
---|
1828 | | - int32_t divisor = 1 << fractional_bits; |
---|
1829 | | - |
---|
1830 | | - uint16_t result; |
---|
1831 | | - |
---|
1832 | | - uint16_t d = (uint16_t)dc_fixpt_floor( |
---|
1833 | | - dc_fixpt_abs( |
---|
1834 | | - arg)); |
---|
1835 | | - |
---|
1836 | | - if (d <= (uint16_t)(1 << integer_bits) - (1 / (uint16_t)divisor)) |
---|
1837 | | - numerator = (uint16_t)dc_fixpt_floor( |
---|
1838 | | - dc_fixpt_mul_int( |
---|
1839 | | - arg, |
---|
1840 | | - divisor)); |
---|
1841 | | - else { |
---|
1842 | | - numerator = dc_fixpt_floor( |
---|
1843 | | - dc_fixpt_sub( |
---|
1844 | | - dc_fixpt_from_int( |
---|
1845 | | - 1LL << integer_bits), |
---|
1846 | | - dc_fixpt_recip( |
---|
1847 | | - dc_fixpt_from_int( |
---|
1848 | | - divisor)))); |
---|
1849 | | - } |
---|
1850 | | - |
---|
1851 | | - if (numerator >= 0) |
---|
1852 | | - result = (uint16_t)numerator; |
---|
1853 | | - else |
---|
1854 | | - result = (uint16_t)( |
---|
1855 | | - (1 << (integer_bits + fractional_bits + 1)) + numerator); |
---|
1856 | | - |
---|
1857 | | - if ((result != 0) && dc_fixpt_lt( |
---|
1858 | | - arg, dc_fixpt_zero)) |
---|
1859 | | - result |= 1 << (integer_bits + fractional_bits); |
---|
1860 | | - |
---|
1861 | | - return result; |
---|
1862 | | -} |
---|
1863 | | - |
---|
1864 | | -void build_prescale_params(struct dc_bias_and_scale *bias_and_scale, |
---|
1865 | | - const struct dc_plane_state *plane_state) |
---|
1866 | | -{ |
---|
1867 | | - if (plane_state->format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN |
---|
1868 | | - && plane_state->format != SURFACE_PIXEL_FORMAT_INVALID |
---|
1869 | | - && plane_state->input_csc_color_matrix.enable_adjustment |
---|
1870 | | - && plane_state->coeff_reduction_factor.value != 0) { |
---|
1871 | | - bias_and_scale->scale_blue = fixed_point_to_int_frac( |
---|
1872 | | - dc_fixpt_mul(plane_state->coeff_reduction_factor, |
---|
1873 | | - dc_fixpt_from_fraction(256, 255)), |
---|
1874 | | - 2, |
---|
1875 | | - 13); |
---|
1876 | | - bias_and_scale->scale_red = bias_and_scale->scale_blue; |
---|
1877 | | - bias_and_scale->scale_green = bias_and_scale->scale_blue; |
---|
1878 | | - } else { |
---|
1879 | | - bias_and_scale->scale_blue = 0x2000; |
---|
1880 | | - bias_and_scale->scale_red = 0x2000; |
---|
1881 | | - bias_and_scale->scale_green = 0x2000; |
---|
1882 | | - } |
---|
1883 | | -} |
---|
1884 | | - |
---|
1885 | | -static void update_dpp(struct dpp *dpp, struct dc_plane_state *plane_state) |
---|
| 2349 | +static void dcn10_update_dpp(struct dpp *dpp, struct dc_plane_state *plane_state) |
---|
1886 | 2350 | { |
---|
1887 | 2351 | struct dc_bias_and_scale bns_params = {0}; |
---|
1888 | 2352 | |
---|
.. | .. |
---|
1891 | 2355 | plane_state->format, |
---|
1892 | 2356 | EXPANSION_MODE_ZERO, |
---|
1893 | 2357 | plane_state->input_csc_color_matrix, |
---|
1894 | | - plane_state->color_space); |
---|
| 2358 | + plane_state->color_space, |
---|
| 2359 | + NULL); |
---|
1895 | 2360 | |
---|
1896 | 2361 | //set scale and bias registers |
---|
1897 | 2362 | build_prescale_params(&bns_params, plane_state); |
---|
.. | .. |
---|
1899 | 2364 | dpp->funcs->dpp_program_bias_and_scale(dpp, &bns_params); |
---|
1900 | 2365 | } |
---|
1901 | 2366 | |
---|
1902 | | -static void dcn10_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx) |
---|
| 2367 | +void dcn10_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx) |
---|
1903 | 2368 | { |
---|
| 2369 | + struct dce_hwseq *hws = dc->hwseq; |
---|
1904 | 2370 | struct hubp *hubp = pipe_ctx->plane_res.hubp; |
---|
1905 | | - struct mpcc_blnd_cfg blnd_cfg = {0}; |
---|
| 2371 | + struct mpcc_blnd_cfg blnd_cfg = {{0}}; |
---|
1906 | 2372 | bool per_pixel_alpha = pipe_ctx->plane_state->per_pixel_alpha && pipe_ctx->bottom_pipe; |
---|
1907 | 2373 | int mpcc_id; |
---|
1908 | 2374 | struct mpcc *new_mpcc; |
---|
1909 | 2375 | struct mpc *mpc = dc->res_pool->mpc; |
---|
1910 | 2376 | struct mpc_tree *mpc_tree_params = &(pipe_ctx->stream_res.opp->mpc_tree_params); |
---|
1911 | 2377 | |
---|
1912 | | - |
---|
1913 | | - |
---|
1914 | | - /* TODO: proper fix once fpga works */ |
---|
1915 | | - |
---|
1916 | 2378 | if (dc->debug.visual_confirm == VISUAL_CONFIRM_HDR) { |
---|
1917 | | - dcn10_get_hdr_visual_confirm_color( |
---|
| 2379 | + hws->funcs.get_hdr_visual_confirm_color( |
---|
1918 | 2380 | pipe_ctx, &blnd_cfg.black_color); |
---|
1919 | 2381 | } else if (dc->debug.visual_confirm == VISUAL_CONFIRM_SURFACE) { |
---|
1920 | | - dcn10_get_surface_visual_confirm_color( |
---|
| 2382 | + hws->funcs.get_surface_visual_confirm_color( |
---|
1921 | 2383 | pipe_ctx, &blnd_cfg.black_color); |
---|
1922 | 2384 | } else { |
---|
1923 | 2385 | color_space_to_black_color( |
---|
.. | .. |
---|
1925 | 2387 | &blnd_cfg.black_color); |
---|
1926 | 2388 | } |
---|
1927 | 2389 | |
---|
1928 | | - if (per_pixel_alpha) |
---|
1929 | | - blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA; |
---|
1930 | | - else |
---|
1931 | | - blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_GLOBAL_ALPHA; |
---|
1932 | | - |
---|
1933 | 2390 | blnd_cfg.overlap_only = false; |
---|
1934 | | - blnd_cfg.global_alpha = 0xff; |
---|
1935 | 2391 | blnd_cfg.global_gain = 0xff; |
---|
| 2392 | + |
---|
| 2393 | + if (per_pixel_alpha && pipe_ctx->plane_state->global_alpha) { |
---|
| 2394 | + blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA_COMBINED_GLOBAL_GAIN; |
---|
| 2395 | + blnd_cfg.global_gain = pipe_ctx->plane_state->global_alpha_value; |
---|
| 2396 | + } else if (per_pixel_alpha) { |
---|
| 2397 | + blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA; |
---|
| 2398 | + } else { |
---|
| 2399 | + blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_GLOBAL_ALPHA; |
---|
| 2400 | + } |
---|
| 2401 | + |
---|
| 2402 | + if (pipe_ctx->plane_state->global_alpha) |
---|
| 2403 | + blnd_cfg.global_alpha = pipe_ctx->plane_state->global_alpha_value; |
---|
| 2404 | + else |
---|
| 2405 | + blnd_cfg.global_alpha = 0xff; |
---|
1936 | 2406 | |
---|
1937 | 2407 | /* DCN1.0 has output CM before MPC which seems to screw with |
---|
1938 | 2408 | * pre-multiplied alpha. |
---|
.. | .. |
---|
1988 | 2458 | bool per_pixel_alpha = |
---|
1989 | 2459 | pipe_ctx->plane_state->per_pixel_alpha && pipe_ctx->bottom_pipe; |
---|
1990 | 2460 | |
---|
1991 | | - /* TODO: proper fix once fpga works */ |
---|
1992 | | - |
---|
1993 | 2461 | pipe_ctx->plane_res.scl_data.lb_params.alpha_en = per_pixel_alpha; |
---|
1994 | 2462 | pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_30BPP; |
---|
1995 | 2463 | /* scaler configuration */ |
---|
.. | .. |
---|
1997 | 2465 | pipe_ctx->plane_res.dpp, &pipe_ctx->plane_res.scl_data); |
---|
1998 | 2466 | } |
---|
1999 | 2467 | |
---|
2000 | | -static void update_dchubp_dpp( |
---|
| 2468 | +static void dcn10_update_dchubp_dpp( |
---|
2001 | 2469 | struct dc *dc, |
---|
2002 | 2470 | struct pipe_ctx *pipe_ctx, |
---|
2003 | 2471 | struct dc_state *context) |
---|
2004 | 2472 | { |
---|
| 2473 | + struct dce_hwseq *hws = dc->hwseq; |
---|
2005 | 2474 | struct hubp *hubp = pipe_ctx->plane_res.hubp; |
---|
2006 | 2475 | struct dpp *dpp = pipe_ctx->plane_res.dpp; |
---|
2007 | 2476 | struct dc_plane_state *plane_state = pipe_ctx->plane_state; |
---|
2008 | | - union plane_size size = plane_state->plane_size; |
---|
| 2477 | + struct plane_size size = plane_state->plane_size; |
---|
| 2478 | + unsigned int compat_level = 0; |
---|
| 2479 | + bool should_divided_by_2 = false; |
---|
2009 | 2480 | |
---|
2010 | 2481 | /* depends on DML calculation, DPP clock value may change dynamically */ |
---|
2011 | 2482 | /* If request max dpp clk is lower than current dispclk, no need to |
---|
2012 | 2483 | * divided by 2 |
---|
2013 | 2484 | */ |
---|
2014 | 2485 | if (plane_state->update_flags.bits.full_update) { |
---|
2015 | | - bool should_divided_by_2 = context->bw.dcn.clk.dppclk_khz <= |
---|
2016 | | - dc->res_pool->dccg->clks.dispclk_khz / 2; |
---|
| 2486 | + |
---|
| 2487 | + /* new calculated dispclk, dppclk are stored in |
---|
| 2488 | + * context->bw_ctx.bw.dcn.clk.dispclk_khz / dppclk_khz. current |
---|
| 2489 | + * dispclk, dppclk are from dc->clk_mgr->clks.dispclk_khz. |
---|
| 2490 | + * dcn_validate_bandwidth compute new dispclk, dppclk. |
---|
| 2491 | + * dispclk will put in use after optimize_bandwidth when |
---|
| 2492 | + * ramp_up_dispclk_with_dpp is called. |
---|
| 2493 | + * there are two places for dppclk be put in use. One location |
---|
| 2494 | + * is the same as the location as dispclk. Another is within |
---|
| 2495 | + * update_dchubp_dpp which happens between pre_bandwidth and |
---|
| 2496 | + * optimize_bandwidth. |
---|
| 2497 | + * dppclk updated within update_dchubp_dpp will cause new |
---|
| 2498 | + * clock values of dispclk and dppclk not be in use at the same |
---|
| 2499 | + * time. when clocks are decreased, this may cause dppclk is |
---|
| 2500 | + * lower than previous configuration and let pipe stuck. |
---|
| 2501 | + * for example, eDP + external dp, change resolution of DP from |
---|
| 2502 | + * 1920x1080x144hz to 1280x960x60hz. |
---|
| 2503 | + * before change: dispclk = 337889 dppclk = 337889 |
---|
| 2504 | + * change mode, dcn_validate_bandwidth calculate |
---|
| 2505 | + * dispclk = 143122 dppclk = 143122 |
---|
| 2506 | + * update_dchubp_dpp be executed before dispclk be updated, |
---|
| 2507 | + * dispclk = 337889, but dppclk use new value dispclk /2 = |
---|
| 2508 | + * 168944. this will cause pipe pstate warning issue. |
---|
| 2509 | + * solution: between pre_bandwidth and optimize_bandwidth, while |
---|
| 2510 | + * dispclk is going to be decreased, keep dppclk = dispclk |
---|
| 2511 | + **/ |
---|
| 2512 | + if (context->bw_ctx.bw.dcn.clk.dispclk_khz < |
---|
| 2513 | + dc->clk_mgr->clks.dispclk_khz) |
---|
| 2514 | + should_divided_by_2 = false; |
---|
| 2515 | + else |
---|
| 2516 | + should_divided_by_2 = |
---|
| 2517 | + context->bw_ctx.bw.dcn.clk.dppclk_khz <= |
---|
| 2518 | + dc->clk_mgr->clks.dispclk_khz / 2; |
---|
2017 | 2519 | |
---|
2018 | 2520 | dpp->funcs->dpp_dppclk_control( |
---|
2019 | 2521 | dpp, |
---|
2020 | 2522 | should_divided_by_2, |
---|
2021 | 2523 | true); |
---|
2022 | 2524 | |
---|
2023 | | - dc->res_pool->dccg->clks.dppclk_khz = should_divided_by_2 ? |
---|
2024 | | - dc->res_pool->dccg->clks.dispclk_khz / 2 : |
---|
2025 | | - dc->res_pool->dccg->clks.dispclk_khz; |
---|
| 2525 | + if (dc->res_pool->dccg) |
---|
| 2526 | + dc->res_pool->dccg->funcs->update_dpp_dto( |
---|
| 2527 | + dc->res_pool->dccg, |
---|
| 2528 | + dpp->inst, |
---|
| 2529 | + pipe_ctx->plane_res.bw.dppclk_khz); |
---|
| 2530 | + else |
---|
| 2531 | + dc->clk_mgr->clks.dppclk_khz = should_divided_by_2 ? |
---|
| 2532 | + dc->clk_mgr->clks.dispclk_khz / 2 : |
---|
| 2533 | + dc->clk_mgr->clks.dispclk_khz; |
---|
2026 | 2534 | } |
---|
2027 | 2535 | |
---|
2028 | 2536 | /* TODO: Need input parameter to tell current DCHUB pipe tie to which OTG |
---|
.. | .. |
---|
2038 | 2546 | &pipe_ctx->ttu_regs, |
---|
2039 | 2547 | &pipe_ctx->rq_regs, |
---|
2040 | 2548 | &pipe_ctx->pipe_dlg_param); |
---|
| 2549 | + hubp->funcs->hubp_setup_interdependent( |
---|
| 2550 | + hubp, |
---|
| 2551 | + &pipe_ctx->dlg_regs, |
---|
| 2552 | + &pipe_ctx->ttu_regs); |
---|
2041 | 2553 | } |
---|
2042 | 2554 | |
---|
2043 | | - size.grph.surface_size = pipe_ctx->plane_res.scl_data.viewport; |
---|
| 2555 | + size.surface_size = pipe_ctx->plane_res.scl_data.viewport; |
---|
2044 | 2556 | |
---|
2045 | 2557 | if (plane_state->update_flags.bits.full_update || |
---|
2046 | 2558 | plane_state->update_flags.bits.bpp_change) |
---|
2047 | | - update_dpp(dpp, plane_state); |
---|
2048 | | - |
---|
2049 | | - if (plane_state->update_flags.bits.full_update || |
---|
2050 | | - plane_state->update_flags.bits.per_pixel_alpha_change) |
---|
2051 | | - dc->hwss.update_mpcc(dc, pipe_ctx); |
---|
| 2559 | + dcn10_update_dpp(dpp, plane_state); |
---|
2052 | 2560 | |
---|
2053 | 2561 | if (plane_state->update_flags.bits.full_update || |
---|
2054 | 2562 | plane_state->update_flags.bits.per_pixel_alpha_change || |
---|
| 2563 | + plane_state->update_flags.bits.global_alpha_change) |
---|
| 2564 | + hws->funcs.update_mpcc(dc, pipe_ctx); |
---|
| 2565 | + |
---|
| 2566 | + if (plane_state->update_flags.bits.full_update || |
---|
| 2567 | + plane_state->update_flags.bits.per_pixel_alpha_change || |
---|
| 2568 | + plane_state->update_flags.bits.global_alpha_change || |
---|
2055 | 2569 | plane_state->update_flags.bits.scaling_change || |
---|
2056 | 2570 | plane_state->update_flags.bits.position_change) { |
---|
2057 | 2571 | update_scaler(pipe_ctx); |
---|
.. | .. |
---|
2069 | 2583 | if (pipe_ctx->stream->cursor_attributes.address.quad_part != 0) { |
---|
2070 | 2584 | dc->hwss.set_cursor_position(pipe_ctx); |
---|
2071 | 2585 | dc->hwss.set_cursor_attribute(pipe_ctx); |
---|
| 2586 | + |
---|
| 2587 | + if (dc->hwss.set_cursor_sdr_white_level) |
---|
| 2588 | + dc->hwss.set_cursor_sdr_white_level(pipe_ctx); |
---|
2072 | 2589 | } |
---|
2073 | 2590 | |
---|
2074 | 2591 | if (plane_state->update_flags.bits.full_update) { |
---|
2075 | 2592 | /*gamut remap*/ |
---|
2076 | | - program_gamut_remap(pipe_ctx); |
---|
| 2593 | + dc->hwss.program_gamut_remap(pipe_ctx); |
---|
2077 | 2594 | |
---|
2078 | 2595 | dc->hwss.program_output_csc(dc, |
---|
2079 | 2596 | pipe_ctx, |
---|
2080 | 2597 | pipe_ctx->stream->output_color_space, |
---|
2081 | 2598 | pipe_ctx->stream->csc_color_matrix.matrix, |
---|
2082 | | - hubp->opp_id); |
---|
| 2599 | + pipe_ctx->stream_res.opp->inst); |
---|
2083 | 2600 | } |
---|
2084 | 2601 | |
---|
2085 | 2602 | if (plane_state->update_flags.bits.full_update || |
---|
.. | .. |
---|
2089 | 2606 | plane_state->update_flags.bits.swizzle_change || |
---|
2090 | 2607 | plane_state->update_flags.bits.dcc_change || |
---|
2091 | 2608 | plane_state->update_flags.bits.bpp_change || |
---|
2092 | | - plane_state->update_flags.bits.scaling_change) { |
---|
| 2609 | + plane_state->update_flags.bits.scaling_change || |
---|
| 2610 | + plane_state->update_flags.bits.plane_size_change) { |
---|
2093 | 2611 | hubp->funcs->hubp_program_surface_config( |
---|
2094 | 2612 | hubp, |
---|
2095 | 2613 | plane_state->format, |
---|
.. | .. |
---|
2097 | 2615 | &size, |
---|
2098 | 2616 | plane_state->rotation, |
---|
2099 | 2617 | &plane_state->dcc, |
---|
2100 | | - plane_state->horizontal_mirror); |
---|
| 2618 | + plane_state->horizontal_mirror, |
---|
| 2619 | + compat_level); |
---|
2101 | 2620 | } |
---|
2102 | 2621 | |
---|
2103 | 2622 | hubp->power_gated = false; |
---|
2104 | 2623 | |
---|
2105 | | - dc->hwss.update_plane_addr(dc, pipe_ctx); |
---|
| 2624 | + hws->funcs.update_plane_addr(dc, pipe_ctx); |
---|
2106 | 2625 | |
---|
2107 | 2626 | if (is_pipe_tree_visible(pipe_ctx)) |
---|
2108 | 2627 | hubp->funcs->set_blank(hubp, false); |
---|
2109 | 2628 | } |
---|
2110 | 2629 | |
---|
2111 | | -static void dcn10_blank_pixel_data( |
---|
| 2630 | +void dcn10_blank_pixel_data( |
---|
2112 | 2631 | struct dc *dc, |
---|
2113 | 2632 | struct pipe_ctx *pipe_ctx, |
---|
2114 | 2633 | bool blank) |
---|
.. | .. |
---|
2139 | 2658 | if (!blank) { |
---|
2140 | 2659 | if (stream_res->tg->funcs->set_blank) |
---|
2141 | 2660 | stream_res->tg->funcs->set_blank(stream_res->tg, blank); |
---|
2142 | | - if (stream_res->abm) |
---|
| 2661 | + if (stream_res->abm) { |
---|
| 2662 | + dc->hwss.set_pipe(pipe_ctx); |
---|
2143 | 2663 | stream_res->abm->funcs->set_abm_level(stream_res->abm, stream->abm_level); |
---|
| 2664 | + } |
---|
2144 | 2665 | } else if (blank) { |
---|
2145 | | - if (stream_res->abm) |
---|
2146 | | - stream_res->abm->funcs->set_abm_immediate_disable(stream_res->abm); |
---|
2147 | | - if (stream_res->tg->funcs->set_blank) |
---|
| 2666 | + dc->hwss.set_abm_immediate_disable(pipe_ctx); |
---|
| 2667 | + if (stream_res->tg->funcs->set_blank) { |
---|
| 2668 | + stream_res->tg->funcs->wait_for_state(stream_res->tg, CRTC_STATE_VBLANK); |
---|
2148 | 2669 | stream_res->tg->funcs->set_blank(stream_res->tg, blank); |
---|
| 2670 | + } |
---|
2149 | 2671 | } |
---|
2150 | 2672 | } |
---|
2151 | 2673 | |
---|
2152 | | -static void set_hdr_multiplier(struct pipe_ctx *pipe_ctx) |
---|
| 2674 | +void dcn10_set_hdr_multiplier(struct pipe_ctx *pipe_ctx) |
---|
2153 | 2675 | { |
---|
2154 | | - struct fixed31_32 multiplier = dc_fixpt_from_fraction( |
---|
2155 | | - pipe_ctx->plane_state->sdr_white_level, 80); |
---|
| 2676 | + struct fixed31_32 multiplier = pipe_ctx->plane_state->hdr_mult; |
---|
2156 | 2677 | uint32_t hw_mult = 0x1f000; // 1.0 default multiplier |
---|
2157 | 2678 | struct custom_float_format fmt; |
---|
2158 | 2679 | |
---|
.. | .. |
---|
2160 | 2681 | fmt.mantissa_bits = 12; |
---|
2161 | 2682 | fmt.sign = true; |
---|
2162 | 2683 | |
---|
2163 | | - if (pipe_ctx->plane_state->sdr_white_level > 80) |
---|
| 2684 | + |
---|
| 2685 | + if (!dc_fixpt_eq(multiplier, dc_fixpt_from_int(0))) // check != 0 |
---|
2164 | 2686 | convert_to_custom_float_format(multiplier, &fmt, &hw_mult); |
---|
2165 | 2687 | |
---|
2166 | 2688 | pipe_ctx->plane_res.dpp->funcs->dpp_set_hdr_multiplier( |
---|
.. | .. |
---|
2172 | 2694 | struct pipe_ctx *pipe_ctx, |
---|
2173 | 2695 | struct dc_state *context) |
---|
2174 | 2696 | { |
---|
| 2697 | + struct dce_hwseq *hws = dc->hwseq; |
---|
| 2698 | + |
---|
2175 | 2699 | if (pipe_ctx->plane_state->update_flags.bits.full_update) |
---|
2176 | 2700 | dcn10_enable_plane(dc, pipe_ctx, context); |
---|
2177 | 2701 | |
---|
2178 | | - update_dchubp_dpp(dc, pipe_ctx, context); |
---|
| 2702 | + dcn10_update_dchubp_dpp(dc, pipe_ctx, context); |
---|
2179 | 2703 | |
---|
2180 | | - set_hdr_multiplier(pipe_ctx); |
---|
| 2704 | + hws->funcs.set_hdr_multiplier(pipe_ctx); |
---|
2181 | 2705 | |
---|
2182 | 2706 | if (pipe_ctx->plane_state->update_flags.bits.full_update || |
---|
2183 | 2707 | pipe_ctx->plane_state->update_flags.bits.in_transfer_func_change || |
---|
2184 | 2708 | pipe_ctx->plane_state->update_flags.bits.gamma_change) |
---|
2185 | | - dc->hwss.set_input_transfer_func(pipe_ctx, pipe_ctx->plane_state); |
---|
| 2709 | + hws->funcs.set_input_transfer_func(dc, pipe_ctx, pipe_ctx->plane_state); |
---|
2186 | 2710 | |
---|
2187 | 2711 | /* dcn10_translate_regamma_to_hw_format takes 750us to finish |
---|
2188 | 2712 | * only do gamma programming for full update. |
---|
.. | .. |
---|
2191 | 2715 | * doing heavy calculation and programming |
---|
2192 | 2716 | */ |
---|
2193 | 2717 | if (pipe_ctx->plane_state->update_flags.bits.full_update) |
---|
2194 | | - dc->hwss.set_output_transfer_func(pipe_ctx, pipe_ctx->stream); |
---|
| 2718 | + hws->funcs.set_output_transfer_func(dc, pipe_ctx, pipe_ctx->stream); |
---|
2195 | 2719 | } |
---|
2196 | 2720 | |
---|
2197 | | -static void program_all_pipe_in_tree( |
---|
| 2721 | +static void dcn10_program_all_pipe_in_tree( |
---|
2198 | 2722 | struct dc *dc, |
---|
2199 | 2723 | struct pipe_ctx *pipe_ctx, |
---|
2200 | 2724 | struct dc_state *context) |
---|
2201 | 2725 | { |
---|
| 2726 | + struct dce_hwseq *hws = dc->hwseq; |
---|
| 2727 | + |
---|
2202 | 2728 | if (pipe_ctx->top_pipe == NULL) { |
---|
2203 | 2729 | bool blank = !is_pipe_tree_visible(pipe_ctx); |
---|
2204 | 2730 | |
---|
2205 | | - pipe_ctx->stream_res.tg->dlg_otg_param.vready_offset = pipe_ctx->pipe_dlg_param.vready_offset; |
---|
2206 | | - pipe_ctx->stream_res.tg->dlg_otg_param.vstartup_start = pipe_ctx->pipe_dlg_param.vstartup_start; |
---|
2207 | | - pipe_ctx->stream_res.tg->dlg_otg_param.vupdate_offset = pipe_ctx->pipe_dlg_param.vupdate_offset; |
---|
2208 | | - pipe_ctx->stream_res.tg->dlg_otg_param.vupdate_width = pipe_ctx->pipe_dlg_param.vupdate_width; |
---|
2209 | | - pipe_ctx->stream_res.tg->dlg_otg_param.signal = pipe_ctx->stream->signal; |
---|
2210 | | - |
---|
2211 | 2731 | pipe_ctx->stream_res.tg->funcs->program_global_sync( |
---|
2212 | | - pipe_ctx->stream_res.tg); |
---|
| 2732 | + pipe_ctx->stream_res.tg, |
---|
| 2733 | + pipe_ctx->pipe_dlg_param.vready_offset, |
---|
| 2734 | + pipe_ctx->pipe_dlg_param.vstartup_start, |
---|
| 2735 | + pipe_ctx->pipe_dlg_param.vupdate_offset, |
---|
| 2736 | + pipe_ctx->pipe_dlg_param.vupdate_width); |
---|
2213 | 2737 | |
---|
2214 | | - dc->hwss.blank_pixel_data(dc, pipe_ctx, blank); |
---|
| 2738 | + pipe_ctx->stream_res.tg->funcs->set_vtg_params( |
---|
| 2739 | + pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing); |
---|
2215 | 2740 | |
---|
| 2741 | + if (hws->funcs.setup_vupdate_interrupt) |
---|
| 2742 | + hws->funcs.setup_vupdate_interrupt(dc, pipe_ctx); |
---|
| 2743 | + |
---|
| 2744 | + hws->funcs.blank_pixel_data(dc, pipe_ctx, blank); |
---|
2216 | 2745 | } |
---|
2217 | 2746 | |
---|
2218 | | - if (pipe_ctx->plane_state != NULL) { |
---|
2219 | | - dcn10_program_pipe(dc, pipe_ctx, context); |
---|
2220 | | - } |
---|
| 2747 | + if (pipe_ctx->plane_state != NULL) |
---|
| 2748 | + hws->funcs.program_pipe(dc, pipe_ctx, context); |
---|
2221 | 2749 | |
---|
2222 | | - if (pipe_ctx->bottom_pipe != NULL && pipe_ctx->bottom_pipe != pipe_ctx) { |
---|
2223 | | - program_all_pipe_in_tree(dc, pipe_ctx->bottom_pipe, context); |
---|
2224 | | - } |
---|
| 2750 | + if (pipe_ctx->bottom_pipe != NULL && pipe_ctx->bottom_pipe != pipe_ctx) |
---|
| 2751 | + dcn10_program_all_pipe_in_tree(dc, pipe_ctx->bottom_pipe, context); |
---|
2225 | 2752 | } |
---|
2226 | 2753 | |
---|
2227 | | -static void dcn10_pplib_apply_display_requirements( |
---|
2228 | | - struct dc *dc, |
---|
2229 | | - struct dc_state *context) |
---|
2230 | | -{ |
---|
2231 | | - struct dm_pp_display_configuration *pp_display_cfg = &context->pp_display_cfg; |
---|
2232 | | - |
---|
2233 | | - pp_display_cfg->min_engine_clock_khz = dc->res_pool->dccg->clks.dcfclk_khz; |
---|
2234 | | - pp_display_cfg->min_memory_clock_khz = dc->res_pool->dccg->clks.fclk_khz; |
---|
2235 | | - pp_display_cfg->min_engine_clock_deep_sleep_khz = dc->res_pool->dccg->clks.dcfclk_deep_sleep_khz; |
---|
2236 | | - pp_display_cfg->min_dcfc_deep_sleep_clock_khz = dc->res_pool->dccg->clks.dcfclk_deep_sleep_khz; |
---|
2237 | | - pp_display_cfg->min_dcfclock_khz = dc->res_pool->dccg->clks.dcfclk_khz; |
---|
2238 | | - pp_display_cfg->disp_clk_khz = dc->res_pool->dccg->clks.dispclk_khz; |
---|
2239 | | - dce110_fill_display_configs(context, pp_display_cfg); |
---|
2240 | | - |
---|
2241 | | - if (memcmp(&dc->prev_display_config, pp_display_cfg, sizeof( |
---|
2242 | | - struct dm_pp_display_configuration)) != 0) |
---|
2243 | | - dm_pp_apply_display_requirements(dc->ctx, pp_display_cfg); |
---|
2244 | | - |
---|
2245 | | - dc->prev_display_config = *pp_display_cfg; |
---|
2246 | | -} |
---|
2247 | | - |
---|
2248 | | -static void optimize_shared_resources(struct dc *dc) |
---|
2249 | | -{ |
---|
2250 | | - if (dc->current_state->stream_count == 0) { |
---|
2251 | | - /* S0i2 message */ |
---|
2252 | | - dcn10_pplib_apply_display_requirements(dc, dc->current_state); |
---|
2253 | | - } |
---|
2254 | | - |
---|
2255 | | - if (dc->debug.pplib_wm_report_mode == WM_REPORT_OVERRIDE) |
---|
2256 | | - dcn_bw_notify_pplib_of_wm_ranges(dc); |
---|
2257 | | -} |
---|
2258 | | - |
---|
2259 | | -static void ready_shared_resources(struct dc *dc, struct dc_state *context) |
---|
2260 | | -{ |
---|
2261 | | - /* S0i2 message */ |
---|
2262 | | - if (dc->current_state->stream_count == 0 && |
---|
2263 | | - context->stream_count != 0) |
---|
2264 | | - dcn10_pplib_apply_display_requirements(dc, context); |
---|
2265 | | -} |
---|
2266 | | - |
---|
2267 | | -static struct pipe_ctx *find_top_pipe_for_stream( |
---|
| 2754 | +static struct pipe_ctx *dcn10_find_top_pipe_for_stream( |
---|
2268 | 2755 | struct dc *dc, |
---|
2269 | 2756 | struct dc_state *context, |
---|
2270 | 2757 | const struct dc_stream_state *stream) |
---|
.. | .. |
---|
2282 | 2769 | if (pipe_ctx->stream != stream) |
---|
2283 | 2770 | continue; |
---|
2284 | 2771 | |
---|
2285 | | - if (!pipe_ctx->top_pipe) |
---|
| 2772 | + if (!pipe_ctx->top_pipe && !pipe_ctx->prev_odm_pipe) |
---|
2286 | 2773 | return pipe_ctx; |
---|
2287 | 2774 | } |
---|
2288 | 2775 | return NULL; |
---|
2289 | 2776 | } |
---|
2290 | 2777 | |
---|
2291 | | -static void dcn10_apply_ctx_for_surface( |
---|
| 2778 | +bool dcn10_disconnect_pipes( |
---|
| 2779 | + struct dc *dc, |
---|
| 2780 | + struct dc_state *context) |
---|
| 2781 | +{ |
---|
| 2782 | + bool found_pipe = false; |
---|
| 2783 | + int i, j; |
---|
| 2784 | + struct dce_hwseq *hws = dc->hwseq; |
---|
| 2785 | + struct dc_state *old_ctx = dc->current_state; |
---|
| 2786 | + bool mpcc_disconnected = false; |
---|
| 2787 | + struct pipe_ctx *old_pipe; |
---|
| 2788 | + struct pipe_ctx *new_pipe; |
---|
| 2789 | + DC_LOGGER_INIT(dc->ctx->logger); |
---|
| 2790 | + |
---|
| 2791 | + /* Set pipe update flags and lock pipes */ |
---|
| 2792 | + for (i = 0; i < dc->res_pool->pipe_count; i++) { |
---|
| 2793 | + old_pipe = &dc->current_state->res_ctx.pipe_ctx[i]; |
---|
| 2794 | + new_pipe = &context->res_ctx.pipe_ctx[i]; |
---|
| 2795 | + new_pipe->update_flags.raw = 0; |
---|
| 2796 | + |
---|
| 2797 | + if (!old_pipe->plane_state && !new_pipe->plane_state) |
---|
| 2798 | + continue; |
---|
| 2799 | + |
---|
| 2800 | + if (old_pipe->plane_state && !new_pipe->plane_state) |
---|
| 2801 | + new_pipe->update_flags.bits.disable = 1; |
---|
| 2802 | + |
---|
| 2803 | + /* Check for scl update */ |
---|
| 2804 | + if (memcmp(&old_pipe->plane_res.scl_data, &new_pipe->plane_res.scl_data, sizeof(struct scaler_data))) |
---|
| 2805 | + new_pipe->update_flags.bits.scaler = 1; |
---|
| 2806 | + |
---|
| 2807 | + /* Check for vp update */ |
---|
| 2808 | + if (memcmp(&old_pipe->plane_res.scl_data.viewport, &new_pipe->plane_res.scl_data.viewport, sizeof(struct rect)) |
---|
| 2809 | + || memcmp(&old_pipe->plane_res.scl_data.viewport_c, |
---|
| 2810 | + &new_pipe->plane_res.scl_data.viewport_c, sizeof(struct rect))) |
---|
| 2811 | + new_pipe->update_flags.bits.viewport = 1; |
---|
| 2812 | + |
---|
| 2813 | + } |
---|
| 2814 | + |
---|
| 2815 | + if (!IS_DIAG_DC(dc->ctx->dce_environment)) { |
---|
| 2816 | + /* Disconnect mpcc here only if losing pipe split*/ |
---|
| 2817 | + for (i = 0; i < dc->res_pool->pipe_count; i++) { |
---|
| 2818 | + if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable && |
---|
| 2819 | + old_ctx->res_ctx.pipe_ctx[i].top_pipe) { |
---|
| 2820 | + |
---|
| 2821 | + /* Find the top pipe in the new ctx for the bottom pipe that we |
---|
| 2822 | + * want to remove by comparing the streams and planes. If both |
---|
| 2823 | + * pipes are being disabled then do it in the regular pipe |
---|
| 2824 | + * programming sequence |
---|
| 2825 | + */ |
---|
| 2826 | + for (j = 0; j < dc->res_pool->pipe_count; j++) { |
---|
| 2827 | + if (old_ctx->res_ctx.pipe_ctx[i].top_pipe->stream == context->res_ctx.pipe_ctx[j].stream && |
---|
| 2828 | + old_ctx->res_ctx.pipe_ctx[i].top_pipe->plane_state == context->res_ctx.pipe_ctx[j].plane_state && |
---|
| 2829 | + !context->res_ctx.pipe_ctx[j].top_pipe && |
---|
| 2830 | + !context->res_ctx.pipe_ctx[j].update_flags.bits.disable) { |
---|
| 2831 | + found_pipe = true; |
---|
| 2832 | + break; |
---|
| 2833 | + } |
---|
| 2834 | + } |
---|
| 2835 | + |
---|
| 2836 | + // Disconnect if the top pipe lost it's pipe split |
---|
| 2837 | + if (found_pipe && !context->res_ctx.pipe_ctx[j].bottom_pipe) { |
---|
| 2838 | + hws->funcs.plane_atomic_disconnect(dc, &dc->current_state->res_ctx.pipe_ctx[i]); |
---|
| 2839 | + DC_LOG_DC("Reset mpcc for pipe %d\n", dc->current_state->res_ctx.pipe_ctx[i].pipe_idx); |
---|
| 2840 | + mpcc_disconnected = true; |
---|
| 2841 | + } |
---|
| 2842 | + } |
---|
| 2843 | + found_pipe = false; |
---|
| 2844 | + } |
---|
| 2845 | + } |
---|
| 2846 | + |
---|
| 2847 | + if (mpcc_disconnected) { |
---|
| 2848 | + for (i = 0; i < dc->res_pool->pipe_count; i++) { |
---|
| 2849 | + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; |
---|
| 2850 | + struct pipe_ctx *old_pipe = &dc->current_state->res_ctx.pipe_ctx[i]; |
---|
| 2851 | + struct dc_plane_state *plane_state = pipe_ctx->plane_state; |
---|
| 2852 | + struct hubp *hubp = pipe_ctx->plane_res.hubp; |
---|
| 2853 | + |
---|
| 2854 | + if (!pipe_ctx || !plane_state || !pipe_ctx->stream) |
---|
| 2855 | + continue; |
---|
| 2856 | + |
---|
| 2857 | + // Only update scaler and viewport here if we lose a pipe split. |
---|
| 2858 | + // This is to prevent half the screen from being black when we |
---|
| 2859 | + // unlock after disconnecting MPCC. |
---|
| 2860 | + if (!(old_pipe && !pipe_ctx->top_pipe && |
---|
| 2861 | + !pipe_ctx->bottom_pipe && old_pipe->bottom_pipe)) |
---|
| 2862 | + continue; |
---|
| 2863 | + |
---|
| 2864 | + if (pipe_ctx->update_flags.raw || pipe_ctx->plane_state->update_flags.raw || pipe_ctx->stream->update_flags.raw) { |
---|
| 2865 | + if (pipe_ctx->update_flags.bits.scaler || |
---|
| 2866 | + plane_state->update_flags.bits.scaling_change || |
---|
| 2867 | + plane_state->update_flags.bits.position_change || |
---|
| 2868 | + plane_state->update_flags.bits.per_pixel_alpha_change || |
---|
| 2869 | + pipe_ctx->stream->update_flags.bits.scaling) { |
---|
| 2870 | + |
---|
| 2871 | + pipe_ctx->plane_res.scl_data.lb_params.alpha_en = pipe_ctx->plane_state->per_pixel_alpha; |
---|
| 2872 | + ASSERT(pipe_ctx->plane_res.scl_data.lb_params.depth == LB_PIXEL_DEPTH_30BPP); |
---|
| 2873 | + /* scaler configuration */ |
---|
| 2874 | + pipe_ctx->plane_res.dpp->funcs->dpp_set_scaler( |
---|
| 2875 | + pipe_ctx->plane_res.dpp, &pipe_ctx->plane_res.scl_data); |
---|
| 2876 | + } |
---|
| 2877 | + |
---|
| 2878 | + if (pipe_ctx->update_flags.bits.viewport || |
---|
| 2879 | + (context == dc->current_state && plane_state->update_flags.bits.position_change) || |
---|
| 2880 | + (context == dc->current_state && plane_state->update_flags.bits.scaling_change) || |
---|
| 2881 | + (context == dc->current_state && pipe_ctx->stream->update_flags.bits.scaling)) { |
---|
| 2882 | + |
---|
| 2883 | + hubp->funcs->mem_program_viewport( |
---|
| 2884 | + hubp, |
---|
| 2885 | + &pipe_ctx->plane_res.scl_data.viewport, |
---|
| 2886 | + &pipe_ctx->plane_res.scl_data.viewport_c); |
---|
| 2887 | + } |
---|
| 2888 | + } |
---|
| 2889 | + } |
---|
| 2890 | + } |
---|
| 2891 | + return mpcc_disconnected; |
---|
| 2892 | +} |
---|
| 2893 | + |
---|
| 2894 | +void dcn10_wait_for_pending_cleared(struct dc *dc, |
---|
| 2895 | + struct dc_state *context) |
---|
| 2896 | +{ |
---|
| 2897 | + struct pipe_ctx *pipe_ctx; |
---|
| 2898 | + struct timing_generator *tg; |
---|
| 2899 | + int i; |
---|
| 2900 | + |
---|
| 2901 | + for (i = 0; i < dc->res_pool->pipe_count; i++) { |
---|
| 2902 | + pipe_ctx = &context->res_ctx.pipe_ctx[i]; |
---|
| 2903 | + tg = pipe_ctx->stream_res.tg; |
---|
| 2904 | + |
---|
| 2905 | + /* |
---|
| 2906 | + * Only wait for top pipe's tg penindg bit |
---|
| 2907 | + * Also skip if pipe is disabled. |
---|
| 2908 | + */ |
---|
| 2909 | + if (pipe_ctx->top_pipe || |
---|
| 2910 | + !pipe_ctx->stream || !pipe_ctx->plane_state || |
---|
| 2911 | + !tg->funcs->is_tg_enabled(tg)) |
---|
| 2912 | + continue; |
---|
| 2913 | + |
---|
| 2914 | + /* |
---|
| 2915 | + * Wait for VBLANK then VACTIVE to ensure we get VUPDATE. |
---|
| 2916 | + * For some reason waiting for OTG_UPDATE_PENDING cleared |
---|
| 2917 | + * seems to not trigger the update right away, and if we |
---|
| 2918 | + * lock again before VUPDATE then we don't get a separated |
---|
| 2919 | + * operation. |
---|
| 2920 | + */ |
---|
| 2921 | + pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VBLANK); |
---|
| 2922 | + pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VACTIVE); |
---|
| 2923 | + } |
---|
| 2924 | +} |
---|
| 2925 | + |
---|
| 2926 | +void dcn10_apply_ctx_for_surface( |
---|
2292 | 2927 | struct dc *dc, |
---|
2293 | 2928 | const struct dc_stream_state *stream, |
---|
2294 | 2929 | int num_planes, |
---|
2295 | 2930 | struct dc_state *context) |
---|
2296 | 2931 | { |
---|
| 2932 | + struct dce_hwseq *hws = dc->hwseq; |
---|
2297 | 2933 | int i; |
---|
2298 | 2934 | struct timing_generator *tg; |
---|
2299 | | - bool removed_pipe[4] = { false }; |
---|
| 2935 | + uint32_t underflow_check_delay_us; |
---|
| 2936 | + bool interdependent_update = false; |
---|
2300 | 2937 | struct pipe_ctx *top_pipe_to_program = |
---|
2301 | | - find_top_pipe_for_stream(dc, context, stream); |
---|
| 2938 | + dcn10_find_top_pipe_for_stream(dc, context, stream); |
---|
2302 | 2939 | DC_LOGGER_INIT(dc->ctx->logger); |
---|
| 2940 | + |
---|
| 2941 | + // Clear pipe_ctx flag |
---|
| 2942 | + for (i = 0; i < dc->res_pool->pipe_count; i++) { |
---|
| 2943 | + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; |
---|
| 2944 | + pipe_ctx->update_flags.raw = 0; |
---|
| 2945 | + } |
---|
2303 | 2946 | |
---|
2304 | 2947 | if (!top_pipe_to_program) |
---|
2305 | 2948 | return; |
---|
2306 | 2949 | |
---|
2307 | 2950 | tg = top_pipe_to_program->stream_res.tg; |
---|
2308 | 2951 | |
---|
2309 | | - dcn10_pipe_control_lock(dc, top_pipe_to_program, true); |
---|
| 2952 | + interdependent_update = top_pipe_to_program->plane_state && |
---|
| 2953 | + top_pipe_to_program->plane_state->update_flags.bits.full_update; |
---|
| 2954 | + |
---|
| 2955 | + underflow_check_delay_us = dc->debug.underflow_assert_delay_us; |
---|
| 2956 | + |
---|
| 2957 | + if (underflow_check_delay_us != 0xFFFFFFFF && hws->funcs.did_underflow_occur) |
---|
| 2958 | + ASSERT(hws->funcs.did_underflow_occur(dc, top_pipe_to_program)); |
---|
| 2959 | + |
---|
| 2960 | + if (underflow_check_delay_us != 0xFFFFFFFF) |
---|
| 2961 | + udelay(underflow_check_delay_us); |
---|
| 2962 | + |
---|
| 2963 | + if (underflow_check_delay_us != 0xFFFFFFFF && hws->funcs.did_underflow_occur) |
---|
| 2964 | + ASSERT(hws->funcs.did_underflow_occur(dc, top_pipe_to_program)); |
---|
2310 | 2965 | |
---|
2311 | 2966 | if (num_planes == 0) { |
---|
2312 | 2967 | /* OTG blank before remove all front end */ |
---|
2313 | | - dc->hwss.blank_pixel_data(dc, top_pipe_to_program, true); |
---|
| 2968 | + hws->funcs.blank_pixel_data(dc, top_pipe_to_program, true); |
---|
2314 | 2969 | } |
---|
2315 | 2970 | |
---|
2316 | 2971 | /* Disconnect unused mpcc */ |
---|
.. | .. |
---|
2318 | 2973 | struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; |
---|
2319 | 2974 | struct pipe_ctx *old_pipe_ctx = |
---|
2320 | 2975 | &dc->current_state->res_ctx.pipe_ctx[i]; |
---|
2321 | | - /* |
---|
2322 | | - * Powergate reused pipes that are not powergated |
---|
2323 | | - * fairly hacky right now, using opp_id as indicator |
---|
2324 | | - * TODO: After move dc_post to dc_update, this will |
---|
2325 | | - * be removed. |
---|
2326 | | - */ |
---|
2327 | | - if (pipe_ctx->plane_state && !old_pipe_ctx->plane_state) { |
---|
2328 | | - if (old_pipe_ctx->stream_res.tg == tg && |
---|
2329 | | - old_pipe_ctx->plane_res.hubp && |
---|
2330 | | - old_pipe_ctx->plane_res.hubp->opp_id != 0xf) { |
---|
2331 | | - dcn10_disable_plane(dc, old_pipe_ctx); |
---|
2332 | | - /* |
---|
2333 | | - * power down fe will unlock when calling reset, need |
---|
2334 | | - * to lock it back here. Messy, need rework. |
---|
2335 | | - */ |
---|
2336 | | - pipe_ctx->stream_res.tg->funcs->lock(pipe_ctx->stream_res.tg); |
---|
2337 | | - } |
---|
2338 | | - } |
---|
2339 | 2976 | |
---|
2340 | 2977 | if ((!pipe_ctx->plane_state || |
---|
2341 | 2978 | pipe_ctx->stream_res.tg != old_pipe_ctx->stream_res.tg) && |
---|
2342 | 2979 | old_pipe_ctx->plane_state && |
---|
2343 | 2980 | old_pipe_ctx->stream_res.tg == tg) { |
---|
2344 | 2981 | |
---|
2345 | | - dc->hwss.plane_atomic_disconnect(dc, old_pipe_ctx); |
---|
2346 | | - removed_pipe[i] = true; |
---|
| 2982 | + hws->funcs.plane_atomic_disconnect(dc, old_pipe_ctx); |
---|
| 2983 | + pipe_ctx->update_flags.bits.disable = 1; |
---|
2347 | 2984 | |
---|
2348 | 2985 | DC_LOG_DC("Reset mpcc for pipe %d\n", |
---|
2349 | 2986 | old_pipe_ctx->pipe_idx); |
---|
.. | .. |
---|
2351 | 2988 | } |
---|
2352 | 2989 | |
---|
2353 | 2990 | if (num_planes > 0) |
---|
2354 | | - program_all_pipe_in_tree(dc, top_pipe_to_program, context); |
---|
| 2991 | + dcn10_program_all_pipe_in_tree(dc, top_pipe_to_program, context); |
---|
2355 | 2992 | |
---|
2356 | | - dcn10_pipe_control_lock(dc, top_pipe_to_program, false); |
---|
| 2993 | + /* Program secondary blending tree and writeback pipes */ |
---|
| 2994 | + if ((stream->num_wb_info > 0) && (hws->funcs.program_all_writeback_pipes_in_tree)) |
---|
| 2995 | + hws->funcs.program_all_writeback_pipes_in_tree(dc, stream, context); |
---|
| 2996 | + if (interdependent_update) |
---|
| 2997 | + for (i = 0; i < dc->res_pool->pipe_count; i++) { |
---|
| 2998 | + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; |
---|
| 2999 | + /* Skip inactive pipes and ones already updated */ |
---|
| 3000 | + if (!pipe_ctx->stream || pipe_ctx->stream == stream || |
---|
| 3001 | + !pipe_ctx->plane_state || !tg->funcs->is_tg_enabled(tg)) |
---|
| 3002 | + continue; |
---|
2357 | 3003 | |
---|
2358 | | - if (num_planes == 0) |
---|
2359 | | - false_optc_underflow_wa(dc, stream, tg); |
---|
| 3004 | + pipe_ctx->plane_res.hubp->funcs->hubp_setup_interdependent( |
---|
| 3005 | + pipe_ctx->plane_res.hubp, |
---|
| 3006 | + &pipe_ctx->dlg_regs, |
---|
| 3007 | + &pipe_ctx->ttu_regs); |
---|
| 3008 | + } |
---|
| 3009 | +} |
---|
| 3010 | + |
---|
| 3011 | +void dcn10_post_unlock_program_front_end( |
---|
| 3012 | + struct dc *dc, |
---|
| 3013 | + struct dc_state *context) |
---|
| 3014 | +{ |
---|
| 3015 | + int i; |
---|
| 3016 | + |
---|
| 3017 | + DC_LOGGER_INIT(dc->ctx->logger); |
---|
| 3018 | + |
---|
| 3019 | + for (i = 0; i < dc->res_pool->pipe_count; i++) { |
---|
| 3020 | + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; |
---|
| 3021 | + |
---|
| 3022 | + if (!pipe_ctx->top_pipe && |
---|
| 3023 | + !pipe_ctx->prev_odm_pipe && |
---|
| 3024 | + pipe_ctx->stream) { |
---|
| 3025 | + struct timing_generator *tg = pipe_ctx->stream_res.tg; |
---|
| 3026 | + |
---|
| 3027 | + if (context->stream_status[i].plane_count == 0) |
---|
| 3028 | + false_optc_underflow_wa(dc, pipe_ctx->stream, tg); |
---|
| 3029 | + } |
---|
| 3030 | + } |
---|
2360 | 3031 | |
---|
2361 | 3032 | for (i = 0; i < dc->res_pool->pipe_count; i++) |
---|
2362 | | - if (removed_pipe[i]) |
---|
2363 | | - dcn10_disable_plane(dc, &dc->current_state->res_ctx.pipe_ctx[i]); |
---|
| 3033 | + if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable) |
---|
| 3034 | + dc->hwss.disable_plane(dc, &dc->current_state->res_ctx.pipe_ctx[i]); |
---|
| 3035 | + |
---|
| 3036 | + for (i = 0; i < dc->res_pool->pipe_count; i++) |
---|
| 3037 | + if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable) { |
---|
| 3038 | + dc->hwss.optimize_bandwidth(dc, context); |
---|
| 3039 | + break; |
---|
| 3040 | + } |
---|
2364 | 3041 | |
---|
2365 | 3042 | if (dc->hwseq->wa.DEGVIDCN10_254) |
---|
2366 | 3043 | hubbub1_wm_change_req_wa(dc->res_pool->hubbub); |
---|
2367 | 3044 | } |
---|
2368 | 3045 | |
---|
2369 | | -static void dcn10_set_bandwidth( |
---|
2370 | | - struct dc *dc, |
---|
2371 | | - struct dc_state *context, |
---|
2372 | | - bool safe_to_lower) |
---|
| 3046 | +static void dcn10_stereo_hw_frame_pack_wa(struct dc *dc, struct dc_state *context) |
---|
2373 | 3047 | { |
---|
| 3048 | + uint8_t i; |
---|
| 3049 | + |
---|
| 3050 | + for (i = 0; i < context->stream_count; i++) { |
---|
| 3051 | + if (context->streams[i]->timing.timing_3d_format |
---|
| 3052 | + == TIMING_3D_FORMAT_HW_FRAME_PACKING) { |
---|
| 3053 | + /* |
---|
| 3054 | + * Disable stutter |
---|
| 3055 | + */ |
---|
| 3056 | + hubbub1_allow_self_refresh_control(dc->res_pool->hubbub, false); |
---|
| 3057 | + break; |
---|
| 3058 | + } |
---|
| 3059 | + } |
---|
| 3060 | +} |
---|
| 3061 | + |
---|
| 3062 | +void dcn10_prepare_bandwidth( |
---|
| 3063 | + struct dc *dc, |
---|
| 3064 | + struct dc_state *context) |
---|
| 3065 | +{ |
---|
| 3066 | + struct dce_hwseq *hws = dc->hwseq; |
---|
| 3067 | + struct hubbub *hubbub = dc->res_pool->hubbub; |
---|
| 3068 | + |
---|
2374 | 3069 | if (dc->debug.sanity_checks) |
---|
2375 | | - dcn10_verify_allow_pstate_change_high(dc); |
---|
| 3070 | + hws->funcs.verify_allow_pstate_change_high(dc); |
---|
2376 | 3071 | |
---|
2377 | 3072 | if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) { |
---|
2378 | 3073 | if (context->stream_count == 0) |
---|
2379 | | - context->bw.dcn.clk.phyclk_khz = 0; |
---|
| 3074 | + context->bw_ctx.bw.dcn.clk.phyclk_khz = 0; |
---|
2380 | 3075 | |
---|
2381 | | - dc->res_pool->dccg->funcs->update_clocks( |
---|
2382 | | - dc->res_pool->dccg, |
---|
2383 | | - &context->bw.dcn.clk, |
---|
2384 | | - safe_to_lower); |
---|
2385 | | - |
---|
2386 | | - dcn10_pplib_apply_display_requirements(dc, context); |
---|
| 3076 | + dc->clk_mgr->funcs->update_clocks( |
---|
| 3077 | + dc->clk_mgr, |
---|
| 3078 | + context, |
---|
| 3079 | + false); |
---|
2387 | 3080 | } |
---|
2388 | 3081 | |
---|
2389 | | - hubbub1_program_watermarks(dc->res_pool->hubbub, |
---|
2390 | | - &context->bw.dcn.watermarks, |
---|
2391 | | - dc->res_pool->ref_clock_inKhz / 1000, |
---|
| 3082 | + dc->wm_optimized_required = hubbub->funcs->program_watermarks(hubbub, |
---|
| 3083 | + &context->bw_ctx.bw.dcn.watermarks, |
---|
| 3084 | + dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000, |
---|
2392 | 3085 | true); |
---|
| 3086 | + dcn10_stereo_hw_frame_pack_wa(dc, context); |
---|
| 3087 | + |
---|
| 3088 | + if (dc->debug.pplib_wm_report_mode == WM_REPORT_OVERRIDE) |
---|
| 3089 | + dcn_bw_notify_pplib_of_wm_ranges(dc); |
---|
2393 | 3090 | |
---|
2394 | 3091 | if (dc->debug.sanity_checks) |
---|
2395 | | - dcn10_verify_allow_pstate_change_high(dc); |
---|
| 3092 | + hws->funcs.verify_allow_pstate_change_high(dc); |
---|
2396 | 3093 | } |
---|
2397 | 3094 | |
---|
2398 | | -static void set_drr(struct pipe_ctx **pipe_ctx, |
---|
2399 | | - int num_pipes, int vmin, int vmax) |
---|
| 3095 | +void dcn10_optimize_bandwidth( |
---|
| 3096 | + struct dc *dc, |
---|
| 3097 | + struct dc_state *context) |
---|
| 3098 | +{ |
---|
| 3099 | + struct dce_hwseq *hws = dc->hwseq; |
---|
| 3100 | + struct hubbub *hubbub = dc->res_pool->hubbub; |
---|
| 3101 | + |
---|
| 3102 | + if (dc->debug.sanity_checks) |
---|
| 3103 | + hws->funcs.verify_allow_pstate_change_high(dc); |
---|
| 3104 | + |
---|
| 3105 | + if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) { |
---|
| 3106 | + if (context->stream_count == 0) |
---|
| 3107 | + context->bw_ctx.bw.dcn.clk.phyclk_khz = 0; |
---|
| 3108 | + |
---|
| 3109 | + dc->clk_mgr->funcs->update_clocks( |
---|
| 3110 | + dc->clk_mgr, |
---|
| 3111 | + context, |
---|
| 3112 | + true); |
---|
| 3113 | + } |
---|
| 3114 | + |
---|
| 3115 | + hubbub->funcs->program_watermarks(hubbub, |
---|
| 3116 | + &context->bw_ctx.bw.dcn.watermarks, |
---|
| 3117 | + dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000, |
---|
| 3118 | + true); |
---|
| 3119 | + |
---|
| 3120 | + dcn10_stereo_hw_frame_pack_wa(dc, context); |
---|
| 3121 | + |
---|
| 3122 | + if (dc->debug.pplib_wm_report_mode == WM_REPORT_OVERRIDE) |
---|
| 3123 | + dcn_bw_notify_pplib_of_wm_ranges(dc); |
---|
| 3124 | + |
---|
| 3125 | + if (dc->debug.sanity_checks) |
---|
| 3126 | + hws->funcs.verify_allow_pstate_change_high(dc); |
---|
| 3127 | +} |
---|
| 3128 | + |
---|
| 3129 | +void dcn10_set_drr(struct pipe_ctx **pipe_ctx, |
---|
| 3130 | + int num_pipes, unsigned int vmin, unsigned int vmax, |
---|
| 3131 | + unsigned int vmid, unsigned int vmid_frame_number) |
---|
2400 | 3132 | { |
---|
2401 | 3133 | int i = 0; |
---|
2402 | 3134 | struct drr_params params = {0}; |
---|
| 3135 | + // DRR set trigger event mapped to OTG_TRIG_A (bit 11) for manual control flow |
---|
| 3136 | + unsigned int event_triggers = 0x800; |
---|
| 3137 | + // Note DRR trigger events are generated regardless of whether num frames met. |
---|
| 3138 | + unsigned int num_frames = 2; |
---|
2403 | 3139 | |
---|
2404 | 3140 | params.vertical_total_max = vmax; |
---|
2405 | 3141 | params.vertical_total_min = vmin; |
---|
| 3142 | + params.vertical_total_mid = vmid; |
---|
| 3143 | + params.vertical_total_mid_frame_num = vmid_frame_number; |
---|
2406 | 3144 | |
---|
2407 | 3145 | /* TODO: If multiple pipes are to be supported, you need |
---|
2408 | | - * some GSL stuff |
---|
| 3146 | + * some GSL stuff. Static screen triggers may be programmed differently |
---|
| 3147 | + * as well. |
---|
2409 | 3148 | */ |
---|
2410 | 3149 | for (i = 0; i < num_pipes; i++) { |
---|
2411 | | - pipe_ctx[i]->stream_res.tg->funcs->set_drr(pipe_ctx[i]->stream_res.tg, ¶ms); |
---|
| 3150 | + pipe_ctx[i]->stream_res.tg->funcs->set_drr( |
---|
| 3151 | + pipe_ctx[i]->stream_res.tg, ¶ms); |
---|
| 3152 | + if (vmax != 0 && vmin != 0) |
---|
| 3153 | + pipe_ctx[i]->stream_res.tg->funcs->set_static_screen_control( |
---|
| 3154 | + pipe_ctx[i]->stream_res.tg, |
---|
| 3155 | + event_triggers, num_frames); |
---|
2412 | 3156 | } |
---|
2413 | 3157 | } |
---|
2414 | 3158 | |
---|
2415 | | -static void get_position(struct pipe_ctx **pipe_ctx, |
---|
| 3159 | +void dcn10_get_position(struct pipe_ctx **pipe_ctx, |
---|
2416 | 3160 | int num_pipes, |
---|
2417 | 3161 | struct crtc_position *position) |
---|
2418 | 3162 | { |
---|
.. | .. |
---|
2424 | 3168 | pipe_ctx[i]->stream_res.tg->funcs->get_position(pipe_ctx[i]->stream_res.tg, position); |
---|
2425 | 3169 | } |
---|
2426 | 3170 | |
---|
2427 | | -static void set_static_screen_control(struct pipe_ctx **pipe_ctx, |
---|
2428 | | - int num_pipes, const struct dc_static_screen_events *events) |
---|
| 3171 | +void dcn10_set_static_screen_control(struct pipe_ctx **pipe_ctx, |
---|
| 3172 | + int num_pipes, const struct dc_static_screen_params *params) |
---|
2429 | 3173 | { |
---|
2430 | 3174 | unsigned int i; |
---|
2431 | | - unsigned int value = 0; |
---|
| 3175 | + unsigned int triggers = 0; |
---|
2432 | 3176 | |
---|
2433 | | - if (events->surface_update) |
---|
2434 | | - value |= 0x80; |
---|
2435 | | - if (events->cursor_update) |
---|
2436 | | - value |= 0x2; |
---|
2437 | | - if (events->force_trigger) |
---|
2438 | | - value |= 0x1; |
---|
| 3177 | + if (params->triggers.surface_update) |
---|
| 3178 | + triggers |= 0x80; |
---|
| 3179 | + if (params->triggers.cursor_update) |
---|
| 3180 | + triggers |= 0x2; |
---|
| 3181 | + if (params->triggers.force_trigger) |
---|
| 3182 | + triggers |= 0x1; |
---|
2439 | 3183 | |
---|
2440 | 3184 | for (i = 0; i < num_pipes; i++) |
---|
2441 | 3185 | pipe_ctx[i]->stream_res.tg->funcs-> |
---|
2442 | | - set_static_screen_control(pipe_ctx[i]->stream_res.tg, value); |
---|
| 3186 | + set_static_screen_control(pipe_ctx[i]->stream_res.tg, |
---|
| 3187 | + triggers, params->num_frames); |
---|
2443 | 3188 | } |
---|
2444 | 3189 | |
---|
2445 | 3190 | static void dcn10_config_stereo_parameters( |
---|
.. | .. |
---|
2464 | 3209 | timing_3d_format == TIMING_3D_FORMAT_DP_HDMI_INBAND_FA || |
---|
2465 | 3210 | timing_3d_format == TIMING_3D_FORMAT_SIDEBAND_FA) { |
---|
2466 | 3211 | enum display_dongle_type dongle = \ |
---|
2467 | | - stream->sink->link->ddc->dongle_type; |
---|
| 3212 | + stream->link->ddc->dongle_type; |
---|
2468 | 3213 | if (dongle == DISPLAY_DONGLE_DP_VGA_CONVERTER || |
---|
2469 | 3214 | dongle == DISPLAY_DONGLE_DP_DVI_CONVERTER || |
---|
2470 | 3215 | dongle == DISPLAY_DONGLE_DP_HDMI_CONVERTER) |
---|
.. | .. |
---|
2479 | 3224 | return; |
---|
2480 | 3225 | } |
---|
2481 | 3226 | |
---|
2482 | | -static void dcn10_setup_stereo(struct pipe_ctx *pipe_ctx, struct dc *dc) |
---|
| 3227 | +void dcn10_setup_stereo(struct pipe_ctx *pipe_ctx, struct dc *dc) |
---|
2483 | 3228 | { |
---|
2484 | 3229 | struct crtc_stereo_flags flags = { 0 }; |
---|
2485 | 3230 | struct dc_stream_state *stream = pipe_ctx->stream; |
---|
2486 | 3231 | |
---|
2487 | 3232 | dcn10_config_stereo_parameters(stream, &flags); |
---|
| 3233 | + |
---|
| 3234 | + if (stream->timing.timing_3d_format == TIMING_3D_FORMAT_SIDEBAND_FA) { |
---|
| 3235 | + if (!dc_set_generic_gpio_for_stereo(true, dc->ctx->gpio_service)) |
---|
| 3236 | + dc_set_generic_gpio_for_stereo(false, dc->ctx->gpio_service); |
---|
| 3237 | + } else { |
---|
| 3238 | + dc_set_generic_gpio_for_stereo(false, dc->ctx->gpio_service); |
---|
| 3239 | + } |
---|
2488 | 3240 | |
---|
2489 | 3241 | pipe_ctx->stream_res.opp->funcs->opp_program_stereo( |
---|
2490 | 3242 | pipe_ctx->stream_res.opp, |
---|
.. | .. |
---|
2511 | 3263 | return NULL; |
---|
2512 | 3264 | } |
---|
2513 | 3265 | |
---|
2514 | | -static void dcn10_wait_for_mpcc_disconnect( |
---|
| 3266 | +void dcn10_wait_for_mpcc_disconnect( |
---|
2515 | 3267 | struct dc *dc, |
---|
2516 | 3268 | struct resource_pool *res_pool, |
---|
2517 | 3269 | struct pipe_ctx *pipe_ctx) |
---|
2518 | 3270 | { |
---|
| 3271 | + struct dce_hwseq *hws = dc->hwseq; |
---|
2519 | 3272 | int mpcc_inst; |
---|
2520 | 3273 | |
---|
2521 | 3274 | if (dc->debug.sanity_checks) { |
---|
2522 | | - dcn10_verify_allow_pstate_change_high(dc); |
---|
| 3275 | + hws->funcs.verify_allow_pstate_change_high(dc); |
---|
2523 | 3276 | } |
---|
2524 | 3277 | |
---|
2525 | 3278 | if (!pipe_ctx->stream_res.opp) |
---|
.. | .. |
---|
2529 | 3282 | if (pipe_ctx->stream_res.opp->mpcc_disconnect_pending[mpcc_inst]) { |
---|
2530 | 3283 | struct hubp *hubp = get_hubp_by_inst(res_pool, mpcc_inst); |
---|
2531 | 3284 | |
---|
2532 | | - res_pool->mpc->funcs->wait_for_idle(res_pool->mpc, mpcc_inst); |
---|
| 3285 | + if (pipe_ctx->stream_res.tg && |
---|
| 3286 | + pipe_ctx->stream_res.tg->funcs->is_tg_enabled(pipe_ctx->stream_res.tg)) |
---|
| 3287 | + res_pool->mpc->funcs->wait_for_idle(res_pool->mpc, mpcc_inst); |
---|
2533 | 3288 | pipe_ctx->stream_res.opp->mpcc_disconnect_pending[mpcc_inst] = false; |
---|
2534 | 3289 | hubp->funcs->set_blank(hubp, true); |
---|
2535 | | - /*DC_LOG_ERROR(dc->ctx->logger, |
---|
2536 | | - "[debug_mpo: wait_for_mpcc finished waiting on mpcc %d]\n", |
---|
2537 | | - i);*/ |
---|
2538 | 3290 | } |
---|
2539 | 3291 | } |
---|
2540 | 3292 | |
---|
2541 | 3293 | if (dc->debug.sanity_checks) { |
---|
2542 | | - dcn10_verify_allow_pstate_change_high(dc); |
---|
| 3294 | + hws->funcs.verify_allow_pstate_change_high(dc); |
---|
2543 | 3295 | } |
---|
2544 | 3296 | |
---|
2545 | 3297 | } |
---|
2546 | 3298 | |
---|
2547 | | -static bool dcn10_dummy_display_power_gating( |
---|
| 3299 | +bool dcn10_dummy_display_power_gating( |
---|
2548 | 3300 | struct dc *dc, |
---|
2549 | 3301 | uint8_t controller_id, |
---|
2550 | 3302 | struct dc_bios *dcb, |
---|
.. | .. |
---|
2553 | 3305 | return true; |
---|
2554 | 3306 | } |
---|
2555 | 3307 | |
---|
2556 | | -static void dcn10_update_pending_status(struct pipe_ctx *pipe_ctx) |
---|
| 3308 | +void dcn10_update_pending_status(struct pipe_ctx *pipe_ctx) |
---|
2557 | 3309 | { |
---|
2558 | 3310 | struct dc_plane_state *plane_state = pipe_ctx->plane_state; |
---|
2559 | 3311 | struct timing_generator *tg = pipe_ctx->stream_res.tg; |
---|
2560 | 3312 | bool flip_pending; |
---|
| 3313 | + struct dc *dc = plane_state->ctx->dc; |
---|
2561 | 3314 | |
---|
2562 | 3315 | if (plane_state == NULL) |
---|
2563 | 3316 | return; |
---|
.. | .. |
---|
2565 | 3318 | flip_pending = pipe_ctx->plane_res.hubp->funcs->hubp_is_flip_pending( |
---|
2566 | 3319 | pipe_ctx->plane_res.hubp); |
---|
2567 | 3320 | |
---|
2568 | | - plane_state->status.is_flip_pending = flip_pending; |
---|
| 3321 | + plane_state->status.is_flip_pending = plane_state->status.is_flip_pending || flip_pending; |
---|
2569 | 3322 | |
---|
2570 | 3323 | if (!flip_pending) |
---|
2571 | 3324 | plane_state->status.current_address = plane_state->status.requested_address; |
---|
.. | .. |
---|
2575 | 3328 | plane_state->status.is_right_eye = |
---|
2576 | 3329 | !tg->funcs->is_stereo_left_eye(pipe_ctx->stream_res.tg); |
---|
2577 | 3330 | } |
---|
2578 | | -} |
---|
2579 | 3331 | |
---|
2580 | | -static void dcn10_update_dchub(struct dce_hwseq *hws, struct dchub_init_data *dh_data) |
---|
2581 | | -{ |
---|
2582 | | - if (hws->ctx->dc->res_pool->hubbub != NULL) { |
---|
2583 | | - struct hubp *hubp = hws->ctx->dc->res_pool->hubps[0]; |
---|
| 3332 | + if (dc->hwseq->wa_state.disallow_self_refresh_during_multi_plane_transition_applied) { |
---|
| 3333 | + struct dce_hwseq *hwseq = dc->hwseq; |
---|
| 3334 | + struct timing_generator *tg = dc->res_pool->timing_generators[0]; |
---|
| 3335 | + unsigned int cur_frame = tg->funcs->get_frame_count(tg); |
---|
2584 | 3336 | |
---|
2585 | | - if (hubp->funcs->hubp_update_dchub) |
---|
2586 | | - hubp->funcs->hubp_update_dchub(hubp, dh_data); |
---|
2587 | | - else |
---|
2588 | | - hubbub1_update_dchub(hws->ctx->dc->res_pool->hubbub, dh_data); |
---|
| 3337 | + if (cur_frame != hwseq->wa_state.disallow_self_refresh_during_multi_plane_transition_applied_on_frame) { |
---|
| 3338 | + struct hubbub *hubbub = dc->res_pool->hubbub; |
---|
| 3339 | + |
---|
| 3340 | + hubbub->funcs->allow_self_refresh_control(hubbub, !dc->debug.disable_stutter); |
---|
| 3341 | + hwseq->wa_state.disallow_self_refresh_during_multi_plane_transition_applied = false; |
---|
| 3342 | + } |
---|
2589 | 3343 | } |
---|
2590 | 3344 | } |
---|
2591 | 3345 | |
---|
2592 | | -static void dcn10_set_cursor_position(struct pipe_ctx *pipe_ctx) |
---|
| 3346 | +void dcn10_update_dchub(struct dce_hwseq *hws, struct dchub_init_data *dh_data) |
---|
| 3347 | +{ |
---|
| 3348 | + struct hubbub *hubbub = hws->ctx->dc->res_pool->hubbub; |
---|
| 3349 | + |
---|
| 3350 | + /* In DCN, this programming sequence is owned by the hubbub */ |
---|
| 3351 | + hubbub->funcs->update_dchub(hubbub, dh_data); |
---|
| 3352 | +} |
---|
| 3353 | + |
---|
| 3354 | +static bool dcn10_can_pipe_disable_cursor(struct pipe_ctx *pipe_ctx) |
---|
| 3355 | +{ |
---|
| 3356 | + struct pipe_ctx *test_pipe; |
---|
| 3357 | + const struct rect *r1 = &pipe_ctx->plane_res.scl_data.recout, *r2; |
---|
| 3358 | + int r1_r = r1->x + r1->width, r1_b = r1->y + r1->height, r2_r, r2_b; |
---|
| 3359 | + |
---|
| 3360 | + /** |
---|
| 3361 | + * Disable the cursor if there's another pipe above this with a |
---|
| 3362 | + * plane that contains this pipe's viewport to prevent double cursor |
---|
| 3363 | + * and incorrect scaling artifacts. |
---|
| 3364 | + */ |
---|
| 3365 | + for (test_pipe = pipe_ctx->top_pipe; test_pipe; |
---|
| 3366 | + test_pipe = test_pipe->top_pipe) { |
---|
| 3367 | + if (!test_pipe->plane_state->visible) |
---|
| 3368 | + continue; |
---|
| 3369 | + |
---|
| 3370 | + r2 = &test_pipe->plane_res.scl_data.recout; |
---|
| 3371 | + r2_r = r2->x + r2->width; |
---|
| 3372 | + r2_b = r2->y + r2->height; |
---|
| 3373 | + |
---|
| 3374 | + if (r1->x >= r2->x && r1->y >= r2->y && r1_r <= r2_r && r1_b <= r2_b) |
---|
| 3375 | + return true; |
---|
| 3376 | + } |
---|
| 3377 | + |
---|
| 3378 | + return false; |
---|
| 3379 | +} |
---|
| 3380 | + |
---|
| 3381 | +void dcn10_set_cursor_position(struct pipe_ctx *pipe_ctx) |
---|
2593 | 3382 | { |
---|
2594 | 3383 | struct dc_cursor_position pos_cpy = pipe_ctx->stream->cursor_position; |
---|
2595 | 3384 | struct hubp *hubp = pipe_ctx->plane_res.hubp; |
---|
2596 | 3385 | struct dpp *dpp = pipe_ctx->plane_res.dpp; |
---|
2597 | 3386 | struct dc_cursor_mi_param param = { |
---|
2598 | | - .pixel_clk_khz = pipe_ctx->stream->timing.pix_clk_khz, |
---|
2599 | | - .ref_clk_khz = pipe_ctx->stream->ctx->dc->res_pool->ref_clock_inKhz, |
---|
| 3387 | + .pixel_clk_khz = pipe_ctx->stream->timing.pix_clk_100hz / 10, |
---|
| 3388 | + .ref_clk_khz = pipe_ctx->stream->ctx->dc->res_pool->ref_clocks.dchub_ref_clock_inKhz, |
---|
2600 | 3389 | .viewport = pipe_ctx->plane_res.scl_data.viewport, |
---|
2601 | 3390 | .h_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.horz, |
---|
2602 | 3391 | .v_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.vert, |
---|
2603 | 3392 | .rotation = pipe_ctx->plane_state->rotation, |
---|
2604 | 3393 | .mirror = pipe_ctx->plane_state->horizontal_mirror |
---|
2605 | 3394 | }; |
---|
| 3395 | + bool pipe_split_on = (pipe_ctx->top_pipe != NULL) || |
---|
| 3396 | + (pipe_ctx->bottom_pipe != NULL); |
---|
| 3397 | + |
---|
| 3398 | + int x_plane = pipe_ctx->plane_state->dst_rect.x; |
---|
| 3399 | + int y_plane = pipe_ctx->plane_state->dst_rect.y; |
---|
| 3400 | + int x_pos = pos_cpy.x; |
---|
| 3401 | + int y_pos = pos_cpy.y; |
---|
| 3402 | + |
---|
| 3403 | + /** |
---|
| 3404 | + * DC cursor is stream space, HW cursor is plane space and drawn |
---|
| 3405 | + * as part of the framebuffer. |
---|
| 3406 | + * |
---|
| 3407 | + * Cursor position can't be negative, but hotspot can be used to |
---|
| 3408 | + * shift cursor out of the plane bounds. Hotspot must be smaller |
---|
| 3409 | + * than the cursor size. |
---|
| 3410 | + */ |
---|
| 3411 | + |
---|
| 3412 | + /** |
---|
| 3413 | + * Translate cursor from stream space to plane space. |
---|
| 3414 | + * |
---|
| 3415 | + * If the cursor is scaled then we need to scale the position |
---|
| 3416 | + * to be in the approximately correct place. We can't do anything |
---|
| 3417 | + * about the actual size being incorrect, that's a limitation of |
---|
| 3418 | + * the hardware. |
---|
| 3419 | + */ |
---|
| 3420 | + x_pos = (x_pos - x_plane) * pipe_ctx->plane_state->src_rect.width / |
---|
| 3421 | + pipe_ctx->plane_state->dst_rect.width; |
---|
| 3422 | + y_pos = (y_pos - y_plane) * pipe_ctx->plane_state->src_rect.height / |
---|
| 3423 | + pipe_ctx->plane_state->dst_rect.height; |
---|
| 3424 | + |
---|
| 3425 | + /** |
---|
| 3426 | + * If the cursor's source viewport is clipped then we need to |
---|
| 3427 | + * translate the cursor to appear in the correct position on |
---|
| 3428 | + * the screen. |
---|
| 3429 | + * |
---|
| 3430 | + * This translation isn't affected by scaling so it needs to be |
---|
| 3431 | + * done *after* we adjust the position for the scale factor. |
---|
| 3432 | + * |
---|
| 3433 | + * This is only done by opt-in for now since there are still |
---|
| 3434 | + * some usecases like tiled display that might enable the |
---|
| 3435 | + * cursor on both streams while expecting dc to clip it. |
---|
| 3436 | + */ |
---|
| 3437 | + if (pos_cpy.translate_by_source) { |
---|
| 3438 | + x_pos += pipe_ctx->plane_state->src_rect.x; |
---|
| 3439 | + y_pos += pipe_ctx->plane_state->src_rect.y; |
---|
| 3440 | + } |
---|
| 3441 | + |
---|
| 3442 | + /** |
---|
| 3443 | + * If the position is negative then we need to add to the hotspot |
---|
| 3444 | + * to shift the cursor outside the plane. |
---|
| 3445 | + */ |
---|
| 3446 | + |
---|
| 3447 | + if (x_pos < 0) { |
---|
| 3448 | + pos_cpy.x_hotspot -= x_pos; |
---|
| 3449 | + x_pos = 0; |
---|
| 3450 | + } |
---|
| 3451 | + |
---|
| 3452 | + if (y_pos < 0) { |
---|
| 3453 | + pos_cpy.y_hotspot -= y_pos; |
---|
| 3454 | + y_pos = 0; |
---|
| 3455 | + } |
---|
| 3456 | + |
---|
| 3457 | + pos_cpy.x = (uint32_t)x_pos; |
---|
| 3458 | + pos_cpy.y = (uint32_t)y_pos; |
---|
2606 | 3459 | |
---|
2607 | 3460 | if (pipe_ctx->plane_state->address.type |
---|
2608 | 3461 | == PLN_ADDR_TYPE_VIDEO_PROGRESSIVE) |
---|
2609 | 3462 | pos_cpy.enable = false; |
---|
2610 | 3463 | |
---|
2611 | | - if (pipe_ctx->top_pipe && pipe_ctx->plane_state != pipe_ctx->top_pipe->plane_state) |
---|
| 3464 | + if (pos_cpy.enable && dcn10_can_pipe_disable_cursor(pipe_ctx)) |
---|
2612 | 3465 | pos_cpy.enable = false; |
---|
2613 | 3466 | |
---|
| 3467 | + // Swap axis and mirror horizontally |
---|
| 3468 | + if (param.rotation == ROTATION_ANGLE_90) { |
---|
| 3469 | + uint32_t temp_x = pos_cpy.x; |
---|
| 3470 | + |
---|
| 3471 | + pos_cpy.x = pipe_ctx->plane_res.scl_data.viewport.width - |
---|
| 3472 | + (pos_cpy.y - pipe_ctx->plane_res.scl_data.viewport.x) + pipe_ctx->plane_res.scl_data.viewport.x; |
---|
| 3473 | + pos_cpy.y = temp_x; |
---|
| 3474 | + } |
---|
| 3475 | + // Swap axis and mirror vertically |
---|
| 3476 | + else if (param.rotation == ROTATION_ANGLE_270) { |
---|
| 3477 | + uint32_t temp_y = pos_cpy.y; |
---|
| 3478 | + int viewport_height = |
---|
| 3479 | + pipe_ctx->plane_res.scl_data.viewport.height; |
---|
| 3480 | + |
---|
| 3481 | + if (pipe_split_on) { |
---|
| 3482 | + if (pos_cpy.x > viewport_height) { |
---|
| 3483 | + pos_cpy.x = pos_cpy.x - viewport_height; |
---|
| 3484 | + pos_cpy.y = viewport_height - pos_cpy.x; |
---|
| 3485 | + } else { |
---|
| 3486 | + pos_cpy.y = 2 * viewport_height - pos_cpy.x; |
---|
| 3487 | + } |
---|
| 3488 | + } else |
---|
| 3489 | + pos_cpy.y = viewport_height - pos_cpy.x; |
---|
| 3490 | + pos_cpy.x = temp_y; |
---|
| 3491 | + } |
---|
| 3492 | + // Mirror horizontally and vertically |
---|
| 3493 | + else if (param.rotation == ROTATION_ANGLE_180) { |
---|
| 3494 | + int viewport_width = |
---|
| 3495 | + pipe_ctx->plane_res.scl_data.viewport.width; |
---|
| 3496 | + int viewport_x = |
---|
| 3497 | + pipe_ctx->plane_res.scl_data.viewport.x; |
---|
| 3498 | + |
---|
| 3499 | + if (pipe_split_on) { |
---|
| 3500 | + if (pos_cpy.x >= viewport_width + viewport_x) { |
---|
| 3501 | + pos_cpy.x = 2 * viewport_width |
---|
| 3502 | + - pos_cpy.x + 2 * viewport_x; |
---|
| 3503 | + } else { |
---|
| 3504 | + uint32_t temp_x = pos_cpy.x; |
---|
| 3505 | + |
---|
| 3506 | + pos_cpy.x = 2 * viewport_x - pos_cpy.x; |
---|
| 3507 | + if (temp_x >= viewport_x + |
---|
| 3508 | + (int)hubp->curs_attr.width || pos_cpy.x |
---|
| 3509 | + <= (int)hubp->curs_attr.width + |
---|
| 3510 | + pipe_ctx->plane_state->src_rect.x) { |
---|
| 3511 | + pos_cpy.x = temp_x + viewport_width; |
---|
| 3512 | + } |
---|
| 3513 | + } |
---|
| 3514 | + } else { |
---|
| 3515 | + pos_cpy.x = viewport_width - pos_cpy.x + 2 * viewport_x; |
---|
| 3516 | + } |
---|
| 3517 | + pos_cpy.y = pipe_ctx->plane_res.scl_data.viewport.height - pos_cpy.y; |
---|
| 3518 | + } |
---|
| 3519 | + |
---|
2614 | 3520 | hubp->funcs->set_cursor_position(hubp, &pos_cpy, ¶m); |
---|
2615 | | - dpp->funcs->set_cursor_position(dpp, &pos_cpy, ¶m, hubp->curs_attr.width); |
---|
| 3521 | + dpp->funcs->set_cursor_position(dpp, &pos_cpy, ¶m, hubp->curs_attr.width, hubp->curs_attr.height); |
---|
2616 | 3522 | } |
---|
2617 | 3523 | |
---|
2618 | | -static void dcn10_set_cursor_attribute(struct pipe_ctx *pipe_ctx) |
---|
| 3524 | +void dcn10_set_cursor_attribute(struct pipe_ctx *pipe_ctx) |
---|
2619 | 3525 | { |
---|
2620 | 3526 | struct dc_cursor_attributes *attributes = &pipe_ctx->stream->cursor_attributes; |
---|
2621 | 3527 | |
---|
2622 | 3528 | pipe_ctx->plane_res.hubp->funcs->set_cursor_attributes( |
---|
2623 | 3529 | pipe_ctx->plane_res.hubp, attributes); |
---|
2624 | 3530 | pipe_ctx->plane_res.dpp->funcs->set_cursor_attributes( |
---|
2625 | | - pipe_ctx->plane_res.dpp, attributes->color_format); |
---|
| 3531 | + pipe_ctx->plane_res.dpp, attributes); |
---|
2626 | 3532 | } |
---|
2627 | 3533 | |
---|
2628 | | -static void dcn10_set_cursor_sdr_white_level(struct pipe_ctx *pipe_ctx) |
---|
| 3534 | +void dcn10_set_cursor_sdr_white_level(struct pipe_ctx *pipe_ctx) |
---|
2629 | 3535 | { |
---|
2630 | 3536 | uint32_t sdr_white_level = pipe_ctx->stream->cursor_attributes.sdr_white_level; |
---|
2631 | 3537 | struct fixed31_32 multiplier; |
---|
.. | .. |
---|
2652 | 3558 | pipe_ctx->plane_res.dpp, &opt_attr); |
---|
2653 | 3559 | } |
---|
2654 | 3560 | |
---|
2655 | | -static const struct hw_sequencer_funcs dcn10_funcs = { |
---|
2656 | | - .program_gamut_remap = program_gamut_remap, |
---|
2657 | | - .program_csc_matrix = program_csc_matrix, |
---|
2658 | | - .init_hw = dcn10_init_hw, |
---|
2659 | | - .apply_ctx_to_hw = dce110_apply_ctx_to_hw, |
---|
2660 | | - .apply_ctx_for_surface = dcn10_apply_ctx_for_surface, |
---|
2661 | | - .update_plane_addr = dcn10_update_plane_addr, |
---|
2662 | | - .plane_atomic_disconnect = hwss1_plane_atomic_disconnect, |
---|
2663 | | - .update_dchub = dcn10_update_dchub, |
---|
2664 | | - .update_mpcc = dcn10_update_mpcc, |
---|
2665 | | - .update_pending_status = dcn10_update_pending_status, |
---|
2666 | | - .set_input_transfer_func = dcn10_set_input_transfer_func, |
---|
2667 | | - .set_output_transfer_func = dcn10_set_output_transfer_func, |
---|
2668 | | - .program_output_csc = dcn10_program_output_csc, |
---|
2669 | | - .power_down = dce110_power_down, |
---|
2670 | | - .enable_accelerated_mode = dce110_enable_accelerated_mode, |
---|
2671 | | - .enable_timing_synchronization = dcn10_enable_timing_synchronization, |
---|
2672 | | - .enable_per_frame_crtc_position_reset = dcn10_enable_per_frame_crtc_position_reset, |
---|
2673 | | - .update_info_frame = dce110_update_info_frame, |
---|
2674 | | - .enable_stream = dce110_enable_stream, |
---|
2675 | | - .disable_stream = dce110_disable_stream, |
---|
2676 | | - .unblank_stream = dce110_unblank_stream, |
---|
2677 | | - .blank_stream = dce110_blank_stream, |
---|
2678 | | - .enable_audio_stream = dce110_enable_audio_stream, |
---|
2679 | | - .disable_audio_stream = dce110_disable_audio_stream, |
---|
2680 | | - .enable_display_power_gating = dcn10_dummy_display_power_gating, |
---|
2681 | | - .disable_plane = dcn10_disable_plane, |
---|
2682 | | - .blank_pixel_data = dcn10_blank_pixel_data, |
---|
2683 | | - .pipe_control_lock = dcn10_pipe_control_lock, |
---|
2684 | | - .set_bandwidth = dcn10_set_bandwidth, |
---|
2685 | | - .reset_hw_ctx_wrap = reset_hw_ctx_wrap, |
---|
2686 | | - .enable_stream_timing = dcn10_enable_stream_timing, |
---|
2687 | | - .set_drr = set_drr, |
---|
2688 | | - .get_position = get_position, |
---|
2689 | | - .set_static_screen_control = set_static_screen_control, |
---|
2690 | | - .setup_stereo = dcn10_setup_stereo, |
---|
2691 | | - .set_avmute = dce110_set_avmute, |
---|
2692 | | - .log_hw_state = dcn10_log_hw_state, |
---|
2693 | | - .wait_for_mpcc_disconnect = dcn10_wait_for_mpcc_disconnect, |
---|
2694 | | - .ready_shared_resources = ready_shared_resources, |
---|
2695 | | - .optimize_shared_resources = optimize_shared_resources, |
---|
2696 | | - .pplib_apply_display_requirements = |
---|
2697 | | - dcn10_pplib_apply_display_requirements, |
---|
2698 | | - .edp_backlight_control = hwss_edp_backlight_control, |
---|
2699 | | - .edp_power_control = hwss_edp_power_control, |
---|
2700 | | - .edp_wait_for_hpd_ready = hwss_edp_wait_for_hpd_ready, |
---|
2701 | | - .set_cursor_position = dcn10_set_cursor_position, |
---|
2702 | | - .set_cursor_attribute = dcn10_set_cursor_attribute, |
---|
2703 | | - .set_cursor_sdr_white_level = dcn10_set_cursor_sdr_white_level |
---|
2704 | | -}; |
---|
2705 | | - |
---|
2706 | | - |
---|
2707 | | -void dcn10_hw_sequencer_construct(struct dc *dc) |
---|
| 3561 | +/* |
---|
| 3562 | + * apply_front_porch_workaround TODO FPGA still need? |
---|
| 3563 | + * |
---|
| 3564 | + * This is a workaround for a bug that has existed since R5xx and has not been |
---|
| 3565 | + * fixed keep Front porch at minimum 2 for Interlaced mode or 1 for progressive. |
---|
| 3566 | + */ |
---|
| 3567 | +static void apply_front_porch_workaround( |
---|
| 3568 | + struct dc_crtc_timing *timing) |
---|
2708 | 3569 | { |
---|
2709 | | - dc->hwss = dcn10_funcs; |
---|
| 3570 | + if (timing->flags.INTERLACE == 1) { |
---|
| 3571 | + if (timing->v_front_porch < 2) |
---|
| 3572 | + timing->v_front_porch = 2; |
---|
| 3573 | + } else { |
---|
| 3574 | + if (timing->v_front_porch < 1) |
---|
| 3575 | + timing->v_front_porch = 1; |
---|
| 3576 | + } |
---|
2710 | 3577 | } |
---|
2711 | 3578 | |
---|
| 3579 | +int dcn10_get_vupdate_offset_from_vsync(struct pipe_ctx *pipe_ctx) |
---|
| 3580 | +{ |
---|
| 3581 | + const struct dc_crtc_timing *dc_crtc_timing = &pipe_ctx->stream->timing; |
---|
| 3582 | + struct dc_crtc_timing patched_crtc_timing; |
---|
| 3583 | + int vesa_sync_start; |
---|
| 3584 | + int asic_blank_end; |
---|
| 3585 | + int interlace_factor; |
---|
| 3586 | + int vertical_line_start; |
---|
| 3587 | + |
---|
| 3588 | + patched_crtc_timing = *dc_crtc_timing; |
---|
| 3589 | + apply_front_porch_workaround(&patched_crtc_timing); |
---|
| 3590 | + |
---|
| 3591 | + interlace_factor = patched_crtc_timing.flags.INTERLACE ? 2 : 1; |
---|
| 3592 | + |
---|
| 3593 | + vesa_sync_start = patched_crtc_timing.v_addressable + |
---|
| 3594 | + patched_crtc_timing.v_border_bottom + |
---|
| 3595 | + patched_crtc_timing.v_front_porch; |
---|
| 3596 | + |
---|
| 3597 | + asic_blank_end = (patched_crtc_timing.v_total - |
---|
| 3598 | + vesa_sync_start - |
---|
| 3599 | + patched_crtc_timing.v_border_top) |
---|
| 3600 | + * interlace_factor; |
---|
| 3601 | + |
---|
| 3602 | + vertical_line_start = asic_blank_end - |
---|
| 3603 | + pipe_ctx->pipe_dlg_param.vstartup_start + 1; |
---|
| 3604 | + |
---|
| 3605 | + return vertical_line_start; |
---|
| 3606 | +} |
---|
| 3607 | + |
---|
| 3608 | +void dcn10_calc_vupdate_position( |
---|
| 3609 | + struct dc *dc, |
---|
| 3610 | + struct pipe_ctx *pipe_ctx, |
---|
| 3611 | + uint32_t *start_line, |
---|
| 3612 | + uint32_t *end_line) |
---|
| 3613 | +{ |
---|
| 3614 | + const struct dc_crtc_timing *dc_crtc_timing = &pipe_ctx->stream->timing; |
---|
| 3615 | + int vline_int_offset_from_vupdate = |
---|
| 3616 | + pipe_ctx->stream->periodic_interrupt.lines_offset; |
---|
| 3617 | + int vupdate_offset_from_vsync = dc->hwss.get_vupdate_offset_from_vsync(pipe_ctx); |
---|
| 3618 | + int start_position; |
---|
| 3619 | + |
---|
| 3620 | + if (vline_int_offset_from_vupdate > 0) |
---|
| 3621 | + vline_int_offset_from_vupdate--; |
---|
| 3622 | + else if (vline_int_offset_from_vupdate < 0) |
---|
| 3623 | + vline_int_offset_from_vupdate++; |
---|
| 3624 | + |
---|
| 3625 | + start_position = vline_int_offset_from_vupdate + vupdate_offset_from_vsync; |
---|
| 3626 | + |
---|
| 3627 | + if (start_position >= 0) |
---|
| 3628 | + *start_line = start_position; |
---|
| 3629 | + else |
---|
| 3630 | + *start_line = dc_crtc_timing->v_total + start_position - 1; |
---|
| 3631 | + |
---|
| 3632 | + *end_line = *start_line + 2; |
---|
| 3633 | + |
---|
| 3634 | + if (*end_line >= dc_crtc_timing->v_total) |
---|
| 3635 | + *end_line = 2; |
---|
| 3636 | +} |
---|
| 3637 | + |
---|
| 3638 | +static void dcn10_cal_vline_position( |
---|
| 3639 | + struct dc *dc, |
---|
| 3640 | + struct pipe_ctx *pipe_ctx, |
---|
| 3641 | + uint32_t *start_line, |
---|
| 3642 | + uint32_t *end_line) |
---|
| 3643 | +{ |
---|
| 3644 | + switch (pipe_ctx->stream->periodic_interrupt.ref_point) { |
---|
| 3645 | + case START_V_UPDATE: |
---|
| 3646 | + dcn10_calc_vupdate_position( |
---|
| 3647 | + dc, |
---|
| 3648 | + pipe_ctx, |
---|
| 3649 | + start_line, |
---|
| 3650 | + end_line); |
---|
| 3651 | + break; |
---|
| 3652 | + case START_V_SYNC: |
---|
| 3653 | + // vsync is line 0 so start_line is just the requested line offset |
---|
| 3654 | + *start_line = pipe_ctx->stream->periodic_interrupt.lines_offset; |
---|
| 3655 | + *end_line = *start_line + 2; |
---|
| 3656 | + break; |
---|
| 3657 | + default: |
---|
| 3658 | + ASSERT(0); |
---|
| 3659 | + break; |
---|
| 3660 | + } |
---|
| 3661 | +} |
---|
| 3662 | + |
---|
| 3663 | +void dcn10_setup_periodic_interrupt( |
---|
| 3664 | + struct dc *dc, |
---|
| 3665 | + struct pipe_ctx *pipe_ctx) |
---|
| 3666 | +{ |
---|
| 3667 | + struct timing_generator *tg = pipe_ctx->stream_res.tg; |
---|
| 3668 | + uint32_t start_line = 0; |
---|
| 3669 | + uint32_t end_line = 0; |
---|
| 3670 | + |
---|
| 3671 | + dcn10_cal_vline_position(dc, pipe_ctx, &start_line, &end_line); |
---|
| 3672 | + |
---|
| 3673 | + tg->funcs->setup_vertical_interrupt0(tg, start_line, end_line); |
---|
| 3674 | +} |
---|
| 3675 | + |
---|
| 3676 | +void dcn10_setup_vupdate_interrupt(struct dc *dc, struct pipe_ctx *pipe_ctx) |
---|
| 3677 | +{ |
---|
| 3678 | + struct timing_generator *tg = pipe_ctx->stream_res.tg; |
---|
| 3679 | + int start_line = dc->hwss.get_vupdate_offset_from_vsync(pipe_ctx); |
---|
| 3680 | + |
---|
| 3681 | + if (start_line < 0) { |
---|
| 3682 | + ASSERT(0); |
---|
| 3683 | + start_line = 0; |
---|
| 3684 | + } |
---|
| 3685 | + |
---|
| 3686 | + if (tg->funcs->setup_vertical_interrupt2) |
---|
| 3687 | + tg->funcs->setup_vertical_interrupt2(tg, start_line); |
---|
| 3688 | +} |
---|
| 3689 | + |
---|
| 3690 | +void dcn10_unblank_stream(struct pipe_ctx *pipe_ctx, |
---|
| 3691 | + struct dc_link_settings *link_settings) |
---|
| 3692 | +{ |
---|
| 3693 | + struct encoder_unblank_param params = { { 0 } }; |
---|
| 3694 | + struct dc_stream_state *stream = pipe_ctx->stream; |
---|
| 3695 | + struct dc_link *link = stream->link; |
---|
| 3696 | + struct dce_hwseq *hws = link->dc->hwseq; |
---|
| 3697 | + |
---|
| 3698 | + /* only 3 items below are used by unblank */ |
---|
| 3699 | + params.timing = pipe_ctx->stream->timing; |
---|
| 3700 | + |
---|
| 3701 | + params.link_settings.link_rate = link_settings->link_rate; |
---|
| 3702 | + |
---|
| 3703 | + if (dc_is_dp_signal(pipe_ctx->stream->signal)) { |
---|
| 3704 | + if (params.timing.pixel_encoding == PIXEL_ENCODING_YCBCR420) |
---|
| 3705 | + params.timing.pix_clk_100hz /= 2; |
---|
| 3706 | + pipe_ctx->stream_res.stream_enc->funcs->dp_unblank(pipe_ctx->stream_res.stream_enc, ¶ms); |
---|
| 3707 | + } |
---|
| 3708 | + |
---|
| 3709 | + if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP) { |
---|
| 3710 | + hws->funcs.edp_backlight_control(link, true); |
---|
| 3711 | + } |
---|
| 3712 | +} |
---|
| 3713 | + |
---|
| 3714 | +void dcn10_send_immediate_sdp_message(struct pipe_ctx *pipe_ctx, |
---|
| 3715 | + const uint8_t *custom_sdp_message, |
---|
| 3716 | + unsigned int sdp_message_size) |
---|
| 3717 | +{ |
---|
| 3718 | + if (dc_is_dp_signal(pipe_ctx->stream->signal)) { |
---|
| 3719 | + pipe_ctx->stream_res.stream_enc->funcs->send_immediate_sdp_message( |
---|
| 3720 | + pipe_ctx->stream_res.stream_enc, |
---|
| 3721 | + custom_sdp_message, |
---|
| 3722 | + sdp_message_size); |
---|
| 3723 | + } |
---|
| 3724 | +} |
---|
| 3725 | +enum dc_status dcn10_set_clock(struct dc *dc, |
---|
| 3726 | + enum dc_clock_type clock_type, |
---|
| 3727 | + uint32_t clk_khz, |
---|
| 3728 | + uint32_t stepping) |
---|
| 3729 | +{ |
---|
| 3730 | + struct dc_state *context = dc->current_state; |
---|
| 3731 | + struct dc_clock_config clock_cfg = {0}; |
---|
| 3732 | + struct dc_clocks *current_clocks = &context->bw_ctx.bw.dcn.clk; |
---|
| 3733 | + |
---|
| 3734 | + if (!dc->clk_mgr || !dc->clk_mgr->funcs->get_clock) |
---|
| 3735 | + return DC_FAIL_UNSUPPORTED_1; |
---|
| 3736 | + |
---|
| 3737 | + dc->clk_mgr->funcs->get_clock(dc->clk_mgr, |
---|
| 3738 | + context, clock_type, &clock_cfg); |
---|
| 3739 | + |
---|
| 3740 | + if (clk_khz > clock_cfg.max_clock_khz) |
---|
| 3741 | + return DC_FAIL_CLK_EXCEED_MAX; |
---|
| 3742 | + |
---|
| 3743 | + if (clk_khz < clock_cfg.min_clock_khz) |
---|
| 3744 | + return DC_FAIL_CLK_BELOW_MIN; |
---|
| 3745 | + |
---|
| 3746 | + if (clk_khz < clock_cfg.bw_requirequired_clock_khz) |
---|
| 3747 | + return DC_FAIL_CLK_BELOW_CFG_REQUIRED; |
---|
| 3748 | + |
---|
| 3749 | + /*update internal request clock for update clock use*/ |
---|
| 3750 | + if (clock_type == DC_CLOCK_TYPE_DISPCLK) |
---|
| 3751 | + current_clocks->dispclk_khz = clk_khz; |
---|
| 3752 | + else if (clock_type == DC_CLOCK_TYPE_DPPCLK) |
---|
| 3753 | + current_clocks->dppclk_khz = clk_khz; |
---|
| 3754 | + else |
---|
| 3755 | + return DC_ERROR_UNEXPECTED; |
---|
| 3756 | + |
---|
| 3757 | + if (dc->clk_mgr->funcs->update_clocks) |
---|
| 3758 | + dc->clk_mgr->funcs->update_clocks(dc->clk_mgr, |
---|
| 3759 | + context, true); |
---|
| 3760 | + return DC_OK; |
---|
| 3761 | + |
---|
| 3762 | +} |
---|
| 3763 | + |
---|
| 3764 | +void dcn10_get_clock(struct dc *dc, |
---|
| 3765 | + enum dc_clock_type clock_type, |
---|
| 3766 | + struct dc_clock_config *clock_cfg) |
---|
| 3767 | +{ |
---|
| 3768 | + struct dc_state *context = dc->current_state; |
---|
| 3769 | + |
---|
| 3770 | + if (dc->clk_mgr && dc->clk_mgr->funcs->get_clock) |
---|
| 3771 | + dc->clk_mgr->funcs->get_clock(dc->clk_mgr, context, clock_type, clock_cfg); |
---|
| 3772 | + |
---|
| 3773 | +} |
---|