From patchwork Mon Jan 8 19:16:14 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: RD Babiera X-Patchwork-Id: 762674 Received: from mail-yw1-f201.google.com (mail-yw1-f201.google.com [209.85.128.201]) (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 E081554FA3 for ; Mon, 8 Jan 2024 19:16:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--rdbabiera.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="JX5s4fAP" Received: by mail-yw1-f201.google.com with SMTP id 00721157ae682-5f38d676cecso35594787b3.0 for ; Mon, 08 Jan 2024 11:16:32 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1704741392; x=1705346192; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=/Wth/8UoV+aL5LC0kJi/DVxESpme0aBOkMeRoyQ8VPg=; b=JX5s4fAPwkuDPyS0kVqY5cblfmoiicWE7EptOaOfAeV18pajJIDRKziwuawvDCgbWJ Xu8Qh0B6zij3cTry78J5D+Qayr3XWL0MzdN5o8ED0v8KX4k4Y8blHkGpIfXxEc50CIZB YYzzC0XBR8JEw81mnaIPA4wDzWPCmtYhHrnD6CE1JV6DuM8q2ATQ4j3iY4PcSfKMqPws DY5g15CE7qUY8dyT0uCU/YUh98wssxcOWRJNJNgakyiwQPETEDv6Cvb5AWMpKFa3HaVB 0rW1s9DOdcp1gMV2Nh1cxSd5KpKb68ZPDqZPKD13RpDZ75Fqs/bnRDaTCk4Y8zfu0Nk+ jKfg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1704741392; x=1705346192; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=/Wth/8UoV+aL5LC0kJi/DVxESpme0aBOkMeRoyQ8VPg=; b=tMdINh60H+9PWn3Sj3s1UEtbbZtIIVmxx6LaElvN8UKFkHW89njzOCeaklg/oeoijX MeXei0lp8SOcblJXtm/1jympj6rt+Rw3xEx7GU/ZE6Y34GjQPUnDFSfZTtW/vROu+Otj JmNpi4fTGb1A4k4PLosjhTpDjDjRG5Zm1WI68RA+uXb7FI1Nlgu6ICwZxoyQMRpaMLIp AKpeAwBJsQYVtdbdjYdjnFcqMC1xbiURWgoS/ruT3GPxYvT8Zy/XUkx+KI/jRp5jMXnu amrT6g3I46Tv0pDkjfdqGAo2R1/ax8eEH5aR9bRq7HAMHalRaKA45ioAhq9j8HPFKqp1 uefA== X-Gm-Message-State: AOJu0YwuyGumoE/bX4DhwMZCrNxkUChGOeiAUXi2tMw4NPXTQ5b9Fw96 rlvlEY8m0quTDYOok4MhjgBvvNgHhbldGtWsP07nOQ== X-Google-Smtp-Source: AGHT+IFvaYMR/S/ZsUdsT9yfFqRaBpdsQUBK95oSocGAC52s8GXENtfDuoYYUqSRde+LO1erDZUAyGIxLwz6qQE= X-Received: from rdbabiera.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:18a8]) (user=rdbabiera job=sendgmr) by 2002:a81:c706:0:b0:5f9:32c7:cc51 with SMTP id m6-20020a81c706000000b005f932c7cc51mr75760ywi.0.1704741391912; Mon, 08 Jan 2024 11:16:31 -0800 (PST) Date: Mon, 8 Jan 2024 19:16:14 +0000 In-Reply-To: <20240108191620.987785-14-rdbabiera@google.com> Precedence: bulk X-Mailing-List: linux-usb@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20240108191620.987785-14-rdbabiera@google.com> X-Developer-Key: i=rdbabiera@google.com; a=openpgp; fpr=639A331F1A21D691815CE090416E17CA2BBBD5C8 X-Developer-Signature: v=1; a=openpgp-sha256; l=7965; i=rdbabiera@google.com; h=from:subject; bh=Y9LvmKwg8nyhTWBiDudZ8gZ35eWUccV05qkVwo8b+M0=; b=owGbwMvMwCFW0bfok0KS4TbG02pJDKlzvFgT/z57lck7+abNwa/fptx4uGjZ/2e+p+M+BMlzS /NPDI4711HKwiDGwSArpsii659ncONK6pY5nDXGMHNYmUCGMHBxCsBEJn5iZJi8Xafn1tHJNzSm x9YGffB28s7Jn+p2fer2jP9TXmnN/ZTN8E+DN3fm6y8hfdv7nmiI3rKfwGum9Mf1h+Bi13b7tzc LOvgB X-Mailer: git-send-email 2.43.0.472.g3155946c3a-goog Message-ID: <20240108191620.987785-15-rdbabiera@google.com> Subject: [PATCH v3 01/12] usb: typec: altmodes: add typec_cable_ops to typec_altmode From: RD Babiera To: rdbabiera@google.com, heikki.krogerus@linux.intel.com, linux@roeck-us.net, gregkh@linuxfoundation.org, linux-kernel@vger.kernel.org, linux-usb@vger.kernel.org Cc: badhri@google.com, bryan.odonoghue@linaro.org, agross@kernel.org, andersson@kernel.org, konrad.dybcio@linaro.org Add typec_cable_ops struct for enter, exit, and vdm. The struct is added to typec_altmode so port alt modes can have access to partner and cable specific callbacks, and alt mode drivers can specify operations over SOP' and SOP'' without modifying the existing API. typec_port_register_cable_ops is added as a new symbol for port drivers to use to register cable operations to their registered port alt modes. Signed-off-by: RD Babiera --- Changes since v2: * fixed documentation prototype errors --- drivers/usb/typec/bus.c | 102 ++++++++++++++++++++++++++++++ drivers/usb/typec/class.c | 19 ++++++ include/linux/usb/typec.h | 4 ++ include/linux/usb/typec_altmode.h | 20 ++++++ 4 files changed, 145 insertions(+) diff --git a/drivers/usb/typec/bus.c b/drivers/usb/typec/bus.c index e95ec7e382bb..6ea103e1abae 100644 --- a/drivers/usb/typec/bus.c +++ b/drivers/usb/typec/bus.c @@ -244,6 +244,108 @@ typec_altmode_get_partner(struct typec_altmode *adev) } EXPORT_SYMBOL_GPL(typec_altmode_get_partner); +/* -------------------------------------------------------------------------- */ +/* API for cable alternate modes */ + +/** + * typec_cable_altmode_enter - Enter Mode + * @adev: The alternate mode + * @sop: Cable plug target for Enter Mode command + * @vdo: VDO for the Enter Mode command + * + * Alternate mode drivers use this function to enter mode on the cable plug. + * If the alternate mode does not require VDO, @vdo must be NULL. + */ +int typec_cable_altmode_enter(struct typec_altmode *adev, enum typec_plug_index sop, u32 *vdo) +{ + struct altmode *partner = to_altmode(adev)->partner; + struct typec_altmode *pdev; + + if (!adev || adev->active) + return 0; + + if (!partner) + return -ENODEV; + + pdev = &partner->adev; + + if (!pdev->active) + return -EPERM; + + if (!pdev->cable_ops || !pdev->cable_ops->enter) + return -EOPNOTSUPP; + + return pdev->cable_ops->enter(pdev, sop, vdo); +} +EXPORT_SYMBOL_GPL(typec_cable_altmode_enter); + +/** + * typec_cable_altmode_exit - Exit Mode + * @adev: The alternate mode + * @sop: Cable plug target for Exit Mode command + * + * The alternate mode drivers use this function to exit mode on the cable plug. + */ +int typec_cable_altmode_exit(struct typec_altmode *adev, enum typec_plug_index sop) +{ + struct altmode *partner = to_altmode(adev)->partner; + struct typec_altmode *pdev; + + if (!adev || !adev->active) + return 0; + + if (!partner) + return -ENODEV; + + pdev = &partner->adev; + + if (!pdev->cable_ops || !pdev->cable_ops->exit) + return -EOPNOTSUPP; + + return pdev->cable_ops->exit(pdev, sop); +} +EXPORT_SYMBOL_GPL(typec_cable_altmode_exit); + +/** + * typec_cable_altmode_vdm - Send Vendor Defined Messages (VDM) between the cable plug and port. + * @adev: Alternate mode handle + * @sop: Cable plug target for VDM + * @header: VDM Header + * @vdo: Array of Vendor Defined Data Objects + * @count: Number of Data Objects + * + * The alternate mode drivers use this function for SVID specific communication + * with the cable plugs. The port drivers use it to deliver the Structured VDMs + * received from the cable plugs to the alternate mode drivers. + */ +int typec_cable_altmode_vdm(struct typec_altmode *adev, enum typec_plug_index sop, + const u32 header, const u32 *vdo, int count) +{ + struct altmode *altmode; + struct typec_altmode *pdev; + + if (!adev) + return 0; + + altmode = to_altmode(adev); + + if (is_typec_plug(adev->dev.parent)) { + if (!altmode->partner) + return -ENODEV; + pdev = &altmode->partner->adev; + } else { + if (!altmode->plug[sop]) + return -ENODEV; + pdev = &altmode->plug[sop]->adev; + } + + if (!pdev->cable_ops || !pdev->cable_ops->vdm) + return -EOPNOTSUPP; + + return pdev->cable_ops->vdm(pdev, sop, header, vdo, count); +} +EXPORT_SYMBOL_GPL(typec_cable_altmode_vdm); + /* -------------------------------------------------------------------------- */ /* API for the alternate mode drivers */ diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c index 015aa9253353..8fc9795d6bd4 100644 --- a/drivers/usb/typec/class.c +++ b/drivers/usb/typec/class.c @@ -2280,6 +2280,25 @@ void typec_port_register_altmodes(struct typec_port *port, } EXPORT_SYMBOL_GPL(typec_port_register_altmodes); +/** + * typec_port_register_cable_ops - Register typec_cable_ops to port altmodes + * @altmodes: USB Type-C Port's altmode vector + * @max_altmodes: The maximum number of alt modes supported by the port + * @ops: Cable alternate mode vector + */ +void typec_port_register_cable_ops(struct typec_altmode **altmodes, int max_altmodes, + const struct typec_cable_ops *ops) +{ + int i; + + for (i = 0; i < max_altmodes; i++) { + if (!altmodes[i]) + return; + altmodes[i]->cable_ops = ops; + } +} +EXPORT_SYMBOL_GPL(typec_port_register_cable_ops); + /** * typec_register_port - Register a USB Type-C Port * @parent: Parent device diff --git a/include/linux/usb/typec.h b/include/linux/usb/typec.h index a05d6f6f2536..38f93d72fd1b 100644 --- a/include/linux/usb/typec.h +++ b/include/linux/usb/typec.h @@ -18,6 +18,7 @@ struct typec_cable; struct typec_plug; struct typec_port; struct typec_altmode_ops; +struct typec_cable_ops; struct fwnode_handle; struct device; @@ -157,6 +158,9 @@ void typec_port_register_altmodes(struct typec_port *port, const struct typec_altmode_ops *ops, void *drvdata, struct typec_altmode **altmodes, size_t n); +void typec_port_register_cable_ops(struct typec_altmode **altmodes, int max_altmodes, + const struct typec_cable_ops *ops); + void typec_unregister_altmode(struct typec_altmode *altmode); struct typec_port *typec_altmode2port(struct typec_altmode *alt); diff --git a/include/linux/usb/typec_altmode.h b/include/linux/usb/typec_altmode.h index 28aeef8f9e7b..72ec8058543a 100644 --- a/include/linux/usb/typec_altmode.h +++ b/include/linux/usb/typec_altmode.h @@ -20,6 +20,7 @@ struct typec_altmode_ops; * @active: Tells has the mode been entered or not * @desc: Optional human readable description of the mode * @ops: Operations vector from the driver + * @cable_ops: Cable operations vector from the driver. */ struct typec_altmode { struct device dev; @@ -30,6 +31,7 @@ struct typec_altmode { char *desc; const struct typec_altmode_ops *ops; + const struct typec_cable_ops *cable_ops; }; #define to_typec_altmode(d) container_of(d, struct typec_altmode, dev) @@ -75,6 +77,24 @@ int typec_altmode_notify(struct typec_altmode *altmode, unsigned long conf, const struct typec_altmode * typec_altmode_get_partner(struct typec_altmode *altmode); +/** + * struct typec_cable_ops - Cable alternate mode operations vector + * @enter: Operations to be executed with Enter Mode Command + * @exit: Operations to be executed with Exit Mode Command + * @vdm: Callback for SVID specific commands + */ +struct typec_cable_ops { + int (*enter)(struct typec_altmode *altmode, enum typec_plug_index sop, u32 *vdo); + int (*exit)(struct typec_altmode *altmode, enum typec_plug_index sop); + int (*vdm)(struct typec_altmode *altmode, enum typec_plug_index sop, + const u32 hdr, const u32 *vdo, int cnt); +}; + +int typec_cable_altmode_enter(struct typec_altmode *altmode, enum typec_plug_index sop, u32 *vdo); +int typec_cable_altmode_exit(struct typec_altmode *altmode, enum typec_plug_index sop); +int typec_cable_altmode_vdm(struct typec_altmode *altmode, enum typec_plug_index sop, + const u32 header, const u32 *vdo, int count); + /* * These are the connector states (USB, Safe and Alt Mode) defined in USB Type-C * Specification. SVID specific connector states are expected to follow and From patchwork Mon Jan 8 19:16:16 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: RD Babiera X-Patchwork-Id: 762673 Received: from mail-pg1-f202.google.com (mail-pg1-f202.google.com [209.85.215.202]) (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 15F6154F9F for ; Mon, 8 Jan 2024 19:16:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--rdbabiera.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="gXjA9WZK" Received: by mail-pg1-f202.google.com with SMTP id 41be03b00d2f7-5ce098b08fdso481795a12.3 for ; Mon, 08 Jan 2024 11:16:35 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1704741395; x=1705346195; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=CVjThMZLotAdWb9TIioEoi19kF6hz6fkppa/3qq7zYI=; b=gXjA9WZKQE618v3eomvwmqVc0HmFl12Pr3USpMwXCUw2qFTAw1aG/M1PwDohAgy6dz RJAJgrVINOeor6NvkoIJ+eLElk+xFxcVbVeFV6K4mWcDxf0MKlm7i/OPIF1g2/1swrC1 k55CwwCkZYl3p9nzGAksScZueBMh2yDsOmnh2WLnNU8Mq2k42CzjGjDzvOylWzsnO+V7 jgkb/OzwQcLo6yIQykTsFV26nGQH6GUCJ8Tu48gT8ZeapQqtUIOohg758t3TMtjzJFAx I5o3wtuUXc7KDf8uNAkB3q+TbKqRuF5XVZjPhkxyOTLx1P6RUypKtsCuoUJ6b68wImNY g7Bw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1704741395; x=1705346195; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=CVjThMZLotAdWb9TIioEoi19kF6hz6fkppa/3qq7zYI=; b=mfqxq1RbOkDrnL9T8wj+Zkl8eAIJdk1F1RxlunbY41gY+i0K4vTHzWx0VexoLXU2Z8 YTIetXH5WML8eLLPD9X5FQnZXMFMPqHLGELHTkotoWUuVMwYKfBbVgqGKTk709M8UwJj OEbGZqn5LYfqX/btYYplqDhPO7aRECYZ0DbqIEKqmZTqakmuM/Ziw+MmwbxWcOQSyIwa ShT9squBPzRFo4XjnevS8tjh085N4FxahDSh0n5NBRvi9al0xMWG6yhzx89zSBdy7HKu JXuHRR5mSqQ2SuomnkyEladpxr+vZpU88x0Gu3u14lkCnbXpFbsfoQkK/bHiWNDMuU3x 1Z+A== X-Gm-Message-State: AOJu0Yx9npw9IoiOqmgt2fLVQm303Np4q/F1xd3ACJX6JObjm8VNgc4r KTrvIiZbuIr2OR+JSP/a62wH4C+33jpdqKbzRDQZoA== X-Google-Smtp-Source: AGHT+IGOIUXWhXCLu+tJx6ka3Fimz8laJsoLIhYNxmZmaI92SoS5S6nir2+WtKY/6bjERFB4yDlbwoqYrIqu5uk= X-Received: from rdbabiera.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:18a8]) (user=rdbabiera job=sendgmr) by 2002:a63:1c54:0:b0:5ca:43c7:a67 with SMTP id c20-20020a631c54000000b005ca43c70a67mr23049pgm.9.1704741395247; Mon, 08 Jan 2024 11:16:35 -0800 (PST) Date: Mon, 8 Jan 2024 19:16:16 +0000 In-Reply-To: <20240108191620.987785-14-rdbabiera@google.com> Precedence: bulk X-Mailing-List: linux-usb@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20240108191620.987785-14-rdbabiera@google.com> X-Developer-Key: i=rdbabiera@google.com; a=openpgp; fpr=639A331F1A21D691815CE090416E17CA2BBBD5C8 X-Developer-Signature: v=1; a=openpgp-sha256; l=4338; i=rdbabiera@google.com; h=from:subject; bh=putn0Ho6wv9tIgjQ9wNDNZ2hIDbeB2w3mtNH9bjlwx0=; b=owGbwMvMwCFW0bfok0KS4TbG02pJDKlzvFjfXD6++XiP0TlvxS1e0R8fJxR032DmMN/EyiVeJ NE7b25RRykLgxgHg6yYIouuf57BjSupW+Zw1hjDzGFlAhnCwMUpABNJaWP4X/Be13n6O/XbTmsP WjzKnD0ptO/hqs4N69V6G2vuPdaUucnIcG+e5DIhF8uQD/JnHk/aleHXf6eGLeO9jnp+rdmdx65 yfAA= X-Mailer: git-send-email 2.43.0.472.g3155946c3a-goog Message-ID: <20240108191620.987785-17-rdbabiera@google.com> Subject: [PATCH v3 03/12] usb: typec: tcpci: add cable_comm_capable attribute From: RD Babiera To: rdbabiera@google.com, heikki.krogerus@linux.intel.com, linux@roeck-us.net, gregkh@linuxfoundation.org, linux-kernel@vger.kernel.org, linux-usb@vger.kernel.org Cc: badhri@google.com, bryan.odonoghue@linaro.org, agross@kernel.org, andersson@kernel.org, konrad.dybcio@linaro.org Add cable_comm_capable to tcpci_data for tcpci drivers to indicate that the port tcpc is capable of communicating to cables over SOP. A corresponding tcpci callback tcpci_cable_comm_capable returns this value. The tcpm will primarily use this in later patches to determine if the port can transmit and receive SOP' messages. Maxim based tcpci drivers are capable of SOP' communication, so the cable_comm_capable flag is set to true. Signed-off-by: RD Babiera Reviewed-by: Heikki Krogerus --- Changes since v2: * Added reviewed-by tag Changes since v1: * Moved tcpm_pd_receive changes to separate patch --- drivers/usb/typec/tcpm/tcpci.c | 8 ++++++++ drivers/usb/typec/tcpm/tcpci_maxim_core.c | 1 + include/linux/usb/tcpci.h | 3 +++ include/linux/usb/tcpm.h | 4 ++++ 4 files changed, 16 insertions(+) diff --git a/drivers/usb/typec/tcpm/tcpci.c b/drivers/usb/typec/tcpm/tcpci.c index 0ee3e6e29bb1..1ededbcecc09 100644 --- a/drivers/usb/typec/tcpm/tcpci.c +++ b/drivers/usb/typec/tcpm/tcpci.c @@ -584,6 +584,13 @@ static int tcpci_pd_transmit(struct tcpc_dev *tcpc, enum tcpm_transmit_type type return 0; } +static bool tcpci_cable_comm_capable(struct tcpc_dev *tcpc) +{ + struct tcpci *tcpci = tcpc_to_tcpci(tcpc); + + return tcpci->data->cable_comm_capable; +} + static int tcpci_init(struct tcpc_dev *tcpc) { struct tcpci *tcpci = tcpc_to_tcpci(tcpc); @@ -793,6 +800,7 @@ struct tcpci *tcpci_register_port(struct device *dev, struct tcpci_data *data) tcpci->tcpc.enable_frs = tcpci_enable_frs; tcpci->tcpc.frs_sourcing_vbus = tcpci_frs_sourcing_vbus; tcpci->tcpc.set_partner_usb_comm_capable = tcpci_set_partner_usb_comm_capable; + tcpci->tcpc.cable_comm_capable = tcpci_cable_comm_capable; if (tcpci->data->check_contaminant) tcpci->tcpc.check_contaminant = tcpci_check_contaminant; diff --git a/drivers/usb/typec/tcpm/tcpci_maxim_core.c b/drivers/usb/typec/tcpm/tcpci_maxim_core.c index 7fb966fd639b..7b2d4e6e52a2 100644 --- a/drivers/usb/typec/tcpm/tcpci_maxim_core.c +++ b/drivers/usb/typec/tcpm/tcpci_maxim_core.c @@ -478,6 +478,7 @@ static int max_tcpci_probe(struct i2c_client *client) chip->data.vbus_vsafe0v = true; chip->data.set_partner_usb_comm_capable = max_tcpci_set_partner_usb_comm_capable; chip->data.check_contaminant = max_tcpci_check_contaminant; + chip->data.cable_comm_capable = true; max_tcpci_init_regs(chip); chip->tcpci = tcpci_register_port(chip->dev, &chip->data); diff --git a/include/linux/usb/tcpci.h b/include/linux/usb/tcpci.h index 467e8045e9f8..1d0b849defd0 100644 --- a/include/linux/usb/tcpci.h +++ b/include/linux/usb/tcpci.h @@ -198,12 +198,15 @@ struct tcpci; * Chip level drivers are expected to check for contaminant and call * tcpm_clean_port when the port is clean to put the port back into * toggling state. + * @cable_comm_capable + * optional; Set when TCPC can communicate with cable plugs over SOP' */ struct tcpci_data { struct regmap *regmap; unsigned char TX_BUF_BYTE_x_hidden:1; unsigned char auto_discharge_disconnect:1; unsigned char vbus_vsafe0v:1; + unsigned char cable_comm_capable:1; int (*init)(struct tcpci *tcpci, struct tcpci_data *data); int (*set_vconn)(struct tcpci *tcpci, struct tcpci_data *data, diff --git a/include/linux/usb/tcpm.h b/include/linux/usb/tcpm.h index 65fac5e1f317..430fa3ec69bb 100644 --- a/include/linux/usb/tcpm.h +++ b/include/linux/usb/tcpm.h @@ -119,6 +119,9 @@ enum tcpm_transmit_type { * at the end of the deboumce period or when the port is still * toggling. Chip level drivers are expected to check for contaminant * and call tcpm_clean_port when the port is clean. + * @cable_comm_capable + * Optional; Returns whether cable communication over SOP' is supported + * by the tcpc */ struct tcpc_dev { struct fwnode_handle *fwnode; @@ -154,6 +157,7 @@ struct tcpc_dev { bool (*is_vbus_vsafe0v)(struct tcpc_dev *dev); void (*set_partner_usb_comm_capable)(struct tcpc_dev *dev, bool enable); void (*check_contaminant)(struct tcpc_dev *dev); + bool (*cable_comm_capable)(struct tcpc_dev *dev); }; struct tcpm_port; From patchwork Mon Jan 8 19:16:18 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: RD Babiera X-Patchwork-Id: 762672 Received: from mail-yw1-f202.google.com (mail-yw1-f202.google.com [209.85.128.202]) (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 1520F55E55 for ; Mon, 8 Jan 2024 19:16:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--rdbabiera.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="ww5b5m/l" Received: by mail-yw1-f202.google.com with SMTP id 00721157ae682-5e8d2c6903dso34310707b3.0 for ; Mon, 08 Jan 2024 11:16:39 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1704741399; x=1705346199; darn=vger.kernel.org; h=content-transfer-encoding:cc:to:from:subject:message-id:references :mime-version:in-reply-to:date:from:to:cc:subject:date:message-id :reply-to; bh=Yz7g2JD7JGEEwsX3Nl/A/E3oQv0uIQXajJK5lnF37zU=; b=ww5b5m/l+Vp+j91KxwzIpqGciy50s4K8ajZCexvZp7yOK5aI/mpGoYaOuGV2ek/sMB dpY0kojONAiQVl3gak7YuYZ0WhXV4I2LvsG9yQ/b8BIre1aHLqQk8lPmJS68HZKMnRah aeHo+IqG0vEFirJZr3XJOWlfeyIg/Bo9P+468yR+fLYnyyKNo7ZMcyDpqP5jJr1xCYS1 hbfF1iIM2Rn++p4JmY6FbMInzxjciPvdgOM1sduLwm1SX1xMiApEvfe+IqH3+Ji8owAb v/wtwx3pOHtQCmygvkz+kJ531MGzTrWj2K/z0qdtlQ+NVRMdYyXEtOhTXaWYkDScBXwL fv/g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1704741399; x=1705346199; h=content-transfer-encoding:cc:to:from:subject:message-id:references :mime-version:in-reply-to:date:x-gm-message-state:from:to:cc:subject :date:message-id:reply-to; bh=Yz7g2JD7JGEEwsX3Nl/A/E3oQv0uIQXajJK5lnF37zU=; b=UuT81mkq01WeSf3c9I+uL+zot8iypRCkhu/2wq56JNUsABAdQiUvfkyzKv1njVRzK/ nCa04Tm3NMC8VXickuIOcmEDPa1NWYP57zKA6iFBjN5ekAVDdg5/c0up5SsA4SekLS3I 9NBzuBUgiwqbg0adnY1oYYZhJsppUUDtoLIisZ+QUrhfDfy2rTFH6hvx6Ym901qpwLxo NrTEs5P6851rmDARaMGeMIqoU+QcAjUGFSNFxEtNFk3l8yG2Ywe2hSwg4mRl3hbtFyUf qxME0oRUT9ayI4PUPccnx5rfh+ONC3UTf4dyE5UFV/bpMdDkBsLl7gjG1Ju35TotAEzN uYxQ== X-Gm-Message-State: AOJu0YwyORwDq+FNr605cW+55kRjlcu86z7BmYlQx3jX2AaiEz+MB0Kp voCYrfZErne3EgXoIoFv3Lop4vdj7LZIQ0sf3J6muw== X-Google-Smtp-Source: AGHT+IFU6L8B3qTY9i63U0pkMxN4GQIMF4BVWXVirYF5OsPW5HzBiGk4yjkmH91kj3+Twk4GsnmLvoIiqE1dMao= X-Received: from rdbabiera.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:18a8]) (user=rdbabiera job=sendgmr) by 2002:a05:6902:136d:b0:dbd:b756:983a with SMTP id bt13-20020a056902136d00b00dbdb756983amr1583830ybb.9.1704741399143; Mon, 08 Jan 2024 11:16:39 -0800 (PST) Date: Mon, 8 Jan 2024 19:16:18 +0000 In-Reply-To: <20240108191620.987785-14-rdbabiera@google.com> Precedence: bulk X-Mailing-List: linux-usb@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20240108191620.987785-14-rdbabiera@google.com> X-Developer-Key: i=rdbabiera@google.com; a=openpgp; fpr=639A331F1A21D691815CE090416E17CA2BBBD5C8 X-Developer-Signature: v=1; a=openpgp-sha256; l=9810; i=rdbabiera@google.com; h=from:subject; bh=aV7trIJOxc2GvxmatydTzZd0ZgpLTve7sQxZ+OQSU14=; b=owGbwMvMwCFW0bfok0KS4TbG02pJDKlzvNhYVs016TogFX3R6/zHiNQV715+cXeTM9eb2TCj8 N3+5jStjlIWBjEOBlkxRRZd/zyDG1dSt8zhrDGGmcPKBDKEgYtTACai/pnhf+WH5oenJnCJ3ply /WRY796QglLmv4xBs455Gt++/W1NviAjw7e7orsmrYyfMmPDrIeCgZNCX8fGWy/k3XiZ5/TuW7f bX/EBAA== X-Mailer: git-send-email 2.43.0.472.g3155946c3a-goog Message-ID: <20240108191620.987785-19-rdbabiera@google.com> Subject: [PATCH v3 05/12] usb: typec: tcpm: process receive and transmission of sop' messages From: RD Babiera To: rdbabiera@google.com, heikki.krogerus@linux.intel.com, linux@roeck-us.net, gregkh@linuxfoundation.org, linux-kernel@vger.kernel.org, linux-usb@vger.kernel.org Cc: badhri@google.com, bryan.odonoghue@linaro.org, agross@kernel.org, andersson@kernel.org, konrad.dybcio@linaro.org Add negotiated revision and tx/rx message ids to tcpm_port specific to SOP'. tx_sop_type is added to the tcpm_port to determine whether the current constructed message will be sent over SOP or SOP' if not sent immediately. tcpm_pd_rx_handler updates the received message ids. SOP* messages are not processed afterwards. The handler also calls tcpm_can_communicate_sop_prime to determine if a SOP' message is directed towards the port, and drops SOP' messages it should not respond to. tcpm_can_communicate_sop_prime is added as a helper to determine whether the port is capable of communicating over SOP' at a given moment. Being the Vconn source is a requirement in Power Delivery 3.0 but only a recommendation in Power Delviery 2.0. Because the port should ensure that the cable is powered before communication, always enforce the port is the Vconn source regardless of revision. Signed-off-by: RD Babiera Reviewed-by: Heikki Krogerus --- Changes since v2: * Fixed style errors, switch statements with TCPC_TX_SOP now combine with default case. --- drivers/usb/typec/tcpm/tcpm.c | 145 +++++++++++++++++++++++++++++++--- 1 file changed, 134 insertions(+), 11 deletions(-) diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c index ff0fcf560c88..d2ca85c8fec6 100644 --- a/drivers/usb/typec/tcpm/tcpm.c +++ b/drivers/usb/typec/tcpm/tcpm.c @@ -505,6 +505,35 @@ struct tcpm_port { * transitions. */ bool potential_contaminant; + + /* SOP* Related Fields */ + /* + * tx_sop_type determines which SOP* a message is being sent on. + * For messages that are queued and not sent immediately such as in + * tcpm_queue_message or messages that send after state changes, + * the tx_sop_type is set accordingly. + */ + enum tcpm_transmit_type tx_sop_type; + /* + * Prior to discovering the port partner's Specification Revision, the + * Vconn source and cable plug will use the lower of their two revisions. + * + * When the port partner's Specification Revision is discovered, the following + * rules are put in place. + * 1. If the cable revision (1) is lower than the revision negotiated + * between the port and partner (2), the port and partner will communicate + * on revision (2), but the port and cable will communicate on revision (1). + * 2. If the cable revision (1) is higher than the revision negotiated + * between the port and partner (2), the port and partner will communicate + * on revision (2), and the port and cable will communicate on revision (2) + * as well. + */ + unsigned int negotiated_rev_prime; + /* + * Each SOP* type must maintain their own tx and rx message IDs + */ + unsigned int message_id_prime; + unsigned int rx_msgid_prime; #ifdef CONFIG_DEBUG_FS struct dentry *dentry; struct mutex logbuffer_lock; /* log buffer access lock */ @@ -894,19 +923,30 @@ static void tcpm_ams_finish(struct tcpm_port *port) } static int tcpm_pd_transmit(struct tcpm_port *port, - enum tcpm_transmit_type type, + enum tcpm_transmit_type tx_sop_type, const struct pd_message *msg) { unsigned long timeout; int ret; + unsigned int negotiated_rev; + + switch (tx_sop_type) { + case TCPC_TX_SOP_PRIME: + negotiated_rev = port->negotiated_rev_prime; + break; + case TCPC_TX_SOP: + default: + negotiated_rev = port->negotiated_rev; + break; + } if (msg) tcpm_log(port, "PD TX, header: %#x", le16_to_cpu(msg->header)); else - tcpm_log(port, "PD TX, type: %#x", type); + tcpm_log(port, "PD TX, type: %#x", tx_sop_type); reinit_completion(&port->tx_complete); - ret = port->tcpc->pd_transmit(port->tcpc, type, msg, port->negotiated_rev); + ret = port->tcpc->pd_transmit(port->tcpc, tx_sop_type, msg, negotiated_rev); if (ret < 0) return ret; @@ -919,7 +959,17 @@ static int tcpm_pd_transmit(struct tcpm_port *port, switch (port->tx_status) { case TCPC_TX_SUCCESS: - port->message_id = (port->message_id + 1) & PD_HEADER_ID_MASK; + switch (tx_sop_type) { + case TCPC_TX_SOP_PRIME: + port->message_id_prime = (port->message_id_prime + 1) & + PD_HEADER_ID_MASK; + break; + case TCPC_TX_SOP: + default: + port->message_id = (port->message_id + 1) & + PD_HEADER_ID_MASK; + break; + } /* * USB PD rev 2.0, 8.3.2.2.1: * USB PD rev 3.0, 8.3.2.1.3: @@ -1604,6 +1654,57 @@ static void tcpm_register_partner_altmodes(struct tcpm_port *port) #define supports_modal(port) PD_IDH_MODAL_SUPP((port)->partner_ident.id_header) +/* + * Helper to determine whether the port is capable of SOP' communication at the + * current point in time. + */ +static bool tcpm_can_communicate_sop_prime(struct tcpm_port *port) +{ + /* Check to see if tcpc supports SOP' communication */ + if (!port->tcpc->cable_comm_capable || !port->tcpc->cable_comm_capable(port->tcpc)) + return false; + /* + * Power Delivery 2.0 Section 6.3.11 + * Before communicating with a Cable Plug a Port Should ensure that it + * is the Vconn Source and that the Cable Plugs are powered by + * performing a Vconn swap if necessary. Since it cannot be guaranteed + * that the present Vconn Source is supplying Vconn, the only means to + * ensure that the Cable Plugs are powered is for a Port wishing to + * communicate with a Cable Plug is to become the Vconn Source. + * + * Power Delivery 3.0 Section 6.3.11 + * Before communicating with a Cable Plug a Port Shall ensure that it + * is the Vconn source. + */ + if (port->vconn_role != TYPEC_SOURCE) + return false; + /* + * Power Delivery 2.0 Section 2.4.4 + * When no Contract or an Implicit Contract is in place the Source can + * communicate with a Cable Plug using SOP' packets in order to discover + * its characteristics. + * + * Power Delivery 3.0 Section 2.4.4 + * When no Contract or an Implicit Contract is in place only the Source + * port that is supplying Vconn is allowed to send packets to a Cable + * Plug and is allowed to respond to packets from the Cable Plug. + */ + if (!port->explicit_contract) + return port->pwr_role == TYPEC_SOURCE; + if (port->negotiated_rev == PD_REV30) + return true; + /* + * Power Delivery 2.0 Section 2.4.4 + * + * When an Explicit Contract is in place the DFP (either the Source or + * the Sink) can communicate with the Cable Plug(s) using SOP’/SOP” + * Packets (see Figure 2-3). + */ + if (port->negotiated_rev == PD_REV20) + return port->data_role == TYPEC_HOST; + return false; +} + static int tcpm_pd_svdm(struct tcpm_port *port, struct typec_altmode *adev, const u32 *p, int cnt, u32 *response, enum adev_actions *adev_action) @@ -2989,14 +3090,18 @@ static void tcpm_pd_rx_handler(struct kthread_work *work) tcpm_log(port, "PD RX, header: %#x [%d]", le16_to_cpu(msg->header), port->attached); - /* Ignore SOP' for now */ - if (rx_sop_type == TCPC_TX_SOP_PRIME) - goto done; - if (port->attached) { enum pd_ctrl_msg_type type = pd_header_type_le(msg->header); unsigned int msgid = pd_header_msgid_le(msg->header); + /* + * Drop SOP' messages if cannot receive via + * tcpm_can_communicate_sop_prime + */ + if (rx_sop_type == TCPC_TX_SOP_PRIME && + !tcpm_can_communicate_sop_prime(port)) + goto done; + /* * USB PD standard, 6.6.1.2: * "... if MessageID value in a received Message is the @@ -3006,16 +3111,27 @@ static void tcpm_pd_rx_handler(struct kthread_work *work) * Message). Note: this shall not apply to the Soft_Reset * Message which always has a MessageID value of zero." */ - if (msgid == port->rx_msgid && type != PD_CTRL_SOFT_RESET) + switch (rx_sop_type) { + case TCPC_TX_SOP_PRIME: + if (msgid == port->rx_msgid_prime) + goto done; + port->rx_msgid_prime = msgid; + /* Ignore SOP' for now */ goto done; - port->rx_msgid = msgid; + case TCPC_TX_SOP: + default: + if (msgid == port->rx_msgid && type != PD_CTRL_SOFT_RESET) + goto done; + port->rx_msgid = msgid; + break; + } /* * If both ends believe to be DFP/host, we have a data role * mismatch. */ if (!!(le16_to_cpu(msg->header) & PD_HEADER_DATA_ROLE) == - (port->data_role == TYPEC_HOST)) { + (port->data_role == TYPEC_HOST) && rx_sop_type == TCPC_TX_SOP) { tcpm_log(port, "Data role mismatch, initiating error recovery"); tcpm_set_state(port, ERROR_RECOVERY, 0); @@ -3720,6 +3836,7 @@ static void tcpm_reset_port(struct tcpm_port *port) * we can check tcpm_pd_rx_handler() if we had seen it before. */ port->rx_msgid = -1; + port->rx_msgid_prime = -1; port->tcpc->set_pd_rx(port->tcpc, false); tcpm_init_vbus(port); /* also disables charging */ @@ -4034,8 +4151,11 @@ static void run_state_machine(struct tcpm_port *port) port->pwr_opmode = TYPEC_PWR_MODE_USB; port->caps_count = 0; port->negotiated_rev = PD_MAX_REV; + port->negotiated_rev_prime = PD_MAX_REV; port->message_id = 0; + port->message_id_prime = 0; port->rx_msgid = -1; + port->rx_msgid_prime = -1; port->explicit_contract = false; /* SNK -> SRC POWER/FAST_ROLE_SWAP finished */ if (port->ams == POWER_ROLE_SWAP || @@ -4275,8 +4395,11 @@ static void run_state_machine(struct tcpm_port *port) typec_set_pwr_opmode(port->typec_port, opmode); port->pwr_opmode = TYPEC_PWR_MODE_USB; port->negotiated_rev = PD_MAX_REV; + port->negotiated_rev_prime = PD_MAX_REV; port->message_id = 0; + port->message_id_prime = 0; port->rx_msgid = -1; + port->rx_msgid_prime = -1; port->explicit_contract = false; if (port->ams == POWER_ROLE_SWAP || From patchwork Mon Jan 8 19:16:20 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: RD Babiera X-Patchwork-Id: 762671 Received: from mail-yw1-f201.google.com (mail-yw1-f201.google.com [209.85.128.201]) (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 5F34D54FAE for ; Mon, 8 Jan 2024 19:16:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--rdbabiera.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="gM5ZWCLY" Received: by mail-yw1-f201.google.com with SMTP id 00721157ae682-5f6f51cd7e8so24410367b3.1 for ; Mon, 08 Jan 2024 11:16:43 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1704741402; x=1705346202; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=5S3fHVY510eUierrKJ56dka07t+3wFOx1R5zr9DqTHs=; b=gM5ZWCLYuMfkMQYbndkZLn8rVK46csVp2ePV5PIC6OuaW4Yx3ZmdTIuWK0XfF2dsCD H192tx6YkuqJw2ps8xKCVuArT6iqoZ2gYyZJqzD4yE/njMOY9Pe+h9Dl+O0KPJjJVFTJ CoVTaQk0wAxvPSqyNIPBLXte5HM96R+x+0kj6vB/puYkjopuDdygCROfv3b9Xb/GUkQV cbztEgBHyGmrc5AZ8+DabUhDGgG8PJFVSUiqNTC6wFUvqpOq/dCmrKG7/wzIdxzDsoRv F3/jInxx4P39oZvtkXxmOcq30igMSbHIU5g+s5Eb843szFdDtJ7+Xs4EYGSd8JdN+6wD 71TA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1704741402; x=1705346202; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=5S3fHVY510eUierrKJ56dka07t+3wFOx1R5zr9DqTHs=; b=QX+zgXI/Y/Zq30TrsC3IxE4r95TDZrF8SdJIXXVPSKALJ0tp4e1rQ036/DBRiE/nv0 rwMgG946dHpjoca2/bP5lzIOA6rmnhktajiAG92WIkzJDp/6kpCRrgh4hfi7Cjk5WD64 HO+2tbMZQqMSUbSBWvspA2DfNyt4NQcBt0kbs8D6C0fPq+NAJFhJAjTncz/y5lXDBHuc dqC+gcKS9lzSH2fLRulHJk/vEW+ZwMvYjRoip12lJSS1NeHo/KBm3dlhNFa37NobABTv pBsrE3B0wrgHTeb8gQ0jFv36lQQCNTV98+TTArVe4p2eaexcmf+lcTfjR1bAHj70cuJ8 1JVQ== X-Gm-Message-State: AOJu0YwBM2Xad9X7xuQ8OtwTh6RHWnABOysNoJ6HTDH2H7/0Ly9anY/l FjJe499jei3NAo635uvDScADLhcBI5rEptJ9ADo+LQ== X-Google-Smtp-Source: AGHT+IEKvdJCYFexbfuslU/IaTufauj2WwZxLpXZXQ//zWcFGyVGulEp6m5CzYu6FWv/WkpisXIdwrAwlfkqKj4= X-Received: from rdbabiera.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:18a8]) (user=rdbabiera job=sendgmr) by 2002:a05:690c:309:b0:5e6:579e:65dd with SMTP id bg9-20020a05690c030900b005e6579e65ddmr1849203ywb.3.1704741402488; Mon, 08 Jan 2024 11:16:42 -0800 (PST) Date: Mon, 8 Jan 2024 19:16:20 +0000 In-Reply-To: <20240108191620.987785-14-rdbabiera@google.com> Precedence: bulk X-Mailing-List: linux-usb@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20240108191620.987785-14-rdbabiera@google.com> X-Developer-Key: i=rdbabiera@google.com; a=openpgp; fpr=639A331F1A21D691815CE090416E17CA2BBBD5C8 X-Developer-Signature: v=1; a=openpgp-sha256; l=6690; i=rdbabiera@google.com; h=from:subject; bh=vyvXaH6qWtx30SqHG/OIUPIttfFPXwU8n6ukoXI76xM=; b=owGbwMvMwCFW0bfok0KS4TbG02pJDKlzvNj5JWNamh/8XLvd4Gpy8sGUhXyXH1iFT6w8ONnxJ 2PTtE9/O0pZGMQ4GGTFFFl0/fMMblxJ3TKHs8YYZg4rE8gQBi5OAZhI8iOGP5zeOpknPH9ELnq+ SF3XM/6o2jOVG+83Oi47ETVPkfv93ChGhsn10vZTtetdE6aW2hif50+eMv3K7I8T2nfd3ZuzuiH 9Oh8A X-Mailer: git-send-email 2.43.0.472.g3155946c3a-goog Message-ID: <20240108191620.987785-21-rdbabiera@google.com> Subject: [PATCH v3 07/12] usb: typec: tcpci: add attempt_vconn_swap_discovery callback From: RD Babiera To: rdbabiera@google.com, heikki.krogerus@linux.intel.com, linux@roeck-us.net, gregkh@linuxfoundation.org, linux-kernel@vger.kernel.org, linux-usb@vger.kernel.org Cc: badhri@google.com, bryan.odonoghue@linaro.org, agross@kernel.org, andersson@kernel.org, konrad.dybcio@linaro.org Add attempt_vconn_swap_discovery callback to determine whether the TCPM should perform a Vconn swap following Discover Identity on SOP. The tcpci will return false unless chip level drivers implement the callback. Maxim based TCPCs will return true unless the last connection resulted in a Vconn Over Current Fault, which may be the result of the Vconn swap. In addition to the port resetting, the TCPCI will veto the next Vconn swap from occurring. Signed-off-by: RD Babiera Reviewed-by: Heikki Krogerus --- Changes since v2: * Added reviewed-by tag --- drivers/usb/typec/tcpm/tcpci.c | 11 +++++++++++ drivers/usb/typec/tcpm/tcpci_maxim.h | 1 + drivers/usb/typec/tcpm/tcpci_maxim_core.c | 17 ++++++++++++++++- include/linux/usb/tcpci.h | 9 +++++++++ include/linux/usb/tcpm.h | 9 +++++++++ 5 files changed, 46 insertions(+), 1 deletion(-) diff --git a/drivers/usb/typec/tcpm/tcpci.c b/drivers/usb/typec/tcpm/tcpci.c index 8ea4ed159a13..40c7b6224c74 100644 --- a/drivers/usb/typec/tcpm/tcpci.c +++ b/drivers/usb/typec/tcpm/tcpci.c @@ -594,6 +594,16 @@ static bool tcpci_cable_comm_capable(struct tcpc_dev *tcpc) return tcpci->data->cable_comm_capable; } +static bool tcpci_attempt_vconn_swap_discovery(struct tcpc_dev *tcpc) +{ + struct tcpci *tcpci = tcpc_to_tcpci(tcpc); + + if (tcpci->data->attempt_vconn_swap_discovery) + return tcpci->data->attempt_vconn_swap_discovery(tcpci, tcpci->data); + + return false; +} + static int tcpci_init(struct tcpc_dev *tcpc) { struct tcpci *tcpci = tcpc_to_tcpci(tcpc); @@ -804,6 +814,7 @@ struct tcpci *tcpci_register_port(struct device *dev, struct tcpci_data *data) tcpci->tcpc.frs_sourcing_vbus = tcpci_frs_sourcing_vbus; tcpci->tcpc.set_partner_usb_comm_capable = tcpci_set_partner_usb_comm_capable; tcpci->tcpc.cable_comm_capable = tcpci_cable_comm_capable; + tcpci->tcpc.attempt_vconn_swap_discovery = tcpci_attempt_vconn_swap_discovery; if (tcpci->data->check_contaminant) tcpci->tcpc.check_contaminant = tcpci_check_contaminant; diff --git a/drivers/usb/typec/tcpm/tcpci_maxim.h b/drivers/usb/typec/tcpm/tcpci_maxim.h index 2c1c4d161b0d..78ff3b73ee7e 100644 --- a/drivers/usb/typec/tcpm/tcpci_maxim.h +++ b/drivers/usb/typec/tcpm/tcpci_maxim.h @@ -62,6 +62,7 @@ struct max_tcpci_chip { struct i2c_client *client; struct tcpm_port *port; enum contamiant_state contaminant_state; + bool veto_vconn_swap; }; static inline int max_tcpci_read16(struct max_tcpci_chip *chip, unsigned int reg, u16 *val) diff --git a/drivers/usb/typec/tcpm/tcpci_maxim_core.c b/drivers/usb/typec/tcpm/tcpci_maxim_core.c index f9f838df43f7..eec3bcec119c 100644 --- a/drivers/usb/typec/tcpm/tcpci_maxim_core.c +++ b/drivers/usb/typec/tcpm/tcpci_maxim_core.c @@ -323,8 +323,10 @@ static irqreturn_t _max_tcpci_irq(struct max_tcpci_chip *chip, u16 status) if (ret < 0) return ret; - if (reg_status & TCPC_FAULT_STATUS_VCONN_OC) + if (reg_status & TCPC_FAULT_STATUS_VCONN_OC) { + chip->veto_vconn_swap = true; tcpm_port_error_recovery(chip->port); + } } if (status & TCPC_ALERT_EXTND) { @@ -458,6 +460,18 @@ static void max_tcpci_check_contaminant(struct tcpci *tcpci, struct tcpci_data * tcpm_port_clean(chip->port); } +static bool max_tcpci_attempt_vconn_swap_discovery(struct tcpci *tcpci, struct tcpci_data *tdata) +{ + struct max_tcpci_chip *chip = tdata_to_max_tcpci(tdata); + + if (chip->veto_vconn_swap) { + chip->veto_vconn_swap = false; + return false; + } + + return true; +} + static int max_tcpci_probe(struct i2c_client *client) { int ret; @@ -493,6 +507,7 @@ static int max_tcpci_probe(struct i2c_client *client) chip->data.set_partner_usb_comm_capable = max_tcpci_set_partner_usb_comm_capable; chip->data.check_contaminant = max_tcpci_check_contaminant; chip->data.cable_comm_capable = true; + chip->data.attempt_vconn_swap_discovery = max_tcpci_attempt_vconn_swap_discovery; max_tcpci_init_regs(chip); chip->tcpci = tcpci_register_port(chip->dev, &chip->data); diff --git a/include/linux/usb/tcpci.h b/include/linux/usb/tcpci.h index 9ed6d62c9c5f..47a86b8a4a50 100644 --- a/include/linux/usb/tcpci.h +++ b/include/linux/usb/tcpci.h @@ -201,6 +201,14 @@ struct tcpci; * toggling state. * @cable_comm_capable * optional; Set when TCPC can communicate with cable plugs over SOP' + * @attempt_vconn_swap_discovery: + * Optional; The callback is called by the TCPM when the result of + * a Discover Identity request indicates that the port partner is + * a receptacle capable of modal operation. Chip level TCPCI drivers + * can implement their own policy to determine if and when a Vconn + * swap following Discover Identity on SOP' occurs. + * Return true when the TCPM is allowed to request a Vconn swap + * after Discovery Identity on SOP. */ struct tcpci_data { struct regmap *regmap; @@ -219,6 +227,7 @@ struct tcpci_data { void (*set_partner_usb_comm_capable)(struct tcpci *tcpci, struct tcpci_data *data, bool capable); void (*check_contaminant)(struct tcpci *tcpci, struct tcpci_data *data); + bool (*attempt_vconn_swap_discovery)(struct tcpci *tcpci, struct tcpci_data *data); }; struct tcpci *tcpci_register_port(struct device *dev, struct tcpci_data *data); diff --git a/include/linux/usb/tcpm.h b/include/linux/usb/tcpm.h index 41d1ac9c8bbf..6671427f7eeb 100644 --- a/include/linux/usb/tcpm.h +++ b/include/linux/usb/tcpm.h @@ -122,6 +122,14 @@ enum tcpm_transmit_type { * @cable_comm_capable * Optional; Returns whether cable communication over SOP' is supported * by the tcpc + * @attempt_vconn_swap_discovery: + * Optional; The callback is called by the TCPM when the result of + * a Discover Identity request indicates that the port partner is + * a receptacle capable of modal operation. Chip level TCPCI drivers + * can implement their own policy to determine if and when a Vconn + * swap following Discover Identity on SOP' occurs. + * Return true when the TCPM is allowed to request a Vconn swap + * after Discovery Identity on SOP. */ struct tcpc_dev { struct fwnode_handle *fwnode; @@ -158,6 +166,7 @@ struct tcpc_dev { void (*set_partner_usb_comm_capable)(struct tcpc_dev *dev, bool enable); void (*check_contaminant)(struct tcpc_dev *dev); bool (*cable_comm_capable)(struct tcpc_dev *dev); + bool (*attempt_vconn_swap_discovery)(struct tcpc_dev *dev); }; struct tcpm_port; From patchwork Mon Jan 8 19:16:22 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: RD Babiera X-Patchwork-Id: 762670 Received: from mail-yb1-f202.google.com (mail-yb1-f202.google.com [209.85.219.202]) (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 0124E5675B for ; Mon, 8 Jan 2024 19:16:46 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--rdbabiera.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="lgYUeUr+" Received: by mail-yb1-f202.google.com with SMTP id 3f1490d57ef6-dbed375def6so2745613276.0 for ; Mon, 08 Jan 2024 11:16:46 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1704741406; x=1705346206; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=l1aAYuC2BqdlAhZMX9amHJf0C2KnJp96CrYM+8fPmRU=; b=lgYUeUr+jkoiQflV2zRlJme+d7boD0WhKoyX+1cUP/mNIdLPUnAUSOsVpG2i5/MWgr oVT5aq1NKyQ/TlOWhDAgnVJ3ifMgVJWULC9jiGXAGAf9EKjxAWJMsbi+zzYIHbHguNzY wDrKVJ9/SFy/ya5k9cwGaySoL3wt/cgvfJFRWQlF2nNpy87J/e0mJpNvfWFpPxkvNUDH VROVEbmC1S6VtC5rWXlSGi/aNd+CpySLB3coR57TPVx+ciHemAojbV3N17dDI5z0qIoJ FpWZdbDv3DRHdIaCzdXn3lKuSdtzVuunzmKRTNbwzTBN57RPnhlkdhnX+K8/7h8DZhlc NFJw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1704741406; x=1705346206; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=l1aAYuC2BqdlAhZMX9amHJf0C2KnJp96CrYM+8fPmRU=; b=XJ7xRmKT3SCDKGNnboNBFGyelsSCI+zJD1ffqkK7Hemu27gghaKcfxeS4JwBQ6OdLX AkhP+zaMU91DHg/4wBLh2jlDgczkI6AQtySCE2hPUOKFmSRHdcinrFq9eLb9ZwfvDgIU rtH5kWnzNNq68OiHFkG/oj2V1X6eKQNV1DQS0fC+4jOdgpOZooOow5UuPg66/w0BbqBU x/6rQiVYCdr6p3alPTpjbUCfYbR5S2Wci7AtMqnxso/IPjtS7F93/P5xACnT0UP2bhOH sk9JbCAchxKs8gg+ot76I7pZSmrybxctBVvZTYZ/c34VIIMloaexcnpTSNtybERCc7IW MVXQ== X-Gm-Message-State: AOJu0Yx07BfnWGlXRoUGGqyoAF5kfLCiR9q2aD28Sb+TGUuMQIJSIdWu NWnRq7dcdMNJSXbANt3pIJigc2F7H2ZWYZA/l2Pajw== X-Google-Smtp-Source: AGHT+IH1sORi4WDvSKneGalaBFqTuk9XLWv8umodlosZb82gjdjxP79P7uYA8f1pKM5SssOgD/7GaHFptikL9vE= X-Received: from rdbabiera.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:18a8]) (user=rdbabiera job=sendgmr) by 2002:a25:d616:0:b0:dbd:3ccf:31e4 with SMTP id n22-20020a25d616000000b00dbd3ccf31e4mr73844ybg.2.1704741406073; Mon, 08 Jan 2024 11:16:46 -0800 (PST) Date: Mon, 8 Jan 2024 19:16:22 +0000 In-Reply-To: <20240108191620.987785-14-rdbabiera@google.com> Precedence: bulk X-Mailing-List: linux-usb@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20240108191620.987785-14-rdbabiera@google.com> X-Developer-Key: i=rdbabiera@google.com; a=openpgp; fpr=639A331F1A21D691815CE090416E17CA2BBBD5C8 X-Developer-Signature: v=1; a=openpgp-sha256; l=4856; i=rdbabiera@google.com; h=from:subject; bh=uVQYc5B6QgFBFc2IJXXGnnh5LigcI8G8edyIRV6rpWM=; b=owGbwMvMwCFW0bfok0KS4TbG02pJDKlzvDi2pX/PPjKl+uBu+TOzYowm1jbe/jXb/cnnlz/vb srwnsS6vqOUhUGMg0FWTJFF1z/P4MaV1C1zOGuMYeawMoEMYeDiFICJrIhhZFh0yk6HKe5W+cEZ 04OyVBlD2W5oWc1++3mnz6TfGswR+j8Y/mdMi/K7tF3Zt+2javSvQpaoNsHy35yZLScfFpbJ/lx 4kwUA X-Mailer: git-send-email 2.43.0.472.g3155946c3a-goog Message-ID: <20240108191620.987785-23-rdbabiera@google.com> Subject: [PATCH v3 09/12] usb: typec: tcpm: add state machine support for SRC_VDM_IDENTITY_REQUEST From: RD Babiera To: rdbabiera@google.com, heikki.krogerus@linux.intel.com, linux@roeck-us.net, gregkh@linuxfoundation.org, linux-kernel@vger.kernel.org, linux-usb@vger.kernel.org Cc: badhri@google.com, bryan.odonoghue@linaro.org, agross@kernel.org, andersson@kernel.org, konrad.dybcio@linaro.org Add SRC_VDM_IDENTITY_REQUEST state which first enters after SRC_STARTUP. The state sends Discover Identity on SOP' and transitions to SRC_SEND_CAPABILITIES. SRC_SEND_CAPABILITIES will transition back into SRC_VDM_IDENTITY_REQUEST instead of retrying immediately. Signed-off-by: RD Babiera Reviewed-by: Heikki Krogerus --- Changes since v2: * Added reviewed-by tag --- drivers/usb/typec/tcpm/tcpm.c | 49 ++++++++++++++++++++++++++++++----- 1 file changed, 43 insertions(+), 6 deletions(-) diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c index a870fbc6bc35..1ce525c8f97c 100644 --- a/drivers/usb/typec/tcpm/tcpm.c +++ b/drivers/usb/typec/tcpm/tcpm.c @@ -146,7 +146,9 @@ S(PORT_RESET_WAIT_OFF), \ \ S(AMS_START), \ - S(CHUNK_NOT_SUPP) + S(CHUNK_NOT_SUPP), \ + \ + S(SRC_VDM_IDENTITY_REQUEST) #define FOREACH_AMS(S) \ S(NONE_AMS), \ @@ -1963,6 +1965,7 @@ static int tcpm_pd_svdm(struct tcpm_port *port, struct typec_altmode *adev, ret = tcpm_ams_start(port, VCONN_SWAP); if (!ret) return 0; + /* Cannot perform Vconn swap */ port->upcoming_state = INVALID_STATE; port->send_discover_prime = false; } @@ -1994,6 +1997,16 @@ static int tcpm_pd_svdm(struct tcpm_port *port, struct typec_altmode *adev, * the svdm_version for the cable moving forward. */ svdm_consume_identity_sop_prime(port, p, cnt); + + /* + * If received in SRC_VDM_IDENTITY_REQUEST, continue + * to SRC_SEND_CAPABILITIES + */ + if (port->state == SRC_VDM_IDENTITY_REQUEST) { + tcpm_set_state(port, SRC_SEND_CAPABILITIES, 0); + return 0; + } + *response_tx_sop_type = TCPC_TX_SOP; response[0] = VDO(USB_SID_PD, 1, typec_get_negotiated_svdm_version(typec), @@ -2288,7 +2301,8 @@ static void vdm_run_state_machine(struct tcpm_port *port) * if there's traffic or we're not in PDO ready state don't send * a VDM. */ - if (port->state != SRC_READY && port->state != SNK_READY) { + if (port->state != SRC_READY && port->state != SNK_READY && + port->state != SRC_VDM_IDENTITY_REQUEST) { port->vdm_sm_running = false; break; } @@ -2364,13 +2378,22 @@ static void vdm_run_state_machine(struct tcpm_port *port) tcpm_ams_finish(port); break; case VDM_STATE_ERR_SEND: + /* + * When sending Discover Identity to SOP' before establishing an + * explicit contract, do not retry. Instead, weave sending + * Source_Capabilities over SOP and Discover Identity over SOP'. + */ + if (port->state == SRC_VDM_IDENTITY_REQUEST) { + tcpm_ams_finish(port); + port->vdm_state = VDM_STATE_DONE; + tcpm_set_state(port, SRC_SEND_CAPABILITIES, 0); /* * A partner which does not support USB PD will not reply, * so this is not a fatal error. At the same time, some * devices may not return GoodCRC under some circumstances, * so we need to retry. */ - if (port->vdm_retries < 3) { + } else if (port->vdm_retries < 3) { tcpm_log(port, "VDM Tx error, retry"); port->vdm_retries++; port->vdm_state = VDM_STATE_READY; @@ -4478,8 +4501,12 @@ static void run_state_machine(struct tcpm_port *port) } ret = tcpm_pd_send_source_caps(port); if (ret < 0) { - tcpm_set_state(port, SRC_SEND_CAPABILITIES, - PD_T_SEND_SOURCE_CAP); + if (tcpm_can_communicate_sop_prime(port) && + IS_ERR_OR_NULL(port->cable)) + tcpm_set_state(port, SRC_VDM_IDENTITY_REQUEST, 0); + else + tcpm_set_state(port, SRC_SEND_CAPABILITIES, + PD_T_SEND_SOURCE_CAP); } else { /* * Per standard, we should clear the reset counter here. @@ -5395,6 +5422,15 @@ static void run_state_machine(struct tcpm_port *port) tcpm_pd_send_control(port, PD_CTRL_NOT_SUPP, TCPC_TX_SOP); tcpm_set_state(port, port->pwr_role == TYPEC_SOURCE ? SRC_READY : SNK_READY, 0); break; + + /* Cable states */ + case SRC_VDM_IDENTITY_REQUEST: + port->send_discover_prime = true; + port->tx_sop_type = TCPC_TX_SOP_PRIME; + mod_send_discover_delayed_work(port, 0); + port->upcoming_state = SRC_SEND_CAPABILITIES; + break; + default: WARN(1, "Unexpected port state %d\n", port->state); break; @@ -6120,7 +6156,8 @@ static void tcpm_send_discover_work(struct kthread_work *work) } /* Retry if the port is not idle */ - if ((port->state != SRC_READY && port->state != SNK_READY) || port->vdm_sm_running) { + if ((port->state != SRC_READY && port->state != SNK_READY && + port->state != SRC_VDM_IDENTITY_REQUEST) || port->vdm_sm_running) { mod_send_discover_delayed_work(port, SEND_DISCOVER_RETRY_MS); goto unlock; } From patchwork Mon Jan 8 19:16:24 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: RD Babiera X-Patchwork-Id: 762669 Received: from mail-yw1-f201.google.com (mail-yw1-f201.google.com [209.85.128.201]) (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 8889E56B74 for ; Mon, 8 Jan 2024 19:16:50 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--rdbabiera.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="O9X2Vt0J" Received: by mail-yw1-f201.google.com with SMTP id 00721157ae682-5f69158f32eso25689387b3.2 for ; Mon, 08 Jan 2024 11:16:50 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1704741409; x=1705346209; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=SrTURjyagiHJyBtcVShn21olo2si3J8rHveL7Fpwpm8=; b=O9X2Vt0JDanbJO9KxEqkTNqe3nnoTUwreYqjRxkQvYJCbLzQMa/G/F4uqLA5WF2vlz vWyB4G5/BHSXtZQceuvSY+7LOqRDcTf0JbjuRv5wHvDXNxehsE2N5iOsvmmnYivKj1G2 GSG2woo20boRRp/iD12mEfkb9DF7WN5pEhtZv3zWYtHFCXJKoNt1mDrUi8Y24ue+i6Yp 9ocEz06z+js2FNBha6lVeTkLJ/kEfC3ELKvPWh7jdVVgeiFkM2U4gm7ayv+XQ8ODjFr4 Il4RkwprMMweJboRnNISMcrwO68MSkJ2yQfCeveHRoD7bCtlffj51luLj40+OLGmloFY 7Fdw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1704741409; x=1705346209; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=SrTURjyagiHJyBtcVShn21olo2si3J8rHveL7Fpwpm8=; b=I2uD5Ho8bAbacQMePBJSkMgknP55OXOkB69C1mGcHiWihnFAQ1deZEPyaO6j+Fh3Iw fGlDF65SFvyhcEpD9sfevkSf4cIQPXQNSY0zvHouJWnQlHx01nAPMXXjXIful4uGzib8 T71QtIURZ/aPj0C6sdxDbTLXJ6VnQgdargLOPckcJufJs5LTnxhU8ik1raixfv3dLwe7 VSe0skuOthBcMUg9VRtURjGFxgXzv6DG+ueiSBgo3x279W9eSze22YSzPSUvvg6bsAkb G/eWGxR/VGdlretvGXhFH4deGh3KJTaR3O3Au0NefpwxIFN/aWCNle9woyvVdNJnaiVe YeTg== X-Gm-Message-State: AOJu0YxCQqOoHf/sJ5kifetlMVGte9N2n6suN88y/V0dCyvxG5IAYfNM d+ifRXYlLbjPC6t3judrHtqAWumDjzm5vZ//ct7hEw== X-Google-Smtp-Source: AGHT+IFTH/hcqBkRqm9hHg05HrQJoXe8OZ4OfLoiCTQeD4qJaCHmwXtxf52nDiOKgbveQlG3D5Eel+6qz5y6kZ4= X-Received: from rdbabiera.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:18a8]) (user=rdbabiera job=sendgmr) by 2002:a05:690c:316:b0:5e6:96cc:9f17 with SMTP id bg22-20020a05690c031600b005e696cc9f17mr1985952ywb.7.1704741409658; Mon, 08 Jan 2024 11:16:49 -0800 (PST) Date: Mon, 8 Jan 2024 19:16:24 +0000 In-Reply-To: <20240108191620.987785-14-rdbabiera@google.com> Precedence: bulk X-Mailing-List: linux-usb@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20240108191620.987785-14-rdbabiera@google.com> X-Developer-Key: i=rdbabiera@google.com; a=openpgp; fpr=639A331F1A21D691815CE090416E17CA2BBBD5C8 X-Developer-Signature: v=1; a=openpgp-sha256; l=7080; i=rdbabiera@google.com; h=from:subject; bh=zfLOD65UxztyY2+yQMPbZDKDeJGzKZyWqg0N75vilbE=; b=owGbwMvMwCFW0bfok0KS4TbG02pJDKlzvDhfR7Ewzl01J91JJaJPku1a8cctd1ZMeLG6Kn3zx 7Uym7PfdZSyMIhxMMiKKbLo+ucZ3LiSumUOZ40xzBxWJpAhDFycAjCRo8sY/kc0Ta0KFN1y84JP +ZNT+v/EL9cFRInaC5kHMj5z+BU2s5ORYWbmucNanrbvDZfkuV5nSpib5PP1belBmW8Jy08dPnC 0kQMA X-Mailer: git-send-email 2.43.0.472.g3155946c3a-goog Message-ID: <20240108191620.987785-25-rdbabiera@google.com> Subject: [PATCH v3 11/12] usb: typec: tcpm: add alt mode enter/exit/vdm support for sop' From: RD Babiera To: rdbabiera@google.com, heikki.krogerus@linux.intel.com, linux@roeck-us.net, gregkh@linuxfoundation.org, linux-kernel@vger.kernel.org, linux-usb@vger.kernel.org Cc: badhri@google.com, bryan.odonoghue@linaro.org, agross@kernel.org, andersson@kernel.org, konrad.dybcio@linaro.org Add tcpm_cable_ops for enter, exit, and vdm to the tcpm, which are registered after registering port alt modes through typec_port_register_cable_ops. Enter Mode on SOP' now sends Exit Mode upon failure to report to the driver. tcpm_queue_vdm_unlocked now takes sop type as input. Proper adev_actions in tcpm_pd_svdm are selected for SOP' messages. Signed-off-by: RD Babiera Reviewed-by: Heikki Krogerus --- drivers/usb/typec/tcpm/tcpm.c | 126 ++++++++++++++++++++++++++++------ 1 file changed, 106 insertions(+), 20 deletions(-) diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c index d16edf112858..86d9962961c2 100644 --- a/drivers/usb/typec/tcpm/tcpm.c +++ b/drivers/usb/typec/tcpm/tcpm.c @@ -1556,7 +1556,7 @@ static void tcpm_queue_vdm(struct tcpm_port *port, const u32 header, } static void tcpm_queue_vdm_unlocked(struct tcpm_port *port, const u32 header, - const u32 *data, int cnt) + const u32 *data, int cnt, enum tcpm_transmit_type tx_sop_type) { mutex_lock(&port->lock); tcpm_queue_vdm(port, header, data, cnt, TCPC_TX_SOP); @@ -2144,14 +2144,28 @@ static int tcpm_pd_svdm(struct tcpm_port *port, struct typec_altmode *adev, } break; case CMD_ENTER_MODE: - if (adev && pdev) - *adev_action = ADEV_QUEUE_VDM_SEND_EXIT_MODE_ON_FAIL; + *response_tx_sop_type = rx_sop_type; + if (rx_sop_type == TCPC_TX_SOP) { + if (adev && pdev) { + typec_altmode_update_active(pdev, true); + *adev_action = ADEV_QUEUE_VDM_SEND_EXIT_MODE_ON_FAIL; + } + } else if (rx_sop_type == TCPC_TX_SOP_PRIME) { + if (adev && pdev_prime) { + typec_altmode_update_active(pdev_prime, true); + *adev_action = ADEV_QUEUE_VDM_SEND_EXIT_MODE_ON_FAIL; + } + } return 0; case CMD_EXIT_MODE: - if (adev && pdev) { - /* Back to USB Operation */ - *adev_action = ADEV_NOTIFY_USB_AND_QUEUE_VDM; - return 0; + *response_tx_sop_type = rx_sop_type; + if (rx_sop_type == TCPC_TX_SOP) { + if (adev && pdev) { + typec_altmode_update_active(pdev, false); + /* Back to USB Operation */ + *adev_action = ADEV_NOTIFY_USB_AND_QUEUE_VDM; + return 0; + } } break; case VDO_CMD_VENDOR(0) ... VDO_CMD_VENDOR(15): @@ -2284,19 +2298,37 @@ static void tcpm_handle_vdm_request(struct tcpm_port *port, typec_altmode_vdm(adev, p[0], &p[1], cnt); break; case ADEV_QUEUE_VDM: - typec_altmode_vdm(adev, p[0], &p[1], cnt); + if (response_tx_sop_type == TCPC_TX_SOP_PRIME) + typec_cable_altmode_vdm(adev, TYPEC_PLUG_SOP_P, p[0], &p[1], cnt); + else + typec_altmode_vdm(adev, p[0], &p[1], cnt); break; case ADEV_QUEUE_VDM_SEND_EXIT_MODE_ON_FAIL: - if (typec_altmode_vdm(adev, p[0], &p[1], cnt)) { - int svdm_version = typec_get_negotiated_svdm_version( - port->typec_port); - if (svdm_version < 0) - break; + if (response_tx_sop_type == TCPC_TX_SOP_PRIME) { + if (typec_cable_altmode_vdm(adev, TYPEC_PLUG_SOP_P, + p[0], &p[1], cnt)) { + int svdm_version = typec_get_cable_svdm_version( + port->typec_port); + if (svdm_version < 0) + break; - response[0] = VDO(adev->svid, 1, svdm_version, - CMD_EXIT_MODE); - response[0] |= VDO_OPOS(adev->mode); - rlen = 1; + response[0] = VDO(adev->svid, 1, svdm_version, + CMD_EXIT_MODE); + response[0] |= VDO_OPOS(adev->mode); + rlen = 1; + } + } else { + if (typec_altmode_vdm(adev, p[0], &p[1], cnt)) { + int svdm_version = typec_get_negotiated_svdm_version( + port->typec_port); + if (svdm_version < 0) + break; + + response[0] = VDO(adev->svid, 1, svdm_version, + CMD_EXIT_MODE); + response[0] |= VDO_OPOS(adev->mode); + rlen = 1; + } } break; case ADEV_ATTENTION: @@ -2731,7 +2763,7 @@ static int tcpm_altmode_enter(struct typec_altmode *altmode, u32 *vdo) header = VDO(altmode->svid, vdo ? 2 : 1, svdm_version, CMD_ENTER_MODE); header |= VDO_OPOS(altmode->mode); - tcpm_queue_vdm_unlocked(port, header, vdo, vdo ? 1 : 0); + tcpm_queue_vdm_unlocked(port, header, vdo, vdo ? 1 : 0, TCPC_TX_SOP); return 0; } @@ -2748,7 +2780,7 @@ static int tcpm_altmode_exit(struct typec_altmode *altmode) header = VDO(altmode->svid, 1, svdm_version, CMD_EXIT_MODE); header |= VDO_OPOS(altmode->mode); - tcpm_queue_vdm_unlocked(port, header, NULL, 0); + tcpm_queue_vdm_unlocked(port, header, NULL, 0, TCPC_TX_SOP); return 0; } @@ -2757,7 +2789,7 @@ static int tcpm_altmode_vdm(struct typec_altmode *altmode, { struct tcpm_port *port = typec_altmode_get_drvdata(altmode); - tcpm_queue_vdm_unlocked(port, header, data, count - 1); + tcpm_queue_vdm_unlocked(port, header, data, count - 1, TCPC_TX_SOP); return 0; } @@ -2768,6 +2800,58 @@ static const struct typec_altmode_ops tcpm_altmode_ops = { .vdm = tcpm_altmode_vdm, }; + +static int tcpm_cable_altmode_enter(struct typec_altmode *altmode, enum typec_plug_index sop, + u32 *vdo) +{ + struct tcpm_port *port = typec_altmode_get_drvdata(altmode); + int svdm_version; + u32 header; + + svdm_version = typec_get_cable_svdm_version(port->typec_port); + if (svdm_version < 0) + return svdm_version; + + header = VDO(altmode->svid, vdo ? 2 : 1, svdm_version, CMD_ENTER_MODE); + header |= VDO_OPOS(altmode->mode); + + tcpm_queue_vdm_unlocked(port, header, vdo, vdo ? 1 : 0, TCPC_TX_SOP_PRIME); + return 0; +} + +static int tcpm_cable_altmode_exit(struct typec_altmode *altmode, enum typec_plug_index sop) +{ + struct tcpm_port *port = typec_altmode_get_drvdata(altmode); + int svdm_version; + u32 header; + + svdm_version = typec_get_cable_svdm_version(port->typec_port); + if (svdm_version < 0) + return svdm_version; + + header = VDO(altmode->svid, 1, svdm_version, CMD_EXIT_MODE); + header |= VDO_OPOS(altmode->mode); + + tcpm_queue_vdm_unlocked(port, header, NULL, 0, TCPC_TX_SOP_PRIME); + return 0; +} + +static int tcpm_cable_altmode_vdm(struct typec_altmode *altmode, enum typec_plug_index sop, + u32 header, const u32 *data, int count) +{ + struct tcpm_port *port = typec_altmode_get_drvdata(altmode); + + tcpm_queue_vdm_unlocked(port, header, data, count - 1, TCPC_TX_SOP_PRIME); + + return 0; +} + +static const struct typec_cable_ops tcpm_cable_ops = { + .enter = tcpm_cable_altmode_enter, + .exit = tcpm_cable_altmode_exit, + .vdm = tcpm_cable_altmode_vdm, +}; + /* * PD (data, control) command handling functions */ @@ -7507,6 +7591,8 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc) typec_port_register_altmodes(port->typec_port, &tcpm_altmode_ops, port, port->port_altmode, ALTMODE_DISCOVERY_MAX); + typec_port_register_cable_ops(port->port_altmode, ARRAY_SIZE(port->port_altmode), + &tcpm_cable_ops); port->registered = true; mutex_lock(&port->lock);