* [PATCH v1 0/5] USB Type-C alternate mode priorities
@ 2025-08-14 18:44 Andrei Kuchynski
2025-08-14 18:44 ` [PATCH v1 1/5] usb: typec: Add alt_mode_override field to port property Andrei Kuchynski
` (4 more replies)
0 siblings, 5 replies; 14+ messages in thread
From: Andrei Kuchynski @ 2025-08-14 18:44 UTC (permalink / raw)
To: Heikki Krogerus, Abhishek Pandit-Subedi, Benson Leung,
Jameson Thies, Tzung-Bi Shih, linux-usb, chrome-platform
Cc: Guenter Roeck, Greg Kroah-Hartman, Dmitry Baryshkov,
Christian A. Ehrhardt, Venkat Jayaraman, linux-kernel,
Andrei Kuchynski
This patch series introduces a mechanism for setting USB Type-C alternate
mode priorities. It allows the user to specify their preferred order for
mode selection, such as USB4, Thunderbolt, or DisplayPort.
A new sysfs attribute named 'priority' is exposed to provide user-space
control over the mode selection process.
This series was tested on a Android OS device running kernel 6.16.
Andrei Kuchynski (5):
usb: typec: Add alt_mode_override field to port property
platform/chrome: cros_ec_typec: Set alt_mode_override flag
usb: typec: ucsi: Set alt_mode_override flag
usb: typec: Implement alternate mode priority handling
usb: typec: Expose alternate mode priority via sysfs
Documentation/ABI/testing/sysfs-class-typec | 12 ++
drivers/platform/chrome/cros_ec_typec.c | 1 +
drivers/usb/typec/Makefile | 2 +-
drivers/usb/typec/class.c | 61 +++++++++-
drivers/usb/typec/class.h | 3 +
drivers/usb/typec/mode_selection.c | 127 ++++++++++++++++++++
drivers/usb/typec/mode_selection.h | 8 ++
drivers/usb/typec/ucsi/ucsi.c | 2 +
include/linux/usb/typec.h | 1 +
include/linux/usb/typec_altmode.h | 9 ++
10 files changed, 221 insertions(+), 5 deletions(-)
create mode 100644 drivers/usb/typec/mode_selection.c
create mode 100644 drivers/usb/typec/mode_selection.h
--
2.51.0.rc0.215.g125493bb4a-goog
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v1 1/5] usb: typec: Add alt_mode_override field to port property
2025-08-14 18:44 [PATCH v1 0/5] USB Type-C alternate mode priorities Andrei Kuchynski
@ 2025-08-14 18:44 ` Andrei Kuchynski
2025-08-20 10:53 ` Heikki Krogerus
2025-08-14 18:44 ` [PATCH v1 2/5] platform/chrome: cros_ec_typec: Set alt_mode_override flag Andrei Kuchynski
` (3 subsequent siblings)
4 siblings, 1 reply; 14+ messages in thread
From: Andrei Kuchynski @ 2025-08-14 18:44 UTC (permalink / raw)
To: Heikki Krogerus, Abhishek Pandit-Subedi, Benson Leung,
Jameson Thies, Tzung-Bi Shih, linux-usb, chrome-platform
Cc: Guenter Roeck, Greg Kroah-Hartman, Dmitry Baryshkov,
Christian A. Ehrhardt, Venkat Jayaraman, linux-kernel,
Andrei Kuchynski
This new field in the port properties dictates whether the Platform Policy
Manager (PPM) allows the OS Policy Manager (OPM) to change the currently
active, negotiated alternate mode.
Signed-off-by: Andrei Kuchynski <akuchynski@chromium.org>
---
drivers/usb/typec/class.c | 14 +++++++++++---
drivers/usb/typec/class.h | 2 ++
include/linux/usb/typec.h | 1 +
3 files changed, 14 insertions(+), 3 deletions(-)
diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c
index 67a533e35150..a72325ff099a 100644
--- a/drivers/usb/typec/class.c
+++ b/drivers/usb/typec/class.c
@@ -459,9 +459,16 @@ static umode_t typec_altmode_attr_is_visible(struct kobject *kobj,
struct typec_altmode *adev = to_typec_altmode(kobj_to_dev(kobj));
if (attr == &dev_attr_active.attr)
- if (!is_typec_port(adev->dev.parent) &&
- (!adev->ops || !adev->ops->activate))
- return 0444;
+ if (!is_typec_port(adev->dev.parent)) {
+ struct typec_partner *partner =
+ to_typec_partner(adev->dev.parent);
+ struct typec_port *port =
+ to_typec_port(partner->dev.parent);
+
+ if (!port->alt_mode_override || !adev->ops ||
+ !adev->ops->activate)
+ return 0444;
+ }
return attr->mode;
}
@@ -2681,6 +2688,7 @@ struct typec_port *typec_register_port(struct device *parent,
}
port->pd = cap->pd;
+ port->alt_mode_override = cap->alt_mode_override;
ret = device_add(&port->dev);
if (ret) {
diff --git a/drivers/usb/typec/class.h b/drivers/usb/typec/class.h
index db2fe96c48ff..f05d9201c233 100644
--- a/drivers/usb/typec/class.h
+++ b/drivers/usb/typec/class.h
@@ -80,6 +80,8 @@ struct typec_port {
*/
struct device *usb2_dev;
struct device *usb3_dev;
+
+ bool alt_mode_override;
};
#define to_typec_port(_dev_) container_of(_dev_, struct typec_port, dev)
diff --git a/include/linux/usb/typec.h b/include/linux/usb/typec.h
index 252af3f77039..6e09e68788dd 100644
--- a/include/linux/usb/typec.h
+++ b/include/linux/usb/typec.h
@@ -304,6 +304,7 @@ struct typec_capability {
enum typec_accessory accessory[TYPEC_MAX_ACCESSORY];
unsigned int orientation_aware:1;
u8 usb_capability;
+ bool alt_mode_override;
struct fwnode_handle *fwnode;
void *driver_data;
--
2.51.0.rc0.215.g125493bb4a-goog
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v1 2/5] platform/chrome: cros_ec_typec: Set alt_mode_override flag
2025-08-14 18:44 [PATCH v1 0/5] USB Type-C alternate mode priorities Andrei Kuchynski
2025-08-14 18:44 ` [PATCH v1 1/5] usb: typec: Add alt_mode_override field to port property Andrei Kuchynski
@ 2025-08-14 18:44 ` Andrei Kuchynski
2025-08-14 18:44 ` [PATCH v1 3/5] usb: typec: ucsi: " Andrei Kuchynski
` (2 subsequent siblings)
4 siblings, 0 replies; 14+ messages in thread
From: Andrei Kuchynski @ 2025-08-14 18:44 UTC (permalink / raw)
To: Heikki Krogerus, Abhishek Pandit-Subedi, Benson Leung,
Jameson Thies, Tzung-Bi Shih, linux-usb, chrome-platform
Cc: Guenter Roeck, Greg Kroah-Hartman, Dmitry Baryshkov,
Christian A. Ehrhardt, Venkat Jayaraman, linux-kernel,
Andrei Kuchynski
This flag specifies that the Embedded Controller (EC) must receive explicit
approval from the Application Processor (AP) before initiating Type-C
alternate modes or USB4 mode.
Signed-off-by: Andrei Kuchynski <akuchynski@chromium.org>
---
drivers/platform/chrome/cros_ec_typec.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/platform/chrome/cros_ec_typec.c b/drivers/platform/chrome/cros_ec_typec.c
index b712bcff6fb2..99f549263c37 100644
--- a/drivers/platform/chrome/cros_ec_typec.c
+++ b/drivers/platform/chrome/cros_ec_typec.c
@@ -491,6 +491,7 @@ static int cros_typec_init_ports(struct cros_typec_data *typec)
cap->driver_data = cros_port;
cap->ops = &cros_typec_usb_mode_ops;
+ cap->alt_mode_override = typec->ap_driven_altmode;
cros_port->port = typec_register_port(dev, cap);
if (IS_ERR(cros_port->port)) {
--
2.51.0.rc0.215.g125493bb4a-goog
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v1 3/5] usb: typec: ucsi: Set alt_mode_override flag
2025-08-14 18:44 [PATCH v1 0/5] USB Type-C alternate mode priorities Andrei Kuchynski
2025-08-14 18:44 ` [PATCH v1 1/5] usb: typec: Add alt_mode_override field to port property Andrei Kuchynski
2025-08-14 18:44 ` [PATCH v1 2/5] platform/chrome: cros_ec_typec: Set alt_mode_override flag Andrei Kuchynski
@ 2025-08-14 18:44 ` Andrei Kuchynski
2025-08-20 10:53 ` Heikki Krogerus
2025-08-14 18:44 ` [PATCH v1 4/5] usb: typec: Implement alternate mode priority handling Andrei Kuchynski
2025-08-14 18:44 ` [PATCH v1 5/5] usb: typec: Expose alternate mode priority via sysfs Andrei Kuchynski
4 siblings, 1 reply; 14+ messages in thread
From: Andrei Kuchynski @ 2025-08-14 18:44 UTC (permalink / raw)
To: Heikki Krogerus, Abhishek Pandit-Subedi, Benson Leung,
Jameson Thies, Tzung-Bi Shih, linux-usb, chrome-platform
Cc: Guenter Roeck, Greg Kroah-Hartman, Dmitry Baryshkov,
Christian A. Ehrhardt, Venkat Jayaraman, linux-kernel,
Andrei Kuchynski
This flag indicates that the PPM allows the OPM to change the currently
negotiated alternate mode using the SET_NEW_CAM command.
Signed-off-by: Andrei Kuchynski <akuchynski@chromium.org>
---
drivers/usb/typec/ucsi/ucsi.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c
index 5739ea2abdd1..5ba8b1bc874b 100644
--- a/drivers/usb/typec/ucsi/ucsi.c
+++ b/drivers/usb/typec/ucsi/ucsi.c
@@ -1616,6 +1616,8 @@ static int ucsi_register_port(struct ucsi *ucsi, struct ucsi_connector *con)
cap->driver_data = con;
cap->ops = &ucsi_ops;
+ cap->alt_mode_override =
+ !!(con->ucsi->cap.features & UCSI_CAP_ALT_MODE_OVERRIDE);
if (ucsi->ops->update_connector)
ucsi->ops->update_connector(con);
--
2.51.0.rc0.215.g125493bb4a-goog
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v1 4/5] usb: typec: Implement alternate mode priority handling
2025-08-14 18:44 [PATCH v1 0/5] USB Type-C alternate mode priorities Andrei Kuchynski
` (2 preceding siblings ...)
2025-08-14 18:44 ` [PATCH v1 3/5] usb: typec: ucsi: " Andrei Kuchynski
@ 2025-08-14 18:44 ` Andrei Kuchynski
2025-08-21 10:09 ` Heikki Krogerus
2025-08-14 18:44 ` [PATCH v1 5/5] usb: typec: Expose alternate mode priority via sysfs Andrei Kuchynski
4 siblings, 1 reply; 14+ messages in thread
From: Andrei Kuchynski @ 2025-08-14 18:44 UTC (permalink / raw)
To: Heikki Krogerus, Abhishek Pandit-Subedi, Benson Leung,
Jameson Thies, Tzung-Bi Shih, linux-usb, chrome-platform
Cc: Guenter Roeck, Greg Kroah-Hartman, Dmitry Baryshkov,
Christian A. Ehrhardt, Venkat Jayaraman, linux-kernel,
Andrei Kuchynski
This patch introduces APIs to manage the priority of USB Type-C alternate
modes. These APIs allow for setting and retrieving a priority number for
each mode. If a new priority value conflicts with an existing mode's
priority, the priorities of the conflicting mode and all subsequent modes
are automatically incremented to ensure uniqueness.
Signed-off-by: Andrei Kuchynski <akuchynski@chromium.org>
---
drivers/usb/typec/Makefile | 2 +-
drivers/usb/typec/class.h | 1 +
drivers/usb/typec/mode_selection.c | 127 +++++++++++++++++++++++++++++
drivers/usb/typec/mode_selection.h | 8 ++
include/linux/usb/typec_altmode.h | 9 ++
5 files changed, 146 insertions(+), 1 deletion(-)
create mode 100644 drivers/usb/typec/mode_selection.c
create mode 100644 drivers/usb/typec/mode_selection.h
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) += typec.o
-typec-y := class.o mux.o bus.o pd.o retimer.o
+typec-y := class.o mux.o bus.o pd.o retimer.o mode_selection.o
typec-$(CONFIG_ACPI) += port-mapper.o
obj-$(CONFIG_TYPEC) += altmodes/
obj-$(CONFIG_TYPEC_TCPM) += tcpm/
diff --git a/drivers/usb/typec/class.h b/drivers/usb/typec/class.h
index f05d9201c233..c6467e576569 100644
--- a/drivers/usb/typec/class.h
+++ b/drivers/usb/typec/class.h
@@ -82,6 +82,7 @@ struct typec_port {
struct device *usb3_dev;
bool alt_mode_override;
+ struct list_head mode_list;
};
#define to_typec_port(_dev_) container_of(_dev_, struct typec_port, dev)
diff --git a/drivers/usb/typec/mode_selection.c b/drivers/usb/typec/mode_selection.c
new file mode 100644
index 000000000000..8a54639b86bf
--- /dev/null
+++ b/drivers/usb/typec/mode_selection.c
@@ -0,0 +1,127 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright 2025 Google LLC.
+ */
+
+#include <linux/usb/typec_altmode.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include "mode_selection.h"
+#include "class.h"
+
+static const char * const mode_names[TYPEC_ALTMODE_MAX] = {
+ [TYPEC_ALTMODE_DP] = "DisplayPort",
+ [TYPEC_ALTMODE_TBT] = "Thunderbolt3",
+ [TYPEC_ALTMODE_USB4] = "USB4",
+};
+
+static const int default_priorities[TYPEC_ALTMODE_MAX] = {
+ [TYPEC_ALTMODE_DP] = 2,
+ [TYPEC_ALTMODE_TBT] = 1,
+ [TYPEC_ALTMODE_USB4] = 0,
+};
+
+static inline enum typec_mode_type typec_svid_to_altmode(const u16 svid)
+{
+ switch (svid) {
+ case USB_TYPEC_DP_SID:
+ return TYPEC_ALTMODE_DP;
+ case USB_TYPEC_TBT_SID:
+ return TYPEC_ALTMODE_TBT;
+ case USB_TYPEC_USB4_SID:
+ return TYPEC_ALTMODE_USB4;
+ }
+ return TYPEC_ALTMODE_MAX;
+}
+
+/**
+ * struct mode_selection_state - State tracking for a specific Type-C mode
+ * @mode: The type of mode this instance represents
+ * @priority: The mode priority. Lower values indicate a more preferred mode.
+ * @list: List head to link this mode state into a prioritized list.
+ */
+struct mode_selection_state {
+ enum typec_mode_type mode;
+ int priority;
+ struct list_head list;
+};
+
+/* -------------------------------------------------------------------------- */
+/* port 'mode_priorities' attribute */
+
+int typec_mode_set_priority(struct typec_altmode *adev, const int priority)
+{
+ struct typec_port *port = to_typec_port(adev->dev.parent);
+ const enum typec_mode_type mode = typec_svid_to_altmode(adev->svid);
+ struct mode_selection_state *ms_target = NULL;
+ struct mode_selection_state *ms, *tmp;
+
+ if (mode >= TYPEC_ALTMODE_MAX || !mode_names[mode])
+ return -EOPNOTSUPP;
+
+ list_for_each_entry_safe(ms, tmp, &port->mode_list, list) {
+ if (ms->mode == mode) {
+ ms_target = ms;
+ list_del(&ms->list);
+ break;
+ }
+ }
+
+ if (!ms_target) {
+ ms_target = kzalloc(sizeof(struct mode_selection_state), GFP_KERNEL);
+ if (!ms_target)
+ return -ENOMEM;
+ ms_target->mode = mode;
+ INIT_LIST_HEAD(&ms_target->list);
+ }
+
+ if (priority >= 0)
+ ms_target->priority = priority;
+ else
+ ms_target->priority = default_priorities[mode];
+
+ while (ms_target) {
+ struct mode_selection_state *ms_peer = NULL;
+
+ list_for_each_entry(ms, &port->mode_list, list)
+ if (ms->priority >= ms_target->priority) {
+ if (ms->priority == ms_target->priority)
+ ms_peer = ms;
+ break;
+ }
+
+ list_add_tail(&ms_target->list, &ms->list);
+ ms_target = ms_peer;
+ if (ms_target) {
+ ms_target->priority++;
+ list_del(&ms_target->list);
+ }
+ }
+
+ return 0;
+}
+
+int typec_mode_get_priority(struct typec_altmode *adev, int *priority)
+{
+ struct typec_port *port = to_typec_port(adev->dev.parent);
+ const enum typec_mode_type mode = typec_svid_to_altmode(adev->svid);
+ struct mode_selection_state *ms;
+
+ list_for_each_entry(ms, &port->mode_list, list)
+ if (ms->mode == mode) {
+ *priority = ms->priority;
+ return 0;
+ }
+
+ return -EOPNOTSUPP;
+}
+
+void typec_mode_selection_destroy(struct typec_port *port)
+{
+ struct mode_selection_state *ms, *tmp;
+
+ list_for_each_entry_safe(ms, tmp, &port->mode_list, list) {
+ list_del(&ms->list);
+ kfree(ms);
+ }
+}
diff --git a/drivers/usb/typec/mode_selection.h b/drivers/usb/typec/mode_selection.h
new file mode 100644
index 000000000000..69adfcf39d7c
--- /dev/null
+++ b/drivers/usb/typec/mode_selection.h
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#include <linux/usb/typec_dp.h>
+#include <linux/usb/typec_tbt.h>
+
+int typec_mode_set_priority(struct typec_altmode *adev, const int priority);
+int typec_mode_get_priority(struct typec_altmode *adev, int *priority);
+void typec_mode_selection_destroy(struct typec_port *port);
diff --git a/include/linux/usb/typec_altmode.h b/include/linux/usb/typec_altmode.h
index b3c0866ea70f..318858fc7bec 100644
--- a/include/linux/usb/typec_altmode.h
+++ b/include/linux/usb/typec_altmode.h
@@ -145,6 +145,15 @@ enum {
#define TYPEC_MODAL_STATE(_state_) ((_state_) + TYPEC_STATE_MODAL)
+#define USB_TYPEC_USB4_SID 0xff00
+
+enum typec_mode_type {
+ TYPEC_ALTMODE_DP = 0,
+ TYPEC_ALTMODE_TBT,
+ TYPEC_ALTMODE_USB4,
+ TYPEC_ALTMODE_MAX,
+};
+
struct typec_altmode *typec_altmode_get_plug(struct typec_altmode *altmode,
enum typec_plug_index index);
void typec_altmode_put_plug(struct typec_altmode *plug);
--
2.51.0.rc0.215.g125493bb4a-goog
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v1 5/5] usb: typec: Expose alternate mode priority via sysfs
2025-08-14 18:44 [PATCH v1 0/5] USB Type-C alternate mode priorities Andrei Kuchynski
` (3 preceding siblings ...)
2025-08-14 18:44 ` [PATCH v1 4/5] usb: typec: Implement alternate mode priority handling Andrei Kuchynski
@ 2025-08-14 18:44 ` Andrei Kuchynski
2025-08-21 7:36 ` Heikki Krogerus
4 siblings, 1 reply; 14+ messages in thread
From: Andrei Kuchynski @ 2025-08-14 18:44 UTC (permalink / raw)
To: Heikki Krogerus, Abhishek Pandit-Subedi, Benson Leung,
Jameson Thies, Tzung-Bi Shih, linux-usb, chrome-platform
Cc: Guenter Roeck, Greg Kroah-Hartman, Dmitry Baryshkov,
Christian A. Ehrhardt, Venkat Jayaraman, linux-kernel,
Andrei Kuchynski
This patch introduces a priority sysfs attribute to the USB Type-C
alternate mode port interface. This new attribute allows user-space to
configure the numeric priority of alternate modes managing their preferred
order of operation.
Signed-off-by: Andrei Kuchynski <akuchynski@chromium.org>
---
Documentation/ABI/testing/sysfs-class-typec | 12 ++++++
drivers/usb/typec/class.c | 47 ++++++++++++++++++++-
2 files changed, 58 insertions(+), 1 deletion(-)
diff --git a/Documentation/ABI/testing/sysfs-class-typec b/Documentation/ABI/testing/sysfs-class-typec
index 38e101c17a00..001202d651fa 100644
--- a/Documentation/ABI/testing/sysfs-class-typec
+++ b/Documentation/ABI/testing/sysfs-class-typec
@@ -162,6 +162,18 @@ Description: Lists the supported USB Modes. The default USB mode that is used
- usb3 (USB 3.2)
- usb4 (USB4)
+ What: /sys/class/typec/<port>/<alt-mode>/priority
+Date: July 2025
+Contact: Andrei Kuchynski <akuchynski@chromium.org>
+Description:
+ Displays and allows setting the priority for a specific alt-mode.
+ When read, it shows the current integer priority value. Lower numerical
+ values indicate higher priority (0 is the highest priority).
+ If the new value is already in use by another mode, the priority of the
+ conflicting mode and any subsequent modes will be incremented until they
+ are all unique.
+ This attribute is visible only if the kernel supports mode selection.
+
USB Type-C partner devices (eg. /sys/class/typec/port0-partner/)
What: /sys/class/typec/<port>-partner/accessory_mode
diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c
index a72325ff099a..708f3487222a 100644
--- a/drivers/usb/typec/class.c
+++ b/drivers/usb/typec/class.c
@@ -19,6 +19,7 @@
#include "bus.h"
#include "class.h"
#include "pd.h"
+#include "mode_selection.h"
static DEFINE_IDA(typec_index_ida);
@@ -445,11 +446,41 @@ svid_show(struct device *dev, struct device_attribute *attr, char *buf)
}
static DEVICE_ATTR_RO(svid);
+static ssize_t priority_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ unsigned int val;
+ int err = kstrtouint(buf, 10, &val);
+
+ if (!err) {
+ err = typec_mode_set_priority(to_typec_altmode(dev), val);
+ if (!err)
+ return size;
+ }
+
+ return err;
+}
+
+static ssize_t priority_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int val;
+ const int err = typec_mode_get_priority(to_typec_altmode(dev), &val);
+
+ if (err)
+ return err;
+
+ return sprintf(buf, "%d\n", val);
+}
+static DEVICE_ATTR_RW(priority);
+
static struct attribute *typec_altmode_attrs[] = {
&dev_attr_active.attr,
&dev_attr_mode.attr,
&dev_attr_svid.attr,
&dev_attr_vdo.attr,
+ &dev_attr_priority.attr,
NULL
};
@@ -458,7 +489,7 @@ static umode_t typec_altmode_attr_is_visible(struct kobject *kobj,
{
struct typec_altmode *adev = to_typec_altmode(kobj_to_dev(kobj));
- if (attr == &dev_attr_active.attr)
+ if (attr == &dev_attr_active.attr) {
if (!is_typec_port(adev->dev.parent)) {
struct typec_partner *partner =
to_typec_partner(adev->dev.parent);
@@ -469,6 +500,15 @@ static umode_t typec_altmode_attr_is_visible(struct kobject *kobj,
!adev->ops->activate)
return 0444;
}
+ } else if (attr == &dev_attr_priority.attr) {
+ if (is_typec_port(adev->dev.parent)) {
+ struct typec_port *port = to_typec_port(adev->dev.parent);
+
+ if (!port->alt_mode_override)
+ return 0;
+ } else
+ return 0;
+ }
return attr->mode;
}
@@ -2029,6 +2069,7 @@ static void typec_release(struct device *dev)
typec_mux_put(port->mux);
typec_retimer_put(port->retimer);
kfree(port->cap);
+ typec_mode_selection_destroy(port);
kfree(port);
}
@@ -2496,6 +2537,8 @@ typec_port_register_altmode(struct typec_port *port,
to_altmode(adev)->retimer = retimer;
}
+ typec_mode_set_priority(adev, -1);
+
return adev;
}
EXPORT_SYMBOL_GPL(typec_port_register_altmode);
@@ -2645,6 +2688,8 @@ struct typec_port *typec_register_port(struct device *parent,
port->con.attach = typec_partner_attach;
port->con.deattach = typec_partner_deattach;
+ INIT_LIST_HEAD(&port->mode_list);
+
if (cap->usb_capability & USB_CAPABILITY_USB4)
port->usb_mode = USB_MODE_USB4;
else if (cap->usb_capability & USB_CAPABILITY_USB3)
--
2.51.0.rc0.215.g125493bb4a-goog
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH v1 1/5] usb: typec: Add alt_mode_override field to port property
2025-08-14 18:44 ` [PATCH v1 1/5] usb: typec: Add alt_mode_override field to port property Andrei Kuchynski
@ 2025-08-20 10:53 ` Heikki Krogerus
2025-08-21 14:19 ` Andrei Kuchynski
0 siblings, 1 reply; 14+ messages in thread
From: Heikki Krogerus @ 2025-08-20 10:53 UTC (permalink / raw)
To: Andrei Kuchynski
Cc: Abhishek Pandit-Subedi, Benson Leung, Jameson Thies,
Tzung-Bi Shih, linux-usb, chrome-platform, Guenter Roeck,
Greg Kroah-Hartman, Dmitry Baryshkov, Christian A. Ehrhardt,
Venkat Jayaraman, linux-kernel
On Thu, Aug 14, 2025 at 06:44:51PM +0000, Andrei Kuchynski wrote:
> This new field in the port properties dictates whether the Platform Policy
> Manager (PPM) allows the OS Policy Manager (OPM) to change the currently
> active, negotiated alternate mode.
>
> Signed-off-by: Andrei Kuchynski <akuchynski@chromium.org>
> ---
> drivers/usb/typec/class.c | 14 +++++++++++---
> drivers/usb/typec/class.h | 2 ++
> include/linux/usb/typec.h | 1 +
> 3 files changed, 14 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c
> index 67a533e35150..a72325ff099a 100644
> --- a/drivers/usb/typec/class.c
> +++ b/drivers/usb/typec/class.c
> @@ -459,9 +459,16 @@ static umode_t typec_altmode_attr_is_visible(struct kobject *kobj,
> struct typec_altmode *adev = to_typec_altmode(kobj_to_dev(kobj));
>
> if (attr == &dev_attr_active.attr)
> - if (!is_typec_port(adev->dev.parent) &&
> - (!adev->ops || !adev->ops->activate))
> - return 0444;
> + if (!is_typec_port(adev->dev.parent)) {
> + struct typec_partner *partner =
> + to_typec_partner(adev->dev.parent);
That looks a bit unnecessary. Also, can't the altmode be a plug alt mode?
> + struct typec_port *port =
> + to_typec_port(partner->dev.parent);
> +
> + if (!port->alt_mode_override || !adev->ops ||
> + !adev->ops->activate)
> + return 0444;
> + }
How about:
struct typec_altmode *adev = to_typec_altmode(kobj_to_dev(kobj));
struct typec_port *port = typec_altmode2port(adev);
if (attr == &dev_attr_active.attr) {
if (!is_typec_port(adev->dev.parent)) {
if (!port->alt_mode_override || !adev->ops || !adev->ops->activate)
return 0444;
}
}
> return attr->mode;
> }
> @@ -2681,6 +2688,7 @@ struct typec_port *typec_register_port(struct device *parent,
> }
>
> port->pd = cap->pd;
> + port->alt_mode_override = cap->alt_mode_override;
This needs to be enabled by default:
port->alt_mode_override = !cap->no_mode_control;
> ret = device_add(&port->dev);
> if (ret) {
> diff --git a/drivers/usb/typec/class.h b/drivers/usb/typec/class.h
> index db2fe96c48ff..f05d9201c233 100644
> --- a/drivers/usb/typec/class.h
> +++ b/drivers/usb/typec/class.h
> @@ -80,6 +80,8 @@ struct typec_port {
> */
> struct device *usb2_dev;
> struct device *usb3_dev;
> +
> + bool alt_mode_override;
s/alt_mode_override/mode_control/ ?
> };
>
> #define to_typec_port(_dev_) container_of(_dev_, struct typec_port, dev)
> diff --git a/include/linux/usb/typec.h b/include/linux/usb/typec.h
> index 252af3f77039..6e09e68788dd 100644
> --- a/include/linux/usb/typec.h
> +++ b/include/linux/usb/typec.h
> @@ -304,6 +304,7 @@ struct typec_capability {
> enum typec_accessory accessory[TYPEC_MAX_ACCESSORY];
> unsigned int orientation_aware:1;
> u8 usb_capability;
> + bool alt_mode_override;
>
> struct fwnode_handle *fwnode;
> void *driver_data;
> --
> 2.51.0.rc0.215.g125493bb4a-goog
--
heikki
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v1 3/5] usb: typec: ucsi: Set alt_mode_override flag
2025-08-14 18:44 ` [PATCH v1 3/5] usb: typec: ucsi: " Andrei Kuchynski
@ 2025-08-20 10:53 ` Heikki Krogerus
0 siblings, 0 replies; 14+ messages in thread
From: Heikki Krogerus @ 2025-08-20 10:53 UTC (permalink / raw)
To: Andrei Kuchynski
Cc: Abhishek Pandit-Subedi, Benson Leung, Jameson Thies,
Tzung-Bi Shih, linux-usb, chrome-platform, Guenter Roeck,
Greg Kroah-Hartman, Dmitry Baryshkov, Christian A. Ehrhardt,
Venkat Jayaraman, linux-kernel
On Thu, Aug 14, 2025 at 06:44:53PM +0000, Andrei Kuchynski wrote:
> This flag indicates that the PPM allows the OPM to change the currently
> negotiated alternate mode using the SET_NEW_CAM command.
>
> Signed-off-by: Andrei Kuchynski <akuchynski@chromium.org>
> ---
> drivers/usb/typec/ucsi/ucsi.c | 2 ++
> 1 file changed, 2 insertions(+)
>
> diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c
> index 5739ea2abdd1..5ba8b1bc874b 100644
> --- a/drivers/usb/typec/ucsi/ucsi.c
> +++ b/drivers/usb/typec/ucsi/ucsi.c
> @@ -1616,6 +1616,8 @@ static int ucsi_register_port(struct ucsi *ucsi, struct ucsi_connector *con)
>
> cap->driver_data = con;
> cap->ops = &ucsi_ops;
> + cap->alt_mode_override =
> + !!(con->ucsi->cap.features & UCSI_CAP_ALT_MODE_OVERRIDE);
One line is enough.
> if (ucsi->ops->update_connector)
> ucsi->ops->update_connector(con);
> --
> 2.51.0.rc0.215.g125493bb4a-goog
thanks,
--
heikki
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v1 5/5] usb: typec: Expose alternate mode priority via sysfs
2025-08-14 18:44 ` [PATCH v1 5/5] usb: typec: Expose alternate mode priority via sysfs Andrei Kuchynski
@ 2025-08-21 7:36 ` Heikki Krogerus
2025-08-21 14:44 ` Andrei Kuchynski
0 siblings, 1 reply; 14+ messages in thread
From: Heikki Krogerus @ 2025-08-21 7:36 UTC (permalink / raw)
To: Andrei Kuchynski
Cc: Abhishek Pandit-Subedi, Benson Leung, Jameson Thies,
Tzung-Bi Shih, linux-usb, chrome-platform, Guenter Roeck,
Greg Kroah-Hartman, Dmitry Baryshkov, Christian A. Ehrhardt,
Venkat Jayaraman, linux-kernel
Hi Andrei,
On Thu, Aug 14, 2025 at 06:44:55PM +0000, Andrei Kuchynski wrote:
> This patch introduces a priority sysfs attribute to the USB Type-C
> alternate mode port interface. This new attribute allows user-space to
> configure the numeric priority of alternate modes managing their preferred
> order of operation.
>
> Signed-off-by: Andrei Kuchynski <akuchynski@chromium.org>
> ---
> Documentation/ABI/testing/sysfs-class-typec | 12 ++++++
> drivers/usb/typec/class.c | 47 ++++++++++++++++++++-
> 2 files changed, 58 insertions(+), 1 deletion(-)
>
> diff --git a/Documentation/ABI/testing/sysfs-class-typec b/Documentation/ABI/testing/sysfs-class-typec
> index 38e101c17a00..001202d651fa 100644
> --- a/Documentation/ABI/testing/sysfs-class-typec
> +++ b/Documentation/ABI/testing/sysfs-class-typec
> @@ -162,6 +162,18 @@ Description: Lists the supported USB Modes. The default USB mode that is used
> - usb3 (USB 3.2)
> - usb4 (USB4)
>
> + What: /sys/class/typec/<port>/<alt-mode>/priority
> +Date: July 2025
> +Contact: Andrei Kuchynski <akuchynski@chromium.org>
> +Description:
> + Displays and allows setting the priority for a specific alt-mode.
> + When read, it shows the current integer priority value. Lower numerical
> + values indicate higher priority (0 is the highest priority).
> + If the new value is already in use by another mode, the priority of the
> + conflicting mode and any subsequent modes will be incremented until they
> + are all unique.
> + This attribute is visible only if the kernel supports mode selection.
I was expecting this to be already used in this series.
IMO this file should be the only thing the user space needs to use by
default at least.
> USB Type-C partner devices (eg. /sys/class/typec/port0-partner/)
>
> What: /sys/class/typec/<port>-partner/accessory_mode
> diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c
> index a72325ff099a..708f3487222a 100644
> --- a/drivers/usb/typec/class.c
> +++ b/drivers/usb/typec/class.c
> @@ -19,6 +19,7 @@
> #include "bus.h"
> #include "class.h"
> #include "pd.h"
> +#include "mode_selection.h"
>
> static DEFINE_IDA(typec_index_ida);
>
> @@ -445,11 +446,41 @@ svid_show(struct device *dev, struct device_attribute *attr, char *buf)
> }
> static DEVICE_ATTR_RO(svid);
>
> +static ssize_t priority_store(struct device *dev,
> + struct device_attribute *attr,
> + const char *buf, size_t size)
> +{
> + unsigned int val;
> + int err = kstrtouint(buf, 10, &val);
> +
> + if (!err) {
> + err = typec_mode_set_priority(to_typec_altmode(dev), val);
> + if (!err)
> + return size;
> + }
> +
> + return err;
> +}
> +
> +static ssize_t priority_show(struct device *dev,
> + struct device_attribute *attr, char *buf)
> +{
> + int val;
> + const int err = typec_mode_get_priority(to_typec_altmode(dev), &val);
> +
> + if (err)
> + return err;
> +
> + return sprintf(buf, "%d\n", val);
> +}
> +static DEVICE_ATTR_RW(priority);
> +
> static struct attribute *typec_altmode_attrs[] = {
> &dev_attr_active.attr,
> &dev_attr_mode.attr,
> &dev_attr_svid.attr,
> &dev_attr_vdo.attr,
> + &dev_attr_priority.attr,
> NULL
> };
>
> @@ -458,7 +489,7 @@ static umode_t typec_altmode_attr_is_visible(struct kobject *kobj,
> {
> struct typec_altmode *adev = to_typec_altmode(kobj_to_dev(kobj));
>
> - if (attr == &dev_attr_active.attr)
> + if (attr == &dev_attr_active.attr) {
> if (!is_typec_port(adev->dev.parent)) {
> struct typec_partner *partner =
> to_typec_partner(adev->dev.parent);
> @@ -469,6 +500,15 @@ static umode_t typec_altmode_attr_is_visible(struct kobject *kobj,
> !adev->ops->activate)
> return 0444;
> }
> + } else if (attr == &dev_attr_priority.attr) {
> + if (is_typec_port(adev->dev.parent)) {
> + struct typec_port *port = to_typec_port(adev->dev.parent);
> +
> + if (!port->alt_mode_override)
> + return 0;
> + } else
> + return 0;
> + }
If we have the local port variable, this should be enough:
if (!is_typec_port(adev->dev.parent) || !port->alt_mode_override)
return 0;
> return attr->mode;
> }
> @@ -2029,6 +2069,7 @@ static void typec_release(struct device *dev)
> typec_mux_put(port->mux);
> typec_retimer_put(port->retimer);
> kfree(port->cap);
> + typec_mode_selection_destroy(port);
> kfree(port);
> }
>
> @@ -2496,6 +2537,8 @@ typec_port_register_altmode(struct typec_port *port,
> to_altmode(adev)->retimer = retimer;
> }
>
> + typec_mode_set_priority(adev, -1);
This really should not be necessary. Why can't we set the priority
based on the order the drives registers the altmodes for the port?
> return adev;
> }
> EXPORT_SYMBOL_GPL(typec_port_register_altmode);
> @@ -2645,6 +2688,8 @@ struct typec_port *typec_register_port(struct device *parent,
> port->con.attach = typec_partner_attach;
> port->con.deattach = typec_partner_deattach;
>
> + INIT_LIST_HEAD(&port->mode_list);
> +
> if (cap->usb_capability & USB_CAPABILITY_USB4)
> port->usb_mode = USB_MODE_USB4;
> else if (cap->usb_capability & USB_CAPABILITY_USB3)
thanks,
--
heikki
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v1 4/5] usb: typec: Implement alternate mode priority handling
2025-08-14 18:44 ` [PATCH v1 4/5] usb: typec: Implement alternate mode priority handling Andrei Kuchynski
@ 2025-08-21 10:09 ` Heikki Krogerus
2025-08-21 11:14 ` Heikki Krogerus
0 siblings, 1 reply; 14+ messages in thread
From: Heikki Krogerus @ 2025-08-21 10:09 UTC (permalink / raw)
To: Andrei Kuchynski
Cc: Abhishek Pandit-Subedi, Benson Leung, Jameson Thies,
Tzung-Bi Shih, linux-usb, chrome-platform, Guenter Roeck,
Greg Kroah-Hartman, Dmitry Baryshkov, Christian A. Ehrhardt,
Venkat Jayaraman, linux-kernel
Hi Andrei,
On Thu, Aug 14, 2025 at 06:44:54PM +0000, Andrei Kuchynski wrote:
> This patch introduces APIs to manage the priority of USB Type-C alternate
> modes. These APIs allow for setting and retrieving a priority number for
> each mode. If a new priority value conflicts with an existing mode's
> priority, the priorities of the conflicting mode and all subsequent modes
> are automatically incremented to ensure uniqueness.
I think this needs to be simplified. You don't need this elaborate
implementation in the beginning.
I'm going to do some suggestions. I don't know if all of them work,
but hopefully you get the idea how I would like to see the initial
support to be implemented.
> Signed-off-by: Andrei Kuchynski <akuchynski@chromium.org>
> ---
> drivers/usb/typec/Makefile | 2 +-
> drivers/usb/typec/class.h | 1 +
> drivers/usb/typec/mode_selection.c | 127 +++++++++++++++++++++++++++++
> drivers/usb/typec/mode_selection.h | 8 ++
> include/linux/usb/typec_altmode.h | 9 ++
> 5 files changed, 146 insertions(+), 1 deletion(-)
> create mode 100644 drivers/usb/typec/mode_selection.c
> create mode 100644 drivers/usb/typec/mode_selection.h
>
> 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) += typec.o
> -typec-y := class.o mux.o bus.o pd.o retimer.o
> +typec-y := class.o mux.o bus.o pd.o retimer.o mode_selection.o
> typec-$(CONFIG_ACPI) += port-mapper.o
> obj-$(CONFIG_TYPEC) += altmodes/
> obj-$(CONFIG_TYPEC_TCPM) += tcpm/
> diff --git a/drivers/usb/typec/class.h b/drivers/usb/typec/class.h
> index f05d9201c233..c6467e576569 100644
> --- a/drivers/usb/typec/class.h
> +++ b/drivers/usb/typec/class.h
> @@ -82,6 +82,7 @@ struct typec_port {
> struct device *usb3_dev;
>
> bool alt_mode_override;
> + struct list_head mode_list;
I'm not sure we need this.
> };
>
> #define to_typec_port(_dev_) container_of(_dev_, struct typec_port, dev)
> diff --git a/drivers/usb/typec/mode_selection.c b/drivers/usb/typec/mode_selection.c
> new file mode 100644
> index 000000000000..8a54639b86bf
> --- /dev/null
> +++ b/drivers/usb/typec/mode_selection.c
> @@ -0,0 +1,127 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright 2025 Google LLC.
> + */
> +
> +#include <linux/usb/typec_altmode.h>
> +#include <linux/slab.h>
> +#include <linux/list.h>
> +#include "mode_selection.h"
> +#include "class.h"
> +
> +static const char * const mode_names[TYPEC_ALTMODE_MAX] = {
> + [TYPEC_ALTMODE_DP] = "DisplayPort",
> + [TYPEC_ALTMODE_TBT] = "Thunderbolt3",
> + [TYPEC_ALTMODE_USB4] = "USB4",
> +};
You only need string for USB4. The altmode names come from the drivers.
> +static const int default_priorities[TYPEC_ALTMODE_MAX] = {
> + [TYPEC_ALTMODE_DP] = 2,
> + [TYPEC_ALTMODE_TBT] = 1,
> + [TYPEC_ALTMODE_USB4] = 0,
> +};
The default priorities is an array of svids. And I really think that
the highest priority should be 1 not 0.
> +static inline enum typec_mode_type typec_svid_to_altmode(const u16 svid)
> +{
> + switch (svid) {
> + case USB_TYPEC_DP_SID:
> + return TYPEC_ALTMODE_DP;
> + case USB_TYPEC_TBT_SID:
> + return TYPEC_ALTMODE_TBT;
> + case USB_TYPEC_USB4_SID:
> + return TYPEC_ALTMODE_USB4;
> + }
> + return TYPEC_ALTMODE_MAX;
> +}
Get rid of this.
> +/**
> + * struct mode_selection_state - State tracking for a specific Type-C mode
> + * @mode: The type of mode this instance represents
> + * @priority: The mode priority. Lower values indicate a more preferred mode.
> + * @list: List head to link this mode state into a prioritized list.
> + */
> +struct mode_selection_state {
> + enum typec_mode_type mode;
> + int priority;
> + struct list_head list;
> +};
Get rid of this. I don't see why you would need to separate the
priority handling at this point. Keep it as simply as possible first.
Just place the priority member to struct typec_altmode. 0 should
indicate that there is no specific priority set, or default order
should be used IMO.
> +/* -------------------------------------------------------------------------- */
> +/* port 'mode_priorities' attribute */
> +
> +int typec_mode_set_priority(struct typec_altmode *adev, const int priority)
> +{
> + struct typec_port *port = to_typec_port(adev->dev.parent);
> + const enum typec_mode_type mode = typec_svid_to_altmode(adev->svid);
> + struct mode_selection_state *ms_target = NULL;
> + struct mode_selection_state *ms, *tmp;
> +
> + if (mode >= TYPEC_ALTMODE_MAX || !mode_names[mode])
> + return -EOPNOTSUPP;
Just support every altmode bind to a driver and USB4. USB4 you
identify with a specific usb4 device type.
> + list_for_each_entry_safe(ms, tmp, &port->mode_list, list) {
> + if (ms->mode == mode) {
> + ms_target = ms;
> + list_del(&ms->list);
> + break;
> + }
> + }
> +
> + if (!ms_target) {
> + ms_target = kzalloc(sizeof(struct mode_selection_state), GFP_KERNEL);
> + if (!ms_target)
> + return -ENOMEM;
> + ms_target->mode = mode;
> + INIT_LIST_HEAD(&ms_target->list);
> + }
> +
> + if (priority >= 0)
> + ms_target->priority = priority;
> + else
> + ms_target->priority = default_priorities[mode];
> +
> + while (ms_target) {
> + struct mode_selection_state *ms_peer = NULL;
> +
> + list_for_each_entry(ms, &port->mode_list, list)
> + if (ms->priority >= ms_target->priority) {
> + if (ms->priority == ms_target->priority)
> + ms_peer = ms;
> + break;
> + }
> +
> + list_add_tail(&ms_target->list, &ms->list);
> + ms_target = ms_peer;
> + if (ms_target) {
> + ms_target->priority++;
> + list_del(&ms_target->list);
> + }
> + }
> +
> + return 0;
> +}
> +
> +int typec_mode_get_priority(struct typec_altmode *adev, int *priority)
> +{
> + struct typec_port *port = to_typec_port(adev->dev.parent);
> + const enum typec_mode_type mode = typec_svid_to_altmode(adev->svid);
> + struct mode_selection_state *ms;
> +
> + list_for_each_entry(ms, &port->mode_list, list)
> + if (ms->mode == mode) {
> + *priority = ms->priority;
> + return 0;
> + }
> +
> + return -EOPNOTSUPP;
> +}
> +
> +void typec_mode_selection_destroy(struct typec_port *port)
> +{
> + struct mode_selection_state *ms, *tmp;
> +
> + list_for_each_entry_safe(ms, tmp, &port->mode_list, list) {
> + list_del(&ms->list);
> + kfree(ms);
> + }
> +}
> diff --git a/drivers/usb/typec/mode_selection.h b/drivers/usb/typec/mode_selection.h
> new file mode 100644
> index 000000000000..69adfcf39d7c
> --- /dev/null
> +++ b/drivers/usb/typec/mode_selection.h
> @@ -0,0 +1,8 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +
> +#include <linux/usb/typec_dp.h>
> +#include <linux/usb/typec_tbt.h>
> +
> +int typec_mode_set_priority(struct typec_altmode *adev, const int priority);
> +int typec_mode_get_priority(struct typec_altmode *adev, int *priority);
> +void typec_mode_selection_destroy(struct typec_port *port);
> diff --git a/include/linux/usb/typec_altmode.h b/include/linux/usb/typec_altmode.h
> index b3c0866ea70f..318858fc7bec 100644
> --- a/include/linux/usb/typec_altmode.h
> +++ b/include/linux/usb/typec_altmode.h
> @@ -145,6 +145,15 @@ enum {
>
> #define TYPEC_MODAL_STATE(_state_) ((_state_) + TYPEC_STATE_MODAL)
>
> +#define USB_TYPEC_USB4_SID 0xff00
I would suggest that you create a separate patch or patches for the
USB4 mode registration.
> +enum typec_mode_type {
> + TYPEC_ALTMODE_DP = 0,
> + TYPEC_ALTMODE_TBT,
> + TYPEC_ALTMODE_USB4,
> + TYPEC_ALTMODE_MAX,
> +};
Drop this completely.
thanks,
--
heikki
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v1 4/5] usb: typec: Implement alternate mode priority handling
2025-08-21 10:09 ` Heikki Krogerus
@ 2025-08-21 11:14 ` Heikki Krogerus
2025-08-22 12:52 ` Andrei Kuchynski
0 siblings, 1 reply; 14+ messages in thread
From: Heikki Krogerus @ 2025-08-21 11:14 UTC (permalink / raw)
To: Andrei Kuchynski
Cc: Abhishek Pandit-Subedi, Benson Leung, Jameson Thies,
Tzung-Bi Shih, linux-usb, chrome-platform, Guenter Roeck,
Greg Kroah-Hartman, Dmitry Baryshkov, Christian A. Ehrhardt,
Venkat Jayaraman, linux-kernel
Hi again,
On Thu, Aug 21, 2025 at 01:09:57PM +0300, Heikki Krogerus wrote:
> > diff --git a/drivers/usb/typec/mode_selection.c b/drivers/usb/typec/mode_selection.c
> > new file mode 100644
> > index 000000000000..8a54639b86bf
> > --- /dev/null
> > +++ b/drivers/usb/typec/mode_selection.c
> > @@ -0,0 +1,127 @@
> > +// SPDX-License-Identifier: GPL-2.0-only
> > +/*
> > + * Copyright 2025 Google LLC.
> > + */
> > +
> > +#include <linux/usb/typec_altmode.h>
> > +#include <linux/slab.h>
> > +#include <linux/list.h>
> > +#include "mode_selection.h"
> > +#include "class.h"
> > +
> > +static const char * const mode_names[TYPEC_ALTMODE_MAX] = {
> > + [TYPEC_ALTMODE_DP] = "DisplayPort",
> > + [TYPEC_ALTMODE_TBT] = "Thunderbolt3",
> > + [TYPEC_ALTMODE_USB4] = "USB4",
> > +};
>
> You only need string for USB4. The altmode names come from the drivers.
Sorry, that won't work with port altmode. But you can still do the
lookup with just the sid.
<snip>
> > +/* -------------------------------------------------------------------------- */
> > +/* port 'mode_priorities' attribute */
> > +
> > +int typec_mode_set_priority(struct typec_altmode *adev, const int priority)
> > +{
> > + struct typec_port *port = to_typec_port(adev->dev.parent);
> > + const enum typec_mode_type mode = typec_svid_to_altmode(adev->svid);
> > + struct mode_selection_state *ms_target = NULL;
> > + struct mode_selection_state *ms, *tmp;
> > +
> > + if (mode >= TYPEC_ALTMODE_MAX || !mode_names[mode])
> > + return -EOPNOTSUPP;
>
> Just support every altmode bind to a driver and USB4. USB4 you
> identify with a specific usb4 device type.
No driver so you would need to use the mode_names, but instead of
doing that, just don't limit this at all.
If there is no name for the mode, use the svid.
thanks,
--
heikki
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v1 1/5] usb: typec: Add alt_mode_override field to port property
2025-08-20 10:53 ` Heikki Krogerus
@ 2025-08-21 14:19 ` Andrei Kuchynski
0 siblings, 0 replies; 14+ messages in thread
From: Andrei Kuchynski @ 2025-08-21 14:19 UTC (permalink / raw)
To: Heikki Krogerus
Cc: Abhishek Pandit-Subedi, Benson Leung, Jameson Thies,
Tzung-Bi Shih, linux-usb, chrome-platform, Guenter Roeck,
Greg Kroah-Hartman, Dmitry Baryshkov, Christian A. Ehrhardt,
Venkat Jayaraman, linux-kernel
On Wed, Aug 20, 2025 at 12:53 PM Heikki Krogerus
<heikki.krogerus@linux.intel.com> wrote:
>
> On Thu, Aug 14, 2025 at 06:44:51PM +0000, Andrei Kuchynski wrote:
> > This new field in the port properties dictates whether the Platform Policy
> > Manager (PPM) allows the OS Policy Manager (OPM) to change the currently
> > active, negotiated alternate mode.
> >
> > Signed-off-by: Andrei Kuchynski <akuchynski@chromium.org>
> > ---
> > drivers/usb/typec/class.c | 14 +++++++++++---
> > drivers/usb/typec/class.h | 2 ++
> > include/linux/usb/typec.h | 1 +
> > 3 files changed, 14 insertions(+), 3 deletions(-)
> >
> > diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c
> > index 67a533e35150..a72325ff099a 100644
> > --- a/drivers/usb/typec/class.c
> > +++ b/drivers/usb/typec/class.c
> > @@ -459,9 +459,16 @@ static umode_t typec_altmode_attr_is_visible(struct kobject *kobj,
> > struct typec_altmode *adev = to_typec_altmode(kobj_to_dev(kobj));
> >
> > if (attr == &dev_attr_active.attr)
> > - if (!is_typec_port(adev->dev.parent) &&
> > - (!adev->ops || !adev->ops->activate))
> > - return 0444;
> > + if (!is_typec_port(adev->dev.parent)) {
> > + struct typec_partner *partner =
> > + to_typec_partner(adev->dev.parent);
>
> That looks a bit unnecessary. Also, can't the altmode be a plug alt mode?
>
> > + struct typec_port *port =
> > + to_typec_port(partner->dev.parent);
> > +
> > + if (!port->alt_mode_override || !adev->ops ||
> > + !adev->ops->activate)
> > + return 0444;
> > + }
>
> How about:
>
> struct typec_altmode *adev = to_typec_altmode(kobj_to_dev(kobj));
> struct typec_port *port = typec_altmode2port(adev);
>
> if (attr == &dev_attr_active.attr) {
> if (!is_typec_port(adev->dev.parent)) {
> if (!port->alt_mode_override || !adev->ops || !adev->ops->activate)
> return 0444;
> }
> }
>
I completely missed typec_altmode2port function.
Thank you!
> > return attr->mode;
> > }
> > @@ -2681,6 +2688,7 @@ struct typec_port *typec_register_port(struct device *parent,
> > }
> >
> > port->pd = cap->pd;
> > + port->alt_mode_override = cap->alt_mode_override;
>
> This needs to be enabled by default:
>
> port->alt_mode_override = !cap->no_mode_control;
>
Agreed. I'll make it enabled by default.
> > ret = device_add(&port->dev);
> > if (ret) {
> > diff --git a/drivers/usb/typec/class.h b/drivers/usb/typec/class.h
> > index db2fe96c48ff..f05d9201c233 100644
> > --- a/drivers/usb/typec/class.h
> > +++ b/drivers/usb/typec/class.h
> > @@ -80,6 +80,8 @@ struct typec_port {
> > */
> > struct device *usb2_dev;
> > struct device *usb3_dev;
> > +
> > + bool alt_mode_override;
>
> s/alt_mode_override/mode_control/ ?
>
Agreed. mode_control is a clearer name.
Thank you for your review!
Andrei
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v1 5/5] usb: typec: Expose alternate mode priority via sysfs
2025-08-21 7:36 ` Heikki Krogerus
@ 2025-08-21 14:44 ` Andrei Kuchynski
0 siblings, 0 replies; 14+ messages in thread
From: Andrei Kuchynski @ 2025-08-21 14:44 UTC (permalink / raw)
To: Heikki Krogerus
Cc: Abhishek Pandit-Subedi, Benson Leung, Jameson Thies,
Tzung-Bi Shih, linux-usb, chrome-platform, Guenter Roeck,
Greg Kroah-Hartman, Dmitry Baryshkov, Christian A. Ehrhardt,
Venkat Jayaraman, linux-kernel
On Thu, Aug 21, 2025 at 9:36 AM Heikki Krogerus
<heikki.krogerus@linux.intel.com> wrote:
>
> Hi Andrei,
>
> On Thu, Aug 14, 2025 at 06:44:55PM +0000, Andrei Kuchynski wrote:
> > This patch introduces a priority sysfs attribute to the USB Type-C
> > alternate mode port interface. This new attribute allows user-space to
> > configure the numeric priority of alternate modes managing their preferred
> > order of operation.
> >
> > Signed-off-by: Andrei Kuchynski <akuchynski@chromium.org>
> > ---
> > Documentation/ABI/testing/sysfs-class-typec | 12 ++++++
> > drivers/usb/typec/class.c | 47 ++++++++++++++++++++-
> > 2 files changed, 58 insertions(+), 1 deletion(-)
> >
> > diff --git a/Documentation/ABI/testing/sysfs-class-typec b/Documentation/ABI/testing/sysfs-class-typec
> > index 38e101c17a00..001202d651fa 100644
> > --- a/Documentation/ABI/testing/sysfs-class-typec
> > +++ b/Documentation/ABI/testing/sysfs-class-typec
> > @@ -162,6 +162,18 @@ Description: Lists the supported USB Modes. The default USB mode that is used
> > - usb3 (USB 3.2)
> > - usb4 (USB4)
> >
> > + What: /sys/class/typec/<port>/<alt-mode>/priority
> > +Date: July 2025
> > +Contact: Andrei Kuchynski <akuchynski@chromium.org>
> > +Description:
> > + Displays and allows setting the priority for a specific alt-mode.
> > + When read, it shows the current integer priority value. Lower numerical
> > + values indicate higher priority (0 is the highest priority).
> > + If the new value is already in use by another mode, the priority of the
> > + conflicting mode and any subsequent modes will be incremented until they
> > + are all unique.
> > + This attribute is visible only if the kernel supports mode selection.
>
> I was expecting this to be already used in this series.
>
> IMO this file should be the only thing the user space needs to use by
> default at least.
>
No more entries for mode priorities.
What about the trigger of the process?
I'm going to introduce a mode_selection binary sysfs attribute in
the next series. Writing 1 to this attribute will activate the
mode selection process. Writing 0 will cancel the process and
exit the currently active mode.
> > @@ -469,6 +500,15 @@ static umode_t typec_altmode_attr_is_visible(struct kobject *kobj,
> > !adev->ops->activate)
> > return 0444;
> > }
> > + } else if (attr == &dev_attr_priority.attr) {
> > + if (is_typec_port(adev->dev.parent)) {
> > + struct typec_port *port = to_typec_port(adev->dev.parent);
> > +
> > + if (!port->alt_mode_override)
> > + return 0;
> > + } else
> > + return 0;
> > + }
>
> If we have the local port variable, this should be enough:
>
> if (!is_typec_port(adev->dev.parent) || !port->alt_mode_override)
> return 0;
>
typec_altmode2port is really powerful. Thank you again for this hint!
> > return attr->mode;
> > }
> > @@ -2029,6 +2069,7 @@ static void typec_release(struct device *dev)
> > typec_mux_put(port->mux);
> > typec_retimer_put(port->retimer);
> > kfree(port->cap);
> > + typec_mode_selection_destroy(port);
> > kfree(port);
> > }
> >
> > @@ -2496,6 +2537,8 @@ typec_port_register_altmode(struct typec_port *port,
> > to_altmode(adev)->retimer = retimer;
> > }
> >
> > + typec_mode_set_priority(adev, -1);
>
> This really should not be necessary. Why can't we set the priority
> based on the order the drives registers the altmodes for the port?
>
Setting priorities based on the order of registration is a good
idea. This simplifies the logic by making the default_priorities
unnecessary.
I will modify the initialization to call
typec_mode_set_priority(adev, 0);
With this change, the later a mode is registered, the higher its
priority will be. For the cros_ec_typec driver, this produces the
same default sequence: USB4 TBT DP.
Thanks,
Andrei
> > return adev;
> > }
> > EXPORT_SYMBOL_GPL(typec_port_register_altmode);
> > @@ -2645,6 +2688,8 @@ struct typec_port *typec_register_port(struct device *parent,
> > port->con.attach = typec_partner_attach;
> > port->con.deattach = typec_partner_deattach;
> >
> > + INIT_LIST_HEAD(&port->mode_list);
> > +
> > if (cap->usb_capability & USB_CAPABILITY_USB4)
> > port->usb_mode = USB_MODE_USB4;
> > else if (cap->usb_capability & USB_CAPABILITY_USB3)
>
> thanks,
>
> --
> heikki
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v1 4/5] usb: typec: Implement alternate mode priority handling
2025-08-21 11:14 ` Heikki Krogerus
@ 2025-08-22 12:52 ` Andrei Kuchynski
0 siblings, 0 replies; 14+ messages in thread
From: Andrei Kuchynski @ 2025-08-22 12:52 UTC (permalink / raw)
To: Heikki Krogerus
Cc: Abhishek Pandit-Subedi, Benson Leung, Jameson Thies,
Tzung-Bi Shih, linux-usb, chrome-platform, Guenter Roeck,
Greg Kroah-Hartman, Dmitry Baryshkov, Christian A. Ehrhardt,
Venkat Jayaraman, linux-kernel
On Thu, Aug 21, 2025 at 1:15 PM Heikki Krogerus
<heikki.krogerus@linux.intel.com> wrote:
>
> Hi again,
>
> On Thu, Aug 21, 2025 at 01:09:57PM +0300, Heikki Krogerus wrote:
> > > diff --git a/drivers/usb/typec/mode_selection.c b/drivers/usb/typec/mode_selection.c
> > > new file mode 100644
> > > index 000000000000..8a54639b86bf
> > > --- /dev/null
> > > +++ b/drivers/usb/typec/mode_selection.c
> > > @@ -0,0 +1,127 @@
> > > +// SPDX-License-Identifier: GPL-2.0-only
> > > +/*
> > > + * Copyright 2025 Google LLC.
> > > + */
> > > +
> > > +#include <linux/usb/typec_altmode.h>
> > > +#include <linux/slab.h>
> > > +#include <linux/list.h>
> > > +#include "mode_selection.h"
> > > +#include "class.h"
> > > +
> > > +static const char * const mode_names[TYPEC_ALTMODE_MAX] = {
> > > + [TYPEC_ALTMODE_DP] = "DisplayPort",
> > > + [TYPEC_ALTMODE_TBT] = "Thunderbolt3",
> > > + [TYPEC_ALTMODE_USB4] = "USB4",
> > > +};
> >
> > You only need string for USB4. The altmode names come from the drivers.
>
> Sorry, that won't work with port altmode. But you can still do the
> lookup with just the sid.
>
Hi Heikki,
I can get names from altmode partner. Names are only needed to
provide results of entering the mode. No partner - no results.
>
> I think this needs to be simplified. You don't need this elaborate
> implementation in the beginning.
>
> I'm going to do some suggestions. I don't know if all of them work,
> but hopefully you get the idea how I would like to see the initial
> support to be implemented.
>
I checked your suggestions. It looks like all of them should
work. Thank you!
- priority is a member to struct typec_altmode
- use svid instead of enum typec_mode_type
- no list or other variables in struct typec_port.
- struct mode_selection_state will be introduced in other series
>
> The default priorities is an array of svids. And I really think that
> the highest priority should be 1 not 0.
>
I think your idea of setting priorities based on the order of
port altmod registrations is better. We don't really need default
priorities in this case.
>
> No driver so you would need to use the mode_names, but instead of
> doing that, just don't limit this at all.
>
> If there is no name for the mode, use the svid.
>
> thanks,
>
> --
> heikki
What if we later create typec_USB4 driver, similar to the
existing typec_displayport and typec_thunderbolt?
This approach could unify how various modes are handled,
eliminating exceptions for USB4 or any other mode.
The port altmode would contain priority and support "enter" and
"exit" operations, while partner altmode would handle "activate"
and name field. I've explored this approach with cros_ec_typec
driver, and it appears to be a promising way to manage USB4 as
alternate mode.
Thanks,
Andrei
^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2025-08-22 12:52 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-08-14 18:44 [PATCH v1 0/5] USB Type-C alternate mode priorities Andrei Kuchynski
2025-08-14 18:44 ` [PATCH v1 1/5] usb: typec: Add alt_mode_override field to port property Andrei Kuchynski
2025-08-20 10:53 ` Heikki Krogerus
2025-08-21 14:19 ` Andrei Kuchynski
2025-08-14 18:44 ` [PATCH v1 2/5] platform/chrome: cros_ec_typec: Set alt_mode_override flag Andrei Kuchynski
2025-08-14 18:44 ` [PATCH v1 3/5] usb: typec: ucsi: " Andrei Kuchynski
2025-08-20 10:53 ` Heikki Krogerus
2025-08-14 18:44 ` [PATCH v1 4/5] usb: typec: Implement alternate mode priority handling Andrei Kuchynski
2025-08-21 10:09 ` Heikki Krogerus
2025-08-21 11:14 ` Heikki Krogerus
2025-08-22 12:52 ` Andrei Kuchynski
2025-08-14 18:44 ` [PATCH v1 5/5] usb: typec: Expose alternate mode priority via sysfs Andrei Kuchynski
2025-08-21 7:36 ` Heikki Krogerus
2025-08-21 14:44 ` Andrei Kuchynski
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).