1/* SPDX-License-Identifier: MIT */
2/*
3 * Copyright 2023 Advanced Micro Devices, Inc.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
19 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21 * OTHER DEALINGS IN THE SOFTWARE.
22 *
23 */
24
25
26#include "dc_bios_types.h"
27#include "dcn30/dcn30_dio_stream_encoder.h"
28#include "dcn314/dcn314_dio_stream_encoder.h"
29#include "dcn32/dcn32_dio_stream_encoder.h"
30#include "dcn35_dio_stream_encoder.h"
31#include "reg_helper.h"
32#include "hw_shared.h"
33#include "link.h"
34#include "dpcd_defs.h"
35
36#define DC_LOGGER \
37 enc1->base.ctx->logger
38
39#define REG(reg)\
40 (enc1->regs->reg)
41
42#undef FN
43#define FN(reg_name, field_name) \
44 enc1->se_shift->field_name, enc1->se_mask->field_name
45
46#define VBI_LINE_0 0
47#define HDMI_CLOCK_CHANNEL_RATE_MORE_340M 340000
48
49#define CTX \
50 enc1->base.ctx
51/* setup stream encoder in dvi mode */
52static void enc35_stream_encoder_dvi_set_stream_attribute(
53 struct stream_encoder *enc,
54 struct dc_crtc_timing *crtc_timing,
55 bool is_dual_link)
56{
57 struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
58
59 if (!enc->ctx->dc->debug.avoid_vbios_exec_table) {
60 struct bp_encoder_control cntl = {0};
61
62 cntl.action = ENCODER_CONTROL_SETUP;
63 cntl.engine_id = enc1->base.id;
64 cntl.signal = is_dual_link ?
65 SIGNAL_TYPE_DVI_DUAL_LINK : SIGNAL_TYPE_DVI_SINGLE_LINK;
66 cntl.enable_dp_audio = false;
67 cntl.pixel_clock = crtc_timing->pix_clk_100hz / 10;
68 cntl.lanes_number = (is_dual_link) ? LANE_COUNT_EIGHT : LANE_COUNT_FOUR;
69
70 if (enc1->base.bp->funcs->encoder_control(
71 enc1->base.bp, &cntl) != BP_RESULT_OK)
72 return;
73
74 } else {
75
76 //Set pattern for clock channel, default vlue 0x63 does not work
77 REG_UPDATE(DIG_CLOCK_PATTERN, DIG_CLOCK_PATTERN, 0x1F);
78
79 //DIG_BE_TMDS_DVI_MODE : TMDS-DVI mode is already set in link_encoder_setup
80
81 //DIG_SOURCE_SELECT is already set in dig_connect_to_otg
82
83 /* DIG_START is removed from the register spec */
84 }
85
86 ASSERT(crtc_timing->pixel_encoding == PIXEL_ENCODING_RGB);
87 ASSERT(crtc_timing->display_color_depth == COLOR_DEPTH_888);
88 enc1_stream_encoder_set_stream_attribute_helper(enc1, crtc_timing);
89}
90/* setup stream encoder in hdmi mode */
91static void enc35_stream_encoder_hdmi_set_stream_attribute(
92 struct stream_encoder *enc,
93 struct dc_crtc_timing *crtc_timing,
94 int actual_pix_clk_khz,
95 bool enable_audio)
96{
97 struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
98
99 if (!enc->ctx->dc->debug.avoid_vbios_exec_table) {
100 struct bp_encoder_control cntl = {0};
101
102 cntl.action = ENCODER_CONTROL_SETUP;
103 cntl.engine_id = enc1->base.id;
104 cntl.signal = SIGNAL_TYPE_HDMI_TYPE_A;
105 cntl.enable_dp_audio = enable_audio;
106 cntl.pixel_clock = actual_pix_clk_khz;
107 cntl.lanes_number = LANE_COUNT_FOUR;
108
109 if (enc1->base.bp->funcs->encoder_control(
110 enc1->base.bp, &cntl) != BP_RESULT_OK)
111 return;
112
113 } else {
114
115 //Set pattern for clock channel, default vlue 0x63 does not work
116 REG_UPDATE(DIG_CLOCK_PATTERN, DIG_CLOCK_PATTERN, 0x1F);
117
118 //DIG_BE_TMDS_HDMI_MODE : TMDS-HDMI mode is already set in link_encoder_setup
119
120 //DIG_SOURCE_SELECT is already set in dig_connect_to_otg
121
122 /* DIG_START is removed from the register spec */
123 enc314_enable_fifo(enc);
124 }
125
126 /* Configure pixel encoding */
127 enc1_stream_encoder_set_stream_attribute_helper(enc1, crtc_timing);
128
129 /* setup HDMI engine */
130 REG_UPDATE_6(HDMI_CONTROL,
131 HDMI_PACKET_GEN_VERSION, 1,
132 HDMI_KEEPOUT_MODE, 1,
133 HDMI_DEEP_COLOR_ENABLE, 0,
134 HDMI_DATA_SCRAMBLE_EN, 0,
135 HDMI_NO_EXTRA_NULL_PACKET_FILLED, 1,
136 HDMI_CLOCK_CHANNEL_RATE, 0);
137
138 /* Configure color depth */
139 switch (crtc_timing->display_color_depth) {
140 case COLOR_DEPTH_888:
141 REG_UPDATE(HDMI_CONTROL, HDMI_DEEP_COLOR_DEPTH, 0);
142 break;
143 case COLOR_DEPTH_101010:
144 if (crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR422) {
145 REG_UPDATE_2(HDMI_CONTROL,
146 HDMI_DEEP_COLOR_DEPTH, 1,
147 HDMI_DEEP_COLOR_ENABLE, 0);
148 } else {
149 REG_UPDATE_2(HDMI_CONTROL,
150 HDMI_DEEP_COLOR_DEPTH, 1,
151 HDMI_DEEP_COLOR_ENABLE, 1);
152 }
153 break;
154 case COLOR_DEPTH_121212:
155 if (crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR422) {
156 REG_UPDATE_2(HDMI_CONTROL,
157 HDMI_DEEP_COLOR_DEPTH, 2,
158 HDMI_DEEP_COLOR_ENABLE, 0);
159 } else {
160 REG_UPDATE_2(HDMI_CONTROL,
161 HDMI_DEEP_COLOR_DEPTH, 2,
162 HDMI_DEEP_COLOR_ENABLE, 1);
163 }
164 break;
165 case COLOR_DEPTH_161616:
166 REG_UPDATE_2(HDMI_CONTROL,
167 HDMI_DEEP_COLOR_DEPTH, 3,
168 HDMI_DEEP_COLOR_ENABLE, 1);
169 break;
170 default:
171 break;
172 }
173
174 if (actual_pix_clk_khz >= HDMI_CLOCK_CHANNEL_RATE_MORE_340M) {
175 /* enable HDMI data scrambler
176 * HDMI_CLOCK_CHANNEL_RATE_MORE_340M
177 * Clock channel frequency is 1/4 of character rate.
178 */
179 REG_UPDATE_2(HDMI_CONTROL,
180 HDMI_DATA_SCRAMBLE_EN, 1,
181 HDMI_CLOCK_CHANNEL_RATE, 1);
182 } else if (crtc_timing->flags.LTE_340MCSC_SCRAMBLE) {
183
184 /* TODO: New feature for DCE11, still need to implement */
185
186 /* enable HDMI data scrambler
187 * HDMI_CLOCK_CHANNEL_FREQ_EQUAL_TO_CHAR_RATE
188 * Clock channel frequency is the same
189 * as character rate
190 */
191 REG_UPDATE_2(HDMI_CONTROL,
192 HDMI_DATA_SCRAMBLE_EN, 1,
193 HDMI_CLOCK_CHANNEL_RATE, 0);
194 }
195
196
197 /* Enable transmission of General Control packet on every frame */
198 REG_UPDATE_3(HDMI_VBI_PACKET_CONTROL,
199 HDMI_GC_CONT, 1,
200 HDMI_GC_SEND, 1,
201 HDMI_NULL_SEND, 1);
202
203 /* Disable Audio Content Protection packet transmission */
204 REG_UPDATE(HDMI_VBI_PACKET_CONTROL, HDMI_ACP_SEND, 0);
205
206 /* following belongs to audio */
207 /* Enable Audio InfoFrame packet transmission. */
208 REG_UPDATE(HDMI_INFOFRAME_CONTROL0, HDMI_AUDIO_INFO_SEND, 1);
209
210 /* update double-buffered AUDIO_INFO registers immediately */
211 ASSERT(enc->afmt);
212 enc->afmt->funcs->audio_info_immediate_update(enc->afmt);
213
214 /* Select line number on which to send Audio InfoFrame packets */
215 REG_UPDATE(HDMI_INFOFRAME_CONTROL1, HDMI_AUDIO_INFO_LINE,
216 VBI_LINE_0 + 2);
217
218 /* set HDMI GC AVMUTE */
219 REG_UPDATE(HDMI_GC, HDMI_GC_AVMUTE, 0);
220 switch (crtc_timing->pixel_encoding) {
221 case PIXEL_ENCODING_YCBCR422:
222 REG_UPDATE(HDMI_CONTROL, TMDS_PIXEL_ENCODING, 1);
223 break;
224 default:
225 REG_UPDATE(HDMI_CONTROL, TMDS_PIXEL_ENCODING, 0);
226 break;
227 }
228 REG_UPDATE(HDMI_CONTROL, TMDS_COLOR_FORMAT, 0);
229}
230
231
232
233static void enc35_stream_encoder_enable(
234 struct stream_encoder *enc,
235 enum signal_type signal,
236 bool enable)
237{
238 struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
239
240 if (enable) {
241 switch (signal) {
242 case SIGNAL_TYPE_DVI_SINGLE_LINK:
243 case SIGNAL_TYPE_DVI_DUAL_LINK:
244 /* TMDS-DVI */
245 REG_UPDATE(DIG_FE_CLK_CNTL, DIG_FE_MODE, 2);
246 break;
247 case SIGNAL_TYPE_HDMI_TYPE_A:
248 /* TMDS-HDMI */
249 REG_UPDATE(DIG_FE_CLK_CNTL, DIG_FE_MODE, 3);
250 break;
251 case SIGNAL_TYPE_DISPLAY_PORT_MST:
252 /* DP MST */
253 REG_UPDATE(DIG_FE_CLK_CNTL, DIG_FE_MODE, 5);
254 break;
255 case SIGNAL_TYPE_EDP:
256 case SIGNAL_TYPE_DISPLAY_PORT:
257 /* DP SST */
258 REG_UPDATE(DIG_FE_CLK_CNTL, DIG_FE_MODE, 0);
259 break;
260 default:
261 /* invalid mode ! */
262 ASSERT_CRITICAL(false);
263 }
264 }
265}
266
267static bool is_two_pixels_per_containter(const struct dc_crtc_timing *timing)
268{
269 bool two_pix = timing->pixel_encoding == PIXEL_ENCODING_YCBCR420;
270
271 two_pix = two_pix || (timing->flags.DSC && timing->pixel_encoding == PIXEL_ENCODING_YCBCR422
272 && !timing->dsc_cfg.ycbcr422_simple);
273 return two_pix;
274}
275
276static bool is_h_timing_divisible_by_2(const struct dc_crtc_timing *timing)
277{
278 /* math borrowed from function of same name in inc/resource
279 * checks if h_timing is divisible by 2
280 */
281
282 bool divisible = false;
283 uint16_t h_blank_start = 0;
284 uint16_t h_blank_end = 0;
285
286 if (timing) {
287 h_blank_start = timing->h_total - timing->h_front_porch;
288 h_blank_end = h_blank_start - timing->h_addressable;
289
290 /* HTOTAL, Hblank start/end, and Hsync start/end all must be
291 * divisible by 2 in order for the horizontal timing params
292 * to be considered divisible by 2. Hsync start is always 0.
293 */
294 divisible = (timing->h_total % 2 == 0) &&
295 (h_blank_start % 2 == 0) &&
296 (h_blank_end % 2 == 0) &&
297 (timing->h_sync_width % 2 == 0);
298 }
299 return divisible;
300}
301
302static bool is_dp_dig_pixel_rate_div_policy(struct dc *dc, const struct dc_crtc_timing *timing)
303{
304 /* should be functionally the same as dcn32_is_dp_dig_pixel_rate_div_policy for DP encoders*/
305 return is_h_timing_divisible_by_2(timing) &&
306 dc->debug.enable_dp_dig_pixel_rate_div_policy;
307}
308
309static void enc35_stream_encoder_dp_unblank(
310 struct dc_link *link,
311 struct stream_encoder *enc,
312 const struct encoder_unblank_param *param)
313{
314 struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
315 struct dc *dc = enc->ctx->dc;
316
317 if (param->link_settings.link_rate != LINK_RATE_UNKNOWN) {
318 uint32_t n_vid = 0x8000;
319 uint32_t m_vid;
320 uint32_t n_multiply = 0;
321 uint32_t pix_per_cycle = 0;
322 uint64_t m_vid_l = n_vid;
323
324 /* YCbCr 4:2:0 : Computed VID_M will be 2X the input rate */
325 if (is_two_pixels_per_containter(timing: &param->timing) || param->opp_cnt > 1
326 || is_dp_dig_pixel_rate_div_policy(dc, timing: &param->timing)) {
327 /*this logic should be the same in get_pixel_clock_parameters() */
328 n_multiply = 1;
329 pix_per_cycle = 1;
330 }
331 /* M / N = Fstream / Flink
332 * m_vid / n_vid = pixel rate / link rate
333 */
334
335 m_vid_l *= param->timing.pix_clk_100hz / 10;
336 m_vid_l = div_u64(dividend: m_vid_l,
337 divisor: param->link_settings.link_rate
338 * LINK_RATE_REF_FREQ_IN_KHZ);
339
340 m_vid = (uint32_t) m_vid_l;
341
342 /* enable auto measurement */
343
344 REG_UPDATE(DP_VID_TIMING, DP_VID_M_N_GEN_EN, 0);
345
346 /* auto measurement need 1 full 0x8000 symbol cycle to kick in,
347 * therefore program initial value for Mvid and Nvid
348 */
349
350 REG_UPDATE(DP_VID_N, DP_VID_N, n_vid);
351
352 REG_UPDATE(DP_VID_M, DP_VID_M, m_vid);
353
354 REG_UPDATE_2(DP_VID_TIMING,
355 DP_VID_M_N_GEN_EN, 1,
356 DP_VID_N_MUL, n_multiply);
357
358 REG_UPDATE(DP_PIXEL_FORMAT,
359 DP_PIXEL_PER_CYCLE_PROCESSING_MODE,
360 pix_per_cycle);
361 }
362
363 /* make sure stream is disabled before resetting steer fifo */
364 REG_UPDATE(DP_VID_STREAM_CNTL, DP_VID_STREAM_ENABLE, false);
365 REG_WAIT(DP_VID_STREAM_CNTL, DP_VID_STREAM_STATUS, 0, 10, 5000);
366
367 /* DIG_START is removed from the register spec */
368
369 /* switch DP encoder to CRTC data, but reset it the fifo first. It may happen
370 * that it overflows during mode transition, and sometimes doesn't recover.
371 */
372 REG_UPDATE(DP_STEER_FIFO, DP_STEER_FIFO_RESET, 1);
373 udelay(10);
374
375 REG_UPDATE(DP_STEER_FIFO, DP_STEER_FIFO_RESET, 0);
376
377 /* wait 100us for DIG/DP logic to prime
378 * (i.e. a few video lines)
379 */
380 udelay(100);
381
382 /* the hardware would start sending video at the start of the next DP
383 * frame (i.e. rising edge of the vblank).
384 * NOTE: We used to program DP_VID_STREAM_DIS_DEFER = 2 here, but this
385 * register has no effect on enable transition! HW always makes sure
386 * VID_STREAM enable at start of next frame, and this is not
387 * programmable
388 */
389
390 REG_UPDATE(DP_VID_STREAM_CNTL, DP_VID_STREAM_ENABLE, true);
391
392 /*
393 * DIG Resync FIFO now needs to be explicitly enabled.
394 * This should come after DP_VID_STREAM_ENABLE per HW docs.
395 */
396 enc314_enable_fifo(enc);
397
398 link->dc->link_srv->dp_trace_source_sequence(link, DPCD_SOURCE_SEQ_AFTER_ENABLE_DP_VID_STREAM);
399}
400
401static void enc35_stream_encoder_map_to_link(
402 struct stream_encoder *enc,
403 uint32_t stream_enc_inst,
404 uint32_t link_enc_inst)
405{
406 struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
407
408 ASSERT(stream_enc_inst < 5 && link_enc_inst < 5);
409 REG_UPDATE(STREAM_MAPPER_CONTROL,
410 DIG_STREAM_LINK_TARGET, link_enc_inst);
411}
412
413static void enc35_reset_fifo(struct stream_encoder *enc, bool reset)
414{
415 struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
416 uint32_t reset_val = reset ? 1 : 0;
417 uint32_t is_symclk_on;
418
419 REG_UPDATE(DIG_FIFO_CTRL0, DIG_FIFO_RESET, reset_val);
420 REG_GET(DIG_FE_CLK_CNTL, DIG_FE_SYMCLK_FE_G_CLOCK_ON, &is_symclk_on);
421
422 if (is_symclk_on)
423 REG_WAIT(DIG_FIFO_CTRL0, DIG_FIFO_RESET_DONE, reset_val, 10, 5000);
424 else
425 udelay(10);
426}
427
428static void enc35_disable_fifo(struct stream_encoder *enc)
429{
430 struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
431
432 REG_UPDATE(DIG_FIFO_CTRL0, DIG_FIFO_ENABLE, 0);
433 REG_UPDATE(DIG_FE_EN_CNTL, DIG_FE_ENABLE, 0);
434 REG_UPDATE(DIG_FE_CLK_CNTL, DIG_FE_CLK_EN, 0);
435}
436
437static void enc35_enable_fifo(struct stream_encoder *enc)
438{
439 struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
440
441 REG_UPDATE(DIG_FIFO_CTRL0, DIG_FIFO_READ_START_LEVEL, 0x7);
442 REG_UPDATE(DIG_FE_CLK_CNTL, DIG_FE_CLK_EN, 1);
443 REG_UPDATE(DIG_FE_EN_CNTL, DIG_FE_ENABLE, 1);
444
445 enc35_reset_fifo(enc, reset: true);
446 enc35_reset_fifo(enc, reset: false);
447
448 REG_UPDATE(DIG_FIFO_CTRL0, DIG_FIFO_ENABLE, 1);
449}
450
451static const struct stream_encoder_funcs dcn35_str_enc_funcs = {
452 .dp_set_odm_combine =
453 enc314_dp_set_odm_combine,
454 .dp_set_stream_attribute =
455 enc2_stream_encoder_dp_set_stream_attribute,
456 .hdmi_set_stream_attribute =
457 enc35_stream_encoder_hdmi_set_stream_attribute,
458 .dvi_set_stream_attribute =
459 enc35_stream_encoder_dvi_set_stream_attribute,
460 .set_throttled_vcp_size =
461 enc1_stream_encoder_set_throttled_vcp_size,
462 .update_hdmi_info_packets =
463 enc3_stream_encoder_update_hdmi_info_packets,
464 .stop_hdmi_info_packets =
465 enc3_stream_encoder_stop_hdmi_info_packets,
466 .update_dp_info_packets_sdp_line_num =
467 enc3_stream_encoder_update_dp_info_packets_sdp_line_num,
468 .update_dp_info_packets =
469 enc3_stream_encoder_update_dp_info_packets,
470 .stop_dp_info_packets =
471 enc1_stream_encoder_stop_dp_info_packets,
472 .dp_blank =
473 enc314_stream_encoder_dp_blank,
474 .dp_unblank =
475 enc35_stream_encoder_dp_unblank,
476 .audio_mute_control = enc3_audio_mute_control,
477
478 .dp_audio_setup = enc3_se_dp_audio_setup,
479 .dp_audio_enable = enc3_se_dp_audio_enable,
480 .dp_audio_disable = enc1_se_dp_audio_disable,
481
482 .hdmi_audio_setup = enc3_se_hdmi_audio_setup,
483 .hdmi_audio_disable = enc1_se_hdmi_audio_disable,
484 .setup_stereo_sync = enc1_setup_stereo_sync,
485 .set_avmute = enc1_stream_encoder_set_avmute,
486 .dig_connect_to_otg = enc1_dig_connect_to_otg,
487 .dig_source_otg = enc1_dig_source_otg,
488
489 .dp_get_pixel_format = enc1_stream_encoder_dp_get_pixel_format,
490
491 .enc_read_state = enc314_read_state,
492 .dp_set_dsc_config = enc314_dp_set_dsc_config,
493 .dp_set_dsc_pps_info_packet = enc3_dp_set_dsc_pps_info_packet,
494 .set_dynamic_metadata = enc2_set_dynamic_metadata,
495 .hdmi_reset_stream_attribute = enc1_reset_hdmi_stream_attribute,
496 .dig_stream_enable = enc35_stream_encoder_enable,
497
498 .set_input_mode = enc314_set_dig_input_mode,
499 .enable_fifo = enc35_enable_fifo,
500 .disable_fifo = enc35_disable_fifo,
501 .map_stream_to_link = enc35_stream_encoder_map_to_link,
502};
503
504void dcn35_dio_stream_encoder_construct(
505 struct dcn10_stream_encoder *enc1,
506 struct dc_context *ctx,
507 struct dc_bios *bp,
508 enum engine_id eng_id,
509 struct vpg *vpg,
510 struct afmt *afmt,
511 const struct dcn10_stream_enc_registers *regs,
512 const struct dcn10_stream_encoder_shift *se_shift,
513 const struct dcn10_stream_encoder_mask *se_mask)
514{
515 enc1->base.funcs = &dcn35_str_enc_funcs;
516 enc1->base.ctx = ctx;
517 enc1->base.id = eng_id;
518 enc1->base.bp = bp;
519 enc1->base.vpg = vpg;
520 enc1->base.afmt = afmt;
521 enc1->regs = regs;
522 enc1->se_shift = se_shift;
523 enc1->se_mask = se_mask;
524 enc1->base.stream_enc_inst = vpg->inst;
525}
526
527

source code of linux/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_dio_stream_encoder.c