Line data Source code
1 : /*
2 : * Copyright 2007-8 Advanced Micro Devices, Inc.
3 : * Copyright 2008 Red Hat Inc.
4 : *
5 : * Permission is hereby granted, free of charge, to any person obtaining a
6 : * copy of this software and associated documentation files (the "Software"),
7 : * to deal in the Software without restriction, including without limitation
8 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 : * and/or sell copies of the Software, and to permit persons to whom the
10 : * Software is furnished to do so, subject to the following conditions:
11 : *
12 : * The above copyright notice and this permission notice shall be included in
13 : * all copies or substantial portions of the Software.
14 : *
15 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 : * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
19 : * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20 : * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21 : * OTHER DEALINGS IN THE SOFTWARE.
22 : *
23 : * Authors: Dave Airlie
24 : * Alex Deucher
25 : * Jerome Glisse
26 : */
27 :
28 : #include <drm/amdgpu_drm.h>
29 : #include <drm/display/drm_dp_helper.h>
30 :
31 : #include "amdgpu.h"
32 :
33 : #include "atom.h"
34 : #include "atom-bits.h"
35 : #include "atombios_encoders.h"
36 : #include "atombios_dp.h"
37 : #include "amdgpu_connectors.h"
38 : #include "amdgpu_atombios.h"
39 :
40 : /* move these to drm_dp_helper.c/h */
41 : #define DP_LINK_CONFIGURATION_SIZE 9
42 : #define DP_DPCD_SIZE DP_RECEIVER_CAP_SIZE
43 :
44 : static char *voltage_names[] = {
45 : "0.4V", "0.6V", "0.8V", "1.2V"
46 : };
47 : static char *pre_emph_names[] = {
48 : "0dB", "3.5dB", "6dB", "9.5dB"
49 : };
50 :
51 : /***** amdgpu AUX functions *****/
52 :
53 : union aux_channel_transaction {
54 : PROCESS_AUX_CHANNEL_TRANSACTION_PS_ALLOCATION v1;
55 : PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS_V2 v2;
56 : };
57 :
58 0 : static int amdgpu_atombios_dp_process_aux_ch(struct amdgpu_i2c_chan *chan,
59 : u8 *send, int send_bytes,
60 : u8 *recv, int recv_size,
61 : u8 delay, u8 *ack)
62 : {
63 0 : struct drm_device *dev = chan->dev;
64 0 : struct amdgpu_device *adev = drm_to_adev(dev);
65 : union aux_channel_transaction args;
66 0 : int index = GetIndexIntoMasterTable(COMMAND, ProcessAuxChannelTransaction);
67 : unsigned char *base;
68 : int recv_bytes;
69 0 : int r = 0;
70 :
71 0 : memset(&args, 0, sizeof(args));
72 :
73 0 : mutex_lock(&chan->mutex);
74 :
75 0 : base = (unsigned char *)(adev->mode_info.atom_context->scratch + 1);
76 :
77 0 : amdgpu_atombios_copy_swap(base, send, send_bytes, true);
78 :
79 0 : args.v2.lpAuxRequest = cpu_to_le16((u16)(0 + 4));
80 0 : args.v2.lpDataOut = cpu_to_le16((u16)(16 + 4));
81 0 : args.v2.ucDataOutLen = 0;
82 0 : args.v2.ucChannelID = chan->rec.i2c_id;
83 0 : args.v2.ucDelay = delay / 10;
84 0 : args.v2.ucHPD_ID = chan->rec.hpd;
85 :
86 0 : amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
87 :
88 0 : *ack = args.v2.ucReplyStatus;
89 :
90 : /* timeout */
91 0 : if (args.v2.ucReplyStatus == 1) {
92 : r = -ETIMEDOUT;
93 : goto done;
94 : }
95 :
96 : /* flags not zero */
97 0 : if (args.v2.ucReplyStatus == 2) {
98 0 : DRM_DEBUG_KMS("dp_aux_ch flags not zero\n");
99 0 : r = -EIO;
100 0 : goto done;
101 : }
102 :
103 : /* error */
104 0 : if (args.v2.ucReplyStatus == 3) {
105 0 : DRM_DEBUG_KMS("dp_aux_ch error\n");
106 0 : r = -EIO;
107 0 : goto done;
108 : }
109 :
110 0 : recv_bytes = args.v1.ucDataOutLen;
111 0 : if (recv_bytes > recv_size)
112 0 : recv_bytes = recv_size;
113 :
114 0 : if (recv && recv_size)
115 0 : amdgpu_atombios_copy_swap(recv, base + 16, recv_bytes, false);
116 :
117 : r = recv_bytes;
118 : done:
119 0 : mutex_unlock(&chan->mutex);
120 :
121 0 : return r;
122 : }
123 :
124 : #define BARE_ADDRESS_SIZE 3
125 : #define HEADER_SIZE (BARE_ADDRESS_SIZE + 1)
126 :
127 : static ssize_t
128 0 : amdgpu_atombios_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
129 : {
130 0 : struct amdgpu_i2c_chan *chan =
131 0 : container_of(aux, struct amdgpu_i2c_chan, aux);
132 : int ret;
133 : u8 tx_buf[20];
134 : size_t tx_size;
135 0 : u8 ack, delay = 0;
136 :
137 0 : if (WARN_ON(msg->size > 16))
138 : return -E2BIG;
139 :
140 0 : tx_buf[0] = msg->address & 0xff;
141 0 : tx_buf[1] = msg->address >> 8;
142 0 : tx_buf[2] = (msg->request << 4) |
143 0 : ((msg->address >> 16) & 0xf);
144 0 : tx_buf[3] = msg->size ? (msg->size - 1) : 0;
145 :
146 0 : switch (msg->request & ~DP_AUX_I2C_MOT) {
147 : case DP_AUX_NATIVE_WRITE:
148 : case DP_AUX_I2C_WRITE:
149 : /* tx_size needs to be 4 even for bare address packets since the atom
150 : * table needs the info in tx_buf[3].
151 : */
152 0 : tx_size = HEADER_SIZE + msg->size;
153 0 : if (msg->size == 0)
154 0 : tx_buf[3] |= BARE_ADDRESS_SIZE << 4;
155 : else
156 0 : tx_buf[3] |= tx_size << 4;
157 0 : memcpy(tx_buf + HEADER_SIZE, msg->buffer, msg->size);
158 0 : ret = amdgpu_atombios_dp_process_aux_ch(chan,
159 : tx_buf, tx_size, NULL, 0, delay, &ack);
160 0 : if (ret >= 0)
161 : /* Return payload size. */
162 0 : ret = msg->size;
163 : break;
164 : case DP_AUX_NATIVE_READ:
165 : case DP_AUX_I2C_READ:
166 : /* tx_size needs to be 4 even for bare address packets since the atom
167 : * table needs the info in tx_buf[3].
168 : */
169 0 : tx_size = HEADER_SIZE;
170 0 : if (msg->size == 0)
171 0 : tx_buf[3] |= BARE_ADDRESS_SIZE << 4;
172 : else
173 0 : tx_buf[3] |= tx_size << 4;
174 0 : ret = amdgpu_atombios_dp_process_aux_ch(chan,
175 0 : tx_buf, tx_size, msg->buffer, msg->size, delay, &ack);
176 0 : break;
177 : default:
178 : ret = -EINVAL;
179 : break;
180 : }
181 :
182 0 : if (ret >= 0)
183 0 : msg->reply = ack >> 4;
184 :
185 0 : return ret;
186 : }
187 :
188 0 : void amdgpu_atombios_dp_aux_init(struct amdgpu_connector *amdgpu_connector)
189 : {
190 0 : amdgpu_connector->ddc_bus->rec.hpd = amdgpu_connector->hpd.hpd;
191 0 : amdgpu_connector->ddc_bus->aux.transfer = amdgpu_atombios_dp_aux_transfer;
192 0 : amdgpu_connector->ddc_bus->aux.drm_dev = amdgpu_connector->base.dev;
193 :
194 0 : drm_dp_aux_init(&amdgpu_connector->ddc_bus->aux);
195 0 : amdgpu_connector->ddc_bus->has_aux = true;
196 0 : }
197 :
198 : /***** general DP utility functions *****/
199 :
200 : #define DP_VOLTAGE_MAX DP_TRAIN_VOLTAGE_SWING_LEVEL_3
201 : #define DP_PRE_EMPHASIS_MAX DP_TRAIN_PRE_EMPH_LEVEL_3
202 :
203 0 : static void amdgpu_atombios_dp_get_adjust_train(const u8 link_status[DP_LINK_STATUS_SIZE],
204 : int lane_count,
205 : u8 train_set[4])
206 : {
207 0 : u8 v = 0;
208 0 : u8 p = 0;
209 : int lane;
210 :
211 0 : for (lane = 0; lane < lane_count; lane++) {
212 0 : u8 this_v = drm_dp_get_adjust_request_voltage(link_status, lane);
213 0 : u8 this_p = drm_dp_get_adjust_request_pre_emphasis(link_status, lane);
214 :
215 0 : DRM_DEBUG_KMS("requested signal parameters: lane %d voltage %s pre_emph %s\n",
216 : lane,
217 : voltage_names[this_v >> DP_TRAIN_VOLTAGE_SWING_SHIFT],
218 : pre_emph_names[this_p >> DP_TRAIN_PRE_EMPHASIS_SHIFT]);
219 :
220 0 : if (this_v > v)
221 0 : v = this_v;
222 0 : if (this_p > p)
223 0 : p = this_p;
224 : }
225 :
226 0 : if (v >= DP_VOLTAGE_MAX)
227 0 : v |= DP_TRAIN_MAX_SWING_REACHED;
228 :
229 0 : if (p >= DP_PRE_EMPHASIS_MAX)
230 0 : p |= DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
231 :
232 0 : DRM_DEBUG_KMS("using signal parameters: voltage %s pre_emph %s\n",
233 : voltage_names[(v & DP_TRAIN_VOLTAGE_SWING_MASK) >> DP_TRAIN_VOLTAGE_SWING_SHIFT],
234 : pre_emph_names[(p & DP_TRAIN_PRE_EMPHASIS_MASK) >> DP_TRAIN_PRE_EMPHASIS_SHIFT]);
235 :
236 0 : for (lane = 0; lane < 4; lane++)
237 0 : train_set[lane] = v | p;
238 0 : }
239 :
240 : /* convert bits per color to bits per pixel */
241 : /* get bpc from the EDID */
242 : static unsigned amdgpu_atombios_dp_convert_bpc_to_bpp(int bpc)
243 : {
244 0 : if (bpc == 0)
245 : return 24;
246 : else
247 0 : return bpc * 3;
248 : }
249 :
250 : /***** amdgpu specific DP functions *****/
251 :
252 0 : static int amdgpu_atombios_dp_get_dp_link_config(struct drm_connector *connector,
253 : const u8 dpcd[DP_DPCD_SIZE],
254 : unsigned pix_clock,
255 : unsigned *dp_lanes, unsigned *dp_rate)
256 : {
257 0 : unsigned bpp =
258 0 : amdgpu_atombios_dp_convert_bpc_to_bpp(amdgpu_connector_get_monitor_bpc(connector));
259 : static const unsigned link_rates[3] = { 162000, 270000, 540000 };
260 0 : unsigned max_link_rate = drm_dp_max_link_rate(dpcd);
261 0 : unsigned max_lane_num = drm_dp_max_lane_count(dpcd);
262 : unsigned lane_num, i, max_pix_clock;
263 :
264 0 : if (amdgpu_connector_encoder_get_dp_bridge_encoder_id(connector) ==
265 : ENCODER_OBJECT_ID_NUTMEG) {
266 0 : for (lane_num = 1; lane_num <= max_lane_num; lane_num <<= 1) {
267 0 : max_pix_clock = (lane_num * 270000 * 8) / bpp;
268 0 : if (max_pix_clock >= pix_clock) {
269 0 : *dp_lanes = lane_num;
270 0 : *dp_rate = 270000;
271 0 : return 0;
272 : }
273 : }
274 : } else {
275 0 : for (i = 0; i < ARRAY_SIZE(link_rates) && link_rates[i] <= max_link_rate; i++) {
276 0 : for (lane_num = 1; lane_num <= max_lane_num; lane_num <<= 1) {
277 0 : max_pix_clock = (lane_num * link_rates[i] * 8) / bpp;
278 0 : if (max_pix_clock >= pix_clock) {
279 0 : *dp_lanes = lane_num;
280 0 : *dp_rate = link_rates[i];
281 0 : return 0;
282 : }
283 : }
284 : }
285 : }
286 :
287 : return -EINVAL;
288 : }
289 :
290 0 : static u8 amdgpu_atombios_dp_encoder_service(struct amdgpu_device *adev,
291 : int action, int dp_clock,
292 : u8 ucconfig, u8 lane_num)
293 : {
294 : DP_ENCODER_SERVICE_PARAMETERS args;
295 0 : int index = GetIndexIntoMasterTable(COMMAND, DPEncoderService);
296 :
297 0 : memset(&args, 0, sizeof(args));
298 0 : args.ucLinkClock = dp_clock / 10;
299 0 : args.ucConfig = ucconfig;
300 0 : args.ucAction = action;
301 0 : args.ucLaneNum = lane_num;
302 0 : args.ucStatus = 0;
303 :
304 0 : amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
305 0 : return args.ucStatus;
306 : }
307 :
308 0 : u8 amdgpu_atombios_dp_get_sinktype(struct amdgpu_connector *amdgpu_connector)
309 : {
310 0 : struct drm_device *dev = amdgpu_connector->base.dev;
311 0 : struct amdgpu_device *adev = drm_to_adev(dev);
312 :
313 0 : return amdgpu_atombios_dp_encoder_service(adev, ATOM_DP_ACTION_GET_SINK_TYPE, 0,
314 0 : amdgpu_connector->ddc_bus->rec.i2c_id, 0);
315 : }
316 :
317 0 : static void amdgpu_atombios_dp_probe_oui(struct amdgpu_connector *amdgpu_connector)
318 : {
319 0 : struct amdgpu_connector_atom_dig *dig_connector = amdgpu_connector->con_priv;
320 : u8 buf[3];
321 :
322 0 : if (!(dig_connector->dpcd[DP_DOWN_STREAM_PORT_COUNT] & DP_OUI_SUPPORT))
323 0 : return;
324 :
325 0 : if (drm_dp_dpcd_read(&amdgpu_connector->ddc_bus->aux, DP_SINK_OUI, buf, 3) == 3)
326 0 : DRM_DEBUG_KMS("Sink OUI: %02hx%02hx%02hx\n",
327 : buf[0], buf[1], buf[2]);
328 :
329 0 : if (drm_dp_dpcd_read(&amdgpu_connector->ddc_bus->aux, DP_BRANCH_OUI, buf, 3) == 3)
330 0 : DRM_DEBUG_KMS("Branch OUI: %02hx%02hx%02hx\n",
331 : buf[0], buf[1], buf[2]);
332 : }
333 :
334 0 : static void amdgpu_atombios_dp_ds_ports(struct amdgpu_connector *amdgpu_connector)
335 : {
336 0 : struct amdgpu_connector_atom_dig *dig_connector = amdgpu_connector->con_priv;
337 : int ret;
338 :
339 0 : if (dig_connector->dpcd[DP_DPCD_REV] > 0x10) {
340 0 : ret = drm_dp_dpcd_read(&amdgpu_connector->ddc_bus->aux,
341 : DP_DOWNSTREAM_PORT_0,
342 0 : dig_connector->downstream_ports,
343 : DP_MAX_DOWNSTREAM_PORTS);
344 0 : if (ret)
345 0 : memset(dig_connector->downstream_ports, 0,
346 : DP_MAX_DOWNSTREAM_PORTS);
347 : }
348 0 : }
349 :
350 0 : int amdgpu_atombios_dp_get_dpcd(struct amdgpu_connector *amdgpu_connector)
351 : {
352 0 : struct amdgpu_connector_atom_dig *dig_connector = amdgpu_connector->con_priv;
353 : u8 msg[DP_DPCD_SIZE];
354 : int ret;
355 :
356 0 : ret = drm_dp_dpcd_read(&amdgpu_connector->ddc_bus->aux, DP_DPCD_REV,
357 : msg, DP_DPCD_SIZE);
358 0 : if (ret == DP_DPCD_SIZE) {
359 0 : memcpy(dig_connector->dpcd, msg, DP_DPCD_SIZE);
360 :
361 0 : DRM_DEBUG_KMS("DPCD: %*ph\n", (int)sizeof(dig_connector->dpcd),
362 : dig_connector->dpcd);
363 :
364 0 : amdgpu_atombios_dp_probe_oui(amdgpu_connector);
365 0 : amdgpu_atombios_dp_ds_ports(amdgpu_connector);
366 0 : return 0;
367 : }
368 :
369 0 : dig_connector->dpcd[0] = 0;
370 0 : return -EINVAL;
371 : }
372 :
373 0 : int amdgpu_atombios_dp_get_panel_mode(struct drm_encoder *encoder,
374 : struct drm_connector *connector)
375 : {
376 0 : struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
377 0 : int panel_mode = DP_PANEL_MODE_EXTERNAL_DP_MODE;
378 0 : u16 dp_bridge = amdgpu_connector_encoder_get_dp_bridge_encoder_id(connector);
379 : u8 tmp;
380 :
381 0 : if (!amdgpu_connector->con_priv)
382 : return panel_mode;
383 :
384 0 : if (dp_bridge != ENCODER_OBJECT_ID_NONE) {
385 : /* DP bridge chips */
386 0 : if (drm_dp_dpcd_readb(&amdgpu_connector->ddc_bus->aux,
387 : DP_EDP_CONFIGURATION_CAP, &tmp) == 1) {
388 0 : if (tmp & 1)
389 : panel_mode = DP_PANEL_MODE_INTERNAL_DP2_MODE;
390 0 : else if ((dp_bridge == ENCODER_OBJECT_ID_NUTMEG) ||
391 : (dp_bridge == ENCODER_OBJECT_ID_TRAVIS))
392 : panel_mode = DP_PANEL_MODE_INTERNAL_DP1_MODE;
393 : else
394 0 : panel_mode = DP_PANEL_MODE_EXTERNAL_DP_MODE;
395 : }
396 0 : } else if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
397 : /* eDP */
398 0 : if (drm_dp_dpcd_readb(&amdgpu_connector->ddc_bus->aux,
399 : DP_EDP_CONFIGURATION_CAP, &tmp) == 1) {
400 0 : if (tmp & 1)
401 0 : panel_mode = DP_PANEL_MODE_INTERNAL_DP2_MODE;
402 : }
403 : }
404 :
405 : return panel_mode;
406 : }
407 :
408 0 : void amdgpu_atombios_dp_set_link_config(struct drm_connector *connector,
409 : const struct drm_display_mode *mode)
410 : {
411 0 : struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
412 : struct amdgpu_connector_atom_dig *dig_connector;
413 : int ret;
414 :
415 0 : if (!amdgpu_connector->con_priv)
416 : return;
417 0 : dig_connector = amdgpu_connector->con_priv;
418 :
419 0 : if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||
420 : (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) {
421 0 : ret = amdgpu_atombios_dp_get_dp_link_config(connector, dig_connector->dpcd,
422 0 : mode->clock,
423 0 : &dig_connector->dp_lane_count,
424 0 : &dig_connector->dp_clock);
425 0 : if (ret) {
426 0 : dig_connector->dp_clock = 0;
427 0 : dig_connector->dp_lane_count = 0;
428 : }
429 : }
430 : }
431 :
432 0 : int amdgpu_atombios_dp_mode_valid_helper(struct drm_connector *connector,
433 : struct drm_display_mode *mode)
434 : {
435 0 : struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
436 : struct amdgpu_connector_atom_dig *dig_connector;
437 : unsigned dp_lanes, dp_clock;
438 : int ret;
439 :
440 0 : if (!amdgpu_connector->con_priv)
441 : return MODE_CLOCK_HIGH;
442 0 : dig_connector = amdgpu_connector->con_priv;
443 :
444 0 : ret = amdgpu_atombios_dp_get_dp_link_config(connector, dig_connector->dpcd,
445 0 : mode->clock, &dp_lanes, &dp_clock);
446 0 : if (ret)
447 : return MODE_CLOCK_HIGH;
448 :
449 0 : if ((dp_clock == 540000) &&
450 0 : (!amdgpu_connector_is_dp12_capable(connector)))
451 : return MODE_CLOCK_HIGH;
452 :
453 : return MODE_OK;
454 : }
455 :
456 0 : bool amdgpu_atombios_dp_needs_link_train(struct amdgpu_connector *amdgpu_connector)
457 : {
458 : u8 link_status[DP_LINK_STATUS_SIZE];
459 0 : struct amdgpu_connector_atom_dig *dig = amdgpu_connector->con_priv;
460 :
461 0 : if (drm_dp_dpcd_read_link_status(&amdgpu_connector->ddc_bus->aux, link_status)
462 : <= 0)
463 : return false;
464 0 : if (drm_dp_channel_eq_ok(link_status, dig->dp_lane_count))
465 : return false;
466 0 : return true;
467 : }
468 :
469 0 : void amdgpu_atombios_dp_set_rx_power_state(struct drm_connector *connector,
470 : u8 power_state)
471 : {
472 0 : struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
473 : struct amdgpu_connector_atom_dig *dig_connector;
474 :
475 0 : if (!amdgpu_connector->con_priv)
476 : return;
477 :
478 0 : dig_connector = amdgpu_connector->con_priv;
479 :
480 : /* power up/down the sink */
481 0 : if (dig_connector->dpcd[0] >= 0x11) {
482 0 : drm_dp_dpcd_writeb(&amdgpu_connector->ddc_bus->aux,
483 : DP_SET_POWER, power_state);
484 : usleep_range(1000, 2000);
485 : }
486 : }
487 :
488 : struct amdgpu_atombios_dp_link_train_info {
489 : struct amdgpu_device *adev;
490 : struct drm_encoder *encoder;
491 : struct drm_connector *connector;
492 : int dp_clock;
493 : int dp_lane_count;
494 : bool tp3_supported;
495 : u8 dpcd[DP_RECEIVER_CAP_SIZE];
496 : u8 train_set[4];
497 : u8 link_status[DP_LINK_STATUS_SIZE];
498 : u8 tries;
499 : struct drm_dp_aux *aux;
500 : };
501 :
502 : static void
503 0 : amdgpu_atombios_dp_update_vs_emph(struct amdgpu_atombios_dp_link_train_info *dp_info)
504 : {
505 : /* set the initial vs/emph on the source */
506 0 : amdgpu_atombios_encoder_setup_dig_transmitter(dp_info->encoder,
507 : ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH,
508 0 : 0, dp_info->train_set[0]); /* sets all lanes at once */
509 :
510 : /* set the vs/emph on the sink */
511 0 : drm_dp_dpcd_write(dp_info->aux, DP_TRAINING_LANE0_SET,
512 0 : dp_info->train_set, dp_info->dp_lane_count);
513 0 : }
514 :
515 : static void
516 0 : amdgpu_atombios_dp_set_tp(struct amdgpu_atombios_dp_link_train_info *dp_info, int tp)
517 : {
518 0 : int rtp = 0;
519 :
520 : /* set training pattern on the source */
521 0 : switch (tp) {
522 : case DP_TRAINING_PATTERN_1:
523 : rtp = ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN1;
524 : break;
525 : case DP_TRAINING_PATTERN_2:
526 : rtp = ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN2;
527 : break;
528 : case DP_TRAINING_PATTERN_3:
529 : rtp = ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN3;
530 : break;
531 : }
532 0 : amdgpu_atombios_encoder_setup_dig_encoder(dp_info->encoder, rtp, 0);
533 :
534 : /* enable training pattern on the sink */
535 0 : drm_dp_dpcd_writeb(dp_info->aux, DP_TRAINING_PATTERN_SET, tp);
536 0 : }
537 :
538 : static int
539 0 : amdgpu_atombios_dp_link_train_init(struct amdgpu_atombios_dp_link_train_info *dp_info)
540 : {
541 0 : struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(dp_info->encoder);
542 0 : struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
543 : u8 tmp;
544 :
545 : /* power up the sink */
546 0 : amdgpu_atombios_dp_set_rx_power_state(dp_info->connector, DP_SET_POWER_D0);
547 :
548 : /* possibly enable downspread on the sink */
549 0 : if (dp_info->dpcd[3] & 0x1)
550 0 : drm_dp_dpcd_writeb(dp_info->aux,
551 : DP_DOWNSPREAD_CTRL, DP_SPREAD_AMP_0_5);
552 : else
553 0 : drm_dp_dpcd_writeb(dp_info->aux,
554 : DP_DOWNSPREAD_CTRL, 0);
555 :
556 0 : if (dig->panel_mode == DP_PANEL_MODE_INTERNAL_DP2_MODE)
557 0 : drm_dp_dpcd_writeb(dp_info->aux, DP_EDP_CONFIGURATION_SET, 1);
558 :
559 : /* set the lane count on the sink */
560 0 : tmp = dp_info->dp_lane_count;
561 0 : if (drm_dp_enhanced_frame_cap(dp_info->dpcd))
562 0 : tmp |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
563 0 : drm_dp_dpcd_writeb(dp_info->aux, DP_LANE_COUNT_SET, tmp);
564 :
565 : /* set the link rate on the sink */
566 0 : tmp = drm_dp_link_rate_to_bw_code(dp_info->dp_clock);
567 0 : drm_dp_dpcd_writeb(dp_info->aux, DP_LINK_BW_SET, tmp);
568 :
569 : /* start training on the source */
570 0 : amdgpu_atombios_encoder_setup_dig_encoder(dp_info->encoder,
571 : ATOM_ENCODER_CMD_DP_LINK_TRAINING_START, 0);
572 :
573 : /* disable the training pattern on the sink */
574 0 : drm_dp_dpcd_writeb(dp_info->aux,
575 : DP_TRAINING_PATTERN_SET,
576 : DP_TRAINING_PATTERN_DISABLE);
577 :
578 0 : return 0;
579 : }
580 :
581 : static int
582 0 : amdgpu_atombios_dp_link_train_finish(struct amdgpu_atombios_dp_link_train_info *dp_info)
583 : {
584 0 : udelay(400);
585 :
586 : /* disable the training pattern on the sink */
587 0 : drm_dp_dpcd_writeb(dp_info->aux,
588 : DP_TRAINING_PATTERN_SET,
589 : DP_TRAINING_PATTERN_DISABLE);
590 :
591 : /* disable the training pattern on the source */
592 0 : amdgpu_atombios_encoder_setup_dig_encoder(dp_info->encoder,
593 : ATOM_ENCODER_CMD_DP_LINK_TRAINING_COMPLETE, 0);
594 :
595 0 : return 0;
596 : }
597 :
598 : static int
599 0 : amdgpu_atombios_dp_link_train_cr(struct amdgpu_atombios_dp_link_train_info *dp_info)
600 : {
601 : bool clock_recovery;
602 : u8 voltage;
603 : int i;
604 :
605 0 : amdgpu_atombios_dp_set_tp(dp_info, DP_TRAINING_PATTERN_1);
606 0 : memset(dp_info->train_set, 0, 4);
607 0 : amdgpu_atombios_dp_update_vs_emph(dp_info);
608 :
609 0 : udelay(400);
610 :
611 : /* clock recovery loop */
612 0 : clock_recovery = false;
613 0 : dp_info->tries = 0;
614 0 : voltage = 0xff;
615 : while (1) {
616 0 : drm_dp_link_train_clock_recovery_delay(dp_info->aux, dp_info->dpcd);
617 :
618 0 : if (drm_dp_dpcd_read_link_status(dp_info->aux,
619 0 : dp_info->link_status) <= 0) {
620 0 : DRM_ERROR("displayport link status failed\n");
621 0 : break;
622 : }
623 :
624 0 : if (drm_dp_clock_recovery_ok(dp_info->link_status, dp_info->dp_lane_count)) {
625 : clock_recovery = true;
626 : break;
627 : }
628 :
629 0 : for (i = 0; i < dp_info->dp_lane_count; i++) {
630 0 : if ((dp_info->train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0)
631 : break;
632 : }
633 0 : if (i == dp_info->dp_lane_count) {
634 0 : DRM_ERROR("clock recovery reached max voltage\n");
635 0 : break;
636 : }
637 :
638 0 : if ((dp_info->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) {
639 0 : ++dp_info->tries;
640 0 : if (dp_info->tries == 5) {
641 0 : DRM_ERROR("clock recovery tried 5 times\n");
642 0 : break;
643 : }
644 : } else
645 0 : dp_info->tries = 0;
646 :
647 0 : voltage = dp_info->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
648 :
649 : /* Compute new train_set as requested by sink */
650 0 : amdgpu_atombios_dp_get_adjust_train(dp_info->link_status, dp_info->dp_lane_count,
651 : dp_info->train_set);
652 :
653 0 : amdgpu_atombios_dp_update_vs_emph(dp_info);
654 : }
655 0 : if (!clock_recovery) {
656 0 : DRM_ERROR("clock recovery failed\n");
657 0 : return -1;
658 : } else {
659 0 : DRM_DEBUG_KMS("clock recovery at voltage %d pre-emphasis %d\n",
660 : dp_info->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK,
661 : (dp_info->train_set[0] & DP_TRAIN_PRE_EMPHASIS_MASK) >>
662 : DP_TRAIN_PRE_EMPHASIS_SHIFT);
663 0 : return 0;
664 : }
665 : }
666 :
667 : static int
668 0 : amdgpu_atombios_dp_link_train_ce(struct amdgpu_atombios_dp_link_train_info *dp_info)
669 : {
670 : bool channel_eq;
671 :
672 0 : if (dp_info->tp3_supported)
673 0 : amdgpu_atombios_dp_set_tp(dp_info, DP_TRAINING_PATTERN_3);
674 : else
675 0 : amdgpu_atombios_dp_set_tp(dp_info, DP_TRAINING_PATTERN_2);
676 :
677 : /* channel equalization loop */
678 0 : dp_info->tries = 0;
679 0 : channel_eq = false;
680 : while (1) {
681 0 : drm_dp_link_train_channel_eq_delay(dp_info->aux, dp_info->dpcd);
682 :
683 0 : if (drm_dp_dpcd_read_link_status(dp_info->aux,
684 0 : dp_info->link_status) <= 0) {
685 0 : DRM_ERROR("displayport link status failed\n");
686 0 : break;
687 : }
688 :
689 0 : if (drm_dp_channel_eq_ok(dp_info->link_status, dp_info->dp_lane_count)) {
690 : channel_eq = true;
691 : break;
692 : }
693 :
694 : /* Try 5 times */
695 0 : if (dp_info->tries > 5) {
696 0 : DRM_ERROR("channel eq failed: 5 tries\n");
697 0 : break;
698 : }
699 :
700 : /* Compute new train_set as requested by sink */
701 0 : amdgpu_atombios_dp_get_adjust_train(dp_info->link_status, dp_info->dp_lane_count,
702 0 : dp_info->train_set);
703 :
704 0 : amdgpu_atombios_dp_update_vs_emph(dp_info);
705 0 : dp_info->tries++;
706 : }
707 :
708 0 : if (!channel_eq) {
709 0 : DRM_ERROR("channel eq failed\n");
710 0 : return -1;
711 : } else {
712 0 : DRM_DEBUG_KMS("channel eq at voltage %d pre-emphasis %d\n",
713 : dp_info->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK,
714 : (dp_info->train_set[0] & DP_TRAIN_PRE_EMPHASIS_MASK)
715 : >> DP_TRAIN_PRE_EMPHASIS_SHIFT);
716 0 : return 0;
717 : }
718 : }
719 :
720 0 : void amdgpu_atombios_dp_link_train(struct drm_encoder *encoder,
721 : struct drm_connector *connector)
722 : {
723 0 : struct drm_device *dev = encoder->dev;
724 0 : struct amdgpu_device *adev = drm_to_adev(dev);
725 0 : struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
726 : struct amdgpu_connector *amdgpu_connector;
727 : struct amdgpu_connector_atom_dig *dig_connector;
728 : struct amdgpu_atombios_dp_link_train_info dp_info;
729 : u8 tmp;
730 :
731 0 : if (!amdgpu_encoder->enc_priv)
732 0 : return;
733 :
734 0 : amdgpu_connector = to_amdgpu_connector(connector);
735 0 : if (!amdgpu_connector->con_priv)
736 : return;
737 0 : dig_connector = amdgpu_connector->con_priv;
738 :
739 0 : if ((dig_connector->dp_sink_type != CONNECTOR_OBJECT_ID_DISPLAYPORT) &&
740 : (dig_connector->dp_sink_type != CONNECTOR_OBJECT_ID_eDP))
741 : return;
742 :
743 0 : if (drm_dp_dpcd_readb(&amdgpu_connector->ddc_bus->aux, DP_MAX_LANE_COUNT, &tmp)
744 : == 1) {
745 0 : if (tmp & DP_TPS3_SUPPORTED)
746 0 : dp_info.tp3_supported = true;
747 : else
748 0 : dp_info.tp3_supported = false;
749 : } else {
750 0 : dp_info.tp3_supported = false;
751 : }
752 :
753 0 : memcpy(dp_info.dpcd, dig_connector->dpcd, DP_RECEIVER_CAP_SIZE);
754 0 : dp_info.adev = adev;
755 0 : dp_info.encoder = encoder;
756 0 : dp_info.connector = connector;
757 0 : dp_info.dp_lane_count = dig_connector->dp_lane_count;
758 0 : dp_info.dp_clock = dig_connector->dp_clock;
759 0 : dp_info.aux = &amdgpu_connector->ddc_bus->aux;
760 :
761 0 : if (amdgpu_atombios_dp_link_train_init(&dp_info))
762 : goto done;
763 0 : if (amdgpu_atombios_dp_link_train_cr(&dp_info))
764 : goto done;
765 0 : if (amdgpu_atombios_dp_link_train_ce(&dp_info))
766 : goto done;
767 : done:
768 0 : if (amdgpu_atombios_dp_link_train_finish(&dp_info))
769 : return;
770 : }
|