thunderbolt: Changes for v5.18 merge window

This includes following Thunderbolt/USB4 changes for the v5.18 merge
 window:
 
   * Improvements for Intel Alpine and Titan Ridge support
   * Replace acpi_bus_get_device() with acpi_fetch_acpi_dev()
   * Improvements around DROM handling on AMD hardware
   * A couple of cleanups.
 
 All these have been in linux-next with no reported issues.
 -----BEGIN PGP SIGNATURE-----
 
 iQJUBAABCgA+FiEEVTdhRGBbNzLrSUBaAP2fSd+ZWKAFAmInSEQgHG1pa2Eud2Vz
 dGVyYmVyZ0BsaW51eC5pbnRlbC5jb20ACgkQAP2fSd+ZWKDsFw//dj4zKf9sng6U
 k7nkklreknVUpzbHyf/vnQeY0BXW3dCKJDj3TCmsXror/rREeBC373GAgKC35poQ
 ndPQirzfb7oksZ6d2UsBrXjcEwzsL+0Uv0PnlE2Xb79wT9X/1PCYjMkTIsbYKJcE
 U63cf5iy/4zBfrvCmYb78CuUIJAGYZ/lhFLp4zsxC+b8zwTyZhupwp9IcTLMm4ec
 4MeDIt6hqM1NyvteVAPTmwOwxBd1DUiW6RS5VxweS9Xu4UOGd/u8Df82kTyYWHGT
 uyhkjOfmrsS92ezGP6v4fo6t+eQShUfzDJS6Za48KpZTZqVXrMmbb83BK6Ni+EOJ
 ly0NLsLPBwggVHpifMdMZH5e2FQOJDouHcD8p370+2BKVncm8xgYFUHGYA3X2+Zm
 OLfm54ZNbB675j5nzZf0m6p9HRH2XcwmR341kKJEx91JdUy8iBAM45LT8ZfRy4Ar
 rATgHeckbvITrn/o0MG569fYC1mxV9lYL+7mGieoFV8C6SajeSdWTH+m9E36ifFl
 W9sKxBzhCtQdRFxzO/OzvXZdzkOuLkIfMmoUxI/Nuf+TBAyaJoAEnr3tGrG9zPTy
 dp6ZCvHpr3f57zEW3IiTIT3RGJ95gZ7sGcwlmSDyqxuwAdf49q2Ah+Sp+RvjsUiQ
 HyPr5o3MTDY62OqO8l0rWXwvt0epArY=
 =eAtZ
 -----END PGP SIGNATURE-----

Merge tag 'thunderbolt-for-v5.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/westeri/thunderbolt into usb-next

Mika writes:

thunderbolt: Changes for v5.18 merge window

This includes following Thunderbolt/USB4 changes for the v5.18 merge
window:

  * Improvements for Intel Alpine and Titan Ridge support
  * Replace acpi_bus_get_device() with acpi_fetch_acpi_dev()
  * Improvements around DROM handling on AMD hardware
  * A couple of cleanups.

All these have been in linux-next with no reported issues.

* tag 'thunderbolt-for-v5.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/westeri/thunderbolt:
  thunderbolt: Rename EEPROM handling bits to match USB4 spec
  thunderbolt: Clarify register definitions for `tb_cap_plug_events`
  thunderbolt: Do not make DROM read success compulsory
  thunderbolt: Do not resume routers if UID is not set
  thunderbolt: Retry DROM reads for more failure scenarios
  thunderbolt: Replace acpi_bus_get_device()
  thunderbolt: Add internal xHCI connect flows for Thunderbolt 3 devices
  thunderbolt: Add missing device ID to tb_switch_is_alpine_ridge()
  thunderbolt: Disable LTTPR on Intel Titan Ridge
  thunderbolt: Remove useless DMA-32 fallback configuration
This commit is contained in:
Greg Kroah-Hartman 2022-03-11 16:31:12 +01:00
commit 7d2c8a13c9
9 changed files with 265 additions and 40 deletions

View file

