summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/drm_dp_mst_topology.c
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2020-09-23 09:49:48 +1000
committerDave Airlie <airlied@redhat.com>2020-09-23 09:52:24 +1000
commit6ea6be77086f23d4b346c9946dae24593befda2e (patch)
treedc3926a543ed2b8270aa111d97ee603970560eda /drivers/gpu/drm/drm_dp_mst_topology.c
parentfc88fef916e8971eefeacc62241b7408b7e7939d (diff)
parent089d83418914abd4d908db117d9a3eca7f51a68c (diff)
Merge tag 'drm-misc-next-2020-09-21' of git://anongit.freedesktop.org/drm/drm-misc into drm-next
drm-misc-next for 5.10: UAPI Changes: Cross-subsystem Changes: - virtio: Merged a PR for patches that will affect drm/virtio Core Changes: - dev: More devm_drm convertions and removal of drm_dev_init - atomic: Split out drm_atomic_helper_calc_timestamping_constants of drm_atomic_helper_update_legacy_modeset_state - ttm: More rework Driver Changes: - i915: selftests improvements - panfrost: support for Amlogic SoC - vc4: one fix - tree-wide: conversions to devm_drm_dev_alloc, - ast: simplifications of the atomic modesetting code - panfrost: multiple fixes - vc4: multiple fixes Signed-off-by: Dave Airlie <airlied@redhat.com> From: Maxime Ripard <maxime@cerno.tech> Link: https://patchwork.freedesktop.org/patch/msgid/20200921152956.2gxnsdgxmwhvjyut@gilmour.lan
Diffstat (limited to 'drivers/gpu/drm/drm_dp_mst_topology.c')
-rw-r--r--drivers/gpu/drm/drm_dp_mst_topology.c106
1 files changed, 90 insertions, 16 deletions
diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c
index 54864400015d..e87542533640 100644
--- a/drivers/gpu/drm/drm_dp_mst_topology.c
+++ b/drivers/gpu/drm/drm_dp_mst_topology.c
@@ -1039,6 +1039,8 @@ static bool drm_dp_sideband_parse_reply(struct drm_dp_sideband_msg_rx *raw,
return drm_dp_sideband_parse_remote_dpcd_write(raw, msg);
case DP_REMOTE_I2C_READ:
return drm_dp_sideband_parse_remote_i2c_read_ack(raw, msg);
+ case DP_REMOTE_I2C_WRITE:
+ return true; /* since there's nothing to parse */
case DP_ENUM_PATH_RESOURCES:
return drm_dp_sideband_parse_enum_path_resources_ack(raw, msg);
case DP_ALLOCATE_PAYLOAD:
@@ -5499,29 +5501,29 @@ static bool remote_i2c_read_ok(const struct i2c_msg msgs[], int num)
msgs[num - 1].len <= 0xff;
}
-/* I2C device */
-static int drm_dp_mst_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
- int num)
+static bool remote_i2c_write_ok(const struct i2c_msg msgs[], int num)
+{
+ int i;
+
+ for (i = 0; i < num - 1; i++) {
+ if (msgs[i].flags & I2C_M_RD || !(msgs[i].flags & I2C_M_STOP) ||
+ msgs[i].len > 0xff)
+ return false;
+ }
+
+ return !(msgs[num - 1].flags & I2C_M_RD) && msgs[num - 1].len <= 0xff;
+}
+
+static int drm_dp_mst_i2c_read(struct drm_dp_mst_branch *mstb,
+ struct drm_dp_mst_port *port,
+ struct i2c_msg *msgs, int num)
{
- struct drm_dp_aux *aux = adapter->algo_data;
- struct drm_dp_mst_port *port = container_of(aux, struct drm_dp_mst_port, aux);
- struct drm_dp_mst_branch *mstb;
struct drm_dp_mst_topology_mgr *mgr = port->mgr;
unsigned int i;
struct drm_dp_sideband_msg_req_body msg;
struct drm_dp_sideband_msg_tx *txmsg = NULL;
int ret;
- mstb = drm_dp_mst_topology_get_mstb_validated(mgr, port->parent);
- if (!mstb)
- return -EREMOTEIO;
-
- if (!remote_i2c_read_ok(msgs, num)) {
- DRM_DEBUG_KMS("Unsupported I2C transaction for MST device\n");
- ret = -EIO;
- goto out;
- }
-
memset(&msg, 0, sizeof(msg));
msg.req_type = DP_REMOTE_I2C_READ;
msg.u.i2c_read.num_transactions = num - 1;
@@ -5562,6 +5564,78 @@ static int drm_dp_mst_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs
}
out:
kfree(txmsg);
+ return ret;
+}
+
+static int drm_dp_mst_i2c_write(struct drm_dp_mst_branch *mstb,
+ struct drm_dp_mst_port *port,
+ struct i2c_msg *msgs, int num)
+{
+ struct drm_dp_mst_topology_mgr *mgr = port->mgr;
+ unsigned int i;
+ struct drm_dp_sideband_msg_req_body msg;
+ struct drm_dp_sideband_msg_tx *txmsg = NULL;
+ int ret;
+
+ txmsg = kzalloc(sizeof(*txmsg), GFP_KERNEL);
+ if (!txmsg) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ for (i = 0; i < num; i++) {
+ memset(&msg, 0, sizeof(msg));
+ msg.req_type = DP_REMOTE_I2C_WRITE;
+ msg.u.i2c_write.port_number = port->port_num;
+ msg.u.i2c_write.write_i2c_device_id = msgs[i].addr;
+ msg.u.i2c_write.num_bytes = msgs[i].len;
+ msg.u.i2c_write.bytes = msgs[i].buf;
+
+ memset(txmsg, 0, sizeof(*txmsg));
+ txmsg->dst = mstb;
+
+ drm_dp_encode_sideband_req(&msg, txmsg);
+ drm_dp_queue_down_tx(mgr, txmsg);
+
+ ret = drm_dp_mst_wait_tx_reply(mstb, txmsg);
+ if (ret > 0) {
+ if (txmsg->reply.reply_type == DP_SIDEBAND_REPLY_NAK) {
+ ret = -EREMOTEIO;
+ goto out;
+ }
+ } else {
+ goto out;
+ }
+ }
+ ret = num;
+out:
+ kfree(txmsg);
+ return ret;
+}
+
+/* I2C device */
+static int drm_dp_mst_i2c_xfer(struct i2c_adapter *adapter,
+ struct i2c_msg *msgs, int num)
+{
+ struct drm_dp_aux *aux = adapter->algo_data;
+ struct drm_dp_mst_port *port =
+ container_of(aux, struct drm_dp_mst_port, aux);
+ struct drm_dp_mst_branch *mstb;
+ struct drm_dp_mst_topology_mgr *mgr = port->mgr;
+ int ret;
+
+ mstb = drm_dp_mst_topology_get_mstb_validated(mgr, port->parent);
+ if (!mstb)
+ return -EREMOTEIO;
+
+ if (remote_i2c_read_ok(msgs, num)) {
+ ret = drm_dp_mst_i2c_read(mstb, port, msgs, num);
+ } else if (remote_i2c_write_ok(msgs, num)) {
+ ret = drm_dp_mst_i2c_write(mstb, port, msgs, num);
+ } else {
+ DRM_DEBUG_KMS("Unsupported I2C transaction for MST device\n");
+ ret = -EIO;
+ }
+
drm_dp_mst_topology_put_mstb(mstb);
return ret;
}