xref: /linux/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_hwseq.c (revision c771600c6af14749609b49565ffb4cac2959710d)
13f68c01bSZhan Liu /*
23f68c01bSZhan Liu  * Copyright 2016 Advanced Micro Devices, Inc.
33f68c01bSZhan Liu  *
43f68c01bSZhan Liu  * Permission is hereby granted, free of charge, to any person obtaining a
53f68c01bSZhan Liu  * copy of this software and associated documentation files (the "Software"),
63f68c01bSZhan Liu  * to deal in the Software without restriction, including without limitation
73f68c01bSZhan Liu  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
83f68c01bSZhan Liu  * and/or sell copies of the Software, and to permit persons to whom the
93f68c01bSZhan Liu  * Software is furnished to do so, subject to the following conditions:
103f68c01bSZhan Liu  *
113f68c01bSZhan Liu  * The above copyright notice and this permission notice shall be included in
123f68c01bSZhan Liu  * all copies or substantial portions of the Software.
133f68c01bSZhan Liu  *
143f68c01bSZhan Liu  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
153f68c01bSZhan Liu  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
163f68c01bSZhan Liu  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
173f68c01bSZhan Liu  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
183f68c01bSZhan Liu  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
193f68c01bSZhan Liu  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
203f68c01bSZhan Liu  * OTHER DEALINGS IN THE SOFTWARE.
213f68c01bSZhan Liu  *
223f68c01bSZhan Liu  * Authors: AMD
233f68c01bSZhan Liu  *
243f68c01bSZhan Liu  */
253f68c01bSZhan Liu 
263f68c01bSZhan Liu #include "dm_services.h"
273f68c01bSZhan Liu #include "basics/dc_common.h"
283f68c01bSZhan Liu #include "core_types.h"
293f68c01bSZhan Liu #include "resource.h"
303f68c01bSZhan Liu #include "dcn201_hwseq.h"
31e53524cdSMounika Adhuri #include "dcn201/dcn201_optc.h"
323f68c01bSZhan Liu #include "dce/dce_hwseq.h"
333f68c01bSZhan Liu #include "hubp.h"
343f68c01bSZhan Liu #include "dchubbub.h"
353f68c01bSZhan Liu #include "timing_generator.h"
363f68c01bSZhan Liu #include "opp.h"
373f68c01bSZhan Liu #include "ipp.h"
383f68c01bSZhan Liu #include "mpc.h"
393f68c01bSZhan Liu #include "dccg.h"
403f68c01bSZhan Liu #include "clk_mgr.h"
413f68c01bSZhan Liu #include "reg_helper.h"
423f68c01bSZhan Liu 
433f68c01bSZhan Liu #define CTX \
443f68c01bSZhan Liu 	hws->ctx
453f68c01bSZhan Liu 
463f68c01bSZhan Liu #define REG(reg)\
473f68c01bSZhan Liu 	hws->regs->reg
483f68c01bSZhan Liu 
493f68c01bSZhan Liu #define DC_LOGGER \
503f68c01bSZhan Liu 	dc->ctx->logger
513f68c01bSZhan Liu 
523f68c01bSZhan Liu #undef FN
533f68c01bSZhan Liu #define FN(reg_name, field_name) \
543f68c01bSZhan Liu 	hws->shifts->field_name, hws->masks->field_name
553f68c01bSZhan Liu 
patch_address_for_sbs_tb_stereo(struct pipe_ctx * pipe_ctx,PHYSICAL_ADDRESS_LOC * addr)563f68c01bSZhan Liu static bool patch_address_for_sbs_tb_stereo(
573f68c01bSZhan Liu 		struct pipe_ctx *pipe_ctx, PHYSICAL_ADDRESS_LOC *addr)
583f68c01bSZhan Liu {
593f68c01bSZhan Liu 	struct dc_plane_state *plane_state = pipe_ctx->plane_state;
603f68c01bSZhan Liu 	bool sec_split = pipe_ctx->top_pipe &&
613f68c01bSZhan Liu 		pipe_ctx->top_pipe->plane_state == pipe_ctx->plane_state;
623f68c01bSZhan Liu 
633f68c01bSZhan Liu 	if (sec_split && plane_state->address.type == PLN_ADDR_TYPE_GRPH_STEREO &&
643f68c01bSZhan Liu 		(pipe_ctx->stream->timing.timing_3d_format ==
653f68c01bSZhan Liu 			TIMING_3D_FORMAT_SIDE_BY_SIDE ||
663f68c01bSZhan Liu 		pipe_ctx->stream->timing.timing_3d_format ==
673f68c01bSZhan Liu 			TIMING_3D_FORMAT_TOP_AND_BOTTOM)) {
683f68c01bSZhan Liu 		*addr = plane_state->address.grph_stereo.left_addr;
693f68c01bSZhan Liu 		plane_state->address.grph_stereo.left_addr =
703f68c01bSZhan Liu 			plane_state->address.grph_stereo.right_addr;
713f68c01bSZhan Liu 		return true;
723f68c01bSZhan Liu 	} else {
733f68c01bSZhan Liu 		if (pipe_ctx->stream->view_format != VIEW_3D_FORMAT_NONE &&
743f68c01bSZhan Liu 			plane_state->address.type != PLN_ADDR_TYPE_GRPH_STEREO) {
753f68c01bSZhan Liu 			plane_state->address.type = PLN_ADDR_TYPE_GRPH_STEREO;
763f68c01bSZhan Liu 			plane_state->address.grph_stereo.right_addr =
773f68c01bSZhan Liu 			plane_state->address.grph_stereo.left_addr;
783f68c01bSZhan Liu 			plane_state->address.grph_stereo.right_meta_addr =
793f68c01bSZhan Liu 			plane_state->address.grph_stereo.left_meta_addr;
803f68c01bSZhan Liu 		}
813f68c01bSZhan Liu 	}
823f68c01bSZhan Liu 	return false;
833f68c01bSZhan Liu }
843f68c01bSZhan Liu 
gpu_addr_to_uma(struct dce_hwseq * hwseq,PHYSICAL_ADDRESS_LOC * addr)858434f818SCharlene Liu static bool gpu_addr_to_uma(struct dce_hwseq *hwseq,
863f68c01bSZhan Liu 		PHYSICAL_ADDRESS_LOC *addr)
873f68c01bSZhan Liu {
883f68c01bSZhan Liu 	bool is_in_uma;
893f68c01bSZhan Liu 
903f68c01bSZhan Liu 	if (hwseq->fb_base.quad_part <= addr->quad_part &&
913f68c01bSZhan Liu 			addr->quad_part < hwseq->fb_top.quad_part) {
923f68c01bSZhan Liu 		addr->quad_part -= hwseq->fb_base.quad_part;
933f68c01bSZhan Liu 		addr->quad_part += hwseq->fb_offset.quad_part;
943f68c01bSZhan Liu 		is_in_uma = true;
953f68c01bSZhan Liu 	} else if (hwseq->fb_offset.quad_part <= addr->quad_part &&
963f68c01bSZhan Liu 			addr->quad_part <= hwseq->uma_top.quad_part) {
973f68c01bSZhan Liu 		is_in_uma = true;
9802fb803dSRodrigo Siqueira 	} else if (addr->quad_part == 0) {
9902fb803dSRodrigo Siqueira 		is_in_uma = false;
1003f68c01bSZhan Liu 	} else {
1013f68c01bSZhan Liu 		is_in_uma = false;
10202fb803dSRodrigo Siqueira 		BREAK_TO_DEBUGGER();
1033f68c01bSZhan Liu 	}
1048434f818SCharlene Liu 	return is_in_uma;
1053f68c01bSZhan Liu }
1063f68c01bSZhan Liu 
plane_address_in_gpu_space_to_uma(struct dce_hwseq * hwseq,struct dc_plane_address * addr)1073f68c01bSZhan Liu static void plane_address_in_gpu_space_to_uma(struct dce_hwseq *hwseq,
1083f68c01bSZhan Liu 		struct dc_plane_address *addr)
1093f68c01bSZhan Liu {
1103f68c01bSZhan Liu 	switch (addr->type) {
1113f68c01bSZhan Liu 	case PLN_ADDR_TYPE_GRAPHICS:
1123f68c01bSZhan Liu 		gpu_addr_to_uma(hwseq, &addr->grph.addr);
1133f68c01bSZhan Liu 		gpu_addr_to_uma(hwseq, &addr->grph.meta_addr);
1143f68c01bSZhan Liu 		break;
1153f68c01bSZhan Liu 	case PLN_ADDR_TYPE_GRPH_STEREO:
1163f68c01bSZhan Liu 		gpu_addr_to_uma(hwseq, &addr->grph_stereo.left_addr);
1173f68c01bSZhan Liu 		gpu_addr_to_uma(hwseq, &addr->grph_stereo.left_meta_addr);
1183f68c01bSZhan Liu 		gpu_addr_to_uma(hwseq, &addr->grph_stereo.right_addr);
1193f68c01bSZhan Liu 		gpu_addr_to_uma(hwseq, &addr->grph_stereo.right_meta_addr);
1203f68c01bSZhan Liu 		break;
1213f68c01bSZhan Liu 	case PLN_ADDR_TYPE_VIDEO_PROGRESSIVE:
1223f68c01bSZhan Liu 		gpu_addr_to_uma(hwseq, &addr->video_progressive.luma_addr);
1233f68c01bSZhan Liu 		gpu_addr_to_uma(hwseq, &addr->video_progressive.luma_meta_addr);
1243f68c01bSZhan Liu 		gpu_addr_to_uma(hwseq, &addr->video_progressive.chroma_addr);
1253f68c01bSZhan Liu 		gpu_addr_to_uma(hwseq, &addr->video_progressive.chroma_meta_addr);
1263f68c01bSZhan Liu 		break;
1273f68c01bSZhan Liu 	default:
1283f68c01bSZhan Liu 		BREAK_TO_DEBUGGER();
1293f68c01bSZhan Liu 		break;
1303f68c01bSZhan Liu 	}
1313f68c01bSZhan Liu }
1323f68c01bSZhan Liu 
dcn201_update_plane_addr(const struct dc * dc,struct pipe_ctx * pipe_ctx)1333f68c01bSZhan Liu void dcn201_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx)
1343f68c01bSZhan Liu {
1353f68c01bSZhan Liu 	bool addr_patched = false;
1363f68c01bSZhan Liu 	PHYSICAL_ADDRESS_LOC addr;
1373f68c01bSZhan Liu 	struct dc_plane_state *plane_state = pipe_ctx->plane_state;
1383f68c01bSZhan Liu 	struct dce_hwseq *hws = dc->hwseq;
139f28cad86SJosé Expósito 	struct dc_plane_address uma;
1403f68c01bSZhan Liu 
1413f68c01bSZhan Liu 	if (plane_state == NULL)
1423f68c01bSZhan Liu 		return;
1433f68c01bSZhan Liu 
144f28cad86SJosé Expósito 	uma = plane_state->address;
1453f68c01bSZhan Liu 	addr_patched = patch_address_for_sbs_tb_stereo(pipe_ctx, &addr);
1463f68c01bSZhan Liu 
1473f68c01bSZhan Liu 	plane_address_in_gpu_space_to_uma(hws, &uma);
1483f68c01bSZhan Liu 
1493f68c01bSZhan Liu 	pipe_ctx->plane_res.hubp->funcs->hubp_program_surface_flip_and_addr(
1503f68c01bSZhan Liu 			pipe_ctx->plane_res.hubp,
1513f68c01bSZhan Liu 			&uma,
1523f68c01bSZhan Liu 			plane_state->flip_immediate);
1533f68c01bSZhan Liu 
1543f68c01bSZhan Liu 	plane_state->status.requested_address = plane_state->address;
1553f68c01bSZhan Liu 
1563f68c01bSZhan Liu 	if (plane_state->flip_immediate)
1573f68c01bSZhan Liu 		plane_state->status.current_address = plane_state->address;
1583f68c01bSZhan Liu 
1593f68c01bSZhan Liu 	if (addr_patched)
1603f68c01bSZhan Liu 		pipe_ctx->plane_state->address.grph_stereo.left_addr = addr;
1613f68c01bSZhan Liu }
1623f68c01bSZhan Liu 
1633f68c01bSZhan Liu /* Blank pixel data during initialization */
dcn201_init_blank(struct dc * dc,struct timing_generator * tg)1643f68c01bSZhan Liu void dcn201_init_blank(
1653f68c01bSZhan Liu 		struct dc *dc,
1663f68c01bSZhan Liu 		struct timing_generator *tg)
1673f68c01bSZhan Liu {
1683f68c01bSZhan Liu 	struct dce_hwseq *hws = dc->hwseq;
1693f68c01bSZhan Liu 	enum dc_color_space color_space;
1703f68c01bSZhan Liu 	struct tg_color black_color = {0};
1713f68c01bSZhan Liu 	struct output_pixel_processor *opp = NULL;
1723f68c01bSZhan Liu 	uint32_t num_opps, opp_id_src0, opp_id_src1;
173ba3193faSAlex Hung 	uint32_t otg_active_width = 0, otg_active_height = 0;
1743f68c01bSZhan Liu 
1753f68c01bSZhan Liu 	/* program opp dpg blank color */
1763f68c01bSZhan Liu 	color_space = COLOR_SPACE_SRGB;
1773f68c01bSZhan Liu 	color_space_to_black_color(dc, color_space, &black_color);
1783f68c01bSZhan Liu 
1793f68c01bSZhan Liu 	/* get the OTG active size */
1803f68c01bSZhan Liu 	tg->funcs->get_otg_active_size(tg,
1813f68c01bSZhan Liu 			&otg_active_width,
1823f68c01bSZhan Liu 			&otg_active_height);
1833f68c01bSZhan Liu 
1843f68c01bSZhan Liu 	/* get the OPTC source */
1853f68c01bSZhan Liu 	tg->funcs->get_optc_source(tg, &num_opps, &opp_id_src0, &opp_id_src1);
1863f68c01bSZhan Liu 	ASSERT(opp_id_src0 < dc->res_pool->res_cap->num_opp);
1873f68c01bSZhan Liu 	opp = dc->res_pool->opps[opp_id_src0];
1883f68c01bSZhan Liu 
1893f68c01bSZhan Liu 	opp->funcs->opp_set_disp_pattern_generator(
1903f68c01bSZhan Liu 			opp,
1913f68c01bSZhan Liu 			CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR,
1923f68c01bSZhan Liu 			CONTROLLER_DP_COLOR_SPACE_UDEFINED,
1933f68c01bSZhan Liu 			COLOR_DEPTH_UNDEFINED,
1943f68c01bSZhan Liu 			&black_color,
1953f68c01bSZhan Liu 			otg_active_width,
1963f68c01bSZhan Liu 			otg_active_height,
1973f68c01bSZhan Liu 			0);
1983f68c01bSZhan Liu 
1993f68c01bSZhan Liu 	hws->funcs.wait_for_blank_complete(opp);
2003f68c01bSZhan Liu }
2013f68c01bSZhan Liu 
read_mmhub_vm_setup(struct dce_hwseq * hws)2023f68c01bSZhan Liu static void read_mmhub_vm_setup(struct dce_hwseq *hws)
2033f68c01bSZhan Liu {
2043f68c01bSZhan Liu 	uint32_t fb_base = REG_READ(MC_VM_FB_LOCATION_BASE);
2053f68c01bSZhan Liu 	uint32_t fb_top = REG_READ(MC_VM_FB_LOCATION_TOP);
2063f68c01bSZhan Liu 	uint32_t fb_offset = REG_READ(MC_VM_FB_OFFSET);
2073f68c01bSZhan Liu 
2083f68c01bSZhan Liu 	/* MC_VM_FB_LOCATION_TOP is in pages, actual top should add 1 */
2093f68c01bSZhan Liu 	fb_top++;
2103f68c01bSZhan Liu 
2113f68c01bSZhan Liu 	/* bit 23:0 in register map to bit 47:24 in address */
2123f68c01bSZhan Liu 	hws->fb_base.low_part = fb_base;
2133f68c01bSZhan Liu 	hws->fb_base.quad_part <<= 24;
2143f68c01bSZhan Liu 
2153f68c01bSZhan Liu 	hws->fb_top.low_part  = fb_top;
2163f68c01bSZhan Liu 	hws->fb_top.quad_part <<= 24;
2173f68c01bSZhan Liu 	hws->fb_offset.low_part = fb_offset;
2183f68c01bSZhan Liu 	hws->fb_offset.quad_part <<= 24;
2193f68c01bSZhan Liu 
2203f68c01bSZhan Liu 	hws->uma_top.quad_part = hws->fb_top.quad_part
2213f68c01bSZhan Liu 			- hws->fb_base.quad_part + hws->fb_offset.quad_part;
2223f68c01bSZhan Liu }
2233f68c01bSZhan Liu 
dcn201_init_hw(struct dc * dc)2243f68c01bSZhan Liu void dcn201_init_hw(struct dc *dc)
2253f68c01bSZhan Liu {
2263f68c01bSZhan Liu 	int i, j;
2273f68c01bSZhan Liu 	struct dce_hwseq *hws = dc->hwseq;
2283f68c01bSZhan Liu 	struct resource_pool *res_pool = dc->res_pool;
2293f68c01bSZhan Liu 	struct dc_state  *context = dc->current_state;
2303f68c01bSZhan Liu 
2313f68c01bSZhan Liu 	if (res_pool->dccg->funcs->dccg_init)
2323f68c01bSZhan Liu 		res_pool->dccg->funcs->dccg_init(res_pool->dccg);
2333f68c01bSZhan Liu 
2343f68c01bSZhan Liu 	if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks)
2353f68c01bSZhan Liu 		dc->clk_mgr->funcs->init_clocks(dc->clk_mgr);
2363f68c01bSZhan Liu 
2373f68c01bSZhan Liu 	hws->funcs.bios_golden_init(dc);
2383f68c01bSZhan Liu 
2393f68c01bSZhan Liu 	if (dc->ctx->dc_bios->fw_info_valid) {
2403f68c01bSZhan Liu 		res_pool->ref_clocks.xtalin_clock_inKhz =
2413f68c01bSZhan Liu 			dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency;
2423f68c01bSZhan Liu 
2431a664dc0SAlex Hung 		if (res_pool->hubbub) {
2443f68c01bSZhan Liu 			(res_pool->dccg->funcs->get_dccg_ref_freq)(res_pool->dccg,
2453f68c01bSZhan Liu 					dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency,
2463f68c01bSZhan Liu 					&res_pool->ref_clocks.dccg_ref_clock_inKhz);
2473f68c01bSZhan Liu 
2483f68c01bSZhan Liu 			(res_pool->hubbub->funcs->get_dchub_ref_freq)(res_pool->hubbub,
2493f68c01bSZhan Liu 					res_pool->ref_clocks.dccg_ref_clock_inKhz,
2503f68c01bSZhan Liu 					&res_pool->ref_clocks.dchub_ref_clock_inKhz);
2513f68c01bSZhan Liu 		} else {
2523f68c01bSZhan Liu 			res_pool->ref_clocks.dccg_ref_clock_inKhz =
2533f68c01bSZhan Liu 					res_pool->ref_clocks.xtalin_clock_inKhz;
2543f68c01bSZhan Liu 			res_pool->ref_clocks.dchub_ref_clock_inKhz =
2553f68c01bSZhan Liu 					res_pool->ref_clocks.xtalin_clock_inKhz;
2563f68c01bSZhan Liu 		}
2573f68c01bSZhan Liu 	} else
2583f68c01bSZhan Liu 		ASSERT_CRITICAL(false);
2593f68c01bSZhan Liu 	for (i = 0; i < dc->link_count; i++) {
2603f68c01bSZhan Liu 		/* Power up AND update implementation according to the
2613f68c01bSZhan Liu 		 * required signal (which may be different from the
2623f68c01bSZhan Liu 		 * default signal on connector).
2633f68c01bSZhan Liu 		 */
2643f68c01bSZhan Liu 		struct dc_link *link = dc->links[i];
2653f68c01bSZhan Liu 
2663f68c01bSZhan Liu 		link->link_enc->funcs->hw_init(link->link_enc);
2673f68c01bSZhan Liu 	}
2683f68c01bSZhan Liu 	if (hws->fb_offset.quad_part == 0)
2693f68c01bSZhan Liu 		read_mmhub_vm_setup(hws);
2703f68c01bSZhan Liu 
2713f68c01bSZhan Liu 	/* Blank pixel data with OPP DPG */
2723f68c01bSZhan Liu 	for (i = 0; i < res_pool->timing_generator_count; i++) {
2733f68c01bSZhan Liu 		struct timing_generator *tg = res_pool->timing_generators[i];
2743f68c01bSZhan Liu 
2753f68c01bSZhan Liu 		if (tg->funcs->is_tg_enabled(tg)) {
2763f68c01bSZhan Liu 			dcn201_init_blank(dc, tg);
2773f68c01bSZhan Liu 		}
2783f68c01bSZhan Liu 	}
2793f68c01bSZhan Liu 
2803f68c01bSZhan Liu 	for (i = 0; i < res_pool->timing_generator_count; i++) {
2813f68c01bSZhan Liu 		struct timing_generator *tg = res_pool->timing_generators[i];
2823f68c01bSZhan Liu 
2833f68c01bSZhan Liu 		if (tg->funcs->is_tg_enabled(tg))
2843f68c01bSZhan Liu 			tg->funcs->lock(tg);
2853f68c01bSZhan Liu 	}
2863f68c01bSZhan Liu 
2873f68c01bSZhan Liu 	for (i = 0; i < res_pool->pipe_count; i++) {
2883f68c01bSZhan Liu 		struct dpp *dpp = res_pool->dpps[i];
2893f68c01bSZhan Liu 
2903f68c01bSZhan Liu 		dpp->funcs->dpp_reset(dpp);
2913f68c01bSZhan Liu 	}
2923f68c01bSZhan Liu 
2933f68c01bSZhan Liu 	/* Reset all MPCC muxes */
2943f68c01bSZhan Liu 	res_pool->mpc->funcs->mpc_init(res_pool->mpc);
2953f68c01bSZhan Liu 
2963f68c01bSZhan Liu 	/* initialize OPP mpc_tree parameter */
2973f68c01bSZhan Liu 	for (i = 0; i < res_pool->res_cap->num_opp; i++) {
2983f68c01bSZhan Liu 		res_pool->opps[i]->mpc_tree_params.opp_id = res_pool->opps[i]->inst;
2993f68c01bSZhan Liu 		res_pool->opps[i]->mpc_tree_params.opp_list = NULL;
3003f68c01bSZhan Liu 		for (j = 0; j < MAX_PIPES; j++)
3013f68c01bSZhan Liu 			res_pool->opps[i]->mpcc_disconnect_pending[j] = false;
3023f68c01bSZhan Liu 	}
3033f68c01bSZhan Liu 
3043f68c01bSZhan Liu 	for (i = 0; i < res_pool->timing_generator_count; i++) {
3053f68c01bSZhan Liu 		struct timing_generator *tg = res_pool->timing_generators[i];
3063f68c01bSZhan Liu 		struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
3073f68c01bSZhan Liu 		struct hubp *hubp = res_pool->hubps[i];
3083f68c01bSZhan Liu 		struct dpp *dpp = res_pool->dpps[i];
3093f68c01bSZhan Liu 
3103f68c01bSZhan Liu 		pipe_ctx->stream_res.tg = tg;
3113f68c01bSZhan Liu 		pipe_ctx->pipe_idx = i;
3123f68c01bSZhan Liu 
3133f68c01bSZhan Liu 		pipe_ctx->plane_res.hubp = hubp;
3143f68c01bSZhan Liu 		pipe_ctx->plane_res.dpp = dpp;
3153f68c01bSZhan Liu 		pipe_ctx->plane_res.mpcc_inst = dpp->inst;
3163f68c01bSZhan Liu 		hubp->mpcc_id = dpp->inst;
3173f68c01bSZhan Liu 		hubp->opp_id = OPP_ID_INVALID;
3183f68c01bSZhan Liu 		hubp->power_gated = false;
3193f68c01bSZhan Liu 		pipe_ctx->stream_res.opp = NULL;
3203f68c01bSZhan Liu 
3213f68c01bSZhan Liu 		hubp->funcs->hubp_init(hubp);
3223f68c01bSZhan Liu 
3233f68c01bSZhan Liu 		res_pool->opps[i]->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true;
3243f68c01bSZhan Liu 		pipe_ctx->stream_res.opp = res_pool->opps[i];
3253f68c01bSZhan Liu 		/*To do: number of MPCC != number of opp*/
326012a04b1SDillon Varone 		hws->funcs.plane_atomic_disconnect(dc, context, pipe_ctx);
3273f68c01bSZhan Liu 	}
3283f68c01bSZhan Liu 
3293f68c01bSZhan Liu 	/* initialize DWB pointer to MCIF_WB */
3303f68c01bSZhan Liu 	for (i = 0; i < res_pool->res_cap->num_dwb; i++)
3313f68c01bSZhan Liu 		res_pool->dwbc[i]->mcif = res_pool->mcif_wb[i];
3323f68c01bSZhan Liu 
3333f68c01bSZhan Liu 	for (i = 0; i < res_pool->timing_generator_count; i++) {
3343f68c01bSZhan Liu 		struct timing_generator *tg = res_pool->timing_generators[i];
3353f68c01bSZhan Liu 
3363f68c01bSZhan Liu 		if (tg->funcs->is_tg_enabled(tg))
3373f68c01bSZhan Liu 			tg->funcs->unlock(tg);
3383f68c01bSZhan Liu 	}
3393f68c01bSZhan Liu 
3403f68c01bSZhan Liu 	for (i = 0; i < res_pool->pipe_count; i++) {
3413f68c01bSZhan Liu 		struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
3423f68c01bSZhan Liu 
343012a04b1SDillon Varone 		dc->hwss.disable_plane(dc, context, pipe_ctx);
3443f68c01bSZhan Liu 
3453f68c01bSZhan Liu 		pipe_ctx->stream_res.tg = NULL;
3463f68c01bSZhan Liu 		pipe_ctx->plane_res.hubp = NULL;
3473f68c01bSZhan Liu 	}
3483f68c01bSZhan Liu 
3493f68c01bSZhan Liu 	for (i = 0; i < res_pool->timing_generator_count; i++) {
3503f68c01bSZhan Liu 		struct timing_generator *tg = res_pool->timing_generators[i];
3513f68c01bSZhan Liu 
3523f68c01bSZhan Liu 		tg->funcs->tg_init(tg);
3533f68c01bSZhan Liu 	}
3543f68c01bSZhan Liu 
3553f68c01bSZhan Liu 	for (i = 0; i < res_pool->audio_count; i++) {
3563f68c01bSZhan Liu 		struct audio *audio = res_pool->audios[i];
3573f68c01bSZhan Liu 
3583f68c01bSZhan Liu 		audio->funcs->hw_init(audio);
3593f68c01bSZhan Liu 	}
3603f68c01bSZhan Liu 
3613f68c01bSZhan Liu 	/* power AFMT HDMI memory TODO: may move to dis/en output save power*/
3623f68c01bSZhan Liu 	REG_WRITE(DIO_MEM_PWR_CTRL, 0);
3633f68c01bSZhan Liu 
3643f68c01bSZhan Liu 	if (!dc->debug.disable_clock_gate) {
3653f68c01bSZhan Liu 		/* enable all DCN clock gating */
3663f68c01bSZhan Liu 		REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0);
3673f68c01bSZhan Liu 
3683f68c01bSZhan Liu 		REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0);
3693f68c01bSZhan Liu 
3703f68c01bSZhan Liu 		REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0);
3713f68c01bSZhan Liu 	}
3723f68c01bSZhan Liu }
3733f68c01bSZhan Liu 
3743f68c01bSZhan Liu /* trigger HW to start disconnect plane from stream on the next vsync */
dcn201_plane_atomic_disconnect(struct dc * dc,struct dc_state * state,struct pipe_ctx * pipe_ctx)375012a04b1SDillon Varone void dcn201_plane_atomic_disconnect(struct dc *dc,
376012a04b1SDillon Varone 		struct dc_state *state,
377012a04b1SDillon Varone 		struct pipe_ctx *pipe_ctx)
3783f68c01bSZhan Liu {
3793f68c01bSZhan Liu 	struct dce_hwseq *hws = dc->hwseq;
3803f68c01bSZhan Liu 	struct hubp *hubp = pipe_ctx->plane_res.hubp;
3813f68c01bSZhan Liu 	int dpp_id = pipe_ctx->plane_res.dpp->inst;
3823f68c01bSZhan Liu 	struct mpc *mpc = dc->res_pool->mpc;
3833f68c01bSZhan Liu 	struct mpc_tree *mpc_tree_params;
3843f68c01bSZhan Liu 	struct mpcc *mpcc_to_remove = NULL;
3853f68c01bSZhan Liu 	struct output_pixel_processor *opp = pipe_ctx->stream_res.opp;
3863f68c01bSZhan Liu 	bool mpcc_removed = false;
3873f68c01bSZhan Liu 
3883f68c01bSZhan Liu 	mpc_tree_params = &(opp->mpc_tree_params);
3893f68c01bSZhan Liu 
3903f68c01bSZhan Liu 	/* check if this plane is being used by an MPCC in the secondary blending chain */
3913f68c01bSZhan Liu 	if (mpc->funcs->get_mpcc_for_dpp_from_secondary)
3923f68c01bSZhan Liu 		mpcc_to_remove = mpc->funcs->get_mpcc_for_dpp_from_secondary(mpc_tree_params, dpp_id);
3933f68c01bSZhan Liu 
3943f68c01bSZhan Liu 	/* remove MPCC from secondary if being used */
3953f68c01bSZhan Liu 	if (mpcc_to_remove != NULL && mpc->funcs->remove_mpcc_from_secondary) {
3963f68c01bSZhan Liu 		mpc->funcs->remove_mpcc_from_secondary(mpc, mpc_tree_params, mpcc_to_remove);
3973f68c01bSZhan Liu 		mpcc_removed = true;
3983f68c01bSZhan Liu 	}
3993f68c01bSZhan Liu 
4003f68c01bSZhan Liu 	/* check if this MPCC is already being used for this plane (dpp) in the primary blending chain */
4013f68c01bSZhan Liu 	mpcc_to_remove = mpc->funcs->get_mpcc_for_dpp(mpc_tree_params, dpp_id);
4023f68c01bSZhan Liu 	if (mpcc_to_remove != NULL) {
4033f68c01bSZhan Liu 		mpc->funcs->remove_mpcc(mpc, mpc_tree_params, mpcc_to_remove);
4043f68c01bSZhan Liu 		mpcc_removed = true;
4053f68c01bSZhan Liu 	}
4063f68c01bSZhan Liu 
4073f68c01bSZhan Liu 	/*Already reset*/
4083f68c01bSZhan Liu 	if (mpcc_removed == false)
4093f68c01bSZhan Liu 		return;
4103f68c01bSZhan Liu 
4113f68c01bSZhan Liu 	opp->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true;
4123f68c01bSZhan Liu 
4133f68c01bSZhan Liu 	dc->optimized_required = true;
4143f68c01bSZhan Liu 
4153f68c01bSZhan Liu 	if (hubp->funcs->hubp_disconnect)
4163f68c01bSZhan Liu 		hubp->funcs->hubp_disconnect(hubp);
4173f68c01bSZhan Liu 
4183f68c01bSZhan Liu 	if (dc->debug.sanity_checks)
4193f68c01bSZhan Liu 		hws->funcs.verify_allow_pstate_change_high(dc);
4203f68c01bSZhan Liu }
4213f68c01bSZhan Liu 
dcn201_update_mpcc(struct dc * dc,struct pipe_ctx * pipe_ctx)4223f68c01bSZhan Liu void dcn201_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx)
4233f68c01bSZhan Liu {
4243f68c01bSZhan Liu 	struct hubp *hubp = pipe_ctx->plane_res.hubp;
4253f68c01bSZhan Liu 	struct mpcc_blnd_cfg blnd_cfg;
4263f68c01bSZhan Liu 	bool per_pixel_alpha = pipe_ctx->plane_state->per_pixel_alpha && pipe_ctx->bottom_pipe;
4273f68c01bSZhan Liu 	int mpcc_id, dpp_id;
4283f68c01bSZhan Liu 	struct mpcc *new_mpcc;
4293f68c01bSZhan Liu 	struct mpcc *remove_mpcc = NULL;
4303f68c01bSZhan Liu 	struct mpc *mpc = dc->res_pool->mpc;
4313f68c01bSZhan Liu 	struct mpc_tree *mpc_tree_params = &(pipe_ctx->stream_res.opp->mpc_tree_params);
4323f68c01bSZhan Liu 
4333f68c01bSZhan Liu 	if (dc->debug.visual_confirm == VISUAL_CONFIRM_HDR) {
4343f68c01bSZhan Liu 		get_hdr_visual_confirm_color(
4353f68c01bSZhan Liu 				pipe_ctx, &blnd_cfg.black_color);
4363f68c01bSZhan Liu 	} else if (dc->debug.visual_confirm == VISUAL_CONFIRM_SURFACE) {
4373f68c01bSZhan Liu 		get_surface_visual_confirm_color(
4383f68c01bSZhan Liu 				pipe_ctx, &blnd_cfg.black_color);
4393f68c01bSZhan Liu 	} else {
4403f68c01bSZhan Liu 		color_space_to_black_color(
4413f68c01bSZhan Liu 				dc, pipe_ctx->stream->output_color_space,
4423f68c01bSZhan Liu 				&blnd_cfg.black_color);
4433f68c01bSZhan Liu 	}
4443f68c01bSZhan Liu 
4453f68c01bSZhan Liu 	if (per_pixel_alpha)
4463f68c01bSZhan Liu 		blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA;
4473f68c01bSZhan Liu 	else
4483f68c01bSZhan Liu 		blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_GLOBAL_ALPHA;
4493f68c01bSZhan Liu 
4503f68c01bSZhan Liu 	blnd_cfg.overlap_only = false;
4513f68c01bSZhan Liu 
4523f68c01bSZhan Liu 	if (pipe_ctx->plane_state->global_alpha_value)
4533f68c01bSZhan Liu 		blnd_cfg.global_alpha = pipe_ctx->plane_state->global_alpha_value;
4543f68c01bSZhan Liu 	else
4553f68c01bSZhan Liu 		blnd_cfg.global_alpha = 0xff;
4563f68c01bSZhan Liu 
4573f68c01bSZhan Liu 	blnd_cfg.global_gain = 0xff;
4583f68c01bSZhan Liu 	blnd_cfg.background_color_bpc = 4;
4593f68c01bSZhan Liu 	blnd_cfg.bottom_gain_mode = 0;
4603f68c01bSZhan Liu 	blnd_cfg.top_gain = 0x1f000;
4613f68c01bSZhan Liu 	blnd_cfg.bottom_inside_gain = 0x1f000;
4623f68c01bSZhan Liu 	blnd_cfg.bottom_outside_gain = 0x1f000;
4633f68c01bSZhan Liu 	/*the input to MPCC is RGB*/
4643f68c01bSZhan Liu 	blnd_cfg.black_color.color_b_cb = 0;
4653f68c01bSZhan Liu 	blnd_cfg.black_color.color_g_y = 0;
4663f68c01bSZhan Liu 	blnd_cfg.black_color.color_r_cr = 0;
4673f68c01bSZhan Liu 
4683f68c01bSZhan Liu 	/* DCN1.0 has output CM before MPC which seems to screw with
4693f68c01bSZhan Liu 	 * pre-multiplied alpha. This is a w/a hopefully unnecessary for DCN2.
4703f68c01bSZhan Liu 	 */
4713f68c01bSZhan Liu 	blnd_cfg.pre_multiplied_alpha = per_pixel_alpha;
4723f68c01bSZhan Liu 
4733f68c01bSZhan Liu 	/*
4743f68c01bSZhan Liu 	 * TODO: remove hack
4753f68c01bSZhan Liu 	 * Note: currently there is a bug in init_hw such that
4763f68c01bSZhan Liu 	 * on resume from hibernate, BIOS sets up MPCC0, and
4773f68c01bSZhan Liu 	 * we do mpcc_remove but the mpcc cannot go to idle
4783f68c01bSZhan Liu 	 * after remove. This cause us to pick mpcc1 here,
4793f68c01bSZhan Liu 	 * which causes a pstate hang for yet unknown reason.
4803f68c01bSZhan Liu 	 */
4813f68c01bSZhan Liu 	dpp_id = hubp->inst;
4823f68c01bSZhan Liu 	mpcc_id = dpp_id;
4833f68c01bSZhan Liu 
4843f68c01bSZhan Liu 	/* If there is no full update, don't need to touch MPC tree*/
4853f68c01bSZhan Liu 	if (!pipe_ctx->plane_state->update_flags.bits.full_update) {
486d205a800SLeo (Hanghong) Ma 		dc->hwss.update_visual_confirm_color(dc, pipe_ctx, mpcc_id);
4873f68c01bSZhan Liu 		mpc->funcs->update_blending(mpc, &blnd_cfg, mpcc_id);
4883f68c01bSZhan Liu 		return;
4893f68c01bSZhan Liu 	}
4903f68c01bSZhan Liu 
4913f68c01bSZhan Liu 	/* check if this plane is being used by an MPCC in the secondary blending chain */
4923f68c01bSZhan Liu 	if (mpc->funcs->get_mpcc_for_dpp_from_secondary)
4933f68c01bSZhan Liu 		remove_mpcc = mpc->funcs->get_mpcc_for_dpp_from_secondary(mpc_tree_params, dpp_id);
4943f68c01bSZhan Liu 
4953f68c01bSZhan Liu 	/* remove MPCC from secondary if being used */
4963f68c01bSZhan Liu 	if (remove_mpcc != NULL && mpc->funcs->remove_mpcc_from_secondary)
4973f68c01bSZhan Liu 		mpc->funcs->remove_mpcc_from_secondary(mpc, mpc_tree_params, remove_mpcc);
4983f68c01bSZhan Liu 
4993f68c01bSZhan Liu 	/* check if this MPCC is already being used for this plane (dpp) in the primary blending chain */
5003f68c01bSZhan Liu 	remove_mpcc = mpc->funcs->get_mpcc_for_dpp(mpc_tree_params, dpp_id);
5013f68c01bSZhan Liu 	/* remove MPCC if being used */
5023f68c01bSZhan Liu 
5033f68c01bSZhan Liu 	if (remove_mpcc != NULL)
5043f68c01bSZhan Liu 		mpc->funcs->remove_mpcc(mpc, mpc_tree_params, remove_mpcc);
5053f68c01bSZhan Liu 	else
5063f68c01bSZhan Liu 		if (dc->debug.sanity_checks)
5073f68c01bSZhan Liu 			mpc->funcs->assert_mpcc_idle_before_connect(
5083f68c01bSZhan Liu 					dc->res_pool->mpc, mpcc_id);
5093f68c01bSZhan Liu 
5103f68c01bSZhan Liu 	/* Call MPC to insert new plane */
511d205a800SLeo (Hanghong) Ma 	dc->hwss.update_visual_confirm_color(dc, pipe_ctx, mpcc_id);
5123f68c01bSZhan Liu 	new_mpcc = mpc->funcs->insert_plane(dc->res_pool->mpc,
5133f68c01bSZhan Liu 			mpc_tree_params,
5143f68c01bSZhan Liu 			&blnd_cfg,
5153f68c01bSZhan Liu 			NULL,
5163f68c01bSZhan Liu 			NULL,
5173f68c01bSZhan Liu 			dpp_id,
5183f68c01bSZhan Liu 			mpcc_id);
5193f68c01bSZhan Liu 
5203f68c01bSZhan Liu 	ASSERT(new_mpcc != NULL);
5213f68c01bSZhan Liu 	hubp->opp_id = pipe_ctx->stream_res.opp->inst;
5223f68c01bSZhan Liu 	hubp->mpcc_id = mpcc_id;
5233f68c01bSZhan Liu }
5243f68c01bSZhan Liu 
dcn201_pipe_control_lock(struct dc * dc,struct pipe_ctx * pipe,bool lock)5253f68c01bSZhan Liu void dcn201_pipe_control_lock(
5263f68c01bSZhan Liu 	struct dc *dc,
5273f68c01bSZhan Liu 	struct pipe_ctx *pipe,
5283f68c01bSZhan Liu 	bool lock)
5293f68c01bSZhan Liu {
5303f68c01bSZhan Liu 	struct dce_hwseq *hws = dc->hwseq;
5313f68c01bSZhan Liu 	/* use TG master update lock to lock everything on the TG
5323f68c01bSZhan Liu 	 * therefore only top pipe need to lock
5333f68c01bSZhan Liu 	 */
5343f68c01bSZhan Liu 	if (pipe->top_pipe)
5353f68c01bSZhan Liu 		return;
5363f68c01bSZhan Liu 
5373f68c01bSZhan Liu 	if (dc->debug.sanity_checks)
5383f68c01bSZhan Liu 		hws->funcs.verify_allow_pstate_change_high(dc);
5393f68c01bSZhan Liu 
5403f68c01bSZhan Liu 	if (pipe->plane_state != NULL && pipe->plane_state->triplebuffer_flips) {
5413f68c01bSZhan Liu 		if (lock)
5423f68c01bSZhan Liu 			pipe->stream_res.tg->funcs->triplebuffer_lock(pipe->stream_res.tg);
5433f68c01bSZhan Liu 		else
5443f68c01bSZhan Liu 			pipe->stream_res.tg->funcs->triplebuffer_unlock(pipe->stream_res.tg);
5453f68c01bSZhan Liu 	} else {
5463f68c01bSZhan Liu 		if (lock)
5473f68c01bSZhan Liu 			pipe->stream_res.tg->funcs->lock(pipe->stream_res.tg);
5483f68c01bSZhan Liu 		else
5493f68c01bSZhan Liu 			pipe->stream_res.tg->funcs->unlock(pipe->stream_res.tg);
5503f68c01bSZhan Liu 	}
5513f68c01bSZhan Liu 
5523f68c01bSZhan Liu 	if (dc->debug.sanity_checks)
5533f68c01bSZhan Liu 		hws->funcs.verify_allow_pstate_change_high(dc);
5543f68c01bSZhan Liu }
5553f68c01bSZhan Liu 
dcn201_set_cursor_attribute(struct pipe_ctx * pipe_ctx)5563f68c01bSZhan Liu void dcn201_set_cursor_attribute(struct pipe_ctx *pipe_ctx)
5573f68c01bSZhan Liu {
5583f68c01bSZhan Liu 	struct dc_cursor_attributes *attributes = &pipe_ctx->stream->cursor_attributes;
5593f68c01bSZhan Liu 
5603f68c01bSZhan Liu 	gpu_addr_to_uma(pipe_ctx->stream->ctx->dc->hwseq, &attributes->address);
5613f68c01bSZhan Liu 
5623f68c01bSZhan Liu 	pipe_ctx->plane_res.hubp->funcs->set_cursor_attributes(
5633f68c01bSZhan Liu 			pipe_ctx->plane_res.hubp, attributes);
5643f68c01bSZhan Liu 	pipe_ctx->plane_res.dpp->funcs->set_cursor_attributes(
5653f68c01bSZhan Liu 		pipe_ctx->plane_res.dpp, attributes);
5663f68c01bSZhan Liu }
5673f68c01bSZhan Liu 
dcn201_set_dmdata_attributes(struct pipe_ctx * pipe_ctx)5683f68c01bSZhan Liu void dcn201_set_dmdata_attributes(struct pipe_ctx *pipe_ctx)
5693f68c01bSZhan Liu {
5703f68c01bSZhan Liu 	struct dc_dmdata_attributes attr = { 0 };
5713f68c01bSZhan Liu 	struct hubp *hubp = pipe_ctx->plane_res.hubp;
5723f68c01bSZhan Liu 
5733f68c01bSZhan Liu 	gpu_addr_to_uma(pipe_ctx->stream->ctx->dc->hwseq,
5743f68c01bSZhan Liu 			&pipe_ctx->stream->dmdata_address);
5753f68c01bSZhan Liu 
5763f68c01bSZhan Liu 	attr.dmdata_mode = DMDATA_HW_MODE;
5773f68c01bSZhan Liu 	attr.dmdata_size =
5783f68c01bSZhan Liu 		dc_is_hdmi_signal(pipe_ctx->stream->signal) ? 32 : 36;
5793f68c01bSZhan Liu 	attr.address.quad_part =
5803f68c01bSZhan Liu 			pipe_ctx->stream->dmdata_address.quad_part;
5813f68c01bSZhan Liu 	attr.dmdata_dl_delta = 0;
5823f68c01bSZhan Liu 	attr.dmdata_qos_mode = 0;
5833f68c01bSZhan Liu 	attr.dmdata_qos_level = 0;
5843f68c01bSZhan Liu 	attr.dmdata_repeat = 1; /* always repeat */
5853f68c01bSZhan Liu 	attr.dmdata_updated = 1;
5863f68c01bSZhan Liu 	attr.dmdata_sw_data = NULL;
5873f68c01bSZhan Liu 
5883f68c01bSZhan Liu 	hubp->funcs->dmdata_set_attributes(hubp, &attr);
5893f68c01bSZhan Liu }
5903f68c01bSZhan Liu 
dcn201_unblank_stream(struct pipe_ctx * pipe_ctx,struct dc_link_settings * link_settings)5913f68c01bSZhan Liu void dcn201_unblank_stream(struct pipe_ctx *pipe_ctx,
5923f68c01bSZhan Liu 		struct dc_link_settings *link_settings)
5933f68c01bSZhan Liu {
5943f68c01bSZhan Liu 	struct encoder_unblank_param params = { { 0 } };
5953f68c01bSZhan Liu 	struct dc_stream_state *stream = pipe_ctx->stream;
5963f68c01bSZhan Liu 	struct dc_link *link = stream->link;
5973f68c01bSZhan Liu 	struct dce_hwseq *hws = link->dc->hwseq;
5983f68c01bSZhan Liu 
5993f68c01bSZhan Liu 	/* only 3 items below are used by unblank */
6003f68c01bSZhan Liu 	params.timing = pipe_ctx->stream->timing;
6013f68c01bSZhan Liu 
6023f68c01bSZhan Liu 	params.link_settings.link_rate = link_settings->link_rate;
6033f68c01bSZhan Liu 
6043f68c01bSZhan Liu 	if (dc_is_dp_signal(pipe_ctx->stream->signal)) {
6053f68c01bSZhan Liu 		/*check whether it is half the rate*/
606e6a901a0SWenjing Liu 		if (pipe_ctx->stream_res.tg->funcs->is_two_pixels_per_container(&stream->timing))
6073f68c01bSZhan Liu 			params.timing.pix_clk_100hz /= 2;
6083f68c01bSZhan Liu 
6093f68c01bSZhan Liu 		pipe_ctx->stream_res.stream_enc->funcs->dp_unblank(link, pipe_ctx->stream_res.stream_enc, &params);
6103f68c01bSZhan Liu 	}
6113f68c01bSZhan Liu 
6123f68c01bSZhan Liu 	if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP) {
6133f68c01bSZhan Liu 		hws->funcs.edp_backlight_control(link, true);
6143f68c01bSZhan Liu 	}
6153f68c01bSZhan Liu }
616