@ -14,15 +14,15 @@
static acpi_status tb_acpi_add_link(acpi_handle handle, u32 level, void *data,
void **return_value)
{
struct acpi_device *adev = acpi_fetch_acpi_dev(handle);
struct fwnode_reference_args args;
struct fwnode_handle *fwnode;
struct tb_nhi *nhi = data;
struct acpi_device *adev;
struct pci_dev *pdev;
struct device *dev;
int ret;
if (acpi_bus_get_device(handle, &adev))
if (!adev)
return AE_OK;
fwnode = acpi_fwnode_handle(adev);

View file

@ -17,7 +17,7 @@
*/
static int tb_eeprom_ctl_write(struct tb_switch *sw, struct tb_eeprom_ctl *ctl)
{
return tb_sw_write(sw, ctl, TB_CFG_SWITCH, sw->cap_plug_events + 4, 1);
return tb_sw_write(sw, ctl, TB_CFG_SWITCH, sw->cap_plug_events + ROUTER_CS_4, 1);
}
/*
@ -25,7 +25,7 @@ static int tb_eeprom_ctl_write(struct tb_switch *sw, struct tb_eeprom_ctl *ctl)
*/
static int tb_eeprom_ctl_read(struct tb_switch *sw, struct tb_eeprom_ctl *ctl)
{
return tb_sw_read(sw, ctl, TB_CFG_SWITCH, sw->cap_plug_events + 4, 1);
return tb_sw_read(sw, ctl, TB_CFG_SWITCH, sw->cap_plug_events + ROUTER_CS_4, 1);
}
enum tb_eeprom_transfer {
@ -46,18 +46,18 @@ static int tb_eeprom_active(struct tb_switch *sw, bool enable)
if (res)
return res;
if (enable) {
ctl.access_high = 1;
ctl.bit_banging_enable = 1;
res = tb_eeprom_ctl_write(sw, &ctl);
if (res)
return res;
ctl.access_low = 0;
ctl.fl_cs = 0;
return tb_eeprom_ctl_write(sw, &ctl);
} else {
ctl.access_low = 1;
ctl.fl_cs = 1;
res = tb_eeprom_ctl_write(sw, &ctl);
if (res)
return res;
ctl.access_high = 0;
ctl.bit_banging_enable = 0;
return tb_eeprom_ctl_write(sw, &ctl);
}
}
@ -65,8 +65,8 @@ static int tb_eeprom_active(struct tb_switch *sw, bool enable)
/*
* tb_eeprom_transfer - transfer one bit
*
* If TB_EEPROM_IN is passed, then the bit can be retrieved from ctl->data_in.
* If TB_EEPROM_OUT is passed, then ctl->data_out will be written.
* If TB_EEPROM_IN is passed, then the bit can be retrieved from ctl->fl_do.
* If TB_EEPROM_OUT is passed, then ctl->fl_di will be written.
*/
static int tb_eeprom_transfer(struct tb_switch *sw, struct tb_eeprom_ctl *ctl,
enum tb_eeprom_transfer direction)
@ -77,7 +77,7 @@ static int tb_eeprom_transfer(struct tb_switch *sw, struct tb_eeprom_ctl *ctl,
if (res)
return res;
}
ctl->clock = 1;
ctl->fl_sk = 1;
res = tb_eeprom_ctl_write(sw, ctl);
if (res)
return res;
@ -86,7 +86,7 @@ static int tb_eeprom_transfer(struct tb_switch *sw, struct tb_eeprom_ctl *ctl,
if (res)
return res;
}
ctl->clock = 0;
ctl->fl_sk = 0;
return tb_eeprom_ctl_write(sw, ctl);
}
@ -101,7 +101,7 @@ static int tb_eeprom_out(struct tb_switch *sw, u8 val)
if (res)
return res;
for (i = 0; i < 8; i++) {
ctl.data_out = val & 0x80;
ctl.fl_di = val & 0x80;
res = tb_eeprom_transfer(sw, &ctl, TB_EEPROM_OUT);
if (res)
return res;
@ -126,7 +126,7 @@ static int tb_eeprom_in(struct tb_switch *sw, u8 *val)
res = tb_eeprom_transfer(sw, &ctl, TB_EEPROM_IN);
if (res)
return res;
*val |= ctl.data_in;
*val |= ctl.fl_do;
}
return 0;
}
@ -553,9 +553,9 @@ static int tb_drom_parse(struct tb_switch *sw)
crc = tb_crc8((u8 *) &header->uid, 8);
if (crc != header->uid_crc8) {
tb_sw_warn(sw,
"DROM UID CRC8 mismatch (expected: %#x, got: %#x), aborting\n",
"DROM UID CRC8 mismatch (expected: %#x, got: %#x)\n",
header->uid_crc8, crc);
return -EINVAL;
return -EILSEQ;
}
if (!sw->uid)
sw->uid = header->uid;
@ -654,6 +654,7 @@ int tb_drom_read(struct tb_switch *sw)
sw->drom = kzalloc(size, GFP_KERNEL);
if (!sw->drom)
return -ENOMEM;
read:
res = tb_drom_read_n(sw, 0, sw->drom, size);
if (res)
goto err;
@ -662,7 +663,11 @@ int tb_drom_read(struct tb_switch *sw)
header = (void *) sw->drom;
if (header->data_len + TB_DROM_DATA_START != size) {
tb_sw_warn(sw, "drom size mismatch, aborting\n");
tb_sw_warn(sw, "drom size mismatch\n");
if (retries--) {
msleep(100);
goto read;
}
goto err;
}
@ -683,11 +688,9 @@ int tb_drom_read(struct tb_switch *sw)
/* If the DROM parsing fails, wait a moment and retry once */
if (res == -EILSEQ && retries--) {
tb_sw_warn(sw, "parsing DROM failed, retrying\n");
tb_sw_warn(sw, "parsing DROM failed\n");
msleep(100);
res = tb_drom_read_n(sw, 0, sw->drom, size);
if (!res)
goto parse;
goto read;
}
if (!res)

