[PATCH 3/7] platform/chrome: cros_ec_typec: Support EC mode entry
Stephen Boyd
swboyd at chromium.org
Tue Apr 15 17:02:03 PDT 2025
Support ChromeOS EC firmwares that don't support AP mode entry. Check
that the mode has been entered by querying the EC and reject mode entry
attempts if the EC hasn't already entered the mode requested. This
allows us to bind the DP altmode driver on devices that don't support AP
mode entry, i.e. most ChromeOS devices where the EC controls mode entry.
Cc: Benson Leung <bleung at chromium.org>
Cc: Tzung-Bi Shih <tzungbi at kernel.org>
Cc: <chrome-platform at lists.linux.dev>
Cc: Pin-yen Lin <treapking at chromium.org>
Cc: Abhishek Pandit-Subedi <abhishekpandit at chromium.org>
Cc: Łukasz Bartosik <ukaszb at chromium.org>
Cc: Jameson Thies <jthies at google.com>
Cc: Andrei Kuchynski <akuchynski at chromium.org>
Signed-off-by: Stephen Boyd <swboyd at chromium.org>
---
drivers/platform/chrome/cros_typec_altmode.c | 112 +++++++++++++------
1 file changed, 75 insertions(+), 37 deletions(-)
diff --git a/drivers/platform/chrome/cros_typec_altmode.c b/drivers/platform/chrome/cros_typec_altmode.c
index c2d9c548b5e8..97ca4cfabbc0 100644
--- a/drivers/platform/chrome/cros_typec_altmode.c
+++ b/drivers/platform/chrome/cros_typec_altmode.c
@@ -58,31 +58,50 @@ static void cros_typec_altmode_work(struct work_struct *work)
static int cros_typec_altmode_enter(struct typec_altmode *alt, u32 *vdo)
{
struct cros_typec_altmode_data *adata = typec_altmode_get_drvdata(alt);
- struct ec_params_typec_control req = {
- .port = adata->port->port_num,
- .command = TYPEC_CONTROL_COMMAND_ENTER_MODE,
- };
+ struct cros_ec_device *ec = adata->port->typec_data->ec;
+ unsigned int port = adata->port->port_num;
int svdm_version;
int ret;
if (!adata->ap_mode_entry) {
- dev_warn(&alt->dev,
- "EC does not support AP driven mode entry\n");
- return -EOPNOTSUPP;
+ struct ec_response_usb_pd_mux_info resp;
+ struct ec_params_usb_pd_mux_info req = {
+ .port = port,
+ };
+ uint8_t flags;
+
+ if (adata->sid == USB_TYPEC_DP_SID)
+ flags = USB_PD_MUX_DP_ENABLED;
+ else if (adata->sid == USB_TYPEC_TBT_SID)
+ flags = USB_PD_MUX_TBT_COMPAT_ENABLED;
+ else
+ return -EOPNOTSUPP;
+
+ ret = cros_ec_cmd(ec, 0, EC_CMD_USB_PD_MUX_INFO,
+ &req, sizeof(req), &resp, sizeof(resp));
+ if (ret < 0)
+ return ret;
+
+ if (!(resp.flags & flags))
+ return -EINVAL;
+ } else {
+ struct ec_params_typec_control req = {
+ .port = port,
+ .command = TYPEC_CONTROL_COMMAND_ENTER_MODE,
+ };
+
+ if (adata->sid == USB_TYPEC_DP_SID)
+ req.mode_to_enter = CROS_EC_ALTMODE_DP;
+ else if (adata->sid == USB_TYPEC_TBT_SID)
+ req.mode_to_enter = CROS_EC_ALTMODE_TBT;
+ else
+ return -EOPNOTSUPP;
+
+ ret = cros_ec_cmd(ec, 0, EC_CMD_TYPEC_CONTROL, &req, sizeof(req), NULL, 0);
+ if (ret < 0)
+ return ret;
}
- if (adata->sid == USB_TYPEC_DP_SID)
- req.mode_to_enter = CROS_EC_ALTMODE_DP;
- else if (adata->sid == USB_TYPEC_TBT_SID)
- req.mode_to_enter = CROS_EC_ALTMODE_TBT;
- else
- return -EOPNOTSUPP;
-
- ret = cros_ec_cmd(adata->port->typec_data->ec, 0, EC_CMD_TYPEC_CONTROL,
- &req, sizeof(req), NULL, 0);
- if (ret < 0)
- return ret;
-
svdm_version = typec_altmode_get_svdm_version(alt);
if (svdm_version < 0)
return svdm_version;
@@ -97,31 +116,52 @@ static int cros_typec_altmode_enter(struct typec_altmode *alt, u32 *vdo)
schedule_work(&adata->work);
mutex_unlock(&adata->lock);
- return ret;
+
+ return 0;
}
static int cros_typec_altmode_exit(struct typec_altmode *alt)
{
struct cros_typec_altmode_data *adata = typec_altmode_get_drvdata(alt);
- struct ec_params_typec_control req = {
- .port = adata->port->port_num,
- .command = TYPEC_CONTROL_COMMAND_EXIT_MODES,
- };
+ struct cros_ec_device *ec = adata->port->typec_data->ec;
+ unsigned int port = adata->port->port_num;
int svdm_version;
int ret;
if (!adata->ap_mode_entry) {
- dev_warn(&alt->dev,
- "EC does not support AP driven mode exit\n");
- return -EOPNOTSUPP;
+ struct ec_response_usb_pd_mux_info resp;
+ struct ec_params_usb_pd_mux_info req = {
+ .port = port,
+ };
+ uint8_t flags;
+
+ if (adata->sid == USB_TYPEC_DP_SID)
+ flags = USB_PD_MUX_DP_ENABLED;
+ else if (adata->sid == USB_TYPEC_TBT_SID)
+ flags = USB_PD_MUX_TBT_COMPAT_ENABLED;
+ else
+ return -EOPNOTSUPP;
+
+ ret = cros_ec_cmd(ec, 0, EC_CMD_USB_PD_MUX_INFO,
+ &req, sizeof(req), &resp, sizeof(resp));
+ if (ret < 0)
+ return ret;
+
+ if (resp.flags & flags)
+ return -EINVAL;
+ } else {
+ struct ec_params_typec_control req = {
+ .port = port,
+ .command = TYPEC_CONTROL_COMMAND_EXIT_MODES,
+ };
+
+ ret = cros_ec_cmd(adata->port->typec_data->ec, 0, EC_CMD_TYPEC_CONTROL,
+ &req, sizeof(req), NULL, 0);
+
+ if (ret < 0)
+ return ret;
}
- ret = cros_ec_cmd(adata->port->typec_data->ec, 0, EC_CMD_TYPEC_CONTROL,
- &req, sizeof(req), NULL, 0);
-
- if (ret < 0)
- return ret;
-
svdm_version = typec_altmode_get_svdm_version(alt);
if (svdm_version < 0)
return svdm_version;
@@ -136,7 +176,8 @@ static int cros_typec_altmode_exit(struct typec_altmode *alt)
schedule_work(&adata->work);
mutex_unlock(&adata->lock);
- return ret;
+
+ return 0;
}
static int cros_typec_displayport_vdm(struct typec_altmode *alt, u32 header,
@@ -254,9 +295,6 @@ static int cros_typec_altmode_vdm(struct typec_altmode *alt, u32 header,
{
struct cros_typec_altmode_data *adata = typec_altmode_get_drvdata(alt);
- if (!adata->ap_mode_entry)
- return -EOPNOTSUPP;
-
if (adata->sid == USB_TYPEC_DP_SID)
return cros_typec_displayport_vdm(alt, header, data, count);
--
https://chromeos.dev
More information about the linux-arm-kernel
mailing list