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