diff options
author | Mika Westerberg <mika.westerberg@linux.intel.com> | 2019-01-09 17:25:43 +0200 |
---|---|---|
committer | Mika Westerberg <mika.westerberg@linux.intel.com> | 2019-04-18 11:18:52 +0300 |
commit | 5480dfc275aa7e5f892505ce082d71635d6a22f8 (patch) | |
tree | ae6ab45771a68ce73fbae4d4c7a2f7a0abbc5cac /drivers/thunderbolt/lc.c | |
parent | e879a709de0210802ba14243a168d632cb7ab527 (diff) |
thunderbolt: Set sleep bit when suspending switch
Thunderbolt 2 devices and beyond link controller needs to be notified
when a switch is going to be suspended by setting bit 31 in LC_SX_CTRL
register. Add this functionality to the software connection manager.
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Diffstat (limited to 'drivers/thunderbolt/lc.c')
-rw-r--r-- | drivers/thunderbolt/lc.c | 44 |
1 files changed, 44 insertions, 0 deletions
diff --git a/drivers/thunderbolt/lc.c b/drivers/thunderbolt/lc.c index a5dddf176546..ae1e92611c3e 100644 --- a/drivers/thunderbolt/lc.c +++ b/drivers/thunderbolt/lc.c @@ -133,3 +133,47 @@ void tb_lc_unconfigure_link(struct tb_switch *sw) tb_lc_configure_lane(up, false); tb_lc_configure_lane(down, false); } + +/** + * tb_lc_set_sleep() - Inform LC that the switch is going to sleep + * @sw: Switch to set sleep + * + * Let the switch link controllers know that the switch is going to + * sleep. + */ +int tb_lc_set_sleep(struct tb_switch *sw) +{ + int start, size, nlc, ret, i; + u32 desc; + + if (sw->generation < 2) + return 0; + + ret = read_lc_desc(sw, &desc); + if (ret) + return ret; + + /* Figure out number of link controllers */ + nlc = desc & TB_LC_DESC_NLC_MASK; + start = (desc & TB_LC_DESC_SIZE_MASK) >> TB_LC_DESC_SIZE_SHIFT; + size = (desc & TB_LC_DESC_PORT_SIZE_MASK) >> TB_LC_DESC_PORT_SIZE_SHIFT; + + /* For each link controller set sleep bit */ + for (i = 0; i < nlc; i++) { + unsigned int offset = sw->cap_lc + start + i * size; + u32 ctrl; + + ret = tb_sw_read(sw, &ctrl, TB_CFG_SWITCH, + offset + TB_LC_SX_CTRL, 1); + if (ret) + return ret; + + ctrl |= TB_LC_SX_CTRL_SLP; + ret = tb_sw_write(sw, &ctrl, TB_CFG_SWITCH, + offset + TB_LC_SX_CTRL, 1); + if (ret) + return ret; + } + + return 0; +} |