Home | History | Annotate | Line # | Download | only in dcn20
      1 /*	$NetBSD: amdgpu_dcn20_hwseq.c,v 1.4 2021/12/19 11:59:31 riastradh Exp $	*/
      2 
      3 /*
      4  * Copyright 2016 Advanced Micro Devices, Inc.
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a
      7  * copy of this software and associated documentation files (the "Software"),
      8  * to deal in the Software without restriction, including without limitation
      9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     10  * and/or sell copies of the Software, and to permit persons to whom the
     11  * Software is furnished to do so, subject to the following conditions:
     12  *
     13  * The above copyright notice and this permission notice shall be included in
     14  * all copies or substantial portions of the Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     19  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
     20  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     21  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     22  * OTHER DEALINGS IN THE SOFTWARE.
     23  *
     24  * Authors: AMD
     25  *
     26  */
     27 #include <sys/cdefs.h>
     28 __KERNEL_RCSID(0, "$NetBSD: amdgpu_dcn20_hwseq.c,v 1.4 2021/12/19 11:59:31 riastradh Exp $");
     29 
     30 #include <linux/delay.h>
     31 
     32 #include "dm_services.h"
     33 #include "basics/dc_common.h"
     34 #include "dm_helpers.h"
     35 #include "core_types.h"
     36 #include "resource.h"
     37 #include "dcn20_resource.h"
     38 #include "dcn20_hwseq.h"
     39 #include "dce/dce_hwseq.h"
     40 #include "dcn20_dsc.h"
     41 #include "dcn20_optc.h"
     42 #include "abm.h"
     43 #include "clk_mgr.h"
     44 #include "dmcu.h"
     45 #include "hubp.h"
     46 #include "timing_generator.h"
     47 #include "opp.h"
     48 #include "ipp.h"
     49 #include "mpc.h"
     50 #include "mcif_wb.h"
     51 #include "dchubbub.h"
     52 #include "reg_helper.h"
     53 #include "dcn10/dcn10_cm_common.h"
     54 #include "dc_link_dp.h"
     55 #include "vm_helper.h"
     56 #include "dccg.h"
     57 
     58 #define DC_LOGGER_INIT(logger)
     59 
     60 #define CTX \
     61 	hws->ctx
     62 #define REG(reg)\
     63 	hws->regs->reg
     64 
     65 #undef FN
     66 #define FN(reg_name, field_name) \
     67 	hws->shifts->field_name, hws->masks->field_name
     68 
     69 static int find_free_gsl_group(const struct dc *dc)
     70 {
     71 	if (dc->res_pool->gsl_groups.gsl_0 == 0)
     72 		return 1;
     73 	if (dc->res_pool->gsl_groups.gsl_1 == 0)
     74 		return 2;
     75 	if (dc->res_pool->gsl_groups.gsl_2 == 0)
     76 		return 3;
     77 
     78 	return 0;
     79 }
     80 
     81 /* NOTE: This is not a generic setup_gsl function (hence the suffix as_lock)
     82  * This is only used to lock pipes in pipe splitting case with immediate flip
     83  * Ordinary MPC/OTG locks suppress VUPDATE which doesn't help with immediate,
     84  * so we get tearing with freesync since we cannot flip multiple pipes
     85  * atomically.
     86  * We use GSL for this:
     87  * - immediate flip: find first available GSL group if not already assigned
     88  *                   program gsl with that group, set current OTG as master
     89  *                   and always us 0x4 = AND of flip_ready from all pipes
     90  * - vsync flip: disable GSL if used
     91  *
     92  * Groups in stream_res are stored as +1 from HW registers, i.e.
     93  * gsl_0 <=> pipe_ctx->stream_res.gsl_group == 1
     94  * Using a magic value like -1 would require tracking all inits/resets
     95  */
     96 static void dcn20_setup_gsl_group_as_lock(
     97 		const struct dc *dc,
     98 		struct pipe_ctx *pipe_ctx,
     99 		bool enable)
    100 {
    101 	struct gsl_params gsl;
    102 	int group_idx;
    103 
    104 	memset(&gsl, 0, sizeof(struct gsl_params));
    105 
    106 	if (enable) {
    107 		/* return if group already assigned since GSL was set up
    108 		 * for vsync flip, we would unassign so it can't be "left over"
    109 		 */
    110 		if (pipe_ctx->stream_res.gsl_group > 0)
    111 			return;
    112 
    113 		group_idx = find_free_gsl_group(dc);
    114 		ASSERT(group_idx != 0);
    115 		pipe_ctx->stream_res.gsl_group = group_idx;
    116 
    117 		/* set gsl group reg field and mark resource used */
    118 		switch (group_idx) {
    119 		case 1:
    120 			gsl.gsl0_en = 1;
    121 			dc->res_pool->gsl_groups.gsl_0 = 1;
    122 			break;
    123 		case 2:
    124 			gsl.gsl1_en = 1;
    125 			dc->res_pool->gsl_groups.gsl_1 = 1;
    126 			break;
    127 		case 3:
    128 			gsl.gsl2_en = 1;
    129 			dc->res_pool->gsl_groups.gsl_2 = 1;
    130 			break;
    131 		default:
    132 			BREAK_TO_DEBUGGER();
    133 			return; // invalid case
    134 		}
    135 		gsl.gsl_master_en = 1;
    136 	} else {
    137 		group_idx = pipe_ctx->stream_res.gsl_group;
    138 		if (group_idx == 0)
    139 			return; // if not in use, just return
    140 
    141 		pipe_ctx->stream_res.gsl_group = 0;
    142 
    143 		/* unset gsl group reg field and mark resource free */
    144 		switch (group_idx) {
    145 		case 1:
    146 			gsl.gsl0_en = 0;
    147 			dc->res_pool->gsl_groups.gsl_0 = 0;
    148 			break;
    149 		case 2:
    150 			gsl.gsl1_en = 0;
    151 			dc->res_pool->gsl_groups.gsl_1 = 0;
    152 			break;
    153 		case 3:
    154 			gsl.gsl2_en = 0;
    155 			dc->res_pool->gsl_groups.gsl_2 = 0;
    156 			break;
    157 		default:
    158 			BREAK_TO_DEBUGGER();
    159 			return;
    160 		}
    161 		gsl.gsl_master_en = 0;
    162 	}
    163 
    164 	/* at this point we want to program whether it's to enable or disable */
    165 	if (pipe_ctx->stream_res.tg->funcs->set_gsl != NULL &&
    166 		pipe_ctx->stream_res.tg->funcs->set_gsl_source_select != NULL) {
    167 		pipe_ctx->stream_res.tg->funcs->set_gsl(
    168 			pipe_ctx->stream_res.tg,
    169 			&gsl);
    170 
    171 		pipe_ctx->stream_res.tg->funcs->set_gsl_source_select(
    172 			pipe_ctx->stream_res.tg, group_idx,	enable ? 4 : 0);
    173 	} else
    174 		BREAK_TO_DEBUGGER();
    175 }
    176 
    177 void dcn20_set_flip_control_gsl(
    178 		struct pipe_ctx *pipe_ctx,
    179 		bool flip_immediate)
    180 {
    181 	if (pipe_ctx && pipe_ctx->plane_res.hubp->funcs->hubp_set_flip_control_surface_gsl)
    182 		pipe_ctx->plane_res.hubp->funcs->hubp_set_flip_control_surface_gsl(
    183 				pipe_ctx->plane_res.hubp, flip_immediate);
    184 
    185 }
    186 
    187 void dcn20_enable_power_gating_plane(
    188 	struct dce_hwseq *hws,
    189 	bool enable)
    190 {
    191 	bool force_on = true; /* disable power gating */
    192 
    193 	if (enable)
    194 		force_on = false;
    195 
    196 	/* DCHUBP0/1/2/3/4/5 */
    197 	REG_UPDATE(DOMAIN0_PG_CONFIG, DOMAIN0_POWER_FORCEON, force_on);
    198 	REG_UPDATE(DOMAIN2_PG_CONFIG, DOMAIN2_POWER_FORCEON, force_on);
    199 	REG_UPDATE(DOMAIN4_PG_CONFIG, DOMAIN4_POWER_FORCEON, force_on);
    200 	REG_UPDATE(DOMAIN6_PG_CONFIG, DOMAIN6_POWER_FORCEON, force_on);
    201 	if (REG(DOMAIN8_PG_CONFIG))
    202 		REG_UPDATE(DOMAIN8_PG_CONFIG, DOMAIN8_POWER_FORCEON, force_on);
    203 	if (REG(DOMAIN10_PG_CONFIG))
    204 		REG_UPDATE(DOMAIN10_PG_CONFIG, DOMAIN8_POWER_FORCEON, force_on);
    205 
    206 	/* DPP0/1/2/3/4/5 */
    207 	REG_UPDATE(DOMAIN1_PG_CONFIG, DOMAIN1_POWER_FORCEON, force_on);
    208 	REG_UPDATE(DOMAIN3_PG_CONFIG, DOMAIN3_POWER_FORCEON, force_on);
    209 	REG_UPDATE(DOMAIN5_PG_CONFIG, DOMAIN5_POWER_FORCEON, force_on);
    210 	REG_UPDATE(DOMAIN7_PG_CONFIG, DOMAIN7_POWER_FORCEON, force_on);
    211 	if (REG(DOMAIN9_PG_CONFIG))
    212 		REG_UPDATE(DOMAIN9_PG_CONFIG, DOMAIN9_POWER_FORCEON, force_on);
    213 	if (REG(DOMAIN11_PG_CONFIG))
    214 		REG_UPDATE(DOMAIN11_PG_CONFIG, DOMAIN9_POWER_FORCEON, force_on);
    215 
    216 	/* DCS0/1/2/3/4/5 */
    217 	REG_UPDATE(DOMAIN16_PG_CONFIG, DOMAIN16_POWER_FORCEON, force_on);
    218 	REG_UPDATE(DOMAIN17_PG_CONFIG, DOMAIN17_POWER_FORCEON, force_on);
    219 	REG_UPDATE(DOMAIN18_PG_CONFIG, DOMAIN18_POWER_FORCEON, force_on);
    220 	if (REG(DOMAIN19_PG_CONFIG))
    221 		REG_UPDATE(DOMAIN19_PG_CONFIG, DOMAIN19_POWER_FORCEON, force_on);
    222 	if (REG(DOMAIN20_PG_CONFIG))
    223 		REG_UPDATE(DOMAIN20_PG_CONFIG, DOMAIN20_POWER_FORCEON, force_on);
    224 	if (REG(DOMAIN21_PG_CONFIG))
    225 		REG_UPDATE(DOMAIN21_PG_CONFIG, DOMAIN21_POWER_FORCEON, force_on);
    226 }
    227 
    228 void dcn20_dccg_init(struct dce_hwseq *hws)
    229 {
    230 	/*
    231 	 * set MICROSECOND_TIME_BASE_DIV
    232 	 * 100Mhz refclk -> 0x120264
    233 	 * 27Mhz refclk -> 0x12021b
    234 	 * 48Mhz refclk -> 0x120230
    235 	 *
    236 	 */
    237 	REG_WRITE(MICROSECOND_TIME_BASE_DIV, 0x120264);
    238 
    239 	/*
    240 	 * set MILLISECOND_TIME_BASE_DIV
    241 	 * 100Mhz refclk -> 0x1186a0
    242 	 * 27Mhz refclk -> 0x106978
    243 	 * 48Mhz refclk -> 0x10bb80
    244 	 *
    245 	 */
    246 	REG_WRITE(MILLISECOND_TIME_BASE_DIV, 0x1186a0);
    247 
    248 	/* This value is dependent on the hardware pipeline delay so set once per SOC */
    249 	REG_WRITE(DISPCLK_FREQ_CHANGE_CNTL, 0x801003c);
    250 }
    251 
    252 void dcn20_disable_vga(
    253 	struct dce_hwseq *hws)
    254 {
    255 	REG_WRITE(D1VGA_CONTROL, 0);
    256 	REG_WRITE(D2VGA_CONTROL, 0);
    257 	REG_WRITE(D3VGA_CONTROL, 0);
    258 	REG_WRITE(D4VGA_CONTROL, 0);
    259 	REG_WRITE(D5VGA_CONTROL, 0);
    260 	REG_WRITE(D6VGA_CONTROL, 0);
    261 }
    262 
    263 void dcn20_program_triple_buffer(
    264 	const struct dc *dc,
    265 	struct pipe_ctx *pipe_ctx,
    266 	bool enable_triple_buffer)
    267 {
    268 	if (pipe_ctx->plane_res.hubp && pipe_ctx->plane_res.hubp->funcs) {
    269 		pipe_ctx->plane_res.hubp->funcs->hubp_enable_tripleBuffer(
    270 			pipe_ctx->plane_res.hubp,
    271 			enable_triple_buffer);
    272 	}
    273 }
    274 
    275 /* Blank pixel data during initialization */
    276 void dcn20_init_blank(
    277 		struct dc *dc,
    278 		struct timing_generator *tg)
    279 {
    280 	struct dce_hwseq *hws = dc->hwseq;
    281 	enum dc_color_space color_space;
    282 	struct tg_color black_color = {0};
    283 	struct output_pixel_processor *opp = NULL;
    284 	struct output_pixel_processor *bottom_opp = NULL;
    285 	uint32_t num_opps, opp_id_src0, opp_id_src1;
    286 	uint32_t otg_active_width, otg_active_height;
    287 
    288 	/* program opp dpg blank color */
    289 	color_space = COLOR_SPACE_SRGB;
    290 	color_space_to_black_color(dc, color_space, &black_color);
    291 
    292 	/* get the OTG active size */
    293 	tg->funcs->get_otg_active_size(tg,
    294 			&otg_active_width,
    295 			&otg_active_height);
    296 
    297 	/* get the OPTC source */
    298 	tg->funcs->get_optc_source(tg, &num_opps, &opp_id_src0, &opp_id_src1);
    299 	ASSERT(opp_id_src0 < dc->res_pool->res_cap->num_opp);
    300 	opp = dc->res_pool->opps[opp_id_src0];
    301 
    302 	if (num_opps == 2) {
    303 		otg_active_width = otg_active_width / 2;
    304 		ASSERT(opp_id_src1 < dc->res_pool->res_cap->num_opp);
    305 		bottom_opp = dc->res_pool->opps[opp_id_src1];
    306 	}
    307 
    308 	opp->funcs->opp_set_disp_pattern_generator(
    309 			opp,
    310 			CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR,
    311 			CONTROLLER_DP_COLOR_SPACE_UDEFINED,
    312 			COLOR_DEPTH_UNDEFINED,
    313 			&black_color,
    314 			otg_active_width,
    315 			otg_active_height);
    316 
    317 	if (num_opps == 2) {
    318 		bottom_opp->funcs->opp_set_disp_pattern_generator(
    319 				bottom_opp,
    320 				CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR,
    321 				CONTROLLER_DP_COLOR_SPACE_UDEFINED,
    322 				COLOR_DEPTH_UNDEFINED,
    323 				&black_color,
    324 				otg_active_width,
    325 				otg_active_height);
    326 	}
    327 
    328 	hws->funcs.wait_for_blank_complete(opp);
    329 }
    330 
    331 void dcn20_dsc_pg_control(
    332 		struct dce_hwseq *hws,
    333 		unsigned int dsc_inst,
    334 		bool power_on)
    335 {
    336 	uint32_t power_gate = power_on ? 0 : 1;
    337 	uint32_t pwr_status = power_on ? 0 : 2;
    338 	uint32_t org_ip_request_cntl = 0;
    339 
    340 	if (hws->ctx->dc->debug.disable_dsc_power_gate)
    341 		return;
    342 
    343 	if (REG(DOMAIN16_PG_CONFIG) == 0)
    344 		return;
    345 
    346 	REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl);
    347 	if (org_ip_request_cntl == 0)
    348 		REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1);
    349 
    350 	switch (dsc_inst) {
    351 	case 0: /* DSC0 */
    352 		REG_UPDATE(DOMAIN16_PG_CONFIG,
    353 				DOMAIN16_POWER_GATE, power_gate);
    354 
    355 		REG_WAIT(DOMAIN16_PG_STATUS,
    356 				DOMAIN16_PGFSM_PWR_STATUS, pwr_status,
    357 				1, 1000);
    358 		break;
    359 	case 1: /* DSC1 */
    360 		REG_UPDATE(DOMAIN17_PG_CONFIG,
    361 				DOMAIN17_POWER_GATE, power_gate);
    362 
    363 		REG_WAIT(DOMAIN17_PG_STATUS,
    364 				DOMAIN17_PGFSM_PWR_STATUS, pwr_status,
    365 				1, 1000);
    366 		break;
    367 	case 2: /* DSC2 */
    368 		REG_UPDATE(DOMAIN18_PG_CONFIG,
    369 				DOMAIN18_POWER_GATE, power_gate);
    370 
    371 		REG_WAIT(DOMAIN18_PG_STATUS,
    372 				DOMAIN18_PGFSM_PWR_STATUS, pwr_status,
    373 				1, 1000);
    374 		break;
    375 	case 3: /* DSC3 */
    376 		REG_UPDATE(DOMAIN19_PG_CONFIG,
    377 				DOMAIN19_POWER_GATE, power_gate);
    378 
    379 		REG_WAIT(DOMAIN19_PG_STATUS,
    380 				DOMAIN19_PGFSM_PWR_STATUS, pwr_status,
    381 				1, 1000);
    382 		break;
    383 	case 4: /* DSC4 */
    384 		REG_UPDATE(DOMAIN20_PG_CONFIG,
    385 				DOMAIN20_POWER_GATE, power_gate);
    386 
    387 		REG_WAIT(DOMAIN20_PG_STATUS,
    388 				DOMAIN20_PGFSM_PWR_STATUS, pwr_status,
    389 				1, 1000);
    390 		break;
    391 	case 5: /* DSC5 */
    392 		REG_UPDATE(DOMAIN21_PG_CONFIG,
    393 				DOMAIN21_POWER_GATE, power_gate);
    394 
    395 		REG_WAIT(DOMAIN21_PG_STATUS,
    396 				DOMAIN21_PGFSM_PWR_STATUS, pwr_status,
    397 				1, 1000);
    398 		break;
    399 	default:
    400 		BREAK_TO_DEBUGGER();
    401 		break;
    402 	}
    403 
    404 	if (org_ip_request_cntl == 0)
    405 		REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0);
    406 }
    407 
    408 void dcn20_dpp_pg_control(
    409 		struct dce_hwseq *hws,
    410 		unsigned int dpp_inst,
    411 		bool power_on)
    412 {
    413 	uint32_t power_gate = power_on ? 0 : 1;
    414 	uint32_t pwr_status = power_on ? 0 : 2;
    415 
    416 	if (hws->ctx->dc->debug.disable_dpp_power_gate)
    417 		return;
    418 	if (REG(DOMAIN1_PG_CONFIG) == 0)
    419 		return;
    420 
    421 	switch (dpp_inst) {
    422 	case 0: /* DPP0 */
    423 		REG_UPDATE(DOMAIN1_PG_CONFIG,
    424 				DOMAIN1_POWER_GATE, power_gate);
    425 
    426 		REG_WAIT(DOMAIN1_PG_STATUS,
    427 				DOMAIN1_PGFSM_PWR_STATUS, pwr_status,
    428 				1, 1000);
    429 		break;
    430 	case 1: /* DPP1 */
    431 		REG_UPDATE(DOMAIN3_PG_CONFIG,
    432 				DOMAIN3_POWER_GATE, power_gate);
    433 
    434 		REG_WAIT(DOMAIN3_PG_STATUS,
    435 				DOMAIN3_PGFSM_PWR_STATUS, pwr_status,
    436 				1, 1000);
    437 		break;
    438 	case 2: /* DPP2 */
    439 		REG_UPDATE(DOMAIN5_PG_CONFIG,
    440 				DOMAIN5_POWER_GATE, power_gate);
    441 
    442 		REG_WAIT(DOMAIN5_PG_STATUS,
    443 				DOMAIN5_PGFSM_PWR_STATUS, pwr_status,
    444 				1, 1000);
    445 		break;
    446 	case 3: /* DPP3 */
    447 		REG_UPDATE(DOMAIN7_PG_CONFIG,
    448 				DOMAIN7_POWER_GATE, power_gate);
    449 
    450 		REG_WAIT(DOMAIN7_PG_STATUS,
    451 				DOMAIN7_PGFSM_PWR_STATUS, pwr_status,
    452 				1, 1000);
    453 		break;
    454 	case 4: /* DPP4 */
    455 		REG_UPDATE(DOMAIN9_PG_CONFIG,
    456 				DOMAIN9_POWER_GATE, power_gate);
    457 
    458 		REG_WAIT(DOMAIN9_PG_STATUS,
    459 				DOMAIN9_PGFSM_PWR_STATUS, pwr_status,
    460 				1, 1000);
    461 		break;
    462 	case 5: /* DPP5 */
    463 		/*
    464 		 * Do not power gate DPP5, should be left at HW default, power on permanently.
    465 		 * PG on Pipe5 is De-featured, attempting to put it to PG state may result in hard
    466 		 * reset.
    467 		 * REG_UPDATE(DOMAIN11_PG_CONFIG,
    468 		 *		DOMAIN11_POWER_GATE, power_gate);
    469 		 *
    470 		 * REG_WAIT(DOMAIN11_PG_STATUS,
    471 		 *		DOMAIN11_PGFSM_PWR_STATUS, pwr_status,
    472 		 * 		1, 1000);
    473 		 */
    474 		break;
    475 	default:
    476 		BREAK_TO_DEBUGGER();
    477 		break;
    478 	}
    479 }
    480 
    481 
    482 void dcn20_hubp_pg_control(
    483 		struct dce_hwseq *hws,
    484 		unsigned int hubp_inst,
    485 		bool power_on)
    486 {
    487 	uint32_t power_gate = power_on ? 0 : 1;
    488 	uint32_t pwr_status = power_on ? 0 : 2;
    489 
    490 	if (hws->ctx->dc->debug.disable_hubp_power_gate)
    491 		return;
    492 	if (REG(DOMAIN0_PG_CONFIG) == 0)
    493 		return;
    494 
    495 	switch (hubp_inst) {
    496 	case 0: /* DCHUBP0 */
    497 		REG_UPDATE(DOMAIN0_PG_CONFIG,
    498 				DOMAIN0_POWER_GATE, power_gate);
    499 
    500 		REG_WAIT(DOMAIN0_PG_STATUS,
    501 				DOMAIN0_PGFSM_PWR_STATUS, pwr_status,
    502 				1, 1000);
    503 		break;
    504 	case 1: /* DCHUBP1 */
    505 		REG_UPDATE(DOMAIN2_PG_CONFIG,
    506 				DOMAIN2_POWER_GATE, power_gate);
    507 
    508 		REG_WAIT(DOMAIN2_PG_STATUS,
    509 				DOMAIN2_PGFSM_PWR_STATUS, pwr_status,
    510 				1, 1000);
    511 		break;
    512 	case 2: /* DCHUBP2 */
    513 		REG_UPDATE(DOMAIN4_PG_CONFIG,
    514 				DOMAIN4_POWER_GATE, power_gate);
    515 
    516 		REG_WAIT(DOMAIN4_PG_STATUS,
    517 				DOMAIN4_PGFSM_PWR_STATUS, pwr_status,
    518 				1, 1000);
    519 		break;
    520 	case 3: /* DCHUBP3 */
    521 		REG_UPDATE(DOMAIN6_PG_CONFIG,
    522 				DOMAIN6_POWER_GATE, power_gate);
    523 
    524 		REG_WAIT(DOMAIN6_PG_STATUS,
    525 				DOMAIN6_PGFSM_PWR_STATUS, pwr_status,
    526 				1, 1000);
    527 		break;
    528 	case 4: /* DCHUBP4 */
    529 		REG_UPDATE(DOMAIN8_PG_CONFIG,
    530 				DOMAIN8_POWER_GATE, power_gate);
    531 
    532 		REG_WAIT(DOMAIN8_PG_STATUS,
    533 				DOMAIN8_PGFSM_PWR_STATUS, pwr_status,
    534 				1, 1000);
    535 		break;
    536 	case 5: /* DCHUBP5 */
    537 		/*
    538 		 * Do not power gate DCHUB5, should be left at HW default, power on permanently.
    539 		 * PG on Pipe5 is De-featured, attempting to put it to PG state may result in hard
    540 		 * reset.
    541 		 * REG_UPDATE(DOMAIN10_PG_CONFIG,
    542 		 *		DOMAIN10_POWER_GATE, power_gate);
    543 		 *
    544 		 * REG_WAIT(DOMAIN10_PG_STATUS,
    545 		 *		DOMAIN10_PGFSM_PWR_STATUS, pwr_status,
    546 		 *		1, 1000);
    547 		 */
    548 		break;
    549 	default:
    550 		BREAK_TO_DEBUGGER();
    551 		break;
    552 	}
    553 }
    554 
    555 
    556 /* disable HW used by plane.
    557  * note:  cannot disable until disconnect is complete
    558  */
    559 void dcn20_plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx)
    560 {
    561 	struct dce_hwseq *hws = dc->hwseq;
    562 	struct hubp *hubp = pipe_ctx->plane_res.hubp;
    563 	struct dpp *dpp = pipe_ctx->plane_res.dpp;
    564 
    565 	dc->hwss.wait_for_mpcc_disconnect(dc, dc->res_pool, pipe_ctx);
    566 
    567 	/* In flip immediate with pipe splitting case GSL is used for
    568 	 * synchronization so we must disable it when the plane is disabled.
    569 	 */
    570 	if (pipe_ctx->stream_res.gsl_group != 0)
    571 		dcn20_setup_gsl_group_as_lock(dc, pipe_ctx, false);
    572 
    573 	dc->hwss.set_flip_control_gsl(pipe_ctx, false);
    574 
    575 	hubp->funcs->hubp_clk_cntl(hubp, false);
    576 
    577 	dpp->funcs->dpp_dppclk_control(dpp, false, false);
    578 
    579 	hubp->power_gated = true;
    580 
    581 	hws->funcs.plane_atomic_power_down(dc,
    582 			pipe_ctx->plane_res.dpp,
    583 			pipe_ctx->plane_res.hubp);
    584 
    585 	pipe_ctx->stream = NULL;
    586 	memset(&pipe_ctx->stream_res, 0, sizeof(pipe_ctx->stream_res));
    587 	memset(&pipe_ctx->plane_res, 0, sizeof(pipe_ctx->plane_res));
    588 	pipe_ctx->top_pipe = NULL;
    589 	pipe_ctx->bottom_pipe = NULL;
    590 	pipe_ctx->plane_state = NULL;
    591 }
    592 
    593 
    594 void dcn20_disable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx)
    595 {
    596 	DC_LOGGER_INIT(dc->ctx->logger);
    597 
    598 	if (!pipe_ctx->plane_res.hubp || pipe_ctx->plane_res.hubp->power_gated)
    599 		return;
    600 
    601 	dcn20_plane_atomic_disable(dc, pipe_ctx);
    602 
    603 	DC_LOG_DC("Power down front end %d\n",
    604 					pipe_ctx->pipe_idx);
    605 }
    606 
    607 enum dc_status dcn20_enable_stream_timing(
    608 		struct pipe_ctx *pipe_ctx,
    609 		struct dc_state *context,
    610 		struct dc *dc)
    611 {
    612 	struct dce_hwseq *hws = dc->hwseq;
    613 	struct dc_stream_state *stream = pipe_ctx->stream;
    614 	struct drr_params params = {0};
    615 	unsigned int event_triggers = 0;
    616 	struct pipe_ctx *odm_pipe;
    617 	int opp_cnt = 1;
    618 	int opp_inst[MAX_PIPES] = { pipe_ctx->stream_res.opp->inst };
    619 
    620 	/* by upper caller loop, pipe0 is parent pipe and be called first.
    621 	 * back end is set up by for pipe0. Other children pipe share back end
    622 	 * with pipe 0. No program is needed.
    623 	 */
    624 	if (pipe_ctx->top_pipe != NULL)
    625 		return DC_OK;
    626 
    627 	/* TODO check if timing_changed, disable stream if timing changed */
    628 
    629 	for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
    630 		opp_inst[opp_cnt] = odm_pipe->stream_res.opp->inst;
    631 		opp_cnt++;
    632 	}
    633 
    634 	if (opp_cnt > 1)
    635 		pipe_ctx->stream_res.tg->funcs->set_odm_combine(
    636 				pipe_ctx->stream_res.tg,
    637 				opp_inst, opp_cnt,
    638 				&pipe_ctx->stream->timing);
    639 
    640 	/* HW program guide assume display already disable
    641 	 * by unplug sequence. OTG assume stop.
    642 	 */
    643 	pipe_ctx->stream_res.tg->funcs->enable_optc_clock(pipe_ctx->stream_res.tg, true);
    644 
    645 	if (false == pipe_ctx->clock_source->funcs->program_pix_clk(
    646 			pipe_ctx->clock_source,
    647 			&pipe_ctx->stream_res.pix_clk_params,
    648 			&pipe_ctx->pll_settings)) {
    649 		BREAK_TO_DEBUGGER();
    650 		return DC_ERROR_UNEXPECTED;
    651 	}
    652 
    653 	pipe_ctx->stream_res.tg->funcs->program_timing(
    654 			pipe_ctx->stream_res.tg,
    655 			&stream->timing,
    656 			pipe_ctx->pipe_dlg_param.vready_offset,
    657 			pipe_ctx->pipe_dlg_param.vstartup_start,
    658 			pipe_ctx->pipe_dlg_param.vupdate_offset,
    659 			pipe_ctx->pipe_dlg_param.vupdate_width,
    660 			pipe_ctx->stream->signal,
    661 			true);
    662 
    663 	for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
    664 		odm_pipe->stream_res.opp->funcs->opp_pipe_clock_control(
    665 				odm_pipe->stream_res.opp,
    666 				true);
    667 
    668 	pipe_ctx->stream_res.opp->funcs->opp_pipe_clock_control(
    669 			pipe_ctx->stream_res.opp,
    670 			true);
    671 
    672 	hws->funcs.blank_pixel_data(dc, pipe_ctx, true);
    673 
    674 	/* VTG is  within DCHUB command block. DCFCLK is always on */
    675 	if (false == pipe_ctx->stream_res.tg->funcs->enable_crtc(pipe_ctx->stream_res.tg)) {
    676 		BREAK_TO_DEBUGGER();
    677 		return DC_ERROR_UNEXPECTED;
    678 	}
    679 
    680 	hws->funcs.wait_for_blank_complete(pipe_ctx->stream_res.opp);
    681 
    682 	params.vertical_total_min = stream->adjust.v_total_min;
    683 	params.vertical_total_max = stream->adjust.v_total_max;
    684 	params.vertical_total_mid = stream->adjust.v_total_mid;
    685 	params.vertical_total_mid_frame_num = stream->adjust.v_total_mid_frame_num;
    686 	if (pipe_ctx->stream_res.tg->funcs->set_drr)
    687 		pipe_ctx->stream_res.tg->funcs->set_drr(
    688 			pipe_ctx->stream_res.tg, &params);
    689 
    690 	// DRR should set trigger event to monitor surface update event
    691 	if (stream->adjust.v_total_min != 0 && stream->adjust.v_total_max != 0)
    692 		event_triggers = 0x80;
    693 	/* Event triggers and num frames initialized for DRR, but can be
    694 	 * later updated for PSR use. Note DRR trigger events are generated
    695 	 * regardless of whether num frames met.
    696 	 */
    697 	if (pipe_ctx->stream_res.tg->funcs->set_static_screen_control)
    698 		pipe_ctx->stream_res.tg->funcs->set_static_screen_control(
    699 				pipe_ctx->stream_res.tg, event_triggers, 2);
    700 
    701 	/* TODO program crtc source select for non-virtual signal*/
    702 	/* TODO program FMT */
    703 	/* TODO setup link_enc */
    704 	/* TODO set stream attributes */
    705 	/* TODO program audio */
    706 	/* TODO enable stream if timing changed */
    707 	/* TODO unblank stream if DP */
    708 
    709 	return DC_OK;
    710 }
    711 
    712 void dcn20_program_output_csc(struct dc *dc,
    713 		struct pipe_ctx *pipe_ctx,
    714 		enum dc_color_space colorspace,
    715 		uint16_t *matrix,
    716 		int opp_id)
    717 {
    718 	struct mpc *mpc = dc->res_pool->mpc;
    719 	enum mpc_output_csc_mode ocsc_mode = MPC_OUTPUT_CSC_COEF_A;
    720 	int mpcc_id = pipe_ctx->plane_res.hubp->inst;
    721 
    722 	if (mpc->funcs->power_on_mpc_mem_pwr)
    723 		mpc->funcs->power_on_mpc_mem_pwr(mpc, mpcc_id, true);
    724 
    725 	if (pipe_ctx->stream->csc_color_matrix.enable_adjustment == true) {
    726 		if (mpc->funcs->set_output_csc != NULL)
    727 			mpc->funcs->set_output_csc(mpc,
    728 					opp_id,
    729 					matrix,
    730 					ocsc_mode);
    731 	} else {
    732 		if (mpc->funcs->set_ocsc_default != NULL)
    733 			mpc->funcs->set_ocsc_default(mpc,
    734 					opp_id,
    735 					colorspace,
    736 					ocsc_mode);
    737 	}
    738 }
    739 
    740 bool dcn20_set_output_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx,
    741 				const struct dc_stream_state *stream)
    742 {
    743 	int mpcc_id = pipe_ctx->plane_res.hubp->inst;
    744 	struct mpc *mpc = pipe_ctx->stream_res.opp->ctx->dc->res_pool->mpc;
    745 	struct pwl_params *params = NULL;
    746 	/*
    747 	 * program OGAM only for the top pipe
    748 	 * if there is a pipe split then fix diagnostic is required:
    749 	 * how to pass OGAM parameter for stream.
    750 	 * if programming for all pipes is required then remove condition
    751 	 * pipe_ctx->top_pipe == NULL ,but then fix the diagnostic.
    752 	 */
    753 	if (mpc->funcs->power_on_mpc_mem_pwr)
    754 		mpc->funcs->power_on_mpc_mem_pwr(mpc, mpcc_id, true);
    755 	if (pipe_ctx->top_pipe == NULL
    756 			&& mpc->funcs->set_output_gamma && stream->out_transfer_func) {
    757 		if (stream->out_transfer_func->type == TF_TYPE_HWPWL)
    758 			params = &stream->out_transfer_func->pwl;
    759 		else if (pipe_ctx->stream->out_transfer_func->type ==
    760 			TF_TYPE_DISTRIBUTED_POINTS &&
    761 			cm_helper_translate_curve_to_hw_format(
    762 			stream->out_transfer_func,
    763 			&mpc->blender_params, false))
    764 			params = &mpc->blender_params;
    765 		/*
    766 		 * there is no ROM
    767 		 */
    768 		if (stream->out_transfer_func->type == TF_TYPE_PREDEFINED)
    769 			BREAK_TO_DEBUGGER();
    770 	}
    771 	/*
    772 	 * if above if is not executed then 'params' equal to 0 and set in bypass
    773 	 */
    774 	mpc->funcs->set_output_gamma(mpc, mpcc_id, params);
    775 
    776 	return true;
    777 }
    778 
    779 bool dcn20_set_blend_lut(
    780 	struct pipe_ctx *pipe_ctx, const struct dc_plane_state *plane_state)
    781 {
    782 	struct dpp *dpp_base = pipe_ctx->plane_res.dpp;
    783 	bool result = true;
    784 	struct pwl_params *blend_lut = NULL;
    785 
    786 	if (plane_state->blend_tf) {
    787 		if (plane_state->blend_tf->type == TF_TYPE_HWPWL)
    788 			blend_lut = &plane_state->blend_tf->pwl;
    789 		else if (plane_state->blend_tf->type == TF_TYPE_DISTRIBUTED_POINTS) {
    790 			cm_helper_translate_curve_to_hw_format(
    791 					plane_state->blend_tf,
    792 					&dpp_base->regamma_params, false);
    793 			blend_lut = &dpp_base->regamma_params;
    794 		}
    795 	}
    796 	result = dpp_base->funcs->dpp_program_blnd_lut(dpp_base, blend_lut);
    797 
    798 	return result;
    799 }
    800 
    801 bool dcn20_set_shaper_3dlut(
    802 	struct pipe_ctx *pipe_ctx, const struct dc_plane_state *plane_state)
    803 {
    804 	struct dpp *dpp_base = pipe_ctx->plane_res.dpp;
    805 	bool result = true;
    806 	struct pwl_params *shaper_lut = NULL;
    807 
    808 	if (plane_state->in_shaper_func) {
    809 		if (plane_state->in_shaper_func->type == TF_TYPE_HWPWL)
    810 			shaper_lut = &plane_state->in_shaper_func->pwl;
    811 		else if (plane_state->in_shaper_func->type == TF_TYPE_DISTRIBUTED_POINTS) {
    812 			cm_helper_translate_curve_to_hw_format(
    813 					plane_state->in_shaper_func,
    814 					&dpp_base->shaper_params, true);
    815 			shaper_lut = &dpp_base->shaper_params;
    816 		}
    817 	}
    818 
    819 	result = dpp_base->funcs->dpp_program_shaper_lut(dpp_base, shaper_lut);
    820 	if (plane_state->lut3d_func &&
    821 		plane_state->lut3d_func->state.bits.initialized == 1)
    822 		result = dpp_base->funcs->dpp_program_3dlut(dpp_base,
    823 								&plane_state->lut3d_func->lut_3d);
    824 	else
    825 		result = dpp_base->funcs->dpp_program_3dlut(dpp_base, NULL);
    826 
    827 	return result;
    828 }
    829 
    830 bool dcn20_set_input_transfer_func(struct dc *dc,
    831 				struct pipe_ctx *pipe_ctx,
    832 				const struct dc_plane_state *plane_state)
    833 {
    834 	struct dce_hwseq *hws = dc->hwseq;
    835 	struct dpp *dpp_base = pipe_ctx->plane_res.dpp;
    836 	const struct dc_transfer_func *tf = NULL;
    837 	bool result = true;
    838 	bool use_degamma_ram = false;
    839 
    840 	if (dpp_base == NULL || plane_state == NULL)
    841 		return false;
    842 
    843 	hws->funcs.set_shaper_3dlut(pipe_ctx, plane_state);
    844 	hws->funcs.set_blend_lut(pipe_ctx, plane_state);
    845 
    846 	if (plane_state->in_transfer_func)
    847 		tf = plane_state->in_transfer_func;
    848 
    849 
    850 	if (tf == NULL) {
    851 		dpp_base->funcs->dpp_set_degamma(dpp_base,
    852 				IPP_DEGAMMA_MODE_BYPASS);
    853 		return true;
    854 	}
    855 
    856 	if (tf->type == TF_TYPE_HWPWL || tf->type == TF_TYPE_DISTRIBUTED_POINTS)
    857 		use_degamma_ram = true;
    858 
    859 	if (use_degamma_ram == true) {
    860 		if (tf->type == TF_TYPE_HWPWL)
    861 			dpp_base->funcs->dpp_program_degamma_pwl(dpp_base,
    862 					&tf->pwl);
    863 		else if (tf->type == TF_TYPE_DISTRIBUTED_POINTS) {
    864 			cm_helper_translate_curve_to_degamma_hw_format(tf,
    865 					&dpp_base->degamma_params);
    866 			dpp_base->funcs->dpp_program_degamma_pwl(dpp_base,
    867 				&dpp_base->degamma_params);
    868 		}
    869 		return true;
    870 	}
    871 	/* handle here the optimized cases when de-gamma ROM could be used.
    872 	 *
    873 	 */
    874 	if (tf->type == TF_TYPE_PREDEFINED) {
    875 		switch (tf->tf) {
    876 		case TRANSFER_FUNCTION_SRGB:
    877 			dpp_base->funcs->dpp_set_degamma(dpp_base,
    878 					IPP_DEGAMMA_MODE_HW_sRGB);
    879 			break;
    880 		case TRANSFER_FUNCTION_BT709:
    881 			dpp_base->funcs->dpp_set_degamma(dpp_base,
    882 					IPP_DEGAMMA_MODE_HW_xvYCC);
    883 			break;
    884 		case TRANSFER_FUNCTION_LINEAR:
    885 			dpp_base->funcs->dpp_set_degamma(dpp_base,
    886 					IPP_DEGAMMA_MODE_BYPASS);
    887 			break;
    888 		case TRANSFER_FUNCTION_PQ:
    889 			dpp_base->funcs->dpp_set_degamma(dpp_base, IPP_DEGAMMA_MODE_USER_PWL);
    890 			cm_helper_translate_curve_to_degamma_hw_format(tf, &dpp_base->degamma_params);
    891 			dpp_base->funcs->dpp_program_degamma_pwl(dpp_base, &dpp_base->degamma_params);
    892 			result = true;
    893 			break;
    894 		default:
    895 			result = false;
    896 			break;
    897 		}
    898 	} else if (tf->type == TF_TYPE_BYPASS)
    899 		dpp_base->funcs->dpp_set_degamma(dpp_base,
    900 				IPP_DEGAMMA_MODE_BYPASS);
    901 	else {
    902 		/*
    903 		 * if we are here, we did not handle correctly.
    904 		 * fix is required for this use case
    905 		 */
    906 		BREAK_TO_DEBUGGER();
    907 		dpp_base->funcs->dpp_set_degamma(dpp_base,
    908 				IPP_DEGAMMA_MODE_BYPASS);
    909 	}
    910 
    911 	return result;
    912 }
    913 
    914 void dcn20_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *pipe_ctx)
    915 {
    916 	struct pipe_ctx *odm_pipe;
    917 	int opp_cnt = 1;
    918 	int opp_inst[MAX_PIPES] = { pipe_ctx->stream_res.opp->inst };
    919 
    920 	for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
    921 		opp_inst[opp_cnt] = odm_pipe->stream_res.opp->inst;
    922 		opp_cnt++;
    923 	}
    924 
    925 	if (opp_cnt > 1)
    926 		pipe_ctx->stream_res.tg->funcs->set_odm_combine(
    927 				pipe_ctx->stream_res.tg,
    928 				opp_inst, opp_cnt,
    929 				&pipe_ctx->stream->timing);
    930 	else
    931 		pipe_ctx->stream_res.tg->funcs->set_odm_bypass(
    932 				pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing);
    933 }
    934 
    935 void dcn20_blank_pixel_data(
    936 		struct dc *dc,
    937 		struct pipe_ctx *pipe_ctx,
    938 		bool blank)
    939 {
    940 	struct tg_color black_color = {0};
    941 	struct stream_resource *stream_res = &pipe_ctx->stream_res;
    942 	struct dc_stream_state *stream = pipe_ctx->stream;
    943 	enum dc_color_space color_space = stream->output_color_space;
    944 	enum controller_dp_test_pattern test_pattern = CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR;
    945 	enum controller_dp_color_space test_pattern_color_space = CONTROLLER_DP_COLOR_SPACE_UDEFINED;
    946 	struct pipe_ctx *odm_pipe;
    947 	int odm_cnt = 1;
    948 
    949 	int width = stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right;
    950 	int height = stream->timing.v_addressable + stream->timing.v_border_bottom + stream->timing.v_border_top;
    951 
    952 	if (stream->link->test_pattern_enabled)
    953 		return;
    954 
    955 	/* get opp dpg blank color */
    956 	color_space_to_black_color(dc, color_space, &black_color);
    957 
    958 	for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
    959 		odm_cnt++;
    960 
    961 	width = width / odm_cnt;
    962 
    963 	if (blank) {
    964 		if (stream_res->abm)
    965 			stream_res->abm->funcs->set_abm_immediate_disable(stream_res->abm);
    966 
    967 		if (dc->debug.visual_confirm != VISUAL_CONFIRM_DISABLE) {
    968 			test_pattern = CONTROLLER_DP_TEST_PATTERN_COLORSQUARES;
    969 			test_pattern_color_space = CONTROLLER_DP_COLOR_SPACE_RGB;
    970 		}
    971 	} else {
    972 		test_pattern = CONTROLLER_DP_TEST_PATTERN_VIDEOMODE;
    973 	}
    974 
    975 	stream_res->opp->funcs->opp_set_disp_pattern_generator(
    976 			stream_res->opp,
    977 			test_pattern,
    978 			test_pattern_color_space,
    979 			stream->timing.display_color_depth,
    980 			&black_color,
    981 			width,
    982 			height);
    983 
    984 	for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
    985 		odm_pipe->stream_res.opp->funcs->opp_set_disp_pattern_generator(
    986 				odm_pipe->stream_res.opp,
    987 				dc->debug.visual_confirm != VISUAL_CONFIRM_DISABLE && blank ?
    988 						CONTROLLER_DP_TEST_PATTERN_COLORRAMP : test_pattern,
    989 				test_pattern_color_space,
    990 				stream->timing.display_color_depth,
    991 				&black_color,
    992 				width,
    993 				height);
    994 	}
    995 
    996 	if (!blank)
    997 		if (stream_res->abm) {
    998 			stream_res->abm->funcs->set_pipe(stream_res->abm, stream_res->tg->inst + 1);
    999 			stream_res->abm->funcs->set_abm_level(stream_res->abm, stream->abm_level);
   1000 		}
   1001 }
   1002 
   1003 
   1004 static void dcn20_power_on_plane(
   1005 	struct dce_hwseq *hws,
   1006 	struct pipe_ctx *pipe_ctx)
   1007 {
   1008 	DC_LOGGER_INIT(hws->ctx->logger);
   1009 	if (REG(DC_IP_REQUEST_CNTL)) {
   1010 		REG_SET(DC_IP_REQUEST_CNTL, 0,
   1011 				IP_REQUEST_EN, 1);
   1012 		dcn20_dpp_pg_control(hws, pipe_ctx->plane_res.dpp->inst, true);
   1013 		dcn20_hubp_pg_control(hws, pipe_ctx->plane_res.hubp->inst, true);
   1014 		REG_SET(DC_IP_REQUEST_CNTL, 0,
   1015 				IP_REQUEST_EN, 0);
   1016 		DC_LOG_DEBUG(
   1017 				"Un-gated front end for pipe %d\n", pipe_ctx->plane_res.hubp->inst);
   1018 	}
   1019 }
   1020 
   1021 void dcn20_enable_plane(
   1022 	struct dc *dc,
   1023 	struct pipe_ctx *pipe_ctx,
   1024 	struct dc_state *context)
   1025 {
   1026 	//if (dc->debug.sanity_checks) {
   1027 	//	dcn10_verify_allow_pstate_change_high(dc);
   1028 	//}
   1029 	dcn20_power_on_plane(dc->hwseq, pipe_ctx);
   1030 
   1031 	/* enable DCFCLK current DCHUB */
   1032 	pipe_ctx->plane_res.hubp->funcs->hubp_clk_cntl(pipe_ctx->plane_res.hubp, true);
   1033 
   1034 	/* initialize HUBP on power up */
   1035 	pipe_ctx->plane_res.hubp->funcs->hubp_init(pipe_ctx->plane_res.hubp);
   1036 
   1037 	/* make sure OPP_PIPE_CLOCK_EN = 1 */
   1038 	pipe_ctx->stream_res.opp->funcs->opp_pipe_clock_control(
   1039 			pipe_ctx->stream_res.opp,
   1040 			true);
   1041 
   1042 /* TODO: enable/disable in dm as per update type.
   1043 	if (plane_state) {
   1044 		DC_LOG_DC(dc->ctx->logger,
   1045 				"Pipe:%d 0x%x: addr hi:0x%x, "
   1046 				"addr low:0x%x, "
   1047 				"src: %d, %d, %d,"
   1048 				" %d; dst: %d, %d, %d, %d;\n",
   1049 				pipe_ctx->pipe_idx,
   1050 				plane_state,
   1051 				plane_state->address.grph.addr.high_part,
   1052 				plane_state->address.grph.addr.low_part,
   1053 				plane_state->src_rect.x,
   1054 				plane_state->src_rect.y,
   1055 				plane_state->src_rect.width,
   1056 				plane_state->src_rect.height,
   1057 				plane_state->dst_rect.x,
   1058 				plane_state->dst_rect.y,
   1059 				plane_state->dst_rect.width,
   1060 				plane_state->dst_rect.height);
   1061 
   1062 		DC_LOG_DC(dc->ctx->logger,
   1063 				"Pipe %d: width, height, x, y         format:%d\n"
   1064 				"viewport:%d, %d, %d, %d\n"
   1065 				"recout:  %d, %d, %d, %d\n",
   1066 				pipe_ctx->pipe_idx,
   1067 				plane_state->format,
   1068 				pipe_ctx->plane_res.scl_data.viewport.width,
   1069 				pipe_ctx->plane_res.scl_data.viewport.height,
   1070 				pipe_ctx->plane_res.scl_data.viewport.x,
   1071 				pipe_ctx->plane_res.scl_data.viewport.y,
   1072 				pipe_ctx->plane_res.scl_data.recout.width,
   1073 				pipe_ctx->plane_res.scl_data.recout.height,
   1074 				pipe_ctx->plane_res.scl_data.recout.x,
   1075 				pipe_ctx->plane_res.scl_data.recout.y);
   1076 		print_rq_dlg_ttu(dc, pipe_ctx);
   1077 	}
   1078 */
   1079 	if (dc->vm_pa_config.valid) {
   1080 		struct vm_system_aperture_param apt;
   1081 
   1082 		apt.sys_default.quad_part = 0;
   1083 
   1084 		apt.sys_low.quad_part = dc->vm_pa_config.system_aperture.start_addr;
   1085 		apt.sys_high.quad_part = dc->vm_pa_config.system_aperture.end_addr;
   1086 
   1087 		// Program system aperture settings
   1088 		pipe_ctx->plane_res.hubp->funcs->hubp_set_vm_system_aperture_settings(pipe_ctx->plane_res.hubp, &apt);
   1089 	}
   1090 
   1091 //	if (dc->debug.sanity_checks) {
   1092 //		dcn10_verify_allow_pstate_change_high(dc);
   1093 //	}
   1094 }
   1095 
   1096 
   1097 void dcn20_pipe_control_lock_global(
   1098 		struct dc *dc,
   1099 		struct pipe_ctx *pipe,
   1100 		bool lock)
   1101 {
   1102 	if (lock) {
   1103 		pipe->stream_res.tg->funcs->lock_doublebuffer_enable(
   1104 				pipe->stream_res.tg);
   1105 		pipe->stream_res.tg->funcs->lock(pipe->stream_res.tg);
   1106 	} else {
   1107 		pipe->stream_res.tg->funcs->unlock(pipe->stream_res.tg);
   1108 		pipe->stream_res.tg->funcs->wait_for_state(pipe->stream_res.tg,
   1109 				CRTC_STATE_VACTIVE);
   1110 		pipe->stream_res.tg->funcs->wait_for_state(pipe->stream_res.tg,
   1111 				CRTC_STATE_VBLANK);
   1112 		pipe->stream_res.tg->funcs->wait_for_state(pipe->stream_res.tg,
   1113 				CRTC_STATE_VACTIVE);
   1114 		pipe->stream_res.tg->funcs->lock_doublebuffer_disable(
   1115 				pipe->stream_res.tg);
   1116 	}
   1117 }
   1118 
   1119 void dcn20_pipe_control_lock(
   1120 	struct dc *dc,
   1121 	struct pipe_ctx *pipe,
   1122 	bool lock)
   1123 {
   1124 	bool flip_immediate = false;
   1125 
   1126 	/* use TG master update lock to lock everything on the TG
   1127 	 * therefore only top pipe need to lock
   1128 	 */
   1129 	if (pipe->top_pipe)
   1130 		return;
   1131 
   1132 	if (pipe->plane_state != NULL)
   1133 		flip_immediate = pipe->plane_state->flip_immediate;
   1134 
   1135 	if (flip_immediate && lock) {
   1136 		const int TIMEOUT_FOR_FLIP_PENDING = 100000;
   1137 		int i;
   1138 
   1139 		for (i = 0; i < TIMEOUT_FOR_FLIP_PENDING; ++i) {
   1140 			if (!pipe->plane_res.hubp->funcs->hubp_is_flip_pending(pipe->plane_res.hubp))
   1141 				break;
   1142 			udelay(1);
   1143 		}
   1144 
   1145 		if (pipe->bottom_pipe != NULL) {
   1146 			for (i = 0; i < TIMEOUT_FOR_FLIP_PENDING; ++i) {
   1147 				if (!pipe->bottom_pipe->plane_res.hubp->funcs->hubp_is_flip_pending(pipe->bottom_pipe->plane_res.hubp))
   1148 					break;
   1149 				udelay(1);
   1150 			}
   1151 		}
   1152 	}
   1153 
   1154 	/* In flip immediate and pipe splitting case, we need to use GSL
   1155 	 * for synchronization. Only do setup on locking and on flip type change.
   1156 	 */
   1157 	if (lock && pipe->bottom_pipe != NULL)
   1158 		if ((flip_immediate && pipe->stream_res.gsl_group == 0) ||
   1159 		    (!flip_immediate && pipe->stream_res.gsl_group > 0))
   1160 			dcn20_setup_gsl_group_as_lock(dc, pipe, flip_immediate);
   1161 
   1162 	if (pipe->plane_state != NULL && pipe->plane_state->triplebuffer_flips) {
   1163 		if (lock)
   1164 			pipe->stream_res.tg->funcs->triplebuffer_lock(pipe->stream_res.tg);
   1165 		else
   1166 			pipe->stream_res.tg->funcs->triplebuffer_unlock(pipe->stream_res.tg);
   1167 	} else {
   1168 		if (lock)
   1169 			pipe->stream_res.tg->funcs->lock(pipe->stream_res.tg);
   1170 		else
   1171 			pipe->stream_res.tg->funcs->unlock(pipe->stream_res.tg);
   1172 	}
   1173 }
   1174 
   1175 static void dcn20_detect_pipe_changes(struct pipe_ctx *old_pipe, struct pipe_ctx *new_pipe)
   1176 {
   1177 	new_pipe->update_flags.raw = 0;
   1178 
   1179 	/* Exit on unchanged, unused pipe */
   1180 	if (!old_pipe->plane_state && !new_pipe->plane_state)
   1181 		return;
   1182 	/* Detect pipe enable/disable */
   1183 	if (!old_pipe->plane_state && new_pipe->plane_state) {
   1184 		new_pipe->update_flags.bits.enable = 1;
   1185 		new_pipe->update_flags.bits.mpcc = 1;
   1186 		new_pipe->update_flags.bits.dppclk = 1;
   1187 		new_pipe->update_flags.bits.hubp_interdependent = 1;
   1188 		new_pipe->update_flags.bits.hubp_rq_dlg_ttu = 1;
   1189 		new_pipe->update_flags.bits.gamut_remap = 1;
   1190 		new_pipe->update_flags.bits.scaler = 1;
   1191 		new_pipe->update_flags.bits.viewport = 1;
   1192 		if (!new_pipe->top_pipe && !new_pipe->prev_odm_pipe) {
   1193 			new_pipe->update_flags.bits.odm = 1;
   1194 			new_pipe->update_flags.bits.global_sync = 1;
   1195 		}
   1196 		return;
   1197 	}
   1198 	if (old_pipe->plane_state && !new_pipe->plane_state) {
   1199 		new_pipe->update_flags.bits.disable = 1;
   1200 		return;
   1201 	}
   1202 
   1203 	/* Detect top pipe only changes */
   1204 	if (!new_pipe->top_pipe && !new_pipe->prev_odm_pipe) {
   1205 		/* Detect odm changes */
   1206 		if ((old_pipe->next_odm_pipe && new_pipe->next_odm_pipe
   1207 			&& old_pipe->next_odm_pipe->pipe_idx != new_pipe->next_odm_pipe->pipe_idx)
   1208 				|| (!old_pipe->next_odm_pipe && new_pipe->next_odm_pipe)
   1209 				|| (old_pipe->next_odm_pipe && !new_pipe->next_odm_pipe)
   1210 				|| old_pipe->stream_res.opp != new_pipe->stream_res.opp)
   1211 			new_pipe->update_flags.bits.odm = 1;
   1212 
   1213 		/* Detect global sync changes */
   1214 		if (old_pipe->pipe_dlg_param.vready_offset != new_pipe->pipe_dlg_param.vready_offset
   1215 				|| old_pipe->pipe_dlg_param.vstartup_start != new_pipe->pipe_dlg_param.vstartup_start
   1216 				|| old_pipe->pipe_dlg_param.vupdate_offset != new_pipe->pipe_dlg_param.vupdate_offset
   1217 				|| old_pipe->pipe_dlg_param.vupdate_width != new_pipe->pipe_dlg_param.vupdate_width)
   1218 			new_pipe->update_flags.bits.global_sync = 1;
   1219 	}
   1220 
   1221 	/*
   1222 	 * Detect opp / tg change, only set on change, not on enable
   1223 	 * Assume mpcc inst = pipe index, if not this code needs to be updated
   1224 	 * since mpcc is what is affected by these. In fact all of our sequence
   1225 	 * makes this assumption at the moment with how hubp reset is matched to
   1226 	 * same index mpcc reset.
   1227 	 */
   1228 	if (old_pipe->stream_res.opp != new_pipe->stream_res.opp)
   1229 		new_pipe->update_flags.bits.opp_changed = 1;
   1230 	if (old_pipe->stream_res.tg != new_pipe->stream_res.tg)
   1231 		new_pipe->update_flags.bits.tg_changed = 1;
   1232 
   1233 	/* Detect mpcc blending changes, only dpp inst and bot matter here */
   1234 	if (old_pipe->plane_res.dpp != new_pipe->plane_res.dpp
   1235 			|| old_pipe->stream_res.opp != new_pipe->stream_res.opp
   1236 			|| (!old_pipe->bottom_pipe && new_pipe->bottom_pipe)
   1237 			|| (old_pipe->bottom_pipe && !new_pipe->bottom_pipe)
   1238 			|| (old_pipe->bottom_pipe && new_pipe->bottom_pipe
   1239 				&& old_pipe->bottom_pipe->plane_res.mpcc_inst
   1240 					!= new_pipe->bottom_pipe->plane_res.mpcc_inst))
   1241 		new_pipe->update_flags.bits.mpcc = 1;
   1242 
   1243 	/* Detect dppclk change */
   1244 	if (old_pipe->plane_res.bw.dppclk_khz != new_pipe->plane_res.bw.dppclk_khz)
   1245 		new_pipe->update_flags.bits.dppclk = 1;
   1246 
   1247 	/* Check for scl update */
   1248 	if (memcmp(&old_pipe->plane_res.scl_data, &new_pipe->plane_res.scl_data, sizeof(struct scaler_data)))
   1249 			new_pipe->update_flags.bits.scaler = 1;
   1250 	/* Check for vp update */
   1251 	if (memcmp(&old_pipe->plane_res.scl_data.viewport, &new_pipe->plane_res.scl_data.viewport, sizeof(struct rect))
   1252 			|| memcmp(&old_pipe->plane_res.scl_data.viewport_c,
   1253 				&new_pipe->plane_res.scl_data.viewport_c, sizeof(struct rect)))
   1254 		new_pipe->update_flags.bits.viewport = 1;
   1255 
   1256 	/* Detect dlg/ttu/rq updates */
   1257 	{
   1258 		struct _vcs_dpi_display_dlg_regs_st old_dlg_attr = old_pipe->dlg_regs;
   1259 		struct _vcs_dpi_display_ttu_regs_st old_ttu_attr = old_pipe->ttu_regs;
   1260 		struct _vcs_dpi_display_dlg_regs_st *new_dlg_attr = &new_pipe->dlg_regs;
   1261 		struct _vcs_dpi_display_ttu_regs_st *new_ttu_attr = &new_pipe->ttu_regs;
   1262 
   1263 		/* Detect pipe interdependent updates */
   1264 		if (old_dlg_attr.dst_y_prefetch != new_dlg_attr->dst_y_prefetch ||
   1265 				old_dlg_attr.vratio_prefetch != new_dlg_attr->vratio_prefetch ||
   1266 				old_dlg_attr.vratio_prefetch_c != new_dlg_attr->vratio_prefetch_c ||
   1267 				old_dlg_attr.dst_y_per_vm_vblank != new_dlg_attr->dst_y_per_vm_vblank ||
   1268 				old_dlg_attr.dst_y_per_row_vblank != new_dlg_attr->dst_y_per_row_vblank ||
   1269 				old_dlg_attr.dst_y_per_vm_flip != new_dlg_attr->dst_y_per_vm_flip ||
   1270 				old_dlg_attr.dst_y_per_row_flip != new_dlg_attr->dst_y_per_row_flip ||
   1271 				old_dlg_attr.refcyc_per_meta_chunk_vblank_l != new_dlg_attr->refcyc_per_meta_chunk_vblank_l ||
   1272 				old_dlg_attr.refcyc_per_meta_chunk_vblank_c != new_dlg_attr->refcyc_per_meta_chunk_vblank_c ||
   1273 				old_dlg_attr.refcyc_per_meta_chunk_flip_l != new_dlg_attr->refcyc_per_meta_chunk_flip_l ||
   1274 				old_dlg_attr.refcyc_per_line_delivery_pre_l != new_dlg_attr->refcyc_per_line_delivery_pre_l ||
   1275 				old_dlg_attr.refcyc_per_line_delivery_pre_c != new_dlg_attr->refcyc_per_line_delivery_pre_c ||
   1276 				old_ttu_attr.refcyc_per_req_delivery_pre_l != new_ttu_attr->refcyc_per_req_delivery_pre_l ||
   1277 				old_ttu_attr.refcyc_per_req_delivery_pre_c != new_ttu_attr->refcyc_per_req_delivery_pre_c ||
   1278 				old_ttu_attr.refcyc_per_req_delivery_pre_cur0 != new_ttu_attr->refcyc_per_req_delivery_pre_cur0 ||
   1279 				old_ttu_attr.refcyc_per_req_delivery_pre_cur1 != new_ttu_attr->refcyc_per_req_delivery_pre_cur1 ||
   1280 				old_ttu_attr.min_ttu_vblank != new_ttu_attr->min_ttu_vblank ||
   1281 				old_ttu_attr.qos_level_flip != new_ttu_attr->qos_level_flip) {
   1282 			old_dlg_attr.dst_y_prefetch = new_dlg_attr->dst_y_prefetch;
   1283 			old_dlg_attr.vratio_prefetch = new_dlg_attr->vratio_prefetch;
   1284 			old_dlg_attr.vratio_prefetch_c = new_dlg_attr->vratio_prefetch_c;
   1285 			old_dlg_attr.dst_y_per_vm_vblank = new_dlg_attr->dst_y_per_vm_vblank;
   1286 			old_dlg_attr.dst_y_per_row_vblank = new_dlg_attr->dst_y_per_row_vblank;
   1287 			old_dlg_attr.dst_y_per_vm_flip = new_dlg_attr->dst_y_per_vm_flip;
   1288 			old_dlg_attr.dst_y_per_row_flip = new_dlg_attr->dst_y_per_row_flip;
   1289 			old_dlg_attr.refcyc_per_meta_chunk_vblank_l = new_dlg_attr->refcyc_per_meta_chunk_vblank_l;
   1290 			old_dlg_attr.refcyc_per_meta_chunk_vblank_c = new_dlg_attr->refcyc_per_meta_chunk_vblank_c;
   1291 			old_dlg_attr.refcyc_per_meta_chunk_flip_l = new_dlg_attr->refcyc_per_meta_chunk_flip_l;
   1292 			old_dlg_attr.refcyc_per_line_delivery_pre_l = new_dlg_attr->refcyc_per_line_delivery_pre_l;
   1293 			old_dlg_attr.refcyc_per_line_delivery_pre_c = new_dlg_attr->refcyc_per_line_delivery_pre_c;
   1294 			old_ttu_attr.refcyc_per_req_delivery_pre_l = new_ttu_attr->refcyc_per_req_delivery_pre_l;
   1295 			old_ttu_attr.refcyc_per_req_delivery_pre_c = new_ttu_attr->refcyc_per_req_delivery_pre_c;
   1296 			old_ttu_attr.refcyc_per_req_delivery_pre_cur0 = new_ttu_attr->refcyc_per_req_delivery_pre_cur0;
   1297 			old_ttu_attr.refcyc_per_req_delivery_pre_cur1 = new_ttu_attr->refcyc_per_req_delivery_pre_cur1;
   1298 			old_ttu_attr.min_ttu_vblank = new_ttu_attr->min_ttu_vblank;
   1299 			old_ttu_attr.qos_level_flip = new_ttu_attr->qos_level_flip;
   1300 			new_pipe->update_flags.bits.hubp_interdependent = 1;
   1301 		}
   1302 		/* Detect any other updates to ttu/rq/dlg */
   1303 		if (memcmp(&old_dlg_attr, &new_pipe->dlg_regs, sizeof(old_dlg_attr)) ||
   1304 				memcmp(&old_ttu_attr, &new_pipe->ttu_regs, sizeof(old_ttu_attr)) ||
   1305 				memcmp(&old_pipe->rq_regs, &new_pipe->rq_regs, sizeof(old_pipe->rq_regs)))
   1306 			new_pipe->update_flags.bits.hubp_rq_dlg_ttu = 1;
   1307 	}
   1308 }
   1309 
   1310 static void dcn20_update_dchubp_dpp(
   1311 	struct dc *dc,
   1312 	struct pipe_ctx *pipe_ctx,
   1313 	struct dc_state *context)
   1314 {
   1315 	struct dce_hwseq *hws = dc->hwseq;
   1316 	struct hubp *hubp = pipe_ctx->plane_res.hubp;
   1317 	struct dpp *dpp = pipe_ctx->plane_res.dpp;
   1318 	struct dc_plane_state *plane_state = pipe_ctx->plane_state;
   1319 	bool viewport_changed = false;
   1320 
   1321 	if (pipe_ctx->update_flags.bits.dppclk)
   1322 		dpp->funcs->dpp_dppclk_control(dpp, false, true);
   1323 
   1324 	/* TODO: Need input parameter to tell current DCHUB pipe tie to which OTG
   1325 	 * VTG is within DCHUBBUB which is commond block share by each pipe HUBP.
   1326 	 * VTG is 1:1 mapping with OTG. Each pipe HUBP will select which VTG
   1327 	 */
   1328 	if (pipe_ctx->update_flags.bits.hubp_rq_dlg_ttu) {
   1329 		hubp->funcs->hubp_vtg_sel(hubp, pipe_ctx->stream_res.tg->inst);
   1330 
   1331 		hubp->funcs->hubp_setup(
   1332 			hubp,
   1333 			&pipe_ctx->dlg_regs,
   1334 			&pipe_ctx->ttu_regs,
   1335 			&pipe_ctx->rq_regs,
   1336 			&pipe_ctx->pipe_dlg_param);
   1337 	}
   1338 	if (pipe_ctx->update_flags.bits.hubp_interdependent)
   1339 		hubp->funcs->hubp_setup_interdependent(
   1340 			hubp,
   1341 			&pipe_ctx->dlg_regs,
   1342 			&pipe_ctx->ttu_regs);
   1343 
   1344 	if (pipe_ctx->update_flags.bits.enable ||
   1345 			plane_state->update_flags.bits.bpp_change ||
   1346 			plane_state->update_flags.bits.input_csc_change ||
   1347 			plane_state->update_flags.bits.color_space_change ||
   1348 			plane_state->update_flags.bits.coeff_reduction_change) {
   1349 		struct dc_bias_and_scale bns_params = {0};
   1350 
   1351 		// program the input csc
   1352 		dpp->funcs->dpp_setup(dpp,
   1353 				plane_state->format,
   1354 				EXPANSION_MODE_ZERO,
   1355 				plane_state->input_csc_color_matrix,
   1356 				plane_state->color_space,
   1357 				NULL);
   1358 
   1359 		if (dpp->funcs->dpp_program_bias_and_scale) {
   1360 			//TODO :for CNVC set scale and bias registers if necessary
   1361 			build_prescale_params(&bns_params, plane_state);
   1362 			dpp->funcs->dpp_program_bias_and_scale(dpp, &bns_params);
   1363 		}
   1364 	}
   1365 
   1366 	if (pipe_ctx->update_flags.bits.mpcc
   1367 			|| plane_state->update_flags.bits.global_alpha_change
   1368 			|| plane_state->update_flags.bits.per_pixel_alpha_change) {
   1369 		// MPCC inst is equal to pipe index in practice
   1370 		int mpcc_inst = hubp->inst;
   1371 		int opp_inst;
   1372 		int opp_count = dc->res_pool->pipe_count;
   1373 
   1374 		for (opp_inst = 0; opp_inst < opp_count; opp_inst++) {
   1375 			if (dc->res_pool->opps[opp_inst]->mpcc_disconnect_pending[mpcc_inst]) {
   1376 				dc->res_pool->mpc->funcs->wait_for_idle(dc->res_pool->mpc, mpcc_inst);
   1377 				dc->res_pool->opps[opp_inst]->mpcc_disconnect_pending[mpcc_inst] = false;
   1378 				break;
   1379 			}
   1380 		}
   1381 		hws->funcs.update_mpcc(dc, pipe_ctx);
   1382 	}
   1383 
   1384 	if (pipe_ctx->update_flags.bits.scaler ||
   1385 			plane_state->update_flags.bits.scaling_change ||
   1386 			plane_state->update_flags.bits.position_change ||
   1387 			plane_state->update_flags.bits.per_pixel_alpha_change ||
   1388 			pipe_ctx->stream->update_flags.bits.scaling) {
   1389 		pipe_ctx->plane_res.scl_data.lb_params.alpha_en = pipe_ctx->plane_state->per_pixel_alpha;
   1390 		ASSERT(pipe_ctx->plane_res.scl_data.lb_params.depth == LB_PIXEL_DEPTH_30BPP);
   1391 		/* scaler configuration */
   1392 		pipe_ctx->plane_res.dpp->funcs->dpp_set_scaler(
   1393 				pipe_ctx->plane_res.dpp, &pipe_ctx->plane_res.scl_data);
   1394 	}
   1395 
   1396 	if (pipe_ctx->update_flags.bits.viewport ||
   1397 			(context == dc->current_state && plane_state->update_flags.bits.scaling_change) ||
   1398 			(context == dc->current_state && pipe_ctx->stream->update_flags.bits.scaling)) {
   1399 
   1400 		hubp->funcs->mem_program_viewport(
   1401 			hubp,
   1402 			&pipe_ctx->plane_res.scl_data.viewport,
   1403 			&pipe_ctx->plane_res.scl_data.viewport_c);
   1404 		viewport_changed = true;
   1405 	}
   1406 
   1407 	/* Any updates are handled in dc interface, just need to apply existing for plane enable */
   1408 	if ((pipe_ctx->update_flags.bits.enable || pipe_ctx->update_flags.bits.opp_changed ||
   1409 			pipe_ctx->update_flags.bits.scaler || pipe_ctx->update_flags.bits.viewport)
   1410 			&& pipe_ctx->stream->cursor_attributes.address.quad_part != 0) {
   1411 		dc->hwss.set_cursor_position(pipe_ctx);
   1412 		dc->hwss.set_cursor_attribute(pipe_ctx);
   1413 
   1414 		if (dc->hwss.set_cursor_sdr_white_level)
   1415 			dc->hwss.set_cursor_sdr_white_level(pipe_ctx);
   1416 	}
   1417 
   1418 	/* Any updates are handled in dc interface, just need
   1419 	 * to apply existing for plane enable / opp change */
   1420 	if (pipe_ctx->update_flags.bits.enable || pipe_ctx->update_flags.bits.opp_changed
   1421 			|| pipe_ctx->stream->update_flags.bits.gamut_remap
   1422 			|| pipe_ctx->stream->update_flags.bits.out_csc) {
   1423 			/* dpp/cm gamut remap*/
   1424 			dc->hwss.program_gamut_remap(pipe_ctx);
   1425 
   1426 		/*call the dcn2 method which uses mpc csc*/
   1427 		dc->hwss.program_output_csc(dc,
   1428 				pipe_ctx,
   1429 				pipe_ctx->stream->output_color_space,
   1430 				pipe_ctx->stream->csc_color_matrix.matrix,
   1431 				hubp->opp_id);
   1432 	}
   1433 
   1434 	if (pipe_ctx->update_flags.bits.enable ||
   1435 			pipe_ctx->update_flags.bits.opp_changed ||
   1436 			plane_state->update_flags.bits.pixel_format_change ||
   1437 			plane_state->update_flags.bits.horizontal_mirror_change ||
   1438 			plane_state->update_flags.bits.rotation_change ||
   1439 			plane_state->update_flags.bits.swizzle_change ||
   1440 			plane_state->update_flags.bits.dcc_change ||
   1441 			plane_state->update_flags.bits.bpp_change ||
   1442 			plane_state->update_flags.bits.scaling_change ||
   1443 			plane_state->update_flags.bits.plane_size_change) {
   1444 		struct plane_size size = plane_state->plane_size;
   1445 
   1446 		size.surface_size = pipe_ctx->plane_res.scl_data.viewport;
   1447 		hubp->funcs->hubp_program_surface_config(
   1448 			hubp,
   1449 			plane_state->format,
   1450 			&plane_state->tiling_info,
   1451 			&size,
   1452 			plane_state->rotation,
   1453 			&plane_state->dcc,
   1454 			plane_state->horizontal_mirror,
   1455 			0);
   1456 		hubp->power_gated = false;
   1457 	}
   1458 
   1459 	if (hubp->funcs->apply_PLAT_54186_wa && viewport_changed)
   1460 		hubp->funcs->apply_PLAT_54186_wa(hubp, &plane_state->address);
   1461 
   1462 	if (pipe_ctx->update_flags.bits.enable || plane_state->update_flags.bits.addr_update)
   1463 		hws->funcs.update_plane_addr(dc, pipe_ctx);
   1464 
   1465 
   1466 
   1467 	if (pipe_ctx->update_flags.bits.enable)
   1468 		hubp->funcs->set_blank(hubp, false);
   1469 }
   1470 
   1471 
   1472 static void dcn20_program_pipe(
   1473 		struct dc *dc,
   1474 		struct pipe_ctx *pipe_ctx,
   1475 		struct dc_state *context)
   1476 {
   1477 	struct dce_hwseq *hws = dc->hwseq;
   1478 	/* Only need to unblank on top pipe */
   1479 	if ((pipe_ctx->update_flags.bits.enable || pipe_ctx->stream->update_flags.bits.abm_level)
   1480 			&& !pipe_ctx->top_pipe && !pipe_ctx->prev_odm_pipe)
   1481 		hws->funcs.blank_pixel_data(dc, pipe_ctx, !pipe_ctx->plane_state->visible);
   1482 
   1483 	if (pipe_ctx->update_flags.bits.global_sync) {
   1484 		pipe_ctx->stream_res.tg->funcs->program_global_sync(
   1485 				pipe_ctx->stream_res.tg,
   1486 				pipe_ctx->pipe_dlg_param.vready_offset,
   1487 				pipe_ctx->pipe_dlg_param.vstartup_start,
   1488 				pipe_ctx->pipe_dlg_param.vupdate_offset,
   1489 				pipe_ctx->pipe_dlg_param.vupdate_width);
   1490 
   1491 		pipe_ctx->stream_res.tg->funcs->set_vtg_params(
   1492 				pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing);
   1493 
   1494 		if (hws->funcs.setup_vupdate_interrupt)
   1495 			hws->funcs.setup_vupdate_interrupt(dc, pipe_ctx);
   1496 	}
   1497 
   1498 	if (pipe_ctx->update_flags.bits.odm)
   1499 		hws->funcs.update_odm(dc, context, pipe_ctx);
   1500 
   1501 	if (pipe_ctx->update_flags.bits.enable)
   1502 		dcn20_enable_plane(dc, pipe_ctx, context);
   1503 
   1504 	if (pipe_ctx->update_flags.raw || pipe_ctx->plane_state->update_flags.raw || pipe_ctx->stream->update_flags.raw)
   1505 		dcn20_update_dchubp_dpp(dc, pipe_ctx, context);
   1506 
   1507 	if (pipe_ctx->update_flags.bits.enable
   1508 			|| pipe_ctx->plane_state->update_flags.bits.hdr_mult)
   1509 		hws->funcs.set_hdr_multiplier(pipe_ctx);
   1510 
   1511 	if (pipe_ctx->update_flags.bits.enable ||
   1512 			pipe_ctx->plane_state->update_flags.bits.in_transfer_func_change ||
   1513 			pipe_ctx->plane_state->update_flags.bits.gamma_change)
   1514 		hws->funcs.set_input_transfer_func(dc, pipe_ctx, pipe_ctx->plane_state);
   1515 
   1516 	/* dcn10_translate_regamma_to_hw_format takes 750us to finish
   1517 	 * only do gamma programming for powering on, internal memcmp to avoid
   1518 	 * updating on slave planes
   1519 	 */
   1520 	if (pipe_ctx->update_flags.bits.enable || pipe_ctx->stream->update_flags.bits.out_tf)
   1521 		hws->funcs.set_output_transfer_func(dc, pipe_ctx, pipe_ctx->stream);
   1522 
   1523 	/* If the pipe has been enabled or has a different opp, we
   1524 	 * should reprogram the fmt. This deals with cases where
   1525 	 * interation between mpc and odm combine on different streams
   1526 	 * causes a different pipe to be chosen to odm combine with.
   1527 	 */
   1528 	if (pipe_ctx->update_flags.bits.enable
   1529 	    || pipe_ctx->update_flags.bits.opp_changed) {
   1530 
   1531 		pipe_ctx->stream_res.opp->funcs->opp_set_dyn_expansion(
   1532 			pipe_ctx->stream_res.opp,
   1533 			COLOR_SPACE_YCBCR601,
   1534 			pipe_ctx->stream->timing.display_color_depth,
   1535 			pipe_ctx->stream->signal);
   1536 
   1537 		pipe_ctx->stream_res.opp->funcs->opp_program_fmt(
   1538 			pipe_ctx->stream_res.opp,
   1539 			&pipe_ctx->stream->bit_depth_params,
   1540 			&pipe_ctx->stream->clamping);
   1541 	}
   1542 }
   1543 
   1544 static bool does_pipe_need_lock(struct pipe_ctx *pipe)
   1545 {
   1546 	if ((pipe->plane_state && pipe->plane_state->update_flags.raw)
   1547 			|| pipe->update_flags.raw)
   1548 		return true;
   1549 	if (pipe->bottom_pipe)
   1550 		return does_pipe_need_lock(pipe->bottom_pipe);
   1551 
   1552 	return false;
   1553 }
   1554 
   1555 void dcn20_program_front_end_for_ctx(
   1556 		struct dc *dc,
   1557 		struct dc_state *context)
   1558 {
   1559 	const unsigned int TIMEOUT_FOR_PIPE_ENABLE_MS = 100;
   1560 	int i;
   1561 	struct dce_hwseq *hws = dc->hwseq;
   1562 	bool pipe_locked[MAX_PIPES] = {false};
   1563 	DC_LOGGER_INIT(dc->ctx->logger);
   1564 
   1565 	/* Carry over GSL groups in case the context is changing. */
   1566 	for (i = 0; i < dc->res_pool->pipe_count; i++)
   1567 		if (context->res_ctx.pipe_ctx[i].stream == dc->current_state->res_ctx.pipe_ctx[i].stream)
   1568 			context->res_ctx.pipe_ctx[i].stream_res.gsl_group =
   1569 				dc->current_state->res_ctx.pipe_ctx[i].stream_res.gsl_group;
   1570 
   1571 	/* Set pipe update flags and lock pipes */
   1572 	for (i = 0; i < dc->res_pool->pipe_count; i++)
   1573 		dcn20_detect_pipe_changes(&dc->current_state->res_ctx.pipe_ctx[i],
   1574 				&context->res_ctx.pipe_ctx[i]);
   1575 	for (i = 0; i < dc->res_pool->pipe_count; i++)
   1576 		if (!context->res_ctx.pipe_ctx[i].top_pipe &&
   1577 				does_pipe_need_lock(&context->res_ctx.pipe_ctx[i])) {
   1578 			struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
   1579 
   1580 			if (pipe_ctx->update_flags.bits.tg_changed || pipe_ctx->update_flags.bits.enable)
   1581 				dc->hwss.pipe_control_lock(dc, pipe_ctx, true);
   1582 			if (!pipe_ctx->update_flags.bits.enable)
   1583 				dc->hwss.pipe_control_lock(dc, &dc->current_state->res_ctx.pipe_ctx[i], true);
   1584 			pipe_locked[i] = true;
   1585 		}
   1586 
   1587 	/* OTG blank before disabling all front ends */
   1588 	for (i = 0; i < dc->res_pool->pipe_count; i++)
   1589 		if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable
   1590 				&& !context->res_ctx.pipe_ctx[i].top_pipe
   1591 				&& !context->res_ctx.pipe_ctx[i].prev_odm_pipe
   1592 				&& context->res_ctx.pipe_ctx[i].stream)
   1593 			hws->funcs.blank_pixel_data(dc, &context->res_ctx.pipe_ctx[i], true);
   1594 
   1595 	/* Disconnect mpcc */
   1596 	for (i = 0; i < dc->res_pool->pipe_count; i++)
   1597 		if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable
   1598 				|| context->res_ctx.pipe_ctx[i].update_flags.bits.opp_changed) {
   1599 			hws->funcs.plane_atomic_disconnect(dc, &dc->current_state->res_ctx.pipe_ctx[i]);
   1600 			DC_LOG_DC("Reset mpcc for pipe %d\n", dc->current_state->res_ctx.pipe_ctx[i].pipe_idx);
   1601 		}
   1602 
   1603 	/*
   1604 	 * Program all updated pipes, order matters for mpcc setup. Start with
   1605 	 * top pipe and program all pipes that follow in order
   1606 	 */
   1607 	for (i = 0; i < dc->res_pool->pipe_count; i++) {
   1608 		struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
   1609 
   1610 		if (pipe->plane_state && !pipe->top_pipe) {
   1611 			while (pipe) {
   1612 				dcn20_program_pipe(dc, pipe, context);
   1613 				pipe = pipe->bottom_pipe;
   1614 			}
   1615 			/* Program secondary blending tree and writeback pipes */
   1616 			pipe = &context->res_ctx.pipe_ctx[i];
   1617 			if (!pipe->prev_odm_pipe && pipe->stream->num_wb_info > 0
   1618 					&& (pipe->update_flags.raw || pipe->plane_state->update_flags.raw || pipe->stream->update_flags.raw)
   1619 					&& hws->funcs.program_all_writeback_pipes_in_tree)
   1620 				hws->funcs.program_all_writeback_pipes_in_tree(dc, pipe->stream, context);
   1621 		}
   1622 	}
   1623 
   1624 	/* Unlock all locked pipes */
   1625 	for (i = 0; i < dc->res_pool->pipe_count; i++)
   1626 		if (pipe_locked[i]) {
   1627 			struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
   1628 
   1629 			if (pipe_ctx->update_flags.bits.tg_changed || pipe_ctx->update_flags.bits.enable)
   1630 				dc->hwss.pipe_control_lock(dc, pipe_ctx, false);
   1631 			if (!pipe_ctx->update_flags.bits.enable)
   1632 				dc->hwss.pipe_control_lock(dc, &dc->current_state->res_ctx.pipe_ctx[i], false);
   1633 		}
   1634 
   1635 	for (i = 0; i < dc->res_pool->pipe_count; i++)
   1636 		if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable)
   1637 			dc->hwss.disable_plane(dc, &dc->current_state->res_ctx.pipe_ctx[i]);
   1638 
   1639 	/*
   1640 	 * If we are enabling a pipe, we need to wait for pending clear as this is a critical
   1641 	 * part of the enable operation otherwise, DM may request an immediate flip which
   1642 	 * will cause HW to perform an "immediate enable" (as opposed to "vsync enable") which
   1643 	 * is unsupported on DCN.
   1644 	 */
   1645 	for (i = 0; i < dc->res_pool->pipe_count; i++) {
   1646 		struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
   1647 
   1648 		if (pipe->plane_state && !pipe->top_pipe && pipe->update_flags.bits.enable) {
   1649 			struct hubp *hubp = pipe->plane_res.hubp;
   1650 			int j = 0;
   1651 
   1652 			for (j = 0; j < TIMEOUT_FOR_PIPE_ENABLE_MS*1000
   1653 					&& hubp->funcs->hubp_is_flip_pending(hubp); j++)
   1654 				mdelay(1);
   1655 		}
   1656 	}
   1657 
   1658 	/* WA to apply WM setting*/
   1659 	if (dc->hwseq->wa.DEGVIDCN21)
   1660 		dc->res_pool->hubbub->funcs->apply_DEDCN21_147_wa(dc->res_pool->hubbub);
   1661 }
   1662 
   1663 
   1664 void dcn20_prepare_bandwidth(
   1665 		struct dc *dc,
   1666 		struct dc_state *context)
   1667 {
   1668 	struct hubbub *hubbub = dc->res_pool->hubbub;
   1669 
   1670 	dc->clk_mgr->funcs->update_clocks(
   1671 			dc->clk_mgr,
   1672 			context,
   1673 			false);
   1674 
   1675 	/* program dchubbub watermarks */
   1676 	hubbub->funcs->program_watermarks(hubbub,
   1677 					&context->bw_ctx.bw.dcn.watermarks,
   1678 					dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000,
   1679 					false);
   1680 }
   1681 
   1682 void dcn20_optimize_bandwidth(
   1683 		struct dc *dc,
   1684 		struct dc_state *context)
   1685 {
   1686 	struct hubbub *hubbub = dc->res_pool->hubbub;
   1687 
   1688 	/* program dchubbub watermarks */
   1689 	hubbub->funcs->program_watermarks(hubbub,
   1690 					&context->bw_ctx.bw.dcn.watermarks,
   1691 					dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000,
   1692 					true);
   1693 
   1694 	dc->clk_mgr->funcs->update_clocks(
   1695 			dc->clk_mgr,
   1696 			context,
   1697 			true);
   1698 }
   1699 
   1700 bool dcn20_update_bandwidth(
   1701 		struct dc *dc,
   1702 		struct dc_state *context)
   1703 {
   1704 	int i;
   1705 	struct dce_hwseq *hws = dc->hwseq;
   1706 
   1707 	/* recalculate DML parameters */
   1708 	if (!dc->res_pool->funcs->validate_bandwidth(dc, context, false))
   1709 		return false;
   1710 
   1711 	/* apply updated bandwidth parameters */
   1712 	dc->hwss.prepare_bandwidth(dc, context);
   1713 
   1714 	/* update hubp configs for all pipes */
   1715 	for (i = 0; i < dc->res_pool->pipe_count; i++) {
   1716 		struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
   1717 
   1718 		if (pipe_ctx->plane_state == NULL)
   1719 			continue;
   1720 
   1721 		if (pipe_ctx->top_pipe == NULL) {
   1722 			bool blank = !is_pipe_tree_visible(pipe_ctx);
   1723 
   1724 			pipe_ctx->stream_res.tg->funcs->program_global_sync(
   1725 					pipe_ctx->stream_res.tg,
   1726 					pipe_ctx->pipe_dlg_param.vready_offset,
   1727 					pipe_ctx->pipe_dlg_param.vstartup_start,
   1728 					pipe_ctx->pipe_dlg_param.vupdate_offset,
   1729 					pipe_ctx->pipe_dlg_param.vupdate_width);
   1730 
   1731 			pipe_ctx->stream_res.tg->funcs->set_vtg_params(
   1732 					pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing);
   1733 
   1734 			if (pipe_ctx->prev_odm_pipe == NULL)
   1735 				hws->funcs.blank_pixel_data(dc, pipe_ctx, blank);
   1736 
   1737 			if (hws->funcs.setup_vupdate_interrupt)
   1738 				hws->funcs.setup_vupdate_interrupt(dc, pipe_ctx);
   1739 		}
   1740 
   1741 		pipe_ctx->plane_res.hubp->funcs->hubp_setup(
   1742 				pipe_ctx->plane_res.hubp,
   1743 					&pipe_ctx->dlg_regs,
   1744 					&pipe_ctx->ttu_regs,
   1745 					&pipe_ctx->rq_regs,
   1746 					&pipe_ctx->pipe_dlg_param);
   1747 	}
   1748 
   1749 	return true;
   1750 }
   1751 
   1752 void dcn20_enable_writeback(
   1753 		struct dc *dc,
   1754 		struct dc_writeback_info *wb_info,
   1755 		struct dc_state *context)
   1756 {
   1757 	struct dwbc *dwb;
   1758 	struct mcif_wb *mcif_wb;
   1759 	struct timing_generator *optc;
   1760 
   1761 	ASSERT(wb_info->dwb_pipe_inst < MAX_DWB_PIPES);
   1762 	ASSERT(wb_info->wb_enabled);
   1763 	dwb = dc->res_pool->dwbc[wb_info->dwb_pipe_inst];
   1764 	mcif_wb = dc->res_pool->mcif_wb[wb_info->dwb_pipe_inst];
   1765 
   1766 	/* set the OPTC source mux */
   1767 	optc = dc->res_pool->timing_generators[dwb->otg_inst];
   1768 	optc->funcs->set_dwb_source(optc, wb_info->dwb_pipe_inst);
   1769 	/* set MCIF_WB buffer and arbitration configuration */
   1770 	mcif_wb->funcs->config_mcif_buf(mcif_wb, &wb_info->mcif_buf_params, wb_info->dwb_params.dest_height);
   1771 	mcif_wb->funcs->config_mcif_arb(mcif_wb, &context->bw_ctx.bw.dcn.bw_writeback.mcif_wb_arb[wb_info->dwb_pipe_inst]);
   1772 	/* Enable MCIF_WB */
   1773 	mcif_wb->funcs->enable_mcif(mcif_wb);
   1774 	/* Enable DWB */
   1775 	dwb->funcs->enable(dwb, &wb_info->dwb_params);
   1776 	/* TODO: add sequence to enable/disable warmup */
   1777 }
   1778 
   1779 void dcn20_disable_writeback(
   1780 		struct dc *dc,
   1781 		unsigned int dwb_pipe_inst)
   1782 {
   1783 	struct dwbc *dwb;
   1784 	struct mcif_wb *mcif_wb;
   1785 
   1786 	ASSERT(dwb_pipe_inst < MAX_DWB_PIPES);
   1787 	dwb = dc->res_pool->dwbc[dwb_pipe_inst];
   1788 	mcif_wb = dc->res_pool->mcif_wb[dwb_pipe_inst];
   1789 
   1790 	dwb->funcs->disable(dwb);
   1791 	mcif_wb->funcs->disable_mcif(mcif_wb);
   1792 }
   1793 
   1794 bool dcn20_wait_for_blank_complete(
   1795 		struct output_pixel_processor *opp)
   1796 {
   1797 	int counter;
   1798 
   1799 	for (counter = 0; counter < 1000; counter++) {
   1800 		if (opp->funcs->dpg_is_blanked(opp))
   1801 			break;
   1802 
   1803 		udelay(100);
   1804 	}
   1805 
   1806 	if (counter == 1000) {
   1807 		dm_error("DC: failed to blank crtc!\n");
   1808 		return false;
   1809 	}
   1810 
   1811 	return true;
   1812 }
   1813 
   1814 bool dcn20_dmdata_status_done(struct pipe_ctx *pipe_ctx)
   1815 {
   1816 	struct hubp *hubp = pipe_ctx->plane_res.hubp;
   1817 
   1818 	if (!hubp)
   1819 		return false;
   1820 	return hubp->funcs->dmdata_status_done(hubp);
   1821 }
   1822 
   1823 void dcn20_disable_stream_gating(struct dc *dc, struct pipe_ctx *pipe_ctx)
   1824 {
   1825 	struct dce_hwseq *hws = dc->hwseq;
   1826 
   1827 	if (pipe_ctx->stream_res.dsc) {
   1828 		struct pipe_ctx *odm_pipe = pipe_ctx->next_odm_pipe;
   1829 
   1830 		dcn20_dsc_pg_control(hws, pipe_ctx->stream_res.dsc->inst, true);
   1831 		while (odm_pipe) {
   1832 			dcn20_dsc_pg_control(hws, odm_pipe->stream_res.dsc->inst, true);
   1833 			odm_pipe = odm_pipe->next_odm_pipe;
   1834 		}
   1835 	}
   1836 }
   1837 
   1838 void dcn20_enable_stream_gating(struct dc *dc, struct pipe_ctx *pipe_ctx)
   1839 {
   1840 	struct dce_hwseq *hws = dc->hwseq;
   1841 
   1842 	if (pipe_ctx->stream_res.dsc) {
   1843 		struct pipe_ctx *odm_pipe = pipe_ctx->next_odm_pipe;
   1844 
   1845 		dcn20_dsc_pg_control(hws, pipe_ctx->stream_res.dsc->inst, false);
   1846 		while (odm_pipe) {
   1847 			dcn20_dsc_pg_control(hws, odm_pipe->stream_res.dsc->inst, false);
   1848 			odm_pipe = odm_pipe->next_odm_pipe;
   1849 		}
   1850 	}
   1851 }
   1852 
   1853 void dcn20_set_dmdata_attributes(struct pipe_ctx *pipe_ctx)
   1854 {
   1855 	struct dc_dmdata_attributes attr = { 0 };
   1856 	struct hubp *hubp = pipe_ctx->plane_res.hubp;
   1857 
   1858 	attr.dmdata_mode = DMDATA_HW_MODE;
   1859 	attr.dmdata_size =
   1860 		dc_is_hdmi_signal(pipe_ctx->stream->signal) ? 32 : 36;
   1861 	attr.address.quad_part =
   1862 			pipe_ctx->stream->dmdata_address.quad_part;
   1863 	attr.dmdata_dl_delta = 0;
   1864 	attr.dmdata_qos_mode = 0;
   1865 	attr.dmdata_qos_level = 0;
   1866 	attr.dmdata_repeat = 1; /* always repeat */
   1867 	attr.dmdata_updated = 1;
   1868 	attr.dmdata_sw_data = NULL;
   1869 
   1870 	hubp->funcs->dmdata_set_attributes(hubp, &attr);
   1871 }
   1872 
   1873 void dcn20_init_vm_ctx(
   1874 		struct dce_hwseq *hws,
   1875 		struct dc *dc,
   1876 		struct dc_virtual_addr_space_config *va_config,
   1877 		int vmid)
   1878 {
   1879 	struct dcn_hubbub_virt_addr_config config;
   1880 
   1881 	if (vmid == 0) {
   1882 		ASSERT(0); /* VMID cannot be 0 for vm context */
   1883 		return;
   1884 	}
   1885 
   1886 	config.page_table_start_addr = va_config->page_table_start_addr;
   1887 	config.page_table_end_addr = va_config->page_table_end_addr;
   1888 	config.page_table_block_size = va_config->page_table_block_size_in_bytes;
   1889 	config.page_table_depth = va_config->page_table_depth;
   1890 	config.page_table_base_addr = va_config->page_table_base_addr;
   1891 
   1892 	dc->res_pool->hubbub->funcs->init_vm_ctx(dc->res_pool->hubbub, &config, vmid);
   1893 }
   1894 
   1895 int dcn20_init_sys_ctx(struct dce_hwseq *hws, struct dc *dc, struct dc_phy_addr_space_config *pa_config)
   1896 {
   1897 	struct dcn_hubbub_phys_addr_config config;
   1898 
   1899 	config.system_aperture.fb_top = pa_config->system_aperture.fb_top;
   1900 	config.system_aperture.fb_offset = pa_config->system_aperture.fb_offset;
   1901 	config.system_aperture.fb_base = pa_config->system_aperture.fb_base;
   1902 	config.system_aperture.agp_top = pa_config->system_aperture.agp_top;
   1903 	config.system_aperture.agp_bot = pa_config->system_aperture.agp_bot;
   1904 	config.system_aperture.agp_base = pa_config->system_aperture.agp_base;
   1905 	config.gart_config.page_table_start_addr = pa_config->gart_config.page_table_start_addr;
   1906 	config.gart_config.page_table_end_addr = pa_config->gart_config.page_table_end_addr;
   1907 	config.gart_config.page_table_base_addr = pa_config->gart_config.page_table_base_addr;
   1908 	config.page_table_default_page_addr = pa_config->page_table_default_page_addr;
   1909 
   1910 	return dc->res_pool->hubbub->funcs->init_dchub_sys_ctx(dc->res_pool->hubbub, &config);
   1911 }
   1912 
   1913 static bool patch_address_for_sbs_tb_stereo(
   1914 		struct pipe_ctx *pipe_ctx, PHYSICAL_ADDRESS_LOC *addr)
   1915 {
   1916 	struct dc_plane_state *plane_state = pipe_ctx->plane_state;
   1917 	bool sec_split = pipe_ctx->top_pipe &&
   1918 			pipe_ctx->top_pipe->plane_state == pipe_ctx->plane_state;
   1919 	if (sec_split && plane_state->address.type == PLN_ADDR_TYPE_GRPH_STEREO &&
   1920 			(pipe_ctx->stream->timing.timing_3d_format ==
   1921 			TIMING_3D_FORMAT_SIDE_BY_SIDE ||
   1922 			pipe_ctx->stream->timing.timing_3d_format ==
   1923 			TIMING_3D_FORMAT_TOP_AND_BOTTOM)) {
   1924 		*addr = plane_state->address.grph_stereo.left_addr;
   1925 		plane_state->address.grph_stereo.left_addr =
   1926 				plane_state->address.grph_stereo.right_addr;
   1927 		return true;
   1928 	}
   1929 
   1930 	if (pipe_ctx->stream->view_format != VIEW_3D_FORMAT_NONE &&
   1931 			plane_state->address.type != PLN_ADDR_TYPE_GRPH_STEREO) {
   1932 		plane_state->address.type = PLN_ADDR_TYPE_GRPH_STEREO;
   1933 		plane_state->address.grph_stereo.right_addr =
   1934 				plane_state->address.grph_stereo.left_addr;
   1935 	}
   1936 	return false;
   1937 }
   1938 
   1939 void dcn20_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx)
   1940 {
   1941 	bool addr_patched = false;
   1942 	PHYSICAL_ADDRESS_LOC addr;
   1943 	struct dc_plane_state *plane_state = pipe_ctx->plane_state;
   1944 
   1945 	if (plane_state == NULL)
   1946 		return;
   1947 
   1948 	addr_patched = patch_address_for_sbs_tb_stereo(pipe_ctx, &addr);
   1949 
   1950 	// Call Helper to track VMID use
   1951 	vm_helper_mark_vmid_used(dc->vm_helper, plane_state->address.vmid, pipe_ctx->plane_res.hubp->inst);
   1952 
   1953 	pipe_ctx->plane_res.hubp->funcs->hubp_program_surface_flip_and_addr(
   1954 			pipe_ctx->plane_res.hubp,
   1955 			&plane_state->address,
   1956 			plane_state->flip_immediate);
   1957 
   1958 	plane_state->status.requested_address = plane_state->address;
   1959 
   1960 	if (plane_state->flip_immediate)
   1961 		plane_state->status.current_address = plane_state->address;
   1962 
   1963 	if (addr_patched)
   1964 		pipe_ctx->plane_state->address.grph_stereo.left_addr = addr;
   1965 }
   1966 
   1967 void dcn20_unblank_stream(struct pipe_ctx *pipe_ctx,
   1968 		struct dc_link_settings *link_settings)
   1969 {
   1970 	struct encoder_unblank_param params = { { 0 } };
   1971 	struct dc_stream_state *stream = pipe_ctx->stream;
   1972 	struct dc_link *link = stream->link;
   1973 	struct dce_hwseq *hws = link->dc->hwseq;
   1974 	struct pipe_ctx *odm_pipe;
   1975 
   1976 	params.opp_cnt = 1;
   1977 	for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
   1978 		params.opp_cnt++;
   1979 	}
   1980 	/* only 3 items below are used by unblank */
   1981 	params.timing = pipe_ctx->stream->timing;
   1982 
   1983 	params.link_settings.link_rate = link_settings->link_rate;
   1984 
   1985 	if (dc_is_dp_signal(pipe_ctx->stream->signal)) {
   1986 		if (optc2_is_two_pixels_per_containter(&stream->timing) || params.opp_cnt > 1)
   1987 			params.timing.pix_clk_100hz /= 2;
   1988 		pipe_ctx->stream_res.stream_enc->funcs->dp_set_odm_combine(
   1989 				pipe_ctx->stream_res.stream_enc, params.opp_cnt > 1);
   1990 		pipe_ctx->stream_res.stream_enc->funcs->dp_unblank(pipe_ctx->stream_res.stream_enc, &params);
   1991 	}
   1992 
   1993 	if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP) {
   1994 		hws->funcs.edp_backlight_control(link, true);
   1995 	}
   1996 }
   1997 
   1998 void dcn20_setup_vupdate_interrupt(struct dc *dc, struct pipe_ctx *pipe_ctx)
   1999 {
   2000 	struct timing_generator *tg = pipe_ctx->stream_res.tg;
   2001 	int start_line = dc->hwss.get_vupdate_offset_from_vsync(pipe_ctx);
   2002 
   2003 	if (start_line < 0)
   2004 		start_line = 0;
   2005 
   2006 	if (tg->funcs->setup_vertical_interrupt2)
   2007 		tg->funcs->setup_vertical_interrupt2(tg, start_line);
   2008 }
   2009 
   2010 static void dcn20_reset_back_end_for_pipe(
   2011 		struct dc *dc,
   2012 		struct pipe_ctx *pipe_ctx,
   2013 		struct dc_state *context)
   2014 {
   2015 	int i;
   2016 	struct dc_link *link;
   2017 	DC_LOGGER_INIT(dc->ctx->logger);
   2018 	if (pipe_ctx->stream_res.stream_enc == NULL) {
   2019 		pipe_ctx->stream = NULL;
   2020 		return;
   2021 	}
   2022 
   2023 	if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
   2024 		link = pipe_ctx->stream->link;
   2025 		/* DPMS may already disable or */
   2026 		/* dpms_off status is incorrect due to fastboot
   2027 		 * feature. When system resume from S4 with second
   2028 		 * screen only, the dpms_off would be true but
   2029 		 * VBIOS lit up eDP, so check link status too.
   2030 		 */
   2031 		if (!pipe_ctx->stream->dpms_off || link->link_status.link_active)
   2032 			core_link_disable_stream(pipe_ctx);
   2033 		else if (pipe_ctx->stream_res.audio)
   2034 			dc->hwss.disable_audio_stream(pipe_ctx);
   2035 
   2036 		/* free acquired resources */
   2037 		if (pipe_ctx->stream_res.audio) {
   2038 			/*disable az_endpoint*/
   2039 			pipe_ctx->stream_res.audio->funcs->az_disable(pipe_ctx->stream_res.audio);
   2040 
   2041 			/*free audio*/
   2042 			if (dc->caps.dynamic_audio == true) {
   2043 				/*we have to dynamic arbitrate the audio endpoints*/
   2044 				/*we free the resource, need reset is_audio_acquired*/
   2045 				update_audio_usage(&dc->current_state->res_ctx, dc->res_pool,
   2046 						pipe_ctx->stream_res.audio, false);
   2047 				pipe_ctx->stream_res.audio = NULL;
   2048 			}
   2049 		}
   2050 	}
   2051 	else if (pipe_ctx->stream_res.dsc) {
   2052 		dp_set_dsc_enable(pipe_ctx, false);
   2053 	}
   2054 
   2055 	/* by upper caller loop, parent pipe: pipe0, will be reset last.
   2056 	 * back end share by all pipes and will be disable only when disable
   2057 	 * parent pipe.
   2058 	 */
   2059 	if (pipe_ctx->top_pipe == NULL) {
   2060 		pipe_ctx->stream_res.tg->funcs->disable_crtc(pipe_ctx->stream_res.tg);
   2061 
   2062 		pipe_ctx->stream_res.tg->funcs->enable_optc_clock(pipe_ctx->stream_res.tg, false);
   2063 		if (pipe_ctx->stream_res.tg->funcs->set_odm_bypass)
   2064 			pipe_ctx->stream_res.tg->funcs->set_odm_bypass(
   2065 					pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing);
   2066 
   2067 		if (pipe_ctx->stream_res.tg->funcs->set_drr)
   2068 			pipe_ctx->stream_res.tg->funcs->set_drr(
   2069 					pipe_ctx->stream_res.tg, NULL);
   2070 	}
   2071 
   2072 	for (i = 0; i < dc->res_pool->pipe_count; i++)
   2073 		if (&dc->current_state->res_ctx.pipe_ctx[i] == pipe_ctx)
   2074 			break;
   2075 
   2076 	if (i == dc->res_pool->pipe_count)
   2077 		return;
   2078 
   2079 	pipe_ctx->stream = NULL;
   2080 	DC_LOG_DEBUG("Reset back end for pipe %d, tg:%d\n",
   2081 					pipe_ctx->pipe_idx, pipe_ctx->stream_res.tg->inst);
   2082 }
   2083 
   2084 void dcn20_reset_hw_ctx_wrap(
   2085 		struct dc *dc,
   2086 		struct dc_state *context)
   2087 {
   2088 	int i;
   2089 	struct dce_hwseq *hws = dc->hwseq;
   2090 
   2091 	/* Reset Back End*/
   2092 	for (i = dc->res_pool->pipe_count - 1; i >= 0 ; i--) {
   2093 		struct pipe_ctx *pipe_ctx_old =
   2094 			&dc->current_state->res_ctx.pipe_ctx[i];
   2095 		struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
   2096 
   2097 		if (!pipe_ctx_old->stream)
   2098 			continue;
   2099 
   2100 		if (pipe_ctx_old->top_pipe || pipe_ctx_old->prev_odm_pipe)
   2101 			continue;
   2102 
   2103 		if (!pipe_ctx->stream ||
   2104 				pipe_need_reprogram(pipe_ctx_old, pipe_ctx)) {
   2105 			struct clock_source *old_clk = pipe_ctx_old->clock_source;
   2106 
   2107 			dcn20_reset_back_end_for_pipe(dc, pipe_ctx_old, dc->current_state);
   2108 			if (hws->funcs.enable_stream_gating)
   2109 				hws->funcs.enable_stream_gating(dc, pipe_ctx);
   2110 			if (old_clk)
   2111 				old_clk->funcs->cs_power_down(old_clk);
   2112 		}
   2113 	}
   2114 }
   2115 
   2116 void dcn20_get_mpctree_visual_confirm_color(
   2117 		struct pipe_ctx *pipe_ctx,
   2118 		struct tg_color *color)
   2119 {
   2120 	const struct tg_color pipe_colors[6] = {
   2121 			{MAX_TG_COLOR_VALUE, 0, 0}, // red
   2122 			{MAX_TG_COLOR_VALUE, 0, MAX_TG_COLOR_VALUE}, // yellow
   2123 			{0, MAX_TG_COLOR_VALUE, 0}, // blue
   2124 			{MAX_TG_COLOR_VALUE / 2, 0, MAX_TG_COLOR_VALUE / 2}, // purple
   2125 			{0, 0, MAX_TG_COLOR_VALUE}, // green
   2126 			{MAX_TG_COLOR_VALUE, MAX_TG_COLOR_VALUE * 2 / 3, 0}, // orange
   2127 	};
   2128 
   2129 	struct pipe_ctx *top_pipe = pipe_ctx;
   2130 
   2131 	while (top_pipe->top_pipe) {
   2132 		top_pipe = top_pipe->top_pipe;
   2133 	}
   2134 
   2135 	*color = pipe_colors[top_pipe->pipe_idx];
   2136 }
   2137 
   2138 void dcn20_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx)
   2139 {
   2140 	struct dce_hwseq *hws = dc->hwseq;
   2141 	struct hubp *hubp = pipe_ctx->plane_res.hubp;
   2142 	struct mpcc_blnd_cfg blnd_cfg = { {0} };
   2143 	bool per_pixel_alpha = pipe_ctx->plane_state->per_pixel_alpha;
   2144 	int mpcc_id;
   2145 	struct mpcc *new_mpcc;
   2146 	struct mpc *mpc = dc->res_pool->mpc;
   2147 	struct mpc_tree *mpc_tree_params = &(pipe_ctx->stream_res.opp->mpc_tree_params);
   2148 
   2149 	// input to MPCC is always RGB, by default leave black_color at 0
   2150 	if (dc->debug.visual_confirm == VISUAL_CONFIRM_HDR) {
   2151 		hws->funcs.get_hdr_visual_confirm_color(
   2152 				pipe_ctx, &blnd_cfg.black_color);
   2153 	} else if (dc->debug.visual_confirm == VISUAL_CONFIRM_SURFACE) {
   2154 		hws->funcs.get_surface_visual_confirm_color(
   2155 				pipe_ctx, &blnd_cfg.black_color);
   2156 	} else if (dc->debug.visual_confirm == VISUAL_CONFIRM_MPCTREE) {
   2157 		dcn20_get_mpctree_visual_confirm_color(
   2158 				pipe_ctx, &blnd_cfg.black_color);
   2159 	}
   2160 
   2161 	if (per_pixel_alpha)
   2162 		blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA;
   2163 	else
   2164 		blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_GLOBAL_ALPHA;
   2165 
   2166 	blnd_cfg.overlap_only = false;
   2167 	blnd_cfg.global_gain = 0xff;
   2168 
   2169 	if (pipe_ctx->plane_state->global_alpha)
   2170 		blnd_cfg.global_alpha = pipe_ctx->plane_state->global_alpha_value;
   2171 	else
   2172 		blnd_cfg.global_alpha = 0xff;
   2173 
   2174 	blnd_cfg.background_color_bpc = 4;
   2175 	blnd_cfg.bottom_gain_mode = 0;
   2176 	blnd_cfg.top_gain = 0x1f000;
   2177 	blnd_cfg.bottom_inside_gain = 0x1f000;
   2178 	blnd_cfg.bottom_outside_gain = 0x1f000;
   2179 	blnd_cfg.pre_multiplied_alpha = per_pixel_alpha;
   2180 
   2181 	/*
   2182 	 * TODO: remove hack
   2183 	 * Note: currently there is a bug in init_hw such that
   2184 	 * on resume from hibernate, BIOS sets up MPCC0, and
   2185 	 * we do mpcc_remove but the mpcc cannot go to idle
   2186 	 * after remove. This cause us to pick mpcc1 here,
   2187 	 * which causes a pstate hang for yet unknown reason.
   2188 	 */
   2189 	mpcc_id = hubp->inst;
   2190 
   2191 	/* check if this MPCC is already being used */
   2192 	new_mpcc = mpc->funcs->get_mpcc_for_dpp(mpc_tree_params, mpcc_id);
   2193 	/* remove MPCC if being used */
   2194 	if (new_mpcc != NULL)
   2195 		mpc->funcs->remove_mpcc(mpc, mpc_tree_params, new_mpcc);
   2196 	else
   2197 		if (dc->debug.sanity_checks)
   2198 			mpc->funcs->assert_mpcc_idle_before_connect(
   2199 					dc->res_pool->mpc, mpcc_id);
   2200 
   2201 	/* Call MPC to insert new plane */
   2202 	new_mpcc = mpc->funcs->insert_plane(dc->res_pool->mpc,
   2203 			mpc_tree_params,
   2204 			&blnd_cfg,
   2205 			NULL,
   2206 			NULL,
   2207 			hubp->inst,
   2208 			mpcc_id);
   2209 
   2210 	ASSERT(new_mpcc != NULL);
   2211 	hubp->opp_id = pipe_ctx->stream_res.opp->inst;
   2212 	hubp->mpcc_id = mpcc_id;
   2213 }
   2214 
   2215 void dcn20_enable_stream(struct pipe_ctx *pipe_ctx)
   2216 {
   2217 	enum dc_lane_count lane_count =
   2218 		pipe_ctx->stream->link->cur_link_settings.lane_count;
   2219 
   2220 	struct dc_crtc_timing *timing = &pipe_ctx->stream->timing;
   2221 	struct dc_link *link = pipe_ctx->stream->link;
   2222 
   2223 	uint32_t active_total_with_borders;
   2224 	uint32_t early_control = 0;
   2225 	struct timing_generator *tg = pipe_ctx->stream_res.tg;
   2226 
   2227 	/* For MST, there are multiply stream go to only one link.
   2228 	 * connect DIG back_end to front_end while enable_stream and
   2229 	 * disconnect them during disable_stream
   2230 	 * BY this, it is logic clean to separate stream and link
   2231 	 */
   2232 	link->link_enc->funcs->connect_dig_be_to_fe(link->link_enc,
   2233 						    pipe_ctx->stream_res.stream_enc->id, true);
   2234 
   2235 	if (pipe_ctx->plane_state && pipe_ctx->plane_state->flip_immediate != 1) {
   2236 		if (link->dc->hwss.program_dmdata_engine)
   2237 			link->dc->hwss.program_dmdata_engine(pipe_ctx);
   2238 	}
   2239 
   2240 	link->dc->hwss.update_info_frame(pipe_ctx);
   2241 
   2242 	/* enable early control to avoid corruption on DP monitor*/
   2243 	active_total_with_borders =
   2244 			timing->h_addressable
   2245 				+ timing->h_border_left
   2246 				+ timing->h_border_right;
   2247 
   2248 	if (lane_count != 0)
   2249 		early_control = active_total_with_borders % lane_count;
   2250 
   2251 	if (early_control == 0)
   2252 		early_control = lane_count;
   2253 
   2254 	tg->funcs->set_early_control(tg, early_control);
   2255 
   2256 	/* enable audio only within mode set */
   2257 	if (pipe_ctx->stream_res.audio != NULL) {
   2258 		if (dc_is_dp_signal(pipe_ctx->stream->signal))
   2259 			pipe_ctx->stream_res.stream_enc->funcs->dp_audio_enable(pipe_ctx->stream_res.stream_enc);
   2260 	}
   2261 }
   2262 
   2263 void dcn20_program_dmdata_engine(struct pipe_ctx *pipe_ctx)
   2264 {
   2265 	struct dc_stream_state    *stream     = pipe_ctx->stream;
   2266 	struct hubp               *hubp       = pipe_ctx->plane_res.hubp;
   2267 	bool                       enable     = false;
   2268 	struct stream_encoder     *stream_enc = pipe_ctx->stream_res.stream_enc;
   2269 	enum dynamic_metadata_mode mode       = dc_is_dp_signal(stream->signal)
   2270 							? dmdata_dp
   2271 							: dmdata_hdmi;
   2272 
   2273 	/* if using dynamic meta, don't set up generic infopackets */
   2274 	if (pipe_ctx->stream->dmdata_address.quad_part != 0) {
   2275 		pipe_ctx->stream_res.encoder_info_frame.hdrsmd.valid = false;
   2276 		enable = true;
   2277 	}
   2278 
   2279 	if (!hubp)
   2280 		return;
   2281 
   2282 	if (!stream_enc || !stream_enc->funcs->set_dynamic_metadata)
   2283 		return;
   2284 
   2285 	stream_enc->funcs->set_dynamic_metadata(stream_enc, enable,
   2286 						hubp->inst, mode);
   2287 }
   2288 
   2289 void dcn20_fpga_init_hw(struct dc *dc)
   2290 {
   2291 	int i, j;
   2292 	struct dce_hwseq *hws = dc->hwseq;
   2293 	struct resource_pool *res_pool = dc->res_pool;
   2294 	struct dc_state  *context = dc->current_state;
   2295 
   2296 	if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks)
   2297 		dc->clk_mgr->funcs->init_clocks(dc->clk_mgr);
   2298 
   2299 	// Initialize the dccg
   2300 	if (res_pool->dccg->funcs->dccg_init)
   2301 		res_pool->dccg->funcs->dccg_init(res_pool->dccg);
   2302 
   2303 	//Enable ability to power gate / don't force power on permanently
   2304 	hws->funcs.enable_power_gating_plane(hws, true);
   2305 
   2306 	// Specific to FPGA dccg and registers
   2307 	REG_WRITE(RBBMIF_TIMEOUT_DIS, 0xFFFFFFFF);
   2308 	REG_WRITE(RBBMIF_TIMEOUT_DIS_2, 0xFFFFFFFF);
   2309 
   2310 	hws->funcs.dccg_init(hws);
   2311 
   2312 	REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_REFDIV, 2);
   2313 	REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_ENABLE, 1);
   2314 	REG_WRITE(REFCLK_CNTL, 0);
   2315 	//
   2316 
   2317 
   2318 	/* Blank pixel data with OPP DPG */
   2319 	for (i = 0; i < dc->res_pool->timing_generator_count; i++) {
   2320 		struct timing_generator *tg = dc->res_pool->timing_generators[i];
   2321 
   2322 		if (tg->funcs->is_tg_enabled(tg))
   2323 			dcn20_init_blank(dc, tg);
   2324 	}
   2325 
   2326 	for (i = 0; i < res_pool->timing_generator_count; i++) {
   2327 		struct timing_generator *tg = dc->res_pool->timing_generators[i];
   2328 
   2329 		if (tg->funcs->is_tg_enabled(tg))
   2330 			tg->funcs->lock(tg);
   2331 	}
   2332 
   2333 	for (i = 0; i < dc->res_pool->pipe_count; i++) {
   2334 		struct dpp *dpp = res_pool->dpps[i];
   2335 
   2336 		dpp->funcs->dpp_reset(dpp);
   2337 	}
   2338 
   2339 	/* Reset all MPCC muxes */
   2340 	res_pool->mpc->funcs->mpc_init(res_pool->mpc);
   2341 
   2342 	/* initialize OPP mpc_tree parameter */
   2343 	for (i = 0; i < dc->res_pool->res_cap->num_opp; i++) {
   2344 		res_pool->opps[i]->mpc_tree_params.opp_id = res_pool->opps[i]->inst;
   2345 		res_pool->opps[i]->mpc_tree_params.opp_list = NULL;
   2346 		for (j = 0; j < MAX_PIPES; j++)
   2347 			res_pool->opps[i]->mpcc_disconnect_pending[j] = false;
   2348 	}
   2349 
   2350 	for (i = 0; i < dc->res_pool->pipe_count; i++) {
   2351 		struct timing_generator *tg = dc->res_pool->timing_generators[i];
   2352 		struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
   2353 		struct hubp *hubp = dc->res_pool->hubps[i];
   2354 		struct dpp *dpp = dc->res_pool->dpps[i];
   2355 
   2356 		pipe_ctx->stream_res.tg = tg;
   2357 		pipe_ctx->pipe_idx = i;
   2358 
   2359 		pipe_ctx->plane_res.hubp = hubp;
   2360 		pipe_ctx->plane_res.dpp = dpp;
   2361 		pipe_ctx->plane_res.mpcc_inst = dpp->inst;
   2362 		hubp->mpcc_id = dpp->inst;
   2363 		hubp->opp_id = OPP_ID_INVALID;
   2364 		hubp->power_gated = false;
   2365 		pipe_ctx->stream_res.opp = NULL;
   2366 
   2367 		hubp->funcs->hubp_init(hubp);
   2368 
   2369 		//dc->res_pool->opps[i]->mpc_tree_params.opp_id = dc->res_pool->opps[i]->inst;
   2370 		//dc->res_pool->opps[i]->mpc_tree_params.opp_list = NULL;
   2371 		dc->res_pool->opps[i]->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true;
   2372 		pipe_ctx->stream_res.opp = dc->res_pool->opps[i];
   2373 		/*to do*/
   2374 		hws->funcs.plane_atomic_disconnect(dc, pipe_ctx);
   2375 	}
   2376 
   2377 	/* initialize DWB pointer to MCIF_WB */
   2378 	for (i = 0; i < res_pool->res_cap->num_dwb; i++)
   2379 		res_pool->dwbc[i]->mcif = res_pool->mcif_wb[i];
   2380 
   2381 	for (i = 0; i < dc->res_pool->timing_generator_count; i++) {
   2382 		struct timing_generator *tg = dc->res_pool->timing_generators[i];
   2383 
   2384 		if (tg->funcs->is_tg_enabled(tg))
   2385 			tg->funcs->unlock(tg);
   2386 	}
   2387 
   2388 	for (i = 0; i < dc->res_pool->pipe_count; i++) {
   2389 		struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
   2390 
   2391 		dc->hwss.disable_plane(dc, pipe_ctx);
   2392 
   2393 		pipe_ctx->stream_res.tg = NULL;
   2394 		pipe_ctx->plane_res.hubp = NULL;
   2395 	}
   2396 
   2397 	for (i = 0; i < dc->res_pool->timing_generator_count; i++) {
   2398 		struct timing_generator *tg = dc->res_pool->timing_generators[i];
   2399 
   2400 		tg->funcs->tg_init(tg);
   2401 	}
   2402 }
   2403