From patchwork Mon Jun 16 13:31:39 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrei Kuchynski X-Patchwork-Id: 897322 Received: from mail-ed1-f46.google.com (mail-ed1-f46.google.com [209.85.208.46]) (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 996432877DC for ; Mon, 16 Jun 2025 13:33:13 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.46 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1750080795; cv=none; b=qONKTCT12BS1LZONxvMjJcYvcVOGeNwTktVvMsuN4sDppmbTKIW7XnaBZO6WEtpimil+ahw0yryRYAVg3x/JtD4PL1GuURjTSbuyL1TkhpwQSalXeyS0j7ftsM0JjK/n/CkEerQ94e7LGnQEEouYCcU03i/ZokbcZUIEiKM5Qo8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1750080795; c=relaxed/simple; bh=Zr0by00gzuLqU/8noVtlHXiuZTGL3C9qQp8UPrlTVhI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=jTIODMMfOIPZhN62f/D580GIZrj3YqEfkfVOfmaLTOjuS9Z7pn3ji2VcdFJAOQfRfVpy6wBhUdUaElHUL5VlWyhd3rzdT+EdUwlBW5Suqe8DrKOspNdVIcFKiV5oYDlVNifOnofPHQMV676Qa6T1cq3NZ6Ufg55iWxYxmynkCp8= 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=VfoyGgc1; arc=none smtp.client-ip=209.85.208.46 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="VfoyGgc1" Received: by mail-ed1-f46.google.com with SMTP id 4fb4d7f45d1cf-60780d74bbaso8094859a12.0 for ; Mon, 16 Jun 2025 06:33:13 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; t=1750080792; x=1750685592; 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=feDBvsCRg//C7YMonBlbgFAdDrxVjfxFzxxt26XS52w=; b=VfoyGgc1ag2hNEN0A+rWuPryMy2nRVOtm0KMNFSApU9jD38nzEfw+mSDyIkBIKsUjm Sz12FpO9L8M51ntJ//H3Te1TBps1xtc3U2pgKWcBcTM/Ci0wwsI8iEYbYqv8lQJYlJZz kZkB/vOThTJaK4BprrnKADL70eoVgYWqPThx0= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1750080792; x=1750685592; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=feDBvsCRg//C7YMonBlbgFAdDrxVjfxFzxxt26XS52w=; b=GZYQxdJmLQcOJuyrRg8dI00jpxAqxdWFWQNIv2moYDjFrdZZY04FOYrPFxFYQpQ8xN smkt9QYhRpqZRnexdle5V9yYAtC4bmTskF+ovKoyMRu412ZAdLwfjtJpNLF97BuwwoHt goIp1qmw3OrBNc5oQoaIoFw4pj2+Qbv3Yp2X/65r95xnNSERf7+fCIL3Qcg5J8qdYM46 zRzFRhFl8Qbo9Tsz3UP+xla9D4zFHMaz0O0+41O9oAGu9nBUfjvaT/FWmhoYcnG/d9SI /vTyFlEU3qhRkJ3WF4kr1DO7ZSsUg1ODfiBnmAmyfm0uh9vItqIEJ037suVD2jxVrKet DboA== X-Forwarded-Encrypted: i=1; AJvYcCXvqWVQhdxvhbEDAhrTMX5KNaCHhyC0h2Z3waZ5zy15hI7WMrVTp5uEEj8/f0ggvNsgzcjRqjDfX7w=@vger.kernel.org X-Gm-Message-State: AOJu0YxHkk5UVJt4+Nob08Z9P2pi4y0SaF7UsuFI2bdRptLnfQ7gsSWz UyGaYnSySySK4o2+Z4rXiaU8+VtKHiH/FdKnGSTtGInSd71lt8ZLFvV0iJVYACAsKQ== X-Gm-Gg: ASbGncv/lAGgvTcpmLgh9Iv2p1qHw+Vh7zUfMGvzo0FuEkZH7PEUPqM0/Im2AUzXlIO uupKbsefwzWvoAIh9hZfD79n3UsufxIn7f+81046yplsuMKTDA0YybwGb03VcVoIyAWF5RTKS/7 CzewqCB2TSN048niPTeRG7w/rILZZ+bYcd6/LKWb1/1Izz7NoKREDK4KZQNQnHLHn5e/WlpgW1P pBvXh0Q449QV5K7D2a4J+/sNyhk2WU1cWvNpd0AcG5yUN5P62BnJZCYshWTbZvX8I4HzUAvlKdA FnwiKozqKbdn/JNVs/TSy8SysonohAZ77oXol8SeAuah76Pm0pmmLXlKKJfpd9Z1/D/9POHRKnf vjM8CvXKE3rq20uJeTAghSg8QL4tubBZH18JlNh2TTtdXYr7OoQlFLw1EhfPBaQtW+Ibr X-Google-Smtp-Source: AGHT+IHjZH5bwhZ1Xd6IbpKopcl9AXhlpygAbGOG0etGiJyiXrgesebapu3fw6k5UbnpFpkYC/Jj0w== X-Received: by 2002:a05:6402:5113:b0:607:ea4e:251c with SMTP id 4fb4d7f45d1cf-608ce4c0fccmr8482617a12.8.1750080791872; Mon, 16 Jun 2025 06:33:11 -0700 (PDT) Received: from akuchynski.c.googlers.com.com (244.175.141.34.bc.googleusercontent.com. [34.141.175.244]) by smtp.gmail.com with ESMTPSA id 4fb4d7f45d1cf-608b4a94ce7sm6036664a12.58.2025.06.16.06.33.11 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 16 Jun 2025 06:33:11 -0700 (PDT) From: Andrei Kuchynski To: Heikki Krogerus , Dmitry Baryshkov , Abhishek Pandit-Subedi , Jameson Thies , Benson Leung , Tzung-Bi Shih Cc: Greg Kroah-Hartman , Guenter Roeck , Pooja Katiyar , Badhri Jagan Sridharan , RD Babiera , linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org, chrome-platform@lists.linux.dev, Andrei Kuchynski Subject: [PATCH 02/10] platform/chrome: cros_ec_typec: Set alt_mode_override flag Date: Mon, 16 Jun 2025 13:31:39 +0000 Message-ID: <20250616133147.1835939-3-akuchynski@chromium.org> X-Mailer: git-send-email 2.50.0.rc1.591.g9c95f17f64-goog In-Reply-To: <20250616133147.1835939-1-akuchynski@chromium.org> References: <20250616133147.1835939-1-akuchynski@chromium.org> Precedence: bulk X-Mailing-List: linux-usb@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 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 --- 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 7678e3d05fd3..3aed429fde03 100644 --- a/drivers/platform/chrome/cros_ec_typec.c +++ b/drivers/platform/chrome/cros_ec_typec.c @@ -408,6 +408,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)) { From patchwork Mon Jun 16 13:31:41 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrei Kuchynski X-Patchwork-Id: 897321 Received: from mail-ed1-f49.google.com (mail-ed1-f49.google.com [209.85.208.49]) (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 84AB02DBF76 for ; Mon, 16 Jun 2025 13:33:17 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.49 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1750080801; cv=none; b=Y2MfPGyru24qb5ZVOqd0lbFlz4d56Y9k3GU2AFHJ0Kerb5kTDu1HcpDsdaS1goj7BVmjZWPaCgrvovtLGTCVDcW3SkNmlBHjHH3PLuGaHpEWt7HnG5DvusUvpHP8u/JmT8rySoOsdxV3QGuLrCtLfA841CA+aQ/TQYAMhyPci9c= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1750080801; c=relaxed/simple; bh=CTkb+Zlmdex8XBt0jVOO6st2izRqSZRpU7vG9r6yMUM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=eGLmNx3p+vqzIPD5nSawsGJbwghEc6wOCFH1TqBLZzqyMPYSnHFV9zN8dqkx4MTS1JfAd0bsFXA3jSINn3ULJ3ikncpVchPZicS0mrTjfAtmlEUAU71mRFGi0H7h5dmuH6NY4IYsS3VE3ATEvMCmh4Rco5DE++EpbDB4axAaxCU= 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=mq+BB86u; arc=none smtp.client-ip=209.85.208.49 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="mq+BB86u" Received: by mail-ed1-f49.google.com with SMTP id 4fb4d7f45d1cf-607ec30df2bso8356376a12.1 for ; Mon, 16 Jun 2025 06:33:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; t=1750080796; x=1750685596; 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=vDh9sojrOp84Y06qtG9e+QA6xkN553TiG7S+NM2mdjE=; b=mq+BB86uhOunM7FEk3Nd2SS8zUDhs8NK+WvgWTP4sdKnr6gr9wZ268lOtFRzKxbLTo Hojv+6qZ8RXz6KDo7q+Ze6tc9IpAtLEFS9lU4pGJwp4pFGJjyexg0igEAmG14vzNmkho Cipdz6cP2JkugCZUTO2E665g6Wbx0yUox+jLQ= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1750080796; x=1750685596; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=vDh9sojrOp84Y06qtG9e+QA6xkN553TiG7S+NM2mdjE=; b=sgDbJ/vAw0v3Hp96ewUXk1FyuLQkwuTGKZCCAauuhg8E/F0SxPEDiKGGp+yhoOdlRB esmPuMA5FYvD9qnLrH2TM6ZTXXrOh/lUJyBZthNe4oySD66mcRDX+YdD9iFyImG5+fRL eCIaSaxpK7RSP14HjMxDRJGQHjh8jaIujGgnSv4E7z/AXHoaji6GevX9dYDXArQAFPXq Pz1BDNMqagSE5k6aSFe8DWpzgSmeVQuehpUXMUZW7yji3q+AjezzCxc0EpESDFXwoHZA xhi7kJWKr8XqF5vyPTIUB7PA1DnKpmWlFY+mDIeBavjuG49fRcXdsC0lc8iA56z7tGRA ssyg== X-Forwarded-Encrypted: i=1; AJvYcCXprme9liTB/ec1hF8j/+1w61I2VQ7wHT7V3OAzypXaG3zKB9tj3bUTCDPCT33tIogQlRr6uQfCROA=@vger.kernel.org X-Gm-Message-State: AOJu0YziRHSMPERdx0xmfqEIBh28u3pP+POJIPnploYFUCkUEoIpO/SL 9f0KXSXOh/wwGOq4jfilhVkJk4yhOXwWo+8bmdqikgnysxGWH6J1txYifIvb0bskuQ== X-Gm-Gg: ASbGnctWK279FVCfC8qJlzy5XP+D/JL8JzbCQvq7CRpdNouEKNmDWkJrIh34NWz5O+B SyfeGG7kJ4+gY0djklkGPoXTM//BlmLwR60smh38UZqK2lST6NqVHlUsnPDk1cEyAW8c/UF9Ogc HASO4HmTNXf0bbqJDE3d1S8mVpT4a3Ve2AyFW5WBPLIl4NqI6Npjl01HoU9LxTR9C34E1ibhETR Aai/1PxZi7hEs408zr7wt/Hp6kS2LgXDwrR5L9PsTIM8XnrmvFYYvpRv8I/Td4evg54WlfsoYwc rr1VYBlU6xIOGXesw5PTTovSlCob1yQJAyiu1iyQlqmNB4fGE5BvSdNBpkY9CXMyD3xB2OlPnyU G6o8vIpYSA5MBkeJ2GwAD510N5bVR2lpgilRy/T3gvwgGYDbDX4h78Z1pEg== X-Google-Smtp-Source: AGHT+IGv/AOmT6GEhQ7oUlSng8rP/zfkQJfNKBJnimzO204DsmsQDo7srREO5LYOs54/Dw1yISBEwQ== X-Received: by 2002:a05:6402:909:b0:607:19a6:9f1d with SMTP id 4fb4d7f45d1cf-608d08aa3d4mr7890265a12.14.1750080795674; Mon, 16 Jun 2025 06:33:15 -0700 (PDT) Received: from akuchynski.c.googlers.com.com (244.175.141.34.bc.googleusercontent.com. [34.141.175.244]) by smtp.gmail.com with ESMTPSA id 4fb4d7f45d1cf-608b4a94ce7sm6036664a12.58.2025.06.16.06.33.15 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 16 Jun 2025 06:33:15 -0700 (PDT) From: Andrei Kuchynski To: Heikki Krogerus , Dmitry Baryshkov , Abhishek Pandit-Subedi , Jameson Thies , Benson Leung , Tzung-Bi Shih Cc: Greg Kroah-Hartman , Guenter Roeck , Pooja Katiyar , Badhri Jagan Sridharan , RD Babiera , linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org, chrome-platform@lists.linux.dev, Andrei Kuchynski Subject: [PATCH 04/10] usb: typec: Expose alternate mode priorities via sysfs Date: Mon, 16 Jun 2025 13:31:41 +0000 Message-ID: <20250616133147.1835939-5-akuchynski@chromium.org> X-Mailer: git-send-email 2.50.0.rc1.591.g9c95f17f64-goog In-Reply-To: <20250616133147.1835939-1-akuchynski@chromium.org> References: <20250616133147.1835939-1-akuchynski@chromium.org> Precedence: bulk X-Mailing-List: linux-usb@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 This sysfs attribute specifies the preferred order for enabling DisplayPort alt-mode, Thunderbolt alt-mode, and USB4 mode. Signed-off-by: Andrei Kuchynski --- Documentation/ABI/testing/sysfs-class-typec | 17 ++++ drivers/usb/typec/Makefile | 2 +- drivers/usb/typec/class.c | 26 ++++++ drivers/usb/typec/class.h | 2 + drivers/usb/typec/mode_selection.c | 93 +++++++++++++++++++++ drivers/usb/typec/mode_selection.h | 5 ++ include/linux/usb/typec_altmode.h | 7 ++ 7 files changed, 151 insertions(+), 1 deletion(-) create mode 100644 drivers/usb/typec/mode_selection.c create mode 100644 drivers/usb/typec/mode_selection.h diff --git a/Documentation/ABI/testing/sysfs-class-typec b/Documentation/ABI/testing/sysfs-class-typec index 38e101c17a00..46eee82042ab 100644 --- a/Documentation/ABI/testing/sysfs-class-typec +++ b/Documentation/ABI/testing/sysfs-class-typec @@ -162,6 +162,23 @@ Description: Lists the supported USB Modes. The default USB mode that is used - usb3 (USB 3.2) - usb4 (USB4) +What: /sys/class/typec//altmode_priorities +Date: June 2025 +Contact: Andrei Kuchynski +Description: Lists the alternate modes supported by the port and their + priorities. The priority setting determines the order in which + Displayport alt-mode, Thunderbolt alt-mode and USB4 mode will be + activated, indicating the preferred selection sequence. A value of -1 + disables automatic entry into a specific mode, while lower numbers + indicate higher priority. The default priorities can be modified by + assigning new values. Modes without explicitly set values default to -1, + effectively disabling them. + + Example values: + - "USB4=0 TBT=1 DP=2" + - "USB4=-1 TBT=0" + - "DP=-1 USB4=-1 TBT=-1" + USB Type-C partner devices (eg. /sys/class/typec/port0-partner/) What: /sys/class/typec/-partner/accessory_mode 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.c b/drivers/usb/typec/class.c index a72325ff099a..726fc0411c44 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); @@ -1942,6 +1943,25 @@ static ssize_t orientation_show(struct device *dev, } static DEVICE_ATTR_RO(orientation); +static ssize_t altmode_priorities_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct typec_port *port = to_typec_port(dev); + int ret = typec_mode_priorities_set(port, buf); + + return ret ? : size; +} + +static ssize_t altmode_priorities_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct typec_port *port = to_typec_port(dev); + + return typec_mode_priorities_get(port, buf); +} +static DEVICE_ATTR_RW(altmode_priorities); + static struct attribute *typec_attrs[] = { &dev_attr_data_role.attr, &dev_attr_power_operation_mode.attr, @@ -1954,6 +1974,7 @@ static struct attribute *typec_attrs[] = { &dev_attr_port_type.attr, &dev_attr_orientation.attr, &dev_attr_usb_capability.attr, + &dev_attr_altmode_priorities.attr, NULL, }; @@ -1992,6 +2013,9 @@ static umode_t typec_attr_is_visible(struct kobject *kobj, return 0; if (!port->ops || !port->ops->default_usb_mode_set) return 0444; + } else if (attr == &dev_attr_altmode_priorities.attr) { + if (!port->alt_mode_override) + return 0; } return attr->mode; @@ -2652,6 +2676,8 @@ struct typec_port *typec_register_port(struct device *parent, else if (cap->usb_capability & USB_CAPABILITY_USB2) port->usb_mode = USB_MODE_USB2; + typec_mode_priorities_set(port, NULL); + device_initialize(&port->dev); port->dev.class = &typec_class; port->dev.parent = parent; diff --git a/drivers/usb/typec/class.h b/drivers/usb/typec/class.h index f05d9201c233..dffe5ef03bc6 100644 --- a/drivers/usb/typec/class.h +++ b/drivers/usb/typec/class.h @@ -5,6 +5,7 @@ #include #include +#include struct typec_mux; struct typec_switch; @@ -82,6 +83,7 @@ struct typec_port { struct device *usb3_dev; bool alt_mode_override; + int altmode_priorities[TYPEC_ALTMODE_MAX]; }; #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..d984c79eef45 --- /dev/null +++ b/drivers/usb/typec/mode_selection.c @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright 2025 Google LLC. + */ + +#include +#include +#include "class.h" + +#define MODE_PRIORITY_DISABLED -1 + +static const char * const altmode_names[] = { + [TYPEC_ALTMODE_DP] = "DP", + [TYPEC_ALTMODE_TBT] = "TBT", + [TYPEC_ALTMODE_USB4] = "USB4", +}; +static const char * const default_priorities = "USB4=0 TBT=1 DP=2"; + +/* -------------------------------------------------------------------------- */ +/* port 'altmode_priorities' attribute */ + +int typec_mode_priorities_set(struct typec_port *port, + const char *user_priorities) +{ + int priorities[TYPEC_ALTMODE_MAX]; + const char *str_priority = user_priorities ? : default_priorities; + char *buf, *buf_free; + int ret = -EINVAL; + char *str_name; + int i; + + buf = vmalloc(strlen(str_priority) + 1); + if (!buf) + return -ENOMEM; + strscpy(buf, str_priority, strlen(str_priority) + 1); + buf_free = buf; + + for (i = 0; i < TYPEC_ALTMODE_MAX; i++) + priorities[i] = MODE_PRIORITY_DISABLED; + + while ((str_name = strsep(&buf, " "))) { + char *str_value = strchr(str_name, '='); + int value; + int mode; + + ret = -EINVAL; + if (!str_value) + goto parse_exit; + *str_value++ = '\0'; + + if (kstrtoint(str_value, 10, &value) || + value < MODE_PRIORITY_DISABLED) + goto parse_exit; + + if (value > MODE_PRIORITY_DISABLED) { + for (i = 0; i < TYPEC_ALTMODE_MAX; i++) + if (value == priorities[i]) + goto parse_exit; + } + + for (mode = 0; mode < TYPEC_ALTMODE_MAX && + strcmp(str_name, altmode_names[mode]);) + mode++; + if (mode == TYPEC_ALTMODE_MAX || + priorities[mode] != MODE_PRIORITY_DISABLED) + goto parse_exit; + + priorities[mode] = value; + ret = 0; + } + + for (i = 0; i < TYPEC_ALTMODE_MAX; i++) + port->altmode_priorities[i] = priorities[i]; + +parse_exit: + vfree(buf_free); + + return ret; +} + +int typec_mode_priorities_get(struct typec_port *port, char *buf) +{ + ssize_t count = 0; + int i; + + for (i = 0; i < TYPEC_ALTMODE_MAX; i++) { + if (i != TYPEC_ALTMODE_USB4 || + port->cap->usb_capability & USB_CAPABILITY_USB4) + count += sysfs_emit_at(buf, count, "%s=%d ", + altmode_names[i], port->altmode_priorities[i]); + } + return count + sysfs_emit_at(buf, count, "\n"); +} diff --git a/drivers/usb/typec/mode_selection.h b/drivers/usb/typec/mode_selection.h new file mode 100644 index 000000000000..643f04f48343 --- /dev/null +++ b/drivers/usb/typec/mode_selection.h @@ -0,0 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +int typec_mode_priorities_set(struct typec_port *port, + const char *user_priorities); +int typec_mode_priorities_get(struct typec_port *port, char *buf); diff --git a/include/linux/usb/typec_altmode.h b/include/linux/usb/typec_altmode.h index b3c0866ea70f..7ca2040ee1e4 100644 --- a/include/linux/usb/typec_altmode.h +++ b/include/linux/usb/typec_altmode.h @@ -145,6 +145,13 @@ enum { #define TYPEC_MODAL_STATE(_state_) ((_state_) + TYPEC_STATE_MODAL) +enum { + 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); From patchwork Mon Jun 16 13:31:42 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrei Kuchynski X-Patchwork-Id: 897320 Received: from mail-ed1-f49.google.com (mail-ed1-f49.google.com [209.85.208.49]) (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 6A0B62DF3D1 for ; Mon, 16 Jun 2025 13:33:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.49 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1750080803; cv=none; b=q0B9BHnNF2fPt2Lwg/OFyrLp28c1TAw0Uu96fG39o0rVQHS6aR/cJZGBW0cdz4I8BB3NWmuVpaFYKBVq8BMu+K2qx1q2oyPBJ4MB7+BAe17wu9fjcrMTodxkrT1eAnWGCH4gxQNOiabzstzkZLDmFZJoQFBjVdz8P/mjwSwO/rI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1750080803; c=relaxed/simple; bh=3/DRUHcMTi2y3mpOqN273fqCN7TXxAZm6Dg+1+doKTo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=lNAh0upD28xwI6UVchuGY8x3uSUhEdkfm6syGeoFrU+CKip+QJqswuFLCOfaVKZX0RolS4sEXgcsK1+4SLLHVxuvraWn+ow6xJfSB/UkHKecc3J/oCgHq1eZbisS2PTJIO9DOi8vUTKt4x1gZxKmZBGfwdBAaViIBBygqgRVKm4= 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=OhYGMn/9; arc=none smtp.client-ip=209.85.208.49 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="OhYGMn/9" Received: by mail-ed1-f49.google.com with SMTP id 4fb4d7f45d1cf-6097d144923so497510a12.1 for ; Mon, 16 Jun 2025 06:33:19 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; t=1750080798; x=1750685598; 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=LJ08ykcaUh86luL6nlhAeVkvWPVp9UYwGXyL0gTTMNk=; b=OhYGMn/9cK50w2ys0eROu1jfa6/WwjUJwvlZ08jjwsYjIhza8+D5UVVcx9XVfKYoUo GyLT6lGVONgDP6JLPjPtPH9qPcd2bOkVg4z7KaRwopR8iO+ixMEbuRp61jfRURaGFIeT rF3O4gzEaHNwmEvvxQb4y3I7ehinmyMwcbsSI= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1750080798; x=1750685598; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=LJ08ykcaUh86luL6nlhAeVkvWPVp9UYwGXyL0gTTMNk=; b=bb3FWsTq5XYZXG78k1LXF6ym3Wl8OozDZt7awLOpTd30qrFjOc9FmtIT/N+xEeUFD4 qF3hhD/+xddEVtlk0hWuCPAkrRB3o7z3cDyWmNkGpKmT5uoXIqyR2Ex6A2FPCiRLxd2A zLRDGHvTCY1/ZQ+i6hD+7OWLjfNUFdQTpJT1GFaYtZUUnVaZak9rmT/2eM0l6UA0+7Vd Ezmu6N5Ig9eM/KEanXZXqgQ5FAyP8U7bMRRiSmwfi4a8oIYYUkMTo1nYYndcTSST13Kl nB+3OLvwkRqYMh5KlcqU4bOsnD8f+/BLBxlH3CXGb6B6IVQIrOvlRp4FfkK5XeKJLmW+ P/hA== X-Forwarded-Encrypted: i=1; AJvYcCXpRFNwn5Ygn0fPE88g9fAyegoSmrI0HyHIa/ORXSwAPMgR1jE4vqrDW81i0bz8fY1YdnuYAvjuPcc=@vger.kernel.org X-Gm-Message-State: AOJu0YxKF/v5zXgB8RnQOzzlytrWxzFIe7tnmd7Eof1r6qLIsdJRi8zL ZTTfyZJcklb2Mn90rvcIzPXKjOM8MGJAx3zaq4Qd7ZyTktagC+B6BOhcTof2uZZhKg== X-Gm-Gg: ASbGncsHE2zdv7MDYoKNTOK9sVAGj5kehFgNEKe+kGr31eqmKD4Ee94s8xwIZ+dOvS8 CwFydbqNtLmQWD3DPnTTwrb0M2htQa3ok42bbkz6t6mXThfo4exjDhLs3nIjrQ97kdckQTM9Zzy CuIP5gJ5PcEJWefa1Lp3KcRqUPRvH7D8676PWfyUYlculxXe29A9oaChitxWiAuS3f/CkbHqiYW sMV0mLFFDRN9a+JJ4DG9uku3mXHw8l9EqXni9vNIT3rf8O9gZPZ7C9OfKSyQRa3LIgodKF5rIFx l7FYIzRWlac76qfDkzQq8O+0kdCsnCW8wdTnsAjmJkuJChzj4iz25bV7iEx32+f4QNLtI2aKq2E E+HIfza1MUfPhV7i4LRLAYpszVq06yYNwBKbFkc61C19lk2EoEtdFw2sEguUf/mXacOvC X-Google-Smtp-Source: AGHT+IF6GKFag0i4Lv/O+v/7mDdJI4fryPv5+oukAaxB/RbyOwFkxmlwO5un2SAx2VKkhO7cXQoPzw== X-Received: by 2002:a05:6402:13d0:b0:601:9afe:8da9 with SMTP id 4fb4d7f45d1cf-608ce59a873mr7840208a12.11.1750080797505; Mon, 16 Jun 2025 06:33:17 -0700 (PDT) Received: from akuchynski.c.googlers.com.com (244.175.141.34.bc.googleusercontent.com. [34.141.175.244]) by smtp.gmail.com with ESMTPSA id 4fb4d7f45d1cf-608b4a94ce7sm6036664a12.58.2025.06.16.06.33.16 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 16 Jun 2025 06:33:17 -0700 (PDT) From: Andrei Kuchynski To: Heikki Krogerus , Dmitry Baryshkov , Abhishek Pandit-Subedi , Jameson Thies , Benson Leung , Tzung-Bi Shih Cc: Greg Kroah-Hartman , Guenter Roeck , Pooja Katiyar , Badhri Jagan Sridharan , RD Babiera , linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org, chrome-platform@lists.linux.dev, Andrei Kuchynski Subject: [PATCH 05/10] usb: typec: Implement automated alternate mode selection Date: Mon, 16 Jun 2025 13:31:42 +0000 Message-ID: <20250616133147.1835939-6-akuchynski@chromium.org> X-Mailer: git-send-email 2.50.0.rc1.591.g9c95f17f64-goog In-Reply-To: <20250616133147.1835939-1-akuchynski@chromium.org> References: <20250616133147.1835939-1-akuchynski@chromium.org> Precedence: bulk X-Mailing-List: linux-usb@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 This commit introduces mode_selection sysfs attribute to control automated alternate mode negotiation. Writing "yes" to this file activates the automated selection process for DisplayPort alt-mode, Thunderbolt alt-mode, and USB4 mode. Conversely, writing "no" will cancel any ongoing selection process and exit the currently active alternate mode. Signed-off-by: Andrei Kuchynski --- Documentation/ABI/testing/sysfs-class-typec | 17 + drivers/usb/typec/class.c | 55 ++- drivers/usb/typec/class.h | 12 + drivers/usb/typec/mode_selection.c | 412 ++++++++++++++++++++ drivers/usb/typec/mode_selection.h | 37 ++ include/linux/usb/pd_vdo.h | 2 + include/linux/usb/typec_altmode.h | 5 + 7 files changed, 537 insertions(+), 3 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-class-typec b/Documentation/ABI/testing/sysfs-class-typec index 46eee82042ab..ec205f49964e 100644 --- a/Documentation/ABI/testing/sysfs-class-typec +++ b/Documentation/ABI/testing/sysfs-class-typec @@ -264,6 +264,23 @@ Description: The USB Modes that the partner device supports. The active mode - usb3 (USB 3.2) - usb4 (USB4) +What: /sys/class/typec/-partner/mode_selection +Date: June 2025 +Contact: Andrei Kuchynski +Description: Lists the partner-supported alternate modes and mode entry + results with the currently entered mode bracketed. If a cable doesn't + support a mode, it's marked as 'nc'. An ellipsis indicates a mode + currently in progress. Automated mode selection is activated by writing + "yes" to the file. Conversely, writing "no" will cancel any ongoing + selection process and exit the currently active mode, if any. + + Example values: + - "DP TBT=... USB4=nc": The cable does not support USB4 mode, + The driver is currently attempting to enter Thunderbolt alt-mode. + - "[DP] TBT=-EOPNOTSUPP USB4=-ETIME": USB4 mode entry failed due to + a timeout, Thunderbolt failed with the result -EOPNOTSUPP, + and DisplayPort is the active alt-mode. + USB Type-C cable devices (eg. /sys/class/typec/port0-cable/) Note: Electronically Marked Cables will have a device also for one cable plug diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c index 726fc0411c44..e8432070b403 100644 --- a/drivers/usb/typec/class.c +++ b/drivers/usb/typec/class.c @@ -541,7 +541,7 @@ static void typec_altmode_release(struct device *dev) } const struct device_type typec_altmode_dev_type = { - .name = "typec_alternate_mode", + .name = ALTERNATE_MODE_DEVICE_TYPE_NAME, .groups = typec_altmode_groups, .release = typec_altmode_release, }; @@ -741,6 +741,34 @@ static ssize_t number_of_alternate_modes_show(struct device *dev, struct device_ } static DEVICE_ATTR_RO(number_of_alternate_modes); +static ssize_t mode_selection_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct typec_partner *partner = to_typec_partner(dev); + + return typec_mode_selection_get(partner, buf); +} + +static ssize_t mode_selection_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t size) +{ + struct typec_partner *partner = to_typec_partner(dev); + bool start; + int ret = kstrtobool(buf, &start); + + if (ret) + return ret; + + if (start) + ret = typec_mode_selection_start(partner); + else + ret = typec_mode_selection_reset(partner); + + return ret ? : size; +} +static DEVICE_ATTR_RW(mode_selection); + static struct attribute *typec_partner_attrs[] = { &dev_attr_accessory_mode.attr, &dev_attr_supports_usb_power_delivery.attr, @@ -748,6 +776,7 @@ static struct attribute *typec_partner_attrs[] = { &dev_attr_type.attr, &dev_attr_usb_mode.attr, &dev_attr_usb_power_delivery_revision.attr, + &dev_attr_mode_selection.attr, NULL }; @@ -772,6 +801,10 @@ static umode_t typec_partner_attr_is_visible(struct kobject *kobj, struct attrib if (!get_pd_product_type(kobj_to_dev(kobj))) return 0; + if (attr == &dev_attr_mode_selection.attr) + if (!port->alt_mode_override) + return 0444; + return attr->mode; } @@ -850,8 +883,10 @@ int typec_partner_set_identity(struct typec_partner *partner) usb_capability |= USB_CAPABILITY_USB2; if (devcap & DEV_USB3_CAPABLE) usb_capability |= USB_CAPABILITY_USB3; - if (devcap & DEV_USB4_CAPABLE) + if (devcap & DEV_USB4_CAPABLE) { usb_capability |= USB_CAPABILITY_USB4; + typec_mode_selection_add_mode(partner, TYPEC_ALTMODE_USB4); + } } else { usb_capability = PD_VDO_DFP_HOSTCAP(id->vdo[0]); } @@ -971,7 +1006,12 @@ struct typec_altmode * typec_partner_register_altmode(struct typec_partner *partner, const struct typec_altmode_desc *desc) { - return typec_register_altmode(&partner->dev, desc); + struct typec_altmode *alt = typec_register_altmode(&partner->dev, desc); + + if (alt) + typec_mode_selection_add_mode(partner, TYPEC_SVID_TO_ALTMODE(alt->svid)); + + return alt; } EXPORT_SYMBOL_GPL(typec_partner_register_altmode); @@ -1075,6 +1115,8 @@ struct typec_partner *typec_register_partner(struct typec_port *port, typec_partner_link_device(partner, port->usb3_dev); mutex_unlock(&port->partner_link_lock); + typec_mode_selection_create(partner); + return partner; } EXPORT_SYMBOL_GPL(typec_register_partner); @@ -1092,6 +1134,7 @@ void typec_unregister_partner(struct typec_partner *partner) if (IS_ERR_OR_NULL(partner)) return; + typec_mode_selection_destroy(partner); port = to_typec_port(partner->dev.parent); mutex_lock(&port->partner_link_lock); @@ -1360,6 +1403,7 @@ int typec_cable_set_identity(struct typec_cable *cable) } EXPORT_SYMBOL_GPL(typec_cable_set_identity); +static struct typec_partner *typec_get_partner(struct typec_port *port); /** * typec_register_cable - Register a USB Type-C Cable * @port: The USB Type-C Port the cable is connected to @@ -1374,6 +1418,7 @@ struct typec_cable *typec_register_cable(struct typec_port *port, struct typec_cable_desc *desc) { struct typec_cable *cable; + struct typec_partner *partner; int ret; cable = kzalloc(sizeof(*cable), GFP_KERNEL); @@ -1405,6 +1450,10 @@ struct typec_cable *typec_register_cable(struct typec_port *port, return ERR_PTR(ret); } + partner = typec_get_partner(port); + typec_mode_selection_add_cable(partner, cable); + put_device(&partner->dev); + return cable; } EXPORT_SYMBOL_GPL(typec_register_cable); diff --git a/drivers/usb/typec/class.h b/drivers/usb/typec/class.h index dffe5ef03bc6..30e66d283a10 100644 --- a/drivers/usb/typec/class.h +++ b/drivers/usb/typec/class.h @@ -6,6 +6,7 @@ #include #include #include +#include struct typec_mux; struct typec_switch; @@ -27,6 +28,8 @@ struct typec_cable { enum usb_pd_svdm_ver svdm_version; }; +struct mode_selection_state; + struct typec_partner { struct device dev; unsigned int usb_pd:1; @@ -41,6 +44,13 @@ struct typec_partner { struct usb_power_delivery *pd; + struct delayed_work mode_selection_work; + DECLARE_KFIFO(mode_sequence, struct mode_selection_state *, + roundup_pow_of_two(TYPEC_ALTMODE_MAX)); + struct mutex mode_sequence_lock; + struct mode_selection_state *mode_states; + struct mode_selection_state *active_mode; + void (*attach)(struct typec_partner *partner, struct device *dev); void (*deattach)(struct typec_partner *partner, struct device *dev); }; @@ -113,4 +123,6 @@ static inline int typec_link_ports(struct typec_port *connector) { return 0; } static inline void typec_unlink_ports(struct typec_port *connector) { } #endif +#define ALTERNATE_MODE_DEVICE_TYPE_NAME "typec_alternate_mode" + #endif /* __USB_TYPEC_CLASS__ */ diff --git a/drivers/usb/typec/mode_selection.c b/drivers/usb/typec/mode_selection.c index d984c79eef45..2bef50226af4 100644 --- a/drivers/usb/typec/mode_selection.c +++ b/drivers/usb/typec/mode_selection.c @@ -5,9 +5,22 @@ #include #include +#include +#include +#include "mode_selection.h" #include "class.h" #define MODE_PRIORITY_DISABLED -1 +#define MODE_SELECTION_NO_RESULT 1 + +static unsigned int mode_selection_timeout = 4000; +module_param(mode_selection_timeout, uint, 0644); +MODULE_PARM_DESC(mode_selection_timeout, "The timeout mode entry, ms"); + +static unsigned int mode_selection_delay = 1000; +module_param(mode_selection_delay, uint, 0644); +MODULE_PARM_DESC(mode_selection_delay, + "The delay between attempts to enter or exit a mode, ms"); static const char * const altmode_names[] = { [TYPEC_ALTMODE_DP] = "DP", @@ -16,6 +29,14 @@ static const char * const altmode_names[] = { }; static const char * const default_priorities = "USB4=0 TBT=1 DP=2"; +struct mode_selection_state { + int mode; + bool enable; + bool cable_capability; + bool enter; + int result; +}; + /* -------------------------------------------------------------------------- */ /* port 'altmode_priorities' attribute */ @@ -91,3 +112,394 @@ int typec_mode_priorities_get(struct typec_port *port, char *buf) } return count + sysfs_emit_at(buf, count, "\n"); } + +/* -------------------------------------------------------------------------- */ +/* partner 'mod_selection' attribute */ + +/** + * mode_selection_next() - Process mode selection results and schedule next + * action + * + * This function evaluates the outcome of the previous mode entry or exit + * attempt. Based on this result, it determines the next alternate mode to + * process and schedules `mode_selection_work()` if further actions are + * required. + * + * If the previous mode entry was successful, the mode selection sequence is + * considered complete for the current cycle. + * + * If the previous mode entry failed, this function schedules + * `mode_selection_work()` to attempt exiting the currently active mode. + * + * If the previous operation was an exit (after a failed entry attempt), + * `mode_selection_next()` then advances the internal list of candidate + * modes to determine the next mode to enter. + */ +static void mode_selection_next( + struct typec_partner *partner, struct mode_selection_state *ms) +{ + if (!ms->result && ms->enter) { + dev_info(&partner->dev, "%s mode entered\n", altmode_names[ms->mode]); + + partner->active_mode = ms; + kfifo_reset(&partner->mode_sequence); + } else { + if (ms->result && ms->enter) + dev_err(&partner->dev, "%s mode entry failed: %pe\n", + altmode_names[ms->mode], ERR_PTR(ms->result)); + + if (ms->result != -EBUSY) { + if (ms->enter) + ms->enter = false; + else + kfifo_skip(&partner->mode_sequence); + } + + if (!kfifo_is_empty(&partner->mode_sequence)) { + cancel_delayed_work(&partner->mode_selection_work); + schedule_delayed_work(&partner->mode_selection_work, + msecs_to_jiffies(mode_selection_delay)); + } + } +} + +static void mode_selection_complete(struct typec_partner *partner, + const int mode, const int result) +{ + struct mode_selection_state *ms; + + mutex_lock(&partner->mode_sequence_lock); + if (kfifo_peek(&partner->mode_sequence, &ms)) { + if (ms->mode == mode) { + ms->result = result; + mode_selection_next(partner, ms); + } + } + mutex_unlock(&partner->mode_sequence_lock); +} + +void typec_mode_selection_altmode_complete(struct typec_altmode *alt, + const int result) +{ + mode_selection_complete(to_typec_partner(alt->dev.parent), + TYPEC_SVID_TO_ALTMODE(alt->svid), result); +} +EXPORT_SYMBOL_GPL(typec_mode_selection_altmode_complete); + +void typec_mode_selection_usb4_complete(struct typec_partner *partner, + const int result) +{ + mode_selection_complete(partner, TYPEC_ALTMODE_USB4, result); +} +EXPORT_SYMBOL_GPL(typec_mode_selection_usb4_complete); + +static int mode_selection_activate_altmode(struct device *dev, void *data) +{ + if (!strcmp(dev->type->name, ALTERNATE_MODE_DEVICE_TYPE_NAME)) { + struct typec_altmode *alt = to_typec_altmode(dev); + struct mode_selection_state *ms = (struct mode_selection_state *)data; + + if (ms->mode == TYPEC_SVID_TO_ALTMODE(alt->svid)) { + int result = -EOPNOTSUPP; + + if (alt->ops && alt->ops->activate) + result = alt->ops->activate(alt, ms->enter ? 1 : 0); + if (ms->enter) + ms->result = result; + return 1; + } + } + + return 0; +} + +static void mode_selection_activate_mode(struct typec_partner *partner, + struct mode_selection_state *ms) +{ + dev_info(&partner->dev, "Attempt to %s %s mode\n", + ms->enter ? "enter" : "exit", altmode_names[ms->mode]); + + if (ms->mode == TYPEC_ALTMODE_USB4) { + struct typec_port *port = to_typec_port(partner->dev.parent); + int result = -EOPNOTSUPP; + + if (port->ops && port->ops->enter_usb_mode) + result = port->ops->enter_usb_mode(port, + ms->enter ? USB_MODE_USB4 : USB_MODE_NONE); + + if (ms->enter) + ms->result = result; + } else { + const int ret = device_for_each_child(&partner->dev, ms, + mode_selection_activate_altmode); + if (!ret && ms->enter) + ms->result = -ENODEV; + } +} + +/** + * mode_selection_work() - Activate entry into the upcoming mode + * + * This function works in conjunction with `mode_selection_next()`. + * It attempts to activate the next alternate mode in the selection sequence. + * + * If the mode activation (`mode_selection_activate_mode()`) fails, + * `mode_selection_next()` will be called to initiate a new selection cycle. + * + * Otherwise, the result is temporarily set to -ETIME, and + * `mode_selection_activate_mode()` is scheduled for a subsequent entry after a + * timeout period. The alternate mode driver is expected to call back with the + * actual mode entry result. Upon this callback, `mode_selection_next()` will + * determine the subsequent mode and re-schedule mode_selection_work(). + */ +static void mode_selection_work(struct work_struct *work) +{ + struct typec_partner *partner = container_of(work, struct typec_partner, + mode_selection_work.work); + struct mode_selection_state *ms; + + mutex_lock(&partner->mode_sequence_lock); + if (kfifo_peek(&partner->mode_sequence, &ms)) { + if (ms->enter && ms->result == -ETIME) { + mode_selection_next(partner, ms); + } else { + mode_selection_activate_mode(partner, ms); + + if (!ms->enter || ms->result) + mode_selection_next(partner, ms); + else { + ms->result = -ETIME; + schedule_delayed_work(&partner->mode_selection_work, + msecs_to_jiffies(mode_selection_timeout)); + } + } + } + mutex_unlock(&partner->mode_sequence_lock); +} + +static void mode_selection_init(struct typec_partner *partner) +{ + int i; + + for (i = 0; i < TYPEC_ALTMODE_MAX; i++) { + partner->mode_states[i].mode = i; + partner->mode_states[i].result = MODE_SELECTION_NO_RESULT; + } + + kfifo_reset(&partner->mode_sequence); + partner->active_mode = NULL; +} + +int typec_mode_selection_create(struct typec_partner *partner) +{ + partner->mode_states = vmalloc( + sizeof(struct mode_selection_state) * TYPEC_ALTMODE_MAX); + if (!partner->mode_states) + return -ENOMEM; + + INIT_KFIFO(partner->mode_sequence); + mutex_init(&partner->mode_sequence_lock); + mode_selection_init(partner); + INIT_DELAYED_WORK(&partner->mode_selection_work, mode_selection_work); + + return 0; +} + +void typec_mode_selection_add_mode(struct typec_partner *partner, + const int mode) +{ + struct typec_port *port = to_typec_port(partner->dev.parent); + + if (!partner->mode_states) + return; + + if (mode < TYPEC_ALTMODE_MAX) { + if (mode == TYPEC_ALTMODE_USB4) { + if (!(port->cap->usb_capability & USB_CAPABILITY_USB4)) + return; + } + partner->mode_states[mode].enable = true; + } +} + +void typec_mode_selection_add_cable(struct typec_partner *partner, + struct typec_cable *cable) +{ + const u32 id_header = cable->identity->id_header; + const u32 vdo0 = cable->identity->vdo[0]; + const u32 vdo1 = cable->identity->vdo[1]; + const u32 type = PD_IDH_PTYPE(id_header); + const u32 speed = VDO_TYPEC_CABLE_SPEED(vdo0); + bool capable_dp = true; + bool capable_tbt = false; + bool capable_usb4 = false; + + if (!partner->mode_states) + return; + + if (type == IDH_PTYPE_PCABLE) { + capable_dp = (speed > CABLE_USB2_ONLY); + capable_tbt = capable_dp; + capable_usb4 = capable_dp; + } else if (type == IDH_PTYPE_ACABLE) { + const u32 version = VDO_TYPEC_CABLE_VERSION(vdo0); + const bool usb4_support = VDO_TYPEC_CABLE_USB4_SUPP(vdo1); + const bool modal_support = PD_IDH_MODAL_SUPP(id_header); + + capable_dp = modal_support; + capable_tbt = true; + capable_usb4 = (version == 3) ? usb4_support : modal_support; + } + + if (capable_dp || capable_tbt || capable_usb4) + dev_info(&partner->dev, "cable capabilities: %s %s %s\n", + capable_dp ? altmode_names[TYPEC_ALTMODE_DP] : "", + capable_tbt ? altmode_names[TYPEC_ALTMODE_TBT] : "", + capable_usb4 ? altmode_names[TYPEC_ALTMODE_USB4] : ""); + partner->mode_states[TYPEC_ALTMODE_DP].cable_capability = capable_dp; + partner->mode_states[TYPEC_ALTMODE_TBT].cable_capability = capable_tbt; + partner->mode_states[TYPEC_ALTMODE_USB4].cable_capability = capable_usb4; +} + +static void mode_selection_cancel_work(struct typec_partner *partner) +{ + /* + * mode_sequence_lock provides exclusive access to `mode_sequence` FIFO + * If the FIFO is empty, no further mode selection activities are expected + */ + mutex_lock(&partner->mode_sequence_lock); + kfifo_reset(&partner->mode_sequence); + mutex_unlock(&partner->mode_sequence_lock); + + cancel_delayed_work_sync(&partner->mode_selection_work); +} + +void typec_mode_selection_destroy(struct typec_partner *partner) +{ + if (!partner->mode_states) + return; + + mode_selection_cancel_work(partner); + mutex_destroy(&partner->mode_sequence_lock); + vfree(partner->mode_states); + partner->mode_states = NULL; +} + +/** + * typec_mode_selection_start() - Starts the alternate mode selection process. + * + * This function populates a 'mode_sequence' FIFO with pointers to + * `struct mode_selection_state` instances. The sequence is generated based on + * partner/cable capabilities and prioritized according to the port's settings. + */ +int typec_mode_selection_start(struct typec_partner *partner) +{ + struct typec_port *port = to_typec_port(partner->dev.parent); + int priorities[TYPEC_ALTMODE_MAX]; + bool pending_mode = true; + int i; + + if (!partner->mode_states) + return -ENOMEM; + + mutex_lock(&partner->mode_sequence_lock); + if (!kfifo_is_empty(&partner->mode_sequence)) { + mutex_unlock(&partner->mode_sequence_lock); + return -EINPROGRESS; + } + if (partner->active_mode) { + mutex_unlock(&partner->mode_sequence_lock); + return -EALREADY; + } + + mode_selection_init(partner); + + for (i = 0; i < TYPEC_ALTMODE_MAX; i++) { + if (partner->mode_states[i].enable && + partner->mode_states[i].cable_capability) + priorities[i] = port->altmode_priorities[i]; + else + priorities[i] = MODE_PRIORITY_DISABLED; + } + + while (pending_mode) { + int mode = TYPEC_ALTMODE_MAX; + int max_priority = INT_MAX; + + for (i = 0; i < TYPEC_ALTMODE_MAX; i++) { + if (priorities[i] != MODE_PRIORITY_DISABLED && + priorities[i] < max_priority) { + max_priority = priorities[i]; + mode = i; + } + } + + if (mode == TYPEC_ALTMODE_MAX) + pending_mode = false; + else { + partner->mode_states[mode].enter = true; + kfifo_put(&partner->mode_sequence, &partner->mode_states[mode]); + priorities[mode] = MODE_PRIORITY_DISABLED; + } + } + + if (!kfifo_is_empty(&partner->mode_sequence)) + schedule_delayed_work(&partner->mode_selection_work, 0); + mutex_unlock(&partner->mode_sequence_lock); + + return 0; +} + +int typec_mode_selection_reset(struct typec_partner *partner) +{ + if (!partner->mode_states) + return -ENOMEM; + + mode_selection_cancel_work(partner); + + if (partner->active_mode) { + partner->active_mode->enter = false; + mode_selection_activate_mode(partner, partner->active_mode); + } + mode_selection_init(partner); + + return 0; +} + +int typec_mode_selection_get(struct typec_partner *partner, char *buf) +{ + ssize_t count = 0; + int i; + struct mode_selection_state *running_ms; + + if (!partner->mode_states) + return -ENOMEM; + + mutex_lock(&partner->mode_sequence_lock); + if (!kfifo_peek(&partner->mode_sequence, &running_ms)) + running_ms = NULL; + + for (i = 0; i < TYPEC_ALTMODE_MAX; i++) { + struct mode_selection_state *ms = &partner->mode_states[i]; + + if (ms->enable) { + if (!ms->cable_capability) + count += sysfs_emit_at(buf, count, "%s=nc ", altmode_names[i]); + else if (ms == running_ms) + count += sysfs_emit_at(buf, count, "%s=... ", altmode_names[i]); + else if (ms->result == MODE_SELECTION_NO_RESULT) + count += sysfs_emit_at(buf, count, "%s ", altmode_names[i]); + else if (ms->result == 0) + count += sysfs_emit_at(buf, count, "[%s] ", altmode_names[i]); + else + count += sysfs_emit_at(buf, count, "%s=%pe ", altmode_names[i], + ERR_PTR(ms->result)); + } + } + mutex_unlock(&partner->mode_sequence_lock); + + if (count) + count += sysfs_emit_at(buf, count, "\n"); + + return count; +} diff --git a/drivers/usb/typec/mode_selection.h b/drivers/usb/typec/mode_selection.h index 643f04f48343..62e92aed76c7 100644 --- a/drivers/usb/typec/mode_selection.h +++ b/drivers/usb/typec/mode_selection.h @@ -1,5 +1,42 @@ /* SPDX-License-Identifier: GPL-2.0 */ +#include +#include + +#define TYPEC_SVID_TO_ALTMODE(svid) \ + (((svid) == USB_TYPEC_DP_SID) ? TYPEC_ALTMODE_DP : \ + ((svid) == USB_TYPEC_TBT_SID) ? TYPEC_ALTMODE_TBT : TYPEC_ALTMODE_MAX) + int typec_mode_priorities_set(struct typec_port *port, const char *user_priorities); int typec_mode_priorities_get(struct typec_port *port, char *buf); + +/** + * The mode selection process follows a lifecycle tied to the USB-C partner + * device. The API is designed to first build a set of desired modes and then + * trigger the selection process. The expected sequence of calls is as follows: + * + * Creation and Configuration: + * call typec_mode_selection_create() when the partner device is being set + * up. This allocates resources for the mode selection. + * After creation, call typec_mode_selection_add_mode() and + * typec_mode_selection_add_cable() to define the parameters for the + * selection process. + * + * Execution: + * Call typec_mode_selection_start() to trigger the mode selection. + * Call typec_mode_selection_reset() to prematurely stop the selection + * process and clear any stored results. + * + * Destruction: + * Before destroying a partner, call typec_mode_selection_destroy() + */ +int typec_mode_selection_create(struct typec_partner *partner); +void typec_mode_selection_destroy(struct typec_partner *partner); +int typec_mode_selection_start(struct typec_partner *partner); +int typec_mode_selection_reset(struct typec_partner *partner); +void typec_mode_selection_add_mode(struct typec_partner *partner, + const int mode); +void typec_mode_selection_add_cable(struct typec_partner *partner, + struct typec_cable *cable); +int typec_mode_selection_get(struct typec_partner *partner, char *buf); diff --git a/include/linux/usb/pd_vdo.h b/include/linux/usb/pd_vdo.h index 5c48e8a81403..20bcf37ad634 100644 --- a/include/linux/usb/pd_vdo.h +++ b/include/linux/usb/pd_vdo.h @@ -439,6 +439,8 @@ | (trans) << 11 | (phy) << 10 | (ele) << 9 | (u4) << 8 \ | ((hops) & 0x3) << 6 | (u2) << 5 | (u32) << 4 | (lane) << 3 \ | (iso) << 2 | (gen)) +#define VDO_TYPEC_CABLE_VERSION(vdo) (((vdo) >> 21) & 0x7) +#define VDO_TYPEC_CABLE_USB4_SUPP(vdo) (((vdo) & BIT(8)) == ACAB2_USB4_SUPP) /* * AMA VDO (PD Rev2.0) diff --git a/include/linux/usb/typec_altmode.h b/include/linux/usb/typec_altmode.h index 7ca2040ee1e4..46b0ab2b8f5d 100644 --- a/include/linux/usb/typec_altmode.h +++ b/include/linux/usb/typec_altmode.h @@ -225,4 +225,9 @@ void typec_altmode_unregister_driver(struct typec_altmode_driver *drv); module_driver(__typec_altmode_driver, typec_altmode_register_driver, \ typec_altmode_unregister_driver) +void typec_mode_selection_altmode_complete(struct typec_altmode *alt, + const int result); +void typec_mode_selection_usb4_complete(struct typec_partner *partner, + const int result); + #endif /* __USB_TYPEC_ALTMODE_H */ From patchwork Mon Jun 16 13:31:46 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrei Kuchynski X-Patchwork-Id: 897319 Received: from mail-ed1-f54.google.com (mail-ed1-f54.google.com [209.85.208.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 86DB62877D5 for ; Mon, 16 Jun 2025 13:33:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.54 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1750080807; cv=none; b=CEEDoaSdV7SgVV2/lQsJmlQUDb98TSg8X9xwku72cn9tTflgMSkLHq2iBhqR8jjSov8SmxmKkH7LGxxlug8fZ67FFsmzLVGUjmH8N7f1M9QsUhVryC7zI5iStyUp7canTBiXm4nQunTNOqVuMOnuEaRr8eLo4XxdYyGZBktw4gI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1750080807; c=relaxed/simple; bh=+scX2JYc7g6Ny57270FvHahCDuDgXd0MvSdrc6MN7nE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=bHPE5RrCOAir0nv5B4O3zkvSXujvJtOEuV7eAIyb0YVV9LOYSibH1g97diDwoTMU5IDeEh9CussNGOMibCOe5HTxUWnPen6U8UxhBec7f4g2j6To5E9Dy1dL/F1d+LwvwlYwo25dqzmz+TVqGZVdN6zMAG/lRNLr04ZqzH2Yvog= 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=gbEXMURP; arc=none smtp.client-ip=209.85.208.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="gbEXMURP" Received: by mail-ed1-f54.google.com with SMTP id 4fb4d7f45d1cf-60707b740a6so6828361a12.0 for ; Mon, 16 Jun 2025 06:33:25 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; t=1750080804; x=1750685604; 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=rPdVq+ZgSkdda1i1UwSKR/3OTMARvQfHUqZ/Ok6pdjM=; b=gbEXMURPbLhmBb8SWn6CgAXg9/Dv1SZUZYgiZf5lIV9zgH6vHMydxFNfhSWxvXjXsj HkzlqQYgEQtOCt0WqkGzI0BzQNKx0CYhVOXQxSrOzbikiUpFtVL8+/V8Oekciqrvp2Rw PQV9FbjaWK+TU61C+LJQdq8jJaJ4v2srpkvtA= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1750080804; x=1750685604; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=rPdVq+ZgSkdda1i1UwSKR/3OTMARvQfHUqZ/Ok6pdjM=; b=JtisrM9GJTZumlkWZdmZViJK2ZHKVOtlPn6ZJKUwI8L9ZNkDPsPjzCE+SLFW3sdGe7 klQIWROHD8h5X3AzemVN4WxVSDEoognymRZzphFNj7WKKjTeyYD7cr8oGtwPQ3qhG3ij 5QiHlhPAXSsDueT/q2CyxdMBcS2eaFzQoMp9/xpGx/JxhVhox4xrmQJFVTdVv05elmnP 4ug1RhT/QCmRGmteyLhqzuS8jsOoFSA0857JN7W5Z25BHzr5PI4kFbnAnvyqL1UFTBHu nn9GeuDKVlvsDsKHDT3bkO6FgeS8aadQ6v3cgzGiJRIRaNe71Ao6iyTaobaJwSnqxW3t PbJw== X-Forwarded-Encrypted: i=1; AJvYcCU2AqDMQoZB3J1dKSomFo9n5/ZlHBiVgraA6TX8VX4bgzn++LMIQNC82Pvkyo2hHTkwRKLdQFK1OWw=@vger.kernel.org X-Gm-Message-State: AOJu0Yzqa8qOb4vNdk+FppOMrcSWsY3tQBG+g1SFCWx/wZQwTK8n4wE/ CIoMSGm55dsY+w94BBs2CXMAlWs4YcOKw4nHn3v4qoL9fBcosaoNScN4IrrJn3j+BQ== X-Gm-Gg: ASbGnctSVVfvB0PRb/PJS0daW7W3//4TN6UldKnhVXllG+NwN4DEKulhmk5/pvJ0qkZ wjP+BDRbZ8SsfGYG7qG94CekPgUUKjR7loC/9EQ9W3QTHbvLCE+hQWWXk+v0Y3ijrxW8p4Q/wzf FiDioUVBDBybkpb8fWDcVUDKGoY9QN6JlzAVDFbN1K0xzBLsZUtFF1nUnAlhMNX2f3DUjdk5i8k wUQ7FueSUxk1a4AxKsjPxhpyUAsOiZlmmCkbpZsW50rCu6CkfgPtP8jcDS+AZnAuqo/AUEJFNoh uHYRHpYJAoypRVXKfNA3DqHVzUM38lxlxFrwWAhkj4EfgxLXRVPyv4u/z8br9SgOeJqc9m5Kbvy eUhBpaI93ApjGq1cWXWHsnty1ohICORlXhRLB1NcXrwGq5muBcW7h6B3rDQ== X-Google-Smtp-Source: AGHT+IEw1MMStshySFu2Mw5NkUcbiGEAYvldonklBIuuR3wJfDRbJH4QZvobhuQJzCFy5gntWE9cAA== X-Received: by 2002:a05:6402:34d3:b0:607:2d8a:9b3e with SMTP id 4fb4d7f45d1cf-608d0835d29mr7714154a12.2.1750080803788; Mon, 16 Jun 2025 06:33:23 -0700 (PDT) Received: from akuchynski.c.googlers.com.com (244.175.141.34.bc.googleusercontent.com. [34.141.175.244]) by smtp.gmail.com with ESMTPSA id 4fb4d7f45d1cf-608b4a94ce7sm6036664a12.58.2025.06.16.06.33.23 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 16 Jun 2025 06:33:23 -0700 (PDT) From: Andrei Kuchynski To: Heikki Krogerus , Dmitry Baryshkov , Abhishek Pandit-Subedi , Jameson Thies , Benson Leung , Tzung-Bi Shih Cc: Greg Kroah-Hartman , Guenter Roeck , Pooja Katiyar , Badhri Jagan Sridharan , RD Babiera , linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org, chrome-platform@lists.linux.dev, Andrei Kuchynski Subject: [PATCH 09/10] platform/chrome: cros_ec_typec: Propagate altmode entry result Date: Mon, 16 Jun 2025 13:31:46 +0000 Message-ID: <20250616133147.1835939-10-akuchynski@chromium.org> X-Mailer: git-send-email 2.50.0.rc1.591.g9c95f17f64-goog In-Reply-To: <20250616133147.1835939-1-akuchynski@chromium.org> References: <20250616133147.1835939-1-akuchynski@chromium.org> Precedence: bulk X-Mailing-List: linux-usb@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 In the `cros_typec_configure_mux` function, which concludes the DP/TBT alternate mode entry, the error code should be reported back to the Type-C mode selection logic. This ensures a detailed result is conveyed to user space. To inform partner drivers about the result, the VDM mechanism is used. For DP altmode, the DP_CMD_STATUS_UPDATE message is utilized, as it is the final one in the mode entry sequence. For TBT mode, the TBT_CMD_STATUS_UPDATE message is sent. Signed-off-by: Andrei Kuchynski --- drivers/platform/chrome/cros_ec_typec.c | 9 ++++++ drivers/platform/chrome/cros_typec_altmode.c | 32 ++++++++++++++++++-- drivers/platform/chrome/cros_typec_altmode.h | 6 ++++ include/linux/usb/typec_dp.h | 2 ++ 4 files changed, 46 insertions(+), 3 deletions(-) diff --git a/drivers/platform/chrome/cros_ec_typec.c b/drivers/platform/chrome/cros_ec_typec.c index 3aed429fde03..a4f338771094 100644 --- a/drivers/platform/chrome/cros_ec_typec.c +++ b/drivers/platform/chrome/cros_ec_typec.c @@ -610,6 +610,7 @@ static int cros_typec_enable_dp(struct cros_typec_data *typec, if (!ret) ret = typec_mux_set(port->mux, &port->state); + dp_data.error = 0; if (!ret) ret = cros_typec_displayport_status_update(port->state.alt, port->state.data); @@ -699,8 +700,16 @@ static int cros_typec_configure_mux(struct cros_typec_data *typec, int port_num, ret = cros_typec_enable_usb4(typec, port_num, pd_ctrl); } else if (port->mux_flags & USB_PD_MUX_TBT_COMPAT_ENABLED) { ret = cros_typec_enable_tbt(typec, port_num, pd_ctrl); + cros_typec_tbt_status_update( + port->port_altmode[CROS_EC_ALTMODE_TBT], ret); } else if (port->mux_flags & USB_PD_MUX_DP_ENABLED) { ret = cros_typec_enable_dp(typec, port_num, pd_ctrl); + if (ret) { + struct typec_displayport_data dp_data = {.error = ret}; + + cros_typec_displayport_status_update( + port->port_altmode[CROS_EC_ALTMODE_DP], &dp_data); + } } else if (port->mux_flags & USB_PD_MUX_SAFE_MODE) { ret = cros_typec_usb_safe_state(port); } else if (port->mux_flags & USB_PD_MUX_USB_ENABLED) { diff --git a/drivers/platform/chrome/cros_typec_altmode.c b/drivers/platform/chrome/cros_typec_altmode.c index 557340b53af0..7ee295cf0c02 100644 --- a/drivers/platform/chrome/cros_typec_altmode.c +++ b/drivers/platform/chrome/cros_typec_altmode.c @@ -28,6 +28,7 @@ struct cros_typec_altmode_data { u16 sid; u8 mode; + int error; }; struct cros_typec_dp_data { @@ -295,9 +296,16 @@ int cros_typec_displayport_status_update(struct typec_altmode *altmode, dp_data->data = *data; dp_data->pending_status_update = false; - adata->header |= VDO_CMDT(CMDT_RSP_ACK); - adata->vdo_data = &dp_data->data.status; - adata->vdo_size = 2; + if (data->error) { + adata->header |= VDO_CMDT(CMDT_RSP_NAK); + adata->error = dp_data->data.error; + adata->vdo_data = &adata->error; + adata->vdo_size = 1; + } else { + adata->header |= VDO_CMDT(CMDT_RSP_ACK); + adata->vdo_data = &dp_data->data.status; + adata->vdo_size = 2; + } schedule_work(&adata->work); mutex_unlock(&adata->lock); @@ -370,4 +378,22 @@ cros_typec_register_thunderbolt(struct cros_typec_port *port, return alt; } + +int cros_typec_tbt_status_update(struct typec_altmode *alt, int error) +{ + struct cros_typec_altmode_data *adata = typec_altmode_get_drvdata(alt); + + mutex_lock(&adata->lock); + + adata->header = VDO(adata->sid, 1, SVDM_VER_2_0, TBT_CMD_STATUS_UPDATE); + adata->header |= VDO_CMDT(error ? CMDT_RSP_NAK : CMDT_RSP_ACK); + adata->error = error; + adata->vdo_data = &adata->error; + adata->vdo_size = 1; + schedule_work(&adata->work); + + mutex_unlock(&adata->lock); + + return 0; +} #endif diff --git a/drivers/platform/chrome/cros_typec_altmode.h b/drivers/platform/chrome/cros_typec_altmode.h index 3f2aa95d065a..848a2b194b34 100644 --- a/drivers/platform/chrome/cros_typec_altmode.h +++ b/drivers/platform/chrome/cros_typec_altmode.h @@ -39,6 +39,7 @@ static inline int cros_typec_displayport_status_update(struct typec_altmode *alt struct typec_altmode * cros_typec_register_thunderbolt(struct cros_typec_port *port, struct typec_altmode_desc *desc); +int cros_typec_tbt_status_update(struct typec_altmode *alt, int error); #else static inline struct typec_altmode * cros_typec_register_thunderbolt(struct cros_typec_port *port, @@ -46,6 +47,11 @@ cros_typec_register_thunderbolt(struct cros_typec_port *port, { return typec_port_register_altmode(port->port, desc); } +static inline int cros_typec_tbt_status_update(struct typec_altmode *alt, + int error) +{ + return 0; +} #endif #endif /* __CROS_TYPEC_ALTMODE_H__ */ diff --git a/include/linux/usb/typec_dp.h b/include/linux/usb/typec_dp.h index f2da264d9c14..1679f7bb0c75 100644 --- a/include/linux/usb/typec_dp.h +++ b/include/linux/usb/typec_dp.h @@ -44,10 +44,12 @@ enum { * commands: Status Update and Configure. * * @status will show for example the status of the HPD signal. + * @error will contain the error code, if applicable. */ struct typec_displayport_data { u32 status; u32 conf; + int error; }; enum { From patchwork Mon Jun 16 13:31:47 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrei Kuchynski X-Patchwork-Id: 897318 Received: from mail-ed1-f54.google.com (mail-ed1-f54.google.com [209.85.208.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 C0F342EACFA for ; Mon, 16 Jun 2025 13:33:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.54 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1750080808; cv=none; b=GAYwtvc557iQfeMdMtn3bCM7JJEjtWZ+Zy059e2xp9z+TyUzpjjCpfWRKsZEyDuZq1ESAGknKMNm556bdNGH7DvXjEDL8modJhcOsjysTFIcIKyFhd/97TNz6YO9KofBBYOvAsbQ/s7XfTMuLBe+fIMgm/1YuF6Sh4yOzXowC7o= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1750080808; c=relaxed/simple; bh=cMKsJUotDdosJ5GgRT61ngKqLnwH/Sc2vQwUb/JvwaQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=IgSMVOrXLbdEkfsiQND/f348gHi2DWU5WQ3gHhXueFxLynnyABajBVaRVZ+HjDhIEzWbp6rFrhg0QsDqPw2/kTyg1tzZjc4EjukEceTUiyNaSO4YKXhGF8FE5wgzwvM3tOgRgCQm46ieU61zZ+45A+YF+oTBRlyUZYEBXjHrju4= 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=P5ba32G5; arc=none smtp.client-ip=209.85.208.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="P5ba32G5" Received: by mail-ed1-f54.google.com with SMTP id 4fb4d7f45d1cf-605b9488c28so8868213a12.2 for ; Mon, 16 Jun 2025 06:33:26 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; t=1750080805; x=1750685605; 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=Lc1xa9XGYazZdbig9CQp0aaqg5/Q33JTrH3v7YQaNmY=; b=P5ba32G54XHUkHVqSLXc8+9deIRH3Ms0dsz+RUhfkLPMi20QlqGv4YQl1SIgT8bAZM OwdoTo8TYSeerWtM8Tc67/+Kn9DTfmazu1tcQ6cVi5wwSuWcDZAP55wUqmMh1O1JejYF qbYsCUyTFyXQGYzoj6h5JQjsFnjwxi113I3DI= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1750080805; x=1750685605; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=Lc1xa9XGYazZdbig9CQp0aaqg5/Q33JTrH3v7YQaNmY=; b=kTooFZO8l/Xc3G9hK/Vnf66gzv0Mssz9dy8uz70yk1GLU+8U41ppu6nNHTlfyZVEaz rrMeUQfyCoR26Hy4W/AlX/wpNgrKXJZb8lG+oCuGokZ+10Ho++76COUc2rjE9WXCJSA0 3Sb1HR8/495BLNSzTYoAb/PZ35wwO9PQtIc6rwXRj70xF0gmpBZ1VQQC5umZQm4vzOky yB/8vBjhAHNQe0q4LUjvfBTLcHnDMw940vC2CJhNiQAZ3OyccMolWOwLm0QNvJoUG0ab snNuZSbmOqeQkPC6wGnt/u315dJVDOaDNosCHeKXbY2awIm0lvv8iWYe8I7RQmMeJpcR bOOg== X-Forwarded-Encrypted: i=1; AJvYcCU0OoCzrKZ7m6Dc7ytewLFs1izaCzixWELcnSgtTMKGy09NyR4lL/z1du6N9uAaQgMMyqEPPH/SpQM=@vger.kernel.org X-Gm-Message-State: AOJu0YxNKKSrAcf/49gQO1t0quP+XRCnSIrXCvOxOIMvCerm+xtOVhvz ctPbTYeRFMgJxpU2KQYcCaVKo10M6Bo2YhPyFbo3+qy28dcQ3thekpa2QOMgmHBX0A== X-Gm-Gg: ASbGnctD2zc2+AyC+Yf/cDWpZVj8a/C1PxhePEjtSn1gcInWpuafmv+MY0zNDi3xgeI IGiZSRUSRtFmLYcDOlkfkDnFgRB5C0M9T2L1N3NOd4xOy7gjK71ZXNWWSCW7ttBmeJEmzrgyJG3 DT6COkcLwYVZVw+4Cnvpk8p7eUM+1vdz0YPxvs2fQdYkEmSqIRu0IxdRYYpTj6IqtNvYBalSC5R 1Fb1PyHUsa8QuqIAGyz3ubDxKMRVLGQRvAOxzaAmtXj+zgRbnp+TsPPwC8AsaXPoJbQ6AdC6nl7 ACiJ3lQZNI+iTO6ly5dvJRyEs4O3WQq8CFpGL1qMmHMbZq1/+phCpgfFKpfrocEGxikQpajSxIJ Tvgww128USSCnuLLEAJ5S6oGyDQfUJkHc3XrwuS8tabGme+xwmuh84Isy3Q== X-Google-Smtp-Source: AGHT+IHw6+ZqjUiGtijKP7659AHwRHhXUfja1QVHvIcjre79jMfTDQp7kopiYwQiEAC5sFmbVRn9HQ== X-Received: by 2002:a05:6402:268d:b0:607:2e6b:47b2 with SMTP id 4fb4d7f45d1cf-608d0979e84mr9154566a12.26.1750080805113; Mon, 16 Jun 2025 06:33:25 -0700 (PDT) Received: from akuchynski.c.googlers.com.com (244.175.141.34.bc.googleusercontent.com. [34.141.175.244]) by smtp.gmail.com with ESMTPSA id 4fb4d7f45d1cf-608b4a94ce7sm6036664a12.58.2025.06.16.06.33.24 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 16 Jun 2025 06:33:24 -0700 (PDT) From: Andrei Kuchynski To: Heikki Krogerus , Dmitry Baryshkov , Abhishek Pandit-Subedi , Jameson Thies , Benson Leung , Tzung-Bi Shih Cc: Greg Kroah-Hartman , Guenter Roeck , Pooja Katiyar , Badhri Jagan Sridharan , RD Babiera , linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org, chrome-platform@lists.linux.dev, Andrei Kuchynski Subject: [PATCH 10/10] platform/chrome: cros_ec_typec: Report USB4 mode entry status via callback Date: Mon, 16 Jun 2025 13:31:47 +0000 Message-ID: <20250616133147.1835939-11-akuchynski@chromium.org> X-Mailer: git-send-email 2.50.0.rc1.591.g9c95f17f64-goog In-Reply-To: <20250616133147.1835939-1-akuchynski@chromium.org> References: <20250616133147.1835939-1-akuchynski@chromium.org> Precedence: bulk X-Mailing-List: linux-usb@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 The Type-C mode selection logic requires feedback on the result of USB4 mode entry attempt. Call the `typec_mode_selection_usb4_complete()` callback to provide this final success or failure status. Signed-off-by: Andrei Kuchynski --- 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 a4f338771094..c5a7f42ffb5a 100644 --- a/drivers/platform/chrome/cros_ec_typec.c +++ b/drivers/platform/chrome/cros_ec_typec.c @@ -698,6 +698,7 @@ static int cros_typec_configure_mux(struct cros_typec_data *typec, int port_num, if (port->mux_flags & USB_PD_MUX_USB4_ENABLED) { ret = cros_typec_enable_usb4(typec, port_num, pd_ctrl); + typec_mode_selection_usb4_complete(port->partner, ret); } else if (port->mux_flags & USB_PD_MUX_TBT_COMPAT_ENABLED) { ret = cros_typec_enable_tbt(typec, port_num, pd_ctrl); cros_typec_tbt_status_update(