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(link: 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(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(link: 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(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(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(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(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(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(signal: stream->signal)) |
107 | stream_encoder->funcs->lvds_set_stream_attribute( |
108 | stream_encoder, |
109 | &stream->timing); |
110 | |
111 | if (dc_is_dp_signal(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(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(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(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(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(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 | |