[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20191001113830.13028-13-mika.westerberg@linux.intel.com>
Date: Tue, 1 Oct 2019 14:38:20 +0300
From: Mika Westerberg <mika.westerberg@...ux.intel.com>
To: linux-usb@...r.kernel.org
Cc: Andreas Noever <andreas.noever@...il.com>,
Michael Jamet <michael.jamet@...el.com>,
Mika Westerberg <mika.westerberg@...ux.intel.com>,
Yehezkel Bernat <YehezkelShB@...il.com>,
Rajmohan Mani <rajmohan.mani@...el.com>,
Nicholas Johnson <nicholas.johnson-opensource@...look.com.au>,
Lukas Wunner <lukas@...ner.de>,
Greg Kroah-Hartman <gregkh@...uxfoundation.org>,
Alan Stern <stern@...land.harvard.edu>,
Mario.Limonciello@...l.com,
Anthony Wong <anthony.wong@...onical.com>,
linux-kernel@...r.kernel.org
Subject: [RFC PATCH 12/22] thunderbolt: Add Display Port CM handshake for Titan Ridge devices
Titan Ridge devices and newer need an additional connection manager
handshake in order to do proper Display Port tunneling so implement it
here.
Signed-off-by: Mika Westerberg <mika.westerberg@...ux.intel.com>
---
drivers/thunderbolt/tb_regs.h | 3 +++
drivers/thunderbolt/tunnel.c | 44 +++++++++++++++++++++++++++++++++++
2 files changed, 47 insertions(+)
diff --git a/drivers/thunderbolt/tb_regs.h b/drivers/thunderbolt/tb_regs.h
index 3a39490a954b..8d11b4a2d552 100644
--- a/drivers/thunderbolt/tb_regs.h
+++ b/drivers/thunderbolt/tb_regs.h
@@ -252,6 +252,9 @@ struct tb_regs_port_header {
#define ADP_DP_CS_3_HDPC BIT(9)
#define DP_LOCAL_CAP 0x04
#define DP_REMOTE_CAP 0x05
+#define DP_STATUS_CTRL 0x06
+#define DP_STATUS_CTRL_CMHS BIT(25)
+#define DP_STATUS_CTRL_UF BIT(26)
/* PCIe adapter registers */
#define ADP_PCIE_CS_0 0x00
diff --git a/drivers/thunderbolt/tunnel.c b/drivers/thunderbolt/tunnel.c
index 3353396e0806..369800110e5e 100644
--- a/drivers/thunderbolt/tunnel.c
+++ b/drivers/thunderbolt/tunnel.c
@@ -6,6 +6,7 @@
* Copyright (C) 2019, Intel Corporation
*/
+#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/list.h>
@@ -242,6 +243,41 @@ struct tb_tunnel *tb_tunnel_alloc_pci(struct tb *tb, struct tb_port *up,
return tunnel;
}
+static int tb_dp_cm_handshake(struct tb_port *in, struct tb_port *out)
+{
+ int timeout = 10;
+ u32 val;
+ int ret;
+
+ /* Both ends need to support this */
+ if (!tb_switch_is_tr(in->sw) || !tb_switch_is_tr(out->sw))
+ return 0;
+
+ ret = tb_port_read(out, &val, TB_CFG_PORT,
+ out->cap_adap + DP_STATUS_CTRL, 1);
+ if (ret)
+ return ret;
+
+ val |= DP_STATUS_CTRL_UF | DP_STATUS_CTRL_CMHS;
+
+ ret = tb_port_write(out, &val, TB_CFG_PORT,
+ out->cap_adap + DP_STATUS_CTRL, 1);
+ if (ret)
+ return ret;
+
+ do {
+ ret = tb_port_read(out, &val, TB_CFG_PORT,
+ out->cap_adap + DP_STATUS_CTRL, 1);
+ if (ret)
+ return ret;
+ if (!(val & DP_STATUS_CTRL_CMHS))
+ return 0;
+ usleep_range(10, 100);
+ } while (timeout--);
+
+ return -ETIMEDOUT;
+}
+
static int tb_dp_xchg_caps(struct tb_tunnel *tunnel)
{
struct tb_port *out = tunnel->dst_port;
@@ -256,6 +292,14 @@ static int tb_dp_xchg_caps(struct tb_tunnel *tunnel)
if (in->sw->generation < 2 || out->sw->generation < 2)
return 0;
+ /*
+ * Perform connection manager handshake between IN and OUT ports
+ * before capabilities exchange can take place.
+ */
+ ret = tb_dp_cm_handshake(in, out);
+ if (ret)
+ return ret;
+
/* Read both DP_LOCAL_CAP registers */
ret = tb_port_read(in, &in_dp_cap, TB_CFG_PORT,
in->cap_adap + DP_LOCAL_CAP, 1);
--
2.23.0
Powered by blists - more mailing lists