File: | dev/pci/drm/amd/display/include/fixed31_32.h |
Warning: | line 528, column 22 The result of the left shift is undefined because the left operand is negative |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* | |||
2 | * Copyright 2012-15 Advanced Micro Devices, Inc. | |||
3 | * | |||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | |||
5 | * copy of this software and associated documentation files (the "Software"), | |||
6 | * to deal in the Software without restriction, including without limitation | |||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | |||
8 | * and/or sell copies of the Software, and to permit persons to whom the | |||
9 | * Software is furnished to do so, subject to the following conditions: | |||
10 | * | |||
11 | * The above copyright notice and this permission notice shall be included in | |||
12 | * all copies or substantial portions of the Software. | |||
13 | * | |||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |||
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | |||
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | |||
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | |||
20 | * OTHER DEALINGS IN THE SOFTWARE. | |||
21 | * | |||
22 | * Authors: AMD | |||
23 | * | |||
24 | */ | |||
25 | ||||
26 | #include "dm_services.h" | |||
27 | ||||
28 | #include "resource.h" | |||
29 | #include "include/irq_service_interface.h" | |||
30 | #include "link_encoder.h" | |||
31 | #include "stream_encoder.h" | |||
32 | #include "opp.h" | |||
33 | #include "timing_generator.h" | |||
34 | #include "transform.h" | |||
35 | #include "dccg.h" | |||
36 | #include "dchubbub.h" | |||
37 | #include "dpp.h" | |||
38 | #include "core_types.h" | |||
39 | #include "set_mode_types.h" | |||
40 | #include "virtual/virtual_stream_encoder.h" | |||
41 | #include "dpcd_defs.h" | |||
42 | #include "link_enc_cfg.h" | |||
43 | #include "dc_link_dp.h" | |||
44 | #include "virtual/virtual_link_hwss.h" | |||
45 | #include "link/link_hwss_dio.h" | |||
46 | #include "link/link_hwss_dpia.h" | |||
47 | #include "link/link_hwss_hpo_dp.h" | |||
48 | ||||
49 | #if defined(CONFIG_DRM_AMD_DC_SI) | |||
50 | #include "dce60/dce60_resource.h" | |||
51 | #endif | |||
52 | #include "dce80/dce80_resource.h" | |||
53 | #include "dce100/dce100_resource.h" | |||
54 | #include "dce110/dce110_resource.h" | |||
55 | #include "dce112/dce112_resource.h" | |||
56 | #include "dce120/dce120_resource.h" | |||
57 | #include "dcn10/dcn10_resource.h" | |||
58 | #include "dcn20/dcn20_resource.h" | |||
59 | #include "dcn21/dcn21_resource.h" | |||
60 | #include "dcn201/dcn201_resource.h" | |||
61 | #include "dcn30/dcn30_resource.h" | |||
62 | #include "dcn301/dcn301_resource.h" | |||
63 | #include "dcn302/dcn302_resource.h" | |||
64 | #include "dcn303/dcn303_resource.h" | |||
65 | #include "dcn31/dcn31_resource.h" | |||
66 | #include "dcn314/dcn314_resource.h" | |||
67 | #include "dcn315/dcn315_resource.h" | |||
68 | #include "dcn316/dcn316_resource.h" | |||
69 | #include "../dcn32/dcn32_resource.h" | |||
70 | #include "../dcn321/dcn321_resource.h" | |||
71 | ||||
72 | #define DC_LOGGER_INIT(logger) | |||
73 | ||||
74 | enum dce_version resource_parse_asic_id(struct hw_asic_id asic_id) | |||
75 | { | |||
76 | enum dce_version dc_version = DCE_VERSION_UNKNOWN; | |||
77 | ||||
78 | switch (asic_id.chip_family) { | |||
79 | ||||
80 | #if defined(CONFIG_DRM_AMD_DC_SI) | |||
81 | case FAMILY_SI110: | |||
82 | if (ASIC_REV_IS_TAHITI_P(asic_id.hw_internal_rev)((asic_id.hw_internal_rev >= 0x01) && (asic_id.hw_internal_rev < 0x14)) || | |||
83 | ASIC_REV_IS_PITCAIRN_PM(asic_id.hw_internal_rev)((asic_id.hw_internal_rev >= 0x14) && (asic_id.hw_internal_rev < 0x28)) || | |||
84 | ASIC_REV_IS_CAPEVERDE_M(asic_id.hw_internal_rev)((asic_id.hw_internal_rev >= 0x28) && (asic_id.hw_internal_rev < 0x3C))) | |||
85 | dc_version = DCE_VERSION_6_0; | |||
86 | else if (ASIC_REV_IS_OLAND_M(asic_id.hw_internal_rev)((asic_id.hw_internal_rev >= 0x3C) && (asic_id.hw_internal_rev < 0x46))) | |||
87 | dc_version = DCE_VERSION_6_4; | |||
88 | else | |||
89 | dc_version = DCE_VERSION_6_1; | |||
90 | break; | |||
91 | #endif | |||
92 | case FAMILY_CI120: | |||
93 | dc_version = DCE_VERSION_8_0; | |||
94 | break; | |||
95 | case FAMILY_KV125: | |||
96 | if (ASIC_REV_IS_KALINDI(asic_id.hw_internal_rev)((asic_id.hw_internal_rev >= 0x81) && (asic_id.hw_internal_rev < 0xFF)) || | |||
97 | ASIC_REV_IS_BHAVANI(asic_id.hw_internal_rev)((asic_id.hw_internal_rev >= 0x85) && (asic_id.hw_internal_rev < 0xA1)) || | |||
98 | ASIC_REV_IS_GODAVARI(asic_id.hw_internal_rev)((asic_id.hw_internal_rev >= 0xA1) && (asic_id.hw_internal_rev < 0xFF))) | |||
99 | dc_version = DCE_VERSION_8_3; | |||
100 | else | |||
101 | dc_version = DCE_VERSION_8_1; | |||
102 | break; | |||
103 | case FAMILY_CZ135: | |||
104 | dc_version = DCE_VERSION_11_0; | |||
105 | break; | |||
106 | ||||
107 | case FAMILY_VI130: | |||
108 | if (ASIC_REV_IS_TONGA_P(asic_id.hw_internal_rev)((asic_id.hw_internal_rev >= 20) && (asic_id.hw_internal_rev < 40)) || | |||
109 | ASIC_REV_IS_FIJI_P(asic_id.hw_internal_rev)((asic_id.hw_internal_rev >= 60) && (asic_id.hw_internal_rev < 80))) { | |||
110 | dc_version = DCE_VERSION_10_0; | |||
111 | break; | |||
112 | } | |||
113 | if (ASIC_REV_IS_POLARIS10_P(asic_id.hw_internal_rev)((asic_id.hw_internal_rev >= 80) && (asic_id.hw_internal_rev < 90)) || | |||
114 | ASIC_REV_IS_POLARIS11_M(asic_id.hw_internal_rev)((asic_id.hw_internal_rev >= 90) && (asic_id.hw_internal_rev < 100)) || | |||
115 | ASIC_REV_IS_POLARIS12_V(asic_id.hw_internal_rev)((asic_id.hw_internal_rev >= 100) && (asic_id.hw_internal_rev < 110))) { | |||
116 | dc_version = DCE_VERSION_11_2; | |||
117 | } | |||
118 | if (ASIC_REV_IS_VEGAM(asic_id.hw_internal_rev)(asic_id.hw_internal_rev >= 110)) | |||
119 | dc_version = DCE_VERSION_11_22; | |||
120 | break; | |||
121 | case FAMILY_AI141: | |||
122 | if (ASICREV_IS_VEGA20_P(asic_id.hw_internal_rev)((asic_id.hw_internal_rev >= 40) && (asic_id.hw_internal_rev < 0xFF))) | |||
123 | dc_version = DCE_VERSION_12_1; | |||
124 | else | |||
125 | dc_version = DCE_VERSION_12_0; | |||
126 | break; | |||
127 | case FAMILY_RV142: | |||
128 | dc_version = DCN_VERSION_1_0; | |||
129 | if (ASICREV_IS_RAVEN2(asic_id.hw_internal_rev)((asic_id.hw_internal_rev >= 0x81) && (asic_id.hw_internal_rev < 0x91))) | |||
130 | dc_version = DCN_VERSION_1_01; | |||
131 | if (ASICREV_IS_RENOIR(asic_id.hw_internal_rev)((asic_id.hw_internal_rev >= 0x91) && (asic_id.hw_internal_rev < 0xF0))) | |||
132 | dc_version = DCN_VERSION_2_1; | |||
133 | if (ASICREV_IS_GREEN_SARDINE(asic_id.hw_internal_rev)((asic_id.hw_internal_rev >= 0xA1) && (asic_id.hw_internal_rev < 0xFF))) | |||
134 | dc_version = DCN_VERSION_2_1; | |||
135 | break; | |||
136 | ||||
137 | case FAMILY_NV143: | |||
138 | dc_version = DCN_VERSION_2_0; | |||
139 | if (asic_id.chip_id == DEVICE_ID_NV_13FE0x13FE || asic_id.chip_id == DEVICE_ID_NV_143F0x143F) { | |||
140 | dc_version = DCN_VERSION_2_01; | |||
141 | break; | |||
142 | } | |||
143 | if (ASICREV_IS_SIENNA_CICHLID_P(asic_id.hw_internal_rev)((asic_id.hw_internal_rev >= NV_SIENNA_CICHLID_P_A0) && (asic_id.hw_internal_rev < NV_DIMGREY_CAVEFISH_P_A0))) | |||
144 | dc_version = DCN_VERSION_3_0; | |||
145 | if (ASICREV_IS_DIMGREY_CAVEFISH_P(asic_id.hw_internal_rev)((asic_id.hw_internal_rev >= NV_DIMGREY_CAVEFISH_P_A0) && (asic_id.hw_internal_rev < NV_BEIGE_GOBY_P_A0))) | |||
146 | dc_version = DCN_VERSION_3_02; | |||
147 | if (ASICREV_IS_BEIGE_GOBY_P(asic_id.hw_internal_rev)((asic_id.hw_internal_rev >= NV_BEIGE_GOBY_P_A0) && (asic_id.hw_internal_rev < NV_UNKNOWN))) | |||
148 | dc_version = DCN_VERSION_3_03; | |||
149 | break; | |||
150 | ||||
151 | case FAMILY_VGH144: | |||
152 | dc_version = DCN_VERSION_3_01; | |||
153 | break; | |||
154 | ||||
155 | case FAMILY_YELLOW_CARP146: | |||
156 | if (ASICREV_IS_YELLOW_CARP(asic_id.hw_internal_rev)((asic_id.hw_internal_rev >= 0x01) && (asic_id.hw_internal_rev < 0xFF))) | |||
157 | dc_version = DCN_VERSION_3_1; | |||
158 | break; | |||
159 | case AMDGPU_FAMILY_GC_10_3_6149: | |||
160 | if (ASICREV_IS_GC_10_3_6(asic_id.hw_internal_rev)((asic_id.hw_internal_rev >= 0x01) && (asic_id.hw_internal_rev < 0xFF))) | |||
161 | dc_version = DCN_VERSION_3_15; | |||
162 | break; | |||
163 | case AMDGPU_FAMILY_GC_10_3_7151: | |||
164 | if (ASICREV_IS_GC_10_3_7(asic_id.hw_internal_rev)((asic_id.hw_internal_rev >= 0x01) && (asic_id.hw_internal_rev < 0xFF))) | |||
165 | dc_version = DCN_VERSION_3_16; | |||
166 | break; | |||
167 | case AMDGPU_FAMILY_GC_11_0_0145: | |||
168 | dc_version = DCN_VERSION_3_2; | |||
169 | if (ASICREV_IS_GC_11_0_2(asic_id.hw_internal_rev)(asic_id.hw_internal_rev >= 0x10 && asic_id.hw_internal_rev < 0x20)) | |||
170 | dc_version = DCN_VERSION_3_21; | |||
171 | break; | |||
172 | case AMDGPU_FAMILY_GC_11_0_1148: | |||
173 | dc_version = DCN_VERSION_3_14; | |||
174 | break; | |||
175 | default: | |||
176 | dc_version = DCE_VERSION_UNKNOWN; | |||
177 | break; | |||
178 | } | |||
179 | return dc_version; | |||
180 | } | |||
181 | ||||
182 | struct resource_pool *dc_create_resource_pool(struct dc *dc, | |||
183 | const struct dc_init_data *init_data, | |||
184 | enum dce_version dc_version) | |||
185 | { | |||
186 | struct resource_pool *res_pool = NULL((void *)0); | |||
187 | ||||
188 | switch (dc_version) { | |||
189 | #if defined(CONFIG_DRM_AMD_DC_SI) | |||
190 | case DCE_VERSION_6_0: | |||
191 | res_pool = dce60_create_resource_pool( | |||
192 | init_data->num_virtual_links, dc); | |||
193 | break; | |||
194 | case DCE_VERSION_6_1: | |||
195 | res_pool = dce61_create_resource_pool( | |||
196 | init_data->num_virtual_links, dc); | |||
197 | break; | |||
198 | case DCE_VERSION_6_4: | |||
199 | res_pool = dce64_create_resource_pool( | |||
200 | init_data->num_virtual_links, dc); | |||
201 | break; | |||
202 | #endif | |||
203 | case DCE_VERSION_8_0: | |||
204 | res_pool = dce80_create_resource_pool( | |||
205 | init_data->num_virtual_links, dc); | |||
206 | break; | |||
207 | case DCE_VERSION_8_1: | |||
208 | res_pool = dce81_create_resource_pool( | |||
209 | init_data->num_virtual_links, dc); | |||
210 | break; | |||
211 | case DCE_VERSION_8_3: | |||
212 | res_pool = dce83_create_resource_pool( | |||
213 | init_data->num_virtual_links, dc); | |||
214 | break; | |||
215 | case DCE_VERSION_10_0: | |||
216 | res_pool = dce100_create_resource_pool( | |||
217 | init_data->num_virtual_links, dc); | |||
218 | break; | |||
219 | case DCE_VERSION_11_0: | |||
220 | res_pool = dce110_create_resource_pool( | |||
221 | init_data->num_virtual_links, dc, | |||
222 | init_data->asic_id); | |||
223 | break; | |||
224 | case DCE_VERSION_11_2: | |||
225 | case DCE_VERSION_11_22: | |||
226 | res_pool = dce112_create_resource_pool( | |||
227 | init_data->num_virtual_links, dc); | |||
228 | break; | |||
229 | case DCE_VERSION_12_0: | |||
230 | case DCE_VERSION_12_1: | |||
231 | res_pool = dce120_create_resource_pool( | |||
232 | init_data->num_virtual_links, dc); | |||
233 | break; | |||
234 | ||||
235 | #if defined(CONFIG_DRM_AMD_DC_DCN1) | |||
236 | case DCN_VERSION_1_0: | |||
237 | case DCN_VERSION_1_01: | |||
238 | res_pool = dcn10_create_resource_pool(init_data, dc); | |||
239 | break; | |||
240 | case DCN_VERSION_2_0: | |||
241 | res_pool = dcn20_create_resource_pool(init_data, dc); | |||
242 | break; | |||
243 | case DCN_VERSION_2_1: | |||
244 | res_pool = dcn21_create_resource_pool(init_data, dc); | |||
245 | break; | |||
246 | case DCN_VERSION_2_01: | |||
247 | res_pool = dcn201_create_resource_pool(init_data, dc); | |||
248 | break; | |||
249 | case DCN_VERSION_3_0: | |||
250 | res_pool = dcn30_create_resource_pool(init_data, dc); | |||
251 | break; | |||
252 | case DCN_VERSION_3_01: | |||
253 | res_pool = dcn301_create_resource_pool(init_data, dc); | |||
254 | break; | |||
255 | case DCN_VERSION_3_02: | |||
256 | res_pool = dcn302_create_resource_pool(init_data, dc); | |||
257 | break; | |||
258 | case DCN_VERSION_3_03: | |||
259 | res_pool = dcn303_create_resource_pool(init_data, dc); | |||
260 | break; | |||
261 | case DCN_VERSION_3_1: | |||
262 | res_pool = dcn31_create_resource_pool(init_data, dc); | |||
263 | break; | |||
264 | case DCN_VERSION_3_14: | |||
265 | res_pool = dcn314_create_resource_pool(init_data, dc); | |||
266 | break; | |||
267 | case DCN_VERSION_3_15: | |||
268 | res_pool = dcn315_create_resource_pool(init_data, dc); | |||
269 | break; | |||
270 | case DCN_VERSION_3_16: | |||
271 | res_pool = dcn316_create_resource_pool(init_data, dc); | |||
272 | break; | |||
273 | case DCN_VERSION_3_2: | |||
274 | res_pool = dcn32_create_resource_pool(init_data, dc); | |||
275 | break; | |||
276 | case DCN_VERSION_3_21: | |||
277 | res_pool = dcn321_create_resource_pool(init_data, dc); | |||
278 | break; | |||
279 | #endif | |||
280 | default: | |||
281 | break; | |||
282 | } | |||
283 | ||||
284 | if (res_pool != NULL((void *)0)) { | |||
285 | if (dc->ctx->dc_bios->fw_info_valid) { | |||
286 | res_pool->ref_clocks.xtalin_clock_inKhz = | |||
287 | dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency; | |||
288 | /* initialize with firmware data first, no all | |||
289 | * ASIC have DCCG SW component. FPGA or | |||
290 | * simulation need initialization of | |||
291 | * dccg_ref_clock_inKhz, dchub_ref_clock_inKhz | |||
292 | * with xtalin_clock_inKhz | |||
293 | */ | |||
294 | res_pool->ref_clocks.dccg_ref_clock_inKhz = | |||
295 | res_pool->ref_clocks.xtalin_clock_inKhz; | |||
296 | res_pool->ref_clocks.dchub_ref_clock_inKhz = | |||
297 | res_pool->ref_clocks.xtalin_clock_inKhz; | |||
298 | } else | |||
299 | ASSERT_CRITICAL(false)do { if (({ int __ret = !!(!(0)); if (__ret) printf("WARNING %s failed at %s:%d\n" , "!(0)", "/usr/src/sys/dev/pci/drm/amd/display/dc/core/dc_resource.c" , 299); __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); | |||
300 | } | |||
301 | ||||
302 | return res_pool; | |||
303 | } | |||
304 | ||||
305 | void dc_destroy_resource_pool(struct dc *dc) | |||
306 | { | |||
307 | if (dc) { | |||
308 | if (dc->res_pool) | |||
309 | dc->res_pool->funcs->destroy(&dc->res_pool); | |||
310 | ||||
311 | kfree(dc->hwseq); | |||
312 | } | |||
313 | } | |||
314 | ||||
315 | static void update_num_audio( | |||
316 | const struct resource_straps *straps, | |||
317 | unsigned int *num_audio, | |||
318 | struct audio_support *aud_support) | |||
319 | { | |||
320 | aud_support->dp_audio = true1; | |||
321 | aud_support->hdmi_audio_native = false0; | |||
322 | aud_support->hdmi_audio_on_dongle = false0; | |||
323 | ||||
324 | if (straps->hdmi_disable == 0) { | |||
325 | if (straps->dc_pinstraps_audio & 0x2) { | |||
326 | aud_support->hdmi_audio_on_dongle = true1; | |||
327 | aud_support->hdmi_audio_native = true1; | |||
328 | } | |||
329 | } | |||
330 | ||||
331 | switch (straps->audio_stream_number) { | |||
332 | case 0: /* multi streams supported */ | |||
333 | break; | |||
334 | case 1: /* multi streams not supported */ | |||
335 | *num_audio = 1; | |||
336 | break; | |||
337 | default: | |||
338 | DC_ERR("DC: unexpected audio fuse!\n")do { __drm_err("DC: unexpected audio fuse!\n"); do { ___drm_dbg (((void *)0), DRM_UT_DRIVER, "%s():%d\n", __func__, 338); do { } while (0); } while (0); } while (0); | |||
339 | } | |||
340 | } | |||
341 | ||||
342 | bool_Bool resource_construct( | |||
343 | unsigned int num_virtual_links, | |||
344 | struct dc *dc, | |||
345 | struct resource_pool *pool, | |||
346 | const struct resource_create_funcs *create_funcs) | |||
347 | { | |||
348 | struct dc_context *ctx = dc->ctx; | |||
349 | const struct resource_caps *caps = pool->res_cap; | |||
350 | int i; | |||
351 | unsigned int num_audio = caps->num_audio; | |||
352 | struct resource_straps straps = {0}; | |||
353 | ||||
354 | if (create_funcs->read_dce_straps) | |||
355 | create_funcs->read_dce_straps(dc->ctx, &straps); | |||
356 | ||||
357 | pool->audio_count = 0; | |||
358 | if (create_funcs->create_audio) { | |||
359 | /* find the total number of streams available via the | |||
360 | * AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_CONFIGURATION_DEFAULT | |||
361 | * registers (one for each pin) starting from pin 1 | |||
362 | * up to the max number of audio pins. | |||
363 | * We stop on the first pin where | |||
364 | * PORT_CONNECTIVITY == 1 (as instructed by HW team). | |||
365 | */ | |||
366 | update_num_audio(&straps, &num_audio, &pool->audio_support); | |||
367 | for (i = 0; i < caps->num_audio; i++) { | |||
368 | struct audio *aud = create_funcs->create_audio(ctx, i); | |||
369 | ||||
370 | if (aud == NULL((void *)0)) { | |||
371 | DC_ERR("DC: failed to create audio!\n")do { __drm_err("DC: failed to create audio!\n"); do { ___drm_dbg (((void *)0), DRM_UT_DRIVER, "%s():%d\n", __func__, 371); do { } while (0); } while (0); } while (0); | |||
372 | return false0; | |||
373 | } | |||
374 | if (!aud->funcs->endpoint_valid(aud)) { | |||
375 | aud->funcs->destroy(&aud); | |||
376 | break; | |||
377 | } | |||
378 | pool->audios[i] = aud; | |||
379 | pool->audio_count++; | |||
380 | } | |||
381 | } | |||
382 | ||||
383 | pool->stream_enc_count = 0; | |||
384 | if (create_funcs->create_stream_encoder) { | |||
385 | for (i = 0; i < caps->num_stream_encoder; i++) { | |||
386 | pool->stream_enc[i] = create_funcs->create_stream_encoder(i, ctx); | |||
387 | if (pool->stream_enc[i] == NULL((void *)0)) | |||
388 | DC_ERR("DC: failed to create stream_encoder!\n")do { __drm_err("DC: failed to create stream_encoder!\n"); do { ___drm_dbg(((void *)0), DRM_UT_DRIVER, "%s():%d\n", __func__ , 388); do {} while (0); } while (0); } while (0); | |||
389 | pool->stream_enc_count++; | |||
390 | } | |||
391 | } | |||
392 | ||||
393 | pool->hpo_dp_stream_enc_count = 0; | |||
394 | if (create_funcs->create_hpo_dp_stream_encoder) { | |||
395 | for (i = 0; i < caps->num_hpo_dp_stream_encoder; i++) { | |||
396 | pool->hpo_dp_stream_enc[i] = create_funcs->create_hpo_dp_stream_encoder(i+ENGINE_ID_HPO_DP_0, ctx); | |||
397 | if (pool->hpo_dp_stream_enc[i] == NULL((void *)0)) | |||
398 | DC_ERR("DC: failed to create HPO DP stream encoder!\n")do { __drm_err("DC: failed to create HPO DP stream encoder!\n" ); do { ___drm_dbg(((void *)0), DRM_UT_DRIVER, "%s():%d\n", __func__ , 398); do {} while (0); } while (0); } while (0); | |||
399 | pool->hpo_dp_stream_enc_count++; | |||
400 | ||||
401 | } | |||
402 | } | |||
403 | ||||
404 | pool->hpo_dp_link_enc_count = 0; | |||
405 | if (create_funcs->create_hpo_dp_link_encoder) { | |||
406 | for (i = 0; i < caps->num_hpo_dp_link_encoder; i++) { | |||
407 | pool->hpo_dp_link_enc[i] = create_funcs->create_hpo_dp_link_encoder(i, ctx); | |||
408 | if (pool->hpo_dp_link_enc[i] == NULL((void *)0)) | |||
409 | DC_ERR("DC: failed to create HPO DP link encoder!\n")do { __drm_err("DC: failed to create HPO DP link encoder!\n") ; do { ___drm_dbg(((void *)0), DRM_UT_DRIVER, "%s():%d\n", __func__ , 409); do {} while (0); } while (0); } while (0); | |||
410 | pool->hpo_dp_link_enc_count++; | |||
411 | } | |||
412 | } | |||
413 | ||||
414 | for (i = 0; i < caps->num_mpc_3dlut; i++) { | |||
415 | pool->mpc_lut[i] = dc_create_3dlut_func(); | |||
416 | if (pool->mpc_lut[i] == NULL((void *)0)) | |||
417 | DC_ERR("DC: failed to create MPC 3dlut!\n")do { __drm_err("DC: failed to create MPC 3dlut!\n"); do { ___drm_dbg (((void *)0), DRM_UT_DRIVER, "%s():%d\n", __func__, 417); do { } while (0); } while (0); } while (0); | |||
418 | pool->mpc_shaper[i] = dc_create_transfer_func(); | |||
419 | if (pool->mpc_shaper[i] == NULL((void *)0)) | |||
420 | DC_ERR("DC: failed to create MPC shaper!\n")do { __drm_err("DC: failed to create MPC shaper!\n"); do { ___drm_dbg (((void *)0), DRM_UT_DRIVER, "%s():%d\n", __func__, 420); do { } while (0); } while (0); } while (0); | |||
421 | } | |||
422 | ||||
423 | dc->caps.dynamic_audio = false0; | |||
424 | if (pool->audio_count < pool->stream_enc_count) { | |||
425 | dc->caps.dynamic_audio = true1; | |||
426 | } | |||
427 | for (i = 0; i < num_virtual_links; i++) { | |||
428 | pool->stream_enc[pool->stream_enc_count] = | |||
429 | virtual_stream_encoder_create( | |||
430 | ctx, ctx->dc_bios); | |||
431 | if (pool->stream_enc[pool->stream_enc_count] == NULL((void *)0)) { | |||
432 | DC_ERR("DC: failed to create stream_encoder!\n")do { __drm_err("DC: failed to create stream_encoder!\n"); do { ___drm_dbg(((void *)0), DRM_UT_DRIVER, "%s():%d\n", __func__ , 432); do {} while (0); } while (0); } while (0); | |||
433 | return false0; | |||
434 | } | |||
435 | pool->stream_enc_count++; | |||
436 | } | |||
437 | ||||
438 | dc->hwseq = create_funcs->create_hwseq(ctx); | |||
439 | ||||
440 | return true1; | |||
441 | } | |||
442 | static int find_matching_clock_source( | |||
443 | const struct resource_pool *pool, | |||
444 | struct clock_source *clock_source) | |||
445 | { | |||
446 | ||||
447 | int i; | |||
448 | ||||
449 | for (i = 0; i < pool->clk_src_count; i++) { | |||
450 | if (pool->clock_sources[i] == clock_source) | |||
451 | return i; | |||
452 | } | |||
453 | return -1; | |||
454 | } | |||
455 | ||||
456 | void resource_unreference_clock_source( | |||
457 | struct resource_context *res_ctx, | |||
458 | const struct resource_pool *pool, | |||
459 | struct clock_source *clock_source) | |||
460 | { | |||
461 | int i = find_matching_clock_source(pool, clock_source); | |||
462 | ||||
463 | if (i > -1) | |||
464 | res_ctx->clock_source_ref_count[i]--; | |||
465 | ||||
466 | if (pool->dp_clock_source == clock_source) | |||
467 | res_ctx->dp_clock_source_ref_count--; | |||
468 | } | |||
469 | ||||
470 | void resource_reference_clock_source( | |||
471 | struct resource_context *res_ctx, | |||
472 | const struct resource_pool *pool, | |||
473 | struct clock_source *clock_source) | |||
474 | { | |||
475 | int i = find_matching_clock_source(pool, clock_source); | |||
476 | ||||
477 | if (i > -1) | |||
478 | res_ctx->clock_source_ref_count[i]++; | |||
479 | ||||
480 | if (pool->dp_clock_source == clock_source) | |||
481 | res_ctx->dp_clock_source_ref_count++; | |||
482 | } | |||
483 | ||||
484 | int resource_get_clock_source_reference( | |||
485 | struct resource_context *res_ctx, | |||
486 | const struct resource_pool *pool, | |||
487 | struct clock_source *clock_source) | |||
488 | { | |||
489 | int i = find_matching_clock_source(pool, clock_source); | |||
490 | ||||
491 | if (i > -1) | |||
492 | return res_ctx->clock_source_ref_count[i]; | |||
493 | ||||
494 | if (pool->dp_clock_source == clock_source) | |||
495 | return res_ctx->dp_clock_source_ref_count; | |||
496 | ||||
497 | return -1; | |||
498 | } | |||
499 | ||||
500 | bool_Bool resource_are_vblanks_synchronizable( | |||
501 | struct dc_stream_state *stream1, | |||
502 | struct dc_stream_state *stream2) | |||
503 | { | |||
504 | uint32_t base60_refresh_rates[] = {10, 20, 5}; | |||
505 | uint8_t i; | |||
506 | uint8_t rr_count = ARRAY_SIZE(base60_refresh_rates)(sizeof((base60_refresh_rates)) / sizeof((base60_refresh_rates )[0])); | |||
507 | uint64_t frame_time_diff; | |||
508 | ||||
509 | if (stream1->ctx->dc->config.vblank_alignment_dto_params && | |||
510 | stream1->ctx->dc->config.vblank_alignment_max_frame_time_diff > 0 && | |||
511 | dc_is_dp_signal(stream1->signal) && | |||
512 | dc_is_dp_signal(stream2->signal) && | |||
513 | false0 == stream1->has_non_synchronizable_pclk && | |||
514 | false0 == stream2->has_non_synchronizable_pclk && | |||
515 | stream1->timing.flags.VBLANK_SYNCHRONIZABLE && | |||
516 | stream2->timing.flags.VBLANK_SYNCHRONIZABLE) { | |||
517 | /* disable refresh rates higher than 60Hz for now */ | |||
518 | if (stream1->timing.pix_clk_100hz*100/stream1->timing.h_total/ | |||
519 | stream1->timing.v_total > 60) | |||
520 | return false0; | |||
521 | if (stream2->timing.pix_clk_100hz*100/stream2->timing.h_total/ | |||
522 | stream2->timing.v_total > 60) | |||
523 | return false0; | |||
524 | frame_time_diff = (uint64_t)10000 * | |||
525 | stream1->timing.h_total * | |||
526 | stream1->timing.v_total * | |||
527 | stream2->timing.pix_clk_100hz; | |||
528 | frame_time_diff = div_u64(frame_time_diff, stream1->timing.pix_clk_100hz); | |||
529 | frame_time_diff = div_u64(frame_time_diff, stream2->timing.h_total); | |||
530 | frame_time_diff = div_u64(frame_time_diff, stream2->timing.v_total); | |||
531 | for (i = 0; i < rr_count; i++) { | |||
532 | int64_t diff = (int64_t)div_u64(frame_time_diff * base60_refresh_rates[i], 10) - 10000; | |||
533 | ||||
534 | if (diff < 0) | |||
535 | diff = -diff; | |||
536 | if (diff < stream1->ctx->dc->config.vblank_alignment_max_frame_time_diff) | |||
537 | return true1; | |||
538 | } | |||
539 | } | |||
540 | return false0; | |||
541 | } | |||
542 | ||||
543 | bool_Bool resource_are_streams_timing_synchronizable( | |||
544 | struct dc_stream_state *stream1, | |||
545 | struct dc_stream_state *stream2) | |||
546 | { | |||
547 | if (stream1->timing.h_total != stream2->timing.h_total) | |||
548 | return false0; | |||
549 | ||||
550 | if (stream1->timing.v_total != stream2->timing.v_total) | |||
551 | return false0; | |||
552 | ||||
553 | if (stream1->timing.h_addressable | |||
554 | != stream2->timing.h_addressable) | |||
555 | return false0; | |||
556 | ||||
557 | if (stream1->timing.v_addressable | |||
558 | != stream2->timing.v_addressable) | |||
559 | return false0; | |||
560 | ||||
561 | if (stream1->timing.v_front_porch | |||
562 | != stream2->timing.v_front_porch) | |||
563 | return false0; | |||
564 | ||||
565 | if (stream1->timing.pix_clk_100hz | |||
566 | != stream2->timing.pix_clk_100hz) | |||
567 | return false0; | |||
568 | ||||
569 | if (stream1->clamping.c_depth != stream2->clamping.c_depth) | |||
570 | return false0; | |||
571 | ||||
572 | if (stream1->phy_pix_clk != stream2->phy_pix_clk | |||
573 | && (!dc_is_dp_signal(stream1->signal) | |||
574 | || !dc_is_dp_signal(stream2->signal))) | |||
575 | return false0; | |||
576 | ||||
577 | if (stream1->view_format != stream2->view_format) | |||
578 | return false0; | |||
579 | ||||
580 | if (stream1->ignore_msa_timing_param || stream2->ignore_msa_timing_param) | |||
581 | return false0; | |||
582 | ||||
583 | return true1; | |||
584 | } | |||
585 | static bool_Bool is_dp_and_hdmi_sharable( | |||
586 | struct dc_stream_state *stream1, | |||
587 | struct dc_stream_state *stream2) | |||
588 | { | |||
589 | if (stream1->ctx->dc->caps.disable_dp_clk_share) | |||
590 | return false0; | |||
591 | ||||
592 | if (stream1->clamping.c_depth != COLOR_DEPTH_888 || | |||
593 | stream2->clamping.c_depth != COLOR_DEPTH_888) | |||
594 | return false0; | |||
595 | ||||
596 | return true1; | |||
597 | ||||
598 | } | |||
599 | ||||
600 | static bool_Bool is_sharable_clk_src( | |||
601 | const struct pipe_ctx *pipe_with_clk_src, | |||
602 | const struct pipe_ctx *pipe) | |||
603 | { | |||
604 | if (pipe_with_clk_src->clock_source == NULL((void *)0)) | |||
605 | return false0; | |||
606 | ||||
607 | if (pipe_with_clk_src->stream->signal == SIGNAL_TYPE_VIRTUAL) | |||
608 | return false0; | |||
609 | ||||
610 | if (dc_is_dp_signal(pipe_with_clk_src->stream->signal) || | |||
611 | (dc_is_dp_signal(pipe->stream->signal) && | |||
612 | !is_dp_and_hdmi_sharable(pipe_with_clk_src->stream, | |||
613 | pipe->stream))) | |||
614 | return false0; | |||
615 | ||||
616 | if (dc_is_hdmi_signal(pipe_with_clk_src->stream->signal) | |||
617 | && dc_is_dual_link_signal(pipe->stream->signal)) | |||
618 | return false0; | |||
619 | ||||
620 | if (dc_is_hdmi_signal(pipe->stream->signal) | |||
621 | && dc_is_dual_link_signal(pipe_with_clk_src->stream->signal)) | |||
622 | return false0; | |||
623 | ||||
624 | if (!resource_are_streams_timing_synchronizable( | |||
625 | pipe_with_clk_src->stream, pipe->stream)) | |||
626 | return false0; | |||
627 | ||||
628 | return true1; | |||
629 | } | |||
630 | ||||
631 | struct clock_source *resource_find_used_clk_src_for_sharing( | |||
632 | struct resource_context *res_ctx, | |||
633 | struct pipe_ctx *pipe_ctx) | |||
634 | { | |||
635 | int i; | |||
636 | ||||
637 | for (i = 0; i < MAX_PIPES6; i++) { | |||
638 | if (is_sharable_clk_src(&res_ctx->pipe_ctx[i], pipe_ctx)) | |||
639 | return res_ctx->pipe_ctx[i].clock_source; | |||
640 | } | |||
641 | ||||
642 | return NULL((void *)0); | |||
643 | } | |||
644 | ||||
645 | static enum pixel_format convert_pixel_format_to_dalsurface( | |||
646 | enum surface_pixel_format surface_pixel_format) | |||
647 | { | |||
648 | enum pixel_format dal_pixel_format = PIXEL_FORMAT_UNKNOWN; | |||
649 | ||||
650 | switch (surface_pixel_format) { | |||
651 | case SURFACE_PIXEL_FORMAT_GRPH_PALETA_256_COLORS: | |||
652 | dal_pixel_format = PIXEL_FORMAT_INDEX8; | |||
653 | break; | |||
654 | case SURFACE_PIXEL_FORMAT_GRPH_ARGB1555: | |||
655 | dal_pixel_format = PIXEL_FORMAT_RGB565; | |||
656 | break; | |||
657 | case SURFACE_PIXEL_FORMAT_GRPH_RGB565: | |||
658 | dal_pixel_format = PIXEL_FORMAT_RGB565; | |||
659 | break; | |||
660 | case SURFACE_PIXEL_FORMAT_GRPH_ARGB8888: | |||
661 | dal_pixel_format = PIXEL_FORMAT_ARGB8888; | |||
662 | break; | |||
663 | case SURFACE_PIXEL_FORMAT_GRPH_ABGR8888: | |||
664 | dal_pixel_format = PIXEL_FORMAT_ARGB8888; | |||
665 | break; | |||
666 | case SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010: | |||
667 | dal_pixel_format = PIXEL_FORMAT_ARGB2101010; | |||
668 | break; | |||
669 | case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010: | |||
670 | dal_pixel_format = PIXEL_FORMAT_ARGB2101010; | |||
671 | break; | |||
672 | case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010_XR_BIAS: | |||
673 | dal_pixel_format = PIXEL_FORMAT_ARGB2101010_XRBIAS; | |||
674 | break; | |||
675 | case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F: | |||
676 | case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F: | |||
677 | dal_pixel_format = PIXEL_FORMAT_FP16; | |||
678 | break; | |||
679 | case SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr: | |||
680 | case SURFACE_PIXEL_FORMAT_VIDEO_420_YCrCb: | |||
681 | dal_pixel_format = PIXEL_FORMAT_420BPP8; | |||
682 | break; | |||
683 | case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCbCr: | |||
684 | case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb: | |||
685 | dal_pixel_format = PIXEL_FORMAT_420BPP10; | |||
686 | break; | |||
687 | case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616: | |||
688 | case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616: | |||
689 | default: | |||
690 | dal_pixel_format = PIXEL_FORMAT_UNKNOWN; | |||
691 | break; | |||
692 | } | |||
693 | return dal_pixel_format; | |||
694 | } | |||
695 | ||||
696 | static inline void get_vp_scan_direction( | |||
697 | enum dc_rotation_angle rotation, | |||
698 | bool_Bool horizontal_mirror, | |||
699 | bool_Bool *orthogonal_rotation, | |||
700 | bool_Bool *flip_vert_scan_dir, | |||
701 | bool_Bool *flip_horz_scan_dir) | |||
702 | { | |||
703 | *orthogonal_rotation = false0; | |||
704 | *flip_vert_scan_dir = false0; | |||
705 | *flip_horz_scan_dir = false0; | |||
706 | if (rotation == ROTATION_ANGLE_180) { | |||
707 | *flip_vert_scan_dir = true1; | |||
708 | *flip_horz_scan_dir = true1; | |||
709 | } else if (rotation == ROTATION_ANGLE_90) { | |||
710 | *orthogonal_rotation = true1; | |||
711 | *flip_horz_scan_dir = true1; | |||
712 | } else if (rotation == ROTATION_ANGLE_270) { | |||
713 | *orthogonal_rotation = true1; | |||
714 | *flip_vert_scan_dir = true1; | |||
715 | } | |||
716 | ||||
717 | if (horizontal_mirror) | |||
718 | *flip_horz_scan_dir = !*flip_horz_scan_dir; | |||
719 | } | |||
720 | ||||
721 | int get_num_mpc_splits(struct pipe_ctx *pipe) | |||
722 | { | |||
723 | int mpc_split_count = 0; | |||
724 | struct pipe_ctx *other_pipe = pipe->bottom_pipe; | |||
725 | ||||
726 | while (other_pipe && other_pipe->plane_state == pipe->plane_state) { | |||
727 | mpc_split_count++; | |||
728 | other_pipe = other_pipe->bottom_pipe; | |||
729 | } | |||
730 | other_pipe = pipe->top_pipe; | |||
731 | while (other_pipe && other_pipe->plane_state == pipe->plane_state) { | |||
732 | mpc_split_count++; | |||
733 | other_pipe = other_pipe->top_pipe; | |||
734 | } | |||
735 | ||||
736 | return mpc_split_count; | |||
737 | } | |||
738 | ||||
739 | int get_num_odm_splits(struct pipe_ctx *pipe) | |||
740 | { | |||
741 | int odm_split_count = 0; | |||
742 | struct pipe_ctx *next_pipe = pipe->next_odm_pipe; | |||
743 | while (next_pipe) { | |||
744 | odm_split_count++; | |||
745 | next_pipe = next_pipe->next_odm_pipe; | |||
746 | } | |||
747 | pipe = pipe->prev_odm_pipe; | |||
748 | while (pipe) { | |||
749 | odm_split_count++; | |||
750 | pipe = pipe->prev_odm_pipe; | |||
751 | } | |||
752 | return odm_split_count; | |||
753 | } | |||
754 | ||||
755 | static void calculate_split_count_and_index(struct pipe_ctx *pipe_ctx, int *split_count, int *split_idx) | |||
756 | { | |||
757 | *split_count = get_num_odm_splits(pipe_ctx); | |||
758 | *split_idx = 0; | |||
759 | if (*split_count == 0) { | |||
760 | /*Check for mpc split*/ | |||
761 | struct pipe_ctx *split_pipe = pipe_ctx->top_pipe; | |||
762 | ||||
763 | *split_count = get_num_mpc_splits(pipe_ctx); | |||
764 | while (split_pipe && split_pipe->plane_state == pipe_ctx->plane_state) { | |||
765 | (*split_idx)++; | |||
766 | split_pipe = split_pipe->top_pipe; | |||
767 | } | |||
768 | ||||
769 | /* MPO window on right side of ODM split */ | |||
770 | if (split_pipe && split_pipe->prev_odm_pipe && !pipe_ctx->prev_odm_pipe) | |||
771 | (*split_idx)++; | |||
772 | } else { | |||
773 | /*Get odm split index*/ | |||
774 | struct pipe_ctx *split_pipe = pipe_ctx->prev_odm_pipe; | |||
775 | ||||
776 | while (split_pipe) { | |||
777 | (*split_idx)++; | |||
778 | split_pipe = split_pipe->prev_odm_pipe; | |||
779 | } | |||
780 | } | |||
781 | } | |||
782 | ||||
783 | /* | |||
784 | * This is a preliminary vp size calculation to allow us to check taps support. | |||
785 | * The result is completely overridden afterwards. | |||
786 | */ | |||
787 | static void calculate_viewport_size(struct pipe_ctx *pipe_ctx) | |||
788 | { | |||
789 | struct scaler_data *data = &pipe_ctx->plane_res.scl_data; | |||
790 | ||||
791 | data->viewport.width = dc_fixpt_ceil(dc_fixpt_mul_int(data->ratios.horz, data->recout.width)); | |||
792 | data->viewport.height = dc_fixpt_ceil(dc_fixpt_mul_int(data->ratios.vert, data->recout.height)); | |||
793 | data->viewport_c.width = dc_fixpt_ceil(dc_fixpt_mul_int(data->ratios.horz_c, data->recout.width)); | |||
794 | data->viewport_c.height = dc_fixpt_ceil(dc_fixpt_mul_int(data->ratios.vert_c, data->recout.height)); | |||
795 | if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_90 || | |||
796 | pipe_ctx->plane_state->rotation == ROTATION_ANGLE_270) { | |||
797 | swap(data->viewport.width, data->viewport.height)do { __typeof(data->viewport.width) __tmp = (data->viewport .width); (data->viewport.width) = (data->viewport.height ); (data->viewport.height) = __tmp; } while(0); | |||
798 | swap(data->viewport_c.width, data->viewport_c.height)do { __typeof(data->viewport_c.width) __tmp = (data->viewport_c .width); (data->viewport_c.width) = (data->viewport_c.height ); (data->viewport_c.height) = __tmp; } while(0); | |||
799 | } | |||
800 | } | |||
801 | ||||
802 | static void calculate_recout(struct pipe_ctx *pipe_ctx) | |||
803 | { | |||
804 | const struct dc_plane_state *plane_state = pipe_ctx->plane_state; | |||
805 | const struct dc_stream_state *stream = pipe_ctx->stream; | |||
806 | struct scaler_data *data = &pipe_ctx->plane_res.scl_data; | |||
807 | struct rect surf_clip = plane_state->clip_rect; | |||
808 | bool_Bool split_tb = stream->view_format == VIEW_3D_FORMAT_TOP_AND_BOTTOM; | |||
809 | int split_count, split_idx; | |||
810 | ||||
811 | calculate_split_count_and_index(pipe_ctx, &split_count, &split_idx); | |||
812 | if (stream->view_format == VIEW_3D_FORMAT_SIDE_BY_SIDE) | |||
813 | split_idx = 0; | |||
814 | ||||
815 | /* | |||
816 | * Only the leftmost ODM pipe should be offset by a nonzero distance | |||
817 | */ | |||
818 | if (pipe_ctx->top_pipe && pipe_ctx->top_pipe->prev_odm_pipe && !pipe_ctx->prev_odm_pipe) { | |||
819 | /* MPO window on right side of ODM split */ | |||
820 | data->recout.x = stream->dst.x + (surf_clip.x - stream->src.x - stream->src.width/2) * | |||
821 | stream->dst.width / stream->src.width; | |||
822 | } else if (!pipe_ctx->prev_odm_pipe || split_idx == split_count) { | |||
823 | data->recout.x = stream->dst.x; | |||
824 | if (stream->src.x < surf_clip.x) | |||
825 | data->recout.x += (surf_clip.x - stream->src.x) * stream->dst.width | |||
826 | / stream->src.width; | |||
827 | } else | |||
828 | data->recout.x = 0; | |||
829 | ||||
830 | if (stream->src.x > surf_clip.x) | |||
831 | surf_clip.width -= stream->src.x - surf_clip.x; | |||
832 | data->recout.width = surf_clip.width * stream->dst.width / stream->src.width; | |||
833 | if (data->recout.width + data->recout.x > stream->dst.x + stream->dst.width) | |||
834 | data->recout.width = stream->dst.x + stream->dst.width - data->recout.x; | |||
835 | ||||
836 | data->recout.y = stream->dst.y; | |||
837 | if (stream->src.y < surf_clip.y) | |||
838 | data->recout.y += (surf_clip.y - stream->src.y) * stream->dst.height | |||
839 | / stream->src.height; | |||
840 | else if (stream->src.y > surf_clip.y) | |||
841 | surf_clip.height -= stream->src.y - surf_clip.y; | |||
842 | ||||
843 | data->recout.height = surf_clip.height * stream->dst.height / stream->src.height; | |||
844 | if (data->recout.height + data->recout.y > stream->dst.y + stream->dst.height) | |||
845 | data->recout.height = stream->dst.y + stream->dst.height - data->recout.y; | |||
846 | ||||
847 | /* Handle h & v split */ | |||
848 | if (split_tb) { | |||
849 | ASSERT(data->recout.height % 2 == 0)do { if (({ static int __warned; int __ret = !!(!(data->recout .height % 2 == 0)); if (__ret && !__warned) { printf( "WARNING %s failed at %s:%d\n", "!(data->recout.height % 2 == 0)" , "/usr/src/sys/dev/pci/drm/amd/display/dc/core/dc_resource.c" , 849); __warned = 1; } __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); | |||
850 | data->recout.height /= 2; | |||
851 | } else if (split_count) { | |||
852 | if (!pipe_ctx->next_odm_pipe && !pipe_ctx->prev_odm_pipe) { | |||
853 | /* extra pixels in the division remainder need to go to pipes after | |||
854 | * the extra pixel index minus one(epimo) defined here as: | |||
855 | */ | |||
856 | int epimo = split_count - data->recout.width % (split_count + 1); | |||
857 | ||||
858 | data->recout.x += (data->recout.width / (split_count + 1)) * split_idx; | |||
859 | if (split_idx > epimo) | |||
860 | data->recout.x += split_idx - epimo - 1; | |||
861 | ASSERT(stream->view_format != VIEW_3D_FORMAT_SIDE_BY_SIDE || data->recout.width % 2 == 0)do { if (({ static int __warned; int __ret = !!(!(stream-> view_format != VIEW_3D_FORMAT_SIDE_BY_SIDE || data->recout .width % 2 == 0)); if (__ret && !__warned) { printf("WARNING %s failed at %s:%d\n" , "!(stream->view_format != VIEW_3D_FORMAT_SIDE_BY_SIDE || data->recout.width % 2 == 0)" , "/usr/src/sys/dev/pci/drm/amd/display/dc/core/dc_resource.c" , 861); __warned = 1; } __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); | |||
862 | data->recout.width = data->recout.width / (split_count + 1) + (split_idx > epimo ? 1 : 0); | |||
863 | } else { | |||
864 | /* odm */ | |||
865 | if (split_idx == split_count) { | |||
866 | /* rightmost pipe is the remainder recout */ | |||
867 | data->recout.width -= data->h_active * split_count - data->recout.x; | |||
868 | ||||
869 | /* ODM combine cases with MPO we can get negative widths */ | |||
870 | if (data->recout.width < 0) | |||
871 | data->recout.width = 0; | |||
872 | ||||
873 | data->recout.x = 0; | |||
874 | } else | |||
875 | data->recout.width = data->h_active - data->recout.x; | |||
876 | } | |||
877 | } | |||
878 | } | |||
879 | ||||
880 | static void calculate_scaling_ratios(struct pipe_ctx *pipe_ctx) | |||
881 | { | |||
882 | const struct dc_plane_state *plane_state = pipe_ctx->plane_state; | |||
883 | const struct dc_stream_state *stream = pipe_ctx->stream; | |||
884 | struct rect surf_src = plane_state->src_rect; | |||
885 | const int in_w = stream->src.width; | |||
886 | const int in_h = stream->src.height; | |||
887 | const int out_w = stream->dst.width; | |||
888 | const int out_h = stream->dst.height; | |||
889 | ||||
890 | /*Swap surf_src height and width since scaling ratios are in recout rotation*/ | |||
891 | if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_90 || | |||
892 | pipe_ctx->plane_state->rotation == ROTATION_ANGLE_270) | |||
893 | swap(surf_src.height, surf_src.width)do { __typeof(surf_src.height) __tmp = (surf_src.height); (surf_src .height) = (surf_src.width); (surf_src.width) = __tmp; } while (0); | |||
894 | ||||
895 | pipe_ctx->plane_res.scl_data.ratios.horz = dc_fixpt_from_fraction( | |||
896 | surf_src.width, | |||
897 | plane_state->dst_rect.width); | |||
898 | pipe_ctx->plane_res.scl_data.ratios.vert = dc_fixpt_from_fraction( | |||
899 | surf_src.height, | |||
900 | plane_state->dst_rect.height); | |||
901 | ||||
902 | if (stream->view_format == VIEW_3D_FORMAT_SIDE_BY_SIDE) | |||
903 | pipe_ctx->plane_res.scl_data.ratios.horz.value *= 2; | |||
904 | else if (stream->view_format == VIEW_3D_FORMAT_TOP_AND_BOTTOM) | |||
905 | pipe_ctx->plane_res.scl_data.ratios.vert.value *= 2; | |||
906 | ||||
907 | pipe_ctx->plane_res.scl_data.ratios.vert.value = div64_s64( | |||
908 | pipe_ctx->plane_res.scl_data.ratios.vert.value * in_h, out_h); | |||
909 | pipe_ctx->plane_res.scl_data.ratios.horz.value = div64_s64( | |||
910 | pipe_ctx->plane_res.scl_data.ratios.horz.value * in_w, out_w); | |||
911 | ||||
912 | pipe_ctx->plane_res.scl_data.ratios.horz_c = pipe_ctx->plane_res.scl_data.ratios.horz; | |||
913 | pipe_ctx->plane_res.scl_data.ratios.vert_c = pipe_ctx->plane_res.scl_data.ratios.vert; | |||
914 | ||||
915 | if (pipe_ctx->plane_res.scl_data.format == PIXEL_FORMAT_420BPP8 | |||
916 | || pipe_ctx->plane_res.scl_data.format == PIXEL_FORMAT_420BPP10) { | |||
917 | pipe_ctx->plane_res.scl_data.ratios.horz_c.value /= 2; | |||
918 | pipe_ctx->plane_res.scl_data.ratios.vert_c.value /= 2; | |||
919 | } | |||
920 | pipe_ctx->plane_res.scl_data.ratios.horz = dc_fixpt_truncate( | |||
921 | pipe_ctx->plane_res.scl_data.ratios.horz, 19); | |||
922 | pipe_ctx->plane_res.scl_data.ratios.vert = dc_fixpt_truncate( | |||
923 | pipe_ctx->plane_res.scl_data.ratios.vert, 19); | |||
924 | pipe_ctx->plane_res.scl_data.ratios.horz_c = dc_fixpt_truncate( | |||
925 | pipe_ctx->plane_res.scl_data.ratios.horz_c, 19); | |||
926 | pipe_ctx->plane_res.scl_data.ratios.vert_c = dc_fixpt_truncate( | |||
927 | pipe_ctx->plane_res.scl_data.ratios.vert_c, 19); | |||
928 | } | |||
929 | ||||
930 | ||||
931 | /* | |||
932 | * We completely calculate vp offset, size and inits here based entirely on scaling | |||
933 | * ratios and recout for pixel perfect pipe combine. | |||
934 | */ | |||
935 | static void calculate_init_and_vp( | |||
936 | bool_Bool flip_scan_dir, | |||
937 | int recout_offset_within_recout_full, | |||
938 | int recout_size, | |||
939 | int src_size, | |||
940 | int taps, | |||
941 | struct fixed31_32 ratio, | |||
942 | struct fixed31_32 *init, | |||
943 | int *vp_offset, | |||
944 | int *vp_size) | |||
945 | { | |||
946 | struct fixed31_32 temp; | |||
947 | int int_part; | |||
948 | ||||
949 | /* | |||
950 | * First of the taps starts sampling pixel number <init_int_part> corresponding to recout | |||
951 | * pixel 1. Next recout pixel samples int part of <init + scaling ratio> and so on. | |||
952 | * All following calculations are based on this logic. | |||
953 | * | |||
954 | * Init calculated according to formula: | |||
955 | * init = (scaling_ratio + number_of_taps + 1) / 2 | |||
956 | * init_bot = init + scaling_ratio | |||
957 | * to get pixel perfect combine add the fraction from calculating vp offset | |||
958 | */ | |||
959 | temp = dc_fixpt_mul_int(ratio, recout_offset_within_recout_full); | |||
960 | *vp_offset = dc_fixpt_floor(temp); | |||
961 | temp.value &= 0xffffffff; | |||
962 | *init = dc_fixpt_truncate(dc_fixpt_add(dc_fixpt_div_int( | |||
| ||||
963 | dc_fixpt_add_int(ratio, taps + 1), 2), temp), 19); | |||
964 | /* | |||
965 | * If viewport has non 0 offset and there are more taps than covered by init then | |||
966 | * we should decrease the offset and increase init so we are never sampling | |||
967 | * outside of viewport. | |||
968 | */ | |||
969 | int_part = dc_fixpt_floor(*init); | |||
970 | if (int_part < taps) { | |||
971 | int_part = taps - int_part; | |||
972 | if (int_part > *vp_offset) | |||
973 | int_part = *vp_offset; | |||
974 | *vp_offset -= int_part; | |||
975 | *init = dc_fixpt_add_int(*init, int_part); | |||
976 | } | |||
977 | /* | |||
978 | * If taps are sampling outside of viewport at end of recout and there are more pixels | |||
979 | * available in the surface we should increase the viewport size, regardless set vp to | |||
980 | * only what is used. | |||
981 | */ | |||
982 | temp = dc_fixpt_add(*init, dc_fixpt_mul_int(ratio, recout_size - 1)); | |||
983 | *vp_size = dc_fixpt_floor(temp); | |||
984 | if (*vp_size + *vp_offset > src_size) | |||
985 | *vp_size = src_size - *vp_offset; | |||
986 | ||||
987 | /* We did all the math assuming we are scanning same direction as display does, | |||
988 | * however mirror/rotation changes how vp scans vs how it is offset. If scan direction | |||
989 | * is flipped we simply need to calculate offset from the other side of plane. | |||
990 | * Note that outside of viewport all scaling hardware works in recout space. | |||
991 | */ | |||
992 | if (flip_scan_dir) | |||
993 | *vp_offset = src_size - *vp_offset - *vp_size; | |||
994 | } | |||
995 | ||||
996 | static void calculate_inits_and_viewports(struct pipe_ctx *pipe_ctx) | |||
997 | { | |||
998 | const struct dc_plane_state *plane_state = pipe_ctx->plane_state; | |||
999 | const struct dc_stream_state *stream = pipe_ctx->stream; | |||
1000 | struct scaler_data *data = &pipe_ctx->plane_res.scl_data; | |||
1001 | struct rect src = plane_state->src_rect; | |||
1002 | int vpc_div = (data->format == PIXEL_FORMAT_420BPP8 | |||
1003 | || data->format == PIXEL_FORMAT_420BPP10) ? 2 : 1; | |||
1004 | int split_count, split_idx, ro_lb, ro_tb, recout_full_x, recout_full_y; | |||
1005 | bool_Bool orthogonal_rotation, flip_vert_scan_dir, flip_horz_scan_dir; | |||
1006 | ||||
1007 | calculate_split_count_and_index(pipe_ctx, &split_count, &split_idx); | |||
1008 | /* | |||
1009 | * recout full is what the recout would have been if we didnt clip | |||
1010 | * the source plane at all. We only care about left(ro_lb) and top(ro_tb) | |||
1011 | * offsets of recout within recout full because those are the directions | |||
1012 | * we scan from and therefore the only ones that affect inits. | |||
1013 | */ | |||
1014 | recout_full_x = stream->dst.x + (plane_state->dst_rect.x - stream->src.x) | |||
1015 | * stream->dst.width / stream->src.width; | |||
1016 | recout_full_y = stream->dst.y + (plane_state->dst_rect.y - stream->src.y) | |||
1017 | * stream->dst.height / stream->src.height; | |||
1018 | if (pipe_ctx->prev_odm_pipe && split_idx) | |||
1019 | ro_lb = data->h_active * split_idx - recout_full_x; | |||
1020 | else if (pipe_ctx->top_pipe && pipe_ctx->top_pipe->prev_odm_pipe) | |||
1021 | ro_lb = data->h_active * split_idx - recout_full_x + data->recout.x; | |||
1022 | else | |||
1023 | ro_lb = data->recout.x - recout_full_x; | |||
1024 | ro_tb = data->recout.y - recout_full_y; | |||
1025 | ASSERT(ro_lb >= 0 && ro_tb >= 0)do { if (({ static int __warned; int __ret = !!(!(ro_lb >= 0 && ro_tb >= 0)); if (__ret && !__warned ) { printf("WARNING %s failed at %s:%d\n", "!(ro_lb >= 0 && ro_tb >= 0)" , "/usr/src/sys/dev/pci/drm/amd/display/dc/core/dc_resource.c" , 1025); __warned = 1; } __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); | |||
1026 | ||||
1027 | /* | |||
1028 | * Work in recout rotation since that requires less transformations | |||
1029 | */ | |||
1030 | get_vp_scan_direction( | |||
1031 | plane_state->rotation, | |||
1032 | plane_state->horizontal_mirror, | |||
1033 | &orthogonal_rotation, | |||
1034 | &flip_vert_scan_dir, | |||
1035 | &flip_horz_scan_dir); | |||
1036 | ||||
1037 | if (orthogonal_rotation) { | |||
1038 | swap(src.width, src.height)do { __typeof(src.width) __tmp = (src.width); (src.width) = ( src.height); (src.height) = __tmp; } while(0); | |||
1039 | swap(flip_vert_scan_dir, flip_horz_scan_dir)do { __typeof(flip_vert_scan_dir) __tmp = (flip_vert_scan_dir ); (flip_vert_scan_dir) = (flip_horz_scan_dir); (flip_horz_scan_dir ) = __tmp; } while(0); | |||
1040 | } | |||
1041 | ||||
1042 | calculate_init_and_vp( | |||
1043 | flip_horz_scan_dir, | |||
1044 | ro_lb, | |||
1045 | data->recout.width, | |||
1046 | src.width, | |||
1047 | data->taps.h_taps, | |||
1048 | data->ratios.horz, | |||
1049 | &data->inits.h, | |||
1050 | &data->viewport.x, | |||
1051 | &data->viewport.width); | |||
1052 | calculate_init_and_vp( | |||
1053 | flip_horz_scan_dir, | |||
1054 | ro_lb, | |||
1055 | data->recout.width, | |||
1056 | src.width / vpc_div, | |||
1057 | data->taps.h_taps_c, | |||
1058 | data->ratios.horz_c, | |||
1059 | &data->inits.h_c, | |||
1060 | &data->viewport_c.x, | |||
1061 | &data->viewport_c.width); | |||
1062 | calculate_init_and_vp( | |||
1063 | flip_vert_scan_dir, | |||
1064 | ro_tb, | |||
1065 | data->recout.height, | |||
1066 | src.height, | |||
1067 | data->taps.v_taps, | |||
1068 | data->ratios.vert, | |||
1069 | &data->inits.v, | |||
1070 | &data->viewport.y, | |||
1071 | &data->viewport.height); | |||
1072 | calculate_init_and_vp( | |||
1073 | flip_vert_scan_dir, | |||
1074 | ro_tb, | |||
1075 | data->recout.height, | |||
1076 | src.height / vpc_div, | |||
1077 | data->taps.v_taps_c, | |||
1078 | data->ratios.vert_c, | |||
1079 | &data->inits.v_c, | |||
1080 | &data->viewport_c.y, | |||
1081 | &data->viewport_c.height); | |||
1082 | if (orthogonal_rotation) { | |||
1083 | swap(data->viewport.x, data->viewport.y)do { __typeof(data->viewport.x) __tmp = (data->viewport .x); (data->viewport.x) = (data->viewport.y); (data-> viewport.y) = __tmp; } while(0); | |||
1084 | swap(data->viewport.width, data->viewport.height)do { __typeof(data->viewport.width) __tmp = (data->viewport .width); (data->viewport.width) = (data->viewport.height ); (data->viewport.height) = __tmp; } while(0); | |||
1085 | swap(data->viewport_c.x, data->viewport_c.y)do { __typeof(data->viewport_c.x) __tmp = (data->viewport_c .x); (data->viewport_c.x) = (data->viewport_c.y); (data ->viewport_c.y) = __tmp; } while(0); | |||
1086 | swap(data->viewport_c.width, data->viewport_c.height)do { __typeof(data->viewport_c.width) __tmp = (data->viewport_c .width); (data->viewport_c.width) = (data->viewport_c.height ); (data->viewport_c.height) = __tmp; } while(0); | |||
1087 | } | |||
1088 | data->viewport.x += src.x; | |||
1089 | data->viewport.y += src.y; | |||
1090 | ASSERT(src.x % vpc_div == 0 && src.y % vpc_div == 0)do { if (({ static int __warned; int __ret = !!(!(src.x % vpc_div == 0 && src.y % vpc_div == 0)); if (__ret && !__warned) { printf("WARNING %s failed at %s:%d\n", "!(src.x % vpc_div == 0 && src.y % vpc_div == 0)" , "/usr/src/sys/dev/pci/drm/amd/display/dc/core/dc_resource.c" , 1090); __warned = 1; } __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); | |||
1091 | data->viewport_c.x += src.x / vpc_div; | |||
1092 | data->viewport_c.y += src.y / vpc_div; | |||
1093 | } | |||
1094 | ||||
1095 | bool_Bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx) | |||
1096 | { | |||
1097 | const struct dc_plane_state *plane_state = pipe_ctx->plane_state; | |||
1098 | struct dc_crtc_timing *timing = &pipe_ctx->stream->timing; | |||
1099 | bool_Bool res = false0; | |||
1100 | DC_LOGGER_INIT(pipe_ctx->stream->ctx->logger); | |||
1101 | ||||
1102 | /* Invalid input */ | |||
1103 | if (!plane_state->dst_rect.width || | |||
1104 | !plane_state->dst_rect.height || | |||
1105 | !plane_state->src_rect.width || | |||
1106 | !plane_state->src_rect.height) { | |||
1107 | ASSERT(0)do { if (({ static int __warned; int __ret = !!(!(0)); if (__ret && !__warned) { printf("WARNING %s failed at %s:%d\n" , "!(0)", "/usr/src/sys/dev/pci/drm/amd/display/dc/core/dc_resource.c" , 1107); __warned = 1; } __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); | |||
1108 | return false0; | |||
1109 | } | |||
1110 | ||||
1111 | pipe_ctx->plane_res.scl_data.format = convert_pixel_format_to_dalsurface( | |||
1112 | pipe_ctx->plane_state->format); | |||
1113 | ||||
1114 | /* Timing borders are part of vactive that we are also supposed to skip in addition | |||
1115 | * to any stream dst offset. Since dm logic assumes dst is in addressable | |||
1116 | * space we need to add the left and top borders to dst offsets temporarily. | |||
1117 | * TODO: fix in DM, stream dst is supposed to be in vactive | |||
1118 | */ | |||
1119 | pipe_ctx->stream->dst.x += timing->h_border_left; | |||
1120 | pipe_ctx->stream->dst.y += timing->v_border_top; | |||
1121 | ||||
1122 | /* Calculate H and V active size */ | |||
1123 | pipe_ctx->plane_res.scl_data.h_active = timing->h_addressable + | |||
1124 | timing->h_border_left + timing->h_border_right; | |||
1125 | pipe_ctx->plane_res.scl_data.v_active = timing->v_addressable + | |||
1126 | timing->v_border_top + timing->v_border_bottom; | |||
1127 | if (pipe_ctx->next_odm_pipe || pipe_ctx->prev_odm_pipe) { | |||
1128 | pipe_ctx->plane_res.scl_data.h_active /= get_num_odm_splits(pipe_ctx) + 1; | |||
1129 | ||||
1130 | DC_LOG_SCALER("%s pipe %d: next_odm_pipe:%d prev_odm_pipe:%d\n",do { } while(0) | |||
1131 | __func__,do { } while(0) | |||
1132 | pipe_ctx->pipe_idx,do { } while(0) | |||
1133 | pipe_ctx->next_odm_pipe ? pipe_ctx->next_odm_pipe->pipe_idx : -1,do { } while(0) | |||
1134 | pipe_ctx->prev_odm_pipe ? pipe_ctx->prev_odm_pipe->pipe_idx : -1)do { } while(0); | |||
1135 | } /* ODM + windows MPO, where window is on either right or left ODM half */ | |||
1136 | else if (pipe_ctx->top_pipe && (pipe_ctx->top_pipe->next_odm_pipe || pipe_ctx->top_pipe->prev_odm_pipe)) { | |||
1137 | ||||
1138 | pipe_ctx->plane_res.scl_data.h_active /= get_num_odm_splits(pipe_ctx->top_pipe) + 1; | |||
1139 | ||||
1140 | DC_LOG_SCALER("%s ODM + windows MPO: pipe:%d top_pipe:%d top_pipe->next_odm_pipe:%d top_pipe->prev_odm_pipe:%d\n",do { } while(0) | |||
1141 | __func__,do { } while(0) | |||
1142 | pipe_ctx->pipe_idx,do { } while(0) | |||
1143 | pipe_ctx->top_pipe->pipe_idx,do { } while(0) | |||
1144 | pipe_ctx->top_pipe->next_odm_pipe ? pipe_ctx->top_pipe->next_odm_pipe->pipe_idx : -1,do { } while(0) | |||
1145 | pipe_ctx->top_pipe->prev_odm_pipe ? pipe_ctx->top_pipe->prev_odm_pipe->pipe_idx : -1)do { } while(0); | |||
1146 | } | |||
1147 | /* depends on h_active */ | |||
1148 | calculate_recout(pipe_ctx); | |||
1149 | /* depends on pixel format */ | |||
1150 | calculate_scaling_ratios(pipe_ctx); | |||
1151 | /* depends on scaling ratios and recout, does not calculate offset yet */ | |||
1152 | calculate_viewport_size(pipe_ctx); | |||
1153 | ||||
1154 | if (!pipe_ctx->stream->ctx->dc->config.enable_windowed_mpo_odm) { | |||
1155 | /* Stopgap for validation of ODM + MPO on one side of screen case */ | |||
1156 | if (pipe_ctx->plane_res.scl_data.viewport.height < 1 || | |||
1157 | pipe_ctx->plane_res.scl_data.viewport.width < 1) | |||
1158 | return false0; | |||
1159 | } | |||
1160 | ||||
1161 | /* | |||
1162 | * LB calculations depend on vp size, h/v_active and scaling ratios | |||
1163 | * Setting line buffer pixel depth to 24bpp yields banding | |||
1164 | * on certain displays, such as the Sharp 4k. 36bpp is needed | |||
1165 | * to support SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616 and | |||
1166 | * SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616 with actual > 10 bpc | |||
1167 | * precision on DCN display engines, but apparently not for DCE, as | |||
1168 | * far as testing on DCE-11.2 and DCE-8 showed. Various DCE parts have | |||
1169 | * problems: Carrizo with DCE_VERSION_11_0 does not like 36 bpp lb depth, | |||
1170 | * neither do DCE-8 at 4k resolution, or DCE-11.2 (broken identify pixel | |||
1171 | * passthrough). Therefore only use 36 bpp on DCN where it is actually needed. | |||
1172 | */ | |||
1173 | if (plane_state->ctx->dce_version > DCE_VERSION_MAX) | |||
1174 | pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_36BPP; | |||
1175 | else | |||
1176 | pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_30BPP; | |||
1177 | ||||
1178 | pipe_ctx->plane_res.scl_data.lb_params.alpha_en = plane_state->per_pixel_alpha; | |||
1179 | ||||
1180 | if (pipe_ctx->plane_res.xfm != NULL((void *)0)) | |||
1181 | res = pipe_ctx->plane_res.xfm->funcs->transform_get_optimal_number_of_taps( | |||
1182 | pipe_ctx->plane_res.xfm, &pipe_ctx->plane_res.scl_data, &plane_state->scaling_quality); | |||
1183 | ||||
1184 | if (pipe_ctx->plane_res.dpp != NULL((void *)0)) | |||
1185 | res = pipe_ctx->plane_res.dpp->funcs->dpp_get_optimal_number_of_taps( | |||
1186 | pipe_ctx->plane_res.dpp, &pipe_ctx->plane_res.scl_data, &plane_state->scaling_quality); | |||
1187 | ||||
1188 | ||||
1189 | if (!res) { | |||
1190 | /* Try 24 bpp linebuffer */ | |||
1191 | pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_24BPP; | |||
1192 | ||||
1193 | if (pipe_ctx->plane_res.xfm != NULL((void *)0)) | |||
1194 | res = pipe_ctx->plane_res.xfm->funcs->transform_get_optimal_number_of_taps( | |||
1195 | pipe_ctx->plane_res.xfm, | |||
1196 | &pipe_ctx->plane_res.scl_data, | |||
1197 | &plane_state->scaling_quality); | |||
1198 | ||||
1199 | if (pipe_ctx->plane_res.dpp != NULL((void *)0)) | |||
1200 | res = pipe_ctx->plane_res.dpp->funcs->dpp_get_optimal_number_of_taps( | |||
1201 | pipe_ctx->plane_res.dpp, | |||
1202 | &pipe_ctx->plane_res.scl_data, | |||
1203 | &plane_state->scaling_quality); | |||
1204 | } | |||
1205 | ||||
1206 | /* | |||
1207 | * Depends on recout, scaling ratios, h_active and taps | |||
1208 | * May need to re-check lb size after this in some obscure scenario | |||
1209 | */ | |||
1210 | if (res) | |||
1211 | calculate_inits_and_viewports(pipe_ctx); | |||
1212 | ||||
1213 | /* | |||
1214 | * Handle side by side and top bottom 3d recout offsets after vp calculation | |||
1215 | * since 3d is special and needs to calculate vp as if there is no recout offset | |||
1216 | * This may break with rotation, good thing we aren't mixing hw rotation and 3d | |||
1217 | */ | |||
1218 | if (pipe_ctx->top_pipe && pipe_ctx->top_pipe->plane_state == plane_state) { | |||
1219 | ASSERT(plane_state->rotation == ROTATION_ANGLE_0 ||do { if (({ static int __warned; int __ret = !!(!(plane_state ->rotation == ROTATION_ANGLE_0 || (pipe_ctx->stream-> view_format != VIEW_3D_FORMAT_TOP_AND_BOTTOM && pipe_ctx ->stream->view_format != VIEW_3D_FORMAT_SIDE_BY_SIDE))) ; if (__ret && !__warned) { printf("WARNING %s failed at %s:%d\n" , "!(plane_state->rotation == ROTATION_ANGLE_0 || (pipe_ctx->stream->view_format != VIEW_3D_FORMAT_TOP_AND_BOTTOM && pipe_ctx->stream->view_format != VIEW_3D_FORMAT_SIDE_BY_SIDE))" , "/usr/src/sys/dev/pci/drm/amd/display/dc/core/dc_resource.c" , 1221); __warned = 1; } __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0) | |||
1220 | (pipe_ctx->stream->view_format != VIEW_3D_FORMAT_TOP_AND_BOTTOM &&do { if (({ static int __warned; int __ret = !!(!(plane_state ->rotation == ROTATION_ANGLE_0 || (pipe_ctx->stream-> view_format != VIEW_3D_FORMAT_TOP_AND_BOTTOM && pipe_ctx ->stream->view_format != VIEW_3D_FORMAT_SIDE_BY_SIDE))) ; if (__ret && !__warned) { printf("WARNING %s failed at %s:%d\n" , "!(plane_state->rotation == ROTATION_ANGLE_0 || (pipe_ctx->stream->view_format != VIEW_3D_FORMAT_TOP_AND_BOTTOM && pipe_ctx->stream->view_format != VIEW_3D_FORMAT_SIDE_BY_SIDE))" , "/usr/src/sys/dev/pci/drm/amd/display/dc/core/dc_resource.c" , 1221); __warned = 1; } __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0) | |||
1221 | pipe_ctx->stream->view_format != VIEW_3D_FORMAT_SIDE_BY_SIDE))do { if (({ static int __warned; int __ret = !!(!(plane_state ->rotation == ROTATION_ANGLE_0 || (pipe_ctx->stream-> view_format != VIEW_3D_FORMAT_TOP_AND_BOTTOM && pipe_ctx ->stream->view_format != VIEW_3D_FORMAT_SIDE_BY_SIDE))) ; if (__ret && !__warned) { printf("WARNING %s failed at %s:%d\n" , "!(plane_state->rotation == ROTATION_ANGLE_0 || (pipe_ctx->stream->view_format != VIEW_3D_FORMAT_TOP_AND_BOTTOM && pipe_ctx->stream->view_format != VIEW_3D_FORMAT_SIDE_BY_SIDE))" , "/usr/src/sys/dev/pci/drm/amd/display/dc/core/dc_resource.c" , 1221); __warned = 1; } __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); | |||
1222 | if (pipe_ctx->stream->view_format == VIEW_3D_FORMAT_TOP_AND_BOTTOM) | |||
1223 | pipe_ctx->plane_res.scl_data.recout.y += pipe_ctx->plane_res.scl_data.recout.height; | |||
1224 | else if (pipe_ctx->stream->view_format == VIEW_3D_FORMAT_SIDE_BY_SIDE) | |||
1225 | pipe_ctx->plane_res.scl_data.recout.x += pipe_ctx->plane_res.scl_data.recout.width; | |||
1226 | } | |||
1227 | ||||
1228 | if (!pipe_ctx->stream->ctx->dc->config.enable_windowed_mpo_odm) { | |||
1229 | if (pipe_ctx->plane_res.scl_data.viewport.height < MIN_VIEWPORT_SIZE12 || | |||
1230 | pipe_ctx->plane_res.scl_data.viewport.width < MIN_VIEWPORT_SIZE12) | |||
1231 | res = false0; | |||
1232 | } else { | |||
1233 | /* Clamp minimum viewport size */ | |||
1234 | if (pipe_ctx->plane_res.scl_data.viewport.height < MIN_VIEWPORT_SIZE12) | |||
1235 | pipe_ctx->plane_res.scl_data.viewport.height = MIN_VIEWPORT_SIZE12; | |||
1236 | if (pipe_ctx->plane_res.scl_data.viewport.width < MIN_VIEWPORT_SIZE12) | |||
1237 | pipe_ctx->plane_res.scl_data.viewport.width = MIN_VIEWPORT_SIZE12; | |||
1238 | } | |||
1239 | ||||
1240 | 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"do { } while(0) | |||
1241 | "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",do { } while(0) | |||
1242 | __func__,do { } while(0) | |||
1243 | pipe_ctx->pipe_idx,do { } while(0) | |||
1244 | pipe_ctx->plane_res.scl_data.viewport.height,do { } while(0) | |||
1245 | pipe_ctx->plane_res.scl_data.viewport.width,do { } while(0) | |||
1246 | pipe_ctx->plane_res.scl_data.viewport.x,do { } while(0) | |||
1247 | pipe_ctx->plane_res.scl_data.viewport.y,do { } while(0) | |||
1248 | pipe_ctx->plane_res.scl_data.recout.height,do { } while(0) | |||
1249 | pipe_ctx->plane_res.scl_data.recout.width,do { } while(0) | |||
1250 | pipe_ctx->plane_res.scl_data.recout.x,do { } while(0) | |||
1251 | pipe_ctx->plane_res.scl_data.recout.y,do { } while(0) | |||
1252 | pipe_ctx->plane_res.scl_data.h_active,do { } while(0) | |||
1253 | pipe_ctx->plane_res.scl_data.v_active,do { } while(0) | |||
1254 | plane_state->src_rect.height,do { } while(0) | |||
1255 | plane_state->src_rect.width,do { } while(0) | |||
1256 | plane_state->src_rect.x,do { } while(0) | |||
1257 | plane_state->src_rect.y,do { } while(0) | |||
1258 | plane_state->dst_rect.height,do { } while(0) | |||
1259 | plane_state->dst_rect.width,do { } while(0) | |||
1260 | plane_state->dst_rect.x,do { } while(0) | |||
1261 | plane_state->dst_rect.y,do { } while(0) | |||
1262 | plane_state->clip_rect.height,do { } while(0) | |||
1263 | plane_state->clip_rect.width,do { } while(0) | |||
1264 | plane_state->clip_rect.x,do { } while(0) | |||
1265 | plane_state->clip_rect.y)do { } while(0); | |||
1266 | ||||
1267 | pipe_ctx->stream->dst.x -= timing->h_border_left; | |||
1268 | pipe_ctx->stream->dst.y -= timing->v_border_top; | |||
1269 | ||||
1270 | return res; | |||
1271 | } | |||
1272 | ||||
1273 | ||||
1274 | enum dc_status resource_build_scaling_params_for_context( | |||
1275 | const struct dc *dc, | |||
1276 | struct dc_state *context) | |||
1277 | { | |||
1278 | int i; | |||
1279 | ||||
1280 | for (i = 0; i < MAX_PIPES6; i++) { | |||
1281 | if (context->res_ctx.pipe_ctx[i].plane_state != NULL((void *)0) && | |||
1282 | context->res_ctx.pipe_ctx[i].stream != NULL((void *)0)) | |||
1283 | if (!resource_build_scaling_params(&context->res_ctx.pipe_ctx[i])) | |||
1284 | return DC_FAIL_SCALING; | |||
1285 | } | |||
1286 | ||||
1287 | return DC_OK; | |||
1288 | } | |||
1289 | ||||
1290 | struct pipe_ctx *find_idle_secondary_pipe( | |||
1291 | struct resource_context *res_ctx, | |||
1292 | const struct resource_pool *pool, | |||
1293 | const struct pipe_ctx *primary_pipe) | |||
1294 | { | |||
1295 | int i; | |||
1296 | struct pipe_ctx *secondary_pipe = NULL((void *)0); | |||
1297 | ||||
1298 | /* | |||
1299 | * We add a preferred pipe mapping to avoid the chance that | |||
1300 | * MPCCs already in use will need to be reassigned to other trees. | |||
1301 | * For example, if we went with the strict, assign backwards logic: | |||
1302 | * | |||
1303 | * (State 1) | |||
1304 | * Display A on, no surface, top pipe = 0 | |||
1305 | * Display B on, no surface, top pipe = 1 | |||
1306 | * | |||
1307 | * (State 2) | |||
1308 | * Display A on, no surface, top pipe = 0 | |||
1309 | * Display B on, surface enable, top pipe = 1, bottom pipe = 5 | |||
1310 | * | |||
1311 | * (State 3) | |||
1312 | * Display A on, surface enable, top pipe = 0, bottom pipe = 5 | |||
1313 | * Display B on, surface enable, top pipe = 1, bottom pipe = 4 | |||
1314 | * | |||
1315 | * The state 2->3 transition requires remapping MPCC 5 from display B | |||
1316 | * to display A. | |||
1317 | * | |||
1318 | * However, with the preferred pipe logic, state 2 would look like: | |||
1319 | * | |||
1320 | * (State 2) | |||
1321 | * Display A on, no surface, top pipe = 0 | |||
1322 | * Display B on, surface enable, top pipe = 1, bottom pipe = 4 | |||
1323 | * | |||
1324 | * This would then cause 2->3 to not require remapping any MPCCs. | |||
1325 | */ | |||
1326 | if (primary_pipe) { | |||
1327 | int preferred_pipe_idx = (pool->pipe_count - 1) - primary_pipe->pipe_idx; | |||
1328 | if (res_ctx->pipe_ctx[preferred_pipe_idx].stream == NULL((void *)0)) { | |||
1329 | secondary_pipe = &res_ctx->pipe_ctx[preferred_pipe_idx]; | |||
1330 | secondary_pipe->pipe_idx = preferred_pipe_idx; | |||
1331 | } | |||
1332 | } | |||
1333 | ||||
1334 | /* | |||
1335 | * search backwards for the second pipe to keep pipe | |||
1336 | * assignment more consistent | |||
1337 | */ | |||
1338 | if (!secondary_pipe) | |||
1339 | for (i = pool->pipe_count - 1; i >= 0; i--) { | |||
1340 | if (res_ctx->pipe_ctx[i].stream == NULL((void *)0)) { | |||
1341 | secondary_pipe = &res_ctx->pipe_ctx[i]; | |||
1342 | secondary_pipe->pipe_idx = i; | |||
1343 | break; | |||
1344 | } | |||
1345 | } | |||
1346 | ||||
1347 | return secondary_pipe; | |||
1348 | } | |||
1349 | ||||
1350 | struct pipe_ctx *resource_get_head_pipe_for_stream( | |||
1351 | struct resource_context *res_ctx, | |||
1352 | struct dc_stream_state *stream) | |||
1353 | { | |||
1354 | int i; | |||
1355 | ||||
1356 | for (i = 0; i < MAX_PIPES6; i++) { | |||
1357 | if (res_ctx->pipe_ctx[i].stream == stream | |||
1358 | && !res_ctx->pipe_ctx[i].top_pipe | |||
1359 | && !res_ctx->pipe_ctx[i].prev_odm_pipe) | |||
1360 | return &res_ctx->pipe_ctx[i]; | |||
1361 | } | |||
1362 | return NULL((void *)0); | |||
1363 | } | |||
1364 | ||||
1365 | static struct pipe_ctx *resource_get_tail_pipe( | |||
1366 | struct resource_context *res_ctx, | |||
1367 | struct pipe_ctx *head_pipe) | |||
1368 | { | |||
1369 | struct pipe_ctx *tail_pipe; | |||
1370 | ||||
1371 | tail_pipe = head_pipe->bottom_pipe; | |||
1372 | ||||
1373 | while (tail_pipe) { | |||
1374 | head_pipe = tail_pipe; | |||
1375 | tail_pipe = tail_pipe->bottom_pipe; | |||
1376 | } | |||
1377 | ||||
1378 | return head_pipe; | |||
1379 | } | |||
1380 | ||||
1381 | /* | |||
1382 | * A free_pipe for a stream is defined here as a pipe | |||
1383 | * that has no surface attached yet | |||
1384 | */ | |||
1385 | static struct pipe_ctx *acquire_free_pipe_for_head( | |||
1386 | struct dc_state *context, | |||
1387 | const struct resource_pool *pool, | |||
1388 | struct pipe_ctx *head_pipe) | |||
1389 | { | |||
1390 | int i; | |||
1391 | struct resource_context *res_ctx = &context->res_ctx; | |||
1392 | ||||
1393 | if (!head_pipe->plane_state) | |||
1394 | return head_pipe; | |||
1395 | ||||
1396 | /* Re-use pipe already acquired for this stream if available*/ | |||
1397 | for (i = pool->pipe_count - 1; i >= 0; i--) { | |||
1398 | if (res_ctx->pipe_ctx[i].stream == head_pipe->stream && | |||
1399 | !res_ctx->pipe_ctx[i].plane_state) { | |||
1400 | return &res_ctx->pipe_ctx[i]; | |||
1401 | } | |||
1402 | } | |||
1403 | ||||
1404 | /* | |||
1405 | * At this point we have no re-useable pipe for this stream and we need | |||
1406 | * to acquire an idle one to satisfy the request | |||
1407 | */ | |||
1408 | ||||
1409 | if (!pool->funcs->acquire_idle_pipe_for_layer) { | |||
1410 | if (!pool->funcs->acquire_idle_pipe_for_head_pipe_in_layer) | |||
1411 | return NULL((void *)0); | |||
1412 | else | |||
1413 | return pool->funcs->acquire_idle_pipe_for_head_pipe_in_layer(context, pool, head_pipe->stream, head_pipe); | |||
1414 | } | |||
1415 | ||||
1416 | return pool->funcs->acquire_idle_pipe_for_layer(context, pool, head_pipe->stream); | |||
1417 | } | |||
1418 | ||||
1419 | static int acquire_first_split_pipe( | |||
1420 | struct resource_context *res_ctx, | |||
1421 | const struct resource_pool *pool, | |||
1422 | struct dc_stream_state *stream) | |||
1423 | { | |||
1424 | int i; | |||
1425 | ||||
1426 | for (i = 0; i < pool->pipe_count; i++) { | |||
1427 | struct pipe_ctx *split_pipe = &res_ctx->pipe_ctx[i]; | |||
1428 | ||||
1429 | if (split_pipe->top_pipe && | |||
1430 | split_pipe->top_pipe->plane_state == split_pipe->plane_state) { | |||
1431 | split_pipe->top_pipe->bottom_pipe = split_pipe->bottom_pipe; | |||
1432 | if (split_pipe->bottom_pipe) | |||
1433 | split_pipe->bottom_pipe->top_pipe = split_pipe->top_pipe; | |||
1434 | ||||
1435 | if (split_pipe->top_pipe->plane_state) | |||
1436 | resource_build_scaling_params(split_pipe->top_pipe); | |||
1437 | ||||
1438 | memset(split_pipe, 0, sizeof(*split_pipe))__builtin_memset((split_pipe), (0), (sizeof(*split_pipe))); | |||
1439 | split_pipe->stream_res.tg = pool->timing_generators[i]; | |||
1440 | split_pipe->plane_res.hubp = pool->hubps[i]; | |||
1441 | split_pipe->plane_res.ipp = pool->ipps[i]; | |||
1442 | split_pipe->plane_res.dpp = pool->dpps[i]; | |||
1443 | split_pipe->stream_res.opp = pool->opps[i]; | |||
1444 | split_pipe->plane_res.mpcc_inst = pool->dpps[i]->inst; | |||
1445 | split_pipe->pipe_idx = i; | |||
1446 | ||||
1447 | split_pipe->stream = stream; | |||
1448 | return i; | |||
1449 | } else if (split_pipe->prev_odm_pipe && | |||
1450 | split_pipe->prev_odm_pipe->plane_state == split_pipe->plane_state) { | |||
1451 | split_pipe->prev_odm_pipe->next_odm_pipe = split_pipe->next_odm_pipe; | |||
1452 | if (split_pipe->next_odm_pipe) | |||
1453 | split_pipe->next_odm_pipe->prev_odm_pipe = split_pipe->prev_odm_pipe; | |||
1454 | ||||
1455 | if (split_pipe->prev_odm_pipe->plane_state) | |||
1456 | resource_build_scaling_params(split_pipe->prev_odm_pipe); | |||
1457 | ||||
1458 | memset(split_pipe, 0, sizeof(*split_pipe))__builtin_memset((split_pipe), (0), (sizeof(*split_pipe))); | |||
1459 | split_pipe->stream_res.tg = pool->timing_generators[i]; | |||
1460 | split_pipe->plane_res.hubp = pool->hubps[i]; | |||
1461 | split_pipe->plane_res.ipp = pool->ipps[i]; | |||
1462 | split_pipe->plane_res.dpp = pool->dpps[i]; | |||
1463 | split_pipe->stream_res.opp = pool->opps[i]; | |||
1464 | split_pipe->plane_res.mpcc_inst = pool->dpps[i]->inst; | |||
1465 | split_pipe->pipe_idx = i; | |||
1466 | ||||
1467 | split_pipe->stream = stream; | |||
1468 | return i; | |||
1469 | } | |||
1470 | } | |||
1471 | return -1; | |||
1472 | } | |||
1473 | ||||
1474 | bool_Bool dc_add_plane_to_context( | |||
1475 | const struct dc *dc, | |||
1476 | struct dc_stream_state *stream, | |||
1477 | struct dc_plane_state *plane_state, | |||
1478 | struct dc_state *context) | |||
1479 | { | |||
1480 | int i; | |||
1481 | struct resource_pool *pool = dc->res_pool; | |||
1482 | struct pipe_ctx *head_pipe, *tail_pipe, *free_pipe; | |||
1483 | struct dc_stream_status *stream_status = NULL((void *)0); | |||
1484 | struct pipe_ctx *prev_right_head = NULL((void *)0); | |||
1485 | struct pipe_ctx *free_right_pipe = NULL((void *)0); | |||
1486 | struct pipe_ctx *prev_left_head = NULL((void *)0); | |||
1487 | ||||
1488 | DC_LOGGER_INIT(stream->ctx->logger); | |||
1489 | for (i = 0; i < context->stream_count; i++) | |||
1490 | if (context->streams[i] == stream) { | |||
1491 | stream_status = &context->stream_status[i]; | |||
1492 | break; | |||
1493 | } | |||
1494 | if (stream_status == NULL((void *)0)) { | |||
1495 | dm_error("Existing stream not found; failed to attach surface!\n")__drm_err("Existing stream not found; failed to attach surface!\n" ); | |||
1496 | return false0; | |||
1497 | } | |||
1498 | ||||
1499 | ||||
1500 | if (stream_status->plane_count == MAX_SURFACE_NUM4) { | |||
1501 | dm_error("Surface: can not attach plane_state %p! Maximum is: %d\n",__drm_err("Surface: can not attach plane_state %p! Maximum is: %d\n" , plane_state, 4) | |||
1502 | plane_state, MAX_SURFACE_NUM)__drm_err("Surface: can not attach plane_state %p! Maximum is: %d\n" , plane_state, 4); | |||
1503 | return false0; | |||
1504 | } | |||
1505 | ||||
1506 | head_pipe = resource_get_head_pipe_for_stream(&context->res_ctx, stream); | |||
1507 | ||||
1508 | if (!head_pipe) { | |||
1509 | dm_error("Head pipe not found for stream_state %p !\n", stream)__drm_err("Head pipe not found for stream_state %p !\n", stream ); | |||
1510 | return false0; | |||
1511 | } | |||
1512 | ||||
1513 | /* retain new surface, but only once per stream */ | |||
1514 | dc_plane_state_retain(plane_state); | |||
1515 | ||||
1516 | while (head_pipe) { | |||
1517 | free_pipe = acquire_free_pipe_for_head(context, pool, head_pipe); | |||
1518 | ||||
1519 | if (!free_pipe) { | |||
1520 | int pipe_idx = acquire_first_split_pipe(&context->res_ctx, pool, stream); | |||
1521 | if (pipe_idx >= 0) | |||
1522 | free_pipe = &context->res_ctx.pipe_ctx[pipe_idx]; | |||
1523 | } | |||
1524 | ||||
1525 | if (!free_pipe) { | |||
1526 | dc_plane_state_release(plane_state); | |||
1527 | return false0; | |||
1528 | } | |||
1529 | ||||
1530 | free_pipe->plane_state = plane_state; | |||
1531 | ||||
1532 | if (head_pipe != free_pipe) { | |||
1533 | tail_pipe = resource_get_tail_pipe(&context->res_ctx, head_pipe); | |||
1534 | ASSERT(tail_pipe)do { if (({ static int __warned; int __ret = !!(!(tail_pipe)) ; if (__ret && !__warned) { printf("WARNING %s failed at %s:%d\n" , "!(tail_pipe)", "/usr/src/sys/dev/pci/drm/amd/display/dc/core/dc_resource.c" , 1534); __warned = 1; } __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); | |||
1535 | ||||
1536 | /* ODM + window MPO, where MPO window is on right half only */ | |||
1537 | if (free_pipe->plane_state && | |||
1538 | (free_pipe->plane_state->clip_rect.x >= free_pipe->stream->src.x + free_pipe->stream->src.width/2) && | |||
1539 | tail_pipe->next_odm_pipe) { | |||
1540 | ||||
1541 | /* For ODM + window MPO, in 3 plane case, if we already have a MPO window on | |||
1542 | * the right side, then we will invalidate a 2nd one on the right side | |||
1543 | */ | |||
1544 | if (head_pipe->next_odm_pipe && tail_pipe->next_odm_pipe->bottom_pipe) { | |||
1545 | dc_plane_state_release(plane_state); | |||
1546 | return false0; | |||
1547 | } | |||
1548 | ||||
1549 | DC_LOG_SCALER("%s - ODM + window MPO(right). free_pipe:%d tail_pipe->next_odm_pipe:%d\n",do { } while(0) | |||
1550 | __func__,do { } while(0) | |||
1551 | free_pipe->pipe_idx,do { } while(0) | |||
1552 | tail_pipe->next_odm_pipe ? tail_pipe->next_odm_pipe->pipe_idx : -1)do { } while(0); | |||
1553 | ||||
1554 | /* | |||
1555 | * We want to avoid the case where the right side already has a pipe assigned to | |||
1556 | * it and is different from free_pipe ( which would cause trigger a pipe | |||
1557 | * reallocation ). | |||
1558 | * Check the old context to see if the right side already has a pipe allocated | |||
1559 | * - If not, continue to use free_pipe | |||
1560 | * - If the right side already has a pipe, use that pipe instead if its available | |||
1561 | */ | |||
1562 | ||||
1563 | /* | |||
1564 | * We also want to avoid the case where with three plane ( 2 MPO videos ), we have | |||
1565 | * both videos on the left side so one of the videos is invalidated. Then we | |||
1566 | * move the invalidated video back to the right side. If the order of the plane | |||
1567 | * states is such that the right MPO plane is processed first, the free pipe | |||
1568 | * selected by the head will be the left MPO pipe. But since there was no right | |||
1569 | * MPO pipe, it will assign the free pipe to the right MPO pipe instead and | |||
1570 | * a pipe reallocation will occur. | |||
1571 | * Check the old context to see if the left side already has a pipe allocated | |||
1572 | * - If not, continue to use free_pipe | |||
1573 | * - If the left side is already using this pipe, then pick another pipe for right | |||
1574 | */ | |||
1575 | ||||
1576 | prev_right_head = &dc->current_state->res_ctx.pipe_ctx[tail_pipe->next_odm_pipe->pipe_idx]; | |||
1577 | if ((prev_right_head->bottom_pipe) && | |||
1578 | (free_pipe->pipe_idx != prev_right_head->bottom_pipe->pipe_idx)) { | |||
1579 | free_right_pipe = acquire_free_pipe_for_head(context, pool, tail_pipe->next_odm_pipe); | |||
1580 | } else { | |||
1581 | prev_left_head = &dc->current_state->res_ctx.pipe_ctx[head_pipe->pipe_idx]; | |||
1582 | if ((prev_left_head->bottom_pipe) && | |||
1583 | (free_pipe->pipe_idx == prev_left_head->bottom_pipe->pipe_idx)) { | |||
1584 | free_right_pipe = acquire_free_pipe_for_head(context, pool, head_pipe); | |||
1585 | } | |||
1586 | } | |||
1587 | ||||
1588 | if (free_right_pipe) { | |||
1589 | free_pipe->stream = NULL((void *)0); | |||
1590 | memset(&free_pipe->stream_res, 0, sizeof(struct stream_resource))__builtin_memset((&free_pipe->stream_res), (0), (sizeof (struct stream_resource))); | |||
1591 | memset(&free_pipe->plane_res, 0, sizeof(struct plane_resource))__builtin_memset((&free_pipe->plane_res), (0), (sizeof (struct plane_resource))); | |||
1592 | free_pipe->plane_state = NULL((void *)0); | |||
1593 | free_pipe->pipe_idx = 0; | |||
1594 | free_right_pipe->plane_state = plane_state; | |||
1595 | free_pipe = free_right_pipe; | |||
1596 | } | |||
1597 | ||||
1598 | free_pipe->stream_res.tg = tail_pipe->next_odm_pipe->stream_res.tg; | |||
1599 | free_pipe->stream_res.abm = tail_pipe->next_odm_pipe->stream_res.abm; | |||
1600 | free_pipe->stream_res.opp = tail_pipe->next_odm_pipe->stream_res.opp; | |||
1601 | free_pipe->stream_res.stream_enc = tail_pipe->next_odm_pipe->stream_res.stream_enc; | |||
1602 | free_pipe->stream_res.audio = tail_pipe->next_odm_pipe->stream_res.audio; | |||
1603 | free_pipe->clock_source = tail_pipe->next_odm_pipe->clock_source; | |||
1604 | ||||
1605 | free_pipe->top_pipe = tail_pipe->next_odm_pipe; | |||
1606 | tail_pipe->next_odm_pipe->bottom_pipe = free_pipe; | |||
1607 | } else if (free_pipe->plane_state && | |||
1608 | (free_pipe->plane_state->clip_rect.x >= free_pipe->stream->src.x + free_pipe->stream->src.width/2) | |||
1609 | && head_pipe->next_odm_pipe) { | |||
1610 | ||||
1611 | /* For ODM + window MPO, support 3 plane ( 2 MPO ) case. | |||
1612 | * Here we have a desktop ODM + left window MPO and a new MPO window appears | |||
1613 | * on the right side only. It fails the first case, because tail_pipe is the | |||
1614 | * left window MPO, so it has no next_odm_pipe. So in this scenario, we check | |||
1615 | * for head_pipe->next_odm_pipe instead | |||
1616 | */ | |||
1617 | DC_LOG_SCALER("%s - ODM + win MPO (left) + win MPO (right). free_pipe:%d head_pipe->next_odm:%d\n",do { } while(0) | |||
1618 | __func__,do { } while(0) | |||
1619 | free_pipe->pipe_idx,do { } while(0) | |||
1620 | head_pipe->next_odm_pipe ? head_pipe->next_odm_pipe->pipe_idx : -1)do { } while(0); | |||
1621 | ||||
1622 | /* | |||
1623 | * We want to avoid the case where the right side already has a pipe assigned to | |||
1624 | * it and is different from free_pipe ( which would cause trigger a pipe | |||
1625 | * reallocation ). | |||
1626 | * Check the old context to see if the right side already has a pipe allocated | |||
1627 | * - If not, continue to use free_pipe | |||
1628 | * - If the right side already has a pipe, use that pipe instead if its available | |||
1629 | */ | |||
1630 | prev_right_head = &dc->current_state->res_ctx.pipe_ctx[head_pipe->next_odm_pipe->pipe_idx]; | |||
1631 | if ((prev_right_head->bottom_pipe) && | |||
1632 | (free_pipe->pipe_idx != prev_right_head->bottom_pipe->pipe_idx)) { | |||
1633 | free_right_pipe = acquire_free_pipe_for_head(context, pool, head_pipe->next_odm_pipe); | |||
1634 | if (free_right_pipe) { | |||
1635 | free_pipe->stream = NULL((void *)0); | |||
1636 | memset(&free_pipe->stream_res, 0, sizeof(struct stream_resource))__builtin_memset((&free_pipe->stream_res), (0), (sizeof (struct stream_resource))); | |||
1637 | memset(&free_pipe->plane_res, 0, sizeof(struct plane_resource))__builtin_memset((&free_pipe->plane_res), (0), (sizeof (struct plane_resource))); | |||
1638 | free_pipe->plane_state = NULL((void *)0); | |||
1639 | free_pipe->pipe_idx = 0; | |||
1640 | free_right_pipe->plane_state = plane_state; | |||
1641 | free_pipe = free_right_pipe; | |||
1642 | } | |||
1643 | } | |||
1644 | ||||
1645 | free_pipe->stream_res.tg = head_pipe->next_odm_pipe->stream_res.tg; | |||
1646 | free_pipe->stream_res.abm = head_pipe->next_odm_pipe->stream_res.abm; | |||
1647 | free_pipe->stream_res.opp = head_pipe->next_odm_pipe->stream_res.opp; | |||
1648 | free_pipe->stream_res.stream_enc = head_pipe->next_odm_pipe->stream_res.stream_enc; | |||
1649 | free_pipe->stream_res.audio = head_pipe->next_odm_pipe->stream_res.audio; | |||
1650 | free_pipe->clock_source = head_pipe->next_odm_pipe->clock_source; | |||
1651 | ||||
1652 | free_pipe->top_pipe = head_pipe->next_odm_pipe; | |||
1653 | head_pipe->next_odm_pipe->bottom_pipe = free_pipe; | |||
1654 | } else { | |||
1655 | ||||
1656 | /* For ODM + window MPO, in 3 plane case, if we already have a MPO window on | |||
1657 | * the left side, then we will invalidate a 2nd one on the left side | |||
1658 | */ | |||
1659 | if (head_pipe->next_odm_pipe && tail_pipe->top_pipe) { | |||
1660 | dc_plane_state_release(plane_state); | |||
1661 | return false0; | |||
1662 | } | |||
1663 | ||||
1664 | free_pipe->stream_res.tg = tail_pipe->stream_res.tg; | |||
1665 | free_pipe->stream_res.abm = tail_pipe->stream_res.abm; | |||
1666 | free_pipe->stream_res.opp = tail_pipe->stream_res.opp; | |||
1667 | free_pipe->stream_res.stream_enc = tail_pipe->stream_res.stream_enc; | |||
1668 | free_pipe->stream_res.audio = tail_pipe->stream_res.audio; | |||
1669 | free_pipe->clock_source = tail_pipe->clock_source; | |||
1670 | ||||
1671 | free_pipe->top_pipe = tail_pipe; | |||
1672 | tail_pipe->bottom_pipe = free_pipe; | |||
1673 | ||||
1674 | /* Connect MPO pipes together if MPO window is in the centre */ | |||
1675 | if (!(free_pipe->plane_state && | |||
1676 | (free_pipe->plane_state->clip_rect.x + free_pipe->plane_state->clip_rect.width <= | |||
1677 | free_pipe->stream->src.x + free_pipe->stream->src.width/2))) { | |||
1678 | if (!free_pipe->next_odm_pipe && | |||
1679 | tail_pipe->next_odm_pipe && tail_pipe->next_odm_pipe->bottom_pipe) { | |||
1680 | free_pipe->next_odm_pipe = tail_pipe->next_odm_pipe->bottom_pipe; | |||
1681 | tail_pipe->next_odm_pipe->bottom_pipe->prev_odm_pipe = free_pipe; | |||
1682 | } | |||
1683 | if (!free_pipe->prev_odm_pipe && | |||
1684 | tail_pipe->prev_odm_pipe && tail_pipe->prev_odm_pipe->bottom_pipe) { | |||
1685 | free_pipe->prev_odm_pipe = tail_pipe->prev_odm_pipe->bottom_pipe; | |||
1686 | tail_pipe->prev_odm_pipe->bottom_pipe->next_odm_pipe = free_pipe; | |||
1687 | } | |||
1688 | } | |||
1689 | } | |||
1690 | } | |||
1691 | ||||
1692 | /* ODM + window MPO, where MPO window is on left half only */ | |||
1693 | if (free_pipe->plane_state && | |||
1694 | (free_pipe->plane_state->clip_rect.x + free_pipe->plane_state->clip_rect.width <= | |||
1695 | free_pipe->stream->src.x + free_pipe->stream->src.width/2)) { | |||
1696 | DC_LOG_SCALER("%s - ODM + window MPO(left). free_pipe:%d\n",do { } while(0) | |||
1697 | __func__,do { } while(0) | |||
1698 | free_pipe->pipe_idx)do { } while(0); | |||
1699 | break; | |||
1700 | } | |||
1701 | /* ODM + window MPO, where MPO window is on right half only */ | |||
1702 | if (free_pipe->plane_state && | |||
1703 | (free_pipe->plane_state->clip_rect.x >= free_pipe->stream->src.x + free_pipe->stream->src.width/2)) { | |||
1704 | DC_LOG_SCALER("%s - ODM + window MPO(right). free_pipe:%d\n",do { } while(0) | |||
1705 | __func__,do { } while(0) | |||
1706 | free_pipe->pipe_idx)do { } while(0); | |||
1707 | break; | |||
1708 | } | |||
1709 | ||||
1710 | head_pipe = head_pipe->next_odm_pipe; | |||
1711 | } | |||
1712 | /* assign new surfaces*/ | |||
1713 | stream_status->plane_states[stream_status->plane_count] = plane_state; | |||
1714 | ||||
1715 | stream_status->plane_count++; | |||
1716 | ||||
1717 | return true1; | |||
1718 | } | |||
1719 | ||||
1720 | bool_Bool dc_remove_plane_from_context( | |||
1721 | const struct dc *dc, | |||
1722 | struct dc_stream_state *stream, | |||
1723 | struct dc_plane_state *plane_state, | |||
1724 | struct dc_state *context) | |||
1725 | { | |||
1726 | int i; | |||
1727 | struct dc_stream_status *stream_status = NULL((void *)0); | |||
1728 | struct resource_pool *pool = dc->res_pool; | |||
1729 | ||||
1730 | if (!plane_state) | |||
1731 | return true1; | |||
1732 | ||||
1733 | for (i = 0; i < context->stream_count; i++) | |||
1734 | if (context->streams[i] == stream) { | |||
1735 | stream_status = &context->stream_status[i]; | |||
1736 | break; | |||
1737 | } | |||
1738 | ||||
1739 | if (stream_status == NULL((void *)0)) { | |||
1740 | dm_error("Existing stream not found; failed to remove plane.\n")__drm_err("Existing stream not found; failed to remove plane.\n" ); | |||
1741 | return false0; | |||
1742 | } | |||
1743 | ||||
1744 | /* release pipe for plane*/ | |||
1745 | for (i = pool->pipe_count - 1; i >= 0; i--) { | |||
1746 | struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; | |||
1747 | ||||
1748 | if (pipe_ctx->plane_state == plane_state) { | |||
1749 | if (pipe_ctx->top_pipe) | |||
1750 | pipe_ctx->top_pipe->bottom_pipe = pipe_ctx->bottom_pipe; | |||
1751 | ||||
1752 | /* Second condition is to avoid setting NULL to top pipe | |||
1753 | * of tail pipe making it look like head pipe in subsequent | |||
1754 | * deletes | |||
1755 | */ | |||
1756 | if (pipe_ctx->bottom_pipe && pipe_ctx->top_pipe) | |||
1757 | pipe_ctx->bottom_pipe->top_pipe = pipe_ctx->top_pipe; | |||
1758 | ||||
1759 | /* | |||
1760 | * For head pipe detach surfaces from pipe for tail | |||
1761 | * pipe just zero it out | |||
1762 | */ | |||
1763 | if (!pipe_ctx->top_pipe) | |||
1764 | pipe_ctx->plane_state = NULL((void *)0); | |||
1765 | else | |||
1766 | memset(pipe_ctx, 0, sizeof(*pipe_ctx))__builtin_memset((pipe_ctx), (0), (sizeof(*pipe_ctx))); | |||
1767 | } | |||
1768 | } | |||
1769 | ||||
1770 | ||||
1771 | for (i = 0; i < stream_status->plane_count; i++) { | |||
1772 | if (stream_status->plane_states[i] == plane_state) { | |||
1773 | dc_plane_state_release(stream_status->plane_states[i]); | |||
1774 | break; | |||
1775 | } | |||
1776 | } | |||
1777 | ||||
1778 | if (i == stream_status->plane_count) { | |||
1779 | dm_error("Existing plane_state not found; failed to detach it!\n")__drm_err("Existing plane_state not found; failed to detach it!\n" ); | |||
1780 | return false0; | |||
1781 | } | |||
1782 | ||||
1783 | stream_status->plane_count--; | |||
1784 | ||||
1785 | /* Start at the plane we've just released, and move all the planes one index forward to "trim" the array */ | |||
1786 | for (; i < stream_status->plane_count; i++) | |||
1787 | stream_status->plane_states[i] = stream_status->plane_states[i + 1]; | |||
1788 | ||||
1789 | stream_status->plane_states[stream_status->plane_count] = NULL((void *)0); | |||
1790 | ||||
1791 | return true1; | |||
1792 | } | |||
1793 | ||||
1794 | bool_Bool dc_rem_all_planes_for_stream( | |||
1795 | const struct dc *dc, | |||
1796 | struct dc_stream_state *stream, | |||
1797 | struct dc_state *context) | |||
1798 | { | |||
1799 | int i, old_plane_count; | |||
1800 | struct dc_stream_status *stream_status = NULL((void *)0); | |||
1801 | struct dc_plane_state *del_planes[MAX_SURFACE_NUM4] = { 0 }; | |||
1802 | ||||
1803 | for (i = 0; i < context->stream_count; i++) | |||
1804 | if (context->streams[i] == stream) { | |||
1805 | stream_status = &context->stream_status[i]; | |||
1806 | break; | |||
1807 | } | |||
1808 | ||||
1809 | if (stream_status == NULL((void *)0)) { | |||
1810 | dm_error("Existing stream %p not found!\n", stream)__drm_err("Existing stream %p not found!\n", stream); | |||
1811 | return false0; | |||
1812 | } | |||
1813 | ||||
1814 | old_plane_count = stream_status->plane_count; | |||
1815 | ||||
1816 | for (i = 0; i < old_plane_count; i++) | |||
1817 | del_planes[i] = stream_status->plane_states[i]; | |||
1818 | ||||
1819 | for (i = 0; i < old_plane_count; i++) | |||
1820 | if (!dc_remove_plane_from_context(dc, stream, del_planes[i], context)) | |||
1821 | return false0; | |||
1822 | ||||
1823 | return true1; | |||
1824 | } | |||
1825 | ||||
1826 | static bool_Bool add_all_planes_for_stream( | |||
1827 | const struct dc *dc, | |||
1828 | struct dc_stream_state *stream, | |||
1829 | const struct dc_validation_set set[], | |||
1830 | int set_count, | |||
1831 | struct dc_state *context) | |||
1832 | { | |||
1833 | int i, j; | |||
1834 | ||||
1835 | for (i = 0; i < set_count; i++) | |||
1836 | if (set[i].stream == stream) | |||
1837 | break; | |||
1838 | ||||
1839 | if (i == set_count) { | |||
1840 | dm_error("Stream %p not found in set!\n", stream)__drm_err("Stream %p not found in set!\n", stream); | |||
1841 | return false0; | |||
1842 | } | |||
1843 | ||||
1844 | for (j = 0; j < set[i].plane_count; j++) | |||
1845 | if (!dc_add_plane_to_context(dc, stream, set[i].plane_states[j], context)) | |||
1846 | return false0; | |||
1847 | ||||
1848 | return true1; | |||
1849 | } | |||
1850 | ||||
1851 | bool_Bool dc_add_all_planes_for_stream( | |||
1852 | const struct dc *dc, | |||
1853 | struct dc_stream_state *stream, | |||
1854 | struct dc_plane_state * const *plane_states, | |||
1855 | int plane_count, | |||
1856 | struct dc_state *context) | |||
1857 | { | |||
1858 | struct dc_validation_set set; | |||
1859 | int i; | |||
1860 | ||||
1861 | set.stream = stream; | |||
1862 | set.plane_count = plane_count; | |||
1863 | ||||
1864 | for (i = 0; i < plane_count; i++) | |||
1865 | set.plane_states[i] = plane_states[i]; | |||
1866 | ||||
1867 | return add_all_planes_for_stream(dc, stream, &set, 1, context); | |||
1868 | } | |||
1869 | ||||
1870 | bool_Bool is_timing_changed(struct dc_stream_state *cur_stream, | |||
1871 | struct dc_stream_state *new_stream) | |||
1872 | { | |||
1873 | if (cur_stream == NULL((void *)0)) | |||
1874 | return true1; | |||
1875 | ||||
1876 | /* If output color space is changed, need to reprogram info frames */ | |||
1877 | if (cur_stream->output_color_space != new_stream->output_color_space) | |||
1878 | return true1; | |||
1879 | ||||
1880 | return memcmp(__builtin_memcmp((&cur_stream->timing), (&new_stream ->timing), (sizeof(struct dc_crtc_timing))) | |||
1881 | &cur_stream->timing,__builtin_memcmp((&cur_stream->timing), (&new_stream ->timing), (sizeof(struct dc_crtc_timing))) | |||
1882 | &new_stream->timing,__builtin_memcmp((&cur_stream->timing), (&new_stream ->timing), (sizeof(struct dc_crtc_timing))) | |||
1883 | sizeof(struct dc_crtc_timing))__builtin_memcmp((&cur_stream->timing), (&new_stream ->timing), (sizeof(struct dc_crtc_timing))) != 0; | |||
1884 | } | |||
1885 | ||||
1886 | static bool_Bool are_stream_backends_same( | |||
1887 | struct dc_stream_state *stream_a, struct dc_stream_state *stream_b) | |||
1888 | { | |||
1889 | if (stream_a == stream_b) | |||
1890 | return true1; | |||
1891 | ||||
1892 | if (stream_a == NULL((void *)0) || stream_b == NULL((void *)0)) | |||
1893 | return false0; | |||
1894 | ||||
1895 | if (is_timing_changed(stream_a, stream_b)) | |||
1896 | return false0; | |||
1897 | ||||
1898 | if (stream_a->signal != stream_b->signal) | |||
1899 | return false0; | |||
1900 | ||||
1901 | if (stream_a->dpms_off != stream_b->dpms_off) | |||
1902 | return false0; | |||
1903 | ||||
1904 | return true1; | |||
1905 | } | |||
1906 | ||||
1907 | /* | |||
1908 | * dc_is_stream_unchanged() - Compare two stream states for equivalence. | |||
1909 | * | |||
1910 | * Checks if there a difference between the two states | |||
1911 | * that would require a mode change. | |||
1912 | * | |||
1913 | * Does not compare cursor position or attributes. | |||
1914 | */ | |||
1915 | bool_Bool dc_is_stream_unchanged( | |||
1916 | struct dc_stream_state *old_stream, struct dc_stream_state *stream) | |||
1917 | { | |||
1918 | ||||
1919 | if (!are_stream_backends_same(old_stream, stream)) | |||
1920 | return false0; | |||
1921 | ||||
1922 | if (old_stream->ignore_msa_timing_param != stream->ignore_msa_timing_param) | |||
1923 | return false0; | |||
1924 | ||||
1925 | /*compare audio info*/ | |||
1926 | if (memcmp(&old_stream->audio_info, &stream->audio_info, sizeof(stream->audio_info))__builtin_memcmp((&old_stream->audio_info), (&stream ->audio_info), (sizeof(stream->audio_info))) != 0) | |||
1927 | return false0; | |||
1928 | ||||
1929 | return true1; | |||
1930 | } | |||
1931 | ||||
1932 | /* | |||
1933 | * dc_is_stream_scaling_unchanged() - Compare scaling rectangles of two streams. | |||
1934 | */ | |||
1935 | bool_Bool dc_is_stream_scaling_unchanged(struct dc_stream_state *old_stream, | |||
1936 | struct dc_stream_state *stream) | |||
1937 | { | |||
1938 | if (old_stream == stream) | |||
1939 | return true1; | |||
1940 | ||||
1941 | if (old_stream == NULL((void *)0) || stream == NULL((void *)0)) | |||
1942 | return false0; | |||
1943 | ||||
1944 | if (memcmp(&old_stream->src,__builtin_memcmp((&old_stream->src), (&stream-> src), (sizeof(struct rect))) | |||
1945 | &stream->src,__builtin_memcmp((&old_stream->src), (&stream-> src), (sizeof(struct rect))) | |||
1946 | sizeof(struct rect))__builtin_memcmp((&old_stream->src), (&stream-> src), (sizeof(struct rect))) != 0) | |||
1947 | return false0; | |||
1948 | ||||
1949 | if (memcmp(&old_stream->dst,__builtin_memcmp((&old_stream->dst), (&stream-> dst), (sizeof(struct rect))) | |||
1950 | &stream->dst,__builtin_memcmp((&old_stream->dst), (&stream-> dst), (sizeof(struct rect))) | |||
1951 | sizeof(struct rect))__builtin_memcmp((&old_stream->dst), (&stream-> dst), (sizeof(struct rect))) != 0) | |||
1952 | return false0; | |||
1953 | ||||
1954 | return true1; | |||
1955 | } | |||
1956 | ||||
1957 | static void update_stream_engine_usage( | |||
1958 | struct resource_context *res_ctx, | |||
1959 | const struct resource_pool *pool, | |||
1960 | struct stream_encoder *stream_enc, | |||
1961 | bool_Bool acquired) | |||
1962 | { | |||
1963 | int i; | |||
1964 | ||||
1965 | for (i = 0; i < pool->stream_enc_count; i++) { | |||
1966 | if (pool->stream_enc[i] == stream_enc) | |||
1967 | res_ctx->is_stream_enc_acquired[i] = acquired; | |||
1968 | } | |||
1969 | } | |||
1970 | ||||
1971 | static void update_hpo_dp_stream_engine_usage( | |||
1972 | struct resource_context *res_ctx, | |||
1973 | const struct resource_pool *pool, | |||
1974 | struct hpo_dp_stream_encoder *hpo_dp_stream_enc, | |||
1975 | bool_Bool acquired) | |||
1976 | { | |||
1977 | int i; | |||
1978 | ||||
1979 | for (i = 0; i < pool->hpo_dp_stream_enc_count; i++) { | |||
1980 | if (pool->hpo_dp_stream_enc[i] == hpo_dp_stream_enc) | |||
1981 | res_ctx->is_hpo_dp_stream_enc_acquired[i] = acquired; | |||
1982 | } | |||
1983 | } | |||
1984 | ||||
1985 | static inline int find_acquired_hpo_dp_link_enc_for_link( | |||
1986 | const struct resource_context *res_ctx, | |||
1987 | const struct dc_link *link) | |||
1988 | { | |||
1989 | int i; | |||
1990 | ||||
1991 | for (i = 0; i < ARRAY_SIZE(res_ctx->hpo_dp_link_enc_to_link_idx)(sizeof((res_ctx->hpo_dp_link_enc_to_link_idx)) / sizeof(( res_ctx->hpo_dp_link_enc_to_link_idx)[0])); i++) | |||
1992 | if (res_ctx->hpo_dp_link_enc_ref_cnts[i] > 0 && | |||
1993 | res_ctx->hpo_dp_link_enc_to_link_idx[i] == link->link_index) | |||
1994 | return i; | |||
1995 | ||||
1996 | return -1; | |||
1997 | } | |||
1998 | ||||
1999 | static inline int find_free_hpo_dp_link_enc(const struct resource_context *res_ctx, | |||
2000 | const struct resource_pool *pool) | |||
2001 | { | |||
2002 | int i; | |||
2003 | ||||
2004 | for (i = 0; i < ARRAY_SIZE(res_ctx->hpo_dp_link_enc_ref_cnts)(sizeof((res_ctx->hpo_dp_link_enc_ref_cnts)) / sizeof((res_ctx ->hpo_dp_link_enc_ref_cnts)[0])); i++) | |||
2005 | if (res_ctx->hpo_dp_link_enc_ref_cnts[i] == 0) | |||
2006 | break; | |||
2007 | ||||
2008 | return (i < ARRAY_SIZE(res_ctx->hpo_dp_link_enc_ref_cnts)(sizeof((res_ctx->hpo_dp_link_enc_ref_cnts)) / sizeof((res_ctx ->hpo_dp_link_enc_ref_cnts)[0])) && | |||
2009 | i < pool->hpo_dp_link_enc_count) ? i : -1; | |||
2010 | } | |||
2011 | ||||
2012 | static inline void acquire_hpo_dp_link_enc( | |||
2013 | struct resource_context *res_ctx, | |||
2014 | unsigned int link_index, | |||
2015 | int enc_index) | |||
2016 | { | |||
2017 | res_ctx->hpo_dp_link_enc_to_link_idx[enc_index] = link_index; | |||
2018 | res_ctx->hpo_dp_link_enc_ref_cnts[enc_index] = 1; | |||
2019 | } | |||
2020 | ||||
2021 | static inline void retain_hpo_dp_link_enc( | |||
2022 | struct resource_context *res_ctx, | |||
2023 | int enc_index) | |||
2024 | { | |||
2025 | res_ctx->hpo_dp_link_enc_ref_cnts[enc_index]++; | |||
2026 | } | |||
2027 | ||||
2028 | static inline void release_hpo_dp_link_enc( | |||
2029 | struct resource_context *res_ctx, | |||
2030 | int enc_index) | |||
2031 | { | |||
2032 | ASSERT(res_ctx->hpo_dp_link_enc_ref_cnts[enc_index] > 0)do { if (({ static int __warned; int __ret = !!(!(res_ctx-> hpo_dp_link_enc_ref_cnts[enc_index] > 0)); if (__ret && !__warned) { printf("WARNING %s failed at %s:%d\n", "!(res_ctx->hpo_dp_link_enc_ref_cnts[enc_index] > 0)" , "/usr/src/sys/dev/pci/drm/amd/display/dc/core/dc_resource.c" , 2032); __warned = 1; } __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); | |||
2033 | res_ctx->hpo_dp_link_enc_ref_cnts[enc_index]--; | |||
2034 | } | |||
2035 | ||||
2036 | static bool_Bool add_hpo_dp_link_enc_to_ctx(struct resource_context *res_ctx, | |||
2037 | const struct resource_pool *pool, | |||
2038 | struct pipe_ctx *pipe_ctx, | |||
2039 | struct dc_stream_state *stream) | |||
2040 | { | |||
2041 | int enc_index; | |||
2042 | ||||
2043 | enc_index = find_acquired_hpo_dp_link_enc_for_link(res_ctx, stream->link); | |||
2044 | ||||
2045 | if (enc_index >= 0) { | |||
2046 | retain_hpo_dp_link_enc(res_ctx, enc_index); | |||
2047 | } else { | |||
2048 | enc_index = find_free_hpo_dp_link_enc(res_ctx, pool); | |||
2049 | if (enc_index >= 0) | |||
2050 | acquire_hpo_dp_link_enc(res_ctx, stream->link->link_index, enc_index); | |||
2051 | } | |||
2052 | ||||
2053 | if (enc_index >= 0) | |||
2054 | pipe_ctx->link_res.hpo_dp_link_enc = pool->hpo_dp_link_enc[enc_index]; | |||
2055 | ||||
2056 | return pipe_ctx->link_res.hpo_dp_link_enc != NULL((void *)0); | |||
2057 | } | |||
2058 | ||||
2059 | static void remove_hpo_dp_link_enc_from_ctx(struct resource_context *res_ctx, | |||
2060 | struct pipe_ctx *pipe_ctx, | |||
2061 | struct dc_stream_state *stream) | |||
2062 | { | |||
2063 | int enc_index; | |||
2064 | ||||
2065 | enc_index = find_acquired_hpo_dp_link_enc_for_link(res_ctx, stream->link); | |||
2066 | ||||
2067 | if (enc_index >= 0) { | |||
2068 | release_hpo_dp_link_enc(res_ctx, enc_index); | |||
2069 | pipe_ctx->link_res.hpo_dp_link_enc = NULL((void *)0); | |||
2070 | } | |||
2071 | } | |||
2072 | ||||
2073 | /* TODO: release audio object */ | |||
2074 | void update_audio_usage( | |||
2075 | struct resource_context *res_ctx, | |||
2076 | const struct resource_pool *pool, | |||
2077 | struct audio *audio, | |||
2078 | bool_Bool acquired) | |||
2079 | { | |||
2080 | int i; | |||
2081 | for (i = 0; i < pool->audio_count; i++) { | |||
2082 | if (pool->audios[i] == audio) | |||
2083 | res_ctx->is_audio_acquired[i] = acquired; | |||
2084 | } | |||
2085 | } | |||
2086 | ||||
2087 | static int acquire_first_free_pipe( | |||
2088 | struct resource_context *res_ctx, | |||
2089 | const struct resource_pool *pool, | |||
2090 | struct dc_stream_state *stream) | |||
2091 | { | |||
2092 | int i; | |||
2093 | ||||
2094 | for (i = 0; i < pool->pipe_count; i++) { | |||
2095 | if (!res_ctx->pipe_ctx[i].stream) { | |||
2096 | struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[i]; | |||
2097 | ||||
2098 | pipe_ctx->stream_res.tg = pool->timing_generators[i]; | |||
2099 | pipe_ctx->plane_res.mi = pool->mis[i]; | |||
2100 | pipe_ctx->plane_res.hubp = pool->hubps[i]; | |||
2101 | pipe_ctx->plane_res.ipp = pool->ipps[i]; | |||
2102 | pipe_ctx->plane_res.xfm = pool->transforms[i]; | |||
2103 | pipe_ctx->plane_res.dpp = pool->dpps[i]; | |||
2104 | pipe_ctx->stream_res.opp = pool->opps[i]; | |||
2105 | if (pool->dpps[i]) | |||
2106 | pipe_ctx->plane_res.mpcc_inst = pool->dpps[i]->inst; | |||
2107 | pipe_ctx->pipe_idx = i; | |||
2108 | ||||
2109 | if (i >= pool->timing_generator_count) { | |||
2110 | int tg_inst = pool->timing_generator_count - 1; | |||
2111 | ||||
2112 | pipe_ctx->stream_res.tg = pool->timing_generators[tg_inst]; | |||
2113 | pipe_ctx->stream_res.opp = pool->opps[tg_inst]; | |||
2114 | } | |||
2115 | ||||
2116 | pipe_ctx->stream = stream; | |||
2117 | return i; | |||
2118 | } | |||
2119 | } | |||
2120 | return -1; | |||
2121 | } | |||
2122 | ||||
2123 | static struct hpo_dp_stream_encoder *find_first_free_match_hpo_dp_stream_enc_for_link( | |||
2124 | struct resource_context *res_ctx, | |||
2125 | const struct resource_pool *pool, | |||
2126 | struct dc_stream_state *stream) | |||
2127 | { | |||
2128 | int i; | |||
2129 | ||||
2130 | for (i = 0; i < pool->hpo_dp_stream_enc_count; i++) { | |||
2131 | if (!res_ctx->is_hpo_dp_stream_enc_acquired[i] && | |||
2132 | pool->hpo_dp_stream_enc[i]) { | |||
2133 | ||||
2134 | return pool->hpo_dp_stream_enc[i]; | |||
2135 | } | |||
2136 | } | |||
2137 | ||||
2138 | return NULL((void *)0); | |||
2139 | } | |||
2140 | ||||
2141 | static struct audio *find_first_free_audio( | |||
2142 | struct resource_context *res_ctx, | |||
2143 | const struct resource_pool *pool, | |||
2144 | enum engine_id id, | |||
2145 | enum dce_version dc_version) | |||
2146 | { | |||
2147 | int i, available_audio_count; | |||
2148 | ||||
2149 | available_audio_count = pool->audio_count; | |||
2150 | ||||
2151 | for (i = 0; i < available_audio_count; i++) { | |||
2152 | if ((res_ctx->is_audio_acquired[i] == false0) && (res_ctx->is_stream_enc_acquired[i] == true1)) { | |||
2153 | /*we have enough audio endpoint, find the matching inst*/ | |||
2154 | if (id != i) | |||
2155 | continue; | |||
2156 | return pool->audios[i]; | |||
2157 | } | |||
2158 | } | |||
2159 | ||||
2160 | /* use engine id to find free audio */ | |||
2161 | if ((id < available_audio_count) && (res_ctx->is_audio_acquired[id] == false0)) { | |||
2162 | return pool->audios[id]; | |||
2163 | } | |||
2164 | /*not found the matching one, first come first serve*/ | |||
2165 | for (i = 0; i < available_audio_count; i++) { | |||
2166 | if (res_ctx->is_audio_acquired[i] == false0) { | |||
2167 | return pool->audios[i]; | |||
2168 | } | |||
2169 | } | |||
2170 | return NULL((void *)0); | |||
2171 | } | |||
2172 | ||||
2173 | /* | |||
2174 | * dc_add_stream_to_ctx() - Add a new dc_stream_state to a dc_state. | |||
2175 | */ | |||
2176 | enum dc_status dc_add_stream_to_ctx( | |||
2177 | struct dc *dc, | |||
2178 | struct dc_state *new_ctx, | |||
2179 | struct dc_stream_state *stream) | |||
2180 | { | |||
2181 | enum dc_status res; | |||
2182 | DC_LOGGER_INIT(dc->ctx->logger); | |||
2183 | ||||
2184 | if (new_ctx->stream_count >= dc->res_pool->timing_generator_count) { | |||
2185 | DC_LOG_WARNING("Max streams reached, can't add stream %p !\n", stream)printk("\0014" "[" "drm" "] " "Max streams reached, can't add stream %p !\n" , stream); | |||
2186 | return DC_ERROR_UNEXPECTED; | |||
2187 | } | |||
2188 | ||||
2189 | new_ctx->streams[new_ctx->stream_count] = stream; | |||
2190 | dc_stream_retain(stream); | |||
2191 | new_ctx->stream_count++; | |||
2192 | ||||
2193 | res = dc->res_pool->funcs->add_stream_to_ctx(dc, new_ctx, stream); | |||
2194 | if (res != DC_OK) | |||
2195 | DC_LOG_WARNING("Adding stream %p to context failed with err %d!\n", stream, res)printk("\0014" "[" "drm" "] " "Adding stream %p to context failed with err %d!\n" , stream, res); | |||
2196 | ||||
2197 | return res; | |||
2198 | } | |||
2199 | ||||
2200 | /* | |||
2201 | * dc_remove_stream_from_ctx() - Remove a stream from a dc_state. | |||
2202 | */ | |||
2203 | enum dc_status dc_remove_stream_from_ctx( | |||
2204 | struct dc *dc, | |||
2205 | struct dc_state *new_ctx, | |||
2206 | struct dc_stream_state *stream) | |||
2207 | { | |||
2208 | int i; | |||
2209 | struct dc_context *dc_ctx = dc->ctx; | |||
2210 | struct pipe_ctx *del_pipe = resource_get_head_pipe_for_stream(&new_ctx->res_ctx, stream); | |||
2211 | struct pipe_ctx *odm_pipe; | |||
2212 | ||||
2213 | if (!del_pipe) { | |||
2214 | DC_ERROR("Pipe not found for stream %p !\n", stream)do { (void)(dc_ctx); __drm_err("Pipe not found for stream %p !\n" , stream); } while (0); | |||
2215 | return DC_ERROR_UNEXPECTED; | |||
2216 | } | |||
2217 | ||||
2218 | odm_pipe = del_pipe->next_odm_pipe; | |||
2219 | ||||
2220 | /* Release primary pipe */ | |||
2221 | ASSERT(del_pipe->stream_res.stream_enc)do { if (({ static int __warned; int __ret = !!(!(del_pipe-> stream_res.stream_enc)); if (__ret && !__warned) { printf ("WARNING %s failed at %s:%d\n", "!(del_pipe->stream_res.stream_enc)" , "/usr/src/sys/dev/pci/drm/amd/display/dc/core/dc_resource.c" , 2221); __warned = 1; } __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); | |||
2222 | update_stream_engine_usage( | |||
2223 | &new_ctx->res_ctx, | |||
2224 | dc->res_pool, | |||
2225 | del_pipe->stream_res.stream_enc, | |||
2226 | false0); | |||
2227 | ||||
2228 | if (is_dp_128b_132b_signal(del_pipe)) { | |||
2229 | update_hpo_dp_stream_engine_usage( | |||
2230 | &new_ctx->res_ctx, dc->res_pool, | |||
2231 | del_pipe->stream_res.hpo_dp_stream_enc, | |||
2232 | false0); | |||
2233 | remove_hpo_dp_link_enc_from_ctx(&new_ctx->res_ctx, del_pipe, del_pipe->stream); | |||
2234 | } | |||
2235 | ||||
2236 | if (del_pipe->stream_res.audio) | |||
2237 | update_audio_usage( | |||
2238 | &new_ctx->res_ctx, | |||
2239 | dc->res_pool, | |||
2240 | del_pipe->stream_res.audio, | |||
2241 | false0); | |||
2242 | ||||
2243 | resource_unreference_clock_source(&new_ctx->res_ctx, | |||
2244 | dc->res_pool, | |||
2245 | del_pipe->clock_source); | |||
2246 | ||||
2247 | if (dc->res_pool->funcs->remove_stream_from_ctx) | |||
2248 | dc->res_pool->funcs->remove_stream_from_ctx(dc, new_ctx, stream); | |||
2249 | ||||
2250 | while (odm_pipe) { | |||
2251 | struct pipe_ctx *next_odm_pipe = odm_pipe->next_odm_pipe; | |||
2252 | ||||
2253 | memset(odm_pipe, 0, sizeof(*odm_pipe))__builtin_memset((odm_pipe), (0), (sizeof(*odm_pipe))); | |||
2254 | odm_pipe = next_odm_pipe; | |||
2255 | } | |||
2256 | memset(del_pipe, 0, sizeof(*del_pipe))__builtin_memset((del_pipe), (0), (sizeof(*del_pipe))); | |||
2257 | ||||
2258 | for (i = 0; i < new_ctx->stream_count; i++) | |||
2259 | if (new_ctx->streams[i] == stream) | |||
2260 | break; | |||
2261 | ||||
2262 | if (new_ctx->streams[i] != stream) { | |||
2263 | DC_ERROR("Context doesn't have stream %p !\n", stream)do { (void)(dc_ctx); __drm_err("Context doesn't have stream %p !\n" , stream); } while (0); | |||
2264 | return DC_ERROR_UNEXPECTED; | |||
2265 | } | |||
2266 | ||||
2267 | dc_stream_release(new_ctx->streams[i]); | |||
2268 | new_ctx->stream_count--; | |||
2269 | ||||
2270 | /* Trim back arrays */ | |||
2271 | for (; i < new_ctx->stream_count; i++) { | |||
2272 | new_ctx->streams[i] = new_ctx->streams[i + 1]; | |||
2273 | new_ctx->stream_status[i] = new_ctx->stream_status[i + 1]; | |||
2274 | } | |||
2275 | ||||
2276 | new_ctx->streams[new_ctx->stream_count] = NULL((void *)0); | |||
2277 | memset(__builtin_memset((&new_ctx->stream_status[new_ctx-> stream_count]), (0), (sizeof(new_ctx->stream_status[0]))) | |||
2278 | &new_ctx->stream_status[new_ctx->stream_count],__builtin_memset((&new_ctx->stream_status[new_ctx-> stream_count]), (0), (sizeof(new_ctx->stream_status[0]))) | |||
2279 | 0,__builtin_memset((&new_ctx->stream_status[new_ctx-> stream_count]), (0), (sizeof(new_ctx->stream_status[0]))) | |||
2280 | sizeof(new_ctx->stream_status[0]))__builtin_memset((&new_ctx->stream_status[new_ctx-> stream_count]), (0), (sizeof(new_ctx->stream_status[0]))); | |||
2281 | ||||
2282 | return DC_OK; | |||
2283 | } | |||
2284 | ||||
2285 | static struct dc_stream_state *find_pll_sharable_stream( | |||
2286 | struct dc_stream_state *stream_needs_pll, | |||
2287 | struct dc_state *context) | |||
2288 | { | |||
2289 | int i; | |||
2290 | ||||
2291 | for (i = 0; i < context->stream_count; i++) { | |||
2292 | struct dc_stream_state *stream_has_pll = context->streams[i]; | |||
2293 | ||||
2294 | /* We are looking for non dp, non virtual stream */ | |||
2295 | if (resource_are_streams_timing_synchronizable( | |||
2296 | stream_needs_pll, stream_has_pll) | |||
2297 | && !dc_is_dp_signal(stream_has_pll->signal) | |||
2298 | && stream_has_pll->link->connector_signal | |||
2299 | != SIGNAL_TYPE_VIRTUAL) | |||
2300 | return stream_has_pll; | |||
2301 | ||||
2302 | } | |||
2303 | ||||
2304 | return NULL((void *)0); | |||
2305 | } | |||
2306 | ||||
2307 | static int get_norm_pix_clk(const struct dc_crtc_timing *timing) | |||
2308 | { | |||
2309 | uint32_t pix_clk = timing->pix_clk_100hz; | |||
2310 | uint32_t normalized_pix_clk = pix_clk; | |||
2311 | ||||
2312 | if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR420) | |||
2313 | pix_clk /= 2; | |||
2314 | if (timing->pixel_encoding != PIXEL_ENCODING_YCBCR422) { | |||
2315 | switch (timing->display_color_depth) { | |||
2316 | case COLOR_DEPTH_666: | |||
2317 | case COLOR_DEPTH_888: | |||
2318 | normalized_pix_clk = pix_clk; | |||
2319 | break; | |||
2320 | case COLOR_DEPTH_101010: | |||
2321 | normalized_pix_clk = (pix_clk * 30) / 24; | |||
2322 | break; | |||
2323 | case COLOR_DEPTH_121212: | |||
2324 | normalized_pix_clk = (pix_clk * 36) / 24; | |||
2325 | break; | |||
2326 | case COLOR_DEPTH_161616: | |||
2327 | normalized_pix_clk = (pix_clk * 48) / 24; | |||
2328 | break; | |||
2329 | default: | |||
2330 | ASSERT(0)do { if (({ static int __warned; int __ret = !!(!(0)); if (__ret && !__warned) { printf("WARNING %s failed at %s:%d\n" , "!(0)", "/usr/src/sys/dev/pci/drm/amd/display/dc/core/dc_resource.c" , 2330); __warned = 1; } __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); | |||
2331 | break; | |||
2332 | } | |||
2333 | } | |||
2334 | return normalized_pix_clk; | |||
2335 | } | |||
2336 | ||||
2337 | static void calculate_phy_pix_clks(struct dc_stream_state *stream) | |||
2338 | { | |||
2339 | /* update actual pixel clock on all streams */ | |||
2340 | if (dc_is_hdmi_signal(stream->signal)) | |||
2341 | stream->phy_pix_clk = get_norm_pix_clk( | |||
2342 | &stream->timing) / 10; | |||
2343 | else | |||
2344 | stream->phy_pix_clk = | |||
2345 | stream->timing.pix_clk_100hz / 10; | |||
2346 | ||||
2347 | if (stream->timing.timing_3d_format == TIMING_3D_FORMAT_HW_FRAME_PACKING) | |||
2348 | stream->phy_pix_clk *= 2; | |||
2349 | } | |||
2350 | ||||
2351 | static int acquire_resource_from_hw_enabled_state( | |||
2352 | struct resource_context *res_ctx, | |||
2353 | const struct resource_pool *pool, | |||
2354 | struct dc_stream_state *stream) | |||
2355 | { | |||
2356 | struct dc_link *link = stream->link; | |||
2357 | unsigned int i, inst, tg_inst = 0; | |||
2358 | uint32_t numPipes = 1; | |||
2359 | uint32_t id_src[4] = {0}; | |||
2360 | ||||
2361 | /* Check for enabled DIG to identify enabled display */ | |||
2362 | if (!link->link_enc->funcs->is_dig_enabled(link->link_enc)) | |||
2363 | return -1; | |||
2364 | ||||
2365 | inst = link->link_enc->funcs->get_dig_frontend(link->link_enc); | |||
2366 | ||||
2367 | if (inst == ENGINE_ID_UNKNOWN) | |||
2368 | return -1; | |||
2369 | ||||
2370 | for (i = 0; i < pool->stream_enc_count; i++) { | |||
2371 | if (pool->stream_enc[i]->id == inst) { | |||
2372 | tg_inst = pool->stream_enc[i]->funcs->dig_source_otg( | |||
2373 | pool->stream_enc[i]); | |||
2374 | break; | |||
2375 | } | |||
2376 | } | |||
2377 | ||||
2378 | // tg_inst not found | |||
2379 | if (i == pool->stream_enc_count) | |||
2380 | return -1; | |||
2381 | ||||
2382 | if (tg_inst >= pool->timing_generator_count) | |||
2383 | return -1; | |||
2384 | ||||
2385 | if (!res_ctx->pipe_ctx[tg_inst].stream) { | |||
2386 | struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[tg_inst]; | |||
2387 | ||||
2388 | pipe_ctx->stream_res.tg = pool->timing_generators[tg_inst]; | |||
2389 | id_src[0] = tg_inst; | |||
2390 | ||||
2391 | if (pipe_ctx->stream_res.tg->funcs->get_optc_source) | |||
2392 | pipe_ctx->stream_res.tg->funcs->get_optc_source(pipe_ctx->stream_res.tg, | |||
2393 | &numPipes, &id_src[0], &id_src[1]); | |||
2394 | ||||
2395 | if (id_src[0] == 0xf && id_src[1] == 0xf) { | |||
2396 | id_src[0] = tg_inst; | |||
2397 | numPipes = 1; | |||
2398 | } | |||
2399 | ||||
2400 | for (i = 0; i < numPipes; i++) { | |||
2401 | //Check if src id invalid | |||
2402 | if (id_src[i] == 0xf) | |||
2403 | return -1; | |||
2404 | ||||
2405 | pipe_ctx = &res_ctx->pipe_ctx[id_src[i]]; | |||
2406 | ||||
2407 | pipe_ctx->stream_res.tg = pool->timing_generators[tg_inst]; | |||
2408 | pipe_ctx->plane_res.mi = pool->mis[id_src[i]]; | |||
2409 | pipe_ctx->plane_res.hubp = pool->hubps[id_src[i]]; | |||
2410 | pipe_ctx->plane_res.ipp = pool->ipps[id_src[i]]; | |||
2411 | pipe_ctx->plane_res.xfm = pool->transforms[id_src[i]]; | |||
2412 | pipe_ctx->plane_res.dpp = pool->dpps[id_src[i]]; | |||
2413 | pipe_ctx->stream_res.opp = pool->opps[id_src[i]]; | |||
2414 | ||||
2415 | if (pool->dpps[id_src[i]]) { | |||
2416 | pipe_ctx->plane_res.mpcc_inst = pool->dpps[id_src[i]]->inst; | |||
2417 | ||||
2418 | if (pool->mpc->funcs->read_mpcc_state) { | |||
2419 | struct mpcc_state s = {0}; | |||
2420 | ||||
2421 | pool->mpc->funcs->read_mpcc_state(pool->mpc, pipe_ctx->plane_res.mpcc_inst, &s); | |||
2422 | ||||
2423 | if (s.dpp_id < MAX_MPCC6) | |||
2424 | pool->mpc->mpcc_array[pipe_ctx->plane_res.mpcc_inst].dpp_id = | |||
2425 | s.dpp_id; | |||
2426 | ||||
2427 | if (s.bot_mpcc_id < MAX_MPCC6) | |||
2428 | pool->mpc->mpcc_array[pipe_ctx->plane_res.mpcc_inst].mpcc_bot = | |||
2429 | &pool->mpc->mpcc_array[s.bot_mpcc_id]; | |||
2430 | ||||
2431 | if (s.opp_id < MAX_OPP6) | |||
2432 | pipe_ctx->stream_res.opp->mpc_tree_params.opp_id = s.opp_id; | |||
2433 | } | |||
2434 | } | |||
2435 | pipe_ctx->pipe_idx = id_src[i]; | |||
2436 | ||||
2437 | if (id_src[i] >= pool->timing_generator_count) { | |||
2438 | id_src[i] = pool->timing_generator_count - 1; | |||
2439 | ||||
2440 | pipe_ctx->stream_res.tg = pool->timing_generators[id_src[i]]; | |||
2441 | pipe_ctx->stream_res.opp = pool->opps[id_src[i]]; | |||
2442 | } | |||
2443 | ||||
2444 | pipe_ctx->stream = stream; | |||
2445 | } | |||
2446 | ||||
2447 | if (numPipes == 2) { | |||
2448 | stream->apply_boot_odm_mode = dm_odm_combine_policy_2to1; | |||
2449 | res_ctx->pipe_ctx[id_src[0]].next_odm_pipe = &res_ctx->pipe_ctx[id_src[1]]; | |||
2450 | res_ctx->pipe_ctx[id_src[0]].prev_odm_pipe = NULL((void *)0); | |||
2451 | res_ctx->pipe_ctx[id_src[1]].next_odm_pipe = NULL((void *)0); | |||
2452 | res_ctx->pipe_ctx[id_src[1]].prev_odm_pipe = &res_ctx->pipe_ctx[id_src[0]]; | |||
2453 | } else | |||
2454 | stream->apply_boot_odm_mode = dm_odm_combine_mode_disabled; | |||
2455 | ||||
2456 | return id_src[0]; | |||
2457 | } | |||
2458 | ||||
2459 | return -1; | |||
2460 | } | |||
2461 | ||||
2462 | static void mark_seamless_boot_stream( | |||
2463 | const struct dc *dc, | |||
2464 | struct dc_stream_state *stream) | |||
2465 | { | |||
2466 | struct dc_bios *dcb = dc->ctx->dc_bios; | |||
2467 | ||||
2468 | if (dc->config.allow_seamless_boot_optimization && | |||
2469 | !dcb->funcs->is_accelerated_mode(dcb)) { | |||
2470 | if (dc_validate_boot_timing(dc, stream->sink, &stream->timing)) | |||
2471 | stream->apply_seamless_boot_optimization = true1; | |||
2472 | } | |||
2473 | } | |||
2474 | ||||
2475 | enum dc_status resource_map_pool_resources( | |||
2476 | const struct dc *dc, | |||
2477 | struct dc_state *context, | |||
2478 | struct dc_stream_state *stream) | |||
2479 | { | |||
2480 | const struct resource_pool *pool = dc->res_pool; | |||
2481 | int i; | |||
2482 | struct dc_context *dc_ctx = dc->ctx; | |||
2483 | struct pipe_ctx *pipe_ctx = NULL((void *)0); | |||
2484 | int pipe_idx = -1; | |||
2485 | ||||
2486 | calculate_phy_pix_clks(stream); | |||
2487 | ||||
2488 | mark_seamless_boot_stream(dc, stream); | |||
2489 | ||||
2490 | if (stream->apply_seamless_boot_optimization) { | |||
2491 | pipe_idx = acquire_resource_from_hw_enabled_state( | |||
2492 | &context->res_ctx, | |||
2493 | pool, | |||
2494 | stream); | |||
2495 | if (pipe_idx < 0) | |||
2496 | /* hw resource was assigned to other stream */ | |||
2497 | stream->apply_seamless_boot_optimization = false0; | |||
2498 | } | |||
2499 | ||||
2500 | if (pipe_idx < 0) | |||
2501 | /* acquire new resources */ | |||
2502 | pipe_idx = acquire_first_free_pipe(&context->res_ctx, pool, stream); | |||
2503 | ||||
2504 | if (pipe_idx < 0) | |||
2505 | pipe_idx = acquire_first_split_pipe(&context->res_ctx, pool, stream); | |||
2506 | ||||
2507 | if (pipe_idx < 0 || context->res_ctx.pipe_ctx[pipe_idx].stream_res.tg == NULL((void *)0)) | |||
2508 | return DC_NO_CONTROLLER_RESOURCE; | |||
2509 | ||||
2510 | pipe_ctx = &context->res_ctx.pipe_ctx[pipe_idx]; | |||
2511 | ||||
2512 | pipe_ctx->stream_res.stream_enc = | |||
2513 | dc->res_pool->funcs->find_first_free_match_stream_enc_for_link( | |||
2514 | &context->res_ctx, pool, stream); | |||
2515 | ||||
2516 | if (!pipe_ctx->stream_res.stream_enc) | |||
2517 | return DC_NO_STREAM_ENC_RESOURCE; | |||
2518 | ||||
2519 | update_stream_engine_usage( | |||
2520 | &context->res_ctx, pool, | |||
2521 | pipe_ctx->stream_res.stream_enc, | |||
2522 | true1); | |||
2523 | ||||
2524 | /* Allocate DP HPO Stream Encoder based on signal, hw capabilities | |||
2525 | * and link settings | |||
2526 | */ | |||
2527 | if (dc_is_dp_signal(stream->signal)) { | |||
2528 | if (!decide_link_settings(stream, &pipe_ctx->link_config.dp_link_settings)) | |||
2529 | return DC_FAIL_DP_LINK_BANDWIDTH; | |||
2530 | if (dp_get_link_encoding_format(&pipe_ctx->link_config.dp_link_settings) == DP_128b_132b_ENCODING) { | |||
2531 | pipe_ctx->stream_res.hpo_dp_stream_enc = | |||
2532 | find_first_free_match_hpo_dp_stream_enc_for_link( | |||
2533 | &context->res_ctx, pool, stream); | |||
2534 | ||||
2535 | if (!pipe_ctx->stream_res.hpo_dp_stream_enc) | |||
2536 | return DC_NO_STREAM_ENC_RESOURCE; | |||
2537 | ||||
2538 | update_hpo_dp_stream_engine_usage( | |||
2539 | &context->res_ctx, pool, | |||
2540 | pipe_ctx->stream_res.hpo_dp_stream_enc, | |||
2541 | true1); | |||
2542 | if (!add_hpo_dp_link_enc_to_ctx(&context->res_ctx, pool, pipe_ctx, stream)) | |||
2543 | return DC_NO_LINK_ENC_RESOURCE; | |||
2544 | } | |||
2545 | } | |||
2546 | ||||
2547 | /* TODO: Add check if ASIC support and EDID audio */ | |||
2548 | if (!stream->converter_disable_audio && | |||
2549 | dc_is_audio_capable_signal(pipe_ctx->stream->signal) && | |||
2550 | stream->audio_info.mode_count && stream->audio_info.flags.all) { | |||
2551 | pipe_ctx->stream_res.audio = find_first_free_audio( | |||
2552 | &context->res_ctx, pool, pipe_ctx->stream_res.stream_enc->id, dc_ctx->dce_version); | |||
2553 | ||||
2554 | /* | |||
2555 | * Audio assigned in order first come first get. | |||
2556 | * There are asics which has number of audio | |||
2557 | * resources less then number of pipes | |||
2558 | */ | |||
2559 | if (pipe_ctx->stream_res.audio) | |||
2560 | update_audio_usage(&context->res_ctx, pool, | |||
2561 | pipe_ctx->stream_res.audio, true1); | |||
2562 | } | |||
2563 | ||||
2564 | /* Add ABM to the resource if on EDP */ | |||
2565 | if (pipe_ctx->stream && dc_is_embedded_signal(pipe_ctx->stream->signal)) { | |||
2566 | if (pool->abm) | |||
2567 | pipe_ctx->stream_res.abm = pool->abm; | |||
2568 | else | |||
2569 | pipe_ctx->stream_res.abm = pool->multiple_abms[pipe_ctx->stream_res.tg->inst]; | |||
2570 | } | |||
2571 | ||||
2572 | for (i = 0; i < context->stream_count; i++) | |||
2573 | if (context->streams[i] == stream) { | |||
2574 | context->stream_status[i].primary_otg_inst = pipe_ctx->stream_res.tg->inst; | |||
2575 | context->stream_status[i].stream_enc_inst = pipe_ctx->stream_res.stream_enc->stream_enc_inst; | |||
2576 | context->stream_status[i].audio_inst = | |||
2577 | pipe_ctx->stream_res.audio ? pipe_ctx->stream_res.audio->inst : -1; | |||
2578 | ||||
2579 | return DC_OK; | |||
2580 | } | |||
2581 | ||||
2582 | DC_ERROR("Stream %p not found in new ctx!\n", stream)do { (void)(dc_ctx); __drm_err("Stream %p not found in new ctx!\n" , stream); } while (0); | |||
2583 | return DC_ERROR_UNEXPECTED; | |||
2584 | } | |||
2585 | ||||
2586 | /** | |||
2587 | * dc_resource_state_copy_construct_current() - Creates a new dc_state from existing state | |||
2588 | * Is a shallow copy. Increments refcounts on existing streams and planes. | |||
2589 | * @dc: copy out of dc->current_state | |||
2590 | * @dst_ctx: copy into this | |||
2591 | */ | |||
2592 | void dc_resource_state_copy_construct_current( | |||
2593 | const struct dc *dc, | |||
2594 | struct dc_state *dst_ctx) | |||
2595 | { | |||
2596 | dc_resource_state_copy_construct(dc->current_state, dst_ctx); | |||
2597 | } | |||
2598 | ||||
2599 | ||||
2600 | void dc_resource_state_construct( | |||
2601 | const struct dc *dc, | |||
2602 | struct dc_state *dst_ctx) | |||
2603 | { | |||
2604 | dst_ctx->clk_mgr = dc->clk_mgr; | |||
2605 | ||||
2606 | /* Initialise DIG link encoder resource tracking variables. */ | |||
2607 | link_enc_cfg_init(dc, dst_ctx); | |||
2608 | } | |||
2609 | ||||
2610 | ||||
2611 | bool_Bool dc_resource_is_dsc_encoding_supported(const struct dc *dc) | |||
2612 | { | |||
2613 | if (dc->res_pool == NULL((void *)0)) | |||
2614 | return false0; | |||
2615 | ||||
2616 | return dc->res_pool->res_cap->num_dsc > 0; | |||
2617 | } | |||
2618 | ||||
2619 | static bool_Bool planes_changed_for_existing_stream(struct dc_state *context, | |||
2620 | struct dc_stream_state *stream, | |||
2621 | const struct dc_validation_set set[], | |||
2622 | int set_count) | |||
2623 | { | |||
2624 | int i, j; | |||
2625 | struct dc_stream_status *stream_status = NULL((void *)0); | |||
2626 | ||||
2627 | for (i = 0; i < context->stream_count; i++) { | |||
2628 | if (context->streams[i] == stream) { | |||
2629 | stream_status = &context->stream_status[i]; | |||
2630 | break; | |||
2631 | } | |||
2632 | } | |||
2633 | ||||
2634 | if (!stream_status) | |||
2635 | ASSERT(0)do { if (({ static int __warned; int __ret = !!(!(0)); if (__ret && !__warned) { printf("WARNING %s failed at %s:%d\n" , "!(0)", "/usr/src/sys/dev/pci/drm/amd/display/dc/core/dc_resource.c" , 2635); __warned = 1; } __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); | |||
2636 | ||||
2637 | for (i = 0; i < set_count; i++) | |||
2638 | if (set[i].stream == stream) | |||
2639 | break; | |||
2640 | ||||
2641 | if (i == set_count) | |||
2642 | ASSERT(0)do { if (({ static int __warned; int __ret = !!(!(0)); if (__ret && !__warned) { printf("WARNING %s failed at %s:%d\n" , "!(0)", "/usr/src/sys/dev/pci/drm/amd/display/dc/core/dc_resource.c" , 2642); __warned = 1; } __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); | |||
2643 | ||||
2644 | if (set[i].plane_count != stream_status->plane_count) | |||
2645 | return true1; | |||
2646 | ||||
2647 | for (j = 0; j < set[i].plane_count; j++) | |||
2648 | if (set[i].plane_states[j] != stream_status->plane_states[j]) | |||
2649 | return true1; | |||
2650 | ||||
2651 | return false0; | |||
2652 | } | |||
2653 | ||||
2654 | /** | |||
2655 | * dc_validate_with_context - Validate and update the potential new stream in the context object | |||
2656 | * | |||
2657 | * @dc: Used to get the current state status | |||
2658 | * @set: An array of dc_validation_set with all the current streams reference | |||
2659 | * @set_count: Total of streams | |||
2660 | * @context: New context | |||
2661 | * @fast_validate: Enable or disable fast validation | |||
2662 | * | |||
2663 | * This function updates the potential new stream in the context object. It | |||
2664 | * creates multiple lists for the add, remove, and unchanged streams. In | |||
2665 | * particular, if the unchanged streams have a plane that changed, it is | |||
2666 | * necessary to remove all planes from the unchanged streams. In summary, this | |||
2667 | * function is responsible for validating the new context. | |||
2668 | * | |||
2669 | * Return: | |||
2670 | * In case of success, return DC_OK (1), otherwise, return a DC error. | |||
2671 | */ | |||
2672 | enum dc_status dc_validate_with_context(struct dc *dc, | |||
2673 | const struct dc_validation_set set[], | |||
2674 | int set_count, | |||
2675 | struct dc_state *context, | |||
2676 | bool_Bool fast_validate) | |||
2677 | { | |||
2678 | struct dc_stream_state *unchanged_streams[MAX_PIPES6] = { 0 }; | |||
2679 | struct dc_stream_state *del_streams[MAX_PIPES6] = { 0 }; | |||
2680 | struct dc_stream_state *add_streams[MAX_PIPES6] = { 0 }; | |||
2681 | int old_stream_count = context->stream_count; | |||
2682 | enum dc_status res = DC_ERROR_UNEXPECTED; | |||
2683 | int unchanged_streams_count = 0; | |||
2684 | int del_streams_count = 0; | |||
2685 | int add_streams_count = 0; | |||
2686 | bool_Bool found = false0; | |||
2687 | int i, j, k; | |||
2688 | ||||
2689 | DC_LOGGER_INIT(dc->ctx->logger); | |||
2690 | ||||
2691 | /* First build a list of streams to be remove from current context */ | |||
2692 | for (i = 0; i < old_stream_count; i++) { | |||
2693 | struct dc_stream_state *stream = context->streams[i]; | |||
2694 | ||||
2695 | for (j = 0; j < set_count; j++) { | |||
2696 | if (stream == set[j].stream) { | |||
2697 | found = true1; | |||
2698 | break; | |||
2699 | } | |||
2700 | } | |||
2701 | ||||
2702 | if (!found) | |||
2703 | del_streams[del_streams_count++] = stream; | |||
2704 | ||||
2705 | found = false0; | |||
2706 | } | |||
2707 | ||||
2708 | /* Second, build a list of new streams */ | |||
2709 | for (i = 0; i < set_count; i++) { | |||
2710 | struct dc_stream_state *stream = set[i].stream; | |||
2711 | ||||
2712 | for (j = 0; j < old_stream_count; j++) { | |||
2713 | if (stream == context->streams[j]) { | |||
2714 | found = true1; | |||
2715 | break; | |||
2716 | } | |||
2717 | } | |||
2718 | ||||
2719 | if (!found) | |||
2720 | add_streams[add_streams_count++] = stream; | |||
2721 | ||||
2722 | found = false0; | |||
2723 | } | |||
2724 | ||||
2725 | /* Build a list of unchanged streams which is necessary for handling | |||
2726 | * planes change such as added, removed, and updated. | |||
2727 | */ | |||
2728 | for (i = 0; i < set_count; i++) { | |||
2729 | /* Check if stream is part of the delete list */ | |||
2730 | for (j = 0; j < del_streams_count; j++) { | |||
2731 | if (set[i].stream == del_streams[j]) { | |||
2732 | found = true1; | |||
2733 | break; | |||
2734 | } | |||
2735 | } | |||
2736 | ||||
2737 | if (!found) { | |||
2738 | /* Check if stream is part of the add list */ | |||
2739 | for (j = 0; j < add_streams_count; j++) { | |||
2740 | if (set[i].stream == add_streams[j]) { | |||
2741 | found = true1; | |||
2742 | break; | |||
2743 | } | |||
2744 | } | |||
2745 | } | |||
2746 | ||||
2747 | if (!found) | |||
2748 | unchanged_streams[unchanged_streams_count++] = set[i].stream; | |||
2749 | ||||
2750 | found = false0; | |||
2751 | } | |||
2752 | ||||
2753 | /* Remove all planes for unchanged streams if planes changed */ | |||
2754 | for (i = 0; i < unchanged_streams_count; i++) { | |||
2755 | if (planes_changed_for_existing_stream(context, | |||
2756 | unchanged_streams[i], | |||
2757 | set, | |||
2758 | set_count)) { | |||
2759 | if (!dc_rem_all_planes_for_stream(dc, | |||
2760 | unchanged_streams[i], | |||
2761 | context)) { | |||
2762 | res = DC_FAIL_DETACH_SURFACES; | |||
2763 | goto fail; | |||
2764 | } | |||
2765 | } | |||
2766 | } | |||
2767 | ||||
2768 | /* Remove all planes for removed streams and then remove the streams */ | |||
2769 | for (i = 0; i < del_streams_count; i++) { | |||
2770 | /* Need to cpy the dwb data from the old stream in order to efc to work */ | |||
2771 | if (del_streams[i]->num_wb_info > 0) { | |||
2772 | for (j = 0; j < add_streams_count; j++) { | |||
2773 | if (del_streams[i]->sink == add_streams[j]->sink) { | |||
2774 | add_streams[j]->num_wb_info = del_streams[i]->num_wb_info; | |||
2775 | for (k = 0; k < del_streams[i]->num_wb_info; k++) | |||
2776 | add_streams[j]->writeback_info[k] = del_streams[i]->writeback_info[k]; | |||
2777 | } | |||
2778 | } | |||
2779 | } | |||
2780 | ||||
2781 | if (!dc_rem_all_planes_for_stream(dc, del_streams[i], context)) { | |||
2782 | res = DC_FAIL_DETACH_SURFACES; | |||
2783 | goto fail; | |||
2784 | } | |||
2785 | ||||
2786 | res = dc_remove_stream_from_ctx(dc, context, del_streams[i]); | |||
2787 | if (res != DC_OK) | |||
2788 | goto fail; | |||
2789 | } | |||
2790 | ||||
2791 | /* Swap seamless boot stream to pipe 0 (if needed) to ensure pipe_ctx | |||
2792 | * matches. This may change in the future if seamless_boot_stream can be | |||
2793 | * multiple. | |||
2794 | */ | |||
2795 | for (i = 0; i < add_streams_count; i++) { | |||
2796 | mark_seamless_boot_stream(dc, add_streams[i]); | |||
2797 | if (add_streams[i]->apply_seamless_boot_optimization && i != 0) { | |||
2798 | struct dc_stream_state *temp = add_streams[0]; | |||
2799 | ||||
2800 | add_streams[0] = add_streams[i]; | |||
2801 | add_streams[i] = temp; | |||
2802 | break; | |||
2803 | } | |||
2804 | } | |||
2805 | ||||
2806 | /* Add new streams and then add all planes for the new stream */ | |||
2807 | for (i = 0; i < add_streams_count; i++) { | |||
2808 | calculate_phy_pix_clks(add_streams[i]); | |||
2809 | res = dc_add_stream_to_ctx(dc, context, add_streams[i]); | |||
2810 | if (res != DC_OK) | |||
2811 | goto fail; | |||
2812 | ||||
2813 | if (!add_all_planes_for_stream(dc, add_streams[i], set, set_count, context)) { | |||
2814 | res = DC_FAIL_ATTACH_SURFACES; | |||
2815 | goto fail; | |||
2816 | } | |||
2817 | } | |||
2818 | ||||
2819 | /* Add all planes for unchanged streams if planes changed */ | |||
2820 | for (i = 0; i < unchanged_streams_count; i++) { | |||
2821 | if (planes_changed_for_existing_stream(context, | |||
2822 | unchanged_streams[i], | |||
2823 | set, | |||
2824 | set_count)) { | |||
2825 | if (!add_all_planes_for_stream(dc, unchanged_streams[i], set, set_count, context)) { | |||
2826 | res = DC_FAIL_ATTACH_SURFACES; | |||
2827 | goto fail; | |||
2828 | } | |||
2829 | } | |||
2830 | } | |||
2831 | ||||
2832 | res = dc_validate_global_state(dc, context, fast_validate); | |||
2833 | ||||
2834 | fail: | |||
2835 | if (res != DC_OK) | |||
2836 | DC_LOG_WARNING("%s:resource validation failed, dc_status:%d\n",printk("\0014" "[" "drm" "] " "%s:resource validation failed, dc_status:%d\n" , __func__, res) | |||
2837 | __func__,printk("\0014" "[" "drm" "] " "%s:resource validation failed, dc_status:%d\n" , __func__, res) | |||
2838 | res)printk("\0014" "[" "drm" "] " "%s:resource validation failed, dc_status:%d\n" , __func__, res); | |||
2839 | ||||
2840 | return res; | |||
2841 | } | |||
2842 | ||||
2843 | /** | |||
2844 | * dc_validate_global_state() - Determine if hardware can support a given state | |||
2845 | * | |||
2846 | * @dc: dc struct for this driver | |||
2847 | * @new_ctx: state to be validated | |||
2848 | * @fast_validate: set to true if only yes/no to support matters | |||
2849 | * | |||
2850 | * Checks hardware resource availability and bandwidth requirement. | |||
2851 | * | |||
2852 | * Return: | |||
2853 | * DC_OK if the result can be programmed. Otherwise, an error code. | |||
2854 | */ | |||
2855 | enum dc_status dc_validate_global_state( | |||
2856 | struct dc *dc, | |||
2857 | struct dc_state *new_ctx, | |||
2858 | bool_Bool fast_validate) | |||
2859 | { | |||
2860 | enum dc_status result = DC_ERROR_UNEXPECTED; | |||
2861 | int i, j; | |||
2862 | ||||
2863 | if (!new_ctx) | |||
2864 | return DC_ERROR_UNEXPECTED; | |||
2865 | ||||
2866 | if (dc->res_pool->funcs->validate_global) { | |||
2867 | result = dc->res_pool->funcs->validate_global(dc, new_ctx); | |||
2868 | if (result != DC_OK) | |||
2869 | return result; | |||
2870 | } | |||
2871 | ||||
2872 | for (i = 0; i < new_ctx->stream_count; i++) { | |||
2873 | struct dc_stream_state *stream = new_ctx->streams[i]; | |||
2874 | ||||
2875 | for (j = 0; j < dc->res_pool->pipe_count; j++) { | |||
2876 | struct pipe_ctx *pipe_ctx = &new_ctx->res_ctx.pipe_ctx[j]; | |||
2877 | ||||
2878 | if (pipe_ctx->stream != stream) | |||
2879 | continue; | |||
2880 | ||||
2881 | if (dc->res_pool->funcs->patch_unknown_plane_state && | |||
2882 | pipe_ctx->plane_state && | |||
2883 | pipe_ctx->plane_state->tiling_info.gfx9.swizzle == DC_SW_UNKNOWN) { | |||
2884 | result = dc->res_pool->funcs->patch_unknown_plane_state(pipe_ctx->plane_state); | |||
2885 | if (result != DC_OK) | |||
2886 | return result; | |||
2887 | } | |||
2888 | ||||
2889 | /* Switch to dp clock source only if there is | |||
2890 | * no non dp stream that shares the same timing | |||
2891 | * with the dp stream. | |||
2892 | */ | |||
2893 | if (dc_is_dp_signal(pipe_ctx->stream->signal) && | |||
2894 | !find_pll_sharable_stream(stream, new_ctx)) { | |||
2895 | ||||
2896 | resource_unreference_clock_source( | |||
2897 | &new_ctx->res_ctx, | |||
2898 | dc->res_pool, | |||
2899 | pipe_ctx->clock_source); | |||
2900 | ||||
2901 | pipe_ctx->clock_source = dc->res_pool->dp_clock_source; | |||
2902 | resource_reference_clock_source( | |||
2903 | &new_ctx->res_ctx, | |||
2904 | dc->res_pool, | |||
2905 | pipe_ctx->clock_source); | |||
2906 | } | |||
2907 | } | |||
2908 | } | |||
2909 | ||||
2910 | result = resource_build_scaling_params_for_context(dc, new_ctx); | |||
2911 | ||||
2912 | if (result == DC_OK) | |||
2913 | if (!dc->res_pool->funcs->validate_bandwidth(dc, new_ctx, fast_validate)) | |||
2914 | result = DC_FAIL_BANDWIDTH_VALIDATE; | |||
2915 | ||||
2916 | /* | |||
2917 | * Only update link encoder to stream assignment after bandwidth validation passed. | |||
2918 | * TODO: Split out assignment and validation. | |||
2919 | */ | |||
2920 | if (result == DC_OK && dc->res_pool->funcs->link_encs_assign && fast_validate == false0) | |||
2921 | dc->res_pool->funcs->link_encs_assign( | |||
2922 | dc, new_ctx, new_ctx->streams, new_ctx->stream_count); | |||
2923 | ||||
2924 | return result; | |||
2925 | } | |||
2926 | ||||
2927 | static void patch_gamut_packet_checksum( | |||
2928 | struct dc_info_packet *gamut_packet) | |||
2929 | { | |||
2930 | /* For gamut we recalc checksum */ | |||
2931 | if (gamut_packet->valid) { | |||
2932 | uint8_t chk_sum = 0; | |||
2933 | uint8_t *ptr; | |||
2934 | uint8_t i; | |||
2935 | ||||
2936 | /*start of the Gamut data. */ | |||
2937 | ptr = &gamut_packet->sb[3]; | |||
2938 | ||||
2939 | for (i = 0; i <= gamut_packet->sb[1]; i++) | |||
2940 | chk_sum += ptr[i]; | |||
2941 | ||||
2942 | gamut_packet->sb[2] = (uint8_t) (0x100 - chk_sum); | |||
2943 | } | |||
2944 | } | |||
2945 | ||||
2946 | static void set_avi_info_frame( | |||
2947 | struct dc_info_packet *info_packet, | |||
2948 | struct pipe_ctx *pipe_ctx) | |||
2949 | { | |||
2950 | struct dc_stream_state *stream = pipe_ctx->stream; | |||
2951 | enum dc_color_space color_space = COLOR_SPACE_UNKNOWN; | |||
2952 | uint32_t pixel_encoding = 0; | |||
2953 | enum scanning_type scan_type = SCANNING_TYPE_NODATA; | |||
2954 | enum dc_aspect_ratio aspect = ASPECT_RATIO_NO_DATA; | |||
2955 | bool_Bool itc = false0; | |||
2956 | uint8_t itc_value = 0; | |||
2957 | uint8_t cn0_cn1 = 0; | |||
2958 | unsigned int cn0_cn1_value = 0; | |||
2959 | uint8_t *check_sum = NULL((void *)0); | |||
2960 | uint8_t byte_index = 0; | |||
2961 | union hdmi_info_packet hdmi_info; | |||
2962 | union display_content_support support = {0}; | |||
2963 | unsigned int vic = pipe_ctx->stream->timing.vic; | |||
2964 | unsigned int rid = pipe_ctx->stream->timing.rid; | |||
2965 | unsigned int fr_ind = pipe_ctx->stream->timing.fr_index; | |||
2966 | enum dc_timing_3d_format format; | |||
2967 | ||||
2968 | memset(&hdmi_info, 0, sizeof(union hdmi_info_packet))__builtin_memset((&hdmi_info), (0), (sizeof(union hdmi_info_packet ))); | |||
2969 | ||||
2970 | color_space = pipe_ctx->stream->output_color_space; | |||
2971 | if (color_space == COLOR_SPACE_UNKNOWN) | |||
2972 | color_space = (stream->timing.pixel_encoding == PIXEL_ENCODING_RGB) ? | |||
2973 | COLOR_SPACE_SRGB:COLOR_SPACE_YCBCR709; | |||
2974 | ||||
2975 | /* Initialize header */ | |||
2976 | hdmi_info.bits.header.info_frame_type = HDMI_INFOFRAME_TYPE_AVI; | |||
2977 | /* InfoFrameVersion_3 is defined by CEA861F (Section 6.4), but shall | |||
2978 | * not be used in HDMI 2.0 (Section 10.1) */ | |||
2979 | hdmi_info.bits.header.version = 2; | |||
2980 | hdmi_info.bits.header.length = HDMI_AVI_INFOFRAME_SIZE13; | |||
2981 | ||||
2982 | /* | |||
2983 | * IDO-defined (Y2,Y1,Y0 = 1,1,1) shall not be used by devices built | |||
2984 | * according to HDMI 2.0 spec (Section 10.1) | |||
2985 | */ | |||
2986 | ||||
2987 | switch (stream->timing.pixel_encoding) { | |||
2988 | case PIXEL_ENCODING_YCBCR422: | |||
2989 | pixel_encoding = 1; | |||
2990 | break; | |||
2991 | ||||
2992 | case PIXEL_ENCODING_YCBCR444: | |||
2993 | pixel_encoding = 2; | |||
2994 | break; | |||
2995 | case PIXEL_ENCODING_YCBCR420: | |||
2996 | pixel_encoding = 3; | |||
2997 | break; | |||
2998 | ||||
2999 | case PIXEL_ENCODING_RGB: | |||
3000 | default: | |||
3001 | pixel_encoding = 0; | |||
3002 | } | |||
3003 | ||||
3004 | /* Y0_Y1_Y2 : The pixel encoding */ | |||
3005 | /* H14b AVI InfoFrame has extension on Y-field from 2 bits to 3 bits */ | |||
3006 | hdmi_info.bits.Y0_Y1_Y2 = pixel_encoding; | |||
3007 | ||||
3008 | /* A0 = 1 Active Format Information valid */ | |||
3009 | hdmi_info.bits.A0 = ACTIVE_FORMAT_VALID; | |||
3010 | ||||
3011 | /* B0, B1 = 3; Bar info data is valid */ | |||
3012 | hdmi_info.bits.B0_B1 = BAR_INFO_BOTH_VALID; | |||
3013 | ||||
3014 | hdmi_info.bits.SC0_SC1 = PICTURE_SCALING_UNIFORM; | |||
3015 | ||||
3016 | /* S0, S1 : Underscan / Overscan */ | |||
3017 | /* TODO: un-hardcode scan type */ | |||
3018 | scan_type = SCANNING_TYPE_UNDERSCAN; | |||
3019 | hdmi_info.bits.S0_S1 = scan_type; | |||
3020 | ||||
3021 | /* C0, C1 : Colorimetry */ | |||
3022 | if (color_space == COLOR_SPACE_YCBCR709 || | |||
3023 | color_space == COLOR_SPACE_YCBCR709_LIMITED) | |||
3024 | hdmi_info.bits.C0_C1 = COLORIMETRY_ITU709; | |||
3025 | else if (color_space == COLOR_SPACE_YCBCR601 || | |||
3026 | color_space == COLOR_SPACE_YCBCR601_LIMITED) | |||
3027 | hdmi_info.bits.C0_C1 = COLORIMETRY_ITU601; | |||
3028 | else { | |||
3029 | hdmi_info.bits.C0_C1 = COLORIMETRY_NO_DATA; | |||
3030 | } | |||
3031 | if (color_space == COLOR_SPACE_2020_RGB_FULLRANGE || | |||
3032 | color_space == COLOR_SPACE_2020_RGB_LIMITEDRANGE || | |||
3033 | color_space == COLOR_SPACE_2020_YCBCR) { | |||
3034 | hdmi_info.bits.EC0_EC2 = COLORIMETRYEX_BT2020RGBYCBCR; | |||
3035 | hdmi_info.bits.C0_C1 = COLORIMETRY_EXTENDED; | |||
3036 | } else if (color_space == COLOR_SPACE_ADOBERGB) { | |||
3037 | hdmi_info.bits.EC0_EC2 = COLORIMETRYEX_ADOBERGB; | |||
3038 | hdmi_info.bits.C0_C1 = COLORIMETRY_EXTENDED; | |||
3039 | } | |||
3040 | ||||
3041 | /* TODO: un-hardcode aspect ratio */ | |||
3042 | aspect = stream->timing.aspect_ratio; | |||
3043 | ||||
3044 | switch (aspect) { | |||
3045 | case ASPECT_RATIO_4_3: | |||
3046 | case ASPECT_RATIO_16_9: | |||
3047 | hdmi_info.bits.M0_M1 = aspect; | |||
3048 | break; | |||
3049 | ||||
3050 | case ASPECT_RATIO_NO_DATA: | |||
3051 | case ASPECT_RATIO_64_27: | |||
3052 | case ASPECT_RATIO_256_135: | |||
3053 | default: | |||
3054 | hdmi_info.bits.M0_M1 = 0; | |||
3055 | } | |||
3056 | ||||
3057 | /* Active Format Aspect ratio - same as Picture Aspect Ratio. */ | |||
3058 | hdmi_info.bits.R0_R3 = ACTIVE_FORMAT_ASPECT_RATIO_SAME_AS_PICTURE; | |||
3059 | ||||
3060 | /* TODO: un-hardcode cn0_cn1 and itc */ | |||
3061 | ||||
3062 | cn0_cn1 = 0; | |||
3063 | cn0_cn1_value = 0; | |||
3064 | ||||
3065 | itc = true1; | |||
3066 | itc_value = 1; | |||
3067 | ||||
3068 | support = stream->content_support; | |||
3069 | ||||
3070 | if (itc) { | |||
3071 | if (!support.bits.valid_content_type) { | |||
3072 | cn0_cn1_value = 0; | |||
3073 | } else { | |||
3074 | if (cn0_cn1 == DISPLAY_CONTENT_TYPE_GRAPHICS) { | |||
3075 | if (support.bits.graphics_content == 1) { | |||
3076 | cn0_cn1_value = 0; | |||
3077 | } | |||
3078 | } else if (cn0_cn1 == DISPLAY_CONTENT_TYPE_PHOTO) { | |||
3079 | if (support.bits.photo_content == 1) { | |||
3080 | cn0_cn1_value = 1; | |||
3081 | } else { | |||
3082 | cn0_cn1_value = 0; | |||
3083 | itc_value = 0; | |||
3084 | } | |||
3085 | } else if (cn0_cn1 == DISPLAY_CONTENT_TYPE_CINEMA) { | |||
3086 | if (support.bits.cinema_content == 1) { | |||
3087 | cn0_cn1_value = 2; | |||
3088 | } else { | |||
3089 | cn0_cn1_value = 0; | |||
3090 | itc_value = 0; | |||
3091 | } | |||
3092 | } else if (cn0_cn1 == DISPLAY_CONTENT_TYPE_GAME) { | |||
3093 | if (support.bits.game_content == 1) { | |||
3094 | cn0_cn1_value = 3; | |||
3095 | } else { | |||
3096 | cn0_cn1_value = 0; | |||
3097 | itc_value = 0; | |||
3098 | } | |||
3099 | } | |||
3100 | } | |||
3101 | hdmi_info.bits.CN0_CN1 = cn0_cn1_value; | |||
3102 | hdmi_info.bits.ITC = itc_value; | |||
3103 | } | |||
3104 | ||||
3105 | if (stream->qs_bit == 1) { | |||
3106 | if (color_space == COLOR_SPACE_SRGB || | |||
3107 | color_space == COLOR_SPACE_2020_RGB_FULLRANGE) | |||
3108 | hdmi_info.bits.Q0_Q1 = RGB_QUANTIZATION_FULL_RANGE; | |||
3109 | else if (color_space == COLOR_SPACE_SRGB_LIMITED || | |||
3110 | color_space == COLOR_SPACE_2020_RGB_LIMITEDRANGE) | |||
3111 | hdmi_info.bits.Q0_Q1 = RGB_QUANTIZATION_LIMITED_RANGE; | |||
3112 | else | |||
3113 | hdmi_info.bits.Q0_Q1 = RGB_QUANTIZATION_DEFAULT_RANGE; | |||
3114 | } else | |||
3115 | hdmi_info.bits.Q0_Q1 = RGB_QUANTIZATION_DEFAULT_RANGE; | |||
3116 | ||||
3117 | /* TODO : We should handle YCC quantization */ | |||
3118 | /* but we do not have matrix calculation */ | |||
3119 | hdmi_info.bits.YQ0_YQ1 = YYC_QUANTIZATION_LIMITED_RANGE; | |||
3120 | ||||
3121 | ///VIC | |||
3122 | if (pipe_ctx->stream->timing.hdmi_vic != 0) | |||
3123 | vic = 0; | |||
3124 | format = stream->timing.timing_3d_format; | |||
3125 | /*todo, add 3DStereo support*/ | |||
3126 | if (format != TIMING_3D_FORMAT_NONE) { | |||
3127 | // Based on HDMI specs hdmi vic needs to be converted to cea vic when 3D is enabled | |||
3128 | switch (pipe_ctx->stream->timing.hdmi_vic) { | |||
3129 | case 1: | |||
3130 | vic = 95; | |||
3131 | break; | |||
3132 | case 2: | |||
3133 | vic = 94; | |||
3134 | break; | |||
3135 | case 3: | |||
3136 | vic = 93; | |||
3137 | break; | |||
3138 | case 4: | |||
3139 | vic = 98; | |||
3140 | break; | |||
3141 | default: | |||
3142 | break; | |||
3143 | } | |||
3144 | } | |||
3145 | /* If VIC >= 128, the Source shall use AVI InfoFrame Version 3*/ | |||
3146 | hdmi_info.bits.VIC0_VIC7 = vic; | |||
3147 | if (vic >= 128) | |||
3148 | hdmi_info.bits.header.version = 3; | |||
3149 | /* If (C1, C0)=(1, 1) and (EC2, EC1, EC0)=(1, 1, 1), | |||
3150 | * the Source shall use 20 AVI InfoFrame Version 4 | |||
3151 | */ | |||
3152 | if (hdmi_info.bits.C0_C1 == COLORIMETRY_EXTENDED && | |||
3153 | hdmi_info.bits.EC0_EC2 == COLORIMETRYEX_RESERVED) { | |||
3154 | hdmi_info.bits.header.version = 4; | |||
3155 | hdmi_info.bits.header.length = 14; | |||
3156 | } | |||
3157 | ||||
3158 | if (rid != 0 && fr_ind != 0) { | |||
3159 | hdmi_info.bits.header.version = 5; | |||
3160 | hdmi_info.bits.header.length = 15; | |||
3161 | ||||
3162 | hdmi_info.bits.FR0_FR3 = fr_ind & 0xF; | |||
3163 | hdmi_info.bits.FR4 = (fr_ind >> 4) & 0x1; | |||
3164 | hdmi_info.bits.RID0_RID5 = rid; | |||
3165 | } | |||
3166 | ||||
3167 | /* pixel repetition | |||
3168 | * PR0 - PR3 start from 0 whereas pHwPathMode->mode.timing.flags.pixel | |||
3169 | * repetition start from 1 */ | |||
3170 | hdmi_info.bits.PR0_PR3 = 0; | |||
3171 | ||||
3172 | /* Bar Info | |||
3173 | * barTop: Line Number of End of Top Bar. | |||
3174 | * barBottom: Line Number of Start of Bottom Bar. | |||
3175 | * barLeft: Pixel Number of End of Left Bar. | |||
3176 | * barRight: Pixel Number of Start of Right Bar. */ | |||
3177 | hdmi_info.bits.bar_top = stream->timing.v_border_top; | |||
3178 | hdmi_info.bits.bar_bottom = (stream->timing.v_total | |||
3179 | - stream->timing.v_border_bottom + 1); | |||
3180 | hdmi_info.bits.bar_left = stream->timing.h_border_left; | |||
3181 | hdmi_info.bits.bar_right = (stream->timing.h_total | |||
3182 | - stream->timing.h_border_right + 1); | |||
3183 | ||||
3184 | /* Additional Colorimetry Extension | |||
3185 | * Used in conduction with C0-C1 and EC0-EC2 | |||
3186 | * 0 = DCI-P3 RGB (D65) | |||
3187 | * 1 = DCI-P3 RGB (theater) | |||
3188 | */ | |||
3189 | hdmi_info.bits.ACE0_ACE3 = 0; | |||
3190 | ||||
3191 | /* check_sum - Calculate AFMT_AVI_INFO0 ~ AFMT_AVI_INFO3 */ | |||
3192 | check_sum = &hdmi_info.packet_raw_data.sb[0]; | |||
3193 | ||||
3194 | *check_sum = HDMI_INFOFRAME_TYPE_AVI + hdmi_info.bits.header.length + hdmi_info.bits.header.version; | |||
3195 | ||||
3196 | for (byte_index = 1; byte_index <= hdmi_info.bits.header.length; byte_index++) | |||
3197 | *check_sum += hdmi_info.packet_raw_data.sb[byte_index]; | |||
3198 | ||||
3199 | /* one byte complement */ | |||
3200 | *check_sum = (uint8_t) (0x100 - *check_sum); | |||
3201 | ||||
3202 | /* Store in hw_path_mode */ | |||
3203 | info_packet->hb0 = hdmi_info.packet_raw_data.hb0; | |||
3204 | info_packet->hb1 = hdmi_info.packet_raw_data.hb1; | |||
3205 | info_packet->hb2 = hdmi_info.packet_raw_data.hb2; | |||
3206 | ||||
3207 | for (byte_index = 0; byte_index < sizeof(hdmi_info.packet_raw_data.sb); byte_index++) | |||
3208 | info_packet->sb[byte_index] = hdmi_info.packet_raw_data.sb[byte_index]; | |||
3209 | ||||
3210 | info_packet->valid = true1; | |||
3211 | } | |||
3212 | ||||
3213 | static void set_vendor_info_packet( | |||
3214 | struct dc_info_packet *info_packet, | |||
3215 | struct dc_stream_state *stream) | |||
3216 | { | |||
3217 | /* SPD info packet for FreeSync */ | |||
3218 | ||||
3219 | /* Check if Freesync is supported. Return if false. If true, | |||
3220 | * set the corresponding bit in the info packet | |||
3221 | */ | |||
3222 | if (!stream->vsp_infopacket.valid) | |||
3223 | return; | |||
3224 | ||||
3225 | *info_packet = stream->vsp_infopacket; | |||
3226 | } | |||
3227 | ||||
3228 | static void set_spd_info_packet( | |||
3229 | struct dc_info_packet *info_packet, | |||
3230 | struct dc_stream_state *stream) | |||
3231 | { | |||
3232 | /* SPD info packet for FreeSync */ | |||
3233 | ||||
3234 | /* Check if Freesync is supported. Return if false. If true, | |||
3235 | * set the corresponding bit in the info packet | |||
3236 | */ | |||
3237 | if (!stream->vrr_infopacket.valid) | |||
3238 | return; | |||
3239 | ||||
3240 | *info_packet = stream->vrr_infopacket; | |||
3241 | } | |||
3242 | ||||
3243 | static void set_hdr_static_info_packet( | |||
3244 | struct dc_info_packet *info_packet, | |||
3245 | struct dc_stream_state *stream) | |||
3246 | { | |||
3247 | /* HDR Static Metadata info packet for HDR10 */ | |||
3248 | ||||
3249 | if (!stream->hdr_static_metadata.valid || | |||
3250 | stream->use_dynamic_meta) | |||
3251 | return; | |||
3252 | ||||
3253 | *info_packet = stream->hdr_static_metadata; | |||
3254 | } | |||
3255 | ||||
3256 | static void set_vsc_info_packet( | |||
3257 | struct dc_info_packet *info_packet, | |||
3258 | struct dc_stream_state *stream) | |||
3259 | { | |||
3260 | if (!stream->vsc_infopacket.valid) | |||
3261 | return; | |||
3262 | ||||
3263 | *info_packet = stream->vsc_infopacket; | |||
3264 | } | |||
3265 | static void set_hfvs_info_packet( | |||
3266 | struct dc_info_packet *info_packet, | |||
3267 | struct dc_stream_state *stream) | |||
3268 | { | |||
3269 | if (!stream->hfvsif_infopacket.valid) | |||
3270 | return; | |||
3271 | ||||
3272 | *info_packet = stream->hfvsif_infopacket; | |||
3273 | } | |||
3274 | ||||
3275 | ||||
3276 | static void set_vtem_info_packet( | |||
3277 | struct dc_info_packet *info_packet, | |||
3278 | struct dc_stream_state *stream) | |||
3279 | { | |||
3280 | if (!stream->vtem_infopacket.valid) | |||
3281 | return; | |||
3282 | ||||
3283 | *info_packet = stream->vtem_infopacket; | |||
3284 | } | |||
3285 | ||||
3286 | void dc_resource_state_destruct(struct dc_state *context) | |||
3287 | { | |||
3288 | int i, j; | |||
3289 | ||||
3290 | for (i = 0; i < context->stream_count; i++) { | |||
3291 | for (j = 0; j < context->stream_status[i].plane_count; j++) | |||
3292 | dc_plane_state_release( | |||
3293 | context->stream_status[i].plane_states[j]); | |||
3294 | ||||
3295 | context->stream_status[i].plane_count = 0; | |||
3296 | dc_stream_release(context->streams[i]); | |||
3297 | context->streams[i] = NULL((void *)0); | |||
3298 | } | |||
3299 | context->stream_count = 0; | |||
3300 | } | |||
3301 | ||||
3302 | void dc_resource_state_copy_construct( | |||
3303 | const struct dc_state *src_ctx, | |||
3304 | struct dc_state *dst_ctx) | |||
3305 | { | |||
3306 | int i, j; | |||
3307 | struct kref refcount = dst_ctx->refcount; | |||
3308 | ||||
3309 | *dst_ctx = *src_ctx; | |||
3310 | ||||
3311 | for (i = 0; i < MAX_PIPES6; i++) { | |||
3312 | struct pipe_ctx *cur_pipe = &dst_ctx->res_ctx.pipe_ctx[i]; | |||
3313 | ||||
3314 | if (cur_pipe->top_pipe) | |||
3315 | cur_pipe->top_pipe = &dst_ctx->res_ctx.pipe_ctx[cur_pipe->top_pipe->pipe_idx]; | |||
3316 | ||||
3317 | if (cur_pipe->bottom_pipe) | |||
3318 | cur_pipe->bottom_pipe = &dst_ctx->res_ctx.pipe_ctx[cur_pipe->bottom_pipe->pipe_idx]; | |||
3319 | ||||
3320 | if (cur_pipe->next_odm_pipe) | |||
3321 | cur_pipe->next_odm_pipe = &dst_ctx->res_ctx.pipe_ctx[cur_pipe->next_odm_pipe->pipe_idx]; | |||
3322 | ||||
3323 | if (cur_pipe->prev_odm_pipe) | |||
3324 | cur_pipe->prev_odm_pipe = &dst_ctx->res_ctx.pipe_ctx[cur_pipe->prev_odm_pipe->pipe_idx]; | |||
3325 | } | |||
3326 | ||||
3327 | for (i = 0; i < dst_ctx->stream_count; i++) { | |||
3328 | dc_stream_retain(dst_ctx->streams[i]); | |||
3329 | for (j = 0; j < dst_ctx->stream_status[i].plane_count; j++) | |||
3330 | dc_plane_state_retain( | |||
3331 | dst_ctx->stream_status[i].plane_states[j]); | |||
3332 | } | |||
3333 | ||||
3334 | /* context refcount should not be overridden */ | |||
3335 | dst_ctx->refcount = refcount; | |||
3336 | ||||
3337 | } | |||
3338 | ||||
3339 | struct clock_source *dc_resource_find_first_free_pll( | |||
3340 | struct resource_context *res_ctx, | |||
3341 | const struct resource_pool *pool) | |||
3342 | { | |||
3343 | int i; | |||
3344 | ||||
3345 | for (i = 0; i < pool->clk_src_count; ++i) { | |||
3346 | if (res_ctx->clock_source_ref_count[i] == 0) | |||
3347 | return pool->clock_sources[i]; | |||
3348 | } | |||
3349 | ||||
3350 | return NULL((void *)0); | |||
3351 | } | |||
3352 | ||||
3353 | void resource_build_info_frame(struct pipe_ctx *pipe_ctx) | |||
3354 | { | |||
3355 | enum amd_signal_type signal = SIGNAL_TYPE_NONE; | |||
3356 | struct encoder_info_frame *info = &pipe_ctx->stream_res.encoder_info_frame; | |||
3357 | ||||
3358 | /* default all packets to invalid */ | |||
3359 | info->avi.valid = false0; | |||
3360 | info->gamut.valid = false0; | |||
3361 | info->vendor.valid = false0; | |||
3362 | info->spd.valid = false0; | |||
3363 | info->hdrsmd.valid = false0; | |||
3364 | info->vsc.valid = false0; | |||
3365 | info->hfvsif.valid = false0; | |||
3366 | info->vtem.valid = false0; | |||
3367 | signal = pipe_ctx->stream->signal; | |||
3368 | ||||
3369 | /* HDMi and DP have different info packets*/ | |||
3370 | if (dc_is_hdmi_signal(signal)) { | |||
3371 | set_avi_info_frame(&info->avi, pipe_ctx); | |||
3372 | ||||
3373 | set_vendor_info_packet(&info->vendor, pipe_ctx->stream); | |||
3374 | set_hfvs_info_packet(&info->hfvsif, pipe_ctx->stream); | |||
3375 | set_vtem_info_packet(&info->vtem, pipe_ctx->stream); | |||
3376 | ||||
3377 | set_spd_info_packet(&info->spd, pipe_ctx->stream); | |||
3378 | ||||
3379 | set_hdr_static_info_packet(&info->hdrsmd, pipe_ctx->stream); | |||
3380 | ||||
3381 | } else if (dc_is_dp_signal(signal)) { | |||
3382 | set_vsc_info_packet(&info->vsc, pipe_ctx->stream); | |||
3383 | ||||
3384 | set_spd_info_packet(&info->spd, pipe_ctx->stream); | |||
3385 | ||||
3386 | set_hdr_static_info_packet(&info->hdrsmd, pipe_ctx->stream); | |||
3387 | } | |||
3388 | ||||
3389 | patch_gamut_packet_checksum(&info->gamut); | |||
3390 | } | |||
3391 | ||||
3392 | enum dc_status resource_map_clock_resources( | |||
3393 | const struct dc *dc, | |||
3394 | struct dc_state *context, | |||
3395 | struct dc_stream_state *stream) | |||
3396 | { | |||
3397 | /* acquire new resources */ | |||
3398 | const struct resource_pool *pool = dc->res_pool; | |||
3399 | struct pipe_ctx *pipe_ctx = resource_get_head_pipe_for_stream( | |||
3400 | &context->res_ctx, stream); | |||
3401 | ||||
3402 | if (!pipe_ctx) | |||
3403 | return DC_ERROR_UNEXPECTED; | |||
3404 | ||||
3405 | if (dc_is_dp_signal(pipe_ctx->stream->signal) | |||
3406 | || pipe_ctx->stream->signal == SIGNAL_TYPE_VIRTUAL) | |||
3407 | pipe_ctx->clock_source = pool->dp_clock_source; | |||
3408 | else { | |||
3409 | pipe_ctx->clock_source = NULL((void *)0); | |||
3410 | ||||
3411 | if (!dc->config.disable_disp_pll_sharing) | |||
3412 | pipe_ctx->clock_source = resource_find_used_clk_src_for_sharing( | |||
3413 | &context->res_ctx, | |||
3414 | pipe_ctx); | |||
3415 | ||||
3416 | if (pipe_ctx->clock_source == NULL((void *)0)) | |||
3417 | pipe_ctx->clock_source = | |||
3418 | dc_resource_find_first_free_pll( | |||
3419 | &context->res_ctx, | |||
3420 | pool); | |||
3421 | } | |||
3422 | ||||
3423 | if (pipe_ctx->clock_source == NULL((void *)0)) | |||
3424 | return DC_NO_CLOCK_SOURCE_RESOURCE; | |||
3425 | ||||
3426 | resource_reference_clock_source( | |||
3427 | &context->res_ctx, pool, | |||
3428 | pipe_ctx->clock_source); | |||
3429 | ||||
3430 | return DC_OK; | |||
3431 | } | |||
3432 | ||||
3433 | /* | |||
3434 | * Note: We need to disable output if clock sources change, | |||
3435 | * since bios does optimization and doesn't apply if changing | |||
3436 | * PHY when not already disabled. | |||
3437 | */ | |||
3438 | bool_Bool pipe_need_reprogram( | |||
3439 | struct pipe_ctx *pipe_ctx_old, | |||
3440 | struct pipe_ctx *pipe_ctx) | |||
3441 | { | |||
3442 | if (!pipe_ctx_old->stream) | |||
3443 | return false0; | |||
3444 | ||||
3445 | if (pipe_ctx_old->stream->sink != pipe_ctx->stream->sink) | |||
3446 | return true1; | |||
3447 | ||||
3448 | if (pipe_ctx_old->stream->signal != pipe_ctx->stream->signal) | |||
3449 | return true1; | |||
3450 | ||||
3451 | if (pipe_ctx_old->stream_res.audio != pipe_ctx->stream_res.audio) | |||
3452 | return true1; | |||
3453 | ||||
3454 | if (pipe_ctx_old->clock_source != pipe_ctx->clock_source | |||
3455 | && pipe_ctx_old->stream != pipe_ctx->stream) | |||
3456 | return true1; | |||
3457 | ||||
3458 | if (pipe_ctx_old->stream_res.stream_enc != pipe_ctx->stream_res.stream_enc) | |||
3459 | return true1; | |||
3460 | ||||
3461 | if (is_timing_changed(pipe_ctx_old->stream, pipe_ctx->stream)) | |||
3462 | return true1; | |||
3463 | ||||
3464 | if (pipe_ctx_old->stream->dpms_off != pipe_ctx->stream->dpms_off) | |||
3465 | return true1; | |||
3466 | ||||
3467 | if (false0 == pipe_ctx_old->stream->link->link_state_valid && | |||
3468 | false0 == pipe_ctx_old->stream->dpms_off) | |||
3469 | return true1; | |||
3470 | ||||
3471 | if (pipe_ctx_old->stream_res.dsc != pipe_ctx->stream_res.dsc) | |||
3472 | return true1; | |||
3473 | ||||
3474 | if (pipe_ctx_old->stream_res.hpo_dp_stream_enc != pipe_ctx->stream_res.hpo_dp_stream_enc) | |||
3475 | return true1; | |||
3476 | if (pipe_ctx_old->link_res.hpo_dp_link_enc != pipe_ctx->link_res.hpo_dp_link_enc) | |||
3477 | return true1; | |||
3478 | ||||
3479 | /* DIG link encoder resource assignment for stream changed. */ | |||
3480 | if (pipe_ctx_old->stream->ctx->dc->res_pool->funcs->link_encs_assign) { | |||
3481 | bool_Bool need_reprogram = false0; | |||
3482 | struct dc *dc = pipe_ctx_old->stream->ctx->dc; | |||
3483 | struct link_encoder *link_enc_prev = | |||
3484 | link_enc_cfg_get_link_enc_used_by_stream_current(dc, pipe_ctx_old->stream); | |||
3485 | ||||
3486 | if (link_enc_prev != pipe_ctx->stream->link_enc) | |||
3487 | need_reprogram = true1; | |||
3488 | ||||
3489 | return need_reprogram; | |||
3490 | } | |||
3491 | ||||
3492 | return false0; | |||
3493 | } | |||
3494 | ||||
3495 | void resource_build_bit_depth_reduction_params(struct dc_stream_state *stream, | |||
3496 | struct bit_depth_reduction_params *fmt_bit_depth) | |||
3497 | { | |||
3498 | enum dc_dither_option option = stream->dither_option; | |||
3499 | enum dc_pixel_encoding pixel_encoding = | |||
3500 | stream->timing.pixel_encoding; | |||
3501 | ||||
3502 | memset(fmt_bit_depth, 0, sizeof(*fmt_bit_depth))__builtin_memset((fmt_bit_depth), (0), (sizeof(*fmt_bit_depth ))); | |||
3503 | ||||
3504 | if (option == DITHER_OPTION_DEFAULT) { | |||
3505 | switch (stream->timing.display_color_depth) { | |||
3506 | case COLOR_DEPTH_666: | |||
3507 | option = DITHER_OPTION_SPATIAL6; | |||
3508 | break; | |||
3509 | case COLOR_DEPTH_888: | |||
3510 | option = DITHER_OPTION_SPATIAL8; | |||
3511 | break; | |||
3512 | case COLOR_DEPTH_101010: | |||
3513 | option = DITHER_OPTION_SPATIAL10; | |||
3514 | break; | |||
3515 | default: | |||
3516 | option = DITHER_OPTION_DISABLE; | |||
3517 | } | |||
3518 | } | |||
3519 | ||||
3520 | if (option == DITHER_OPTION_DISABLE) | |||
3521 | return; | |||
3522 | ||||
3523 | if (option == DITHER_OPTION_TRUN6) { | |||
3524 | fmt_bit_depth->flags.TRUNCATE_ENABLED = 1; | |||
3525 | fmt_bit_depth->flags.TRUNCATE_DEPTH = 0; | |||
3526 | } else if (option == DITHER_OPTION_TRUN8 || | |||
3527 | option == DITHER_OPTION_TRUN8_SPATIAL6 || | |||
3528 | option == DITHER_OPTION_TRUN8_FM6) { | |||
3529 | fmt_bit_depth->flags.TRUNCATE_ENABLED = 1; | |||
3530 | fmt_bit_depth->flags.TRUNCATE_DEPTH = 1; | |||
3531 | } else if (option == DITHER_OPTION_TRUN10 || | |||
3532 | option == DITHER_OPTION_TRUN10_SPATIAL6 || | |||
3533 | option == DITHER_OPTION_TRUN10_SPATIAL8 || | |||
3534 | option == DITHER_OPTION_TRUN10_FM8 || | |||
3535 | option == DITHER_OPTION_TRUN10_FM6 || | |||
3536 | option == DITHER_OPTION_TRUN10_SPATIAL8_FM6) { | |||
3537 | fmt_bit_depth->flags.TRUNCATE_ENABLED = 1; | |||
3538 | fmt_bit_depth->flags.TRUNCATE_DEPTH = 2; | |||
3539 | } | |||
3540 | ||||
3541 | /* special case - Formatter can only reduce by 4 bits at most. | |||
3542 | * When reducing from 12 to 6 bits, | |||
3543 | * HW recommends we use trunc with round mode | |||
3544 | * (if we did nothing, trunc to 10 bits would be used) | |||
3545 | * note that any 12->10 bit reduction is ignored prior to DCE8, | |||
3546 | * as the input was 10 bits. | |||
3547 | */ | |||
3548 | if (option == DITHER_OPTION_SPATIAL6_FRAME_RANDOM || | |||
3549 | option == DITHER_OPTION_SPATIAL6 || | |||
3550 | option == DITHER_OPTION_FM6) { | |||
3551 | fmt_bit_depth->flags.TRUNCATE_ENABLED = 1; | |||
3552 | fmt_bit_depth->flags.TRUNCATE_DEPTH = 2; | |||
3553 | fmt_bit_depth->flags.TRUNCATE_MODE = 1; | |||
3554 | } | |||
3555 | ||||
3556 | /* spatial dither | |||
3557 | * note that spatial modes 1-3 are never used | |||
3558 | */ | |||
3559 | if (option == DITHER_OPTION_SPATIAL6_FRAME_RANDOM || | |||
3560 | option == DITHER_OPTION_SPATIAL6 || | |||
3561 | option == DITHER_OPTION_TRUN10_SPATIAL6 || | |||
3562 | option == DITHER_OPTION_TRUN8_SPATIAL6) { | |||
3563 | fmt_bit_depth->flags.SPATIAL_DITHER_ENABLED = 1; | |||
3564 | fmt_bit_depth->flags.SPATIAL_DITHER_DEPTH = 0; | |||
3565 | fmt_bit_depth->flags.HIGHPASS_RANDOM = 1; | |||
3566 | fmt_bit_depth->flags.RGB_RANDOM = | |||
3567 | (pixel_encoding == PIXEL_ENCODING_RGB) ? 1 : 0; | |||
3568 | } else if (option == DITHER_OPTION_SPATIAL8_FRAME_RANDOM || | |||
3569 | option == DITHER_OPTION_SPATIAL8 || | |||
3570 | option == DITHER_OPTION_SPATIAL8_FM6 || | |||
3571 | option == DITHER_OPTION_TRUN10_SPATIAL8 || | |||
3572 | option == DITHER_OPTION_TRUN10_SPATIAL8_FM6) { | |||
3573 | fmt_bit_depth->flags.SPATIAL_DITHER_ENABLED = 1; | |||
3574 | fmt_bit_depth->flags.SPATIAL_DITHER_DEPTH = 1; | |||
3575 | fmt_bit_depth->flags.HIGHPASS_RANDOM = 1; | |||
3576 | fmt_bit_depth->flags.RGB_RANDOM = | |||
3577 | (pixel_encoding == PIXEL_ENCODING_RGB) ? 1 : 0; | |||
3578 | } else if (option == DITHER_OPTION_SPATIAL10_FRAME_RANDOM || | |||
3579 | option == DITHER_OPTION_SPATIAL10 || | |||
3580 | option == DITHER_OPTION_SPATIAL10_FM8 || | |||
3581 | option == DITHER_OPTION_SPATIAL10_FM6) { | |||
3582 | fmt_bit_depth->flags.SPATIAL_DITHER_ENABLED = 1; | |||
3583 | fmt_bit_depth->flags.SPATIAL_DITHER_DEPTH = 2; | |||
3584 | fmt_bit_depth->flags.HIGHPASS_RANDOM = 1; | |||
3585 | fmt_bit_depth->flags.RGB_RANDOM = | |||
3586 | (pixel_encoding == PIXEL_ENCODING_RGB) ? 1 : 0; | |||
3587 | } | |||
3588 | ||||
3589 | if (option == DITHER_OPTION_SPATIAL6 || | |||
3590 | option == DITHER_OPTION_SPATIAL8 || | |||
3591 | option == DITHER_OPTION_SPATIAL10) { | |||
3592 | fmt_bit_depth->flags.FRAME_RANDOM = 0; | |||
3593 | } else { | |||
3594 | fmt_bit_depth->flags.FRAME_RANDOM = 1; | |||
3595 | } | |||
3596 | ||||
3597 | ////////////////////// | |||
3598 | //// temporal dither | |||
3599 | ////////////////////// | |||
3600 | if (option == DITHER_OPTION_FM6 || | |||
3601 | option == DITHER_OPTION_SPATIAL8_FM6 || | |||
3602 | option == DITHER_OPTION_SPATIAL10_FM6 || | |||
3603 | option == DITHER_OPTION_TRUN10_FM6 || | |||
3604 | option == DITHER_OPTION_TRUN8_FM6 || | |||
3605 | option == DITHER_OPTION_TRUN10_SPATIAL8_FM6) { | |||
3606 | fmt_bit_depth->flags.FRAME_MODULATION_ENABLED = 1; | |||
3607 | fmt_bit_depth->flags.FRAME_MODULATION_DEPTH = 0; | |||
3608 | } else if (option == DITHER_OPTION_FM8 || | |||
3609 | option == DITHER_OPTION_SPATIAL10_FM8 || | |||
3610 | option == DITHER_OPTION_TRUN10_FM8) { | |||
3611 | fmt_bit_depth->flags.FRAME_MODULATION_ENABLED = 1; | |||
3612 | fmt_bit_depth->flags.FRAME_MODULATION_DEPTH = 1; | |||
3613 | } else if (option == DITHER_OPTION_FM10) { | |||
3614 | fmt_bit_depth->flags.FRAME_MODULATION_ENABLED = 1; | |||
3615 | fmt_bit_depth->flags.FRAME_MODULATION_DEPTH = 2; | |||
3616 | } | |||
3617 | ||||
3618 | fmt_bit_depth->pixel_encoding = pixel_encoding; | |||
3619 | } | |||
3620 | ||||
3621 | enum dc_status dc_validate_stream(struct dc *dc, struct dc_stream_state *stream) | |||
3622 | { | |||
3623 | struct dc_link *link = stream->link; | |||
3624 | struct timing_generator *tg = dc->res_pool->timing_generators[0]; | |||
3625 | enum dc_status res = DC_OK; | |||
3626 | ||||
3627 | calculate_phy_pix_clks(stream); | |||
3628 | ||||
3629 | if (!tg->funcs->validate_timing(tg, &stream->timing)) | |||
3630 | res = DC_FAIL_CONTROLLER_VALIDATE; | |||
3631 | ||||
3632 | if (res == DC_OK) { | |||
3633 | if (link->ep_type == DISPLAY_ENDPOINT_PHY && | |||
3634 | !link->link_enc->funcs->validate_output_with_stream( | |||
3635 | link->link_enc, stream)) | |||
3636 | res = DC_FAIL_ENC_VALIDATE; | |||
3637 | } | |||
3638 | ||||
3639 | /* TODO: validate audio ASIC caps, encoder */ | |||
3640 | ||||
3641 | if (res == DC_OK) | |||
3642 | res = dc_link_validate_mode_timing(stream, | |||
3643 | link, | |||
3644 | &stream->timing); | |||
3645 | ||||
3646 | return res; | |||
3647 | } | |||
3648 | ||||
3649 | enum dc_status dc_validate_plane(struct dc *dc, const struct dc_plane_state *plane_state) | |||
3650 | { | |||
3651 | enum dc_status res = DC_OK; | |||
3652 | ||||
3653 | /* check if surface has invalid dimensions */ | |||
3654 | if (plane_state->src_rect.width == 0 || plane_state->src_rect.height == 0 || | |||
3655 | plane_state->dst_rect.width == 0 || plane_state->dst_rect.height == 0) | |||
3656 | return DC_FAIL_SURFACE_VALIDATE; | |||
3657 | ||||
3658 | /* TODO For now validates pixel format only */ | |||
3659 | if (dc->res_pool->funcs->validate_plane) | |||
3660 | return dc->res_pool->funcs->validate_plane(plane_state, &dc->caps); | |||
3661 | ||||
3662 | return res; | |||
3663 | } | |||
3664 | ||||
3665 | unsigned int resource_pixel_format_to_bpp(enum surface_pixel_format format) | |||
3666 | { | |||
3667 | switch (format) { | |||
3668 | case SURFACE_PIXEL_FORMAT_GRPH_PALETA_256_COLORS: | |||
3669 | return 8; | |||
3670 | case SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr: | |||
3671 | case SURFACE_PIXEL_FORMAT_VIDEO_420_YCrCb: | |||
3672 | return 12; | |||
3673 | case SURFACE_PIXEL_FORMAT_GRPH_ARGB1555: | |||
3674 | case SURFACE_PIXEL_FORMAT_GRPH_RGB565: | |||
3675 | case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCbCr: | |||
3676 | case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb: | |||
3677 | return 16; | |||
3678 | case SURFACE_PIXEL_FORMAT_GRPH_ARGB8888: | |||
3679 | case SURFACE_PIXEL_FORMAT_GRPH_ABGR8888: | |||
3680 | case SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010: | |||
3681 | case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010: | |||
3682 | case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010_XR_BIAS: | |||
3683 | case SURFACE_PIXEL_FORMAT_GRPH_RGBE: | |||
3684 | case SURFACE_PIXEL_FORMAT_GRPH_RGBE_ALPHA: | |||
3685 | return 32; | |||
3686 | case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616: | |||
3687 | case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616: | |||
3688 | case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F: | |||
3689 | case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F: | |||
3690 | return 64; | |||
3691 | default: | |||
3692 | ASSERT_CRITICAL(false)do { if (({ int __ret = !!(!(0)); if (__ret) printf("WARNING %s failed at %s:%d\n" , "!(0)", "/usr/src/sys/dev/pci/drm/amd/display/dc/core/dc_resource.c" , 3692); __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); | |||
3693 | return -1; | |||
3694 | } | |||
3695 | } | |||
3696 | static unsigned int get_max_audio_sample_rate(struct audio_mode *modes) | |||
3697 | { | |||
3698 | if (modes) { | |||
3699 | if (modes->sample_rates.rate.RATE_192) | |||
3700 | return 192000; | |||
3701 | if (modes->sample_rates.rate.RATE_176_4) | |||
3702 | return 176400; | |||
3703 | if (modes->sample_rates.rate.RATE_96) | |||
3704 | return 96000; | |||
3705 | if (modes->sample_rates.rate.RATE_88_2) | |||
3706 | return 88200; | |||
3707 | if (modes->sample_rates.rate.RATE_48) | |||
3708 | return 48000; | |||
3709 | if (modes->sample_rates.rate.RATE_44_1) | |||
3710 | return 44100; | |||
3711 | if (modes->sample_rates.rate.RATE_32) | |||
3712 | return 32000; | |||
3713 | } | |||
3714 | /*original logic when no audio info*/ | |||
3715 | return 441000; | |||
3716 | } | |||
3717 | ||||
3718 | void get_audio_check(struct audio_info *aud_modes, | |||
3719 | struct audio_check *audio_chk) | |||
3720 | { | |||
3721 | unsigned int i; | |||
3722 | unsigned int max_sample_rate = 0; | |||
3723 | ||||
3724 | if (aud_modes) { | |||
3725 | audio_chk->audio_packet_type = 0x2;/*audio sample packet AP = .25 for layout0, 1 for layout1*/ | |||
3726 | ||||
3727 | audio_chk->max_audiosample_rate = 0; | |||
3728 | for (i = 0; i < aud_modes->mode_count; i++) { | |||
3729 | max_sample_rate = get_max_audio_sample_rate(&aud_modes->modes[i]); | |||
3730 | if (audio_chk->max_audiosample_rate < max_sample_rate) | |||
3731 | audio_chk->max_audiosample_rate = max_sample_rate; | |||
3732 | /*dts takes the same as type 2: AP = 0.25*/ | |||
3733 | } | |||
3734 | /*check which one take more bandwidth*/ | |||
3735 | if (audio_chk->max_audiosample_rate > 192000) | |||
3736 | audio_chk->audio_packet_type = 0x9;/*AP =1*/ | |||
3737 | audio_chk->acat = 0;/*not support*/ | |||
3738 | } | |||
3739 | } | |||
3740 | ||||
3741 | static struct hpo_dp_link_encoder *get_temp_hpo_dp_link_enc( | |||
3742 | const struct resource_context *res_ctx, | |||
3743 | const struct resource_pool *const pool, | |||
3744 | const struct dc_link *link) | |||
3745 | { | |||
3746 | struct hpo_dp_link_encoder *hpo_dp_link_enc = NULL((void *)0); | |||
3747 | int enc_index; | |||
3748 | ||||
3749 | enc_index = find_acquired_hpo_dp_link_enc_for_link(res_ctx, link); | |||
3750 | ||||
3751 | if (enc_index < 0) | |||
3752 | enc_index = find_free_hpo_dp_link_enc(res_ctx, pool); | |||
3753 | ||||
3754 | if (enc_index >= 0) | |||
3755 | hpo_dp_link_enc = pool->hpo_dp_link_enc[enc_index]; | |||
3756 | ||||
3757 | return hpo_dp_link_enc; | |||
3758 | } | |||
3759 | ||||
3760 | bool_Bool get_temp_dp_link_res(struct dc_link *link, | |||
3761 | struct link_resource *link_res, | |||
3762 | struct dc_link_settings *link_settings) | |||
3763 | { | |||
3764 | const struct dc *dc = link->dc; | |||
3765 | const struct resource_context *res_ctx = &dc->current_state->res_ctx; | |||
3766 | ||||
3767 | memset(link_res, 0, sizeof(*link_res))__builtin_memset((link_res), (0), (sizeof(*link_res))); | |||
3768 | ||||
3769 | if (dp_get_link_encoding_format(link_settings) == DP_128b_132b_ENCODING) { | |||
3770 | link_res->hpo_dp_link_enc = get_temp_hpo_dp_link_enc(res_ctx, | |||
3771 | dc->res_pool, link); | |||
3772 | if (!link_res->hpo_dp_link_enc) | |||
3773 | return false0; | |||
3774 | } | |||
3775 | return true1; | |||
3776 | } | |||
3777 | ||||
3778 | void reset_syncd_pipes_from_disabled_pipes(struct dc *dc, | |||
3779 | struct dc_state *context) | |||
3780 | { | |||
3781 | int i, j; | |||
3782 | struct pipe_ctx *pipe_ctx_old, *pipe_ctx, *pipe_ctx_syncd; | |||
3783 | ||||
3784 | /* If pipe backend is reset, need to reset pipe syncd status */ | |||
3785 | for (i = 0; i < dc->res_pool->pipe_count; i++) { | |||
3786 | pipe_ctx_old = &dc->current_state->res_ctx.pipe_ctx[i]; | |||
3787 | pipe_ctx = &context->res_ctx.pipe_ctx[i]; | |||
3788 | ||||
3789 | if (!pipe_ctx_old->stream) | |||
3790 | continue; | |||
3791 | ||||
3792 | if (pipe_ctx_old->top_pipe || pipe_ctx_old->prev_odm_pipe) | |||
3793 | continue; | |||
3794 | ||||
3795 | if (!pipe_ctx->stream || | |||
3796 | pipe_need_reprogram(pipe_ctx_old, pipe_ctx)) { | |||
3797 | ||||
3798 | /* Reset all the syncd pipes from the disabled pipe */ | |||
3799 | for (j = 0; j < dc->res_pool->pipe_count; j++) { | |||
3800 | pipe_ctx_syncd = &context->res_ctx.pipe_ctx[j]; | |||
3801 | if ((GET_PIPE_SYNCD_FROM_PIPE(pipe_ctx_syncd)((pipe_ctx_syncd)->pipe_idx_syncd & 0x7F) == pipe_ctx_old->pipe_idx) || | |||
3802 | !IS_PIPE_SYNCD_VALID(pipe_ctx_syncd)((((pipe_ctx_syncd)->pipe_idx_syncd) & 0x80)?1:0)) | |||
3803 | SET_PIPE_SYNCD_TO_PIPE(pipe_ctx_syncd, j)((pipe_ctx_syncd)->pipe_idx_syncd = (0x80 | j)); | |||
3804 | } | |||
3805 | } | |||
3806 | } | |||
3807 | } | |||
3808 | ||||
3809 | void check_syncd_pipes_for_disabled_master_pipe(struct dc *dc, | |||
3810 | struct dc_state *context, | |||
3811 | uint8_t disabled_master_pipe_idx) | |||
3812 | { | |||
3813 | int i; | |||
3814 | struct pipe_ctx *pipe_ctx, *pipe_ctx_check; | |||
3815 | ||||
3816 | pipe_ctx = &context->res_ctx.pipe_ctx[disabled_master_pipe_idx]; | |||
3817 | if ((GET_PIPE_SYNCD_FROM_PIPE(pipe_ctx)((pipe_ctx)->pipe_idx_syncd & 0x7F) != disabled_master_pipe_idx) || | |||
3818 | !IS_PIPE_SYNCD_VALID(pipe_ctx)((((pipe_ctx)->pipe_idx_syncd) & 0x80)?1:0)) | |||
3819 | SET_PIPE_SYNCD_TO_PIPE(pipe_ctx, disabled_master_pipe_idx)((pipe_ctx)->pipe_idx_syncd = (0x80 | disabled_master_pipe_idx )); | |||
3820 | ||||
3821 | /* for the pipe disabled, check if any slave pipe exists and assert */ | |||
3822 | for (i = 0; i < dc->res_pool->pipe_count; i++) { | |||
3823 | pipe_ctx_check = &context->res_ctx.pipe_ctx[i]; | |||
3824 | ||||
3825 | if ((GET_PIPE_SYNCD_FROM_PIPE(pipe_ctx_check)((pipe_ctx_check)->pipe_idx_syncd & 0x7F) == disabled_master_pipe_idx) && | |||
3826 | IS_PIPE_SYNCD_VALID(pipe_ctx_check)((((pipe_ctx_check)->pipe_idx_syncd) & 0x80)?1:0) && (i != disabled_master_pipe_idx)) | |||
3827 | DC_ERR("DC: Failure: pipe_idx[%d] syncd with disabled master pipe_idx[%d]\n",do { __drm_err("DC: Failure: pipe_idx[%d] syncd with disabled master pipe_idx[%d]\n" , i, disabled_master_pipe_idx); do { ___drm_dbg(((void *)0), DRM_UT_DRIVER , "%s():%d\n", __func__, 3828); do {} while (0); } while (0); } while (0) | |||
3828 | i, disabled_master_pipe_idx)do { __drm_err("DC: Failure: pipe_idx[%d] syncd with disabled master pipe_idx[%d]\n" , i, disabled_master_pipe_idx); do { ___drm_dbg(((void *)0), DRM_UT_DRIVER , "%s():%d\n", __func__, 3828); do {} while (0); } while (0); } while (0); | |||
3829 | } | |||
3830 | } | |||
3831 | ||||
3832 | void reset_sync_context_for_pipe(const struct dc *dc, | |||
3833 | struct dc_state *context, | |||
3834 | uint8_t pipe_idx) | |||
3835 | { | |||
3836 | int i; | |||
3837 | struct pipe_ctx *pipe_ctx_reset; | |||
3838 | ||||
3839 | /* reset the otg sync context for the pipe and its slave pipes if any */ | |||
3840 | for (i = 0; i < dc->res_pool->pipe_count; i++) { | |||
3841 | pipe_ctx_reset = &context->res_ctx.pipe_ctx[i]; | |||
3842 | ||||
3843 | if (((GET_PIPE_SYNCD_FROM_PIPE(pipe_ctx_reset)((pipe_ctx_reset)->pipe_idx_syncd & 0x7F) == pipe_idx) && | |||
3844 | IS_PIPE_SYNCD_VALID(pipe_ctx_reset)((((pipe_ctx_reset)->pipe_idx_syncd) & 0x80)?1:0)) || (i == pipe_idx)) | |||
3845 | SET_PIPE_SYNCD_TO_PIPE(pipe_ctx_reset, i)((pipe_ctx_reset)->pipe_idx_syncd = (0x80 | i)); | |||
3846 | } | |||
3847 | } | |||
3848 | ||||
3849 | uint8_t resource_transmitter_to_phy_idx(const struct dc *dc, enum transmitter transmitter) | |||
3850 | { | |||
3851 | /* TODO - get transmitter to phy idx mapping from DMUB */ | |||
3852 | uint8_t phy_idx = transmitter - TRANSMITTER_UNIPHY_A; | |||
3853 | ||||
3854 | if (dc->ctx->dce_version == DCN_VERSION_3_1 && | |||
3855 | dc->ctx->asic_id.hw_internal_rev == YELLOW_CARP_B00x20) { | |||
3856 | switch (transmitter) { | |||
3857 | case TRANSMITTER_UNIPHY_A: | |||
3858 | phy_idx = 0; | |||
3859 | break; | |||
3860 | case TRANSMITTER_UNIPHY_B: | |||
3861 | phy_idx = 1; | |||
3862 | break; | |||
3863 | case TRANSMITTER_UNIPHY_C: | |||
3864 | phy_idx = 5; | |||
3865 | break; | |||
3866 | case TRANSMITTER_UNIPHY_D: | |||
3867 | phy_idx = 6; | |||
3868 | break; | |||
3869 | case TRANSMITTER_UNIPHY_E: | |||
3870 | phy_idx = 4; | |||
3871 | break; | |||
3872 | default: | |||
3873 | phy_idx = 0; | |||
3874 | break; | |||
3875 | } | |||
3876 | } | |||
3877 | ||||
3878 | return phy_idx; | |||
3879 | } | |||
3880 | ||||
3881 | const struct link_hwss *get_link_hwss(const struct dc_link *link, | |||
3882 | const struct link_resource *link_res) | |||
3883 | { | |||
3884 | /* Link_hwss is only accessible by getter function instead of accessing | |||
3885 | * by pointers in dc with the intent to protect against breaking polymorphism. | |||
3886 | */ | |||
3887 | if (can_use_hpo_dp_link_hwss(link, link_res)) | |||
3888 | /* TODO: some assumes that if decided link settings is 128b/132b | |||
3889 | * channel coding format hpo_dp_link_enc should be used. | |||
3890 | * Others believe that if hpo_dp_link_enc is available in link | |||
3891 | * resource then hpo_dp_link_enc must be used. This bound between | |||
3892 | * hpo_dp_link_enc != NULL and decided link settings is loosely coupled | |||
3893 | * with a premise that both hpo_dp_link_enc pointer and decided link | |||
3894 | * settings are determined based on single policy function like | |||
3895 | * "decide_link_settings" from upper layer. This "convention" | |||
3896 | * cannot be maintained and enforced at current level. | |||
3897 | * Therefore a refactor is due so we can enforce a strong bound | |||
3898 | * between those two parameters at this level. | |||
3899 | * | |||
3900 | * To put it simple, we want to make enforcement at low level so that | |||
3901 | * we will not return link hwss if caller plans to do 8b/10b | |||
3902 | * with an hpo encoder. Or we can return a very dummy one that doesn't | |||
3903 | * do work for all functions | |||
3904 | */ | |||
3905 | return get_hpo_dp_link_hwss(); | |||
3906 | else if (can_use_dpia_link_hwss(link, link_res)) | |||
3907 | return get_dpia_link_hwss(); | |||
3908 | else if (can_use_dio_link_hwss(link, link_res)) | |||
3909 | return get_dio_link_hwss(); | |||
3910 | else | |||
3911 | return get_virtual_link_hwss(); | |||
3912 | } | |||
3913 | ||||
3914 | bool_Bool is_h_timing_divisible_by_2(struct dc_stream_state *stream) | |||
3915 | { | |||
3916 | bool_Bool divisible = false0; | |||
3917 | uint16_t h_blank_start = 0; | |||
3918 | uint16_t h_blank_end = 0; | |||
3919 | ||||
3920 | if (stream) { | |||
3921 | h_blank_start = stream->timing.h_total - stream->timing.h_front_porch; | |||
3922 | h_blank_end = h_blank_start - stream->timing.h_addressable; | |||
3923 | ||||
3924 | /* HTOTAL, Hblank start/end, and Hsync start/end all must be | |||
3925 | * divisible by 2 in order for the horizontal timing params | |||
3926 | * to be considered divisible by 2. Hsync start is always 0. | |||
3927 | */ | |||
3928 | divisible = (stream->timing.h_total % 2 == 0) && | |||
3929 | (h_blank_start % 2 == 0) && | |||
3930 | (h_blank_end % 2 == 0) && | |||
3931 | (stream->timing.h_sync_width % 2 == 0); | |||
3932 | } | |||
3933 | return divisible; | |||
3934 | } | |||
3935 | ||||
3936 | bool_Bool dc_resource_acquire_secondary_pipe_for_mpc_odm( | |||
3937 | const struct dc *dc, | |||
3938 | struct dc_state *state, | |||
3939 | struct pipe_ctx *pri_pipe, | |||
3940 | struct pipe_ctx *sec_pipe, | |||
3941 | bool_Bool odm) | |||
3942 | { | |||
3943 | int pipe_idx = sec_pipe->pipe_idx; | |||
3944 | struct pipe_ctx *sec_top, *sec_bottom, *sec_next, *sec_prev; | |||
3945 | const struct resource_pool *pool = dc->res_pool; | |||
3946 | ||||
3947 | sec_top = sec_pipe->top_pipe; | |||
3948 | sec_bottom = sec_pipe->bottom_pipe; | |||
3949 | sec_next = sec_pipe->next_odm_pipe; | |||
3950 | sec_prev = sec_pipe->prev_odm_pipe; | |||
3951 | ||||
3952 | *sec_pipe = *pri_pipe; | |||
3953 | ||||
3954 | sec_pipe->top_pipe = sec_top; | |||
3955 | sec_pipe->bottom_pipe = sec_bottom; | |||
3956 | sec_pipe->next_odm_pipe = sec_next; | |||
3957 | sec_pipe->prev_odm_pipe = sec_prev; | |||
3958 | ||||
3959 | sec_pipe->pipe_idx = pipe_idx; | |||
3960 | sec_pipe->plane_res.mi = pool->mis[pipe_idx]; | |||
3961 | sec_pipe->plane_res.hubp = pool->hubps[pipe_idx]; | |||
3962 | sec_pipe->plane_res.ipp = pool->ipps[pipe_idx]; | |||
3963 | sec_pipe->plane_res.xfm = pool->transforms[pipe_idx]; | |||
3964 | sec_pipe->plane_res.dpp = pool->dpps[pipe_idx]; | |||
3965 | sec_pipe->plane_res.mpcc_inst = pool->dpps[pipe_idx]->inst; | |||
3966 | sec_pipe->stream_res.dsc = NULL((void *)0); | |||
3967 | if (odm) { | |||
3968 | if (!sec_pipe->top_pipe) | |||
3969 | sec_pipe->stream_res.opp = pool->opps[pipe_idx]; | |||
3970 | else | |||
3971 | sec_pipe->stream_res.opp = sec_pipe->top_pipe->stream_res.opp; | |||
3972 | if (sec_pipe->stream->timing.flags.DSC == 1) { | |||
3973 | #if defined(CONFIG_DRM_AMD_DC_DCN1) | |||
3974 | dcn20_acquire_dsc(dc, &state->res_ctx, &sec_pipe->stream_res.dsc, pipe_idx); | |||
3975 | #endif | |||
3976 | ASSERT(sec_pipe->stream_res.dsc)do { if (({ static int __warned; int __ret = !!(!(sec_pipe-> stream_res.dsc)); if (__ret && !__warned) { printf("WARNING %s failed at %s:%d\n" , "!(sec_pipe->stream_res.dsc)", "/usr/src/sys/dev/pci/drm/amd/display/dc/core/dc_resource.c" , 3976); __warned = 1; } __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); | |||
3977 | if (sec_pipe->stream_res.dsc == NULL((void *)0)) | |||
3978 | return false0; | |||
3979 | } | |||
3980 | #if defined(CONFIG_DRM_AMD_DC_DCN1) | |||
3981 | dcn20_build_mapped_resource(dc, state, sec_pipe->stream); | |||
3982 | #endif | |||
3983 | } | |||
3984 | ||||
3985 | return true1; | |||
3986 | } |
1 | /* | ||||
2 | * Copyright 2012-15 Advanced Micro Devices, Inc. | ||||
3 | * | ||||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||||
5 | * copy of this software and associated documentation files (the "Software"), | ||||
6 | * to deal in the Software without restriction, including without limitation | ||||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||||
9 | * Software is furnished to do so, subject to the following conditions: | ||||
10 | * | ||||
11 | * The above copyright notice and this permission notice shall be included in | ||||
12 | * all copies or substantial portions of the Software. | ||||
13 | * | ||||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||||
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||||
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||||
20 | * OTHER DEALINGS IN THE SOFTWARE. | ||||
21 | * | ||||
22 | * Authors: AMD | ||||
23 | * | ||||
24 | */ | ||||
25 | |||||
26 | #ifndef __DAL_FIXED31_32_H__ | ||||
27 | #define __DAL_FIXED31_32_H__ | ||||
28 | |||||
29 | #ifndef LLONG_MAX0x7fffffffffffffffLL | ||||
30 | #define LLONG_MAX0x7fffffffffffffffLL 9223372036854775807ll | ||||
31 | #endif | ||||
32 | #ifndef LLONG_MIN(-0x7fffffffffffffffLL-1) | ||||
33 | #define LLONG_MIN(-0x7fffffffffffffffLL-1) (-LLONG_MAX0x7fffffffffffffffLL - 1ll) | ||||
34 | #endif | ||||
35 | |||||
36 | #define FIXED31_32_BITS_PER_FRACTIONAL_PART32 32 | ||||
37 | #ifndef LLONG_MIN(-0x7fffffffffffffffLL-1) | ||||
38 | #define LLONG_MIN(-0x7fffffffffffffffLL-1) (1LL<<63) | ||||
39 | #endif | ||||
40 | #ifndef LLONG_MAX0x7fffffffffffffffLL | ||||
41 | #define LLONG_MAX0x7fffffffffffffffLL (-1LL>>1) | ||||
42 | #endif | ||||
43 | |||||
44 | /* | ||||
45 | * @brief | ||||
46 | * Arithmetic operations on real numbers | ||||
47 | * represented as fixed-point numbers. | ||||
48 | * There are: 1 bit for sign, | ||||
49 | * 31 bit for integer part, | ||||
50 | * 32 bits for fractional part. | ||||
51 | * | ||||
52 | * @note | ||||
53 | * Currently, overflows and underflows are asserted; | ||||
54 | * no special result returned. | ||||
55 | */ | ||||
56 | |||||
57 | struct fixed31_32 { | ||||
58 | long long value; | ||||
59 | }; | ||||
60 | |||||
61 | |||||
62 | /* | ||||
63 | * @brief | ||||
64 | * Useful constants | ||||
65 | */ | ||||
66 | |||||
67 | static const struct fixed31_32 dc_fixpt_zero = { 0 }; | ||||
68 | static const struct fixed31_32 dc_fixpt_epsilon = { 1LL }; | ||||
69 | static const struct fixed31_32 dc_fixpt_half = { 0x80000000LL }; | ||||
70 | static const struct fixed31_32 dc_fixpt_one = { 0x100000000LL }; | ||||
71 | |||||
72 | /* | ||||
73 | * @brief | ||||
74 | * Initialization routines | ||||
75 | */ | ||||
76 | |||||
77 | /* | ||||
78 | * @brief | ||||
79 | * result = numerator / denominator | ||||
80 | */ | ||||
81 | struct fixed31_32 dc_fixpt_from_fraction(long long numerator, long long denominator); | ||||
82 | |||||
83 | /* | ||||
84 | * @brief | ||||
85 | * result = arg | ||||
86 | */ | ||||
87 | static inline struct fixed31_32 dc_fixpt_from_int(int arg) | ||||
88 | { | ||||
89 | struct fixed31_32 res; | ||||
90 | |||||
91 | res.value = (long long) arg << FIXED31_32_BITS_PER_FRACTIONAL_PART32; | ||||
92 | |||||
93 | return res; | ||||
94 | } | ||||
95 | |||||
96 | /* | ||||
97 | * @brief | ||||
98 | * Unary operators | ||||
99 | */ | ||||
100 | |||||
101 | /* | ||||
102 | * @brief | ||||
103 | * result = -arg | ||||
104 | */ | ||||
105 | static inline struct fixed31_32 dc_fixpt_neg(struct fixed31_32 arg) | ||||
106 | { | ||||
107 | struct fixed31_32 res; | ||||
108 | |||||
109 | res.value = -arg.value; | ||||
110 | |||||
111 | return res; | ||||
112 | } | ||||
113 | |||||
114 | /* | ||||
115 | * @brief | ||||
116 | * result = abs(arg) := (arg >= 0) ? arg : -arg | ||||
117 | */ | ||||
118 | static inline struct fixed31_32 dc_fixpt_abs(struct fixed31_32 arg) | ||||
119 | { | ||||
120 | if (arg.value < 0) | ||||
121 | return dc_fixpt_neg(arg); | ||||
122 | else | ||||
123 | return arg; | ||||
124 | } | ||||
125 | |||||
126 | /* | ||||
127 | * @brief | ||||
128 | * Binary relational operators | ||||
129 | */ | ||||
130 | |||||
131 | /* | ||||
132 | * @brief | ||||
133 | * result = arg1 < arg2 | ||||
134 | */ | ||||
135 | static inline bool_Bool dc_fixpt_lt(struct fixed31_32 arg1, struct fixed31_32 arg2) | ||||
136 | { | ||||
137 | return arg1.value < arg2.value; | ||||
138 | } | ||||
139 | |||||
140 | /* | ||||
141 | * @brief | ||||
142 | * result = arg1 <= arg2 | ||||
143 | */ | ||||
144 | static inline bool_Bool dc_fixpt_le(struct fixed31_32 arg1, struct fixed31_32 arg2) | ||||
145 | { | ||||
146 | return arg1.value <= arg2.value; | ||||
147 | } | ||||
148 | |||||
149 | /* | ||||
150 | * @brief | ||||
151 | * result = arg1 == arg2 | ||||
152 | */ | ||||
153 | static inline bool_Bool dc_fixpt_eq(struct fixed31_32 arg1, struct fixed31_32 arg2) | ||||
154 | { | ||||
155 | return arg1.value == arg2.value; | ||||
156 | } | ||||
157 | |||||
158 | /* | ||||
159 | * @brief | ||||
160 | * result = min(arg1, arg2) := (arg1 <= arg2) ? arg1 : arg2 | ||||
161 | */ | ||||
162 | static inline struct fixed31_32 dc_fixpt_min(struct fixed31_32 arg1, struct fixed31_32 arg2) | ||||
163 | { | ||||
164 | if (arg1.value <= arg2.value) | ||||
165 | return arg1; | ||||
166 | else | ||||
167 | return arg2; | ||||
168 | } | ||||
169 | |||||
170 | /* | ||||
171 | * @brief | ||||
172 | * result = max(arg1, arg2) := (arg1 <= arg2) ? arg2 : arg1 | ||||
173 | */ | ||||
174 | static inline struct fixed31_32 dc_fixpt_max(struct fixed31_32 arg1, struct fixed31_32 arg2) | ||||
175 | { | ||||
176 | if (arg1.value <= arg2.value) | ||||
177 | return arg2; | ||||
178 | else | ||||
179 | return arg1; | ||||
180 | } | ||||
181 | |||||
182 | /* | ||||
183 | * @brief | ||||
184 | * | min_value, when arg <= min_value | ||||
185 | * result = | arg, when min_value < arg < max_value | ||||
186 | * | max_value, when arg >= max_value | ||||
187 | */ | ||||
188 | static inline struct fixed31_32 dc_fixpt_clamp( | ||||
189 | struct fixed31_32 arg, | ||||
190 | struct fixed31_32 min_value, | ||||
191 | struct fixed31_32 max_value) | ||||
192 | { | ||||
193 | if (dc_fixpt_le(arg, min_value)) | ||||
194 | return min_value; | ||||
195 | else if (dc_fixpt_le(max_value, arg)) | ||||
196 | return max_value; | ||||
197 | else | ||||
198 | return arg; | ||||
199 | } | ||||
200 | |||||
201 | /* | ||||
202 | * @brief | ||||
203 | * Binary shift operators | ||||
204 | */ | ||||
205 | |||||
206 | /* | ||||
207 | * @brief | ||||
208 | * result = arg << shift | ||||
209 | */ | ||||
210 | static inline struct fixed31_32 dc_fixpt_shl(struct fixed31_32 arg, unsigned char shift) | ||||
211 | { | ||||
212 | ASSERT(((arg.value >= 0) && (arg.value <= LLONG_MAX >> shift)) ||do { if (({ static int __warned; int __ret = !!(!(((arg.value >= 0) && (arg.value <= 0x7fffffffffffffffLL >> shift)) || ((arg.value < 0) && (arg.value >= ~ (0x7fffffffffffffffLL >> shift))))); if (__ret && !__warned) { printf("WARNING %s failed at %s:%d\n", "!(((arg.value >= 0) && (arg.value <= 0x7fffffffffffffffLL >> shift)) || ((arg.value < 0) && (arg.value >= ~(0x7fffffffffffffffLL >> shift))))" , "/usr/src/sys/dev/pci/drm/amd/display/include/fixed31_32.h" , 213); __warned = 1; } __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0) | ||||
213 | ((arg.value < 0) && (arg.value >= ~(LLONG_MAX >> shift))))do { if (({ static int __warned; int __ret = !!(!(((arg.value >= 0) && (arg.value <= 0x7fffffffffffffffLL >> shift)) || ((arg.value < 0) && (arg.value >= ~ (0x7fffffffffffffffLL >> shift))))); if (__ret && !__warned) { printf("WARNING %s failed at %s:%d\n", "!(((arg.value >= 0) && (arg.value <= 0x7fffffffffffffffLL >> shift)) || ((arg.value < 0) && (arg.value >= ~(0x7fffffffffffffffLL >> shift))))" , "/usr/src/sys/dev/pci/drm/amd/display/include/fixed31_32.h" , 213); __warned = 1; } __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); | ||||
214 | |||||
215 | arg.value = arg.value << shift; | ||||
216 | |||||
217 | return arg; | ||||
218 | } | ||||
219 | |||||
220 | /* | ||||
221 | * @brief | ||||
222 | * result = arg >> shift | ||||
223 | */ | ||||
224 | static inline struct fixed31_32 dc_fixpt_shr(struct fixed31_32 arg, unsigned char shift) | ||||
225 | { | ||||
226 | bool_Bool negative = arg.value < 0; | ||||
227 | |||||
228 | if (negative) | ||||
229 | arg.value = -arg.value; | ||||
230 | arg.value = arg.value >> shift; | ||||
231 | if (negative) | ||||
232 | arg.value = -arg.value; | ||||
233 | return arg; | ||||
234 | } | ||||
235 | |||||
236 | /* | ||||
237 | * @brief | ||||
238 | * Binary additive operators | ||||
239 | */ | ||||
240 | |||||
241 | /* | ||||
242 | * @brief | ||||
243 | * result = arg1 + arg2 | ||||
244 | */ | ||||
245 | static inline struct fixed31_32 dc_fixpt_add(struct fixed31_32 arg1, struct fixed31_32 arg2) | ||||
246 | { | ||||
247 | struct fixed31_32 res; | ||||
248 | |||||
249 | ASSERT(((arg1.value >= 0) && (LLONG_MAX - arg1.value >= arg2.value)) ||do { if (({ static int __warned; int __ret = !!(!(((arg1.value >= 0) && (0x7fffffffffffffffLL - arg1.value >= arg2.value)) || ((arg1.value < 0) && ((-0x7fffffffffffffffLL -1) - arg1.value <= arg2.value)))); if (__ret && ! __warned) { printf("WARNING %s failed at %s:%d\n", "!(((arg1.value >= 0) && (0x7fffffffffffffffLL - arg1.value >= arg2.value)) || ((arg1.value < 0) && ((-0x7fffffffffffffffLL-1) - arg1.value <= arg2.value)))" , "/usr/src/sys/dev/pci/drm/amd/display/include/fixed31_32.h" , 250); __warned = 1; } __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0) | ||||
250 | ((arg1.value < 0) && (LLONG_MIN - arg1.value <= arg2.value)))do { if (({ static int __warned; int __ret = !!(!(((arg1.value >= 0) && (0x7fffffffffffffffLL - arg1.value >= arg2.value)) || ((arg1.value < 0) && ((-0x7fffffffffffffffLL -1) - arg1.value <= arg2.value)))); if (__ret && ! __warned) { printf("WARNING %s failed at %s:%d\n", "!(((arg1.value >= 0) && (0x7fffffffffffffffLL - arg1.value >= arg2.value)) || ((arg1.value < 0) && ((-0x7fffffffffffffffLL-1) - arg1.value <= arg2.value)))" , "/usr/src/sys/dev/pci/drm/amd/display/include/fixed31_32.h" , 250); __warned = 1; } __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); | ||||
251 | |||||
252 | res.value = arg1.value + arg2.value; | ||||
253 | |||||
254 | return res; | ||||
255 | } | ||||
256 | |||||
257 | /* | ||||
258 | * @brief | ||||
259 | * result = arg1 + arg2 | ||||
260 | */ | ||||
261 | static inline struct fixed31_32 dc_fixpt_add_int(struct fixed31_32 arg1, int arg2) | ||||
262 | { | ||||
263 | return dc_fixpt_add(arg1, dc_fixpt_from_int(arg2)); | ||||
264 | } | ||||
265 | |||||
266 | /* | ||||
267 | * @brief | ||||
268 | * result = arg1 - arg2 | ||||
269 | */ | ||||
270 | static inline struct fixed31_32 dc_fixpt_sub(struct fixed31_32 arg1, struct fixed31_32 arg2) | ||||
271 | { | ||||
272 | struct fixed31_32 res; | ||||
273 | |||||
274 | ASSERT(((arg2.value >= 0) && (LLONG_MIN + arg2.value <= arg1.value)) ||do { if (({ static int __warned; int __ret = !!(!(((arg2.value >= 0) && ((-0x7fffffffffffffffLL-1) + arg2.value <= arg1.value)) || ((arg2.value < 0) && (0x7fffffffffffffffLL + arg2.value >= arg1.value)))); if (__ret && !__warned ) { printf("WARNING %s failed at %s:%d\n", "!(((arg2.value >= 0) && ((-0x7fffffffffffffffLL-1) + arg2.value <= arg1.value)) || ((arg2.value < 0) && (0x7fffffffffffffffLL + arg2.value >= arg1.value)))" , "/usr/src/sys/dev/pci/drm/amd/display/include/fixed31_32.h" , 275); __warned = 1; } __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0) | ||||
275 | ((arg2.value < 0) && (LLONG_MAX + arg2.value >= arg1.value)))do { if (({ static int __warned; int __ret = !!(!(((arg2.value >= 0) && ((-0x7fffffffffffffffLL-1) + arg2.value <= arg1.value)) || ((arg2.value < 0) && (0x7fffffffffffffffLL + arg2.value >= arg1.value)))); if (__ret && !__warned ) { printf("WARNING %s failed at %s:%d\n", "!(((arg2.value >= 0) && ((-0x7fffffffffffffffLL-1) + arg2.value <= arg1.value)) || ((arg2.value < 0) && (0x7fffffffffffffffLL + arg2.value >= arg1.value)))" , "/usr/src/sys/dev/pci/drm/amd/display/include/fixed31_32.h" , 275); __warned = 1; } __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); | ||||
276 | |||||
277 | res.value = arg1.value - arg2.value; | ||||
278 | |||||
279 | return res; | ||||
280 | } | ||||
281 | |||||
282 | /* | ||||
283 | * @brief | ||||
284 | * result = arg1 - arg2 | ||||
285 | */ | ||||
286 | static inline struct fixed31_32 dc_fixpt_sub_int(struct fixed31_32 arg1, int arg2) | ||||
287 | { | ||||
288 | return dc_fixpt_sub(arg1, dc_fixpt_from_int(arg2)); | ||||
289 | } | ||||
290 | |||||
291 | |||||
292 | /* | ||||
293 | * @brief | ||||
294 | * Binary multiplicative operators | ||||
295 | */ | ||||
296 | |||||
297 | /* | ||||
298 | * @brief | ||||
299 | * result = arg1 * arg2 | ||||
300 | */ | ||||
301 | struct fixed31_32 dc_fixpt_mul(struct fixed31_32 arg1, struct fixed31_32 arg2); | ||||
302 | |||||
303 | |||||
304 | /* | ||||
305 | * @brief | ||||
306 | * result = arg1 * arg2 | ||||
307 | */ | ||||
308 | static inline struct fixed31_32 dc_fixpt_mul_int(struct fixed31_32 arg1, int arg2) | ||||
309 | { | ||||
310 | return dc_fixpt_mul(arg1, dc_fixpt_from_int(arg2)); | ||||
311 | } | ||||
312 | |||||
313 | /* | ||||
314 | * @brief | ||||
315 | * result = square(arg) := arg * arg | ||||
316 | */ | ||||
317 | struct fixed31_32 dc_fixpt_sqr(struct fixed31_32 arg); | ||||
318 | |||||
319 | /* | ||||
320 | * @brief | ||||
321 | * result = arg1 / arg2 | ||||
322 | */ | ||||
323 | static inline struct fixed31_32 dc_fixpt_div_int(struct fixed31_32 arg1, long long arg2) | ||||
324 | { | ||||
325 | return dc_fixpt_from_fraction(arg1.value, dc_fixpt_from_int((int)arg2).value); | ||||
326 | } | ||||
327 | |||||
328 | /* | ||||
329 | * @brief | ||||
330 | * result = arg1 / arg2 | ||||
331 | */ | ||||
332 | static inline struct fixed31_32 dc_fixpt_div(struct fixed31_32 arg1, struct fixed31_32 arg2) | ||||
333 | { | ||||
334 | return dc_fixpt_from_fraction(arg1.value, arg2.value); | ||||
335 | } | ||||
336 | |||||
337 | /* | ||||
338 | * @brief | ||||
339 | * Reciprocal function | ||||
340 | */ | ||||
341 | |||||
342 | /* | ||||
343 | * @brief | ||||
344 | * result = reciprocal(arg) := 1 / arg | ||||
345 | * | ||||
346 | * @note | ||||
347 | * No special actions taken in case argument is zero. | ||||
348 | */ | ||||
349 | struct fixed31_32 dc_fixpt_recip(struct fixed31_32 arg); | ||||
350 | |||||
351 | /* | ||||
352 | * @brief | ||||
353 | * Trigonometric functions | ||||
354 | */ | ||||
355 | |||||
356 | /* | ||||
357 | * @brief | ||||
358 | * result = sinc(arg) := sin(arg) / arg | ||||
359 | * | ||||
360 | * @note | ||||
361 | * Argument specified in radians, | ||||
362 | * internally it's normalized to [-2pi...2pi] range. | ||||
363 | */ | ||||
364 | struct fixed31_32 dc_fixpt_sinc(struct fixed31_32 arg); | ||||
365 | |||||
366 | /* | ||||
367 | * @brief | ||||
368 | * result = sin(arg) | ||||
369 | * | ||||
370 | * @note | ||||
371 | * Argument specified in radians, | ||||
372 | * internally it's normalized to [-2pi...2pi] range. | ||||
373 | */ | ||||
374 | struct fixed31_32 dc_fixpt_sin(struct fixed31_32 arg); | ||||
375 | |||||
376 | /* | ||||
377 | * @brief | ||||
378 | * result = cos(arg) | ||||
379 | * | ||||
380 | * @note | ||||
381 | * Argument specified in radians | ||||
382 | * and should be in [-2pi...2pi] range - | ||||
383 | * passing arguments outside that range | ||||
384 | * will cause incorrect result! | ||||
385 | */ | ||||
386 | struct fixed31_32 dc_fixpt_cos(struct fixed31_32 arg); | ||||
387 | |||||
388 | /* | ||||
389 | * @brief | ||||
390 | * Transcendent functions | ||||
391 | */ | ||||
392 | |||||
393 | /* | ||||
394 | * @brief | ||||
395 | * result = exp(arg) | ||||
396 | * | ||||
397 | * @note | ||||
398 | * Currently, function is verified for abs(arg) <= 1. | ||||
399 | */ | ||||
400 | struct fixed31_32 dc_fixpt_exp(struct fixed31_32 arg); | ||||
401 | |||||
402 | /* | ||||
403 | * @brief | ||||
404 | * result = log(arg) | ||||
405 | * | ||||
406 | * @note | ||||
407 | * Currently, abs(arg) should be less than 1. | ||||
408 | * No normalization is done. | ||||
409 | * Currently, no special actions taken | ||||
410 | * in case of invalid argument(s). Take care! | ||||
411 | */ | ||||
412 | struct fixed31_32 dc_fixpt_log(struct fixed31_32 arg); | ||||
413 | |||||
414 | /* | ||||
415 | * @brief | ||||
416 | * Power function | ||||
417 | */ | ||||
418 | |||||
419 | /* | ||||
420 | * @brief | ||||
421 | * result = pow(arg1, arg2) | ||||
422 | * | ||||
423 | * @note | ||||
424 | * Currently, abs(arg1) should be less than 1. Take care! | ||||
425 | */ | ||||
426 | static inline struct fixed31_32 dc_fixpt_pow(struct fixed31_32 arg1, struct fixed31_32 arg2) | ||||
427 | { | ||||
428 | if (arg1.value == 0) | ||||
429 | return arg2.value == 0 ? dc_fixpt_one : dc_fixpt_zero; | ||||
430 | |||||
431 | return dc_fixpt_exp( | ||||
432 | dc_fixpt_mul( | ||||
433 | dc_fixpt_log(arg1), | ||||
434 | arg2)); | ||||
435 | } | ||||
436 | |||||
437 | /* | ||||
438 | * @brief | ||||
439 | * Rounding functions | ||||
440 | */ | ||||
441 | |||||
442 | /* | ||||
443 | * @brief | ||||
444 | * result = floor(arg) := greatest integer lower than or equal to arg | ||||
445 | */ | ||||
446 | static inline int dc_fixpt_floor(struct fixed31_32 arg) | ||||
447 | { | ||||
448 | unsigned long long arg_value = arg.value > 0 ? arg.value : -arg.value; | ||||
449 | |||||
450 | if (arg.value >= 0) | ||||
451 | return (int)(arg_value >> FIXED31_32_BITS_PER_FRACTIONAL_PART32); | ||||
452 | else | ||||
453 | return -(int)(arg_value >> FIXED31_32_BITS_PER_FRACTIONAL_PART32); | ||||
454 | } | ||||
455 | |||||
456 | /* | ||||
457 | * @brief | ||||
458 | * result = round(arg) := integer nearest to arg | ||||
459 | */ | ||||
460 | static inline int dc_fixpt_round(struct fixed31_32 arg) | ||||
461 | { | ||||
462 | unsigned long long arg_value = arg.value > 0 ? arg.value : -arg.value; | ||||
463 | |||||
464 | const long long summand = dc_fixpt_half.value; | ||||
465 | |||||
466 | ASSERT(LLONG_MAX - (long long)arg_value >= summand)do { if (({ static int __warned; int __ret = !!(!(0x7fffffffffffffffLL - (long long)arg_value >= summand)); if (__ret && !__warned) { printf("WARNING %s failed at %s:%d\n", "!(0x7fffffffffffffffLL - (long long)arg_value >= summand)" , "/usr/src/sys/dev/pci/drm/amd/display/include/fixed31_32.h" , 466); __warned = 1; } __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); | ||||
467 | |||||
468 | arg_value += summand; | ||||
469 | |||||
470 | if (arg.value >= 0) | ||||
471 | return (int)(arg_value >> FIXED31_32_BITS_PER_FRACTIONAL_PART32); | ||||
472 | else | ||||
473 | return -(int)(arg_value >> FIXED31_32_BITS_PER_FRACTIONAL_PART32); | ||||
474 | } | ||||
475 | |||||
476 | /* | ||||
477 | * @brief | ||||
478 | * result = ceil(arg) := lowest integer greater than or equal to arg | ||||
479 | */ | ||||
480 | static inline int dc_fixpt_ceil(struct fixed31_32 arg) | ||||
481 | { | ||||
482 | unsigned long long arg_value = arg.value > 0 ? arg.value : -arg.value; | ||||
483 | |||||
484 | const long long summand = dc_fixpt_one.value - | ||||
485 | dc_fixpt_epsilon.value; | ||||
486 | |||||
487 | ASSERT(LLONG_MAX - (long long)arg_value >= summand)do { if (({ static int __warned; int __ret = !!(!(0x7fffffffffffffffLL - (long long)arg_value >= summand)); if (__ret && !__warned) { printf("WARNING %s failed at %s:%d\n", "!(0x7fffffffffffffffLL - (long long)arg_value >= summand)" , "/usr/src/sys/dev/pci/drm/amd/display/include/fixed31_32.h" , 487); __warned = 1; } __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); | ||||
488 | |||||
489 | arg_value += summand; | ||||
490 | |||||
491 | if (arg.value >= 0) | ||||
492 | return (int)(arg_value >> FIXED31_32_BITS_PER_FRACTIONAL_PART32); | ||||
493 | else | ||||
494 | return -(int)(arg_value >> FIXED31_32_BITS_PER_FRACTIONAL_PART32); | ||||
495 | } | ||||
496 | |||||
497 | /* the following two function are used in scaler hw programming to convert fixed | ||||
498 | * point value to format 2 bits from integer part and 19 bits from fractional | ||||
499 | * part. The same applies for u0d19, 0 bits from integer part and 19 bits from | ||||
500 | * fractional | ||||
501 | */ | ||||
502 | |||||
503 | unsigned int dc_fixpt_u4d19(struct fixed31_32 arg); | ||||
504 | |||||
505 | unsigned int dc_fixpt_u3d19(struct fixed31_32 arg); | ||||
506 | |||||
507 | unsigned int dc_fixpt_u2d19(struct fixed31_32 arg); | ||||
508 | |||||
509 | unsigned int dc_fixpt_u0d19(struct fixed31_32 arg); | ||||
510 | |||||
511 | unsigned int dc_fixpt_clamp_u0d14(struct fixed31_32 arg); | ||||
512 | |||||
513 | unsigned int dc_fixpt_clamp_u0d10(struct fixed31_32 arg); | ||||
514 | |||||
515 | int dc_fixpt_s4d19(struct fixed31_32 arg); | ||||
516 | |||||
517 | static inline struct fixed31_32 dc_fixpt_truncate(struct fixed31_32 arg, unsigned int frac_bits) | ||||
518 | { | ||||
519 | bool_Bool negative = arg.value < 0; | ||||
520 | |||||
521 | if (frac_bits
| ||||
522 | ASSERT(frac_bits == FIXED31_32_BITS_PER_FRACTIONAL_PART)do { if (({ static int __warned; int __ret = !!(!(frac_bits == 32)); if (__ret && !__warned) { printf("WARNING %s failed at %s:%d\n" , "!(frac_bits == 32)", "/usr/src/sys/dev/pci/drm/amd/display/include/fixed31_32.h" , 522); __warned = 1; } __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); | ||||
523 | return arg; | ||||
524 | } | ||||
525 | |||||
526 | if (negative
| ||||
527 | arg.value = -arg.value; | ||||
528 | arg.value &= (~0LL) << (FIXED31_32_BITS_PER_FRACTIONAL_PART32 - frac_bits); | ||||
| |||||
529 | if (negative) | ||||
530 | arg.value = -arg.value; | ||||
531 | return arg; | ||||
532 | } | ||||
533 | |||||
534 | #endif |