mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-12 21:57:43 +00:00
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:
commit
7d2c8a13c9
9 changed files with 265 additions and 40 deletions
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue