cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

dcn201_hwseq.c (19714B)


      1/*
      2 * Copyright 2016 Advanced Micro Devices, Inc.
      3 *
      4 * Permission is hereby granted, free of charge, to any person obtaining a
      5 * copy of this software and associated documentation files (the "Software"),
      6 * to deal in the Software without restriction, including without limitation
      7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8 * and/or sell copies of the Software, and to permit persons to whom the
      9 * Software is furnished to do so, subject to the following conditions:
     10 *
     11 * The above copyright notice and this permission notice shall be included in
     12 * all copies or substantial portions of the Software.
     13 *
     14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
     18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     20 * OTHER DEALINGS IN THE SOFTWARE.
     21 *
     22 * Authors: AMD
     23 *
     24 */
     25
     26#include "dm_services.h"
     27#include "basics/dc_common.h"
     28#include "core_types.h"
     29#include "resource.h"
     30#include "dcn201_hwseq.h"
     31#include "dcn201_optc.h"
     32#include "dce/dce_hwseq.h"
     33#include "hubp.h"
     34#include "dchubbub.h"
     35#include "timing_generator.h"
     36#include "opp.h"
     37#include "ipp.h"
     38#include "mpc.h"
     39#include "dccg.h"
     40#include "clk_mgr.h"
     41#include "reg_helper.h"
     42
     43#define CTX \
     44	hws->ctx
     45
     46#define REG(reg)\
     47	hws->regs->reg
     48
     49#define DC_LOGGER \
     50	dc->ctx->logger
     51
     52#undef FN
     53#define FN(reg_name, field_name) \
     54	hws->shifts->field_name, hws->masks->field_name
     55
     56static bool patch_address_for_sbs_tb_stereo(
     57		struct pipe_ctx *pipe_ctx, PHYSICAL_ADDRESS_LOC *addr)
     58{
     59	struct dc_plane_state *plane_state = pipe_ctx->plane_state;
     60	bool sec_split = pipe_ctx->top_pipe &&
     61		pipe_ctx->top_pipe->plane_state == pipe_ctx->plane_state;
     62
     63	if (sec_split && plane_state->address.type == PLN_ADDR_TYPE_GRPH_STEREO &&
     64		(pipe_ctx->stream->timing.timing_3d_format ==
     65			TIMING_3D_FORMAT_SIDE_BY_SIDE ||
     66		pipe_ctx->stream->timing.timing_3d_format ==
     67			TIMING_3D_FORMAT_TOP_AND_BOTTOM)) {
     68		*addr = plane_state->address.grph_stereo.left_addr;
     69		plane_state->address.grph_stereo.left_addr =
     70			plane_state->address.grph_stereo.right_addr;
     71		return true;
     72	} else {
     73		if (pipe_ctx->stream->view_format != VIEW_3D_FORMAT_NONE &&
     74			plane_state->address.type != PLN_ADDR_TYPE_GRPH_STEREO) {
     75			plane_state->address.type = PLN_ADDR_TYPE_GRPH_STEREO;
     76			plane_state->address.grph_stereo.right_addr =
     77			plane_state->address.grph_stereo.left_addr;
     78			plane_state->address.grph_stereo.right_meta_addr =
     79			plane_state->address.grph_stereo.left_meta_addr;
     80		}
     81	}
     82	return false;
     83}
     84
     85static void gpu_addr_to_uma(struct dce_hwseq *hwseq,
     86		PHYSICAL_ADDRESS_LOC *addr)
     87{
     88	bool is_in_uma;
     89
     90	if (hwseq->fb_base.quad_part <= addr->quad_part &&
     91			addr->quad_part < hwseq->fb_top.quad_part) {
     92		addr->quad_part -= hwseq->fb_base.quad_part;
     93		addr->quad_part += hwseq->fb_offset.quad_part;
     94		is_in_uma = true;
     95	} else if (hwseq->fb_offset.quad_part <= addr->quad_part &&
     96			addr->quad_part <= hwseq->uma_top.quad_part) {
     97		is_in_uma = true;
     98	} else {
     99		is_in_uma = false;
    100	}
    101}
    102
    103static void plane_address_in_gpu_space_to_uma(struct dce_hwseq *hwseq,
    104		struct dc_plane_address *addr)
    105{
    106	switch (addr->type) {
    107	case PLN_ADDR_TYPE_GRAPHICS:
    108		gpu_addr_to_uma(hwseq, &addr->grph.addr);
    109		gpu_addr_to_uma(hwseq, &addr->grph.meta_addr);
    110		break;
    111	case PLN_ADDR_TYPE_GRPH_STEREO:
    112		gpu_addr_to_uma(hwseq, &addr->grph_stereo.left_addr);
    113		gpu_addr_to_uma(hwseq, &addr->grph_stereo.left_meta_addr);
    114		gpu_addr_to_uma(hwseq, &addr->grph_stereo.right_addr);
    115		gpu_addr_to_uma(hwseq, &addr->grph_stereo.right_meta_addr);
    116		break;
    117	case PLN_ADDR_TYPE_VIDEO_PROGRESSIVE:
    118		gpu_addr_to_uma(hwseq, &addr->video_progressive.luma_addr);
    119		gpu_addr_to_uma(hwseq, &addr->video_progressive.luma_meta_addr);
    120		gpu_addr_to_uma(hwseq, &addr->video_progressive.chroma_addr);
    121		gpu_addr_to_uma(hwseq, &addr->video_progressive.chroma_meta_addr);
    122		break;
    123	default:
    124		BREAK_TO_DEBUGGER();
    125		break;
    126	}
    127}
    128
    129void dcn201_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx)
    130{
    131	bool addr_patched = false;
    132	PHYSICAL_ADDRESS_LOC addr;
    133	struct dc_plane_state *plane_state = pipe_ctx->plane_state;
    134	struct dce_hwseq *hws = dc->hwseq;
    135	struct dc_plane_address uma;
    136
    137	if (plane_state == NULL)
    138		return;
    139
    140	uma = plane_state->address;
    141	addr_patched = patch_address_for_sbs_tb_stereo(pipe_ctx, &addr);
    142
    143	plane_address_in_gpu_space_to_uma(hws, &uma);
    144
    145	pipe_ctx->plane_res.hubp->funcs->hubp_program_surface_flip_and_addr(
    146			pipe_ctx->plane_res.hubp,
    147			&uma,
    148			plane_state->flip_immediate);
    149
    150	plane_state->status.requested_address = plane_state->address;
    151
    152	if (plane_state->flip_immediate)
    153		plane_state->status.current_address = plane_state->address;
    154
    155	if (addr_patched)
    156		pipe_ctx->plane_state->address.grph_stereo.left_addr = addr;
    157}
    158
    159/* Blank pixel data during initialization */
    160void dcn201_init_blank(
    161		struct dc *dc,
    162		struct timing_generator *tg)
    163{
    164	struct dce_hwseq *hws = dc->hwseq;
    165	enum dc_color_space color_space;
    166	struct tg_color black_color = {0};
    167	struct output_pixel_processor *opp = NULL;
    168	uint32_t num_opps, opp_id_src0, opp_id_src1;
    169	uint32_t otg_active_width, otg_active_height;
    170
    171	/* program opp dpg blank color */
    172	color_space = COLOR_SPACE_SRGB;
    173	color_space_to_black_color(dc, color_space, &black_color);
    174
    175	/* get the OTG active size */
    176	tg->funcs->get_otg_active_size(tg,
    177			&otg_active_width,
    178			&otg_active_height);
    179
    180	/* get the OPTC source */
    181	tg->funcs->get_optc_source(tg, &num_opps, &opp_id_src0, &opp_id_src1);
    182	ASSERT(opp_id_src0 < dc->res_pool->res_cap->num_opp);
    183	opp = dc->res_pool->opps[opp_id_src0];
    184
    185	opp->funcs->opp_set_disp_pattern_generator(
    186			opp,
    187			CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR,
    188			CONTROLLER_DP_COLOR_SPACE_UDEFINED,
    189			COLOR_DEPTH_UNDEFINED,
    190			&black_color,
    191			otg_active_width,
    192			otg_active_height,
    193			0);
    194
    195	hws->funcs.wait_for_blank_complete(opp);
    196}
    197
    198static void read_mmhub_vm_setup(struct dce_hwseq *hws)
    199{
    200	uint32_t fb_base = REG_READ(MC_VM_FB_LOCATION_BASE);
    201	uint32_t fb_top = REG_READ(MC_VM_FB_LOCATION_TOP);
    202	uint32_t fb_offset = REG_READ(MC_VM_FB_OFFSET);
    203
    204	/* MC_VM_FB_LOCATION_TOP is in pages, actual top should add 1 */
    205	fb_top++;
    206
    207	/* bit 23:0 in register map to bit 47:24 in address */
    208	hws->fb_base.low_part = fb_base;
    209	hws->fb_base.quad_part <<= 24;
    210
    211	hws->fb_top.low_part  = fb_top;
    212	hws->fb_top.quad_part <<= 24;
    213	hws->fb_offset.low_part = fb_offset;
    214	hws->fb_offset.quad_part <<= 24;
    215
    216	hws->uma_top.quad_part = hws->fb_top.quad_part
    217			- hws->fb_base.quad_part + hws->fb_offset.quad_part;
    218}
    219
    220void dcn201_init_hw(struct dc *dc)
    221{
    222	int i, j;
    223	struct dce_hwseq *hws = dc->hwseq;
    224	struct resource_pool *res_pool = dc->res_pool;
    225	struct dc_state  *context = dc->current_state;
    226
    227	if (res_pool->dccg->funcs->dccg_init)
    228		res_pool->dccg->funcs->dccg_init(res_pool->dccg);
    229
    230	if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks)
    231		dc->clk_mgr->funcs->init_clocks(dc->clk_mgr);
    232
    233	if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
    234		REG_WRITE(RBBMIF_TIMEOUT_DIS, 0xFFFFFFFF);
    235		REG_WRITE(RBBMIF_TIMEOUT_DIS_2, 0xFFFFFFFF);
    236
    237		hws->funcs.dccg_init(hws);
    238
    239		REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_REFDIV, 2);
    240		REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_ENABLE, 1);
    241		REG_WRITE(REFCLK_CNTL, 0);
    242	} else {
    243		hws->funcs.bios_golden_init(dc);
    244
    245		if (dc->ctx->dc_bios->fw_info_valid) {
    246			res_pool->ref_clocks.xtalin_clock_inKhz =
    247				dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency;
    248
    249			if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
    250				if (res_pool->dccg && res_pool->hubbub) {
    251					(res_pool->dccg->funcs->get_dccg_ref_freq)(res_pool->dccg,
    252							dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency,
    253							&res_pool->ref_clocks.dccg_ref_clock_inKhz);
    254
    255					(res_pool->hubbub->funcs->get_dchub_ref_freq)(res_pool->hubbub,
    256							res_pool->ref_clocks.dccg_ref_clock_inKhz,
    257							&res_pool->ref_clocks.dchub_ref_clock_inKhz);
    258				} else {
    259					res_pool->ref_clocks.dccg_ref_clock_inKhz =
    260							res_pool->ref_clocks.xtalin_clock_inKhz;
    261					res_pool->ref_clocks.dchub_ref_clock_inKhz =
    262							res_pool->ref_clocks.xtalin_clock_inKhz;
    263				}
    264			}
    265		} else
    266			ASSERT_CRITICAL(false);
    267		for (i = 0; i < dc->link_count; i++) {
    268			/* Power up AND update implementation according to the
    269			 * required signal (which may be different from the
    270			 * default signal on connector).
    271			 */
    272			struct dc_link *link = dc->links[i];
    273
    274			link->link_enc->funcs->hw_init(link->link_enc);
    275		}
    276		if (hws->fb_offset.quad_part == 0)
    277			read_mmhub_vm_setup(hws);
    278	}
    279
    280	/* Blank pixel data with OPP DPG */
    281	for (i = 0; i < res_pool->timing_generator_count; i++) {
    282		struct timing_generator *tg = res_pool->timing_generators[i];
    283
    284		if (tg->funcs->is_tg_enabled(tg)) {
    285			dcn201_init_blank(dc, tg);
    286		}
    287	}
    288
    289	for (i = 0; i < res_pool->timing_generator_count; i++) {
    290		struct timing_generator *tg = res_pool->timing_generators[i];
    291
    292		if (tg->funcs->is_tg_enabled(tg))
    293			tg->funcs->lock(tg);
    294	}
    295
    296	for (i = 0; i < res_pool->pipe_count; i++) {
    297		struct dpp *dpp = res_pool->dpps[i];
    298
    299		dpp->funcs->dpp_reset(dpp);
    300	}
    301
    302	/* Reset all MPCC muxes */
    303	res_pool->mpc->funcs->mpc_init(res_pool->mpc);
    304
    305	/* initialize OPP mpc_tree parameter */
    306	for (i = 0; i < res_pool->res_cap->num_opp; i++) {
    307		res_pool->opps[i]->mpc_tree_params.opp_id = res_pool->opps[i]->inst;
    308		res_pool->opps[i]->mpc_tree_params.opp_list = NULL;
    309		for (j = 0; j < MAX_PIPES; j++)
    310			res_pool->opps[i]->mpcc_disconnect_pending[j] = false;
    311	}
    312
    313	for (i = 0; i < res_pool->timing_generator_count; i++) {
    314		struct timing_generator *tg = res_pool->timing_generators[i];
    315		struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
    316		struct hubp *hubp = res_pool->hubps[i];
    317		struct dpp *dpp = res_pool->dpps[i];
    318
    319		pipe_ctx->stream_res.tg = tg;
    320		pipe_ctx->pipe_idx = i;
    321
    322		pipe_ctx->plane_res.hubp = hubp;
    323		pipe_ctx->plane_res.dpp = dpp;
    324		pipe_ctx->plane_res.mpcc_inst = dpp->inst;
    325		hubp->mpcc_id = dpp->inst;
    326		hubp->opp_id = OPP_ID_INVALID;
    327		hubp->power_gated = false;
    328		pipe_ctx->stream_res.opp = NULL;
    329
    330		hubp->funcs->hubp_init(hubp);
    331
    332		res_pool->opps[i]->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true;
    333		pipe_ctx->stream_res.opp = res_pool->opps[i];
    334		/*To do: number of MPCC != number of opp*/
    335		hws->funcs.plane_atomic_disconnect(dc, pipe_ctx);
    336	}
    337
    338	/* initialize DWB pointer to MCIF_WB */
    339	for (i = 0; i < res_pool->res_cap->num_dwb; i++)
    340		res_pool->dwbc[i]->mcif = res_pool->mcif_wb[i];
    341
    342	for (i = 0; i < res_pool->timing_generator_count; i++) {
    343		struct timing_generator *tg = res_pool->timing_generators[i];
    344
    345		if (tg->funcs->is_tg_enabled(tg))
    346			tg->funcs->unlock(tg);
    347	}
    348
    349	for (i = 0; i < res_pool->pipe_count; i++) {
    350		struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
    351
    352		dc->hwss.disable_plane(dc, pipe_ctx);
    353
    354		pipe_ctx->stream_res.tg = NULL;
    355		pipe_ctx->plane_res.hubp = NULL;
    356	}
    357
    358	for (i = 0; i < res_pool->timing_generator_count; i++) {
    359		struct timing_generator *tg = res_pool->timing_generators[i];
    360
    361		tg->funcs->tg_init(tg);
    362	}
    363
    364	/* end of FPGA. Below if real ASIC */
    365	if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment))
    366		return;
    367
    368	for (i = 0; i < res_pool->audio_count; i++) {
    369		struct audio *audio = res_pool->audios[i];
    370
    371		audio->funcs->hw_init(audio);
    372	}
    373
    374	/* power AFMT HDMI memory TODO: may move to dis/en output save power*/
    375	REG_WRITE(DIO_MEM_PWR_CTRL, 0);
    376
    377	if (!dc->debug.disable_clock_gate) {
    378		/* enable all DCN clock gating */
    379		REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0);
    380
    381		REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0);
    382
    383		REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0);
    384	}
    385}
    386
    387/* trigger HW to start disconnect plane from stream on the next vsync */
    388void dcn201_plane_atomic_disconnect(struct dc *dc, struct pipe_ctx *pipe_ctx)
    389{
    390	struct dce_hwseq *hws = dc->hwseq;
    391	struct hubp *hubp = pipe_ctx->plane_res.hubp;
    392	int dpp_id = pipe_ctx->plane_res.dpp->inst;
    393	struct mpc *mpc = dc->res_pool->mpc;
    394	struct mpc_tree *mpc_tree_params;
    395	struct mpcc *mpcc_to_remove = NULL;
    396	struct output_pixel_processor *opp = pipe_ctx->stream_res.opp;
    397	bool mpcc_removed = false;
    398
    399	mpc_tree_params = &(opp->mpc_tree_params);
    400
    401	/* check if this plane is being used by an MPCC in the secondary blending chain */
    402	if (mpc->funcs->get_mpcc_for_dpp_from_secondary)
    403		mpcc_to_remove = mpc->funcs->get_mpcc_for_dpp_from_secondary(mpc_tree_params, dpp_id);
    404
    405	/* remove MPCC from secondary if being used */
    406	if (mpcc_to_remove != NULL && mpc->funcs->remove_mpcc_from_secondary) {
    407		mpc->funcs->remove_mpcc_from_secondary(mpc, mpc_tree_params, mpcc_to_remove);
    408		mpcc_removed = true;
    409	}
    410
    411	/* check if this MPCC is already being used for this plane (dpp) in the primary blending chain */
    412	mpcc_to_remove = mpc->funcs->get_mpcc_for_dpp(mpc_tree_params, dpp_id);
    413	if (mpcc_to_remove != NULL) {
    414		mpc->funcs->remove_mpcc(mpc, mpc_tree_params, mpcc_to_remove);
    415		mpcc_removed = true;
    416	}
    417
    418	/*Already reset*/
    419	if (mpcc_removed == false)
    420		return;
    421
    422	if (opp != NULL)
    423		opp->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true;
    424
    425	dc->optimized_required = true;
    426
    427	if (hubp->funcs->hubp_disconnect)
    428		hubp->funcs->hubp_disconnect(hubp);
    429
    430	if (dc->debug.sanity_checks)
    431		hws->funcs.verify_allow_pstate_change_high(dc);
    432}
    433
    434void dcn201_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx)
    435{
    436	struct hubp *hubp = pipe_ctx->plane_res.hubp;
    437	struct mpcc_blnd_cfg blnd_cfg;
    438	bool per_pixel_alpha = pipe_ctx->plane_state->per_pixel_alpha && pipe_ctx->bottom_pipe;
    439	int mpcc_id, dpp_id;
    440	struct mpcc *new_mpcc;
    441	struct mpcc *remove_mpcc = NULL;
    442	struct mpc *mpc = dc->res_pool->mpc;
    443	struct mpc_tree *mpc_tree_params = &(pipe_ctx->stream_res.opp->mpc_tree_params);
    444
    445	if (dc->debug.visual_confirm == VISUAL_CONFIRM_HDR) {
    446		get_hdr_visual_confirm_color(
    447				pipe_ctx, &blnd_cfg.black_color);
    448	} else if (dc->debug.visual_confirm == VISUAL_CONFIRM_SURFACE) {
    449		get_surface_visual_confirm_color(
    450				pipe_ctx, &blnd_cfg.black_color);
    451	} else {
    452		color_space_to_black_color(
    453				dc, pipe_ctx->stream->output_color_space,
    454				&blnd_cfg.black_color);
    455	}
    456
    457	if (per_pixel_alpha)
    458		blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA;
    459	else
    460		blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_GLOBAL_ALPHA;
    461
    462	blnd_cfg.overlap_only = false;
    463
    464	if (pipe_ctx->plane_state->global_alpha_value)
    465		blnd_cfg.global_alpha = pipe_ctx->plane_state->global_alpha_value;
    466	else
    467		blnd_cfg.global_alpha = 0xff;
    468
    469	blnd_cfg.global_gain = 0xff;
    470	blnd_cfg.background_color_bpc = 4;
    471	blnd_cfg.bottom_gain_mode = 0;
    472	blnd_cfg.top_gain = 0x1f000;
    473	blnd_cfg.bottom_inside_gain = 0x1f000;
    474	blnd_cfg.bottom_outside_gain = 0x1f000;
    475	/*the input to MPCC is RGB*/
    476	blnd_cfg.black_color.color_b_cb = 0;
    477	blnd_cfg.black_color.color_g_y = 0;
    478	blnd_cfg.black_color.color_r_cr = 0;
    479
    480	/* DCN1.0 has output CM before MPC which seems to screw with
    481	 * pre-multiplied alpha. This is a w/a hopefully unnecessary for DCN2.
    482	 */
    483	blnd_cfg.pre_multiplied_alpha = per_pixel_alpha;
    484
    485	/*
    486	 * TODO: remove hack
    487	 * Note: currently there is a bug in init_hw such that
    488	 * on resume from hibernate, BIOS sets up MPCC0, and
    489	 * we do mpcc_remove but the mpcc cannot go to idle
    490	 * after remove. This cause us to pick mpcc1 here,
    491	 * which causes a pstate hang for yet unknown reason.
    492	 */
    493	dpp_id = hubp->inst;
    494	mpcc_id = dpp_id;
    495
    496	/* If there is no full update, don't need to touch MPC tree*/
    497	if (!pipe_ctx->plane_state->update_flags.bits.full_update) {
    498		dc->hwss.update_visual_confirm_color(dc, pipe_ctx, &blnd_cfg.black_color, mpcc_id);
    499		mpc->funcs->update_blending(mpc, &blnd_cfg, mpcc_id);
    500		return;
    501	}
    502
    503	/* check if this plane is being used by an MPCC in the secondary blending chain */
    504	if (mpc->funcs->get_mpcc_for_dpp_from_secondary)
    505		remove_mpcc = mpc->funcs->get_mpcc_for_dpp_from_secondary(mpc_tree_params, dpp_id);
    506
    507	/* remove MPCC from secondary if being used */
    508	if (remove_mpcc != NULL && mpc->funcs->remove_mpcc_from_secondary)
    509		mpc->funcs->remove_mpcc_from_secondary(mpc, mpc_tree_params, remove_mpcc);
    510
    511	/* check if this MPCC is already being used for this plane (dpp) in the primary blending chain */
    512	remove_mpcc = mpc->funcs->get_mpcc_for_dpp(mpc_tree_params, dpp_id);
    513	/* remove MPCC if being used */
    514
    515	if (remove_mpcc != NULL)
    516		mpc->funcs->remove_mpcc(mpc, mpc_tree_params, remove_mpcc);
    517	else
    518		if (dc->debug.sanity_checks)
    519			mpc->funcs->assert_mpcc_idle_before_connect(
    520					dc->res_pool->mpc, mpcc_id);
    521
    522	/* Call MPC to insert new plane */
    523	dc->hwss.update_visual_confirm_color(dc, pipe_ctx, &blnd_cfg.black_color, mpcc_id);
    524	new_mpcc = mpc->funcs->insert_plane(dc->res_pool->mpc,
    525			mpc_tree_params,
    526			&blnd_cfg,
    527			NULL,
    528			NULL,
    529			dpp_id,
    530			mpcc_id);
    531
    532	ASSERT(new_mpcc != NULL);
    533	hubp->opp_id = pipe_ctx->stream_res.opp->inst;
    534	hubp->mpcc_id = mpcc_id;
    535}
    536
    537void dcn201_pipe_control_lock(
    538	struct dc *dc,
    539	struct pipe_ctx *pipe,
    540	bool lock)
    541{
    542	struct dce_hwseq *hws = dc->hwseq;
    543	struct hubp *hubp = NULL;
    544	hubp = dc->res_pool->hubps[pipe->pipe_idx];
    545	/* use TG master update lock to lock everything on the TG
    546	 * therefore only top pipe need to lock
    547	 */
    548	if (pipe->top_pipe)
    549		return;
    550
    551	if (dc->debug.sanity_checks)
    552		hws->funcs.verify_allow_pstate_change_high(dc);
    553
    554	if (pipe->plane_state != NULL && pipe->plane_state->triplebuffer_flips) {
    555		if (lock)
    556			pipe->stream_res.tg->funcs->triplebuffer_lock(pipe->stream_res.tg);
    557		else
    558			pipe->stream_res.tg->funcs->triplebuffer_unlock(pipe->stream_res.tg);
    559	} else {
    560		if (lock)
    561			pipe->stream_res.tg->funcs->lock(pipe->stream_res.tg);
    562		else
    563			pipe->stream_res.tg->funcs->unlock(pipe->stream_res.tg);
    564	}
    565
    566	if (dc->debug.sanity_checks)
    567		hws->funcs.verify_allow_pstate_change_high(dc);
    568}
    569
    570void dcn201_set_cursor_attribute(struct pipe_ctx *pipe_ctx)
    571{
    572	struct dc_cursor_attributes *attributes = &pipe_ctx->stream->cursor_attributes;
    573
    574	gpu_addr_to_uma(pipe_ctx->stream->ctx->dc->hwseq, &attributes->address);
    575
    576	pipe_ctx->plane_res.hubp->funcs->set_cursor_attributes(
    577			pipe_ctx->plane_res.hubp, attributes);
    578	pipe_ctx->plane_res.dpp->funcs->set_cursor_attributes(
    579		pipe_ctx->plane_res.dpp, attributes);
    580}
    581
    582void dcn201_set_dmdata_attributes(struct pipe_ctx *pipe_ctx)
    583{
    584	struct dc_dmdata_attributes attr = { 0 };
    585	struct hubp *hubp = pipe_ctx->plane_res.hubp;
    586
    587	gpu_addr_to_uma(pipe_ctx->stream->ctx->dc->hwseq,
    588			&pipe_ctx->stream->dmdata_address);
    589
    590	attr.dmdata_mode = DMDATA_HW_MODE;
    591	attr.dmdata_size =
    592		dc_is_hdmi_signal(pipe_ctx->stream->signal) ? 32 : 36;
    593	attr.address.quad_part =
    594			pipe_ctx->stream->dmdata_address.quad_part;
    595	attr.dmdata_dl_delta = 0;
    596	attr.dmdata_qos_mode = 0;
    597	attr.dmdata_qos_level = 0;
    598	attr.dmdata_repeat = 1; /* always repeat */
    599	attr.dmdata_updated = 1;
    600	attr.dmdata_sw_data = NULL;
    601
    602	hubp->funcs->dmdata_set_attributes(hubp, &attr);
    603}
    604
    605void dcn201_unblank_stream(struct pipe_ctx *pipe_ctx,
    606		struct dc_link_settings *link_settings)
    607{
    608	struct encoder_unblank_param params = { { 0 } };
    609	struct dc_stream_state *stream = pipe_ctx->stream;
    610	struct dc_link *link = stream->link;
    611	struct dce_hwseq *hws = link->dc->hwseq;
    612
    613	/* only 3 items below are used by unblank */
    614	params.timing = pipe_ctx->stream->timing;
    615
    616	params.link_settings.link_rate = link_settings->link_rate;
    617
    618	if (dc_is_dp_signal(pipe_ctx->stream->signal)) {
    619		/*check whether it is half the rate*/
    620		if (optc201_is_two_pixels_per_containter(&stream->timing))
    621			params.timing.pix_clk_100hz /= 2;
    622
    623		pipe_ctx->stream_res.stream_enc->funcs->dp_unblank(link, pipe_ctx->stream_res.stream_enc, &params);
    624	}
    625
    626	if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP) {
    627		hws->funcs.edp_backlight_control(link, true);
    628	}
    629}