aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/drm_dp_helper.c
diff options
context:
space:
mode:
authorThierry Reding <treding@nvidia.com>2013-11-28 05:31:00 -0500
committerThierry Reding <treding@nvidia.com>2014-02-26 11:21:32 -0500
commitc197db75ff5c1d4f015c7668a3715e230a5d7e27 (patch)
tree9ba1ee03f90e51548bb4c1d9533b81e87fa04539 /drivers/gpu/drm/drm_dp_helper.c
parent38dbfb59d1175ef458d006556061adeaa8751b72 (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.c110
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}
348EXPORT_SYMBOL(drm_dp_bw_code_to_link_rate); 348EXPORT_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
369static 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 */
430ssize_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}
436EXPORT_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 */
452ssize_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}
458EXPORT_SYMBOL(drm_dp_dpcd_write);