thunderbolt: Enable CL2 low power state

For USB4 v2 routers we can also enable CL2 which allows better power
savings and thermal management than CL0s and CL1.

Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
This commit is contained in:
Mika Westerberg 2022-11-06 13:07:43 +02:00
parent d49b4f043d
commit fd4d58d1fe
2 changed files with 25 additions and 15 deletions

View file

@ -17,17 +17,22 @@ MODULE_PARM_DESC(clx, "allow low power states on the high-speed lanes (default:
static const char *clx_name(unsigned int clx)
{
if (!clx)
return "disabled";
if (clx & TB_CL2)
switch (clx) {
case TB_CL0S | TB_CL1 | TB_CL2:
return "CL0s/CL1/CL2";
if (clx & TB_CL1)
case TB_CL1 | TB_CL2:
return "CL1/CL2";
case TB_CL0S | TB_CL2:
return "CL0s/CL2";
case TB_CL0S | TB_CL1:
return "CL0s/CL1";
if (clx & TB_CL0S)
case TB_CL0S:
return "CL0s";
return "unknown";
case 0:
return "disabled";
default:
return "unknown";
}
}
static int tb_port_pm_secondary_set(struct tb_port *port, bool secondary)
@ -104,6 +109,8 @@ static int tb_port_clx_set(struct tb_port *port, unsigned int clx, bool enable)
mask |= LANE_ADP_CS_1_CL0S_ENABLE;
if (clx & TB_CL1)
mask |= LANE_ADP_CS_1_CL1_ENABLE;
if (clx & TB_CL2)
mask |= LANE_ADP_CS_1_CL2_ENABLE;
if (!mask)
return -EOPNOTSUPP;
@ -291,8 +298,6 @@ bool tb_switch_clx_is_supported(const struct tb_switch *sw)
static bool validate_mask(unsigned int clx)
{
/* Previous states need to be enabled */
if (clx & TB_CL2)
return (clx & (TB_CL0S | TB_CL1)) == (TB_CL0S | TB_CL1);
if (clx & TB_CL1)
return (clx & TB_CL0S) == TB_CL0S;
return true;
@ -331,8 +336,10 @@ int tb_switch_clx_enable(struct tb_switch *sw, unsigned int clx)
!tb_switch_clx_is_supported(sw))
return 0;
/* CL2 is not yet supported */
if (clx & TB_CL2)
/* Only support CL2 for v2 routers */
if ((clx & TB_CL2) &&
(usb4_switch_version(parent_sw) < 2 ||
usb4_switch_version(sw) < 2))
return -EOPNOTSUPP;
ret = tb_switch_pm_secondary_resolve(sw);

View file

@ -244,6 +244,7 @@ static void tb_discover_dp_resources(struct tb *tb)
static int tb_enable_clx(struct tb_switch *sw)
{
struct tb_cm *tcm = tb_priv(sw->tb);
unsigned int clx = TB_CL0S | TB_CL1;
const struct tb_tunnel *tunnel;
int ret;
@ -275,10 +276,12 @@ static int tb_enable_clx(struct tb_switch *sw)
}
/*
* CL0s and CL1 are enabled and supported together.
* Silently ignore CLx enabling in case CLx is not supported.
* Initially try with CL2. If that's not supported by the
* topology try with CL0s and CL1 and then give up.
*/
ret = tb_switch_clx_enable(sw, TB_CL0S | TB_CL1);
ret = tb_switch_clx_enable(sw, clx | TB_CL2);
if (ret == -EOPNOTSUPP)
ret = tb_switch_clx_enable(sw, clx);
return ret == -EOPNOTSUPP ? 0 : ret;
}