1746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie/*
2746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie * Copyright 2007-8 Advanced Micro Devices, Inc.
3746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie * Copyright 2008 Red Hat Inc.
4746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie *
5746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie * Permission is hereby granted, free of charge, to any person obtaining a
6746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie * copy of this software and associated documentation files (the "Software"),
7746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie * to deal in the Software without restriction, including without limitation
8746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie * and/or sell copies of the Software, and to permit persons to whom the
10746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie * Software is furnished to do so, subject to the following conditions:
11746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie *
12746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie * The above copyright notice and this permission notice shall be included in
13746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie * all copies or substantial portions of the Software.
14746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie *
15746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
19746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie * OTHER DEALINGS IN THE SOFTWARE.
22746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie *
23746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie * Authors: Dave Airlie
24746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie *          Alex Deucher
25746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie */
26746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie#include "drmP.h"
27746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie#include "radeon_drm.h"
28746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie#include "radeon.h"
29746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie
30746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie#include "atom.h"
31746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie#include "atom-bits.h"
32746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie#include "drm_dp_helper.h"
33746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie
34f92a8b6758bdc0f277c4f42aa7d736a205ac9dedAlex Deucher/* move these to drm_dp_helper.c/h */
355801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher#define DP_LINK_CONFIGURATION_SIZE 9
365801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher#define DP_LINK_STATUS_SIZE	   6
375801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher#define DP_DPCD_SIZE	           8
385801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher
395801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucherstatic char *voltage_names[] = {
405801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher        "0.4V", "0.6V", "0.8V", "1.2V"
415801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher};
425801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucherstatic char *pre_emph_names[] = {
435801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher        "0dB", "3.5dB", "6dB", "9.5dB"
445801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher};
45f92a8b6758bdc0f277c4f42aa7d736a205ac9dedAlex Deucher
46224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher/***** radeon AUX functions *****/
47224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucherunion aux_channel_transaction {
48224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	PROCESS_AUX_CHANNEL_TRANSACTION_PS_ALLOCATION v1;
49224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS_V2 v2;
50f92a8b6758bdc0f277c4f42aa7d736a205ac9dedAlex Deucher};
51f92a8b6758bdc0f277c4f42aa7d736a205ac9dedAlex Deucher
52224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucherstatic int radeon_process_aux_ch(struct radeon_i2c_chan *chan,
53224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher				 u8 *send, int send_bytes,
54224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher				 u8 *recv, int recv_size,
55224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher				 u8 delay, u8 *ack)
56224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher{
57224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	struct drm_device *dev = chan->dev;
58224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	struct radeon_device *rdev = dev->dev_private;
59224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	union aux_channel_transaction args;
60224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	int index = GetIndexIntoMasterTable(COMMAND, ProcessAuxChannelTransaction);
61224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	unsigned char *base;
62224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	int recv_bytes;
63224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher
64224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	memset(&args, 0, sizeof(args));
65f92a8b6758bdc0f277c4f42aa7d736a205ac9dedAlex Deucher
66224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	base = (unsigned char *)rdev->mode_info.atom_context->scratch;
67224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher
68224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	memcpy(base, send, send_bytes);
69224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher
70224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	args.v1.lpAuxRequest = 0;
71224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	args.v1.lpDataOut = 16;
72224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	args.v1.ucDataOutLen = 0;
73224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	args.v1.ucChannelID = chan->rec.i2c_id;
74224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	args.v1.ucDelay = delay / 10;
75224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	if (ASIC_IS_DCE4(rdev))
76224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		args.v2.ucHPD_ID = chan->rec.hpd;
77224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher
78224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
79224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher
80224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	*ack = args.v1.ucReplyStatus;
81224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher
82224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	/* timeout */
83224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	if (args.v1.ucReplyStatus == 1) {
84224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		DRM_DEBUG_KMS("dp_aux_ch timeout\n");
85224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		return -ETIMEDOUT;
86224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	}
87224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher
88224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	/* flags not zero */
89224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	if (args.v1.ucReplyStatus == 2) {
90224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		DRM_DEBUG_KMS("dp_aux_ch flags not zero\n");
91224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		return -EBUSY;
92224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	}
93224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher
94224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	/* error */
95224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	if (args.v1.ucReplyStatus == 3) {
96224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		DRM_DEBUG_KMS("dp_aux_ch error\n");
97224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		return -EIO;
98224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	}
99224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher
100224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	recv_bytes = args.v1.ucDataOutLen;
101224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	if (recv_bytes > recv_size)
102224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		recv_bytes = recv_size;
103224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher
104224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	if (recv && recv_size)
105224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		memcpy(recv, base + 16, recv_bytes);
106224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher
107224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	return recv_bytes;
108224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher}
109224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher
110224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucherstatic int radeon_dp_aux_native_write(struct radeon_connector *radeon_connector,
111224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher				      u16 address, u8 *send, u8 send_bytes, u8 delay)
112f92a8b6758bdc0f277c4f42aa7d736a205ac9dedAlex Deucher{
113224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;
114224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	int ret;
115224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	u8 msg[20];
116224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	int msg_bytes = send_bytes + 4;
117224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	u8 ack;
1186375bda073724ead7df08746866b724b1799a295Alex Deucher	unsigned retry;
1195801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher
120224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	if (send_bytes > 16)
121224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		return -1;
1225801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher
123224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	msg[0] = address;
124224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	msg[1] = address >> 8;
125224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	msg[2] = AUX_NATIVE_WRITE << 4;
126224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	msg[3] = (msg_bytes << 4) | (send_bytes - 1);
127224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	memcpy(&msg[4], send, send_bytes);
128f92a8b6758bdc0f277c4f42aa7d736a205ac9dedAlex Deucher
1296375bda073724ead7df08746866b724b1799a295Alex Deucher	for (retry = 0; retry < 4; retry++) {
130224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		ret = radeon_process_aux_ch(dig_connector->dp_i2c_bus,
131224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher					    msg, msg_bytes, NULL, 0, delay, &ack);
1324f332844cc87c5f99c5300f788abbe8a8c731390Alex Deucher		if (ret == -EBUSY)
1334f332844cc87c5f99c5300f788abbe8a8c731390Alex Deucher			continue;
1344f332844cc87c5f99c5300f788abbe8a8c731390Alex Deucher		else if (ret < 0)
135224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher			return ret;
136224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_ACK)
1376375bda073724ead7df08746866b724b1799a295Alex Deucher			return send_bytes;
138224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		else if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_DEFER)
139224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher			udelay(400);
140224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		else
141224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher			return -EIO;
142f92a8b6758bdc0f277c4f42aa7d736a205ac9dedAlex Deucher	}
143f92a8b6758bdc0f277c4f42aa7d736a205ac9dedAlex Deucher
1446375bda073724ead7df08746866b724b1799a295Alex Deucher	return -EIO;
145f92a8b6758bdc0f277c4f42aa7d736a205ac9dedAlex Deucher}
146f92a8b6758bdc0f277c4f42aa7d736a205ac9dedAlex Deucher
147224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucherstatic int radeon_dp_aux_native_read(struct radeon_connector *radeon_connector,
148224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher				     u16 address, u8 *recv, int recv_bytes, u8 delay)
149f92a8b6758bdc0f277c4f42aa7d736a205ac9dedAlex Deucher{
150224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;
151224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	u8 msg[4];
152224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	int msg_bytes = 4;
153224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	u8 ack;
154224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	int ret;
1556375bda073724ead7df08746866b724b1799a295Alex Deucher	unsigned retry;
1565801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher
157224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	msg[0] = address;
158224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	msg[1] = address >> 8;
159224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	msg[2] = AUX_NATIVE_READ << 4;
160224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	msg[3] = (msg_bytes << 4) | (recv_bytes - 1);
1615801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher
1626375bda073724ead7df08746866b724b1799a295Alex Deucher	for (retry = 0; retry < 4; retry++) {
163224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		ret = radeon_process_aux_ch(dig_connector->dp_i2c_bus,
164224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher					    msg, msg_bytes, recv, recv_bytes, delay, &ack);
1654f332844cc87c5f99c5300f788abbe8a8c731390Alex Deucher		if (ret == -EBUSY)
1664f332844cc87c5f99c5300f788abbe8a8c731390Alex Deucher			continue;
1674f332844cc87c5f99c5300f788abbe8a8c731390Alex Deucher		else if (ret < 0)
168224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher			return ret;
169224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_ACK)
170224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher			return ret;
171224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		else if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_DEFER)
172224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher			udelay(400);
173109bc10d30f33e84f1d7289f0039e0c858ade82fAlex Deucher		else if (ret == 0)
174109bc10d30f33e84f1d7289f0039e0c858ade82fAlex Deucher			return -EPROTO;
175224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		else
176224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher			return -EIO;
177224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	}
1786375bda073724ead7df08746866b724b1799a295Alex Deucher
1796375bda073724ead7df08746866b724b1799a295Alex Deucher	return -EIO;
180224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher}
181f92a8b6758bdc0f277c4f42aa7d736a205ac9dedAlex Deucher
182224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucherstatic void radeon_write_dpcd_reg(struct radeon_connector *radeon_connector,
183224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher				 u16 reg, u8 val)
184224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher{
185224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	radeon_dp_aux_native_write(radeon_connector, reg, &val, 1, 0);
186224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher}
187224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher
188224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucherstatic u8 radeon_read_dpcd_reg(struct radeon_connector *radeon_connector,
189224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher			       u16 reg)
190224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher{
191224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	u8 val = 0;
192224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher
193224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	radeon_dp_aux_native_read(radeon_connector, reg, &val, 1, 0);
194224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher
195224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	return val;
196224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher}
197224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher
198224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucherint radeon_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode,
199224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher			 u8 write_byte, u8 *read_byte)
200224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher{
201224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
202224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	struct radeon_i2c_chan *auxch = (struct radeon_i2c_chan *)adapter;
203224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	u16 address = algo_data->address;
204224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	u8 msg[5];
205224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	u8 reply[2];
206224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	unsigned retry;
207224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	int msg_bytes;
208224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	int reply_bytes = 1;
209224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	int ret;
210224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	u8 ack;
211224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher
212224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	/* Set up the command byte */
213224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	if (mode & MODE_I2C_READ)
214224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		msg[2] = AUX_I2C_READ << 4;
215224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	else
216224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		msg[2] = AUX_I2C_WRITE << 4;
217224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher
218224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	if (!(mode & MODE_I2C_STOP))
219224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		msg[2] |= AUX_I2C_MOT << 4;
220224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher
221224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	msg[0] = address;
222224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	msg[1] = address >> 8;
223224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher
224224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	switch (mode) {
225224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	case MODE_I2C_WRITE:
226224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		msg_bytes = 5;
227224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		msg[3] = msg_bytes << 4;
228224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		msg[4] = write_byte;
229224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		break;
230224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	case MODE_I2C_READ:
231224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		msg_bytes = 4;
232224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		msg[3] = msg_bytes << 4;
233224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		break;
234f92a8b6758bdc0f277c4f42aa7d736a205ac9dedAlex Deucher	default:
235224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		msg_bytes = 4;
236224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		msg[3] = 3 << 4;
237f92a8b6758bdc0f277c4f42aa7d736a205ac9dedAlex Deucher		break;
238f92a8b6758bdc0f277c4f42aa7d736a205ac9dedAlex Deucher	}
239f92a8b6758bdc0f277c4f42aa7d736a205ac9dedAlex Deucher
240224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	for (retry = 0; retry < 4; retry++) {
241224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		ret = radeon_process_aux_ch(auxch,
242224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher					    msg, msg_bytes, reply, reply_bytes, 0, &ack);
2434f332844cc87c5f99c5300f788abbe8a8c731390Alex Deucher		if (ret == -EBUSY)
2444f332844cc87c5f99c5300f788abbe8a8c731390Alex Deucher			continue;
2454f332844cc87c5f99c5300f788abbe8a8c731390Alex Deucher		else if (ret < 0) {
246224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher			DRM_DEBUG_KMS("aux_ch failed %d\n", ret);
247224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher			return ret;
248224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		}
249f92a8b6758bdc0f277c4f42aa7d736a205ac9dedAlex Deucher
250224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		switch (ack & AUX_NATIVE_REPLY_MASK) {
251224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		case AUX_NATIVE_REPLY_ACK:
252224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher			/* I2C-over-AUX Reply field is only valid
253224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher			 * when paired with AUX ACK.
254224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher			 */
255224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher			break;
256224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		case AUX_NATIVE_REPLY_NACK:
257224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher			DRM_DEBUG_KMS("aux_ch native nack\n");
258224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher			return -EREMOTEIO;
259224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		case AUX_NATIVE_REPLY_DEFER:
260224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher			DRM_DEBUG_KMS("aux_ch native defer\n");
261224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher			udelay(400);
262224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher			continue;
263224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		default:
264224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher			DRM_ERROR("aux_ch invalid native reply 0x%02x\n", ack);
265224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher			return -EREMOTEIO;
266224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		}
2675801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher
268224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		switch (ack & AUX_I2C_REPLY_MASK) {
269224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		case AUX_I2C_REPLY_ACK:
270224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher			if (mode == MODE_I2C_READ)
271224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher				*read_byte = reply[0];
272224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher			return ret;
273224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		case AUX_I2C_REPLY_NACK:
274224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher			DRM_DEBUG_KMS("aux_i2c nack\n");
275224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher			return -EREMOTEIO;
276224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		case AUX_I2C_REPLY_DEFER:
277224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher			DRM_DEBUG_KMS("aux_i2c defer\n");
278224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher			udelay(400);
279224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher			break;
280224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		default:
281224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher			DRM_ERROR("aux_i2c invalid reply 0x%02x\n", ack);
282224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher			return -EREMOTEIO;
283224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		}
284224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	}
2855801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher
286091264f0bc12419560ac64fcef4567809d611658Alex Deucher	DRM_DEBUG_KMS("aux i2c too many retries, giving up\n");
287224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	return -EREMOTEIO;
2885801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher}
2895801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher
290224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher/***** general DP utility functions *****/
291224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher
2925801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucherstatic u8 dp_link_status(u8 link_status[DP_LINK_STATUS_SIZE], int r)
2935801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher{
2945801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher	return link_status[r - DP_LANE0_1_STATUS];
2955801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher}
2965801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher
2975801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucherstatic u8 dp_get_lane_status(u8 link_status[DP_LINK_STATUS_SIZE],
2985801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher			     int lane)
2995801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher{
3005801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher	int i = DP_LANE0_1_STATUS + (lane >> 1);
3015801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher	int s = (lane & 1) * 4;
3025801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher	u8 l = dp_link_status(link_status, i);
3035801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher	return (l >> s) & 0xf;
3045801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher}
3055801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher
3065801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucherstatic bool dp_clock_recovery_ok(u8 link_status[DP_LINK_STATUS_SIZE],
3075801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher				 int lane_count)
3085801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher{
3095801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher	int lane;
3105801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher	u8 lane_status;
3115801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher
3125801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher	for (lane = 0; lane < lane_count; lane++) {
3135801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher		lane_status = dp_get_lane_status(link_status, lane);
3145801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher		if ((lane_status & DP_LANE_CR_DONE) == 0)
3155801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher			return false;
3165801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher	}
3175801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher	return true;
3185801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher}
3195801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher
3205801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucherstatic bool dp_channel_eq_ok(u8 link_status[DP_LINK_STATUS_SIZE],
3215801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher			     int lane_count)
3225801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher{
3235801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher	u8 lane_align;
3245801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher	u8 lane_status;
3255801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher	int lane;
3265801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher
3275801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher	lane_align = dp_link_status(link_status,
3285801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher				    DP_LANE_ALIGN_STATUS_UPDATED);
3295801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher	if ((lane_align & DP_INTERLANE_ALIGN_DONE) == 0)
3305801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher		return false;
3315801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher	for (lane = 0; lane < lane_count; lane++) {
3325801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher		lane_status = dp_get_lane_status(link_status, lane);
3335801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher		if ((lane_status & DP_CHANNEL_EQ_BITS) != DP_CHANNEL_EQ_BITS)
3345801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher			return false;
3355801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher	}
3365801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher	return true;
3375801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher}
3385801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher
339224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucherstatic u8 dp_get_adjust_request_voltage(u8 link_status[DP_LINK_STATUS_SIZE],
3405801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher					int lane)
3415801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher
3425801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher{
3435801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher	int i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1);
3445801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher	int s = ((lane & 1) ?
3455801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher		 DP_ADJUST_VOLTAGE_SWING_LANE1_SHIFT :
3465801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher		 DP_ADJUST_VOLTAGE_SWING_LANE0_SHIFT);
3475801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher	u8 l = dp_link_status(link_status, i);
3485801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher
3495801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher	return ((l >> s) & 0x3) << DP_TRAIN_VOLTAGE_SWING_SHIFT;
3505801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher}
3515801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher
352224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucherstatic u8 dp_get_adjust_request_pre_emphasis(u8 link_status[DP_LINK_STATUS_SIZE],
3535801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher					     int lane)
3545801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher{
3555801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher	int i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1);
3565801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher	int s = ((lane & 1) ?
3575801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher		 DP_ADJUST_PRE_EMPHASIS_LANE1_SHIFT :
3585801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher		 DP_ADJUST_PRE_EMPHASIS_LANE0_SHIFT);
3595801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher	u8 l = dp_link_status(link_status, i);
3605801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher
3615801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher	return ((l >> s) & 0x3) << DP_TRAIN_PRE_EMPHASIS_SHIFT;
3625801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher}
3635801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher
3645801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher#define DP_VOLTAGE_MAX         DP_TRAIN_VOLTAGE_SWING_1200
365224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher#define DP_PRE_EMPHASIS_MAX    DP_TRAIN_PRE_EMPHASIS_9_5
3665801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher
3675801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucherstatic void dp_get_adjust_train(u8 link_status[DP_LINK_STATUS_SIZE],
3685801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher				int lane_count,
3695801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher				u8 train_set[4])
3705801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher{
3715801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher	u8 v = 0;
3725801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher	u8 p = 0;
3735801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher	int lane;
3745801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher
3755801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher	for (lane = 0; lane < lane_count; lane++) {
3765801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher		u8 this_v = dp_get_adjust_request_voltage(link_status, lane);
3775801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher		u8 this_p = dp_get_adjust_request_pre_emphasis(link_status, lane);
3785801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher
379d9fdaafbe912a34ef06ed569c6606fe2811f325bDave Airlie		DRM_DEBUG_KMS("requested signal parameters: lane %d voltage %s pre_emph %s\n",
38053c1e09fea4cf3fc0ec1f735a5fcab78c43cb55dAlex Deucher			  lane,
38153c1e09fea4cf3fc0ec1f735a5fcab78c43cb55dAlex Deucher			  voltage_names[this_v >> DP_TRAIN_VOLTAGE_SWING_SHIFT],
38253c1e09fea4cf3fc0ec1f735a5fcab78c43cb55dAlex Deucher			  pre_emph_names[this_p >> DP_TRAIN_PRE_EMPHASIS_SHIFT]);
3835801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher
3845801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher		if (this_v > v)
3855801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher			v = this_v;
3865801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher		if (this_p > p)
3875801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher			p = this_p;
3885801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher	}
3895801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher
3905801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher	if (v >= DP_VOLTAGE_MAX)
391224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		v |= DP_TRAIN_MAX_SWING_REACHED;
3925801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher
393224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	if (p >= DP_PRE_EMPHASIS_MAX)
394224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		p |= DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
3955801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher
396d9fdaafbe912a34ef06ed569c6606fe2811f325bDave Airlie	DRM_DEBUG_KMS("using signal parameters: voltage %s pre_emph %s\n",
39753c1e09fea4cf3fc0ec1f735a5fcab78c43cb55dAlex Deucher		  voltage_names[(v & DP_TRAIN_VOLTAGE_SWING_MASK) >> DP_TRAIN_VOLTAGE_SWING_SHIFT],
39853c1e09fea4cf3fc0ec1f735a5fcab78c43cb55dAlex Deucher		  pre_emph_names[(p & DP_TRAIN_PRE_EMPHASIS_MASK) >> DP_TRAIN_PRE_EMPHASIS_SHIFT]);
3995801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher
4005801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher	for (lane = 0; lane < 4; lane++)
4015801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher		train_set[lane] = v | p;
4025801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher}
4035801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher
404224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher/* convert bits per color to bits per pixel */
405224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher/* get bpc from the EDID */
406224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucherstatic int convert_bpc_to_bpp(int bpc)
407746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie{
408224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	if (bpc == 0)
409224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		return 24;
410224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	else
411224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		return bpc * 3;
412224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher}
413746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie
414224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher/* get the max pix clock supported by the link rate and lane num */
415224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucherstatic int dp_get_max_dp_pix_clock(int link_rate,
416224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher				   int lane_num,
417224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher				   int bpp)
418224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher{
419224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	return (link_rate * lane_num * 8) / bpp;
420224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher}
421834b2904bbfde3d85b5e984688777d56e9c7bf80Alex Deucher
422224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucherstatic int dp_get_max_link_rate(u8 dpcd[DP_DPCD_SIZE])
423224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher{
424224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	switch (dpcd[DP_MAX_LINK_RATE]) {
425224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	case DP_LINK_BW_1_62:
426224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	default:
427224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		return 162000;
428224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	case DP_LINK_BW_2_7:
429224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		return 270000;
430224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	case DP_LINK_BW_5_4:
431224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		return 540000;
432834b2904bbfde3d85b5e984688777d56e9c7bf80Alex Deucher	}
433746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie}
434746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie
435224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucherstatic u8 dp_get_max_lane_number(u8 dpcd[DP_DPCD_SIZE])
436746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie{
437224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	return dpcd[DP_MAX_LANE_COUNT] & DP_MAX_LANE_COUNT_MASK;
438224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher}
439834b2904bbfde3d85b5e984688777d56e9c7bf80Alex Deucher
440224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucherstatic u8 dp_get_dp_link_rate_coded(int link_rate)
441224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher{
442224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	switch (link_rate) {
443224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	case 162000:
444224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	default:
445224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		return DP_LINK_BW_1_62;
446224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	case 270000:
447224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		return DP_LINK_BW_2_7;
448224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	case 540000:
449224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		return DP_LINK_BW_5_4;
450224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	}
451224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher}
452746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie
453224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher/***** radeon specific DP functions *****/
454746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie
455224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher/* First get the min lane# when low rate is used according to pixel clock
456224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher * (prefer low rate), second check max lane# supported by DP panel,
457224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher * if the max lane# < low rate lane# then use max lane# instead.
458224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher */
459224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucherstatic int radeon_dp_get_dp_lane_number(struct drm_connector *connector,
460224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher					u8 dpcd[DP_DPCD_SIZE],
461224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher					int pix_clock)
462224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher{
463224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	int bpp = convert_bpc_to_bpp(connector->display_info.bpc);
464224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	int max_link_rate = dp_get_max_link_rate(dpcd);
465224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	int max_lane_num = dp_get_max_lane_number(dpcd);
466224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	int lane_num;
467224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	int max_dp_pix_clock;
468224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher
469224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	for (lane_num = 1; lane_num < max_lane_num; lane_num <<= 1) {
470224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		max_dp_pix_clock = dp_get_max_dp_pix_clock(max_link_rate, lane_num, bpp);
471224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		if (pix_clock <= max_dp_pix_clock)
472224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher			break;
473834b2904bbfde3d85b5e984688777d56e9c7bf80Alex Deucher	}
474746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie
475224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	return lane_num;
476746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie}
477746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie
478224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucherstatic int radeon_dp_get_dp_link_clock(struct drm_connector *connector,
479224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher				       u8 dpcd[DP_DPCD_SIZE],
480224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher				       int pix_clock)
481746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie{
482224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	int bpp = convert_bpc_to_bpp(connector->display_info.bpc);
483224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	int lane_num, max_pix_clock;
484224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher
485fdca78c3b8876e47f1c92b3b28693b261bfd913aAlex Deucher	if (radeon_connector_encoder_get_dp_bridge_encoder_id(connector) ==
486fdca78c3b8876e47f1c92b3b28693b261bfd913aAlex Deucher	    ENCODER_OBJECT_ID_NUTMEG)
487224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		return 270000;
488224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher
489224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	lane_num = radeon_dp_get_dp_lane_number(connector, dpcd, pix_clock);
490224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	max_pix_clock = dp_get_max_dp_pix_clock(162000, lane_num, bpp);
491224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	if (pix_clock <= max_pix_clock)
492224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		return 162000;
493224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	max_pix_clock = dp_get_max_dp_pix_clock(270000, lane_num, bpp);
494224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	if (pix_clock <= max_pix_clock)
495224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		return 270000;
496224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	if (radeon_connector_is_dp12_capable(connector)) {
497224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		max_pix_clock = dp_get_max_dp_pix_clock(540000, lane_num, bpp);
498224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		if (pix_clock <= max_pix_clock)
499224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher			return 540000;
500834b2904bbfde3d85b5e984688777d56e9c7bf80Alex Deucher	}
501224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher
502224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	return dp_get_max_link_rate(dpcd);
503746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie}
504746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie
505834b2904bbfde3d85b5e984688777d56e9c7bf80Alex Deucherstatic u8 radeon_dp_encoder_service(struct radeon_device *rdev,
506834b2904bbfde3d85b5e984688777d56e9c7bf80Alex Deucher				    int action, int dp_clock,
507224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher				    u8 ucconfig, u8 lane_num)
5085801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher{
5095801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher	DP_ENCODER_SERVICE_PARAMETERS args;
5105801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher	int index = GetIndexIntoMasterTable(COMMAND, DPEncoderService);
5115801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher
5125801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher	memset(&args, 0, sizeof(args));
5135801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher	args.ucLinkClock = dp_clock / 10;
5145801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher	args.ucConfig = ucconfig;
5155801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher	args.ucAction = action;
5165801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher	args.ucLaneNum = lane_num;
5175801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher	args.ucStatus = 0;
5185801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher
5195801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
5205801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher	return args.ucStatus;
5215801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher}
5225801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher
5235801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucheru8 radeon_dp_getsinktype(struct radeon_connector *radeon_connector)
5245801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher{
5255801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher	struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;
5265801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher	struct drm_device *dev = radeon_connector->base.dev;
5275801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher	struct radeon_device *rdev = dev->dev_private;
5285801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher
5295801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher	return radeon_dp_encoder_service(rdev, ATOM_DP_ACTION_GET_SINK_TYPE, 0,
5305801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher					 dig_connector->dp_i2c_bus->rec.i2c_id, 0);
5315801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher}
5325801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher
5339fa05c98d69eb77c82e59b5e434ca63bba230ba0Alex Deucherbool radeon_dp_getdpcd(struct radeon_connector *radeon_connector)
534746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie{
5355801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher	struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;
536746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie	u8 msg[25];
537224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	int ret, i;
538746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie
539834b2904bbfde3d85b5e984688777d56e9c7bf80Alex Deucher	ret = radeon_dp_aux_native_read(radeon_connector, DP_DPCD_REV, msg, 8, 0);
540834b2904bbfde3d85b5e984688777d56e9c7bf80Alex Deucher	if (ret > 0) {
5415801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher		memcpy(dig_connector->dpcd, msg, 8);
542224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		DRM_DEBUG_KMS("DPCD: ");
543224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		for (i = 0; i < 8; i++)
544224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher			DRM_DEBUG_KMS("%02x ", msg[i]);
545224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		DRM_DEBUG_KMS("\n");
5469fa05c98d69eb77c82e59b5e434ca63bba230ba0Alex Deucher		return true;
547746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie	}
5485801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher	dig_connector->dpcd[0] = 0;
5499fa05c98d69eb77c82e59b5e434ca63bba230ba0Alex Deucher	return false;
550746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie}
551746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie
552386d4d751e8e0b4b693bb724f09aae064ee5297dAlex Deucherint radeon_dp_get_panel_mode(struct drm_encoder *encoder,
553386d4d751e8e0b4b693bb724f09aae064ee5297dAlex Deucher			     struct drm_connector *connector)
554224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher{
555224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	struct drm_device *dev = encoder->dev;
556224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	struct radeon_device *rdev = dev->dev_private;
55700dfb8df5bf8c3afe4c0bb8361133156b06b7a2cAlex Deucher	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
558224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	int panel_mode = DP_PANEL_MODE_EXTERNAL_DP_MODE;
559224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher
560224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	if (!ASIC_IS_DCE4(rdev))
561386d4d751e8e0b4b693bb724f09aae064ee5297dAlex Deucher		return panel_mode;
562224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher
563cf2aff6eff251b6fbdaf8c253e65ff7c693de8cdAlex Deucher	if (radeon_connector_encoder_get_dp_bridge_encoder_id(connector) ==
564cf2aff6eff251b6fbdaf8c253e65ff7c693de8cdAlex Deucher	    ENCODER_OBJECT_ID_NUTMEG)
565224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		panel_mode = DP_PANEL_MODE_INTERNAL_DP1_MODE;
566cf2aff6eff251b6fbdaf8c253e65ff7c693de8cdAlex Deucher	else if (radeon_connector_encoder_get_dp_bridge_encoder_id(connector) ==
567304a48400d9718f74ec35ae46f30868a5f4c4516Alex Deucher		 ENCODER_OBJECT_ID_TRAVIS) {
568304a48400d9718f74ec35ae46f30868a5f4c4516Alex Deucher		u8 id[6];
569304a48400d9718f74ec35ae46f30868a5f4c4516Alex Deucher		int i;
570304a48400d9718f74ec35ae46f30868a5f4c4516Alex Deucher		for (i = 0; i < 6; i++)
571304a48400d9718f74ec35ae46f30868a5f4c4516Alex Deucher			id[i] = radeon_read_dpcd_reg(radeon_connector, 0x503 + i);
572304a48400d9718f74ec35ae46f30868a5f4c4516Alex Deucher		if (id[0] == 0x73 &&
573304a48400d9718f74ec35ae46f30868a5f4c4516Alex Deucher		    id[1] == 0x69 &&
574304a48400d9718f74ec35ae46f30868a5f4c4516Alex Deucher		    id[2] == 0x76 &&
575304a48400d9718f74ec35ae46f30868a5f4c4516Alex Deucher		    id[3] == 0x61 &&
576304a48400d9718f74ec35ae46f30868a5f4c4516Alex Deucher		    id[4] == 0x72 &&
577304a48400d9718f74ec35ae46f30868a5f4c4516Alex Deucher		    id[5] == 0x54)
578304a48400d9718f74ec35ae46f30868a5f4c4516Alex Deucher			panel_mode = DP_PANEL_MODE_INTERNAL_DP1_MODE;
579304a48400d9718f74ec35ae46f30868a5f4c4516Alex Deucher		else
580304a48400d9718f74ec35ae46f30868a5f4c4516Alex Deucher			panel_mode = DP_PANEL_MODE_INTERNAL_DP2_MODE;
581304a48400d9718f74ec35ae46f30868a5f4c4516Alex Deucher	} else if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
58200dfb8df5bf8c3afe4c0bb8361133156b06b7a2cAlex Deucher		u8 tmp = radeon_read_dpcd_reg(radeon_connector, DP_EDP_CONFIGURATION_CAP);
58300dfb8df5bf8c3afe4c0bb8361133156b06b7a2cAlex Deucher		if (tmp & 1)
58400dfb8df5bf8c3afe4c0bb8361133156b06b7a2cAlex Deucher			panel_mode = DP_PANEL_MODE_INTERNAL_DP2_MODE;
58500dfb8df5bf8c3afe4c0bb8361133156b06b7a2cAlex Deucher	}
586224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher
587386d4d751e8e0b4b693bb724f09aae064ee5297dAlex Deucher	return panel_mode;
588224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher}
589224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher
5905801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deuchervoid radeon_dp_set_link_config(struct drm_connector *connector,
5915801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher			       struct drm_display_mode *mode)
5925801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher{
593224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
5945801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher	struct radeon_connector_atom_dig *dig_connector;
5955801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher
5965801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher	if (!radeon_connector->con_priv)
5975801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher		return;
5985801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher	dig_connector = radeon_connector->con_priv;
5995801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher
600224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||
601224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	    (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) {
602224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		dig_connector->dp_clock =
603224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher			radeon_dp_get_dp_link_clock(connector, dig_connector->dpcd, mode->clock);
604224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		dig_connector->dp_lane_count =
605224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher			radeon_dp_get_dp_lane_number(connector, dig_connector->dpcd, mode->clock);
606224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	}
6075801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher}
6085801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher
609224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucherint radeon_dp_mode_valid_helper(struct drm_connector *connector,
6105801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher				struct drm_display_mode *mode)
6115801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher{
612224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
613224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	struct radeon_connector_atom_dig *dig_connector;
614224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	int dp_clock;
6155801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher
616224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	if (!radeon_connector->con_priv)
617224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		return MODE_CLOCK_HIGH;
618224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	dig_connector = radeon_connector->con_priv;
619224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher
620224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	dp_clock =
621224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		radeon_dp_get_dp_link_clock(connector, dig_connector->dpcd, mode->clock);
622224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher
623224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	if ((dp_clock == 540000) &&
624224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	    (!radeon_connector_is_dp12_capable(connector)))
625224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		return MODE_CLOCK_HIGH;
626224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher
627224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	return MODE_OK;
6285801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher}
6295801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher
630224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucherstatic bool radeon_dp_get_link_status(struct radeon_connector *radeon_connector,
631224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher				      u8 link_status[DP_LINK_STATUS_SIZE])
632746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie{
633746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie	int ret;
634834b2904bbfde3d85b5e984688777d56e9c7bf80Alex Deucher	ret = radeon_dp_aux_native_read(radeon_connector, DP_LANE0_1_STATUS,
635834b2904bbfde3d85b5e984688777d56e9c7bf80Alex Deucher					link_status, DP_LINK_STATUS_SIZE, 100);
636834b2904bbfde3d85b5e984688777d56e9c7bf80Alex Deucher	if (ret <= 0) {
637746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie		DRM_ERROR("displayport link status failed\n");
638746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie		return false;
639746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie	}
640746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie
641d9fdaafbe912a34ef06ed569c6606fe2811f325bDave Airlie	DRM_DEBUG_KMS("link status %02x %02x %02x %02x %02x %02x\n",
64253c1e09fea4cf3fc0ec1f735a5fcab78c43cb55dAlex Deucher		  link_status[0], link_status[1], link_status[2],
64353c1e09fea4cf3fc0ec1f735a5fcab78c43cb55dAlex Deucher		  link_status[3], link_status[4], link_status[5]);
644746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie	return true;
645746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie}
646746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie
647d5811e8731213f80c80d89e980505052f16aca1cAlex Deucherbool radeon_dp_needs_link_train(struct radeon_connector *radeon_connector)
648d5811e8731213f80c80d89e980505052f16aca1cAlex Deucher{
649d5811e8731213f80c80d89e980505052f16aca1cAlex Deucher	u8 link_status[DP_LINK_STATUS_SIZE];
650d5811e8731213f80c80d89e980505052f16aca1cAlex Deucher	struct radeon_connector_atom_dig *dig = radeon_connector->con_priv;
651d5811e8731213f80c80d89e980505052f16aca1cAlex Deucher
652d5811e8731213f80c80d89e980505052f16aca1cAlex Deucher	if (!radeon_dp_get_link_status(radeon_connector, link_status))
653d5811e8731213f80c80d89e980505052f16aca1cAlex Deucher		return false;
654d5811e8731213f80c80d89e980505052f16aca1cAlex Deucher	if (dp_channel_eq_ok(link_status, dig->dp_lane_count))
655d5811e8731213f80c80d89e980505052f16aca1cAlex Deucher		return false;
656d5811e8731213f80c80d89e980505052f16aca1cAlex Deucher	return true;
657d5811e8731213f80c80d89e980505052f16aca1cAlex Deucher}
658d5811e8731213f80c80d89e980505052f16aca1cAlex Deucher
659224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucherstruct radeon_dp_link_train_info {
660224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	struct radeon_device *rdev;
661224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	struct drm_encoder *encoder;
662224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	struct drm_connector *connector;
663224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	struct radeon_connector *radeon_connector;
664224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	int enc_id;
665224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	int dp_clock;
666224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	int dp_lane_count;
667224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	int rd_interval;
668224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	bool tp3_supported;
669224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	u8 dpcd[8];
670224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	u8 train_set[4];
671224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	u8 link_status[DP_LINK_STATUS_SIZE];
672224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	u8 tries;
6735a96a899bbdee86024ab9ea6d02b9e242faacbedJerome Glisse	bool use_dpencoder;
674224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher};
6755801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher
676224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucherstatic void radeon_dp_update_vs_emph(struct radeon_dp_link_train_info *dp_info)
6775801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher{
678224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	/* set the initial vs/emph on the source */
679224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	atombios_dig_transmitter_setup(dp_info->encoder,
680224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher				       ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH,
681224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher				       0, dp_info->train_set[0]); /* sets all lanes at once */
682224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher
683224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	/* set the vs/emph on the sink */
684224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	radeon_dp_aux_native_write(dp_info->radeon_connector, DP_TRAINING_LANE0_SET,
685224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher				   dp_info->train_set, dp_info->dp_lane_count, 0);
6865801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher}
6875801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher
688224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucherstatic void radeon_dp_set_tp(struct radeon_dp_link_train_info *dp_info, int tp)
689746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie{
690224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	int rtp = 0;
691746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie
692224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	/* set training pattern on the source */
6935a96a899bbdee86024ab9ea6d02b9e242faacbedJerome Glisse	if (ASIC_IS_DCE4(dp_info->rdev) || !dp_info->use_dpencoder) {
694224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		switch (tp) {
695224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		case DP_TRAINING_PATTERN_1:
696224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher			rtp = ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN1;
697224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher			break;
698224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		case DP_TRAINING_PATTERN_2:
699224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher			rtp = ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN2;
700224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher			break;
701224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		case DP_TRAINING_PATTERN_3:
702224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher			rtp = ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN3;
703224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher			break;
704224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		}
705224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		atombios_dig_encoder_setup(dp_info->encoder, rtp, 0);
706224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	} else {
707224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		switch (tp) {
708224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		case DP_TRAINING_PATTERN_1:
709224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher			rtp = 0;
710224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher			break;
711224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		case DP_TRAINING_PATTERN_2:
712224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher			rtp = 1;
713224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher			break;
714224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		}
715224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		radeon_dp_encoder_service(dp_info->rdev, ATOM_DP_ACTION_TRAINING_PATTERN_SEL,
716224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher					  dp_info->dp_clock, dp_info->enc_id, rtp);
717224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	}
718746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie
719224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	/* enable training pattern on the sink */
720224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	radeon_write_dpcd_reg(dp_info->radeon_connector, DP_TRAINING_PATTERN_SET, tp);
721746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie}
722746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie
723224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucherstatic int radeon_dp_link_train_init(struct radeon_dp_link_train_info *dp_info)
7245801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher{
725386d4d751e8e0b4b693bb724f09aae064ee5297dAlex Deucher	struct radeon_encoder *radeon_encoder = to_radeon_encoder(dp_info->encoder);
726386d4d751e8e0b4b693bb724f09aae064ee5297dAlex Deucher	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
727224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	u8 tmp;
7285801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher
729224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	/* power up the sink */
730224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	if (dp_info->dpcd[0] >= 0x11)
731224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		radeon_write_dpcd_reg(dp_info->radeon_connector,
732224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher				      DP_SET_POWER, DP_SET_POWER_D0);
733224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher
734224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	/* possibly enable downspread on the sink */
735224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	if (dp_info->dpcd[3] & 0x1)
736224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		radeon_write_dpcd_reg(dp_info->radeon_connector,
737224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher				      DP_DOWNSPREAD_CTRL, DP_SPREAD_AMP_0_5);
738224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	else
739224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		radeon_write_dpcd_reg(dp_info->radeon_connector,
740224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher				      DP_DOWNSPREAD_CTRL, 0);
7415801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher
742386d4d751e8e0b4b693bb724f09aae064ee5297dAlex Deucher	if ((dp_info->connector->connector_type == DRM_MODE_CONNECTOR_eDP) &&
743386d4d751e8e0b4b693bb724f09aae064ee5297dAlex Deucher	    (dig->panel_mode == DP_PANEL_MODE_INTERNAL_DP2_MODE)) {
744386d4d751e8e0b4b693bb724f09aae064ee5297dAlex Deucher		radeon_write_dpcd_reg(dp_info->radeon_connector, DP_EDP_CONFIGURATION_SET, 1);
745386d4d751e8e0b4b693bb724f09aae064ee5297dAlex Deucher	}
7465801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher
747224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	/* set the lane count on the sink */
748224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	tmp = dp_info->dp_lane_count;
749224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	if (dp_info->dpcd[0] >= 0x11)
750224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		tmp |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
751224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	radeon_write_dpcd_reg(dp_info->radeon_connector, DP_LANE_COUNT_SET, tmp);
7525801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher
753224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	/* set the link rate on the sink */
754224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	tmp = dp_get_dp_link_rate_coded(dp_info->dp_clock);
755224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	radeon_write_dpcd_reg(dp_info->radeon_connector, DP_LINK_BW_SET, tmp);
7565801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher
757224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	/* start training on the source */
7585a96a899bbdee86024ab9ea6d02b9e242faacbedJerome Glisse	if (ASIC_IS_DCE4(dp_info->rdev) || !dp_info->use_dpencoder)
759224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		atombios_dig_encoder_setup(dp_info->encoder,
760224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher					   ATOM_ENCODER_CMD_DP_LINK_TRAINING_START, 0);
7615801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher	else
762224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		radeon_dp_encoder_service(dp_info->rdev, ATOM_DP_ACTION_TRAINING_START,
763224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher					  dp_info->dp_clock, dp_info->enc_id, 0);
7645801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher
7655801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher	/* disable the training pattern on the sink */
766224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	radeon_write_dpcd_reg(dp_info->radeon_connector,
767224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher			      DP_TRAINING_PATTERN_SET,
768224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher			      DP_TRAINING_PATTERN_DISABLE);
769224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher
770224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	return 0;
771224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher}
7725801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher
773224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucherstatic int radeon_dp_link_train_finish(struct radeon_dp_link_train_info *dp_info)
774224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher{
7755801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher	udelay(400);
7765801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher
777224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	/* disable the training pattern on the sink */
778224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	radeon_write_dpcd_reg(dp_info->radeon_connector,
779224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher			      DP_TRAINING_PATTERN_SET,
780224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher			      DP_TRAINING_PATTERN_DISABLE);
781224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher
782224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	/* disable the training pattern on the source */
7835a96a899bbdee86024ab9ea6d02b9e242faacbedJerome Glisse	if (ASIC_IS_DCE4(dp_info->rdev) || !dp_info->use_dpencoder)
784224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		atombios_dig_encoder_setup(dp_info->encoder,
785224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher					   ATOM_ENCODER_CMD_DP_LINK_TRAINING_COMPLETE, 0);
786224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	else
787224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		radeon_dp_encoder_service(dp_info->rdev, ATOM_DP_ACTION_TRAINING_COMPLETE,
788224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher					  dp_info->dp_clock, dp_info->enc_id, 0);
789224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher
790224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	return 0;
791224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher}
792224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher
793224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucherstatic int radeon_dp_link_train_cr(struct radeon_dp_link_train_info *dp_info)
794224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher{
795224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	bool clock_recovery;
796224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher 	u8 voltage;
797224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	int i;
798224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher
799224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	radeon_dp_set_tp(dp_info, DP_TRAINING_PATTERN_1);
800224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	memset(dp_info->train_set, 0, 4);
801224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	radeon_dp_update_vs_emph(dp_info);
802224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher
803224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	udelay(400);
8045fbfce7fc906c4a9e3d5e0872e5d6affaca54761Dave Airlie
8055801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher	/* clock recovery loop */
8065801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher	clock_recovery = false;
807224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	dp_info->tries = 0;
8085801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher	voltage = 0xff;
809224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	while (1) {
810224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		if (dp_info->rd_interval == 0)
811224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher			udelay(100);
812224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		else
813224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher			mdelay(dp_info->rd_interval * 4);
814224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher
815224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		if (!radeon_dp_get_link_status(dp_info->radeon_connector, dp_info->link_status))
8165801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher			break;
8175801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher
818224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		if (dp_clock_recovery_ok(dp_info->link_status, dp_info->dp_lane_count)) {
8195801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher			clock_recovery = true;
8205801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher			break;
8215801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher		}
8225801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher
823224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		for (i = 0; i < dp_info->dp_lane_count; i++) {
824224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher			if ((dp_info->train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0)
8255801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher				break;
8265801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher		}
827224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		if (i == dp_info->dp_lane_count) {
8285801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher			DRM_ERROR("clock recovery reached max voltage\n");
8295801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher			break;
8305801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher		}
8315801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher
832224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		if ((dp_info->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) {
833224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher			++dp_info->tries;
834224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher			if (dp_info->tries == 5) {
8355801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher				DRM_ERROR("clock recovery tried 5 times\n");
8365801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher				break;
8375801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher			}
8385801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher		} else
839224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher			dp_info->tries = 0;
8405801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher
841224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		voltage = dp_info->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
8425801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher
8435801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher		/* Compute new train_set as requested by sink */
844224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		dp_get_adjust_train(dp_info->link_status, dp_info->dp_lane_count, dp_info->train_set);
845224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher
846224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		radeon_dp_update_vs_emph(dp_info);
8475801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher	}
848224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	if (!clock_recovery) {
8495801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher		DRM_ERROR("clock recovery failed\n");
850224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		return -1;
851224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	} else {
852d9fdaafbe912a34ef06ed569c6606fe2811f325bDave Airlie		DRM_DEBUG_KMS("clock recovery at voltage %d pre-emphasis %d\n",
853224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher			  dp_info->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK,
854224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher			  (dp_info->train_set[0] & DP_TRAIN_PRE_EMPHASIS_MASK) >>
85553c1e09fea4cf3fc0ec1f735a5fcab78c43cb55dAlex Deucher			  DP_TRAIN_PRE_EMPHASIS_SHIFT);
856224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		return 0;
857224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	}
858224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher}
8595801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher
860224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucherstatic int radeon_dp_link_train_ce(struct radeon_dp_link_train_info *dp_info)
861224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher{
862224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	bool channel_eq;
8635801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher
864224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	if (dp_info->tp3_supported)
865224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		radeon_dp_set_tp(dp_info, DP_TRAINING_PATTERN_3);
866bcc1c2a1d22974215e39dc87ce746ba9a39223e5Alex Deucher	else
867224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		radeon_dp_set_tp(dp_info, DP_TRAINING_PATTERN_2);
8685801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher
8695801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher	/* channel equalization loop */
870224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	dp_info->tries = 0;
8715801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher	channel_eq = false;
872224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	while (1) {
873224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		if (dp_info->rd_interval == 0)
874224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher			udelay(400);
875224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		else
876224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher			mdelay(dp_info->rd_interval * 4);
877224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher
878224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		if (!radeon_dp_get_link_status(dp_info->radeon_connector, dp_info->link_status))
8795801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher			break;
8805801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher
881224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		if (dp_channel_eq_ok(dp_info->link_status, dp_info->dp_lane_count)) {
8825801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher			channel_eq = true;
8835801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher			break;
8845801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher		}
8855801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher
8865801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher		/* Try 5 times */
887224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		if (dp_info->tries > 5) {
8885801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher			DRM_ERROR("channel eq failed: 5 tries\n");
8895801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher			break;
8905801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher		}
8915801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher
8925801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher		/* Compute new train_set as requested by sink */
893224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		dp_get_adjust_train(dp_info->link_status, dp_info->dp_lane_count, dp_info->train_set);
8945801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher
895224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		radeon_dp_update_vs_emph(dp_info);
896224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		dp_info->tries++;
8975801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher	}
8985801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher
899224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	if (!channel_eq) {
9005801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher		DRM_ERROR("channel eq failed\n");
901224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		return -1;
902224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	} else {
903d9fdaafbe912a34ef06ed569c6606fe2811f325bDave Airlie		DRM_DEBUG_KMS("channel eq at voltage %d pre-emphasis %d\n",
904224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher			  dp_info->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK,
905224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher			  (dp_info->train_set[0] & DP_TRAIN_PRE_EMPHASIS_MASK)
90653c1e09fea4cf3fc0ec1f735a5fcab78c43cb55dAlex Deucher			  >> DP_TRAIN_PRE_EMPHASIS_SHIFT);
907224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		return 0;
908224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	}
9095801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher}
9105801ead6bd6bddf5505d6eab55f84d8ee8106cd8Alex Deucher
911224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deuchervoid radeon_dp_link_train(struct drm_encoder *encoder,
912224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher			  struct drm_connector *connector)
913746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie{
914224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	struct drm_device *dev = encoder->dev;
915224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	struct radeon_device *rdev = dev->dev_private;
916224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
917224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	struct radeon_encoder_atom_dig *dig;
918224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	struct radeon_connector *radeon_connector;
919224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	struct radeon_connector_atom_dig *dig_connector;
920224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	struct radeon_dp_link_train_info dp_info;
9215a96a899bbdee86024ab9ea6d02b9e242faacbedJerome Glisse	int index;
9225a96a899bbdee86024ab9ea6d02b9e242faacbedJerome Glisse	u8 tmp, frev, crev;
923746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie
924224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	if (!radeon_encoder->enc_priv)
925224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		return;
926224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	dig = radeon_encoder->enc_priv;
927746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie
928224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	radeon_connector = to_radeon_connector(connector);
929224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	if (!radeon_connector->con_priv)
930224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		return;
931224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	dig_connector = radeon_connector->con_priv;
932834b2904bbfde3d85b5e984688777d56e9c7bf80Alex Deucher
933224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	if ((dig_connector->dp_sink_type != CONNECTOR_OBJECT_ID_DISPLAYPORT) &&
934224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	    (dig_connector->dp_sink_type != CONNECTOR_OBJECT_ID_eDP))
935224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		return;
936746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie
9375a96a899bbdee86024ab9ea6d02b9e242faacbedJerome Glisse	/* DPEncoderService newer than 1.1 can't program properly the
9385a96a899bbdee86024ab9ea6d02b9e242faacbedJerome Glisse	 * training pattern. When facing such version use the
9395a96a899bbdee86024ab9ea6d02b9e242faacbedJerome Glisse	 * DIGXEncoderControl (X== 1 | 2)
9405a96a899bbdee86024ab9ea6d02b9e242faacbedJerome Glisse	 */
9415a96a899bbdee86024ab9ea6d02b9e242faacbedJerome Glisse	dp_info.use_dpencoder = true;
9425a96a899bbdee86024ab9ea6d02b9e242faacbedJerome Glisse	index = GetIndexIntoMasterTable(COMMAND, DPEncoderService);
9435a96a899bbdee86024ab9ea6d02b9e242faacbedJerome Glisse	if (atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) {
9445a96a899bbdee86024ab9ea6d02b9e242faacbedJerome Glisse		if (crev > 1) {
9455a96a899bbdee86024ab9ea6d02b9e242faacbedJerome Glisse			dp_info.use_dpencoder = false;
9465a96a899bbdee86024ab9ea6d02b9e242faacbedJerome Glisse		}
9475a96a899bbdee86024ab9ea6d02b9e242faacbedJerome Glisse	}
9485a96a899bbdee86024ab9ea6d02b9e242faacbedJerome Glisse
949224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	dp_info.enc_id = 0;
950224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	if (dig->dig_encoder)
951224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		dp_info.enc_id |= ATOM_DP_CONFIG_DIG2_ENCODER;
952224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	else
953224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		dp_info.enc_id |= ATOM_DP_CONFIG_DIG1_ENCODER;
954224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	if (dig->linkb)
955224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		dp_info.enc_id |= ATOM_DP_CONFIG_LINK_B;
956224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	else
957224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		dp_info.enc_id |= ATOM_DP_CONFIG_LINK_A;
958834b2904bbfde3d85b5e984688777d56e9c7bf80Alex Deucher
959224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	dp_info.rd_interval = radeon_read_dpcd_reg(radeon_connector, DP_TRAINING_AUX_RD_INTERVAL);
960224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	tmp = radeon_read_dpcd_reg(radeon_connector, DP_MAX_LANE_COUNT);
961224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	if (ASIC_IS_DCE5(rdev) && (tmp & DP_TPS3_SUPPORTED))
962224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		dp_info.tp3_supported = true;
963224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	else
964224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		dp_info.tp3_supported = false;
965224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher
966224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	memcpy(dp_info.dpcd, dig_connector->dpcd, 8);
967224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	dp_info.rdev = rdev;
968224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	dp_info.encoder = encoder;
969224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	dp_info.connector = connector;
970224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	dp_info.radeon_connector = radeon_connector;
971224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	dp_info.dp_lane_count = dig_connector->dp_lane_count;
972224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	dp_info.dp_clock = dig_connector->dp_clock;
973224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher
974224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	if (radeon_dp_link_train_init(&dp_info))
975224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		goto done;
976224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	if (radeon_dp_link_train_cr(&dp_info))
977224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		goto done;
978224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	if (radeon_dp_link_train_ce(&dp_info))
979224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		goto done;
980224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucherdone:
981224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher	if (radeon_dp_link_train_finish(&dp_info))
982224d94b1445e2a836cd3790ff29f1866c052de4dAlex Deucher		return;
983746c1aa4d100f7441423050f34be79f401fbf7d4Dave Airlie}
984