Rev 4560 | Rev 5271 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
3192 | Serge | 1 | /* |
2 | * Copyright © 2009 Keith Packard |
||
3 | * |
||
4 | * Permission to use, copy, modify, distribute, and sell this software and its |
||
5 | * documentation for any purpose is hereby granted without fee, provided that |
||
6 | * the above copyright notice appear in all copies and that both that copyright |
||
7 | * notice and this permission notice appear in supporting documentation, and |
||
8 | * that the name of the copyright holders not be used in advertising or |
||
9 | * publicity pertaining to distribution of the software without specific, |
||
10 | * written prior permission. The copyright holders make no representations |
||
11 | * about the suitability of this software for any purpose. It is provided "as |
||
12 | * is" without express or implied warranty. |
||
13 | * |
||
14 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, |
||
15 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO |
||
16 | * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR |
||
17 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, |
||
18 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER |
||
19 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE |
||
20 | * OF THIS SOFTWARE. |
||
21 | */ |
||
22 | |||
23 | #include |
||
24 | #include |
||
25 | //#include |
||
26 | //#include |
||
27 | #include |
||
28 | #include |
||
29 | #include |
||
5060 | serge | 30 | #include |
3192 | Serge | 31 | #include |
32 | |||
33 | /** |
||
34 | * DOC: dp helpers |
||
35 | * |
||
36 | * These functions contain some common logic and helpers at various abstraction |
||
37 | * levels to deal with Display Port sink devices and related things like DP aux |
||
38 | * channel transfers, EDID reading over DP aux channels, decoding certain DPCD |
||
39 | * blocks, ... |
||
40 | */ |
||
41 | |||
42 | /* Run a single AUX_CH I2C transaction, writing/reading data as necessary */ |
||
43 | static int |
||
44 | i2c_algo_dp_aux_transaction(struct i2c_adapter *adapter, int mode, |
||
45 | uint8_t write_byte, uint8_t *read_byte) |
||
46 | { |
||
47 | struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data; |
||
48 | int ret; |
||
49 | |||
50 | ret = (*algo_data->aux_ch)(adapter, mode, |
||
51 | write_byte, read_byte); |
||
52 | return ret; |
||
53 | } |
||
54 | |||
55 | /* |
||
56 | * I2C over AUX CH |
||
57 | */ |
||
58 | |||
59 | /* |
||
60 | * Send the address. If the I2C link is running, this 'restarts' |
||
61 | * the connection with the new address, this is used for doing |
||
62 | * a write followed by a read (as needed for DDC) |
||
63 | */ |
||
64 | static int |
||
65 | i2c_algo_dp_aux_address(struct i2c_adapter *adapter, u16 address, bool reading) |
||
66 | { |
||
67 | struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data; |
||
68 | int mode = MODE_I2C_START; |
||
69 | int ret; |
||
70 | |||
71 | if (reading) |
||
72 | mode |= MODE_I2C_READ; |
||
73 | else |
||
74 | mode |= MODE_I2C_WRITE; |
||
75 | algo_data->address = address; |
||
76 | algo_data->running = true; |
||
77 | ret = i2c_algo_dp_aux_transaction(adapter, mode, 0, NULL); |
||
78 | return ret; |
||
79 | } |
||
80 | |||
81 | /* |
||
82 | * Stop the I2C transaction. This closes out the link, sending |
||
83 | * a bare address packet with the MOT bit turned off |
||
84 | */ |
||
85 | static void |
||
86 | i2c_algo_dp_aux_stop(struct i2c_adapter *adapter, bool reading) |
||
87 | { |
||
88 | struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data; |
||
89 | int mode = MODE_I2C_STOP; |
||
90 | |||
91 | if (reading) |
||
92 | mode |= MODE_I2C_READ; |
||
93 | else |
||
94 | mode |= MODE_I2C_WRITE; |
||
95 | if (algo_data->running) { |
||
96 | (void) i2c_algo_dp_aux_transaction(adapter, mode, 0, NULL); |
||
97 | algo_data->running = false; |
||
98 | } |
||
99 | } |
||
100 | |||
101 | /* |
||
102 | * Write a single byte to the current I2C address, the |
||
103 | * the I2C link must be running or this returns -EIO |
||
104 | */ |
||
105 | static int |
||
106 | i2c_algo_dp_aux_put_byte(struct i2c_adapter *adapter, u8 byte) |
||
107 | { |
||
108 | struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data; |
||
109 | int ret; |
||
110 | |||
111 | if (!algo_data->running) |
||
112 | return -EIO; |
||
113 | |||
114 | ret = i2c_algo_dp_aux_transaction(adapter, MODE_I2C_WRITE, byte, NULL); |
||
115 | return ret; |
||
116 | } |
||
117 | |||
118 | /* |
||
119 | * Read a single byte from the current I2C address, the |
||
120 | * I2C link must be running or this returns -EIO |
||
121 | */ |
||
122 | static int |
||
123 | i2c_algo_dp_aux_get_byte(struct i2c_adapter *adapter, u8 *byte_ret) |
||
124 | { |
||
125 | struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data; |
||
126 | int ret; |
||
127 | |||
128 | if (!algo_data->running) |
||
129 | return -EIO; |
||
130 | |||
131 | ret = i2c_algo_dp_aux_transaction(adapter, MODE_I2C_READ, 0, byte_ret); |
||
132 | return ret; |
||
133 | } |
||
134 | |||
135 | static int |
||
136 | i2c_algo_dp_aux_xfer(struct i2c_adapter *adapter, |
||
137 | struct i2c_msg *msgs, |
||
138 | int num) |
||
139 | { |
||
140 | int ret = 0; |
||
141 | bool reading = false; |
||
142 | int m; |
||
143 | int b; |
||
144 | |||
145 | for (m = 0; m < num; m++) { |
||
146 | u16 len = msgs[m].len; |
||
147 | u8 *buf = msgs[m].buf; |
||
148 | reading = (msgs[m].flags & I2C_M_RD) != 0; |
||
149 | ret = i2c_algo_dp_aux_address(adapter, msgs[m].addr, reading); |
||
150 | if (ret < 0) |
||
151 | break; |
||
152 | if (reading) { |
||
153 | for (b = 0; b < len; b++) { |
||
154 | ret = i2c_algo_dp_aux_get_byte(adapter, &buf[b]); |
||
155 | if (ret < 0) |
||
156 | break; |
||
157 | } |
||
158 | } else { |
||
159 | for (b = 0; b < len; b++) { |
||
160 | ret = i2c_algo_dp_aux_put_byte(adapter, buf[b]); |
||
161 | if (ret < 0) |
||
162 | break; |
||
163 | } |
||
164 | } |
||
165 | if (ret < 0) |
||
166 | break; |
||
167 | } |
||
168 | if (ret >= 0) |
||
169 | ret = num; |
||
170 | i2c_algo_dp_aux_stop(adapter, reading); |
||
171 | DRM_DEBUG_KMS("dp_aux_xfer return %d\n", ret); |
||
172 | return ret; |
||
173 | } |
||
174 | |||
175 | static u32 |
||
176 | i2c_algo_dp_aux_functionality(struct i2c_adapter *adapter) |
||
177 | { |
||
178 | return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | |
||
179 | I2C_FUNC_SMBUS_READ_BLOCK_DATA | |
||
180 | I2C_FUNC_SMBUS_BLOCK_PROC_CALL | |
||
181 | I2C_FUNC_10BIT_ADDR; |
||
182 | } |
||
183 | |||
184 | static const struct i2c_algorithm i2c_dp_aux_algo = { |
||
185 | .master_xfer = i2c_algo_dp_aux_xfer, |
||
186 | .functionality = i2c_algo_dp_aux_functionality, |
||
187 | }; |
||
188 | |||
189 | static void |
||
190 | i2c_dp_aux_reset_bus(struct i2c_adapter *adapter) |
||
191 | { |
||
192 | (void) i2c_algo_dp_aux_address(adapter, 0, false); |
||
193 | (void) i2c_algo_dp_aux_stop(adapter, false); |
||
194 | } |
||
195 | |||
196 | static int |
||
197 | i2c_dp_aux_prepare_bus(struct i2c_adapter *adapter) |
||
198 | { |
||
199 | adapter->algo = &i2c_dp_aux_algo; |
||
200 | adapter->retries = 3; |
||
201 | i2c_dp_aux_reset_bus(adapter); |
||
202 | return 0; |
||
203 | } |
||
204 | |||
205 | /** |
||
206 | * i2c_dp_aux_add_bus() - register an i2c adapter using the aux ch helper |
||
207 | * @adapter: i2c adapter to register |
||
208 | * |
||
5060 | serge | 209 | * This registers an i2c adapter that uses dp aux channel as it's underlaying |
3192 | Serge | 210 | * transport. The driver needs to fill out the &i2c_algo_dp_aux_data structure |
211 | * and store it in the algo_data member of the @adapter argument. This will be |
||
212 | * used by the i2c over dp aux algorithm to drive the hardware. |
||
213 | * |
||
214 | * RETURNS: |
||
215 | * 0 on success, -ERRNO on failure. |
||
5060 | serge | 216 | * |
217 | * IMPORTANT: |
||
218 | * This interface is deprecated, please switch to the new dp aux helpers and |
||
219 | * drm_dp_aux_register(). |
||
3192 | Serge | 220 | */ |
221 | int |
||
222 | i2c_dp_aux_add_bus(struct i2c_adapter *adapter) |
||
223 | { |
||
224 | int error; |
||
225 | |||
226 | error = i2c_dp_aux_prepare_bus(adapter); |
||
227 | if (error) |
||
228 | return error; |
||
229 | error = i2c_add_adapter(adapter); |
||
230 | return error; |
||
231 | } |
||
232 | EXPORT_SYMBOL(i2c_dp_aux_add_bus); |
||
233 | |||
234 | /* Helpers for DP link training */ |
||
4560 | Serge | 235 | static u8 dp_link_status(const u8 link_status[DP_LINK_STATUS_SIZE], int r) |
3192 | Serge | 236 | { |
237 | return link_status[r - DP_LANE0_1_STATUS]; |
||
238 | } |
||
239 | |||
4560 | Serge | 240 | static u8 dp_get_lane_status(const u8 link_status[DP_LINK_STATUS_SIZE], |
3192 | Serge | 241 | int lane) |
242 | { |
||
243 | int i = DP_LANE0_1_STATUS + (lane >> 1); |
||
244 | int s = (lane & 1) * 4; |
||
245 | u8 l = dp_link_status(link_status, i); |
||
246 | return (l >> s) & 0xf; |
||
247 | } |
||
248 | |||
4560 | Serge | 249 | bool drm_dp_channel_eq_ok(const u8 link_status[DP_LINK_STATUS_SIZE], |
3192 | Serge | 250 | int lane_count) |
251 | { |
||
252 | u8 lane_align; |
||
253 | u8 lane_status; |
||
254 | int lane; |
||
255 | |||
256 | lane_align = dp_link_status(link_status, |
||
257 | DP_LANE_ALIGN_STATUS_UPDATED); |
||
258 | if ((lane_align & DP_INTERLANE_ALIGN_DONE) == 0) |
||
259 | return false; |
||
260 | for (lane = 0; lane < lane_count; lane++) { |
||
261 | lane_status = dp_get_lane_status(link_status, lane); |
||
262 | if ((lane_status & DP_CHANNEL_EQ_BITS) != DP_CHANNEL_EQ_BITS) |
||
263 | return false; |
||
264 | } |
||
265 | return true; |
||
266 | } |
||
267 | EXPORT_SYMBOL(drm_dp_channel_eq_ok); |
||
268 | |||
4560 | Serge | 269 | bool drm_dp_clock_recovery_ok(const u8 link_status[DP_LINK_STATUS_SIZE], |
3192 | Serge | 270 | int lane_count) |
271 | { |
||
272 | int lane; |
||
273 | u8 lane_status; |
||
274 | |||
275 | for (lane = 0; lane < lane_count; lane++) { |
||
276 | lane_status = dp_get_lane_status(link_status, lane); |
||
277 | if ((lane_status & DP_LANE_CR_DONE) == 0) |
||
278 | return false; |
||
279 | } |
||
280 | return true; |
||
281 | } |
||
282 | EXPORT_SYMBOL(drm_dp_clock_recovery_ok); |
||
283 | |||
4560 | Serge | 284 | u8 drm_dp_get_adjust_request_voltage(const u8 link_status[DP_LINK_STATUS_SIZE], |
3192 | Serge | 285 | int lane) |
286 | { |
||
287 | int i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1); |
||
288 | int s = ((lane & 1) ? |
||
289 | DP_ADJUST_VOLTAGE_SWING_LANE1_SHIFT : |
||
290 | DP_ADJUST_VOLTAGE_SWING_LANE0_SHIFT); |
||
291 | u8 l = dp_link_status(link_status, i); |
||
292 | |||
293 | return ((l >> s) & 0x3) << DP_TRAIN_VOLTAGE_SWING_SHIFT; |
||
294 | } |
||
295 | EXPORT_SYMBOL(drm_dp_get_adjust_request_voltage); |
||
296 | |||
4560 | Serge | 297 | u8 drm_dp_get_adjust_request_pre_emphasis(const u8 link_status[DP_LINK_STATUS_SIZE], |
3192 | Serge | 298 | int lane) |
299 | { |
||
300 | int i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1); |
||
301 | int s = ((lane & 1) ? |
||
302 | DP_ADJUST_PRE_EMPHASIS_LANE1_SHIFT : |
||
303 | DP_ADJUST_PRE_EMPHASIS_LANE0_SHIFT); |
||
304 | u8 l = dp_link_status(link_status, i); |
||
305 | |||
306 | return ((l >> s) & 0x3) << DP_TRAIN_PRE_EMPHASIS_SHIFT; |
||
307 | } |
||
308 | EXPORT_SYMBOL(drm_dp_get_adjust_request_pre_emphasis); |
||
309 | |||
4560 | Serge | 310 | void drm_dp_link_train_clock_recovery_delay(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) { |
3192 | Serge | 311 | if (dpcd[DP_TRAINING_AUX_RD_INTERVAL] == 0) |
312 | udelay(100); |
||
313 | else |
||
314 | mdelay(dpcd[DP_TRAINING_AUX_RD_INTERVAL] * 4); |
||
315 | } |
||
316 | EXPORT_SYMBOL(drm_dp_link_train_clock_recovery_delay); |
||
317 | |||
4560 | Serge | 318 | void drm_dp_link_train_channel_eq_delay(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) { |
3192 | Serge | 319 | if (dpcd[DP_TRAINING_AUX_RD_INTERVAL] == 0) |
320 | udelay(400); |
||
321 | else |
||
322 | mdelay(dpcd[DP_TRAINING_AUX_RD_INTERVAL] * 4); |
||
323 | } |
||
324 | EXPORT_SYMBOL(drm_dp_link_train_channel_eq_delay); |
||
325 | |||
326 | u8 drm_dp_link_rate_to_bw_code(int link_rate) |
||
327 | { |
||
328 | switch (link_rate) { |
||
329 | case 162000: |
||
330 | default: |
||
331 | return DP_LINK_BW_1_62; |
||
332 | case 270000: |
||
333 | return DP_LINK_BW_2_7; |
||
334 | case 540000: |
||
335 | return DP_LINK_BW_5_4; |
||
336 | } |
||
337 | } |
||
338 | EXPORT_SYMBOL(drm_dp_link_rate_to_bw_code); |
||
339 | |||
340 | int drm_dp_bw_code_to_link_rate(u8 link_bw) |
||
341 | { |
||
342 | switch (link_bw) { |
||
343 | case DP_LINK_BW_1_62: |
||
344 | default: |
||
345 | return 162000; |
||
346 | case DP_LINK_BW_2_7: |
||
347 | return 270000; |
||
348 | case DP_LINK_BW_5_4: |
||
349 | return 540000; |
||
350 | } |
||
351 | } |
||
352 | EXPORT_SYMBOL(drm_dp_bw_code_to_link_rate); |
||
5060 | serge | 353 | |
354 | /** |
||
355 | * DOC: dp helpers |
||
356 | * |
||
357 | * The DisplayPort AUX channel is an abstraction to allow generic, driver- |
||
358 | * independent access to AUX functionality. Drivers can take advantage of |
||
359 | * this by filling in the fields of the drm_dp_aux structure. |
||
360 | * |
||
361 | * Transactions are described using a hardware-independent drm_dp_aux_msg |
||
362 | * structure, which is passed into a driver's .transfer() implementation. |
||
363 | * Both native and I2C-over-AUX transactions are supported. |
||
364 | */ |
||
365 | |||
366 | static int drm_dp_dpcd_access(struct drm_dp_aux *aux, u8 request, |
||
367 | unsigned int offset, void *buffer, size_t size) |
||
368 | { |
||
369 | struct drm_dp_aux_msg msg; |
||
370 | unsigned int retry; |
||
371 | int err; |
||
372 | |||
373 | memset(&msg, 0, sizeof(msg)); |
||
374 | msg.address = offset; |
||
375 | msg.request = request; |
||
376 | msg.buffer = buffer; |
||
377 | msg.size = size; |
||
378 | |||
379 | /* |
||
380 | * The specification doesn't give any recommendation on how often to |
||
381 | * retry native transactions, so retry 7 times like for I2C-over-AUX |
||
382 | * transactions. |
||
383 | */ |
||
384 | for (retry = 0; retry < 7; retry++) { |
||
385 | |||
386 | mutex_lock(&aux->hw_mutex); |
||
387 | err = aux->transfer(aux, &msg); |
||
388 | mutex_unlock(&aux->hw_mutex); |
||
389 | if (err < 0) { |
||
390 | if (err == -EBUSY) |
||
391 | continue; |
||
392 | |||
393 | return err; |
||
394 | } |
||
395 | |||
396 | |||
397 | switch (msg.reply & DP_AUX_NATIVE_REPLY_MASK) { |
||
398 | case DP_AUX_NATIVE_REPLY_ACK: |
||
399 | if (err < size) |
||
400 | return -EPROTO; |
||
401 | return err; |
||
402 | |||
403 | case DP_AUX_NATIVE_REPLY_NACK: |
||
404 | return -EIO; |
||
405 | |||
406 | case DP_AUX_NATIVE_REPLY_DEFER: |
||
407 | usleep(500); |
||
408 | break; |
||
409 | } |
||
410 | } |
||
411 | |||
412 | DRM_DEBUG_KMS("too many retries, giving up\n"); |
||
413 | return -EIO; |
||
414 | } |
||
415 | |||
416 | /** |
||
417 | * drm_dp_dpcd_read() - read a series of bytes from the DPCD |
||
418 | * @aux: DisplayPort AUX channel |
||
419 | * @offset: address of the (first) register to read |
||
420 | * @buffer: buffer to store the register values |
||
421 | * @size: number of bytes in @buffer |
||
422 | * |
||
423 | * Returns the number of bytes transferred on success, or a negative error |
||
424 | * code on failure. -EIO is returned if the request was NAKed by the sink or |
||
425 | * if the retry count was exceeded. If not all bytes were transferred, this |
||
426 | * function returns -EPROTO. Errors from the underlying AUX channel transfer |
||
427 | * function, with the exception of -EBUSY (which causes the transaction to |
||
428 | * be retried), are propagated to the caller. |
||
429 | */ |
||
430 | ssize_t drm_dp_dpcd_read(struct drm_dp_aux *aux, unsigned int offset, |
||
431 | void *buffer, size_t size) |
||
432 | { |
||
433 | return drm_dp_dpcd_access(aux, DP_AUX_NATIVE_READ, offset, buffer, |
||
434 | size); |
||
435 | } |
||
436 | EXPORT_SYMBOL(drm_dp_dpcd_read); |
||
437 | |||
438 | /** |
||
439 | * drm_dp_dpcd_write() - write a series of bytes to the DPCD |
||
440 | * @aux: DisplayPort AUX channel |
||
441 | * @offset: address of the (first) register to write |
||
442 | * @buffer: buffer containing the values to write |
||
443 | * @size: number of bytes in @buffer |
||
444 | * |
||
445 | * Returns the number of bytes transferred on success, or a negative error |
||
446 | * code on failure. -EIO is returned if the request was NAKed by the sink or |
||
447 | * if the retry count was exceeded. If not all bytes were transferred, this |
||
448 | * function returns -EPROTO. Errors from the underlying AUX channel transfer |
||
449 | * function, with the exception of -EBUSY (which causes the transaction to |
||
450 | * be retried), are propagated to the caller. |
||
451 | */ |
||
452 | ssize_t drm_dp_dpcd_write(struct drm_dp_aux *aux, unsigned int offset, |
||
453 | void *buffer, size_t size) |
||
454 | { |
||
455 | return drm_dp_dpcd_access(aux, DP_AUX_NATIVE_WRITE, offset, buffer, |
||
456 | size); |
||
457 | } |
||
458 | EXPORT_SYMBOL(drm_dp_dpcd_write); |
||
459 | |||
460 | /** |
||
461 | * drm_dp_dpcd_read_link_status() - read DPCD link status (bytes 0x202-0x207) |
||
462 | * @aux: DisplayPort AUX channel |
||
463 | * @status: buffer to store the link status in (must be at least 6 bytes) |
||
464 | * |
||
465 | * Returns the number of bytes transferred on success or a negative error |
||
466 | * code on failure. |
||
467 | */ |
||
468 | int drm_dp_dpcd_read_link_status(struct drm_dp_aux *aux, |
||
469 | u8 status[DP_LINK_STATUS_SIZE]) |
||
470 | { |
||
471 | return drm_dp_dpcd_read(aux, DP_LANE0_1_STATUS, status, |
||
472 | DP_LINK_STATUS_SIZE); |
||
473 | } |
||
474 | EXPORT_SYMBOL(drm_dp_dpcd_read_link_status); |
||
475 | |||
476 | /** |
||
477 | * drm_dp_link_probe() - probe a DisplayPort link for capabilities |
||
478 | * @aux: DisplayPort AUX channel |
||
479 | * @link: pointer to structure in which to return link capabilities |
||
480 | * |
||
481 | * The structure filled in by this function can usually be passed directly |
||
482 | * into drm_dp_link_power_up() and drm_dp_link_configure() to power up and |
||
483 | * configure the link based on the link's capabilities. |
||
484 | * |
||
485 | * Returns 0 on success or a negative error code on failure. |
||
486 | */ |
||
487 | int drm_dp_link_probe(struct drm_dp_aux *aux, struct drm_dp_link *link) |
||
488 | { |
||
489 | u8 values[3]; |
||
490 | int err; |
||
491 | |||
492 | memset(link, 0, sizeof(*link)); |
||
493 | |||
494 | err = drm_dp_dpcd_read(aux, DP_DPCD_REV, values, sizeof(values)); |
||
495 | if (err < 0) |
||
496 | return err; |
||
497 | |||
498 | link->revision = values[0]; |
||
499 | link->rate = drm_dp_bw_code_to_link_rate(values[1]); |
||
500 | link->num_lanes = values[2] & DP_MAX_LANE_COUNT_MASK; |
||
501 | |||
502 | if (values[2] & DP_ENHANCED_FRAME_CAP) |
||
503 | link->capabilities |= DP_LINK_CAP_ENHANCED_FRAMING; |
||
504 | |||
505 | return 0; |
||
506 | } |
||
507 | EXPORT_SYMBOL(drm_dp_link_probe); |
||
508 | |||
509 | /** |
||
510 | * drm_dp_link_power_up() - power up a DisplayPort link |
||
511 | * @aux: DisplayPort AUX channel |
||
512 | * @link: pointer to a structure containing the link configuration |
||
513 | * |
||
514 | * Returns 0 on success or a negative error code on failure. |
||
515 | */ |
||
516 | int drm_dp_link_power_up(struct drm_dp_aux *aux, struct drm_dp_link *link) |
||
517 | { |
||
518 | u8 value; |
||
519 | int err; |
||
520 | |||
521 | /* DP_SET_POWER register is only available on DPCD v1.1 and later */ |
||
522 | if (link->revision < 0x11) |
||
523 | return 0; |
||
524 | |||
525 | err = drm_dp_dpcd_readb(aux, DP_SET_POWER, &value); |
||
526 | if (err < 0) |
||
527 | return err; |
||
528 | |||
529 | value &= ~DP_SET_POWER_MASK; |
||
530 | value |= DP_SET_POWER_D0; |
||
531 | |||
532 | err = drm_dp_dpcd_writeb(aux, DP_SET_POWER, value); |
||
533 | if (err < 0) |
||
534 | return err; |
||
535 | |||
536 | /* |
||
537 | * According to the DP 1.1 specification, a "Sink Device must exit the |
||
538 | * power saving state within 1 ms" (Section 2.5.3.1, Table 5-52, "Sink |
||
539 | * Control Field" (register 0x600). |
||
540 | */ |
||
541 | usleep(2000); |
||
542 | |||
543 | return 0; |
||
544 | } |
||
545 | EXPORT_SYMBOL(drm_dp_link_power_up); |
||
546 | |||
547 | /** |
||
548 | * drm_dp_link_configure() - configure a DisplayPort link |
||
549 | * @aux: DisplayPort AUX channel |
||
550 | * @link: pointer to a structure containing the link configuration |
||
551 | * |
||
552 | * Returns 0 on success or a negative error code on failure. |
||
553 | */ |
||
554 | int drm_dp_link_configure(struct drm_dp_aux *aux, struct drm_dp_link *link) |
||
555 | { |
||
556 | u8 values[2]; |
||
557 | int err; |
||
558 | |||
559 | values[0] = drm_dp_link_rate_to_bw_code(link->rate); |
||
560 | values[1] = link->num_lanes; |
||
561 | |||
562 | if (link->capabilities & DP_LINK_CAP_ENHANCED_FRAMING) |
||
563 | values[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN; |
||
564 | |||
565 | err = drm_dp_dpcd_write(aux, DP_LINK_BW_SET, values, sizeof(values)); |
||
566 | if (err < 0) |
||
567 | return err; |
||
568 | |||
569 | return 0; |
||
570 | } |
||
571 | EXPORT_SYMBOL(drm_dp_link_configure); |
||
572 | |||
573 | /* |
||
574 | * I2C-over-AUX implementation |
||
575 | */ |
||
576 | |||
577 | static u32 drm_dp_i2c_functionality(struct i2c_adapter *adapter) |
||
578 | { |
||
579 | return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | |
||
580 | I2C_FUNC_SMBUS_READ_BLOCK_DATA | |
||
581 | I2C_FUNC_SMBUS_BLOCK_PROC_CALL | |
||
582 | I2C_FUNC_10BIT_ADDR; |
||
583 | } |
||
584 | |||
585 | /* |
||
586 | * Transfer a single I2C-over-AUX message and handle various error conditions, |
||
587 | * retrying the transaction as appropriate. It is assumed that the |
||
588 | * aux->transfer function does not modify anything in the msg other than the |
||
589 | * reply field. |
||
590 | */ |
||
591 | static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) |
||
592 | { |
||
593 | unsigned int retry; |
||
594 | int err; |
||
595 | |||
596 | /* |
||
597 | * DP1.2 sections 2.7.7.1.5.6.1 and 2.7.7.1.6.6.1: A DP Source device |
||
598 | * is required to retry at least seven times upon receiving AUX_DEFER |
||
599 | * before giving up the AUX transaction. |
||
600 | */ |
||
601 | for (retry = 0; retry < 7; retry++) { |
||
602 | mutex_lock(&aux->hw_mutex); |
||
603 | err = aux->transfer(aux, msg); |
||
604 | mutex_unlock(&aux->hw_mutex); |
||
605 | if (err < 0) { |
||
606 | if (err == -EBUSY) |
||
607 | continue; |
||
608 | |||
609 | DRM_DEBUG_KMS("transaction failed: %d\n", err); |
||
610 | return err; |
||
611 | } |
||
612 | |||
613 | |||
614 | switch (msg->reply & DP_AUX_NATIVE_REPLY_MASK) { |
||
615 | case DP_AUX_NATIVE_REPLY_ACK: |
||
616 | /* |
||
617 | * For I2C-over-AUX transactions this isn't enough, we |
||
618 | * need to check for the I2C ACK reply. |
||
619 | */ |
||
620 | break; |
||
621 | |||
622 | case DP_AUX_NATIVE_REPLY_NACK: |
||
623 | DRM_DEBUG_KMS("native nack\n"); |
||
624 | return -EREMOTEIO; |
||
625 | |||
626 | case DP_AUX_NATIVE_REPLY_DEFER: |
||
627 | DRM_DEBUG_KMS("native defer"); |
||
628 | /* |
||
629 | * We could check for I2C bit rate capabilities and if |
||
630 | * available adjust this interval. We could also be |
||
631 | * more careful with DP-to-legacy adapters where a |
||
632 | * long legacy cable may force very low I2C bit rates. |
||
633 | * |
||
634 | * For now just defer for long enough to hopefully be |
||
635 | * safe for all use-cases. |
||
636 | */ |
||
637 | usleep_range(500, 600); |
||
638 | continue; |
||
639 | |||
640 | default: |
||
641 | DRM_ERROR("invalid native reply %#04x\n", msg->reply); |
||
642 | return -EREMOTEIO; |
||
643 | } |
||
644 | |||
645 | switch (msg->reply & DP_AUX_I2C_REPLY_MASK) { |
||
646 | case DP_AUX_I2C_REPLY_ACK: |
||
647 | /* |
||
648 | * Both native ACK and I2C ACK replies received. We |
||
649 | * can assume the transfer was successful. |
||
650 | */ |
||
651 | if (err < msg->size) |
||
652 | return -EPROTO; |
||
653 | return 0; |
||
654 | |||
655 | case DP_AUX_I2C_REPLY_NACK: |
||
656 | DRM_DEBUG_KMS("I2C nack\n"); |
||
657 | return -EREMOTEIO; |
||
658 | |||
659 | case DP_AUX_I2C_REPLY_DEFER: |
||
660 | DRM_DEBUG_KMS("I2C defer\n"); |
||
661 | usleep_range(400, 500); |
||
662 | continue; |
||
663 | |||
664 | default: |
||
665 | DRM_ERROR("invalid I2C reply %#04x\n", msg->reply); |
||
666 | return -EREMOTEIO; |
||
667 | } |
||
668 | } |
||
669 | |||
670 | DRM_DEBUG_KMS("too many retries, giving up\n"); |
||
671 | return -EREMOTEIO; |
||
672 | } |
||
673 | |||
674 | static int drm_dp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, |
||
675 | int num) |
||
676 | { |
||
677 | struct drm_dp_aux *aux = adapter->algo_data; |
||
678 | unsigned int i, j; |
||
679 | struct drm_dp_aux_msg msg; |
||
680 | int err = 0; |
||
681 | |||
682 | memset(&msg, 0, sizeof(msg)); |
||
683 | |||
684 | for (i = 0; i < num; i++) { |
||
685 | msg.address = msgs[i].addr; |
||
686 | msg.request = (msgs[i].flags & I2C_M_RD) ? |
||
687 | DP_AUX_I2C_READ : |
||
688 | DP_AUX_I2C_WRITE; |
||
689 | msg.request |= DP_AUX_I2C_MOT; |
||
690 | /* Send a bare address packet to start the transaction. |
||
691 | * Zero sized messages specify an address only (bare |
||
692 | * address) transaction. |
||
693 | */ |
||
694 | msg.buffer = NULL; |
||
695 | msg.size = 0; |
||
696 | err = drm_dp_i2c_do_msg(aux, &msg); |
||
697 | if (err < 0) |
||
698 | break; |
||
699 | /* |
||
700 | * Many hardware implementations support FIFOs larger than a |
||
701 | * single byte, but it has been empirically determined that |
||
702 | * transferring data in larger chunks can actually lead to |
||
703 | * decreased performance. Therefore each message is simply |
||
704 | * transferred byte-by-byte. |
||
705 | */ |
||
706 | for (j = 0; j < msgs[i].len; j++) { |
||
707 | msg.buffer = msgs[i].buf + j; |
||
708 | msg.size = 1; |
||
709 | |||
710 | err = drm_dp_i2c_do_msg(aux, &msg); |
||
711 | if (err < 0) |
||
712 | break; |
||
713 | } |
||
714 | if (err < 0) |
||
715 | break; |
||
716 | } |
||
717 | if (err >= 0) |
||
718 | err = num; |
||
719 | /* Send a bare address packet to close out the transaction. |
||
720 | * Zero sized messages specify an address only (bare |
||
721 | * address) transaction. |
||
722 | */ |
||
723 | msg.request &= ~DP_AUX_I2C_MOT; |
||
724 | msg.buffer = NULL; |
||
725 | msg.size = 0; |
||
726 | (void)drm_dp_i2c_do_msg(aux, &msg); |
||
727 | |||
728 | return err; |
||
729 | } |
||
730 | |||
731 | static const struct i2c_algorithm drm_dp_i2c_algo = { |
||
732 | .functionality = drm_dp_i2c_functionality, |
||
733 | .master_xfer = drm_dp_i2c_xfer, |
||
734 | }; |
||
735 | |||
736 | /** |
||
737 | * drm_dp_aux_register() - initialise and register aux channel |
||
738 | * @aux: DisplayPort AUX channel |
||
739 | * |
||
740 | * Returns 0 on success or a negative error code on failure. |
||
741 | */ |
||
742 | int drm_dp_aux_register(struct drm_dp_aux *aux) |
||
743 | { |
||
744 | mutex_init(&aux->hw_mutex); |
||
745 | |||
746 | aux->ddc.algo = &drm_dp_i2c_algo; |
||
747 | aux->ddc.algo_data = aux; |
||
748 | aux->ddc.retries = 3; |
||
749 | |||
750 | aux->ddc.class = I2C_CLASS_DDC; |
||
751 | aux->ddc.owner = THIS_MODULE; |
||
752 | aux->ddc.dev.parent = aux->dev; |
||
753 | // aux->ddc.dev.of_node = aux->dev->of_node; |
||
754 | |||
755 | strlcpy(aux->ddc.name, aux->name ? aux->name : "aux", |
||
756 | sizeof(aux->ddc.name)); |
||
757 | |||
758 | return i2c_add_adapter(&aux->ddc); |
||
759 | } |
||
760 | EXPORT_SYMBOL(drm_dp_aux_register); |
||
761 | |||
762 | /** |
||
763 | * drm_dp_aux_unregister() - unregister an AUX adapter |
||
764 | * @aux: DisplayPort AUX channel |
||
765 | */ |
||
766 | void drm_dp_aux_unregister(struct drm_dp_aux *aux) |
||
767 | { |
||
768 | i2c_del_adapter(&aux->ddc); |
||
769 | } |
||
770 | EXPORT_SYMBOL(drm_dp_aux_unregister);>>>>>>>>>>>>>>>>><>><>>>>>>>>>> |