]>
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 | ||
4fc4dca8 | 25 | #include <linux/slab.h> |
44f3dd09 | 26 | #include <linux/mm.h> |
4fc4dca8 | 27 | |
4562236b HW |
28 | #include "dm_services.h" |
29 | ||
30 | #include "dc.h" | |
31 | ||
32 | #include "core_status.h" | |
33 | #include "core_types.h" | |
34 | #include "hw_sequencer.h" | |
405c50a0 | 35 | #include "dce/dce_hwseq.h" |
4562236b HW |
36 | |
37 | #include "resource.h" | |
38 | ||
dc88b4a6 | 39 | #include "clk_mgr.h" |
4562236b HW |
40 | #include "clock_source.h" |
41 | #include "dc_bios_types.h" | |
42 | ||
4562236b HW |
43 | #include "bios_parser_interface.h" |
44 | #include "include/irq_service_interface.h" | |
45 | #include "transform.h" | |
e923a355 | 46 | #include "dmcu.h" |
d94585a0 | 47 | #include "dpp.h" |
4562236b | 48 | #include "timing_generator.h" |
aa5a5777 | 49 | #include "abm.h" |
4562236b HW |
50 | #include "virtual/virtual_link_encoder.h" |
51 | ||
52 | #include "link_hwss.h" | |
53 | #include "link_encoder.h" | |
54 | ||
55 | #include "dc_link_ddc.h" | |
56 | #include "dm_helpers.h" | |
57 | #include "mem_input.h" | |
8feabd03 | 58 | #include "hubp.h" |
8f7040b8 ST |
59 | |
60 | #include "dc_link_dp.h" | |
3a1627b0 | 61 | #include "dc_dmub_srv.h" |
3a1627b0 | 62 | |
97bda032 | 63 | #include "dsc.h" |
97bda032 | 64 | |
6fbefb84 | 65 | #include "vm_helper.h" |
6fbefb84 | 66 | |
c85e6e54 DF |
67 | #include "dce/dce_i2c.h" |
68 | ||
6b5d7730 NA |
69 | #define CTX \ |
70 | dc->ctx | |
71 | ||
1296423b BL |
72 | #define DC_LOGGER \ |
73 | dc->ctx->logger | |
4562236b | 74 | |
39a502c8 | 75 | static const char DC_BUILD_ID[] = "production-build"; |
7fb77c51 | 76 | |
2119aa17 DF |
77 | /** |
78 | * DOC: Overview | |
79 | * | |
80 | * DC is the OS-agnostic component of the amdgpu DC driver. | |
81 | * | |
82 | * DC maintains and validates a set of structs representing the state of the | |
83 | * driver and writes that state to AMD hardware | |
84 | * | |
85 | * Main DC HW structs: | |
86 | * | |
87 | * struct dc - The central struct. One per driver. Created on driver load, | |
88 | * destroyed on driver unload. | |
89 | * | |
90 | * struct dc_context - One per driver. | |
91 | * Used as a backpointer by most other structs in dc. | |
92 | * | |
93 | * struct dc_link - One per connector (the physical DP, HDMI, miniDP, or eDP | |
94 | * plugpoints). Created on driver load, destroyed on driver unload. | |
95 | * | |
96 | * struct dc_sink - One per display. Created on boot or hotplug. | |
97 | * Destroyed on shutdown or hotunplug. A dc_link can have a local sink | |
98 | * (the display directly attached). It may also have one or more remote | |
99 | * sinks (in the Multi-Stream Transport case) | |
100 | * | |
101 | * struct resource_pool - One per driver. Represents the hw blocks not in the | |
102 | * main pipeline. Not directly accessible by dm. | |
103 | * | |
104 | * Main dc state structs: | |
105 | * | |
106 | * These structs can be created and destroyed as needed. There is a full set of | |
107 | * these structs in dc->current_state representing the currently programmed state. | |
108 | * | |
109 | * struct dc_state - The global DC state to track global state information, | |
110 | * such as bandwidth values. | |
111 | * | |
112 | * struct dc_stream_state - Represents the hw configuration for the pipeline from | |
113 | * a framebuffer to a display. Maps one-to-one with dc_sink. | |
114 | * | |
115 | * struct dc_plane_state - Represents a framebuffer. Each stream has at least one, | |
116 | * and may have more in the Multi-Plane Overlay case. | |
117 | * | |
118 | * struct resource_context - Represents the programmable state of everything in | |
119 | * the resource_pool. Not directly accessible by dm. | |
120 | * | |
121 | * struct pipe_ctx - A member of struct resource_context. Represents the | |
122 | * internal hardware pipeline components. Each dc_plane_state has either | |
123 | * one or two (in the pipe-split case). | |
124 | */ | |
125 | ||
4562236b HW |
126 | /******************************************************************************* |
127 | * Private functions | |
128 | ******************************************************************************/ | |
19ec320e AJ |
129 | |
130 | static inline void elevate_update_type(enum surface_update_type *original, enum surface_update_type new) | |
131 | { | |
132 | if (new > *original) | |
133 | *original = new; | |
134 | } | |
135 | ||
fb3466a4 | 136 | static void destroy_links(struct dc *dc) |
4562236b HW |
137 | { |
138 | uint32_t i; | |
139 | ||
140 | for (i = 0; i < dc->link_count; i++) { | |
141 | if (NULL != dc->links[i]) | |
142 | link_destroy(&dc->links[i]); | |
143 | } | |
144 | } | |
145 | ||
146 | static bool create_links( | |
fb3466a4 | 147 | struct dc *dc, |
4562236b HW |
148 | uint32_t num_virtual_links) |
149 | { | |
150 | int i; | |
151 | int connectors_num; | |
152 | struct dc_bios *bios = dc->ctx->dc_bios; | |
153 | ||
154 | dc->link_count = 0; | |
155 | ||
156 | connectors_num = bios->funcs->get_connectors_number(bios); | |
157 | ||
158 | if (connectors_num > ENUM_ID_COUNT) { | |
159 | dm_error( | |
160 | "DC: Number of connectors %d exceeds maximum of %d!\n", | |
161 | connectors_num, | |
162 | ENUM_ID_COUNT); | |
163 | return false; | |
164 | } | |
165 | ||
4562236b HW |
166 | dm_output_to_console( |
167 | "DC: %s: connectors_num: physical:%d, virtual:%d\n", | |
168 | __func__, | |
169 | connectors_num, | |
170 | num_virtual_links); | |
171 | ||
172 | for (i = 0; i < connectors_num; i++) { | |
173 | struct link_init_data link_init_params = {0}; | |
d0778ebf | 174 | struct dc_link *link; |
4562236b HW |
175 | |
176 | link_init_params.ctx = dc->ctx; | |
e4bf0a0e | 177 | /* next BIOS object table connector */ |
4562236b HW |
178 | link_init_params.connector_index = i; |
179 | link_init_params.link_index = dc->link_count; | |
180 | link_init_params.dc = dc; | |
181 | link = link_create(&link_init_params); | |
182 | ||
183 | if (link) { | |
291ac8fb LH |
184 | bool should_destory_link = false; |
185 | ||
186 | if (link->connector_signal == SIGNAL_TYPE_EDP) { | |
187 | if (dc->config.edp_not_connected) | |
188 | should_destory_link = true; | |
189 | else if (dc->debug.remove_disconnect_edp) { | |
190 | enum dc_connection_type type; | |
191 | dc_link_detect_sink(link, &type); | |
192 | if (type == dc_connection_none) | |
193 | should_destory_link = true; | |
194 | } | |
195 | } | |
196 | ||
22631bb8 | 197 | if (dc->config.force_enum_edp || !should_destory_link) { |
8dea4960 JL |
198 | dc->links[dc->link_count] = link; |
199 | link->dc = dc; | |
200 | ++dc->link_count; | |
291ac8fb LH |
201 | } else { |
202 | link_destroy(&link); | |
8dea4960 | 203 | } |
4562236b HW |
204 | } |
205 | } | |
206 | ||
207 | for (i = 0; i < num_virtual_links; i++) { | |
2004f45e | 208 | struct dc_link *link = kzalloc(sizeof(*link), GFP_KERNEL); |
4562236b HW |
209 | struct encoder_init_data enc_init = {0}; |
210 | ||
211 | if (link == NULL) { | |
212 | BREAK_TO_DEBUGGER(); | |
213 | goto failed_alloc; | |
214 | } | |
215 | ||
edf38b58 HW |
216 | link->link_index = dc->link_count; |
217 | dc->links[dc->link_count] = link; | |
218 | dc->link_count++; | |
219 | ||
4562236b HW |
220 | link->ctx = dc->ctx; |
221 | link->dc = dc; | |
d0778ebf | 222 | link->connector_signal = SIGNAL_TYPE_VIRTUAL; |
4562236b HW |
223 | link->link_id.type = OBJECT_TYPE_CONNECTOR; |
224 | link->link_id.id = CONNECTOR_ID_VIRTUAL; | |
225 | link->link_id.enum_id = ENUM_ID_1; | |
2004f45e | 226 | link->link_enc = kzalloc(sizeof(*link->link_enc), GFP_KERNEL); |
edf38b58 HW |
227 | |
228 | if (!link->link_enc) { | |
229 | BREAK_TO_DEBUGGER(); | |
230 | goto failed_alloc; | |
231 | } | |
232 | ||
6bffebc9 | 233 | link->link_status.dpcd_caps = &link->dpcd_caps; |
4562236b HW |
234 | |
235 | enc_init.ctx = dc->ctx; | |
236 | enc_init.channel = CHANNEL_ID_UNKNOWN; | |
237 | enc_init.hpd_source = HPD_SOURCEID_UNKNOWN; | |
238 | enc_init.transmitter = TRANSMITTER_UNKNOWN; | |
239 | enc_init.connector = link->link_id; | |
240 | enc_init.encoder.type = OBJECT_TYPE_ENCODER; | |
241 | enc_init.encoder.id = ENCODER_ID_INTERNAL_VIRTUAL; | |
242 | enc_init.encoder.enum_id = ENUM_ID_1; | |
243 | virtual_link_encoder_construct(link->link_enc, &enc_init); | |
4562236b HW |
244 | } |
245 | ||
246 | return true; | |
247 | ||
248 | failed_alloc: | |
249 | return false; | |
250 | } | |
251 | ||
0cf5eb76 DF |
252 | static struct dc_perf_trace *dc_perf_trace_create(void) |
253 | { | |
254 | return kzalloc(sizeof(struct dc_perf_trace), GFP_KERNEL); | |
255 | } | |
256 | ||
257 | static void dc_perf_trace_destroy(struct dc_perf_trace **perf_trace) | |
258 | { | |
259 | kfree(*perf_trace); | |
260 | *perf_trace = NULL; | |
261 | } | |
262 | ||
a27f1996 YAS |
263 | /** |
264 | ***************************************************************************** | |
265 | * Function: dc_stream_adjust_vmin_vmax | |
266 | * | |
267 | * @brief | |
268 | * Looks up the pipe context of dc_stream_state and updates the | |
269 | * vertical_total_min and vertical_total_max of the DRR, Dynamic Refresh | |
270 | * Rate, which is a power-saving feature that targets reducing panel | |
271 | * refresh rate while the screen is static | |
272 | * | |
273 | * @param [in] dc: dc reference | |
274 | * @param [in] stream: Initial dc stream state | |
275 | * @param [in] adjust: Updated parameters for vertical_total_min and | |
276 | * vertical_total_max | |
277 | ***************************************************************************** | |
278 | */ | |
2a06e0a5 | 279 | bool dc_stream_adjust_vmin_vmax(struct dc *dc, |
98e6436d AK |
280 | struct dc_stream_state *stream, |
281 | struct dc_crtc_timing_adjust *adjust) | |
4562236b | 282 | { |
4562236b HW |
283 | int i = 0; |
284 | bool ret = false; | |
4562236b | 285 | |
346d8a0a IZ |
286 | stream->adjust = *adjust; |
287 | ||
4562236b | 288 | for (i = 0; i < MAX_PIPES; i++) { |
608ac7bb | 289 | struct pipe_ctx *pipe = &dc->current_state->res_ctx.pipe_ctx[i]; |
4562236b | 290 | |
e63e2491 | 291 | if (pipe->stream == stream && pipe->stream_res.tg) { |
98e6436d AK |
292 | dc->hwss.set_drr(&pipe, |
293 | 1, | |
294 | adjust->v_total_min, | |
470e2ca5 BZ |
295 | adjust->v_total_max, |
296 | adjust->v_total_mid, | |
297 | adjust->v_total_mid_frame_num); | |
4562236b HW |
298 | |
299 | ret = true; | |
300 | } | |
301 | } | |
4562236b HW |
302 | return ret; |
303 | } | |
304 | ||
2a06e0a5 | 305 | bool dc_stream_get_crtc_position(struct dc *dc, |
0971c40e | 306 | struct dc_stream_state **streams, int num_streams, |
72ada5f7 EC |
307 | unsigned int *v_pos, unsigned int *nom_v_pos) |
308 | { | |
309 | /* TODO: Support multiple streams */ | |
98e6436d | 310 | const struct dc_stream_state *stream = streams[0]; |
72ada5f7 EC |
311 | int i = 0; |
312 | bool ret = false; | |
313 | struct crtc_position position; | |
314 | ||
315 | for (i = 0; i < MAX_PIPES; i++) { | |
316 | struct pipe_ctx *pipe = | |
608ac7bb | 317 | &dc->current_state->res_ctx.pipe_ctx[i]; |
72ada5f7 | 318 | |
8e9c4c8c | 319 | if (pipe->stream == stream && pipe->stream_res.stream_enc) { |
15659045 | 320 | dc->hwss.get_position(&pipe, 1, &position); |
72ada5f7 EC |
321 | |
322 | *v_pos = position.vertical_count; | |
323 | *nom_v_pos = position.nominal_vcount; | |
324 | ret = true; | |
325 | } | |
326 | } | |
327 | return ret; | |
328 | } | |
4562236b | 329 | |
31aec354 | 330 | /** |
2119aa17 | 331 | * dc_stream_configure_crc() - Configure CRC capture for the given stream. |
31aec354 LSL |
332 | * @dc: DC Object |
333 | * @stream: The stream to configure CRC on. | |
334 | * @enable: Enable CRC if true, disable otherwise. | |
335 | * @continuous: Capture CRC on every frame if true. Otherwise, only capture | |
336 | * once. | |
337 | * | |
338 | * By default, only CRC0 is configured, and the entire frame is used to | |
339 | * calculate the crc. | |
340 | */ | |
341 | bool dc_stream_configure_crc(struct dc *dc, struct dc_stream_state *stream, | |
342 | bool enable, bool continuous) | |
343 | { | |
344 | int i; | |
345 | struct pipe_ctx *pipe; | |
346 | struct crc_params param; | |
347 | struct timing_generator *tg; | |
348 | ||
349 | for (i = 0; i < MAX_PIPES; i++) { | |
350 | pipe = &dc->current_state->res_ctx.pipe_ctx[i]; | |
351 | if (pipe->stream == stream) | |
352 | break; | |
353 | } | |
354 | /* Stream not found */ | |
355 | if (i == MAX_PIPES) | |
356 | return false; | |
357 | ||
358 | /* Always capture the full frame */ | |
359 | param.windowa_x_start = 0; | |
360 | param.windowa_y_start = 0; | |
361 | param.windowa_x_end = pipe->stream->timing.h_addressable; | |
362 | param.windowa_y_end = pipe->stream->timing.v_addressable; | |
363 | param.windowb_x_start = 0; | |
364 | param.windowb_y_start = 0; | |
365 | param.windowb_x_end = pipe->stream->timing.h_addressable; | |
366 | param.windowb_y_end = pipe->stream->timing.v_addressable; | |
367 | ||
368 | /* Default to the union of both windows */ | |
369 | param.selection = UNION_WINDOW_A_B; | |
370 | param.continuous_mode = continuous; | |
371 | param.enable = enable; | |
372 | ||
373 | tg = pipe->stream_res.tg; | |
374 | ||
375 | /* Only call if supported */ | |
376 | if (tg->funcs->configure_crc) | |
377 | return tg->funcs->configure_crc(tg, ¶m); | |
1296423b | 378 | DC_LOG_WARNING("CRC capture not supported."); |
31aec354 LSL |
379 | return false; |
380 | } | |
381 | ||
382 | /** | |
2119aa17 | 383 | * dc_stream_get_crc() - Get CRC values for the given stream. |
31aec354 LSL |
384 | * @dc: DC object |
385 | * @stream: The DC stream state of the stream to get CRCs from. | |
386 | * @r_cr, g_y, b_cb: CRC values for the three channels are stored here. | |
387 | * | |
388 | * dc_stream_configure_crc needs to be called beforehand to enable CRCs. | |
389 | * Return false if stream is not found, or if CRCs are not enabled. | |
390 | */ | |
391 | bool dc_stream_get_crc(struct dc *dc, struct dc_stream_state *stream, | |
392 | uint32_t *r_cr, uint32_t *g_y, uint32_t *b_cb) | |
393 | { | |
394 | int i; | |
395 | struct pipe_ctx *pipe; | |
396 | struct timing_generator *tg; | |
397 | ||
398 | for (i = 0; i < MAX_PIPES; i++) { | |
399 | pipe = &dc->current_state->res_ctx.pipe_ctx[i]; | |
400 | if (pipe->stream == stream) | |
401 | break; | |
402 | } | |
403 | /* Stream not found */ | |
404 | if (i == MAX_PIPES) | |
405 | return false; | |
406 | ||
407 | tg = pipe->stream_res.tg; | |
408 | ||
409 | if (tg->funcs->get_crc) | |
410 | return tg->funcs->get_crc(tg, r_cr, g_y, b_cb); | |
1296423b | 411 | DC_LOG_WARNING("CRC capture not supported."); |
31aec354 LSL |
412 | return false; |
413 | } | |
414 | ||
90d26874 RS |
415 | void dc_stream_set_dyn_expansion(struct dc *dc, struct dc_stream_state *stream, |
416 | enum dc_dynamic_expansion option) | |
417 | { | |
418 | /* OPP FMT dyn expansion updates*/ | |
419 | int i = 0; | |
420 | struct pipe_ctx *pipe_ctx; | |
421 | ||
422 | for (i = 0; i < MAX_PIPES; i++) { | |
423 | if (dc->current_state->res_ctx.pipe_ctx[i].stream | |
424 | == stream) { | |
425 | pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i]; | |
426 | pipe_ctx->stream_res.opp->dyn_expansion = option; | |
427 | pipe_ctx->stream_res.opp->funcs->opp_set_dyn_expansion( | |
428 | pipe_ctx->stream_res.opp, | |
429 | COLOR_SPACE_YCBCR601, | |
430 | stream->timing.display_color_depth, | |
431 | stream->signal); | |
432 | } | |
433 | } | |
434 | } | |
435 | ||
44af70a7 LSL |
436 | void dc_stream_set_dither_option(struct dc_stream_state *stream, |
437 | enum dc_dither_option option) | |
438 | { | |
439 | struct bit_depth_reduction_params params; | |
ceb3dbb4 | 440 | struct dc_link *link = stream->link; |
44af70a7 LSL |
441 | struct pipe_ctx *pipes = NULL; |
442 | int i; | |
443 | ||
444 | for (i = 0; i < MAX_PIPES; i++) { | |
445 | if (link->dc->current_state->res_ctx.pipe_ctx[i].stream == | |
446 | stream) { | |
447 | pipes = &link->dc->current_state->res_ctx.pipe_ctx[i]; | |
448 | break; | |
449 | } | |
450 | } | |
451 | ||
44af70a7 LSL |
452 | if (!pipes) |
453 | return; | |
454 | if (option > DITHER_OPTION_MAX) | |
455 | return; | |
456 | ||
457 | stream->dither_option = option; | |
458 | ||
aed7b06e LSL |
459 | memset(¶ms, 0, sizeof(params)); |
460 | resource_build_bit_depth_reduction_params(stream, ¶ms); | |
44af70a7 | 461 | stream->bit_depth_params = params; |
aed7b06e LSL |
462 | |
463 | if (pipes->plane_res.xfm && | |
464 | pipes->plane_res.xfm->funcs->transform_set_pixel_storage_depth) { | |
465 | pipes->plane_res.xfm->funcs->transform_set_pixel_storage_depth( | |
466 | pipes->plane_res.xfm, | |
467 | pipes->plane_res.scl_data.lb_params.depth, | |
468 | &stream->bit_depth_params); | |
469 | } | |
470 | ||
44af70a7 LSL |
471 | pipes->stream_res.opp->funcs-> |
472 | opp_program_bit_depth_reduction(pipes->stream_res.opp, ¶ms); | |
473 | } | |
474 | ||
8ab56172 S |
475 | bool dc_stream_set_gamut_remap(struct dc *dc, const struct dc_stream_state *stream) |
476 | { | |
477 | int i = 0; | |
478 | bool ret = false; | |
479 | struct pipe_ctx *pipes; | |
480 | ||
481 | for (i = 0; i < MAX_PIPES; i++) { | |
482 | if (dc->current_state->res_ctx.pipe_ctx[i].stream == stream) { | |
483 | pipes = &dc->current_state->res_ctx.pipe_ctx[i]; | |
484 | dc->hwss.program_gamut_remap(pipes); | |
485 | ret = true; | |
486 | } | |
487 | } | |
488 | ||
489 | return ret; | |
490 | } | |
491 | ||
eb385204 S |
492 | bool dc_stream_program_csc_matrix(struct dc *dc, struct dc_stream_state *stream) |
493 | { | |
494 | int i = 0; | |
495 | bool ret = false; | |
496 | struct pipe_ctx *pipes; | |
497 | ||
498 | for (i = 0; i < MAX_PIPES; i++) { | |
499 | if (dc->current_state->res_ctx.pipe_ctx[i].stream | |
500 | == stream) { | |
501 | ||
502 | pipes = &dc->current_state->res_ctx.pipe_ctx[i]; | |
3917a470 KK |
503 | dc->hwss.program_output_csc(dc, |
504 | pipes, | |
505 | stream->output_color_space, | |
506 | stream->csc_color_matrix.matrix, | |
c0826487 | 507 | pipes->stream_res.opp->inst); |
eb385204 S |
508 | ret = true; |
509 | } | |
510 | } | |
511 | ||
512 | return ret; | |
513 | } | |
514 | ||
5b5abe95 | 515 | void dc_stream_set_static_screen_params(struct dc *dc, |
0971c40e | 516 | struct dc_stream_state **streams, |
94267b3d | 517 | int num_streams, |
5b5abe95 | 518 | const struct dc_static_screen_params *params) |
94267b3d | 519 | { |
94267b3d ST |
520 | int i = 0; |
521 | int j = 0; | |
522 | struct pipe_ctx *pipes_affected[MAX_PIPES]; | |
523 | int num_pipes_affected = 0; | |
524 | ||
525 | for (i = 0; i < num_streams; i++) { | |
0971c40e | 526 | struct dc_stream_state *stream = streams[i]; |
94267b3d ST |
527 | |
528 | for (j = 0; j < MAX_PIPES; j++) { | |
608ac7bb | 529 | if (dc->current_state->res_ctx.pipe_ctx[j].stream |
4fa086b9 | 530 | == stream) { |
94267b3d | 531 | pipes_affected[num_pipes_affected++] = |
608ac7bb | 532 | &dc->current_state->res_ctx.pipe_ctx[j]; |
94267b3d ST |
533 | } |
534 | } | |
535 | } | |
536 | ||
5b5abe95 | 537 | dc->hwss.set_static_screen_control(pipes_affected, num_pipes_affected, params); |
94267b3d ST |
538 | } |
539 | ||
d9e32672 | 540 | static void dc_destruct(struct dc *dc) |
4562236b | 541 | { |
8897810a JP |
542 | if (dc->current_state) { |
543 | dc_release_state(dc->current_state); | |
544 | dc->current_state = NULL; | |
545 | } | |
4562236b | 546 | |
4562236b HW |
547 | destroy_links(dc); |
548 | ||
dc88b4a6 EY |
549 | if (dc->clk_mgr) { |
550 | dc_destroy_clk_mgr(dc->clk_mgr); | |
551 | dc->clk_mgr = NULL; | |
552 | } | |
553 | ||
4562236b HW |
554 | dc_destroy_resource_pool(dc); |
555 | ||
556 | if (dc->ctx->gpio_service) | |
557 | dal_gpio_service_destroy(&dc->ctx->gpio_service); | |
558 | ||
4562236b HW |
559 | if (dc->ctx->created_bios) |
560 | dal_bios_parser_destroy(&dc->ctx->dc_bios); | |
561 | ||
0cf5eb76 DF |
562 | dc_perf_trace_destroy(&dc->ctx->perf_trace); |
563 | ||
2004f45e | 564 | kfree(dc->ctx); |
4562236b | 565 | dc->ctx = NULL; |
77a4ea53 | 566 | |
2004f45e | 567 | kfree(dc->bw_vbios); |
77a4ea53 BL |
568 | dc->bw_vbios = NULL; |
569 | ||
2004f45e | 570 | kfree(dc->bw_dceip); |
77a4ea53 BL |
571 | dc->bw_dceip = NULL; |
572 | ||
b86a1aa3 | 573 | #ifdef CONFIG_DRM_AMD_DC_DCN |
2004f45e | 574 | kfree(dc->dcn_soc); |
65111f25 BL |
575 | dc->dcn_soc = NULL; |
576 | ||
2004f45e | 577 | kfree(dc->dcn_ip); |
65111f25 | 578 | dc->dcn_ip = NULL; |
fb3466a4 | 579 | |
6fbefb84 | 580 | #endif |
6fbefb84 HW |
581 | kfree(dc->vm_helper); |
582 | dc->vm_helper = NULL; | |
583 | ||
4562236b HW |
584 | } |
585 | ||
68c0fca5 JL |
586 | static bool dc_construct_ctx(struct dc *dc, |
587 | const struct dc_init_data *init_params) | |
588 | { | |
589 | struct dc_context *dc_ctx; | |
590 | enum dce_version dc_version = DCE_VERSION_UNKNOWN; | |
591 | ||
592 | dc_ctx = kzalloc(sizeof(*dc_ctx), GFP_KERNEL); | |
593 | if (!dc_ctx) | |
594 | return false; | |
595 | ||
596 | dc_ctx->cgs_device = init_params->cgs_device; | |
597 | dc_ctx->driver_context = init_params->driver; | |
598 | dc_ctx->dc = dc; | |
599 | dc_ctx->asic_id = init_params->asic_id; | |
600 | dc_ctx->dc_sink_id_count = 0; | |
601 | dc_ctx->dc_stream_id_count = 0; | |
602 | dc_ctx->dce_environment = init_params->dce_environment; | |
603 | ||
604 | /* Create logger */ | |
605 | ||
606 | dc_version = resource_parse_asic_id(init_params->asic_id); | |
607 | dc_ctx->dce_version = dc_version; | |
608 | ||
609 | dc_ctx->perf_trace = dc_perf_trace_create(); | |
610 | if (!dc_ctx->perf_trace) { | |
611 | ASSERT_CRITICAL(false); | |
612 | return false; | |
613 | } | |
614 | ||
615 | dc->ctx = dc_ctx; | |
616 | ||
617 | return true; | |
618 | } | |
619 | ||
d9e32672 | 620 | static bool dc_construct(struct dc *dc, |
4562236b HW |
621 | const struct dc_init_data *init_params) |
622 | { | |
52924dc3 HW |
623 | struct dc_context *dc_ctx; |
624 | struct bw_calcs_dceip *dc_dceip; | |
625 | struct bw_calcs_vbios *dc_vbios; | |
b86a1aa3 | 626 | #ifdef CONFIG_DRM_AMD_DC_DCN |
52924dc3 HW |
627 | struct dcn_soc_bounding_box *dcn_soc; |
628 | struct dcn_ip_params *dcn_ip; | |
65111f25 | 629 | #endif |
77a4ea53 | 630 | |
c85fc65e AK |
631 | dc->config = init_params->flags; |
632 | ||
6fbefb84 HW |
633 | // Allocate memory for the vm_helper |
634 | dc->vm_helper = kzalloc(sizeof(struct vm_helper), GFP_KERNEL); | |
039ffeaa | 635 | if (!dc->vm_helper) { |
636 | dm_error("%s: failed to create dc->vm_helper\n", __func__); | |
637 | goto fail; | |
638 | } | |
6fbefb84 | 639 | |
6649f19a JL |
640 | memcpy(&dc->bb_overrides, &init_params->bb_overrides, sizeof(dc->bb_overrides)); |
641 | ||
52924dc3 | 642 | dc_dceip = kzalloc(sizeof(*dc_dceip), GFP_KERNEL); |
77a4ea53 BL |
643 | if (!dc_dceip) { |
644 | dm_error("%s: failed to create dceip\n", __func__); | |
65111f25 | 645 | goto fail; |
77a4ea53 BL |
646 | } |
647 | ||
648 | dc->bw_dceip = dc_dceip; | |
649 | ||
52924dc3 | 650 | dc_vbios = kzalloc(sizeof(*dc_vbios), GFP_KERNEL); |
77a4ea53 BL |
651 | if (!dc_vbios) { |
652 | dm_error("%s: failed to create vbios\n", __func__); | |
65111f25 | 653 | goto fail; |
77a4ea53 BL |
654 | } |
655 | ||
656 | dc->bw_vbios = dc_vbios; | |
b86a1aa3 | 657 | #ifdef CONFIG_DRM_AMD_DC_DCN |
52924dc3 | 658 | dcn_soc = kzalloc(sizeof(*dcn_soc), GFP_KERNEL); |
65111f25 BL |
659 | if (!dcn_soc) { |
660 | dm_error("%s: failed to create dcn_soc\n", __func__); | |
661 | goto fail; | |
662 | } | |
663 | ||
664 | dc->dcn_soc = dcn_soc; | |
665 | ||
52924dc3 | 666 | dcn_ip = kzalloc(sizeof(*dcn_ip), GFP_KERNEL); |
65111f25 BL |
667 | if (!dcn_ip) { |
668 | dm_error("%s: failed to create dcn_ip\n", __func__); | |
669 | goto fail; | |
670 | } | |
671 | ||
672 | dc->dcn_ip = dcn_ip; | |
6fbefb84 | 673 | dc->soc_bounding_box = init_params->soc_bounding_box; |
65111f25 | 674 | #endif |
77a4ea53 | 675 | |
68c0fca5 | 676 | if (!dc_construct_ctx(dc, init_params)) { |
4562236b | 677 | dm_error("%s: failed to create ctx\n", __func__); |
65111f25 | 678 | goto fail; |
4562236b HW |
679 | } |
680 | ||
68c0fca5 | 681 | dc_ctx = dc->ctx; |
553aae12 | 682 | |
4562236b HW |
683 | /* Resource should construct all asic specific resources. |
684 | * This should be the only place where we need to parse the asic id | |
685 | */ | |
686 | if (init_params->vbios_override) | |
687 | dc_ctx->dc_bios = init_params->vbios_override; | |
688 | else { | |
689 | /* Create BIOS parser */ | |
690 | struct bp_init_data bp_init_data; | |
e8c963d6 | 691 | |
4562236b HW |
692 | bp_init_data.ctx = dc_ctx; |
693 | bp_init_data.bios = init_params->asic_id.atombios_base_address; | |
694 | ||
695 | dc_ctx->dc_bios = dal_bios_parser_create( | |
68c0fca5 | 696 | &bp_init_data, dc_ctx->dce_version); |
4562236b HW |
697 | |
698 | if (!dc_ctx->dc_bios) { | |
699 | ASSERT_CRITICAL(false); | |
65111f25 | 700 | goto fail; |
4562236b HW |
701 | } |
702 | ||
703 | dc_ctx->created_bios = true; | |
0cf5eb76 DF |
704 | } |
705 | ||
0136684f | 706 | dc->vendor_signature = init_params->vendor_signature; |
68c0fca5 | 707 | |
4562236b HW |
708 | /* Create GPIO service */ |
709 | dc_ctx->gpio_service = dal_gpio_service_create( | |
68c0fca5 | 710 | dc_ctx->dce_version, |
4562236b HW |
711 | dc_ctx->dce_environment, |
712 | dc_ctx); | |
713 | ||
714 | if (!dc_ctx->gpio_service) { | |
715 | ASSERT_CRITICAL(false); | |
65111f25 | 716 | goto fail; |
4562236b HW |
717 | } |
718 | ||
68c0fca5 | 719 | dc->res_pool = dc_create_resource_pool(dc, init_params, dc_ctx->dce_version); |
4562236b | 720 | if (!dc->res_pool) |
65111f25 | 721 | goto fail; |
4562236b | 722 | |
dc88b4a6 EY |
723 | dc->clk_mgr = dc_clk_mgr_create(dc->ctx, dc->res_pool->pp_smu, dc->res_pool->dccg); |
724 | if (!dc->clk_mgr) | |
725 | goto fail; | |
726 | ||
1b2c7b2c BL |
727 | if (dc->res_pool->funcs->update_bw_bounding_box) |
728 | dc->res_pool->funcs->update_bw_bounding_box(dc, dc->clk_mgr->bw_params); | |
1b2c7b2c | 729 | |
813d20dc AW |
730 | /* Creation of current_state must occur after dc->dml |
731 | * is initialized in dc_create_resource_pool because | |
732 | * on creation it copies the contents of dc->dml | |
733 | */ | |
734 | ||
735 | dc->current_state = dc_create_state(dc); | |
736 | ||
737 | if (!dc->current_state) { | |
738 | dm_error("%s: failed to create validate ctx\n", __func__); | |
739 | goto fail; | |
740 | } | |
741 | ||
ab8db3e1 AG |
742 | dc_resource_state_construct(dc, dc->current_state); |
743 | ||
4562236b | 744 | if (!create_links(dc, init_params->num_virtual_links)) |
65111f25 | 745 | goto fail; |
4562236b | 746 | |
4562236b HW |
747 | return true; |
748 | ||
65111f25 | 749 | fail: |
4562236b HW |
750 | return false; |
751 | } | |
752 | ||
6fbefb84 HW |
753 | static bool disable_all_writeback_pipes_for_stream( |
754 | const struct dc *dc, | |
755 | struct dc_stream_state *stream, | |
756 | struct dc_state *context) | |
757 | { | |
758 | int i; | |
759 | ||
760 | for (i = 0; i < stream->num_wb_info; i++) | |
761 | stream->writeback_info[i].wb_enabled = false; | |
762 | ||
763 | return true; | |
764 | } | |
6fbefb84 | 765 | |
009114f6 AK |
766 | void apply_ctx_interdependent_lock(struct dc *dc, struct dc_state *context, struct dc_stream_state *stream, bool lock) |
767 | { | |
768 | int i = 0; | |
769 | ||
770 | /* Checks if interdependent update function pointer is NULL or not, takes care of DCE110 case */ | |
771 | if (dc->hwss.interdependent_update_lock) | |
772 | dc->hwss.interdependent_update_lock(dc, context, lock); | |
773 | else { | |
774 | for (i = 0; i < dc->res_pool->pipe_count; i++) { | |
775 | struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; | |
776 | struct pipe_ctx *old_pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i]; | |
777 | ||
778 | // Copied conditions that were previously in dce110_apply_ctx_for_surface | |
779 | if (stream == pipe_ctx->stream) { | |
780 | if (!pipe_ctx->top_pipe && | |
781 | (pipe_ctx->plane_state || old_pipe_ctx->plane_state)) | |
782 | dc->hwss.pipe_control_lock(dc, pipe_ctx, lock); | |
009114f6 AK |
783 | } |
784 | } | |
785 | } | |
786 | } | |
787 | ||
524bed9a LSL |
788 | static void disable_dangling_plane(struct dc *dc, struct dc_state *context) |
789 | { | |
790 | int i, j; | |
813d20dc | 791 | struct dc_state *dangling_context = dc_create_state(dc); |
524bed9a LSL |
792 | struct dc_state *current_ctx; |
793 | ||
794 | if (dangling_context == NULL) | |
795 | return; | |
796 | ||
797 | dc_resource_state_copy_construct(dc->current_state, dangling_context); | |
798 | ||
799 | for (i = 0; i < dc->res_pool->pipe_count; i++) { | |
800 | struct dc_stream_state *old_stream = | |
801 | dc->current_state->res_ctx.pipe_ctx[i].stream; | |
802 | bool should_disable = true; | |
803 | ||
804 | for (j = 0; j < context->stream_count; j++) { | |
805 | if (old_stream == context->streams[j]) { | |
806 | should_disable = false; | |
807 | break; | |
808 | } | |
809 | } | |
810 | if (should_disable && old_stream) { | |
811 | dc_rem_all_planes_for_stream(dc, old_stream, dangling_context); | |
6fbefb84 | 812 | disable_all_writeback_pipes_for_stream(dc, old_stream, dangling_context); |
009114f6 | 813 | |
bbf5f6c3 | 814 | if (dc->hwss.apply_ctx_for_surface) { |
009114f6 | 815 | apply_ctx_interdependent_lock(dc, dc->current_state, old_stream, true); |
b6e881c9 | 816 | dc->hwss.apply_ctx_for_surface(dc, old_stream, 0, dangling_context); |
009114f6 | 817 | apply_ctx_interdependent_lock(dc, dc->current_state, old_stream, false); |
bbf5f6c3 AK |
818 | dc->hwss.post_unlock_program_front_end(dc, dangling_context); |
819 | } | |
820 | if (dc->hwss.program_front_end_for_ctx) { | |
009114f6 | 821 | dc->hwss.interdependent_update_lock(dc, dc->current_state, true); |
bbf5f6c3 | 822 | dc->hwss.program_front_end_for_ctx(dc, dangling_context); |
009114f6 | 823 | dc->hwss.interdependent_update_lock(dc, dc->current_state, false); |
bbf5f6c3 AK |
824 | dc->hwss.post_unlock_program_front_end(dc, dangling_context); |
825 | } | |
524bed9a LSL |
826 | } |
827 | } | |
828 | ||
829 | current_ctx = dc->current_state; | |
830 | dc->current_state = dangling_context; | |
831 | dc_release_state(current_ctx); | |
832 | } | |
833 | ||
6b5d7730 NA |
834 | static void wait_for_no_pipes_pending(struct dc *dc, struct dc_state *context) |
835 | { | |
836 | int i; | |
6b5d7730 NA |
837 | PERF_TRACE(); |
838 | for (i = 0; i < MAX_PIPES; i++) { | |
80797dd6 RL |
839 | int count = 0; |
840 | struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; | |
6b5d7730 NA |
841 | |
842 | if (!pipe->plane_state) | |
843 | continue; | |
844 | ||
845 | /* Timeout 100 ms */ | |
846 | while (count < 100000) { | |
847 | /* Must set to false to start with, due to OR in update function */ | |
848 | pipe->plane_state->status.is_flip_pending = false; | |
849 | dc->hwss.update_pending_status(pipe); | |
850 | if (!pipe->plane_state->status.is_flip_pending) | |
851 | break; | |
852 | udelay(1); | |
853 | count++; | |
854 | } | |
855 | ASSERT(!pipe->plane_state->status.is_flip_pending); | |
856 | } | |
857 | PERF_TRACE(); | |
858 | } | |
859 | ||
4562236b HW |
860 | /******************************************************************************* |
861 | * Public functions | |
862 | ******************************************************************************/ | |
863 | ||
864 | struct dc *dc_create(const struct dc_init_data *init_params) | |
447a5647 | 865 | { |
2004f45e | 866 | struct dc *dc = kzalloc(sizeof(*dc), GFP_KERNEL); |
4562236b HW |
867 | unsigned int full_pipe_count; |
868 | ||
15659045 | 869 | if (NULL == dc) |
4562236b HW |
870 | goto alloc_fail; |
871 | ||
68c0fca5 JL |
872 | if (init_params->dce_environment == DCE_ENV_VIRTUAL_HW) { |
873 | if (false == dc_construct_ctx(dc, init_params)) { | |
874 | dc_destruct(dc); | |
875 | goto construct_fail; | |
876 | } | |
877 | } else { | |
878 | if (false == dc_construct(dc, init_params)) { | |
879 | dc_destruct(dc); | |
880 | goto construct_fail; | |
881 | } | |
4562236b | 882 | |
68c0fca5 JL |
883 | full_pipe_count = dc->res_pool->pipe_count; |
884 | if (dc->res_pool->underlay_pipe_index != NO_UNDERLAY_PIPE) | |
885 | full_pipe_count--; | |
886 | dc->caps.max_streams = min( | |
887 | full_pipe_count, | |
888 | dc->res_pool->stream_enc_count); | |
4562236b | 889 | |
68c0fca5 JL |
890 | dc->optimize_seamless_boot_streams = 0; |
891 | dc->caps.max_links = dc->link_count; | |
892 | dc->caps.max_audios = dc->res_pool->audio_count; | |
893 | dc->caps.linear_pitch_alignment = 64; | |
4562236b | 894 | |
68c0fca5 JL |
895 | dc->caps.max_dp_protocol_version = DP_VERSION_1_4; |
896 | ||
897 | if (dc->res_pool->dmcu != NULL) | |
898 | dc->versions.dmcu_version = dc->res_pool->dmcu->dmcu_version; | |
899 | } | |
8d623f86 | 900 | |
e923a355 AK |
901 | /* Populate versioning information */ |
902 | dc->versions.dc_ver = DC_VER; | |
903 | ||
be61df57 JL |
904 | dc->build_id = DC_BUILD_ID; |
905 | ||
1296423b | 906 | DC_LOG_DC("Display Core initialized\n"); |
4562236b HW |
907 | |
908 | ||
4562236b | 909 | |
15659045 | 910 | return dc; |
4562236b HW |
911 | |
912 | construct_fail: | |
2004f45e | 913 | kfree(dc); |
4562236b HW |
914 | |
915 | alloc_fail: | |
916 | return NULL; | |
917 | } | |
918 | ||
98bf2f52 JP |
919 | void dc_hardware_init(struct dc *dc) |
920 | { | |
68c0fca5 JL |
921 | if (dc->ctx->dce_environment != DCE_ENV_VIRTUAL_HW) |
922 | dc->hwss.init_hw(dc); | |
98bf2f52 JP |
923 | } |
924 | ||
d5cf79ee WL |
925 | void dc_init_callbacks(struct dc *dc, |
926 | const struct dc_callback_init *init_params) | |
927 | { | |
d462fcf5 BL |
928 | #ifdef CONFIG_DRM_AMD_DC_HDCP |
929 | dc->ctx->cp_psp = init_params->cp_psp; | |
930 | #endif | |
931 | } | |
932 | ||
933 | void dc_deinit_callbacks(struct dc *dc) | |
934 | { | |
935 | #ifdef CONFIG_DRM_AMD_DC_HDCP | |
936 | memset(&dc->ctx->cp_psp, 0, sizeof(dc->ctx->cp_psp)); | |
937 | #endif | |
d5cf79ee WL |
938 | } |
939 | ||
4562236b HW |
940 | void dc_destroy(struct dc **dc) |
941 | { | |
d9e32672 | 942 | dc_destruct(*dc); |
2004f45e | 943 | kfree(*dc); |
4562236b HW |
944 | *dc = NULL; |
945 | } | |
946 | ||
fa2123db ML |
947 | static void enable_timing_multisync( |
948 | struct dc *dc, | |
949 | struct dc_state *ctx) | |
950 | { | |
951 | int i = 0, multisync_count = 0; | |
952 | int pipe_count = dc->res_pool->pipe_count; | |
953 | struct pipe_ctx *multisync_pipes[MAX_PIPES] = { NULL }; | |
954 | ||
955 | for (i = 0; i < pipe_count; i++) { | |
956 | if (!ctx->res_ctx.pipe_ctx[i].stream || | |
957 | !ctx->res_ctx.pipe_ctx[i].stream->triggered_crtc_reset.enabled) | |
958 | continue; | |
03736f4c ML |
959 | if (ctx->res_ctx.pipe_ctx[i].stream == ctx->res_ctx.pipe_ctx[i].stream->triggered_crtc_reset.event_source) |
960 | continue; | |
fa2123db ML |
961 | multisync_pipes[multisync_count] = &ctx->res_ctx.pipe_ctx[i]; |
962 | multisync_count++; | |
963 | } | |
964 | ||
03736f4c | 965 | if (multisync_count > 0) { |
fa2123db ML |
966 | dc->hwss.enable_per_frame_crtc_position_reset( |
967 | dc, multisync_count, multisync_pipes); | |
968 | } | |
969 | } | |
970 | ||
4562236b | 971 | static void program_timing_sync( |
15659045 | 972 | struct dc *dc, |
608ac7bb | 973 | struct dc_state *ctx) |
4562236b | 974 | { |
8dac4e7d | 975 | int i, j, k; |
4562236b | 976 | int group_index = 0; |
8dac4e7d | 977 | int num_group = 0; |
15659045 | 978 | int pipe_count = dc->res_pool->pipe_count; |
4562236b HW |
979 | struct pipe_ctx *unsynced_pipes[MAX_PIPES] = { NULL }; |
980 | ||
981 | for (i = 0; i < pipe_count; i++) { | |
982 | if (!ctx->res_ctx.pipe_ctx[i].stream || ctx->res_ctx.pipe_ctx[i].top_pipe) | |
983 | continue; | |
984 | ||
985 | unsynced_pipes[i] = &ctx->res_ctx.pipe_ctx[i]; | |
986 | } | |
987 | ||
988 | for (i = 0; i < pipe_count; i++) { | |
989 | int group_size = 1; | |
990 | struct pipe_ctx *pipe_set[MAX_PIPES]; | |
991 | ||
992 | if (!unsynced_pipes[i]) | |
993 | continue; | |
994 | ||
995 | pipe_set[0] = unsynced_pipes[i]; | |
996 | unsynced_pipes[i] = NULL; | |
997 | ||
998 | /* Add tg to the set, search rest of the tg's for ones with | |
999 | * same timing, add all tgs with same timing to the group | |
1000 | */ | |
1001 | for (j = i + 1; j < pipe_count; j++) { | |
1002 | if (!unsynced_pipes[j]) | |
1003 | continue; | |
1004 | ||
1005 | if (resource_are_streams_timing_synchronizable( | |
1006 | unsynced_pipes[j]->stream, | |
1007 | pipe_set[0]->stream)) { | |
1008 | pipe_set[group_size] = unsynced_pipes[j]; | |
1009 | unsynced_pipes[j] = NULL; | |
1010 | group_size++; | |
1011 | } | |
1012 | } | |
1013 | ||
5fc0cbfa | 1014 | /* set first pipe with plane as master */ |
4562236b | 1015 | for (j = 0; j < group_size; j++) { |
5fc0cbfa | 1016 | if (pipe_set[j]->plane_state) { |
4562236b HW |
1017 | if (j == 0) |
1018 | break; | |
1019 | ||
34b86b75 | 1020 | swap(pipe_set[0], pipe_set[j]); |
4562236b HW |
1021 | break; |
1022 | } | |
1023 | } | |
1024 | ||
8dac4e7d SSC |
1025 | |
1026 | for (k = 0; k < group_size; k++) { | |
1027 | struct dc_stream_status *status = dc_stream_get_status_from_state(ctx, pipe_set[k]->stream); | |
1028 | ||
1029 | status->timing_sync_info.group_id = num_group; | |
1030 | status->timing_sync_info.group_size = group_size; | |
1031 | if (k == 0) | |
1032 | status->timing_sync_info.master = true; | |
1033 | else | |
1034 | status->timing_sync_info.master = false; | |
1035 | ||
1036 | } | |
5fc0cbfa | 1037 | /* remove any other pipes with plane as they have already been synced */ |
4562236b | 1038 | for (j = j + 1; j < group_size; j++) { |
5fc0cbfa | 1039 | if (pipe_set[j]->plane_state) { |
4562236b HW |
1040 | group_size--; |
1041 | pipe_set[j] = pipe_set[group_size]; | |
1042 | j--; | |
1043 | } | |
1044 | } | |
1045 | ||
1046 | if (group_size > 1) { | |
15659045 BL |
1047 | dc->hwss.enable_timing_synchronization( |
1048 | dc, group_index, group_size, pipe_set); | |
4562236b HW |
1049 | group_index++; |
1050 | } | |
8dac4e7d | 1051 | num_group++; |
4562236b HW |
1052 | } |
1053 | } | |
1054 | ||
e2c7bb12 | 1055 | static bool context_changed( |
fb3466a4 | 1056 | struct dc *dc, |
608ac7bb | 1057 | struct dc_state *context) |
7cf2c840 HW |
1058 | { |
1059 | uint8_t i; | |
1060 | ||
608ac7bb | 1061 | if (context->stream_count != dc->current_state->stream_count) |
7cf2c840 HW |
1062 | return true; |
1063 | ||
608ac7bb JZ |
1064 | for (i = 0; i < dc->current_state->stream_count; i++) { |
1065 | if (dc->current_state->streams[i] != context->streams[i]) | |
7cf2c840 HW |
1066 | return true; |
1067 | } | |
1068 | ||
1069 | return false; | |
1070 | } | |
1071 | ||
46570f09 | 1072 | bool dc_validate_seamless_boot_timing(const struct dc *dc, |
68f1a00c AK |
1073 | const struct dc_sink *sink, |
1074 | struct dc_crtc_timing *crtc_timing) | |
1075 | { | |
1076 | struct timing_generator *tg; | |
52883b36 | 1077 | struct stream_encoder *se = NULL; |
93c2340b ML |
1078 | |
1079 | struct dc_crtc_timing hw_crtc_timing = {0}; | |
1080 | ||
68f1a00c | 1081 | struct dc_link *link = sink->link; |
08b66279 | 1082 | unsigned int i, enc_inst, tg_inst = 0; |
7f7652ee ML |
1083 | |
1084 | // Seamless port only support single DP and EDP so far | |
1085 | if (sink->sink_signal != SIGNAL_TYPE_DISPLAY_PORT && | |
1086 | sink->sink_signal != SIGNAL_TYPE_EDP) | |
1087 | return false; | |
68f1a00c AK |
1088 | |
1089 | /* Check for enabled DIG to identify enabled display */ | |
1090 | if (!link->link_enc->funcs->is_dig_enabled(link->link_enc)) | |
1091 | return false; | |
1092 | ||
5ec43eda | 1093 | enc_inst = link->link_enc->funcs->get_dig_frontend(link->link_enc); |
68f1a00c | 1094 | |
7f7652ee | 1095 | if (enc_inst == ENGINE_ID_UNKNOWN) |
68f1a00c AK |
1096 | return false; |
1097 | ||
7f7652ee ML |
1098 | for (i = 0; i < dc->res_pool->stream_enc_count; i++) { |
1099 | if (dc->res_pool->stream_enc[i]->id == enc_inst) { | |
93c2340b ML |
1100 | |
1101 | se = dc->res_pool->stream_enc[i]; | |
1102 | ||
7f7652ee ML |
1103 | tg_inst = dc->res_pool->stream_enc[i]->funcs->dig_source_otg( |
1104 | dc->res_pool->stream_enc[i]); | |
1105 | break; | |
1106 | } | |
1107 | } | |
5ec43eda | 1108 | |
7f7652ee ML |
1109 | // tg_inst not found |
1110 | if (i == dc->res_pool->stream_enc_count) | |
1111 | return false; | |
5ec43eda ML |
1112 | |
1113 | if (tg_inst >= dc->res_pool->timing_generator_count) | |
1114 | return false; | |
1115 | ||
1116 | tg = dc->res_pool->timing_generators[tg_inst]; | |
68f1a00c | 1117 | |
93c2340b ML |
1118 | if (!tg->funcs->get_hw_timing) |
1119 | return false; | |
1120 | ||
1121 | if (!tg->funcs->get_hw_timing(tg, &hw_crtc_timing)) | |
1122 | return false; | |
1123 | ||
1124 | if (crtc_timing->h_total != hw_crtc_timing.h_total) | |
1125 | return false; | |
1126 | ||
1127 | if (crtc_timing->h_border_left != hw_crtc_timing.h_border_left) | |
1128 | return false; | |
1129 | ||
1130 | if (crtc_timing->h_addressable != hw_crtc_timing.h_addressable) | |
1131 | return false; | |
1132 | ||
1133 | if (crtc_timing->h_border_right != hw_crtc_timing.h_border_right) | |
1134 | return false; | |
1135 | ||
1136 | if (crtc_timing->h_front_porch != hw_crtc_timing.h_front_porch) | |
1137 | return false; | |
1138 | ||
1139 | if (crtc_timing->h_sync_width != hw_crtc_timing.h_sync_width) | |
68f1a00c AK |
1140 | return false; |
1141 | ||
93c2340b ML |
1142 | if (crtc_timing->v_total != hw_crtc_timing.v_total) |
1143 | return false; | |
1144 | ||
1145 | if (crtc_timing->v_border_top != hw_crtc_timing.v_border_top) | |
1146 | return false; | |
1147 | ||
1148 | if (crtc_timing->v_addressable != hw_crtc_timing.v_addressable) | |
1149 | return false; | |
1150 | ||
1151 | if (crtc_timing->v_border_bottom != hw_crtc_timing.v_border_bottom) | |
1152 | return false; | |
1153 | ||
1154 | if (crtc_timing->v_front_porch != hw_crtc_timing.v_front_porch) | |
1155 | return false; | |
1156 | ||
1157 | if (crtc_timing->v_sync_width != hw_crtc_timing.v_sync_width) | |
68f1a00c AK |
1158 | return false; |
1159 | ||
1160 | if (dc_is_dp_signal(link->connector_signal)) { | |
1161 | unsigned int pix_clk_100hz; | |
1162 | ||
1163 | dc->res_pool->dp_clock_source->funcs->get_pixel_clk_frequency_100hz( | |
1164 | dc->res_pool->dp_clock_source, | |
5ec43eda | 1165 | tg_inst, &pix_clk_100hz); |
68f1a00c AK |
1166 | |
1167 | if (crtc_timing->pix_clk_100hz != pix_clk_100hz) | |
1168 | return false; | |
5ec43eda | 1169 | |
93c2340b ML |
1170 | if (!se->funcs->dp_get_pixel_format) |
1171 | return false; | |
1172 | ||
1173 | if (!se->funcs->dp_get_pixel_format( | |
1174 | se, | |
1175 | &hw_crtc_timing.pixel_encoding, | |
1176 | &hw_crtc_timing.display_color_depth)) | |
1177 | return false; | |
1178 | ||
1179 | if (hw_crtc_timing.display_color_depth != crtc_timing->display_color_depth) | |
1180 | return false; | |
1181 | ||
1182 | if (hw_crtc_timing.pixel_encoding != crtc_timing->pixel_encoding) | |
1183 | return false; | |
68f1a00c AK |
1184 | } |
1185 | ||
1186 | return true; | |
1187 | } | |
1188 | ||
7f5c22d1 VP |
1189 | bool dc_enable_stereo( |
1190 | struct dc *dc, | |
608ac7bb | 1191 | struct dc_state *context, |
0971c40e | 1192 | struct dc_stream_state *streams[], |
7f5c22d1 VP |
1193 | uint8_t stream_count) |
1194 | { | |
1195 | bool ret = true; | |
1196 | int i, j; | |
1197 | struct pipe_ctx *pipe; | |
1663ae1c | 1198 | |
7f5c22d1 VP |
1199 | for (i = 0; i < MAX_PIPES; i++) { |
1200 | if (context != NULL) | |
1201 | pipe = &context->res_ctx.pipe_ctx[i]; | |
1202 | else | |
608ac7bb | 1203 | pipe = &dc->current_state->res_ctx.pipe_ctx[i]; |
7f5c22d1 | 1204 | for (j = 0 ; pipe && j < stream_count; j++) { |
4fa086b9 | 1205 | if (streams[j] && streams[j] == pipe->stream && |
15659045 BL |
1206 | dc->hwss.setup_stereo) |
1207 | dc->hwss.setup_stereo(pipe, dc); | |
7f5c22d1 VP |
1208 | } |
1209 | } | |
1663ae1c | 1210 | |
7f5c22d1 VP |
1211 | return ret; |
1212 | } | |
1213 | ||
fa6ecfc6 AG |
1214 | /* |
1215 | * Applies given context to HW and copy it into current context. | |
1216 | * It's up to the user to release the src context afterwards. | |
1217 | */ | |
62c933f9 | 1218 | static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *context) |
7cf2c840 | 1219 | { |
15659045 | 1220 | struct dc_bios *dcb = dc->ctx->dc_bios; |
7cf2c840 | 1221 | enum dc_status result = DC_ERROR_UNEXPECTED; |
7cf2c840 | 1222 | struct pipe_ctx *pipe; |
3dc780ec | 1223 | int i, k, l; |
0971c40e | 1224 | struct dc_stream_state *dc_streams[MAX_STREAMS] = {0}; |
7cf2c840 | 1225 | |
524bed9a LSL |
1226 | disable_dangling_plane(dc, context); |
1227 | ||
fa6ecfc6 | 1228 | for (i = 0; i < context->stream_count; i++) |
4fa086b9 | 1229 | dc_streams[i] = context->streams[i]; |
7cf2c840 | 1230 | |
25292028 YS |
1231 | if (!dcb->funcs->is_accelerated_mode(dcb)) |
1232 | dc->hwss.enable_accelerated_mode(dc, context); | |
7cf2c840 | 1233 | |
46570f09 AK |
1234 | for (i = 0; i < context->stream_count; i++) { |
1235 | if (context->streams[i]->apply_seamless_boot_optimization) | |
ccce745c | 1236 | dc->optimize_seamless_boot_streams++; |
46570f09 AK |
1237 | } |
1238 | ||
ccce745c | 1239 | if (dc->optimize_seamless_boot_streams == 0) |
46570f09 | 1240 | dc->hwss.prepare_bandwidth(dc, context); |
623a7e96 | 1241 | |
949785b5 TC |
1242 | /* re-program planes for existing stream, in case we need to |
1243 | * free up plane resource for later use | |
1244 | */ | |
009114f6 | 1245 | if (dc->hwss.apply_ctx_for_surface) { |
b6e881c9 DL |
1246 | for (i = 0; i < context->stream_count; i++) { |
1247 | if (context->streams[i]->mode_changed) | |
1248 | continue; | |
009114f6 | 1249 | apply_ctx_interdependent_lock(dc, context, context->streams[i], true); |
b6e881c9 DL |
1250 | dc->hwss.apply_ctx_for_surface( |
1251 | dc, context->streams[i], | |
1252 | context->stream_status[i].plane_count, | |
1253 | context); /* use new pipe config in new context */ | |
009114f6 | 1254 | apply_ctx_interdependent_lock(dc, context, context->streams[i], false); |
bbf5f6c3 | 1255 | dc->hwss.post_unlock_program_front_end(dc, context); |
b6e881c9 | 1256 | } |
009114f6 | 1257 | } |
b674f1ed LSL |
1258 | |
1259 | /* Program hardware */ | |
b674f1ed LSL |
1260 | for (i = 0; i < dc->res_pool->pipe_count; i++) { |
1261 | pipe = &context->res_ctx.pipe_ctx[i]; | |
1262 | dc->hwss.wait_for_mpcc_disconnect(dc, dc->res_pool, pipe); | |
1263 | } | |
1264 | ||
1265 | result = dc->hwss.apply_ctx_to_hw(dc, context); | |
1266 | ||
1267 | if (result != DC_OK) | |
e7f93e90 | 1268 | return result; |
b674f1ed | 1269 | |
70f1476a | 1270 | if (context->stream_count > 1 && !dc->debug.disable_timing_sync) { |
b674f1ed LSL |
1271 | enable_timing_multisync(dc, context); |
1272 | program_timing_sync(dc, context); | |
1273 | } | |
1274 | ||
1275 | /* Program all planes within new context*/ | |
bbf5f6c3 | 1276 | if (dc->hwss.program_front_end_for_ctx) { |
009114f6 | 1277 | dc->hwss.interdependent_update_lock(dc, context, true); |
b6e881c9 | 1278 | dc->hwss.program_front_end_for_ctx(dc, context); |
009114f6 | 1279 | dc->hwss.interdependent_update_lock(dc, context, false); |
bbf5f6c3 AK |
1280 | dc->hwss.post_unlock_program_front_end(dc, context); |
1281 | } | |
7cf2c840 | 1282 | for (i = 0; i < context->stream_count; i++) { |
ceb3dbb4 | 1283 | const struct dc_link *link = context->streams[i]->link; |
7cf2c840 | 1284 | |
27b3f4fc LSL |
1285 | if (!context->streams[i]->mode_changed) |
1286 | continue; | |
1287 | ||
bbf5f6c3 | 1288 | if (dc->hwss.apply_ctx_for_surface) { |
009114f6 | 1289 | apply_ctx_interdependent_lock(dc, context, context->streams[i], true); |
b6e881c9 DL |
1290 | dc->hwss.apply_ctx_for_surface( |
1291 | dc, context->streams[i], | |
1292 | context->stream_status[i].plane_count, | |
1293 | context); | |
009114f6 | 1294 | apply_ctx_interdependent_lock(dc, context, context->streams[i], false); |
bbf5f6c3 AK |
1295 | dc->hwss.post_unlock_program_front_end(dc, context); |
1296 | } | |
13ab1b44 YS |
1297 | |
1298 | /* | |
1299 | * enable stereo | |
1300 | * TODO rework dc_enable_stereo call to work with validation sets? | |
1301 | */ | |
1302 | for (k = 0; k < MAX_PIPES; k++) { | |
1303 | pipe = &context->res_ctx.pipe_ctx[k]; | |
1304 | ||
1305 | for (l = 0 ; pipe && l < context->stream_count; l++) { | |
1306 | if (context->streams[l] && | |
1307 | context->streams[l] == pipe->stream && | |
1308 | dc->hwss.setup_stereo) | |
1309 | dc->hwss.setup_stereo(pipe, dc); | |
7cf2c840 HW |
1310 | } |
1311 | } | |
1312 | ||
ceb3dbb4 | 1313 | CONN_MSG_MODE(link, "{%dx%d, %dx%d@%dKhz}", |
4fa086b9 LSL |
1314 | context->streams[i]->timing.h_addressable, |
1315 | context->streams[i]->timing.v_addressable, | |
1316 | context->streams[i]->timing.h_total, | |
1317 | context->streams[i]->timing.v_total, | |
380604e2 | 1318 | context->streams[i]->timing.pix_clk_100hz / 10); |
7cf2c840 HW |
1319 | } |
1320 | ||
8e437c79 YS |
1321 | dc_enable_stereo(dc, context, dc_streams, context->stream_count); |
1322 | ||
ccce745c | 1323 | if (dc->optimize_seamless_boot_streams == 0) { |
6b5d7730 NA |
1324 | /* Must wait for no flips to be pending before doing optimize bw */ |
1325 | wait_for_no_pipes_pending(dc, context); | |
1326 | /* pplib is notified if disp_num changed */ | |
1327 | dc->hwss.optimize_bandwidth(dc, context); | |
1328 | } | |
f2988e67 | 1329 | |
d8d2f174 NK |
1330 | for (i = 0; i < context->stream_count; i++) |
1331 | context->streams[i]->mode_changed = false; | |
1332 | ||
608ac7bb | 1333 | dc_release_state(dc->current_state); |
8a76708e | 1334 | |
608ac7bb | 1335 | dc->current_state = context; |
7cf2c840 | 1336 | |
608ac7bb | 1337 | dc_retain_state(dc->current_state); |
60bf1860 | 1338 | |
62c933f9 | 1339 | return result; |
7cf2c840 HW |
1340 | } |
1341 | ||
608ac7bb | 1342 | bool dc_commit_state(struct dc *dc, struct dc_state *context) |
fa6ecfc6 AG |
1343 | { |
1344 | enum dc_status result = DC_ERROR_UNEXPECTED; | |
fa6ecfc6 AG |
1345 | int i; |
1346 | ||
15659045 | 1347 | if (false == context_changed(dc, context)) |
fa6ecfc6 AG |
1348 | return DC_OK; |
1349 | ||
1296423b | 1350 | DC_LOG_DC("%s: %d streams\n", |
fa6ecfc6 AG |
1351 | __func__, context->stream_count); |
1352 | ||
1353 | for (i = 0; i < context->stream_count; i++) { | |
0971c40e | 1354 | struct dc_stream_state *stream = context->streams[i]; |
fa6ecfc6 | 1355 | |
e1cb3e48 | 1356 | dc_stream_log(dc, stream); |
fa6ecfc6 AG |
1357 | } |
1358 | ||
608ac7bb | 1359 | result = dc_commit_state_no_check(dc, context); |
fa6ecfc6 AG |
1360 | |
1361 | return (result == DC_OK); | |
1362 | } | |
1363 | ||
9941b812 YS |
1364 | static bool is_flip_pending_in_pipes(struct dc *dc, struct dc_state *context) |
1365 | { | |
1366 | int i; | |
1367 | struct pipe_ctx *pipe; | |
1368 | ||
1369 | for (i = 0; i < MAX_PIPES; i++) { | |
1370 | pipe = &context->res_ctx.pipe_ctx[i]; | |
1371 | ||
1372 | if (!pipe->plane_state) | |
1373 | continue; | |
1374 | ||
1375 | /* Must set to false to start with, due to OR in update function */ | |
1376 | pipe->plane_state->status.is_flip_pending = false; | |
1377 | dc->hwss.update_pending_status(pipe); | |
1378 | if (pipe->plane_state->status.is_flip_pending) | |
1379 | return true; | |
1380 | } | |
1381 | return false; | |
1382 | } | |
1383 | ||
ab2541b6 | 1384 | bool dc_post_update_surfaces_to_stream(struct dc *dc) |
4562236b | 1385 | { |
4562236b | 1386 | int i; |
608ac7bb | 1387 | struct dc_state *context = dc->current_state; |
4562236b | 1388 | |
0aa63a33 | 1389 | if ((!dc->optimized_required) || dc->optimize_seamless_boot_streams > 0) |
e6d24213 ML |
1390 | return true; |
1391 | ||
4562236b | 1392 | post_surface_trace(dc); |
de37e273 | 1393 | |
9941b812 YS |
1394 | if (is_flip_pending_in_pipes(dc, context)) |
1395 | return true; | |
1396 | ||
15659045 | 1397 | for (i = 0; i < dc->res_pool->pipe_count; i++) |
e6c258cb YS |
1398 | if (context->res_ctx.pipe_ctx[i].stream == NULL || |
1399 | context->res_ctx.pipe_ctx[i].plane_state == NULL) { | |
1400 | context->res_ctx.pipe_ctx[i].pipe_idx = i; | |
7f914a62 | 1401 | dc->hwss.disable_plane(dc, &context->res_ctx.pipe_ctx[i]); |
e6c258cb | 1402 | } |
4562236b | 1403 | |
9566b675 | 1404 | dc->hwss.optimize_bandwidth(dc, context); |
4c631826 | 1405 | |
0aa63a33 | 1406 | dc->optimized_required = false; |
4c631826 YS |
1407 | dc->wm_optimized_required = false; |
1408 | ||
de37e273 | 1409 | return true; |
4562236b HW |
1410 | } |
1411 | ||
813d20dc | 1412 | struct dc_state *dc_create_state(struct dc *dc) |
81c90ec0 | 1413 | { |
44f3dd09 AD |
1414 | struct dc_state *context = kvzalloc(sizeof(struct dc_state), |
1415 | GFP_KERNEL); | |
81c90ec0 LSL |
1416 | |
1417 | if (!context) | |
1418 | return NULL; | |
813d20dc AW |
1419 | /* Each context must have their own instance of VBA and in order to |
1420 | * initialize and obtain IP and SOC the base DML instance from DC is | |
1421 | * initially copied into every context | |
1422 | */ | |
b86a1aa3 | 1423 | #ifdef CONFIG_DRM_AMD_DC_DCN |
813d20dc | 1424 | memcpy(&context->bw_ctx.dml, &dc->dml, sizeof(struct display_mode_lib)); |
805ab8f7 | 1425 | #endif |
81c90ec0 | 1426 | |
8ee5702a | 1427 | kref_init(&context->refcount); |
813d20dc | 1428 | |
81c90ec0 LSL |
1429 | return context; |
1430 | } | |
1431 | ||
813d20dc AW |
1432 | struct dc_state *dc_copy_state(struct dc_state *src_ctx) |
1433 | { | |
1434 | int i, j; | |
44f3dd09 | 1435 | struct dc_state *new_ctx = kvmalloc(sizeof(struct dc_state), GFP_KERNEL); |
813d20dc AW |
1436 | |
1437 | if (!new_ctx) | |
1438 | return NULL; | |
44f3dd09 | 1439 | memcpy(new_ctx, src_ctx, sizeof(struct dc_state)); |
813d20dc | 1440 | |
813d20dc AW |
1441 | for (i = 0; i < MAX_PIPES; i++) { |
1442 | struct pipe_ctx *cur_pipe = &new_ctx->res_ctx.pipe_ctx[i]; | |
1443 | ||
1444 | if (cur_pipe->top_pipe) | |
1445 | cur_pipe->top_pipe = &new_ctx->res_ctx.pipe_ctx[cur_pipe->top_pipe->pipe_idx]; | |
1446 | ||
1447 | if (cur_pipe->bottom_pipe) | |
1448 | cur_pipe->bottom_pipe = &new_ctx->res_ctx.pipe_ctx[cur_pipe->bottom_pipe->pipe_idx]; | |
1449 | ||
24d01c9b DL |
1450 | if (cur_pipe->prev_odm_pipe) |
1451 | cur_pipe->prev_odm_pipe = &new_ctx->res_ctx.pipe_ctx[cur_pipe->prev_odm_pipe->pipe_idx]; | |
1452 | ||
1453 | if (cur_pipe->next_odm_pipe) | |
1454 | cur_pipe->next_odm_pipe = &new_ctx->res_ctx.pipe_ctx[cur_pipe->next_odm_pipe->pipe_idx]; | |
1455 | ||
813d20dc AW |
1456 | } |
1457 | ||
1458 | for (i = 0; i < new_ctx->stream_count; i++) { | |
1459 | dc_stream_retain(new_ctx->streams[i]); | |
1460 | for (j = 0; j < new_ctx->stream_status[i].plane_count; j++) | |
1461 | dc_plane_state_retain( | |
1462 | new_ctx->stream_status[i].plane_states[j]); | |
1463 | } | |
1464 | ||
1465 | kref_init(&new_ctx->refcount); | |
1466 | ||
1467 | return new_ctx; | |
1468 | } | |
1469 | ||
608ac7bb | 1470 | void dc_retain_state(struct dc_state *context) |
8a76708e | 1471 | { |
8ee5702a | 1472 | kref_get(&context->refcount); |
8a76708e AG |
1473 | } |
1474 | ||
8ee5702a | 1475 | static void dc_state_free(struct kref *kref) |
8a76708e | 1476 | { |
8ee5702a DA |
1477 | struct dc_state *context = container_of(kref, struct dc_state, refcount); |
1478 | dc_resource_state_destruct(context); | |
44f3dd09 | 1479 | kvfree(context); |
8ee5702a | 1480 | } |
8a76708e | 1481 | |
8ee5702a DA |
1482 | void dc_release_state(struct dc_state *context) |
1483 | { | |
1484 | kref_put(&context->refcount, dc_state_free); | |
8a76708e AG |
1485 | } |
1486 | ||
c2cd9d04 ML |
1487 | bool dc_set_generic_gpio_for_stereo(bool enable, |
1488 | struct gpio_service *gpio_service) | |
1489 | { | |
1490 | enum gpio_result gpio_result = GPIO_RESULT_NON_SPECIFIC_ERROR; | |
1491 | struct gpio_pin_info pin_info; | |
1492 | struct gpio *generic; | |
1493 | struct gpio_generic_mux_config *config = kzalloc(sizeof(struct gpio_generic_mux_config), | |
1494 | GFP_KERNEL); | |
1495 | ||
87abff77 CIK |
1496 | if (!config) |
1497 | return false; | |
c2cd9d04 ML |
1498 | pin_info = dal_gpio_get_generic_pin_info(gpio_service, GPIO_ID_GENERIC, 0); |
1499 | ||
1500 | if (pin_info.mask == 0xFFFFFFFF || pin_info.offset == 0xFFFFFFFF) { | |
1501 | kfree(config); | |
1502 | return false; | |
1503 | } else { | |
1504 | generic = dal_gpio_service_create_generic_mux( | |
1505 | gpio_service, | |
1506 | pin_info.offset, | |
1507 | pin_info.mask); | |
1508 | } | |
1509 | ||
1510 | if (!generic) { | |
1511 | kfree(config); | |
1512 | return false; | |
1513 | } | |
1514 | ||
1515 | gpio_result = dal_gpio_open(generic, GPIO_MODE_OUTPUT); | |
1516 | ||
1517 | config->enable_output_from_mux = enable; | |
1518 | config->mux_select = GPIO_SIGNAL_SOURCE_PASS_THROUGH_STEREO_SYNC; | |
1519 | ||
1520 | if (gpio_result == GPIO_RESULT_OK) | |
1521 | gpio_result = dal_mux_setup_config(generic, config); | |
1522 | ||
1523 | if (gpio_result == GPIO_RESULT_OK) { | |
1524 | dal_gpio_close(generic); | |
1525 | dal_gpio_destroy_generic_mux(&generic); | |
1526 | kfree(config); | |
1527 | return true; | |
1528 | } else { | |
1529 | dal_gpio_close(generic); | |
1530 | dal_gpio_destroy_generic_mux(&generic); | |
1531 | kfree(config); | |
1532 | return false; | |
1533 | } | |
1534 | } | |
1535 | ||
e72f0acd | 1536 | static bool is_surface_in_context( |
608ac7bb | 1537 | const struct dc_state *context, |
3be5262e | 1538 | const struct dc_plane_state *plane_state) |
4562236b | 1539 | { |
e72f0acd | 1540 | int j; |
4562236b | 1541 | |
a2b8659d | 1542 | for (j = 0; j < MAX_PIPES; j++) { |
e72f0acd | 1543 | const struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j]; |
4562236b | 1544 | |
3be5262e | 1545 | if (plane_state == pipe_ctx->plane_state) { |
e72f0acd TC |
1546 | return true; |
1547 | } | |
1548 | } | |
4562236b | 1549 | |
e72f0acd TC |
1550 | return false; |
1551 | } | |
4562236b | 1552 | |
9f89df7d | 1553 | static enum surface_update_type get_plane_info_update_type(const struct dc_surface_update *u) |
5869b0f6 | 1554 | { |
19ec320e | 1555 | union surface_update_flags *update_flags = &u->surface->update_flags; |
aa5fdb1a | 1556 | enum surface_update_type update_type = UPDATE_TYPE_FAST; |
5869b0f6 LE |
1557 | |
1558 | if (!u->plane_info) | |
1559 | return UPDATE_TYPE_FAST; | |
1560 | ||
aa5fdb1a | 1561 | if (u->plane_info->color_space != u->surface->color_space) { |
19ec320e | 1562 | update_flags->bits.color_space_change = 1; |
aa5fdb1a NK |
1563 | elevate_update_type(&update_type, UPDATE_TYPE_MED); |
1564 | } | |
80b4c5a8 | 1565 | |
aa5fdb1a | 1566 | if (u->plane_info->horizontal_mirror != u->surface->horizontal_mirror) { |
19ec320e | 1567 | update_flags->bits.horizontal_mirror_change = 1; |
aa5fdb1a NK |
1568 | elevate_update_type(&update_type, UPDATE_TYPE_MED); |
1569 | } | |
5869b0f6 | 1570 | |
aa5fdb1a | 1571 | if (u->plane_info->rotation != u->surface->rotation) { |
19ec320e | 1572 | update_flags->bits.rotation_change = 1; |
aa5fdb1a NK |
1573 | elevate_update_type(&update_type, UPDATE_TYPE_FULL); |
1574 | } | |
19ec320e | 1575 | |
aa5fdb1a | 1576 | if (u->plane_info->format != u->surface->format) { |
3aa0cadd | 1577 | update_flags->bits.pixel_format_change = 1; |
aa5fdb1a NK |
1578 | elevate_update_type(&update_type, UPDATE_TYPE_FULL); |
1579 | } | |
3aa0cadd | 1580 | |
aa5fdb1a | 1581 | if (u->plane_info->stereo_format != u->surface->stereo_format) { |
19ec320e | 1582 | update_flags->bits.stereo_format_change = 1; |
aa5fdb1a NK |
1583 | elevate_update_type(&update_type, UPDATE_TYPE_FULL); |
1584 | } | |
19ec320e | 1585 | |
aa5fdb1a | 1586 | if (u->plane_info->per_pixel_alpha != u->surface->per_pixel_alpha) { |
19ec320e | 1587 | update_flags->bits.per_pixel_alpha_change = 1; |
aa5fdb1a NK |
1588 | elevate_update_type(&update_type, UPDATE_TYPE_MED); |
1589 | } | |
5869b0f6 | 1590 | |
aa5fdb1a | 1591 | if (u->plane_info->global_alpha_value != u->surface->global_alpha_value) { |
94a4ffd1 | 1592 | update_flags->bits.global_alpha_change = 1; |
aa5fdb1a NK |
1593 | elevate_update_type(&update_type, UPDATE_TYPE_MED); |
1594 | } | |
94a4ffd1 | 1595 | |
e9dd9223 | 1596 | if (u->plane_info->dcc.enable != u->surface->dcc.enable |
12e2b2d4 DL |
1597 | || u->plane_info->dcc.independent_64b_blks != u->surface->dcc.independent_64b_blks |
1598 | || u->plane_info->dcc.meta_pitch != u->surface->dcc.meta_pitch) { | |
e9dd9223 | 1599 | update_flags->bits.dcc_change = 1; |
aa5fdb1a NK |
1600 | elevate_update_type(&update_type, UPDATE_TYPE_MED); |
1601 | } | |
e9dd9223 | 1602 | |
74eac5f3 | 1603 | if (resource_pixel_format_to_bpp(u->plane_info->format) != |
aa5fdb1a | 1604 | resource_pixel_format_to_bpp(u->surface->format)) { |
4b7e7e2b SC |
1605 | /* different bytes per element will require full bandwidth |
1606 | * and DML calculation | |
1607 | */ | |
19ec320e | 1608 | update_flags->bits.bpp_change = 1; |
aa5fdb1a NK |
1609 | elevate_update_type(&update_type, UPDATE_TYPE_FULL); |
1610 | } | |
4b7e7e2b | 1611 | |
12e2b2d4 | 1612 | if (u->plane_info->plane_size.surface_pitch != u->surface->plane_size.surface_pitch |
12e2b2d4 | 1613 | || u->plane_info->plane_size.chroma_pitch != u->surface->plane_size.chroma_pitch) { |
ebd084cd | 1614 | update_flags->bits.plane_size_change = 1; |
aa5fdb1a NK |
1615 | elevate_update_type(&update_type, UPDATE_TYPE_MED); |
1616 | } | |
ebd084cd LH |
1617 | |
1618 | ||
4b7e7e2b SC |
1619 | if (memcmp(&u->plane_info->tiling_info, &u->surface->tiling_info, |
1620 | sizeof(union dc_tiling_info)) != 0) { | |
19ec320e | 1621 | update_flags->bits.swizzle_change = 1; |
aa5fdb1a NK |
1622 | elevate_update_type(&update_type, UPDATE_TYPE_MED); |
1623 | ||
4b7e7e2b SC |
1624 | /* todo: below are HW dependent, we should add a hook to |
1625 | * DCE/N resource and validated there. | |
1626 | */ | |
aa5fdb1a | 1627 | if (u->plane_info->tiling_info.gfx9.swizzle != DC_SW_LINEAR) { |
4b7e7e2b SC |
1628 | /* swizzled mode requires RQ to be setup properly, |
1629 | * thus need to run DML to calculate RQ settings | |
1630 | */ | |
19ec320e | 1631 | update_flags->bits.bandwidth_change = 1; |
aa5fdb1a NK |
1632 | elevate_update_type(&update_type, UPDATE_TYPE_FULL); |
1633 | } | |
4b7e7e2b SC |
1634 | } |
1635 | ||
aa5fdb1a NK |
1636 | /* This should be UPDATE_TYPE_FAST if nothing has changed. */ |
1637 | return update_type; | |
5869b0f6 LE |
1638 | } |
1639 | ||
19ec320e | 1640 | static enum surface_update_type get_scaling_info_update_type( |
5869b0f6 LE |
1641 | const struct dc_surface_update *u) |
1642 | { | |
19ec320e AJ |
1643 | union surface_update_flags *update_flags = &u->surface->update_flags; |
1644 | ||
5869b0f6 LE |
1645 | if (!u->scaling_info) |
1646 | return UPDATE_TYPE_FAST; | |
1647 | ||
5fd9f8a1 | 1648 | if (u->scaling_info->clip_rect.width != u->surface->clip_rect.width |
b71a0618 DL |
1649 | || u->scaling_info->clip_rect.height != u->surface->clip_rect.height |
1650 | || u->scaling_info->dst_rect.width != u->surface->dst_rect.width | |
00ada9d1 RA |
1651 | || u->scaling_info->dst_rect.height != u->surface->dst_rect.height |
1652 | || u->scaling_info->scaling_quality.integer_scaling != | |
1653 | u->surface->scaling_quality.integer_scaling | |
1654 | ) { | |
19ec320e AJ |
1655 | update_flags->bits.scaling_change = 1; |
1656 | ||
1657 | if ((u->scaling_info->dst_rect.width < u->surface->dst_rect.width | |
1658 | || u->scaling_info->dst_rect.height < u->surface->dst_rect.height) | |
1659 | && (u->scaling_info->dst_rect.width < u->surface->src_rect.width | |
1660 | || u->scaling_info->dst_rect.height < u->surface->src_rect.height)) | |
1661 | /* Making dst rect smaller requires a bandwidth change */ | |
1662 | update_flags->bits.bandwidth_change = 1; | |
1663 | } | |
5869b0f6 | 1664 | |
5fd9f8a1 AJ |
1665 | if (u->scaling_info->src_rect.width != u->surface->src_rect.width |
1666 | || u->scaling_info->src_rect.height != u->surface->src_rect.height) { | |
1667 | ||
19ec320e | 1668 | update_flags->bits.scaling_change = 1; |
5fd9f8a1 | 1669 | if (u->scaling_info->src_rect.width > u->surface->src_rect.width |
8d5bc3a5 | 1670 | || u->scaling_info->src_rect.height > u->surface->src_rect.height) |
19ec320e AJ |
1671 | /* Making src rect bigger requires a bandwidth change */ |
1672 | update_flags->bits.clock_change = 1; | |
5fd9f8a1 AJ |
1673 | } |
1674 | ||
b71a0618 DL |
1675 | if (u->scaling_info->src_rect.x != u->surface->src_rect.x |
1676 | || u->scaling_info->src_rect.y != u->surface->src_rect.y | |
1677 | || u->scaling_info->clip_rect.x != u->surface->clip_rect.x | |
1678 | || u->scaling_info->clip_rect.y != u->surface->clip_rect.y | |
1679 | || u->scaling_info->dst_rect.x != u->surface->dst_rect.x | |
1680 | || u->scaling_info->dst_rect.y != u->surface->dst_rect.y) | |
19ec320e AJ |
1681 | update_flags->bits.position_change = 1; |
1682 | ||
1683 | if (update_flags->bits.clock_change | |
8d5bc3a5 AC |
1684 | || update_flags->bits.bandwidth_change |
1685 | || update_flags->bits.scaling_change) | |
19ec320e AJ |
1686 | return UPDATE_TYPE_FULL; |
1687 | ||
8d5bc3a5 | 1688 | if (update_flags->bits.position_change) |
b71a0618 | 1689 | return UPDATE_TYPE_MED; |
5869b0f6 LE |
1690 | |
1691 | return UPDATE_TYPE_FAST; | |
1692 | } | |
4562236b | 1693 | |
9f89df7d | 1694 | static enum surface_update_type det_surface_update(const struct dc *dc, |
19ec320e | 1695 | const struct dc_surface_update *u) |
e72f0acd | 1696 | { |
608ac7bb | 1697 | const struct dc_state *context = dc->current_state; |
19ec320e | 1698 | enum surface_update_type type; |
5869b0f6 | 1699 | enum surface_update_type overall_type = UPDATE_TYPE_FAST; |
19ec320e AJ |
1700 | union surface_update_flags *update_flags = &u->surface->update_flags; |
1701 | ||
ad141db9 DL |
1702 | if (u->flip_addr) |
1703 | update_flags->bits.addr_update = 1; | |
1704 | ||
b6e881c9 DL |
1705 | if (!is_surface_in_context(context, u->surface) || u->surface->force_full_update) { |
1706 | update_flags->raw = 0xFFFFFFFF; | |
e72f0acd | 1707 | return UPDATE_TYPE_FULL; |
19ec320e | 1708 | } |
4562236b | 1709 | |
b6e881c9 | 1710 | update_flags->raw = 0; // Reset all flags |
c238bfe0 | 1711 | |
9f89df7d | 1712 | type = get_plane_info_update_type(u); |
19ec320e | 1713 | elevate_update_type(&overall_type, type); |
5869b0f6 LE |
1714 | |
1715 | type = get_scaling_info_update_type(u); | |
19ec320e AJ |
1716 | elevate_update_type(&overall_type, type); |
1717 | ||
aa5fdb1a NK |
1718 | if (u->flip_addr) |
1719 | update_flags->bits.addr_update = 1; | |
1720 | ||
19ec320e | 1721 | if (u->in_transfer_func) |
405c50a0 | 1722 | update_flags->bits.in_transfer_func_change = 1; |
19ec320e AJ |
1723 | |
1724 | if (u->input_csc_color_matrix) | |
1725 | update_flags->bits.input_csc_change = 1; | |
5869b0f6 | 1726 | |
35ad2254 AK |
1727 | if (u->coeff_reduction_factor) |
1728 | update_flags->bits.coeff_reduction_change = 1; | |
1729 | ||
5c41c023 SW |
1730 | if (u->gamut_remap_matrix) |
1731 | update_flags->bits.gamut_remap_change = 1; | |
1732 | ||
30049754 S |
1733 | if (u->gamma) { |
1734 | enum surface_pixel_format format = SURFACE_PIXEL_FORMAT_GRPH_BEGIN; | |
1735 | ||
1736 | if (u->plane_info) | |
1737 | format = u->plane_info->format; | |
1738 | else if (u->surface) | |
1739 | format = u->surface->format; | |
1740 | ||
1741 | if (dce_use_lut(format)) | |
1742 | update_flags->bits.gamma_change = 1; | |
1743 | } | |
1744 | ||
46250a0c MS |
1745 | if (u->hdr_mult.value) |
1746 | if (u->hdr_mult.value != u->surface->hdr_mult.value) { | |
1747 | update_flags->bits.hdr_mult = 1; | |
1748 | elevate_update_type(&overall_type, UPDATE_TYPE_MED); | |
1749 | } | |
1750 | ||
35ad2254 | 1751 | if (update_flags->bits.in_transfer_func_change) { |
19ec320e AJ |
1752 | type = UPDATE_TYPE_MED; |
1753 | elevate_update_type(&overall_type, type); | |
5869b0f6 | 1754 | } |
1c4e6bce | 1755 | |
35ad2254 | 1756 | if (update_flags->bits.input_csc_change |
30049754 | 1757 | || update_flags->bits.coeff_reduction_change |
5c41c023 SW |
1758 | || update_flags->bits.gamma_change |
1759 | || update_flags->bits.gamut_remap_change) { | |
35ad2254 AK |
1760 | type = UPDATE_TYPE_FULL; |
1761 | elevate_update_type(&overall_type, type); | |
1762 | } | |
1763 | ||
5869b0f6 | 1764 | return overall_type; |
e72f0acd | 1765 | } |
4562236b | 1766 | |
27b89313 | 1767 | static enum surface_update_type check_update_surfaces_for_stream( |
5869b0f6 | 1768 | struct dc *dc, |
e72f0acd TC |
1769 | struct dc_surface_update *updates, |
1770 | int surface_count, | |
ee8f63e1 | 1771 | struct dc_stream_update *stream_update, |
e72f0acd TC |
1772 | const struct dc_stream_status *stream_status) |
1773 | { | |
1774 | int i; | |
1775 | enum surface_update_type overall_type = UPDATE_TYPE_FAST; | |
1776 | ||
3be5262e | 1777 | if (stream_status == NULL || stream_status->plane_count != surface_count) |
b6e881c9 | 1778 | overall_type = UPDATE_TYPE_FULL; |
e72f0acd | 1779 | |
98e6436d AK |
1780 | /* some stream updates require passive update */ |
1781 | if (stream_update) { | |
b6e881c9 | 1782 | union stream_update_flags *su_flags = &stream_update->stream->update_flags; |
98e6436d | 1783 | |
b6e881c9 | 1784 | if ((stream_update->src.height != 0 && stream_update->src.width != 0) || |
00ada9d1 RA |
1785 | (stream_update->dst.height != 0 && stream_update->dst.width != 0) || |
1786 | stream_update->integer_scaling_update) | |
b6e881c9 | 1787 | su_flags->bits.scaling = 1; |
98e6436d AK |
1788 | |
1789 | if (stream_update->out_transfer_func) | |
b6e881c9 | 1790 | su_flags->bits.out_tf = 1; |
98e6436d | 1791 | |
98e6436d | 1792 | if (stream_update->abm_level) |
b6e881c9 | 1793 | su_flags->bits.abm_level = 1; |
1e7e86c4 ST |
1794 | |
1795 | if (stream_update->dpms_off) | |
b6e881c9 DL |
1796 | su_flags->bits.dpms_off = 1; |
1797 | ||
1798 | if (stream_update->gamut_remap) | |
1799 | su_flags->bits.gamut_remap = 1; | |
c3ec8ba5 | 1800 | |
c3ec8ba5 | 1801 | if (stream_update->wb_update) |
b6e881c9 | 1802 | su_flags->bits.wb_update = 1; |
acdac228 AK |
1803 | |
1804 | if (stream_update->dsc_config) | |
1805 | su_flags->bits.dsc_changed = 1; | |
1806 | ||
b6e881c9 DL |
1807 | if (su_flags->raw != 0) |
1808 | overall_type = UPDATE_TYPE_FULL; | |
1809 | ||
1810 | if (stream_update->output_csc_transform || stream_update->output_color_space) | |
1811 | su_flags->bits.out_csc = 1; | |
98e6436d | 1812 | } |
ee8f63e1 | 1813 | |
e72f0acd TC |
1814 | for (i = 0 ; i < surface_count; i++) { |
1815 | enum surface_update_type type = | |
9f89df7d | 1816 | det_surface_update(dc, &updates[i]); |
e72f0acd | 1817 | |
19ec320e | 1818 | elevate_update_type(&overall_type, type); |
4562236b HW |
1819 | } |
1820 | ||
e72f0acd TC |
1821 | return overall_type; |
1822 | } | |
4562236b | 1823 | |
2119aa17 DF |
1824 | /** |
1825 | * dc_check_update_surfaces_for_stream() - Determine update type (fast, med, or full) | |
1826 | * | |
1827 | * See :c:type:`enum surface_update_type <surface_update_type>` for explanation of update types | |
1828 | */ | |
27b89313 AJ |
1829 | enum surface_update_type dc_check_update_surfaces_for_stream( |
1830 | struct dc *dc, | |
1831 | struct dc_surface_update *updates, | |
1832 | int surface_count, | |
1833 | struct dc_stream_update *stream_update, | |
1834 | const struct dc_stream_status *stream_status) | |
1835 | { | |
1836 | int i; | |
1837 | enum surface_update_type type; | |
1838 | ||
b6e881c9 DL |
1839 | if (stream_update) |
1840 | stream_update->stream->update_flags.raw = 0; | |
27b89313 AJ |
1841 | for (i = 0; i < surface_count; i++) |
1842 | updates[i].surface->update_flags.raw = 0; | |
1843 | ||
1844 | type = check_update_surfaces_for_stream(dc, updates, surface_count, stream_update, stream_status); | |
b6e881c9 | 1845 | if (type == UPDATE_TYPE_FULL) { |
acdac228 AK |
1846 | if (stream_update) { |
1847 | uint32_t dsc_changed = stream_update->stream->update_flags.bits.dsc_changed; | |
b6e881c9 | 1848 | stream_update->stream->update_flags.raw = 0xFFFFFFFF; |
acdac228 AK |
1849 | stream_update->stream->update_flags.bits.dsc_changed = dsc_changed; |
1850 | } | |
27b89313 | 1851 | for (i = 0; i < surface_count; i++) |
1402c605 | 1852 | updates[i].surface->update_flags.raw = 0xFFFFFFFF; |
b6e881c9 | 1853 | } |
27b89313 | 1854 | |
deb79818 JL |
1855 | if (type == UPDATE_TYPE_FAST) { |
1856 | // If there's an available clock comparator, we use that. | |
1857 | if (dc->clk_mgr->funcs->are_clock_states_equal) { | |
1858 | if (!dc->clk_mgr->funcs->are_clock_states_equal(&dc->clk_mgr->clks, &dc->current_state->bw_ctx.bw.dcn.clk)) | |
0aa63a33 | 1859 | dc->optimized_required = true; |
deb79818 JL |
1860 | // Else we fallback to mem compare. |
1861 | } else if (memcmp(&dc->current_state->bw_ctx.bw.dcn.clk, &dc->clk_mgr->clks, offsetof(struct dc_clocks, prev_p_state_change_support)) != 0) { | |
0aa63a33 | 1862 | dc->optimized_required = true; |
6dbebf4d JA |
1863 | } |
1864 | ||
1865 | dc->optimized_required |= dc->wm_optimized_required; | |
deb79818 | 1866 | } |
3a4d180d | 1867 | |
27b89313 AJ |
1868 | return type; |
1869 | } | |
1870 | ||
3e9ad616 | 1871 | static struct dc_stream_status *stream_get_status( |
608ac7bb | 1872 | struct dc_state *ctx, |
3e9ad616 EY |
1873 | struct dc_stream_state *stream) |
1874 | { | |
1875 | uint8_t i; | |
1876 | ||
1877 | for (i = 0; i < ctx->stream_count; i++) { | |
1878 | if (stream == ctx->streams[i]) { | |
1879 | return &ctx->stream_status[i]; | |
1880 | } | |
1881 | } | |
1882 | ||
1883 | return NULL; | |
1884 | } | |
1885 | ||
b8a1d69c | 1886 | static const enum surface_update_type update_surface_trace_level = UPDATE_TYPE_FULL; |
4562236b | 1887 | |
f3e3698d NK |
1888 | static void copy_surface_update_to_plane( |
1889 | struct dc_plane_state *surface, | |
1890 | struct dc_surface_update *srf_update) | |
1891 | { | |
1892 | if (srf_update->flip_addr) { | |
1893 | surface->address = srf_update->flip_addr->address; | |
1894 | surface->flip_immediate = | |
1895 | srf_update->flip_addr->flip_immediate; | |
1896 | surface->time.time_elapsed_in_us[surface->time.index] = | |
1897 | srf_update->flip_addr->flip_timestamp_in_us - | |
1898 | surface->time.prev_update_time_in_us; | |
1899 | surface->time.prev_update_time_in_us = | |
1900 | srf_update->flip_addr->flip_timestamp_in_us; | |
1901 | surface->time.index++; | |
1902 | if (surface->time.index >= DC_PLANE_UPDATE_TIMES_MAX) | |
1903 | surface->time.index = 0; | |
c803bb4e NK |
1904 | |
1905 | surface->triplebuffer_flips = srf_update->flip_addr->triplebuffer_flips; | |
f3e3698d NK |
1906 | } |
1907 | ||
1908 | if (srf_update->scaling_info) { | |
1909 | surface->scaling_quality = | |
1910 | srf_update->scaling_info->scaling_quality; | |
1911 | surface->dst_rect = | |
1912 | srf_update->scaling_info->dst_rect; | |
1913 | surface->src_rect = | |
1914 | srf_update->scaling_info->src_rect; | |
1915 | surface->clip_rect = | |
1916 | srf_update->scaling_info->clip_rect; | |
1917 | } | |
1918 | ||
1919 | if (srf_update->plane_info) { | |
1920 | surface->color_space = | |
1921 | srf_update->plane_info->color_space; | |
1922 | surface->format = | |
1923 | srf_update->plane_info->format; | |
1924 | surface->plane_size = | |
1925 | srf_update->plane_info->plane_size; | |
1926 | surface->rotation = | |
1927 | srf_update->plane_info->rotation; | |
1928 | surface->horizontal_mirror = | |
1929 | srf_update->plane_info->horizontal_mirror; | |
1930 | surface->stereo_format = | |
1931 | srf_update->plane_info->stereo_format; | |
1932 | surface->tiling_info = | |
1933 | srf_update->plane_info->tiling_info; | |
1934 | surface->visible = | |
1935 | srf_update->plane_info->visible; | |
1936 | surface->per_pixel_alpha = | |
1937 | srf_update->plane_info->per_pixel_alpha; | |
1938 | surface->global_alpha = | |
1939 | srf_update->plane_info->global_alpha; | |
1940 | surface->global_alpha_value = | |
1941 | srf_update->plane_info->global_alpha_value; | |
1942 | surface->dcc = | |
1943 | srf_update->plane_info->dcc; | |
6d83a32d MS |
1944 | surface->layer_index = |
1945 | srf_update->plane_info->layer_index; | |
f3e3698d NK |
1946 | } |
1947 | ||
1948 | if (srf_update->gamma && | |
1949 | (surface->gamma_correction != | |
1950 | srf_update->gamma)) { | |
1951 | memcpy(&surface->gamma_correction->entries, | |
1952 | &srf_update->gamma->entries, | |
1953 | sizeof(struct dc_gamma_entries)); | |
1954 | surface->gamma_correction->is_identity = | |
1955 | srf_update->gamma->is_identity; | |
1956 | surface->gamma_correction->num_entries = | |
1957 | srf_update->gamma->num_entries; | |
1958 | surface->gamma_correction->type = | |
1959 | srf_update->gamma->type; | |
1960 | } | |
1961 | ||
1962 | if (srf_update->in_transfer_func && | |
1963 | (surface->in_transfer_func != | |
1964 | srf_update->in_transfer_func)) { | |
1965 | surface->in_transfer_func->sdr_ref_white_level = | |
1966 | srf_update->in_transfer_func->sdr_ref_white_level; | |
1967 | surface->in_transfer_func->tf = | |
1968 | srf_update->in_transfer_func->tf; | |
1969 | surface->in_transfer_func->type = | |
1970 | srf_update->in_transfer_func->type; | |
1971 | memcpy(&surface->in_transfer_func->tf_pts, | |
1972 | &srf_update->in_transfer_func->tf_pts, | |
1973 | sizeof(struct dc_transfer_func_distributed_points)); | |
1974 | } | |
1975 | ||
6fbefb84 HW |
1976 | if (srf_update->func_shaper && |
1977 | (surface->in_shaper_func != | |
1978 | srf_update->func_shaper)) | |
1979 | memcpy(surface->in_shaper_func, srf_update->func_shaper, | |
1980 | sizeof(*surface->in_shaper_func)); | |
1981 | ||
1982 | if (srf_update->lut3d_func && | |
1983 | (surface->lut3d_func != | |
1984 | srf_update->lut3d_func)) | |
1985 | memcpy(surface->lut3d_func, srf_update->lut3d_func, | |
1986 | sizeof(*surface->lut3d_func)); | |
f99b6f4f | 1987 | |
46250a0c MS |
1988 | if (srf_update->hdr_mult.value) |
1989 | surface->hdr_mult = | |
1990 | srf_update->hdr_mult; | |
1991 | ||
f99b6f4f VP |
1992 | if (srf_update->blend_tf && |
1993 | (surface->blend_tf != | |
1994 | srf_update->blend_tf)) | |
1995 | memcpy(surface->blend_tf, srf_update->blend_tf, | |
1996 | sizeof(*surface->blend_tf)); | |
1997 | ||
f3e3698d NK |
1998 | if (srf_update->input_csc_color_matrix) |
1999 | surface->input_csc_color_matrix = | |
2000 | *srf_update->input_csc_color_matrix; | |
2001 | ||
2002 | if (srf_update->coeff_reduction_factor) | |
2003 | surface->coeff_reduction_factor = | |
2004 | *srf_update->coeff_reduction_factor; | |
5c41c023 SW |
2005 | |
2006 | if (srf_update->gamut_remap_matrix) | |
2007 | surface->gamut_remap_matrix = | |
2008 | *srf_update->gamut_remap_matrix; | |
f3e3698d NK |
2009 | } |
2010 | ||
6f4992b0 NK |
2011 | static void copy_stream_update_to_stream(struct dc *dc, |
2012 | struct dc_state *context, | |
2013 | struct dc_stream_state *stream, | |
f6fe4053 | 2014 | struct dc_stream_update *update) |
6f4992b0 | 2015 | { |
f6fe4053 NC |
2016 | struct dc_context *dc_ctx = dc->ctx; |
2017 | ||
6f4992b0 NK |
2018 | if (update == NULL || stream == NULL) |
2019 | return; | |
2020 | ||
2021 | if (update->src.height && update->src.width) | |
2022 | stream->src = update->src; | |
2023 | ||
2024 | if (update->dst.height && update->dst.width) | |
2025 | stream->dst = update->dst; | |
2026 | ||
2027 | if (update->out_transfer_func && | |
2028 | stream->out_transfer_func != update->out_transfer_func) { | |
2029 | stream->out_transfer_func->sdr_ref_white_level = | |
2030 | update->out_transfer_func->sdr_ref_white_level; | |
2031 | stream->out_transfer_func->tf = update->out_transfer_func->tf; | |
2032 | stream->out_transfer_func->type = | |
2033 | update->out_transfer_func->type; | |
2034 | memcpy(&stream->out_transfer_func->tf_pts, | |
2035 | &update->out_transfer_func->tf_pts, | |
2036 | sizeof(struct dc_transfer_func_distributed_points)); | |
2037 | } | |
2038 | ||
2039 | if (update->hdr_static_metadata) | |
2040 | stream->hdr_static_metadata = *update->hdr_static_metadata; | |
2041 | ||
2042 | if (update->abm_level) | |
2043 | stream->abm_level = *update->abm_level; | |
2044 | ||
2045 | if (update->periodic_interrupt0) | |
2046 | stream->periodic_interrupt0 = *update->periodic_interrupt0; | |
2047 | ||
2048 | if (update->periodic_interrupt1) | |
2049 | stream->periodic_interrupt1 = *update->periodic_interrupt1; | |
2050 | ||
2051 | if (update->gamut_remap) | |
2052 | stream->gamut_remap_matrix = *update->gamut_remap; | |
2053 | ||
2054 | /* Note: this being updated after mode set is currently not a use case | |
2055 | * however if it arises OCSC would need to be reprogrammed at the | |
2056 | * minimum | |
2057 | */ | |
2058 | if (update->output_color_space) | |
2059 | stream->output_color_space = *update->output_color_space; | |
2060 | ||
2061 | if (update->output_csc_transform) | |
2062 | stream->csc_color_matrix = *update->output_csc_transform; | |
2063 | ||
2064 | if (update->vrr_infopacket) | |
2065 | stream->vrr_infopacket = *update->vrr_infopacket; | |
2066 | ||
2067 | if (update->dpms_off) | |
2068 | stream->dpms_off = *update->dpms_off; | |
2069 | ||
2070 | if (update->vsc_infopacket) | |
2071 | stream->vsc_infopacket = *update->vsc_infopacket; | |
2072 | ||
2073 | if (update->vsp_infopacket) | |
2074 | stream->vsp_infopacket = *update->vsp_infopacket; | |
2075 | ||
2076 | if (update->dither_option) | |
2077 | stream->dither_option = *update->dither_option; | |
6f4992b0 NK |
2078 | /* update current stream with writeback info */ |
2079 | if (update->wb_update) { | |
2080 | int i; | |
2081 | ||
2082 | stream->num_wb_info = update->wb_update->num_wb_info; | |
2083 | ASSERT(stream->num_wb_info <= MAX_DWB_PIPES); | |
2084 | for (i = 0; i < stream->num_wb_info; i++) | |
2085 | stream->writeback_info[i] = | |
2086 | update->wb_update->writeback_info[i]; | |
2087 | } | |
6f4992b0 NK |
2088 | if (update->dsc_config) { |
2089 | struct dc_dsc_config old_dsc_cfg = stream->timing.dsc_cfg; | |
2090 | uint32_t old_dsc_enabled = stream->timing.flags.DSC; | |
2091 | uint32_t enable_dsc = (update->dsc_config->num_slices_h != 0 && | |
2092 | update->dsc_config->num_slices_v != 0); | |
2093 | ||
f6fe4053 NC |
2094 | /* Use temporarry context for validating new DSC config */ |
2095 | struct dc_state *dsc_validate_context = dc_create_state(dc); | |
2096 | ||
2097 | if (dsc_validate_context) { | |
2098 | dc_resource_state_copy_construct(dc->current_state, dsc_validate_context); | |
2099 | ||
2100 | stream->timing.dsc_cfg = *update->dsc_config; | |
2101 | stream->timing.flags.DSC = enable_dsc; | |
2102 | if (!dc->res_pool->funcs->validate_bandwidth(dc, dsc_validate_context, true)) { | |
2103 | stream->timing.dsc_cfg = old_dsc_cfg; | |
2104 | stream->timing.flags.DSC = old_dsc_enabled; | |
07863a6c | 2105 | update->dsc_config = NULL; |
f6fe4053 NC |
2106 | } |
2107 | ||
2108 | dc_release_state(dsc_validate_context); | |
2109 | } else { | |
2110 | DC_ERROR("Failed to allocate new validate context for DSC change\n"); | |
07863a6c | 2111 | update->dsc_config = NULL; |
6f4992b0 NK |
2112 | } |
2113 | } | |
6f4992b0 NK |
2114 | } |
2115 | ||
1e7e86c4 ST |
2116 | static void commit_planes_do_stream_update(struct dc *dc, |
2117 | struct dc_stream_state *stream, | |
2118 | struct dc_stream_update *stream_update, | |
2119 | enum surface_update_type update_type, | |
2120 | struct dc_state *context) | |
2121 | { | |
2122 | int j; | |
11963006 | 2123 | bool should_program_abm; |
1e7e86c4 ST |
2124 | |
2125 | // Stream updates | |
2126 | for (j = 0; j < dc->res_pool->pipe_count; j++) { | |
2127 | struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j]; | |
2128 | ||
b1f6d01c | 2129 | if (!pipe_ctx->top_pipe && !pipe_ctx->prev_odm_pipe && pipe_ctx->stream == stream) { |
1e7e86c4 | 2130 | |
d6001aed YS |
2131 | if (stream_update->periodic_interrupt0 && |
2132 | dc->hwss.setup_periodic_interrupt) | |
78c77382 | 2133 | dc->hwss.setup_periodic_interrupt(dc, pipe_ctx, VLINE0); |
8fde60b7 | 2134 | |
d6001aed YS |
2135 | if (stream_update->periodic_interrupt1 && |
2136 | dc->hwss.setup_periodic_interrupt) | |
78c77382 | 2137 | dc->hwss.setup_periodic_interrupt(dc, pipe_ctx, VLINE1); |
27e2e207 | 2138 | |
72ac71a7 | 2139 | if ((stream_update->hdr_static_metadata && !stream->use_dynamic_meta) || |
e71f8ca1 | 2140 | stream_update->vrr_infopacket || |
fd085356 S |
2141 | stream_update->vsc_infopacket || |
2142 | stream_update->vsp_infopacket) { | |
e71f8ca1 KK |
2143 | resource_build_info_frame(pipe_ctx); |
2144 | dc->hwss.update_info_frame(pipe_ctx); | |
2145 | } | |
2146 | ||
f42ea55b AK |
2147 | if (stream_update->hdr_static_metadata && |
2148 | stream->use_dynamic_meta && | |
2149 | dc->hwss.set_dmdata_attributes && | |
2150 | pipe_ctx->stream->dmdata_address.quad_part != 0) | |
2151 | dc->hwss.set_dmdata_attributes(pipe_ctx); | |
2152 | ||
8ab56172 S |
2153 | if (stream_update->gamut_remap) |
2154 | dc_stream_set_gamut_remap(dc, stream); | |
2155 | ||
eb385204 S |
2156 | if (stream_update->output_csc_transform) |
2157 | dc_stream_program_csc_matrix(dc, stream); | |
2158 | ||
8ccb596f | 2159 | if (stream_update->dither_option) { |
b1f6d01c | 2160 | struct pipe_ctx *odm_pipe = pipe_ctx->next_odm_pipe; |
8ccb596f S |
2161 | resource_build_bit_depth_reduction_params(pipe_ctx->stream, |
2162 | &pipe_ctx->stream->bit_depth_params); | |
2163 | pipe_ctx->stream_res.opp->funcs->opp_program_fmt(pipe_ctx->stream_res.opp, | |
2164 | &stream->bit_depth_params, | |
2165 | &stream->clamping); | |
b1f6d01c | 2166 | while (odm_pipe) { |
6fbefb84 HW |
2167 | odm_pipe->stream_res.opp->funcs->opp_program_fmt(odm_pipe->stream_res.opp, |
2168 | &stream->bit_depth_params, | |
2169 | &stream->clamping); | |
b1f6d01c DL |
2170 | odm_pipe = odm_pipe->next_odm_pipe; |
2171 | } | |
8ccb596f S |
2172 | } |
2173 | ||
acdac228 AK |
2174 | /* Full fe update*/ |
2175 | if (update_type == UPDATE_TYPE_FAST) | |
2176 | continue; | |
2177 | ||
009114f6 | 2178 | if (stream_update->dsc_config) |
ba32c50f | 2179 | dp_update_dsc_config(pipe_ctx); |
1e7e86c4 ST |
2180 | |
2181 | if (stream_update->dpms_off) { | |
2182 | if (*stream_update->dpms_off) { | |
57430404 SSC |
2183 | core_link_disable_stream(pipe_ctx); |
2184 | /* for dpms, keep acquired resources*/ | |
2185 | if (pipe_ctx->stream_res.audio && !dc->debug.az_endpoint_mute_only) | |
2186 | pipe_ctx->stream_res.audio->funcs->az_disable(pipe_ctx->stream_res.audio); | |
2187 | ||
e2bf2007 | 2188 | dc->hwss.optimize_bandwidth(dc, dc->current_state); |
1e7e86c4 | 2189 | } else { |
ccce745c | 2190 | if (dc->optimize_seamless_boot_streams == 0) |
5ec43eda ML |
2191 | dc->hwss.prepare_bandwidth(dc, dc->current_state); |
2192 | ||
1e7e86c4 ST |
2193 | core_link_enable_stream(dc->current_state, pipe_ctx); |
2194 | } | |
2195 | } | |
2196 | ||
2197 | if (stream_update->abm_level && pipe_ctx->stream_res.abm) { | |
11963006 JL |
2198 | should_program_abm = true; |
2199 | ||
2200 | // if otg funcs defined check if blanked before programming | |
2201 | if (pipe_ctx->stream_res.tg->funcs->is_blanked) | |
2202 | if (pipe_ctx->stream_res.tg->funcs->is_blanked(pipe_ctx->stream_res.tg)) | |
2203 | should_program_abm = false; | |
2204 | ||
2205 | if (should_program_abm) { | |
2206 | if (*stream_update->abm_level == ABM_LEVEL_IMMEDIATE_DISABLE) { | |
2207 | pipe_ctx->stream_res.abm->funcs->set_abm_immediate_disable(pipe_ctx->stream_res.abm); | |
2208 | } else { | |
1e7e86c4 ST |
2209 | pipe_ctx->stream_res.abm->funcs->set_abm_level( |
2210 | pipe_ctx->stream_res.abm, stream->abm_level); | |
11963006 JL |
2211 | } |
2212 | } | |
1e7e86c4 | 2213 | } |
1e7e86c4 ST |
2214 | } |
2215 | } | |
2216 | } | |
2217 | ||
bc6828e0 BL |
2218 | static void commit_planes_for_stream(struct dc *dc, |
2219 | struct dc_surface_update *srf_updates, | |
2220 | int surface_count, | |
0971c40e | 2221 | struct dc_stream_state *stream, |
bc6828e0 BL |
2222 | struct dc_stream_update *stream_update, |
2223 | enum surface_update_type update_type, | |
2224 | struct dc_state *context) | |
e72f0acd | 2225 | { |
e72f0acd | 2226 | int i, j; |
05133ac8 | 2227 | struct pipe_ctx *top_pipe_to_program = NULL; |
4562236b | 2228 | |
ccce745c | 2229 | if (dc->optimize_seamless_boot_streams > 0 && surface_count > 0) { |
46570f09 AK |
2230 | /* Optimize seamless boot flag keeps clocks and watermarks high until |
2231 | * first flip. After first flip, optimization is required to lower | |
4cd75ff0 AK |
2232 | * bandwidth. Important to note that it is expected UEFI will |
2233 | * only light up a single display on POST, therefore we only expect | |
2234 | * one stream with seamless boot flag set. | |
46570f09 | 2235 | */ |
4cd75ff0 AK |
2236 | if (stream->apply_seamless_boot_optimization) { |
2237 | stream->apply_seamless_boot_optimization = false; | |
ccce745c ML |
2238 | dc->optimize_seamless_boot_streams--; |
2239 | ||
2240 | if (dc->optimize_seamless_boot_streams == 0) | |
0aa63a33 | 2241 | dc->optimized_required = true; |
4cd75ff0 | 2242 | } |
46570f09 AK |
2243 | } |
2244 | ||
ccce745c | 2245 | if (update_type == UPDATE_TYPE_FULL && dc->optimize_seamless_boot_streams == 0) { |
9566b675 | 2246 | dc->hwss.prepare_bandwidth(dc, context); |
bc6828e0 | 2247 | context_clock_trace(dc, context); |
87480687 EY |
2248 | } |
2249 | ||
009114f6 AK |
2250 | for (j = 0; j < dc->res_pool->pipe_count; j++) { |
2251 | struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j]; | |
2252 | ||
2253 | if (!pipe_ctx->top_pipe && | |
2254 | !pipe_ctx->prev_odm_pipe && | |
2255 | pipe_ctx->stream && | |
2256 | pipe_ctx->stream == stream) { | |
2257 | top_pipe_to_program = pipe_ctx; | |
2258 | } | |
2259 | } | |
2260 | ||
71b81f12 WL |
2261 | if ((update_type != UPDATE_TYPE_FAST) && stream->update_flags.bits.dsc_changed) |
2262 | if (top_pipe_to_program->stream_res.tg->funcs->lock_doublebuffer_enable) | |
2263 | top_pipe_to_program->stream_res.tg->funcs->lock_doublebuffer_enable( | |
2264 | top_pipe_to_program->stream_res.tg); | |
2265 | ||
009114f6 AK |
2266 | if ((update_type != UPDATE_TYPE_FAST) && dc->hwss.interdependent_update_lock) |
2267 | dc->hwss.interdependent_update_lock(dc, context, true); | |
2268 | else | |
2269 | /* Lock the top pipe while updating plane addrs, since freesync requires | |
2270 | * plane addr update event triggers to be synchronized. | |
2271 | * top_pipe_to_program is expected to never be NULL | |
2272 | */ | |
2273 | dc->hwss.pipe_control_lock(dc, top_pipe_to_program, true); | |
2274 | ||
2275 | ||
1e7e86c4 ST |
2276 | // Stream updates |
2277 | if (stream_update) | |
2278 | commit_planes_do_stream_update(dc, stream, stream_update, update_type, context); | |
2279 | ||
671a6246 YS |
2280 | if (surface_count == 0) { |
2281 | /* | |
2282 | * In case of turning off screen, no need to program front end a second time. | |
1e7e86c4 | 2283 | * just return after program blank. |
671a6246 | 2284 | */ |
b6e881c9 DL |
2285 | if (dc->hwss.apply_ctx_for_surface) |
2286 | dc->hwss.apply_ctx_for_surface(dc, stream, 0, context); | |
b6e881c9 DL |
2287 | if (dc->hwss.program_front_end_for_ctx) |
2288 | dc->hwss.program_front_end_for_ctx(dc, context); | |
b6e881c9 | 2289 | |
009114f6 AK |
2290 | if ((update_type != UPDATE_TYPE_FAST) && dc->hwss.interdependent_update_lock) |
2291 | dc->hwss.interdependent_update_lock(dc, context, false); | |
2292 | else | |
2293 | dc->hwss.pipe_control_lock(dc, top_pipe_to_program, false); | |
2294 | ||
bbf5f6c3 | 2295 | dc->hwss.post_unlock_program_front_end(dc, context); |
671a6246 YS |
2296 | return; |
2297 | } | |
e72f0acd | 2298 | |
6fbefb84 HW |
2299 | if (!IS_DIAG_DC(dc->ctx->dce_environment)) { |
2300 | for (i = 0; i < surface_count; i++) { | |
2301 | struct dc_plane_state *plane_state = srf_updates[i].surface; | |
2302 | /*set logical flag for lock/unlock use*/ | |
2303 | for (j = 0; j < dc->res_pool->pipe_count; j++) { | |
2304 | struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j]; | |
2305 | if (!pipe_ctx->plane_state) | |
2306 | continue; | |
2307 | if (pipe_ctx->plane_state != plane_state) | |
2308 | continue; | |
2309 | plane_state->triplebuffer_flips = false; | |
2310 | if (update_type == UPDATE_TYPE_FAST && | |
2311 | dc->hwss.program_triplebuffer != NULL && | |
2312 | !plane_state->flip_immediate && | |
2313 | !dc->debug.disable_tri_buf) { | |
2314 | /*triple buffer for VUpdate only*/ | |
2315 | plane_state->triplebuffer_flips = true; | |
2316 | } | |
2317 | } | |
2318 | } | |
2319 | } | |
6fbefb84 | 2320 | |
1e7e86c4 | 2321 | // Update Type FULL, Surface updates |
15659045 | 2322 | for (j = 0; j < dc->res_pool->pipe_count; j++) { |
f19d5f35 | 2323 | struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j]; |
3e9ad616 | 2324 | |
e6c258cb | 2325 | if (!pipe_ctx->top_pipe && |
285e3004 | 2326 | !pipe_ctx->prev_odm_pipe && |
05133ac8 S |
2327 | pipe_ctx->stream && |
2328 | pipe_ctx->stream == stream) { | |
2329 | struct dc_stream_status *stream_status = NULL; | |
2330 | ||
98e6436d AK |
2331 | if (!pipe_ctx->plane_state) |
2332 | continue; | |
2333 | ||
98e6436d AK |
2334 | /* Full fe update*/ |
2335 | if (update_type == UPDATE_TYPE_FAST) | |
05133ac8 S |
2336 | continue; |
2337 | ||
6fbefb84 HW |
2338 | ASSERT(!pipe_ctx->plane_state->triplebuffer_flips); |
2339 | ||
2340 | if (dc->hwss.program_triplebuffer != NULL && | |
2341 | !dc->debug.disable_tri_buf) { | |
2342 | /*turn off triple buffer for full update*/ | |
2343 | dc->hwss.program_triplebuffer( | |
2344 | dc, pipe_ctx, pipe_ctx->plane_state->triplebuffer_flips); | |
2345 | } | |
05133ac8 | 2346 | stream_status = |
98e6436d | 2347 | stream_get_status(context, pipe_ctx->stream); |
3e9ad616 | 2348 | |
b6e881c9 DL |
2349 | if (dc->hwss.apply_ctx_for_surface) |
2350 | dc->hwss.apply_ctx_for_surface( | |
15659045 | 2351 | dc, pipe_ctx->stream, stream_status->plane_count, context); |
3e9ad616 | 2352 | } |
f19d5f35 | 2353 | } |
b9fe5151 | 2354 | if (dc->hwss.program_front_end_for_ctx && update_type != UPDATE_TYPE_FAST) { |
b6e881c9 | 2355 | dc->hwss.program_front_end_for_ctx(dc, context); |
a4cea116 | 2356 | #ifdef CONFIG_DRM_AMD_DC_DCN |
b9fe5151 JC |
2357 | if (dc->debug.validate_dml_output) { |
2358 | for (i = 0; i < dc->res_pool->pipe_count; i++) { | |
2359 | struct pipe_ctx cur_pipe = context->res_ctx.pipe_ctx[i]; | |
2360 | if (cur_pipe.stream == NULL) | |
2361 | continue; | |
2362 | ||
2363 | cur_pipe.plane_res.hubp->funcs->validate_dml_output( | |
2364 | cur_pipe.plane_res.hubp, dc->ctx, | |
2365 | &context->res_ctx.pipe_ctx[i].rq_regs, | |
2366 | &context->res_ctx.pipe_ctx[i].dlg_regs, | |
2367 | &context->res_ctx.pipe_ctx[i].ttu_regs); | |
2368 | } | |
2369 | } | |
2370 | #endif | |
2371 | } | |
f19d5f35 | 2372 | |
1e7e86c4 | 2373 | // Update Type FAST, Surface updates |
05133ac8 | 2374 | if (update_type == UPDATE_TYPE_FAST) { |
6fbefb84 HW |
2375 | if (dc->hwss.set_flip_control_gsl) |
2376 | for (i = 0; i < surface_count; i++) { | |
2377 | struct dc_plane_state *plane_state = srf_updates[i].surface; | |
2378 | ||
2379 | for (j = 0; j < dc->res_pool->pipe_count; j++) { | |
2380 | struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j]; | |
2381 | ||
2382 | if (pipe_ctx->stream != stream) | |
2383 | continue; | |
2384 | ||
2385 | if (pipe_ctx->plane_state != plane_state) | |
2386 | continue; | |
2387 | ||
2388 | // GSL has to be used for flip immediate | |
2389 | dc->hwss.set_flip_control_gsl(pipe_ctx, | |
2390 | plane_state->flip_immediate); | |
2391 | } | |
2392 | } | |
05133ac8 S |
2393 | /* Perform requested Updates */ |
2394 | for (i = 0; i < surface_count; i++) { | |
2395 | struct dc_plane_state *plane_state = srf_updates[i].surface; | |
00f02019 | 2396 | |
05133ac8 S |
2397 | for (j = 0; j < dc->res_pool->pipe_count; j++) { |
2398 | struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j]; | |
00f02019 | 2399 | |
05133ac8 S |
2400 | if (pipe_ctx->stream != stream) |
2401 | continue; | |
4562236b | 2402 | |
05133ac8 S |
2403 | if (pipe_ctx->plane_state != plane_state) |
2404 | continue; | |
6fbefb84 HW |
2405 | /*program triple buffer after lock based on flip type*/ |
2406 | if (dc->hwss.program_triplebuffer != NULL && | |
2407 | !dc->debug.disable_tri_buf) { | |
2408 | /*only enable triplebuffer for fast_update*/ | |
2409 | dc->hwss.program_triplebuffer( | |
2410 | dc, pipe_ctx, plane_state->triplebuffer_flips); | |
2411 | } | |
05133ac8 | 2412 | if (srf_updates[i].flip_addr) |
4f804817 | 2413 | dc->hwss.update_plane_addr(dc, pipe_ctx); |
05133ac8 | 2414 | } |
56ef6ed9 | 2415 | } |
009114f6 | 2416 | } |
05133ac8 | 2417 | |
009114f6 AK |
2418 | if ((update_type != UPDATE_TYPE_FAST) && dc->hwss.interdependent_update_lock) |
2419 | dc->hwss.interdependent_update_lock(dc, context, false); | |
2420 | else | |
05133ac8 | 2421 | dc->hwss.pipe_control_lock(dc, top_pipe_to_program, false); |
e63e2491 | 2422 | |
71b81f12 WL |
2423 | if ((update_type != UPDATE_TYPE_FAST) && stream->update_flags.bits.dsc_changed) |
2424 | if (top_pipe_to_program->stream_res.tg->funcs->lock_doublebuffer_enable) { | |
2425 | top_pipe_to_program->stream_res.tg->funcs->wait_for_state( | |
2426 | top_pipe_to_program->stream_res.tg, | |
2427 | CRTC_STATE_VACTIVE); | |
2428 | top_pipe_to_program->stream_res.tg->funcs->wait_for_state( | |
2429 | top_pipe_to_program->stream_res.tg, | |
2430 | CRTC_STATE_VBLANK); | |
2431 | top_pipe_to_program->stream_res.tg->funcs->wait_for_state( | |
2432 | top_pipe_to_program->stream_res.tg, | |
2433 | CRTC_STATE_VACTIVE); | |
2434 | top_pipe_to_program->stream_res.tg->funcs->lock_doublebuffer_disable( | |
2435 | top_pipe_to_program->stream_res.tg); | |
2436 | } | |
2437 | ||
bbf5f6c3 AK |
2438 | if (update_type != UPDATE_TYPE_FAST) |
2439 | dc->hwss.post_unlock_program_front_end(dc, context); | |
2440 | ||
4fd33412 AC |
2441 | // Fire manual trigger only when bottom plane is flipped |
2442 | for (j = 0; j < dc->res_pool->pipe_count; j++) { | |
2443 | struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j]; | |
e63e2491 | 2444 | |
4fd33412 AC |
2445 | if (pipe_ctx->bottom_pipe || |
2446 | !pipe_ctx->stream || | |
2447 | pipe_ctx->stream != stream || | |
2448 | !pipe_ctx->plane_state->update_flags.bits.addr_update) | |
e63e2491 EB |
2449 | continue; |
2450 | ||
2451 | if (pipe_ctx->stream_res.tg->funcs->program_manual_trigger) | |
2452 | pipe_ctx->stream_res.tg->funcs->program_manual_trigger(pipe_ctx->stream_res.tg); | |
2453 | } | |
bc6828e0 | 2454 | } |
4562236b | 2455 | |
bc6828e0 BL |
2456 | void dc_commit_updates_for_stream(struct dc *dc, |
2457 | struct dc_surface_update *srf_updates, | |
2458 | int surface_count, | |
2459 | struct dc_stream_state *stream, | |
2460 | struct dc_stream_update *stream_update, | |
bc6828e0 BL |
2461 | struct dc_state *state) |
2462 | { | |
2463 | const struct dc_stream_status *stream_status; | |
2464 | enum surface_update_type update_type; | |
2465 | struct dc_state *context; | |
60d671db | 2466 | struct dc_context *dc_ctx = dc->ctx; |
3bae2013 | 2467 | int i, j; |
bc6828e0 BL |
2468 | |
2469 | stream_status = dc_stream_get_status(stream); | |
2470 | context = dc->current_state; | |
2471 | ||
2472 | update_type = dc_check_update_surfaces_for_stream( | |
2473 | dc, srf_updates, surface_count, stream_update, stream_status); | |
2474 | ||
2475 | if (update_type >= update_surface_trace_level) | |
2476 | update_surface_trace(dc, srf_updates, surface_count); | |
e771aae0 | 2477 | |
e771aae0 | 2478 | |
60d671db JZ |
2479 | if (update_type >= UPDATE_TYPE_FULL) { |
2480 | ||
2481 | /* initialize scratch memory for building context */ | |
813d20dc | 2482 | context = dc_create_state(dc); |
60d671db JZ |
2483 | if (context == NULL) { |
2484 | DC_ERROR("Failed to allocate new validate context!\n"); | |
2485 | return; | |
2486 | } | |
2487 | ||
bc6828e0 | 2488 | dc_resource_state_copy_construct(state, context); |
c238bfe0 DF |
2489 | |
2490 | for (i = 0; i < dc->res_pool->pipe_count; i++) { | |
2491 | struct pipe_ctx *new_pipe = &context->res_ctx.pipe_ctx[i]; | |
2492 | struct pipe_ctx *old_pipe = &dc->current_state->res_ctx.pipe_ctx[i]; | |
2493 | ||
2494 | if (new_pipe->plane_state && new_pipe->plane_state != old_pipe->plane_state) | |
2495 | new_pipe->plane_state->force_full_update = true; | |
2496 | } | |
60d671db | 2497 | } |
5aa72db7 | 2498 | |
bc6828e0 BL |
2499 | |
2500 | for (i = 0; i < surface_count; i++) { | |
2501 | struct dc_plane_state *surface = srf_updates[i].surface; | |
2502 | ||
f3e3698d | 2503 | copy_surface_update_to_plane(surface, &srf_updates[i]); |
5aa72db7 | 2504 | |
3bae2013 NK |
2505 | if (update_type >= UPDATE_TYPE_MED) { |
2506 | for (j = 0; j < dc->res_pool->pipe_count; j++) { | |
2507 | struct pipe_ctx *pipe_ctx = | |
2508 | &context->res_ctx.pipe_ctx[j]; | |
2509 | ||
2510 | if (pipe_ctx->plane_state != surface) | |
2511 | continue; | |
2512 | ||
2513 | resource_build_scaling_params(pipe_ctx); | |
2514 | } | |
2515 | } | |
80e80ec8 | 2516 | } |
bc6828e0 | 2517 | |
6f4992b0 NK |
2518 | copy_stream_update_to_stream(dc, context, stream, stream_update); |
2519 | ||
bc6828e0 BL |
2520 | commit_planes_for_stream( |
2521 | dc, | |
2522 | srf_updates, | |
2523 | surface_count, | |
2524 | stream, | |
2525 | stream_update, | |
2526 | update_type, | |
2527 | context); | |
c2a5b500 | 2528 | /*update current_State*/ |
60d671db JZ |
2529 | if (dc->current_state != context) { |
2530 | ||
2531 | struct dc_state *old = dc->current_state; | |
2532 | ||
2533 | dc->current_state = context; | |
2534 | dc_release_state(old); | |
2535 | ||
c238bfe0 DF |
2536 | for (i = 0; i < dc->res_pool->pipe_count; i++) { |
2537 | struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; | |
2538 | ||
2539 | if (pipe_ctx->plane_state && pipe_ctx->stream == stream) | |
2540 | pipe_ctx->plane_state->force_full_update = false; | |
2541 | } | |
60d671db | 2542 | } |
c2a5b500 CL |
2543 | /*let's use current_state to update watermark etc*/ |
2544 | if (update_type >= UPDATE_TYPE_FULL) | |
2545 | dc_post_update_surfaces_to_stream(dc); | |
60d671db | 2546 | |
6d9501e4 HW |
2547 | return; |
2548 | ||
4562236b HW |
2549 | } |
2550 | ||
fb3466a4 | 2551 | uint8_t dc_get_current_stream_count(struct dc *dc) |
4562236b | 2552 | { |
608ac7bb | 2553 | return dc->current_state->stream_count; |
4562236b HW |
2554 | } |
2555 | ||
fb3466a4 | 2556 | struct dc_stream_state *dc_get_stream_at_index(struct dc *dc, uint8_t i) |
4562236b | 2557 | { |
608ac7bb JZ |
2558 | if (i < dc->current_state->stream_count) |
2559 | return dc->current_state->streams[i]; | |
4562236b HW |
2560 | return NULL; |
2561 | } | |
2562 | ||
4562236b HW |
2563 | enum dc_irq_source dc_interrupt_to_irq_source( |
2564 | struct dc *dc, | |
2565 | uint32_t src_id, | |
2566 | uint32_t ext_id) | |
2567 | { | |
15659045 | 2568 | return dal_irq_service_to_irq_source(dc->res_pool->irqs, src_id, ext_id); |
4562236b HW |
2569 | } |
2570 | ||
2119aa17 DF |
2571 | /** |
2572 | * dc_interrupt_set() - Enable/disable an AMD hw interrupt source | |
2573 | */ | |
a0e30392 | 2574 | bool dc_interrupt_set(struct dc *dc, enum dc_irq_source src, bool enable) |
4562236b | 2575 | { |
21de3396 RZ |
2576 | |
2577 | if (dc == NULL) | |
a0e30392 | 2578 | return false; |
21de3396 | 2579 | |
a0e30392 | 2580 | return dal_irq_service_set(dc->res_pool->irqs, src, enable); |
4562236b HW |
2581 | } |
2582 | ||
2583 | void dc_interrupt_ack(struct dc *dc, enum dc_irq_source src) | |
2584 | { | |
15659045 | 2585 | dal_irq_service_ack(dc->res_pool->irqs, src); |
4562236b HW |
2586 | } |
2587 | ||
2588 | void dc_set_power_state( | |
2589 | struct dc *dc, | |
a3621485 | 2590 | enum dc_acpi_cm_power_state power_state) |
4562236b | 2591 | { |
8ee5702a | 2592 | struct kref refcount; |
bb67bfd2 | 2593 | struct display_mode_lib *dml; |
4562236b | 2594 | |
4562236b HW |
2595 | switch (power_state) { |
2596 | case DC_ACPI_CM_POWER_STATE_D0: | |
ab8db3e1 | 2597 | dc_resource_state_construct(dc, dc->current_state); |
2200eb9e | 2598 | |
3a1627b0 NK |
2599 | if (dc->ctx->dmub_srv) |
2600 | dc_dmub_srv_wait_phy_init(dc->ctx->dmub_srv); | |
ab8db3e1 | 2601 | |
15659045 | 2602 | dc->hwss.init_hw(dc); |
e5382701 | 2603 | |
e5382701 LH |
2604 | if (dc->hwss.init_sys_ctx != NULL && |
2605 | dc->vm_pa_config.valid) { | |
2606 | dc->hwss.init_sys_ctx(dc->hwseq, dc, &dc->vm_pa_config); | |
2607 | } | |
e5382701 | 2608 | |
4562236b HW |
2609 | break; |
2610 | default: | |
ad908423 | 2611 | ASSERT(dc->current_state->stream_count == 0); |
4562236b HW |
2612 | /* Zero out the current context so that on resume we start with |
2613 | * clean state, and dc hw programming optimizations will not | |
2614 | * cause any trouble. | |
2615 | */ | |
bb67bfd2 DA |
2616 | dml = kzalloc(sizeof(struct display_mode_lib), |
2617 | GFP_KERNEL); | |
2618 | ||
2619 | ASSERT(dml); | |
2620 | if (!dml) | |
2621 | return; | |
60bf1860 AG |
2622 | |
2623 | /* Preserve refcount */ | |
8ee5702a | 2624 | refcount = dc->current_state->refcount; |
540c1229 TH |
2625 | /* Preserve display mode lib */ |
2626 | memcpy(dml, &dc->current_state->bw_ctx.dml, sizeof(struct display_mode_lib)); | |
2627 | ||
f36cc577 | 2628 | dc_resource_state_destruct(dc->current_state); |
608ac7bb JZ |
2629 | memset(dc->current_state, 0, |
2630 | sizeof(*dc->current_state)); | |
ab8db3e1 | 2631 | |
8ee5702a | 2632 | dc->current_state->refcount = refcount; |
540c1229 | 2633 | dc->current_state->bw_ctx.dml = *dml; |
4562236b | 2634 | |
bb67bfd2 DA |
2635 | kfree(dml); |
2636 | ||
4562236b HW |
2637 | break; |
2638 | } | |
4562236b HW |
2639 | } |
2640 | ||
fb3466a4 | 2641 | void dc_resume(struct dc *dc) |
4562236b | 2642 | { |
4562236b HW |
2643 | |
2644 | uint32_t i; | |
2645 | ||
15659045 BL |
2646 | for (i = 0; i < dc->link_count; i++) |
2647 | core_link_resume(dc->links[i]); | |
4562236b HW |
2648 | } |
2649 | ||
f284975e DF |
2650 | unsigned int dc_get_current_backlight_pwm(struct dc *dc) |
2651 | { | |
2652 | struct abm *abm = dc->res_pool->abm; | |
2653 | ||
2654 | if (abm) | |
2655 | return abm->funcs->get_current_backlight(abm); | |
2656 | ||
2657 | return 0; | |
2658 | } | |
2659 | ||
2660 | unsigned int dc_get_target_backlight_pwm(struct dc *dc) | |
2661 | { | |
2662 | struct abm *abm = dc->res_pool->abm; | |
2663 | ||
2664 | if (abm) | |
2665 | return abm->funcs->get_target_backlight(abm); | |
2666 | ||
2667 | return 0; | |
2668 | } | |
2669 | ||
c1ee92f9 DF |
2670 | bool dc_is_dmcu_initialized(struct dc *dc) |
2671 | { | |
2672 | struct dmcu *dmcu = dc->res_pool->dmcu; | |
2673 | ||
2674 | if (dmcu) | |
2675 | return dmcu->funcs->is_dmcu_initialized(dmcu); | |
2676 | return false; | |
2677 | } | |
2678 | ||
4562236b HW |
2679 | bool dc_submit_i2c( |
2680 | struct dc *dc, | |
2681 | uint32_t link_index, | |
2682 | struct i2c_command *cmd) | |
2683 | { | |
4562236b | 2684 | |
15659045 | 2685 | struct dc_link *link = dc->links[link_index]; |
d0778ebf | 2686 | struct ddc_service *ddc = link->ddc; |
c85e6e54 DF |
2687 | return dce_i2c_submit_command( |
2688 | dc->res_pool, | |
4562236b HW |
2689 | ddc->ddc_pin, |
2690 | cmd); | |
2691 | } | |
2692 | ||
d9a07577 JL |
2693 | bool dc_submit_i2c_oem( |
2694 | struct dc *dc, | |
2695 | struct i2c_command *cmd) | |
2696 | { | |
2697 | struct ddc_service *ddc = dc->res_pool->oem_device; | |
2698 | return dce_i2c_submit_command( | |
2699 | dc->res_pool, | |
2700 | ddc->ddc_pin, | |
2701 | cmd); | |
2702 | } | |
2703 | ||
d0778ebf | 2704 | static bool link_add_remote_sink_helper(struct dc_link *dc_link, struct dc_sink *sink) |
4562236b | 2705 | { |
4562236b HW |
2706 | if (dc_link->sink_count >= MAX_SINKS_PER_LINK) { |
2707 | BREAK_TO_DEBUGGER(); | |
2708 | return false; | |
2709 | } | |
2710 | ||
2711 | dc_sink_retain(sink); | |
2712 | ||
2713 | dc_link->remote_sinks[dc_link->sink_count] = sink; | |
2714 | dc_link->sink_count++; | |
2715 | ||
2716 | return true; | |
2717 | } | |
2718 | ||
2119aa17 DF |
2719 | /** |
2720 | * dc_link_add_remote_sink() - Create a sink and attach it to an existing link | |
2721 | * | |
2722 | * EDID length is in bytes | |
2723 | */ | |
4562236b | 2724 | struct dc_sink *dc_link_add_remote_sink( |
d0778ebf | 2725 | struct dc_link *link, |
4562236b HW |
2726 | const uint8_t *edid, |
2727 | int len, | |
2728 | struct dc_sink_init_data *init_data) | |
2729 | { | |
2730 | struct dc_sink *dc_sink; | |
2731 | enum dc_edid_status edid_status; | |
4562236b | 2732 | |
8de94233 | 2733 | if (len > DC_MAX_EDID_BUFFER_SIZE) { |
4562236b HW |
2734 | dm_error("Max EDID buffer size breached!\n"); |
2735 | return NULL; | |
2736 | } | |
2737 | ||
2738 | if (!init_data) { | |
2739 | BREAK_TO_DEBUGGER(); | |
2740 | return NULL; | |
2741 | } | |
2742 | ||
2743 | if (!init_data->link) { | |
2744 | BREAK_TO_DEBUGGER(); | |
2745 | return NULL; | |
2746 | } | |
2747 | ||
2748 | dc_sink = dc_sink_create(init_data); | |
2749 | ||
2750 | if (!dc_sink) | |
2751 | return NULL; | |
2752 | ||
2753 | memmove(dc_sink->dc_edid.raw_edid, edid, len); | |
2754 | dc_sink->dc_edid.length = len; | |
2755 | ||
2756 | if (!link_add_remote_sink_helper( | |
d0778ebf | 2757 | link, |
4562236b HW |
2758 | dc_sink)) |
2759 | goto fail_add_sink; | |
2760 | ||
2761 | edid_status = dm_helpers_parse_edid_caps( | |
d0778ebf | 2762 | link->ctx, |
4562236b HW |
2763 | &dc_sink->dc_edid, |
2764 | &dc_sink->edid_caps); | |
2765 | ||
65317388 EY |
2766 | /* |
2767 | * Treat device as no EDID device if EDID | |
2768 | * parsing fails | |
2769 | */ | |
2770 | if (edid_status != EDID_OK) { | |
2771 | dc_sink->dc_edid.length = 0; | |
2772 | dm_error("Bad EDID, status%d!\n", edid_status); | |
2773 | } | |
4562236b HW |
2774 | |
2775 | return dc_sink; | |
65317388 | 2776 | |
4562236b HW |
2777 | fail_add_sink: |
2778 | dc_sink_release(dc_sink); | |
2779 | return NULL; | |
2780 | } | |
2781 | ||
2119aa17 DF |
2782 | /** |
2783 | * dc_link_remove_remote_sink() - Remove a remote sink from a dc_link | |
2784 | * | |
2785 | * Note that this just removes the struct dc_sink - it doesn't | |
2786 | * program hardware or alter other members of dc_link | |
2787 | */ | |
b73a22d3 | 2788 | void dc_link_remove_remote_sink(struct dc_link *link, struct dc_sink *sink) |
4562236b HW |
2789 | { |
2790 | int i; | |
4562236b HW |
2791 | |
2792 | if (!link->sink_count) { | |
2793 | BREAK_TO_DEBUGGER(); | |
2794 | return; | |
2795 | } | |
2796 | ||
d0778ebf HW |
2797 | for (i = 0; i < link->sink_count; i++) { |
2798 | if (link->remote_sinks[i] == sink) { | |
4562236b | 2799 | dc_sink_release(sink); |
d0778ebf | 2800 | link->remote_sinks[i] = NULL; |
4562236b HW |
2801 | |
2802 | /* shrink array to remove empty place */ | |
d0778ebf HW |
2803 | while (i < link->sink_count - 1) { |
2804 | link->remote_sinks[i] = link->remote_sinks[i+1]; | |
4562236b HW |
2805 | i++; |
2806 | } | |
d0778ebf HW |
2807 | link->remote_sinks[i] = NULL; |
2808 | link->sink_count--; | |
4562236b HW |
2809 | return; |
2810 | } | |
2811 | } | |
2812 | } | |
8ab2180f EB |
2813 | |
2814 | void get_clock_requirements_for_state(struct dc_state *state, struct AsicStateEx *info) | |
2815 | { | |
813d20dc AW |
2816 | info->displayClock = (unsigned int)state->bw_ctx.bw.dcn.clk.dispclk_khz; |
2817 | info->engineClock = (unsigned int)state->bw_ctx.bw.dcn.clk.dcfclk_khz; | |
2818 | info->memoryClock = (unsigned int)state->bw_ctx.bw.dcn.clk.dramclk_khz; | |
2819 | info->maxSupportedDppClock = (unsigned int)state->bw_ctx.bw.dcn.clk.max_supported_dppclk_khz; | |
2820 | info->dppClock = (unsigned int)state->bw_ctx.bw.dcn.clk.dppclk_khz; | |
2821 | info->socClock = (unsigned int)state->bw_ctx.bw.dcn.clk.socclk_khz; | |
2822 | info->dcfClockDeepSleep = (unsigned int)state->bw_ctx.bw.dcn.clk.dcfclk_deep_sleep_khz; | |
2823 | info->fClock = (unsigned int)state->bw_ctx.bw.dcn.clk.fclk_khz; | |
2824 | info->phyClock = (unsigned int)state->bw_ctx.bw.dcn.clk.phyclk_khz; | |
c1ee92f9 | 2825 | } |
925f566c CL |
2826 | enum dc_status dc_set_clock(struct dc *dc, enum dc_clock_type clock_type, uint32_t clk_khz, uint32_t stepping) |
2827 | { | |
2828 | if (dc->hwss.set_clock) | |
2829 | return dc->hwss.set_clock(dc, clock_type, clk_khz, stepping); | |
2830 | return DC_ERROR_UNEXPECTED; | |
2831 | } | |
2832 | void dc_get_clock(struct dc *dc, enum dc_clock_type clock_type, struct dc_clock_config *clock_cfg) | |
2833 | { | |
2834 | if (dc->hwss.get_clock) | |
2835 | dc->hwss.get_clock(dc, clock_type, clock_cfg); | |
2836 | } |