File Index
Files and directories
Sign in
FILE

dcn32_hwseq.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c C
   1/*
   2 * Copyright 2016 Advanced Micro Devices, Inc.
   3 *
   4 * Permission is hereby granted, free of charge, to any person obtaining a
   5 * copy of this software and associated documentation files (the "Software"),
   6 * to deal in the Software without restriction, including without limitation
   7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
   8 * and/or sell copies of the Software, and to permit persons to whom the
   9 * Software is furnished to do so, subject to the following conditions:
  10 *
  11 * The above copyright notice and this permission notice shall be included in
  12 * all copies or substantial portions of the Software.
  13 *
  14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
  18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  20 * OTHER DEALINGS IN THE SOFTWARE.
  21 *
  22 * Authors: AMD
  23 *
  24 */
  25
  26
  27#include "dm_services.h"
  28#include "dm_helpers.h"
  29#include "core_types.h"
  30#include "resource.h"
  31#include "dccg.h"
  32#include "dce/dce_hwseq.h"
  33#include "dcn30/dcn30_cm_common.h"
  34#include "reg_helper.h"
  35#include "abm.h"
  36#include "hubp.h"
  37#include "dchubbub.h"
  38#include "timing_generator.h"
  39#include "opp.h"
  40#include "ipp.h"
  41#include "mpc.h"
  42#include "mcif_wb.h"
  43#include "dc_dmub_srv.h"
  44#include "link_hwss.h"
  45#include "dpcd_defs.h"
  46#include "dcn32_hwseq.h"
  47#include "clk_mgr.h"
  48#include "dsc.h"
  49#include "dcn20/dcn20_optc.h"
  50#include "dce/dmub_hw_lock_mgr.h"
  51#include "dcn32/dcn32_resource.h"
  52#include "link_service.h"
  53#include "../dcn20/dcn20_hwseq.h"
  54#include "dc_state_priv.h"
  55
  56#define DC_LOGGER_INIT(logger)
  57
  58#define CTX \
  59	hws->ctx
  60#define REG(reg)\
  61	hws->regs->reg
  62#define DC_LOGGER \
  63	dc->ctx->logger
  64
  65#undef FN
  66#define FN(reg_name, field_name) \
  67	hws->shifts->field_name, hws->masks->field_name
  68
  69void dcn32_dsc_pg_control(
  70		struct dce_hwseq *hws,
  71		unsigned int dsc_inst,
  72		bool power_on)
  73{
  74	uint32_t power_gate = power_on ? 0 : 1;
  75	uint32_t pwr_status = power_on ? 0 : 2;
  76	uint32_t org_ip_request_cntl = 0;
  77	struct dc *dc = hws->ctx->dc;
  78
  79	if (dc->debug.disable_dsc_power_gate)
  80		return;
  81
  82	if (!dc->debug.enable_double_buffered_dsc_pg_support)
  83		return;
  84
  85	REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl);
  86	if (org_ip_request_cntl == 0)
  87		REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1);
  88
  89	DC_LOG_DSC("%s DSC power gate for inst %d", power_gate ? "enable" : "disable", dsc_inst);
  90	switch (dsc_inst) {
  91	case 0: /* DSC0 */
  92		REG_UPDATE(DOMAIN16_PG_CONFIG,
  93				DOMAIN_POWER_GATE, power_gate);
  94
  95		REG_WAIT(DOMAIN16_PG_STATUS,
  96				DOMAIN_PGFSM_PWR_STATUS, pwr_status,
  97				1, 1000);
  98		break;
  99	case 1: /* DSC1 */
 100		REG_UPDATE(DOMAIN17_PG_CONFIG,
 101				DOMAIN_POWER_GATE, power_gate);
 102
 103		REG_WAIT(DOMAIN17_PG_STATUS,
 104				DOMAIN_PGFSM_PWR_STATUS, pwr_status,
 105				1, 1000);
 106		break;
 107	case 2: /* DSC2 */
 108		REG_UPDATE(DOMAIN18_PG_CONFIG,
 109				DOMAIN_POWER_GATE, power_gate);
 110
 111		REG_WAIT(DOMAIN18_PG_STATUS,
 112				DOMAIN_PGFSM_PWR_STATUS, pwr_status,
 113				1, 1000);
 114		break;
 115	case 3: /* DSC3 */
 116		REG_UPDATE(DOMAIN19_PG_CONFIG,
 117				DOMAIN_POWER_GATE, power_gate);
 118
 119		REG_WAIT(DOMAIN19_PG_STATUS,
 120				DOMAIN_PGFSM_PWR_STATUS, pwr_status,
 121				1, 1000);
 122		break;
 123	default:
 124		BREAK_TO_DEBUGGER();
 125		break;
 126	}
 127
 128	if (org_ip_request_cntl == 0)
 129		REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0);
 130}
 131
 132
 133void dcn32_enable_power_gating_plane(
 134	struct dce_hwseq *hws,
 135	bool enable)
 136{
 137	bool force_on = true; /* disable power gating */
 138	uint32_t org_ip_request_cntl = 0;
 139
 140	if (enable)
 141		force_on = false;
 142
 143	REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl);
 144	if (org_ip_request_cntl == 0)
 145		REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1);
 146
 147	/* DCHUBP0/1/2/3 */
 148	REG_UPDATE(DOMAIN0_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);
 149	REG_UPDATE(DOMAIN1_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);
 150	REG_UPDATE(DOMAIN2_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);
 151	REG_UPDATE(DOMAIN3_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);
 152
 153	/* DCS0/1/2/3 */
 154	REG_UPDATE(DOMAIN16_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);
 155	REG_UPDATE(DOMAIN17_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);
 156	REG_UPDATE(DOMAIN18_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);
 157	REG_UPDATE(DOMAIN19_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);
 158
 159	if (org_ip_request_cntl == 0)
 160		REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0);
 161}
 162
 163void dcn32_hubp_pg_control(struct dce_hwseq *hws, unsigned int hubp_inst, bool power_on)
 164{
 165	uint32_t power_gate = power_on ? 0 : 1;
 166	uint32_t pwr_status = power_on ? 0 : 2;
 167
 168	if (hws->ctx->dc->debug.disable_hubp_power_gate)
 169		return;
 170
 171	if (REG(DOMAIN0_PG_CONFIG) == 0)
 172		return;
 173
 174	switch (hubp_inst) {
 175	case 0:
 176		REG_SET(DOMAIN0_PG_CONFIG, 0, DOMAIN_POWER_GATE, power_gate);
 177		REG_WAIT(DOMAIN0_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000);
 178		break;
 179	case 1:
 180		REG_SET(DOMAIN1_PG_CONFIG, 0, DOMAIN_POWER_GATE, power_gate);
 181		REG_WAIT(DOMAIN1_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000);
 182		break;
 183	case 2:
 184		REG_SET(DOMAIN2_PG_CONFIG, 0, DOMAIN_POWER_GATE, power_gate);
 185		REG_WAIT(DOMAIN2_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000);
 186		break;
 187	case 3:
 188		REG_SET(DOMAIN3_PG_CONFIG, 0, DOMAIN_POWER_GATE, power_gate);
 189		REG_WAIT(DOMAIN3_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000);
 190		break;
 191	default:
 192		BREAK_TO_DEBUGGER();
 193		break;
 194	}
 195}
 196
 197static bool dcn32_check_no_memory_request_for_cab(struct dc *dc)
 198{
 199	int i;
 200
 201    /* First, check no-memory-request case */
 202	for (i = 0; i < dc->current_state->stream_count; i++) {
 203		if ((dc->current_state->stream_status[i].plane_count) &&
 204			(dc->current_state->streams[i]->link->psr_settings.psr_version == DC_PSR_VERSION_UNSUPPORTED))
 205			/* Fail eligibility on a visible stream */
 206			break;
 207	}
 208
 209	if (i == dc->current_state->stream_count)
 210		return true;
 211
 212	return false;
 213}
 214
 215
 216/* This function loops through every surface that needs to be cached in CAB for SS,
 217 * and calculates the total number of ways required to store all surfaces (primary,
 218 * meta, cursor).
 219 */
 220static uint32_t dcn32_calculate_cab_allocation(struct dc *dc, struct dc_state *ctx)
 221{
 222	int i;
 223	uint32_t num_ways = 0;
 224	uint32_t mall_ss_size_bytes = 0;
 225
 226	mall_ss_size_bytes = ctx->bw_ctx.bw.dcn.mall_ss_size_bytes;
 227	// TODO add additional logic for PSR active stream exclusion optimization
 228	// mall_ss_psr_active_size_bytes = ctx->bw_ctx.bw.dcn.mall_ss_psr_active_size_bytes;
 229
 230	// Include cursor size for CAB allocation
 231	for (i = 0; i < dc->res_pool->pipe_count; i++) {
 232		struct pipe_ctx *pipe = &ctx->res_ctx.pipe_ctx[i];
 233
 234		if (!pipe->stream || !pipe->plane_state)
 235			continue;
 236
 237		mall_ss_size_bytes += dcn32_helper_calculate_mall_bytes_for_cursor(dc, pipe, false);
 238	}
 239
 240	// Convert number of cache lines required to number of ways
 241	if (dc->debug.force_mall_ss_num_ways > 0) {
 242		num_ways = dc->debug.force_mall_ss_num_ways;
 243	} else if (dc->res_pool->funcs->calculate_mall_ways_from_bytes) {
 244		num_ways = dc->res_pool->funcs->calculate_mall_ways_from_bytes(dc, mall_ss_size_bytes);
 245	} else {
 246		num_ways = 0;
 247	}
 248
 249	return num_ways;
 250}
 251
 252bool dcn32_apply_idle_power_optimizations(struct dc *dc, bool enable)
 253{
 254	union dmub_rb_cmd cmd;
 255	uint8_t i;
 256	uint32_t ways;
 257	int j;
 258	bool mall_ss_unsupported = false;
 259	struct dc_plane_state *plane = NULL;
 260
 261	if (!dc->ctx->dmub_srv)
 262		return false;
 263
 264	for (i = 0; i < dc->current_state->stream_count; i++) {
 265		/* MALL SS messaging is not supported with PSR at this time */
 266		if (dc->current_state->streams[i] != NULL &&
 267				dc->current_state->streams[i]->link->psr_settings.psr_version != DC_PSR_VERSION_UNSUPPORTED &&
 268				(dc->current_state->stream_count > 1 || (!dc->current_state->streams[i]->dpms_off &&
 269						dc->current_state->stream_status[i].plane_count > 0)))
 270			return false;
 271	}
 272
 273	if (enable) {
 274		/* 1. Check no memory request case for CAB.
 275		 * If no memory request case, send CAB_ACTION NO_DF_REQ DMUB message
 276		 */
 277		if (dcn32_check_no_memory_request_for_cab(dc)) {
 278			/* Enable no-memory-requests case */
 279			memset(&cmd, 0, sizeof(cmd));
 280			cmd.cab.header.type = DMUB_CMD__CAB_FOR_SS;
 281			cmd.cab.header.sub_type = DMUB_CMD__CAB_NO_DCN_REQ;
 282			cmd.cab.header.payload_bytes = sizeof(cmd.cab) - sizeof(cmd.cab.header);
 283
 284			dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_NO_WAIT);
 285
 286			return true;
 287		}
 288
 289		/* 2. Check if all surfaces can fit in CAB.
 290		 * If surfaces can fit into CAB, send CAB_ACTION_ALLOW DMUB message
 291		 * and configure HUBP's to fetch from MALL
 292		 */
 293		ways = dcn32_calculate_cab_allocation(dc, dc->current_state);
 294
 295		/* MALL not supported with Stereo3D or TMZ surface. If any plane is using stereo,
 296		 * or TMZ surface, don't try to enter MALL.
 297		 */
 298		for (i = 0; i < dc->current_state->stream_count; i++) {
 299			for (j = 0; j < dc->current_state->stream_status[i].plane_count; j++) {
 300				plane = dc->current_state->stream_status[i].plane_states[j];
 301
 302				if (plane->address.type == PLN_ADDR_TYPE_GRPH_STEREO ||
 303						plane->address.tmz_surface) {
 304					mall_ss_unsupported = true;
 305					break;
 306				}
 307			}
 308			if (mall_ss_unsupported)
 309				break;
 310		}
 311		if (ways <= dc->caps.cache_num_ways && !mall_ss_unsupported) {
 312			memset(&cmd, 0, sizeof(cmd));
 313			cmd.cab.header.type = DMUB_CMD__CAB_FOR_SS;
 314			cmd.cab.header.sub_type = DMUB_CMD__CAB_DCN_SS_FIT_IN_CAB;
 315			cmd.cab.header.payload_bytes = sizeof(cmd.cab) - sizeof(cmd.cab.header);
 316			cmd.cab.cab_alloc_ways = (uint8_t)ways;
 317
 318			dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_NO_WAIT);
 319			DC_LOG_MALL("enable scanout from MALL");
 320
 321			return true;
 322		}
 323
 324		DC_LOG_MALL("surface cannot fit in CAB, disabling scanout from MALL\n");
 325		return false;
 326	}
 327
 328	/* Disable CAB */
 329	memset(&cmd, 0, sizeof(cmd));
 330	cmd.cab.header.type = DMUB_CMD__CAB_FOR_SS;
 331	cmd.cab.header.sub_type = DMUB_CMD__CAB_NO_IDLE_OPTIMIZATION;
 332	cmd.cab.header.payload_bytes =
 333			sizeof(cmd.cab) - sizeof(cmd.cab.header);
 334
 335	dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
 336
 337	return true;
 338}
 339
 340/* Send DMCUB message with SubVP pipe info
 341 * - For each pipe in context, populate payload with required SubVP information
 342 *   if the pipe is using SubVP for MCLK switch
 343 * - This function must be called while the DMUB HW lock is acquired by driver
 344 */
 345void dcn32_commit_subvp_config(struct dc *dc, struct dc_state *context)
 346{
 347	int i;
 348	bool enable_subvp = false;
 349
 350	if (!dc->ctx || !dc->ctx->dmub_srv)
 351		return;
 352
 353	for (i = 0; i < dc->res_pool->pipe_count; i++) {
 354		struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
 355
 356		if (pipe_ctx->stream && dc_state_get_pipe_subvp_type(context, pipe_ctx) == SUBVP_MAIN) {
 357			// There is at least 1 SubVP pipe, so enable SubVP
 358			enable_subvp = true;
 359			break;
 360		}
 361	}
 362	dc_dmub_setup_subvp_dmub_command(dc, context, enable_subvp);
 363}
 364
 365/* Sub-Viewport DMUB lock needs to be acquired by driver whenever SubVP is active and:
 366 * 1. Any full update for any SubVP main pipe
 367 * 2. Any immediate flip for any SubVP pipe
 368 * 3. Any flip for DRR pipe
 369 * 4. If SubVP was previously in use (i.e. in old context)
 370 */
 371void dcn32_subvp_pipe_control_lock(struct dc *dc,
 372		struct dc_state *context,
 373		bool lock,
 374		bool should_lock_all_pipes,
 375		struct pipe_ctx *top_pipe_to_program,
 376		bool subvp_prev_use)
 377{
 378	unsigned int i = 0;
 379	bool subvp_immediate_flip = false;
 380	bool subvp_in_use = false;
 381	struct pipe_ctx *pipe;
 382	enum mall_stream_type pipe_mall_type = SUBVP_NONE;
 383
 384	for (i = 0; i < dc->res_pool->pipe_count; i++) {
 385		pipe = &context->res_ctx.pipe_ctx[i];
 386		pipe_mall_type = dc_state_get_pipe_subvp_type(context, pipe);
 387
 388		if (pipe->stream && pipe->plane_state && pipe_mall_type == SUBVP_MAIN) {
 389			subvp_in_use = true;
 390			break;
 391		}
 392	}
 393
 394	if (top_pipe_to_program && top_pipe_to_program->stream && top_pipe_to_program->plane_state) {
 395		if (dc_state_get_pipe_subvp_type(context, top_pipe_to_program) == SUBVP_MAIN &&
 396				top_pipe_to_program->plane_state->flip_immediate)
 397			subvp_immediate_flip = true;
 398	}
 399
 400	// Don't need to lock for DRR VSYNC flips -- FW will wait for DRR pending update cleared.
 401	if ((subvp_in_use && (should_lock_all_pipes || subvp_immediate_flip)) || (!subvp_in_use && subvp_prev_use)) {
 402		union dmub_inbox0_cmd_lock_hw hw_lock_cmd = { 0 };
 403
 404		if (!lock) {
 405			for (i = 0; i < dc->res_pool->pipe_count; i++) {
 406				pipe = &context->res_ctx.pipe_ctx[i];
 407				if (pipe->stream && pipe->plane_state && pipe_mall_type == SUBVP_MAIN &&
 408						should_lock_all_pipes)
 409					pipe->stream_res.tg->funcs->wait_for_state(pipe->stream_res.tg, CRTC_STATE_VBLANK);
 410			}
 411		}
 412
 413		hw_lock_cmd.bits.command_code = DMUB_INBOX0_CMD__HW_LOCK;
 414		hw_lock_cmd.bits.hw_lock_client = HW_LOCK_CLIENT_DRIVER;
 415		hw_lock_cmd.bits.lock = lock;
 416		hw_lock_cmd.bits.should_release = !lock;
 417		dmub_hw_lock_mgr_inbox0_cmd(dc->ctx->dmub_srv, hw_lock_cmd);
 418	}
 419}
 420
 421void dcn32_subvp_pipe_control_lock_fast(union block_sequence_params *params)
 422{
 423	struct dc *dc = params->subvp_pipe_control_lock_fast_params.dc;
 424	bool lock = params->subvp_pipe_control_lock_fast_params.lock;
 425	bool subvp_immediate_flip = params->subvp_pipe_control_lock_fast_params.subvp_immediate_flip;
 426
 427	// Don't need to lock for DRR VSYNC flips -- FW will wait for DRR pending update cleared.
 428	if (subvp_immediate_flip) {
 429		union dmub_inbox0_cmd_lock_hw hw_lock_cmd = { 0 };
 430
 431		hw_lock_cmd.bits.command_code = DMUB_INBOX0_CMD__HW_LOCK;
 432		hw_lock_cmd.bits.hw_lock_client = HW_LOCK_CLIENT_DRIVER;
 433		hw_lock_cmd.bits.lock = lock;
 434		hw_lock_cmd.bits.should_release = !lock;
 435		dmub_hw_lock_mgr_inbox0_cmd(dc->ctx->dmub_srv, hw_lock_cmd);
 436	}
 437}
 438
 439bool dcn32_set_mpc_shaper_3dlut(
 440	struct pipe_ctx *pipe_ctx, const struct dc_stream_state *stream)
 441{
 442	struct dpp *dpp_base = pipe_ctx->plane_res.dpp;
 443	int mpcc_id = pipe_ctx->plane_res.hubp->inst;
 444	struct dc *dc = pipe_ctx->stream->ctx->dc;
 445	struct mpc *mpc = pipe_ctx->stream_res.opp->ctx->dc->res_pool->mpc;
 446	bool result = false;
 447
 448	const struct pwl_params *shaper_lut = NULL;
 449	//get the shaper lut params
 450	if (stream->func_shaper) {
 451		if (stream->func_shaper->type == TF_TYPE_HWPWL)
 452			shaper_lut = &stream->func_shaper->pwl;
 453		else if (stream->func_shaper->type == TF_TYPE_DISTRIBUTED_POINTS) {
 454			cm_helper_translate_curve_to_hw_format(stream->ctx,
 455					stream->func_shaper,
 456					&dpp_base->shaper_params, true);
 457			shaper_lut = &dpp_base->shaper_params;
 458		}
 459	}
 460
 461	if (stream->lut3d_func &&
 462		stream->lut3d_func->state.bits.initialized == 1) {
 463
 464		result = mpc->funcs->program_3dlut(mpc,	&stream->lut3d_func->lut_3d, mpcc_id);
 465		if (!result)
 466			DC_LOG_ERROR("%s: program_3dlut failed\n", __func__);
 467
 468		result = mpc->funcs->program_shaper(mpc, shaper_lut, mpcc_id);
 469		if (!result)
 470			DC_LOG_ERROR("%s: program_shaper failed\n", __func__);
 471	}
 472
 473	return result;
 474}
 475
 476bool dcn32_set_mcm_luts(
 477	struct pipe_ctx *pipe_ctx, const struct dc_plane_state *plane_state)
 478{
 479	struct dpp *dpp_base = pipe_ctx->plane_res.dpp;
 480	int mpcc_id = pipe_ctx->plane_res.hubp->inst;
 481	struct mpc *mpc = pipe_ctx->stream_res.opp->ctx->dc->res_pool->mpc;
 482	bool result = true;
 483	const struct pwl_params *lut_params = NULL;
 484
 485	// 1D LUT
 486	if (plane_state->blend_tf.type == TF_TYPE_HWPWL)
 487		lut_params = &plane_state->blend_tf.pwl;
 488	else if (plane_state->blend_tf.type == TF_TYPE_DISTRIBUTED_POINTS) {
 489		result = cm3_helper_translate_curve_to_hw_format(plane_state->ctx,
 490								 &plane_state->blend_tf,
 491								 &dpp_base->regamma_params, false);
 492		if (!result)
 493			return result;
 494
 495		lut_params = &dpp_base->regamma_params;
 496	}
 497	mpc->funcs->program_1dlut(mpc, lut_params, mpcc_id);
 498	lut_params = NULL;
 499
 500	// Shaper
 501	if (plane_state->in_shaper_func.type == TF_TYPE_HWPWL)
 502		lut_params = &plane_state->in_shaper_func.pwl;
 503	else if (plane_state->in_shaper_func.type == TF_TYPE_DISTRIBUTED_POINTS) {
 504		// TODO: dpp_base replace
 505		cm3_helper_translate_curve_to_hw_format(plane_state->ctx,
 506							&plane_state->in_shaper_func,
 507							&dpp_base->shaper_params, true);
 508		lut_params = &dpp_base->shaper_params;
 509	}
 510
 511	mpc->funcs->program_shaper(mpc, lut_params, mpcc_id);
 512
 513	// 3D
 514	if (plane_state->lut3d_func.state.bits.initialized == 1)
 515		result = mpc->funcs->program_3dlut(mpc, &plane_state->lut3d_func.lut_3d, mpcc_id);
 516	else
 517		result = mpc->funcs->program_3dlut(mpc, NULL, mpcc_id);
 518
 519	return result;
 520}
 521
 522bool dcn32_set_input_transfer_func(struct dc *dc,
 523				struct pipe_ctx *pipe_ctx,
 524				const struct dc_plane_state *plane_state)
 525{
 526	struct dce_hwseq *hws = dc->hwseq;
 527	struct mpc *mpc = dc->res_pool->mpc;
 528	struct dpp *dpp_base = pipe_ctx->plane_res.dpp;
 529
 530	enum dc_transfer_func_predefined tf;
 531	bool result = true;
 532	const struct pwl_params *params = NULL;
 533
 534	if (mpc == NULL || plane_state == NULL)
 535		return false;
 536
 537	tf = TRANSFER_FUNCTION_UNITY;
 538
 539	if (plane_state->in_transfer_func.type == TF_TYPE_PREDEFINED)
 540		tf = plane_state->in_transfer_func.tf;
 541
 542	dpp_base->funcs->dpp_set_pre_degam(dpp_base, tf);
 543
 544	if (plane_state->in_transfer_func.type == TF_TYPE_HWPWL)
 545		params = &plane_state->in_transfer_func.pwl;
 546	else if (plane_state->in_transfer_func.type == TF_TYPE_DISTRIBUTED_POINTS &&
 547		cm3_helper_translate_curve_to_hw_format(plane_state->ctx,
 548							&plane_state->in_transfer_func,
 549							&dpp_base->degamma_params, false))
 550		params = &dpp_base->degamma_params;
 551
 552	dpp_base->funcs->dpp_program_gamcor_lut(dpp_base, params);
 553
 554	if (pipe_ctx->stream_res.opp &&
 555			pipe_ctx->stream_res.opp->ctx &&
 556			hws->funcs.set_mcm_luts)
 557		result = hws->funcs.set_mcm_luts(pipe_ctx, plane_state);
 558
 559	return result;
 560}
 561
 562bool dcn32_set_output_transfer_func(struct dc *dc,
 563				struct pipe_ctx *pipe_ctx,
 564				const struct dc_stream_state *stream)
 565{
 566	int mpcc_id = pipe_ctx->plane_res.hubp->inst;
 567	struct mpc *mpc = pipe_ctx->stream_res.opp->ctx->dc->res_pool->mpc;
 568	const struct pwl_params *params = NULL;
 569	bool ret = false;
 570
 571	/* program OGAM or 3DLUT only for the top pipe*/
 572	if (resource_is_pipe_type(pipe_ctx, OPP_HEAD)) {
 573		/*program shaper and 3dlut in MPC*/
 574		ret = dcn32_set_mpc_shaper_3dlut(pipe_ctx, stream);
 575		if (ret == false && mpc->funcs->set_output_gamma) {
 576			if (stream->out_transfer_func.type == TF_TYPE_HWPWL)
 577				params = &stream->out_transfer_func.pwl;
 578			else if (pipe_ctx->stream->out_transfer_func.type ==
 579					TF_TYPE_DISTRIBUTED_POINTS &&
 580					cm3_helper_translate_curve_to_hw_format(stream->ctx,
 581					&stream->out_transfer_func,
 582					&mpc->blender_params, false))
 583				params = &mpc->blender_params;
 584			/* there are no ROM LUTs in OUTGAM */
 585			if (stream->out_transfer_func.type == TF_TYPE_PREDEFINED)
 586				BREAK_TO_DEBUGGER();
 587		}
 588	}
 589
 590	if (mpc->funcs->set_output_gamma)
 591		mpc->funcs->set_output_gamma(mpc, mpcc_id, params);
 592
 593	return ret;
 594}
 595
 596/* Program P-State force value according to if pipe is using SubVP / FPO or not:
 597 * 1. Reset P-State force on all pipes first
 598 * 2. For each main pipe, force P-State disallow (P-State allow moderated by DMUB)
 599 */
 600void dcn32_update_force_pstate(struct dc *dc, struct dc_state *context)
 601{
 602	int i;
 603
 604	/* Unforce p-state for each pipe if it is not FPO or SubVP.
 605	 * For FPO and SubVP, if it's already forced disallow, leave
 606	 * it as disallow.
 607	 */
 608	for (i = 0; i < dc->res_pool->pipe_count; i++) {
 609		struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
 610		struct hubp *hubp = pipe->plane_res.hubp;
 611		struct dc_stream_status *stream_status = NULL;
 612
 613		if (pipe->stream)
 614			stream_status = dc_state_get_stream_status(context, pipe->stream);
 615
 616		if (!pipe->stream || !(dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_MAIN ||
 617		    (stream_status && stream_status->fpo_in_use))) {
 618			if (hubp && hubp->funcs->hubp_update_force_pstate_disallow)
 619				hubp->funcs->hubp_update_force_pstate_disallow(hubp, false);
 620			if (hubp && hubp->funcs->hubp_update_force_cursor_pstate_disallow)
 621				hubp->funcs->hubp_update_force_cursor_pstate_disallow(hubp, false);
 622		}
 623	}
 624
 625	/* Loop through each pipe -- for each subvp main pipe force p-state allow equal to false.
 626	 */
 627	for (i = 0; i < dc->res_pool->pipe_count; i++) {
 628		struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
 629		struct pipe_ctx *old_pipe = &dc->current_state->res_ctx.pipe_ctx[i];
 630		struct hubp *hubp = pipe->plane_res.hubp;
 631		struct dc_stream_status *stream_status = NULL;
 632		struct dc_stream_status *old_stream_status = NULL;
 633
 634		/* Today for MED update type we do not call update clocks. However, for FPO
 635		 * the assumption is that update clocks should be called to disable P-State
 636		 * switch before any HW programming since FPO in FW and driver are not
 637		 * synchronized. This causes an issue where on a MED update, an FPO P-State
 638		 * switch could be taking place, then driver forces P-State disallow in the below
 639		 * code and prevents FPO from completing the sequence. In this case we add a check
 640		 * to avoid re-programming (and thus re-setting) the P-State force register by
 641		 * only reprogramming if the pipe was not previously Subvp or FPO. The assumption
 642		 * is that the P-State force register should be programmed correctly the first
 643		 * time SubVP / FPO was enabled, so there's no need to update / reset it if the
 644		 * pipe config has never exited SubVP / FPO.
 645		 */
 646		if (pipe->stream)
 647			stream_status = dc_state_get_stream_status(context, pipe->stream);
 648		if (old_pipe->stream)
 649			old_stream_status = dc_state_get_stream_status(dc->current_state, old_pipe->stream);
 650
 651		if (pipe->stream && (dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_MAIN ||
 652				(stream_status && stream_status->fpo_in_use)) &&
 653				(!old_pipe->stream || (dc_state_get_pipe_subvp_type(dc->current_state, old_pipe) != SUBVP_MAIN &&
 654				(old_stream_status && !old_stream_status->fpo_in_use)))) {
 655			if (hubp && hubp->funcs->hubp_update_force_pstate_disallow)
 656				hubp->funcs->hubp_update_force_pstate_disallow(hubp, true);
 657			if (hubp && hubp->funcs->hubp_update_force_cursor_pstate_disallow)
 658				hubp->funcs->hubp_update_force_cursor_pstate_disallow(hubp, true);
 659		}
 660	}
 661}
 662
 663/* Update MALL_SEL register based on if pipe / plane
 664 * is a phantom pipe, main pipe, and if using MALL
 665 * for SS.
 666 */
 667void dcn32_update_mall_sel(struct dc *dc, struct dc_state *context)
 668{
 669	int i;
 670	unsigned int num_ways = dcn32_calculate_cab_allocation(dc, context);
 671	bool cache_cursor = false;
 672
 673	for (i = 0; i < dc->res_pool->pipe_count; i++) {
 674		struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
 675		struct hubp *hubp = pipe->plane_res.hubp;
 676
 677		if (pipe->stream && pipe->plane_state && hubp && hubp->funcs->hubp_update_mall_sel) {
 678			int cursor_size = hubp->curs_attr.pitch * hubp->curs_attr.height;
 679
 680			switch (hubp->curs_attr.color_format) {
 681			case CURSOR_MODE_MONO:
 682				cursor_size /= 2;
 683				break;
 684			case CURSOR_MODE_COLOR_1BIT_AND:
 685			case CURSOR_MODE_COLOR_PRE_MULTIPLIED_ALPHA:
 686			case CURSOR_MODE_COLOR_UN_PRE_MULTIPLIED_ALPHA:
 687				cursor_size *= 4;
 688				break;
 689
 690			case CURSOR_MODE_COLOR_64BIT_FP_PRE_MULTIPLIED:
 691			case CURSOR_MODE_COLOR_64BIT_FP_UN_PRE_MULTIPLIED:
 692			default:
 693				cursor_size *= 8;
 694				break;
 695			}
 696
 697			if (cursor_size > 16384)
 698				cache_cursor = true;
 699
 700			if (dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_PHANTOM) {
 701				hubp->funcs->hubp_update_mall_sel(hubp, 1, false);
 702			} else {
 703				// MALL not supported with Stereo3D
 704				hubp->funcs->hubp_update_mall_sel(hubp,
 705					num_ways <= dc->caps.cache_num_ways &&
 706					pipe->stream->link->psr_settings.psr_version == DC_PSR_VERSION_UNSUPPORTED &&
 707					pipe->plane_state->address.type !=  PLN_ADDR_TYPE_GRPH_STEREO &&
 708					!pipe->plane_state->address.tmz_surface ? 2 : 0,
 709							cache_cursor);
 710			}
 711		}
 712	}
 713}
 714
 715/* Program the sub-viewport pipe configuration after the main / phantom pipes
 716 * have been programmed in hardware.
 717 * 1. Update force P-State for all the main pipes (disallow P-state)
 718 * 2. Update MALL_SEL register
 719 * 3. Program FORCE_ONE_ROW_FOR_FRAME for main subvp pipes
 720 */
 721void dcn32_program_mall_pipe_config(struct dc *dc, struct dc_state *context)
 722{
 723	int i;
 724	struct dce_hwseq *hws = dc->hwseq;
 725
 726	// Don't force p-state disallow -- can't block dummy p-state
 727
 728	// Update MALL_SEL register for each pipe
 729	if (hws && hws->funcs.update_mall_sel)
 730		hws->funcs.update_mall_sel(dc, context);
 731
 732	// Program FORCE_ONE_ROW_FOR_FRAME and CURSOR_REQ_MODE for main subvp pipes
 733	for (i = 0; i < dc->res_pool->pipe_count; i++) {
 734		struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
 735		struct hubp *hubp = pipe->plane_res.hubp;
 736
 737		if (pipe->stream && hubp && hubp->funcs->hubp_prepare_subvp_buffering) {
 738			/* TODO - remove setting CURSOR_REQ_MODE to 0 for legacy cases
 739			 *      - need to investigate single pipe MPO + SubVP case to
 740			 *        see if CURSOR_REQ_MODE will be back to 1 for SubVP
 741			 *        when it should be 0 for MPO
 742			 */
 743			if (dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_MAIN)
 744				hubp->funcs->hubp_prepare_subvp_buffering(hubp, true);
 745		}
 746	}
 747}
 748
 749static void dcn32_initialize_min_clocks(struct dc *dc)
 750{
 751	struct dc_clocks *clocks = &dc->current_state->bw_ctx.bw.dcn.clk;
 752
 753	clocks->dcfclk_deep_sleep_khz = DCN3_2_DCFCLK_DS_INIT_KHZ;
 754	clocks->dcfclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].dcfclk_mhz * 1000;
 755	clocks->socclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].socclk_mhz * 1000;
 756	clocks->dramclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].memclk_mhz * 1000;
 757	clocks->dppclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].dppclk_mhz * 1000;
 758	clocks->ref_dtbclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].dtbclk_mhz * 1000;
 759	clocks->fclk_p_state_change_support = true;
 760	clocks->p_state_change_support = true;
 761	if (dc->debug.disable_boot_optimizations) {
 762		clocks->dispclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].dispclk_mhz * 1000;
 763	} else {
 764		/* Even though DPG_EN = 1 for the connected display, it still requires the
 765		 * correct timing so we cannot set DISPCLK to min freq or it could cause
 766		 * audio corruption. Read current DISPCLK from DENTIST and request the same
 767		 * freq to ensure that the timing is valid and unchanged.
 768		 */
 769		clocks->dispclk_khz = dc->clk_mgr->funcs->get_dispclk_from_dentist(dc->clk_mgr);
 770	}
 771
 772	dc->clk_mgr->funcs->update_clocks(
 773			dc->clk_mgr,
 774			dc->current_state,
 775			true);
 776}
 777
 778void dcn32_init_hw(struct dc *dc)
 779{
 780	struct abm **abms = dc->res_pool->multiple_abms;
 781	struct dce_hwseq *hws = dc->hwseq;
 782	struct dc_bios *dcb = dc->ctx->dc_bios;
 783	struct resource_pool *res_pool = dc->res_pool;
 784	int i;
 785	int edp_num;
 786	uint32_t backlight = MAX_BACKLIGHT_LEVEL;
 787	uint32_t user_level = MAX_BACKLIGHT_LEVEL;
 788
 789	if (dc->clk_mgr && dc->clk_mgr->funcs && dc->clk_mgr->funcs->init_clocks)
 790		dc->clk_mgr->funcs->init_clocks(dc->clk_mgr);
 791
 792	// Initialize the dccg
 793	if (res_pool->dccg->funcs->dccg_init)
 794		res_pool->dccg->funcs->dccg_init(res_pool->dccg);
 795
 796	if (!dcb->funcs->is_accelerated_mode(dcb)) {
 797		hws->funcs.bios_golden_init(dc);
 798		hws->funcs.disable_vga(dc->hwseq);
 799	}
 800
 801	// Set default OPTC memory power states
 802	if (dc->debug.enable_mem_low_power.bits.optc) {
 803		// Shutdown when unassigned and light sleep in VBLANK
 804		REG_SET_2(ODM_MEM_PWR_CTRL3, 0, ODM_MEM_UNASSIGNED_PWR_MODE, 3, ODM_MEM_VBLANK_PWR_MODE, 1);
 805	}
 806
 807	if (dc->debug.enable_mem_low_power.bits.vga) {
 808		// Power down VGA memory
 809		REG_UPDATE(MMHUBBUB_MEM_PWR_CNTL, VGA_MEM_PWR_FORCE, 1);
 810	}
 811
 812	if (dc->ctx->dc_bios->fw_info_valid) {
 813		res_pool->ref_clocks.xtalin_clock_inKhz =
 814				dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency;
 815
 816		if (res_pool->hubbub) {
 817			(res_pool->dccg->funcs->get_dccg_ref_freq)(res_pool->dccg,
 818					dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency,
 819					&res_pool->ref_clocks.dccg_ref_clock_inKhz);
 820
 821			(res_pool->hubbub->funcs->get_dchub_ref_freq)(res_pool->hubbub,
 822					res_pool->ref_clocks.dccg_ref_clock_inKhz,
 823					&res_pool->ref_clocks.dchub_ref_clock_inKhz);
 824		} else {
 825			// Not all ASICs have DCCG sw component
 826			res_pool->ref_clocks.dccg_ref_clock_inKhz =
 827					res_pool->ref_clocks.xtalin_clock_inKhz;
 828			res_pool->ref_clocks.dchub_ref_clock_inKhz =
 829					res_pool->ref_clocks.xtalin_clock_inKhz;
 830		}
 831	} else
 832		ASSERT_CRITICAL(false);
 833
 834	for (i = 0; i < dc->link_count; i++) {
 835		/* Power up AND update implementation according to the
 836		 * required signal (which may be different from the
 837		 * default signal on connector).
 838		 */
 839		struct dc_link *link = dc->links[i];
 840
 841		link->link_enc->funcs->hw_init(link->link_enc);
 842
 843		/* Check for enabled DIG to identify enabled display */
 844		if (link->link_enc->funcs->is_dig_enabled &&
 845			link->link_enc->funcs->is_dig_enabled(link->link_enc)) {
 846			link->link_status.link_active = true;
 847			link->phy_state.symclk_state = SYMCLK_ON_TX_ON;
 848			if (link->link_enc->funcs->fec_is_active &&
 849					link->link_enc->funcs->fec_is_active(link->link_enc))
 850				link->fec_state = dc_link_fec_enabled;
 851		}
 852	}
 853
 854	/* enable_power_gating_plane before dsc_pg_control because
 855	 * FORCEON = 1 with hw default value on bootup, resume from s3
 856	 */
 857	if (hws->funcs.enable_power_gating_plane)
 858		hws->funcs.enable_power_gating_plane(dc->hwseq, true);
 859
 860	/* we want to turn off all dp displays before doing detection */
 861	dc->link_srv->blank_all_dp_displays(dc);
 862
 863	/* If taking control over from VBIOS, we may want to optimize our first
 864	 * mode set, so we need to skip powering down pipes until we know which
 865	 * pipes we want to use.
 866	 * Otherwise, if taking control is not possible, we need to power
 867	 * everything down.
 868	 */
 869	if (dcb->funcs->is_accelerated_mode(dcb) || !dc->config.seamless_boot_edp_requested) {
 870		/* Disable boot optimizations means power down everything including PHY, DIG,
 871		 * and OTG (i.e. the boot is not optimized because we do a full power down).
 872		 */
 873		if (dc->hwss.enable_accelerated_mode && dc->debug.disable_boot_optimizations)
 874			dc->hwss.enable_accelerated_mode(dc, dc->current_state);
 875		else
 876			hws->funcs.init_pipes(dc, dc->current_state);
 877
 878		if (dc->res_pool->hubbub->funcs->allow_self_refresh_control)
 879			dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub,
 880					!dc->res_pool->hubbub->ctx->dc->debug.disable_stutter);
 881
 882		dcn32_initialize_min_clocks(dc);
 883
 884		/* On HW init, allow idle optimizations after pipes have been turned off.
 885		 *
 886		 * In certain D3 cases (i.e. BOCO / BOMACO) it's possible that hardware state
 887		 * is reset (i.e. not in idle at the time hw init is called), but software state
 888		 * still has idle_optimizations = true, so we must disable idle optimizations first
 889		 * (i.e. set false), then re-enable (set true).
 890		 */
 891		dc_allow_idle_optimizations(dc, false);
 892		dc_allow_idle_optimizations(dc, true);
 893	}
 894
 895	/* In headless boot cases, DIG may be turned
 896	 * on which causes HW/SW discrepancies.
 897	 * To avoid this, power down hardware on boot
 898	 * if DIG is turned on and seamless boot not enabled
 899	 */
 900	if (!dc->config.seamless_boot_edp_requested) {
 901		struct dc_link *edp_links[MAX_NUM_EDP];
 902		struct dc_link *edp_link;
 903
 904		dc_get_edp_links(dc, edp_links, &edp_num);
 905		if (edp_num) {
 906			for (i = 0; i < edp_num; i++) {
 907				edp_link = edp_links[i];
 908				if (edp_link->link_enc->funcs->is_dig_enabled &&
 909						edp_link->link_enc->funcs->is_dig_enabled(edp_link->link_enc) &&
 910						dc->hwss.edp_backlight_control &&
 911						hws->funcs.power_down &&
 912						dc->hwss.edp_power_control) {
 913					dc->hwss.edp_backlight_control(edp_link, false);
 914					hws->funcs.power_down(dc);
 915					dc->hwss.edp_power_control(edp_link, false);
 916				}
 917			}
 918		} else {
 919			for (i = 0; i < dc->link_count; i++) {
 920				struct dc_link *link = dc->links[i];
 921
 922				if (link->link_enc->funcs->is_dig_enabled &&
 923						link->link_enc->funcs->is_dig_enabled(link->link_enc) &&
 924						hws->funcs.power_down) {
 925					hws->funcs.power_down(dc);
 926					break;
 927				}
 928
 929			}
 930		}
 931	}
 932
 933	for (i = 0; i < res_pool->audio_count; i++) {
 934		struct audio *audio = res_pool->audios[i];
 935
 936		audio->funcs->hw_init(audio);
 937	}
 938
 939	for (i = 0; i < dc->link_count; i++) {
 940		struct dc_link *link = dc->links[i];
 941
 942		if (link->panel_cntl) {
 943			backlight = link->panel_cntl->funcs->hw_init(link->panel_cntl);
 944			user_level = link->panel_cntl->stored_backlight_registers.USER_LEVEL;
 945		}
 946	}
 947
 948	for (i = 0; i < dc->res_pool->pipe_count; i++) {
 949		if (abms[i] != NULL && abms[i]->funcs != NULL)
 950			abms[i]->funcs->abm_init(abms[i], backlight, user_level);
 951	}
 952
 953	/* power AFMT HDMI memory TODO: may move to dis/en output save power*/
 954	REG_WRITE(DIO_MEM_PWR_CTRL, 0);
 955
 956	if (!dc->debug.disable_clock_gate) {
 957		/* enable all DCN clock gating */
 958		REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0);
 959
 960		REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0);
 961
 962		REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0);
 963	}
 964
 965	if (!dcb->funcs->is_accelerated_mode(dcb) && dc->res_pool->hubbub->funcs->init_watermarks)
 966		dc->res_pool->hubbub->funcs->init_watermarks(dc->res_pool->hubbub);
 967
 968	if (dc->clk_mgr && dc->clk_mgr->funcs && dc->clk_mgr->funcs->notify_wm_ranges)
 969		dc->clk_mgr->funcs->notify_wm_ranges(dc->clk_mgr);
 970
 971	if (dc->clk_mgr && dc->clk_mgr->funcs && dc->clk_mgr->funcs->set_hard_max_memclk &&
 972	    !dc->clk_mgr->dc_mode_softmax_enabled)
 973		dc->clk_mgr->funcs->set_hard_max_memclk(dc->clk_mgr);
 974
 975	if (dc->res_pool->hubbub->funcs->force_pstate_change_control)
 976		dc->res_pool->hubbub->funcs->force_pstate_change_control(
 977				dc->res_pool->hubbub, false, false);
 978
 979	if (dc->res_pool->hubbub->funcs->init_crb)
 980		dc->res_pool->hubbub->funcs->init_crb(dc->res_pool->hubbub);
 981
 982	if (dc->res_pool->hubbub->funcs->set_request_limit && dc->config.sdpif_request_limit_words_per_umc > 0)
 983		dc->res_pool->hubbub->funcs->set_request_limit(dc->res_pool->hubbub, dc->ctx->dc_bios->vram_info.num_chans, dc->config.sdpif_request_limit_words_per_umc);
 984
 985	// Get DMCUB capabilities
 986	if (dc->ctx->dmub_srv) {
 987		dc_dmub_srv_query_caps_cmd(dc->ctx->dmub_srv);
 988		dc->caps.dmub_caps.psr = dc->ctx->dmub_srv->dmub->feature_caps.psr;
 989		dc->caps.dmub_caps.subvp_psr = dc->ctx->dmub_srv->dmub->feature_caps.subvp_psr_support;
 990		dc->caps.dmub_caps.gecc_enable = dc->ctx->dmub_srv->dmub->feature_caps.gecc_enable;
 991		dc->caps.dmub_caps.mclk_sw = dc->ctx->dmub_srv->dmub->feature_caps.fw_assisted_mclk_switch_ver;
 992		dc->caps.dmub_caps.aux_backlight_support = dc->ctx->dmub_srv->dmub->feature_caps.abm_aux_backlight_support;
 993
 994		/* for DCN401 testing only */
 995		dc->caps.dmub_caps.fams_ver = dc->ctx->dmub_srv->dmub->feature_caps.fw_assisted_mclk_switch_ver;
 996		if (dc->caps.dmub_caps.fams_ver == 2) {
 997			/* FAMS2 is enabled */
 998			dc->debug.fams2_config.bits.enable &= true;
 999		} else if (dc->ctx->dmub_srv->dmub->fw_version <
1000				DMUB_FW_VERSION(7, 0, 35)) {
1001			/* FAMS2 is disabled */
1002			dc->debug.fams2_config.bits.enable = false;
1003			if (dc->debug.using_dml2 && dc->res_pool->funcs->update_bw_bounding_box) {
1004				/* update bounding box if FAMS2 disabled */
1005				dc->res_pool->funcs->update_bw_bounding_box(dc, dc->clk_mgr->bw_params);
1006			}
1007			dc->debug.force_disable_subvp = true;
1008			dc->debug.disable_fpo_optimizations = true;
1009		}
1010	}
1011}
1012
1013void dcn32_update_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable)
1014{
1015	struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc;
1016	struct dc *dc = pipe_ctx->stream->ctx->dc;
1017	struct dc_stream_state *stream = pipe_ctx->stream;
1018	struct pipe_ctx *odm_pipe;
1019	int opp_cnt = 1;
1020	struct dccg *dccg = dc->res_pool->dccg;
1021	/* It has been found that when DSCCLK is lower than 16Mhz, we will get DCN
1022	 * register access hung. When DSCCLk is based on refclk, DSCCLk is always a
1023	 * fixed value higher than 16Mhz so the issue doesn't occur. When DSCCLK is
1024	 * generated by DTO, DSCCLK would be based on 1/3 dispclk. For small timings
1025	 * with DSC such as 480p60Hz, the dispclk could be low enough to trigger
1026	 * this problem. We are implementing a workaround here to keep using dscclk
1027	 * based on fixed value refclk when timing is smaller than 3x16Mhz (i.e
1028	 * 48Mhz) pixel clock to avoid hitting this problem.
1029	 */
1030	bool should_use_dto_dscclk = (dccg->funcs->set_dto_dscclk != NULL) &&
1031			stream->timing.pix_clk_100hz > 480000;
1032
1033	ASSERT(dsc);
1034	for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
1035		opp_cnt++;
1036
1037	if (enable) {
1038		struct dsc_config dsc_cfg;
1039		struct dsc_optc_config dsc_optc_cfg = {0};
1040		enum optc_dsc_mode optc_dsc_mode;
1041		struct dcn_dsc_state dsc_state = {0};
1042
1043		if (!dsc) {
1044			DC_LOG_DSC("DSC is NULL for tg instance %d:", pipe_ctx->stream_res.tg->inst);
1045			return;
1046		}
1047
1048		if (dsc->funcs->dsc_read_state) {
1049			dsc->funcs->dsc_read_state(dsc, &dsc_state);
1050			if (!dsc_state.dsc_fw_en) {
1051				DC_LOG_DSC("DSC has been disabled for tg instance %d:", pipe_ctx->stream_res.tg->inst);
1052				return;
1053			}
1054		}
1055
1056		/* Enable DSC hw block */
1057		dsc_cfg.pic_width = (stream->timing.h_addressable + pipe_ctx->dsc_padding_params.dsc_hactive_padding +
1058				stream->timing.h_border_left + stream->timing.h_border_right) / opp_cnt;
1059		dsc_cfg.pic_height = stream->timing.v_addressable + stream->timing.v_border_top + stream->timing.v_border_bottom;
1060		dsc_cfg.pixel_encoding = stream->timing.pixel_encoding;
1061		dsc_cfg.color_depth = stream->timing.display_color_depth;
1062		dsc_cfg.is_odm = pipe_ctx->next_odm_pipe ? true : false;
1063		dsc_cfg.dc_dsc_cfg = stream->timing.dsc_cfg;
1064		ASSERT(dsc_cfg.dc_dsc_cfg.num_slices_h % opp_cnt == 0);
1065		dsc_cfg.dc_dsc_cfg.num_slices_h /= opp_cnt;
1066		dsc_cfg.dsc_padding = 0;
1067
1068		if (should_use_dto_dscclk)
1069			dccg->funcs->set_dto_dscclk(dccg, dsc->inst, dsc_cfg.dc_dsc_cfg.num_slices_h);
1070		dsc->funcs->dsc_set_config(dsc, &dsc_cfg, &dsc_optc_cfg);
1071		dsc->funcs->dsc_enable(dsc, pipe_ctx->stream_res.opp->inst);
1072		for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
1073			struct display_stream_compressor *odm_dsc = odm_pipe->stream_res.dsc;
1074
1075			ASSERT(odm_dsc);
1076			if (!odm_dsc)
1077				continue;
1078			if (should_use_dto_dscclk)
1079				dccg->funcs->set_dto_dscclk(dccg, odm_dsc->inst, dsc_cfg.dc_dsc_cfg.num_slices_h);
1080			odm_dsc->funcs->dsc_set_config(odm_dsc, &dsc_cfg, &dsc_optc_cfg);
1081			odm_dsc->funcs->dsc_enable(odm_dsc, odm_pipe->stream_res.opp->inst);
1082		}
1083		optc_dsc_mode = dsc_optc_cfg.is_pixel_format_444 ? OPTC_DSC_ENABLED_444 : OPTC_DSC_ENABLED_NATIVE_SUBSAMPLED;
1084		/* Enable DSC in OPTC */
1085		DC_LOG_DSC("Setting optc DSC config for tg instance %d:", pipe_ctx->stream_res.tg->inst);
1086		pipe_ctx->stream_res.tg->funcs->set_dsc_config(pipe_ctx->stream_res.tg,
1087							optc_dsc_mode,
1088							dsc_optc_cfg.bytes_per_pixel,
1089							dsc_optc_cfg.slice_width);
1090	} else {
1091		/* disable DSC in OPTC */
1092		pipe_ctx->stream_res.tg->funcs->set_dsc_config(
1093				pipe_ctx->stream_res.tg,
1094				OPTC_DSC_DISABLED, 0, 0);
1095
1096		/* only disconnect DSC block, DSC is disabled when OPP head pipe is reset */
1097		dsc->funcs->dsc_disconnect(pipe_ctx->stream_res.dsc);
1098		for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
1099			ASSERT(odm_pipe->stream_res.dsc);
1100			odm_pipe->stream_res.dsc->funcs->dsc_disconnect(odm_pipe->stream_res.dsc);
1101		}
1102	}
1103}
1104
1105/*
1106* Given any pipe_ctx, return the total ODM combine factor, and optionally return
1107* the OPPids which are used
1108* */
1109static unsigned int get_odm_config(struct pipe_ctx *pipe_ctx, unsigned int *opp_instances)
1110{
1111	unsigned int opp_count = 1;
1112	struct pipe_ctx *odm_pipe;
1113
1114	/* First get to the top pipe */
1115	for (odm_pipe = pipe_ctx; odm_pipe->prev_odm_pipe; odm_pipe = odm_pipe->prev_odm_pipe)
1116		;
1117
1118	/* First pipe is always used */
1119	if (opp_instances)
1120		opp_instances[0] = odm_pipe->stream_res.opp->inst;
1121
1122	/* Find and count odm pipes, if any */
1123	for (odm_pipe = odm_pipe->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
1124		if (opp_instances)
1125			opp_instances[opp_count] = odm_pipe->stream_res.opp->inst;
1126		opp_count++;
1127	}
1128
1129	return opp_count;
1130}
1131
1132void dcn32_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *pipe_ctx)
1133{
1134	struct pipe_ctx *odm_pipe;
1135	int opp_cnt = 0;
1136	int opp_inst[MAX_PIPES] = {0};
1137	int odm_slice_width = resource_get_odm_slice_dst_width(pipe_ctx, false);
1138	int last_odm_slice_width = resource_get_odm_slice_dst_width(pipe_ctx, true);
1139
1140	opp_cnt = get_odm_config(pipe_ctx, opp_inst);
1141
1142	if (opp_cnt > 1)
1143		pipe_ctx->stream_res.tg->funcs->set_odm_combine(
1144				pipe_ctx->stream_res.tg,
1145				opp_inst, opp_cnt,
1146				odm_slice_width, last_odm_slice_width);
1147	else
1148		pipe_ctx->stream_res.tg->funcs->set_odm_bypass(
1149				pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing);
1150
1151	for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
1152		odm_pipe->stream_res.opp->funcs->opp_pipe_clock_control(
1153				odm_pipe->stream_res.opp,
1154				true);
1155		odm_pipe->stream_res.opp->funcs->opp_program_left_edge_extra_pixel(
1156				odm_pipe->stream_res.opp,
1157				pipe_ctx->stream->timing.pixel_encoding,
1158				resource_is_pipe_type(odm_pipe, OTG_MASTER));
1159	}
1160
1161	if (pipe_ctx->stream_res.dsc) {
1162		struct pipe_ctx *current_pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[pipe_ctx->pipe_idx];
1163
1164		dcn32_update_dsc_on_stream(pipe_ctx, pipe_ctx->stream->timing.flags.DSC);
1165
1166		/* Check if no longer using pipe for ODM, then need to disconnect DSC for that pipe */
1167		if (!pipe_ctx->next_odm_pipe && current_pipe_ctx->next_odm_pipe &&
1168				current_pipe_ctx->next_odm_pipe->stream_res.dsc) {
1169			struct display_stream_compressor *dsc = current_pipe_ctx->next_odm_pipe->stream_res.dsc;
1170
1171			/* disconnect DSC block from stream */
1172			dsc->funcs->dsc_disconnect(dsc);
1173		}
1174	}
1175
1176	if (!resource_is_pipe_type(pipe_ctx, DPP_PIPE))
1177		/*
1178		 * blank pattern is generated by OPP, reprogram blank pattern
1179		 * due to OPP count change
1180		 */
1181		dc->hwseq->funcs.blank_pixel_data(dc, pipe_ctx, true);
1182}
1183
1184unsigned int dcn32_calculate_dccg_k1_k2_values(struct pipe_ctx *pipe_ctx, unsigned int *k1_div, unsigned int *k2_div)
1185{
1186	struct dc_stream_state *stream = pipe_ctx->stream;
1187	unsigned int odm_combine_factor = 0;
1188	bool two_pix_per_container = false;
1189	struct dce_hwseq *hws = stream->ctx->dc->hwseq;
1190
1191	two_pix_per_container = pipe_ctx->stream_res.tg->funcs->is_two_pixels_per_container(&stream->timing);
1192	odm_combine_factor = get_odm_config(pipe_ctx, NULL);
1193
1194	if (stream->ctx->dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) {
1195		*k1_div = PIXEL_RATE_DIV_BY_1;
1196		*k2_div = PIXEL_RATE_DIV_BY_1;
1197	} else if (dc_is_hdmi_tmds_signal(stream->signal) || dc_is_dvi_signal(stream->signal)) {
1198		*k1_div = PIXEL_RATE_DIV_BY_1;
1199		if (stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR420)
1200			*k2_div = PIXEL_RATE_DIV_BY_2;
1201		else
1202			*k2_div = PIXEL_RATE_DIV_BY_4;
1203	} else if (dc_is_dp_signal(stream->signal) || dc_is_virtual_signal(stream->signal)) {
1204		if (two_pix_per_container) {
1205			*k1_div = PIXEL_RATE_DIV_BY_1;
1206			*k2_div = PIXEL_RATE_DIV_BY_2;
1207		} else {
1208			*k1_div = PIXEL_RATE_DIV_BY_1;
1209			*k2_div = PIXEL_RATE_DIV_BY_4;
1210			if ((odm_combine_factor == 2) || (hws->funcs.is_dp_dig_pixel_rate_div_policy &&
1211				hws->funcs.is_dp_dig_pixel_rate_div_policy(pipe_ctx)))
1212				*k2_div = PIXEL_RATE_DIV_BY_2;
1213		}
1214	}
1215
1216	if ((*k1_div == PIXEL_RATE_DIV_NA) && (*k2_div == PIXEL_RATE_DIV_NA))
1217		ASSERT(false);
1218
1219	return odm_combine_factor;
1220}
1221
1222void dcn32_calculate_pix_rate_divider(
1223		struct dc *dc,
1224		struct dc_state *context,
1225		const struct dc_stream_state *stream)
1226{
1227	struct dce_hwseq *hws = dc->hwseq;
1228	struct pipe_ctx *pipe_ctx = NULL;
1229	unsigned int k1_div = PIXEL_RATE_DIV_NA;
1230	unsigned int k2_div = PIXEL_RATE_DIV_NA;
1231
1232	pipe_ctx = resource_get_otg_master_for_stream(&context->res_ctx, stream);
1233
1234	if (pipe_ctx) {
1235
1236		if (hws->funcs.calculate_dccg_k1_k2_values)
1237			hws->funcs.calculate_dccg_k1_k2_values(pipe_ctx, &k1_div, &k2_div);
1238
1239		pipe_ctx->pixel_rate_divider.div_factor1 = k1_div;
1240		pipe_ctx->pixel_rate_divider.div_factor2 = k2_div;
1241	}
1242}
1243
1244void dcn32_resync_fifo_dccg_dio(struct dce_hwseq *hws, struct dc *dc, struct dc_state *context, unsigned int current_pipe_idx)
1245{
1246	unsigned int i;
1247	struct pipe_ctx *pipe = NULL;
1248	bool otg_disabled[MAX_PIPES] = {false};
1249	struct dc_state *dc_state = NULL;
1250
1251	for (i = 0; i < dc->res_pool->pipe_count; i++) {
1252		if (i <= current_pipe_idx) {
1253			pipe = &context->res_ctx.pipe_ctx[i];
1254			dc_state = context;
1255		} else {
1256			pipe = &dc->current_state->res_ctx.pipe_ctx[i];
1257			dc_state = dc->current_state;
1258		}
1259
1260		if (!resource_is_pipe_type(pipe, OTG_MASTER))
1261			continue;
1262
1263		if ((pipe->stream->dpms_off || dc_is_virtual_signal(pipe->stream->signal))
1264			&& dc_state_get_pipe_subvp_type(dc_state, pipe) != SUBVP_PHANTOM) {
1265			pipe->stream_res.tg->funcs->disable_crtc(pipe->stream_res.tg);
1266			reset_sync_context_for_pipe(dc, context, i);
1267			otg_disabled[i] = true;
1268		}
1269	}
1270
1271	hws->ctx->dc->res_pool->dccg->funcs->trigger_dio_fifo_resync(hws->ctx->dc->res_pool->dccg);
1272
1273	for (i = 0; i < dc->res_pool->pipe_count; i++) {
1274		if (i <= current_pipe_idx)
1275			pipe = &context->res_ctx.pipe_ctx[i];
1276		else
1277			pipe = &dc->current_state->res_ctx.pipe_ctx[i];
1278
1279		if (otg_disabled[i]) {
1280			int opp_inst[MAX_PIPES] = { pipe->stream_res.opp->inst };
1281			int opp_cnt = 1;
1282			int last_odm_slice_width = resource_get_odm_slice_dst_width(pipe, true);
1283			int odm_slice_width = resource_get_odm_slice_dst_width(pipe, false);
1284			struct pipe_ctx *odm_pipe;
1285
1286			for (odm_pipe = pipe->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
1287				opp_inst[opp_cnt] = odm_pipe->stream_res.opp->inst;
1288				opp_cnt++;
1289			}
1290			if (opp_cnt > 1)
1291				pipe->stream_res.tg->funcs->set_odm_combine(
1292						pipe->stream_res.tg,
1293						opp_inst, opp_cnt,
1294						odm_slice_width,
1295						last_odm_slice_width);
1296			pipe->stream_res.tg->funcs->enable_crtc(pipe->stream_res.tg);
1297		}
1298	}
1299
1300	dc_trigger_sync(dc, dc->current_state);
1301}
1302
1303void dcn32_unblank_stream(struct pipe_ctx *pipe_ctx,
1304		struct dc_link_settings *link_settings)
1305{
1306	struct encoder_unblank_param params = {0};
1307	struct dc_stream_state *stream = pipe_ctx->stream;
1308	struct dc_link *link = stream->link;
1309	struct dce_hwseq *hws = link->dc->hwseq;
1310	struct pipe_ctx *odm_pipe;
1311
1312	params.opp_cnt = 1;
1313	params.pix_per_cycle = pipe_ctx->stream_res.pix_clk_params.dio_se_pix_per_cycle;
1314
1315	for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
1316		params.opp_cnt++;
1317
1318	/* only 3 items below are used by unblank */
1319	params.timing = pipe_ctx->stream->timing;
1320
1321	params.link_settings.link_rate = link_settings->link_rate;
1322
1323	if (link->dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) {
1324		/* TODO - DP2.0 HW: Set ODM mode in dp hpo encoder here */
1325		pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_unblank(
1326				pipe_ctx->stream_res.hpo_dp_stream_enc,
1327				pipe_ctx->stream_res.tg->inst);
1328	} else if (dc_is_dp_signal(pipe_ctx->stream->signal)) {
1329		if (pipe_ctx->stream_res.tg->funcs->is_two_pixels_per_container(&stream->timing) ||
1330			params.opp_cnt > 1) {
1331			params.timing.pix_clk_100hz /= 2;
1332			params.pix_per_cycle = 2;
1333		}
1334		if (pipe_ctx->stream_res.stream_enc->funcs->dp_set_odm_combine)
1335			pipe_ctx->stream_res.stream_enc->funcs->dp_set_odm_combine(
1336				pipe_ctx->stream_res.stream_enc, params.pix_per_cycle > 1);
1337		pipe_ctx->stream_res.stream_enc->funcs->dp_unblank(link, pipe_ctx->stream_res.stream_enc, &params);
1338	}
1339
1340	if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP)
1341		hws->funcs.edp_backlight_control(link, true);
1342}
1343
1344bool dcn32_is_dp_dig_pixel_rate_div_policy(struct pipe_ctx *pipe_ctx)
1345{
1346	struct dc *dc = pipe_ctx->stream->ctx->dc;
1347
1348	if (!is_h_timing_divisible_by_2(pipe_ctx->stream))
1349		return false;
1350
1351	if (dc_is_dp_signal(pipe_ctx->stream->signal) && !dc->link_srv->dp_is_128b_132b_signal(pipe_ctx) &&
1352		dc->debug.enable_dp_dig_pixel_rate_div_policy)
1353		return true;
1354	return false;
1355}
1356
1357static void apply_symclk_on_tx_off_wa(struct dc_link *link)
1358{
1359	/* There are use cases where SYMCLK is referenced by OTG. For instance
1360	 * for TMDS signal, OTG relies SYMCLK even if TX video output is off.
1361	 * However current link interface will power off PHY when disabling link
1362	 * output. This will turn off SYMCLK generated by PHY. The workaround is
1363	 * to identify such case where SYMCLK is still in use by OTG when we
1364	 * power off PHY. When this is detected, we will temporarily power PHY
1365	 * back on and move PHY's SYMCLK state to SYMCLK_ON_TX_OFF by calling
1366	 * program_pix_clk interface. When OTG is disabled, we will then power
1367	 * off PHY by calling disable link output again.
1368	 *
1369	 * In future dcn generations, we plan to rework transmitter control
1370	 * interface so that we could have an option to set SYMCLK ON TX OFF
1371	 * state in one step without this workaround
1372	 */
1373
1374	struct dc *dc = link->ctx->dc;
1375	struct pipe_ctx *pipe_ctx = NULL;
1376	uint8_t i;
1377
1378	if (link->phy_state.symclk_ref_cnts.otg > 0) {
1379		for (i = 0; i < MAX_PIPES; i++) {
1380			pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i];
1381			if (resource_is_pipe_type(pipe_ctx, OPP_HEAD) && pipe_ctx->stream->link == link) {
1382				pipe_ctx->clock_source->funcs->program_pix_clk(
1383						pipe_ctx->clock_source,
1384						&pipe_ctx->stream_res.pix_clk_params,
1385						dc->link_srv->dp_get_encoding_format(
1386								&pipe_ctx->link_config.dp_link_settings),
1387						&pipe_ctx->pll_settings);
1388				link->phy_state.symclk_state = SYMCLK_ON_TX_OFF;
1389				break;
1390			}
1391		}
1392	}
1393}
1394
1395void dcn32_disable_link_output(struct dc_link *link,
1396		const struct link_resource *link_res,
1397		enum signal_type signal)
1398{
1399	struct dc *dc = link->ctx->dc;
1400	const struct link_hwss *link_hwss = get_link_hwss(link, link_res);
1401	struct dmcu *dmcu = dc->res_pool->dmcu;
1402
1403	if (signal == SIGNAL_TYPE_EDP &&
1404			link->dc->hwss.edp_backlight_control &&
1405			!link->skip_implict_edp_power_control)
1406		link->dc->hwss.edp_backlight_control(link, false);
1407	else if (dmcu != NULL && dmcu->funcs->lock_phy)
1408		dmcu->funcs->lock_phy(dmcu);
1409
1410	link_hwss->disable_link_output(link, link_res, signal);
1411	link->phy_state.symclk_state = SYMCLK_OFF_TX_OFF;
1412	/*
1413	 * Add the logic to extract BOTH power up and power down sequences
1414	 * from enable/disable link output and only call edp panel control
1415	 * in enable_link_dp and disable_link_dp once.
1416	 */
1417	if (dmcu != NULL && dmcu->funcs->unlock_phy)
1418		dmcu->funcs->unlock_phy(dmcu);
1419
1420	dc->link_srv->dp_trace_source_sequence(link, DPCD_SOURCE_SEQ_AFTER_DISABLE_LINK_PHY);
1421
1422	apply_symclk_on_tx_off_wa(link);
1423}
1424
1425/* For SubVP the main pipe can have a viewport position change
1426 * without a full update. In this case we must also update the
1427 * viewport positions for the phantom pipe accordingly.
1428 */
1429void dcn32_update_phantom_vp_position(struct dc *dc,
1430		struct dc_state *context,
1431		struct pipe_ctx *phantom_pipe)
1432{
1433	uint32_t i;
1434	struct dc_plane_state *phantom_plane = phantom_pipe->plane_state;
1435
1436	for (i = 0; i < dc->res_pool->pipe_count; i++) {
1437		struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
1438
1439		if (pipe->stream && dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_MAIN &&
1440				dc_state_get_paired_subvp_stream(context, pipe->stream) == phantom_pipe->stream) {
1441			if (pipe->plane_state && pipe->plane_state->update_flags.bits.position_change) {
1442
1443				phantom_plane->src_rect.x = pipe->plane_state->src_rect.x;
1444				phantom_plane->src_rect.y = pipe->plane_state->src_rect.y;
1445				phantom_plane->clip_rect.x = pipe->plane_state->clip_rect.x;
1446				phantom_plane->dst_rect.x = pipe->plane_state->dst_rect.x;
1447				phantom_plane->dst_rect.y = pipe->plane_state->dst_rect.y;
1448
1449				phantom_pipe->plane_state->update_flags.bits.position_change = 1;
1450				resource_build_scaling_params(phantom_pipe);
1451				return;
1452			}
1453		}
1454	}
1455}
1456
1457/* Treat the phantom pipe as if it needs to be fully enabled.
1458 * If the pipe was previously in use but not phantom, it would
1459 * have been disabled earlier in the sequence so we need to run
1460 * the full enable sequence.
1461 */
1462void dcn32_apply_update_flags_for_phantom(struct pipe_ctx *phantom_pipe)
1463{
1464	phantom_pipe->update_flags.raw = 0;
1465	if (resource_is_pipe_type(phantom_pipe, DPP_PIPE)) {
1466		phantom_pipe->update_flags.bits.enable = 1;
1467		phantom_pipe->update_flags.bits.mpcc = 1;
1468		phantom_pipe->update_flags.bits.dppclk = 1;
1469		phantom_pipe->update_flags.bits.hubp_interdependent = 1;
1470		phantom_pipe->update_flags.bits.hubp_rq_dlg_ttu = 1;
1471		phantom_pipe->update_flags.bits.gamut_remap = 1;
1472		phantom_pipe->update_flags.bits.scaler = 1;
1473		phantom_pipe->update_flags.bits.viewport = 1;
1474		phantom_pipe->update_flags.bits.det_size = 1;
1475		if (resource_is_pipe_type(phantom_pipe, OTG_MASTER)) {
1476			phantom_pipe->update_flags.bits.odm = 1;
1477			phantom_pipe->update_flags.bits.global_sync = 1;
1478		}
1479	}
1480}
1481
1482bool dcn32_dsc_pg_status(
1483		struct dce_hwseq *hws,
1484		unsigned int dsc_inst)
1485{
1486	uint32_t pwr_status = 0;
1487
1488	switch (dsc_inst) {
1489	case 0: /* DSC0 */
1490		REG_GET(DOMAIN16_PG_STATUS,
1491				DOMAIN_PGFSM_PWR_STATUS, &pwr_status);
1492		break;
1493	case 1: /* DSC1 */
1494
1495		REG_GET(DOMAIN17_PG_STATUS,
1496				DOMAIN_PGFSM_PWR_STATUS, &pwr_status);
1497		break;
1498	case 2: /* DSC2 */
1499		REG_GET(DOMAIN18_PG_STATUS,
1500				DOMAIN_PGFSM_PWR_STATUS, &pwr_status);
1501		break;
1502	case 3: /* DSC3 */
1503		REG_GET(DOMAIN19_PG_STATUS,
1504				DOMAIN_PGFSM_PWR_STATUS, &pwr_status);
1505		break;
1506	default:
1507		BREAK_TO_DEBUGGER();
1508		break;
1509	}
1510
1511	return pwr_status == 0;
1512}
1513
1514void dcn32_update_dsc_pg(struct dc *dc,
1515		struct dc_state *context,
1516		bool safe_to_disable)
1517{
1518	struct dce_hwseq *hws = dc->hwseq;
1519	int i;
1520
1521	for (i = 0; i < dc->res_pool->res_cap->num_dsc; i++) {
1522		struct display_stream_compressor *dsc = dc->res_pool->dscs[i];
1523		bool is_dsc_ungated = hws->funcs.dsc_pg_status(hws, dsc->inst);
1524
1525		if (context->res_ctx.is_dsc_acquired[i]) {
1526			if (!is_dsc_ungated) {
1527				hws->funcs.dsc_pg_control(hws, dsc->inst, true);
1528			}
1529		} else if (safe_to_disable) {
1530			if (is_dsc_ungated) {
1531				hws->funcs.dsc_pg_control(hws, dsc->inst, false);
1532			}
1533		}
1534	}
1535}
1536
1537void dcn32_disable_phantom_streams(struct dc *dc, struct dc_state *context)
1538{
1539	struct dce_hwseq *hws = dc->hwseq;
1540	int i;
1541
1542	for (i = dc->res_pool->pipe_count - 1; i >= 0 ; i--) {
1543		struct pipe_ctx *pipe_ctx_old =
1544			&dc->current_state->res_ctx.pipe_ctx[i];
1545		struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
1546
1547		if (!pipe_ctx_old->stream)
1548			continue;
1549
1550		if (dc_state_get_pipe_subvp_type(dc->current_state, pipe_ctx_old) != SUBVP_PHANTOM)
1551			continue;
1552
1553		if (pipe_ctx_old->top_pipe || pipe_ctx_old->prev_odm_pipe)
1554			continue;
1555
1556		if (!pipe_ctx->stream || pipe_need_reprogram(pipe_ctx_old, pipe_ctx) ||
1557				(pipe_ctx->stream && dc_state_get_pipe_subvp_type(context, pipe_ctx) != SUBVP_PHANTOM)) {
1558			struct clock_source *old_clk = pipe_ctx_old->clock_source;
1559
1560			if (hws->funcs.reset_back_end_for_pipe)
1561				hws->funcs.reset_back_end_for_pipe(dc, pipe_ctx_old, dc->current_state);
1562			if (hws->funcs.enable_stream_gating)
1563				hws->funcs.enable_stream_gating(dc, pipe_ctx_old);
1564			if (old_clk)
1565				old_clk->funcs->cs_power_down(old_clk);
1566		}
1567	}
1568}
1569
1570void dcn32_enable_phantom_streams(struct dc *dc, struct dc_state *context)
1571{
1572	unsigned int i;
1573	enum dc_status status = DC_OK;
1574	struct dce_hwseq *hws = dc->hwseq;
1575
1576	for (i = 0; i < dc->res_pool->pipe_count; i++) {
1577		struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
1578		struct pipe_ctx *old_pipe = &dc->current_state->res_ctx.pipe_ctx[i];
1579
1580		/* If an active, non-phantom pipe is being transitioned into a phantom
1581		 * pipe, wait for the double buffer update to complete first before we do
1582		 * ANY phantom pipe programming.
1583		 */
1584		if (pipe->stream && dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_PHANTOM &&
1585				old_pipe->stream && dc_state_get_pipe_subvp_type(dc->current_state, old_pipe) != SUBVP_PHANTOM) {
1586			old_pipe->stream_res.tg->funcs->wait_for_state(
1587					old_pipe->stream_res.tg,
1588					CRTC_STATE_VBLANK);
1589			old_pipe->stream_res.tg->funcs->wait_for_state(
1590					old_pipe->stream_res.tg,
1591					CRTC_STATE_VACTIVE);
1592		}
1593	}
1594	for (i = 0; i < dc->res_pool->pipe_count; i++) {
1595		struct pipe_ctx *pipe_ctx_old =
1596					&dc->current_state->res_ctx.pipe_ctx[i];
1597		struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
1598
1599		if (pipe_ctx->stream == NULL)
1600			continue;
1601
1602		if (dc_state_get_pipe_subvp_type(context, pipe_ctx) != SUBVP_PHANTOM)
1603			continue;
1604
1605		if (pipe_ctx->stream == pipe_ctx_old->stream &&
1606			pipe_ctx->stream->link->link_state_valid) {
1607			continue;
1608		}
1609
1610		if (pipe_ctx_old->stream && !pipe_need_reprogram(pipe_ctx_old, pipe_ctx))
1611			continue;
1612
1613		if (pipe_ctx->top_pipe || pipe_ctx->prev_odm_pipe)
1614			continue;
1615
1616		if (hws->funcs.apply_single_controller_ctx_to_hw)
1617			status = hws->funcs.apply_single_controller_ctx_to_hw(
1618					pipe_ctx,
1619					context,
1620					dc);
1621
1622		ASSERT(status == DC_OK);
1623
1624#ifdef CONFIG_DRM_AMD_DC_FP
1625		if (hws->funcs.resync_fifo_dccg_dio)
1626			hws->funcs.resync_fifo_dccg_dio(hws, dc, context, i);
1627#endif
1628	}
1629}
1630
1631/* Blank pixel data during initialization */
1632void dcn32_init_blank(
1633		struct dc *dc,
1634		struct timing_generator *tg)
1635{
1636	struct dce_hwseq *hws = dc->hwseq;
1637	enum dc_color_space color_space;
1638	struct tg_color black_color = {0};
1639	struct output_pixel_processor *opp = NULL;
1640	struct output_pixel_processor *bottom_opp = NULL;
1641	uint32_t num_opps, opp_id_src0, opp_id_src1;
1642	uint32_t otg_active_width = 0, otg_active_height = 0;
1643	uint32_t i;
1644
1645	/* program opp dpg blank color */
1646	color_space = COLOR_SPACE_SRGB;
1647	color_space_to_black_color(dc, color_space, &black_color);
1648
1649	/* get the OTG active size */
1650	tg->funcs->get_otg_active_size(tg,
1651			&otg_active_width,
1652			&otg_active_height);
1653
1654	/* get the OPTC source */
1655	tg->funcs->get_optc_source(tg, &num_opps, &opp_id_src0, &opp_id_src1);
1656
1657	if (opp_id_src0 >= dc->res_pool->res_cap->num_opp) {
1658		ASSERT(false);
1659		return;
1660	}
1661
1662	for (i = 0; i < dc->res_pool->res_cap->num_opp; i++) {
1663		if (dc->res_pool->opps[i] != NULL && dc->res_pool->opps[i]->inst == opp_id_src0) {
1664			opp = dc->res_pool->opps[i];
1665			break;
1666		}
1667	}
1668
1669	if (num_opps == 2) {
1670		otg_active_width = otg_active_width / 2;
1671
1672		if (opp_id_src1 >= dc->res_pool->res_cap->num_opp) {
1673			ASSERT(false);
1674			return;
1675		}
1676		for (i = 0; i < dc->res_pool->res_cap->num_opp; i++) {
1677			if (dc->res_pool->opps[i] != NULL && dc->res_pool->opps[i]->inst == opp_id_src1) {
1678				bottom_opp = dc->res_pool->opps[i];
1679				break;
1680			}
1681		}
1682	}
1683
1684	if (opp && opp->funcs->opp_set_disp_pattern_generator)
1685		opp->funcs->opp_set_disp_pattern_generator(
1686				opp,
1687				CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR,
1688				CONTROLLER_DP_COLOR_SPACE_UDEFINED,
1689				COLOR_DEPTH_UNDEFINED,
1690				&black_color,
1691				otg_active_width,
1692				otg_active_height,
1693				0);
1694
1695	if (num_opps == 2) {
1696		if (bottom_opp && bottom_opp->funcs->opp_set_disp_pattern_generator) {
1697			bottom_opp->funcs->opp_set_disp_pattern_generator(
1698					bottom_opp,
1699					CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR,
1700					CONTROLLER_DP_COLOR_SPACE_UDEFINED,
1701					COLOR_DEPTH_UNDEFINED,
1702					&black_color,
1703					otg_active_width,
1704					otg_active_height,
1705					0);
1706			hws->funcs.wait_for_blank_complete(bottom_opp);
1707		}
1708	}
1709
1710	if (opp)
1711		hws->funcs.wait_for_blank_complete(opp);
1712}
1713
1714/* phantom stream id's can change often, but can be identical between contexts.
1715*  This function checks for the condition the streams are identical to avoid
1716*  redundant pipe transitions.
1717*/
1718static bool is_subvp_phantom_topology_transition_seamless(
1719	const struct dc_state *cur_ctx,
1720	const struct dc_state *new_ctx,
1721	const struct pipe_ctx *cur_pipe,
1722	const struct pipe_ctx *new_pipe)
1723{
1724	enum mall_stream_type cur_pipe_type = dc_state_get_pipe_subvp_type(cur_ctx, cur_pipe);
1725	enum mall_stream_type new_pipe_type = dc_state_get_pipe_subvp_type(new_ctx, new_pipe);
1726
1727	const struct dc_stream_state *cur_paired_stream = dc_state_get_paired_subvp_stream(cur_ctx, cur_pipe->stream);
1728	const struct dc_stream_state *new_paired_stream = dc_state_get_paired_subvp_stream(new_ctx, new_pipe->stream);
1729
1730	return cur_pipe_type == SUBVP_PHANTOM &&
1731			cur_pipe_type == new_pipe_type &&
1732			cur_paired_stream && new_paired_stream &&
1733			cur_paired_stream->stream_id == new_paired_stream->stream_id;
1734}
1735
1736bool dcn32_is_pipe_topology_transition_seamless(struct dc *dc,
1737		const struct dc_state *cur_ctx,
1738		const struct dc_state *new_ctx)
1739{
1740	int i;
1741	const struct pipe_ctx *cur_pipe, *new_pipe;
1742	bool is_seamless = true;
1743
1744	for (i = 0; i < dc->res_pool->pipe_count; i++) {
1745		cur_pipe = &cur_ctx->res_ctx.pipe_ctx[i];
1746		new_pipe = &new_ctx->res_ctx.pipe_ctx[i];
1747
1748		if (resource_is_pipe_type(cur_pipe, FREE_PIPE) ||
1749				resource_is_pipe_type(new_pipe, FREE_PIPE))
1750			/* adding or removing free pipes is always seamless */
1751			continue;
1752		else if (resource_is_pipe_type(cur_pipe, OTG_MASTER)) {
1753			if (resource_is_pipe_type(new_pipe, OTG_MASTER))
1754				if (cur_pipe->stream->stream_id == new_pipe->stream->stream_id ||
1755						is_subvp_phantom_topology_transition_seamless(cur_ctx, new_ctx, cur_pipe, new_pipe))
1756				/* OTG master with the same stream is seamless */
1757					continue;
1758		} else if (resource_is_pipe_type(cur_pipe, OPP_HEAD)) {
1759			if (resource_is_pipe_type(new_pipe, OPP_HEAD)) {
1760				if (cur_pipe->stream_res.tg == new_pipe->stream_res.tg)
1761					/*
1762					 * OPP heads sharing the same timing
1763					 * generator is seamless
1764					 */
1765					continue;
1766			}
1767		} else if (resource_is_pipe_type(cur_pipe, DPP_PIPE)) {
1768			if (resource_is_pipe_type(new_pipe, DPP_PIPE)) {
1769				if (cur_pipe->stream_res.opp == new_pipe->stream_res.opp)
1770					/*
1771					 * DPP pipes sharing the same OPP head is
1772					 * seamless
1773					 */
1774					continue;
1775			}
1776		}
1777
1778		/*
1779		 * This pipe's transition doesn't fall under any seamless
1780		 * conditions
1781		 */
1782		is_seamless = false;
1783		break;
1784	}
1785
1786	return is_seamless;
1787}
1788
1789void dcn32_prepare_bandwidth(struct dc *dc,
1790	struct dc_state *context)
1791{
1792	bool p_state_change_support = context->bw_ctx.bw.dcn.clk.p_state_change_support;
1793	/* Any transition into an FPO config should disable MCLK switching first to avoid
1794	 * driver and FW P-State synchronization issues.
1795	 */
1796	if (context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching || dc->clk_mgr->clks.fw_based_mclk_switching) {
1797		dc->optimized_required = true;
1798		context->bw_ctx.bw.dcn.clk.p_state_change_support = false;
1799	}
1800
1801	if (dc->clk_mgr->dc_mode_softmax_enabled)
1802		if (dc->clk_mgr->clks.dramclk_khz <= dc->clk_mgr->bw_params->dc_mode_softmax_memclk * 1000 &&
1803				context->bw_ctx.bw.dcn.clk.dramclk_khz > dc->clk_mgr->bw_params->dc_mode_softmax_memclk * 1000)
1804			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);
1805
1806	dcn20_prepare_bandwidth(dc, context);
1807
1808	if (!context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching)
1809		dc_dmub_srv_p_state_delegate(dc, false, context);
1810
1811	if (context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching || dc->clk_mgr->clks.fw_based_mclk_switching) {
1812		/* After disabling P-State, restore the original value to ensure we get the correct P-State
1813		 * on the next optimize.
1814		 */
1815		context->bw_ctx.bw.dcn.clk.p_state_change_support = p_state_change_support;
1816	}
1817}
1818
1819void dcn32_interdependent_update_lock(struct dc *dc,
1820		struct dc_state *context, bool lock)
1821{
1822	unsigned int i;
1823	struct pipe_ctx *pipe;
1824	struct timing_generator *tg;
1825
1826	for (i = 0; i < dc->res_pool->pipe_count; i++) {
1827		pipe = &context->res_ctx.pipe_ctx[i];
1828		tg = pipe->stream_res.tg;
1829
1830		if (!resource_is_pipe_type(pipe, OTG_MASTER) ||
1831				!tg->funcs->is_tg_enabled(tg) ||
1832				dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_PHANTOM)
1833			continue;
1834
1835		if (lock)
1836			dc->hwss.pipe_control_lock(dc, pipe, true);
1837		else
1838			dc->hwss.pipe_control_lock(dc, pipe, false);
1839	}
1840}
1841
1842void dcn32_program_outstanding_updates(struct dc *dc,
1843		struct dc_state *context)
1844{
1845	struct hubbub *hubbub = dc->res_pool->hubbub;
1846
1847	/* update compbuf if required */
1848	if (hubbub->funcs->program_compbuf_size)
1849		hubbub->funcs->program_compbuf_size(hubbub, context->bw_ctx.bw.dcn.compbuf_size_kb, true);
1850}
~/ Read-only file preview.