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_dpp.h"
36 #include "dcn10/dcn10_mpc.h"
37 #include "timing_generator.h"
41 #include "raven1/DCN/dcn_1_0_offset.h"
42 #include "raven1/DCN/dcn_1_0_sh_mask.h"
43 #include "vega10/soc15ip.h"
44 #include "reg_helper.h"
52 #define FN(reg_name, field_name) \
53 hws->shifts->field_name, hws->masks->field_name
56 static void verify_allow_pstate_change_high(
57 struct dce_hwseq
*hws
)
59 /* pstate latency is ~20us so if we wait over 40us and pstate allow
60 * still not asserted, we are probably stuck and going to hang
62 static unsigned int pstate_wait_timeout_us
= 40;
63 static unsigned int max_sampled_pstate_wait_us
; /* data collection */
64 static bool forced_pstate_allow
; /* help with revert wa */
66 unsigned int debug_index
= 0x7;
67 unsigned int debug_data
;
68 unsigned int force_allow_pstate
= 0x30;
71 if (forced_pstate_allow
) {
72 /* we hacked to force pstate allow to prevent hang last time
73 * we verify_allow_pstate_change_high. so disable force
74 * here so we can check status
76 REG_WRITE(DCHUBBUB_ARB_DRAM_STATE_CNTL
, 0);
77 forced_pstate_allow
= false;
80 /* description "3-0: Pipe0 cursor0 QOS
81 * 7-4: Pipe1 cursor0 QOS
82 * 11-8: Pipe2 cursor0 QOS
83 * 15-12: Pipe3 cursor0 QOS
84 * 16: Pipe0 Plane0 Allow Pstate Change
85 * 17: Pipe1 Plane0 Allow Pstate Change
86 * 18: Pipe2 Plane0 Allow Pstate Change
87 * 19: Pipe3 Plane0 Allow Pstate Change
88 * 20: Pipe0 Plane1 Allow Pstate Change
89 * 21: Pipe1 Plane1 Allow Pstate Change
90 * 22: Pipe2 Plane1 Allow Pstate Change
91 * 23: Pipe3 Plane1 Allow Pstate Change
92 * 24: Pipe0 cursor0 Allow Pstate Change
93 * 25: Pipe1 cursor0 Allow Pstate Change
94 * 26: Pipe2 cursor0 Allow Pstate Change
95 * 27: Pipe3 cursor0 Allow Pstate Change
96 * 28: WB0 Allow Pstate Change
97 * 29: WB1 Allow Pstate Change
98 * 30: Arbiter's allow_pstate_change
99 * 31: SOC pstate change request
102 REG_WRITE(DCHUBBUB_TEST_DEBUG_INDEX
, debug_index
);
104 for (i
= 0; i
< pstate_wait_timeout_us
; i
++) {
105 debug_data
= REG_READ(DCHUBBUB_TEST_DEBUG_DATA
);
107 if (debug_data
& (1 << 30))
110 if (max_sampled_pstate_wait_us
< i
)
111 max_sampled_pstate_wait_us
= i
;
116 /* force pstate allow to prevent system hang
117 * and break to debugger to investigate
119 REG_WRITE(DCHUBBUB_ARB_DRAM_STATE_CNTL
, force_allow_pstate
);
120 forced_pstate_allow
= true;
124 static void enable_dppclk(
125 struct dce_hwseq
*hws
,
127 uint32_t requested_pix_clk
,
130 dm_logger_write(hws
->ctx
->logger
, LOG_SURFACE
,
131 "dppclk_rate_control for pipe %d programed to %d\n",
135 if (hws
->shifts
->DPPCLK_RATE_CONTROL
)
136 REG_UPDATE_2(DPP_CONTROL
[plane_id
],
137 DPPCLK_RATE_CONTROL
, dppclk_div
,
138 DPP_CLOCK_ENABLE
, 1);
140 REG_UPDATE(DPP_CONTROL
[plane_id
],
141 DPP_CLOCK_ENABLE
, 1);
144 static void enable_power_gating_plane(
145 struct dce_hwseq
*hws
,
148 bool force_on
= 1; /* disable power gating */
154 REG_UPDATE(DOMAIN0_PG_CONFIG
, DOMAIN0_POWER_FORCEON
, force_on
);
155 REG_UPDATE(DOMAIN2_PG_CONFIG
, DOMAIN2_POWER_FORCEON
, force_on
);
156 REG_UPDATE(DOMAIN4_PG_CONFIG
, DOMAIN4_POWER_FORCEON
, force_on
);
157 REG_UPDATE(DOMAIN6_PG_CONFIG
, DOMAIN6_POWER_FORCEON
, force_on
);
160 REG_UPDATE(DOMAIN1_PG_CONFIG
, DOMAIN1_POWER_FORCEON
, force_on
);
161 REG_UPDATE(DOMAIN3_PG_CONFIG
, DOMAIN3_POWER_FORCEON
, force_on
);
162 REG_UPDATE(DOMAIN5_PG_CONFIG
, DOMAIN5_POWER_FORCEON
, force_on
);
163 REG_UPDATE(DOMAIN7_PG_CONFIG
, DOMAIN7_POWER_FORCEON
, force_on
);
166 static void disable_vga(
167 struct dce_hwseq
*hws
)
169 REG_WRITE(D1VGA_CONTROL
, 0);
170 REG_WRITE(D2VGA_CONTROL
, 0);
171 REG_WRITE(D3VGA_CONTROL
, 0);
172 REG_WRITE(D4VGA_CONTROL
, 0);
175 static void dpp_pg_control(
176 struct dce_hwseq
*hws
,
177 unsigned int dpp_inst
,
180 uint32_t power_gate
= power_on
? 0 : 1;
181 uint32_t pwr_status
= power_on
? 0 : 2;
183 if (hws
->ctx
->dc
->debug
.disable_dpp_power_gate
)
188 REG_UPDATE(DOMAIN1_PG_CONFIG
,
189 DOMAIN1_POWER_GATE
, power_gate
);
191 REG_WAIT(DOMAIN1_PG_STATUS
,
192 DOMAIN1_PGFSM_PWR_STATUS
, pwr_status
, 20000, 200000);
195 REG_UPDATE(DOMAIN3_PG_CONFIG
,
196 DOMAIN3_POWER_GATE
, power_gate
);
198 REG_WAIT(DOMAIN3_PG_STATUS
,
199 DOMAIN3_PGFSM_PWR_STATUS
, pwr_status
, 20000, 200000);
202 REG_UPDATE(DOMAIN5_PG_CONFIG
,
203 DOMAIN5_POWER_GATE
, power_gate
);
205 REG_WAIT(DOMAIN5_PG_STATUS
,
206 DOMAIN5_PGFSM_PWR_STATUS
, pwr_status
, 20000, 200000);
209 REG_UPDATE(DOMAIN7_PG_CONFIG
,
210 DOMAIN7_POWER_GATE
, power_gate
);
212 REG_WAIT(DOMAIN7_PG_STATUS
,
213 DOMAIN7_PGFSM_PWR_STATUS
, pwr_status
, 20000, 200000);
221 static uint32_t convert_and_clamp(
224 uint32_t clamp_value
)
226 uint32_t ret_val
= 0;
227 ret_val
= wm_ns
* refclk_mhz
;
230 if (ret_val
> clamp_value
)
231 ret_val
= clamp_value
;
236 static void program_watermarks(
237 struct dce_hwseq
*hws
,
238 struct dcn_watermark_set
*watermarks
,
239 unsigned int refclk_mhz
)
241 uint32_t force_en
= hws
->ctx
->dc
->debug
.disable_stutter
? 1 : 0;
243 * Need to clamp to max of the register values (i.e. no wrap)
244 * for dcn1, all wm registers are 21-bit wide
246 uint32_t prog_wm_value
;
248 /* Repeat for water mark set A, B, C and D. */
250 prog_wm_value
= convert_and_clamp(watermarks
->a
.urgent_ns
,
251 refclk_mhz
, 0x1fffff);
252 REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A
, prog_wm_value
);
254 dm_logger_write(hws
->ctx
->logger
, LOG_HW_MARKS
,
255 "URGENCY_WATERMARK_A calculated =%d\n"
256 "HW register value = 0x%x\n",
257 watermarks
->a
.urgent_ns
, prog_wm_value
);
259 prog_wm_value
= convert_and_clamp(watermarks
->a
.pte_meta_urgent_ns
,
260 refclk_mhz
, 0x1fffff);
261 REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_A
, prog_wm_value
);
262 dm_logger_write(hws
->ctx
->logger
, LOG_HW_MARKS
,
263 "PTE_META_URGENCY_WATERMARK_A calculated =%d\n"
264 "HW register value = 0x%x\n",
265 watermarks
->a
.pte_meta_urgent_ns
, prog_wm_value
);
268 prog_wm_value
= convert_and_clamp(
269 watermarks
->a
.cstate_pstate
.cstate_enter_plus_exit_ns
,
270 refclk_mhz
, 0x1fffff);
272 REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A
, prog_wm_value
);
273 dm_logger_write(hws
->ctx
->logger
, LOG_HW_MARKS
,
274 "SR_ENTER_EXIT_WATERMARK_A calculated =%d\n"
275 "HW register value = 0x%x\n",
276 watermarks
->a
.cstate_pstate
.cstate_enter_plus_exit_ns
, prog_wm_value
);
279 prog_wm_value
= convert_and_clamp(
280 watermarks
->a
.cstate_pstate
.cstate_exit_ns
,
281 refclk_mhz
, 0x1fffff);
282 REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A
, prog_wm_value
);
283 dm_logger_write(hws
->ctx
->logger
, LOG_HW_MARKS
,
284 "SR_EXIT_WATERMARK_A calculated =%d\n"
285 "HW register value = 0x%x\n",
286 watermarks
->a
.cstate_pstate
.cstate_exit_ns
, prog_wm_value
);
289 prog_wm_value
= convert_and_clamp(
290 watermarks
->a
.cstate_pstate
.pstate_change_ns
,
291 refclk_mhz
, 0x1fffff);
292 REG_WRITE(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A
, prog_wm_value
);
293 dm_logger_write(hws
->ctx
->logger
, LOG_HW_MARKS
,
294 "DRAM_CLK_CHANGE_WATERMARK_A calculated =%d\n"
295 "HW register value = 0x%x\n\n",
296 watermarks
->a
.cstate_pstate
.pstate_change_ns
, prog_wm_value
);
300 prog_wm_value
= convert_and_clamp(
301 watermarks
->b
.urgent_ns
, refclk_mhz
, 0x1fffff);
302 REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B
, prog_wm_value
);
303 dm_logger_write(hws
->ctx
->logger
, LOG_HW_MARKS
,
304 "URGENCY_WATERMARK_B calculated =%d\n"
305 "HW register value = 0x%x\n",
306 watermarks
->b
.urgent_ns
, prog_wm_value
);
309 prog_wm_value
= convert_and_clamp(
310 watermarks
->b
.pte_meta_urgent_ns
,
311 refclk_mhz
, 0x1fffff);
312 REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_B
, prog_wm_value
);
313 dm_logger_write(hws
->ctx
->logger
, LOG_HW_MARKS
,
314 "PTE_META_URGENCY_WATERMARK_B calculated =%d\n"
315 "HW register value = 0x%x\n",
316 watermarks
->b
.pte_meta_urgent_ns
, prog_wm_value
);
319 prog_wm_value
= convert_and_clamp(
320 watermarks
->b
.cstate_pstate
.cstate_enter_plus_exit_ns
,
321 refclk_mhz
, 0x1fffff);
322 REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B
, prog_wm_value
);
323 dm_logger_write(hws
->ctx
->logger
, LOG_HW_MARKS
,
324 "SR_ENTER_WATERMARK_B calculated =%d\n"
325 "HW register value = 0x%x\n",
326 watermarks
->b
.cstate_pstate
.cstate_enter_plus_exit_ns
, prog_wm_value
);
329 prog_wm_value
= convert_and_clamp(
330 watermarks
->b
.cstate_pstate
.cstate_exit_ns
,
331 refclk_mhz
, 0x1fffff);
332 REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B
, prog_wm_value
);
333 dm_logger_write(hws
->ctx
->logger
, LOG_HW_MARKS
,
334 "SR_EXIT_WATERMARK_B calculated =%d\n"
335 "HW register value = 0x%x\n",
336 watermarks
->b
.cstate_pstate
.cstate_exit_ns
, prog_wm_value
);
338 prog_wm_value
= convert_and_clamp(
339 watermarks
->b
.cstate_pstate
.pstate_change_ns
,
340 refclk_mhz
, 0x1fffff);
341 REG_WRITE(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B
, prog_wm_value
);
342 dm_logger_write(hws
->ctx
->logger
, LOG_HW_MARKS
,
343 "DRAM_CLK_CHANGE_WATERMARK_B calculated =%d\n\n"
344 "HW register value = 0x%x\n",
345 watermarks
->b
.cstate_pstate
.pstate_change_ns
, prog_wm_value
);
348 prog_wm_value
= convert_and_clamp(
349 watermarks
->c
.urgent_ns
, refclk_mhz
, 0x1fffff);
350 REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C
, prog_wm_value
);
351 dm_logger_write(hws
->ctx
->logger
, LOG_HW_MARKS
,
352 "URGENCY_WATERMARK_C calculated =%d\n"
353 "HW register value = 0x%x\n",
354 watermarks
->c
.urgent_ns
, prog_wm_value
);
357 prog_wm_value
= convert_and_clamp(
358 watermarks
->c
.pte_meta_urgent_ns
,
359 refclk_mhz
, 0x1fffff);
360 REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_C
, prog_wm_value
);
361 dm_logger_write(hws
->ctx
->logger
, LOG_HW_MARKS
,
362 "PTE_META_URGENCY_WATERMARK_C calculated =%d\n"
363 "HW register value = 0x%x\n",
364 watermarks
->c
.pte_meta_urgent_ns
, prog_wm_value
);
367 prog_wm_value
= convert_and_clamp(
368 watermarks
->c
.cstate_pstate
.cstate_enter_plus_exit_ns
,
369 refclk_mhz
, 0x1fffff);
370 REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C
, prog_wm_value
);
371 dm_logger_write(hws
->ctx
->logger
, LOG_HW_MARKS
,
372 "SR_ENTER_WATERMARK_C calculated =%d\n"
373 "HW register value = 0x%x\n",
374 watermarks
->c
.cstate_pstate
.cstate_enter_plus_exit_ns
, prog_wm_value
);
377 prog_wm_value
= convert_and_clamp(
378 watermarks
->c
.cstate_pstate
.cstate_exit_ns
,
379 refclk_mhz
, 0x1fffff);
380 REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C
, prog_wm_value
);
381 dm_logger_write(hws
->ctx
->logger
, LOG_HW_MARKS
,
382 "SR_EXIT_WATERMARK_C calculated =%d\n"
383 "HW register value = 0x%x\n",
384 watermarks
->c
.cstate_pstate
.cstate_exit_ns
, prog_wm_value
);
387 prog_wm_value
= convert_and_clamp(
388 watermarks
->c
.cstate_pstate
.pstate_change_ns
,
389 refclk_mhz
, 0x1fffff);
390 REG_WRITE(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C
, prog_wm_value
);
391 dm_logger_write(hws
->ctx
->logger
, LOG_HW_MARKS
,
392 "DRAM_CLK_CHANGE_WATERMARK_C calculated =%d\n\n"
393 "HW register value = 0x%x\n",
394 watermarks
->c
.cstate_pstate
.pstate_change_ns
, prog_wm_value
);
397 prog_wm_value
= convert_and_clamp(
398 watermarks
->d
.urgent_ns
, refclk_mhz
, 0x1fffff);
399 REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D
, prog_wm_value
);
400 dm_logger_write(hws
->ctx
->logger
, LOG_HW_MARKS
,
401 "URGENCY_WATERMARK_D calculated =%d\n"
402 "HW register value = 0x%x\n",
403 watermarks
->d
.urgent_ns
, prog_wm_value
);
405 prog_wm_value
= convert_and_clamp(
406 watermarks
->d
.pte_meta_urgent_ns
,
407 refclk_mhz
, 0x1fffff);
408 REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_D
, prog_wm_value
);
409 dm_logger_write(hws
->ctx
->logger
, LOG_HW_MARKS
,
410 "PTE_META_URGENCY_WATERMARK_D calculated =%d\n"
411 "HW register value = 0x%x\n",
412 watermarks
->d
.pte_meta_urgent_ns
, prog_wm_value
);
415 prog_wm_value
= convert_and_clamp(
416 watermarks
->d
.cstate_pstate
.cstate_enter_plus_exit_ns
,
417 refclk_mhz
, 0x1fffff);
418 REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D
, prog_wm_value
);
419 dm_logger_write(hws
->ctx
->logger
, LOG_HW_MARKS
,
420 "SR_ENTER_WATERMARK_D calculated =%d\n"
421 "HW register value = 0x%x\n",
422 watermarks
->d
.cstate_pstate
.cstate_enter_plus_exit_ns
, prog_wm_value
);
425 prog_wm_value
= convert_and_clamp(
426 watermarks
->d
.cstate_pstate
.cstate_exit_ns
,
427 refclk_mhz
, 0x1fffff);
428 REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D
, prog_wm_value
);
429 dm_logger_write(hws
->ctx
->logger
, LOG_HW_MARKS
,
430 "SR_EXIT_WATERMARK_D calculated =%d\n"
431 "HW register value = 0x%x\n",
432 watermarks
->d
.cstate_pstate
.cstate_exit_ns
, prog_wm_value
);
435 prog_wm_value
= convert_and_clamp(
436 watermarks
->d
.cstate_pstate
.pstate_change_ns
,
437 refclk_mhz
, 0x1fffff);
438 REG_WRITE(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D
, prog_wm_value
);
439 dm_logger_write(hws
->ctx
->logger
, LOG_HW_MARKS
,
440 "DRAM_CLK_CHANGE_WATERMARK_D calculated =%d\n"
441 "HW register value = 0x%x\n\n",
442 watermarks
->d
.cstate_pstate
.pstate_change_ns
, prog_wm_value
);
444 REG_UPDATE(DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL
,
445 DCHUBBUB_ARB_WATERMARK_CHANGE_REQUEST
, 1);
446 REG_UPDATE(DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL
,
447 DCHUBBUB_ARB_WATERMARK_CHANGE_REQUEST
, 0);
448 REG_UPDATE(DCHUBBUB_ARB_SAT_LEVEL
,
449 DCHUBBUB_ARB_SAT_LEVEL
, 60 * refclk_mhz
);
450 REG_UPDATE(DCHUBBUB_ARB_DF_REQ_OUTSTAND
,
451 DCHUBBUB_ARB_MIN_REQ_OUTSTAND
, 68);
453 REG_UPDATE_2(DCHUBBUB_ARB_DRAM_STATE_CNTL
,
454 DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_VALUE
, 0,
455 DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE
, force_en
);
458 REG_UPDATE_2(DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL
,
459 DCHUBBUB_ARB_WATERMARK_CHANGE_DONE_INTERRUPT_DISABLE
, 1,
460 DCHUBBUB_ARB_WATERMARK_CHANGE_REQUEST
, 1);
465 static void dcn10_update_dchub(
466 struct dce_hwseq
*hws
,
467 struct dchub_init_data
*dh_data
)
469 /* TODO: port code from dal2 */
470 switch (dh_data
->fb_mode
) {
471 case FRAME_BUFFER_MODE_ZFB_ONLY
:
472 /*For ZFB case need to put DCHUB FB BASE and TOP upside down to indicate ZFB mode*/
473 REG_UPDATE(DCHUBBUB_SDPIF_FB_TOP
,
476 REG_UPDATE(DCHUBBUB_SDPIF_FB_BASE
,
477 SDPIF_FB_BASE
, 0x0FFFF);
479 REG_UPDATE(DCHUBBUB_SDPIF_AGP_BASE
,
480 SDPIF_AGP_BASE
, dh_data
->zfb_phys_addr_base
>> 22);
482 REG_UPDATE(DCHUBBUB_SDPIF_AGP_BOT
,
483 SDPIF_AGP_BOT
, dh_data
->zfb_mc_base_addr
>> 22);
485 REG_UPDATE(DCHUBBUB_SDPIF_AGP_TOP
,
486 SDPIF_AGP_TOP
, (dh_data
->zfb_mc_base_addr
+
487 dh_data
->zfb_size_in_byte
- 1) >> 22);
489 case FRAME_BUFFER_MODE_MIXED_ZFB_AND_LOCAL
:
490 /*Should not touch FB LOCATION (done by VBIOS on AsicInit table)*/
492 REG_UPDATE(DCHUBBUB_SDPIF_AGP_BASE
,
493 SDPIF_AGP_BASE
, dh_data
->zfb_phys_addr_base
>> 22);
495 REG_UPDATE(DCHUBBUB_SDPIF_AGP_BOT
,
496 SDPIF_AGP_BOT
, dh_data
->zfb_mc_base_addr
>> 22);
498 REG_UPDATE(DCHUBBUB_SDPIF_AGP_TOP
,
499 SDPIF_AGP_TOP
, (dh_data
->zfb_mc_base_addr
+
500 dh_data
->zfb_size_in_byte
- 1) >> 22);
502 case FRAME_BUFFER_MODE_LOCAL_ONLY
:
503 /*Should not touch FB LOCATION (done by VBIOS on AsicInit table)*/
504 REG_UPDATE(DCHUBBUB_SDPIF_AGP_BASE
,
507 REG_UPDATE(DCHUBBUB_SDPIF_AGP_BOT
,
508 SDPIF_AGP_BOT
, 0X03FFFF);
510 REG_UPDATE(DCHUBBUB_SDPIF_AGP_TOP
,
517 dh_data
->dchub_initialzied
= true;
518 dh_data
->dchub_info_valid
= false;
521 static void hubp_pg_control(
522 struct dce_hwseq
*hws
,
523 unsigned int hubp_inst
,
526 uint32_t power_gate
= power_on
? 0 : 1;
527 uint32_t pwr_status
= power_on
? 0 : 2;
529 if (hws
->ctx
->dc
->debug
.disable_hubp_power_gate
)
533 case 0: /* DCHUBP0 */
534 REG_UPDATE(DOMAIN0_PG_CONFIG
,
535 DOMAIN0_POWER_GATE
, power_gate
);
537 REG_WAIT(DOMAIN0_PG_STATUS
,
538 DOMAIN0_PGFSM_PWR_STATUS
, pwr_status
, 20000, 200000);
540 case 1: /* DCHUBP1 */
541 REG_UPDATE(DOMAIN2_PG_CONFIG
,
542 DOMAIN2_POWER_GATE
, power_gate
);
544 REG_WAIT(DOMAIN2_PG_STATUS
,
545 DOMAIN2_PGFSM_PWR_STATUS
, pwr_status
, 20000, 200000);
547 case 2: /* DCHUBP2 */
548 REG_UPDATE(DOMAIN4_PG_CONFIG
,
549 DOMAIN4_POWER_GATE
, power_gate
);
551 REG_WAIT(DOMAIN4_PG_STATUS
,
552 DOMAIN4_PGFSM_PWR_STATUS
, pwr_status
, 20000, 200000);
554 case 3: /* DCHUBP3 */
555 REG_UPDATE(DOMAIN6_PG_CONFIG
,
556 DOMAIN6_POWER_GATE
, power_gate
);
558 REG_WAIT(DOMAIN6_PG_STATUS
,
559 DOMAIN6_PGFSM_PWR_STATUS
, pwr_status
, 20000, 200000);
567 static void power_on_plane(
568 struct dce_hwseq
*hws
,
571 REG_SET(DC_IP_REQUEST_CNTL
, 0,
573 dpp_pg_control(hws
, plane_id
, true);
574 hubp_pg_control(hws
, plane_id
, true);
575 REG_SET(DC_IP_REQUEST_CNTL
, 0,
577 dm_logger_write(hws
->ctx
->logger
, LOG_DC
,
578 "Un-gated front end for pipe %d\n", plane_id
);
581 static void bios_golden_init(struct core_dc
*dc
)
583 struct dc_bios
*bp
= dc
->ctx
->dc_bios
;
586 /* initialize dcn global */
587 bp
->funcs
->enable_disp_power_gating(bp
,
588 CONTROLLER_ID_D0
, ASIC_PIPE_INIT
);
590 for (i
= 0; i
< dc
->res_pool
->pipe_count
; i
++) {
591 /* initialize dcn per pipe */
592 bp
->funcs
->enable_disp_power_gating(bp
,
593 CONTROLLER_ID_D0
+ i
, ASIC_PIPE_DISABLE
);
597 static void dcn10_init_hw(struct core_dc
*dc
)
600 struct abm
*abm
= dc
->res_pool
->abm
;
601 struct dce_hwseq
*hws
= dc
->hwseq
;
603 if (IS_FPGA_MAXIMUS_DC(dc
->ctx
->dce_environment
)) {
604 REG_WRITE(REFCLK_CNTL
, 0);
605 REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL
, DCHUBBUB_GLOBAL_TIMER_ENABLE
, 1);
606 REG_WRITE(DIO_MEM_PWR_CTRL
, 0);
608 if (!dc
->public.debug
.disable_clock_gate
) {
609 /* enable all DCN clock gating */
610 REG_WRITE(DCCG_GATE_DISABLE_CNTL
, 0);
612 REG_WRITE(DCCG_GATE_DISABLE_CNTL2
, 0);
614 REG_UPDATE(DCFCLK_CNTL
, DCFCLK_GATE_DIS
, 0);
617 enable_power_gating_plane(dc
->hwseq
, true);
620 /* end of FPGA. Below if real ASIC */
622 bios_golden_init(dc
);
624 disable_vga(dc
->hwseq
);
626 for (i
= 0; i
< dc
->link_count
; i
++) {
627 /* Power up AND update implementation according to the
628 * required signal (which may be different from the
629 * default signal on connector).
631 struct dc_link
*link
= dc
->links
[i
];
633 link
->link_enc
->funcs
->hw_init(link
->link_enc
);
636 for (i
= 0; i
< dc
->res_pool
->pipe_count
; i
++) {
637 struct transform
*xfm
= dc
->res_pool
->transforms
[i
];
638 struct timing_generator
*tg
= dc
->res_pool
->timing_generators
[i
];
639 struct mpcc
*mpcc
= dc
->res_pool
->mpcc
[i
];
640 struct mpcc_cfg mpcc_cfg
;
642 xfm
->funcs
->transform_reset(xfm
);
643 mpcc_cfg
.opp_id
= 0xf;
644 mpcc_cfg
.top_dpp_id
= 0xf;
645 mpcc_cfg
.bot_mpcc_id
= 0xf;
646 mpcc_cfg
.top_of_tree
= true;
647 mpcc
->funcs
->set(mpcc
, &mpcc_cfg
);
649 /* Blank controller using driver code instead of
652 tg
->funcs
->set_blank(tg
, true);
653 hwss_wait_for_blank_complete(tg
);
656 for (i
= 0; i
< dc
->res_pool
->audio_count
; i
++) {
657 struct audio
*audio
= dc
->res_pool
->audios
[i
];
659 audio
->funcs
->hw_init(audio
);
663 abm
->funcs
->init_backlight(abm
);
664 abm
->funcs
->abm_init(abm
);
667 /* power AFMT HDMI memory TODO: may move to dis/en output save power*/
668 REG_WRITE(DIO_MEM_PWR_CTRL
, 0);
670 if (!dc
->public.debug
.disable_clock_gate
) {
671 /* enable all DCN clock gating */
672 REG_WRITE(DCCG_GATE_DISABLE_CNTL
, 0);
674 REG_WRITE(DCCG_GATE_DISABLE_CNTL2
, 0);
676 REG_UPDATE(DCFCLK_CNTL
, DCFCLK_GATE_DIS
, 0);
679 enable_power_gating_plane(dc
->hwseq
, true);
682 static enum dc_status
dcn10_prog_pixclk_crtc_otg(
683 struct pipe_ctx
*pipe_ctx
,
684 struct validate_context
*context
,
687 struct dc_stream
*stream
= pipe_ctx
->stream
;
688 enum dc_color_space color_space
;
689 struct tg_color black_color
= {0};
690 bool enableStereo
= stream
->timing
.timing_3d_format
== TIMING_3D_FORMAT_NONE
?
692 bool rightEyePolarity
= stream
->timing
.flags
.RIGHT_EYE_3D_POLARITY
;
695 /* by upper caller loop, pipe0 is parent pipe and be called first.
696 * back end is set up by for pipe0. Other children pipe share back end
697 * with pipe 0. No program is needed.
699 if (pipe_ctx
->top_pipe
!= NULL
)
702 /* TODO check if timing_changed, disable stream if timing changed */
704 /* HW program guide assume display already disable
705 * by unplug sequence. OTG assume stop.
707 pipe_ctx
->tg
->funcs
->enable_optc_clock(pipe_ctx
->tg
, true);
709 if (false == pipe_ctx
->clock_source
->funcs
->program_pix_clk(
710 pipe_ctx
->clock_source
,
711 &pipe_ctx
->pix_clk_params
,
712 &pipe_ctx
->pll_settings
)) {
714 return DC_ERROR_UNEXPECTED
;
716 pipe_ctx
->tg
->dlg_otg_param
.vready_offset
= pipe_ctx
->pipe_dlg_param
.vready_offset
;
717 pipe_ctx
->tg
->dlg_otg_param
.vstartup_start
= pipe_ctx
->pipe_dlg_param
.vstartup_start
;
718 pipe_ctx
->tg
->dlg_otg_param
.vupdate_offset
= pipe_ctx
->pipe_dlg_param
.vupdate_offset
;
719 pipe_ctx
->tg
->dlg_otg_param
.vupdate_width
= pipe_ctx
->pipe_dlg_param
.vupdate_width
;
721 pipe_ctx
->tg
->dlg_otg_param
.signal
= pipe_ctx
->stream
->signal
;
723 pipe_ctx
->tg
->funcs
->program_timing(
728 pipe_ctx
->opp
->funcs
->opp_set_stereo_polarity(
733 #if 0 /* move to after enable_crtc */
734 /* TODO: OPP FMT, ABM. etc. should be done here. */
735 /* or FPGA now. instance 0 only. TODO: move to opp.c */
737 inst_offset
= reg_offsets
[pipe_ctx
->tg
->inst
].fmt
;
739 pipe_ctx
->opp
->funcs
->opp_program_fmt(
741 &stream
->bit_depth_params
,
744 /* program otg blank color */
745 color_space
= stream
->output_color_space
;
746 color_space_to_black_color(dc
, color_space
, &black_color
);
747 pipe_ctx
->tg
->funcs
->set_blank_color(
751 pipe_ctx
->tg
->funcs
->set_blank(pipe_ctx
->tg
, true);
752 hwss_wait_for_blank_complete(pipe_ctx
->tg
);
754 /* VTG is within DCHUB command block. DCFCLK is always on */
755 if (false == pipe_ctx
->tg
->funcs
->enable_crtc(pipe_ctx
->tg
)) {
757 return DC_ERROR_UNEXPECTED
;
760 /* TODO program crtc source select for non-virtual signal*/
761 /* TODO program FMT */
762 /* TODO setup link_enc */
763 /* TODO set stream attributes */
764 /* TODO program audio */
765 /* TODO enable stream if timing changed */
766 /* TODO unblank stream if DP */
771 static void reset_back_end_for_pipe(
773 struct pipe_ctx
*pipe_ctx
,
774 struct validate_context
*context
)
778 if (pipe_ctx
->stream_enc
== NULL
) {
779 pipe_ctx
->stream
= NULL
;
783 /* TODOFPGA break core_link_disable_stream into 2 functions:
784 * disable_stream and disable_link. disable_link will disable PHYPLL
785 * which is used by otg. Move disable_link after disable_crtc
787 if (!IS_FPGA_MAXIMUS_DC(dc
->ctx
->dce_environment
))
788 core_link_disable_stream(pipe_ctx
);
790 /* by upper caller loop, parent pipe: pipe0, will be reset last.
791 * back end share by all pipes and will be disable only when disable
794 if (pipe_ctx
->top_pipe
== NULL
) {
795 pipe_ctx
->tg
->funcs
->disable_crtc(pipe_ctx
->tg
);
797 pipe_ctx
->tg
->funcs
->enable_optc_clock(pipe_ctx
->tg
, false);
800 if (!IS_FPGA_MAXIMUS_DC(dc
->ctx
->dce_environment
))
801 resource_unreference_clock_source(
802 &context
->res_ctx
, dc
->res_pool
,
803 &pipe_ctx
->clock_source
);
805 for (i
= 0; i
< dc
->res_pool
->pipe_count
; i
++)
806 if (&dc
->current_context
->res_ctx
.pipe_ctx
[i
] == pipe_ctx
)
809 if (i
== dc
->res_pool
->pipe_count
)
812 pipe_ctx
->stream
= NULL
;
813 dm_logger_write(dc
->ctx
->logger
, LOG_DC
,
814 "Reset back end for pipe %d, tg:%d\n",
815 pipe_ctx
->pipe_idx
, pipe_ctx
->tg
->inst
);
818 /* trigger HW to start disconnect plane from stream on the next vsync */
819 static void plane_atomic_disconnect(struct core_dc
*dc
,
822 struct mpcc_cfg mpcc_cfg
;
823 struct mem_input
*mi
= dc
->res_pool
->mis
[fe_idx
];
824 struct transform
*xfm
= dc
->res_pool
->transforms
[fe_idx
];
825 struct mpcc
*mpcc
= dc
->res_pool
->mpcc
[fe_idx
];
826 struct timing_generator
*tg
= dc
->res_pool
->timing_generators
[mpcc
->opp_id
];
827 unsigned int opp_id
= mpcc
->opp_id
;
828 int opp_id_cached
= mpcc
->opp_id
;
834 if (dc
->public.debug
.sanity_checks
)
835 verify_allow_pstate_change_high(dc
->hwseq
);
837 mi
->funcs
->dcc_control(mi
, false, false);
839 if (dc
->public.debug
.sanity_checks
)
840 verify_allow_pstate_change_high(dc
->hwseq
);
842 mpcc_cfg
.opp_id
= 0xf;
843 mpcc_cfg
.top_dpp_id
= 0xf;
844 mpcc_cfg
.bot_mpcc_id
= 0xf;
845 mpcc_cfg
.top_of_tree
= tg
->inst
== mpcc
->inst
;
846 mpcc
->funcs
->set(mpcc
, &mpcc_cfg
);
849 * Hack to preserve old opp_id for plane_atomic_disable
850 * to find the correct otg
852 mpcc
->opp_id
= opp_id_cached
;
854 /* todo:call remove pipe from tree */
855 /* flag mpcc idle pending */
857 /*dm_logger_write(dc->ctx->logger, LOG_ERROR,
858 "[debug_mpo: plane_atomic_disconnect pending on mpcc %d]\n",
860 xfm
->funcs
->transform_reset(xfm
);
863 /* disable HW used by plane.
864 * note: cannot disable until disconnect is complete */
865 static void plane_atomic_disable(struct core_dc
*dc
,
868 struct dce_hwseq
*hws
= dc
->hwseq
;
869 struct mem_input
*mi
= dc
->res_pool
->mis
[fe_idx
];
870 struct mpcc
*mpcc
= dc
->res_pool
->mpcc
[fe_idx
];
871 struct timing_generator
*tg
= dc
->res_pool
->timing_generators
[mpcc
->opp_id
];
872 unsigned int opp_id
= mpcc
->opp_id
;
877 mpcc
->funcs
->wait_for_idle(mpcc
);
878 dc
->res_pool
->opps
[opp_id
]->mpcc_disconnect_pending
[mpcc
->inst
] = false;
879 /*dm_logger_write(dc->ctx->logger, LOG_ERROR,
880 "[debug_mpo: atomic disable finished on mpcc %d]\n",
883 mi
->funcs
->set_blank(mi
, true);
885 if (dc
->public.debug
.sanity_checks
)
886 verify_allow_pstate_change_high(dc
->hwseq
);
888 REG_UPDATE(HUBP_CLK_CNTL
[fe_idx
],
889 HUBP_CLOCK_ENABLE
, 0);
890 REG_UPDATE(DPP_CONTROL
[fe_idx
],
891 DPP_CLOCK_ENABLE
, 0);
893 if (tg
->inst
== mpcc
->inst
)
894 REG_UPDATE(OPP_PIPE_CONTROL
[opp_id
],
895 OPP_PIPE_CLOCK_EN
, 0);
899 if (dc
->public.debug
.sanity_checks
)
900 verify_allow_pstate_change_high(dc
->hwseq
);
904 * kill power to plane hw
905 * note: cannot power down until plane is disable
907 static void plane_atomic_power_down(struct core_dc
*dc
, int fe_idx
)
909 struct dce_hwseq
*hws
= dc
->hwseq
;
911 REG_SET(DC_IP_REQUEST_CNTL
, 0,
913 dpp_pg_control(hws
, fe_idx
, false);
914 hubp_pg_control(hws
, fe_idx
, false);
915 REG_SET(DC_IP_REQUEST_CNTL
, 0,
917 dm_logger_write(dc
->ctx
->logger
, LOG_DC
,
918 "Power gated front end %d\n", fe_idx
);
920 if (dc
->public.debug
.sanity_checks
)
921 verify_allow_pstate_change_high(dc
->hwseq
);
925 static void reset_front_end(
929 struct dce_hwseq
*hws
= dc
->hwseq
;
930 struct mpcc
*mpcc
= dc
->res_pool
->mpcc
[fe_idx
];
931 struct timing_generator
*tg
= dc
->res_pool
->timing_generators
[mpcc
->opp_id
];
932 unsigned int opp_id
= mpcc
->opp_id
;
940 plane_atomic_disconnect(dc
, fe_idx
);
942 REG_UPDATE(OTG_GLOBAL_SYNC_STATUS
[tg
->inst
], VUPDATE_NO_LOCK_EVENT_CLEAR
, 1);
943 tg
->funcs
->unlock(tg
);
945 if (dc
->public.debug
.sanity_checks
)
946 verify_allow_pstate_change_high(dc
->hwseq
);
948 if (tg
->ctx
->dce_environment
!= DCE_ENV_FPGA_MAXIMUS
)
949 REG_WAIT(OTG_GLOBAL_SYNC_STATUS
[tg
->inst
],
950 VUPDATE_NO_LOCK_EVENT_OCCURRED
, 1, 20000, 200000);
952 plane_atomic_disable(dc
, fe_idx
);
954 dm_logger_write(dc
->ctx
->logger
, LOG_DC
,
955 "Reset front end %d\n",
959 static void dcn10_power_down_fe(struct core_dc
*dc
, int fe_idx
)
961 struct dce_hwseq
*hws
= dc
->hwseq
;
963 reset_front_end(dc
, fe_idx
);
965 REG_SET(DC_IP_REQUEST_CNTL
, 0,
967 dpp_pg_control(hws
, fe_idx
, false);
968 hubp_pg_control(hws
, fe_idx
, false);
969 REG_SET(DC_IP_REQUEST_CNTL
, 0,
971 dm_logger_write(dc
->ctx
->logger
, LOG_DC
,
972 "Power gated front end %d\n", fe_idx
);
974 if (dc
->public.debug
.sanity_checks
)
975 verify_allow_pstate_change_high(dc
->hwseq
);
978 static void reset_hw_ctx_wrap(
980 struct validate_context
*context
)
986 for (i
= 0; i
< dc
->res_pool
->pipe_count
; i
++) {
987 struct pipe_ctx
*cur_pipe_ctx
= &dc
->current_context
->res_ctx
.pipe_ctx
[i
];
988 struct timing_generator
*tg
= cur_pipe_ctx
->tg
;
990 if (cur_pipe_ctx
->stream
)
994 for (i
= dc
->res_pool
->pipe_count
- 1; i
>= 0 ; i
--) {
995 struct pipe_ctx
*pipe_ctx_old
=
996 &dc
->current_context
->res_ctx
.pipe_ctx
[i
];
997 struct pipe_ctx
*pipe_ctx
= &context
->res_ctx
.pipe_ctx
[i
];
999 if (!pipe_ctx
->stream
||
1000 !pipe_ctx
->surface
||
1001 pipe_need_reprogram(pipe_ctx_old
, pipe_ctx
)) {
1003 plane_atomic_disconnect(dc
, i
);
1007 for (i
= dc
->res_pool
->pipe_count
- 1; i
>= 0; i
--) {
1008 struct pipe_ctx
*cur_pipe_ctx
= &dc
->current_context
->res_ctx
.pipe_ctx
[i
];
1009 struct timing_generator
*tg
= cur_pipe_ctx
->tg
;
1011 if (cur_pipe_ctx
->stream
)
1012 tg
->funcs
->unlock(tg
);
1015 /* Disable and Powerdown*/
1016 for (i
= dc
->res_pool
->pipe_count
- 1; i
>= 0 ; i
--) {
1017 struct pipe_ctx
*pipe_ctx_old
=
1018 &dc
->current_context
->res_ctx
.pipe_ctx
[i
];
1019 struct pipe_ctx
*pipe_ctx
= &context
->res_ctx
.pipe_ctx
[i
];
1021 /*if (!pipe_ctx_old->stream)
1024 if (pipe_ctx
->stream
&& pipe_ctx
->surface
1025 && !pipe_need_reprogram(pipe_ctx_old
, pipe_ctx
))
1028 plane_atomic_disable(dc
, i
);
1030 if (!pipe_ctx
->stream
|| !pipe_ctx
->surface
)
1031 plane_atomic_power_down(dc
, i
);
1035 for (i
= dc
->res_pool
->pipe_count
- 1; i
>= 0 ; i
--) {
1036 struct pipe_ctx
*pipe_ctx_old
=
1037 &dc
->current_context
->res_ctx
.pipe_ctx
[i
];
1038 struct pipe_ctx
*pipe_ctx
= &context
->res_ctx
.pipe_ctx
[i
];
1040 if (!pipe_ctx_old
->stream
)
1043 if (!pipe_ctx
->stream
||
1044 pipe_need_reprogram(pipe_ctx_old
, pipe_ctx
))
1045 reset_back_end_for_pipe(dc
, pipe_ctx_old
, dc
->current_context
);
1049 static bool patch_address_for_sbs_tb_stereo(
1050 struct pipe_ctx
*pipe_ctx
, PHYSICAL_ADDRESS_LOC
*addr
)
1052 struct dc_surface
*surface
= pipe_ctx
->surface
;
1053 bool sec_split
= pipe_ctx
->top_pipe
&&
1054 pipe_ctx
->top_pipe
->surface
== pipe_ctx
->surface
;
1055 if (sec_split
&& surface
->address
.type
== PLN_ADDR_TYPE_GRPH_STEREO
&&
1056 (pipe_ctx
->stream
->timing
.timing_3d_format
==
1057 TIMING_3D_FORMAT_SIDE_BY_SIDE
||
1058 pipe_ctx
->stream
->timing
.timing_3d_format
==
1059 TIMING_3D_FORMAT_TOP_AND_BOTTOM
)) {
1060 *addr
= surface
->address
.grph_stereo
.left_addr
;
1061 surface
->address
.grph_stereo
.left_addr
=
1062 surface
->address
.grph_stereo
.right_addr
;
1065 if (pipe_ctx
->stream
->view_format
!= VIEW_3D_FORMAT_NONE
&&
1066 surface
->address
.type
!= PLN_ADDR_TYPE_GRPH_STEREO
) {
1067 surface
->address
.type
= PLN_ADDR_TYPE_GRPH_STEREO
;
1068 surface
->address
.grph_stereo
.right_addr
=
1069 surface
->address
.grph_stereo
.left_addr
;
1075 static void update_plane_addr(const struct core_dc
*dc
, struct pipe_ctx
*pipe_ctx
)
1077 bool addr_patched
= false;
1078 PHYSICAL_ADDRESS_LOC addr
;
1079 struct dc_surface
*surface
= pipe_ctx
->surface
;
1081 if (surface
== NULL
)
1083 addr_patched
= patch_address_for_sbs_tb_stereo(pipe_ctx
, &addr
);
1084 pipe_ctx
->mi
->funcs
->mem_input_program_surface_flip_and_addr(
1087 surface
->flip_immediate
);
1088 surface
->status
.requested_address
= surface
->address
;
1090 pipe_ctx
->surface
->address
.grph_stereo
.left_addr
= addr
;
1093 static bool dcn10_set_input_transfer_func(
1094 struct pipe_ctx
*pipe_ctx
, const struct dc_surface
*surface
)
1096 struct input_pixel_processor
*ipp
= pipe_ctx
->ipp
;
1097 const struct dc_transfer_func
*tf
= NULL
;
1103 if (surface
->in_transfer_func
)
1104 tf
= surface
->in_transfer_func
;
1106 if (surface
->gamma_correction
&& dce_use_lut(surface
))
1107 ipp
->funcs
->ipp_program_input_lut(ipp
,
1108 surface
->gamma_correction
);
1111 ipp
->funcs
->ipp_set_degamma(ipp
, IPP_DEGAMMA_MODE_BYPASS
);
1112 else if (tf
->type
== TF_TYPE_PREDEFINED
) {
1114 case TRANSFER_FUNCTION_SRGB
:
1115 ipp
->funcs
->ipp_set_degamma(ipp
,
1116 IPP_DEGAMMA_MODE_HW_sRGB
);
1118 case TRANSFER_FUNCTION_BT709
:
1119 ipp
->funcs
->ipp_set_degamma(ipp
,
1120 IPP_DEGAMMA_MODE_HW_xvYCC
);
1122 case TRANSFER_FUNCTION_LINEAR
:
1123 ipp
->funcs
->ipp_set_degamma(ipp
,
1124 IPP_DEGAMMA_MODE_BYPASS
);
1126 case TRANSFER_FUNCTION_PQ
:
1133 } else if (tf
->type
== TF_TYPE_BYPASS
) {
1134 ipp
->funcs
->ipp_set_degamma(ipp
, IPP_DEGAMMA_MODE_BYPASS
);
1136 /*TF_TYPE_DISTRIBUTED_POINTS*/
1142 /*modify the method to handle rgb for arr_points*/
1143 static bool convert_to_custom_float(
1144 struct pwl_result_data
*rgb_resulted
,
1145 struct curve_points
*arr_points
,
1146 uint32_t hw_points_num
)
1148 struct custom_float_format fmt
;
1150 struct pwl_result_data
*rgb
= rgb_resulted
;
1154 fmt
.exponenta_bits
= 6;
1155 fmt
.mantissa_bits
= 12;
1158 if (!convert_to_custom_float_format(
1161 &arr_points
[0].custom_float_x
)) {
1162 BREAK_TO_DEBUGGER();
1166 if (!convert_to_custom_float_format(
1167 arr_points
[0].offset
,
1169 &arr_points
[0].custom_float_offset
)) {
1170 BREAK_TO_DEBUGGER();
1174 if (!convert_to_custom_float_format(
1175 arr_points
[0].slope
,
1177 &arr_points
[0].custom_float_slope
)) {
1178 BREAK_TO_DEBUGGER();
1182 fmt
.mantissa_bits
= 10;
1185 if (!convert_to_custom_float_format(
1188 &arr_points
[1].custom_float_x
)) {
1189 BREAK_TO_DEBUGGER();
1193 if (!convert_to_custom_float_format(
1196 &arr_points
[1].custom_float_y
)) {
1197 BREAK_TO_DEBUGGER();
1201 if (!convert_to_custom_float_format(
1202 arr_points
[1].slope
,
1204 &arr_points
[1].custom_float_slope
)) {
1205 BREAK_TO_DEBUGGER();
1209 fmt
.mantissa_bits
= 12;
1212 while (i
!= hw_points_num
) {
1213 if (!convert_to_custom_float_format(
1217 BREAK_TO_DEBUGGER();
1221 if (!convert_to_custom_float_format(
1225 BREAK_TO_DEBUGGER();
1229 if (!convert_to_custom_float_format(
1233 BREAK_TO_DEBUGGER();
1237 if (!convert_to_custom_float_format(
1240 &rgb
->delta_red_reg
)) {
1241 BREAK_TO_DEBUGGER();
1245 if (!convert_to_custom_float_format(
1248 &rgb
->delta_green_reg
)) {
1249 BREAK_TO_DEBUGGER();
1253 if (!convert_to_custom_float_format(
1256 &rgb
->delta_blue_reg
)) {
1257 BREAK_TO_DEBUGGER();
1267 #define MAX_REGIONS_NUMBER 34
1268 #define MAX_LOW_POINT 25
1269 #define NUMBER_SEGMENTS 32
1271 static bool dcn10_translate_regamma_to_hw_format(const struct dc_transfer_func
1272 *output_tf
, struct pwl_params
*regamma_params
)
1274 struct curve_points
*arr_points
;
1275 struct pwl_result_data
*rgb_resulted
;
1276 struct pwl_result_data
*rgb
;
1277 struct pwl_result_data
*rgb_plus_1
;
1278 struct fixed31_32 y_r
;
1279 struct fixed31_32 y_g
;
1280 struct fixed31_32 y_b
;
1281 struct fixed31_32 y1_min
;
1282 struct fixed31_32 y3_max
;
1284 int32_t segment_start
, segment_end
;
1286 uint32_t j
, k
, seg_distr
[MAX_REGIONS_NUMBER
], increment
, start_index
, hw_points
;
1288 if (output_tf
== NULL
|| regamma_params
== NULL
||
1289 output_tf
->type
== TF_TYPE_BYPASS
)
1292 arr_points
= regamma_params
->arr_points
;
1293 rgb_resulted
= regamma_params
->rgb_resulted
;
1296 memset(regamma_params
, 0, sizeof(struct pwl_params
));
1297 memset(seg_distr
, 0, sizeof(seg_distr
));
1299 if (output_tf
->tf
== TRANSFER_FUNCTION_PQ
) {
1301 * segments are from 2^-25 to 2^7
1303 for (i
= 0; i
< 32 ; i
++)
1306 segment_start
= -25;
1310 * segment is from 2^-10 to 2^0
1311 * There are less than 256 points, for optimization
1324 segment_start
= -10;
1328 for (i
= segment_end
- segment_start
; i
< MAX_REGIONS_NUMBER
; i
++)
1331 for (k
= 0; k
< MAX_REGIONS_NUMBER
; k
++) {
1332 if (seg_distr
[k
] != -1)
1333 hw_points
+= (1 << seg_distr
[k
]);
1337 for (k
= 0; k
< (segment_end
- segment_start
); k
++) {
1338 increment
= NUMBER_SEGMENTS
/ (1 << seg_distr
[k
]);
1339 start_index
= (segment_start
+ k
+ MAX_LOW_POINT
) * NUMBER_SEGMENTS
;
1340 for (i
= start_index
; i
< start_index
+ NUMBER_SEGMENTS
; i
+= increment
) {
1341 if (j
== hw_points
- 1)
1343 rgb_resulted
[j
].red
= output_tf
->tf_pts
.red
[i
];
1344 rgb_resulted
[j
].green
= output_tf
->tf_pts
.green
[i
];
1345 rgb_resulted
[j
].blue
= output_tf
->tf_pts
.blue
[i
];
1351 start_index
= (segment_end
+ MAX_LOW_POINT
) * NUMBER_SEGMENTS
;
1352 rgb_resulted
[hw_points
- 1].red
=
1353 output_tf
->tf_pts
.red
[start_index
];
1354 rgb_resulted
[hw_points
- 1].green
=
1355 output_tf
->tf_pts
.green
[start_index
];
1356 rgb_resulted
[hw_points
- 1].blue
=
1357 output_tf
->tf_pts
.blue
[start_index
];
1359 arr_points
[0].x
= dal_fixed31_32_pow(dal_fixed31_32_from_int(2),
1360 dal_fixed31_32_from_int(segment_start
));
1361 arr_points
[1].x
= dal_fixed31_32_pow(dal_fixed31_32_from_int(2),
1362 dal_fixed31_32_from_int(segment_end
));
1363 arr_points
[2].x
= dal_fixed31_32_pow(dal_fixed31_32_from_int(2),
1364 dal_fixed31_32_from_int(segment_end
));
1366 y_r
= rgb_resulted
[0].red
;
1367 y_g
= rgb_resulted
[0].green
;
1368 y_b
= rgb_resulted
[0].blue
;
1370 y1_min
= dal_fixed31_32_min(y_r
, dal_fixed31_32_min(y_g
, y_b
));
1372 arr_points
[0].y
= y1_min
;
1373 arr_points
[0].slope
= dal_fixed31_32_div(
1376 y_r
= rgb_resulted
[hw_points
- 1].red
;
1377 y_g
= rgb_resulted
[hw_points
- 1].green
;
1378 y_b
= rgb_resulted
[hw_points
- 1].blue
;
1380 /* see comment above, m_arrPoints[1].y should be the Y value for the
1381 * region end (m_numOfHwPoints), not last HW point(m_numOfHwPoints - 1)
1383 y3_max
= dal_fixed31_32_max(y_r
, dal_fixed31_32_max(y_g
, y_b
));
1385 arr_points
[1].y
= y3_max
;
1386 arr_points
[2].y
= y3_max
;
1388 arr_points
[1].slope
= dal_fixed31_32_zero
;
1389 arr_points
[2].slope
= dal_fixed31_32_zero
;
1391 if (output_tf
->tf
== TRANSFER_FUNCTION_PQ
) {
1392 /* for PQ, we want to have a straight line from last HW X point,
1393 * and the slope to be such that we hit 1.0 at 10000 nits.
1395 const struct fixed31_32 end_value
=
1396 dal_fixed31_32_from_int(125);
1398 arr_points
[1].slope
= dal_fixed31_32_div(
1399 dal_fixed31_32_sub(dal_fixed31_32_one
, arr_points
[1].y
),
1400 dal_fixed31_32_sub(end_value
, arr_points
[1].x
));
1401 arr_points
[2].slope
= dal_fixed31_32_div(
1402 dal_fixed31_32_sub(dal_fixed31_32_one
, arr_points
[1].y
),
1403 dal_fixed31_32_sub(end_value
, arr_points
[1].x
));
1406 regamma_params
->hw_points_num
= hw_points
;
1409 for (k
= 0; k
< MAX_REGIONS_NUMBER
&& i
< MAX_REGIONS_NUMBER
; k
++) {
1410 if (seg_distr
[k
] != -1) {
1411 regamma_params
->arr_curve_points
[k
].segments_num
=
1413 regamma_params
->arr_curve_points
[i
].offset
=
1414 regamma_params
->arr_curve_points
[k
].
1415 offset
+ (1 << seg_distr
[k
]);
1420 if (seg_distr
[k
] != -1)
1421 regamma_params
->arr_curve_points
[k
].segments_num
=
1425 rgb_plus_1
= rgb_resulted
+ 1;
1429 while (i
!= hw_points
+ 1) {
1430 if (dal_fixed31_32_lt(rgb_plus_1
->red
, rgb
->red
))
1431 rgb_plus_1
->red
= rgb
->red
;
1432 if (dal_fixed31_32_lt(rgb_plus_1
->green
, rgb
->green
))
1433 rgb_plus_1
->green
= rgb
->green
;
1434 if (dal_fixed31_32_lt(rgb_plus_1
->blue
, rgb
->blue
))
1435 rgb_plus_1
->blue
= rgb
->blue
;
1437 rgb
->delta_red
= dal_fixed31_32_sub(
1440 rgb
->delta_green
= dal_fixed31_32_sub(
1443 rgb
->delta_blue
= dal_fixed31_32_sub(
1452 convert_to_custom_float(rgb_resulted
, arr_points
, hw_points
);
1457 static bool dcn10_set_output_transfer_func(
1458 struct pipe_ctx
*pipe_ctx
,
1459 const struct dc_stream
*stream
)
1461 struct transform
*xfm
= pipe_ctx
->xfm
;
1466 xfm
->regamma_params
.hw_points_num
= GAMMA_HW_POINTS_NUM
;
1468 if (stream
->out_transfer_func
&&
1469 stream
->out_transfer_func
->type
==
1470 TF_TYPE_PREDEFINED
&&
1471 stream
->out_transfer_func
->tf
==
1472 TRANSFER_FUNCTION_SRGB
) {
1473 xfm
->funcs
->opp_set_regamma_mode(xfm
, OPP_REGAMMA_SRGB
);
1474 } else if (dcn10_translate_regamma_to_hw_format(
1475 stream
->out_transfer_func
, &xfm
->regamma_params
)) {
1476 xfm
->funcs
->opp_program_regamma_pwl(xfm
, &xfm
->regamma_params
);
1477 xfm
->funcs
->opp_set_regamma_mode(xfm
, OPP_REGAMMA_USER
);
1479 xfm
->funcs
->opp_set_regamma_mode(xfm
, OPP_REGAMMA_BYPASS
);
1485 static void dcn10_pipe_control_lock(
1487 struct pipe_ctx
*pipe
,
1490 /* use TG master update lock to lock everything on the TG
1491 * therefore only top pipe need to lock
1496 if (dc
->public.debug
.sanity_checks
)
1497 verify_allow_pstate_change_high(dc
->hwseq
);
1500 pipe
->tg
->funcs
->lock(pipe
->tg
);
1502 pipe
->tg
->funcs
->unlock(pipe
->tg
);
1504 if (dc
->public.debug
.sanity_checks
)
1505 verify_allow_pstate_change_high(dc
->hwseq
);
1508 static bool wait_for_reset_trigger_to_occur(
1509 struct dc_context
*dc_ctx
,
1510 struct timing_generator
*tg
)
1514 /* To avoid endless loop we wait at most
1515 * frames_to_wait_on_triggered_reset frames for the reset to occur. */
1516 const uint32_t frames_to_wait_on_triggered_reset
= 10;
1519 for (i
= 0; i
< frames_to_wait_on_triggered_reset
; i
++) {
1521 if (!tg
->funcs
->is_counter_moving(tg
)) {
1522 DC_ERROR("TG counter is not moving!\n");
1526 if (tg
->funcs
->did_triggered_reset_occur(tg
)) {
1528 /* usually occurs at i=1 */
1529 DC_SYNC_INFO("GSL: reset occurred at wait count: %d\n",
1534 /* Wait for one frame. */
1535 tg
->funcs
->wait_for_state(tg
, CRTC_STATE_VACTIVE
);
1536 tg
->funcs
->wait_for_state(tg
, CRTC_STATE_VBLANK
);
1540 DC_ERROR("GSL: Timeout on reset trigger!\n");
1545 static void dcn10_enable_timing_synchronization(
1549 struct pipe_ctx
*grouped_pipes
[])
1551 struct dc_context
*dc_ctx
= dc
->ctx
;
1554 DC_SYNC_INFO("Setting up OTG reset trigger\n");
1556 for (i
= 1; i
< group_size
; i
++)
1557 grouped_pipes
[i
]->tg
->funcs
->enable_reset_trigger(
1558 grouped_pipes
[i
]->tg
, grouped_pipes
[0]->tg
->inst
);
1561 DC_SYNC_INFO("Waiting for trigger\n");
1563 /* Need to get only check 1 pipe for having reset as all the others are
1564 * synchronized. Look at last pipe programmed to reset.
1566 wait_for_reset_trigger_to_occur(dc_ctx
, grouped_pipes
[1]->tg
);
1567 for (i
= 1; i
< group_size
; i
++)
1568 grouped_pipes
[i
]->tg
->funcs
->disable_reset_trigger(
1569 grouped_pipes
[i
]->tg
);
1571 DC_SYNC_INFO("Sync complete\n");
1574 static void print_rq_dlg_ttu(
1575 struct core_dc
*core_dc
,
1576 struct pipe_ctx
*pipe_ctx
)
1578 dm_logger_write(core_dc
->ctx
->logger
, LOG_BANDWIDTH_CALCS
,
1579 "\n============== DML TTU Output parameters [%d] ==============\n"
1580 "qos_level_low_wm: %d, \n"
1581 "qos_level_high_wm: %d, \n"
1582 "min_ttu_vblank: %d, \n"
1583 "qos_level_flip: %d, \n"
1584 "refcyc_per_req_delivery_l: %d, \n"
1585 "qos_level_fixed_l: %d, \n"
1586 "qos_ramp_disable_l: %d, \n"
1587 "refcyc_per_req_delivery_pre_l: %d, \n"
1588 "refcyc_per_req_delivery_c: %d, \n"
1589 "qos_level_fixed_c: %d, \n"
1590 "qos_ramp_disable_c: %d, \n"
1591 "refcyc_per_req_delivery_pre_c: %d\n"
1592 "=============================================================\n",
1594 pipe_ctx
->ttu_regs
.qos_level_low_wm
,
1595 pipe_ctx
->ttu_regs
.qos_level_high_wm
,
1596 pipe_ctx
->ttu_regs
.min_ttu_vblank
,
1597 pipe_ctx
->ttu_regs
.qos_level_flip
,
1598 pipe_ctx
->ttu_regs
.refcyc_per_req_delivery_l
,
1599 pipe_ctx
->ttu_regs
.qos_level_fixed_l
,
1600 pipe_ctx
->ttu_regs
.qos_ramp_disable_l
,
1601 pipe_ctx
->ttu_regs
.refcyc_per_req_delivery_pre_l
,
1602 pipe_ctx
->ttu_regs
.refcyc_per_req_delivery_c
,
1603 pipe_ctx
->ttu_regs
.qos_level_fixed_c
,
1604 pipe_ctx
->ttu_regs
.qos_ramp_disable_c
,
1605 pipe_ctx
->ttu_regs
.refcyc_per_req_delivery_pre_c
1608 dm_logger_write(core_dc
->ctx
->logger
, LOG_BANDWIDTH_CALCS
,
1609 "\n============== DML DLG Output parameters [%d] ==============\n"
1610 "refcyc_h_blank_end: %d, \n"
1611 "dlg_vblank_end: %d, \n"
1612 "min_dst_y_next_start: %d, \n"
1613 "refcyc_per_htotal: %d, \n"
1614 "refcyc_x_after_scaler: %d, \n"
1615 "dst_y_after_scaler: %d, \n"
1616 "dst_y_prefetch: %d, \n"
1617 "dst_y_per_vm_vblank: %d, \n"
1618 "dst_y_per_row_vblank: %d, \n"
1619 "ref_freq_to_pix_freq: %d, \n"
1620 "vratio_prefetch: %d, \n"
1621 "refcyc_per_pte_group_vblank_l: %d, \n"
1622 "refcyc_per_meta_chunk_vblank_l: %d, \n"
1623 "dst_y_per_pte_row_nom_l: %d, \n"
1624 "refcyc_per_pte_group_nom_l: %d, \n",
1626 pipe_ctx
->dlg_regs
.refcyc_h_blank_end
,
1627 pipe_ctx
->dlg_regs
.dlg_vblank_end
,
1628 pipe_ctx
->dlg_regs
.min_dst_y_next_start
,
1629 pipe_ctx
->dlg_regs
.refcyc_per_htotal
,
1630 pipe_ctx
->dlg_regs
.refcyc_x_after_scaler
,
1631 pipe_ctx
->dlg_regs
.dst_y_after_scaler
,
1632 pipe_ctx
->dlg_regs
.dst_y_prefetch
,
1633 pipe_ctx
->dlg_regs
.dst_y_per_vm_vblank
,
1634 pipe_ctx
->dlg_regs
.dst_y_per_row_vblank
,
1635 pipe_ctx
->dlg_regs
.ref_freq_to_pix_freq
,
1636 pipe_ctx
->dlg_regs
.vratio_prefetch
,
1637 pipe_ctx
->dlg_regs
.refcyc_per_pte_group_vblank_l
,
1638 pipe_ctx
->dlg_regs
.refcyc_per_meta_chunk_vblank_l
,
1639 pipe_ctx
->dlg_regs
.dst_y_per_pte_row_nom_l
,
1640 pipe_ctx
->dlg_regs
.refcyc_per_pte_group_nom_l
1643 dm_logger_write(core_dc
->ctx
->logger
, LOG_BANDWIDTH_CALCS
,
1644 "\ndst_y_per_meta_row_nom_l: %d, \n"
1645 "refcyc_per_meta_chunk_nom_l: %d, \n"
1646 "refcyc_per_line_delivery_pre_l: %d, \n"
1647 "refcyc_per_line_delivery_l: %d, \n"
1648 "vratio_prefetch_c: %d, \n"
1649 "refcyc_per_pte_group_vblank_c: %d, \n"
1650 "refcyc_per_meta_chunk_vblank_c: %d, \n"
1651 "dst_y_per_pte_row_nom_c: %d, \n"
1652 "refcyc_per_pte_group_nom_c: %d, \n"
1653 "dst_y_per_meta_row_nom_c: %d, \n"
1654 "refcyc_per_meta_chunk_nom_c: %d, \n"
1655 "refcyc_per_line_delivery_pre_c: %d, \n"
1656 "refcyc_per_line_delivery_c: %d \n"
1657 "========================================================\n",
1658 pipe_ctx
->dlg_regs
.dst_y_per_meta_row_nom_l
,
1659 pipe_ctx
->dlg_regs
.refcyc_per_meta_chunk_nom_l
,
1660 pipe_ctx
->dlg_regs
.refcyc_per_line_delivery_pre_l
,
1661 pipe_ctx
->dlg_regs
.refcyc_per_line_delivery_l
,
1662 pipe_ctx
->dlg_regs
.vratio_prefetch_c
,
1663 pipe_ctx
->dlg_regs
.refcyc_per_pte_group_vblank_c
,
1664 pipe_ctx
->dlg_regs
.refcyc_per_meta_chunk_vblank_c
,
1665 pipe_ctx
->dlg_regs
.dst_y_per_pte_row_nom_c
,
1666 pipe_ctx
->dlg_regs
.refcyc_per_pte_group_nom_c
,
1667 pipe_ctx
->dlg_regs
.dst_y_per_meta_row_nom_c
,
1668 pipe_ctx
->dlg_regs
.refcyc_per_meta_chunk_nom_c
,
1669 pipe_ctx
->dlg_regs
.refcyc_per_line_delivery_pre_c
,
1670 pipe_ctx
->dlg_regs
.refcyc_per_line_delivery_c
1673 dm_logger_write(core_dc
->ctx
->logger
, LOG_BANDWIDTH_CALCS
,
1674 "\n============== DML RQ Output parameters [%d] ==============\n"
1676 "min_chunk_size: %d \n"
1677 "meta_chunk_size: %d \n"
1678 "min_meta_chunk_size: %d \n"
1679 "dpte_group_size: %d \n"
1680 "mpte_group_size: %d \n"
1681 "swath_height: %d \n"
1682 "pte_row_height_linear: %d \n"
1683 "========================================================\n",
1685 pipe_ctx
->rq_regs
.rq_regs_l
.chunk_size
,
1686 pipe_ctx
->rq_regs
.rq_regs_l
.min_chunk_size
,
1687 pipe_ctx
->rq_regs
.rq_regs_l
.meta_chunk_size
,
1688 pipe_ctx
->rq_regs
.rq_regs_l
.min_meta_chunk_size
,
1689 pipe_ctx
->rq_regs
.rq_regs_l
.dpte_group_size
,
1690 pipe_ctx
->rq_regs
.rq_regs_l
.mpte_group_size
,
1691 pipe_ctx
->rq_regs
.rq_regs_l
.swath_height
,
1692 pipe_ctx
->rq_regs
.rq_regs_l
.pte_row_height_linear
1696 static void dcn10_power_on_fe(
1698 struct pipe_ctx
*pipe_ctx
,
1699 struct validate_context
*context
)
1701 struct dc_surface
*dc_surface
= pipe_ctx
->surface
;
1702 struct dce_hwseq
*hws
= dc
->hwseq
;
1704 power_on_plane(dc
->hwseq
,
1705 pipe_ctx
->pipe_idx
);
1707 /* enable DCFCLK current DCHUB */
1708 REG_UPDATE(HUBP_CLK_CNTL
[pipe_ctx
->pipe_idx
],
1709 HUBP_CLOCK_ENABLE
, 1);
1711 /* make sure OPP_PIPE_CLOCK_EN = 1 */
1712 REG_UPDATE(OPP_PIPE_CONTROL
[pipe_ctx
->tg
->inst
],
1713 OPP_PIPE_CLOCK_EN
, 1);
1714 /*TODO: REG_UPDATE(DENTIST_DISPCLK_CNTL, DENTIST_DPPCLK_WDIVIDER, 0x1f);*/
1717 dm_logger_write(dc
->ctx
->logger
, LOG_DC
,
1718 "Pipe:%d 0x%x: addr hi:0x%x, "
1721 " %d; dst: %d, %d, %d, %d;\n",
1724 dc_surface
->address
.grph
.addr
.high_part
,
1725 dc_surface
->address
.grph
.addr
.low_part
,
1726 dc_surface
->src_rect
.x
,
1727 dc_surface
->src_rect
.y
,
1728 dc_surface
->src_rect
.width
,
1729 dc_surface
->src_rect
.height
,
1730 dc_surface
->dst_rect
.x
,
1731 dc_surface
->dst_rect
.y
,
1732 dc_surface
->dst_rect
.width
,
1733 dc_surface
->dst_rect
.height
);
1735 dm_logger_write(dc
->ctx
->logger
, LOG_HW_SET_MODE
,
1736 "Pipe %d: width, height, x, y\n"
1737 "viewport:%d, %d, %d, %d\n"
1738 "recout: %d, %d, %d, %d\n",
1740 pipe_ctx
->scl_data
.viewport
.width
,
1741 pipe_ctx
->scl_data
.viewport
.height
,
1742 pipe_ctx
->scl_data
.viewport
.x
,
1743 pipe_ctx
->scl_data
.viewport
.y
,
1744 pipe_ctx
->scl_data
.recout
.width
,
1745 pipe_ctx
->scl_data
.recout
.height
,
1746 pipe_ctx
->scl_data
.recout
.x
,
1747 pipe_ctx
->scl_data
.recout
.y
);
1748 print_rq_dlg_ttu(dc
, pipe_ctx
);
1752 static void program_gamut_remap(struct pipe_ctx
*pipe_ctx
)
1754 struct xfm_grph_csc_adjustment adjust
;
1755 memset(&adjust
, 0, sizeof(adjust
));
1756 adjust
.gamut_adjust_type
= GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS
;
1759 if (pipe_ctx
->stream
->gamut_remap_matrix
.enable_remap
== true) {
1760 adjust
.gamut_adjust_type
= GRAPHICS_GAMUT_ADJUST_TYPE_SW
;
1761 adjust
.temperature_matrix
[0] =
1763 gamut_remap_matrix
.matrix
[0];
1764 adjust
.temperature_matrix
[1] =
1766 gamut_remap_matrix
.matrix
[1];
1767 adjust
.temperature_matrix
[2] =
1769 gamut_remap_matrix
.matrix
[2];
1770 adjust
.temperature_matrix
[3] =
1772 gamut_remap_matrix
.matrix
[4];
1773 adjust
.temperature_matrix
[4] =
1775 gamut_remap_matrix
.matrix
[5];
1776 adjust
.temperature_matrix
[5] =
1778 gamut_remap_matrix
.matrix
[6];
1779 adjust
.temperature_matrix
[6] =
1781 gamut_remap_matrix
.matrix
[8];
1782 adjust
.temperature_matrix
[7] =
1784 gamut_remap_matrix
.matrix
[9];
1785 adjust
.temperature_matrix
[8] =
1787 gamut_remap_matrix
.matrix
[10];
1790 pipe_ctx
->xfm
->funcs
->transform_set_gamut_remap(pipe_ctx
->xfm
, &adjust
);
1794 static void program_csc_matrix(struct pipe_ctx
*pipe_ctx
,
1795 enum dc_color_space colorspace
,
1799 struct out_csc_color_matrix tbl_entry
;
1801 if (pipe_ctx
->stream
->csc_color_matrix
.enable_adjustment
1803 enum dc_color_space color_space
=
1804 pipe_ctx
->stream
->output_color_space
;
1806 //uint16_t matrix[12];
1807 for (i
= 0; i
< 12; i
++)
1808 tbl_entry
.regval
[i
] = pipe_ctx
->stream
->csc_color_matrix
.matrix
[i
];
1810 tbl_entry
.color_space
= color_space
;
1811 //tbl_entry.regval = matrix;
1812 pipe_ctx
->xfm
->funcs
->opp_set_csc_adjustment(pipe_ctx
->xfm
, &tbl_entry
);
1815 static bool is_lower_pipe_tree_visible(struct pipe_ctx
*pipe_ctx
)
1817 if (pipe_ctx
->surface
->visible
)
1819 if (pipe_ctx
->bottom_pipe
&& is_lower_pipe_tree_visible(pipe_ctx
->bottom_pipe
))
1824 static bool is_upper_pipe_tree_visible(struct pipe_ctx
*pipe_ctx
)
1826 if (pipe_ctx
->surface
->visible
)
1828 if (pipe_ctx
->top_pipe
&& is_upper_pipe_tree_visible(pipe_ctx
->top_pipe
))
1833 static bool is_pipe_tree_visible(struct pipe_ctx
*pipe_ctx
)
1835 if (pipe_ctx
->surface
->visible
)
1837 if (pipe_ctx
->top_pipe
&& is_upper_pipe_tree_visible(pipe_ctx
->top_pipe
))
1839 if (pipe_ctx
->bottom_pipe
&& is_lower_pipe_tree_visible(pipe_ctx
->bottom_pipe
))
1844 static bool is_rgb_cspace(enum dc_color_space output_color_space
)
1846 switch (output_color_space
) {
1847 case COLOR_SPACE_SRGB
:
1848 case COLOR_SPACE_SRGB_LIMITED
:
1849 case COLOR_SPACE_2020_RGB_FULLRANGE
:
1850 case COLOR_SPACE_2020_RGB_LIMITEDRANGE
:
1851 case COLOR_SPACE_ADOBERGB
:
1853 case COLOR_SPACE_YCBCR601
:
1854 case COLOR_SPACE_YCBCR709
:
1855 case COLOR_SPACE_YCBCR601_LIMITED
:
1856 case COLOR_SPACE_YCBCR709_LIMITED
:
1857 case COLOR_SPACE_2020_YCBCR
:
1860 /* Add a case to switch */
1861 BREAK_TO_DEBUGGER();
1866 static void dcn10_get_surface_visual_confirm_color(
1867 const struct pipe_ctx
*pipe_ctx
,
1868 struct tg_color
*color
)
1870 uint32_t color_value
= MAX_TG_COLOR_VALUE
;
1872 switch (pipe_ctx
->scl_data
.format
) {
1873 case PIXEL_FORMAT_ARGB8888
:
1874 /* set boarder color to red */
1875 color
->color_r_cr
= color_value
;
1878 case PIXEL_FORMAT_ARGB2101010
:
1879 /* set boarder color to blue */
1880 color
->color_b_cb
= color_value
;
1882 case PIXEL_FORMAT_420BPP8
:
1883 /* set boarder color to green */
1884 color
->color_g_y
= color_value
;
1886 case PIXEL_FORMAT_420BPP10
:
1887 /* set boarder color to yellow */
1888 color
->color_g_y
= color_value
;
1889 color
->color_r_cr
= color_value
;
1891 case PIXEL_FORMAT_FP16
:
1892 /* set boarder color to white */
1893 color
->color_r_cr
= color_value
;
1894 color
->color_b_cb
= color_value
;
1895 color
->color_g_y
= color_value
;
1902 static void update_dchubp_dpp(
1904 struct pipe_ctx
*pipe_ctx
,
1905 struct validate_context
*context
)
1907 struct dce_hwseq
*hws
= dc
->hwseq
;
1908 struct mem_input
*mi
= pipe_ctx
->mi
;
1909 struct input_pixel_processor
*ipp
= pipe_ctx
->ipp
;
1910 struct dc_surface
*surface
= pipe_ctx
->surface
;
1911 union plane_size size
= surface
->plane_size
;
1912 struct default_adjustment ocsc
= {0};
1913 struct tg_color black_color
= {0};
1914 struct mpcc_cfg mpcc_cfg
;
1915 bool per_pixel_alpha
= surface
->per_pixel_alpha
&& pipe_ctx
->bottom_pipe
;
1917 /* TODO: proper fix once fpga works */
1918 /* depends on DML calculation, DPP clock value may change dynamically */
1922 pipe_ctx
->pix_clk_params
.requested_pix_clk
,
1923 context
->bw
.dcn
.calc_clk
.dppclk_div
);
1924 dc
->current_context
->bw
.dcn
.cur_clk
.dppclk_div
=
1925 context
->bw
.dcn
.calc_clk
.dppclk_div
;
1926 context
->bw
.dcn
.cur_clk
.dppclk_div
= context
->bw
.dcn
.calc_clk
.dppclk_div
;
1928 /* TODO: Need input parameter to tell current DCHUB pipe tie to which OTG
1929 * VTG is within DCHUBBUB which is commond block share by each pipe HUBP.
1930 * VTG is 1:1 mapping with OTG. Each pipe HUBP will select which VTG
1932 REG_UPDATE(DCHUBP_CNTL
[pipe_ctx
->pipe_idx
], HUBP_VTG_SEL
, pipe_ctx
->tg
->inst
);
1934 update_plane_addr(dc
, pipe_ctx
);
1936 mi
->funcs
->mem_input_setup(
1938 &pipe_ctx
->dlg_regs
,
1939 &pipe_ctx
->ttu_regs
,
1941 &pipe_ctx
->pipe_dlg_param
);
1943 size
.grph
.surface_size
= pipe_ctx
->scl_data
.viewport
;
1945 if (dc
->public.config
.gpu_vm_support
)
1946 mi
->funcs
->mem_input_program_pte_vm(
1949 &surface
->tiling_info
,
1952 ipp
->funcs
->ipp_setup(ipp
,
1955 IPP_OUTPUT_FORMAT_12_BIT_FIX
);
1957 pipe_ctx
->scl_data
.lb_params
.alpha_en
= per_pixel_alpha
;
1958 mpcc_cfg
.top_dpp_id
= pipe_ctx
->pipe_idx
;
1959 if (pipe_ctx
->bottom_pipe
)
1960 mpcc_cfg
.bot_mpcc_id
= pipe_ctx
->bottom_pipe
->mpcc
->inst
;
1962 mpcc_cfg
.bot_mpcc_id
= 0xf;
1963 mpcc_cfg
.opp_id
= pipe_ctx
->tg
->inst
;
1964 mpcc_cfg
.top_of_tree
= pipe_ctx
->pipe_idx
== pipe_ctx
->tg
->inst
;
1965 mpcc_cfg
.per_pixel_alpha
= per_pixel_alpha
;
1966 /* DCN1.0 has output CM before MPC which seems to screw with
1967 * pre-multiplied alpha.
1969 mpcc_cfg
.pre_multiplied_alpha
= is_rgb_cspace(
1970 pipe_ctx
->stream
->output_color_space
)
1972 pipe_ctx
->mpcc
->funcs
->set(pipe_ctx
->mpcc
, &mpcc_cfg
);
1974 if (dc
->public.debug
.surface_visual_confirm
) {
1975 dcn10_get_surface_visual_confirm_color(pipe_ctx
, &black_color
);
1977 color_space_to_black_color(
1978 dc
, pipe_ctx
->stream
->output_color_space
,
1981 pipe_ctx
->mpcc
->funcs
->set_bg_color(pipe_ctx
->mpcc
, &black_color
);
1983 pipe_ctx
->scl_data
.lb_params
.depth
= LB_PIXEL_DEPTH_30BPP
;
1984 /* scaler configuration */
1985 pipe_ctx
->xfm
->funcs
->transform_set_scaler(
1986 pipe_ctx
->xfm
, &pipe_ctx
->scl_data
);
1987 mi
->funcs
->mem_program_viewport(mi
,
1988 &pipe_ctx
->scl_data
.viewport
, &pipe_ctx
->scl_data
.viewport_c
);
1991 program_gamut_remap(pipe_ctx
);
1993 /*TODO add adjustments parameters*/
1994 ocsc
.out_color_space
= pipe_ctx
->stream
->output_color_space
;
1995 pipe_ctx
->xfm
->funcs
->opp_set_csc_default(pipe_ctx
->xfm
, &ocsc
);
1997 mi
->funcs
->mem_input_program_surface_config(
2000 &surface
->tiling_info
,
2004 surface
->horizontal_mirror
);
2006 mi
->funcs
->set_blank(mi
, !is_pipe_tree_visible(pipe_ctx
));
2009 static void program_all_pipe_in_tree(
2011 struct pipe_ctx
*pipe_ctx
,
2012 struct validate_context
*context
)
2014 unsigned int ref_clk_mhz
= dc
->res_pool
->ref_clock_inKhz
/1000;
2016 if (pipe_ctx
->top_pipe
== NULL
) {
2018 /* lock otg_master_update to process all pipes associated with
2019 * this OTG. this is done only one time.
2021 /* watermark is for all pipes */
2022 program_watermarks(dc
->hwseq
, &context
->bw
.dcn
.watermarks
, ref_clk_mhz
);
2024 if (dc
->public.debug
.sanity_checks
) {
2025 /* pstate stuck check after watermark update */
2026 verify_allow_pstate_change_high(dc
->hwseq
);
2029 pipe_ctx
->tg
->funcs
->lock(pipe_ctx
->tg
);
2031 pipe_ctx
->tg
->dlg_otg_param
.vready_offset
= pipe_ctx
->pipe_dlg_param
.vready_offset
;
2032 pipe_ctx
->tg
->dlg_otg_param
.vstartup_start
= pipe_ctx
->pipe_dlg_param
.vstartup_start
;
2033 pipe_ctx
->tg
->dlg_otg_param
.vupdate_offset
= pipe_ctx
->pipe_dlg_param
.vupdate_offset
;
2034 pipe_ctx
->tg
->dlg_otg_param
.vupdate_width
= pipe_ctx
->pipe_dlg_param
.vupdate_width
;
2035 pipe_ctx
->tg
->dlg_otg_param
.signal
= pipe_ctx
->stream
->signal
;
2037 pipe_ctx
->tg
->funcs
->program_global_sync(
2039 pipe_ctx
->tg
->funcs
->set_blank(pipe_ctx
->tg
, !is_pipe_tree_visible(pipe_ctx
));
2042 if (pipe_ctx
->surface
!= NULL
) {
2043 dcn10_power_on_fe(dc
, pipe_ctx
, context
);
2044 update_dchubp_dpp(dc
, pipe_ctx
, context
);
2047 if (dc
->public.debug
.sanity_checks
) {
2048 /* pstate stuck check after each pipe is programmed */
2049 verify_allow_pstate_change_high(dc
->hwseq
);
2052 if (pipe_ctx
->bottom_pipe
!= NULL
)
2053 program_all_pipe_in_tree(dc
, pipe_ctx
->bottom_pipe
, context
);
2056 static void dcn10_pplib_apply_display_requirements(
2058 struct validate_context
*context
)
2060 struct dm_pp_display_configuration
*pp_display_cfg
= &context
->pp_display_cfg
;
2062 pp_display_cfg
->all_displays_in_sync
= false;/*todo*/
2063 pp_display_cfg
->nb_pstate_switch_disable
= false;
2064 pp_display_cfg
->min_engine_clock_khz
= context
->bw
.dcn
.cur_clk
.dcfclk_khz
;
2065 pp_display_cfg
->min_memory_clock_khz
= context
->bw
.dcn
.cur_clk
.fclk_khz
;
2066 pp_display_cfg
->min_engine_clock_deep_sleep_khz
= context
->bw
.dcn
.cur_clk
.dcfclk_deep_sleep_khz
;
2067 pp_display_cfg
->min_dcfc_deep_sleep_clock_khz
= context
->bw
.dcn
.cur_clk
.dcfclk_deep_sleep_khz
;
2068 pp_display_cfg
->avail_mclk_switch_time_us
=
2069 context
->bw
.dcn
.cur_clk
.dram_ccm_us
> 0 ? context
->bw
.dcn
.cur_clk
.dram_ccm_us
: 0;
2070 pp_display_cfg
->avail_mclk_switch_time_in_disp_active_us
=
2071 context
->bw
.dcn
.cur_clk
.min_active_dram_ccm_us
> 0 ? context
->bw
.dcn
.cur_clk
.min_active_dram_ccm_us
: 0;
2072 pp_display_cfg
->min_dcfclock_khz
= context
->bw
.dcn
.cur_clk
.dcfclk_khz
;
2073 pp_display_cfg
->disp_clk_khz
= context
->bw
.dcn
.cur_clk
.dispclk_khz
;
2074 dce110_fill_display_configs(context
, pp_display_cfg
);
2076 if (memcmp(&dc
->prev_display_config
, pp_display_cfg
, sizeof(
2077 struct dm_pp_display_configuration
)) != 0)
2078 dm_pp_apply_display_requirements(dc
->ctx
, pp_display_cfg
);
2080 dc
->prev_display_config
= *pp_display_cfg
;
2083 static void dcn10_apply_ctx_for_surface(
2085 const struct dc_surface
*surface
,
2086 struct validate_context
*context
)
2090 if (dc
->public.debug
.sanity_checks
)
2091 verify_allow_pstate_change_high(dc
->hwseq
);
2096 for (be_idx
= 0; be_idx
< dc
->res_pool
->pipe_count
; be_idx
++)
2097 if (surface
== context
->res_ctx
.pipe_ctx
[be_idx
].surface
)
2100 /* reset unused mpcc */
2101 for (i
= 0; i
< dc
->res_pool
->pipe_count
; i
++) {
2102 struct pipe_ctx
*pipe_ctx
= &context
->res_ctx
.pipe_ctx
[i
];
2103 struct pipe_ctx
*old_pipe_ctx
=
2104 &dc
->current_context
->res_ctx
.pipe_ctx
[i
];
2106 if (!pipe_ctx
->surface
&& !old_pipe_ctx
->surface
)
2110 * Powergate reused pipes that are not powergated
2111 * fairly hacky right now, using opp_id as indicator
2114 if (pipe_ctx
->surface
&& !old_pipe_ctx
->surface
) {
2115 if (pipe_ctx
->mpcc
->opp_id
!= 0xf && pipe_ctx
->tg
->inst
== be_idx
) {
2116 dcn10_power_down_fe(dc
, pipe_ctx
->pipe_idx
);
2118 * power down fe will unlock when calling reset, need
2119 * to lock it back here. Messy, need rework.
2121 pipe_ctx
->tg
->funcs
->lock(pipe_ctx
->tg
);
2126 if ((!pipe_ctx
->surface
&& old_pipe_ctx
->surface
)
2127 || (!pipe_ctx
->stream
&& old_pipe_ctx
->stream
)) {
2128 struct mpcc_cfg mpcc_cfg
;
2129 int opp_id_cached
= old_pipe_ctx
->mpcc
->opp_id
;
2131 if (old_pipe_ctx
->tg
->inst
!= be_idx
)
2134 if (!old_pipe_ctx
->top_pipe
) {
2140 mpcc_cfg
.opp_id
= 0xf;
2141 mpcc_cfg
.top_dpp_id
= 0xf;
2142 mpcc_cfg
.bot_mpcc_id
= 0xf;
2143 mpcc_cfg
.top_of_tree
= !old_pipe_ctx
->top_pipe
;
2144 old_pipe_ctx
->mpcc
->funcs
->set(old_pipe_ctx
->mpcc
, &mpcc_cfg
);
2145 old_pipe_ctx
->top_pipe
->opp
->mpcc_disconnect_pending
[old_pipe_ctx
->mpcc
->inst
] = true;
2147 /*dm_logger_write(dc->ctx->logger, LOG_ERROR,
2148 "[debug_mpo: apply_ctx disconnect pending on mpcc %d]\n",
2149 old_pipe_ctx->mpcc->inst);*/
2151 if (dc
->public.debug
.sanity_checks
)
2152 verify_allow_pstate_change_high(dc
->hwseq
);
2155 * the mpcc is the only thing that keeps track of the mpcc
2156 * mapping for reset front end right now. Might need some
2159 old_pipe_ctx
->mpcc
->opp_id
= opp_id_cached
;
2161 old_pipe_ctx
->top_pipe
= NULL
;
2162 old_pipe_ctx
->bottom_pipe
= NULL
;
2163 old_pipe_ctx
->surface
= NULL
;
2165 dm_logger_write(dc
->ctx
->logger
, LOG_DC
,
2166 "Reset mpcc for pipe %d\n",
2167 old_pipe_ctx
->pipe_idx
);
2171 for (i
= 0; i
< dc
->res_pool
->pipe_count
; i
++) {
2172 struct pipe_ctx
*pipe_ctx
= &context
->res_ctx
.pipe_ctx
[i
];
2174 if (pipe_ctx
->surface
!= surface
)
2177 /* looking for top pipe to program */
2178 if (!pipe_ctx
->top_pipe
)
2179 program_all_pipe_in_tree(dc
, pipe_ctx
, context
);
2182 dm_logger_write(dc
->ctx
->logger
, LOG_BANDWIDTH_CALCS
,
2183 "\n============== Watermark parameters ==============\n"
2184 "a.urgent_ns: %d \n"
2185 "a.cstate_enter_plus_exit: %d \n"
2186 "a.cstate_exit: %d \n"
2187 "a.pstate_change: %d \n"
2188 "a.pte_meta_urgent: %d \n"
2189 "b.urgent_ns: %d \n"
2190 "b.cstate_enter_plus_exit: %d \n"
2191 "b.cstate_exit: %d \n"
2192 "b.pstate_change: %d \n"
2193 "b.pte_meta_urgent: %d \n",
2194 context
->bw
.dcn
.watermarks
.a
.urgent_ns
,
2195 context
->bw
.dcn
.watermarks
.a
.cstate_pstate
.cstate_enter_plus_exit_ns
,
2196 context
->bw
.dcn
.watermarks
.a
.cstate_pstate
.cstate_exit_ns
,
2197 context
->bw
.dcn
.watermarks
.a
.cstate_pstate
.pstate_change_ns
,
2198 context
->bw
.dcn
.watermarks
.a
.pte_meta_urgent_ns
,
2199 context
->bw
.dcn
.watermarks
.b
.urgent_ns
,
2200 context
->bw
.dcn
.watermarks
.b
.cstate_pstate
.cstate_enter_plus_exit_ns
,
2201 context
->bw
.dcn
.watermarks
.b
.cstate_pstate
.cstate_exit_ns
,
2202 context
->bw
.dcn
.watermarks
.b
.cstate_pstate
.pstate_change_ns
,
2203 context
->bw
.dcn
.watermarks
.b
.pte_meta_urgent_ns
2205 dm_logger_write(dc
->ctx
->logger
, LOG_BANDWIDTH_CALCS
,
2206 "\nc.urgent_ns: %d \n"
2207 "c.cstate_enter_plus_exit: %d \n"
2208 "c.cstate_exit: %d \n"
2209 "c.pstate_change: %d \n"
2210 "c.pte_meta_urgent: %d \n"
2211 "d.urgent_ns: %d \n"
2212 "d.cstate_enter_plus_exit: %d \n"
2213 "d.cstate_exit: %d \n"
2214 "d.pstate_change: %d \n"
2215 "d.pte_meta_urgent: %d \n"
2216 "========================================================\n",
2217 context
->bw
.dcn
.watermarks
.c
.urgent_ns
,
2218 context
->bw
.dcn
.watermarks
.c
.cstate_pstate
.cstate_enter_plus_exit_ns
,
2219 context
->bw
.dcn
.watermarks
.c
.cstate_pstate
.cstate_exit_ns
,
2220 context
->bw
.dcn
.watermarks
.c
.cstate_pstate
.pstate_change_ns
,
2221 context
->bw
.dcn
.watermarks
.c
.pte_meta_urgent_ns
,
2222 context
->bw
.dcn
.watermarks
.d
.urgent_ns
,
2223 context
->bw
.dcn
.watermarks
.d
.cstate_pstate
.cstate_enter_plus_exit_ns
,
2224 context
->bw
.dcn
.watermarks
.d
.cstate_pstate
.cstate_exit_ns
,
2225 context
->bw
.dcn
.watermarks
.d
.cstate_pstate
.pstate_change_ns
,
2226 context
->bw
.dcn
.watermarks
.d
.pte_meta_urgent_ns
2229 if (dc
->public.debug
.sanity_checks
)
2230 verify_allow_pstate_change_high(dc
->hwseq
);
2233 static void dcn10_set_bandwidth(
2235 struct validate_context
*context
,
2236 bool decrease_allowed
)
2238 struct dm_pp_clock_for_voltage_req clock
;
2240 if (IS_FPGA_MAXIMUS_DC(dc
->ctx
->dce_environment
))
2243 if (decrease_allowed
|| context
->bw
.dcn
.calc_clk
.dispclk_khz
2244 > dc
->current_context
->bw
.dcn
.cur_clk
.dispclk_khz
) {
2245 dc
->res_pool
->display_clock
->funcs
->set_clock(
2246 dc
->res_pool
->display_clock
,
2247 context
->bw
.dcn
.calc_clk
.dispclk_khz
);
2248 dc
->current_context
->bw
.dcn
.cur_clk
.dispclk_khz
=
2249 context
->bw
.dcn
.calc_clk
.dispclk_khz
;
2251 if (decrease_allowed
|| context
->bw
.dcn
.calc_clk
.dcfclk_khz
2252 > dc
->current_context
->bw
.dcn
.cur_clk
.dcfclk_khz
) {
2253 clock
.clk_type
= DM_PP_CLOCK_TYPE_DCFCLK
;
2254 clock
.clocks_in_khz
= context
->bw
.dcn
.calc_clk
.dcfclk_khz
;
2255 dm_pp_apply_clock_for_voltage_request(dc
->ctx
, &clock
);
2256 dc
->current_context
->bw
.dcn
.cur_clk
.dcfclk_khz
= clock
.clocks_in_khz
;
2257 context
->bw
.dcn
.cur_clk
.dcfclk_khz
= clock
.clocks_in_khz
;
2259 if (decrease_allowed
|| context
->bw
.dcn
.calc_clk
.fclk_khz
2260 > dc
->current_context
->bw
.dcn
.cur_clk
.fclk_khz
) {
2261 clock
.clk_type
= DM_PP_CLOCK_TYPE_FCLK
;
2262 clock
.clocks_in_khz
= context
->bw
.dcn
.calc_clk
.fclk_khz
;
2263 dm_pp_apply_clock_for_voltage_request(dc
->ctx
, &clock
);
2264 dc
->current_context
->bw
.dcn
.calc_clk
.fclk_khz
= clock
.clocks_in_khz
;
2265 context
->bw
.dcn
.cur_clk
.fclk_khz
= clock
.clocks_in_khz
;
2267 if (decrease_allowed
|| context
->bw
.dcn
.calc_clk
.dcfclk_deep_sleep_khz
2268 > dc
->current_context
->bw
.dcn
.cur_clk
.dcfclk_deep_sleep_khz
) {
2269 dc
->current_context
->bw
.dcn
.calc_clk
.dcfclk_deep_sleep_khz
=
2270 context
->bw
.dcn
.calc_clk
.dcfclk_deep_sleep_khz
;
2271 context
->bw
.dcn
.cur_clk
.dcfclk_deep_sleep_khz
=
2272 context
->bw
.dcn
.calc_clk
.dcfclk_deep_sleep_khz
;
2274 /* Decrease in freq is increase in period so opposite comparison for dram_ccm */
2275 if (decrease_allowed
|| context
->bw
.dcn
.calc_clk
.dram_ccm_us
2276 < dc
->current_context
->bw
.dcn
.cur_clk
.dram_ccm_us
) {
2277 dc
->current_context
->bw
.dcn
.calc_clk
.dram_ccm_us
=
2278 context
->bw
.dcn
.calc_clk
.dram_ccm_us
;
2279 context
->bw
.dcn
.cur_clk
.dram_ccm_us
=
2280 context
->bw
.dcn
.calc_clk
.dram_ccm_us
;
2282 if (decrease_allowed
|| context
->bw
.dcn
.calc_clk
.min_active_dram_ccm_us
2283 < dc
->current_context
->bw
.dcn
.cur_clk
.min_active_dram_ccm_us
) {
2284 dc
->current_context
->bw
.dcn
.calc_clk
.min_active_dram_ccm_us
=
2285 context
->bw
.dcn
.calc_clk
.min_active_dram_ccm_us
;
2286 context
->bw
.dcn
.cur_clk
.min_active_dram_ccm_us
=
2287 context
->bw
.dcn
.calc_clk
.min_active_dram_ccm_us
;
2289 dcn10_pplib_apply_display_requirements(dc
, context
);
2291 /* need to fix this function. not doing the right thing here */
2294 static void set_drr(struct pipe_ctx
**pipe_ctx
,
2295 int num_pipes
, int vmin
, int vmax
)
2298 struct drr_params params
= {0};
2300 params
.vertical_total_max
= vmax
;
2301 params
.vertical_total_min
= vmin
;
2303 /* TODO: If multiple pipes are to be supported, you need
2306 for (i
= 0; i
< num_pipes
; i
++) {
2307 pipe_ctx
[i
]->tg
->funcs
->set_drr(pipe_ctx
[i
]->tg
, ¶ms
);
2311 static void get_position(struct pipe_ctx
**pipe_ctx
,
2313 struct crtc_position
*position
)
2317 /* TODO: handle pipes > 1
2319 for (i
= 0; i
< num_pipes
; i
++)
2320 pipe_ctx
[i
]->tg
->funcs
->get_position(pipe_ctx
[i
]->tg
, position
);
2323 static void set_static_screen_control(struct pipe_ctx
**pipe_ctx
,
2324 int num_pipes
, const struct dc_static_screen_events
*events
)
2327 unsigned int value
= 0;
2329 if (events
->surface_update
)
2331 if (events
->cursor_update
)
2334 for (i
= 0; i
< num_pipes
; i
++)
2335 pipe_ctx
[i
]->tg
->funcs
->
2336 set_static_screen_control(pipe_ctx
[i
]->tg
, value
);
2339 static void set_plane_config(
2340 const struct core_dc
*dc
,
2341 struct pipe_ctx
*pipe_ctx
,
2342 struct resource_context
*res_ctx
)
2345 program_gamut_remap(pipe_ctx
);
2348 static void dcn10_config_stereo_parameters(
2349 struct dc_stream
*stream
, struct crtc_stereo_flags
*flags
)
2351 enum view_3d_format view_format
= stream
->view_format
;
2352 enum dc_timing_3d_format timing_3d_format
=\
2353 stream
->timing
.timing_3d_format
;
2354 bool non_stereo_timing
= false;
2356 if (timing_3d_format
== TIMING_3D_FORMAT_NONE
||
2357 timing_3d_format
== TIMING_3D_FORMAT_SIDE_BY_SIDE
||
2358 timing_3d_format
== TIMING_3D_FORMAT_TOP_AND_BOTTOM
)
2359 non_stereo_timing
= true;
2361 if (non_stereo_timing
== false &&
2362 view_format
== VIEW_3D_FORMAT_FRAME_SEQUENTIAL
) {
2364 flags
->PROGRAM_STEREO
= 1;
2365 flags
->PROGRAM_POLARITY
= 1;
2366 if (timing_3d_format
== TIMING_3D_FORMAT_INBAND_FA
||
2367 timing_3d_format
== TIMING_3D_FORMAT_DP_HDMI_INBAND_FA
||
2368 timing_3d_format
== TIMING_3D_FORMAT_SIDEBAND_FA
) {
2369 enum display_dongle_type dongle
= \
2370 stream
->sink
->link
->ddc
->dongle_type
;
2371 if (dongle
== DISPLAY_DONGLE_DP_VGA_CONVERTER
||
2372 dongle
== DISPLAY_DONGLE_DP_DVI_CONVERTER
||
2373 dongle
== DISPLAY_DONGLE_DP_HDMI_CONVERTER
)
2374 flags
->DISABLE_STEREO_DP_SYNC
= 1;
2376 flags
->RIGHT_EYE_POLARITY
=\
2377 stream
->timing
.flags
.RIGHT_EYE_3D_POLARITY
;
2378 if (timing_3d_format
== TIMING_3D_FORMAT_HW_FRAME_PACKING
)
2379 flags
->FRAME_PACKED
= 1;
2385 static void dcn10_setup_stereo(struct pipe_ctx
*pipe_ctx
, struct core_dc
*dc
)
2387 struct crtc_stereo_flags flags
= { 0 };
2388 struct dc_stream
*stream
= pipe_ctx
->stream
;
2390 dcn10_config_stereo_parameters(stream
, &flags
);
2392 pipe_ctx
->opp
->funcs
->opp_set_stereo_polarity(
2394 flags
.PROGRAM_STEREO
== 1 ? true:false,
2395 stream
->timing
.flags
.RIGHT_EYE_3D_POLARITY
== 1 ? true:false);
2397 pipe_ctx
->tg
->funcs
->program_stereo(
2406 static void log_mpc_crc(struct core_dc
*dc
)
2408 struct dc_context
*dc_ctx
= dc
->ctx
;
2409 struct dce_hwseq
*hws
= dc
->hwseq
;
2411 if (REG(MPC_CRC_RESULT_GB
))
2412 DTN_INFO("MPC_CRC_RESULT_GB:%d MPC_CRC_RESULT_C:%d MPC_CRC_RESULT_AR:%d\n",
2413 REG_READ(MPC_CRC_RESULT_GB
), REG_READ(MPC_CRC_RESULT_C
), REG_READ(MPC_CRC_RESULT_AR
));
2414 if (REG(DPP_TOP0_DPP_CRC_VAL_B_A
))
2415 DTN_INFO("DPP_TOP0_DPP_CRC_VAL_B_A:%d DPP_TOP0_DPP_CRC_VAL_R_G:%d\n",
2416 REG_READ(DPP_TOP0_DPP_CRC_VAL_B_A
), REG_READ(DPP_TOP0_DPP_CRC_VAL_R_G
));
2419 static void dcn10_log_hw_state(struct core_dc
*dc
)
2421 struct dc_context
*dc_ctx
= dc
->ctx
;
2422 struct resource_pool
*pool
= dc
->res_pool
;
2427 DTN_INFO("HUBP:\t format \t addr_hi \t width \t height \t rotation \t"
2428 "mirror \t sw_mode \t dcc_en \t blank_en \t ttu_dis \t"
2429 "min_ttu_vblank \t qos_low_wm \t qos_high_wm \n");
2431 for (i
= 0; i
< pool
->pipe_count
; i
++) {
2432 struct mem_input
*mi
= pool
->mis
[i
];
2433 struct dcn_hubp_state s
;
2435 dcn10_mem_input_read_state(TO_DCN10_MEM_INPUT(mi
), &s
);
2437 DTN_INFO("[%d]:\t %xh \t %xh \t %d \t %d \t %xh \t %xh \t "
2438 "%d \t %d \t %d \t %d \t"
2439 "%d \t %d \t %d \n",
2453 s
.qos_level_high_wm
);
2462 static void dcn10_wait_for_mpcc_disconnect(
2464 struct resource_pool
*res_pool
,
2465 struct pipe_ctx
*pipe_ctx
)
2469 if (!pipe_ctx
->opp
|| !pipe_ctx
->mpcc
)
2472 for (i
= 0; i
< MAX_PIPES
; i
++) {
2473 if (pipe_ctx
->opp
->mpcc_disconnect_pending
[i
]) {
2474 pipe_ctx
->mpcc
->funcs
->wait_for_idle(res_pool
->mpcc
[i
]);
2475 pipe_ctx
->opp
->mpcc_disconnect_pending
[i
] = false;
2476 res_pool
->mis
[i
]->funcs
->set_blank(res_pool
->mis
[i
], true);
2477 /*dm_logger_write(dc->ctx->logger, LOG_ERROR,
2478 "[debug_mpo: wait_for_mpcc finished waiting on mpcc %d]\n",
2485 static bool dcn10_dummy_display_power_gating(
2487 uint8_t controller_id
,
2488 struct dc_bios
*dcb
,
2489 enum pipe_gating_control power_gating
)
2494 void dcn10_update_pending_status(struct pipe_ctx
*pipe_ctx
)
2496 struct dc_surface
*surface
= pipe_ctx
->surface
;
2497 struct timing_generator
*tg
= pipe_ctx
->tg
;
2499 if (surface
->ctx
->dc
->debug
.sanity_checks
) {
2500 struct core_dc
*dc
= DC_TO_CORE(surface
->ctx
->dc
);
2502 verify_allow_pstate_change_high(dc
->hwseq
);
2505 if (surface
== NULL
)
2508 surface
->status
.is_flip_pending
=
2509 pipe_ctx
->mi
->funcs
->mem_input_is_flip_pending(
2512 /* DCN we read INUSE address in MI, do we still need this wa? */
2513 if (surface
->status
.is_flip_pending
&&
2514 !surface
->visible
) {
2515 pipe_ctx
->mi
->current_address
=
2516 pipe_ctx
->mi
->request_address
;
2517 BREAK_TO_DEBUGGER();
2520 surface
->status
.current_address
= pipe_ctx
->mi
->current_address
;
2521 if (pipe_ctx
->mi
->current_address
.type
== PLN_ADDR_TYPE_GRPH_STEREO
&&
2522 tg
->funcs
->is_stereo_left_eye
) {
2523 surface
->status
.is_right_eye
=
2524 !tg
->funcs
->is_stereo_left_eye(pipe_ctx
->tg
);
2528 static const struct hw_sequencer_funcs dcn10_funcs
= {
2529 .program_gamut_remap
= program_gamut_remap
,
2530 .program_csc_matrix
= program_csc_matrix
,
2531 .init_hw
= dcn10_init_hw
,
2532 .apply_ctx_to_hw
= dce110_apply_ctx_to_hw
,
2533 .apply_ctx_for_surface
= dcn10_apply_ctx_for_surface
,
2534 .set_plane_config
= set_plane_config
,
2535 .update_plane_addr
= update_plane_addr
,
2536 .update_dchub
= dcn10_update_dchub
,
2537 .update_pending_status
= dcn10_update_pending_status
,
2538 .set_input_transfer_func
= dcn10_set_input_transfer_func
,
2539 .set_output_transfer_func
= dcn10_set_output_transfer_func
,
2540 .power_down
= dce110_power_down
,
2541 .enable_accelerated_mode
= dce110_enable_accelerated_mode
,
2542 .enable_timing_synchronization
= dcn10_enable_timing_synchronization
,
2543 .update_info_frame
= dce110_update_info_frame
,
2544 .enable_stream
= dce110_enable_stream
,
2545 .disable_stream
= dce110_disable_stream
,
2546 .unblank_stream
= dce110_unblank_stream
,
2547 .enable_display_power_gating
= dcn10_dummy_display_power_gating
,
2548 .power_down_front_end
= dcn10_power_down_fe
,
2549 .power_on_front_end
= dcn10_power_on_fe
,
2550 .pipe_control_lock
= dcn10_pipe_control_lock
,
2551 .set_bandwidth
= dcn10_set_bandwidth
,
2552 .reset_hw_ctx_wrap
= reset_hw_ctx_wrap
,
2553 .prog_pixclk_crtc_otg
= dcn10_prog_pixclk_crtc_otg
,
2555 .get_position
= get_position
,
2556 .set_static_screen_control
= set_static_screen_control
,
2557 .setup_stereo
= dcn10_setup_stereo
,
2558 .set_avmute
= dce110_set_avmute
,
2559 .log_hw_state
= dcn10_log_hw_state
,
2560 .wait_for_mpcc_disconnect
= dcn10_wait_for_mpcc_disconnect
2564 void dcn10_hw_sequencer_construct(struct core_dc
*dc
)
2566 dc
->hwss
= dcn10_funcs
;