1
2
3
4#include "dm_services.h"
5#include "dc.h"
6#include "inc/core_types.h"
7#include "include/ddc_service_types.h"
8#include "include/i2caux_interface.h"
9#include "link_hwss.h"
10#include "hw_sequencer.h"
11#include "dc_link_dp.h"
12#include "dc_link_ddc.h"
13#include "dm_helpers.h"
14#include "dpcd_defs.h"
15#include "dsc.h"
16#include "resource.h"
17
18static uint8_t convert_to_count(uint8_t lttpr_repeater_count)
19{
20 switch (lttpr_repeater_count) {
21 case 0x80:
22 return 1;
23 case 0x40:
24 return 2;
25 case 0x20:
26 return 3;
27 case 0x10:
28 return 4;
29 case 0x08:
30 return 5;
31 case 0x04:
32 return 6;
33 case 0x02:
34 return 7;
35 case 0x01:
36 return 8;
37 default:
38 break;
39 }
40 return 0;
41}
42
43static inline bool is_immediate_downstream(struct dc_link *link, uint32_t offset)
44{
45 return (convert_to_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt) == offset);
46}
47
48enum dc_status core_link_read_dpcd(
49 struct dc_link *link,
50 uint32_t address,
51 uint8_t *data,
52 uint32_t size)
53{
54 if (!link->aux_access_disabled &&
55 !dm_helpers_dp_read_dpcd(link->ctx,
56 link, address, data, size)) {
57 return DC_ERROR_UNEXPECTED;
58 }
59
60 return DC_OK;
61}
62
63enum dc_status core_link_write_dpcd(
64 struct dc_link *link,
65 uint32_t address,
66 const uint8_t *data,
67 uint32_t size)
68{
69 if (!link->aux_access_disabled &&
70 !dm_helpers_dp_write_dpcd(link->ctx,
71 link, address, data, size)) {
72 return DC_ERROR_UNEXPECTED;
73 }
74
75 return DC_OK;
76}
77
78void dp_receiver_power_ctrl(struct dc_link *link, bool on)
79{
80 uint8_t state;
81
82 state = on ? DP_POWER_STATE_D0 : DP_POWER_STATE_D3;
83
84 if (link->sync_lt_in_progress)
85 return;
86
87 core_link_write_dpcd(link, DP_SET_POWER, &state,
88 sizeof(state));
89}
90
91void dp_enable_link_phy(
92 struct dc_link *link,
93 enum signal_type signal,
94 enum clock_source_id clock_source,
95 const struct dc_link_settings *link_settings)
96{
97 struct link_encoder *link_enc = link->link_enc;
98 struct dc *dc = link->ctx->dc;
99 struct dmcu *dmcu = dc->res_pool->dmcu;
100
101 struct pipe_ctx *pipes =
102 link->dc->current_state->res_ctx.pipe_ctx;
103 struct clock_source *dp_cs =
104 link->dc->res_pool->dp_clock_source;
105 unsigned int i;
106
107
108
109
110 for (i = 0; i < MAX_PIPES; i++) {
111 if (pipes[i].stream != NULL &&
112 pipes[i].stream->link == link) {
113 if (pipes[i].clock_source != NULL &&
114 pipes[i].clock_source->id != CLOCK_SOURCE_ID_DP_DTO) {
115 pipes[i].clock_source = dp_cs;
116 pipes[i].stream_res.pix_clk_params.requested_pix_clk_100hz =
117 pipes[i].stream->timing.pix_clk_100hz;
118 pipes[i].clock_source->funcs->program_pix_clk(
119 pipes[i].clock_source,
120 &pipes[i].stream_res.pix_clk_params,
121 &pipes[i].pll_settings);
122 }
123 }
124 }
125
126 if (dmcu != NULL && dmcu->funcs->lock_phy)
127 dmcu->funcs->lock_phy(dmcu);
128
129 if (dc_is_dp_sst_signal(signal)) {
130 link_enc->funcs->enable_dp_output(
131 link_enc,
132 link_settings,
133 clock_source);
134 } else {
135 link_enc->funcs->enable_dp_mst_output(
136 link_enc,
137 link_settings,
138 clock_source);
139 }
140
141 if (dmcu != NULL && dmcu->funcs->unlock_phy)
142 dmcu->funcs->unlock_phy(dmcu);
143
144 link->cur_link_settings = *link_settings;
145
146 dp_receiver_power_ctrl(link, true);
147}
148
149bool edp_receiver_ready_T9(struct dc_link *link)
150{
151 unsigned int tries = 0;
152 unsigned char sinkstatus = 0;
153 unsigned char edpRev = 0;
154 enum dc_status result = DC_OK;
155 result = core_link_read_dpcd(link, DP_EDP_DPCD_REV, &edpRev, sizeof(edpRev));
156
157
158 if (result == DC_OK && edpRev >= DP_EDP_12) {
159 do {
160 sinkstatus = 1;
161 result = core_link_read_dpcd(link, DP_SINK_STATUS, &sinkstatus, sizeof(sinkstatus));
162 if (sinkstatus == 0)
163 break;
164 if (result != DC_OK)
165 break;
166 udelay(100);
167 } while (++tries < 50);
168 }
169
170 if (link->local_sink->edid_caps.panel_patch.extra_delay_backlight_off > 0)
171 udelay(link->local_sink->edid_caps.panel_patch.extra_delay_backlight_off * 1000);
172
173 return result;
174}
175bool edp_receiver_ready_T7(struct dc_link *link)
176{
177 unsigned char sinkstatus = 0;
178 unsigned char edpRev = 0;
179 enum dc_status result = DC_OK;
180
181
182 unsigned long long enter_timestamp = 0;
183 unsigned long long finish_timestamp = 0;
184 unsigned long long time_taken_in_ns = 0;
185
186 result = core_link_read_dpcd(link, DP_EDP_DPCD_REV, &edpRev, sizeof(edpRev));
187
188 if (result == DC_OK && edpRev >= DP_EDP_12) {
189
190 enter_timestamp = dm_get_timestamp(link->ctx);
191 do {
192 sinkstatus = 0;
193 result = core_link_read_dpcd(link, DP_SINK_STATUS, &sinkstatus, sizeof(sinkstatus));
194 if (sinkstatus == 1)
195 break;
196 if (result != DC_OK)
197 break;
198 udelay(25);
199 finish_timestamp = dm_get_timestamp(link->ctx);
200 time_taken_in_ns = dm_get_elapse_time_in_ns(link->ctx, finish_timestamp, enter_timestamp);
201 } while (time_taken_in_ns < 50 * 1000000);
202 }
203
204 if (link->local_sink->edid_caps.panel_patch.extra_t7_ms > 0)
205 udelay(link->local_sink->edid_caps.panel_patch.extra_t7_ms * 1000);
206
207 return result;
208}
209
210void dp_disable_link_phy(struct dc_link *link, enum signal_type signal)
211{
212 struct dc *dc = link->ctx->dc;
213 struct dmcu *dmcu = dc->res_pool->dmcu;
214
215 if (!link->wa_flags.dp_keep_receiver_powered)
216 dp_receiver_power_ctrl(link, false);
217
218 if (signal == SIGNAL_TYPE_EDP) {
219 link->link_enc->funcs->disable_output(link->link_enc, signal);
220 link->dc->hwss.edp_power_control(link, false);
221 } else {
222 if (dmcu != NULL && dmcu->funcs->lock_phy)
223 dmcu->funcs->lock_phy(dmcu);
224
225 link->link_enc->funcs->disable_output(link->link_enc, signal);
226
227 if (dmcu != NULL && dmcu->funcs->unlock_phy)
228 dmcu->funcs->unlock_phy(dmcu);
229 }
230
231
232 memset(&link->cur_link_settings, 0,
233 sizeof(link->cur_link_settings));
234}
235
236void dp_disable_link_phy_mst(struct dc_link *link, enum signal_type signal)
237{
238
239 if (link->mst_stream_alloc_table.stream_count > 0)
240 return;
241
242 dp_disable_link_phy(link, signal);
243
244
245 dp_enable_mst_on_sink(link, false);
246}
247
248bool dp_set_hw_training_pattern(
249 struct dc_link *link,
250 enum dc_dp_training_pattern pattern,
251 uint32_t offset)
252{
253 enum dp_test_pattern test_pattern = DP_TEST_PATTERN_UNSUPPORTED;
254
255 switch (pattern) {
256 case DP_TRAINING_PATTERN_SEQUENCE_1:
257 test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN1;
258 break;
259 case DP_TRAINING_PATTERN_SEQUENCE_2:
260 test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN2;
261 break;
262 case DP_TRAINING_PATTERN_SEQUENCE_3:
263 test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN3;
264 break;
265 case DP_TRAINING_PATTERN_SEQUENCE_4:
266 test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN4;
267 break;
268 default:
269 break;
270 }
271
272 dp_set_hw_test_pattern(link, test_pattern, NULL, 0);
273
274 return true;
275}
276
277void dp_set_hw_lane_settings(
278 struct dc_link *link,
279 const struct link_training_settings *link_settings,
280 uint32_t offset)
281{
282 struct link_encoder *encoder = link->link_enc;
283
284 if (!link->is_lttpr_mode_transparent && !is_immediate_downstream(link, offset))
285 return;
286
287
288 encoder->funcs->dp_set_lane_settings(encoder, link_settings);
289}
290
291void dp_set_hw_test_pattern(
292 struct dc_link *link,
293 enum dp_test_pattern test_pattern,
294 uint8_t *custom_pattern,
295 uint32_t custom_pattern_size)
296{
297 struct encoder_set_dp_phy_pattern_param pattern_param = {0};
298 struct link_encoder *encoder = link->link_enc;
299
300 pattern_param.dp_phy_pattern = test_pattern;
301 pattern_param.custom_pattern = custom_pattern;
302 pattern_param.custom_pattern_size = custom_pattern_size;
303 pattern_param.dp_panel_mode = dp_get_panel_mode(link);
304
305 encoder->funcs->dp_set_phy_pattern(encoder, &pattern_param);
306}
307
308void dp_retrain_link_dp_test(struct dc_link *link,
309 struct dc_link_settings *link_setting,
310 bool skip_video_pattern)
311{
312 struct pipe_ctx *pipes =
313 &link->dc->current_state->res_ctx.pipe_ctx[0];
314 unsigned int i;
315
316 for (i = 0; i < MAX_PIPES; i++) {
317 if (pipes[i].stream != NULL &&
318 !pipes[i].top_pipe && !pipes[i].prev_odm_pipe &&
319 pipes[i].stream->link != NULL &&
320 pipes[i].stream_res.stream_enc != NULL &&
321 pipes[i].stream->link == link) {
322 udelay(100);
323
324 pipes[i].stream_res.stream_enc->funcs->dp_blank(
325 pipes[i].stream_res.stream_enc);
326
327
328 dp_set_hw_test_pattern(link,
329 DP_TEST_PATTERN_VIDEO_MODE, NULL, 0);
330
331 dp_receiver_power_ctrl(link, false);
332
333 link->dc->hwss.disable_stream(&pipes[i]);
334 if ((&pipes[i])->stream_res.audio && !link->dc->debug.az_endpoint_mute_only)
335 (&pipes[i])->stream_res.audio->funcs->az_disable((&pipes[i])->stream_res.audio);
336
337 link->link_enc->funcs->disable_output(
338 link->link_enc,
339 SIGNAL_TYPE_DISPLAY_PORT);
340
341
342 memset(&link->cur_link_settings, 0,
343 sizeof(link->cur_link_settings));
344
345 perform_link_training_with_retries(
346 link_setting,
347 skip_video_pattern,
348 LINK_TRAINING_ATTEMPTS,
349 &pipes[i],
350 SIGNAL_TYPE_DISPLAY_PORT);
351
352 link->dc->hwss.enable_stream(&pipes[i]);
353
354 link->dc->hwss.unblank_stream(&pipes[i],
355 link_setting);
356
357 if (pipes[i].stream_res.audio) {
358
359
360 pipes[i].stream_res.audio->funcs->az_enable(
361 pipes[i].stream_res.audio);
362
363
364
365
366 pipes[i].stream_res.stream_enc->funcs->
367 audio_mute_control(
368 pipes[i].stream_res.stream_enc, false);
369 }
370 }
371 }
372}
373
374#define DC_LOGGER \
375 dsc->ctx->logger
376static void dsc_optc_config_log(struct display_stream_compressor *dsc,
377 struct dsc_optc_config *config)
378{
379 uint32_t precision = 1 << 28;
380 uint32_t bytes_per_pixel_int = config->bytes_per_pixel / precision;
381 uint32_t bytes_per_pixel_mod = config->bytes_per_pixel % precision;
382 uint64_t ll_bytes_per_pix_fraq = bytes_per_pixel_mod;
383
384
385
386
387
388 ll_bytes_per_pix_fraq *= 10000000;
389 ll_bytes_per_pix_fraq /= precision;
390
391 DC_LOG_DSC("\tbytes_per_pixel 0x%08x (%d.%07d)",
392 config->bytes_per_pixel, bytes_per_pixel_int, (uint32_t)ll_bytes_per_pix_fraq);
393 DC_LOG_DSC("\tis_pixel_format_444 %d", config->is_pixel_format_444);
394 DC_LOG_DSC("\tslice_width %d", config->slice_width);
395}
396
397static bool dp_set_dsc_on_rx(struct pipe_ctx *pipe_ctx, bool enable)
398{
399 struct dc *dc = pipe_ctx->stream->ctx->dc;
400 struct dc_stream_state *stream = pipe_ctx->stream;
401 bool result = false;
402
403 if (dc_is_virtual_signal(stream->signal) || IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment))
404 result = true;
405 else
406 result = dm_helpers_dp_write_dsc_enable(dc->ctx, stream, enable);
407 return result;
408}
409
410
411
412
413void dp_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable)
414{
415 struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc;
416 struct dc *dc = pipe_ctx->stream->ctx->dc;
417 struct dc_stream_state *stream = pipe_ctx->stream;
418 struct pipe_ctx *odm_pipe;
419 int opp_cnt = 1;
420
421 for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
422 opp_cnt++;
423
424 if (enable) {
425 struct dsc_config dsc_cfg;
426 struct dsc_optc_config dsc_optc_cfg;
427 enum optc_dsc_mode optc_dsc_mode;
428
429
430 dsc_cfg.pic_width = (stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right) / opp_cnt;
431 dsc_cfg.pic_height = stream->timing.v_addressable + stream->timing.v_border_top + stream->timing.v_border_bottom;
432 dsc_cfg.pixel_encoding = stream->timing.pixel_encoding;
433 dsc_cfg.color_depth = stream->timing.display_color_depth;
434 dsc_cfg.is_odm = pipe_ctx->next_odm_pipe ? true : false;
435 dsc_cfg.dc_dsc_cfg = stream->timing.dsc_cfg;
436 ASSERT(dsc_cfg.dc_dsc_cfg.num_slices_h % opp_cnt == 0);
437 dsc_cfg.dc_dsc_cfg.num_slices_h /= opp_cnt;
438
439 dsc->funcs->dsc_set_config(dsc, &dsc_cfg, &dsc_optc_cfg);
440 dsc->funcs->dsc_enable(dsc, pipe_ctx->stream_res.opp->inst);
441 for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
442 struct display_stream_compressor *odm_dsc = odm_pipe->stream_res.dsc;
443
444 odm_dsc->funcs->dsc_set_config(odm_dsc, &dsc_cfg, &dsc_optc_cfg);
445 odm_dsc->funcs->dsc_enable(odm_dsc, odm_pipe->stream_res.opp->inst);
446 }
447 dsc_cfg.dc_dsc_cfg.num_slices_h *= opp_cnt;
448 dsc_cfg.pic_width *= opp_cnt;
449
450 optc_dsc_mode = dsc_optc_cfg.is_pixel_format_444 ? OPTC_DSC_ENABLED_444 : OPTC_DSC_ENABLED_NATIVE_SUBSAMPLED;
451
452
453 if (dc_is_dp_signal(stream->signal) && !IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
454 DC_LOG_DSC("Setting stream encoder DSC config for engine %d:", (int)pipe_ctx->stream_res.stream_enc->id);
455 dsc_optc_config_log(dsc, &dsc_optc_cfg);
456 pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_config(pipe_ctx->stream_res.stream_enc,
457 optc_dsc_mode,
458 dsc_optc_cfg.bytes_per_pixel,
459 dsc_optc_cfg.slice_width);
460
461
462 }
463
464
465 DC_LOG_DSC("Setting optc DSC config for tg instance %d:", pipe_ctx->stream_res.tg->inst);
466 dsc_optc_config_log(dsc, &dsc_optc_cfg);
467 pipe_ctx->stream_res.tg->funcs->set_dsc_config(pipe_ctx->stream_res.tg,
468 optc_dsc_mode,
469 dsc_optc_cfg.bytes_per_pixel,
470 dsc_optc_cfg.slice_width);
471 } else {
472
473 pipe_ctx->stream_res.tg->funcs->set_dsc_config(
474 pipe_ctx->stream_res.tg,
475 OPTC_DSC_DISABLED, 0, 0);
476
477
478 if (dc_is_dp_signal(stream->signal) && !IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
479 pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_config(
480 pipe_ctx->stream_res.stream_enc,
481 OPTC_DSC_DISABLED, 0, 0);
482
483 pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_pps_info_packet(
484 pipe_ctx->stream_res.stream_enc, false, NULL);
485 }
486
487
488 pipe_ctx->stream_res.dsc->funcs->dsc_disable(pipe_ctx->stream_res.dsc);
489 for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
490 odm_pipe->stream_res.dsc->funcs->dsc_disable(odm_pipe->stream_res.dsc);
491 }
492}
493
494bool dp_set_dsc_enable(struct pipe_ctx *pipe_ctx, bool enable)
495{
496 struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc;
497 bool result = false;
498
499 if (!pipe_ctx->stream->timing.flags.DSC)
500 goto out;
501 if (!dsc)
502 goto out;
503
504 if (enable) {
505 if (dp_set_dsc_on_rx(pipe_ctx, true)) {
506 dp_set_dsc_on_stream(pipe_ctx, true);
507 result = true;
508 }
509 } else {
510 dp_set_dsc_on_rx(pipe_ctx, false);
511 dp_set_dsc_on_stream(pipe_ctx, false);
512 result = true;
513 }
514out:
515 return result;
516}
517
518bool dp_set_dsc_pps_sdp(struct pipe_ctx *pipe_ctx, bool enable)
519{
520 struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc;
521 struct dc *dc = pipe_ctx->stream->ctx->dc;
522 struct dc_stream_state *stream = pipe_ctx->stream;
523
524 if (!pipe_ctx->stream->timing.flags.DSC || !dsc)
525 return false;
526
527 if (enable) {
528 struct dsc_config dsc_cfg;
529 uint8_t dsc_packed_pps[128];
530
531 memset(&dsc_cfg, 0, sizeof(dsc_cfg));
532 memset(dsc_packed_pps, 0, 128);
533
534
535 dsc_cfg.pic_width = stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right;
536 dsc_cfg.pic_height = stream->timing.v_addressable + stream->timing.v_border_top + stream->timing.v_border_bottom;
537 dsc_cfg.pixel_encoding = stream->timing.pixel_encoding;
538 dsc_cfg.color_depth = stream->timing.display_color_depth;
539 dsc_cfg.is_odm = pipe_ctx->next_odm_pipe ? true : false;
540 dsc_cfg.dc_dsc_cfg = stream->timing.dsc_cfg;
541
542 DC_LOG_DSC(" ");
543 dsc->funcs->dsc_get_packed_pps(dsc, &dsc_cfg, &dsc_packed_pps[0]);
544 if (dc_is_dp_signal(stream->signal) && !IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
545 DC_LOG_DSC("Setting stream encoder DSC PPS SDP for engine %d\n", (int)pipe_ctx->stream_res.stream_enc->id);
546 pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_pps_info_packet(
547 pipe_ctx->stream_res.stream_enc,
548 true,
549 &dsc_packed_pps[0]);
550 }
551 } else {
552
553 if (dc_is_dp_signal(stream->signal) && !IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
554 pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_pps_info_packet(
555 pipe_ctx->stream_res.stream_enc, false, NULL);
556 }
557 }
558
559 return true;
560}
561
562
563bool dp_update_dsc_config(struct pipe_ctx *pipe_ctx)
564{
565 struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc;
566
567 if (!pipe_ctx->stream->timing.flags.DSC)
568 return false;
569 if (!dsc)
570 return false;
571
572 dp_set_dsc_on_stream(pipe_ctx, true);
573 dp_set_dsc_pps_sdp(pipe_ctx, true);
574 return true;
575}
576
577