Message ID | 20190723232808.28128-3-sunpeng.li@amd.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | MST AUX Devices (v3) | expand |
Noticed something! important note below On Tue, 2019-07-23 at 19:28 -0400, sunpeng.li@amd.com wrote: > From: Ville Syrjälä <ville.syrjala@linux.intel.com> > > All available downstream ports - physical and logical - are exposed for > each MST device. They are listed in /dev/, following the same naming > scheme as SST devices by appending an incremental ID. > > Although all downstream ports are exposed, only some will work as > expected. Consider the following topology: > > +---------+ > | ASIC | > +---------+ > Conn-0| > | > +----v----+ > +----| MST HUB |----+ > | +---------+ | > | | > |Port-1 Port-2| > +-----v-----+ +-----v-----+ > | MST | | SST | > | Display | | Display | > +-----------+ +-----------+ > |Port-1 > x > > MST Path | MST Device > ----------+---------------------------------- > sst:0 | MST Hub > mst:0-1 | MST Display > mst:0-1-1 | MST Display's disconnected DP out > mst:0-1-8 | MST Display's internal sink > mst:0-2 | SST Display > > On certain MST displays, the upstream physical port will ACK DPCD reads. > However, reads on the local logical port to the internal sink will > *NAK*. i.e. reading mst:0-1 ACKs, but mst:0-1-8 NAKs. > > There may also be duplicates. Some displays will return the same GUID > when reading DPCD from both mst:0-1 and mst:0-1-8. > > There are some device-dependent behavior as well. The MST hub used > during testing will actually *ACK* read requests on a disconnected > physical port, whereas the MST displays will NAK. > > In light of these discrepancies, it's simpler to expose all downstream > ports - both physical and logical - and let the user decide what to use. > > v3 changes: > * Change WARN_ON_ONCE -> DRM_ERROR on dpcd read errors > * Docstring and cosmetic fixes > > v2 changes: > > Moved remote aux device (un)registration to new mst connector late > register and early unregister helpers. Drivers should call these from > their own mst connector function hooks. > > This is to solve an issue during driver unload, where mst connector > devices are unregistered before the remote aux devices are. In a setup > where aux devices are created as children of connector devices, the aux > device would be removed too early, and uncleanly. Doing so in > early_unregister solves this issue, as that is called before connector > unregistration. > > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> > Signed-off-by: Leo Li <sunpeng.li@amd.com> > Reviewed-by: Lyude Paul <lyude@redhat.com> > --- > drivers/gpu/drm/drm_dp_aux_dev.c | 15 ++- > drivers/gpu/drm/drm_dp_mst_topology.c | 144 ++++++++++++++++++++++++-- > include/drm/drm_dp_helper.h | 4 + > include/drm/drm_dp_mst_helper.h | 11 ++ > 4 files changed, 162 insertions(+), 12 deletions(-) > > diff --git a/drivers/gpu/drm/drm_dp_aux_dev.c > b/drivers/gpu/drm/drm_dp_aux_dev.c > index 26e38dacf654..0cfb386754c3 100644 > --- a/drivers/gpu/drm/drm_dp_aux_dev.c > +++ b/drivers/gpu/drm/drm_dp_aux_dev.c > @@ -37,6 +37,7 @@ > > #include <drm/drm_crtc.h> > #include <drm/drm_dp_helper.h> > +#include <drm/drm_dp_mst_helper.h> > #include <drm/drm_print.h> > > #include "drm_crtc_helper_internal.h" > @@ -162,7 +163,12 @@ static ssize_t auxdev_read_iter(struct kiocb *iocb, > struct iov_iter *to) > break; > } > > - res = drm_dp_dpcd_read(aux_dev->aux, pos, buf, todo); > + if (aux_dev->aux->is_remote) > + res = drm_dp_mst_dpcd_read(aux_dev->aux, pos, buf, > + todo); > + else > + res = drm_dp_dpcd_read(aux_dev->aux, pos, buf, todo); > + > if (res <= 0) > break; > > @@ -209,7 +215,12 @@ static ssize_t auxdev_write_iter(struct kiocb *iocb, > struct iov_iter *from) > break; > } > > - res = drm_dp_dpcd_write(aux_dev->aux, pos, buf, todo); > + if (aux_dev->aux->is_remote) > + res = drm_dp_mst_dpcd_write(aux_dev->aux, pos, buf, > + todo); > + else > + res = drm_dp_dpcd_write(aux_dev->aux, pos, buf, todo); > + > if (res <= 0) > break; > > diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c > b/drivers/gpu/drm/drm_dp_mst_topology.c > index 0984b9a34d55..4733d3350ede 100644 > --- a/drivers/gpu/drm/drm_dp_mst_topology.c > +++ b/drivers/gpu/drm/drm_dp_mst_topology.c > @@ -36,6 +36,8 @@ > #include <drm/drm_print.h> > #include <drm/drm_probe_helper.h> > > +#include "drm_crtc_helper_internal.h" > + > /** > * DOC: dp mst helper > * > @@ -53,6 +55,9 @@ static int drm_dp_dpcd_write_payload(struct > drm_dp_mst_topology_mgr *mgr, > int id, > struct drm_dp_payload *payload); > > +static int drm_dp_send_dpcd_read(struct drm_dp_mst_topology_mgr *mgr, > + struct drm_dp_mst_port *port, > + int offset, int size, u8 *bytes); > static int drm_dp_send_dpcd_write(struct drm_dp_mst_topology_mgr *mgr, > struct drm_dp_mst_port *port, > int offset, int size, u8 *bytes); > @@ -1238,6 +1243,8 @@ static void drm_dp_destroy_port(struct kref *kref) > struct drm_dp_mst_topology_mgr *mgr = port->mgr; > > if (!port->input) { > + port->vcpi.num_slots = 0; > + This looks like some rebase ditritus you probably don't want in the final patch ;) Other then that, everything still looks good to me > kfree(port->cached_edid); > > /* > @@ -1483,6 +1490,52 @@ static bool drm_dp_port_setup_pdt(struct > drm_dp_mst_port *port) > return send_link; > } > > +/** > + * drm_dp_mst_dpcd_read() - read a series of bytes from the DPCD via > sideband > + * @aux: Fake sideband AUX CH > + * @offset: address of the (first) register to read > + * @buffer: buffer to store the register values > + * @size: number of bytes in @buffer > + * > + * Performs the same functionality for remote devices via > + * sideband messaging as drm_dp_dpcd_read() does for local > + * devices via actual AUX CH. > + * > + * Return: Number of bytes read, or negative error code on failure. > + */ > +ssize_t drm_dp_mst_dpcd_read(struct drm_dp_aux *aux, > + unsigned int offset, void *buffer, size_t size) > +{ > + struct drm_dp_mst_port *port = container_of(aux, struct > drm_dp_mst_port, > + aux); > + > + return drm_dp_send_dpcd_read(port->mgr, port, > + offset, size, buffer); > +} > + > +/** > + * drm_dp_mst_dpcd_write() - write a series of bytes to the DPCD via > sideband > + * @aux: Fake sideband AUX CH > + * @offset: address of the (first) register to write > + * @buffer: buffer containing the values to write > + * @size: number of bytes in @buffer > + * > + * Performs the same functionality for remote devices via > + * sideband messaging as drm_dp_dpcd_write() does for local > + * devices via actual AUX CH. > + * > + * Return: 0 on success, negative error code on failure. > + */ > +ssize_t drm_dp_mst_dpcd_write(struct drm_dp_aux *aux, > + unsigned int offset, void *buffer, size_t size) > +{ > + struct drm_dp_mst_port *port = container_of(aux, struct > drm_dp_mst_port, > + aux); > + > + return drm_dp_send_dpcd_write(port->mgr, port, > + offset, size, buffer); > +} > + > static void drm_dp_check_mstb_guid(struct drm_dp_mst_branch *mstb, u8 > *guid) > { > int ret; > @@ -1526,6 +1579,46 @@ static void build_mst_prop_path(const struct > drm_dp_mst_branch *mstb, > strlcat(proppath, temp, proppath_size); > } > > +/** > + * drm_dp_mst_connector_late_register() - Late MST connector registration > + * @drm_connector: The MST connector > + * @port: The MST port for this connector > + * > + * Helper to register the remote aux device for this MST port. Drivers > should > + * call this from their mst connector's late_register hook to enable MST > aux > + * devices. > + * > + * Return: 0 on success, negative error code on failure. > + */ > +int drm_dp_mst_connector_late_register(struct drm_connector *connector, > + struct drm_dp_mst_port *port) > +{ > + DRM_DEBUG_KMS("registering %s remote bus for %s\n", > + port->aux.name, connector->kdev->kobj.name); > + > + port->aux.dev = connector->kdev; > + return drm_dp_aux_register_devnode(&port->aux); > +} > +EXPORT_SYMBOL(drm_dp_mst_connector_late_register); > + > +/** > + * drm_dp_mst_connector_early_unregister() - Early MST connector > unregistration > + * @drm_connector: The MST connector > + * @port: The MST port for this connector > + * > + * Helper to unregister the remote aux device for this MST port, registered > by > + * drm_dp_mst_connector_late_register(). Drivers should call this from > their mst > + * connector's early_unregister hook. > + */ > +void drm_dp_mst_connector_early_unregister(struct drm_connector *connector, > + struct drm_dp_mst_port *port) > +{ > + DRM_DEBUG_KMS("unregistering %s remote bus for %s\n", > + port->aux.name, connector->kdev->kobj.name); > + drm_dp_aux_unregister_devnode(&port->aux); > +} > +EXPORT_SYMBOL(drm_dp_mst_connector_early_unregister); > + > static void drm_dp_add_port(struct drm_dp_mst_branch *mstb, > struct drm_device *dev, > struct drm_dp_link_addr_reply_port *port_msg) > @@ -1548,6 +1641,7 @@ static void drm_dp_add_port(struct drm_dp_mst_branch > *mstb, > port->mgr = mstb->mgr; > port->aux.name = "DPMST"; > port->aux.dev = dev->dev; > + port->aux.is_remote = true; > > /* > * Make sure the memory allocation for our parent branch stays > @@ -1816,7 +1910,6 @@ static bool drm_dp_validate_guid(struct > drm_dp_mst_topology_mgr *mgr, > return false; > } > > -#if 0 > static int build_dpcd_read(struct drm_dp_sideband_msg_tx *msg, u8 port_num, > u32 offset, u8 num_bytes) > { > struct drm_dp_sideband_msg_req_body req; > @@ -1829,7 +1922,6 @@ static int build_dpcd_read(struct > drm_dp_sideband_msg_tx *msg, u8 port_num, u32 > > return 0; > } > -#endif > > static int drm_dp_send_sideband_msg(struct drm_dp_mst_topology_mgr *mgr, > bool up, u8 *msg, int len) > @@ -2441,26 +2533,58 @@ int drm_dp_update_payload_part2(struct > drm_dp_mst_topology_mgr *mgr) > } > EXPORT_SYMBOL(drm_dp_update_payload_part2); > > -#if 0 /* unused as of yet */ > static int drm_dp_send_dpcd_read(struct drm_dp_mst_topology_mgr *mgr, > struct drm_dp_mst_port *port, > - int offset, int size) > + int offset, int size, u8 *bytes) > { > int len; > + int ret = 0; > struct drm_dp_sideband_msg_tx *txmsg; > + struct drm_dp_mst_branch *mstb; > + > + mstb = drm_dp_mst_topology_get_mstb_validated(mgr, port->parent); > + if (!mstb) > + return -EINVAL; > > txmsg = kzalloc(sizeof(*txmsg), GFP_KERNEL); > - if (!txmsg) > - return -ENOMEM; > + if (!txmsg) { > + ret = -ENOMEM; > + goto fail_put; > + } > > - len = build_dpcd_read(txmsg, port->port_num, 0, 8); > + len = build_dpcd_read(txmsg, port->port_num, offset, size); > txmsg->dst = port->parent; > > drm_dp_queue_down_tx(mgr, txmsg); > > - return 0; > + ret = drm_dp_mst_wait_tx_reply(mstb, txmsg); > + if (ret < 0) > + goto fail_free; > + > + /* DPCD read should never be NACKed */ > + if (txmsg->reply.reply_type == 1) { > + DRM_ERROR("mstb %p port %d: DPCD read on addr 0x%x for %d > bytes NAKed\n", > + mstb, port->port_num, offset, size); > + ret = -EIO; > + goto fail_free; > + } > + > + if (txmsg->reply.u.remote_dpcd_read_ack.num_bytes != size) { > + ret = -EPROTO; > + goto fail_free; > + } > + > + ret = min_t(size_t, txmsg->reply.u.remote_dpcd_read_ack.num_bytes, > + size); > + memcpy(bytes, txmsg->reply.u.remote_dpcd_read_ack.bytes, ret); > + > +fail_free: > + kfree(txmsg); > +fail_put: > + drm_dp_mst_topology_put_mstb(mstb); > + > + return ret; > } > -#endif > > static int drm_dp_send_dpcd_write(struct drm_dp_mst_topology_mgr *mgr, > struct drm_dp_mst_port *port, > @@ -2489,7 +2613,7 @@ static int drm_dp_send_dpcd_write(struct > drm_dp_mst_topology_mgr *mgr, > ret = drm_dp_mst_wait_tx_reply(mstb, txmsg); > if (ret > 0) { > if (txmsg->reply.reply_type == DP_SIDEBAND_REPLY_NAK) > - ret = -EINVAL; > + ret = -EIO; > else > ret = 0; > } > diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h > index 397896b5b21a..8364502f92cf 100644 > --- a/include/drm/drm_dp_helper.h > +++ b/include/drm/drm_dp_helper.h > @@ -1309,6 +1309,10 @@ struct drm_dp_aux { > * @cec: struct containing fields used for CEC-Tunneling-over-AUX. > */ > struct drm_dp_aux_cec cec; > + /** > + * @is_remote: Is this AUX CH actually using sideband messaging. > + */ > + bool is_remote; > }; > > ssize_t drm_dp_dpcd_read(struct drm_dp_aux *aux, unsigned int offset, > diff --git a/include/drm/drm_dp_mst_helper.h > b/include/drm/drm_dp_mst_helper.h > index 8c97a5f92c47..2ba6253ea6d3 100644 > --- a/include/drm/drm_dp_mst_helper.h > +++ b/include/drm/drm_dp_mst_helper.h > @@ -643,6 +643,17 @@ void drm_dp_mst_dump_topology(struct seq_file *m, > void drm_dp_mst_topology_mgr_suspend(struct drm_dp_mst_topology_mgr *mgr); > int __must_check > drm_dp_mst_topology_mgr_resume(struct drm_dp_mst_topology_mgr *mgr); > + > +ssize_t drm_dp_mst_dpcd_read(struct drm_dp_aux *aux, > + unsigned int offset, void *buffer, size_t size); > +ssize_t drm_dp_mst_dpcd_write(struct drm_dp_aux *aux, > + unsigned int offset, void *buffer, size_t size); > + > +int drm_dp_mst_connector_late_register(struct drm_connector *connector, > + struct drm_dp_mst_port *port); > +void drm_dp_mst_connector_early_unregister(struct drm_connector *connector, > + struct drm_dp_mst_port *port); > + > struct drm_dp_mst_topology_state *drm_atomic_get_mst_topology_state(struct > drm_atomic_state *state, > struct > drm_dp_mst_topology_mgr *mgr); > int __must_check
diff --git a/drivers/gpu/drm/drm_dp_aux_dev.c b/drivers/gpu/drm/drm_dp_aux_dev.c index 26e38dacf654..0cfb386754c3 100644 --- a/drivers/gpu/drm/drm_dp_aux_dev.c +++ b/drivers/gpu/drm/drm_dp_aux_dev.c @@ -37,6 +37,7 @@ #include <drm/drm_crtc.h> #include <drm/drm_dp_helper.h> +#include <drm/drm_dp_mst_helper.h> #include <drm/drm_print.h> #include "drm_crtc_helper_internal.h" @@ -162,7 +163,12 @@ static ssize_t auxdev_read_iter(struct kiocb *iocb, struct iov_iter *to) break; } - res = drm_dp_dpcd_read(aux_dev->aux, pos, buf, todo); + if (aux_dev->aux->is_remote) + res = drm_dp_mst_dpcd_read(aux_dev->aux, pos, buf, + todo); + else + res = drm_dp_dpcd_read(aux_dev->aux, pos, buf, todo); + if (res <= 0) break; @@ -209,7 +215,12 @@ static ssize_t auxdev_write_iter(struct kiocb *iocb, struct iov_iter *from) break; } - res = drm_dp_dpcd_write(aux_dev->aux, pos, buf, todo); + if (aux_dev->aux->is_remote) + res = drm_dp_mst_dpcd_write(aux_dev->aux, pos, buf, + todo); + else + res = drm_dp_dpcd_write(aux_dev->aux, pos, buf, todo); + if (res <= 0) break; diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index 0984b9a34d55..4733d3350ede 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c @@ -36,6 +36,8 @@ #include <drm/drm_print.h> #include <drm/drm_probe_helper.h> +#include "drm_crtc_helper_internal.h" + /** * DOC: dp mst helper * @@ -53,6 +55,9 @@ static int drm_dp_dpcd_write_payload(struct drm_dp_mst_topology_mgr *mgr, int id, struct drm_dp_payload *payload); +static int drm_dp_send_dpcd_read(struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_port *port, + int offset, int size, u8 *bytes); static int drm_dp_send_dpcd_write(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port, int offset, int size, u8 *bytes); @@ -1238,6 +1243,8 @@ static void drm_dp_destroy_port(struct kref *kref) struct drm_dp_mst_topology_mgr *mgr = port->mgr; if (!port->input) { + port->vcpi.num_slots = 0; + kfree(port->cached_edid); /* @@ -1483,6 +1490,52 @@ static bool drm_dp_port_setup_pdt(struct drm_dp_mst_port *port) return send_link; } +/** + * drm_dp_mst_dpcd_read() - read a series of bytes from the DPCD via sideband + * @aux: Fake sideband AUX CH + * @offset: address of the (first) register to read + * @buffer: buffer to store the register values + * @size: number of bytes in @buffer + * + * Performs the same functionality for remote devices via + * sideband messaging as drm_dp_dpcd_read() does for local + * devices via actual AUX CH. + * + * Return: Number of bytes read, or negative error code on failure. + */ +ssize_t drm_dp_mst_dpcd_read(struct drm_dp_aux *aux, + unsigned int offset, void *buffer, size_t size) +{ + struct drm_dp_mst_port *port = container_of(aux, struct drm_dp_mst_port, + aux); + + return drm_dp_send_dpcd_read(port->mgr, port, + offset, size, buffer); +} + +/** + * drm_dp_mst_dpcd_write() - write a series of bytes to the DPCD via sideband + * @aux: Fake sideband AUX CH + * @offset: address of the (first) register to write + * @buffer: buffer containing the values to write + * @size: number of bytes in @buffer + * + * Performs the same functionality for remote devices via + * sideband messaging as drm_dp_dpcd_write() does for local + * devices via actual AUX CH. + * + * Return: 0 on success, negative error code on failure. + */ +ssize_t drm_dp_mst_dpcd_write(struct drm_dp_aux *aux, + unsigned int offset, void *buffer, size_t size) +{ + struct drm_dp_mst_port *port = container_of(aux, struct drm_dp_mst_port, + aux); + + return drm_dp_send_dpcd_write(port->mgr, port, + offset, size, buffer); +} + static void drm_dp_check_mstb_guid(struct drm_dp_mst_branch *mstb, u8 *guid) { int ret; @@ -1526,6 +1579,46 @@ static void build_mst_prop_path(const struct drm_dp_mst_branch *mstb, strlcat(proppath, temp, proppath_size); } +/** + * drm_dp_mst_connector_late_register() - Late MST connector registration + * @drm_connector: The MST connector + * @port: The MST port for this connector + * + * Helper to register the remote aux device for this MST port. Drivers should + * call this from their mst connector's late_register hook to enable MST aux + * devices. + * + * Return: 0 on success, negative error code on failure. + */ +int drm_dp_mst_connector_late_register(struct drm_connector *connector, + struct drm_dp_mst_port *port) +{ + DRM_DEBUG_KMS("registering %s remote bus for %s\n", + port->aux.name, connector->kdev->kobj.name); + + port->aux.dev = connector->kdev; + return drm_dp_aux_register_devnode(&port->aux); +} +EXPORT_SYMBOL(drm_dp_mst_connector_late_register); + +/** + * drm_dp_mst_connector_early_unregister() - Early MST connector unregistration + * @drm_connector: The MST connector + * @port: The MST port for this connector + * + * Helper to unregister the remote aux device for this MST port, registered by + * drm_dp_mst_connector_late_register(). Drivers should call this from their mst + * connector's early_unregister hook. + */ +void drm_dp_mst_connector_early_unregister(struct drm_connector *connector, + struct drm_dp_mst_port *port) +{ + DRM_DEBUG_KMS("unregistering %s remote bus for %s\n", + port->aux.name, connector->kdev->kobj.name); + drm_dp_aux_unregister_devnode(&port->aux); +} +EXPORT_SYMBOL(drm_dp_mst_connector_early_unregister); + static void drm_dp_add_port(struct drm_dp_mst_branch *mstb, struct drm_device *dev, struct drm_dp_link_addr_reply_port *port_msg) @@ -1548,6 +1641,7 @@ static void drm_dp_add_port(struct drm_dp_mst_branch *mstb, port->mgr = mstb->mgr; port->aux.name = "DPMST"; port->aux.dev = dev->dev; + port->aux.is_remote = true; /* * Make sure the memory allocation for our parent branch stays @@ -1816,7 +1910,6 @@ static bool drm_dp_validate_guid(struct drm_dp_mst_topology_mgr *mgr, return false; } -#if 0 static int build_dpcd_read(struct drm_dp_sideband_msg_tx *msg, u8 port_num, u32 offset, u8 num_bytes) { struct drm_dp_sideband_msg_req_body req; @@ -1829,7 +1922,6 @@ static int build_dpcd_read(struct drm_dp_sideband_msg_tx *msg, u8 port_num, u32 return 0; } -#endif static int drm_dp_send_sideband_msg(struct drm_dp_mst_topology_mgr *mgr, bool up, u8 *msg, int len) @@ -2441,26 +2533,58 @@ int drm_dp_update_payload_part2(struct drm_dp_mst_topology_mgr *mgr) } EXPORT_SYMBOL(drm_dp_update_payload_part2); -#if 0 /* unused as of yet */ static int drm_dp_send_dpcd_read(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port, - int offset, int size) + int offset, int size, u8 *bytes) { int len; + int ret = 0; struct drm_dp_sideband_msg_tx *txmsg; + struct drm_dp_mst_branch *mstb; + + mstb = drm_dp_mst_topology_get_mstb_validated(mgr, port->parent); + if (!mstb) + return -EINVAL; txmsg = kzalloc(sizeof(*txmsg), GFP_KERNEL); - if (!txmsg) - return -ENOMEM; + if (!txmsg) { + ret = -ENOMEM; + goto fail_put; + } - len = build_dpcd_read(txmsg, port->port_num, 0, 8); + len = build_dpcd_read(txmsg, port->port_num, offset, size); txmsg->dst = port->parent; drm_dp_queue_down_tx(mgr, txmsg); - return 0; + ret = drm_dp_mst_wait_tx_reply(mstb, txmsg); + if (ret < 0) + goto fail_free; + + /* DPCD read should never be NACKed */ + if (txmsg->reply.reply_type == 1) { + DRM_ERROR("mstb %p port %d: DPCD read on addr 0x%x for %d bytes NAKed\n", + mstb, port->port_num, offset, size); + ret = -EIO; + goto fail_free; + } + + if (txmsg->reply.u.remote_dpcd_read_ack.num_bytes != size) { + ret = -EPROTO; + goto fail_free; + } + + ret = min_t(size_t, txmsg->reply.u.remote_dpcd_read_ack.num_bytes, + size); + memcpy(bytes, txmsg->reply.u.remote_dpcd_read_ack.bytes, ret); + +fail_free: + kfree(txmsg); +fail_put: + drm_dp_mst_topology_put_mstb(mstb); + + return ret; } -#endif static int drm_dp_send_dpcd_write(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port, @@ -2489,7 +2613,7 @@ static int drm_dp_send_dpcd_write(struct drm_dp_mst_topology_mgr *mgr, ret = drm_dp_mst_wait_tx_reply(mstb, txmsg); if (ret > 0) { if (txmsg->reply.reply_type == DP_SIDEBAND_REPLY_NAK) - ret = -EINVAL; + ret = -EIO; else ret = 0; } diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index 397896b5b21a..8364502f92cf 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -1309,6 +1309,10 @@ struct drm_dp_aux { * @cec: struct containing fields used for CEC-Tunneling-over-AUX. */ struct drm_dp_aux_cec cec; + /** + * @is_remote: Is this AUX CH actually using sideband messaging. + */ + bool is_remote; }; ssize_t drm_dp_dpcd_read(struct drm_dp_aux *aux, unsigned int offset, diff --git a/include/drm/drm_dp_mst_helper.h b/include/drm/drm_dp_mst_helper.h index 8c97a5f92c47..2ba6253ea6d3 100644 --- a/include/drm/drm_dp_mst_helper.h +++ b/include/drm/drm_dp_mst_helper.h @@ -643,6 +643,17 @@ void drm_dp_mst_dump_topology(struct seq_file *m, void drm_dp_mst_topology_mgr_suspend(struct drm_dp_mst_topology_mgr *mgr); int __must_check drm_dp_mst_topology_mgr_resume(struct drm_dp_mst_topology_mgr *mgr); + +ssize_t drm_dp_mst_dpcd_read(struct drm_dp_aux *aux, + unsigned int offset, void *buffer, size_t size); +ssize_t drm_dp_mst_dpcd_write(struct drm_dp_aux *aux, + unsigned int offset, void *buffer, size_t size); + +int drm_dp_mst_connector_late_register(struct drm_connector *connector, + struct drm_dp_mst_port *port); +void drm_dp_mst_connector_early_unregister(struct drm_connector *connector, + struct drm_dp_mst_port *port); + struct drm_dp_mst_topology_state *drm_atomic_get_mst_topology_state(struct drm_atomic_state *state, struct drm_dp_mst_topology_mgr *mgr); int __must_check