mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2024-12-28 16:52:18 +00:00
thunderbolt: Introduce tb_port_reset()
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 <Sanath.S@amd.com> Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
This commit is contained in:
parent
6613476e22
commit
01da6b99d4
@ -6,6 +6,8 @@
|
||||
* Author: Mika Westerberg <mika.westerberg@linux.intel.com>
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include "tb.h"
|
||||
|
||||
/**
|
||||
@ -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);
|
||||
|
@ -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
|
||||
*
|
||||
|
@ -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);
|
||||
@ -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);
|
||||
|
@ -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)
|
||||
@ -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)
|
||||
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user