View file

@ -217,6 +217,116 @@ bool tb_lc_is_clx_supported(struct tb_port *port)
return !!(val & TB_LC_LINK_ATTR_CPS);
}
/**
* tb_lc_is_usb_plugged() - Is there USB device connected to port
* @port: Device router lane 0 adapter
*
* Returns true if the @port has USB type-C device connected.
*/
bool tb_lc_is_usb_plugged(struct tb_port *port)
{
struct tb_switch *sw = port->sw;
int cap, ret;
u32 val;
if (sw->generation != 3)
return false;
cap = find_port_lc_cap(port);
if (cap < 0)
return false;
ret = tb_sw_read(sw, &val, TB_CFG_SWITCH, cap + TB_LC_CS_42, 1);
if (ret)
return false;
return !!(val & TB_LC_CS_42_USB_PLUGGED);
}
/**
* tb_lc_is_xhci_connected() - Is the internal xHCI connected
* @port: Device router lane 0 adapter
*
* Returns true if the internal xHCI has been connected to @port.
*/
bool tb_lc_is_xhci_connected(struct tb_port *port)
{
struct tb_switch *sw = port->sw;
int cap, ret;
u32 val;
if (sw->generation != 3)
return false;
cap = find_port_lc_cap(port);
if (cap < 0)
return false;
ret = tb_sw_read(sw, &val, TB_CFG_SWITCH, cap + TB_LC_LINK_REQ, 1);
if (ret)
return false;
return !!(val & TB_LC_LINK_REQ_XHCI_CONNECT);
}
static int __tb_lc_xhci_connect(struct tb_port *port, bool connect)
{
struct tb_switch *sw = port->sw;
int cap, ret;
u32 val;
if (sw->generation != 3)
return -EINVAL;
cap = find_port_lc_cap(port);
if (cap < 0)
return cap;
ret = tb_sw_read(sw, &val, TB_CFG_SWITCH, cap + TB_LC_LINK_REQ, 1);
if (ret)
return ret;
if (connect)
val |= TB_LC_LINK_REQ_XHCI_CONNECT;
else
val &= ~TB_LC_LINK_REQ_XHCI_CONNECT;
return tb_sw_write(sw, &val, TB_CFG_SWITCH, cap + TB_LC_LINK_REQ, 1);
}
/**
* tb_lc_xhci_connect() - Connect internal xHCI
* @port: Device router lane 0 adapter
*
* Tells LC to connect the internal xHCI to @port. Returns %0 on success
* and negative errno in case of failure. Can be called for Thunderbolt 3
* routers only.
*/
int tb_lc_xhci_connect(struct tb_port *port)
{
int ret;
ret = __tb_lc_xhci_connect(port, true);
if (ret)
return ret;
tb_port_dbg(port, "xHCI connected\n");
return 0;
}
/**
* tb_lc_xhci_disconnect() - Disconnect internal xHCI
* @port: Device router lane 0 adapter
*
* Tells LC to disconnect the internal xHCI from @port. Can be called
* for Thunderbolt 3 routers only.
*/
void tb_lc_xhci_disconnect(struct tb_port *port)
{
__tb_lc_xhci_connect(port, false);
tb_port_dbg(port, "xHCI disconnected\n");
}
static int tb_lc_set_wake_one(struct tb_switch *sw, unsigned int offset,
unsigned int flags)
{

View file

@ -13,6 +13,7 @@
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/pci.h>
#include <linux/dma-mapping.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/delay.h>
@ -1229,8 +1230,6 @@ static int nhi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
spin_lock_init(&nhi->lock);
res = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
if (res)
res = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
if (res) {
dev_err(&pdev->dev, "failed to set DMA mask\n");
return res;

View file

@ -1528,7 +1528,13 @@ static int tb_plug_events_active(struct tb_switch *sw, bool active)
case PCI_DEVICE_ID_INTEL_PORT_RIDGE:
break;
default:
data |= 4;
/*
* Skip Alpine Ridge, it needs to have vendor
* specific USB hotplug event enabled for the
* internal xHCI to work.
*/
if (!tb_switch_is_alpine_ridge(sw))
data |= TB_PLUG_EVENTS_USB_DISABLE;
}
} else {
data = data | 0x7c;
@ -2778,10 +2784,8 @@ int tb_switch_add(struct tb_switch *sw)
/* read drom */
ret = tb_drom_read(sw);
if (ret) {
dev_err(&sw->dev, "reading DROM failed\n");
return ret;
}
if (ret)
dev_warn(&sw->dev, "reading DROM failed: %d\n", ret);
tb_sw_dbg(sw, "uid: %#llx\n", sw->uid);
tb_check_quirks(sw);
@ -2974,6 +2978,10 @@ int tb_switch_resume(struct tb_switch *sw)
return err;
}
/* We don't have any way to confirm this was the same device */
if (!sw->uid)
return -ENODEV;
if (tb_switch_is_usb4(sw))
err = usb4_switch_read_uid(sw, &uid);
else
@ -3689,3 +3697,66 @@ int tb_switch_pcie_l1_enable(struct tb_switch *sw)
/* Write to Upstream PCIe bridge #0 aka Up0 */
return tb_switch_pcie_bridge_write(sw, 0, 0x143, 0x0c5806b1);
}
/**
* tb_switch_xhci_connect() - Connect internal xHCI
* @sw: Router whose xHCI to connect
*
* Can be called to any router. For Alpine Ridge and Titan Ridge
* performs special flows that bring the xHCI functional for any device
* connected to the type-C port. Call only after PCIe tunnel has been
* established. The function only does the connect if not done already
* so can be called several times for the same router.
*/
int tb_switch_xhci_connect(struct tb_switch *sw)
{
bool usb_port1, usb_port3, xhci_port1, xhci_port3;
struct tb_port *port1, *port3;
int ret;
port1 = &sw->ports[1];
port3 = &sw->ports[3];
if (tb_switch_is_alpine_ridge(sw)) {
usb_port1 = tb_lc_is_usb_plugged(port1);
usb_port3 = tb_lc_is_usb_plugged(port3);
xhci_port1 = tb_lc_is_xhci_connected(port1);
xhci_port3 = tb_lc_is_xhci_connected(port3);
/* Figure out correct USB port to connect */
if (usb_port1 && !xhci_port1) {
ret = tb_lc_xhci_connect(port1);
if (ret)
return ret;
}
if (usb_port3 && !xhci_port3)
return tb_lc_xhci_connect(port3);
} else if (tb_switch_is_titan_ridge(sw)) {
ret = tb_lc_xhci_connect(port1);
if (ret)
return ret;
return tb_lc_xhci_connect(port3);
}
return 0;
}
/**
* tb_switch_xhci_disconnect() - Disconnect internal xHCI
* @sw: Router whose xHCI to disconnect
*
* The opposite of tb_switch_xhci_connect(). Disconnects xHCI on both
* ports.
*/
void tb_switch_xhci_disconnect(struct tb_switch *sw)
{
if (sw->generation == 3) {
struct tb_port *port1 = &sw->ports[1];
struct tb_port *port3 = &sw->ports[3];
tb_lc_xhci_disconnect(port1);
tb_port_dbg(port1, "disconnected xHCI\n");
tb_lc_xhci_disconnect(port3);
tb_port_dbg(port3, "disconnected xHCI\n");
}
}

