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