File Index
Files and directories
Sign in
FILE

dc_state.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/amd/display/dc/core/dc_state.c C
   1/*
   2 * Copyright 2023 Advanced Micro Devices, Inc.
   3 *
   4 * Permission is hereby granted, free of charge, to any person obtaining a
   5 * copy of this software and associated documentation files (the "Software"),
   6 * to deal in the Software without restriction, including without limitation
   7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
   8 * and/or sell copies of the Software, and to permit persons to whom the
   9 * Software is furnished to do so, subject to the following conditions:
  10 *
  11 * The above copyright notice and this permission notice shall be included in
  12 * all copies or substantial portions of the Software.
  13 *
  14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
  18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  20 * OTHER DEALINGS IN THE SOFTWARE.
  21 *
  22 * Authors: AMD
  23 *
  24 */
  25#include "dc_types.h"
  26#include "core_types.h"
  27#include "core_status.h"
  28#include "dc_state.h"
  29#include "dc_state_priv.h"
  30#include "dc_stream_priv.h"
  31#include "dc_plane_priv.h"
  32
  33#include "dm_services.h"
  34#include "resource.h"
  35#include "link_enc_cfg.h"
  36
  37#if defined(CONFIG_DRM_AMD_DC_FP)
  38#include "dml2_0/dml2_wrapper.h"
  39#include "dml2_0/dml2_internal_types.h"
  40#endif
  41
  42#define DC_LOGGER \
  43	dc->ctx->logger
  44#define DC_LOGGER_INIT(logger)
  45
  46/* Private dc_state helper functions */
  47static bool dc_state_track_phantom_stream(struct dc_state *state,
  48		struct dc_stream_state *phantom_stream)
  49{
  50	if (state->phantom_stream_count >= MAX_PHANTOM_PIPES)
  51		return false;
  52
  53	state->phantom_streams[state->phantom_stream_count++] = phantom_stream;
  54
  55	return true;
  56}
  57
  58static bool dc_state_untrack_phantom_stream(struct dc_state *state, struct dc_stream_state *phantom_stream)
  59{
  60	bool res = false;
  61	int i;
  62
  63	/* first find phantom stream in the dc_state */
  64	for (i = 0; i < state->phantom_stream_count; i++) {
  65		if (state->phantom_streams[i] == phantom_stream) {
  66			state->phantom_streams[i] = NULL;
  67			res = true;
  68			break;
  69		}
  70	}
  71
  72	/* failed to find stream in state */
  73	if (!res)
  74		return res;
  75
  76	/* trim back phantom streams */
  77	state->phantom_stream_count--;
  78	for (; i < state->phantom_stream_count; i++)
  79		state->phantom_streams[i] = state->phantom_streams[i + 1];
  80
  81	return res;
  82}
  83
  84static bool dc_state_is_phantom_stream_tracked(struct dc_state *state, struct dc_stream_state *phantom_stream)
  85{
  86	int i;
  87
  88	for (i = 0; i < state->phantom_stream_count; i++) {
  89		if (state->phantom_streams[i] == phantom_stream)
  90			return true;
  91	}
  92
  93	return false;
  94}
  95
  96static bool dc_state_track_phantom_plane(struct dc_state *state,
  97		struct dc_plane_state *phantom_plane)
  98{
  99	if (state->phantom_plane_count >= MAX_PHANTOM_PIPES)
 100		return false;
 101
 102	state->phantom_planes[state->phantom_plane_count++] = phantom_plane;
 103
 104	return true;
 105}
 106
 107static bool dc_state_untrack_phantom_plane(struct dc_state *state, struct dc_plane_state *phantom_plane)
 108{
 109	bool res = false;
 110	int i;
 111
 112	/* first find phantom plane in the dc_state */
 113	for (i = 0; i < state->phantom_plane_count; i++) {
 114		if (state->phantom_planes[i] == phantom_plane) {
 115			state->phantom_planes[i] = NULL;
 116			res = true;
 117			break;
 118		}
 119	}
 120
 121	/* failed to find plane in state */
 122	if (!res)
 123		return res;
 124
 125	/* trim back phantom planes */
 126	state->phantom_plane_count--;
 127	for (; i < state->phantom_plane_count; i++)
 128		state->phantom_planes[i] = state->phantom_planes[i + 1];
 129
 130	return res;
 131}
 132
 133static bool dc_state_is_phantom_plane_tracked(struct dc_state *state, struct dc_plane_state *phantom_plane)
 134{
 135	int i;
 136
 137	for (i = 0; i < state->phantom_plane_count; i++) {
 138		if (state->phantom_planes[i] == phantom_plane)
 139			return true;
 140	}
 141
 142	return false;
 143}
 144
 145static void dc_state_copy_internal(struct dc_state *dst_state, struct dc_state *src_state)
 146{
 147	int i, j;
 148
 149	memcpy(dst_state, src_state, sizeof(struct dc_state));
 150
 151	for (i = 0; i < MAX_PIPES; i++) {
 152		struct pipe_ctx *cur_pipe = &dst_state->res_ctx.pipe_ctx[i];
 153
 154		if (cur_pipe->top_pipe)
 155			cur_pipe->top_pipe =  &dst_state->res_ctx.pipe_ctx[cur_pipe->top_pipe->pipe_idx];
 156
 157		if (cur_pipe->bottom_pipe)
 158			cur_pipe->bottom_pipe = &dst_state->res_ctx.pipe_ctx[cur_pipe->bottom_pipe->pipe_idx];
 159
 160		if (cur_pipe->prev_odm_pipe)
 161			cur_pipe->prev_odm_pipe =  &dst_state->res_ctx.pipe_ctx[cur_pipe->prev_odm_pipe->pipe_idx];
 162
 163		if (cur_pipe->next_odm_pipe)
 164			cur_pipe->next_odm_pipe = &dst_state->res_ctx.pipe_ctx[cur_pipe->next_odm_pipe->pipe_idx];
 165	}
 166
 167	/* retain phantoms */
 168	for (i = 0; i < dst_state->phantom_stream_count; i++)
 169		dc_stream_retain(dst_state->phantom_streams[i]);
 170
 171	for (i = 0; i < dst_state->phantom_plane_count; i++)
 172		dc_plane_state_retain(dst_state->phantom_planes[i]);
 173
 174	/* retain streams and planes */
 175	for (i = 0; i < dst_state->stream_count; i++) {
 176		dc_stream_retain(dst_state->streams[i]);
 177		for (j = 0; j < dst_state->stream_status[i].plane_count; j++)
 178			dc_plane_state_retain(
 179					dst_state->stream_status[i].plane_states[j]);
 180	}
 181
 182}
 183
 184static void init_state(struct dc *dc, struct dc_state *state)
 185{
 186	/* Each context must have their own instance of VBA and in order to
 187	 * initialize and obtain IP and SOC the base DML instance from DC is
 188	 * initially copied into every context
 189	 */
 190	memcpy(&state->bw_ctx.dml, &dc->dml, sizeof(struct display_mode_lib));
 191}
 192
 193/* Public dc_state functions */
 194struct dc_state *dc_state_create(struct dc *dc, struct dc_state_create_params *params)
 195{
 196	struct dc_state *state;
 197
 198	state = kvzalloc(sizeof(struct dc_state), GFP_KERNEL);
 199
 200	if (!state)
 201		return NULL;
 202
 203	init_state(dc, state);
 204	dc_state_construct(dc, state);
 205	state->power_source = params ? params->power_source : DC_POWER_SOURCE_AC;
 206
 207#ifdef CONFIG_DRM_AMD_DC_FP
 208	if (dc->debug.using_dml2) {
 209		if (!dml2_create(dc, &dc->dml2_options, &state->bw_ctx.dml2)) {
 210			dc_state_release(state);
 211			return NULL;
 212		}
 213
 214		if (dc->caps.dcmode_power_limits_present && !dml2_create(dc, &dc->dml2_dc_power_options, &state->bw_ctx.dml2_dc_power_source)) {
 215			dc_state_release(state);
 216			return NULL;
 217		}
 218	}
 219#endif
 220
 221	kref_init(&state->refcount);
 222
 223	return state;
 224}
 225
 226void dc_state_copy(struct dc_state *dst_state, struct dc_state *src_state)
 227{
 228	struct kref refcount = dst_state->refcount;
 229#ifdef CONFIG_DRM_AMD_DC_FP
 230	struct dml2_context *dst_dml2 = dst_state->bw_ctx.dml2;
 231	struct dml2_context *dst_dml2_dc_power_source = dst_state->bw_ctx.dml2_dc_power_source;
 232#endif
 233
 234	dc_state_copy_internal(dst_state, src_state);
 235
 236#ifdef CONFIG_DRM_AMD_DC_FP
 237	dst_state->bw_ctx.dml2 = dst_dml2;
 238	if (src_state->bw_ctx.dml2)
 239		dml2_copy(dst_state->bw_ctx.dml2, src_state->bw_ctx.dml2);
 240
 241	dst_state->bw_ctx.dml2_dc_power_source = dst_dml2_dc_power_source;
 242	if (src_state->bw_ctx.dml2_dc_power_source)
 243		dml2_copy(dst_state->bw_ctx.dml2_dc_power_source, src_state->bw_ctx.dml2_dc_power_source);
 244#endif
 245
 246	/* context refcount should not be overridden */
 247	dst_state->refcount = refcount;
 248}
 249
 250struct dc_state *dc_state_create_copy(struct dc_state *src_state)
 251{
 252	struct dc_state *new_state;
 253
 254	new_state = kvmalloc(sizeof(struct dc_state),
 255			GFP_KERNEL);
 256	if (!new_state)
 257		return NULL;
 258
 259	dc_state_copy_internal(new_state, src_state);
 260
 261#ifdef CONFIG_DRM_AMD_DC_FP
 262	new_state->bw_ctx.dml2 = NULL;
 263	new_state->bw_ctx.dml2_dc_power_source = NULL;
 264
 265	if (src_state->bw_ctx.dml2 &&
 266			!dml2_create_copy(&new_state->bw_ctx.dml2, src_state->bw_ctx.dml2)) {
 267		dc_state_release(new_state);
 268		return NULL;
 269	}
 270
 271	if (src_state->bw_ctx.dml2_dc_power_source &&
 272			!dml2_create_copy(&new_state->bw_ctx.dml2_dc_power_source, src_state->bw_ctx.dml2_dc_power_source)) {
 273		dc_state_release(new_state);
 274		return NULL;
 275	}
 276#endif
 277
 278	kref_init(&new_state->refcount);
 279
 280	return new_state;
 281}
 282
 283void dc_state_copy_current(struct dc *dc, struct dc_state *dst_state)
 284{
 285	dc_state_copy(dst_state, dc->current_state);
 286}
 287
 288struct dc_state *dc_state_create_current_copy(struct dc *dc)
 289{
 290	return dc_state_create_copy(dc->current_state);
 291}
 292
 293void dc_state_construct(struct dc *dc, struct dc_state *state)
 294{
 295	state->clk_mgr = dc->clk_mgr;
 296
 297	/* Initialise DIG link encoder resource tracking variables. */
 298	if (dc->res_pool)
 299		link_enc_cfg_init(dc, state);
 300}
 301
 302void dc_state_destruct(struct dc_state *state)
 303{
 304	int i, j;
 305
 306	for (i = 0; i < state->stream_count; i++) {
 307		for (j = 0; j < state->stream_status[i].plane_count; j++)
 308			dc_plane_state_release(
 309					state->stream_status[i].plane_states[j]);
 310
 311		state->stream_status[i].plane_count = 0;
 312		dc_stream_release(state->streams[i]);
 313		state->streams[i] = NULL;
 314	}
 315	state->stream_count = 0;
 316
 317	/* release tracked phantoms */
 318	for (i = 0; i < state->phantom_stream_count; i++) {
 319		dc_stream_release(state->phantom_streams[i]);
 320		state->phantom_streams[i] = NULL;
 321	}
 322	state->phantom_stream_count = 0;
 323
 324	for (i = 0; i < state->phantom_plane_count; i++) {
 325		dc_plane_state_release(state->phantom_planes[i]);
 326		state->phantom_planes[i] = NULL;
 327	}
 328	state->phantom_plane_count = 0;
 329
 330	state->stream_mask = 0;
 331	memset(&state->res_ctx, 0, sizeof(state->res_ctx));
 332	memset(&state->pp_display_cfg, 0, sizeof(state->pp_display_cfg));
 333	memset(&state->dcn_bw_vars, 0, sizeof(state->dcn_bw_vars));
 334	state->clk_mgr = NULL;
 335	memset(&state->bw_ctx.bw, 0, sizeof(state->bw_ctx.bw));
 336	memset(state->block_sequence, 0, sizeof(state->block_sequence));
 337	state->block_sequence_steps = 0;
 338	memset(state->dc_dmub_cmd, 0, sizeof(state->dc_dmub_cmd));
 339	state->dmub_cmd_count = 0;
 340	memset(&state->perf_params, 0, sizeof(state->perf_params));
 341}
 342
 343void dc_state_retain(struct dc_state *state)
 344{
 345	kref_get(&state->refcount);
 346}
 347
 348static void dc_state_free(struct kref *kref)
 349{
 350	struct dc_state *state = container_of(kref, struct dc_state, refcount);
 351
 352	dc_state_destruct(state);
 353
 354#ifdef CONFIG_DRM_AMD_DC_FP
 355	dml2_destroy(state->bw_ctx.dml2);
 356	state->bw_ctx.dml2 = 0;
 357
 358	dml2_destroy(state->bw_ctx.dml2_dc_power_source);
 359	state->bw_ctx.dml2_dc_power_source = 0;
 360#endif
 361
 362	kvfree(state);
 363}
 364
 365void dc_state_release(struct dc_state *state)
 366{
 367	if (state != NULL)
 368		kref_put(&state->refcount, dc_state_free);
 369}
 370/*
 371 * dc_state_add_stream() - Add a new dc_stream_state to a dc_state.
 372 */
 373enum dc_status dc_state_add_stream(
 374		const struct dc *dc,
 375		struct dc_state *state,
 376		struct dc_stream_state *stream)
 377{
 378	enum dc_status res;
 379
 380	DC_LOGGER_INIT(dc->ctx->logger);
 381
 382	if (state->stream_count >= dc->res_pool->timing_generator_count) {
 383		DC_LOG_WARNING("Max streams reached, can't add stream %p !\n", stream);
 384		return DC_ERROR_UNEXPECTED;
 385	}
 386
 387	state->streams[state->stream_count] = stream;
 388	dc_stream_retain(stream);
 389	state->stream_count++;
 390
 391	res = resource_add_otg_master_for_stream_output(
 392			state, dc->res_pool, stream);
 393	if (res != DC_OK)
 394		DC_LOG_WARNING("Adding stream %p to context failed with err %d!\n", stream, res);
 395
 396	return res;
 397}
 398
 399/*
 400 * dc_state_remove_stream() - Remove a stream from a dc_state.
 401 */
 402enum dc_status dc_state_remove_stream(
 403		const struct dc *dc,
 404		struct dc_state *state,
 405		struct dc_stream_state *stream)
 406{
 407	int i;
 408	struct pipe_ctx *del_pipe = resource_get_otg_master_for_stream(
 409			&state->res_ctx, stream);
 410
 411	if (!del_pipe) {
 412		dm_error("Pipe not found for stream %p !\n", stream);
 413		return DC_ERROR_UNEXPECTED;
 414	}
 415
 416	resource_update_pipes_for_stream_with_slice_count(state,
 417			dc->current_state, dc->res_pool, stream, 1);
 418	resource_remove_otg_master_for_stream_output(
 419			state, dc->res_pool, stream);
 420
 421	for (i = 0; i < state->stream_count; i++)
 422		if (state->streams[i] == stream)
 423			break;
 424
 425	if (state->streams[i] != stream) {
 426		dm_error("Context doesn't have stream %p !\n", stream);
 427		return DC_ERROR_UNEXPECTED;
 428	}
 429
 430	dc_stream_release_3dlut_for_stream(dc, stream);
 431
 432	dc_stream_release(state->streams[i]);
 433	state->stream_count--;
 434
 435	/* Trim back arrays */
 436	for (; i < state->stream_count; i++) {
 437		state->streams[i] = state->streams[i + 1];
 438		state->stream_status[i] = state->stream_status[i + 1];
 439	}
 440
 441	state->streams[state->stream_count] = NULL;
 442	memset(
 443			&state->stream_status[state->stream_count],
 444			0,
 445			sizeof(state->stream_status[0]));
 446
 447	return DC_OK;
 448}
 449
 450static void remove_mpc_combine_for_stream(const struct dc *dc,
 451		struct dc_state *new_ctx,
 452		const struct dc_state *cur_ctx,
 453		struct dc_stream_status *status)
 454{
 455	int i;
 456
 457	for (i = 0; i < status->plane_count; i++)
 458		resource_update_pipes_for_plane_with_slice_count(
 459				new_ctx, cur_ctx, dc->res_pool,
 460				status->plane_states[i], 1);
 461}
 462
 463bool dc_state_add_plane(
 464		const struct dc *dc,
 465		struct dc_stream_state *stream,
 466		struct dc_plane_state *plane_state,
 467		struct dc_state *state)
 468{
 469	struct resource_pool *pool = dc->res_pool;
 470	struct pipe_ctx *otg_master_pipe;
 471	struct dc_stream_status *stream_status = NULL;
 472	bool added = false;
 473	int odm_slice_count;
 474	int i;
 475
 476	stream_status = dc_state_get_stream_status(state, stream);
 477	otg_master_pipe = resource_get_otg_master_for_stream(
 478			&state->res_ctx, stream);
 479	if (stream_status == NULL) {
 480		dm_error("Existing stream not found; failed to attach surface!\n");
 481		goto out;
 482	} else if (stream_status->plane_count == MAX_SURFACES) {
 483		dm_error("Surface: can not attach plane_state %p! Maximum is: %d\n",
 484				plane_state, MAX_SURFACES);
 485		goto out;
 486	} else if (!otg_master_pipe) {
 487		goto out;
 488	}
 489
 490	added = resource_append_dpp_pipes_for_plane_composition(state,
 491			dc->current_state, pool, otg_master_pipe, plane_state);
 492
 493	if (!added) {
 494		/* try to remove MPC combine to free up pipes */
 495		for (i = 0; i < state->stream_count; i++)
 496			remove_mpc_combine_for_stream(dc, state,
 497					dc->current_state,
 498					&state->stream_status[i]);
 499		added = resource_append_dpp_pipes_for_plane_composition(state,
 500					dc->current_state, pool,
 501					otg_master_pipe, plane_state);
 502	}
 503
 504	if (!added) {
 505		/* try to decrease ODM slice count gradually to free up pipes */
 506		odm_slice_count = resource_get_odm_slice_count(otg_master_pipe);
 507		for (i = odm_slice_count - 1; i > 0; i--) {
 508			resource_update_pipes_for_stream_with_slice_count(state,
 509					dc->current_state, dc->res_pool, stream,
 510					i);
 511			added = resource_append_dpp_pipes_for_plane_composition(
 512					state,
 513					dc->current_state, pool,
 514					otg_master_pipe, plane_state);
 515			if (added)
 516				break;
 517		}
 518	}
 519
 520	if (added) {
 521		stream_status->plane_states[stream_status->plane_count] =
 522				plane_state;
 523		stream_status->plane_count++;
 524		dc_plane_state_retain(plane_state);
 525	}
 526
 527out:
 528	return added;
 529}
 530
 531bool dc_state_remove_plane(
 532		const struct dc *dc,
 533		struct dc_stream_state *stream,
 534		struct dc_plane_state *plane_state,
 535		struct dc_state *state)
 536{
 537	int i;
 538	struct dc_stream_status *stream_status = NULL;
 539	struct resource_pool *pool = dc->res_pool;
 540
 541	if (!plane_state)
 542		return true;
 543
 544	for (i = 0; i < state->stream_count; i++)
 545		if (state->streams[i] == stream) {
 546			stream_status = &state->stream_status[i];
 547			break;
 548		}
 549
 550	if (stream_status == NULL) {
 551		dm_error("Existing stream not found; failed to remove plane.\n");
 552		return false;
 553	}
 554
 555	resource_remove_dpp_pipes_for_plane_composition(
 556			state, pool, plane_state);
 557
 558	for (i = 0; i < stream_status->plane_count; i++) {
 559		if (stream_status->plane_states[i] == plane_state) {
 560			dc_plane_state_release(stream_status->plane_states[i]);
 561			break;
 562		}
 563	}
 564
 565	if (i == stream_status->plane_count) {
 566		dm_error("Existing plane_state not found; failed to detach it!\n");
 567		return false;
 568	}
 569
 570	stream_status->plane_count--;
 571
 572	/* Start at the plane we've just released, and move all the planes one index forward to "trim" the array */
 573	for (; i < stream_status->plane_count; i++)
 574		stream_status->plane_states[i] = stream_status->plane_states[i + 1];
 575
 576	stream_status->plane_states[stream_status->plane_count] = NULL;
 577
 578	return true;
 579}
 580
 581/**
 582 * dc_state_rem_all_planes_for_stream - Remove planes attached to the target stream.
 583 *
 584 * @dc: Current dc state.
 585 * @stream: Target stream, which we want to remove the attached plans.
 586 * @state: context from which the planes are to be removed.
 587 *
 588 * Return:
 589 * Return true if DC was able to remove all planes from the target
 590 * stream, otherwise, return false.
 591 */
 592bool dc_state_rem_all_planes_for_stream(
 593		const struct dc *dc,
 594		struct dc_stream_state *stream,
 595		struct dc_state *state)
 596{
 597	int i, old_plane_count;
 598	struct dc_stream_status *stream_status = NULL;
 599	struct dc_plane_state *del_planes[MAX_SURFACES] = { 0 };
 600
 601	for (i = 0; i < state->stream_count; i++)
 602		if (state->streams[i] == stream) {
 603			stream_status = &state->stream_status[i];
 604			break;
 605		}
 606
 607	if (stream_status == NULL) {
 608		dm_error("Existing stream %p not found!\n", stream);
 609		return false;
 610	}
 611
 612	old_plane_count = stream_status->plane_count;
 613
 614	for (i = 0; i < old_plane_count; i++)
 615		del_planes[i] = stream_status->plane_states[i];
 616
 617	for (i = 0; i < old_plane_count; i++)
 618		if (!dc_state_remove_plane(dc, stream, del_planes[i], state))
 619			return false;
 620
 621	return true;
 622}
 623
 624bool dc_state_add_all_planes_for_stream(
 625		const struct dc *dc,
 626		struct dc_stream_state *stream,
 627		struct dc_plane_state * const *plane_states,
 628		int plane_count,
 629		struct dc_state *state)
 630{
 631	int i;
 632	bool result = true;
 633
 634	for (i = 0; i < plane_count; i++)
 635		if (!dc_state_add_plane(dc, stream, plane_states[i], state)) {
 636			result = false;
 637			break;
 638		}
 639
 640	return result;
 641}
 642
 643/* Private dc_state functions */
 644
 645/**
 646 * dc_state_get_stream_status - Get stream status from given dc state
 647 * @state: DC state to find the stream status in
 648 * @stream: The stream to get the stream status for
 649 *
 650 * The given stream is expected to exist in the given dc state. Otherwise, NULL
 651 * will be returned.
 652 */
 653struct dc_stream_status *dc_state_get_stream_status(
 654		struct dc_state *state,
 655		const struct dc_stream_state *stream)
 656{
 657	uint8_t i;
 658
 659	if (state == NULL)
 660		return NULL;
 661
 662	for (i = 0; i < state->stream_count; i++) {
 663		if (stream == state->streams[i])
 664			return &state->stream_status[i];
 665	}
 666
 667	return NULL;
 668}
 669
 670enum mall_stream_type dc_state_get_pipe_subvp_type(const struct dc_state *state,
 671		const struct pipe_ctx *pipe_ctx)
 672{
 673	return dc_state_get_stream_subvp_type(state, pipe_ctx->stream);
 674}
 675
 676enum mall_stream_type dc_state_get_stream_subvp_type(const struct dc_state *state,
 677		const struct dc_stream_state *stream)
 678{
 679	int i;
 680
 681	enum mall_stream_type type = SUBVP_NONE;
 682
 683	for (i = 0; i < state->stream_count; i++) {
 684		if (state->streams[i] == stream) {
 685			type = state->stream_status[i].mall_stream_config.type;
 686			break;
 687		}
 688	}
 689
 690	return type;
 691}
 692
 693struct dc_stream_state *dc_state_get_paired_subvp_stream(const struct dc_state *state,
 694		const struct dc_stream_state *stream)
 695{
 696	int i;
 697
 698	struct dc_stream_state *paired_stream = NULL;
 699
 700	for (i = 0; i < state->stream_count; i++) {
 701		if (state->streams[i] == stream) {
 702			paired_stream = state->stream_status[i].mall_stream_config.paired_stream;
 703			break;
 704		}
 705	}
 706
 707	return paired_stream;
 708}
 709
 710struct dc_stream_state *dc_state_create_phantom_stream(const struct dc *dc,
 711		struct dc_state *state,
 712		struct dc_stream_state *main_stream)
 713{
 714	struct dc_stream_state *phantom_stream;
 715
 716	DC_LOGGER_INIT(dc->ctx->logger);
 717
 718	phantom_stream = dc_create_stream_for_sink(main_stream->sink);
 719
 720	if (!phantom_stream) {
 721		DC_LOG_ERROR("Failed to allocate phantom stream.\n");
 722		return NULL;
 723	}
 724
 725	/* track phantom stream in dc_state */
 726	dc_state_track_phantom_stream(state, phantom_stream);
 727
 728	phantom_stream->is_phantom = true;
 729	phantom_stream->signal = SIGNAL_TYPE_VIRTUAL;
 730	phantom_stream->dpms_off = true;
 731
 732	return phantom_stream;
 733}
 734
 735void dc_state_release_phantom_stream(const struct dc *dc,
 736		struct dc_state *state,
 737		struct dc_stream_state *phantom_stream)
 738{
 739	DC_LOGGER_INIT(dc->ctx->logger);
 740
 741	if (!dc_state_untrack_phantom_stream(state, phantom_stream)) {
 742		DC_LOG_ERROR("Failed to free phantom stream %p in dc state %p.\n", phantom_stream, state);
 743		return;
 744	}
 745
 746	dc_stream_release(phantom_stream);
 747}
 748
 749struct dc_plane_state *dc_state_create_phantom_plane(const struct dc *dc,
 750		struct dc_state *state,
 751		struct dc_plane_state *main_plane)
 752{
 753	struct dc_plane_state *phantom_plane = dc_create_plane_state(dc);
 754
 755	DC_LOGGER_INIT(dc->ctx->logger);
 756
 757	if (!phantom_plane) {
 758		DC_LOG_ERROR("Failed to allocate phantom plane.\n");
 759		return NULL;
 760	}
 761
 762	/* track phantom inside dc_state */
 763	dc_state_track_phantom_plane(state, phantom_plane);
 764
 765	phantom_plane->is_phantom = true;
 766
 767	return phantom_plane;
 768}
 769
 770void dc_state_release_phantom_plane(const struct dc *dc,
 771		struct dc_state *state,
 772		struct dc_plane_state *phantom_plane)
 773{
 774	DC_LOGGER_INIT(dc->ctx->logger);
 775
 776	if (!dc_state_untrack_phantom_plane(state, phantom_plane)) {
 777		DC_LOG_ERROR("Failed to free phantom plane %p in dc state %p.\n", phantom_plane, state);
 778		return;
 779	}
 780
 781	dc_plane_state_release(phantom_plane);
 782}
 783
 784/* add phantom streams to context and generate correct meta inside dc_state */
 785enum dc_status dc_state_add_phantom_stream(const struct dc *dc,
 786		struct dc_state *state,
 787		struct dc_stream_state *phantom_stream,
 788		struct dc_stream_state *main_stream)
 789{
 790	struct dc_stream_status *main_stream_status;
 791	struct dc_stream_status *phantom_stream_status;
 792	enum dc_status res = dc_state_add_stream(dc, state, phantom_stream);
 793
 794	/* check if stream is tracked */
 795	if (res == DC_OK && !dc_state_is_phantom_stream_tracked(state, phantom_stream)) {
 796		/* stream must be tracked if added to state */
 797		dc_state_track_phantom_stream(state, phantom_stream);
 798	}
 799
 800	/* setup subvp meta */
 801	main_stream_status = dc_state_get_stream_status(state, main_stream);
 802	if (main_stream_status) {
 803		main_stream_status->mall_stream_config.type = SUBVP_MAIN;
 804		main_stream_status->mall_stream_config.paired_stream = phantom_stream;
 805	}
 806
 807	phantom_stream_status = dc_state_get_stream_status(state, phantom_stream);
 808	if (phantom_stream_status) {
 809		phantom_stream_status->mall_stream_config.type = SUBVP_PHANTOM;
 810		phantom_stream_status->mall_stream_config.paired_stream = main_stream;
 811		phantom_stream_status->mall_stream_config.subvp_limit_cursor_size = false;
 812		phantom_stream_status->mall_stream_config.cursor_size_limit_subvp = false;
 813	}
 814
 815	dc_state_set_stream_subvp_cursor_limit(main_stream, state, true);
 816
 817	return res;
 818}
 819
 820enum dc_status dc_state_remove_phantom_stream(const struct dc *dc,
 821		struct dc_state *state,
 822		struct dc_stream_state *phantom_stream)
 823{
 824	struct dc_stream_status *main_stream_status = NULL;
 825	struct dc_stream_status *phantom_stream_status;
 826
 827	/* reset subvp meta */
 828	phantom_stream_status = dc_state_get_stream_status(state, phantom_stream);
 829	if (phantom_stream_status) {
 830		main_stream_status = dc_state_get_stream_status(state, phantom_stream_status->mall_stream_config.paired_stream);
 831		phantom_stream_status->mall_stream_config.type = SUBVP_NONE;
 832		phantom_stream_status->mall_stream_config.paired_stream = NULL;
 833	}
 834
 835	if (main_stream_status) {
 836		main_stream_status->mall_stream_config.type = SUBVP_NONE;
 837		main_stream_status->mall_stream_config.paired_stream = NULL;
 838	}
 839
 840	/* remove stream from state */
 841	return dc_state_remove_stream(dc, state, phantom_stream);
 842}
 843
 844bool dc_state_add_phantom_plane(
 845		const struct dc *dc,
 846		struct dc_stream_state *phantom_stream,
 847		struct dc_plane_state *phantom_plane,
 848		struct dc_state *state)
 849{
 850	bool res = dc_state_add_plane(dc, phantom_stream, phantom_plane, state);
 851
 852	/* check if stream is tracked */
 853	if (res && !dc_state_is_phantom_plane_tracked(state, phantom_plane)) {
 854		/* stream must be tracked if added to state */
 855		dc_state_track_phantom_plane(state, phantom_plane);
 856	}
 857
 858	return res;
 859}
 860
 861bool dc_state_remove_phantom_plane(
 862		const struct dc *dc,
 863		struct dc_stream_state *phantom_stream,
 864		struct dc_plane_state *phantom_plane,
 865		struct dc_state *state)
 866{
 867	return dc_state_remove_plane(dc, phantom_stream, phantom_plane, state);
 868}
 869
 870bool dc_state_rem_all_phantom_planes_for_stream(
 871		const struct dc *dc,
 872		struct dc_stream_state *phantom_stream,
 873		struct dc_state *state,
 874		bool should_release_planes)
 875{
 876	int i, old_plane_count;
 877	struct dc_stream_status *stream_status = NULL;
 878	struct dc_plane_state *del_planes[MAX_SURFACES] = { 0 };
 879
 880	for (i = 0; i < state->stream_count; i++)
 881		if (state->streams[i] == phantom_stream) {
 882			stream_status = &state->stream_status[i];
 883			break;
 884		}
 885
 886	if (stream_status == NULL) {
 887		dm_error("Existing stream %p not found!\n", phantom_stream);
 888		return false;
 889	}
 890
 891	old_plane_count = stream_status->plane_count;
 892
 893	for (i = 0; i < old_plane_count; i++)
 894		del_planes[i] = stream_status->plane_states[i];
 895
 896	for (i = 0; i < old_plane_count; i++) {
 897		if (!dc_state_remove_plane(dc, phantom_stream, del_planes[i], state))
 898			return false;
 899		if (should_release_planes)
 900			dc_state_release_phantom_plane(dc, state, del_planes[i]);
 901	}
 902
 903	return true;
 904}
 905
 906bool dc_state_add_all_phantom_planes_for_stream(
 907		const struct dc *dc,
 908		struct dc_stream_state *phantom_stream,
 909		struct dc_plane_state * const *phantom_planes,
 910		int plane_count,
 911		struct dc_state *state)
 912{
 913	return dc_state_add_all_planes_for_stream(dc, phantom_stream, phantom_planes, plane_count, state);
 914}
 915
 916bool dc_state_remove_phantom_streams_and_planes(
 917	const struct dc *dc,
 918	struct dc_state *state)
 919{
 920	int i;
 921	bool removed_phantom = false;
 922	struct dc_stream_state *phantom_stream = NULL;
 923
 924	for (i = 0; i < dc->res_pool->pipe_count; i++) {
 925		struct pipe_ctx *pipe = &state->res_ctx.pipe_ctx[i];
 926
 927		if (pipe->plane_state && pipe->stream && dc_state_get_pipe_subvp_type(state, pipe) == SUBVP_PHANTOM) {
 928			phantom_stream = pipe->stream;
 929
 930			dc_state_rem_all_phantom_planes_for_stream(dc, phantom_stream, state, false);
 931			dc_state_remove_phantom_stream(dc, state, phantom_stream);
 932			removed_phantom = true;
 933		}
 934	}
 935	return removed_phantom;
 936}
 937
 938void dc_state_release_phantom_streams_and_planes(
 939		const struct dc *dc,
 940		struct dc_state *state)
 941{
 942	unsigned int phantom_count;
 943	struct dc_stream_state *phantom_streams[MAX_PHANTOM_PIPES];
 944	struct dc_plane_state *phantom_planes[MAX_PHANTOM_PIPES];
 945	int i;
 946
 947	phantom_count = state->phantom_stream_count;
 948	memcpy(phantom_streams, state->phantom_streams, sizeof(struct dc_stream_state *) * MAX_PHANTOM_PIPES);
 949	for (i = 0; i < phantom_count; i++)
 950		dc_state_release_phantom_stream(dc, state, phantom_streams[i]);
 951
 952	phantom_count = state->phantom_plane_count;
 953	memcpy(phantom_planes, state->phantom_planes, sizeof(struct dc_plane_state *) * MAX_PHANTOM_PIPES);
 954	for (i = 0; i < phantom_count; i++)
 955		dc_state_release_phantom_plane(dc, state, phantom_planes[i]);
 956}
 957
 958struct dc_stream_state *dc_state_get_stream_from_id(const struct dc_state *state, unsigned int id)
 959{
 960	struct dc_stream_state *stream = NULL;
 961	int i;
 962
 963	for (i = 0; i < state->stream_count; i++) {
 964		if (state->streams[i] && state->streams[i]->stream_id == id) {
 965			stream = state->streams[i];
 966			break;
 967		}
 968	}
 969
 970	return stream;
 971}
 972
 973bool dc_state_is_fams2_in_use(
 974		const struct dc *dc,
 975		const struct dc_state *state)
 976{
 977	bool is_fams2_in_use = false;
 978
 979	if (state)
 980		is_fams2_in_use |= state->bw_ctx.bw.dcn.fams2_global_config.features.bits.enable;
 981
 982	if (dc->current_state)
 983		is_fams2_in_use |= dc->current_state->bw_ctx.bw.dcn.fams2_global_config.features.bits.enable;
 984
 985	return is_fams2_in_use;
 986}
 987
 988void dc_state_set_stream_subvp_cursor_limit(const struct dc_stream_state *stream,
 989		struct dc_state *state,
 990		bool limit)
 991{
 992	struct dc_stream_status *stream_status;
 993
 994	stream_status = dc_state_get_stream_status(state, stream);
 995
 996	if (stream_status) {
 997		stream_status->mall_stream_config.subvp_limit_cursor_size = limit;
 998	}
 999}
