]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blob - drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
drm/amd/display: mpc block redesign
[mirror_ubuntu-bionic-kernel.git] / drivers / gpu / drm / amd / display / dc / dcn10 / dcn10_hw_sequencer.c
1 /*
2 * Copyright 2016 Advanced Micro Devices, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * Authors: AMD
23 *
24 */
25
26 #include "dm_services.h"
27 #include "core_types.h"
28 #include "resource.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"
33 #include "abm.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"
38 #include "opp.h"
39 #include "ipp.h"
40 #include "mpc.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"
45
46 #define CTX \
47 hws->ctx
48 #define REG(reg)\
49 hws->regs->reg
50
51 #undef FN
52 #define FN(reg_name, field_name) \
53 hws->shifts->field_name, hws->masks->field_name
54
55
56 static void verify_allow_pstate_change_high(
57 struct dce_hwseq *hws)
58 {
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
61 */
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 */
65
66 unsigned int debug_index = 0x7;
67 unsigned int debug_data;
68 unsigned int force_allow_pstate = 0x30;
69 unsigned int i;
70
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
75 */
76 REG_WRITE(DCHUBBUB_ARB_DRAM_STATE_CNTL, 0);
77 forced_pstate_allow = false;
78 }
79
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
100 */
101
102 REG_WRITE(DCHUBBUB_TEST_DEBUG_INDEX, debug_index);
103
104 for (i = 0; i < pstate_wait_timeout_us; i++) {
105 debug_data = REG_READ(DCHUBBUB_TEST_DEBUG_DATA);
106
107 if (debug_data & (1 << 30))
108 return;
109
110 if (max_sampled_pstate_wait_us < i)
111 max_sampled_pstate_wait_us = i;
112
113 udelay(1);
114 }
115
116 /* force pstate allow to prevent system hang
117 * and break to debugger to investigate
118 */
119 REG_WRITE(DCHUBBUB_ARB_DRAM_STATE_CNTL, force_allow_pstate);
120 forced_pstate_allow = true;
121 BREAK_TO_DEBUGGER();
122 }
123
124 static void enable_dppclk(
125 struct dce_hwseq *hws,
126 uint8_t plane_id,
127 uint32_t requested_pix_clk,
128 bool dppclk_div)
129 {
130 dm_logger_write(hws->ctx->logger, LOG_SURFACE,
131 "dppclk_rate_control for pipe %d programed to %d\n",
132 plane_id,
133 dppclk_div);
134
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);
139 else
140 REG_UPDATE(DPP_CONTROL[plane_id],
141 DPP_CLOCK_ENABLE, 1);
142 }
143
144 static void enable_power_gating_plane(
145 struct dce_hwseq *hws,
146 bool enable)
147 {
148 bool force_on = 1; /* disable power gating */
149
150 if (enable)
151 force_on = 0;
152
153 /* DCHUBP0/1/2/3 */
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);
158
159 /* DPP0/1/2/3 */
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);
164 }
165
166 static void disable_vga(
167 struct dce_hwseq *hws)
168 {
169 REG_WRITE(D1VGA_CONTROL, 0);
170 REG_WRITE(D2VGA_CONTROL, 0);
171 REG_WRITE(D3VGA_CONTROL, 0);
172 REG_WRITE(D4VGA_CONTROL, 0);
173 }
174
175 static void dpp_pg_control(
176 struct dce_hwseq *hws,
177 unsigned int dpp_inst,
178 bool power_on)
179 {
180 uint32_t power_gate = power_on ? 0 : 1;
181 uint32_t pwr_status = power_on ? 0 : 2;
182
183 if (hws->ctx->dc->debug.disable_dpp_power_gate)
184 return;
185
186 switch (dpp_inst) {
187 case 0: /* DPP0 */
188 REG_UPDATE(DOMAIN1_PG_CONFIG,
189 DOMAIN1_POWER_GATE, power_gate);
190
191 REG_WAIT(DOMAIN1_PG_STATUS,
192 DOMAIN1_PGFSM_PWR_STATUS, pwr_status, 20000, 200000);
193 break;
194 case 1: /* DPP1 */
195 REG_UPDATE(DOMAIN3_PG_CONFIG,
196 DOMAIN3_POWER_GATE, power_gate);
197
198 REG_WAIT(DOMAIN3_PG_STATUS,
199 DOMAIN3_PGFSM_PWR_STATUS, pwr_status, 20000, 200000);
200 break;
201 case 2: /* DPP2 */
202 REG_UPDATE(DOMAIN5_PG_CONFIG,
203 DOMAIN5_POWER_GATE, power_gate);
204
205 REG_WAIT(DOMAIN5_PG_STATUS,
206 DOMAIN5_PGFSM_PWR_STATUS, pwr_status, 20000, 200000);
207 break;
208 case 3: /* DPP3 */
209 REG_UPDATE(DOMAIN7_PG_CONFIG,
210 DOMAIN7_POWER_GATE, power_gate);
211
212 REG_WAIT(DOMAIN7_PG_STATUS,
213 DOMAIN7_PGFSM_PWR_STATUS, pwr_status, 20000, 200000);
214 break;
215 default:
216 BREAK_TO_DEBUGGER();
217 break;
218 }
219 }
220
221 static uint32_t convert_and_clamp(
222 uint32_t wm_ns,
223 uint32_t refclk_mhz,
224 uint32_t clamp_value)
225 {
226 uint32_t ret_val = 0;
227 ret_val = wm_ns * refclk_mhz;
228 ret_val /= 1000;
229
230 if (ret_val > clamp_value)
231 ret_val = clamp_value;
232
233 return ret_val;
234 }
235
236 static void program_watermarks(
237 struct dce_hwseq *hws,
238 struct dcn_watermark_set *watermarks,
239 unsigned int refclk_mhz)
240 {
241 uint32_t force_en = hws->ctx->dc->debug.disable_stutter ? 1 : 0;
242 /*
243 * Need to clamp to max of the register values (i.e. no wrap)
244 * for dcn1, all wm registers are 21-bit wide
245 */
246 uint32_t prog_wm_value;
247
248 /* Repeat for water mark set A, B, C and D. */
249 /* clock state A */
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);
253
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);
258
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);
266
267
268 prog_wm_value = convert_and_clamp(
269 watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns,
270 refclk_mhz, 0x1fffff);
271
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);
277
278
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);
287
288
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);
297
298
299 /* clock state B */
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);
307
308
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);
317
318
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);
327
328
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);
337
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);
346
347 /* clock state C */
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);
355
356
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);
365
366
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);
375
376
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);
385
386
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);
395
396 /* clock state D */
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);
404
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);
413
414
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);
423
424
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);
433
434
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);
443
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);
452
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);
456
457 #if 0
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);
461 #endif
462 }
463
464
465 static void dcn10_update_dchub(
466 struct dce_hwseq *hws,
467 struct dchub_init_data *dh_data)
468 {
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,
474 SDPIF_FB_TOP, 0);
475
476 REG_UPDATE(DCHUBBUB_SDPIF_FB_BASE,
477 SDPIF_FB_BASE, 0x0FFFF);
478
479 REG_UPDATE(DCHUBBUB_SDPIF_AGP_BASE,
480 SDPIF_AGP_BASE, dh_data->zfb_phys_addr_base >> 22);
481
482 REG_UPDATE(DCHUBBUB_SDPIF_AGP_BOT,
483 SDPIF_AGP_BOT, dh_data->zfb_mc_base_addr >> 22);
484
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);
488 break;
489 case FRAME_BUFFER_MODE_MIXED_ZFB_AND_LOCAL:
490 /*Should not touch FB LOCATION (done by VBIOS on AsicInit table)*/
491
492 REG_UPDATE(DCHUBBUB_SDPIF_AGP_BASE,
493 SDPIF_AGP_BASE, dh_data->zfb_phys_addr_base >> 22);
494
495 REG_UPDATE(DCHUBBUB_SDPIF_AGP_BOT,
496 SDPIF_AGP_BOT, dh_data->zfb_mc_base_addr >> 22);
497
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);
501 break;
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,
505 SDPIF_AGP_BASE, 0);
506
507 REG_UPDATE(DCHUBBUB_SDPIF_AGP_BOT,
508 SDPIF_AGP_BOT, 0X03FFFF);
509
510 REG_UPDATE(DCHUBBUB_SDPIF_AGP_TOP,
511 SDPIF_AGP_TOP, 0);
512 break;
513 default:
514 break;
515 }
516
517 dh_data->dchub_initialzied = true;
518 dh_data->dchub_info_valid = false;
519 }
520
521 static void hubp_pg_control(
522 struct dce_hwseq *hws,
523 unsigned int hubp_inst,
524 bool power_on)
525 {
526 uint32_t power_gate = power_on ? 0 : 1;
527 uint32_t pwr_status = power_on ? 0 : 2;
528
529 if (hws->ctx->dc->debug.disable_hubp_power_gate)
530 return;
531
532 switch (hubp_inst) {
533 case 0: /* DCHUBP0 */
534 REG_UPDATE(DOMAIN0_PG_CONFIG,
535 DOMAIN0_POWER_GATE, power_gate);
536
537 REG_WAIT(DOMAIN0_PG_STATUS,
538 DOMAIN0_PGFSM_PWR_STATUS, pwr_status, 20000, 200000);
539 break;
540 case 1: /* DCHUBP1 */
541 REG_UPDATE(DOMAIN2_PG_CONFIG,
542 DOMAIN2_POWER_GATE, power_gate);
543
544 REG_WAIT(DOMAIN2_PG_STATUS,
545 DOMAIN2_PGFSM_PWR_STATUS, pwr_status, 20000, 200000);
546 break;
547 case 2: /* DCHUBP2 */
548 REG_UPDATE(DOMAIN4_PG_CONFIG,
549 DOMAIN4_POWER_GATE, power_gate);
550
551 REG_WAIT(DOMAIN4_PG_STATUS,
552 DOMAIN4_PGFSM_PWR_STATUS, pwr_status, 20000, 200000);
553 break;
554 case 3: /* DCHUBP3 */
555 REG_UPDATE(DOMAIN6_PG_CONFIG,
556 DOMAIN6_POWER_GATE, power_gate);
557
558 REG_WAIT(DOMAIN6_PG_STATUS,
559 DOMAIN6_PGFSM_PWR_STATUS, pwr_status, 20000, 200000);
560 break;
561 default:
562 BREAK_TO_DEBUGGER();
563 break;
564 }
565 }
566
567 static void power_on_plane(
568 struct dce_hwseq *hws,
569 int plane_id)
570 {
571 REG_SET(DC_IP_REQUEST_CNTL, 0,
572 IP_REQUEST_EN, 1);
573 dpp_pg_control(hws, plane_id, true);
574 hubp_pg_control(hws, plane_id, true);
575 REG_SET(DC_IP_REQUEST_CNTL, 0,
576 IP_REQUEST_EN, 0);
577 dm_logger_write(hws->ctx->logger, LOG_DC,
578 "Un-gated front end for pipe %d\n", plane_id);
579 }
580
581 static void bios_golden_init(struct core_dc *dc)
582 {
583 struct dc_bios *bp = dc->ctx->dc_bios;
584 int i;
585
586 /* initialize dcn global */
587 bp->funcs->enable_disp_power_gating(bp,
588 CONTROLLER_ID_D0, ASIC_PIPE_INIT);
589
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);
594 }
595 }
596
597 static void dcn10_init_hw(struct core_dc *dc)
598 {
599 int i;
600 struct abm *abm = dc->res_pool->abm;
601 struct dce_hwseq *hws = dc->hwseq;
602
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);
607
608 if (!dc->public.debug.disable_clock_gate) {
609 /* enable all DCN clock gating */
610 REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0);
611
612 REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0);
613
614 REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0);
615 }
616
617 enable_power_gating_plane(dc->hwseq, true);
618 return;
619 }
620 /* end of FPGA. Below if real ASIC */
621
622 bios_golden_init(dc);
623
624 disable_vga(dc->hwseq);
625
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).
630 */
631 struct dc_link *link = dc->links[i];
632
633 link->link_enc->funcs->hw_init(link->link_enc);
634 }
635
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
640 xfm->funcs->transform_reset(xfm);
641 dc->res_pool->mpc->funcs->remove(
642 dc->res_pool->mpc, dc->res_pool->opps[i], i);
643
644 /* Blank controller using driver code instead of
645 * command table.
646 */
647 tg->funcs->set_blank(tg, true);
648 hwss_wait_for_blank_complete(tg);
649 }
650
651 for (i = 0; i < dc->res_pool->audio_count; i++) {
652 struct audio *audio = dc->res_pool->audios[i];
653
654 audio->funcs->hw_init(audio);
655 }
656
657 if (abm != NULL) {
658 abm->funcs->init_backlight(abm);
659 abm->funcs->abm_init(abm);
660 }
661
662 /* power AFMT HDMI memory TODO: may move to dis/en output save power*/
663 REG_WRITE(DIO_MEM_PWR_CTRL, 0);
664
665 if (!dc->public.debug.disable_clock_gate) {
666 /* enable all DCN clock gating */
667 REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0);
668
669 REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0);
670
671 REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0);
672 }
673
674 enable_power_gating_plane(dc->hwseq, true);
675 }
676
677 static enum dc_status dcn10_prog_pixclk_crtc_otg(
678 struct pipe_ctx *pipe_ctx,
679 struct validate_context *context,
680 struct core_dc *dc)
681 {
682 struct dc_stream *stream = pipe_ctx->stream;
683 enum dc_color_space color_space;
684 struct tg_color black_color = {0};
685 bool enableStereo = stream->timing.timing_3d_format == TIMING_3D_FORMAT_NONE ?
686 false:true;
687 bool rightEyePolarity = stream->timing.flags.RIGHT_EYE_3D_POLARITY;
688
689
690 /* by upper caller loop, pipe0 is parent pipe and be called first.
691 * back end is set up by for pipe0. Other children pipe share back end
692 * with pipe 0. No program is needed.
693 */
694 if (pipe_ctx->top_pipe != NULL)
695 return DC_OK;
696
697 /* TODO check if timing_changed, disable stream if timing changed */
698
699 /* HW program guide assume display already disable
700 * by unplug sequence. OTG assume stop.
701 */
702 pipe_ctx->tg->funcs->enable_optc_clock(pipe_ctx->tg, true);
703
704 if (false == pipe_ctx->clock_source->funcs->program_pix_clk(
705 pipe_ctx->clock_source,
706 &pipe_ctx->pix_clk_params,
707 &pipe_ctx->pll_settings)) {
708 BREAK_TO_DEBUGGER();
709 return DC_ERROR_UNEXPECTED;
710 }
711 pipe_ctx->tg->dlg_otg_param.vready_offset = pipe_ctx->pipe_dlg_param.vready_offset;
712 pipe_ctx->tg->dlg_otg_param.vstartup_start = pipe_ctx->pipe_dlg_param.vstartup_start;
713 pipe_ctx->tg->dlg_otg_param.vupdate_offset = pipe_ctx->pipe_dlg_param.vupdate_offset;
714 pipe_ctx->tg->dlg_otg_param.vupdate_width = pipe_ctx->pipe_dlg_param.vupdate_width;
715
716 pipe_ctx->tg->dlg_otg_param.signal = pipe_ctx->stream->signal;
717
718 pipe_ctx->tg->funcs->program_timing(
719 pipe_ctx->tg,
720 &stream->timing,
721 true);
722
723 pipe_ctx->opp->funcs->opp_set_stereo_polarity(
724 pipe_ctx->opp,
725 enableStereo,
726 rightEyePolarity);
727
728 #if 0 /* move to after enable_crtc */
729 /* TODO: OPP FMT, ABM. etc. should be done here. */
730 /* or FPGA now. instance 0 only. TODO: move to opp.c */
731
732 inst_offset = reg_offsets[pipe_ctx->tg->inst].fmt;
733
734 pipe_ctx->opp->funcs->opp_program_fmt(
735 pipe_ctx->opp,
736 &stream->bit_depth_params,
737 &stream->clamping);
738 #endif
739 /* program otg blank color */
740 color_space = stream->output_color_space;
741 color_space_to_black_color(dc, color_space, &black_color);
742 pipe_ctx->tg->funcs->set_blank_color(
743 pipe_ctx->tg,
744 &black_color);
745
746 pipe_ctx->tg->funcs->set_blank(pipe_ctx->tg, true);
747 hwss_wait_for_blank_complete(pipe_ctx->tg);
748
749 /* VTG is within DCHUB command block. DCFCLK is always on */
750 if (false == pipe_ctx->tg->funcs->enable_crtc(pipe_ctx->tg)) {
751 BREAK_TO_DEBUGGER();
752 return DC_ERROR_UNEXPECTED;
753 }
754
755 /* TODO program crtc source select for non-virtual signal*/
756 /* TODO program FMT */
757 /* TODO setup link_enc */
758 /* TODO set stream attributes */
759 /* TODO program audio */
760 /* TODO enable stream if timing changed */
761 /* TODO unblank stream if DP */
762
763 return DC_OK;
764 }
765
766 static void reset_back_end_for_pipe(
767 struct core_dc *dc,
768 struct pipe_ctx *pipe_ctx,
769 struct validate_context *context)
770 {
771 int i;
772
773 if (pipe_ctx->stream_enc == NULL) {
774 pipe_ctx->stream = NULL;
775 return;
776 }
777
778 /* TODOFPGA break core_link_disable_stream into 2 functions:
779 * disable_stream and disable_link. disable_link will disable PHYPLL
780 * which is used by otg. Move disable_link after disable_crtc
781 */
782 if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment))
783 core_link_disable_stream(pipe_ctx);
784
785 /* by upper caller loop, parent pipe: pipe0, will be reset last.
786 * back end share by all pipes and will be disable only when disable
787 * parent pipe.
788 */
789 if (pipe_ctx->top_pipe == NULL) {
790 pipe_ctx->tg->funcs->disable_crtc(pipe_ctx->tg);
791
792 pipe_ctx->tg->funcs->enable_optc_clock(pipe_ctx->tg, false);
793 }
794
795 if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment))
796 resource_unreference_clock_source(
797 &context->res_ctx, dc->res_pool,
798 &pipe_ctx->clock_source);
799
800 for (i = 0; i < dc->res_pool->pipe_count; i++)
801 if (&dc->current_context->res_ctx.pipe_ctx[i] == pipe_ctx)
802 break;
803
804 if (i == dc->res_pool->pipe_count)
805 return;
806
807 pipe_ctx->stream = NULL;
808 dm_logger_write(dc->ctx->logger, LOG_DC,
809 "Reset back end for pipe %d, tg:%d\n",
810 pipe_ctx->pipe_idx, pipe_ctx->tg->inst);
811 }
812
813 /* trigger HW to start disconnect plane from stream on the next vsync */
814 static void plane_atomic_disconnect(struct core_dc *dc,
815 int fe_idx)
816 {
817 struct mem_input *mi = dc->res_pool->mis[fe_idx];
818 struct mpc *mpc = dc->res_pool->mpc;
819 int opp_id, z_idx;
820 int mpcc_id = -1;
821
822 /* look at tree rather than mi here to know if we already reset */
823 for (opp_id = 0; opp_id < dc->res_pool->pipe_count; opp_id++) {
824 struct output_pixel_processor *opp = dc->res_pool->opps[opp_id];
825
826 for (z_idx = 0; z_idx < opp->mpc_tree.num_pipes; z_idx++) {
827 if (opp->mpc_tree.dpp[z_idx] == fe_idx) {
828 mpcc_id = opp->mpc_tree.mpcc[z_idx];
829 break;
830 }
831 }
832 if (mpcc_id != -1)
833 break;
834 }
835 /*Already reset*/
836 if (opp_id == dc->res_pool->pipe_count)
837 return;
838
839 if (dc->public.debug.sanity_checks)
840 verify_allow_pstate_change_high(dc->hwseq);
841 mi->funcs->dcc_control(mi, false, false);
842 if (dc->public.debug.sanity_checks)
843 verify_allow_pstate_change_high(dc->hwseq);
844
845 mpc->funcs->remove(mpc, dc->res_pool->opps[opp_id], fe_idx);
846 }
847
848 /* disable HW used by plane.
849 * note: cannot disable until disconnect is complete */
850 static void plane_atomic_disable(struct core_dc *dc,
851 int fe_idx)
852 {
853 struct dce_hwseq *hws = dc->hwseq;
854 struct mem_input *mi = dc->res_pool->mis[fe_idx];
855 struct mpc *mpc = dc->res_pool->mpc;
856
857 if (mi->opp_id == 0xf)
858 return;
859
860 mpc->funcs->wait_for_idle(mpc, mi->mpcc_id);
861 dc->res_pool->opps[mi->opp_id]->mpcc_disconnect_pending[mi->mpcc_id] = false;
862 /*dm_logger_write(dc->ctx->logger, LOG_ERROR,
863 "[debug_mpo: atomic disable finished on mpcc %d]\n",
864 fe_idx);*/
865
866 mi->funcs->set_blank(mi, true);
867 /*todo: unhack this*/
868 mi->opp_id = 0xf;
869 mi->mpcc_id = 0xf;
870
871 if (dc->public.debug.sanity_checks)
872 verify_allow_pstate_change_high(dc->hwseq);
873
874 REG_UPDATE(HUBP_CLK_CNTL[fe_idx],
875 HUBP_CLOCK_ENABLE, 0);
876 REG_UPDATE(DPP_CONTROL[fe_idx],
877 DPP_CLOCK_ENABLE, 0);
878
879 if (dc->res_pool->opps[mi->opp_id]->mpc_tree.num_pipes == 0)
880 REG_UPDATE(OPP_PIPE_CONTROL[mi->opp_id],
881 OPP_PIPE_CLOCK_EN, 0);
882
883 if (dc->public.debug.sanity_checks)
884 verify_allow_pstate_change_high(dc->hwseq);
885 }
886
887 /*
888 * kill power to plane hw
889 * note: cannot power down until plane is disable
890 */
891 static void plane_atomic_power_down(struct core_dc *dc, int fe_idx)
892 {
893 struct dce_hwseq *hws = dc->hwseq;
894 struct transform *xfm = dc->res_pool->transforms[fe_idx];
895
896 REG_SET(DC_IP_REQUEST_CNTL, 0,
897 IP_REQUEST_EN, 1);
898 dpp_pg_control(hws, fe_idx, false);
899 hubp_pg_control(hws, fe_idx, false);
900 xfm->funcs->transform_reset(xfm);
901 REG_SET(DC_IP_REQUEST_CNTL, 0,
902 IP_REQUEST_EN, 0);
903 dm_logger_write(dc->ctx->logger, LOG_DC,
904 "Power gated front end %d\n", fe_idx);
905
906 if (dc->public.debug.sanity_checks)
907 verify_allow_pstate_change_high(dc->hwseq);
908 }
909
910
911 static void reset_front_end(
912 struct core_dc *dc,
913 int fe_idx)
914 {
915 struct dce_hwseq *hws = dc->hwseq;
916 struct timing_generator *tg;
917 int opp_id = dc->res_pool->mis[fe_idx]->opp_id;
918
919 /*Already reset*/
920 if (opp_id == 0xf)
921 return;
922
923 tg = dc->res_pool->timing_generators[opp_id];
924 tg->funcs->lock(tg);
925
926 plane_atomic_disconnect(dc, fe_idx);
927
928 REG_UPDATE(OTG_GLOBAL_SYNC_STATUS[tg->inst], VUPDATE_NO_LOCK_EVENT_CLEAR, 1);
929 tg->funcs->unlock(tg);
930
931 if (dc->public.debug.sanity_checks)
932 verify_allow_pstate_change_high(hws);
933
934 if (tg->ctx->dce_environment != DCE_ENV_FPGA_MAXIMUS)
935 REG_WAIT(OTG_GLOBAL_SYNC_STATUS[tg->inst],
936 VUPDATE_NO_LOCK_EVENT_OCCURRED, 1, 20000, 200000);
937
938 plane_atomic_disable(dc, fe_idx);
939
940 dm_logger_write(dc->ctx->logger, LOG_DC,
941 "Reset front end %d\n",
942 fe_idx);
943 }
944
945 static void dcn10_power_down_fe(struct core_dc *dc, int fe_idx)
946 {
947 struct dce_hwseq *hws = dc->hwseq;
948 struct transform *xfm = dc->res_pool->transforms[fe_idx];
949
950 reset_front_end(dc, fe_idx);
951
952 REG_SET(DC_IP_REQUEST_CNTL, 0,
953 IP_REQUEST_EN, 1);
954 dpp_pg_control(hws, fe_idx, false);
955 hubp_pg_control(hws, fe_idx, false);
956 xfm->funcs->transform_reset(xfm);
957 REG_SET(DC_IP_REQUEST_CNTL, 0,
958 IP_REQUEST_EN, 0);
959 dm_logger_write(dc->ctx->logger, LOG_DC,
960 "Power gated front end %d\n", fe_idx);
961
962 if (dc->public.debug.sanity_checks)
963 verify_allow_pstate_change_high(dc->hwseq);
964 }
965
966 static void reset_hw_ctx_wrap(
967 struct core_dc *dc,
968 struct validate_context *context)
969 {
970 int i;
971
972 /* Reset Front End*/
973 /* Lock*/
974 for (i = 0; i < dc->res_pool->pipe_count; i++) {
975 struct pipe_ctx *cur_pipe_ctx = &dc->current_context->res_ctx.pipe_ctx[i];
976 struct timing_generator *tg = cur_pipe_ctx->tg;
977
978 if (cur_pipe_ctx->stream)
979 tg->funcs->lock(tg);
980 }
981 /* Disconnect*/
982 for (i = dc->res_pool->pipe_count - 1; i >= 0 ; i--) {
983 struct pipe_ctx *pipe_ctx_old =
984 &dc->current_context->res_ctx.pipe_ctx[i];
985 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
986
987 if (!pipe_ctx->stream ||
988 !pipe_ctx->surface ||
989 pipe_need_reprogram(pipe_ctx_old, pipe_ctx)) {
990
991 plane_atomic_disconnect(dc, i);
992 }
993 }
994 /* Unlock*/
995 for (i = dc->res_pool->pipe_count - 1; i >= 0; i--) {
996 struct pipe_ctx *cur_pipe_ctx = &dc->current_context->res_ctx.pipe_ctx[i];
997 struct timing_generator *tg = cur_pipe_ctx->tg;
998
999 if (cur_pipe_ctx->stream)
1000 tg->funcs->unlock(tg);
1001 }
1002
1003 /* Disable and Powerdown*/
1004 for (i = dc->res_pool->pipe_count - 1; i >= 0 ; i--) {
1005 struct pipe_ctx *pipe_ctx_old =
1006 &dc->current_context->res_ctx.pipe_ctx[i];
1007 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
1008
1009 /*if (!pipe_ctx_old->stream)
1010 continue;*/
1011
1012 if (pipe_ctx->stream && pipe_ctx->surface
1013 && !pipe_need_reprogram(pipe_ctx_old, pipe_ctx))
1014 continue;
1015
1016 plane_atomic_disable(dc, i);
1017
1018 if (!pipe_ctx->stream || !pipe_ctx->surface)
1019 plane_atomic_power_down(dc, i);
1020 }
1021
1022 /* Reset Back End*/
1023 for (i = dc->res_pool->pipe_count - 1; i >= 0 ; i--) {
1024 struct pipe_ctx *pipe_ctx_old =
1025 &dc->current_context->res_ctx.pipe_ctx[i];
1026 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
1027
1028 if (!pipe_ctx_old->stream)
1029 continue;
1030
1031 if (!pipe_ctx->stream ||
1032 pipe_need_reprogram(pipe_ctx_old, pipe_ctx))
1033 reset_back_end_for_pipe(dc, pipe_ctx_old, dc->current_context);
1034 }
1035 }
1036
1037 static bool patch_address_for_sbs_tb_stereo(
1038 struct pipe_ctx *pipe_ctx, PHYSICAL_ADDRESS_LOC *addr)
1039 {
1040 struct dc_surface *surface = pipe_ctx->surface;
1041 bool sec_split = pipe_ctx->top_pipe &&
1042 pipe_ctx->top_pipe->surface == pipe_ctx->surface;
1043 if (sec_split && surface->address.type == PLN_ADDR_TYPE_GRPH_STEREO &&
1044 (pipe_ctx->stream->timing.timing_3d_format ==
1045 TIMING_3D_FORMAT_SIDE_BY_SIDE ||
1046 pipe_ctx->stream->timing.timing_3d_format ==
1047 TIMING_3D_FORMAT_TOP_AND_BOTTOM)) {
1048 *addr = surface->address.grph_stereo.left_addr;
1049 surface->address.grph_stereo.left_addr =
1050 surface->address.grph_stereo.right_addr;
1051 return true;
1052 } else {
1053 if (pipe_ctx->stream->view_format != VIEW_3D_FORMAT_NONE &&
1054 surface->address.type != PLN_ADDR_TYPE_GRPH_STEREO) {
1055 surface->address.type = PLN_ADDR_TYPE_GRPH_STEREO;
1056 surface->address.grph_stereo.right_addr =
1057 surface->address.grph_stereo.left_addr;
1058 }
1059 }
1060 return false;
1061 }
1062
1063 static void update_plane_addr(const struct core_dc *dc, struct pipe_ctx *pipe_ctx)
1064 {
1065 bool addr_patched = false;
1066 PHYSICAL_ADDRESS_LOC addr;
1067 struct dc_surface *surface = pipe_ctx->surface;
1068
1069 if (surface == NULL)
1070 return;
1071 addr_patched = patch_address_for_sbs_tb_stereo(pipe_ctx, &addr);
1072 pipe_ctx->mi->funcs->mem_input_program_surface_flip_and_addr(
1073 pipe_ctx->mi,
1074 &surface->address,
1075 surface->flip_immediate);
1076 surface->status.requested_address = surface->address;
1077 if (addr_patched)
1078 pipe_ctx->surface->address.grph_stereo.left_addr = addr;
1079 }
1080
1081 static bool dcn10_set_input_transfer_func(
1082 struct pipe_ctx *pipe_ctx, const struct dc_surface *surface)
1083 {
1084 struct input_pixel_processor *ipp = pipe_ctx->ipp;
1085 const struct dc_transfer_func *tf = NULL;
1086 bool result = true;
1087
1088 if (ipp == NULL)
1089 return false;
1090
1091 if (surface->in_transfer_func)
1092 tf = surface->in_transfer_func;
1093
1094 if (surface->gamma_correction && dce_use_lut(surface))
1095 ipp->funcs->ipp_program_input_lut(ipp,
1096 surface->gamma_correction);
1097
1098 if (tf == NULL)
1099 ipp->funcs->ipp_set_degamma(ipp, IPP_DEGAMMA_MODE_BYPASS);
1100 else if (tf->type == TF_TYPE_PREDEFINED) {
1101 switch (tf->tf) {
1102 case TRANSFER_FUNCTION_SRGB:
1103 ipp->funcs->ipp_set_degamma(ipp,
1104 IPP_DEGAMMA_MODE_HW_sRGB);
1105 break;
1106 case TRANSFER_FUNCTION_BT709:
1107 ipp->funcs->ipp_set_degamma(ipp,
1108 IPP_DEGAMMA_MODE_HW_xvYCC);
1109 break;
1110 case TRANSFER_FUNCTION_LINEAR:
1111 ipp->funcs->ipp_set_degamma(ipp,
1112 IPP_DEGAMMA_MODE_BYPASS);
1113 break;
1114 case TRANSFER_FUNCTION_PQ:
1115 result = false;
1116 break;
1117 default:
1118 result = false;
1119 break;
1120 }
1121 } else if (tf->type == TF_TYPE_BYPASS) {
1122 ipp->funcs->ipp_set_degamma(ipp, IPP_DEGAMMA_MODE_BYPASS);
1123 } else {
1124 /*TF_TYPE_DISTRIBUTED_POINTS*/
1125 result = false;
1126 }
1127
1128 return result;
1129 }
1130 /*modify the method to handle rgb for arr_points*/
1131 static bool convert_to_custom_float(
1132 struct pwl_result_data *rgb_resulted,
1133 struct curve_points *arr_points,
1134 uint32_t hw_points_num)
1135 {
1136 struct custom_float_format fmt;
1137
1138 struct pwl_result_data *rgb = rgb_resulted;
1139
1140 uint32_t i = 0;
1141
1142 fmt.exponenta_bits = 6;
1143 fmt.mantissa_bits = 12;
1144 fmt.sign = false;
1145
1146 if (!convert_to_custom_float_format(
1147 arr_points[0].x,
1148 &fmt,
1149 &arr_points[0].custom_float_x)) {
1150 BREAK_TO_DEBUGGER();
1151 return false;
1152 }
1153
1154 if (!convert_to_custom_float_format(
1155 arr_points[0].offset,
1156 &fmt,
1157 &arr_points[0].custom_float_offset)) {
1158 BREAK_TO_DEBUGGER();
1159 return false;
1160 }
1161
1162 if (!convert_to_custom_float_format(
1163 arr_points[0].slope,
1164 &fmt,
1165 &arr_points[0].custom_float_slope)) {
1166 BREAK_TO_DEBUGGER();
1167 return false;
1168 }
1169
1170 fmt.mantissa_bits = 10;
1171 fmt.sign = false;
1172
1173 if (!convert_to_custom_float_format(
1174 arr_points[1].x,
1175 &fmt,
1176 &arr_points[1].custom_float_x)) {
1177 BREAK_TO_DEBUGGER();
1178 return false;
1179 }
1180
1181 if (!convert_to_custom_float_format(
1182 arr_points[1].y,
1183 &fmt,
1184 &arr_points[1].custom_float_y)) {
1185 BREAK_TO_DEBUGGER();
1186 return false;
1187 }
1188
1189 if (!convert_to_custom_float_format(
1190 arr_points[1].slope,
1191 &fmt,
1192 &arr_points[1].custom_float_slope)) {
1193 BREAK_TO_DEBUGGER();
1194 return false;
1195 }
1196
1197 fmt.mantissa_bits = 12;
1198 fmt.sign = true;
1199
1200 while (i != hw_points_num) {
1201 if (!convert_to_custom_float_format(
1202 rgb->red,
1203 &fmt,
1204 &rgb->red_reg)) {
1205 BREAK_TO_DEBUGGER();
1206 return false;
1207 }
1208
1209 if (!convert_to_custom_float_format(
1210 rgb->green,
1211 &fmt,
1212 &rgb->green_reg)) {
1213 BREAK_TO_DEBUGGER();
1214 return false;
1215 }
1216
1217 if (!convert_to_custom_float_format(
1218 rgb->blue,
1219 &fmt,
1220 &rgb->blue_reg)) {
1221 BREAK_TO_DEBUGGER();
1222 return false;
1223 }
1224
1225 if (!convert_to_custom_float_format(
1226 rgb->delta_red,
1227 &fmt,
1228 &rgb->delta_red_reg)) {
1229 BREAK_TO_DEBUGGER();
1230 return false;
1231 }
1232
1233 if (!convert_to_custom_float_format(
1234 rgb->delta_green,
1235 &fmt,
1236 &rgb->delta_green_reg)) {
1237 BREAK_TO_DEBUGGER();
1238 return false;
1239 }
1240
1241 if (!convert_to_custom_float_format(
1242 rgb->delta_blue,
1243 &fmt,
1244 &rgb->delta_blue_reg)) {
1245 BREAK_TO_DEBUGGER();
1246 return false;
1247 }
1248
1249 ++rgb;
1250 ++i;
1251 }
1252
1253 return true;
1254 }
1255 #define MAX_REGIONS_NUMBER 34
1256 #define MAX_LOW_POINT 25
1257 #define NUMBER_SEGMENTS 32
1258
1259 static bool dcn10_translate_regamma_to_hw_format(const struct dc_transfer_func
1260 *output_tf, struct pwl_params *regamma_params)
1261 {
1262 struct curve_points *arr_points;
1263 struct pwl_result_data *rgb_resulted;
1264 struct pwl_result_data *rgb;
1265 struct pwl_result_data *rgb_plus_1;
1266 struct fixed31_32 y_r;
1267 struct fixed31_32 y_g;
1268 struct fixed31_32 y_b;
1269 struct fixed31_32 y1_min;
1270 struct fixed31_32 y3_max;
1271
1272 int32_t segment_start, segment_end;
1273 int32_t i;
1274 uint32_t j, k, seg_distr[MAX_REGIONS_NUMBER], increment, start_index, hw_points;
1275
1276 if (output_tf == NULL || regamma_params == NULL ||
1277 output_tf->type == TF_TYPE_BYPASS)
1278 return false;
1279
1280 arr_points = regamma_params->arr_points;
1281 rgb_resulted = regamma_params->rgb_resulted;
1282 hw_points = 0;
1283
1284 memset(regamma_params, 0, sizeof(struct pwl_params));
1285 memset(seg_distr, 0, sizeof(seg_distr));
1286
1287 if (output_tf->tf == TRANSFER_FUNCTION_PQ) {
1288 /* 32 segments
1289 * segments are from 2^-25 to 2^7
1290 */
1291 for (i = 0; i < 32 ; i++)
1292 seg_distr[i] = 3;
1293
1294 segment_start = -25;
1295 segment_end = 7;
1296 } else {
1297 /* 10 segments
1298 * segment is from 2^-10 to 2^0
1299 * There are less than 256 points, for optimization
1300 */
1301 seg_distr[0] = 3;
1302 seg_distr[1] = 4;
1303 seg_distr[2] = 4;
1304 seg_distr[3] = 4;
1305 seg_distr[4] = 4;
1306 seg_distr[5] = 4;
1307 seg_distr[6] = 4;
1308 seg_distr[7] = 4;
1309 seg_distr[8] = 5;
1310 seg_distr[9] = 5;
1311
1312 segment_start = -10;
1313 segment_end = 0;
1314 }
1315
1316 for (i = segment_end - segment_start; i < MAX_REGIONS_NUMBER ; i++)
1317 seg_distr[i] = -1;
1318
1319 for (k = 0; k < MAX_REGIONS_NUMBER; k++) {
1320 if (seg_distr[k] != -1)
1321 hw_points += (1 << seg_distr[k]);
1322 }
1323
1324 j = 0;
1325 for (k = 0; k < (segment_end - segment_start); k++) {
1326 increment = NUMBER_SEGMENTS / (1 << seg_distr[k]);
1327 start_index = (segment_start + k + MAX_LOW_POINT) * NUMBER_SEGMENTS;
1328 for (i = start_index; i < start_index + NUMBER_SEGMENTS; i += increment) {
1329 if (j == hw_points - 1)
1330 break;
1331 rgb_resulted[j].red = output_tf->tf_pts.red[i];
1332 rgb_resulted[j].green = output_tf->tf_pts.green[i];
1333 rgb_resulted[j].blue = output_tf->tf_pts.blue[i];
1334 j++;
1335 }
1336 }
1337
1338 /* last point */
1339 start_index = (segment_end + MAX_LOW_POINT) * NUMBER_SEGMENTS;
1340 rgb_resulted[hw_points - 1].red =
1341 output_tf->tf_pts.red[start_index];
1342 rgb_resulted[hw_points - 1].green =
1343 output_tf->tf_pts.green[start_index];
1344 rgb_resulted[hw_points - 1].blue =
1345 output_tf->tf_pts.blue[start_index];
1346
1347 arr_points[0].x = dal_fixed31_32_pow(dal_fixed31_32_from_int(2),
1348 dal_fixed31_32_from_int(segment_start));
1349 arr_points[1].x = dal_fixed31_32_pow(dal_fixed31_32_from_int(2),
1350 dal_fixed31_32_from_int(segment_end));
1351 arr_points[2].x = dal_fixed31_32_pow(dal_fixed31_32_from_int(2),
1352 dal_fixed31_32_from_int(segment_end));
1353
1354 y_r = rgb_resulted[0].red;
1355 y_g = rgb_resulted[0].green;
1356 y_b = rgb_resulted[0].blue;
1357
1358 y1_min = dal_fixed31_32_min(y_r, dal_fixed31_32_min(y_g, y_b));
1359
1360 arr_points[0].y = y1_min;
1361 arr_points[0].slope = dal_fixed31_32_div(
1362 arr_points[0].y,
1363 arr_points[0].x);
1364 y_r = rgb_resulted[hw_points - 1].red;
1365 y_g = rgb_resulted[hw_points - 1].green;
1366 y_b = rgb_resulted[hw_points - 1].blue;
1367
1368 /* see comment above, m_arrPoints[1].y should be the Y value for the
1369 * region end (m_numOfHwPoints), not last HW point(m_numOfHwPoints - 1)
1370 */
1371 y3_max = dal_fixed31_32_max(y_r, dal_fixed31_32_max(y_g, y_b));
1372
1373 arr_points[1].y = y3_max;
1374 arr_points[2].y = y3_max;
1375
1376 arr_points[1].slope = dal_fixed31_32_zero;
1377 arr_points[2].slope = dal_fixed31_32_zero;
1378
1379 if (output_tf->tf == TRANSFER_FUNCTION_PQ) {
1380 /* for PQ, we want to have a straight line from last HW X point,
1381 * and the slope to be such that we hit 1.0 at 10000 nits.
1382 */
1383 const struct fixed31_32 end_value =
1384 dal_fixed31_32_from_int(125);
1385
1386 arr_points[1].slope = dal_fixed31_32_div(
1387 dal_fixed31_32_sub(dal_fixed31_32_one, arr_points[1].y),
1388 dal_fixed31_32_sub(end_value, arr_points[1].x));
1389 arr_points[2].slope = dal_fixed31_32_div(
1390 dal_fixed31_32_sub(dal_fixed31_32_one, arr_points[1].y),
1391 dal_fixed31_32_sub(end_value, arr_points[1].x));
1392 }
1393
1394 regamma_params->hw_points_num = hw_points;
1395
1396 i = 1;
1397 for (k = 0; k < MAX_REGIONS_NUMBER && i < MAX_REGIONS_NUMBER; k++) {
1398 if (seg_distr[k] != -1) {
1399 regamma_params->arr_curve_points[k].segments_num =
1400 seg_distr[k];
1401 regamma_params->arr_curve_points[i].offset =
1402 regamma_params->arr_curve_points[k].
1403 offset + (1 << seg_distr[k]);
1404 }
1405 i++;
1406 }
1407
1408 if (seg_distr[k] != -1)
1409 regamma_params->arr_curve_points[k].segments_num =
1410 seg_distr[k];
1411
1412 rgb = rgb_resulted;
1413 rgb_plus_1 = rgb_resulted + 1;
1414
1415 i = 1;
1416
1417 while (i != hw_points + 1) {
1418 if (dal_fixed31_32_lt(rgb_plus_1->red, rgb->red))
1419 rgb_plus_1->red = rgb->red;
1420 if (dal_fixed31_32_lt(rgb_plus_1->green, rgb->green))
1421 rgb_plus_1->green = rgb->green;
1422 if (dal_fixed31_32_lt(rgb_plus_1->blue, rgb->blue))
1423 rgb_plus_1->blue = rgb->blue;
1424
1425 rgb->delta_red = dal_fixed31_32_sub(
1426 rgb_plus_1->red,
1427 rgb->red);
1428 rgb->delta_green = dal_fixed31_32_sub(
1429 rgb_plus_1->green,
1430 rgb->green);
1431 rgb->delta_blue = dal_fixed31_32_sub(
1432 rgb_plus_1->blue,
1433 rgb->blue);
1434
1435 ++rgb_plus_1;
1436 ++rgb;
1437 ++i;
1438 }
1439
1440 convert_to_custom_float(rgb_resulted, arr_points, hw_points);
1441
1442 return true;
1443 }
1444
1445 static bool dcn10_set_output_transfer_func(
1446 struct pipe_ctx *pipe_ctx,
1447 const struct dc_stream *stream)
1448 {
1449 struct transform *xfm = pipe_ctx->xfm;
1450
1451 if (xfm == NULL)
1452 return false;
1453
1454 xfm->regamma_params.hw_points_num = GAMMA_HW_POINTS_NUM;
1455
1456 if (stream->out_transfer_func &&
1457 stream->out_transfer_func->type ==
1458 TF_TYPE_PREDEFINED &&
1459 stream->out_transfer_func->tf ==
1460 TRANSFER_FUNCTION_SRGB) {
1461 xfm->funcs->opp_set_regamma_mode(xfm, OPP_REGAMMA_SRGB);
1462 } else if (dcn10_translate_regamma_to_hw_format(
1463 stream->out_transfer_func, &xfm->regamma_params)) {
1464 xfm->funcs->opp_program_regamma_pwl(xfm, &xfm->regamma_params);
1465 xfm->funcs->opp_set_regamma_mode(xfm, OPP_REGAMMA_USER);
1466 } else {
1467 xfm->funcs->opp_set_regamma_mode(xfm, OPP_REGAMMA_BYPASS);
1468 }
1469
1470 return true;
1471 }
1472
1473 static void dcn10_pipe_control_lock(
1474 struct core_dc *dc,
1475 struct pipe_ctx *pipe,
1476 bool lock)
1477 {
1478 /* use TG master update lock to lock everything on the TG
1479 * therefore only top pipe need to lock
1480 */
1481 if (pipe->top_pipe)
1482 return;
1483
1484 if (dc->public.debug.sanity_checks)
1485 verify_allow_pstate_change_high(dc->hwseq);
1486
1487 if (lock)
1488 pipe->tg->funcs->lock(pipe->tg);
1489 else
1490 pipe->tg->funcs->unlock(pipe->tg);
1491
1492 if (dc->public.debug.sanity_checks)
1493 verify_allow_pstate_change_high(dc->hwseq);
1494 }
1495
1496 static bool wait_for_reset_trigger_to_occur(
1497 struct dc_context *dc_ctx,
1498 struct timing_generator *tg)
1499 {
1500 bool rc = false;
1501
1502 /* To avoid endless loop we wait at most
1503 * frames_to_wait_on_triggered_reset frames for the reset to occur. */
1504 const uint32_t frames_to_wait_on_triggered_reset = 10;
1505 int i;
1506
1507 for (i = 0; i < frames_to_wait_on_triggered_reset; i++) {
1508
1509 if (!tg->funcs->is_counter_moving(tg)) {
1510 DC_ERROR("TG counter is not moving!\n");
1511 break;
1512 }
1513
1514 if (tg->funcs->did_triggered_reset_occur(tg)) {
1515 rc = true;
1516 /* usually occurs at i=1 */
1517 DC_SYNC_INFO("GSL: reset occurred at wait count: %d\n",
1518 i);
1519 break;
1520 }
1521
1522 /* Wait for one frame. */
1523 tg->funcs->wait_for_state(tg, CRTC_STATE_VACTIVE);
1524 tg->funcs->wait_for_state(tg, CRTC_STATE_VBLANK);
1525 }
1526
1527 if (false == rc)
1528 DC_ERROR("GSL: Timeout on reset trigger!\n");
1529
1530 return rc;
1531 }
1532
1533 static void dcn10_enable_timing_synchronization(
1534 struct core_dc *dc,
1535 int group_index,
1536 int group_size,
1537 struct pipe_ctx *grouped_pipes[])
1538 {
1539 struct dc_context *dc_ctx = dc->ctx;
1540 int i;
1541
1542 DC_SYNC_INFO("Setting up OTG reset trigger\n");
1543
1544 for (i = 1; i < group_size; i++)
1545 grouped_pipes[i]->tg->funcs->enable_reset_trigger(
1546 grouped_pipes[i]->tg, grouped_pipes[0]->tg->inst);
1547
1548
1549 DC_SYNC_INFO("Waiting for trigger\n");
1550
1551 /* Need to get only check 1 pipe for having reset as all the others are
1552 * synchronized. Look at last pipe programmed to reset.
1553 */
1554 wait_for_reset_trigger_to_occur(dc_ctx, grouped_pipes[1]->tg);
1555 for (i = 1; i < group_size; i++)
1556 grouped_pipes[i]->tg->funcs->disable_reset_trigger(
1557 grouped_pipes[i]->tg);
1558
1559 DC_SYNC_INFO("Sync complete\n");
1560 }
1561
1562 static void print_rq_dlg_ttu(
1563 struct core_dc *core_dc,
1564 struct pipe_ctx *pipe_ctx)
1565 {
1566 dm_logger_write(core_dc->ctx->logger, LOG_BANDWIDTH_CALCS,
1567 "\n============== DML TTU Output parameters [%d] ==============\n"
1568 "qos_level_low_wm: %d, \n"
1569 "qos_level_high_wm: %d, \n"
1570 "min_ttu_vblank: %d, \n"
1571 "qos_level_flip: %d, \n"
1572 "refcyc_per_req_delivery_l: %d, \n"
1573 "qos_level_fixed_l: %d, \n"
1574 "qos_ramp_disable_l: %d, \n"
1575 "refcyc_per_req_delivery_pre_l: %d, \n"
1576 "refcyc_per_req_delivery_c: %d, \n"
1577 "qos_level_fixed_c: %d, \n"
1578 "qos_ramp_disable_c: %d, \n"
1579 "refcyc_per_req_delivery_pre_c: %d\n"
1580 "=============================================================\n",
1581 pipe_ctx->pipe_idx,
1582 pipe_ctx->ttu_regs.qos_level_low_wm,
1583 pipe_ctx->ttu_regs.qos_level_high_wm,
1584 pipe_ctx->ttu_regs.min_ttu_vblank,
1585 pipe_ctx->ttu_regs.qos_level_flip,
1586 pipe_ctx->ttu_regs.refcyc_per_req_delivery_l,
1587 pipe_ctx->ttu_regs.qos_level_fixed_l,
1588 pipe_ctx->ttu_regs.qos_ramp_disable_l,
1589 pipe_ctx->ttu_regs.refcyc_per_req_delivery_pre_l,
1590 pipe_ctx->ttu_regs.refcyc_per_req_delivery_c,
1591 pipe_ctx->ttu_regs.qos_level_fixed_c,
1592 pipe_ctx->ttu_regs.qos_ramp_disable_c,
1593 pipe_ctx->ttu_regs.refcyc_per_req_delivery_pre_c
1594 );
1595
1596 dm_logger_write(core_dc->ctx->logger, LOG_BANDWIDTH_CALCS,
1597 "\n============== DML DLG Output parameters [%d] ==============\n"
1598 "refcyc_h_blank_end: %d, \n"
1599 "dlg_vblank_end: %d, \n"
1600 "min_dst_y_next_start: %d, \n"
1601 "refcyc_per_htotal: %d, \n"
1602 "refcyc_x_after_scaler: %d, \n"
1603 "dst_y_after_scaler: %d, \n"
1604 "dst_y_prefetch: %d, \n"
1605 "dst_y_per_vm_vblank: %d, \n"
1606 "dst_y_per_row_vblank: %d, \n"
1607 "ref_freq_to_pix_freq: %d, \n"
1608 "vratio_prefetch: %d, \n"
1609 "refcyc_per_pte_group_vblank_l: %d, \n"
1610 "refcyc_per_meta_chunk_vblank_l: %d, \n"
1611 "dst_y_per_pte_row_nom_l: %d, \n"
1612 "refcyc_per_pte_group_nom_l: %d, \n",
1613 pipe_ctx->pipe_idx,
1614 pipe_ctx->dlg_regs.refcyc_h_blank_end,
1615 pipe_ctx->dlg_regs.dlg_vblank_end,
1616 pipe_ctx->dlg_regs.min_dst_y_next_start,
1617 pipe_ctx->dlg_regs.refcyc_per_htotal,
1618 pipe_ctx->dlg_regs.refcyc_x_after_scaler,
1619 pipe_ctx->dlg_regs.dst_y_after_scaler,
1620 pipe_ctx->dlg_regs.dst_y_prefetch,
1621 pipe_ctx->dlg_regs.dst_y_per_vm_vblank,
1622 pipe_ctx->dlg_regs.dst_y_per_row_vblank,
1623 pipe_ctx->dlg_regs.ref_freq_to_pix_freq,
1624 pipe_ctx->dlg_regs.vratio_prefetch,
1625 pipe_ctx->dlg_regs.refcyc_per_pte_group_vblank_l,
1626 pipe_ctx->dlg_regs.refcyc_per_meta_chunk_vblank_l,
1627 pipe_ctx->dlg_regs.dst_y_per_pte_row_nom_l,
1628 pipe_ctx->dlg_regs.refcyc_per_pte_group_nom_l
1629 );
1630
1631 dm_logger_write(core_dc->ctx->logger, LOG_BANDWIDTH_CALCS,
1632 "\ndst_y_per_meta_row_nom_l: %d, \n"
1633 "refcyc_per_meta_chunk_nom_l: %d, \n"
1634 "refcyc_per_line_delivery_pre_l: %d, \n"
1635 "refcyc_per_line_delivery_l: %d, \n"
1636 "vratio_prefetch_c: %d, \n"
1637 "refcyc_per_pte_group_vblank_c: %d, \n"
1638 "refcyc_per_meta_chunk_vblank_c: %d, \n"
1639 "dst_y_per_pte_row_nom_c: %d, \n"
1640 "refcyc_per_pte_group_nom_c: %d, \n"
1641 "dst_y_per_meta_row_nom_c: %d, \n"
1642 "refcyc_per_meta_chunk_nom_c: %d, \n"
1643 "refcyc_per_line_delivery_pre_c: %d, \n"
1644 "refcyc_per_line_delivery_c: %d \n"
1645 "========================================================\n",
1646 pipe_ctx->dlg_regs.dst_y_per_meta_row_nom_l,
1647 pipe_ctx->dlg_regs.refcyc_per_meta_chunk_nom_l,
1648 pipe_ctx->dlg_regs.refcyc_per_line_delivery_pre_l,
1649 pipe_ctx->dlg_regs.refcyc_per_line_delivery_l,
1650 pipe_ctx->dlg_regs.vratio_prefetch_c,
1651 pipe_ctx->dlg_regs.refcyc_per_pte_group_vblank_c,
1652 pipe_ctx->dlg_regs.refcyc_per_meta_chunk_vblank_c,
1653 pipe_ctx->dlg_regs.dst_y_per_pte_row_nom_c,
1654 pipe_ctx->dlg_regs.refcyc_per_pte_group_nom_c,
1655 pipe_ctx->dlg_regs.dst_y_per_meta_row_nom_c,
1656 pipe_ctx->dlg_regs.refcyc_per_meta_chunk_nom_c,
1657 pipe_ctx->dlg_regs.refcyc_per_line_delivery_pre_c,
1658 pipe_ctx->dlg_regs.refcyc_per_line_delivery_c
1659 );
1660
1661 dm_logger_write(core_dc->ctx->logger, LOG_BANDWIDTH_CALCS,
1662 "\n============== DML RQ Output parameters [%d] ==============\n"
1663 "chunk_size: %d \n"
1664 "min_chunk_size: %d \n"
1665 "meta_chunk_size: %d \n"
1666 "min_meta_chunk_size: %d \n"
1667 "dpte_group_size: %d \n"
1668 "mpte_group_size: %d \n"
1669 "swath_height: %d \n"
1670 "pte_row_height_linear: %d \n"
1671 "========================================================\n",
1672 pipe_ctx->pipe_idx,
1673 pipe_ctx->rq_regs.rq_regs_l.chunk_size,
1674 pipe_ctx->rq_regs.rq_regs_l.min_chunk_size,
1675 pipe_ctx->rq_regs.rq_regs_l.meta_chunk_size,
1676 pipe_ctx->rq_regs.rq_regs_l.min_meta_chunk_size,
1677 pipe_ctx->rq_regs.rq_regs_l.dpte_group_size,
1678 pipe_ctx->rq_regs.rq_regs_l.mpte_group_size,
1679 pipe_ctx->rq_regs.rq_regs_l.swath_height,
1680 pipe_ctx->rq_regs.rq_regs_l.pte_row_height_linear
1681 );
1682 }
1683
1684 static void dcn10_power_on_fe(
1685 struct core_dc *dc,
1686 struct pipe_ctx *pipe_ctx,
1687 struct validate_context *context)
1688 {
1689 struct dc_surface *dc_surface = pipe_ctx->surface;
1690 struct dce_hwseq *hws = dc->hwseq;
1691
1692 power_on_plane(dc->hwseq,
1693 pipe_ctx->pipe_idx);
1694
1695 /* enable DCFCLK current DCHUB */
1696 REG_UPDATE(HUBP_CLK_CNTL[pipe_ctx->pipe_idx],
1697 HUBP_CLOCK_ENABLE, 1);
1698
1699 /* make sure OPP_PIPE_CLOCK_EN = 1 */
1700 REG_UPDATE(OPP_PIPE_CONTROL[pipe_ctx->tg->inst],
1701 OPP_PIPE_CLOCK_EN, 1);
1702 /*TODO: REG_UPDATE(DENTIST_DISPCLK_CNTL, DENTIST_DPPCLK_WDIVIDER, 0x1f);*/
1703
1704 if (dc_surface) {
1705 dm_logger_write(dc->ctx->logger, LOG_DC,
1706 "Pipe:%d 0x%x: addr hi:0x%x, "
1707 "addr low:0x%x, "
1708 "src: %d, %d, %d,"
1709 " %d; dst: %d, %d, %d, %d;\n",
1710 pipe_ctx->pipe_idx,
1711 dc_surface,
1712 dc_surface->address.grph.addr.high_part,
1713 dc_surface->address.grph.addr.low_part,
1714 dc_surface->src_rect.x,
1715 dc_surface->src_rect.y,
1716 dc_surface->src_rect.width,
1717 dc_surface->src_rect.height,
1718 dc_surface->dst_rect.x,
1719 dc_surface->dst_rect.y,
1720 dc_surface->dst_rect.width,
1721 dc_surface->dst_rect.height);
1722
1723 dm_logger_write(dc->ctx->logger, LOG_HW_SET_MODE,
1724 "Pipe %d: width, height, x, y\n"
1725 "viewport:%d, %d, %d, %d\n"
1726 "recout: %d, %d, %d, %d\n",
1727 pipe_ctx->pipe_idx,
1728 pipe_ctx->scl_data.viewport.width,
1729 pipe_ctx->scl_data.viewport.height,
1730 pipe_ctx->scl_data.viewport.x,
1731 pipe_ctx->scl_data.viewport.y,
1732 pipe_ctx->scl_data.recout.width,
1733 pipe_ctx->scl_data.recout.height,
1734 pipe_ctx->scl_data.recout.x,
1735 pipe_ctx->scl_data.recout.y);
1736 print_rq_dlg_ttu(dc, pipe_ctx);
1737 }
1738 }
1739
1740 static void program_gamut_remap(struct pipe_ctx *pipe_ctx)
1741 {
1742 struct xfm_grph_csc_adjustment adjust;
1743 memset(&adjust, 0, sizeof(adjust));
1744 adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS;
1745
1746
1747 if (pipe_ctx->stream->gamut_remap_matrix.enable_remap == true) {
1748 adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW;
1749 adjust.temperature_matrix[0] =
1750 pipe_ctx->stream->
1751 gamut_remap_matrix.matrix[0];
1752 adjust.temperature_matrix[1] =
1753 pipe_ctx->stream->
1754 gamut_remap_matrix.matrix[1];
1755 adjust.temperature_matrix[2] =
1756 pipe_ctx->stream->
1757 gamut_remap_matrix.matrix[2];
1758 adjust.temperature_matrix[3] =
1759 pipe_ctx->stream->
1760 gamut_remap_matrix.matrix[4];
1761 adjust.temperature_matrix[4] =
1762 pipe_ctx->stream->
1763 gamut_remap_matrix.matrix[5];
1764 adjust.temperature_matrix[5] =
1765 pipe_ctx->stream->
1766 gamut_remap_matrix.matrix[6];
1767 adjust.temperature_matrix[6] =
1768 pipe_ctx->stream->
1769 gamut_remap_matrix.matrix[8];
1770 adjust.temperature_matrix[7] =
1771 pipe_ctx->stream->
1772 gamut_remap_matrix.matrix[9];
1773 adjust.temperature_matrix[8] =
1774 pipe_ctx->stream->
1775 gamut_remap_matrix.matrix[10];
1776 }
1777
1778 pipe_ctx->xfm->funcs->transform_set_gamut_remap(pipe_ctx->xfm, &adjust);
1779 }
1780
1781
1782 static void program_csc_matrix(struct pipe_ctx *pipe_ctx,
1783 enum dc_color_space colorspace,
1784 uint16_t *matrix)
1785 {
1786 int i;
1787 struct out_csc_color_matrix tbl_entry;
1788
1789 if (pipe_ctx->stream->csc_color_matrix.enable_adjustment
1790 == true) {
1791 enum dc_color_space color_space =
1792 pipe_ctx->stream->output_color_space;
1793
1794 //uint16_t matrix[12];
1795 for (i = 0; i < 12; i++)
1796 tbl_entry.regval[i] = pipe_ctx->stream->csc_color_matrix.matrix[i];
1797
1798 tbl_entry.color_space = color_space;
1799 //tbl_entry.regval = matrix;
1800 pipe_ctx->xfm->funcs->opp_set_csc_adjustment(pipe_ctx->xfm, &tbl_entry);
1801 }
1802 }
1803 static bool is_lower_pipe_tree_visible(struct pipe_ctx *pipe_ctx)
1804 {
1805 if (pipe_ctx->surface->visible)
1806 return true;
1807 if (pipe_ctx->bottom_pipe && is_lower_pipe_tree_visible(pipe_ctx->bottom_pipe))
1808 return true;
1809 return false;
1810 }
1811
1812 static bool is_upper_pipe_tree_visible(struct pipe_ctx *pipe_ctx)
1813 {
1814 if (pipe_ctx->surface->visible)
1815 return true;
1816 if (pipe_ctx->top_pipe && is_upper_pipe_tree_visible(pipe_ctx->top_pipe))
1817 return true;
1818 return false;
1819 }
1820
1821 static bool is_pipe_tree_visible(struct pipe_ctx *pipe_ctx)
1822 {
1823 if (pipe_ctx->surface->visible)
1824 return true;
1825 if (pipe_ctx->top_pipe && is_upper_pipe_tree_visible(pipe_ctx->top_pipe))
1826 return true;
1827 if (pipe_ctx->bottom_pipe && is_lower_pipe_tree_visible(pipe_ctx->bottom_pipe))
1828 return true;
1829 return false;
1830 }
1831
1832 static bool is_rgb_cspace(enum dc_color_space output_color_space)
1833 {
1834 switch (output_color_space) {
1835 case COLOR_SPACE_SRGB:
1836 case COLOR_SPACE_SRGB_LIMITED:
1837 case COLOR_SPACE_2020_RGB_FULLRANGE:
1838 case COLOR_SPACE_2020_RGB_LIMITEDRANGE:
1839 case COLOR_SPACE_ADOBERGB:
1840 return true;
1841 case COLOR_SPACE_YCBCR601:
1842 case COLOR_SPACE_YCBCR709:
1843 case COLOR_SPACE_YCBCR601_LIMITED:
1844 case COLOR_SPACE_YCBCR709_LIMITED:
1845 case COLOR_SPACE_2020_YCBCR:
1846 return false;
1847 default:
1848 /* Add a case to switch */
1849 BREAK_TO_DEBUGGER();
1850 return false;
1851 }
1852 }
1853
1854 static void dcn10_get_surface_visual_confirm_color(
1855 const struct pipe_ctx *pipe_ctx,
1856 struct tg_color *color)
1857 {
1858 uint32_t color_value = MAX_TG_COLOR_VALUE;
1859
1860 switch (pipe_ctx->scl_data.format) {
1861 case PIXEL_FORMAT_ARGB8888:
1862 /* set boarder color to red */
1863 color->color_r_cr = color_value;
1864 break;
1865
1866 case PIXEL_FORMAT_ARGB2101010:
1867 /* set boarder color to blue */
1868 color->color_b_cb = color_value;
1869 break;
1870 case PIXEL_FORMAT_420BPP8:
1871 /* set boarder color to green */
1872 color->color_g_y = color_value;
1873 break;
1874 case PIXEL_FORMAT_420BPP10:
1875 /* set boarder color to yellow */
1876 color->color_g_y = color_value;
1877 color->color_r_cr = color_value;
1878 break;
1879 case PIXEL_FORMAT_FP16:
1880 /* set boarder color to white */
1881 color->color_r_cr = color_value;
1882 color->color_b_cb = color_value;
1883 color->color_g_y = color_value;
1884 break;
1885 default:
1886 break;
1887 }
1888 }
1889
1890 static void update_dchubp_dpp(
1891 struct core_dc *dc,
1892 struct pipe_ctx *pipe_ctx,
1893 struct validate_context *context)
1894 {
1895 struct dce_hwseq *hws = dc->hwseq;
1896 struct mem_input *mi = pipe_ctx->mi;
1897 struct input_pixel_processor *ipp = pipe_ctx->ipp;
1898 struct dc_surface *surface = pipe_ctx->surface;
1899 union plane_size size = surface->plane_size;
1900 struct default_adjustment ocsc = {0};
1901 struct mpcc_cfg mpcc_cfg = {0};
1902 struct pipe_ctx *top_pipe;
1903 bool per_pixel_alpha = surface->per_pixel_alpha && pipe_ctx->bottom_pipe;
1904
1905 /* TODO: proper fix once fpga works */
1906 /* depends on DML calculation, DPP clock value may change dynamically */
1907 enable_dppclk(
1908 dc->hwseq,
1909 pipe_ctx->pipe_idx,
1910 pipe_ctx->pix_clk_params.requested_pix_clk,
1911 context->bw.dcn.calc_clk.dppclk_div);
1912 dc->current_context->bw.dcn.cur_clk.dppclk_div =
1913 context->bw.dcn.calc_clk.dppclk_div;
1914 context->bw.dcn.cur_clk.dppclk_div = context->bw.dcn.calc_clk.dppclk_div;
1915
1916 /* TODO: Need input parameter to tell current DCHUB pipe tie to which OTG
1917 * VTG is within DCHUBBUB which is commond block share by each pipe HUBP.
1918 * VTG is 1:1 mapping with OTG. Each pipe HUBP will select which VTG
1919 */
1920 REG_UPDATE(DCHUBP_CNTL[pipe_ctx->pipe_idx], HUBP_VTG_SEL, pipe_ctx->tg->inst);
1921
1922 update_plane_addr(dc, pipe_ctx);
1923
1924 mi->funcs->mem_input_setup(
1925 mi,
1926 &pipe_ctx->dlg_regs,
1927 &pipe_ctx->ttu_regs,
1928 &pipe_ctx->rq_regs,
1929 &pipe_ctx->pipe_dlg_param);
1930
1931 size.grph.surface_size = pipe_ctx->scl_data.viewport;
1932
1933 if (dc->public.config.gpu_vm_support)
1934 mi->funcs->mem_input_program_pte_vm(
1935 pipe_ctx->mi,
1936 surface->format,
1937 &surface->tiling_info,
1938 surface->rotation);
1939
1940 ipp->funcs->ipp_setup(ipp,
1941 surface->format,
1942 1,
1943 IPP_OUTPUT_FORMAT_12_BIT_FIX);
1944
1945 mpcc_cfg.mi = mi;
1946 mpcc_cfg.opp = pipe_ctx->opp;
1947 for (top_pipe = pipe_ctx->top_pipe; top_pipe; top_pipe = top_pipe->top_pipe)
1948 mpcc_cfg.z_index++;
1949 if (dc->public.debug.surface_visual_confirm)
1950 dcn10_get_surface_visual_confirm_color(
1951 pipe_ctx, &mpcc_cfg.black_color);
1952 else
1953 color_space_to_black_color(
1954 dc, pipe_ctx->stream->output_color_space,
1955 &mpcc_cfg.black_color);
1956 mpcc_cfg.per_pixel_alpha = per_pixel_alpha;
1957 /* DCN1.0 has output CM before MPC which seems to screw with
1958 * pre-multiplied alpha.
1959 */
1960 mpcc_cfg.pre_multiplied_alpha = is_rgb_cspace(
1961 pipe_ctx->stream->output_color_space)
1962 && per_pixel_alpha;
1963 dc->res_pool->mpc->funcs->add(dc->res_pool->mpc, &mpcc_cfg);
1964
1965 pipe_ctx->scl_data.lb_params.alpha_en = per_pixel_alpha;
1966 pipe_ctx->scl_data.lb_params.depth = LB_PIXEL_DEPTH_30BPP;
1967 /* scaler configuration */
1968 pipe_ctx->xfm->funcs->transform_set_scaler(
1969 pipe_ctx->xfm, &pipe_ctx->scl_data);
1970 mi->funcs->mem_program_viewport(mi,
1971 &pipe_ctx->scl_data.viewport, &pipe_ctx->scl_data.viewport_c);
1972
1973 /*gamut remap*/
1974 program_gamut_remap(pipe_ctx);
1975
1976 /*TODO add adjustments parameters*/
1977 ocsc.out_color_space = pipe_ctx->stream->output_color_space;
1978 pipe_ctx->xfm->funcs->opp_set_csc_default(pipe_ctx->xfm, &ocsc);
1979
1980 mi->funcs->mem_input_program_surface_config(
1981 mi,
1982 surface->format,
1983 &surface->tiling_info,
1984 &size,
1985 surface->rotation,
1986 &surface->dcc,
1987 surface->horizontal_mirror);
1988
1989 mi->funcs->set_blank(mi, !is_pipe_tree_visible(pipe_ctx));
1990 }
1991
1992 static void program_all_pipe_in_tree(
1993 struct core_dc *dc,
1994 struct pipe_ctx *pipe_ctx,
1995 struct validate_context *context)
1996 {
1997 unsigned int ref_clk_mhz = dc->res_pool->ref_clock_inKhz/1000;
1998
1999 if (pipe_ctx->top_pipe == NULL) {
2000
2001 /* lock otg_master_update to process all pipes associated with
2002 * this OTG. this is done only one time.
2003 */
2004 /* watermark is for all pipes */
2005 program_watermarks(dc->hwseq, &context->bw.dcn.watermarks, ref_clk_mhz);
2006
2007 if (dc->public.debug.sanity_checks) {
2008 /* pstate stuck check after watermark update */
2009 verify_allow_pstate_change_high(dc->hwseq);
2010 }
2011
2012 pipe_ctx->tg->funcs->lock(pipe_ctx->tg);
2013
2014 pipe_ctx->tg->dlg_otg_param.vready_offset = pipe_ctx->pipe_dlg_param.vready_offset;
2015 pipe_ctx->tg->dlg_otg_param.vstartup_start = pipe_ctx->pipe_dlg_param.vstartup_start;
2016 pipe_ctx->tg->dlg_otg_param.vupdate_offset = pipe_ctx->pipe_dlg_param.vupdate_offset;
2017 pipe_ctx->tg->dlg_otg_param.vupdate_width = pipe_ctx->pipe_dlg_param.vupdate_width;
2018 pipe_ctx->tg->dlg_otg_param.signal = pipe_ctx->stream->signal;
2019
2020 pipe_ctx->tg->funcs->program_global_sync(
2021 pipe_ctx->tg);
2022 pipe_ctx->tg->funcs->set_blank(pipe_ctx->tg, !is_pipe_tree_visible(pipe_ctx));
2023 }
2024
2025 if (pipe_ctx->surface != NULL) {
2026 dcn10_power_on_fe(dc, pipe_ctx, context);
2027 update_dchubp_dpp(dc, pipe_ctx, context);
2028 }
2029
2030 if (dc->public.debug.sanity_checks) {
2031 /* pstate stuck check after each pipe is programmed */
2032 verify_allow_pstate_change_high(dc->hwseq);
2033 }
2034
2035 if (pipe_ctx->bottom_pipe != NULL)
2036 program_all_pipe_in_tree(dc, pipe_ctx->bottom_pipe, context);
2037 }
2038
2039 static void dcn10_pplib_apply_display_requirements(
2040 struct core_dc *dc,
2041 struct validate_context *context)
2042 {
2043 struct dm_pp_display_configuration *pp_display_cfg = &context->pp_display_cfg;
2044
2045 pp_display_cfg->all_displays_in_sync = false;/*todo*/
2046 pp_display_cfg->nb_pstate_switch_disable = false;
2047 pp_display_cfg->min_engine_clock_khz = context->bw.dcn.cur_clk.dcfclk_khz;
2048 pp_display_cfg->min_memory_clock_khz = context->bw.dcn.cur_clk.fclk_khz;
2049 pp_display_cfg->min_engine_clock_deep_sleep_khz = context->bw.dcn.cur_clk.dcfclk_deep_sleep_khz;
2050 pp_display_cfg->min_dcfc_deep_sleep_clock_khz = context->bw.dcn.cur_clk.dcfclk_deep_sleep_khz;
2051 pp_display_cfg->avail_mclk_switch_time_us =
2052 context->bw.dcn.cur_clk.dram_ccm_us > 0 ? context->bw.dcn.cur_clk.dram_ccm_us : 0;
2053 pp_display_cfg->avail_mclk_switch_time_in_disp_active_us =
2054 context->bw.dcn.cur_clk.min_active_dram_ccm_us > 0 ? context->bw.dcn.cur_clk.min_active_dram_ccm_us : 0;
2055 pp_display_cfg->min_dcfclock_khz = context->bw.dcn.cur_clk.dcfclk_khz;
2056 pp_display_cfg->disp_clk_khz = context->bw.dcn.cur_clk.dispclk_khz;
2057 dce110_fill_display_configs(context, pp_display_cfg);
2058
2059 if (memcmp(&dc->prev_display_config, pp_display_cfg, sizeof(
2060 struct dm_pp_display_configuration)) != 0)
2061 dm_pp_apply_display_requirements(dc->ctx, pp_display_cfg);
2062
2063 dc->prev_display_config = *pp_display_cfg;
2064 }
2065
2066 static void dcn10_apply_ctx_for_surface(
2067 struct core_dc *dc,
2068 const struct dc_surface *surface,
2069 struct validate_context *context)
2070 {
2071 int i, be_idx;
2072
2073 if (dc->public.debug.sanity_checks)
2074 verify_allow_pstate_change_high(dc->hwseq);
2075
2076 if (!surface)
2077 return;
2078
2079 for (be_idx = 0; be_idx < dc->res_pool->pipe_count; be_idx++)
2080 if (surface == context->res_ctx.pipe_ctx[be_idx].surface)
2081 break;
2082
2083 /* reset unused mpcc */
2084 for (i = 0; i < dc->res_pool->pipe_count; i++) {
2085 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
2086 struct pipe_ctx *old_pipe_ctx =
2087 &dc->current_context->res_ctx.pipe_ctx[i];
2088
2089 if (!pipe_ctx->surface && !old_pipe_ctx->surface)
2090 continue;
2091
2092 /*
2093 * Powergate reused pipes that are not powergated
2094 * fairly hacky right now, using opp_id as indicator
2095 */
2096
2097 if (pipe_ctx->surface && !old_pipe_ctx->surface) {
2098 if (pipe_ctx->mi->opp_id != 0xf && pipe_ctx->tg->inst == be_idx) {
2099 dcn10_power_down_fe(dc, pipe_ctx->pipe_idx);
2100 /*
2101 * power down fe will unlock when calling reset, need
2102 * to lock it back here. Messy, need rework.
2103 */
2104 pipe_ctx->tg->funcs->lock(pipe_ctx->tg);
2105 }
2106 }
2107
2108
2109 if ((!pipe_ctx->surface && old_pipe_ctx->surface)
2110 || (!pipe_ctx->stream && old_pipe_ctx->stream)) {
2111 if (old_pipe_ctx->tg->inst != be_idx)
2112 continue;
2113
2114 if (!old_pipe_ctx->top_pipe) {
2115 ASSERT(0);
2116 continue;
2117 }
2118
2119 /* reset mpc */
2120 dc->res_pool->mpc->funcs->remove(
2121 dc->res_pool->mpc,
2122 old_pipe_ctx->opp,
2123 old_pipe_ctx->pipe_idx);
2124 old_pipe_ctx->opp->mpcc_disconnect_pending[old_pipe_ctx->mi->mpcc_id] = true;
2125
2126 /*dm_logger_write(dc->ctx->logger, LOG_ERROR,
2127 "[debug_mpo: apply_ctx disconnect pending on mpcc %d]\n",
2128 old_pipe_ctx->mpcc->inst);*/
2129
2130 if (dc->public.debug.sanity_checks)
2131 verify_allow_pstate_change_high(dc->hwseq);
2132
2133 old_pipe_ctx->top_pipe = NULL;
2134 old_pipe_ctx->bottom_pipe = NULL;
2135 old_pipe_ctx->surface = NULL;
2136
2137 dm_logger_write(dc->ctx->logger, LOG_DC,
2138 "Reset mpcc for pipe %d\n",
2139 old_pipe_ctx->pipe_idx);
2140 }
2141 }
2142
2143 for (i = 0; i < dc->res_pool->pipe_count; i++) {
2144 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
2145
2146 if (pipe_ctx->surface != surface)
2147 continue;
2148
2149 /* looking for top pipe to program */
2150 if (!pipe_ctx->top_pipe)
2151 program_all_pipe_in_tree(dc, pipe_ctx, context);
2152 }
2153
2154 dm_logger_write(dc->ctx->logger, LOG_BANDWIDTH_CALCS,
2155 "\n============== Watermark parameters ==============\n"
2156 "a.urgent_ns: %d \n"
2157 "a.cstate_enter_plus_exit: %d \n"
2158 "a.cstate_exit: %d \n"
2159 "a.pstate_change: %d \n"
2160 "a.pte_meta_urgent: %d \n"
2161 "b.urgent_ns: %d \n"
2162 "b.cstate_enter_plus_exit: %d \n"
2163 "b.cstate_exit: %d \n"
2164 "b.pstate_change: %d \n"
2165 "b.pte_meta_urgent: %d \n",
2166 context->bw.dcn.watermarks.a.urgent_ns,
2167 context->bw.dcn.watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns,
2168 context->bw.dcn.watermarks.a.cstate_pstate.cstate_exit_ns,
2169 context->bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns,
2170 context->bw.dcn.watermarks.a.pte_meta_urgent_ns,
2171 context->bw.dcn.watermarks.b.urgent_ns,
2172 context->bw.dcn.watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns,
2173 context->bw.dcn.watermarks.b.cstate_pstate.cstate_exit_ns,
2174 context->bw.dcn.watermarks.b.cstate_pstate.pstate_change_ns,
2175 context->bw.dcn.watermarks.b.pte_meta_urgent_ns
2176 );
2177 dm_logger_write(dc->ctx->logger, LOG_BANDWIDTH_CALCS,
2178 "\nc.urgent_ns: %d \n"
2179 "c.cstate_enter_plus_exit: %d \n"
2180 "c.cstate_exit: %d \n"
2181 "c.pstate_change: %d \n"
2182 "c.pte_meta_urgent: %d \n"
2183 "d.urgent_ns: %d \n"
2184 "d.cstate_enter_plus_exit: %d \n"
2185 "d.cstate_exit: %d \n"
2186 "d.pstate_change: %d \n"
2187 "d.pte_meta_urgent: %d \n"
2188 "========================================================\n",
2189 context->bw.dcn.watermarks.c.urgent_ns,
2190 context->bw.dcn.watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns,
2191 context->bw.dcn.watermarks.c.cstate_pstate.cstate_exit_ns,
2192 context->bw.dcn.watermarks.c.cstate_pstate.pstate_change_ns,
2193 context->bw.dcn.watermarks.c.pte_meta_urgent_ns,
2194 context->bw.dcn.watermarks.d.urgent_ns,
2195 context->bw.dcn.watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns,
2196 context->bw.dcn.watermarks.d.cstate_pstate.cstate_exit_ns,
2197 context->bw.dcn.watermarks.d.cstate_pstate.pstate_change_ns,
2198 context->bw.dcn.watermarks.d.pte_meta_urgent_ns
2199 );
2200
2201 if (dc->public.debug.sanity_checks)
2202 verify_allow_pstate_change_high(dc->hwseq);
2203 }
2204
2205 static void dcn10_set_bandwidth(
2206 struct core_dc *dc,
2207 struct validate_context *context,
2208 bool decrease_allowed)
2209 {
2210 struct dm_pp_clock_for_voltage_req clock;
2211
2212 if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment))
2213 return;
2214
2215 if (decrease_allowed || context->bw.dcn.calc_clk.dispclk_khz
2216 > dc->current_context->bw.dcn.cur_clk.dispclk_khz) {
2217 dc->res_pool->display_clock->funcs->set_clock(
2218 dc->res_pool->display_clock,
2219 context->bw.dcn.calc_clk.dispclk_khz);
2220 dc->current_context->bw.dcn.cur_clk.dispclk_khz =
2221 context->bw.dcn.calc_clk.dispclk_khz;
2222 }
2223 if (decrease_allowed || context->bw.dcn.calc_clk.dcfclk_khz
2224 > dc->current_context->bw.dcn.cur_clk.dcfclk_khz) {
2225 clock.clk_type = DM_PP_CLOCK_TYPE_DCFCLK;
2226 clock.clocks_in_khz = context->bw.dcn.calc_clk.dcfclk_khz;
2227 dm_pp_apply_clock_for_voltage_request(dc->ctx, &clock);
2228 dc->current_context->bw.dcn.cur_clk.dcfclk_khz = clock.clocks_in_khz;
2229 context->bw.dcn.cur_clk.dcfclk_khz = clock.clocks_in_khz;
2230 }
2231 if (decrease_allowed || context->bw.dcn.calc_clk.fclk_khz
2232 > dc->current_context->bw.dcn.cur_clk.fclk_khz) {
2233 clock.clk_type = DM_PP_CLOCK_TYPE_FCLK;
2234 clock.clocks_in_khz = context->bw.dcn.calc_clk.fclk_khz;
2235 dm_pp_apply_clock_for_voltage_request(dc->ctx, &clock);
2236 dc->current_context->bw.dcn.calc_clk.fclk_khz = clock.clocks_in_khz;
2237 context->bw.dcn.cur_clk.fclk_khz = clock.clocks_in_khz;
2238 }
2239 if (decrease_allowed || context->bw.dcn.calc_clk.dcfclk_deep_sleep_khz
2240 > dc->current_context->bw.dcn.cur_clk.dcfclk_deep_sleep_khz) {
2241 dc->current_context->bw.dcn.calc_clk.dcfclk_deep_sleep_khz =
2242 context->bw.dcn.calc_clk.dcfclk_deep_sleep_khz;
2243 context->bw.dcn.cur_clk.dcfclk_deep_sleep_khz =
2244 context->bw.dcn.calc_clk.dcfclk_deep_sleep_khz;
2245 }
2246 /* Decrease in freq is increase in period so opposite comparison for dram_ccm */
2247 if (decrease_allowed || context->bw.dcn.calc_clk.dram_ccm_us
2248 < dc->current_context->bw.dcn.cur_clk.dram_ccm_us) {
2249 dc->current_context->bw.dcn.calc_clk.dram_ccm_us =
2250 context->bw.dcn.calc_clk.dram_ccm_us;
2251 context->bw.dcn.cur_clk.dram_ccm_us =
2252 context->bw.dcn.calc_clk.dram_ccm_us;
2253 }
2254 if (decrease_allowed || context->bw.dcn.calc_clk.min_active_dram_ccm_us
2255 < dc->current_context->bw.dcn.cur_clk.min_active_dram_ccm_us) {
2256 dc->current_context->bw.dcn.calc_clk.min_active_dram_ccm_us =
2257 context->bw.dcn.calc_clk.min_active_dram_ccm_us;
2258 context->bw.dcn.cur_clk.min_active_dram_ccm_us =
2259 context->bw.dcn.calc_clk.min_active_dram_ccm_us;
2260 }
2261 dcn10_pplib_apply_display_requirements(dc, context);
2262
2263 /* need to fix this function. not doing the right thing here */
2264 }
2265
2266 static void set_drr(struct pipe_ctx **pipe_ctx,
2267 int num_pipes, int vmin, int vmax)
2268 {
2269 int i = 0;
2270 struct drr_params params = {0};
2271
2272 params.vertical_total_max = vmax;
2273 params.vertical_total_min = vmin;
2274
2275 /* TODO: If multiple pipes are to be supported, you need
2276 * some GSL stuff
2277 */
2278 for (i = 0; i < num_pipes; i++) {
2279 pipe_ctx[i]->tg->funcs->set_drr(pipe_ctx[i]->tg, &params);
2280 }
2281 }
2282
2283 static void get_position(struct pipe_ctx **pipe_ctx,
2284 int num_pipes,
2285 struct crtc_position *position)
2286 {
2287 int i = 0;
2288
2289 /* TODO: handle pipes > 1
2290 */
2291 for (i = 0; i < num_pipes; i++)
2292 pipe_ctx[i]->tg->funcs->get_position(pipe_ctx[i]->tg, position);
2293 }
2294
2295 static void set_static_screen_control(struct pipe_ctx **pipe_ctx,
2296 int num_pipes, const struct dc_static_screen_events *events)
2297 {
2298 unsigned int i;
2299 unsigned int value = 0;
2300
2301 if (events->surface_update)
2302 value |= 0x80;
2303 if (events->cursor_update)
2304 value |= 0x2;
2305
2306 for (i = 0; i < num_pipes; i++)
2307 pipe_ctx[i]->tg->funcs->
2308 set_static_screen_control(pipe_ctx[i]->tg, value);
2309 }
2310
2311 static void set_plane_config(
2312 const struct core_dc *dc,
2313 struct pipe_ctx *pipe_ctx,
2314 struct resource_context *res_ctx)
2315 {
2316 /* TODO */
2317 program_gamut_remap(pipe_ctx);
2318 }
2319
2320 static void dcn10_config_stereo_parameters(
2321 struct dc_stream *stream, struct crtc_stereo_flags *flags)
2322 {
2323 enum view_3d_format view_format = stream->view_format;
2324 enum dc_timing_3d_format timing_3d_format =\
2325 stream->timing.timing_3d_format;
2326 bool non_stereo_timing = false;
2327
2328 if (timing_3d_format == TIMING_3D_FORMAT_NONE ||
2329 timing_3d_format == TIMING_3D_FORMAT_SIDE_BY_SIDE ||
2330 timing_3d_format == TIMING_3D_FORMAT_TOP_AND_BOTTOM)
2331 non_stereo_timing = true;
2332
2333 if (non_stereo_timing == false &&
2334 view_format == VIEW_3D_FORMAT_FRAME_SEQUENTIAL) {
2335
2336 flags->PROGRAM_STEREO = 1;
2337 flags->PROGRAM_POLARITY = 1;
2338 if (timing_3d_format == TIMING_3D_FORMAT_INBAND_FA ||
2339 timing_3d_format == TIMING_3D_FORMAT_DP_HDMI_INBAND_FA ||
2340 timing_3d_format == TIMING_3D_FORMAT_SIDEBAND_FA) {
2341 enum display_dongle_type dongle = \
2342 stream->sink->link->ddc->dongle_type;
2343 if (dongle == DISPLAY_DONGLE_DP_VGA_CONVERTER ||
2344 dongle == DISPLAY_DONGLE_DP_DVI_CONVERTER ||
2345 dongle == DISPLAY_DONGLE_DP_HDMI_CONVERTER)
2346 flags->DISABLE_STEREO_DP_SYNC = 1;
2347 }
2348 flags->RIGHT_EYE_POLARITY =\
2349 stream->timing.flags.RIGHT_EYE_3D_POLARITY;
2350 if (timing_3d_format == TIMING_3D_FORMAT_HW_FRAME_PACKING)
2351 flags->FRAME_PACKED = 1;
2352 }
2353
2354 return;
2355 }
2356
2357 static void dcn10_setup_stereo(struct pipe_ctx *pipe_ctx, struct core_dc *dc)
2358 {
2359 struct crtc_stereo_flags flags = { 0 };
2360 struct dc_stream *stream = pipe_ctx->stream;
2361
2362 dcn10_config_stereo_parameters(stream, &flags);
2363
2364 pipe_ctx->opp->funcs->opp_set_stereo_polarity(
2365 pipe_ctx->opp,
2366 flags.PROGRAM_STEREO == 1 ? true:false,
2367 stream->timing.flags.RIGHT_EYE_3D_POLARITY == 1 ? true:false);
2368
2369 pipe_ctx->tg->funcs->program_stereo(
2370 pipe_ctx->tg,
2371 &stream->timing,
2372 &flags);
2373
2374 return;
2375 }
2376
2377
2378 static void log_mpc_crc(struct core_dc *dc)
2379 {
2380 struct dc_context *dc_ctx = dc->ctx;
2381 struct dce_hwseq *hws = dc->hwseq;
2382
2383 if (REG(MPC_CRC_RESULT_GB))
2384 DTN_INFO("MPC_CRC_RESULT_GB:%d MPC_CRC_RESULT_C:%d MPC_CRC_RESULT_AR:%d\n",
2385 REG_READ(MPC_CRC_RESULT_GB), REG_READ(MPC_CRC_RESULT_C), REG_READ(MPC_CRC_RESULT_AR));
2386 if (REG(DPP_TOP0_DPP_CRC_VAL_B_A))
2387 DTN_INFO("DPP_TOP0_DPP_CRC_VAL_B_A:%d DPP_TOP0_DPP_CRC_VAL_R_G:%d\n",
2388 REG_READ(DPP_TOP0_DPP_CRC_VAL_B_A), REG_READ(DPP_TOP0_DPP_CRC_VAL_R_G));
2389 }
2390
2391 static void dcn10_log_hw_state(struct core_dc *dc)
2392 {
2393 struct dc_context *dc_ctx = dc->ctx;
2394 struct resource_pool *pool = dc->res_pool;
2395 int i;
2396
2397 DTN_INFO_BEGIN();
2398
2399 DTN_INFO("HUBP:\t format \t addr_hi \t width \t height \t rotation \t"
2400 "mirror \t sw_mode \t dcc_en \t blank_en \t ttu_dis \t"
2401 "min_ttu_vblank \t qos_low_wm \t qos_high_wm \n");
2402
2403 for (i = 0; i < pool->pipe_count; i++) {
2404 struct mem_input *mi = pool->mis[i];
2405 struct dcn_hubp_state s;
2406
2407 dcn10_mem_input_read_state(TO_DCN10_MEM_INPUT(mi), &s);
2408
2409 DTN_INFO("[%d]:\t %xh \t %xh \t %d \t %d \t %xh \t %xh \t "
2410 "%d \t %d \t %d \t %d \t"
2411 "%d \t %d \t %d \n",
2412 i,
2413 s.pixel_format,
2414 s.inuse_addr_hi,
2415 s.viewport_width,
2416 s.viewport_height,
2417 s.rotation_angle,
2418 s.h_mirror_en,
2419 s.sw_mode,
2420 s.dcc_en,
2421 s.blank_en,
2422 s.ttu_disable,
2423 s.min_ttu_vblank,
2424 s.qos_level_low_wm,
2425 s.qos_level_high_wm);
2426 }
2427 DTN_INFO("\n");
2428
2429 log_mpc_crc(dc);
2430
2431 DTN_INFO_END();
2432 }
2433
2434 static void dcn10_wait_for_mpcc_disconnect(
2435 struct core_dc *dc,
2436 struct resource_pool *res_pool,
2437 struct pipe_ctx *pipe_ctx)
2438 {
2439 int i;
2440
2441 if (!pipe_ctx->opp)
2442 return;
2443
2444 for (i = 0; i < MAX_PIPES; i++) {
2445 if (pipe_ctx->opp->mpcc_disconnect_pending[i]) {
2446 res_pool->mpc->funcs->wait_for_idle(res_pool->mpc, i);
2447 pipe_ctx->opp->mpcc_disconnect_pending[i] = false;
2448 res_pool->mis[i]->funcs->set_blank(res_pool->mis[i], true);
2449 /*dm_logger_write(dc->ctx->logger, LOG_ERROR,
2450 "[debug_mpo: wait_for_mpcc finished waiting on mpcc %d]\n",
2451 i);*/
2452 }
2453 }
2454
2455 }
2456
2457 static bool dcn10_dummy_display_power_gating(
2458 struct core_dc *dc,
2459 uint8_t controller_id,
2460 struct dc_bios *dcb,
2461 enum pipe_gating_control power_gating)
2462 {
2463 return true;
2464 }
2465
2466 void dcn10_update_pending_status(struct pipe_ctx *pipe_ctx)
2467 {
2468 struct dc_surface *surface = pipe_ctx->surface;
2469 struct timing_generator *tg = pipe_ctx->tg;
2470
2471 if (surface->ctx->dc->debug.sanity_checks) {
2472 struct core_dc *dc = DC_TO_CORE(surface->ctx->dc);
2473
2474 verify_allow_pstate_change_high(dc->hwseq);
2475 }
2476
2477 if (surface == NULL)
2478 return;
2479
2480 surface->status.is_flip_pending =
2481 pipe_ctx->mi->funcs->mem_input_is_flip_pending(
2482 pipe_ctx->mi);
2483
2484 /* DCN we read INUSE address in MI, do we still need this wa? */
2485 if (surface->status.is_flip_pending &&
2486 !surface->visible) {
2487 pipe_ctx->mi->current_address =
2488 pipe_ctx->mi->request_address;
2489 BREAK_TO_DEBUGGER();
2490 }
2491
2492 surface->status.current_address = pipe_ctx->mi->current_address;
2493 if (pipe_ctx->mi->current_address.type == PLN_ADDR_TYPE_GRPH_STEREO &&
2494 tg->funcs->is_stereo_left_eye) {
2495 surface->status.is_right_eye =
2496 !tg->funcs->is_stereo_left_eye(pipe_ctx->tg);
2497 }
2498 }
2499
2500 static const struct hw_sequencer_funcs dcn10_funcs = {
2501 .program_gamut_remap = program_gamut_remap,
2502 .program_csc_matrix = program_csc_matrix,
2503 .init_hw = dcn10_init_hw,
2504 .apply_ctx_to_hw = dce110_apply_ctx_to_hw,
2505 .apply_ctx_for_surface = dcn10_apply_ctx_for_surface,
2506 .set_plane_config = set_plane_config,
2507 .update_plane_addr = update_plane_addr,
2508 .update_dchub = dcn10_update_dchub,
2509 .update_pending_status = dcn10_update_pending_status,
2510 .set_input_transfer_func = dcn10_set_input_transfer_func,
2511 .set_output_transfer_func = dcn10_set_output_transfer_func,
2512 .power_down = dce110_power_down,
2513 .enable_accelerated_mode = dce110_enable_accelerated_mode,
2514 .enable_timing_synchronization = dcn10_enable_timing_synchronization,
2515 .update_info_frame = dce110_update_info_frame,
2516 .enable_stream = dce110_enable_stream,
2517 .disable_stream = dce110_disable_stream,
2518 .unblank_stream = dce110_unblank_stream,
2519 .enable_display_power_gating = dcn10_dummy_display_power_gating,
2520 .power_down_front_end = dcn10_power_down_fe,
2521 .power_on_front_end = dcn10_power_on_fe,
2522 .pipe_control_lock = dcn10_pipe_control_lock,
2523 .set_bandwidth = dcn10_set_bandwidth,
2524 .reset_hw_ctx_wrap = reset_hw_ctx_wrap,
2525 .prog_pixclk_crtc_otg = dcn10_prog_pixclk_crtc_otg,
2526 .set_drr = set_drr,
2527 .get_position = get_position,
2528 .set_static_screen_control = set_static_screen_control,
2529 .setup_stereo = dcn10_setup_stereo,
2530 .set_avmute = dce110_set_avmute,
2531 .log_hw_state = dcn10_log_hw_state,
2532 .wait_for_mpcc_disconnect = dcn10_wait_for_mpcc_disconnect
2533 };
2534
2535
2536 void dcn10_hw_sequencer_construct(struct core_dc *dc)
2537 {
2538 dc->hwss = dcn10_funcs;
2539 }
2540