]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blob - drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
drm/amd/display: Roll core_surface into dc_surface
[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_dpp.h"
35 #include "dcn10/dcn10_mpc.h"
36 #include "mem_input.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 core_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 struct mpcc *mpcc = dc->res_pool->mpcc[i];
640 struct mpcc_cfg mpcc_cfg;
641
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);
648
649 /* Blank controller using driver code instead of
650 * command table.
651 */
652 tg->funcs->set_blank(tg, true);
653 hwss_wait_for_blank_complete(tg);
654 }
655
656 for (i = 0; i < dc->res_pool->audio_count; i++) {
657 struct audio *audio = dc->res_pool->audios[i];
658
659 audio->funcs->hw_init(audio);
660 }
661
662 if (abm != NULL) {
663 abm->funcs->init_backlight(abm);
664 abm->funcs->abm_init(abm);
665 }
666
667 /* power AFMT HDMI memory TODO: may move to dis/en output save power*/
668 REG_WRITE(DIO_MEM_PWR_CTRL, 0);
669
670 if (!dc->public.debug.disable_clock_gate) {
671 /* enable all DCN clock gating */
672 REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0);
673
674 REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0);
675
676 REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0);
677 }
678
679 enable_power_gating_plane(dc->hwseq, true);
680 }
681
682 static enum dc_status dcn10_prog_pixclk_crtc_otg(
683 struct pipe_ctx *pipe_ctx,
684 struct validate_context *context,
685 struct core_dc *dc)
686 {
687 struct core_stream *stream = pipe_ctx->stream;
688 enum dc_color_space color_space;
689 struct tg_color black_color = {0};
690 bool enableStereo = stream->public.timing.timing_3d_format == TIMING_3D_FORMAT_NONE ?
691 false:true;
692 bool rightEyePolarity = stream->public.timing.flags.RIGHT_EYE_3D_POLARITY;
693
694
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.
698 */
699 if (pipe_ctx->top_pipe != NULL)
700 return DC_OK;
701
702 /* TODO check if timing_changed, disable stream if timing changed */
703
704 /* HW program guide assume display already disable
705 * by unplug sequence. OTG assume stop.
706 */
707 pipe_ctx->tg->funcs->enable_optc_clock(pipe_ctx->tg, true);
708
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)) {
713 BREAK_TO_DEBUGGER();
714 return DC_ERROR_UNEXPECTED;
715 }
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;
720
721 pipe_ctx->tg->dlg_otg_param.signal = pipe_ctx->stream->signal;
722
723 pipe_ctx->tg->funcs->program_timing(
724 pipe_ctx->tg,
725 &stream->public.timing,
726 true);
727
728 pipe_ctx->opp->funcs->opp_set_stereo_polarity(
729 pipe_ctx->opp,
730 enableStereo,
731 rightEyePolarity);
732
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 */
736
737 inst_offset = reg_offsets[pipe_ctx->tg->inst].fmt;
738
739 pipe_ctx->opp->funcs->opp_program_fmt(
740 pipe_ctx->opp,
741 &stream->bit_depth_params,
742 &stream->clamping);
743 #endif
744 /* program otg blank color */
745 color_space = stream->public.output_color_space;
746 color_space_to_black_color(dc, color_space, &black_color);
747 pipe_ctx->tg->funcs->set_blank_color(
748 pipe_ctx->tg,
749 &black_color);
750
751 pipe_ctx->tg->funcs->set_blank(pipe_ctx->tg, true);
752 hwss_wait_for_blank_complete(pipe_ctx->tg);
753
754 /* VTG is within DCHUB command block. DCFCLK is always on */
755 if (false == pipe_ctx->tg->funcs->enable_crtc(pipe_ctx->tg)) {
756 BREAK_TO_DEBUGGER();
757 return DC_ERROR_UNEXPECTED;
758 }
759
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 */
767
768 return DC_OK;
769 }
770
771 static void reset_back_end_for_pipe(
772 struct core_dc *dc,
773 struct pipe_ctx *pipe_ctx,
774 struct validate_context *context)
775 {
776 int i;
777
778 if (pipe_ctx->stream_enc == NULL) {
779 pipe_ctx->stream = NULL;
780 return;
781 }
782
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
786 */
787 if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment))
788 core_link_disable_stream(pipe_ctx);
789
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
792 * parent pipe.
793 */
794 if (pipe_ctx->top_pipe == NULL) {
795 pipe_ctx->tg->funcs->disable_crtc(pipe_ctx->tg);
796
797 pipe_ctx->tg->funcs->enable_optc_clock(pipe_ctx->tg, false);
798 }
799
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);
804
805 for (i = 0; i < dc->res_pool->pipe_count; i++)
806 if (&dc->current_context->res_ctx.pipe_ctx[i] == pipe_ctx)
807 break;
808
809 if (i == dc->res_pool->pipe_count)
810 return;
811
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);
816 }
817
818 static void plane_atomic_stop(
819 struct core_dc *dc,
820 int fe_idx)
821 {
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
828 mi->funcs->dcc_control(mi, false, false);
829
830 mpcc_cfg.opp_id = 0xf;
831 mpcc_cfg.top_dpp_id = 0xf;
832 mpcc_cfg.bot_mpcc_id = 0xf;
833 mpcc_cfg.top_of_tree = tg->inst == mpcc->inst;
834 mpcc->funcs->set(mpcc, &mpcc_cfg);
835
836 xfm->funcs->transform_reset(xfm);
837 }
838
839 static void reset_front_end(
840 struct core_dc *dc,
841 int fe_idx)
842 {
843 struct dce_hwseq *hws = dc->hwseq;
844 struct mem_input *mi = dc->res_pool->mis[fe_idx];
845 struct mpcc *mpcc = dc->res_pool->mpcc[fe_idx];
846 struct timing_generator *tg = dc->res_pool->timing_generators[mpcc->opp_id];
847 unsigned int opp_id = mpcc->opp_id;
848
849 /*Already reset*/
850 if (opp_id == 0xf)
851 return;
852
853 tg->funcs->lock(tg);
854
855 plane_atomic_stop(dc, fe_idx);
856
857 REG_UPDATE(OTG_GLOBAL_SYNC_STATUS[tg->inst], VUPDATE_NO_LOCK_EVENT_CLEAR, 1);
858 tg->funcs->unlock(tg);
859
860 if (dc->public.debug.sanity_checks)
861 verify_allow_pstate_change_high(dc->hwseq);
862
863 if (tg->ctx->dce_environment != DCE_ENV_FPGA_MAXIMUS)
864 REG_WAIT(OTG_GLOBAL_SYNC_STATUS[tg->inst],
865 VUPDATE_NO_LOCK_EVENT_OCCURRED, 1, 20000, 200000);
866
867 mpcc->funcs->wait_for_idle(mpcc);
868
869 mi->funcs->set_blank(mi, true);
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 (tg->inst == mpcc->inst)
880 REG_UPDATE(OPP_PIPE_CONTROL[opp_id],
881 OPP_PIPE_CLOCK_EN, 0);
882
883 dm_logger_write(dc->ctx->logger, LOG_DC,
884 "Reset front end %d\n",
885 fe_idx);
886
887 if (dc->public.debug.sanity_checks)
888 verify_allow_pstate_change_high(dc->hwseq);
889 }
890
891 static void dcn10_power_down_fe(struct core_dc *dc, int fe_idx)
892 {
893 struct dce_hwseq *hws = dc->hwseq;
894
895 reset_front_end(dc, fe_idx);
896
897 REG_SET(DC_IP_REQUEST_CNTL, 0,
898 IP_REQUEST_EN, 1);
899 dpp_pg_control(hws, fe_idx, false);
900 hubp_pg_control(hws, fe_idx, false);
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 static void reset_hw_ctx_wrap(
911 struct core_dc *dc,
912 struct validate_context *context)
913 {
914 int i;
915
916 /* Reset Front End*/
917 for (i = dc->res_pool->pipe_count - 1; i >= 0 ; i--) {
918 struct pipe_ctx *pipe_ctx_old =
919 &dc->current_context->res_ctx.pipe_ctx[i];
920 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
921
922 /*if (!pipe_ctx_old->stream)
923 continue;*/
924
925 if (!pipe_ctx->stream || !pipe_ctx->surface)
926 dcn10_power_down_fe(dc, i);
927 else if (pipe_need_reprogram(pipe_ctx_old, pipe_ctx))
928 reset_front_end(dc, i);
929 }
930 /* Reset Back End*/
931 for (i = dc->res_pool->pipe_count - 1; i >= 0 ; i--) {
932 struct pipe_ctx *pipe_ctx_old =
933 &dc->current_context->res_ctx.pipe_ctx[i];
934 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
935
936 if (!pipe_ctx_old->stream)
937 continue;
938
939 if (!pipe_ctx->stream ||
940 pipe_need_reprogram(pipe_ctx_old, pipe_ctx))
941 reset_back_end_for_pipe(dc, pipe_ctx_old, dc->current_context);
942 }
943 }
944
945 static bool patch_address_for_sbs_tb_stereo(
946 struct pipe_ctx *pipe_ctx, PHYSICAL_ADDRESS_LOC *addr)
947 {
948 struct dc_surface *surface = pipe_ctx->surface;
949 bool sec_split = pipe_ctx->top_pipe &&
950 pipe_ctx->top_pipe->surface == pipe_ctx->surface;
951 if (sec_split && surface->address.type == PLN_ADDR_TYPE_GRPH_STEREO &&
952 (pipe_ctx->stream->public.timing.timing_3d_format ==
953 TIMING_3D_FORMAT_SIDE_BY_SIDE ||
954 pipe_ctx->stream->public.timing.timing_3d_format ==
955 TIMING_3D_FORMAT_TOP_AND_BOTTOM)) {
956 *addr = surface->address.grph_stereo.left_addr;
957 surface->address.grph_stereo.left_addr =
958 surface->address.grph_stereo.right_addr;
959 return true;
960 } else {
961 if (pipe_ctx->stream->public.view_format != VIEW_3D_FORMAT_NONE &&
962 surface->address.type != PLN_ADDR_TYPE_GRPH_STEREO) {
963 surface->address.type = PLN_ADDR_TYPE_GRPH_STEREO;
964 surface->address.grph_stereo.right_addr =
965 surface->address.grph_stereo.left_addr;
966 }
967 }
968 return false;
969 }
970
971 static void update_plane_addr(const struct core_dc *dc, struct pipe_ctx *pipe_ctx)
972 {
973 bool addr_patched = false;
974 PHYSICAL_ADDRESS_LOC addr;
975 struct dc_surface *surface = pipe_ctx->surface;
976
977 if (surface == NULL)
978 return;
979 addr_patched = patch_address_for_sbs_tb_stereo(pipe_ctx, &addr);
980 pipe_ctx->mi->funcs->mem_input_program_surface_flip_and_addr(
981 pipe_ctx->mi,
982 &surface->address,
983 surface->flip_immediate);
984 surface->status.requested_address = surface->address;
985 if (addr_patched)
986 pipe_ctx->surface->address.grph_stereo.left_addr = addr;
987 }
988
989 static bool dcn10_set_input_transfer_func(
990 struct pipe_ctx *pipe_ctx, const struct dc_surface *surface)
991 {
992 struct input_pixel_processor *ipp = pipe_ctx->ipp;
993 const struct dc_transfer_func *tf = NULL;
994 bool result = true;
995
996 if (ipp == NULL)
997 return false;
998
999 if (surface->in_transfer_func)
1000 tf = surface->in_transfer_func;
1001
1002 if (surface->gamma_correction && dce_use_lut(surface))
1003 ipp->funcs->ipp_program_input_lut(ipp,
1004 surface->gamma_correction);
1005
1006 if (tf == NULL)
1007 ipp->funcs->ipp_set_degamma(ipp, IPP_DEGAMMA_MODE_BYPASS);
1008 else if (tf->type == TF_TYPE_PREDEFINED) {
1009 switch (tf->tf) {
1010 case TRANSFER_FUNCTION_SRGB:
1011 ipp->funcs->ipp_set_degamma(ipp,
1012 IPP_DEGAMMA_MODE_HW_sRGB);
1013 break;
1014 case TRANSFER_FUNCTION_BT709:
1015 ipp->funcs->ipp_set_degamma(ipp,
1016 IPP_DEGAMMA_MODE_HW_xvYCC);
1017 break;
1018 case TRANSFER_FUNCTION_LINEAR:
1019 ipp->funcs->ipp_set_degamma(ipp,
1020 IPP_DEGAMMA_MODE_BYPASS);
1021 break;
1022 case TRANSFER_FUNCTION_PQ:
1023 result = false;
1024 break;
1025 default:
1026 result = false;
1027 break;
1028 }
1029 } else if (tf->type == TF_TYPE_BYPASS) {
1030 ipp->funcs->ipp_set_degamma(ipp, IPP_DEGAMMA_MODE_BYPASS);
1031 } else {
1032 /*TF_TYPE_DISTRIBUTED_POINTS*/
1033 result = false;
1034 }
1035
1036 return result;
1037 }
1038 /*modify the method to handle rgb for arr_points*/
1039 static bool convert_to_custom_float(
1040 struct pwl_result_data *rgb_resulted,
1041 struct curve_points *arr_points,
1042 uint32_t hw_points_num)
1043 {
1044 struct custom_float_format fmt;
1045
1046 struct pwl_result_data *rgb = rgb_resulted;
1047
1048 uint32_t i = 0;
1049
1050 fmt.exponenta_bits = 6;
1051 fmt.mantissa_bits = 12;
1052 fmt.sign = false;
1053
1054 if (!convert_to_custom_float_format(
1055 arr_points[0].x,
1056 &fmt,
1057 &arr_points[0].custom_float_x)) {
1058 BREAK_TO_DEBUGGER();
1059 return false;
1060 }
1061
1062 if (!convert_to_custom_float_format(
1063 arr_points[0].offset,
1064 &fmt,
1065 &arr_points[0].custom_float_offset)) {
1066 BREAK_TO_DEBUGGER();
1067 return false;
1068 }
1069
1070 if (!convert_to_custom_float_format(
1071 arr_points[0].slope,
1072 &fmt,
1073 &arr_points[0].custom_float_slope)) {
1074 BREAK_TO_DEBUGGER();
1075 return false;
1076 }
1077
1078 fmt.mantissa_bits = 10;
1079 fmt.sign = false;
1080
1081 if (!convert_to_custom_float_format(
1082 arr_points[1].x,
1083 &fmt,
1084 &arr_points[1].custom_float_x)) {
1085 BREAK_TO_DEBUGGER();
1086 return false;
1087 }
1088
1089 if (!convert_to_custom_float_format(
1090 arr_points[1].y,
1091 &fmt,
1092 &arr_points[1].custom_float_y)) {
1093 BREAK_TO_DEBUGGER();
1094 return false;
1095 }
1096
1097 if (!convert_to_custom_float_format(
1098 arr_points[1].slope,
1099 &fmt,
1100 &arr_points[1].custom_float_slope)) {
1101 BREAK_TO_DEBUGGER();
1102 return false;
1103 }
1104
1105 fmt.mantissa_bits = 12;
1106 fmt.sign = true;
1107
1108 while (i != hw_points_num) {
1109 if (!convert_to_custom_float_format(
1110 rgb->red,
1111 &fmt,
1112 &rgb->red_reg)) {
1113 BREAK_TO_DEBUGGER();
1114 return false;
1115 }
1116
1117 if (!convert_to_custom_float_format(
1118 rgb->green,
1119 &fmt,
1120 &rgb->green_reg)) {
1121 BREAK_TO_DEBUGGER();
1122 return false;
1123 }
1124
1125 if (!convert_to_custom_float_format(
1126 rgb->blue,
1127 &fmt,
1128 &rgb->blue_reg)) {
1129 BREAK_TO_DEBUGGER();
1130 return false;
1131 }
1132
1133 if (!convert_to_custom_float_format(
1134 rgb->delta_red,
1135 &fmt,
1136 &rgb->delta_red_reg)) {
1137 BREAK_TO_DEBUGGER();
1138 return false;
1139 }
1140
1141 if (!convert_to_custom_float_format(
1142 rgb->delta_green,
1143 &fmt,
1144 &rgb->delta_green_reg)) {
1145 BREAK_TO_DEBUGGER();
1146 return false;
1147 }
1148
1149 if (!convert_to_custom_float_format(
1150 rgb->delta_blue,
1151 &fmt,
1152 &rgb->delta_blue_reg)) {
1153 BREAK_TO_DEBUGGER();
1154 return false;
1155 }
1156
1157 ++rgb;
1158 ++i;
1159 }
1160
1161 return true;
1162 }
1163 #define MAX_REGIONS_NUMBER 34
1164 #define MAX_LOW_POINT 25
1165 #define NUMBER_SEGMENTS 32
1166
1167 static bool dcn10_translate_regamma_to_hw_format(const struct dc_transfer_func
1168 *output_tf, struct pwl_params *regamma_params)
1169 {
1170 struct curve_points *arr_points;
1171 struct pwl_result_data *rgb_resulted;
1172 struct pwl_result_data *rgb;
1173 struct pwl_result_data *rgb_plus_1;
1174 struct fixed31_32 y_r;
1175 struct fixed31_32 y_g;
1176 struct fixed31_32 y_b;
1177 struct fixed31_32 y1_min;
1178 struct fixed31_32 y3_max;
1179
1180 int32_t segment_start, segment_end;
1181 int32_t i;
1182 uint32_t j, k, seg_distr[MAX_REGIONS_NUMBER], increment, start_index, hw_points;
1183
1184 if (output_tf == NULL || regamma_params == NULL ||
1185 output_tf->type == TF_TYPE_BYPASS)
1186 return false;
1187
1188 arr_points = regamma_params->arr_points;
1189 rgb_resulted = regamma_params->rgb_resulted;
1190 hw_points = 0;
1191
1192 memset(regamma_params, 0, sizeof(struct pwl_params));
1193 memset(seg_distr, 0, sizeof(seg_distr));
1194
1195 if (output_tf->tf == TRANSFER_FUNCTION_PQ) {
1196 /* 32 segments
1197 * segments are from 2^-25 to 2^7
1198 */
1199 for (i = 0; i < 32 ; i++)
1200 seg_distr[i] = 3;
1201
1202 segment_start = -25;
1203 segment_end = 7;
1204 } else {
1205 /* 10 segments
1206 * segment is from 2^-10 to 2^0
1207 * There are less than 256 points, for optimization
1208 */
1209 seg_distr[0] = 3;
1210 seg_distr[1] = 4;
1211 seg_distr[2] = 4;
1212 seg_distr[3] = 4;
1213 seg_distr[4] = 4;
1214 seg_distr[5] = 4;
1215 seg_distr[6] = 4;
1216 seg_distr[7] = 4;
1217 seg_distr[8] = 5;
1218 seg_distr[9] = 5;
1219
1220 segment_start = -10;
1221 segment_end = 0;
1222 }
1223
1224 for (i = segment_end - segment_start; i < MAX_REGIONS_NUMBER ; i++)
1225 seg_distr[i] = -1;
1226
1227 for (k = 0; k < MAX_REGIONS_NUMBER; k++) {
1228 if (seg_distr[k] != -1)
1229 hw_points += (1 << seg_distr[k]);
1230 }
1231
1232 j = 0;
1233 for (k = 0; k < (segment_end - segment_start); k++) {
1234 increment = NUMBER_SEGMENTS / (1 << seg_distr[k]);
1235 start_index = (segment_start + k + MAX_LOW_POINT) * NUMBER_SEGMENTS;
1236 for (i = start_index; i < start_index + NUMBER_SEGMENTS; i += increment) {
1237 if (j == hw_points - 1)
1238 break;
1239 rgb_resulted[j].red = output_tf->tf_pts.red[i];
1240 rgb_resulted[j].green = output_tf->tf_pts.green[i];
1241 rgb_resulted[j].blue = output_tf->tf_pts.blue[i];
1242 j++;
1243 }
1244 }
1245
1246 /* last point */
1247 start_index = (segment_end + MAX_LOW_POINT) * NUMBER_SEGMENTS;
1248 rgb_resulted[hw_points - 1].red =
1249 output_tf->tf_pts.red[start_index];
1250 rgb_resulted[hw_points - 1].green =
1251 output_tf->tf_pts.green[start_index];
1252 rgb_resulted[hw_points - 1].blue =
1253 output_tf->tf_pts.blue[start_index];
1254
1255 arr_points[0].x = dal_fixed31_32_pow(dal_fixed31_32_from_int(2),
1256 dal_fixed31_32_from_int(segment_start));
1257 arr_points[1].x = dal_fixed31_32_pow(dal_fixed31_32_from_int(2),
1258 dal_fixed31_32_from_int(segment_end));
1259 arr_points[2].x = dal_fixed31_32_pow(dal_fixed31_32_from_int(2),
1260 dal_fixed31_32_from_int(segment_end));
1261
1262 y_r = rgb_resulted[0].red;
1263 y_g = rgb_resulted[0].green;
1264 y_b = rgb_resulted[0].blue;
1265
1266 y1_min = dal_fixed31_32_min(y_r, dal_fixed31_32_min(y_g, y_b));
1267
1268 arr_points[0].y = y1_min;
1269 arr_points[0].slope = dal_fixed31_32_div(
1270 arr_points[0].y,
1271 arr_points[0].x);
1272 y_r = rgb_resulted[hw_points - 1].red;
1273 y_g = rgb_resulted[hw_points - 1].green;
1274 y_b = rgb_resulted[hw_points - 1].blue;
1275
1276 /* see comment above, m_arrPoints[1].y should be the Y value for the
1277 * region end (m_numOfHwPoints), not last HW point(m_numOfHwPoints - 1)
1278 */
1279 y3_max = dal_fixed31_32_max(y_r, dal_fixed31_32_max(y_g, y_b));
1280
1281 arr_points[1].y = y3_max;
1282 arr_points[2].y = y3_max;
1283
1284 arr_points[1].slope = dal_fixed31_32_zero;
1285 arr_points[2].slope = dal_fixed31_32_zero;
1286
1287 if (output_tf->tf == TRANSFER_FUNCTION_PQ) {
1288 /* for PQ, we want to have a straight line from last HW X point,
1289 * and the slope to be such that we hit 1.0 at 10000 nits.
1290 */
1291 const struct fixed31_32 end_value =
1292 dal_fixed31_32_from_int(125);
1293
1294 arr_points[1].slope = dal_fixed31_32_div(
1295 dal_fixed31_32_sub(dal_fixed31_32_one, arr_points[1].y),
1296 dal_fixed31_32_sub(end_value, arr_points[1].x));
1297 arr_points[2].slope = dal_fixed31_32_div(
1298 dal_fixed31_32_sub(dal_fixed31_32_one, arr_points[1].y),
1299 dal_fixed31_32_sub(end_value, arr_points[1].x));
1300 }
1301
1302 regamma_params->hw_points_num = hw_points;
1303
1304 i = 1;
1305 for (k = 0; k < MAX_REGIONS_NUMBER && i < MAX_REGIONS_NUMBER; k++) {
1306 if (seg_distr[k] != -1) {
1307 regamma_params->arr_curve_points[k].segments_num =
1308 seg_distr[k];
1309 regamma_params->arr_curve_points[i].offset =
1310 regamma_params->arr_curve_points[k].
1311 offset + (1 << seg_distr[k]);
1312 }
1313 i++;
1314 }
1315
1316 if (seg_distr[k] != -1)
1317 regamma_params->arr_curve_points[k].segments_num =
1318 seg_distr[k];
1319
1320 rgb = rgb_resulted;
1321 rgb_plus_1 = rgb_resulted + 1;
1322
1323 i = 1;
1324
1325 while (i != hw_points + 1) {
1326 if (dal_fixed31_32_lt(rgb_plus_1->red, rgb->red))
1327 rgb_plus_1->red = rgb->red;
1328 if (dal_fixed31_32_lt(rgb_plus_1->green, rgb->green))
1329 rgb_plus_1->green = rgb->green;
1330 if (dal_fixed31_32_lt(rgb_plus_1->blue, rgb->blue))
1331 rgb_plus_1->blue = rgb->blue;
1332
1333 rgb->delta_red = dal_fixed31_32_sub(
1334 rgb_plus_1->red,
1335 rgb->red);
1336 rgb->delta_green = dal_fixed31_32_sub(
1337 rgb_plus_1->green,
1338 rgb->green);
1339 rgb->delta_blue = dal_fixed31_32_sub(
1340 rgb_plus_1->blue,
1341 rgb->blue);
1342
1343 ++rgb_plus_1;
1344 ++rgb;
1345 ++i;
1346 }
1347
1348 convert_to_custom_float(rgb_resulted, arr_points, hw_points);
1349
1350 return true;
1351 }
1352
1353 static bool dcn10_set_output_transfer_func(
1354 struct pipe_ctx *pipe_ctx,
1355 const struct core_stream *stream)
1356 {
1357 struct transform *xfm = pipe_ctx->xfm;
1358
1359 if (xfm == NULL)
1360 return false;
1361
1362 xfm->regamma_params.hw_points_num = GAMMA_HW_POINTS_NUM;
1363
1364 if (stream->public.out_transfer_func &&
1365 stream->public.out_transfer_func->type ==
1366 TF_TYPE_PREDEFINED &&
1367 stream->public.out_transfer_func->tf ==
1368 TRANSFER_FUNCTION_SRGB) {
1369 xfm->funcs->opp_set_regamma_mode(xfm, OPP_REGAMMA_SRGB);
1370 } else if (dcn10_translate_regamma_to_hw_format(
1371 stream->public.out_transfer_func, &xfm->regamma_params)) {
1372 xfm->funcs->opp_program_regamma_pwl(xfm, &xfm->regamma_params);
1373 xfm->funcs->opp_set_regamma_mode(xfm, OPP_REGAMMA_USER);
1374 } else {
1375 xfm->funcs->opp_set_regamma_mode(xfm, OPP_REGAMMA_BYPASS);
1376 }
1377
1378 return true;
1379 }
1380
1381 static void dcn10_pipe_control_lock(
1382 struct core_dc *dc,
1383 struct pipe_ctx *pipe,
1384 bool lock)
1385 {
1386 /* use TG master update lock to lock everything on the TG
1387 * therefore only top pipe need to lock
1388 */
1389 if (pipe->top_pipe)
1390 return;
1391
1392 if (dc->public.debug.sanity_checks)
1393 verify_allow_pstate_change_high(dc->hwseq);
1394
1395 if (lock)
1396 pipe->tg->funcs->lock(pipe->tg);
1397 else
1398 pipe->tg->funcs->unlock(pipe->tg);
1399
1400 if (dc->public.debug.sanity_checks)
1401 verify_allow_pstate_change_high(dc->hwseq);
1402 }
1403
1404 static bool wait_for_reset_trigger_to_occur(
1405 struct dc_context *dc_ctx,
1406 struct timing_generator *tg)
1407 {
1408 bool rc = false;
1409
1410 /* To avoid endless loop we wait at most
1411 * frames_to_wait_on_triggered_reset frames for the reset to occur. */
1412 const uint32_t frames_to_wait_on_triggered_reset = 10;
1413 int i;
1414
1415 for (i = 0; i < frames_to_wait_on_triggered_reset; i++) {
1416
1417 if (!tg->funcs->is_counter_moving(tg)) {
1418 DC_ERROR("TG counter is not moving!\n");
1419 break;
1420 }
1421
1422 if (tg->funcs->did_triggered_reset_occur(tg)) {
1423 rc = true;
1424 /* usually occurs at i=1 */
1425 DC_SYNC_INFO("GSL: reset occurred at wait count: %d\n",
1426 i);
1427 break;
1428 }
1429
1430 /* Wait for one frame. */
1431 tg->funcs->wait_for_state(tg, CRTC_STATE_VACTIVE);
1432 tg->funcs->wait_for_state(tg, CRTC_STATE_VBLANK);
1433 }
1434
1435 if (false == rc)
1436 DC_ERROR("GSL: Timeout on reset trigger!\n");
1437
1438 return rc;
1439 }
1440
1441 static void dcn10_enable_timing_synchronization(
1442 struct core_dc *dc,
1443 int group_index,
1444 int group_size,
1445 struct pipe_ctx *grouped_pipes[])
1446 {
1447 struct dc_context *dc_ctx = dc->ctx;
1448 int i;
1449
1450 DC_SYNC_INFO("Setting up OTG reset trigger\n");
1451
1452 for (i = 1; i < group_size; i++)
1453 grouped_pipes[i]->tg->funcs->enable_reset_trigger(
1454 grouped_pipes[i]->tg, grouped_pipes[0]->tg->inst);
1455
1456
1457 DC_SYNC_INFO("Waiting for trigger\n");
1458
1459 /* Need to get only check 1 pipe for having reset as all the others are
1460 * synchronized. Look at last pipe programmed to reset.
1461 */
1462 wait_for_reset_trigger_to_occur(dc_ctx, grouped_pipes[1]->tg);
1463 for (i = 1; i < group_size; i++)
1464 grouped_pipes[i]->tg->funcs->disable_reset_trigger(
1465 grouped_pipes[i]->tg);
1466
1467 DC_SYNC_INFO("Sync complete\n");
1468 }
1469
1470 static void print_rq_dlg_ttu(
1471 struct core_dc *core_dc,
1472 struct pipe_ctx *pipe_ctx)
1473 {
1474 dm_logger_write(core_dc->ctx->logger, LOG_BANDWIDTH_CALCS,
1475 "\n============== DML TTU Output parameters [%d] ==============\n"
1476 "qos_level_low_wm: %d, \n"
1477 "qos_level_high_wm: %d, \n"
1478 "min_ttu_vblank: %d, \n"
1479 "qos_level_flip: %d, \n"
1480 "refcyc_per_req_delivery_l: %d, \n"
1481 "qos_level_fixed_l: %d, \n"
1482 "qos_ramp_disable_l: %d, \n"
1483 "refcyc_per_req_delivery_pre_l: %d, \n"
1484 "refcyc_per_req_delivery_c: %d, \n"
1485 "qos_level_fixed_c: %d, \n"
1486 "qos_ramp_disable_c: %d, \n"
1487 "refcyc_per_req_delivery_pre_c: %d\n"
1488 "=============================================================\n",
1489 pipe_ctx->pipe_idx,
1490 pipe_ctx->ttu_regs.qos_level_low_wm,
1491 pipe_ctx->ttu_regs.qos_level_high_wm,
1492 pipe_ctx->ttu_regs.min_ttu_vblank,
1493 pipe_ctx->ttu_regs.qos_level_flip,
1494 pipe_ctx->ttu_regs.refcyc_per_req_delivery_l,
1495 pipe_ctx->ttu_regs.qos_level_fixed_l,
1496 pipe_ctx->ttu_regs.qos_ramp_disable_l,
1497 pipe_ctx->ttu_regs.refcyc_per_req_delivery_pre_l,
1498 pipe_ctx->ttu_regs.refcyc_per_req_delivery_c,
1499 pipe_ctx->ttu_regs.qos_level_fixed_c,
1500 pipe_ctx->ttu_regs.qos_ramp_disable_c,
1501 pipe_ctx->ttu_regs.refcyc_per_req_delivery_pre_c
1502 );
1503
1504 dm_logger_write(core_dc->ctx->logger, LOG_BANDWIDTH_CALCS,
1505 "\n============== DML DLG Output parameters [%d] ==============\n"
1506 "refcyc_h_blank_end: %d, \n"
1507 "dlg_vblank_end: %d, \n"
1508 "min_dst_y_next_start: %d, \n"
1509 "refcyc_per_htotal: %d, \n"
1510 "refcyc_x_after_scaler: %d, \n"
1511 "dst_y_after_scaler: %d, \n"
1512 "dst_y_prefetch: %d, \n"
1513 "dst_y_per_vm_vblank: %d, \n"
1514 "dst_y_per_row_vblank: %d, \n"
1515 "ref_freq_to_pix_freq: %d, \n"
1516 "vratio_prefetch: %d, \n"
1517 "refcyc_per_pte_group_vblank_l: %d, \n"
1518 "refcyc_per_meta_chunk_vblank_l: %d, \n"
1519 "dst_y_per_pte_row_nom_l: %d, \n"
1520 "refcyc_per_pte_group_nom_l: %d, \n",
1521 pipe_ctx->pipe_idx,
1522 pipe_ctx->dlg_regs.refcyc_h_blank_end,
1523 pipe_ctx->dlg_regs.dlg_vblank_end,
1524 pipe_ctx->dlg_regs.min_dst_y_next_start,
1525 pipe_ctx->dlg_regs.refcyc_per_htotal,
1526 pipe_ctx->dlg_regs.refcyc_x_after_scaler,
1527 pipe_ctx->dlg_regs.dst_y_after_scaler,
1528 pipe_ctx->dlg_regs.dst_y_prefetch,
1529 pipe_ctx->dlg_regs.dst_y_per_vm_vblank,
1530 pipe_ctx->dlg_regs.dst_y_per_row_vblank,
1531 pipe_ctx->dlg_regs.ref_freq_to_pix_freq,
1532 pipe_ctx->dlg_regs.vratio_prefetch,
1533 pipe_ctx->dlg_regs.refcyc_per_pte_group_vblank_l,
1534 pipe_ctx->dlg_regs.refcyc_per_meta_chunk_vblank_l,
1535 pipe_ctx->dlg_regs.dst_y_per_pte_row_nom_l,
1536 pipe_ctx->dlg_regs.refcyc_per_pte_group_nom_l
1537 );
1538
1539 dm_logger_write(core_dc->ctx->logger, LOG_BANDWIDTH_CALCS,
1540 "\ndst_y_per_meta_row_nom_l: %d, \n"
1541 "refcyc_per_meta_chunk_nom_l: %d, \n"
1542 "refcyc_per_line_delivery_pre_l: %d, \n"
1543 "refcyc_per_line_delivery_l: %d, \n"
1544 "vratio_prefetch_c: %d, \n"
1545 "refcyc_per_pte_group_vblank_c: %d, \n"
1546 "refcyc_per_meta_chunk_vblank_c: %d, \n"
1547 "dst_y_per_pte_row_nom_c: %d, \n"
1548 "refcyc_per_pte_group_nom_c: %d, \n"
1549 "dst_y_per_meta_row_nom_c: %d, \n"
1550 "refcyc_per_meta_chunk_nom_c: %d, \n"
1551 "refcyc_per_line_delivery_pre_c: %d, \n"
1552 "refcyc_per_line_delivery_c: %d \n"
1553 "========================================================\n",
1554 pipe_ctx->dlg_regs.dst_y_per_meta_row_nom_l,
1555 pipe_ctx->dlg_regs.refcyc_per_meta_chunk_nom_l,
1556 pipe_ctx->dlg_regs.refcyc_per_line_delivery_pre_l,
1557 pipe_ctx->dlg_regs.refcyc_per_line_delivery_l,
1558 pipe_ctx->dlg_regs.vratio_prefetch_c,
1559 pipe_ctx->dlg_regs.refcyc_per_pte_group_vblank_c,
1560 pipe_ctx->dlg_regs.refcyc_per_meta_chunk_vblank_c,
1561 pipe_ctx->dlg_regs.dst_y_per_pte_row_nom_c,
1562 pipe_ctx->dlg_regs.refcyc_per_pte_group_nom_c,
1563 pipe_ctx->dlg_regs.dst_y_per_meta_row_nom_c,
1564 pipe_ctx->dlg_regs.refcyc_per_meta_chunk_nom_c,
1565 pipe_ctx->dlg_regs.refcyc_per_line_delivery_pre_c,
1566 pipe_ctx->dlg_regs.refcyc_per_line_delivery_c
1567 );
1568
1569 dm_logger_write(core_dc->ctx->logger, LOG_BANDWIDTH_CALCS,
1570 "\n============== DML RQ Output parameters [%d] ==============\n"
1571 "chunk_size: %d \n"
1572 "min_chunk_size: %d \n"
1573 "meta_chunk_size: %d \n"
1574 "min_meta_chunk_size: %d \n"
1575 "dpte_group_size: %d \n"
1576 "mpte_group_size: %d \n"
1577 "swath_height: %d \n"
1578 "pte_row_height_linear: %d \n"
1579 "========================================================\n",
1580 pipe_ctx->pipe_idx,
1581 pipe_ctx->rq_regs.rq_regs_l.chunk_size,
1582 pipe_ctx->rq_regs.rq_regs_l.min_chunk_size,
1583 pipe_ctx->rq_regs.rq_regs_l.meta_chunk_size,
1584 pipe_ctx->rq_regs.rq_regs_l.min_meta_chunk_size,
1585 pipe_ctx->rq_regs.rq_regs_l.dpte_group_size,
1586 pipe_ctx->rq_regs.rq_regs_l.mpte_group_size,
1587 pipe_ctx->rq_regs.rq_regs_l.swath_height,
1588 pipe_ctx->rq_regs.rq_regs_l.pte_row_height_linear
1589 );
1590 }
1591
1592 static void dcn10_power_on_fe(
1593 struct core_dc *dc,
1594 struct pipe_ctx *pipe_ctx,
1595 struct validate_context *context)
1596 {
1597 struct dc_surface *dc_surface = pipe_ctx->surface;
1598 struct dce_hwseq *hws = dc->hwseq;
1599
1600 power_on_plane(dc->hwseq,
1601 pipe_ctx->pipe_idx);
1602
1603 /* enable DCFCLK current DCHUB */
1604 REG_UPDATE(HUBP_CLK_CNTL[pipe_ctx->pipe_idx],
1605 HUBP_CLOCK_ENABLE, 1);
1606
1607 /* make sure OPP_PIPE_CLOCK_EN = 1 */
1608 REG_UPDATE(OPP_PIPE_CONTROL[pipe_ctx->tg->inst],
1609 OPP_PIPE_CLOCK_EN, 1);
1610 /*TODO: REG_UPDATE(DENTIST_DISPCLK_CNTL, DENTIST_DPPCLK_WDIVIDER, 0x1f);*/
1611
1612 if (dc_surface) {
1613 dm_logger_write(dc->ctx->logger, LOG_DC,
1614 "Pipe:%d 0x%x: addr hi:0x%x, "
1615 "addr low:0x%x, "
1616 "src: %d, %d, %d,"
1617 " %d; dst: %d, %d, %d, %d;\n",
1618 pipe_ctx->pipe_idx,
1619 dc_surface,
1620 dc_surface->address.grph.addr.high_part,
1621 dc_surface->address.grph.addr.low_part,
1622 dc_surface->src_rect.x,
1623 dc_surface->src_rect.y,
1624 dc_surface->src_rect.width,
1625 dc_surface->src_rect.height,
1626 dc_surface->dst_rect.x,
1627 dc_surface->dst_rect.y,
1628 dc_surface->dst_rect.width,
1629 dc_surface->dst_rect.height);
1630
1631 dm_logger_write(dc->ctx->logger, LOG_HW_SET_MODE,
1632 "Pipe %d: width, height, x, y\n"
1633 "viewport:%d, %d, %d, %d\n"
1634 "recout: %d, %d, %d, %d\n",
1635 pipe_ctx->pipe_idx,
1636 pipe_ctx->scl_data.viewport.width,
1637 pipe_ctx->scl_data.viewport.height,
1638 pipe_ctx->scl_data.viewport.x,
1639 pipe_ctx->scl_data.viewport.y,
1640 pipe_ctx->scl_data.recout.width,
1641 pipe_ctx->scl_data.recout.height,
1642 pipe_ctx->scl_data.recout.x,
1643 pipe_ctx->scl_data.recout.y);
1644 print_rq_dlg_ttu(dc, pipe_ctx);
1645 }
1646 }
1647
1648 static void program_gamut_remap(struct pipe_ctx *pipe_ctx)
1649 {
1650 struct xfm_grph_csc_adjustment adjust;
1651 memset(&adjust, 0, sizeof(adjust));
1652 adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS;
1653
1654
1655 if (pipe_ctx->stream->public.gamut_remap_matrix.enable_remap == true) {
1656 adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW;
1657 adjust.temperature_matrix[0] =
1658 pipe_ctx->stream->
1659 public.gamut_remap_matrix.matrix[0];
1660 adjust.temperature_matrix[1] =
1661 pipe_ctx->stream->
1662 public.gamut_remap_matrix.matrix[1];
1663 adjust.temperature_matrix[2] =
1664 pipe_ctx->stream->
1665 public.gamut_remap_matrix.matrix[2];
1666 adjust.temperature_matrix[3] =
1667 pipe_ctx->stream->
1668 public.gamut_remap_matrix.matrix[4];
1669 adjust.temperature_matrix[4] =
1670 pipe_ctx->stream->
1671 public.gamut_remap_matrix.matrix[5];
1672 adjust.temperature_matrix[5] =
1673 pipe_ctx->stream->
1674 public.gamut_remap_matrix.matrix[6];
1675 adjust.temperature_matrix[6] =
1676 pipe_ctx->stream->
1677 public.gamut_remap_matrix.matrix[8];
1678 adjust.temperature_matrix[7] =
1679 pipe_ctx->stream->
1680 public.gamut_remap_matrix.matrix[9];
1681 adjust.temperature_matrix[8] =
1682 pipe_ctx->stream->
1683 public.gamut_remap_matrix.matrix[10];
1684 }
1685
1686 pipe_ctx->xfm->funcs->transform_set_gamut_remap(pipe_ctx->xfm, &adjust);
1687 }
1688
1689
1690 static void program_csc_matrix(struct pipe_ctx *pipe_ctx,
1691 enum dc_color_space colorspace,
1692 uint16_t *matrix)
1693 {
1694 int i;
1695 struct out_csc_color_matrix tbl_entry;
1696
1697 if (pipe_ctx->stream->public.csc_color_matrix.enable_adjustment
1698 == true) {
1699 enum dc_color_space color_space =
1700 pipe_ctx->stream->public.output_color_space;
1701
1702 //uint16_t matrix[12];
1703 for (i = 0; i < 12; i++)
1704 tbl_entry.regval[i] = pipe_ctx->stream->public.csc_color_matrix.matrix[i];
1705
1706 tbl_entry.color_space = color_space;
1707 //tbl_entry.regval = matrix;
1708 pipe_ctx->opp->funcs->opp_set_csc_adjustment(pipe_ctx->opp, &tbl_entry);
1709 }
1710 }
1711 static bool is_lower_pipe_tree_visible(struct pipe_ctx *pipe_ctx)
1712 {
1713 if (pipe_ctx->surface->visible)
1714 return true;
1715 if (pipe_ctx->bottom_pipe && is_lower_pipe_tree_visible(pipe_ctx->bottom_pipe))
1716 return true;
1717 return false;
1718 }
1719
1720 static bool is_upper_pipe_tree_visible(struct pipe_ctx *pipe_ctx)
1721 {
1722 if (pipe_ctx->surface->visible)
1723 return true;
1724 if (pipe_ctx->top_pipe && is_upper_pipe_tree_visible(pipe_ctx->top_pipe))
1725 return true;
1726 return false;
1727 }
1728
1729 static bool is_pipe_tree_visible(struct pipe_ctx *pipe_ctx)
1730 {
1731 if (pipe_ctx->surface->visible)
1732 return true;
1733 if (pipe_ctx->top_pipe && is_upper_pipe_tree_visible(pipe_ctx->top_pipe))
1734 return true;
1735 if (pipe_ctx->bottom_pipe && is_lower_pipe_tree_visible(pipe_ctx->bottom_pipe))
1736 return true;
1737 return false;
1738 }
1739
1740 static bool is_rgb_cspace(enum dc_color_space output_color_space)
1741 {
1742 switch (output_color_space) {
1743 case COLOR_SPACE_SRGB:
1744 case COLOR_SPACE_SRGB_LIMITED:
1745 case COLOR_SPACE_2020_RGB_FULLRANGE:
1746 case COLOR_SPACE_2020_RGB_LIMITEDRANGE:
1747 case COLOR_SPACE_ADOBERGB:
1748 return true;
1749 case COLOR_SPACE_YCBCR601:
1750 case COLOR_SPACE_YCBCR709:
1751 case COLOR_SPACE_YCBCR601_LIMITED:
1752 case COLOR_SPACE_YCBCR709_LIMITED:
1753 case COLOR_SPACE_2020_YCBCR:
1754 return false;
1755 default:
1756 /* Add a case to switch */
1757 BREAK_TO_DEBUGGER();
1758 return false;
1759 }
1760 }
1761
1762 static void dcn10_get_surface_visual_confirm_color(
1763 const struct pipe_ctx *pipe_ctx,
1764 struct tg_color *color)
1765 {
1766 uint32_t color_value = MAX_TG_COLOR_VALUE;
1767
1768 switch (pipe_ctx->scl_data.format) {
1769 case PIXEL_FORMAT_ARGB8888:
1770 /* set boarder color to red */
1771 color->color_r_cr = color_value;
1772 break;
1773
1774 case PIXEL_FORMAT_ARGB2101010:
1775 /* set boarder color to blue */
1776 color->color_b_cb = color_value;
1777 break;
1778 case PIXEL_FORMAT_420BPP8:
1779 /* set boarder color to green */
1780 color->color_g_y = color_value;
1781 break;
1782 case PIXEL_FORMAT_420BPP10:
1783 /* set boarder color to yellow */
1784 color->color_g_y = color_value;
1785 color->color_r_cr = color_value;
1786 break;
1787 case PIXEL_FORMAT_FP16:
1788 /* set boarder color to white */
1789 color->color_r_cr = color_value;
1790 color->color_b_cb = color_value;
1791 color->color_g_y = color_value;
1792 break;
1793 default:
1794 break;
1795 }
1796 }
1797
1798 static void update_dchubp_dpp(
1799 struct core_dc *dc,
1800 struct pipe_ctx *pipe_ctx,
1801 struct validate_context *context)
1802 {
1803 struct dce_hwseq *hws = dc->hwseq;
1804 struct mem_input *mi = pipe_ctx->mi;
1805 struct input_pixel_processor *ipp = pipe_ctx->ipp;
1806 struct dc_surface *surface = pipe_ctx->surface;
1807 union plane_size size = surface->plane_size;
1808 struct default_adjustment ocsc = {0};
1809 struct tg_color black_color = {0};
1810 struct mpcc_cfg mpcc_cfg;
1811 bool per_pixel_alpha = surface->per_pixel_alpha && pipe_ctx->bottom_pipe;
1812
1813 /* TODO: proper fix once fpga works */
1814 /* depends on DML calculation, DPP clock value may change dynamically */
1815 enable_dppclk(
1816 dc->hwseq,
1817 pipe_ctx->pipe_idx,
1818 pipe_ctx->pix_clk_params.requested_pix_clk,
1819 context->bw.dcn.calc_clk.dppclk_div);
1820 dc->current_context->bw.dcn.cur_clk.dppclk_div =
1821 context->bw.dcn.calc_clk.dppclk_div;
1822 context->bw.dcn.cur_clk.dppclk_div = context->bw.dcn.calc_clk.dppclk_div;
1823
1824 /* TODO: Need input parameter to tell current DCHUB pipe tie to which OTG
1825 * VTG is within DCHUBBUB which is commond block share by each pipe HUBP.
1826 * VTG is 1:1 mapping with OTG. Each pipe HUBP will select which VTG
1827 */
1828 REG_UPDATE(DCHUBP_CNTL[pipe_ctx->pipe_idx], HUBP_VTG_SEL, pipe_ctx->tg->inst);
1829
1830 update_plane_addr(dc, pipe_ctx);
1831
1832 mi->funcs->mem_input_setup(
1833 mi,
1834 &pipe_ctx->dlg_regs,
1835 &pipe_ctx->ttu_regs,
1836 &pipe_ctx->rq_regs,
1837 &pipe_ctx->pipe_dlg_param);
1838
1839 size.grph.surface_size = pipe_ctx->scl_data.viewport;
1840
1841 if (dc->public.config.gpu_vm_support)
1842 mi->funcs->mem_input_program_pte_vm(
1843 pipe_ctx->mi,
1844 surface->format,
1845 &surface->tiling_info,
1846 surface->rotation);
1847
1848 ipp->funcs->ipp_setup(ipp,
1849 surface->format,
1850 1,
1851 IPP_OUTPUT_FORMAT_12_BIT_FIX);
1852
1853 pipe_ctx->scl_data.lb_params.alpha_en = per_pixel_alpha;
1854 mpcc_cfg.top_dpp_id = pipe_ctx->pipe_idx;
1855 if (pipe_ctx->bottom_pipe)
1856 mpcc_cfg.bot_mpcc_id = pipe_ctx->bottom_pipe->mpcc->inst;
1857 else
1858 mpcc_cfg.bot_mpcc_id = 0xf;
1859 mpcc_cfg.opp_id = pipe_ctx->tg->inst;
1860 mpcc_cfg.top_of_tree = pipe_ctx->pipe_idx == pipe_ctx->tg->inst;
1861 mpcc_cfg.per_pixel_alpha = per_pixel_alpha;
1862 /* DCN1.0 has output CM before MPC which seems to screw with
1863 * pre-multiplied alpha.
1864 */
1865 mpcc_cfg.pre_multiplied_alpha = is_rgb_cspace(
1866 pipe_ctx->stream->public.output_color_space)
1867 && per_pixel_alpha;
1868 pipe_ctx->mpcc->funcs->set(pipe_ctx->mpcc, &mpcc_cfg);
1869
1870 if (dc->public.debug.surface_visual_confirm) {
1871 dcn10_get_surface_visual_confirm_color(pipe_ctx, &black_color);
1872 } else {
1873 color_space_to_black_color(
1874 dc, pipe_ctx->stream->public.output_color_space,
1875 &black_color);
1876 }
1877 pipe_ctx->mpcc->funcs->set_bg_color(pipe_ctx->mpcc, &black_color);
1878
1879 pipe_ctx->scl_data.lb_params.depth = LB_PIXEL_DEPTH_30BPP;
1880 /* scaler configuration */
1881 pipe_ctx->xfm->funcs->transform_set_scaler(
1882 pipe_ctx->xfm, &pipe_ctx->scl_data);
1883 mi->funcs->mem_program_viewport(mi,
1884 &pipe_ctx->scl_data.viewport, &pipe_ctx->scl_data.viewport_c);
1885
1886 /*gamut remap*/
1887 program_gamut_remap(pipe_ctx);
1888
1889 /*TODO add adjustments parameters*/
1890 ocsc.out_color_space = pipe_ctx->stream->public.output_color_space;
1891 pipe_ctx->xfm->funcs->opp_set_csc_default(pipe_ctx->xfm, &ocsc);
1892
1893 mi->funcs->mem_input_program_surface_config(
1894 mi,
1895 surface->format,
1896 &surface->tiling_info,
1897 &size,
1898 surface->rotation,
1899 &surface->dcc,
1900 surface->horizontal_mirror);
1901
1902 mi->funcs->set_blank(mi, !is_pipe_tree_visible(pipe_ctx));
1903 }
1904
1905 static void program_all_pipe_in_tree(
1906 struct core_dc *dc,
1907 struct pipe_ctx *pipe_ctx,
1908 struct validate_context *context)
1909 {
1910 unsigned int ref_clk_mhz = dc->res_pool->ref_clock_inKhz/1000;
1911
1912 if (pipe_ctx->top_pipe == NULL) {
1913
1914 /* lock otg_master_update to process all pipes associated with
1915 * this OTG. this is done only one time.
1916 */
1917 /* watermark is for all pipes */
1918 program_watermarks(dc->hwseq, &context->bw.dcn.watermarks, ref_clk_mhz);
1919
1920 if (dc->public.debug.sanity_checks) {
1921 /* pstate stuck check after watermark update */
1922 verify_allow_pstate_change_high(dc->hwseq);
1923 }
1924
1925 pipe_ctx->tg->funcs->lock(pipe_ctx->tg);
1926
1927 pipe_ctx->tg->dlg_otg_param.vready_offset = pipe_ctx->pipe_dlg_param.vready_offset;
1928 pipe_ctx->tg->dlg_otg_param.vstartup_start = pipe_ctx->pipe_dlg_param.vstartup_start;
1929 pipe_ctx->tg->dlg_otg_param.vupdate_offset = pipe_ctx->pipe_dlg_param.vupdate_offset;
1930 pipe_ctx->tg->dlg_otg_param.vupdate_width = pipe_ctx->pipe_dlg_param.vupdate_width;
1931 pipe_ctx->tg->dlg_otg_param.signal = pipe_ctx->stream->signal;
1932
1933 pipe_ctx->tg->funcs->program_global_sync(
1934 pipe_ctx->tg);
1935 pipe_ctx->tg->funcs->set_blank(pipe_ctx->tg, !is_pipe_tree_visible(pipe_ctx));
1936 }
1937
1938 if (pipe_ctx->surface != NULL) {
1939 dcn10_power_on_fe(dc, pipe_ctx, context);
1940 update_dchubp_dpp(dc, pipe_ctx, context);
1941 }
1942
1943 if (dc->public.debug.sanity_checks) {
1944 /* pstate stuck check after each pipe is programmed */
1945 verify_allow_pstate_change_high(dc->hwseq);
1946 }
1947
1948 if (pipe_ctx->bottom_pipe != NULL)
1949 program_all_pipe_in_tree(dc, pipe_ctx->bottom_pipe, context);
1950 }
1951
1952 static void dcn10_pplib_apply_display_requirements(
1953 struct core_dc *dc,
1954 struct validate_context *context)
1955 {
1956 struct dm_pp_display_configuration *pp_display_cfg = &context->pp_display_cfg;
1957
1958 pp_display_cfg->all_displays_in_sync = false;/*todo*/
1959 pp_display_cfg->nb_pstate_switch_disable = false;
1960 pp_display_cfg->min_engine_clock_khz = context->bw.dcn.cur_clk.dcfclk_khz;
1961 pp_display_cfg->min_memory_clock_khz = context->bw.dcn.cur_clk.fclk_khz;
1962 pp_display_cfg->min_engine_clock_deep_sleep_khz = context->bw.dcn.cur_clk.dcfclk_deep_sleep_khz;
1963 pp_display_cfg->min_dcfc_deep_sleep_clock_khz = context->bw.dcn.cur_clk.dcfclk_deep_sleep_khz;
1964 pp_display_cfg->avail_mclk_switch_time_us =
1965 context->bw.dcn.cur_clk.dram_ccm_us > 0 ? context->bw.dcn.cur_clk.dram_ccm_us : 0;
1966 pp_display_cfg->avail_mclk_switch_time_in_disp_active_us =
1967 context->bw.dcn.cur_clk.min_active_dram_ccm_us > 0 ? context->bw.dcn.cur_clk.min_active_dram_ccm_us : 0;
1968 pp_display_cfg->min_dcfclock_khz = context->bw.dcn.cur_clk.dcfclk_khz;
1969 pp_display_cfg->disp_clk_khz = context->bw.dcn.cur_clk.dispclk_khz;
1970 dce110_fill_display_configs(context, pp_display_cfg);
1971
1972 if (memcmp(&dc->prev_display_config, pp_display_cfg, sizeof(
1973 struct dm_pp_display_configuration)) != 0)
1974 dm_pp_apply_display_requirements(dc->ctx, pp_display_cfg);
1975
1976 dc->prev_display_config = *pp_display_cfg;
1977 }
1978
1979 static void dcn10_apply_ctx_for_surface(
1980 struct core_dc *dc,
1981 const struct dc_surface *surface,
1982 struct validate_context *context)
1983 {
1984 int i, be_idx;
1985
1986 if (dc->public.debug.sanity_checks)
1987 verify_allow_pstate_change_high(dc->hwseq);
1988
1989 if (!surface)
1990 return;
1991
1992 for (be_idx = 0; be_idx < dc->res_pool->pipe_count; be_idx++)
1993 if (surface == context->res_ctx.pipe_ctx[be_idx].surface)
1994 break;
1995
1996 /* reset unused mpcc */
1997 for (i = 0; i < dc->res_pool->pipe_count; i++) {
1998 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
1999 struct pipe_ctx *old_pipe_ctx =
2000 &dc->current_context->res_ctx.pipe_ctx[i];
2001
2002 if (!pipe_ctx->surface && !old_pipe_ctx->surface)
2003 continue;
2004
2005 /*
2006 * Powergate reused pipes that are not powergated
2007 * fairly hacky right now, using opp_id as indicator
2008 */
2009
2010 if (pipe_ctx->surface && !old_pipe_ctx->surface) {
2011 if (pipe_ctx->mpcc->opp_id != 0xf && pipe_ctx->tg->inst == be_idx) {
2012 dcn10_power_down_fe(dc, pipe_ctx->pipe_idx);
2013 /*
2014 * power down fe will unlock when calling reset, need
2015 * to lock it back here. Messy, need rework.
2016 */
2017 pipe_ctx->tg->funcs->lock(pipe_ctx->tg);
2018 }
2019 }
2020
2021
2022 if ((!pipe_ctx->surface && old_pipe_ctx->surface)
2023 || (!pipe_ctx->stream && old_pipe_ctx->stream)) {
2024 struct mpcc_cfg mpcc_cfg;
2025 int opp_id_cached = old_pipe_ctx->mpcc->opp_id;
2026
2027 if (old_pipe_ctx->tg->inst != be_idx)
2028 continue;
2029
2030 if (!old_pipe_ctx->top_pipe) {
2031 ASSERT(0);
2032 continue;
2033 }
2034
2035 /* reset mpc */
2036 mpcc_cfg.opp_id = 0xf;
2037 mpcc_cfg.top_dpp_id = 0xf;
2038 mpcc_cfg.bot_mpcc_id = 0xf;
2039 mpcc_cfg.top_of_tree = !old_pipe_ctx->top_pipe;
2040 old_pipe_ctx->mpcc->funcs->set(old_pipe_ctx->mpcc, &mpcc_cfg);
2041 old_pipe_ctx->top_pipe->opp->mpcc_disconnect_pending[old_pipe_ctx->mpcc->inst] = true;
2042
2043 if (dc->public.debug.sanity_checks)
2044 verify_allow_pstate_change_high(dc->hwseq);
2045
2046 /*
2047 * the mpcc is the only thing that keeps track of the mpcc
2048 * mapping for reset front end right now. Might need some
2049 * rework.
2050 */
2051 old_pipe_ctx->mpcc->opp_id = opp_id_cached;
2052
2053 old_pipe_ctx->top_pipe = NULL;
2054 old_pipe_ctx->bottom_pipe = NULL;
2055 old_pipe_ctx->surface = NULL;
2056
2057 dm_logger_write(dc->ctx->logger, LOG_DC,
2058 "Reset mpcc for pipe %d\n",
2059 old_pipe_ctx->pipe_idx);
2060 }
2061 }
2062
2063 for (i = 0; i < dc->res_pool->pipe_count; i++) {
2064 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
2065
2066 if (pipe_ctx->surface != surface)
2067 continue;
2068
2069 /* looking for top pipe to program */
2070 if (!pipe_ctx->top_pipe)
2071 program_all_pipe_in_tree(dc, pipe_ctx, context);
2072 }
2073
2074 dm_logger_write(dc->ctx->logger, LOG_BANDWIDTH_CALCS,
2075 "\n============== Watermark parameters ==============\n"
2076 "a.urgent_ns: %d \n"
2077 "a.cstate_enter_plus_exit: %d \n"
2078 "a.cstate_exit: %d \n"
2079 "a.pstate_change: %d \n"
2080 "a.pte_meta_urgent: %d \n"
2081 "b.urgent_ns: %d \n"
2082 "b.cstate_enter_plus_exit: %d \n"
2083 "b.cstate_exit: %d \n"
2084 "b.pstate_change: %d \n"
2085 "b.pte_meta_urgent: %d \n",
2086 context->bw.dcn.watermarks.a.urgent_ns,
2087 context->bw.dcn.watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns,
2088 context->bw.dcn.watermarks.a.cstate_pstate.cstate_exit_ns,
2089 context->bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns,
2090 context->bw.dcn.watermarks.a.pte_meta_urgent_ns,
2091 context->bw.dcn.watermarks.b.urgent_ns,
2092 context->bw.dcn.watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns,
2093 context->bw.dcn.watermarks.b.cstate_pstate.cstate_exit_ns,
2094 context->bw.dcn.watermarks.b.cstate_pstate.pstate_change_ns,
2095 context->bw.dcn.watermarks.b.pte_meta_urgent_ns
2096 );
2097 dm_logger_write(dc->ctx->logger, LOG_BANDWIDTH_CALCS,
2098 "\nc.urgent_ns: %d \n"
2099 "c.cstate_enter_plus_exit: %d \n"
2100 "c.cstate_exit: %d \n"
2101 "c.pstate_change: %d \n"
2102 "c.pte_meta_urgent: %d \n"
2103 "d.urgent_ns: %d \n"
2104 "d.cstate_enter_plus_exit: %d \n"
2105 "d.cstate_exit: %d \n"
2106 "d.pstate_change: %d \n"
2107 "d.pte_meta_urgent: %d \n"
2108 "========================================================\n",
2109 context->bw.dcn.watermarks.c.urgent_ns,
2110 context->bw.dcn.watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns,
2111 context->bw.dcn.watermarks.c.cstate_pstate.cstate_exit_ns,
2112 context->bw.dcn.watermarks.c.cstate_pstate.pstate_change_ns,
2113 context->bw.dcn.watermarks.c.pte_meta_urgent_ns,
2114 context->bw.dcn.watermarks.d.urgent_ns,
2115 context->bw.dcn.watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns,
2116 context->bw.dcn.watermarks.d.cstate_pstate.cstate_exit_ns,
2117 context->bw.dcn.watermarks.d.cstate_pstate.pstate_change_ns,
2118 context->bw.dcn.watermarks.d.pte_meta_urgent_ns
2119 );
2120
2121 if (dc->public.debug.sanity_checks)
2122 verify_allow_pstate_change_high(dc->hwseq);
2123 }
2124
2125 static void dcn10_set_bandwidth(
2126 struct core_dc *dc,
2127 struct validate_context *context,
2128 bool decrease_allowed)
2129 {
2130 struct dm_pp_clock_for_voltage_req clock;
2131
2132 if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment))
2133 return;
2134
2135 if (decrease_allowed || context->bw.dcn.calc_clk.dispclk_khz
2136 > dc->current_context->bw.dcn.cur_clk.dispclk_khz) {
2137 dc->res_pool->display_clock->funcs->set_clock(
2138 dc->res_pool->display_clock,
2139 context->bw.dcn.calc_clk.dispclk_khz);
2140 dc->current_context->bw.dcn.cur_clk.dispclk_khz =
2141 context->bw.dcn.calc_clk.dispclk_khz;
2142 }
2143 if (decrease_allowed || context->bw.dcn.calc_clk.dcfclk_khz
2144 > dc->current_context->bw.dcn.cur_clk.dcfclk_khz) {
2145 clock.clk_type = DM_PP_CLOCK_TYPE_DCFCLK;
2146 clock.clocks_in_khz = context->bw.dcn.calc_clk.dcfclk_khz;
2147 dm_pp_apply_clock_for_voltage_request(dc->ctx, &clock);
2148 dc->current_context->bw.dcn.cur_clk.dcfclk_khz = clock.clocks_in_khz;
2149 context->bw.dcn.cur_clk.dcfclk_khz = clock.clocks_in_khz;
2150 }
2151 if (decrease_allowed || context->bw.dcn.calc_clk.fclk_khz
2152 > dc->current_context->bw.dcn.cur_clk.fclk_khz) {
2153 clock.clk_type = DM_PP_CLOCK_TYPE_FCLK;
2154 clock.clocks_in_khz = context->bw.dcn.calc_clk.fclk_khz;
2155 dm_pp_apply_clock_for_voltage_request(dc->ctx, &clock);
2156 dc->current_context->bw.dcn.calc_clk.fclk_khz = clock.clocks_in_khz;
2157 context->bw.dcn.cur_clk.fclk_khz = clock.clocks_in_khz;
2158 }
2159 if (decrease_allowed || context->bw.dcn.calc_clk.dcfclk_deep_sleep_khz
2160 > dc->current_context->bw.dcn.cur_clk.dcfclk_deep_sleep_khz) {
2161 dc->current_context->bw.dcn.calc_clk.dcfclk_deep_sleep_khz =
2162 context->bw.dcn.calc_clk.dcfclk_deep_sleep_khz;
2163 context->bw.dcn.cur_clk.dcfclk_deep_sleep_khz =
2164 context->bw.dcn.calc_clk.dcfclk_deep_sleep_khz;
2165 }
2166 /* Decrease in freq is increase in period so opposite comparison for dram_ccm */
2167 if (decrease_allowed || context->bw.dcn.calc_clk.dram_ccm_us
2168 < dc->current_context->bw.dcn.cur_clk.dram_ccm_us) {
2169 dc->current_context->bw.dcn.calc_clk.dram_ccm_us =
2170 context->bw.dcn.calc_clk.dram_ccm_us;
2171 context->bw.dcn.cur_clk.dram_ccm_us =
2172 context->bw.dcn.calc_clk.dram_ccm_us;
2173 }
2174 if (decrease_allowed || context->bw.dcn.calc_clk.min_active_dram_ccm_us
2175 < dc->current_context->bw.dcn.cur_clk.min_active_dram_ccm_us) {
2176 dc->current_context->bw.dcn.calc_clk.min_active_dram_ccm_us =
2177 context->bw.dcn.calc_clk.min_active_dram_ccm_us;
2178 context->bw.dcn.cur_clk.min_active_dram_ccm_us =
2179 context->bw.dcn.calc_clk.min_active_dram_ccm_us;
2180 }
2181 dcn10_pplib_apply_display_requirements(dc, context);
2182
2183 /* need to fix this function. not doing the right thing here */
2184 }
2185
2186 static void set_drr(struct pipe_ctx **pipe_ctx,
2187 int num_pipes, int vmin, int vmax)
2188 {
2189 int i = 0;
2190 struct drr_params params = {0};
2191
2192 params.vertical_total_max = vmax;
2193 params.vertical_total_min = vmin;
2194
2195 /* TODO: If multiple pipes are to be supported, you need
2196 * some GSL stuff
2197 */
2198 for (i = 0; i < num_pipes; i++) {
2199 pipe_ctx[i]->tg->funcs->set_drr(pipe_ctx[i]->tg, &params);
2200 }
2201 }
2202
2203 static void get_position(struct pipe_ctx **pipe_ctx,
2204 int num_pipes,
2205 struct crtc_position *position)
2206 {
2207 int i = 0;
2208
2209 /* TODO: handle pipes > 1
2210 */
2211 for (i = 0; i < num_pipes; i++)
2212 pipe_ctx[i]->tg->funcs->get_position(pipe_ctx[i]->tg, position);
2213 }
2214
2215 static void set_static_screen_control(struct pipe_ctx **pipe_ctx,
2216 int num_pipes, const struct dc_static_screen_events *events)
2217 {
2218 unsigned int i;
2219 unsigned int value = 0;
2220
2221 if (events->surface_update)
2222 value |= 0x80;
2223 if (events->cursor_update)
2224 value |= 0x2;
2225
2226 for (i = 0; i < num_pipes; i++)
2227 pipe_ctx[i]->tg->funcs->
2228 set_static_screen_control(pipe_ctx[i]->tg, value);
2229 }
2230
2231 static void set_plane_config(
2232 const struct core_dc *dc,
2233 struct pipe_ctx *pipe_ctx,
2234 struct resource_context *res_ctx)
2235 {
2236 /* TODO */
2237 program_gamut_remap(pipe_ctx);
2238 }
2239
2240 static void dcn10_config_stereo_parameters(
2241 struct core_stream *stream, struct crtc_stereo_flags *flags)
2242 {
2243 enum view_3d_format view_format = stream->public.view_format;
2244 enum dc_timing_3d_format timing_3d_format =\
2245 stream->public.timing.timing_3d_format;
2246 bool non_stereo_timing = false;
2247
2248 if (timing_3d_format == TIMING_3D_FORMAT_NONE ||
2249 timing_3d_format == TIMING_3D_FORMAT_SIDE_BY_SIDE ||
2250 timing_3d_format == TIMING_3D_FORMAT_TOP_AND_BOTTOM)
2251 non_stereo_timing = true;
2252
2253 if (non_stereo_timing == false &&
2254 view_format == VIEW_3D_FORMAT_FRAME_SEQUENTIAL) {
2255
2256 flags->PROGRAM_STEREO = 1;
2257 flags->PROGRAM_POLARITY = 1;
2258 if (timing_3d_format == TIMING_3D_FORMAT_INBAND_FA ||
2259 timing_3d_format == TIMING_3D_FORMAT_DP_HDMI_INBAND_FA ||
2260 timing_3d_format == TIMING_3D_FORMAT_SIDEBAND_FA) {
2261 enum display_dongle_type dongle = \
2262 stream->sink->link->public.ddc->dongle_type;
2263 if (dongle == DISPLAY_DONGLE_DP_VGA_CONVERTER ||
2264 dongle == DISPLAY_DONGLE_DP_DVI_CONVERTER ||
2265 dongle == DISPLAY_DONGLE_DP_HDMI_CONVERTER)
2266 flags->DISABLE_STEREO_DP_SYNC = 1;
2267 }
2268 flags->RIGHT_EYE_POLARITY =\
2269 stream->public.timing.flags.RIGHT_EYE_3D_POLARITY;
2270 if (timing_3d_format == TIMING_3D_FORMAT_HW_FRAME_PACKING)
2271 flags->FRAME_PACKED = 1;
2272 }
2273
2274 return;
2275 }
2276
2277 static void dcn10_setup_stereo(struct pipe_ctx *pipe_ctx, struct core_dc *dc)
2278 {
2279 struct crtc_stereo_flags flags = { 0 };
2280 struct core_stream *stream = pipe_ctx->stream;
2281
2282 dcn10_config_stereo_parameters(stream, &flags);
2283
2284 pipe_ctx->opp->funcs->opp_set_stereo_polarity(
2285 pipe_ctx->opp,
2286 flags.PROGRAM_STEREO == 1 ? true:false,
2287 stream->public.timing.flags.RIGHT_EYE_3D_POLARITY == 1 ? true:false);
2288
2289 pipe_ctx->tg->funcs->program_stereo(
2290 pipe_ctx->tg,
2291 &stream->public.timing,
2292 &flags);
2293
2294 return;
2295 }
2296
2297 static void dcn10_log_hw_state(struct core_dc *dc)
2298 {
2299 struct dc_context *dc_ctx = dc->ctx;
2300 struct dce_hwseq *hws = dc->hwseq;
2301
2302 DTN_INFO("%s: Hello World", __func__);
2303
2304 if (REG(MPC_CRC_RESULT_GB))
2305 DTN_INFO("MPC_CRC_RESULT_GB:%d MPC_CRC_RESULT_C:%d MPC_CRC_RESULT_AR:%d\n",
2306 REG_READ(MPC_CRC_RESULT_GB), REG_READ(MPC_CRC_RESULT_C), REG_READ(MPC_CRC_RESULT_AR));
2307 if (REG(DPP_TOP0_DPP_CRC_VAL_B_A))
2308 DTN_INFO("DPP_TOP0_DPP_CRC_VAL_B_A:%d DPP_TOP0_DPP_CRC_VAL_R_G:%d\n",
2309 REG_READ(DPP_TOP0_DPP_CRC_VAL_B_A), REG_READ(DPP_TOP0_DPP_CRC_VAL_R_G));
2310 /* todo: add meaningful register reads and print out HW state
2311 *
2312 */
2313 }
2314
2315 static void dcn10_wait_for_mpcc_disconnect(struct resource_pool *res_pool, struct pipe_ctx *pipe_ctx)
2316 {
2317 int i;
2318 for (i = 0; i < MAX_PIPES; i++) {
2319 if (!pipe_ctx->opp || !pipe_ctx->mpcc)
2320 continue;
2321
2322 if (pipe_ctx->opp->mpcc_disconnect_pending[i]) {
2323 pipe_ctx->mpcc->funcs->wait_for_idle(res_pool->mpcc[i]);
2324 pipe_ctx->opp->mpcc_disconnect_pending[i] = false;
2325 }
2326 }
2327 }
2328
2329 static bool dcn10_dummy_display_power_gating(
2330 struct core_dc *dc,
2331 uint8_t controller_id,
2332 struct dc_bios *dcb,
2333 enum pipe_gating_control power_gating)
2334 {
2335 return true;
2336 }
2337
2338 void dcn10_update_pending_status(struct pipe_ctx *pipe_ctx)
2339 {
2340 struct dc_surface *surface = pipe_ctx->surface;
2341 struct timing_generator *tg = pipe_ctx->tg;
2342
2343 if (surface->ctx->dc->debug.sanity_checks) {
2344 struct core_dc *dc = DC_TO_CORE(surface->ctx->dc);
2345
2346 verify_allow_pstate_change_high(dc->hwseq);
2347 }
2348
2349 if (surface == NULL)
2350 return;
2351
2352 surface->status.is_flip_pending =
2353 pipe_ctx->mi->funcs->mem_input_is_flip_pending(
2354 pipe_ctx->mi);
2355
2356 /* DCN we read INUSE address in MI, do we still need this wa? */
2357 if (surface->status.is_flip_pending &&
2358 !surface->visible) {
2359 pipe_ctx->mi->current_address =
2360 pipe_ctx->mi->request_address;
2361 BREAK_TO_DEBUGGER();
2362 }
2363
2364 surface->status.current_address = pipe_ctx->mi->current_address;
2365 if (pipe_ctx->mi->current_address.type == PLN_ADDR_TYPE_GRPH_STEREO &&
2366 tg->funcs->is_stereo_left_eye) {
2367 surface->status.is_right_eye =
2368 !tg->funcs->is_stereo_left_eye(pipe_ctx->tg);
2369 }
2370 }
2371
2372 static const struct hw_sequencer_funcs dcn10_funcs = {
2373 .program_gamut_remap = program_gamut_remap,
2374 .program_csc_matrix = program_csc_matrix,
2375 .init_hw = dcn10_init_hw,
2376 .apply_ctx_to_hw = dce110_apply_ctx_to_hw,
2377 .apply_ctx_for_surface = dcn10_apply_ctx_for_surface,
2378 .set_plane_config = set_plane_config,
2379 .update_plane_addr = update_plane_addr,
2380 .update_dchub = dcn10_update_dchub,
2381 .update_pending_status = dcn10_update_pending_status,
2382 .set_input_transfer_func = dcn10_set_input_transfer_func,
2383 .set_output_transfer_func = dcn10_set_output_transfer_func,
2384 .power_down = dce110_power_down,
2385 .enable_accelerated_mode = dce110_enable_accelerated_mode,
2386 .enable_timing_synchronization = dcn10_enable_timing_synchronization,
2387 .update_info_frame = dce110_update_info_frame,
2388 .enable_stream = dce110_enable_stream,
2389 .disable_stream = dce110_disable_stream,
2390 .unblank_stream = dce110_unblank_stream,
2391 .enable_display_power_gating = dcn10_dummy_display_power_gating,
2392 .power_down_front_end = dcn10_power_down_fe,
2393 .power_on_front_end = dcn10_power_on_fe,
2394 .pipe_control_lock = dcn10_pipe_control_lock,
2395 .set_bandwidth = dcn10_set_bandwidth,
2396 .reset_hw_ctx_wrap = reset_hw_ctx_wrap,
2397 .prog_pixclk_crtc_otg = dcn10_prog_pixclk_crtc_otg,
2398 .set_drr = set_drr,
2399 .get_position = get_position,
2400 .set_static_screen_control = set_static_screen_control,
2401 .setup_stereo = dcn10_setup_stereo,
2402 .set_avmute = dce110_set_avmute,
2403 .log_hw_state = dcn10_log_hw_state,
2404 .wait_for_mpcc_disconnect = dcn10_wait_for_mpcc_disconnect
2405 };
2406
2407
2408 void dcn10_hw_sequencer_construct(struct core_dc *dc)
2409 {
2410 dc->hwss = dcn10_funcs;
2411 }
2412