aboutsummaryrefslogtreecommitdiffstats
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
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
-rw-r--r--drivers/gpu/drm/drm_dp_helper.c110
-rw-r--r--include/drm/drm_dp_helper.h79
2 files changed, 189 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);
diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h
index 1d09050a8c00..70f18eb3ca1a 100644
--- a/include/drm/drm_dp_helper.h
+++ b/include/drm/drm_dp_helper.h
@@ -398,4 +398,83 @@ drm_dp_enhanced_frame_cap(const u8 dpcd[DP_RECEIVER_CAP_SIZE])
398 (dpcd[DP_MAX_LANE_COUNT] & DP_ENHANCED_FRAME_CAP); 398 (dpcd[DP_MAX_LANE_COUNT] & DP_ENHANCED_FRAME_CAP);
399} 399}
400 400
401/*
402 * DisplayPort AUX channel
403 */
404
405/**
406 * struct drm_dp_aux_msg - DisplayPort AUX channel transaction
407 * @address: address of the (first) register to access
408 * @request: contains the type of transaction (see DP_AUX_* macros)
409 * @reply: upon completion, contains the reply type of the transaction
410 * @buffer: pointer to a transmission or reception buffer
411 * @size: size of @buffer
412 */
413struct drm_dp_aux_msg {
414 unsigned int address;
415 u8 request;
416 u8 reply;
417 void *buffer;
418 size_t size;
419};
420
421/**
422 * struct drm_dp_aux - DisplayPort AUX channel
423 * @dev: pointer to struct device that is the parent for this AUX channel
424 * @transfer: transfers a message representing a single AUX transaction
425 *
426 * The .dev field should be set to a pointer to the device that implements
427 * the AUX channel.
428 *
429 * Drivers provide a hardware-specific implementation of how transactions
430 * are executed via the .transfer() function. A pointer to a drm_dp_aux_msg
431 * structure describing the transaction is passed into this function. Upon
432 * success, the implementation should return the number of payload bytes
433 * that were transferred, or a negative error-code on failure. Helpers
434 * propagate errors from the .transfer() function, with the exception of
435 * the -EBUSY error, which causes a transaction to be retried. On a short,
436 * helpers will return -EPROTO to make it simpler to check for failure.
437 */
438struct drm_dp_aux {
439 struct device *dev;
440
441 ssize_t (*transfer)(struct drm_dp_aux *aux,
442 struct drm_dp_aux_msg *msg);
443};
444
445ssize_t drm_dp_dpcd_read(struct drm_dp_aux *aux, unsigned int offset,
446 void *buffer, size_t size);
447ssize_t drm_dp_dpcd_write(struct drm_dp_aux *aux, unsigned int offset,
448 void *buffer, size_t size);
449
450/**
451 * drm_dp_dpcd_readb() - read a single byte from the DPCD
452 * @aux: DisplayPort AUX channel
453 * @offset: address of the register to read
454 * @valuep: location where the value of the register will be stored
455 *
456 * Returns the number of bytes transferred (1) on success, or a negative
457 * error code on failure.
458 */
459static inline ssize_t drm_dp_dpcd_readb(struct drm_dp_aux *aux,
460 unsigned int offset, u8 *valuep)
461{
462 return drm_dp_dpcd_read(aux, offset, valuep, 1);
463}
464
465/**
466 * drm_dp_dpcd_writeb() - write a single byte to the DPCD
467 * @aux: DisplayPort AUX channel
468 * @offset: address of the register to write
469 * @value: value to write to the register
470 *
471 * Returns the number of bytes transferred (1) on success, or a negative
472 * error code on failure.
473 */
474static inline ssize_t drm_dp_dpcd_writeb(struct drm_dp_aux *aux,
475 unsigned int offset, u8 value)
476{
477 return drm_dp_dpcd_write(aux, offset, &value, 1);
478}
479
401#endif /* _DRM_DP_HELPER_H_ */ 480#endif /* _DRM_DP_HELPER_H_ */