]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blob - drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
drm/amd/display: revert order change of HUBP and MPC disable
[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 static void enable_dppclk(
56 struct dce_hwseq *hws,
57 uint8_t plane_id,
58 uint32_t requested_pix_clk,
59 bool dppclk_div)
60 {
61 dm_logger_write(hws->ctx->logger, LOG_SURFACE,
62 "dppclk_rate_control for pipe %d programed to %d\n",
63 plane_id,
64 dppclk_div);
65
66 if (hws->shifts->DPPCLK_RATE_CONTROL)
67 REG_UPDATE_2(DPP_CONTROL[plane_id],
68 DPPCLK_RATE_CONTROL, dppclk_div,
69 DPP_CLOCK_ENABLE, 1);
70 else
71 REG_UPDATE(DPP_CONTROL[plane_id],
72 DPP_CLOCK_ENABLE, 1);
73 }
74
75 static void enable_power_gating_plane(
76 struct dce_hwseq *hws,
77 bool enable)
78 {
79 bool force_on = 1; /* disable power gating */
80
81 if (enable)
82 force_on = 0;
83
84 /* DCHUBP0/1/2/3 */
85 REG_UPDATE(DOMAIN0_PG_CONFIG, DOMAIN0_POWER_FORCEON, force_on);
86 REG_UPDATE(DOMAIN2_PG_CONFIG, DOMAIN2_POWER_FORCEON, force_on);
87 REG_UPDATE(DOMAIN4_PG_CONFIG, DOMAIN4_POWER_FORCEON, force_on);
88 REG_UPDATE(DOMAIN6_PG_CONFIG, DOMAIN6_POWER_FORCEON, force_on);
89
90 /* DPP0/1/2/3 */
91 REG_UPDATE(DOMAIN1_PG_CONFIG, DOMAIN1_POWER_FORCEON, force_on);
92 REG_UPDATE(DOMAIN3_PG_CONFIG, DOMAIN3_POWER_FORCEON, force_on);
93 REG_UPDATE(DOMAIN5_PG_CONFIG, DOMAIN5_POWER_FORCEON, force_on);
94 REG_UPDATE(DOMAIN7_PG_CONFIG, DOMAIN7_POWER_FORCEON, force_on);
95 }
96
97 static void dpp_pg_control(
98 struct dce_hwseq *hws,
99 unsigned int dpp_inst,
100 bool power_on)
101 {
102 uint32_t power_gate = power_on ? 0 : 1;
103 uint32_t pwr_status = power_on ? 0 : 2;
104
105 if (hws->ctx->dc->debug.disable_dpp_power_gate)
106 return;
107
108 switch (dpp_inst) {
109 case 0: /* DPP0 */
110 REG_UPDATE(DOMAIN1_PG_CONFIG,
111 DOMAIN1_POWER_GATE, power_gate);
112
113 REG_WAIT(DOMAIN1_PG_STATUS,
114 DOMAIN1_PGFSM_PWR_STATUS, pwr_status, 20000, 200000);
115 break;
116 case 1: /* DPP1 */
117 REG_UPDATE(DOMAIN3_PG_CONFIG,
118 DOMAIN3_POWER_GATE, power_gate);
119
120 REG_WAIT(DOMAIN3_PG_STATUS,
121 DOMAIN3_PGFSM_PWR_STATUS, pwr_status, 20000, 200000);
122 break;
123 case 2: /* DPP2 */
124 REG_UPDATE(DOMAIN5_PG_CONFIG,
125 DOMAIN5_POWER_GATE, power_gate);
126
127 REG_WAIT(DOMAIN5_PG_STATUS,
128 DOMAIN5_PGFSM_PWR_STATUS, pwr_status, 20000, 200000);
129 break;
130 case 3: /* DPP3 */
131 REG_UPDATE(DOMAIN7_PG_CONFIG,
132 DOMAIN7_POWER_GATE, power_gate);
133
134 REG_WAIT(DOMAIN7_PG_STATUS,
135 DOMAIN7_PGFSM_PWR_STATUS, pwr_status, 20000, 200000);
136 break;
137 default:
138 BREAK_TO_DEBUGGER();
139 break;
140 }
141 }
142
143 static void hubp_pg_control(
144 struct dce_hwseq *hws,
145 unsigned int hubp_inst,
146 bool power_on)
147 {
148 uint32_t power_gate = power_on ? 0 : 1;
149 uint32_t pwr_status = power_on ? 0 : 2;
150
151 if (hws->ctx->dc->debug.disable_hubp_power_gate)
152 return;
153
154 switch (hubp_inst) {
155 case 0: /* DCHUBP0 */
156 REG_UPDATE(DOMAIN0_PG_CONFIG,
157 DOMAIN0_POWER_GATE, power_gate);
158
159 REG_WAIT(DOMAIN0_PG_STATUS,
160 DOMAIN0_PGFSM_PWR_STATUS, pwr_status, 20000, 200000);
161 break;
162 case 1: /* DCHUBP1 */
163 REG_UPDATE(DOMAIN2_PG_CONFIG,
164 DOMAIN2_POWER_GATE, power_gate);
165
166 REG_WAIT(DOMAIN2_PG_STATUS,
167 DOMAIN2_PGFSM_PWR_STATUS, pwr_status, 20000, 200000);
168 break;
169 case 2: /* DCHUBP2 */
170 REG_UPDATE(DOMAIN4_PG_CONFIG,
171 DOMAIN4_POWER_GATE, power_gate);
172
173 REG_WAIT(DOMAIN4_PG_STATUS,
174 DOMAIN4_PGFSM_PWR_STATUS, pwr_status, 20000, 200000);
175 break;
176 case 3: /* DCHUBP3 */
177 REG_UPDATE(DOMAIN6_PG_CONFIG,
178 DOMAIN6_POWER_GATE, power_gate);
179
180 REG_WAIT(DOMAIN6_PG_STATUS,
181 DOMAIN6_PGFSM_PWR_STATUS, pwr_status, 20000, 200000);
182 break;
183 default:
184 BREAK_TO_DEBUGGER();
185 break;
186 }
187 }
188
189 static void power_on_plane(
190 struct dce_hwseq *hws,
191 int plane_id)
192 {
193 REG_SET(DC_IP_REQUEST_CNTL, 0,
194 IP_REQUEST_EN, 1);
195 dpp_pg_control(hws, plane_id, true);
196 hubp_pg_control(hws, plane_id, true);
197 REG_SET(DC_IP_REQUEST_CNTL, 0,
198 IP_REQUEST_EN, 0);
199 dm_logger_write(hws->ctx->logger, LOG_DC,
200 "Un-gated front end for pipe %d\n", plane_id);
201 }
202
203 static void bios_golden_init(struct core_dc *dc)
204 {
205 struct dc_bios *bp = dc->ctx->dc_bios;
206 int i;
207
208 /* initialize dcn global */
209 bp->funcs->enable_disp_power_gating(bp,
210 CONTROLLER_ID_D0, ASIC_PIPE_INIT);
211
212 for (i = 0; i < dc->res_pool->pipe_count; i++) {
213 /* initialize dcn per pipe */
214 bp->funcs->enable_disp_power_gating(bp,
215 CONTROLLER_ID_D0 + i, ASIC_PIPE_DISABLE);
216 }
217 }
218
219 static void dcn10_init_hw(struct core_dc *dc)
220 {
221 int i;
222 struct abm *abm = dc->res_pool->abm;
223 struct dce_hwseq *hws = dc->hwseq;
224
225 if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
226 REG_WRITE(REFCLK_CNTL, 0);
227 REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_ENABLE, 1);
228 REG_WRITE(DIO_MEM_PWR_CTRL, 0);
229
230 if (!dc->public.debug.disable_clock_gate) {
231 /* enable all DCN clock gating */
232 REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0);
233
234 REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0);
235
236 REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0);
237 }
238
239 enable_power_gating_plane(dc->hwseq, true);
240 return;
241 }
242 /* end of FPGA. Below if real ASIC */
243
244 bios_golden_init(dc);
245
246 for (i = 0; i < dc->link_count; i++) {
247 /* Power up AND update implementation according to the
248 * required signal (which may be different from the
249 * default signal on connector).
250 */
251 struct core_link *link = dc->links[i];
252
253 link->link_enc->funcs->hw_init(link->link_enc);
254 }
255
256 for (i = 0; i < dc->res_pool->pipe_count; i++) {
257 struct transform *xfm = dc->res_pool->transforms[i];
258 struct timing_generator *tg = dc->res_pool->timing_generators[i];
259 struct mpcc *mpcc = dc->res_pool->mpcc[i];
260 struct mpcc_cfg mpcc_cfg;
261
262 xfm->funcs->transform_reset(xfm);
263 mpcc_cfg.opp_id = 0xf;
264 mpcc_cfg.top_dpp_id = 0xf;
265 mpcc_cfg.bot_mpcc_id = 0xf;
266 mpcc_cfg.top_of_tree = true;
267 mpcc->funcs->set(mpcc, &mpcc_cfg);
268
269 tg->funcs->disable_vga(tg);
270 /* Blank controller using driver code instead of
271 * command table.
272 */
273 tg->funcs->set_blank(tg, true);
274 hwss_wait_for_blank_complete(tg);
275 }
276
277 for (i = 0; i < dc->res_pool->audio_count; i++) {
278 struct audio *audio = dc->res_pool->audios[i];
279
280 audio->funcs->hw_init(audio);
281 }
282
283 if (abm != NULL) {
284 abm->funcs->init_backlight(abm);
285 abm->funcs->abm_init(abm);
286 }
287
288 /* power AFMT HDMI memory TODO: may move to dis/en output save power*/
289 REG_WRITE(DIO_MEM_PWR_CTRL, 0);
290
291 if (!dc->public.debug.disable_clock_gate) {
292 /* enable all DCN clock gating */
293 REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0);
294
295 REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0);
296
297 REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0);
298 }
299
300 enable_power_gating_plane(dc->hwseq, true);
301 }
302
303 static enum dc_status dcn10_prog_pixclk_crtc_otg(
304 struct pipe_ctx *pipe_ctx,
305 struct validate_context *context,
306 struct core_dc *dc)
307 {
308 struct core_stream *stream = pipe_ctx->stream;
309 enum dc_color_space color_space;
310 struct tg_color black_color = {0};
311 bool enableStereo = stream->public.timing.timing_3d_format == TIMING_3D_FORMAT_NONE ?
312 false:true;
313 bool rightEyePolarity = stream->public.timing.flags.RIGHT_EYE_3D_POLARITY;
314
315
316 /* by upper caller loop, pipe0 is parent pipe and be called first.
317 * back end is set up by for pipe0. Other children pipe share back end
318 * with pipe 0. No program is needed.
319 */
320 if (pipe_ctx->top_pipe != NULL)
321 return DC_OK;
322
323 /* TODO check if timing_changed, disable stream if timing changed */
324
325 /* HW program guide assume display already disable
326 * by unplug sequence. OTG assume stop.
327 */
328 pipe_ctx->tg->funcs->enable_optc_clock(pipe_ctx->tg, true);
329
330 if (false == pipe_ctx->clock_source->funcs->program_pix_clk(
331 pipe_ctx->clock_source,
332 &pipe_ctx->pix_clk_params,
333 &pipe_ctx->pll_settings)) {
334 BREAK_TO_DEBUGGER();
335 return DC_ERROR_UNEXPECTED;
336 }
337 pipe_ctx->tg->dlg_otg_param.vready_offset = pipe_ctx->pipe_dlg_param.vready_offset;
338 pipe_ctx->tg->dlg_otg_param.vstartup_start = pipe_ctx->pipe_dlg_param.vstartup_start;
339 pipe_ctx->tg->dlg_otg_param.vupdate_offset = pipe_ctx->pipe_dlg_param.vupdate_offset;
340 pipe_ctx->tg->dlg_otg_param.vupdate_width = pipe_ctx->pipe_dlg_param.vupdate_width;
341
342 pipe_ctx->tg->dlg_otg_param.signal = pipe_ctx->stream->signal;
343
344 pipe_ctx->tg->funcs->program_timing(
345 pipe_ctx->tg,
346 &stream->public.timing,
347 true);
348
349 pipe_ctx->opp->funcs->opp_set_stereo_polarity(
350 pipe_ctx->opp,
351 enableStereo,
352 rightEyePolarity);
353
354 #if 0 /* move to after enable_crtc */
355 /* TODO: OPP FMT, ABM. etc. should be done here. */
356 /* or FPGA now. instance 0 only. TODO: move to opp.c */
357
358 inst_offset = reg_offsets[pipe_ctx->tg->inst].fmt;
359
360 pipe_ctx->opp->funcs->opp_program_fmt(
361 pipe_ctx->opp,
362 &stream->bit_depth_params,
363 &stream->clamping);
364 #endif
365 /* program otg blank color */
366 color_space = stream->public.output_color_space;
367 color_space_to_black_color(dc, color_space, &black_color);
368 pipe_ctx->tg->funcs->set_blank_color(
369 pipe_ctx->tg,
370 &black_color);
371
372 pipe_ctx->tg->funcs->set_blank(pipe_ctx->tg, true);
373 hwss_wait_for_blank_complete(pipe_ctx->tg);
374
375 /* VTG is within DCHUB command block. DCFCLK is always on */
376 if (false == pipe_ctx->tg->funcs->enable_crtc(pipe_ctx->tg)) {
377 BREAK_TO_DEBUGGER();
378 return DC_ERROR_UNEXPECTED;
379 }
380
381 /* TODO program crtc source select for non-virtual signal*/
382 /* TODO program FMT */
383 /* TODO setup link_enc */
384 /* TODO set stream attributes */
385 /* TODO program audio */
386 /* TODO enable stream if timing changed */
387 /* TODO unblank stream if DP */
388
389 return DC_OK;
390 }
391
392 static void reset_back_end_for_pipe(
393 struct core_dc *dc,
394 struct pipe_ctx *pipe_ctx,
395 struct validate_context *context)
396 {
397 int i;
398
399 if (pipe_ctx->stream_enc == NULL) {
400 pipe_ctx->stream = NULL;
401 return;
402 }
403
404 /* TODOFPGA break core_link_disable_stream into 2 functions:
405 * disable_stream and disable_link. disable_link will disable PHYPLL
406 * which is used by otg. Move disable_link after disable_crtc
407 */
408 if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment))
409 core_link_disable_stream(pipe_ctx);
410
411 /* by upper caller loop, parent pipe: pipe0, will be reset last.
412 * back end share by all pipes and will be disable only when disable
413 * parent pipe.
414 */
415 if (pipe_ctx->top_pipe == NULL) {
416 pipe_ctx->tg->funcs->disable_crtc(pipe_ctx->tg);
417
418 pipe_ctx->tg->funcs->enable_optc_clock(pipe_ctx->tg, false);
419 }
420
421 if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment))
422 resource_unreference_clock_source(
423 &context->res_ctx, dc->res_pool,
424 &pipe_ctx->clock_source);
425
426 for (i = 0; i < dc->res_pool->pipe_count; i++)
427 if (&dc->current_context->res_ctx.pipe_ctx[i] == pipe_ctx)
428 break;
429
430 if (i == dc->res_pool->pipe_count)
431 return;
432
433 pipe_ctx->stream = NULL;
434 dm_logger_write(dc->ctx->logger, LOG_DC,
435 "Reset back end for pipe %d, tg:%d\n",
436 pipe_ctx->pipe_idx, pipe_ctx->tg->inst);
437 }
438
439 static void plane_atomic_stop(
440 struct core_dc *dc,
441 int fe_idx)
442 {
443 struct mpcc_cfg mpcc_cfg;
444 struct mem_input *mi = dc->res_pool->mis[fe_idx];
445 struct transform *xfm = dc->res_pool->transforms[fe_idx];
446 struct mpcc *mpcc = dc->res_pool->mpcc[fe_idx];
447 struct timing_generator *tg = dc->res_pool->timing_generators[mpcc->opp_id];
448
449 mi->funcs->dcc_control(mi, false, false);
450
451 mpcc_cfg.opp_id = 0xf;
452 mpcc_cfg.top_dpp_id = 0xf;
453 mpcc_cfg.bot_mpcc_id = 0xf;
454 mpcc_cfg.top_of_tree = tg->inst == mpcc->inst;
455 mpcc->funcs->set(mpcc, &mpcc_cfg);
456
457 xfm->funcs->transform_reset(xfm);
458 }
459
460 static void reset_front_end(
461 struct core_dc *dc,
462 int fe_idx)
463 {
464 struct dce_hwseq *hws = dc->hwseq;
465 struct mem_input *mi = dc->res_pool->mis[fe_idx];
466 struct mpcc *mpcc = dc->res_pool->mpcc[fe_idx];
467 struct timing_generator *tg = dc->res_pool->timing_generators[mpcc->opp_id];
468 unsigned int opp_id = mpcc->opp_id;
469
470 /*Already reset*/
471 if (opp_id == 0xf)
472 return;
473
474 tg->funcs->lock(tg);
475
476 plane_atomic_stop(dc, fe_idx);
477
478 REG_UPDATE(OTG_GLOBAL_SYNC_STATUS[tg->inst], VUPDATE_NO_LOCK_EVENT_CLEAR, 1);
479 tg->funcs->unlock(tg);
480 REG_WAIT(OTG_GLOBAL_SYNC_STATUS[tg->inst], VUPDATE_NO_LOCK_EVENT_OCCURRED, 1, 20000, 200000);
481
482 mpcc->funcs->wait_for_idle(mpcc);
483
484 mi->funcs->set_blank(mi, true);
485
486 REG_UPDATE(HUBP_CLK_CNTL[fe_idx],
487 HUBP_CLOCK_ENABLE, 0);
488 REG_UPDATE(DPP_CONTROL[fe_idx],
489 DPP_CLOCK_ENABLE, 0);
490
491 if (tg->inst == mpcc->inst)
492 REG_UPDATE(OPP_PIPE_CONTROL[opp_id],
493 OPP_PIPE_CLOCK_EN, 0);
494
495 dm_logger_write(dc->ctx->logger, LOG_DC,
496 "Reset front end %d\n",
497 fe_idx);
498 }
499
500 static void dcn10_power_down_fe(struct core_dc *dc, int fe_idx)
501 {
502 struct dce_hwseq *hws = dc->hwseq;
503
504 reset_front_end(dc, fe_idx);
505
506 REG_SET(DC_IP_REQUEST_CNTL, 0,
507 IP_REQUEST_EN, 1);
508 dpp_pg_control(hws, fe_idx, false);
509 hubp_pg_control(hws, fe_idx, false);
510 REG_SET(DC_IP_REQUEST_CNTL, 0,
511 IP_REQUEST_EN, 0);
512 dm_logger_write(dc->ctx->logger, LOG_DC,
513 "Power gated front end %d\n", fe_idx);
514 }
515
516 static void reset_hw_ctx_wrap(
517 struct core_dc *dc,
518 struct validate_context *context)
519 {
520 int i;
521
522 /* Reset Front End*/
523 for (i = dc->res_pool->pipe_count - 1; i >= 0 ; i--) {
524 struct pipe_ctx *pipe_ctx_old =
525 &dc->current_context->res_ctx.pipe_ctx[i];
526 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
527
528 /*if (!pipe_ctx_old->stream)
529 continue;*/
530
531 if (!pipe_ctx->stream || !pipe_ctx->surface)
532 dcn10_power_down_fe(dc, i);
533 else if (pipe_need_reprogram(pipe_ctx_old, pipe_ctx))
534 reset_front_end(dc, i);
535 }
536 /* Reset Back End*/
537 for (i = dc->res_pool->pipe_count - 1; i >= 0 ; i--) {
538 struct pipe_ctx *pipe_ctx_old =
539 &dc->current_context->res_ctx.pipe_ctx[i];
540 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
541
542 if (!pipe_ctx_old->stream)
543 continue;
544
545 if (!pipe_ctx->stream ||
546 pipe_need_reprogram(pipe_ctx_old, pipe_ctx))
547 reset_back_end_for_pipe(dc, pipe_ctx_old, dc->current_context);
548 }
549 }
550
551 static bool patch_address_for_sbs_tb_stereo(
552 struct pipe_ctx *pipe_ctx, PHYSICAL_ADDRESS_LOC *addr)
553 {
554 struct core_surface *surface = pipe_ctx->surface;
555 bool sec_split = pipe_ctx->top_pipe &&
556 pipe_ctx->top_pipe->surface == pipe_ctx->surface;
557 if (sec_split && surface->public.address.type == PLN_ADDR_TYPE_GRPH_STEREO &&
558 (pipe_ctx->stream->public.timing.timing_3d_format ==
559 TIMING_3D_FORMAT_SIDE_BY_SIDE ||
560 pipe_ctx->stream->public.timing.timing_3d_format ==
561 TIMING_3D_FORMAT_TOP_AND_BOTTOM)) {
562 *addr = surface->public.address.grph_stereo.left_addr;
563 surface->public.address.grph_stereo.left_addr =
564 surface->public.address.grph_stereo.right_addr;
565 return true;
566 } else {
567 if (pipe_ctx->stream->public.view_format != VIEW_3D_FORMAT_NONE &&
568 surface->public.address.type != PLN_ADDR_TYPE_GRPH_STEREO) {
569 surface->public.address.type = PLN_ADDR_TYPE_GRPH_STEREO;
570 surface->public.address.grph_stereo.right_addr =
571 surface->public.address.grph_stereo.left_addr;
572 }
573 }
574 return false;
575 }
576
577 static void update_plane_addr(const struct core_dc *dc, struct pipe_ctx *pipe_ctx)
578 {
579 bool addr_patched = false;
580 PHYSICAL_ADDRESS_LOC addr;
581 struct core_surface *surface = pipe_ctx->surface;
582
583 if (surface == NULL)
584 return;
585 addr_patched = patch_address_for_sbs_tb_stereo(pipe_ctx, &addr);
586 pipe_ctx->mi->funcs->mem_input_program_surface_flip_and_addr(
587 pipe_ctx->mi,
588 &surface->public.address,
589 surface->public.flip_immediate);
590 surface->status.requested_address = surface->public.address;
591 if (addr_patched)
592 pipe_ctx->surface->public.address.grph_stereo.left_addr = addr;
593 }
594
595 static bool dcn10_set_input_transfer_func(
596 struct pipe_ctx *pipe_ctx, const struct core_surface *surface)
597 {
598 struct input_pixel_processor *ipp = pipe_ctx->ipp;
599 const struct dc_transfer_func *tf = NULL;
600 bool result = true;
601
602 if (ipp == NULL)
603 return false;
604
605 if (surface->public.in_transfer_func)
606 tf = surface->public.in_transfer_func;
607
608 if (surface->public.gamma_correction && dce_use_lut(surface))
609 ipp->funcs->ipp_program_input_lut(ipp,
610 surface->public.gamma_correction);
611
612 if (tf == NULL)
613 ipp->funcs->ipp_set_degamma(ipp, IPP_DEGAMMA_MODE_BYPASS);
614 else if (tf->type == TF_TYPE_PREDEFINED) {
615 switch (tf->tf) {
616 case TRANSFER_FUNCTION_SRGB:
617 ipp->funcs->ipp_set_degamma(ipp,
618 IPP_DEGAMMA_MODE_HW_sRGB);
619 break;
620 case TRANSFER_FUNCTION_BT709:
621 ipp->funcs->ipp_set_degamma(ipp,
622 IPP_DEGAMMA_MODE_HW_xvYCC);
623 break;
624 case TRANSFER_FUNCTION_LINEAR:
625 ipp->funcs->ipp_set_degamma(ipp,
626 IPP_DEGAMMA_MODE_BYPASS);
627 break;
628 case TRANSFER_FUNCTION_PQ:
629 result = false;
630 break;
631 default:
632 result = false;
633 break;
634 }
635 } else if (tf->type == TF_TYPE_BYPASS) {
636 ipp->funcs->ipp_set_degamma(ipp, IPP_DEGAMMA_MODE_BYPASS);
637 } else {
638 /*TF_TYPE_DISTRIBUTED_POINTS*/
639 result = false;
640 }
641
642 return result;
643 }
644 /*modify the method to handle rgb for arr_points*/
645 static bool convert_to_custom_float(
646 struct pwl_result_data *rgb_resulted,
647 struct curve_points *arr_points,
648 uint32_t hw_points_num)
649 {
650 struct custom_float_format fmt;
651
652 struct pwl_result_data *rgb = rgb_resulted;
653
654 uint32_t i = 0;
655
656 fmt.exponenta_bits = 6;
657 fmt.mantissa_bits = 12;
658 fmt.sign = false;
659
660 if (!convert_to_custom_float_format(
661 arr_points[0].x,
662 &fmt,
663 &arr_points[0].custom_float_x)) {
664 BREAK_TO_DEBUGGER();
665 return false;
666 }
667
668 if (!convert_to_custom_float_format(
669 arr_points[0].offset,
670 &fmt,
671 &arr_points[0].custom_float_offset)) {
672 BREAK_TO_DEBUGGER();
673 return false;
674 }
675
676 if (!convert_to_custom_float_format(
677 arr_points[0].slope,
678 &fmt,
679 &arr_points[0].custom_float_slope)) {
680 BREAK_TO_DEBUGGER();
681 return false;
682 }
683
684 fmt.mantissa_bits = 10;
685 fmt.sign = false;
686
687 if (!convert_to_custom_float_format(
688 arr_points[1].x,
689 &fmt,
690 &arr_points[1].custom_float_x)) {
691 BREAK_TO_DEBUGGER();
692 return false;
693 }
694
695 if (!convert_to_custom_float_format(
696 arr_points[1].y,
697 &fmt,
698 &arr_points[1].custom_float_y)) {
699 BREAK_TO_DEBUGGER();
700 return false;
701 }
702
703 if (!convert_to_custom_float_format(
704 arr_points[1].slope,
705 &fmt,
706 &arr_points[1].custom_float_slope)) {
707 BREAK_TO_DEBUGGER();
708 return false;
709 }
710
711 fmt.mantissa_bits = 12;
712 fmt.sign = true;
713
714 while (i != hw_points_num) {
715 if (!convert_to_custom_float_format(
716 rgb->red,
717 &fmt,
718 &rgb->red_reg)) {
719 BREAK_TO_DEBUGGER();
720 return false;
721 }
722
723 if (!convert_to_custom_float_format(
724 rgb->green,
725 &fmt,
726 &rgb->green_reg)) {
727 BREAK_TO_DEBUGGER();
728 return false;
729 }
730
731 if (!convert_to_custom_float_format(
732 rgb->blue,
733 &fmt,
734 &rgb->blue_reg)) {
735 BREAK_TO_DEBUGGER();
736 return false;
737 }
738
739 if (!convert_to_custom_float_format(
740 rgb->delta_red,
741 &fmt,
742 &rgb->delta_red_reg)) {
743 BREAK_TO_DEBUGGER();
744 return false;
745 }
746
747 if (!convert_to_custom_float_format(
748 rgb->delta_green,
749 &fmt,
750 &rgb->delta_green_reg)) {
751 BREAK_TO_DEBUGGER();
752 return false;
753 }
754
755 if (!convert_to_custom_float_format(
756 rgb->delta_blue,
757 &fmt,
758 &rgb->delta_blue_reg)) {
759 BREAK_TO_DEBUGGER();
760 return false;
761 }
762
763 ++rgb;
764 ++i;
765 }
766
767 return true;
768 }
769 #define MAX_REGIONS_NUMBER 34
770 #define MAX_LOW_POINT 25
771 #define NUMBER_SEGMENTS 32
772
773 static bool dcn10_translate_regamma_to_hw_format(const struct dc_transfer_func
774 *output_tf, struct pwl_params *regamma_params)
775 {
776 struct curve_points *arr_points;
777 struct pwl_result_data *rgb_resulted;
778 struct pwl_result_data *rgb;
779 struct pwl_result_data *rgb_plus_1;
780 struct fixed31_32 y_r;
781 struct fixed31_32 y_g;
782 struct fixed31_32 y_b;
783 struct fixed31_32 y1_min;
784 struct fixed31_32 y3_max;
785
786 int32_t segment_start, segment_end;
787 int32_t i;
788 uint32_t j, k, seg_distr[MAX_REGIONS_NUMBER], increment, start_index, hw_points;
789
790 if (output_tf == NULL || regamma_params == NULL ||
791 output_tf->type == TF_TYPE_BYPASS)
792 return false;
793
794 arr_points = regamma_params->arr_points;
795 rgb_resulted = regamma_params->rgb_resulted;
796 hw_points = 0;
797
798 memset(regamma_params, 0, sizeof(struct pwl_params));
799 memset(seg_distr, 0, sizeof(seg_distr));
800
801 if (output_tf->tf == TRANSFER_FUNCTION_PQ) {
802 /* 32 segments
803 * segments are from 2^-25 to 2^7
804 */
805 for (i = 0; i < 32 ; i++)
806 seg_distr[i] = 3;
807
808 segment_start = -25;
809 segment_end = 7;
810 } else {
811 /* 10 segments
812 * segment is from 2^-10 to 2^0
813 * There are less than 256 points, for optimization
814 */
815 seg_distr[0] = 3;
816 seg_distr[1] = 4;
817 seg_distr[2] = 4;
818 seg_distr[3] = 4;
819 seg_distr[4] = 4;
820 seg_distr[5] = 4;
821 seg_distr[6] = 4;
822 seg_distr[7] = 4;
823 seg_distr[8] = 5;
824 seg_distr[9] = 5;
825
826 segment_start = -10;
827 segment_end = 0;
828 }
829
830 for (i = segment_end - segment_start; i < MAX_REGIONS_NUMBER ; i++)
831 seg_distr[i] = -1;
832
833 for (k = 0; k < MAX_REGIONS_NUMBER; k++) {
834 if (seg_distr[k] != -1)
835 hw_points += (1 << seg_distr[k]);
836 }
837
838 j = 0;
839 for (k = 0; k < (segment_end - segment_start); k++) {
840 increment = NUMBER_SEGMENTS / (1 << seg_distr[k]);
841 start_index = (segment_start + k + MAX_LOW_POINT) * NUMBER_SEGMENTS;
842 for (i = start_index; i < start_index + NUMBER_SEGMENTS; i += increment) {
843 if (j == hw_points - 1)
844 break;
845 rgb_resulted[j].red = output_tf->tf_pts.red[i];
846 rgb_resulted[j].green = output_tf->tf_pts.green[i];
847 rgb_resulted[j].blue = output_tf->tf_pts.blue[i];
848 j++;
849 }
850 }
851
852 /* last point */
853 start_index = (segment_end + MAX_LOW_POINT) * NUMBER_SEGMENTS;
854 rgb_resulted[hw_points - 1].red =
855 output_tf->tf_pts.red[start_index];
856 rgb_resulted[hw_points - 1].green =
857 output_tf->tf_pts.green[start_index];
858 rgb_resulted[hw_points - 1].blue =
859 output_tf->tf_pts.blue[start_index];
860
861 arr_points[0].x = dal_fixed31_32_pow(dal_fixed31_32_from_int(2),
862 dal_fixed31_32_from_int(segment_start));
863 arr_points[1].x = dal_fixed31_32_pow(dal_fixed31_32_from_int(2),
864 dal_fixed31_32_from_int(segment_end));
865 arr_points[2].x = dal_fixed31_32_pow(dal_fixed31_32_from_int(2),
866 dal_fixed31_32_from_int(segment_end));
867
868 y_r = rgb_resulted[0].red;
869 y_g = rgb_resulted[0].green;
870 y_b = rgb_resulted[0].blue;
871
872 y1_min = dal_fixed31_32_min(y_r, dal_fixed31_32_min(y_g, y_b));
873
874 arr_points[0].y = y1_min;
875 arr_points[0].slope = dal_fixed31_32_div(
876 arr_points[0].y,
877 arr_points[0].x);
878 y_r = rgb_resulted[hw_points - 1].red;
879 y_g = rgb_resulted[hw_points - 1].green;
880 y_b = rgb_resulted[hw_points - 1].blue;
881
882 /* see comment above, m_arrPoints[1].y should be the Y value for the
883 * region end (m_numOfHwPoints), not last HW point(m_numOfHwPoints - 1)
884 */
885 y3_max = dal_fixed31_32_max(y_r, dal_fixed31_32_max(y_g, y_b));
886
887 arr_points[1].y = y3_max;
888 arr_points[2].y = y3_max;
889
890 arr_points[1].slope = dal_fixed31_32_zero;
891 arr_points[2].slope = dal_fixed31_32_zero;
892
893 if (output_tf->tf == TRANSFER_FUNCTION_PQ) {
894 /* for PQ, we want to have a straight line from last HW X point,
895 * and the slope to be such that we hit 1.0 at 10000 nits.
896 */
897 const struct fixed31_32 end_value =
898 dal_fixed31_32_from_int(125);
899
900 arr_points[1].slope = dal_fixed31_32_div(
901 dal_fixed31_32_sub(dal_fixed31_32_one, arr_points[1].y),
902 dal_fixed31_32_sub(end_value, arr_points[1].x));
903 arr_points[2].slope = dal_fixed31_32_div(
904 dal_fixed31_32_sub(dal_fixed31_32_one, arr_points[1].y),
905 dal_fixed31_32_sub(end_value, arr_points[1].x));
906 }
907
908 regamma_params->hw_points_num = hw_points;
909
910 i = 1;
911 for (k = 0; k < MAX_REGIONS_NUMBER && i < MAX_REGIONS_NUMBER; k++) {
912 if (seg_distr[k] != -1) {
913 regamma_params->arr_curve_points[k].segments_num =
914 seg_distr[k];
915 regamma_params->arr_curve_points[i].offset =
916 regamma_params->arr_curve_points[k].
917 offset + (1 << seg_distr[k]);
918 }
919 i++;
920 }
921
922 if (seg_distr[k] != -1)
923 regamma_params->arr_curve_points[k].segments_num =
924 seg_distr[k];
925
926 rgb = rgb_resulted;
927 rgb_plus_1 = rgb_resulted + 1;
928
929 i = 1;
930
931 while (i != hw_points + 1) {
932 if (dal_fixed31_32_lt(rgb_plus_1->red, rgb->red))
933 rgb_plus_1->red = rgb->red;
934 if (dal_fixed31_32_lt(rgb_plus_1->green, rgb->green))
935 rgb_plus_1->green = rgb->green;
936 if (dal_fixed31_32_lt(rgb_plus_1->blue, rgb->blue))
937 rgb_plus_1->blue = rgb->blue;
938
939 rgb->delta_red = dal_fixed31_32_sub(
940 rgb_plus_1->red,
941 rgb->red);
942 rgb->delta_green = dal_fixed31_32_sub(
943 rgb_plus_1->green,
944 rgb->green);
945 rgb->delta_blue = dal_fixed31_32_sub(
946 rgb_plus_1->blue,
947 rgb->blue);
948
949 ++rgb_plus_1;
950 ++rgb;
951 ++i;
952 }
953
954 convert_to_custom_float(rgb_resulted, arr_points, hw_points);
955
956 return true;
957 }
958
959 static bool dcn10_set_output_transfer_func(
960 struct pipe_ctx *pipe_ctx,
961 const struct core_stream *stream)
962 {
963 struct output_pixel_processor *opp = pipe_ctx->opp;
964
965 if (opp == NULL)
966 return false;
967
968 opp->regamma_params.hw_points_num = GAMMA_HW_POINTS_NUM;
969
970 if (stream->public.out_transfer_func &&
971 stream->public.out_transfer_func->type ==
972 TF_TYPE_PREDEFINED &&
973 stream->public.out_transfer_func->tf ==
974 TRANSFER_FUNCTION_SRGB) {
975 opp->funcs->opp_set_regamma_mode(opp, OPP_REGAMMA_SRGB);
976 } else if (dcn10_translate_regamma_to_hw_format(
977 stream->public.out_transfer_func, &opp->regamma_params)) {
978 opp->funcs->opp_program_regamma_pwl(opp, &opp->regamma_params);
979 opp->funcs->opp_set_regamma_mode(opp, OPP_REGAMMA_USER);
980 } else {
981 opp->funcs->opp_set_regamma_mode(opp, OPP_REGAMMA_BYPASS);
982 }
983
984 return true;
985 }
986
987 static void dcn10_pipe_control_lock(
988 struct core_dc *dc,
989 struct pipe_ctx *pipe,
990 bool lock)
991 {
992 /* use TG master update lock to lock everything on the TG
993 * therefore only top pipe need to lock
994 */
995 if (pipe->top_pipe)
996 return;
997
998 if (lock)
999 pipe->tg->funcs->lock(pipe->tg);
1000 else
1001 pipe->tg->funcs->unlock(pipe->tg);
1002 }
1003
1004 static bool wait_for_reset_trigger_to_occur(
1005 struct dc_context *dc_ctx,
1006 struct timing_generator *tg)
1007 {
1008 bool rc = false;
1009
1010 /* To avoid endless loop we wait at most
1011 * frames_to_wait_on_triggered_reset frames for the reset to occur. */
1012 const uint32_t frames_to_wait_on_triggered_reset = 10;
1013 int i;
1014
1015 for (i = 0; i < frames_to_wait_on_triggered_reset; i++) {
1016
1017 if (!tg->funcs->is_counter_moving(tg)) {
1018 DC_ERROR("TG counter is not moving!\n");
1019 break;
1020 }
1021
1022 if (tg->funcs->did_triggered_reset_occur(tg)) {
1023 rc = true;
1024 /* usually occurs at i=1 */
1025 DC_SYNC_INFO("GSL: reset occurred at wait count: %d\n",
1026 i);
1027 break;
1028 }
1029
1030 /* Wait for one frame. */
1031 tg->funcs->wait_for_state(tg, CRTC_STATE_VACTIVE);
1032 tg->funcs->wait_for_state(tg, CRTC_STATE_VBLANK);
1033 }
1034
1035 if (false == rc)
1036 DC_ERROR("GSL: Timeout on reset trigger!\n");
1037
1038 return rc;
1039 }
1040
1041 static void dcn10_enable_timing_synchronization(
1042 struct core_dc *dc,
1043 int group_index,
1044 int group_size,
1045 struct pipe_ctx *grouped_pipes[])
1046 {
1047 struct dc_context *dc_ctx = dc->ctx;
1048 int i;
1049
1050 DC_SYNC_INFO("Setting up OTG reset trigger\n");
1051
1052 for (i = 1; i < group_size; i++)
1053 grouped_pipes[i]->tg->funcs->enable_reset_trigger(
1054 grouped_pipes[i]->tg, grouped_pipes[0]->tg->inst);
1055
1056
1057 DC_SYNC_INFO("Waiting for trigger\n");
1058
1059 /* Need to get only check 1 pipe for having reset as all the others are
1060 * synchronized. Look at last pipe programmed to reset.
1061 */
1062 wait_for_reset_trigger_to_occur(dc_ctx, grouped_pipes[1]->tg);
1063 for (i = 1; i < group_size; i++)
1064 grouped_pipes[i]->tg->funcs->disable_reset_trigger(
1065 grouped_pipes[i]->tg);
1066
1067 DC_SYNC_INFO("Sync complete\n");
1068 }
1069
1070 static void print_rq_dlg_ttu(
1071 struct core_dc *core_dc,
1072 struct pipe_ctx *pipe_ctx)
1073 {
1074 dm_logger_write(core_dc->ctx->logger, LOG_BANDWIDTH_CALCS,
1075 "\n============== DML TTU Output parameters [%d] ==============\n"
1076 "qos_level_low_wm: %d, \n"
1077 "qos_level_high_wm: %d, \n"
1078 "min_ttu_vblank: %d, \n"
1079 "qos_level_flip: %d, \n"
1080 "refcyc_per_req_delivery_l: %d, \n"
1081 "qos_level_fixed_l: %d, \n"
1082 "qos_ramp_disable_l: %d, \n"
1083 "refcyc_per_req_delivery_pre_l: %d, \n"
1084 "refcyc_per_req_delivery_c: %d, \n"
1085 "qos_level_fixed_c: %d, \n"
1086 "qos_ramp_disable_c: %d, \n"
1087 "refcyc_per_req_delivery_pre_c: %d\n"
1088 "=============================================================\n",
1089 pipe_ctx->pipe_idx,
1090 pipe_ctx->ttu_regs.qos_level_low_wm,
1091 pipe_ctx->ttu_regs.qos_level_high_wm,
1092 pipe_ctx->ttu_regs.min_ttu_vblank,
1093 pipe_ctx->ttu_regs.qos_level_flip,
1094 pipe_ctx->ttu_regs.refcyc_per_req_delivery_l,
1095 pipe_ctx->ttu_regs.qos_level_fixed_l,
1096 pipe_ctx->ttu_regs.qos_ramp_disable_l,
1097 pipe_ctx->ttu_regs.refcyc_per_req_delivery_pre_l,
1098 pipe_ctx->ttu_regs.refcyc_per_req_delivery_c,
1099 pipe_ctx->ttu_regs.qos_level_fixed_c,
1100 pipe_ctx->ttu_regs.qos_ramp_disable_c,
1101 pipe_ctx->ttu_regs.refcyc_per_req_delivery_pre_c
1102 );
1103
1104 dm_logger_write(core_dc->ctx->logger, LOG_BANDWIDTH_CALCS,
1105 "\n============== DML DLG Output parameters [%d] ==============\n"
1106 "refcyc_h_blank_end: %d, \n"
1107 "dlg_vblank_end: %d, \n"
1108 "min_dst_y_next_start: %d, \n"
1109 "refcyc_per_htotal: %d, \n"
1110 "refcyc_x_after_scaler: %d, \n"
1111 "dst_y_after_scaler: %d, \n"
1112 "dst_y_prefetch: %d, \n"
1113 "dst_y_per_vm_vblank: %d, \n"
1114 "dst_y_per_row_vblank: %d, \n"
1115 "ref_freq_to_pix_freq: %d, \n"
1116 "vratio_prefetch: %d, \n"
1117 "refcyc_per_pte_group_vblank_l: %d, \n"
1118 "refcyc_per_meta_chunk_vblank_l: %d, \n"
1119 "dst_y_per_pte_row_nom_l: %d, \n"
1120 "refcyc_per_pte_group_nom_l: %d, \n",
1121 pipe_ctx->pipe_idx,
1122 pipe_ctx->dlg_regs.refcyc_h_blank_end,
1123 pipe_ctx->dlg_regs.dlg_vblank_end,
1124 pipe_ctx->dlg_regs.min_dst_y_next_start,
1125 pipe_ctx->dlg_regs.refcyc_per_htotal,
1126 pipe_ctx->dlg_regs.refcyc_x_after_scaler,
1127 pipe_ctx->dlg_regs.dst_y_after_scaler,
1128 pipe_ctx->dlg_regs.dst_y_prefetch,
1129 pipe_ctx->dlg_regs.dst_y_per_vm_vblank,
1130 pipe_ctx->dlg_regs.dst_y_per_row_vblank,
1131 pipe_ctx->dlg_regs.ref_freq_to_pix_freq,
1132 pipe_ctx->dlg_regs.vratio_prefetch,
1133 pipe_ctx->dlg_regs.refcyc_per_pte_group_vblank_l,
1134 pipe_ctx->dlg_regs.refcyc_per_meta_chunk_vblank_l,
1135 pipe_ctx->dlg_regs.dst_y_per_pte_row_nom_l,
1136 pipe_ctx->dlg_regs.refcyc_per_pte_group_nom_l
1137 );
1138
1139 dm_logger_write(core_dc->ctx->logger, LOG_BANDWIDTH_CALCS,
1140 "\ndst_y_per_meta_row_nom_l: %d, \n"
1141 "refcyc_per_meta_chunk_nom_l: %d, \n"
1142 "refcyc_per_line_delivery_pre_l: %d, \n"
1143 "refcyc_per_line_delivery_l: %d, \n"
1144 "vratio_prefetch_c: %d, \n"
1145 "refcyc_per_pte_group_vblank_c: %d, \n"
1146 "refcyc_per_meta_chunk_vblank_c: %d, \n"
1147 "dst_y_per_pte_row_nom_c: %d, \n"
1148 "refcyc_per_pte_group_nom_c: %d, \n"
1149 "dst_y_per_meta_row_nom_c: %d, \n"
1150 "refcyc_per_meta_chunk_nom_c: %d, \n"
1151 "refcyc_per_line_delivery_pre_c: %d, \n"
1152 "refcyc_per_line_delivery_c: %d \n"
1153 "========================================================\n",
1154 pipe_ctx->dlg_regs.dst_y_per_meta_row_nom_l,
1155 pipe_ctx->dlg_regs.refcyc_per_meta_chunk_nom_l,
1156 pipe_ctx->dlg_regs.refcyc_per_line_delivery_pre_l,
1157 pipe_ctx->dlg_regs.refcyc_per_line_delivery_l,
1158 pipe_ctx->dlg_regs.vratio_prefetch_c,
1159 pipe_ctx->dlg_regs.refcyc_per_pte_group_vblank_c,
1160 pipe_ctx->dlg_regs.refcyc_per_meta_chunk_vblank_c,
1161 pipe_ctx->dlg_regs.dst_y_per_pte_row_nom_c,
1162 pipe_ctx->dlg_regs.refcyc_per_pte_group_nom_c,
1163 pipe_ctx->dlg_regs.dst_y_per_meta_row_nom_c,
1164 pipe_ctx->dlg_regs.refcyc_per_meta_chunk_nom_c,
1165 pipe_ctx->dlg_regs.refcyc_per_line_delivery_pre_c,
1166 pipe_ctx->dlg_regs.refcyc_per_line_delivery_c
1167 );
1168
1169 dm_logger_write(core_dc->ctx->logger, LOG_BANDWIDTH_CALCS,
1170 "\n============== DML RQ Output parameters [%d] ==============\n"
1171 "chunk_size: %d \n"
1172 "min_chunk_size: %d \n"
1173 "meta_chunk_size: %d \n"
1174 "min_meta_chunk_size: %d \n"
1175 "dpte_group_size: %d \n"
1176 "mpte_group_size: %d \n"
1177 "swath_height: %d \n"
1178 "pte_row_height_linear: %d \n"
1179 "========================================================\n",
1180 pipe_ctx->pipe_idx,
1181 pipe_ctx->rq_regs.rq_regs_l.chunk_size,
1182 pipe_ctx->rq_regs.rq_regs_l.min_chunk_size,
1183 pipe_ctx->rq_regs.rq_regs_l.meta_chunk_size,
1184 pipe_ctx->rq_regs.rq_regs_l.min_meta_chunk_size,
1185 pipe_ctx->rq_regs.rq_regs_l.dpte_group_size,
1186 pipe_ctx->rq_regs.rq_regs_l.mpte_group_size,
1187 pipe_ctx->rq_regs.rq_regs_l.swath_height,
1188 pipe_ctx->rq_regs.rq_regs_l.pte_row_height_linear
1189 );
1190 }
1191
1192 static void dcn10_power_on_fe(
1193 struct core_dc *dc,
1194 struct pipe_ctx *pipe_ctx,
1195 struct validate_context *context)
1196 {
1197 struct dc_surface *dc_surface = &pipe_ctx->surface->public;
1198 struct dce_hwseq *hws = dc->hwseq;
1199
1200 power_on_plane(dc->hwseq,
1201 pipe_ctx->pipe_idx);
1202
1203 /* enable DCFCLK current DCHUB */
1204 REG_UPDATE(HUBP_CLK_CNTL[pipe_ctx->pipe_idx],
1205 HUBP_CLOCK_ENABLE, 1);
1206
1207 /* make sure OPP_PIPE_CLOCK_EN = 1 */
1208 REG_UPDATE(OPP_PIPE_CONTROL[pipe_ctx->tg->inst],
1209 OPP_PIPE_CLOCK_EN, 1);
1210
1211 if (dc_surface) {
1212 dm_logger_write(dc->ctx->logger, LOG_DC,
1213 "Pipe:%d 0x%x: addr hi:0x%x, "
1214 "addr low:0x%x, "
1215 "src: %d, %d, %d,"
1216 " %d; dst: %d, %d, %d, %d;\n",
1217 pipe_ctx->pipe_idx,
1218 dc_surface,
1219 dc_surface->address.grph.addr.high_part,
1220 dc_surface->address.grph.addr.low_part,
1221 dc_surface->src_rect.x,
1222 dc_surface->src_rect.y,
1223 dc_surface->src_rect.width,
1224 dc_surface->src_rect.height,
1225 dc_surface->dst_rect.x,
1226 dc_surface->dst_rect.y,
1227 dc_surface->dst_rect.width,
1228 dc_surface->dst_rect.height);
1229
1230 dm_logger_write(dc->ctx->logger, LOG_HW_SET_MODE,
1231 "Pipe %d: width, height, x, y\n"
1232 "viewport:%d, %d, %d, %d\n"
1233 "recout: %d, %d, %d, %d\n",
1234 pipe_ctx->pipe_idx,
1235 pipe_ctx->scl_data.viewport.width,
1236 pipe_ctx->scl_data.viewport.height,
1237 pipe_ctx->scl_data.viewport.x,
1238 pipe_ctx->scl_data.viewport.y,
1239 pipe_ctx->scl_data.recout.width,
1240 pipe_ctx->scl_data.recout.height,
1241 pipe_ctx->scl_data.recout.x,
1242 pipe_ctx->scl_data.recout.y);
1243 print_rq_dlg_ttu(dc, pipe_ctx);
1244 }
1245 }
1246
1247 static void program_gamut_remap(struct pipe_ctx *pipe_ctx)
1248 {
1249 struct xfm_grph_csc_adjustment adjust;
1250 memset(&adjust, 0, sizeof(adjust));
1251 adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS;
1252
1253
1254 if (pipe_ctx->stream->public.gamut_remap_matrix.enable_remap == true) {
1255 adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW;
1256 adjust.temperature_matrix[0] =
1257 pipe_ctx->stream->
1258 public.gamut_remap_matrix.matrix[0];
1259 adjust.temperature_matrix[1] =
1260 pipe_ctx->stream->
1261 public.gamut_remap_matrix.matrix[1];
1262 adjust.temperature_matrix[2] =
1263 pipe_ctx->stream->
1264 public.gamut_remap_matrix.matrix[2];
1265 adjust.temperature_matrix[3] =
1266 pipe_ctx->stream->
1267 public.gamut_remap_matrix.matrix[4];
1268 adjust.temperature_matrix[4] =
1269 pipe_ctx->stream->
1270 public.gamut_remap_matrix.matrix[5];
1271 adjust.temperature_matrix[5] =
1272 pipe_ctx->stream->
1273 public.gamut_remap_matrix.matrix[6];
1274 adjust.temperature_matrix[6] =
1275 pipe_ctx->stream->
1276 public.gamut_remap_matrix.matrix[8];
1277 adjust.temperature_matrix[7] =
1278 pipe_ctx->stream->
1279 public.gamut_remap_matrix.matrix[9];
1280 adjust.temperature_matrix[8] =
1281 pipe_ctx->stream->
1282 public.gamut_remap_matrix.matrix[10];
1283 }
1284
1285 pipe_ctx->xfm->funcs->transform_set_gamut_remap(pipe_ctx->xfm, &adjust);
1286 }
1287
1288
1289 static void program_csc_matrix(struct pipe_ctx *pipe_ctx,
1290 enum dc_color_space colorspace,
1291 uint16_t *matrix)
1292 {
1293 int i;
1294 struct out_csc_color_matrix tbl_entry;
1295
1296 if (pipe_ctx->stream->public.csc_color_matrix.enable_adjustment
1297 == true) {
1298 enum dc_color_space color_space =
1299 pipe_ctx->stream->public.output_color_space;
1300
1301 //uint16_t matrix[12];
1302 for (i = 0; i < 12; i++)
1303 tbl_entry.regval[i] = pipe_ctx->stream->public.csc_color_matrix.matrix[i];
1304
1305 tbl_entry.color_space = color_space;
1306 //tbl_entry.regval = matrix;
1307 pipe_ctx->opp->funcs->opp_set_csc_adjustment(pipe_ctx->opp, &tbl_entry);
1308 }
1309 }
1310 static bool is_lower_pipe_tree_visible(struct pipe_ctx *pipe_ctx)
1311 {
1312 if (pipe_ctx->surface->public.visible)
1313 return true;
1314 if (pipe_ctx->bottom_pipe && is_lower_pipe_tree_visible(pipe_ctx->bottom_pipe))
1315 return true;
1316 return false;
1317 }
1318
1319 static bool is_upper_pipe_tree_visible(struct pipe_ctx *pipe_ctx)
1320 {
1321 if (pipe_ctx->surface->public.visible)
1322 return true;
1323 if (pipe_ctx->top_pipe && is_upper_pipe_tree_visible(pipe_ctx->top_pipe))
1324 return true;
1325 return false;
1326 }
1327
1328 static bool is_pipe_tree_visible(struct pipe_ctx *pipe_ctx)
1329 {
1330 if (pipe_ctx->surface->public.visible)
1331 return true;
1332 if (pipe_ctx->top_pipe && is_upper_pipe_tree_visible(pipe_ctx->top_pipe))
1333 return true;
1334 if (pipe_ctx->bottom_pipe && is_lower_pipe_tree_visible(pipe_ctx->bottom_pipe))
1335 return true;
1336 return false;
1337 }
1338
1339 static bool is_rgb_cspace(enum dc_color_space output_color_space)
1340 {
1341 switch (output_color_space) {
1342 case COLOR_SPACE_SRGB:
1343 case COLOR_SPACE_SRGB_LIMITED:
1344 case COLOR_SPACE_2020_RGB_FULLRANGE:
1345 case COLOR_SPACE_2020_RGB_LIMITEDRANGE:
1346 case COLOR_SPACE_ADOBERGB:
1347 return true;
1348 case COLOR_SPACE_YCBCR601:
1349 case COLOR_SPACE_YCBCR709:
1350 case COLOR_SPACE_YCBCR601_LIMITED:
1351 case COLOR_SPACE_YCBCR709_LIMITED:
1352 case COLOR_SPACE_2020_YCBCR:
1353 return false;
1354 default:
1355 /* Add a case to switch */
1356 BREAK_TO_DEBUGGER();
1357 return false;
1358 }
1359 }
1360
1361 static void dcn10_get_surface_visual_confirm_color(
1362 const struct pipe_ctx *pipe_ctx,
1363 struct tg_color *color)
1364 {
1365 uint32_t color_value = MAX_TG_COLOR_VALUE;
1366
1367 switch (pipe_ctx->scl_data.format) {
1368 case PIXEL_FORMAT_ARGB8888:
1369 /* set boarder color to red */
1370 color->color_r_cr = color_value;
1371 break;
1372
1373 case PIXEL_FORMAT_ARGB2101010:
1374 /* set boarder color to blue */
1375 color->color_b_cb = color_value;
1376 break;
1377 case PIXEL_FORMAT_420BPP8:
1378 /* set boarder color to green */
1379 color->color_g_y = color_value;
1380 break;
1381 case PIXEL_FORMAT_420BPP10:
1382 /* set boarder color to yellow */
1383 color->color_g_y = color_value;
1384 color->color_r_cr = color_value;
1385 break;
1386 case PIXEL_FORMAT_FP16:
1387 /* set boarder color to white */
1388 color->color_r_cr = color_value;
1389 color->color_b_cb = color_value;
1390 color->color_g_y = color_value;
1391 break;
1392 default:
1393 break;
1394 }
1395 }
1396
1397 static void update_dchubp_dpp(
1398 struct core_dc *dc,
1399 struct pipe_ctx *pipe_ctx,
1400 struct validate_context *context)
1401 {
1402 struct dce_hwseq *hws = dc->hwseq;
1403 struct mem_input *mi = pipe_ctx->mi;
1404 struct input_pixel_processor *ipp = pipe_ctx->ipp;
1405 struct core_surface *surface = pipe_ctx->surface;
1406 union plane_size size = surface->public.plane_size;
1407 struct default_adjustment ocsc = {0};
1408 struct tg_color black_color = {0};
1409 struct mpcc_cfg mpcc_cfg;
1410 bool per_pixel_alpha = surface->public.per_pixel_alpha && pipe_ctx->bottom_pipe;
1411
1412 /* TODO: proper fix once fpga works */
1413 /* depends on DML calculation, DPP clock value may change dynamically */
1414 enable_dppclk(
1415 dc->hwseq,
1416 pipe_ctx->pipe_idx,
1417 pipe_ctx->pix_clk_params.requested_pix_clk,
1418 context->bw.dcn.calc_clk.dppclk_div);
1419 dc->current_context->bw.dcn.cur_clk.dppclk_div =
1420 context->bw.dcn.calc_clk.dppclk_div;
1421 context->bw.dcn.cur_clk.dppclk_div = context->bw.dcn.calc_clk.dppclk_div;
1422
1423 /* TODO: Need input parameter to tell current DCHUB pipe tie to which OTG
1424 * VTG is within DCHUBBUB which is commond block share by each pipe HUBP.
1425 * VTG is 1:1 mapping with OTG. Each pipe HUBP will select which VTG
1426 */
1427 REG_UPDATE(DCHUBP_CNTL[pipe_ctx->pipe_idx], HUBP_VTG_SEL, pipe_ctx->tg->inst);
1428
1429 update_plane_addr(dc, pipe_ctx);
1430
1431 mi->funcs->mem_input_setup(
1432 mi,
1433 &pipe_ctx->dlg_regs,
1434 &pipe_ctx->ttu_regs,
1435 &pipe_ctx->rq_regs,
1436 &pipe_ctx->pipe_dlg_param);
1437
1438 size.grph.surface_size = pipe_ctx->scl_data.viewport;
1439
1440 if (dc->public.config.gpu_vm_support)
1441 mi->funcs->mem_input_program_pte_vm(
1442 pipe_ctx->mi,
1443 surface->public.format,
1444 &surface->public.tiling_info,
1445 surface->public.rotation);
1446
1447 ipp->funcs->ipp_setup(ipp,
1448 surface->public.format,
1449 1,
1450 IPP_OUTPUT_FORMAT_12_BIT_FIX);
1451
1452 pipe_ctx->scl_data.lb_params.alpha_en = per_pixel_alpha;
1453 mpcc_cfg.top_dpp_id = pipe_ctx->pipe_idx;
1454 if (pipe_ctx->bottom_pipe)
1455 mpcc_cfg.bot_mpcc_id = pipe_ctx->bottom_pipe->mpcc->inst;
1456 else
1457 mpcc_cfg.bot_mpcc_id = 0xf;
1458 mpcc_cfg.opp_id = pipe_ctx->tg->inst;
1459 mpcc_cfg.top_of_tree = pipe_ctx->pipe_idx == pipe_ctx->tg->inst;
1460 mpcc_cfg.per_pixel_alpha = per_pixel_alpha;
1461 /* DCN1.0 has output CM before MPC which seems to screw with
1462 * pre-multiplied alpha.
1463 */
1464 mpcc_cfg.pre_multiplied_alpha = is_rgb_cspace(
1465 pipe_ctx->stream->public.output_color_space)
1466 && per_pixel_alpha;
1467 pipe_ctx->mpcc->funcs->set(pipe_ctx->mpcc, &mpcc_cfg);
1468
1469 if (dc->public.debug.surface_visual_confirm) {
1470 dcn10_get_surface_visual_confirm_color(pipe_ctx, &black_color);
1471 } else {
1472 color_space_to_black_color(
1473 dc, pipe_ctx->stream->public.output_color_space,
1474 &black_color);
1475 }
1476 pipe_ctx->mpcc->funcs->set_bg_color(pipe_ctx->mpcc, &black_color);
1477
1478 pipe_ctx->scl_data.lb_params.depth = LB_PIXEL_DEPTH_30BPP;
1479 /* scaler configuration */
1480 pipe_ctx->xfm->funcs->transform_set_scaler(
1481 pipe_ctx->xfm, &pipe_ctx->scl_data);
1482 mi->funcs->mem_program_viewport(mi,
1483 &pipe_ctx->scl_data.viewport, &pipe_ctx->scl_data.viewport_c);
1484
1485 /*gamut remap*/
1486 program_gamut_remap(pipe_ctx);
1487
1488 /*TODO add adjustments parameters*/
1489 ocsc.out_color_space = pipe_ctx->stream->public.output_color_space;
1490 pipe_ctx->opp->funcs->opp_set_csc_default(pipe_ctx->opp, &ocsc);
1491
1492 mi->funcs->mem_input_program_surface_config(
1493 mi,
1494 surface->public.format,
1495 &surface->public.tiling_info,
1496 &size,
1497 surface->public.rotation,
1498 &surface->public.dcc,
1499 surface->public.horizontal_mirror);
1500
1501 mi->funcs->set_blank(mi, !is_pipe_tree_visible(pipe_ctx));
1502 }
1503
1504 static void program_all_pipe_in_tree(
1505 struct core_dc *dc,
1506 struct pipe_ctx *pipe_ctx,
1507 struct validate_context *context)
1508 {
1509 unsigned int ref_clk_mhz = dc->res_pool->ref_clock_inKhz/1000;
1510
1511 if (pipe_ctx->top_pipe == NULL) {
1512
1513 /* lock otg_master_update to process all pipes associated with
1514 * this OTG. this is done only one time.
1515 */
1516 /* watermark is for all pipes */
1517 pipe_ctx->mi->funcs->program_watermarks(
1518 pipe_ctx->mi, &context->bw.dcn.watermarks, ref_clk_mhz);
1519 pipe_ctx->tg->funcs->lock(pipe_ctx->tg);
1520
1521 pipe_ctx->tg->dlg_otg_param.vready_offset = pipe_ctx->pipe_dlg_param.vready_offset;
1522 pipe_ctx->tg->dlg_otg_param.vstartup_start = pipe_ctx->pipe_dlg_param.vstartup_start;
1523 pipe_ctx->tg->dlg_otg_param.vupdate_offset = pipe_ctx->pipe_dlg_param.vupdate_offset;
1524 pipe_ctx->tg->dlg_otg_param.vupdate_width = pipe_ctx->pipe_dlg_param.vupdate_width;
1525 pipe_ctx->tg->dlg_otg_param.signal = pipe_ctx->stream->signal;
1526
1527 pipe_ctx->tg->funcs->program_global_sync(
1528 pipe_ctx->tg);
1529 pipe_ctx->tg->funcs->set_blank(pipe_ctx->tg, !is_pipe_tree_visible(pipe_ctx));
1530 }
1531
1532 if (pipe_ctx->surface != NULL) {
1533 dcn10_power_on_fe(dc, pipe_ctx, context);
1534 update_dchubp_dpp(dc, pipe_ctx, context);
1535 }
1536
1537 if (pipe_ctx->bottom_pipe != NULL)
1538 program_all_pipe_in_tree(dc, pipe_ctx->bottom_pipe, context);
1539 }
1540
1541 static void dcn10_pplib_apply_display_requirements(
1542 struct core_dc *dc,
1543 struct validate_context *context)
1544 {
1545 struct dm_pp_display_configuration *pp_display_cfg = &context->pp_display_cfg;
1546
1547 pp_display_cfg->all_displays_in_sync = false;/*todo*/
1548 pp_display_cfg->nb_pstate_switch_disable = false;
1549 pp_display_cfg->min_engine_clock_khz = context->bw.dcn.cur_clk.dcfclk_khz;
1550 pp_display_cfg->min_memory_clock_khz = context->bw.dcn.cur_clk.fclk_khz;
1551 pp_display_cfg->min_engine_clock_deep_sleep_khz = context->bw.dcn.cur_clk.dcfclk_deep_sleep_khz;
1552 pp_display_cfg->min_dcfc_deep_sleep_clock_khz = context->bw.dcn.cur_clk.dcfclk_deep_sleep_khz;
1553 pp_display_cfg->avail_mclk_switch_time_us =
1554 context->bw.dcn.cur_clk.dram_ccm_us > 0 ? context->bw.dcn.cur_clk.dram_ccm_us : 0;
1555 pp_display_cfg->avail_mclk_switch_time_in_disp_active_us =
1556 context->bw.dcn.cur_clk.min_active_dram_ccm_us > 0 ? context->bw.dcn.cur_clk.min_active_dram_ccm_us : 0;
1557 pp_display_cfg->min_dcfclock_khz = context->bw.dcn.cur_clk.dcfclk_khz;
1558 pp_display_cfg->disp_clk_khz = context->bw.dcn.cur_clk.dispclk_khz;
1559 dce110_fill_display_configs(context, pp_display_cfg);
1560
1561 if (memcmp(&dc->prev_display_config, pp_display_cfg, sizeof(
1562 struct dm_pp_display_configuration)) != 0)
1563 dm_pp_apply_display_requirements(dc->ctx, pp_display_cfg);
1564
1565 dc->prev_display_config = *pp_display_cfg;
1566 }
1567
1568 static void dcn10_apply_ctx_for_surface(
1569 struct core_dc *dc,
1570 struct core_surface *surface,
1571 struct validate_context *context)
1572 {
1573 int i;
1574
1575 /* reset unused mpcc */
1576 for (i = 0; i < dc->res_pool->pipe_count; i++) {
1577 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
1578 struct pipe_ctx *old_pipe_ctx =
1579 &dc->current_context->res_ctx.pipe_ctx[i];
1580
1581 if ((!pipe_ctx->surface && old_pipe_ctx->surface)
1582 || (!pipe_ctx->stream && old_pipe_ctx->stream)) {
1583 struct mpcc_cfg mpcc_cfg;
1584 int opp_id_cached = old_pipe_ctx->mpcc->opp_id;
1585
1586 if (!old_pipe_ctx->top_pipe) {
1587 ASSERT(0);
1588 continue;
1589 }
1590
1591 mpcc_cfg.opp_id = 0xf;
1592 mpcc_cfg.top_dpp_id = 0xf;
1593 mpcc_cfg.bot_mpcc_id = 0xf;
1594 mpcc_cfg.top_of_tree = !old_pipe_ctx->top_pipe;
1595 old_pipe_ctx->mpcc->funcs->set(old_pipe_ctx->mpcc, &mpcc_cfg);
1596 /*
1597 * the mpcc is the only thing that keeps track of the mpcc
1598 * mapping for reset front end right now. Might need some
1599 * rework.
1600 */
1601 old_pipe_ctx->mpcc->opp_id = opp_id_cached;
1602
1603 old_pipe_ctx->top_pipe = NULL;
1604 old_pipe_ctx->bottom_pipe = NULL;
1605 old_pipe_ctx->surface = NULL;
1606
1607 dm_logger_write(dc->ctx->logger, LOG_DC,
1608 "Reset mpcc for pipe %d\n",
1609 old_pipe_ctx->pipe_idx);
1610 }
1611 }
1612
1613 if (!surface)
1614 return;
1615
1616 for (i = 0; i < dc->res_pool->pipe_count; i++) {
1617 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
1618
1619 if (pipe_ctx->surface != surface)
1620 continue;
1621
1622 /* looking for top pipe to program */
1623 if (!pipe_ctx->top_pipe)
1624 program_all_pipe_in_tree(dc, pipe_ctx, context);
1625 }
1626
1627 dm_logger_write(dc->ctx->logger, LOG_BANDWIDTH_CALCS,
1628 "\n============== Watermark parameters ==============\n"
1629 "a.urgent_ns: %d \n"
1630 "a.cstate_enter_plus_exit: %d \n"
1631 "a.cstate_exit: %d \n"
1632 "a.pstate_change: %d \n"
1633 "a.pte_meta_urgent: %d \n"
1634 "b.urgent_ns: %d \n"
1635 "b.cstate_enter_plus_exit: %d \n"
1636 "b.cstate_exit: %d \n"
1637 "b.pstate_change: %d \n"
1638 "b.pte_meta_urgent: %d \n",
1639 context->bw.dcn.watermarks.a.urgent_ns,
1640 context->bw.dcn.watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns,
1641 context->bw.dcn.watermarks.a.cstate_pstate.cstate_exit_ns,
1642 context->bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns,
1643 context->bw.dcn.watermarks.a.pte_meta_urgent_ns,
1644 context->bw.dcn.watermarks.b.urgent_ns,
1645 context->bw.dcn.watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns,
1646 context->bw.dcn.watermarks.b.cstate_pstate.cstate_exit_ns,
1647 context->bw.dcn.watermarks.b.cstate_pstate.pstate_change_ns,
1648 context->bw.dcn.watermarks.b.pte_meta_urgent_ns
1649 );
1650 dm_logger_write(dc->ctx->logger, LOG_BANDWIDTH_CALCS,
1651 "\nc.urgent_ns: %d \n"
1652 "c.cstate_enter_plus_exit: %d \n"
1653 "c.cstate_exit: %d \n"
1654 "c.pstate_change: %d \n"
1655 "c.pte_meta_urgent: %d \n"
1656 "d.urgent_ns: %d \n"
1657 "d.cstate_enter_plus_exit: %d \n"
1658 "d.cstate_exit: %d \n"
1659 "d.pstate_change: %d \n"
1660 "d.pte_meta_urgent: %d \n"
1661 "========================================================\n",
1662 context->bw.dcn.watermarks.c.urgent_ns,
1663 context->bw.dcn.watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns,
1664 context->bw.dcn.watermarks.c.cstate_pstate.cstate_exit_ns,
1665 context->bw.dcn.watermarks.c.cstate_pstate.pstate_change_ns,
1666 context->bw.dcn.watermarks.c.pte_meta_urgent_ns,
1667 context->bw.dcn.watermarks.d.urgent_ns,
1668 context->bw.dcn.watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns,
1669 context->bw.dcn.watermarks.d.cstate_pstate.cstate_exit_ns,
1670 context->bw.dcn.watermarks.d.cstate_pstate.pstate_change_ns,
1671 context->bw.dcn.watermarks.d.pte_meta_urgent_ns
1672 );
1673 }
1674
1675 static void dcn10_set_bandwidth(
1676 struct core_dc *dc,
1677 struct validate_context *context,
1678 bool decrease_allowed)
1679 {
1680 struct dm_pp_clock_for_voltage_req clock;
1681
1682 if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment))
1683 return;
1684
1685 if (decrease_allowed || context->bw.dcn.calc_clk.dispclk_khz
1686 > dc->current_context->bw.dcn.cur_clk.dispclk_khz) {
1687 dc->res_pool->display_clock->funcs->set_clock(
1688 dc->res_pool->display_clock,
1689 context->bw.dcn.calc_clk.dispclk_khz);
1690 dc->current_context->bw.dcn.cur_clk.dispclk_khz =
1691 context->bw.dcn.calc_clk.dispclk_khz;
1692 }
1693 if (decrease_allowed || context->bw.dcn.calc_clk.dcfclk_khz
1694 > dc->current_context->bw.dcn.cur_clk.dcfclk_khz) {
1695 clock.clk_type = DM_PP_CLOCK_TYPE_DCFCLK;
1696 clock.clocks_in_khz = context->bw.dcn.calc_clk.dcfclk_khz;
1697 dm_pp_apply_clock_for_voltage_request(dc->ctx, &clock);
1698 dc->current_context->bw.dcn.cur_clk.dcfclk_khz = clock.clocks_in_khz;
1699 context->bw.dcn.cur_clk.dcfclk_khz = clock.clocks_in_khz;
1700 }
1701 if (decrease_allowed || context->bw.dcn.calc_clk.fclk_khz
1702 > dc->current_context->bw.dcn.cur_clk.fclk_khz) {
1703 clock.clk_type = DM_PP_CLOCK_TYPE_FCLK;
1704 clock.clocks_in_khz = context->bw.dcn.calc_clk.fclk_khz;
1705 dm_pp_apply_clock_for_voltage_request(dc->ctx, &clock);
1706 dc->current_context->bw.dcn.calc_clk.fclk_khz = clock.clocks_in_khz;
1707 context->bw.dcn.cur_clk.fclk_khz = clock.clocks_in_khz;
1708 }
1709 if (decrease_allowed || context->bw.dcn.calc_clk.dcfclk_deep_sleep_khz
1710 > dc->current_context->bw.dcn.cur_clk.dcfclk_deep_sleep_khz) {
1711 dc->current_context->bw.dcn.calc_clk.dcfclk_deep_sleep_khz =
1712 context->bw.dcn.calc_clk.dcfclk_deep_sleep_khz;
1713 context->bw.dcn.cur_clk.dcfclk_deep_sleep_khz =
1714 context->bw.dcn.calc_clk.dcfclk_deep_sleep_khz;
1715 }
1716 /* Decrease in freq is increase in period so opposite comparison for dram_ccm */
1717 if (decrease_allowed || context->bw.dcn.calc_clk.dram_ccm_us
1718 < dc->current_context->bw.dcn.cur_clk.dram_ccm_us) {
1719 dc->current_context->bw.dcn.calc_clk.dram_ccm_us =
1720 context->bw.dcn.calc_clk.dram_ccm_us;
1721 context->bw.dcn.cur_clk.dram_ccm_us =
1722 context->bw.dcn.calc_clk.dram_ccm_us;
1723 }
1724 if (decrease_allowed || context->bw.dcn.calc_clk.min_active_dram_ccm_us
1725 < dc->current_context->bw.dcn.cur_clk.min_active_dram_ccm_us) {
1726 dc->current_context->bw.dcn.calc_clk.min_active_dram_ccm_us =
1727 context->bw.dcn.calc_clk.min_active_dram_ccm_us;
1728 context->bw.dcn.cur_clk.min_active_dram_ccm_us =
1729 context->bw.dcn.calc_clk.min_active_dram_ccm_us;
1730 }
1731 dcn10_pplib_apply_display_requirements(dc, context);
1732 }
1733
1734 static void set_drr(struct pipe_ctx **pipe_ctx,
1735 int num_pipes, int vmin, int vmax)
1736 {
1737 int i = 0;
1738 struct drr_params params = {0};
1739
1740 params.vertical_total_max = vmax;
1741 params.vertical_total_min = vmin;
1742
1743 /* TODO: If multiple pipes are to be supported, you need
1744 * some GSL stuff
1745 */
1746 for (i = 0; i < num_pipes; i++) {
1747 pipe_ctx[i]->tg->funcs->set_drr(pipe_ctx[i]->tg, &params);
1748 }
1749 }
1750
1751 static void get_position(struct pipe_ctx **pipe_ctx,
1752 int num_pipes,
1753 struct crtc_position *position)
1754 {
1755 int i = 0;
1756
1757 /* TODO: handle pipes > 1
1758 */
1759 for (i = 0; i < num_pipes; i++)
1760 pipe_ctx[i]->tg->funcs->get_position(pipe_ctx[i]->tg, position);
1761 }
1762
1763 static void set_static_screen_control(struct pipe_ctx **pipe_ctx,
1764 int num_pipes, const struct dc_static_screen_events *events)
1765 {
1766 unsigned int i;
1767 unsigned int value = 0;
1768
1769 if (events->surface_update)
1770 value |= 0x80;
1771 if (events->cursor_update)
1772 value |= 0x2;
1773
1774 for (i = 0; i < num_pipes; i++)
1775 pipe_ctx[i]->tg->funcs->
1776 set_static_screen_control(pipe_ctx[i]->tg, value);
1777 }
1778
1779 static void set_plane_config(
1780 const struct core_dc *dc,
1781 struct pipe_ctx *pipe_ctx,
1782 struct resource_context *res_ctx)
1783 {
1784 /* TODO */
1785 program_gamut_remap(pipe_ctx);
1786 }
1787
1788 static void dcn10_config_stereo_parameters(
1789 struct core_stream *stream, struct crtc_stereo_flags *flags)
1790 {
1791 enum view_3d_format view_format = stream->public.view_format;
1792 enum dc_timing_3d_format timing_3d_format =\
1793 stream->public.timing.timing_3d_format;
1794 bool non_stereo_timing = false;
1795
1796 if (timing_3d_format == TIMING_3D_FORMAT_NONE ||
1797 timing_3d_format == TIMING_3D_FORMAT_SIDE_BY_SIDE ||
1798 timing_3d_format == TIMING_3D_FORMAT_TOP_AND_BOTTOM)
1799 non_stereo_timing = true;
1800
1801 if (non_stereo_timing == false &&
1802 view_format == VIEW_3D_FORMAT_FRAME_SEQUENTIAL) {
1803
1804 flags->PROGRAM_STEREO = 1;
1805 flags->PROGRAM_POLARITY = 1;
1806 if (timing_3d_format == TIMING_3D_FORMAT_INBAND_FA ||
1807 timing_3d_format == TIMING_3D_FORMAT_DP_HDMI_INBAND_FA ||
1808 timing_3d_format == TIMING_3D_FORMAT_SIDEBAND_FA) {
1809 enum display_dongle_type dongle = \
1810 stream->sink->link->public.ddc->dongle_type;
1811 if (dongle == DISPLAY_DONGLE_DP_VGA_CONVERTER ||
1812 dongle == DISPLAY_DONGLE_DP_DVI_CONVERTER ||
1813 dongle == DISPLAY_DONGLE_DP_HDMI_CONVERTER)
1814 flags->DISABLE_STEREO_DP_SYNC = 1;
1815 }
1816 flags->RIGHT_EYE_POLARITY =\
1817 stream->public.timing.flags.RIGHT_EYE_3D_POLARITY;
1818 if (timing_3d_format == TIMING_3D_FORMAT_HW_FRAME_PACKING)
1819 flags->FRAME_PACKED = 1;
1820 }
1821
1822 return;
1823 }
1824
1825 static void dcn10_setup_stereo(struct pipe_ctx *pipe_ctx, struct core_dc *dc)
1826 {
1827 struct crtc_stereo_flags flags = { 0 };
1828 struct core_stream *stream = pipe_ctx->stream;
1829
1830 dcn10_config_stereo_parameters(stream, &flags);
1831
1832 pipe_ctx->opp->funcs->opp_set_stereo_polarity(
1833 pipe_ctx->opp,
1834 flags.PROGRAM_STEREO == 1 ? true:false,
1835 stream->public.timing.flags.RIGHT_EYE_3D_POLARITY == 1 ? true:false);
1836
1837 pipe_ctx->tg->funcs->program_stereo(
1838 pipe_ctx->tg,
1839 &stream->public.timing,
1840 &flags);
1841
1842 return;
1843 }
1844
1845 static bool dcn10_dummy_display_power_gating(
1846 struct core_dc *dc,
1847 uint8_t controller_id,
1848 struct dc_bios *dcb,
1849 enum pipe_gating_control power_gating) {return true; }
1850
1851 static const struct hw_sequencer_funcs dcn10_funcs = {
1852 .program_gamut_remap = program_gamut_remap,
1853 .program_csc_matrix = program_csc_matrix,
1854 .init_hw = dcn10_init_hw,
1855 .apply_ctx_to_hw = dce110_apply_ctx_to_hw,
1856 .apply_ctx_for_surface = dcn10_apply_ctx_for_surface,
1857 .set_plane_config = set_plane_config,
1858 .update_plane_addr = update_plane_addr,
1859 .update_pending_status = dce110_update_pending_status,
1860 .set_input_transfer_func = dcn10_set_input_transfer_func,
1861 .set_output_transfer_func = dcn10_set_output_transfer_func,
1862 .power_down = dce110_power_down,
1863 .enable_accelerated_mode = dce110_enable_accelerated_mode,
1864 .enable_timing_synchronization = dcn10_enable_timing_synchronization,
1865 .update_info_frame = dce110_update_info_frame,
1866 .enable_stream = dce110_enable_stream,
1867 .disable_stream = dce110_disable_stream,
1868 .unblank_stream = dce110_unblank_stream,
1869 .enable_display_power_gating = dcn10_dummy_display_power_gating,
1870 .power_down_front_end = dcn10_power_down_fe,
1871 .power_on_front_end = dcn10_power_on_fe,
1872 .pipe_control_lock = dcn10_pipe_control_lock,
1873 .set_bandwidth = dcn10_set_bandwidth,
1874 .reset_hw_ctx_wrap = reset_hw_ctx_wrap,
1875 .prog_pixclk_crtc_otg = dcn10_prog_pixclk_crtc_otg,
1876 .set_drr = set_drr,
1877 .get_position = get_position,
1878 .set_static_screen_control = set_static_screen_control,
1879 .setup_stereo = dcn10_setup_stereo,
1880 .set_avmute = dce110_set_avmute,
1881 };
1882
1883
1884 void dcn10_hw_sequencer_construct(struct core_dc *dc)
1885 {
1886 dc->hwss = dcn10_funcs;
1887 }
1888