1 | /* |
2 | * Copyright 2023 Advanced Micro Devices, Inc. |
3 | * |
4 | * Permission is hereby granted, free of charge, to any person obtaining a |
5 | * copy of this software and associated documentation files (the "Software"), |
6 | * to deal in the Software without restriction, including without limitation |
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
8 | * and/or sell copies of the Software, and to permit persons to whom the |
9 | * Software is furnished to do so, subject to the following conditions: |
10 | * |
11 | * The above copyright notice and this permission notice shall be included in |
12 | * all copies or substantial portions of the Software. |
13 | * |
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
20 | * OTHER DEALINGS IN THE SOFTWARE. |
21 | * |
22 | * Authors: AMD |
23 | * |
24 | */ |
25 | |
26 | /* FILE POLICY AND INTENDED USAGE: |
27 | * This file provides single entrance to link functionality declared in dc |
28 | * public headers. The file is intended to be used as a thin translation layer |
29 | * that directly calls link internal functions without adding new functional |
30 | * behavior. |
31 | * |
32 | * When exporting a new link related dc function, add function declaration in |
33 | * dc.h with detail interface documentation, then add function implementation |
34 | * in this file which calls link functions. |
35 | */ |
36 | #include "link.h" |
37 | #include "dce/dce_i2c.h" |
38 | struct dc_link *dc_get_link_at_index(struct dc *dc, uint32_t link_index) |
39 | { |
40 | return dc->links[link_index]; |
41 | } |
42 | |
43 | void dc_get_edp_links(const struct dc *dc, |
44 | struct dc_link **edp_links, |
45 | int *edp_num) |
46 | { |
47 | int i; |
48 | |
49 | *edp_num = 0; |
50 | for (i = 0; i < dc->link_count; i++) { |
51 | // report any eDP links, even unconnected DDI's |
52 | if (!dc->links[i]) |
53 | continue; |
54 | if (dc->links[i]->connector_signal == SIGNAL_TYPE_EDP) { |
55 | edp_links[*edp_num] = dc->links[i]; |
56 | if (++(*edp_num) == MAX_NUM_EDP) |
57 | return; |
58 | } |
59 | } |
60 | } |
61 | |
62 | bool dc_get_edp_link_panel_inst(const struct dc *dc, |
63 | const struct dc_link *link, |
64 | unsigned int *inst_out) |
65 | { |
66 | struct dc_link *edp_links[MAX_NUM_EDP]; |
67 | int edp_num, i; |
68 | |
69 | *inst_out = 0; |
70 | if (link->connector_signal != SIGNAL_TYPE_EDP) |
71 | return false; |
72 | dc_get_edp_links(dc, edp_links, edp_num: &edp_num); |
73 | for (i = 0; i < edp_num; i++) { |
74 | if (link == edp_links[i]) |
75 | break; |
76 | (*inst_out)++; |
77 | } |
78 | return true; |
79 | } |
80 | |
81 | bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason) |
82 | { |
83 | return link->dc->link_srv->detect_link(link, reason); |
84 | } |
85 | |
86 | bool dc_link_detect_connection_type(struct dc_link *link, |
87 | enum dc_connection_type *type) |
88 | { |
89 | return link->dc->link_srv->detect_connection_type(link, type); |
90 | } |
91 | |
92 | const struct dc_link_status *dc_link_get_status(const struct dc_link *link) |
93 | { |
94 | return link->dc->link_srv->get_status(link); |
95 | } |
96 | |
97 | /* return true if the connected receiver supports the hdcp version */ |
98 | bool dc_link_is_hdcp14(struct dc_link *link, enum signal_type signal) |
99 | { |
100 | return link->dc->link_srv->is_hdcp1x_supported(link, signal); |
101 | } |
102 | |
103 | bool dc_link_is_hdcp22(struct dc_link *link, enum signal_type signal) |
104 | { |
105 | return link->dc->link_srv->is_hdcp2x_supported(link, signal); |
106 | } |
107 | |
108 | void dc_link_clear_dprx_states(struct dc_link *link) |
109 | { |
110 | link->dc->link_srv->clear_dprx_states(link); |
111 | } |
112 | |
113 | bool dc_link_reset_cur_dp_mst_topology(struct dc_link *link) |
114 | { |
115 | return link->dc->link_srv->reset_cur_dp_mst_topology(link); |
116 | } |
117 | |
118 | uint32_t dc_link_bandwidth_kbps( |
119 | const struct dc_link *link, |
120 | const struct dc_link_settings *link_settings) |
121 | { |
122 | return link->dc->link_srv->dp_link_bandwidth_kbps(link, link_settings); |
123 | } |
124 | |
125 | void dc_get_cur_link_res_map(const struct dc *dc, uint32_t *map) |
126 | { |
127 | dc->link_srv->get_cur_res_map(dc, map); |
128 | } |
129 | |
130 | void dc_restore_link_res_map(const struct dc *dc, uint32_t *map) |
131 | { |
132 | dc->link_srv->restore_res_map(dc, map); |
133 | } |
134 | |
135 | bool dc_link_update_dsc_config(struct pipe_ctx *pipe_ctx) |
136 | { |
137 | struct dc_link *link = pipe_ctx->stream->link; |
138 | |
139 | return link->dc->link_srv->update_dsc_config(pipe_ctx); |
140 | } |
141 | |
142 | bool dc_is_oem_i2c_device_present( |
143 | struct dc *dc, |
144 | size_t slave_address) |
145 | { |
146 | if (dc->res_pool->oem_device) |
147 | return dce_i2c_oem_device_present( |
148 | pool: dc->res_pool, |
149 | ddc: dc->res_pool->oem_device, |
150 | slave_address); |
151 | |
152 | return false; |
153 | } |
154 | |
155 | bool dc_submit_i2c( |
156 | struct dc *dc, |
157 | uint32_t link_index, |
158 | struct i2c_command *cmd) |
159 | { |
160 | |
161 | struct dc_link *link = dc->links[link_index]; |
162 | struct ddc_service *ddc = link->ddc; |
163 | |
164 | return dce_i2c_submit_command( |
165 | pool: dc->res_pool, |
166 | ddc: ddc->ddc_pin, |
167 | cmd); |
168 | } |
169 | |
170 | bool dc_submit_i2c_oem( |
171 | struct dc *dc, |
172 | struct i2c_command *cmd) |
173 | { |
174 | struct ddc_service *ddc = dc->res_pool->oem_device; |
175 | |
176 | if (ddc) |
177 | return dce_i2c_submit_command( |
178 | pool: dc->res_pool, |
179 | ddc: ddc->ddc_pin, |
180 | cmd); |
181 | |
182 | return false; |
183 | } |
184 | |
185 | void dc_link_dp_handle_automated_test(struct dc_link *link) |
186 | { |
187 | link->dc->link_srv->dp_handle_automated_test(link); |
188 | } |
189 | |
190 | bool dc_link_dp_set_test_pattern( |
191 | struct dc_link *link, |
192 | enum dp_test_pattern test_pattern, |
193 | enum dp_test_pattern_color_space test_pattern_color_space, |
194 | const struct link_training_settings *p_link_settings, |
195 | const unsigned char *p_custom_pattern, |
196 | unsigned int cust_pattern_size) |
197 | { |
198 | return link->dc->link_srv->dp_set_test_pattern(link, test_pattern, |
199 | test_pattern_color_space, p_link_settings, |
200 | p_custom_pattern, cust_pattern_size); |
201 | } |
202 | |
203 | void dc_link_set_drive_settings(struct dc *dc, |
204 | struct link_training_settings *lt_settings, |
205 | struct dc_link *link) |
206 | { |
207 | struct link_resource link_res; |
208 | |
209 | dc->link_srv->get_cur_link_res(link, &link_res); |
210 | dc->link_srv->dp_set_drive_settings(link, &link_res, lt_settings); |
211 | } |
212 | |
213 | void dc_link_set_preferred_link_settings(struct dc *dc, |
214 | struct dc_link_settings *link_setting, |
215 | struct dc_link *link) |
216 | { |
217 | dc->link_srv->dp_set_preferred_link_settings(dc, link_setting, link); |
218 | } |
219 | |
220 | void dc_link_set_preferred_training_settings(struct dc *dc, |
221 | struct dc_link_settings *link_setting, |
222 | struct dc_link_training_overrides *lt_overrides, |
223 | struct dc_link *link, |
224 | bool skip_immediate_retrain) |
225 | { |
226 | dc->link_srv->dp_set_preferred_training_settings(dc, link_setting, |
227 | lt_overrides, link, skip_immediate_retrain); |
228 | } |
229 | |
230 | bool dc_dp_trace_is_initialized(struct dc_link *link) |
231 | { |
232 | return link->dc->link_srv->dp_trace_is_initialized(link); |
233 | } |
234 | |
235 | void dc_dp_trace_set_is_logged_flag(struct dc_link *link, |
236 | bool in_detection, |
237 | bool is_logged) |
238 | { |
239 | link->dc->link_srv->dp_trace_set_is_logged_flag(link, in_detection, is_logged); |
240 | } |
241 | |
242 | bool dc_dp_trace_is_logged(struct dc_link *link, bool in_detection) |
243 | { |
244 | return link->dc->link_srv->dp_trace_is_logged(link, in_detection); |
245 | } |
246 | |
247 | unsigned long long dc_dp_trace_get_lt_end_timestamp(struct dc_link *link, |
248 | bool in_detection) |
249 | { |
250 | return link->dc->link_srv->dp_trace_get_lt_end_timestamp(link, in_detection); |
251 | } |
252 | |
253 | const struct dp_trace_lt_counts *dc_dp_trace_get_lt_counts(struct dc_link *link, |
254 | bool in_detection) |
255 | { |
256 | return link->dc->link_srv->dp_trace_get_lt_counts(link, in_detection); |
257 | } |
258 | |
259 | unsigned int dc_dp_trace_get_link_loss_count(struct dc_link *link) |
260 | { |
261 | return link->dc->link_srv->dp_trace_get_link_loss_count(link); |
262 | } |
263 | |
264 | struct dc_sink *dc_link_add_remote_sink( |
265 | struct dc_link *link, |
266 | const uint8_t *edid, |
267 | int len, |
268 | struct dc_sink_init_data *init_data) |
269 | { |
270 | return link->dc->link_srv->add_remote_sink(link, edid, len, init_data); |
271 | } |
272 | |
273 | void dc_link_remove_remote_sink(struct dc_link *link, struct dc_sink *sink) |
274 | { |
275 | link->dc->link_srv->remove_remote_sink(link, sink); |
276 | } |
277 | |
278 | int dc_link_aux_transfer_raw(struct ddc_service *ddc, |
279 | struct aux_payload *payload, |
280 | enum aux_return_code_type *operation_result) |
281 | { |
282 | const struct dc *dc = ddc->link->dc; |
283 | |
284 | return dc->link_srv->aux_transfer_raw( |
285 | ddc, payload, operation_result); |
286 | } |
287 | |
288 | uint32_t dc_link_bw_kbps_from_raw_frl_link_rate_data(const struct dc *dc, uint8_t bw) |
289 | { |
290 | return dc->link_srv->bw_kbps_from_raw_frl_link_rate_data(bw); |
291 | } |
292 | |
293 | bool dc_link_decide_edp_link_settings(struct dc_link *link, |
294 | struct dc_link_settings *link_setting, uint32_t req_bw) |
295 | { |
296 | return link->dc->link_srv->edp_decide_link_settings(link, link_setting, req_bw); |
297 | } |
298 | |
299 | |
300 | bool dc_link_dp_get_max_link_enc_cap(const struct dc_link *link, |
301 | struct dc_link_settings *max_link_enc_cap) |
302 | { |
303 | return link->dc->link_srv->dp_get_max_link_enc_cap(link, max_link_enc_cap); |
304 | } |
305 | |
306 | enum dp_link_encoding dc_link_dp_mst_decide_link_encoding_format( |
307 | const struct dc_link *link) |
308 | { |
309 | return link->dc->link_srv->mst_decide_link_encoding_format(link); |
310 | } |
311 | |
312 | const struct dc_link_settings *dc_link_get_link_cap(const struct dc_link *link) |
313 | { |
314 | return link->dc->link_srv->dp_get_verified_link_cap(link); |
315 | } |
316 | |
317 | enum dc_link_encoding_format dc_link_get_highest_encoding_format(const struct dc_link *link) |
318 | { |
319 | if (dc_is_dp_signal(signal: link->connector_signal)) { |
320 | if (link->dpcd_caps.dongle_type >= DISPLAY_DONGLE_DP_DVI_DONGLE && |
321 | link->dpcd_caps.dongle_type <= DISPLAY_DONGLE_DP_HDMI_MISMATCHED_DONGLE) |
322 | return DC_LINK_ENCODING_HDMI_TMDS; |
323 | else if (link->dc->link_srv->dp_get_encoding_format(&link->verified_link_cap) == |
324 | DP_8b_10b_ENCODING) |
325 | return DC_LINK_ENCODING_DP_8b_10b; |
326 | else if (link->dc->link_srv->dp_get_encoding_format(&link->verified_link_cap) == |
327 | DP_128b_132b_ENCODING) |
328 | return DC_LINK_ENCODING_DP_128b_132b; |
329 | } else if (dc_is_hdmi_signal(signal: link->connector_signal)) { |
330 | } |
331 | |
332 | return DC_LINK_ENCODING_UNSPECIFIED; |
333 | } |
334 | |
335 | bool dc_link_is_dp_sink_present(struct dc_link *link) |
336 | { |
337 | return link->dc->link_srv->dp_is_sink_present(link); |
338 | } |
339 | |
340 | bool dc_link_is_fec_supported(const struct dc_link *link) |
341 | { |
342 | return link->dc->link_srv->dp_is_fec_supported(link); |
343 | } |
344 | |
345 | void dc_link_overwrite_extended_receiver_cap( |
346 | struct dc_link *link) |
347 | { |
348 | link->dc->link_srv->dp_overwrite_extended_receiver_cap(link); |
349 | } |
350 | |
351 | bool dc_link_should_enable_fec(const struct dc_link *link) |
352 | { |
353 | return link->dc->link_srv->dp_should_enable_fec(link); |
354 | } |
355 | |
356 | int dc_link_dp_dpia_handle_usb4_bandwidth_allocation_for_link( |
357 | struct dc_link *link, int peak_bw) |
358 | { |
359 | return link->dc->link_srv->dpia_handle_usb4_bandwidth_allocation_for_link(link, peak_bw); |
360 | } |
361 | |
362 | void dc_link_handle_usb4_bw_alloc_response(struct dc_link *link, uint8_t bw, uint8_t result) |
363 | { |
364 | link->dc->link_srv->dpia_handle_bw_alloc_response(link, bw, result); |
365 | } |
366 | |
367 | bool dc_link_check_link_loss_status( |
368 | struct dc_link *link, |
369 | union hpd_irq_data *hpd_irq_dpcd_data) |
370 | { |
371 | return link->dc->link_srv->dp_parse_link_loss_status(link, hpd_irq_dpcd_data); |
372 | } |
373 | |
374 | bool dc_link_dp_allow_hpd_rx_irq(const struct dc_link *link) |
375 | { |
376 | return link->dc->link_srv->dp_should_allow_hpd_rx_irq(link); |
377 | } |
378 | |
379 | void dc_link_dp_handle_link_loss(struct dc_link *link) |
380 | { |
381 | link->dc->link_srv->dp_handle_link_loss(link); |
382 | } |
383 | |
384 | enum dc_status dc_link_dp_read_hpd_rx_irq_data( |
385 | struct dc_link *link, |
386 | union hpd_irq_data *irq_data) |
387 | { |
388 | return link->dc->link_srv->dp_read_hpd_rx_irq_data(link, irq_data); |
389 | } |
390 | |
391 | bool dc_link_handle_hpd_rx_irq(struct dc_link *link, |
392 | union hpd_irq_data *out_hpd_irq_dpcd_data, bool *out_link_loss, |
393 | bool defer_handling, bool *has_left_work) |
394 | { |
395 | return link->dc->link_srv->dp_handle_hpd_rx_irq(link, out_hpd_irq_dpcd_data, |
396 | out_link_loss, defer_handling, has_left_work); |
397 | } |
398 | |
399 | void dc_link_dp_receiver_power_ctrl(struct dc_link *link, bool on) |
400 | { |
401 | link->dc->link_srv->dpcd_write_rx_power_ctrl(link, on); |
402 | } |
403 | |
404 | enum lttpr_mode dc_link_decide_lttpr_mode(struct dc_link *link, |
405 | struct dc_link_settings *link_setting) |
406 | { |
407 | return link->dc->link_srv->dp_decide_lttpr_mode(link, link_setting); |
408 | } |
409 | |
410 | void dc_link_edp_panel_backlight_power_on(struct dc_link *link, bool wait_for_hpd) |
411 | { |
412 | link->dc->link_srv->edp_panel_backlight_power_on(link, wait_for_hpd); |
413 | } |
414 | |
415 | int dc_link_get_backlight_level(const struct dc_link *link) |
416 | { |
417 | return link->dc->link_srv->edp_get_backlight_level(link); |
418 | } |
419 | |
420 | bool dc_link_get_backlight_level_nits(struct dc_link *link, |
421 | uint32_t *backlight_millinits_avg, |
422 | uint32_t *backlight_millinits_peak) |
423 | { |
424 | return link->dc->link_srv->edp_get_backlight_level_nits(link, |
425 | backlight_millinits_avg, |
426 | backlight_millinits_peak); |
427 | } |
428 | |
429 | bool dc_link_set_backlight_level(const struct dc_link *link, |
430 | uint32_t backlight_pwm_u16_16, |
431 | uint32_t frame_ramp) |
432 | { |
433 | return link->dc->link_srv->edp_set_backlight_level(link, |
434 | backlight_pwm_u16_16, frame_ramp); |
435 | } |
436 | |
437 | bool dc_link_set_backlight_level_nits(struct dc_link *link, |
438 | bool isHDR, |
439 | uint32_t backlight_millinits, |
440 | uint32_t transition_time_in_ms) |
441 | { |
442 | return link->dc->link_srv->edp_set_backlight_level_nits(link, isHDR, |
443 | backlight_millinits, transition_time_in_ms); |
444 | } |
445 | |
446 | int dc_link_get_target_backlight_pwm(const struct dc_link *link) |
447 | { |
448 | return link->dc->link_srv->edp_get_target_backlight_pwm(link); |
449 | } |
450 | |
451 | bool dc_link_get_psr_state(const struct dc_link *link, enum dc_psr_state *state) |
452 | { |
453 | return link->dc->link_srv->edp_get_psr_state(link, state); |
454 | } |
455 | |
456 | bool dc_link_set_psr_allow_active(struct dc_link *link, const bool *allow_active, |
457 | bool wait, bool force_static, const unsigned int *power_opts) |
458 | { |
459 | return link->dc->link_srv->edp_set_psr_allow_active(link, allow_active, wait, |
460 | force_static, power_opts); |
461 | } |
462 | |
463 | bool dc_link_setup_psr(struct dc_link *link, |
464 | const struct dc_stream_state *stream, struct psr_config *psr_config, |
465 | struct psr_context *psr_context) |
466 | { |
467 | return link->dc->link_srv->edp_setup_psr(link, stream, psr_config, psr_context); |
468 | } |
469 | |
470 | bool dc_link_set_replay_allow_active(struct dc_link *link, const bool *allow_active, |
471 | bool wait, bool force_static, const unsigned int *power_opts) |
472 | { |
473 | return link->dc->link_srv->edp_set_replay_allow_active(link, allow_active, wait, |
474 | force_static, power_opts); |
475 | } |
476 | |
477 | bool dc_link_get_replay_state(const struct dc_link *link, uint64_t *state) |
478 | { |
479 | return link->dc->link_srv->edp_get_replay_state(link, state); |
480 | } |
481 | |
482 | bool dc_link_wait_for_t12(struct dc_link *link) |
483 | { |
484 | return link->dc->link_srv->edp_wait_for_t12(link); |
485 | } |
486 | |
487 | bool dc_link_get_hpd_state(struct dc_link *link) |
488 | { |
489 | return link->dc->link_srv->get_hpd_state(link); |
490 | } |
491 | |
492 | void dc_link_enable_hpd(const struct dc_link *link) |
493 | { |
494 | link->dc->link_srv->enable_hpd(link); |
495 | } |
496 | |
497 | void dc_link_disable_hpd(const struct dc_link *link) |
498 | { |
499 | link->dc->link_srv->disable_hpd(link); |
500 | } |
501 | |
502 | void dc_link_enable_hpd_filter(struct dc_link *link, bool enable) |
503 | { |
504 | link->dc->link_srv->enable_hpd_filter(link, enable); |
505 | } |
506 | |
507 | bool dc_link_dp_dpia_validate(struct dc *dc, const struct dc_stream_state *streams, const unsigned int count) |
508 | { |
509 | return dc->link_srv->validate_dpia_bandwidth(streams, count); |
510 | } |
511 | |