Skip to content

Commit

Permalink
thunderbolt: Introduce tb_port_reset()
Browse files Browse the repository at this point in the history
Introduce a function that issues Downstream Port Reset to a USB4 port.
This supports Thunderbolt 2, 3 and USB4 routers.

Signed-off-by: Sanath S <[email protected]>
Signed-off-by: Mika Westerberg <[email protected]>
  • Loading branch information
Sanath S authored and westeri committed Jan 22, 2024
1 parent 6613476 commit 01da6b9
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 0 deletions.
45 changes: 45 additions & 0 deletions drivers/thunderbolt/lc.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
* Author: Mika Westerberg <[email protected]>
*/

#include <linux/delay.h>

#include "tb.h"

/**
Expand Down Expand Up @@ -45,6 +47,49 @@ static int find_port_lc_cap(struct tb_port *port)
return sw->cap_lc + start + phys * size;
}

/**
* tb_lc_reset_port() - Trigger downstream port reset through LC
* @port: Port that is reset
*
* Triggers downstream port reset through link controller registers.
* Returns %0 in case of success negative errno otherwise. Only supports
* non-USB4 routers with link controller (that's Thunderbolt 2 and
* Thunderbolt 3).
*/
int tb_lc_reset_port(struct tb_port *port)
{
struct tb_switch *sw = port->sw;
int cap, ret;
u32 mode;

if (sw->generation < 2)
return -EINVAL;

cap = find_port_lc_cap(port);
if (cap < 0)
return cap;

ret = tb_sw_read(sw, &mode, TB_CFG_SWITCH, cap + TB_LC_PORT_MODE, 1);
if (ret)
return ret;

mode |= TB_LC_PORT_MODE_DPR;

ret = tb_sw_write(sw, &mode, TB_CFG_SWITCH, cap + TB_LC_PORT_MODE, 1);
if (ret)
return ret;

fsleep(10000);

ret = tb_sw_read(sw, &mode, TB_CFG_SWITCH, cap + TB_LC_PORT_MODE, 1);
if (ret)
return ret;

mode &= ~TB_LC_PORT_MODE_DPR;

return tb_sw_write(sw, &mode, TB_CFG_SWITCH, cap + TB_LC_PORT_MODE, 1);
}

static int tb_lc_set_port_configured(struct tb_port *port, bool configured)
{
bool upstream = tb_is_upstream_port(port);
Expand Down
7 changes: 7 additions & 0 deletions drivers/thunderbolt/switch.c
Original file line number Diff line number Diff line change
Expand Up @@ -676,6 +676,13 @@ int tb_port_disable(struct tb_port *port)
return __tb_port_enable(port, false);
}

static int tb_port_reset(struct tb_port *port)
{
if (tb_switch_is_usb4(port->sw))
return port->cap_usb4 ? usb4_port_reset(port) : 0;
return tb_lc_reset_port(port);
}

/*
* tb_init_port() - initialize a port
*
Expand Down
2 changes: 2 additions & 0 deletions drivers/thunderbolt/tb.h
Original file line number Diff line number Diff line change
Expand Up @@ -1169,6 +1169,7 @@ int tb_drom_read(struct tb_switch *sw);
int tb_drom_read_uid_only(struct tb_switch *sw, u64 *uid);

int tb_lc_read_uuid(struct tb_switch *sw, u32 *uuid);
int tb_lc_reset_port(struct tb_port *port);
int tb_lc_configure_port(struct tb_port *port);
void tb_lc_unconfigure_port(struct tb_port *port);
int tb_lc_configure_xdomain(struct tb_port *port);
Expand Down Expand Up @@ -1301,6 +1302,7 @@ void usb4_switch_remove_ports(struct tb_switch *sw);

int usb4_port_unlock(struct tb_port *port);
int usb4_port_hotplug_enable(struct tb_port *port);
int usb4_port_reset(struct tb_port *port);
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, struct tb_xdomain *xd);
Expand Down
4 changes: 4 additions & 0 deletions drivers/thunderbolt/tb_regs.h
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,7 @@ struct tb_regs_port_header {
#define PORT_CS_18_CSA BIT(22)
#define PORT_CS_18_TIP BIT(24)
#define PORT_CS_19 0x13
#define PORT_CS_19_DPR BIT(0)
#define PORT_CS_19_PC BIT(3)
#define PORT_CS_19_PID BIT(4)
#define PORT_CS_19_WOC BIT(16)
Expand Down Expand Up @@ -584,6 +585,9 @@ struct tb_regs_hop {
#define TB_LC_POWER 0x740

/* Link controller registers */
#define TB_LC_PORT_MODE 0x26
#define TB_LC_PORT_MODE_DPR BIT(0)

#define TB_LC_CS_42 0x2a
#define TB_LC_CS_42_USB_PLUGGED BIT(31)

Expand Down
39 changes: 39 additions & 0 deletions drivers/thunderbolt/usb4.c
Original file line number Diff line number Diff line change
Expand Up @@ -1113,6 +1113,45 @@ int usb4_port_hotplug_enable(struct tb_port *port)
return tb_port_write(port, &val, TB_CFG_PORT, ADP_CS_5, 1);
}

/**
* usb4_port_reset() - Issue downstream port reset
* @port: USB4 port to reset
*
* Issues downstream port reset to @port.
*/
int usb4_port_reset(struct tb_port *port)
{
int ret;
u32 val;

if (!port->cap_usb4)
return -EINVAL;

ret = tb_port_read(port, &val, TB_CFG_PORT,
port->cap_usb4 + PORT_CS_19, 1);
if (ret)
return ret;

val |= PORT_CS_19_DPR;

ret = tb_port_write(port, &val, TB_CFG_PORT,
port->cap_usb4 + PORT_CS_19, 1);
if (ret)
return ret;

fsleep(10000);

ret = tb_port_read(port, &val, TB_CFG_PORT,
port->cap_usb4 + PORT_CS_19, 1);
if (ret)
return ret;

val &= ~PORT_CS_19_DPR;

return tb_port_write(port, &val, TB_CFG_PORT,
port->cap_usb4 + PORT_CS_19, 1);
}

static int usb4_port_set_configured(struct tb_port *port, bool configured)
{
int ret;
Expand Down

0 comments on commit 01da6b9

Please sign in to comment.