[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <20251201122604.1268071-9-akuchynski@chromium.org>
Date: Mon, 1 Dec 2025 12:26:04 +0000
From: Andrei Kuchynski <akuchynski@...omium.org>
To: Heikki Krogerus <heikki.krogerus@...ux.intel.com>,
Abhishek Pandit-Subedi <abhishekpandit@...omium.org>,
Benson Leung <bleung@...omium.org>,
Jameson Thies <jthies@...gle.com>,
Tzung-Bi Shih <tzungbi@...nel.org>,
linux-usb@...r.kernel.org,
chrome-platform@...ts.linux.dev
Cc: Guenter Roeck <groeck@...omium.org>,
Greg Kroah-Hartman <gregkh@...uxfoundation.org>,
Dmitry Baryshkov <dmitry.baryshkov@....qualcomm.com>,
"Christian A. Ehrhardt" <lk@...e.de>,
Abel Vesa <abel.vesa@...aro.org>,
Pooja Katiyar <pooja.katiyar@...el.com>,
Pavan Holla <pholla@...omium.org>,
Madhu M <madhu.m@...el.com>,
Venkat Jayaraman <venkat.jayaraman@...el.com>,
linux-kernel@...r.kernel.org,
Andrei Kuchynski <akuchynski@...omium.org>
Subject: [PATCH RFC 8/8] platform/chrome: cros_ec_typec: Enforce priority-based mode selection
The driver sets mode_selection bit for each Alternate mode, thereby
preventing individual altmode drivers from activating their respective
modes. Once the registration of all Alternate Modes is complete, the driver
invokes typec_mode_selection_start to initiate the mode selection process
based on mode priorities.
The driver communicates the current Type-C mode to the mode selection
process via typec_altmode_state_update.
Signed-off-by: Andrei Kuchynski <akuchynski@...omium.org>
---
drivers/platform/chrome/cros_ec_typec.c | 47 +++++++++++++++-----
drivers/platform/chrome/cros_typec_altmode.c | 8 +++-
2 files changed, 42 insertions(+), 13 deletions(-)
diff --git a/drivers/platform/chrome/cros_ec_typec.c b/drivers/platform/chrome/cros_ec_typec.c
index c0806c562bb9..cd827b1822e2 100644
--- a/drivers/platform/chrome/cros_ec_typec.c
+++ b/drivers/platform/chrome/cros_ec_typec.c
@@ -27,6 +27,11 @@
BIT(DP_PIN_ASSIGN_D) | \
BIT(DP_PIN_ASSIGN_E)))
+/* Delay between mode entry/exit attempts, ms */
+static const unsigned int mode_selection_delay = 1000;
+/* Timeout for a mode entry attempt, ms */
+static const unsigned int mode_selection_timeout = 4000;
+
static void cros_typec_role_switch_quirk(struct fwnode_handle *fwnode)
{
#ifdef CONFIG_ACPI
@@ -325,6 +330,7 @@ static void cros_typec_remove_partner(struct cros_typec_data *typec,
if (!port->partner)
return;
+ typec_mode_selection_delete(port->partner);
cros_typec_unregister_altmodes(typec, port_num, true);
typec_partner_set_usb_power_delivery(port->partner, NULL);
@@ -400,17 +406,6 @@ static int cros_typec_register_port_altmodes(struct cros_typec_data *typec,
struct typec_altmode_desc desc;
struct typec_altmode *amode;
- /* All PD capable CrOS devices are assumed to support DP altmode. */
- memset(&desc, 0, sizeof(desc));
- desc.svid = USB_TYPEC_DP_SID;
- desc.mode = USB_TYPEC_DP_MODE;
- desc.vdo = DP_PORT_VDO;
- amode = cros_typec_register_displayport(port, &desc,
- typec->ap_driven_altmode);
- if (IS_ERR(amode))
- return PTR_ERR(amode);
- port->port_altmode[CROS_EC_ALTMODE_DP] = amode;
-
/*
* Register TBT compatibility alt mode. The EC will not enter the mode
* if it doesn't support it and it will not enter automatically by
@@ -428,6 +423,17 @@ static int cros_typec_register_port_altmodes(struct cros_typec_data *typec,
port->port_altmode[CROS_EC_ALTMODE_TBT] = amode;
}
+ /* All PD capable CrOS devices are assumed to support DP altmode. */
+ memset(&desc, 0, sizeof(desc));
+ desc.svid = USB_TYPEC_DP_SID;
+ desc.mode = USB_TYPEC_DP_MODE;
+ desc.vdo = DP_PORT_VDO;
+ amode = cros_typec_register_displayport(port, &desc,
+ typec->ap_driven_altmode);
+ if (IS_ERR(amode))
+ return PTR_ERR(amode);
+ port->port_altmode[CROS_EC_ALTMODE_DP] = amode;
+
port->state.alt = NULL;
port->state.mode = TYPEC_STATE_USB;
port->state.data = NULL;
@@ -742,6 +748,7 @@ static int cros_typec_configure_mux(struct cros_typec_data *typec, int port_num,
enum typec_orientation orientation;
struct cros_typec_altmode_node *node;
int ret;
+ u16 active_svid = 0;
ret = cros_ec_cmd(typec->ec, 0, EC_CMD_USB_PD_MUX_INFO,
&req, sizeof(req), &resp, sizeof(resp));
@@ -780,10 +787,13 @@ static int cros_typec_configure_mux(struct cros_typec_data *typec, int port_num,
if (port->mux_flags & USB_PD_MUX_USB4_ENABLED) {
ret = cros_typec_enable_usb4(typec, port_num, pd_ctrl);
+ active_svid = USB_TYPEC_USB4_SID;
} else if (port->mux_flags & USB_PD_MUX_TBT_COMPAT_ENABLED) {
ret = cros_typec_enable_tbt(typec, port_num, pd_ctrl);
+ active_svid = USB_TYPEC_TBT_SID;
} else if (port->mux_flags & USB_PD_MUX_DP_ENABLED) {
ret = cros_typec_enable_dp(typec, port_num, pd_ctrl);
+ active_svid = USB_TYPEC_DP_SID;
} else if (port->mux_flags & USB_PD_MUX_SAFE_MODE) {
ret = cros_typec_usb_safe_state(port);
} else if (port->mux_flags & USB_PD_MUX_USB_ENABLED) {
@@ -799,6 +809,9 @@ static int cros_typec_configure_mux(struct cros_typec_data *typec, int port_num,
port->mux_flags);
}
+ if (port->partner)
+ typec_altmode_state_update(port->partner, active_svid, ret);
+
/* Iterate all partner alt-modes and set the active alternate mode. */
list_for_each_entry(node, &port->partner_mode_list, list) {
typec_altmode_update_active(
@@ -899,6 +912,7 @@ static int cros_typec_register_altmodes(struct cros_typec_data *typec, int port_
memset(&desc, 0, sizeof(desc));
desc.svid = sop_disc->svids[i].svid;
desc.mode = j + 1;
+ desc.mode_selection = typec->ap_driven_altmode;
desc.vdo = sop_disc->svids[i].mode_vdo[j];
if (is_partner)
@@ -940,6 +954,17 @@ static int cros_typec_register_altmodes(struct cros_typec_data *typec, int port_
goto err_cleanup;
}
+ /* Once all partner alt-modes are added, we should also trigger
+ * mode selection.
+ */
+ if (is_partner && typec->ap_driven_altmode) {
+ ret = typec_mode_selection_start(port->partner,
+ mode_selection_delay, mode_selection_timeout);
+ if (ret < 0)
+ dev_err(typec->dev,
+ "Unable to run mode selection on port%d partner\n", port_num);
+ }
+
return 0;
err_cleanup:
diff --git a/drivers/platform/chrome/cros_typec_altmode.c b/drivers/platform/chrome/cros_typec_altmode.c
index 557340b53af0..ee4f2a9dd68a 100644
--- a/drivers/platform/chrome/cros_typec_altmode.c
+++ b/drivers/platform/chrome/cros_typec_altmode.c
@@ -41,12 +41,16 @@ static void cros_typec_altmode_work(struct work_struct *work)
{
struct cros_typec_altmode_data *data =
container_of(work, struct cros_typec_altmode_data, work);
+ int ret;
mutex_lock(&data->lock);
- if (typec_altmode_vdm(data->alt, data->header, data->vdo_data,
- data->vdo_size))
+ ret = typec_altmode_vdm(data->alt, data->header, data->vdo_data,
+ data->vdo_size);
+ if (ret) {
dev_err(&data->alt->dev, "VDM 0x%x failed\n", data->header);
+ typec_altmode_state_update(data->port->partner, data->sid, ret);
+ }
data->header = 0;
data->vdo_data = NULL;
--
2.52.0.158.g65b55ccf14-goog
Powered by blists - more mailing lists