thunderbolt: Add additional USB4 port operations for retimer access

When accessing retimers when there is no cable connected we are going to
need additional USB4 port operations. First the port needs to be put
into offline mode, and then the sideband channel transactions must be
enabled on the SBTX line. This adds support for these operations.

Signed-off-by: Rajmohan Mani <rajmohan.mani@intel.com>
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Rajmohan Mani 2021-04-01 18:38:05 +03:00 committed by Mika Westerberg
parent ccc5cb8ad5
commit 3406de7cc2
3 changed files with 74 additions and 0 deletions

View File

@ -17,7 +17,9 @@
enum usb4_sb_opcode {
USB4_SB_OPCODE_ERR = 0x20525245, /* "ERR " */
USB4_SB_OPCODE_ONS = 0x444d4321, /* "!CMD" */
USB4_SB_OPCODE_ROUTER_OFFLINE = 0x4e45534c, /* "LSEN" */
USB4_SB_OPCODE_ENUMERATE_RETIMERS = 0x4d554e45, /* "ENUM" */
USB4_SB_OPCODE_SET_INBOUND_SBTX = 0x5055534c, /* "LSUP" */
USB4_SB_OPCODE_QUERY_LAST_RETIMER = 0x5453414c, /* "LAST" */
USB4_SB_OPCODE_GET_NVM_SECTOR_SIZE = 0x53534e47, /* "GNSS" */
USB4_SB_OPCODE_NVM_SET_OFFSET = 0x53504f42, /* "BOPS" */

View File

@ -1062,8 +1062,11 @@ int usb4_port_configure(struct tb_port *port);
void usb4_port_unconfigure(struct tb_port *port);
int usb4_port_configure_xdomain(struct tb_port *port);
void usb4_port_unconfigure_xdomain(struct tb_port *port);
int usb4_port_router_offline(struct tb_port *port);
int usb4_port_router_online(struct tb_port *port);
int usb4_port_enumerate_retimers(struct tb_port *port);
int usb4_port_retimer_set_inbound_sbtx(struct tb_port *port, u8 index);
int usb4_port_retimer_read(struct tb_port *port, u8 index, u8 reg, void *buf,
u8 size);
int usb4_port_retimer_write(struct tb_port *port, u8 index, u8 reg,

View File

@ -1318,6 +1318,48 @@ static int usb4_port_sb_op(struct tb_port *port, enum usb4_sb_target target,
return -ETIMEDOUT;
}
static int usb4_port_set_router_offline(struct tb_port *port, bool offline)
{
u32 val = !offline;
int ret;
ret = usb4_port_sb_write(port, USB4_SB_TARGET_ROUTER, 0,
USB4_SB_METADATA, &val, sizeof(val));
if (ret)
return ret;
val = USB4_SB_OPCODE_ROUTER_OFFLINE;
return usb4_port_sb_write(port, USB4_SB_TARGET_ROUTER, 0,
USB4_SB_OPCODE, &val, sizeof(val));
}
/**
* usb4_port_router_offline() - Put the USB4 port to offline mode
* @port: USB4 port
*
* This function puts the USB4 port into offline mode. In this mode the
* port does not react on hotplug events anymore. This needs to be
* called before retimer access is done when the USB4 links is not up.
*
* Returns %0 in case of success and negative errno if there was an
* error.
*/
int usb4_port_router_offline(struct tb_port *port)
{
return usb4_port_set_router_offline(port, true);
}
/**
* usb4_port_router_online() - Put the USB4 port back to online
* @port: USB4 port
*
* Makes the USB4 port functional again.
*/
int usb4_port_router_online(struct tb_port *port)
{
return usb4_port_set_router_offline(port, false);
}
/**
* usb4_port_enumerate_retimers() - Send RT broadcast transaction
* @port: USB4 port
@ -1343,6 +1385,33 @@ static inline int usb4_port_retimer_op(struct tb_port *port, u8 index,
timeout_msec);
}
/**
* usb4_port_retimer_set_inbound_sbtx() - Enable sideband channel transactions
* @port: USB4 port
* @index: Retimer index
*
* Enables sideband channel transations on SBTX. Can be used when USB4
* link does not go up, for example if there is no device connected.
*/
int usb4_port_retimer_set_inbound_sbtx(struct tb_port *port, u8 index)
{
int ret;
ret = usb4_port_retimer_op(port, index, USB4_SB_OPCODE_SET_INBOUND_SBTX,
500);
if (ret != -ENODEV)
return ret;
/*
* Per the USB4 retimer spec, the retimer is not required to
* send an RT (Retimer Transaction) response for the first
* SET_INBOUND_SBTX command
*/
return usb4_port_retimer_op(port, index, USB4_SB_OPCODE_SET_INBOUND_SBTX,
500);
}
/**
* usb4_port_retimer_read() - Read from retimer sideband registers
* @port: USB4 port