View file

@ -1054,6 +1054,8 @@ static int tb_disconnect_pci(struct tb *tb, struct tb_switch *sw)
if (WARN_ON(!tunnel))
return -ENODEV;
tb_switch_xhci_disconnect(sw);
tb_tunnel_deactivate(tunnel);
list_del(&tunnel->list);
tb_tunnel_free(tunnel);
@ -1099,6 +1101,9 @@ static int tb_tunnel_pci(struct tb *tb, struct tb_switch *sw)
if (tb_switch_pcie_l1_enable(sw))
tb_sw_warn(sw, "failed to enable PCIe L1 for Titan Ridge\n");
if (tb_switch_xhci_connect(sw))
tb_sw_warn(sw, "failed to connect xHCI\n");
list_add_tail(&tunnel->list, &tcm->tunnel_list);
return 0;
}
@ -1256,12 +1261,18 @@ static void tb_handle_hotplug(struct work_struct *work)
tb_port_unconfigure_xdomain(port);
} else if (tb_port_is_dpout(port) || tb_port_is_dpin(port)) {
tb_dp_resource_unavailable(tb, port);
} else if (!port->port) {
tb_sw_dbg(sw, "xHCI disconnect request\n");
tb_switch_xhci_disconnect(sw);
} else {
tb_port_dbg(port,
"got unplug event for disconnected port, ignoring\n");
}
} else if (port->remote) {
tb_port_dbg(port, "got plug event for connected port, ignoring\n");
} else if (!port->port && sw->authorized) {
tb_sw_dbg(sw, "xHCI connect request\n");
tb_switch_xhci_connect(sw);
} else {
if (tb_port_is_null(port)) {
tb_port_dbg(port, "hotplug: scanning\n");

View file

@ -855,6 +855,7 @@ static inline bool tb_switch_is_alpine_ridge(const struct tb_switch *sw)
if (sw->config.vendor_id == PCI_VENDOR_ID_INTEL) {
switch (sw->config.device_id) {
case PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_2C_BRIDGE:
case PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_4C_BRIDGE:
case PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_LP_BRIDGE:
case PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_C_4C_BRIDGE:
case PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_C_2C_BRIDGE:
@ -987,6 +988,9 @@ int tb_switch_mask_clx_objections(struct tb_switch *sw);
int tb_switch_pcie_l1_enable(struct tb_switch *sw);
int tb_switch_xhci_connect(struct tb_switch *sw);
void tb_switch_xhci_disconnect(struct tb_switch *sw);
int tb_wait_for_port(struct tb_port *port, bool wait_if_unplugged);
int tb_port_add_nfc_credits(struct tb_port *port, int credits);
int tb_port_clear_counter(struct tb_port *port, int counter);
@ -1081,6 +1085,10 @@ int tb_lc_configure_xdomain(struct tb_port *port);
void tb_lc_unconfigure_xdomain(struct tb_port *port);
int tb_lc_start_lane_initialization(struct tb_port *port);
bool tb_lc_is_clx_supported(struct tb_port *port);
bool tb_lc_is_usb_plugged(struct tb_port *port);
bool tb_lc_is_xhci_connected(struct tb_port *port);
int tb_lc_xhci_connect(struct tb_port *port);
void tb_lc_xhci_disconnect(struct tb_port *port);
int tb_lc_set_wake(struct tb_switch *sw, unsigned int flags);
int tb_lc_set_sleep(struct tb_switch *sw);
bool tb_lc_lane_bonding_possible(struct tb_switch *sw);

View file

@ -133,11 +133,11 @@ struct tb_cap_phy {
} __packed;
struct tb_eeprom_ctl {
bool clock:1; /* send pulse to transfer one bit */
bool access_low:1; /* set to 0 before access */
bool data_out:1; /* to eeprom */
bool data_in:1; /* from eeprom */
bool access_high:1; /* set to 1 before access */
bool fl_sk:1; /* send pulse to transfer one bit */
bool fl_cs:1; /* set to 0 before access */
bool fl_di:1; /* to eeprom */
bool fl_do:1; /* from eeprom */
bool bit_banging_enable:1; /* set to 1 before access */
bool not_present:1; /* should be 0 */
bool unknown1:1;
bool present:1; /* should be 1 */
@ -146,14 +146,14 @@ struct tb_eeprom_ctl {
struct tb_cap_plug_events {
struct tb_cap_extended_short cap_header;
u32 __unknown1:2;
u32 plug_events:5;
u32 __unknown2:25;
u32 __unknown3;
u32 __unknown4;
u32 __unknown1:2; /* VSC_CS_1 */
u32 plug_events:5; /* VSC_CS_1 */
u32 __unknown2:25; /* VSC_CS_1 */
u32 vsc_cs_2;
u32 vsc_cs_3;
struct tb_eeprom_ctl eeprom_ctl;
u32 __unknown5[7];
u32 drom_offset; /* 32 bit register, but eeprom addresses are 16 bit */
u32 __unknown5[7]; /* VSC_CS_5 -> VSC_CS_11 */
u32 drom_offset; /* VSC_CS_12: 32 bit register, but eeprom addresses are 16 bit */
} __packed;
/* device headers */
@ -389,6 +389,7 @@ struct tb_regs_port_header {
#define DP_COMMON_CAP_1_LANE 0x0
#define DP_COMMON_CAP_2_LANES 0x1
#define DP_COMMON_CAP_4_LANES 0x2
#define DP_COMMON_CAP_LTTPR_NS BIT(27)
#define DP_COMMON_CAP_DPRX_DONE BIT(31)
/* PCIe adapter registers */
@ -462,6 +463,12 @@ struct tb_regs_hop {
#define TMU_ADP_CS_6_DISABLE_TMU_OBJ_CL2 BIT(3)
/* Plug Events registers */
#define TB_PLUG_EVENTS_USB_DISABLE BIT(2)
#define TB_PLUG_EVENTS_CS_1_LANE_DISABLE BIT(3)
#define TB_PLUG_EVENTS_CS_1_DPOUT_DISABLE BIT(4)
#define TB_PLUG_EVENTS_CS_1_LOW_DPIN_DISABLE BIT(5)
#define TB_PLUG_EVENTS_CS_1_HIGH_DPIN_DISABLE BIT(6)
#define TB_PLUG_EVENTS_PCIE_WR_DATA 0x1b
#define TB_PLUG_EVENTS_PCIE_CMD 0x1c
#define TB_PLUG_EVENTS_PCIE_CMD_DW_OFFSET_MASK GENMASK(9, 0)
@ -501,6 +508,9 @@ struct tb_regs_hop {
#define TB_LC_POWER 0x740
/* Link controller registers */
#define TB_LC_CS_42 0x2a
#define TB_LC_CS_42_USB_PLUGGED BIT(31)
#define TB_LC_PORT_ATTR 0x8d
#define TB_LC_PORT_ATTR_BE BIT(12)
@ -521,4 +531,7 @@ struct tb_regs_hop {
#define TB_LC_LINK_ATTR 0x97
#define TB_LC_LINK_ATTR_CPS BIT(18)
#define TB_LC_LINK_REQ 0xad
#define TB_LC_LINK_REQ_XHCI_CONNECT BIT(31)
#endif

View file

@ -580,6 +580,16 @@ static int tb_dp_xchg_caps(struct tb_tunnel *tunnel)
out_dp_cap = tb_dp_cap_set_lanes(out_dp_cap, new_lanes);
}
/*
* Titan Ridge does not disable AUX timers when it gets
* SET_CONFIG with SET_LTTPR_MODE set. This causes problems with
* DP tunneling.
*/
if (tb_route(out->sw) && tb_switch_is_titan_ridge(out->sw)) {
out_dp_cap |= DP_COMMON_CAP_LTTPR_NS;
tb_port_dbg(out, "disabling LTTPR\n");
}
return tb_port_write(in, &out_dp_cap, TB_CFG_PORT,
in->cap_adap + DP_REMOTE_CAP, 1);
}