1 /*
2  * Copyright 2022 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 #include "link_hwss_dio.h"
26 #include "core_types.h"
27 #include "link_enc_cfg.h"
28 
29 void set_dio_throttled_vcp_size(struct pipe_ctx *pipe_ctx,
30 		struct fixed31_32 throttled_vcp_size)
31 {
32 	struct stream_encoder *stream_encoder = pipe_ctx->stream_res.stream_enc;
33 
34 	stream_encoder->funcs->set_throttled_vcp_size(
35 				stream_encoder,
36 				throttled_vcp_size);
37 }
38 
39 void setup_dio_stream_encoder(struct pipe_ctx *pipe_ctx)
40 {
41 	struct link_encoder *link_enc = link_enc_cfg_get_link_enc(pipe_ctx->stream->link);
42 	struct stream_encoder *stream_enc = pipe_ctx->stream_res.stream_enc;
43 
44 	link_enc->funcs->connect_dig_be_to_fe(link_enc,
45 			pipe_ctx->stream_res.stream_enc->id, true);
46 	if (dc_is_dp_signal(pipe_ctx->stream->signal))
47 		link_dp_source_sequence_trace(pipe_ctx->stream->link,
48 				DPCD_SOURCE_SEQ_AFTER_CONNECT_DIG_FE_BE);
49 	if (stream_enc->funcs->enable_fifo)
50 		stream_enc->funcs->enable_fifo(stream_enc);
51 }
52 
53 void reset_dio_stream_encoder(struct pipe_ctx *pipe_ctx)
54 {
55 	struct link_encoder *link_enc = link_enc_cfg_get_link_enc(pipe_ctx->stream->link);
56 	struct stream_encoder *stream_enc = pipe_ctx->stream_res.stream_enc;
57 
58 	if (stream_enc && stream_enc->funcs->disable_fifo)
59 		stream_enc->funcs->disable_fifo(stream_enc);
60 
61 	link_enc->funcs->connect_dig_be_to_fe(
62 			link_enc,
63 			pipe_ctx->stream_res.stream_enc->id,
64 			false);
65 	if (dc_is_dp_signal(pipe_ctx->stream->signal))
66 		link_dp_source_sequence_trace(pipe_ctx->stream->link,
67 				DPCD_SOURCE_SEQ_AFTER_DISCONNECT_DIG_FE_BE);
68 
69 }
70 
71 void setup_dio_stream_attribute(struct pipe_ctx *pipe_ctx)
72 {
73 	struct stream_encoder *stream_encoder = pipe_ctx->stream_res.stream_enc;
74 	struct dc_stream_state *stream = pipe_ctx->stream;
75 	struct dc_link *link = stream->link;
76 
77 	if (!dc_is_virtual_signal(stream->signal))
78 		stream_encoder->funcs->setup_stereo_sync(
79 				stream_encoder,
80 				pipe_ctx->stream_res.tg->inst,
81 				stream->timing.timing_3d_format != TIMING_3D_FORMAT_NONE);
82 
83 	if (dc_is_dp_signal(stream->signal))
84 		stream_encoder->funcs->dp_set_stream_attribute(
85 				stream_encoder,
86 				&stream->timing,
87 				stream->output_color_space,
88 				stream->use_vsc_sdp_for_colorimetry,
89 				link->dpcd_caps.dprx_feature.bits.SST_SPLIT_SDP_CAP);
90 	else if (dc_is_hdmi_tmds_signal(stream->signal))
91 		stream_encoder->funcs->hdmi_set_stream_attribute(
92 				stream_encoder,
93 				&stream->timing,
94 				stream->phy_pix_clk,
95 				pipe_ctx->stream_res.audio != NULL);
96 	else if (dc_is_dvi_signal(stream->signal))
97 		stream_encoder->funcs->dvi_set_stream_attribute(
98 				stream_encoder,
99 				&stream->timing,
100 				(stream->signal == SIGNAL_TYPE_DVI_DUAL_LINK) ?
101 						true : false);
102 	else if (dc_is_lvds_signal(stream->signal))
103 		stream_encoder->funcs->lvds_set_stream_attribute(
104 				stream_encoder,
105 				&stream->timing);
106 
107 	if (dc_is_dp_signal(stream->signal))
108 		link_dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_DP_STREAM_ATTR);
109 }
110 
111 void enable_dio_dp_link_output(struct dc_link *link,
112 		const struct link_resource *link_res,
113 		enum signal_type signal,
114 		enum clock_source_id clock_source,
115 		const struct dc_link_settings *link_settings)
116 {
117 	struct link_encoder *link_enc = link_enc_cfg_get_link_enc(link);
118 
119 	if (dc_is_dp_sst_signal(signal))
120 		link_enc->funcs->enable_dp_output(
121 				link_enc,
122 				link_settings,
123 				clock_source);
124 	else
125 		link_enc->funcs->enable_dp_mst_output(
126 				link_enc,
127 				link_settings,
128 				clock_source);
129 	link_dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_ENABLE_LINK_PHY);
130 }
131 
132 void disable_dio_link_output(struct dc_link *link,
133 		const struct link_resource *link_res,
134 		enum signal_type signal)
135 {
136 	struct link_encoder *link_enc = link_enc_cfg_get_link_enc(link);
137 
138 	link_enc->funcs->disable_output(link_enc, signal);
139 	link_dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_DISABLE_LINK_PHY);
140 }
141 
142 void set_dio_dp_link_test_pattern(struct dc_link *link,
143 		const struct link_resource *link_res,
144 		struct encoder_set_dp_phy_pattern_param *tp_params)
145 {
146 	struct link_encoder *link_enc = link_enc_cfg_get_link_enc(link);
147 
148 	link_enc->funcs->dp_set_phy_pattern(link_enc, tp_params);
149 	link_dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_SET_SOURCE_PATTERN);
150 }
151 
152 void set_dio_dp_lane_settings(struct dc_link *link,
153 		const struct link_resource *link_res,
154 		const struct dc_link_settings *link_settings,
155 		const struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX])
156 {
157 	struct link_encoder *link_enc = link_enc_cfg_get_link_enc(link);
158 
159 	link_enc->funcs->dp_set_lane_settings(link_enc, link_settings, lane_settings);
160 }
161 
162 static void update_dio_stream_allocation_table(struct dc_link *link,
163 		const struct link_resource *link_res,
164 		const struct link_mst_stream_allocation_table *table)
165 {
166 	struct link_encoder *link_enc = link_enc_cfg_get_link_enc(link);
167 
168 	ASSERT(link_enc);
169 	link_enc->funcs->update_mst_stream_allocation_table(link_enc, table);
170 }
171 
172 void setup_dio_audio_output(struct pipe_ctx *pipe_ctx,
173 		struct audio_output *audio_output, uint32_t audio_inst)
174 {
175 	if (dc_is_dp_signal(pipe_ctx->stream->signal))
176 		pipe_ctx->stream_res.stream_enc->funcs->dp_audio_setup(
177 				pipe_ctx->stream_res.stream_enc,
178 				audio_inst,
179 				&pipe_ctx->stream->audio_info);
180 	else
181 		pipe_ctx->stream_res.stream_enc->funcs->hdmi_audio_setup(
182 				pipe_ctx->stream_res.stream_enc,
183 				audio_inst,
184 				&pipe_ctx->stream->audio_info,
185 				&audio_output->crtc_info);
186 }
187 
188 void enable_dio_audio_packet(struct pipe_ctx *pipe_ctx)
189 {
190 	if (dc_is_dp_signal(pipe_ctx->stream->signal))
191 		pipe_ctx->stream_res.stream_enc->funcs->dp_audio_enable(
192 				pipe_ctx->stream_res.stream_enc);
193 
194 	pipe_ctx->stream_res.stream_enc->funcs->audio_mute_control(
195 			pipe_ctx->stream_res.stream_enc, false);
196 
197 	if (dc_is_dp_signal(pipe_ctx->stream->signal))
198 		link_dp_source_sequence_trace(pipe_ctx->stream->link,
199 				DPCD_SOURCE_SEQ_AFTER_ENABLE_AUDIO_STREAM);
200 }
201 
202 void disable_dio_audio_packet(struct pipe_ctx *pipe_ctx)
203 {
204 	pipe_ctx->stream_res.stream_enc->funcs->audio_mute_control(
205 			pipe_ctx->stream_res.stream_enc, true);
206 
207 	if (pipe_ctx->stream_res.audio) {
208 		if (dc_is_dp_signal(pipe_ctx->stream->signal))
209 			pipe_ctx->stream_res.stream_enc->funcs->dp_audio_disable(
210 					pipe_ctx->stream_res.stream_enc);
211 		else
212 			pipe_ctx->stream_res.stream_enc->funcs->hdmi_audio_disable(
213 					pipe_ctx->stream_res.stream_enc);
214 	}
215 
216 	if (dc_is_dp_signal(pipe_ctx->stream->signal))
217 		link_dp_source_sequence_trace(pipe_ctx->stream->link,
218 				DPCD_SOURCE_SEQ_AFTER_DISABLE_AUDIO_STREAM);
219 }
220 
221 static const struct link_hwss dio_link_hwss = {
222 	.setup_stream_encoder = setup_dio_stream_encoder,
223 	.reset_stream_encoder = reset_dio_stream_encoder,
224 	.setup_stream_attribute = setup_dio_stream_attribute,
225 	.disable_link_output = disable_dio_link_output,
226 	.setup_audio_output = setup_dio_audio_output,
227 	.enable_audio_packet = enable_dio_audio_packet,
228 	.disable_audio_packet = disable_dio_audio_packet,
229 	.ext = {
230 		.set_throttled_vcp_size = set_dio_throttled_vcp_size,
231 		.enable_dp_link_output = enable_dio_dp_link_output,
232 		.set_dp_link_test_pattern = set_dio_dp_link_test_pattern,
233 		.set_dp_lane_settings = set_dio_dp_lane_settings,
234 		.update_stream_allocation_table = update_dio_stream_allocation_table,
235 	},
236 };
237 
238 bool can_use_dio_link_hwss(const struct dc_link *link,
239 		const struct link_resource *link_res)
240 {
241 	return link->link_enc != NULL;
242 }
243 
244 const struct link_hwss *get_dio_link_hwss(void)
245 {
246 	return &dio_link_hwss;
247 }
248