xref: /dragonfly/sys/dev/drm/amd/display/dc/core/dc_link_hwss.c (revision b843c749addef9340ee7d4e250b09fdd492602a1)
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