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