From nobody Mon Dec 1 21:30:56 2025 Received: from mail-ej1-f41.google.com (mail-ej1-f41.google.com [209.85.218.41]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4C63330BF52 for ; Mon, 1 Dec 2025 12:26:16 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.218.41 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764591978; cv=none; b=Ooii/7D2KxhfGQp8tt721ZXePWEJawedD5n6wdP9plj/Ur+cPBbOXCqN8y/tCvdGQDuzK9eaZFHbdEOGC7tOL2vPbxAMI119aBmnvZRwZjADXjcn1A4Aj72LVxS6FyOUnlDT6H6eqrfu44ezj+agP9vjimUGhqbWXFeZRxKuHZo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764591978; c=relaxed/simple; bh=mFFOFxlXkYzqkxL/jBvCvI+dfjNbxB2plNZeiEbJmZQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=IQjyOMKCpRxRJOu88/7FuquTHEXuz3yAK0mf2dh8d9kP6kToVKXmS9aUv0MepR3FlIuVYfahfQ80R1bXMspxLMngMJEsGzOvvjcJb8Gd+gCqV3LO96UAut+XUnhf47A2Ptc8R6GSU3U2FPaFvM4IG4LdaZTBYB/WRn+prdSuw1Y= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=chromium.org; spf=pass smtp.mailfrom=chromium.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b=ECoPe78S; arc=none smtp.client-ip=209.85.218.41 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=chromium.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="ECoPe78S" Received: by mail-ej1-f41.google.com with SMTP id a640c23a62f3a-b735e278fa1so72635766b.0 for ; Mon, 01 Dec 2025 04:26:16 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; t=1764591975; x=1765196775; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=rOzvEryKCkrNpvspLpfMwILhAFa2s2m3Cqxq22OFJJc=; b=ECoPe78SE2XeK7va/XeUzk5On68OcCSSHhWxD3MkXu7JlYnY/77yiRNkqPu1D/iOxu u2Sf71Joz3uwEI33gmbTOBby4C5alH2fQlLJmaDlh1Jf0wf/7sew5ixiR6HhMZgmIRNE enHNNR+WwYVtd0UCDyILkr7Tsy3aSILH9VxIQ= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1764591975; x=1765196775; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=rOzvEryKCkrNpvspLpfMwILhAFa2s2m3Cqxq22OFJJc=; b=dx/DOmPp0+moYAlcCJiNgTxFPS+bAV9XtWPzE7JQrYhMD4/fPeARWZkDWU0afWkCdq 4yCL3kq7nTScAO5UYsqnsvICVqTpIQxBnUWDYCyj3skGe8umQTEz+iTS7twQ3ULSPHRL Hy3b+kmUJX2Yvc4fyXPDBodftwGu3C+lw2NrVvLkRQJ6XCMi1t8GSUC1fpIKIKpAhFSn F05n959PZQorq3V4w3j4atFmm9EK/vV5U0/HqqeJGtSiY04XZsZZ7Kis+kJNTNg+yy7r +nIH1SS90ZpMjdTpgBpZvg63obYDD+Gy7I73WndfzJykPJoPjbbq4nFmFvquUpmH/omY ESeQ== X-Forwarded-Encrypted: i=1; AJvYcCXA8E9aJtd1wbF9QNwkaTnJQ/v7BXTD3TAvBNGut+lGXex/7DQfF9xEqcOwlS+Gee6ltR1rxD5CcOOYKqA=@vger.kernel.org X-Gm-Message-State: AOJu0YxEFsFUG9HYy06xbI49Nm60BoFpYaCoruvRnk2UPdrLqaUgvEKe LIHV1YfGoaGwqk1eK6rVUI9V/JdGN8xyW9sD+nZ58UmGMmkYx/W2q2BE9lE2GhfdUA== X-Gm-Gg: ASbGncv3N488mFpsyPnaKRd7fFutbZ4y6GtVxhuRc8JmzFmvZL9PitRuUuRe0vtNQF9 A7uQOOc38GazGkEAPhLaSW7g3yKJzHwzxheD7+a7qWKIlMujKn/4r/z8ZESykneo7IckXzrtIKt XiNOqZ5KIHjR/v+eNuUl+aXE7DSKxjHf/E9QuhrNbH4Gw5IgYdQFyhafTpBTFLPIMpAHmx6Zpxe r5QYVjfDn8YhOd6MYER0dMzExnBT5P8FG/dHUhfTJVI8smw2+V9CnMmlquucl2rjFkyPm6kdRmd SSnv1xcl6kG86ueKwa14A2dkjGEVQIIkQOxDLudk3rzNSp+FC/F5h8tAzmMSjMCvmx24+1ENfe6 zlY4yDNX+x971k6fE569Yxipy9c25I7i0qrlZV9ncwsBEaAR0oEED9HFHJynFtkCNL85Ry7N1Zg izaiPlnN4HDvN/Wc0OUz5KCTeXUy4lFeoIoNmpo/2Gqdj+nk2nCbj9+3fItmXdewxzK59cRjkqq 6Peaj/4PlM= X-Google-Smtp-Source: AGHT+IE8DaR7Kik8466aWNYAdspu3ISPD7yBbPMq0lguD6XcCygqXCAx20V+4wMbwRnBnuB9+Z3lcA== X-Received: by 2002:a17:907:cbc6:b0:b76:d882:5aaa with SMTP id a640c23a62f3a-b76d8825d0bmr2269904566b.3.1764591974487; Mon, 01 Dec 2025 04:26:14 -0800 (PST) Received: from akuchynski.c.googlers.com.com (218.127.147.34.bc.googleusercontent.com. [34.147.127.218]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-b76f519e331sm1229049266b.24.2025.12.01.04.26.13 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 01 Dec 2025 04:26:14 -0800 (PST) From: Andrei Kuchynski To: Heikki Krogerus , Abhishek Pandit-Subedi , Benson Leung , Jameson Thies , Tzung-Bi Shih , linux-usb@vger.kernel.org, chrome-platform@lists.linux.dev Cc: Guenter Roeck , Greg Kroah-Hartman , Dmitry Baryshkov , "Christian A. Ehrhardt" , Abel Vesa , Pooja Katiyar , Pavan Holla , Madhu M , Venkat Jayaraman , linux-kernel@vger.kernel.org, Andrei Kuchynski Subject: [PATCH RFC 1/8] usb: typec: Implement mode selection Date: Mon, 1 Dec 2025 12:25:57 +0000 Message-ID: <20251201122604.1268071-2-akuchynski@chromium.org> X-Mailer: git-send-email 2.52.0.158.g65b55ccf14-goog In-Reply-To: <20251201122604.1268071-1-akuchynski@chromium.org> References: <20251201122604.1268071-1-akuchynski@chromium.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The mode selection process is controlled by the following API functions, which allow to initiate and complete mode entry based on the priority of each mode: `typec_mode_selection_start` function compiles a priority list of supported Alternate Modes. `typec_altmode_state_update` function is invoked by the port driver to communicate the current mode of the Type-C connector. `typec_mode_selection_delete` function stops the currently running mode selection process and releases all associated system resources. `mode_selection_work_fn` task attempts to activate modes. The process stops on success; otherwise, it proceeds to the next mode after a timeout or error. Signed-off-by: Andrei Kuchynski --- drivers/usb/typec/Makefile | 2 +- drivers/usb/typec/class.h | 2 + drivers/usb/typec/mode_selection.c | 285 +++++++++++++++++++++++++++++ include/linux/usb/typec_altmode.h | 40 ++++ 4 files changed, 328 insertions(+), 1 deletion(-) create mode 100644 drivers/usb/typec/mode_selection.c diff --git a/drivers/usb/typec/Makefile b/drivers/usb/typec/Makefile index 7a368fea61bc..8a6a1c663eb6 100644 --- a/drivers/usb/typec/Makefile +++ b/drivers/usb/typec/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_TYPEC) +=3D typec.o -typec-y :=3D class.o mux.o bus.o pd.o retimer.o +typec-y :=3D class.o mux.o bus.o pd.o retimer.o mode_selection.o typec-$(CONFIG_ACPI) +=3D port-mapper.o obj-$(CONFIG_TYPEC) +=3D altmodes/ obj-$(CONFIG_TYPEC_TCPM) +=3D tcpm/ diff --git a/drivers/usb/typec/class.h b/drivers/usb/typec/class.h index 2e89a83c2eb7..d3435936ee7c 100644 --- a/drivers/usb/typec/class.h +++ b/drivers/usb/typec/class.h @@ -9,6 +9,7 @@ struct typec_mux; struct typec_switch; struct usb_device; +struct mode_selection; =20 struct typec_plug { struct device dev; @@ -39,6 +40,7 @@ struct typec_partner { u8 usb_capability; =20 struct usb_power_delivery *pd; + struct mode_selection *sel; =20 void (*attach)(struct typec_partner *partner, struct device *dev); void (*deattach)(struct typec_partner *partner, struct device *dev); diff --git a/drivers/usb/typec/mode_selection.c b/drivers/usb/typec/mode_se= lection.c new file mode 100644 index 000000000000..1cf8a4dcd742 --- /dev/null +++ b/drivers/usb/typec/mode_selection.c @@ -0,0 +1,285 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright 2025 Google LLC. + */ + +#include +#include +#include +#include +#include + +#include "class.h" +#include "bus.h" + +/** + * struct mode_state - State tracking for a specific Type-C alternate mode + * @svid: Standard or Vendor ID of the Alternate Mode + * @priority: mode priority. + * @error: outcome of the last attempt to enter the mode. + * @list: list head to link this mode state into a prioritized list + */ +struct mode_state { + u16 svid; + u8 priority; + int error; + struct list_head list; +}; + +/** + * struct mode_selection - Manages the selection and state of Alternate Mo= des + * @mode_list: prioritized list of available Alternate Modes + * @lock: mutex to protect mode_list + * @work: work structure + * @partner: handle to the Type-C partner device + * @active_svid: svid of currently active mode + * @timeout: timeout for a mode entry attempt, ms + * @delay: delay between mode entry/exit attempts, ms + */ +struct mode_selection { + struct list_head mode_list; + struct mutex lock; + struct delayed_work work; + struct typec_partner *partner; + u16 active_svid; + unsigned int timeout; + unsigned int delay; +}; + +struct mode_order { + u16 svid; + int enter; + int result; +}; + +static int activate_altmode(struct device *dev, void *data) +{ + if (is_typec_altmode(dev)) { + struct typec_altmode *alt =3D to_typec_altmode(dev); + struct mode_order *order =3D (struct mode_order *)data; + + if (order->svid =3D=3D alt->svid) { + if (alt->ops && alt->ops->activate) + order->result =3D alt->ops->activate(alt, order->enter); + else + order->result =3D -EOPNOTSUPP; + return 1; + } + } + return 0; +} + +static int mode_selection_activate(struct mode_selection *sel, + const u16 svid, const int enter) + + __must_hold(&sel->lock) +{ + struct mode_order order =3D {.svid =3D svid, .enter =3D enter, .result = =3D -ENODEV}; + + /* + * The port driver may acquire its internal mutex during alternate mode + * activation. Since this is the same mutex that may be held during the + * execution of typec_altmode_state_update(), it is crucial to release + * sel->mutex before activation to avoid potential deadlock. + * Note that sel->mode_list must remain invariant throughout this unlocked + * interval. + */ + mutex_unlock(&sel->lock); + device_for_each_child(&sel->partner->dev, &order, activate_altmode); + mutex_lock(&sel->lock); + + return order.result; +} + +static void mode_list_clean(struct mode_selection *sel) +{ + struct mode_state *ms, *tmp; + + list_for_each_entry_safe(ms, tmp, &sel->mode_list, list) { + list_del(&ms->list); + kfree(ms); + } +} + +/** + * mode_selection_work_fn() - Alternate mode activation task + * @work: work structure + * + * - If the Alternate Mode currently prioritized at the top of the list is= already + * active, the entire selection process is considered finished. + * - If a different Alternate Mode is currently active, the system must ex= it that + * active mode first before attempting any new entry. + * + * The function then checks the result of the attempt to entre the current= mode, + * stored in the `ms->error` field: + * - if the attempt FAILED, the mode is deactivated and removed from the l= ist. + * - `ms->error` value of 0 signifies that the mode has not yet been activ= ated. + * Once successfully activated, the task is scheduled for subsequent entry= after + * a timeout period. The alternate mode driver is expected to call back wi= th the + * actual mode entry result via `typec_altmode_state_update()`. + */ +static void mode_selection_work_fn(struct work_struct *work) +{ + struct mode_selection *sel =3D container_of(work, + struct mode_selection, work.work); + struct mode_state *ms; + unsigned int delay =3D sel->delay; + int result; + + mutex_lock(&sel->lock); + + ms =3D list_first_entry_or_null(&sel->mode_list, struct mode_state, list); + if (!ms) { + mutex_unlock(&sel->lock); + return; + } + + if (sel->active_svid =3D=3D ms->svid) { + dev_dbg(&sel->partner->dev, "%x altmode is active\n", ms->svid); + mode_list_clean(sel); + } else if (sel->active_svid !=3D 0) { + result =3D mode_selection_activate(sel, sel->active_svid, 0); + if (result) { + dev_dbg(&sel->partner->dev, "enable to exit %x altmode\n", + sel->active_svid); + mode_list_clean(sel); + } + } else if (ms->error) { + dev_dbg(&sel->partner->dev, "%x: entry error %pe\n", + ms->svid, ERR_PTR(ms->error)); + mode_selection_activate(sel, ms->svid, 0); + list_del(&ms->list); + kfree(ms); + } else { + result =3D mode_selection_activate(sel, ms->svid, 1); + if (result) { + dev_dbg(&sel->partner->dev, "%x: activation error %pe\n", + ms->svid, ERR_PTR(result)); + list_del(&ms->list); + kfree(ms); + } else { + delay =3D sel->timeout; + ms->error =3D -ETIMEDOUT; + } + } + + if (!list_empty(&sel->mode_list)) + schedule_delayed_work(&sel->work, msecs_to_jiffies(delay)); + mutex_unlock(&sel->lock); +} + +void typec_altmode_state_update(struct typec_partner *partner, const u16 s= vid, + const int error) +{ + struct mode_selection *sel =3D partner->sel; + struct mode_state *ms; + + if (sel) { + mutex_lock(&sel->lock); + ms =3D list_first_entry_or_null(&sel->mode_list, struct mode_state, list= ); + if (ms && ms->svid =3D=3D svid) { + ms->error =3D error; + cancel_delayed_work(&sel->work); + schedule_delayed_work(&sel->work, 0); + } + if (!error) + sel->active_svid =3D svid; + else + sel->active_svid =3D 0; + mutex_unlock(&sel->lock); + } +} +EXPORT_SYMBOL_GPL(typec_altmode_state_update); + +static int compare_priorities(void *priv, + const struct list_head *a, const struct list_head *b) +{ + const struct mode_state *msa =3D container_of(a, struct mode_state, list); + const struct mode_state *msb =3D container_of(b, struct mode_state, list); + + if (msa->priority < msb->priority) + return -1; + return 1; +} + +static struct mode_state *create_mode_entry(u16 svid, u8 priority) +{ + struct mode_state *ms =3D kzalloc(sizeof(struct mode_state), GFP_KERNEL); + + if (ms) { + ms->svid =3D svid; + ms->priority =3D priority; + INIT_LIST_HEAD(&ms->list); + } + + return ms; +} + +static int altmode_add_to_list(struct device *dev, void *data) +{ + if (is_typec_altmode(dev)) { + struct list_head *list =3D (struct list_head *)data; + struct typec_altmode *altmode =3D to_typec_altmode(dev); + const struct typec_altmode *pdev =3D typec_altmode_get_partner(altmode); + struct mode_state *ms; + + if (pdev && altmode->ops && altmode->ops->activate) { + ms =3D create_mode_entry(pdev->svid, pdev->priority); + if (!ms) + return -ENOMEM; + list_add_tail(&ms->list, list); + } + } + return 0; +} + +int typec_mode_selection_start(struct typec_partner *partner, + const unsigned int delay, const unsigned int timeout) +{ + struct mode_selection *sel; + int ret; + + if (partner->sel) + return -EALREADY; + + sel =3D kzalloc(sizeof(struct mode_selection), GFP_KERNEL); + if (!sel) + return -ENOMEM; + + INIT_LIST_HEAD(&sel->mode_list); + + ret =3D device_for_each_child( + &partner->dev, &sel->mode_list, altmode_add_to_list); + + if (ret || list_empty(&sel->mode_list)) { + mode_list_clean(sel); + kfree(sel); + return ret; + } + + list_sort(NULL, &sel->mode_list, compare_priorities); + sel->partner =3D partner; + sel->delay =3D delay; + sel->timeout =3D timeout; + mutex_init(&sel->lock); + partner->sel =3D sel; + INIT_DELAYED_WORK(&sel->work, mode_selection_work_fn); + schedule_delayed_work(&sel->work, msecs_to_jiffies(delay)); + + return 0; +} +EXPORT_SYMBOL_GPL(typec_mode_selection_start); + +void typec_mode_selection_delete(struct typec_partner *partner) +{ + struct mode_selection *sel =3D partner->sel; + + if (sel) { + partner->sel =3D NULL; + cancel_delayed_work_sync(&sel->work); + mode_list_clean(sel); + mutex_destroy(&sel->lock); + kfree(sel); + } +} +EXPORT_SYMBOL_GPL(typec_mode_selection_delete); diff --git a/include/linux/usb/typec_altmode.h b/include/linux/usb/typec_al= tmode.h index 2c3b6bec2eca..a240d8264b92 100644 --- a/include/linux/usb/typec_altmode.h +++ b/include/linux/usb/typec_altmode.h @@ -232,4 +232,44 @@ void typec_altmode_unregister_driver(struct typec_altm= ode_driver *drv); module_driver(__typec_altmode_driver, typec_altmode_register_driver, \ typec_altmode_unregister_driver) =20 +/** + * typec_mode_selection_start - Start an alternate mode selection process + * @partner: Handle to the Type-C partner device + * @delay: Delay between mode entry/exit attempts, ms + * @timeout: Timeout for a mode entry attempt, ms + * + * This function initiates the process of attempting to enter an Alternate= Mode + * supported by the connected Type-C partner. + * Returns 0 on success, or a negative error code on failure. + */ +int typec_mode_selection_start(struct typec_partner *partner, + const unsigned int delay, const unsigned int timeout); + +/** + * typec_altmode_state_update - Report the current status of an Alternate = Mode + * negotiation + * @partner: Handle to the Type-C partner device + * @svid: Standard or Vendor ID of the Alternate Mode. A value of 0 should= be + * passed if no mode is currently active + * @result: Result of the entry operation. This should be 0 on success, or= a + * negative error code if the negotiation failed + * + * This function should be called by an Alternate Mode driver to report the + * result of an asynchronous alternate mode entry request. It signals what= the + * current active SVID is (or 0 if none) and the success or failure status= of + * the last attempt. + */ +void typec_altmode_state_update(struct typec_partner *partner, const u16 s= vid, + const int result); + +/** + * typec_mode_selection_delete - Delete an alternate mode selection instan= ce + * @partner: Handle to the Type-C partner device. + * + * This function cancels a pending alternate mode selection request that w= as + * previously started with typec_mode_selection_start(). + * This is typically called when the partner disconnects. + */ +void typec_mode_selection_delete(struct typec_partner *partner); + #endif /* __USB_TYPEC_ALTMODE_H */ --=20 2.52.0.158.g65b55ccf14-goog From nobody Mon Dec 1 21:30:56 2025 Received: from mail-ed1-f48.google.com (mail-ed1-f48.google.com [209.85.208.48]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9CC0230BF77 for ; Mon, 1 Dec 2025 12:26:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.48 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764591980; cv=none; b=doG/e/1F9Wbgli7/IJM71OcGBBRq0+OzO+uLL0eNWUWneVdHTEKVGRWrnZrf/4dGgOD3v6CFTl2WYWF8/XvOeuLOJnVXV4ET9UK3beym9ECaF8FeWCVGlETmjq4IpEGTD+AeoJ5JdHJjK1yEPC30jb+oNpmchbCBBg0RN63MbIA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764591980; c=relaxed/simple; bh=6VDUNhFKjIyxAfmAoMmcN/eMripBuE0sbN890k7u5Co=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=uGiesR439jDBrphwH7CeVCr010fX3Ls/ArlMN8wMyuvlbjBzGdAL7tke4rz6SrWEjKP6JWSXT1ScNJzVBC24ZVvCf+1Irv9lWUyl4SuyJFKfZTn6wgbocex/XEEisK0OhKpQGDWV+YKyQlI2DUEt5vZ5PXjeWNT/tTubkfkuTBI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=chromium.org; spf=pass smtp.mailfrom=chromium.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b=UpPT4Zoe; arc=none smtp.client-ip=209.85.208.48 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=chromium.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="UpPT4Zoe" Received: by mail-ed1-f48.google.com with SMTP id 4fb4d7f45d1cf-64162c04f90so7795783a12.0 for ; Mon, 01 Dec 2025 04:26:18 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; t=1764591977; x=1765196777; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=OjAcK5jQuv2kklMSEXof63giOR/XCPNAsoShF6a7bVw=; b=UpPT4ZoeVHXHl59Vz3mg1aWK8Bg+Y2G78tqyTR+u93i9qxlrYWsDH/CSft5fSF2J/K aPMZV3to8k/rCzJZLA/3/gTzjQ6MwCYhhBIH54nZDqJ4+lmqmtCKJDSgM14msRdzIjQ6 /zX75RCprvagV65UZ5zbLqh6Zz3AvIZESa25A= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1764591977; x=1765196777; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=OjAcK5jQuv2kklMSEXof63giOR/XCPNAsoShF6a7bVw=; b=figHgpaBzYA1zPnsnoGQtrS+xkuH0ZTkOYEQEq4+Vu1CuN2Ff95FLQ9V8l5eXikXYa qVF4lH+U2zu+8iRXJISG1Ib//YpIgy4VF8sJE3chimVopagJYM5SxBSZFBtrUKMmem37 HlzTYD89/6IWoQxO+iatbDj99selW5K4TsE+E49e1oHb8HAqcUKd46CRjRACSSBur3qu Zr581OK8SNeFh81FvrHUoDT13VTfdRlTUnKjgeMl7aAgdgcWy7YOeB610uAZo3ike1pA ace+dzr9OOMa0AmGxy6qZFD46OlnEQmkLW/W+ynTYVV39S5FI/NxNHpYMVeR8iy/Y+/8 xQ5Q== X-Forwarded-Encrypted: i=1; AJvYcCVytlpSLKbwCCI29goTJhxsXSFsrZEjIdSxHQuOnplqb4SuMSVWtUsGWbJkNIa9YG7sk0ZdmoJXQTbCEaQ=@vger.kernel.org X-Gm-Message-State: AOJu0YyXOGInRBgMtCB+FMfdUQBZZU0FO0gB8SvFXLnJA5mST5JJlnFg 07scvA1Cg+9zAfj0kSvH3gx45mc7IiX2iIdBAcroegXd83rdyde+noI9POcNDssa0g== X-Gm-Gg: ASbGncv8Z/t0YfCqDnVIlbuMCAPK8aVgxtRwG3Lb7MqzwAGYg/rXGT1hl/neqbtGOkC VUIUmaR4ChTwtx4dyyPDSm41lWqxY2TOQa8elR5Db0FLybLEVKyz3l0ZaMJT2kmDoMpK9Wd0vSK ofmikF9CbvsrwAnIkiDSMJhwLoI5kBudxaHmvkWaTysSh9Q42Blw0gxfwF2tWPlup+X5x4TeVQP KN4y42Om9pSHAHXGngiYcPJpI1o8hkw9sqrM+Ajx0B1B6GtsnZjXPZUGW0bUKcB1FmGL64DhD1u dtp7Fa+bh6q9ZK7K8FAY2/qfKAC3wdGe+q0yFvixfWFFN6c6XP0nHNjLJUrK/clFrnQwfFOAz2O 4cwh4iBqAxH+NaMCVmX4qZHHmwtrCgOUmDgjIUdjYKa85AGMCAApONT7LcYjPOfuATnPjfNAu/r mF9Z/kp3s3eaLCdlYfq8VB3cN1e2tVTTM10mnJJFmgOPGLUZSe4/u9RFBnBFxzdSVxDXLcwE7+0 SJ4c+CxnBs= X-Google-Smtp-Source: AGHT+IG3kfMAbGwiNdUyy1C0roJ6R6b1shoAdCyb+csyZ1jwsKMGfN9QjFVoFo8tRijm4LmBgMo8uQ== X-Received: by 2002:a17:907:6eaa:b0:b71:854:4e49 with SMTP id a640c23a62f3a-b767189cf54mr4375094666b.56.1764591976789; Mon, 01 Dec 2025 04:26:16 -0800 (PST) Received: from akuchynski.c.googlers.com.com (218.127.147.34.bc.googleusercontent.com. [34.147.127.218]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-b76f519e331sm1229049266b.24.2025.12.01.04.26.16 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 01 Dec 2025 04:26:16 -0800 (PST) From: Andrei Kuchynski To: Heikki Krogerus , Abhishek Pandit-Subedi , Benson Leung , Jameson Thies , Tzung-Bi Shih , linux-usb@vger.kernel.org, chrome-platform@lists.linux.dev Cc: Guenter Roeck , Greg Kroah-Hartman , Dmitry Baryshkov , "Christian A. Ehrhardt" , Abel Vesa , Pooja Katiyar , Pavan Holla , Madhu M , Venkat Jayaraman , linux-kernel@vger.kernel.org, Andrei Kuchynski Subject: [PATCH RFC 2/8] usb: typec: Integrate USB4 into the mode selection process Date: Mon, 1 Dec 2025 12:25:58 +0000 Message-ID: <20251201122604.1268071-3-akuchynski@chromium.org> X-Mailer: git-send-email 2.52.0.158.g65b55ccf14-goog In-Reply-To: <20251201122604.1268071-1-akuchynski@chromium.org> References: <20251201122604.1268071-1-akuchynski@chromium.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" USB4 is defined as the most preferred mode and is placed at the top of the mode priority list. This ensures that if the port and partner support USB4, activation is attempted first. Activation is handled via the `enter_usb_mode` function. System control (enabling/disabling) over the mode is exposed through the `usb_capability` sysfs port attribute. Signed-off-by: Andrei Kuchynski --- drivers/usb/typec/mode_selection.c | 27 +++++++++++++++++++++++++-- include/linux/usb/typec_altmode.h | 2 ++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/drivers/usb/typec/mode_selection.c b/drivers/usb/typec/mode_se= lection.c index 1cf8a4dcd742..957e09813831 100644 --- a/drivers/usb/typec/mode_selection.c +++ b/drivers/usb/typec/mode_selection.c @@ -74,6 +74,7 @@ static int mode_selection_activate(struct mode_selection = *sel, =20 __must_hold(&sel->lock) { + struct typec_port *port =3D to_typec_port(sel->partner->dev.parent); struct mode_order order =3D {.svid =3D svid, .enter =3D enter, .result = =3D -ENODEV}; =20 /* @@ -85,7 +86,14 @@ static int mode_selection_activate(struct mode_selection= *sel, * interval. */ mutex_unlock(&sel->lock); - device_for_each_child(&sel->partner->dev, &order, activate_altmode); + if (svid =3D=3D USB_TYPEC_USB4_SID) { + if (port->ops && port->ops->enter_usb_mode) + order.result =3D port->ops->enter_usb_mode(port, + enter ? USB_MODE_USB4 : USB_MODE_USB3); + else + order.result =3D -EOPNOTSUPP; + } else + device_for_each_child(&sel->partner->dev, &order, activate_altmode); mutex_lock(&sel->lock); =20 return order.result; @@ -236,7 +244,9 @@ static int altmode_add_to_list(struct device *dev, void= *data) int typec_mode_selection_start(struct typec_partner *partner, const unsigned int delay, const unsigned int timeout) { + struct typec_port *port =3D to_typec_port(partner->dev.parent); struct mode_selection *sel; + struct mode_state *ms; int ret; =20 if (partner->sel) @@ -251,13 +261,26 @@ int typec_mode_selection_start(struct typec_partner *= partner, ret =3D device_for_each_child( &partner->dev, &sel->mode_list, altmode_add_to_list); =20 + if (!ret) { + list_sort(NULL, &sel->mode_list, compare_priorities); + + if (port->usb_mode =3D=3D USB_MODE_USB4 && + partner->usb_capability & USB_CAPABILITY_USB4 && + port->ops && port->ops->enter_usb_mode) { + ms =3D create_mode_entry(USB_TYPEC_USB4_SID, 0); + if (!ms) + ret =3D -ENOMEM; + else + list_add(&ms->list, &sel->mode_list); + } + } + if (ret || list_empty(&sel->mode_list)) { mode_list_clean(sel); kfree(sel); return ret; } =20 - list_sort(NULL, &sel->mode_list, compare_priorities); sel->partner =3D partner; sel->delay =3D delay; sel->timeout =3D timeout; diff --git a/include/linux/usb/typec_altmode.h b/include/linux/usb/typec_al= tmode.h index a240d8264b92..faf72e4d6ceb 100644 --- a/include/linux/usb/typec_altmode.h +++ b/include/linux/usb/typec_altmode.h @@ -9,6 +9,8 @@ =20 #define MODE_DISCOVERY_MAX 6 =20 +#define USB_TYPEC_USB4_SID 0xFF00 + struct typec_altmode_ops; =20 /** --=20 2.52.0.158.g65b55ccf14-goog From nobody Mon Dec 1 21:30:56 2025 Received: from mail-ej1-f51.google.com (mail-ej1-f51.google.com [209.85.218.51]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DD40B30CD8D for ; Mon, 1 Dec 2025 12:26:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.218.51 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764591983; cv=none; b=GBZSDhGSSSXQwL3CVg90YfJtvc7RSkpLEIiVQf6YducM57UpAY5EENJZXScydA/Bwfbmv8VXPPFvG3B+eKsNZKvY20soVPEjFddUGyzTWCaxaTtq92qp1BUPFX2jrHtkiPhXy19lS6kn53B2u6BcIIKRUOR4Mvv/ZTRdN+Dzv4Q= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764591983; c=relaxed/simple; bh=2fgxrQ6jc8GbzE02aljh/gumtmLhDqXZ2JKdgPay0tQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=LTz/apcj3SpfmPztqkHMctleUBjjH3Iw346KgrN/Bq8AC1PbTijEAY2dXk+0PJPywYQq1qbslybOKpinqJdw24q90/U2OoxEEONpzgComDPtlJfp14s5QfMKarSu0oGYXWfbyHpdMcAzj9uahNtvko/ztLb5ptPcYIrsrC484Ac= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=chromium.org; spf=pass smtp.mailfrom=chromium.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b=FlTyu7YO; arc=none smtp.client-ip=209.85.218.51 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=chromium.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="FlTyu7YO" Received: by mail-ej1-f51.google.com with SMTP id a640c23a62f3a-b7277324204so652080366b.0 for ; Mon, 01 Dec 2025 04:26:20 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; t=1764591979; x=1765196779; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=HQwsVtSafiZd3UhajYLeZRsX8ICttvoyqVoP0kXhJGQ=; b=FlTyu7YO8kqqXe2M25mbovei5S+TIqE+GJ4890teKAQvCOw/7gRd5gdzrhEkhwWdcB VjSbEH1y9xKUtuJBFt+SxmPtdM4SMf+VSB6GnzHlI7V9wtI+yL6+1ckv93orrAWT8iIB Mq17yYjva9V5DIDgHXDtSL9I2a6leq4yveZ00= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1764591979; x=1765196779; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=HQwsVtSafiZd3UhajYLeZRsX8ICttvoyqVoP0kXhJGQ=; b=Ti+sT+vVy7cuWLwC/Ce+XAz4cf1ggry70HtswgXmeiA8hWMFm8OIxcCccbc9Flv/vs 9MUw5wC4G2IbvJXn1uP19AIrrPeqOI8KCunh3hejt/xPkfJuXy321NEloQzNVOLsl4sP d8hyG6riW+WWN8xCfwvLNxt6hkXGt4SwM3y15ejeWGZF05qTljYyaW4oyMqeClbXcQPD eftDw+XsTxUrvJRNUcK27eM4ewmM08ANA6YP7TmztVVCkeRMCJrW7oN0n6RusC9dg4A6 ee01oCYOhaMahtsGrBZpYoRJnMSlO7sMdzfF53m4yoQRq7OjMf7GzfT1kBHrR20K5SRJ ax9Q== X-Forwarded-Encrypted: i=1; AJvYcCW1NfY4AGGekgyJEHKCV96h+gwXRfnX2GgBd/L3JradVofK5j+r+Etmf/rLcJO/dgZiio/jglcXYrt1GXE=@vger.kernel.org X-Gm-Message-State: AOJu0YyxGWL7J4YzhlvCRmy4YfRnNXHlx6c19jdzv/x1yKUXJ898iqQ+ 70zyp905I/yjBLNYHkChW3tFokeDs0RWAybkeBm8s3JQeFfZqiEE3EHayaNtxxZNpA== X-Gm-Gg: ASbGncvPUKsG4b+TsP3A3T/I4fT/QR9SqtVhhJ2vGBhk8qSNHTs/+u1BsAsslM/oDPB rcjI7ysdfEeAs1Kl3JW/XzBqu6Wulb2Ocj841ghThUxFWyceYRHv+Qg7y/0wQrvsnyDi2P5wp8m TzB2nWoG8+vG1coZzPoGCpgIY/iXvd3WBTQHgRAZMp+6TS8F9JuYs3Rpp/GekPobwBY+PDTKNgj cfTxpOLEZMt7MhHtGjm8ZscTyDX8elhT8kZT7FX4lK4ZbYajAJnETPkHtdQK+1hrrWAhHkR4xdw wRmRt/SfGzMRbDy2WAdsv9shQItE1otnAO2sN8DAVbPY9SIOz9A7zpduxIdd7J6Th+UKbMoRpQ2 bs4yGqa6lY2omYWpDL9sY3Vhez2PzU0qie1dUSFaqPNim3qSWLL23D8ucpbOtGeGVMCLInayZ8O +g6wwTNgK7ngFC4ubIqto8BO+4uozXZqd2XD907VrX9haCO350qfDyYWCyOdmXSoxF2SgPe9bl6 N79vwSFqxA= X-Google-Smtp-Source: AGHT+IH3FHNKiHqdnaGg19IfebqWiFqLmfFp6qr3dC+UY3zUwt8OkPTo0J+bJm2U71ymQvdRKypR8Q== X-Received: by 2002:a17:907:78a:b0:b73:5b9a:47c7 with SMTP id a640c23a62f3a-b76c555dc15mr2821605766b.51.1764591978997; Mon, 01 Dec 2025 04:26:18 -0800 (PST) Received: from akuchynski.c.googlers.com.com (218.127.147.34.bc.googleusercontent.com. [34.147.127.218]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-b76f519e331sm1229049266b.24.2025.12.01.04.26.18 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 01 Dec 2025 04:26:18 -0800 (PST) From: Andrei Kuchynski To: Heikki Krogerus , Abhishek Pandit-Subedi , Benson Leung , Jameson Thies , Tzung-Bi Shih , linux-usb@vger.kernel.org, chrome-platform@lists.linux.dev Cc: Guenter Roeck , Greg Kroah-Hartman , Dmitry Baryshkov , "Christian A. Ehrhardt" , Abel Vesa , Pooja Katiyar , Pavan Holla , Madhu M , Venkat Jayaraman , linux-kernel@vger.kernel.org, Andrei Kuchynski Subject: [PATCH RFC 3/8] usb: typec: Introduce mode_selection bit Date: Mon, 1 Dec 2025 12:25:59 +0000 Message-ID: <20251201122604.1268071-4-akuchynski@chromium.org> X-Mailer: git-send-email 2.52.0.158.g65b55ccf14-goog In-Reply-To: <20251201122604.1268071-1-akuchynski@chromium.org> References: <20251201122604.1268071-1-akuchynski@chromium.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The port driver sets this bit for an alternate mode description to indicate support for the mode selection feature. Once set, individual Alt Mode drivers will no longer attempt to activate their respective modes within their probe functions. This prevents race conditions and non-prioritized activation. The bit is not set by default. If left unset, the system retains the current behavior where Alt Mode drivers manage their own activation logic. Signed-off-by: Andrei Kuchynski --- drivers/usb/typec/altmodes/displayport.c | 6 ++++-- drivers/usb/typec/altmodes/thunderbolt.c | 2 +- drivers/usb/typec/class.c | 1 + include/linux/usb/typec.h | 1 + include/linux/usb/typec_altmode.h | 1 + 5 files changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/usb/typec/altmodes/displayport.c b/drivers/usb/typec/a= ltmodes/displayport.c index 8d111ad3b71b..49d5a123e4c4 100644 --- a/drivers/usb/typec/altmodes/displayport.c +++ b/drivers/usb/typec/altmodes/displayport.c @@ -800,8 +800,10 @@ int dp_altmode_probe(struct typec_altmode *alt) if (plug) typec_altmode_set_drvdata(plug, dp); =20 - dp->state =3D plug ? DP_STATE_ENTER_PRIME : DP_STATE_ENTER; - schedule_work(&dp->work); + if (!alt->mode_selection) { + dp->state =3D plug ? DP_STATE_ENTER_PRIME : DP_STATE_ENTER; + schedule_work(&dp->work); + } =20 return 0; } diff --git a/drivers/usb/typec/altmodes/thunderbolt.c b/drivers/usb/typec/a= ltmodes/thunderbolt.c index 6eadf7835f8f..c4c5da6154da 100644 --- a/drivers/usb/typec/altmodes/thunderbolt.c +++ b/drivers/usb/typec/altmodes/thunderbolt.c @@ -307,7 +307,7 @@ static int tbt_altmode_probe(struct typec_altmode *alt) typec_altmode_set_drvdata(alt, tbt); typec_altmode_set_ops(alt, &tbt_altmode_ops); =20 - if (tbt_ready(alt)) { + if (!alt->mode_selection && tbt_ready(alt)) { if (tbt->plug[TYPEC_PLUG_SOP_P]) tbt->state =3D TBT_STATE_SOP_P_ENTER; else if (tbt->plug[TYPEC_PLUG_SOP_PP]) diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c index 049d1829be98..cffe3c7d1671 100644 --- a/drivers/usb/typec/class.c +++ b/drivers/usb/typec/class.c @@ -639,6 +639,7 @@ typec_register_altmode(struct device *parent, alt->adev.svid =3D desc->svid; alt->adev.mode =3D desc->mode; alt->adev.vdo =3D desc->vdo; + alt->adev.mode_selection =3D desc->mode_selection; alt->roles =3D desc->roles; alt->id =3D id; =20 diff --git a/include/linux/usb/typec.h b/include/linux/usb/typec.h index 59d5fd7e4ff4..7a9dec9b0775 100644 --- a/include/linux/usb/typec.h +++ b/include/linux/usb/typec.h @@ -152,6 +152,7 @@ struct typec_altmode_desc { /* Only used with ports */ enum typec_port_data roles; bool inactive; + bool mode_selection; }; =20 void typec_partner_set_pd_revision(struct typec_partner *partner, u16 pd_r= evision); diff --git a/include/linux/usb/typec_altmode.h b/include/linux/usb/typec_al= tmode.h index faf72e4d6ceb..c72065fddb7b 100644 --- a/include/linux/usb/typec_altmode.h +++ b/include/linux/usb/typec_altmode.h @@ -31,6 +31,7 @@ struct typec_altmode { u32 vdo; unsigned int active:1; u8 priority; + bool mode_selection; =20 char *desc; const struct typec_altmode_ops *ops; --=20 2.52.0.158.g65b55ccf14-goog From nobody Mon Dec 1 21:30:56 2025 Received: from mail-ed1-f44.google.com (mail-ed1-f44.google.com [209.85.208.44]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D982E30DEA5 for ; Mon, 1 Dec 2025 12:26:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.44 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764591985; cv=none; b=FJFsLQn7k1ogQ+kToCy7LSrvgZ8fVymSUpv07EUKkVFJ1EiH6JEhEpxhCvestyMEagzRIL7DyWyIsagZyCIP7mfSKZxyt9C+P7NneNN1MiUimz578/16wCQY62grZKQyJFomPghHN+2Auvs/etTlhBOjf8SzXSK28xkS00BGR9I= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764591985; c=relaxed/simple; bh=GLVgDEZR/yW+dPBnqZM2+KBG6I9egBK1BkHdtIV8Re0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ofnQ+KFR0DUWKLTvVqDY8mNecwD28iuYHnnFv6Qy2BujaYePSJ2TugAEPL+/5CYsLkzZEgTzjot32kaMEF2wXn9MuquDNjVAnP+a38nlEjQZO1apKVn3qvLuuC8AqQiAtPfK6/LvJ5Djrkuf/oU3CKJaSqQm6Nr1QYkvFEZ12WE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=chromium.org; spf=pass smtp.mailfrom=chromium.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b=PL6kwHBC; arc=none smtp.client-ip=209.85.208.44 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=chromium.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="PL6kwHBC" Received: by mail-ed1-f44.google.com with SMTP id 4fb4d7f45d1cf-640a503fbe8so561467a12.1 for ; Mon, 01 Dec 2025 04:26:22 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; t=1764591981; x=1765196781; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=k5OrnZlcNOQDMQX5tOxuMnlnnAQiRlG+9PrDueeCn1s=; b=PL6kwHBCXaOG0GpyjSuR7vY3o72TK/qPdu4Vw7BpX/CxClIf2SLsfkMZB8d5sa80Cm XgY1fcfkuHn+QCihaVsVqQxKpYB4yTE5m86c/h/4J9Pm/EGtIzLCaPSlbE1iUpvJXn9j 8vkfiEQpeNWJ9p7bs7cnx91iYKJVX7jide8Zk= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1764591981; x=1765196781; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=k5OrnZlcNOQDMQX5tOxuMnlnnAQiRlG+9PrDueeCn1s=; b=LZvp7zIRF1tWWNIHgv4Qzf1eTVuhcSe20RJyX9/pmU4qedd2Cwz796c+OeEqibx3mT RoFM3TY5SHp2jBP2V6sUOfXePix92ElT9tRiqB3L8cUkVZreIlxwAGdb6xNc5h04KZfF aYH5bdmCOI40i5qy3nZDQYZkhqE9AYoxxOY9W3Glf6kLFWHrxGBndkT0il9znljsb4lY tXrDehJGrCrbRi9PJJbhdTBysy1SXolxyG27OJbF8DNSycghA+CIWCqmc4iR3lUDm4hk OM0cHSPJT+XEbNNm+FD2INnXGBUF1IfgK5UKl1xPewRGERkKwlFLstPoghYo5t/0n5uC FqiQ== X-Forwarded-Encrypted: i=1; AJvYcCX45NuVqoEfTbPf/G/cXFKYiaWjfgI5RIV0inB/BvbyRzVYm4ayrwNPGqSZHzFuXN0OCkykXoWgVDStA5s=@vger.kernel.org X-Gm-Message-State: AOJu0YwFguExheWKrCkGALcHcTehIYE2jHkjAmjyWD9ysQxeXIBVMEVC 36aP/v4oKaHFmRY59h/9WPv/UlkLXUT7oPbJ6aJ8yKHX/OfsrrpTnuuJBeKaZzBYLQ== X-Gm-Gg: ASbGncujzE7wC4POp9+twooXnaO/PaNRlXz4K00XfyqyOmPgShVAg8+UzPZN1jEAyNG n0TkWuHYVIlXcjv209y5EzHirk4zGJU4LEGDg33aaBUpjnv6yNwof95uEoMUXo2XoncgIgfUT8A Tbarz8EQp2/Dq5bGnWosY87pWgkKH1Gg9eCBm31LdJF001d4fo2H1NJFoMjYhvSWuAgCp//ugcG FVPL8v7jkTCqLr+wYCNcNeyFHCLjrwJJwpna9Za7TNaBy3w/hvKG5/98L5Jk8eKHBbq1GryEEq6 TjL0BjjsnPYi2bh9XLEd7NlfGRuLM4oJV/OvIDzlmIJogLxB4OTKo5PPW8l+Ty18KXbxPK5IAtK c63CqSIWtGf/hv9BLv0Pv/prACG7Yda143rGpanU1s9u2it4Nr3JBXw3EGdJLvJlV5XmcCVJ3Nq 2sy/4ZrtqmTSqfFqDmwmUBPWEFHd+mNGTJZKTHtH3jlwjz4Ic2z/ggpaDRkchYS2zuV15M5B4wM a/Z3hp5WfjIq8/mzk8J3w== X-Google-Smtp-Source: AGHT+IHo6BcWEO8aAB6UKpwKa3lU4iaGYTslO6xLm3i1HGiV97D5oGlqLdkkc3mN0VhnSOUSh5Hb2g== X-Received: by 2002:a17:907:980a:b0:b71:ea7c:e4ff with SMTP id a640c23a62f3a-b76c546d949mr2614872766b.6.1764591981126; Mon, 01 Dec 2025 04:26:21 -0800 (PST) Received: from akuchynski.c.googlers.com.com (218.127.147.34.bc.googleusercontent.com. [34.147.127.218]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-b76f519e331sm1229049266b.24.2025.12.01.04.26.20 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 01 Dec 2025 04:26:20 -0800 (PST) From: Andrei Kuchynski To: Heikki Krogerus , Abhishek Pandit-Subedi , Benson Leung , Jameson Thies , Tzung-Bi Shih , linux-usb@vger.kernel.org, chrome-platform@lists.linux.dev Cc: Guenter Roeck , Greg Kroah-Hartman , Dmitry Baryshkov , "Christian A. Ehrhardt" , Abel Vesa , Pooja Katiyar , Pavan Holla , Madhu M , Venkat Jayaraman , linux-kernel@vger.kernel.org, Andrei Kuchynski Subject: [PATCH RFC 4/8] usb: typec: ucsi: Support mode selection to activate altmodes Date: Mon, 1 Dec 2025 12:26:00 +0000 Message-ID: <20251201122604.1268071-5-akuchynski@chromium.org> X-Mailer: git-send-email 2.52.0.158.g65b55ccf14-goog In-Reply-To: <20251201122604.1268071-1-akuchynski@chromium.org> References: <20251201122604.1268071-1-akuchynski@chromium.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" If the ucsi port driver supports modes selection, it should implement `add_partner_altmodes` and `remove_partner_altmodes` ucsi operations. With these operations the driver can manage the mode selection process. Once partner altmodes are registered, `add_partner_altmodes` is called to start the mode selection. When the partner is unregistered, `remove_partner_altmodes` is supposed to stop any ongoing processes and clean up the resources. `typec_altmode_state_update` informes mode selection about the current mode of the Type-C connector. Signed-off-by: Andrei Kuchynski --- drivers/usb/typec/ucsi/ucsi.c | 17 +++++++++++++++++ drivers/usb/typec/ucsi/ucsi.h | 4 ++++ 2 files changed, 21 insertions(+) diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c index 82c3efd72639..ee96c42e9e27 100644 --- a/drivers/usb/typec/ucsi/ucsi.c +++ b/drivers/usb/typec/ucsi/ucsi.c @@ -331,6 +331,7 @@ void ucsi_altmode_update_active(struct ucsi_connector *= con) { const struct typec_altmode *altmode =3D NULL; u64 command; + u16 svid =3D 0; int ret; u8 cur; int i; @@ -355,6 +356,15 @@ void ucsi_altmode_update_active(struct ucsi_connector = *con) for (i =3D 0; con->partner_altmode[i]; i++) typec_altmode_update_active(con->partner_altmode[i], con->partner_altmode[i] =3D=3D altmode); + + if ((con->ucsi->version >=3D UCSI_VERSION_3_0 && + UCSI_CONSTAT(con, PARTNER_FLAG_USB4_GEN4)) || + (con->ucsi->version >=3D UCSI_VERSION_2_0 && + UCSI_CONSTAT(con, PARTNER_FLAG_USB4_GEN3))) + svid =3D USB_TYPEC_USB4_SID; + else if (altmode) + svid =3D altmode->svid; + typec_altmode_state_update(con->partner, svid, 0); } =20 static int ucsi_altmode_next_mode(struct typec_altmode **alt, u16 svid) @@ -635,6 +645,8 @@ static int ucsi_register_altmodes(struct ucsi_connector= *con, u8 recipient) desc.vdo =3D alt[j].mid; desc.svid =3D alt[j].svid; desc.roles =3D TYPEC_PORT_DRD; + desc.mode_selection =3D con->ucsi->ops->add_partner_altmodes && + con->ucsi->cap.features & UCSI_CAP_ALT_MODE_OVERRIDE; =20 ret =3D ucsi_register_altmode(con, &desc, recipient); if (ret) @@ -858,6 +870,9 @@ static int ucsi_check_altmodes(struct ucsi_connector *c= on) "con%d: failed to register partner alt modes (%d)\n", con->num, ret); =20 + if (con->ucsi->ops->add_partner_altmodes) + con->ucsi->ops->add_partner_altmodes(con); + /* Ignoring the errors in this case. */ if (con->partner_altmode[0]) { num_partner_am =3D ucsi_get_num_altmode(con->partner_altmode); @@ -1154,6 +1169,8 @@ static void ucsi_unregister_partner(struct ucsi_conne= ctor *con) return; =20 typec_set_mode(con->port, TYPEC_STATE_SAFE); + if (con->ucsi->ops->remove_partner_altmodes) + con->ucsi->ops->remove_partner_altmodes(con); =20 typec_partner_set_usb_power_delivery(con->partner, NULL); ucsi_unregister_partner_pdos(con); diff --git a/drivers/usb/typec/ucsi/ucsi.h b/drivers/usb/typec/ucsi/ucsi.h index f946b728c373..6e77bdbdaeae 100644 --- a/drivers/usb/typec/ucsi/ucsi.h +++ b/drivers/usb/typec/ucsi/ucsi.h @@ -75,6 +75,8 @@ struct dentry; * @update_altmodes: Squashes duplicate DP altmodes * @update_connector: Update connector capabilities before registering * @connector_status: Updates connector status, called holding connector l= ock + * @add_partner_altmodes: Start mode selection + * @remove_partner_altmodes: Clean mode selection * * Read and write routines for UCSI interface. @sync_write must wait for t= he * Command Completion Event from the PPM before returning, and @async_writ= e must @@ -93,6 +95,8 @@ struct ucsi_operations { struct ucsi_altmode *updated); void (*update_connector)(struct ucsi_connector *con); void (*connector_status)(struct ucsi_connector *con); + void (*add_partner_altmodes)(struct ucsi_connector *con); + void (*remove_partner_altmodes)(struct ucsi_connector *con); }; =20 struct ucsi *ucsi_create(struct device *dev, const struct ucsi_operations = *ops); --=20 2.52.0.158.g65b55ccf14-goog From nobody Mon Dec 1 21:30:56 2025 Received: from mail-ej1-f54.google.com (mail-ej1-f54.google.com [209.85.218.54]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id CB65F30E0D8 for ; Mon, 1 Dec 2025 12:26:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.218.54 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764591986; cv=none; b=sR7gy6ZNu3QhmJ3oWtBJ9o05A+4rBPjWJOdti1qO6ah4PYJTBjgTaCBftpJ4LMw+vVU4UJBf+T1e56wasWkL8PSUz33s1nruTyQVWGo10BUAPvSYN7JMUU7ZHjSo477nJp46Okglr3jpfrMtLxSrzyjqBOjIRr/o7d4Ipria6+M= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764591986; c=relaxed/simple; bh=EjyjRDZ14jo9PQ2gU5QebdkTOWDTQZAHb1P+d2FyXxY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Z25xz05Rq1Uapo1X9X+sT+w41t4pKzhWe8VuPKuMuqnVKkpTq+/EfMUbBYeJ/NHQ4MRxqRFUHWMJF7Lqfzm3gtLjQHxUVcXDxeUplNLp0UA6d4FRr360mcVozKtVoBcUcULX61OBuz143GNnkTgI3tgbMzE0CXf8REd+MNnJZGk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=chromium.org; spf=pass smtp.mailfrom=chromium.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b=L7xOPtmb; arc=none smtp.client-ip=209.85.218.54 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=chromium.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="L7xOPtmb" Received: by mail-ej1-f54.google.com with SMTP id a640c23a62f3a-b7355f6ef12so820968966b.3 for ; Mon, 01 Dec 2025 04:26:24 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; t=1764591983; x=1765196783; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=w3siUDoeibOS44ZiVJ7r4alLl9iFlDQ+/+PWsVjixhQ=; b=L7xOPtmbT670qlMGzeURDqdGIq++hu1bLeI6jSNk/5KGw27xXSwpxIMbKAXV40Gxez zPxh2+lpR+XNDd0viiB7dcrTh++KBpxIDE9NtDtGoI6yAKqQZhYMW8jER5r7svFUk4bu 5zTcxLcvEESP99+dkjixIC8lbtmiGF2M9DEyQ= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1764591983; x=1765196783; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=w3siUDoeibOS44ZiVJ7r4alLl9iFlDQ+/+PWsVjixhQ=; b=UI1IJjOBKHprBTcerr/4/+ALDZl3I+qcsMdWBUN4VywxEGPdMrEWxmrP2pxcgRqGb4 8+4nRkQ7CKTxGW3sewkfc0rCd0i7XOxvVyQBWkOAp4w49CISadgAqJ7t0Z6Ude5nSuOU als426cBIeNHPDSETF/RP8Z+yFO98wJcH6/tageSqDt8tQkR0buEpG0ruRlag9m2Wpxt 48otoLfgd5/LOcEdloLVQfh0gDzcXiwoYXiAd4fPcCDkQgoo4dxK4KwgTM+tWL/rOcFy RpOYQ+uGOMyG9J6kN4gEOcUOpL8nxUwSxqlCqtZQ9k/VlmPSkvU+RnRyvT29OmhPF4mm 821w== X-Forwarded-Encrypted: i=1; AJvYcCWuQnnsW9uwzTTJjzhHCKBWkpZxGgjAuNVSGAZUERUYsqKi6sBddHI8Zt8qRaQxEuIla5ljHGsJeHL2jxE=@vger.kernel.org X-Gm-Message-State: AOJu0YwphxS5wll8+A47zDaLCHFpETfYmlbu7lMSYpGsiF/zX68IIXGo oKnMvJJv1QCu05bSAvB3wW6aRpTEhWLkqH0+yhOwmaRbUe3v+sJBm5BeObi8ENXpGA== X-Gm-Gg: ASbGncvqzybwyg4R4s/5up4HRIKho3ZUmqdbeKVW9Vd5wjImsT09d5Dm6ZB/40oRZob i216A+tsKtkljuwX4xc6r3LMpMLumZOAPYFo5onqsGvstoPorO8OvVcLfkbbeJzt//5voT1hudY izTaVNXYB7DjQaEtVYxOQ74MnnQxuNmQ2a93kIG+UXzITc58w9qx7NLRkWCyutHkVv0AsGH08Hb x1lePqFbc7K7Oz7Ew4jJKBrVg/b2UvwTJsuG9jS4IvwmVPSau1KFaMQtmdL48rNF3k2NLcy46de LX1QRzMf/DIcNLxufgHGRKRgJfdxUHoX56upEG6RdyV7L+kVcWbp8ChlbQ0GUl9QZUI71UlF7TQ 3QbLO76duS/zSbr6FE7rlXCtBAc0KIf39D2SrZ97tJiOmPaBCE2+OqcmLvO11BJGKiFvRu+Kft6 IJQfqqgamHQ9Ms2xE8ynT59uFPWv8NrTJ3NaC1SSgGLkjk1bm8SGH8oddGDhUUlxiMOKxLV4n87 5l7J6nK4YE= X-Google-Smtp-Source: AGHT+IGdIbQA5fN2pjwFCGt2uQXmBVTAC2xTd2yjO+gh50cAVKF7tAIvotcRnv9TG3dRpl06Kz7Dmw== X-Received: by 2002:a17:906:fe08:b0:b72:a5bd:c585 with SMTP id a640c23a62f3a-b7671732667mr4428434466b.46.1764591983127; Mon, 01 Dec 2025 04:26:23 -0800 (PST) Received: from akuchynski.c.googlers.com.com (218.127.147.34.bc.googleusercontent.com. [34.147.127.218]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-b76f519e331sm1229049266b.24.2025.12.01.04.26.22 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 01 Dec 2025 04:26:22 -0800 (PST) From: Andrei Kuchynski To: Heikki Krogerus , Abhishek Pandit-Subedi , Benson Leung , Jameson Thies , Tzung-Bi Shih , linux-usb@vger.kernel.org, chrome-platform@lists.linux.dev Cc: Guenter Roeck , Greg Kroah-Hartman , Dmitry Baryshkov , "Christian A. Ehrhardt" , Abel Vesa , Pooja Katiyar , Pavan Holla , Madhu M , Venkat Jayaraman , linux-kernel@vger.kernel.org, Andrei Kuchynski Subject: [PATCH RFC 5/8] usb: typec: ucsi: Enforce mode selection for cros_ec_ucsi Date: Mon, 1 Dec 2025 12:26:01 +0000 Message-ID: <20251201122604.1268071-6-akuchynski@chromium.org> X-Mailer: git-send-email 2.52.0.158.g65b55ccf14-goog In-Reply-To: <20251201122604.1268071-1-akuchynski@chromium.org> References: <20251201122604.1268071-1-akuchynski@chromium.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The mode selection sequence is initiated by the driver after all partner alternate modes have been successfully registered. To prevent the Power Delivery Controller (PDC) from activating alternate modes, the driver disables all alternate modes on the connector: - During the connector registration - Upon partner disconnection When a partner is disconnected, the driver also stops the mode selection process and releases resources via `typec_mode_selection_delete`. Signed-off-by: Andrei Kuchynski --- drivers/usb/typec/ucsi/cros_ec_ucsi.c | 44 +++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/drivers/usb/typec/ucsi/cros_ec_ucsi.c b/drivers/usb/typec/ucsi= /cros_ec_ucsi.c index d753f2188e25..988a159ed778 100644 --- a/drivers/usb/typec/ucsi/cros_ec_ucsi.c +++ b/drivers/usb/typec/ucsi/cros_ec_ucsi.c @@ -16,6 +16,7 @@ #include #include #include +#include =20 #include "ucsi.h" =20 @@ -33,6 +34,11 @@ /* Number of times to attempt recovery from a write timeout before giving = up. */ #define WRITE_TMO_CTR_MAX 5 =20 +/* Delay between mode entry/exit attempts, ms */ +static const unsigned int mode_selection_delay =3D 1000; +/* Timeout for a mode entry attempt, ms */ +static const unsigned int mode_selection_timeout =3D 4000; + struct cros_ucsi_data { struct device *dev; struct ucsi *ucsi; @@ -133,6 +139,41 @@ static int cros_ucsi_sync_control(struct ucsi *ucsi, u= 64 cmd, u32 *cci) return ret; } =20 +static void cros_ucsi_disable_altmodes(struct ucsi_connector *con) +{ + struct cros_ucsi_data *udata =3D ucsi_get_drvdata(con->ucsi); + u64 command =3D UCSI_SET_NEW_CAM | UCSI_CONNECTOR_NUMBER(con->num) | + UCSI_SET_NEW_CAM_SET_AM((u64)0xFF); + int ret; + + con->ucsi->message_in_size =3D 0; + ret =3D ucsi_send_command(con->ucsi, command); + if (ret < 0) + dev_err(udata->dev, + "Unable to disable alt-modes on port %d\n", con->num); +} + +static void cros_ucsi_update_connector(struct ucsi_connector *con) +{ + if (con->ucsi->cap.features & UCSI_CAP_ALT_MODE_OVERRIDE) + cros_ucsi_disable_altmodes(con); +} + +static void cros_ucsi_add_partner_altmodes(struct ucsi_connector *con) +{ + if (con->ucsi->cap.features & UCSI_CAP_ALT_MODE_OVERRIDE) + typec_mode_selection_start(con->partner, + mode_selection_delay, mode_selection_timeout); +} + +static void cros_ucsi_remove_partner_altmodes(struct ucsi_connector *con) +{ + if (con->ucsi->cap.features & UCSI_CAP_ALT_MODE_OVERRIDE) { + typec_mode_selection_delete(con->partner); + cros_ucsi_disable_altmodes(con); + } +} + static const struct ucsi_operations cros_ucsi_ops =3D { .read_version =3D cros_ucsi_read_version, .read_cci =3D cros_ucsi_read_cci, @@ -140,6 +181,9 @@ static const struct ucsi_operations cros_ucsi_ops =3D { .read_message_in =3D cros_ucsi_read_message_in, .async_control =3D cros_ucsi_async_control, .sync_control =3D cros_ucsi_sync_control, + .update_connector =3D cros_ucsi_update_connector, + .add_partner_altmodes =3D cros_ucsi_add_partner_altmodes, + .remove_partner_altmodes =3D cros_ucsi_remove_partner_altmodes, }; =20 static void cros_ucsi_work(struct work_struct *work) --=20 2.52.0.158.g65b55ccf14-goog From nobody Mon Dec 1 21:30:57 2025 Received: from mail-ej1-f43.google.com (mail-ej1-f43.google.com [209.85.218.43]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E830F30DED1 for ; Mon, 1 Dec 2025 12:26:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.218.43 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764591988; cv=none; b=ZQTj97TJuvRao6fDMDEAWaDEt8V5XccHHzpbiaC0iO0x8fZ3H+gsUr2uIp67Pqtmc5Q97oEXnEhnaRtvdZkfCtfG7UmieY9T5c/sZOyiv9undgr0AswDK1UVRN8+qY3gpmyWFXHJLuE7f3KwQ+GNz8ehCYrujDrjL6aANUk/7xs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764591988; c=relaxed/simple; bh=fqrnPd4WduD46/XBBnyXBF4b8D6EY+CUvKdyAZAiwiY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=soZ8FJ9Cfr1KEKOAqK75MM2OKiNAabzhOsb6VRtag1ZDkN8KrQ8bNYZIrYKV9PeSeNZ7OBKP1AdCEELdrwtHf+ms/c1zzjsKNPUyzJkcn0b5OBaaXjEyMmUWqBdEHqdfWPsntL79Gw81P0oxOpQ5qF6dr9vRR3WV6EQoms9cvLo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=chromium.org; spf=pass smtp.mailfrom=chromium.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b=N24/OuYs; arc=none smtp.client-ip=209.85.218.43 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=chromium.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="N24/OuYs" Received: by mail-ej1-f43.google.com with SMTP id a640c23a62f3a-b73161849e1so993988166b.2 for ; Mon, 01 Dec 2025 04:26:26 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; t=1764591985; x=1765196785; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=8OH98ZYDJQZtNnl6fPGXU4bT8ZiUExlrTHFtG0JJc9Y=; b=N24/OuYsxvTnt0grSgvy/892SMM2pdrlfYW+21nkOn631MFZ8p4YBfiKibskb4sshg gqhpy1ZWmARgPD0g/cesbYbTN0kI6AWrI2rWYc+Icy3gMwwBNyMTZbwFjExqebsuOP5/ Xbqy95rKD27WvB0XyYnMAsfv+fFDCrcp+2WoQ= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1764591985; x=1765196785; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=8OH98ZYDJQZtNnl6fPGXU4bT8ZiUExlrTHFtG0JJc9Y=; b=dxnQRq4UN/apbl3nGic1P+Dn77f6hj5aPWIP1ugr0dJf0AdMGmhshbU4jit5CPlL9a DAXaJbPmKdyrDhQI8l5gxi7TvMpapGSAPIO19pQIwfsBxkOiB2eOEylxvKzGVXIDCNkz 35gYWN9SOwsvjjl6hF0fLbFGfC0MFMSxhWW1Ciw2RaUJBattnkQVZfKY/XgUqg2C9RdS 8bIr2YvOx1pw6+e31kcOoi8EwQTf35aRKlnaKZga3r6BBXz3d48OZmUiTttZNt01uTIE ZABHwLYzqAKJSkyjjjORS+tJkoKDqDHlhPV6nZtuohis9VYYP8ndb60fvtcvb0+wOCco 9ZzQ== X-Forwarded-Encrypted: i=1; AJvYcCUfwD19vQ0aZ2Q5qfSg1R2oyBeh9yLv4TsYWh1zpGFcckILWEUJDNImvn8PBiFoFRM5aC6KZHPhvyupqdw=@vger.kernel.org X-Gm-Message-State: AOJu0YwswlVDEMiV1FmF4h5PMW2rAud0KJu8Mkn1WJxhH2qT2MhO0dX9 csDfTIx7IMigjFtSUhwrqsOo83G9n+frcoURCYKXnCQGIb4+ditTMppCi/5rOrps2w== X-Gm-Gg: ASbGncvzj+6yJ/u5pjtbnFd8IDDHB4RFPiCQHVWJdjQ4Q3cGzc3WgaZCMGkTKdCivqY Uwj5OueFGK3hrUnC+C0c4HTmL5pMIFTjKTzgaunkjiaS5HpYRs9LwADBshcdRgMNn5ak3hMNlH6 G7PQNO2tL4SnDtdYfZvhgJTZWiLqn7PyEh/kGJQ1EMUtLop+rBuoqTJDcVNMFJqdKDufiZ4ZuYQ xaWFsaNW+GvA4AGRZEMRX7D1cWIpat35jTj2vbzN7GeK/V1CjwGL2tA6sHfj/C5JR7TgT47cYbz QJcVMwT24jFXKag1fTjx5DNaykQ9v1QLSTgNkZRx6AZeoBU74UOk3+rdmdQT+uvduyNpl/RlTlS o+O7GoYfmAbIpnMkDR5/CJkIXz+31cxBqCtklam/KWuZhRTN5XdBQUEUhwspjYqlH8Qed3TE/YD dOHKw9x1cUphtSMC01Kk1xnmwwNYc6IetentSMNydOIu7xZ7iIlSPhV/MCnDNge5q/Y2NLQFLqf v+Hf9bl/MM= X-Google-Smtp-Source: AGHT+IGnKQdr5PepexfByhiK/VHIvgqI+kwxEyqKKnfjEsKm61/OkPzj8RjDbEc+U2QIWtElauJeDw== X-Received: by 2002:a17:907:940e:b0:b74:352d:6dc1 with SMTP id a640c23a62f3a-b7671695438mr3121812966b.28.1764591985193; Mon, 01 Dec 2025 04:26:25 -0800 (PST) Received: from akuchynski.c.googlers.com.com (218.127.147.34.bc.googleusercontent.com. [34.147.127.218]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-b76f519e331sm1229049266b.24.2025.12.01.04.26.24 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 01 Dec 2025 04:26:24 -0800 (PST) From: Andrei Kuchynski To: Heikki Krogerus , Abhishek Pandit-Subedi , Benson Leung , Jameson Thies , Tzung-Bi Shih , linux-usb@vger.kernel.org, chrome-platform@lists.linux.dev Cc: Guenter Roeck , Greg Kroah-Hartman , Dmitry Baryshkov , "Christian A. Ehrhardt" , Abel Vesa , Pooja Katiyar , Pavan Holla , Madhu M , Venkat Jayaraman , linux-kernel@vger.kernel.org, Andrei Kuchynski Subject: [PATCH RFC 6/8] usb: typec: ucsi: Implement enter_usb_mode operation Date: Mon, 1 Dec 2025 12:26:02 +0000 Message-ID: <20251201122604.1268071-7-akuchynski@chromium.org> X-Mailer: git-send-email 2.52.0.158.g65b55ccf14-goog In-Reply-To: <20251201122604.1268071-1-akuchynski@chromium.org> References: <20251201122604.1268071-1-akuchynski@chromium.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" `enter_usb_mode` uses the SET_USB UCSI command to manage USB modes such as USB3, and USB4 for current and future connections. It allows port drivers and user-space applications (via the "usb_mode" partner attribute) to enable and disable USB modes on a connector. Signed-off-by: Andrei Kuchynski --- drivers/usb/typec/ucsi/ucsi.c | 22 ++++++++++++++++++++++ drivers/usb/typec/ucsi/ucsi.h | 3 +++ 2 files changed, 25 insertions(+) diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c index ee96c42e9e27..3d4c277bcd49 100644 --- a/drivers/usb/typec/ucsi/ucsi.c +++ b/drivers/usb/typec/ucsi/ucsi.c @@ -1624,7 +1624,29 @@ static int ucsi_pr_swap(struct typec_port *port, enu= m typec_role role) return ret; } =20 +static int ucsi_enter_usb_mode(struct typec_port *port, enum usb_mode mode) +{ + struct ucsi_connector *con =3D typec_get_drvdata(port); + u64 command; + int ret; + + command =3D UCSI_SET_USB | UCSI_CONNECTOR_NUMBER(con->num); + if (mode =3D=3D USB_MODE_USB3) + command |=3D UCSI_USB3_ENABLE; + else if (mode =3D=3D USB_MODE_USB4) + command |=3D UCSI_USB4_ENABLE; + + if (!ucsi_con_mutex_lock(con)) + return -ENOTCONN; + con->ucsi->message_in_size =3D 0; + ret =3D ucsi_send_command(con->ucsi, command); + ucsi_con_mutex_unlock(con); + + return ret; +} + static const struct typec_operations ucsi_ops =3D { + .enter_usb_mode =3D ucsi_enter_usb_mode, .dr_set =3D ucsi_dr_swap, .pr_set =3D ucsi_pr_swap }; diff --git a/drivers/usb/typec/ucsi/ucsi.h b/drivers/usb/typec/ucsi/ucsi.h index 6e77bdbdaeae..a5ef35d9dce5 100644 --- a/drivers/usb/typec/ucsi/ucsi.h +++ b/drivers/usb/typec/ucsi/ucsi.h @@ -219,6 +219,9 @@ void ucsi_connector_change(struct ucsi *ucsi, u8 num); #define UCSI_GET_PD_MESSAGE_TYPE_IDENTITY 4 #define UCSI_GET_PD_MESSAGE_TYPE_REVISION 5 =20 +/* SET_USB command bits */ +#define UCSI_USB3_ENABLE ((u64)1 << 23) +#define UCSI_USB4_ENABLE ((u64)1 << 24) /* -----------------------------------------------------------------------= --- */ =20 /* Error information returned by PPM in response to GET_ERROR_STATUS comma= nd. */ --=20 2.52.0.158.g65b55ccf14-goog From nobody Mon Dec 1 21:30:57 2025 Received: from mail-ej1-f48.google.com (mail-ej1-f48.google.com [209.85.218.48]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1F45330F807 for ; Mon, 1 Dec 2025 12:26:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.218.48 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764591991; cv=none; b=Ml1KiZ29poVOQE4/oQLsI1PuiWS0mGzsopwWCe3YhnS+KZ9hFLXaP5FUQmrwXjyT2xEhAtSeJripDyIgS4/YkhuBwdI5CIS6YlH4eRFgjeg0qsAsBsLveSBepFmSTHid25YCNq6135SlrydH2/Ym22dP/GDQQyASJ+IyCC/bOBg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764591991; c=relaxed/simple; bh=Aw9cRokS/uZtiRRUzr7HvgFMTdAZMAC2OR3yeCxVV8k=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=lH2NH7yZSfwF24+YMNt7Nlodl6S/S8wcIFGBR1ssVlmwvMNQR1AgKfxN3xX64jSnlbTCAbd9HJs44C0f+majIqrfSPZz/dEh19ZuewOl0S+2lMIpQblbmyRdYvAOYsd+baEcP8oupdo7BMBG+HxdMXlNlE1NKQF9sQjI9JioFb4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=chromium.org; spf=pass smtp.mailfrom=chromium.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b=K1rpz7Ru; arc=none smtp.client-ip=209.85.218.48 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=chromium.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="K1rpz7Ru" Received: by mail-ej1-f48.google.com with SMTP id a640c23a62f3a-b770f4accc0so515628966b.1 for ; Mon, 01 Dec 2025 04:26:28 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; t=1764591987; x=1765196787; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=Tm2xzdVNcbrW6Xwd+l1xE/GsVThA2I1Dhuida+Cqw6c=; b=K1rpz7RumWjD4tlEsj1XyqgMbh6/7eMxnRItyFnkAE6JSKueRwfmAiPPCzgpnU/8Qn VjvfXmbCjbmHVFfIorVPVrYYz25qPcxgAqFN7F3Fj94JdcoBQ/MZe3Bjlt+dec2w6Zxc AP49oy79Wb7n5maf9l+RQN4nAX5sxWJ+9Cvdo= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1764591987; x=1765196787; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=Tm2xzdVNcbrW6Xwd+l1xE/GsVThA2I1Dhuida+Cqw6c=; b=jOsUH74R+TAktQFIUMpqRDiMhqx+eVwzqozw8/YTqU3fJKf4rQddXAMcYklpoasDj6 zwG2Pyozmq0N6B/jQ3ngMPyLvhC/Kjl8z9Pf6zecIiaELyBX4QaJVmAJugLfNohnid3N X9NtBFF1kgQIXnvZoaDE7DuQ1j5S5zwzasmr3mywbz5I6FiS3LiUDDa2nXteYQYTBNf8 TMFyrQVXdJGqvjeafzPIJ6CuZKgF4ToSJy0S5xxSZv7CIp+5MOthStynozXeKAnt3SBx eCga07uH11pitUe0fpQE0zuzBq2vBmSAVRCF4+pS5b2LJVCD1yJHtIBY50YEeY2gD6lk pyuw== X-Forwarded-Encrypted: i=1; AJvYcCUVhQyPkKMefAAnddRTftqskaEb+8gXc304G3YzlytRMp9Wgm1i/J8Us2NqpnaqTKM98lAOU9dj6bDU/is=@vger.kernel.org X-Gm-Message-State: AOJu0YwYgv73kawr3G0RoK1+zl4M+r5v9tFHz0SZlFmhjdN38xP6vEfU VLaYMQ3FSY9LJCXA6V5OAwsd5ELT7ddJtsrwSEZq+8YcmsA0D/CIzH0mLiMwKkq/KQ== X-Gm-Gg: ASbGnct6wcTWDQicbouHfUbQG464e3M4R9NJQ7qgEpjmTVo9ae8KzSUYDmXbJqQ5Z8U d03YO6YssE9jCf3/VqS3v9uIaDPhTx/z8gEqINkJsDjIEuFjIbp3rTC2BlINNPR7stLSAQihQ8/ XNk7rwplbZgW41yWUbkYU92cenotptxd0QsLFZ1Nbp9AbQgHbPZhr6VdYl0qI7xA+Vi90g+tBo8 Fx4wHGY2vhUhchSFedCtULWKqeIqhblh/W32//slYA2NvxjdFIzETCmFewDE5O+y4Fe1DjKc/xi HBAhaC3bpHZyRgzb1OvVz4nwVfJYEVeF9RNCQlw3qWw18IrdgOdylSHn6iJts79B5cLGH6ANp2m 6BbY3UWY2/I2fe5qwngUXpqx77do7wFBJU1lhGNPrJZBt277gAkB8kvwoqhx4odaa+RieNp4xAw QH0njR/lfIBt6fpeSZG8P+frEIgckmZlrI63IKb6io1MkYWQePDE4F9EOpUYJ5bYCBRR0EA9EIF pR8GCptFEw= X-Google-Smtp-Source: AGHT+IGhiJudIaKRHf4l8rAikemNGaJh4kR2eXwxXLj3hd7r42POxmccuoXvUuS74QXXqJ13JrDiDQ== X-Received: by 2002:a17:907:7f19:b0:b73:9b49:2dc7 with SMTP id a640c23a62f3a-b76c558f4b0mr2627081066b.52.1764591987274; Mon, 01 Dec 2025 04:26:27 -0800 (PST) Received: from akuchynski.c.googlers.com.com (218.127.147.34.bc.googleusercontent.com. [34.147.127.218]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-b76f519e331sm1229049266b.24.2025.12.01.04.26.26 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 01 Dec 2025 04:26:26 -0800 (PST) From: Andrei Kuchynski To: Heikki Krogerus , Abhishek Pandit-Subedi , Benson Leung , Jameson Thies , Tzung-Bi Shih , linux-usb@vger.kernel.org, chrome-platform@lists.linux.dev Cc: Guenter Roeck , Greg Kroah-Hartman , Dmitry Baryshkov , "Christian A. Ehrhardt" , Abel Vesa , Pooja Katiyar , Pavan Holla , Madhu M , Venkat Jayaraman , linux-kernel@vger.kernel.org, Andrei Kuchynski Subject: [PATCH RFC 7/8] usb: typec: ucsi: Support for Thunderbolt alt mode Date: Mon, 1 Dec 2025 12:26:03 +0000 Message-ID: <20251201122604.1268071-8-akuchynski@chromium.org> X-Mailer: git-send-email 2.52.0.158.g65b55ccf14-goog In-Reply-To: <20251201122604.1268071-1-akuchynski@chromium.org> References: <20251201122604.1268071-1-akuchynski@chromium.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" This makes it possible to bind a driver to a Thunderbolt alt mode adapter devices. Signed-off-by: Andrei Kuchynski --- drivers/usb/typec/ucsi/Makefile | 4 + drivers/usb/typec/ucsi/thunderbolt.c | 199 +++++++++++++++++++++++++++ drivers/usb/typec/ucsi/ucsi.c | 17 ++- drivers/usb/typec/ucsi/ucsi.h | 20 +++ 4 files changed, 235 insertions(+), 5 deletions(-) create mode 100644 drivers/usb/typec/ucsi/thunderbolt.c diff --git a/drivers/usb/typec/ucsi/Makefile b/drivers/usb/typec/ucsi/Makef= ile index dbc571763eff..c7e38bf01350 100644 --- a/drivers/usb/typec/ucsi/Makefile +++ b/drivers/usb/typec/ucsi/Makefile @@ -17,6 +17,10 @@ ifneq ($(CONFIG_TYPEC_DP_ALTMODE),) typec_ucsi-y +=3D displayport.o endif =20 +ifneq ($(CONFIG_TYPEC_TBT_ALTMODE),) + typec_ucsi-y +=3D thunderbolt.o +endif + obj-$(CONFIG_UCSI_ACPI) +=3D ucsi_acpi.o obj-$(CONFIG_UCSI_CCG) +=3D ucsi_ccg.o obj-$(CONFIG_UCSI_STM32G0) +=3D ucsi_stm32g0.o diff --git a/drivers/usb/typec/ucsi/thunderbolt.c b/drivers/usb/typec/ucsi/= thunderbolt.c new file mode 100644 index 000000000000..b48aba30fb9f --- /dev/null +++ b/drivers/usb/typec/ucsi/thunderbolt.c @@ -0,0 +1,199 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * UCSI Thunderbolt Alternate Mode Support + * + * Copyright 2025 Google LLC + */ + +#include +#include + +#include "ucsi.h" + +struct ucsi_tbt { + struct ucsi_connector *con; + struct typec_altmode *alt; + struct work_struct work; + + int cam; + u32 header; +}; + +static int ucsi_thunderbolt_send_set_new_cam(struct ucsi_tbt *tbt, + const int enter) +{ + int ret; + const u64 command =3D UCSI_SET_NEW_CAM | + UCSI_CONNECTOR_NUMBER(tbt->con->num) | + UCSI_SET_NEW_CAM_SET_ENTER(enter) | + UCSI_SET_NEW_CAM_SET_AM(tbt->cam); + + tbt->con->ucsi->message_in_size =3D 0; + ret =3D ucsi_send_command(tbt->con->ucsi, command); + + return ret < 0 ? ret : 0; +} + +static void ucsi_thunderbolt_work(struct work_struct *work) +{ + struct ucsi_tbt *tbt =3D container_of(work, struct ucsi_tbt, work); + const int ret =3D typec_altmode_vdm(tbt->alt, tbt->header, NULL, 0); + + if (ret) + dev_err(&tbt->alt->dev, "VDM 0x%x failed\n", tbt->header); +} + +static int ucsi_thunderbolt_send_vdm(struct ucsi_tbt *tbt, + const int cmd, const int cmdt, + const int svdm_version) +{ + if (svdm_version < 0) + return svdm_version; + + tbt->header =3D VDO(USB_TYPEC_TBT_SID, 1, svdm_version, cmd); + tbt->header |=3D VDO_OPOS(TYPEC_TBT_MODE); + tbt->header |=3D VDO_CMDT(cmdt); + + schedule_work(&tbt->work); + + return 0; +} + +static int ucsi_thunderbolt_enter(struct typec_altmode *alt, u32 *vdo) +{ + struct ucsi_tbt *tbt =3D typec_altmode_get_drvdata(alt); + struct ucsi *ucsi =3D tbt->con->ucsi; + int svdm_version; + u64 command; + u8 cur =3D 0; + int ret =3D 0; + + if (!ucsi_con_mutex_lock(tbt->con)) + return -ENOTCONN; + + command =3D UCSI_GET_CURRENT_CAM | UCSI_CONNECTOR_NUMBER(tbt->con->num); + ucsi->message_in_size =3D 0; + ret =3D ucsi_send_command(ucsi, command); + if (ret < 0) { + if (tbt->con->ucsi->version > 0x0100) + goto err_unlock; + cur =3D 0xff; + } else { + memcpy(&cur, ucsi->message_in, ucsi->message_in_size); + } + + if (cur !=3D 0xff) { + ret =3D tbt->con->port_altmode[cur] =3D=3D alt ? 0 : -EBUSY; + } else { + ret =3D ucsi_thunderbolt_send_set_new_cam(tbt, 1); + if (!ret) { + svdm_version =3D typec_altmode_get_svdm_version(alt); + ret =3D ucsi_thunderbolt_send_vdm(tbt, CMD_ENTER_MODE, CMDT_RSP_ACK, + svdm_version); + } + } + +err_unlock: + ucsi_con_mutex_unlock(tbt->con); + + return ret; +} + +static int ucsi_thunderbolt_exit(struct typec_altmode *alt) +{ + struct ucsi_tbt *tbt =3D typec_altmode_get_drvdata(alt); + int svdm_version; + int ret; + + if (!ucsi_con_mutex_lock(tbt->con)) + return -ENOTCONN; + + ret =3D ucsi_thunderbolt_send_set_new_cam(tbt, 0); + if (!ret) { + svdm_version =3D typec_altmode_get_svdm_version(alt); + ret =3D ucsi_thunderbolt_send_vdm(tbt, CMD_EXIT_MODE, CMDT_RSP_ACK, + svdm_version); + } + + ucsi_con_mutex_unlock(tbt->con); + + return ret; +} + +static int ucsi_thunderbolt_vdm(struct typec_altmode *alt, + u32 header, const u32 *data, int count) +{ + struct ucsi_tbt *tbt =3D typec_altmode_get_drvdata(alt); + const int cmd_type =3D PD_VDO_CMDT(header); + const int cmd =3D PD_VDO_CMD(header); + int svdm_version; + + if (!ucsi_con_mutex_lock(tbt->con)) + return -ENOTCONN; + + svdm_version =3D typec_altmode_get_svdm_version(alt); + if (svdm_version < 0) { + ucsi_con_mutex_unlock(tbt->con); + return svdm_version; + } + + switch (cmd_type) { + case CMDT_INIT: + if (PD_VDO_SVDM_VER(header) < svdm_version) { + svdm_version =3D PD_VDO_SVDM_VER(header); + typec_partner_set_svdm_version(tbt->con->partner, svdm_version); + } + ucsi_thunderbolt_send_vdm(tbt, cmd, CMDT_RSP_ACK, svdm_version); + break; + default: + break; + } + + ucsi_con_mutex_unlock(tbt->con); + + return 0; +} + +static const struct typec_altmode_ops ucsi_thunderbolt_ops =3D { + .enter =3D ucsi_thunderbolt_enter, + .exit =3D ucsi_thunderbolt_exit, + .vdm =3D ucsi_thunderbolt_vdm, +}; + +struct typec_altmode *ucsi_register_thunderbolt(struct ucsi_connector *con, + bool override, int offset, + struct typec_altmode_desc *desc) +{ + struct typec_altmode *alt; + struct ucsi_tbt *tbt; + + alt =3D typec_port_register_altmode(con->port, desc); + if (IS_ERR(alt) || !override) + return alt; + + tbt =3D devm_kzalloc(&alt->dev, sizeof(*tbt), GFP_KERNEL); + if (!tbt) { + typec_unregister_altmode(alt); + return ERR_PTR(-ENOMEM); + } + + tbt->cam =3D offset; + tbt->con =3D con; + tbt->alt =3D alt; + typec_altmode_set_drvdata(alt, tbt); + typec_altmode_set_ops(alt, &ucsi_thunderbolt_ops); + INIT_WORK(&tbt->work, ucsi_thunderbolt_work); + + return alt; +} + +void ucsi_thunderbolt_remove_partner(struct typec_altmode *alt) +{ + struct ucsi_tbt *tbt; + + if (alt) { + tbt =3D typec_altmode_get_drvdata(alt); + if (tbt) + cancel_work_sync(&tbt->work); + } +} diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c index 3d4c277bcd49..d2b00b3a8fd1 100644 --- a/drivers/usb/typec/ucsi/ucsi.c +++ b/drivers/usb/typec/ucsi/ucsi.c @@ -13,6 +13,7 @@ #include #include #include +#include =20 #include "ucsi.h" #include "trace.h" @@ -442,6 +443,9 @@ static int ucsi_register_altmode(struct ucsi_connector = *con, alt =3D ucsi_register_displayport(con, override, i, desc); break; + case USB_TYPEC_TBT_SID: + alt =3D ucsi_register_thunderbolt(con, override, i, desc); + break; default: alt =3D typec_port_register_altmode(con->port, desc); break; @@ -678,12 +682,15 @@ static void ucsi_unregister_altmodes(struct ucsi_conn= ector *con, u8 recipient) } =20 while (adev[i]) { - if (recipient =3D=3D UCSI_RECIPIENT_SOP && - (adev[i]->svid =3D=3D USB_TYPEC_DP_SID || - (adev[i]->svid =3D=3D USB_TYPEC_NVIDIA_VLINK_SID && - adev[i]->vdo !=3D USB_TYPEC_NVIDIA_VLINK_DBG_VDO))) { + if (recipient =3D=3D UCSI_RECIPIENT_SOP) { pdev =3D typec_altmode_get_partner(adev[i]); - ucsi_displayport_remove_partner((void *)pdev); + + if (adev[i]->svid =3D=3D USB_TYPEC_DP_SID || + (adev[i]->svid =3D=3D USB_TYPEC_NVIDIA_VLINK_SID && + adev[i]->vdo !=3D USB_TYPEC_NVIDIA_VLINK_DBG_VDO)) + ucsi_displayport_remove_partner((void *)pdev); + else if (adev[i]->svid =3D=3D USB_TYPEC_TBT_SID) + ucsi_thunderbolt_remove_partner((void *)pdev); } typec_unregister_altmode(adev[i]); adev[i++] =3D NULL; diff --git a/drivers/usb/typec/ucsi/ucsi.h b/drivers/usb/typec/ucsi/ucsi.h index a5ef35d9dce5..b405cce554af 100644 --- a/drivers/usb/typec/ucsi/ucsi.h +++ b/drivers/usb/typec/ucsi/ucsi.h @@ -242,6 +242,7 @@ void ucsi_connector_change(struct ucsi *ucsi, u8 num); #define UCSI_ERROR_SET_SINK_PATH_REJECTED BIT(14) =20 #define UCSI_SET_NEW_CAM_ENTER(x) (((x) >> 23) & 0x1) +#define UCSI_SET_NEW_CAM_SET_ENTER(x) (((x) & 1) << 23) #define UCSI_SET_NEW_CAM_GET_AM(x) (((x) >> 24) & 0xff) #define UCSI_SET_NEW_CAM_AM_MASK (0xff << 24) #define UCSI_SET_NEW_CAM_SET_AM(x) (((x) & 0xff) << 24) @@ -613,6 +614,25 @@ static inline void ucsi_displayport_remove_partner(struct typec_altmode *adev) { } #endif /* CONFIG_TYPEC_DP_ALTMODE */ =20 +#if IS_ENABLED(CONFIG_TYPEC_TBT_ALTMODE) +struct typec_altmode * +ucsi_register_thunderbolt(struct ucsi_connector *con, + bool override, int offset, + struct typec_altmode_desc *desc); + +void ucsi_thunderbolt_remove_partner(struct typec_altmode *adev); +#else +static inline struct typec_altmode * +ucsi_register_thunderbolt(struct ucsi_connector *con, + bool override, int offset, + struct typec_altmode_desc *desc) +{ + return typec_port_register_altmode(con->port, desc); +} +static inline void +ucsi_thunderbolt_remove_partner(struct typec_altmode *adev) { } +#endif /* CONFIG_TYPEC_TBT_ALTMODE */ + #ifdef CONFIG_DEBUG_FS void ucsi_debugfs_init(void); void ucsi_debugfs_exit(void); --=20 2.52.0.158.g65b55ccf14-goog From nobody Mon Dec 1 21:30:57 2025 Received: from mail-ej1-f41.google.com (mail-ej1-f41.google.com [209.85.218.41]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3EA5A30FC25 for ; Mon, 1 Dec 2025 12:26:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.218.41 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764591993; cv=none; b=tumLAovSyXRwe0TFxO1B78uXRkvpMFNMFeCmo9cJmOzdUyhaKyHgiaNEC9ncqTEvQvdN50VMctAEPpeY6zjQ74cXX9CYWsaW6Wh37mewxshQEXlWYOaJ6p5s8ePVttPKapEKAx4quEsPkqQjipeykE+I79GZoyaalzXiM4mFyvs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764591993; c=relaxed/simple; bh=8/vLyDy3MTFQaWy0TuwBeVxho4lSfebWQQDxH1LU0Dc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=rENf6HqqJ0g1YsyW8cIdG9UvYPjWQXISibs9NKK8cT/Jit+mzN8xd2JStrHE7M8bBlTvZIo1iTRlb0s3wqYFBGncDZyT4B53+/jIlMpfg1APhJY/ERkr2OXpW3F/xhRM4TEBtVYDuvykv+DSZ9TE8jcvSDsmpfqsh/GF3sDND7s= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=chromium.org; spf=pass smtp.mailfrom=chromium.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b=E2VGiZUm; arc=none smtp.client-ip=209.85.218.41 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=chromium.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="E2VGiZUm" Received: by mail-ej1-f41.google.com with SMTP id a640c23a62f3a-b73a9592fb8so1071486566b.1 for ; Mon, 01 Dec 2025 04:26:30 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; t=1764591989; x=1765196789; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=g1naprGdujl0hDct49jHvoowZM6Cf+zk8w9Ns/4eimc=; b=E2VGiZUmmrIaGREcEYJoI4EQo1pgD7y0z6T9LzM8PgL5L/TaSowXlRthWVRWirshUF RguA/ApMl1lwaGY8J8mkUYf6ryWnmDHe0E89TRm13qb1zIQ/KGBaeolVTwg8+t4VB8yi tR4p4vvK7EUwlbvbKluDAC1QOiZX5pP3mgw0E= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1764591989; x=1765196789; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=g1naprGdujl0hDct49jHvoowZM6Cf+zk8w9Ns/4eimc=; b=eYAOMt9WwQUn+VY/WvJ4tUckE3I5d3PicFMeBbHP2kA8vAiLsGAAQiT4LfekQNDvmS 5mRcdiumksOXnuCAant4a6KMCOGu2xv0EtnObILsdtRJo3ozvUCGLExL/25Pv59H0zsa EESdyjZQVc82q63ZNNKTC09GLySbu0y2HPHtCIAS32z7t/er7zk0tr80SaMjZxRaASYO UVjiW+7Y+ZOEWFqek94n4ZgJbUarhh9cNwuaGdfrkuYv6XKK9dgflAm8wTdrMtvOMxBO IbsrhJwhOqsMWMaRCuVVezF/FsSsTyQWr6IV7j57NjZCCoq7PMy6qwqTM5N40HyW8Aip F3+A== X-Forwarded-Encrypted: i=1; AJvYcCUd6DcBVdHTchHx6uVxQTMK853FsswvA0+N9W0x4IlfWxkBY91JZKmo32594ad+GeiYMuOOs7Xc981llLQ=@vger.kernel.org X-Gm-Message-State: AOJu0YwFBBCr2KwTbQ4s2fGSSgJS80ab+EU7j0aaETU3tuNyH7Y4kI18 SMOCMt3kpPQDNt5K5kLXcCQVzow2Q64tkYLjNc4TR9UgF+cqTvnxbcfkUykyfh7HSg== X-Gm-Gg: ASbGncur748XkLTok7N1wS99IEhed5NYqQxz08GR20lDgvZZmMwG5ziEFd2WVXqVfNO nmtOinLfkl7/DuOcn8mwJJ3ILc0hAbVfW5t/Z04eBeSubobURhhIPeXNmVoHPNVhta7xAH/dNIs AgrkI7L5iyzjsztmC9CBmdZfM0OI+MkERCvPg4FQrUR/+v4e3OMm7b0qLnLUunQ+YCrdyvQA3as 6RCshzpJL8zsJQGyPMly0yDtIcNbMRO8KkQ6Qk5oADTZaT1v2LWb4VN4zBtXG5xfU4eASWLzkVG ZCpF5LYeLj1VXYZt1QcnZshgdqRcT8XHduREQ1LfS8YnlCPMQCdCdjY63Xu3pbZQqwUdCm5tytY 6j3ge74XS/JCw7QRFoMfUgrymz5o+I8Aht/xS0HioQo7/PrftxdDVMCNPQ/vjFzPXfDfqn29rSz IO/n8EI1Hvr+85wKm2bCRiS53GpxWrJjfPYC7aj3wAwqxdFS5QT2Pjv5/r8iGEYerpYuCZnOant b20RJ8AGqM= X-Google-Smtp-Source: AGHT+IFu9VlvB+GE4wPCZvLjBJQVkYcCGQiYYmtpwkbYyZkwNjLgf5X/ol5wQZA4UhW+seYvD1Sedw== X-Received: by 2002:a17:907:1ca4:b0:b6d:5dbb:a1e1 with SMTP id a640c23a62f3a-b766ed8362dmr4714235166b.5.1764591989425; Mon, 01 Dec 2025 04:26:29 -0800 (PST) Received: from akuchynski.c.googlers.com.com (218.127.147.34.bc.googleusercontent.com. [34.147.127.218]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-b76f519e331sm1229049266b.24.2025.12.01.04.26.28 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 01 Dec 2025 04:26:29 -0800 (PST) From: Andrei Kuchynski To: Heikki Krogerus , Abhishek Pandit-Subedi , Benson Leung , Jameson Thies , Tzung-Bi Shih , linux-usb@vger.kernel.org, chrome-platform@lists.linux.dev Cc: Guenter Roeck , Greg Kroah-Hartman , Dmitry Baryshkov , "Christian A. Ehrhardt" , Abel Vesa , Pooja Katiyar , Pavan Holla , Madhu M , Venkat Jayaraman , linux-kernel@vger.kernel.org, Andrei Kuchynski Subject: [PATCH RFC 8/8] platform/chrome: cros_ec_typec: Enforce priority-based mode selection Date: Mon, 1 Dec 2025 12:26:04 +0000 Message-ID: <20251201122604.1268071-9-akuchynski@chromium.org> X-Mailer: git-send-email 2.52.0.158.g65b55ccf14-goog In-Reply-To: <20251201122604.1268071-1-akuchynski@chromium.org> References: <20251201122604.1268071-1-akuchynski@chromium.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" 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 --- 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/chr= ome/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))) =20 +/* Delay between mode entry/exit attempts, ms */ +static const unsigned int mode_selection_delay =3D 1000; +/* Timeout for a mode entry attempt, ms */ +static const unsigned int mode_selection_timeout =3D 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; =20 + typec_mode_selection_delete(port->partner); cros_typec_unregister_altmodes(typec, port_num, true); =20 typec_partner_set_usb_power_delivery(port->partner, NULL); @@ -400,17 +406,6 @@ static int cros_typec_register_port_altmodes(struct cr= os_typec_data *typec, struct typec_altmode_desc desc; struct typec_altmode *amode; =20 - /* All PD capable CrOS devices are assumed to support DP altmode. */ - memset(&desc, 0, sizeof(desc)); - desc.svid =3D USB_TYPEC_DP_SID; - desc.mode =3D USB_TYPEC_DP_MODE; - desc.vdo =3D DP_PORT_VDO; - amode =3D 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] =3D 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 cr= os_typec_data *typec, port->port_altmode[CROS_EC_ALTMODE_TBT] =3D amode; } =20 + /* All PD capable CrOS devices are assumed to support DP altmode. */ + memset(&desc, 0, sizeof(desc)); + desc.svid =3D USB_TYPEC_DP_SID; + desc.mode =3D USB_TYPEC_DP_MODE; + desc.vdo =3D DP_PORT_VDO; + amode =3D 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] =3D amode; + port->state.alt =3D NULL; port->state.mode =3D TYPEC_STATE_USB; port->state.data =3D NULL; @@ -742,6 +748,7 @@ static int cros_typec_configure_mux(struct cros_typec_d= ata *typec, int port_num, enum typec_orientation orientation; struct cros_typec_altmode_node *node; int ret; + u16 active_svid =3D 0; =20 ret =3D 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, =20 if (port->mux_flags & USB_PD_MUX_USB4_ENABLED) { ret =3D cros_typec_enable_usb4(typec, port_num, pd_ctrl); + active_svid =3D USB_TYPEC_USB4_SID; } else if (port->mux_flags & USB_PD_MUX_TBT_COMPAT_ENABLED) { ret =3D cros_typec_enable_tbt(typec, port_num, pd_ctrl); + active_svid =3D USB_TYPEC_TBT_SID; } else if (port->mux_flags & USB_PD_MUX_DP_ENABLED) { ret =3D cros_typec_enable_dp(typec, port_num, pd_ctrl); + active_svid =3D USB_TYPEC_DP_SID; } else if (port->mux_flags & USB_PD_MUX_SAFE_MODE) { ret =3D 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_d= ata *typec, int port_num, port->mux_flags); } =20 + 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_typ= ec_data *typec, int port_ memset(&desc, 0, sizeof(desc)); desc.svid =3D sop_disc->svids[i].svid; desc.mode =3D j + 1; + desc.mode_selection =3D typec->ap_driven_altmode; desc.vdo =3D sop_disc->svids[i].mode_vdo[j]; =20 if (is_partner) @@ -940,6 +954,17 @@ static int cros_typec_register_altmodes(struct cros_ty= pec_data *typec, int port_ goto err_cleanup; } =20 + /* Once all partner alt-modes are added, we should also trigger + * mode selection. + */ + if (is_partner && typec->ap_driven_altmode) { + ret =3D 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; =20 err_cleanup: diff --git a/drivers/platform/chrome/cros_typec_altmode.c b/drivers/platfor= m/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 =3D container_of(work, struct cros_typec_altmode_data, work); + int ret; =20 mutex_lock(&data->lock); =20 - if (typec_altmode_vdm(data->alt, data->header, data->vdo_data, - data->vdo_size)) + ret =3D 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); + } =20 data->header =3D 0; data->vdo_data =3D NULL; --=20 2.52.0.158.g65b55ccf14-goog