xref: /rk3399_rockchip-uboot/drivers/video/drm/drm_dp_helper.c (revision 7efec348ce3c05852b4e4f7aa93b5e8ecd946ac1)
1c5b1fb65SWyon Bi // SPDX-License-Identifier: GPL-2.0+
2c5b1fb65SWyon Bi /*
3c5b1fb65SWyon Bi  * Copyright © 2009 Keith Packard
4c5b1fb65SWyon Bi  *
5c5b1fb65SWyon Bi  * Permission to use, copy, modify, distribute, and sell this software and its
6c5b1fb65SWyon Bi  * documentation for any purpose is hereby granted without fee, provided that
7c5b1fb65SWyon Bi  * the above copyright notice appear in all copies and that both that copyright
8c5b1fb65SWyon Bi  * notice and this permission notice appear in supporting documentation, and
9c5b1fb65SWyon Bi  * that the name of the copyright holders not be used in advertising or
10c5b1fb65SWyon Bi  * publicity pertaining to distribution of the software without specific,
11c5b1fb65SWyon Bi  * written prior permission.  The copyright holders make no representations
12c5b1fb65SWyon Bi  * about the suitability of this software for any purpose.  It is provided "as
13c5b1fb65SWyon Bi  * is" without express or implied warranty.
14c5b1fb65SWyon Bi  *
15c5b1fb65SWyon Bi  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16c5b1fb65SWyon Bi  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
17c5b1fb65SWyon Bi  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18c5b1fb65SWyon Bi  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
19c5b1fb65SWyon Bi  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
20c5b1fb65SWyon Bi  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
21c5b1fb65SWyon Bi  * OF THIS SOFTWARE.
22c5b1fb65SWyon Bi  */
23c5b1fb65SWyon Bi 
24c5b1fb65SWyon Bi #include <common.h>
25c5b1fb65SWyon Bi #include <drm/drm_dp_helper.h>
26c5b1fb65SWyon Bi 
27c5b1fb65SWyon Bi /**
28c5b1fb65SWyon Bi  * DOC: dp helpers
29c5b1fb65SWyon Bi  *
30c5b1fb65SWyon Bi  * These functions contain some common logic and helpers at various abstraction
31c5b1fb65SWyon Bi  * levels to deal with Display Port sink devices and related things like DP aux
32c5b1fb65SWyon Bi  * channel transfers, EDID reading over DP aux channels, decoding certain DPCD
33c5b1fb65SWyon Bi  * blocks, ...
34c5b1fb65SWyon Bi  */
35c5b1fb65SWyon Bi 
36c5b1fb65SWyon Bi /* Helpers for DP link training */
dp_link_status(const u8 link_status[DP_LINK_STATUS_SIZE],int r)37c5b1fb65SWyon Bi static u8 dp_link_status(const u8 link_status[DP_LINK_STATUS_SIZE], int r)
38c5b1fb65SWyon Bi {
39c5b1fb65SWyon Bi 	return link_status[r - DP_LANE0_1_STATUS];
40c5b1fb65SWyon Bi }
41c5b1fb65SWyon Bi 
dp_get_lane_status(const u8 link_status[DP_LINK_STATUS_SIZE],int lane)42c5b1fb65SWyon Bi static u8 dp_get_lane_status(const u8 link_status[DP_LINK_STATUS_SIZE],
43c5b1fb65SWyon Bi 			     int lane)
44c5b1fb65SWyon Bi {
45c5b1fb65SWyon Bi 	int i = DP_LANE0_1_STATUS + (lane >> 1);
46c5b1fb65SWyon Bi 	int s = (lane & 1) * 4;
47c5b1fb65SWyon Bi 	u8 l = dp_link_status(link_status, i);
48c5b1fb65SWyon Bi 
49c5b1fb65SWyon Bi 	return (l >> s) & 0xf;
50c5b1fb65SWyon Bi }
51c5b1fb65SWyon Bi 
drm_dp_channel_eq_ok(const u8 link_status[DP_LINK_STATUS_SIZE],int lane_count)52c5b1fb65SWyon Bi bool drm_dp_channel_eq_ok(const u8 link_status[DP_LINK_STATUS_SIZE],
53c5b1fb65SWyon Bi 			  int lane_count)
54c5b1fb65SWyon Bi {
55c5b1fb65SWyon Bi 	u8 lane_align;
56c5b1fb65SWyon Bi 	u8 lane_status;
57c5b1fb65SWyon Bi 	int lane;
58c5b1fb65SWyon Bi 
59c5b1fb65SWyon Bi 	lane_align = dp_link_status(link_status,
60c5b1fb65SWyon Bi 				    DP_LANE_ALIGN_STATUS_UPDATED);
61c5b1fb65SWyon Bi 	if ((lane_align & DP_INTERLANE_ALIGN_DONE) == 0)
62c5b1fb65SWyon Bi 		return false;
63c5b1fb65SWyon Bi 	for (lane = 0; lane < lane_count; lane++) {
64c5b1fb65SWyon Bi 		lane_status = dp_get_lane_status(link_status, lane);
65c5b1fb65SWyon Bi 		if ((lane_status & DP_CHANNEL_EQ_BITS) != DP_CHANNEL_EQ_BITS)
66c5b1fb65SWyon Bi 			return false;
67c5b1fb65SWyon Bi 	}
68c5b1fb65SWyon Bi 	return true;
69c5b1fb65SWyon Bi }
70c5b1fb65SWyon Bi 
drm_dp_clock_recovery_ok(const u8 link_status[DP_LINK_STATUS_SIZE],int lane_count)71c5b1fb65SWyon Bi bool drm_dp_clock_recovery_ok(const u8 link_status[DP_LINK_STATUS_SIZE],
72c5b1fb65SWyon Bi 			      int lane_count)
73c5b1fb65SWyon Bi {
74c5b1fb65SWyon Bi 	int lane;
75c5b1fb65SWyon Bi 	u8 lane_status;
76c5b1fb65SWyon Bi 
77c5b1fb65SWyon Bi 	for (lane = 0; lane < lane_count; lane++) {
78c5b1fb65SWyon Bi 		lane_status = dp_get_lane_status(link_status, lane);
79c5b1fb65SWyon Bi 		if ((lane_status & DP_LANE_CR_DONE) == 0)
80c5b1fb65SWyon Bi 			return false;
81c5b1fb65SWyon Bi 	}
82c5b1fb65SWyon Bi 	return true;
83c5b1fb65SWyon Bi }
84c5b1fb65SWyon Bi 
drm_dp_get_adjust_request_voltage(const u8 link_status[DP_LINK_STATUS_SIZE],int lane)85c5b1fb65SWyon Bi u8 drm_dp_get_adjust_request_voltage(const u8 link_status[DP_LINK_STATUS_SIZE],
86c5b1fb65SWyon Bi 				     int lane)
87c5b1fb65SWyon Bi {
88c5b1fb65SWyon Bi 	int i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1);
89c5b1fb65SWyon Bi 	int s = ((lane & 1) ?
90c5b1fb65SWyon Bi 		 DP_ADJUST_VOLTAGE_SWING_LANE1_SHIFT :
91c5b1fb65SWyon Bi 		 DP_ADJUST_VOLTAGE_SWING_LANE0_SHIFT);
92c5b1fb65SWyon Bi 	u8 l = dp_link_status(link_status, i);
93c5b1fb65SWyon Bi 
94c5b1fb65SWyon Bi 	return ((l >> s) & 0x3) << DP_TRAIN_VOLTAGE_SWING_SHIFT;
95c5b1fb65SWyon Bi }
96c5b1fb65SWyon Bi 
drm_dp_get_adjust_request_pre_emphasis(const u8 link_status[DP_LINK_STATUS_SIZE],int lane)97c5b1fb65SWyon Bi u8 drm_dp_get_adjust_request_pre_emphasis(const u8 link_status[DP_LINK_STATUS_SIZE],
98c5b1fb65SWyon Bi 					  int lane)
99c5b1fb65SWyon Bi {
100c5b1fb65SWyon Bi 	int i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1);
101c5b1fb65SWyon Bi 	int s = ((lane & 1) ?
102c5b1fb65SWyon Bi 		 DP_ADJUST_PRE_EMPHASIS_LANE1_SHIFT :
103c5b1fb65SWyon Bi 		 DP_ADJUST_PRE_EMPHASIS_LANE0_SHIFT);
104c5b1fb65SWyon Bi 	u8 l = dp_link_status(link_status, i);
105c5b1fb65SWyon Bi 
106c5b1fb65SWyon Bi 	return ((l >> s) & 0x3) << DP_TRAIN_PRE_EMPHASIS_SHIFT;
107c5b1fb65SWyon Bi }
108c5b1fb65SWyon Bi 
drm_dp_link_train_clock_recovery_delay(const u8 dpcd[DP_RECEIVER_CAP_SIZE])109c5b1fb65SWyon Bi void drm_dp_link_train_clock_recovery_delay(const u8 dpcd[DP_RECEIVER_CAP_SIZE])
110c5b1fb65SWyon Bi {
111c5b1fb65SWyon Bi 	int rd_interval = dpcd[DP_TRAINING_AUX_RD_INTERVAL] &
112c5b1fb65SWyon Bi 			  DP_TRAINING_AUX_RD_MASK;
113c5b1fb65SWyon Bi 
114c5b1fb65SWyon Bi 	if (rd_interval > 4)
115c5b1fb65SWyon Bi 		printf("AUX interval %d, out of range (max 4)\n", rd_interval);
116c5b1fb65SWyon Bi 
117c5b1fb65SWyon Bi 	if (rd_interval == 0 || dpcd[DP_DPCD_REV] >= DP_DPCD_REV_14)
118c5b1fb65SWyon Bi 		udelay(100);
119c5b1fb65SWyon Bi 	else
120c5b1fb65SWyon Bi 		mdelay(rd_interval * 4);
121c5b1fb65SWyon Bi }
122c5b1fb65SWyon Bi 
drm_dp_link_train_channel_eq_delay(const u8 dpcd[DP_RECEIVER_CAP_SIZE])123c5b1fb65SWyon Bi void drm_dp_link_train_channel_eq_delay(const u8 dpcd[DP_RECEIVER_CAP_SIZE])
124c5b1fb65SWyon Bi {
125c5b1fb65SWyon Bi 	int rd_interval = dpcd[DP_TRAINING_AUX_RD_INTERVAL] &
126c5b1fb65SWyon Bi 			  DP_TRAINING_AUX_RD_MASK;
127c5b1fb65SWyon Bi 
128c5b1fb65SWyon Bi 	if (rd_interval > 4)
129c5b1fb65SWyon Bi 		printf("AUX interval %d, out of range (max 4)\n", rd_interval);
130c5b1fb65SWyon Bi 
131c5b1fb65SWyon Bi 	if (rd_interval == 0)
132c5b1fb65SWyon Bi 		udelay(400);
133c5b1fb65SWyon Bi 	else
134c5b1fb65SWyon Bi 		mdelay(rd_interval * 4);
135c5b1fb65SWyon Bi }
136c5b1fb65SWyon Bi 
drm_dp_link_rate_to_bw_code(int link_rate)137c5b1fb65SWyon Bi u8 drm_dp_link_rate_to_bw_code(int link_rate)
138c5b1fb65SWyon Bi {
139*7efec348SDamon Ding 	/* Spec says link_bw = link_rate / 0.27Gbps */
140*7efec348SDamon Ding 	return link_rate / 27000;
141c5b1fb65SWyon Bi }
142c5b1fb65SWyon Bi 
drm_dp_bw_code_to_link_rate(u8 link_bw)143c5b1fb65SWyon Bi int drm_dp_bw_code_to_link_rate(u8 link_bw)
144c5b1fb65SWyon Bi {
145*7efec348SDamon Ding 	/* Spec says link_rate = link_bw * 0.27Gbps */
146*7efec348SDamon Ding 	return link_bw * 27000;
147c5b1fb65SWyon Bi }
148ebdfc6a4SZhang Yubing 
149ebdfc6a4SZhang Yubing #define AUX_RETRY_INTERVAL 500 /* us */
150ebdfc6a4SZhang Yubing 
drm_dp_dpcd_access(struct drm_dp_aux * aux,u8 request,unsigned int offset,void * buffer,size_t size)151ebdfc6a4SZhang Yubing static int drm_dp_dpcd_access(struct drm_dp_aux *aux, u8 request,
152ebdfc6a4SZhang Yubing 			      unsigned int offset, void *buffer, size_t size)
153ebdfc6a4SZhang Yubing {
154ebdfc6a4SZhang Yubing 	struct drm_dp_aux_msg msg;
155ebdfc6a4SZhang Yubing 	unsigned int retry, native_reply;
156ebdfc6a4SZhang Yubing 	int err = 0, ret = 0;
157ebdfc6a4SZhang Yubing 
158ebdfc6a4SZhang Yubing 	memset(&msg, 0, sizeof(msg));
159ebdfc6a4SZhang Yubing 	msg.address = offset;
160ebdfc6a4SZhang Yubing 	msg.request = request;
161ebdfc6a4SZhang Yubing 	msg.buffer = buffer;
162ebdfc6a4SZhang Yubing 	msg.size = size;
163ebdfc6a4SZhang Yubing 
164ebdfc6a4SZhang Yubing 	/*
165ebdfc6a4SZhang Yubing 	 * The specification doesn't give any recommendation on how often to
166ebdfc6a4SZhang Yubing 	 * retry native transactions. We used to retry 7 times like for
167ebdfc6a4SZhang Yubing 	 * aux i2c transactions but real world devices this wasn't
168ebdfc6a4SZhang Yubing 	 * sufficient, bump to 32 which makes Dell 4k monitors happier.
169ebdfc6a4SZhang Yubing 	 */
170ebdfc6a4SZhang Yubing 	for (retry = 0; retry < 32; retry++) {
171ebdfc6a4SZhang Yubing 		if (ret != 0 && ret != -ETIMEDOUT)
172ebdfc6a4SZhang Yubing 			udelay(AUX_RETRY_INTERVAL);
173ebdfc6a4SZhang Yubing 
174ebdfc6a4SZhang Yubing 		ret = aux->transfer(aux, &msg);
175ebdfc6a4SZhang Yubing 		if (ret >= 0) {
176ebdfc6a4SZhang Yubing 			native_reply = msg.reply & DP_AUX_NATIVE_REPLY_MASK;
177ebdfc6a4SZhang Yubing 			if (native_reply == DP_AUX_NATIVE_REPLY_ACK) {
178ebdfc6a4SZhang Yubing 				if (ret == size)
179ebdfc6a4SZhang Yubing 					goto out;
180ebdfc6a4SZhang Yubing 
181ebdfc6a4SZhang Yubing 				ret = -EPROTO;
182ebdfc6a4SZhang Yubing 			} else {
183ebdfc6a4SZhang Yubing 				ret = -EIO;
184ebdfc6a4SZhang Yubing 			}
185ebdfc6a4SZhang Yubing 		}
186ebdfc6a4SZhang Yubing 
187ebdfc6a4SZhang Yubing 		/*
188ebdfc6a4SZhang Yubing 		 * We want the error we return to be the error we received on
189ebdfc6a4SZhang Yubing 		 * the first transaction, since we may get a different error the
190ebdfc6a4SZhang Yubing 		 * next time we retry
191ebdfc6a4SZhang Yubing 		 */
192ebdfc6a4SZhang Yubing 		if (!err)
193ebdfc6a4SZhang Yubing 			err = ret;
194ebdfc6a4SZhang Yubing 	}
195ebdfc6a4SZhang Yubing 
196ebdfc6a4SZhang Yubing 	printf("%s: Too many retries, giving up. First error: %d\n",
197ebdfc6a4SZhang Yubing 	       aux->name, err);
198ebdfc6a4SZhang Yubing 	ret = err;
199ebdfc6a4SZhang Yubing 
200ebdfc6a4SZhang Yubing out:
201ebdfc6a4SZhang Yubing 	return ret;
202ebdfc6a4SZhang Yubing }
203ebdfc6a4SZhang Yubing 
drm_dp_dpcd_read(struct drm_dp_aux * aux,unsigned int offset,void * buffer,size_t size)204ebdfc6a4SZhang Yubing ssize_t drm_dp_dpcd_read(struct drm_dp_aux *aux, unsigned int offset,
205ebdfc6a4SZhang Yubing 			 void *buffer, size_t size)
206ebdfc6a4SZhang Yubing {
207ebdfc6a4SZhang Yubing 	int ret;
208ebdfc6a4SZhang Yubing 
209ebdfc6a4SZhang Yubing 	ret = drm_dp_dpcd_access(aux, DP_AUX_NATIVE_READ, DP_DPCD_REV,
210ebdfc6a4SZhang Yubing 				 buffer, 1);
211ebdfc6a4SZhang Yubing 	if (ret != 1)
212ebdfc6a4SZhang Yubing 		goto out;
213ebdfc6a4SZhang Yubing 
214ebdfc6a4SZhang Yubing 	ret = drm_dp_dpcd_access(aux, DP_AUX_NATIVE_READ, offset,
215ebdfc6a4SZhang Yubing 				 buffer, size);
216ebdfc6a4SZhang Yubing 
217ebdfc6a4SZhang Yubing out:
218ebdfc6a4SZhang Yubing 	return ret;
219ebdfc6a4SZhang Yubing }
220ebdfc6a4SZhang Yubing 
drm_dp_dpcd_write(struct drm_dp_aux * aux,unsigned int offset,void * buffer,size_t size)221ebdfc6a4SZhang Yubing ssize_t drm_dp_dpcd_write(struct drm_dp_aux *aux, unsigned int offset,
222ebdfc6a4SZhang Yubing 			  void *buffer, size_t size)
223ebdfc6a4SZhang Yubing {
224ebdfc6a4SZhang Yubing 	int ret;
225ebdfc6a4SZhang Yubing 
226ebdfc6a4SZhang Yubing 	ret = drm_dp_dpcd_access(aux, DP_AUX_NATIVE_WRITE, offset,
227ebdfc6a4SZhang Yubing 				 buffer, size);
228ebdfc6a4SZhang Yubing 
229ebdfc6a4SZhang Yubing 	return ret;
230ebdfc6a4SZhang Yubing }
231ebdfc6a4SZhang Yubing 
drm_dp_dpcd_read_link_status(struct drm_dp_aux * aux,u8 status[DP_LINK_STATUS_SIZE])232ebdfc6a4SZhang Yubing int drm_dp_dpcd_read_link_status(struct drm_dp_aux *aux,
233ebdfc6a4SZhang Yubing 				 u8 status[DP_LINK_STATUS_SIZE])
234ebdfc6a4SZhang Yubing {
235ebdfc6a4SZhang Yubing 	return drm_dp_dpcd_read(aux, DP_LANE0_1_STATUS, status,
236ebdfc6a4SZhang Yubing 				DP_LINK_STATUS_SIZE);
237ebdfc6a4SZhang Yubing }
238ebdfc6a4SZhang Yubing 
drm_dp_read_extended_dpcd_caps(struct drm_dp_aux * aux,u8 dpcd[DP_RECEIVER_CAP_SIZE])239ebdfc6a4SZhang Yubing static int drm_dp_read_extended_dpcd_caps(struct drm_dp_aux *aux,
240ebdfc6a4SZhang Yubing 					  u8 dpcd[DP_RECEIVER_CAP_SIZE])
241ebdfc6a4SZhang Yubing {
242ebdfc6a4SZhang Yubing 	u8 dpcd_ext[6];
243ebdfc6a4SZhang Yubing 	int ret;
244ebdfc6a4SZhang Yubing 
245ebdfc6a4SZhang Yubing 	/*
246ebdfc6a4SZhang Yubing 	 * Prior to DP1.3 the bit represented by
247ebdfc6a4SZhang Yubing 	 * DP_EXTENDED_RECEIVER_CAP_FIELD_PRESENT was reserved.
248ebdfc6a4SZhang Yubing 	 * If it is set DP_DPCD_REV at 0000h could be at a value less than
249ebdfc6a4SZhang Yubing 	 * the true capability of the panel. The only way to check is to
250ebdfc6a4SZhang Yubing 	 * then compare 0000h and 2200h.
251ebdfc6a4SZhang Yubing 	 */
252ebdfc6a4SZhang Yubing 	if (!(dpcd[DP_TRAINING_AUX_RD_INTERVAL] &
253ebdfc6a4SZhang Yubing 	      DP_EXTENDED_RECEIVER_CAP_FIELD_PRESENT))
254ebdfc6a4SZhang Yubing 		return 0;
255ebdfc6a4SZhang Yubing 
256ebdfc6a4SZhang Yubing 	ret = drm_dp_dpcd_read(aux, DP_DP13_DPCD_REV, &dpcd_ext,
257ebdfc6a4SZhang Yubing 			       sizeof(dpcd_ext));
258ebdfc6a4SZhang Yubing 	if (ret < 0)
259ebdfc6a4SZhang Yubing 		return ret;
260ebdfc6a4SZhang Yubing 	if (ret != sizeof(dpcd_ext))
261ebdfc6a4SZhang Yubing 		return -EIO;
262ebdfc6a4SZhang Yubing 
263ebdfc6a4SZhang Yubing 	if (dpcd[DP_DPCD_REV] > dpcd_ext[DP_DPCD_REV]) {
264ebdfc6a4SZhang Yubing 		printf("%s: Extended DPCD rev less than base DPCD rev (%d > %d)\n",
265ebdfc6a4SZhang Yubing 		       aux->name, dpcd[DP_DPCD_REV], dpcd_ext[DP_DPCD_REV]);
266ebdfc6a4SZhang Yubing 		return 0;
267ebdfc6a4SZhang Yubing 	}
268ebdfc6a4SZhang Yubing 
269ebdfc6a4SZhang Yubing 	if (!memcmp(dpcd, dpcd_ext, sizeof(dpcd_ext)))
270ebdfc6a4SZhang Yubing 		return 0;
271ebdfc6a4SZhang Yubing 
27243448503SZhang Yubing 	debug("%s: Base DPCD: %*ph\n",
273ebdfc6a4SZhang Yubing 	       aux->name, DP_RECEIVER_CAP_SIZE, dpcd);
274ebdfc6a4SZhang Yubing 
275ebdfc6a4SZhang Yubing 	memcpy(dpcd, dpcd_ext, sizeof(dpcd_ext));
276ebdfc6a4SZhang Yubing 
277ebdfc6a4SZhang Yubing 	return 0;
278ebdfc6a4SZhang Yubing }
279ebdfc6a4SZhang Yubing 
drm_dp_read_dpcd_caps(struct drm_dp_aux * aux,u8 dpcd[DP_RECEIVER_CAP_SIZE])280ebdfc6a4SZhang Yubing int drm_dp_read_dpcd_caps(struct drm_dp_aux *aux,
281ebdfc6a4SZhang Yubing 			  u8 dpcd[DP_RECEIVER_CAP_SIZE])
282ebdfc6a4SZhang Yubing {
283ebdfc6a4SZhang Yubing 	int ret;
284ebdfc6a4SZhang Yubing 
285ebdfc6a4SZhang Yubing 	ret = drm_dp_dpcd_read(aux, DP_DPCD_REV, dpcd, DP_RECEIVER_CAP_SIZE);
286ebdfc6a4SZhang Yubing 	if (ret < 0)
287ebdfc6a4SZhang Yubing 		return ret;
288ebdfc6a4SZhang Yubing 	if (ret != DP_RECEIVER_CAP_SIZE || dpcd[DP_DPCD_REV] == 0)
289ebdfc6a4SZhang Yubing 		return -EIO;
290ebdfc6a4SZhang Yubing 
291ebdfc6a4SZhang Yubing 	ret = drm_dp_read_extended_dpcd_caps(aux, dpcd);
292ebdfc6a4SZhang Yubing 	if (ret < 0)
293ebdfc6a4SZhang Yubing 		return ret;
294ebdfc6a4SZhang Yubing 
29543448503SZhang Yubing 	debug("%s: DPCD: %*ph\n",
296ebdfc6a4SZhang Yubing 	       aux->name, DP_RECEIVER_CAP_SIZE, dpcd);
297ebdfc6a4SZhang Yubing 
298ebdfc6a4SZhang Yubing 	return ret;
299ebdfc6a4SZhang Yubing }
300ebdfc6a4SZhang Yubing 
drm_dp_i2c_msg_write_status_update(struct drm_dp_aux_msg * msg)301ebdfc6a4SZhang Yubing static void drm_dp_i2c_msg_write_status_update(struct drm_dp_aux_msg *msg)
302ebdfc6a4SZhang Yubing {
303ebdfc6a4SZhang Yubing 	/*
304ebdfc6a4SZhang Yubing 	 * In case of i2c defer or short i2c ack reply to a write,
305ebdfc6a4SZhang Yubing 	 * we need to switch to WRITE_STATUS_UPDATE to drain the
306ebdfc6a4SZhang Yubing 	 * rest of the message
307ebdfc6a4SZhang Yubing 	 */
308ebdfc6a4SZhang Yubing 	if ((msg->request & ~DP_AUX_I2C_MOT) == DP_AUX_I2C_WRITE) {
309ebdfc6a4SZhang Yubing 		msg->request &= DP_AUX_I2C_MOT;
310ebdfc6a4SZhang Yubing 		msg->request |= DP_AUX_I2C_WRITE_STATUS_UPDATE;
311ebdfc6a4SZhang Yubing 	}
312ebdfc6a4SZhang Yubing }
313ebdfc6a4SZhang Yubing 
drm_dp_i2c_do_msg(struct drm_dp_aux * aux,struct drm_dp_aux_msg * msg)314ebdfc6a4SZhang Yubing static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
315ebdfc6a4SZhang Yubing {
316ebdfc6a4SZhang Yubing 	unsigned int retry, defer_i2c;
317ebdfc6a4SZhang Yubing 	int ret;
318ebdfc6a4SZhang Yubing 	/*
319ebdfc6a4SZhang Yubing 	 * DP1.2 sections 2.7.7.1.5.6.1 and 2.7.7.1.6.6.1: A DP Source device
320ebdfc6a4SZhang Yubing 	 * is required to retry at least seven times upon receiving AUX_DEFER
321ebdfc6a4SZhang Yubing 	 * before giving up the AUX transaction.
322ebdfc6a4SZhang Yubing 	 *
323ebdfc6a4SZhang Yubing 	 * We also try to account for the i2c bus speed.
324ebdfc6a4SZhang Yubing 	 */
325ebdfc6a4SZhang Yubing 	int max_retries = 7;
326ebdfc6a4SZhang Yubing 
327ebdfc6a4SZhang Yubing 	for (retry = 0, defer_i2c = 0; retry < (max_retries + defer_i2c);
328ebdfc6a4SZhang Yubing 	     retry++) {
329ebdfc6a4SZhang Yubing 		ret = aux->transfer(aux, msg);
330ebdfc6a4SZhang Yubing 		if (ret < 0) {
331ebdfc6a4SZhang Yubing 			if (ret == -EBUSY)
332ebdfc6a4SZhang Yubing 				continue;
333ebdfc6a4SZhang Yubing 
334ebdfc6a4SZhang Yubing 			/*
335ebdfc6a4SZhang Yubing 			 * While timeouts can be errors, they're usually normal
336ebdfc6a4SZhang Yubing 			 * behavior (for instance, when a driver tries to
337ebdfc6a4SZhang Yubing 			 * communicate with a non-existent DisplayPort device).
338ebdfc6a4SZhang Yubing 			 * Avoid spamming the kernel log with timeout errors.
339ebdfc6a4SZhang Yubing 			 */
340ebdfc6a4SZhang Yubing 			if (ret == -ETIMEDOUT)
341ebdfc6a4SZhang Yubing 				printf("%s: transaction timed out\n",
342ebdfc6a4SZhang Yubing 				       aux->name);
343ebdfc6a4SZhang Yubing 			else
344ebdfc6a4SZhang Yubing 				printf("%s: transaction failed: %d\n",
345ebdfc6a4SZhang Yubing 				       aux->name, ret);
346ebdfc6a4SZhang Yubing 			return ret;
347ebdfc6a4SZhang Yubing 		}
348ebdfc6a4SZhang Yubing 
349ebdfc6a4SZhang Yubing 		switch (msg->reply & DP_AUX_NATIVE_REPLY_MASK) {
350ebdfc6a4SZhang Yubing 		case DP_AUX_NATIVE_REPLY_ACK:
351ebdfc6a4SZhang Yubing 			/*
352ebdfc6a4SZhang Yubing 			 * For I2C-over-AUX transactions this isn't enough, we
353ebdfc6a4SZhang Yubing 			 * need to check for the I2C ACK reply.
354ebdfc6a4SZhang Yubing 			 */
355ebdfc6a4SZhang Yubing 			break;
356ebdfc6a4SZhang Yubing 
357ebdfc6a4SZhang Yubing 		case DP_AUX_NATIVE_REPLY_NACK:
358ebdfc6a4SZhang Yubing 			printf("%s: native nack (result=%d, size=%zu)\n",
359ebdfc6a4SZhang Yubing 			       aux->name, ret, msg->size);
360ebdfc6a4SZhang Yubing 			return -EREMOTEIO;
361ebdfc6a4SZhang Yubing 
362ebdfc6a4SZhang Yubing 		case DP_AUX_NATIVE_REPLY_DEFER:
363ebdfc6a4SZhang Yubing 			printf("%s: native defer\n", aux->name);
364ebdfc6a4SZhang Yubing 			/*
365ebdfc6a4SZhang Yubing 			 * We could check for I2C bit rate capabilities and if
366ebdfc6a4SZhang Yubing 			 * available adjust this interval. We could also be
367ebdfc6a4SZhang Yubing 			 * more careful with DP-to-legacy adapters where a
368ebdfc6a4SZhang Yubing 			 * long legacy cable may force very low I2C bit rates.
369ebdfc6a4SZhang Yubing 			 *
370ebdfc6a4SZhang Yubing 			 * For now just defer for long enough to hopefully be
371ebdfc6a4SZhang Yubing 			 * safe for all use-cases.
372ebdfc6a4SZhang Yubing 			 */
373ebdfc6a4SZhang Yubing 			udelay(AUX_RETRY_INTERVAL);
374ebdfc6a4SZhang Yubing 			continue;
375ebdfc6a4SZhang Yubing 
376ebdfc6a4SZhang Yubing 		default:
377ebdfc6a4SZhang Yubing 			printf("%s: invalid native reply %#04x\n",
378ebdfc6a4SZhang Yubing 			       aux->name, msg->reply);
379ebdfc6a4SZhang Yubing 			return -EREMOTEIO;
380ebdfc6a4SZhang Yubing 		}
381ebdfc6a4SZhang Yubing 
382ebdfc6a4SZhang Yubing 		switch (msg->reply & DP_AUX_I2C_REPLY_MASK) {
383ebdfc6a4SZhang Yubing 		case DP_AUX_I2C_REPLY_ACK:
384ebdfc6a4SZhang Yubing 			/*
385ebdfc6a4SZhang Yubing 			 * Both native ACK and I2C ACK replies received. We
386ebdfc6a4SZhang Yubing 			 * can assume the transfer was successful.
387ebdfc6a4SZhang Yubing 			 */
388ebdfc6a4SZhang Yubing 			if (ret != msg->size)
389ebdfc6a4SZhang Yubing 				drm_dp_i2c_msg_write_status_update(msg);
390ebdfc6a4SZhang Yubing 			return ret;
391ebdfc6a4SZhang Yubing 
392ebdfc6a4SZhang Yubing 		case DP_AUX_I2C_REPLY_NACK:
393ebdfc6a4SZhang Yubing 			printf("%s: I2C nack (result=%d, size=%zu)\n",
394ebdfc6a4SZhang Yubing 			       aux->name, ret, msg->size);
395ebdfc6a4SZhang Yubing 			aux->i2c_nack_count++;
396ebdfc6a4SZhang Yubing 			return -EREMOTEIO;
397ebdfc6a4SZhang Yubing 
398ebdfc6a4SZhang Yubing 		case DP_AUX_I2C_REPLY_DEFER:
399ebdfc6a4SZhang Yubing 			printf("%s: I2C defer\n", aux->name);
400ebdfc6a4SZhang Yubing 			/* DP Compliance Test 4.2.2.5 Requirement:
401ebdfc6a4SZhang Yubing 			 * Must have at least 7 retries for I2C defers on the
402ebdfc6a4SZhang Yubing 			 * transaction to pass this test
403ebdfc6a4SZhang Yubing 			 */
404ebdfc6a4SZhang Yubing 			aux->i2c_defer_count++;
405ebdfc6a4SZhang Yubing 			if (defer_i2c < 7)
406ebdfc6a4SZhang Yubing 				defer_i2c++;
407ebdfc6a4SZhang Yubing 			udelay(AUX_RETRY_INTERVAL);
408ebdfc6a4SZhang Yubing 			drm_dp_i2c_msg_write_status_update(msg);
409ebdfc6a4SZhang Yubing 
410ebdfc6a4SZhang Yubing 			continue;
411ebdfc6a4SZhang Yubing 
412ebdfc6a4SZhang Yubing 		default:
413ebdfc6a4SZhang Yubing 			printf("%s: invalid I2C reply %#04x\n",
414ebdfc6a4SZhang Yubing 			       aux->name, msg->reply);
415ebdfc6a4SZhang Yubing 			return -EREMOTEIO;
416ebdfc6a4SZhang Yubing 		}
417ebdfc6a4SZhang Yubing 	}
418ebdfc6a4SZhang Yubing 
419ebdfc6a4SZhang Yubing 	printf("%s: Too many retries, giving up\n", aux->name);
420ebdfc6a4SZhang Yubing 	return -EREMOTEIO;
421ebdfc6a4SZhang Yubing }
422ebdfc6a4SZhang Yubing 
drm_dp_i2c_msg_set_request(struct drm_dp_aux_msg * msg,const struct i2c_msg * i2c_msg)423ebdfc6a4SZhang Yubing static void drm_dp_i2c_msg_set_request(struct drm_dp_aux_msg *msg,
424ebdfc6a4SZhang Yubing 				       const struct i2c_msg *i2c_msg)
425ebdfc6a4SZhang Yubing {
426ebdfc6a4SZhang Yubing 	msg->request = (i2c_msg->flags & I2C_M_RD) ?
427ebdfc6a4SZhang Yubing 		DP_AUX_I2C_READ : DP_AUX_I2C_WRITE;
428ebdfc6a4SZhang Yubing 	if (!(i2c_msg->flags & I2C_M_STOP))
429ebdfc6a4SZhang Yubing 		msg->request |= DP_AUX_I2C_MOT;
430ebdfc6a4SZhang Yubing }
431ebdfc6a4SZhang Yubing 
432ebdfc6a4SZhang Yubing /*
433ebdfc6a4SZhang Yubing  * Keep retrying drm_dp_i2c_do_msg until all data has been transferred.
434ebdfc6a4SZhang Yubing  *
435ebdfc6a4SZhang Yubing  * Returns an error code on failure, or a recommended transfer size on success.
436ebdfc6a4SZhang Yubing  */
drm_dp_i2c_drain_msg(struct drm_dp_aux * aux,struct drm_dp_aux_msg * orig_msg)437ebdfc6a4SZhang Yubing static int drm_dp_i2c_drain_msg(struct drm_dp_aux *aux,
438ebdfc6a4SZhang Yubing 				struct drm_dp_aux_msg *orig_msg)
439ebdfc6a4SZhang Yubing {
440ebdfc6a4SZhang Yubing 	int err, ret = orig_msg->size;
441ebdfc6a4SZhang Yubing 	struct drm_dp_aux_msg msg = *orig_msg;
442ebdfc6a4SZhang Yubing 
443ebdfc6a4SZhang Yubing 	while (msg.size > 0) {
444ebdfc6a4SZhang Yubing 		err = drm_dp_i2c_do_msg(aux, &msg);
445ebdfc6a4SZhang Yubing 		if (err <= 0)
446ebdfc6a4SZhang Yubing 			return err == 0 ? -EPROTO : err;
447ebdfc6a4SZhang Yubing 
448ebdfc6a4SZhang Yubing 		if (err < msg.size && err < ret) {
449ebdfc6a4SZhang Yubing 			printf("%s: Reply: requested %zu bytes got %d bytes\n",
450ebdfc6a4SZhang Yubing 			       aux->name, msg.size, err);
451ebdfc6a4SZhang Yubing 			ret = err;
452ebdfc6a4SZhang Yubing 		}
453ebdfc6a4SZhang Yubing 
454ebdfc6a4SZhang Yubing 		msg.size -= err;
455ebdfc6a4SZhang Yubing 		msg.buffer += err;
456ebdfc6a4SZhang Yubing 	}
457ebdfc6a4SZhang Yubing 
458ebdfc6a4SZhang Yubing 	return ret;
459ebdfc6a4SZhang Yubing }
460ebdfc6a4SZhang Yubing 
drm_dp_i2c_xfer(struct ddc_adapter * adapter,struct i2c_msg * msgs,int num)461ebdfc6a4SZhang Yubing int drm_dp_i2c_xfer(struct ddc_adapter *adapter, struct i2c_msg *msgs,
462ebdfc6a4SZhang Yubing 		    int num)
463ebdfc6a4SZhang Yubing {
464ebdfc6a4SZhang Yubing 	struct drm_dp_aux *aux = container_of(adapter, struct drm_dp_aux, ddc);
465ebdfc6a4SZhang Yubing 	unsigned int i, j;
466ebdfc6a4SZhang Yubing 	unsigned int transfer_size;
467ebdfc6a4SZhang Yubing 	struct drm_dp_aux_msg msg;
468ebdfc6a4SZhang Yubing 	int err = 0;
469ebdfc6a4SZhang Yubing 
470ebdfc6a4SZhang Yubing 	memset(&msg, 0, sizeof(msg));
471ebdfc6a4SZhang Yubing 
472ebdfc6a4SZhang Yubing 	for (i = 0; i < num; i++) {
473ebdfc6a4SZhang Yubing 		msg.address = msgs[i].addr;
474ebdfc6a4SZhang Yubing 		drm_dp_i2c_msg_set_request(&msg, &msgs[i]);
475ebdfc6a4SZhang Yubing 		/* Send a bare address packet to start the transaction.
476ebdfc6a4SZhang Yubing 		 * Zero sized messages specify an address only (bare
477ebdfc6a4SZhang Yubing 		 * address) transaction.
478ebdfc6a4SZhang Yubing 		 */
479ebdfc6a4SZhang Yubing 		msg.buffer = NULL;
480ebdfc6a4SZhang Yubing 		msg.size = 0;
481ebdfc6a4SZhang Yubing 		err = drm_dp_i2c_do_msg(aux, &msg);
482ebdfc6a4SZhang Yubing 
483ebdfc6a4SZhang Yubing 		/*
484ebdfc6a4SZhang Yubing 		 * Reset msg.request in case in case it got
485ebdfc6a4SZhang Yubing 		 * changed into a WRITE_STATUS_UPDATE.
486ebdfc6a4SZhang Yubing 		 */
487ebdfc6a4SZhang Yubing 		drm_dp_i2c_msg_set_request(&msg, &msgs[i]);
488ebdfc6a4SZhang Yubing 
489ebdfc6a4SZhang Yubing 		if (err < 0)
490ebdfc6a4SZhang Yubing 			break;
491ebdfc6a4SZhang Yubing 		/* We want each transaction to be as large as possible, but
492ebdfc6a4SZhang Yubing 		 * we'll go to smaller sizes if the hardware gives us a
493ebdfc6a4SZhang Yubing 		 * short reply.
494ebdfc6a4SZhang Yubing 		 */
495ebdfc6a4SZhang Yubing 		transfer_size = DP_AUX_MAX_PAYLOAD_BYTES;
496ebdfc6a4SZhang Yubing 		for (j = 0; j < msgs[i].len; j += msg.size) {
497ebdfc6a4SZhang Yubing 			msg.buffer = msgs[i].buf + j;
498ebdfc6a4SZhang Yubing 			msg.size = min(transfer_size, msgs[i].len - j);
499ebdfc6a4SZhang Yubing 
500ebdfc6a4SZhang Yubing 			err = drm_dp_i2c_drain_msg(aux, &msg);
501ebdfc6a4SZhang Yubing 
502ebdfc6a4SZhang Yubing 			/*
503ebdfc6a4SZhang Yubing 			 * Reset msg.request in case in case it got
504ebdfc6a4SZhang Yubing 			 * changed into a WRITE_STATUS_UPDATE.
505ebdfc6a4SZhang Yubing 			 */
506ebdfc6a4SZhang Yubing 			drm_dp_i2c_msg_set_request(&msg, &msgs[i]);
507ebdfc6a4SZhang Yubing 
508ebdfc6a4SZhang Yubing 			if (err < 0)
509ebdfc6a4SZhang Yubing 				break;
510ebdfc6a4SZhang Yubing 			transfer_size = err;
511ebdfc6a4SZhang Yubing 		}
512ebdfc6a4SZhang Yubing 		if (err < 0)
513ebdfc6a4SZhang Yubing 			break;
514ebdfc6a4SZhang Yubing 	}
515ebdfc6a4SZhang Yubing 	if (err >= 0)
516ebdfc6a4SZhang Yubing 		err = num;
517ebdfc6a4SZhang Yubing 	/* Send a bare address packet to close out the transaction.
518ebdfc6a4SZhang Yubing 	 * Zero sized messages specify an address only (bare
519ebdfc6a4SZhang Yubing 	 * address) transaction.
520ebdfc6a4SZhang Yubing 	 */
521ebdfc6a4SZhang Yubing 	msg.request &= ~DP_AUX_I2C_MOT;
522ebdfc6a4SZhang Yubing 	msg.buffer = NULL;
523ebdfc6a4SZhang Yubing 	msg.size = 0;
524ebdfc6a4SZhang Yubing 	(void)drm_dp_i2c_do_msg(aux, &msg);
525ebdfc6a4SZhang Yubing 
526ebdfc6a4SZhang Yubing 	return err;
527ebdfc6a4SZhang Yubing }
528ebdfc6a4SZhang Yubing 
529