diff options
| author | Dave Airlie <airlied@redhat.com> | 2026-01-28 05:44:28 +0300 |
|---|---|---|
| committer | Dave Airlie <airlied@redhat.com> | 2026-01-28 05:44:28 +0300 |
| commit | 6704d98a4f48b7424edc0f7ae2a06c0a8af02e2f (patch) | |
| tree | 261ac2fddcd79f6b66568a613ee458260f5cc62c /include/drm/display | |
| parent | 504f3cead6b04914c53831f9efce902b8d91c009 (diff) | |
| parent | 63804fed149a6750ffd28610c5c1c98cce6bd377 (diff) | |
| download | linux-6704d98a4f48b7424edc0f7ae2a06c0a8af02e2f.tar.xz | |
BackMerge tag 'v6.19-rc7' into drm-next
Linux 6.19-rc7
This is needed for msm and rust trees.
Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'include/drm/display')
| -rw-r--r-- | include/drm/display/drm_dp_helper.h | 57 |
1 files changed, 37 insertions, 20 deletions
diff --git a/include/drm/display/drm_dp_helper.h b/include/drm/display/drm_dp_helper.h index 85e868238e28..1d0acd58f486 100644 --- a/include/drm/display/drm_dp_helper.h +++ b/include/drm/display/drm_dp_helper.h @@ -555,6 +555,22 @@ ssize_t drm_dp_dpcd_write(struct drm_dp_aux *aux, unsigned int offset, void *buffer, size_t size); /** + * drm_dp_dpcd_readb() - read a single byte from the DPCD + * @aux: DisplayPort AUX channel + * @offset: address of the register to read + * @valuep: location where the value of the register will be stored + * + * Returns the number of bytes transferred (1) on success, or a negative + * error code on failure. In most of the cases you should be using + * drm_dp_dpcd_read_byte() instead. + */ +static inline ssize_t drm_dp_dpcd_readb(struct drm_dp_aux *aux, + unsigned int offset, u8 *valuep) +{ + return drm_dp_dpcd_read(aux, offset, valuep, 1); +} + +/** * drm_dp_dpcd_read_data() - read a series of bytes from the DPCD * @aux: DisplayPort AUX channel (SST or MST) * @offset: address of the (first) register to read @@ -573,12 +589,29 @@ static inline int drm_dp_dpcd_read_data(struct drm_dp_aux *aux, void *buffer, size_t size) { int ret; + size_t i; + u8 *buf = buffer; ret = drm_dp_dpcd_read(aux, offset, buffer, size); - if (ret < 0) - return ret; - if (ret < size) - return -EPROTO; + if (ret >= 0) { + if (ret < size) + return -EPROTO; + return 0; + } + + /* + * Workaround for USB-C hubs/adapters with buggy firmware that fail + * multi-byte AUX reads but work with single-byte reads. + * Known affected devices: + * - Lenovo USB-C to VGA adapter (VIA VL817, idVendor=17ef, idProduct=7217) + * - Dell DA310 USB-C hub (idVendor=413c, idProduct=c010) + * Attempt byte-by-byte reading as a fallback. + */ + for (i = 0; i < size; i++) { + ret = drm_dp_dpcd_readb(aux, offset + i, &buf[i]); + if (ret < 0) + return ret; + } return 0; } @@ -613,22 +646,6 @@ static inline int drm_dp_dpcd_write_data(struct drm_dp_aux *aux, } /** - * drm_dp_dpcd_readb() - read a single byte from the DPCD - * @aux: DisplayPort AUX channel - * @offset: address of the register to read - * @valuep: location where the value of the register will be stored - * - * Returns the number of bytes transferred (1) on success, or a negative - * error code on failure. In most of the cases you should be using - * drm_dp_dpcd_read_byte() instead. - */ -static inline ssize_t drm_dp_dpcd_readb(struct drm_dp_aux *aux, - unsigned int offset, u8 *valuep) -{ - return drm_dp_dpcd_read(aux, offset, valuep, 1); -} - -/** * drm_dp_dpcd_writeb() - write a single byte to the DPCD * @aux: DisplayPort AUX channel * @offset: address of the register to write |
