File Index
Files and directories
Sign in
FILE

dc.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/amd/display/dc/core/dc.c C
   1/*
   2 * Copyright 2015 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 "dm_services.h"
  26
  27#include "amdgpu.h"
  28
  29#include "dc.h"
  30
  31#include "core_status.h"
  32#include "core_types.h"
  33#include "hw_sequencer.h"
  34#include "dce/dce_hwseq.h"
  35
  36#include "resource.h"
  37#include "dc_state.h"
  38#include "dc_state_priv.h"
  39#include "dc_plane.h"
  40#include "dc_plane_priv.h"
  41#include "dc_stream_priv.h"
  42
  43#include "gpio_service_interface.h"
  44#include "clk_mgr.h"
  45#include "clock_source.h"
  46#include "dc_bios_types.h"
  47
  48#include "bios_parser_interface.h"
  49#include "bios/bios_parser_helper.h"
  50#include "include/irq_service_interface.h"
  51#include "transform.h"
  52#include "dmcu.h"
  53#include "dpp.h"
  54#include "timing_generator.h"
  55#include "abm.h"
  56#include "virtual/virtual_link_encoder.h"
  57#include "hubp.h"
  58
  59#include "link_hwss.h"
  60#include "link_encoder.h"
  61#include "link_enc_cfg.h"
  62
  63#include "link_service.h"
  64#include "dm_helpers.h"
  65#include "mem_input.h"
  66
  67#include "dc_dmub_srv.h"
  68
  69#include "dsc.h"
  70
  71#include "vm_helper.h"
  72
  73#include "dce/dce_i2c.h"
  74
  75#include "dmub/dmub_srv.h"
  76
  77#include "dce/dmub_psr.h"
  78
  79#include "dce/dmub_hw_lock_mgr.h"
  80
  81#include "dc_trace.h"
  82
  83#include "hw_sequencer_private.h"
  84
  85#if defined(CONFIG_DRM_AMD_DC_FP)
  86#include "dml2_0/dml2_internal_types.h"
  87#include "soc_and_ip_translator.h"
  88#endif
  89
  90#include "dce/dmub_outbox.h"
  91
  92#define CTX \
  93	dc->ctx
  94
  95#define DC_LOGGER \
  96	dc->ctx->logger
  97
  98static const char DC_BUILD_ID[] = "production-build";
  99
 100/**
 101 * DOC: Overview
 102 *
 103 * DC is the OS-agnostic component of the amdgpu DC driver.
 104 *
 105 * DC maintains and validates a set of structs representing the state of the
 106 * driver and writes that state to AMD hardware
 107 *
 108 * Main DC HW structs:
 109 *
 110 * struct dc - The central struct.  One per driver.  Created on driver load,
 111 * destroyed on driver unload.
 112 *
 113 * struct dc_context - One per driver.
 114 * Used as a backpointer by most other structs in dc.
 115 *
 116 * struct dc_link - One per connector (the physical DP, HDMI, miniDP, or eDP
 117 * plugpoints).  Created on driver load, destroyed on driver unload.
 118 *
 119 * struct dc_sink - One per display.  Created on boot or hotplug.
 120 * Destroyed on shutdown or hotunplug.  A dc_link can have a local sink
 121 * (the display directly attached).  It may also have one or more remote
 122 * sinks (in the Multi-Stream Transport case)
 123 *
 124 * struct resource_pool - One per driver.  Represents the hw blocks not in the
 125 * main pipeline.  Not directly accessible by dm.
 126 *
 127 * Main dc state structs:
 128 *
 129 * These structs can be created and destroyed as needed.  There is a full set of
 130 * these structs in dc->current_state representing the currently programmed state.
 131 *
 132 * struct dc_state - The global DC state to track global state information,
 133 * such as bandwidth values.
 134 *
 135 * struct dc_stream_state - Represents the hw configuration for the pipeline from
 136 * a framebuffer to a display.  Maps one-to-one with dc_sink.
 137 *
 138 * struct dc_plane_state - Represents a framebuffer.  Each stream has at least one,
 139 * and may have more in the Multi-Plane Overlay case.
 140 *
 141 * struct resource_context - Represents the programmable state of everything in
 142 * the resource_pool.  Not directly accessible by dm.
 143 *
 144 * struct pipe_ctx - A member of struct resource_context.  Represents the
 145 * internal hardware pipeline components.  Each dc_plane_state has either
 146 * one or two (in the pipe-split case).
 147 */
 148
 149/* Private functions */
 150
 151static inline void elevate_update_type(
 152		struct surface_update_descriptor *descriptor,
 153		enum surface_update_type new_type,
 154		enum dc_lock_descriptor new_locks
 155)
 156{
 157	if (new_type > descriptor->update_type)
 158		descriptor->update_type = new_type;
 159
 160	descriptor->lock_descriptor |= new_locks;
 161}
 162
 163static void destroy_links(struct dc *dc)
 164{
 165	uint32_t i;
 166
 167	for (i = 0; i < dc->link_count; i++) {
 168		if (NULL != dc->links[i])
 169			dc->link_srv->destroy_link(&dc->links[i]);
 170	}
 171}
 172
 173static uint32_t get_num_of_internal_disp(struct dc_link **links, uint32_t num_links)
 174{
 175	int i;
 176	uint32_t count = 0;
 177
 178	for (i = 0; i < num_links; i++) {
 179		if (links[i]->connector_signal == SIGNAL_TYPE_EDP ||
 180				links[i]->is_internal_display)
 181			count++;
 182	}
 183
 184	return count;
 185}
 186
 187static int get_seamless_boot_stream_count(struct dc_state *ctx)
 188{
 189	uint8_t i;
 190	uint8_t seamless_boot_stream_count = 0;
 191
 192	for (i = 0; i < ctx->stream_count; i++)
 193		if (ctx->streams[i]->apply_seamless_boot_optimization)
 194			seamless_boot_stream_count++;
 195
 196	return seamless_boot_stream_count;
 197}
 198
 199static bool create_links(
 200		struct dc *dc,
 201		uint32_t num_virtual_links)
 202{
 203	int i;
 204	int connectors_num;
 205	struct dc_bios *bios = dc->ctx->dc_bios;
 206
 207	dc->link_count = 0;
 208
 209	connectors_num = bios->funcs->get_connectors_number(bios);
 210
 211	DC_LOG_DC("BIOS object table - number of connectors: %d", connectors_num);
 212
 213	if (connectors_num > ENUM_ID_COUNT) {
 214		dm_error(
 215			"DC: Number of connectors %d exceeds maximum of %d!\n",
 216			connectors_num,
 217			ENUM_ID_COUNT);
 218		return false;
 219	}
 220
 221	dm_output_to_console(
 222		"DC: %s: connectors_num: physical:%d, virtual:%d\n",
 223		__func__,
 224		connectors_num,
 225		num_virtual_links);
 226
 227	/* When getting the number of connectors, the VBIOS reports the number of valid indices,
 228	 * but it doesn't say which indices are valid, and not every index has an actual connector.
 229	 * So, if we don't find a connector on an index, that is not an error.
 230	 *
 231	 * - There is no guarantee that the first N indices will be valid
 232	 * - VBIOS may report a higher amount of valid indices than there are actual connectors
 233	 * - Some VBIOS have valid configurations for more connectors than there actually are
 234	 *   on the card. This may be because the manufacturer used the same VBIOS for different
 235	 *   variants of the same card.
 236	 */
 237	for (i = 0; dc->link_count < connectors_num && i < MAX_LINKS; i++) {
 238		struct graphics_object_id connector_id = bios->funcs->get_connector_id(bios, i);
 239		struct link_init_data link_init_params = {0};
 240		struct dc_link *link;
 241
 242		if (connector_id.id == CONNECTOR_ID_UNKNOWN)
 243			continue;
 244
 245		DC_LOG_DC("BIOS object table - printing link object info for connector number: %d, link_index: %d", i, dc->link_count);
 246
 247		link_init_params.ctx = dc->ctx;
 248		/* next BIOS object table connector */
 249		link_init_params.connector_index = i;
 250		link_init_params.link_index = dc->link_count;
 251		link_init_params.dc = dc;
 252		link = dc->link_srv->create_link(&link_init_params);
 253
 254		if (link) {
 255			dc->links[dc->link_count] = link;
 256			link->dc = dc;
 257			++dc->link_count;
 258		}
 259	}
 260
 261	DC_LOG_DC("BIOS object table - end");
 262
 263	/* Create a link for each usb4 dpia port */
 264	dc->lowest_dpia_link_index = MAX_LINKS;
 265	for (i = 0; i < dc->res_pool->usb4_dpia_count; i++) {
 266		struct link_init_data link_init_params = {0};
 267		struct dc_link *link;
 268
 269		link_init_params.ctx = dc->ctx;
 270		link_init_params.connector_index = i;
 271		link_init_params.link_index = dc->link_count;
 272		link_init_params.dc = dc;
 273		link_init_params.is_dpia_link = true;
 274
 275		link = dc->link_srv->create_link(&link_init_params);
 276		if (link) {
 277			if (dc->lowest_dpia_link_index > dc->link_count)
 278				dc->lowest_dpia_link_index = dc->link_count;
 279
 280			dc->links[dc->link_count] = link;
 281			link->dc = dc;
 282			++dc->link_count;
 283		}
 284	}
 285
 286	for (i = 0; i < num_virtual_links; i++) {
 287		struct dc_link *link = kzalloc(sizeof(*link), GFP_KERNEL);
 288		struct encoder_init_data enc_init = {0};
 289
 290		if (link == NULL) {
 291			BREAK_TO_DEBUGGER();
 292			goto failed_alloc;
 293		}
 294
 295		link->link_index = dc->link_count;
 296		dc->links[dc->link_count] = link;
 297		dc->link_count++;
 298
 299		link->ctx = dc->ctx;
 300		link->dc = dc;
 301		link->connector_signal = SIGNAL_TYPE_VIRTUAL;
 302		link->link_id.type = OBJECT_TYPE_CONNECTOR;
 303		link->link_id.id = CONNECTOR_ID_VIRTUAL;
 304		link->link_id.enum_id = ENUM_ID_1;
 305		link->psr_settings.psr_version = DC_PSR_VERSION_UNSUPPORTED;
 306		link->replay_settings.config.replay_version = DC_REPLAY_VERSION_UNSUPPORTED;
 307		link->link_enc = kzalloc(sizeof(*link->link_enc), GFP_KERNEL);
 308
 309		if (!link->link_enc) {
 310			BREAK_TO_DEBUGGER();
 311			goto failed_alloc;
 312		}
 313
 314		link->link_status.dpcd_caps = &link->dpcd_caps;
 315
 316		enc_init.ctx = dc->ctx;
 317		enc_init.channel = CHANNEL_ID_UNKNOWN;
 318		enc_init.hpd_source = HPD_SOURCEID_UNKNOWN;
 319		enc_init.transmitter = TRANSMITTER_UNKNOWN;
 320		enc_init.connector = link->link_id;
 321		enc_init.encoder.type = OBJECT_TYPE_ENCODER;
 322		enc_init.encoder.id = ENCODER_ID_INTERNAL_VIRTUAL;
 323		enc_init.encoder.enum_id = ENUM_ID_1;
 324		virtual_link_encoder_construct(link->link_enc, &enc_init);
 325	}
 326
 327	dc->caps.num_of_internal_disp = get_num_of_internal_disp(dc->links, dc->link_count);
 328
 329	return true;
 330
 331failed_alloc:
 332	return false;
 333}
 334
 335/* Create additional DIG link encoder objects if fewer than the platform
 336 * supports were created during link construction. This can happen if the
 337 * number of physical connectors is less than the number of DIGs.
 338 */
 339static bool create_link_encoders(struct dc *dc)
 340{
 341	bool res = true;
 342	unsigned int num_usb4_dpia = dc->res_pool->res_cap->num_usb4_dpia;
 343	unsigned int num_dig_link_enc = dc->res_pool->res_cap->num_dig_link_enc;
 344	int i;
 345
 346	/* A platform without USB4 DPIA endpoints has a fixed mapping between DIG
 347	 * link encoders and physical display endpoints and does not require
 348	 * additional link encoder objects.
 349	 */
 350	if (num_usb4_dpia == 0)
 351		return res;
 352
 353	/* Create as many link encoder objects as the platform supports. DPIA
 354	 * endpoints can be programmably mapped to any DIG.
 355	 */
 356	if (num_dig_link_enc > dc->res_pool->dig_link_enc_count) {
 357		for (i = 0; i < num_dig_link_enc; i++) {
 358			struct link_encoder *link_enc = dc->res_pool->link_encoders[i];
 359
 360			if (!link_enc && dc->res_pool->funcs->link_enc_create_minimal) {
 361				link_enc = dc->res_pool->funcs->link_enc_create_minimal(dc->ctx,
 362						(enum engine_id)(ENGINE_ID_DIGA + i));
 363				if (link_enc) {
 364					dc->res_pool->link_encoders[i] = link_enc;
 365					dc->res_pool->dig_link_enc_count++;
 366				} else {
 367					res = false;
 368				}
 369			}
 370		}
 371	}
 372
 373	return res;
 374}
 375
 376/* Destroy any additional DIG link encoder objects created by
 377 * create_link_encoders().
 378 * NB: Must only be called after destroy_links().
 379 */
 380static void destroy_link_encoders(struct dc *dc)
 381{
 382	unsigned int num_usb4_dpia;
 383	unsigned int num_dig_link_enc;
 384	int i;
 385
 386	if (!dc->res_pool)
 387		return;
 388
 389	num_usb4_dpia = dc->res_pool->res_cap->num_usb4_dpia;
 390	num_dig_link_enc = dc->res_pool->res_cap->num_dig_link_enc;
 391
 392	/* A platform without USB4 DPIA endpoints has a fixed mapping between DIG
 393	 * link encoders and physical display endpoints and does not require
 394	 * additional link encoder objects.
 395	 */
 396	if (num_usb4_dpia == 0)
 397		return;
 398
 399	for (i = 0; i < num_dig_link_enc; i++) {
 400		struct link_encoder *link_enc = dc->res_pool->link_encoders[i];
 401
 402		if (link_enc) {
 403			link_enc->funcs->destroy(&link_enc);
 404			dc->res_pool->link_encoders[i] = NULL;
 405			dc->res_pool->dig_link_enc_count--;
 406		}
 407	}
 408}
 409
 410static struct dc_perf_trace *dc_perf_trace_create(void)
 411{
 412	return kzalloc(sizeof(struct dc_perf_trace), GFP_KERNEL);
 413}
 414
 415static void dc_perf_trace_destroy(struct dc_perf_trace **perf_trace)
 416{
 417	kfree(*perf_trace);
 418	*perf_trace = NULL;
 419}
 420
 421static bool set_long_vtotal(struct dc *dc, struct dc_stream_state *stream, struct dc_crtc_timing_adjust *adjust)
 422{
 423	if (!dc || !stream || !adjust)
 424		return false;
 425
 426	if (!dc->current_state)
 427		return false;
 428
 429	int i;
 430
 431	for (i = 0; i < MAX_PIPES; i++) {
 432		struct pipe_ctx *pipe = &dc->current_state->res_ctx.pipe_ctx[i];
 433
 434		if (pipe->stream == stream && pipe->stream_res.tg) {
 435			if (dc->hwss.set_long_vtotal)
 436				dc->hwss.set_long_vtotal(&pipe, 1, adjust->v_total_min, adjust->v_total_max);
 437
 438			return true;
 439		}
 440	}
 441
 442	return false;
 443}
 444
 445/**
 446 *  dc_stream_adjust_vmin_vmax - look up pipe context & update parts of DRR
 447 *  @dc:     dc reference
 448 *  @stream: Initial dc stream state
 449 *  @adjust: Updated parameters for vertical_total_min and vertical_total_max
 450 *
 451 *  Looks up the pipe context of dc_stream_state and updates the
 452 *  vertical_total_min and vertical_total_max of the DRR, Dynamic Refresh
 453 *  Rate, which is a power-saving feature that targets reducing panel
 454 *  refresh rate while the screen is static
 455 *
 456 *  Return: %true if the pipe context is found and adjusted;
 457 *          %false if the pipe context is not found.
 458 */
 459bool dc_stream_adjust_vmin_vmax(struct dc *dc,
 460		struct dc_stream_state *stream,
 461		struct dc_crtc_timing_adjust *adjust)
 462{
 463	int i;
 464
 465	/*
 466	 * Don't adjust DRR while there's bandwidth optimizations pending to
 467	 * avoid conflicting with firmware updates.
 468	 */
 469	if (dc->ctx->dce_version > DCE_VERSION_MAX) {
 470		if (dc->optimized_required &&
 471			(stream->adjust.v_total_max != adjust->v_total_max ||
 472			stream->adjust.v_total_min != adjust->v_total_min)) {
 473			stream->adjust.timing_adjust_pending = true;
 474			return false;
 475		}
 476	}
 477
 478	dc_exit_ips_for_hw_access(dc);
 479
 480	stream->adjust.v_total_max = adjust->v_total_max;
 481	stream->adjust.v_total_mid = adjust->v_total_mid;
 482	stream->adjust.v_total_mid_frame_num = adjust->v_total_mid_frame_num;
 483	stream->adjust.v_total_min = adjust->v_total_min;
 484	stream->adjust.allow_otg_v_count_halt = adjust->allow_otg_v_count_halt;
 485
 486	if (dc->caps.max_v_total != 0 &&
 487		(adjust->v_total_max > dc->caps.max_v_total || adjust->v_total_min > dc->caps.max_v_total)) {
 488		stream->adjust.timing_adjust_pending = false;
 489		if (adjust->allow_otg_v_count_halt)
 490			return set_long_vtotal(dc, stream, adjust);
 491		else
 492			return false;
 493	}
 494
 495	for (i = 0; i < MAX_PIPES; i++) {
 496		struct pipe_ctx *pipe = &dc->current_state->res_ctx.pipe_ctx[i];
 497
 498		if (pipe->stream == stream && pipe->stream_res.tg) {
 499			dc->hwss.set_drr(&pipe,
 500					1,
 501					*adjust);
 502			stream->adjust.timing_adjust_pending = false;
 503
 504			if (dc->hwss.notify_cursor_offload_drr_update)
 505				dc->hwss.notify_cursor_offload_drr_update(dc, dc->current_state, stream);
 506
 507			return true;
 508		}
 509	}
 510
 511	return false;
 512}
 513
 514/**
 515 * dc_stream_get_last_used_drr_vtotal - Looks up the pipe context of
 516 * dc_stream_state and gets the last VTOTAL used by DRR (Dynamic Refresh Rate)
 517 *
 518 * @dc: [in] dc reference
 519 * @stream: [in] Initial dc stream state
 520 * @refresh_rate: [in] new refresh_rate
 521 *
 522 * Return: %true if the pipe context is found and there is an associated
 523 *         timing_generator for the DC;
 524 *         %false if the pipe context is not found or there is no
 525 *         timing_generator for the DC.
 526 */
 527bool dc_stream_get_last_used_drr_vtotal(struct dc *dc,
 528		struct dc_stream_state *stream,
 529		uint32_t *refresh_rate)
 530{
 531	bool status = false;
 532
 533	int i = 0;
 534
 535	dc_exit_ips_for_hw_access(dc);
 536
 537	for (i = 0; i < MAX_PIPES; i++) {
 538		struct pipe_ctx *pipe = &dc->current_state->res_ctx.pipe_ctx[i];
 539
 540		if (pipe->stream == stream && pipe->stream_res.tg) {
 541			/* Only execute if a function pointer has been defined for
 542			 * the DC version in question
 543			 */
 544			if (pipe->stream_res.tg->funcs->get_last_used_drr_vtotal) {
 545				pipe->stream_res.tg->funcs->get_last_used_drr_vtotal(pipe->stream_res.tg, refresh_rate);
 546
 547				status = true;
 548
 549				break;
 550			}
 551		}
 552	}
 553
 554	return status;
 555}
 556
 557#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
 558static inline void
 559dc_stream_forward_dmub_crc_window(struct dc_dmub_srv *dmub_srv,
 560		struct rect *rect, struct otg_phy_mux *mux_mapping, bool is_stop)
 561{
 562	union dmub_rb_cmd cmd = {0};
 563
 564	cmd.secure_display.roi_info.phy_id = mux_mapping->phy_output_num;
 565	cmd.secure_display.roi_info.otg_id = mux_mapping->otg_output_num;
 566
 567	if (is_stop) {
 568		cmd.secure_display.header.type = DMUB_CMD__SECURE_DISPLAY;
 569		cmd.secure_display.header.sub_type = DMUB_CMD__SECURE_DISPLAY_CRC_STOP_UPDATE;
 570	} else {
 571		cmd.secure_display.header.type = DMUB_CMD__SECURE_DISPLAY;
 572		cmd.secure_display.header.sub_type = DMUB_CMD__SECURE_DISPLAY_CRC_WIN_NOTIFY;
 573		cmd.secure_display.roi_info.x_start = rect->x;
 574		cmd.secure_display.roi_info.y_start = rect->y;
 575		cmd.secure_display.roi_info.x_end = rect->x + rect->width;
 576		cmd.secure_display.roi_info.y_end = rect->y + rect->height;
 577	}
 578
 579	dc_wake_and_execute_dmub_cmd(dmub_srv->ctx, &cmd, DM_DMUB_WAIT_TYPE_NO_WAIT);
 580}
 581
 582static inline void
 583dc_stream_forward_dmcu_crc_window(struct dmcu *dmcu,
 584		struct rect *rect, struct otg_phy_mux *mux_mapping, bool is_stop)
 585{
 586	if (is_stop)
 587		dmcu->funcs->stop_crc_win_update(dmcu, mux_mapping);
 588	else
 589		dmcu->funcs->forward_crc_window(dmcu, rect, mux_mapping);
 590}
 591
 592bool
 593dc_stream_forward_crc_window(struct dc_stream_state *stream,
 594		struct rect *rect, uint8_t phy_id, bool is_stop)
 595{
 596	struct dmcu *dmcu;
 597	struct dc_dmub_srv *dmub_srv;
 598	struct otg_phy_mux mux_mapping;
 599	struct pipe_ctx *pipe;
 600	int i;
 601	struct dc *dc = stream->ctx->dc;
 602
 603	for (i = 0; i < MAX_PIPES; i++) {
 604		pipe = &dc->current_state->res_ctx.pipe_ctx[i];
 605		if (pipe->stream == stream && !pipe->top_pipe && !pipe->prev_odm_pipe)
 606			break;
 607	}
 608
 609	/* Stream not found */
 610	if (i == MAX_PIPES)
 611		return false;
 612
 613	mux_mapping.phy_output_num = phy_id;
 614	mux_mapping.otg_output_num = pipe->stream_res.tg->inst;
 615
 616	dmcu = dc->res_pool->dmcu;
 617	dmub_srv = dc->ctx->dmub_srv;
 618
 619	/* forward to dmub */
 620	if (dmub_srv)
 621		dc_stream_forward_dmub_crc_window(dmub_srv, rect, &mux_mapping, is_stop);
 622	/* forward to dmcu */
 623	else if (dmcu && dmcu->funcs->is_dmcu_initialized(dmcu))
 624		dc_stream_forward_dmcu_crc_window(dmcu, rect, &mux_mapping, is_stop);
 625	else
 626		return false;
 627
 628	return true;
 629}
 630
 631static void
 632dc_stream_forward_dmub_multiple_crc_window(struct dc_dmub_srv *dmub_srv,
 633		struct crc_window *window, struct otg_phy_mux *mux_mapping, bool stop)
 634{
 635	int i;
 636	union dmub_rb_cmd cmd = {0};
 637
 638	cmd.secure_display.mul_roi_ctl.phy_id = mux_mapping->phy_output_num;
 639	cmd.secure_display.mul_roi_ctl.otg_id = mux_mapping->otg_output_num;
 640
 641	cmd.secure_display.header.type = DMUB_CMD__SECURE_DISPLAY;
 642
 643	if (stop) {
 644		cmd.secure_display.header.sub_type = DMUB_CMD__SECURE_DISPLAY_MULTIPLE_CRC_STOP_UPDATE;
 645	} else {
 646		cmd.secure_display.header.sub_type = DMUB_CMD__SECURE_DISPLAY_MULTIPLE_CRC_WIN_NOTIFY;
 647		for (i = 0; i < MAX_CRC_WINDOW_NUM; i++) {
 648			cmd.secure_display.mul_roi_ctl.roi_ctl[i].x_start = window[i].rect.x;
 649			cmd.secure_display.mul_roi_ctl.roi_ctl[i].y_start = window[i].rect.y;
 650			cmd.secure_display.mul_roi_ctl.roi_ctl[i].x_end = window[i].rect.x + window[i].rect.width;
 651			cmd.secure_display.mul_roi_ctl.roi_ctl[i].y_end = window[i].rect.y + window[i].rect.height;
 652			cmd.secure_display.mul_roi_ctl.roi_ctl[i].enable = window[i].enable;
 653		}
 654	}
 655
 656	dc_wake_and_execute_dmub_cmd(dmub_srv->ctx, &cmd, DM_DMUB_WAIT_TYPE_NO_WAIT);
 657}
 658
 659bool
 660dc_stream_forward_multiple_crc_window(struct dc_stream_state *stream,
 661		struct crc_window *window, uint8_t phy_id, bool stop)
 662{
 663	struct dc_dmub_srv *dmub_srv;
 664	struct otg_phy_mux mux_mapping;
 665	struct pipe_ctx *pipe;
 666	int i;
 667	struct dc *dc = stream->ctx->dc;
 668
 669	for (i = 0; i < MAX_PIPES; i++) {
 670		pipe = &dc->current_state->res_ctx.pipe_ctx[i];
 671		if (pipe->stream == stream && !pipe->top_pipe && !pipe->prev_odm_pipe)
 672			break;
 673	}
 674
 675	/* Stream not found */
 676	if (i == MAX_PIPES)
 677		return false;
 678
 679	mux_mapping.phy_output_num = phy_id;
 680	mux_mapping.otg_output_num = pipe->stream_res.tg->inst;
 681
 682	dmub_srv = dc->ctx->dmub_srv;
 683
 684	/* forward to dmub only. no dmcu support*/
 685	if (dmub_srv)
 686		dc_stream_forward_dmub_multiple_crc_window(dmub_srv, window, &mux_mapping, stop);
 687	else
 688		return false;
 689
 690	return true;
 691}
 692#endif /* CONFIG_DRM_AMD_SECURE_DISPLAY */
 693
 694/**
 695 * dc_stream_configure_crc() - Configure CRC capture for the given stream.
 696 * @dc: DC Object
 697 * @stream: The stream to configure CRC on.
 698 * @crc_window: CRC window (x/y start/end) information
 699 * @enable: Enable CRC if true, disable otherwise.
 700 * @continuous: Capture CRC on every frame if true. Otherwise, only capture
 701 *              once.
 702 * @idx: Capture CRC on which CRC engine instance
 703 * @reset: Reset CRC engine before the configuration
 704 *
 705 * By default, the entire frame is used to calculate the CRC.
 706 *
 707 * Return: %false if the stream is not found or CRC capture is not supported;
 708 *         %true if the stream has been configured.
 709 */
 710bool dc_stream_configure_crc(struct dc *dc, struct dc_stream_state *stream,
 711			     struct crc_params *crc_window, bool enable, bool continuous,
 712			     uint8_t idx, bool reset)
 713{
 714	struct pipe_ctx *pipe;
 715	struct crc_params param;
 716	struct timing_generator *tg;
 717
 718	pipe = resource_get_otg_master_for_stream(
 719			&dc->current_state->res_ctx, stream);
 720
 721	/* Stream not found */
 722	if (pipe == NULL)
 723		return false;
 724
 725	dc_exit_ips_for_hw_access(dc);
 726
 727	/* By default, capture the full frame */
 728	param.windowa_x_start = 0;
 729	param.windowa_y_start = 0;
 730	param.windowa_x_end = pipe->stream->timing.h_addressable;
 731	param.windowa_y_end = pipe->stream->timing.v_addressable;
 732	param.windowb_x_start = 0;
 733	param.windowb_y_start = 0;
 734	param.windowb_x_end = pipe->stream->timing.h_addressable;
 735	param.windowb_y_end = pipe->stream->timing.v_addressable;
 736
 737	if (crc_window) {
 738		param.windowa_x_start = crc_window->windowa_x_start;
 739		param.windowa_y_start = crc_window->windowa_y_start;
 740		param.windowa_x_end = crc_window->windowa_x_end;
 741		param.windowa_y_end = crc_window->windowa_y_end;
 742		param.windowb_x_start = crc_window->windowb_x_start;
 743		param.windowb_y_start = crc_window->windowb_y_start;
 744		param.windowb_x_end = crc_window->windowb_x_end;
 745		param.windowb_y_end = crc_window->windowb_y_end;
 746	}
 747
 748	param.dsc_mode = pipe->stream->timing.flags.DSC ? 1:0;
 749	param.odm_mode = pipe->next_odm_pipe ? 1:0;
 750
 751	/* Default to the union of both windows */
 752	param.selection = UNION_WINDOW_A_B;
 753	param.continuous_mode = continuous;
 754	param.enable = enable;
 755
 756	param.crc_eng_inst = idx;
 757	param.reset = reset;
 758
 759	tg = pipe->stream_res.tg;
 760
 761	/* Only call if supported */
 762	if (tg->funcs->configure_crc)
 763		return tg->funcs->configure_crc(tg, &param);
 764	DC_LOG_WARNING("CRC capture not supported.");
 765	return false;
 766}
 767
 768/**
 769 * dc_stream_get_crc() - Get CRC values for the given stream.
 770 *
 771 * @dc: DC object.
 772 * @stream: The DC stream state of the stream to get CRCs from.
 773 * @idx: index of crc engine to get CRC from
 774 * @r_cr: CRC value for the red component.
 775 * @g_y:  CRC value for the green component.
 776 * @b_cb: CRC value for the blue component.
 777 *
 778 * dc_stream_configure_crc needs to be called beforehand to enable CRCs.
 779 *
 780 * Return:
 781 * %false if stream is not found, or if CRCs are not enabled.
 782 */
 783bool dc_stream_get_crc(struct dc *dc, struct dc_stream_state *stream, uint8_t idx,
 784		       uint32_t *r_cr, uint32_t *g_y, uint32_t *b_cb)
 785{
 786	int i;
 787	struct pipe_ctx *pipe;
 788	struct timing_generator *tg;
 789
 790	dc_exit_ips_for_hw_access(dc);
 791
 792	for (i = 0; i < MAX_PIPES; i++) {
 793		pipe = &dc->current_state->res_ctx.pipe_ctx[i];
 794		if (pipe->stream == stream)
 795			break;
 796	}
 797	/* Stream not found */
 798	if (i == MAX_PIPES)
 799		return false;
 800
 801	tg = pipe->stream_res.tg;
 802
 803	if (tg->funcs->get_crc)
 804		return tg->funcs->get_crc(tg, idx, r_cr, g_y, b_cb);
 805	DC_LOG_WARNING("CRC capture not supported.");
 806	return false;
 807}
 808
 809void dc_stream_set_dyn_expansion(struct dc *dc, struct dc_stream_state *stream,
 810		enum dc_dynamic_expansion option)
 811{
 812	/* OPP FMT dyn expansion updates*/
 813	int i;
 814	struct pipe_ctx *pipe_ctx;
 815
 816	dc_exit_ips_for_hw_access(dc);
 817
 818	for (i = 0; i < MAX_PIPES; i++) {
 819		if (dc->current_state->res_ctx.pipe_ctx[i].stream
 820				== stream) {
 821			pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i];
 822			pipe_ctx->stream_res.opp->dyn_expansion = option;
 823			pipe_ctx->stream_res.opp->funcs->opp_set_dyn_expansion(
 824					pipe_ctx->stream_res.opp,
 825					COLOR_SPACE_YCBCR601,
 826					stream->timing.display_color_depth,
 827					stream->signal);
 828		}
 829	}
 830}
 831
 832void dc_stream_set_dither_option(struct dc_stream_state *stream,
 833		enum dc_dither_option option)
 834{
 835	struct bit_depth_reduction_params params;
 836	struct dc_link *link = stream->link;
 837	struct pipe_ctx *pipes = NULL;
 838	int i;
 839
 840	for (i = 0; i < MAX_PIPES; i++) {
 841		if (link->dc->current_state->res_ctx.pipe_ctx[i].stream ==
 842				stream) {
 843			pipes = &link->dc->current_state->res_ctx.pipe_ctx[i];
 844			break;
 845		}
 846	}
 847
 848	if (!pipes)
 849		return;
 850	if (option > DITHER_OPTION_MAX)
 851		return;
 852
 853	dc_exit_ips_for_hw_access(stream->ctx->dc);
 854
 855	stream->dither_option = option;
 856
 857	memset(&params, 0, sizeof(params));
 858	resource_build_bit_depth_reduction_params(stream, &params);
 859	stream->bit_depth_params = params;
 860
 861	if (pipes->plane_res.xfm &&
 862	    pipes->plane_res.xfm->funcs->transform_set_pixel_storage_depth) {
 863		pipes->plane_res.xfm->funcs->transform_set_pixel_storage_depth(
 864			pipes->plane_res.xfm,
 865			pipes->plane_res.scl_data.lb_params.depth,
 866			&stream->bit_depth_params);
 867	}
 868
 869	pipes->stream_res.opp->funcs->
 870		opp_program_bit_depth_reduction(pipes->stream_res.opp, &params);
 871}
 872
 873bool dc_stream_set_gamut_remap(struct dc *dc, const struct dc_stream_state *stream)
 874{
 875	int i;
 876	bool ret = false;
 877	struct pipe_ctx *pipes;
 878
 879	dc_exit_ips_for_hw_access(dc);
 880
 881	for (i = 0; i < MAX_PIPES; i++) {
 882		if (dc->current_state->res_ctx.pipe_ctx[i].stream == stream) {
 883			pipes = &dc->current_state->res_ctx.pipe_ctx[i];
 884			dc->hwss.program_gamut_remap(pipes);
 885			ret = true;
 886		}
 887	}
 888
 889	return ret;
 890}
 891
 892bool dc_stream_program_csc_matrix(struct dc *dc, struct dc_stream_state *stream)
 893{
 894	int i;
 895	bool ret = false;
 896	struct pipe_ctx *pipes;
 897
 898	dc_exit_ips_for_hw_access(dc);
 899
 900	for (i = 0; i < MAX_PIPES; i++) {
 901		if (dc->current_state->res_ctx.pipe_ctx[i].stream
 902				== stream) {
 903
 904			pipes = &dc->current_state->res_ctx.pipe_ctx[i];
 905			dc->hwss.program_output_csc(dc,
 906					pipes,
 907					stream->output_color_space,
 908					stream->csc_color_matrix.matrix,
 909					pipes->stream_res.opp->inst);
 910			ret = true;
 911		}
 912	}
 913
 914	return ret;
 915}
 916
 917void dc_stream_set_static_screen_params(struct dc *dc,
 918		struct dc_stream_state **streams,
 919		int num_streams,
 920		const struct dc_static_screen_params *params)
 921{
 922	int i, j;
 923	struct pipe_ctx *pipes_affected[MAX_PIPES];
 924	int num_pipes_affected = 0;
 925
 926	dc_exit_ips_for_hw_access(dc);
 927
 928	for (i = 0; i < num_streams; i++) {
 929		struct dc_stream_state *stream = streams[i];
 930
 931		for (j = 0; j < MAX_PIPES; j++) {
 932			if (dc->current_state->res_ctx.pipe_ctx[j].stream
 933					== stream) {
 934				pipes_affected[num_pipes_affected++] =
 935						&dc->current_state->res_ctx.pipe_ctx[j];
 936			}
 937		}
 938	}
 939
 940	dc->hwss.set_static_screen_control(pipes_affected, num_pipes_affected, params);
 941}
 942
 943static void dc_destruct(struct dc *dc)
 944{
 945	// reset link encoder assignment table on destruct
 946	if (dc->res_pool && dc->res_pool->funcs->link_encs_assign &&
 947			!dc->config.unify_link_enc_assignment)
 948		link_enc_cfg_init(dc, dc->current_state);
 949
 950	if (dc->current_state) {
 951		dc_state_release(dc->current_state);
 952		dc->current_state = NULL;
 953	}
 954
 955	destroy_links(dc);
 956
 957	destroy_link_encoders(dc);
 958
 959	if (dc->clk_mgr) {
 960		dc_destroy_clk_mgr(dc->clk_mgr);
 961		dc->clk_mgr = NULL;
 962	}
 963
 964	dc_destroy_resource_pool(dc);
 965#ifdef CONFIG_DRM_AMD_DC_FP
 966	dc_destroy_soc_and_ip_translator(&dc->soc_and_ip_translator);
 967#endif
 968	if (dc->link_srv)
 969		link_destroy_link_service(&dc->link_srv);
 970
 971	if (dc->ctx) {
 972		if (dc->ctx->gpio_service)
 973			dal_gpio_service_destroy(&dc->ctx->gpio_service);
 974
 975		if (dc->ctx->created_bios)
 976			dal_bios_parser_destroy(&dc->ctx->dc_bios);
 977		kfree(dc->ctx->logger);
 978		dc_perf_trace_destroy(&dc->ctx->perf_trace);
 979
 980		kfree(dc->ctx);
 981		dc->ctx = NULL;
 982	}
 983
 984	kfree(dc->bw_vbios);
 985	dc->bw_vbios = NULL;
 986
 987	kfree(dc->bw_dceip);
 988	dc->bw_dceip = NULL;
 989
 990	kfree(dc->dcn_soc);
 991	dc->dcn_soc = NULL;
 992
 993	kfree(dc->dcn_ip);
 994	dc->dcn_ip = NULL;
 995
 996	kfree(dc->vm_helper);
 997	dc->vm_helper = NULL;
 998
 999}
