hc
2024-01-03 2f7c68cb55ecb7331f2381deb497c27155f32faf
kernel/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
....@@ -25,26 +25,33 @@
2525
2626 #include <linux/delay.h>
2727 #include "dm_services.h"
28
+#include "basics/dc_common.h"
2829 #include "core_types.h"
2930 #include "resource.h"
3031 #include "custom_float.h"
3132 #include "dcn10_hw_sequencer.h"
32
-#include "dce110/dce110_hw_sequencer.h"
33
+#include "dcn10_hw_sequencer_debug.h"
3334 #include "dce/dce_hwseq.h"
3435 #include "abm.h"
3536 #include "dmcu.h"
3637 #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"
3940 #include "timing_generator.h"
4041 #include "opp.h"
4142 #include "ipp.h"
4243 #include "mpc.h"
4344 #include "reg_helper.h"
44
-#include "custom_float.h"
4545 #include "dcn10_hubp.h"
4646 #include "dcn10_hubbub.h"
4747 #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"
4855
4956 #define DC_LOGGER_INIT(logger)
5057
....@@ -59,11 +66,15 @@
5966
6067 /*print is 17 wide, first two characters are spaces*/
6168 #define DTN_INFO_MICRO_SEC(ref_cycle) \
62
- print_microsec(dc_ctx, ref_cycle)
69
+ print_microsec(dc_ctx, log_ctx, ref_cycle)
6370
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)
6576 {
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;
6778 static const unsigned int frac = 1000;
6879 uint32_t us_x10 = (ref_cycle * frac) / ref_clk_mhz;
6980
....@@ -72,8 +83,36 @@
7283 us_x10 % frac);
7384 }
7485
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;
7593
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)
77116 {
78117 struct dc_context *dc_ctx = dc->ctx;
79118 struct dce_hwseq *hws = dc->hwseq;
....@@ -86,13 +125,14 @@
86125 REG_READ(DPP_TOP0_DPP_CRC_VAL_B_A), REG_READ(DPP_TOP0_DPP_CRC_VAL_R_G));
87126 }
88127
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)
90129 {
91130 struct dc_context *dc_ctx = dc->ctx;
92131 struct dcn_hubbub_wm wm;
93132 int i;
94133
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);
96136
97137 DTN_INFO("HUBBUB WM: data_urgent pte_meta_urgent"
98138 " sr_enter sr_exit dram_clk_change\n");
....@@ -113,15 +153,14 @@
113153 DTN_INFO("\n");
114154 }
115155
116
-static void dcn10_log_hubp_states(struct dc *dc)
156
+static void dcn10_log_hubp_states(struct dc *dc, void *log_ctx)
117157 {
118158 struct dc_context *dc_ctx = dc->ctx;
119159 struct resource_pool *pool = dc->res_pool;
120160 int i;
121161
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");
125164 for (i = 0; i < pool->pipe_count; i++) {
126165 struct hubp *hubp = pool->hubps[i];
127166 struct dcn_hubp_state *s = &(TO_DCN10_HUBP(hubp)->state);
....@@ -129,8 +168,7 @@
129168 hubp->funcs->hubp_read_state(hubp);
130169
131170 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",
134172 hubp->inst,
135173 s->pixel_format,
136174 s->inuse_addr_hi,
....@@ -141,6 +179,7 @@
141179 s->sw_mode,
142180 s->dcc_en,
143181 s->blank_en,
182
+ s->clock_en,
144183 s->ttu_disable,
145184 s->underflow_status);
146185 DTN_INFO_MICRO_SEC(s->min_ttu_vblank);
....@@ -228,7 +267,8 @@
228267 DTN_INFO("\n");
229268 }
230269
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)
232272 {
233273 struct dc_context *dc_ctx = dc->ctx;
234274 struct resource_pool *pool = dc->res_pool;
....@@ -236,18 +276,21 @@
236276
237277 DTN_INFO_BEGIN();
238278
239
- dcn10_log_hubbub_state(dc);
279
+ dcn10_log_hubbub_state(dc, log_ctx);
240280
241
- dcn10_log_hubp_states(dc);
281
+ dcn10_log_hubp_states(dc, log_ctx);
242282
243283 DTN_INFO("DPP: IGAM format IGAM mode DGAM mode RGAM mode"
244284 " GAMUT mode C11 C12 C13 C14 C21 C22 C23 C24 "
245285 "C31 C32 C33 C34\n");
246286 for (i = 0; i < pool->pipe_count; i++) {
247287 struct dpp *dpp = pool->dpps[i];
248
- struct dcn_dpp_state s;
288
+ struct dcn_dpp_state s = {0};
249289
250290 dpp->funcs->dpp_read_state(dpp, &s);
291
+
292
+ if (!s.is_enabled)
293
+ continue;
251294
252295 DTN_INFO("[%2d]: %11xh %-11s %-11s %-11s"
253296 "%8x %08xh %08xh %08xh %08xh %08xh %08xh",
....@@ -294,21 +337,31 @@
294337 }
295338 DTN_INFO("\n");
296339
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");
299341
300342 for (i = 0; i < pool->timing_generator_count; i++) {
301343 struct timing_generator *tg = pool->timing_generators[i];
302344 struct dcn_otg_state s = {0};
303
-
345
+ /* Read shared OTG state registers for all DCNx */
304346 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);
305359
306360 //only print if OTG master is enabled
307361 if ((s.otg_enabled & 1) == 0)
308362 continue;
309363
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",
312365 tg->inst,
313366 s.v_blank_start,
314367 s.v_blank_end,
....@@ -326,7 +379,8 @@
326379 s.h_sync_a_pol,
327380 s.h_total,
328381 s.v_total,
329
- s.underflow_occurred_status);
382
+ s.underflow_occurred_status,
383
+ s.blank_enabled);
330384
331385 // Clear underflow for debug purposes
332386 // We want to keep underflow sticky bit on for the longevity tests outside of test environment.
....@@ -336,29 +390,103 @@
336390 }
337391 DTN_INFO("\n");
338392
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
+
339450 DTN_INFO("\nCALCULATED Clocks: dcfclk_khz:%d dcfclk_deep_sleep_khz:%d dispclk_khz:%d\n"
340451 "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);
348459
349
- log_mpc_crc(dc);
460
+ log_mpc_crc(dc, log_ctx);
350461
351462 DTN_INFO_END();
352463 }
353464
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(
355483 struct dce_hwseq *hws,
356484 bool enable)
357485 {
358
- bool force_on = 1; /* disable power gating */
486
+ bool force_on = true; /* disable power gating */
359487
360488 if (enable)
361
- force_on = 0;
489
+ force_on = false;
362490
363491 /* DCHUBP0/1/2/3 */
364492 REG_UPDATE(DOMAIN0_PG_CONFIG, DOMAIN0_POWER_FORCEON, force_on);
....@@ -373,7 +501,7 @@
373501 REG_UPDATE(DOMAIN7_PG_CONFIG, DOMAIN7_POWER_FORCEON, force_on);
374502 }
375503
376
-static void disable_vga(
504
+void dcn10_disable_vga(
377505 struct dce_hwseq *hws)
378506 {
379507 unsigned int in_vga1_mode = 0;
....@@ -406,7 +534,7 @@
406534 REG_UPDATE(VGA_TEST_CONTROL, VGA_TEST_RENDER_START, 1);
407535 }
408536
409
-static void dpp_pg_control(
537
+void dcn10_dpp_pg_control(
410538 struct dce_hwseq *hws,
411539 unsigned int dpp_inst,
412540 bool power_on)
....@@ -458,7 +586,7 @@
458586 }
459587 }
460588
461
-static void hubp_pg_control(
589
+void dcn10_hubp_pg_control(
462590 struct dce_hwseq *hws,
463591 unsigned int hubp_inst,
464592 bool power_on)
....@@ -518,8 +646,13 @@
518646 if (REG(DC_IP_REQUEST_CNTL)) {
519647 REG_SET(DC_IP_REQUEST_CNTL, 0,
520648 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
+
523656 REG_SET(DC_IP_REQUEST_CNTL, 0,
524657 IP_REQUEST_EN, 0);
525658 DC_LOG_DEBUG(
....@@ -540,7 +673,7 @@
540673 REG_SET(DC_IP_REQUEST_CNTL, 0,
541674 IP_REQUEST_EN, 1);
542675
543
- hubp_pg_control(hws, 0, false);
676
+ hws->funcs.hubp_pg_control(hws, 0, false);
544677 REG_SET(DC_IP_REQUEST_CNTL, 0,
545678 IP_REQUEST_EN, 0);
546679
....@@ -569,7 +702,7 @@
569702 REG_SET(DC_IP_REQUEST_CNTL, 0,
570703 IP_REQUEST_EN, 1);
571704
572
- hubp_pg_control(hws, 0, true);
705
+ hws->funcs.hubp_pg_control(hws, 0, true);
573706 REG_SET(DC_IP_REQUEST_CNTL, 0,
574707 IP_REQUEST_EN, 0);
575708
....@@ -577,10 +710,27 @@
577710 hws->wa_state.DEGVIDCN10_253_applied = true;
578711 }
579712
580
-static void bios_golden_init(struct dc *dc)
713
+void dcn10_bios_golden_init(struct dc *dc)
581714 {
715
+ struct dce_hwseq *hws = dc->hwseq;
582716 struct dc_bios *bp = dc->ctx->dc_bios;
583717 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
+ */
584734
585735 /* initialize dcn global */
586736 bp->funcs->enable_disp_power_gating(bp,
....@@ -591,6 +741,13 @@
591741 bp->funcs->enable_disp_power_gating(bp,
592742 CONTROLLER_ID_D0 + i, ASIC_PIPE_DISABLE);
593743 }
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
+
594751 }
595752
596753 static void false_optc_underflow_wa(
....@@ -615,13 +772,14 @@
615772 dc->hwss.wait_for_mpcc_disconnect(dc, dc->res_pool, old_pipe_ctx);
616773 }
617774
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);
619777
620778 if (tg->funcs->is_optc_underflow_occurred(tg) && !underflow)
621779 tg->funcs->clear_optc_underflow(tg);
622780 }
623781
624
-static enum dc_status dcn10_enable_stream_timing(
782
+enum dc_status dcn10_enable_stream_timing(
625783 struct pipe_ctx *pipe_ctx,
626784 struct dc_state *context,
627785 struct dc *dc)
....@@ -651,16 +809,15 @@
651809 BREAK_TO_DEBUGGER();
652810 return DC_ERROR_UNEXPECTED;
653811 }
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;
660812
661813 pipe_ctx->stream_res.tg->funcs->program_timing(
662814 pipe_ctx->stream_res.tg,
663815 &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,
664821 true);
665822
666823 #if 0 /* move to after enable_crtc */
....@@ -677,6 +834,14 @@
677834 /* program otg blank color */
678835 color_space = stream->output_color_space;
679836 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;
680845
681846 if (pipe_ctx->stream_res.tg->funcs->set_blank_color)
682847 pipe_ctx->stream_res.tg->funcs->set_blank_color(
....@@ -707,12 +872,13 @@
707872 return DC_OK;
708873 }
709874
710
-static void reset_back_end_for_pipe(
875
+static void dcn10_reset_back_end_for_pipe(
711876 struct dc *dc,
712877 struct pipe_ctx *pipe_ctx,
713878 struct dc_state *context)
714879 {
715880 int i;
881
+ struct dc_link *link;
716882 DC_LOGGER_INIT(dc->ctx->logger);
717883 if (pipe_ctx->stream_res.stream_enc == NULL) {
718884 pipe_ctx->stream = NULL;
....@@ -720,13 +886,31 @@
720886 }
721887
722888 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);
729900
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
+ }
730914 }
731915
732916 /* by upper caller loop, parent pipe: pipe0, will be reset last.
....@@ -734,9 +918,16 @@
734918 * parent pipe.
735919 */
736920 if (pipe_ctx->top_pipe == NULL) {
921
+
922
+ if (pipe_ctx->stream_res.abm)
923
+ dc->hwss.set_abm_immediate_disable(pipe_ctx);
924
+
737925 pipe_ctx->stream_res.tg->funcs->disable_crtc(pipe_ctx->stream_res.tg);
738926
739927 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);
740931 }
741932
742933 for (i = 0; i < dc->res_pool->pipe_count; i++)
....@@ -765,7 +956,7 @@
765956 &dc->current_state->res_ctx.pipe_ctx[i];
766957 if (pipe_ctx != NULL) {
767958 hubp = pipe_ctx->plane_res.hubp;
768
- if (hubp != NULL) {
959
+ if (hubp != NULL && hubp->funcs->hubp_get_underflow_status) {
769960 if (hubp->funcs->hubp_get_underflow_status(hubp) != 0) {
770961 /* one pipe underflow, we will reset all the pipes*/
771962 need_recover = true;
....@@ -791,7 +982,7 @@
791982 if (pipe_ctx != NULL) {
792983 hubp = pipe_ctx->plane_res.hubp;
793984 /*DCHUBP_CNTL:HUBP_BLANK_EN=1*/
794
- if (hubp != NULL)
985
+ if (hubp != NULL && hubp->funcs->set_hubp_blank_en)
795986 hubp->funcs->set_hubp_blank_en(hubp, true);
796987 }
797988 }
....@@ -804,7 +995,7 @@
804995 if (pipe_ctx != NULL) {
805996 hubp = pipe_ctx->plane_res.hubp;
806997 /*DCHUBP_CNTL:HUBP_DISABLE=1*/
807
- if (hubp != NULL)
998
+ if (hubp != NULL && hubp->funcs->hubp_disable_control)
808999 hubp->funcs->hubp_disable_control(hubp, true);
8091000 }
8101001 }
....@@ -814,7 +1005,7 @@
8141005 if (pipe_ctx != NULL) {
8151006 hubp = pipe_ctx->plane_res.hubp;
8161007 /*DCHUBP_CNTL:HUBP_DISABLE=0*/
817
- if (hubp != NULL)
1008
+ if (hubp != NULL && hubp->funcs->hubp_disable_control)
8181009 hubp->funcs->hubp_disable_control(hubp, true);
8191010 }
8201011 }
....@@ -826,7 +1017,7 @@
8261017 if (pipe_ctx != NULL) {
8271018 hubp = pipe_ctx->plane_res.hubp;
8281019 /*DCHUBP_CNTL:HUBP_BLANK_EN=0*/
829
- if (hubp != NULL)
1020
+ if (hubp != NULL && hubp->funcs->set_hubp_blank_en)
8301021 hubp->funcs->set_hubp_blank_en(hubp, true);
8311022 }
8321023 }
....@@ -841,7 +1032,7 @@
8411032
8421033 if (!hubbub1_verify_allow_pstate_change_high(dc->res_pool->hubbub)) {
8431034 if (should_log_hw_state) {
844
- dcn10_log_hw_state(dc);
1035
+ dcn10_log_hw_state(dc, NULL);
8451036 }
8461037 BREAK_TO_DEBUGGER();
8471038 if (dcn10_hw_wa_force_recovery(dc)) {
....@@ -853,8 +1044,9 @@
8531044 }
8541045
8551046 /* 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)
8571048 {
1049
+ struct dce_hwseq *hws = dc->hwseq;
8581050 struct hubp *hubp = pipe_ctx->plane_res.hubp;
8591051 int dpp_id = pipe_ctx->plane_res.dpp->inst;
8601052 struct mpc *mpc = dc->res_pool->mpc;
....@@ -879,33 +1071,40 @@
8791071 hubp->funcs->hubp_disconnect(hubp);
8801072
8811073 if (dc->debug.sanity_checks)
882
- dcn10_verify_allow_pstate_change_high(dc);
1074
+ hws->funcs.verify_allow_pstate_change_high(dc);
8831075 }
8841076
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)
8861080 {
8871081 struct dce_hwseq *hws = dc->hwseq;
888
- struct dpp *dpp = pipe_ctx->plane_res.dpp;
8891082 DC_LOGGER_INIT(dc->ctx->logger);
8901083
8911084 if (REG(DC_IP_REQUEST_CNTL)) {
8921085 REG_SET(DC_IP_REQUEST_CNTL, 0,
8931086 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
+
8961094 dpp->funcs->dpp_reset(dpp);
8971095 REG_SET(DC_IP_REQUEST_CNTL, 0,
8981096 IP_REQUEST_EN, 0);
8991097 DC_LOG_DEBUG(
900
- "Power gated front end %d\n", pipe_ctx->pipe_idx);
1098
+ "Power gated front end %d\n", hubp->inst);
9011099 }
9021100 }
9031101
9041102 /* disable HW used by plane.
9051103 * note: cannot disable until disconnect is complete
9061104 */
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)
9081106 {
1107
+ struct dce_hwseq *hws = dc->hwseq;
9091108 struct hubp *hubp = pipe_ctx->plane_res.hubp;
9101109 struct dpp *dpp = pipe_ctx->plane_res.dpp;
9111110 int opp_id = hubp->opp_id;
....@@ -924,7 +1123,9 @@
9241123 hubp->power_gated = true;
9251124 dc->optimized_required = false; /* We're powering off, no need to optimize */
9261125
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);
9281129
9291130 pipe_ctx->stream = NULL;
9301131 memset(&pipe_ctx->stream_res, 0, sizeof(pipe_ctx->stream_res));
....@@ -934,14 +1135,15 @@
9341135 pipe_ctx->plane_state = NULL;
9351136 }
9361137
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)
9381139 {
1140
+ struct dce_hwseq *hws = dc->hwseq;
9391141 DC_LOGGER_INIT(dc->ctx->logger);
9401142
9411143 if (!pipe_ctx->plane_res.hubp || pipe_ctx->plane_res.hubp->power_gated)
9421144 return;
9431145
944
- plane_atomic_disable(dc, pipe_ctx);
1146
+ hws->funcs.plane_atomic_disable(dc, pipe_ctx);
9451147
9461148 apply_DEGVIDCN10_253_wa(dc);
9471149
....@@ -949,16 +1151,133 @@
9491151 pipe_ctx->pipe_idx);
9501152 }
9511153
952
-static void dcn10_init_hw(struct dc *dc)
1154
+void dcn10_init_pipes(struct dc *dc, struct dc_state *context)
9531155 {
9541156 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;
9551264 struct abm *abm = dc->res_pool->abm;
9561265 struct dmcu *dmcu = dc->res_pool->dmcu;
9571266 struct dce_hwseq *hws = dc->hwseq;
9581267 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);
9601278
9611279 if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
1280
+
9621281 REG_WRITE(REFCLK_CNTL, 0);
9631282 REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_ENABLE, 1);
9641283 REG_WRITE(DIO_MEM_PWR_CTRL, 0);
....@@ -972,113 +1291,145 @@
9721291 REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0);
9731292 }
9741293
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);
9771297
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);
9811411 }
9821412
9831413 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
- */
9881414 struct dc_link *link = dc->links[i];
9891415
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);
9941418 }
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);
9951425 }
9961426
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);
10791429
10801430 /* 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);
10821433
10831434 if (!dc->debug.disable_clock_gate) {
10841435 /* enable all DCN clock gating */
....@@ -1088,17 +1439,71 @@
10881439
10891440 REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0);
10901441 }
1442
+ if (hws->funcs.enable_power_gating_plane)
1443
+ hws->funcs.enable_power_gating_plane(dc->hwseq, true);
10911444
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);
10931447
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
+
10951453 }
10961454
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(
10981502 struct dc *dc,
10991503 struct dc_state *context)
11001504 {
11011505 int i;
1506
+ struct dce_hwseq *hws = dc->hwseq;
11021507
11031508 /* Reset Back End*/
11041509 for (i = dc->res_pool->pipe_count - 1; i >= 0 ; i--) {
....@@ -1116,12 +1521,13 @@
11161521 pipe_need_reprogram(pipe_ctx_old, pipe_ctx)) {
11171522 struct clock_source *old_clk = pipe_ctx_old->clock_source;
11181523
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);
11201527 if (old_clk)
11211528 old_clk->funcs->cs_power_down(old_clk);
11221529 }
11231530 }
1124
-
11251531 }
11261532
11271533 static bool patch_address_for_sbs_tb_stereo(
....@@ -1150,9 +1556,7 @@
11501556 return false;
11511557 }
11521558
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)
11561560 {
11571561 bool addr_patched = false;
11581562 PHYSICAL_ADDRESS_LOC addr;
....@@ -1177,8 +1581,8 @@
11771581 pipe_ctx->plane_state->address.grph_stereo.left_addr = addr;
11781582 }
11791583
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)
11821586 {
11831587 struct dpp *dpp_base = pipe_ctx->plane_res.dpp;
11841588 const struct dc_transfer_func *tf = NULL;
....@@ -1210,6 +1614,11 @@
12101614 dpp_base->funcs->dpp_set_degamma(dpp_base, IPP_DEGAMMA_MODE_BYPASS);
12111615 break;
12121616 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;
12131622 default:
12141623 result = false;
12151624 break;
....@@ -1227,13 +1636,36 @@
12271636 return result;
12281637 }
12291638
1639
+#define MAX_NUM_HW_POINTS 0x200
12301640
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;
12311648
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...");
12321653
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
+ }
12331659
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)
12371669 {
12381670 struct dpp *dpp = pipe_ctx->plane_res.dpp;
12391671
....@@ -1259,22 +1691,31 @@
12591691 } else
12601692 dpp->funcs->dpp_program_regamma_pwl(dpp, NULL, OPP_REGAMMA_BYPASS);
12611693
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
+
12621701 return true;
12631702 }
12641703
1265
-static void dcn10_pipe_control_lock(
1704
+void dcn10_pipe_control_lock(
12661705 struct dc *dc,
12671706 struct pipe_ctx *pipe,
12681707 bool lock)
12691708 {
1709
+ struct dce_hwseq *hws = dc->hwseq;
1710
+
12701711 /* use TG master update lock to lock everything on the TG
12711712 * therefore only top pipe need to lock
12721713 */
1273
- if (pipe->top_pipe)
1714
+ if (!pipe || pipe->top_pipe)
12741715 return;
12751716
12761717 if (dc->debug.sanity_checks)
1277
- dcn10_verify_allow_pstate_change_high(dc);
1718
+ hws->funcs.verify_allow_pstate_change_high(dc);
12781719
12791720 if (lock)
12801721 pipe->stream_res.tg->funcs->lock(pipe->stream_res.tg);
....@@ -1282,7 +1723,98 @@
12821723 pipe->stream_res.tg->funcs->unlock(pipe->stream_res.tg);
12831724
12841725 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);
12861818 }
12871819
12881820 static bool wait_for_reset_trigger_to_occur(
....@@ -1322,7 +1854,7 @@
13221854 return rc;
13231855 }
13241856
1325
-static void dcn10_enable_timing_synchronization(
1857
+void dcn10_enable_timing_synchronization(
13261858 struct dc *dc,
13271859 int group_index,
13281860 int group_size,
....@@ -1352,7 +1884,7 @@
13521884 DC_SYNC_INFO("Sync complete\n");
13531885 }
13541886
1355
-static void dcn10_enable_per_frame_crtc_position_reset(
1887
+void dcn10_enable_per_frame_crtc_position_reset(
13561888 struct dc *dc,
13571889 int group_size,
13581890 struct pipe_ctx *grouped_pipes[])
....@@ -1365,7 +1897,7 @@
13651897 if (grouped_pipes[i]->stream_res.tg->funcs->enable_crtc_reset)
13661898 grouped_pipes[i]->stream_res.tg->funcs->enable_crtc_reset(
13671899 grouped_pipes[i]->stream_res.tg,
1368
- grouped_pipes[i]->stream->triggered_crtc_reset.event_source->status.primary_otg_inst,
1900
+ 0,
13691901 &grouped_pipes[i]->stream->triggered_crtc_reset);
13701902
13711903 DC_SYNC_INFO("Waiting for trigger\n");
....@@ -1377,10 +1909,10 @@
13771909 }
13781910
13791911 /*static void print_rq_dlg_ttu(
1380
- struct dc *core_dc,
1912
+ struct dc *dc,
13811913 struct pipe_ctx *pipe_ctx)
13821914 {
1383
- DC_LOG_BANDWIDTH_CALCS(core_dc->ctx->logger,
1915
+ DC_LOG_BANDWIDTH_CALCS(dc->ctx->logger,
13841916 "\n============== DML TTU Output parameters [%d] ==============\n"
13851917 "qos_level_low_wm: %d, \n"
13861918 "qos_level_high_wm: %d, \n"
....@@ -1410,7 +1942,7 @@
14101942 pipe_ctx->ttu_regs.refcyc_per_req_delivery_pre_c
14111943 );
14121944
1413
- DC_LOG_BANDWIDTH_CALCS(core_dc->ctx->logger,
1945
+ DC_LOG_BANDWIDTH_CALCS(dc->ctx->logger,
14141946 "\n============== DML DLG Output parameters [%d] ==============\n"
14151947 "refcyc_h_blank_end: %d, \n"
14161948 "dlg_vblank_end: %d, \n"
....@@ -1445,7 +1977,7 @@
14451977 pipe_ctx->dlg_regs.refcyc_per_pte_group_nom_l
14461978 );
14471979
1448
- DC_LOG_BANDWIDTH_CALCS(core_dc->ctx->logger,
1980
+ DC_LOG_BANDWIDTH_CALCS(dc->ctx->logger,
14491981 "\ndst_y_per_meta_row_nom_l: %d, \n"
14501982 "refcyc_per_meta_chunk_nom_l: %d, \n"
14511983 "refcyc_per_line_delivery_pre_l: %d, \n"
....@@ -1475,7 +2007,7 @@
14752007 pipe_ctx->dlg_regs.refcyc_per_line_delivery_c
14762008 );
14772009
1478
- DC_LOG_BANDWIDTH_CALCS(core_dc->ctx->logger,
2010
+ DC_LOG_BANDWIDTH_CALCS(dc->ctx->logger,
14792011 "\n============== DML RQ Output parameters [%d] ==============\n"
14802012 "chunk_size: %d \n"
14812013 "min_chunk_size: %d \n"
....@@ -1569,7 +2101,7 @@
15692101 }
15702102
15712103
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)
15732105 {
15742106 struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp);
15752107 struct vm_system_aperture_param apt = { {{ 0 } } };
....@@ -1590,7 +2122,7 @@
15902122 struct dce_hwseq *hws = dc->hwseq;
15912123
15922124 if (dc->debug.sanity_checks) {
1593
- dcn10_verify_allow_pstate_change_high(dc);
2125
+ hws->funcs.verify_allow_pstate_change_high(dc);
15942126 }
15952127
15962128 undo_DEGVIDCN10_253_wa(dc);
....@@ -1647,11 +2179,11 @@
16472179 dcn10_program_pte_vm(hws, pipe_ctx->plane_res.hubp);
16482180
16492181 if (dc->debug.sanity_checks) {
1650
- dcn10_verify_allow_pstate_change_high(dc);
2182
+ hws->funcs.verify_allow_pstate_change_high(dc);
16512183 }
16522184 }
16532185
1654
-static void program_gamut_remap(struct pipe_ctx *pipe_ctx)
2186
+void dcn10_program_gamut_remap(struct pipe_ctx *pipe_ctx)
16552187 {
16562188 int i = 0;
16572189 struct dpp_grph_csc_adjustment adjust;
....@@ -1664,89 +2196,80 @@
16642196 for (i = 0; i < CSC_TEMPERATURE_MATRIX_SIZE; i++)
16652197 adjust.temperature_matrix[i] =
16662198 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];
16672205 }
16682206
16692207 pipe_ctx->plane_res.dpp->funcs->dpp_set_gamut_remap(pipe_ctx->plane_res.dpp, &adjust);
16702208 }
16712209
16722210
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,
16742242 enum dc_color_space colorspace,
1675
- uint16_t *matrix)
2243
+ uint16_t *matrix,
2244
+ int opp_id)
16762245 {
16772246 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 {
16792263 pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_adjustment(pipe_ctx->plane_res.dpp, matrix);
2264
+ }
2265
+ }
16802266 } else {
16812267 if (pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_default != NULL)
16822268 pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_default(pipe_ctx->plane_res.dpp, colorspace);
16832269 }
16842270 }
16852271
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(
17502273 const struct pipe_ctx *pipe_ctx,
17512274 struct tg_color *color)
17522275 {
....@@ -1754,25 +2277,25 @@
17542277
17552278 switch (pipe_ctx->plane_res.scl_data.format) {
17562279 case PIXEL_FORMAT_ARGB8888:
1757
- /* set boarder color to red */
2280
+ /* set border color to red */
17582281 color->color_r_cr = color_value;
17592282 break;
17602283
17612284 case PIXEL_FORMAT_ARGB2101010:
1762
- /* set boarder color to blue */
2285
+ /* set border color to blue */
17632286 color->color_b_cb = color_value;
17642287 break;
17652288 case PIXEL_FORMAT_420BPP8:
1766
- /* set boarder color to green */
2289
+ /* set border color to green */
17672290 color->color_g_y = color_value;
17682291 break;
17692292 case PIXEL_FORMAT_420BPP10:
1770
- /* set boarder color to yellow */
2293
+ /* set border color to yellow */
17712294 color->color_g_y = color_value;
17722295 color->color_r_cr = color_value;
17732296 break;
17742297 case PIXEL_FORMAT_FP16:
1775
- /* set boarder color to white */
2298
+ /* set border color to white */
17762299 color->color_r_cr = color_value;
17772300 color->color_b_cb = color_value;
17782301 color->color_g_y = color_value;
....@@ -1782,7 +2305,7 @@
17822305 }
17832306 }
17842307
1785
-static void dcn10_get_hdr_visual_confirm_color(
2308
+void dcn10_get_hdr_visual_confirm_color(
17862309 struct pipe_ctx *pipe_ctx,
17872310 struct tg_color *color)
17882311 {
....@@ -1796,22 +2319,26 @@
17962319
17972320 switch (top_pipe_ctx->plane_res.scl_data.format) {
17982321 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 */
18012324 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;
18022329 }
18032330 break;
18042331 case PIXEL_FORMAT_FP16:
18052332 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 */
18072334 color->color_b_cb = color_value;
18082335 } 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 */
18102337 color->color_g_y = color_value;
18112338 }
18122339 break;
18132340 default:
1814
- /* SDR - set boarder color to Gray */
2341
+ /* SDR - set border color to Gray */
18152342 color->color_r_cr = color_value/2;
18162343 color->color_b_cb = color_value/2;
18172344 color->color_g_y = color_value/2;
....@@ -1819,70 +2346,7 @@
18192346 }
18202347 }
18212348
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)
18862350 {
18872351 struct dc_bias_and_scale bns_params = {0};
18882352
....@@ -1891,7 +2355,8 @@
18912355 plane_state->format,
18922356 EXPANSION_MODE_ZERO,
18932357 plane_state->input_csc_color_matrix,
1894
- plane_state->color_space);
2358
+ plane_state->color_space,
2359
+ NULL);
18952360
18962361 //set scale and bias registers
18972362 build_prescale_params(&bns_params, plane_state);
....@@ -1899,25 +2364,22 @@
18992364 dpp->funcs->dpp_program_bias_and_scale(dpp, &bns_params);
19002365 }
19012366
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)
19032368 {
2369
+ struct dce_hwseq *hws = dc->hwseq;
19042370 struct hubp *hubp = pipe_ctx->plane_res.hubp;
1905
- struct mpcc_blnd_cfg blnd_cfg = {0};
2371
+ struct mpcc_blnd_cfg blnd_cfg = {{0}};
19062372 bool per_pixel_alpha = pipe_ctx->plane_state->per_pixel_alpha && pipe_ctx->bottom_pipe;
19072373 int mpcc_id;
19082374 struct mpcc *new_mpcc;
19092375 struct mpc *mpc = dc->res_pool->mpc;
19102376 struct mpc_tree *mpc_tree_params = &(pipe_ctx->stream_res.opp->mpc_tree_params);
19112377
1912
-
1913
-
1914
- /* TODO: proper fix once fpga works */
1915
-
19162378 if (dc->debug.visual_confirm == VISUAL_CONFIRM_HDR) {
1917
- dcn10_get_hdr_visual_confirm_color(
2379
+ hws->funcs.get_hdr_visual_confirm_color(
19182380 pipe_ctx, &blnd_cfg.black_color);
19192381 } else if (dc->debug.visual_confirm == VISUAL_CONFIRM_SURFACE) {
1920
- dcn10_get_surface_visual_confirm_color(
2382
+ hws->funcs.get_surface_visual_confirm_color(
19212383 pipe_ctx, &blnd_cfg.black_color);
19222384 } else {
19232385 color_space_to_black_color(
....@@ -1925,14 +2387,22 @@
19252387 &blnd_cfg.black_color);
19262388 }
19272389
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
-
19332390 blnd_cfg.overlap_only = false;
1934
- blnd_cfg.global_alpha = 0xff;
19352391 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;
19362406
19372407 /* DCN1.0 has output CM before MPC which seems to screw with
19382408 * pre-multiplied alpha.
....@@ -1988,8 +2458,6 @@
19882458 bool per_pixel_alpha =
19892459 pipe_ctx->plane_state->per_pixel_alpha && pipe_ctx->bottom_pipe;
19902460
1991
- /* TODO: proper fix once fpga works */
1992
-
19932461 pipe_ctx->plane_res.scl_data.lb_params.alpha_en = per_pixel_alpha;
19942462 pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_30BPP;
19952463 /* scaler configuration */
....@@ -1997,32 +2465,72 @@
19972465 pipe_ctx->plane_res.dpp, &pipe_ctx->plane_res.scl_data);
19982466 }
19992467
2000
-static void update_dchubp_dpp(
2468
+static void dcn10_update_dchubp_dpp(
20012469 struct dc *dc,
20022470 struct pipe_ctx *pipe_ctx,
20032471 struct dc_state *context)
20042472 {
2473
+ struct dce_hwseq *hws = dc->hwseq;
20052474 struct hubp *hubp = pipe_ctx->plane_res.hubp;
20062475 struct dpp *dpp = pipe_ctx->plane_res.dpp;
20072476 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;
20092480
20102481 /* depends on DML calculation, DPP clock value may change dynamically */
20112482 /* If request max dpp clk is lower than current dispclk, no need to
20122483 * divided by 2
20132484 */
20142485 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;
20172519
20182520 dpp->funcs->dpp_dppclk_control(
20192521 dpp,
20202522 should_divided_by_2,
20212523 true);
20222524
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;
20262534 }
20272535
20282536 /* TODO: Need input parameter to tell current DCHUB pipe tie to which OTG
....@@ -2038,20 +2546,26 @@
20382546 &pipe_ctx->ttu_regs,
20392547 &pipe_ctx->rq_regs,
20402548 &pipe_ctx->pipe_dlg_param);
2549
+ hubp->funcs->hubp_setup_interdependent(
2550
+ hubp,
2551
+ &pipe_ctx->dlg_regs,
2552
+ &pipe_ctx->ttu_regs);
20412553 }
20422554
2043
- size.grph.surface_size = pipe_ctx->plane_res.scl_data.viewport;
2555
+ size.surface_size = pipe_ctx->plane_res.scl_data.viewport;
20442556
20452557 if (plane_state->update_flags.bits.full_update ||
20462558 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);
20522560
20532561 if (plane_state->update_flags.bits.full_update ||
20542562 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 ||
20552569 plane_state->update_flags.bits.scaling_change ||
20562570 plane_state->update_flags.bits.position_change) {
20572571 update_scaler(pipe_ctx);
....@@ -2069,17 +2583,20 @@
20692583 if (pipe_ctx->stream->cursor_attributes.address.quad_part != 0) {
20702584 dc->hwss.set_cursor_position(pipe_ctx);
20712585 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);
20722589 }
20732590
20742591 if (plane_state->update_flags.bits.full_update) {
20752592 /*gamut remap*/
2076
- program_gamut_remap(pipe_ctx);
2593
+ dc->hwss.program_gamut_remap(pipe_ctx);
20772594
20782595 dc->hwss.program_output_csc(dc,
20792596 pipe_ctx,
20802597 pipe_ctx->stream->output_color_space,
20812598 pipe_ctx->stream->csc_color_matrix.matrix,
2082
- hubp->opp_id);
2599
+ pipe_ctx->stream_res.opp->inst);
20832600 }
20842601
20852602 if (plane_state->update_flags.bits.full_update ||
....@@ -2089,7 +2606,8 @@
20892606 plane_state->update_flags.bits.swizzle_change ||
20902607 plane_state->update_flags.bits.dcc_change ||
20912608 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) {
20932611 hubp->funcs->hubp_program_surface_config(
20942612 hubp,
20952613 plane_state->format,
....@@ -2097,18 +2615,19 @@
20972615 &size,
20982616 plane_state->rotation,
20992617 &plane_state->dcc,
2100
- plane_state->horizontal_mirror);
2618
+ plane_state->horizontal_mirror,
2619
+ compat_level);
21012620 }
21022621
21032622 hubp->power_gated = false;
21042623
2105
- dc->hwss.update_plane_addr(dc, pipe_ctx);
2624
+ hws->funcs.update_plane_addr(dc, pipe_ctx);
21062625
21072626 if (is_pipe_tree_visible(pipe_ctx))
21082627 hubp->funcs->set_blank(hubp, false);
21092628 }
21102629
2111
-static void dcn10_blank_pixel_data(
2630
+void dcn10_blank_pixel_data(
21122631 struct dc *dc,
21132632 struct pipe_ctx *pipe_ctx,
21142633 bool blank)
....@@ -2139,20 +2658,22 @@
21392658 if (!blank) {
21402659 if (stream_res->tg->funcs->set_blank)
21412660 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);
21432663 stream_res->abm->funcs->set_abm_level(stream_res->abm, stream->abm_level);
2664
+ }
21442665 } 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);
21482669 stream_res->tg->funcs->set_blank(stream_res->tg, blank);
2670
+ }
21492671 }
21502672 }
21512673
2152
-static void set_hdr_multiplier(struct pipe_ctx *pipe_ctx)
2674
+void dcn10_set_hdr_multiplier(struct pipe_ctx *pipe_ctx)
21532675 {
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;
21562677 uint32_t hw_mult = 0x1f000; // 1.0 default multiplier
21572678 struct custom_float_format fmt;
21582679
....@@ -2160,7 +2681,8 @@
21602681 fmt.mantissa_bits = 12;
21612682 fmt.sign = true;
21622683
2163
- if (pipe_ctx->plane_state->sdr_white_level > 80)
2684
+
2685
+ if (!dc_fixpt_eq(multiplier, dc_fixpt_from_int(0))) // check != 0
21642686 convert_to_custom_float_format(multiplier, &fmt, &hw_mult);
21652687
21662688 pipe_ctx->plane_res.dpp->funcs->dpp_set_hdr_multiplier(
....@@ -2172,17 +2694,19 @@
21722694 struct pipe_ctx *pipe_ctx,
21732695 struct dc_state *context)
21742696 {
2697
+ struct dce_hwseq *hws = dc->hwseq;
2698
+
21752699 if (pipe_ctx->plane_state->update_flags.bits.full_update)
21762700 dcn10_enable_plane(dc, pipe_ctx, context);
21772701
2178
- update_dchubp_dpp(dc, pipe_ctx, context);
2702
+ dcn10_update_dchubp_dpp(dc, pipe_ctx, context);
21792703
2180
- set_hdr_multiplier(pipe_ctx);
2704
+ hws->funcs.set_hdr_multiplier(pipe_ctx);
21812705
21822706 if (pipe_ctx->plane_state->update_flags.bits.full_update ||
21832707 pipe_ctx->plane_state->update_flags.bits.in_transfer_func_change ||
21842708 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);
21862710
21872711 /* dcn10_translate_regamma_to_hw_format takes 750us to finish
21882712 * only do gamma programming for full update.
....@@ -2191,80 +2715,43 @@
21912715 * doing heavy calculation and programming
21922716 */
21932717 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);
21952719 }
21962720
2197
-static void program_all_pipe_in_tree(
2721
+static void dcn10_program_all_pipe_in_tree(
21982722 struct dc *dc,
21992723 struct pipe_ctx *pipe_ctx,
22002724 struct dc_state *context)
22012725 {
2726
+ struct dce_hwseq *hws = dc->hwseq;
2727
+
22022728 if (pipe_ctx->top_pipe == NULL) {
22032729 bool blank = !is_pipe_tree_visible(pipe_ctx);
22042730
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
-
22112731 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);
22132737
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);
22152740
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);
22162745 }
22172746
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);
22212749
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);
22252752 }
22262753
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(
22682755 struct dc *dc,
22692756 struct dc_state *context,
22702757 const struct dc_stream_state *stream)
....@@ -2282,35 +2769,203 @@
22822769 if (pipe_ctx->stream != stream)
22832770 continue;
22842771
2285
- if (!pipe_ctx->top_pipe)
2772
+ if (!pipe_ctx->top_pipe && !pipe_ctx->prev_odm_pipe)
22862773 return pipe_ctx;
22872774 }
22882775 return NULL;
22892776 }
22902777
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(
22922927 struct dc *dc,
22932928 const struct dc_stream_state *stream,
22942929 int num_planes,
22952930 struct dc_state *context)
22962931 {
2932
+ struct dce_hwseq *hws = dc->hwseq;
22972933 int i;
22982934 struct timing_generator *tg;
2299
- bool removed_pipe[4] = { false };
2935
+ uint32_t underflow_check_delay_us;
2936
+ bool interdependent_update = false;
23002937 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);
23022939 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
+ }
23032946
23042947 if (!top_pipe_to_program)
23052948 return;
23062949
23072950 tg = top_pipe_to_program->stream_res.tg;
23082951
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));
23102965
23112966 if (num_planes == 0) {
23122967 /* 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);
23142969 }
23152970
23162971 /* Disconnect unused mpcc */
....@@ -2318,32 +2973,14 @@
23182973 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
23192974 struct pipe_ctx *old_pipe_ctx =
23202975 &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
- }
23392976
23402977 if ((!pipe_ctx->plane_state ||
23412978 pipe_ctx->stream_res.tg != old_pipe_ctx->stream_res.tg) &&
23422979 old_pipe_ctx->plane_state &&
23432980 old_pipe_ctx->stream_res.tg == tg) {
23442981
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;
23472984
23482985 DC_LOG_DC("Reset mpcc for pipe %d\n",
23492986 old_pipe_ctx->pipe_idx);
....@@ -2351,68 +2988,175 @@
23512988 }
23522989
23532990 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);
23552992
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;
23573003
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
+ }
23603031
23613032 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
+ }
23643041
23653042 if (dc->hwseq->wa.DEGVIDCN10_254)
23663043 hubbub1_wm_change_req_wa(dc->res_pool->hubbub);
23673044 }
23683045
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)
23733047 {
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
+
23743069 if (dc->debug.sanity_checks)
2375
- dcn10_verify_allow_pstate_change_high(dc);
3070
+ hws->funcs.verify_allow_pstate_change_high(dc);
23763071
23773072 if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
23783073 if (context->stream_count == 0)
2379
- context->bw.dcn.clk.phyclk_khz = 0;
3074
+ context->bw_ctx.bw.dcn.clk.phyclk_khz = 0;
23803075
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);
23873080 }
23883081
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,
23923085 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);
23933090
23943091 if (dc->debug.sanity_checks)
2395
- dcn10_verify_allow_pstate_change_high(dc);
3092
+ hws->funcs.verify_allow_pstate_change_high(dc);
23963093 }
23973094
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)
24003132 {
24013133 int i = 0;
24023134 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;
24033139
24043140 params.vertical_total_max = vmax;
24053141 params.vertical_total_min = vmin;
3142
+ params.vertical_total_mid = vmid;
3143
+ params.vertical_total_mid_frame_num = vmid_frame_number;
24063144
24073145 /* 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.
24093148 */
24103149 for (i = 0; i < num_pipes; i++) {
2411
- pipe_ctx[i]->stream_res.tg->funcs->set_drr(pipe_ctx[i]->stream_res.tg, &params);
3150
+ pipe_ctx[i]->stream_res.tg->funcs->set_drr(
3151
+ pipe_ctx[i]->stream_res.tg, &params);
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);
24123156 }
24133157 }
24143158
2415
-static void get_position(struct pipe_ctx **pipe_ctx,
3159
+void dcn10_get_position(struct pipe_ctx **pipe_ctx,
24163160 int num_pipes,
24173161 struct crtc_position *position)
24183162 {
....@@ -2424,22 +3168,23 @@
24243168 pipe_ctx[i]->stream_res.tg->funcs->get_position(pipe_ctx[i]->stream_res.tg, position);
24253169 }
24263170
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)
24293173 {
24303174 unsigned int i;
2431
- unsigned int value = 0;
3175
+ unsigned int triggers = 0;
24323176
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;
24393183
24403184 for (i = 0; i < num_pipes; i++)
24413185 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);
24433188 }
24443189
24453190 static void dcn10_config_stereo_parameters(
....@@ -2464,7 +3209,7 @@
24643209 timing_3d_format == TIMING_3D_FORMAT_DP_HDMI_INBAND_FA ||
24653210 timing_3d_format == TIMING_3D_FORMAT_SIDEBAND_FA) {
24663211 enum display_dongle_type dongle = \
2467
- stream->sink->link->ddc->dongle_type;
3212
+ stream->link->ddc->dongle_type;
24683213 if (dongle == DISPLAY_DONGLE_DP_VGA_CONVERTER ||
24693214 dongle == DISPLAY_DONGLE_DP_DVI_CONVERTER ||
24703215 dongle == DISPLAY_DONGLE_DP_HDMI_CONVERTER)
....@@ -2479,12 +3224,19 @@
24793224 return;
24803225 }
24813226
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)
24833228 {
24843229 struct crtc_stereo_flags flags = { 0 };
24853230 struct dc_stream_state *stream = pipe_ctx->stream;
24863231
24873232 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
+ }
24883240
24893241 pipe_ctx->stream_res.opp->funcs->opp_program_stereo(
24903242 pipe_ctx->stream_res.opp,
....@@ -2511,15 +3263,16 @@
25113263 return NULL;
25123264 }
25133265
2514
-static void dcn10_wait_for_mpcc_disconnect(
3266
+void dcn10_wait_for_mpcc_disconnect(
25153267 struct dc *dc,
25163268 struct resource_pool *res_pool,
25173269 struct pipe_ctx *pipe_ctx)
25183270 {
3271
+ struct dce_hwseq *hws = dc->hwseq;
25193272 int mpcc_inst;
25203273
25213274 if (dc->debug.sanity_checks) {
2522
- dcn10_verify_allow_pstate_change_high(dc);
3275
+ hws->funcs.verify_allow_pstate_change_high(dc);
25233276 }
25243277
25253278 if (!pipe_ctx->stream_res.opp)
....@@ -2529,22 +3282,21 @@
25293282 if (pipe_ctx->stream_res.opp->mpcc_disconnect_pending[mpcc_inst]) {
25303283 struct hubp *hubp = get_hubp_by_inst(res_pool, mpcc_inst);
25313284
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);
25333288 pipe_ctx->stream_res.opp->mpcc_disconnect_pending[mpcc_inst] = false;
25343289 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);*/
25383290 }
25393291 }
25403292
25413293 if (dc->debug.sanity_checks) {
2542
- dcn10_verify_allow_pstate_change_high(dc);
3294
+ hws->funcs.verify_allow_pstate_change_high(dc);
25433295 }
25443296
25453297 }
25463298
2547
-static bool dcn10_dummy_display_power_gating(
3299
+bool dcn10_dummy_display_power_gating(
25483300 struct dc *dc,
25493301 uint8_t controller_id,
25503302 struct dc_bios *dcb,
....@@ -2553,11 +3305,12 @@
25533305 return true;
25543306 }
25553307
2556
-static void dcn10_update_pending_status(struct pipe_ctx *pipe_ctx)
3308
+void dcn10_update_pending_status(struct pipe_ctx *pipe_ctx)
25573309 {
25583310 struct dc_plane_state *plane_state = pipe_ctx->plane_state;
25593311 struct timing_generator *tg = pipe_ctx->stream_res.tg;
25603312 bool flip_pending;
3313
+ struct dc *dc = plane_state->ctx->dc;
25613314
25623315 if (plane_state == NULL)
25633316 return;
....@@ -2565,7 +3318,7 @@
25653318 flip_pending = pipe_ctx->plane_res.hubp->funcs->hubp_is_flip_pending(
25663319 pipe_ctx->plane_res.hubp);
25673320
2568
- plane_state->status.is_flip_pending = flip_pending;
3321
+ plane_state->status.is_flip_pending = plane_state->status.is_flip_pending || flip_pending;
25693322
25703323 if (!flip_pending)
25713324 plane_state->status.current_address = plane_state->status.requested_address;
....@@ -2575,57 +3328,210 @@
25753328 plane_state->status.is_right_eye =
25763329 !tg->funcs->is_stereo_left_eye(pipe_ctx->stream_res.tg);
25773330 }
2578
-}
25793331
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);
25843336
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
+ }
25893343 }
25903344 }
25913345
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)
25933382 {
25943383 struct dc_cursor_position pos_cpy = pipe_ctx->stream->cursor_position;
25953384 struct hubp *hubp = pipe_ctx->plane_res.hubp;
25963385 struct dpp *dpp = pipe_ctx->plane_res.dpp;
25973386 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,
26003389 .viewport = pipe_ctx->plane_res.scl_data.viewport,
26013390 .h_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.horz,
26023391 .v_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.vert,
26033392 .rotation = pipe_ctx->plane_state->rotation,
26043393 .mirror = pipe_ctx->plane_state->horizontal_mirror
26053394 };
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;
26063459
26073460 if (pipe_ctx->plane_state->address.type
26083461 == PLN_ADDR_TYPE_VIDEO_PROGRESSIVE)
26093462 pos_cpy.enable = false;
26103463
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))
26123465 pos_cpy.enable = false;
26133466
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
+
26143520 hubp->funcs->set_cursor_position(hubp, &pos_cpy, &param);
2615
- dpp->funcs->set_cursor_position(dpp, &pos_cpy, &param, hubp->curs_attr.width);
3521
+ dpp->funcs->set_cursor_position(dpp, &pos_cpy, &param, hubp->curs_attr.width, hubp->curs_attr.height);
26163522 }
26173523
2618
-static void dcn10_set_cursor_attribute(struct pipe_ctx *pipe_ctx)
3524
+void dcn10_set_cursor_attribute(struct pipe_ctx *pipe_ctx)
26193525 {
26203526 struct dc_cursor_attributes *attributes = &pipe_ctx->stream->cursor_attributes;
26213527
26223528 pipe_ctx->plane_res.hubp->funcs->set_cursor_attributes(
26233529 pipe_ctx->plane_res.hubp, attributes);
26243530 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);
26263532 }
26273533
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)
26293535 {
26303536 uint32_t sdr_white_level = pipe_ctx->stream->cursor_attributes.sdr_white_level;
26313537 struct fixed31_32 multiplier;
....@@ -2652,60 +3558,216 @@
26523558 pipe_ctx->plane_res.dpp, &opt_attr);
26533559 }
26543560
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)
27083569 {
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
+ }
27103577 }
27113578
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, &params);
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
+}