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

dcn30_hwseq.c (33233B)


      1/*
      2 * Copyright 2020 Advanced Micro Devices, Inc.
      3 *
      4 * Permission is hereby granted, free of charge, to any person obtaining a
      5 * copy of this software and associated documentation files (the "Software"),
      6 * to deal in the Software without restriction, including without limitation
      7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8 * and/or sell copies of the Software, and to permit persons to whom the
      9 * Software is furnished to do so, subject to the following conditions:
     10 *
     11 * The above copyright notice and this permission notice shall be included in
     12 * all copies or substantial portions of the Software.
     13 *
     14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
     18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     20 * OTHER DEALINGS IN THE SOFTWARE.
     21 *
     22 * Authors: AMD
     23 *
     24 */
     25
     26
     27#include "dm_services.h"
     28#include "dm_helpers.h"
     29#include "core_types.h"
     30#include "resource.h"
     31#include "dcn30_hwseq.h"
     32#include "dccg.h"
     33#include "dce/dce_hwseq.h"
     34#include "dcn30_mpc.h"
     35#include "dcn30_dpp.h"
     36#include "dcn10/dcn10_cm_common.h"
     37#include "dcn30_cm_common.h"
     38#include "reg_helper.h"
     39#include "abm.h"
     40#include "clk_mgr.h"
     41#include "hubp.h"
     42#include "dchubbub.h"
     43#include "timing_generator.h"
     44#include "opp.h"
     45#include "ipp.h"
     46#include "mpc.h"
     47#include "mcif_wb.h"
     48#include "dc_dmub_srv.h"
     49#include "link_hwss.h"
     50#include "dpcd_defs.h"
     51#include "inc/dc_link_dp.h"
     52#include "inc/link_dpcd.h"
     53
     54
     55
     56
     57#define DC_LOGGER_INIT(logger)
     58
     59#define CTX \
     60	hws->ctx
     61#define REG(reg)\
     62	hws->regs->reg
     63#define DC_LOGGER \
     64		dc->ctx->logger
     65
     66
     67#undef FN
     68#define FN(reg_name, field_name) \
     69	hws->shifts->field_name, hws->masks->field_name
     70
     71bool dcn30_set_blend_lut(
     72	struct pipe_ctx *pipe_ctx, const struct dc_plane_state *plane_state)
     73{
     74	struct dpp *dpp_base = pipe_ctx->plane_res.dpp;
     75	bool result = true;
     76	struct pwl_params *blend_lut = NULL;
     77
     78	if (plane_state->blend_tf) {
     79		if (plane_state->blend_tf->type == TF_TYPE_HWPWL)
     80			blend_lut = &plane_state->blend_tf->pwl;
     81		else if (plane_state->blend_tf->type == TF_TYPE_DISTRIBUTED_POINTS) {
     82			cm3_helper_translate_curve_to_hw_format(
     83					plane_state->blend_tf, &dpp_base->regamma_params, false);
     84			blend_lut = &dpp_base->regamma_params;
     85		}
     86	}
     87	result = dpp_base->funcs->dpp_program_blnd_lut(dpp_base, blend_lut);
     88
     89	return result;
     90}
     91
     92static bool dcn30_set_mpc_shaper_3dlut(
     93	struct pipe_ctx *pipe_ctx, const struct dc_stream_state *stream)
     94{
     95	struct dpp *dpp_base = pipe_ctx->plane_res.dpp;
     96	int mpcc_id = pipe_ctx->plane_res.hubp->inst;
     97	struct mpc *mpc = pipe_ctx->stream_res.opp->ctx->dc->res_pool->mpc;
     98	bool result = false;
     99	int acquired_rmu = 0;
    100	int mpcc_id_projected = 0;
    101
    102	const struct pwl_params *shaper_lut = NULL;
    103	//get the shaper lut params
    104	if (stream->func_shaper) {
    105		if (stream->func_shaper->type == TF_TYPE_HWPWL)
    106			shaper_lut = &stream->func_shaper->pwl;
    107		else if (stream->func_shaper->type == TF_TYPE_DISTRIBUTED_POINTS) {
    108			cm_helper_translate_curve_to_hw_format(
    109					stream->func_shaper,
    110					&dpp_base->shaper_params, true);
    111			shaper_lut = &dpp_base->shaper_params;
    112		}
    113	}
    114
    115	if (stream->lut3d_func &&
    116		stream->lut3d_func->state.bits.initialized == 1 &&
    117		stream->lut3d_func->state.bits.rmu_idx_valid == 1) {
    118		if (stream->lut3d_func->state.bits.rmu_mux_num == 0)
    119			mpcc_id_projected = stream->lut3d_func->state.bits.mpc_rmu0_mux;
    120		else if (stream->lut3d_func->state.bits.rmu_mux_num == 1)
    121			mpcc_id_projected = stream->lut3d_func->state.bits.mpc_rmu1_mux;
    122		else if (stream->lut3d_func->state.bits.rmu_mux_num == 2)
    123			mpcc_id_projected = stream->lut3d_func->state.bits.mpc_rmu2_mux;
    124		if (mpcc_id_projected != mpcc_id)
    125			BREAK_TO_DEBUGGER();
    126		/*find the reason why logical layer assigned a differant mpcc_id into acquire_post_bldn_3dlut*/
    127		acquired_rmu = mpc->funcs->acquire_rmu(mpc, mpcc_id,
    128				stream->lut3d_func->state.bits.rmu_mux_num);
    129		if (acquired_rmu != stream->lut3d_func->state.bits.rmu_mux_num)
    130			BREAK_TO_DEBUGGER();
    131		result = mpc->funcs->program_3dlut(mpc,
    132								&stream->lut3d_func->lut_3d,
    133								stream->lut3d_func->state.bits.rmu_mux_num);
    134		result = mpc->funcs->program_shaper(mpc, shaper_lut,
    135				stream->lut3d_func->state.bits.rmu_mux_num);
    136	} else
    137		/*loop through the available mux and release the requested mpcc_id*/
    138		mpc->funcs->release_rmu(mpc, mpcc_id);
    139
    140
    141	return result;
    142}
    143
    144bool dcn30_set_input_transfer_func(struct dc *dc,
    145				struct pipe_ctx *pipe_ctx,
    146				const struct dc_plane_state *plane_state)
    147{
    148	struct dce_hwseq *hws = dc->hwseq;
    149	struct dpp *dpp_base = pipe_ctx->plane_res.dpp;
    150	enum dc_transfer_func_predefined tf;
    151	bool result = true;
    152	struct pwl_params *params = NULL;
    153
    154	if (dpp_base == NULL || plane_state == NULL)
    155		return false;
    156
    157	tf = TRANSFER_FUNCTION_UNITY;
    158
    159	if (plane_state->in_transfer_func &&
    160		plane_state->in_transfer_func->type == TF_TYPE_PREDEFINED)
    161		tf = plane_state->in_transfer_func->tf;
    162
    163	dpp_base->funcs->dpp_set_pre_degam(dpp_base, tf);
    164
    165	if (plane_state->in_transfer_func) {
    166		if (plane_state->in_transfer_func->type == TF_TYPE_HWPWL)
    167			params = &plane_state->in_transfer_func->pwl;
    168		else if (plane_state->in_transfer_func->type == TF_TYPE_DISTRIBUTED_POINTS &&
    169			cm3_helper_translate_curve_to_hw_format(plane_state->in_transfer_func,
    170					&dpp_base->degamma_params, false))
    171			params = &dpp_base->degamma_params;
    172	}
    173
    174	result = dpp_base->funcs->dpp_program_gamcor_lut(dpp_base, params);
    175
    176	if (pipe_ctx->stream_res.opp && pipe_ctx->stream_res.opp->ctx) {
    177		if (dpp_base->funcs->dpp_program_blnd_lut)
    178			hws->funcs.set_blend_lut(pipe_ctx, plane_state);
    179		if (dpp_base->funcs->dpp_program_shaper_lut &&
    180				dpp_base->funcs->dpp_program_3dlut)
    181			hws->funcs.set_shaper_3dlut(pipe_ctx, plane_state);
    182	}
    183
    184	return result;
    185}
    186
    187bool dcn30_set_output_transfer_func(struct dc *dc,
    188				struct pipe_ctx *pipe_ctx,
    189				const struct dc_stream_state *stream)
    190{
    191	int mpcc_id = pipe_ctx->plane_res.hubp->inst;
    192	struct mpc *mpc = pipe_ctx->stream_res.opp->ctx->dc->res_pool->mpc;
    193	struct pwl_params *params = NULL;
    194	bool ret = false;
    195
    196	/* program OGAM or 3DLUT only for the top pipe*/
    197	if (pipe_ctx->top_pipe == NULL) {
    198		/*program rmu shaper and 3dlut in MPC*/
    199		ret = dcn30_set_mpc_shaper_3dlut(pipe_ctx, stream);
    200		if (ret == false && mpc->funcs->set_output_gamma && stream->out_transfer_func) {
    201			if (stream->out_transfer_func->type == TF_TYPE_HWPWL)
    202				params = &stream->out_transfer_func->pwl;
    203			else if (pipe_ctx->stream->out_transfer_func->type ==
    204					TF_TYPE_DISTRIBUTED_POINTS &&
    205					cm3_helper_translate_curve_to_hw_format(
    206					stream->out_transfer_func,
    207					&mpc->blender_params, false))
    208				params = &mpc->blender_params;
    209			 /* there are no ROM LUTs in OUTGAM */
    210			if (stream->out_transfer_func->type == TF_TYPE_PREDEFINED)
    211				BREAK_TO_DEBUGGER();
    212		}
    213	}
    214
    215	mpc->funcs->set_output_gamma(mpc, mpcc_id, params);
    216	return ret;
    217}
    218
    219static void dcn30_set_writeback(
    220		struct dc *dc,
    221		struct dc_writeback_info *wb_info,
    222		struct dc_state *context)
    223{
    224	struct mcif_wb *mcif_wb;
    225	struct mcif_buf_params *mcif_buf_params;
    226
    227	ASSERT(wb_info->dwb_pipe_inst < MAX_DWB_PIPES);
    228	ASSERT(wb_info->wb_enabled);
    229	ASSERT(wb_info->mpcc_inst >= 0);
    230	ASSERT(wb_info->mpcc_inst < dc->res_pool->mpcc_count);
    231	mcif_wb = dc->res_pool->mcif_wb[wb_info->dwb_pipe_inst];
    232	mcif_buf_params = &wb_info->mcif_buf_params;
    233
    234	/* set DWB MPC mux */
    235	dc->res_pool->mpc->funcs->set_dwb_mux(dc->res_pool->mpc,
    236			wb_info->dwb_pipe_inst, wb_info->mpcc_inst);
    237	/* set MCIF_WB buffer and arbitration configuration */
    238	mcif_wb->funcs->config_mcif_buf(mcif_wb, mcif_buf_params, wb_info->dwb_params.dest_height);
    239	mcif_wb->funcs->config_mcif_arb(mcif_wb, &context->bw_ctx.bw.dcn.bw_writeback.mcif_wb_arb[wb_info->dwb_pipe_inst]);
    240}
    241
    242void dcn30_update_writeback(
    243		struct dc *dc,
    244		struct dc_writeback_info *wb_info,
    245		struct dc_state *context)
    246{
    247	struct dwbc *dwb;
    248	dwb = dc->res_pool->dwbc[wb_info->dwb_pipe_inst];
    249	DC_LOG_DWB("%s dwb_pipe_inst = %d, mpcc_inst = %d",\
    250		__func__, wb_info->dwb_pipe_inst,\
    251		wb_info->mpcc_inst);
    252
    253	dcn30_set_writeback(dc, wb_info, context);
    254
    255	/* update DWB */
    256	dwb->funcs->update(dwb, &wb_info->dwb_params);
    257}
    258
    259bool dcn30_mmhubbub_warmup(
    260	struct dc *dc,
    261	unsigned int num_dwb,
    262	struct dc_writeback_info *wb_info)
    263{
    264	struct dwbc *dwb;
    265	struct mcif_wb *mcif_wb;
    266	struct mcif_warmup_params warmup_params = {0};
    267	unsigned int  i, i_buf;
    268	/*make sure there is no active DWB eanbled */
    269	for (i = 0; i < num_dwb; i++) {
    270		dwb = dc->res_pool->dwbc[wb_info[i].dwb_pipe_inst];
    271		if (dwb->dwb_is_efc_transition || dwb->dwb_is_drc) {
    272			/*can not do warmup while any dwb enabled*/
    273			return false;
    274		}
    275	}
    276
    277	if (wb_info->mcif_warmup_params.p_vmid == 0)
    278		return false;
    279
    280	/*check whether this is new interface: warmup big buffer once*/
    281	if (wb_info->mcif_warmup_params.start_address.quad_part != 0 &&
    282		wb_info->mcif_warmup_params.region_size != 0) {
    283		/*mmhubbub is shared, so it does not matter which MCIF*/
    284		mcif_wb = dc->res_pool->mcif_wb[0];
    285		/*warmup a big chunk of VM buffer at once*/
    286		warmup_params.start_address.quad_part = wb_info->mcif_warmup_params.start_address.quad_part;
    287		warmup_params.address_increment =  wb_info->mcif_warmup_params.region_size;
    288		warmup_params.region_size = wb_info->mcif_warmup_params.region_size;
    289		warmup_params.p_vmid = wb_info->mcif_warmup_params.p_vmid;
    290
    291		if (warmup_params.address_increment == 0)
    292			warmup_params.address_increment = dc->dml.soc.vmm_page_size_bytes;
    293
    294		mcif_wb->funcs->warmup_mcif(mcif_wb, &warmup_params);
    295		return true;
    296	}
    297	/*following is the original: warmup each DWB's mcif buffer*/
    298	for (i = 0; i < num_dwb; i++) {
    299		dwb = dc->res_pool->dwbc[wb_info[i].dwb_pipe_inst];
    300		mcif_wb = dc->res_pool->mcif_wb[wb_info[i].dwb_pipe_inst];
    301		/*warmup is for VM mode only*/
    302		if (wb_info[i].mcif_buf_params.p_vmid == 0)
    303			return false;
    304
    305		/* Warmup MCIF_WB */
    306		for (i_buf = 0; i_buf < MCIF_BUF_COUNT; i_buf++) {
    307			warmup_params.start_address.quad_part = wb_info[i].mcif_buf_params.luma_address[i_buf];
    308			warmup_params.address_increment = dc->dml.soc.vmm_page_size_bytes;
    309			warmup_params.region_size = wb_info[i].mcif_buf_params.luma_pitch * wb_info[i].dwb_params.dest_height;
    310			warmup_params.p_vmid = wb_info[i].mcif_buf_params.p_vmid;
    311			mcif_wb->funcs->warmup_mcif(mcif_wb, &warmup_params);
    312		}
    313	}
    314	return true;
    315}
    316
    317void dcn30_enable_writeback(
    318		struct dc *dc,
    319		struct dc_writeback_info *wb_info,
    320		struct dc_state *context)
    321{
    322	struct dwbc *dwb;
    323	struct mcif_wb *mcif_wb;
    324	struct timing_generator *optc;
    325
    326	dwb = dc->res_pool->dwbc[wb_info->dwb_pipe_inst];
    327	mcif_wb = dc->res_pool->mcif_wb[wb_info->dwb_pipe_inst];
    328
    329	/* set the OPTC source mux */
    330	optc = dc->res_pool->timing_generators[dwb->otg_inst];
    331	DC_LOG_DWB("%s dwb_pipe_inst = %d, mpcc_inst = %d",\
    332		__func__, wb_info->dwb_pipe_inst,\
    333		wb_info->mpcc_inst);
    334	if (IS_DIAG_DC(dc->ctx->dce_environment)) {
    335		/*till diags switch to warmup interface*/
    336		dcn30_mmhubbub_warmup(dc, 1, wb_info);
    337	}
    338	/* Update writeback pipe */
    339	dcn30_set_writeback(dc, wb_info, context);
    340
    341	/* Enable MCIF_WB */
    342	mcif_wb->funcs->enable_mcif(mcif_wb);
    343	/* Enable DWB */
    344	dwb->funcs->enable(dwb, &wb_info->dwb_params);
    345}
    346
    347void dcn30_prepare_bandwidth(struct dc *dc,
    348 	struct dc_state *context)
    349{
    350	if (dc->clk_mgr->dc_mode_softmax_enabled)
    351		if (dc->clk_mgr->clks.dramclk_khz <= dc->clk_mgr->bw_params->dc_mode_softmax_memclk * 1000 &&
    352				context->bw_ctx.bw.dcn.clk.dramclk_khz > dc->clk_mgr->bw_params->dc_mode_softmax_memclk * 1000)
    353			dc->clk_mgr->funcs->set_max_memclk(dc->clk_mgr, dc->clk_mgr->bw_params->clk_table.entries[dc->clk_mgr->bw_params->clk_table.num_entries - 1].memclk_mhz);
    354
    355 	dcn20_prepare_bandwidth(dc, context);
    356}
    357
    358void dcn30_disable_writeback(
    359		struct dc *dc,
    360		unsigned int dwb_pipe_inst)
    361{
    362	struct dwbc *dwb;
    363	struct mcif_wb *mcif_wb;
    364
    365	ASSERT(dwb_pipe_inst < MAX_DWB_PIPES);
    366	dwb = dc->res_pool->dwbc[dwb_pipe_inst];
    367	mcif_wb = dc->res_pool->mcif_wb[dwb_pipe_inst];
    368	DC_LOG_DWB("%s dwb_pipe_inst = %d",\
    369		__func__, dwb_pipe_inst);
    370
    371	/* disable DWB */
    372	dwb->funcs->disable(dwb);
    373	/* disable MCIF */
    374	mcif_wb->funcs->disable_mcif(mcif_wb);
    375	/* disable MPC DWB mux */
    376	dc->res_pool->mpc->funcs->disable_dwb_mux(dc->res_pool->mpc, dwb_pipe_inst);
    377}
    378
    379void dcn30_program_all_writeback_pipes_in_tree(
    380		struct dc *dc,
    381		const struct dc_stream_state *stream,
    382		struct dc_state *context)
    383{
    384	struct dc_writeback_info wb_info;
    385	struct dwbc *dwb;
    386	struct dc_stream_status *stream_status = NULL;
    387	int i_wb, i_pipe, i_stream;
    388	DC_LOG_DWB("%s", __func__);
    389
    390	ASSERT(stream);
    391	for (i_stream = 0; i_stream < context->stream_count; i_stream++) {
    392		if (context->streams[i_stream] == stream) {
    393			stream_status = &context->stream_status[i_stream];
    394			break;
    395		}
    396	}
    397	ASSERT(stream_status);
    398
    399	ASSERT(stream->num_wb_info <= dc->res_pool->res_cap->num_dwb);
    400	/* For each writeback pipe */
    401	for (i_wb = 0; i_wb < stream->num_wb_info; i_wb++) {
    402
    403		/* copy writeback info to local non-const so mpcc_inst can be set */
    404		wb_info = stream->writeback_info[i_wb];
    405		if (wb_info.wb_enabled) {
    406
    407			/* get the MPCC instance for writeback_source_plane */
    408			wb_info.mpcc_inst = -1;
    409			for (i_pipe = 0; i_pipe < dc->res_pool->pipe_count; i_pipe++) {
    410				struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i_pipe];
    411
    412				if (!pipe_ctx->plane_state)
    413					continue;
    414
    415				if (pipe_ctx->plane_state == wb_info.writeback_source_plane) {
    416					wb_info.mpcc_inst = pipe_ctx->plane_res.mpcc_inst;
    417					break;
    418				}
    419			}
    420
    421			if (wb_info.mpcc_inst == -1) {
    422				/* Disable writeback pipe and disconnect from MPCC
    423				 * if source plane has been removed
    424				 */
    425				dc->hwss.disable_writeback(dc, wb_info.dwb_pipe_inst);
    426				continue;
    427			}
    428
    429			ASSERT(wb_info.dwb_pipe_inst < dc->res_pool->res_cap->num_dwb);
    430			dwb = dc->res_pool->dwbc[wb_info.dwb_pipe_inst];
    431			if (dwb->funcs->is_enabled(dwb)) {
    432				/* writeback pipe already enabled, only need to update */
    433				dc->hwss.update_writeback(dc, &wb_info, context);
    434			} else {
    435				/* Enable writeback pipe and connect to MPCC */
    436				dc->hwss.enable_writeback(dc, &wb_info, context);
    437			}
    438		} else {
    439			/* Disable writeback pipe and disconnect from MPCC */
    440			dc->hwss.disable_writeback(dc, wb_info.dwb_pipe_inst);
    441		}
    442	}
    443}
    444
    445void dcn30_init_hw(struct dc *dc)
    446{
    447	struct abm **abms = dc->res_pool->multiple_abms;
    448	struct dce_hwseq *hws = dc->hwseq;
    449	struct dc_bios *dcb = dc->ctx->dc_bios;
    450	struct resource_pool *res_pool = dc->res_pool;
    451	int i;
    452	int edp_num;
    453	uint32_t backlight = MAX_BACKLIGHT_LEVEL;
    454
    455	if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks)
    456		dc->clk_mgr->funcs->init_clocks(dc->clk_mgr);
    457
    458	// Initialize the dccg
    459	if (res_pool->dccg->funcs->dccg_init)
    460		res_pool->dccg->funcs->dccg_init(res_pool->dccg);
    461
    462	if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
    463
    464		REG_WRITE(REFCLK_CNTL, 0);
    465		REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_ENABLE, 1);
    466		REG_WRITE(DIO_MEM_PWR_CTRL, 0);
    467
    468		if (!dc->debug.disable_clock_gate) {
    469			/* enable all DCN clock gating */
    470			REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0);
    471
    472			REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0);
    473
    474			REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0);
    475		}
    476
    477		//Enable ability to power gate / don't force power on permanently
    478		if (hws->funcs.enable_power_gating_plane)
    479			hws->funcs.enable_power_gating_plane(hws, true);
    480
    481		return;
    482	}
    483
    484	if (!dcb->funcs->is_accelerated_mode(dcb)) {
    485		hws->funcs.bios_golden_init(dc);
    486		hws->funcs.disable_vga(dc->hwseq);
    487	}
    488
    489	if (dc->debug.enable_mem_low_power.bits.dmcu) {
    490		// Force ERAM to shutdown if DMCU is not enabled
    491		if (dc->debug.disable_dmcu || dc->config.disable_dmcu) {
    492			REG_UPDATE(DMU_MEM_PWR_CNTL, DMCU_ERAM_MEM_PWR_FORCE, 3);
    493		}
    494	}
    495
    496	// Set default OPTC memory power states
    497	if (dc->debug.enable_mem_low_power.bits.optc) {
    498		// Shutdown when unassigned and light sleep in VBLANK
    499		REG_SET_2(ODM_MEM_PWR_CTRL3, 0, ODM_MEM_UNASSIGNED_PWR_MODE, 3, ODM_MEM_VBLANK_PWR_MODE, 1);
    500	}
    501
    502	if (dc->ctx->dc_bios->fw_info_valid) {
    503		res_pool->ref_clocks.xtalin_clock_inKhz =
    504				dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency;
    505
    506		if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
    507			if (res_pool->dccg && res_pool->hubbub) {
    508
    509				(res_pool->dccg->funcs->get_dccg_ref_freq)(res_pool->dccg,
    510						dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency,
    511						&res_pool->ref_clocks.dccg_ref_clock_inKhz);
    512
    513				(res_pool->hubbub->funcs->get_dchub_ref_freq)(res_pool->hubbub,
    514						res_pool->ref_clocks.dccg_ref_clock_inKhz,
    515						&res_pool->ref_clocks.dchub_ref_clock_inKhz);
    516			} else {
    517				// Not all ASICs have DCCG sw component
    518				res_pool->ref_clocks.dccg_ref_clock_inKhz =
    519						res_pool->ref_clocks.xtalin_clock_inKhz;
    520				res_pool->ref_clocks.dchub_ref_clock_inKhz =
    521						res_pool->ref_clocks.xtalin_clock_inKhz;
    522			}
    523		}
    524	} else
    525		ASSERT_CRITICAL(false);
    526
    527	for (i = 0; i < dc->link_count; i++) {
    528		/* Power up AND update implementation according to the
    529		 * required signal (which may be different from the
    530		 * default signal on connector).
    531		 */
    532		struct dc_link *link = dc->links[i];
    533
    534		link->link_enc->funcs->hw_init(link->link_enc);
    535
    536		/* Check for enabled DIG to identify enabled display */
    537		if (link->link_enc->funcs->is_dig_enabled &&
    538			link->link_enc->funcs->is_dig_enabled(link->link_enc)) {
    539			link->link_status.link_active = true;
    540			if (link->link_enc->funcs->fec_is_active &&
    541					link->link_enc->funcs->fec_is_active(link->link_enc))
    542				link->fec_state = dc_link_fec_enabled;
    543		}
    544	}
    545
    546	/* Power gate DSCs */
    547	for (i = 0; i < res_pool->res_cap->num_dsc; i++)
    548		if (hws->funcs.dsc_pg_control != NULL)
    549			hws->funcs.dsc_pg_control(hws, res_pool->dscs[i]->inst, false);
    550
    551	/* we want to turn off all dp displays before doing detection */
    552	dc_link_blank_all_dp_displays(dc);
    553
    554	if (hws->funcs.enable_power_gating_plane)
    555		hws->funcs.enable_power_gating_plane(dc->hwseq, true);
    556
    557	/* If taking control over from VBIOS, we may want to optimize our first
    558	 * mode set, so we need to skip powering down pipes until we know which
    559	 * pipes we want to use.
    560	 * Otherwise, if taking control is not possible, we need to power
    561	 * everything down.
    562	 */
    563	if (dcb->funcs->is_accelerated_mode(dcb) || !dc->config.seamless_boot_edp_requested) {
    564		hws->funcs.init_pipes(dc, dc->current_state);
    565		if (dc->res_pool->hubbub->funcs->allow_self_refresh_control)
    566			dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub,
    567					!dc->res_pool->hubbub->ctx->dc->debug.disable_stutter);
    568	}
    569
    570	/* In headless boot cases, DIG may be turned
    571	 * on which causes HW/SW discrepancies.
    572	 * To avoid this, power down hardware on boot
    573	 * if DIG is turned on and seamless boot not enabled
    574	 */
    575	if (!dc->config.seamless_boot_edp_requested) {
    576		struct dc_link *edp_links[MAX_NUM_EDP];
    577		struct dc_link *edp_link = NULL;
    578
    579		get_edp_links(dc, edp_links, &edp_num);
    580		if (edp_num)
    581			edp_link = edp_links[0];
    582		if (edp_link && edp_link->link_enc->funcs->is_dig_enabled &&
    583				edp_link->link_enc->funcs->is_dig_enabled(edp_link->link_enc) &&
    584				dc->hwss.edp_backlight_control &&
    585				dc->hwss.power_down &&
    586				dc->hwss.edp_power_control) {
    587			dc->hwss.edp_backlight_control(edp_link, false);
    588			dc->hwss.power_down(dc);
    589			dc->hwss.edp_power_control(edp_link, false);
    590		} else {
    591			for (i = 0; i < dc->link_count; i++) {
    592				struct dc_link *link = dc->links[i];
    593
    594				if (link->link_enc->funcs->is_dig_enabled &&
    595						link->link_enc->funcs->is_dig_enabled(link->link_enc) &&
    596						dc->hwss.power_down) {
    597					dc->hwss.power_down(dc);
    598					break;
    599				}
    600
    601			}
    602		}
    603	}
    604
    605	for (i = 0; i < res_pool->audio_count; i++) {
    606		struct audio *audio = res_pool->audios[i];
    607
    608		audio->funcs->hw_init(audio);
    609	}
    610
    611	for (i = 0; i < dc->link_count; i++) {
    612		struct dc_link *link = dc->links[i];
    613
    614		if (link->panel_cntl)
    615			backlight = link->panel_cntl->funcs->hw_init(link->panel_cntl);
    616	}
    617
    618	for (i = 0; i < dc->res_pool->pipe_count; i++) {
    619		if (abms[i] != NULL)
    620			abms[i]->funcs->abm_init(abms[i], backlight);
    621	}
    622
    623	/* power AFMT HDMI memory TODO: may move to dis/en output save power*/
    624	REG_WRITE(DIO_MEM_PWR_CTRL, 0);
    625
    626	if (!dc->debug.disable_clock_gate) {
    627		/* enable all DCN clock gating */
    628		REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0);
    629
    630		REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0);
    631
    632		REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0);
    633	}
    634
    635	if (!dcb->funcs->is_accelerated_mode(dcb) && dc->res_pool->hubbub->funcs->init_watermarks)
    636		dc->res_pool->hubbub->funcs->init_watermarks(dc->res_pool->hubbub);
    637
    638	if (dc->clk_mgr->funcs->notify_wm_ranges)
    639		dc->clk_mgr->funcs->notify_wm_ranges(dc->clk_mgr);
    640
    641	if (dc->clk_mgr->funcs->set_hard_max_memclk)
    642		dc->clk_mgr->funcs->set_hard_max_memclk(dc->clk_mgr);
    643
    644	if (dc->res_pool->hubbub->funcs->force_pstate_change_control)
    645		dc->res_pool->hubbub->funcs->force_pstate_change_control(
    646				dc->res_pool->hubbub, false, false);
    647	if (dc->res_pool->hubbub->funcs->init_crb)
    648		dc->res_pool->hubbub->funcs->init_crb(dc->res_pool->hubbub);
    649
    650}
    651
    652void dcn30_set_avmute(struct pipe_ctx *pipe_ctx, bool enable)
    653{
    654	if (pipe_ctx == NULL)
    655		return;
    656
    657	if (dc_is_hdmi_signal(pipe_ctx->stream->signal) && pipe_ctx->stream_res.stream_enc != NULL)
    658		pipe_ctx->stream_res.stream_enc->funcs->set_avmute(
    659				pipe_ctx->stream_res.stream_enc,
    660				enable);
    661}
    662
    663void dcn30_update_info_frame(struct pipe_ctx *pipe_ctx)
    664{
    665	bool is_hdmi_tmds;
    666	bool is_dp;
    667
    668	ASSERT(pipe_ctx->stream);
    669
    670	if (pipe_ctx->stream_res.stream_enc == NULL)
    671		return;  /* this is not root pipe */
    672
    673	is_hdmi_tmds = dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal);
    674	is_dp = dc_is_dp_signal(pipe_ctx->stream->signal);
    675
    676	if (!is_hdmi_tmds && !is_dp)
    677		return;
    678
    679	if (is_hdmi_tmds)
    680		pipe_ctx->stream_res.stream_enc->funcs->update_hdmi_info_packets(
    681			pipe_ctx->stream_res.stream_enc,
    682			&pipe_ctx->stream_res.encoder_info_frame);
    683	else
    684		pipe_ctx->stream_res.stream_enc->funcs->update_dp_info_packets(
    685			pipe_ctx->stream_res.stream_enc,
    686			&pipe_ctx->stream_res.encoder_info_frame);
    687}
    688
    689void dcn30_program_dmdata_engine(struct pipe_ctx *pipe_ctx)
    690{
    691	struct dc_stream_state    *stream     = pipe_ctx->stream;
    692	struct hubp               *hubp       = pipe_ctx->plane_res.hubp;
    693	bool                       enable     = false;
    694	struct stream_encoder     *stream_enc = pipe_ctx->stream_res.stream_enc;
    695	enum dynamic_metadata_mode mode       = dc_is_dp_signal(stream->signal)
    696							? dmdata_dp
    697							: dmdata_hdmi;
    698
    699	/* if using dynamic meta, don't set up generic infopackets */
    700	if (pipe_ctx->stream->dmdata_address.quad_part != 0) {
    701		pipe_ctx->stream_res.encoder_info_frame.hdrsmd.valid = false;
    702		enable = true;
    703	}
    704
    705	if (!hubp)
    706		return;
    707
    708	if (!stream_enc || !stream_enc->funcs->set_dynamic_metadata)
    709		return;
    710
    711	stream_enc->funcs->set_dynamic_metadata(stream_enc, enable,
    712							hubp->inst, mode);
    713}
    714
    715bool dcn30_apply_idle_power_optimizations(struct dc *dc, bool enable)
    716{
    717	union dmub_rb_cmd cmd;
    718	uint32_t tmr_delay = 0, tmr_scale = 0;
    719	struct dc_cursor_attributes cursor_attr;
    720	bool cursor_cache_enable = false;
    721	struct dc_stream_state *stream = NULL;
    722	struct dc_plane_state *plane = NULL;
    723
    724	if (!dc->ctx->dmub_srv)
    725		return false;
    726
    727	if (enable) {
    728		if (dc->current_state) {
    729			int i;
    730
    731			/* First, check no-memory-requests case */
    732			for (i = 0; i < dc->current_state->stream_count; i++) {
    733				if (dc->current_state->stream_status[i].plane_count)
    734					/* Fail eligibility on a visible stream */
    735					break;
    736			}
    737
    738			if (i == dc->current_state->stream_count) {
    739				/* Enable no-memory-requests case */
    740				memset(&cmd, 0, sizeof(cmd));
    741				cmd.mall.header.type = DMUB_CMD__MALL;
    742				cmd.mall.header.sub_type = DMUB_CMD__MALL_ACTION_NO_DF_REQ;
    743				cmd.mall.header.payload_bytes = sizeof(cmd.mall) - sizeof(cmd.mall.header);
    744
    745				dc_dmub_srv_cmd_queue(dc->ctx->dmub_srv, &cmd);
    746				dc_dmub_srv_cmd_execute(dc->ctx->dmub_srv);
    747
    748				return true;
    749			}
    750
    751			stream = dc->current_state->streams[0];
    752			plane = (stream ? dc->current_state->stream_status[0].plane_states[0] : NULL);
    753
    754			if (stream && plane) {
    755				cursor_cache_enable = stream->cursor_position.enable &&
    756						plane->address.grph.cursor_cache_addr.quad_part;
    757				cursor_attr = stream->cursor_attributes;
    758			}
    759
    760			/*
    761			 * Second, check MALL eligibility
    762			 *
    763			 * single display only, single surface only, 8 and 16 bit formats only, no VM,
    764			 * do not use MALL for displays that support PSR as they use D0i3.2 in DMCUB FW
    765			 *
    766			 * TODO: When we implement multi-display, PSR displays will be allowed if there is
    767			 * a non-PSR display present, since in that case we can't do D0i3.2
    768			 */
    769			if (dc->current_state->stream_count == 1 &&
    770					stream->link->psr_settings.psr_version == DC_PSR_VERSION_UNSUPPORTED &&
    771					dc->current_state->stream_status[0].plane_count == 1 &&
    772					plane->format <= SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F &&
    773					plane->format >= SURFACE_PIXEL_FORMAT_GRPH_ARGB8888 &&
    774					plane->address.page_table_base.quad_part == 0 &&
    775					dc->hwss.does_plane_fit_in_mall &&
    776					dc->hwss.does_plane_fit_in_mall(dc, plane,
    777							cursor_cache_enable ? &cursor_attr : NULL)) {
    778				unsigned int v_total = stream->adjust.v_total_max ?
    779						stream->adjust.v_total_max : stream->timing.v_total;
    780				unsigned int refresh_hz = div_u64((unsigned long long) stream->timing.pix_clk_100hz *
    781						100LL, (v_total * stream->timing.h_total));
    782
    783				/*
    784				 * one frame time in microsec:
    785				 * Delay_Us = 1000000 / refresh
    786				 * dynamic_delay_us = 1000000 / refresh + 2 * stutter_period
    787				 *
    788				 * one frame time modified by 'additional timer percent' (p):
    789				 * Delay_Us_modified = dynamic_delay_us + dynamic_delay_us * p / 100
    790				 *                   = dynamic_delay_us * (1 + p / 100)
    791				 *                   = (1000000 / refresh + 2 * stutter_period) * (100 + p) / 100
    792				 *                   = (1000000 + 2 * stutter_period * refresh) * (100 + p) / (100 * refresh)
    793				 *
    794				 * formula for timer duration based on parameters, from regspec:
    795				 * dynamic_delay_us = 65.28 * (64 + MallFrameCacheTmrDly) * 2^MallFrameCacheTmrScale
    796				 *
    797				 * dynamic_delay_us / 65.28 = (64 + MallFrameCacheTmrDly) * 2^MallFrameCacheTmrScale
    798				 * (dynamic_delay_us / 65.28) / 2^MallFrameCacheTmrScale = 64 + MallFrameCacheTmrDly
    799				 * MallFrameCacheTmrDly = ((dynamic_delay_us / 65.28) / 2^MallFrameCacheTmrScale) - 64
    800				 *                      = (1000000 + 2 * stutter_period * refresh) * (100 + p) / (100 * refresh) / 65.28 / 2^MallFrameCacheTmrScale - 64
    801				 *                      = (1000000 + 2 * stutter_period * refresh) * (100 + p) / (refresh * 6528 * 2^MallFrameCacheTmrScale) - 64
    802				 *
    803				 * need to round up the result of the division before the subtraction
    804				 */
    805				unsigned int denom = refresh_hz * 6528;
    806				unsigned int stutter_period = dc->current_state->perf_params.stutter_period_us;
    807
    808				tmr_delay = div_u64(((1000000LL + 2 * stutter_period * refresh_hz) *
    809						(100LL + dc->debug.mall_additional_timer_percent) + denom - 1),
    810						denom) - 64LL;
    811
    812				/* In some cases the stutter period is really big (tiny modes) in these
    813				 * cases MALL cant be enabled, So skip these cases to avoid a ASSERT()
    814				 *
    815				 * We can check if stutter_period is more than 1/10th the frame time to
    816				 * consider if we can actually meet the range of hysteresis timer
    817				 */
    818				if (stutter_period > 100000/refresh_hz)
    819					return false;
    820
    821				/* scale should be increased until it fits into 6 bits */
    822				while (tmr_delay & ~0x3F) {
    823					tmr_scale++;
    824
    825					if (tmr_scale > 3) {
    826						/* Delay exceeds range of hysteresis timer */
    827						ASSERT(false);
    828						return false;
    829					}
    830
    831					denom *= 2;
    832					tmr_delay = div_u64(((1000000LL + 2 * stutter_period * refresh_hz) *
    833							(100LL + dc->debug.mall_additional_timer_percent) + denom - 1),
    834							denom) - 64LL;
    835				}
    836
    837				/* Copy HW cursor */
    838				if (cursor_cache_enable) {
    839					memset(&cmd, 0, sizeof(cmd));
    840					cmd.mall.header.type = DMUB_CMD__MALL;
    841					cmd.mall.header.sub_type = DMUB_CMD__MALL_ACTION_COPY_CURSOR;
    842					cmd.mall.header.payload_bytes =
    843							sizeof(cmd.mall) - sizeof(cmd.mall.header);
    844
    845					switch (cursor_attr.color_format) {
    846					case CURSOR_MODE_MONO:
    847						cmd.mall.cursor_bpp = 2;
    848						break;
    849					case CURSOR_MODE_COLOR_1BIT_AND:
    850					case CURSOR_MODE_COLOR_PRE_MULTIPLIED_ALPHA:
    851					case CURSOR_MODE_COLOR_UN_PRE_MULTIPLIED_ALPHA:
    852						cmd.mall.cursor_bpp = 32;
    853						break;
    854
    855					case CURSOR_MODE_COLOR_64BIT_FP_PRE_MULTIPLIED:
    856					case CURSOR_MODE_COLOR_64BIT_FP_UN_PRE_MULTIPLIED:
    857						cmd.mall.cursor_bpp = 64;
    858						break;
    859					}
    860
    861					cmd.mall.cursor_copy_src.quad_part = cursor_attr.address.quad_part;
    862					cmd.mall.cursor_copy_dst.quad_part =
    863							(plane->address.grph.cursor_cache_addr.quad_part + 2047) & ~2047;
    864					cmd.mall.cursor_width = cursor_attr.width;
    865					cmd.mall.cursor_height = cursor_attr.height;
    866					cmd.mall.cursor_pitch = cursor_attr.pitch;
    867
    868					dc_dmub_srv_cmd_queue(dc->ctx->dmub_srv, &cmd);
    869					dc_dmub_srv_cmd_execute(dc->ctx->dmub_srv);
    870					dc_dmub_srv_wait_idle(dc->ctx->dmub_srv);
    871
    872					/* Use copied cursor, and it's okay to not switch back */
    873					cursor_attr.address.quad_part = cmd.mall.cursor_copy_dst.quad_part;
    874					dc_stream_set_cursor_attributes(stream, &cursor_attr);
    875				}
    876
    877				/* Enable MALL */
    878				memset(&cmd, 0, sizeof(cmd));
    879				cmd.mall.header.type = DMUB_CMD__MALL;
    880				cmd.mall.header.sub_type = DMUB_CMD__MALL_ACTION_ALLOW;
    881				cmd.mall.header.payload_bytes = sizeof(cmd.mall) - sizeof(cmd.mall.header);
    882				cmd.mall.tmr_delay = tmr_delay;
    883				cmd.mall.tmr_scale = tmr_scale;
    884				cmd.mall.debug_bits = dc->debug.mall_error_as_fatal;
    885
    886				dc_dmub_srv_cmd_queue(dc->ctx->dmub_srv, &cmd);
    887				dc_dmub_srv_cmd_execute(dc->ctx->dmub_srv);
    888
    889				return true;
    890			}
    891		}
    892
    893		/* No applicable optimizations */
    894		return false;
    895	}
    896
    897	/* Disable MALL */
    898	memset(&cmd, 0, sizeof(cmd));
    899	cmd.mall.header.type = DMUB_CMD__MALL;
    900	cmd.mall.header.sub_type = DMUB_CMD__MALL_ACTION_DISALLOW;
    901	cmd.mall.header.payload_bytes =
    902		sizeof(cmd.mall) - sizeof(cmd.mall.header);
    903
    904	dc_dmub_srv_cmd_queue(dc->ctx->dmub_srv, &cmd);
    905	dc_dmub_srv_cmd_execute(dc->ctx->dmub_srv);
    906	dc_dmub_srv_wait_idle(dc->ctx->dmub_srv);
    907
    908	return true;
    909}
    910
    911bool dcn30_does_plane_fit_in_mall(struct dc *dc, struct dc_plane_state *plane, struct dc_cursor_attributes *cursor_attr)
    912{
    913	// add meta size?
    914	unsigned int surface_size = plane->plane_size.surface_pitch * plane->plane_size.surface_size.height *
    915			(plane->format >= SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616 ? 8 : 4);
    916	unsigned int mall_size = dc->caps.mall_size_total;
    917	unsigned int cursor_size = 0;
    918
    919	if (dc->debug.mall_size_override)
    920		mall_size = 1024 * 1024 * dc->debug.mall_size_override;
    921
    922	if (cursor_attr) {
    923		cursor_size = dc->caps.max_cursor_size * dc->caps.max_cursor_size;
    924
    925		switch (cursor_attr->color_format) {
    926		case CURSOR_MODE_MONO:
    927			cursor_size /= 2;
    928			break;
    929		case CURSOR_MODE_COLOR_1BIT_AND:
    930		case CURSOR_MODE_COLOR_PRE_MULTIPLIED_ALPHA:
    931		case CURSOR_MODE_COLOR_UN_PRE_MULTIPLIED_ALPHA:
    932			cursor_size *= 4;
    933			break;
    934
    935		case CURSOR_MODE_COLOR_64BIT_FP_PRE_MULTIPLIED:
    936		case CURSOR_MODE_COLOR_64BIT_FP_UN_PRE_MULTIPLIED:
    937			cursor_size *= 8;
    938			break;
    939		}
    940	}
    941
    942	return (surface_size + cursor_size) < mall_size;
    943}
    944
    945void dcn30_hardware_release(struct dc *dc)
    946{
    947	/* if pstate unsupported, force it supported */
    948	if (!dc->clk_mgr->clks.p_state_change_support &&
    949			dc->res_pool->hubbub->funcs->force_pstate_change_control)
    950		dc->res_pool->hubbub->funcs->force_pstate_change_control(
    951				dc->res_pool->hubbub, true, true);
    952}
    953
    954void dcn30_set_disp_pattern_generator(const struct dc *dc,
    955		struct pipe_ctx *pipe_ctx,
    956		enum controller_dp_test_pattern test_pattern,
    957		enum controller_dp_color_space color_space,
    958		enum dc_color_depth color_depth,
    959		const struct tg_color *solid_color,
    960		int width, int height, int offset)
    961{
    962	struct stream_resource *stream_res = &pipe_ctx->stream_res;
    963	struct pipe_ctx *mpcc_pipe;
    964
    965	if (test_pattern != CONTROLLER_DP_TEST_PATTERN_VIDEOMODE) {
    966		pipe_ctx->vtp_locked = false;
    967		/* turning on DPG */
    968		stream_res->opp->funcs->opp_set_disp_pattern_generator(stream_res->opp, test_pattern, color_space,
    969				color_depth, solid_color, width, height, offset);
    970
    971		/* Defer hubp blank if tg is locked */
    972		if (stream_res->tg->funcs->is_tg_enabled(stream_res->tg)) {
    973			if (stream_res->tg->funcs->is_locked(stream_res->tg))
    974				pipe_ctx->vtp_locked = true;
    975			else {
    976				/* Blank HUBP to allow p-state during blank on all timings */
    977				pipe_ctx->plane_res.hubp->funcs->set_blank(pipe_ctx->plane_res.hubp, true);
    978
    979				for (mpcc_pipe = pipe_ctx->bottom_pipe; mpcc_pipe; mpcc_pipe = mpcc_pipe->bottom_pipe)
    980					mpcc_pipe->plane_res.hubp->funcs->set_blank(mpcc_pipe->plane_res.hubp, true);
    981			}
    982		}
    983	} else {
    984		/* turning off DPG */
    985		pipe_ctx->plane_res.hubp->funcs->set_blank(pipe_ctx->plane_res.hubp, false);
    986		for (mpcc_pipe = pipe_ctx->bottom_pipe; mpcc_pipe; mpcc_pipe = mpcc_pipe->bottom_pipe)
    987			if (mpcc_pipe->plane_res.hubp)
    988				mpcc_pipe->plane_res.hubp->funcs->set_blank(mpcc_pipe->plane_res.hubp, false);
    989
    990		stream_res->opp->funcs->opp_set_disp_pattern_generator(stream_res->opp, test_pattern, color_space,
    991				color_depth, solid_color, width, height, offset);
    992	}
    993}