diff options
author | Sam Hurst <shurst@google.com> | 2017-08-05 13:24:40 -0700 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2017-10-24 15:30:15 -0700 |
commit | c91dbb26d87573b9789a6a8b3e05eac3a9c205fa (patch) | |
tree | 145ef633cb7ebaf387da040557399afecc44188f /common/usb_pd_protocol.c | |
parent | 5fd1540e62be47747c4fe234a0b348e58e0cfd3f (diff) | |
download | chrome-ec-c91dbb26d87573b9789a6a8b3e05eac3a9c205fa.tar.gz |
PD: Make current USB PD Stack REV 3 compliant
Implement the following required features in the USB PD Rev. 3.0
specification.
Not_supported control message: Inform a port partner that a
particular message is not supported.
Battery capabilities extended message: Report battery design
capacity and last full charge capacity.
Battery status data message: Report battery state of charge
Collision avoidance: New scheme to avoid collisions caused when both
source and sink want to send messages.
Cable communication: Only the VCONN source can communicate with the
cable plug. This is NOT implemented because although the drivers have
the capability of communicating with a cable plug, the PD stack doesn't
currently need to talk to a cable plug. This is okay since the current
PD design doesn't source or sink more than 3 amps and all Type-C cables
are required to be 3 amp capable.
BUG=b:64411727
BRANCH=None
TEST=`make -j buildall`
Passed relevant PD Rev 2.0 compliance tests
Successful PD negotiation with PD Rev 2.0 and 3.0 chargers
Tested with low power none PD charger.
Modified a Kevin to operate as a PD 3.0 charger and sent
all required messages and verified the return messages.
Also tested collision avoidance by verifying that a sink only
transmits when the source indicates it's okay.
Used Twinkie to verify that PD was operating as v3.0.
Signed-off-by: Sam Hurst <shurst@chromium.org>
Change-Id: Ifd77e92ec4e9106236f9221393d2bfb97263d979
Reviewed-on: https://chromium-review.googlesource.com/603003
Commit-Ready: Sam Hurst <shurst@google.com>
Tested-by: Sam Hurst <shurst@google.com>
Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
Diffstat (limited to 'common/usb_pd_protocol.c')
-rw-r--r-- | common/usb_pd_protocol.c | 440 |
1 files changed, 422 insertions, 18 deletions
diff --git a/common/usb_pd_protocol.c b/common/usb_pd_protocol.c index 61a329f3ed..c1628beff0 100644 --- a/common/usb_pd_protocol.c +++ b/common/usb_pd_protocol.c @@ -4,6 +4,7 @@ */ #include "battery.h" +#include "battery_smart.h" #include "board.h" #include "charge_manager.h" #include "charge_state.h" @@ -100,6 +101,34 @@ enum pd_dual_role_states drp_state = CONFIG_USB_PD_INITIAL_DRP_STATE; static uint8_t pd_try_src_enable; #endif +#ifdef CONFIG_USB_PD_REV30 +/* + * The spec. revision is used to index into this array. + * Rev 0 (PD 1.0) - return PD_CTRL_REJECT + * Rev 1 (PD 2.0) - return PD_CTRL_REJECT + * Rev 2 (PD 3.0) - return PD_CTRL_NOT_SUPPORTED + */ +static const uint8_t refuse[] = { + PD_CTRL_REJECT, PD_CTRL_REJECT, PD_CTRL_NOT_SUPPORTED}; +#define REFUSE(r) refuse[r] +#else +#define REFUSE(r) PD_CTRL_REJECT +#endif + +#ifdef CONFIG_USB_PD_REV30 +/* + * The spec. revision is used to index into this array. + * Rev 0 (VDO 1.0) - return VDM_VER10 + * Rev 1 (VDO 1.0) - return VDM_VER10 + * Rev 2 (VDO 2.0) - return VDM_VER20 + */ +static const uint8_t vdo_ver[] = { + VDM_VER10, VDM_VER10, VDM_VER20}; +#define VDO_VER(v) vdo_ver[v] +#else +#define VDO_VER(v) VDM_VER10 +#endif + static struct pd_protocol { /* current port power role (SOURCE or SINK) */ uint8_t power_role; @@ -158,6 +187,15 @@ static struct pd_protocol { uint16_t dev_id; uint32_t dev_rw_hash[PD_RW_HASH_SIZE/4]; enum ec_current_image current_image; +#ifdef CONFIG_USB_PD_REV30 + /* PD Collision avoidance buffer */ + uint16_t ca_buffered; + uint16_t ca_header; + uint32_t ca_buffer[PDO_MAX_OBJECTS]; + enum tcpm_transmit_type ca_type; + /* protocol revision */ + uint8_t rev; +#endif } pd[CONFIG_USB_PD_PORT_COUNT]; #ifdef CONFIG_COMMON_RUNTIME @@ -215,6 +253,18 @@ static inline void set_state_timeout(int port, pd[port].timeout_state = timeout_state; } +#ifdef CONFIG_USB_PD_REV30 +int pd_get_rev(int port) +{ + return pd[port].rev; +} + +int pd_get_vdo_ver(int port) +{ + return vdo_ver[pd[port].rev]; +} +#endif + /* Return flag for pd state is connected */ int pd_is_connected(int port) { @@ -303,10 +353,27 @@ static inline void set_state(int port, enum pd_states next_state) #else /* CONFIG_USB_PD_DUAL_ROLE */ if (next_state == PD_STATE_SRC_DISCONNECTED) { #endif - /* If we are source, make sure VBUS is off */ - if (pd[port].power_role == PD_ROLE_SOURCE) + /* + * If we are source, make sure VBUS is off and + * if PD REV3.0, restore RP. + */ + if (pd[port].power_role == PD_ROLE_SOURCE) { + /* + * Rp is restored by pd_power_supply_reset if + * CONFIG_USB_PD_MAX_SINGLE_SOURCE_CURRENT is defined. + */ pd_power_supply_reset(port); - +#if !defined(CONFIG_USB_PD_MAX_SINGLE_SOURCE_CURRENT) && \ + defined(CONFIG_USB_PD_REV30) + /* Restore Rp */ + tcpm_select_rp_value(port, CONFIG_USB_PD_PULLUP); + tcpm_set_cc(port, TYPEC_CC_RP); +#endif + } +#ifdef CONFIG_USB_PD_REV30 + /* Adjust rev to highest level*/ + pd[port].rev = PD_REV30; +#endif pd[port].dev_id = 0; pd[port].flags &= ~PD_FLAGS_RESET_ON_DISCONNECT_MASK; #ifdef CONFIG_CHARGE_MANAGER @@ -348,6 +415,19 @@ static void inc_id(int port) pd[port].msg_id = (pd[port].msg_id + 1) & PD_MESSAGE_ID_COUNT; } +#ifdef CONFIG_USB_PD_REV30 +static void sink_can_xmit(int port, int rp) +{ + tcpm_select_rp_value(port, rp); + tcpm_set_cc(port, TYPEC_CC_RP); +} + +static inline void pd_ca_reset(int port) +{ + pd[port].ca_buffered = 0; +} +#endif + void pd_transmit_complete(int port, int status) { if (status == TCPC_TX_COMPLETE_SUCCESS) @@ -365,12 +445,76 @@ static int pd_transmit(int port, enum tcpm_transmit_type type, /* If comms are disabled, do not transmit, return error */ if (!pd_comm_is_enabled(port)) return -1; +#ifdef CONFIG_USB_PD_REV30 + /* Source-coordinated collision avoidance */ + /* + * In order to avoid message collisions due to asynchronous Messaging + * sent from the Sink, the Source sets Rp to SinkTxOk to indicate to + * the Sink that it is ok to initiate an AMS. When the Source wishes + * to initiate an AMS it sets Rp to SinkTxNG. When the Sink detects + * that Rp is set to SinkTxOk it May initiate an AMS. When the Sink + * detects that Rp is set to SinkTxNG it Shall Not initiate an AMS + * and Shall only send Messages that are part of an AMS the Source has + * initiated. Note that this restriction applies to SOP* AMS’s i.e. + * for both Port to Port and Port to Cable Plug communications. + * + * This starts after an Explicit Contract is in place + * PD R3 V1.1 Section 2.5.2. + * + * Note: a Sink can still send Hard Reset signaling at any time. + */ + if ((pd[port].rev == PD_REV30) && + (pd[port].flags & PD_FLAGS_EXPLICIT_CONTRACT)) { + if (pd[port].power_role == PD_ROLE_SOURCE) { + /* + * Inform Sink that it can't transmit. If a sink + * transmition is in progress and a collsion occurs, + * a reset is generated. This should be rare because + * all extended messages are chunked. This effectively + * defaults to PD REV 2.0 collision avoidance. + */ + sink_can_xmit(port, SINK_TX_NG); + } else if (type != TCPC_TX_HARD_RESET) { + int cc1; + int cc2; + tcpm_get_cc(port, &cc1, &cc2); + if (cc1 == TYPEC_CC_VOLT_SNK_1_5 || + cc2 == TYPEC_CC_VOLT_SNK_1_5) { + /* Sink can't transmit now. */ + /* Check if message is already buffered. */ + if (pd[port].ca_buffered) + return -1; + + /* Buffer message and send later. */ + pd[port].ca_type = type; + pd[port].ca_header = header; + memcpy(pd[port].ca_buffer, + data, sizeof(uint32_t) * + PD_HEADER_CNT(header)); + pd[port].ca_buffered = 1; + return 1; + } + } + } +#endif tcpm_transmit(port, type, header, data); /* Wait until TX is complete */ evt = task_wait_event_mask(PD_EVENT_TX, PD_T_TCPC_TX_TIMEOUT); +#ifdef CONFIG_USB_PD_REV30 + /* + * If the source just completed a transmit, tell + * the sink it can transmit if it wants to. + */ + if ((pd[port].rev == PD_REV30) && + (pd[port].power_role == PD_ROLE_SOURCE) && + (pd[port].flags & PD_FLAGS_EXPLICIT_CONTRACT)) { + sink_can_xmit(port, SINK_TX_OK); + } +#endif + if (evt & TASK_EVENT_TIMER) return -1; @@ -378,6 +522,29 @@ static int pd_transmit(int port, enum tcpm_transmit_type type, return pd[port].tx_status == TCPC_TX_COMPLETE_SUCCESS ? 1 : -1; } +#ifdef CONFIG_USB_PD_REV30 +static void pd_ca_send_pending(int port) +{ + int cc1; + int cc2; + + /* Check if a message has been buffered. */ + if (!pd[port].ca_buffered) + return; + + tcpm_get_cc(port, &cc1, &cc2); + if ((cc1 != TYPEC_CC_VOLT_SNK_1_5) && + (cc2 != TYPEC_CC_VOLT_SNK_1_5)) + if (pd_transmit(port, pd[port].ca_type, + pd[port].ca_header, + pd[port].ca_buffer) < 0) + return; + + /* Message was sent, so free up the buffer. */ + pd[port].ca_buffered = 0; +} +#endif + static void pd_update_roles(int port) { /* Notify TCPC of role update */ @@ -388,7 +555,8 @@ static int send_control(int port, int type) { int bit_len; uint16_t header = PD_HEADER(type, pd[port].power_role, - pd[port].data_role, pd[port].msg_id, 0); + pd[port].data_role, pd[port].msg_id, 0, + pd_get_rev(port), 0); bit_len = pd_transmit(port, TCPC_TX_SOP, header, NULL); if (debug_level >= 2) @@ -413,10 +581,12 @@ static int send_source_cap(int port) if (src_pdo_cnt == 0) /* No source capabilities defined, sink only */ header = PD_HEADER(PD_CTRL_REJECT, pd[port].power_role, - pd[port].data_role, pd[port].msg_id, 0); + pd[port].data_role, pd[port].msg_id, 0, + pd_get_rev(port), 0); else header = PD_HEADER(PD_DATA_SOURCE_CAP, pd[port].power_role, - pd[port].data_role, pd[port].msg_id, src_pdo_cnt); + pd[port].data_role, pd[port].msg_id, src_pdo_cnt, + pd_get_rev(port), 0); bit_len = pd_transmit(port, TCPC_TX_SOP, header, src_pdo); if (debug_level >= 2) @@ -425,12 +595,168 @@ static int send_source_cap(int port) return bit_len; } +#ifdef CONFIG_USB_PD_REV30 +static int send_battery_cap(int port, uint32_t *payload) +{ + int bit_len; + uint16_t msg[6] = {0, 0, 0, 0, 0, 0}; + uint16_t header = PD_HEADER(PD_EXT_BATTERY_CAP, + pd[port].power_role, + pd[port].data_role, + pd[port].msg_id, + 3, /* Number of Data Objects */ + pd[port].rev, + 1 /* This is an exteded message */ + ); + + /* Set extended header */ + msg[0] = PD_EXT_HEADER(0, /* Chunk Number */ + 0, /* Request Chunk */ + 9 /* Data Size in bytes */ + ); + /* Set VID */ + msg[1] = USB_VID_GOOGLE; + + /* Set PID */ + msg[2] = CONFIG_USB_PID; + + if (battery_is_present()) { + /* + * We only have one fixed battery, + * so make sure batt cap ref is 0. + */ + if (BATT_CAP_REF(payload[0]) != 0) { + /* Invalid battery reference */ + msg[5] = 1; + } else { + uint32_t v; + uint32_t c; + + /* + * The Battery Design Capacity field shall return the + * Battery’s design capacity in tenths of Wh. If the + * Battery is Hot Swappable and is not present, the + * Battery Design Capacity field shall be set to 0. If + * the Battery is unable to report its Design Capacity, + * it shall return 0xFFFF + */ + msg[3] = 0xffff; + + /* + * The Battery Last Full Charge Capacity field shall + * return the Battery’s last full charge capacity in + * tenths of Wh. If the Battery is Hot Swappable and + * is not present, the Battery Last Full Charge Capacity + * field shall be set to 0. If the Battery is unable to + * report its Design Capacity, the Battery Last Full + * Charge Capacity field shall be set to 0xFFFF. + */ + msg[4] = 0xffff; + + if (battery_design_voltage(&v) == 0) { + if (battery_design_capacity(&c) == 0) { + /* + * Wh = (c * v) / 1000000 + * 10th of a Wh = Wh * 10 + */ + msg[3] = DIV_ROUND_NEAREST((c * v), + 100000); + } + + if (battery_full_charge_capacity(&c) == 0) { + /* + * Wh = (c * v) / 1000000 + * 10th of a Wh = Wh * 10 + */ + msg[4] = DIV_ROUND_NEAREST((c * v), + 100000); + } + } + } + } + + bit_len = pd_transmit(port, TCPC_TX_SOP, header, (uint32_t *)msg); + if (debug_level >= 2) + CPRINTF("batCap>%d\n", bit_len); + return bit_len; +} + +static int send_battery_status(int port, uint32_t *payload) +{ + int bit_len; + uint32_t msg = 0; + uint16_t header = PD_HEADER(PD_DATA_BATTERY_STATUS, + pd[port].power_role, + pd[port].data_role, + pd[port].msg_id, + 1, /* Number of Data Objects */ + pd[port].rev, + 0 /* This is NOT an extended message */ + ); + + if (battery_is_present()) { + /* + * We only have one fixed battery, + * so make sure batt cap ref is 0. + */ + if (BATT_CAP_REF(payload[0]) != 0) { + /* Invalid battery reference */ + msg |= BSDO_INVALID; + } else { + uint32_t v; + uint32_t c; + + if (battery_design_voltage(&v) != 0 || + battery_remaining_capacity(&c) != 0) { + msg |= BSDO_CAP(BSDO_CAP_UNKNOWN); + } else { + /* + * Wh = (c * v) / 1000000 + * 10th of a Wh = Wh * 10 + */ + msg |= BSDO_CAP(DIV_ROUND_NEAREST((c * v), + 100000)); + } + + /* Battery is present */ + msg |= BSDO_PRESENT; + + /* + * For drivers that are not smart battery compliant, + * battery_status() returns EC_ERROR_UNIMPLEMENTED and + * the battery is assumed to be idle. + */ + if (battery_status(&c) != 0) { + msg |= BSDO_IDLE; /* assume idle */ + } else { + if (c & STATUS_FULLY_CHARGED) + /* Fully charged */ + msg |= BSDO_IDLE; + else if (c & STATUS_DISCHARGING) + /* Discharging */ + msg |= BSDO_DISCHARGING; + /* else battery is charging.*/ + } + } + } else { + msg = BSDO_CAP(BSDO_CAP_UNKNOWN); + } + + bit_len = pd_transmit(port, TCPC_TX_SOP, header, &msg); + if (debug_level >= 2) + CPRINTF("batStat>%d\n", bit_len); + + return bit_len; +} +#endif + #ifdef CONFIG_USB_PD_DUAL_ROLE static void send_sink_cap(int port) { int bit_len; uint16_t header = PD_HEADER(PD_DATA_SINK_CAP, pd[port].power_role, - pd[port].data_role, pd[port].msg_id, pd_snk_pdo_cnt); + pd[port].data_role, pd[port].msg_id, pd_snk_pdo_cnt, + pd_get_rev(port), 0); bit_len = pd_transmit(port, TCPC_TX_SOP, header, pd_snk_pdo); if (debug_level >= 2) @@ -441,7 +767,8 @@ static int send_request(int port, uint32_t rdo) { int bit_len; uint16_t header = PD_HEADER(PD_DATA_REQUEST, pd[port].power_role, - pd[port].data_role, pd[port].msg_id, 1); + pd[port].data_role, pd[port].msg_id, 1, + pd_get_rev(port), 0); bit_len = pd_transmit(port, TCPC_TX_SOP, header, &rdo); if (debug_level >= 2) @@ -477,7 +804,8 @@ static int send_bist_cmd(int port) uint32_t bdo = BDO(BDO_MODE_CARRIER2, 0); int bit_len; uint16_t header = PD_HEADER(PD_DATA_BIST, pd[port].power_role, - pd[port].data_role, pd[port].msg_id, 1); + pd[port].data_role, pd[port].msg_id, 1, + pd_get_rev(port), 0); bit_len = pd_transmit(port, TCPC_TX_SOP, header, &bdo); CPRINTF("BIST>%d\n", bit_len); @@ -541,6 +869,10 @@ void pd_execute_hard_reset(int port) pd_dfp_exit_mode(port, 0, 0); #endif +#ifdef CONFIG_USB_PD_REV30 + pd[port].rev = PD_REV30; + pd_ca_reset(port); +#endif /* * Fake set last state to hard reset to make sure that the next * state to run knows that we just did a hard reset. @@ -737,6 +1069,13 @@ static void handle_data_request(int port, uint16_t head, PD_STATE_SNK_HARD_RESET_RECOVER) #endif || (pd[port].task_state == PD_STATE_SNK_READY)) { +#ifdef CONFIG_USB_PD_REV30 + /* + * Only adjust sink rev if source rev is higher. + */ + if (PD_HEADER_REV(head) < pd[port].rev) + pd[port].rev = PD_HEADER_REV(head); +#endif /* Port partner is now known to be PD capable */ pd[port].flags |= PD_FLAGS_PREVIOUS_PD_CONN; @@ -751,7 +1090,14 @@ static void handle_data_request(int port, uint16_t head, break; #endif /* CONFIG_USB_PD_DUAL_ROLE */ case PD_DATA_REQUEST: - if ((pd[port].power_role == PD_ROLE_SOURCE) && (cnt == 1)) + if ((pd[port].power_role == PD_ROLE_SOURCE) && (cnt == 1)) { +#ifdef CONFIG_USB_PD_REV30 + /* + * Adjust the rev level to what the sink supports. If + * they're equal, no harm done. + */ + pd[port].rev = PD_HEADER_REV(head); +#endif if (!pd_check_requested_voltage(payload[0], port)) { if (send_control(port, PD_CTRL_ACCEPT) < 0) /* @@ -763,6 +1109,15 @@ static void handle_data_request(int port, uint16_t head, /* explicit contract is now in place */ pd[port].flags |= PD_FLAGS_EXPLICIT_CONTRACT; +#ifdef CONFIG_USB_PD_REV30 + /* + * Start Source-coordinated collision + * avoidance + */ + if (pd[port].rev == PD_REV30 && + pd[port].power_role == PD_ROLE_SOURCE) + sink_can_xmit(port, SINK_TX_OK); +#endif #ifdef CONFIG_USB_PD_DUAL_ROLE pd_set_saved_active(port, 1); #endif @@ -770,6 +1125,7 @@ static void handle_data_request(int port, uint16_t head, set_state(port, PD_STATE_SRC_ACCEPTED); return; } + } /* the message was incorrect or cannot be satisfied */ send_control(port, PD_CTRL_REJECT); /* keep last contract in place (whether implicit or explicit) */ @@ -799,6 +1155,10 @@ static void handle_data_request(int port, uint16_t head, if (pd[port].task_state == PD_STATE_SRC_GET_SINK_CAP) set_state(port, PD_STATE_SRC_READY); break; +#ifdef CONFIG_USB_PD_REV30 + case PD_DATA_BATTERY_STATUS: + break; +#endif case PD_DATA_VENDOR_DEF: handle_vdm_request(port, cnt, payload); break; @@ -903,7 +1263,7 @@ static void handle_ctrl_request(int port, uint16_t head, #ifdef CONFIG_USB_PD_DUAL_ROLE send_sink_cap(port); #else - send_control(port, PD_CTRL_REJECT); + send_control(port, REFUSE(pd[port].rev)); #endif break; #ifdef CONFIG_USB_PD_DUAL_ROLE @@ -1075,10 +1435,10 @@ static void handle_ctrl_request(int port, uint16_t head, PD_STATE_SNK_SWAP_SNK_DISABLE, PD_STATE_SRC_SWAP_SNK_DISABLE)); } else { - send_control(port, PD_CTRL_REJECT); + send_control(port, REFUSE(pd[port].rev)); } #else - send_control(port, PD_CTRL_REJECT); + send_control(port, REFUSE(pd[port].rev)); #endif break; case PD_CTRL_DR_SWAP: @@ -1092,7 +1452,8 @@ static void handle_ctrl_request(int port, uint16_t head, if (send_control(port, PD_CTRL_ACCEPT) >= 0) pd_dr_swap(port); } else { - send_control(port, PD_CTRL_REJECT); + send_control(port, REFUSE(pd[port].rev)); + } break; case PD_CTRL_VCONN_SWAP: @@ -1104,18 +1465,41 @@ static void handle_ctrl_request(int port, uint16_t head, set_state(port, PD_STATE_VCONN_SWAP_INIT); } else { - send_control(port, PD_CTRL_REJECT); + send_control(port, REFUSE(pd[port].rev)); } } #else - send_control(port, PD_CTRL_REJECT); + send_control(port, REFUSE(pd[port].rev)); #endif break; default: +#ifdef CONFIG_USB_PD_REV30 + send_control(port, PD_CTRL_NOT_SUPPORTED); +#endif CPRINTF("Unhandled ctrl message type %d\n", type); } } +#ifdef CONFIG_USB_PD_REV30 +static void handle_ext_request(int port, uint16_t head, uint32_t *payload) +{ + int type = PD_HEADER_TYPE(head); + + switch (type) { + case PD_EXT_GET_BATTERY_CAP: + send_battery_cap(port, payload); + break; + case PD_EXT_GET_BATTERY_STATUS: + send_battery_status(port, payload); + break; + case PD_EXT_BATTERY_CAP: + break; + default: + send_control(port, PD_CTRL_NOT_SUPPORTED); + } +} +#endif + static void handle_request(int port, uint16_t head, uint32_t *payload) { @@ -1138,6 +1522,13 @@ static void handle_request(int port, uint16_t head, if (!pd_is_connected(port)) set_state(port, PD_STATE_HARD_RESET_SEND); +#ifdef CONFIG_USB_PD_REV30 + /* Check if this is an extended chunked data message. */ + if (pd[port].rev == PD_REV30 && PD_HEADER_EXT(head)) { + handle_ext_request(port, head, payload); + return; + } +#endif if (cnt) handle_data_request(port, head, payload); else @@ -1155,6 +1546,9 @@ void pd_send_vdm(int port, uint32_t vid, int cmd, const uint32_t *data, /* set VDM header with VID & CMD */ pd[port].vdo_data[0] = VDO(vid, ((vid & USB_SID_PD) == USB_SID_PD) ? 1 : (PD_VDO_CMD(cmd) <= CMD_ATTENTION), cmd); +#ifdef CONFIG_USB_PD_REV30 + pd[port].vdo_data[0] |= VDO_SVDM_VERS(vdo_ver[pd[port].rev]); +#endif queue_vdm(port, pd[port].vdo_data, data, count); task_wake(PD_PORT_TO_TASK_ID(port)); @@ -1223,7 +1617,8 @@ static void pd_vdm_send_state_machine(int port) /* Prepare and send VDM */ header = PD_HEADER(PD_DATA_VENDOR_DEF, pd[port].power_role, pd[port].data_role, pd[port].msg_id, - (int)pd[port].vdo_count); + (int)pd[port].vdo_count, + pd_get_rev(port), 0); res = pd_transmit(port, TCPC_TX_SOP, header, pd[port].vdo_data); if (res < 0) { @@ -1664,6 +2059,12 @@ void pd_task(void *u) } #endif +#ifdef CONFIG_USB_PD_REV30 + /* Set Revision to highest */ + pd[port].rev = PD_REV30; + pd_ca_reset(port); +#endif + #ifdef CONFIG_USB_PD_DUAL_ROLE /* * If VBUS is high, then initialize flag for VBUS has always been @@ -1707,6 +2108,10 @@ void pd_task(void *u) #endif while (1) { +#ifdef CONFIG_USB_PD_REV30 + /* send any pending messages */ + pd_ca_send_pending(port); +#endif /* process VDM messages last */ pd_vdm_send_state_machine(port); @@ -1796,7 +2201,6 @@ void pd_task(void *u) case PD_STATE_SRC_DISCONNECTED: timeout = 10*MSEC; tcpm_get_cc(port, &cc1, &cc2); - #ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE /* * Attempt TCPC auto DRP toggle if it is |