diff options
author | Thierry Reding <treding@nvidia.com> | 2013-11-28 05:31:00 -0500 |
---|---|---|
committer | Thierry Reding <treding@nvidia.com> | 2014-02-26 11:21:32 -0500 |
commit | c197db75ff5c1d4f015c7668a3715e230a5d7e27 (patch) | |
tree | 9ba1ee03f90e51548bb4c1d9533b81e87fa04539 /drivers/gpu/drm/drm_dp_helper.c | |
parent | 38dbfb59d1175ef458d006556061adeaa8751b72 (diff) |
drm/dp: Add AUX channel infrastructure
This is a superset of the current i2c_dp_aux bus functionality and can
be used to transfer native AUX in addition to I2C-over-AUX messages.
Helpers are provided to read and write the DPCD, either blockwise or
byte-wise. Many of the existing helpers for DisplayPort take a copy of a
portion of the DPCD and operate on that, without a way to write data
back to the DPCD (e.g. for configuration of the link).
Subsequent patches will build upon this infrastructure to provide common
functionality in a generic way.
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
Reviewed-by: Jani Nikula <jani.nikula@intel.com>
Signed-off-by: Thierry Reding <treding@nvidia.com>
---
Changes in v5:
- move comments partially to struct drm_dp_aux_msg in header file
- return -EPROTO on short reads in DPCD helpers
Changes in v4:
- fix a typo in a comment
Changes in v3:
- reorder drm_dp_dpcd_writeb() arguments to be more intuitive
- return number of bytes transferred in drm_dp_dpcd_write()
- factor out drm_dp_dpcd_access()
- describe error codes
Diffstat (limited to 'drivers/gpu/drm/drm_dp_helper.c')
-rw-r--r-- | drivers/gpu/drm/drm_dp_helper.c | 110 |
1 files changed, 110 insertions, 0 deletions
diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index 9e978aae8972..da6bcfe178a6 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c | |||
@@ -346,3 +346,113 @@ int drm_dp_bw_code_to_link_rate(u8 link_bw) | |||
346 | } | 346 | } |
347 | } | 347 | } |
348 | EXPORT_SYMBOL(drm_dp_bw_code_to_link_rate); | 348 | EXPORT_SYMBOL(drm_dp_bw_code_to_link_rate); |
349 | |||
350 | /** | ||
351 | * DOC: dp helpers | ||
352 | * | ||
353 | * The DisplayPort AUX channel is an abstraction to allow generic, driver- | ||
354 | * independent access to AUX functionality. Drivers can take advantage of | ||
355 | * this by filling in the fields of the drm_dp_aux structure. | ||
356 | * | ||
357 | * Transactions are described using a hardware-independent drm_dp_aux_msg | ||
358 | * structure, which is passed into a driver's .transfer() implementation. | ||
359 | * Both native and I2C-over-AUX transactions are supported. | ||
360 | * | ||
361 | * An AUX channel can also be used to transport I2C messages to a sink. A | ||
362 | * typical application of that is to access an EDID that's present in the | ||
363 | * sink device. The .transfer() function can also be used to execute such | ||
364 | * transactions. The drm_dp_aux_register_i2c_bus() function registers an | ||
365 | * I2C adapter that can be passed to drm_probe_ddc(). Upon removal, drivers | ||
366 | * should call drm_dp_aux_unregister_i2c_bus() to remove the I2C adapter. | ||
367 | */ | ||
368 | |||
369 | static int drm_dp_dpcd_access(struct drm_dp_aux *aux, u8 request, | ||
370 | unsigned int offset, void *buffer, size_t size) | ||
371 | { | ||
372 | struct drm_dp_aux_msg msg; | ||
373 | unsigned int retry; | ||
374 | int err; | ||
375 | |||
376 | memset(&msg, 0, sizeof(msg)); | ||
377 | msg.address = offset; | ||
378 | msg.request = request; | ||
379 | msg.buffer = buffer; | ||
380 | msg.size = size; | ||
381 | |||
382 | /* | ||
383 | * The specification doesn't give any recommendation on how often to | ||
384 | * retry native transactions, so retry 7 times like for I2C-over-AUX | ||
385 | * transactions. | ||
386 | */ | ||
387 | for (retry = 0; retry < 7; retry++) { | ||
388 | err = aux->transfer(aux, &msg); | ||
389 | if (err < 0) { | ||
390 | if (err == -EBUSY) | ||
391 | continue; | ||
392 | |||
393 | return err; | ||
394 | } | ||
395 | |||
396 | if (err < size) | ||
397 | return -EPROTO; | ||
398 | |||
399 | switch (msg.reply & DP_AUX_NATIVE_REPLY_MASK) { | ||
400 | case DP_AUX_NATIVE_REPLY_ACK: | ||
401 | return err; | ||
402 | |||
403 | case DP_AUX_NATIVE_REPLY_NACK: | ||
404 | return -EIO; | ||
405 | |||
406 | case DP_AUX_NATIVE_REPLY_DEFER: | ||
407 | usleep_range(400, 500); | ||
408 | break; | ||
409 | } | ||
410 | } | ||
411 | |||
412 | DRM_ERROR("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); | ||