]>
Commit | Line | Data |
---|---|---|
4562236b HW |
1 | /* |
2 | * Copyright 2015 Advanced Micro Devices, Inc. | |
3 | * | |
4 | * Permission is hereby granted, free of charge, to any person obtaining a | |
5 | * copy of this software and associated documentation files (the "Software"), | |
6 | * to deal in the Software without restriction, including without limitation | |
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
8 | * and/or sell copies of the Software, and to permit persons to whom the | |
9 | * Software is furnished to do so, subject to the following conditions: | |
10 | * | |
11 | * The above copyright notice and this permission notice shall be included in | |
12 | * all copies or substantial portions of the Software. | |
13 | * | |
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | |
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | |
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | |
20 | * OTHER DEALINGS IN THE SOFTWARE. | |
21 | * | |
22 | * Authors: AMD | |
23 | */ | |
24 | ||
25 | #include "dm_services.h" | |
26 | ||
27 | #include "dc.h" | |
28 | ||
29 | #include "core_status.h" | |
30 | #include "core_types.h" | |
31 | #include "hw_sequencer.h" | |
32 | ||
33 | #include "resource.h" | |
34 | ||
35 | #include "clock_source.h" | |
36 | #include "dc_bios_types.h" | |
37 | ||
5e141de4 | 38 | #include "dce_calcs.h" |
4562236b HW |
39 | #include "bios_parser_interface.h" |
40 | #include "include/irq_service_interface.h" | |
41 | #include "transform.h" | |
42 | #include "timing_generator.h" | |
43 | #include "virtual/virtual_link_encoder.h" | |
44 | ||
45 | #include "link_hwss.h" | |
46 | #include "link_encoder.h" | |
47 | ||
48 | #include "dc_link_ddc.h" | |
49 | #include "dm_helpers.h" | |
50 | #include "mem_input.h" | |
51 | ||
4562236b HW |
52 | /******************************************************************************* |
53 | * Private functions | |
54 | ******************************************************************************/ | |
55 | static void destroy_links(struct core_dc *dc) | |
56 | { | |
57 | uint32_t i; | |
58 | ||
59 | for (i = 0; i < dc->link_count; i++) { | |
60 | if (NULL != dc->links[i]) | |
61 | link_destroy(&dc->links[i]); | |
62 | } | |
63 | } | |
64 | ||
65 | static bool create_links( | |
66 | struct core_dc *dc, | |
67 | uint32_t num_virtual_links) | |
68 | { | |
69 | int i; | |
70 | int connectors_num; | |
71 | struct dc_bios *bios = dc->ctx->dc_bios; | |
72 | ||
73 | dc->link_count = 0; | |
74 | ||
75 | connectors_num = bios->funcs->get_connectors_number(bios); | |
76 | ||
77 | if (connectors_num > ENUM_ID_COUNT) { | |
78 | dm_error( | |
79 | "DC: Number of connectors %d exceeds maximum of %d!\n", | |
80 | connectors_num, | |
81 | ENUM_ID_COUNT); | |
82 | return false; | |
83 | } | |
84 | ||
85 | if (connectors_num == 0 && num_virtual_links == 0) { | |
86 | dm_error("DC: Number of connectors is zero!\n"); | |
87 | } | |
88 | ||
89 | dm_output_to_console( | |
90 | "DC: %s: connectors_num: physical:%d, virtual:%d\n", | |
91 | __func__, | |
92 | connectors_num, | |
93 | num_virtual_links); | |
94 | ||
95 | for (i = 0; i < connectors_num; i++) { | |
96 | struct link_init_data link_init_params = {0}; | |
d0778ebf | 97 | struct dc_link *link; |
4562236b HW |
98 | |
99 | link_init_params.ctx = dc->ctx; | |
e4bf0a0e | 100 | /* next BIOS object table connector */ |
4562236b HW |
101 | link_init_params.connector_index = i; |
102 | link_init_params.link_index = dc->link_count; | |
103 | link_init_params.dc = dc; | |
104 | link = link_create(&link_init_params); | |
105 | ||
106 | if (link) { | |
107 | dc->links[dc->link_count] = link; | |
108 | link->dc = dc; | |
109 | ++dc->link_count; | |
4562236b HW |
110 | } |
111 | } | |
112 | ||
113 | for (i = 0; i < num_virtual_links; i++) { | |
d0778ebf | 114 | struct dc_link *link = dm_alloc(sizeof(*link)); |
4562236b HW |
115 | struct encoder_init_data enc_init = {0}; |
116 | ||
117 | if (link == NULL) { | |
118 | BREAK_TO_DEBUGGER(); | |
119 | goto failed_alloc; | |
120 | } | |
121 | ||
122 | link->ctx = dc->ctx; | |
123 | link->dc = dc; | |
d0778ebf | 124 | link->connector_signal = SIGNAL_TYPE_VIRTUAL; |
4562236b HW |
125 | link->link_id.type = OBJECT_TYPE_CONNECTOR; |
126 | link->link_id.id = CONNECTOR_ID_VIRTUAL; | |
127 | link->link_id.enum_id = ENUM_ID_1; | |
128 | link->link_enc = dm_alloc(sizeof(*link->link_enc)); | |
129 | ||
130 | enc_init.ctx = dc->ctx; | |
131 | enc_init.channel = CHANNEL_ID_UNKNOWN; | |
132 | enc_init.hpd_source = HPD_SOURCEID_UNKNOWN; | |
133 | enc_init.transmitter = TRANSMITTER_UNKNOWN; | |
134 | enc_init.connector = link->link_id; | |
135 | enc_init.encoder.type = OBJECT_TYPE_ENCODER; | |
136 | enc_init.encoder.id = ENCODER_ID_INTERNAL_VIRTUAL; | |
137 | enc_init.encoder.enum_id = ENUM_ID_1; | |
138 | virtual_link_encoder_construct(link->link_enc, &enc_init); | |
139 | ||
d0778ebf | 140 | link->link_index = dc->link_count; |
4562236b HW |
141 | dc->links[dc->link_count] = link; |
142 | dc->link_count++; | |
143 | } | |
144 | ||
145 | return true; | |
146 | ||
147 | failed_alloc: | |
148 | return false; | |
149 | } | |
150 | ||
151 | static bool stream_adjust_vmin_vmax(struct dc *dc, | |
0971c40e | 152 | struct dc_stream_state **streams, int num_streams, |
4562236b HW |
153 | int vmin, int vmax) |
154 | { | |
155 | /* TODO: Support multiple streams */ | |
156 | struct core_dc *core_dc = DC_TO_CORE(dc); | |
0971c40e | 157 | struct dc_stream_state *stream = streams[0]; |
4562236b HW |
158 | int i = 0; |
159 | bool ret = false; | |
4562236b HW |
160 | |
161 | for (i = 0; i < MAX_PIPES; i++) { | |
6680b6a1 | 162 | struct pipe_ctx *pipe = &core_dc->current_context->res_ctx.pipe_ctx[i]; |
4562236b | 163 | |
4fa086b9 | 164 | if (pipe->stream == stream && pipe->stream_enc) { |
6680b6a1 | 165 | core_dc->hwss.set_drr(&pipe, 1, vmin, vmax); |
4562236b HW |
166 | |
167 | /* build and update the info frame */ | |
6680b6a1 YS |
168 | resource_build_info_frame(pipe); |
169 | core_dc->hwss.update_info_frame(pipe); | |
4562236b HW |
170 | |
171 | ret = true; | |
172 | } | |
173 | } | |
4562236b HW |
174 | return ret; |
175 | } | |
176 | ||
72ada5f7 | 177 | static bool stream_get_crtc_position(struct dc *dc, |
0971c40e | 178 | struct dc_stream_state **streams, int num_streams, |
72ada5f7 EC |
179 | unsigned int *v_pos, unsigned int *nom_v_pos) |
180 | { | |
181 | /* TODO: Support multiple streams */ | |
182 | struct core_dc *core_dc = DC_TO_CORE(dc); | |
0971c40e | 183 | struct dc_stream_state *stream = streams[0]; |
72ada5f7 EC |
184 | int i = 0; |
185 | bool ret = false; | |
186 | struct crtc_position position; | |
187 | ||
188 | for (i = 0; i < MAX_PIPES; i++) { | |
189 | struct pipe_ctx *pipe = | |
190 | &core_dc->current_context->res_ctx.pipe_ctx[i]; | |
191 | ||
4fa086b9 | 192 | if (pipe->stream == stream && pipe->stream_enc) { |
72ada5f7 EC |
193 | core_dc->hwss.get_position(&pipe, 1, &position); |
194 | ||
195 | *v_pos = position.vertical_count; | |
196 | *nom_v_pos = position.nominal_vcount; | |
197 | ret = true; | |
198 | } | |
199 | } | |
200 | return ret; | |
201 | } | |
4562236b | 202 | |
0971c40e | 203 | static bool set_gamut_remap(struct dc *dc, const struct dc_stream_state *stream) |
4562236b HW |
204 | { |
205 | struct core_dc *core_dc = DC_TO_CORE(dc); | |
4562236b HW |
206 | int i = 0; |
207 | bool ret = false; | |
208 | struct pipe_ctx *pipes; | |
209 | ||
210 | for (i = 0; i < MAX_PIPES; i++) { | |
4fa086b9 | 211 | if (core_dc->current_context->res_ctx.pipe_ctx[i].stream == stream) { |
4562236b | 212 | pipes = &core_dc->current_context->res_ctx.pipe_ctx[i]; |
1bf56e62 | 213 | core_dc->hwss.program_gamut_remap(pipes); |
4562236b HW |
214 | ret = true; |
215 | } | |
216 | } | |
217 | ||
218 | return ret; | |
219 | } | |
220 | ||
0971c40e | 221 | static bool program_csc_matrix(struct dc *dc, struct dc_stream_state *stream) |
abe07e80 YHL |
222 | { |
223 | struct core_dc *core_dc = DC_TO_CORE(dc); | |
abe07e80 YHL |
224 | int i = 0; |
225 | bool ret = false; | |
226 | struct pipe_ctx *pipes; | |
227 | ||
228 | for (i = 0; i < MAX_PIPES; i++) { | |
229 | if (core_dc->current_context->res_ctx.pipe_ctx[i].stream | |
4fa086b9 | 230 | == stream) { |
abe07e80 YHL |
231 | |
232 | pipes = &core_dc->current_context->res_ctx.pipe_ctx[i]; | |
233 | core_dc->hwss.program_csc_matrix(pipes, | |
4fa086b9 LSL |
234 | stream->output_color_space, |
235 | stream->csc_color_matrix.matrix); | |
abe07e80 YHL |
236 | ret = true; |
237 | } | |
238 | } | |
239 | ||
240 | return ret; | |
241 | } | |
242 | ||
94267b3d | 243 | static void set_static_screen_events(struct dc *dc, |
0971c40e | 244 | struct dc_stream_state **streams, |
94267b3d ST |
245 | int num_streams, |
246 | const struct dc_static_screen_events *events) | |
247 | { | |
248 | struct core_dc *core_dc = DC_TO_CORE(dc); | |
249 | int i = 0; | |
250 | int j = 0; | |
251 | struct pipe_ctx *pipes_affected[MAX_PIPES]; | |
252 | int num_pipes_affected = 0; | |
253 | ||
254 | for (i = 0; i < num_streams; i++) { | |
0971c40e | 255 | struct dc_stream_state *stream = streams[i]; |
94267b3d ST |
256 | |
257 | for (j = 0; j < MAX_PIPES; j++) { | |
258 | if (core_dc->current_context->res_ctx.pipe_ctx[j].stream | |
4fa086b9 | 259 | == stream) { |
94267b3d ST |
260 | pipes_affected[num_pipes_affected++] = |
261 | &core_dc->current_context->res_ctx.pipe_ctx[j]; | |
262 | } | |
263 | } | |
264 | } | |
265 | ||
266 | core_dc->hwss.set_static_screen_control(pipes_affected, num_pipes_affected, events); | |
267 | } | |
268 | ||
4562236b | 269 | static void set_drive_settings(struct dc *dc, |
bf5cda33 HW |
270 | struct link_training_settings *lt_settings, |
271 | const struct dc_link *link) | |
4562236b HW |
272 | { |
273 | struct core_dc *core_dc = DC_TO_CORE(dc); | |
274 | int i; | |
275 | ||
bf5cda33 | 276 | for (i = 0; i < core_dc->link_count; i++) { |
d0778ebf | 277 | if (core_dc->links[i] == link) |
bf5cda33 HW |
278 | break; |
279 | } | |
280 | ||
281 | if (i >= core_dc->link_count) | |
282 | ASSERT_CRITICAL(false); | |
283 | ||
d0778ebf | 284 | dc_link_dp_set_drive_settings(core_dc->links[i], lt_settings); |
4562236b HW |
285 | } |
286 | ||
287 | static void perform_link_training(struct dc *dc, | |
288 | struct dc_link_settings *link_setting, | |
289 | bool skip_video_pattern) | |
290 | { | |
291 | struct core_dc *core_dc = DC_TO_CORE(dc); | |
292 | int i; | |
293 | ||
294 | for (i = 0; i < core_dc->link_count; i++) | |
295 | dc_link_dp_perform_link_training( | |
d0778ebf | 296 | core_dc->links[i], |
4562236b HW |
297 | link_setting, |
298 | skip_video_pattern); | |
299 | } | |
300 | ||
301 | static void set_preferred_link_settings(struct dc *dc, | |
88639168 | 302 | struct dc_link_settings *link_setting, |
d0778ebf | 303 | struct dc_link *link) |
4562236b | 304 | { |
d0778ebf HW |
305 | link->preferred_link_setting = *link_setting; |
306 | dp_retrain_link_dp_test(link, link_setting, false); | |
4562236b HW |
307 | } |
308 | ||
309 | static void enable_hpd(const struct dc_link *link) | |
310 | { | |
311 | dc_link_dp_enable_hpd(link); | |
312 | } | |
313 | ||
314 | static void disable_hpd(const struct dc_link *link) | |
315 | { | |
316 | dc_link_dp_disable_hpd(link); | |
317 | } | |
318 | ||
319 | ||
320 | static void set_test_pattern( | |
d0778ebf | 321 | struct dc_link *link, |
4562236b HW |
322 | enum dp_test_pattern test_pattern, |
323 | const struct link_training_settings *p_link_settings, | |
324 | const unsigned char *p_custom_pattern, | |
325 | unsigned int cust_pattern_size) | |
326 | { | |
327 | if (link != NULL) | |
328 | dc_link_dp_set_test_pattern( | |
329 | link, | |
330 | test_pattern, | |
331 | p_link_settings, | |
332 | p_custom_pattern, | |
333 | cust_pattern_size); | |
334 | } | |
335 | ||
0971c40e | 336 | void set_dither_option(struct dc_stream_state *stream, |
529cad0f DW |
337 | enum dc_dither_option option) |
338 | { | |
529cad0f | 339 | struct bit_depth_reduction_params params; |
d0778ebf HW |
340 | struct dc_link *link = stream->status.link; |
341 | struct pipe_ctx *pipes = link->dc->current_context->res_ctx.pipe_ctx; | |
529cad0f DW |
342 | |
343 | memset(¶ms, 0, sizeof(params)); | |
344 | if (!stream) | |
345 | return; | |
346 | if (option > DITHER_OPTION_MAX) | |
347 | return; | |
348 | if (option == DITHER_OPTION_DEFAULT) { | |
4fa086b9 | 349 | switch (stream->timing.display_color_depth) { |
529cad0f | 350 | case COLOR_DEPTH_666: |
4fa086b9 | 351 | stream->dither_option = DITHER_OPTION_SPATIAL6; |
529cad0f DW |
352 | break; |
353 | case COLOR_DEPTH_888: | |
4fa086b9 | 354 | stream->dither_option = DITHER_OPTION_SPATIAL8; |
529cad0f DW |
355 | break; |
356 | case COLOR_DEPTH_101010: | |
4fa086b9 | 357 | stream->dither_option = DITHER_OPTION_SPATIAL10; |
529cad0f DW |
358 | break; |
359 | default: | |
360 | option = DITHER_OPTION_DISABLE; | |
361 | } | |
362 | } else { | |
4fa086b9 | 363 | stream->dither_option = option; |
529cad0f DW |
364 | } |
365 | resource_build_bit_depth_reduction_params(stream, | |
366 | ¶ms); | |
367 | stream->bit_depth_params = params; | |
368 | pipes->opp->funcs-> | |
369 | opp_program_bit_depth_reduction(pipes->opp, ¶ms); | |
370 | } | |
371 | ||
4562236b HW |
372 | static void allocate_dc_stream_funcs(struct core_dc *core_dc) |
373 | { | |
4562236b HW |
374 | if (core_dc->hwss.set_drr != NULL) { |
375 | core_dc->public.stream_funcs.adjust_vmin_vmax = | |
376 | stream_adjust_vmin_vmax; | |
377 | } | |
378 | ||
94267b3d ST |
379 | core_dc->public.stream_funcs.set_static_screen_events = |
380 | set_static_screen_events; | |
381 | ||
72ada5f7 EC |
382 | core_dc->public.stream_funcs.get_crtc_position = |
383 | stream_get_crtc_position; | |
384 | ||
4562236b HW |
385 | core_dc->public.stream_funcs.set_gamut_remap = |
386 | set_gamut_remap; | |
387 | ||
abe07e80 YHL |
388 | core_dc->public.stream_funcs.program_csc_matrix = |
389 | program_csc_matrix; | |
390 | ||
529cad0f DW |
391 | core_dc->public.stream_funcs.set_dither_option = |
392 | set_dither_option; | |
393 | ||
4562236b HW |
394 | core_dc->public.link_funcs.set_drive_settings = |
395 | set_drive_settings; | |
396 | ||
397 | core_dc->public.link_funcs.perform_link_training = | |
398 | perform_link_training; | |
399 | ||
400 | core_dc->public.link_funcs.set_preferred_link_settings = | |
401 | set_preferred_link_settings; | |
402 | ||
403 | core_dc->public.link_funcs.enable_hpd = | |
404 | enable_hpd; | |
405 | ||
406 | core_dc->public.link_funcs.disable_hpd = | |
407 | disable_hpd; | |
408 | ||
409 | core_dc->public.link_funcs.set_test_pattern = | |
410 | set_test_pattern; | |
411 | } | |
412 | ||
413 | static void destruct(struct core_dc *dc) | |
414 | { | |
8a76708e | 415 | dc_release_validate_context(dc->current_context); |
9a3afbb3 | 416 | dc->current_context = NULL; |
4562236b | 417 | |
4562236b HW |
418 | destroy_links(dc); |
419 | ||
420 | dc_destroy_resource_pool(dc); | |
421 | ||
422 | if (dc->ctx->gpio_service) | |
423 | dal_gpio_service_destroy(&dc->ctx->gpio_service); | |
424 | ||
425 | if (dc->ctx->i2caux) | |
426 | dal_i2caux_destroy(&dc->ctx->i2caux); | |
427 | ||
428 | if (dc->ctx->created_bios) | |
429 | dal_bios_parser_destroy(&dc->ctx->dc_bios); | |
430 | ||
431 | if (dc->ctx->logger) | |
432 | dal_logger_destroy(&dc->ctx->logger); | |
433 | ||
4562236b HW |
434 | dm_free(dc->ctx); |
435 | dc->ctx = NULL; | |
436 | } | |
437 | ||
438 | static bool construct(struct core_dc *dc, | |
439 | const struct dc_init_data *init_params) | |
440 | { | |
441 | struct dal_logger *logger; | |
442 | struct dc_context *dc_ctx = dm_alloc(sizeof(*dc_ctx)); | |
443 | enum dce_version dc_version = DCE_VERSION_UNKNOWN; | |
444 | ||
445 | if (!dc_ctx) { | |
446 | dm_error("%s: failed to create ctx\n", __func__); | |
447 | goto ctx_fail; | |
448 | } | |
449 | ||
450 | dc->current_context = dm_alloc(sizeof(*dc->current_context)); | |
4562236b | 451 | |
6d9501e4 | 452 | if (!dc->current_context) { |
4562236b HW |
453 | dm_error("%s: failed to create validate ctx\n", __func__); |
454 | goto val_ctx_fail; | |
455 | } | |
456 | ||
8a76708e AG |
457 | dc->current_context->ref_count++; |
458 | ||
4562236b HW |
459 | dc_ctx->cgs_device = init_params->cgs_device; |
460 | dc_ctx->driver_context = init_params->driver; | |
461 | dc_ctx->dc = &dc->public; | |
462 | dc_ctx->asic_id = init_params->asic_id; | |
463 | ||
464 | /* Create logger */ | |
465 | logger = dal_logger_create(dc_ctx); | |
466 | ||
467 | if (!logger) { | |
468 | /* can *not* call logger. call base driver 'print error' */ | |
469 | dm_error("%s: failed to create Logger!\n", __func__); | |
470 | goto logger_fail; | |
471 | } | |
472 | dc_ctx->logger = logger; | |
473 | dc->ctx = dc_ctx; | |
474 | dc->ctx->dce_environment = init_params->dce_environment; | |
475 | ||
476 | dc_version = resource_parse_asic_id(init_params->asic_id); | |
477 | dc->ctx->dce_version = dc_version; | |
690b5e39 RL |
478 | #ifdef ENABLE_FBC |
479 | dc->ctx->fbc_gpu_addr = init_params->fbc_gpu_addr; | |
480 | #endif | |
4562236b HW |
481 | /* Resource should construct all asic specific resources. |
482 | * This should be the only place where we need to parse the asic id | |
483 | */ | |
484 | if (init_params->vbios_override) | |
485 | dc_ctx->dc_bios = init_params->vbios_override; | |
486 | else { | |
487 | /* Create BIOS parser */ | |
488 | struct bp_init_data bp_init_data; | |
e8c963d6 | 489 | |
4562236b HW |
490 | bp_init_data.ctx = dc_ctx; |
491 | bp_init_data.bios = init_params->asic_id.atombios_base_address; | |
492 | ||
493 | dc_ctx->dc_bios = dal_bios_parser_create( | |
494 | &bp_init_data, dc_version); | |
495 | ||
496 | if (!dc_ctx->dc_bios) { | |
497 | ASSERT_CRITICAL(false); | |
498 | goto bios_fail; | |
499 | } | |
500 | ||
501 | dc_ctx->created_bios = true; | |
e8c963d6 | 502 | } |
4562236b HW |
503 | |
504 | /* Create I2C AUX */ | |
505 | dc_ctx->i2caux = dal_i2caux_create(dc_ctx); | |
506 | ||
507 | if (!dc_ctx->i2caux) { | |
508 | ASSERT_CRITICAL(false); | |
509 | goto failed_to_create_i2caux; | |
510 | } | |
511 | ||
512 | /* Create GPIO service */ | |
513 | dc_ctx->gpio_service = dal_gpio_service_create( | |
514 | dc_version, | |
515 | dc_ctx->dce_environment, | |
516 | dc_ctx); | |
517 | ||
518 | if (!dc_ctx->gpio_service) { | |
519 | ASSERT_CRITICAL(false); | |
520 | goto gpio_fail; | |
521 | } | |
522 | ||
523 | dc->res_pool = dc_create_resource_pool( | |
524 | dc, | |
525 | init_params->num_virtual_links, | |
526 | dc_version, | |
527 | init_params->asic_id); | |
528 | if (!dc->res_pool) | |
529 | goto create_resource_fail; | |
530 | ||
531 | if (!create_links(dc, init_params->num_virtual_links)) | |
532 | goto create_links_fail; | |
533 | ||
534 | allocate_dc_stream_funcs(dc); | |
535 | ||
536 | return true; | |
537 | ||
538 | /**** error handling here ****/ | |
539 | create_links_fail: | |
540 | create_resource_fail: | |
541 | gpio_fail: | |
542 | failed_to_create_i2caux: | |
543 | bios_fail: | |
544 | logger_fail: | |
545 | val_ctx_fail: | |
546 | ctx_fail: | |
547 | destruct(dc); | |
548 | return false; | |
549 | } | |
550 | ||
551 | /* | |
552 | void ProgramPixelDurationV(unsigned int pixelClockInKHz ) | |
553 | { | |
554 | fixed31_32 pixel_duration = Fixed31_32(100000000, pixelClockInKHz) * 10; | |
555 | unsigned int pixDurationInPico = round(pixel_duration); | |
556 | ||
557 | DPG_PIPE_ARBITRATION_CONTROL1 arb_control; | |
558 | ||
559 | arb_control.u32All = ReadReg (mmDPGV0_PIPE_ARBITRATION_CONTROL1); | |
560 | arb_control.bits.PIXEL_DURATION = pixDurationInPico; | |
561 | WriteReg (mmDPGV0_PIPE_ARBITRATION_CONTROL1, arb_control.u32All); | |
562 | ||
563 | arb_control.u32All = ReadReg (mmDPGV1_PIPE_ARBITRATION_CONTROL1); | |
564 | arb_control.bits.PIXEL_DURATION = pixDurationInPico; | |
565 | WriteReg (mmDPGV1_PIPE_ARBITRATION_CONTROL1, arb_control.u32All); | |
566 | ||
567 | WriteReg (mmDPGV0_PIPE_ARBITRATION_CONTROL2, 0x4000800); | |
568 | WriteReg (mmDPGV0_REPEATER_PROGRAM, 0x11); | |
569 | ||
570 | WriteReg (mmDPGV1_PIPE_ARBITRATION_CONTROL2, 0x4000800); | |
571 | WriteReg (mmDPGV1_REPEATER_PROGRAM, 0x11); | |
572 | } | |
573 | */ | |
574 | ||
575 | /******************************************************************************* | |
576 | * Public functions | |
577 | ******************************************************************************/ | |
578 | ||
579 | struct dc *dc_create(const struct dc_init_data *init_params) | |
580 | { | |
581 | struct core_dc *core_dc = dm_alloc(sizeof(*core_dc)); | |
582 | unsigned int full_pipe_count; | |
583 | ||
584 | if (NULL == core_dc) | |
585 | goto alloc_fail; | |
586 | ||
587 | if (false == construct(core_dc, init_params)) | |
588 | goto construct_fail; | |
589 | ||
590 | /*TODO: separate HW and SW initialization*/ | |
591 | core_dc->hwss.init_hw(core_dc); | |
592 | ||
593 | full_pipe_count = core_dc->res_pool->pipe_count; | |
f0e3db90 | 594 | if (core_dc->res_pool->underlay_pipe_index != NO_UNDERLAY_PIPE) |
4562236b | 595 | full_pipe_count--; |
ab2541b6 | 596 | core_dc->public.caps.max_streams = min( |
4562236b HW |
597 | full_pipe_count, |
598 | core_dc->res_pool->stream_enc_count); | |
599 | ||
600 | core_dc->public.caps.max_links = core_dc->link_count; | |
601 | core_dc->public.caps.max_audios = core_dc->res_pool->audio_count; | |
602 | ||
603 | core_dc->public.config = init_params->flags; | |
604 | ||
605 | dm_logger_write(core_dc->ctx->logger, LOG_DC, | |
606 | "Display Core initialized\n"); | |
607 | ||
608 | ||
609 | /* TODO: missing feature to be enabled */ | |
610 | core_dc->public.debug.disable_dfs_bypass = true; | |
611 | ||
612 | return &core_dc->public; | |
613 | ||
614 | construct_fail: | |
615 | dm_free(core_dc); | |
616 | ||
617 | alloc_fail: | |
618 | return NULL; | |
619 | } | |
620 | ||
621 | void dc_destroy(struct dc **dc) | |
622 | { | |
623 | struct core_dc *core_dc = DC_TO_CORE(*dc); | |
624 | destruct(core_dc); | |
625 | dm_free(core_dc); | |
626 | *dc = NULL; | |
627 | } | |
628 | ||
afc8935e DL |
629 | static bool is_validation_required( |
630 | const struct core_dc *dc, | |
631 | const struct dc_validation_set set[], | |
632 | int set_count) | |
633 | { | |
634 | const struct validate_context *context = dc->current_context; | |
635 | int i, j; | |
636 | ||
637 | if (context->stream_count != set_count) | |
638 | return true; | |
639 | ||
640 | for (i = 0; i < set_count; i++) { | |
641 | ||
3be5262e | 642 | if (set[i].plane_count != context->stream_status[i].plane_count) |
afc8935e | 643 | return true; |
d54d29db | 644 | if (!dc_is_stream_unchanged(set[i].stream, context->streams[i])) |
afc8935e DL |
645 | return true; |
646 | ||
3be5262e HW |
647 | for (j = 0; j < set[i].plane_count; j++) { |
648 | struct dc_plane_state temp_plane; | |
649 | memset(&temp_plane, 0, sizeof(temp_plane)); | |
afc8935e | 650 | |
3be5262e HW |
651 | temp_plane = *context->stream_status[i].plane_states[j]; |
652 | temp_plane.clip_rect = set[i].plane_states[j]->clip_rect; | |
653 | temp_plane.dst_rect.x = set[i].plane_states[j]->dst_rect.x; | |
654 | temp_plane.dst_rect.y = set[i].plane_states[j]->dst_rect.y; | |
afc8935e | 655 | |
3be5262e | 656 | if (memcmp(&temp_plane, set[i].plane_states[j], sizeof(temp_plane)) != 0) |
afc8935e DL |
657 | return true; |
658 | } | |
659 | } | |
660 | ||
661 | return false; | |
662 | } | |
663 | ||
9345d987 AG |
664 | static bool validate_streams ( |
665 | const struct dc *dc, | |
666 | const struct dc_validation_set set[], | |
667 | int set_count) | |
668 | { | |
669 | int i; | |
670 | ||
671 | for (i = 0; i < set_count; i++) | |
672 | if (!dc_validate_stream(dc, set[i].stream)) | |
673 | return false; | |
674 | ||
675 | return true; | |
676 | } | |
677 | ||
f669089a AG |
678 | static bool validate_surfaces( |
679 | const struct dc *dc, | |
680 | const struct dc_validation_set set[], | |
681 | int set_count) | |
682 | { | |
683 | int i, j; | |
684 | ||
685 | for (i = 0; i < set_count; i++) | |
3be5262e HW |
686 | for (j = 0; j < set[i].plane_count; j++) |
687 | if (!dc_validate_plane(dc, set[i].plane_states[j])) | |
f669089a AG |
688 | return false; |
689 | ||
690 | return true; | |
691 | } | |
692 | ||
07d72b39 | 693 | struct validate_context *dc_get_validate_context( |
4562236b HW |
694 | const struct dc *dc, |
695 | const struct dc_validation_set set[], | |
696 | uint8_t set_count) | |
697 | { | |
698 | struct core_dc *core_dc = DC_TO_CORE(dc); | |
699 | enum dc_status result = DC_ERROR_UNEXPECTED; | |
700 | struct validate_context *context; | |
701 | ||
9345d987 | 702 | |
4562236b | 703 | context = dm_alloc(sizeof(struct validate_context)); |
afc8935e | 704 | if (context == NULL) |
4562236b HW |
705 | goto context_alloc_fail; |
706 | ||
8a76708e AG |
707 | ++context->ref_count; |
708 | ||
afc8935e DL |
709 | if (!is_validation_required(core_dc, set, set_count)) { |
710 | dc_resource_validate_ctx_copy_construct(core_dc->current_context, context); | |
711 | return context; | |
712 | } | |
713 | ||
4562236b | 714 | result = core_dc->res_pool->funcs->validate_with_context( |
afc8935e | 715 | core_dc, set, set_count, context, core_dc->current_context); |
4562236b | 716 | |
4562236b HW |
717 | context_alloc_fail: |
718 | if (result != DC_OK) { | |
719 | dm_logger_write(core_dc->ctx->logger, LOG_WARNING, | |
720 | "%s:resource validation failed, dc_status:%d\n", | |
721 | __func__, | |
722 | result); | |
07d72b39 | 723 | |
8a76708e | 724 | dc_release_validate_context(context); |
07d72b39 | 725 | context = NULL; |
4562236b HW |
726 | } |
727 | ||
07d72b39 HW |
728 | return context; |
729 | ||
730 | } | |
4562236b | 731 | |
07d72b39 HW |
732 | bool dc_validate_resources( |
733 | const struct dc *dc, | |
734 | const struct dc_validation_set set[], | |
735 | uint8_t set_count) | |
736 | { | |
afc8935e DL |
737 | struct core_dc *core_dc = DC_TO_CORE(dc); |
738 | enum dc_status result = DC_ERROR_UNEXPECTED; | |
739 | struct validate_context *context; | |
07d72b39 | 740 | |
9345d987 AG |
741 | if (!validate_streams(dc, set, set_count)) |
742 | return false; | |
743 | ||
f669089a AG |
744 | if (!validate_surfaces(dc, set, set_count)) |
745 | return false; | |
746 | ||
afc8935e DL |
747 | context = dm_alloc(sizeof(struct validate_context)); |
748 | if (context == NULL) | |
749 | goto context_alloc_fail; | |
750 | ||
8a76708e AG |
751 | ++context->ref_count; |
752 | ||
afc8935e DL |
753 | result = core_dc->res_pool->funcs->validate_with_context( |
754 | core_dc, set, set_count, context, NULL); | |
755 | ||
756 | context_alloc_fail: | |
757 | if (result != DC_OK) { | |
758 | dm_logger_write(core_dc->ctx->logger, LOG_WARNING, | |
759 | "%s:resource validation failed, dc_status:%d\n", | |
760 | __func__, | |
761 | result); | |
07d72b39 HW |
762 | } |
763 | ||
8a76708e | 764 | dc_release_validate_context(context); |
afc8935e DL |
765 | context = NULL; |
766 | ||
767 | return result == DC_OK; | |
4562236b HW |
768 | } |
769 | ||
770 | bool dc_validate_guaranteed( | |
771 | const struct dc *dc, | |
0971c40e | 772 | struct dc_stream_state *stream) |
4562236b HW |
773 | { |
774 | struct core_dc *core_dc = DC_TO_CORE(dc); | |
775 | enum dc_status result = DC_ERROR_UNEXPECTED; | |
776 | struct validate_context *context; | |
777 | ||
9345d987 AG |
778 | if (!dc_validate_stream(dc, stream)) |
779 | return false; | |
780 | ||
4562236b HW |
781 | context = dm_alloc(sizeof(struct validate_context)); |
782 | if (context == NULL) | |
783 | goto context_alloc_fail; | |
784 | ||
8a76708e AG |
785 | ++context->ref_count; |
786 | ||
4562236b | 787 | result = core_dc->res_pool->funcs->validate_guaranteed( |
ab2541b6 | 788 | core_dc, stream, context); |
4562236b | 789 | |
8a76708e | 790 | dc_release_validate_context(context); |
4562236b HW |
791 | |
792 | context_alloc_fail: | |
793 | if (result != DC_OK) { | |
794 | dm_logger_write(core_dc->ctx->logger, LOG_WARNING, | |
795 | "%s:guaranteed validation failed, dc_status:%d\n", | |
796 | __func__, | |
797 | result); | |
798 | } | |
799 | ||
800 | return (result == DC_OK); | |
801 | } | |
802 | ||
803 | static void program_timing_sync( | |
804 | struct core_dc *core_dc, | |
805 | struct validate_context *ctx) | |
806 | { | |
807 | int i, j; | |
808 | int group_index = 0; | |
a2b8659d | 809 | int pipe_count = core_dc->res_pool->pipe_count; |
4562236b HW |
810 | struct pipe_ctx *unsynced_pipes[MAX_PIPES] = { NULL }; |
811 | ||
812 | for (i = 0; i < pipe_count; i++) { | |
813 | if (!ctx->res_ctx.pipe_ctx[i].stream || ctx->res_ctx.pipe_ctx[i].top_pipe) | |
814 | continue; | |
815 | ||
816 | unsynced_pipes[i] = &ctx->res_ctx.pipe_ctx[i]; | |
817 | } | |
818 | ||
819 | for (i = 0; i < pipe_count; i++) { | |
820 | int group_size = 1; | |
821 | struct pipe_ctx *pipe_set[MAX_PIPES]; | |
822 | ||
823 | if (!unsynced_pipes[i]) | |
824 | continue; | |
825 | ||
826 | pipe_set[0] = unsynced_pipes[i]; | |
827 | unsynced_pipes[i] = NULL; | |
828 | ||
829 | /* Add tg to the set, search rest of the tg's for ones with | |
830 | * same timing, add all tgs with same timing to the group | |
831 | */ | |
832 | for (j = i + 1; j < pipe_count; j++) { | |
833 | if (!unsynced_pipes[j]) | |
834 | continue; | |
835 | ||
836 | if (resource_are_streams_timing_synchronizable( | |
837 | unsynced_pipes[j]->stream, | |
838 | pipe_set[0]->stream)) { | |
839 | pipe_set[group_size] = unsynced_pipes[j]; | |
840 | unsynced_pipes[j] = NULL; | |
841 | group_size++; | |
842 | } | |
843 | } | |
844 | ||
845 | /* set first unblanked pipe as master */ | |
846 | for (j = 0; j < group_size; j++) { | |
847 | struct pipe_ctx *temp; | |
848 | ||
849 | if (!pipe_set[j]->tg->funcs->is_blanked(pipe_set[j]->tg)) { | |
850 | if (j == 0) | |
851 | break; | |
852 | ||
853 | temp = pipe_set[0]; | |
854 | pipe_set[0] = pipe_set[j]; | |
855 | pipe_set[j] = temp; | |
856 | break; | |
857 | } | |
858 | } | |
859 | ||
860 | /* remove any other unblanked pipes as they have already been synced */ | |
861 | for (j = j + 1; j < group_size; j++) { | |
862 | if (!pipe_set[j]->tg->funcs->is_blanked(pipe_set[j]->tg)) { | |
863 | group_size--; | |
864 | pipe_set[j] = pipe_set[group_size]; | |
865 | j--; | |
866 | } | |
867 | } | |
868 | ||
869 | if (group_size > 1) { | |
870 | core_dc->hwss.enable_timing_synchronization( | |
871 | core_dc, group_index, group_size, pipe_set); | |
872 | group_index++; | |
873 | } | |
874 | } | |
875 | } | |
876 | ||
e2c7bb12 | 877 | static bool context_changed( |
7cf2c840 | 878 | struct core_dc *dc, |
e2c7bb12 | 879 | struct validate_context *context) |
7cf2c840 HW |
880 | { |
881 | uint8_t i; | |
882 | ||
e2c7bb12 | 883 | if (context->stream_count != dc->current_context->stream_count) |
7cf2c840 HW |
884 | return true; |
885 | ||
886 | for (i = 0; i < dc->current_context->stream_count; i++) { | |
4fa086b9 | 887 | if (dc->current_context->streams[i] != context->streams[i]) |
7cf2c840 HW |
888 | return true; |
889 | } | |
890 | ||
891 | return false; | |
892 | } | |
893 | ||
ab2541b6 | 894 | static bool streams_changed( |
4562236b | 895 | struct core_dc *dc, |
0971c40e | 896 | struct dc_stream_state *streams[], |
ab2541b6 | 897 | uint8_t stream_count) |
4562236b HW |
898 | { |
899 | uint8_t i; | |
900 | ||
ab2541b6 | 901 | if (stream_count != dc->current_context->stream_count) |
4562236b HW |
902 | return true; |
903 | ||
ab2541b6 | 904 | for (i = 0; i < dc->current_context->stream_count; i++) { |
4fa086b9 | 905 | if (dc->current_context->streams[i] != streams[i]) |
4562236b HW |
906 | return true; |
907 | } | |
908 | ||
909 | return false; | |
910 | } | |
911 | ||
7f5c22d1 VP |
912 | bool dc_enable_stereo( |
913 | struct dc *dc, | |
914 | struct validate_context *context, | |
0971c40e | 915 | struct dc_stream_state *streams[], |
7f5c22d1 VP |
916 | uint8_t stream_count) |
917 | { | |
918 | bool ret = true; | |
919 | int i, j; | |
920 | struct pipe_ctx *pipe; | |
921 | struct core_dc *core_dc = DC_TO_CORE(dc); | |
1663ae1c BL |
922 | |
923 | #ifdef ENABLE_FBC | |
924 | struct compressor *fbc_compressor = core_dc->fbc_compressor; | |
925 | #endif | |
926 | ||
7f5c22d1 VP |
927 | for (i = 0; i < MAX_PIPES; i++) { |
928 | if (context != NULL) | |
929 | pipe = &context->res_ctx.pipe_ctx[i]; | |
930 | else | |
931 | pipe = &core_dc->current_context->res_ctx.pipe_ctx[i]; | |
932 | for (j = 0 ; pipe && j < stream_count; j++) { | |
4fa086b9 | 933 | if (streams[j] && streams[j] == pipe->stream && |
7f5c22d1 VP |
934 | core_dc->hwss.setup_stereo) |
935 | core_dc->hwss.setup_stereo(pipe, core_dc); | |
936 | } | |
937 | } | |
1663ae1c BL |
938 | |
939 | #ifdef ENABLE_FBC | |
940 | if (fbc_compressor != NULL && | |
941 | fbc_compressor->funcs->is_fbc_enabled_in_hw(core_dc->fbc_compressor, | |
690b5e39 | 942 | NULL)) |
1663ae1c BL |
943 | fbc_compressor->funcs->disable_fbc(fbc_compressor); |
944 | ||
945 | #endif | |
7f5c22d1 VP |
946 | return ret; |
947 | } | |
948 | ||
fa6ecfc6 AG |
949 | |
950 | /* | |
951 | * Applies given context to HW and copy it into current context. | |
952 | * It's up to the user to release the src context afterwards. | |
953 | */ | |
954 | static bool dc_commit_context_no_check(struct dc *dc, struct validate_context *context) | |
7cf2c840 HW |
955 | { |
956 | struct core_dc *core_dc = DC_TO_CORE(dc); | |
957 | struct dc_bios *dcb = core_dc->ctx->dc_bios; | |
958 | enum dc_status result = DC_ERROR_UNEXPECTED; | |
7cf2c840 HW |
959 | struct pipe_ctx *pipe; |
960 | int i, j, k, l; | |
0971c40e | 961 | struct dc_stream_state *dc_streams[MAX_STREAMS] = {0}; |
7cf2c840 | 962 | |
fa6ecfc6 | 963 | for (i = 0; i < context->stream_count; i++) |
4fa086b9 | 964 | dc_streams[i] = context->streams[i]; |
7cf2c840 HW |
965 | |
966 | if (!dcb->funcs->is_accelerated_mode(dcb)) | |
967 | core_dc->hwss.enable_accelerated_mode(core_dc); | |
968 | ||
87480687 EY |
969 | for (i = 0; i < core_dc->res_pool->pipe_count; i++) { |
970 | pipe = &context->res_ctx.pipe_ctx[i]; | |
6be425f3 | 971 | core_dc->hwss.wait_for_mpcc_disconnect(core_dc, core_dc->res_pool, pipe); |
87480687 | 972 | } |
e2c7bb12 | 973 | result = core_dc->hwss.apply_ctx_to_hw(core_dc, context); |
7cf2c840 HW |
974 | |
975 | program_timing_sync(core_dc, context); | |
976 | ||
977 | for (i = 0; i < context->stream_count; i++) { | |
b73a22d3 | 978 | const struct dc_sink *sink = context->streams[i]->sink; |
7cf2c840 | 979 | |
3be5262e HW |
980 | for (j = 0; j < context->stream_status[i].plane_count; j++) { |
981 | const struct dc_plane_state *plane_state = | |
982 | context->stream_status[i].plane_states[j]; | |
7cf2c840 | 983 | |
3be5262e | 984 | core_dc->hwss.apply_ctx_for_surface(core_dc, plane_state, context); |
7cf2c840 HW |
985 | |
986 | /* | |
987 | * enable stereo | |
988 | * TODO rework dc_enable_stereo call to work with validation sets? | |
989 | */ | |
990 | for (k = 0; k < MAX_PIPES; k++) { | |
991 | pipe = &context->res_ctx.pipe_ctx[k]; | |
992 | ||
993 | for (l = 0 ; pipe && l < context->stream_count; l++) { | |
994 | if (context->streams[l] && | |
995 | context->streams[l] == pipe->stream && | |
996 | core_dc->hwss.setup_stereo) | |
997 | core_dc->hwss.setup_stereo(pipe, core_dc); | |
998 | } | |
999 | } | |
1000 | } | |
1001 | ||
1002 | CONN_MSG_MODE(sink->link, "{%dx%d, %dx%d@%dKhz}", | |
4fa086b9 LSL |
1003 | context->streams[i]->timing.h_addressable, |
1004 | context->streams[i]->timing.v_addressable, | |
1005 | context->streams[i]->timing.h_total, | |
1006 | context->streams[i]->timing.v_total, | |
1007 | context->streams[i]->timing.pix_clk_khz); | |
7cf2c840 HW |
1008 | } |
1009 | ||
fa6ecfc6 AG |
1010 | dc_enable_stereo(dc, context, dc_streams, context->stream_count); |
1011 | ||
8a76708e AG |
1012 | dc_release_validate_context(core_dc->current_context); |
1013 | ||
a85c205a | 1014 | core_dc->current_context = context; |
7cf2c840 | 1015 | |
60bf1860 AG |
1016 | dc_retain_validate_context(core_dc->current_context); |
1017 | ||
7cf2c840 HW |
1018 | return (result == DC_OK); |
1019 | } | |
1020 | ||
fa6ecfc6 AG |
1021 | bool dc_commit_context(struct dc *dc, struct validate_context *context) |
1022 | { | |
1023 | enum dc_status result = DC_ERROR_UNEXPECTED; | |
1024 | struct core_dc *core_dc = DC_TO_CORE(dc); | |
1025 | int i; | |
1026 | ||
1027 | if (false == context_changed(core_dc, context)) | |
1028 | return DC_OK; | |
1029 | ||
1030 | dm_logger_write(core_dc->ctx->logger, LOG_DC, "%s: %d streams\n", | |
1031 | __func__, context->stream_count); | |
1032 | ||
1033 | for (i = 0; i < context->stream_count; i++) { | |
0971c40e | 1034 | struct dc_stream_state *stream = context->streams[i]; |
fa6ecfc6 AG |
1035 | |
1036 | dc_stream_log(stream, | |
1037 | core_dc->ctx->logger, | |
1038 | LOG_DC); | |
1039 | } | |
1040 | ||
1041 | result = dc_commit_context_no_check(dc, context); | |
1042 | ||
1043 | return (result == DC_OK); | |
1044 | } | |
1045 | ||
1046 | ||
ab2541b6 | 1047 | bool dc_commit_streams( |
4562236b | 1048 | struct dc *dc, |
0971c40e | 1049 | struct dc_stream_state *streams[], |
ab2541b6 | 1050 | uint8_t stream_count) |
4562236b HW |
1051 | { |
1052 | struct core_dc *core_dc = DC_TO_CORE(dc); | |
4562236b HW |
1053 | enum dc_status result = DC_ERROR_UNEXPECTED; |
1054 | struct validate_context *context; | |
e72f0acd | 1055 | struct dc_validation_set set[MAX_STREAMS] = { {0, {0} } }; |
fa6ecfc6 | 1056 | int i; |
4562236b | 1057 | |
ab2541b6 | 1058 | if (false == streams_changed(core_dc, streams, stream_count)) |
4562236b HW |
1059 | return DC_OK; |
1060 | ||
ab2541b6 AC |
1061 | dm_logger_write(core_dc->ctx->logger, LOG_DC, "%s: %d streams\n", |
1062 | __func__, stream_count); | |
4562236b | 1063 | |
ab2541b6 | 1064 | for (i = 0; i < stream_count; i++) { |
0971c40e | 1065 | struct dc_stream_state *stream = streams[i]; |
4fa086b9 | 1066 | struct dc_stream_status *status = dc_stream_get_status(stream); |
f84a8161 | 1067 | int j; |
4562236b | 1068 | |
ab2541b6 | 1069 | dc_stream_log(stream, |
4562236b HW |
1070 | core_dc->ctx->logger, |
1071 | LOG_DC); | |
1072 | ||
ab2541b6 | 1073 | set[i].stream = stream; |
f84a8161 TC |
1074 | |
1075 | if (status) { | |
3be5262e HW |
1076 | set[i].plane_count = status->plane_count; |
1077 | for (j = 0; j < status->plane_count; j++) | |
1078 | set[i].plane_states[j] = status->plane_states[j]; | |
f84a8161 | 1079 | } |
4562236b HW |
1080 | |
1081 | } | |
1082 | ||
9345d987 AG |
1083 | if (!validate_streams(dc, set, stream_count)) |
1084 | return false; | |
1085 | ||
f669089a AG |
1086 | if (!validate_surfaces(dc, set, stream_count)) |
1087 | return false; | |
1088 | ||
4562236b HW |
1089 | context = dm_alloc(sizeof(struct validate_context)); |
1090 | if (context == NULL) | |
1091 | goto context_alloc_fail; | |
1092 | ||
8a76708e AG |
1093 | ++context->ref_count; |
1094 | ||
430ef426 DL |
1095 | result = core_dc->res_pool->funcs->validate_with_context( |
1096 | core_dc, set, stream_count, context, core_dc->current_context); | |
4562236b HW |
1097 | if (result != DC_OK){ |
1098 | dm_logger_write(core_dc->ctx->logger, LOG_ERROR, | |
1099 | "%s: Context validation failed! dc_status:%d\n", | |
1100 | __func__, | |
1101 | result); | |
1102 | BREAK_TO_DEBUGGER(); | |
4562236b HW |
1103 | goto fail; |
1104 | } | |
1105 | ||
fa6ecfc6 | 1106 | result = dc_commit_context_no_check(dc, context); |
4562236b | 1107 | |
4562236b | 1108 | fail: |
8a76708e | 1109 | dc_release_validate_context(context); |
4562236b HW |
1110 | |
1111 | context_alloc_fail: | |
1112 | return (result == DC_OK); | |
1113 | } | |
1114 | ||
ab2541b6 | 1115 | bool dc_post_update_surfaces_to_stream(struct dc *dc) |
4562236b | 1116 | { |
4562236b | 1117 | int i; |
45209ef7 | 1118 | struct core_dc *core_dc = DC_TO_CORE(dc); |
9037d802 | 1119 | struct validate_context *context = core_dc->current_context; |
4562236b HW |
1120 | |
1121 | post_surface_trace(dc); | |
de37e273 | 1122 | |
a2b8659d | 1123 | for (i = 0; i < core_dc->res_pool->pipe_count; i++) |
7950f0f9 | 1124 | if (context->res_ctx.pipe_ctx[i].stream == NULL |
3be5262e | 1125 | || context->res_ctx.pipe_ctx[i].plane_state == NULL) |
cfe4645e | 1126 | core_dc->hwss.power_down_front_end(core_dc, i); |
4562236b | 1127 | |
7950f0f9 DL |
1128 | /* 3rd param should be true, temp w/a for RV*/ |
1129 | #if defined(CONFIG_DRM_AMD_DC_DCN1_0) | |
3639fa68 | 1130 | core_dc->hwss.set_bandwidth(core_dc, context, core_dc->ctx->dce_version < DCN_VERSION_1_0); |
7950f0f9 | 1131 | #else |
cf437593 | 1132 | core_dc->hwss.set_bandwidth(core_dc, context, true); |
7950f0f9 | 1133 | #endif |
de37e273 | 1134 | return true; |
4562236b HW |
1135 | } |
1136 | ||
3be5262e | 1137 | bool dc_commit_planes_to_stream( |
4562236b | 1138 | struct dc *dc, |
3be5262e HW |
1139 | struct dc_plane_state **plane_states, |
1140 | uint8_t new_plane_count, | |
0971c40e | 1141 | struct dc_stream_state *dc_stream) |
4562236b | 1142 | { |
ab2541b6 AC |
1143 | struct dc_surface_update updates[MAX_SURFACES]; |
1144 | struct dc_flip_addrs flip_addr[MAX_SURFACES]; | |
1145 | struct dc_plane_info plane_info[MAX_SURFACES]; | |
1146 | struct dc_scaling_info scaling_info[MAX_SURFACES]; | |
4562236b | 1147 | int i; |
c1473558 AG |
1148 | struct dc_stream_update *stream_update = |
1149 | dm_alloc(sizeof(struct dc_stream_update)); | |
1150 | ||
1151 | if (!stream_update) { | |
1152 | BREAK_TO_DEBUGGER(); | |
1153 | return false; | |
1154 | } | |
4562236b | 1155 | |
ab2541b6 AC |
1156 | memset(updates, 0, sizeof(updates)); |
1157 | memset(flip_addr, 0, sizeof(flip_addr)); | |
1158 | memset(plane_info, 0, sizeof(plane_info)); | |
1159 | memset(scaling_info, 0, sizeof(scaling_info)); | |
1160 | ||
c1473558 AG |
1161 | stream_update->src = dc_stream->src; |
1162 | stream_update->dst = dc_stream->dst; | |
90114434 | 1163 | stream_update->out_transfer_func = dc_stream->out_transfer_func; |
c1473558 | 1164 | |
3be5262e HW |
1165 | for (i = 0; i < new_plane_count; i++) { |
1166 | updates[i].surface = plane_states[i]; | |
89e89630 | 1167 | updates[i].gamma = |
3be5262e HW |
1168 | (struct dc_gamma *)plane_states[i]->gamma_correction; |
1169 | updates[i].in_transfer_func = plane_states[i]->in_transfer_func; | |
1170 | flip_addr[i].address = plane_states[i]->address; | |
1171 | flip_addr[i].flip_immediate = plane_states[i]->flip_immediate; | |
1172 | plane_info[i].color_space = plane_states[i]->color_space; | |
1173 | plane_info[i].format = plane_states[i]->format; | |
1174 | plane_info[i].plane_size = plane_states[i]->plane_size; | |
1175 | plane_info[i].rotation = plane_states[i]->rotation; | |
1176 | plane_info[i].horizontal_mirror = plane_states[i]->horizontal_mirror; | |
1177 | plane_info[i].stereo_format = plane_states[i]->stereo_format; | |
1178 | plane_info[i].tiling_info = plane_states[i]->tiling_info; | |
1179 | plane_info[i].visible = plane_states[i]->visible; | |
1180 | plane_info[i].per_pixel_alpha = plane_states[i]->per_pixel_alpha; | |
1181 | plane_info[i].dcc = plane_states[i]->dcc; | |
1182 | scaling_info[i].scaling_quality = plane_states[i]->scaling_quality; | |
1183 | scaling_info[i].src_rect = plane_states[i]->src_rect; | |
1184 | scaling_info[i].dst_rect = plane_states[i]->dst_rect; | |
1185 | scaling_info[i].clip_rect = plane_states[i]->clip_rect; | |
4562236b HW |
1186 | |
1187 | updates[i].flip_addr = &flip_addr[i]; | |
1188 | updates[i].plane_info = &plane_info[i]; | |
1189 | updates[i].scaling_info = &scaling_info[i]; | |
1190 | } | |
4562236b | 1191 | |
3be5262e | 1192 | dc_update_planes_and_stream( |
c1473558 AG |
1193 | dc, |
1194 | updates, | |
3be5262e | 1195 | new_plane_count, |
c1473558 AG |
1196 | dc_stream, stream_update); |
1197 | ||
cfe4645e | 1198 | dc_post_update_surfaces_to_stream(dc); |
c1473558 AG |
1199 | |
1200 | dm_free(stream_update); | |
cfe4645e | 1201 | return true; |
4562236b HW |
1202 | } |
1203 | ||
8a76708e AG |
1204 | void dc_retain_validate_context(struct validate_context *context) |
1205 | { | |
1206 | ASSERT(context->ref_count > 0); | |
1207 | ++context->ref_count; | |
1208 | } | |
1209 | ||
1210 | void dc_release_validate_context(struct validate_context *context) | |
1211 | { | |
1212 | ASSERT(context->ref_count > 0); | |
1213 | --context->ref_count; | |
1214 | ||
1215 | if (context->ref_count == 0) { | |
1216 | dc_resource_validate_ctx_destruct(context); | |
1217 | dm_free(context); | |
1218 | } | |
1219 | } | |
1220 | ||
e72f0acd TC |
1221 | static bool is_surface_in_context( |
1222 | const struct validate_context *context, | |
3be5262e | 1223 | const struct dc_plane_state *plane_state) |
4562236b | 1224 | { |
e72f0acd | 1225 | int j; |
4562236b | 1226 | |
a2b8659d | 1227 | for (j = 0; j < MAX_PIPES; j++) { |
e72f0acd | 1228 | const struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j]; |
4562236b | 1229 | |
3be5262e | 1230 | if (plane_state == pipe_ctx->plane_state) { |
e72f0acd TC |
1231 | return true; |
1232 | } | |
1233 | } | |
4562236b | 1234 | |
e72f0acd TC |
1235 | return false; |
1236 | } | |
4562236b | 1237 | |
5869b0f6 LE |
1238 | static unsigned int pixel_format_to_bpp(enum surface_pixel_format format) |
1239 | { | |
1240 | switch (format) { | |
0e12c3f6 DL |
1241 | case SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr: |
1242 | case SURFACE_PIXEL_FORMAT_VIDEO_420_YCrCb: | |
1243 | return 12; | |
5869b0f6 LE |
1244 | case SURFACE_PIXEL_FORMAT_GRPH_ARGB1555: |
1245 | case SURFACE_PIXEL_FORMAT_GRPH_RGB565: | |
0e12c3f6 DL |
1246 | case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCbCr: |
1247 | case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb: | |
5869b0f6 LE |
1248 | return 16; |
1249 | case SURFACE_PIXEL_FORMAT_GRPH_ARGB8888: | |
1250 | case SURFACE_PIXEL_FORMAT_GRPH_ABGR8888: | |
1251 | case SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010: | |
1252 | case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010: | |
1253 | return 32; | |
1254 | case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616: | |
1255 | case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F: | |
1256 | case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F: | |
1257 | return 64; | |
1258 | default: | |
1259 | ASSERT_CRITICAL(false); | |
1260 | return -1; | |
1261 | } | |
1262 | } | |
1263 | ||
1264 | static enum surface_update_type get_plane_info_update_type( | |
fb9611d2 YS |
1265 | const struct dc_surface_update *u, |
1266 | int surface_index) | |
5869b0f6 | 1267 | { |
80b4c5a8 | 1268 | struct dc_plane_info temp_plane_info; |
ebf055f9 | 1269 | memset(&temp_plane_info, 0, sizeof(temp_plane_info)); |
5869b0f6 LE |
1270 | |
1271 | if (!u->plane_info) | |
1272 | return UPDATE_TYPE_FAST; | |
1273 | ||
80b4c5a8 DL |
1274 | temp_plane_info = *u->plane_info; |
1275 | ||
5869b0f6 LE |
1276 | /* Copy all parameters that will cause a full update |
1277 | * from current surface, the rest of the parameters | |
1278 | * from provided plane configuration. | |
1279 | * Perform memory compare and special validation | |
1280 | * for those that can cause fast/medium updates | |
1281 | */ | |
1282 | ||
1283 | /* Full update parameters */ | |
1284 | temp_plane_info.color_space = u->surface->color_space; | |
1285 | temp_plane_info.dcc = u->surface->dcc; | |
1286 | temp_plane_info.horizontal_mirror = u->surface->horizontal_mirror; | |
1287 | temp_plane_info.plane_size = u->surface->plane_size; | |
1288 | temp_plane_info.rotation = u->surface->rotation; | |
1289 | temp_plane_info.stereo_format = u->surface->stereo_format; | |
1290 | temp_plane_info.tiling_info = u->surface->tiling_info; | |
5869b0f6 | 1291 | |
fb9611d2 YS |
1292 | if (surface_index == 0) |
1293 | temp_plane_info.visible = u->plane_info->visible; | |
1294 | else | |
1295 | temp_plane_info.visible = u->surface->visible; | |
5869b0f6 LE |
1296 | |
1297 | if (memcmp(u->plane_info, &temp_plane_info, | |
1298 | sizeof(struct dc_plane_info)) != 0) | |
1299 | return UPDATE_TYPE_FULL; | |
1300 | ||
1301 | if (pixel_format_to_bpp(u->plane_info->format) != | |
1302 | pixel_format_to_bpp(u->surface->format)) { | |
1303 | return UPDATE_TYPE_FULL; | |
1304 | } else { | |
1305 | return UPDATE_TYPE_MED; | |
1306 | } | |
1307 | } | |
1308 | ||
1309 | static enum surface_update_type get_scaling_info_update_type( | |
1310 | const struct dc_surface_update *u) | |
1311 | { | |
5869b0f6 LE |
1312 | if (!u->scaling_info) |
1313 | return UPDATE_TYPE_FAST; | |
1314 | ||
b71a0618 DL |
1315 | if (u->scaling_info->src_rect.width != u->surface->src_rect.width |
1316 | || u->scaling_info->src_rect.height != u->surface->src_rect.height | |
1317 | || u->scaling_info->clip_rect.width != u->surface->clip_rect.width | |
1318 | || u->scaling_info->clip_rect.height != u->surface->clip_rect.height | |
1319 | || u->scaling_info->dst_rect.width != u->surface->dst_rect.width | |
1320 | || u->scaling_info->dst_rect.height != u->surface->dst_rect.height) | |
5869b0f6 LE |
1321 | return UPDATE_TYPE_FULL; |
1322 | ||
b71a0618 DL |
1323 | if (u->scaling_info->src_rect.x != u->surface->src_rect.x |
1324 | || u->scaling_info->src_rect.y != u->surface->src_rect.y | |
1325 | || u->scaling_info->clip_rect.x != u->surface->clip_rect.x | |
1326 | || u->scaling_info->clip_rect.y != u->surface->clip_rect.y | |
1327 | || u->scaling_info->dst_rect.x != u->surface->dst_rect.x | |
1328 | || u->scaling_info->dst_rect.y != u->surface->dst_rect.y) | |
1329 | return UPDATE_TYPE_MED; | |
5869b0f6 LE |
1330 | |
1331 | return UPDATE_TYPE_FAST; | |
1332 | } | |
4562236b | 1333 | |
e72f0acd TC |
1334 | static enum surface_update_type det_surface_update( |
1335 | const struct core_dc *dc, | |
fb9611d2 YS |
1336 | const struct dc_surface_update *u, |
1337 | int surface_index) | |
e72f0acd TC |
1338 | { |
1339 | const struct validate_context *context = dc->current_context; | |
5869b0f6 LE |
1340 | enum surface_update_type type = UPDATE_TYPE_FAST; |
1341 | enum surface_update_type overall_type = UPDATE_TYPE_FAST; | |
4562236b | 1342 | |
e72f0acd TC |
1343 | if (!is_surface_in_context(context, u->surface)) |
1344 | return UPDATE_TYPE_FULL; | |
4562236b | 1345 | |
fb9611d2 | 1346 | type = get_plane_info_update_type(u, surface_index); |
5869b0f6 LE |
1347 | if (overall_type < type) |
1348 | overall_type = type; | |
1349 | ||
1350 | type = get_scaling_info_update_type(u); | |
1351 | if (overall_type < type) | |
1352 | overall_type = type; | |
1353 | ||
e72f0acd | 1354 | if (u->in_transfer_func || |
5869b0f6 LE |
1355 | u->hdr_static_metadata) { |
1356 | if (overall_type < UPDATE_TYPE_MED) | |
1357 | overall_type = UPDATE_TYPE_MED; | |
1358 | } | |
1c4e6bce | 1359 | |
5869b0f6 | 1360 | return overall_type; |
e72f0acd | 1361 | } |
4562236b | 1362 | |
5869b0f6 LE |
1363 | enum surface_update_type dc_check_update_surfaces_for_stream( |
1364 | struct dc *dc, | |
e72f0acd TC |
1365 | struct dc_surface_update *updates, |
1366 | int surface_count, | |
ee8f63e1 | 1367 | struct dc_stream_update *stream_update, |
e72f0acd TC |
1368 | const struct dc_stream_status *stream_status) |
1369 | { | |
5869b0f6 | 1370 | struct core_dc *core_dc = DC_TO_CORE(dc); |
e72f0acd TC |
1371 | int i; |
1372 | enum surface_update_type overall_type = UPDATE_TYPE_FAST; | |
1373 | ||
3be5262e | 1374 | if (stream_status == NULL || stream_status->plane_count != surface_count) |
e72f0acd TC |
1375 | return UPDATE_TYPE_FULL; |
1376 | ||
ee8f63e1 LE |
1377 | if (stream_update) |
1378 | return UPDATE_TYPE_FULL; | |
1379 | ||
e72f0acd TC |
1380 | for (i = 0 ; i < surface_count; i++) { |
1381 | enum surface_update_type type = | |
fb9611d2 | 1382 | det_surface_update(core_dc, &updates[i], i); |
e72f0acd TC |
1383 | |
1384 | if (type == UPDATE_TYPE_FULL) | |
1385 | return type; | |
1c4e6bce | 1386 | |
e72f0acd TC |
1387 | if (overall_type < type) |
1388 | overall_type = type; | |
4562236b HW |
1389 | } |
1390 | ||
e72f0acd TC |
1391 | return overall_type; |
1392 | } | |
4562236b | 1393 | |
e72f0acd | 1394 | enum surface_update_type update_surface_trace_level = UPDATE_TYPE_FULL; |
4562236b | 1395 | |
3be5262e | 1396 | void dc_update_planes_and_stream(struct dc *dc, |
ee8f63e1 | 1397 | struct dc_surface_update *srf_updates, int surface_count, |
0971c40e | 1398 | struct dc_stream_state *stream, |
ee8f63e1 | 1399 | struct dc_stream_update *stream_update) |
e72f0acd TC |
1400 | { |
1401 | struct core_dc *core_dc = DC_TO_CORE(dc); | |
1402 | struct validate_context *context; | |
1403 | int i, j; | |
e72f0acd TC |
1404 | enum surface_update_type update_type; |
1405 | const struct dc_stream_status *stream_status; | |
8a76708e | 1406 | struct dc_context *dc_ctx = core_dc->ctx; |
e72f0acd | 1407 | |
6be425f3 EY |
1408 | /* Currently this function do not result in any HW programming |
1409 | * when called with 0 surface. But proceeding will cause | |
1410 | * SW state to be updated in validate_context. So we might as | |
1411 | * well make it not do anything at all until the hw programming | |
1412 | * is implemented properly to handle 0 surface case. | |
1413 | * TODO: fix hw programming then remove this early return | |
1414 | */ | |
1415 | if (surface_count == 0) | |
1416 | return; | |
1417 | ||
4fa086b9 LSL |
1418 | stream_status = dc_stream_get_status(stream); |
1419 | ||
e72f0acd TC |
1420 | ASSERT(stream_status); |
1421 | if (!stream_status) | |
1422 | return; /* Cannot commit surface to stream that is not committed */ | |
1423 | ||
1663ae1c BL |
1424 | #ifdef ENABLE_FBC |
1425 | if (srf_updates->flip_addr) { | |
1426 | if (srf_updates->flip_addr->address.grph.addr.low_part == 0) | |
1427 | ASSERT(0); | |
1428 | } | |
1429 | #endif | |
c7dbdf15 | 1430 | context = core_dc->current_context; |
ee8f63e1 LE |
1431 | |
1432 | /* update current stream with the new updates */ | |
1433 | if (stream_update) { | |
f46661dd AZ |
1434 | if ((stream_update->src.height != 0) && |
1435 | (stream_update->src.width != 0)) | |
4fa086b9 | 1436 | stream->src = stream_update->src; |
f46661dd AZ |
1437 | |
1438 | if ((stream_update->dst.height != 0) && | |
1439 | (stream_update->dst.width != 0)) | |
4fa086b9 | 1440 | stream->dst = stream_update->dst; |
f46661dd AZ |
1441 | |
1442 | if (stream_update->out_transfer_func && | |
1443 | stream_update->out_transfer_func != | |
4fa086b9 LSL |
1444 | stream->out_transfer_func) { |
1445 | if (stream->out_transfer_func != NULL) | |
1446 | dc_transfer_func_release(stream->out_transfer_func); | |
7950f0f9 | 1447 | dc_transfer_func_retain(stream_update->out_transfer_func); |
4fa086b9 | 1448 | stream->out_transfer_func = |
7950f0f9 | 1449 | stream_update->out_transfer_func; |
f46661dd | 1450 | } |
ee8f63e1 LE |
1451 | } |
1452 | ||
e7b1322e CM |
1453 | /* do not perform surface update if surface has invalid dimensions |
1454 | * (all zero) and no scaling_info is provided | |
1455 | */ | |
1456 | if (surface_count > 0 && | |
1457 | srf_updates->surface->src_rect.width == 0 && | |
1458 | srf_updates->surface->src_rect.height == 0 && | |
1459 | srf_updates->surface->dst_rect.width == 0 && | |
1460 | srf_updates->surface->dst_rect.height == 0 && | |
556ee1b7 CM |
1461 | !srf_updates->scaling_info) { |
1462 | ASSERT(false); | |
c7dbdf15 | 1463 | return; |
556ee1b7 | 1464 | } |
c7dbdf15 CM |
1465 | |
1466 | update_type = dc_check_update_surfaces_for_stream( | |
1467 | dc, srf_updates, surface_count, stream_update, stream_status); | |
1468 | ||
1469 | if (update_type >= update_surface_trace_level) | |
1470 | update_surface_trace(dc, srf_updates, surface_count); | |
1471 | ||
1472 | if (update_type >= UPDATE_TYPE_FULL) { | |
3be5262e | 1473 | struct dc_plane_state *new_planes[MAX_SURFACES] = {0}; |
c7dbdf15 CM |
1474 | |
1475 | for (i = 0; i < surface_count; i++) | |
3be5262e | 1476 | new_planes[i] = srf_updates[i].surface; |
c7dbdf15 CM |
1477 | |
1478 | /* initialize scratch memory for building context */ | |
1479 | context = dm_alloc(sizeof(*context)); | |
8a76708e AG |
1480 | if (context == NULL) |
1481 | goto context_alloc_fail; | |
1482 | ||
1483 | ++context->ref_count; | |
1484 | ||
c7dbdf15 CM |
1485 | dc_resource_validate_ctx_copy_construct( |
1486 | core_dc->current_context, context); | |
1487 | ||
1488 | /* add surface to context */ | |
1489 | if (!resource_attach_surfaces_to_context( | |
3be5262e | 1490 | new_planes, surface_count, stream, |
c7dbdf15 CM |
1491 | context, core_dc->res_pool)) { |
1492 | BREAK_TO_DEBUGGER(); | |
1493 | goto fail; | |
1494 | } | |
1495 | } | |
1496 | ||
ee8f63e1 | 1497 | /* save update parameters into surface */ |
4562236b | 1498 | for (i = 0; i < surface_count; i++) { |
c9614aeb | 1499 | struct dc_plane_state *surface = srf_updates[i].surface; |
4562236b | 1500 | |
ee8f63e1 | 1501 | if (srf_updates[i].flip_addr) { |
e12cfcb1 HW |
1502 | surface->address = srf_updates[i].flip_addr->address; |
1503 | surface->flip_immediate = | |
ee8f63e1 | 1504 | srf_updates[i].flip_addr->flip_immediate; |
e72f0acd TC |
1505 | } |
1506 | ||
ee8f63e1 | 1507 | if (srf_updates[i].scaling_info) { |
e12cfcb1 | 1508 | surface->scaling_quality = |
ee8f63e1 | 1509 | srf_updates[i].scaling_info->scaling_quality; |
e12cfcb1 | 1510 | surface->dst_rect = |
ee8f63e1 | 1511 | srf_updates[i].scaling_info->dst_rect; |
e12cfcb1 | 1512 | surface->src_rect = |
ee8f63e1 | 1513 | srf_updates[i].scaling_info->src_rect; |
e12cfcb1 | 1514 | surface->clip_rect = |
ee8f63e1 | 1515 | srf_updates[i].scaling_info->clip_rect; |
e72f0acd TC |
1516 | } |
1517 | ||
ee8f63e1 | 1518 | if (srf_updates[i].plane_info) { |
e12cfcb1 | 1519 | surface->color_space = |
ee8f63e1 | 1520 | srf_updates[i].plane_info->color_space; |
e12cfcb1 | 1521 | surface->format = |
ee8f63e1 | 1522 | srf_updates[i].plane_info->format; |
e12cfcb1 | 1523 | surface->plane_size = |
ee8f63e1 | 1524 | srf_updates[i].plane_info->plane_size; |
e12cfcb1 | 1525 | surface->rotation = |
ee8f63e1 | 1526 | srf_updates[i].plane_info->rotation; |
e12cfcb1 | 1527 | surface->horizontal_mirror = |
ee8f63e1 | 1528 | srf_updates[i].plane_info->horizontal_mirror; |
e12cfcb1 | 1529 | surface->stereo_format = |
ee8f63e1 | 1530 | srf_updates[i].plane_info->stereo_format; |
e12cfcb1 | 1531 | surface->tiling_info = |
ee8f63e1 | 1532 | srf_updates[i].plane_info->tiling_info; |
e12cfcb1 | 1533 | surface->visible = |
ee8f63e1 | 1534 | srf_updates[i].plane_info->visible; |
e12cfcb1 | 1535 | surface->per_pixel_alpha = |
ba326a91 | 1536 | srf_updates[i].plane_info->per_pixel_alpha; |
e12cfcb1 | 1537 | surface->dcc = |
ee8f63e1 | 1538 | srf_updates[i].plane_info->dcc; |
e72f0acd TC |
1539 | } |
1540 | ||
e61a04f1 | 1541 | if (update_type >= UPDATE_TYPE_MED) { |
a2b8659d | 1542 | for (j = 0; j < core_dc->res_pool->pipe_count; j++) { |
ed151940 | 1543 | struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j]; |
4562236b | 1544 | |
3be5262e | 1545 | if (pipe_ctx->plane_state != surface) |
ed151940 | 1546 | continue; |
4562236b | 1547 | |
b2d0a103 | 1548 | resource_build_scaling_params(pipe_ctx); |
4562236b | 1549 | } |
e72f0acd | 1550 | } |
89e89630 | 1551 | |
ee8f63e1 | 1552 | if (srf_updates[i].gamma && |
e12cfcb1 HW |
1553 | srf_updates[i].gamma != surface->gamma_correction) { |
1554 | if (surface->gamma_correction != NULL) | |
7a6c4af6 | 1555 | dc_gamma_release(&surface->gamma_correction); |
89e89630 | 1556 | |
ee8f63e1 | 1557 | dc_gamma_retain(srf_updates[i].gamma); |
7a6c4af6 | 1558 | surface->gamma_correction = srf_updates[i].gamma; |
e72f0acd | 1559 | } |
fb735a9f | 1560 | |
ee8f63e1 | 1561 | if (srf_updates[i].in_transfer_func && |
e12cfcb1 HW |
1562 | srf_updates[i].in_transfer_func != surface->in_transfer_func) { |
1563 | if (surface->in_transfer_func != NULL) | |
e72f0acd | 1564 | dc_transfer_func_release( |
e12cfcb1 | 1565 | surface-> |
e72f0acd TC |
1566 | in_transfer_func); |
1567 | ||
1568 | dc_transfer_func_retain( | |
ee8f63e1 | 1569 | srf_updates[i].in_transfer_func); |
e12cfcb1 | 1570 | surface->in_transfer_func = |
ee8f63e1 | 1571 | srf_updates[i].in_transfer_func; |
e72f0acd | 1572 | } |
fb735a9f | 1573 | |
ee8f63e1 | 1574 | if (srf_updates[i].hdr_static_metadata) |
e12cfcb1 | 1575 | surface->hdr_static_ctx = |
ee8f63e1 | 1576 | *(srf_updates[i].hdr_static_metadata); |
4562236b HW |
1577 | } |
1578 | ||
745cc746 DL |
1579 | if (update_type == UPDATE_TYPE_FULL) { |
1580 | if (!core_dc->res_pool->funcs->validate_bandwidth(core_dc, context)) { | |
1581 | BREAK_TO_DEBUGGER(); | |
6d9501e4 | 1582 | goto fail; |
c9742685 | 1583 | } else { |
745cc746 | 1584 | core_dc->hwss.set_bandwidth(core_dc, context, false); |
c9742685 DL |
1585 | context_clock_trace(dc, context); |
1586 | } | |
45209ef7 | 1587 | } |
e72f0acd | 1588 | |
87480687 | 1589 | if (update_type > UPDATE_TYPE_FAST) { |
6be425f3 EY |
1590 | for (j = 0; j < core_dc->res_pool->pipe_count; j++) { |
1591 | struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j]; | |
87480687 | 1592 | |
6be425f3 | 1593 | core_dc->hwss.wait_for_mpcc_disconnect(core_dc, core_dc->res_pool, pipe_ctx); |
87480687 EY |
1594 | } |
1595 | } | |
1596 | ||
cfe4645e | 1597 | if (surface_count == 0) |
e72f0acd TC |
1598 | core_dc->hwss.apply_ctx_for_surface(core_dc, NULL, context); |
1599 | ||
f19d5f35 | 1600 | /* Lock pipes for provided surfaces, or all active if full update*/ |
4562236b | 1601 | for (i = 0; i < surface_count; i++) { |
3be5262e | 1602 | struct dc_plane_state *plane_state = srf_updates[i].surface; |
4562236b | 1603 | |
a2b8659d | 1604 | for (j = 0; j < core_dc->res_pool->pipe_count; j++) { |
f0828115 | 1605 | struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j]; |
92a65e32 | 1606 | |
3be5262e | 1607 | if (update_type != UPDATE_TYPE_FULL && pipe_ctx->plane_state != plane_state) |
f19d5f35 | 1608 | continue; |
3be5262e | 1609 | if (!pipe_ctx->plane_state || pipe_ctx->top_pipe) |
f0828115 | 1610 | continue; |
f19d5f35 | 1611 | |
d70ccd4a YS |
1612 | core_dc->hwss.pipe_control_lock( |
1613 | core_dc, | |
1614 | pipe_ctx, | |
1615 | true); | |
00f02019 | 1616 | } |
f19d5f35 DL |
1617 | if (update_type == UPDATE_TYPE_FULL) |
1618 | break; | |
00f02019 LE |
1619 | } |
1620 | ||
f19d5f35 DL |
1621 | /* Full fe update*/ |
1622 | for (j = 0; j < core_dc->res_pool->pipe_count; j++) { | |
1623 | struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j]; | |
1624 | struct pipe_ctx *cur_pipe_ctx = &core_dc->current_context->res_ctx.pipe_ctx[j]; | |
3be5262e | 1625 | bool is_new_pipe_surface = cur_pipe_ctx->plane_state != pipe_ctx->plane_state; |
f19d5f35 DL |
1626 | struct dc_cursor_position position = { 0 }; |
1627 | ||
3be5262e | 1628 | if (update_type != UPDATE_TYPE_FULL || !pipe_ctx->plane_state) |
f19d5f35 DL |
1629 | continue; |
1630 | ||
1631 | if (!pipe_ctx->top_pipe) | |
1632 | core_dc->hwss.apply_ctx_for_surface( | |
3be5262e | 1633 | core_dc, pipe_ctx->plane_state, context); |
f19d5f35 DL |
1634 | |
1635 | /* TODO: this is a hack w/a for switching from mpo to pipe split */ | |
4fa086b9 | 1636 | dc_stream_set_cursor_position(pipe_ctx->stream, &position); |
f19d5f35 DL |
1637 | |
1638 | if (is_new_pipe_surface) { | |
1639 | core_dc->hwss.update_plane_addr(core_dc, pipe_ctx); | |
1640 | core_dc->hwss.set_input_transfer_func( | |
3be5262e | 1641 | pipe_ctx, pipe_ctx->plane_state); |
f19d5f35 DL |
1642 | core_dc->hwss.set_output_transfer_func( |
1643 | pipe_ctx, pipe_ctx->stream); | |
1644 | } | |
1645 | } | |
1646 | ||
1647 | if (update_type > UPDATE_TYPE_FAST) | |
1648 | context_timing_trace(dc, &context->res_ctx); | |
1649 | ||
00f02019 LE |
1650 | /* Perform requested Updates */ |
1651 | for (i = 0; i < surface_count; i++) { | |
3be5262e | 1652 | struct dc_plane_state *plane_state = srf_updates[i].surface; |
00f02019 | 1653 | |
f19d5f35 DL |
1654 | if (update_type == UPDATE_TYPE_MED) |
1655 | core_dc->hwss.apply_ctx_for_surface( | |
3be5262e | 1656 | core_dc, plane_state, context); |
00f02019 | 1657 | |
a2b8659d | 1658 | for (j = 0; j < core_dc->res_pool->pipe_count; j++) { |
00f02019 | 1659 | struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j]; |
00f02019 | 1660 | |
3be5262e | 1661 | if (pipe_ctx->plane_state != plane_state) |
00f02019 | 1662 | continue; |
4562236b | 1663 | |
ee8f63e1 | 1664 | if (srf_updates[i].flip_addr) |
e72f0acd | 1665 | core_dc->hwss.update_plane_addr(core_dc, pipe_ctx); |
4562236b | 1666 | |
e72f0acd TC |
1667 | if (update_type == UPDATE_TYPE_FAST) |
1668 | continue; | |
1669 | ||
f9ea47ce | 1670 | if (srf_updates[i].in_transfer_func) |
90e508ba | 1671 | core_dc->hwss.set_input_transfer_func( |
3be5262e | 1672 | pipe_ctx, pipe_ctx->plane_state); |
90e508ba | 1673 | |
f19d5f35 DL |
1674 | if (stream_update != NULL && |
1675 | stream_update->out_transfer_func != NULL) { | |
90e508ba | 1676 | core_dc->hwss.set_output_transfer_func( |
f46661dd AZ |
1677 | pipe_ctx, pipe_ctx->stream); |
1678 | } | |
90e508ba | 1679 | |
ee8f63e1 | 1680 | if (srf_updates[i].hdr_static_metadata) { |
fcd2f4bf AZ |
1681 | resource_build_info_frame(pipe_ctx); |
1682 | core_dc->hwss.update_info_frame(pipe_ctx); | |
1683 | } | |
9474980a | 1684 | } |
4562236b HW |
1685 | } |
1686 | ||
00f02019 | 1687 | /* Unlock pipes */ |
a2b8659d | 1688 | for (i = core_dc->res_pool->pipe_count - 1; i >= 0; i--) { |
4562236b HW |
1689 | struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; |
1690 | ||
1691 | for (j = 0; j < surface_count; j++) { | |
f19d5f35 | 1692 | if (update_type != UPDATE_TYPE_FULL && |
3be5262e | 1693 | srf_updates[j].surface != pipe_ctx->plane_state) |
f19d5f35 | 1694 | continue; |
3be5262e | 1695 | if (!pipe_ctx->plane_state || pipe_ctx->top_pipe) |
f19d5f35 DL |
1696 | continue; |
1697 | ||
d70ccd4a YS |
1698 | core_dc->hwss.pipe_control_lock( |
1699 | core_dc, | |
1700 | pipe_ctx, | |
1701 | false); | |
1702 | ||
f19d5f35 | 1703 | break; |
4562236b HW |
1704 | } |
1705 | } | |
1706 | ||
e72f0acd | 1707 | if (core_dc->current_context != context) { |
8a76708e | 1708 | dc_release_validate_context(core_dc->current_context); |
e72f0acd TC |
1709 | core_dc->current_context = context; |
1710 | } | |
6d9501e4 HW |
1711 | return; |
1712 | ||
1713 | fail: | |
8a76708e AG |
1714 | dc_release_validate_context(context); |
1715 | ||
1716 | context_alloc_fail: | |
1717 | DC_ERROR("Failed to allocate new validate context!\n"); | |
4562236b HW |
1718 | } |
1719 | ||
ab2541b6 | 1720 | uint8_t dc_get_current_stream_count(const struct dc *dc) |
4562236b HW |
1721 | { |
1722 | struct core_dc *core_dc = DC_TO_CORE(dc); | |
ab2541b6 | 1723 | return core_dc->current_context->stream_count; |
4562236b HW |
1724 | } |
1725 | ||
0971c40e | 1726 | struct dc_stream_state *dc_get_stream_at_index(const struct dc *dc, uint8_t i) |
4562236b HW |
1727 | { |
1728 | struct core_dc *core_dc = DC_TO_CORE(dc); | |
ab2541b6 | 1729 | if (i < core_dc->current_context->stream_count) |
4fa086b9 | 1730 | return core_dc->current_context->streams[i]; |
4562236b HW |
1731 | return NULL; |
1732 | } | |
1733 | ||
d0778ebf | 1734 | struct dc_link *dc_get_link_at_index(const struct dc *dc, uint32_t link_index) |
4562236b HW |
1735 | { |
1736 | struct core_dc *core_dc = DC_TO_CORE(dc); | |
d0778ebf | 1737 | return core_dc->links[link_index]; |
4562236b HW |
1738 | } |
1739 | ||
1740 | const struct graphics_object_id dc_get_link_id_at_index( | |
1741 | struct dc *dc, uint32_t link_index) | |
1742 | { | |
1743 | struct core_dc *core_dc = DC_TO_CORE(dc); | |
1744 | return core_dc->links[link_index]->link_id; | |
1745 | } | |
1746 | ||
4562236b HW |
1747 | enum dc_irq_source dc_get_hpd_irq_source_at_index( |
1748 | struct dc *dc, uint32_t link_index) | |
1749 | { | |
1750 | struct core_dc *core_dc = DC_TO_CORE(dc); | |
d0778ebf | 1751 | return core_dc->links[link_index]->irq_source_hpd; |
4562236b HW |
1752 | } |
1753 | ||
1754 | const struct audio **dc_get_audios(struct dc *dc) | |
1755 | { | |
1756 | struct core_dc *core_dc = DC_TO_CORE(dc); | |
1757 | return (const struct audio **)core_dc->res_pool->audios; | |
1758 | } | |
1759 | ||
4562236b HW |
1760 | enum dc_irq_source dc_interrupt_to_irq_source( |
1761 | struct dc *dc, | |
1762 | uint32_t src_id, | |
1763 | uint32_t ext_id) | |
1764 | { | |
1765 | struct core_dc *core_dc = DC_TO_CORE(dc); | |
1766 | return dal_irq_service_to_irq_source(core_dc->res_pool->irqs, src_id, ext_id); | |
1767 | } | |
1768 | ||
1769 | void dc_interrupt_set(const struct dc *dc, enum dc_irq_source src, bool enable) | |
1770 | { | |
21de3396 RZ |
1771 | struct core_dc *core_dc; |
1772 | ||
1773 | if (dc == NULL) | |
1774 | return; | |
1775 | core_dc = DC_TO_CORE(dc); | |
1776 | ||
4562236b HW |
1777 | dal_irq_service_set(core_dc->res_pool->irqs, src, enable); |
1778 | } | |
1779 | ||
1780 | void dc_interrupt_ack(struct dc *dc, enum dc_irq_source src) | |
1781 | { | |
1782 | struct core_dc *core_dc = DC_TO_CORE(dc); | |
1783 | dal_irq_service_ack(core_dc->res_pool->irqs, src); | |
1784 | } | |
1785 | ||
1786 | void dc_set_power_state( | |
1787 | struct dc *dc, | |
a3621485 | 1788 | enum dc_acpi_cm_power_state power_state) |
4562236b HW |
1789 | { |
1790 | struct core_dc *core_dc = DC_TO_CORE(dc); | |
60bf1860 | 1791 | int ref_count; |
4562236b | 1792 | |
4562236b HW |
1793 | switch (power_state) { |
1794 | case DC_ACPI_CM_POWER_STATE_D0: | |
1795 | core_dc->hwss.init_hw(core_dc); | |
1796 | break; | |
1797 | default: | |
4562236b HW |
1798 | |
1799 | core_dc->hwss.power_down(core_dc); | |
1800 | ||
1801 | /* Zero out the current context so that on resume we start with | |
1802 | * clean state, and dc hw programming optimizations will not | |
1803 | * cause any trouble. | |
1804 | */ | |
60bf1860 AG |
1805 | |
1806 | /* Preserve refcount */ | |
1807 | ref_count = core_dc->current_context->ref_count; | |
1808 | dc_resource_validate_ctx_destruct(core_dc->current_context); | |
4562236b HW |
1809 | memset(core_dc->current_context, 0, |
1810 | sizeof(*core_dc->current_context)); | |
60bf1860 | 1811 | core_dc->current_context->ref_count = ref_count; |
4562236b | 1812 | |
4562236b HW |
1813 | break; |
1814 | } | |
1815 | ||
1816 | } | |
1817 | ||
1818 | void dc_resume(const struct dc *dc) | |
1819 | { | |
1820 | struct core_dc *core_dc = DC_TO_CORE(dc); | |
1821 | ||
1822 | uint32_t i; | |
1823 | ||
1824 | for (i = 0; i < core_dc->link_count; i++) | |
1825 | core_link_resume(core_dc->links[i]); | |
1826 | } | |
1827 | ||
7c7f5b15 | 1828 | bool dc_read_aux_dpcd( |
4562236b HW |
1829 | struct dc *dc, |
1830 | uint32_t link_index, | |
1831 | uint32_t address, | |
1832 | uint8_t *data, | |
1833 | uint32_t size) | |
1834 | { | |
1835 | struct core_dc *core_dc = DC_TO_CORE(dc); | |
1836 | ||
d0778ebf | 1837 | struct dc_link *link = core_dc->links[link_index]; |
4562236b | 1838 | enum ddc_result r = dal_ddc_service_read_dpcd_data( |
d0778ebf | 1839 | link->ddc, |
7c7f5b15 AG |
1840 | false, |
1841 | I2C_MOT_UNDEF, | |
4562236b HW |
1842 | address, |
1843 | data, | |
1844 | size); | |
1845 | return r == DDC_RESULT_SUCESSFULL; | |
1846 | } | |
1847 | ||
7c7f5b15 | 1848 | bool dc_write_aux_dpcd( |
2b230ea3 ZF |
1849 | struct dc *dc, |
1850 | uint32_t link_index, | |
1851 | uint32_t address, | |
7c7f5b15 AG |
1852 | const uint8_t *data, |
1853 | uint32_t size) | |
1854 | { | |
2b230ea3 | 1855 | struct core_dc *core_dc = DC_TO_CORE(dc); |
d0778ebf | 1856 | struct dc_link *link = core_dc->links[link_index]; |
2b230ea3 | 1857 | |
7c7f5b15 | 1858 | enum ddc_result r = dal_ddc_service_write_dpcd_data( |
d0778ebf | 1859 | link->ddc, |
7c7f5b15 AG |
1860 | false, |
1861 | I2C_MOT_UNDEF, | |
2b230ea3 | 1862 | address, |
7c7f5b15 AG |
1863 | data, |
1864 | size); | |
1865 | return r == DDC_RESULT_SUCESSFULL; | |
2b230ea3 ZF |
1866 | } |
1867 | ||
7c7f5b15 AG |
1868 | bool dc_read_aux_i2c( |
1869 | struct dc *dc, | |
1870 | uint32_t link_index, | |
1871 | enum i2c_mot_mode mot, | |
1872 | uint32_t address, | |
1873 | uint8_t *data, | |
1874 | uint32_t size) | |
1875 | { | |
1876 | struct core_dc *core_dc = DC_TO_CORE(dc); | |
2b230ea3 | 1877 | |
d0778ebf | 1878 | struct dc_link *link = core_dc->links[link_index]; |
7c7f5b15 | 1879 | enum ddc_result r = dal_ddc_service_read_dpcd_data( |
d0778ebf | 1880 | link->ddc, |
7c7f5b15 AG |
1881 | true, |
1882 | mot, | |
1883 | address, | |
1884 | data, | |
1885 | size); | |
1886 | return r == DDC_RESULT_SUCESSFULL; | |
1887 | } | |
1888 | ||
1889 | bool dc_write_aux_i2c( | |
4562236b HW |
1890 | struct dc *dc, |
1891 | uint32_t link_index, | |
7c7f5b15 | 1892 | enum i2c_mot_mode mot, |
4562236b HW |
1893 | uint32_t address, |
1894 | const uint8_t *data, | |
1895 | uint32_t size) | |
1896 | { | |
1897 | struct core_dc *core_dc = DC_TO_CORE(dc); | |
d0778ebf | 1898 | struct dc_link *link = core_dc->links[link_index]; |
4562236b HW |
1899 | |
1900 | enum ddc_result r = dal_ddc_service_write_dpcd_data( | |
d0778ebf | 1901 | link->ddc, |
7c7f5b15 AG |
1902 | true, |
1903 | mot, | |
4562236b HW |
1904 | address, |
1905 | data, | |
1906 | size); | |
1907 | return r == DDC_RESULT_SUCESSFULL; | |
1908 | } | |
1909 | ||
7c7f5b15 AG |
1910 | bool dc_query_ddc_data( |
1911 | struct dc *dc, | |
1912 | uint32_t link_index, | |
1913 | uint32_t address, | |
1914 | uint8_t *write_buf, | |
1915 | uint32_t write_size, | |
1916 | uint8_t *read_buf, | |
1917 | uint32_t read_size) { | |
1918 | ||
1919 | struct core_dc *core_dc = DC_TO_CORE(dc); | |
1920 | ||
d0778ebf | 1921 | struct dc_link *link = core_dc->links[link_index]; |
7c7f5b15 AG |
1922 | |
1923 | bool result = dal_ddc_service_query_ddc_data( | |
d0778ebf | 1924 | link->ddc, |
7c7f5b15 AG |
1925 | address, |
1926 | write_buf, | |
1927 | write_size, | |
1928 | read_buf, | |
1929 | read_size); | |
1930 | ||
1931 | return result; | |
1932 | } | |
1933 | ||
4562236b HW |
1934 | bool dc_submit_i2c( |
1935 | struct dc *dc, | |
1936 | uint32_t link_index, | |
1937 | struct i2c_command *cmd) | |
1938 | { | |
1939 | struct core_dc *core_dc = DC_TO_CORE(dc); | |
1940 | ||
d0778ebf HW |
1941 | struct dc_link *link = core_dc->links[link_index]; |
1942 | struct ddc_service *ddc = link->ddc; | |
4562236b HW |
1943 | |
1944 | return dal_i2caux_submit_i2c_command( | |
1945 | ddc->ctx->i2caux, | |
1946 | ddc->ddc_pin, | |
1947 | cmd); | |
1948 | } | |
1949 | ||
d0778ebf | 1950 | static bool link_add_remote_sink_helper(struct dc_link *dc_link, struct dc_sink *sink) |
4562236b | 1951 | { |
4562236b HW |
1952 | if (dc_link->sink_count >= MAX_SINKS_PER_LINK) { |
1953 | BREAK_TO_DEBUGGER(); | |
1954 | return false; | |
1955 | } | |
1956 | ||
1957 | dc_sink_retain(sink); | |
1958 | ||
1959 | dc_link->remote_sinks[dc_link->sink_count] = sink; | |
1960 | dc_link->sink_count++; | |
1961 | ||
1962 | return true; | |
1963 | } | |
1964 | ||
1965 | struct dc_sink *dc_link_add_remote_sink( | |
d0778ebf | 1966 | struct dc_link *link, |
4562236b HW |
1967 | const uint8_t *edid, |
1968 | int len, | |
1969 | struct dc_sink_init_data *init_data) | |
1970 | { | |
1971 | struct dc_sink *dc_sink; | |
1972 | enum dc_edid_status edid_status; | |
4562236b HW |
1973 | |
1974 | if (len > MAX_EDID_BUFFER_SIZE) { | |
1975 | dm_error("Max EDID buffer size breached!\n"); | |
1976 | return NULL; | |
1977 | } | |
1978 | ||
1979 | if (!init_data) { | |
1980 | BREAK_TO_DEBUGGER(); | |
1981 | return NULL; | |
1982 | } | |
1983 | ||
1984 | if (!init_data->link) { | |
1985 | BREAK_TO_DEBUGGER(); | |
1986 | return NULL; | |
1987 | } | |
1988 | ||
1989 | dc_sink = dc_sink_create(init_data); | |
1990 | ||
1991 | if (!dc_sink) | |
1992 | return NULL; | |
1993 | ||
1994 | memmove(dc_sink->dc_edid.raw_edid, edid, len); | |
1995 | dc_sink->dc_edid.length = len; | |
1996 | ||
1997 | if (!link_add_remote_sink_helper( | |
d0778ebf | 1998 | link, |
4562236b HW |
1999 | dc_sink)) |
2000 | goto fail_add_sink; | |
2001 | ||
2002 | edid_status = dm_helpers_parse_edid_caps( | |
d0778ebf | 2003 | link->ctx, |
4562236b HW |
2004 | &dc_sink->dc_edid, |
2005 | &dc_sink->edid_caps); | |
2006 | ||
2007 | if (edid_status != EDID_OK) | |
2008 | goto fail; | |
2009 | ||
2010 | return dc_sink; | |
2011 | fail: | |
2012 | dc_link_remove_remote_sink(link, dc_sink); | |
2013 | fail_add_sink: | |
2014 | dc_sink_release(dc_sink); | |
2015 | return NULL; | |
2016 | } | |
2017 | ||
d0778ebf | 2018 | void dc_link_set_sink(struct dc_link *link, struct dc_sink *sink) |
4562236b | 2019 | { |
d0778ebf | 2020 | link->local_sink = sink; |
4562236b HW |
2021 | |
2022 | if (sink == NULL) { | |
d0778ebf | 2023 | link->type = dc_connection_none; |
4562236b | 2024 | } else { |
d0778ebf | 2025 | link->type = dc_connection_single; |
4562236b HW |
2026 | } |
2027 | } | |
2028 | ||
b73a22d3 | 2029 | void dc_link_remove_remote_sink(struct dc_link *link, struct dc_sink *sink) |
4562236b HW |
2030 | { |
2031 | int i; | |
4562236b HW |
2032 | |
2033 | if (!link->sink_count) { | |
2034 | BREAK_TO_DEBUGGER(); | |
2035 | return; | |
2036 | } | |
2037 | ||
d0778ebf HW |
2038 | for (i = 0; i < link->sink_count; i++) { |
2039 | if (link->remote_sinks[i] == sink) { | |
4562236b | 2040 | dc_sink_release(sink); |
d0778ebf | 2041 | link->remote_sinks[i] = NULL; |
4562236b HW |
2042 | |
2043 | /* shrink array to remove empty place */ | |
d0778ebf HW |
2044 | while (i < link->sink_count - 1) { |
2045 | link->remote_sinks[i] = link->remote_sinks[i+1]; | |
4562236b HW |
2046 | i++; |
2047 | } | |
d0778ebf HW |
2048 | link->remote_sinks[i] = NULL; |
2049 | link->sink_count--; | |
4562236b HW |
2050 | return; |
2051 | } | |
2052 | } | |
2053 | } | |
2054 | ||
2c8ad2d5 AD |
2055 | bool dc_init_dchub(struct dc *dc, struct dchub_init_data *dh_data) |
2056 | { | |
2057 | int i; | |
2058 | struct core_dc *core_dc = DC_TO_CORE(dc); | |
2059 | struct mem_input *mi = NULL; | |
2060 | ||
2061 | for (i = 0; i < core_dc->res_pool->pipe_count; i++) { | |
2062 | if (core_dc->res_pool->mis[i] != NULL) { | |
2063 | mi = core_dc->res_pool->mis[i]; | |
2064 | break; | |
2065 | } | |
2066 | } | |
2067 | if (mi == NULL) { | |
2068 | dm_error("no mem_input!\n"); | |
2069 | return false; | |
2070 | } | |
2071 | ||
08b16886 ZF |
2072 | if (core_dc->hwss.update_dchub) |
2073 | core_dc->hwss.update_dchub(core_dc->hwseq, dh_data); | |
2c8ad2d5 | 2074 | else |
08b16886 | 2075 | ASSERT(core_dc->hwss.update_dchub); |
2c8ad2d5 AD |
2076 | |
2077 | ||
2078 | return true; | |
2079 | ||
2080 | } | |
2c8ad2d5 | 2081 | |
6d244be8 TC |
2082 | void dc_log_hw_state(struct dc *dc) |
2083 | { | |
2084 | struct core_dc *core_dc = DC_TO_CORE(dc); | |
2085 | ||
2086 | if (core_dc->hwss.log_hw_state) | |
2087 | core_dc->hwss.log_hw_state(core_dc); | |
2088 | } | |
690b5e39 | 2089 |