1000
1001static bool dc_construct_ctx(struct dc *dc,
1002		const struct dc_init_data *init_params)
1003{
1004	struct dc_context *dc_ctx;
1005
1006	dc_ctx = kzalloc(sizeof(*dc_ctx), GFP_KERNEL);
1007	if (!dc_ctx)
1008		return false;
1009
1010	dc_stream_init_rmcm_3dlut(dc);
1011
1012	dc_ctx->cgs_device = init_params->cgs_device;
1013	dc_ctx->driver_context = init_params->driver;
1014	dc_ctx->dc = dc;
1015	dc_ctx->asic_id = init_params->asic_id;
1016	dc_ctx->dc_sink_id_count = 0;
1017	dc_ctx->dc_stream_id_count = 0;
1018	dc_ctx->dce_environment = init_params->dce_environment;
1019	dc_ctx->dcn_reg_offsets = init_params->dcn_reg_offsets;
1020	dc_ctx->nbio_reg_offsets = init_params->nbio_reg_offsets;
1021	dc_ctx->clk_reg_offsets = init_params->clk_reg_offsets;
1022
1023	/* Create logger */
1024	dc_ctx->logger = kmalloc(sizeof(*dc_ctx->logger), GFP_KERNEL);
1025
1026	if (!dc_ctx->logger) {
1027		kfree(dc_ctx);
1028		return false;
1029	}
1030
1031	dc_ctx->logger->dev = adev_to_drm(init_params->driver);
1032	dc->dml.logger = dc_ctx->logger;
1033
1034	dc_ctx->dce_version = resource_parse_asic_id(init_params->asic_id);
1035
1036	dc_ctx->perf_trace = dc_perf_trace_create();
1037	if (!dc_ctx->perf_trace) {
1038		kfree(dc_ctx);
1039		ASSERT_CRITICAL(false);
1040		return false;
1041	}
1042
1043	dc->ctx = dc_ctx;
1044
1045	dc->link_srv = link_create_link_service();
1046	if (!dc->link_srv)
1047		return false;
1048
1049	return true;
1050}
1051
1052static bool dc_construct(struct dc *dc,
1053		const struct dc_init_data *init_params)
1054{
1055	struct dc_context *dc_ctx;
1056	struct bw_calcs_dceip *dc_dceip;
1057	struct bw_calcs_vbios *dc_vbios;
1058	struct dcn_soc_bounding_box *dcn_soc;
1059	struct dcn_ip_params *dcn_ip;
1060
1061	dc->config = init_params->flags;
1062
1063	// Allocate memory for the vm_helper
1064	dc->vm_helper = kzalloc(sizeof(struct vm_helper), GFP_KERNEL);
1065	if (!dc->vm_helper) {
1066		dm_error("%s: failed to create dc->vm_helper\n", __func__);
1067		goto fail;
1068	}
1069
1070	memcpy(&dc->bb_overrides, &init_params->bb_overrides, sizeof(dc->bb_overrides));
1071
1072	dc_dceip = kzalloc(sizeof(*dc_dceip), GFP_KERNEL);
1073	if (!dc_dceip) {
1074		dm_error("%s: failed to create dceip\n", __func__);
1075		goto fail;
1076	}
1077
1078	dc->bw_dceip = dc_dceip;
1079
1080	dc_vbios = kzalloc(sizeof(*dc_vbios), GFP_KERNEL);
1081	if (!dc_vbios) {
1082		dm_error("%s: failed to create vbios\n", __func__);
1083		goto fail;
1084	}
1085
1086	dc->bw_vbios = dc_vbios;
1087	dcn_soc = kzalloc(sizeof(*dcn_soc), GFP_KERNEL);
1088	if (!dcn_soc) {
1089		dm_error("%s: failed to create dcn_soc\n", __func__);
1090		goto fail;
1091	}
1092
1093	dc->dcn_soc = dcn_soc;
1094
1095	dcn_ip = kzalloc(sizeof(*dcn_ip), GFP_KERNEL);
1096	if (!dcn_ip) {
1097		dm_error("%s: failed to create dcn_ip\n", __func__);
1098		goto fail;
1099	}
1100
1101	dc->dcn_ip = dcn_ip;
1102
1103	if (init_params->bb_from_dmub)
1104		dc->dml2_options.bb_from_dmub = init_params->bb_from_dmub;
1105	else
1106		dc->dml2_options.bb_from_dmub = NULL;
1107
1108	if (!dc_construct_ctx(dc, init_params)) {
1109		dm_error("%s: failed to create ctx\n", __func__);
1110		goto fail;
1111	}
1112
1113	dc_ctx = dc->ctx;
1114
1115	/* Resource should construct all asic specific resources.
1116	 * This should be the only place where we need to parse the asic id
1117	 */
1118	if (init_params->vbios_override)
1119		dc_ctx->dc_bios = init_params->vbios_override;
1120	else {
1121		/* Create BIOS parser */
1122		struct bp_init_data bp_init_data;
1123
1124		bp_init_data.ctx = dc_ctx;
1125		bp_init_data.bios = init_params->asic_id.atombios_base_address;
1126
1127		dc_ctx->dc_bios = dal_bios_parser_create(
1128				&bp_init_data, dc_ctx->dce_version);
1129
1130		if (!dc_ctx->dc_bios) {
1131			ASSERT_CRITICAL(false);
1132			goto fail;
1133		}
1134
1135		dc_ctx->created_bios = true;
1136	}
1137
1138	dc->vendor_signature = init_params->vendor_signature;
1139
1140	/* Create GPIO service */
1141	dc_ctx->gpio_service = dal_gpio_service_create(
1142			dc_ctx->dce_version,
1143			dc_ctx->dce_environment,
1144			dc_ctx);
1145
1146	if (!dc_ctx->gpio_service) {
1147		ASSERT_CRITICAL(false);
1148		goto fail;
1149	}
1150
1151	dc->res_pool = dc_create_resource_pool(dc, init_params, dc_ctx->dce_version);
1152	if (!dc->res_pool)
1153		goto fail;
1154
1155	/* set i2c speed if not done by the respective dcnxxx__resource.c */
1156	if (dc->caps.i2c_speed_in_khz_hdcp == 0)
1157		dc->caps.i2c_speed_in_khz_hdcp = dc->caps.i2c_speed_in_khz;
1158	if (dc->check_config.max_optimizable_video_width == 0)
1159		dc->check_config.max_optimizable_video_width = 5120;
1160	dc->clk_mgr = dc_clk_mgr_create(dc->ctx, dc->res_pool->pp_smu, dc->res_pool->dccg);
1161	if (!dc->clk_mgr)
1162		goto fail;
1163#ifdef CONFIG_DRM_AMD_DC_FP
1164	dc->clk_mgr->force_smu_not_present = init_params->force_smu_not_present;
1165
1166	if (dc->res_pool->funcs->update_bw_bounding_box) {
1167		DC_FP_START();
1168		dc->res_pool->funcs->update_bw_bounding_box(dc, dc->clk_mgr->bw_params);
1169		DC_FP_END();
1170	}
1171	dc->soc_and_ip_translator = dc_create_soc_and_ip_translator(dc_ctx->dce_version);
1172	if (!dc->soc_and_ip_translator)
1173		goto fail;
1174#endif
1175
1176	if (!create_links(dc, init_params->num_virtual_links))
1177		goto fail;
1178
1179	/* Create additional DIG link encoder objects if fewer than the platform
1180	 * supports were created during link construction.
1181	 */
1182	if (!create_link_encoders(dc))
1183		goto fail;
1184
1185	/* Creation of current_state must occur after dc->dml
1186	 * is initialized in dc_create_resource_pool because
1187	 * on creation it copies the contents of dc->dml
1188	 */
1189	dc->current_state = dc_state_create(dc, NULL);
1190
1191	if (!dc->current_state) {
1192		dm_error("%s: failed to create validate ctx\n", __func__);
1193		goto fail;
1194	}
1195
1196	return true;
1197
1198fail:
1199	return false;
1200}
1201
1202static void disable_all_writeback_pipes_for_stream(
1203		const struct dc *dc,
1204		struct dc_stream_state *stream,
1205		struct dc_state *context)
1206{
1207	int i;
1208
1209	for (i = 0; i < stream->num_wb_info; i++)
1210		stream->writeback_info[i].wb_enabled = false;
1211}
1212
1213static void apply_ctx_interdependent_lock(struct dc *dc,
1214					  struct dc_state *context,
1215					  struct dc_stream_state *stream,
1216					  bool lock)
1217{
1218	int i;
1219
1220	/* Checks if interdependent update function pointer is NULL or not, takes care of DCE110 case */
1221	if (dc->hwss.interdependent_update_lock)
1222		dc->hwss.interdependent_update_lock(dc, context, lock);
1223	else {
1224		for (i = 0; i < dc->res_pool->pipe_count; i++) {
1225			struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
1226			struct pipe_ctx *old_pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i];
1227
1228			// Copied conditions that were previously in dce110_apply_ctx_for_surface
1229			if (stream == pipe_ctx->stream) {
1230				if (resource_is_pipe_type(pipe_ctx, OPP_HEAD) &&
1231					(pipe_ctx->plane_state || old_pipe_ctx->plane_state))
1232					dc->hwss.pipe_control_lock(dc, pipe_ctx, lock);
1233			}
1234		}
1235	}
1236}
1237
1238static void dc_update_visual_confirm_color(struct dc *dc, struct dc_state *context, struct pipe_ctx *pipe_ctx)
1239{
1240	if (dc->debug.visual_confirm & VISUAL_CONFIRM_EXPLICIT) {
1241		memcpy(&pipe_ctx->visual_confirm_color, &pipe_ctx->plane_state->visual_confirm_color,
1242		sizeof(pipe_ctx->visual_confirm_color));
1243		return;
1244	}
1245
1246	if (dc->ctx->dce_version >= DCN_VERSION_1_0) {
1247		memset(&pipe_ctx->visual_confirm_color, 0, sizeof(struct tg_color));
1248
1249		if (dc->debug.visual_confirm == VISUAL_CONFIRM_HDR)
1250			get_hdr_visual_confirm_color(pipe_ctx, &(pipe_ctx->visual_confirm_color));
1251		else if (dc->debug.visual_confirm == VISUAL_CONFIRM_SURFACE)
1252			get_surface_visual_confirm_color(pipe_ctx, &(pipe_ctx->visual_confirm_color));
1253		else if (dc->debug.visual_confirm == VISUAL_CONFIRM_SWIZZLE)
1254			get_surface_tile_visual_confirm_color(pipe_ctx, &(pipe_ctx->visual_confirm_color));
1255		else if (dc->debug.visual_confirm == VISUAL_CONFIRM_HW_CURSOR)
1256			get_cursor_visual_confirm_color(pipe_ctx, &(pipe_ctx->visual_confirm_color));
1257		else if (dc->debug.visual_confirm == VISUAL_CONFIRM_DCC)
1258			get_dcc_visual_confirm_color(dc, pipe_ctx, &(pipe_ctx->visual_confirm_color));
1259		else {
1260			if (dc->ctx->dce_version < DCN_VERSION_2_0)
1261				color_space_to_black_color(
1262					dc, pipe_ctx->stream->output_color_space, &(pipe_ctx->visual_confirm_color));
1263		}
1264		if (dc->ctx->dce_version >= DCN_VERSION_2_0) {
1265			if (dc->debug.visual_confirm == VISUAL_CONFIRM_MPCTREE)
1266				get_mpctree_visual_confirm_color(pipe_ctx, &(pipe_ctx->visual_confirm_color));
1267			else if (dc->debug.visual_confirm == VISUAL_CONFIRM_SUBVP)
1268				get_subvp_visual_confirm_color(pipe_ctx, &(pipe_ctx->visual_confirm_color));
1269			else if (dc->debug.visual_confirm == VISUAL_CONFIRM_MCLK_SWITCH)
1270				get_mclk_switch_visual_confirm_color(pipe_ctx, &(pipe_ctx->visual_confirm_color));
1271			else if (dc->debug.visual_confirm == VISUAL_CONFIRM_FAMS2)
1272				get_fams2_visual_confirm_color(dc, context, pipe_ctx, &(pipe_ctx->visual_confirm_color));
1273			else if (dc->debug.visual_confirm == VISUAL_CONFIRM_VABC)
1274				get_vabc_visual_confirm_color(pipe_ctx, &(pipe_ctx->visual_confirm_color));
1275		}
1276	}
1277}
1278
1279void dc_get_visual_confirm_for_stream(
1280	struct dc *dc,
1281	struct dc_stream_state *stream_state,
1282	struct tg_color *color)
1283{
1284	struct dc_stream_status *stream_status = dc_stream_get_status(stream_state);
1285	struct pipe_ctx *pipe_ctx;
1286	int i;
1287	struct dc_plane_state *plane_state = NULL;
1288
1289	if (!stream_status)
1290		return;
1291
1292	switch (dc->debug.visual_confirm) {
1293	case VISUAL_CONFIRM_DISABLE:
1294		return;
1295	case VISUAL_CONFIRM_PSR:
1296	case VISUAL_CONFIRM_FAMS:
1297		pipe_ctx = dc_stream_get_pipe_ctx(stream_state);
1298		if (!pipe_ctx)
1299			return;
1300		dc_dmub_srv_get_visual_confirm_color_cmd(dc, pipe_ctx);
1301		memcpy(color, &dc->ctx->dmub_srv->dmub->visual_confirm_color, sizeof(struct tg_color));
1302		return;
1303
1304	default:
1305		/* find plane with highest layer_index */
1306		for (i = 0; i < stream_status->plane_count; i++) {
1307			if (stream_status->plane_states[i]->visible)
1308				plane_state = stream_status->plane_states[i];
1309		}
1310		if (!plane_state)
1311			return;
1312		/* find pipe that contains plane with highest layer index */
1313		for (i = 0; i < MAX_PIPES; i++) {
1314			struct pipe_ctx *pipe = &dc->current_state->res_ctx.pipe_ctx[i];
1315
1316			if (pipe->plane_state == plane_state) {
1317				memcpy(color, &pipe->visual_confirm_color, sizeof(struct tg_color));
1318				return;
1319			}
1320		}
1321	}
1322}
1323
1324static void disable_dangling_plane(struct dc *dc, struct dc_state *context)
1325{
1326	int i, j;
1327	struct dc_state *dangling_context = dc_state_create_current_copy(dc);
1328	struct dc_state *current_ctx;
1329	struct pipe_ctx *pipe;
1330	struct timing_generator *tg;
1331
1332	if (dangling_context == NULL)
1333		return;
1334
1335	for (i = 0; i < dc->res_pool->pipe_count; i++) {
1336		struct dc_stream_state *old_stream =
1337				dc->current_state->res_ctx.pipe_ctx[i].stream;
1338		bool should_disable = true;
1339		bool pipe_split_change = false;
1340
1341		if ((context->res_ctx.pipe_ctx[i].top_pipe) &&
1342			(dc->current_state->res_ctx.pipe_ctx[i].top_pipe))
1343			pipe_split_change = context->res_ctx.pipe_ctx[i].top_pipe->pipe_idx !=
1344				dc->current_state->res_ctx.pipe_ctx[i].top_pipe->pipe_idx;
1345		else
1346			pipe_split_change = context->res_ctx.pipe_ctx[i].top_pipe !=
1347				dc->current_state->res_ctx.pipe_ctx[i].top_pipe;
1348
1349		for (j = 0; j < context->stream_count; j++) {
1350			if (old_stream == context->streams[j]) {
1351				should_disable = false;
1352				break;
1353			}
1354		}
1355		if (!should_disable && pipe_split_change &&
1356				dc->current_state->stream_count != context->stream_count)
1357			should_disable = true;
1358
1359		if (old_stream && !dc->current_state->res_ctx.pipe_ctx[i].top_pipe &&
1360				!dc->current_state->res_ctx.pipe_ctx[i].prev_odm_pipe) {
1361			struct pipe_ctx *old_pipe, *new_pipe;
1362
1363			old_pipe = &dc->current_state->res_ctx.pipe_ctx[i];
1364			new_pipe = &context->res_ctx.pipe_ctx[i];
1365
1366			if (old_pipe->plane_state && !new_pipe->plane_state)
1367				should_disable = true;
1368		}
1369
1370		if (should_disable && old_stream) {
1371			bool is_phantom = dc_state_get_stream_subvp_type(dc->current_state, old_stream) == SUBVP_PHANTOM;
1372			pipe = &dc->current_state->res_ctx.pipe_ctx[i];
1373			tg = pipe->stream_res.tg;
1374			/* When disabling plane for a phantom pipe, we must turn on the
1375			 * phantom OTG so the disable programming gets the double buffer
1376			 * update. Otherwise the pipe will be left in a partially disabled
1377			 * state that can result in underflow or hang when enabling it
1378			 * again for different use.
1379			 */
1380			if (is_phantom) {
1381				if (tg->funcs->enable_crtc) {
1382					if (dc->hwseq->funcs.blank_pixel_data)
1383						dc->hwseq->funcs.blank_pixel_data(dc, pipe, true);
1384					tg->funcs->enable_crtc(tg);
1385				}
1386			}
1387
1388			if (is_phantom)
1389				dc_state_rem_all_phantom_planes_for_stream(dc, old_stream, dangling_context, true);
1390			else
1391				dc_state_rem_all_planes_for_stream(dc, old_stream, dangling_context);
1392			disable_all_writeback_pipes_for_stream(dc, old_stream, dangling_context);
1393
1394			if (pipe->stream && pipe->plane_state) {
1395				if (!dc->debug.using_dml2)
1396					set_p_state_switch_method(dc, context, pipe);
1397				dc_update_visual_confirm_color(dc, context, pipe);
1398			}
1399
1400			if (dc->hwss.apply_ctx_for_surface) {
1401				apply_ctx_interdependent_lock(dc, dc->current_state, old_stream, true);
1402				dc->hwss.apply_ctx_for_surface(dc, old_stream, 0, dangling_context);
1403				apply_ctx_interdependent_lock(dc, dc->current_state, old_stream, false);
1404				dc->hwss.post_unlock_program_front_end(dc, dangling_context);
1405			}
1406
1407			if (dc->res_pool->funcs->prepare_mcache_programming)
1408				dc->res_pool->funcs->prepare_mcache_programming(dc, dangling_context);
1409			if (dc->hwss.program_front_end_for_ctx) {
1410				dc->hwss.interdependent_update_lock(dc, dc->current_state, true);
1411				dc->hwss.program_front_end_for_ctx(dc, dangling_context);
1412				dc->hwss.interdependent_update_lock(dc, dc->current_state, false);
1413				dc->hwss.post_unlock_program_front_end(dc, dangling_context);
1414			}
1415			/* We need to put the phantom OTG back into it's default (disabled) state or we
1416			 * can get corruption when transition from one SubVP config to a different one.
1417			 * The OTG is set to disable on falling edge of VUPDATE so the plane disable
1418			 * will still get it's double buffer update.
1419			 */
1420			if (is_phantom) {
1421				if (tg->funcs->disable_phantom_crtc)
1422					tg->funcs->disable_phantom_crtc(tg);
1423			}
1424		}
1425	}
1426
1427	current_ctx = dc->current_state;
1428	dc->current_state = dangling_context;
1429	dc_state_release(current_ctx);
1430}
1431
1432static void disable_vbios_mode_if_required(
1433		struct dc *dc,
1434		struct dc_state *context)
1435{
1436	unsigned int i, j;
1437
1438	/* check if timing_changed, disable stream*/
1439	for (i = 0; i < dc->res_pool->pipe_count; i++) {
1440		struct dc_stream_state *stream = NULL;
1441		struct dc_link *link = NULL;
1442		struct pipe_ctx *pipe = NULL;
1443
1444		pipe = &context->res_ctx.pipe_ctx[i];
1445		stream = pipe->stream;
1446		if (stream == NULL)
1447			continue;
1448
1449		if (stream->apply_seamless_boot_optimization)
1450			continue;
1451
1452		// only looking for first odm pipe
1453		if (pipe->prev_odm_pipe)
1454			continue;
1455
1456		if (stream->link->local_sink &&
1457			stream->link->local_sink->sink_signal == SIGNAL_TYPE_EDP) {
1458			link = stream->link;
1459		}
1460
1461		if (link != NULL && link->link_enc->funcs->is_dig_enabled(link->link_enc)) {
1462			unsigned int enc_inst, tg_inst = 0;
1463			unsigned int pix_clk_100hz = 0;
1464
1465			enc_inst = link->link_enc->funcs->get_dig_frontend(link->link_enc);
1466			if (enc_inst != ENGINE_ID_UNKNOWN) {
1467				for (j = 0; j < dc->res_pool->stream_enc_count; j++) {
1468					if (dc->res_pool->stream_enc[j]->id == enc_inst) {
1469						tg_inst = dc->res_pool->stream_enc[j]->funcs->dig_source_otg(
1470							dc->res_pool->stream_enc[j]);
1471						break;
1472					}
1473				}
1474
1475				dc->res_pool->dp_clock_source->funcs->get_pixel_clk_frequency_100hz(
1476					dc->res_pool->dp_clock_source,
1477					tg_inst, &pix_clk_100hz);
1478
1479				if (link->link_status.link_active) {
1480					uint32_t requested_pix_clk_100hz =
1481						pipe->stream_res.pix_clk_params.requested_pix_clk_100hz;
1482
1483					if (pix_clk_100hz != requested_pix_clk_100hz) {
1484						dc->link_srv->set_dpms_off(pipe);
1485						pipe->stream->dpms_off = false;
1486					}
1487				}
1488			}
1489		}
1490	}
1491}
1492
1493/* Public functions */
1494
1495struct dc *dc_create(const struct dc_init_data *init_params)
1496{
1497	struct dc *dc = kzalloc(sizeof(*dc), GFP_KERNEL);
1498	unsigned int full_pipe_count;
1499
1500	if (!dc)
1501		return NULL;
1502
1503	if (init_params->dce_environment == DCE_ENV_VIRTUAL_HW) {
1504		dc->caps.linear_pitch_alignment = 64;
1505		if (!dc_construct_ctx(dc, init_params))
1506			goto destruct_dc;
1507	} else {
1508		if (!dc_construct(dc, init_params))
1509			goto destruct_dc;
1510
1511		full_pipe_count = dc->res_pool->pipe_count;
1512		if (dc->res_pool->underlay_pipe_index != NO_UNDERLAY_PIPE)
1513			full_pipe_count--;
1514		dc->caps.max_streams = min(
1515				full_pipe_count,
1516				dc->res_pool->stream_enc_count);
1517
1518		dc->caps.max_links = dc->link_count;
1519		dc->caps.max_audios = dc->res_pool->audio_count;
1520		dc->caps.linear_pitch_alignment = 64;
1521
1522		dc->caps.max_dp_protocol_version = DP_VERSION_1_4;
1523
1524		dc->caps.max_otg_num = dc->res_pool->res_cap->num_timing_generator;
1525
1526		if (dc->res_pool->dmcu != NULL)
1527			dc->versions.dmcu_version = dc->res_pool->dmcu->dmcu_version;
1528	}
1529
1530	dc->dcn_reg_offsets = init_params->dcn_reg_offsets;
1531	dc->nbio_reg_offsets = init_params->nbio_reg_offsets;
1532	dc->clk_reg_offsets = init_params->clk_reg_offsets;
1533
1534	/* Populate versioning information */
1535	dc->versions.dc_ver = DC_VER;
1536
1537	dc->build_id = DC_BUILD_ID;
1538
1539	DC_LOG_DC("Display Core initialized\n");
1540
1541	return dc;
1542
1543destruct_dc:
1544	dc_destruct(dc);
1545	kfree(dc);
1546	return NULL;
1547}
1548
1549static void detect_edp_presence(struct dc *dc)
1550{
1551	struct dc_link *edp_links[MAX_NUM_EDP];
1552	struct dc_link *edp_link = NULL;
1553	enum dc_connection_type type;
1554	int i;
1555	int edp_num;
1556
1557	dc_get_edp_links(dc, edp_links, &edp_num);
1558	if (!edp_num)
1559		return;
1560
1561	for (i = 0; i < edp_num; i++) {
1562		edp_link = edp_links[i];
1563		if (dc->config.edp_not_connected) {
1564			edp_link->edp_sink_present = false;
1565		} else {
1566			dc_link_detect_connection_type(edp_link, &type);
1567			edp_link->edp_sink_present = (type != dc_connection_none);
1568		}
1569	}
1570}
1571
1572void dc_hardware_init(struct dc *dc)
1573{
1574
1575	detect_edp_presence(dc);
1576	if (dc->ctx->dce_environment != DCE_ENV_VIRTUAL_HW)
1577		dc->hwss.init_hw(dc);
1578	dc_dmub_srv_notify_fw_dc_power_state(dc->ctx->dmub_srv, DC_ACPI_CM_POWER_STATE_D0);
1579}
1580
1581void dc_init_callbacks(struct dc *dc,
1582		const struct dc_callback_init *init_params)
1583{
1584	dc->ctx->cp_psp = init_params->cp_psp;
1585}
1586
1587void dc_deinit_callbacks(struct dc *dc)
1588{
1589	memset(&dc->ctx->cp_psp, 0, sizeof(dc->ctx->cp_psp));
1590}
1591
1592void dc_destroy(struct dc **dc)
1593{
1594	dc_destruct(*dc);
1595	kfree(*dc);
1596	*dc = NULL;
1597}
1598
1599static void enable_timing_multisync(
1600		struct dc *dc,
1601		struct dc_state *ctx)
1602{
1603	int i, multisync_count = 0;
1604	int pipe_count = dc->res_pool->pipe_count;
1605	struct pipe_ctx *multisync_pipes[MAX_PIPES] = { NULL };
1606
1607	for (i = 0; i < pipe_count; i++) {
1608		if (!ctx->res_ctx.pipe_ctx[i].stream ||
1609				!ctx->res_ctx.pipe_ctx[i].stream->triggered_crtc_reset.enabled)
1610			continue;
1611		if (ctx->res_ctx.pipe_ctx[i].stream == ctx->res_ctx.pipe_ctx[i].stream->triggered_crtc_reset.event_source)
1612			continue;
1613		multisync_pipes[multisync_count] = &ctx->res_ctx.pipe_ctx[i];
1614		multisync_count++;
1615	}
1616
1617	if (multisync_count > 0) {
1618		dc->hwss.enable_per_frame_crtc_position_reset(
1619			dc, multisync_count, multisync_pipes);
1620	}
1621}
1622
1623static void program_timing_sync(
1624		struct dc *dc,
1625		struct dc_state *ctx)
1626{
1627	int i, j, k;
1628	int group_index = 0;
1629	int num_group = 0;
1630	int pipe_count = dc->res_pool->pipe_count;
1631	struct pipe_ctx *unsynced_pipes[MAX_PIPES] = { NULL };
1632
1633	for (i = 0; i < pipe_count; i++) {
1634		if (!ctx->res_ctx.pipe_ctx[i].stream
1635				|| ctx->res_ctx.pipe_ctx[i].top_pipe
1636				|| ctx->res_ctx.pipe_ctx[i].prev_odm_pipe)
1637			continue;
1638
1639		unsynced_pipes[i] = &ctx->res_ctx.pipe_ctx[i];
1640	}
1641
1642	for (i = 0; i < pipe_count; i++) {
1643		int group_size = 1;
1644		enum timing_synchronization_type sync_type = NOT_SYNCHRONIZABLE;
1645		struct pipe_ctx *pipe_set[MAX_PIPES];
1646
1647		if (!unsynced_pipes[i])
1648			continue;
1649
1650		pipe_set[0] = unsynced_pipes[i];
1651		unsynced_pipes[i] = NULL;
1652
1653		/* Add tg to the set, search rest of the tg's for ones with
1654		 * same timing, add all tgs with same timing to the group
1655		 */
1656		for (j = i + 1; j < pipe_count; j++) {
1657			if (!unsynced_pipes[j])
1658				continue;
1659			if (sync_type != TIMING_SYNCHRONIZABLE &&
1660				dc->hwss.enable_vblanks_synchronization &&
1661				unsynced_pipes[j]->stream_res.tg->funcs->align_vblanks &&
1662				resource_are_vblanks_synchronizable(
1663					unsynced_pipes[j]->stream,
1664					pipe_set[0]->stream)) {
1665				sync_type = VBLANK_SYNCHRONIZABLE;
1666				pipe_set[group_size] = unsynced_pipes[j];
1667				unsynced_pipes[j] = NULL;
1668				group_size++;
1669			} else
1670			if (sync_type != VBLANK_SYNCHRONIZABLE &&
1671				resource_are_streams_timing_synchronizable(
1672					unsynced_pipes[j]->stream,
1673					pipe_set[0]->stream)) {
1674				sync_type = TIMING_SYNCHRONIZABLE;
1675				pipe_set[group_size] = unsynced_pipes[j];
1676				unsynced_pipes[j] = NULL;
1677				group_size++;
1678			}
1679		}
1680
1681		/* set first unblanked pipe as master */
1682		for (j = 0; j < group_size; j++) {
1683			bool is_blanked;
1684
1685			if (pipe_set[j]->stream_res.opp->funcs->dpg_is_blanked)
1686				is_blanked =
1687					pipe_set[j]->stream_res.opp->funcs->dpg_is_blanked(pipe_set[j]->stream_res.opp);
1688			else
1689				is_blanked =
1690					pipe_set[j]->stream_res.tg->funcs->is_blanked(pipe_set[j]->stream_res.tg);
1691			if (!is_blanked) {
1692				if (j == 0)
1693					break;
1694
1695				swap(pipe_set[0], pipe_set[j]);
1696				break;
1697			}
1698		}
1699
1700		for (k = 0; k < group_size; k++) {
1701			struct dc_stream_status *status = dc_state_get_stream_status(ctx, pipe_set[k]->stream);
1702
1703			if (!status)
1704				continue;
1705
1706			status->timing_sync_info.group_id = num_group;
1707			status->timing_sync_info.group_size = group_size;
1708			if (k == 0)
1709				status->timing_sync_info.master = true;
1710			else
1711				status->timing_sync_info.master = false;
1712
1713		}
1714
1715		/* remove any other unblanked pipes as they have already been synced */
1716		if (dc->config.use_pipe_ctx_sync_logic) {
1717			/* check pipe's syncd to decide which pipe to be removed */
1718			for (j = 1; j < group_size; j++) {
1719				if (pipe_set[j]->pipe_idx_syncd == pipe_set[0]->pipe_idx_syncd) {
1720					group_size--;
1721					pipe_set[j] = pipe_set[group_size];
1722					j--;
1723				} else
1724					/* link slave pipe's syncd with master pipe */
1725					pipe_set[j]->pipe_idx_syncd = pipe_set[0]->pipe_idx_syncd;
1726			}
1727		} else {
1728			/* remove any other pipes by checking valid plane */
1729			for (j = j + 1; j < group_size; j++) {
1730				bool is_blanked;
1731
1732				if (pipe_set[j]->stream_res.opp->funcs->dpg_is_blanked)
1733					is_blanked =
1734						pipe_set[j]->stream_res.opp->funcs->dpg_is_blanked(pipe_set[j]->stream_res.opp);
1735				else
1736					is_blanked =
1737						pipe_set[j]->stream_res.tg->funcs->is_blanked(pipe_set[j]->stream_res.tg);
1738				if (!is_blanked) {
1739					group_size--;
1740					pipe_set[j] = pipe_set[group_size];
1741					j--;
1742				}
1743			}
1744		}
1745
1746		if (group_size > 1) {
1747			if (sync_type == TIMING_SYNCHRONIZABLE) {
1748				dc->hwss.enable_timing_synchronization(
1749					dc, ctx, group_index, group_size, pipe_set);
1750			} else
1751				if (sync_type == VBLANK_SYNCHRONIZABLE) {
1752				dc->hwss.enable_vblanks_synchronization(
1753					dc, group_index, group_size, pipe_set);
1754				}
1755			group_index++;
1756		}
1757		num_group++;
1758	}
1759}
1760
1761static bool streams_changed(struct dc *dc,
1762			    struct dc_stream_state *streams[],
1763			    uint8_t stream_count)
1764{
1765	uint8_t i;
1766
1767	if (stream_count != dc->current_state->stream_count)
1768		return true;
1769
1770	for (i = 0; i < dc->current_state->stream_count; i++) {
1771		if (dc->current_state->streams[i] != streams[i])
1772			return true;
1773		if (!streams[i]->link->link_state_valid)
1774			return true;
1775	}
1776
1777	return false;
1778}
1779
1780bool dc_validate_boot_timing(const struct dc *dc,
1781				const struct dc_sink *sink,
1782				struct dc_crtc_timing *crtc_timing)
1783{
1784	struct timing_generator *tg;
1785	struct stream_encoder *se = NULL;
1786
1787	struct dc_crtc_timing hw_crtc_timing = {0};
1788
1789	struct dc_link *link = sink->link;
1790	unsigned int i, enc_inst, tg_inst = 0;
1791
1792	/* Support seamless boot on EDP displays only */
1793	if (sink->sink_signal != SIGNAL_TYPE_EDP) {
1794		return false;
1795	}
1796
1797	if (dc->debug.force_odm_combine) {
1798		DC_LOG_DEBUG("boot timing validation failed due to force_odm_combine\n");
1799		return false;
1800	}
1801
1802	/* Check for enabled DIG to identify enabled display */
1803	if (!link->link_enc->funcs->is_dig_enabled(link->link_enc)) {
1804		DC_LOG_DEBUG("boot timing validation failed due to disabled DIG\n");
1805		return false;
1806	}
1807
1808	enc_inst = link->link_enc->funcs->get_dig_frontend(link->link_enc);
1809
1810	if (enc_inst == ENGINE_ID_UNKNOWN) {
1811		DC_LOG_DEBUG("boot timing validation failed due to unknown DIG engine ID\n");
1812		return false;
1813	}
1814
1815	for (i = 0; i < dc->res_pool->stream_enc_count; i++) {
1816		if (dc->res_pool->stream_enc[i]->id == enc_inst) {
1817
1818			se = dc->res_pool->stream_enc[i];
1819
1820			tg_inst = dc->res_pool->stream_enc[i]->funcs->dig_source_otg(
1821				dc->res_pool->stream_enc[i]);
1822			break;
1823		}
1824	}
1825
1826	// tg_inst not found
1827	if (i == dc->res_pool->stream_enc_count) {
1828		DC_LOG_DEBUG("boot timing validation failed due to timing generator instance not found\n");
1829		return false;
1830	}
1831
1832	if (tg_inst >= dc->res_pool->timing_generator_count) {
1833		DC_LOG_DEBUG("boot timing validation failed due to invalid timing generator count\n");
1834		return false;
1835	}
1836
1837	if (tg_inst != link->link_enc->preferred_engine) {
1838		DC_LOG_DEBUG("boot timing validation failed due to non-preferred timing generator\n");
1839		return false;
1840	}
1841
1842	tg = dc->res_pool->timing_generators[tg_inst];
1843
1844	if (!tg->funcs->get_hw_timing) {
1845		DC_LOG_DEBUG("boot timing validation failed due to missing get_hw_timing callback\n");
1846		return false;
1847	}
1848
1849	if (!tg->funcs->get_hw_timing(tg, &hw_crtc_timing)) {
1850		DC_LOG_DEBUG("boot timing validation failed due to failed get_hw_timing return\n");
1851		return false;
1852	}
1853
1854	if (crtc_timing->h_total != hw_crtc_timing.h_total) {
1855		DC_LOG_DEBUG("boot timing validation failed due to h_total mismatch\n");
1856		return false;
1857	}
1858
1859	if (crtc_timing->h_border_left != hw_crtc_timing.h_border_left) {
1860		DC_LOG_DEBUG("boot timing validation failed due to h_border_left mismatch\n");
1861		return false;
1862	}
1863
1864	if (crtc_timing->h_addressable != hw_crtc_timing.h_addressable) {
1865		DC_LOG_DEBUG("boot timing validation failed due to h_addressable mismatch\n");
1866		return false;
1867	}
1868
1869	if (crtc_timing->h_border_right != hw_crtc_timing.h_border_right) {
1870		DC_LOG_DEBUG("boot timing validation failed due to h_border_right mismatch\n");
1871		return false;
1872	}
1873
1874	if (crtc_timing->h_front_porch != hw_crtc_timing.h_front_porch) {
1875		DC_LOG_DEBUG("boot timing validation failed due to h_front_porch mismatch\n");
1876		return false;
1877	}
1878
1879	if (crtc_timing->h_sync_width != hw_crtc_timing.h_sync_width) {
1880		DC_LOG_DEBUG("boot timing validation failed due to h_sync_width mismatch\n");
1881		return false;
1882	}
1883
1884	if (crtc_timing->v_total != hw_crtc_timing.v_total) {
1885		DC_LOG_DEBUG("boot timing validation failed due to v_total mismatch\n");
1886		return false;
1887	}
1888
1889	if (crtc_timing->v_border_top != hw_crtc_timing.v_border_top) {
1890		DC_LOG_DEBUG("boot timing validation failed due to v_border_top mismatch\n");
1891		return false;
1892	}
1893
1894	if (crtc_timing->v_addressable != hw_crtc_timing.v_addressable) {
1895		DC_LOG_DEBUG("boot timing validation failed due to v_addressable mismatch\n");
1896		return false;
1897	}
1898
1899	if (crtc_timing->v_border_bottom != hw_crtc_timing.v_border_bottom) {
1900		DC_LOG_DEBUG("boot timing validation failed due to v_border_bottom mismatch\n");
1901		return false;
1902	}
1903
1904	if (crtc_timing->v_front_porch != hw_crtc_timing.v_front_porch) {
1905		DC_LOG_DEBUG("boot timing validation failed due to v_front_porch mismatch\n");
1906		return false;
1907	}
1908
1909	if (crtc_timing->v_sync_width != hw_crtc_timing.v_sync_width) {
1910		DC_LOG_DEBUG("boot timing validation failed due to v_sync_width mismatch\n");
1911		return false;
1912	}
1913
1914	/* block DSC for now, as VBIOS does not currently support DSC timings */
1915	if (crtc_timing->flags.DSC) {
1916		DC_LOG_DEBUG("boot timing validation failed due to DSC\n");
1917		return false;
1918	}
1919
1920	if (dc_is_dp_signal(link->connector_signal)) {
1921		unsigned int pix_clk_100hz = 0;
1922		uint32_t numOdmPipes = 1;
1923		uint32_t id_src[4] = {0};
1924
1925		dc->res_pool->dp_clock_source->funcs->get_pixel_clk_frequency_100hz(
1926			dc->res_pool->dp_clock_source,
1927			tg_inst, &pix_clk_100hz);
1928
1929		if (tg->funcs->get_optc_source)
1930			tg->funcs->get_optc_source(tg,
1931						&numOdmPipes, &id_src[0], &id_src[1]);
1932
1933		if (numOdmPipes == 2) {
1934			pix_clk_100hz *= 2;
1935		} else if (numOdmPipes == 4) {
1936			pix_clk_100hz *= 4;
1937		} else if (se && se->funcs->get_pixels_per_cycle) {
1938			uint32_t pixels_per_cycle = se->funcs->get_pixels_per_cycle(se);
1939
1940			if (pixels_per_cycle != 1 && !dc->debug.enable_dp_dig_pixel_rate_div_policy) {
1941				DC_LOG_DEBUG("boot timing validation failed due to pixels_per_cycle\n");
1942				return false;
1943			}
1944
1945			pix_clk_100hz *= pixels_per_cycle;
1946		}
1947
1948		// Note: In rare cases, HW pixclk may differ from crtc's pixclk
1949		// slightly due to rounding issues in 10 kHz units.
1950		if (crtc_timing->pix_clk_100hz != pix_clk_100hz) {
1951			DC_LOG_DEBUG("boot timing validation failed due to pix_clk_100hz mismatch\n");
1952			return false;
1953		}
1954
1955		if (!se || !se->funcs->dp_get_pixel_format) {
1956			DC_LOG_DEBUG("boot timing validation failed due to missing dp_get_pixel_format\n");
1957			return false;
1958		}
1959
1960		if (!se->funcs->dp_get_pixel_format(
1961			se,
1962			&hw_crtc_timing.pixel_encoding,
1963			&hw_crtc_timing.display_color_depth)) {
1964			DC_LOG_DEBUG("boot timing validation failed due to dp_get_pixel_format failure\n");
1965			return false;
1966		}
1967
1968		if (hw_crtc_timing.display_color_depth != crtc_timing->display_color_depth) {
1969			DC_LOG_DEBUG("boot timing validation failed due to display_color_depth mismatch\n");
1970			return false;
1971		}
1972
1973		if (hw_crtc_timing.pixel_encoding != crtc_timing->pixel_encoding) {
1974			DC_LOG_DEBUG("boot timing validation failed due to pixel_encoding mismatch\n");
1975			return false;
1976		}
1977	}
1978
1979
1980	if (link->dpcd_caps.dprx_feature.bits.VSC_SDP_COLORIMETRY_SUPPORTED) {
1981		DC_LOG_DEBUG("boot timing validation failed due to VSC SDP colorimetry\n");
1982		return false;
1983	}
1984
1985	if (link->dpcd_caps.channel_coding_cap.bits.DP_128b_132b_SUPPORTED) {
1986		DC_LOG_DEBUG("boot timing validation failed due to DP 128b/132b\n");
1987		return false;
1988	}
1989
1990	if (dc->link_srv->edp_is_ilr_optimization_required(link, crtc_timing)) {
1991		DC_LOG_EVENT_LINK_TRAINING("Seamless boot disabled to optimize eDP link rate\n");
1992		return false;
1993	}
1994
1995	return true;
1996}
1997
1998static inline bool should_update_pipe_for_stream(
1999		struct dc_state *context,
2000		struct pipe_ctx *pipe_ctx,
2001		struct dc_stream_state *stream)
2002{
2003	return (pipe_ctx->stream && pipe_ctx->stream == stream);
2004}
2005
2006static inline bool should_update_pipe_for_plane(
2007		struct dc_state *context,
2008		struct pipe_ctx *pipe_ctx,
2009		struct dc_plane_state *plane_state)
2010{
2011	return (pipe_ctx->plane_state == plane_state);
2012}
2013
2014void dc_enable_stereo(
2015	struct dc *dc,
2016	struct dc_state *context,
2017	struct dc_stream_state *streams[],
2018	uint8_t stream_count)
2019{
2020	int i, j;
2021	struct pipe_ctx *pipe;
2022
2023	dc_exit_ips_for_hw_access(dc);
2024
2025	for (i = 0; i < MAX_PIPES; i++) {
2026		if (context != NULL) {
2027			pipe = &context->res_ctx.pipe_ctx[i];
2028		} else {
2029			context = dc->current_state;
2030			pipe = &dc->current_state->res_ctx.pipe_ctx[i];
2031		}
2032
2033		for (j = 0; pipe && j < stream_count; j++)  {
2034			if (should_update_pipe_for_stream(context, pipe, streams[j]) &&
2035				dc->hwss.setup_stereo)
2036				dc->hwss.setup_stereo(pipe, dc);
2037		}
2038	}
2039}
2040
2041void dc_trigger_sync(struct dc *dc, struct dc_state *context)
2042{
2043	if (context->stream_count > 1 && !dc->debug.disable_timing_sync) {
2044		dc_exit_ips_for_hw_access(dc);
2045
2046		enable_timing_multisync(dc, context);
2047		program_timing_sync(dc, context);
2048	}
2049}
2050
2051static uint8_t get_stream_mask(struct dc *dc, struct dc_state *context)
2052{
2053	int i;
2054	unsigned int stream_mask = 0;
2055
2056	for (i = 0; i < dc->res_pool->pipe_count; i++) {
2057		if (context->res_ctx.pipe_ctx[i].stream)
2058			stream_mask |= 1 << i;
2059	}
2060
2061	return stream_mask;
2062}
2063
2064void dc_z10_restore(const struct dc *dc)
2065{
2066	if (dc->hwss.z10_restore)
2067		dc->hwss.z10_restore(dc);
2068}
2069
2070void dc_z10_save_init(struct dc *dc)
2071{
2072	if (dc->hwss.z10_save_init)
2073		dc->hwss.z10_save_init(dc);
2074}
2075
2076/* Set a pipe unlock order based on the change in DET allocation and stores it in dc scratch memory
2077 * Prevents over allocation of DET during unlock process
2078 * e.g. 2 pipe config with different streams with a max of 20 DET segments
2079 *	Before:								After:
2080 *		- Pipe0: 10 DET segments			- Pipe0: 12 DET segments
2081 *		- Pipe1: 10 DET segments			- Pipe1: 8 DET segments
2082 * If Pipe0 gets updated first, 22 DET segments will be allocated
2083 */
2084static void determine_pipe_unlock_order(struct dc *dc, struct dc_state *context)
2085{
2086	unsigned int i = 0;
2087	struct pipe_ctx *pipe = NULL;
2088	struct timing_generator *tg = NULL;
2089
2090	if (!dc->config.set_pipe_unlock_order)
2091		return;
2092
2093	memset(dc->scratch.pipes_to_unlock_first, 0, sizeof(dc->scratch.pipes_to_unlock_first));
2094	for (i = 0; i < dc->res_pool->pipe_count; i++) {
2095		pipe = &context->res_ctx.pipe_ctx[i];
2096		tg = pipe->stream_res.tg;
2097
2098		if (!resource_is_pipe_type(pipe, OTG_MASTER) ||
2099				!tg->funcs->is_tg_enabled(tg) ||
2100				dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_PHANTOM) {
2101			continue;
2102		}
2103
2104		if (resource_calculate_det_for_stream(context, pipe) <
2105				resource_calculate_det_for_stream(dc->current_state, &dc->current_state->res_ctx.pipe_ctx[i])) {
2106			dc->scratch.pipes_to_unlock_first[i] = true;
2107		}
2108	}
2109}
2110
2111/**
2112 * dc_commit_state_no_check - Apply context to the hardware
2113 *
2114 * @dc: DC object with the current status to be updated
2115 * @context: New state that will become the current status at the end of this function
2116 *
2117 * Applies given context to the hardware and copy it into current context.
2118 * It's up to the user to release the src context afterwards.
2119 *
2120 * Return: an enum dc_status result code for the operation
2121 */
2122static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *context)
2123{
2124	struct dc_bios *dcb = dc->ctx->dc_bios;
2125	enum dc_status result = DC_ERROR_UNEXPECTED;
2126	struct pipe_ctx *pipe;
2127	int i, k, l;
2128	struct dc_stream_state *dc_streams[MAX_STREAMS] = {0};
2129	struct dc_state *old_state;
2130	bool subvp_prev_use = false;
2131
2132	dc_z10_restore(dc);
2133	dc_allow_idle_optimizations(dc, false);
2134
2135	for (i = 0; i < dc->res_pool->pipe_count; i++) {
2136		struct pipe_ctx *old_pipe = &dc->current_state->res_ctx.pipe_ctx[i];
2137
2138		/* Check old context for SubVP */
2139		subvp_prev_use |= (dc_state_get_pipe_subvp_type(dc->current_state, old_pipe) == SUBVP_PHANTOM);
2140		if (subvp_prev_use)
2141			break;
2142	}
2143
2144	for (i = 0; i < context->stream_count; i++)
2145		dc_streams[i] =  context->streams[i];
2146
2147	if (!dcb->funcs->is_accelerated_mode(dcb)) {
2148		disable_vbios_mode_if_required(dc, context);
2149		dc->hwss.enable_accelerated_mode(dc, context);
2150	} else if (get_seamless_boot_stream_count(dc->current_state) > 0) {
2151		/* If the previous Stream still retains the apply seamless boot flag,
2152		 * it means the OS has not actually performed a flip yet.
2153		 * At this point, if we receive dc_commit_streams again, we should
2154		 * once more check whether the actual HW timing matches what the OS
2155		 * has provided
2156		 */
2157		disable_vbios_mode_if_required(dc, context);
2158	}
2159
2160	if (dc->hwseq->funcs.wait_for_pipe_update_if_needed) {
2161		for (i = 0; i < dc->res_pool->pipe_count; i++) {
2162			pipe = &context->res_ctx.pipe_ctx[i];
2163			//Only delay otg master for a given config
2164			if (resource_is_pipe_type(pipe, OTG_MASTER)) {
2165				//dc_commit_state_no_check is always a full update
2166				dc->hwseq->funcs.wait_for_pipe_update_if_needed(dc, pipe, false);
2167				break;
2168			}
2169		}
2170	}
2171
2172	if (context->stream_count > get_seamless_boot_stream_count(context) ||
2173		context->stream_count == 0)
2174		dc->hwss.prepare_bandwidth(dc, context);
2175
2176	/* When SubVP is active, all HW programming must be done while
2177	 * SubVP lock is acquired
2178	 */
2179	if (dc->hwss.subvp_pipe_control_lock)
2180		dc->hwss.subvp_pipe_control_lock(dc, context, true, true, NULL, subvp_prev_use);
2181	if (dc->hwss.dmub_hw_control_lock)
2182		dc->hwss.dmub_hw_control_lock(dc, context, true);
2183
2184	if (dc->hwss.update_dsc_pg)
2185		dc->hwss.update_dsc_pg(dc, context, false);
2186
2187	disable_dangling_plane(dc, context);
2188	/* re-program planes for existing stream, in case we need to
2189	 * free up plane resource for later use
2190	 */
2191	if (dc->hwss.apply_ctx_for_surface) {
2192		for (i = 0; i < context->stream_count; i++) {
2193			if (context->streams[i]->mode_changed)
2194				continue;
2195			apply_ctx_interdependent_lock(dc, context, context->streams[i], true);
2196			dc->hwss.apply_ctx_for_surface(
2197				dc, context->streams[i],
2198				context->stream_status[i].plane_count,
2199				context); /* use new pipe config in new context */
2200			apply_ctx_interdependent_lock(dc, context, context->streams[i], false);
2201			dc->hwss.post_unlock_program_front_end(dc, context);
2202		}
2203	}
2204
2205	/* Program hardware */
2206	for (i = 0; i < dc->res_pool->pipe_count; i++) {
2207		pipe = &context->res_ctx.pipe_ctx[i];
2208		dc->hwss.wait_for_mpcc_disconnect(dc, dc->res_pool, pipe);
2209	}
2210
2211	for (i = 0; i < dc->current_state->stream_count; i++)
2212		dc_dmub_srv_control_cursor_offload(dc, dc->current_state, dc->current_state->streams[i], false);
2213
2214	result = dc->hwss.apply_ctx_to_hw(dc, context);
2215
2216	for (i = 0; i < context->stream_count; i++)
2217		dc_dmub_srv_control_cursor_offload(dc, context, context->streams[i], true);
2218
2219	if (result != DC_OK) {
2220		/* Application of dc_state to hardware stopped. */
2221		dc->current_state->res_ctx.link_enc_cfg_ctx.mode = LINK_ENC_CFG_STEADY;
2222		return result;
2223	}
2224
2225	dc_trigger_sync(dc, context);
2226
2227	/* Full update should unconditionally be triggered when dc_commit_state_no_check is called */
2228	for (i = 0; i < context->stream_count; i++) {
2229		uint32_t prev_dsc_changed = context->streams[i]->update_flags.bits.dsc_changed;
2230
2231		context->streams[i]->update_flags.raw = 0xFFFFFFFF;
2232		context->streams[i]->update_flags.bits.dsc_changed = prev_dsc_changed;
2233	}
2234
2235	determine_pipe_unlock_order(dc, context);
2236	/* Program all planes within new context*/
2237	if (dc->res_pool->funcs->prepare_mcache_programming)
2238		dc->res_pool->funcs->prepare_mcache_programming(dc, context);
2239	if (dc->hwss.program_front_end_for_ctx) {
2240		dc->hwss.interdependent_update_lock(dc, context, true);
2241		dc->hwss.program_front_end_for_ctx(dc, context);
2242
2243		if (dc->hwseq->funcs.set_wait_for_update_needed_for_pipe) {
2244			for (i = 0; i < dc->res_pool->pipe_count; i++) {
2245				pipe = &context->res_ctx.pipe_ctx[i];
2246				dc->hwseq->funcs.set_wait_for_update_needed_for_pipe(dc, pipe);
2247			}
2248		}
2249
2250		dc->hwss.interdependent_update_lock(dc, context, false);
2251		dc->hwss.post_unlock_program_front_end(dc, context);
2252	}
2253
2254	if (dc->hwss.commit_subvp_config)
2255		dc->hwss.commit_subvp_config(dc, context);
2256	if (dc->hwss.subvp_pipe_control_lock)
2257		dc->hwss.subvp_pipe_control_lock(dc, context, false, true, NULL, subvp_prev_use);
2258	if (dc->hwss.dmub_hw_control_lock)
2259		dc->hwss.dmub_hw_control_lock(dc, context, false);
2260
2261	for (i = 0; i < context->stream_count; i++) {
2262		const struct dc_link *link = context->streams[i]->link;
2263
2264		if (!context->streams[i]->mode_changed)
2265			continue;
2266
2267		if (dc->hwss.apply_ctx_for_surface) {
2268			apply_ctx_interdependent_lock(dc, context, context->streams[i], true);
2269			dc->hwss.apply_ctx_for_surface(
2270					dc, context->streams[i],
2271					context->stream_status[i].plane_count,
2272					context);
2273			apply_ctx_interdependent_lock(dc, context, context->streams[i], false);
2274			dc->hwss.post_unlock_program_front_end(dc, context);
2275		}
2276
2277		/*
2278		 * enable stereo
2279		 * TODO rework dc_enable_stereo call to work with validation sets?
2280		 */
2281		for (k = 0; k < MAX_PIPES; k++) {
2282			pipe = &context->res_ctx.pipe_ctx[k];
2283
2284			for (l = 0 ; pipe && l < context->stream_count; l++)  {
2285				if (context->streams[l] &&
2286					context->streams[l] == pipe->stream &&
2287					dc->hwss.setup_stereo)
2288					dc->hwss.setup_stereo(pipe, dc);
2289			}
2290		}
2291
2292		CONN_MSG_MODE(link, "{%dx%d, %dx%d@%dKhz}",
2293				context->streams[i]->timing.h_addressable,
2294				context->streams[i]->timing.v_addressable,
2295				context->streams[i]->timing.h_total,
2296				context->streams[i]->timing.v_total,
2297				context->streams[i]->timing.pix_clk_100hz / 10);
2298	}
2299
2300	dc_enable_stereo(dc, context, dc_streams, context->stream_count);
2301
2302	if (get_seamless_boot_stream_count(context) == 0 ||
2303		context->stream_count == 0) {
2304		/* Must wait for no flips to be pending before doing optimize bw */
2305		hwss_wait_for_no_pipes_pending(dc, context);
2306		/*
2307		 * optimized dispclk depends on ODM setup. Need to wait for ODM
2308		 * update pending complete before optimizing bandwidth.
2309		 */
2310		hwss_wait_for_odm_update_pending_complete(dc, context);
2311		/* pplib is notified if disp_num changed */
2312		dc->hwss.optimize_bandwidth(dc, context);
2313		/* Need to do otg sync again as otg could be out of sync due to otg
2314		 * workaround applied during clock update
2315		 */
2316		dc_trigger_sync(dc, context);
2317	}
2318
2319	if (dc->hwss.update_dsc_pg)
2320		dc->hwss.update_dsc_pg(dc, context, true);
2321
2322	if (dc->ctx->dce_version >= DCE_VERSION_MAX)
2323		TRACE_DCN_CLOCK_STATE(&context->bw_ctx.bw.dcn.clk);
2324	else
2325		TRACE_DCE_CLOCK_STATE(&context->bw_ctx.bw.dce);
2326
2327	context->stream_mask = get_stream_mask(dc, context);
2328
2329	if (context->stream_mask != dc->current_state->stream_mask)
2330		dc_dmub_srv_notify_stream_mask(dc->ctx->dmub_srv, context->stream_mask);
2331
2332	for (i = 0; i < context->stream_count; i++)
2333		context->streams[i]->mode_changed = false;
2334
2335	/* Clear update flags that were set earlier to avoid redundant programming */
2336	for (i = 0; i < context->stream_count; i++) {
2337		context->streams[i]->update_flags.raw = 0x0;
2338	}
2339
2340	old_state = dc->current_state;
2341	dc->current_state = context;
2342
2343	dc_state_release(old_state);
2344
2345	dc_state_retain(dc->current_state);
2346
2347	return result;
2348}
2349
2350static bool commit_minimal_transition_state(struct dc *dc,
2351		struct dc_state *transition_base_context);
2352
2353/**
2354 * dc_commit_streams - Commit current stream state
2355 *
2356 * @dc: DC object with the commit state to be configured in the hardware
2357 * @params: Parameters for the commit, including the streams to be committed
2358 *
2359 * Function responsible for commit streams change to the hardware.
2360 *
2361 * Return:
2362 * Return DC_OK if everything work as expected, otherwise, return a dc_status
2363 * code.
2364 */
2365enum dc_status dc_commit_streams(struct dc *dc, struct dc_commit_streams_params *params)
2366{
2367	int i, j;
2368	struct dc_state *context;
2369	enum dc_status res = DC_OK;
2370	struct dc_validation_set set[MAX_STREAMS] = {0};
2371	struct pipe_ctx *pipe;
2372	bool handle_exit_odm2to1 = false;
2373
2374	if (!params)
2375		return DC_ERROR_UNEXPECTED;
2376
2377	if (dc->ctx->dce_environment == DCE_ENV_VIRTUAL_HW)
2378		return res;
2379
2380	if (!streams_changed(dc, params->streams, params->stream_count) &&
2381			dc->current_state->power_source == params->power_source)
2382		return res;
2383
2384	dc_exit_ips_for_hw_access(dc);
2385
2386	DC_LOG_DC("%s: %d streams\n", __func__, params->stream_count);
2387
2388	for (i = 0; i < params->stream_count; i++) {
2389		struct dc_stream_state *stream = params->streams[i];
2390		struct dc_stream_status *status = dc_stream_get_status(stream);
2391		struct dc_sink *sink = stream->sink;
2392
2393		/* revalidate streams */
2394		if (!dc_is_virtual_signal(sink->sink_signal)) {
2395			res = dc_validate_stream(dc, stream);
2396			if (res != DC_OK)
2397				return res;
2398		}
2399
2400
2401		dc_stream_log(dc, stream);
2402
2403		set[i].stream = stream;
2404
2405		if (status) {
2406			set[i].plane_count = status->plane_count;
2407			for (j = 0; j < status->plane_count; j++)
2408				set[i].plane_states[j] = status->plane_states[j];
2409		}
2410	}
2411
2412	/* ODM Combine 2:1 power optimization is only applied for single stream
2413	 * scenario, it uses extra pipes than needed to reduce power consumption
2414	 * We need to switch off this feature to make room for new streams.
2415	 */
2416	if (params->stream_count > dc->current_state->stream_count &&
2417			dc->current_state->stream_count == 1) {
2418		for (i = 0; i < dc->res_pool->pipe_count; i++) {
2419			pipe = &dc->current_state->res_ctx.pipe_ctx[i];
2420			if (pipe->next_odm_pipe)
2421				handle_exit_odm2to1 = true;
2422		}
2423	}
2424
2425	if (handle_exit_odm2to1)
2426		res = commit_minimal_transition_state(dc, dc->current_state);
2427
2428	context = dc_state_create_current_copy(dc);
2429	if (!context)
2430		goto context_alloc_fail;
2431
2432	context->power_source = params->power_source;
2433
2434	res = dc_validate_with_context(dc, set, params->stream_count, context, DC_VALIDATE_MODE_AND_PROGRAMMING);
2435
2436	/*
2437	 * Only update link encoder to stream assignment after bandwidth validation passed.
2438	 */
2439	if (res == DC_OK && dc->res_pool->funcs->link_encs_assign && !dc->config.unify_link_enc_assignment)
2440		dc->res_pool->funcs->link_encs_assign(
2441			dc, context, context->streams, context->stream_count);
2442
2443	if (res != DC_OK) {
2444		BREAK_TO_DEBUGGER();
2445		goto fail;
2446	}
2447
2448	/*
2449	 * If not already seamless, make transition seamless by inserting intermediate minimal transition
2450	 */
2451	if (dc->hwss.is_pipe_topology_transition_seamless &&
2452			!dc->hwss.is_pipe_topology_transition_seamless(dc, dc->current_state, context)) {
2453		res = commit_minimal_transition_state(dc, context);
2454		if (res != DC_OK) {
2455			BREAK_TO_DEBUGGER();
2456			goto fail;
2457		}
2458	}
2459
2460	res = dc_commit_state_no_check(dc, context);
2461
2462	for (i = 0; i < params->stream_count; i++) {
2463		for (j = 0; j < context->stream_count; j++) {
2464			if (params->streams[i]->stream_id == context->streams[j]->stream_id)
2465				params->streams[i]->out.otg_offset = context->stream_status[j].primary_otg_inst;
2466
2467			if (dc_is_embedded_signal(params->streams[i]->signal)) {
2468				struct dc_stream_status *status = dc_state_get_stream_status(context, params->streams[i]);
2469
2470				if (!status)
2471					continue;
2472
2473				if (dc->hwss.is_abm_supported)
2474					status->is_abm_supported = dc->hwss.is_abm_supported(dc, context, params->streams[i]);
2475				else
2476					status->is_abm_supported = true;
2477			}
2478		}
2479	}
2480
2481fail:
2482	dc_state_release(context);
2483
2484context_alloc_fail:
2485
2486	DC_LOG_DC("%s Finished.\n", __func__);
2487
2488	return res;
2489}
2490
2491bool dc_acquire_release_mpc_3dlut(
2492		struct dc *dc, bool acquire,
2493		struct dc_stream_state *stream,
2494		struct dc_3dlut **lut,
2495		struct dc_transfer_func **shaper)
2496{
2497	int pipe_idx;
2498	bool ret = false;
2499	bool found_pipe_idx = false;
2500	const struct resource_pool *pool = dc->res_pool;
2501	struct resource_context *res_ctx = &dc->current_state->res_ctx;
2502	int mpcc_id = 0;
2503
2504	if (pool && res_ctx) {
2505		if (acquire) {
2506			/*find pipe idx for the given stream*/
2507			for (pipe_idx = 0; pipe_idx < pool->pipe_count; pipe_idx++) {
2508				if (res_ctx->pipe_ctx[pipe_idx].stream == stream) {
2509					found_pipe_idx = true;
2510					mpcc_id = res_ctx->pipe_ctx[pipe_idx].plane_res.hubp->inst;
2511					break;
2512				}
2513			}
2514		} else
2515			found_pipe_idx = true;/*for release pipe_idx is not required*/
2516
2517		if (found_pipe_idx) {
2518			if (acquire && pool->funcs->acquire_post_bldn_3dlut)
2519				ret = pool->funcs->acquire_post_bldn_3dlut(res_ctx, pool, mpcc_id, lut, shaper);
2520			else if (!acquire && pool->funcs->release_post_bldn_3dlut)
2521				ret = pool->funcs->release_post_bldn_3dlut(res_ctx, pool, lut, shaper);
2522		}
2523	}
2524	return ret;
2525}
2526
2527static bool is_flip_pending_in_pipes(struct dc *dc, struct dc_state *context)
2528{
2529	int i;
2530	struct pipe_ctx *pipe;
2531
2532	for (i = 0; i < MAX_PIPES; i++) {
2533		pipe = &context->res_ctx.pipe_ctx[i];
2534
2535		// Don't check flip pending on phantom pipes
2536		if (!pipe->plane_state || (dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_PHANTOM))
2537			continue;
2538
2539		/* Must set to false to start with, due to OR in update function */
2540		pipe->plane_state->status.is_flip_pending = false;
2541		dc->hwss.update_pending_status(pipe);
2542		if (pipe->plane_state->status.is_flip_pending)
2543			return true;
2544	}
2545	return false;
2546}
2547
2548/* Perform updates here which need to be deferred until next vupdate
2549 *
2550 * i.e. blnd lut, 3dlut, and shaper lut bypass regs are double buffered
2551 * but forcing lut memory to shutdown state is immediate. This causes
2552 * single frame corruption as lut gets disabled mid-frame unless shutdown
2553 * is deferred until after entering bypass.
2554 */
2555static void process_deferred_updates(struct dc *dc)
2556{
2557	int i = 0;
2558
2559	if (dc->debug.enable_mem_low_power.bits.cm) {
2560		ASSERT(dc->dcn_ip->max_num_dpp);
2561		for (i = 0; i < dc->dcn_ip->max_num_dpp; i++)
2562			if (dc->res_pool->dpps[i]->funcs->dpp_deferred_update)
2563				dc->res_pool->dpps[i]->funcs->dpp_deferred_update(dc->res_pool->dpps[i]);
2564	}
2565}
2566
2567void dc_post_update_surfaces_to_stream(struct dc *dc)
2568{
2569	int i;
2570	struct dc_state *context = dc->current_state;
2571
2572	if ((!dc->optimized_required) || get_seamless_boot_stream_count(context) > 0)
2573		return;
2574
2575	post_surface_trace(dc);
2576
2577	/*
2578	 * Only relevant for DCN behavior where we can guarantee the optimization
2579	 * is safe to apply - retain the legacy behavior for DCE.
2580	 */
2581
2582	if (dc->ctx->dce_version < DCE_VERSION_MAX)
2583		TRACE_DCE_CLOCK_STATE(&context->bw_ctx.bw.dce);
2584	else {
2585		TRACE_DCN_CLOCK_STATE(&context->bw_ctx.bw.dcn.clk);
2586
2587		if (is_flip_pending_in_pipes(dc, context))
2588			return;
2589
2590		for (i = 0; i < dc->res_pool->pipe_count; i++)
2591			if (context->res_ctx.pipe_ctx[i].stream == NULL ||
2592					context->res_ctx.pipe_ctx[i].plane_state == NULL) {
2593				context->res_ctx.pipe_ctx[i].pipe_idx = i;
2594				dc->hwss.disable_plane(dc, context, &context->res_ctx.pipe_ctx[i]);
2595			}
2596
2597		process_deferred_updates(dc);
2598
2599		dc->hwss.optimize_bandwidth(dc, context);
2600
2601		if (dc->hwss.update_dsc_pg)
2602			dc->hwss.update_dsc_pg(dc, context, true);
2603	}
2604
2605	dc->optimized_required = false;
2606}
2607
2608bool dc_set_generic_gpio_for_stereo(bool enable,
2609		struct gpio_service *gpio_service)
2610{
2611	enum gpio_result gpio_result = GPIO_RESULT_NON_SPECIFIC_ERROR;
2612	struct gpio_pin_info pin_info;
2613	struct gpio *generic;
2614	struct gpio_generic_mux_config *config = kzalloc(sizeof(struct gpio_generic_mux_config),
2615			   GFP_KERNEL);
2616
2617	if (!config)
2618		return false;
2619	pin_info = dal_gpio_get_generic_pin_info(gpio_service, GPIO_ID_GENERIC, 0);
2620
2621	if (pin_info.mask == 0xFFFFFFFF || pin_info.offset == 0xFFFFFFFF) {
2622		kfree(config);
2623		return false;
2624	} else {
2625		generic = dal_gpio_service_create_generic_mux(
2626			gpio_service,
2627			pin_info.offset,
2628			pin_info.mask);
2629	}
2630
2631	if (!generic) {
2632		kfree(config);
2633		return false;
2634	}
2635
2636	gpio_result = dal_gpio_open(generic, GPIO_MODE_OUTPUT);
2637
2638	config->enable_output_from_mux = enable;
2639	config->mux_select = GPIO_SIGNAL_SOURCE_PASS_THROUGH_STEREO_SYNC;
2640
2641	if (gpio_result == GPIO_RESULT_OK)
2642		gpio_result = dal_mux_setup_config(generic, config);
2643
2644	if (gpio_result == GPIO_RESULT_OK) {
2645		dal_gpio_close(generic);
2646		dal_gpio_destroy_generic_mux(&generic);
2647		kfree(config);
2648		return true;
2649	} else {
2650		dal_gpio_close(generic);
2651		dal_gpio_destroy_generic_mux(&generic);
2652		kfree(config);
2653		return false;
2654	}
2655}
2656
2657static bool is_surface_in_context(
2658		const struct dc_state *context,
2659		const struct dc_plane_state *plane_state)
2660{
2661	int j;
2662
2663	for (j = 0; j < MAX_PIPES; j++) {
2664		const struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j];
2665
2666		if (plane_state == pipe_ctx->plane_state) {
2667			return true;
2668		}
2669	}
2670
2671	return false;
2672}
2673
2674static struct surface_update_descriptor get_plane_info_update_type(const struct dc_surface_update *u)
2675{
2676	union surface_update_flags *update_flags = &u->surface->update_flags;
2677	struct surface_update_descriptor update_type = { UPDATE_TYPE_FAST, LOCK_DESCRIPTOR_NONE };
2678
2679	if (!u->plane_info)
2680		return update_type;
2681
2682	// `plane_info` present means at least `STREAM` lock is required
2683	elevate_update_type(&update_type, UPDATE_TYPE_FAST, LOCK_DESCRIPTOR_STREAM);
2684
2685	if (u->plane_info->color_space != u->surface->color_space) {
2686		update_flags->bits.color_space_change = 1;
2687		elevate_update_type(&update_type, UPDATE_TYPE_MED, LOCK_DESCRIPTOR_STREAM);
2688	}
2689
2690	if (u->plane_info->horizontal_mirror != u->surface->horizontal_mirror) {
2691		update_flags->bits.horizontal_mirror_change = 1;
2692		elevate_update_type(&update_type, UPDATE_TYPE_MED, LOCK_DESCRIPTOR_STREAM);
2693	}
2694
2695	if (u->plane_info->rotation != u->surface->rotation) {
2696		update_flags->bits.rotation_change = 1;
2697		elevate_update_type(&update_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_GLOBAL);
2698	}
2699
2700	if (u->plane_info->format != u->surface->format) {
2701		update_flags->bits.pixel_format_change = 1;
2702		elevate_update_type(&update_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_GLOBAL);
2703	}
2704
2705	if (u->plane_info->stereo_format != u->surface->stereo_format) {
2706		update_flags->bits.stereo_format_change = 1;
2707		elevate_update_type(&update_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_GLOBAL);
2708	}
2709
2710	if (u->plane_info->per_pixel_alpha != u->surface->per_pixel_alpha) {
2711		update_flags->bits.per_pixel_alpha_change = 1;
2712		elevate_update_type(&update_type, UPDATE_TYPE_MED, LOCK_DESCRIPTOR_STREAM);
2713	}
2714
2715	if (u->plane_info->global_alpha_value != u->surface->global_alpha_value) {
2716		update_flags->bits.global_alpha_change = 1;
2717		elevate_update_type(&update_type, UPDATE_TYPE_MED, LOCK_DESCRIPTOR_STREAM);
2718	}
2719
2720	if (u->plane_info->dcc.enable != u->surface->dcc.enable
2721			|| u->plane_info->dcc.dcc_ind_blk != u->surface->dcc.dcc_ind_blk
2722			|| u->plane_info->dcc.meta_pitch != u->surface->dcc.meta_pitch) {
2723		/* During DCC on/off, stutter period is calculated before
2724		 * DCC has fully transitioned. This results in incorrect
2725		 * stutter period calculation. Triggering a full update will
2726		 * recalculate stutter period.
2727		 */
2728		update_flags->bits.dcc_change = 1;
2729		elevate_update_type(&update_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_GLOBAL);
2730	}
2731
2732	if (resource_pixel_format_to_bpp(u->plane_info->format) !=
2733			resource_pixel_format_to_bpp(u->surface->format)) {
2734		/* different bytes per element will require full bandwidth
2735		 * and DML calculation
2736		 */
2737		update_flags->bits.bpp_change = 1;
2738		elevate_update_type(&update_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_GLOBAL);
2739	}
2740
2741	if (u->plane_info->plane_size.surface_pitch != u->surface->plane_size.surface_pitch
2742			|| u->plane_info->plane_size.chroma_pitch != u->surface->plane_size.chroma_pitch) {
2743		update_flags->bits.plane_size_change = 1;
2744		elevate_update_type(&update_type, UPDATE_TYPE_MED, LOCK_DESCRIPTOR_STREAM);
2745	}
2746
2747	const struct dc_tiling_info *tiling = &u->plane_info->tiling_info;
2748
2749	if (memcmp(tiling, &u->surface->tiling_info, sizeof(*tiling)) != 0) {
2750		update_flags->bits.swizzle_change = 1;
2751		elevate_update_type(&update_type, UPDATE_TYPE_MED, LOCK_DESCRIPTOR_STREAM);
2752
2753		switch (tiling->gfxversion) {
2754		case DcGfxVersion9:
2755		case DcGfxVersion10:
2756		case DcGfxVersion11:
2757			if (tiling->gfx9.swizzle != DC_SW_LINEAR) {
2758				update_flags->bits.bandwidth_change = 1;
2759				elevate_update_type(&update_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_GLOBAL);
2760			}
2761			break;
2762		case DcGfxAddr3:
2763			if (tiling->gfx_addr3.swizzle != DC_ADDR3_SW_LINEAR) {
2764				update_flags->bits.bandwidth_change = 1;
2765				elevate_update_type(&update_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_GLOBAL);
2766			}
2767			break;
2768		case DcGfxVersion7:
2769		case DcGfxVersion8:
2770		case DcGfxVersionUnknown:
2771		default:
2772			break;
2773		}
2774	}
2775
2776	/* This should be UPDATE_TYPE_FAST if nothing has changed. */
2777	return update_type;
2778}
2779
2780static struct surface_update_descriptor get_scaling_info_update_type(
2781		const struct dc_check_config *check_config,
2782		const struct dc_surface_update *u)
2783{
2784	union surface_update_flags *update_flags = &u->surface->update_flags;
2785	struct surface_update_descriptor update_type = { UPDATE_TYPE_FAST, LOCK_DESCRIPTOR_NONE };
2786
2787	if (!u->scaling_info)
2788		return update_type;
2789
2790	// `scaling_info` present means at least `STREAM` lock is required
2791	elevate_update_type(&update_type, UPDATE_TYPE_FAST, LOCK_DESCRIPTOR_STREAM);
2792
2793	if (u->scaling_info->src_rect.width != u->surface->src_rect.width
2794			|| u->scaling_info->src_rect.height != u->surface->src_rect.height
2795			|| u->scaling_info->dst_rect.width != u->surface->dst_rect.width
2796			|| u->scaling_info->dst_rect.height != u->surface->dst_rect.height
2797			|| u->scaling_info->clip_rect.width != u->surface->clip_rect.width
2798			|| u->scaling_info->clip_rect.height != u->surface->clip_rect.height
2799			|| u->scaling_info->scaling_quality.integer_scaling !=
2800					u->surface->scaling_quality.integer_scaling) {
2801		update_flags->bits.scaling_change = 1;
2802		elevate_update_type(&update_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_GLOBAL);
2803
2804		if (u->scaling_info->src_rect.width > u->surface->src_rect.width
2805				|| u->scaling_info->src_rect.height > u->surface->src_rect.height)
2806			/* Making src rect bigger requires a bandwidth change */
2807			update_flags->bits.clock_change = 1;
2808
2809		if ((u->scaling_info->dst_rect.width < u->surface->dst_rect.width
2810			|| u->scaling_info->dst_rect.height < u->surface->dst_rect.height)
2811				&& (u->scaling_info->dst_rect.width < u->surface->src_rect.width
2812					|| u->scaling_info->dst_rect.height < u->surface->src_rect.height))
2813			/* Making dst rect smaller requires a bandwidth change */
2814			update_flags->bits.bandwidth_change = 1;
2815
2816		if (u->scaling_info->src_rect.width > check_config->max_optimizable_video_width &&
2817			(u->scaling_info->clip_rect.width > u->surface->clip_rect.width ||
2818			 u->scaling_info->clip_rect.height > u->surface->clip_rect.height))
2819			 /* Changing clip size of a large surface may result in MPC slice count change */
2820			update_flags->bits.bandwidth_change = 1;
2821	}
2822
2823	if (u->scaling_info->src_rect.x != u->surface->src_rect.x
2824			|| u->scaling_info->src_rect.y != u->surface->src_rect.y
2825			|| u->scaling_info->clip_rect.x != u->surface->clip_rect.x
2826			|| u->scaling_info->clip_rect.y != u->surface->clip_rect.y
2827			|| u->scaling_info->dst_rect.x != u->surface->dst_rect.x
2828			|| u->scaling_info->dst_rect.y != u->surface->dst_rect.y) {
2829		elevate_update_type(&update_type, UPDATE_TYPE_MED, LOCK_DESCRIPTOR_STREAM);
2830		update_flags->bits.position_change = 1;
2831	}
2832
2833	return update_type;
2834}
2835
2836static struct surface_update_descriptor det_surface_update(
2837		const struct dc_check_config *check_config,
2838		struct dc_surface_update *u)
2839{
2840	struct surface_update_descriptor overall_type = { UPDATE_TYPE_FAST, LOCK_DESCRIPTOR_NONE };
2841	union surface_update_flags *update_flags = &u->surface->update_flags;
2842
2843	if (u->surface->force_full_update) {
2844		update_flags->raw = 0xFFFFFFFF;
2845		elevate_update_type(&overall_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_GLOBAL);
2846		return overall_type;
2847	}
2848
2849	update_flags->raw = 0; // Reset all flags
2850
2851	struct surface_update_descriptor inner_type = get_plane_info_update_type(u);
2852
2853	elevate_update_type(&overall_type, inner_type.update_type, inner_type.lock_descriptor);
2854
2855	inner_type = get_scaling_info_update_type(check_config, u);
2856	elevate_update_type(&overall_type, inner_type.update_type, inner_type.lock_descriptor);
2857
2858	if (u->flip_addr) {
2859		update_flags->bits.addr_update = 1;
2860		elevate_update_type(&overall_type, UPDATE_TYPE_FAST, LOCK_DESCRIPTOR_STREAM);
2861
2862		if (u->flip_addr->address.tmz_surface != u->surface->address.tmz_surface) {
2863			update_flags->bits.tmz_changed = 1;
2864			elevate_update_type(&overall_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_GLOBAL);
2865		}
2866	}
2867	if (u->in_transfer_func) {
2868		update_flags->bits.in_transfer_func_change = 1;
2869		elevate_update_type(&overall_type, UPDATE_TYPE_MED, LOCK_DESCRIPTOR_STREAM);
2870	}
2871
2872	if (u->input_csc_color_matrix) {
2873		update_flags->bits.input_csc_change = 1;
2874		elevate_update_type(&overall_type, UPDATE_TYPE_FAST, LOCK_DESCRIPTOR_STREAM);
2875	}
2876
2877	if (u->coeff_reduction_factor) {
2878		update_flags->bits.coeff_reduction_change = 1;
2879		elevate_update_type(&overall_type, UPDATE_TYPE_FAST, LOCK_DESCRIPTOR_STREAM);
2880	}
2881
2882	if (u->gamut_remap_matrix) {
2883		update_flags->bits.gamut_remap_change = 1;
2884		elevate_update_type(&overall_type, UPDATE_TYPE_FAST, LOCK_DESCRIPTOR_STREAM);
2885	}
2886
2887	if (u->blend_tf || (u->gamma && dce_use_lut(u->plane_info ? u->plane_info->format : u->surface->format))) {
2888		update_flags->bits.gamma_change = 1;
2889		elevate_update_type(&overall_type, UPDATE_TYPE_FAST, LOCK_DESCRIPTOR_STREAM);
2890	}
2891
2892	if (u->lut3d_func || u->func_shaper) {
2893		update_flags->bits.lut_3d = 1;
2894		elevate_update_type(&overall_type, UPDATE_TYPE_FAST, LOCK_DESCRIPTOR_STREAM);
2895	}
2896
2897	if (u->hdr_mult.value)
2898		if (u->hdr_mult.value != u->surface->hdr_mult.value) {
2899			// TODO: Should be fast?
2900			update_flags->bits.hdr_mult = 1;
2901			elevate_update_type(&overall_type, UPDATE_TYPE_MED, LOCK_DESCRIPTOR_STREAM);
2902		}
2903
2904	if (u->sdr_white_level_nits)
2905		if (u->sdr_white_level_nits != u->surface->sdr_white_level_nits) {
2906			// TODO: Should be fast?
2907			update_flags->bits.sdr_white_level_nits = 1;
2908			elevate_update_type(&overall_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_GLOBAL);
2909		}
2910
2911	if (u->cm2_params) {
2912		if (u->cm2_params->component_settings.shaper_3dlut_setting != u->surface->mcm_shaper_3dlut_setting
2913				|| u->cm2_params->component_settings.lut1d_enable != u->surface->mcm_lut1d_enable
2914				|| u->cm2_params->cm2_luts.lut3d_data.lut3d_src != u->surface->mcm_luts.lut3d_data.lut3d_src) {
2915			update_flags->bits.mcm_transfer_function_enable_change = 1;
2916			elevate_update_type(&overall_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_GLOBAL);
2917		}
2918	}
2919
2920	if (update_flags->bits.lut_3d &&
2921			u->surface->mcm_luts.lut3d_data.lut3d_src != DC_CM2_TRANSFER_FUNC_SOURCE_VIDMEM) {
2922		elevate_update_type(&overall_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_GLOBAL);
2923	}
2924
2925	if (check_config->enable_legacy_fast_update &&
2926			(update_flags->bits.gamma_change ||
2927			update_flags->bits.gamut_remap_change ||
2928			update_flags->bits.input_csc_change ||
2929			update_flags->bits.coeff_reduction_change)) {
2930		elevate_update_type(&overall_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_GLOBAL);
2931	}
2932	return overall_type;
2933}
2934
2935/* May need to flip the desktop plane in cases where MPO plane receives a flip but desktop plane doesn't
2936 * while both planes are flip_immediate
2937 */
2938static void force_immediate_gsl_plane_flip(struct dc *dc, struct dc_surface_update *updates, int surface_count)
2939{
2940	bool has_flip_immediate_plane = false;
2941	int i;
2942
2943	for (i = 0; i < surface_count; i++) {
2944		if (updates[i].surface->flip_immediate) {
2945			has_flip_immediate_plane = true;
2946			break;
2947		}
2948	}
2949
2950	if (has_flip_immediate_plane && surface_count > 1) {
2951		for (i = 0; i < surface_count; i++) {
2952			if (updates[i].surface->flip_immediate)
2953				updates[i].surface->update_flags.bits.addr_update = 1;
2954		}
2955	}
2956}
2957
2958static struct surface_update_descriptor check_update_surfaces_for_stream(
2959		const struct dc_check_config *check_config,
2960		struct dc_surface_update *updates,
2961		int surface_count,
2962		struct dc_stream_update *stream_update)
2963{
2964	struct surface_update_descriptor overall_type = { UPDATE_TYPE_FAST, LOCK_DESCRIPTOR_NONE };
2965
2966	if (stream_update && stream_update->pending_test_pattern) {
2967		elevate_update_type(&overall_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_GLOBAL);
2968	}
2969
2970	if (stream_update && stream_update->hw_cursor_req) {
2971		elevate_update_type(&overall_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_GLOBAL);
2972	}
2973
2974	/* some stream updates require passive update */
2975	if (stream_update) {
2976		elevate_update_type(&overall_type, UPDATE_TYPE_FAST, LOCK_DESCRIPTOR_STREAM);
2977
2978		union stream_update_flags *su_flags = &stream_update->stream->update_flags;
2979
2980		if ((stream_update->src.height != 0 && stream_update->src.width != 0) ||
2981			(stream_update->dst.height != 0 && stream_update->dst.width != 0) ||
2982			stream_update->integer_scaling_update)
2983			su_flags->bits.scaling = 1;
2984
2985		if (check_config->enable_legacy_fast_update && stream_update->out_transfer_func)
2986			su_flags->bits.out_tf = 1;
2987
2988		if (stream_update->abm_level)
2989			su_flags->bits.abm_level = 1;
2990
2991		if (stream_update->dpms_off) {
2992			su_flags->bits.dpms_off = 1;
2993			elevate_update_type(&overall_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_GLOBAL | LOCK_DESCRIPTOR_LINK);
2994		}
2995
2996		if (stream_update->gamut_remap)
2997			su_flags->bits.gamut_remap = 1;
2998
2999		if (stream_update->wb_update)
3000			su_flags->bits.wb_update = 1;
3001
3002		if (stream_update->dsc_config)
3003			su_flags->bits.dsc_changed = 1;
3004
3005		if (stream_update->mst_bw_update)
3006			su_flags->bits.mst_bw = 1;
3007
3008		if (stream_update->stream->freesync_on_desktop &&
3009			(stream_update->vrr_infopacket || stream_update->allow_freesync ||
3010				stream_update->vrr_active_variable || stream_update->vrr_active_fixed))
3011			su_flags->bits.fams_changed = 1;
3012
3013		if (stream_update->scaler_sharpener_update)
3014			su_flags->bits.scaler_sharpener = 1;
3015
3016		if (stream_update->sharpening_required)
3017			su_flags->bits.sharpening_required = 1;
3018
3019		if (stream_update->output_color_space)
3020			su_flags->bits.out_csc = 1;
3021
3022		// TODO: Make each elevation explicit, as to not override fast stream in crct_timing_adjust
3023		if (su_flags->raw)
3024			elevate_update_type(&overall_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_GLOBAL);
3025
3026		// Non-global cases
3027		if (stream_update->output_csc_transform) {
3028			su_flags->bits.out_csc = 1;
3029			elevate_update_type(&overall_type, UPDATE_TYPE_FAST, LOCK_DESCRIPTOR_STREAM);
3030		}
3031
3032		if (!check_config->enable_legacy_fast_update && stream_update->out_transfer_func) {
3033			su_flags->bits.out_tf = 1;
3034			elevate_update_type(&overall_type, UPDATE_TYPE_FAST, LOCK_DESCRIPTOR_STREAM);
3035		}
3036	}
3037
3038	for (int i = 0 ; i < surface_count; i++) {
3039		struct surface_update_descriptor inner_type =
3040				det_surface_update(check_config, &updates[i]);
3041
3042		elevate_update_type(&overall_type, inner_type.update_type, inner_type.lock_descriptor);
3043	}
3044
3045	return overall_type;
3046}
3047
3048/*
3049 * dc_check_update_surfaces_for_stream() - Determine update type (fast, med, or full)
3050 *
3051 * See :c:type:`enum surface_update_type <surface_update_type>` for explanation of update types
3052 */
3053struct surface_update_descriptor dc_check_update_surfaces_for_stream(
3054		const struct dc_check_config *check_config,
3055		struct dc_surface_update *updates,
3056		int surface_count,
3057		struct dc_stream_update *stream_update)
3058{
3059	if (stream_update)
3060		stream_update->stream->update_flags.raw = 0;
3061	for (size_t i = 0; i < surface_count; i++)
3062		updates[i].surface->update_flags.raw = 0;
3063
3064	return check_update_surfaces_for_stream(check_config, updates, surface_count, stream_update);
3065}
3066
3067static struct dc_stream_status *stream_get_status(
3068	struct dc_state *ctx,
3069	struct dc_stream_state *stream)
3070{
3071	uint8_t i;
3072
3073	for (i = 0; i < ctx->stream_count; i++) {
3074		if (stream == ctx->streams[i]) {
3075			return &ctx->stream_status[i];
3076		}
3077	}
3078
3079	return NULL;
3080}
3081
3082static const enum surface_update_type update_surface_trace_level = UPDATE_TYPE_FULL;
3083
3084static void copy_surface_update_to_plane(
3085		struct dc_plane_state *surface,
3086		struct dc_surface_update *srf_update)
3087{
3088	if (srf_update->flip_addr) {
3089		surface->address = srf_update->flip_addr->address;
3090		surface->flip_immediate =
3091			srf_update->flip_addr->flip_immediate;
3092		surface->time.time_elapsed_in_us[surface->time.index] =
3093			srf_update->flip_addr->flip_timestamp_in_us -
3094				surface->time.prev_update_time_in_us;
3095		surface->time.prev_update_time_in_us =
3096			srf_update->flip_addr->flip_timestamp_in_us;
3097		surface->time.index++;
3098		if (surface->time.index >= DC_PLANE_UPDATE_TIMES_MAX)
3099			surface->time.index = 0;
3100
3101		surface->triplebuffer_flips = srf_update->flip_addr->triplebuffer_flips;
3102	}
3103
3104	if (srf_update->scaling_info) {
3105		surface->scaling_quality =
3106				srf_update->scaling_info->scaling_quality;
3107		surface->dst_rect =
3108				srf_update->scaling_info->dst_rect;
3109		surface->src_rect =
3110				srf_update->scaling_info->src_rect;
3111		surface->clip_rect =
3112				srf_update->scaling_info->clip_rect;
3113	}
3114
3115	if (srf_update->plane_info) {
3116		surface->color_space =
3117				srf_update->plane_info->color_space;
3118		surface->format =
3119				srf_update->plane_info->format;
3120		surface->plane_size =
3121				srf_update->plane_info->plane_size;
3122		surface->rotation =
3123				srf_update->plane_info->rotation;
3124		surface->horizontal_mirror =
3125				srf_update->plane_info->horizontal_mirror;
3126		surface->stereo_format =
3127				srf_update->plane_info->stereo_format;
3128		surface->tiling_info =
3129				srf_update->plane_info->tiling_info;
3130		surface->visible =
3131				srf_update->plane_info->visible;
3132		surface->per_pixel_alpha =
3133				srf_update->plane_info->per_pixel_alpha;
3134		surface->global_alpha =
3135				srf_update->plane_info->global_alpha;
3136		surface->global_alpha_value =
3137				srf_update->plane_info->global_alpha_value;
3138		surface->dcc =
3139				srf_update->plane_info->dcc;
3140		surface->layer_index =
3141				srf_update->plane_info->layer_index;
3142	}
3143
3144	if (srf_update->gamma) {
3145		memcpy(&surface->gamma_correction.entries,
3146			&srf_update->gamma->entries,
3147			sizeof(struct dc_gamma_entries));
3148		surface->gamma_correction.is_identity =
3149			srf_update->gamma->is_identity;
3150		surface->gamma_correction.num_entries =
3151			srf_update->gamma->num_entries;
3152		surface->gamma_correction.type =
3153			srf_update->gamma->type;
3154	}
3155
3156	if (srf_update->in_transfer_func) {
3157		surface->in_transfer_func.sdr_ref_white_level =
3158			srf_update->in_transfer_func->sdr_ref_white_level;
3159		surface->in_transfer_func.tf =
3160			srf_update->in_transfer_func->tf;
3161		surface->in_transfer_func.type =
3162			srf_update->in_transfer_func->type;
3163		memcpy(&surface->in_transfer_func.tf_pts,
3164			&srf_update->in_transfer_func->tf_pts,
3165			sizeof(struct dc_transfer_func_distributed_points));
3166	}
3167
3168	if (srf_update->cm2_params) {
3169		surface->mcm_shaper_3dlut_setting = srf_update->cm2_params->component_settings.shaper_3dlut_setting;
3170		surface->mcm_lut1d_enable = srf_update->cm2_params->component_settings.lut1d_enable;
3171		surface->mcm_luts = srf_update->cm2_params->cm2_luts;
3172	}
3173
3174	if (srf_update->func_shaper) {
3175		memcpy(&surface->in_shaper_func, srf_update->func_shaper,
3176		sizeof(surface->in_shaper_func));
3177
3178		if (surface->mcm_shaper_3dlut_setting >= DC_CM2_SHAPER_3DLUT_SETTING_ENABLE_SHAPER)
3179			surface->mcm_luts.shaper = &surface->in_shaper_func;
3180	}
3181
3182	if (srf_update->lut3d_func)
3183		memcpy(&surface->lut3d_func, srf_update->lut3d_func,
3184		sizeof(surface->lut3d_func));
3185
3186	if (srf_update->hdr_mult.value)
3187		surface->hdr_mult =
3188				srf_update->hdr_mult;
3189
3190	if (srf_update->sdr_white_level_nits)
3191		surface->sdr_white_level_nits =
3192				srf_update->sdr_white_level_nits;
3193
3194	if (srf_update->blend_tf) {
3195		memcpy(&surface->blend_tf, srf_update->blend_tf,
3196		sizeof(surface->blend_tf));
3197
3198		if (surface->mcm_lut1d_enable)
3199			surface->mcm_luts.lut1d_func = &surface->blend_tf;
3200	}
3201
3202	if (srf_update->cm2_params || srf_update->blend_tf)
3203		surface->lut_bank_a = !surface->lut_bank_a;
3204
3205	if (srf_update->input_csc_color_matrix)
3206		surface->input_csc_color_matrix =
3207			*srf_update->input_csc_color_matrix;
3208
3209	if (srf_update->coeff_reduction_factor)
3210		surface->coeff_reduction_factor =
3211			*srf_update->coeff_reduction_factor;
3212
3213	if (srf_update->gamut_remap_matrix)
3214		surface->gamut_remap_matrix =
3215			*srf_update->gamut_remap_matrix;
3216
3217	if (srf_update->cursor_csc_color_matrix)
3218		surface->cursor_csc_color_matrix =
3219			*srf_update->cursor_csc_color_matrix;
3220
3221	if (srf_update->bias_and_scale.bias_and_scale_valid)
3222			surface->bias_and_scale =
3223					srf_update->bias_and_scale;
3224}
3225
3226static void copy_stream_update_to_stream(struct dc *dc,
3227					 struct dc_state *context,
3228					 struct dc_stream_state *stream,
3229					 struct dc_stream_update *update)
3230{
3231	struct dc_context *dc_ctx = dc->ctx;
3232
3233	if (update == NULL || stream == NULL)
3234		return;
3235
3236	if (update->src.height && update->src.width)
3237		stream->src = update->src;
3238
3239	if (update->dst.height && update->dst.width)
3240		stream->dst = update->dst;
3241
3242	if (update->out_transfer_func) {
3243		stream->out_transfer_func.sdr_ref_white_level =
3244			update->out_transfer_func->sdr_ref_white_level;
3245		stream->out_transfer_func.tf = update->out_transfer_func->tf;
3246		stream->out_transfer_func.type =
3247			update->out_transfer_func->type;
3248		memcpy(&stream->out_transfer_func.tf_pts,
3249		       &update->out_transfer_func->tf_pts,
3250		       sizeof(struct dc_transfer_func_distributed_points));
3251	}
3252
3253	if (update->hdr_static_metadata)
3254		stream->hdr_static_metadata = *update->hdr_static_metadata;
3255
3256	if (update->abm_level)
3257		stream->abm_level = *update->abm_level;
3258
3259	if (update->periodic_interrupt)
3260		stream->periodic_interrupt = *update->periodic_interrupt;
3261
3262	if (update->gamut_remap)
3263		stream->gamut_remap_matrix = *update->gamut_remap;
3264
3265	/* Note: this being updated after mode set is currently not a use case
3266	 * however if it arises OCSC would need to be reprogrammed at the
3267	 * minimum
3268	 */
3269	if (update->output_color_space)
3270		stream->output_color_space = *update->output_color_space;
3271
3272	if (update->output_csc_transform)
3273		stream->csc_color_matrix = *update->output_csc_transform;
3274
3275	if (update->vrr_infopacket)
3276		stream->vrr_infopacket = *update->vrr_infopacket;
3277
3278	if (update->hw_cursor_req)
3279		stream->hw_cursor_req = *update->hw_cursor_req;
3280
3281	if (update->allow_freesync)
3282		stream->allow_freesync = *update->allow_freesync;
3283
3284	if (update->vrr_active_variable)
3285		stream->vrr_active_variable = *update->vrr_active_variable;
3286
3287	if (update->vrr_active_fixed)
3288		stream->vrr_active_fixed = *update->vrr_active_fixed;
3289
3290	if (update->crtc_timing_adjust) {
3291		if (stream->adjust.v_total_min != update->crtc_timing_adjust->v_total_min ||
3292			stream->adjust.v_total_max != update->crtc_timing_adjust->v_total_max ||
3293			stream->adjust.timing_adjust_pending)
3294			update->crtc_timing_adjust->timing_adjust_pending = true;
3295		stream->adjust = *update->crtc_timing_adjust;
3296		update->crtc_timing_adjust->timing_adjust_pending = false;
3297	}
3298
3299	if (update->dpms_off)
3300		stream->dpms_off = *update->dpms_off;
3301
3302	if (update->hfvsif_infopacket)
3303		stream->hfvsif_infopacket = *update->hfvsif_infopacket;
3304
3305	if (update->vtem_infopacket)
3306		stream->vtem_infopacket = *update->vtem_infopacket;
3307
3308	if (update->vsc_infopacket)
3309		stream->vsc_infopacket = *update->vsc_infopacket;
3310
3311	if (update->vsp_infopacket)
3312		stream->vsp_infopacket = *update->vsp_infopacket;
3313
3314	if (update->adaptive_sync_infopacket)
3315		stream->adaptive_sync_infopacket = *update->adaptive_sync_infopacket;
3316
3317	if (update->avi_infopacket)
3318		stream->avi_infopacket = *update->avi_infopacket;
3319
3320	if (update->dither_option)
3321		stream->dither_option = *update->dither_option;
3322
3323	if (update->pending_test_pattern)
3324		stream->test_pattern = *update->pending_test_pattern;
3325	/* update current stream with writeback info */
3326	if (update->wb_update) {
3327		int i;
3328
3329		stream->num_wb_info = update->wb_update->num_wb_info;
3330		ASSERT(stream->num_wb_info <= MAX_DWB_PIPES);
3331		for (i = 0; i < stream->num_wb_info; i++)
3332			stream->writeback_info[i] =
3333				update->wb_update->writeback_info[i];
3334	}
3335	if (update->dsc_config) {
3336		struct dc_dsc_config old_dsc_cfg = stream->timing.dsc_cfg;
3337		uint32_t old_dsc_enabled = stream->timing.flags.DSC;
3338		uint32_t enable_dsc = (update->dsc_config->num_slices_h != 0 &&
3339				       update->dsc_config->num_slices_v != 0);
3340
3341		/* Use temporarry context for validating new DSC config */
3342		struct dc_state *dsc_validate_context = dc_state_create_copy(dc->current_state);
3343
3344		if (dsc_validate_context) {
3345			stream->timing.dsc_cfg = *update->dsc_config;
3346			stream->timing.flags.DSC = enable_dsc;
3347			if (dc->res_pool->funcs->validate_bandwidth(dc, dsc_validate_context,
3348				DC_VALIDATE_MODE_ONLY) != DC_OK) {
3349				stream->timing.dsc_cfg = old_dsc_cfg;
3350				stream->timing.flags.DSC = old_dsc_enabled;
3351				update->dsc_config = NULL;
3352			}
3353
3354			dc_state_release(dsc_validate_context);
3355		} else {
3356			DC_ERROR("Failed to allocate new validate context for DSC change\n");
3357			update->dsc_config = NULL;
3358		}
3359	}
3360	if (update->scaler_sharpener_update)
3361		stream->scaler_sharpener_update = *update->scaler_sharpener_update;
3362	if (update->sharpening_required)
3363		stream->sharpening_required = *update->sharpening_required;
3364}
3365
3366static void backup_planes_and_stream_state(
3367		struct dc_scratch_space *scratch,
3368		struct dc_stream_state *stream)
3369{
3370	int i;
3371	struct dc_stream_status *status = dc_stream_get_status(stream);
3372
3373	if (!status)
3374		return;
3375
3376	for (i = 0; i < status->plane_count; i++) {
3377		dc_plane_copy_config(&scratch->plane_states[i], status->plane_states[i]);
3378	}
3379	scratch->stream_state = *stream;
3380}
3381
3382static void restore_planes_and_stream_state(
3383		struct dc_scratch_space *scratch,
3384		struct dc_stream_state *stream)
3385{
3386	int i;
3387	struct dc_stream_status *status = dc_stream_get_status(stream);
3388
3389	if (!status)
3390		return;
3391
3392	for (i = 0; i < status->plane_count; i++) {
3393		dc_plane_copy_config(status->plane_states[i], &scratch->plane_states[i]);
3394	}
3395
3396	// refcount is persistent
3397	struct kref temp_refcount = stream->refcount;
3398	*stream = scratch->stream_state;
3399	stream->refcount = temp_refcount;
3400}
3401
3402/**
3403 * update_seamless_boot_flags() - Helper function for updating seamless boot flags
3404 *
3405 * @dc: Current DC state
3406 * @context: New DC state to be programmed
3407 * @surface_count: Number of surfaces that have an updated
3408 * @stream: Corresponding stream to be updated in the current flip
3409 *
3410 * Updating seamless boot flags do not need to be part of the commit sequence. This
3411 * helper function will update the seamless boot flags on each flip (if required)
3412 * outside of the HW commit sequence (fast or slow).
3413 *
3414 * Return: void
3415 */
3416static void update_seamless_boot_flags(struct dc *dc,
3417		struct dc_state *context,
3418		int surface_count,
3419		struct dc_stream_state *stream)
3420{
3421	if (get_seamless_boot_stream_count(context) > 0 && (surface_count > 0 || stream->dpms_off)) {
3422		/* Optimize seamless boot flag keeps clocks and watermarks high until
3423		 * first flip. After first flip, optimization is required to lower
3424		 * bandwidth. Important to note that it is expected UEFI will
3425		 * only light up a single display on POST, therefore we only expect
3426		 * one stream with seamless boot flag set.
3427		 */
3428		if (stream->apply_seamless_boot_optimization) {
3429			stream->apply_seamless_boot_optimization = false;
3430
3431			if (get_seamless_boot_stream_count(context) == 0)
3432				dc->optimized_required = true;
3433		}
3434	}
3435}
3436
3437static bool full_update_required_weak(
3438		const struct dc *dc,
3439		const struct dc_surface_update *srf_updates,
3440		int surface_count,
3441		const struct dc_stream_update *stream_update,
3442		const struct dc_stream_state *stream);
3443
3444/**
3445 * update_planes_and_stream_state() - The function takes planes and stream
3446 * updates as inputs and determines the appropriate update type. If update type
3447 * is FULL, the function allocates a new context, populates and validates it.
3448 * Otherwise, it updates current dc context. The function will return both
3449 * new_context and new_update_type back to the caller. The function also backs
3450 * up both current and new contexts into corresponding dc state scratch memory.
3451 * TODO: The function does too many things, and even conditionally allocates dc
3452 * context memory implicitly. We should consider to break it down.
3453 *
3454 * @dc: Current DC state
3455 * @srf_updates: an array of surface updates
3456 * @surface_count: surface update count
3457 * @stream: Corresponding stream to be updated
3458 * @stream_update: stream update
3459 * @new_update_type: [out] determined update type by the function
3460 * @new_context: [out] new context allocated and validated if update type is
3461 * FULL, reference to current context if update type is less than FULL.
3462 *
3463 * Return: true if a valid update is populated into new_context, false
3464 * otherwise.
3465 */
3466static bool update_planes_and_stream_state(struct dc *dc,
3467		struct dc_surface_update *srf_updates, int surface_count,
3468		struct dc_stream_state *stream,
3469		struct dc_stream_update *stream_update,
3470		enum surface_update_type *new_update_type,
3471		struct dc_state **new_context)
3472{
3473	struct dc_state *context;
3474	int i, j;
3475	enum surface_update_type update_type;
3476	const struct dc_stream_status *stream_status;
3477	struct dc_context *dc_ctx = dc->ctx;
3478
3479	stream_status = dc_stream_get_status(stream);
3480
3481	if (!stream_status) {
3482		if (surface_count) /* Only an error condition if surf_count non-zero*/
3483			ASSERT(false);
3484
3485		return false; /* Cannot commit surface to stream that is not committed */
3486	}
3487
3488	context = dc->current_state;
3489	update_type = dc_check_update_surfaces_for_stream(
3490			&dc->check_config, srf_updates, surface_count, stream_update).update_type;
3491	if (full_update_required_weak(dc, srf_updates, surface_count, stream_update, stream))
3492		update_type = UPDATE_TYPE_FULL;
3493
3494	/* It is possible to receive a flip for one plane while there are multiple flip_immediate planes in the same stream.
3495	 * E.g. Desktop and MPO plane are flip_immediate but only the MPO plane received a flip
3496	 * Force the other flip_immediate planes to flip so GSL doesn't wait for a flip that won't come.
3497	 */
3498	force_immediate_gsl_plane_flip(dc, srf_updates, surface_count);
3499	if (update_type == UPDATE_TYPE_FULL)
3500		backup_planes_and_stream_state(&dc->scratch.current_state, stream);
3501
3502	/* update current stream with the new updates */
3503	copy_stream_update_to_stream(dc, context, stream, stream_update);
3504
3505	/* do not perform surface update if surface has invalid dimensions
3506	 * (all zero) and no scaling_info is provided
3507	 */
3508	if (surface_count > 0) {
3509		for (i = 0; i < surface_count; i++) {
3510			if ((srf_updates[i].surface->src_rect.width == 0 ||
3511				 srf_updates[i].surface->src_rect.height == 0 ||
3512				 srf_updates[i].surface->dst_rect.width == 0 ||
3513				 srf_updates[i].surface->dst_rect.height == 0) &&
3514				(!srf_updates[i].scaling_info ||
3515				  srf_updates[i].scaling_info->src_rect.width == 0 ||
3516				  srf_updates[i].scaling_info->src_rect.height == 0 ||
3517				  srf_updates[i].scaling_info->dst_rect.width == 0 ||
3518				  srf_updates[i].scaling_info->dst_rect.height == 0)) {
3519				DC_ERROR("Invalid src/dst rects in surface update!\n");
3520				return false;
3521			}
3522		}
3523	}
3524
3525	if (update_type == UPDATE_TYPE_FULL) {
3526		if (stream_update) {
3527			uint32_t dsc_changed = stream_update->stream->update_flags.bits.dsc_changed;
3528			stream_update->stream->update_flags.raw = 0xFFFFFFFF;
3529			stream_update->stream->update_flags.bits.dsc_changed = dsc_changed;
3530		}
3531		for (i = 0; i < surface_count; i++)
3532			srf_updates[i].surface->update_flags.raw = 0xFFFFFFFF;
3533	}
3534
3535	if (update_type >= update_surface_trace_level)
3536		update_surface_trace(dc, srf_updates, surface_count);
3537
3538	for (i = 0; i < surface_count; i++)
3539		copy_surface_update_to_plane(srf_updates[i].surface, &srf_updates[i]);
3540
3541	if (update_type >= UPDATE_TYPE_FULL) {
3542		struct dc_plane_state *new_planes[MAX_SURFACES] = {0};
3543
3544		for (i = 0; i < surface_count; i++)
3545			new_planes[i] = srf_updates[i].surface;
3546
3547		/* initialize scratch memory for building context */
3548		context = dc_state_create_copy(dc->current_state);
3549		if (context == NULL) {
3550			DC_ERROR("Failed to allocate new validate context!\n");
3551			return false;
3552		}
3553
3554		/* For each full update, remove all existing phantom pipes first.
3555		 * Ensures that we have enough pipes for newly added MPO planes
3556		 */
3557		dc_state_remove_phantom_streams_and_planes(dc, context);
3558		dc_state_release_phantom_streams_and_planes(dc, context);
3559
3560		/*remove old surfaces from context */
3561		if (!dc_state_rem_all_planes_for_stream(dc, stream, context)) {
3562
3563			BREAK_TO_DEBUGGER();
3564			goto fail;
3565		}
3566
3567		/* add surface to context */
3568		if (!dc_state_add_all_planes_for_stream(dc, stream, new_planes, surface_count, context)) {
3569
3570			BREAK_TO_DEBUGGER();
3571			goto fail;
3572		}
3573	}
3574
3575	/* save update parameters into surface */
3576	for (i = 0; i < surface_count; i++) {
3577		struct dc_plane_state *surface = srf_updates[i].surface;
3578
3579		if (update_type != UPDATE_TYPE_MED)
3580			continue;
3581		if (surface->update_flags.bits.position_change) {
3582			for (j = 0; j < dc->res_pool->pipe_count; j++) {
3583				struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j];
3584
3585				if (pipe_ctx->plane_state != surface)
3586					continue;
3587
3588				resource_build_scaling_params(pipe_ctx);
3589			}
3590		}
3591	}
3592
3593	if (update_type == UPDATE_TYPE_FULL) {
3594		if (dc->res_pool->funcs->validate_bandwidth(dc, context, DC_VALIDATE_MODE_AND_PROGRAMMING) != DC_OK) {
3595			BREAK_TO_DEBUGGER();
3596			goto fail;
3597		}
3598	}
3599	update_seamless_boot_flags(dc, context, surface_count, stream);
3600
3601	*new_context = context;
3602	*new_update_type = update_type;
3603	if (update_type == UPDATE_TYPE_FULL)
3604		backup_planes_and_stream_state(&dc->scratch.new_state, stream);
3605
3606	return true;
3607
3608fail:
3609	dc_state_release(context);
3610
3611	return false;
3612
3613}
3614
3615static void commit_planes_do_stream_update(struct dc *dc,
3616		struct dc_stream_state *stream,
3617		struct dc_stream_update *stream_update,
3618		enum surface_update_type update_type,
3619		struct dc_state *context)
3620{
3621	int j;
3622
3623	// Stream updates
3624	for (j = 0; j < dc->res_pool->pipe_count; j++) {
3625		struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j];
3626
3627		if (resource_is_pipe_type(pipe_ctx, OTG_MASTER) && pipe_ctx->stream == stream) {
3628
3629			if (stream_update->periodic_interrupt && dc->hwss.setup_periodic_interrupt)
3630				dc->hwss.setup_periodic_interrupt(dc, pipe_ctx);
3631
3632			if ((stream_update->hdr_static_metadata && !stream->use_dynamic_meta) ||
3633					stream_update->vrr_infopacket ||
3634					stream_update->vsc_infopacket ||
3635					stream_update->vsp_infopacket ||
3636					stream_update->hfvsif_infopacket ||
3637					stream_update->adaptive_sync_infopacket ||
3638					stream_update->vtem_infopacket ||
3639					stream_update->avi_infopacket) {
3640				resource_build_info_frame(pipe_ctx);
3641				dc->hwss.update_info_frame(pipe_ctx);
3642
3643				if (dc_is_dp_signal(pipe_ctx->stream->signal))
3644					dc->link_srv->dp_trace_source_sequence(
3645							pipe_ctx->stream->link,
3646							DPCD_SOURCE_SEQ_AFTER_UPDATE_INFO_FRAME);
3647			}
3648
3649			if (stream_update->hdr_static_metadata &&
3650					stream->use_dynamic_meta &&
3651					dc->hwss.set_dmdata_attributes &&
3652					pipe_ctx->stream->dmdata_address.quad_part != 0)
3653				dc->hwss.set_dmdata_attributes(pipe_ctx);
3654
3655			if (stream_update->gamut_remap)
3656				dc_stream_set_gamut_remap(dc, stream);
3657
3658			if (stream_update->output_csc_transform)
3659				dc_stream_program_csc_matrix(dc, stream);
3660
3661			if (stream_update->dither_option) {
3662				struct pipe_ctx *odm_pipe = pipe_ctx->next_odm_pipe;
3663				resource_build_bit_depth_reduction_params(pipe_ctx->stream,
3664									&pipe_ctx->stream->bit_depth_params);
3665				pipe_ctx->stream_res.opp->funcs->opp_program_fmt(pipe_ctx->stream_res.opp,
3666						&stream->bit_depth_params,
3667						&stream->clamping);
3668				while (odm_pipe) {
3669					odm_pipe->stream_res.opp->funcs->opp_program_fmt(odm_pipe->stream_res.opp,
3670							&stream->bit_depth_params,
3671							&stream->clamping);
3672					odm_pipe = odm_pipe->next_odm_pipe;
3673				}
3674			}
3675
3676			if (stream_update->cursor_attributes)
3677				program_cursor_attributes(dc, stream);
3678
3679			if (stream_update->cursor_position)
3680				program_cursor_position(dc, stream);
3681
3682			/* Full fe update*/
3683			if (update_type == UPDATE_TYPE_FAST)
3684				continue;
3685
3686			if (stream_update->dsc_config)
3687				dc->link_srv->update_dsc_config(pipe_ctx);
3688
3689			if (stream_update->mst_bw_update) {
3690				if (stream_update->mst_bw_update->is_increase)
3691					dc->link_srv->increase_mst_payload(pipe_ctx,
3692							stream_update->mst_bw_update->mst_stream_bw);
3693				else
3694					dc->link_srv->reduce_mst_payload(pipe_ctx,
3695							stream_update->mst_bw_update->mst_stream_bw);
3696			}
3697
3698			if (stream_update->pending_test_pattern) {
3699				/*
3700				 * test pattern params depends on ODM topology
3701				 * changes that we could be applying to front
3702				 * end. Since at the current stage front end
3703				 * changes are not yet applied. We can only
3704				 * apply test pattern in hw based on current
3705				 * state and populate the final test pattern
3706				 * params in new state. If current and new test
3707				 * pattern params are different as result of
3708				 * different ODM topology being used, it will be
3709				 * detected and handle during front end
3710				 * programming update.
3711				 */
3712				dc->link_srv->dp_set_test_pattern(stream->link,
3713					stream->test_pattern.type,
3714					stream->test_pattern.color_space,
3715					stream->test_pattern.p_link_settings,
3716					stream->test_pattern.p_custom_pattern,
3717					stream->test_pattern.cust_pattern_size);
3718				resource_build_test_pattern_params(&context->res_ctx, pipe_ctx);
3719			}
3720
3721			if (stream_update->dpms_off) {
3722				if (*stream_update->dpms_off) {
3723					dc->link_srv->set_dpms_off(pipe_ctx);
3724					/* for dpms, keep acquired resources*/
3725					if (pipe_ctx->stream_res.audio && !dc->debug.az_endpoint_mute_only)
3726						pipe_ctx->stream_res.audio->funcs->az_disable(pipe_ctx->stream_res.audio);
3727
3728					dc->optimized_required = true;
3729
3730				} else {
3731					if (get_seamless_boot_stream_count(context) == 0)
3732						dc->hwss.prepare_bandwidth(dc, dc->current_state);
3733					dc->link_srv->set_dpms_on(dc->current_state, pipe_ctx);
3734				}
3735			} else if (pipe_ctx->stream->link->wa_flags.blank_stream_on_ocs_change && stream_update->output_color_space
3736					&& !stream->dpms_off && dc_is_dp_signal(pipe_ctx->stream->signal)) {
3737				/*
3738				 * Workaround for firmware issue in some receivers where they don't pick up
3739				 * correct output color space unless DP link is disabled/re-enabled
3740				 */
3741				dc->link_srv->set_dpms_on(dc->current_state, pipe_ctx);
3742			}
3743
3744			if (stream_update->abm_level && pipe_ctx->stream_res.abm) {
3745				bool should_program_abm = true;
3746
3747				// if otg funcs defined check if blanked before programming
3748				if (pipe_ctx->stream_res.tg->funcs->is_blanked)
3749					if (pipe_ctx->stream_res.tg->funcs->is_blanked(pipe_ctx->stream_res.tg))
3750						should_program_abm = false;
3751
3752				if (should_program_abm) {
3753					if (*stream_update->abm_level == ABM_LEVEL_IMMEDIATE_DISABLE) {
3754						dc->hwss.set_abm_immediate_disable(pipe_ctx);
3755					} else {
3756						pipe_ctx->stream_res.abm->funcs->set_abm_level(
3757							pipe_ctx->stream_res.abm, stream->abm_level);
3758					}
3759				}
3760			}
3761		}
3762	}
3763}
3764
3765static bool dc_dmub_should_send_dirty_rect_cmd(struct dc *dc, struct dc_stream_state *stream)
3766{
3767	if ((stream->link->psr_settings.psr_version == DC_PSR_VERSION_SU_1
3768			|| stream->link->psr_settings.psr_version == DC_PSR_VERSION_1)
3769			&& stream->ctx->dce_version >= DCN_VERSION_3_1)
3770		return true;
3771
3772	if (stream->link->replay_settings.config.replay_supported)
3773		return true;
3774
3775	if (stream->ctx->dce_version >= DCN_VERSION_3_5 && stream->abm_level)
3776		return true;
3777
3778	return false;
3779}
3780
3781void dc_dmub_update_dirty_rect(struct dc *dc,
3782			       int surface_count,
3783			       struct dc_stream_state *stream,
3784			       struct dc_surface_update *srf_updates,
3785			       struct dc_state *context)
3786{
3787	union dmub_rb_cmd cmd;
3788	struct dmub_cmd_update_dirty_rect_data *update_dirty_rect;
3789	unsigned int i, j;
3790	unsigned int panel_inst = 0;
3791
3792	if (!dc_dmub_should_send_dirty_rect_cmd(dc, stream))
3793		return;
3794
3795	if (!dc_get_edp_link_panel_inst(dc, stream->link, &panel_inst))
3796		return;
3797
3798	memset(&cmd, 0x0, sizeof(cmd));
3799	cmd.update_dirty_rect.header.type = DMUB_CMD__UPDATE_DIRTY_RECT;
3800	cmd.update_dirty_rect.header.sub_type = 0;
3801	cmd.update_dirty_rect.header.payload_bytes =
3802		sizeof(cmd.update_dirty_rect) -
3803		sizeof(cmd.update_dirty_rect.header);
3804	update_dirty_rect = &cmd.update_dirty_rect.update_dirty_rect_data;
3805	for (i = 0; i < surface_count; i++) {
3806		struct dc_plane_state *plane_state = srf_updates[i].surface;
3807		const struct dc_flip_addrs *flip_addr = srf_updates[i].flip_addr;
3808
3809		if (!srf_updates[i].surface || !flip_addr)
3810			continue;
3811		/* Do not send in immediate flip mode */
3812		if (srf_updates[i].surface->flip_immediate)
3813			continue;
3814
3815		update_dirty_rect->cmd_version = DMUB_CMD_PSR_CONTROL_VERSION_1;
3816		update_dirty_rect->dirty_rect_count = flip_addr->dirty_rect_count;
3817		memcpy(update_dirty_rect->src_dirty_rects, flip_addr->dirty_rects,
3818				sizeof(flip_addr->dirty_rects));
3819		for (j = 0; j < dc->res_pool->pipe_count; j++) {
3820			struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j];
3821
3822			if (pipe_ctx->stream != stream)
3823				continue;
3824			if (pipe_ctx->plane_state != plane_state)
3825				continue;
3826
3827			update_dirty_rect->panel_inst = panel_inst;
3828			update_dirty_rect->pipe_idx = j;
3829			dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_NO_WAIT);
3830		}
3831	}
3832}
3833
3834static void build_dmub_update_dirty_rect(
3835		struct dc *dc,
3836		int surface_count,
3837		struct dc_stream_state *stream,
3838		struct dc_surface_update *srf_updates,
3839		struct dc_state *context,
3840		struct dc_dmub_cmd dc_dmub_cmd[],
3841		unsigned int *dmub_cmd_count)
3842{
3843	union dmub_rb_cmd cmd;
3844	struct dmub_cmd_update_dirty_rect_data *update_dirty_rect;
3845	unsigned int i, j;
3846	unsigned int panel_inst = 0;
3847
3848	if (!dc_dmub_should_send_dirty_rect_cmd(dc, stream))
3849		return;
3850
3851	if (!dc_get_edp_link_panel_inst(dc, stream->link, &panel_inst))
3852		return;
3853
3854	memset(&cmd, 0x0, sizeof(cmd));
3855	cmd.update_dirty_rect.header.type = DMUB_CMD__UPDATE_DIRTY_RECT;
3856	cmd.update_dirty_rect.header.sub_type = 0;
3857	cmd.update_dirty_rect.header.payload_bytes =
3858		sizeof(cmd.update_dirty_rect) -
3859		sizeof(cmd.update_dirty_rect.header);
3860	update_dirty_rect = &cmd.update_dirty_rect.update_dirty_rect_data;
3861	for (i = 0; i < surface_count; i++) {
3862		struct dc_plane_state *plane_state = srf_updates[i].surface;
3863		const struct dc_flip_addrs *flip_addr = srf_updates[i].flip_addr;
3864
3865		if (!srf_updates[i].surface || !flip_addr)
3866			continue;
3867		/* Do not send in immediate flip mode */
3868		if (srf_updates[i].surface->flip_immediate)
3869			continue;
3870		update_dirty_rect->cmd_version = DMUB_CMD_PSR_CONTROL_VERSION_1;
3871		update_dirty_rect->dirty_rect_count = flip_addr->dirty_rect_count;
3872		memcpy(update_dirty_rect->src_dirty_rects, flip_addr->dirty_rects,
3873				sizeof(flip_addr->dirty_rects));
3874		for (j = 0; j < dc->res_pool->pipe_count; j++) {
3875			struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j];
3876
3877			if (pipe_ctx->stream != stream)
3878				continue;
3879			if (pipe_ctx->plane_state != plane_state)
3880				continue;
3881			update_dirty_rect->panel_inst = panel_inst;
3882			update_dirty_rect->pipe_idx = j;
3883			dc_dmub_cmd[*dmub_cmd_count].dmub_cmd = cmd;
3884			dc_dmub_cmd[*dmub_cmd_count].wait_type = DM_DMUB_WAIT_TYPE_NO_WAIT;
3885			(*dmub_cmd_count)++;
3886		}
3887	}
3888}
3889
3890static bool check_address_only_update(union surface_update_flags update_flags)
3891{
3892	union surface_update_flags addr_only_update_flags;
3893	addr_only_update_flags.raw = 0;
3894	addr_only_update_flags.bits.addr_update = 1;
3895
3896	return update_flags.bits.addr_update &&
3897			!(update_flags.raw & ~addr_only_update_flags.raw);
3898}
3899
3900/**
3901 * build_dmub_cmd_list() - Build an array of DMCUB commands to be sent to DMCUB
3902 *
3903 * @dc: Current DC state
3904 * @srf_updates: Array of surface updates
3905 * @surface_count: Number of surfaces that have an updated
3906 * @stream: Corresponding stream to be updated in the current flip
3907 * @context: New DC state to be programmed
3908 *
3909 * @dc_dmub_cmd: Array of DMCUB commands to be sent to DMCUB
3910 * @dmub_cmd_count: Count indicating the number of DMCUB commands in dc_dmub_cmd array
3911 *
3912 * This function builds an array of DMCUB commands to be sent to DMCUB. This function is required
3913 * to build an array of commands and have them sent while the OTG lock is acquired.
3914 *
3915 * Return: void
3916 */
3917static void build_dmub_cmd_list(struct dc *dc,
3918		struct dc_surface_update *srf_updates,
3919		int surface_count,
3920		struct dc_stream_state *stream,
3921		struct dc_state *context,
3922		struct dc_dmub_cmd dc_dmub_cmd[],
3923		unsigned int *dmub_cmd_count)
3924{
3925	// Initialize cmd count to 0
3926	*dmub_cmd_count = 0;
3927	build_dmub_update_dirty_rect(dc, surface_count, stream, srf_updates, context, dc_dmub_cmd, dmub_cmd_count);
3928}
3929
3930static void commit_plane_for_stream_offload_fams2_flip(struct dc *dc,
3931		struct dc_surface_update *srf_updates,
3932		int surface_count,
3933		struct dc_stream_state *stream,
3934		struct dc_state *context)
3935{
3936	int i, j;
3937
3938	/* update dirty rect for PSR */
3939	dc_dmub_update_dirty_rect(dc, surface_count, stream,
3940			srf_updates, context);
3941
3942	/* Perform requested Updates */
3943	for (i = 0; i < surface_count; i++) {
3944		struct dc_plane_state *plane_state = srf_updates[i].surface;
3945
3946		for (j = 0; j < dc->res_pool->pipe_count; j++) {
3947			struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j];
3948
3949			if (!should_update_pipe_for_stream(context, pipe_ctx, stream))
3950				continue;
3951
3952			if (!should_update_pipe_for_plane(context, pipe_ctx, plane_state))
3953				continue;
3954
3955			/* update pipe context for plane */
3956			if (pipe_ctx->plane_state->update_flags.bits.addr_update)
3957				dc->hwss.update_plane_addr(dc, pipe_ctx);
3958		}
3959	}
3960
3961	/* Send commands to DMCUB */
3962	dc_dmub_srv_fams2_passthrough_flip(dc,
3963				context,
3964				stream,
3965				srf_updates,
3966				surface_count);
3967}
3968
3969static void commit_planes_for_stream_fast(struct dc *dc,
3970		struct dc_surface_update *srf_updates,
3971		int surface_count,
3972		struct dc_stream_state *stream,
3973		struct dc_stream_update *stream_update,
3974		enum surface_update_type update_type,
3975		struct dc_state *context)
3976{
3977	int i, j;
3978	struct pipe_ctx *top_pipe_to_program = NULL;
3979	struct dc_stream_status *stream_status = NULL;
3980	bool should_offload_fams2_flip = false;
3981	bool should_lock_all_pipes = (update_type != UPDATE_TYPE_FAST);
3982
3983	if (should_lock_all_pipes)
3984		determine_pipe_unlock_order(dc, context);
3985
3986	if (dc->debug.fams2_config.bits.enable &&
3987			dc->debug.fams2_config.bits.enable_offload_flip &&
3988			dc_state_is_fams2_in_use(dc, context)) {
3989		/* if not offloading to HWFQ, offload to FAMS2 if needed */
3990		should_offload_fams2_flip = true;
3991		for (i = 0; i < surface_count; i++) {
3992			if (srf_updates[i].surface &&
3993					srf_updates[i].surface->update_flags.raw &&
3994					!check_address_only_update(srf_updates[i].surface->update_flags)) {
3995				/* more than address update, need to acquire FAMS2 lock */
3996				should_offload_fams2_flip = false;
3997				break;
3998			}
3999		}
4000		if (stream_update) {
4001			/* more than address update, need to acquire FAMS2 lock */
4002			should_offload_fams2_flip = false;
4003		}
4004	}
4005
4006	dc_exit_ips_for_hw_access(dc);
4007
4008	dc_z10_restore(dc);
4009
4010	top_pipe_to_program = resource_get_otg_master_for_stream(
4011			&context->res_ctx,
4012			stream);
4013
4014	if (!top_pipe_to_program)
4015		return;
4016
4017	for (i = 0; i < dc->res_pool->pipe_count; i++) {
4018		struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
4019
4020		if (pipe->stream && pipe->plane_state) {
4021			if (!dc->debug.using_dml2)
4022				set_p_state_switch_method(dc, context, pipe);
4023
4024			if (dc->debug.visual_confirm)
4025				dc_update_visual_confirm_color(dc, context, pipe);
4026		}
4027	}
4028
4029	for (i = 0; i < surface_count; i++) {
4030		struct dc_plane_state *plane_state = srf_updates[i].surface;
4031		/*set logical flag for lock/unlock use*/
4032		for (j = 0; j < dc->res_pool->pipe_count; j++) {
4033			struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j];
4034
4035			if (!pipe_ctx->plane_state)
4036				continue;
4037			if (!should_update_pipe_for_plane(context, pipe_ctx, plane_state))
4038				continue;
4039
4040			pipe_ctx->plane_state->triplebuffer_flips = false;
4041			if (update_type == UPDATE_TYPE_FAST &&
4042					dc->hwss.program_triplebuffer != NULL &&
4043					!pipe_ctx->plane_state->flip_immediate && dc->debug.enable_tri_buf) {
4044				/*triple buffer for VUpdate only*/
4045				pipe_ctx->plane_state->triplebuffer_flips = true;
4046			}
4047		}
4048	}
4049
4050	stream_status = dc_state_get_stream_status(context, stream);
4051
4052	if (should_offload_fams2_flip) {
4053		commit_plane_for_stream_offload_fams2_flip(dc,
4054				srf_updates,
4055				surface_count,
4056				stream,
4057				context);
4058	} else if (stream_status) {
4059		build_dmub_cmd_list(dc,
4060				srf_updates,
4061				surface_count,
4062				stream,
4063				context,
4064				context->dc_dmub_cmd,
4065				&(context->dmub_cmd_count));
4066		hwss_build_fast_sequence(dc,
4067				context->dc_dmub_cmd,
4068				context->dmub_cmd_count,
4069				context->block_sequence,
4070				&(context->block_sequence_steps),
4071				top_pipe_to_program,
4072				stream_status,
4073				context);
4074		hwss_execute_sequence(dc,
4075				context->block_sequence,
4076				context->block_sequence_steps);
4077	}
4078
4079	/* Clear update flags so next flip doesn't have redundant programming
4080	 * (if there's no stream update, the update flags are not cleared).
4081	 * Surface updates are cleared unconditionally at the beginning of each flip,
4082	 * so no need to clear here.
4083	 */
4084	if (top_pipe_to_program->stream)
4085		top_pipe_to_program->stream->update_flags.raw = 0;
4086}
4087
4088static void commit_planes_for_stream(struct dc *dc,
4089		struct dc_surface_update *srf_updates,
4090		int surface_count,
4091		struct dc_stream_state *stream,
4092		struct dc_stream_update *stream_update,
4093		enum surface_update_type update_type,
4094		struct dc_state *context)
4095{
4096	int i, j;
4097	struct pipe_ctx *top_pipe_to_program = NULL;
4098	bool should_lock_all_pipes = (update_type != UPDATE_TYPE_FAST);
4099	bool subvp_prev_use = false;
4100	bool subvp_curr_use = false;
4101	uint8_t current_stream_mask = 0;
4102
4103	if (should_lock_all_pipes)
4104		determine_pipe_unlock_order(dc, context);
4105	// Once we apply the new subvp context to hardware it won't be in the
4106	// dc->current_state anymore, so we have to cache it before we apply
4107	// the new SubVP context
4108	subvp_prev_use = false;
4109	dc_exit_ips_for_hw_access(dc);
4110
4111	dc_z10_restore(dc);
4112	if (update_type == UPDATE_TYPE_FULL && dc->optimized_required)
4113		hwss_process_outstanding_hw_updates(dc, dc->current_state);
4114
4115	if (update_type != UPDATE_TYPE_FAST && dc->res_pool->funcs->prepare_mcache_programming)
4116		dc->res_pool->funcs->prepare_mcache_programming(dc, context);
4117
4118	for (i = 0; i < dc->res_pool->pipe_count; i++) {
4119		struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
4120
4121		if (pipe->stream && pipe->plane_state) {
4122			if (!dc->debug.using_dml2)
4123				set_p_state_switch_method(dc, context, pipe);
4124
4125			if (dc->debug.visual_confirm)
4126				dc_update_visual_confirm_color(dc, context, pipe);
4127		}
4128	}
4129
4130	if (update_type == UPDATE_TYPE_FULL) {
4131		dc_allow_idle_optimizations(dc, false);
4132
4133		if (get_seamless_boot_stream_count(context) == 0)
4134			dc->hwss.prepare_bandwidth(dc, context);
4135
4136		if (dc->hwss.update_dsc_pg)
4137			dc->hwss.update_dsc_pg(dc, context, false);
4138
4139		context_clock_trace(dc, context);
4140	}
4141
4142	if (update_type == UPDATE_TYPE_FULL)
4143		hwss_wait_for_outstanding_hw_updates(dc, dc->current_state);
4144
4145	top_pipe_to_program = resource_get_otg_master_for_stream(
4146				&context->res_ctx,
4147				stream);
4148	ASSERT(top_pipe_to_program != NULL);
4149
4150	for (i = 0; i < dc->res_pool->pipe_count; i++) {
4151		struct pipe_ctx *old_pipe = &dc->current_state->res_ctx.pipe_ctx[i];
4152
4153		// Check old context for SubVP
4154		subvp_prev_use |= (dc_state_get_pipe_subvp_type(dc->current_state, old_pipe) == SUBVP_PHANTOM);
4155		if (subvp_prev_use)
4156			break;
4157	}
4158
4159	for (i = 0; i < dc->res_pool->pipe_count; i++) {
4160		struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
4161
4162		if (dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_PHANTOM) {
4163			subvp_curr_use = true;
4164			break;
4165		}
4166	}
4167
4168	if (stream->test_pattern.type != DP_TEST_PATTERN_VIDEO_MODE) {
4169		struct pipe_ctx *mpcc_pipe;
4170		struct pipe_ctx *odm_pipe;
4171
4172		for (mpcc_pipe = top_pipe_to_program; mpcc_pipe; mpcc_pipe = mpcc_pipe->bottom_pipe)
4173			for (odm_pipe = mpcc_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
4174				odm_pipe->ttu_regs.min_ttu_vblank = MAX_TTU;
4175	}
4176
4177	if ((update_type != UPDATE_TYPE_FAST) && stream->update_flags.bits.dsc_changed)
4178		if (top_pipe_to_program &&
4179			top_pipe_to_program->stream_res.tg->funcs->lock_doublebuffer_enable) {
4180			if (should_use_dmub_inbox1_lock(dc, stream->link)) {
4181				union dmub_hw_lock_flags hw_locks = { 0 };
4182				struct dmub_hw_lock_inst_flags inst_flags = { 0 };
4183
4184				hw_locks.bits.lock_dig = 1;
4185				inst_flags.dig_inst = top_pipe_to_program->stream_res.tg->inst;
4186
4187				dmub_hw_lock_mgr_cmd(dc->ctx->dmub_srv,
4188							true,
4189							&hw_locks,
4190							&inst_flags);
4191			} else
4192				top_pipe_to_program->stream_res.tg->funcs->lock_doublebuffer_enable(
4193						top_pipe_to_program->stream_res.tg);
4194		}
4195
4196	if (dc->hwss.wait_for_dcc_meta_propagation) {
4197		dc->hwss.wait_for_dcc_meta_propagation(dc, top_pipe_to_program);
4198	}
4199
4200	if (dc->hwseq->funcs.wait_for_pipe_update_if_needed)
4201		dc->hwseq->funcs.wait_for_pipe_update_if_needed(dc, top_pipe_to_program, update_type < UPDATE_TYPE_FULL);
4202
4203	if (should_lock_all_pipes && dc->hwss.interdependent_update_lock) {
4204		if (dc->hwss.subvp_pipe_control_lock)
4205			dc->hwss.subvp_pipe_control_lock(dc, context, true, should_lock_all_pipes, NULL, subvp_prev_use);
4206
4207		if (dc->hwss.dmub_hw_control_lock)
4208			dc->hwss.dmub_hw_control_lock(dc, context, true);
4209
4210		dc->hwss.interdependent_update_lock(dc, context, true);
4211	} else {
4212		if (dc->hwss.subvp_pipe_control_lock)
4213			dc->hwss.subvp_pipe_control_lock(dc, context, true, should_lock_all_pipes, top_pipe_to_program, subvp_prev_use);
4214
4215		if (dc->hwss.dmub_hw_control_lock)
4216			dc->hwss.dmub_hw_control_lock(dc, context, true);
4217
4218		/* Lock the top pipe while updating plane addrs, since freesync requires
4219		 *  plane addr update event triggers to be synchronized.
4220		 *  top_pipe_to_program is expected to never be NULL
4221		 */
4222		dc->hwss.pipe_control_lock(dc, top_pipe_to_program, true);
4223	}
4224
4225	dc_dmub_update_dirty_rect(dc, surface_count, stream, srf_updates, context);
4226
4227	// Stream updates
4228	if (stream_update)
4229		commit_planes_do_stream_update(dc, stream, stream_update, update_type, context);
4230
4231	if (surface_count == 0) {
4232		/*
4233		 * In case of turning off screen, no need to program front end a second time.
4234		 * just return after program blank.
4235		 */
4236		if (dc->hwss.apply_ctx_for_surface)
4237			dc->hwss.apply_ctx_for_surface(dc, stream, 0, context);
4238		if (dc->hwss.program_front_end_for_ctx)
4239			dc->hwss.program_front_end_for_ctx(dc, context);
4240
4241		if (should_lock_all_pipes && dc->hwss.interdependent_update_lock) {
4242			dc->hwss.interdependent_update_lock(dc, context, false);
4243		} else {
4244			dc->hwss.pipe_control_lock(dc, top_pipe_to_program, false);
4245		}
4246		dc->hwss.post_unlock_program_front_end(dc, context);
4247
4248		if (update_type != UPDATE_TYPE_FAST)
4249			if (dc->hwss.commit_subvp_config)
4250				dc->hwss.commit_subvp_config(dc, context);
4251
4252		/* Since phantom pipe programming is moved to post_unlock_program_front_end,
4253		 * move the SubVP lock to after the phantom pipes have been setup
4254		 */
4255		if (dc->hwss.subvp_pipe_control_lock)
4256			dc->hwss.subvp_pipe_control_lock(dc, context, false, should_lock_all_pipes,
4257							 NULL, subvp_prev_use);
4258
4259		if (dc->hwss.dmub_hw_control_lock)
4260			dc->hwss.dmub_hw_control_lock(dc, context, false);
4261		return;
4262	}
4263
4264	if (update_type != UPDATE_TYPE_FAST) {
4265		for (j = 0; j < dc->res_pool->pipe_count; j++) {
4266			struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j];
4267
4268			if ((dc->debug.visual_confirm == VISUAL_CONFIRM_SUBVP ||
4269				dc->debug.visual_confirm == VISUAL_CONFIRM_MCLK_SWITCH) &&
4270				pipe_ctx->stream && pipe_ctx->plane_state) {
4271				/* Only update visual confirm for SUBVP and Mclk switching here.
4272				 * The bar appears on all pipes, so we need to update the bar on all displays,
4273				 * so the information doesn't get stale.
4274				 */
4275				dc->hwss.update_visual_confirm_color(dc, pipe_ctx,
4276						pipe_ctx->plane_res.hubp->inst);
4277			}
4278		}
4279	}
4280
4281	for (i = 0; i < surface_count; i++) {
4282		struct dc_plane_state *plane_state = srf_updates[i].surface;
4283
4284		/*set logical flag for lock/unlock use*/
4285		for (j = 0; j < dc->res_pool->pipe_count; j++) {
4286			struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j];
4287			if (!pipe_ctx->plane_state)
4288				continue;
4289			if (!should_update_pipe_for_plane(context, pipe_ctx, plane_state))
4290				continue;
4291			pipe_ctx->plane_state->triplebuffer_flips = false;
4292			if (update_type == UPDATE_TYPE_FAST &&
4293					dc->hwss.program_triplebuffer != NULL &&
4294					!pipe_ctx->plane_state->flip_immediate && dc->debug.enable_tri_buf) {
4295				/*triple buffer for VUpdate only*/
4296				pipe_ctx->plane_state->triplebuffer_flips = true;
4297			}
4298		}
4299		if (update_type == UPDATE_TYPE_FULL) {
4300			/* force vsync flip when reconfiguring pipes to prevent underflow */
4301			plane_state->flip_immediate = false;
4302			plane_state->triplebuffer_flips = false;
4303		}
4304	}
4305
4306	// Update Type FULL, Surface updates
4307	for (j = 0; j < dc->res_pool->pipe_count; j++) {
4308		struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j];
4309
4310		if (!pipe_ctx->top_pipe &&
4311			!pipe_ctx->prev_odm_pipe &&
4312			should_update_pipe_for_stream(context, pipe_ctx, stream)) {
4313			struct dc_stream_status *stream_status = NULL;
4314
4315			if (!pipe_ctx->plane_state)
4316				continue;
4317
4318			/* Full fe update*/
4319			if (update_type == UPDATE_TYPE_FAST)
4320				continue;
4321
4322			stream_status =
4323				stream_get_status(context, pipe_ctx->stream);
4324
4325			if (dc->hwss.apply_ctx_for_surface && stream_status)
4326				dc->hwss.apply_ctx_for_surface(
4327					dc, pipe_ctx->stream, stream_status->plane_count, context);
4328		}
4329	}
4330
4331	for (j = 0; j < dc->res_pool->pipe_count; j++) {
4332		struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j];
4333
4334		if (!pipe_ctx->plane_state)
4335			continue;
4336
4337		/* Full fe update*/
4338		if (update_type == UPDATE_TYPE_FAST)
4339			continue;
4340
4341		ASSERT(!pipe_ctx->plane_state->triplebuffer_flips);
4342		if (dc->hwss.program_triplebuffer != NULL && dc->debug.enable_tri_buf) {
4343			/*turn off triple buffer for full update*/
4344			dc->hwss.program_triplebuffer(
4345				dc, pipe_ctx, pipe_ctx->plane_state->triplebuffer_flips);
4346		}
4347	}
4348
4349	if (dc->hwss.program_front_end_for_ctx && update_type != UPDATE_TYPE_FAST) {
4350		dc->hwss.program_front_end_for_ctx(dc, context);
4351
4352		//Pipe busy until some frame and line #
4353		if (dc->hwseq->funcs.set_wait_for_update_needed_for_pipe && update_type == UPDATE_TYPE_FULL) {
4354			for (j = 0; j < dc->res_pool->pipe_count; j++) {
4355				struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j];
4356
4357				dc->hwseq->funcs.set_wait_for_update_needed_for_pipe(dc, pipe_ctx);
4358			}
4359		}
4360
4361		if (dc->debug.validate_dml_output) {
4362			for (i = 0; i < dc->res_pool->pipe_count; i++) {
4363				struct pipe_ctx *cur_pipe = &context->res_ctx.pipe_ctx[i];
4364				if (cur_pipe->stream == NULL)
4365					continue;
4366
4367				cur_pipe->plane_res.hubp->funcs->validate_dml_output(
4368						cur_pipe->plane_res.hubp, dc->ctx,
4369						&context->res_ctx.pipe_ctx[i].rq_regs,
4370						&context->res_ctx.pipe_ctx[i].dlg_regs,
4371						&context->res_ctx.pipe_ctx[i].ttu_regs);
4372			}
4373		}
4374	}
4375
4376	// Update Type FAST, Surface updates
4377	if (update_type == UPDATE_TYPE_FAST) {
4378		if (dc->hwss.set_flip_control_gsl)
4379			for (i = 0; i < surface_count; i++) {
4380				struct dc_plane_state *plane_state = srf_updates[i].surface;
4381
4382				for (j = 0; j < dc->res_pool->pipe_count; j++) {
4383					struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j];
4384
4385					if (!should_update_pipe_for_stream(context, pipe_ctx, stream))
4386						continue;
4387
4388					if (!should_update_pipe_for_plane(context, pipe_ctx, plane_state))
4389						continue;
4390
4391					// GSL has to be used for flip immediate
4392					dc->hwss.set_flip_control_gsl(pipe_ctx,
4393							pipe_ctx->plane_state->flip_immediate);
4394				}
4395			}
4396
4397		/* Perform requested Updates */
4398		for (i = 0; i < surface_count; i++) {
4399			struct dc_plane_state *plane_state = srf_updates[i].surface;
4400
4401			for (j = 0; j < dc->res_pool->pipe_count; j++) {
4402				struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j];
4403
4404				if (!should_update_pipe_for_stream(context, pipe_ctx, stream))
4405					continue;
4406
4407				if (!should_update_pipe_for_plane(context, pipe_ctx, plane_state))
4408					continue;
4409
4410				if (srf_updates[i].cm2_params &&
4411						srf_updates[i].cm2_params->cm2_luts.lut3d_data.lut3d_src ==
4412								DC_CM2_TRANSFER_FUNC_SOURCE_VIDMEM &&
4413						srf_updates[i].cm2_params->component_settings.shaper_3dlut_setting ==
4414								DC_CM2_SHAPER_3DLUT_SETTING_ENABLE_SHAPER_3DLUT &&
4415						dc->hwss.trigger_3dlut_dma_load)
4416					dc->hwss.trigger_3dlut_dma_load(dc, pipe_ctx);
4417
4418				/*program triple buffer after lock based on flip type*/
4419				if (dc->hwss.program_triplebuffer != NULL && dc->debug.enable_tri_buf) {
4420					/*only enable triplebuffer for fast_update*/
4421					dc->hwss.program_triplebuffer(
4422						dc, pipe_ctx, pipe_ctx->plane_state->triplebuffer_flips);
4423				}
4424				if (pipe_ctx->plane_state->update_flags.bits.addr_update)
4425					dc->hwss.update_plane_addr(dc, pipe_ctx);
4426			}
4427		}
4428	}
4429
4430	if (should_lock_all_pipes && dc->hwss.interdependent_update_lock) {
4431		dc->hwss.interdependent_update_lock(dc, context, false);
4432	} else {
4433		dc->hwss.pipe_control_lock(dc, top_pipe_to_program, false);
4434	}
4435
4436	if ((update_type != UPDATE_TYPE_FAST) && stream->update_flags.bits.dsc_changed)
4437		if (top_pipe_to_program &&
4438		    top_pipe_to_program->stream_res.tg->funcs->lock_doublebuffer_enable) {
4439			top_pipe_to_program->stream_res.tg->funcs->wait_for_state(
4440				top_pipe_to_program->stream_res.tg,
4441				CRTC_STATE_VACTIVE);
4442			top_pipe_to_program->stream_res.tg->funcs->wait_for_state(
4443				top_pipe_to_program->stream_res.tg,
4444				CRTC_STATE_VBLANK);
4445			top_pipe_to_program->stream_res.tg->funcs->wait_for_state(
4446				top_pipe_to_program->stream_res.tg,
4447				CRTC_STATE_VACTIVE);
4448
4449			if (should_use_dmub_inbox1_lock(dc, stream->link)) {
4450				union dmub_hw_lock_flags hw_locks = { 0 };
4451				struct dmub_hw_lock_inst_flags inst_flags = { 0 };
4452
4453				hw_locks.bits.lock_dig = 1;
4454				inst_flags.dig_inst = top_pipe_to_program->stream_res.tg->inst;
4455
4456				dmub_hw_lock_mgr_cmd(dc->ctx->dmub_srv,
4457							false,
4458							&hw_locks,
4459							&inst_flags);
4460			} else
4461				top_pipe_to_program->stream_res.tg->funcs->lock_doublebuffer_disable(
4462					top_pipe_to_program->stream_res.tg);
4463		}
4464
4465	if (subvp_curr_use) {
4466		/* If enabling subvp or transitioning from subvp->subvp, enable the
4467		 * phantom streams before we program front end for the phantom pipes.
4468		 */
4469		if (update_type != UPDATE_TYPE_FAST) {
4470			if (dc->hwss.enable_phantom_streams)
4471				dc->hwss.enable_phantom_streams(dc, context);
4472		}
4473	}
4474
4475	if (update_type != UPDATE_TYPE_FAST)
4476		dc->hwss.post_unlock_program_front_end(dc, context);
4477
4478	if (subvp_prev_use && !subvp_curr_use) {
4479		/* If disabling subvp, disable phantom streams after front end
4480		 * programming has completed (we turn on phantom OTG in order
4481		 * to complete the plane disable for phantom pipes).
4482		 */
4483
4484		if (dc->hwss.disable_phantom_streams)
4485			dc->hwss.disable_phantom_streams(dc, context);
4486	}
4487
4488	if (update_type != UPDATE_TYPE_FAST)
4489		if (dc->hwss.commit_subvp_config)
4490			dc->hwss.commit_subvp_config(dc, context);
4491	/* Since phantom pipe programming is moved to post_unlock_program_front_end,
4492	 * move the SubVP lock to after the phantom pipes have been setup
4493	 */
4494	if (should_lock_all_pipes && dc->hwss.interdependent_update_lock) {
4495		if (dc->hwss.subvp_pipe_control_lock)
4496			dc->hwss.subvp_pipe_control_lock(dc, context, false, should_lock_all_pipes, NULL, subvp_prev_use);
4497		if (dc->hwss.dmub_hw_control_lock)
4498			dc->hwss.dmub_hw_control_lock(dc, context, false);
4499	} else {
4500		if (dc->hwss.subvp_pipe_control_lock)
4501			dc->hwss.subvp_pipe_control_lock(dc, context, false, should_lock_all_pipes, top_pipe_to_program, subvp_prev_use);
4502		if (dc->hwss.dmub_hw_control_lock)
4503			dc->hwss.dmub_hw_control_lock(dc, context, false);
4504	}
4505
4506	// Fire manual trigger only when bottom plane is flipped
4507	for (j = 0; j < dc->res_pool->pipe_count; j++) {
4508		struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j];
4509
4510		if (!pipe_ctx->plane_state)
4511			continue;
4512
4513		if (pipe_ctx->bottom_pipe || pipe_ctx->next_odm_pipe ||
4514				!pipe_ctx->stream || !should_update_pipe_for_stream(context, pipe_ctx, stream) ||
4515				!pipe_ctx->plane_state->update_flags.bits.addr_update ||
4516				pipe_ctx->plane_state->skip_manual_trigger)
4517			continue;
4518
4519		if (dc->hwss.program_cursor_offload_now)
4520			dc->hwss.program_cursor_offload_now(dc, pipe_ctx);
4521		if (pipe_ctx->stream_res.tg->funcs->program_manual_trigger)
4522			pipe_ctx->stream_res.tg->funcs->program_manual_trigger(pipe_ctx->stream_res.tg);
4523	}
4524
4525	current_stream_mask = get_stream_mask(dc, context);
4526	if (current_stream_mask != context->stream_mask) {
4527		context->stream_mask = current_stream_mask;
4528		dc_dmub_srv_notify_stream_mask(dc->ctx->dmub_srv, current_stream_mask);
4529	}
4530}
4531
4532/**
4533 * could_mpcc_tree_change_for_active_pipes - Check if an OPP associated with MPCC might change
4534 *
4535 * @dc: Used to get the current state status
4536 * @stream: Target stream, which we want to remove the attached planes
4537 * @srf_updates: Array of surface updates
4538 * @surface_count: Number of surface update
4539 * @is_plane_addition: [in] Fill out with true if it is a plane addition case
4540 *
4541 * DCN32x and newer support a feature named Dynamic ODM which can conflict with
4542 * the MPO if used simultaneously in some specific configurations (e.g.,
4543 * 4k@144). This function checks if the incoming context requires applying a
4544 * transition state with unnecessary pipe splitting and ODM disabled to
4545 * circumvent our hardware limitations to prevent this edge case. If the OPP
4546 * associated with an MPCC might change due to plane additions, this function
4547 * returns true.
4548 *
4549 * Return:
4550 * Return true if OPP and MPCC might change, otherwise, return false.
4551 */
4552static bool could_mpcc_tree_change_for_active_pipes(struct dc *dc,
4553		struct dc_stream_state *stream,
4554		struct dc_surface_update *srf_updates,
4555		int surface_count,
4556		bool *is_plane_addition)
4557{
4558
4559	struct dc_stream_status *cur_stream_status = stream_get_status(dc->current_state, stream);
4560	bool force_minimal_pipe_splitting = false;
4561	bool subvp_active = false;
4562	uint32_t i;
4563
4564	*is_plane_addition = false;
4565
4566	if (cur_stream_status &&
4567			dc->current_state->stream_count > 0 &&
4568			dc->debug.pipe_split_policy != MPC_SPLIT_AVOID) {
4569		/* determine if minimal transition is required due to MPC*/
4570		if (surface_count > 0) {
4571			if (cur_stream_status->plane_count > surface_count) {
4572				force_minimal_pipe_splitting = true;
4573			} else if (cur_stream_status->plane_count < surface_count) {
4574				force_minimal_pipe_splitting = true;
4575				*is_plane_addition = true;
4576			}
4577		}
4578	}
4579
4580	if (cur_stream_status &&
4581			dc->current_state->stream_count == 1 &&
4582			dc->debug.enable_single_display_2to1_odm_policy) {
4583		/* determine if minimal transition is required due to dynamic ODM*/
4584		if (surface_count > 0) {
4585			if (cur_stream_status->plane_count > 2 && cur_stream_status->plane_count > surface_count) {
4586				force_minimal_pipe_splitting = true;
4587			} else if (surface_count > 2 && cur_stream_status->plane_count < surface_count) {
4588				force_minimal_pipe_splitting = true;
4589				*is_plane_addition = true;
4590			}
4591		}
4592	}
4593
4594	for (i = 0; i < dc->res_pool->pipe_count; i++) {
4595		struct pipe_ctx *pipe = &dc->current_state->res_ctx.pipe_ctx[i];
4596
4597		if (dc_state_get_pipe_subvp_type(dc->current_state, pipe) != SUBVP_NONE) {
4598			subvp_active = true;
4599			break;
4600		}
4601	}
4602
4603	/* For SubVP when adding or removing planes we need to add a minimal transition
4604	 * (even when disabling all planes). Whenever disabling a phantom pipe, we
4605	 * must use the minimal transition path to disable the pipe correctly.
4606	 *
4607	 * We want to use the minimal transition whenever subvp is active, not only if
4608	 * a plane is being added / removed from a subvp stream (MPO plane can be added
4609	 * to a DRR pipe of SubVP + DRR config, in which case we still want to run through
4610	 * a min transition to disable subvp.
4611	 */
4612	if (cur_stream_status && subvp_active) {
4613		/* determine if minimal transition is required due to SubVP*/
4614		if (cur_stream_status->plane_count > surface_count) {
4615			force_minimal_pipe_splitting = true;
4616		} else if (cur_stream_status->plane_count < surface_count) {
4617			force_minimal_pipe_splitting = true;
4618			*is_plane_addition = true;
4619		}
4620	}
4621
4622	return force_minimal_pipe_splitting;
4623}
4624
4625struct pipe_split_policy_backup {
4626	bool dynamic_odm_policy;
4627	bool subvp_policy;
4628	enum pipe_split_policy mpc_policy;
4629	char force_odm[MAX_PIPES];
4630};
4631
4632static void backup_and_set_minimal_pipe_split_policy(struct dc *dc,
4633		struct dc_state *context,
4634		struct pipe_split_policy_backup *policy)
4635{
4636	int i;
4637
4638	if (!dc->config.is_vmin_only_asic) {
4639		policy->mpc_policy = dc->debug.pipe_split_policy;
4640		dc->debug.pipe_split_policy = MPC_SPLIT_AVOID;
4641	}
4642	policy->dynamic_odm_policy = dc->debug.enable_single_display_2to1_odm_policy;
4643	dc->debug.enable_single_display_2to1_odm_policy = false;
4644	policy->subvp_policy = dc->debug.force_disable_subvp;
4645	dc->debug.force_disable_subvp = true;
4646	for (i = 0; i < context->stream_count; i++) {
4647		policy->force_odm[i] = context->streams[i]->debug.force_odm_combine_segments;
4648		if (context->streams[i]->debug.allow_transition_for_forced_odm)
4649			context->streams[i]->debug.force_odm_combine_segments = 0;
4650	}
4651}
4652
4653static void restore_minimal_pipe_split_policy(struct dc *dc,
4654		struct dc_state *context,
4655		struct pipe_split_policy_backup *policy)
4656{
4657	uint8_t i;
4658
4659	if (!dc->config.is_vmin_only_asic)
4660		dc->debug.pipe_split_policy = policy->mpc_policy;
4661	dc->debug.enable_single_display_2to1_odm_policy =
4662			policy->dynamic_odm_policy;
4663	dc->debug.force_disable_subvp = policy->subvp_policy;
4664	for (i = 0; i < context->stream_count; i++)
4665		context->streams[i]->debug.force_odm_combine_segments = policy->force_odm[i];
4666}
4667
4668static void release_minimal_transition_state(struct dc *dc,
4669		struct dc_state *minimal_transition_context,
4670		struct dc_state *base_context,
4671		struct pipe_split_policy_backup *policy)
4672{
4673	restore_minimal_pipe_split_policy(dc, base_context, policy);
4674	dc_state_release(minimal_transition_context);
4675}
4676
4677static void force_vsync_flip_in_minimal_transition_context(struct dc_state *context)
4678{
4679	uint8_t i;
4680	int j;
4681	struct dc_stream_status *stream_status;
4682
4683	for (i = 0; i < context->stream_count; i++) {
4684		stream_status = &context->stream_status[i];
4685
4686		for (j = 0; j < stream_status->plane_count; j++)
4687			stream_status->plane_states[j]->flip_immediate = false;
4688	}
4689}
4690
4691static struct dc_state *create_minimal_transition_state(struct dc *dc,
4692		struct dc_state *base_context, struct pipe_split_policy_backup *policy)
4693{
4694	struct dc_state *minimal_transition_context = NULL;
4695
4696	minimal_transition_context = dc_state_create_copy(base_context);
4697	if (!minimal_transition_context)
4698		return NULL;
4699
4700	backup_and_set_minimal_pipe_split_policy(dc, base_context, policy);
4701	/* commit minimal state */
4702	if (dc->res_pool->funcs->validate_bandwidth(dc, minimal_transition_context,
4703		DC_VALIDATE_MODE_AND_PROGRAMMING) == DC_OK) {
4704		/* prevent underflow and corruption when reconfiguring pipes */
4705		force_vsync_flip_in_minimal_transition_context(minimal_transition_context);
4706	} else {
4707		/*
4708		 * This should never happen, minimal transition state should
4709		 * always be validated first before adding pipe split features.
4710		 */
4711		release_minimal_transition_state(dc, minimal_transition_context, base_context, policy);
4712		BREAK_TO_DEBUGGER();
4713		minimal_transition_context = NULL;
4714	}
4715	return minimal_transition_context;
4716}
4717
4718static bool is_pipe_topology_transition_seamless_with_intermediate_step(
4719		struct dc *dc,
4720		struct dc_state *initial_state,
4721		struct dc_state *intermediate_state,
4722		struct dc_state *final_state)
4723{
4724	return dc->hwss.is_pipe_topology_transition_seamless(dc, initial_state,
4725			intermediate_state) &&
4726			dc->hwss.is_pipe_topology_transition_seamless(dc,
4727					intermediate_state, final_state);
4728}
4729
4730static void swap_and_release_current_context(struct dc *dc,
4731		struct dc_state *new_context, struct dc_stream_state *stream)
4732{
4733
4734	int i;
4735	struct dc_state *old = dc->current_state;
4736	struct pipe_ctx *pipe_ctx;
4737
4738	/* Since memory free requires elevated IRQ, an interrupt
4739	 * request is generated by mem free. If this happens
4740	 * between freeing and reassigning the context, our vsync
4741	 * interrupt will call into dc and cause a memory
4742	 * corruption. Hence, we first reassign the context,
4743	 * then free the old context.
4744	 */
4745	dc->current_state = new_context;
4746	dc_state_release(old);
4747
4748	// clear any forced full updates
4749	for (i = 0; i < dc->res_pool->pipe_count; i++) {
4750		pipe_ctx = &new_context->res_ctx.pipe_ctx[i];
4751
4752		if (pipe_ctx->plane_state && pipe_ctx->stream == stream)
4753			pipe_ctx->plane_state->force_full_update = false;
4754	}
4755}
4756
4757static int initialize_empty_surface_updates(
4758		struct dc_stream_state *stream,
4759		struct dc_surface_update *srf_updates)
4760{
4761	struct dc_stream_status *status = dc_stream_get_status(stream);
4762	int i;
4763
4764	if (!status)
4765		return 0;
4766
4767	for (i = 0; i < status->plane_count; i++)
4768		srf_updates[i].surface = status->plane_states[i];
4769
4770	return status->plane_count;
4771}
4772
4773static bool commit_minimal_transition_based_on_new_context(struct dc *dc,
4774		struct dc_state *new_context,
4775		struct dc_stream_state *stream,
4776		struct dc_surface_update *srf_updates,
4777		int surface_count)
4778{
4779	bool success = false;
4780	struct pipe_split_policy_backup policy;
4781	struct dc_state *intermediate_context =
4782			create_minimal_transition_state(dc, new_context,
4783					&policy);
4784
4785	if (intermediate_context) {
4786		if (is_pipe_topology_transition_seamless_with_intermediate_step(
4787				dc,
4788				dc->current_state,
4789				intermediate_context,
4790				new_context)) {
4791			DC_LOG_DC("commit minimal transition state: base = new state\n");
4792			commit_planes_for_stream(dc, srf_updates,
4793					surface_count, stream, NULL,
4794					UPDATE_TYPE_FULL, intermediate_context);
4795			swap_and_release_current_context(
4796					dc, intermediate_context, stream);
4797			dc_state_retain(dc->current_state);
4798			success = true;
4799		}
4800		release_minimal_transition_state(
4801				dc, intermediate_context, new_context, &policy);
4802	}
4803	return success;
4804}
4805
4806static bool commit_minimal_transition_based_on_current_context(struct dc *dc,
4807		struct dc_state *new_context, struct dc_stream_state *stream)
4808{
4809	bool success = false;
4810	struct pipe_split_policy_backup policy;
4811	struct dc_state *intermediate_context;
4812	struct dc_state *old_current_state = dc->current_state;
4813	struct dc_surface_update srf_updates[MAX_SURFACES] = {0};
4814	int surface_count;
4815
4816	/*
4817	 * Both current and new contexts share the same stream and plane state
4818	 * pointers. When new context is validated, stream and planes get
4819	 * populated with new updates such as new plane addresses. This makes
4820	 * the current context no longer valid because stream and planes are
4821	 * modified from the original. We backup current stream and plane states
4822	 * into scratch space whenever we are populating new context. So we can
4823	 * restore the original values back by calling the restore function now.
4824	 * This restores back the original stream and plane states associated
4825	 * with the current state.
4826	 */
4827	restore_planes_and_stream_state(&dc->scratch.current_state, stream);
4828	dc_state_retain(old_current_state);
4829	intermediate_context = create_minimal_transition_state(dc,
4830			old_current_state, &policy);
4831
4832	if (intermediate_context) {
4833		if (is_pipe_topology_transition_seamless_with_intermediate_step(
4834				dc,
4835				dc->current_state,
4836				intermediate_context,
4837				new_context)) {
4838			DC_LOG_DC("commit minimal transition state: base = current state\n");
4839			surface_count = initialize_empty_surface_updates(
4840					stream, srf_updates);
4841			commit_planes_for_stream(dc, srf_updates,
4842					surface_count, stream, NULL,
4843					UPDATE_TYPE_FULL, intermediate_context);
4844			swap_and_release_current_context(
4845					dc, intermediate_context, stream);
4846			dc_state_retain(dc->current_state);
4847			success = true;
4848		}
4849		release_minimal_transition_state(dc, intermediate_context,
4850				old_current_state, &policy);
4851	}
4852	dc_state_release(old_current_state);
4853	/*
4854	 * Restore stream and plane states back to the values associated with
4855	 * new context.
4856	 */
4857	restore_planes_and_stream_state(&dc->scratch.new_state, stream);
4858	return success;
4859}
4860
4861/**
4862 * commit_minimal_transition_state_in_dc_update - Commit a minimal state based
4863 * on current or new context
4864 *
4865 * @dc: DC structure, used to get the current state
4866 * @new_context: New context
4867 * @stream: Stream getting the update for the flip
4868 * @srf_updates: Surface updates
4869 * @surface_count: Number of surfaces
4870 *
4871 * The function takes in current state and new state and determine a minimal
4872 * transition state as the intermediate step which could make the transition
4873 * between current and new states seamless. If found, it will commit the minimal
4874 * transition state and update current state to this minimal transition state
4875 * and return true, if not, it will return false.
4876 *
4877 * Return:
4878 * Return True if the minimal transition succeeded, false otherwise
4879 */
4880static bool commit_minimal_transition_state_in_dc_update(struct dc *dc,
4881		struct dc_state *new_context,
4882		struct dc_stream_state *stream,
4883		struct dc_surface_update *srf_updates,
4884		int surface_count)
4885{
4886	bool success = commit_minimal_transition_based_on_new_context(
4887				dc, new_context, stream, srf_updates,
4888				surface_count);
4889	if (!success)
4890		success = commit_minimal_transition_based_on_current_context(dc,
4891				new_context, stream);
4892	if (!success)
4893		DC_LOG_ERROR("Fail to commit a seamless minimal transition state between current and new states.\nThis pipe topology update is non-seamless!\n");
4894	return success;
4895}
4896
4897/**
4898 * commit_minimal_transition_state - Create a transition pipe split state
4899 *
4900 * @dc: Used to get the current state status
4901 * @transition_base_context: New transition state
4902 *
4903 * In some specific configurations, such as pipe split on multi-display with
4904 * MPO and/or Dynamic ODM, removing a plane may cause unsupported pipe
4905 * programming when moving to new planes. To mitigate those types of problems,
4906 * this function adds a transition state that minimizes pipe usage before
4907 * programming the new configuration. When adding a new plane, the current
4908 * state requires the least pipes, so it is applied without splitting. When
4909 * removing a plane, the new state requires the least pipes, so it is applied
4910 * without splitting.
4911 *
4912 * Return:
4913 * Return false if something is wrong in the transition state.
4914 */
4915static bool commit_minimal_transition_state(struct dc *dc,
4916		struct dc_state *transition_base_context)
4917{
4918	struct dc_state *transition_context;
4919	struct pipe_split_policy_backup policy;
4920	enum dc_status ret = DC_ERROR_UNEXPECTED;
4921	unsigned int i, j;
4922	unsigned int pipe_in_use = 0;
4923	bool subvp_in_use = false;
4924	bool odm_in_use = false;
4925
4926	/* check current pipes in use*/
4927	for (i = 0; i < dc->res_pool->pipe_count; i++) {
4928		struct pipe_ctx *pipe = &transition_base_context->res_ctx.pipe_ctx[i];
4929
4930		if (pipe->plane_state)
4931			pipe_in_use++;
4932	}
4933
4934	/* If SubVP is enabled and we are adding or removing planes from any main subvp
4935	 * pipe, we must use the minimal transition.
4936	 */
4937	for (i = 0; i < dc->res_pool->pipe_count; i++) {
4938		struct pipe_ctx *pipe = &dc->current_state->res_ctx.pipe_ctx[i];
4939
4940		if (pipe->stream && dc_state_get_pipe_subvp_type(dc->current_state, pipe) == SUBVP_PHANTOM) {
4941			subvp_in_use = true;
4942			break;
4943		}
4944	}
4945
4946	/* If ODM is enabled and we are adding or removing planes from any ODM
4947	 * pipe, we must use the minimal transition.
4948	 */
4949	for (i = 0; i < dc->res_pool->pipe_count; i++) {
4950		struct pipe_ctx *pipe = &transition_base_context->res_ctx.pipe_ctx[i];
4951
4952		if (resource_is_pipe_type(pipe, OTG_MASTER)) {
4953			odm_in_use = resource_get_odm_slice_count(pipe) > 1;
4954			break;
4955		}
4956	}
4957
4958	/* When the OS add a new surface if we have been used all of pipes with odm combine
4959	 * and mpc split feature, it need use commit_minimal_transition_state to transition safely.
4960	 * After OS exit MPO, it will back to use odm and mpc split with all of pipes, we need
4961	 * call it again. Otherwise return true to skip.
4962	 *
4963	 * Reduce the scenarios to use dc_commit_state_no_check in the stage of flip. Especially
4964	 * enter/exit MPO when DCN still have enough resources.
4965	 */
4966	if (pipe_in_use != dc->res_pool->pipe_count && !subvp_in_use && !odm_in_use)
4967		return true;
4968
4969	DC_LOG_DC("%s base = %s state, reason = %s\n", __func__,
4970			dc->current_state == transition_base_context ? "current" : "new",
4971			subvp_in_use ? "Subvp In Use" :
4972			odm_in_use ? "ODM in Use" :
4973			dc->debug.pipe_split_policy != MPC_SPLIT_AVOID ? "MPC in Use" :
4974			"Unknown");
4975
4976	dc_state_retain(transition_base_context);
4977	transition_context = create_minimal_transition_state(dc,
4978			transition_base_context, &policy);
4979	if (transition_context) {
4980		ret = dc_commit_state_no_check(dc, transition_context);
4981		release_minimal_transition_state(dc, transition_context, transition_base_context, &policy);
4982	}
4983	dc_state_release(transition_base_context);
4984
4985	if (ret != DC_OK) {
4986		/* this should never happen */
4987		BREAK_TO_DEBUGGER();
4988		return false;
4989	}
4990
4991	/* force full surface update */
4992	for (i = 0; i < dc->current_state->stream_count; i++) {
4993		for (j = 0; j < dc->current_state->stream_status[i].plane_count; j++) {
4994			dc->current_state->stream_status[i].plane_states[j]->update_flags.raw = 0xFFFFFFFF;
4995		}
4996	}
4997
4998	return true;
4999}
5000
5001void populate_fast_updates(struct dc_fast_update *fast_update,
5002		struct dc_surface_update *srf_updates,
5003		int surface_count,
5004		struct dc_stream_update *stream_update)
5005{
5006	int i = 0;
5007
5008	if (stream_update) {
5009		fast_update[0].out_transfer_func = stream_update->out_transfer_func;
5010		fast_update[0].output_csc_transform = stream_update->output_csc_transform;
5011	} else {
5012		fast_update[0].out_transfer_func = NULL;
5013		fast_update[0].output_csc_transform = NULL;
5014	}
5015
5016	for (i = 0; i < surface_count; i++) {
5017		fast_update[i].flip_addr = srf_updates[i].flip_addr;
5018		fast_update[i].gamma = srf_updates[i].gamma;
5019		fast_update[i].gamut_remap_matrix = srf_updates[i].gamut_remap_matrix;
5020		fast_update[i].input_csc_color_matrix = srf_updates[i].input_csc_color_matrix;
5021		fast_update[i].coeff_reduction_factor = srf_updates[i].coeff_reduction_factor;
5022		fast_update[i].cursor_csc_color_matrix = srf_updates[i].cursor_csc_color_matrix;
5023	}
5024}
5025
5026static bool fast_updates_exist(const struct dc_fast_update *fast_update, int surface_count)
5027{
5028	int i;
5029
5030	if (fast_update[0].out_transfer_func ||
5031		fast_update[0].output_csc_transform)
5032		return true;
5033
5034	for (i = 0; i < surface_count; i++) {
5035		if (fast_update[i].flip_addr ||
5036				fast_update[i].gamma ||
5037				fast_update[i].gamut_remap_matrix ||
5038				fast_update[i].input_csc_color_matrix ||
5039				fast_update[i].cursor_csc_color_matrix ||
5040				fast_update[i].coeff_reduction_factor)
5041			return true;
5042	}
5043
5044	return false;
5045}
5046
5047bool fast_nonaddr_updates_exist(struct dc_fast_update *fast_update, int surface_count)
5048{
5049	int i;
5050
5051	if (fast_update[0].out_transfer_func ||
5052		fast_update[0].output_csc_transform)
5053		return true;
5054
5055	for (i = 0; i < surface_count; i++) {
5056		if (fast_update[i].input_csc_color_matrix ||
5057				fast_update[i].gamma ||
5058				fast_update[i].gamut_remap_matrix ||
5059				fast_update[i].coeff_reduction_factor ||
5060				fast_update[i].cursor_csc_color_matrix)
5061			return true;
5062	}
5063
5064	return false;
5065}
5066
5067static bool full_update_required_weak(
5068		const struct dc *dc,
5069		const struct dc_surface_update *srf_updates,
5070		int surface_count,
5071		const struct dc_stream_update *stream_update,
5072		const struct dc_stream_state *stream)
5073{
5074	const struct dc_state *context = dc->current_state;
5075	if (srf_updates)
5076		for (int i = 0; i < surface_count; i++)
5077			if (!is_surface_in_context(context, srf_updates[i].surface))
5078				return true;
5079
5080	if (stream) {
5081		const struct dc_stream_status *stream_status = dc_stream_get_status_const(stream);
5082		if (stream_status == NULL || stream_status->plane_count != surface_count)
5083			return true;
5084	}
5085	if (dc->idle_optimizations_allowed)
5086		return true;
5087
5088	if (dc_can_clear_cursor_limit(dc))
5089		return true;
5090
5091	return false;
5092}
5093
5094static bool full_update_required(
5095		const struct dc *dc,
5096		const struct dc_surface_update *srf_updates,
5097		int surface_count,
5098		const struct dc_stream_update *stream_update,
5099		const struct dc_stream_state *stream)
5100{
5101	if (full_update_required_weak(dc, srf_updates, surface_count, stream_update, stream))
5102		return true;
5103
5104	for (int i = 0; i < surface_count; i++) {
5105		if (srf_updates &&
5106				(srf_updates[i].plane_info ||
5107				srf_updates[i].scaling_info ||
5108				(srf_updates[i].hdr_mult.value &&
5109				srf_updates[i].hdr_mult.value != srf_updates->surface->hdr_mult.value) ||
5110				(srf_updates[i].sdr_white_level_nits &&
5111				srf_updates[i].sdr_white_level_nits != srf_updates->surface->sdr_white_level_nits) ||
5112				srf_updates[i].in_transfer_func ||
5113				srf_updates[i].func_shaper ||
5114				srf_updates[i].lut3d_func ||
5115				srf_updates[i].surface->force_full_update ||
5116				(srf_updates[i].flip_addr &&
5117				srf_updates[i].flip_addr->address.tmz_surface != srf_updates[i].surface->address.tmz_surface) ||
5118				(srf_updates[i].cm2_params &&
5119				 (srf_updates[i].cm2_params->component_settings.shaper_3dlut_setting != srf_updates[i].surface->mcm_shaper_3dlut_setting ||
5120				  srf_updates[i].cm2_params->component_settings.lut1d_enable != srf_updates[i].surface->mcm_lut1d_enable))))
5121			return true;
5122	}
5123
5124	if (stream_update &&
5125			(((stream_update->src.height != 0 && stream_update->src.width != 0) ||
5126			(stream_update->dst.height != 0 && stream_update->dst.width != 0) ||
5127			stream_update->integer_scaling_update) ||
5128			stream_update->hdr_static_metadata ||
5129			stream_update->abm_level ||
5130			stream_update->periodic_interrupt ||
5131			stream_update->vrr_infopacket ||
5132			stream_update->vsc_infopacket ||
5133			stream_update->vsp_infopacket ||
5134			stream_update->hfvsif_infopacket ||
5135			stream_update->vtem_infopacket ||
5136			stream_update->adaptive_sync_infopacket ||
5137			stream_update->avi_infopacket ||
5138			stream_update->dpms_off ||
5139			stream_update->allow_freesync ||
5140			stream_update->vrr_active_variable ||
5141			stream_update->vrr_active_fixed ||
5142			stream_update->gamut_remap ||
5143			stream_update->output_color_space ||
5144			stream_update->dither_option ||
5145			stream_update->wb_update ||
5146			stream_update->dsc_config ||
5147			stream_update->mst_bw_update ||
5148			stream_update->func_shaper ||
5149			stream_update->lut3d_func ||
5150			stream_update->pending_test_pattern ||
5151			stream_update->crtc_timing_adjust ||
5152			stream_update->scaler_sharpener_update ||
5153			stream_update->hw_cursor_req))
5154		return true;
5155
5156	return false;
5157}
5158
5159static bool fast_update_only(
5160		const struct dc *dc,
5161		const struct dc_fast_update *fast_update,
5162		const struct dc_surface_update *srf_updates,
5163		int surface_count,
5164		const struct dc_stream_update *stream_update,
5165		const struct dc_stream_state *stream)
5166{
5167	return fast_updates_exist(fast_update, surface_count)
5168			&& !full_update_required(dc, srf_updates, surface_count, stream_update, stream);
5169}
5170
5171static bool update_planes_and_stream_v2(struct dc *dc,
5172		struct dc_surface_update *srf_updates, int surface_count,
5173		struct dc_stream_state *stream,
5174		struct dc_stream_update *stream_update)
5175{
5176	struct dc_state *context;
5177	enum surface_update_type update_type;
5178	struct dc_fast_update fast_update[MAX_SURFACES] = {0};
5179
5180	/* In cases where MPO and split or ODM are used transitions can
5181	 * cause underflow. Apply stream configuration with minimal pipe
5182	 * split first to avoid unsupported transitions for active pipes.
5183	 */
5184	bool force_minimal_pipe_splitting = 0;
5185	bool is_plane_addition = 0;
5186	bool is_fast_update_only;
5187
5188	populate_fast_updates(fast_update, srf_updates, surface_count, stream_update);
5189	is_fast_update_only = fast_update_only(dc, fast_update, srf_updates,
5190			surface_count, stream_update, stream);
5191	force_minimal_pipe_splitting = could_mpcc_tree_change_for_active_pipes(
5192			dc,
5193			stream,
5194			srf_updates,
5195			surface_count,
5196			&is_plane_addition);
5197
5198	/* on plane addition, minimal state is the current one */
5199	if (force_minimal_pipe_splitting && is_plane_addition &&
5200		!commit_minimal_transition_state(dc, dc->current_state))
5201		return false;
5202
5203	if (!update_planes_and_stream_state(
5204			dc,
5205			srf_updates,
5206			surface_count,
5207			stream,
5208			stream_update,
5209			&update_type,
5210			&context))
5211		return false;
5212
5213	/* on plane removal, minimal state is the new one */
5214	if (force_minimal_pipe_splitting && !is_plane_addition) {
5215		if (!commit_minimal_transition_state(dc, context)) {
5216			dc_state_release(context);
5217			return false;
5218		}
5219		update_type = UPDATE_TYPE_FULL;
5220	}
5221
5222	if (dc->hwss.is_pipe_topology_transition_seamless &&
5223			!dc->hwss.is_pipe_topology_transition_seamless(
5224					dc, dc->current_state, context))
5225		commit_minimal_transition_state_in_dc_update(dc, context, stream,
5226				srf_updates, surface_count);
5227
5228	if (is_fast_update_only && !dc->check_config.enable_legacy_fast_update) {
5229		commit_planes_for_stream_fast(dc,
5230				srf_updates,
5231				surface_count,
5232				stream,
5233				stream_update,
5234				update_type,
5235				context);
5236	} else {
5237		if (!stream_update &&
5238				dc->hwss.is_pipe_topology_transition_seamless &&
5239				!dc->hwss.is_pipe_topology_transition_seamless(
5240						dc, dc->current_state, context)) {
5241			DC_LOG_ERROR("performing non-seamless pipe topology transition with surface only update!\n");
5242			BREAK_TO_DEBUGGER();
5243		}
5244		commit_planes_for_stream(
5245				dc,
5246				srf_updates,
5247				surface_count,
5248				stream,
5249				stream_update,
5250				update_type,
5251				context);
5252	}
5253	if (dc->current_state != context)
5254		swap_and_release_current_context(dc, context, stream);
5255	return true;
5256}
5257
5258static void commit_planes_and_stream_update_on_current_context(struct dc *dc,
5259		struct dc_surface_update *srf_updates, int surface_count,
5260		struct dc_stream_state *stream,
5261		struct dc_stream_update *stream_update,
5262		enum surface_update_type update_type)
5263{
5264	struct dc_fast_update fast_update[MAX_SURFACES] = {0};
5265
5266	ASSERT(update_type < UPDATE_TYPE_FULL);
5267	populate_fast_updates(fast_update, srf_updates, surface_count,
5268			stream_update);
5269	if (fast_update_only(dc, fast_update, srf_updates, surface_count,
5270			stream_update, stream) &&
5271			!dc->check_config.enable_legacy_fast_update)
5272		commit_planes_for_stream_fast(dc,
5273				srf_updates,
5274				surface_count,
5275				stream,
5276				stream_update,
5277				update_type,
5278				dc->current_state);
5279	else
5280		commit_planes_for_stream(
5281				dc,
5282				srf_updates,
5283				surface_count,
5284				stream,
5285				stream_update,
5286				update_type,
5287				dc->current_state);
5288}
5289
5290static void commit_planes_and_stream_update_with_new_context(struct dc *dc,
5291		struct dc_surface_update *srf_updates, int surface_count,
5292		struct dc_stream_state *stream,
5293		struct dc_stream_update *stream_update,
5294		enum surface_update_type update_type,
5295		struct dc_state *new_context)
5296{
5297	ASSERT(update_type >= UPDATE_TYPE_FULL);
5298	if (!dc->hwss.is_pipe_topology_transition_seamless(dc,
5299			dc->current_state, new_context))
5300		/*
5301		 * It is required by the feature design that all pipe topologies
5302		 * using extra free pipes for power saving purposes such as
5303		 * dynamic ODM or SubVp shall only be enabled when it can be
5304		 * transitioned seamlessly to AND from its minimal transition
5305		 * state. A minimal transition state is defined as the same dc
5306		 * state but with all power saving features disabled. So it uses
5307		 * the minimum pipe topology. When we can't seamlessly
5308		 * transition from state A to state B, we will insert the
5309		 * minimal transition state A' or B' in between so seamless
5310		 * transition between A and B can be made possible.
5311		 */
5312		commit_minimal_transition_state_in_dc_update(dc, new_context,
5313				stream, srf_updates, surface_count);
5314
5315	commit_planes_for_stream(
5316			dc,
5317			srf_updates,
5318			surface_count,
5319			stream,
5320			stream_update,
5321			update_type,
5322			new_context);
5323}
5324
5325static bool update_planes_and_stream_v3(struct dc *dc,
5326		struct dc_surface_update *srf_updates, int surface_count,
5327		struct dc_stream_state *stream,
5328		struct dc_stream_update *stream_update)
5329{
5330	struct dc_state *new_context;
5331	enum surface_update_type update_type;
5332
5333	/*
5334	 * When this function returns true and new_context is not equal to
5335	 * current state, the function allocates and validates a new dc state
5336	 * and assigns it to new_context. The function expects that the caller
5337	 * is responsible to free this memory when new_context is no longer
5338	 * used. We swap current with new context and free current instead. So
5339	 * new_context's memory will live until the next full update after it is
5340	 * replaced by a newer context. Refer to the use of
5341	 * swap_and_free_current_context below.
5342	 */
5343	if (!update_planes_and_stream_state(dc, srf_updates, surface_count,
5344				stream, stream_update, &update_type,
5345				&new_context))
5346		return false;
5347
5348	if (new_context == dc->current_state) {
5349		commit_planes_and_stream_update_on_current_context(dc,
5350				srf_updates, surface_count, stream,
5351				stream_update, update_type);
5352	} else {
5353		commit_planes_and_stream_update_with_new_context(dc,
5354				srf_updates, surface_count, stream,
5355				stream_update, update_type, new_context);
5356		swap_and_release_current_context(dc, new_context, stream);
5357	}
5358
5359	return true;
5360}
5361
5362static void clear_update_flags(struct dc_surface_update *srf_updates,
5363	int surface_count, struct dc_stream_state *stream)
5364{
5365	int i;
5366
5367	if (stream)
5368		stream->update_flags.raw = 0;
5369
5370	for (i = 0; i < surface_count; i++)
5371		if (srf_updates[i].surface)
5372			srf_updates[i].surface->update_flags.raw = 0;
5373}
5374
5375bool dc_update_planes_and_stream(struct dc *dc,
5376		struct dc_surface_update *srf_updates, int surface_count,
5377		struct dc_stream_state *stream,
5378		struct dc_stream_update *stream_update)
5379{
5380	bool ret = false;
5381
5382	dc_exit_ips_for_hw_access(dc);
5383	/*
5384	 * update planes and stream version 3 separates FULL and FAST updates
5385	 * to their own sequences. It aims to clean up frequent checks for
5386	 * update type resulting unnecessary branching in logic flow. It also
5387	 * adds a new commit minimal transition sequence, which detects the need
5388	 * for minimal transition based on the actual comparison of current and
5389	 * new states instead of "predicting" it based on per feature software
5390	 * policy.i.e could_mpcc_tree_change_for_active_pipes. The new commit
5391	 * minimal transition sequence is made universal to any power saving
5392	 * features that would use extra free pipes such as Dynamic ODM/MPC
5393	 * Combine, MPO or SubVp. Therefore there is no longer a need to
5394	 * specially handle compatibility problems with transitions among those
5395	 * features as they are now transparent to the new sequence.
5396	 */
5397	if (dc->ctx->dce_version >= DCN_VERSION_4_01 || dc->ctx->dce_version == DCN_VERSION_3_2 ||
5398			dc->ctx->dce_version == DCN_VERSION_3_21)
5399		ret = update_planes_and_stream_v3(dc, srf_updates,
5400				surface_count, stream, stream_update);
5401	else
5402		ret = update_planes_and_stream_v2(dc, srf_updates,
5403			surface_count, stream, stream_update);
5404	if (ret && (dc->ctx->dce_version >= DCN_VERSION_3_2 ||
5405		dc->ctx->dce_version == DCN_VERSION_3_01))
5406		clear_update_flags(srf_updates, surface_count, stream);
5407
5408	return ret;
5409}
5410
5411void dc_commit_updates_for_stream(struct dc *dc,
5412		struct dc_surface_update *srf_updates,
5413		int surface_count,
5414		struct dc_stream_state *stream,
5415		struct dc_stream_update *stream_update,
5416		struct dc_state *state)
5417{
5418	bool ret = false;
5419
5420	dc_exit_ips_for_hw_access(dc);
5421	/* TODO: Since change commit sequence can have a huge impact,
5422	 * we decided to only enable it for DCN3x. However, as soon as
5423	 * we get more confident about this change we'll need to enable
5424	 * the new sequence for all ASICs.
5425	 */
5426	if (dc->ctx->dce_version >= DCN_VERSION_4_01) {
5427		ret = update_planes_and_stream_v3(dc, srf_updates, surface_count,
5428				stream, stream_update);
5429	} else {
5430		ret = update_planes_and_stream_v2(dc, srf_updates, surface_count,
5431				stream, stream_update);
5432	}
5433
5434	if (ret && dc->ctx->dce_version >= DCN_VERSION_3_2)
5435		clear_update_flags(srf_updates, surface_count, stream);
5436}
5437
5438uint8_t dc_get_current_stream_count(struct dc *dc)
5439{
5440	return dc->current_state->stream_count;
5441}
5442
5443struct dc_stream_state *dc_get_stream_at_index(struct dc *dc, uint8_t i)
5444{
5445	if (i < dc->current_state->stream_count)
5446		return dc->current_state->streams[i];
5447	return NULL;
5448}
5449
5450enum dc_irq_source dc_interrupt_to_irq_source(
5451		struct dc *dc,
5452		uint32_t src_id,
5453		uint32_t ext_id)
5454{
5455	return dal_irq_service_to_irq_source(dc->res_pool->irqs, src_id, ext_id);
5456}
5457
5458/*
5459 * dc_interrupt_set() - Enable/disable an AMD hw interrupt source
5460 */
5461bool dc_interrupt_set(struct dc *dc, enum dc_irq_source src, bool enable)
5462{
5463
5464	if (dc == NULL)
5465		return false;
5466
5467	return dal_irq_service_set(dc->res_pool->irqs, src, enable);
5468}
5469
5470void dc_interrupt_ack(struct dc *dc, enum dc_irq_source src)
5471{
5472	dal_irq_service_ack(dc->res_pool->irqs, src);
5473}
5474
5475void dc_power_down_on_boot(struct dc *dc)
5476{
5477	if (dc->ctx->dce_environment != DCE_ENV_VIRTUAL_HW &&
5478	    dc->hwss.power_down_on_boot) {
5479		if (dc->caps.ips_support)
5480			dc_exit_ips_for_hw_access(dc);
5481		dc->hwss.power_down_on_boot(dc);
5482	}
5483}
5484
5485void dc_set_power_state(struct dc *dc, enum dc_acpi_cm_power_state power_state)
5486{
5487	if (!dc->current_state)
5488		return;
5489
5490	switch (power_state) {
5491	case DC_ACPI_CM_POWER_STATE_D0:
5492		dc_state_construct(dc, dc->current_state);
5493
5494		dc_exit_ips_for_hw_access(dc);
5495
5496		dc_z10_restore(dc);
5497
5498		dc_dmub_srv_notify_fw_dc_power_state(dc->ctx->dmub_srv, power_state);
5499
5500		dc->hwss.init_hw(dc);
5501
5502		if (dc->hwss.init_sys_ctx != NULL &&
5503			dc->vm_pa_config.valid) {
5504			dc->hwss.init_sys_ctx(dc->hwseq, dc, &dc->vm_pa_config);
5505		}
5506		break;
5507	case DC_ACPI_CM_POWER_STATE_D3:
5508		if (dc->caps.ips_support)
5509			dc_dmub_srv_notify_fw_dc_power_state(dc->ctx->dmub_srv, DC_ACPI_CM_POWER_STATE_D3);
5510
5511		if (dc->caps.ips_v2_support) {
5512			if (dc->clk_mgr->funcs->set_low_power_state)
5513				dc->clk_mgr->funcs->set_low_power_state(dc->clk_mgr);
5514		}
5515		break;
5516	default:
5517		ASSERT(dc->current_state->stream_count == 0);
5518		dc_dmub_srv_notify_fw_dc_power_state(dc->ctx->dmub_srv, power_state);
5519
5520		dc_state_destruct(dc->current_state);
5521
5522		break;
5523	}
5524}
5525
5526void dc_resume(struct dc *dc)
5527{
5528	uint32_t i;
5529
5530	for (i = 0; i < dc->link_count; i++)
5531		dc->link_srv->resume(dc->links[i]);
5532}
5533
5534bool dc_is_dmcu_initialized(struct dc *dc)
5535{
5536	struct dmcu *dmcu = dc->res_pool->dmcu;
5537
5538	if (dmcu)
5539		return dmcu->funcs->is_dmcu_initialized(dmcu);
5540	return false;
5541}
5542
5543enum dc_status dc_set_clock(struct dc *dc, enum dc_clock_type clock_type, uint32_t clk_khz, uint32_t stepping)
5544{
5545	if (dc->hwss.set_clock)
5546		return dc->hwss.set_clock(dc, clock_type, clk_khz, stepping);
5547	return DC_ERROR_UNEXPECTED;
5548}
5549void dc_get_clock(struct dc *dc, enum dc_clock_type clock_type, struct dc_clock_config *clock_cfg)
5550{
5551	if (dc->hwss.get_clock)
5552		dc->hwss.get_clock(dc, clock_type, clock_cfg);
5553}
5554
5555/* enable/disable eDP PSR without specify stream for eDP */
5556bool dc_set_psr_allow_active(struct dc *dc, bool enable)
5557{
5558	int i;
5559	bool allow_active;
5560
5561	for (i = 0; i < dc->current_state->stream_count ; i++) {
5562		struct dc_link *link;
5563		struct dc_stream_state *stream = dc->current_state->streams[i];
5564
5565		link = stream->link;
5566		if (!link)
5567			continue;
5568
5569		if (link->psr_settings.psr_feature_enabled) {
5570			if (enable && !link->psr_settings.psr_allow_active) {
5571				allow_active = true;
5572				if (!dc_link_set_psr_allow_active(link, &allow_active, false, false, NULL))
5573					return false;
5574			} else if (!enable && link->psr_settings.psr_allow_active) {
5575				allow_active = false;
5576				if (!dc_link_set_psr_allow_active(link, &allow_active, true, false, NULL))
5577					return false;
5578			}
5579		}
5580	}
5581
5582	return true;
5583}
5584
5585/* enable/disable eDP Replay without specify stream for eDP */
5586bool dc_set_replay_allow_active(struct dc *dc, bool active)
5587{
5588	int i;
5589	bool allow_active;
5590
5591	for (i = 0; i < dc->current_state->stream_count; i++) {
5592		struct dc_link *link;
5593		struct dc_stream_state *stream = dc->current_state->streams[i];
5594
5595		link = stream->link;
5596		if (!link)
5597			continue;
5598
5599		if (link->replay_settings.replay_feature_enabled) {
5600			if (active && !link->replay_settings.replay_allow_active) {
5601				allow_active = true;
5602				if (!dc_link_set_replay_allow_active(link, &allow_active,
5603					false, false, NULL))
5604					return false;
5605			} else if (!active && link->replay_settings.replay_allow_active) {
5606				allow_active = false;
5607				if (!dc_link_set_replay_allow_active(link, &allow_active,
5608					true, false, NULL))
5609					return false;
5610			}
5611		}
5612	}
5613
5614	return true;
5615}
5616
5617/* set IPS disable state */
5618bool dc_set_ips_disable(struct dc *dc, unsigned int disable_ips)
5619{
5620	dc_exit_ips_for_hw_access(dc);
5621
5622	dc->config.disable_ips = disable_ips;
5623
5624	return true;
5625}
5626
5627void dc_allow_idle_optimizations_internal(struct dc *dc, bool allow, char const *caller_name)
5628{
5629	int idle_fclk_khz = 0, idle_dramclk_khz = 0, i = 0;
5630	enum mall_stream_type subvp_pipe_type[MAX_PIPES] = {0};
5631	struct pipe_ctx *pipe = NULL;
5632	struct dc_state *context = dc->current_state;
5633
5634	if (dc->debug.disable_idle_power_optimizations) {
5635		DC_LOG_DEBUG("%s: disabled\n", __func__);
5636		return;
5637	}
5638
5639	if (allow != dc->idle_optimizations_allowed)
5640		DC_LOG_IPS("%s: allow_idle old=%d new=%d (caller=%s)\n", __func__,
5641			   dc->idle_optimizations_allowed, allow, caller_name);
5642
5643	if (dc->caps.ips_support && (dc->config.disable_ips == DMUB_IPS_DISABLE_ALL))
5644		return;
5645
5646	if (dc->clk_mgr != NULL && dc->clk_mgr->funcs->is_smu_present)
5647		if (!dc->clk_mgr->funcs->is_smu_present(dc->clk_mgr))
5648			return;
5649
5650	if (allow == dc->idle_optimizations_allowed)
5651		return;
5652
5653	if (dc->hwss.apply_idle_power_optimizations && dc->clk_mgr != NULL &&
5654	    dc->hwss.apply_idle_power_optimizations(dc, allow)) {
5655		dc->idle_optimizations_allowed = allow;
5656		DC_LOG_DEBUG("%s: %s\n", __func__, allow ? "enabled" : "disabled");
5657	}
5658
5659	// log idle clocks and sub vp pipe types at idle optimization time
5660	if (dc->clk_mgr != NULL && dc->clk_mgr->funcs->get_hard_min_fclk)
5661		idle_fclk_khz = dc->clk_mgr->funcs->get_hard_min_fclk(dc->clk_mgr);
5662
5663	if (dc->clk_mgr != NULL && dc->clk_mgr->funcs->get_hard_min_memclk)
5664		idle_dramclk_khz = dc->clk_mgr->funcs->get_hard_min_memclk(dc->clk_mgr);
5665
5666	if (dc->res_pool && context) {
5667		for (i = 0; i < dc->res_pool->pipe_count; i++) {
5668			pipe = &context->res_ctx.pipe_ctx[i];
5669			subvp_pipe_type[i] = dc_state_get_pipe_subvp_type(context, pipe);
5670		}
5671	}
5672	if (!dc->caps.is_apu)
5673		DC_LOG_DC("%s: allow_idle=%d\n HardMinUClk_Khz=%d HardMinDramclk_Khz=%d\n Pipe_0=%d Pipe_1=%d Pipe_2=%d Pipe_3=%d Pipe_4=%d Pipe_5=%d (caller=%s)\n",
5674			__func__, allow, idle_fclk_khz, idle_dramclk_khz, subvp_pipe_type[0], subvp_pipe_type[1], subvp_pipe_type[2],
5675			subvp_pipe_type[3], subvp_pipe_type[4], subvp_pipe_type[5], caller_name);
5676
5677}
5678
5679void dc_exit_ips_for_hw_access_internal(struct dc *dc, const char *caller_name)
5680{
5681	if (dc->caps.ips_support)
5682		dc_allow_idle_optimizations_internal(dc, false, caller_name);
5683}
5684
5685bool dc_dmub_is_ips_idle_state(struct dc *dc)
5686{
5687	if (dc->debug.disable_idle_power_optimizations)
5688		return false;
5689
5690	if (!dc->caps.ips_support || (dc->config.disable_ips == DMUB_IPS_DISABLE_ALL))
5691		return false;
5692
5693	if (!dc->ctx->dmub_srv)
5694		return false;
5695
5696	return dc->ctx->dmub_srv->idle_allowed;
5697}
5698
5699/* set min and max memory clock to lowest and highest DPM level, respectively */
5700void dc_unlock_memory_clock_frequency(struct dc *dc)
5701{
5702	if (dc->clk_mgr->funcs->set_hard_min_memclk)
5703		dc->clk_mgr->funcs->set_hard_min_memclk(dc->clk_mgr, false);
5704
5705	if (dc->clk_mgr->funcs->set_hard_max_memclk)
5706		dc->clk_mgr->funcs->set_hard_max_memclk(dc->clk_mgr);
5707}
5708
5709/* set min memory clock to the min required for current mode, max to maxDPM */
5710void dc_lock_memory_clock_frequency(struct dc *dc)
5711{
5712	if (dc->clk_mgr->funcs->get_memclk_states_from_smu)
5713		dc->clk_mgr->funcs->get_memclk_states_from_smu(dc->clk_mgr);
5714
5715	if (dc->clk_mgr->funcs->set_hard_min_memclk)
5716		dc->clk_mgr->funcs->set_hard_min_memclk(dc->clk_mgr, true);
5717
5718	if (dc->clk_mgr->funcs->set_hard_max_memclk)
5719		dc->clk_mgr->funcs->set_hard_max_memclk(dc->clk_mgr);
5720}
5721
5722static void blank_and_force_memclk(struct dc *dc, bool apply, unsigned int memclk_mhz)
5723{
5724	struct dc_state *context = dc->current_state;
5725	struct hubp *hubp;
5726	struct pipe_ctx *pipe;
5727	int i;
5728
5729	for (i = 0; i < dc->res_pool->pipe_count; i++) {
5730		pipe = &context->res_ctx.pipe_ctx[i];
5731
5732		if (pipe->stream != NULL) {
5733			dc->hwss.disable_pixel_data(dc, pipe, true);
5734
5735			// wait for double buffer
5736			pipe->stream_res.tg->funcs->wait_for_state(pipe->stream_res.tg, CRTC_STATE_VACTIVE);
5737			pipe->stream_res.tg->funcs->wait_for_state(pipe->stream_res.tg, CRTC_STATE_VBLANK);
5738			pipe->stream_res.tg->funcs->wait_for_state(pipe->stream_res.tg, CRTC_STATE_VACTIVE);
5739
5740			hubp = pipe->plane_res.hubp;
5741			hubp->funcs->set_blank_regs(hubp, true);
5742		}
5743	}
5744	if (dc->clk_mgr->funcs->set_max_memclk)
5745		dc->clk_mgr->funcs->set_max_memclk(dc->clk_mgr, memclk_mhz);
5746	if (dc->clk_mgr->funcs->set_min_memclk)
5747		dc->clk_mgr->funcs->set_min_memclk(dc->clk_mgr, memclk_mhz);
5748
5749	for (i = 0; i < dc->res_pool->pipe_count; i++) {
5750		pipe = &context->res_ctx.pipe_ctx[i];
5751
5752		if (pipe->stream != NULL) {
5753			dc->hwss.disable_pixel_data(dc, pipe, false);
5754
5755			hubp = pipe->plane_res.hubp;
5756			hubp->funcs->set_blank_regs(hubp, false);
5757		}
5758	}
5759}
5760
5761
5762/**
5763 * dc_enable_dcmode_clk_limit() - lower clocks in dc (battery) mode
5764 * @dc: pointer to dc of the dm calling this
5765 * @enable: True = transition to DC mode, false = transition back to AC mode
5766 *
5767 * Some SoCs define additional clock limits when in DC mode, DM should
5768 * invoke this function when the platform undergoes a power source transition
5769 * so DC can apply/unapply the limit. This interface may be disruptive to
5770 * the onscreen content.
5771 *
5772 * Context: Triggered by OS through DM interface, or manually by escape calls.
5773 * Need to hold a dclock when doing so.
5774 *
5775 * Return: none (void function)
5776 *
5777 */
5778void dc_enable_dcmode_clk_limit(struct dc *dc, bool enable)
5779{
5780	unsigned int softMax = 0, maxDPM = 0, funcMin = 0, i;
5781	bool p_state_change_support;
5782
5783	if (!dc->config.dc_mode_clk_limit_support)
5784		return;
5785
5786	softMax = dc->clk_mgr->bw_params->dc_mode_softmax_memclk;
5787	for (i = 0; i < dc->clk_mgr->bw_params->clk_table.num_entries; i++) {
5788		if (dc->clk_mgr->bw_params->clk_table.entries[i].memclk_mhz > maxDPM)
5789			maxDPM = dc->clk_mgr->bw_params->clk_table.entries[i].memclk_mhz;
5790	}
5791	funcMin = (dc->clk_mgr->clks.dramclk_khz + 999) / 1000;
5792	p_state_change_support = dc->clk_mgr->clks.p_state_change_support;
5793
5794	if (enable && !dc->clk_mgr->dc_mode_softmax_enabled) {
5795		if (p_state_change_support) {
5796			if (funcMin <= softMax && dc->clk_mgr->funcs->set_max_memclk)
5797				dc->clk_mgr->funcs->set_max_memclk(dc->clk_mgr, softMax);
5798			// else: No-Op
5799		} else {
5800			if (funcMin <= softMax)
5801				blank_and_force_memclk(dc, true, softMax);
5802			// else: No-Op
5803		}
5804	} else if (!enable && dc->clk_mgr->dc_mode_softmax_enabled) {
5805		if (p_state_change_support) {
5806			if (funcMin <= softMax && dc->clk_mgr->funcs->set_max_memclk)
5807				dc->clk_mgr->funcs->set_max_memclk(dc->clk_mgr, maxDPM);
5808			// else: No-Op
5809		} else {
5810			if (funcMin <= softMax)
5811				blank_and_force_memclk(dc, true, maxDPM);
5812			// else: No-Op
5813		}
5814	}
5815	dc->clk_mgr->dc_mode_softmax_enabled = enable;
5816}
5817bool dc_is_plane_eligible_for_idle_optimizations(struct dc *dc,
5818		unsigned int pitch,
5819		unsigned int height,
5820		enum surface_pixel_format format,
5821		struct dc_cursor_attributes *cursor_attr)
5822{
5823	if (dc->hwss.does_plane_fit_in_mall && dc->hwss.does_plane_fit_in_mall(dc, pitch, height, format, cursor_attr))
5824		return true;
5825	return false;
5826}
5827
5828/* cleanup on driver unload */
5829void dc_hardware_release(struct dc *dc)
5830{
5831	dc_mclk_switch_using_fw_based_vblank_stretch_shut_down(dc);
5832
5833	if (dc->hwss.hardware_release)
5834		dc->hwss.hardware_release(dc);
5835}
5836
5837void dc_mclk_switch_using_fw_based_vblank_stretch_shut_down(struct dc *dc)
5838{
5839	if (dc->current_state)
5840		dc->current_state->bw_ctx.bw.dcn.clk.fw_based_mclk_switching_shut_down = true;
5841}
5842
5843/**
5844 * dc_is_dmub_outbox_supported - Check if DMUB firmware support outbox notification
5845 *
5846 * @dc: [in] dc structure
5847 *
5848 * Checks whether DMUB FW supports outbox notifications, if supported DM
5849 * should register outbox interrupt prior to actually enabling interrupts
5850 * via dc_enable_dmub_outbox
5851 *
5852 * Return:
5853 * True if DMUB FW supports outbox notifications, False otherwise
5854 */
5855bool dc_is_dmub_outbox_supported(struct dc *dc)
5856{
5857	if (!dc->caps.dmcub_support)
5858		return false;
5859
5860	switch (dc->ctx->asic_id.chip_family) {
5861
5862	case FAMILY_YELLOW_CARP:
5863		/* DCN31 B0 USB4 DPIA needs dmub notifications for interrupts */
5864		if (dc->ctx->asic_id.hw_internal_rev == YELLOW_CARP_B0 &&
5865		    !dc->debug.dpia_debug.bits.disable_dpia)
5866			return true;
5867	break;
5868
5869	case AMDGPU_FAMILY_GC_11_0_1:
5870	case AMDGPU_FAMILY_GC_11_5_0:
5871		if (!dc->debug.dpia_debug.bits.disable_dpia)
5872			return true;
5873	break;
5874
5875	default:
5876		break;
5877	}
5878
5879	/* dmub aux needs dmub notifications to be enabled */
5880	return dc->debug.enable_dmub_aux_for_legacy_ddc;
5881
5882}
5883
5884/**
5885 * dc_enable_dmub_notifications - Check if dmub fw supports outbox
5886 *
5887 * @dc: [in] dc structure
5888 *
5889 * Calls dc_is_dmub_outbox_supported to check if dmub fw supports outbox
5890 * notifications. All DMs shall switch to dc_is_dmub_outbox_supported.  This
5891 * API shall be removed after switching.
5892 *
5893 * Return:
5894 * True if DMUB FW supports outbox notifications, False otherwise
5895 */
5896bool dc_enable_dmub_notifications(struct dc *dc)
5897{
5898	return dc_is_dmub_outbox_supported(dc);
5899}
5900
5901/**
5902 * dc_enable_dmub_outbox - Enables DMUB unsolicited notification
5903 *
5904 * @dc: [in] dc structure
5905 *
5906 * Enables DMUB unsolicited notifications to x86 via outbox.
5907 */
5908void dc_enable_dmub_outbox(struct dc *dc)
5909{
5910	struct dc_context *dc_ctx = dc->ctx;
5911
5912	dmub_enable_outbox_notification(dc_ctx->dmub_srv);
5913	DC_LOG_DC("%s: dmub outbox notifications enabled\n", __func__);
5914}
5915
5916/**
5917 * dc_process_dmub_aux_transfer_async - Submits aux command to dmub via inbox message
5918 *                                      Sets port index appropriately for legacy DDC
5919 * @dc: dc structure
5920 * @link_index: link index
5921 * @payload: aux payload
5922 *
5923 * Returns: True if successful, False if failure
5924 */
5925bool dc_process_dmub_aux_transfer_async(struct dc *dc,
5926				uint32_t link_index,
5927				struct aux_payload *payload)
5928{
5929	uint8_t action;
5930	union dmub_rb_cmd cmd = {0};
5931
5932	ASSERT(payload->length <= 16);
5933
5934	cmd.dp_aux_access.header.type = DMUB_CMD__DP_AUX_ACCESS;
5935	cmd.dp_aux_access.header.payload_bytes = 0;
5936	/* For dpia, ddc_pin is set to NULL */
5937	if (!dc->links[link_index]->ddc->ddc_pin)
5938		cmd.dp_aux_access.aux_control.type = AUX_CHANNEL_DPIA;
5939	else
5940		cmd.dp_aux_access.aux_control.type = AUX_CHANNEL_LEGACY_DDC;
5941
5942	cmd.dp_aux_access.aux_control.instance = dc->links[link_index]->ddc_hw_inst;
5943	cmd.dp_aux_access.aux_control.sw_crc_enabled = 0;
5944	cmd.dp_aux_access.aux_control.timeout = 0;
5945	cmd.dp_aux_access.aux_control.dpaux.address = payload->address;
5946	cmd.dp_aux_access.aux_control.dpaux.is_i2c_over_aux = payload->i2c_over_aux;
5947	cmd.dp_aux_access.aux_control.dpaux.length = payload->length;
5948
5949	/* set aux action */
5950	if (payload->i2c_over_aux) {
5951		if (payload->write) {
5952			if (payload->mot)
5953				action = DP_AUX_REQ_ACTION_I2C_WRITE_MOT;
5954			else
5955				action = DP_AUX_REQ_ACTION_I2C_WRITE;
5956		} else {
5957			if (payload->mot)
5958				action = DP_AUX_REQ_ACTION_I2C_READ_MOT;
5959			else
5960				action = DP_AUX_REQ_ACTION_I2C_READ;
5961			}
5962	} else {
5963		if (payload->write)
5964			action = DP_AUX_REQ_ACTION_DPCD_WRITE;
5965		else
5966			action = DP_AUX_REQ_ACTION_DPCD_READ;
5967	}
5968
5969	cmd.dp_aux_access.aux_control.dpaux.action = action;
5970
5971	if (payload->length && payload->write) {
5972		memcpy(cmd.dp_aux_access.aux_control.dpaux.data,
5973			payload->data,
5974			payload->length
5975			);
5976	}
5977
5978	dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
5979
5980	return true;
5981}
5982
5983bool dc_smart_power_oled_enable(const struct dc_link *link, bool enable, uint16_t peak_nits,
5984			uint8_t debug_control, uint16_t fixed_CLL, uint32_t triggerline)
5985{
5986	bool status = false;
5987	struct dc *dc = link->ctx->dc;
5988	union dmub_rb_cmd cmd;
5989	uint8_t otg_inst = 0;
5990	unsigned int panel_inst = 0;
5991	struct pipe_ctx *pipe_ctx = NULL;
5992	struct resource_context *res_ctx = &link->ctx->dc->current_state->res_ctx;
5993	int i = 0;
5994
5995	// get panel_inst
5996	if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst))
5997		return status;
5998
5999	// get otg_inst
6000	for (i = 0; i < MAX_PIPES; i++) {
6001		if (res_ctx &&
6002			res_ctx->pipe_ctx[i].stream &&
6003			res_ctx->pipe_ctx[i].stream->link &&
6004			res_ctx->pipe_ctx[i].stream->link == link &&
6005			res_ctx->pipe_ctx[i].stream->link->connector_signal == SIGNAL_TYPE_EDP) {
6006			pipe_ctx = &res_ctx->pipe_ctx[i];
6007			//TODO: refactor for multi edp support
6008			break;
6009		}
6010	}
6011
6012	if (pipe_ctx)
6013		otg_inst = pipe_ctx->stream_res.tg->inst;
6014
6015	// before enable smart power OLED, we need to call set pipe for DMUB to set ABM config
6016	if (enable) {
6017		if (dc->hwss.set_pipe && pipe_ctx)
6018			dc->hwss.set_pipe(pipe_ctx);
6019	}
6020
6021	// fill in cmd
6022	memset(&cmd, 0, sizeof(cmd));
6023
6024	cmd.smart_power_oled_enable.header.type = DMUB_CMD__SMART_POWER_OLED;
6025	cmd.smart_power_oled_enable.header.sub_type = DMUB_CMD__SMART_POWER_OLED_ENABLE;
6026	cmd.smart_power_oled_enable.header.payload_bytes =
6027		sizeof(struct dmub_rb_cmd_smart_power_oled_enable_data) - sizeof(struct dmub_cmd_header);
6028	cmd.smart_power_oled_enable.header.ret_status = 1;
6029	cmd.smart_power_oled_enable.data.enable = enable;
6030	cmd.smart_power_oled_enable.data.panel_inst = panel_inst;
6031	cmd.smart_power_oled_enable.data.peak_nits = peak_nits;
6032	cmd.smart_power_oled_enable.data.otg_inst = otg_inst;
6033	cmd.smart_power_oled_enable.data.digfe_inst = link->link_enc->preferred_engine;
6034	cmd.smart_power_oled_enable.data.digbe_inst = link->link_enc->transmitter;
6035
6036	cmd.smart_power_oled_enable.data.debugcontrol = debug_control;
6037	cmd.smart_power_oled_enable.data.triggerline = triggerline;
6038	cmd.smart_power_oled_enable.data.fixed_max_cll = fixed_CLL;
6039
6040	// send cmd
6041	status = dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
6042
6043	return status;
6044}
6045
6046bool dc_smart_power_oled_get_max_cll(const struct dc_link *link, unsigned int *pCurrent_MaxCLL)
6047{
6048	struct dc *dc = link->ctx->dc;
6049	union dmub_rb_cmd cmd;
6050	bool status = false;
6051	unsigned int panel_inst = 0;
6052
6053	// get panel_inst
6054	if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst))
6055		return status;
6056
6057	// fill in cmd
6058	memset(&cmd, 0, sizeof(cmd));
6059
6060	cmd.smart_power_oled_getmaxcll.header.type = DMUB_CMD__SMART_POWER_OLED;
6061	cmd.smart_power_oled_getmaxcll.header.sub_type = DMUB_CMD__SMART_POWER_OLED_GETMAXCLL;
6062	cmd.smart_power_oled_getmaxcll.header.payload_bytes = sizeof(cmd.smart_power_oled_getmaxcll.data);
6063	cmd.smart_power_oled_getmaxcll.header.ret_status = 1;
6064
6065	cmd.smart_power_oled_getmaxcll.data.input.panel_inst = panel_inst;
6066
6067	// send cmd and wait for reply
6068	status = dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY);
6069
6070	if (status)
6071		*pCurrent_MaxCLL = cmd.smart_power_oled_getmaxcll.data.output.current_max_cll;
6072	else
6073		*pCurrent_MaxCLL = 0;
6074
6075	return status;
6076}
6077
6078uint8_t get_link_index_from_dpia_port_index(const struct dc *dc,
6079					    uint8_t dpia_port_index)
6080{
6081	uint8_t index, link_index = 0xFF;
6082
6083	for (index = 0; index < dc->link_count; index++) {
6084		/* ddc_hw_inst has dpia port index for dpia links
6085		 * and ddc instance for legacy links
6086		 */
6087		if (!dc->links[index]->ddc->ddc_pin) {
6088			if (dc->links[index]->ddc_hw_inst == dpia_port_index) {
6089				link_index = index;
6090				break;
6091			}
6092		}
6093	}
6094	ASSERT(link_index != 0xFF);
6095	return link_index;
6096}
6097
6098/**
6099 * dc_process_dmub_set_config_async - Submits set_config command
6100 *
6101 * @dc: [in] dc structure
6102 * @link_index: [in] link_index: link index
6103 * @payload: [in] aux payload
6104 * @notify: [out] set_config immediate reply
6105 *
6106 * Submits set_config command to dmub via inbox message.
6107 *
6108 * Return:
6109 * True if successful, False if failure
6110 */
6111bool dc_process_dmub_set_config_async(struct dc *dc,
6112				uint32_t link_index,
6113				struct set_config_cmd_payload *payload,
6114				struct dmub_notification *notify)
6115{
6116	union dmub_rb_cmd cmd = {0};
6117	bool is_cmd_complete = true;
6118
6119	/* prepare SET_CONFIG command */
6120	cmd.set_config_access.header.type = DMUB_CMD__DPIA;
6121	cmd.set_config_access.header.sub_type = DMUB_CMD__DPIA_SET_CONFIG_ACCESS;
6122
6123	cmd.set_config_access.set_config_control.instance = dc->links[link_index]->ddc_hw_inst;
6124	cmd.set_config_access.set_config_control.cmd_pkt.msg_type = payload->msg_type;
6125	cmd.set_config_access.set_config_control.cmd_pkt.msg_data = payload->msg_data;
6126
6127	if (!dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY)) {
6128		/* command is not processed by dmub */
6129		notify->sc_status = SET_CONFIG_UNKNOWN_ERROR;
6130		return is_cmd_complete;
6131	}
6132
6133	/* command processed by dmub, if ret_status is 1, it is completed instantly */
6134	if (cmd.set_config_access.header.ret_status == 1)
6135		notify->sc_status = cmd.set_config_access.set_config_control.immed_status;
6136	else
6137		/* cmd pending, will receive notification via outbox */
6138		is_cmd_complete = false;
6139
6140	return is_cmd_complete;
6141}
6142
6143/**
6144 * dc_process_dmub_set_mst_slots - Submits MST solt allocation
6145 *
6146 * @dc: [in] dc structure
6147 * @link_index: [in] link index
6148 * @mst_alloc_slots: [in] mst slots to be allotted
6149 * @mst_slots_in_use: [out] mst slots in use returned in failure case
6150 *
6151 * Submits mst slot allocation command to dmub via inbox message
6152 *
6153 * Return:
6154 * DC_OK if successful, DC_ERROR if failure
6155 */
6156enum dc_status dc_process_dmub_set_mst_slots(const struct dc *dc,
6157				uint32_t link_index,
6158				uint8_t mst_alloc_slots,
6159				uint8_t *mst_slots_in_use)
6160{
6161	union dmub_rb_cmd cmd = {0};
6162
6163	/* prepare MST_ALLOC_SLOTS command */
6164	cmd.set_mst_alloc_slots.header.type = DMUB_CMD__DPIA;
6165	cmd.set_mst_alloc_slots.header.sub_type = DMUB_CMD__DPIA_MST_ALLOC_SLOTS;
6166
6167	cmd.set_mst_alloc_slots.mst_slots_control.instance = dc->links[link_index]->ddc_hw_inst;
6168	cmd.set_mst_alloc_slots.mst_slots_control.mst_alloc_slots = mst_alloc_slots;
6169
6170	if (!dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY))
6171		/* command is not processed by dmub */
6172		return DC_ERROR_UNEXPECTED;
6173
6174	/* command processed by dmub, if ret_status is 1 */
6175	if (cmd.set_config_access.header.ret_status != 1)
6176		/* command processing error */
6177		return DC_ERROR_UNEXPECTED;
6178
6179	/* command processed and we have a status of 2, mst not enabled in dpia */
6180	if (cmd.set_mst_alloc_slots.mst_slots_control.immed_status == 2)
6181		return DC_FAIL_UNSUPPORTED_1;
6182
6183	/* previously configured mst alloc and used slots did not match */
6184	if (cmd.set_mst_alloc_slots.mst_slots_control.immed_status == 3) {
6185		*mst_slots_in_use = cmd.set_mst_alloc_slots.mst_slots_control.mst_slots_in_use;
6186		return DC_NOT_SUPPORTED;
6187	}
6188
6189	return DC_OK;
6190}
6191
6192/**
6193 * dc_process_dmub_dpia_set_tps_notification - Submits tps notification
6194 *
6195 * @dc: [in] dc structure
6196 * @link_index: [in] link index
6197 * @tps: [in] request tps
6198 *
6199 * Submits set_tps_notification command to dmub via inbox message
6200 */
6201void dc_process_dmub_dpia_set_tps_notification(const struct dc *dc, uint32_t link_index, uint8_t tps)
6202{
6203	union dmub_rb_cmd cmd = {0};
6204
6205	cmd.set_tps_notification.header.type = DMUB_CMD__DPIA;
6206	cmd.set_tps_notification.header.sub_type = DMUB_CMD__DPIA_SET_TPS_NOTIFICATION;
6207	cmd.set_tps_notification.tps_notification.instance = dc->links[link_index]->ddc_hw_inst;
6208	cmd.set_tps_notification.tps_notification.tps = tps;
6209
6210	dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
6211}
6212
6213/**
6214 * dc_process_dmub_dpia_hpd_int_enable - Submits DPIA DPD interruption
6215 *
6216 * @dc: [in] dc structure
6217 * @hpd_int_enable: [in] 1 for hpd int enable, 0 to disable
6218 *
6219 * Submits dpia hpd int enable command to dmub via inbox message
6220 */
6221void dc_process_dmub_dpia_hpd_int_enable(const struct dc *dc,
6222				uint32_t hpd_int_enable)
6223{
6224	union dmub_rb_cmd cmd = {0};
6225
6226	cmd.dpia_hpd_int_enable.header.type = DMUB_CMD__DPIA_HPD_INT_ENABLE;
6227	cmd.dpia_hpd_int_enable.enable = hpd_int_enable;
6228
6229	dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
6230
6231	DC_LOG_DEBUG("%s: hpd_int_enable(%d)\n", __func__, hpd_int_enable);
6232}
6233
6234/**
6235 * dc_print_dmub_diagnostic_data - Print DMUB diagnostic data for debugging
6236 *
6237 * @dc: [in] dc structure
6238 *
6239 *
6240 */
6241void dc_print_dmub_diagnostic_data(const struct dc *dc)
6242{
6243	dc_dmub_srv_log_diagnostic_data(dc->ctx->dmub_srv);
6244}
6245
6246/**
6247 * dc_disable_accelerated_mode - disable accelerated mode
6248 * @dc: dc structure
6249 */
6250void dc_disable_accelerated_mode(struct dc *dc)
6251{
6252	bios_set_scratch_acc_mode_change(dc->ctx->dc_bios, 0);
6253}
6254
6255
6256/**
6257 *  dc_notify_vsync_int_state - notifies vsync enable/disable state
6258 *  @dc: dc structure
6259 *  @stream: stream where vsync int state changed
6260 *  @enable: whether vsync is enabled or disabled
6261 *
6262 *  Called when vsync is enabled/disabled Will notify DMUB to start/stop ABM
6263 *  interrupts after steady state is reached.
6264 */
6265void dc_notify_vsync_int_state(struct dc *dc, struct dc_stream_state *stream, bool enable)
6266{
6267	int i;
6268	int edp_num;
6269	struct pipe_ctx *pipe = NULL;
6270	struct dc_link *link = stream->sink->link;
6271	struct dc_link *edp_links[MAX_NUM_EDP];
6272
6273
6274	if (link->psr_settings.psr_feature_enabled)
6275		return;
6276
6277	if (link->replay_settings.replay_feature_enabled)
6278		return;
6279
6280	/*find primary pipe associated with stream*/
6281	for (i = 0; i < MAX_PIPES; i++) {
6282		pipe = &dc->current_state->res_ctx.pipe_ctx[i];
6283
6284		if (pipe->stream == stream && pipe->stream_res.tg)
6285			break;
6286	}
6287
6288	if (i == MAX_PIPES) {
6289		ASSERT(0);
6290		return;
6291	}
6292
6293	dc_get_edp_links(dc, edp_links, &edp_num);
6294
6295	/* Determine panel inst */
6296	for (i = 0; i < edp_num; i++) {
6297		if (edp_links[i] == link)
6298			break;
6299	}
6300
6301	if (i == edp_num) {
6302		return;
6303	}
6304
6305	if (pipe->stream_res.abm && pipe->stream_res.abm->funcs->set_abm_pause)
6306		pipe->stream_res.abm->funcs->set_abm_pause(pipe->stream_res.abm, !enable, i, pipe->stream_res.tg->inst);
6307}
6308
6309/*****************************************************************************
6310 *  dc_abm_save_restore() - Interface to DC for save+pause and restore+un-pause
6311 *                          ABM
6312 *  @dc: dc structure
6313 *	@stream: stream where vsync int state changed
6314 *  @pData: abm hw states
6315 *
6316 ****************************************************************************/
6317bool dc_abm_save_restore(
6318		struct dc *dc,
6319		struct dc_stream_state *stream,
6320		struct abm_save_restore *pData)
6321{
6322	int i;
6323	int edp_num;
6324	struct pipe_ctx *pipe = NULL;
6325	struct dc_link *link = stream->sink->link;
6326	struct dc_link *edp_links[MAX_NUM_EDP];
6327
6328	if (link->replay_settings.replay_feature_enabled)
6329		return false;
6330
6331	/*find primary pipe associated with stream*/
6332	for (i = 0; i < MAX_PIPES; i++) {
6333		pipe = &dc->current_state->res_ctx.pipe_ctx[i];
6334
6335		if (pipe->stream == stream && pipe->stream_res.tg)
6336			break;
6337	}
6338
6339	if (i == MAX_PIPES) {
6340		ASSERT(0);
6341		return false;
6342	}
6343
6344	dc_get_edp_links(dc, edp_links, &edp_num);
6345
6346	/* Determine panel inst */
6347	for (i = 0; i < edp_num; i++)
6348		if (edp_links[i] == link)
6349			break;
6350
6351	if (i == edp_num)
6352		return false;
6353
6354	if (pipe->stream_res.abm &&
6355		pipe->stream_res.abm->funcs->save_restore)
6356		return pipe->stream_res.abm->funcs->save_restore(
6357				pipe->stream_res.abm,
6358				i,
6359				pData);
6360	return false;
6361}
6362
6363void dc_query_current_properties(struct dc *dc, struct dc_current_properties *properties)
6364{
6365	unsigned int i;
6366	unsigned int max_cursor_size = dc->caps.max_cursor_size;
6367	unsigned int stream_cursor_size;
6368
6369	if (dc->debug.allow_sw_cursor_fallback && dc->res_pool->funcs->get_max_hw_cursor_size) {
6370		for (i = 0; i < dc->current_state->stream_count; i++) {
6371			stream_cursor_size = dc->res_pool->funcs->get_max_hw_cursor_size(dc,
6372					dc->current_state,
6373					dc->current_state->streams[i]);
6374
6375			if (stream_cursor_size < max_cursor_size) {
6376				max_cursor_size = stream_cursor_size;
6377			}
6378		}
6379	}
6380
6381	properties->cursor_size_limit = max_cursor_size;
6382}
6383
6384/**
6385 * dc_set_edp_power() - DM controls eDP power to be ON/OFF
6386 *
6387 * Called when DM wants to power on/off eDP.
6388 *     Only work on links with flag skip_implict_edp_power_control is set.
6389 *
6390 * @dc: Current DC state
6391 * @edp_link: a link with eDP connector signal type
6392 * @powerOn: power on/off eDP
6393 *
6394 * Return: void
6395 */
6396void dc_set_edp_power(const struct dc *dc, struct dc_link *edp_link,
6397				 bool powerOn)
6398{
6399	if (edp_link->connector_signal != SIGNAL_TYPE_EDP)
6400		return;
6401
6402	if (edp_link->skip_implict_edp_power_control == false)
6403		return;
6404
6405	edp_link->dc->link_srv->edp_set_panel_power(edp_link, powerOn);
6406}
6407
6408/**
6409 * dc_get_power_profile_for_dc_state() - extracts power profile from dc state
6410 *
6411 * Called when DM wants to make power policy decisions based on dc_state
6412 *
6413 * @context: Pointer to the dc_state from which the power profile is extracted.
6414 *
6415 * Return: The power profile structure containing the power level information.
6416 */
6417struct dc_power_profile dc_get_power_profile_for_dc_state(const struct dc_state *context)
6418{
6419	struct dc_power_profile profile = { 0 };
6420
6421	profile.power_level = !context->bw_ctx.bw.dcn.clk.p_state_change_support;
6422	if (!context->clk_mgr || !context->clk_mgr->ctx || !context->clk_mgr->ctx->dc)
6423		return profile;
6424	struct dc *dc = context->clk_mgr->ctx->dc;
6425
6426	if (dc->res_pool->funcs->get_power_profile)
6427		profile.power_level = dc->res_pool->funcs->get_power_profile(context);
6428	return profile;
6429}
6430
6431/**
6432 * dc_get_det_buffer_size_from_state() - extracts detile buffer size from dc state
6433 *
6434 * This function is called to log the detile buffer size from the dc_state.
6435 *
6436 * @context: a pointer to the dc_state from which the detile buffer size is extracted.
6437 *
6438 * Return: the size of the detile buffer, or 0 if not available.
6439 */
6440unsigned int dc_get_det_buffer_size_from_state(const struct dc_state *context)
6441{
6442	struct dc *dc = context->clk_mgr->ctx->dc;
6443
6444	if (dc->res_pool->funcs->get_det_buffer_size)
6445		return dc->res_pool->funcs->get_det_buffer_size(context);
6446	else
6447		return 0;
6448}
6449
6450/**
6451 * dc_get_host_router_index: Get index of host router from a dpia link
6452 *
6453 * This function return a host router index of the target link. If the target link is dpia link.
6454 *
6455 * @link: Pointer to the target link (input)
6456 * @host_router_index: Pointer to store the host router index of the target link (output).
6457 *
6458 * Return: true if the host router index is found and valid.
6459 *
6460 */
6461bool dc_get_host_router_index(const struct dc_link *link, unsigned int *host_router_index)
6462{
6463	struct dc *dc;
6464
6465	if (!link || !host_router_index || link->ep_type != DISPLAY_ENDPOINT_USB4_DPIA)
6466		return false;
6467
6468	dc = link->ctx->dc;
6469
6470	if (link->link_index < dc->lowest_dpia_link_index)
6471		return false;
6472
6473	*host_router_index = (link->link_index - dc->lowest_dpia_link_index) / dc->caps.num_of_dpias_per_host_router;
6474	if (*host_router_index < dc->caps.num_of_host_routers)
6475		return true;
6476	else
6477		return false;
6478}
6479
6480bool dc_is_cursor_limit_pending(struct dc *dc)
6481{
6482	uint32_t i;
6483
6484	for (i = 0; i < dc->current_state->stream_count; i++) {
6485		if (dc_stream_is_cursor_limit_pending(dc, dc->current_state->streams[i]))
6486			return true;
6487	}
6488
6489	return false;
6490}
6491
6492bool dc_can_clear_cursor_limit(const struct dc *dc)
6493{
6494	uint32_t i;
6495
6496	for (i = 0; i < dc->current_state->stream_count; i++) {
6497		if (dc_state_can_clear_stream_cursor_subvp_limit(dc->current_state->streams[i], dc->current_state))
6498			return true;
6499	}
6500
6501	return false;
6502}
6503
6504void dc_get_underflow_debug_data_for_otg(struct dc *dc, int primary_otg_inst,
6505				struct dc_underflow_debug_data *out_data)
6506{
6507	struct timing_generator *tg = NULL;
6508
6509	for (int i = 0; i < MAX_PIPES; i++) {
6510		if (dc->res_pool->timing_generators[i] &&
6511			dc->res_pool->timing_generators[i]->inst == primary_otg_inst) {
6512				tg = dc->res_pool->timing_generators[i];
6513				break;
6514		}
6515	}
6516
6517	dc_exit_ips_for_hw_access(dc);
6518	if (dc->hwss.get_underflow_debug_data)
6519		dc->hwss.get_underflow_debug_data(dc, tg, out_data);
6520}
6521
6522void dc_get_power_feature_status(struct dc *dc, int primary_otg_inst,
6523				struct power_features *out_data)
6524{
6525	out_data->uclk_p_state = dc->current_state->clk_mgr->clks.p_state_change_support;
6526	out_data->fams = dc->current_state->bw_ctx.bw.dcn.clk.fw_based_mclk_switching;
6527}
6528
6529bool dc_capture_register_software_state(struct dc *dc, struct dc_register_software_state *state)
6530{
6531	struct dc_state *context;
6532	struct resource_context *res_ctx;
6533	int i;
6534
6535	if (!dc || !dc->current_state || !state) {
6536		if (state)
6537			state->state_valid = false;
6538		return false;
6539	}
6540
6541	/* Initialize the state structure */
6542	memset(state, 0, sizeof(struct dc_register_software_state));
6543
6544	context = dc->current_state;
6545	res_ctx = &context->res_ctx;
6546
6547	/* Count active pipes and streams */
6548	state->active_pipe_count = 0;
6549	state->active_stream_count = context->stream_count;
6550
6551	for (i = 0; i < dc->res_pool->pipe_count; i++) {
6552		if (res_ctx->pipe_ctx[i].stream)
6553			state->active_pipe_count++;
6554	}
6555
6556	/* Capture HUBP programming state for each pipe */
6557	for (i = 0; i < MAX_PIPES && i < dc->res_pool->pipe_count; i++) {
6558		struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[i];
6559
6560		state->hubp[i].valid_stream = false;
6561		if (!pipe_ctx->stream)
6562			continue;
6563
6564		state->hubp[i].valid_stream = true;
6565
6566		/* HUBP register programming variables */
6567		if (pipe_ctx->stream_res.tg)
6568			state->hubp[i].vtg_sel = pipe_ctx->stream_res.tg->inst;
6569
6570		state->hubp[i].hubp_clock_enable = (pipe_ctx->plane_res.hubp != NULL) ? 1 : 0;
6571
6572		state->hubp[i].valid_plane_state = false;
6573		if (pipe_ctx->plane_state) {
6574			state->hubp[i].valid_plane_state = true;
6575			state->hubp[i].surface_pixel_format = pipe_ctx->plane_state->format;
6576			state->hubp[i].rotation_angle = pipe_ctx->plane_state->rotation;
6577			state->hubp[i].h_mirror_en = pipe_ctx->plane_state->horizontal_mirror ? 1 : 0;
6578
6579			/* Surface size */
6580			if (pipe_ctx->plane_state->plane_size.surface_size.width > 0) {
6581				state->hubp[i].surface_size_width = pipe_ctx->plane_state->plane_size.surface_size.width;
6582				state->hubp[i].surface_size_height = pipe_ctx->plane_state->plane_size.surface_size.height;
6583			}
6584
6585			/* Viewport dimensions from scaler data */
6586			if (pipe_ctx->plane_state->src_rect.width > 0) {
6587				state->hubp[i].pri_viewport_width = pipe_ctx->plane_state->src_rect.width;
6588				state->hubp[i].pri_viewport_height = pipe_ctx->plane_state->src_rect.height;
6589				state->hubp[i].pri_viewport_x_start = pipe_ctx->plane_state->src_rect.x;
6590				state->hubp[i].pri_viewport_y_start = pipe_ctx->plane_state->src_rect.y;
6591			}
6592
6593			/* DCC settings */
6594			state->hubp[i].surface_dcc_en = (pipe_ctx->plane_state->dcc.enable) ? 1 : 0;
6595			state->hubp[i].surface_dcc_ind_64b_blk = pipe_ctx->plane_state->dcc.independent_64b_blks;
6596			state->hubp[i].surface_dcc_ind_128b_blk = pipe_ctx->plane_state->dcc.dcc_ind_blk;
6597
6598			/* Surface pitch */
6599			state->hubp[i].surface_pitch = pipe_ctx->plane_state->plane_size.surface_pitch;
6600			state->hubp[i].meta_pitch = pipe_ctx->plane_state->dcc.meta_pitch;
6601			state->hubp[i].chroma_pitch = pipe_ctx->plane_state->plane_size.chroma_pitch;
6602			state->hubp[i].meta_pitch_c = pipe_ctx->plane_state->dcc.meta_pitch_c;
6603
6604			/* Surface addresses - primary */
6605			state->hubp[i].primary_surface_address_low = pipe_ctx->plane_state->address.grph.addr.low_part;
6606			state->hubp[i].primary_surface_address_high = pipe_ctx->plane_state->address.grph.addr.high_part;
6607			state->hubp[i].primary_meta_surface_address_low = pipe_ctx->plane_state->address.grph.meta_addr.low_part;
6608			state->hubp[i].primary_meta_surface_address_high = pipe_ctx->plane_state->address.grph.meta_addr.high_part;
6609
6610			/* TMZ settings */
6611			state->hubp[i].primary_surface_tmz = pipe_ctx->plane_state->address.tmz_surface;
6612			state->hubp[i].primary_meta_surface_tmz = pipe_ctx->plane_state->address.tmz_surface;
6613
6614			/* Tiling configuration */
6615			state->hubp[i].min_dc_gfx_version9 = false;
6616			if (pipe_ctx->plane_state->tiling_info.gfxversion >= DcGfxVersion9) {
6617				state->hubp[i].min_dc_gfx_version9 = true;
6618				state->hubp[i].sw_mode = pipe_ctx->plane_state->tiling_info.gfx9.swizzle;
6619				state->hubp[i].num_pipes = pipe_ctx->plane_state->tiling_info.gfx9.num_pipes;
6620				state->hubp[i].num_banks = pipe_ctx->plane_state->tiling_info.gfx9.num_banks;
6621				state->hubp[i].pipe_interleave = pipe_ctx->plane_state->tiling_info.gfx9.pipe_interleave;
6622				state->hubp[i].num_shader_engines = pipe_ctx->plane_state->tiling_info.gfx9.num_shader_engines;
6623				state->hubp[i].num_rb_per_se = pipe_ctx->plane_state->tiling_info.gfx9.num_rb_per_se;
6624				state->hubp[i].num_pkrs = pipe_ctx->plane_state->tiling_info.gfx9.num_pkrs;
6625			}
6626		}
6627
6628		/* DML Request Size Configuration */
6629		if (pipe_ctx->rq_regs.rq_regs_l.chunk_size > 0) {
6630			state->hubp[i].rq_chunk_size = pipe_ctx->rq_regs.rq_regs_l.chunk_size;
6631			state->hubp[i].rq_min_chunk_size = pipe_ctx->rq_regs.rq_regs_l.min_chunk_size;
6632			state->hubp[i].rq_meta_chunk_size = pipe_ctx->rq_regs.rq_regs_l.meta_chunk_size;
6633			state->hubp[i].rq_min_meta_chunk_size = pipe_ctx->rq_regs.rq_regs_l.min_meta_chunk_size;
6634			state->hubp[i].rq_dpte_group_size = pipe_ctx->rq_regs.rq_regs_l.dpte_group_size;
6635			state->hubp[i].rq_mpte_group_size = pipe_ctx->rq_regs.rq_regs_l.mpte_group_size;
6636			state->hubp[i].rq_swath_height_l = pipe_ctx->rq_regs.rq_regs_l.swath_height;
6637			state->hubp[i].rq_pte_row_height_l = pipe_ctx->rq_regs.rq_regs_l.pte_row_height_linear;
6638		}
6639
6640		/* Chroma request size configuration */
6641		if (pipe_ctx->rq_regs.rq_regs_c.chunk_size > 0) {
6642			state->hubp[i].rq_chunk_size_c = pipe_ctx->rq_regs.rq_regs_c.chunk_size;
6643			state->hubp[i].rq_min_chunk_size_c = pipe_ctx->rq_regs.rq_regs_c.min_chunk_size;
6644			state->hubp[i].rq_meta_chunk_size_c = pipe_ctx->rq_regs.rq_regs_c.meta_chunk_size;
6645			state->hubp[i].rq_min_meta_chunk_size_c = pipe_ctx->rq_regs.rq_regs_c.min_meta_chunk_size;
6646			state->hubp[i].rq_dpte_group_size_c = pipe_ctx->rq_regs.rq_regs_c.dpte_group_size;
6647			state->hubp[i].rq_mpte_group_size_c = pipe_ctx->rq_regs.rq_regs_c.mpte_group_size;
6648			state->hubp[i].rq_swath_height_c = pipe_ctx->rq_regs.rq_regs_c.swath_height;
6649			state->hubp[i].rq_pte_row_height_c = pipe_ctx->rq_regs.rq_regs_c.pte_row_height_linear;
6650		}
6651
6652		/* DML expansion modes */
6653		state->hubp[i].drq_expansion_mode = pipe_ctx->rq_regs.drq_expansion_mode;
6654		state->hubp[i].prq_expansion_mode = pipe_ctx->rq_regs.prq_expansion_mode;
6655		state->hubp[i].mrq_expansion_mode = pipe_ctx->rq_regs.mrq_expansion_mode;
6656		state->hubp[i].crq_expansion_mode = pipe_ctx->rq_regs.crq_expansion_mode;
6657
6658		/* DML DLG parameters - nominal */
6659		state->hubp[i].dst_y_per_vm_vblank = pipe_ctx->dlg_regs.dst_y_per_vm_vblank;
6660		state->hubp[i].dst_y_per_row_vblank = pipe_ctx->dlg_regs.dst_y_per_row_vblank;
6661		state->hubp[i].dst_y_per_vm_flip = pipe_ctx->dlg_regs.dst_y_per_vm_flip;
6662		state->hubp[i].dst_y_per_row_flip = pipe_ctx->dlg_regs.dst_y_per_row_flip;
6663
6664		/* DML prefetch settings */
6665		state->hubp[i].dst_y_prefetch = pipe_ctx->dlg_regs.dst_y_prefetch;
6666		state->hubp[i].vratio_prefetch = pipe_ctx->dlg_regs.vratio_prefetch;
6667		state->hubp[i].vratio_prefetch_c = pipe_ctx->dlg_regs.vratio_prefetch_c;
6668
6669		/* TTU parameters */
6670		state->hubp[i].qos_level_low_wm = pipe_ctx->ttu_regs.qos_level_low_wm;
6671		state->hubp[i].qos_level_high_wm = pipe_ctx->ttu_regs.qos_level_high_wm;
6672		state->hubp[i].qos_level_flip = pipe_ctx->ttu_regs.qos_level_flip;
6673		state->hubp[i].min_ttu_vblank = pipe_ctx->ttu_regs.min_ttu_vblank;
6674	}
6675
6676	/* Capture HUBBUB programming state */
6677	if (dc->res_pool->hubbub) {
6678		/* Individual DET buffer sizes - software state variables that program DET registers */
6679		for (i = 0; i < 4 && i < dc->res_pool->pipe_count; i++) {
6680			uint32_t det_size = res_ctx->pipe_ctx[i].det_buffer_size_kb;
6681			switch (i) {
6682			case 0:
6683				state->hubbub.det0_size = det_size;
6684				break;
6685			case 1:
6686				state->hubbub.det1_size = det_size;
6687				break;
6688			case 2:
6689				state->hubbub.det2_size = det_size;
6690				break;
6691			case 3:
6692				state->hubbub.det3_size = det_size;
6693				break;
6694			}
6695		}
6696
6697		/* Compression buffer configuration - software state that programs COMPBUF_SIZE register */
6698		// TODO: Handle logic for legacy DCN pre-DCN401
6699		state->hubbub.compbuf_size = context->bw_ctx.bw.dcn.arb_regs.compbuf_size;
6700	}
6701
6702	/* Capture DPP programming state for each pipe */
6703	for (i = 0; i < MAX_PIPES && i < dc->res_pool->pipe_count; i++) {
6704		struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[i];
6705
6706		if (!pipe_ctx->stream)
6707			continue;
6708
6709		state->dpp[i].dpp_clock_enable = (pipe_ctx->plane_res.dpp != NULL) ? 1 : 0;
6710
6711		if (pipe_ctx->plane_state && pipe_ctx->plane_res.scl_data.recout.width > 0) {
6712			/* Access dscl_prog_data directly - this contains the actual software state used for register programming */
6713			struct dscl_prog_data *dscl_data = &pipe_ctx->plane_res.scl_data.dscl_prog_data;
6714
6715			/* Recout (Rectangle of Interest) configuration - software state that programs RECOUT registers */
6716			state->dpp[i].recout_start_x = dscl_data->recout.x;
6717			state->dpp[i].recout_start_y = dscl_data->recout.y;
6718			state->dpp[i].recout_width = dscl_data->recout.width;
6719			state->dpp[i].recout_height = dscl_data->recout.height;
6720
6721			/* MPC (Multiple Pipe/Plane Combiner) size - software state that programs MPC_SIZE registers */
6722			state->dpp[i].mpc_width = dscl_data->mpc_size.width;
6723			state->dpp[i].mpc_height = dscl_data->mpc_size.height;
6724
6725			/* DSCL mode - software state that programs SCL_MODE registers */
6726			state->dpp[i].dscl_mode = dscl_data->dscl_mode;
6727
6728			/* Scaler ratios - software state that programs scale ratio registers (use actual programmed ratios) */
6729			state->dpp[i].horz_ratio_int = dscl_data->ratios.h_scale_ratio >> 19; // Extract integer part from programmed ratio
6730			state->dpp[i].vert_ratio_int = dscl_data->ratios.v_scale_ratio >> 19; // Extract integer part from programmed ratio
6731
6732			/* Basic scaler taps - software state that programs tap control registers (use actual programmed taps) */
6733			state->dpp[i].h_taps = dscl_data->taps.h_taps + 1; // dscl_prog_data.taps stores (taps - 1), so add 1 back
6734			state->dpp[i].v_taps = dscl_data->taps.v_taps + 1; // dscl_prog_data.taps stores (taps - 1), so add 1 back
6735		}
6736	}
6737
6738	/* Capture essential clock state for underflow analysis */
6739	if (dc->clk_mgr && dc->clk_mgr->clks.dispclk_khz > 0) {
6740		/* Core display clocks affecting bandwidth and timing */
6741		state->dccg.dispclk_khz = dc->clk_mgr->clks.dispclk_khz;
6742
6743		/* Per-pipe clock configuration - only capture what's essential */
6744		for (i = 0; i < MAX_PIPES && i < dc->res_pool->pipe_count; i++) {
6745			struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[i];
6746			if (pipe_ctx->stream) {
6747				/* Essential clocks that directly affect underflow risk */
6748				state->dccg.dppclk_khz[i] = dc->clk_mgr->clks.dppclk_khz;
6749				state->dccg.pixclk_khz[i] = pipe_ctx->stream->timing.pix_clk_100hz / 10;
6750				state->dccg.dppclk_enable[i] = 1;
6751
6752				/* DP stream clock only for DP signals */
6753				if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT ||
6754						pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) {
6755					state->dccg.dpstreamclk_enable[i] = 1;
6756				} else {
6757					state->dccg.dpstreamclk_enable[i] = 0;
6758				}
6759			} else {
6760				/* Inactive pipe - no clocks */
6761				state->dccg.dppclk_khz[i] = 0;
6762				state->dccg.pixclk_khz[i] = 0;
6763				state->dccg.dppclk_enable[i] = 0;
6764				if (i < 4) {
6765					state->dccg.dpstreamclk_enable[i] = 0;
6766				}
6767			}
6768		}
6769
6770		/* DSC clock state - only when actually using DSC */
6771		for (i = 0; i < MAX_PIPES; i++) {
6772			struct pipe_ctx *pipe_ctx = (i < dc->res_pool->pipe_count) ? &res_ctx->pipe_ctx[i] : NULL;
6773			if (pipe_ctx && pipe_ctx->stream && pipe_ctx->stream->timing.dsc_cfg.num_slices_h > 0) {
6774				state->dccg.dscclk_khz[i] = 400000; /* Typical DSC clock frequency */
6775			} else {
6776				state->dccg.dscclk_khz[i] = 0;
6777			}
6778		}
6779
6780		/* SYMCLK32 LE Control - only the essential HPO state for underflow analysis */
6781		for (i = 0; i < 2; i++) {
6782			state->dccg.symclk32_le_enable[i] = 0; /* Default: disabled */
6783		}
6784
6785	}
6786
6787	/* Capture essential DSC configuration for underflow analysis */
6788	for (i = 0; i < MAX_PIPES && i < dc->res_pool->pipe_count; i++) {
6789		struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[i];
6790
6791		if (pipe_ctx->stream && pipe_ctx->stream->timing.dsc_cfg.num_slices_h > 0) {
6792			/* DSC is enabled - capture essential configuration */
6793			state->dsc[i].dsc_clock_enable = 1;
6794
6795			/* DSC configuration affecting bandwidth and timing */
6796			struct dc_dsc_config *dsc_cfg = &pipe_ctx->stream->timing.dsc_cfg;
6797			state->dsc[i].dsc_num_slices_h = dsc_cfg->num_slices_h;
6798			state->dsc[i].dsc_num_slices_v = dsc_cfg->num_slices_v;
6799			state->dsc[i].dsc_bits_per_pixel = dsc_cfg->bits_per_pixel;
6800
6801			/* OPP pipe source for DSC forwarding */
6802			if (pipe_ctx->stream_res.opp) {
6803				state->dsc[i].dscrm_dsc_forward_enable = 1;
6804				state->dsc[i].dscrm_dsc_opp_pipe_source = pipe_ctx->stream_res.opp->inst;
6805			} else {
6806				state->dsc[i].dscrm_dsc_forward_enable = 0;
6807				state->dsc[i].dscrm_dsc_opp_pipe_source = 0;
6808			}
6809		} else {
6810			/* DSC not enabled - clear all fields */
6811			memset(&state->dsc[i], 0, sizeof(state->dsc[i]));
6812		}
6813	}
6814
6815	/* Capture MPC programming state - comprehensive register field coverage */
6816	for (i = 0; i < MAX_PIPES && i < dc->res_pool->pipe_count; i++) {
6817		struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[i];
6818
6819		if (pipe_ctx->plane_state && pipe_ctx->stream) {
6820			struct dc_plane_state *plane_state = pipe_ctx->plane_state;
6821
6822			/* MPCC blending tree and mode control - capture actual blend configuration */
6823			state->mpc.mpcc_mode[i] = (plane_state->blend_tf.type != TF_TYPE_BYPASS) ? 1 : 0;
6824			state->mpc.mpcc_alpha_blend_mode[i] = plane_state->per_pixel_alpha ? 1 : 0;
6825			state->mpc.mpcc_alpha_multiplied_mode[i] = plane_state->pre_multiplied_alpha ? 1 : 0;
6826			state->mpc.mpcc_blnd_active_overlap_only[i] = 0; /* Default - no overlap restriction */
6827			state->mpc.mpcc_global_alpha[i] = plane_state->global_alpha_value;
6828			state->mpc.mpcc_global_gain[i] = plane_state->global_alpha ? 255 : 0;
6829			state->mpc.mpcc_bg_bpc[i] = 8; /* Standard 8-bit background */
6830			state->mpc.mpcc_bot_gain_mode[i] = 0; /* Standard gain mode */
6831
6832			/* MPCC blending tree connections - capture tree topology */
6833			if (pipe_ctx->bottom_pipe) {
6834				state->mpc.mpcc_bot_sel[i] = pipe_ctx->bottom_pipe->pipe_idx;
6835			} else {
6836				state->mpc.mpcc_bot_sel[i] = 0xF; /* No bottom connection */
6837			}
6838			state->mpc.mpcc_top_sel[i] = pipe_ctx->pipe_idx; /* This pipe's DPP ID */
6839
6840			/* MPCC output gamma control - capture gamma programming */
6841			if (plane_state->gamma_correction.type != GAMMA_CS_TFM_1D && plane_state->gamma_correction.num_entries > 0) {
6842				state->mpc.mpcc_ogam_mode[i] = 1; /* Gamma enabled */
6843				state->mpc.mpcc_ogam_select[i] = 0; /* Bank A selection */
6844				state->mpc.mpcc_ogam_pwl_disable[i] = 0; /* PWL enabled */
6845			} else {
6846				state->mpc.mpcc_ogam_mode[i] = 0; /* Bypass mode */
6847				state->mpc.mpcc_ogam_select[i] = 0;
6848				state->mpc.mpcc_ogam_pwl_disable[i] = 1; /* PWL disabled */
6849			}
6850
6851			/* MPCC pipe assignment and operational status */
6852			if (pipe_ctx->stream_res.opp) {
6853				state->mpc.mpcc_opp_id[i] = pipe_ctx->stream_res.opp->inst;
6854			} else {
6855				state->mpc.mpcc_opp_id[i] = 0xF; /* No OPP assignment */
6856			}
6857
6858			/* MPCC status indicators - active pipe state */
6859			state->mpc.mpcc_idle[i] = 0; /* Active pipe - not idle */
6860			state->mpc.mpcc_busy[i] = 1; /* Active pipe - busy processing */
6861
6862		} else {
6863			/* Pipe not active - set disabled/idle state for all fields */
6864			state->mpc.mpcc_mode[i] = 0;
6865			state->mpc.mpcc_alpha_blend_mode[i] = 0;
6866			state->mpc.mpcc_alpha_multiplied_mode[i] = 0;
6867			state->mpc.mpcc_blnd_active_overlap_only[i] = 0;
6868			state->mpc.mpcc_global_alpha[i] = 0;
6869			state->mpc.mpcc_global_gain[i] = 0;
6870			state->mpc.mpcc_bg_bpc[i] = 0;
6871			state->mpc.mpcc_bot_gain_mode[i] = 0;
6872			state->mpc.mpcc_bot_sel[i] = 0xF; /* No bottom connection */
6873			state->mpc.mpcc_top_sel[i] = 0xF; /* No top connection */
6874			state->mpc.mpcc_ogam_mode[i] = 0; /* Bypass */
6875			state->mpc.mpcc_ogam_select[i] = 0;
6876			state->mpc.mpcc_ogam_pwl_disable[i] = 1; /* PWL disabled */
6877			state->mpc.mpcc_opp_id[i] = 0xF; /* No OPP assignment */
6878			state->mpc.mpcc_idle[i] = 1; /* Idle */
6879			state->mpc.mpcc_busy[i] = 0; /* Not busy */
6880		}
6881	}
6882
6883	/* Capture OPP programming state for each pipe - comprehensive register field coverage */
6884	for (i = 0; i < MAX_PIPES && i < dc->res_pool->pipe_count; i++) {
6885		struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[i];
6886
6887		if (!pipe_ctx->stream)
6888			continue;
6889
6890		if (pipe_ctx->stream_res.opp) {
6891			struct dc_crtc_timing *timing = &pipe_ctx->stream->timing;
6892
6893			/* OPP Pipe Control */
6894			state->opp[i].opp_pipe_clock_enable = 1; /* Active pipe has clock enabled */
6895
6896			/* Display Pattern Generator (DPG) Control - 19 fields */
6897			if (pipe_ctx->stream->test_pattern.type != DP_TEST_PATTERN_VIDEO_MODE) {
6898				state->opp[i].dpg_enable = 1;
6899			} else {
6900				/* Video mode - DPG disabled */
6901				state->opp[i].dpg_enable = 0;
6902			}
6903
6904			/* Format Control (FMT) - 18 fields */
6905			state->opp[i].fmt_pixel_encoding = timing->pixel_encoding;
6906
6907			/* Chroma subsampling mode based on pixel encoding */
6908			if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR420) {
6909				state->opp[i].fmt_subsampling_mode = 1; /* 4:2:0 subsampling */
6910			} else if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR422) {
6911				state->opp[i].fmt_subsampling_mode = 2; /* 4:2:2 subsampling */
6912			} else {
6913				state->opp[i].fmt_subsampling_mode = 0; /* No subsampling (4:4:4) */
6914			}
6915
6916			state->opp[i].fmt_cbcr_bit_reduction_bypass = (timing->pixel_encoding == PIXEL_ENCODING_RGB) ? 1 : 0;
6917			state->opp[i].fmt_stereosync_override = (timing->timing_3d_format != TIMING_3D_FORMAT_NONE) ? 1 : 0;
6918
6919			/* Dithering control based on bit depth */
6920			if (timing->display_color_depth < COLOR_DEPTH_121212) {
6921				state->opp[i].fmt_spatial_dither_frame_counter_max = 15; /* Typical frame counter max */
6922				state->opp[i].fmt_spatial_dither_frame_counter_bit_swap = 0; /* No bit swapping */
6923				state->opp[i].fmt_spatial_dither_enable = 1;
6924				state->opp[i].fmt_spatial_dither_mode = 0; /* Spatial dithering mode */
6925				state->opp[i].fmt_spatial_dither_depth = timing->display_color_depth;
6926				state->opp[i].fmt_temporal_dither_enable = 0; /* Spatial dithering preferred */
6927			} else {
6928				state->opp[i].fmt_spatial_dither_frame_counter_max = 0;
6929				state->opp[i].fmt_spatial_dither_frame_counter_bit_swap = 0;
6930				state->opp[i].fmt_spatial_dither_enable = 0;
6931				state->opp[i].fmt_spatial_dither_mode = 0;
6932				state->opp[i].fmt_spatial_dither_depth = 0;
6933				state->opp[i].fmt_temporal_dither_enable = 0;
6934			}
6935
6936			/* Truncation control for bit depth reduction */
6937			if (timing->display_color_depth < COLOR_DEPTH_121212) {
6938				state->opp[i].fmt_truncate_enable = 1;
6939				state->opp[i].fmt_truncate_depth = timing->display_color_depth;
6940				state->opp[i].fmt_truncate_mode = 0; /* Round mode */
6941			} else {
6942				state->opp[i].fmt_truncate_enable = 0;
6943				state->opp[i].fmt_truncate_depth = 0;
6944				state->opp[i].fmt_truncate_mode = 0;
6945			}
6946
6947			/* Data clamping control */
6948			state->opp[i].fmt_clamp_data_enable = 1; /* Clamping typically enabled */
6949			state->opp[i].fmt_clamp_color_format = timing->pixel_encoding;
6950
6951			/* Dynamic expansion for limited range content */
6952			if (timing->pixel_encoding != PIXEL_ENCODING_RGB) {
6953				state->opp[i].fmt_dynamic_exp_enable = 1; /* YCbCr typically needs expansion */
6954				state->opp[i].fmt_dynamic_exp_mode = 0; /* Standard expansion */
6955			} else {
6956				state->opp[i].fmt_dynamic_exp_enable = 0; /* RGB typically full range */
6957				state->opp[i].fmt_dynamic_exp_mode = 0;
6958			}
6959
6960			/* Legacy field for compatibility */
6961			state->opp[i].fmt_bit_depth_control = timing->display_color_depth;
6962
6963			/* Output Buffer (OPPBUF) Control - 6 fields */
6964			state->opp[i].oppbuf_active_width = timing->h_addressable;
6965			state->opp[i].oppbuf_pixel_repetition = 0; /* No pixel repetition by default */
6966
6967			/* Multi-Stream Output (MSO) / ODM segmentation */
6968			if (pipe_ctx->next_odm_pipe) {
6969				state->opp[i].oppbuf_display_segmentation = 1; /* Segmented display */
6970				state->opp[i].oppbuf_overlap_pixel_num = 0; /* ODM overlap pixels */
6971			} else {
6972				state->opp[i].oppbuf_display_segmentation = 0; /* Single segment */
6973				state->opp[i].oppbuf_overlap_pixel_num = 0;
6974			}
6975
6976			/* 3D/Stereo control */
6977			if (timing->timing_3d_format != TIMING_3D_FORMAT_NONE) {
6978				state->opp[i].oppbuf_3d_vact_space1_size = 30; /* Typical stereo blanking */
6979				state->opp[i].oppbuf_3d_vact_space2_size = 30;
6980			} else {
6981				state->opp[i].oppbuf_3d_vact_space1_size = 0;
6982				state->opp[i].oppbuf_3d_vact_space2_size = 0;
6983			}
6984
6985			/* DSC Forward Config - 3 fields */
6986			if (timing->dsc_cfg.num_slices_h > 0) {
6987				state->opp[i].dscrm_dsc_forward_enable = 1;
6988				state->opp[i].dscrm_dsc_opp_pipe_source = pipe_ctx->stream_res.opp->inst;
6989				state->opp[i].dscrm_dsc_forward_enable_status = 1; /* Status follows enable */
6990			} else {
6991				state->opp[i].dscrm_dsc_forward_enable = 0;
6992				state->opp[i].dscrm_dsc_opp_pipe_source = 0;
6993				state->opp[i].dscrm_dsc_forward_enable_status = 0;
6994			}
6995		} else {
6996			/* No OPP resource - set all fields to disabled state */
6997			memset(&state->opp[i], 0, sizeof(state->opp[i]));
6998		}
6999	}
7000
7001	/* Capture OPTC programming state for each pipe - comprehensive register field coverage */
7002	for (i = 0; i < MAX_PIPES && i < dc->res_pool->pipe_count; i++) {
7003		struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[i];
7004
7005		if (!pipe_ctx->stream)
7006			continue;
7007
7008		if (pipe_ctx->stream_res.tg) {
7009			struct dc_crtc_timing *timing = &pipe_ctx->stream->timing;
7010
7011			state->optc[i].otg_master_inst = pipe_ctx->stream_res.tg->inst;
7012
7013			/* OTG_CONTROL register - 5 fields */
7014			state->optc[i].otg_master_enable = 1; /* Active stream */
7015			state->optc[i].otg_disable_point_cntl = 0; /* Normal operation */
7016			state->optc[i].otg_start_point_cntl = 0; /* Normal start */
7017			state->optc[i].otg_field_number_cntl = (timing->flags.INTERLACE) ? 1 : 0;
7018			state->optc[i].otg_out_mux = 0; /* Direct output */
7019
7020			/* OTG Horizontal Timing - 7 fields */
7021			state->optc[i].otg_h_total = timing->h_total;
7022			state->optc[i].otg_h_blank_start = timing->h_addressable;
7023			state->optc[i].otg_h_blank_end = timing->h_total - timing->h_front_porch;
7024			state->optc[i].otg_h_sync_start = timing->h_addressable + timing->h_front_porch;
7025			state->optc[i].otg_h_sync_end = timing->h_addressable + timing->h_front_porch + timing->h_sync_width;
7026			state->optc[i].otg_h_sync_polarity = timing->flags.HSYNC_POSITIVE_POLARITY ? 0 : 1;
7027			state->optc[i].otg_h_timing_div_mode = (pipe_ctx->next_odm_pipe) ? 1 : 0; /* ODM divide mode */
7028
7029			/* OTG Vertical Timing - 7 fields */
7030			state->optc[i].otg_v_total = timing->v_total;
7031			state->optc[i].otg_v_blank_start = timing->v_addressable;
7032			state->optc[i].otg_v_blank_end = timing->v_total - timing->v_front_porch;
7033			state->optc[i].otg_v_sync_start = timing->v_addressable + timing->v_front_porch;
7034			state->optc[i].otg_v_sync_end = timing->v_addressable + timing->v_front_porch + timing->v_sync_width;
7035			state->optc[i].otg_v_sync_polarity = timing->flags.VSYNC_POSITIVE_POLARITY ? 0 : 1;
7036			state->optc[i].otg_v_sync_mode = 0; /* Normal sync mode */
7037
7038			/* Initialize remaining core fields with appropriate defaults */
7039			// TODO: Update logic for accurate vtotal min/max
7040			state->optc[i].otg_v_total_max = timing->v_total + 100; /* Typical DRR range */
7041			state->optc[i].otg_v_total_min = timing->v_total - 50;
7042			state->optc[i].otg_v_total_mid = timing->v_total;
7043
7044			/* ODM configuration */
7045			// TODO: Update logic to have complete ODM mappings (e.g. 3:1 and 4:1) stored in single pipe
7046			if (pipe_ctx->next_odm_pipe) {
7047				state->optc[i].optc_seg0_src_sel = pipe_ctx->stream_res.opp ? pipe_ctx->stream_res.opp->inst : 0;
7048				state->optc[i].optc_seg1_src_sel = pipe_ctx->next_odm_pipe->stream_res.opp ? pipe_ctx->next_odm_pipe->stream_res.opp->inst : 0;
7049				state->optc[i].optc_num_of_input_segment = 1; /* 2 segments - 1 */
7050			} else {
7051				state->optc[i].optc_seg0_src_sel = pipe_ctx->stream_res.opp ? pipe_ctx->stream_res.opp->inst : 0;
7052				state->optc[i].optc_seg1_src_sel = 0;
7053				state->optc[i].optc_num_of_input_segment = 0; /* Single segment */
7054			}
7055
7056			/* DSC configuration */
7057			if (timing->dsc_cfg.num_slices_h > 0) {
7058				state->optc[i].optc_dsc_mode = 1; /* DSC enabled */
7059				state->optc[i].optc_dsc_bytes_per_pixel = timing->dsc_cfg.bits_per_pixel / 16; /* Convert to bytes */
7060				state->optc[i].optc_dsc_slice_width = timing->h_addressable / timing->dsc_cfg.num_slices_h;
7061			} else {
7062				state->optc[i].optc_dsc_mode = 0;
7063				state->optc[i].optc_dsc_bytes_per_pixel = 0;
7064				state->optc[i].optc_dsc_slice_width = 0;
7065			}
7066
7067			/* Essential control fields */
7068			state->optc[i].otg_stereo_enable = (timing->timing_3d_format != TIMING_3D_FORMAT_NONE) ? 1 : 0;
7069			state->optc[i].otg_interlace_enable = timing->flags.INTERLACE ? 1 : 0;
7070			state->optc[i].otg_clock_enable = 1; /* OTG clock enabled */
7071			state->optc[i].vtg0_enable = 1; /* VTG enabled for timing generation */
7072
7073			/* Initialize other key fields to defaults */
7074			state->optc[i].optc_input_pix_clk_en = 1;
7075			state->optc[i].optc_segment_width = (pipe_ctx->next_odm_pipe) ? (timing->h_addressable / 2) : timing->h_addressable;
7076			state->optc[i].otg_vready_offset = 1;
7077			state->optc[i].otg_vstartup_start = timing->v_addressable + 10;
7078			state->optc[i].otg_vupdate_offset = 0;
7079			state->optc[i].otg_vupdate_width = 5;
7080		} else {
7081			/* No timing generator resource - initialize all fields to 0 */
7082			memset(&state->optc[i], 0, sizeof(state->optc[i]));
7083		}
7084	}
7085
7086	state->state_valid = true;
7087	return true;
7088}
7089
7090void dc_log_preos_dmcub_info(const struct dc *dc)
7091{
7092	dc_dmub_srv_log_preos_dmcub_info(dc->ctx->dmub_srv);
7093}
~/ Read-only file preview.