Commit fd4d58d1 authored by Mika Westerberg's avatar Mika Westerberg

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: default avatarMika Westerberg <mika.westerberg@linux.intel.com>
parent d49b4f04
...@@ -17,17 +17,22 @@ MODULE_PARM_DESC(clx, "allow low power states on the high-speed lanes (default: ...@@ -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) static const char *clx_name(unsigned int clx)
{ {
if (!clx) switch (clx) {
return "disabled"; case TB_CL0S | TB_CL1 | TB_CL2:
if (clx & TB_CL2)
return "CL0s/CL1/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"; return "CL0s/CL1";
if (clx & TB_CL0S) case TB_CL0S:
return "CL0s"; return "CL0s";
case 0:
return "disabled";
default:
return "unknown"; return "unknown";
}
} }
static int tb_port_pm_secondary_set(struct tb_port *port, bool secondary) 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) ...@@ -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; mask |= LANE_ADP_CS_1_CL0S_ENABLE;
if (clx & TB_CL1) if (clx & TB_CL1)
mask |= LANE_ADP_CS_1_CL1_ENABLE; mask |= LANE_ADP_CS_1_CL1_ENABLE;
if (clx & TB_CL2)
mask |= LANE_ADP_CS_1_CL2_ENABLE;
if (!mask) if (!mask)
return -EOPNOTSUPP; return -EOPNOTSUPP;
...@@ -291,8 +298,6 @@ bool tb_switch_clx_is_supported(const struct tb_switch *sw) ...@@ -291,8 +298,6 @@ bool tb_switch_clx_is_supported(const struct tb_switch *sw)
static bool validate_mask(unsigned int clx) static bool validate_mask(unsigned int clx)
{ {
/* Previous states need to be enabled */ /* Previous states need to be enabled */
if (clx & TB_CL2)
return (clx & (TB_CL0S | TB_CL1)) == (TB_CL0S | TB_CL1);
if (clx & TB_CL1) if (clx & TB_CL1)
return (clx & TB_CL0S) == TB_CL0S; return (clx & TB_CL0S) == TB_CL0S;
return true; return true;
...@@ -331,8 +336,10 @@ int tb_switch_clx_enable(struct tb_switch *sw, unsigned int clx) ...@@ -331,8 +336,10 @@ int tb_switch_clx_enable(struct tb_switch *sw, unsigned int clx)
!tb_switch_clx_is_supported(sw)) !tb_switch_clx_is_supported(sw))
return 0; return 0;
/* CL2 is not yet supported */ /* Only support CL2 for v2 routers */
if (clx & TB_CL2) if ((clx & TB_CL2) &&
(usb4_switch_version(parent_sw) < 2 ||
usb4_switch_version(sw) < 2))
return -EOPNOTSUPP; return -EOPNOTSUPP;
ret = tb_switch_pm_secondary_resolve(sw); ret = tb_switch_pm_secondary_resolve(sw);
......
...@@ -244,6 +244,7 @@ static void tb_discover_dp_resources(struct tb *tb) ...@@ -244,6 +244,7 @@ static void tb_discover_dp_resources(struct tb *tb)
static int tb_enable_clx(struct tb_switch *sw) static int tb_enable_clx(struct tb_switch *sw)
{ {
struct tb_cm *tcm = tb_priv(sw->tb); struct tb_cm *tcm = tb_priv(sw->tb);
unsigned int clx = TB_CL0S | TB_CL1;
const struct tb_tunnel *tunnel; const struct tb_tunnel *tunnel;
int ret; int ret;
...@@ -275,10 +276,12 @@ static int tb_enable_clx(struct tb_switch *sw) ...@@ -275,10 +276,12 @@ static int tb_enable_clx(struct tb_switch *sw)
} }
/* /*
* CL0s and CL1 are enabled and supported together. * Initially try with CL2. If that's not supported by the
* Silently ignore CLx enabling in case CLx is not supported. * 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; return ret == -EOPNOTSUPP ? 0 : ret;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment