GNU Linux-libre 4.19.245-gnu1
[releases.git] / drivers / gpu / drm / amd / display / dc / core / dc_link_hwss.c
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
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
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
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
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
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 }
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
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
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
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
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
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
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
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 }