1000
1001bool dc_state_get_stream_subvp_cursor_limit(const struct dc_stream_state *stream,
1002		struct dc_state *state)
1003{
1004	bool limit = false;
1005
1006	struct dc_stream_status *stream_status;
1007
1008	stream_status = dc_state_get_stream_status(state, stream);
1009
1010	if (stream_status) {
1011		limit = stream_status->mall_stream_config.subvp_limit_cursor_size;
1012	}
1013
1014	return limit;
1015}
1016
1017void dc_state_set_stream_cursor_subvp_limit(const struct dc_stream_state *stream,
1018		struct dc_state *state,
1019		bool limit)
1020{
1021	struct dc_stream_status *stream_status;
1022
1023	stream_status = dc_state_get_stream_status(state, stream);
1024
1025	if (stream_status) {
1026		stream_status->mall_stream_config.cursor_size_limit_subvp = limit;
1027	}
1028}
1029
1030bool dc_state_get_stream_cursor_subvp_limit(const struct dc_stream_state *stream,
1031		struct dc_state *state)
1032{
1033	bool limit = false;
1034
1035	struct dc_stream_status *stream_status;
1036
1037	stream_status = dc_state_get_stream_status(state, stream);
1038
1039	if (stream_status) {
1040		limit = stream_status->mall_stream_config.cursor_size_limit_subvp;
1041	}
1042
1043	return limit;
1044}
1045
1046bool dc_state_can_clear_stream_cursor_subvp_limit(const struct dc_stream_state *stream,
1047		struct dc_state *state)
1048{
1049	bool can_clear_limit = false;
1050
1051	struct dc_stream_status *stream_status;
1052
1053	stream_status = dc_state_get_stream_status(state, stream);
1054
1055	if (stream_status) {
1056		can_clear_limit = dc_state_get_stream_cursor_subvp_limit(stream, state) &&
1057				(stream_status->mall_stream_config.type == SUBVP_PHANTOM ||
1058				stream->hw_cursor_req ||
1059				!stream_status->mall_stream_config.subvp_limit_cursor_size ||
1060				!stream->cursor_position.enable ||
1061				dc_stream_check_cursor_attributes(stream, state, &stream->cursor_attributes));
1062	}
1063
1064	return can_clear_limit;
1065}
1066
1067bool dc_state_is_subvp_in_use(struct dc_state *state)
1068{
1069	uint32_t i;
1070
1071	for (i = 0; i < state->stream_count; i++) {
1072		if (dc_state_get_stream_subvp_type(state, state->streams[i]) != SUBVP_NONE)
1073			return true;
1074	}
1075
1076	return false;
1077}
~/ Read-only file preview.