]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blame - drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
drm/amd/display: don't ignore alpha property on pre-multiplied mode
[mirror_ubuntu-jammy-kernel.git] / drivers / gpu / drm / amd / display / dc / dcn10 / dcn10_hw_sequencer.c
CommitLineData
70ccab60
HW
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
88099f53 26#include <linux/delay.h>
70ccab60 27#include "dm_services.h"
78c77382 28#include "basics/dc_common.h"
70ccab60 29#include "core_types.h"
70ccab60 30#include "resource.h"
b02c3b05 31#include "custom_float.h"
70ccab60 32#include "dcn10_hw_sequencer.h"
78c77382 33#include "dcn10_hw_sequencer_debug.h"
5aff86c1 34#include "dce/dce_hwseq.h"
70ccab60 35#include "abm.h"
4952d4c5 36#include "dmcu.h"
b51adc77 37#include "dcn10_optc.h"
78c77382
AK
38#include "dcn10_dpp.h"
39#include "dcn10_mpc.h"
70ccab60
HW
40#include "timing_generator.h"
41#include "opp.h"
42#include "ipp.h"
b02c3b05 43#include "mpc.h"
184debdb 44#include "reg_helper.h"
86be9a04 45#include "dcn10_hubp.h"
62d591a8 46#include "dcn10_hubbub.h"
b6295960 47#include "dcn10_cm_common.h"
aa9c4abe 48#include "dc_link_dp.h"
ea2e8d92 49#include "dccg.h"
dc88b4a6 50#include "clk_mgr.h"
896dace8
JG
51#include "link_hwss.h"
52#include "dpcd_defs.h"
97bda032 53#include "dsc.h"
dc6e2448 54#include "dce/dmub_hw_lock_mgr.h"
8b198f6e 55#include "dc_trace.h"
4f8e37db 56#include "dce/dmub_outbox.h"
c5bc8c1b 57#include "inc/dc_link_dp.h"
30adeee5 58#include "inc/link_dpcd.h"
7ed4e635 59
5d4b05dd
BL
60#define DC_LOGGER_INIT(logger)
61
184debdb
DL
62#define CTX \
63 hws->ctx
64#define REG(reg)\
65 hws->regs->reg
70ccab60 66
184debdb
DL
67#undef FN
68#define FN(reg_name, field_name) \
69 hws->shifts->field_name, hws->masks->field_name
70ccab60 70
a052a516 71/*print is 17 wide, first two characters are spaces*/
62d591a8 72#define DTN_INFO_MICRO_SEC(ref_cycle) \
46659a83 73 print_microsec(dc_ctx, log_ctx, ref_cycle)
71395011 74
78c77382
AK
75#define GAMMA_HW_POINTS_NUM 256
76
23344703
RS
77#define PGFSM_POWER_ON 0
78#define PGFSM_POWER_OFF 2
79
46659a83
NK
80void print_microsec(struct dc_context *dc_ctx,
81 struct dc_log_buffer_ctx *log_ctx,
82 uint32_t ref_cycle)
eb4e33b7 83{
33d7598d 84 const uint32_t ref_clk_mhz = dc_ctx->dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000;
a052a516 85 static const unsigned int frac = 1000;
eb4e33b7
TC
86 uint32_t us_x10 = (ref_cycle * frac) / ref_clk_mhz;
87
a052a516 88 DTN_INFO(" %11d.%03d",
eb4e33b7
TC
89 us_x10 / frac,
90 us_x10 % frac);
91}
92
009114f6 93void dcn10_lock_all_pipes(struct dc *dc,
78c77382
AK
94 struct dc_state *context,
95 bool lock)
96{
97 struct pipe_ctx *pipe_ctx;
98 struct timing_generator *tg;
99 int i;
100
101 for (i = 0; i < dc->res_pool->pipe_count; i++) {
102 pipe_ctx = &context->res_ctx.pipe_ctx[i];
103 tg = pipe_ctx->stream_res.tg;
009114f6 104
78c77382
AK
105 /*
106 * Only lock the top pipe's tg to prevent redundant
107 * (un)locking. Also skip if pipe is disabled.
108 */
109 if (pipe_ctx->top_pipe ||
110 !pipe_ctx->stream || !pipe_ctx->plane_state ||
111 !tg->funcs->is_tg_enabled(tg))
112 continue;
113
114 if (lock)
009114f6 115 dc->hwss.pipe_control_lock(dc, pipe_ctx, true);
78c77382 116 else
009114f6 117 dc->hwss.pipe_control_lock(dc, pipe_ctx, false);
78c77382
AK
118 }
119}
120
46659a83
NK
121static void log_mpc_crc(struct dc *dc,
122 struct dc_log_buffer_ctx *log_ctx)
233dcd20 123{
62d591a8
YHL
124 struct dc_context *dc_ctx = dc->ctx;
125 struct dce_hwseq *hws = dc->hwseq;
126
127 if (REG(MPC_CRC_RESULT_GB))
128 DTN_INFO("MPC_CRC_RESULT_GB:%d MPC_CRC_RESULT_C:%d MPC_CRC_RESULT_AR:%d\n",
129 REG_READ(MPC_CRC_RESULT_GB), REG_READ(MPC_CRC_RESULT_C), REG_READ(MPC_CRC_RESULT_AR));
130 if (REG(DPP_TOP0_DPP_CRC_VAL_B_A))
131 DTN_INFO("DPP_TOP0_DPP_CRC_VAL_B_A:%d DPP_TOP0_DPP_CRC_VAL_R_G:%d\n",
132 REG_READ(DPP_TOP0_DPP_CRC_VAL_B_A), REG_READ(DPP_TOP0_DPP_CRC_VAL_R_G));
233dcd20
TC
133}
134
46659a83 135void dcn10_log_hubbub_state(struct dc *dc, struct dc_log_buffer_ctx *log_ctx)
233dcd20
TC
136{
137 struct dc_context *dc_ctx = dc->ctx;
785fd44c 138 struct dcn_hubbub_wm wm;
233dcd20
TC
139 int i;
140
785fd44c 141 memset(&wm, 0, sizeof(struct dcn_hubbub_wm));
da1043cf 142 dc->res_pool->hubbub->funcs->wm_read_state(dc->res_pool->hubbub, &wm);
233dcd20 143
a052a516
DL
144 DTN_INFO("HUBBUB WM: data_urgent pte_meta_urgent"
145 " sr_enter sr_exit dram_clk_change\n");
233dcd20
TC
146
147 for (i = 0; i < 4; i++) {
148 struct dcn_hubbub_wm_set *s;
149
150 s = &wm.sets[i];
a052a516 151 DTN_INFO("WM_Set[%d]:", s->wm_set);
233dcd20
TC
152 DTN_INFO_MICRO_SEC(s->data_urgent);
153 DTN_INFO_MICRO_SEC(s->pte_meta_urgent);
154 DTN_INFO_MICRO_SEC(s->sr_enter);
155 DTN_INFO_MICRO_SEC(s->sr_exit);
156 DTN_INFO_MICRO_SEC(s->dram_clk_chanage);
157 DTN_INFO("\n");
158 }
159
160 DTN_INFO("\n");
161}
162
46659a83 163static void dcn10_log_hubp_states(struct dc *dc, void *log_ctx)
71395011
TC
164{
165 struct dc_context *dc_ctx = dc->ctx;
166 struct resource_pool *pool = dc->res_pool;
167 int i;
168
ae8cf977
LHM
169 DTN_INFO(
170 "HUBP: format addr_hi width height rot mir sw_mode dcc_en blank_en clock_en ttu_dis underflow min_ttu_vblank qos_low_wm qos_high_wm\n");
71395011 171 for (i = 0; i < pool->pipe_count; i++) {
8feabd03 172 struct hubp *hubp = pool->hubps[i];
34cb6b38 173 struct dcn_hubp_state *s = &(TO_DCN10_HUBP(hubp)->state);
71395011 174
34cb6b38 175 hubp->funcs->hubp_read_state(hubp);
71395011 176
a3cb1c1c 177 if (!s->blank_en) {
ae8cf977 178 DTN_INFO("[%2d]: %5xh %6xh %5d %6d %2xh %2xh %6xh %6d %8d %8d %7d %8xh",
a3cb1c1c
NC
179 hubp->inst,
180 s->pixel_format,
181 s->inuse_addr_hi,
182 s->viewport_width,
183 s->viewport_height,
184 s->rotation_angle,
185 s->h_mirror_en,
186 s->sw_mode,
187 s->dcc_en,
188 s->blank_en,
ae8cf977 189 s->clock_en,
a3cb1c1c
NC
190 s->ttu_disable,
191 s->underflow_status);
192 DTN_INFO_MICRO_SEC(s->min_ttu_vblank);
193 DTN_INFO_MICRO_SEC(s->qos_level_low_wm);
194 DTN_INFO_MICRO_SEC(s->qos_level_high_wm);
195 DTN_INFO("\n");
196 }
71395011 197 }
34cb6b38
DL
198
199 DTN_INFO("\n=========RQ========\n");
200 DTN_INFO("HUBP: drq_exp_m prq_exp_m mrq_exp_m crq_exp_m plane1_ba L:chunk_s min_chu_s meta_ch_s"
b9c1c67a 201 " min_m_c_s dpte_gr_s mpte_gr_s swath_hei pte_row_h C:chunk_s min_chu_s meta_ch_s"
34cb6b38
DL
202 " min_m_c_s dpte_gr_s mpte_gr_s swath_hei pte_row_h\n");
203 for (i = 0; i < pool->pipe_count; i++) {
204 struct dcn_hubp_state *s = &(TO_DCN10_HUBP(pool->hubps[i])->state);
205 struct _vcs_dpi_display_rq_regs_st *rq_regs = &s->rq_regs;
206
a3cb1c1c 207 if (!s->blank_en)
b9c1c67a 208 DTN_INFO("[%2d]: %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh\n",
a3cb1c1c
NC
209 pool->hubps[i]->inst, rq_regs->drq_expansion_mode, rq_regs->prq_expansion_mode, rq_regs->mrq_expansion_mode,
210 rq_regs->crq_expansion_mode, rq_regs->plane1_base_address, rq_regs->rq_regs_l.chunk_size,
211 rq_regs->rq_regs_l.min_chunk_size, rq_regs->rq_regs_l.meta_chunk_size,
212 rq_regs->rq_regs_l.min_meta_chunk_size, rq_regs->rq_regs_l.dpte_group_size,
213 rq_regs->rq_regs_l.mpte_group_size, rq_regs->rq_regs_l.swath_height,
b9c1c67a
DL
214 rq_regs->rq_regs_l.pte_row_height_linear, rq_regs->rq_regs_c.chunk_size, rq_regs->rq_regs_c.min_chunk_size,
215 rq_regs->rq_regs_c.meta_chunk_size, rq_regs->rq_regs_c.min_meta_chunk_size,
216 rq_regs->rq_regs_c.dpte_group_size, rq_regs->rq_regs_c.mpte_group_size,
217 rq_regs->rq_regs_c.swath_height, rq_regs->rq_regs_c.pte_row_height_linear);
34cb6b38
DL
218 }
219
220 DTN_INFO("========DLG========\n");
221 DTN_INFO("HUBP: rc_hbe dlg_vbe min_d_y_n rc_per_ht rc_x_a_s "
222 " dst_y_a_s dst_y_pf dst_y_vvb dst_y_rvb dst_y_vfl dst_y_rfl rf_pix_fq"
223 " vratio_pf vrat_pf_c rc_pg_vbl rc_pg_vbc rc_mc_vbl rc_mc_vbc rc_pg_fll"
224 " rc_pg_flc rc_mc_fll rc_mc_flc pr_nom_l pr_nom_c rc_pg_nl rc_pg_nc "
225 " mr_nom_l mr_nom_c rc_mc_nl rc_mc_nc rc_ld_pl rc_ld_pc rc_ld_l "
226 " rc_ld_c cha_cur0 ofst_cur1 cha_cur1 vr_af_vc0 ddrq_limt x_rt_dlay"
227 " x_rp_dlay x_rr_sfl\n");
228 for (i = 0; i < pool->pipe_count; i++) {
229 struct dcn_hubp_state *s = &(TO_DCN10_HUBP(pool->hubps[i])->state);
230 struct _vcs_dpi_display_dlg_regs_st *dlg_regs = &s->dlg_attr;
231
a3cb1c1c
NC
232 if (!s->blank_en)
233 DTN_INFO("[%2d]: %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh"
234 "% 8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh"
235 " %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh\n",
236 pool->hubps[i]->inst, dlg_regs->refcyc_h_blank_end, dlg_regs->dlg_vblank_end, dlg_regs->min_dst_y_next_start,
237 dlg_regs->refcyc_per_htotal, dlg_regs->refcyc_x_after_scaler, dlg_regs->dst_y_after_scaler,
238 dlg_regs->dst_y_prefetch, dlg_regs->dst_y_per_vm_vblank, dlg_regs->dst_y_per_row_vblank,
239 dlg_regs->dst_y_per_vm_flip, dlg_regs->dst_y_per_row_flip, dlg_regs->ref_freq_to_pix_freq,
240 dlg_regs->vratio_prefetch, dlg_regs->vratio_prefetch_c, dlg_regs->refcyc_per_pte_group_vblank_l,
241 dlg_regs->refcyc_per_pte_group_vblank_c, dlg_regs->refcyc_per_meta_chunk_vblank_l,
242 dlg_regs->refcyc_per_meta_chunk_vblank_c, dlg_regs->refcyc_per_pte_group_flip_l,
243 dlg_regs->refcyc_per_pte_group_flip_c, dlg_regs->refcyc_per_meta_chunk_flip_l,
244 dlg_regs->refcyc_per_meta_chunk_flip_c, dlg_regs->dst_y_per_pte_row_nom_l,
245 dlg_regs->dst_y_per_pte_row_nom_c, dlg_regs->refcyc_per_pte_group_nom_l,
246 dlg_regs->refcyc_per_pte_group_nom_c, dlg_regs->dst_y_per_meta_row_nom_l,
247 dlg_regs->dst_y_per_meta_row_nom_c, dlg_regs->refcyc_per_meta_chunk_nom_l,
248 dlg_regs->refcyc_per_meta_chunk_nom_c, dlg_regs->refcyc_per_line_delivery_pre_l,
249 dlg_regs->refcyc_per_line_delivery_pre_c, dlg_regs->refcyc_per_line_delivery_l,
250 dlg_regs->refcyc_per_line_delivery_c, dlg_regs->chunk_hdl_adjust_cur0, dlg_regs->dst_y_offset_cur1,
251 dlg_regs->chunk_hdl_adjust_cur1, dlg_regs->vready_after_vcount0, dlg_regs->dst_y_delta_drq_limit,
252 dlg_regs->xfc_reg_transfer_delay, dlg_regs->xfc_reg_precharge_delay,
253 dlg_regs->xfc_reg_remote_surface_flip_latency);
34cb6b38
DL
254 }
255
256 DTN_INFO("========TTU========\n");
257 DTN_INFO("HUBP: qos_ll_wm qos_lh_wm mn_ttu_vb qos_l_flp rc_rd_p_l rc_rd_l rc_rd_p_c"
258 " rc_rd_c rc_rd_c0 rc_rd_pc0 rc_rd_c1 rc_rd_pc1 qos_lf_l qos_rds_l"
259 " qos_lf_c qos_rds_c qos_lf_c0 qos_rds_c0 qos_lf_c1 qos_rds_c1\n");
260 for (i = 0; i < pool->pipe_count; i++) {
261 struct dcn_hubp_state *s = &(TO_DCN10_HUBP(pool->hubps[i])->state);
262 struct _vcs_dpi_display_ttu_regs_st *ttu_regs = &s->ttu_attr;
263
a3cb1c1c
NC
264 if (!s->blank_en)
265 DTN_INFO("[%2d]: %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh\n",
266 pool->hubps[i]->inst, ttu_regs->qos_level_low_wm, ttu_regs->qos_level_high_wm, ttu_regs->min_ttu_vblank,
267 ttu_regs->qos_level_flip, ttu_regs->refcyc_per_req_delivery_pre_l, ttu_regs->refcyc_per_req_delivery_l,
268 ttu_regs->refcyc_per_req_delivery_pre_c, ttu_regs->refcyc_per_req_delivery_c, ttu_regs->refcyc_per_req_delivery_cur0,
269 ttu_regs->refcyc_per_req_delivery_pre_cur0, ttu_regs->refcyc_per_req_delivery_cur1,
270 ttu_regs->refcyc_per_req_delivery_pre_cur1, ttu_regs->qos_level_fixed_l, ttu_regs->qos_ramp_disable_l,
271 ttu_regs->qos_level_fixed_c, ttu_regs->qos_ramp_disable_c, ttu_regs->qos_level_fixed_cur0,
272 ttu_regs->qos_ramp_disable_cur0, ttu_regs->qos_level_fixed_cur1, ttu_regs->qos_ramp_disable_cur1);
34cb6b38 273 }
71395011 274 DTN_INFO("\n");
34cb6b38
DL
275}
276
46659a83
NK
277void dcn10_log_hw_state(struct dc *dc,
278 struct dc_log_buffer_ctx *log_ctx)
34cb6b38
DL
279{
280 struct dc_context *dc_ctx = dc->ctx;
281 struct resource_pool *pool = dc->res_pool;
282 int i;
283
284 DTN_INFO_BEGIN();
285
46659a83 286 dcn10_log_hubbub_state(dc, log_ctx);
34cb6b38 287
46659a83 288 dcn10_log_hubp_states(dc, log_ctx);
a052a516 289
7c91bd43
AK
290 DTN_INFO("DPP: IGAM format IGAM mode DGAM mode RGAM mode"
291 " GAMUT mode C11 C12 C13 C14 C21 C22 C23 C24 "
292 "C31 C32 C33 C34\n");
293 for (i = 0; i < pool->pipe_count; i++) {
294 struct dpp *dpp = pool->dpps[i];
d02e0794 295 struct dcn_dpp_state s = {0};
7c91bd43
AK
296
297 dpp->funcs->dpp_read_state(dpp, &s);
298
d02e0794
NC
299 if (!s.is_enabled)
300 continue;
301
7c91bd43 302 DTN_INFO("[%2d]: %11xh %-11s %-11s %-11s"
7b265fd9 303 "%8x %08xh %08xh %08xh %08xh %08xh %08xh",
7c91bd43
AK
304 dpp->inst,
305 s.igam_input_format,
306 (s.igam_lut_mode == 0) ? "BypassFixed" :
307 ((s.igam_lut_mode == 1) ? "BypassFloat" :
308 ((s.igam_lut_mode == 2) ? "RAM" :
309 ((s.igam_lut_mode == 3) ? "RAM" :
310 "Unknown"))),
311 (s.dgam_lut_mode == 0) ? "Bypass" :
312 ((s.dgam_lut_mode == 1) ? "sRGB" :
313 ((s.dgam_lut_mode == 2) ? "Ycc" :
314 ((s.dgam_lut_mode == 3) ? "RAM" :
315 ((s.dgam_lut_mode == 4) ? "RAM" :
316 "Unknown")))),
317 (s.rgam_lut_mode == 0) ? "Bypass" :
318 ((s.rgam_lut_mode == 1) ? "sRGB" :
319 ((s.rgam_lut_mode == 2) ? "Ycc" :
320 ((s.rgam_lut_mode == 3) ? "RAM" :
321 ((s.rgam_lut_mode == 4) ? "RAM" :
322 "Unknown")))),
323 s.gamut_remap_mode,
324 s.gamut_remap_c11_c12,
325 s.gamut_remap_c13_c14,
326 s.gamut_remap_c21_c22,
327 s.gamut_remap_c23_c24,
328 s.gamut_remap_c31_c32,
329 s.gamut_remap_c33_c34);
330 DTN_INFO("\n");
331 }
332 DTN_INFO("\n");
333
a052a516 334 DTN_INFO("MPCC: OPP DPP MPCCBOT MODE ALPHA_MODE PREMULT OVERLAP_ONLY IDLE\n");
dfd01f29 335 for (i = 0; i < pool->pipe_count; i++) {
dfd01f29
DL
336 struct mpcc_state s = {0};
337
a052a516 338 pool->mpc->funcs->read_mpcc_state(pool->mpc, i, &s);
1ba2faf2
DL
339 if (s.opp_id != 0xf)
340 DTN_INFO("[%2d]: %2xh %2xh %6xh %4d %10d %7d %12d %4d\n",
341 i, s.opp_id, s.dpp_id, s.bot_mpcc_id,
342 s.mode, s.alpha_mode, s.pre_multiplied_alpha, s.overlap_only,
343 s.idle);
dfd01f29
DL
344 }
345 DTN_INFO("\n");
71395011 346
ae8cf977 347 DTN_INFO("OTG: v_bs v_be v_ss v_se vpol vmax vmin vmax_sel vmin_sel h_bs h_be h_ss h_se hpol htot vtot underflow blank_en\n");
214435ff 348
3be1406a 349 for (i = 0; i < pool->timing_generator_count; i++) {
214435ff 350 struct timing_generator *tg = pool->timing_generators[i];
6f54d0b1 351 struct dcn_otg_state s = {0};
ae8cf977 352 /* Read shared OTG state registers for all DCNx */
40e045a9 353 optc1_read_otg_state(DCN10TG_FROM_TG(tg), &s);
214435ff 354
ae8cf977
LHM
355 /*
356 * For DCN2 and greater, a register on the OPP is used to
357 * determine if the CRTC is blanked instead of the OTG. So use
358 * dpg_is_blanked() if exists, otherwise fallback on otg.
359 *
360 * TODO: Implement DCN-specific read_otg_state hooks.
361 */
362 if (pool->opps[i]->funcs->dpg_is_blanked)
363 s.blank_enabled = pool->opps[i]->funcs->dpg_is_blanked(pool->opps[i]);
364 else
365 s.blank_enabled = tg->funcs->is_blanked(tg);
ae8cf977 366
6f54d0b1
LT
367 //only print if OTG master is enabled
368 if ((s.otg_enabled & 1) == 0)
369 continue;
370
ae8cf977 371 DTN_INFO("[%d]: %5d %5d %5d %5d %5d %5d %5d %9d %9d %5d %5d %5d %5d %5d %5d %5d %9d %8d\n",
3be1406a 372 tg->inst,
214435ff
CM
373 s.v_blank_start,
374 s.v_blank_end,
375 s.v_sync_a_start,
376 s.v_sync_a_end,
377 s.v_sync_a_pol,
378 s.v_total_max,
379 s.v_total_min,
01fe3e48
AK
380 s.v_total_max_sel,
381 s.v_total_min_sel,
214435ff
CM
382 s.h_blank_start,
383 s.h_blank_end,
384 s.h_sync_a_start,
385 s.h_sync_a_end,
386 s.h_sync_a_pol,
387 s.h_total,
388 s.v_total,
ae8cf977
LHM
389 s.underflow_occurred_status,
390 s.blank_enabled);
a944744b
NC
391
392 // Clear underflow for debug purposes
393 // We want to keep underflow sticky bit on for the longevity tests outside of test environment.
394 // This function is called only from Windows or Diags test environment, hence it's safe to clear
395 // it from here without affecting the original intent.
396 tg->funcs->clear_optc_underflow(tg);
214435ff
CM
397 }
398 DTN_INFO("\n");
399
91b2e45b
EB
400 // dcn_dsc_state struct field bytes_per_pixel was renamed to bits_per_pixel
401 // TODO: Update golden log header to reflect this name change
97bda032
HW
402 DTN_INFO("DSC: CLOCK_EN SLICE_WIDTH Bytes_pp\n");
403 for (i = 0; i < pool->res_cap->num_dsc; i++) {
404 struct display_stream_compressor *dsc = pool->dscs[i];
405 struct dcn_dsc_state s = {0};
406
407 dsc->funcs->dsc_read_state(dsc, &s);
408 DTN_INFO("[%d]: %-9d %-12d %-10d\n",
409 dsc->inst,
410 s.dsc_clock_en,
411 s.dsc_slice_width,
91b2e45b 412 s.dsc_bits_per_pixel);
97bda032
HW
413 DTN_INFO("\n");
414 }
415 DTN_INFO("\n");
416
417 DTN_INFO("S_ENC: DSC_MODE SEC_GSP7_LINE_NUM"
418 " VBID6_LINE_REFERENCE VBID6_LINE_NUM SEC_GSP7_ENABLE SEC_STREAM_ENABLE\n");
419 for (i = 0; i < pool->stream_enc_count; i++) {
420 struct stream_encoder *enc = pool->stream_enc[i];
421 struct enc_state s = {0};
422
423 if (enc->funcs->enc_read_state) {
424 enc->funcs->enc_read_state(enc, &s);
425 DTN_INFO("[%-3d]: %-9d %-18d %-21d %-15d %-16d %-17d\n",
426 enc->id,
427 s.dsc_mode,
bcba830c 428 s.sec_gsp_pps_line_num,
97bda032
HW
429 s.vbid6_line_reference,
430 s.vbid6_line_num,
bcba830c 431 s.sec_gsp_pps_enable,
97bda032
HW
432 s.sec_stream_enable);
433 DTN_INFO("\n");
434 }
435 }
436 DTN_INFO("\n");
437
ae8cf977 438 DTN_INFO("L_ENC: DPHY_FEC_EN DPHY_FEC_READY_SHADOW DPHY_FEC_ACTIVE_STATUS DP_LINK_TRAINING_COMPLETE\n");
97bda032
HW
439 for (i = 0; i < dc->link_count; i++) {
440 struct link_encoder *lenc = dc->links[i]->link_enc;
441
442 struct link_enc_state s = {0};
443
444 if (lenc->funcs->read_state) {
445 lenc->funcs->read_state(lenc, &s);
ae8cf977 446 DTN_INFO("[%-3d]: %-12d %-22d %-22d %-25d\n",
97bda032
HW
447 i,
448 s.dphy_fec_en,
449 s.dphy_fec_ready_shadow,
ae8cf977
LHM
450 s.dphy_fec_active_status,
451 s.dp_link_training_complete);
97bda032
HW
452 DTN_INFO("\n");
453 }
454 }
455 DTN_INFO("\n");
7ed4e635 456
a4765463
DL
457 DTN_INFO("\nCALCULATED Clocks: dcfclk_khz:%d dcfclk_deep_sleep_khz:%d dispclk_khz:%d\n"
458 "dppclk_khz:%d max_supported_dppclk_khz:%d fclk_khz:%d socclk_khz:%d\n\n",
813d20dc
AW
459 dc->current_state->bw_ctx.bw.dcn.clk.dcfclk_khz,
460 dc->current_state->bw_ctx.bw.dcn.clk.dcfclk_deep_sleep_khz,
461 dc->current_state->bw_ctx.bw.dcn.clk.dispclk_khz,
462 dc->current_state->bw_ctx.bw.dcn.clk.dppclk_khz,
463 dc->current_state->bw_ctx.bw.dcn.clk.max_supported_dppclk_khz,
464 dc->current_state->bw_ctx.bw.dcn.clk.fclk_khz,
465 dc->current_state->bw_ctx.bw.dcn.clk.socclk_khz);
0a93dc7f 466
46659a83 467 log_mpc_crc(dc, log_ctx);
71395011
TC
468
469 DTN_INFO_END();
470}
2b13d7d3 471
1a7d296d
TL
472bool dcn10_did_underflow_occur(struct dc *dc, struct pipe_ctx *pipe_ctx)
473{
474 struct hubp *hubp = pipe_ctx->plane_res.hubp;
475 struct timing_generator *tg = pipe_ctx->stream_res.tg;
476
477 if (tg->funcs->is_optc_underflow_occurred(tg)) {
478 tg->funcs->clear_optc_underflow(tg);
479 return true;
480 }
481
482 if (hubp->funcs->hubp_get_underflow_status(hubp)) {
483 hubp->funcs->hubp_clear_underflow(hubp);
484 return true;
485 }
486 return false;
487}
488
78c77382 489void dcn10_enable_power_gating_plane(
184debdb 490 struct dce_hwseq *hws,
70ccab60
HW
491 bool enable)
492{
0ee600a7 493 bool force_on = true; /* disable power gating */
70ccab60
HW
494
495 if (enable)
0ee600a7 496 force_on = false;
70ccab60
HW
497
498 /* DCHUBP0/1/2/3 */
184debdb
DL
499 REG_UPDATE(DOMAIN0_PG_CONFIG, DOMAIN0_POWER_FORCEON, force_on);
500 REG_UPDATE(DOMAIN2_PG_CONFIG, DOMAIN2_POWER_FORCEON, force_on);
501 REG_UPDATE(DOMAIN4_PG_CONFIG, DOMAIN4_POWER_FORCEON, force_on);
502 REG_UPDATE(DOMAIN6_PG_CONFIG, DOMAIN6_POWER_FORCEON, force_on);
70ccab60
HW
503
504 /* DPP0/1/2/3 */
184debdb
DL
505 REG_UPDATE(DOMAIN1_PG_CONFIG, DOMAIN1_POWER_FORCEON, force_on);
506 REG_UPDATE(DOMAIN3_PG_CONFIG, DOMAIN3_POWER_FORCEON, force_on);
507 REG_UPDATE(DOMAIN5_PG_CONFIG, DOMAIN5_POWER_FORCEON, force_on);
508 REG_UPDATE(DOMAIN7_PG_CONFIG, DOMAIN7_POWER_FORCEON, force_on);
70ccab60
HW
509}
510
78c77382 511void dcn10_disable_vga(
0a87425a
TC
512 struct dce_hwseq *hws)
513{
5e9a4f08
CZ
514 unsigned int in_vga1_mode = 0;
515 unsigned int in_vga2_mode = 0;
516 unsigned int in_vga3_mode = 0;
517 unsigned int in_vga4_mode = 0;
518
519 REG_GET(D1VGA_CONTROL, D1VGA_MODE_ENABLE, &in_vga1_mode);
520 REG_GET(D2VGA_CONTROL, D2VGA_MODE_ENABLE, &in_vga2_mode);
521 REG_GET(D3VGA_CONTROL, D3VGA_MODE_ENABLE, &in_vga3_mode);
522 REG_GET(D4VGA_CONTROL, D4VGA_MODE_ENABLE, &in_vga4_mode);
523
524 if (in_vga1_mode == 0 && in_vga2_mode == 0 &&
525 in_vga3_mode == 0 && in_vga4_mode == 0)
e18d3086
EY
526 return;
527
0a87425a 528 REG_WRITE(D1VGA_CONTROL, 0);
5e9a4f08
CZ
529 REG_WRITE(D2VGA_CONTROL, 0);
530 REG_WRITE(D3VGA_CONTROL, 0);
531 REG_WRITE(D4VGA_CONTROL, 0);
90e3103e
BL
532
533 /* HW Engineer's Notes:
534 * During switch from vga->extended, if we set the VGA_TEST_ENABLE and
535 * then hit the VGA_TEST_RENDER_START, then the DCHUBP timing gets updated correctly.
536 *
537 * Then vBIOS will have it poll for the VGA_TEST_RENDER_DONE and unset
538 * VGA_TEST_ENABLE, to leave it in the same state as before.
539 */
540 REG_UPDATE(VGA_TEST_CONTROL, VGA_TEST_ENABLE, 1);
541 REG_UPDATE(VGA_TEST_CONTROL, VGA_TEST_RENDER_START, 1);
0a87425a
TC
542}
543
23344703
RS
544/**
545 * dcn10_dpp_pg_control - DPP power gate control.
546 *
547 * @hws: dce_hwseq reference.
548 * @dpp_inst: DPP instance reference.
549 * @power_on: true if we want to enable power gate, false otherwise.
550 *
551 * Enable or disable power gate in the specific DPP instance.
552 */
78c77382 553void dcn10_dpp_pg_control(
184debdb 554 struct dce_hwseq *hws,
70ccab60
HW
555 unsigned int dpp_inst,
556 bool power_on)
557{
70ccab60 558 uint32_t power_gate = power_on ? 0 : 1;
23344703 559 uint32_t pwr_status = power_on ? PGFSM_POWER_ON : PGFSM_POWER_OFF;
70ccab60 560
184debdb 561 if (hws->ctx->dc->debug.disable_dpp_power_gate)
70ccab60 562 return;
7f93c1de
CL
563 if (REG(DOMAIN1_PG_CONFIG) == 0)
564 return;
70ccab60
HW
565
566 switch (dpp_inst) {
567 case 0: /* DPP0 */
184debdb 568 REG_UPDATE(DOMAIN1_PG_CONFIG,
70ccab60
HW
569 DOMAIN1_POWER_GATE, power_gate);
570
184debdb 571 REG_WAIT(DOMAIN1_PG_STATUS,
8a5d8245
TC
572 DOMAIN1_PGFSM_PWR_STATUS, pwr_status,
573 1, 1000);
70ccab60
HW
574 break;
575 case 1: /* DPP1 */
184debdb 576 REG_UPDATE(DOMAIN3_PG_CONFIG,
70ccab60
HW
577 DOMAIN3_POWER_GATE, power_gate);
578
184debdb 579 REG_WAIT(DOMAIN3_PG_STATUS,
8a5d8245
TC
580 DOMAIN3_PGFSM_PWR_STATUS, pwr_status,
581 1, 1000);
70ccab60
HW
582 break;
583 case 2: /* DPP2 */
184debdb 584 REG_UPDATE(DOMAIN5_PG_CONFIG,
70ccab60
HW
585 DOMAIN5_POWER_GATE, power_gate);
586
184debdb 587 REG_WAIT(DOMAIN5_PG_STATUS,
8a5d8245
TC
588 DOMAIN5_PGFSM_PWR_STATUS, pwr_status,
589 1, 1000);
70ccab60
HW
590 break;
591 case 3: /* DPP3 */
184debdb 592 REG_UPDATE(DOMAIN7_PG_CONFIG,
70ccab60
HW
593 DOMAIN7_POWER_GATE, power_gate);
594
184debdb 595 REG_WAIT(DOMAIN7_PG_STATUS,
8a5d8245
TC
596 DOMAIN7_PGFSM_PWR_STATUS, pwr_status,
597 1, 1000);
70ccab60
HW
598 break;
599 default:
600 BREAK_TO_DEBUGGER();
601 break;
602 }
603}
604
23344703
RS
605/**
606 * dcn10_hubp_pg_control - HUBP power gate control.
607 *
608 * @hws: dce_hwseq reference.
609 * @hubp_inst: DPP instance reference.
610 * @power_on: true if we want to enable power gate, false otherwise.
611 *
612 * Enable or disable power gate in the specific HUBP instance.
613 */
78c77382 614void dcn10_hubp_pg_control(
184debdb 615 struct dce_hwseq *hws,
70ccab60
HW
616 unsigned int hubp_inst,
617 bool power_on)
618{
70ccab60 619 uint32_t power_gate = power_on ? 0 : 1;
23344703 620 uint32_t pwr_status = power_on ? PGFSM_POWER_ON : PGFSM_POWER_OFF;
70ccab60 621
184debdb 622 if (hws->ctx->dc->debug.disable_hubp_power_gate)
70ccab60 623 return;
7f93c1de
CL
624 if (REG(DOMAIN0_PG_CONFIG) == 0)
625 return;
70ccab60
HW
626
627 switch (hubp_inst) {
628 case 0: /* DCHUBP0 */
184debdb 629 REG_UPDATE(DOMAIN0_PG_CONFIG,
70ccab60
HW
630 DOMAIN0_POWER_GATE, power_gate);
631
184debdb 632 REG_WAIT(DOMAIN0_PG_STATUS,
8a5d8245
TC
633 DOMAIN0_PGFSM_PWR_STATUS, pwr_status,
634 1, 1000);
70ccab60
HW
635 break;
636 case 1: /* DCHUBP1 */
184debdb 637 REG_UPDATE(DOMAIN2_PG_CONFIG,
70ccab60
HW
638 DOMAIN2_POWER_GATE, power_gate);
639
184debdb 640 REG_WAIT(DOMAIN2_PG_STATUS,
8a5d8245
TC
641 DOMAIN2_PGFSM_PWR_STATUS, pwr_status,
642 1, 1000);
70ccab60
HW
643 break;
644 case 2: /* DCHUBP2 */
184debdb 645 REG_UPDATE(DOMAIN4_PG_CONFIG,
70ccab60
HW
646 DOMAIN4_POWER_GATE, power_gate);
647
184debdb 648 REG_WAIT(DOMAIN4_PG_STATUS,
8a5d8245
TC
649 DOMAIN4_PGFSM_PWR_STATUS, pwr_status,
650 1, 1000);
70ccab60
HW
651 break;
652 case 3: /* DCHUBP3 */
184debdb 653 REG_UPDATE(DOMAIN6_PG_CONFIG,
70ccab60
HW
654 DOMAIN6_POWER_GATE, power_gate);
655
184debdb 656 REG_WAIT(DOMAIN6_PG_STATUS,
8a5d8245
TC
657 DOMAIN6_PGFSM_PWR_STATUS, pwr_status,
658 1, 1000);
70ccab60
HW
659 break;
660 default:
661 BREAK_TO_DEBUGGER();
662 break;
663 }
664}
665
666static void power_on_plane(
184debdb 667 struct dce_hwseq *hws,
cfe4645e 668 int plane_id)
70ccab60 669{
5d4b05dd 670 DC_LOGGER_INIT(hws->ctx->logger);
5df921d4
KC
671 if (REG(DC_IP_REQUEST_CNTL)) {
672 REG_SET(DC_IP_REQUEST_CNTL, 0,
673 IP_REQUEST_EN, 1);
d2138be3
NK
674
675 if (hws->funcs.dpp_pg_control)
676 hws->funcs.dpp_pg_control(hws, plane_id, true);
677
678 if (hws->funcs.hubp_pg_control)
679 hws->funcs.hubp_pg_control(hws, plane_id, true);
680
5df921d4
KC
681 REG_SET(DC_IP_REQUEST_CNTL, 0,
682 IP_REQUEST_EN, 0);
1296423b 683 DC_LOG_DEBUG(
5df921d4
KC
684 "Un-gated front end for pipe %d\n", plane_id);
685 }
70ccab60
HW
686}
687
41f97c07
HW
688static void undo_DEGVIDCN10_253_wa(struct dc *dc)
689{
690 struct dce_hwseq *hws = dc->hwseq;
8feabd03 691 struct hubp *hubp = dc->res_pool->hubps[0];
c9bb686b 692
7f914a62 693 if (!hws->wa_state.DEGVIDCN10_253_applied)
c9bb686b 694 return;
41f97c07 695
8feabd03 696 hubp->funcs->set_blank(hubp, true);
41f97c07
HW
697
698 REG_SET(DC_IP_REQUEST_CNTL, 0,
699 IP_REQUEST_EN, 1);
700
f42ea55b 701 hws->funcs.hubp_pg_control(hws, 0, false);
41f97c07
HW
702 REG_SET(DC_IP_REQUEST_CNTL, 0,
703 IP_REQUEST_EN, 0);
7f914a62
YS
704
705 hws->wa_state.DEGVIDCN10_253_applied = false;
41f97c07
HW
706}
707
41f97c07
HW
708static void apply_DEGVIDCN10_253_wa(struct dc *dc)
709{
710 struct dce_hwseq *hws = dc->hwseq;
8feabd03 711 struct hubp *hubp = dc->res_pool->hubps[0];
7f914a62 712 int i;
41f97c07 713
6bf52028
HW
714 if (dc->debug.disable_stutter)
715 return;
716
7f914a62
YS
717 if (!hws->wa.DEGVIDCN10_253)
718 return;
719
720 for (i = 0; i < dc->res_pool->pipe_count; i++) {
721 if (!dc->res_pool->hubps[i]->power_gated)
722 return;
723 }
724
725 /* all pipe power gated, apply work around to enable stutter. */
726
41f97c07
HW
727 REG_SET(DC_IP_REQUEST_CNTL, 0,
728 IP_REQUEST_EN, 1);
729
f42ea55b 730 hws->funcs.hubp_pg_control(hws, 0, true);
41f97c07
HW
731 REG_SET(DC_IP_REQUEST_CNTL, 0,
732 IP_REQUEST_EN, 0);
733
8feabd03 734 hubp->funcs->set_hubp_blank_en(hubp, false);
7f914a62 735 hws->wa_state.DEGVIDCN10_253_applied = true;
41f97c07
HW
736}
737
78c77382 738void dcn10_bios_golden_init(struct dc *dc)
70ccab60 739{
f42ea55b 740 struct dce_hwseq *hws = dc->hwseq;
70ccab60
HW
741 struct dc_bios *bp = dc->ctx->dc_bios;
742 int i;
8a31820b
ML
743 bool allow_self_fresh_force_enable = true;
744
f42ea55b 745 if (hws->funcs.s0i3_golden_init_wa && hws->funcs.s0i3_golden_init_wa(dc))
c0fb59a4 746 return;
f42ea55b 747
8a31820b
ML
748 if (dc->res_pool->hubbub->funcs->is_allow_self_refresh_enabled)
749 allow_self_fresh_force_enable =
750 dc->res_pool->hubbub->funcs->is_allow_self_refresh_enabled(dc->res_pool->hubbub);
751
752
753 /* WA for making DF sleep when idle after resume from S0i3.
754 * DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE is set to 1 by
755 * command table, if DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE = 0
756 * before calling command table and it changed to 1 after,
757 * it should be set back to 0.
758 */
70ccab60
HW
759
760 /* initialize dcn global */
761 bp->funcs->enable_disp_power_gating(bp,
762 CONTROLLER_ID_D0, ASIC_PIPE_INIT);
763
764 for (i = 0; i < dc->res_pool->pipe_count; i++) {
765 /* initialize dcn per pipe */
766 bp->funcs->enable_disp_power_gating(bp,
767 CONTROLLER_ID_D0 + i, ASIC_PIPE_DISABLE);
768 }
8a31820b
ML
769
770 if (dc->res_pool->hubbub->funcs->allow_self_refresh_control)
771 if (allow_self_fresh_force_enable == false &&
772 dc->res_pool->hubbub->funcs->is_allow_self_refresh_enabled(dc->res_pool->hubbub))
087a1ff8
HW
773 dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub,
774 !dc->res_pool->hubbub->ctx->dc->debug.disable_stutter);
8a31820b 775
70ccab60
HW
776}
777
5cc2687c
YS
778static void false_optc_underflow_wa(
779 struct dc *dc,
780 const struct dc_stream_state *stream,
781 struct timing_generator *tg)
782{
783 int i;
784 bool underflow;
785
786 if (!dc->hwseq->wa.false_optc_underflow)
787 return;
788
789 underflow = tg->funcs->is_optc_underflow_occurred(tg);
790
791 for (i = 0; i < dc->res_pool->pipe_count; i++) {
792 struct pipe_ctx *old_pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i];
793
794 if (old_pipe_ctx->stream != stream)
795 continue;
796
797 dc->hwss.wait_for_mpcc_disconnect(dc, dc->res_pool, old_pipe_ctx);
798 }
799
90830e84
VP
800 if (tg->funcs->set_blank_data_double_buffer)
801 tg->funcs->set_blank_data_double_buffer(tg, true);
5cc2687c
YS
802
803 if (tg->funcs->is_optc_underflow_occurred(tg) && !underflow)
804 tg->funcs->clear_optc_underflow(tg);
805}
806
78c77382 807enum dc_status dcn10_enable_stream_timing(
70ccab60 808 struct pipe_ctx *pipe_ctx,
608ac7bb 809 struct dc_state *context,
fb3466a4 810 struct dc *dc)
70ccab60 811{
0971c40e 812 struct dc_stream_state *stream = pipe_ctx->stream;
70ccab60
HW
813 enum dc_color_space color_space;
814 struct tg_color black_color = {0};
70ccab60 815
70ccab60
HW
816 /* by upper caller loop, pipe0 is parent pipe and be called first.
817 * back end is set up by for pipe0. Other children pipe share back end
818 * with pipe 0. No program is needed.
819 */
820 if (pipe_ctx->top_pipe != NULL)
821 return DC_OK;
822
823 /* TODO check if timing_changed, disable stream if timing changed */
824
825 /* HW program guide assume display already disable
826 * by unplug sequence. OTG assume stop.
827 */
6b670fa9 828 pipe_ctx->stream_res.tg->funcs->enable_optc_clock(pipe_ctx->stream_res.tg, true);
70ccab60
HW
829
830 if (false == pipe_ctx->clock_source->funcs->program_pix_clk(
831 pipe_ctx->clock_source,
10688217 832 &pipe_ctx->stream_res.pix_clk_params,
70ccab60
HW
833 &pipe_ctx->pll_settings)) {
834 BREAK_TO_DEBUGGER();
835 return DC_ERROR_UNEXPECTED;
836 }
70ccab60 837
6b670fa9
HW
838 pipe_ctx->stream_res.tg->funcs->program_timing(
839 pipe_ctx->stream_res.tg,
4fa086b9 840 &stream->timing,
e7e10c46
DL
841 pipe_ctx->pipe_dlg_param.vready_offset,
842 pipe_ctx->pipe_dlg_param.vstartup_start,
843 pipe_ctx->pipe_dlg_param.vupdate_offset,
844 pipe_ctx->pipe_dlg_param.vupdate_width,
845 pipe_ctx->stream->signal,
70ccab60
HW
846 true);
847
70ccab60
HW
848#if 0 /* move to after enable_crtc */
849 /* TODO: OPP FMT, ABM. etc. should be done here. */
850 /* or FPGA now. instance 0 only. TODO: move to opp.c */
851
6b670fa9 852 inst_offset = reg_offsets[pipe_ctx->stream_res.tg->inst].fmt;
70ccab60 853
a6a6cb34
HW
854 pipe_ctx->stream_res.opp->funcs->opp_program_fmt(
855 pipe_ctx->stream_res.opp,
70ccab60
HW
856 &stream->bit_depth_params,
857 &stream->clamping);
858#endif
859 /* program otg blank color */
4fa086b9 860 color_space = stream->output_color_space;
70ccab60 861 color_space_to_black_color(dc, color_space, &black_color);
70ccab60 862
e0a3794d 863 /*
864 * The way 420 is packed, 2 channels carry Y component, 1 channel
865 * alternate between Cb and Cr, so both channels need the pixel
866 * value for Y
867 */
868 if (stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR420)
869 black_color.color_r_cr = black_color.color_g_y;
870
b51adc77
YHL
871 if (pipe_ctx->stream_res.tg->funcs->set_blank_color)
872 pipe_ctx->stream_res.tg->funcs->set_blank_color(
873 pipe_ctx->stream_res.tg,
874 &black_color);
875
876 if (pipe_ctx->stream_res.tg->funcs->is_blanked &&
877 !pipe_ctx->stream_res.tg->funcs->is_blanked(pipe_ctx->stream_res.tg)) {
5cc2687c
YS
878 pipe_ctx->stream_res.tg->funcs->set_blank(pipe_ctx->stream_res.tg, true);
879 hwss_wait_for_blank_complete(pipe_ctx->stream_res.tg);
880 false_optc_underflow_wa(dc, pipe_ctx->stream, pipe_ctx->stream_res.tg);
881 }
70ccab60
HW
882
883 /* VTG is within DCHUB command block. DCFCLK is always on */
6b670fa9 884 if (false == pipe_ctx->stream_res.tg->funcs->enable_crtc(pipe_ctx->stream_res.tg)) {
70ccab60
HW
885 BREAK_TO_DEBUGGER();
886 return DC_ERROR_UNEXPECTED;
887 }
888
889 /* TODO program crtc source select for non-virtual signal*/
890 /* TODO program FMT */
891 /* TODO setup link_enc */
892 /* TODO set stream attributes */
893 /* TODO program audio */
894 /* TODO enable stream if timing changed */
895 /* TODO unblank stream if DP */
896
897 return DC_OK;
898}
899
4a797d24 900static void dcn10_reset_back_end_for_pipe(
fb3466a4 901 struct dc *dc,
70ccab60 902 struct pipe_ctx *pipe_ctx,
608ac7bb 903 struct dc_state *context)
70ccab60
HW
904{
905 int i;
efca0905 906 struct dc_link *link;
5d4b05dd 907 DC_LOGGER_INIT(dc->ctx->logger);
8e9c4c8c 908 if (pipe_ctx->stream_res.stream_enc == NULL) {
70ccab60
HW
909 pipe_ctx->stream = NULL;
910 return;
911 }
912
d050f8ed 913 if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
efca0905
PH
914 link = pipe_ctx->stream->link;
915 /* DPMS may already disable or */
916 /* dpms_off status is incorrect due to fastboot
917 * feature. When system resume from S4 with second
918 * screen only, the dpms_off would be true but
919 * VBIOS lit up eDP, so check link status too.
920 */
921 if (!pipe_ctx->stream->dpms_off || link->link_status.link_active)
57430404
SSC
922 core_link_disable_stream(pipe_ctx);
923 else if (pipe_ctx->stream_res.audio)
924 dc->hwss.disable_audio_stream(pipe_ctx);
925
926 if (pipe_ctx->stream_res.audio) {
927 /*disable az_endpoint*/
928 pipe_ctx->stream_res.audio->funcs->az_disable(pipe_ctx->stream_res.audio);
929
930 /*free audio*/
931 if (dc->caps.dynamic_audio == true) {
932 /*we have to dynamic arbitrate the audio endpoints*/
933 /*we free the resource, need reset is_audio_acquired*/
934 update_audio_usage(&dc->current_state->res_ctx, dc->res_pool,
935 pipe_ctx->stream_res.audio, false);
936 pipe_ctx->stream_res.audio = NULL;
937 }
ea7ea2a8 938 }
d050f8ed 939 }
70ccab60
HW
940
941 /* by upper caller loop, parent pipe: pipe0, will be reset last.
942 * back end share by all pipes and will be disable only when disable
943 * parent pipe.
944 */
945 if (pipe_ctx->top_pipe == NULL) {
9edf202d
JZ
946
947 if (pipe_ctx->stream_res.abm)
3ba01817 948 dc->hwss.set_abm_immediate_disable(pipe_ctx);
9edf202d 949
6b670fa9 950 pipe_ctx->stream_res.tg->funcs->disable_crtc(pipe_ctx->stream_res.tg);
70ccab60 951
6b670fa9 952 pipe_ctx->stream_res.tg->funcs->enable_optc_clock(pipe_ctx->stream_res.tg, false);
38df0701
WL
953 if (pipe_ctx->stream_res.tg->funcs->set_drr)
954 pipe_ctx->stream_res.tg->funcs->set_drr(
955 pipe_ctx->stream_res.tg, NULL);
70ccab60
HW
956 }
957
70ccab60 958 for (i = 0; i < dc->res_pool->pipe_count; i++)
608ac7bb 959 if (&dc->current_state->res_ctx.pipe_ctx[i] == pipe_ctx)
70ccab60
HW
960 break;
961
962 if (i == dc->res_pool->pipe_count)
963 return;
964
965 pipe_ctx->stream = NULL;
1296423b 966 DC_LOG_DEBUG("Reset back end for pipe %d, tg:%d\n",
6b670fa9 967 pipe_ctx->pipe_idx, pipe_ctx->stream_res.tg->inst);
70ccab60
HW
968}
969
3ba43a59
CL
970static bool dcn10_hw_wa_force_recovery(struct dc *dc)
971{
972 struct hubp *hubp ;
973 unsigned int i;
974 bool need_recover = true;
975
976 if (!dc->debug.recovery_enabled)
977 return false;
978
979 for (i = 0; i < dc->res_pool->pipe_count; i++) {
980 struct pipe_ctx *pipe_ctx =
981 &dc->current_state->res_ctx.pipe_ctx[i];
982 if (pipe_ctx != NULL) {
983 hubp = pipe_ctx->plane_res.hubp;
95022795 984 if (hubp != NULL && hubp->funcs->hubp_get_underflow_status) {
3ba43a59
CL
985 if (hubp->funcs->hubp_get_underflow_status(hubp) != 0) {
986 /* one pipe underflow, we will reset all the pipes*/
987 need_recover = true;
988 }
989 }
990 }
991 }
992 if (!need_recover)
993 return false;
994 /*
995 DCHUBP_CNTL:HUBP_BLANK_EN=1
996 DCHUBBUB_SOFT_RESET:DCHUBBUB_GLOBAL_SOFT_RESET=1
997 DCHUBP_CNTL:HUBP_DISABLE=1
998 DCHUBP_CNTL:HUBP_DISABLE=0
999 DCHUBBUB_SOFT_RESET:DCHUBBUB_GLOBAL_SOFT_RESET=0
1000 DCSURF_PRIMARY_SURFACE_ADDRESS
1001 DCHUBP_CNTL:HUBP_BLANK_EN=0
1002 */
1003
1004 for (i = 0; i < dc->res_pool->pipe_count; i++) {
1005 struct pipe_ctx *pipe_ctx =
1006 &dc->current_state->res_ctx.pipe_ctx[i];
1007 if (pipe_ctx != NULL) {
1008 hubp = pipe_ctx->plane_res.hubp;
1009 /*DCHUBP_CNTL:HUBP_BLANK_EN=1*/
95022795 1010 if (hubp != NULL && hubp->funcs->set_hubp_blank_en)
3ba43a59
CL
1011 hubp->funcs->set_hubp_blank_en(hubp, true);
1012 }
1013 }
1014 /*DCHUBBUB_SOFT_RESET:DCHUBBUB_GLOBAL_SOFT_RESET=1*/
1015 hubbub1_soft_reset(dc->res_pool->hubbub, true);
1016
1017 for (i = 0; i < dc->res_pool->pipe_count; i++) {
1018 struct pipe_ctx *pipe_ctx =
1019 &dc->current_state->res_ctx.pipe_ctx[i];
1020 if (pipe_ctx != NULL) {
1021 hubp = pipe_ctx->plane_res.hubp;
1022 /*DCHUBP_CNTL:HUBP_DISABLE=1*/
95022795 1023 if (hubp != NULL && hubp->funcs->hubp_disable_control)
3ba43a59
CL
1024 hubp->funcs->hubp_disable_control(hubp, true);
1025 }
1026 }
1027 for (i = 0; i < dc->res_pool->pipe_count; i++) {
1028 struct pipe_ctx *pipe_ctx =
1029 &dc->current_state->res_ctx.pipe_ctx[i];
1030 if (pipe_ctx != NULL) {
1031 hubp = pipe_ctx->plane_res.hubp;
1032 /*DCHUBP_CNTL:HUBP_DISABLE=0*/
95022795 1033 if (hubp != NULL && hubp->funcs->hubp_disable_control)
3ba43a59
CL
1034 hubp->funcs->hubp_disable_control(hubp, true);
1035 }
1036 }
1037 /*DCHUBBUB_SOFT_RESET:DCHUBBUB_GLOBAL_SOFT_RESET=0*/
1038 hubbub1_soft_reset(dc->res_pool->hubbub, false);
1039 for (i = 0; i < dc->res_pool->pipe_count; i++) {
1040 struct pipe_ctx *pipe_ctx =
1041 &dc->current_state->res_ctx.pipe_ctx[i];
1042 if (pipe_ctx != NULL) {
1043 hubp = pipe_ctx->plane_res.hubp;
1044 /*DCHUBP_CNTL:HUBP_BLANK_EN=0*/
95022795 1045 if (hubp != NULL && hubp->funcs->set_hubp_blank_en)
3ba43a59
CL
1046 hubp->funcs->set_hubp_blank_en(hubp, true);
1047 }
1048 }
1049 return true;
1050
1051}
1052
c2437b1f 1053void dcn10_verify_allow_pstate_change_high(struct dc *dc)
ea00f297 1054{
f042c330 1055 struct hubbub *hubbub = dc->res_pool->hubbub;
ea00f297
YHL
1056 static bool should_log_hw_state; /* prevent hw state log by default */
1057
f042c330
NK
1058 if (!hubbub->funcs->verify_allow_pstate_change_high)
1059 return;
1060
1061 if (!hubbub->funcs->verify_allow_pstate_change_high(hubbub)) {
8b198f6e
RS
1062 int i = 0;
1063
1064 if (should_log_hw_state)
46659a83 1065 dcn10_log_hw_state(dc, NULL);
8b198f6e
RS
1066
1067 TRACE_DC_PIPE_STATE(pipe_ctx, i, MAX_PIPES);
ea00f297 1068 BREAK_TO_DEBUGGER();
3ba43a59 1069 if (dcn10_hw_wa_force_recovery(dc)) {
f042c330
NK
1070 /*check again*/
1071 if (!hubbub->funcs->verify_allow_pstate_change_high(hubbub))
3ba43a59
CL
1072 BREAK_TO_DEBUGGER();
1073 }
ea00f297
YHL
1074 }
1075}
1076
a74b2734 1077/* trigger HW to start disconnect plane from stream on the next vsync */
78c77382 1078void dcn10_plane_atomic_disconnect(struct dc *dc, struct pipe_ctx *pipe_ctx)
70ccab60 1079{
f42ea55b 1080 struct dce_hwseq *hws = dc->hwseq;
e07f541f
YS
1081 struct hubp *hubp = pipe_ctx->plane_res.hubp;
1082 int dpp_id = pipe_ctx->plane_res.dpp->inst;
cc408d72 1083 struct mpc *mpc = dc->res_pool->mpc;
feb4a3cd
EB
1084 struct mpc_tree *mpc_tree_params;
1085 struct mpcc *mpcc_to_remove = NULL;
365acbaf 1086 struct output_pixel_processor *opp = pipe_ctx->stream_res.opp;
cc408d72 1087
365acbaf
YS
1088 mpc_tree_params = &(opp->mpc_tree_params);
1089 mpcc_to_remove = mpc->funcs->get_mpcc_for_dpp(mpc_tree_params, dpp_id);
feb4a3cd 1090
a74b2734 1091 /*Already reset*/
365acbaf 1092 if (mpcc_to_remove == NULL)
a74b2734 1093 return;
70ccab60 1094
feb4a3cd 1095 mpc->funcs->remove_mpcc(mpc, mpc_tree_params, mpcc_to_remove);
7f93c1de
CL
1096 if (opp != NULL)
1097 opp->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true;
e6c258cb 1098
0aa63a33 1099 dc->optimized_required = true;
82c026d1 1100
e6c258cb
YS
1101 if (hubp->funcs->hubp_disconnect)
1102 hubp->funcs->hubp_disconnect(hubp);
1103
fb3466a4 1104 if (dc->debug.sanity_checks)
f42ea55b 1105 hws->funcs.verify_allow_pstate_change_high(dc);
d65359d5
TC
1106}
1107
23344703
RS
1108/**
1109 * dcn10_plane_atomic_power_down - Power down plane components.
1110 *
1111 * @dc: dc struct reference. used for grab hwseq.
1112 * @dpp: dpp struct reference.
1113 * @hubp: hubp struct reference.
1114 *
1115 * Keep in mind that this operation requires a power gate configuration;
1116 * however, requests for switch power gate are precisely controlled to avoid
1117 * problems. For this reason, power gate request is usually disabled. This
1118 * function first needs to enable the power gate request before disabling DPP
1119 * and HUBP. Finally, it disables the power gate request again.
1120 */
78c77382 1121void dcn10_plane_atomic_power_down(struct dc *dc,
522f82f3
AK
1122 struct dpp *dpp,
1123 struct hubp *hubp)
a74b2734
TC
1124{
1125 struct dce_hwseq *hws = dc->hwseq;
5d4b05dd 1126 DC_LOGGER_INIT(dc->ctx->logger);
a74b2734 1127
e6c258cb
YS
1128 if (REG(DC_IP_REQUEST_CNTL)) {
1129 REG_SET(DC_IP_REQUEST_CNTL, 0,
1130 IP_REQUEST_EN, 1);
d2138be3
NK
1131
1132 if (hws->funcs.dpp_pg_control)
1133 hws->funcs.dpp_pg_control(hws, dpp->inst, false);
1134
1135 if (hws->funcs.hubp_pg_control)
1136 hws->funcs.hubp_pg_control(hws, hubp->inst, false);
1137
e6c258cb
YS
1138 dpp->funcs->dpp_reset(dpp);
1139 REG_SET(DC_IP_REQUEST_CNTL, 0,
1140 IP_REQUEST_EN, 0);
1296423b 1141 DC_LOG_DEBUG(
522f82f3 1142 "Power gated front end %d\n", hubp->inst);
e6c258cb
YS
1143 }
1144}
a74b2734 1145
7f914a62
YS
1146/* disable HW used by plane.
1147 * note: cannot disable until disconnect is complete
1148 */
78c77382 1149void dcn10_plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx)
e6c258cb 1150{
f42ea55b 1151 struct dce_hwseq *hws = dc->hwseq;
e07f541f 1152 struct hubp *hubp = pipe_ctx->plane_res.hubp;
f8e413bf 1153 struct dpp *dpp = pipe_ctx->plane_res.dpp;
7f914a62 1154 int opp_id = hubp->opp_id;
a74b2734 1155
1ccda80f 1156 dc->hwss.wait_for_mpcc_disconnect(dc, dc->res_pool, pipe_ctx);
a74b2734 1157
c8242b98
YS
1158 hubp->funcs->hubp_clk_cntl(hubp, false);
1159
f8e413bf 1160 dpp->funcs->dpp_dppclk_control(dpp, false, false);
a74b2734 1161
2e9d6a57 1162 if (opp_id != 0xf && pipe_ctx->stream_res.opp->mpc_tree_params.opp_list == NULL)
be2f449a
YS
1163 pipe_ctx->stream_res.opp->funcs->opp_pipe_clock_control(
1164 pipe_ctx->stream_res.opp,
1165 false);
e6c258cb 1166
7f914a62 1167 hubp->power_gated = true;
0aa63a33 1168 dc->optimized_required = false; /* We're powering off, no need to optimize */
a74b2734 1169
f42ea55b 1170 hws->funcs.plane_atomic_power_down(dc,
522f82f3
AK
1171 pipe_ctx->plane_res.dpp,
1172 pipe_ctx->plane_res.hubp);
1ccda80f
YS
1173
1174 pipe_ctx->stream = NULL;
1175 memset(&pipe_ctx->stream_res, 0, sizeof(pipe_ctx->stream_res));
1176 memset(&pipe_ctx->plane_res, 0, sizeof(pipe_ctx->plane_res));
1177 pipe_ctx->top_pipe = NULL;
1178 pipe_ctx->bottom_pipe = NULL;
1179 pipe_ctx->plane_state = NULL;
7f914a62
YS
1180}
1181
78c77382 1182void dcn10_disable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx)
7f914a62 1183{
f42ea55b 1184 struct dce_hwseq *hws = dc->hwseq;
5d4b05dd 1185 DC_LOGGER_INIT(dc->ctx->logger);
1296423b 1186
24a30505 1187 if (!pipe_ctx->plane_res.hubp || pipe_ctx->plane_res.hubp->power_gated)
7f914a62
YS
1188 return;
1189
f42ea55b 1190 hws->funcs.plane_atomic_disable(dc, pipe_ctx);
7f914a62
YS
1191
1192 apply_DEGVIDCN10_253_wa(dc);
a74b2734 1193
1296423b 1194 DC_LOG_DC("Power down front end %d\n",
7f914a62 1195 pipe_ctx->pipe_idx);
a74b2734
TC
1196}
1197
78c77382 1198void dcn10_init_pipes(struct dc *dc, struct dc_state *context)
7a5086a7 1199{
4e1c1875 1200 int i;
f42ea55b 1201 struct dce_hwseq *hws = dc->hwseq;
ce72741b
AK
1202 bool can_apply_seamless_boot = false;
1203
1204 for (i = 0; i < context->stream_count; i++) {
1205 if (context->streams[i]->apply_seamless_boot_optimization) {
1206 can_apply_seamless_boot = true;
1207 break;
1208 }
1209 }
7a5086a7
YS
1210
1211 for (i = 0; i < dc->res_pool->pipe_count; i++) {
7a5086a7 1212 struct timing_generator *tg = dc->res_pool->timing_generators[i];
ce72741b
AK
1213 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
1214
1215 /* There is assumption that pipe_ctx is not mapping irregularly
1216 * to non-preferred front end. If pipe_ctx->stream is not NULL,
1217 * we will use the pipe, so don't disable
1218 */
d5ca5fdb 1219 if (pipe_ctx->stream != NULL && can_apply_seamless_boot)
ce72741b 1220 continue;
7a5086a7 1221
fb55546e
AK
1222 /* Blank controller using driver code instead of
1223 * command table.
1224 */
0af4096d 1225 if (tg->funcs->is_tg_enabled(tg)) {
f42ea55b
AK
1226 if (hws->funcs.init_blank != NULL) {
1227 hws->funcs.init_blank(dc, tg);
8a31820b
ML
1228 tg->funcs->lock(tg);
1229 } else {
1230 tg->funcs->lock(tg);
1231 tg->funcs->set_blank(tg, true);
1232 hwss_wait_for_blank_complete(tg);
1233 }
0af4096d
YS
1234 }
1235 }
7a5086a7 1236
1380c1bf
NA
1237 /* num_opp will be equal to number of mpcc */
1238 for (i = 0; i < dc->res_pool->res_cap->num_opp; i++) {
5ec43eda
ML
1239 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
1240
1241 /* Cannot reset the MPC mux if seamless boot */
1242 if (pipe_ctx->stream != NULL && can_apply_seamless_boot)
1243 continue;
1244
1245 dc->res_pool->mpc->funcs->mpc_init_single_inst(
1246 dc->res_pool->mpc, i);
1247 }
feb4a3cd 1248
fb55546e 1249 for (i = 0; i < dc->res_pool->pipe_count; i++) {
0af4096d 1250 struct timing_generator *tg = dc->res_pool->timing_generators[i];
621fd3e3 1251 struct hubp *hubp = dc->res_pool->hubps[i];
e07f541f 1252 struct dpp *dpp = dc->res_pool->dpps[i];
fb55546e
AK
1253 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
1254
ce72741b
AK
1255 /* There is assumption that pipe_ctx is not mapping irregularly
1256 * to non-preferred front end. If pipe_ctx->stream is not NULL,
1257 * we will use the pipe, so don't disable
1258 */
46570f09
AK
1259 if (can_apply_seamless_boot &&
1260 pipe_ctx->stream != NULL &&
1261 pipe_ctx->stream_res.tg->funcs->is_tg_enabled(
9f21f379
AL
1262 pipe_ctx->stream_res.tg)) {
1263 // Enable double buffering for OTG_BLANK no matter if
1264 // seamless boot is enabled or not to suppress global sync
1265 // signals when OTG blanked. This is to prevent pipe from
1266 // requesting data while in PSR.
1267 tg->funcs->tg_init(tg);
accff74e 1268 hubp->power_gated = true;
ce72741b 1269 continue;
9f21f379 1270 }
ce72741b 1271
4bc46da4
NK
1272 /* Disable on the current state so the new one isn't cleared. */
1273 pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i];
1274
fb55546e 1275 dpp->funcs->dpp_reset(dpp);
621fd3e3 1276
0af4096d
YS
1277 pipe_ctx->stream_res.tg = tg;
1278 pipe_ctx->pipe_idx = i;
621fd3e3
AJ
1279
1280 pipe_ctx->plane_res.hubp = hubp;
e07f541f
YS
1281 pipe_ctx->plane_res.dpp = dpp;
1282 pipe_ctx->plane_res.mpcc_inst = dpp->inst;
1283 hubp->mpcc_id = dpp->inst;
043f5bb6 1284 hubp->opp_id = OPP_ID_INVALID;
621fd3e3 1285 hubp->power_gated = false;
0af4096d 1286
f23d5584
EB
1287 dc->res_pool->opps[i]->mpc_tree_params.opp_id = dc->res_pool->opps[i]->inst;
1288 dc->res_pool->opps[i]->mpc_tree_params.opp_list = NULL;
e07f541f 1289 dc->res_pool->opps[i]->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true;
cc55b1f5 1290 pipe_ctx->stream_res.opp = dc->res_pool->opps[i];
1ccda80f 1291
f42ea55b 1292 hws->funcs.plane_atomic_disconnect(dc, pipe_ctx);
0af4096d
YS
1293
1294 if (tg->funcs->is_tg_enabled(tg))
1295 tg->funcs->unlock(tg);
0af4096d 1296
8a31820b 1297 dc->hwss.disable_plane(dc, pipe_ctx);
073a45e8 1298
0af4096d
YS
1299 pipe_ctx->stream_res.tg = NULL;
1300 pipe_ctx->plane_res.hubp = NULL;
1301
073a45e8 1302 tg->funcs->tg_init(tg);
7a5086a7 1303 }
fb55546e
AK
1304}
1305
78c77382 1306void dcn10_init_hw(struct dc *dc)
fb55546e 1307{
8ceb47e8 1308 int i;
fb55546e
AK
1309 struct abm *abm = dc->res_pool->abm;
1310 struct dmcu *dmcu = dc->res_pool->dmcu;
1311 struct dce_hwseq *hws = dc->hwseq;
1312 struct dc_bios *dcb = dc->ctx->dc_bios;
8a31820b 1313 struct resource_pool *res_pool = dc->res_pool;
3ba01817 1314 uint32_t backlight = MAX_BACKLIGHT_LEVEL;
cd9a180a 1315 bool is_optimized_init_done = false;
8a31820b
ML
1316
1317 if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks)
1318 dc->clk_mgr->funcs->init_clocks(dc->clk_mgr);
1319
1320 // Initialize the dccg
1321 if (dc->res_pool->dccg && dc->res_pool->dccg->funcs->dccg_init)
1322 dc->res_pool->dccg->funcs->dccg_init(res_pool->dccg);
fb55546e
AK
1323
1324 if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
8a31820b 1325
fb55546e
AK
1326 REG_WRITE(REFCLK_CNTL, 0);
1327 REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_ENABLE, 1);
1328 REG_WRITE(DIO_MEM_PWR_CTRL, 0);
7a5086a7 1329
fb55546e
AK
1330 if (!dc->debug.disable_clock_gate) {
1331 /* enable all DCN clock gating */
1332 REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0);
1333
1334 REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0);
1335
1336 REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0);
1337 }
1338
8a31820b 1339 //Enable ability to power gate / don't force power on permanently
3c9de4da
AL
1340 if (hws->funcs.enable_power_gating_plane)
1341 hws->funcs.enable_power_gating_plane(hws, true);
fb55546e 1342
529c690b 1343 return;
fb55546e
AK
1344 }
1345
f49cfa27 1346 if (!dcb->funcs->is_accelerated_mode(dcb))
f42ea55b 1347 hws->funcs.disable_vga(dc->hwseq);
f49cfa27 1348
64c51ea5 1349 hws->funcs.bios_golden_init(dc);
8f95ff28 1350
f49cfa27 1351 if (dc->ctx->dc_bios->fw_info_valid) {
1352 res_pool->ref_clocks.xtalin_clock_inKhz =
1353 dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency;
1354
1355 if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
1356 if (res_pool->dccg && res_pool->hubbub) {
1357
1358 (res_pool->dccg->funcs->get_dccg_ref_freq)(res_pool->dccg,
1359 dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency,
1360 &res_pool->ref_clocks.dccg_ref_clock_inKhz);
1361
1362 (res_pool->hubbub->funcs->get_dchub_ref_freq)(res_pool->hubbub,
1363 res_pool->ref_clocks.dccg_ref_clock_inKhz,
1364 &res_pool->ref_clocks.dchub_ref_clock_inKhz);
1365 } else {
1366 // Not all ASICs have DCCG sw component
1367 res_pool->ref_clocks.dccg_ref_clock_inKhz =
1368 res_pool->ref_clocks.xtalin_clock_inKhz;
1369 res_pool->ref_clocks.dchub_ref_clock_inKhz =
1370 res_pool->ref_clocks.xtalin_clock_inKhz;
1371 }
1372 }
1373 } else
1374 ASSERT_CRITICAL(false);
fb55546e
AK
1375
1376 for (i = 0; i < dc->link_count; i++) {
1377 /* Power up AND update implementation according to the
1378 * required signal (which may be different from the
1379 * default signal on connector).
1380 */
1381 struct dc_link *link = dc->links[i];
1382
cd9a180a
IK
1383 if (!is_optimized_init_done)
1384 link->link_enc->funcs->hw_init(link->link_enc);
fb55546e
AK
1385
1386 /* Check for enabled DIG to identify enabled display */
1387 if (link->link_enc->funcs->is_dig_enabled &&
1388 link->link_enc->funcs->is_dig_enabled(link->link_enc))
1389 link->link_status.link_active = true;
1390 }
529c690b 1391
8a31820b 1392 /* Power gate DSCs */
cd9a180a
IK
1393 if (!is_optimized_init_done) {
1394 for (i = 0; i < res_pool->res_cap->num_dsc; i++)
1395 if (hws->funcs.dsc_pg_control != NULL)
1396 hws->funcs.dsc_pg_control(hws, res_pool->dscs[i]->inst, false);
1397 }
8a31820b 1398
4f8e37db
MS
1399 /* Enable outbox notification feature of dmub */
1400 if (dc->debug.enable_dmub_aux_for_legacy_ddc)
1401 dmub_enable_outbox_notification(dc);
1402
896dace8 1403 /* we want to turn off all dp displays before doing detection */
8ceb47e8
LHM
1404 if (dc->config.power_down_display_on_boot)
1405 blank_all_dp_displays(dc, true);
896dace8 1406
235fb600
RL
1407 if (hws->funcs.enable_power_gating_plane)
1408 hws->funcs.enable_power_gating_plane(dc->hwseq, true);
1409
522f82f3
AK
1410 /* If taking control over from VBIOS, we may want to optimize our first
1411 * mode set, so we need to skip powering down pipes until we know which
1412 * pipes we want to use.
1413 * Otherwise, if taking control is not possible, we need to power
1414 * everything down.
1415 */
27eaa492 1416 if (dcb->funcs->is_accelerated_mode(dcb) || dc->config.power_down_display_on_boot) {
cd9a180a
IK
1417 if (!is_optimized_init_done) {
1418 hws->funcs.init_pipes(dc, dc->current_state);
1419 if (dc->res_pool->hubbub->funcs->allow_self_refresh_control)
1420 dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub,
1421 !dc->res_pool->hubbub->ctx->dc->debug.disable_stutter);
1422 }
522f82f3
AK
1423 }
1424
cd9a180a 1425 if (!is_optimized_init_done) {
7a5086a7 1426
cd9a180a
IK
1427 for (i = 0; i < res_pool->audio_count; i++) {
1428 struct audio *audio = res_pool->audios[i];
7a5086a7 1429
cd9a180a
IK
1430 audio->funcs->hw_init(audio);
1431 }
3ba01817 1432
cd9a180a
IK
1433 for (i = 0; i < dc->link_count; i++) {
1434 struct dc_link *link = dc->links[i];
7a5086a7 1435
cd9a180a
IK
1436 if (link->panel_cntl)
1437 backlight = link->panel_cntl->funcs->hw_init(link->panel_cntl);
1438 }
3ba01817 1439
cd9a180a
IK
1440 if (abm != NULL)
1441 abm->funcs->abm_init(abm, backlight);
1442
1443 if (dmcu != NULL && !dmcu->auto_load_dmcu)
1444 dmcu->funcs->dmcu_init(dmcu);
1445 }
7a5086a7 1446
70d9e8cb
PH
1447 if (abm != NULL && dmcu != NULL)
1448 abm->dmcu_is_running = dmcu->funcs->is_dmcu_initialized(dmcu);
1449
7a5086a7 1450 /* power AFMT HDMI memory TODO: may move to dis/en output save power*/
cd9a180a
IK
1451 if (!is_optimized_init_done)
1452 REG_WRITE(DIO_MEM_PWR_CTRL, 0);
7a5086a7
YS
1453
1454 if (!dc->debug.disable_clock_gate) {
1455 /* enable all DCN clock gating */
1456 REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0);
1457
1458 REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0);
1459
1460 REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0);
1461 }
622a88c8
EY
1462
1463 if (dc->clk_mgr->funcs->notify_wm_ranges)
1464 dc->clk_mgr->funcs->notify_wm_ranges(dc->clk_mgr);
7a5086a7
YS
1465}
1466
ca751df2
SL
1467/* In headless boot cases, DIG may be turned
1468 * on which causes HW/SW discrepancies.
1469 * To avoid this, power down hardware on boot
25331a18 1470 * if DIG is turned on
ca751df2
SL
1471 */
1472void dcn10_power_down_on_boot(struct dc *dc)
1473{
45a1261b 1474 struct dc_link *edp_links[MAX_NUM_EDP];
3addbde2 1475 struct dc_link *edp_link = NULL;
45a1261b
JW
1476 int edp_num;
1477 int i = 0;
ca751df2 1478
45a1261b 1479 get_edp_links(dc, edp_links, &edp_num);
3addbde2
JW
1480 if (edp_num)
1481 edp_link = edp_links[0];
1482
1483 if (edp_link && edp_link->link_enc->funcs->is_dig_enabled &&
1484 edp_link->link_enc->funcs->is_dig_enabled(edp_link->link_enc) &&
1485 dc->hwseq->funcs.edp_backlight_control &&
1486 dc->hwss.power_down &&
1487 dc->hwss.edp_power_control) {
1488 dc->hwseq->funcs.edp_backlight_control(edp_link, false);
1489 dc->hwss.power_down(dc);
1490 dc->hwss.edp_power_control(edp_link, false);
387f3a30
SL
1491 } else {
1492 for (i = 0; i < dc->link_count; i++) {
1493 struct dc_link *link = dc->links[i];
ca751df2 1494
74a3e2f9 1495 if (link->link_enc && link->link_enc->funcs->is_dig_enabled &&
387f3a30
SL
1496 link->link_enc->funcs->is_dig_enabled(link->link_enc) &&
1497 dc->hwss.power_down) {
1498 dc->hwss.power_down(dc);
1499 break;
ca751df2 1500 }
387f3a30 1501
ca751df2
SL
1502 }
1503 }
387f3a30
SL
1504
1505 /*
1506 * Call update_clocks with empty context
1507 * to send DISPLAY_OFF
1508 * Otherwise DISPLAY_OFF may not be asserted
1509 */
1510 if (dc->clk_mgr->funcs->set_low_power_state)
1511 dc->clk_mgr->funcs->set_low_power_state(dc->clk_mgr);
ca751df2
SL
1512}
1513
78c77382 1514void dcn10_reset_hw_ctx_wrap(
fb3466a4 1515 struct dc *dc,
608ac7bb 1516 struct dc_state *context)
70ccab60
HW
1517{
1518 int i;
f42ea55b 1519 struct dce_hwseq *hws = dc->hwseq;
70ccab60 1520
cfe4645e 1521 /* Reset Back End*/
70ccab60
HW
1522 for (i = dc->res_pool->pipe_count - 1; i >= 0 ; i--) {
1523 struct pipe_ctx *pipe_ctx_old =
608ac7bb 1524 &dc->current_state->res_ctx.pipe_ctx[i];
70ccab60
HW
1525 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
1526
1527 if (!pipe_ctx_old->stream)
1528 continue;
1529
56e6ed45
YS
1530 if (pipe_ctx_old->top_pipe)
1531 continue;
1532
70ccab60 1533 if (!pipe_ctx->stream ||
21e67d4d
HW
1534 pipe_need_reprogram(pipe_ctx_old, pipe_ctx)) {
1535 struct clock_source *old_clk = pipe_ctx_old->clock_source;
1536
4a797d24 1537 dcn10_reset_back_end_for_pipe(dc, pipe_ctx_old, dc->current_state);
f42ea55b
AK
1538 if (hws->funcs.enable_stream_gating)
1539 hws->funcs.enable_stream_gating(dc, pipe_ctx);
21e67d4d
HW
1540 if (old_clk)
1541 old_clk->funcs->cs_power_down(old_clk);
1542 }
70ccab60
HW
1543 }
1544}
1545
cfe4645e
DL
1546static bool patch_address_for_sbs_tb_stereo(
1547 struct pipe_ctx *pipe_ctx, PHYSICAL_ADDRESS_LOC *addr)
70ccab60 1548{
3be5262e 1549 struct dc_plane_state *plane_state = pipe_ctx->plane_state;
70ccab60 1550 bool sec_split = pipe_ctx->top_pipe &&
3be5262e
HW
1551 pipe_ctx->top_pipe->plane_state == pipe_ctx->plane_state;
1552 if (sec_split && plane_state->address.type == PLN_ADDR_TYPE_GRPH_STEREO &&
4fa086b9 1553 (pipe_ctx->stream->timing.timing_3d_format ==
70ccab60 1554 TIMING_3D_FORMAT_SIDE_BY_SIDE ||
4fa086b9 1555 pipe_ctx->stream->timing.timing_3d_format ==
70ccab60 1556 TIMING_3D_FORMAT_TOP_AND_BOTTOM)) {
3be5262e
HW
1557 *addr = plane_state->address.grph_stereo.left_addr;
1558 plane_state->address.grph_stereo.left_addr =
1559 plane_state->address.grph_stereo.right_addr;
70ccab60 1560 return true;
cdc5e048 1561 } else {
4fa086b9 1562 if (pipe_ctx->stream->view_format != VIEW_3D_FORMAT_NONE &&
3be5262e
HW
1563 plane_state->address.type != PLN_ADDR_TYPE_GRPH_STEREO) {
1564 plane_state->address.type = PLN_ADDR_TYPE_GRPH_STEREO;
1565 plane_state->address.grph_stereo.right_addr =
1566 plane_state->address.grph_stereo.left_addr;
480c5b8f
AL
1567 plane_state->address.grph_stereo.right_meta_addr =
1568 plane_state->address.grph_stereo.left_meta_addr;
cdc5e048 1569 }
70ccab60
HW
1570 }
1571 return false;
1572}
1573
78c77382 1574void dcn10_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx)
70ccab60
HW
1575{
1576 bool addr_patched = false;
1577 PHYSICAL_ADDRESS_LOC addr;
3be5262e 1578 struct dc_plane_state *plane_state = pipe_ctx->plane_state;
70ccab60 1579
3be5262e 1580 if (plane_state == NULL)
70ccab60 1581 return;
68199bd1 1582
70ccab60 1583 addr_patched = patch_address_for_sbs_tb_stereo(pipe_ctx, &addr);
68199bd1 1584
8feabd03
YHL
1585 pipe_ctx->plane_res.hubp->funcs->hubp_program_surface_flip_and_addr(
1586 pipe_ctx->plane_res.hubp,
3be5262e 1587 &plane_state->address,
bda9afda 1588 plane_state->flip_immediate);
68199bd1 1589
3be5262e 1590 plane_state->status.requested_address = plane_state->address;
68199bd1
TC
1591
1592 if (plane_state->flip_immediate)
1593 plane_state->status.current_address = plane_state->address;
1594
70ccab60 1595 if (addr_patched)
3be5262e 1596 pipe_ctx->plane_state->address.grph_stereo.left_addr = addr;
70ccab60
HW
1597}
1598
78c77382
AK
1599bool dcn10_set_input_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx,
1600 const struct dc_plane_state *plane_state)
70ccab60 1601{
d94585a0 1602 struct dpp *dpp_base = pipe_ctx->plane_res.dpp;
7b0c470f 1603 const struct dc_transfer_func *tf = NULL;
70ccab60
HW
1604 bool result = true;
1605
d94585a0 1606 if (dpp_base == NULL)
70ccab60
HW
1607 return false;
1608
3be5262e
HW
1609 if (plane_state->in_transfer_func)
1610 tf = plane_state->in_transfer_func;
70ccab60 1611
f9549850 1612 if (plane_state->gamma_correction &&
8ce504b9
ML
1613 !dpp_base->ctx->dc->debug.always_use_regamma
1614 && !plane_state->gamma_correction->is_identity
e43a432c 1615 && dce_use_lut(plane_state->format))
a6114e85 1616 dpp_base->funcs->dpp_program_input_lut(dpp_base, plane_state->gamma_correction);
5aff86c1 1617
70ccab60 1618 if (tf == NULL)
5fa2ec4f 1619 dpp_base->funcs->dpp_set_degamma(dpp_base, IPP_DEGAMMA_MODE_BYPASS);
7b0c470f
LSL
1620 else if (tf->type == TF_TYPE_PREDEFINED) {
1621 switch (tf->tf) {
70ccab60 1622 case TRANSFER_FUNCTION_SRGB:
a6114e85 1623 dpp_base->funcs->dpp_set_degamma(dpp_base, IPP_DEGAMMA_MODE_HW_sRGB);
70ccab60
HW
1624 break;
1625 case TRANSFER_FUNCTION_BT709:
a6114e85 1626 dpp_base->funcs->dpp_set_degamma(dpp_base, IPP_DEGAMMA_MODE_HW_xvYCC);
70ccab60
HW
1627 break;
1628 case TRANSFER_FUNCTION_LINEAR:
a6114e85 1629 dpp_base->funcs->dpp_set_degamma(dpp_base, IPP_DEGAMMA_MODE_BYPASS);
70ccab60
HW
1630 break;
1631 case TRANSFER_FUNCTION_PQ:
2853ecc6
RA
1632 dpp_base->funcs->dpp_set_degamma(dpp_base, IPP_DEGAMMA_MODE_USER_PWL);
1633 cm_helper_translate_curve_to_degamma_hw_format(tf, &dpp_base->degamma_params);
1634 dpp_base->funcs->dpp_program_degamma_pwl(dpp_base, &dpp_base->degamma_params);
1635 result = true;
1636 break;
70ccab60
HW
1637 default:
1638 result = false;
1639 break;
1640 }
7b0c470f 1641 } else if (tf->type == TF_TYPE_BYPASS) {
5fa2ec4f 1642 dpp_base->funcs->dpp_set_degamma(dpp_base, IPP_DEGAMMA_MODE_BYPASS);
70ccab60 1643 } else {
78e4405c
DF
1644 cm_helper_translate_curve_to_degamma_hw_format(tf,
1645 &dpp_base->degamma_params);
1646 dpp_base->funcs->dpp_program_degamma_pwl(dpp_base,
1647 &dpp_base->degamma_params);
1648 result = true;
70ccab60
HW
1649 }
1650
1651 return result;
1652}
70ccab60 1653
8221b6ea
WW
1654#define MAX_NUM_HW_POINTS 0x200
1655
1656static void log_tf(struct dc_context *ctx,
1657 struct dc_transfer_func *tf, uint32_t hw_points_num)
1658{
1659 // DC_LOG_GAMMA is default logging of all hw points
1660 // DC_LOG_ALL_GAMMA logs all points, not only hw points
1661 // DC_LOG_ALL_TF_POINTS logs all channels of the tf
1662 int i = 0;
1663
1664 DC_LOGGER_INIT(ctx->logger);
1665 DC_LOG_GAMMA("Gamma Correction TF");
1666 DC_LOG_ALL_GAMMA("Logging all tf points...");
1667 DC_LOG_ALL_TF_CHANNELS("Logging all channels...");
1668
1669 for (i = 0; i < hw_points_num; i++) {
cbc697b2
WW
1670 DC_LOG_GAMMA("R\t%d\t%llu", i, tf->tf_pts.red[i].value);
1671 DC_LOG_ALL_TF_CHANNELS("G\t%d\t%llu", i, tf->tf_pts.green[i].value);
1672 DC_LOG_ALL_TF_CHANNELS("B\t%d\t%llu", i, tf->tf_pts.blue[i].value);
8221b6ea
WW
1673 }
1674
1675 for (i = hw_points_num; i < MAX_NUM_HW_POINTS; i++) {
cbc697b2
WW
1676 DC_LOG_ALL_GAMMA("R\t%d\t%llu", i, tf->tf_pts.red[i].value);
1677 DC_LOG_ALL_TF_CHANNELS("G\t%d\t%llu", i, tf->tf_pts.green[i].value);
1678 DC_LOG_ALL_TF_CHANNELS("B\t%d\t%llu", i, tf->tf_pts.blue[i].value);
8221b6ea
WW
1679 }
1680}
1681
78c77382
AK
1682bool dcn10_set_output_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx,
1683 const struct dc_stream_state *stream)
70ccab60 1684{
d94585a0 1685 struct dpp *dpp = pipe_ctx->plane_res.dpp;
70ccab60 1686
d94585a0 1687 if (dpp == NULL)
f46661dd
AZ
1688 return false;
1689
d94585a0 1690 dpp->regamma_params.hw_points_num = GAMMA_HW_POINTS_NUM;
70ccab60 1691
4fa086b9 1692 if (stream->out_transfer_func &&
a6114e85
HW
1693 stream->out_transfer_func->type == TF_TYPE_PREDEFINED &&
1694 stream->out_transfer_func->tf == TRANSFER_FUNCTION_SRGB)
5fa2ec4f 1695 dpp->funcs->dpp_program_regamma_pwl(dpp, NULL, OPP_REGAMMA_SRGB);
675634c5
YS
1696
1697 /* dcn10_translate_regamma_to_hw_format takes 750us, only do it when full
1698 * update.
1699 */
b6295960 1700 else if (cm_helper_translate_curve_to_hw_format(
675634c5 1701 stream->out_transfer_func,
b6295960 1702 &dpp->regamma_params, false)) {
675634c5
YS
1703 dpp->funcs->dpp_program_regamma_pwl(
1704 dpp,
1705 &dpp->regamma_params, OPP_REGAMMA_USER);
1706 } else
5fa2ec4f 1707 dpp->funcs->dpp_program_regamma_pwl(dpp, NULL, OPP_REGAMMA_BYPASS);
70ccab60 1708
ddef02de
WW
1709 if (stream != NULL && stream->ctx != NULL &&
1710 stream->out_transfer_func != NULL) {
1711 log_tf(stream->ctx,
1712 stream->out_transfer_func,
1713 dpp->regamma_params.hw_points_num);
1714 }
8221b6ea 1715
70ccab60
HW
1716 return true;
1717}
1718
78c77382 1719void dcn10_pipe_control_lock(
fb3466a4 1720 struct dc *dc,
70ccab60
HW
1721 struct pipe_ctx *pipe,
1722 bool lock)
1723{
f42ea55b
AK
1724 struct dce_hwseq *hws = dc->hwseq;
1725
70ccab60
HW
1726 /* use TG master update lock to lock everything on the TG
1727 * therefore only top pipe need to lock
1728 */
009114f6 1729 if (!pipe || pipe->top_pipe)
70ccab60
HW
1730 return;
1731
fb3466a4 1732 if (dc->debug.sanity_checks)
f42ea55b 1733 hws->funcs.verify_allow_pstate_change_high(dc);
2b13d7d3 1734
70ccab60 1735 if (lock)
6b670fa9 1736 pipe->stream_res.tg->funcs->lock(pipe->stream_res.tg);
70ccab60 1737 else
6b670fa9 1738 pipe->stream_res.tg->funcs->unlock(pipe->stream_res.tg);
2b13d7d3 1739
fb3466a4 1740 if (dc->debug.sanity_checks)
f42ea55b 1741 hws->funcs.verify_allow_pstate_change_high(dc);
70ccab60
HW
1742}
1743
63731e73
NK
1744/**
1745 * delay_cursor_until_vupdate() - Delay cursor update if too close to VUPDATE.
1746 *
1747 * Software keepout workaround to prevent cursor update locking from stalling
1748 * out cursor updates indefinitely or from old values from being retained in
1749 * the case where the viewport changes in the same frame as the cursor.
1750 *
1751 * The idea is to calculate the remaining time from VPOS to VUPDATE. If it's
1752 * too close to VUPDATE, then stall out until VUPDATE finishes.
1753 *
1754 * TODO: Optimize cursor programming to be once per frame before VUPDATE
1755 * to avoid the need for this workaround.
1756 */
1757static void delay_cursor_until_vupdate(struct dc *dc, struct pipe_ctx *pipe_ctx)
1758{
1759 struct dc_stream_state *stream = pipe_ctx->stream;
1760 struct crtc_position position;
1761 uint32_t vupdate_start, vupdate_end;
1762 unsigned int lines_to_vupdate, us_to_vupdate, vpos;
1763 unsigned int us_per_line, us_vupdate;
1764
1765 if (!dc->hwss.calc_vupdate_position || !dc->hwss.get_position)
1766 return;
1767
1768 if (!pipe_ctx->stream_res.stream_enc || !pipe_ctx->stream_res.tg)
1769 return;
1770
1771 dc->hwss.calc_vupdate_position(dc, pipe_ctx, &vupdate_start,
1772 &vupdate_end);
1773
1774 dc->hwss.get_position(&pipe_ctx, 1, &position);
1775 vpos = position.vertical_count;
1776
1777 /* Avoid wraparound calculation issues */
1778 vupdate_start += stream->timing.v_total;
1779 vupdate_end += stream->timing.v_total;
1780 vpos += stream->timing.v_total;
1781
1782 if (vpos <= vupdate_start) {
1783 /* VPOS is in VACTIVE or back porch. */
1784 lines_to_vupdate = vupdate_start - vpos;
1785 } else if (vpos > vupdate_end) {
1786 /* VPOS is in the front porch. */
1787 return;
1788 } else {
1789 /* VPOS is in VUPDATE. */
1790 lines_to_vupdate = 0;
1791 }
1792
1793 /* Calculate time until VUPDATE in microseconds. */
1794 us_per_line =
1795 stream->timing.h_total * 10000u / stream->timing.pix_clk_100hz;
1796 us_to_vupdate = lines_to_vupdate * us_per_line;
1797
1798 /* 70 us is a conservative estimate of cursor update time*/
1799 if (us_to_vupdate > 70)
1800 return;
1801
1802 /* Stall out until the cursor update completes. */
185082b6
AC
1803 if (vupdate_end < vupdate_start)
1804 vupdate_end += stream->timing.v_total;
63731e73
NK
1805 us_vupdate = (vupdate_end - vupdate_start + 1) * us_per_line;
1806 udelay(us_to_vupdate + us_vupdate);
1807}
1808
1e461c37
AC
1809void dcn10_cursor_lock(struct dc *dc, struct pipe_ctx *pipe, bool lock)
1810{
1811 /* cursor lock is per MPCC tree, so only need to lock one pipe per stream */
1812 if (!pipe || pipe->top_pipe)
1813 return;
1814
63731e73
NK
1815 /* Prevent cursor lock from stalling out cursor updates. */
1816 if (lock)
1817 delay_cursor_until_vupdate(dc, pipe);
1818
dc6e2448
WW
1819 if (pipe->stream && should_use_dmub_lock(pipe->stream->link)) {
1820 union dmub_hw_lock_flags hw_locks = { 0 };
1821 struct dmub_hw_lock_inst_flags inst_flags = { 0 };
1822
1823 hw_locks.bits.lock_cursor = 1;
1824 inst_flags.opp_inst = pipe->stream_res.opp->inst;
1825
1826 dmub_hw_lock_mgr_cmd(dc->ctx->dmub_srv,
1827 lock,
1828 &hw_locks,
1829 &inst_flags);
1830 } else
1831 dc->res_pool->mpc->funcs->cursor_lock(dc->res_pool->mpc,
1832 pipe->stream_res.opp->inst, lock);
1e461c37
AC
1833}
1834
70ccab60
HW
1835static bool wait_for_reset_trigger_to_occur(
1836 struct dc_context *dc_ctx,
1837 struct timing_generator *tg)
1838{
1839 bool rc = false;
1840
1841 /* To avoid endless loop we wait at most
1842 * frames_to_wait_on_triggered_reset frames for the reset to occur. */
1843 const uint32_t frames_to_wait_on_triggered_reset = 10;
1844 int i;
1845
1846 for (i = 0; i < frames_to_wait_on_triggered_reset; i++) {
1847
1848 if (!tg->funcs->is_counter_moving(tg)) {
1849 DC_ERROR("TG counter is not moving!\n");
1850 break;
1851 }
1852
1853 if (tg->funcs->did_triggered_reset_occur(tg)) {
1854 rc = true;
1855 /* usually occurs at i=1 */
1856 DC_SYNC_INFO("GSL: reset occurred at wait count: %d\n",
1857 i);
1858 break;
1859 }
1860
1861 /* Wait for one frame. */
1862 tg->funcs->wait_for_state(tg, CRTC_STATE_VACTIVE);
1863 tg->funcs->wait_for_state(tg, CRTC_STATE_VBLANK);
1864 }
1865
1866 if (false == rc)
1867 DC_ERROR("GSL: Timeout on reset trigger!\n");
1868
1869 return rc;
1870}
1871
77a2b726
VS
1872uint64_t reduceSizeAndFraction(
1873 uint64_t *numerator,
1874 uint64_t *denominator,
1875 bool checkUint32Bounary)
1876{
1877 int i;
1878 bool ret = checkUint32Bounary == false;
1879 uint64_t max_int32 = 0xffffffff;
1880 uint64_t num, denom;
1881 static const uint16_t prime_numbers[] = {
1882 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43,
1883 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103,
1884 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163,
1885 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227,
1886 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281,
1887 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353,
1888 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421,
1889 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487,
1890 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569,
1891 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631,
1892 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701,
1893 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773,
1894 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857,
1895 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937,
1896 941, 947, 953, 967, 971, 977, 983, 991, 997};
1897 int count = ARRAY_SIZE(prime_numbers);
1898
1899 num = *numerator;
1900 denom = *denominator;
1901 for (i = 0; i < count; i++) {
553ef24d 1902 uint32_t num_remainder, denom_remainder;
a8a2e134 1903 uint64_t num_result, denom_result;
77a2b726
VS
1904 if (checkUint32Bounary &&
1905 num <= max_int32 && denom <= max_int32) {
1906 ret = true;
1907 break;
1908 }
a8a2e134 1909 do {
553ef24d
VS
1910 num_result = div_u64_rem(num, prime_numbers[i], &num_remainder);
1911 denom_result = div_u64_rem(denom, prime_numbers[i], &denom_remainder);
1912 if (num_remainder == 0 && denom_remainder == 0) {
a8a2e134
VS
1913 num = num_result;
1914 denom = denom_result;
1915 }
553ef24d 1916 } while (num_remainder == 0 && denom_remainder == 0);
77a2b726
VS
1917 }
1918 *numerator = num;
1919 *denominator = denom;
1920 return ret;
1921}
1922
1923bool is_low_refresh_rate(struct pipe_ctx *pipe)
1924{
1925 uint32_t master_pipe_refresh_rate =
1926 pipe->stream->timing.pix_clk_100hz * 100 /
1927 pipe->stream->timing.h_total /
1928 pipe->stream->timing.v_total;
1929 return master_pipe_refresh_rate <= 30;
1930}
1931
1932uint8_t get_clock_divider(struct pipe_ctx *pipe, bool account_low_refresh_rate)
1933{
1934 uint32_t clock_divider = 1;
1935 uint32_t numpipes = 1;
1936
1937 if (account_low_refresh_rate && is_low_refresh_rate(pipe))
1938 clock_divider *= 2;
1939
1940 if (pipe->stream_res.pix_clk_params.pixel_encoding == PIXEL_ENCODING_YCBCR420)
1941 clock_divider *= 2;
1942
1943 while (pipe->next_odm_pipe) {
1944 pipe = pipe->next_odm_pipe;
1945 numpipes++;
1946 }
1947 clock_divider *= numpipes;
1948
1949 return clock_divider;
1950}
1951
1952int dcn10_align_pixel_clocks(
1953 struct dc *dc,
1954 int group_size,
1955 struct pipe_ctx *grouped_pipes[])
1956{
1957 struct dc_context *dc_ctx = dc->ctx;
1958 int i, master = -1, embedded = -1;
1959 struct dc_crtc_timing hw_crtc_timing[MAX_PIPES] = {0};
1960 uint64_t phase[MAX_PIPES];
1961 uint64_t modulo[MAX_PIPES];
1962 unsigned int pclk;
1963
1964 uint32_t embedded_pix_clk_100hz;
1965 uint16_t embedded_h_total;
1966 uint16_t embedded_v_total;
1967 bool clamshell_closed = false;
1968 uint32_t dp_ref_clk_100hz =
1969 dc->res_pool->dp_clock_source->ctx->dc->clk_mgr->dprefclk_khz*10;
1970
1971 if (dc->config.vblank_alignment_dto_params &&
1972 dc->res_pool->dp_clock_source->funcs->override_dp_pix_clk) {
1973 clamshell_closed =
1974 (dc->config.vblank_alignment_dto_params >> 63);
1975 embedded_h_total =
1976 (dc->config.vblank_alignment_dto_params >> 32) & 0x7FFF;
1977 embedded_v_total =
1978 (dc->config.vblank_alignment_dto_params >> 48) & 0x7FFF;
1979 embedded_pix_clk_100hz =
1980 dc->config.vblank_alignment_dto_params & 0xFFFFFFFF;
1981
1982 for (i = 0; i < group_size; i++) {
1983 grouped_pipes[i]->stream_res.tg->funcs->get_hw_timing(
1984 grouped_pipes[i]->stream_res.tg,
1985 &hw_crtc_timing[i]);
1986 dc->res_pool->dp_clock_source->funcs->get_pixel_clk_frequency_100hz(
1987 dc->res_pool->dp_clock_source,
1988 grouped_pipes[i]->stream_res.tg->inst,
1989 &pclk);
1990 hw_crtc_timing[i].pix_clk_100hz = pclk;
1991 if (dc_is_embedded_signal(
1992 grouped_pipes[i]->stream->signal)) {
1993 embedded = i;
1994 master = i;
1995 phase[i] = embedded_pix_clk_100hz*100;
1996 modulo[i] = dp_ref_clk_100hz*100;
1997 } else {
1998
1999 phase[i] = (uint64_t)embedded_pix_clk_100hz*
2000 hw_crtc_timing[i].h_total*
783bf403
VS
2001 hw_crtc_timing[i].v_total;
2002 phase[i] = div_u64(phase[i], get_clock_divider(grouped_pipes[i], true));
77a2b726
VS
2003 modulo[i] = (uint64_t)dp_ref_clk_100hz*
2004 embedded_h_total*
2005 embedded_v_total;
2006
2007 if (reduceSizeAndFraction(&phase[i],
2008 &modulo[i], true) == false) {
2009 /*
2010 * this will help to stop reporting
2011 * this timing synchronizable
2012 */
2013 DC_SYNC_INFO("Failed to reduce DTO parameters\n");
2014 grouped_pipes[i]->stream->has_non_synchronizable_pclk = true;
2015 }
2016 }
2017 }
2018
2019 for (i = 0; i < group_size; i++) {
2020 if (i != embedded && !grouped_pipes[i]->stream->has_non_synchronizable_pclk) {
2021 dc->res_pool->dp_clock_source->funcs->override_dp_pix_clk(
2022 dc->res_pool->dp_clock_source,
2023 grouped_pipes[i]->stream_res.tg->inst,
2024 phase[i], modulo[i]);
2025 dc->res_pool->dp_clock_source->funcs->get_pixel_clk_frequency_100hz(
2026 dc->res_pool->dp_clock_source,
2027 grouped_pipes[i]->stream_res.tg->inst, &pclk);
2028 grouped_pipes[i]->stream->timing.pix_clk_100hz =
2029 pclk*get_clock_divider(grouped_pipes[i], false);
2030 if (master == -1)
2031 master = i;
2032 }
2033 }
2034
2035 }
2036 return master;
2037}
2038
2039void dcn10_enable_vblanks_synchronization(
2040 struct dc *dc,
2041 int group_index,
2042 int group_size,
2043 struct pipe_ctx *grouped_pipes[])
2044{
2045 struct dc_context *dc_ctx = dc->ctx;
2046 struct output_pixel_processor *opp;
2047 struct timing_generator *tg;
2048 int i, width, height, master;
2049
2050 for (i = 1; i < group_size; i++) {
2051 opp = grouped_pipes[i]->stream_res.opp;
2052 tg = grouped_pipes[i]->stream_res.tg;
2053 tg->funcs->get_otg_active_size(tg, &width, &height);
2054 if (opp->funcs->opp_program_dpg_dimensions)
2055 opp->funcs->opp_program_dpg_dimensions(opp, width, 2*(height) + 1);
2056 }
2057
2058 for (i = 0; i < group_size; i++) {
2059 if (grouped_pipes[i]->stream == NULL)
2060 continue;
2061 grouped_pipes[i]->stream->vblank_synchronized = false;
2062 grouped_pipes[i]->stream->has_non_synchronizable_pclk = false;
2063 }
2064
2065 DC_SYNC_INFO("Aligning DP DTOs\n");
2066
2067 master = dcn10_align_pixel_clocks(dc, group_size, grouped_pipes);
2068
2069 DC_SYNC_INFO("Synchronizing VBlanks\n");
2070
2071 if (master >= 0) {
2072 for (i = 0; i < group_size; i++) {
2073 if (i != master && !grouped_pipes[i]->stream->has_non_synchronizable_pclk)
2074 grouped_pipes[i]->stream_res.tg->funcs->align_vblanks(
2075 grouped_pipes[master]->stream_res.tg,
2076 grouped_pipes[i]->stream_res.tg,
2077 grouped_pipes[master]->stream->timing.pix_clk_100hz,
2078 grouped_pipes[i]->stream->timing.pix_clk_100hz,
2079 get_clock_divider(grouped_pipes[master], false),
2080 get_clock_divider(grouped_pipes[i], false));
2081 grouped_pipes[i]->stream->vblank_synchronized = true;
2082 }
2083 grouped_pipes[master]->stream->vblank_synchronized = true;
2084 DC_SYNC_INFO("Sync complete\n");
2085 }
2086
2087 for (i = 1; i < group_size; i++) {
2088 opp = grouped_pipes[i]->stream_res.opp;
2089 tg = grouped_pipes[i]->stream_res.tg;
2090 tg->funcs->get_otg_active_size(tg, &width, &height);
2091 if (opp->funcs->opp_program_dpg_dimensions)
2092 opp->funcs->opp_program_dpg_dimensions(opp, width, height);
2093 }
2094}
2095
78c77382 2096void dcn10_enable_timing_synchronization(
fb3466a4 2097 struct dc *dc,
70ccab60
HW
2098 int group_index,
2099 int group_size,
2100 struct pipe_ctx *grouped_pipes[])
2101{
2102 struct dc_context *dc_ctx = dc->ctx;
a47cc3ab
TH
2103 struct output_pixel_processor *opp;
2104 struct timing_generator *tg;
2105 int i, width, height;
70ccab60
HW
2106
2107 DC_SYNC_INFO("Setting up OTG reset trigger\n");
2108
a47cc3ab
TH
2109 for (i = 1; i < group_size; i++) {
2110 opp = grouped_pipes[i]->stream_res.opp;
2111 tg = grouped_pipes[i]->stream_res.tg;
2112 tg->funcs->get_otg_active_size(tg, &width, &height);
2113 if (opp->funcs->opp_program_dpg_dimensions)
2114 opp->funcs->opp_program_dpg_dimensions(opp, width, 2*(height) + 1);
2115 }
2116
77a2b726
VS
2117 for (i = 0; i < group_size; i++) {
2118 if (grouped_pipes[i]->stream == NULL)
2119 continue;
2120 grouped_pipes[i]->stream->vblank_synchronized = false;
2121 }
2122
70ccab60 2123 for (i = 1; i < group_size; i++)
6b670fa9 2124 grouped_pipes[i]->stream_res.tg->funcs->enable_reset_trigger(
fa2123db
ML
2125 grouped_pipes[i]->stream_res.tg,
2126 grouped_pipes[0]->stream_res.tg->inst);
70ccab60
HW
2127
2128 DC_SYNC_INFO("Waiting for trigger\n");
2129
2130 /* Need to get only check 1 pipe for having reset as all the others are
2131 * synchronized. Look at last pipe programmed to reset.
2132 */
fa2123db 2133
6b670fa9 2134 wait_for_reset_trigger_to_occur(dc_ctx, grouped_pipes[1]->stream_res.tg);
70ccab60 2135 for (i = 1; i < group_size; i++)
6b670fa9
HW
2136 grouped_pipes[i]->stream_res.tg->funcs->disable_reset_trigger(
2137 grouped_pipes[i]->stream_res.tg);
70ccab60 2138
a47cc3ab
TH
2139 for (i = 1; i < group_size; i++) {
2140 opp = grouped_pipes[i]->stream_res.opp;
2141 tg = grouped_pipes[i]->stream_res.tg;
2142 tg->funcs->get_otg_active_size(tg, &width, &height);
2143 if (opp->funcs->opp_program_dpg_dimensions)
2144 opp->funcs->opp_program_dpg_dimensions(opp, width, height);
2145 }
2146
70ccab60
HW
2147 DC_SYNC_INFO("Sync complete\n");
2148}
2149
78c77382 2150void dcn10_enable_per_frame_crtc_position_reset(
fa2123db
ML
2151 struct dc *dc,
2152 int group_size,
2153 struct pipe_ctx *grouped_pipes[])
2154{
2155 struct dc_context *dc_ctx = dc->ctx;
2156 int i;
2157
2158 DC_SYNC_INFO("Setting up\n");
2159 for (i = 0; i < group_size; i++)
7f93c1de
CL
2160 if (grouped_pipes[i]->stream_res.tg->funcs->enable_crtc_reset)
2161 grouped_pipes[i]->stream_res.tg->funcs->enable_crtc_reset(
2162 grouped_pipes[i]->stream_res.tg,
37cd85ce 2163 0,
7f93c1de 2164 &grouped_pipes[i]->stream->triggered_crtc_reset);
fa2123db
ML
2165
2166 DC_SYNC_INFO("Waiting for trigger\n");
2167
03736f4c 2168 for (i = 0; i < group_size; i++)
fa2123db
ML
2169 wait_for_reset_trigger_to_occur(dc_ctx, grouped_pipes[i]->stream_res.tg);
2170
2171 DC_SYNC_INFO("Multi-display sync is complete\n");
2172}
2173
a4e6d14e
YS
2174static void mmhub_read_vm_system_aperture_settings(struct dcn10_hubp *hubp1,
2175 struct vm_system_aperture_param *apt,
2176 struct dce_hwseq *hws)
2177{
2178 PHYSICAL_ADDRESS_LOC physical_page_number;
2179 uint32_t logical_addr_low;
2180 uint32_t logical_addr_high;
2181
2182 REG_GET(MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB,
2183 PHYSICAL_PAGE_NUMBER_MSB, &physical_page_number.high_part);
2184 REG_GET(MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB,
2185 PHYSICAL_PAGE_NUMBER_LSB, &physical_page_number.low_part);
2186
2187 REG_GET(MC_VM_SYSTEM_APERTURE_LOW_ADDR,
2188 LOGICAL_ADDR, &logical_addr_low);
2189
2190 REG_GET(MC_VM_SYSTEM_APERTURE_HIGH_ADDR,
2191 LOGICAL_ADDR, &logical_addr_high);
2192
2193 apt->sys_default.quad_part = physical_page_number.quad_part << 12;
2194 apt->sys_low.quad_part = (int64_t)logical_addr_low << 18;
2195 apt->sys_high.quad_part = (int64_t)logical_addr_high << 18;
2196}
2197
2198/* Temporary read settings, future will get values from kmd directly */
2199static void mmhub_read_vm_context0_settings(struct dcn10_hubp *hubp1,
2200 struct vm_context0_param *vm0,
2201 struct dce_hwseq *hws)
2202{
2203 PHYSICAL_ADDRESS_LOC fb_base;
2204 PHYSICAL_ADDRESS_LOC fb_offset;
2205 uint32_t fb_base_value;
2206 uint32_t fb_offset_value;
2207
2208 REG_GET(DCHUBBUB_SDPIF_FB_BASE, SDPIF_FB_BASE, &fb_base_value);
2209 REG_GET(DCHUBBUB_SDPIF_FB_OFFSET, SDPIF_FB_OFFSET, &fb_offset_value);
2210
2211 REG_GET(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32,
2212 PAGE_DIRECTORY_ENTRY_HI32, &vm0->pte_base.high_part);
2213 REG_GET(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LO32,
2214 PAGE_DIRECTORY_ENTRY_LO32, &vm0->pte_base.low_part);
2215
2216 REG_GET(VM_CONTEXT0_PAGE_TABLE_START_ADDR_HI32,
2217 LOGICAL_PAGE_NUMBER_HI4, &vm0->pte_start.high_part);
2218 REG_GET(VM_CONTEXT0_PAGE_TABLE_START_ADDR_LO32,
2219 LOGICAL_PAGE_NUMBER_LO32, &vm0->pte_start.low_part);
2220
2221 REG_GET(VM_CONTEXT0_PAGE_TABLE_END_ADDR_HI32,
2222 LOGICAL_PAGE_NUMBER_HI4, &vm0->pte_end.high_part);
2223 REG_GET(VM_CONTEXT0_PAGE_TABLE_END_ADDR_LO32,
2224 LOGICAL_PAGE_NUMBER_LO32, &vm0->pte_end.low_part);
2225
2226 REG_GET(VM_L2_PROTECTION_FAULT_DEFAULT_ADDR_HI32,
2227 PHYSICAL_PAGE_ADDR_HI4, &vm0->fault_default.high_part);
2228 REG_GET(VM_L2_PROTECTION_FAULT_DEFAULT_ADDR_LO32,
2229 PHYSICAL_PAGE_ADDR_LO32, &vm0->fault_default.low_part);
2230
2231 /*
2232 * The values in VM_CONTEXT0_PAGE_TABLE_BASE_ADDR is in UMA space.
2233 * Therefore we need to do
2234 * DCN_VM_CONTEXT0_PAGE_TABLE_BASE_ADDR = VM_CONTEXT0_PAGE_TABLE_BASE_ADDR
2235 * - DCHUBBUB_SDPIF_FB_OFFSET + DCHUBBUB_SDPIF_FB_BASE
2236 */
2237 fb_base.quad_part = (uint64_t)fb_base_value << 24;
2238 fb_offset.quad_part = (uint64_t)fb_offset_value << 24;
2239 vm0->pte_base.quad_part += fb_base.quad_part;
2240 vm0->pte_base.quad_part -= fb_offset.quad_part;
2241}
2242
2243
560a77f5 2244void dcn10_program_pte_vm(struct dce_hwseq *hws, struct hubp *hubp)
a4e6d14e
YS
2245{
2246 struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp);
2247 struct vm_system_aperture_param apt = { {{ 0 } } };
2248 struct vm_context0_param vm0 = { { { 0 } } };
2249
2250 mmhub_read_vm_system_aperture_settings(hubp1, &apt, hws);
2251 mmhub_read_vm_context0_settings(hubp1, &vm0, hws);
2252
2253 hubp->funcs->hubp_set_vm_system_aperture_settings(hubp, &apt);
2254 hubp->funcs->hubp_set_vm_context0_settings(hubp, &vm0);
2255}
2256
7f914a62 2257static void dcn10_enable_plane(
fb3466a4 2258 struct dc *dc,
70ccab60 2259 struct pipe_ctx *pipe_ctx,
608ac7bb 2260 struct dc_state *context)
70ccab60 2261{
184debdb 2262 struct dce_hwseq *hws = dc->hwseq;
70ccab60 2263
fb3466a4 2264 if (dc->debug.sanity_checks) {
f42ea55b 2265 hws->funcs.verify_allow_pstate_change_high(dc);
665da60f
CM
2266 }
2267
7f914a62
YS
2268 undo_DEGVIDCN10_253_wa(dc);
2269
184debdb 2270 power_on_plane(dc->hwseq,
e07f541f 2271 pipe_ctx->plane_res.hubp->inst);
70ccab60 2272
c9742685 2273 /* enable DCFCLK current DCHUB */
c8242b98 2274 pipe_ctx->plane_res.hubp->funcs->hubp_clk_cntl(pipe_ctx->plane_res.hubp, true);
d21becbe
TC
2275
2276 /* make sure OPP_PIPE_CLOCK_EN = 1 */
be2f449a
YS
2277 pipe_ctx->stream_res.opp->funcs->opp_pipe_clock_control(
2278 pipe_ctx->stream_res.opp,
2279 true);
c9742685 2280
a4e6d14e
YS
2281 if (dc->config.gpu_vm_support)
2282 dcn10_program_pte_vm(hws, pipe_ctx->plane_res.hubp);
665da60f 2283
fb3466a4 2284 if (dc->debug.sanity_checks) {
f42ea55b 2285 hws->funcs.verify_allow_pstate_change_high(dc);
665da60f 2286 }
0c66824b
QZ
2287
2288 if (!pipe_ctx->top_pipe
2289 && pipe_ctx->plane_state
2290 && pipe_ctx->plane_state->flip_int_enabled
2291 && pipe_ctx->plane_res.hubp->funcs->hubp_set_flip_int)
2292 pipe_ctx->plane_res.hubp->funcs->hubp_set_flip_int(pipe_ctx->plane_res.hubp);
2293
70ccab60
HW
2294}
2295
78c77382 2296void dcn10_program_gamut_remap(struct pipe_ctx *pipe_ctx)
70ccab60 2297{
146a9f63 2298 int i = 0;
d94585a0 2299 struct dpp_grph_csc_adjustment adjust;
70ccab60
HW
2300 memset(&adjust, 0, sizeof(adjust));
2301 adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS;
2302
2303
4fa086b9 2304 if (pipe_ctx->stream->gamut_remap_matrix.enable_remap == true) {
70ccab60 2305 adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW;
146a9f63
KK
2306 for (i = 0; i < CSC_TEMPERATURE_MATRIX_SIZE; i++)
2307 adjust.temperature_matrix[i] =
2308 pipe_ctx->stream->gamut_remap_matrix.matrix[i];
5c41c023
SW
2309 } else if (pipe_ctx->plane_state &&
2310 pipe_ctx->plane_state->gamut_remap_matrix.enable_remap == true) {
2311 adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW;
2312 for (i = 0; i < CSC_TEMPERATURE_MATRIX_SIZE; i++)
2313 adjust.temperature_matrix[i] =
2314 pipe_ctx->plane_state->gamut_remap_matrix.matrix[i];
70ccab60
HW
2315 }
2316
d94585a0 2317 pipe_ctx->plane_res.dpp->funcs->dpp_set_gamut_remap(pipe_ctx->plane_res.dpp, &adjust);
70ccab60
HW
2318}
2319
6d83a32d
MS
2320
2321static bool dcn10_is_rear_mpo_fix_required(struct pipe_ctx *pipe_ctx, enum dc_color_space colorspace)
2322{
2323 if (pipe_ctx->plane_state && pipe_ctx->plane_state->layer_index > 0 && is_rgb_cspace(colorspace)) {
2324 if (pipe_ctx->top_pipe) {
2325 struct pipe_ctx *top = pipe_ctx->top_pipe;
2326
2327 while (top->top_pipe)
2328 top = top->top_pipe; // Traverse to top pipe_ctx
2329 if (top->plane_state && top->plane_state->layer_index == 0)
2330 return true; // Front MPO plane not hidden
2331 }
2332 }
2333 return false;
2334}
2335
2336static void dcn10_set_csc_adjustment_rgb_mpo_fix(struct pipe_ctx *pipe_ctx, uint16_t *matrix)
2337{
2338 // Override rear plane RGB bias to fix MPO brightness
2339 uint16_t rgb_bias = matrix[3];
2340
2341 matrix[3] = 0;
2342 matrix[7] = 0;
2343 matrix[11] = 0;
2344 pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_adjustment(pipe_ctx->plane_res.dpp, matrix);
2345 matrix[3] = rgb_bias;
2346 matrix[7] = rgb_bias;
2347 matrix[11] = rgb_bias;
2348}
2349
78c77382 2350void dcn10_program_output_csc(struct dc *dc,
3917a470 2351 struct pipe_ctx *pipe_ctx,
abe07e80 2352 enum dc_color_space colorspace,
3917a470
KK
2353 uint16_t *matrix,
2354 int opp_id)
abe07e80 2355{
56ef6ed9 2356 if (pipe_ctx->stream->csc_color_matrix.enable_adjustment == true) {
6d83a32d
MS
2357 if (pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_adjustment != NULL) {
2358
2359 /* MPO is broken with RGB colorspaces when OCSC matrix
2360 * brightness offset >= 0 on DCN1 due to OCSC before MPC
2361 * Blending adds offsets from front + rear to rear plane
2362 *
2363 * Fix is to set RGB bias to 0 on rear plane, top plane
2364 * black value pixels add offset instead of rear + front
2365 */
2366
2367 int16_t rgb_bias = matrix[3];
2368 // matrix[3/7/11] are all the same offset value
2369
2370 if (rgb_bias > 0 && dcn10_is_rear_mpo_fix_required(pipe_ctx, colorspace)) {
2371 dcn10_set_csc_adjustment_rgb_mpo_fix(pipe_ctx, matrix);
2372 } else {
2373 pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_adjustment(pipe_ctx->plane_res.dpp, matrix);
2374 }
2375 }
ea826d64 2376 } else {
afbeb263
YHL
2377 if (pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_default != NULL)
2378 pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_default(pipe_ctx->plane_res.dpp, colorspace);
abe07e80
YHL
2379 }
2380}
de4a2967 2381
78c77382 2382static void dcn10_update_dpp(struct dpp *dpp, struct dc_plane_state *plane_state)
70ccab60 2383{
de4a2967 2384 struct dc_bias_and_scale bns_params = {0};
cbfd33fd 2385
de4a2967 2386 // program the input csc
5fa2ec4f 2387 dpp->funcs->dpp_setup(dpp,
3be5262e 2388 plane_state->format,
de4a2967
S
2389 EXPANSION_MODE_ZERO,
2390 plane_state->input_csc_color_matrix,
7ed4e635
HW
2391 plane_state->color_space,
2392 NULL);
de4a2967
S
2393
2394 //set scale and bias registers
78c77382 2395 build_prescale_params(&bns_params, plane_state);
5fa2ec4f
YHL
2396 if (dpp->funcs->dpp_program_bias_and_scale)
2397 dpp->funcs->dpp_program_bias_and_scale(dpp, &bns_params);
480bd0cf
YS
2398}
2399
60df8441
WW
2400void dcn10_update_visual_confirm_color(struct dc *dc, struct pipe_ctx *pipe_ctx, struct tg_color *color, int mpcc_id)
2401{
2402 struct mpc *mpc = dc->res_pool->mpc;
2403
2404 if (dc->debug.visual_confirm == VISUAL_CONFIRM_HDR)
2405 get_hdr_visual_confirm_color(pipe_ctx, color);
2406 else if (dc->debug.visual_confirm == VISUAL_CONFIRM_SURFACE)
2407 get_surface_visual_confirm_color(pipe_ctx, color);
793c82ee
PTC
2408 else if (dc->debug.visual_confirm == VISUAL_CONFIRM_SWIZZLE)
2409 get_surface_tile_visual_confirm_color(pipe_ctx, color);
60df8441
WW
2410 else
2411 color_space_to_black_color(
2412 dc, pipe_ctx->stream->output_color_space, color);
2413
2414 if (mpc->funcs->set_bg_color)
2415 mpc->funcs->set_bg_color(mpc, color, mpcc_id);
2416}
2417
3ca40237
WW
2418void dcn10_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx)
2419{
480bd0cf 2420 struct hubp *hubp = pipe_ctx->plane_res.hubp;
35fb7220 2421 struct mpcc_blnd_cfg blnd_cfg = {{0}};
feb4a3cd
EB
2422 bool per_pixel_alpha = pipe_ctx->plane_state->per_pixel_alpha && pipe_ctx->bottom_pipe;
2423 int mpcc_id;
2424 struct mpcc *new_mpcc;
2425 struct mpc *mpc = dc->res_pool->mpc;
2426 struct mpc_tree *mpc_tree_params = &(pipe_ctx->stream_res.opp->mpc_tree_params);
480bd0cf 2427
feb4a3cd 2428 blnd_cfg.overlap_only = false;
feb4a3cd
EB
2429 blnd_cfg.global_gain = 0xff;
2430
978f203d
MW
2431 if (per_pixel_alpha && pipe_ctx->plane_state->global_alpha) {
2432 blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA_COMBINED_GLOBAL_GAIN;
2433 blnd_cfg.global_gain = pipe_ctx->plane_state->global_alpha_value;
2434 } else if (per_pixel_alpha) {
2435 blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA;
2436 } else {
2437 blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_GLOBAL_ALPHA;
2438 }
2439
94a4ffd1
GL
2440 if (pipe_ctx->plane_state->global_alpha)
2441 blnd_cfg.global_alpha = pipe_ctx->plane_state->global_alpha_value;
2442 else
2443 blnd_cfg.global_alpha = 0xff;
2444
ad327346
DL
2445 /* DCN1.0 has output CM before MPC which seems to screw with
2446 * pre-multiplied alpha.
2447 */
feb4a3cd 2448 blnd_cfg.pre_multiplied_alpha = is_rgb_cspace(
4fa086b9 2449 pipe_ctx->stream->output_color_space)
ad327346 2450 && per_pixel_alpha;
feb4a3cd 2451
4173c0bd 2452
feb4a3cd
EB
2453 /*
2454 * TODO: remove hack
2455 * Note: currently there is a bug in init_hw such that
2456 * on resume from hibernate, BIOS sets up MPCC0, and
2457 * we do mpcc_remove but the mpcc cannot go to idle
2458 * after remove. This cause us to pick mpcc1 here,
2459 * which causes a pstate hang for yet unknown reason.
2460 */
2461 mpcc_id = hubp->inst;
2462
4173c0bd
EY
2463 /* If there is no full update, don't need to touch MPC tree*/
2464 if (!pipe_ctx->plane_state->update_flags.bits.full_update) {
2465 mpc->funcs->update_blending(mpc, &blnd_cfg, mpcc_id);
60df8441 2466 dc->hwss.update_visual_confirm_color(dc, pipe_ctx, &blnd_cfg.black_color, mpcc_id);
4173c0bd
EY
2467 return;
2468 }
2469
feb4a3cd
EB
2470 /* check if this MPCC is already being used */
2471 new_mpcc = mpc->funcs->get_mpcc_for_dpp(mpc_tree_params, mpcc_id);
2472 /* remove MPCC if being used */
2473 if (new_mpcc != NULL)
2474 mpc->funcs->remove_mpcc(mpc, mpc_tree_params, new_mpcc);
49fac0b4
EB
2475 else
2476 if (dc->debug.sanity_checks)
2477 mpc->funcs->assert_mpcc_idle_before_connect(
2478 dc->res_pool->mpc, mpcc_id);
feb4a3cd
EB
2479
2480 /* Call MPC to insert new plane */
2481 new_mpcc = mpc->funcs->insert_plane(dc->res_pool->mpc,
2482 mpc_tree_params,
2483 &blnd_cfg,
2484 NULL,
2485 NULL,
2486 hubp->inst,
2487 mpcc_id);
60df8441 2488 dc->hwss.update_visual_confirm_color(dc, pipe_ctx, &blnd_cfg.black_color, mpcc_id);
feb4a3cd
EB
2489
2490 ASSERT(new_mpcc != NULL);
2491
2492 hubp->opp_id = pipe_ctx->stream_res.opp->inst;
2493 hubp->mpcc_id = mpcc_id;
480bd0cf
YS
2494}
2495
2496static void update_scaler(struct pipe_ctx *pipe_ctx)
2497{
2498 bool per_pixel_alpha =
2499 pipe_ctx->plane_state->per_pixel_alpha && pipe_ctx->bottom_pipe;
2500
6702a9ac 2501 pipe_ctx->plane_res.scl_data.lb_params.alpha_en = per_pixel_alpha;
a316db72 2502 pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_36BPP;
70ccab60 2503 /* scaler configuration */
d94585a0
YHL
2504 pipe_ctx->plane_res.dpp->funcs->dpp_set_scaler(
2505 pipe_ctx->plane_res.dpp, &pipe_ctx->plane_res.scl_data);
480bd0cf
YS
2506}
2507
78c77382 2508static void dcn10_update_dchubp_dpp(
480bd0cf
YS
2509 struct dc *dc,
2510 struct pipe_ctx *pipe_ctx,
2511 struct dc_state *context)
2512{
f42ea55b 2513 struct dce_hwseq *hws = dc->hwseq;
480bd0cf
YS
2514 struct hubp *hubp = pipe_ctx->plane_res.hubp;
2515 struct dpp *dpp = pipe_ctx->plane_res.dpp;
2516 struct dc_plane_state *plane_state = pipe_ctx->plane_state;
12e2b2d4 2517 struct plane_size size = plane_state->plane_size;
a465feae 2518 unsigned int compat_level = 0;
1f9ce3cf 2519 bool should_divided_by_2 = false;
480bd0cf
YS
2520
2521 /* depends on DML calculation, DPP clock value may change dynamically */
45bb8dd6
YS
2522 /* If request max dpp clk is lower than current dispclk, no need to
2523 * divided by 2
2524 */
16a29dd3 2525 if (plane_state->update_flags.bits.full_update) {
1f9ce3cf 2526
2527 /* new calculated dispclk, dppclk are stored in
2528 * context->bw_ctx.bw.dcn.clk.dispclk_khz / dppclk_khz. current
2529 * dispclk, dppclk are from dc->clk_mgr->clks.dispclk_khz.
2530 * dcn_validate_bandwidth compute new dispclk, dppclk.
2531 * dispclk will put in use after optimize_bandwidth when
2532 * ramp_up_dispclk_with_dpp is called.
2533 * there are two places for dppclk be put in use. One location
2534 * is the same as the location as dispclk. Another is within
2535 * update_dchubp_dpp which happens between pre_bandwidth and
2536 * optimize_bandwidth.
2537 * dppclk updated within update_dchubp_dpp will cause new
2538 * clock values of dispclk and dppclk not be in use at the same
2539 * time. when clocks are decreased, this may cause dppclk is
2540 * lower than previous configuration and let pipe stuck.
2541 * for example, eDP + external dp, change resolution of DP from
2542 * 1920x1080x144hz to 1280x960x60hz.
2543 * before change: dispclk = 337889 dppclk = 337889
2544 * change mode, dcn_validate_bandwidth calculate
2545 * dispclk = 143122 dppclk = 143122
2546 * update_dchubp_dpp be executed before dispclk be updated,
2547 * dispclk = 337889, but dppclk use new value dispclk /2 =
2548 * 168944. this will cause pipe pstate warning issue.
2549 * solution: between pre_bandwidth and optimize_bandwidth, while
2550 * dispclk is going to be decreased, keep dppclk = dispclk
2551 **/
2552 if (context->bw_ctx.bw.dcn.clk.dispclk_khz <
2553 dc->clk_mgr->clks.dispclk_khz)
2554 should_divided_by_2 = false;
2555 else
2556 should_divided_by_2 =
2557 context->bw_ctx.bw.dcn.clk.dppclk_khz <=
2558 dc->clk_mgr->clks.dispclk_khz / 2;
45bb8dd6 2559
f8e413bf
YS
2560 dpp->funcs->dpp_dppclk_control(
2561 dpp,
45bb8dd6 2562 should_divided_by_2,
f8e413bf
YS
2563 true);
2564
ea2e8d92
DL
2565 if (dc->res_pool->dccg)
2566 dc->res_pool->dccg->funcs->update_dpp_dto(
2567 dc->res_pool->dccg,
2568 dpp->inst,
799c5b9c 2569 pipe_ctx->plane_res.bw.dppclk_khz);
ea2e8d92 2570 else
dc88b4a6
EY
2571 dc->clk_mgr->clks.dppclk_khz = should_divided_by_2 ?
2572 dc->clk_mgr->clks.dispclk_khz / 2 :
2573 dc->clk_mgr->clks.dispclk_khz;
480bd0cf
YS
2574 }
2575
2576 /* TODO: Need input parameter to tell current DCHUB pipe tie to which OTG
2577 * VTG is within DCHUBBUB which is commond block share by each pipe HUBP.
2578 * VTG is 1:1 mapping with OTG. Each pipe HUBP will select which VTG
2579 */
2580 if (plane_state->update_flags.bits.full_update) {
c8242b98 2581 hubp->funcs->hubp_vtg_sel(hubp, pipe_ctx->stream_res.tg->inst);
d94585a0 2582
480bd0cf
YS
2583 hubp->funcs->hubp_setup(
2584 hubp,
2585 &pipe_ctx->dlg_regs,
2586 &pipe_ctx->ttu_regs,
2587 &pipe_ctx->rq_regs,
2588 &pipe_ctx->pipe_dlg_param);
1a1adf17
DL
2589 hubp->funcs->hubp_setup_interdependent(
2590 hubp,
2591 &pipe_ctx->dlg_regs,
2592 &pipe_ctx->ttu_regs);
480bd0cf 2593 }
70ccab60 2594
12e2b2d4 2595 size.surface_size = pipe_ctx->plane_res.scl_data.viewport;
70ccab60 2596
480bd0cf
YS
2597 if (plane_state->update_flags.bits.full_update ||
2598 plane_state->update_flags.bits.bpp_change)
78c77382 2599 dcn10_update_dpp(dpp, plane_state);
480bd0cf
YS
2600
2601 if (plane_state->update_flags.bits.full_update ||
94a4ffd1
GL
2602 plane_state->update_flags.bits.per_pixel_alpha_change ||
2603 plane_state->update_flags.bits.global_alpha_change)
f42ea55b 2604 hws->funcs.update_mpcc(dc, pipe_ctx);
480bd0cf
YS
2605
2606 if (plane_state->update_flags.bits.full_update ||
2607 plane_state->update_flags.bits.per_pixel_alpha_change ||
94a4ffd1 2608 plane_state->update_flags.bits.global_alpha_change ||
480bd0cf
YS
2609 plane_state->update_flags.bits.scaling_change ||
2610 plane_state->update_flags.bits.position_change) {
2611 update_scaler(pipe_ctx);
2612 }
2613
2614 if (plane_state->update_flags.bits.full_update ||
16a29dd3
AJ
2615 plane_state->update_flags.bits.scaling_change ||
2616 plane_state->update_flags.bits.position_change) {
480bd0cf
YS
2617 hubp->funcs->mem_program_viewport(
2618 hubp,
2619 &pipe_ctx->plane_res.scl_data.viewport,
cf27a6d1 2620 &pipe_ctx->plane_res.scl_data.viewport_c);
480bd0cf
YS
2621 }
2622
33fd17d9
EY
2623 if (pipe_ctx->stream->cursor_attributes.address.quad_part != 0) {
2624 dc->hwss.set_cursor_position(pipe_ctx);
2625 dc->hwss.set_cursor_attribute(pipe_ctx);
86eb426a
S
2626
2627 if (dc->hwss.set_cursor_sdr_white_level)
2628 dc->hwss.set_cursor_sdr_white_level(pipe_ctx);
33fd17d9
EY
2629 }
2630
480bd0cf
YS
2631 if (plane_state->update_flags.bits.full_update) {
2632 /*gamut remap*/
8a31820b 2633 dc->hwss.program_gamut_remap(pipe_ctx);
480bd0cf 2634
8e357610 2635 dc->hwss.program_output_csc(dc,
480bd0cf
YS
2636 pipe_ctx,
2637 pipe_ctx->stream->output_color_space,
2638 pipe_ctx->stream->csc_color_matrix.matrix,
c0826487 2639 pipe_ctx->stream_res.opp->inst);
480bd0cf
YS
2640 }
2641
2642 if (plane_state->update_flags.bits.full_update ||
3aa0cadd 2643 plane_state->update_flags.bits.pixel_format_change ||
480bd0cf
YS
2644 plane_state->update_flags.bits.horizontal_mirror_change ||
2645 plane_state->update_flags.bits.rotation_change ||
2646 plane_state->update_flags.bits.swizzle_change ||
e9dd9223 2647 plane_state->update_flags.bits.dcc_change ||
f8668c09 2648 plane_state->update_flags.bits.bpp_change ||
ebd084cd
LH
2649 plane_state->update_flags.bits.scaling_change ||
2650 plane_state->update_flags.bits.plane_size_change) {
480bd0cf
YS
2651 hubp->funcs->hubp_program_surface_config(
2652 hubp,
2653 plane_state->format,
2654 &plane_state->tiling_info,
2655 &size,
2656 plane_state->rotation,
2657 &plane_state->dcc,
a465feae
CL
2658 plane_state->horizontal_mirror,
2659 compat_level);
480bd0cf 2660 }
70ccab60 2661
7f914a62
YS
2662 hubp->power_gated = false;
2663
f42ea55b 2664 hws->funcs.update_plane_addr(dc, pipe_ctx);
50d4cfdc 2665
8eb5def9 2666 if (is_pipe_tree_visible(pipe_ctx))
0b7421f0 2667 hubp->funcs->set_blank(hubp, false);
70ccab60
HW
2668}
2669
78c77382 2670void dcn10_blank_pixel_data(
9aef1a31 2671 struct dc *dc,
ea4a2020 2672 struct pipe_ctx *pipe_ctx,
aa5a5777
S
2673 bool blank)
2674{
9aef1a31
S
2675 enum dc_color_space color_space;
2676 struct tg_color black_color = {0};
ea4a2020
EB
2677 struct stream_resource *stream_res = &pipe_ctx->stream_res;
2678 struct dc_stream_state *stream = pipe_ctx->stream;
9aef1a31
S
2679
2680 /* program otg blank color */
2681 color_space = stream->output_color_space;
2682 color_space_to_black_color(dc, color_space, &black_color);
2683
12750d16
EY
2684 /*
2685 * The way 420 is packed, 2 channels carry Y component, 1 channel
2686 * alternate between Cb and Cr, so both channels need the pixel
2687 * value for Y
2688 */
2689 if (stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR420)
2690 black_color.color_r_cr = black_color.color_g_y;
2691
2692
3158223e
EB
2693 if (stream_res->tg->funcs->set_blank_color)
2694 stream_res->tg->funcs->set_blank_color(
2695 stream_res->tg,
9aef1a31 2696 &black_color);
aa5a5777
S
2697
2698 if (!blank) {
3158223e
EB
2699 if (stream_res->tg->funcs->set_blank)
2700 stream_res->tg->funcs->set_blank(stream_res->tg, blank);
4dfdd0ee 2701 if (stream_res->abm) {
474ac4a8 2702 dc->hwss.set_pipe(pipe_ctx);
3158223e 2703 stream_res->abm->funcs->set_abm_level(stream_res->abm, stream->abm_level);
4dfdd0ee 2704 }
aa5a5777 2705 } else if (blank) {
3ba01817 2706 dc->hwss.set_abm_immediate_disable(pipe_ctx);
0976ef31
PH
2707 if (stream_res->tg->funcs->set_blank) {
2708 stream_res->tg->funcs->wait_for_state(stream_res->tg, CRTC_STATE_VBLANK);
3158223e 2709 stream_res->tg->funcs->set_blank(stream_res->tg, blank);
0976ef31 2710 }
aa5a5777
S
2711 }
2712}
9d6f264b 2713
78c77382 2714void dcn10_set_hdr_multiplier(struct pipe_ctx *pipe_ctx)
a4056c2a 2715{
46250a0c 2716 struct fixed31_32 multiplier = pipe_ctx->plane_state->hdr_mult;
a4056c2a
KK
2717 uint32_t hw_mult = 0x1f000; // 1.0 default multiplier
2718 struct custom_float_format fmt;
2719
2720 fmt.exponenta_bits = 6;
2721 fmt.mantissa_bits = 12;
2722 fmt.sign = true;
2723
46250a0c 2724
186a1fb7 2725 if (!dc_fixpt_eq(multiplier, dc_fixpt_from_int(0))) // check != 0
a4056c2a
KK
2726 convert_to_custom_float_format(multiplier, &fmt, &hw_mult);
2727
2728 pipe_ctx->plane_res.dpp->funcs->dpp_set_hdr_multiplier(
2729 pipe_ctx->plane_res.dpp, hw_mult);
2730}
2731
c2437b1f
EB
2732void dcn10_program_pipe(
2733 struct dc *dc,
2734 struct pipe_ctx *pipe_ctx,
2735 struct dc_state *context)
2736{
f42ea55b
AK
2737 struct dce_hwseq *hws = dc->hwseq;
2738
1a2c82a2 2739 if (pipe_ctx->top_pipe == NULL) {
aa5a5777 2740 bool blank = !is_pipe_tree_visible(pipe_ctx);
70ccab60 2741
6b670fa9 2742 pipe_ctx->stream_res.tg->funcs->program_global_sync(
e7e10c46
DL
2743 pipe_ctx->stream_res.tg,
2744 pipe_ctx->pipe_dlg_param.vready_offset,
2745 pipe_ctx->pipe_dlg_param.vstartup_start,
2746 pipe_ctx->pipe_dlg_param.vupdate_offset,
2747 pipe_ctx->pipe_dlg_param.vupdate_width);
b51adc77 2748
6476a7c8 2749 pipe_ctx->stream_res.tg->funcs->set_vtg_params(
5200c401 2750 pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing, true);
6476a7c8 2751
f42ea55b
AK
2752 if (hws->funcs.setup_vupdate_interrupt)
2753 hws->funcs.setup_vupdate_interrupt(dc, pipe_ctx);
bf53769d 2754
f42ea55b 2755 hws->funcs.blank_pixel_data(dc, pipe_ctx, blank);
1a2c82a2 2756 }
cbfd33fd 2757
7f63d8a1
PH
2758 if (pipe_ctx->plane_state->update_flags.bits.full_update)
2759 dcn10_enable_plane(dc, pipe_ctx, context);
e6c258cb 2760
7f63d8a1 2761 dcn10_update_dchubp_dpp(dc, pipe_ctx, context);
e6c258cb 2762
7f63d8a1 2763 hws->funcs.set_hdr_multiplier(pipe_ctx);
e6c258cb 2764
7f63d8a1
PH
2765 if (pipe_ctx->plane_state->update_flags.bits.full_update ||
2766 pipe_ctx->plane_state->update_flags.bits.in_transfer_func_change ||
2767 pipe_ctx->plane_state->update_flags.bits.gamma_change)
2768 hws->funcs.set_input_transfer_func(dc, pipe_ctx, pipe_ctx->plane_state);
e6c258cb 2769
7f63d8a1
PH
2770 /* dcn10_translate_regamma_to_hw_format takes 750us to finish
2771 * only do gamma programming for full update.
2772 * TODO: This can be further optimized/cleaned up
2773 * Always call this for now since it does memcmp inside before
2774 * doing heavy calculation and programming
2775 */
2776 if (pipe_ctx->plane_state->update_flags.bits.full_update)
2777 hws->funcs.set_output_transfer_func(dc, pipe_ctx, pipe_ctx->stream);
e6c258cb
YS
2778}
2779
81b437f5
AL
2780void dcn10_wait_for_pending_cleared(struct dc *dc,
2781 struct dc_state *context)
2782{
2783 struct pipe_ctx *pipe_ctx;
2784 struct timing_generator *tg;
2785 int i;
2786
2787 for (i = 0; i < dc->res_pool->pipe_count; i++) {
2788 pipe_ctx = &context->res_ctx.pipe_ctx[i];
2789 tg = pipe_ctx->stream_res.tg;
2790
2791 /*
2792 * Only wait for top pipe's tg penindg bit
2793 * Also skip if pipe is disabled.
2794 */
2795 if (pipe_ctx->top_pipe ||
2796 !pipe_ctx->stream || !pipe_ctx->plane_state ||
2797 !tg->funcs->is_tg_enabled(tg))
2798 continue;
2799
2800 /*
2801 * Wait for VBLANK then VACTIVE to ensure we get VUPDATE.
2802 * For some reason waiting for OTG_UPDATE_PENDING cleared
2803 * seems to not trigger the update right away, and if we
2804 * lock again before VUPDATE then we don't get a separated
2805 * operation.
2806 */
2807 pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VBLANK);
2808 pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VACTIVE);
2809 }
2810}
2811
bbf5f6c3
AK
2812void dcn10_post_unlock_program_front_end(
2813 struct dc *dc,
2814 struct dc_state *context)
2815{
db70e2c1 2816 int i;
bbf5f6c3
AK
2817
2818 DC_LOGGER_INIT(dc->ctx->logger);
c7e557ab 2819
bbf5f6c3
AK
2820 for (i = 0; i < dc->res_pool->pipe_count; i++) {
2821 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
2822
2823 if (!pipe_ctx->top_pipe &&
2824 !pipe_ctx->prev_odm_pipe &&
2825 pipe_ctx->stream) {
bbf5f6c3
AK
2826 struct timing_generator *tg = pipe_ctx->stream_res.tg;
2827
bbf5f6c3
AK
2828 if (context->stream_status[i].plane_count == 0)
2829 false_optc_underflow_wa(dc, pipe_ctx->stream, tg);
2830 }
2831 }
5cc2687c 2832
e21db6db 2833 for (i = 0; i < dc->res_pool->pipe_count; i++)
bbf5f6c3 2834 if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable)
8a31820b 2835 dc->hwss.disable_plane(dc, &dc->current_state->res_ctx.pipe_ctx[i]);
7144d3cf 2836
08d238e6 2837 for (i = 0; i < dc->res_pool->pipe_count; i++)
bbf5f6c3 2838 if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable) {
08d238e6
ML
2839 dc->hwss.optimize_bandwidth(dc, context);
2840 break;
2841 }
2842
e21db6db
DL
2843 if (dc->hwseq->wa.DEGVIDCN10_254)
2844 hubbub1_wm_change_req_wa(dc->res_pool->hubbub);
70ccab60
HW
2845}
2846
b9d4b330
WC
2847static void dcn10_stereo_hw_frame_pack_wa(struct dc *dc, struct dc_state *context)
2848{
2849 uint8_t i;
2850
2851 for (i = 0; i < context->stream_count; i++) {
2852 if (context->streams[i]->timing.timing_3d_format
2853 == TIMING_3D_FORMAT_HW_FRAME_PACKING) {
2854 /*
2855 * Disable stutter
2856 */
2857 hubbub1_allow_self_refresh_control(dc->res_pool->hubbub, false);
2858 break;
2859 }
2860 }
2861}
2862
78c77382 2863void dcn10_prepare_bandwidth(
fb3466a4 2864 struct dc *dc,
9566b675 2865 struct dc_state *context)
70ccab60 2866{
f42ea55b 2867 struct dce_hwseq *hws = dc->hwseq;
91f28756
YS
2868 struct hubbub *hubbub = dc->res_pool->hubbub;
2869
c910a717 2870 if (dc->debug.sanity_checks)
f42ea55b 2871 hws->funcs.verify_allow_pstate_change_high(dc);
665da60f 2872
e21db6db
DL
2873 if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
2874 if (context->stream_count == 0)
813d20dc 2875 context->bw_ctx.bw.dcn.clk.phyclk_khz = 0;
70ccab60 2876
dc88b4a6
EY
2877 dc->clk_mgr->funcs->update_clocks(
2878 dc->clk_mgr,
24f7dd7e 2879 context,
9566b675
DL
2880 false);
2881 }
2882
89e94bc5 2883 dc->wm_optimized_required = hubbub->funcs->program_watermarks(hubbub,
813d20dc 2884 &context->bw_ctx.bw.dcn.watermarks,
33d7598d 2885 dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000,
9566b675 2886 true);
b9d4b330 2887 dcn10_stereo_hw_frame_pack_wa(dc, context);
9566b675
DL
2888
2889 if (dc->debug.pplib_wm_report_mode == WM_REPORT_OVERRIDE)
2890 dcn_bw_notify_pplib_of_wm_ranges(dc);
2891
2892 if (dc->debug.sanity_checks)
f42ea55b 2893 hws->funcs.verify_allow_pstate_change_high(dc);
9566b675
DL
2894}
2895
78c77382 2896void dcn10_optimize_bandwidth(
9566b675
DL
2897 struct dc *dc,
2898 struct dc_state *context)
2899{
f42ea55b 2900 struct dce_hwseq *hws = dc->hwseq;
91f28756
YS
2901 struct hubbub *hubbub = dc->res_pool->hubbub;
2902
9566b675 2903 if (dc->debug.sanity_checks)
f42ea55b 2904 hws->funcs.verify_allow_pstate_change_high(dc);
9566b675
DL
2905
2906 if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
4c631826 2907 if (context->stream_count == 0)
813d20dc 2908 context->bw_ctx.bw.dcn.clk.phyclk_khz = 0;
9566b675 2909
4c631826
YS
2910 dc->clk_mgr->funcs->update_clocks(
2911 dc->clk_mgr,
2912 context,
9566b675 2913 true);
e21db6db 2914 }
fab55d61 2915
4c631826
YS
2916 hubbub->funcs->program_watermarks(hubbub,
2917 &context->bw_ctx.bw.dcn.watermarks,
2918 dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000,
2919 true);
2920
b9d4b330 2921 dcn10_stereo_hw_frame_pack_wa(dc, context);
2b13d7d3 2922
24f7dd7e
DL
2923 if (dc->debug.pplib_wm_report_mode == WM_REPORT_OVERRIDE)
2924 dcn_bw_notify_pplib_of_wm_ranges(dc);
2925
c910a717 2926 if (dc->debug.sanity_checks)
f42ea55b 2927 hws->funcs.verify_allow_pstate_change_high(dc);
70ccab60
HW
2928}
2929
78c77382 2930void dcn10_set_drr(struct pipe_ctx **pipe_ctx,
49c70ece 2931 int num_pipes, struct dc_crtc_timing_adjust adjust)
70ccab60
HW
2932{
2933 int i = 0;
2934 struct drr_params params = {0};
e63e2491
EB
2935 // DRR set trigger event mapped to OTG_TRIG_A (bit 11) for manual control flow
2936 unsigned int event_triggers = 0x800;
5b5abe95
AK
2937 // Note DRR trigger events are generated regardless of whether num frames met.
2938 unsigned int num_frames = 2;
70ccab60 2939
49c70ece
AL
2940 params.vertical_total_max = adjust.v_total_max;
2941 params.vertical_total_min = adjust.v_total_min;
2942 params.vertical_total_mid = adjust.v_total_mid;
2943 params.vertical_total_mid_frame_num = adjust.v_total_mid_frame_num;
70ccab60 2944 /* TODO: If multiple pipes are to be supported, you need
98e6436d
AK
2945 * some GSL stuff. Static screen triggers may be programmed differently
2946 * as well.
70ccab60
HW
2947 */
2948 for (i = 0; i < num_pipes; i++) {
98e6436d
AK
2949 pipe_ctx[i]->stream_res.tg->funcs->set_drr(
2950 pipe_ctx[i]->stream_res.tg, &params);
49c70ece 2951 if (adjust.v_total_max != 0 && adjust.v_total_min != 0)
98e6436d
AK
2952 pipe_ctx[i]->stream_res.tg->funcs->set_static_screen_control(
2953 pipe_ctx[i]->stream_res.tg,
5b5abe95 2954 event_triggers, num_frames);
70ccab60
HW
2955 }
2956}
2957
78c77382 2958void dcn10_get_position(struct pipe_ctx **pipe_ctx,
70ccab60
HW
2959 int num_pipes,
2960 struct crtc_position *position)
2961{
2962 int i = 0;
2963
2964 /* TODO: handle pipes > 1
2965 */
2966 for (i = 0; i < num_pipes; i++)
6b670fa9 2967 pipe_ctx[i]->stream_res.tg->funcs->get_position(pipe_ctx[i]->stream_res.tg, position);
70ccab60
HW
2968}
2969
78c77382 2970void dcn10_set_static_screen_control(struct pipe_ctx **pipe_ctx,
5b5abe95 2971 int num_pipes, const struct dc_static_screen_params *params)
70ccab60
HW
2972{
2973 unsigned int i;
5b5abe95 2974 unsigned int triggers = 0;
70ccab60 2975
5b5abe95
AK
2976 if (params->triggers.surface_update)
2977 triggers |= 0x80;
2978 if (params->triggers.cursor_update)
2979 triggers |= 0x2;
2980 if (params->triggers.force_trigger)
2981 triggers |= 0x1;
70ccab60
HW
2982
2983 for (i = 0; i < num_pipes; i++)
6b670fa9 2984 pipe_ctx[i]->stream_res.tg->funcs->
5b5abe95
AK
2985 set_static_screen_control(pipe_ctx[i]->stream_res.tg,
2986 triggers, params->num_frames);
70ccab60
HW
2987}
2988
4fac6da2 2989static void dcn10_config_stereo_parameters(
0971c40e 2990 struct dc_stream_state *stream, struct crtc_stereo_flags *flags)
7f5c22d1 2991{
4fa086b9 2992 enum view_3d_format view_format = stream->view_format;
7f5c22d1 2993 enum dc_timing_3d_format timing_3d_format =\
4fa086b9 2994 stream->timing.timing_3d_format;
7f5c22d1
VP
2995 bool non_stereo_timing = false;
2996
2997 if (timing_3d_format == TIMING_3D_FORMAT_NONE ||
2998 timing_3d_format == TIMING_3D_FORMAT_SIDE_BY_SIDE ||
2999 timing_3d_format == TIMING_3D_FORMAT_TOP_AND_BOTTOM)
3000 non_stereo_timing = true;
3001
3002 if (non_stereo_timing == false &&
3003 view_format == VIEW_3D_FORMAT_FRAME_SEQUENTIAL) {
3004
3005 flags->PROGRAM_STEREO = 1;
3006 flags->PROGRAM_POLARITY = 1;
3007 if (timing_3d_format == TIMING_3D_FORMAT_INBAND_FA ||
3008 timing_3d_format == TIMING_3D_FORMAT_DP_HDMI_INBAND_FA ||
3009 timing_3d_format == TIMING_3D_FORMAT_SIDEBAND_FA) {
3010 enum display_dongle_type dongle = \
ceb3dbb4 3011 stream->link->ddc->dongle_type;
7f5c22d1
VP
3012 if (dongle == DISPLAY_DONGLE_DP_VGA_CONVERTER ||
3013 dongle == DISPLAY_DONGLE_DP_DVI_CONVERTER ||
3014 dongle == DISPLAY_DONGLE_DP_HDMI_CONVERTER)
3015 flags->DISABLE_STEREO_DP_SYNC = 1;
3016 }
3017 flags->RIGHT_EYE_POLARITY =\
4fa086b9 3018 stream->timing.flags.RIGHT_EYE_3D_POLARITY;
7f5c22d1
VP
3019 if (timing_3d_format == TIMING_3D_FORMAT_HW_FRAME_PACKING)
3020 flags->FRAME_PACKED = 1;
3021 }
3022
3023 return;
3024}
3025
78c77382 3026void dcn10_setup_stereo(struct pipe_ctx *pipe_ctx, struct dc *dc)
7f5c22d1
VP
3027{
3028 struct crtc_stereo_flags flags = { 0 };
0971c40e 3029 struct dc_stream_state *stream = pipe_ctx->stream;
7f5c22d1
VP
3030
3031 dcn10_config_stereo_parameters(stream, &flags);
3032
c2cd9d04
ML
3033 if (stream->timing.timing_3d_format == TIMING_3D_FORMAT_SIDEBAND_FA) {
3034 if (!dc_set_generic_gpio_for_stereo(true, dc->ctx->gpio_service))
3035 dc_set_generic_gpio_for_stereo(false, dc->ctx->gpio_service);
3036 } else {
3037 dc_set_generic_gpio_for_stereo(false, dc->ctx->gpio_service);
3038 }
3039
72d520d4 3040 pipe_ctx->stream_res.opp->funcs->opp_program_stereo(
a6a6cb34 3041 pipe_ctx->stream_res.opp,
20bdcc99 3042 flags.PROGRAM_STEREO == 1,
72d520d4 3043 &stream->timing);
7f5c22d1 3044
6b670fa9
HW
3045 pipe_ctx->stream_res.tg->funcs->program_stereo(
3046 pipe_ctx->stream_res.tg,
4fa086b9 3047 &stream->timing,
7f5c22d1
VP
3048 &flags);
3049
7f5c22d1
VP
3050 return;
3051}
3052
0b7421f0 3053static struct hubp *get_hubp_by_inst(struct resource_pool *res_pool, int mpcc_inst)
e07f541f
YS
3054{
3055 int i;
3056
0b7421f0
AP
3057 for (i = 0; i < res_pool->pipe_count; i++) {
3058 if (res_pool->hubps[i]->inst == mpcc_inst)
3059 return res_pool->hubps[i];
e07f541f
YS
3060 }
3061 ASSERT(false);
3062 return NULL;
3063}
3064
78c77382 3065void dcn10_wait_for_mpcc_disconnect(
fb3466a4 3066 struct dc *dc,
6be425f3
EY
3067 struct resource_pool *res_pool,
3068 struct pipe_ctx *pipe_ctx)
87480687 3069{
f42ea55b 3070 struct dce_hwseq *hws = dc->hwseq;
e07f541f 3071 int mpcc_inst;
87480687 3072
fb3466a4 3073 if (dc->debug.sanity_checks) {
f42ea55b 3074 hws->funcs.verify_allow_pstate_change_high(dc);
665da60f
CM
3075 }
3076
a6a6cb34 3077 if (!pipe_ctx->stream_res.opp)
6be425f3
EY
3078 return;
3079
e07f541f
YS
3080 for (mpcc_inst = 0; mpcc_inst < MAX_PIPES; mpcc_inst++) {
3081 if (pipe_ctx->stream_res.opp->mpcc_disconnect_pending[mpcc_inst]) {
0b7421f0 3082 struct hubp *hubp = get_hubp_by_inst(res_pool, mpcc_inst);
e07f541f
YS
3083
3084 res_pool->mpc->funcs->wait_for_idle(res_pool->mpc, mpcc_inst);
3085 pipe_ctx->stream_res.opp->mpcc_disconnect_pending[mpcc_inst] = false;
0b7421f0 3086 hubp->funcs->set_blank(hubp, true);
87480687
EY
3087 }
3088 }
6be425f3 3089
fb3466a4 3090 if (dc->debug.sanity_checks) {
f42ea55b 3091 hws->funcs.verify_allow_pstate_change_high(dc);
665da60f
CM
3092 }
3093
87480687
EY
3094}
3095
78c77382 3096bool dcn10_dummy_display_power_gating(
fb3466a4 3097 struct dc *dc,
4fac6da2
DL
3098 uint8_t controller_id,
3099 struct dc_bios *dcb,
2b13d7d3
TC
3100 enum pipe_gating_control power_gating)
3101{
3102 return true;
3103}
3104
78c77382 3105void dcn10_update_pending_status(struct pipe_ctx *pipe_ctx)
2b13d7d3 3106{
3be5262e 3107 struct dc_plane_state *plane_state = pipe_ctx->plane_state;
6b670fa9 3108 struct timing_generator *tg = pipe_ctx->stream_res.tg;
68199bd1 3109 bool flip_pending;
d9758768 3110 struct dc *dc = plane_state->ctx->dc;
2b13d7d3 3111
3be5262e 3112 if (plane_state == NULL)
2b13d7d3
TC
3113 return;
3114
68199bd1 3115 flip_pending = pipe_ctx->plane_res.hubp->funcs->hubp_is_flip_pending(
8feabd03 3116 pipe_ctx->plane_res.hubp);
2b13d7d3 3117
128c075a 3118 plane_state->status.is_flip_pending = plane_state->status.is_flip_pending || flip_pending;
68199bd1
TC
3119
3120 if (!flip_pending)
3121 plane_state->status.current_address = plane_state->status.requested_address;
3122
3123 if (plane_state->status.current_address.type == PLN_ADDR_TYPE_GRPH_STEREO &&
2b13d7d3 3124 tg->funcs->is_stereo_left_eye) {
3be5262e 3125 plane_state->status.is_right_eye =
6b670fa9 3126 !tg->funcs->is_stereo_left_eye(pipe_ctx->stream_res.tg);
2b13d7d3 3127 }
d9758768
GS
3128
3129 if (dc->hwseq->wa_state.disallow_self_refresh_during_multi_plane_transition_applied) {
3130 struct dce_hwseq *hwseq = dc->hwseq;
3131 struct timing_generator *tg = dc->res_pool->timing_generators[0];
3132 unsigned int cur_frame = tg->funcs->get_frame_count(tg);
3133
3134 if (cur_frame != hwseq->wa_state.disallow_self_refresh_during_multi_plane_transition_applied_on_frame) {
3135 struct hubbub *hubbub = dc->res_pool->hubbub;
3136
3137 hubbub->funcs->allow_self_refresh_control(hubbub, !dc->debug.disable_stutter);
3138 hwseq->wa_state.disallow_self_refresh_during_multi_plane_transition_applied = false;
3139 }
3140 }
2b13d7d3 3141}
4fac6da2 3142
78c77382 3143void dcn10_update_dchub(struct dce_hwseq *hws, struct dchub_init_data *dh_data)
afa9104b 3144{
5fc43055 3145 struct hubbub *hubbub = hws->ctx->dc->res_pool->hubbub;
7f93c1de 3146
5fc43055
JP
3147 /* In DCN, this programming sequence is owned by the hubbub */
3148 hubbub->funcs->update_dchub(hubbub, dh_data);
afa9104b 3149}
0cb8a881 3150
c6a228be
NK
3151static bool dcn10_can_pipe_disable_cursor(struct pipe_ctx *pipe_ctx)
3152{
3153 struct pipe_ctx *test_pipe;
5bb0d5cf
KK
3154 const struct scaler_data *scl_data = &pipe_ctx->plane_res.scl_data;
3155 const struct rect *r1 = &scl_data->recout, *r2;
3156 int r1_r = r1->x + r1->width, r1_b = r1->y + r1->height, r2_r, r2_b;
71e433ee 3157 int cur_layer = pipe_ctx->plane_state->layer_index;
5bb0d5cf
KK
3158 bool upper_pipe_exists = false;
3159 struct fixed31_32 one = dc_fixpt_from_int(1);
c6a228be
NK
3160
3161 /**
5bb0d5cf
KK
3162 * Disable the cursor if there's another pipe above this with a
3163 * plane that contains this pipe's viewport to prevent double cursor
3164 * and incorrect scaling artifacts.
c6a228be
NK
3165 */
3166 for (test_pipe = pipe_ctx->top_pipe; test_pipe;
3167 test_pipe = test_pipe->top_pipe) {
3168 if (!test_pipe->plane_state->visible)
3169 continue;
3170
5bb0d5cf
KK
3171 r2 = &test_pipe->plane_res.scl_data.recout;
3172 r2_r = r2->x + r2->width;
3173 r2_b = r2->y + r2->height;
3174
3175 if (r1->x >= r2->x && r1->y >= r2->y && r1_r <= r2_r && r1_b <= r2_b)
c6a228be 3176 return true;
5bb0d5cf
KK
3177
3178 if (test_pipe->plane_state->layer_index < cur_layer)
3179 upper_pipe_exists = true;
c6a228be
NK
3180 }
3181
5bb0d5cf
KK
3182 // if plane scaled, assume an upper plane can handle cursor if it exists.
3183 if (upper_pipe_exists &&
3184 (scl_data->ratios.horz.value != one.value ||
3185 scl_data->ratios.vert.value != one.value))
3186 return true;
3187
c6a228be
NK
3188 return false;
3189}
3190
78c77382 3191void dcn10_set_cursor_position(struct pipe_ctx *pipe_ctx)
33fd17d9
EY
3192{
3193 struct dc_cursor_position pos_cpy = pipe_ctx->stream->cursor_position;
3194 struct hubp *hubp = pipe_ctx->plane_res.hubp;
3195 struct dpp *dpp = pipe_ctx->plane_res.dpp;
3196 struct dc_cursor_mi_param param = {
380604e2 3197 .pixel_clk_khz = pipe_ctx->stream->timing.pix_clk_100hz / 10,
33d7598d 3198 .ref_clk_khz = pipe_ctx->stream->ctx->dc->res_pool->ref_clocks.dchub_ref_clock_inKhz,
39a9f4d8
DL
3199 .viewport = pipe_ctx->plane_res.scl_data.viewport,
3200 .h_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.horz,
3201 .v_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.vert,
08ed681c
DL
3202 .rotation = pipe_ctx->plane_state->rotation,
3203 .mirror = pipe_ctx->plane_state->horizontal_mirror
33fd17d9 3204 };
64267454
ST
3205 bool pipe_split_on = (pipe_ctx->top_pipe != NULL) ||
3206 (pipe_ctx->bottom_pipe != NULL);
aceeeea3
ST
3207 bool odm_combine_on = (pipe_ctx->next_odm_pipe != NULL) ||
3208 (pipe_ctx->prev_odm_pipe != NULL);
4ed79864
AC
3209
3210 int x_plane = pipe_ctx->plane_state->dst_rect.x;
3211 int y_plane = pipe_ctx->plane_state->dst_rect.y;
3212 int x_pos = pos_cpy.x;
3213 int y_pos = pos_cpy.y;
3214
12aec9ef
NK
3215 /**
3216 * DC cursor is stream space, HW cursor is plane space and drawn
3217 * as part of the framebuffer.
3218 *
3219 * Cursor position can't be negative, but hotspot can be used to
3220 * shift cursor out of the plane bounds. Hotspot must be smaller
3221 * than the cursor size.
3222 */
3223
3224 /**
3225 * Translate cursor from stream space to plane space.
3226 *
3227 * If the cursor is scaled then we need to scale the position
3228 * to be in the approximately correct place. We can't do anything
3229 * about the actual size being incorrect, that's a limitation of
3230 * the hardware.
3231 */
d9b20b45
AC
3232 if (param.rotation == ROTATION_ANGLE_90 || param.rotation == ROTATION_ANGLE_270) {
3233 x_pos = (x_pos - x_plane) * pipe_ctx->plane_state->src_rect.height /
3234 pipe_ctx->plane_state->dst_rect.width;
3235 y_pos = (y_pos - y_plane) * pipe_ctx->plane_state->src_rect.width /
3236 pipe_ctx->plane_state->dst_rect.height;
3237 } else {
3238 x_pos = (x_pos - x_plane) * pipe_ctx->plane_state->src_rect.width /
3239 pipe_ctx->plane_state->dst_rect.width;
3240 y_pos = (y_pos - y_plane) * pipe_ctx->plane_state->src_rect.height /
3241 pipe_ctx->plane_state->dst_rect.height;
3242 }
4ed79864 3243
12aec9ef
NK
3244 /**
3245 * If the cursor's source viewport is clipped then we need to
3246 * translate the cursor to appear in the correct position on
3247 * the screen.
3248 *
3249 * This translation isn't affected by scaling so it needs to be
3250 * done *after* we adjust the position for the scale factor.
033baeee
NK
3251 *
3252 * This is only done by opt-in for now since there are still
3253 * some usecases like tiled display that might enable the
3254 * cursor on both streams while expecting dc to clip it.
12aec9ef 3255 */
033baeee
NK
3256 if (pos_cpy.translate_by_source) {
3257 x_pos += pipe_ctx->plane_state->src_rect.x;
3258 y_pos += pipe_ctx->plane_state->src_rect.y;
3259 }
12aec9ef
NK
3260
3261 /**
3262 * If the position is negative then we need to add to the hotspot
3263 * to shift the cursor outside the plane.
3264 */
3265
4ed79864
AC
3266 if (x_pos < 0) {
3267 pos_cpy.x_hotspot -= x_pos;
3268 x_pos = 0;
3269 }
3270
3271 if (y_pos < 0) {
3272 pos_cpy.y_hotspot -= y_pos;
3273 y_pos = 0;
3274 }
3275
3276 pos_cpy.x = (uint32_t)x_pos;
3277 pos_cpy.y = (uint32_t)y_pos;
94a4ffd1 3278
33fd17d9
EY
3279 if (pipe_ctx->plane_state->address.type
3280 == PLN_ADDR_TYPE_VIDEO_PROGRESSIVE)
3281 pos_cpy.enable = false;
c6a228be
NK
3282
3283 if (pos_cpy.enable && dcn10_can_pipe_disable_cursor(pipe_ctx))
3284 pos_cpy.enable = false;
33fd17d9 3285
c0057622
JC
3286 // Swap axis and mirror horizontally
3287 if (param.rotation == ROTATION_ANGLE_90) {
3288 uint32_t temp_x = pos_cpy.x;
64267454 3289
c0057622
JC
3290 pos_cpy.x = pipe_ctx->plane_res.scl_data.viewport.width -
3291 (pos_cpy.y - pipe_ctx->plane_res.scl_data.viewport.x) + pipe_ctx->plane_res.scl_data.viewport.x;
3292 pos_cpy.y = temp_x;
3293 }
3294 // Swap axis and mirror vertically
3295 else if (param.rotation == ROTATION_ANGLE_270) {
3296 uint32_t temp_y = pos_cpy.y;
64267454
ST
3297 int viewport_height =
3298 pipe_ctx->plane_res.scl_data.viewport.height;
aceeeea3
ST
3299 int viewport_y =
3300 pipe_ctx->plane_res.scl_data.viewport.y;
3301
3302 /**
3303 * Display groups that are 1xnY, have pos_cpy.x > 2 * viewport.height
3304 * For pipe split cases:
3305 * - apply offset of viewport.y to normalize pos_cpy.x
3306 * - calculate the pos_cpy.y as before
3307 * - shift pos_cpy.y back by same offset to get final value
3308 * - since we iterate through both pipes, use the lower
3309 * viewport.y for offset
3310 * For non pipe split cases, use the same calculation for
3311 * pos_cpy.y as the 180 degree rotation case below,
3312 * but use pos_cpy.x as our input because we are rotating
3313 * 270 degrees
3314 */
3315 if (pipe_split_on || odm_combine_on) {
3316 int pos_cpy_x_offset;
3317 int other_pipe_viewport_y;
3318
3319 if (pipe_split_on) {
3320 if (pipe_ctx->bottom_pipe) {
3321 other_pipe_viewport_y =
3322 pipe_ctx->bottom_pipe->plane_res.scl_data.viewport.y;
3323 } else {
3324 other_pipe_viewport_y =
3325 pipe_ctx->top_pipe->plane_res.scl_data.viewport.y;
3326 }
3327 } else {
3328 if (pipe_ctx->next_odm_pipe) {
3329 other_pipe_viewport_y =
3330 pipe_ctx->next_odm_pipe->plane_res.scl_data.viewport.y;
3331 } else {
3332 other_pipe_viewport_y =
3333 pipe_ctx->prev_odm_pipe->plane_res.scl_data.viewport.y;
3334 }
3335 }
3336 pos_cpy_x_offset = (viewport_y > other_pipe_viewport_y) ?
3337 other_pipe_viewport_y : viewport_y;
3338 pos_cpy.x -= pos_cpy_x_offset;
64267454
ST
3339 if (pos_cpy.x > viewport_height) {
3340 pos_cpy.x = pos_cpy.x - viewport_height;
3341 pos_cpy.y = viewport_height - pos_cpy.x;
3342 } else {
3343 pos_cpy.y = 2 * viewport_height - pos_cpy.x;
3344 }
aceeeea3
ST
3345 pos_cpy.y += pos_cpy_x_offset;
3346 } else {
3347 pos_cpy.y = (2 * viewport_y) + viewport_height - pos_cpy.x;
3348 }
c0057622
JC
3349 pos_cpy.x = temp_y;
3350 }
3351 // Mirror horizontally and vertically
3352 else if (param.rotation == ROTATION_ANGLE_180) {
64267454
ST
3353 int viewport_width =
3354 pipe_ctx->plane_res.scl_data.viewport.width;
3355 int viewport_x =
3356 pipe_ctx->plane_res.scl_data.viewport.x;
3357
aceeeea3 3358 if (pipe_split_on || odm_combine_on) {
64267454
ST
3359 if (pos_cpy.x >= viewport_width + viewport_x) {
3360 pos_cpy.x = 2 * viewport_width
3361 - pos_cpy.x + 2 * viewport_x;
3362 } else {
3363 uint32_t temp_x = pos_cpy.x;
3364
3365 pos_cpy.x = 2 * viewport_x - pos_cpy.x;
3366 if (temp_x >= viewport_x +
3367 (int)hubp->curs_attr.width || pos_cpy.x
3368 <= (int)hubp->curs_attr.width +
3369 pipe_ctx->plane_state->src_rect.x) {
3370 pos_cpy.x = temp_x + viewport_width;
3371 }
c0057622 3372 }
64267454
ST
3373 } else {
3374 pos_cpy.x = viewport_width - pos_cpy.x + 2 * viewport_x;
c0057622 3375 }
aceeeea3
ST
3376
3377 /**
3378 * Display groups that are 1xnY, have pos_cpy.y > viewport.height
3379 * Calculation:
3380 * delta_from_bottom = viewport.y + viewport.height - pos_cpy.y
3381 * pos_cpy.y_new = viewport.y + delta_from_bottom
3382 * Simplify it as:
3383 * pos_cpy.y = viewport.y * 2 + viewport.height - pos_cpy.y
3384 */
3385 pos_cpy.y = (2 * pipe_ctx->plane_res.scl_data.viewport.y) +
3386 pipe_ctx->plane_res.scl_data.viewport.height - pos_cpy.y;
c0057622
JC
3387 }
3388
33fd17d9 3389 hubp->funcs->set_cursor_position(hubp, &pos_cpy, &param);
94a4ffd1 3390 dpp->funcs->set_cursor_position(dpp, &pos_cpy, &param, hubp->curs_attr.width, hubp->curs_attr.height);
33fd17d9
EY
3391}
3392
78c77382 3393void dcn10_set_cursor_attribute(struct pipe_ctx *pipe_ctx)
33fd17d9
EY
3394{
3395 struct dc_cursor_attributes *attributes = &pipe_ctx->stream->cursor_attributes;
3396
3397 pipe_ctx->plane_res.hubp->funcs->set_cursor_attributes(
3398 pipe_ctx->plane_res.hubp, attributes);
3399 pipe_ctx->plane_res.dpp->funcs->set_cursor_attributes(
5e1613e2 3400 pipe_ctx->plane_res.dpp, attributes);
33fd17d9
EY
3401}
3402
78c77382 3403void dcn10_set_cursor_sdr_white_level(struct pipe_ctx *pipe_ctx)
6d92b5c2
KK
3404{
3405 uint32_t sdr_white_level = pipe_ctx->stream->cursor_attributes.sdr_white_level;
3406 struct fixed31_32 multiplier;
3407 struct dpp_cursor_attributes opt_attr = { 0 };
3408 uint32_t hw_scale = 0x3c00; // 1.0 default multiplier
3409 struct custom_float_format fmt;
3410
3411 if (!pipe_ctx->plane_res.dpp->funcs->set_optional_cursor_attributes)
3412 return;
3413
3414 fmt.exponenta_bits = 5;
3415 fmt.mantissa_bits = 10;
3416 fmt.sign = true;
3417
3418 if (sdr_white_level > 80) {
3419 multiplier = dc_fixpt_from_fraction(sdr_white_level, 80);
3420 convert_to_custom_float_format(multiplier, &fmt, &hw_scale);
3421 }
3422
3423 opt_attr.scale = hw_scale;
3424 opt_attr.bias = 0;
3425
3426 pipe_ctx->plane_res.dpp->funcs->set_optional_cursor_attributes(
3427 pipe_ctx->plane_res.dpp, &opt_attr);
3428}
3429
78c77382
AK
3430/*
3431 * apply_front_porch_workaround TODO FPGA still need?
3432 *
3433 * This is a workaround for a bug that has existed since R5xx and has not been
3434 * fixed keep Front porch at minimum 2 for Interlaced mode or 1 for progressive.
3435 */
d6001aed
YS
3436static void apply_front_porch_workaround(
3437 struct dc_crtc_timing *timing)
3438{
3439 if (timing->flags.INTERLACE == 1) {
3440 if (timing->v_front_porch < 2)
3441 timing->v_front_porch = 2;
3442 } else {
3443 if (timing->v_front_porch < 1)
3444 timing->v_front_porch = 1;
3445 }
3446}
3447
78c77382 3448int dcn10_get_vupdate_offset_from_vsync(struct pipe_ctx *pipe_ctx)
d6001aed 3449{
d6001aed
YS
3450 const struct dc_crtc_timing *dc_crtc_timing = &pipe_ctx->stream->timing;
3451 struct dc_crtc_timing patched_crtc_timing;
3452 int vesa_sync_start;
3453 int asic_blank_end;
3454 int interlace_factor;
3455 int vertical_line_start;
3456
3457 patched_crtc_timing = *dc_crtc_timing;
3458 apply_front_porch_workaround(&patched_crtc_timing);
3459
3460 interlace_factor = patched_crtc_timing.flags.INTERLACE ? 2 : 1;
3461
3462 vesa_sync_start = patched_crtc_timing.v_addressable +
3463 patched_crtc_timing.v_border_bottom +
3464 patched_crtc_timing.v_front_porch;
3465
3466 asic_blank_end = (patched_crtc_timing.v_total -
3467 vesa_sync_start -
3468 patched_crtc_timing.v_border_top)
3469 * interlace_factor;
3470
3471 vertical_line_start = asic_blank_end -
e7e10c46 3472 pipe_ctx->pipe_dlg_param.vstartup_start + 1;
d6001aed
YS
3473
3474 return vertical_line_start;
3475}
3476
63731e73 3477void dcn10_calc_vupdate_position(
78c77382 3478 struct dc *dc,
d6001aed
YS
3479 struct pipe_ctx *pipe_ctx,
3480 uint32_t *start_line,
3481 uint32_t *end_line)
3482{
3483 const struct dc_crtc_timing *dc_crtc_timing = &pipe_ctx->stream->timing;
3484 int vline_int_offset_from_vupdate =
3485 pipe_ctx->stream->periodic_interrupt0.lines_offset;
78c77382 3486 int vupdate_offset_from_vsync = dc->hwss.get_vupdate_offset_from_vsync(pipe_ctx);
d6001aed
YS
3487 int start_position;
3488
3489 if (vline_int_offset_from_vupdate > 0)
3490 vline_int_offset_from_vupdate--;
3491 else if (vline_int_offset_from_vupdate < 0)
3492 vline_int_offset_from_vupdate++;
3493
3494 start_position = vline_int_offset_from_vupdate + vupdate_offset_from_vsync;
3495
3496 if (start_position >= 0)
3497 *start_line = start_position;
3498 else
3499 *start_line = dc_crtc_timing->v_total + start_position - 1;
3500
3501 *end_line = *start_line + 2;
3502
3503 if (*end_line >= dc_crtc_timing->v_total)
3504 *end_line = 2;
3505}
3506
78c77382
AK
3507static void dcn10_cal_vline_position(
3508 struct dc *dc,
d6001aed
YS
3509 struct pipe_ctx *pipe_ctx,
3510 enum vline_select vline,
3511 uint32_t *start_line,
3512 uint32_t *end_line)
3513{
3514 enum vertical_interrupt_ref_point ref_point = INVALID_POINT;
3515
3516 if (vline == VLINE0)
3517 ref_point = pipe_ctx->stream->periodic_interrupt0.ref_point;
3518 else if (vline == VLINE1)
3519 ref_point = pipe_ctx->stream->periodic_interrupt1.ref_point;
3520
3521 switch (ref_point) {
3522 case START_V_UPDATE:
78c77382
AK
3523 dcn10_calc_vupdate_position(
3524 dc,
d6001aed
YS
3525 pipe_ctx,
3526 start_line,
3527 end_line);
3528 break;
3529 case START_V_SYNC:
3530 // Suppose to do nothing because vsync is 0;
3531 break;
3532 default:
3533 ASSERT(0);
3534 break;
3535 }
3536}
3537
78c77382
AK
3538void dcn10_setup_periodic_interrupt(
3539 struct dc *dc,
d6001aed
YS
3540 struct pipe_ctx *pipe_ctx,
3541 enum vline_select vline)
3542{
3543 struct timing_generator *tg = pipe_ctx->stream_res.tg;
3544
3545 if (vline == VLINE0) {
3546 uint32_t start_line = 0;
3547 uint32_t end_line = 0;
3548
78c77382 3549 dcn10_cal_vline_position(dc, pipe_ctx, vline, &start_line, &end_line);
d6001aed
YS
3550
3551 tg->funcs->setup_vertical_interrupt0(tg, start_line, end_line);
3552
3553 } else if (vline == VLINE1) {
3554 pipe_ctx->stream_res.tg->funcs->setup_vertical_interrupt1(
3555 tg,
3556 pipe_ctx->stream->periodic_interrupt1.lines_offset);
3557 }
3558}
3559
78c77382 3560void dcn10_setup_vupdate_interrupt(struct dc *dc, struct pipe_ctx *pipe_ctx)
d6001aed
YS
3561{
3562 struct timing_generator *tg = pipe_ctx->stream_res.tg;
78c77382 3563 int start_line = dc->hwss.get_vupdate_offset_from_vsync(pipe_ctx);
d6001aed
YS
3564
3565 if (start_line < 0) {
3566 ASSERT(0);
3567 start_line = 0;
3568 }
3569
3570 if (tg->funcs->setup_vertical_interrupt2)
3571 tg->funcs->setup_vertical_interrupt2(tg, start_line);
3572}
3573
78c77382 3574void dcn10_unblank_stream(struct pipe_ctx *pipe_ctx,
7fe538a4
CL
3575 struct dc_link_settings *link_settings)
3576{
3577 struct encoder_unblank_param params = { { 0 } };
3578 struct dc_stream_state *stream = pipe_ctx->stream;
3579 struct dc_link *link = stream->link;
f42ea55b 3580 struct dce_hwseq *hws = link->dc->hwseq;
7fe538a4
CL
3581
3582 /* only 3 items below are used by unblank */
3583 params.timing = pipe_ctx->stream->timing;
3584
3585 params.link_settings.link_rate = link_settings->link_rate;
3586
3587 if (dc_is_dp_signal(pipe_ctx->stream->signal)) {
3588 if (params.timing.pixel_encoding == PIXEL_ENCODING_YCBCR420)
3589 params.timing.pix_clk_100hz /= 2;
bc749a88 3590 pipe_ctx->stream_res.stream_enc->funcs->dp_unblank(link, pipe_ctx->stream_res.stream_enc, &params);
7fe538a4
CL
3591 }
3592
3593 if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP) {
f42ea55b 3594 hws->funcs.edp_backlight_control(link, true);
7fe538a4
CL
3595 }
3596}
3597
78c77382 3598void dcn10_send_immediate_sdp_message(struct pipe_ctx *pipe_ctx,
88ccdf1d
LHM
3599 const uint8_t *custom_sdp_message,
3600 unsigned int sdp_message_size)
3601{
3602 if (dc_is_dp_signal(pipe_ctx->stream->signal)) {
3603 pipe_ctx->stream_res.stream_enc->funcs->send_immediate_sdp_message(
3604 pipe_ctx->stream_res.stream_enc,
3605 custom_sdp_message,
3606 sdp_message_size);
3607 }
3608}
78c77382 3609enum dc_status dcn10_set_clock(struct dc *dc,
925f566c
CL
3610 enum dc_clock_type clock_type,
3611 uint32_t clk_khz,
3612 uint32_t stepping)
3613{
3614 struct dc_state *context = dc->current_state;
3615 struct dc_clock_config clock_cfg = {0};
3616 struct dc_clocks *current_clocks = &context->bw_ctx.bw.dcn.clk;
3617
55459456 3618 if (!dc->clk_mgr || !dc->clk_mgr->funcs->get_clock)
925f566c
CL
3619 return DC_FAIL_UNSUPPORTED_1;
3620
55459456
TL
3621 dc->clk_mgr->funcs->get_clock(dc->clk_mgr,
3622 context, clock_type, &clock_cfg);
3623
925f566c
CL
3624 if (clk_khz > clock_cfg.max_clock_khz)
3625 return DC_FAIL_CLK_EXCEED_MAX;
3626
3627 if (clk_khz < clock_cfg.min_clock_khz)
3628 return DC_FAIL_CLK_BELOW_MIN;
3629
3630 if (clk_khz < clock_cfg.bw_requirequired_clock_khz)
3631 return DC_FAIL_CLK_BELOW_CFG_REQUIRED;
3632
3633 /*update internal request clock for update clock use*/
3634 if (clock_type == DC_CLOCK_TYPE_DISPCLK)
3635 current_clocks->dispclk_khz = clk_khz;
3636 else if (clock_type == DC_CLOCK_TYPE_DPPCLK)
3637 current_clocks->dppclk_khz = clk_khz;
3638 else
3639 return DC_ERROR_UNEXPECTED;
3640
55459456 3641 if (dc->clk_mgr->funcs->update_clocks)
925f566c
CL
3642 dc->clk_mgr->funcs->update_clocks(dc->clk_mgr,
3643 context, true);
3644 return DC_OK;
3645
3646}
3647
78c77382 3648void dcn10_get_clock(struct dc *dc,
925f566c
CL
3649 enum dc_clock_type clock_type,
3650 struct dc_clock_config *clock_cfg)
3651{
3652 struct dc_state *context = dc->current_state;
3653
3654 if (dc->clk_mgr && dc->clk_mgr->funcs->get_clock)
3655 dc->clk_mgr->funcs->get_clock(dc->clk_mgr, context, clock_type, clock_cfg);
3656
3657}
712343cd
VL
3658
3659void dcn10_get_dcc_en_bits(struct dc *dc, int *dcc_en_bits)
3660{
3661 struct resource_pool *pool = dc->res_pool;
3662 int i;
3663
3664 for (i = 0; i < pool->pipe_count; i++) {
3665 struct hubp *hubp = pool->hubps[i];
3666 struct dcn_hubp_state *s = &(TO_DCN10_HUBP(hubp)->state);
3667
3668 hubp->funcs->hubp_read_state(hubp);
3669
3670 if (!s->blank_en)
3671 dcc_en_bits[i] = s->dcc_en ? 1 : 0;
3672 }
3673}