14562236bSHarry Wentland /*
24562236bSHarry Wentland  * Copyright 2012-15 Advanced Micro Devices, Inc.
34562236bSHarry Wentland  *
44562236bSHarry Wentland  * Permission is hereby granted, free of charge, to any person obtaining a
54562236bSHarry Wentland  * copy of this software and associated documentation files (the "Software"),
64562236bSHarry Wentland  * to deal in the Software without restriction, including without limitation
74562236bSHarry Wentland  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
84562236bSHarry Wentland  * and/or sell copies of the Software, and to permit persons to whom the
94562236bSHarry Wentland  * Software is furnished to do so, subject to the following conditions:
104562236bSHarry Wentland  *
114562236bSHarry Wentland  * The above copyright notice and this permission notice shall be included in
124562236bSHarry Wentland  * all copies or substantial portions of the Software.
134562236bSHarry Wentland  *
144562236bSHarry Wentland  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
154562236bSHarry Wentland  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
164562236bSHarry Wentland  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
174562236bSHarry Wentland  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
184562236bSHarry Wentland  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
194562236bSHarry Wentland  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
204562236bSHarry Wentland  * OTHER DEALINGS IN THE SOFTWARE.
214562236bSHarry Wentland  *
224562236bSHarry Wentland  * Authors: AMD
234562236bSHarry Wentland  *
244562236bSHarry Wentland  */
254fc4dca8SSam Ravnborg 
264fc4dca8SSam Ravnborg #include <linux/slab.h>
274fc4dca8SSam Ravnborg 
284562236bSHarry Wentland #include "dm_services.h"
294562236bSHarry Wentland 
304562236bSHarry Wentland #include "resource.h"
314562236bSHarry Wentland #include "include/irq_service_interface.h"
324562236bSHarry Wentland #include "link_encoder.h"
334562236bSHarry Wentland #include "stream_encoder.h"
344562236bSHarry Wentland #include "opp.h"
354562236bSHarry Wentland #include "timing_generator.h"
364562236bSHarry Wentland #include "transform.h"
3733d7598dSJun Lei #include "dccg.h"
3833d7598dSJun Lei #include "dchubbub.h"
39d94585a0SYue Hin Lau #include "dpp.h"
405ac3d3c9SCharlene Liu #include "core_types.h"
414562236bSHarry Wentland #include "set_mode_types.h"
424562236bSHarry Wentland #include "virtual/virtual_stream_encoder.h"
433b94a400STao #include "dpcd_defs.h"
44*0d4b4253SJimmy Kizito #include "link_enc_cfg.h"
45f01ee019SFangzhi Zuo #include "dc_link_dp.h"
464562236bSHarry Wentland 
47683b5950SMauro Rossi #if defined(CONFIG_DRM_AMD_DC_SI)
48683b5950SMauro Rossi #include "dce60/dce60_resource.h"
49683b5950SMauro Rossi #endif
504562236bSHarry Wentland #include "dce80/dce80_resource.h"
514562236bSHarry Wentland #include "dce100/dce100_resource.h"
524562236bSHarry Wentland #include "dce110/dce110_resource.h"
534562236bSHarry Wentland #include "dce112/dce112_resource.h"
54cf2156e2SAlex Deucher #include "dce120/dce120_resource.h"
55b86a1aa3SBhawanpreet Lakha #if defined(CONFIG_DRM_AMD_DC_DCN)
56ff5ef992SAlex Deucher #include "dcn10/dcn10_resource.h"
577ed4e635SHarry Wentland #include "dcn20/dcn20_resource.h"
58e22ece54SBhawanpreet Lakha #include "dcn21/dcn21_resource.h"
5920f2ffe5SAlex Deucher #include "dcn30/dcn30_resource.h"
6020f2ffe5SAlex Deucher #include "dcn301/dcn301_resource.h"
6120f2ffe5SAlex Deucher #include "dcn302/dcn302_resource.h"
62cd6d421eSAurabindo Pillai #include "dcn303/dcn303_resource.h"
638fe44c08SAlex Deucher #include "dcn31/dcn31_resource.h"
6436d26912SBhawanpreet Lakha #endif
655d4b05ddSBhawanpreet Lakha 
665d4b05ddSBhawanpreet Lakha #define DC_LOGGER_INIT(logger)
675d4b05ddSBhawanpreet Lakha 
684562236bSHarry Wentland enum dce_version resource_parse_asic_id(struct hw_asic_id asic_id)
694562236bSHarry Wentland {
704562236bSHarry Wentland 	enum dce_version dc_version = DCE_VERSION_UNKNOWN;
714562236bSHarry Wentland 	switch (asic_id.chip_family) {
724562236bSHarry Wentland 
73683b5950SMauro Rossi #if defined(CONFIG_DRM_AMD_DC_SI)
74683b5950SMauro Rossi 	case FAMILY_SI:
75683b5950SMauro Rossi 		if (ASIC_REV_IS_TAHITI_P(asic_id.hw_internal_rev) ||
76683b5950SMauro Rossi 		    ASIC_REV_IS_PITCAIRN_PM(asic_id.hw_internal_rev) ||
77683b5950SMauro Rossi 		    ASIC_REV_IS_CAPEVERDE_M(asic_id.hw_internal_rev))
78683b5950SMauro Rossi 			dc_version = DCE_VERSION_6_0;
79683b5950SMauro Rossi 		else if (ASIC_REV_IS_OLAND_M(asic_id.hw_internal_rev))
80683b5950SMauro Rossi 			dc_version = DCE_VERSION_6_4;
81683b5950SMauro Rossi 		else
82683b5950SMauro Rossi 			dc_version = DCE_VERSION_6_1;
83683b5950SMauro Rossi 		break;
84683b5950SMauro Rossi #endif
854562236bSHarry Wentland 	case FAMILY_CI:
864562236bSHarry Wentland 		dc_version = DCE_VERSION_8_0;
874562236bSHarry Wentland 		break;
88ebfdf0d0SAlex Deucher 	case FAMILY_KV:
89ebfdf0d0SAlex Deucher 		if (ASIC_REV_IS_KALINDI(asic_id.hw_internal_rev) ||
90ebfdf0d0SAlex Deucher 		    ASIC_REV_IS_BHAVANI(asic_id.hw_internal_rev) ||
91ebfdf0d0SAlex Deucher 		    ASIC_REV_IS_GODAVARI(asic_id.hw_internal_rev))
92ebfdf0d0SAlex Deucher 			dc_version = DCE_VERSION_8_3;
93ebfdf0d0SAlex Deucher 		else
94ebfdf0d0SAlex Deucher 			dc_version = DCE_VERSION_8_1;
95ebfdf0d0SAlex Deucher 		break;
964562236bSHarry Wentland 	case FAMILY_CZ:
974562236bSHarry Wentland 		dc_version = DCE_VERSION_11_0;
984562236bSHarry Wentland 		break;
994562236bSHarry Wentland 
1004562236bSHarry Wentland 	case FAMILY_VI:
1014562236bSHarry Wentland 		if (ASIC_REV_IS_TONGA_P(asic_id.hw_internal_rev) ||
1024562236bSHarry Wentland 				ASIC_REV_IS_FIJI_P(asic_id.hw_internal_rev)) {
1034562236bSHarry Wentland 			dc_version = DCE_VERSION_10_0;
1044562236bSHarry Wentland 			break;
1054562236bSHarry Wentland 		}
1064562236bSHarry Wentland 		if (ASIC_REV_IS_POLARIS10_P(asic_id.hw_internal_rev) ||
107b264d345SJordan Lazare 				ASIC_REV_IS_POLARIS11_M(asic_id.hw_internal_rev) ||
108b264d345SJordan Lazare 				ASIC_REV_IS_POLARIS12_V(asic_id.hw_internal_rev)) {
1094562236bSHarry Wentland 			dc_version = DCE_VERSION_11_2;
1104562236bSHarry Wentland 		}
1110c75d5acSJerry (Fangzhi) Zuo 		if (ASIC_REV_IS_VEGAM(asic_id.hw_internal_rev))
1120c75d5acSJerry (Fangzhi) Zuo 			dc_version = DCE_VERSION_11_22;
1134562236bSHarry Wentland 		break;
1142c8ad2d5SAlex Deucher 	case FAMILY_AI:
115b8b6ce89SLeo Li 		if (ASICREV_IS_VEGA20_P(asic_id.hw_internal_rev))
116b8b6ce89SLeo Li 			dc_version = DCE_VERSION_12_1;
117b8b6ce89SLeo Li 		else
1182c8ad2d5SAlex Deucher 			dc_version = DCE_VERSION_12_0;
1192c8ad2d5SAlex Deucher 		break;
120b86a1aa3SBhawanpreet Lakha #if defined(CONFIG_DRM_AMD_DC_DCN)
121ff5ef992SAlex Deucher 	case FAMILY_RV:
122ff5ef992SAlex Deucher 		dc_version = DCN_VERSION_1_0;
1230e3d73f1SBhawanpreet Lakha 		if (ASICREV_IS_RAVEN2(asic_id.hw_internal_rev))
1240e3d73f1SBhawanpreet Lakha 			dc_version = DCN_VERSION_1_01;
125e22ece54SBhawanpreet Lakha 		if (ASICREV_IS_RENOIR(asic_id.hw_internal_rev))
126e22ece54SBhawanpreet Lakha 			dc_version = DCN_VERSION_2_1;
1279ba93114SRoman Li 		if (ASICREV_IS_GREEN_SARDINE(asic_id.hw_internal_rev))
1289ba93114SRoman Li 			dc_version = DCN_VERSION_2_1;
129ff5ef992SAlex Deucher 		break;
1307ed4e635SHarry Wentland 
1317ed4e635SHarry Wentland 	case FAMILY_NV:
1327ed4e635SHarry Wentland 		dc_version = DCN_VERSION_2_0;
1335dba4991SBhawanpreet Lakha 		if (ASICREV_IS_SIENNA_CICHLID_P(asic_id.hw_internal_rev))
1345dba4991SBhawanpreet Lakha 			dc_version = DCN_VERSION_3_0;
13536d26912SBhawanpreet Lakha 		if (ASICREV_IS_DIMGREY_CAVEFISH_P(asic_id.hw_internal_rev))
13636d26912SBhawanpreet Lakha 			dc_version = DCN_VERSION_3_02;
137cd6d421eSAurabindo Pillai 		if (ASICREV_IS_BEIGE_GOBY_P(asic_id.hw_internal_rev))
138cd6d421eSAurabindo Pillai 			dc_version = DCN_VERSION_3_03;
1397ed4e635SHarry Wentland 		break;
1403a83e4e6SRoman Li 
1413a83e4e6SRoman Li 	case FAMILY_VGH:
1423a83e4e6SRoman Li 		dc_version = DCN_VERSION_3_01;
1433a83e4e6SRoman Li 		break;
1442083640fSNicholas Kazlauskas 
1452083640fSNicholas Kazlauskas 	case FAMILY_YELLOW_CARP:
1462083640fSNicholas Kazlauskas 		if (ASICREV_IS_YELLOW_CARP(asic_id.hw_internal_rev))
1472083640fSNicholas Kazlauskas 			dc_version = DCN_VERSION_3_1;
1482083640fSNicholas Kazlauskas 		break;
1492083640fSNicholas Kazlauskas #endif
1502083640fSNicholas Kazlauskas 
1514562236bSHarry Wentland 	default:
1524562236bSHarry Wentland 		dc_version = DCE_VERSION_UNKNOWN;
1534562236bSHarry Wentland 		break;
1544562236bSHarry Wentland 	}
1554562236bSHarry Wentland 	return dc_version;
1564562236bSHarry Wentland }
1574562236bSHarry Wentland 
158d9673c92SHarry Wentland struct resource_pool *dc_create_resource_pool(struct dc  *dc,
159d9673c92SHarry Wentland 					      const struct dc_init_data *init_data,
160d9673c92SHarry Wentland 					      enum dce_version dc_version)
1614562236bSHarry Wentland {
1625ac3d3c9SCharlene Liu 	struct resource_pool *res_pool = NULL;
1634562236bSHarry Wentland 
1644562236bSHarry Wentland 	switch (dc_version) {
165683b5950SMauro Rossi #if defined(CONFIG_DRM_AMD_DC_SI)
166683b5950SMauro Rossi 	case DCE_VERSION_6_0:
167683b5950SMauro Rossi 		res_pool = dce60_create_resource_pool(
168683b5950SMauro Rossi 			init_data->num_virtual_links, dc);
169683b5950SMauro Rossi 		break;
170683b5950SMauro Rossi 	case DCE_VERSION_6_1:
171683b5950SMauro Rossi 		res_pool = dce61_create_resource_pool(
172683b5950SMauro Rossi 			init_data->num_virtual_links, dc);
173683b5950SMauro Rossi 		break;
174683b5950SMauro Rossi 	case DCE_VERSION_6_4:
175683b5950SMauro Rossi 		res_pool = dce64_create_resource_pool(
176683b5950SMauro Rossi 			init_data->num_virtual_links, dc);
177683b5950SMauro Rossi 		break;
178683b5950SMauro Rossi #endif
1794562236bSHarry Wentland 	case DCE_VERSION_8_0:
1805ac3d3c9SCharlene Liu 		res_pool = dce80_create_resource_pool(
181d9673c92SHarry Wentland 				init_data->num_virtual_links, dc);
1825ac3d3c9SCharlene Liu 		break;
1837992a629SAlex Deucher 	case DCE_VERSION_8_1:
1847992a629SAlex Deucher 		res_pool = dce81_create_resource_pool(
185d9673c92SHarry Wentland 				init_data->num_virtual_links, dc);
1867992a629SAlex Deucher 		break;
1877992a629SAlex Deucher 	case DCE_VERSION_8_3:
1887992a629SAlex Deucher 		res_pool = dce83_create_resource_pool(
189d9673c92SHarry Wentland 				init_data->num_virtual_links, dc);
1907992a629SAlex Deucher 		break;
1914562236bSHarry Wentland 	case DCE_VERSION_10_0:
1925ac3d3c9SCharlene Liu 		res_pool = dce100_create_resource_pool(
193d9673c92SHarry Wentland 				init_data->num_virtual_links, dc);
1945ac3d3c9SCharlene Liu 		break;
1954562236bSHarry Wentland 	case DCE_VERSION_11_0:
1965ac3d3c9SCharlene Liu 		res_pool = dce110_create_resource_pool(
197d9673c92SHarry Wentland 				init_data->num_virtual_links, dc,
198d9673c92SHarry Wentland 				init_data->asic_id);
1995ac3d3c9SCharlene Liu 		break;
2004562236bSHarry Wentland 	case DCE_VERSION_11_2:
2010c75d5acSJerry (Fangzhi) Zuo 	case DCE_VERSION_11_22:
2025ac3d3c9SCharlene Liu 		res_pool = dce112_create_resource_pool(
203d9673c92SHarry Wentland 				init_data->num_virtual_links, dc);
2045ac3d3c9SCharlene Liu 		break;
2052c8ad2d5SAlex Deucher 	case DCE_VERSION_12_0:
206b8b6ce89SLeo Li 	case DCE_VERSION_12_1:
2072c8ad2d5SAlex Deucher 		res_pool = dce120_create_resource_pool(
208d9673c92SHarry Wentland 				init_data->num_virtual_links, dc);
2092c8ad2d5SAlex Deucher 		break;
210ff5ef992SAlex Deucher 
211b86a1aa3SBhawanpreet Lakha #if defined(CONFIG_DRM_AMD_DC_DCN)
212ff5ef992SAlex Deucher 	case DCN_VERSION_1_0:
2130e3d73f1SBhawanpreet Lakha 	case DCN_VERSION_1_01:
214d9673c92SHarry Wentland 		res_pool = dcn10_create_resource_pool(init_data, dc);
215ff5ef992SAlex Deucher 		break;
2167ed4e635SHarry Wentland 	case DCN_VERSION_2_0:
2177ed4e635SHarry Wentland 		res_pool = dcn20_create_resource_pool(init_data, dc);
2187ed4e635SHarry Wentland 		break;
219e22ece54SBhawanpreet Lakha 	case DCN_VERSION_2_1:
220e22ece54SBhawanpreet Lakha 		res_pool = dcn21_create_resource_pool(init_data, dc);
221e22ece54SBhawanpreet Lakha 		break;
2225dba4991SBhawanpreet Lakha 	case DCN_VERSION_3_0:
2235dba4991SBhawanpreet Lakha 		res_pool = dcn30_create_resource_pool(init_data, dc);
2245dba4991SBhawanpreet Lakha 		break;
2253a83e4e6SRoman Li 	case DCN_VERSION_3_01:
2263a83e4e6SRoman Li 		res_pool = dcn301_create_resource_pool(init_data, dc);
2273a83e4e6SRoman Li 		break;
22836d26912SBhawanpreet Lakha 	case DCN_VERSION_3_02:
22936d26912SBhawanpreet Lakha 		res_pool = dcn302_create_resource_pool(init_data, dc);
23036d26912SBhawanpreet Lakha 		break;
231cd6d421eSAurabindo Pillai 	case DCN_VERSION_3_03:
232cd6d421eSAurabindo Pillai 		res_pool = dcn303_create_resource_pool(init_data, dc);
233cd6d421eSAurabindo Pillai 		break;
2342083640fSNicholas Kazlauskas 	case DCN_VERSION_3_1:
2352083640fSNicholas Kazlauskas 		res_pool = dcn31_create_resource_pool(init_data, dc);
2362083640fSNicholas Kazlauskas 		break;
2372083640fSNicholas Kazlauskas #endif
2384562236bSHarry Wentland 	default:
2394562236bSHarry Wentland 		break;
2404562236bSHarry Wentland 	}
241f49cfa27Shersen wu 
2425ac3d3c9SCharlene Liu 	if (res_pool != NULL) {
2439adc8050SDmytro Laktyushkin 		if (dc->ctx->dc_bios->fw_info_valid) {
24441a5a2a8Shersen wu 			res_pool->ref_clocks.xtalin_clock_inKhz =
2459adc8050SDmytro Laktyushkin 				dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency;
24641a5a2a8Shersen wu 			/* initialize with firmware data first, no all
24741a5a2a8Shersen wu 			 * ASIC have DCCG SW component. FPGA or
24841a5a2a8Shersen wu 			 * simulation need initialization of
24941a5a2a8Shersen wu 			 * dccg_ref_clock_inKhz, dchub_ref_clock_inKhz
25041a5a2a8Shersen wu 			 * with xtalin_clock_inKhz
25141a5a2a8Shersen wu 			 */
25241a5a2a8Shersen wu 			res_pool->ref_clocks.dccg_ref_clock_inKhz =
25341a5a2a8Shersen wu 				res_pool->ref_clocks.xtalin_clock_inKhz;
25441a5a2a8Shersen wu 			res_pool->ref_clocks.dchub_ref_clock_inKhz =
25541a5a2a8Shersen wu 				res_pool->ref_clocks.xtalin_clock_inKhz;
2565ac3d3c9SCharlene Liu 		} else
2575ac3d3c9SCharlene Liu 			ASSERT_CRITICAL(false);
2585ac3d3c9SCharlene Liu 	}
2595ac3d3c9SCharlene Liu 
2605ac3d3c9SCharlene Liu 	return res_pool;
2614562236bSHarry Wentland }
2624562236bSHarry Wentland 
263fb3466a4SBhawanpreet Lakha void dc_destroy_resource_pool(struct dc  *dc)
2644562236bSHarry Wentland {
2654562236bSHarry Wentland 	if (dc) {
2664562236bSHarry Wentland 		if (dc->res_pool)
2674562236bSHarry Wentland 			dc->res_pool->funcs->destroy(&dc->res_pool);
2684562236bSHarry Wentland 
2692004f45eSHarry Wentland 		kfree(dc->hwseq);
2704562236bSHarry Wentland 	}
2714562236bSHarry Wentland }
2724562236bSHarry Wentland 
2734562236bSHarry Wentland static void update_num_audio(
2744562236bSHarry Wentland 	const struct resource_straps *straps,
2754562236bSHarry Wentland 	unsigned int *num_audio,
2764562236bSHarry Wentland 	struct audio_support *aud_support)
2774562236bSHarry Wentland {
2784562236bSHarry Wentland 	aud_support->dp_audio = true;
279b8e9eb72SCharlene Liu 	aud_support->hdmi_audio_native = false;
280b8e9eb72SCharlene Liu 	aud_support->hdmi_audio_on_dongle = false;
281b8e9eb72SCharlene Liu 
282b8e9eb72SCharlene Liu 	if (straps->hdmi_disable == 0) {
2834562236bSHarry Wentland 		if (straps->dc_pinstraps_audio & 0x2) {
2844562236bSHarry Wentland 			aud_support->hdmi_audio_on_dongle = true;
285b8e9eb72SCharlene Liu 			aud_support->hdmi_audio_native = true;
2864562236bSHarry Wentland 		}
2874562236bSHarry Wentland 	}
2884562236bSHarry Wentland 
2894562236bSHarry Wentland 	switch (straps->audio_stream_number) {
2904562236bSHarry Wentland 	case 0: /* multi streams supported */
2914562236bSHarry Wentland 		break;
2924562236bSHarry Wentland 	case 1: /* multi streams not supported */
2934562236bSHarry Wentland 		*num_audio = 1;
2944562236bSHarry Wentland 		break;
2954562236bSHarry Wentland 	default:
2964562236bSHarry Wentland 		DC_ERR("DC: unexpected audio fuse!\n");
29717a96033SJulia Lawall 	}
2984562236bSHarry Wentland }
2994562236bSHarry Wentland 
3004562236bSHarry Wentland bool resource_construct(
3014562236bSHarry Wentland 	unsigned int num_virtual_links,
302fb3466a4SBhawanpreet Lakha 	struct dc  *dc,
3034562236bSHarry Wentland 	struct resource_pool *pool,
3044562236bSHarry Wentland 	const struct resource_create_funcs *create_funcs)
3054562236bSHarry Wentland {
3064562236bSHarry Wentland 	struct dc_context *ctx = dc->ctx;
3074562236bSHarry Wentland 	const struct resource_caps *caps = pool->res_cap;
3084562236bSHarry Wentland 	int i;
3094562236bSHarry Wentland 	unsigned int num_audio = caps->num_audio;
3104562236bSHarry Wentland 	struct resource_straps straps = {0};
3114562236bSHarry Wentland 
3124562236bSHarry Wentland 	if (create_funcs->read_dce_straps)
3134562236bSHarry Wentland 		create_funcs->read_dce_straps(dc->ctx, &straps);
3144562236bSHarry Wentland 
3154562236bSHarry Wentland 	pool->audio_count = 0;
3164562236bSHarry Wentland 	if (create_funcs->create_audio) {
3174562236bSHarry Wentland 		/* find the total number of streams available via the
3184562236bSHarry Wentland 		 * AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_CONFIGURATION_DEFAULT
3194562236bSHarry Wentland 		 * registers (one for each pin) starting from pin 1
3204562236bSHarry Wentland 		 * up to the max number of audio pins.
3214562236bSHarry Wentland 		 * We stop on the first pin where
3224562236bSHarry Wentland 		 * PORT_CONNECTIVITY == 1 (as instructed by HW team).
3234562236bSHarry Wentland 		 */
3244562236bSHarry Wentland 		update_num_audio(&straps, &num_audio, &pool->audio_support);
3255feb9f07STai Man 		for (i = 0; i < caps->num_audio; i++) {
3264562236bSHarry Wentland 			struct audio *aud = create_funcs->create_audio(ctx, i);
3274562236bSHarry Wentland 
3284562236bSHarry Wentland 			if (aud == NULL) {
3294562236bSHarry Wentland 				DC_ERR("DC: failed to create audio!\n");
3304562236bSHarry Wentland 				return false;
3314562236bSHarry Wentland 			}
3324562236bSHarry Wentland 			if (!aud->funcs->endpoint_valid(aud)) {
3334562236bSHarry Wentland 				aud->funcs->destroy(&aud);
3344562236bSHarry Wentland 				break;
3354562236bSHarry Wentland 			}
3364562236bSHarry Wentland 			pool->audios[i] = aud;
3374562236bSHarry Wentland 			pool->audio_count++;
3384562236bSHarry Wentland 		}
3394562236bSHarry Wentland 	}
3404562236bSHarry Wentland 
3414562236bSHarry Wentland 	pool->stream_enc_count = 0;
3424562236bSHarry Wentland 	if (create_funcs->create_stream_encoder) {
3434562236bSHarry Wentland 		for (i = 0; i < caps->num_stream_encoder; i++) {
3444562236bSHarry Wentland 			pool->stream_enc[i] = create_funcs->create_stream_encoder(i, ctx);
3454562236bSHarry Wentland 			if (pool->stream_enc[i] == NULL)
3464562236bSHarry Wentland 				DC_ERR("DC: failed to create stream_encoder!\n");
3474562236bSHarry Wentland 			pool->stream_enc_count++;
3484562236bSHarry Wentland 		}
3494562236bSHarry Wentland 	}
350929c3aaaSEric Bernstein 
35120f2ffe5SAlex Deucher #if defined(CONFIG_DRM_AMD_DC_DCN)
352f01ee019SFangzhi Zuo 	pool->hpo_dp_stream_enc_count = 0;
353f01ee019SFangzhi Zuo 	if (create_funcs->create_hpo_dp_stream_encoder) {
354f01ee019SFangzhi Zuo 		for (i = 0; i < caps->num_hpo_dp_stream_encoder; i++) {
355f01ee019SFangzhi Zuo 			pool->hpo_dp_stream_enc[i] = create_funcs->create_hpo_dp_stream_encoder(i+ENGINE_ID_HPO_DP_0, ctx);
356f01ee019SFangzhi Zuo 			if (pool->hpo_dp_stream_enc[i] == NULL)
357f01ee019SFangzhi Zuo 				DC_ERR("DC: failed to create HPO DP stream encoder!\n");
358f01ee019SFangzhi Zuo 			pool->hpo_dp_stream_enc_count++;
359f01ee019SFangzhi Zuo 
360f01ee019SFangzhi Zuo 		}
361f01ee019SFangzhi Zuo 	}
362f01ee019SFangzhi Zuo 
363f01ee019SFangzhi Zuo 	pool->hpo_dp_link_enc_count = 0;
364f01ee019SFangzhi Zuo 	if (create_funcs->create_hpo_dp_link_encoder) {
365f01ee019SFangzhi Zuo 		for (i = 0; i < caps->num_hpo_dp_link_encoder; i++) {
366f01ee019SFangzhi Zuo 			pool->hpo_dp_link_enc[i] = create_funcs->create_hpo_dp_link_encoder(i, ctx);
367f01ee019SFangzhi Zuo 			if (pool->hpo_dp_link_enc[i] == NULL)
368f01ee019SFangzhi Zuo 				DC_ERR("DC: failed to create HPO DP link encoder!\n");
369f01ee019SFangzhi Zuo 			pool->hpo_dp_link_enc_count++;
370f01ee019SFangzhi Zuo 		}
371f01ee019SFangzhi Zuo 	}
372f01ee019SFangzhi Zuo #endif
373f01ee019SFangzhi Zuo 
374f01ee019SFangzhi Zuo #if defined(CONFIG_DRM_AMD_DC_DCN)
3755dba4991SBhawanpreet Lakha 	for (i = 0; i < caps->num_mpc_3dlut; i++) {
3765dba4991SBhawanpreet Lakha 		pool->mpc_lut[i] = dc_create_3dlut_func();
3775dba4991SBhawanpreet Lakha 		if (pool->mpc_lut[i] == NULL)
3785dba4991SBhawanpreet Lakha 			DC_ERR("DC: failed to create MPC 3dlut!\n");
3795dba4991SBhawanpreet Lakha 		pool->mpc_shaper[i] = dc_create_transfer_func();
3805dba4991SBhawanpreet Lakha 		if (pool->mpc_shaper[i] == NULL)
3815dba4991SBhawanpreet Lakha 			DC_ERR("DC: failed to create MPC shaper!\n");
3825dba4991SBhawanpreet Lakha 	}
3835dba4991SBhawanpreet Lakha #endif
3844176664bSCharlene Liu 	dc->caps.dynamic_audio = false;
3854176664bSCharlene Liu 	if (pool->audio_count < pool->stream_enc_count) {
3864176664bSCharlene Liu 		dc->caps.dynamic_audio = true;
3874176664bSCharlene Liu 	}
3884562236bSHarry Wentland 	for (i = 0; i < num_virtual_links; i++) {
3894562236bSHarry Wentland 		pool->stream_enc[pool->stream_enc_count] =
3904562236bSHarry Wentland 			virtual_stream_encoder_create(
3914562236bSHarry Wentland 					ctx, ctx->dc_bios);
3924562236bSHarry Wentland 		if (pool->stream_enc[pool->stream_enc_count] == NULL) {
3934562236bSHarry Wentland 			DC_ERR("DC: failed to create stream_encoder!\n");
3944562236bSHarry Wentland 			return false;
3954562236bSHarry Wentland 		}
3964562236bSHarry Wentland 		pool->stream_enc_count++;
3974562236bSHarry Wentland 	}
3984562236bSHarry Wentland 
3994562236bSHarry Wentland 	dc->hwseq = create_funcs->create_hwseq(ctx);
4004562236bSHarry Wentland 
4014562236bSHarry Wentland 	return true;
4024562236bSHarry Wentland }
403ad8960a6SMikita Lipski static int find_matching_clock_source(
404ad8960a6SMikita Lipski 		const struct resource_pool *pool,
405ad8960a6SMikita Lipski 		struct clock_source *clock_source)
406ad8960a6SMikita Lipski {
4074562236bSHarry Wentland 
408ad8960a6SMikita Lipski 	int i;
409ad8960a6SMikita Lipski 
410ad8960a6SMikita Lipski 	for (i = 0; i < pool->clk_src_count; i++) {
411ad8960a6SMikita Lipski 		if (pool->clock_sources[i] == clock_source)
412ad8960a6SMikita Lipski 			return i;
413ad8960a6SMikita Lipski 	}
414ad8960a6SMikita Lipski 	return -1;
415ad8960a6SMikita Lipski }
4164562236bSHarry Wentland 
41721e67d4dSHarry Wentland void resource_unreference_clock_source(
4184562236bSHarry Wentland 		struct resource_context *res_ctx,
419a2b8659dSTony Cheng 		const struct resource_pool *pool,
4204a629536SHarry Wentland 		struct clock_source *clock_source)
4214562236bSHarry Wentland {
422ad8960a6SMikita Lipski 	int i = find_matching_clock_source(pool, clock_source);
4234a629536SHarry Wentland 
424ad8960a6SMikita Lipski 	if (i > -1)
4254562236bSHarry Wentland 		res_ctx->clock_source_ref_count[i]--;
4264562236bSHarry Wentland 
42721e67d4dSHarry Wentland 	if (pool->dp_clock_source == clock_source)
4284562236bSHarry Wentland 		res_ctx->dp_clock_source_ref_count--;
4294562236bSHarry Wentland }
4304562236bSHarry Wentland 
4314562236bSHarry Wentland void resource_reference_clock_source(
4324562236bSHarry Wentland 		struct resource_context *res_ctx,
433a2b8659dSTony Cheng 		const struct resource_pool *pool,
4344562236bSHarry Wentland 		struct clock_source *clock_source)
4354562236bSHarry Wentland {
436ad8960a6SMikita Lipski 	int i = find_matching_clock_source(pool, clock_source);
4374562236bSHarry Wentland 
438ad8960a6SMikita Lipski 	if (i > -1)
4394562236bSHarry Wentland 		res_ctx->clock_source_ref_count[i]++;
4404562236bSHarry Wentland 
441a2b8659dSTony Cheng 	if (pool->dp_clock_source == clock_source)
4424562236bSHarry Wentland 		res_ctx->dp_clock_source_ref_count++;
4434562236bSHarry Wentland }
4444562236bSHarry Wentland 
445ad8960a6SMikita Lipski int resource_get_clock_source_reference(
446ad8960a6SMikita Lipski 		struct resource_context *res_ctx,
447ad8960a6SMikita Lipski 		const struct resource_pool *pool,
448ad8960a6SMikita Lipski 		struct clock_source *clock_source)
449ad8960a6SMikita Lipski {
450ad8960a6SMikita Lipski 	int i = find_matching_clock_source(pool, clock_source);
451ad8960a6SMikita Lipski 
452ad8960a6SMikita Lipski 	if (i > -1)
453ad8960a6SMikita Lipski 		return res_ctx->clock_source_ref_count[i];
454ad8960a6SMikita Lipski 
455ad8960a6SMikita Lipski 	if (pool->dp_clock_source == clock_source)
456ad8960a6SMikita Lipski 		return res_ctx->dp_clock_source_ref_count;
457ad8960a6SMikita Lipski 
458ad8960a6SMikita Lipski 	return -1;
459ad8960a6SMikita Lipski }
460ad8960a6SMikita Lipski 
46177a2b726SVladimir Stempen bool resource_are_vblanks_synchronizable(
46277a2b726SVladimir Stempen 	struct dc_stream_state *stream1,
46377a2b726SVladimir Stempen 	struct dc_stream_state *stream2)
46477a2b726SVladimir Stempen {
46577a2b726SVladimir Stempen 	uint32_t base60_refresh_rates[] = {10, 20, 5};
46677a2b726SVladimir Stempen 	uint8_t i;
467d0b3bbd3SJiapeng Chong 	uint8_t rr_count = ARRAY_SIZE(base60_refresh_rates);
468783bf403SVladimir Stempen 	uint64_t frame_time_diff;
46977a2b726SVladimir Stempen 
47077a2b726SVladimir Stempen 	if (stream1->ctx->dc->config.vblank_alignment_dto_params &&
47177a2b726SVladimir Stempen 		stream1->ctx->dc->config.vblank_alignment_max_frame_time_diff > 0 &&
47277a2b726SVladimir Stempen 		dc_is_dp_signal(stream1->signal) &&
47377a2b726SVladimir Stempen 		dc_is_dp_signal(stream2->signal) &&
47477a2b726SVladimir Stempen 		false == stream1->has_non_synchronizable_pclk &&
47577a2b726SVladimir Stempen 		false == stream2->has_non_synchronizable_pclk &&
47677a2b726SVladimir Stempen 		stream1->timing.flags.VBLANK_SYNCHRONIZABLE &&
47777a2b726SVladimir Stempen 		stream2->timing.flags.VBLANK_SYNCHRONIZABLE) {
47877a2b726SVladimir Stempen 		/* disable refresh rates higher than 60Hz for now */
47977a2b726SVladimir Stempen 		if (stream1->timing.pix_clk_100hz*100/stream1->timing.h_total/
48077a2b726SVladimir Stempen 				stream1->timing.v_total > 60)
48177a2b726SVladimir Stempen 			return false;
48277a2b726SVladimir Stempen 		if (stream2->timing.pix_clk_100hz*100/stream2->timing.h_total/
48377a2b726SVladimir Stempen 				stream2->timing.v_total > 60)
48477a2b726SVladimir Stempen 			return false;
485783bf403SVladimir Stempen 		frame_time_diff = (uint64_t)10000 *
48677a2b726SVladimir Stempen 			stream1->timing.h_total *
48777a2b726SVladimir Stempen 			stream1->timing.v_total *
488783bf403SVladimir Stempen 			stream2->timing.pix_clk_100hz;
489783bf403SVladimir Stempen 		frame_time_diff = div_u64(frame_time_diff, stream1->timing.pix_clk_100hz);
490783bf403SVladimir Stempen 		frame_time_diff = div_u64(frame_time_diff, stream2->timing.h_total);
491783bf403SVladimir Stempen 		frame_time_diff = div_u64(frame_time_diff, stream2->timing.v_total);
49277a2b726SVladimir Stempen 		for (i = 0; i < rr_count; i++) {
493783bf403SVladimir Stempen 			int64_t diff = (int64_t)div_u64(frame_time_diff * base60_refresh_rates[i], 10) - 10000;
49477a2b726SVladimir Stempen 
49577a2b726SVladimir Stempen 			if (diff < 0)
49677a2b726SVladimir Stempen 				diff = -diff;
49777a2b726SVladimir Stempen 			if (diff < stream1->ctx->dc->config.vblank_alignment_max_frame_time_diff)
49877a2b726SVladimir Stempen 				return true;
49977a2b726SVladimir Stempen 		}
50077a2b726SVladimir Stempen 	}
50177a2b726SVladimir Stempen 	return false;
50277a2b726SVladimir Stempen }
50377a2b726SVladimir Stempen 
5044562236bSHarry Wentland bool resource_are_streams_timing_synchronizable(
5050971c40eSHarry Wentland 	struct dc_stream_state *stream1,
5060971c40eSHarry Wentland 	struct dc_stream_state *stream2)
5074562236bSHarry Wentland {
5084fa086b9SLeo (Sunpeng) Li 	if (stream1->timing.h_total != stream2->timing.h_total)
5094562236bSHarry Wentland 		return false;
5104562236bSHarry Wentland 
5114fa086b9SLeo (Sunpeng) Li 	if (stream1->timing.v_total != stream2->timing.v_total)
5124562236bSHarry Wentland 		return false;
5134562236bSHarry Wentland 
5144fa086b9SLeo (Sunpeng) Li 	if (stream1->timing.h_addressable
5154fa086b9SLeo (Sunpeng) Li 				!= stream2->timing.h_addressable)
5164562236bSHarry Wentland 		return false;
5174562236bSHarry Wentland 
5184fa086b9SLeo (Sunpeng) Li 	if (stream1->timing.v_addressable
5194fa086b9SLeo (Sunpeng) Li 				!= stream2->timing.v_addressable)
5204562236bSHarry Wentland 		return false;
5214562236bSHarry Wentland 
5228582aea2SDavid Galiffi 	if (stream1->timing.v_front_porch
5238582aea2SDavid Galiffi 				!= stream2->timing.v_front_porch)
5248582aea2SDavid Galiffi 		return false;
5258582aea2SDavid Galiffi 
526380604e2SKen Chalmers 	if (stream1->timing.pix_clk_100hz
527380604e2SKen Chalmers 				!= stream2->timing.pix_clk_100hz)
5284562236bSHarry Wentland 		return false;
5294562236bSHarry Wentland 
5303e27e10eSMikita Lipski 	if (stream1->clamping.c_depth != stream2->clamping.c_depth)
5313e27e10eSMikita Lipski 		return false;
5323e27e10eSMikita Lipski 
5334562236bSHarry Wentland 	if (stream1->phy_pix_clk != stream2->phy_pix_clk
5347e2fe319SCharlene Liu 			&& (!dc_is_dp_signal(stream1->signal)
5357e2fe319SCharlene Liu 			|| !dc_is_dp_signal(stream2->signal)))
5364562236bSHarry Wentland 		return false;
5374562236bSHarry Wentland 
538d77f778eSCharlene Liu 	if (stream1->view_format != stream2->view_format)
539d77f778eSCharlene Liu 		return false;
540d77f778eSCharlene Liu 
5410460f9abSJun Lei 	if (stream1->ignore_msa_timing_param || stream2->ignore_msa_timing_param)
5420460f9abSJun Lei 		return false;
5430460f9abSJun Lei 
5444562236bSHarry Wentland 	return true;
5454562236bSHarry Wentland }
5463e27e10eSMikita Lipski static bool is_dp_and_hdmi_sharable(
5473e27e10eSMikita Lipski 		struct dc_stream_state *stream1,
5483e27e10eSMikita Lipski 		struct dc_stream_state *stream2)
5493e27e10eSMikita Lipski {
5503e27e10eSMikita Lipski 	if (stream1->ctx->dc->caps.disable_dp_clk_share)
5513e27e10eSMikita Lipski 		return false;
5523e27e10eSMikita Lipski 
5533e27e10eSMikita Lipski 	if (stream1->clamping.c_depth != COLOR_DEPTH_888 ||
5543e27e10eSMikita Lipski 		stream2->clamping.c_depth != COLOR_DEPTH_888)
5553e27e10eSMikita Lipski 		return false;
5563e27e10eSMikita Lipski 
5573e27e10eSMikita Lipski 	return true;
5583e27e10eSMikita Lipski 
5593e27e10eSMikita Lipski }
5604562236bSHarry Wentland 
5614562236bSHarry Wentland static bool is_sharable_clk_src(
5624562236bSHarry Wentland 	const struct pipe_ctx *pipe_with_clk_src,
5634562236bSHarry Wentland 	const struct pipe_ctx *pipe)
5644562236bSHarry Wentland {
5654562236bSHarry Wentland 	if (pipe_with_clk_src->clock_source == NULL)
5664562236bSHarry Wentland 		return false;
5674562236bSHarry Wentland 
5684562236bSHarry Wentland 	if (pipe_with_clk_src->stream->signal == SIGNAL_TYPE_VIRTUAL)
5694562236bSHarry Wentland 		return false;
5704562236bSHarry Wentland 
5713e27e10eSMikita Lipski 	if (dc_is_dp_signal(pipe_with_clk_src->stream->signal) ||
5723e27e10eSMikita Lipski 		(dc_is_dp_signal(pipe->stream->signal) &&
5733e27e10eSMikita Lipski 		!is_dp_and_hdmi_sharable(pipe_with_clk_src->stream,
5743e27e10eSMikita Lipski 				     pipe->stream)))
5754562236bSHarry Wentland 		return false;
5764562236bSHarry Wentland 
5774562236bSHarry Wentland 	if (dc_is_hdmi_signal(pipe_with_clk_src->stream->signal)
578fc69009eSMikita Lipski 			&& dc_is_dual_link_signal(pipe->stream->signal))
5794562236bSHarry Wentland 		return false;
5804562236bSHarry Wentland 
5814562236bSHarry Wentland 	if (dc_is_hdmi_signal(pipe->stream->signal)
582fc69009eSMikita Lipski 			&& dc_is_dual_link_signal(pipe_with_clk_src->stream->signal))
5834562236bSHarry Wentland 		return false;
5844562236bSHarry Wentland 
5854562236bSHarry Wentland 	if (!resource_are_streams_timing_synchronizable(
5864562236bSHarry Wentland 			pipe_with_clk_src->stream, pipe->stream))
5874562236bSHarry Wentland 		return false;
5884562236bSHarry Wentland 
5894562236bSHarry Wentland 	return true;
5904562236bSHarry Wentland }
5914562236bSHarry Wentland 
5924562236bSHarry Wentland struct clock_source *resource_find_used_clk_src_for_sharing(
5934562236bSHarry Wentland 					struct resource_context *res_ctx,
5944562236bSHarry Wentland 					struct pipe_ctx *pipe_ctx)
5954562236bSHarry Wentland {
5964562236bSHarry Wentland 	int i;
5974562236bSHarry Wentland 
5984562236bSHarry Wentland 	for (i = 0; i < MAX_PIPES; i++) {
5994562236bSHarry Wentland 		if (is_sharable_clk_src(&res_ctx->pipe_ctx[i], pipe_ctx))
6004562236bSHarry Wentland 			return res_ctx->pipe_ctx[i].clock_source;
6014562236bSHarry Wentland 	}
6024562236bSHarry Wentland 
6034562236bSHarry Wentland 	return NULL;
6044562236bSHarry Wentland }
6054562236bSHarry Wentland 
6064562236bSHarry Wentland static enum pixel_format convert_pixel_format_to_dalsurface(
6074562236bSHarry Wentland 		enum surface_pixel_format surface_pixel_format)
6084562236bSHarry Wentland {
6094562236bSHarry Wentland 	enum pixel_format dal_pixel_format = PIXEL_FORMAT_UNKNOWN;
6104562236bSHarry Wentland 
6114562236bSHarry Wentland 	switch (surface_pixel_format) {
6124562236bSHarry Wentland 	case SURFACE_PIXEL_FORMAT_GRPH_PALETA_256_COLORS:
6134562236bSHarry Wentland 		dal_pixel_format = PIXEL_FORMAT_INDEX8;
6144562236bSHarry Wentland 		break;
6154562236bSHarry Wentland 	case SURFACE_PIXEL_FORMAT_GRPH_ARGB1555:
6164562236bSHarry Wentland 		dal_pixel_format = PIXEL_FORMAT_RGB565;
6174562236bSHarry Wentland 		break;
6184562236bSHarry Wentland 	case SURFACE_PIXEL_FORMAT_GRPH_RGB565:
6194562236bSHarry Wentland 		dal_pixel_format = PIXEL_FORMAT_RGB565;
6204562236bSHarry Wentland 		break;
6214562236bSHarry Wentland 	case SURFACE_PIXEL_FORMAT_GRPH_ARGB8888:
6224562236bSHarry Wentland 		dal_pixel_format = PIXEL_FORMAT_ARGB8888;
6234562236bSHarry Wentland 		break;
6248693049aSTony Cheng 	case SURFACE_PIXEL_FORMAT_GRPH_ABGR8888:
6254562236bSHarry Wentland 		dal_pixel_format = PIXEL_FORMAT_ARGB8888;
6264562236bSHarry Wentland 		break;
6274562236bSHarry Wentland 	case SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010:
6284562236bSHarry Wentland 		dal_pixel_format = PIXEL_FORMAT_ARGB2101010;
6294562236bSHarry Wentland 		break;
6304562236bSHarry Wentland 	case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010:
6314562236bSHarry Wentland 		dal_pixel_format = PIXEL_FORMAT_ARGB2101010;
6324562236bSHarry Wentland 		break;
6334562236bSHarry Wentland 	case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010_XR_BIAS:
6344562236bSHarry Wentland 		dal_pixel_format = PIXEL_FORMAT_ARGB2101010_XRBIAS;
6354562236bSHarry Wentland 		break;
6364562236bSHarry Wentland 	case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F:
6374562236bSHarry Wentland 	case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F:
6384562236bSHarry Wentland 		dal_pixel_format = PIXEL_FORMAT_FP16;
6394562236bSHarry Wentland 		break;
6404562236bSHarry Wentland 	case SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr:
6414562236bSHarry Wentland 	case SURFACE_PIXEL_FORMAT_VIDEO_420_YCrCb:
64287449a90SAnthony Koo 		dal_pixel_format = PIXEL_FORMAT_420BPP8;
6434562236bSHarry Wentland 		break;
644ffbcd19aSVitaly Prosyak 	case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCbCr:
645ffbcd19aSVitaly Prosyak 	case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb:
64687449a90SAnthony Koo 		dal_pixel_format = PIXEL_FORMAT_420BPP10;
647ffbcd19aSVitaly Prosyak 		break;
6484562236bSHarry Wentland 	case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616:
649050cd3d6SMario Kleiner 	case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616:
6504562236bSHarry Wentland 	default:
6514562236bSHarry Wentland 		dal_pixel_format = PIXEL_FORMAT_UNKNOWN;
6524562236bSHarry Wentland 		break;
6534562236bSHarry Wentland 	}
6544562236bSHarry Wentland 	return dal_pixel_format;
6554562236bSHarry Wentland }
6564562236bSHarry Wentland 
6579b6067c0SDmytro Laktyushkin static inline void get_vp_scan_direction(
6589b6067c0SDmytro Laktyushkin 	enum dc_rotation_angle rotation,
6599b6067c0SDmytro Laktyushkin 	bool horizontal_mirror,
6609b6067c0SDmytro Laktyushkin 	bool *orthogonal_rotation,
6619b6067c0SDmytro Laktyushkin 	bool *flip_vert_scan_dir,
6629b6067c0SDmytro Laktyushkin 	bool *flip_horz_scan_dir)
6634562236bSHarry Wentland {
6649b6067c0SDmytro Laktyushkin 	*orthogonal_rotation = false;
6659b6067c0SDmytro Laktyushkin 	*flip_vert_scan_dir = false;
6669b6067c0SDmytro Laktyushkin 	*flip_horz_scan_dir = false;
6679b6067c0SDmytro Laktyushkin 	if (rotation == ROTATION_ANGLE_180) {
6689b6067c0SDmytro Laktyushkin 		*flip_vert_scan_dir = true;
6699b6067c0SDmytro Laktyushkin 		*flip_horz_scan_dir = true;
6709b6067c0SDmytro Laktyushkin 	} else if (rotation == ROTATION_ANGLE_90) {
6719b6067c0SDmytro Laktyushkin 		*orthogonal_rotation = true;
6729b6067c0SDmytro Laktyushkin 		*flip_horz_scan_dir = true;
6739b6067c0SDmytro Laktyushkin 	} else if (rotation == ROTATION_ANGLE_270) {
6749b6067c0SDmytro Laktyushkin 		*orthogonal_rotation = true;
6759b6067c0SDmytro Laktyushkin 		*flip_vert_scan_dir = true;
6769b6067c0SDmytro Laktyushkin 	}
6779b6067c0SDmytro Laktyushkin 
6789b6067c0SDmytro Laktyushkin 	if (horizontal_mirror)
6799b6067c0SDmytro Laktyushkin 		*flip_horz_scan_dir = !*flip_horz_scan_dir;
6804562236bSHarry Wentland }
6814562236bSHarry Wentland 
682570bc18cSDmytro Laktyushkin int get_num_mpc_splits(struct pipe_ctx *pipe)
683570bc18cSDmytro Laktyushkin {
684570bc18cSDmytro Laktyushkin 	int mpc_split_count = 0;
685570bc18cSDmytro Laktyushkin 	struct pipe_ctx *other_pipe = pipe->bottom_pipe;
686570bc18cSDmytro Laktyushkin 
687570bc18cSDmytro Laktyushkin 	while (other_pipe && other_pipe->plane_state == pipe->plane_state) {
688570bc18cSDmytro Laktyushkin 		mpc_split_count++;
689570bc18cSDmytro Laktyushkin 		other_pipe = other_pipe->bottom_pipe;
690570bc18cSDmytro Laktyushkin 	}
691570bc18cSDmytro Laktyushkin 	other_pipe = pipe->top_pipe;
692570bc18cSDmytro Laktyushkin 	while (other_pipe && other_pipe->plane_state == pipe->plane_state) {
693570bc18cSDmytro Laktyushkin 		mpc_split_count++;
694570bc18cSDmytro Laktyushkin 		other_pipe = other_pipe->top_pipe;
695570bc18cSDmytro Laktyushkin 	}
696570bc18cSDmytro Laktyushkin 
697570bc18cSDmytro Laktyushkin 	return mpc_split_count;
698570bc18cSDmytro Laktyushkin }
699570bc18cSDmytro Laktyushkin 
700228a10d4SAlex Deucher int get_num_odm_splits(struct pipe_ctx *pipe)
701228a10d4SAlex Deucher {
702228a10d4SAlex Deucher 	int odm_split_count = 0;
703228a10d4SAlex Deucher 	struct pipe_ctx *next_pipe = pipe->next_odm_pipe;
704228a10d4SAlex Deucher 	while (next_pipe) {
705228a10d4SAlex Deucher 		odm_split_count++;
706228a10d4SAlex Deucher 		next_pipe = next_pipe->next_odm_pipe;
707228a10d4SAlex Deucher 	}
708228a10d4SAlex Deucher 	pipe = pipe->prev_odm_pipe;
709228a10d4SAlex Deucher 	while (pipe) {
710228a10d4SAlex Deucher 		odm_split_count++;
711228a10d4SAlex Deucher 		pipe = pipe->prev_odm_pipe;
712228a10d4SAlex Deucher 	}
713228a10d4SAlex Deucher 	return odm_split_count;
714228a10d4SAlex Deucher }
715228a10d4SAlex Deucher 
7165bf24270SDmytro Laktyushkin static void calculate_split_count_and_index(struct pipe_ctx *pipe_ctx, int *split_count, int *split_idx)
7175bf24270SDmytro Laktyushkin {
7185bf24270SDmytro Laktyushkin 	*split_count = get_num_odm_splits(pipe_ctx);
7195bf24270SDmytro Laktyushkin 	*split_idx = 0;
7205bf24270SDmytro Laktyushkin 	if (*split_count == 0) {
7215bf24270SDmytro Laktyushkin 		/*Check for mpc split*/
7225bf24270SDmytro Laktyushkin 		struct pipe_ctx *split_pipe = pipe_ctx->top_pipe;
7235bf24270SDmytro Laktyushkin 
724570bc18cSDmytro Laktyushkin 		*split_count = get_num_mpc_splits(pipe_ctx);
7255bf24270SDmytro Laktyushkin 		while (split_pipe && split_pipe->plane_state == pipe_ctx->plane_state) {
7265bf24270SDmytro Laktyushkin 			(*split_idx)++;
7275bf24270SDmytro Laktyushkin 			split_pipe = split_pipe->top_pipe;
7285bf24270SDmytro Laktyushkin 		}
7295bf24270SDmytro Laktyushkin 	} else {
7305bf24270SDmytro Laktyushkin 		/*Get odm split index*/
7315bf24270SDmytro Laktyushkin 		struct pipe_ctx *split_pipe = pipe_ctx->prev_odm_pipe;
7325bf24270SDmytro Laktyushkin 
7335bf24270SDmytro Laktyushkin 		while (split_pipe) {
7345bf24270SDmytro Laktyushkin 			(*split_idx)++;
7355bf24270SDmytro Laktyushkin 			split_pipe = split_pipe->prev_odm_pipe;
7365bf24270SDmytro Laktyushkin 		}
7375bf24270SDmytro Laktyushkin 	}
7385bf24270SDmytro Laktyushkin }
7395bf24270SDmytro Laktyushkin 
7409b6067c0SDmytro Laktyushkin /*
7416566cae7SDmytro Laktyushkin  * This is a preliminary vp size calculation to allow us to check taps support.
7426566cae7SDmytro Laktyushkin  * The result is completely overridden afterwards.
7439b6067c0SDmytro Laktyushkin  */
7446566cae7SDmytro Laktyushkin static void calculate_viewport_size(struct pipe_ctx *pipe_ctx)
7456566cae7SDmytro Laktyushkin {
7466566cae7SDmytro Laktyushkin 	struct scaler_data *data = &pipe_ctx->plane_res.scl_data;
7479b6067c0SDmytro Laktyushkin 
7486566cae7SDmytro Laktyushkin 	data->viewport.width = dc_fixpt_ceil(dc_fixpt_mul_int(data->ratios.horz, data->recout.width));
7496566cae7SDmytro Laktyushkin 	data->viewport.height = dc_fixpt_ceil(dc_fixpt_mul_int(data->ratios.vert, data->recout.height));
7506566cae7SDmytro Laktyushkin 	data->viewport_c.width = dc_fixpt_ceil(dc_fixpt_mul_int(data->ratios.horz_c, data->recout.width));
7516566cae7SDmytro Laktyushkin 	data->viewport_c.height = dc_fixpt_ceil(dc_fixpt_mul_int(data->ratios.vert_c, data->recout.height));
7526566cae7SDmytro Laktyushkin 	if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_90 ||
7536566cae7SDmytro Laktyushkin 			pipe_ctx->plane_state->rotation == ROTATION_ANGLE_270) {
7546566cae7SDmytro Laktyushkin 		swap(data->viewport.width, data->viewport.height);
7556566cae7SDmytro Laktyushkin 		swap(data->viewport_c.width, data->viewport_c.height);
7569b6067c0SDmytro Laktyushkin 	}
757b2d0a103SDmytro Laktyushkin }
7581fbd2cfcSDmytro Laktyushkin 
7599b6067c0SDmytro Laktyushkin static void calculate_recout(struct pipe_ctx *pipe_ctx)
7604562236bSHarry Wentland {
7613be5262eSHarry Wentland 	const struct dc_plane_state *plane_state = pipe_ctx->plane_state;
7620971c40eSHarry Wentland 	const struct dc_stream_state *stream = pipe_ctx->stream;
7635bf24270SDmytro Laktyushkin 	struct scaler_data *data = &pipe_ctx->plane_res.scl_data;
7643be5262eSHarry Wentland 	struct rect surf_clip = plane_state->clip_rect;
7656566cae7SDmytro Laktyushkin 	bool split_tb = stream->view_format == VIEW_3D_FORMAT_TOP_AND_BOTTOM;
7666566cae7SDmytro Laktyushkin 	int split_count, split_idx;
7674562236bSHarry Wentland 
7685bf24270SDmytro Laktyushkin 	calculate_split_count_and_index(pipe_ctx, &split_count, &split_idx);
7696566cae7SDmytro Laktyushkin 	if (stream->view_format == VIEW_3D_FORMAT_SIDE_BY_SIDE)
7706566cae7SDmytro Laktyushkin 		split_idx = 0;
7715bf24270SDmytro Laktyushkin 
77205e3d830SWesley Chalmers 	/*
77305e3d830SWesley Chalmers 	 * Only the leftmost ODM pipe should be offset by a nonzero distance
77405e3d830SWesley Chalmers 	 */
7756566cae7SDmytro Laktyushkin 	if (!pipe_ctx->prev_odm_pipe || split_idx == split_count) {
7765bf24270SDmytro Laktyushkin 		data->recout.x = stream->dst.x;
7774fa086b9SLeo (Sunpeng) Li 		if (stream->src.x < surf_clip.x)
7785bf24270SDmytro Laktyushkin 			data->recout.x += (surf_clip.x - stream->src.x) * stream->dst.width
7794fa086b9SLeo (Sunpeng) Li 						/ stream->src.width;
78025b31581SWesley Chalmers 	} else
78125b31581SWesley Chalmers 		data->recout.x = 0;
78225b31581SWesley Chalmers 
78384aef2abSDmytro Laktyushkin 	if (stream->src.x > surf_clip.x)
78484aef2abSDmytro Laktyushkin 		surf_clip.width -= stream->src.x - surf_clip.x;
7855bf24270SDmytro Laktyushkin 	data->recout.width = surf_clip.width * stream->dst.width / stream->src.width;
7865bf24270SDmytro Laktyushkin 	if (data->recout.width + data->recout.x > stream->dst.x + stream->dst.width)
7875bf24270SDmytro Laktyushkin 		data->recout.width = stream->dst.x + stream->dst.width - data->recout.x;
7884562236bSHarry Wentland 
7895bf24270SDmytro Laktyushkin 	data->recout.y = stream->dst.y;
7904fa086b9SLeo (Sunpeng) Li 	if (stream->src.y < surf_clip.y)
7915bf24270SDmytro Laktyushkin 		data->recout.y += (surf_clip.y - stream->src.y) * stream->dst.height
7924fa086b9SLeo (Sunpeng) Li 						/ stream->src.height;
79384aef2abSDmytro Laktyushkin 	else if (stream->src.y > surf_clip.y)
79484aef2abSDmytro Laktyushkin 		surf_clip.height -= stream->src.y - surf_clip.y;
7954562236bSHarry Wentland 
7965bf24270SDmytro Laktyushkin 	data->recout.height = surf_clip.height * stream->dst.height / stream->src.height;
7975bf24270SDmytro Laktyushkin 	if (data->recout.height + data->recout.y > stream->dst.y + stream->dst.height)
7985bf24270SDmytro Laktyushkin 		data->recout.height = stream->dst.y + stream->dst.height - data->recout.y;
799b2d0a103SDmytro Laktyushkin 
8006566cae7SDmytro Laktyushkin 	/* Handle h & v split */
8016566cae7SDmytro Laktyushkin 	if (split_tb) {
8026566cae7SDmytro Laktyushkin 		ASSERT(data->recout.height % 2 == 0);
8035bf24270SDmytro Laktyushkin 		data->recout.height /= 2;
8046566cae7SDmytro Laktyushkin 	} else if (split_count) {
8056566cae7SDmytro Laktyushkin 		if (!pipe_ctx->next_odm_pipe && !pipe_ctx->prev_odm_pipe) {
8065bf24270SDmytro Laktyushkin 			/* extra pixels in the division remainder need to go to pipes after
8075bf24270SDmytro Laktyushkin 			 * the extra pixel index minus one(epimo) defined here as:
8085bf24270SDmytro Laktyushkin 			 */
8095bf24270SDmytro Laktyushkin 			int epimo = split_count - data->recout.width % (split_count + 1);
8105bf24270SDmytro Laktyushkin 
8115bf24270SDmytro Laktyushkin 			data->recout.x += (data->recout.width / (split_count + 1)) * split_idx;
8125bf24270SDmytro Laktyushkin 			if (split_idx > epimo)
8135bf24270SDmytro Laktyushkin 				data->recout.x += split_idx - epimo - 1;
8146566cae7SDmytro Laktyushkin 			ASSERT(stream->view_format != VIEW_3D_FORMAT_SIDE_BY_SIDE || data->recout.width % 2 == 0);
8155bf24270SDmytro Laktyushkin 			data->recout.width = data->recout.width / (split_count + 1) + (split_idx > epimo ? 1 : 0);
8166566cae7SDmytro Laktyushkin 		} else {
8176566cae7SDmytro Laktyushkin 			/* odm */
8186566cae7SDmytro Laktyushkin 			if (split_idx == split_count) {
8196566cae7SDmytro Laktyushkin 				/* rightmost pipe is the remainder recout */
8206566cae7SDmytro Laktyushkin 				data->recout.width -= data->h_active * split_count - data->recout.x;
821665f2850SAric Cyr 
822665f2850SAric Cyr 				/* ODM combine cases with MPO we can get negative widths */
823665f2850SAric Cyr 				if (data->recout.width < 0)
824665f2850SAric Cyr 					data->recout.width = 0;
825665f2850SAric Cyr 
8266566cae7SDmytro Laktyushkin 				data->recout.x = 0;
8276566cae7SDmytro Laktyushkin 			} else
8286566cae7SDmytro Laktyushkin 				data->recout.width = data->h_active - data->recout.x;
8296566cae7SDmytro Laktyushkin 		}
8305bf24270SDmytro Laktyushkin 	}
8314562236bSHarry Wentland }
832b2d0a103SDmytro Laktyushkin 
833b2d0a103SDmytro Laktyushkin static void calculate_scaling_ratios(struct pipe_ctx *pipe_ctx)
8344562236bSHarry Wentland {
8353be5262eSHarry Wentland 	const struct dc_plane_state *plane_state = pipe_ctx->plane_state;
8360971c40eSHarry Wentland 	const struct dc_stream_state *stream = pipe_ctx->stream;
8373be5262eSHarry Wentland 	struct rect surf_src = plane_state->src_rect;
8384fa086b9SLeo (Sunpeng) Li 	const int in_w = stream->src.width;
8394fa086b9SLeo (Sunpeng) Li 	const int in_h = stream->src.height;
8404fa086b9SLeo (Sunpeng) Li 	const int out_w = stream->dst.width;
8414fa086b9SLeo (Sunpeng) Li 	const int out_h = stream->dst.height;
8424562236bSHarry Wentland 
8439b6067c0SDmytro Laktyushkin 	/*Swap surf_src height and width since scaling ratios are in recout rotation*/
8443be5262eSHarry Wentland 	if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_90 ||
8453be5262eSHarry Wentland 			pipe_ctx->plane_state->rotation == ROTATION_ANGLE_270)
8469b6067c0SDmytro Laktyushkin 		swap(surf_src.height, surf_src.width);
84786006a7fSDmytro Laktyushkin 
848eb0e5154SDmytro Laktyushkin 	pipe_ctx->plane_res.scl_data.ratios.horz = dc_fixpt_from_fraction(
84986006a7fSDmytro Laktyushkin 					surf_src.width,
8503be5262eSHarry Wentland 					plane_state->dst_rect.width);
851eb0e5154SDmytro Laktyushkin 	pipe_ctx->plane_res.scl_data.ratios.vert = dc_fixpt_from_fraction(
85286006a7fSDmytro Laktyushkin 					surf_src.height,
8533be5262eSHarry Wentland 					plane_state->dst_rect.height);
8544562236bSHarry Wentland 
8554fa086b9SLeo (Sunpeng) Li 	if (stream->view_format == VIEW_3D_FORMAT_SIDE_BY_SIDE)
8566702a9acSHarry Wentland 		pipe_ctx->plane_res.scl_data.ratios.horz.value *= 2;
8574fa086b9SLeo (Sunpeng) Li 	else if (stream->view_format == VIEW_3D_FORMAT_TOP_AND_BOTTOM)
8586702a9acSHarry Wentland 		pipe_ctx->plane_res.scl_data.ratios.vert.value *= 2;
8594562236bSHarry Wentland 
8606702a9acSHarry Wentland 	pipe_ctx->plane_res.scl_data.ratios.vert.value = div64_s64(
8616702a9acSHarry Wentland 		pipe_ctx->plane_res.scl_data.ratios.vert.value * in_h, out_h);
8626702a9acSHarry Wentland 	pipe_ctx->plane_res.scl_data.ratios.horz.value = div64_s64(
8636702a9acSHarry Wentland 		pipe_ctx->plane_res.scl_data.ratios.horz.value * in_w, out_w);
8644562236bSHarry Wentland 
8656702a9acSHarry Wentland 	pipe_ctx->plane_res.scl_data.ratios.horz_c = pipe_ctx->plane_res.scl_data.ratios.horz;
8666702a9acSHarry Wentland 	pipe_ctx->plane_res.scl_data.ratios.vert_c = pipe_ctx->plane_res.scl_data.ratios.vert;
8674562236bSHarry Wentland 
8686702a9acSHarry Wentland 	if (pipe_ctx->plane_res.scl_data.format == PIXEL_FORMAT_420BPP8
8696702a9acSHarry Wentland 			|| pipe_ctx->plane_res.scl_data.format == PIXEL_FORMAT_420BPP10) {
8706702a9acSHarry Wentland 		pipe_ctx->plane_res.scl_data.ratios.horz_c.value /= 2;
8716702a9acSHarry Wentland 		pipe_ctx->plane_res.scl_data.ratios.vert_c.value /= 2;
8724562236bSHarry Wentland 	}
8730002d3acSDmytro Laktyushkin 	pipe_ctx->plane_res.scl_data.ratios.horz = dc_fixpt_truncate(
8740002d3acSDmytro Laktyushkin 			pipe_ctx->plane_res.scl_data.ratios.horz, 19);
8750002d3acSDmytro Laktyushkin 	pipe_ctx->plane_res.scl_data.ratios.vert = dc_fixpt_truncate(
8760002d3acSDmytro Laktyushkin 			pipe_ctx->plane_res.scl_data.ratios.vert, 19);
8770002d3acSDmytro Laktyushkin 	pipe_ctx->plane_res.scl_data.ratios.horz_c = dc_fixpt_truncate(
8780002d3acSDmytro Laktyushkin 			pipe_ctx->plane_res.scl_data.ratios.horz_c, 19);
8790002d3acSDmytro Laktyushkin 	pipe_ctx->plane_res.scl_data.ratios.vert_c = dc_fixpt_truncate(
8800002d3acSDmytro Laktyushkin 			pipe_ctx->plane_res.scl_data.ratios.vert_c, 19);
8814562236bSHarry Wentland }
8824562236bSHarry Wentland 
8836566cae7SDmytro Laktyushkin 
8846566cae7SDmytro Laktyushkin /*
8856566cae7SDmytro Laktyushkin  * We completely calculate vp offset, size and inits here based entirely on scaling
8866566cae7SDmytro Laktyushkin  * ratios and recout for pixel perfect pipe combine.
8876566cae7SDmytro Laktyushkin  */
8886566cae7SDmytro Laktyushkin static void calculate_init_and_vp(
8899b6067c0SDmytro Laktyushkin 		bool flip_scan_dir,
8906566cae7SDmytro Laktyushkin 		int recout_offset_within_recout_full,
8916566cae7SDmytro Laktyushkin 		int recout_size,
8929b6067c0SDmytro Laktyushkin 		int src_size,
8939b6067c0SDmytro Laktyushkin 		int taps,
8949b6067c0SDmytro Laktyushkin 		struct fixed31_32 ratio,
8959b6067c0SDmytro Laktyushkin 		struct fixed31_32 *init,
8969b6067c0SDmytro Laktyushkin 		int *vp_offset,
8979b6067c0SDmytro Laktyushkin 		int *vp_size)
8984562236bSHarry Wentland {
8996566cae7SDmytro Laktyushkin 	struct fixed31_32 temp;
9009b6067c0SDmytro Laktyushkin 	int int_part;
9019b6067c0SDmytro Laktyushkin 
9026566cae7SDmytro Laktyushkin 	/*
9036566cae7SDmytro Laktyushkin 	 * First of the taps starts sampling pixel number <init_int_part> corresponding to recout
9046566cae7SDmytro Laktyushkin 	 * pixel 1. Next recout pixel samples int part of <init + scaling ratio> and so on.
9056566cae7SDmytro Laktyushkin 	 * All following calculations are based on this logic.
9066566cae7SDmytro Laktyushkin 	 *
9076566cae7SDmytro Laktyushkin 	 * Init calculated according to formula:
9086566cae7SDmytro Laktyushkin 	 * 	init = (scaling_ratio + number_of_taps + 1) / 2
9096566cae7SDmytro Laktyushkin 	 * 	init_bot = init + scaling_ratio
9106566cae7SDmytro Laktyushkin 	 * 	to get pixel perfect combine add the fraction from calculating vp offset
9116566cae7SDmytro Laktyushkin 	 */
9126566cae7SDmytro Laktyushkin 	temp = dc_fixpt_mul_int(ratio, recout_offset_within_recout_full);
9136566cae7SDmytro Laktyushkin 	*vp_offset = dc_fixpt_floor(temp);
9146566cae7SDmytro Laktyushkin 	temp.value &= 0xffffffff;
9156566cae7SDmytro Laktyushkin 	*init = dc_fixpt_truncate(dc_fixpt_add(dc_fixpt_div_int(
9166566cae7SDmytro Laktyushkin 			dc_fixpt_add_int(ratio, taps + 1), 2), temp), 19);
9176566cae7SDmytro Laktyushkin 	/*
9186566cae7SDmytro Laktyushkin 	 * If viewport has non 0 offset and there are more taps than covered by init then
9196566cae7SDmytro Laktyushkin 	 * we should decrease the offset and increase init so we are never sampling
9206566cae7SDmytro Laktyushkin 	 * outside of viewport.
9216566cae7SDmytro Laktyushkin 	 */
9226566cae7SDmytro Laktyushkin 	int_part = dc_fixpt_floor(*init);
9239b6067c0SDmytro Laktyushkin 	if (int_part < taps) {
9246566cae7SDmytro Laktyushkin 		int_part = taps - int_part;
9256566cae7SDmytro Laktyushkin 		if (int_part > *vp_offset)
9266566cae7SDmytro Laktyushkin 			int_part = *vp_offset;
9276566cae7SDmytro Laktyushkin 		*vp_offset -= int_part;
9289b6067c0SDmytro Laktyushkin 		*init = dc_fixpt_add_int(*init, int_part);
9299b6067c0SDmytro Laktyushkin 	}
9309b6067c0SDmytro Laktyushkin 	/*
9316566cae7SDmytro Laktyushkin 	 * If taps are sampling outside of viewport at end of recout and there are more pixels
9326566cae7SDmytro Laktyushkin 	 * available in the surface we should increase the viewport size, regardless set vp to
9336566cae7SDmytro Laktyushkin 	 * only what is used.
9349b6067c0SDmytro Laktyushkin 	 */
9356566cae7SDmytro Laktyushkin 	temp = dc_fixpt_add(*init, dc_fixpt_mul_int(ratio, recout_size - 1));
9366566cae7SDmytro Laktyushkin 	*vp_size = dc_fixpt_floor(temp);
9376566cae7SDmytro Laktyushkin 	if (*vp_size + *vp_offset > src_size)
9386566cae7SDmytro Laktyushkin 		*vp_size = src_size - *vp_offset;
9396566cae7SDmytro Laktyushkin 
9406566cae7SDmytro Laktyushkin 	/* We did all the math assuming we are scanning same direction as display does,
9416566cae7SDmytro Laktyushkin 	 * however mirror/rotation changes how vp scans vs how it is offset. If scan direction
9426566cae7SDmytro Laktyushkin 	 * is flipped we simply need to calculate offset from the other side of plane.
9436566cae7SDmytro Laktyushkin 	 * Note that outside of viewport all scaling hardware works in recout space.
9449b6067c0SDmytro Laktyushkin 	 */
9456566cae7SDmytro Laktyushkin 	if (flip_scan_dir)
9466566cae7SDmytro Laktyushkin 		*vp_offset = src_size - *vp_offset - *vp_size;
9479b6067c0SDmytro Laktyushkin }
9489b6067c0SDmytro Laktyushkin 
9496566cae7SDmytro Laktyushkin static void calculate_inits_and_viewports(struct pipe_ctx *pipe_ctx)
9509b6067c0SDmytro Laktyushkin {
9519b6067c0SDmytro Laktyushkin 	const struct dc_plane_state *plane_state = pipe_ctx->plane_state;
9529b6067c0SDmytro Laktyushkin 	const struct dc_stream_state *stream = pipe_ctx->stream;
9536702a9acSHarry Wentland 	struct scaler_data *data = &pipe_ctx->plane_res.scl_data;
9546566cae7SDmytro Laktyushkin 	struct rect src = plane_state->src_rect;
95587449a90SAnthony Koo 	int vpc_div = (data->format == PIXEL_FORMAT_420BPP8
95687449a90SAnthony Koo 				|| data->format == PIXEL_FORMAT_420BPP10) ? 2 : 1;
9576566cae7SDmytro Laktyushkin 	int split_count, split_idx, ro_lb, ro_tb, recout_full_x, recout_full_y;
9589b6067c0SDmytro Laktyushkin 	bool orthogonal_rotation, flip_vert_scan_dir, flip_horz_scan_dir;
9596566cae7SDmytro Laktyushkin 
9606566cae7SDmytro Laktyushkin 	calculate_split_count_and_index(pipe_ctx, &split_count, &split_idx);
9616566cae7SDmytro Laktyushkin 	/*
9626566cae7SDmytro Laktyushkin 	 * recout full is what the recout would have been if we didnt clip
9636566cae7SDmytro Laktyushkin 	 * the source plane at all. We only care about left(ro_lb) and top(ro_tb)
9646566cae7SDmytro Laktyushkin 	 * offsets of recout within recout full because those are the directions
9656566cae7SDmytro Laktyushkin 	 * we scan from and therefore the only ones that affect inits.
9666566cae7SDmytro Laktyushkin 	 */
9676566cae7SDmytro Laktyushkin 	recout_full_x = stream->dst.x + (plane_state->dst_rect.x - stream->src.x)
9686566cae7SDmytro Laktyushkin 			* stream->dst.width / stream->src.width;
9696566cae7SDmytro Laktyushkin 	recout_full_y = stream->dst.y + (plane_state->dst_rect.y - stream->src.y)
9706566cae7SDmytro Laktyushkin 			* stream->dst.height / stream->src.height;
9716566cae7SDmytro Laktyushkin 	if (pipe_ctx->prev_odm_pipe && split_idx)
9726566cae7SDmytro Laktyushkin 		ro_lb = data->h_active * split_idx - recout_full_x;
9736566cae7SDmytro Laktyushkin 	else
9746566cae7SDmytro Laktyushkin 		ro_lb = data->recout.x - recout_full_x;
9756566cae7SDmytro Laktyushkin 	ro_tb = data->recout.y - recout_full_y;
9766566cae7SDmytro Laktyushkin 	ASSERT(ro_lb >= 0 && ro_tb >= 0);
977b2d0a103SDmytro Laktyushkin 
978b0131391SDmytro Laktyushkin 	/*
9796566cae7SDmytro Laktyushkin 	 * Work in recout rotation since that requires less transformations
980b0131391SDmytro Laktyushkin 	 */
9819b6067c0SDmytro Laktyushkin 	get_vp_scan_direction(
9829b6067c0SDmytro Laktyushkin 			plane_state->rotation,
9839b6067c0SDmytro Laktyushkin 			plane_state->horizontal_mirror,
9849b6067c0SDmytro Laktyushkin 			&orthogonal_rotation,
9859b6067c0SDmytro Laktyushkin 			&flip_vert_scan_dir,
9869b6067c0SDmytro Laktyushkin 			&flip_horz_scan_dir);
987b0131391SDmytro Laktyushkin 
9889b6067c0SDmytro Laktyushkin 	if (orthogonal_rotation) {
9899b6067c0SDmytro Laktyushkin 		swap(src.width, src.height);
9906566cae7SDmytro Laktyushkin 		swap(flip_vert_scan_dir, flip_horz_scan_dir);
9919b5349f7SMartin Tsai 	}
9921fbd2cfcSDmytro Laktyushkin 
9936566cae7SDmytro Laktyushkin 	calculate_init_and_vp(
9949b6067c0SDmytro Laktyushkin 			flip_horz_scan_dir,
9956566cae7SDmytro Laktyushkin 			ro_lb,
9966566cae7SDmytro Laktyushkin 			data->recout.width,
9976566cae7SDmytro Laktyushkin 			src.width,
9986566cae7SDmytro Laktyushkin 			data->taps.h_taps,
9996566cae7SDmytro Laktyushkin 			data->ratios.horz,
10006566cae7SDmytro Laktyushkin 			&data->inits.h,
10019b6067c0SDmytro Laktyushkin 			&data->viewport.x,
10029b6067c0SDmytro Laktyushkin 			&data->viewport.width);
10036566cae7SDmytro Laktyushkin 	calculate_init_and_vp(
10049b6067c0SDmytro Laktyushkin 			flip_horz_scan_dir,
10056566cae7SDmytro Laktyushkin 			ro_lb,
10066566cae7SDmytro Laktyushkin 			data->recout.width,
10076566cae7SDmytro Laktyushkin 			src.width / vpc_div,
10086566cae7SDmytro Laktyushkin 			data->taps.h_taps_c,
10096566cae7SDmytro Laktyushkin 			data->ratios.horz_c,
10106566cae7SDmytro Laktyushkin 			&data->inits.h_c,
10119b6067c0SDmytro Laktyushkin 			&data->viewport_c.x,
10129b6067c0SDmytro Laktyushkin 			&data->viewport_c.width);
10136566cae7SDmytro Laktyushkin 	calculate_init_and_vp(
10149b6067c0SDmytro Laktyushkin 			flip_vert_scan_dir,
10156566cae7SDmytro Laktyushkin 			ro_tb,
10166566cae7SDmytro Laktyushkin 			data->recout.height,
10176566cae7SDmytro Laktyushkin 			src.height,
10186566cae7SDmytro Laktyushkin 			data->taps.v_taps,
10196566cae7SDmytro Laktyushkin 			data->ratios.vert,
10206566cae7SDmytro Laktyushkin 			&data->inits.v,
10219b6067c0SDmytro Laktyushkin 			&data->viewport.y,
10229b6067c0SDmytro Laktyushkin 			&data->viewport.height);
10236566cae7SDmytro Laktyushkin 	calculate_init_and_vp(
10249b6067c0SDmytro Laktyushkin 			flip_vert_scan_dir,
10256566cae7SDmytro Laktyushkin 			ro_tb,
10266566cae7SDmytro Laktyushkin 			data->recout.height,
10276566cae7SDmytro Laktyushkin 			src.height / vpc_div,
10286566cae7SDmytro Laktyushkin 			data->taps.v_taps_c,
10296566cae7SDmytro Laktyushkin 			data->ratios.vert_c,
10306566cae7SDmytro Laktyushkin 			&data->inits.v_c,
10319b6067c0SDmytro Laktyushkin 			&data->viewport_c.y,
10329b6067c0SDmytro Laktyushkin 			&data->viewport_c.height);
10336566cae7SDmytro Laktyushkin 	if (orthogonal_rotation) {
10346566cae7SDmytro Laktyushkin 		swap(data->viewport.x, data->viewport.y);
10356566cae7SDmytro Laktyushkin 		swap(data->viewport.width, data->viewport.height);
10366566cae7SDmytro Laktyushkin 		swap(data->viewport_c.x, data->viewport_c.y);
10376566cae7SDmytro Laktyushkin 		swap(data->viewport_c.width, data->viewport_c.height);
1038b2d0a103SDmytro Laktyushkin 	}
10396566cae7SDmytro Laktyushkin 	data->viewport.x += src.x;
10406566cae7SDmytro Laktyushkin 	data->viewport.y += src.y;
10416566cae7SDmytro Laktyushkin 	ASSERT(src.x % vpc_div == 0 && src.y % vpc_div == 0);
10426566cae7SDmytro Laktyushkin 	data->viewport_c.x += src.x / vpc_div;
10436566cae7SDmytro Laktyushkin 	data->viewport_c.y += src.y / vpc_div;
104489d07b66SSamson Tam }
104589d07b66SSamson Tam 
1046b2d0a103SDmytro Laktyushkin bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx)
1047b2d0a103SDmytro Laktyushkin {
10483be5262eSHarry Wentland 	const struct dc_plane_state *plane_state = pipe_ctx->plane_state;
10494fa086b9SLeo (Sunpeng) Li 	struct dc_crtc_timing *timing = &pipe_ctx->stream->timing;
1050b2d0a103SDmytro Laktyushkin 	bool res = false;
10515d4b05ddSBhawanpreet Lakha 	DC_LOGGER_INIT(pipe_ctx->stream->ctx->logger);
10526566cae7SDmytro Laktyushkin 
10536702a9acSHarry Wentland 	pipe_ctx->plane_res.scl_data.format = convert_pixel_format_to_dalsurface(
10543be5262eSHarry Wentland 			pipe_ctx->plane_state->format);
10554562236bSHarry Wentland 
10566566cae7SDmytro Laktyushkin 	/* Timing borders are part of vactive that we are also supposed to skip in addition
10576566cae7SDmytro Laktyushkin 	 * to any stream dst offset. Since dm logic assumes dst is in addressable
10584dc8e494SCai Huoqing 	 * space we need to add the left and top borders to dst offsets temporarily.
10596566cae7SDmytro Laktyushkin 	 * TODO: fix in DM, stream dst is supposed to be in vactive
10606566cae7SDmytro Laktyushkin 	 */
10616566cae7SDmytro Laktyushkin 	pipe_ctx->stream->dst.x += timing->h_border_left;
10626566cae7SDmytro Laktyushkin 	pipe_ctx->stream->dst.y += timing->v_border_top;
1063b2d0a103SDmytro Laktyushkin 
10646566cae7SDmytro Laktyushkin 	/* Calculate H and V active size */
10656566cae7SDmytro Laktyushkin 	pipe_ctx->plane_res.scl_data.h_active = timing->h_addressable +
10666566cae7SDmytro Laktyushkin 			timing->h_border_left + timing->h_border_right;
10676566cae7SDmytro Laktyushkin 	pipe_ctx->plane_res.scl_data.v_active = timing->v_addressable +
10686566cae7SDmytro Laktyushkin 		timing->v_border_top + timing->v_border_bottom;
10696566cae7SDmytro Laktyushkin 	if (pipe_ctx->next_odm_pipe || pipe_ctx->prev_odm_pipe)
10706566cae7SDmytro Laktyushkin 		pipe_ctx->plane_res.scl_data.h_active /= get_num_odm_splits(pipe_ctx) + 1;
10714562236bSHarry Wentland 
10726566cae7SDmytro Laktyushkin 	/* depends on h_active */
10739b6067c0SDmytro Laktyushkin 	calculate_recout(pipe_ctx);
10746566cae7SDmytro Laktyushkin 	/* depends on pixel format */
10756566cae7SDmytro Laktyushkin 	calculate_scaling_ratios(pipe_ctx);
10766566cae7SDmytro Laktyushkin 	/* depends on scaling ratios and recout, does not calculate offset yet */
10776566cae7SDmytro Laktyushkin 	calculate_viewport_size(pipe_ctx);
10784562236bSHarry Wentland 
1079e13c2ea2SJaehyun Chung 	/* Stopgap for validation of ODM + MPO on one side of screen case */
1080e13c2ea2SJaehyun Chung 	if (pipe_ctx->plane_res.scl_data.viewport.height < 1 ||
1081e13c2ea2SJaehyun Chung 			pipe_ctx->plane_res.scl_data.viewport.width < 1)
1082e13c2ea2SJaehyun Chung 		return false;
1083e13c2ea2SJaehyun Chung 
10846566cae7SDmytro Laktyushkin 	/*
10856566cae7SDmytro Laktyushkin 	 * LB calculations depend on vp size, h/v_active and scaling ratios
10864562236bSHarry Wentland 	 * Setting line buffer pixel depth to 24bpp yields banding
1087a316db72SMario Kleiner 	 * on certain displays, such as the Sharp 4k. 36bpp is needed
1088a316db72SMario Kleiner 	 * to support SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616 and
1089a316db72SMario Kleiner 	 * SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616 with actual > 10 bpc
109072a7cf0aSMario Kleiner 	 * precision on at least DCN display engines. However, at least
109172a7cf0aSMario Kleiner 	 * Carrizo with DCE_VERSION_11_0 does not like 36 bpp lb depth,
109272a7cf0aSMario Kleiner 	 * so use only 30 bpp on DCE_VERSION_11_0. Testing with DCE 11.2 and 8.3
109372a7cf0aSMario Kleiner 	 * did not show such problems, so this seems to be the exception.
10944562236bSHarry Wentland 	 */
1095353ca0faSLiviu Dudau 	if (plane_state->ctx->dce_version > DCE_VERSION_11_0)
1096a316db72SMario Kleiner 		pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_36BPP;
109772a7cf0aSMario Kleiner 	else
109872a7cf0aSMario Kleiner 		pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_30BPP;
109972a7cf0aSMario Kleiner 
110033eef72fSEric Bernstein 	pipe_ctx->plane_res.scl_data.lb_params.alpha_en = plane_state->per_pixel_alpha;
11014562236bSHarry Wentland 
1102d94585a0SYue Hin Lau 	if (pipe_ctx->plane_res.xfm != NULL)
110386a66c4eSHarry Wentland 		res = pipe_ctx->plane_res.xfm->funcs->transform_get_optimal_number_of_taps(
110486a66c4eSHarry Wentland 				pipe_ctx->plane_res.xfm, &pipe_ctx->plane_res.scl_data, &plane_state->scaling_quality);
11054562236bSHarry Wentland 
1106d94585a0SYue Hin Lau 	if (pipe_ctx->plane_res.dpp != NULL)
1107d94585a0SYue Hin Lau 		res = pipe_ctx->plane_res.dpp->funcs->dpp_get_optimal_number_of_taps(
1108d94585a0SYue Hin Lau 				pipe_ctx->plane_res.dpp, &pipe_ctx->plane_res.scl_data, &plane_state->scaling_quality);
1109f7938bc0SReza Amini 
1110f7938bc0SReza Amini 
11114562236bSHarry Wentland 	if (!res) {
11124562236bSHarry Wentland 		/* Try 24 bpp linebuffer */
11136702a9acSHarry Wentland 		pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_24BPP;
11144562236bSHarry Wentland 
11151b6c8067SBhawanpreet Lakha 		if (pipe_ctx->plane_res.xfm != NULL)
111686a66c4eSHarry Wentland 			res = pipe_ctx->plane_res.xfm->funcs->transform_get_optimal_number_of_taps(
11171b6c8067SBhawanpreet Lakha 					pipe_ctx->plane_res.xfm,
11181b6c8067SBhawanpreet Lakha 					&pipe_ctx->plane_res.scl_data,
11191b6c8067SBhawanpreet Lakha 					&plane_state->scaling_quality);
1120d94585a0SYue Hin Lau 
11211b6c8067SBhawanpreet Lakha 		if (pipe_ctx->plane_res.dpp != NULL)
1122d94585a0SYue Hin Lau 			res = pipe_ctx->plane_res.dpp->funcs->dpp_get_optimal_number_of_taps(
11231b6c8067SBhawanpreet Lakha 					pipe_ctx->plane_res.dpp,
11241b6c8067SBhawanpreet Lakha 					&pipe_ctx->plane_res.scl_data,
11251b6c8067SBhawanpreet Lakha 					&plane_state->scaling_quality);
11264562236bSHarry Wentland 	}
11274562236bSHarry Wentland 
11286566cae7SDmytro Laktyushkin 	/*
11296566cae7SDmytro Laktyushkin 	 * Depends on recout, scaling ratios, h_active and taps
11306566cae7SDmytro Laktyushkin 	 * May need to re-check lb size after this in some obscure scenario
11316566cae7SDmytro Laktyushkin 	 */
1132b2d0a103SDmytro Laktyushkin 	if (res)
11336566cae7SDmytro Laktyushkin 		calculate_inits_and_viewports(pipe_ctx);
11346566cae7SDmytro Laktyushkin 
11356566cae7SDmytro Laktyushkin 	/*
11366566cae7SDmytro Laktyushkin 	 * Handle side by side and top bottom 3d recout offsets after vp calculation
11376566cae7SDmytro Laktyushkin 	 * since 3d is special and needs to calculate vp as if there is no recout offset
11386566cae7SDmytro Laktyushkin 	 * This may break with rotation, good thing we aren't mixing hw rotation and 3d
11396566cae7SDmytro Laktyushkin 	 */
11406566cae7SDmytro Laktyushkin 	if (pipe_ctx->top_pipe && pipe_ctx->top_pipe->plane_state == plane_state) {
11416566cae7SDmytro Laktyushkin 		ASSERT(plane_state->rotation == ROTATION_ANGLE_0 ||
11426566cae7SDmytro Laktyushkin 			(pipe_ctx->stream->view_format != VIEW_3D_FORMAT_TOP_AND_BOTTOM &&
11436566cae7SDmytro Laktyushkin 				pipe_ctx->stream->view_format != VIEW_3D_FORMAT_SIDE_BY_SIDE));
11446566cae7SDmytro Laktyushkin 		if (pipe_ctx->stream->view_format == VIEW_3D_FORMAT_TOP_AND_BOTTOM)
11456566cae7SDmytro Laktyushkin 			pipe_ctx->plane_res.scl_data.recout.y += pipe_ctx->plane_res.scl_data.recout.height;
11466566cae7SDmytro Laktyushkin 		else if (pipe_ctx->stream->view_format == VIEW_3D_FORMAT_SIDE_BY_SIDE)
11476566cae7SDmytro Laktyushkin 			pipe_ctx->plane_res.scl_data.recout.x += pipe_ctx->plane_res.scl_data.recout.width;
11486566cae7SDmytro Laktyushkin 	}
11496566cae7SDmytro Laktyushkin 
11506566cae7SDmytro Laktyushkin 	if (pipe_ctx->plane_res.scl_data.viewport.height < MIN_VIEWPORT_SIZE ||
11516566cae7SDmytro Laktyushkin 			pipe_ctx->plane_res.scl_data.viewport.width < MIN_VIEWPORT_SIZE)
11526566cae7SDmytro Laktyushkin 		res = false;
1153b2d0a103SDmytro Laktyushkin 
11543c0dcf9fSDmytro Laktyushkin 	DC_LOG_SCALER("%s pipe %d:\nViewport: height:%d width:%d x:%d y:%d  Recout: height:%d width:%d x:%d y:%d  HACTIVE:%d VACTIVE:%d\n"
11553c0dcf9fSDmytro Laktyushkin 			"src_rect: height:%d width:%d x:%d y:%d  dst_rect: height:%d width:%d x:%d y:%d  clip_rect: height:%d width:%d x:%d y:%d\n",
11564562236bSHarry Wentland 			__func__,
11573c0dcf9fSDmytro Laktyushkin 			pipe_ctx->pipe_idx,
11586702a9acSHarry Wentland 			pipe_ctx->plane_res.scl_data.viewport.height,
11596702a9acSHarry Wentland 			pipe_ctx->plane_res.scl_data.viewport.width,
11606702a9acSHarry Wentland 			pipe_ctx->plane_res.scl_data.viewport.x,
11616702a9acSHarry Wentland 			pipe_ctx->plane_res.scl_data.viewport.y,
11623c0dcf9fSDmytro Laktyushkin 			pipe_ctx->plane_res.scl_data.recout.height,
11633c0dcf9fSDmytro Laktyushkin 			pipe_ctx->plane_res.scl_data.recout.width,
11643c0dcf9fSDmytro Laktyushkin 			pipe_ctx->plane_res.scl_data.recout.x,
11653c0dcf9fSDmytro Laktyushkin 			pipe_ctx->plane_res.scl_data.recout.y,
11663c0dcf9fSDmytro Laktyushkin 			pipe_ctx->plane_res.scl_data.h_active,
11673c0dcf9fSDmytro Laktyushkin 			pipe_ctx->plane_res.scl_data.v_active,
11683c0dcf9fSDmytro Laktyushkin 			plane_state->src_rect.height,
11693c0dcf9fSDmytro Laktyushkin 			plane_state->src_rect.width,
11703c0dcf9fSDmytro Laktyushkin 			plane_state->src_rect.x,
11713c0dcf9fSDmytro Laktyushkin 			plane_state->src_rect.y,
11723be5262eSHarry Wentland 			plane_state->dst_rect.height,
11733be5262eSHarry Wentland 			plane_state->dst_rect.width,
11743be5262eSHarry Wentland 			plane_state->dst_rect.x,
11753c0dcf9fSDmytro Laktyushkin 			plane_state->dst_rect.y,
11763c0dcf9fSDmytro Laktyushkin 			plane_state->clip_rect.height,
11773c0dcf9fSDmytro Laktyushkin 			plane_state->clip_rect.width,
11783c0dcf9fSDmytro Laktyushkin 			plane_state->clip_rect.x,
11793c0dcf9fSDmytro Laktyushkin 			plane_state->clip_rect.y);
11804562236bSHarry Wentland 
11816566cae7SDmytro Laktyushkin 	pipe_ctx->stream->dst.x -= timing->h_border_left;
11826566cae7SDmytro Laktyushkin 	pipe_ctx->stream->dst.y -= timing->v_border_top;
118389d07b66SSamson Tam 
11844562236bSHarry Wentland 	return res;
11854562236bSHarry Wentland }
11864562236bSHarry Wentland 
11874562236bSHarry Wentland 
11884562236bSHarry Wentland enum dc_status resource_build_scaling_params_for_context(
1189fb3466a4SBhawanpreet Lakha 	const struct dc  *dc,
1190608ac7bbSJerry Zuo 	struct dc_state *context)
11914562236bSHarry Wentland {
11924562236bSHarry Wentland 	int i;
11934562236bSHarry Wentland 
11944562236bSHarry Wentland 	for (i = 0; i < MAX_PIPES; i++) {
11953be5262eSHarry Wentland 		if (context->res_ctx.pipe_ctx[i].plane_state != NULL &&
11964562236bSHarry Wentland 				context->res_ctx.pipe_ctx[i].stream != NULL)
1197b2d0a103SDmytro Laktyushkin 			if (!resource_build_scaling_params(&context->res_ctx.pipe_ctx[i]))
1198f84a8161STony Cheng 				return DC_FAIL_SCALING;
11994562236bSHarry Wentland 	}
12004562236bSHarry Wentland 
12014562236bSHarry Wentland 	return DC_OK;
12024562236bSHarry Wentland }
12034562236bSHarry Wentland 
1204a2b8659dSTony Cheng struct pipe_ctx *find_idle_secondary_pipe(
1205a2b8659dSTony Cheng 		struct resource_context *res_ctx,
12065581192dSJun Lei 		const struct resource_pool *pool,
12075581192dSJun Lei 		const struct pipe_ctx *primary_pipe)
12084562236bSHarry Wentland {
12094562236bSHarry Wentland 	int i;
12104562236bSHarry Wentland 	struct pipe_ctx *secondary_pipe = NULL;
12114562236bSHarry Wentland 
12124562236bSHarry Wentland 	/*
12135581192dSJun Lei 	 * We add a preferred pipe mapping to avoid the chance that
12145581192dSJun Lei 	 * MPCCs already in use will need to be reassigned to other trees.
12155581192dSJun Lei 	 * For example, if we went with the strict, assign backwards logic:
12165581192dSJun Lei 	 *
12175581192dSJun Lei 	 * (State 1)
12185581192dSJun Lei 	 * Display A on, no surface, top pipe = 0
12195581192dSJun Lei 	 * Display B on, no surface, top pipe = 1
12205581192dSJun Lei 	 *
12215581192dSJun Lei 	 * (State 2)
12225581192dSJun Lei 	 * Display A on, no surface, top pipe = 0
12235581192dSJun Lei 	 * Display B on, surface enable, top pipe = 1, bottom pipe = 5
12245581192dSJun Lei 	 *
12255581192dSJun Lei 	 * (State 3)
12265581192dSJun Lei 	 * Display A on, surface enable, top pipe = 0, bottom pipe = 5
12275581192dSJun Lei 	 * Display B on, surface enable, top pipe = 1, bottom pipe = 4
12285581192dSJun Lei 	 *
12295581192dSJun Lei 	 * The state 2->3 transition requires remapping MPCC 5 from display B
12305581192dSJun Lei 	 * to display A.
12315581192dSJun Lei 	 *
12325581192dSJun Lei 	 * However, with the preferred pipe logic, state 2 would look like:
12335581192dSJun Lei 	 *
12345581192dSJun Lei 	 * (State 2)
12355581192dSJun Lei 	 * Display A on, no surface, top pipe = 0
12365581192dSJun Lei 	 * Display B on, surface enable, top pipe = 1, bottom pipe = 4
12375581192dSJun Lei 	 *
12385581192dSJun Lei 	 * This would then cause 2->3 to not require remapping any MPCCs.
12395581192dSJun Lei 	 */
12405581192dSJun Lei 	if (primary_pipe) {
12415581192dSJun Lei 		int preferred_pipe_idx = (pool->pipe_count - 1) - primary_pipe->pipe_idx;
12425581192dSJun Lei 		if (res_ctx->pipe_ctx[preferred_pipe_idx].stream == NULL) {
12435581192dSJun Lei 			secondary_pipe = &res_ctx->pipe_ctx[preferred_pipe_idx];
12445581192dSJun Lei 			secondary_pipe->pipe_idx = preferred_pipe_idx;
12455581192dSJun Lei 		}
12465581192dSJun Lei 	}
12475581192dSJun Lei 
12485581192dSJun Lei 	/*
12494562236bSHarry Wentland 	 * search backwards for the second pipe to keep pipe
12504562236bSHarry Wentland 	 * assignment more consistent
12514562236bSHarry Wentland 	 */
12525581192dSJun Lei 	if (!secondary_pipe)
1253a2b8659dSTony Cheng 		for (i = pool->pipe_count - 1; i >= 0; i--) {
12544562236bSHarry Wentland 			if (res_ctx->pipe_ctx[i].stream == NULL) {
12554562236bSHarry Wentland 				secondary_pipe = &res_ctx->pipe_ctx[i];
12564562236bSHarry Wentland 				secondary_pipe->pipe_idx = i;
12574562236bSHarry Wentland 				break;
12584562236bSHarry Wentland 			}
12594562236bSHarry Wentland 		}
12604562236bSHarry Wentland 
12614562236bSHarry Wentland 	return secondary_pipe;
12624562236bSHarry Wentland }
12634562236bSHarry Wentland 
12644562236bSHarry Wentland struct pipe_ctx *resource_get_head_pipe_for_stream(
12654562236bSHarry Wentland 		struct resource_context *res_ctx,
12660971c40eSHarry Wentland 		struct dc_stream_state *stream)
12674562236bSHarry Wentland {
12684562236bSHarry Wentland 	int i;
126922498036SDmytro Laktyushkin 
1270a2b8659dSTony Cheng 	for (i = 0; i < MAX_PIPES; i++) {
1271b1f6d01cSDmytro Laktyushkin 		if (res_ctx->pipe_ctx[i].stream == stream
1272b1f6d01cSDmytro Laktyushkin 				&& !res_ctx->pipe_ctx[i].top_pipe
127322498036SDmytro Laktyushkin 				&& !res_ctx->pipe_ctx[i].prev_odm_pipe)
12744562236bSHarry Wentland 			return &res_ctx->pipe_ctx[i];
12754562236bSHarry Wentland 	}
12764562236bSHarry Wentland 	return NULL;
12774562236bSHarry Wentland }
12784562236bSHarry Wentland 
1279b1f6d01cSDmytro Laktyushkin static struct pipe_ctx *resource_get_tail_pipe(
128019f89e23SAndrey Grodzovsky 		struct resource_context *res_ctx,
1281b1f6d01cSDmytro Laktyushkin 		struct pipe_ctx *head_pipe)
128219f89e23SAndrey Grodzovsky {
1283b1f6d01cSDmytro Laktyushkin 	struct pipe_ctx *tail_pipe;
128419f89e23SAndrey Grodzovsky 
128519f89e23SAndrey Grodzovsky 	tail_pipe = head_pipe->bottom_pipe;
128619f89e23SAndrey Grodzovsky 
128719f89e23SAndrey Grodzovsky 	while (tail_pipe) {
128819f89e23SAndrey Grodzovsky 		head_pipe = tail_pipe;
128919f89e23SAndrey Grodzovsky 		tail_pipe = tail_pipe->bottom_pipe;
129019f89e23SAndrey Grodzovsky 	}
129119f89e23SAndrey Grodzovsky 
129219f89e23SAndrey Grodzovsky 	return head_pipe;
129319f89e23SAndrey Grodzovsky }
129419f89e23SAndrey Grodzovsky 
12954562236bSHarry Wentland /*
1296ab2541b6SAric Cyr  * A free_pipe for a stream is defined here as a pipe
1297ab2541b6SAric Cyr  * that has no surface attached yet
12984562236bSHarry Wentland  */
1299b1f6d01cSDmytro Laktyushkin static struct pipe_ctx *acquire_free_pipe_for_head(
1300608ac7bbSJerry Zuo 		struct dc_state *context,
1301a2b8659dSTony Cheng 		const struct resource_pool *pool,
1302b1f6d01cSDmytro Laktyushkin 		struct pipe_ctx *head_pipe)
13034562236bSHarry Wentland {
13044562236bSHarry Wentland 	int i;
1305745cc746SDmytro Laktyushkin 	struct resource_context *res_ctx = &context->res_ctx;
13064562236bSHarry Wentland 
13073be5262eSHarry Wentland 	if (!head_pipe->plane_state)
13084562236bSHarry Wentland 		return head_pipe;
13094562236bSHarry Wentland 
13104562236bSHarry Wentland 	/* Re-use pipe already acquired for this stream if available*/
1311a2b8659dSTony Cheng 	for (i = pool->pipe_count - 1; i >= 0; i--) {
1312b1f6d01cSDmytro Laktyushkin 		if (res_ctx->pipe_ctx[i].stream == head_pipe->stream &&
13133be5262eSHarry Wentland 				!res_ctx->pipe_ctx[i].plane_state) {
13144562236bSHarry Wentland 			return &res_ctx->pipe_ctx[i];
13154562236bSHarry Wentland 		}
13164562236bSHarry Wentland 	}
13174562236bSHarry Wentland 
13184562236bSHarry Wentland 	/*
13194562236bSHarry Wentland 	 * At this point we have no re-useable pipe for this stream and we need
13204562236bSHarry Wentland 	 * to acquire an idle one to satisfy the request
13214562236bSHarry Wentland 	 */
13224562236bSHarry Wentland 
1323a2b8659dSTony Cheng 	if (!pool->funcs->acquire_idle_pipe_for_layer)
13244562236bSHarry Wentland 		return NULL;
13254562236bSHarry Wentland 
1326b1f6d01cSDmytro Laktyushkin 	return pool->funcs->acquire_idle_pipe_for_layer(context, pool, head_pipe->stream);
13274562236bSHarry Wentland }
13284562236bSHarry Wentland 
1329b86a1aa3SBhawanpreet Lakha #if defined(CONFIG_DRM_AMD_DC_DCN)
13300f9a536fSDmytro Laktyushkin static int acquire_first_split_pipe(
13310f9a536fSDmytro Laktyushkin 		struct resource_context *res_ctx,
13320f9a536fSDmytro Laktyushkin 		const struct resource_pool *pool,
13330971c40eSHarry Wentland 		struct dc_stream_state *stream)
13340f9a536fSDmytro Laktyushkin {
13350f9a536fSDmytro Laktyushkin 	int i;
13360f9a536fSDmytro Laktyushkin 
13370f9a536fSDmytro Laktyushkin 	for (i = 0; i < pool->pipe_count; i++) {
133879592db3SDmytro Laktyushkin 		struct pipe_ctx *split_pipe = &res_ctx->pipe_ctx[i];
13390f9a536fSDmytro Laktyushkin 
1340b1f6d01cSDmytro Laktyushkin 		if (split_pipe->top_pipe &&
134179592db3SDmytro Laktyushkin 				split_pipe->top_pipe->plane_state == split_pipe->plane_state) {
134279592db3SDmytro Laktyushkin 			split_pipe->top_pipe->bottom_pipe = split_pipe->bottom_pipe;
134379592db3SDmytro Laktyushkin 			if (split_pipe->bottom_pipe)
134479592db3SDmytro Laktyushkin 				split_pipe->bottom_pipe->top_pipe = split_pipe->top_pipe;
13450f9a536fSDmytro Laktyushkin 
134679592db3SDmytro Laktyushkin 			if (split_pipe->top_pipe->plane_state)
134779592db3SDmytro Laktyushkin 				resource_build_scaling_params(split_pipe->top_pipe);
13480f9a536fSDmytro Laktyushkin 
134979592db3SDmytro Laktyushkin 			memset(split_pipe, 0, sizeof(*split_pipe));
135079592db3SDmytro Laktyushkin 			split_pipe->stream_res.tg = pool->timing_generators[i];
135179592db3SDmytro Laktyushkin 			split_pipe->plane_res.hubp = pool->hubps[i];
135279592db3SDmytro Laktyushkin 			split_pipe->plane_res.ipp = pool->ipps[i];
135379592db3SDmytro Laktyushkin 			split_pipe->plane_res.dpp = pool->dpps[i];
135479592db3SDmytro Laktyushkin 			split_pipe->stream_res.opp = pool->opps[i];
135579592db3SDmytro Laktyushkin 			split_pipe->plane_res.mpcc_inst = pool->dpps[i]->inst;
135679592db3SDmytro Laktyushkin 			split_pipe->pipe_idx = i;
135779592db3SDmytro Laktyushkin 
135879592db3SDmytro Laktyushkin 			split_pipe->stream = stream;
13590f9a536fSDmytro Laktyushkin 			return i;
13600f9a536fSDmytro Laktyushkin 		}
13610f9a536fSDmytro Laktyushkin 	}
13620f9a536fSDmytro Laktyushkin 	return -1;
13630f9a536fSDmytro Laktyushkin }
13640f9a536fSDmytro Laktyushkin #endif
13650f9a536fSDmytro Laktyushkin 
136619f89e23SAndrey Grodzovsky bool dc_add_plane_to_context(
136719f89e23SAndrey Grodzovsky 		const struct dc *dc,
13680971c40eSHarry Wentland 		struct dc_stream_state *stream,
136919f89e23SAndrey Grodzovsky 		struct dc_plane_state *plane_state,
1370608ac7bbSJerry Zuo 		struct dc_state *context)
13714562236bSHarry Wentland {
13724562236bSHarry Wentland 	int i;
137319f89e23SAndrey Grodzovsky 	struct resource_pool *pool = dc->res_pool;
137419f89e23SAndrey Grodzovsky 	struct pipe_ctx *head_pipe, *tail_pipe, *free_pipe;
1375ab2541b6SAric Cyr 	struct dc_stream_status *stream_status = NULL;
13764562236bSHarry Wentland 
1377ab2541b6SAric Cyr 	for (i = 0; i < context->stream_count; i++)
13784fa086b9SLeo (Sunpeng) Li 		if (context->streams[i] == stream) {
1379ab2541b6SAric Cyr 			stream_status = &context->stream_status[i];
13804562236bSHarry Wentland 			break;
13814562236bSHarry Wentland 		}
1382ab2541b6SAric Cyr 	if (stream_status == NULL) {
138319f89e23SAndrey Grodzovsky 		dm_error("Existing stream not found; failed to attach surface!\n");
138419f89e23SAndrey Grodzovsky 		return false;
138519f89e23SAndrey Grodzovsky 	}
138619f89e23SAndrey Grodzovsky 
138719f89e23SAndrey Grodzovsky 
138819f89e23SAndrey Grodzovsky 	if (stream_status->plane_count == MAX_SURFACE_NUM) {
138919f89e23SAndrey Grodzovsky 		dm_error("Surface: can not attach plane_state %p! Maximum is: %d\n",
139019f89e23SAndrey Grodzovsky 				plane_state, MAX_SURFACE_NUM);
139119f89e23SAndrey Grodzovsky 		return false;
139219f89e23SAndrey Grodzovsky 	}
139319f89e23SAndrey Grodzovsky 
139419f89e23SAndrey Grodzovsky 	head_pipe = resource_get_head_pipe_for_stream(&context->res_ctx, stream);
139519f89e23SAndrey Grodzovsky 
139619f89e23SAndrey Grodzovsky 	if (!head_pipe) {
139719f89e23SAndrey Grodzovsky 		dm_error("Head pipe not found for stream_state %p !\n", stream);
13984562236bSHarry Wentland 		return false;
13994562236bSHarry Wentland 	}
14004562236bSHarry Wentland 
1401b1f6d01cSDmytro Laktyushkin 	/* retain new surface, but only once per stream */
1402b1f6d01cSDmytro Laktyushkin 	dc_plane_state_retain(plane_state);
1403b1f6d01cSDmytro Laktyushkin 
1404b1f6d01cSDmytro Laktyushkin 	while (head_pipe) {
1405b1f6d01cSDmytro Laktyushkin 		free_pipe = acquire_free_pipe_for_head(context, pool, head_pipe);
14064562236bSHarry Wentland 
1407b86a1aa3SBhawanpreet Lakha 	#if defined(CONFIG_DRM_AMD_DC_DCN)
14080f9a536fSDmytro Laktyushkin 		if (!free_pipe) {
14090f9a536fSDmytro Laktyushkin 			int pipe_idx = acquire_first_split_pipe(&context->res_ctx, pool, stream);
14100f9a536fSDmytro Laktyushkin 			if (pipe_idx >= 0)
14110f9a536fSDmytro Laktyushkin 				free_pipe = &context->res_ctx.pipe_ctx[pipe_idx];
14120f9a536fSDmytro Laktyushkin 		}
14130f9a536fSDmytro Laktyushkin 	#endif
1414b1f6d01cSDmytro Laktyushkin 		if (!free_pipe) {
1415b1f6d01cSDmytro Laktyushkin 			dc_plane_state_release(plane_state);
14164562236bSHarry Wentland 			return false;
1417b1f6d01cSDmytro Laktyushkin 		}
14184562236bSHarry Wentland 
14193be5262eSHarry Wentland 		free_pipe->plane_state = plane_state;
14204562236bSHarry Wentland 
142119f89e23SAndrey Grodzovsky 		if (head_pipe != free_pipe) {
14225b5c1777SJosip Pavic 			tail_pipe = resource_get_tail_pipe(&context->res_ctx, head_pipe);
14235b5c1777SJosip Pavic 			ASSERT(tail_pipe);
14246b670fa9SHarry Wentland 			free_pipe->stream_res.tg = tail_pipe->stream_res.tg;
14259aef1a31SSivapiriyanKumarasamy 			free_pipe->stream_res.abm = tail_pipe->stream_res.abm;
1426a6a6cb34SHarry Wentland 			free_pipe->stream_res.opp = tail_pipe->stream_res.opp;
14278e9c4c8cSHarry Wentland 			free_pipe->stream_res.stream_enc = tail_pipe->stream_res.stream_enc;
1428afaacef4SHarry Wentland 			free_pipe->stream_res.audio = tail_pipe->stream_res.audio;
1429cfe4645eSDmytro Laktyushkin 			free_pipe->clock_source = tail_pipe->clock_source;
14304562236bSHarry Wentland 			free_pipe->top_pipe = tail_pipe;
14314562236bSHarry Wentland 			tail_pipe->bottom_pipe = free_pipe;
14322e7b43e6SDmytro Laktyushkin 			if (!free_pipe->next_odm_pipe && tail_pipe->next_odm_pipe && tail_pipe->next_odm_pipe->bottom_pipe) {
14332e7b43e6SDmytro Laktyushkin 				free_pipe->next_odm_pipe = tail_pipe->next_odm_pipe->bottom_pipe;
14342e7b43e6SDmytro Laktyushkin 				tail_pipe->next_odm_pipe->bottom_pipe->prev_odm_pipe = free_pipe;
14352e7b43e6SDmytro Laktyushkin 			}
14362e7b43e6SDmytro Laktyushkin 			if (!free_pipe->prev_odm_pipe && tail_pipe->prev_odm_pipe && tail_pipe->prev_odm_pipe->bottom_pipe) {
14372e7b43e6SDmytro Laktyushkin 				free_pipe->prev_odm_pipe = tail_pipe->prev_odm_pipe->bottom_pipe;
14382e7b43e6SDmytro Laktyushkin 				tail_pipe->prev_odm_pipe->bottom_pipe->next_odm_pipe = free_pipe;
14392e7b43e6SDmytro Laktyushkin 			}
14404562236bSHarry Wentland 		}
1441b1f6d01cSDmytro Laktyushkin 		head_pipe = head_pipe->next_odm_pipe;
1442b1f6d01cSDmytro Laktyushkin 	}
14434562236bSHarry Wentland 	/* assign new surfaces*/
144419f89e23SAndrey Grodzovsky 	stream_status->plane_states[stream_status->plane_count] = plane_state;
14454562236bSHarry Wentland 
144619f89e23SAndrey Grodzovsky 	stream_status->plane_count++;
14474562236bSHarry Wentland 
14484562236bSHarry Wentland 	return true;
14494562236bSHarry Wentland }
14504562236bSHarry Wentland 
145119f89e23SAndrey Grodzovsky bool dc_remove_plane_from_context(
145219f89e23SAndrey Grodzovsky 		const struct dc *dc,
145319f89e23SAndrey Grodzovsky 		struct dc_stream_state *stream,
145419f89e23SAndrey Grodzovsky 		struct dc_plane_state *plane_state,
1455608ac7bbSJerry Zuo 		struct dc_state *context)
145619f89e23SAndrey Grodzovsky {
145719f89e23SAndrey Grodzovsky 	int i;
145819f89e23SAndrey Grodzovsky 	struct dc_stream_status *stream_status = NULL;
145919f89e23SAndrey Grodzovsky 	struct resource_pool *pool = dc->res_pool;
146019f89e23SAndrey Grodzovsky 
146119f89e23SAndrey Grodzovsky 	for (i = 0; i < context->stream_count; i++)
146219f89e23SAndrey Grodzovsky 		if (context->streams[i] == stream) {
146319f89e23SAndrey Grodzovsky 			stream_status = &context->stream_status[i];
146419f89e23SAndrey Grodzovsky 			break;
146519f89e23SAndrey Grodzovsky 		}
146619f89e23SAndrey Grodzovsky 
146719f89e23SAndrey Grodzovsky 	if (stream_status == NULL) {
146819f89e23SAndrey Grodzovsky 		dm_error("Existing stream not found; failed to remove plane.\n");
146919f89e23SAndrey Grodzovsky 		return false;
147019f89e23SAndrey Grodzovsky 	}
147119f89e23SAndrey Grodzovsky 
147219f89e23SAndrey Grodzovsky 	/* release pipe for plane*/
147319f89e23SAndrey Grodzovsky 	for (i = pool->pipe_count - 1; i >= 0; i--) {
14746ffaa6fcSDmytro Laktyushkin 		struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
147519f89e23SAndrey Grodzovsky 
14766ffaa6fcSDmytro Laktyushkin 		if (pipe_ctx->plane_state == plane_state) {
147719f89e23SAndrey Grodzovsky 			if (pipe_ctx->top_pipe)
147819f89e23SAndrey Grodzovsky 				pipe_ctx->top_pipe->bottom_pipe = pipe_ctx->bottom_pipe;
147919f89e23SAndrey Grodzovsky 
148019f89e23SAndrey Grodzovsky 			/* Second condition is to avoid setting NULL to top pipe
148119f89e23SAndrey Grodzovsky 			 * of tail pipe making it look like head pipe in subsequent
148219f89e23SAndrey Grodzovsky 			 * deletes
148319f89e23SAndrey Grodzovsky 			 */
148419f89e23SAndrey Grodzovsky 			if (pipe_ctx->bottom_pipe && pipe_ctx->top_pipe)
148519f89e23SAndrey Grodzovsky 				pipe_ctx->bottom_pipe->top_pipe = pipe_ctx->top_pipe;
148619f89e23SAndrey Grodzovsky 
148719f89e23SAndrey Grodzovsky 			/*
148819f89e23SAndrey Grodzovsky 			 * For head pipe detach surfaces from pipe for tail
148919f89e23SAndrey Grodzovsky 			 * pipe just zero it out
149019f89e23SAndrey Grodzovsky 			 */
1491b1f6d01cSDmytro Laktyushkin 			if (!pipe_ctx->top_pipe)
149219f89e23SAndrey Grodzovsky 				pipe_ctx->plane_state = NULL;
1493b1f6d01cSDmytro Laktyushkin 			else
149419f89e23SAndrey Grodzovsky 				memset(pipe_ctx, 0, sizeof(*pipe_ctx));
149519f89e23SAndrey Grodzovsky 		}
149619f89e23SAndrey Grodzovsky 	}
149719f89e23SAndrey Grodzovsky 
149819f89e23SAndrey Grodzovsky 
149919f89e23SAndrey Grodzovsky 	for (i = 0; i < stream_status->plane_count; i++) {
150019f89e23SAndrey Grodzovsky 		if (stream_status->plane_states[i] == plane_state) {
150119f89e23SAndrey Grodzovsky 
150219f89e23SAndrey Grodzovsky 			dc_plane_state_release(stream_status->plane_states[i]);
150319f89e23SAndrey Grodzovsky 			break;
150419f89e23SAndrey Grodzovsky 		}
150519f89e23SAndrey Grodzovsky 	}
150619f89e23SAndrey Grodzovsky 
150719f89e23SAndrey Grodzovsky 	if (i == stream_status->plane_count) {
150819f89e23SAndrey Grodzovsky 		dm_error("Existing plane_state not found; failed to detach it!\n");
150919f89e23SAndrey Grodzovsky 		return false;
151019f89e23SAndrey Grodzovsky 	}
151119f89e23SAndrey Grodzovsky 
151219f89e23SAndrey Grodzovsky 	stream_status->plane_count--;
151319f89e23SAndrey Grodzovsky 
1514abb4986eSAndrew Jiang 	/* Start at the plane we've just released, and move all the planes one index forward to "trim" the array */
1515abb4986eSAndrew Jiang 	for (; i < stream_status->plane_count; i++)
151619f89e23SAndrey Grodzovsky 		stream_status->plane_states[i] = stream_status->plane_states[i + 1];
151719f89e23SAndrey Grodzovsky 
151819f89e23SAndrey Grodzovsky 	stream_status->plane_states[stream_status->plane_count] = NULL;
151919f89e23SAndrey Grodzovsky 
152019f89e23SAndrey Grodzovsky 	return true;
152119f89e23SAndrey Grodzovsky }
152219f89e23SAndrey Grodzovsky 
152319f89e23SAndrey Grodzovsky bool dc_rem_all_planes_for_stream(
152419f89e23SAndrey Grodzovsky 		const struct dc *dc,
152519f89e23SAndrey Grodzovsky 		struct dc_stream_state *stream,
1526608ac7bbSJerry Zuo 		struct dc_state *context)
152719f89e23SAndrey Grodzovsky {
152819f89e23SAndrey Grodzovsky 	int i, old_plane_count;
152919f89e23SAndrey Grodzovsky 	struct dc_stream_status *stream_status = NULL;
153019f89e23SAndrey Grodzovsky 	struct dc_plane_state *del_planes[MAX_SURFACE_NUM] = { 0 };
153119f89e23SAndrey Grodzovsky 
153219f89e23SAndrey Grodzovsky 	for (i = 0; i < context->stream_count; i++)
153319f89e23SAndrey Grodzovsky 			if (context->streams[i] == stream) {
153419f89e23SAndrey Grodzovsky 				stream_status = &context->stream_status[i];
153519f89e23SAndrey Grodzovsky 				break;
153619f89e23SAndrey Grodzovsky 			}
153719f89e23SAndrey Grodzovsky 
153819f89e23SAndrey Grodzovsky 	if (stream_status == NULL) {
153919f89e23SAndrey Grodzovsky 		dm_error("Existing stream %p not found!\n", stream);
154019f89e23SAndrey Grodzovsky 		return false;
154119f89e23SAndrey Grodzovsky 	}
154219f89e23SAndrey Grodzovsky 
154319f89e23SAndrey Grodzovsky 	old_plane_count = stream_status->plane_count;
154419f89e23SAndrey Grodzovsky 
154519f89e23SAndrey Grodzovsky 	for (i = 0; i < old_plane_count; i++)
154619f89e23SAndrey Grodzovsky 		del_planes[i] = stream_status->plane_states[i];
154719f89e23SAndrey Grodzovsky 
154819f89e23SAndrey Grodzovsky 	for (i = 0; i < old_plane_count; i++)
154919f89e23SAndrey Grodzovsky 		if (!dc_remove_plane_from_context(dc, stream, del_planes[i], context))
155019f89e23SAndrey Grodzovsky 			return false;
155119f89e23SAndrey Grodzovsky 
155219f89e23SAndrey Grodzovsky 	return true;
155319f89e23SAndrey Grodzovsky }
155419f89e23SAndrey Grodzovsky 
155519f89e23SAndrey Grodzovsky static bool add_all_planes_for_stream(
155619f89e23SAndrey Grodzovsky 		const struct dc *dc,
155719f89e23SAndrey Grodzovsky 		struct dc_stream_state *stream,
155819f89e23SAndrey Grodzovsky 		const struct dc_validation_set set[],
155919f89e23SAndrey Grodzovsky 		int set_count,
1560608ac7bbSJerry Zuo 		struct dc_state *context)
156119f89e23SAndrey Grodzovsky {
156219f89e23SAndrey Grodzovsky 	int i, j;
156319f89e23SAndrey Grodzovsky 
156419f89e23SAndrey Grodzovsky 	for (i = 0; i < set_count; i++)
156519f89e23SAndrey Grodzovsky 		if (set[i].stream == stream)
156619f89e23SAndrey Grodzovsky 			break;
156719f89e23SAndrey Grodzovsky 
156819f89e23SAndrey Grodzovsky 	if (i == set_count) {
156919f89e23SAndrey Grodzovsky 		dm_error("Stream %p not found in set!\n", stream);
157019f89e23SAndrey Grodzovsky 		return false;
157119f89e23SAndrey Grodzovsky 	}
157219f89e23SAndrey Grodzovsky 
157319f89e23SAndrey Grodzovsky 	for (j = 0; j < set[i].plane_count; j++)
157419f89e23SAndrey Grodzovsky 		if (!dc_add_plane_to_context(dc, stream, set[i].plane_states[j], context))
157519f89e23SAndrey Grodzovsky 			return false;
157619f89e23SAndrey Grodzovsky 
157719f89e23SAndrey Grodzovsky 	return true;
157819f89e23SAndrey Grodzovsky }
157919f89e23SAndrey Grodzovsky 
158019f89e23SAndrey Grodzovsky bool dc_add_all_planes_for_stream(
158119f89e23SAndrey Grodzovsky 		const struct dc *dc,
158219f89e23SAndrey Grodzovsky 		struct dc_stream_state *stream,
158319f89e23SAndrey Grodzovsky 		struct dc_plane_state * const *plane_states,
158419f89e23SAndrey Grodzovsky 		int plane_count,
1585608ac7bbSJerry Zuo 		struct dc_state *context)
158619f89e23SAndrey Grodzovsky {
158719f89e23SAndrey Grodzovsky 	struct dc_validation_set set;
158819f89e23SAndrey Grodzovsky 	int i;
158919f89e23SAndrey Grodzovsky 
159019f89e23SAndrey Grodzovsky 	set.stream = stream;
159119f89e23SAndrey Grodzovsky 	set.plane_count = plane_count;
159219f89e23SAndrey Grodzovsky 
159319f89e23SAndrey Grodzovsky 	for (i = 0; i < plane_count; i++)
159419f89e23SAndrey Grodzovsky 		set.plane_states[i] = plane_states[i];
159519f89e23SAndrey Grodzovsky 
159619f89e23SAndrey Grodzovsky 	return add_all_planes_for_stream(dc, stream, &set, 1, context);
159719f89e23SAndrey Grodzovsky }
159819f89e23SAndrey Grodzovsky 
15990971c40eSHarry Wentland static bool is_timing_changed(struct dc_stream_state *cur_stream,
16000971c40eSHarry Wentland 		struct dc_stream_state *new_stream)
16014562236bSHarry Wentland {
16024562236bSHarry Wentland 	if (cur_stream == NULL)
16034562236bSHarry Wentland 		return true;
16044562236bSHarry Wentland 
16054562236bSHarry Wentland 	/* If output color space is changed, need to reprogram info frames */
16064fa086b9SLeo (Sunpeng) Li 	if (cur_stream->output_color_space != new_stream->output_color_space)
16074562236bSHarry Wentland 		return true;
16084562236bSHarry Wentland 
16094562236bSHarry Wentland 	return memcmp(
16104fa086b9SLeo (Sunpeng) Li 		&cur_stream->timing,
16114fa086b9SLeo (Sunpeng) Li 		&new_stream->timing,
16124562236bSHarry Wentland 		sizeof(struct dc_crtc_timing)) != 0;
16134562236bSHarry Wentland }
16144562236bSHarry Wentland 
16154562236bSHarry Wentland static bool are_stream_backends_same(
16160971c40eSHarry Wentland 	struct dc_stream_state *stream_a, struct dc_stream_state *stream_b)
16174562236bSHarry Wentland {
16184562236bSHarry Wentland 	if (stream_a == stream_b)
16194562236bSHarry Wentland 		return true;
16204562236bSHarry Wentland 
16214562236bSHarry Wentland 	if (stream_a == NULL || stream_b == NULL)
16224562236bSHarry Wentland 		return false;
16234562236bSHarry Wentland 
16244562236bSHarry Wentland 	if (is_timing_changed(stream_a, stream_b))
16254562236bSHarry Wentland 		return false;
16264562236bSHarry Wentland 
16271e7e86c4SSamson Tam 	if (stream_a->dpms_off != stream_b->dpms_off)
16281e7e86c4SSamson Tam 		return false;
16291e7e86c4SSamson Tam 
16304562236bSHarry Wentland 	return true;
16314562236bSHarry Wentland }
16324562236bSHarry Wentland 
1633625a15bfSLee Jones /*
16342119aa17SDavid Francis  * dc_is_stream_unchanged() - Compare two stream states for equivalence.
16352119aa17SDavid Francis  *
16362119aa17SDavid Francis  * Checks if there a difference between the two states
16372119aa17SDavid Francis  * that would require a mode change.
16382119aa17SDavid Francis  *
16392119aa17SDavid Francis  * Does not compare cursor position or attributes.
16402119aa17SDavid Francis  */
1641d54d29dbSBhawanpreet Lakha bool dc_is_stream_unchanged(
16420971c40eSHarry Wentland 	struct dc_stream_state *old_stream, struct dc_stream_state *stream)
16434562236bSHarry Wentland {
16444562236bSHarry Wentland 
16454562236bSHarry Wentland 	if (!are_stream_backends_same(old_stream, stream))
16464562236bSHarry Wentland 		return false;
16474562236bSHarry Wentland 
16480460f9abSJun Lei 	if (old_stream->ignore_msa_timing_param != stream->ignore_msa_timing_param)
16490460f9abSJun Lei 		return false;
16500460f9abSJun Lei 
16514562236bSHarry Wentland 	return true;
16524562236bSHarry Wentland }
16534562236bSHarry Wentland 
1654625a15bfSLee Jones /*
16552119aa17SDavid Francis  * dc_is_stream_scaling_unchanged() - Compare scaling rectangles of two streams.
16562119aa17SDavid Francis  */
16579a5d9c48SLeo (Sunpeng) Li bool dc_is_stream_scaling_unchanged(
16589a5d9c48SLeo (Sunpeng) Li 	struct dc_stream_state *old_stream, struct dc_stream_state *stream)
16599a5d9c48SLeo (Sunpeng) Li {
16609a5d9c48SLeo (Sunpeng) Li 	if (old_stream == stream)
16619a5d9c48SLeo (Sunpeng) Li 		return true;
16629a5d9c48SLeo (Sunpeng) Li 
16639a5d9c48SLeo (Sunpeng) Li 	if (old_stream == NULL || stream == NULL)
16649a5d9c48SLeo (Sunpeng) Li 		return false;
16659a5d9c48SLeo (Sunpeng) Li 
16669a5d9c48SLeo (Sunpeng) Li 	if (memcmp(&old_stream->src,
16679a5d9c48SLeo (Sunpeng) Li 			&stream->src,
16689a5d9c48SLeo (Sunpeng) Li 			sizeof(struct rect)) != 0)
16699a5d9c48SLeo (Sunpeng) Li 		return false;
16709a5d9c48SLeo (Sunpeng) Li 
16719a5d9c48SLeo (Sunpeng) Li 	if (memcmp(&old_stream->dst,
16729a5d9c48SLeo (Sunpeng) Li 			&stream->dst,
16739a5d9c48SLeo (Sunpeng) Li 			sizeof(struct rect)) != 0)
16749a5d9c48SLeo (Sunpeng) Li 		return false;
16759a5d9c48SLeo (Sunpeng) Li 
16769a5d9c48SLeo (Sunpeng) Li 	return true;
16779a5d9c48SLeo (Sunpeng) Li }
16789a5d9c48SLeo (Sunpeng) Li 
16791dc90497SAndrey Grodzovsky static void update_stream_engine_usage(
16804562236bSHarry Wentland 		struct resource_context *res_ctx,
1681a2b8659dSTony Cheng 		const struct resource_pool *pool,
16821dc90497SAndrey Grodzovsky 		struct stream_encoder *stream_enc,
16831dc90497SAndrey Grodzovsky 		bool acquired)
16844562236bSHarry Wentland {
16854562236bSHarry Wentland 	int i;
16864562236bSHarry Wentland 
1687a2b8659dSTony Cheng 	for (i = 0; i < pool->stream_enc_count; i++) {
1688a2b8659dSTony Cheng 		if (pool->stream_enc[i] == stream_enc)
16891dc90497SAndrey Grodzovsky 			res_ctx->is_stream_enc_acquired[i] = acquired;
16904562236bSHarry Wentland 	}
16914562236bSHarry Wentland }
16924562236bSHarry Wentland 
1693f01ee019SFangzhi Zuo #if defined(CONFIG_DRM_AMD_DC_DCN)
1694f01ee019SFangzhi Zuo static void update_hpo_dp_stream_engine_usage(
1695f01ee019SFangzhi Zuo 		struct resource_context *res_ctx,
1696f01ee019SFangzhi Zuo 		const struct resource_pool *pool,
1697f01ee019SFangzhi Zuo 		struct hpo_dp_stream_encoder *hpo_dp_stream_enc,
1698f01ee019SFangzhi Zuo 		bool acquired)
1699f01ee019SFangzhi Zuo {
1700f01ee019SFangzhi Zuo 	int i;
1701f01ee019SFangzhi Zuo 
1702f01ee019SFangzhi Zuo 	for (i = 0; i < pool->hpo_dp_stream_enc_count; i++) {
1703f01ee019SFangzhi Zuo 		if (pool->hpo_dp_stream_enc[i] == hpo_dp_stream_enc)
1704f01ee019SFangzhi Zuo 			res_ctx->is_hpo_dp_stream_enc_acquired[i] = acquired;
1705f01ee019SFangzhi Zuo 	}
1706f01ee019SFangzhi Zuo }
1707f01ee019SFangzhi Zuo #endif
1708f01ee019SFangzhi Zuo 
17094562236bSHarry Wentland /* TODO: release audio object */
17104176664bSCharlene Liu void update_audio_usage(
17114562236bSHarry Wentland 		struct resource_context *res_ctx,
1712a2b8659dSTony Cheng 		const struct resource_pool *pool,
17131dc90497SAndrey Grodzovsky 		struct audio *audio,
17141dc90497SAndrey Grodzovsky 		bool acquired)
17154562236bSHarry Wentland {
17164562236bSHarry Wentland 	int i;
1717a2b8659dSTony Cheng 	for (i = 0; i < pool->audio_count; i++) {
1718a2b8659dSTony Cheng 		if (pool->audios[i] == audio)
17191dc90497SAndrey Grodzovsky 			res_ctx->is_audio_acquired[i] = acquired;
17204562236bSHarry Wentland 	}
17214562236bSHarry Wentland }
17224562236bSHarry Wentland 
17234562236bSHarry Wentland static int acquire_first_free_pipe(
17244562236bSHarry Wentland 		struct resource_context *res_ctx,
1725a2b8659dSTony Cheng 		const struct resource_pool *pool,
17260971c40eSHarry Wentland 		struct dc_stream_state *stream)
17274562236bSHarry Wentland {
17284562236bSHarry Wentland 	int i;
17294562236bSHarry Wentland 
1730a2b8659dSTony Cheng 	for (i = 0; i < pool->pipe_count; i++) {
17314562236bSHarry Wentland 		if (!res_ctx->pipe_ctx[i].stream) {
17324562236bSHarry Wentland 			struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[i];
17334562236bSHarry Wentland 
17346b670fa9SHarry Wentland 			pipe_ctx->stream_res.tg = pool->timing_generators[i];
173586a66c4eSHarry Wentland 			pipe_ctx->plane_res.mi = pool->mis[i];
17368feabd03SYue Hin Lau 			pipe_ctx->plane_res.hubp = pool->hubps[i];
173786a66c4eSHarry Wentland 			pipe_ctx->plane_res.ipp = pool->ipps[i];
173886a66c4eSHarry Wentland 			pipe_ctx->plane_res.xfm = pool->transforms[i];
1739d94585a0SYue Hin Lau 			pipe_ctx->plane_res.dpp = pool->dpps[i];
1740a6a6cb34SHarry Wentland 			pipe_ctx->stream_res.opp = pool->opps[i];
1741bc373a89SRoman Li 			if (pool->dpps[i])
1742e07f541fSYongqiang Sun 				pipe_ctx->plane_res.mpcc_inst = pool->dpps[i]->inst;
17434562236bSHarry Wentland 			pipe_ctx->pipe_idx = i;
17444562236bSHarry Wentland 
1745ff5ef992SAlex Deucher 
17464562236bSHarry Wentland 			pipe_ctx->stream = stream;
17474562236bSHarry Wentland 			return i;
17484562236bSHarry Wentland 		}
17494562236bSHarry Wentland 	}
17504562236bSHarry Wentland 	return -1;
17514562236bSHarry Wentland }
17524562236bSHarry Wentland 
1753f01ee019SFangzhi Zuo #if defined(CONFIG_DRM_AMD_DC_DCN)
1754f01ee019SFangzhi Zuo static struct hpo_dp_stream_encoder *find_first_free_match_hpo_dp_stream_enc_for_link(
1755f01ee019SFangzhi Zuo 		struct resource_context *res_ctx,
1756f01ee019SFangzhi Zuo 		const struct resource_pool *pool,
1757f01ee019SFangzhi Zuo 		struct dc_stream_state *stream)
1758f01ee019SFangzhi Zuo {
1759f01ee019SFangzhi Zuo 	int i;
1760f01ee019SFangzhi Zuo 
1761f01ee019SFangzhi Zuo 	for (i = 0; i < pool->hpo_dp_stream_enc_count; i++) {
1762f01ee019SFangzhi Zuo 		if (!res_ctx->is_hpo_dp_stream_enc_acquired[i] &&
1763f01ee019SFangzhi Zuo 				pool->hpo_dp_stream_enc[i]) {
1764f01ee019SFangzhi Zuo 
1765f01ee019SFangzhi Zuo 			return pool->hpo_dp_stream_enc[i];
1766f01ee019SFangzhi Zuo 		}
1767f01ee019SFangzhi Zuo 	}
1768f01ee019SFangzhi Zuo 
1769f01ee019SFangzhi Zuo 	return NULL;
1770f01ee019SFangzhi Zuo }
1771f01ee019SFangzhi Zuo #endif
1772f01ee019SFangzhi Zuo 
1773a2b8659dSTony Cheng static struct audio *find_first_free_audio(
1774a2b8659dSTony Cheng 		struct resource_context *res_ctx,
1775cfb071f7SCharlene Liu 		const struct resource_pool *pool,
1776f24b0522SPaul Hsieh 		enum engine_id id,
1777f24b0522SPaul Hsieh 		enum dce_version dc_version)
17784562236bSHarry Wentland {
1779b5a41620SCharlene Liu 	int i, available_audio_count;
1780b5a41620SCharlene Liu 
1781b5a41620SCharlene Liu 	available_audio_count = pool->audio_count;
1782b5a41620SCharlene Liu 
1783b5a41620SCharlene Liu 	for (i = 0; i < available_audio_count; i++) {
17844176664bSCharlene Liu 		if ((res_ctx->is_audio_acquired[i] == false) && (res_ctx->is_stream_enc_acquired[i] == true)) {
1785cfb071f7SCharlene Liu 			/*we have enough audio endpoint, find the matching inst*/
1786cfb071f7SCharlene Liu 			if (id != i)
1787cfb071f7SCharlene Liu 				continue;
1788a2b8659dSTony Cheng 			return pool->audios[i];
17894562236bSHarry Wentland 		}
17904562236bSHarry Wentland 	}
17915feb9f07STai Man 
17925feb9f07STai Man 	/* use engine id to find free audio */
1793b5a41620SCharlene Liu 	if ((id < available_audio_count) && (res_ctx->is_audio_acquired[id] == false)) {
17945feb9f07STai Man 		return pool->audios[id];
17955feb9f07STai Man 	}
179666bfd4fdSCharlene Liu 	/*not found the matching one, first come first serve*/
1797b5a41620SCharlene Liu 	for (i = 0; i < available_audio_count; i++) {
17984176664bSCharlene Liu 		if (res_ctx->is_audio_acquired[i] == false) {
17994176664bSCharlene Liu 			return pool->audios[i];
18004176664bSCharlene Liu 		}
18014176664bSCharlene Liu 	}
18024562236bSHarry Wentland 	return 0;
18034562236bSHarry Wentland }
18044562236bSHarry Wentland 
1805625a15bfSLee Jones /*
18062119aa17SDavid Francis  * dc_add_stream_to_ctx() - Add a new dc_stream_state to a dc_state.
18072119aa17SDavid Francis  */
180813ab1b44SYongqiang Sun enum dc_status dc_add_stream_to_ctx(
18091dc90497SAndrey Grodzovsky 		struct dc *dc,
1810608ac7bbSJerry Zuo 		struct dc_state *new_ctx,
18111dc90497SAndrey Grodzovsky 		struct dc_stream_state *stream)
18121dc90497SAndrey Grodzovsky {
18131dc90497SAndrey Grodzovsky 	enum dc_status res;
1814eb9714a2SWenjing Liu 	DC_LOGGER_INIT(dc->ctx->logger);
18151dc90497SAndrey Grodzovsky 
1816ece4147fSKen Chalmers 	if (new_ctx->stream_count >= dc->res_pool->timing_generator_count) {
1817eb9714a2SWenjing Liu 		DC_LOG_WARNING("Max streams reached, can't add stream %p !\n", stream);
18181dc90497SAndrey Grodzovsky 		return DC_ERROR_UNEXPECTED;
18191dc90497SAndrey Grodzovsky 	}
18201dc90497SAndrey Grodzovsky 
18211dc90497SAndrey Grodzovsky 	new_ctx->streams[new_ctx->stream_count] = stream;
18221dc90497SAndrey Grodzovsky 	dc_stream_retain(stream);
18231dc90497SAndrey Grodzovsky 	new_ctx->stream_count++;
18241dc90497SAndrey Grodzovsky 
18251dc90497SAndrey Grodzovsky 	res = dc->res_pool->funcs->add_stream_to_ctx(dc, new_ctx, stream);
18261dc90497SAndrey Grodzovsky 	if (res != DC_OK)
1827eb9714a2SWenjing Liu 		DC_LOG_WARNING("Adding stream %p to context failed with err %d!\n", stream, res);
18281dc90497SAndrey Grodzovsky 
182913ab1b44SYongqiang Sun 	return res;
18301dc90497SAndrey Grodzovsky }
18311dc90497SAndrey Grodzovsky 
1832625a15bfSLee Jones /*
18332119aa17SDavid Francis  * dc_remove_stream_from_ctx() - Remove a stream from a dc_state.
18342119aa17SDavid Francis  */
183562c933f9SYongqiang Sun enum dc_status dc_remove_stream_from_ctx(
18361dc90497SAndrey Grodzovsky 			struct dc *dc,
1837608ac7bbSJerry Zuo 			struct dc_state *new_ctx,
18381dc90497SAndrey Grodzovsky 			struct dc_stream_state *stream)
18391dc90497SAndrey Grodzovsky {
184019f89e23SAndrey Grodzovsky 	int i;
18411dc90497SAndrey Grodzovsky 	struct dc_context *dc_ctx = dc->ctx;
184222498036SDmytro Laktyushkin 	struct pipe_ctx *del_pipe = resource_get_head_pipe_for_stream(&new_ctx->res_ctx, stream);
184322498036SDmytro Laktyushkin 	struct pipe_ctx *odm_pipe;
184422498036SDmytro Laktyushkin 
184522498036SDmytro Laktyushkin 	if (!del_pipe) {
184622498036SDmytro Laktyushkin 		DC_ERROR("Pipe not found for stream %p !\n", stream);
184722498036SDmytro Laktyushkin 		return DC_ERROR_UNEXPECTED;
184822498036SDmytro Laktyushkin 	}
184922498036SDmytro Laktyushkin 
185022498036SDmytro Laktyushkin 	odm_pipe = del_pipe->next_odm_pipe;
18511dc90497SAndrey Grodzovsky 
185219f89e23SAndrey Grodzovsky 	/* Release primary pipe */
185319f89e23SAndrey Grodzovsky 	ASSERT(del_pipe->stream_res.stream_enc);
18541dc90497SAndrey Grodzovsky 	update_stream_engine_usage(
18551dc90497SAndrey Grodzovsky 			&new_ctx->res_ctx,
18561dc90497SAndrey Grodzovsky 				dc->res_pool,
18571dc90497SAndrey Grodzovsky 			del_pipe->stream_res.stream_enc,
18581dc90497SAndrey Grodzovsky 			false);
1859f42ef862SJimmy Kizito 	/* Release link encoder from stream in new dc_state. */
1860f42ef862SJimmy Kizito 	if (dc->res_pool->funcs->link_enc_unassign)
1861f42ef862SJimmy Kizito 		dc->res_pool->funcs->link_enc_unassign(new_ctx, del_pipe->stream);
18621dc90497SAndrey Grodzovsky 
1863f01ee019SFangzhi Zuo #if defined(CONFIG_DRM_AMD_DC_DCN)
1864f01ee019SFangzhi Zuo 	if (is_dp_128b_132b_signal(del_pipe)) {
1865f01ee019SFangzhi Zuo 		update_hpo_dp_stream_engine_usage(
1866f01ee019SFangzhi Zuo 			&new_ctx->res_ctx, dc->res_pool,
1867f01ee019SFangzhi Zuo 			del_pipe->stream_res.hpo_dp_stream_enc,
1868f01ee019SFangzhi Zuo 			false);
1869f01ee019SFangzhi Zuo 	}
1870f01ee019SFangzhi Zuo #endif
1871f01ee019SFangzhi Zuo 
18721dc90497SAndrey Grodzovsky 	if (del_pipe->stream_res.audio)
18731dc90497SAndrey Grodzovsky 		update_audio_usage(
18741dc90497SAndrey Grodzovsky 			&new_ctx->res_ctx,
18751dc90497SAndrey Grodzovsky 			dc->res_pool,
18761dc90497SAndrey Grodzovsky 			del_pipe->stream_res.audio,
18771dc90497SAndrey Grodzovsky 			false);
18781dc90497SAndrey Grodzovsky 
18799d0dcecdSHarry Wentland 	resource_unreference_clock_source(&new_ctx->res_ctx,
18809d0dcecdSHarry Wentland 					  dc->res_pool,
18819d0dcecdSHarry Wentland 					  del_pipe->clock_source);
18829d0dcecdSHarry Wentland 
1883e56ae556SNikola Cornij 	if (dc->res_pool->funcs->remove_stream_from_ctx)
1884e56ae556SNikola Cornij 		dc->res_pool->funcs->remove_stream_from_ctx(dc, new_ctx, stream);
1885e56ae556SNikola Cornij 
188622498036SDmytro Laktyushkin 	while (odm_pipe) {
188722498036SDmytro Laktyushkin 		struct pipe_ctx *next_odm_pipe = odm_pipe->next_odm_pipe;
188822498036SDmytro Laktyushkin 
188922498036SDmytro Laktyushkin 		memset(odm_pipe, 0, sizeof(*odm_pipe));
189022498036SDmytro Laktyushkin 		odm_pipe = next_odm_pipe;
189122498036SDmytro Laktyushkin 	}
18921dc90497SAndrey Grodzovsky 	memset(del_pipe, 0, sizeof(*del_pipe));
18936ffaa6fcSDmytro Laktyushkin 
18941dc90497SAndrey Grodzovsky 	for (i = 0; i < new_ctx->stream_count; i++)
18951dc90497SAndrey Grodzovsky 		if (new_ctx->streams[i] == stream)
18961dc90497SAndrey Grodzovsky 			break;
18971dc90497SAndrey Grodzovsky 
18981dc90497SAndrey Grodzovsky 	if (new_ctx->streams[i] != stream) {
18991dc90497SAndrey Grodzovsky 		DC_ERROR("Context doesn't have stream %p !\n", stream);
19001dc90497SAndrey Grodzovsky 		return DC_ERROR_UNEXPECTED;
19011dc90497SAndrey Grodzovsky 	}
19021dc90497SAndrey Grodzovsky 
19031dc90497SAndrey Grodzovsky 	dc_stream_release(new_ctx->streams[i]);
19041dc90497SAndrey Grodzovsky 	new_ctx->stream_count--;
19051dc90497SAndrey Grodzovsky 
19061dc90497SAndrey Grodzovsky 	/* Trim back arrays */
19071dc90497SAndrey Grodzovsky 	for (; i < new_ctx->stream_count; i++) {
19081dc90497SAndrey Grodzovsky 		new_ctx->streams[i] = new_ctx->streams[i + 1];
19091dc90497SAndrey Grodzovsky 		new_ctx->stream_status[i] = new_ctx->stream_status[i + 1];
19101dc90497SAndrey Grodzovsky 	}
19111dc90497SAndrey Grodzovsky 
19121dc90497SAndrey Grodzovsky 	new_ctx->streams[new_ctx->stream_count] = NULL;
19131dc90497SAndrey Grodzovsky 	memset(
19141dc90497SAndrey Grodzovsky 			&new_ctx->stream_status[new_ctx->stream_count],
19151dc90497SAndrey Grodzovsky 			0,
19161dc90497SAndrey Grodzovsky 			sizeof(new_ctx->stream_status[0]));
19171dc90497SAndrey Grodzovsky 
19181dc90497SAndrey Grodzovsky 	return DC_OK;
19191dc90497SAndrey Grodzovsky }
19201dc90497SAndrey Grodzovsky 
19210971c40eSHarry Wentland static struct dc_stream_state *find_pll_sharable_stream(
19220971c40eSHarry Wentland 		struct dc_stream_state *stream_needs_pll,
1923608ac7bbSJerry Zuo 		struct dc_state *context)
19244562236bSHarry Wentland {
1925ab2541b6SAric Cyr 	int i;
19264562236bSHarry Wentland 
1927ab2541b6SAric Cyr 	for (i = 0; i < context->stream_count; i++) {
19280971c40eSHarry Wentland 		struct dc_stream_state *stream_has_pll = context->streams[i];
19294562236bSHarry Wentland 
19304562236bSHarry Wentland 		/* We are looking for non dp, non virtual stream */
19314562236bSHarry Wentland 		if (resource_are_streams_timing_synchronizable(
19324562236bSHarry Wentland 			stream_needs_pll, stream_has_pll)
19334562236bSHarry Wentland 			&& !dc_is_dp_signal(stream_has_pll->signal)
1934ceb3dbb4SJun Lei 			&& stream_has_pll->link->connector_signal
19354562236bSHarry Wentland 			!= SIGNAL_TYPE_VIRTUAL)
19364562236bSHarry Wentland 			return stream_has_pll;
1937ab2541b6SAric Cyr 
19384562236bSHarry Wentland 	}
19394562236bSHarry Wentland 
19404562236bSHarry Wentland 	return NULL;
19414562236bSHarry Wentland }
19424562236bSHarry Wentland 
19434562236bSHarry Wentland static int get_norm_pix_clk(const struct dc_crtc_timing *timing)
19444562236bSHarry Wentland {
1945380604e2SKen Chalmers 	uint32_t pix_clk = timing->pix_clk_100hz;
19464562236bSHarry Wentland 	uint32_t normalized_pix_clk = pix_clk;
19474562236bSHarry Wentland 
19484562236bSHarry Wentland 	if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR420)
19494562236bSHarry Wentland 		pix_clk /= 2;
1950cc4d99b8SCharlene Liu 	if (timing->pixel_encoding != PIXEL_ENCODING_YCBCR422) {
19514562236bSHarry Wentland 		switch (timing->display_color_depth) {
19528897810aSJulian Parkin 		case COLOR_DEPTH_666:
19534562236bSHarry Wentland 		case COLOR_DEPTH_888:
19544562236bSHarry Wentland 			normalized_pix_clk = pix_clk;
19554562236bSHarry Wentland 			break;
19564562236bSHarry Wentland 		case COLOR_DEPTH_101010:
19574562236bSHarry Wentland 			normalized_pix_clk = (pix_clk * 30) / 24;
19584562236bSHarry Wentland 			break;
19594562236bSHarry Wentland 		case COLOR_DEPTH_121212:
19604562236bSHarry Wentland 			normalized_pix_clk = (pix_clk * 36) / 24;
19614562236bSHarry Wentland 		break;
19624562236bSHarry Wentland 		case COLOR_DEPTH_161616:
19634562236bSHarry Wentland 			normalized_pix_clk = (pix_clk * 48) / 24;
19644562236bSHarry Wentland 		break;
19654562236bSHarry Wentland 		default:
19664562236bSHarry Wentland 			ASSERT(0);
19674562236bSHarry Wentland 		break;
19684562236bSHarry Wentland 		}
1969cc4d99b8SCharlene Liu 	}
19704562236bSHarry Wentland 	return normalized_pix_clk;
19714562236bSHarry Wentland }
19724562236bSHarry Wentland 
19730971c40eSHarry Wentland static void calculate_phy_pix_clks(struct dc_stream_state *stream)
19744562236bSHarry Wentland {
19754562236bSHarry Wentland 	/* update actual pixel clock on all streams */
19764562236bSHarry Wentland 	if (dc_is_hdmi_signal(stream->signal))
19774562236bSHarry Wentland 		stream->phy_pix_clk = get_norm_pix_clk(
1978380604e2SKen Chalmers 			&stream->timing) / 10;
19794562236bSHarry Wentland 	else
19804562236bSHarry Wentland 		stream->phy_pix_clk =
1981380604e2SKen Chalmers 			stream->timing.pix_clk_100hz / 10;
198239c03e00SCharlene Liu 
198339c03e00SCharlene Liu 	if (stream->timing.timing_3d_format == TIMING_3D_FORMAT_HW_FRAME_PACKING)
198439c03e00SCharlene Liu 		stream->phy_pix_clk *= 2;
19854562236bSHarry Wentland }
19864562236bSHarry Wentland 
1987d2d7885fSAnthony Koo static int acquire_resource_from_hw_enabled_state(
1988d2d7885fSAnthony Koo 		struct resource_context *res_ctx,
1989d2d7885fSAnthony Koo 		const struct resource_pool *pool,
1990d2d7885fSAnthony Koo 		struct dc_stream_state *stream)
1991d2d7885fSAnthony Koo {
1992d2d7885fSAnthony Koo 	struct dc_link *link = stream->link;
199308b66279SMartin Leung 	unsigned int i, inst, tg_inst = 0;
1994d2d7885fSAnthony Koo 
1995d2d7885fSAnthony Koo 	/* Check for enabled DIG to identify enabled display */
1996d2d7885fSAnthony Koo 	if (!link->link_enc->funcs->is_dig_enabled(link->link_enc))
1997d2d7885fSAnthony Koo 		return -1;
1998d2d7885fSAnthony Koo 
19995ec43edaSMartin Leung 	inst = link->link_enc->funcs->get_dig_frontend(link->link_enc);
2000d2d7885fSAnthony Koo 
20017f7652eeSMartin Leung 	if (inst == ENGINE_ID_UNKNOWN)
200275441d9dSMikita Lipski 		return -1;
2003d2d7885fSAnthony Koo 
20047f7652eeSMartin Leung 	for (i = 0; i < pool->stream_enc_count; i++) {
20057f7652eeSMartin Leung 		if (pool->stream_enc[i]->id == inst) {
20067f7652eeSMartin Leung 			tg_inst = pool->stream_enc[i]->funcs->dig_source_otg(
20077f7652eeSMartin Leung 				pool->stream_enc[i]);
20087f7652eeSMartin Leung 			break;
20097f7652eeSMartin Leung 		}
20107f7652eeSMartin Leung 	}
2011d2d7885fSAnthony Koo 
20127f7652eeSMartin Leung 	// tg_inst not found
20137f7652eeSMartin Leung 	if (i == pool->stream_enc_count)
201475441d9dSMikita Lipski 		return -1;
20155ec43edaSMartin Leung 
20165ec43edaSMartin Leung 	if (tg_inst >= pool->timing_generator_count)
201775441d9dSMikita Lipski 		return -1;
20185ec43edaSMartin Leung 
20195ec43edaSMartin Leung 	if (!res_ctx->pipe_ctx[tg_inst].stream) {
20205ec43edaSMartin Leung 		struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[tg_inst];
20215ec43edaSMartin Leung 
20225ec43edaSMartin Leung 		pipe_ctx->stream_res.tg = pool->timing_generators[tg_inst];
20235ec43edaSMartin Leung 		pipe_ctx->plane_res.mi = pool->mis[tg_inst];
20245ec43edaSMartin Leung 		pipe_ctx->plane_res.hubp = pool->hubps[tg_inst];
20255ec43edaSMartin Leung 		pipe_ctx->plane_res.ipp = pool->ipps[tg_inst];
20265ec43edaSMartin Leung 		pipe_ctx->plane_res.xfm = pool->transforms[tg_inst];
20275ec43edaSMartin Leung 		pipe_ctx->plane_res.dpp = pool->dpps[tg_inst];
20285ec43edaSMartin Leung 		pipe_ctx->stream_res.opp = pool->opps[tg_inst];
20295ec43edaSMartin Leung 
2030ccce745cSMartin Leung 		if (pool->dpps[tg_inst]) {
20315ec43edaSMartin Leung 			pipe_ctx->plane_res.mpcc_inst = pool->dpps[tg_inst]->inst;
2032ccce745cSMartin Leung 
2033ccce745cSMartin Leung 			// Read DPP->MPCC->OPP Pipe from HW State
2034ccce745cSMartin Leung 			if (pool->mpc->funcs->read_mpcc_state) {
2035ccce745cSMartin Leung 				struct mpcc_state s = {0};
2036ccce745cSMartin Leung 
2037ccce745cSMartin Leung 				pool->mpc->funcs->read_mpcc_state(pool->mpc, pipe_ctx->plane_res.mpcc_inst, &s);
2038ccce745cSMartin Leung 
2039ccce745cSMartin Leung 				if (s.dpp_id < MAX_MPCC)
2040ccce745cSMartin Leung 					pool->mpc->mpcc_array[pipe_ctx->plane_res.mpcc_inst].dpp_id = s.dpp_id;
2041ccce745cSMartin Leung 
2042ccce745cSMartin Leung 				if (s.bot_mpcc_id < MAX_MPCC)
2043ccce745cSMartin Leung 					pool->mpc->mpcc_array[pipe_ctx->plane_res.mpcc_inst].mpcc_bot =
2044ccce745cSMartin Leung 							&pool->mpc->mpcc_array[s.bot_mpcc_id];
2045ccce745cSMartin Leung 
2046ccce745cSMartin Leung 				if (s.opp_id < MAX_OPP)
2047ccce745cSMartin Leung 					pipe_ctx->stream_res.opp->mpc_tree_params.opp_id = s.opp_id;
2048ccce745cSMartin Leung 			}
2049ccce745cSMartin Leung 		}
20505ec43edaSMartin Leung 		pipe_ctx->pipe_idx = tg_inst;
2051d2d7885fSAnthony Koo 
2052d2d7885fSAnthony Koo 		pipe_ctx->stream = stream;
20535ec43edaSMartin Leung 		return tg_inst;
2054d2d7885fSAnthony Koo 	}
2055d2d7885fSAnthony Koo 
2056d2d7885fSAnthony Koo 	return -1;
2057d2d7885fSAnthony Koo }
2058d2d7885fSAnthony Koo 
205996b5e3e1SRaymond Yang static void mark_seamless_boot_stream(
206096b5e3e1SRaymond Yang 		const struct dc  *dc,
206196b5e3e1SRaymond Yang 		struct dc_stream_state *stream)
206296b5e3e1SRaymond Yang {
206396b5e3e1SRaymond Yang 	struct dc_bios *dcb = dc->ctx->dc_bios;
206496b5e3e1SRaymond Yang 
206596b5e3e1SRaymond Yang 	/* TODO: Check Linux */
206696b5e3e1SRaymond Yang 	if (dc->config.allow_seamless_boot_optimization &&
206796b5e3e1SRaymond Yang 			!dcb->funcs->is_accelerated_mode(dcb)) {
206896b5e3e1SRaymond Yang 		if (dc_validate_seamless_boot_timing(dc, stream->sink, &stream->timing))
206996b5e3e1SRaymond Yang 			stream->apply_seamless_boot_optimization = true;
207096b5e3e1SRaymond Yang 	}
207196b5e3e1SRaymond Yang }
207296b5e3e1SRaymond Yang 
20734562236bSHarry Wentland enum dc_status resource_map_pool_resources(
2074fb3466a4SBhawanpreet Lakha 		const struct dc  *dc,
2075608ac7bbSJerry Zuo 		struct dc_state *context,
20761dc90497SAndrey Grodzovsky 		struct dc_stream_state *stream)
20774562236bSHarry Wentland {
2078a2b8659dSTony Cheng 	const struct resource_pool *pool = dc->res_pool;
20791dc90497SAndrey Grodzovsky 	int i;
20801dc90497SAndrey Grodzovsky 	struct dc_context *dc_ctx = dc->ctx;
20811dc90497SAndrey Grodzovsky 	struct pipe_ctx *pipe_ctx = NULL;
20821dc90497SAndrey Grodzovsky 	int pipe_idx = -1;
20834562236bSHarry Wentland 
208408e1c28dSYogesh Mohan Marimuthu 	calculate_phy_pix_clks(stream);
208508e1c28dSYogesh Mohan Marimuthu 
208696b5e3e1SRaymond Yang 	mark_seamless_boot_stream(dc, stream);
208746570f09SAnthony Koo 
208896b5e3e1SRaymond Yang 	if (stream->apply_seamless_boot_optimization) {
2089d2d7885fSAnthony Koo 		pipe_idx = acquire_resource_from_hw_enabled_state(
2090d2d7885fSAnthony Koo 				&context->res_ctx,
2091d2d7885fSAnthony Koo 				pool,
2092d2d7885fSAnthony Koo 				stream);
209396b5e3e1SRaymond Yang 		if (pipe_idx < 0)
209496b5e3e1SRaymond Yang 			/* hw resource was assigned to other stream */
209596b5e3e1SRaymond Yang 			stream->apply_seamless_boot_optimization = false;
209696b5e3e1SRaymond Yang 	}
2097d2d7885fSAnthony Koo 
2098d2d7885fSAnthony Koo 	if (pipe_idx < 0)
20994562236bSHarry Wentland 		/* acquire new resources */
21005d11e9fcSDmytro Laktyushkin 		pipe_idx = acquire_first_free_pipe(&context->res_ctx, pool, stream);
21011dc90497SAndrey Grodzovsky 
2102b86a1aa3SBhawanpreet Lakha #ifdef CONFIG_DRM_AMD_DC_DCN
21035d11e9fcSDmytro Laktyushkin 	if (pipe_idx < 0)
210413ab1b44SYongqiang Sun 		pipe_idx = acquire_first_split_pipe(&context->res_ctx, pool, stream);
210594c6d735SHarry Wentland #endif
210613ab1b44SYongqiang Sun 
2107c5b38aecSDmytro Laktyushkin 	if (pipe_idx < 0 || context->res_ctx.pipe_ctx[pipe_idx].stream_res.tg == NULL)
21084562236bSHarry Wentland 		return DC_NO_CONTROLLER_RESOURCE;
21094562236bSHarry Wentland 
21104562236bSHarry Wentland 	pipe_ctx = &context->res_ctx.pipe_ctx[pipe_idx];
21114562236bSHarry Wentland 
21128e9c4c8cSHarry Wentland 	pipe_ctx->stream_res.stream_enc =
211378cc70b1SWesley Chalmers 		dc->res_pool->funcs->find_first_free_match_stream_enc_for_link(
2114a2b8659dSTony Cheng 			&context->res_ctx, pool, stream);
21154562236bSHarry Wentland 
21168e9c4c8cSHarry Wentland 	if (!pipe_ctx->stream_res.stream_enc)
211738684e46SEric Bernstein 		return DC_NO_STREAM_ENC_RESOURCE;
21184562236bSHarry Wentland 
21191dc90497SAndrey Grodzovsky 	update_stream_engine_usage(
2120a2b8659dSTony Cheng 		&context->res_ctx, pool,
21211dc90497SAndrey Grodzovsky 		pipe_ctx->stream_res.stream_enc,
21221dc90497SAndrey Grodzovsky 		true);
21234562236bSHarry Wentland 
2124f01ee019SFangzhi Zuo #if defined(CONFIG_DRM_AMD_DC_DCN)
2125f01ee019SFangzhi Zuo 	/* Allocate DP HPO Stream Encoder based on signal, hw capabilities
2126f01ee019SFangzhi Zuo 	 * and link settings
2127f01ee019SFangzhi Zuo 	 */
2128f01ee019SFangzhi Zuo 	if (dc_is_dp_signal(stream->signal) &&
2129f01ee019SFangzhi Zuo 			dc->caps.dp_hpo) {
2130f01ee019SFangzhi Zuo 		struct dc_link_settings link_settings = {0};
2131f01ee019SFangzhi Zuo 
2132f01ee019SFangzhi Zuo 		decide_link_settings(stream, &link_settings);
2133f01ee019SFangzhi Zuo 		if (dp_get_link_encoding_format(&link_settings) == DP_128b_132b_ENCODING) {
2134f01ee019SFangzhi Zuo 			pipe_ctx->stream_res.hpo_dp_stream_enc =
2135f01ee019SFangzhi Zuo 					find_first_free_match_hpo_dp_stream_enc_for_link(
2136f01ee019SFangzhi Zuo 							&context->res_ctx, pool, stream);
2137f01ee019SFangzhi Zuo 
2138f01ee019SFangzhi Zuo 			if (!pipe_ctx->stream_res.hpo_dp_stream_enc)
2139f01ee019SFangzhi Zuo 				return DC_NO_STREAM_ENC_RESOURCE;
2140f01ee019SFangzhi Zuo 
2141f01ee019SFangzhi Zuo 			update_hpo_dp_stream_engine_usage(
2142f01ee019SFangzhi Zuo 					&context->res_ctx, pool,
2143f01ee019SFangzhi Zuo 					pipe_ctx->stream_res.hpo_dp_stream_enc,
2144f01ee019SFangzhi Zuo 					true);
2145f01ee019SFangzhi Zuo 		}
2146f01ee019SFangzhi Zuo 	}
2147f01ee019SFangzhi Zuo #endif
2148f01ee019SFangzhi Zuo 
21494562236bSHarry Wentland 	/* TODO: Add check if ASIC support and EDID audio */
2150ceb3dbb4SJun Lei 	if (!stream->converter_disable_audio &&
21514562236bSHarry Wentland 	    dc_is_audio_capable_signal(pipe_ctx->stream->signal) &&
2152ce08aad3SAlvin Lee 	    stream->audio_info.mode_count && stream->audio_info.flags.all) {
2153afaacef4SHarry Wentland 		pipe_ctx->stream_res.audio = find_first_free_audio(
2154f24b0522SPaul Hsieh 		&context->res_ctx, pool, pipe_ctx->stream_res.stream_enc->id, dc_ctx->dce_version);
21554562236bSHarry Wentland 
21564562236bSHarry Wentland 		/*
21574562236bSHarry Wentland 		 * Audio assigned in order first come first get.
21584562236bSHarry Wentland 		 * There are asics which has number of audio
21594562236bSHarry Wentland 		 * resources less then number of pipes
21604562236bSHarry Wentland 		 */
2161afaacef4SHarry Wentland 		if (pipe_ctx->stream_res.audio)
21621dc90497SAndrey Grodzovsky 			update_audio_usage(&context->res_ctx, pool,
21631dc90497SAndrey Grodzovsky 					   pipe_ctx->stream_res.audio, true);
21644562236bSHarry Wentland 	}
21654562236bSHarry Wentland 
21669aef1a31SSivapiriyanKumarasamy 	/* Add ABM to the resource if on EDP */
21675dba4991SBhawanpreet Lakha 	if (pipe_ctx->stream && dc_is_embedded_signal(pipe_ctx->stream->signal)) {
216820f2ffe5SAlex Deucher #if defined(CONFIG_DRM_AMD_DC_DCN)
21695dba4991SBhawanpreet Lakha 		if (pool->abm)
21709aef1a31SSivapiriyanKumarasamy 			pipe_ctx->stream_res.abm = pool->abm;
21715dba4991SBhawanpreet Lakha 		else
21725dba4991SBhawanpreet Lakha 			pipe_ctx->stream_res.abm = pool->multiple_abms[pipe_ctx->stream_res.tg->inst];
21735dba4991SBhawanpreet Lakha #else
21745dba4991SBhawanpreet Lakha 		pipe_ctx->stream_res.abm = pool->abm;
21755dba4991SBhawanpreet Lakha #endif
21765dba4991SBhawanpreet Lakha 	}
21779aef1a31SSivapiriyanKumarasamy 
21781dc90497SAndrey Grodzovsky 	for (i = 0; i < context->stream_count; i++)
21791dc90497SAndrey Grodzovsky 		if (context->streams[i] == stream) {
21806b670fa9SHarry Wentland 			context->stream_status[i].primary_otg_inst = pipe_ctx->stream_res.tg->inst;
21813f0940f8SCharlene Liu 			context->stream_status[i].stream_enc_inst = pipe_ctx->stream_res.stream_enc->stream_enc_inst;
21825fdb7c4cSNicholas Kazlauskas 			context->stream_status[i].audio_inst =
21835fdb7c4cSNicholas Kazlauskas 				pipe_ctx->stream_res.audio ? pipe_ctx->stream_res.audio->inst : -1;
21845fdb7c4cSNicholas Kazlauskas 
21851dc90497SAndrey Grodzovsky 			return DC_OK;
21864562236bSHarry Wentland 		}
21874562236bSHarry Wentland 
21881dc90497SAndrey Grodzovsky 	DC_ERROR("Stream %p not found in new ctx!\n", stream);
21891dc90497SAndrey Grodzovsky 	return DC_ERROR_UNEXPECTED;
21904562236bSHarry Wentland }
21914562236bSHarry Wentland 
21922119aa17SDavid Francis /**
21932119aa17SDavid Francis  * dc_resource_state_copy_construct_current() - Creates a new dc_state from existing state
21942119aa17SDavid Francis  * Is a shallow copy.  Increments refcounts on existing streams and planes.
21952119aa17SDavid Francis  * @dc: copy out of dc->current_state
21962119aa17SDavid Francis  * @dst_ctx: copy into this
21972119aa17SDavid Francis  */
2198f36cc577SBhawanpreet Lakha void dc_resource_state_copy_construct_current(
21991dc90497SAndrey Grodzovsky 		const struct dc *dc,
2200608ac7bbSJerry Zuo 		struct dc_state *dst_ctx)
22011dc90497SAndrey Grodzovsky {
2202f36cc577SBhawanpreet Lakha 	dc_resource_state_copy_construct(dc->current_state, dst_ctx);
22031dc90497SAndrey Grodzovsky }
22041dc90497SAndrey Grodzovsky 
2205ab8db3e1SAndrey Grodzovsky 
2206ab8db3e1SAndrey Grodzovsky void dc_resource_state_construct(
2207ab8db3e1SAndrey Grodzovsky 		const struct dc *dc,
2208ab8db3e1SAndrey Grodzovsky 		struct dc_state *dst_ctx)
2209ab8db3e1SAndrey Grodzovsky {
2210dc88b4a6SEric Yang 	dst_ctx->clk_mgr = dc->clk_mgr;
2211ab8db3e1SAndrey Grodzovsky }
2212ab8db3e1SAndrey Grodzovsky 
22136d822156SNikola Cornij 
22146d822156SNikola Cornij bool dc_resource_is_dsc_encoding_supported(const struct dc *dc)
22156d822156SNikola Cornij {
22166d822156SNikola Cornij 	return dc->res_pool->res_cap->num_dsc > 0;
22176d822156SNikola Cornij }
22186d822156SNikola Cornij 
22196d822156SNikola Cornij 
22202119aa17SDavid Francis /**
22212119aa17SDavid Francis  * dc_validate_global_state() - Determine if HW can support a given state
22222119aa17SDavid Francis  * Checks HW resource availability and bandwidth requirement.
22232119aa17SDavid Francis  * @dc: dc struct for this driver
22242119aa17SDavid Francis  * @new_ctx: state to be validated
2225afcd526bSJoshua Aberback  * @fast_validate: set to true if only yes/no to support matters
22262119aa17SDavid Francis  *
22272119aa17SDavid Francis  * Return: DC_OK if the result can be programmed.  Otherwise, an error code.
22282119aa17SDavid Francis  */
2229e750d56dSYongqiang Sun enum dc_status dc_validate_global_state(
22301dc90497SAndrey Grodzovsky 		struct dc *dc,
2231afcd526bSJoshua Aberback 		struct dc_state *new_ctx,
2232afcd526bSJoshua Aberback 		bool fast_validate)
22331dc90497SAndrey Grodzovsky {
22341dc90497SAndrey Grodzovsky 	enum dc_status result = DC_ERROR_UNEXPECTED;
22351dc90497SAndrey Grodzovsky 	int i, j;
22361dc90497SAndrey Grodzovsky 
2237e41ab030SHarry Wentland 	if (!new_ctx)
2238e41ab030SHarry Wentland 		return DC_ERROR_UNEXPECTED;
22398fe44c08SAlex Deucher #if defined(CONFIG_DRM_AMD_DC_DCN)
2240cbaf919fSNicholas Kazlauskas 
2241cbaf919fSNicholas Kazlauskas 	/*
2242cbaf919fSNicholas Kazlauskas 	 * Update link encoder to stream assignment.
2243cbaf919fSNicholas Kazlauskas 	 * TODO: Split out reason allocation from validation.
2244cbaf919fSNicholas Kazlauskas 	 */
2245b3492ed1SJimmy Kizito 	if (dc->res_pool->funcs->link_encs_assign && fast_validate == false)
2246cbaf919fSNicholas Kazlauskas 		dc->res_pool->funcs->link_encs_assign(
2247cbaf919fSNicholas Kazlauskas 			dc, new_ctx, new_ctx->streams, new_ctx->stream_count);
2248cbaf919fSNicholas Kazlauskas #endif
2249e41ab030SHarry Wentland 
2250d596e5d0SYongqiang Sun 	if (dc->res_pool->funcs->validate_global) {
2251d596e5d0SYongqiang Sun 		result = dc->res_pool->funcs->validate_global(dc, new_ctx);
2252d596e5d0SYongqiang Sun 		if (result != DC_OK)
2253d596e5d0SYongqiang Sun 			return result;
2254d596e5d0SYongqiang Sun 	}
22551dc90497SAndrey Grodzovsky 
2256e41ab030SHarry Wentland 	for (i = 0; i < new_ctx->stream_count; i++) {
22571dc90497SAndrey Grodzovsky 		struct dc_stream_state *stream = new_ctx->streams[i];
22581dc90497SAndrey Grodzovsky 
22591dc90497SAndrey Grodzovsky 		for (j = 0; j < dc->res_pool->pipe_count; j++) {
22601dc90497SAndrey Grodzovsky 			struct pipe_ctx *pipe_ctx = &new_ctx->res_ctx.pipe_ctx[j];
22611dc90497SAndrey Grodzovsky 
22621dc90497SAndrey Grodzovsky 			if (pipe_ctx->stream != stream)
22631dc90497SAndrey Grodzovsky 				continue;
22641dc90497SAndrey Grodzovsky 
22658d8c82b6SJoseph Gravenor 			if (dc->res_pool->funcs->patch_unknown_plane_state &&
226674eac5f3SSu Sung Chung 					pipe_ctx->plane_state &&
226774eac5f3SSu Sung Chung 					pipe_ctx->plane_state->tiling_info.gfx9.swizzle == DC_SW_UNKNOWN) {
22688d8c82b6SJoseph Gravenor 				result = dc->res_pool->funcs->patch_unknown_plane_state(pipe_ctx->plane_state);
226974eac5f3SSu Sung Chung 				if (result != DC_OK)
227074eac5f3SSu Sung Chung 					return result;
227174eac5f3SSu Sung Chung 			}
227274eac5f3SSu Sung Chung 
22731dc90497SAndrey Grodzovsky 			/* Switch to dp clock source only if there is
22741dc90497SAndrey Grodzovsky 			 * no non dp stream that shares the same timing
22751dc90497SAndrey Grodzovsky 			 * with the dp stream.
22761dc90497SAndrey Grodzovsky 			 */
22771dc90497SAndrey Grodzovsky 			if (dc_is_dp_signal(pipe_ctx->stream->signal) &&
22781dc90497SAndrey Grodzovsky 				!find_pll_sharable_stream(stream, new_ctx)) {
22791dc90497SAndrey Grodzovsky 
22809d0dcecdSHarry Wentland 				resource_unreference_clock_source(
22811dc90497SAndrey Grodzovsky 						&new_ctx->res_ctx,
22821dc90497SAndrey Grodzovsky 						dc->res_pool,
22839d0dcecdSHarry Wentland 						pipe_ctx->clock_source);
22844a629536SHarry Wentland 
22851dc90497SAndrey Grodzovsky 				pipe_ctx->clock_source = dc->res_pool->dp_clock_source;
22861dc90497SAndrey Grodzovsky 				resource_reference_clock_source(
22871dc90497SAndrey Grodzovsky 						&new_ctx->res_ctx,
22881dc90497SAndrey Grodzovsky 						dc->res_pool,
22891dc90497SAndrey Grodzovsky 						 pipe_ctx->clock_source);
22901dc90497SAndrey Grodzovsky 			}
22911dc90497SAndrey Grodzovsky 		}
22921dc90497SAndrey Grodzovsky 	}
22931dc90497SAndrey Grodzovsky 
22941dc90497SAndrey Grodzovsky 	result = resource_build_scaling_params_for_context(dc, new_ctx);
22951dc90497SAndrey Grodzovsky 
22961dc90497SAndrey Grodzovsky 	if (result == DC_OK)
2297afcd526bSJoshua Aberback 		if (!dc->res_pool->funcs->validate_bandwidth(dc, new_ctx, fast_validate))
22981dc90497SAndrey Grodzovsky 			result = DC_FAIL_BANDWIDTH_VALIDATE;
22991dc90497SAndrey Grodzovsky 
23001dc90497SAndrey Grodzovsky 	return result;
23011dc90497SAndrey Grodzovsky }
23021dc90497SAndrey Grodzovsky 
23036e4d6beeSTony Cheng static void patch_gamut_packet_checksum(
2304e09b6473SAnthony Koo 		struct dc_info_packet *gamut_packet)
23054562236bSHarry Wentland {
23064562236bSHarry Wentland 	/* For gamut we recalc checksum */
23076e4d6beeSTony Cheng 	if (gamut_packet->valid) {
23084562236bSHarry Wentland 		uint8_t chk_sum = 0;
23094562236bSHarry Wentland 		uint8_t *ptr;
23104562236bSHarry Wentland 		uint8_t i;
23114562236bSHarry Wentland 
23124562236bSHarry Wentland 		/*start of the Gamut data. */
23136e4d6beeSTony Cheng 		ptr = &gamut_packet->sb[3];
23144562236bSHarry Wentland 
23156e4d6beeSTony Cheng 		for (i = 0; i <= gamut_packet->sb[1]; i++)
23164562236bSHarry Wentland 			chk_sum += ptr[i];
23174562236bSHarry Wentland 
23186e4d6beeSTony Cheng 		gamut_packet->sb[2] = (uint8_t) (0x100 - chk_sum);
23191646a6feSAndrew Wong 	}
23204562236bSHarry Wentland }
23214562236bSHarry Wentland 
23224562236bSHarry Wentland static void set_avi_info_frame(
2323e09b6473SAnthony Koo 		struct dc_info_packet *info_packet,
23244562236bSHarry Wentland 		struct pipe_ctx *pipe_ctx)
23254562236bSHarry Wentland {
23260971c40eSHarry Wentland 	struct dc_stream_state *stream = pipe_ctx->stream;
23274562236bSHarry Wentland 	enum dc_color_space color_space = COLOR_SPACE_UNKNOWN;
23284562236bSHarry Wentland 	uint32_t pixel_encoding = 0;
23294562236bSHarry Wentland 	enum scanning_type scan_type = SCANNING_TYPE_NODATA;
23304562236bSHarry Wentland 	enum dc_aspect_ratio aspect = ASPECT_RATIO_NO_DATA;
23314562236bSHarry Wentland 	bool itc = false;
233250e27654SZeyu Fan 	uint8_t itc_value = 0;
23334562236bSHarry Wentland 	uint8_t cn0_cn1 = 0;
233450e27654SZeyu Fan 	unsigned int cn0_cn1_value = 0;
23354562236bSHarry Wentland 	uint8_t *check_sum = NULL;
23364562236bSHarry Wentland 	uint8_t byte_index = 0;
2337754e3673SAnthony Koo 	union hdmi_info_packet hdmi_info;
233850e27654SZeyu Fan 	union display_content_support support = {0};
23394fa086b9SLeo (Sunpeng) Li 	unsigned int vic = pipe_ctx->stream->timing.vic;
234015e17335SCharlene Liu 	enum dc_timing_3d_format format;
23414562236bSHarry Wentland 
2342754e3673SAnthony Koo 	memset(&hdmi_info, 0, sizeof(union hdmi_info_packet));
2343754e3673SAnthony Koo 
23444fa086b9SLeo (Sunpeng) Li 	color_space = pipe_ctx->stream->output_color_space;
2345e5f2038eSCharlene Liu 	if (color_space == COLOR_SPACE_UNKNOWN)
23464fa086b9SLeo (Sunpeng) Li 		color_space = (stream->timing.pixel_encoding == PIXEL_ENCODING_RGB) ?
2347e5f2038eSCharlene Liu 			COLOR_SPACE_SRGB:COLOR_SPACE_YCBCR709;
23484562236bSHarry Wentland 
23494562236bSHarry Wentland 	/* Initialize header */
2350e09b6473SAnthony Koo 	hdmi_info.bits.header.info_frame_type = HDMI_INFOFRAME_TYPE_AVI;
23514562236bSHarry Wentland 	/* InfoFrameVersion_3 is defined by CEA861F (Section 6.4), but shall
23524562236bSHarry Wentland 	* not be used in HDMI 2.0 (Section 10.1) */
2353e09b6473SAnthony Koo 	hdmi_info.bits.header.version = 2;
2354e09b6473SAnthony Koo 	hdmi_info.bits.header.length = HDMI_AVI_INFOFRAME_SIZE;
23554562236bSHarry Wentland 
23564562236bSHarry Wentland 	/*
23574562236bSHarry Wentland 	 * IDO-defined (Y2,Y1,Y0 = 1,1,1) shall not be used by devices built
23584562236bSHarry Wentland 	 * according to HDMI 2.0 spec (Section 10.1)
23594562236bSHarry Wentland 	 */
23604562236bSHarry Wentland 
23614fa086b9SLeo (Sunpeng) Li 	switch (stream->timing.pixel_encoding) {
23624562236bSHarry Wentland 	case PIXEL_ENCODING_YCBCR422:
23634562236bSHarry Wentland 		pixel_encoding = 1;
23644562236bSHarry Wentland 		break;
23654562236bSHarry Wentland 
23664562236bSHarry Wentland 	case PIXEL_ENCODING_YCBCR444:
23674562236bSHarry Wentland 		pixel_encoding = 2;
23684562236bSHarry Wentland 		break;
23694562236bSHarry Wentland 	case PIXEL_ENCODING_YCBCR420:
23704562236bSHarry Wentland 		pixel_encoding = 3;
23714562236bSHarry Wentland 		break;
23724562236bSHarry Wentland 
23734562236bSHarry Wentland 	case PIXEL_ENCODING_RGB:
23744562236bSHarry Wentland 	default:
23754562236bSHarry Wentland 		pixel_encoding = 0;
23764562236bSHarry Wentland 	}
23774562236bSHarry Wentland 
23784562236bSHarry Wentland 	/* Y0_Y1_Y2 : The pixel encoding */
23794562236bSHarry Wentland 	/* H14b AVI InfoFrame has extension on Y-field from 2 bits to 3 bits */
2380e09b6473SAnthony Koo 	hdmi_info.bits.Y0_Y1_Y2 = pixel_encoding;
23814562236bSHarry Wentland 
23824562236bSHarry Wentland 	/* A0 = 1 Active Format Information valid */
2383e09b6473SAnthony Koo 	hdmi_info.bits.A0 = ACTIVE_FORMAT_VALID;
23844562236bSHarry Wentland 
23854562236bSHarry Wentland 	/* B0, B1 = 3; Bar info data is valid */
2386e09b6473SAnthony Koo 	hdmi_info.bits.B0_B1 = BAR_INFO_BOTH_VALID;
23874562236bSHarry Wentland 
2388e09b6473SAnthony Koo 	hdmi_info.bits.SC0_SC1 = PICTURE_SCALING_UNIFORM;
23894562236bSHarry Wentland 
23904562236bSHarry Wentland 	/* S0, S1 : Underscan / Overscan */
23914562236bSHarry Wentland 	/* TODO: un-hardcode scan type */
23924562236bSHarry Wentland 	scan_type = SCANNING_TYPE_UNDERSCAN;
2393e09b6473SAnthony Koo 	hdmi_info.bits.S0_S1 = scan_type;
23944562236bSHarry Wentland 
23954562236bSHarry Wentland 	/* C0, C1 : Colorimetry */
23968fde5884SCharlene Liu 	if (color_space == COLOR_SPACE_YCBCR709 ||
239715e17335SCharlene Liu 			color_space == COLOR_SPACE_YCBCR709_LIMITED)
2398e09b6473SAnthony Koo 		hdmi_info.bits.C0_C1 = COLORIMETRY_ITU709;
23998fde5884SCharlene Liu 	else if (color_space == COLOR_SPACE_YCBCR601 ||
24008fde5884SCharlene Liu 			color_space == COLOR_SPACE_YCBCR601_LIMITED)
2401e09b6473SAnthony Koo 		hdmi_info.bits.C0_C1 = COLORIMETRY_ITU601;
24028fde5884SCharlene Liu 	else {
2403e09b6473SAnthony Koo 		hdmi_info.bits.C0_C1 = COLORIMETRY_NO_DATA;
24048fde5884SCharlene Liu 	}
2405534db198SAmy Zhang 	if (color_space == COLOR_SPACE_2020_RGB_FULLRANGE ||
2406534db198SAmy Zhang 			color_space == COLOR_SPACE_2020_RGB_LIMITEDRANGE ||
2407534db198SAmy Zhang 			color_space == COLOR_SPACE_2020_YCBCR) {
2408e09b6473SAnthony Koo 		hdmi_info.bits.EC0_EC2 = COLORIMETRYEX_BT2020RGBYCBCR;
2409e09b6473SAnthony Koo 		hdmi_info.bits.C0_C1   = COLORIMETRY_EXTENDED;
2410534db198SAmy Zhang 	} else if (color_space == COLOR_SPACE_ADOBERGB) {
2411e09b6473SAnthony Koo 		hdmi_info.bits.EC0_EC2 = COLORIMETRYEX_ADOBERGB;
2412e09b6473SAnthony Koo 		hdmi_info.bits.C0_C1   = COLORIMETRY_EXTENDED;
2413534db198SAmy Zhang 	}
2414534db198SAmy Zhang 
24154562236bSHarry Wentland 	/* TODO: un-hardcode aspect ratio */
24164fa086b9SLeo (Sunpeng) Li 	aspect = stream->timing.aspect_ratio;
24174562236bSHarry Wentland 
24184562236bSHarry Wentland 	switch (aspect) {
24194562236bSHarry Wentland 	case ASPECT_RATIO_4_3:
24204562236bSHarry Wentland 	case ASPECT_RATIO_16_9:
2421e09b6473SAnthony Koo 		hdmi_info.bits.M0_M1 = aspect;
24224562236bSHarry Wentland 		break;
24234562236bSHarry Wentland 
24244562236bSHarry Wentland 	case ASPECT_RATIO_NO_DATA:
24254562236bSHarry Wentland 	case ASPECT_RATIO_64_27:
24264562236bSHarry Wentland 	case ASPECT_RATIO_256_135:
24274562236bSHarry Wentland 	default:
2428e09b6473SAnthony Koo 		hdmi_info.bits.M0_M1 = 0;
24294562236bSHarry Wentland 	}
24304562236bSHarry Wentland 
24314562236bSHarry Wentland 	/* Active Format Aspect ratio - same as Picture Aspect Ratio. */
2432e09b6473SAnthony Koo 	hdmi_info.bits.R0_R3 = ACTIVE_FORMAT_ASPECT_RATIO_SAME_AS_PICTURE;
24334562236bSHarry Wentland 
24344562236bSHarry Wentland 	/* TODO: un-hardcode cn0_cn1 and itc */
243550e27654SZeyu Fan 
24364562236bSHarry Wentland 	cn0_cn1 = 0;
243750e27654SZeyu Fan 	cn0_cn1_value = 0;
243850e27654SZeyu Fan 
243950e27654SZeyu Fan 	itc = true;
244050e27654SZeyu Fan 	itc_value = 1;
244150e27654SZeyu Fan 
2442ceb3dbb4SJun Lei 	support = stream->content_support;
24434562236bSHarry Wentland 
24444562236bSHarry Wentland 	if (itc) {
244550e27654SZeyu Fan 		if (!support.bits.valid_content_type) {
244650e27654SZeyu Fan 			cn0_cn1_value = 0;
244750e27654SZeyu Fan 		} else {
244850e27654SZeyu Fan 			if (cn0_cn1 == DISPLAY_CONTENT_TYPE_GRAPHICS) {
244950e27654SZeyu Fan 				if (support.bits.graphics_content == 1) {
245050e27654SZeyu Fan 					cn0_cn1_value = 0;
245150e27654SZeyu Fan 				}
245250e27654SZeyu Fan 			} else if (cn0_cn1 == DISPLAY_CONTENT_TYPE_PHOTO) {
245350e27654SZeyu Fan 				if (support.bits.photo_content == 1) {
245450e27654SZeyu Fan 					cn0_cn1_value = 1;
245550e27654SZeyu Fan 				} else {
245650e27654SZeyu Fan 					cn0_cn1_value = 0;
245750e27654SZeyu Fan 					itc_value = 0;
245850e27654SZeyu Fan 				}
245950e27654SZeyu Fan 			} else if (cn0_cn1 == DISPLAY_CONTENT_TYPE_CINEMA) {
246050e27654SZeyu Fan 				if (support.bits.cinema_content == 1) {
246150e27654SZeyu Fan 					cn0_cn1_value = 2;
246250e27654SZeyu Fan 				} else {
246350e27654SZeyu Fan 					cn0_cn1_value = 0;
246450e27654SZeyu Fan 					itc_value = 0;
246550e27654SZeyu Fan 				}
246650e27654SZeyu Fan 			} else if (cn0_cn1 == DISPLAY_CONTENT_TYPE_GAME) {
246750e27654SZeyu Fan 				if (support.bits.game_content == 1) {
246850e27654SZeyu Fan 					cn0_cn1_value = 3;
246950e27654SZeyu Fan 				} else {
247050e27654SZeyu Fan 					cn0_cn1_value = 0;
247150e27654SZeyu Fan 					itc_value = 0;
247250e27654SZeyu Fan 				}
247350e27654SZeyu Fan 			}
247450e27654SZeyu Fan 		}
2475e09b6473SAnthony Koo 		hdmi_info.bits.CN0_CN1 = cn0_cn1_value;
2476e09b6473SAnthony Koo 		hdmi_info.bits.ITC = itc_value;
24774562236bSHarry Wentland 	}
24784562236bSHarry Wentland 
2479fdf7d4f5SDillon Varone 	if (stream->qs_bit == 1) {
2480fdf7d4f5SDillon Varone 		if (color_space == COLOR_SPACE_SRGB ||
2481fdf7d4f5SDillon Varone 			color_space == COLOR_SPACE_2020_RGB_FULLRANGE)
2482fdf7d4f5SDillon Varone 			hdmi_info.bits.Q0_Q1   = RGB_QUANTIZATION_FULL_RANGE;
2483fdf7d4f5SDillon Varone 		else if (color_space == COLOR_SPACE_SRGB_LIMITED ||
2484fdf7d4f5SDillon Varone 					color_space == COLOR_SPACE_2020_RGB_LIMITEDRANGE)
2485fdf7d4f5SDillon Varone 			hdmi_info.bits.Q0_Q1   = RGB_QUANTIZATION_LIMITED_RANGE;
2486fdf7d4f5SDillon Varone 		else
2487fdf7d4f5SDillon Varone 			hdmi_info.bits.Q0_Q1   = RGB_QUANTIZATION_DEFAULT_RANGE;
2488fdf7d4f5SDillon Varone 	} else
2489fdf7d4f5SDillon Varone 		hdmi_info.bits.Q0_Q1   = RGB_QUANTIZATION_DEFAULT_RANGE;
2490fdf7d4f5SDillon Varone 
24914562236bSHarry Wentland 	/* TODO : We should handle YCC quantization */
24924562236bSHarry Wentland 	/* but we do not have matrix calculation */
2493fdf7d4f5SDillon Varone 	if (stream->qy_bit == 1) {
249450e27654SZeyu Fan 		if (color_space == COLOR_SPACE_SRGB ||
2495fdf7d4f5SDillon Varone 			color_space == COLOR_SPACE_2020_RGB_FULLRANGE)
2496993dca3eSQingqing Zhuo 			hdmi_info.bits.YQ0_YQ1 = YYC_QUANTIZATION_LIMITED_RANGE;
2497fdf7d4f5SDillon Varone 		else if (color_space == COLOR_SPACE_SRGB_LIMITED ||
2498fdf7d4f5SDillon Varone 					color_space == COLOR_SPACE_2020_RGB_LIMITEDRANGE)
2499e09b6473SAnthony Koo 			hdmi_info.bits.YQ0_YQ1 = YYC_QUANTIZATION_LIMITED_RANGE;
2500fdf7d4f5SDillon Varone 		else
2501e09b6473SAnthony Koo 			hdmi_info.bits.YQ0_YQ1 = YYC_QUANTIZATION_LIMITED_RANGE;
2502fdf7d4f5SDillon Varone 	} else
2503e09b6473SAnthony Koo 		hdmi_info.bits.YQ0_YQ1 = YYC_QUANTIZATION_LIMITED_RANGE;
250450e27654SZeyu Fan 
250515e17335SCharlene Liu 	///VIC
25064fa086b9SLeo (Sunpeng) Li 	format = stream->timing.timing_3d_format;
250715e17335SCharlene Liu 	/*todo, add 3DStereo support*/
250815e17335SCharlene Liu 	if (format != TIMING_3D_FORMAT_NONE) {
250915e17335SCharlene Liu 		// Based on HDMI specs hdmi vic needs to be converted to cea vic when 3D is enabled
25104fa086b9SLeo (Sunpeng) Li 		switch (pipe_ctx->stream->timing.hdmi_vic) {
251115e17335SCharlene Liu 		case 1:
251215e17335SCharlene Liu 			vic = 95;
251315e17335SCharlene Liu 			break;
251415e17335SCharlene Liu 		case 2:
251515e17335SCharlene Liu 			vic = 94;
251615e17335SCharlene Liu 			break;
251715e17335SCharlene Liu 		case 3:
251815e17335SCharlene Liu 			vic = 93;
251915e17335SCharlene Liu 			break;
252015e17335SCharlene Liu 		case 4:
252115e17335SCharlene Liu 			vic = 98;
252215e17335SCharlene Liu 			break;
252315e17335SCharlene Liu 		default:
252415e17335SCharlene Liu 			break;
252515e17335SCharlene Liu 		}
252615e17335SCharlene Liu 	}
2527efa02336SChris Park 	/* If VIC >= 128, the Source shall use AVI InfoFrame Version 3*/
2528e09b6473SAnthony Koo 	hdmi_info.bits.VIC0_VIC7 = vic;
2529efa02336SChris Park 	if (vic >= 128)
2530efa02336SChris Park 		hdmi_info.bits.header.version = 3;
2531efa02336SChris Park 	/* If (C1, C0)=(1, 1) and (EC2, EC1, EC0)=(1, 1, 1),
2532efa02336SChris Park 	 * the Source shall use 20 AVI InfoFrame Version 4
2533efa02336SChris Park 	 */
2534efa02336SChris Park 	if (hdmi_info.bits.C0_C1 == COLORIMETRY_EXTENDED &&
2535efa02336SChris Park 			hdmi_info.bits.EC0_EC2 == COLORIMETRYEX_RESERVED) {
2536efa02336SChris Park 		hdmi_info.bits.header.version = 4;
2537efa02336SChris Park 		hdmi_info.bits.header.length = 14;
2538efa02336SChris Park 	}
25394562236bSHarry Wentland 
25404562236bSHarry Wentland 	/* pixel repetition
25414562236bSHarry Wentland 	 * PR0 - PR3 start from 0 whereas pHwPathMode->mode.timing.flags.pixel
25424562236bSHarry Wentland 	 * repetition start from 1 */
2543e09b6473SAnthony Koo 	hdmi_info.bits.PR0_PR3 = 0;
25444562236bSHarry Wentland 
25454562236bSHarry Wentland 	/* Bar Info
25464562236bSHarry Wentland 	 * barTop:    Line Number of End of Top Bar.
25474562236bSHarry Wentland 	 * barBottom: Line Number of Start of Bottom Bar.
25484562236bSHarry Wentland 	 * barLeft:   Pixel Number of End of Left Bar.
25494562236bSHarry Wentland 	 * barRight:  Pixel Number of Start of Right Bar. */
2550e09b6473SAnthony Koo 	hdmi_info.bits.bar_top = stream->timing.v_border_top;
2551e09b6473SAnthony Koo 	hdmi_info.bits.bar_bottom = (stream->timing.v_total
25524fa086b9SLeo (Sunpeng) Li 			- stream->timing.v_border_bottom + 1);
2553e09b6473SAnthony Koo 	hdmi_info.bits.bar_left  = stream->timing.h_border_left;
2554e09b6473SAnthony Koo 	hdmi_info.bits.bar_right = (stream->timing.h_total
25554fa086b9SLeo (Sunpeng) Li 			- stream->timing.h_border_right + 1);
25564562236bSHarry Wentland 
25572f482c4fSChris Park     /* Additional Colorimetry Extension
25582f482c4fSChris Park      * Used in conduction with C0-C1 and EC0-EC2
25592f482c4fSChris Park      * 0 = DCI-P3 RGB (D65)
25602f482c4fSChris Park      * 1 = DCI-P3 RGB (theater)
25612f482c4fSChris Park      */
25622f482c4fSChris Park 	hdmi_info.bits.ACE0_ACE3 = 0;
25632f482c4fSChris Park 
25644562236bSHarry Wentland 	/* check_sum - Calculate AFMT_AVI_INFO0 ~ AFMT_AVI_INFO3 */
2565e09b6473SAnthony Koo 	check_sum = &hdmi_info.packet_raw_data.sb[0];
2566e8d726b7SReza Amini 
2567efa02336SChris Park 	*check_sum = HDMI_INFOFRAME_TYPE_AVI + hdmi_info.bits.header.length + hdmi_info.bits.header.version;
25684562236bSHarry Wentland 
2569efa02336SChris Park 	for (byte_index = 1; byte_index <= hdmi_info.bits.header.length; byte_index++)
2570e09b6473SAnthony Koo 		*check_sum += hdmi_info.packet_raw_data.sb[byte_index];
25714562236bSHarry Wentland 
25724562236bSHarry Wentland 	/* one byte complement */
25734562236bSHarry Wentland 	*check_sum = (uint8_t) (0x100 - *check_sum);
25744562236bSHarry Wentland 
25754562236bSHarry Wentland 	/* Store in hw_path_mode */
2576e09b6473SAnthony Koo 	info_packet->hb0 = hdmi_info.packet_raw_data.hb0;
2577e09b6473SAnthony Koo 	info_packet->hb1 = hdmi_info.packet_raw_data.hb1;
2578e09b6473SAnthony Koo 	info_packet->hb2 = hdmi_info.packet_raw_data.hb2;
25794562236bSHarry Wentland 
2580e09b6473SAnthony Koo 	for (byte_index = 0; byte_index < sizeof(hdmi_info.packet_raw_data.sb); byte_index++)
2581e09b6473SAnthony Koo 		info_packet->sb[byte_index] = hdmi_info.packet_raw_data.sb[byte_index];
25824562236bSHarry Wentland 
25834562236bSHarry Wentland 	info_packet->valid = true;
25844562236bSHarry Wentland }
25854562236bSHarry Wentland 
25866e4d6beeSTony Cheng static void set_vendor_info_packet(
2587e09b6473SAnthony Koo 		struct dc_info_packet *info_packet,
25880971c40eSHarry Wentland 		struct dc_stream_state *stream)
25894562236bSHarry Wentland {
2590ecd0136bSHarmanprit Tatla 	/* SPD info packet for FreeSync */
259115e17335SCharlene Liu 
2592ecd0136bSHarmanprit Tatla 	/* Check if Freesync is supported. Return if false. If true,
2593ecd0136bSHarmanprit Tatla 	 * set the corresponding bit in the info packet
2594ecd0136bSHarmanprit Tatla 	 */
2595ecd0136bSHarmanprit Tatla 	if (!stream->vsp_infopacket.valid)
25964562236bSHarry Wentland 		return;
25974562236bSHarry Wentland 
2598ecd0136bSHarmanprit Tatla 	*info_packet = stream->vsp_infopacket;
25994562236bSHarry Wentland }
26004562236bSHarry Wentland 
26016e4d6beeSTony Cheng static void set_spd_info_packet(
2602e09b6473SAnthony Koo 		struct dc_info_packet *info_packet,
26030971c40eSHarry Wentland 		struct dc_stream_state *stream)
26044562236bSHarry Wentland {
26054562236bSHarry Wentland 	/* SPD info packet for FreeSync */
26064562236bSHarry Wentland 
26074562236bSHarry Wentland 	/* Check if Freesync is supported. Return if false. If true,
26084562236bSHarry Wentland 	 * set the corresponding bit in the info packet
26094562236bSHarry Wentland 	 */
261098e6436dSAnthony Koo 	if (!stream->vrr_infopacket.valid)
26114562236bSHarry Wentland 		return;
26124562236bSHarry Wentland 
261398e6436dSAnthony Koo 	*info_packet = stream->vrr_infopacket;
26144562236bSHarry Wentland }
26154562236bSHarry Wentland 
26161646a6feSAndrew Wong static void set_hdr_static_info_packet(
2617e09b6473SAnthony Koo 		struct dc_info_packet *info_packet,
26180971c40eSHarry Wentland 		struct dc_stream_state *stream)
26191646a6feSAndrew Wong {
26200eeef690SAnthony Koo 	/* HDR Static Metadata info packet for HDR10 */
26211646a6feSAndrew Wong 
2622a10dc97aSKrunoslav Kovac 	if (!stream->hdr_static_metadata.valid ||
2623a10dc97aSKrunoslav Kovac 			stream->use_dynamic_meta)
262410bff005SYongqiang Sun 		return;
262510bff005SYongqiang Sun 
26260eeef690SAnthony Koo 	*info_packet = stream->hdr_static_metadata;
26271646a6feSAndrew Wong }
26281646a6feSAndrew Wong 
26296e4d6beeSTony Cheng static void set_vsc_info_packet(
2630e09b6473SAnthony Koo 		struct dc_info_packet *info_packet,
26310971c40eSHarry Wentland 		struct dc_stream_state *stream)
26324562236bSHarry Wentland {
26331336926fSAlvin lee 	if (!stream->vsc_infopacket.valid)
26344562236bSHarry Wentland 		return;
26354562236bSHarry Wentland 
26361336926fSAlvin lee 	*info_packet = stream->vsc_infopacket;
26374562236bSHarry Wentland }
26384562236bSHarry Wentland 
2639f36cc577SBhawanpreet Lakha void dc_resource_state_destruct(struct dc_state *context)
26404562236bSHarry Wentland {
26414562236bSHarry Wentland 	int i, j;
26424562236bSHarry Wentland 
2643ab2541b6SAric Cyr 	for (i = 0; i < context->stream_count; i++) {
26443be5262eSHarry Wentland 		for (j = 0; j < context->stream_status[i].plane_count; j++)
26453be5262eSHarry Wentland 			dc_plane_state_release(
26463be5262eSHarry Wentland 				context->stream_status[i].plane_states[j]);
26474562236bSHarry Wentland 
26483be5262eSHarry Wentland 		context->stream_status[i].plane_count = 0;
26494fa086b9SLeo (Sunpeng) Li 		dc_stream_release(context->streams[i]);
2650ab2541b6SAric Cyr 		context->streams[i] = NULL;
26514562236bSHarry Wentland 	}
26525728d5e5SPaul Wu 	context->stream_count = 0;
26534562236bSHarry Wentland }
26544562236bSHarry Wentland 
2655f36cc577SBhawanpreet Lakha void dc_resource_state_copy_construct(
2656608ac7bbSJerry Zuo 		const struct dc_state *src_ctx,
2657608ac7bbSJerry Zuo 		struct dc_state *dst_ctx)
26584562236bSHarry Wentland {
26594562236bSHarry Wentland 	int i, j;
26608ee5702aSDave Airlie 	struct kref refcount = dst_ctx->refcount;
26614562236bSHarry Wentland 
26624562236bSHarry Wentland 	*dst_ctx = *src_ctx;
26634562236bSHarry Wentland 
2664a2b8659dSTony Cheng 	for (i = 0; i < MAX_PIPES; i++) {
26654562236bSHarry Wentland 		struct pipe_ctx *cur_pipe = &dst_ctx->res_ctx.pipe_ctx[i];
26664562236bSHarry Wentland 
26674562236bSHarry Wentland 		if (cur_pipe->top_pipe)
26684562236bSHarry Wentland 			cur_pipe->top_pipe =  &dst_ctx->res_ctx.pipe_ctx[cur_pipe->top_pipe->pipe_idx];
26694562236bSHarry Wentland 
26704562236bSHarry Wentland 		if (cur_pipe->bottom_pipe)
26714562236bSHarry Wentland 			cur_pipe->bottom_pipe = &dst_ctx->res_ctx.pipe_ctx[cur_pipe->bottom_pipe->pipe_idx];
2672b1f6d01cSDmytro Laktyushkin 
2673b1f6d01cSDmytro Laktyushkin 		if (cur_pipe->next_odm_pipe)
2674b1f6d01cSDmytro Laktyushkin 			cur_pipe->next_odm_pipe =  &dst_ctx->res_ctx.pipe_ctx[cur_pipe->next_odm_pipe->pipe_idx];
2675b1f6d01cSDmytro Laktyushkin 
2676b1f6d01cSDmytro Laktyushkin 		if (cur_pipe->prev_odm_pipe)
2677b1f6d01cSDmytro Laktyushkin 			cur_pipe->prev_odm_pipe = &dst_ctx->res_ctx.pipe_ctx[cur_pipe->prev_odm_pipe->pipe_idx];
26784562236bSHarry Wentland 	}
26794562236bSHarry Wentland 
2680ab2541b6SAric Cyr 	for (i = 0; i < dst_ctx->stream_count; i++) {
26814fa086b9SLeo (Sunpeng) Li 		dc_stream_retain(dst_ctx->streams[i]);
26823be5262eSHarry Wentland 		for (j = 0; j < dst_ctx->stream_status[i].plane_count; j++)
26833be5262eSHarry Wentland 			dc_plane_state_retain(
26843be5262eSHarry Wentland 				dst_ctx->stream_status[i].plane_states[j]);
26854562236bSHarry Wentland 	}
26869a3afbb3SAndrey Grodzovsky 
26879a3afbb3SAndrey Grodzovsky 	/* context refcount should not be overridden */
26888ee5702aSDave Airlie 	dst_ctx->refcount = refcount;
26899a3afbb3SAndrey Grodzovsky 
26904562236bSHarry Wentland }
26914562236bSHarry Wentland 
26924562236bSHarry Wentland struct clock_source *dc_resource_find_first_free_pll(
2693a2b8659dSTony Cheng 		struct resource_context *res_ctx,
2694a2b8659dSTony Cheng 		const struct resource_pool *pool)
26954562236bSHarry Wentland {
26964562236bSHarry Wentland 	int i;
26974562236bSHarry Wentland 
2698a2b8659dSTony Cheng 	for (i = 0; i < pool->clk_src_count; ++i) {
26994562236bSHarry Wentland 		if (res_ctx->clock_source_ref_count[i] == 0)
2700a2b8659dSTony Cheng 			return pool->clock_sources[i];
27014562236bSHarry Wentland 	}
27024562236bSHarry Wentland 
27034562236bSHarry Wentland 	return NULL;
27044562236bSHarry Wentland }
27054562236bSHarry Wentland 
27064562236bSHarry Wentland void resource_build_info_frame(struct pipe_ctx *pipe_ctx)
27074562236bSHarry Wentland {
27084562236bSHarry Wentland 	enum signal_type signal = SIGNAL_TYPE_NONE;
270996c50c0dSHarry Wentland 	struct encoder_info_frame *info = &pipe_ctx->stream_res.encoder_info_frame;
27104562236bSHarry Wentland 
27114562236bSHarry Wentland 	/* default all packets to invalid */
27126e4d6beeSTony Cheng 	info->avi.valid = false;
27136e4d6beeSTony Cheng 	info->gamut.valid = false;
27146e4d6beeSTony Cheng 	info->vendor.valid = false;
2715630e3573SJeff Smith 	info->spd.valid = false;
27166e4d6beeSTony Cheng 	info->hdrsmd.valid = false;
27176e4d6beeSTony Cheng 	info->vsc.valid = false;
27184562236bSHarry Wentland 
27194562236bSHarry Wentland 	signal = pipe_ctx->stream->signal;
27204562236bSHarry Wentland 
27214562236bSHarry Wentland 	/* HDMi and DP have different info packets*/
27224562236bSHarry Wentland 	if (dc_is_hdmi_signal(signal)) {
27236e4d6beeSTony Cheng 		set_avi_info_frame(&info->avi, pipe_ctx);
27246e4d6beeSTony Cheng 
27256e4d6beeSTony Cheng 		set_vendor_info_packet(&info->vendor, pipe_ctx->stream);
27266e4d6beeSTony Cheng 
27276e4d6beeSTony Cheng 		set_spd_info_packet(&info->spd, pipe_ctx->stream);
27286e4d6beeSTony Cheng 
272956ef6ed9SAnthony Koo 		set_hdr_static_info_packet(&info->hdrsmd, pipe_ctx->stream);
27306e4d6beeSTony Cheng 
2731a33fa99dSHarry Wentland 	} else if (dc_is_dp_signal(signal)) {
27326e4d6beeSTony Cheng 		set_vsc_info_packet(&info->vsc, pipe_ctx->stream);
27336e4d6beeSTony Cheng 
27346e4d6beeSTony Cheng 		set_spd_info_packet(&info->spd, pipe_ctx->stream);
27356e4d6beeSTony Cheng 
273656ef6ed9SAnthony Koo 		set_hdr_static_info_packet(&info->hdrsmd, pipe_ctx->stream);
2737a33fa99dSHarry Wentland 	}
27384562236bSHarry Wentland 
27396e4d6beeSTony Cheng 	patch_gamut_packet_checksum(&info->gamut);
27404562236bSHarry Wentland }
27414562236bSHarry Wentland 
27424562236bSHarry Wentland enum dc_status resource_map_clock_resources(
2743fb3466a4SBhawanpreet Lakha 		const struct dc  *dc,
2744608ac7bbSJerry Zuo 		struct dc_state *context,
27451dc90497SAndrey Grodzovsky 		struct dc_stream_state *stream)
27464562236bSHarry Wentland {
27474562236bSHarry Wentland 	/* acquire new resources */
27481dc90497SAndrey Grodzovsky 	const struct resource_pool *pool = dc->res_pool;
27491dc90497SAndrey Grodzovsky 	struct pipe_ctx *pipe_ctx = resource_get_head_pipe_for_stream(
27501dc90497SAndrey Grodzovsky 				&context->res_ctx, stream);
27514562236bSHarry Wentland 
27521dc90497SAndrey Grodzovsky 	if (!pipe_ctx)
27531dc90497SAndrey Grodzovsky 		return DC_ERROR_UNEXPECTED;
27544562236bSHarry Wentland 
27554562236bSHarry Wentland 	if (dc_is_dp_signal(pipe_ctx->stream->signal)
27564562236bSHarry Wentland 		|| pipe_ctx->stream->signal == SIGNAL_TYPE_VIRTUAL)
2757a2b8659dSTony Cheng 		pipe_ctx->clock_source = pool->dp_clock_source;
27584562236bSHarry Wentland 	else {
27594562236bSHarry Wentland 		pipe_ctx->clock_source = NULL;
27604562236bSHarry Wentland 
2761fb3466a4SBhawanpreet Lakha 		if (!dc->config.disable_disp_pll_sharing)
27624ed4e51bSMikita Lipski 			pipe_ctx->clock_source = resource_find_used_clk_src_for_sharing(
27634562236bSHarry Wentland 				&context->res_ctx,
27644562236bSHarry Wentland 				pipe_ctx);
27654562236bSHarry Wentland 
27664562236bSHarry Wentland 		if (pipe_ctx->clock_source == NULL)
27674562236bSHarry Wentland 			pipe_ctx->clock_source =
2768a2b8659dSTony Cheng 				dc_resource_find_first_free_pll(
2769a2b8659dSTony Cheng 					&context->res_ctx,
2770a2b8659dSTony Cheng 					pool);
27714562236bSHarry Wentland 	}
27724562236bSHarry Wentland 
27734562236bSHarry Wentland 	if (pipe_ctx->clock_source == NULL)
27744562236bSHarry Wentland 		return DC_NO_CLOCK_SOURCE_RESOURCE;
27754562236bSHarry Wentland 
27764562236bSHarry Wentland 	resource_reference_clock_source(
2777a2b8659dSTony Cheng 		&context->res_ctx, pool,
27784562236bSHarry Wentland 		pipe_ctx->clock_source);
27794562236bSHarry Wentland 
27804562236bSHarry Wentland 	return DC_OK;
27814562236bSHarry Wentland }
27824562236bSHarry Wentland 
27834562236bSHarry Wentland /*
27844562236bSHarry Wentland  * Note: We need to disable output if clock sources change,
27854562236bSHarry Wentland  * since bios does optimization and doesn't apply if changing
27864562236bSHarry Wentland  * PHY when not already disabled.
27874562236bSHarry Wentland  */
27884562236bSHarry Wentland bool pipe_need_reprogram(
27894562236bSHarry Wentland 		struct pipe_ctx *pipe_ctx_old,
27904562236bSHarry Wentland 		struct pipe_ctx *pipe_ctx)
27914562236bSHarry Wentland {
2792cfe4645eSDmytro Laktyushkin 	if (!pipe_ctx_old->stream)
2793cfe4645eSDmytro Laktyushkin 		return false;
2794cfe4645eSDmytro Laktyushkin 
27954562236bSHarry Wentland 	if (pipe_ctx_old->stream->sink != pipe_ctx->stream->sink)
27964562236bSHarry Wentland 		return true;
27974562236bSHarry Wentland 
27984562236bSHarry Wentland 	if (pipe_ctx_old->stream->signal != pipe_ctx->stream->signal)
27994562236bSHarry Wentland 		return true;
28004562236bSHarry Wentland 
2801afaacef4SHarry Wentland 	if (pipe_ctx_old->stream_res.audio != pipe_ctx->stream_res.audio)
28024562236bSHarry Wentland 		return true;
28034562236bSHarry Wentland 
28044562236bSHarry Wentland 	if (pipe_ctx_old->clock_source != pipe_ctx->clock_source
28054562236bSHarry Wentland 			&& pipe_ctx_old->stream != pipe_ctx->stream)
28064562236bSHarry Wentland 		return true;
28074562236bSHarry Wentland 
28088e9c4c8cSHarry Wentland 	if (pipe_ctx_old->stream_res.stream_enc != pipe_ctx->stream_res.stream_enc)
28094562236bSHarry Wentland 		return true;
28104562236bSHarry Wentland 
28114562236bSHarry Wentland 	if (is_timing_changed(pipe_ctx_old->stream, pipe_ctx->stream))
28124562236bSHarry Wentland 		return true;
28134562236bSHarry Wentland 
28141e7e86c4SSamson Tam 	if (pipe_ctx_old->stream->dpms_off != pipe_ctx->stream->dpms_off)
28151e7e86c4SSamson Tam 		return true;
28161e7e86c4SSamson Tam 
2817eed928dcSCharlene Liu 	if (false == pipe_ctx_old->stream->link->link_state_valid &&
2818eed928dcSCharlene Liu 		false == pipe_ctx_old->stream->dpms_off)
2819eed928dcSCharlene Liu 		return true;
2820eed928dcSCharlene Liu 
282114e49bb3SNikola Cornij 	if (pipe_ctx_old->stream_res.dsc != pipe_ctx->stream_res.dsc)
282214e49bb3SNikola Cornij 		return true;
282314e49bb3SNikola Cornij 
2824f01ee019SFangzhi Zuo #if defined(CONFIG_DRM_AMD_DC_DCN)
2825f01ee019SFangzhi Zuo 	if (pipe_ctx_old->stream_res.hpo_dp_stream_enc != pipe_ctx->stream_res.hpo_dp_stream_enc)
2826f01ee019SFangzhi Zuo 		return true;
2827f01ee019SFangzhi Zuo #endif
2828f01ee019SFangzhi Zuo 
2829f42ef862SJimmy Kizito 	/* DIG link encoder resource assignment for stream changed. */
2830*0d4b4253SJimmy Kizito 	if (pipe_ctx_old->stream->ctx->dc->res_pool->funcs->link_encs_assign) {
2831*0d4b4253SJimmy Kizito 		bool need_reprogram = false;
2832*0d4b4253SJimmy Kizito 		struct dc *dc = pipe_ctx_old->stream->ctx->dc;
2833*0d4b4253SJimmy Kizito 		enum link_enc_cfg_mode mode = dc->current_state->res_ctx.link_enc_cfg_ctx.mode;
2834*0d4b4253SJimmy Kizito 
2835*0d4b4253SJimmy Kizito 		dc->current_state->res_ctx.link_enc_cfg_ctx.mode = LINK_ENC_CFG_STEADY;
2836*0d4b4253SJimmy Kizito 		if (link_enc_cfg_get_link_enc_used_by_stream(dc, pipe_ctx_old->stream) != pipe_ctx->stream->link_enc)
2837*0d4b4253SJimmy Kizito 			need_reprogram = true;
2838*0d4b4253SJimmy Kizito 		dc->current_state->res_ctx.link_enc_cfg_ctx.mode = mode;
2839*0d4b4253SJimmy Kizito 
2840*0d4b4253SJimmy Kizito 		return need_reprogram;
2841*0d4b4253SJimmy Kizito 	}
2842f42ef862SJimmy Kizito 
28434562236bSHarry Wentland 	return false;
28444562236bSHarry Wentland }
2845529cad0fSDing Wang 
28460971c40eSHarry Wentland void resource_build_bit_depth_reduction_params(struct dc_stream_state *stream,
2847529cad0fSDing Wang 		struct bit_depth_reduction_params *fmt_bit_depth)
2848529cad0fSDing Wang {
28494fa086b9SLeo (Sunpeng) Li 	enum dc_dither_option option = stream->dither_option;
2850529cad0fSDing Wang 	enum dc_pixel_encoding pixel_encoding =
28514fa086b9SLeo (Sunpeng) Li 			stream->timing.pixel_encoding;
2852529cad0fSDing Wang 
2853529cad0fSDing Wang 	memset(fmt_bit_depth, 0, sizeof(*fmt_bit_depth));
2854529cad0fSDing Wang 
2855603767f9STony Cheng 	if (option == DITHER_OPTION_DEFAULT) {
2856603767f9STony Cheng 		switch (stream->timing.display_color_depth) {
2857603767f9STony Cheng 		case COLOR_DEPTH_666:
2858603767f9STony Cheng 			option = DITHER_OPTION_SPATIAL6;
2859603767f9STony Cheng 			break;
2860603767f9STony Cheng 		case COLOR_DEPTH_888:
2861603767f9STony Cheng 			option = DITHER_OPTION_SPATIAL8;
2862603767f9STony Cheng 			break;
2863603767f9STony Cheng 		case COLOR_DEPTH_101010:
2864603767f9STony Cheng 			option = DITHER_OPTION_SPATIAL10;
2865603767f9STony Cheng 			break;
2866603767f9STony Cheng 		default:
2867603767f9STony Cheng 			option = DITHER_OPTION_DISABLE;
2868603767f9STony Cheng 		}
2869603767f9STony Cheng 	}
2870603767f9STony Cheng 
2871529cad0fSDing Wang 	if (option == DITHER_OPTION_DISABLE)
2872529cad0fSDing Wang 		return;
2873529cad0fSDing Wang 
2874529cad0fSDing Wang 	if (option == DITHER_OPTION_TRUN6) {
2875529cad0fSDing Wang 		fmt_bit_depth->flags.TRUNCATE_ENABLED = 1;
2876529cad0fSDing Wang 		fmt_bit_depth->flags.TRUNCATE_DEPTH = 0;
2877529cad0fSDing Wang 	} else if (option == DITHER_OPTION_TRUN8 ||
2878529cad0fSDing Wang 			option == DITHER_OPTION_TRUN8_SPATIAL6 ||
2879529cad0fSDing Wang 			option == DITHER_OPTION_TRUN8_FM6) {
2880529cad0fSDing Wang 		fmt_bit_depth->flags.TRUNCATE_ENABLED = 1;
2881529cad0fSDing Wang 		fmt_bit_depth->flags.TRUNCATE_DEPTH = 1;
2882529cad0fSDing Wang 	} else if (option == DITHER_OPTION_TRUN10        ||
2883529cad0fSDing Wang 			option == DITHER_OPTION_TRUN10_SPATIAL6   ||
2884529cad0fSDing Wang 			option == DITHER_OPTION_TRUN10_SPATIAL8   ||
2885529cad0fSDing Wang 			option == DITHER_OPTION_TRUN10_FM8     ||
2886529cad0fSDing Wang 			option == DITHER_OPTION_TRUN10_FM6     ||
2887529cad0fSDing Wang 			option == DITHER_OPTION_TRUN10_SPATIAL8_FM6) {
2888529cad0fSDing Wang 		fmt_bit_depth->flags.TRUNCATE_ENABLED = 1;
2889529cad0fSDing Wang 		fmt_bit_depth->flags.TRUNCATE_DEPTH = 2;
2890529cad0fSDing Wang 	}
2891529cad0fSDing Wang 
2892529cad0fSDing Wang 	/* special case - Formatter can only reduce by 4 bits at most.
2893529cad0fSDing Wang 	 * When reducing from 12 to 6 bits,
2894529cad0fSDing Wang 	 * HW recommends we use trunc with round mode
2895529cad0fSDing Wang 	 * (if we did nothing, trunc to 10 bits would be used)
2896529cad0fSDing Wang 	 * note that any 12->10 bit reduction is ignored prior to DCE8,
2897529cad0fSDing Wang 	 * as the input was 10 bits.
2898529cad0fSDing Wang 	 */
2899529cad0fSDing Wang 	if (option == DITHER_OPTION_SPATIAL6_FRAME_RANDOM ||
2900529cad0fSDing Wang 			option == DITHER_OPTION_SPATIAL6 ||
2901529cad0fSDing Wang 			option == DITHER_OPTION_FM6) {
2902529cad0fSDing Wang 		fmt_bit_depth->flags.TRUNCATE_ENABLED = 1;
2903529cad0fSDing Wang 		fmt_bit_depth->flags.TRUNCATE_DEPTH = 2;
2904529cad0fSDing Wang 		fmt_bit_depth->flags.TRUNCATE_MODE = 1;
2905529cad0fSDing Wang 	}
2906529cad0fSDing Wang 
2907529cad0fSDing Wang 	/* spatial dither
2908529cad0fSDing Wang 	 * note that spatial modes 1-3 are never used
2909529cad0fSDing Wang 	 */
2910529cad0fSDing Wang 	if (option == DITHER_OPTION_SPATIAL6_FRAME_RANDOM            ||
2911529cad0fSDing Wang 			option == DITHER_OPTION_SPATIAL6 ||
2912529cad0fSDing Wang 			option == DITHER_OPTION_TRUN10_SPATIAL6      ||
2913529cad0fSDing Wang 			option == DITHER_OPTION_TRUN8_SPATIAL6) {
2914529cad0fSDing Wang 		fmt_bit_depth->flags.SPATIAL_DITHER_ENABLED = 1;
2915529cad0fSDing Wang 		fmt_bit_depth->flags.SPATIAL_DITHER_DEPTH = 0;
2916529cad0fSDing Wang 		fmt_bit_depth->flags.HIGHPASS_RANDOM = 1;
2917529cad0fSDing Wang 		fmt_bit_depth->flags.RGB_RANDOM =
2918529cad0fSDing Wang 				(pixel_encoding == PIXEL_ENCODING_RGB) ? 1 : 0;
2919529cad0fSDing Wang 	} else if (option == DITHER_OPTION_SPATIAL8_FRAME_RANDOM            ||
2920529cad0fSDing Wang 			option == DITHER_OPTION_SPATIAL8 ||
2921529cad0fSDing Wang 			option == DITHER_OPTION_SPATIAL8_FM6        ||
2922529cad0fSDing Wang 			option == DITHER_OPTION_TRUN10_SPATIAL8      ||
2923529cad0fSDing Wang 			option == DITHER_OPTION_TRUN10_SPATIAL8_FM6) {
2924529cad0fSDing Wang 		fmt_bit_depth->flags.SPATIAL_DITHER_ENABLED = 1;
2925529cad0fSDing Wang 		fmt_bit_depth->flags.SPATIAL_DITHER_DEPTH = 1;
2926529cad0fSDing Wang 		fmt_bit_depth->flags.HIGHPASS_RANDOM = 1;
2927529cad0fSDing Wang 		fmt_bit_depth->flags.RGB_RANDOM =
2928529cad0fSDing Wang 				(pixel_encoding == PIXEL_ENCODING_RGB) ? 1 : 0;
2929529cad0fSDing Wang 	} else if (option == DITHER_OPTION_SPATIAL10_FRAME_RANDOM ||
2930529cad0fSDing Wang 			option == DITHER_OPTION_SPATIAL10 ||
2931529cad0fSDing Wang 			option == DITHER_OPTION_SPATIAL10_FM8 ||
2932529cad0fSDing Wang 			option == DITHER_OPTION_SPATIAL10_FM6) {
2933529cad0fSDing Wang 		fmt_bit_depth->flags.SPATIAL_DITHER_ENABLED = 1;
2934529cad0fSDing Wang 		fmt_bit_depth->flags.SPATIAL_DITHER_DEPTH = 2;
2935529cad0fSDing Wang 		fmt_bit_depth->flags.HIGHPASS_RANDOM = 1;
2936529cad0fSDing Wang 		fmt_bit_depth->flags.RGB_RANDOM =
2937529cad0fSDing Wang 				(pixel_encoding == PIXEL_ENCODING_RGB) ? 1 : 0;
2938529cad0fSDing Wang 	}
2939529cad0fSDing Wang 
2940529cad0fSDing Wang 	if (option == DITHER_OPTION_SPATIAL6 ||
2941529cad0fSDing Wang 			option == DITHER_OPTION_SPATIAL8 ||
2942529cad0fSDing Wang 			option == DITHER_OPTION_SPATIAL10) {
2943529cad0fSDing Wang 		fmt_bit_depth->flags.FRAME_RANDOM = 0;
2944529cad0fSDing Wang 	} else {
2945529cad0fSDing Wang 		fmt_bit_depth->flags.FRAME_RANDOM = 1;
2946529cad0fSDing Wang 	}
2947529cad0fSDing Wang 
2948529cad0fSDing Wang 	//////////////////////
2949529cad0fSDing Wang 	//// temporal dither
2950529cad0fSDing Wang 	//////////////////////
2951529cad0fSDing Wang 	if (option == DITHER_OPTION_FM6           ||
2952529cad0fSDing Wang 			option == DITHER_OPTION_SPATIAL8_FM6     ||
2953529cad0fSDing Wang 			option == DITHER_OPTION_SPATIAL10_FM6     ||
2954529cad0fSDing Wang 			option == DITHER_OPTION_TRUN10_FM6     ||
2955529cad0fSDing Wang 			option == DITHER_OPTION_TRUN8_FM6      ||
2956529cad0fSDing Wang 			option == DITHER_OPTION_TRUN10_SPATIAL8_FM6) {
2957529cad0fSDing Wang 		fmt_bit_depth->flags.FRAME_MODULATION_ENABLED = 1;
2958529cad0fSDing Wang 		fmt_bit_depth->flags.FRAME_MODULATION_DEPTH = 0;
2959529cad0fSDing Wang 	} else if (option == DITHER_OPTION_FM8        ||
2960529cad0fSDing Wang 			option == DITHER_OPTION_SPATIAL10_FM8  ||
2961529cad0fSDing Wang 			option == DITHER_OPTION_TRUN10_FM8) {
2962529cad0fSDing Wang 		fmt_bit_depth->flags.FRAME_MODULATION_ENABLED = 1;
2963529cad0fSDing Wang 		fmt_bit_depth->flags.FRAME_MODULATION_DEPTH = 1;
2964529cad0fSDing Wang 	} else if (option == DITHER_OPTION_FM10) {
2965529cad0fSDing Wang 		fmt_bit_depth->flags.FRAME_MODULATION_ENABLED = 1;
2966529cad0fSDing Wang 		fmt_bit_depth->flags.FRAME_MODULATION_DEPTH = 2;
2967529cad0fSDing Wang 	}
2968529cad0fSDing Wang 
2969529cad0fSDing Wang 	fmt_bit_depth->pixel_encoding = pixel_encoding;
2970529cad0fSDing Wang }
29719345d987SAndrey Grodzovsky 
297262c933f9SYongqiang Sun enum dc_status dc_validate_stream(struct dc *dc, struct dc_stream_state *stream)
29739345d987SAndrey Grodzovsky {
2974ceb3dbb4SJun Lei 	struct dc_link *link = stream->link;
29752b77dcc5SAnthony Koo 	struct timing_generator *tg = dc->res_pool->timing_generators[0];
29769345d987SAndrey Grodzovsky 	enum dc_status res = DC_OK;
29779345d987SAndrey Grodzovsky 
29784fa086b9SLeo (Sunpeng) Li 	calculate_phy_pix_clks(stream);
29799345d987SAndrey Grodzovsky 
29804fa086b9SLeo (Sunpeng) Li 	if (!tg->funcs->validate_timing(tg, &stream->timing))
29819345d987SAndrey Grodzovsky 		res = DC_FAIL_CONTROLLER_VALIDATE;
29829345d987SAndrey Grodzovsky 
2983248cbed6SEric Bernstein 	if (res == DC_OK) {
298464d283cbSJimmy Kizito 		if (link->ep_type == DISPLAY_ENDPOINT_PHY &&
298564d283cbSJimmy Kizito 				!link->link_enc->funcs->validate_output_with_stream(
29864fa086b9SLeo (Sunpeng) Li 						link->link_enc, stream))
29879345d987SAndrey Grodzovsky 			res = DC_FAIL_ENC_VALIDATE;
2988248cbed6SEric Bernstein 	}
29899345d987SAndrey Grodzovsky 
29909345d987SAndrey Grodzovsky 	/* TODO: validate audio ASIC caps, encoder */
29919345d987SAndrey Grodzovsky 
29929345d987SAndrey Grodzovsky 	if (res == DC_OK)
29934fa086b9SLeo (Sunpeng) Li 		res = dc_link_validate_mode_timing(stream,
29949345d987SAndrey Grodzovsky 		      link,
29954fa086b9SLeo (Sunpeng) Li 		      &stream->timing);
29969345d987SAndrey Grodzovsky 
299762c933f9SYongqiang Sun 	return res;
29989345d987SAndrey Grodzovsky }
2999792671d7SAndrey Grodzovsky 
300062c933f9SYongqiang Sun enum dc_status dc_validate_plane(struct dc *dc, const struct dc_plane_state *plane_state)
3001792671d7SAndrey Grodzovsky {
300262c933f9SYongqiang Sun 	enum dc_status res = DC_OK;
300362c933f9SYongqiang Sun 
3004792671d7SAndrey Grodzovsky 	/* TODO For now validates pixel format only */
30058e7095b9SDmytro Laktyushkin 	if (dc->res_pool->funcs->validate_plane)
300662c933f9SYongqiang Sun 		return dc->res_pool->funcs->validate_plane(plane_state, &dc->caps);
3007792671d7SAndrey Grodzovsky 
300862c933f9SYongqiang Sun 	return res;
3009792671d7SAndrey Grodzovsky }
301074eac5f3SSu Sung Chung 
301174eac5f3SSu Sung Chung unsigned int resource_pixel_format_to_bpp(enum surface_pixel_format format)
301274eac5f3SSu Sung Chung {
301374eac5f3SSu Sung Chung 	switch (format) {
301474eac5f3SSu Sung Chung 	case SURFACE_PIXEL_FORMAT_GRPH_PALETA_256_COLORS:
301574eac5f3SSu Sung Chung 		return 8;
301674eac5f3SSu Sung Chung 	case SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr:
301774eac5f3SSu Sung Chung 	case SURFACE_PIXEL_FORMAT_VIDEO_420_YCrCb:
301874eac5f3SSu Sung Chung 		return 12;
301974eac5f3SSu Sung Chung 	case SURFACE_PIXEL_FORMAT_GRPH_ARGB1555:
302074eac5f3SSu Sung Chung 	case SURFACE_PIXEL_FORMAT_GRPH_RGB565:
302174eac5f3SSu Sung Chung 	case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCbCr:
302274eac5f3SSu Sung Chung 	case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb:
302374eac5f3SSu Sung Chung 		return 16;
302474eac5f3SSu Sung Chung 	case SURFACE_PIXEL_FORMAT_GRPH_ARGB8888:
302574eac5f3SSu Sung Chung 	case SURFACE_PIXEL_FORMAT_GRPH_ABGR8888:
302674eac5f3SSu Sung Chung 	case SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010:
302774eac5f3SSu Sung Chung 	case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010:
302874eac5f3SSu Sung Chung 	case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010_XR_BIAS:
302920f2ffe5SAlex Deucher #if defined(CONFIG_DRM_AMD_DC_DCN)
30305dba4991SBhawanpreet Lakha 	case SURFACE_PIXEL_FORMAT_GRPH_RGBE:
30315dba4991SBhawanpreet Lakha 	case SURFACE_PIXEL_FORMAT_GRPH_RGBE_ALPHA:
30325dba4991SBhawanpreet Lakha #endif
303374eac5f3SSu Sung Chung 		return 32;
303474eac5f3SSu Sung Chung 	case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616:
3035050cd3d6SMario Kleiner 	case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616:
303674eac5f3SSu Sung Chung 	case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F:
303774eac5f3SSu Sung Chung 	case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F:
303874eac5f3SSu Sung Chung 		return 64;
303974eac5f3SSu Sung Chung 	default:
304074eac5f3SSu Sung Chung 		ASSERT_CRITICAL(false);
304174eac5f3SSu Sung Chung 		return -1;
304274eac5f3SSu Sung Chung 	}
304374eac5f3SSu Sung Chung }
30443ab4cc65SCharlene Liu static unsigned int get_max_audio_sample_rate(struct audio_mode *modes)
30453ab4cc65SCharlene Liu {
30463ab4cc65SCharlene Liu 	if (modes) {
30473ab4cc65SCharlene Liu 		if (modes->sample_rates.rate.RATE_192)
30483ab4cc65SCharlene Liu 			return 192000;
30493ab4cc65SCharlene Liu 		if (modes->sample_rates.rate.RATE_176_4)
30503ab4cc65SCharlene Liu 			return 176400;
30513ab4cc65SCharlene Liu 		if (modes->sample_rates.rate.RATE_96)
30523ab4cc65SCharlene Liu 			return 96000;
30533ab4cc65SCharlene Liu 		if (modes->sample_rates.rate.RATE_88_2)
30543ab4cc65SCharlene Liu 			return 88200;
30553ab4cc65SCharlene Liu 		if (modes->sample_rates.rate.RATE_48)
30563ab4cc65SCharlene Liu 			return 48000;
30573ab4cc65SCharlene Liu 		if (modes->sample_rates.rate.RATE_44_1)
30583ab4cc65SCharlene Liu 			return 44100;
30593ab4cc65SCharlene Liu 		if (modes->sample_rates.rate.RATE_32)
30603ab4cc65SCharlene Liu 			return 32000;
30613ab4cc65SCharlene Liu 	}
30623ab4cc65SCharlene Liu 	/*original logic when no audio info*/
30633ab4cc65SCharlene Liu 	return 441000;
30643ab4cc65SCharlene Liu }
30653ab4cc65SCharlene Liu 
30663ab4cc65SCharlene Liu void get_audio_check(struct audio_info *aud_modes,
30673ab4cc65SCharlene Liu 	struct audio_check *audio_chk)
30683ab4cc65SCharlene Liu {
30693ab4cc65SCharlene Liu 	unsigned int i;
30703ab4cc65SCharlene Liu 	unsigned int max_sample_rate = 0;
30713ab4cc65SCharlene Liu 
30723ab4cc65SCharlene Liu 	if (aud_modes) {
30733ab4cc65SCharlene Liu 		audio_chk->audio_packet_type = 0x2;/*audio sample packet AP = .25 for layout0, 1 for layout1*/
30743ab4cc65SCharlene Liu 
30753ab4cc65SCharlene Liu 		audio_chk->max_audiosample_rate = 0;
30763ab4cc65SCharlene Liu 		for (i = 0; i < aud_modes->mode_count; i++) {
30773ab4cc65SCharlene Liu 			max_sample_rate = get_max_audio_sample_rate(&aud_modes->modes[i]);
30783ab4cc65SCharlene Liu 			if (audio_chk->max_audiosample_rate < max_sample_rate)
30793ab4cc65SCharlene Liu 				audio_chk->max_audiosample_rate = max_sample_rate;
30803ab4cc65SCharlene Liu 			/*dts takes the same as type 2: AP = 0.25*/
30813ab4cc65SCharlene Liu 		}
30823ab4cc65SCharlene Liu 		/*check which one take more bandwidth*/
30833ab4cc65SCharlene Liu 		if (audio_chk->max_audiosample_rate > 192000)
30843ab4cc65SCharlene Liu 			audio_chk->audio_packet_type = 0x9;/*AP =1*/
30853ab4cc65SCharlene Liu 		audio_chk->acat = 0;/*not support*/
30863ab4cc65SCharlene Liu 	}
30873ab4cc65SCharlene Liu }
30883ab4cc65SCharlene Liu 
3089f01ee019SFangzhi Zuo #if defined(CONFIG_DRM_AMD_DC_DCN)
3090f01ee019SFangzhi Zuo struct hpo_dp_link_encoder *resource_get_unused_hpo_dp_link_encoder(
3091f01ee019SFangzhi Zuo 		const struct resource_pool *pool)
3092f01ee019SFangzhi Zuo {
3093f01ee019SFangzhi Zuo 	uint8_t i;
3094f01ee019SFangzhi Zuo 	struct hpo_dp_link_encoder *enc = NULL;
3095f01ee019SFangzhi Zuo 
3096f01ee019SFangzhi Zuo 	ASSERT(pool->hpo_dp_link_enc_count <= MAX_HPO_DP2_LINK_ENCODERS);
3097f01ee019SFangzhi Zuo 
3098f01ee019SFangzhi Zuo 	for (i = 0; i < pool->hpo_dp_link_enc_count; i++) {
3099f01ee019SFangzhi Zuo 		if (pool->hpo_dp_link_enc[i]->transmitter == TRANSMITTER_UNKNOWN) {
3100f01ee019SFangzhi Zuo 			enc = pool->hpo_dp_link_enc[i];
3101f01ee019SFangzhi Zuo 			break;
3102f01ee019SFangzhi Zuo 		}
3103f01ee019SFangzhi Zuo 	}
3104f01ee019SFangzhi Zuo 
3105f01ee019SFangzhi Zuo 	return enc;
3106f01ee019SFangzhi Zuo }
3107f01ee019SFangzhi Zuo #endif
3108