1 /* Copyright 2015 Advanced Micro Devices, Inc. */
2
3
4 #include "dm_services.h"
5 #include "dc.h"
6 #include "inc/core_types.h"
7 #include "include/ddc_service_types.h"
8 #include "include/i2caux_interface.h"
9 #include "link_hwss.h"
10 #include "hw_sequencer.h"
11 #include "dc_link_dp.h"
12 #include "dc_link_ddc.h"
13 #include "dm_helpers.h"
14 #include "dpcd_defs.h"
15
core_link_read_dpcd(struct dc_link * link,uint32_t address,uint8_t * data,uint32_t size)16 enum dc_status core_link_read_dpcd(
17 struct dc_link *link,
18 uint32_t address,
19 uint8_t *data,
20 uint32_t size)
21 {
22 if (!dm_helpers_dp_read_dpcd(link->ctx,
23 link,
24 address, data, size))
25 return DC_ERROR_UNEXPECTED;
26
27 return DC_OK;
28 }
29
core_link_write_dpcd(struct dc_link * link,uint32_t address,const uint8_t * data,uint32_t size)30 enum dc_status core_link_write_dpcd(
31 struct dc_link *link,
32 uint32_t address,
33 const uint8_t *data,
34 uint32_t size)
35 {
36 if (!dm_helpers_dp_write_dpcd(link->ctx,
37 link,
38 address, data, size))
39 return DC_ERROR_UNEXPECTED;
40
41 return DC_OK;
42 }
43
dp_receiver_power_ctrl(struct dc_link * link,bool on)44 void dp_receiver_power_ctrl(struct dc_link *link, bool on)
45 {
46 uint8_t state;
47
48 state = on ? DP_POWER_STATE_D0 : DP_POWER_STATE_D3;
49
50 core_link_write_dpcd(link, DP_SET_POWER, &state,
51 sizeof(state));
52 }
53
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)54 void dp_enable_link_phy(
55 struct dc_link *link,
56 enum signal_type signal,
57 enum clock_source_id clock_source,
58 const struct dc_link_settings *link_settings)
59 {
60 struct link_encoder *link_enc = link->link_enc;
61
62 struct pipe_ctx *pipes =
63 link->dc->current_state->res_ctx.pipe_ctx;
64 struct clock_source *dp_cs =
65 link->dc->res_pool->dp_clock_source;
66 unsigned int i;
67 /* If the current pixel clock source is not DTO(happens after
68 * switching from HDMI passive dongle to DP on the same connector),
69 * switch the pixel clock source to DTO.
70 */
71 for (i = 0; i < MAX_PIPES; i++) {
72 if (pipes[i].stream != NULL &&
73 pipes[i].stream->sink != NULL &&
74 pipes[i].stream->sink->link == link) {
75 if (pipes[i].clock_source != NULL &&
76 pipes[i].clock_source->id != CLOCK_SOURCE_ID_DP_DTO) {
77 pipes[i].clock_source = dp_cs;
78 pipes[i].stream_res.pix_clk_params.requested_pix_clk =
79 pipes[i].stream->timing.pix_clk_khz;
80 pipes[i].clock_source->funcs->program_pix_clk(
81 pipes[i].clock_source,
82 &pipes[i].stream_res.pix_clk_params,
83 &pipes[i].pll_settings);
84 }
85 }
86 }
87
88 if (dc_is_dp_sst_signal(signal)) {
89 link_enc->funcs->enable_dp_output(
90 link_enc,
91 link_settings,
92 clock_source);
93 } else {
94 link_enc->funcs->enable_dp_mst_output(
95 link_enc,
96 link_settings,
97 clock_source);
98 }
99
100 dp_receiver_power_ctrl(link, true);
101 }
102
edp_receiver_ready_T9(struct dc_link * link)103 bool edp_receiver_ready_T9(struct dc_link *link)
104 {
105 unsigned int tries = 0;
106 unsigned char sinkstatus = 0;
107 unsigned char edpRev = 0;
108 enum dc_status result = DC_OK;
109 result = core_link_read_dpcd(link, DP_EDP_DPCD_REV, &edpRev, sizeof(edpRev));
110 if (edpRev < DP_EDP_12)
111 return true;
112 /* start from eDP version 1.2, SINK_STAUS indicate the sink is ready.*/
113 do {
114 sinkstatus = 1;
115 result = core_link_read_dpcd(link, DP_SINK_STATUS, &sinkstatus, sizeof(sinkstatus));
116 if (sinkstatus == 0)
117 break;
118 if (result != DC_OK)
119 break;
120 udelay(100); //MAx T9
121 } while (++tries < 50);
122 return result;
123 }
edp_receiver_ready_T7(struct dc_link * link)124 bool edp_receiver_ready_T7(struct dc_link *link)
125 {
126 unsigned int tries = 0;
127 unsigned char sinkstatus = 0;
128 unsigned char edpRev = 0;
129 enum dc_status result = DC_OK;
130
131 result = core_link_read_dpcd(link, DP_EDP_DPCD_REV, &edpRev, sizeof(edpRev));
132 if (result == DC_OK && edpRev < DP_EDP_12)
133 return true;
134 /* start from eDP version 1.2, SINK_STAUS indicate the sink is ready.*/
135 do {
136 sinkstatus = 0;
137 result = core_link_read_dpcd(link, DP_SINK_STATUS, &sinkstatus, sizeof(sinkstatus));
138 if (sinkstatus == 1)
139 break;
140 if (result != DC_OK)
141 break;
142 udelay(25); //MAx T7 is 50ms
143 } while (++tries < 300);
144 return result;
145 }
146
dp_disable_link_phy(struct dc_link * link,enum signal_type signal)147 void dp_disable_link_phy(struct dc_link *link, enum signal_type signal)
148 {
149 if (!link->wa_flags.dp_keep_receiver_powered)
150 dp_receiver_power_ctrl(link, false);
151
152 if (signal == SIGNAL_TYPE_EDP) {
153 link->link_enc->funcs->disable_output(link->link_enc, signal);
154 link->dc->hwss.edp_power_control(link, false);
155 } else
156 link->link_enc->funcs->disable_output(link->link_enc, signal);
157
158 /* Clear current link setting.*/
159 memset(&link->cur_link_settings, 0,
160 sizeof(link->cur_link_settings));
161 }
162
dp_disable_link_phy_mst(struct dc_link * link,enum signal_type signal)163 void dp_disable_link_phy_mst(struct dc_link *link, enum signal_type signal)
164 {
165 /* MST disable link only when no stream use the link */
166 if (link->mst_stream_alloc_table.stream_count > 0)
167 return;
168
169 dp_disable_link_phy(link, signal);
170
171 /* set the sink to SST mode after disabling the link */
172 dp_enable_mst_on_sink(link, false);
173 }
174
dp_set_hw_training_pattern(struct dc_link * link,enum hw_dp_training_pattern pattern)175 bool dp_set_hw_training_pattern(
176 struct dc_link *link,
177 enum hw_dp_training_pattern pattern)
178 {
179 enum dp_test_pattern test_pattern = DP_TEST_PATTERN_UNSUPPORTED;
180
181 switch (pattern) {
182 case HW_DP_TRAINING_PATTERN_1:
183 test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN1;
184 break;
185 case HW_DP_TRAINING_PATTERN_2:
186 test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN2;
187 break;
188 case HW_DP_TRAINING_PATTERN_3:
189 test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN3;
190 break;
191 case HW_DP_TRAINING_PATTERN_4:
192 test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN4;
193 break;
194 default:
195 break;
196 }
197
198 dp_set_hw_test_pattern(link, test_pattern, NULL, 0);
199
200 return true;
201 }
202
dp_set_hw_lane_settings(struct dc_link * link,const struct link_training_settings * link_settings)203 void dp_set_hw_lane_settings(
204 struct dc_link *link,
205 const struct link_training_settings *link_settings)
206 {
207 struct link_encoder *encoder = link->link_enc;
208
209 /* call Encoder to set lane settings */
210 encoder->funcs->dp_set_lane_settings(encoder, link_settings);
211 }
212
dp_get_panel_mode(struct dc_link * link)213 enum dp_panel_mode dp_get_panel_mode(struct dc_link *link)
214 {
215 /* We need to explicitly check that connector
216 * is not DP. Some Travis_VGA get reported
217 * by video bios as DP.
218 */
219 if (link->connector_signal != SIGNAL_TYPE_DISPLAY_PORT) {
220
221 switch (link->dpcd_caps.branch_dev_id) {
222 case DP_BRANCH_DEVICE_ID_2:
223 if (strncmp(
224 link->dpcd_caps.branch_dev_name,
225 DP_VGA_LVDS_CONVERTER_ID_2,
226 sizeof(
227 link->dpcd_caps.
228 branch_dev_name)) == 0) {
229 return DP_PANEL_MODE_SPECIAL;
230 }
231 break;
232 case DP_BRANCH_DEVICE_ID_3:
233 if (strncmp(link->dpcd_caps.branch_dev_name,
234 DP_VGA_LVDS_CONVERTER_ID_3,
235 sizeof(
236 link->dpcd_caps.
237 branch_dev_name)) == 0) {
238 return DP_PANEL_MODE_SPECIAL;
239 }
240 break;
241 default:
242 break;
243 }
244 }
245
246 if (link->dpcd_caps.panel_mode_edp) {
247 return DP_PANEL_MODE_EDP;
248 }
249
250 return DP_PANEL_MODE_DEFAULT;
251 }
252
dp_set_hw_test_pattern(struct dc_link * link,enum dp_test_pattern test_pattern,uint8_t * custom_pattern,uint32_t custom_pattern_size)253 void dp_set_hw_test_pattern(
254 struct dc_link *link,
255 enum dp_test_pattern test_pattern,
256 uint8_t *custom_pattern,
257 uint32_t custom_pattern_size)
258 {
259 struct encoder_set_dp_phy_pattern_param pattern_param = {0};
260 struct link_encoder *encoder = link->link_enc;
261
262 pattern_param.dp_phy_pattern = test_pattern;
263 pattern_param.custom_pattern = custom_pattern;
264 pattern_param.custom_pattern_size = custom_pattern_size;
265 pattern_param.dp_panel_mode = dp_get_panel_mode(link);
266
267 encoder->funcs->dp_set_phy_pattern(encoder, &pattern_param);
268 }
269
dp_retrain_link_dp_test(struct dc_link * link,struct dc_link_settings * link_setting,bool skip_video_pattern)270 void dp_retrain_link_dp_test(struct dc_link *link,
271 struct dc_link_settings *link_setting,
272 bool skip_video_pattern)
273 {
274 struct pipe_ctx *pipes =
275 &link->dc->current_state->res_ctx.pipe_ctx[0];
276 unsigned int i;
277
278 for (i = 0; i < MAX_PIPES; i++) {
279 if (pipes[i].stream != NULL &&
280 !pipes[i].top_pipe &&
281 pipes[i].stream->sink != NULL &&
282 pipes[i].stream->sink->link != NULL &&
283 pipes[i].stream_res.stream_enc != NULL &&
284 pipes[i].stream->sink->link == link) {
285 udelay(100);
286
287 pipes[i].stream_res.stream_enc->funcs->dp_blank(
288 pipes[i].stream_res.stream_enc);
289
290 /* disable any test pattern that might be active */
291 dp_set_hw_test_pattern(link,
292 DP_TEST_PATTERN_VIDEO_MODE, NULL, 0);
293
294 dp_receiver_power_ctrl(link, false);
295
296 link->dc->hwss.disable_stream(&pipes[i], KEEP_ACQUIRED_RESOURCE);
297
298 link->link_enc->funcs->disable_output(
299 link->link_enc,
300 SIGNAL_TYPE_DISPLAY_PORT);
301
302 /* Clear current link setting. */
303 memset(&link->cur_link_settings, 0,
304 sizeof(link->cur_link_settings));
305
306 link->link_enc->funcs->enable_dp_output(
307 link->link_enc,
308 link_setting,
309 pipes[i].clock_source->id);
310
311 dp_receiver_power_ctrl(link, true);
312
313 perform_link_training_with_retries(
314 link,
315 link_setting,
316 skip_video_pattern,
317 LINK_TRAINING_ATTEMPTS);
318
319 link->cur_link_settings = *link_setting;
320
321 link->dc->hwss.enable_stream(&pipes[i]);
322
323 link->dc->hwss.unblank_stream(&pipes[i],
324 link_setting);
325
326 if (pipes[i].stream_res.audio) {
327 /* notify audio driver for
328 * audio modes of monitor */
329 pipes[i].stream_res.audio->funcs->az_enable(
330 pipes[i].stream_res.audio);
331
332 /* un-mute audio */
333 /* TODO: audio should be per stream rather than
334 * per link */
335 pipes[i].stream_res.stream_enc->funcs->
336 audio_mute_control(
337 pipes[i].stream_res.stream_enc, false);
338 }
339 }
340 }
341 }
342