]> www.infradead.org Git - users/hch/misc.git/commitdiff
usb: typec: tcpm: Add new AMS for Get_Revision response
authorAmit Sunil Dhamne <amitsd@google.com>
Wed, 11 Dec 2024 03:07:09 +0000 (19:07 -0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 24 Dec 2024 07:56:04 +0000 (08:56 +0100)
This commit adds a new AMS for responding to a "Get_Revision" request.
Revision message consists of the following fields:

 +----------------------------------------------------+
 |         Header             |         RMDO          |
 |  No. of data objects = 1   |                       |
 +----------------------------------------------------+

 While RMDO consists of:
  * B31..28     Revision Major
  * B27..24     Revision Minor
  * B23..20     Version Major
  * B19..16     Version Minor
  * B15..0      Reserved, shall be set to zero.

As per the PD spec ("8.3.3.16.2.1 PR_Give_Revision State"), a request is
only expected when an explicit contract is established and the port is
in ready state. This AMS is only supported for PD >= 3.0.

Signed-off-by: Amit Sunil Dhamne <amitsd@google.com>
Reviewed-by: Badhri Jagan Sridharan <badhri@google.com>
Link: https://lore.kernel.org/r/20241210-get_rev_upstream-v2-3-d0094e52d48f@google.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/typec/tcpm/tcpm.c
include/linux/usb/pd.h

index 59621cfaee3d67a36f3ad6870bd1aa92d382f33a..460dbde9fe2239b10c43cfb12dce92c736b1cea9 100644 (file)
        S(UNSTRUCTURED_VDMS),                   \
        S(STRUCTURED_VDMS),                     \
        S(COUNTRY_INFO),                        \
-       S(COUNTRY_CODES)
+       S(COUNTRY_CODES),                       \
+       S(REVISION_INFORMATION)
 
 #define GENERATE_ENUM(e)       e
 #define GENERATE_STRING(s)     #s
@@ -225,6 +226,7 @@ enum pd_msg_request {
        PD_MSG_CTRL_NOT_SUPP,
        PD_MSG_DATA_SINK_CAP,
        PD_MSG_DATA_SOURCE_CAP,
+       PD_MSG_DATA_REV,
 };
 
 enum adev_actions {
@@ -1244,6 +1246,24 @@ static u32 tcpm_forge_legacy_pdo(struct tcpm_port *port, u32 pdo, enum typec_rol
        }
 }
 
+static int tcpm_pd_send_revision(struct tcpm_port *port)
+{
+       struct pd_message msg;
+       u32 rmdo;
+
+       memset(&msg, 0, sizeof(msg));
+       rmdo = RMDO(port->pd_rev.rev_major, port->pd_rev.rev_minor,
+                   port->pd_rev.ver_major, port->pd_rev.ver_minor);
+       msg.payload[0] = cpu_to_le32(rmdo);
+       msg.header = PD_HEADER_LE(PD_DATA_REVISION,
+                                 port->pwr_role,
+                                 port->data_role,
+                                 port->negotiated_rev,
+                                 port->message_id,
+                                 1);
+       return tcpm_pd_transmit(port, TCPC_TX_SOP, &msg);
+}
+
 static int tcpm_pd_send_source_caps(struct tcpm_port *port)
 {
        struct pd_message msg;
@@ -3547,6 +3567,17 @@ static void tcpm_pd_ctrl_request(struct tcpm_port *port,
                                   PD_MSG_CTRL_NOT_SUPP,
                                   NONE_AMS);
                break;
+       case PD_CTRL_GET_REVISION:
+               if (port->negotiated_rev >= PD_REV30 && port->pd_rev.rev_major)
+                       tcpm_pd_handle_msg(port, PD_MSG_DATA_REV,
+                                          REVISION_INFORMATION);
+               else
+                       tcpm_pd_handle_msg(port,
+                                          port->negotiated_rev < PD_REV30 ?
+                                          PD_MSG_CTRL_REJECT :
+                                          PD_MSG_CTRL_NOT_SUPP,
+                                          NONE_AMS);
+               break;
        default:
                tcpm_pd_handle_msg(port,
                                   port->negotiated_rev < PD_REV30 ?
@@ -3791,6 +3822,14 @@ static bool tcpm_send_queued_message(struct tcpm_port *port)
                                tcpm_ams_finish(port);
                        }
                        break;
+               case PD_MSG_DATA_REV:
+                       ret = tcpm_pd_send_revision(port);
+                       if (ret)
+                               tcpm_log(port,
+                                        "Unable to send revision msg, ret=%d",
+                                        ret);
+                       tcpm_ams_finish(port);
+                       break;
                default:
                        break;
                }
index d50098fb16b5d2e2d9e39c55db4329224115e8b1..3068c3084eb6176d7d9184c3959a4110282a9fa0 100644 (file)
@@ -33,7 +33,9 @@ enum pd_ctrl_msg_type {
        PD_CTRL_FR_SWAP = 19,
        PD_CTRL_GET_PPS_STATUS = 20,
        PD_CTRL_GET_COUNTRY_CODES = 21,
-       /* 22-31 Reserved */
+       /* 22-23 Reserved */
+       PD_CTRL_GET_REVISION = 24,
+       /* 25-31 Reserved */
 };
 
 enum pd_data_msg_type {
@@ -46,7 +48,9 @@ enum pd_data_msg_type {
        PD_DATA_ALERT = 6,
        PD_DATA_GET_COUNTRY_INFO = 7,
        PD_DATA_ENTER_USB = 8,
-       /* 9-14 Reserved */
+       /* 9-11 Reserved */
+       PD_DATA_REVISION = 12,
+       /* 13-14 Reserved */
        PD_DATA_VENDOR_DEF = 15,
        /* 16-31 Reserved */
 };
@@ -453,6 +457,20 @@ static inline unsigned int rdo_max_power(u32 rdo)
 #define EUDO_TBT_SUPPORT               BIT(14)
 #define EUDO_HOST_PRESENT              BIT(13)
 
+/*
+ * Request Message Data Object (PD Revision 3.1+ only)
+ * --------
+ * <31:28> :: Revision Major
+ * <27:24> :: Revision Minor
+ * <23:20> :: Version Major
+ * <19:16> :: Version Minor
+ * <15:0>  :: Reserved, Shall be set to zero
+ */
+
+#define RMDO(rev_maj, rev_min, ver_maj, ver_min)                       \
+       (((rev_maj) & 0xf) << 28 | ((rev_min) & 0xf) << 24 |            \
+        ((ver_maj) & 0xf) << 20 | ((ver_min) & 0xf) << 16)
+
 /* USB PD timers and counters */
 #define PD_T_NO_RESPONSE       5000    /* 4.5 - 5.5 seconds */
 #define PD_T_DB_DETECT         10000   /* 10 - 15 seconds */