File Index
Files and directories
Sign in
FILE

dc_stream.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/amd/display/dc/core/dc_stream.c C
   1/*
   2 * Copyright 2012-15 Advanced Micro Devices, Inc.
   3 *
   4 * Permission is hereby granted, free of charge, to any person obtaining a
   5 * copy of this software and associated documentation files (the "Software"),
   6 * to deal in the Software without restriction, including without limitation
   7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
   8 * and/or sell copies of the Software, and to permit persons to whom the
   9 * Software is furnished to do so, subject to the following conditions:
  10 *
  11 * The above copyright notice and this permission notice shall be included in
  12 * all copies or substantial portions of the Software.
  13 *
  14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
  18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  20 * OTHER DEALINGS IN THE SOFTWARE.
  21 *
  22 * Authors: AMD
  23 *
  24 */
  25
  26#include "dm_services.h"
  27#include "basics/dc_common.h"
  28#include "dc.h"
  29#include "core_types.h"
  30#include "resource.h"
  31#include "ipp.h"
  32#include "timing_generator.h"
  33#include "dc_dmub_srv.h"
  34#include "dc_state_priv.h"
  35#include "dc_stream_priv.h"
  36
  37#define DC_LOGGER dc->ctx->logger
  38#ifndef MIN
  39#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
  40#endif
  41#ifndef MAX
  42#define MAX(x, y) ((x > y) ? x : y)
  43#endif
  44
  45/*******************************************************************************
  46 * Private functions
  47 ******************************************************************************/
  48void update_stream_signal(struct dc_stream_state *stream, struct dc_sink *sink)
  49{
  50	if (sink->sink_signal == SIGNAL_TYPE_NONE)
  51		stream->signal = stream->link->connector_signal;
  52	else
  53		stream->signal = sink->sink_signal;
  54
  55	if (dc_is_dvi_signal(stream->signal)) {
  56		if (stream->ctx->dc->caps.dual_link_dvi &&
  57			(stream->timing.pix_clk_100hz / 10) > TMDS_MAX_PIXEL_CLOCK &&
  58			sink->sink_signal != SIGNAL_TYPE_DVI_SINGLE_LINK)
  59			stream->signal = SIGNAL_TYPE_DVI_DUAL_LINK;
  60		else
  61			stream->signal = SIGNAL_TYPE_DVI_SINGLE_LINK;
  62	}
  63}
  64
  65bool dc_stream_construct(struct dc_stream_state *stream,
  66	struct dc_sink *dc_sink_data)
  67{
  68	uint32_t i = 0;
  69
  70	stream->sink = dc_sink_data;
  71	dc_sink_retain(dc_sink_data);
  72
  73	stream->ctx = dc_sink_data->ctx;
  74	stream->link = dc_sink_data->link;
  75	stream->sink_patches = dc_sink_data->edid_caps.panel_patch;
  76	stream->converter_disable_audio = dc_sink_data->converter_disable_audio;
  77	stream->qs_bit = dc_sink_data->edid_caps.qs_bit;
  78	stream->qy_bit = dc_sink_data->edid_caps.qy_bit;
  79
  80	/* Copy audio modes */
  81	/* TODO - Remove this translation */
  82	for (i = 0; i < (dc_sink_data->edid_caps.audio_mode_count); i++) {
  83		stream->audio_info.modes[i].channel_count = dc_sink_data->edid_caps.audio_modes[i].channel_count;
  84		stream->audio_info.modes[i].format_code = dc_sink_data->edid_caps.audio_modes[i].format_code;
  85		stream->audio_info.modes[i].sample_rates.all = dc_sink_data->edid_caps.audio_modes[i].sample_rate;
  86		stream->audio_info.modes[i].sample_size = dc_sink_data->edid_caps.audio_modes[i].sample_size;
  87	}
  88	stream->audio_info.mode_count = dc_sink_data->edid_caps.audio_mode_count;
  89	stream->audio_info.audio_latency = dc_sink_data->edid_caps.audio_latency;
  90	stream->audio_info.video_latency = dc_sink_data->edid_caps.video_latency;
  91	memmove(
  92		stream->audio_info.display_name,
  93		dc_sink_data->edid_caps.display_name,
  94		AUDIO_INFO_DISPLAY_NAME_SIZE_IN_CHARS);
  95	stream->audio_info.manufacture_id = dc_sink_data->edid_caps.manufacturer_id;
  96	stream->audio_info.product_id = dc_sink_data->edid_caps.product_id;
  97	stream->audio_info.flags.all = dc_sink_data->edid_caps.speaker_flags;
  98
  99	if (dc_sink_data->dc_container_id != NULL) {
 100		struct dc_container_id *dc_container_id = dc_sink_data->dc_container_id;
 101
 102		stream->audio_info.port_id[0] = dc_container_id->portId[0];
 103		stream->audio_info.port_id[1] = dc_container_id->portId[1];
 104	} else {
 105		/* TODO - WindowDM has implemented,
 106		other DMs need Unhardcode port_id */
 107		stream->audio_info.port_id[0] = 0x5558859e;
 108		stream->audio_info.port_id[1] = 0xd989449;
 109	}
 110
 111	/* EDID CAP translation for HDMI 2.0 */
 112	stream->timing.flags.LTE_340MCSC_SCRAMBLE = dc_sink_data->edid_caps.lte_340mcsc_scramble;
 113
 114	memset(&stream->timing.dsc_cfg, 0, sizeof(stream->timing.dsc_cfg));
 115	stream->timing.dsc_cfg.num_slices_h = 0;
 116	stream->timing.dsc_cfg.num_slices_v = 0;
 117	stream->timing.dsc_cfg.bits_per_pixel = 128;
 118	stream->timing.dsc_cfg.block_pred_enable = 1;
 119	stream->timing.dsc_cfg.linebuf_depth = 9;
 120	stream->timing.dsc_cfg.version_minor = 2;
 121	stream->timing.dsc_cfg.ycbcr422_simple = 0;
 122
 123	update_stream_signal(stream, dc_sink_data);
 124
 125	stream->out_transfer_func.type = TF_TYPE_BYPASS;
 126
 127	dc_stream_assign_stream_id(stream);
 128
 129	return true;
 130}
 131
 132void dc_stream_destruct(struct dc_stream_state *stream)
 133{
 134	dc_sink_release(stream->sink);
 135}
 136
 137void dc_stream_assign_stream_id(struct dc_stream_state *stream)
 138{
 139	/* MSB is reserved to indicate phantoms */
 140	stream->stream_id = stream->ctx->dc_stream_id_count;
 141	stream->ctx->dc_stream_id_count++;
 142}
 143
 144void dc_stream_retain(struct dc_stream_state *stream)
 145{
 146	kref_get(&stream->refcount);
 147}
 148
 149static void dc_stream_free(struct kref *kref)
 150{
 151	struct dc_stream_state *stream = container_of(kref, struct dc_stream_state, refcount);
 152
 153	dc_stream_destruct(stream);
 154	kfree(stream);
 155}
 156
 157void dc_stream_release(struct dc_stream_state *stream)
 158{
 159	if (stream != NULL) {
 160		kref_put(&stream->refcount, dc_stream_free);
 161	}
 162}
 163
 164struct dc_stream_state *dc_create_stream_for_sink(
 165		struct dc_sink *sink)
 166{
 167	struct dc_stream_state *stream;
 168
 169	if (sink == NULL)
 170		return NULL;
 171
 172	stream = kzalloc(sizeof(struct dc_stream_state), GFP_ATOMIC);
 173	if (stream == NULL)
 174		goto alloc_fail;
 175
 176	if (dc_stream_construct(stream, sink) == false)
 177		goto construct_fail;
 178
 179	kref_init(&stream->refcount);
 180
 181	return stream;
 182
 183construct_fail:
 184	kfree(stream);
 185
 186alloc_fail:
 187	return NULL;
 188}
 189
 190struct dc_stream_state *dc_copy_stream(const struct dc_stream_state *stream)
 191{
 192	struct dc_stream_state *new_stream;
 193
 194	new_stream = kmemdup(stream, sizeof(struct dc_stream_state), GFP_KERNEL);
 195	if (!new_stream)
 196		return NULL;
 197
 198	if (new_stream->sink)
 199		dc_sink_retain(new_stream->sink);
 200
 201	dc_stream_assign_stream_id(new_stream);
 202
 203	/* If using dynamic encoder assignment, wait till stream committed to assign encoder. */
 204	if (new_stream->ctx->dc->res_pool->funcs->link_encs_assign &&
 205			!new_stream->ctx->dc->config.unify_link_enc_assignment)
 206		new_stream->link_enc = NULL;
 207
 208	kref_init(&new_stream->refcount);
 209
 210	return new_stream;
 211}
 212
 213/**
 214 * dc_stream_get_status() - Get current stream status of the given stream state
 215 * @stream: The stream to get the stream status for.
 216 *
 217 * The given stream is expected to exist in dc->current_state. Otherwise, NULL
 218 * will be returned.
 219 */
 220struct dc_stream_status *dc_stream_get_status(
 221	struct dc_stream_state *stream)
 222{
 223	struct dc *dc = stream->ctx->dc;
 224	return dc_state_get_stream_status(dc->current_state, stream);
 225}
 226
 227const struct dc_stream_status *dc_stream_get_status_const(
 228	const struct dc_stream_state *stream)
 229{
 230	struct dc *dc = stream->ctx->dc;
 231
 232	return dc_state_get_stream_status(dc->current_state, stream);
 233}
 234
 235void program_cursor_attributes(
 236	struct dc *dc,
 237	struct dc_stream_state *stream)
 238{
 239	int i;
 240	struct resource_context *res_ctx;
 241	struct pipe_ctx *pipe_to_program = NULL;
 242	bool enable_cursor_offload = dc_dmub_srv_is_cursor_offload_enabled(dc);
 243
 244	if (!stream)
 245		return;
 246
 247	res_ctx = &dc->current_state->res_ctx;
 248
 249	for (i = 0; i < MAX_PIPES; i++) {
 250		struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[i];
 251
 252		if (pipe_ctx->stream != stream)
 253			continue;
 254
 255		if (!pipe_to_program) {
 256			pipe_to_program = pipe_ctx;
 257
 258			if (enable_cursor_offload && dc->hwss.begin_cursor_offload_update) {
 259				dc->hwss.begin_cursor_offload_update(dc, pipe_ctx);
 260			} else {
 261				dc->hwss.cursor_lock(dc, pipe_to_program, true);
 262				if (pipe_to_program->next_odm_pipe)
 263					dc->hwss.cursor_lock(dc, pipe_to_program->next_odm_pipe, true);
 264			}
 265		}
 266
 267		dc->hwss.set_cursor_attribute(pipe_ctx);
 268		if (dc->ctx->dmub_srv)
 269			dc_send_update_cursor_info_to_dmu(pipe_ctx, i);
 270		if (dc->hwss.set_cursor_sdr_white_level)
 271			dc->hwss.set_cursor_sdr_white_level(pipe_ctx);
 272		if (enable_cursor_offload && dc->hwss.update_cursor_offload_pipe)
 273			dc->hwss.update_cursor_offload_pipe(dc, pipe_ctx);
 274	}
 275
 276	if (pipe_to_program) {
 277		if (enable_cursor_offload && dc->hwss.commit_cursor_offload_update) {
 278			dc->hwss.commit_cursor_offload_update(dc, pipe_to_program);
 279		} else {
 280			dc->hwss.cursor_lock(dc, pipe_to_program, false);
 281			if (pipe_to_program->next_odm_pipe)
 282				dc->hwss.cursor_lock(dc, pipe_to_program->next_odm_pipe, false);
 283		}
 284	}
 285}
 286
 287/*
 288 * dc_stream_check_cursor_attributes() - Check validitity of cursor attributes and surface address
 289 */
 290bool dc_stream_check_cursor_attributes(
 291	const struct dc_stream_state *stream,
 292	struct dc_state *state,
 293	const struct dc_cursor_attributes *attributes)
 294{
 295	const struct dc *dc;
 296
 297	unsigned int max_cursor_size;
 298
 299	if (NULL == stream) {
 300		dm_error("DC: dc_stream is NULL!\n");
 301		return false;
 302	}
 303	if (NULL == attributes) {
 304		dm_error("DC: attributes is NULL!\n");
 305		return false;
 306	}
 307
 308	if (attributes->address.quad_part == 0) {
 309		dm_output_to_console("DC: Cursor address is 0!\n");
 310		return false;
 311	}
 312
 313	dc = stream->ctx->dc;
 314
 315	/* SubVP is not compatible with HW cursor larger than what can fit in cursor SRAM.
 316	 * Therefore, if cursor is greater than this, fallback to SW cursor.
 317	 */
 318	if (dc->debug.allow_sw_cursor_fallback && dc->res_pool->funcs->get_max_hw_cursor_size) {
 319		max_cursor_size = dc->res_pool->funcs->get_max_hw_cursor_size(dc, state, stream);
 320		max_cursor_size = max_cursor_size * max_cursor_size * 4;
 321
 322		if (attributes->height * attributes->width * 4 > max_cursor_size) {
 323			return false;
 324		}
 325	}
 326
 327	return true;
 328}
 329
 330/*
 331 * dc_stream_set_cursor_attributes() - Update cursor attributes and set cursor surface address
 332 */
 333bool dc_stream_set_cursor_attributes(
 334	struct dc_stream_state *stream,
 335	const struct dc_cursor_attributes *attributes)
 336{
 337	bool result = false;
 338
 339	if (!stream)
 340		return false;
 341
 342	if (dc_stream_check_cursor_attributes(stream, stream->ctx->dc->current_state, attributes)) {
 343		stream->cursor_attributes = *attributes;
 344		result = true;
 345	}
 346
 347	return result;
 348}
 349
 350bool dc_stream_program_cursor_attributes(
 351	struct dc_stream_state *stream,
 352	const struct dc_cursor_attributes *attributes)
 353{
 354	struct dc  *dc;
 355	bool reset_idle_optimizations = false;
 356
 357	if (!stream)
 358		return false;
 359
 360	dc = stream->ctx->dc;
 361
 362	if (dc_stream_set_cursor_attributes(stream, attributes)) {
 363		dc_z10_restore(dc);
 364		/* disable idle optimizations while updating cursor */
 365		if (dc->idle_optimizations_allowed) {
 366			dc_allow_idle_optimizations(dc, false);
 367			reset_idle_optimizations = true;
 368		}
 369
 370		program_cursor_attributes(dc, stream);
 371
 372		/* re-enable idle optimizations if necessary */
 373		if (reset_idle_optimizations && !dc->debug.disable_dmub_reallow_idle)
 374			dc_allow_idle_optimizations(dc, true);
 375
 376		return true;
 377	}
 378
 379	return false;
 380}
 381
 382void program_cursor_position(
 383	struct dc *dc,
 384	struct dc_stream_state *stream)
 385{
 386	int i;
 387	struct resource_context *res_ctx;
 388	struct pipe_ctx *pipe_to_program = NULL;
 389	bool enable_cursor_offload = dc_dmub_srv_is_cursor_offload_enabled(dc);
 390
 391	if (!stream)
 392		return;
 393
 394	res_ctx = &dc->current_state->res_ctx;
 395
 396	for (i = 0; i < MAX_PIPES; i++) {
 397		struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[i];
 398
 399		if (pipe_ctx->stream != stream ||
 400				(!pipe_ctx->plane_res.mi  && !pipe_ctx->plane_res.hubp) ||
 401				!pipe_ctx->plane_state ||
 402				(!pipe_ctx->plane_res.xfm && !pipe_ctx->plane_res.dpp) ||
 403				(!pipe_ctx->plane_res.ipp && !pipe_ctx->plane_res.dpp))
 404			continue;
 405
 406		if (!pipe_to_program) {
 407			pipe_to_program = pipe_ctx;
 408
 409			if (enable_cursor_offload && dc->hwss.begin_cursor_offload_update)
 410				dc->hwss.begin_cursor_offload_update(dc, pipe_ctx);
 411			else
 412				dc->hwss.cursor_lock(dc, pipe_to_program, true);
 413		}
 414
 415		dc->hwss.set_cursor_position(pipe_ctx);
 416		if (enable_cursor_offload && dc->hwss.update_cursor_offload_pipe)
 417			dc->hwss.update_cursor_offload_pipe(dc, pipe_ctx);
 418
 419		if (dc->ctx->dmub_srv)
 420			dc_send_update_cursor_info_to_dmu(pipe_ctx, i);
 421	}
 422
 423	if (pipe_to_program) {
 424		if (enable_cursor_offload && dc->hwss.commit_cursor_offload_update)
 425			dc->hwss.commit_cursor_offload_update(dc, pipe_to_program);
 426		else
 427			dc->hwss.cursor_lock(dc, pipe_to_program, false);
 428	}
 429}
 430
 431bool dc_stream_set_cursor_position(
 432	struct dc_stream_state *stream,
 433	const struct dc_cursor_position *position)
 434{
 435	if (NULL == stream) {
 436		dm_error("DC: dc_stream is NULL!\n");
 437		return false;
 438	}
 439
 440	if (NULL == position) {
 441		dm_error("DC: cursor position is NULL!\n");
 442		return false;
 443	}
 444
 445	stream->cursor_position = *position;
 446
 447
 448	return true;
 449}
 450
 451bool dc_stream_program_cursor_position(
 452	struct dc_stream_state *stream,
 453	const struct dc_cursor_position *position)
 454{
 455	struct dc *dc;
 456	bool reset_idle_optimizations = false;
 457	const struct dc_cursor_position *old_position;
 458
 459	if (!stream)
 460		return false;
 461
 462	old_position = &stream->cursor_position;
 463	dc = stream->ctx->dc;
 464
 465	if (dc_stream_set_cursor_position(stream, position)) {
 466		dc_z10_restore(dc);
 467
 468		/* disable idle optimizations if enabling cursor */
 469		if (dc->idle_optimizations_allowed &&
 470		    (!old_position->enable || dc->debug.exit_idle_opt_for_cursor_updates) &&
 471		    position->enable) {
 472			dc_allow_idle_optimizations(dc, false);
 473			reset_idle_optimizations = true;
 474		}
 475
 476		program_cursor_position(dc, stream);
 477		/* re-enable idle optimizations if necessary */
 478		if (reset_idle_optimizations && !dc->debug.disable_dmub_reallow_idle)
 479			dc_allow_idle_optimizations(dc, true);
 480
 481		/* apply/update visual confirm */
 482		if (dc->debug.visual_confirm == VISUAL_CONFIRM_HW_CURSOR) {
 483			/* update software state */
 484			int i;
 485
 486			for (i = 0; i < dc->res_pool->pipe_count; i++) {
 487				struct pipe_ctx *pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i];
 488
 489				/* adjust visual confirm color for all pipes with current stream */
 490				if (stream == pipe_ctx->stream) {
 491					get_cursor_visual_confirm_color(pipe_ctx, &(pipe_ctx->visual_confirm_color));
 492
 493					/* programming hardware */
 494					if (pipe_ctx->plane_state)
 495						dc->hwss.update_visual_confirm_color(dc, pipe_ctx,
 496								pipe_ctx->plane_res.hubp->mpcc_id);
 497				}
 498			}
 499		}
 500
 501		return true;
 502	}
 503
 504	return false;
 505}
 506
 507bool dc_stream_add_writeback(struct dc *dc,
 508		struct dc_stream_state *stream,
 509		struct dc_writeback_info *wb_info)
 510{
 511	bool isDrc = false;
 512	int i = 0;
 513	struct dwbc *dwb;
 514
 515	if (stream == NULL) {
 516		dm_error("DC: dc_stream is NULL!\n");
 517		return false;
 518	}
 519
 520	if (wb_info == NULL) {
 521		dm_error("DC: dc_writeback_info is NULL!\n");
 522		return false;
 523	}
 524
 525	if (wb_info->dwb_pipe_inst >= MAX_DWB_PIPES) {
 526		dm_error("DC: writeback pipe is invalid!\n");
 527		return false;
 528	}
 529
 530	dc_exit_ips_for_hw_access(dc);
 531
 532	wb_info->dwb_params.out_transfer_func = &stream->out_transfer_func;
 533
 534	dwb = dc->res_pool->dwbc[wb_info->dwb_pipe_inst];
 535	dwb->dwb_is_drc = false;
 536
 537	/* recalculate and apply DML parameters */
 538
 539	for (i = 0; i < stream->num_wb_info; i++) {
 540		/*dynamic update*/
 541		if (stream->writeback_info[i].wb_enabled &&
 542			stream->writeback_info[i].dwb_pipe_inst == wb_info->dwb_pipe_inst) {
 543			stream->writeback_info[i] = *wb_info;
 544			isDrc = true;
 545		}
 546	}
 547
 548	if (!isDrc) {
 549		ASSERT(stream->num_wb_info + 1 <= MAX_DWB_PIPES);
 550		stream->writeback_info[stream->num_wb_info++] = *wb_info;
 551	}
 552
 553	if (dc->hwss.enable_writeback) {
 554		struct dc_stream_status *stream_status = dc_stream_get_status(stream);
 555		struct dwbc *dwb = dc->res_pool->dwbc[wb_info->dwb_pipe_inst];
 556		if (stream_status)
 557			dwb->otg_inst = stream_status->primary_otg_inst;
 558	}
 559
 560	if (!dc->hwss.update_bandwidth(dc, dc->current_state)) {
 561		dm_error("DC: update_bandwidth failed!\n");
 562		return false;
 563	}
 564
 565	/* enable writeback */
 566	if (dc->hwss.enable_writeback) {
 567		struct dwbc *dwb = dc->res_pool->dwbc[wb_info->dwb_pipe_inst];
 568
 569		if (dwb->funcs->is_enabled(dwb)) {
 570			/* writeback pipe already enabled, only need to update */
 571			dc->hwss.update_writeback(dc, wb_info, dc->current_state);
 572		} else {
 573			/* Enable writeback pipe from scratch*/
 574			dc->hwss.enable_writeback(dc, wb_info, dc->current_state);
 575		}
 576	}
 577
 578	return true;
 579}
 580
 581bool dc_stream_fc_disable_writeback(struct dc *dc,
 582		struct dc_stream_state *stream,
 583		uint32_t dwb_pipe_inst)
 584{
 585	struct dwbc *dwb = dc->res_pool->dwbc[dwb_pipe_inst];
 586
 587	if (stream == NULL) {
 588		dm_error("DC: dc_stream is NULL!\n");
 589		return false;
 590	}
 591
 592	if (dwb_pipe_inst >= MAX_DWB_PIPES) {
 593		dm_error("DC: writeback pipe is invalid!\n");
 594		return false;
 595	}
 596
 597	if (stream->num_wb_info > MAX_DWB_PIPES) {
 598		dm_error("DC: num_wb_info is invalid!\n");
 599		return false;
 600	}
 601
 602	dc_exit_ips_for_hw_access(dc);
 603
 604	if (dwb->funcs->set_fc_enable)
 605		dwb->funcs->set_fc_enable(dwb, DWB_FRAME_CAPTURE_DISABLE);
 606
 607	return true;
 608}
 609
 610/**
 611 * dc_stream_remove_writeback() - Disables writeback and removes writeback info.
 612 * @dc: Display core control structure.
 613 * @stream: Display core stream state.
 614 * @dwb_pipe_inst: Display writeback pipe.
 615 *
 616 * Return: returns true on success, false otherwise.
 617 */
 618bool dc_stream_remove_writeback(struct dc *dc,
 619		struct dc_stream_state *stream,
 620		uint32_t dwb_pipe_inst)
 621{
 622	unsigned int i, j;
 623	if (stream == NULL) {
 624		dm_error("DC: dc_stream is NULL!\n");
 625		return false;
 626	}
 627
 628	if (dwb_pipe_inst >= MAX_DWB_PIPES) {
 629		dm_error("DC: writeback pipe is invalid!\n");
 630		return false;
 631	}
 632
 633	if (stream->num_wb_info > MAX_DWB_PIPES) {
 634		dm_error("DC: num_wb_info is invalid!\n");
 635		return false;
 636	}
 637
 638	/* remove writeback info for disabled writeback pipes from stream */
 639	for (i = 0, j = 0; i < stream->num_wb_info; i++) {
 640		if (stream->writeback_info[i].wb_enabled) {
 641
 642			if (stream->writeback_info[i].dwb_pipe_inst == dwb_pipe_inst)
 643				stream->writeback_info[i].wb_enabled = false;
 644
 645			/* trim the array */
 646			if (j < i) {
 647				memcpy(&stream->writeback_info[j], &stream->writeback_info[i],
 648						sizeof(struct dc_writeback_info));
 649				j++;
 650			}
 651		}
 652	}
 653	stream->num_wb_info = j;
 654
 655	/* recalculate and apply DML parameters */
 656	if (!dc->hwss.update_bandwidth(dc, dc->current_state)) {
 657		dm_error("DC: update_bandwidth failed!\n");
 658		return false;
 659	}
 660
 661	dc_exit_ips_for_hw_access(dc);
 662
 663	/* disable writeback */
 664	if (dc->hwss.disable_writeback) {
 665		struct dwbc *dwb = dc->res_pool->dwbc[dwb_pipe_inst];
 666
 667		if (dwb->funcs->is_enabled(dwb))
 668			dc->hwss.disable_writeback(dc, dwb_pipe_inst);
 669	}
 670
 671	return true;
 672}
 673
 674uint32_t dc_stream_get_vblank_counter(const struct dc_stream_state *stream)
 675{
 676	uint8_t i;
 677	struct dc  *dc = stream->ctx->dc;
 678	struct resource_context *res_ctx =
 679		&dc->current_state->res_ctx;
 680
 681	dc_exit_ips_for_hw_access(dc);
 682
 683	for (i = 0; i < MAX_PIPES; i++) {
 684		struct timing_generator *tg = res_ctx->pipe_ctx[i].stream_res.tg;
 685
 686		if (res_ctx->pipe_ctx[i].stream != stream || !tg)
 687			continue;
 688
 689		return tg->funcs->get_frame_count(tg);
 690	}
 691
 692	return 0;
 693}
 694
 695bool dc_stream_send_dp_sdp(const struct dc_stream_state *stream,
 696		const uint8_t *custom_sdp_message,
 697		unsigned int sdp_message_size)
 698{
 699	int i;
 700	struct dc  *dc;
 701	struct resource_context *res_ctx;
 702
 703	if (stream == NULL) {
 704		dm_error("DC: dc_stream is NULL!\n");
 705		return false;
 706	}
 707
 708	dc = stream->ctx->dc;
 709	res_ctx = &dc->current_state->res_ctx;
 710
 711	dc_exit_ips_for_hw_access(dc);
 712
 713	for (i = 0; i < MAX_PIPES; i++) {
 714		struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[i];
 715
 716		if (pipe_ctx->stream != stream)
 717			continue;
 718
 719		if (dc->hwss.send_immediate_sdp_message != NULL)
 720			dc->hwss.send_immediate_sdp_message(pipe_ctx,
 721								custom_sdp_message,
 722								sdp_message_size);
 723		else
 724			DC_LOG_WARNING("%s:send_immediate_sdp_message not implemented on this ASIC\n",
 725			__func__);
 726
 727	}
 728
 729	return true;
 730}
 731
 732bool dc_stream_get_scanoutpos(const struct dc_stream_state *stream,
 733				  uint32_t *v_blank_start,
 734				  uint32_t *v_blank_end,
 735				  uint32_t *h_position,
 736				  uint32_t *v_position)
 737{
 738	uint8_t i;
 739	bool ret = false;
 740	struct dc  *dc;
 741	struct resource_context *res_ctx;
 742
 743	if (!stream->ctx)
 744		return false;
 745
 746	dc = stream->ctx->dc;
 747	res_ctx = &dc->current_state->res_ctx;
 748
 749	dc_exit_ips_for_hw_access(dc);
 750
 751	for (i = 0; i < MAX_PIPES; i++) {
 752		struct timing_generator *tg = res_ctx->pipe_ctx[i].stream_res.tg;
 753
 754		if (res_ctx->pipe_ctx[i].stream != stream || !tg)
 755			continue;
 756
 757		tg->funcs->get_scanoutpos(tg,
 758					  v_blank_start,
 759					  v_blank_end,
 760					  h_position,
 761					  v_position);
 762
 763		ret = true;
 764		break;
 765	}
 766
 767	return ret;
 768}
 769
 770bool dc_stream_dmdata_status_done(struct dc *dc, struct dc_stream_state *stream)
 771{
 772	struct pipe_ctx *pipe = NULL;
 773	int i;
 774
 775	if (!dc->hwss.dmdata_status_done)
 776		return false;
 777
 778	for (i = 0; i < MAX_PIPES; i++) {
 779		pipe = &dc->current_state->res_ctx.pipe_ctx[i];
 780		if (pipe->stream == stream)
 781			break;
 782	}
 783	/* Stream not found, by default we'll assume HUBP fetched dm data */
 784	if (i == MAX_PIPES)
 785		return true;
 786
 787	dc_exit_ips_for_hw_access(dc);
 788
 789	return dc->hwss.dmdata_status_done(pipe);
 790}
 791
 792bool dc_stream_set_dynamic_metadata(struct dc *dc,
 793		struct dc_stream_state *stream,
 794		struct dc_dmdata_attributes *attr)
 795{
 796	struct pipe_ctx *pipe_ctx = NULL;
 797	struct hubp *hubp;
 798	int i;
 799
 800	/* Dynamic metadata is only supported on HDMI or DP */
 801	if (!dc_is_hdmi_signal(stream->signal) && !dc_is_dp_signal(stream->signal))
 802		return false;
 803
 804	/* Check hardware support */
 805	if (!dc->hwss.program_dmdata_engine)
 806		return false;
 807
 808	for (i = 0; i < MAX_PIPES; i++) {
 809		pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i];
 810		if (pipe_ctx->stream == stream)
 811			break;
 812	}
 813
 814	if (i == MAX_PIPES)
 815		return false;
 816
 817	hubp = pipe_ctx->plane_res.hubp;
 818	if (hubp == NULL)
 819		return false;
 820
 821	pipe_ctx->stream->dmdata_address = attr->address;
 822
 823	dc_exit_ips_for_hw_access(dc);
 824
 825	dc->hwss.program_dmdata_engine(pipe_ctx);
 826
 827	if (hubp->funcs->dmdata_set_attributes != NULL &&
 828			pipe_ctx->stream->dmdata_address.quad_part != 0) {
 829		hubp->funcs->dmdata_set_attributes(hubp, attr);
 830	}
 831
 832	return true;
 833}
 834
 835enum dc_status dc_stream_add_dsc_to_resource(struct dc *dc,
 836		struct dc_state *state,
 837		struct dc_stream_state *stream)
 838{
 839	if (dc->res_pool->funcs->add_dsc_to_stream_resource) {
 840		return dc->res_pool->funcs->add_dsc_to_stream_resource(dc, state, stream);
 841	} else {
 842		return DC_NO_DSC_RESOURCE;
 843	}
 844}
 845
 846struct pipe_ctx *dc_stream_get_pipe_ctx(struct dc_stream_state *stream)
 847{
 848	int i = 0;
 849
 850	for (i = 0; i < MAX_PIPES; i++) {
 851		struct pipe_ctx *pipe = &stream->ctx->dc->current_state->res_ctx.pipe_ctx[i];
 852
 853		if (pipe->stream == stream)
 854			return pipe;
 855	}
 856
 857	return NULL;
 858}
 859
 860void dc_stream_log(const struct dc *dc, const struct dc_stream_state *stream)
 861{
 862	DC_LOG_DC(
 863			"core_stream 0x%p: src: %d, %d, %d, %d; dst: %d, %d, %d, %d, colorSpace:%d\n",
 864			stream,
 865			stream->src.x,
 866			stream->src.y,
 867			stream->src.width,
 868			stream->src.height,
 869			stream->dst.x,
 870			stream->dst.y,
 871			stream->dst.width,
 872			stream->dst.height,
 873			stream->output_color_space);
 874	DC_LOG_DC(
 875			"\tpix_clk_khz: %d, h_total: %d, v_total: %d, pixel_encoding:%s, color_depth:%s\n",
 876			stream->timing.pix_clk_100hz / 10,
 877			stream->timing.h_total,
 878			stream->timing.v_total,
 879			dc_pixel_encoding_to_str(stream->timing.pixel_encoding),
 880			dc_color_depth_to_str(stream->timing.display_color_depth));
 881	DC_LOG_DC(
 882			"\tlink: %d\n",
 883			stream->link->link_index);
 884
 885	DC_LOG_DC(
 886			"\tdsc: %d, mst_pbn: %d\n",
 887			stream->timing.flags.DSC,
 888			stream->timing.dsc_cfg.mst_pbn);
 889
 890	if (stream->sink) {
 891		if (stream->sink->sink_signal != SIGNAL_TYPE_VIRTUAL &&
 892			stream->sink->sink_signal != SIGNAL_TYPE_NONE) {
 893
 894			DC_LOG_DC(
 895					"\tsignal: %x dispname: %s manufacturer_id: 0x%x product_id: 0x%x\n",
 896					stream->signal,
 897					stream->sink->edid_caps.display_name,
 898					stream->sink->edid_caps.manufacturer_id,
 899					stream->sink->edid_caps.product_id);
 900		}
 901	}
 902}
 903
 904/*
 905*	dc_stream_get_3dlut()
 906*	Requirements:
 907*	1. Is stream already owns an RMCM instance, return it.
 908*	2. If it doesn't and we don't need to allocate, return NULL.
 909*	3. If there's a free RMCM instance, assign to stream and return it.
 910*	4. If no free RMCM instances, return NULL.
 911*/
 912
 913struct dc_rmcm_3dlut *dc_stream_get_3dlut_for_stream(
 914	const struct dc *dc,
 915	const struct dc_stream_state *stream,
 916	bool allocate_one)
 917{
 918	unsigned int num_rmcm = dc->caps.color.mpc.num_rmcm_3dluts;
 919
 920	// see if one is allocated for this stream
 921	for (int i = 0; i < num_rmcm; i++) {
 922		if (dc->res_pool->rmcm_3dlut[i].isInUse &&
 923			dc->res_pool->rmcm_3dlut[i].stream == stream)
 924			return &dc->res_pool->rmcm_3dlut[i];
 925	}
 926
 927	//case: not found one, and dont need to allocate
 928	if (!allocate_one)
 929		return NULL;
 930
 931	//see if there is an unused 3dlut, allocate
 932	for (int i = 0; i < num_rmcm; i++) {
 933		if (!dc->res_pool->rmcm_3dlut[i].isInUse) {
 934			dc->res_pool->rmcm_3dlut[i].isInUse = true;
 935			dc->res_pool->rmcm_3dlut[i].stream = stream;
 936			return &dc->res_pool->rmcm_3dlut[i];
 937		}
 938	}
 939
 940	//dont have a 3dlut
 941	return NULL;
 942}
 943
 944
 945void dc_stream_release_3dlut_for_stream(
 946	const struct dc *dc,
 947	const struct dc_stream_state *stream)
 948{
 949	struct dc_rmcm_3dlut *rmcm_3dlut =
 950		dc_stream_get_3dlut_for_stream(dc, stream, false);
 951
 952	if (rmcm_3dlut) {
 953		rmcm_3dlut->isInUse = false;
 954		rmcm_3dlut->stream  = NULL;
 955		rmcm_3dlut->protection_bits = 0;
 956	}
 957}
 958
 959
 960void dc_stream_init_rmcm_3dlut(struct dc *dc)
 961{
 962	unsigned int num_rmcm = dc->caps.color.mpc.num_rmcm_3dluts;
 963
 964	for (int i = 0; i < num_rmcm; i++) {
 965		dc->res_pool->rmcm_3dlut[i].isInUse = false;
 966		dc->res_pool->rmcm_3dlut[i].stream = NULL;
 967		dc->res_pool->rmcm_3dlut[i].protection_bits = 0;
 968	}
 969}
 970
 971/*
 972 * Finds the greatest index in refresh_rate_hz that contains a value <= refresh
 973 */
 974static int dc_stream_get_nearest_smallest_index(struct dc_stream_state *stream, int refresh)
 975{
 976	for (int i = 0; i < (LUMINANCE_DATA_TABLE_SIZE - 1); ++i) {
 977		if ((stream->lumin_data.refresh_rate_hz[i] <= refresh) && (refresh < stream->lumin_data.refresh_rate_hz[i + 1])) {
 978			return i;
 979		}
 980	}
 981	return 9;
 982}
 983
 984/*
 985 * Finds a corresponding brightness for a given refresh rate between 2 given indices, where index1 < index2
 986 */
 987static int dc_stream_get_brightness_millinits_linear_interpolation (struct dc_stream_state *stream,
 988								     int index1,
 989								     int index2,
 990								     int refresh_hz)
 991{
 992	long long slope = 0;
 993	if (stream->lumin_data.refresh_rate_hz[index2] != stream->lumin_data.refresh_rate_hz[index1]) {
 994		slope = (stream->lumin_data.luminance_millinits[index2] - stream->lumin_data.luminance_millinits[index1]) /
 995			    (stream->lumin_data.refresh_rate_hz[index2] - stream->lumin_data.refresh_rate_hz[index1]);
 996	}
 997
 998	int y_intercept = stream->lumin_data.luminance_millinits[index2] - slope * stream->lumin_data.refresh_rate_hz[index2];
 999
1000	return (y_intercept + refresh_hz * slope);
1001}
1002
1003/*
1004 * Finds a corresponding refresh rate for a given brightness between 2 given indices, where index1 < index2
1005 */
1006static int dc_stream_get_refresh_hz_linear_interpolation (struct dc_stream_state *stream,
1007							   int index1,
1008							   int index2,
1009							   int brightness_millinits)
1010{
1011	long long slope = 1;
1012	if (stream->lumin_data.refresh_rate_hz[index2] != stream->lumin_data.refresh_rate_hz[index1]) {
1013		slope = (stream->lumin_data.luminance_millinits[index2] - stream->lumin_data.luminance_millinits[index1]) /
1014				(stream->lumin_data.refresh_rate_hz[index2] - stream->lumin_data.refresh_rate_hz[index1]);
1015	}
1016
1017	int y_intercept = stream->lumin_data.luminance_millinits[index2] - slope * stream->lumin_data.refresh_rate_hz[index2];
1018
1019	return ((int)div64_s64((brightness_millinits - y_intercept), slope));
1020}
1021
1022/*
1023 * Finds the current brightness in millinits given a refresh rate
1024 */
1025static int dc_stream_get_brightness_millinits_from_refresh (struct dc_stream_state *stream, int refresh_hz)
1026{
1027	int nearest_smallest_index = dc_stream_get_nearest_smallest_index(stream, refresh_hz);
1028	int nearest_smallest_value = stream->lumin_data.refresh_rate_hz[nearest_smallest_index];
1029
1030	if (nearest_smallest_value == refresh_hz)
1031		return stream->lumin_data.luminance_millinits[nearest_smallest_index];
1032
1033	if (nearest_smallest_index >= 9)
1034		return dc_stream_get_brightness_millinits_linear_interpolation(stream, nearest_smallest_index - 1, nearest_smallest_index, refresh_hz);
1035
1036	if (nearest_smallest_value == stream->lumin_data.refresh_rate_hz[nearest_smallest_index + 1])
1037		return stream->lumin_data.luminance_millinits[nearest_smallest_index];
1038
1039	return dc_stream_get_brightness_millinits_linear_interpolation(stream, nearest_smallest_index, nearest_smallest_index + 1, refresh_hz);
1040}
1041
1042/*
1043 * Finds the lowest/highest refresh rate (depending on search_for_max_increase)
1044 * that can be achieved from starting_refresh_hz while staying
1045 * within flicker criteria
1046 */
1047static int dc_stream_calculate_flickerless_refresh_rate(struct dc_stream_state *stream,
1048							 int current_brightness,
1049							 int starting_refresh_hz,
1050							 bool is_gaming,
1051							 bool search_for_max_increase)
1052{
1053	int nearest_smallest_index = dc_stream_get_nearest_smallest_index(stream, starting_refresh_hz);
1054
1055	int flicker_criteria_millinits = is_gaming ?
1056					 stream->lumin_data.flicker_criteria_milli_nits_GAMING :
1057					 stream->lumin_data.flicker_criteria_milli_nits_STATIC;
1058
1059	int safe_upper_bound = current_brightness + flicker_criteria_millinits;
1060	int safe_lower_bound = current_brightness - flicker_criteria_millinits;
1061	int lumin_millinits_temp = 0;
1062
1063	int offset = -1;
1064	if (search_for_max_increase) {
1065		offset = 1;
1066	}
1067
1068	/*
1069	 * Increments up or down by 1 depending on search_for_max_increase
1070	 */
1071	for (int i = nearest_smallest_index; (i > 0 && !search_for_max_increase) || (i < (LUMINANCE_DATA_TABLE_SIZE - 1) && search_for_max_increase); i += offset) {
1072
1073		lumin_millinits_temp = stream->lumin_data.luminance_millinits[i + offset];
1074
1075		if ((lumin_millinits_temp >= safe_upper_bound) || (lumin_millinits_temp <= safe_lower_bound)) {
1076
1077			if (stream->lumin_data.refresh_rate_hz[i + offset] == stream->lumin_data.refresh_rate_hz[i])
1078				return stream->lumin_data.refresh_rate_hz[i];
1079
1080			int target_brightness = (stream->lumin_data.luminance_millinits[i + offset] >= (current_brightness + flicker_criteria_millinits)) ?
1081											current_brightness + flicker_criteria_millinits :
1082											current_brightness - flicker_criteria_millinits;
1083
1084			int refresh = 0;
1085
1086			/*
1087			 * Need the second input to be < third input for dc_stream_get_refresh_hz_linear_interpolation
1088			 */
1089			if (search_for_max_increase)
1090				refresh = dc_stream_get_refresh_hz_linear_interpolation(stream, i, i + offset, target_brightness);
1091			else
1092				refresh = dc_stream_get_refresh_hz_linear_interpolation(stream, i + offset, i, target_brightness);
1093
1094			if (refresh == stream->lumin_data.refresh_rate_hz[i + offset])
1095				return stream->lumin_data.refresh_rate_hz[i + offset];
1096
1097			return refresh;
1098		}
1099	}
1100
1101	if (search_for_max_increase)
1102		return (int)div64_s64((long long)stream->timing.pix_clk_100hz*100, stream->timing.v_total*(long long)stream->timing.h_total);
1103	else
1104		return stream->lumin_data.refresh_rate_hz[0];
1105}
1106
1107/*
1108 * Gets the max delta luminance within a specified refresh range
1109 */
1110static int dc_stream_get_max_delta_lumin_millinits(struct dc_stream_state *stream, int hz1, int hz2, bool isGaming)
1111{
1112	int lower_refresh_brightness = dc_stream_get_brightness_millinits_from_refresh (stream, hz1);
1113	int higher_refresh_brightness = dc_stream_get_brightness_millinits_from_refresh (stream, hz2);
1114
1115	int min = lower_refresh_brightness;
1116	int max = higher_refresh_brightness;
1117
1118	/*
1119	 * Static screen, therefore no need to scan through array
1120	 */
1121	if (!isGaming) {
1122		if (lower_refresh_brightness >= higher_refresh_brightness) {
1123			return lower_refresh_brightness - higher_refresh_brightness;
1124		}
1125		return higher_refresh_brightness - lower_refresh_brightness;
1126	}
1127
1128	min = MIN(lower_refresh_brightness, higher_refresh_brightness);
1129	max = MAX(lower_refresh_brightness, higher_refresh_brightness);
1130
1131	int nearest_smallest_index = dc_stream_get_nearest_smallest_index(stream, hz1);
1132
1133	for (; nearest_smallest_index < (LUMINANCE_DATA_TABLE_SIZE - 1) &&
1134			stream->lumin_data.refresh_rate_hz[nearest_smallest_index + 1] <= hz2 ; nearest_smallest_index++) {
1135		min = MIN(min, stream->lumin_data.luminance_millinits[nearest_smallest_index + 1]);
1136		max = MAX(max, stream->lumin_data.luminance_millinits[nearest_smallest_index + 1]);
1137	}
1138
1139	return (max - min);
1140}
1141
1142/*
1143 * Determines the max flickerless instant vtotal delta for a stream.
1144 * Determines vtotal increase/decrease based on the bool "increase"
1145 */
1146static unsigned int dc_stream_get_max_flickerless_instant_vtotal_delta(struct dc_stream_state *stream, bool is_gaming, bool increase)
1147{
1148	if (stream->timing.v_total * stream->timing.h_total == 0)
1149		return 0;
1150
1151	int current_refresh_hz = (int)div64_s64((long long)stream->timing.pix_clk_100hz*100, stream->timing.v_total*(long long)stream->timing.h_total);
1152
1153	int safe_refresh_hz = dc_stream_calculate_flickerless_refresh_rate(stream,
1154							 dc_stream_get_brightness_millinits_from_refresh(stream, current_refresh_hz),
1155							 current_refresh_hz,
1156							 is_gaming,
1157							 increase);
1158
1159	int safe_refresh_v_total = (int)div64_s64((long long)stream->timing.pix_clk_100hz*100, safe_refresh_hz*(long long)stream->timing.h_total);
1160
1161	if (increase)
1162		return (((int) stream->timing.v_total - safe_refresh_v_total) >= 0) ? (stream->timing.v_total - safe_refresh_v_total) : 0;
1163
1164	return ((safe_refresh_v_total - (int) stream->timing.v_total) >= 0) ? (safe_refresh_v_total - stream->timing.v_total) : 0;
1165}
1166
1167/*
1168 * Finds the highest refresh rate that can be achieved
1169 * from starting_refresh_hz while staying within flicker criteria
1170 */
1171int dc_stream_calculate_max_flickerless_refresh_rate(struct dc_stream_state *stream, int starting_refresh_hz, bool is_gaming)
1172{
1173	if (!stream->lumin_data.is_valid)
1174		return 0;
1175
1176	int current_brightness = dc_stream_get_brightness_millinits_from_refresh(stream, starting_refresh_hz);
1177
1178	return dc_stream_calculate_flickerless_refresh_rate(stream,
1179							    current_brightness,
1180							    starting_refresh_hz,
1181							    is_gaming,
1182							    true);
1183}
1184
1185/*
1186 * Finds the lowest refresh rate that can be achieved
1187 * from starting_refresh_hz while staying within flicker criteria
1188 */
1189int dc_stream_calculate_min_flickerless_refresh_rate(struct dc_stream_state *stream, int starting_refresh_hz, bool is_gaming)
1190{
1191	if (!stream->lumin_data.is_valid)
1192			return 0;
1193
1194	int current_brightness = dc_stream_get_brightness_millinits_from_refresh(stream, starting_refresh_hz);
1195
1196	return dc_stream_calculate_flickerless_refresh_rate(stream,
1197							    current_brightness,
1198							    starting_refresh_hz,
1199							    is_gaming,
1200							    false);
1201}
1202
1203/*
1204 * Determines if there will be a flicker when moving between 2 refresh rates
1205 */
1206bool dc_stream_is_refresh_rate_range_flickerless(struct dc_stream_state *stream, int hz1, int hz2, bool is_gaming)
1207{
1208
1209	/*
1210	 * Assume that we wont flicker if there is invalid data
1211	 */
1212	if (!stream->lumin_data.is_valid)
1213		return false;
1214
1215	int dl = dc_stream_get_max_delta_lumin_millinits(stream, hz1, hz2, is_gaming);
1216
1217	int flicker_criteria_millinits = (is_gaming) ?
1218					  stream->lumin_data.flicker_criteria_milli_nits_GAMING :
1219					  stream->lumin_data.flicker_criteria_milli_nits_STATIC;
1220
1221	return (dl <= flicker_criteria_millinits);
1222}
1223
1224/*
1225 * Determines the max instant vtotal delta increase that can be applied without
1226 * flickering for a given stream
1227 */
1228unsigned int dc_stream_get_max_flickerless_instant_vtotal_decrease(struct dc_stream_state *stream,
1229									  bool is_gaming)
1230{
1231	if (!stream->lumin_data.is_valid)
1232		return 0;
1233
1234	return dc_stream_get_max_flickerless_instant_vtotal_delta(stream, is_gaming, true);
1235}
1236
1237/*
1238 * Determines the max instant vtotal delta decrease that can be applied without
1239 * flickering for a given stream
1240 */
1241unsigned int dc_stream_get_max_flickerless_instant_vtotal_increase(struct dc_stream_state *stream,
1242									  bool is_gaming)
1243{
1244	if (!stream->lumin_data.is_valid)
1245		return 0;
1246
1247	return dc_stream_get_max_flickerless_instant_vtotal_delta(stream, is_gaming, false);
1248}
1249
1250bool dc_stream_is_cursor_limit_pending(struct dc *dc, struct dc_stream_state *stream)
1251{
1252	bool is_limit_pending = false;
1253
1254	if (dc->current_state)
1255		is_limit_pending = dc_state_get_stream_cursor_subvp_limit(stream, dc->current_state);
1256
1257	return is_limit_pending;
1258}
1259
1260bool dc_stream_can_clear_cursor_limit(struct dc *dc, struct dc_stream_state *stream)
1261{
1262	bool can_clear_limit = false;
1263
1264	if (dc->current_state)
1265		can_clear_limit = dc_state_get_stream_cursor_subvp_limit(stream, dc->current_state) &&
1266				(stream->hw_cursor_req ||
1267				!stream->cursor_position.enable ||
1268				dc_stream_check_cursor_attributes(stream, dc->current_state, &stream->cursor_attributes));
1269
1270	return can_clear_limit;
1271}
~/ Read-only file preview.