From patchwork Wed Nov 1 17:03:15 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adam Thomson X-Patchwork-Id: 10036789 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 035306032D for ; Wed, 1 Nov 2017 17:04:06 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E0EA22832B for ; Wed, 1 Nov 2017 17:04:05 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id D5D6828686; Wed, 1 Nov 2017 17:04:05 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,FROM_WORDY, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 432282832B for ; Wed, 1 Nov 2017 17:04:05 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932989AbdKARED (ORCPT ); Wed, 1 Nov 2017 13:04:03 -0400 Received: from mail1.bemta3.messagelabs.com ([195.245.230.176]:50938 "EHLO mail1.bemta3.messagelabs.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755107AbdKARDV (ORCPT ); Wed, 1 Nov 2017 13:03:21 -0400 Received: from [85.158.137.19] by server-16.bemta-3.messagelabs.com id 37/D0-05089-55EF9F95; Wed, 01 Nov 2017 17:03:17 +0000 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFupkleJIrShJLcpLzFFi42KJ27nUWDf0389 Ig9v/xS2aF69ns3hzfDqTRdfqnSwWl3fNYbP43HuE0WLRslZmiycLzzBZNC54z2JxeneJxZ/n t9gcuDx2zrrL7rFpVSebx7yTgR77565h93i/7yqbx87vDewenzfJBbBHsWbmJeVXJLBmdL3uY ixosKro3fmSqYHxmUEXIxeHkMA6Romnb18ydjFyAjkVEivm/wGzeQUyJTbNnckMYnMKuEs8Of wXqsZNYu+RXjCbTcBCYvKJB2wgNouAisSGA/9ZQWxhAX+Jhut32EAWiAjMY5J4teEuWBGzQJ1 E7++3LBALBCVOznzCAhGXkDj44gUzxAIDidMLGsHiEgL2EtPfXwWKcwDZ+hKNx2IhwoYS32d9 gyoxl2jfuI95AqPgLCRTZyGZuoCRaRWjenFqUVlqka65XlJRZnpGSW5iZo6uoYGxXm5qcXFie mpOYlKxXnJ+7iZGYLQwAMEOxsbvTocYJTmYlER5Ne//jBTiS8pPqcxILM6ILyrNSS0+xCjDwa EkwXvoL1BOsCg1PbUiLTMHGLcwaQkOHiUR3jUgad7igsTc4sx0iNQpRl2OZzNfNzALseTl56V KifPuASkSACnKKM2DGwFLIZcYZaWEeRmBjhLiKUgtys0sQZV/xSjOwagkzHsAZApPZl4J3KZX QEcwAR3hJfED5IiSRISUVAOjS//+F191hHOq6m4U/MqJlugtaXV8/M/eNSh8sxHftr+uL5m+T dn2+0jDCq0Z0yeXTJm5XUlS7GLQjN0GAlmCh/cVP9g+xUg4TNxBLj3qi+ZWK96gbRryjtotrz eV+M+4vVpsj1LZkQ+lElMYvVfF+QtHuDX4TX5Yc/TQleZzXYJF81VZDigrsRRnJBpqMRcVJwI AlWoUkhwDAAA= X-Env-Sender: Adam.Thomson.Opensource@diasemi.com X-Msg-Ref: server-15.tower-39.messagelabs.com!1509555796!55314425!1 X-Originating-IP: [94.185.165.51] X-StarScan-Received: X-StarScan-Version: 9.4.45; banners=-,-,- X-VirusChecked: Checked Received: (qmail 2095 invoked from network); 1 Nov 2017 17:03:17 -0000 Received: from mailrelay2.diasemi.com (HELO sw-ex-cashub01.diasemi.com) (94.185.165.51) by server-15.tower-39.messagelabs.com with AES128-SHA encrypted SMTP; 1 Nov 2017 17:03:17 -0000 Received: from swsrvapps-01.diasemi.com (10.20.28.141) by SW-EX-CASHUB01.diasemi.com (10.20.16.140) with Microsoft SMTP Server id 14.3.248.2; Wed, 1 Nov 2017 17:03:15 +0000 Received: by swsrvapps-01.diasemi.com (Postfix, from userid 22379) id 9A09C3FBE4; Wed, 1 Nov 2017 17:03:15 +0000 (GMT) Message-ID: <2df84d61cf0f475d7208b60ce2034a164e1569c1.1509554370.git.Adam.Thomson.Opensource@diasemi.com> In-Reply-To: References: From: Adam Thomson Date: Wed, 1 Nov 2017 17:03:15 +0000 Subject: [RFC PATCH 7/7] typec: tcpm: Add support for sink PPS related messages To: Heikki Krogerus , Guenter Roeck , Greg Kroah-Hartman , Sebastian Reichel , Hans de Goede , Yueyao Zhu , Rui Miguel Silva CC: , , , MIME-Version: 1.0 X-KSE-AttachmentFiltering-Interceptor-Info: protection disabled X-KSE-ServerInfo: sw-ex-cashub01.diasemi.com, 9 X-KSE-Antivirus-Interceptor-Info: scan successful X-KSE-Antivirus-Info: Clean, bases: 01/11/2017 12:45:00 Sender: linux-pm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This commit adds sink side support for Get_Status, Status, Get_PPS_Status and PPS_Status handling. As there's the potential for a partner to respond with Not_Supported handling of this message is also added. Sending of Not_Supported is added is added to handle messages received but not yet handled. Signed-off-by: Adam Thomson --- drivers/usb/typec/tcpm.c | 152 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 143 insertions(+), 9 deletions(-) diff --git a/drivers/usb/typec/tcpm.c b/drivers/usb/typec/tcpm.c index bf3c93a..d12304e 100644 --- a/drivers/usb/typec/tcpm.c +++ b/drivers/usb/typec/tcpm.c @@ -28,7 +28,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -122,6 +124,11 @@ S(SNK_TRYWAIT_VBUS), \ S(BIST_RX), \ \ + S(GET_STATUS_SEND), \ + S(GET_STATUS_SEND_TIMEOUT), \ + S(GET_PPS_STATUS_SEND), \ + S(GET_PPS_STATUS_SEND_TIMEOUT), \ + \ S(ERROR_RECOVERY), \ S(PORT_RESET), \ S(PORT_RESET_WAIT_OFF) @@ -152,6 +159,7 @@ enum pd_msg_request { PD_MSG_NONE = 0, PD_MSG_CTRL_REJECT, PD_MSG_CTRL_WAIT, + PD_MSG_CTRL_NOT_SUPP, PD_MSG_DATA_SINK_CAP, PD_MSG_DATA_SOURCE_CAP, }; @@ -1288,10 +1296,42 @@ static void vdm_state_machine_work(struct work_struct *work) /* * PD (data, control) command handling functions */ +static inline enum tcpm_state ready_state(struct tcpm_port *port) +{ + if (port->pwr_role == TYPEC_SOURCE) + return SRC_READY; + else + return SNK_READY; +} static int tcpm_pd_send_control(struct tcpm_port *port, enum pd_ctrl_msg_type type); +static void tcpm_handle_alert(struct tcpm_port *port, const __le32 *payload, + int cnt) +{ + u32 p0 = le32_to_cpu(payload[0]); + unsigned int type = ado_type(p0); + + if (!type) { + tcpm_log(port, "Alert message received with no type"); + return; + } + + /* Just handling non-battery alerts for now */ + if (!(type & ADO_TYPE_BATT_STATUS_CHANGE)) { + switch (port->state) { + case SRC_READY: + case SNK_READY: + tcpm_set_state(port, GET_STATUS_SEND, 0); + break; + default: + tcpm_queue_message(port, PD_MSG_CTRL_WAIT); + break; + } + } +} + static void tcpm_pd_data_request(struct tcpm_port *port, const struct pd_message *msg) { @@ -1350,6 +1390,14 @@ static void tcpm_pd_data_request(struct tcpm_port *port, tcpm_set_state(port, BIST_RX, 0); } break; + case PD_DATA_ALERT: + tcpm_handle_alert(port, msg->payload, cnt); + break; + case PD_DATA_BATT_STATUS: + case PD_DATA_GET_COUNTRY_INFO: + tcpm_queue_message(port, PD_MSG_CTRL_NOT_SUPP); + /* Currently unsupported */ + break; default: tcpm_log(port, "Unhandled data message type %#x", type); break; @@ -1432,6 +1480,7 @@ static void tcpm_pd_ctrl_request(struct tcpm_port *port, break; case PD_CTRL_REJECT: case PD_CTRL_WAIT: + case PD_CTRL_NOT_SUPP: switch (port->state) { case SNK_NEGOTIATE_CAPABILITIES: /* USB PD specification, Figure 8-43 */ @@ -1548,12 +1597,84 @@ static void tcpm_pd_ctrl_request(struct tcpm_port *port, break; } break; + case PD_CTRL_GET_SOURCE_CAP_EXT: + case PD_CTRL_GET_STATUS: + case PD_CTRL_FR_SWAP: + case PD_CTRL_GET_PPS_STATUS: + case PD_CTRL_GET_COUNTRY_CODES: + /* Currently not supported */ + tcpm_queue_message(port, PD_MSG_CTRL_NOT_SUPP); + break; default: tcpm_log(port, "Unhandled ctrl message type %#x", type); break; } } +static void tcpm_pd_ext_msg_request(struct tcpm_port *port, + const struct pd_message *msg) +{ + enum pd_ext_msg_type type = pd_header_type_le(msg->header); + unsigned int data_size = pd_ext_header_data_size_le(msg->ext_msg.header); + u8 *data; + + if (!(msg->ext_msg.header && PD_EXT_HDR_CHUNKED)) { + tcpm_log(port, "Unchunked extended messages unsupported"); + return; + } + + if (data_size > (PD_EXT_MAX_LEGACY_DATA)) { + tcpm_log(port, "Chunk handling not yet supported"); + return; + } + + data = kzalloc(data_size, GFP_KERNEL); + if (!data) { + tcpm_log(port, "Failed to allocate memory for ext msg data"); + return; + } + memcpy(data, msg->ext_msg.data, data_size); + + switch (type) { + case PD_EXT_STATUS: + /* + * If PPS related events raised then get PPS status to clear + * (see USB PD 3.0 Spec, 6.5.2.4) + */ + if (data[EXT_SDB_EVENT_FLAGS] & EXT_SDB_PPS_EVENTS) + tcpm_set_state(port, GET_PPS_STATUS_SEND, 0); + else + tcpm_set_state(port, ready_state(port), 0); + break; + case PD_EXT_PPS_STATUS: + /* + * For now the PPS status message is used to clear events + * and nothing more. + */ + tcpm_set_state(port, ready_state(port), 0); + break; + case PD_EXT_SOURCE_CAP_EXT: + case PD_EXT_GET_BATT_CAP: + case PD_EXT_GET_BATT_STATUS: + case PD_EXT_BATT_CAP: + case PD_EXT_GET_MANUFACTURER_INFO: + case PD_EXT_MANUFACTURER_INFO: + case PD_EXT_SECURITY_REQUEST: + case PD_EXT_SECURITY_RESPONSE: + case PD_EXT_FW_UPDATE_REQUEST: + case PD_EXT_FW_UPDATE_RESPONSE: + case PD_EXT_COUNTRY_INFO: + case PD_EXT_COUNTRY_CODES: + tcpm_queue_message(port, PD_MSG_CTRL_NOT_SUPP); + break; + default: + tcpm_log(port, "Unhandle extended message type %#x", type); + break; + } + + kfree(data); +} + static void tcpm_pd_rx_handler(struct work_struct *work) { struct pd_rx_event *event = container_of(work, @@ -1594,7 +1715,9 @@ static void tcpm_pd_rx_handler(struct work_struct *work) "Data role mismatch, initiating error recovery"); tcpm_set_state(port, ERROR_RECOVERY, 0); } else { - if (cnt) + if (msg->header & PD_HEADER_EXT_HDR) + tcpm_pd_ext_msg_request(port, msg); + else if (cnt) tcpm_pd_data_request(port, msg); else tcpm_pd_ctrl_request(port, msg); @@ -1654,6 +1777,9 @@ static bool tcpm_send_queued_message(struct tcpm_port *port) case PD_MSG_CTRL_REJECT: tcpm_pd_send_control(port, PD_CTRL_REJECT); break; + case PD_MSG_CTRL_NOT_SUPP: + tcpm_pd_send_control(port, PD_CTRL_NOT_SUPP); + break; case PD_MSG_DATA_SINK_CAP: tcpm_pd_send_sink_caps(port); break; @@ -2324,14 +2450,6 @@ static inline enum tcpm_state hard_reset_state(struct tcpm_port *port) return SNK_UNATTACHED; } -static inline enum tcpm_state ready_state(struct tcpm_port *port) -{ - if (port->pwr_role == TYPEC_SOURCE) - return SRC_READY; - else - return SNK_READY; -} - static inline enum tcpm_state unattached_state(struct tcpm_port *port) { if (port->port_type == TYPEC_PORT_DRP) { @@ -3032,6 +3150,22 @@ static void run_state_machine(struct tcpm_port *port) /* Always switch to unattached state */ tcpm_set_state(port, unattached_state(port), 0); break; + case GET_STATUS_SEND: + tcpm_pd_send_control(port, PD_CTRL_GET_STATUS); + tcpm_set_state(port, GET_STATUS_SEND_TIMEOUT, + PD_T_SENDER_RESPONSE); + break; + case GET_STATUS_SEND_TIMEOUT: + tcpm_set_state(port, ready_state(port), 0); + break; + case GET_PPS_STATUS_SEND: + tcpm_pd_send_control(port, PD_CTRL_GET_PPS_STATUS); + tcpm_set_state(port, GET_PPS_STATUS_SEND_TIMEOUT, + PD_T_SENDER_RESPONSE); + break; + case GET_PPS_STATUS_SEND_TIMEOUT: + tcpm_set_state(port, ready_state(port), 0); + break; case ERROR_RECOVERY: tcpm_swap_complete(port, -EPROTO); tcpm_pps_complete(port, -EPROTO);