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

dcn20_hwseq.c (85283B)


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