2 * Copyright 2016 Advanced Micro Devices, Inc.
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
26 #include "dm_services.h"
27 #include "core_types.h"
29 #include "custom_float.h"
30 #include "dcn10_hw_sequencer.h"
31 #include "dce110/dce110_hw_sequencer.h"
32 #include "dce/dce_hwseq.h"
34 #include "dcn10/dcn10_mem_input.h"
35 #include "dcn10/dcn10_timing_generator.h"
36 #include "dcn10/dcn10_dpp.h"
37 #include "dcn10/dcn10_mpc.h"
38 #include "timing_generator.h"
42 #include "reg_helper.h"
43 #include "custom_float.h"
51 #define FN(reg_name, field_name) \
52 hws->shifts->field_name, hws->masks->field_name
54 static void log_mpc_crc(struct dc *dc)
56 struct dc_context *dc_ctx = dc->ctx;
57 struct dce_hwseq *hws = dc->hwseq;
59 if (REG(MPC_CRC_RESULT_GB))
60 DTN_INFO("MPC_CRC_RESULT_GB:%d MPC_CRC_RESULT_C:%d MPC_CRC_RESULT_AR:%d\n",
61 REG_READ(MPC_CRC_RESULT_GB), REG_READ(MPC_CRC_RESULT_C), REG_READ(MPC_CRC_RESULT_AR));
62 if (REG(DPP_TOP0_DPP_CRC_VAL_B_A))
63 DTN_INFO("DPP_TOP0_DPP_CRC_VAL_B_A:%d DPP_TOP0_DPP_CRC_VAL_R_G:%d\n",
64 REG_READ(DPP_TOP0_DPP_CRC_VAL_B_A), REG_READ(DPP_TOP0_DPP_CRC_VAL_R_G));
67 void print_microsec(struct dc_context *dc_ctx, uint32_t ref_cycle)
69 static const uint32_t ref_clk_mhz = 48;
70 static const unsigned int frac = 10;
71 uint32_t us_x10 = (ref_cycle * frac) / ref_clk_mhz;
78 #define DTN_INFO_MICRO_SEC(ref_cycle) \
79 print_microsec(dc_ctx, ref_cycle)
81 struct dcn_hubbub_wm_set {
84 uint32_t pte_meta_urgent;
87 uint32_t dram_clk_chanage;
90 struct dcn_hubbub_wm {
91 struct dcn_hubbub_wm_set sets[4];
94 static void dcn10_hubbub_wm_read_state(struct dce_hwseq *hws,
95 struct dcn_hubbub_wm *wm)
97 struct dcn_hubbub_wm_set *s;
101 s->data_urgent = REG_READ(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A);
102 s->pte_meta_urgent = REG_READ(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_A);
103 s->sr_enter = REG_READ(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A);
104 s->sr_exit = REG_READ(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A);
105 s->dram_clk_chanage = REG_READ(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A);
109 s->data_urgent = REG_READ(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B);
110 s->pte_meta_urgent = REG_READ(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_B);
111 s->sr_enter = REG_READ(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B);
112 s->sr_exit = REG_READ(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B);
113 s->dram_clk_chanage = REG_READ(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B);
117 s->data_urgent = REG_READ(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C);
118 s->pte_meta_urgent = REG_READ(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_C);
119 s->sr_enter = REG_READ(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C);
120 s->sr_exit = REG_READ(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C);
121 s->dram_clk_chanage = REG_READ(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C);
125 s->data_urgent = REG_READ(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D);
126 s->pte_meta_urgent = REG_READ(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_D);
127 s->sr_enter = REG_READ(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D);
128 s->sr_exit = REG_READ(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D);
129 s->dram_clk_chanage = REG_READ(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D);
132 static void dcn10_log_hubbub_state(struct dc *dc)
134 struct dc_context *dc_ctx = dc->ctx;
135 struct dcn_hubbub_wm wm;
138 dcn10_hubbub_wm_read_state(dc->hwseq, &wm);
140 DTN_INFO("HUBBUB WM: \t data_urgent \t pte_meta_urgent \t "
141 "sr_enter \t sr_exit \t dram_clk_change \n");
143 for (i = 0; i < 4; i++) {
144 struct dcn_hubbub_wm_set *s;
147 DTN_INFO("WM_Set[%d]:\t ", s->wm_set);
148 DTN_INFO_MICRO_SEC(s->data_urgent);
149 DTN_INFO_MICRO_SEC(s->pte_meta_urgent);
150 DTN_INFO_MICRO_SEC(s->sr_enter);
151 DTN_INFO_MICRO_SEC(s->sr_exit);
152 DTN_INFO_MICRO_SEC(s->dram_clk_chanage);
159 static void dcn10_log_hw_state(struct dc *dc)
161 struct dc_context *dc_ctx = dc->ctx;
162 struct resource_pool *pool = dc->res_pool;
167 dcn10_log_hubbub_state(dc);
169 DTN_INFO("HUBP:\t format \t addr_hi \t width \t height \t "
170 "rotation \t mirror \t sw_mode \t "
171 "dcc_en \t blank_en \t ttu_dis \t underflow \t "
172 "min_ttu_vblank \t qos_low_wm \t qos_high_wm \n");
174 for (i = 0; i < pool->pipe_count; i++) {
175 struct mem_input *mi = pool->mis[i];
176 struct dcn_hubp_state s;
178 dcn10_mem_input_read_state(TO_DCN10_MEM_INPUT(mi), &s);
180 DTN_INFO("[%d]:\t %xh \t %xh \t %d \t %d \t "
181 "%xh \t %xh \t %xh \t "
182 "%d \t %d \t %d \t %xh \t",
195 DTN_INFO_MICRO_SEC(s.min_ttu_vblank);
196 DTN_INFO_MICRO_SEC(s.qos_level_low_wm);
197 DTN_INFO_MICRO_SEC(s.qos_level_high_wm);
202 DTN_INFO("OTG:\t v_bs \t v_be \t v_ss \t v_se \t vpol \t vmax \t vmin \t "
203 "h_bs \t h_be \t h_ss \t h_se \t hpol \t htot \t vtot \t underflow\n");
205 for (i = 0; i < pool->pipe_count; i++) {
206 struct timing_generator *tg = pool->timing_generators[i];
207 struct dcn_otg_state s = {0};
209 tgn10_read_otg_state(DCN10TG_FROM_TG(tg), &s);
211 //only print if OTG master is enabled
212 if ((s.otg_enabled & 1) == 0)
215 DTN_INFO("[%d]:\t %d \t %d \t %d \t %d \t "
216 "%d \t %d \t %d \t %d \t %d \t %d \t "
217 "%d \t %d \t %d \t %d \t %d \t ",
233 s.underflow_occurred_status);
243 static void verify_allow_pstate_change_high(
244 struct dce_hwseq *hws)
246 /* pstate latency is ~20us so if we wait over 40us and pstate allow
247 * still not asserted, we are probably stuck and going to hang
249 static unsigned int pstate_wait_timeout_us = 40;
250 static unsigned int max_sampled_pstate_wait_us; /* data collection */
251 static bool forced_pstate_allow; /* help with revert wa */
252 static bool should_log_hw_state; /* prevent hw state log by default */
254 unsigned int debug_index = 0x7;
255 unsigned int debug_data;
256 unsigned int force_allow_pstate = 0x30;
259 if (forced_pstate_allow) {
260 /* we hacked to force pstate allow to prevent hang last time
261 * we verify_allow_pstate_change_high. so disable force
262 * here so we can check status
264 REG_WRITE(DCHUBBUB_ARB_DRAM_STATE_CNTL, 0);
265 forced_pstate_allow = false;
268 /* description "3-0: Pipe0 cursor0 QOS
269 * 7-4: Pipe1 cursor0 QOS
270 * 11-8: Pipe2 cursor0 QOS
271 * 15-12: Pipe3 cursor0 QOS
272 * 16: Pipe0 Plane0 Allow Pstate Change
273 * 17: Pipe1 Plane0 Allow Pstate Change
274 * 18: Pipe2 Plane0 Allow Pstate Change
275 * 19: Pipe3 Plane0 Allow Pstate Change
276 * 20: Pipe0 Plane1 Allow Pstate Change
277 * 21: Pipe1 Plane1 Allow Pstate Change
278 * 22: Pipe2 Plane1 Allow Pstate Change
279 * 23: Pipe3 Plane1 Allow Pstate Change
280 * 24: Pipe0 cursor0 Allow Pstate Change
281 * 25: Pipe1 cursor0 Allow Pstate Change
282 * 26: Pipe2 cursor0 Allow Pstate Change
283 * 27: Pipe3 cursor0 Allow Pstate Change
284 * 28: WB0 Allow Pstate Change
285 * 29: WB1 Allow Pstate Change
286 * 30: Arbiter's allow_pstate_change
287 * 31: SOC pstate change request
290 REG_WRITE(DCHUBBUB_TEST_DEBUG_INDEX, debug_index);
292 for (i = 0; i < pstate_wait_timeout_us; i++) {
293 debug_data = REG_READ(DCHUBBUB_TEST_DEBUG_DATA);
295 if (debug_data & (1 << 30))
298 if (max_sampled_pstate_wait_us < i)
299 max_sampled_pstate_wait_us = i;
304 /* force pstate allow to prevent system hang
305 * and break to debugger to investigate
307 REG_WRITE(DCHUBBUB_ARB_DRAM_STATE_CNTL, force_allow_pstate);
308 forced_pstate_allow = true;
310 if (should_log_hw_state) {
311 dcn10_log_hw_state(hws->ctx->dc);
317 static void enable_dppclk(
318 struct dce_hwseq *hws,
320 uint32_t requested_pix_clk,
323 dm_logger_write(hws->ctx->logger, LOG_SURFACE,
324 "dppclk_rate_control for pipe %d programed to %d\n",
328 if (hws->shifts->DPPCLK_RATE_CONTROL)
329 REG_UPDATE_2(DPP_CONTROL[plane_id],
330 DPPCLK_RATE_CONTROL, dppclk_div,
331 DPP_CLOCK_ENABLE, 1);
333 REG_UPDATE(DPP_CONTROL[plane_id],
334 DPP_CLOCK_ENABLE, 1);
337 static void enable_power_gating_plane(
338 struct dce_hwseq *hws,
341 bool force_on = 1; /* disable power gating */
347 REG_UPDATE(DOMAIN0_PG_CONFIG, DOMAIN0_POWER_FORCEON, force_on);
348 REG_UPDATE(DOMAIN2_PG_CONFIG, DOMAIN2_POWER_FORCEON, force_on);
349 REG_UPDATE(DOMAIN4_PG_CONFIG, DOMAIN4_POWER_FORCEON, force_on);
350 REG_UPDATE(DOMAIN6_PG_CONFIG, DOMAIN6_POWER_FORCEON, force_on);
353 REG_UPDATE(DOMAIN1_PG_CONFIG, DOMAIN1_POWER_FORCEON, force_on);
354 REG_UPDATE(DOMAIN3_PG_CONFIG, DOMAIN3_POWER_FORCEON, force_on);
355 REG_UPDATE(DOMAIN5_PG_CONFIG, DOMAIN5_POWER_FORCEON, force_on);
356 REG_UPDATE(DOMAIN7_PG_CONFIG, DOMAIN7_POWER_FORCEON, force_on);
359 static void disable_vga(
360 struct dce_hwseq *hws)
362 REG_WRITE(D1VGA_CONTROL, 0);
363 REG_WRITE(D2VGA_CONTROL, 0);
364 REG_WRITE(D3VGA_CONTROL, 0);
365 REG_WRITE(D4VGA_CONTROL, 0);
368 static void dpp_pg_control(
369 struct dce_hwseq *hws,
370 unsigned int dpp_inst,
373 uint32_t power_gate = power_on ? 0 : 1;
374 uint32_t pwr_status = power_on ? 0 : 2;
376 if (hws->ctx->dc->debug.disable_dpp_power_gate)
381 REG_UPDATE(DOMAIN1_PG_CONFIG,
382 DOMAIN1_POWER_GATE, power_gate);
384 REG_WAIT(DOMAIN1_PG_STATUS,
385 DOMAIN1_PGFSM_PWR_STATUS, pwr_status,
389 REG_UPDATE(DOMAIN3_PG_CONFIG,
390 DOMAIN3_POWER_GATE, power_gate);
392 REG_WAIT(DOMAIN3_PG_STATUS,
393 DOMAIN3_PGFSM_PWR_STATUS, pwr_status,
397 REG_UPDATE(DOMAIN5_PG_CONFIG,
398 DOMAIN5_POWER_GATE, power_gate);
400 REG_WAIT(DOMAIN5_PG_STATUS,
401 DOMAIN5_PGFSM_PWR_STATUS, pwr_status,
405 REG_UPDATE(DOMAIN7_PG_CONFIG,
406 DOMAIN7_POWER_GATE, power_gate);
408 REG_WAIT(DOMAIN7_PG_STATUS,
409 DOMAIN7_PGFSM_PWR_STATUS, pwr_status,
418 static uint32_t convert_and_clamp(
421 uint32_t clamp_value)
423 uint32_t ret_val = 0;
424 ret_val = wm_ns * refclk_mhz;
427 if (ret_val > clamp_value)
428 ret_val = clamp_value;
433 static void program_watermarks(
434 struct dce_hwseq *hws,
435 struct dcn_watermark_set *watermarks,
436 unsigned int refclk_mhz)
438 uint32_t force_en = hws->ctx->dc->debug.disable_stutter ? 1 : 0;
440 * Need to clamp to max of the register values (i.e. no wrap)
441 * for dcn1, all wm registers are 21-bit wide
443 uint32_t prog_wm_value;
445 REG_UPDATE(DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL,
446 DCHUBBUB_ARB_WATERMARK_CHANGE_REQUEST, 0);
448 /* Repeat for water mark set A, B, C and D. */
450 prog_wm_value = convert_and_clamp(watermarks->a.urgent_ns,
451 refclk_mhz, 0x1fffff);
452 REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, prog_wm_value);
454 dm_logger_write(hws->ctx->logger, LOG_HW_MARKS,
455 "URGENCY_WATERMARK_A calculated =%d\n"
456 "HW register value = 0x%x\n",
457 watermarks->a.urgent_ns, prog_wm_value);
459 prog_wm_value = convert_and_clamp(watermarks->a.pte_meta_urgent_ns,
460 refclk_mhz, 0x1fffff);
461 REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_A, prog_wm_value);
462 dm_logger_write(hws->ctx->logger, LOG_HW_MARKS,
463 "PTE_META_URGENCY_WATERMARK_A calculated =%d\n"
464 "HW register value = 0x%x\n",
465 watermarks->a.pte_meta_urgent_ns, prog_wm_value);
468 prog_wm_value = convert_and_clamp(
469 watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns,
470 refclk_mhz, 0x1fffff);
472 REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A, prog_wm_value);
473 dm_logger_write(hws->ctx->logger, LOG_HW_MARKS,
474 "SR_ENTER_EXIT_WATERMARK_A calculated =%d\n"
475 "HW register value = 0x%x\n",
476 watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value);
479 prog_wm_value = convert_and_clamp(
480 watermarks->a.cstate_pstate.cstate_exit_ns,
481 refclk_mhz, 0x1fffff);
482 REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A, prog_wm_value);
483 dm_logger_write(hws->ctx->logger, LOG_HW_MARKS,
484 "SR_EXIT_WATERMARK_A calculated =%d\n"
485 "HW register value = 0x%x\n",
486 watermarks->a.cstate_pstate.cstate_exit_ns, prog_wm_value);
489 prog_wm_value = convert_and_clamp(
490 watermarks->a.cstate_pstate.pstate_change_ns,
491 refclk_mhz, 0x1fffff);
492 REG_WRITE(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A, prog_wm_value);
493 dm_logger_write(hws->ctx->logger, LOG_HW_MARKS,
494 "DRAM_CLK_CHANGE_WATERMARK_A calculated =%d\n"
495 "HW register value = 0x%x\n\n",
496 watermarks->a.cstate_pstate.pstate_change_ns, prog_wm_value);
500 prog_wm_value = convert_and_clamp(
501 watermarks->b.urgent_ns, refclk_mhz, 0x1fffff);
502 REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, prog_wm_value);
503 dm_logger_write(hws->ctx->logger, LOG_HW_MARKS,
504 "URGENCY_WATERMARK_B calculated =%d\n"
505 "HW register value = 0x%x\n",
506 watermarks->b.urgent_ns, prog_wm_value);
509 prog_wm_value = convert_and_clamp(
510 watermarks->b.pte_meta_urgent_ns,
511 refclk_mhz, 0x1fffff);
512 REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_B, prog_wm_value);
513 dm_logger_write(hws->ctx->logger, LOG_HW_MARKS,
514 "PTE_META_URGENCY_WATERMARK_B calculated =%d\n"
515 "HW register value = 0x%x\n",
516 watermarks->b.pte_meta_urgent_ns, prog_wm_value);
519 prog_wm_value = convert_and_clamp(
520 watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns,
521 refclk_mhz, 0x1fffff);
522 REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, prog_wm_value);
523 dm_logger_write(hws->ctx->logger, LOG_HW_MARKS,
524 "SR_ENTER_WATERMARK_B calculated =%d\n"
525 "HW register value = 0x%x\n",
526 watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value);
529 prog_wm_value = convert_and_clamp(
530 watermarks->b.cstate_pstate.cstate_exit_ns,
531 refclk_mhz, 0x1fffff);
532 REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, prog_wm_value);
533 dm_logger_write(hws->ctx->logger, LOG_HW_MARKS,
534 "SR_EXIT_WATERMARK_B calculated =%d\n"
535 "HW register value = 0x%x\n",
536 watermarks->b.cstate_pstate.cstate_exit_ns, prog_wm_value);
538 prog_wm_value = convert_and_clamp(
539 watermarks->b.cstate_pstate.pstate_change_ns,
540 refclk_mhz, 0x1fffff);
541 REG_WRITE(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B, prog_wm_value);
542 dm_logger_write(hws->ctx->logger, LOG_HW_MARKS,
543 "DRAM_CLK_CHANGE_WATERMARK_B calculated =%d\n\n"
544 "HW register value = 0x%x\n",
545 watermarks->b.cstate_pstate.pstate_change_ns, prog_wm_value);
548 prog_wm_value = convert_and_clamp(
549 watermarks->c.urgent_ns, refclk_mhz, 0x1fffff);
550 REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C, prog_wm_value);
551 dm_logger_write(hws->ctx->logger, LOG_HW_MARKS,
552 "URGENCY_WATERMARK_C calculated =%d\n"
553 "HW register value = 0x%x\n",
554 watermarks->c.urgent_ns, prog_wm_value);
557 prog_wm_value = convert_and_clamp(
558 watermarks->c.pte_meta_urgent_ns,
559 refclk_mhz, 0x1fffff);
560 REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_C, prog_wm_value);
561 dm_logger_write(hws->ctx->logger, LOG_HW_MARKS,
562 "PTE_META_URGENCY_WATERMARK_C calculated =%d\n"
563 "HW register value = 0x%x\n",
564 watermarks->c.pte_meta_urgent_ns, prog_wm_value);
567 prog_wm_value = convert_and_clamp(
568 watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns,
569 refclk_mhz, 0x1fffff);
570 REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C, prog_wm_value);
571 dm_logger_write(hws->ctx->logger, LOG_HW_MARKS,
572 "SR_ENTER_WATERMARK_C calculated =%d\n"
573 "HW register value = 0x%x\n",
574 watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value);
577 prog_wm_value = convert_and_clamp(
578 watermarks->c.cstate_pstate.cstate_exit_ns,
579 refclk_mhz, 0x1fffff);
580 REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C, prog_wm_value);
581 dm_logger_write(hws->ctx->logger, LOG_HW_MARKS,
582 "SR_EXIT_WATERMARK_C calculated =%d\n"
583 "HW register value = 0x%x\n",
584 watermarks->c.cstate_pstate.cstate_exit_ns, prog_wm_value);
587 prog_wm_value = convert_and_clamp(
588 watermarks->c.cstate_pstate.pstate_change_ns,
589 refclk_mhz, 0x1fffff);
590 REG_WRITE(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C, prog_wm_value);
591 dm_logger_write(hws->ctx->logger, LOG_HW_MARKS,
592 "DRAM_CLK_CHANGE_WATERMARK_C calculated =%d\n\n"
593 "HW register value = 0x%x\n",
594 watermarks->c.cstate_pstate.pstate_change_ns, prog_wm_value);
597 prog_wm_value = convert_and_clamp(
598 watermarks->d.urgent_ns, refclk_mhz, 0x1fffff);
599 REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D, prog_wm_value);
600 dm_logger_write(hws->ctx->logger, LOG_HW_MARKS,
601 "URGENCY_WATERMARK_D calculated =%d\n"
602 "HW register value = 0x%x\n",
603 watermarks->d.urgent_ns, prog_wm_value);
605 prog_wm_value = convert_and_clamp(
606 watermarks->d.pte_meta_urgent_ns,
607 refclk_mhz, 0x1fffff);
608 REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_D, prog_wm_value);
609 dm_logger_write(hws->ctx->logger, LOG_HW_MARKS,
610 "PTE_META_URGENCY_WATERMARK_D calculated =%d\n"
611 "HW register value = 0x%x\n",
612 watermarks->d.pte_meta_urgent_ns, prog_wm_value);
615 prog_wm_value = convert_and_clamp(
616 watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns,
617 refclk_mhz, 0x1fffff);
618 REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D, prog_wm_value);
619 dm_logger_write(hws->ctx->logger, LOG_HW_MARKS,
620 "SR_ENTER_WATERMARK_D calculated =%d\n"
621 "HW register value = 0x%x\n",
622 watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value);
625 prog_wm_value = convert_and_clamp(
626 watermarks->d.cstate_pstate.cstate_exit_ns,
627 refclk_mhz, 0x1fffff);
628 REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D, prog_wm_value);
629 dm_logger_write(hws->ctx->logger, LOG_HW_MARKS,
630 "SR_EXIT_WATERMARK_D calculated =%d\n"
631 "HW register value = 0x%x\n",
632 watermarks->d.cstate_pstate.cstate_exit_ns, prog_wm_value);
635 prog_wm_value = convert_and_clamp(
636 watermarks->d.cstate_pstate.pstate_change_ns,
637 refclk_mhz, 0x1fffff);
638 REG_WRITE(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D, prog_wm_value);
639 dm_logger_write(hws->ctx->logger, LOG_HW_MARKS,
640 "DRAM_CLK_CHANGE_WATERMARK_D calculated =%d\n"
641 "HW register value = 0x%x\n\n",
642 watermarks->d.cstate_pstate.pstate_change_ns, prog_wm_value);
644 REG_UPDATE(DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL,
645 DCHUBBUB_ARB_WATERMARK_CHANGE_REQUEST, 1);
647 REG_UPDATE(DCHUBBUB_ARB_SAT_LEVEL,
648 DCHUBBUB_ARB_SAT_LEVEL, 60 * refclk_mhz);
649 REG_UPDATE(DCHUBBUB_ARB_DF_REQ_OUTSTAND,
650 DCHUBBUB_ARB_MIN_REQ_OUTSTAND, 68);
652 REG_UPDATE_2(DCHUBBUB_ARB_DRAM_STATE_CNTL,
653 DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_VALUE, 0,
654 DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE, force_en);
657 REG_UPDATE_2(DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL,
658 DCHUBBUB_ARB_WATERMARK_CHANGE_DONE_INTERRUPT_DISABLE, 1,
659 DCHUBBUB_ARB_WATERMARK_CHANGE_REQUEST, 1);
664 static void dcn10_update_dchub(
665 struct dce_hwseq *hws,
666 struct dchub_init_data *dh_data)
668 /* TODO: port code from dal2 */
669 switch (dh_data->fb_mode) {
670 case FRAME_BUFFER_MODE_ZFB_ONLY:
671 /*For ZFB case need to put DCHUB FB BASE and TOP upside down to indicate ZFB mode*/
672 REG_UPDATE(DCHUBBUB_SDPIF_FB_TOP,
675 REG_UPDATE(DCHUBBUB_SDPIF_FB_BASE,
676 SDPIF_FB_BASE, 0x0FFFF);
678 REG_UPDATE(DCHUBBUB_SDPIF_AGP_BASE,
679 SDPIF_AGP_BASE, dh_data->zfb_phys_addr_base >> 22);
681 REG_UPDATE(DCHUBBUB_SDPIF_AGP_BOT,
682 SDPIF_AGP_BOT, dh_data->zfb_mc_base_addr >> 22);
684 REG_UPDATE(DCHUBBUB_SDPIF_AGP_TOP,
685 SDPIF_AGP_TOP, (dh_data->zfb_mc_base_addr +
686 dh_data->zfb_size_in_byte - 1) >> 22);
688 case FRAME_BUFFER_MODE_MIXED_ZFB_AND_LOCAL:
689 /*Should not touch FB LOCATION (done by VBIOS on AsicInit table)*/
691 REG_UPDATE(DCHUBBUB_SDPIF_AGP_BASE,
692 SDPIF_AGP_BASE, dh_data->zfb_phys_addr_base >> 22);
694 REG_UPDATE(DCHUBBUB_SDPIF_AGP_BOT,
695 SDPIF_AGP_BOT, dh_data->zfb_mc_base_addr >> 22);
697 REG_UPDATE(DCHUBBUB_SDPIF_AGP_TOP,
698 SDPIF_AGP_TOP, (dh_data->zfb_mc_base_addr +
699 dh_data->zfb_size_in_byte - 1) >> 22);
701 case FRAME_BUFFER_MODE_LOCAL_ONLY:
702 /*Should not touch FB LOCATION (done by VBIOS on AsicInit table)*/
703 REG_UPDATE(DCHUBBUB_SDPIF_AGP_BASE,
706 REG_UPDATE(DCHUBBUB_SDPIF_AGP_BOT,
707 SDPIF_AGP_BOT, 0X03FFFF);
709 REG_UPDATE(DCHUBBUB_SDPIF_AGP_TOP,
716 dh_data->dchub_initialzied = true;
717 dh_data->dchub_info_valid = false;
720 static void hubp_pg_control(
721 struct dce_hwseq *hws,
722 unsigned int hubp_inst,
725 uint32_t power_gate = power_on ? 0 : 1;
726 uint32_t pwr_status = power_on ? 0 : 2;
728 if (hws->ctx->dc->debug.disable_hubp_power_gate)
732 case 0: /* DCHUBP0 */
733 REG_UPDATE(DOMAIN0_PG_CONFIG,
734 DOMAIN0_POWER_GATE, power_gate);
736 REG_WAIT(DOMAIN0_PG_STATUS,
737 DOMAIN0_PGFSM_PWR_STATUS, pwr_status,
740 case 1: /* DCHUBP1 */
741 REG_UPDATE(DOMAIN2_PG_CONFIG,
742 DOMAIN2_POWER_GATE, power_gate);
744 REG_WAIT(DOMAIN2_PG_STATUS,
745 DOMAIN2_PGFSM_PWR_STATUS, pwr_status,
748 case 2: /* DCHUBP2 */
749 REG_UPDATE(DOMAIN4_PG_CONFIG,
750 DOMAIN4_POWER_GATE, power_gate);
752 REG_WAIT(DOMAIN4_PG_STATUS,
753 DOMAIN4_PGFSM_PWR_STATUS, pwr_status,
756 case 3: /* DCHUBP3 */
757 REG_UPDATE(DOMAIN6_PG_CONFIG,
758 DOMAIN6_POWER_GATE, power_gate);
760 REG_WAIT(DOMAIN6_PG_STATUS,
761 DOMAIN6_PGFSM_PWR_STATUS, pwr_status,
770 static void power_on_plane(
771 struct dce_hwseq *hws,
774 REG_SET(DC_IP_REQUEST_CNTL, 0,
776 dpp_pg_control(hws, plane_id, true);
777 hubp_pg_control(hws, plane_id, true);
778 REG_SET(DC_IP_REQUEST_CNTL, 0,
780 dm_logger_write(hws->ctx->logger, LOG_DEBUG,
781 "Un-gated front end for pipe %d\n", plane_id);
784 static void undo_DEGVIDCN10_253_wa(struct dc *dc)
786 struct dce_hwseq *hws = dc->hwseq;
787 struct mem_input *mi = dc->res_pool->mis[0];
790 REG_GET(DOMAIN0_PG_STATUS, DOMAIN0_PGFSM_PWR_STATUS, &pwr_status);
791 /* Don't need to blank if hubp is power gated*/
795 mi->funcs->set_blank(mi, true);
797 REG_SET(DC_IP_REQUEST_CNTL, 0,
800 hubp_pg_control(hws, 0, false);
801 REG_SET(DC_IP_REQUEST_CNTL, 0,
805 static void apply_DEGVIDCN10_253_wa(struct dc *dc)
807 struct dce_hwseq *hws = dc->hwseq;
808 struct mem_input *mi = dc->res_pool->mis[0];
810 if (dc->debug.disable_stutter)
813 REG_SET(DC_IP_REQUEST_CNTL, 0,
816 hubp_pg_control(hws, 0, true);
817 REG_SET(DC_IP_REQUEST_CNTL, 0,
820 mi->funcs->set_hubp_blank_en(mi, false);
823 static void bios_golden_init(struct dc *dc)
825 struct dc_bios *bp = dc->ctx->dc_bios;
828 /* initialize dcn global */
829 bp->funcs->enable_disp_power_gating(bp,
830 CONTROLLER_ID_D0, ASIC_PIPE_INIT);
832 for (i = 0; i < dc->res_pool->pipe_count; i++) {
833 /* initialize dcn per pipe */
834 bp->funcs->enable_disp_power_gating(bp,
835 CONTROLLER_ID_D0 + i, ASIC_PIPE_DISABLE);
839 static void dcn10_init_hw(struct dc *dc)
842 struct abm *abm = dc->res_pool->abm;
843 struct dce_hwseq *hws = dc->hwseq;
845 if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
846 REG_WRITE(REFCLK_CNTL, 0);
847 REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_ENABLE, 1);
848 REG_WRITE(DIO_MEM_PWR_CTRL, 0);
850 if (!dc->debug.disable_clock_gate) {
851 /* enable all DCN clock gating */
852 REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0);
854 REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0);
856 REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0);
859 enable_power_gating_plane(dc->hwseq, true);
862 /* end of FPGA. Below if real ASIC */
864 bios_golden_init(dc);
866 disable_vga(dc->hwseq);
868 for (i = 0; i < dc->link_count; i++) {
869 /* Power up AND update implementation according to the
870 * required signal (which may be different from the
871 * default signal on connector).
873 struct dc_link *link = dc->links[i];
875 link->link_enc->funcs->hw_init(link->link_enc);
878 for (i = 0; i < dc->res_pool->pipe_count; i++) {
879 struct transform *xfm = dc->res_pool->transforms[i];
880 struct timing_generator *tg = dc->res_pool->timing_generators[i];
882 xfm->funcs->transform_reset(xfm);
883 dc->res_pool->mpc->funcs->remove(
884 dc->res_pool->mpc, &(dc->res_pool->opps[i]->mpc_tree),
885 dc->res_pool->opps[i]->inst, i);
887 /* Blank controller using driver code instead of
890 tg->funcs->set_blank(tg, true);
891 hwss_wait_for_blank_complete(tg);
894 for (i = 0; i < dc->res_pool->audio_count; i++) {
895 struct audio *audio = dc->res_pool->audios[i];
897 audio->funcs->hw_init(audio);
901 abm->funcs->init_backlight(abm);
902 abm->funcs->abm_init(abm);
905 /* power AFMT HDMI memory TODO: may move to dis/en output save power*/
906 REG_WRITE(DIO_MEM_PWR_CTRL, 0);
908 if (!dc->debug.disable_clock_gate) {
909 /* enable all DCN clock gating */
910 REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0);
912 REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0);
914 REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0);
917 enable_power_gating_plane(dc->hwseq, true);
920 static enum dc_status dcn10_prog_pixclk_crtc_otg(
921 struct pipe_ctx *pipe_ctx,
922 struct dc_state *context,
925 struct dc_stream_state *stream = pipe_ctx->stream;
926 enum dc_color_space color_space;
927 struct tg_color black_color = {0};
928 bool enableStereo = stream->timing.timing_3d_format == TIMING_3D_FORMAT_NONE ?
930 bool rightEyePolarity = stream->timing.flags.RIGHT_EYE_3D_POLARITY;
933 /* by upper caller loop, pipe0 is parent pipe and be called first.
934 * back end is set up by for pipe0. Other children pipe share back end
935 * with pipe 0. No program is needed.
937 if (pipe_ctx->top_pipe != NULL)
940 /* TODO check if timing_changed, disable stream if timing changed */
942 /* HW program guide assume display already disable
943 * by unplug sequence. OTG assume stop.
945 pipe_ctx->stream_res.tg->funcs->enable_optc_clock(pipe_ctx->stream_res.tg, true);
947 if (false == pipe_ctx->clock_source->funcs->program_pix_clk(
948 pipe_ctx->clock_source,
949 &pipe_ctx->stream_res.pix_clk_params,
950 &pipe_ctx->pll_settings)) {
952 return DC_ERROR_UNEXPECTED;
954 pipe_ctx->stream_res.tg->dlg_otg_param.vready_offset = pipe_ctx->pipe_dlg_param.vready_offset;
955 pipe_ctx->stream_res.tg->dlg_otg_param.vstartup_start = pipe_ctx->pipe_dlg_param.vstartup_start;
956 pipe_ctx->stream_res.tg->dlg_otg_param.vupdate_offset = pipe_ctx->pipe_dlg_param.vupdate_offset;
957 pipe_ctx->stream_res.tg->dlg_otg_param.vupdate_width = pipe_ctx->pipe_dlg_param.vupdate_width;
959 pipe_ctx->stream_res.tg->dlg_otg_param.signal = pipe_ctx->stream->signal;
961 pipe_ctx->stream_res.tg->funcs->program_timing(
962 pipe_ctx->stream_res.tg,
966 pipe_ctx->stream_res.opp->funcs->opp_set_stereo_polarity(
967 pipe_ctx->stream_res.opp,
971 #if 0 /* move to after enable_crtc */
972 /* TODO: OPP FMT, ABM. etc. should be done here. */
973 /* or FPGA now. instance 0 only. TODO: move to opp.c */
975 inst_offset = reg_offsets[pipe_ctx->stream_res.tg->inst].fmt;
977 pipe_ctx->stream_res.opp->funcs->opp_program_fmt(
978 pipe_ctx->stream_res.opp,
979 &stream->bit_depth_params,
982 /* program otg blank color */
983 color_space = stream->output_color_space;
984 color_space_to_black_color(dc, color_space, &black_color);
985 pipe_ctx->stream_res.tg->funcs->set_blank_color(
986 pipe_ctx->stream_res.tg,
989 pipe_ctx->stream_res.tg->funcs->set_blank(pipe_ctx->stream_res.tg, true);
990 hwss_wait_for_blank_complete(pipe_ctx->stream_res.tg);
992 /* VTG is within DCHUB command block. DCFCLK is always on */
993 if (false == pipe_ctx->stream_res.tg->funcs->enable_crtc(pipe_ctx->stream_res.tg)) {
995 return DC_ERROR_UNEXPECTED;
998 /* TODO program crtc source select for non-virtual signal*/
999 /* TODO program FMT */
1000 /* TODO setup link_enc */
1001 /* TODO set stream attributes */
1002 /* TODO program audio */
1003 /* TODO enable stream if timing changed */
1004 /* TODO unblank stream if DP */
1009 static void reset_back_end_for_pipe(
1011 struct pipe_ctx *pipe_ctx,
1012 struct dc_state *context)
1016 if (pipe_ctx->stream_res.stream_enc == NULL) {
1017 pipe_ctx->stream = NULL;
1021 /* TODOFPGA break core_link_disable_stream into 2 functions:
1022 * disable_stream and disable_link. disable_link will disable PHYPLL
1023 * which is used by otg. Move disable_link after disable_crtc
1025 if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment))
1026 core_link_disable_stream(pipe_ctx);
1028 /* by upper caller loop, parent pipe: pipe0, will be reset last.
1029 * back end share by all pipes and will be disable only when disable
1032 if (pipe_ctx->top_pipe == NULL) {
1033 pipe_ctx->stream_res.tg->funcs->disable_crtc(pipe_ctx->stream_res.tg);
1035 pipe_ctx->stream_res.tg->funcs->enable_optc_clock(pipe_ctx->stream_res.tg, false);
1038 for (i = 0; i < dc->res_pool->pipe_count; i++)
1039 if (&dc->current_state->res_ctx.pipe_ctx[i] == pipe_ctx)
1042 if (i == dc->res_pool->pipe_count)
1045 pipe_ctx->stream = NULL;
1046 dm_logger_write(dc->ctx->logger, LOG_DEBUG,
1047 "Reset back end for pipe %d, tg:%d\n",
1048 pipe_ctx->pipe_idx, pipe_ctx->stream_res.tg->inst);
1051 /* trigger HW to start disconnect plane from stream on the next vsync */
1052 static void plane_atomic_disconnect(struct dc *dc,
1055 struct mem_input *mi = dc->res_pool->mis[fe_idx];
1056 struct mpc *mpc = dc->res_pool->mpc;
1060 /* look at tree rather than mi here to know if we already reset */
1061 for (opp_id = 0; opp_id < dc->res_pool->pipe_count; opp_id++) {
1062 struct output_pixel_processor *opp = dc->res_pool->opps[opp_id];
1064 for (z_idx = 0; z_idx < opp->mpc_tree.num_pipes; z_idx++) {
1065 if (opp->mpc_tree.dpp[z_idx] == fe_idx) {
1066 mpcc_id = opp->mpc_tree.mpcc[z_idx];
1074 if (opp_id == dc->res_pool->pipe_count)
1077 if (dc->debug.sanity_checks)
1078 verify_allow_pstate_change_high(dc->hwseq);
1079 mi->funcs->dcc_control(mi, false, false);
1080 if (dc->debug.sanity_checks)
1081 verify_allow_pstate_change_high(dc->hwseq);
1083 mpc->funcs->remove(mpc, &(dc->res_pool->opps[opp_id]->mpc_tree),
1084 dc->res_pool->opps[opp_id]->inst, fe_idx);
1087 /* disable HW used by plane.
1088 * note: cannot disable until disconnect is complete */
1089 static void plane_atomic_disable(struct dc *dc,
1092 struct dce_hwseq *hws = dc->hwseq;
1093 struct mem_input *mi = dc->res_pool->mis[fe_idx];
1094 struct mpc *mpc = dc->res_pool->mpc;
1095 int opp_id = mi->opp_id;
1100 mpc->funcs->wait_for_idle(mpc, mi->mpcc_id);
1101 dc->res_pool->opps[mi->opp_id]->mpcc_disconnect_pending[mi->mpcc_id] = false;
1102 /*dm_logger_write(dc->ctx->logger, LOG_ERROR,
1103 "[debug_mpo: atomic disable finished on mpcc %d]\n",
1106 mi->funcs->set_blank(mi, true);
1108 if (dc->debug.sanity_checks)
1109 verify_allow_pstate_change_high(dc->hwseq);
1111 REG_UPDATE(HUBP_CLK_CNTL[fe_idx],
1112 HUBP_CLOCK_ENABLE, 0);
1113 REG_UPDATE(DPP_CONTROL[fe_idx],
1114 DPP_CLOCK_ENABLE, 0);
1116 if (dc->res_pool->opps[opp_id]->mpc_tree.num_pipes == 0)
1117 REG_UPDATE(OPP_PIPE_CONTROL[opp_id],
1118 OPP_PIPE_CLOCK_EN, 0);
1120 if (dc->debug.sanity_checks)
1121 verify_allow_pstate_change_high(dc->hwseq);
1125 * kill power to plane hw
1126 * note: cannot power down until plane is disable
1128 static void plane_atomic_power_down(struct dc *dc, int fe_idx)
1130 struct dce_hwseq *hws = dc->hwseq;
1131 struct transform *xfm = dc->res_pool->transforms[fe_idx];
1133 REG_SET(DC_IP_REQUEST_CNTL, 0,
1135 dpp_pg_control(hws, fe_idx, false);
1136 hubp_pg_control(hws, fe_idx, false);
1137 xfm->funcs->transform_reset(xfm);
1138 REG_SET(DC_IP_REQUEST_CNTL, 0,
1140 dm_logger_write(dc->ctx->logger, LOG_DEBUG,
1141 "Power gated front end %d\n", fe_idx);
1143 if (dc->debug.sanity_checks)
1144 verify_allow_pstate_change_high(dc->hwseq);
1148 static void reset_front_end(
1152 struct dce_hwseq *hws = dc->hwseq;
1153 struct timing_generator *tg;
1154 int opp_id = dc->res_pool->mis[fe_idx]->opp_id;
1160 tg = dc->res_pool->timing_generators[opp_id];
1161 tg->funcs->lock(tg);
1163 plane_atomic_disconnect(dc, fe_idx);
1165 REG_UPDATE(OTG_GLOBAL_SYNC_STATUS[tg->inst], VUPDATE_NO_LOCK_EVENT_CLEAR, 1);
1166 tg->funcs->unlock(tg);
1168 if (dc->debug.sanity_checks)
1169 verify_allow_pstate_change_high(hws);
1171 if (tg->ctx->dce_environment != DCE_ENV_FPGA_MAXIMUS)
1172 REG_WAIT(OTG_GLOBAL_SYNC_STATUS[tg->inst],
1173 VUPDATE_NO_LOCK_EVENT_OCCURRED, 1,
1176 plane_atomic_disable(dc, fe_idx);
1178 dm_logger_write(dc->ctx->logger, LOG_DC,
1179 "Reset front end %d\n",
1183 static void dcn10_power_down_fe(struct dc *dc, int fe_idx)
1185 struct dce_hwseq *hws = dc->hwseq;
1186 struct transform *xfm = dc->res_pool->transforms[fe_idx];
1188 reset_front_end(dc, fe_idx);
1190 REG_SET(DC_IP_REQUEST_CNTL, 0,
1192 dpp_pg_control(hws, fe_idx, false);
1193 hubp_pg_control(hws, fe_idx, false);
1194 xfm->funcs->transform_reset(xfm);
1195 REG_SET(DC_IP_REQUEST_CNTL, 0,
1197 dm_logger_write(dc->ctx->logger, LOG_DEBUG,
1198 "Power gated front end %d\n", fe_idx);
1200 if (dc->debug.sanity_checks)
1201 verify_allow_pstate_change_high(dc->hwseq);
1204 static void reset_hw_ctx_wrap(
1206 struct dc_state *context)
1210 /* Reset Front End*/
1212 for (i = 0; i < dc->res_pool->pipe_count; i++) {
1213 struct pipe_ctx *cur_pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i];
1214 struct timing_generator *tg = cur_pipe_ctx->stream_res.tg;
1216 if (cur_pipe_ctx->stream)
1217 tg->funcs->lock(tg);
1220 for (i = dc->res_pool->pipe_count - 1; i >= 0 ; i--) {
1221 struct pipe_ctx *pipe_ctx_old =
1222 &dc->current_state->res_ctx.pipe_ctx[i];
1223 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
1225 if (!pipe_ctx->stream ||
1226 !pipe_ctx->plane_state ||
1227 pipe_need_reprogram(pipe_ctx_old, pipe_ctx)) {
1229 plane_atomic_disconnect(dc, i);
1233 for (i = dc->res_pool->pipe_count - 1; i >= 0; i--) {
1234 struct pipe_ctx *cur_pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i];
1235 struct timing_generator *tg = cur_pipe_ctx->stream_res.tg;
1237 if (cur_pipe_ctx->stream)
1238 tg->funcs->unlock(tg);
1241 /* Disable and Powerdown*/
1242 for (i = dc->res_pool->pipe_count - 1; i >= 0 ; i--) {
1243 struct pipe_ctx *pipe_ctx_old =
1244 &dc->current_state->res_ctx.pipe_ctx[i];
1245 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
1247 /*if (!pipe_ctx_old->stream)
1250 if (pipe_ctx->stream && pipe_ctx->plane_state
1251 && !pipe_need_reprogram(pipe_ctx_old, pipe_ctx))
1254 plane_atomic_disable(dc, i);
1256 if (!pipe_ctx->stream || !pipe_ctx->plane_state)
1257 plane_atomic_power_down(dc, i);
1261 for (i = dc->res_pool->pipe_count - 1; i >= 0 ; i--) {
1262 struct pipe_ctx *pipe_ctx_old =
1263 &dc->current_state->res_ctx.pipe_ctx[i];
1264 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
1266 if (!pipe_ctx_old->stream)
1269 if (!pipe_ctx->stream ||
1270 pipe_need_reprogram(pipe_ctx_old, pipe_ctx)) {
1271 struct clock_source *old_clk = pipe_ctx_old->clock_source;
1273 reset_back_end_for_pipe(dc, pipe_ctx_old, dc->current_state);
1276 old_clk->funcs->cs_power_down(old_clk);
1282 static bool patch_address_for_sbs_tb_stereo(
1283 struct pipe_ctx *pipe_ctx, PHYSICAL_ADDRESS_LOC *addr)
1285 struct dc_plane_state *plane_state = pipe_ctx->plane_state;
1286 bool sec_split = pipe_ctx->top_pipe &&
1287 pipe_ctx->top_pipe->plane_state == pipe_ctx->plane_state;
1288 if (sec_split && plane_state->address.type == PLN_ADDR_TYPE_GRPH_STEREO &&
1289 (pipe_ctx->stream->timing.timing_3d_format ==
1290 TIMING_3D_FORMAT_SIDE_BY_SIDE ||
1291 pipe_ctx->stream->timing.timing_3d_format ==
1292 TIMING_3D_FORMAT_TOP_AND_BOTTOM)) {
1293 *addr = plane_state->address.grph_stereo.left_addr;
1294 plane_state->address.grph_stereo.left_addr =
1295 plane_state->address.grph_stereo.right_addr;
1298 if (pipe_ctx->stream->view_format != VIEW_3D_FORMAT_NONE &&
1299 plane_state->address.type != PLN_ADDR_TYPE_GRPH_STEREO) {
1300 plane_state->address.type = PLN_ADDR_TYPE_GRPH_STEREO;
1301 plane_state->address.grph_stereo.right_addr =
1302 plane_state->address.grph_stereo.left_addr;
1308 static void toggle_watermark_change_req(struct dce_hwseq *hws)
1310 uint32_t watermark_change_req;
1312 REG_GET(DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL,
1313 DCHUBBUB_ARB_WATERMARK_CHANGE_REQUEST, &watermark_change_req);
1315 if (watermark_change_req)
1316 watermark_change_req = 0;
1318 watermark_change_req = 1;
1320 REG_UPDATE(DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL,
1321 DCHUBBUB_ARB_WATERMARK_CHANGE_REQUEST, watermark_change_req);
1324 static void dcn10_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx)
1326 bool addr_patched = false;
1327 PHYSICAL_ADDRESS_LOC addr;
1328 struct dc_plane_state *plane_state = pipe_ctx->plane_state;
1330 if (plane_state == NULL)
1332 addr_patched = patch_address_for_sbs_tb_stereo(pipe_ctx, &addr);
1333 pipe_ctx->plane_res.mi->funcs->mem_input_program_surface_flip_and_addr(
1334 pipe_ctx->plane_res.mi,
1335 &plane_state->address,
1336 plane_state->flip_immediate);
1337 plane_state->status.requested_address = plane_state->address;
1339 pipe_ctx->plane_state->address.grph_stereo.left_addr = addr;
1342 static bool dcn10_set_input_transfer_func(
1343 struct pipe_ctx *pipe_ctx, const struct dc_plane_state *plane_state)
1345 struct transform *xfm_base = pipe_ctx->plane_res.xfm;
1346 const struct dc_transfer_func *tf = NULL;
1349 if (xfm_base == NULL)
1352 if (plane_state->in_transfer_func)
1353 tf = plane_state->in_transfer_func;
1355 if (plane_state->gamma_correction && dce_use_lut(plane_state))
1356 xfm_base->funcs->ipp_program_input_lut(xfm_base,
1357 plane_state->gamma_correction);
1360 xfm_base->funcs->ipp_set_degamma(xfm_base, IPP_DEGAMMA_MODE_BYPASS);
1361 else if (tf->type == TF_TYPE_PREDEFINED) {
1363 case TRANSFER_FUNCTION_SRGB:
1364 xfm_base->funcs->ipp_set_degamma(xfm_base,
1365 IPP_DEGAMMA_MODE_HW_sRGB);
1367 case TRANSFER_FUNCTION_BT709:
1368 xfm_base->funcs->ipp_set_degamma(xfm_base,
1369 IPP_DEGAMMA_MODE_HW_xvYCC);
1371 case TRANSFER_FUNCTION_LINEAR:
1372 xfm_base->funcs->ipp_set_degamma(xfm_base,
1373 IPP_DEGAMMA_MODE_BYPASS);
1375 case TRANSFER_FUNCTION_PQ:
1382 } else if (tf->type == TF_TYPE_BYPASS) {
1383 xfm_base->funcs->ipp_set_degamma(xfm_base, IPP_DEGAMMA_MODE_BYPASS);
1385 /*TF_TYPE_DISTRIBUTED_POINTS*/
1391 /*modify the method to handle rgb for arr_points*/
1392 static bool convert_to_custom_float(
1393 struct pwl_result_data *rgb_resulted,
1394 struct curve_points *arr_points,
1395 uint32_t hw_points_num)
1397 struct custom_float_format fmt;
1399 struct pwl_result_data *rgb = rgb_resulted;
1403 fmt.exponenta_bits = 6;
1404 fmt.mantissa_bits = 12;
1407 if (!convert_to_custom_float_format(
1410 &arr_points[0].custom_float_x)) {
1411 BREAK_TO_DEBUGGER();
1415 if (!convert_to_custom_float_format(
1416 arr_points[0].offset,
1418 &arr_points[0].custom_float_offset)) {
1419 BREAK_TO_DEBUGGER();
1423 if (!convert_to_custom_float_format(
1424 arr_points[0].slope,
1426 &arr_points[0].custom_float_slope)) {
1427 BREAK_TO_DEBUGGER();
1431 fmt.mantissa_bits = 10;
1434 if (!convert_to_custom_float_format(
1437 &arr_points[1].custom_float_x)) {
1438 BREAK_TO_DEBUGGER();
1442 if (!convert_to_custom_float_format(
1445 &arr_points[1].custom_float_y)) {
1446 BREAK_TO_DEBUGGER();
1450 if (!convert_to_custom_float_format(
1451 arr_points[1].slope,
1453 &arr_points[1].custom_float_slope)) {
1454 BREAK_TO_DEBUGGER();
1458 fmt.mantissa_bits = 12;
1461 while (i != hw_points_num) {
1462 if (!convert_to_custom_float_format(
1466 BREAK_TO_DEBUGGER();
1470 if (!convert_to_custom_float_format(
1474 BREAK_TO_DEBUGGER();
1478 if (!convert_to_custom_float_format(
1482 BREAK_TO_DEBUGGER();
1486 if (!convert_to_custom_float_format(
1489 &rgb->delta_red_reg)) {
1490 BREAK_TO_DEBUGGER();
1494 if (!convert_to_custom_float_format(
1497 &rgb->delta_green_reg)) {
1498 BREAK_TO_DEBUGGER();
1502 if (!convert_to_custom_float_format(
1505 &rgb->delta_blue_reg)) {
1506 BREAK_TO_DEBUGGER();
1516 #define MAX_REGIONS_NUMBER 34
1517 #define MAX_LOW_POINT 25
1518 #define NUMBER_SEGMENTS 32
1520 static bool dcn10_translate_regamma_to_hw_format(const struct dc_transfer_func
1521 *output_tf, struct pwl_params *regamma_params)
1523 struct curve_points *arr_points;
1524 struct pwl_result_data *rgb_resulted;
1525 struct pwl_result_data *rgb;
1526 struct pwl_result_data *rgb_plus_1;
1527 struct fixed31_32 y_r;
1528 struct fixed31_32 y_g;
1529 struct fixed31_32 y_b;
1530 struct fixed31_32 y1_min;
1531 struct fixed31_32 y3_max;
1533 int32_t segment_start, segment_end;
1535 uint32_t j, k, seg_distr[MAX_REGIONS_NUMBER], increment, start_index, hw_points;
1537 if (output_tf == NULL || regamma_params == NULL ||
1538 output_tf->type == TF_TYPE_BYPASS)
1541 arr_points = regamma_params->arr_points;
1542 rgb_resulted = regamma_params->rgb_resulted;
1545 memset(regamma_params, 0, sizeof(struct pwl_params));
1546 memset(seg_distr, 0, sizeof(seg_distr));
1548 if (output_tf->tf == TRANSFER_FUNCTION_PQ) {
1550 * segments are from 2^-25 to 2^7
1552 for (i = 0; i < 32 ; i++)
1555 segment_start = -25;
1559 * segment is from 2^-10 to 2^0
1560 * There are less than 256 points, for optimization
1573 segment_start = -10;
1577 for (i = segment_end - segment_start; i < MAX_REGIONS_NUMBER ; i++)
1580 for (k = 0; k < MAX_REGIONS_NUMBER; k++) {
1581 if (seg_distr[k] != -1)
1582 hw_points += (1 << seg_distr[k]);
1586 for (k = 0; k < (segment_end - segment_start); k++) {
1587 increment = NUMBER_SEGMENTS / (1 << seg_distr[k]);
1588 start_index = (segment_start + k + MAX_LOW_POINT) * NUMBER_SEGMENTS;
1589 for (i = start_index; i < start_index + NUMBER_SEGMENTS; i += increment) {
1590 if (j == hw_points - 1)
1592 rgb_resulted[j].red = output_tf->tf_pts.red[i];
1593 rgb_resulted[j].green = output_tf->tf_pts.green[i];
1594 rgb_resulted[j].blue = output_tf->tf_pts.blue[i];
1600 start_index = (segment_end + MAX_LOW_POINT) * NUMBER_SEGMENTS;
1601 rgb_resulted[hw_points - 1].red =
1602 output_tf->tf_pts.red[start_index];
1603 rgb_resulted[hw_points - 1].green =
1604 output_tf->tf_pts.green[start_index];
1605 rgb_resulted[hw_points - 1].blue =
1606 output_tf->tf_pts.blue[start_index];
1608 arr_points[0].x = dal_fixed31_32_pow(dal_fixed31_32_from_int(2),
1609 dal_fixed31_32_from_int(segment_start));
1610 arr_points[1].x = dal_fixed31_32_pow(dal_fixed31_32_from_int(2),
1611 dal_fixed31_32_from_int(segment_end));
1612 arr_points[2].x = dal_fixed31_32_pow(dal_fixed31_32_from_int(2),
1613 dal_fixed31_32_from_int(segment_end));
1615 y_r = rgb_resulted[0].red;
1616 y_g = rgb_resulted[0].green;
1617 y_b = rgb_resulted[0].blue;
1619 y1_min = dal_fixed31_32_min(y_r, dal_fixed31_32_min(y_g, y_b));
1621 arr_points[0].y = y1_min;
1622 arr_points[0].slope = dal_fixed31_32_div(
1625 y_r = rgb_resulted[hw_points - 1].red;
1626 y_g = rgb_resulted[hw_points - 1].green;
1627 y_b = rgb_resulted[hw_points - 1].blue;
1629 /* see comment above, m_arrPoints[1].y should be the Y value for the
1630 * region end (m_numOfHwPoints), not last HW point(m_numOfHwPoints - 1)
1632 y3_max = dal_fixed31_32_max(y_r, dal_fixed31_32_max(y_g, y_b));
1634 arr_points[1].y = y3_max;
1635 arr_points[2].y = y3_max;
1637 arr_points[1].slope = dal_fixed31_32_zero;
1638 arr_points[2].slope = dal_fixed31_32_zero;
1640 if (output_tf->tf == TRANSFER_FUNCTION_PQ) {
1641 /* for PQ, we want to have a straight line from last HW X point,
1642 * and the slope to be such that we hit 1.0 at 10000 nits.
1644 const struct fixed31_32 end_value =
1645 dal_fixed31_32_from_int(125);
1647 arr_points[1].slope = dal_fixed31_32_div(
1648 dal_fixed31_32_sub(dal_fixed31_32_one, arr_points[1].y),
1649 dal_fixed31_32_sub(end_value, arr_points[1].x));
1650 arr_points[2].slope = dal_fixed31_32_div(
1651 dal_fixed31_32_sub(dal_fixed31_32_one, arr_points[1].y),
1652 dal_fixed31_32_sub(end_value, arr_points[1].x));
1655 regamma_params->hw_points_num = hw_points;
1658 for (k = 0; k < MAX_REGIONS_NUMBER && i < MAX_REGIONS_NUMBER; k++) {
1659 if (seg_distr[k] != -1) {
1660 regamma_params->arr_curve_points[k].segments_num =
1662 regamma_params->arr_curve_points[i].offset =
1663 regamma_params->arr_curve_points[k].
1664 offset + (1 << seg_distr[k]);
1669 if (seg_distr[k] != -1)
1670 regamma_params->arr_curve_points[k].segments_num =
1674 rgb_plus_1 = rgb_resulted + 1;
1678 while (i != hw_points + 1) {
1679 if (dal_fixed31_32_lt(rgb_plus_1->red, rgb->red))
1680 rgb_plus_1->red = rgb->red;
1681 if (dal_fixed31_32_lt(rgb_plus_1->green, rgb->green))
1682 rgb_plus_1->green = rgb->green;
1683 if (dal_fixed31_32_lt(rgb_plus_1->blue, rgb->blue))
1684 rgb_plus_1->blue = rgb->blue;
1686 rgb->delta_red = dal_fixed31_32_sub(
1689 rgb->delta_green = dal_fixed31_32_sub(
1692 rgb->delta_blue = dal_fixed31_32_sub(
1701 convert_to_custom_float(rgb_resulted, arr_points, hw_points);
1706 static bool dcn10_set_output_transfer_func(
1707 struct pipe_ctx *pipe_ctx,
1708 const struct dc_stream_state *stream)
1710 struct transform *xfm = pipe_ctx->plane_res.xfm;
1715 xfm->regamma_params.hw_points_num = GAMMA_HW_POINTS_NUM;
1717 if (stream->out_transfer_func &&
1718 stream->out_transfer_func->type ==
1719 TF_TYPE_PREDEFINED &&
1720 stream->out_transfer_func->tf ==
1721 TRANSFER_FUNCTION_SRGB) {
1722 xfm->funcs->opp_set_regamma_mode(xfm, OPP_REGAMMA_SRGB);
1723 } else if (dcn10_translate_regamma_to_hw_format(
1724 stream->out_transfer_func, &xfm->regamma_params)) {
1725 xfm->funcs->opp_program_regamma_pwl(xfm, &xfm->regamma_params);
1726 xfm->funcs->opp_set_regamma_mode(xfm, OPP_REGAMMA_USER);
1728 xfm->funcs->opp_set_regamma_mode(xfm, OPP_REGAMMA_BYPASS);
1734 static void dcn10_pipe_control_lock(
1736 struct pipe_ctx *pipe,
1739 struct mem_input *mi = NULL;
1740 mi = dc->res_pool->mis[pipe->pipe_idx];
1741 /* use TG master update lock to lock everything on the TG
1742 * therefore only top pipe need to lock
1747 if (dc->debug.sanity_checks)
1748 verify_allow_pstate_change_high(dc->hwseq);
1751 pipe->stream_res.tg->funcs->lock(pipe->stream_res.tg);
1753 pipe->stream_res.tg->funcs->unlock(pipe->stream_res.tg);
1755 if (dc->debug.sanity_checks)
1756 verify_allow_pstate_change_high(dc->hwseq);
1759 static bool wait_for_reset_trigger_to_occur(
1760 struct dc_context *dc_ctx,
1761 struct timing_generator *tg)
1765 /* To avoid endless loop we wait at most
1766 * frames_to_wait_on_triggered_reset frames for the reset to occur. */
1767 const uint32_t frames_to_wait_on_triggered_reset = 10;
1770 for (i = 0; i < frames_to_wait_on_triggered_reset; i++) {
1772 if (!tg->funcs->is_counter_moving(tg)) {
1773 DC_ERROR("TG counter is not moving!\n");
1777 if (tg->funcs->did_triggered_reset_occur(tg)) {
1779 /* usually occurs at i=1 */
1780 DC_SYNC_INFO("GSL: reset occurred at wait count: %d\n",
1785 /* Wait for one frame. */
1786 tg->funcs->wait_for_state(tg, CRTC_STATE_VACTIVE);
1787 tg->funcs->wait_for_state(tg, CRTC_STATE_VBLANK);
1791 DC_ERROR("GSL: Timeout on reset trigger!\n");
1796 static void dcn10_enable_timing_synchronization(
1800 struct pipe_ctx *grouped_pipes[])
1802 struct dc_context *dc_ctx = dc->ctx;
1805 DC_SYNC_INFO("Setting up OTG reset trigger\n");
1807 for (i = 1; i < group_size; i++)
1808 grouped_pipes[i]->stream_res.tg->funcs->enable_reset_trigger(
1809 grouped_pipes[i]->stream_res.tg, grouped_pipes[0]->stream_res.tg->inst);
1812 DC_SYNC_INFO("Waiting for trigger\n");
1814 /* Need to get only check 1 pipe for having reset as all the others are
1815 * synchronized. Look at last pipe programmed to reset.
1817 wait_for_reset_trigger_to_occur(dc_ctx, grouped_pipes[1]->stream_res.tg);
1818 for (i = 1; i < group_size; i++)
1819 grouped_pipes[i]->stream_res.tg->funcs->disable_reset_trigger(
1820 grouped_pipes[i]->stream_res.tg);
1822 DC_SYNC_INFO("Sync complete\n");
1825 static void print_rq_dlg_ttu(
1827 struct pipe_ctx *pipe_ctx)
1829 dm_logger_write(core_dc->ctx->logger, LOG_BANDWIDTH_CALCS,
1830 "\n============== DML TTU Output parameters [%d] ==============\n"
1831 "qos_level_low_wm: %d, \n"
1832 "qos_level_high_wm: %d, \n"
1833 "min_ttu_vblank: %d, \n"
1834 "qos_level_flip: %d, \n"
1835 "refcyc_per_req_delivery_l: %d, \n"
1836 "qos_level_fixed_l: %d, \n"
1837 "qos_ramp_disable_l: %d, \n"
1838 "refcyc_per_req_delivery_pre_l: %d, \n"
1839 "refcyc_per_req_delivery_c: %d, \n"
1840 "qos_level_fixed_c: %d, \n"
1841 "qos_ramp_disable_c: %d, \n"
1842 "refcyc_per_req_delivery_pre_c: %d\n"
1843 "=============================================================\n",
1845 pipe_ctx->ttu_regs.qos_level_low_wm,
1846 pipe_ctx->ttu_regs.qos_level_high_wm,
1847 pipe_ctx->ttu_regs.min_ttu_vblank,
1848 pipe_ctx->ttu_regs.qos_level_flip,
1849 pipe_ctx->ttu_regs.refcyc_per_req_delivery_l,
1850 pipe_ctx->ttu_regs.qos_level_fixed_l,
1851 pipe_ctx->ttu_regs.qos_ramp_disable_l,
1852 pipe_ctx->ttu_regs.refcyc_per_req_delivery_pre_l,
1853 pipe_ctx->ttu_regs.refcyc_per_req_delivery_c,
1854 pipe_ctx->ttu_regs.qos_level_fixed_c,
1855 pipe_ctx->ttu_regs.qos_ramp_disable_c,
1856 pipe_ctx->ttu_regs.refcyc_per_req_delivery_pre_c
1859 dm_logger_write(core_dc->ctx->logger, LOG_BANDWIDTH_CALCS,
1860 "\n============== DML DLG Output parameters [%d] ==============\n"
1861 "refcyc_h_blank_end: %d, \n"
1862 "dlg_vblank_end: %d, \n"
1863 "min_dst_y_next_start: %d, \n"
1864 "refcyc_per_htotal: %d, \n"
1865 "refcyc_x_after_scaler: %d, \n"
1866 "dst_y_after_scaler: %d, \n"
1867 "dst_y_prefetch: %d, \n"
1868 "dst_y_per_vm_vblank: %d, \n"
1869 "dst_y_per_row_vblank: %d, \n"
1870 "ref_freq_to_pix_freq: %d, \n"
1871 "vratio_prefetch: %d, \n"
1872 "refcyc_per_pte_group_vblank_l: %d, \n"
1873 "refcyc_per_meta_chunk_vblank_l: %d, \n"
1874 "dst_y_per_pte_row_nom_l: %d, \n"
1875 "refcyc_per_pte_group_nom_l: %d, \n",
1877 pipe_ctx->dlg_regs.refcyc_h_blank_end,
1878 pipe_ctx->dlg_regs.dlg_vblank_end,
1879 pipe_ctx->dlg_regs.min_dst_y_next_start,
1880 pipe_ctx->dlg_regs.refcyc_per_htotal,
1881 pipe_ctx->dlg_regs.refcyc_x_after_scaler,
1882 pipe_ctx->dlg_regs.dst_y_after_scaler,
1883 pipe_ctx->dlg_regs.dst_y_prefetch,
1884 pipe_ctx->dlg_regs.dst_y_per_vm_vblank,
1885 pipe_ctx->dlg_regs.dst_y_per_row_vblank,
1886 pipe_ctx->dlg_regs.ref_freq_to_pix_freq,
1887 pipe_ctx->dlg_regs.vratio_prefetch,
1888 pipe_ctx->dlg_regs.refcyc_per_pte_group_vblank_l,
1889 pipe_ctx->dlg_regs.refcyc_per_meta_chunk_vblank_l,
1890 pipe_ctx->dlg_regs.dst_y_per_pte_row_nom_l,
1891 pipe_ctx->dlg_regs.refcyc_per_pte_group_nom_l
1894 dm_logger_write(core_dc->ctx->logger, LOG_BANDWIDTH_CALCS,
1895 "\ndst_y_per_meta_row_nom_l: %d, \n"
1896 "refcyc_per_meta_chunk_nom_l: %d, \n"
1897 "refcyc_per_line_delivery_pre_l: %d, \n"
1898 "refcyc_per_line_delivery_l: %d, \n"
1899 "vratio_prefetch_c: %d, \n"
1900 "refcyc_per_pte_group_vblank_c: %d, \n"
1901 "refcyc_per_meta_chunk_vblank_c: %d, \n"
1902 "dst_y_per_pte_row_nom_c: %d, \n"
1903 "refcyc_per_pte_group_nom_c: %d, \n"
1904 "dst_y_per_meta_row_nom_c: %d, \n"
1905 "refcyc_per_meta_chunk_nom_c: %d, \n"
1906 "refcyc_per_line_delivery_pre_c: %d, \n"
1907 "refcyc_per_line_delivery_c: %d \n"
1908 "========================================================\n",
1909 pipe_ctx->dlg_regs.dst_y_per_meta_row_nom_l,
1910 pipe_ctx->dlg_regs.refcyc_per_meta_chunk_nom_l,
1911 pipe_ctx->dlg_regs.refcyc_per_line_delivery_pre_l,
1912 pipe_ctx->dlg_regs.refcyc_per_line_delivery_l,
1913 pipe_ctx->dlg_regs.vratio_prefetch_c,
1914 pipe_ctx->dlg_regs.refcyc_per_pte_group_vblank_c,
1915 pipe_ctx->dlg_regs.refcyc_per_meta_chunk_vblank_c,
1916 pipe_ctx->dlg_regs.dst_y_per_pte_row_nom_c,
1917 pipe_ctx->dlg_regs.refcyc_per_pte_group_nom_c,
1918 pipe_ctx->dlg_regs.dst_y_per_meta_row_nom_c,
1919 pipe_ctx->dlg_regs.refcyc_per_meta_chunk_nom_c,
1920 pipe_ctx->dlg_regs.refcyc_per_line_delivery_pre_c,
1921 pipe_ctx->dlg_regs.refcyc_per_line_delivery_c
1924 dm_logger_write(core_dc->ctx->logger, LOG_BANDWIDTH_CALCS,
1925 "\n============== DML RQ Output parameters [%d] ==============\n"
1927 "min_chunk_size: %d \n"
1928 "meta_chunk_size: %d \n"
1929 "min_meta_chunk_size: %d \n"
1930 "dpte_group_size: %d \n"
1931 "mpte_group_size: %d \n"
1932 "swath_height: %d \n"
1933 "pte_row_height_linear: %d \n"
1934 "========================================================\n",
1936 pipe_ctx->rq_regs.rq_regs_l.chunk_size,
1937 pipe_ctx->rq_regs.rq_regs_l.min_chunk_size,
1938 pipe_ctx->rq_regs.rq_regs_l.meta_chunk_size,
1939 pipe_ctx->rq_regs.rq_regs_l.min_meta_chunk_size,
1940 pipe_ctx->rq_regs.rq_regs_l.dpte_group_size,
1941 pipe_ctx->rq_regs.rq_regs_l.mpte_group_size,
1942 pipe_ctx->rq_regs.rq_regs_l.swath_height,
1943 pipe_ctx->rq_regs.rq_regs_l.pte_row_height_linear
1947 static void dcn10_power_on_fe(
1949 struct pipe_ctx *pipe_ctx,
1950 struct dc_state *context)
1952 struct dc_plane_state *plane_state = pipe_ctx->plane_state;
1953 struct dce_hwseq *hws = dc->hwseq;
1955 if (dc->debug.sanity_checks) {
1956 verify_allow_pstate_change_high(dc->hwseq);
1959 power_on_plane(dc->hwseq,
1960 pipe_ctx->pipe_idx);
1962 /* enable DCFCLK current DCHUB */
1963 REG_UPDATE(HUBP_CLK_CNTL[pipe_ctx->pipe_idx],
1964 HUBP_CLOCK_ENABLE, 1);
1966 /* make sure OPP_PIPE_CLOCK_EN = 1 */
1967 REG_UPDATE(OPP_PIPE_CONTROL[pipe_ctx->stream_res.tg->inst],
1968 OPP_PIPE_CLOCK_EN, 1);
1969 /*TODO: REG_UPDATE(DENTIST_DISPCLK_CNTL, DENTIST_DPPCLK_WDIVIDER, 0x1f);*/
1972 dm_logger_write(dc->ctx->logger, LOG_DC,
1973 "Pipe:%d 0x%x: addr hi:0x%x, "
1976 " %d; dst: %d, %d, %d, %d;\n",
1979 plane_state->address.grph.addr.high_part,
1980 plane_state->address.grph.addr.low_part,
1981 plane_state->src_rect.x,
1982 plane_state->src_rect.y,
1983 plane_state->src_rect.width,
1984 plane_state->src_rect.height,
1985 plane_state->dst_rect.x,
1986 plane_state->dst_rect.y,
1987 plane_state->dst_rect.width,
1988 plane_state->dst_rect.height);
1990 dm_logger_write(dc->ctx->logger, LOG_DC,
1991 "Pipe %d: width, height, x, y\n"
1992 "viewport:%d, %d, %d, %d\n"
1993 "recout: %d, %d, %d, %d\n",
1995 pipe_ctx->plane_res.scl_data.viewport.width,
1996 pipe_ctx->plane_res.scl_data.viewport.height,
1997 pipe_ctx->plane_res.scl_data.viewport.x,
1998 pipe_ctx->plane_res.scl_data.viewport.y,
1999 pipe_ctx->plane_res.scl_data.recout.width,
2000 pipe_ctx->plane_res.scl_data.recout.height,
2001 pipe_ctx->plane_res.scl_data.recout.x,
2002 pipe_ctx->plane_res.scl_data.recout.y);
2003 print_rq_dlg_ttu(dc, pipe_ctx);
2006 if (dc->debug.sanity_checks) {
2007 verify_allow_pstate_change_high(dc->hwseq);
2011 static void program_gamut_remap(struct pipe_ctx *pipe_ctx)
2013 struct xfm_grph_csc_adjustment adjust;
2014 memset(&adjust, 0, sizeof(adjust));
2015 adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS;
2018 if (pipe_ctx->stream->gamut_remap_matrix.enable_remap == true) {
2019 adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW;
2020 adjust.temperature_matrix[0] =
2022 gamut_remap_matrix.matrix[0];
2023 adjust.temperature_matrix[1] =
2025 gamut_remap_matrix.matrix[1];
2026 adjust.temperature_matrix[2] =
2028 gamut_remap_matrix.matrix[2];
2029 adjust.temperature_matrix[3] =
2031 gamut_remap_matrix.matrix[4];
2032 adjust.temperature_matrix[4] =
2034 gamut_remap_matrix.matrix[5];
2035 adjust.temperature_matrix[5] =
2037 gamut_remap_matrix.matrix[6];
2038 adjust.temperature_matrix[6] =
2040 gamut_remap_matrix.matrix[8];
2041 adjust.temperature_matrix[7] =
2043 gamut_remap_matrix.matrix[9];
2044 adjust.temperature_matrix[8] =
2046 gamut_remap_matrix.matrix[10];
2049 pipe_ctx->plane_res.xfm->funcs->transform_set_gamut_remap(pipe_ctx->plane_res.xfm, &adjust);
2053 static void program_csc_matrix(struct pipe_ctx *pipe_ctx,
2054 enum dc_color_space colorspace,
2058 struct out_csc_color_matrix tbl_entry;
2060 if (pipe_ctx->stream->csc_color_matrix.enable_adjustment
2062 enum dc_color_space color_space =
2063 pipe_ctx->stream->output_color_space;
2065 //uint16_t matrix[12];
2066 for (i = 0; i < 12; i++)
2067 tbl_entry.regval[i] = pipe_ctx->stream->csc_color_matrix.matrix[i];
2069 tbl_entry.color_space = color_space;
2070 //tbl_entry.regval = matrix;
2071 pipe_ctx->plane_res.xfm->funcs->opp_set_csc_adjustment(pipe_ctx->plane_res.xfm, &tbl_entry);
2074 static bool is_lower_pipe_tree_visible(struct pipe_ctx *pipe_ctx)
2076 if (pipe_ctx->plane_state->visible)
2078 if (pipe_ctx->bottom_pipe && is_lower_pipe_tree_visible(pipe_ctx->bottom_pipe))
2083 static bool is_upper_pipe_tree_visible(struct pipe_ctx *pipe_ctx)
2085 if (pipe_ctx->plane_state->visible)
2087 if (pipe_ctx->top_pipe && is_upper_pipe_tree_visible(pipe_ctx->top_pipe))
2092 static bool is_pipe_tree_visible(struct pipe_ctx *pipe_ctx)
2094 if (pipe_ctx->plane_state->visible)
2096 if (pipe_ctx->top_pipe && is_upper_pipe_tree_visible(pipe_ctx->top_pipe))
2098 if (pipe_ctx->bottom_pipe && is_lower_pipe_tree_visible(pipe_ctx->bottom_pipe))
2103 static bool is_rgb_cspace(enum dc_color_space output_color_space)
2105 switch (output_color_space) {
2106 case COLOR_SPACE_SRGB:
2107 case COLOR_SPACE_SRGB_LIMITED:
2108 case COLOR_SPACE_2020_RGB_FULLRANGE:
2109 case COLOR_SPACE_2020_RGB_LIMITEDRANGE:
2110 case COLOR_SPACE_ADOBERGB:
2112 case COLOR_SPACE_YCBCR601:
2113 case COLOR_SPACE_YCBCR709:
2114 case COLOR_SPACE_YCBCR601_LIMITED:
2115 case COLOR_SPACE_YCBCR709_LIMITED:
2116 case COLOR_SPACE_2020_YCBCR:
2119 /* Add a case to switch */
2120 BREAK_TO_DEBUGGER();
2125 static void dcn10_get_surface_visual_confirm_color(
2126 const struct pipe_ctx *pipe_ctx,
2127 struct tg_color *color)
2129 uint32_t color_value = MAX_TG_COLOR_VALUE;
2131 switch (pipe_ctx->plane_res.scl_data.format) {
2132 case PIXEL_FORMAT_ARGB8888:
2133 /* set boarder color to red */
2134 color->color_r_cr = color_value;
2137 case PIXEL_FORMAT_ARGB2101010:
2138 /* set boarder color to blue */
2139 color->color_b_cb = color_value;
2141 case PIXEL_FORMAT_420BPP8:
2142 /* set boarder color to green */
2143 color->color_g_y = color_value;
2145 case PIXEL_FORMAT_420BPP10:
2146 /* set boarder color to yellow */
2147 color->color_g_y = color_value;
2148 color->color_r_cr = color_value;
2150 case PIXEL_FORMAT_FP16:
2151 /* set boarder color to white */
2152 color->color_r_cr = color_value;
2153 color->color_b_cb = color_value;
2154 color->color_g_y = color_value;
2161 static void mmhub_read_vm_system_aperture_settings(struct dcn10_mem_input *mi,
2162 struct vm_system_aperture_param *apt,
2163 struct dce_hwseq *hws)
2165 PHYSICAL_ADDRESS_LOC physical_page_number;
2166 uint32_t logical_addr_low;
2167 uint32_t logical_addr_high;
2169 REG_GET(MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB,
2170 PHYSICAL_PAGE_NUMBER_MSB, &physical_page_number.high_part);
2171 REG_GET(MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB,
2172 PHYSICAL_PAGE_NUMBER_LSB, &physical_page_number.low_part);
2174 REG_GET(MC_VM_SYSTEM_APERTURE_LOW_ADDR,
2175 LOGICAL_ADDR, &logical_addr_low);
2177 REG_GET(MC_VM_SYSTEM_APERTURE_HIGH_ADDR,
2178 LOGICAL_ADDR, &logical_addr_high);
2180 apt->sys_default.quad_part = physical_page_number.quad_part << 12;
2181 apt->sys_low.quad_part = (int64_t)logical_addr_low << 18;
2182 apt->sys_high.quad_part = (int64_t)logical_addr_high << 18;
2185 /* Temporary read settings, future will get values from kmd directly */
2186 static void mmhub_read_vm_context0_settings(struct dcn10_mem_input *mi,
2187 struct vm_context0_param *vm0,
2188 struct dce_hwseq *hws)
2190 PHYSICAL_ADDRESS_LOC fb_base;
2191 PHYSICAL_ADDRESS_LOC fb_offset;
2192 uint32_t fb_base_value;
2193 uint32_t fb_offset_value;
2195 REG_GET(DCHUBBUB_SDPIF_FB_BASE, SDPIF_FB_BASE, &fb_base_value);
2196 REG_GET(DCHUBBUB_SDPIF_FB_OFFSET, SDPIF_FB_OFFSET, &fb_offset_value);
2198 REG_GET(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32,
2199 PAGE_DIRECTORY_ENTRY_HI32, &vm0->pte_base.high_part);
2200 REG_GET(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LO32,
2201 PAGE_DIRECTORY_ENTRY_LO32, &vm0->pte_base.low_part);
2203 REG_GET(VM_CONTEXT0_PAGE_TABLE_START_ADDR_HI32,
2204 LOGICAL_PAGE_NUMBER_HI4, &vm0->pte_start.high_part);
2205 REG_GET(VM_CONTEXT0_PAGE_TABLE_START_ADDR_LO32,
2206 LOGICAL_PAGE_NUMBER_LO32, &vm0->pte_start.low_part);
2208 REG_GET(VM_CONTEXT0_PAGE_TABLE_END_ADDR_HI32,
2209 LOGICAL_PAGE_NUMBER_HI4, &vm0->pte_end.high_part);
2210 REG_GET(VM_CONTEXT0_PAGE_TABLE_END_ADDR_LO32,
2211 LOGICAL_PAGE_NUMBER_LO32, &vm0->pte_end.low_part);
2213 REG_GET(VM_L2_PROTECTION_FAULT_DEFAULT_ADDR_HI32,
2214 PHYSICAL_PAGE_ADDR_HI4, &vm0->fault_default.high_part);
2215 REG_GET(VM_L2_PROTECTION_FAULT_DEFAULT_ADDR_LO32,
2216 PHYSICAL_PAGE_ADDR_LO32, &vm0->fault_default.low_part);
2219 * The values in VM_CONTEXT0_PAGE_TABLE_BASE_ADDR is in UMA space.
2220 * Therefore we need to do
2221 * DCN_VM_CONTEXT0_PAGE_TABLE_BASE_ADDR = VM_CONTEXT0_PAGE_TABLE_BASE_ADDR
2222 * - DCHUBBUB_SDPIF_FB_OFFSET + DCHUBBUB_SDPIF_FB_BASE
2224 fb_base.quad_part = (uint64_t)fb_base_value << 24;
2225 fb_offset.quad_part = (uint64_t)fb_offset_value << 24;
2226 vm0->pte_base.quad_part += fb_base.quad_part;
2227 vm0->pte_base.quad_part -= fb_offset.quad_part;
2230 static void dcn10_program_pte_vm(struct mem_input *mem_input,
2231 enum surface_pixel_format format,
2232 union dc_tiling_info *tiling_info,
2233 enum dc_rotation_angle rotation,
2234 struct dce_hwseq *hws)
2236 struct dcn10_mem_input *mi = TO_DCN10_MEM_INPUT(mem_input);
2237 struct vm_system_aperture_param apt = { {{ 0 } } };
2238 struct vm_context0_param vm0 = { { { 0 } } };
2241 mmhub_read_vm_system_aperture_settings(mi, &apt, hws);
2242 mmhub_read_vm_context0_settings(mi, &vm0, hws);
2244 mem_input->funcs->mem_input_set_vm_system_aperture_settings(mem_input, &apt);
2245 mem_input->funcs->mem_input_set_vm_context0_settings(mem_input, &vm0);
2248 static void update_dchubp_dpp(
2250 struct pipe_ctx *pipe_ctx,
2251 struct dc_state *context)
2253 struct dce_hwseq *hws = dc->hwseq;
2254 struct mem_input *mi = pipe_ctx->plane_res.mi;
2255 struct transform *xfm = pipe_ctx->plane_res.xfm;
2256 struct dc_plane_state *plane_state = pipe_ctx->plane_state;
2257 union plane_size size = plane_state->plane_size;
2258 struct default_adjustment ocsc = {0};
2259 struct mpcc_cfg mpcc_cfg = {0};
2260 struct pipe_ctx *top_pipe;
2261 bool per_pixel_alpha = plane_state->per_pixel_alpha && pipe_ctx->bottom_pipe;
2263 /* TODO: proper fix once fpga works */
2264 /* depends on DML calculation, DPP clock value may change dynamically */
2268 pipe_ctx->stream_res.pix_clk_params.requested_pix_clk,
2269 context->bw.dcn.calc_clk.dppclk_div);
2270 dc->current_state->bw.dcn.cur_clk.dppclk_div =
2271 context->bw.dcn.calc_clk.dppclk_div;
2272 context->bw.dcn.cur_clk.dppclk_div = context->bw.dcn.calc_clk.dppclk_div;
2274 /* TODO: Need input parameter to tell current DCHUB pipe tie to which OTG
2275 * VTG is within DCHUBBUB which is commond block share by each pipe HUBP.
2276 * VTG is 1:1 mapping with OTG. Each pipe HUBP will select which VTG
2278 REG_UPDATE(DCHUBP_CNTL[pipe_ctx->pipe_idx], HUBP_VTG_SEL, pipe_ctx->stream_res.tg->inst);
2280 dc->hwss.update_plane_addr(dc, pipe_ctx);
2282 mi->funcs->mem_input_setup(
2284 &pipe_ctx->dlg_regs,
2285 &pipe_ctx->ttu_regs,
2287 &pipe_ctx->pipe_dlg_param);
2289 size.grph.surface_size = pipe_ctx->plane_res.scl_data.viewport;
2291 if (dc->config.gpu_vm_support)
2292 dcn10_program_pte_vm(
2293 pipe_ctx->plane_res.mi,
2294 plane_state->format,
2295 &plane_state->tiling_info,
2296 plane_state->rotation,
2300 xfm->funcs->ipp_setup(xfm,
2301 plane_state->format,
2302 EXPANSION_MODE_ZERO);
2304 mpcc_cfg.dpp_id = mi->inst;
2305 mpcc_cfg.opp_id = pipe_ctx->stream_res.opp->inst;
2306 mpcc_cfg.tree_cfg = &(pipe_ctx->stream_res.opp->mpc_tree);
2307 for (top_pipe = pipe_ctx->top_pipe; top_pipe; top_pipe = top_pipe->top_pipe)
2309 if (dc->debug.surface_visual_confirm)
2310 dcn10_get_surface_visual_confirm_color(
2311 pipe_ctx, &mpcc_cfg.black_color);
2313 color_space_to_black_color(
2314 dc, pipe_ctx->stream->output_color_space,
2315 &mpcc_cfg.black_color);
2316 mpcc_cfg.per_pixel_alpha = per_pixel_alpha;
2317 /* DCN1.0 has output CM before MPC which seems to screw with
2318 * pre-multiplied alpha.
2320 mpcc_cfg.pre_multiplied_alpha = is_rgb_cspace(
2321 pipe_ctx->stream->output_color_space)
2323 mi->mpcc_id = dc->res_pool->mpc->funcs->add(dc->res_pool->mpc, &mpcc_cfg);
2324 mi->opp_id = mpcc_cfg.opp_id;
2326 pipe_ctx->plane_res.scl_data.lb_params.alpha_en = per_pixel_alpha;
2327 pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_30BPP;
2328 /* scaler configuration */
2329 pipe_ctx->plane_res.xfm->funcs->transform_set_scaler(
2330 pipe_ctx->plane_res.xfm, &pipe_ctx->plane_res.scl_data);
2331 mi->funcs->mem_program_viewport(mi,
2332 &pipe_ctx->plane_res.scl_data.viewport, &pipe_ctx->plane_res.scl_data.viewport_c);
2335 program_gamut_remap(pipe_ctx);
2337 /*TODO add adjustments parameters*/
2338 ocsc.out_color_space = pipe_ctx->stream->output_color_space;
2339 pipe_ctx->plane_res.xfm->funcs->opp_set_csc_default(pipe_ctx->plane_res.xfm, &ocsc);
2341 mi->funcs->mem_input_program_surface_config(
2343 plane_state->format,
2344 &plane_state->tiling_info,
2346 plane_state->rotation,
2348 plane_state->horizontal_mirror);
2350 if (is_pipe_tree_visible(pipe_ctx))
2351 mi->funcs->set_blank(mi, false);
2355 static void program_all_pipe_in_tree(
2357 struct pipe_ctx *pipe_ctx,
2358 struct dc_state *context)
2360 unsigned int ref_clk_mhz = dc->res_pool->ref_clock_inKhz/1000;
2362 if (pipe_ctx->top_pipe == NULL) {
2364 /* lock otg_master_update to process all pipes associated with
2365 * this OTG. this is done only one time.
2367 /* watermark is for all pipes */
2368 program_watermarks(dc->hwseq, &context->bw.dcn.watermarks, ref_clk_mhz);
2370 if (dc->debug.sanity_checks) {
2371 /* pstate stuck check after watermark update */
2372 verify_allow_pstate_change_high(dc->hwseq);
2375 pipe_ctx->stream_res.tg->funcs->lock(pipe_ctx->stream_res.tg);
2377 pipe_ctx->stream_res.tg->dlg_otg_param.vready_offset = pipe_ctx->pipe_dlg_param.vready_offset;
2378 pipe_ctx->stream_res.tg->dlg_otg_param.vstartup_start = pipe_ctx->pipe_dlg_param.vstartup_start;
2379 pipe_ctx->stream_res.tg->dlg_otg_param.vupdate_offset = pipe_ctx->pipe_dlg_param.vupdate_offset;
2380 pipe_ctx->stream_res.tg->dlg_otg_param.vupdate_width = pipe_ctx->pipe_dlg_param.vupdate_width;
2381 pipe_ctx->stream_res.tg->dlg_otg_param.signal = pipe_ctx->stream->signal;
2383 pipe_ctx->stream_res.tg->funcs->program_global_sync(
2384 pipe_ctx->stream_res.tg);
2385 pipe_ctx->stream_res.tg->funcs->set_blank(pipe_ctx->stream_res.tg, !is_pipe_tree_visible(pipe_ctx));
2388 if (pipe_ctx->plane_state != NULL) {
2389 dcn10_power_on_fe(dc, pipe_ctx, context);
2391 /* temporary dcn1 wa:
2392 * watermark update requires toggle after a/b/c/d sets are programmed
2393 * if hubp is pg then wm value doesn't get properaged to hubp
2394 * need to toggle after ungate to ensure wm gets to hubp.
2396 * final solution: we need to get SMU to do the toggle as
2397 * DCHUBBUB_ARB_WATERMARK_CHANGE_REQUEST is owned by SMU we should have
2398 * both driver and fw accessing same register
2400 toggle_watermark_change_req(dc->hwseq);
2402 update_dchubp_dpp(dc, pipe_ctx, context);
2405 if (dc->debug.sanity_checks) {
2406 /* pstate stuck check after each pipe is programmed */
2407 verify_allow_pstate_change_high(dc->hwseq);
2410 if (pipe_ctx->bottom_pipe != NULL && pipe_ctx->bottom_pipe != pipe_ctx)
2411 program_all_pipe_in_tree(dc, pipe_ctx->bottom_pipe, context);
2414 static void dcn10_pplib_apply_display_requirements(
2416 struct dc_state *context)
2418 struct dm_pp_display_configuration *pp_display_cfg = &context->pp_display_cfg;
2420 pp_display_cfg->all_displays_in_sync = false;/*todo*/
2421 pp_display_cfg->nb_pstate_switch_disable = false;
2422 pp_display_cfg->min_engine_clock_khz = context->bw.dcn.cur_clk.dcfclk_khz;
2423 pp_display_cfg->min_memory_clock_khz = context->bw.dcn.cur_clk.fclk_khz;
2424 pp_display_cfg->min_engine_clock_deep_sleep_khz = context->bw.dcn.cur_clk.dcfclk_deep_sleep_khz;
2425 pp_display_cfg->min_dcfc_deep_sleep_clock_khz = context->bw.dcn.cur_clk.dcfclk_deep_sleep_khz;
2426 pp_display_cfg->avail_mclk_switch_time_us =
2427 context->bw.dcn.cur_clk.dram_ccm_us > 0 ? context->bw.dcn.cur_clk.dram_ccm_us : 0;
2428 pp_display_cfg->avail_mclk_switch_time_in_disp_active_us =
2429 context->bw.dcn.cur_clk.min_active_dram_ccm_us > 0 ? context->bw.dcn.cur_clk.min_active_dram_ccm_us : 0;
2430 pp_display_cfg->min_dcfclock_khz = context->bw.dcn.cur_clk.dcfclk_khz;
2431 pp_display_cfg->disp_clk_khz = context->bw.dcn.cur_clk.dispclk_khz;
2432 dce110_fill_display_configs(context, pp_display_cfg);
2434 if (memcmp(&dc->prev_display_config, pp_display_cfg, sizeof(
2435 struct dm_pp_display_configuration)) != 0)
2436 dm_pp_apply_display_requirements(dc->ctx, pp_display_cfg);
2438 dc->prev_display_config = *pp_display_cfg;
2441 static void optimize_shared_resources(struct dc *dc)
2443 if (dc->current_state->stream_count == 0) {
2444 apply_DEGVIDCN10_253_wa(dc);
2446 dcn10_pplib_apply_display_requirements(dc, dc->current_state);
2450 static void ready_shared_resources(struct dc *dc, struct dc_state *context)
2452 if (dc->current_state->stream_count == 0 &&
2453 !dc->debug.disable_stutter)
2454 undo_DEGVIDCN10_253_wa(dc);
2457 if (dc->current_state->stream_count == 0 &&
2458 context->stream_count != 0)
2459 dcn10_pplib_apply_display_requirements(dc, context);
2462 static void dcn10_apply_ctx_for_surface(
2464 const struct dc_stream_state *stream,
2466 struct dc_state *context)
2470 if (dc->debug.sanity_checks)
2471 verify_allow_pstate_change_high(dc->hwseq);
2474 for (i = 0; i < dc->res_pool->pipe_count; i++) {
2475 if (stream == context->res_ctx.pipe_ctx[i].stream) {
2476 be_idx = context->res_ctx.pipe_ctx[i].stream_res.tg->inst;
2481 ASSERT(be_idx != -1);
2483 if (num_planes == 0) {
2484 for (i = dc->res_pool->pipe_count - 1; i >= 0 ; i--) {
2485 struct pipe_ctx *old_pipe_ctx =
2486 &dc->current_state->res_ctx.pipe_ctx[i];
2488 if (old_pipe_ctx->stream_res.tg && old_pipe_ctx->stream_res.tg->inst == be_idx) {
2489 old_pipe_ctx->stream_res.tg->funcs->set_blank(old_pipe_ctx->stream_res.tg, true);
2490 dcn10_power_down_fe(dc, old_pipe_ctx->pipe_idx);
2496 /* reset unused mpcc */
2497 for (i = 0; i < dc->res_pool->pipe_count; i++) {
2498 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
2499 struct pipe_ctx *old_pipe_ctx =
2500 &dc->current_state->res_ctx.pipe_ctx[i];
2502 if (!pipe_ctx->plane_state && !old_pipe_ctx->plane_state)
2506 * Powergate reused pipes that are not powergated
2507 * fairly hacky right now, using opp_id as indicator
2510 if (pipe_ctx->plane_state && !old_pipe_ctx->plane_state) {
2511 if (pipe_ctx->plane_res.mi->opp_id != 0xf && pipe_ctx->stream_res.tg->inst == be_idx) {
2512 dcn10_power_down_fe(dc, pipe_ctx->pipe_idx);
2514 * power down fe will unlock when calling reset, need
2515 * to lock it back here. Messy, need rework.
2517 pipe_ctx->stream_res.tg->funcs->lock(pipe_ctx->stream_res.tg);
2522 if ((!pipe_ctx->plane_state && old_pipe_ctx->plane_state)
2523 || (!pipe_ctx->stream && old_pipe_ctx->stream)) {
2524 if (old_pipe_ctx->stream_res.tg->inst != be_idx)
2527 if (!old_pipe_ctx->top_pipe) {
2533 dc->res_pool->mpc->funcs->remove(
2535 &(old_pipe_ctx->stream_res.opp->mpc_tree),
2536 old_pipe_ctx->stream_res.opp->inst,
2537 old_pipe_ctx->pipe_idx);
2538 old_pipe_ctx->stream_res.opp->mpcc_disconnect_pending[old_pipe_ctx->plane_res.mi->mpcc_id] = true;
2540 /*dm_logger_write(dc->ctx->logger, LOG_ERROR,
2541 "[debug_mpo: apply_ctx disconnect pending on mpcc %d]\n",
2542 old_pipe_ctx->mpcc->inst);*/
2544 if (dc->debug.sanity_checks)
2545 verify_allow_pstate_change_high(dc->hwseq);
2547 old_pipe_ctx->top_pipe = NULL;
2548 old_pipe_ctx->bottom_pipe = NULL;
2549 old_pipe_ctx->plane_state = NULL;
2551 dm_logger_write(dc->ctx->logger, LOG_DC,
2552 "Reset mpcc for pipe %d\n",
2553 old_pipe_ctx->pipe_idx);
2557 for (i = 0; i < dc->res_pool->pipe_count; i++) {
2558 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
2560 if (pipe_ctx->stream != stream)
2563 /* looking for top pipe to program */
2564 if (!pipe_ctx->top_pipe)
2565 program_all_pipe_in_tree(dc, pipe_ctx, context);
2568 dm_logger_write(dc->ctx->logger, LOG_BANDWIDTH_CALCS,
2569 "\n============== Watermark parameters ==============\n"
2570 "a.urgent_ns: %d \n"
2571 "a.cstate_enter_plus_exit: %d \n"
2572 "a.cstate_exit: %d \n"
2573 "a.pstate_change: %d \n"
2574 "a.pte_meta_urgent: %d \n"
2575 "b.urgent_ns: %d \n"
2576 "b.cstate_enter_plus_exit: %d \n"
2577 "b.cstate_exit: %d \n"
2578 "b.pstate_change: %d \n"
2579 "b.pte_meta_urgent: %d \n",
2580 context->bw.dcn.watermarks.a.urgent_ns,
2581 context->bw.dcn.watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns,
2582 context->bw.dcn.watermarks.a.cstate_pstate.cstate_exit_ns,
2583 context->bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns,
2584 context->bw.dcn.watermarks.a.pte_meta_urgent_ns,
2585 context->bw.dcn.watermarks.b.urgent_ns,
2586 context->bw.dcn.watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns,
2587 context->bw.dcn.watermarks.b.cstate_pstate.cstate_exit_ns,
2588 context->bw.dcn.watermarks.b.cstate_pstate.pstate_change_ns,
2589 context->bw.dcn.watermarks.b.pte_meta_urgent_ns
2591 dm_logger_write(dc->ctx->logger, LOG_BANDWIDTH_CALCS,
2592 "\nc.urgent_ns: %d \n"
2593 "c.cstate_enter_plus_exit: %d \n"
2594 "c.cstate_exit: %d \n"
2595 "c.pstate_change: %d \n"
2596 "c.pte_meta_urgent: %d \n"
2597 "d.urgent_ns: %d \n"
2598 "d.cstate_enter_plus_exit: %d \n"
2599 "d.cstate_exit: %d \n"
2600 "d.pstate_change: %d \n"
2601 "d.pte_meta_urgent: %d \n"
2602 "========================================================\n",
2603 context->bw.dcn.watermarks.c.urgent_ns,
2604 context->bw.dcn.watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns,
2605 context->bw.dcn.watermarks.c.cstate_pstate.cstate_exit_ns,
2606 context->bw.dcn.watermarks.c.cstate_pstate.pstate_change_ns,
2607 context->bw.dcn.watermarks.c.pte_meta_urgent_ns,
2608 context->bw.dcn.watermarks.d.urgent_ns,
2609 context->bw.dcn.watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns,
2610 context->bw.dcn.watermarks.d.cstate_pstate.cstate_exit_ns,
2611 context->bw.dcn.watermarks.d.cstate_pstate.pstate_change_ns,
2612 context->bw.dcn.watermarks.d.pte_meta_urgent_ns
2615 if (dc->debug.sanity_checks)
2616 verify_allow_pstate_change_high(dc->hwseq);
2619 static void dcn10_set_bandwidth(
2621 struct dc_state *context,
2622 bool decrease_allowed)
2624 struct pp_smu_display_requirement_rv *smu_req_cur =
2625 &dc->res_pool->pp_smu_req;
2626 struct pp_smu_display_requirement_rv smu_req = *smu_req_cur;
2627 struct pp_smu_funcs_rv *pp_smu = dc->res_pool->pp_smu;
2629 if (dc->debug.sanity_checks) {
2630 verify_allow_pstate_change_high(dc->hwseq);
2633 if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment))
2636 if (decrease_allowed || context->bw.dcn.calc_clk.dispclk_khz
2637 > dc->current_state->bw.dcn.cur_clk.dispclk_khz) {
2638 dc->res_pool->display_clock->funcs->set_clock(
2639 dc->res_pool->display_clock,
2640 context->bw.dcn.calc_clk.dispclk_khz);
2641 dc->current_state->bw.dcn.cur_clk.dispclk_khz =
2642 context->bw.dcn.calc_clk.dispclk_khz;
2644 if (decrease_allowed || context->bw.dcn.calc_clk.dcfclk_khz
2645 > dc->current_state->bw.dcn.cur_clk.dcfclk_khz) {
2646 smu_req.hard_min_dcefclk_khz =
2647 context->bw.dcn.calc_clk.dcfclk_khz;
2649 if (decrease_allowed || context->bw.dcn.calc_clk.fclk_khz
2650 > dc->current_state->bw.dcn.cur_clk.fclk_khz) {
2651 smu_req.hard_min_fclk_khz = context->bw.dcn.calc_clk.fclk_khz;
2653 if (decrease_allowed || context->bw.dcn.calc_clk.dcfclk_deep_sleep_khz
2654 > dc->current_state->bw.dcn.cur_clk.dcfclk_deep_sleep_khz) {
2655 dc->current_state->bw.dcn.calc_clk.dcfclk_deep_sleep_khz =
2656 context->bw.dcn.calc_clk.dcfclk_deep_sleep_khz;
2657 context->bw.dcn.cur_clk.dcfclk_deep_sleep_khz =
2658 context->bw.dcn.calc_clk.dcfclk_deep_sleep_khz;
2661 smu_req.display_count = context->stream_count;
2663 if (pp_smu->set_display_requirement)
2664 pp_smu->set_display_requirement(&pp_smu->pp_smu, &smu_req);
2666 *smu_req_cur = smu_req;
2668 /* Decrease in freq is increase in period so opposite comparison for dram_ccm */
2669 if (decrease_allowed || context->bw.dcn.calc_clk.dram_ccm_us
2670 < dc->current_state->bw.dcn.cur_clk.dram_ccm_us) {
2671 dc->current_state->bw.dcn.calc_clk.dram_ccm_us =
2672 context->bw.dcn.calc_clk.dram_ccm_us;
2673 context->bw.dcn.cur_clk.dram_ccm_us =
2674 context->bw.dcn.calc_clk.dram_ccm_us;
2676 if (decrease_allowed || context->bw.dcn.calc_clk.min_active_dram_ccm_us
2677 < dc->current_state->bw.dcn.cur_clk.min_active_dram_ccm_us) {
2678 dc->current_state->bw.dcn.calc_clk.min_active_dram_ccm_us =
2679 context->bw.dcn.calc_clk.min_active_dram_ccm_us;
2680 context->bw.dcn.cur_clk.min_active_dram_ccm_us =
2681 context->bw.dcn.calc_clk.min_active_dram_ccm_us;
2683 dcn10_pplib_apply_display_requirements(dc, context);
2685 if (dc->debug.sanity_checks) {
2686 verify_allow_pstate_change_high(dc->hwseq);
2689 /* need to fix this function. not doing the right thing here */
2692 static void set_drr(struct pipe_ctx **pipe_ctx,
2693 int num_pipes, int vmin, int vmax)
2696 struct drr_params params = {0};
2698 params.vertical_total_max = vmax;
2699 params.vertical_total_min = vmin;
2701 /* TODO: If multiple pipes are to be supported, you need
2704 for (i = 0; i < num_pipes; i++) {
2705 pipe_ctx[i]->stream_res.tg->funcs->set_drr(pipe_ctx[i]->stream_res.tg, ¶ms);
2709 static void get_position(struct pipe_ctx **pipe_ctx,
2711 struct crtc_position *position)
2715 /* TODO: handle pipes > 1
2717 for (i = 0; i < num_pipes; i++)
2718 pipe_ctx[i]->stream_res.tg->funcs->get_position(pipe_ctx[i]->stream_res.tg, position);
2721 static void set_static_screen_control(struct pipe_ctx **pipe_ctx,
2722 int num_pipes, const struct dc_static_screen_events *events)
2725 unsigned int value = 0;
2727 if (events->surface_update)
2729 if (events->cursor_update)
2732 for (i = 0; i < num_pipes; i++)
2733 pipe_ctx[i]->stream_res.tg->funcs->
2734 set_static_screen_control(pipe_ctx[i]->stream_res.tg, value);
2737 static void set_plane_config(
2738 const struct dc *dc,
2739 struct pipe_ctx *pipe_ctx,
2740 struct resource_context *res_ctx)
2743 program_gamut_remap(pipe_ctx);
2746 static void dcn10_config_stereo_parameters(
2747 struct dc_stream_state *stream, struct crtc_stereo_flags *flags)
2749 enum view_3d_format view_format = stream->view_format;
2750 enum dc_timing_3d_format timing_3d_format =\
2751 stream->timing.timing_3d_format;
2752 bool non_stereo_timing = false;
2754 if (timing_3d_format == TIMING_3D_FORMAT_NONE ||
2755 timing_3d_format == TIMING_3D_FORMAT_SIDE_BY_SIDE ||
2756 timing_3d_format == TIMING_3D_FORMAT_TOP_AND_BOTTOM)
2757 non_stereo_timing = true;
2759 if (non_stereo_timing == false &&
2760 view_format == VIEW_3D_FORMAT_FRAME_SEQUENTIAL) {
2762 flags->PROGRAM_STEREO = 1;
2763 flags->PROGRAM_POLARITY = 1;
2764 if (timing_3d_format == TIMING_3D_FORMAT_INBAND_FA ||
2765 timing_3d_format == TIMING_3D_FORMAT_DP_HDMI_INBAND_FA ||
2766 timing_3d_format == TIMING_3D_FORMAT_SIDEBAND_FA) {
2767 enum display_dongle_type dongle = \
2768 stream->sink->link->ddc->dongle_type;
2769 if (dongle == DISPLAY_DONGLE_DP_VGA_CONVERTER ||
2770 dongle == DISPLAY_DONGLE_DP_DVI_CONVERTER ||
2771 dongle == DISPLAY_DONGLE_DP_HDMI_CONVERTER)
2772 flags->DISABLE_STEREO_DP_SYNC = 1;
2774 flags->RIGHT_EYE_POLARITY =\
2775 stream->timing.flags.RIGHT_EYE_3D_POLARITY;
2776 if (timing_3d_format == TIMING_3D_FORMAT_HW_FRAME_PACKING)
2777 flags->FRAME_PACKED = 1;
2783 static void dcn10_setup_stereo(struct pipe_ctx *pipe_ctx, struct dc *dc)
2785 struct crtc_stereo_flags flags = { 0 };
2786 struct dc_stream_state *stream = pipe_ctx->stream;
2788 dcn10_config_stereo_parameters(stream, &flags);
2790 pipe_ctx->stream_res.opp->funcs->opp_set_stereo_polarity(
2791 pipe_ctx->stream_res.opp,
2792 flags.PROGRAM_STEREO == 1 ? true:false,
2793 stream->timing.flags.RIGHT_EYE_3D_POLARITY == 1 ? true:false);
2795 pipe_ctx->stream_res.tg->funcs->program_stereo(
2796 pipe_ctx->stream_res.tg,
2803 static void dcn10_wait_for_mpcc_disconnect(
2805 struct resource_pool *res_pool,
2806 struct pipe_ctx *pipe_ctx)
2810 if (dc->debug.sanity_checks) {
2811 verify_allow_pstate_change_high(dc->hwseq);
2814 if (!pipe_ctx->stream_res.opp)
2817 for (i = 0; i < MAX_PIPES; i++) {
2818 if (pipe_ctx->stream_res.opp->mpcc_disconnect_pending[i]) {
2819 res_pool->mpc->funcs->wait_for_idle(res_pool->mpc, i);
2820 pipe_ctx->stream_res.opp->mpcc_disconnect_pending[i] = false;
2821 res_pool->mis[i]->funcs->set_blank(res_pool->mis[i], true);
2822 /*dm_logger_write(dc->ctx->logger, LOG_ERROR,
2823 "[debug_mpo: wait_for_mpcc finished waiting on mpcc %d]\n",
2828 if (dc->debug.sanity_checks) {
2829 verify_allow_pstate_change_high(dc->hwseq);
2834 static bool dcn10_dummy_display_power_gating(
2836 uint8_t controller_id,
2837 struct dc_bios *dcb,
2838 enum pipe_gating_control power_gating)
2843 void dcn10_update_pending_status(struct pipe_ctx *pipe_ctx)
2845 struct dc_plane_state *plane_state = pipe_ctx->plane_state;
2846 struct timing_generator *tg = pipe_ctx->stream_res.tg;
2848 if (plane_state == NULL)
2851 plane_state->status.is_flip_pending =
2852 pipe_ctx->plane_res.mi->funcs->mem_input_is_flip_pending(
2853 pipe_ctx->plane_res.mi);
2855 plane_state->status.current_address = pipe_ctx->plane_res.mi->current_address;
2856 if (pipe_ctx->plane_res.mi->current_address.type == PLN_ADDR_TYPE_GRPH_STEREO &&
2857 tg->funcs->is_stereo_left_eye) {
2858 plane_state->status.is_right_eye =
2859 !tg->funcs->is_stereo_left_eye(pipe_ctx->stream_res.tg);
2865 static const struct hw_sequencer_funcs dcn10_funcs = {
2866 .program_gamut_remap = program_gamut_remap,
2867 .program_csc_matrix = program_csc_matrix,
2868 .init_hw = dcn10_init_hw,
2869 .apply_ctx_to_hw = dce110_apply_ctx_to_hw,
2870 .apply_ctx_for_surface = dcn10_apply_ctx_for_surface,
2871 .set_plane_config = set_plane_config,
2872 .update_plane_addr = dcn10_update_plane_addr,
2873 .update_dchub = dcn10_update_dchub,
2874 .update_pending_status = dcn10_update_pending_status,
2875 .set_input_transfer_func = dcn10_set_input_transfer_func,
2876 .set_output_transfer_func = dcn10_set_output_transfer_func,
2877 .power_down = dce110_power_down,
2878 .enable_accelerated_mode = dce110_enable_accelerated_mode,
2879 .enable_timing_synchronization = dcn10_enable_timing_synchronization,
2880 .update_info_frame = dce110_update_info_frame,
2881 .enable_stream = dce110_enable_stream,
2882 .disable_stream = dce110_disable_stream,
2883 .unblank_stream = dce110_unblank_stream,
2884 .enable_display_power_gating = dcn10_dummy_display_power_gating,
2885 .power_down_front_end = dcn10_power_down_fe,
2886 .power_on_front_end = dcn10_power_on_fe,
2887 .pipe_control_lock = dcn10_pipe_control_lock,
2888 .set_bandwidth = dcn10_set_bandwidth,
2889 .reset_hw_ctx_wrap = reset_hw_ctx_wrap,
2890 .prog_pixclk_crtc_otg = dcn10_prog_pixclk_crtc_otg,
2892 .get_position = get_position,
2893 .set_static_screen_control = set_static_screen_control,
2894 .setup_stereo = dcn10_setup_stereo,
2895 .set_avmute = dce110_set_avmute,
2896 .log_hw_state = dcn10_log_hw_state,
2897 .wait_for_mpcc_disconnect = dcn10_wait_for_mpcc_disconnect,
2898 .ready_shared_resources = ready_shared_resources,
2899 .optimize_shared_resources = optimize_shared_resources,
2903 void dcn10_hw_sequencer_construct(struct dc *dc)
2905 dc->hwss = dcn10_funcs;