diff options
Diffstat (limited to 'common/usbc/usb_prl_sm.c')
-rw-r--r-- | common/usbc/usb_prl_sm.c | 2471 |
1 files changed, 0 insertions, 2471 deletions
diff --git a/common/usbc/usb_prl_sm.c b/common/usbc/usb_prl_sm.c deleted file mode 100644 index a58a579775..0000000000 --- a/common/usbc/usb_prl_sm.c +++ /dev/null @@ -1,2471 +0,0 @@ -/* Copyright 2019 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "battery.h" -#include "battery_smart.h" -#include "board.h" -#include "charge_manager.h" -#include "charge_state.h" -#include "chipset.h" -#include "common.h" -#include "console.h" -#include "cros_version.h" -#include "ec_commands.h" -#include "gpio.h" -#include "hooks.h" -#include "host_command.h" -#include "registers.h" -#include "system.h" -#include "task.h" -#include "tcpm/tcpm.h" -#include "util.h" -#include "usb_charge.h" -#include "usb_mux.h" -#include "usb_pd.h" -#include "usb_pd_timer.h" -#include "usb_pe_sm.h" -#include "usb_prl_sm.h" -#include "usb_tc_sm.h" -#include "usb_emsg.h" -#include "usb_sm.h" -#include "vpd_api.h" - -#ifdef CONFIG_COMMON_RUNTIME -#define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args) -#define CPRINTS(format, args...) cprints(CC_USBPD, format, ## args) -#else -#define CPRINTF(format, args...) -#define CPRINTS(format, args...) -#endif - -/* - * Define DEBUG_PRINT_FLAG_NAMES to print flag names when set and cleared. - */ -#undef DEBUG_PRINT_FLAG_NAMES - -#ifdef DEBUG_PRINT_FLAG_NAMES -__maybe_unused static void print_flag(const char *group, - int set_or_clear, - int flag); -#define SET_FLAG(group, flags, flag) \ - do { \ - print_flag(group, 1, flag); \ - atomic_or(flags, (flag)); \ - } while (0) -#define CLR_FLAG(group, flags, flag) \ - do { \ - int before = *flags; \ - atomic_clear_bits(flags, (flag)); \ - if (*flags != before) \ - print_flag(group, 0, flag); \ - } while (0) -#else -#define SET_FLAG(group, flags, flag) atomic_or(flags, (flag)) -#define CLR_FLAG(group, flags, flag) atomic_clear_bits(flags, (flag)) -#endif - - -#define RCH_SET_FLAG(port, flag) SET_FLAG("RCH", &rch[port].flags, (flag)) -#define RCH_CLR_FLAG(port, flag) CLR_FLAG("RCH", &rch[port].flags, (flag)) -#define RCH_CHK_FLAG(port, flag) (rch[port].flags & (flag)) - -#define TCH_SET_FLAG(port, flag) SET_FLAG("TCH", &tch[port].flags, (flag)) -#define TCH_CLR_FLAG(port, flag) CLR_FLAG("TCH", &tch[port].flags, (flag)) -#define TCH_CHK_FLAG(port, flag) (tch[port].flags & (flag)) - -#define PRL_TX_SET_FLAG(port, flag) \ - SET_FLAG("PRL_TX", &prl_tx[port].flags, (flag)) -#define PRL_TX_CLR_FLAG(port, flag) \ - CLR_FLAG("PRL_TX", &prl_tx[port].flags, (flag)) -#define PRL_TX_CHK_FLAG(port, flag) (prl_tx[port].flags & (flag)) - -#define PRL_HR_SET_FLAG(port, flag) \ - SET_FLAG("PRL_HR", &prl_hr[port].flags, (flag)) -#define PRL_HR_CLR_FLAG(port, flag) \ - CLR_FLAG("PRL_HR", &prl_hr[port].flags, (flag)) -#define PRL_HR_CHK_FLAG(port, flag) (prl_hr[port].flags & (flag)) - -#define PDMSG_SET_FLAG(port, flag) SET_FLAG("PDMSG", &pdmsg[port].flags, (flag)) -#define PDMSG_CLR_FLAG(port, flag) CLR_FLAG("PDMSG", &pdmsg[port].flags, (flag)) -#define PDMSG_CHK_FLAG(port, flag) (pdmsg[port].flags & (flag)) - -/* Protocol Layer Flags */ -/* - * NOTE: - * These flags are used in multiple state machines and could have - * different meanings in each state machine. - */ -/* Flag to note message transmission completed */ -#define PRL_FLAGS_TX_COMPLETE BIT(0) -/* Flag to note that PRL requested to set SINK_NG CC state */ -#define PRL_FLAGS_SINK_NG BIT(1) -/* Flag to note PRL waited for SINK_OK CC state before transmitting */ -#define PRL_FLAGS_WAIT_SINK_OK BIT(2) -/* Flag to note transmission error occurred */ -#define PRL_FLAGS_TX_ERROR BIT(3) -/* Flag to note PE triggered a hard reset */ -#define PRL_FLAGS_PE_HARD_RESET BIT(4) -/* Flag to note hard reset has completed */ -#define PRL_FLAGS_HARD_RESET_COMPLETE BIT(5) -/* Flag to note port partner sent a hard reset */ -#define PRL_FLAGS_PORT_PARTNER_HARD_RESET BIT(6) -/* - * Flag to note a message transmission has been requested. It is only cleared - * when we send the message to the TCPC layer. - */ -#define PRL_FLAGS_MSG_XMIT BIT(7) -/* Flag to note a message was received */ -#define PRL_FLAGS_MSG_RECEIVED BIT(8) -/* Flag to note aborting current TX message, not currently set */ -#define PRL_FLAGS_ABORT BIT(9) -/* Flag to note current TX message uses chunking */ -#define PRL_FLAGS_CHUNKING BIT(10) - -struct bit_name { - int value; - const char *name; -}; - -static __const_data struct bit_name flag_bit_names[] = { - { PRL_FLAGS_TX_COMPLETE, "PRL_FLAGS_TX_COMPLETE" }, - { PRL_FLAGS_SINK_NG, "PRL_FLAGS_SINK_NG" }, - { PRL_FLAGS_WAIT_SINK_OK, "PRL_FLAGS_WAIT_SINK_OK" }, - { PRL_FLAGS_TX_ERROR, "PRL_FLAGS_TX_ERROR" }, - { PRL_FLAGS_PE_HARD_RESET, "PRL_FLAGS_PE_HARD_RESET" }, - { PRL_FLAGS_HARD_RESET_COMPLETE, "PRL_FLAGS_HARD_RESET_COMPLETE" }, - { PRL_FLAGS_PORT_PARTNER_HARD_RESET, - "PRL_FLAGS_PORT_PARTNER_HARD_RESET" }, - { PRL_FLAGS_MSG_XMIT, "PRL_FLAGS_MSG_XMIT" }, - { PRL_FLAGS_MSG_RECEIVED, "PRL_FLAGS_MSG_RECEIVED" }, - { PRL_FLAGS_ABORT, "PRL_FLAGS_ABORT" }, - { PRL_FLAGS_CHUNKING, "PRL_FLAGS_CHUNKING" }, -}; - -__maybe_unused static void print_bits(const char *group, - const char *desc, - int value, - struct bit_name *names, - int names_size) -{ - int i; - - CPRINTF("%s %s 0x%x : ", group, desc, value); - for (i = 0; i < names_size; i++) { - if (value & names[i].value) - CPRINTF("%s | ", names[i].name); - value &= ~names[i].value; - } - if (value != 0) - CPRINTF("0x%x", value); - CPRINTF("\n"); -} - -__maybe_unused static void print_flag(const char *group, - int set_or_clear, - int flag) -{ - print_bits(group, set_or_clear ? "Set" : "Clr", flag, flag_bit_names, - ARRAY_SIZE(flag_bit_names)); -} - -/* PD counter definitions */ -#define PD_MESSAGE_ID_COUNT 7 - -/* Size of PDMSG Chunk Buffer */ -#define CHK_BUF_SIZE 7 -#define CHK_BUF_SIZE_BYTES 28 - -/* - * Debug log level - higher number == more log - * Level 0: disabled - * Level 1: not currently used - * Level 2: plus non-ping messages - * Level 3: plus ping packet and PRL states - * - * Note that higher log level causes timing changes and thus may affect - * performance. - */ -#ifdef CONFIG_USB_PD_DEBUG_LEVEL -static const enum debug_level prl_debug_level = CONFIG_USB_PD_DEBUG_LEVEL; -#else -static enum debug_level prl_debug_level = DEBUG_LEVEL_1; -#endif - -static enum sm_local_state local_state[CONFIG_USB_PD_PORT_MAX_COUNT]; - -/* Protocol Transmit States (Section 6.11.2.2) */ -enum usb_prl_tx_state { - PRL_TX_PHY_LAYER_RESET, - PRL_TX_WAIT_FOR_MESSAGE_REQUEST, - PRL_TX_LAYER_RESET_FOR_TRANSMIT, - PRL_TX_WAIT_FOR_PHY_RESPONSE, - PRL_TX_SRC_SOURCE_TX, - PRL_TX_SNK_START_AMS, - PRL_TX_SRC_PENDING, - PRL_TX_SNK_PENDING, - PRL_TX_DISCARD_MESSAGE, -}; - -/* Protocol Hard Reset States (Section 6.11.2.4) */ -enum usb_prl_hr_state { - PRL_HR_WAIT_FOR_REQUEST, - PRL_HR_RESET_LAYER, - PRL_HR_WAIT_FOR_PHY_HARD_RESET_COMPLETE, - PRL_HR_WAIT_FOR_PE_HARD_RESET_COMPLETE, -}; - -/* Chunked Rx states (Section 6.11.2.1.2) */ -enum usb_rch_state { - RCH_WAIT_FOR_MESSAGE_FROM_PROTOCOL_LAYER, - RCH_PASS_UP_MESSAGE, - RCH_PROCESSING_EXTENDED_MESSAGE, - RCH_REQUESTING_CHUNK, - RCH_WAITING_CHUNK, - RCH_REPORT_ERROR, -}; - -/* Chunked Tx states (Section 6.11.2.1.3) */ -enum usb_tch_state { - TCH_WAIT_FOR_MESSAGE_REQUEST_FROM_PE, - TCH_WAIT_FOR_TRANSMISSION_COMPLETE, - TCH_CONSTRUCT_CHUNKED_MESSAGE, - TCH_SENDING_CHUNKED_MESSAGE, - TCH_WAIT_CHUNK_REQUEST, - TCH_MESSAGE_RECEIVED, - TCH_MESSAGE_SENT, - TCH_REPORT_ERROR, -}; - -static const char * const prl_tx_state_names[] = { - [PRL_TX_PHY_LAYER_RESET] = "PRL_TX_PHY_LAYER_RESET", - [PRL_TX_WAIT_FOR_MESSAGE_REQUEST] = "PRL_TX_WAIT_FOR_MESSAGE_REQUEST", - [PRL_TX_LAYER_RESET_FOR_TRANSMIT] = "PRL_TX_LAYER_RESET_FOR_TRANSMIT", - [PRL_TX_WAIT_FOR_PHY_RESPONSE] = "PRL_TX_WAIT_FOR_PHY_RESPONSE", - [PRL_TX_SRC_SOURCE_TX] = "PRL_TX_SRC_SOURCE_TX", - [PRL_TX_SNK_START_AMS] = "PRL_TX_SNK_START_AMS", - [PRL_TX_SRC_PENDING] = "PRL_TX_SRC_PENDING", - [PRL_TX_SNK_PENDING] = "PRL_TX_SNK_PENDING", - [PRL_TX_DISCARD_MESSAGE] = "PRL_TX_DISCARD_MESSAGE", -}; - -static const char * const prl_hr_state_names[] = { - [PRL_HR_WAIT_FOR_REQUEST] = "PRL_HR_WAIT_FOR_REQUEST", - [PRL_HR_RESET_LAYER] = "PRL_HR_RESET_LAYER", - [PRL_HR_WAIT_FOR_PHY_HARD_RESET_COMPLETE] - = "PRL_HR_WAIT_FOR_PHY_HARD_RESET_COMPLETE", - [PRL_HR_WAIT_FOR_PE_HARD_RESET_COMPLETE] - = "PRL_HR_WAIT_FOR_PE_HARD_RESET_COMPLETE", -}; - -__maybe_unused static const char * const rch_state_names[] = { - [RCH_WAIT_FOR_MESSAGE_FROM_PROTOCOL_LAYER] - = "RCH_WAIT_FOR_MESSAGE_FROM_PROTOCOL_LAYER", - [RCH_PASS_UP_MESSAGE] = "RCH_PASS_UP_MESSAGE", - [RCH_PROCESSING_EXTENDED_MESSAGE] = "RCH_PROCESSING_EXTENDED_MESSAGE", - [RCH_REQUESTING_CHUNK] = "RCH_REQUESTING_CHUNK", - [RCH_WAITING_CHUNK] = "RCH_WAITING_CHUNK", - [RCH_REPORT_ERROR] = "RCH_REPORT_ERROR", -}; - -__maybe_unused static const char * const tch_state_names[] = { - [TCH_WAIT_FOR_MESSAGE_REQUEST_FROM_PE] - = "TCH_WAIT_FOR_MESSAGE_REQUEST_FROM_PE", - [TCH_WAIT_FOR_TRANSMISSION_COMPLETE] - = "TCH_WAIT_FOR_TRANSMISSION_COMPLETE", - [TCH_CONSTRUCT_CHUNKED_MESSAGE] = "TCH_CONSTRUCT_CHUNKED_MESSAGE", - [TCH_SENDING_CHUNKED_MESSAGE] = "TCH_SENDING_CHUNKED_MESSAGE", - [TCH_WAIT_CHUNK_REQUEST] = "TCH_WAIT_CHUNK_REQUEST", - [TCH_MESSAGE_RECEIVED] = "TCH_MESSAGE_RECEIVED", - [TCH_MESSAGE_SENT] = "TCH_MESSAGE_SENT", - [TCH_REPORT_ERROR] = "TCH_REPORT_ERROR", -}; - -/* Forward declare full list of states. Index by above enums. */ -static const struct usb_state prl_tx_states[]; -static const struct usb_state prl_hr_states[]; - -__maybe_unused static const struct usb_state rch_states[]; -__maybe_unused static const struct usb_state tch_states[]; - -/* Chunked Rx State Machine Object */ -static struct rx_chunked { - /* state machine context */ - struct sm_ctx ctx; - /* PRL_FLAGS */ - uint32_t flags; - /* error to report when moving to rch_report_error state */ - enum pe_error error; -} rch[CONFIG_USB_PD_PORT_MAX_COUNT]; - -/* Chunked Tx State Machine Object */ -static struct tx_chunked { - /* state machine context */ - struct sm_ctx ctx; - /* state machine flags */ - uint32_t flags; - /* error to report when moving to tch_report_error state */ - enum pe_error error; -} tch[CONFIG_USB_PD_PORT_MAX_COUNT]; - -/* Message Reception State Machine Object */ -static struct protocol_layer_rx { - /* received message type */ - enum tcpci_msg_type sop; - /* message ids for all valid port partners */ - int msg_id[NUM_SOP_STAR_TYPES]; -} prl_rx[CONFIG_USB_PD_PORT_MAX_COUNT]; - -/* Message Transmission State Machine Object */ -static struct protocol_layer_tx { - /* state machine context */ - struct sm_ctx ctx; - /* state machine flags */ - uint32_t flags; - /* last message type we transmitted */ - enum tcpci_msg_type last_xmit_type; - /* message id counters for all 6 port partners */ - uint32_t msg_id_counter[NUM_SOP_STAR_TYPES]; - /* transmit status */ - int xmit_status; -} prl_tx[CONFIG_USB_PD_PORT_MAX_COUNT]; - -/* Hard Reset State Machine Object */ -static struct protocol_hard_reset { - /* state machine context */ - struct sm_ctx ctx; - /* state machine flags */ - uint32_t flags; -} prl_hr[CONFIG_USB_PD_PORT_MAX_COUNT]; - -/* Chunking Message Object */ -static struct pd_message { - /* message status flags */ - uint32_t flags; - /* SOP* */ - enum tcpci_msg_type xmit_type; - /* type of message */ - uint8_t msg_type; - /* PD revision */ - enum pd_rev_type rev[NUM_SOP_STAR_TYPES]; - /* Number of 32-bit objects in chk_buf */ - uint16_t data_objs; - /* temp chunk buffer */ - uint32_t tx_chk_buf[CHK_BUF_SIZE]; - uint32_t rx_chk_buf[CHK_BUF_SIZE]; - uint32_t chunk_number_expected; - uint32_t num_bytes_received; -#ifdef CONFIG_USB_PD_EXTENDED_MESSAGES - /* extended message */ - uint8_t ext; - uint32_t chunk_number_to_send; - uint32_t send_offset; -#endif /* CONFIG_USB_PD_EXTENDED_MESSAGES */ -} pdmsg[CONFIG_USB_PD_PORT_MAX_COUNT]; - -struct extended_msg rx_emsg[CONFIG_USB_PD_PORT_MAX_COUNT]; -struct extended_msg tx_emsg[CONFIG_USB_PD_PORT_MAX_COUNT]; - -/* Common Protocol Layer Message Transmission */ -static void prl_tx_construct_message(int port); -static void prl_rx_wait_for_phy_message(const int port, int evt); -static void prl_copy_msg_to_buffer(int port); - -#ifndef CONFIG_USB_PD_REV30 -GEN_NOT_SUPPORTED(PRL_TX_SRC_SOURCE_TX); -#define PRL_TX_SRC_SOURCE_TX PRL_TX_SRC_SOURCE_TX_NOT_SUPPORTED -GEN_NOT_SUPPORTED(PRL_TX_SNK_START_AMS); -#define PRL_TX_SNK_START_AMS PRL_TX_SNK_START_AMS_NOT_SUPPORTED - -GEN_NOT_SUPPORTED(RCH_WAIT_FOR_MESSAGE_FROM_PROTOCOL_LAYER); -#define RCH_WAIT_FOR_MESSAGE_FROM_PROTOCOL_LAYER \ - RCH_WAIT_FOR_MESSAGE_FROM_PROTOCOL_LAYER_NOT_SUPPORTED -GEN_NOT_SUPPORTED(RCH_PASS_UP_MESSAGE); -#define RCH_PASS_UP_MESSAGE RCH_PASS_UP_MESSAGE_NOT_SUPPORTED -GEN_NOT_SUPPORTED(RCH_PROCESSING_EXTENDED_MESSAGE); -#define RCH_PROCESSING_EXTENDED_MESSAGE \ - RCH_PROCESSING_EXTENDED_MESSAGE_NOT_SUPPORTED -GEN_NOT_SUPPORTED(RCH_REQUESTING_CHUNK); -#define RCH_REQUESTING_CHUNK RCH_REQUESTING_CHUNK_NOT_SUPPORTED -GEN_NOT_SUPPORTED(RCH_WAITING_CHUNK); -#define RCH_WAITING_CHUNK RCH_WAITING_CHUNK_NOT_SUPPORTED -GEN_NOT_SUPPORTED(RCH_REPORT_ERROR); -#define RCH_REPORT_ERROR RCH_REPORT_ERROR_NOT_SUPPORTED - -GEN_NOT_SUPPORTED(TCH_WAIT_FOR_MESSAGE_REQUEST_FROM_PE); -#define TCH_WAIT_FOR_MESSAGE_REQUEST_FROM_PE \ - TCH_WAIT_FOR_MESSAGE_REQUEST_FROM_PE_NOT_SUPPORTED -GEN_NOT_SUPPORTED(TCH_WAIT_FOR_TRANSMISSION_COMPLETE); -#define TCH_WAIT_FOR_TRANSMISSION_COMPLETE \ - TCH_WAIT_FOR_TRANSMISSION_COMPLETE_NOT_SUPPORTED -GEN_NOT_SUPPORTED(TCH_CONSTRUCT_CHUNKED_MESSAGE); -#define TCH_CONSTRUCT_CHUNKED_MESSAGE \ - TCH_CONSTRUCT_CHUNKED_MESSAGE_NOT_SUPPORTED -GEN_NOT_SUPPORTED(TCH_SENDING_CHUNKED_MESSAGE); -#define TCH_SENDING_CHUNKED_MESSAGE TCH_SENDING_CHUNKED_MESSAGE_NOT_SUPPORTED -GEN_NOT_SUPPORTED(TCH_WAIT_CHUNK_REQUEST); -#define TCH_WAIT_CHUNK_REQUEST TCH_WAIT_CHUNK_REQUEST_NOT_SUPPORTED -GEN_NOT_SUPPORTED(TCH_MESSAGE_RECEIVED); -#define TCH_MESSAGE_RECEIVED TCH_MESSAGE_RECEIVED_NOT_SUPPORTED -GEN_NOT_SUPPORTED(TCH_MESSAGE_SENT); -#define TCH_MESSAGE_SENT TCH_MESSAGE_SENT_NOT_SUPPORTED -GEN_NOT_SUPPORTED(TCH_REPORT_ERROR); -#define TCH_REPORT_ERROR TCH_REPORT_ERROR_NOT_SUPPORTED -#endif /* !CONFIG_USB_PD_REV30 */ - -/* To store the time stamp when TCPC sets TX Complete Success */ -static timestamp_t tcpc_tx_success_ts[CONFIG_USB_PD_PORT_MAX_COUNT]; - -/* Set the protocol transmit statemachine to a new state. */ -static void set_state_prl_tx(const int port, - const enum usb_prl_tx_state new_state) -{ - set_state(port, &prl_tx[port].ctx, &prl_tx_states[new_state]); -} - -/* Get the protocol transmit statemachine's current state. */ -test_export_static enum usb_prl_tx_state prl_tx_get_state(const int port) -{ - return prl_tx[port].ctx.current - &prl_tx_states[0]; -} - -/* Print the protocol transmit statemachine's current state. */ -static void print_current_prl_tx_state(const int port) -{ - if (prl_debug_level >= DEBUG_LEVEL_3) - CPRINTS("C%d: %s", port, - prl_tx_state_names[prl_tx_get_state(port)]); -} - -/* Set the hard reset statemachine to a new state. */ -static void set_state_prl_hr(const int port, - const enum usb_prl_hr_state new_state) -{ - set_state(port, &prl_hr[port].ctx, &prl_hr_states[new_state]); -} - -/* Get the hard reset statemachine's current state. */ -enum usb_prl_hr_state prl_hr_get_state(const int port) -{ - return prl_hr[port].ctx.current - &prl_hr_states[0]; -} - -/* Print the hard reset statemachine's current state. */ -static void print_current_prl_hr_state(const int port) -{ - if (prl_debug_level >= DEBUG_LEVEL_3) - CPRINTS("C%d: %s", port, - prl_hr_state_names[prl_hr_get_state(port)]); -} - -/* Set the chunked Rx statemachine to a new state. */ -static void set_state_rch(const int port, const enum usb_rch_state new_state) -{ - if (IS_ENABLED(CONFIG_USB_PD_EXTENDED_MESSAGES)) - set_state(port, &rch[port].ctx, &rch_states[new_state]); -} - -#ifdef CONFIG_USB_PD_EXTENDED_MESSAGES -/* Get the chunked Rx statemachine's current state. */ -test_export_static enum usb_rch_state rch_get_state(const int port) -{ - return rch[port].ctx.current - &rch_states[0]; -} - -/* Print the chunked Rx statemachine's current state. */ -static void print_current_rch_state(const int port) -{ - if (prl_debug_level >= DEBUG_LEVEL_3) - CPRINTS("C%d: %s", port, - rch_state_names[rch_get_state(port)]); -} -#endif /* CONFIG_USB_PD_EXTENDED_MESSAGES */ - -/* Set the chunked Tx statemachine to a new state. */ -static void set_state_tch(const int port, const enum usb_tch_state new_state) -{ - if (IS_ENABLED(CONFIG_USB_PD_EXTENDED_MESSAGES)) - set_state(port, &tch[port].ctx, &tch_states[new_state]); -} - -/* Get the chunked Tx statemachine's current state. */ -test_export_static enum usb_tch_state tch_get_state(const int port) -{ - if (IS_ENABLED(CONFIG_USB_PD_EXTENDED_MESSAGES)) - return tch[port].ctx.current - &tch_states[0]; - else - return 0; -} - -#ifdef CONFIG_USB_PD_EXTENDED_MESSAGES -/* Print the chunked Tx statemachine's current state. */ -static void print_current_tch_state(const int port) -{ - if (prl_debug_level >= DEBUG_LEVEL_3) - CPRINTS("C%d: %s", port, - tch_state_names[tch_get_state(port)]); -} -#endif /* CONFIG_USB_PD_EXTENDED_MESSAGES */ - - -timestamp_t prl_get_tcpc_tx_success_ts(int port) -{ - return tcpc_tx_success_ts[port]; -} - -/* Sets the time stamp when TCPC reports TX success. */ -static void set_tcpc_tx_success_ts(int port) -{ - tcpc_tx_success_ts[port] = get_time(); -} - -void pd_transmit_complete(int port, int status) -{ - if (status == TCPC_TX_COMPLETE_SUCCESS) - set_tcpc_tx_success_ts(port); - prl_tx[port].xmit_status = status; -} - -void pd_execute_hard_reset(int port) -{ - /* Only allow async. function calls when state machine is running */ - if (!prl_is_running(port)) - return; - - PRL_HR_SET_FLAG(port, PRL_FLAGS_PORT_PARTNER_HARD_RESET); - set_state_prl_hr(port, PRL_HR_RESET_LAYER); - task_wake(PD_PORT_TO_TASK_ID(port)); -} - -void prl_execute_hard_reset(int port) -{ - /* Only allow async. function calls when state machine is running */ - if (!prl_is_running(port)) - return; - - PRL_HR_SET_FLAG(port, PRL_FLAGS_PE_HARD_RESET); - set_state_prl_hr(port, PRL_HR_RESET_LAYER); - task_wake(PD_PORT_TO_TASK_ID(port)); -} - -int prl_is_running(int port) -{ - return local_state[port] == SM_RUN; -} - -static void prl_init(int port) -{ - int i; - const struct sm_ctx cleared = {}; - - /* - * flags without PRL_FLAGS_SINK_NG present means we are initially - * in SinkTxOK state - */ - prl_tx[port].flags = 0; - if (IS_ENABLED(CONFIG_USB_PD_REV30)) - typec_select_src_collision_rp(port, SINK_TX_OK); - prl_tx[port].last_xmit_type = TCPCI_MSG_SOP; - prl_tx[port].xmit_status = TCPC_TX_UNSET; - - if (IS_ENABLED(CONFIG_USB_PD_REV30)) { - tch[port].flags = 0; - rch[port].flags = 0; - } - - pdmsg[port].flags = 0; - - prl_hr[port].flags = 0; - - for (i = 0; i < NUM_SOP_STAR_TYPES; i++) { - prl_rx[port].msg_id[i] = -1; - prl_tx[port].msg_id_counter[i] = 0; - } - - pd_timer_disable_range(port, PR_TIMER_RANGE); - - /* Clear state machines and set initial states */ - prl_tx[port].ctx = cleared; - set_state_prl_tx(port, PRL_TX_PHY_LAYER_RESET); - - if (IS_ENABLED(CONFIG_USB_PD_EXTENDED_MESSAGES)) { - rch[port].ctx = cleared; - set_state_rch(port, RCH_WAIT_FOR_MESSAGE_FROM_PROTOCOL_LAYER); - - tch[port].ctx = cleared; - set_state_tch(port, TCH_WAIT_FOR_MESSAGE_REQUEST_FROM_PE); - } - - prl_hr[port].ctx = cleared; - set_state_prl_hr(port, PRL_HR_WAIT_FOR_REQUEST); -} - -bool prl_is_busy(int port) -{ -#ifdef CONFIG_USB_PD_EXTENDED_MESSAGES - return rch_get_state(port) != - RCH_WAIT_FOR_MESSAGE_FROM_PROTOCOL_LAYER || - tch_get_state(port) != - TCH_WAIT_FOR_MESSAGE_REQUEST_FROM_PE; -#else - return false; -#endif /* CONFIG_USB_PD_EXTENDED_MESSAGES */ -} - -void prl_set_debug_level(enum debug_level debug_level) -{ -#ifndef CONFIG_USB_PD_DEBUG_LEVEL - prl_debug_level = debug_level; -#endif -} - -void prl_hard_reset_complete(int port) -{ - PRL_HR_SET_FLAG(port, PRL_FLAGS_HARD_RESET_COMPLETE); - task_wake(PD_PORT_TO_TASK_ID(port)); -} - -void prl_send_ctrl_msg(int port, - enum tcpci_msg_type type, - enum pd_ctrl_msg_type msg) -{ - pdmsg[port].xmit_type = type; - pdmsg[port].msg_type = msg; - pdmsg[port].data_objs = 0; - tx_emsg[port].len = 0; - -#ifdef CONFIG_USB_PD_EXTENDED_MESSAGES - pdmsg[port].ext = 0; - - TCH_SET_FLAG(port, PRL_FLAGS_MSG_XMIT); -#else - PRL_TX_SET_FLAG(port, PRL_FLAGS_MSG_XMIT); -#endif /* CONFIG_USB_PD_EXTENDED_MESSAGES */ - - task_wake(PD_PORT_TO_TASK_ID(port)); -} - -void prl_send_data_msg(int port, - enum tcpci_msg_type type, - enum pd_data_msg_type msg) -{ - pdmsg[port].xmit_type = type; - pdmsg[port].msg_type = msg; - -#ifdef CONFIG_USB_PD_EXTENDED_MESSAGES - pdmsg[port].ext = 0; - - TCH_SET_FLAG(port, PRL_FLAGS_MSG_XMIT); -#else - prl_copy_msg_to_buffer(port); - PRL_TX_SET_FLAG(port, PRL_FLAGS_MSG_XMIT); -#endif /* CONFIG_USB_PD_EXTENDED_MESSAGES */ - - task_wake(PD_PORT_TO_TASK_ID(port)); -} - -#ifdef CONFIG_USB_PD_EXTENDED_MESSAGES -void prl_send_ext_data_msg(int port, - enum tcpci_msg_type type, - enum pd_ext_msg_type msg) -{ - pdmsg[port].xmit_type = type; - pdmsg[port].msg_type = msg; - pdmsg[port].ext = 1; - - TCH_SET_FLAG(port, PRL_FLAGS_MSG_XMIT); - task_wake(PD_PORT_TO_TASK_ID(port)); -} -#endif /* CONFIG_USB_PD_EXTENDED_MESSAGES */ - -void prl_set_default_pd_revision(int port) -{ - /* - * Initialize to highest revision supported. If the port or cable - * partner doesn't support this revision, the Protocol Engine will - * lower this value to the revision supported by the partner. - */ - pdmsg[port].rev[TCPCI_MSG_SOP] = PD_REVISION; - pdmsg[port].rev[TCPCI_MSG_SOP_PRIME] = PD_REVISION; - pdmsg[port].rev[TCPCI_MSG_SOP_PRIME_PRIME] = PD_REVISION; - pdmsg[port].rev[TCPCI_MSG_SOP_DEBUG_PRIME] = PD_REVISION; - pdmsg[port].rev[TCPCI_MSG_SOP_DEBUG_PRIME_PRIME] = PD_REVISION; -} - -void prl_reset_soft(int port) -{ - /* Do not change negotiated PD Revision Specification level */ - local_state[port] = SM_INIT; - - /* Ensure we process the reset quickly */ - task_wake(PD_PORT_TO_TASK_ID(port)); -} - -void prl_run(int port, int evt, int en) -{ - switch (local_state[port]) { - case SM_PAUSED: - if (!en) - break; - /* fall through */ - case SM_INIT: - prl_init(port); - local_state[port] = SM_RUN; - /* fall through */ - case SM_RUN: - if (!en) { - /* Disable RX */ - if (IS_ENABLED(CONFIG_USB_CTVPD) || - IS_ENABLED(CONFIG_USB_VPD)) - vpd_rx_enable(0); - else - tcpm_set_rx_enable(port, 0); - - local_state[port] = SM_PAUSED; - break; - } - - /* Run Protocol Layer Hard Reset state machine */ - run_state(port, &prl_hr[port].ctx); - - /* - * If the Hard Reset state machine is active, then there is no - * need to execute any other PRL state machines. When the hard - * reset is complete, all PRL state machines will have been - * reset. - */ - if (prl_hr_get_state(port) == PRL_HR_WAIT_FOR_REQUEST) { - - /* Run Protocol Layer Message Reception */ - prl_rx_wait_for_phy_message(port, evt); - - - if (IS_ENABLED(CONFIG_USB_PD_EXTENDED_MESSAGES)) { - /* - * Run RX Chunked state machine after prl_rx. - * This is what informs the PE of incoming - * message. Its input is prl_rx - */ - run_state(port, &rch[port].ctx); - - /* - * Run TX Chunked state machine before prl_tx - * in case we need to split an extended message - * and prl_tx can send it for us - */ - run_state(port, &tch[port].ctx); - } - - /* Run Protocol Layer Message Tx state machine */ - run_state(port, &prl_tx[port].ctx); - - if (IS_ENABLED(CONFIG_USB_PD_EXTENDED_MESSAGES)) - /* - * Run TX Chunked state machine again after - * prl_tx so we can handle passing TX_COMPLETE - * (or failure) up to PE in a single iteration. - */ - run_state(port, &tch[port].ctx); - } - break; - } -} - -void prl_set_rev(int port, enum tcpci_msg_type type, - enum pd_rev_type rev) -{ - /* We only store revisions for SOP* types. */ - ASSERT(type < NUM_SOP_STAR_TYPES); - - pdmsg[port].rev[type] = rev; -} - -enum pd_rev_type prl_get_rev(int port, enum tcpci_msg_type type) -{ - /* We only store revisions for SOP* types. */ - ASSERT(type < NUM_SOP_STAR_TYPES); - - return pdmsg[port].rev[type]; -} - -static void prl_copy_msg_to_buffer(int port) -{ - /* - * Control Messages will have a length of 0 and - * no need to spend time with the tx_chk_buf - * for this path - */ - if (tx_emsg[port].len == 0) { - pdmsg[port].data_objs = 0; - return; - } - - /* - * Make sure the Policy Engine isn't sending - * more than CHK_BUF_SIZE_BYTES. If so, - * truncate len. This will surely send a - * malformed packet resulting in the port - * partner soft\hard resetting us. - */ - if (tx_emsg[port].len > CHK_BUF_SIZE_BYTES) - tx_emsg[port].len = CHK_BUF_SIZE_BYTES; - - /* Copy message to chunked buffer */ - memset((uint8_t *)pdmsg[port].tx_chk_buf, 0, CHK_BUF_SIZE_BYTES); - memcpy((uint8_t *)pdmsg[port].tx_chk_buf, (uint8_t *)tx_emsg[port].buf, - tx_emsg[port].len); - /* - * Pad length to 4-byte boundary and - * convert to number of 32-bit objects. - * Since the value is shifted right by 2, - * no need to explicitly clear the lower - * 2-bits. - */ - pdmsg[port].data_objs = (tx_emsg[port].len + 3) >> 2; -} - -static __maybe_unused int pdmsg_xmit_type_is_rev30(const int port) -{ - if (IS_ENABLED(CONFIG_USB_PD_REV30)) - return ((pdmsg[port].xmit_type < NUM_SOP_STAR_TYPES) - && (prl_get_rev(port, pdmsg[port].xmit_type) == PD_REV30)); - else - return 0; -} - -/* Returns true if the SOP port partner operates at PD rev3.0 */ -static bool is_sop_rev30(const int port) -{ - return IS_ENABLED(CONFIG_USB_PD_REV30) && - prl_get_rev(port, TCPCI_MSG_SOP) == PD_REV30; -} - -/* Common Protocol Layer Message Transmission */ -static void prl_tx_phy_layer_reset_entry(const int port) -{ - print_current_prl_tx_state(port); - - if (IS_ENABLED(CONFIG_USB_CTVPD) - || IS_ENABLED(CONFIG_USB_VPD)) { - vpd_rx_enable(pd_is_connected(port)); - } else { - /* Note: can't clear PHY messages due to TCPC architecture */ - /* Enable communications*/ - tcpm_set_rx_enable(port, pd_is_connected(port)); - } - set_state_prl_tx(port, PRL_TX_WAIT_FOR_MESSAGE_REQUEST); -} - -static void prl_tx_wait_for_message_request_entry(const int port) -{ - /* No phy layer response is pending */ - prl_tx[port].xmit_status = TCPC_TX_UNSET; - print_current_prl_tx_state(port); -} - -static void prl_tx_wait_for_message_request_run(const int port) -{ - /* Clear any AMS flags and state if we are no longer in an AMS */ - if (IS_ENABLED(CONFIG_USB_PD_REV30) && !pe_in_local_ams(port)) { - /* Note PRL_Tx_Src_Sink_Tx is embedded here. */ - if (PRL_TX_CHK_FLAG(port, PRL_FLAGS_SINK_NG)) { - typec_select_src_collision_rp(port, SINK_TX_OK); - typec_update_cc(port); - } - PRL_TX_CLR_FLAG(port, - PRL_FLAGS_SINK_NG | PRL_FLAGS_WAIT_SINK_OK); - } - - /* - * Check if we are starting an AMS and need to wait and/or set the CC - * lines appropriately. - */ - if (IS_ENABLED(CONFIG_USB_PD_REV30) && is_sop_rev30(port) && - pe_in_local_ams(port)) { - if (PRL_TX_CHK_FLAG(port, PRL_FLAGS_SINK_NG | - PRL_FLAGS_WAIT_SINK_OK)) { - /* - * If we are already in an AMS then allow the - * multi-message AMS to continue, even if we - * swap power roles. - * - * Fall Through using the current AMS - */ - } else { - /* - * Start of SRC AMS notification received from - * Policy Engine - */ - if (pd_get_power_role(port) == PD_ROLE_SOURCE) { - PRL_TX_SET_FLAG(port, PRL_FLAGS_SINK_NG); - set_state_prl_tx(port, PRL_TX_SRC_SOURCE_TX); - } else { - PRL_TX_SET_FLAG(port, PRL_FLAGS_WAIT_SINK_OK); - set_state_prl_tx(port, PRL_TX_SNK_START_AMS); - } - return; - } - } - - /* Handle non Rev 3.0 or subsequent messages in AMS sequence */ - if (PRL_TX_CHK_FLAG(port, PRL_FLAGS_MSG_XMIT)) { - PRL_TX_CLR_FLAG(port, PRL_FLAGS_MSG_XMIT); - /* - * Soft Reset Message Message pending - */ - if ((pdmsg[port].msg_type == PD_CTRL_SOFT_RESET) && - (tx_emsg[port].len == 0)) { - set_state_prl_tx(port, PRL_TX_LAYER_RESET_FOR_TRANSMIT); - } - /* - * Message pending (except Soft Reset) - */ - else { - /* NOTE: PRL_TX_Construct_Message State embedded here */ - prl_tx_construct_message(port); - set_state_prl_tx(port, PRL_TX_WAIT_FOR_PHY_RESPONSE); - } - - return; - } -} - -static void increment_msgid_counter(int port) -{ - /* If the last message wasn't an SOP* message, no need to increment */ - if (prl_tx[port].last_xmit_type >= NUM_SOP_STAR_TYPES) - return; - - prl_tx[port].msg_id_counter[prl_tx[port].last_xmit_type] = - (prl_tx[port].msg_id_counter[prl_tx[port].last_xmit_type] + 1) & - PD_MESSAGE_ID_COUNT; -} - -/* - * PrlTxDiscard - */ -static void prl_tx_discard_message_entry(const int port) -{ - print_current_prl_tx_state(port); - - /* - * Discard queued message - * Note: We differ from spec here, which allows us to not discard on - * incoming SOP' or SOP''. However this would get the TCH out of sync. - * - * prl_tx will be set to this state following message reception in - * prl_rx. So this path will be entered following each rx message. If - * this state is entered, and there is either a message from the PE - * pending, or if a message was passed to the phy and there is either no - * response yet, or it was discarded in the phy layer, then a tx message - * discard event has been detected. - */ - if (PRL_TX_CHK_FLAG(port, PRL_FLAGS_MSG_XMIT) || - prl_tx[port].xmit_status == TCPC_TX_WAIT || - prl_tx[port].xmit_status == TCPC_TX_COMPLETE_DISCARDED) { - PRL_TX_CLR_FLAG(port, PRL_FLAGS_MSG_XMIT); - increment_msgid_counter(port); - pe_report_discard(port); - } - - set_state_prl_tx(port, PRL_TX_PHY_LAYER_RESET); -} - -#ifdef CONFIG_USB_PD_REV30 -/* - * PrlTxSrcSourceTx - */ -static void prl_tx_src_source_tx_entry(const int port) -{ - print_current_prl_tx_state(port); - - /* Set Rp = SinkTxNG */ - typec_select_src_collision_rp(port, SINK_TX_NG); - typec_update_cc(port); -} - -static void prl_tx_src_source_tx_run(const int port) -{ - if (PRL_TX_CHK_FLAG(port, PRL_FLAGS_MSG_XMIT)) { - /* - * Don't clear pending XMIT flag here. Wait until we send so - * we can detect if we dropped this message or not. - */ - set_state_prl_tx(port, PRL_TX_SRC_PENDING); - } -} - -/* - * PrlTxSnkStartAms - */ -static void prl_tx_snk_start_ams_entry(const int port) -{ - print_current_prl_tx_state(port); -} - -static void prl_tx_snk_start_ams_run(const int port) -{ - if (PRL_TX_CHK_FLAG(port, PRL_FLAGS_MSG_XMIT)) { - /* - * Don't clear pending XMIT flag here. Wait until we send so - * we can detect if we dropped this message or not. - */ - set_state_prl_tx(port, PRL_TX_SNK_PENDING); - } -} -#endif /* CONFIG_USB_PD_REV30 */ - -/* - * PrlTxLayerResetForTransmit - */ -static void prl_tx_layer_reset_for_transmit_entry(const int port) -{ - print_current_prl_tx_state(port); - - if (pdmsg[port].xmit_type < NUM_SOP_STAR_TYPES) { - /* - * This state is only used during soft resets. Reset only the - * matching message type. - * - * From section 6.3.13 Soft Reset Message in the USB PD 3.0 - * v2.0 spec, Soft_Reset Message Shall be targeted at a - * specific entity depending on the type of SOP* Packet used. - */ - prl_tx[port].msg_id_counter[pdmsg[port].xmit_type] = 0; - - /* - * From section 6.11.2.3.2, the MessageID should be cleared - * from the PRL_Rx_Layer_Reset_for_Receive state. However, we - * don't implement a full state machine for PRL RX states so - * clear the MessageID here. - */ - prl_rx[port].msg_id[pdmsg[port].xmit_type] = -1; - } -} - -static void prl_tx_layer_reset_for_transmit_run(const int port) -{ - /* NOTE: PRL_Tx_Construct_Message State embedded here */ - prl_tx_construct_message(port); - set_state_prl_tx(port, PRL_TX_WAIT_FOR_PHY_RESPONSE); -} - -static uint32_t get_sop_star_header(const int port) -{ - const int is_sop_packet = pdmsg[port].xmit_type == TCPCI_MSG_SOP; - int ext; - -#ifdef CONFIG_USB_PD_EXTENDED_MESSAGES - ext = pdmsg[port].ext; -#else - ext = 0; -#endif - - /* SOP vs SOP'/SOP" headers are different. Replace fields as needed */ - return PD_HEADER( - pdmsg[port].msg_type, - is_sop_packet ? - pd_get_power_role(port) : tc_get_cable_plug(port), - is_sop_packet ? - pd_get_data_role(port) : 0, - prl_tx[port].msg_id_counter[pdmsg[port].xmit_type], - pdmsg[port].data_objs, - pdmsg[port].rev[pdmsg[port].xmit_type], - ext); -} - -static void prl_tx_construct_message(const int port) -{ - /* The header is unused for hard reset, etc. */ - const uint32_t header = pdmsg[port].xmit_type < NUM_SOP_STAR_TYPES ? - get_sop_star_header(port) : 0; - - /* Save SOP* so the correct msg_id_counter can be incremented */ - prl_tx[port].last_xmit_type = pdmsg[port].xmit_type; - - /* Indicate that a tx message is being passed to the phy layer */ - prl_tx[port].xmit_status = TCPC_TX_WAIT; - /* - * PRL_FLAGS_TX_COMPLETE could be set if this function is called before - * the Policy Engine is informed of the previous transmission. Clear the - * flag so that this message can be sent. - */ - PDMSG_CLR_FLAG(port, PRL_FLAGS_TX_COMPLETE); - - /* - * Pass message to PHY Layer. It handles retries in hardware as the EC - * cannot handle the required timing ~ 1ms (tReceive + tRetry). - * - * Note if we ever start sending large, extendend messages, then we - * should not retry those messages. We do not support that and probably - * never will (since we support chunking). - */ - tcpm_transmit(port, pdmsg[port].xmit_type, header, - pdmsg[port].tx_chk_buf); -} - -/* - * PrlTxWaitForPhyResponse - */ -static void prl_tx_wait_for_phy_response_entry(const int port) -{ - print_current_prl_tx_state(port); - - pd_timer_enable(port, PR_TIMER_TCPC_TX_TIMEOUT, PD_T_TCPC_TX_TIMEOUT); -} - -static void prl_tx_wait_for_phy_response_run(const int port) -{ - /* Wait until TX is complete */ - - /* - * NOTE: The TCPC will set xmit_status to TCPC_TX_COMPLETE_DISCARDED - * when a GoodCRC containing an incorrect MessageID is received. - * This condition satisfies the PRL_Tx_Match_MessageID state - * requirement. - */ - - if (prl_tx[port].xmit_status == TCPC_TX_COMPLETE_SUCCESS) { - /* NOTE: PRL_TX_Message_Sent State embedded here. */ - /* Increment messageId counter */ - increment_msgid_counter(port); - - /* Inform Policy Engine Message was sent */ - if (IS_ENABLED(CONFIG_USB_PD_EXTENDED_MESSAGES)) - PDMSG_SET_FLAG(port, PRL_FLAGS_TX_COMPLETE); - else - pe_message_sent(port); - - /* - * This event reduces the time of informing the policy engine of - * the transmission by one state machine cycle - */ - task_wake(PD_PORT_TO_TASK_ID(port)); - set_state_prl_tx(port, PRL_TX_WAIT_FOR_MESSAGE_REQUEST); - } else if (pd_timer_is_expired(port, PR_TIMER_TCPC_TX_TIMEOUT) || - prl_tx[port].xmit_status == TCPC_TX_COMPLETE_FAILED) { - /* - * NOTE: PRL_Tx_Transmission_Error State embedded - * here. - */ - - if (IS_ENABLED(CONFIG_USB_PD_EXTENDED_MESSAGES)) { - /* - * State tch_wait_for_transmission_complete will - * inform policy engine of error - */ - PDMSG_SET_FLAG(port, PRL_FLAGS_TX_ERROR); - } else { - /* Report Error To Policy Engine */ - pe_report_error(port, ERR_TCH_XMIT, - prl_tx[port].last_xmit_type); - } - - /* Increment message id counter */ - increment_msgid_counter(port); - set_state_prl_tx(port, PRL_TX_WAIT_FOR_MESSAGE_REQUEST); - } -} - -static void prl_tx_wait_for_phy_response_exit(const int port) -{ - pd_timer_disable(port, PR_TIMER_TCPC_TX_TIMEOUT); -} - -/* Source Protocol Layer Message Transmission */ -/* - * PrlTxSrcPending - */ -static void prl_tx_src_pending_entry(const int port) -{ - print_current_prl_tx_state(port); - - /* Start SinkTxTimer */ - pd_timer_enable(port, PR_TIMER_SINK_TX, PD_T_SINK_TX); -} - -static void prl_tx_src_pending_run(const int port) -{ - if (pd_timer_is_expired(port, PR_TIMER_SINK_TX)) { - /* - * We clear the pending XMIT flag here right before we send so - * we can detect if we discarded this message or not - */ - PRL_TX_CLR_FLAG(port, PRL_FLAGS_MSG_XMIT); - - /* - * Soft Reset Message pending & - * SinkTxTimer timeout - */ - if ((tx_emsg[port].len == 0) && - (pdmsg[port].msg_type == PD_CTRL_SOFT_RESET)) { - set_state_prl_tx(port, PRL_TX_LAYER_RESET_FOR_TRANSMIT); - } - /* Message pending (except Soft Reset) & - * SinkTxTimer timeout - */ - else { - prl_tx_construct_message(port); - set_state_prl_tx(port, PRL_TX_WAIT_FOR_PHY_RESPONSE); - } - - return; - } -} - -static void prl_tx_src_pending_exit(int port) -{ - pd_timer_disable(port, PR_TIMER_SINK_TX); -} - -/* - * PrlTxSnkPending - */ -static void prl_tx_snk_pending_entry(const int port) -{ - print_current_prl_tx_state(port); -} - -static void prl_tx_snk_pending_run(const int port) -{ - bool start_tx = false; - - /* - * Wait unit the SRC applies SINK_TX_OK so we can transmit. In FRS mode, - * don't wait for SINK_TX_OK since either the source (and Rp) could be - * gone or the TCPC CC_STATUS update time could be too long to meet - * tFRSwapInit. - */ - if (pe_in_frs_mode(port)) { - /* shortcut to save some i2c_xfer calls on the FRS path. */ - start_tx = true; - } else { - enum tcpc_cc_voltage_status cc1, cc2; - - tcpm_get_cc(port, &cc1, &cc2); - start_tx = (cc1 == TYPEC_CC_VOLT_RP_3_0 || - cc2 == TYPEC_CC_VOLT_RP_3_0); - } - if (start_tx) { - /* - * We clear the pending XMIT flag here right before we send so - * we can detect if we discarded this message or not - */ - PRL_TX_CLR_FLAG(port, PRL_FLAGS_MSG_XMIT); - - /* - * Soft Reset Message Message pending & - * Rp = SinkTxOk - */ - if ((pdmsg[port].msg_type == PD_CTRL_SOFT_RESET) && - (tx_emsg[port].len == 0)) { - set_state_prl_tx(port, PRL_TX_LAYER_RESET_FOR_TRANSMIT); - } - /* - * Message pending (except Soft Reset) & - * Rp = SinkTxOk - */ - else { - prl_tx_construct_message(port); - set_state_prl_tx(port, PRL_TX_WAIT_FOR_PHY_RESPONSE); - } - return; - } -} - -/* Hard Reset Operation */ -void prl_hr_send_msg_to_phy(const int port) -{ - /* Header is not used for hard reset */ - const uint32_t header = 0; - - pdmsg[port].xmit_type = TCPCI_MSG_TX_HARD_RESET; - - /* - * These flags could be set if this function is called before the - * Policy Engine is informed of the previous transmission. Clear the - * flags so that this message can be sent. - */ - prl_tx[port].xmit_status = TCPC_TX_UNSET; - PDMSG_CLR_FLAG(port, PRL_FLAGS_TX_COMPLETE); - - /* Pass message to PHY Layer */ - tcpm_transmit(port, pdmsg[port].xmit_type, header, - pdmsg[port].tx_chk_buf); -} - -static void prl_hr_wait_for_request_entry(const int port) -{ - print_current_prl_hr_state(port); - - prl_hr[port].flags = 0; -} - -static void prl_hr_wait_for_request_run(const int port) -{ - if (PRL_HR_CHK_FLAG(port, PRL_FLAGS_PE_HARD_RESET | - PRL_FLAGS_PORT_PARTNER_HARD_RESET)) - set_state_prl_hr(port, PRL_HR_RESET_LAYER); -} - -/* - * PrlHrResetLayer - */ -static void prl_hr_reset_layer_entry(const int port) -{ - int i; - - print_current_prl_hr_state(port); - - if (IS_ENABLED(CONFIG_USB_PD_EXTENDED_MESSAGES)) { - tch[port].flags = 0; - rch[port].flags = 0; - } - - pdmsg[port].flags = 0; - - /* Hard reset resets messageIDCounters for all TX types */ - for (i = 0; i < NUM_SOP_STAR_TYPES; i++) { - prl_rx[port].msg_id[i] = -1; - prl_tx[port].msg_id_counter[i] = 0; - } - - /* Disable RX */ - if (IS_ENABLED(CONFIG_USB_CTVPD) || - IS_ENABLED(CONFIG_USB_VPD)) - vpd_rx_enable(0); - else - tcpm_set_rx_enable(port, 0); - - /* - * PD r3.0 v2.0, ss6.2.1.1.5: - * After a physical or logical (USB Type-C Error Recovery) Attach, a - * Port discovers the common Specification Revision level between itself - * and its Port Partner and/or the Cable Plug(s), and uses this - * Specification Revision level until a Detach, Hard Reset or Error - * Recovery happens. - * - * This covers the Hard Reset case. - */ - prl_set_default_pd_revision(port); - - /* Inform the AP of Hard Reset */ - if (IS_ENABLED(CONFIG_USB_PD_HOST_CMD)) - pd_notify_event(port, PD_STATUS_EVENT_HARD_RESET); - - /* - * Protocol Layer message transmission transitions to - * PRL_Tx_Wait_For_Message_Request state. - */ - set_state_prl_tx(port, PRL_TX_WAIT_FOR_MESSAGE_REQUEST); - - return; -} - -static void prl_hr_reset_layer_run(const int port) -{ - /* - * Protocol Layer reset Complete & - * Hard Reset was initiated by Policy Engine - */ - if (PRL_HR_CHK_FLAG(port, PRL_FLAGS_PE_HARD_RESET)) { - /* - * Request PHY to perform a Hard Reset. Note - * PRL_HR_Request_Reset state is embedded here. - */ - prl_hr_send_msg_to_phy(port); - set_state_prl_hr(port, PRL_HR_WAIT_FOR_PHY_HARD_RESET_COMPLETE); - } - /* - * Protocol Layer reset complete & - * Hard Reset was initiated by Port Partner - */ - else { - /* Inform Policy Engine of the Hard Reset */ - pe_got_hard_reset(port); - set_state_prl_hr(port, PRL_HR_WAIT_FOR_PE_HARD_RESET_COMPLETE); - } -} - -/* - * PrlHrWaitForPhyHardResetComplete - */ -static void prl_hr_wait_for_phy_hard_reset_complete_entry(const int port) -{ - print_current_prl_hr_state(port); - - /* Start HardResetCompleteTimer */ - pd_timer_enable(port, PR_TIMER_HARD_RESET_COMPLETE, - PD_T_PS_HARD_RESET); -} - -static void prl_hr_wait_for_phy_hard_reset_complete_run(const int port) -{ - /* - * Wait for hard reset from PHY - * or timeout - */ - if (PDMSG_CHK_FLAG(port, PRL_FLAGS_TX_COMPLETE) || - pd_timer_is_expired(port, PR_TIMER_HARD_RESET_COMPLETE)) { - /* PRL_HR_PHY_Hard_Reset_Requested */ - - /* Inform Policy Engine Hard Reset was sent */ - pe_hard_reset_sent(port); - set_state_prl_hr(port, PRL_HR_WAIT_FOR_PE_HARD_RESET_COMPLETE); - - return; - } -} - -static void prl_hr_wait_for_phy_hard_reset_complete_exit(int port) -{ - pd_timer_disable(port, PR_TIMER_HARD_RESET_COMPLETE); -} - -/* - * PrlHrWaitForPeHardResetComplete - */ -static void prl_hr_wait_for_pe_hard_reset_complete_entry(const int port) -{ - print_current_prl_hr_state(port); -} - -static void prl_hr_wait_for_pe_hard_reset_complete_run(const int port) -{ - /* - * Wait for Hard Reset complete indication from Policy Engine - */ - if (PRL_HR_CHK_FLAG(port, PRL_FLAGS_HARD_RESET_COMPLETE)) - set_state_prl_hr(port, PRL_HR_WAIT_FOR_REQUEST); -} - -static void prl_hr_wait_for_pe_hard_reset_complete_exit(const int port) -{ - /* Exit from Hard Reset */ - - set_state_prl_tx(port, PRL_TX_PHY_LAYER_RESET); - if (IS_ENABLED(CONFIG_USB_PD_EXTENDED_MESSAGES)) { - set_state_rch(port, RCH_WAIT_FOR_MESSAGE_FROM_PROTOCOL_LAYER); - set_state_tch(port, TCH_WAIT_FOR_MESSAGE_REQUEST_FROM_PE); - } -} - -static void copy_chunk_to_ext(int port) -{ - /* Calculate number of bytes */ - pdmsg[port].num_bytes_received = - (PD_HEADER_CNT(rx_emsg[port].header) * 4); - - /* Copy chunk into extended message */ - memcpy((uint8_t *)rx_emsg[port].buf, (uint8_t *)pdmsg[port].rx_chk_buf, - pdmsg[port].num_bytes_received); - - /* Set extended message length */ - rx_emsg[port].len = pdmsg[port].num_bytes_received; -} - -#ifdef CONFIG_USB_PD_EXTENDED_MESSAGES -/* - * Chunked Rx State Machine - */ -/* - * RchWaitForMessageFromProtocolLayer - */ -static void rch_wait_for_message_from_protocol_layer_entry(const int port) -{ - print_current_rch_state(port); - - /* Clear Abort flag */ - PDMSG_CLR_FLAG(port, PRL_FLAGS_ABORT); - - /* All Messages are chunked */ - rch[port].flags = PRL_FLAGS_CHUNKING; -} - -static void rch_wait_for_message_from_protocol_layer_run(const int port) -{ - if (RCH_CHK_FLAG(port, PRL_FLAGS_MSG_RECEIVED)) { - RCH_CLR_FLAG(port, PRL_FLAGS_MSG_RECEIVED); - /* - * Are we communicating with a PD3.0 device and is - * this an extended message? - */ - if (pdmsg_xmit_type_is_rev30(port) - && PD_HEADER_EXT(rx_emsg[port].header)) { - uint16_t exhdr = - GET_EXT_HEADER(*pdmsg[port].rx_chk_buf); - uint8_t chunked = PD_EXT_HEADER_CHUNKED(exhdr); - - /* - * Received Extended Message & - * (Chunking = 1 & Chunked = 1) - */ - if ((RCH_CHK_FLAG(port, PRL_FLAGS_CHUNKING)) && - chunked) { - /* - * RCH_Processing_Extended_Message first chunk - * entry processing embedded here - * - * This is the first chunk: - * Set Chunk_number_expected = 0 and - * Num_Bytes_Received = 0 - */ - pdmsg[port].chunk_number_expected = 0; - pdmsg[port].num_bytes_received = 0; - pdmsg[port].msg_type = - PD_HEADER_TYPE(rx_emsg[port].header); - - set_state_rch(port, - RCH_PROCESSING_EXTENDED_MESSAGE); - } - /* - * (Received Extended Message & - * (Chunking = 0 & Chunked = 0)) - */ - else if (!RCH_CHK_FLAG(port, PRL_FLAGS_CHUNKING) && - !chunked) { - /* Copy chunk to extended buffer */ - copy_chunk_to_ext(port); - set_state_rch(port, RCH_PASS_UP_MESSAGE); - } - /* - * Chunked != Chunking - */ - else { - rch[port].error = ERR_RCH_CHUNKED; - set_state_rch(port, RCH_REPORT_ERROR); - } - } - /* - * Received Non-Extended Message - */ - else if (!PD_HEADER_EXT(rx_emsg[port].header)) { - /* Copy chunk to extended buffer */ - copy_chunk_to_ext(port); - set_state_rch(port, RCH_PASS_UP_MESSAGE); - } - /* - * Received an Extended Message while communicating at a - * revision lower than PD3.0 - */ - else { - rch[port].error = ERR_RCH_CHUNKED; - set_state_rch(port, RCH_REPORT_ERROR); - } - } -} - -/* - * RchPassUpMessage - */ -static void rch_pass_up_message_entry(const int port) -{ - print_current_rch_state(port); - - /* Pass Message to Policy Engine */ - pe_message_received(port); - set_state_rch(port, RCH_WAIT_FOR_MESSAGE_FROM_PROTOCOL_LAYER); -} - -/* - * RchProcessingExtendedMessage - */ -static void rch_processing_extended_message_entry(const int port) -{ - print_current_rch_state(port); -} - -static void rch_processing_extended_message_run(const int port) -{ - uint16_t exhdr = GET_EXT_HEADER(pdmsg[port].rx_chk_buf[0]); - uint8_t chunk_num = PD_EXT_HEADER_CHUNK_NUM(exhdr); - uint32_t data_size = PD_EXT_HEADER_DATA_SIZE(exhdr); - uint32_t byte_num; - - /* - * Abort Flag Set - */ - if (PDMSG_CHK_FLAG(port, PRL_FLAGS_ABORT)) - set_state_rch(port, RCH_WAIT_FOR_MESSAGE_FROM_PROTOCOL_LAYER); - - /* - * If expected Chunk Number: - * Append data to Extended_Message_Buffer - * Increment Chunk_number_Expected - * Adjust Num Bytes Received - */ - else if (chunk_num == pdmsg[port].chunk_number_expected) { - byte_num = data_size - pdmsg[port].num_bytes_received; - - if (byte_num >= PD_MAX_EXTENDED_MSG_CHUNK_LEN) - byte_num = PD_MAX_EXTENDED_MSG_CHUNK_LEN; - - /* Make sure extended message buffer does not overflow */ - if (pdmsg[port].num_bytes_received + - byte_num > EXTENDED_BUFFER_SIZE) { - rch[port].error = ERR_RCH_CHUNKED; - set_state_rch(port, RCH_REPORT_ERROR); - return; - } - - /* Append data */ - /* Add 2 to chk_buf to skip over extended message header */ - memcpy(((uint8_t *)rx_emsg[port].buf + - pdmsg[port].num_bytes_received), - (uint8_t *)pdmsg[port].rx_chk_buf + 2, - byte_num); - /* increment chunk number expected */ - pdmsg[port].chunk_number_expected++; - /* adjust num bytes received */ - pdmsg[port].num_bytes_received += byte_num; - - /* Was that the last chunk? */ - if (pdmsg[port].num_bytes_received >= data_size) { - rx_emsg[port].len = pdmsg[port].num_bytes_received; - /* Pass Message to Policy Engine */ - set_state_rch(port, RCH_PASS_UP_MESSAGE); - } - /* - * Message not Complete - */ - else - set_state_rch(port, RCH_REQUESTING_CHUNK); - } - /* - * Unexpected Chunk Number - */ - else { - rch[port].error = ERR_RCH_CHUNKED; - set_state_rch(port, RCH_REPORT_ERROR); - } -} - -/* - * RchRequestingChunk - */ -static void rch_requesting_chunk_entry(const int port) -{ - print_current_rch_state(port); - - /* - * Send Chunk Request to Protocol Layer - * with chunk number = Chunk_Number_Expected - */ - pdmsg[port].tx_chk_buf[0] = PD_EXT_HEADER( - pdmsg[port].chunk_number_expected, - 1, /* Request Chunk */ - 0 /* Data Size */ - ); - - pdmsg[port].data_objs = 1; - pdmsg[port].ext = 1; - pdmsg[port].xmit_type = prl_rx[port].sop; - PRL_TX_SET_FLAG(port, PRL_FLAGS_MSG_XMIT); - task_set_event(PD_PORT_TO_TASK_ID(port), PD_EVENT_TX); -} - -static void rch_requesting_chunk_run(const int port) -{ - /* - * Message Transmitted received from Protocol Layer - */ - if (PDMSG_CHK_FLAG(port, PRL_FLAGS_TX_COMPLETE)) { - PDMSG_CLR_FLAG(port, PRL_FLAGS_TX_COMPLETE); - set_state_rch(port, RCH_WAITING_CHUNK); - } else if (PDMSG_CHK_FLAG(port, PRL_FLAGS_TX_ERROR)) { - /* Transmission Error from Protocol Layer detetected */ - rch[port].error = ERR_RCH_CHUNKED; - set_state_rch(port, RCH_REPORT_ERROR); - } else if (RCH_CHK_FLAG(port, PRL_FLAGS_MSG_RECEIVED)) { - /* - * It is possible to have both message received and the chunk - * request transmit complete before a full PRL SM run. But, the - * PRL_RX state machine runs prior to RCH, but before PRL_TX, so - * PRL_FLAGS_MSG_RECEIVED can be set without - * PRL_FLAGS_TX_COMPLETE set at this point (though it will be - * set as soon as PRL_TX is executed next. - */ - set_state_rch(port, RCH_WAITING_CHUNK); - } -} - -/* - * RchWaitingChunk - */ -static void rch_waiting_chunk_entry(const int port) -{ - print_current_rch_state(port); - - /* - * Start ChunkSenderResponseTimer - */ - pd_timer_enable(port, PR_TIMER_CHUNK_SENDER_RESPONSE, - PD_T_CHUNK_SENDER_RESPONSE); -} - -static void rch_waiting_chunk_run(const int port) -{ - if (RCH_CHK_FLAG(port, PRL_FLAGS_MSG_RECEIVED)) { - /* - * Because of the 5 msec tick time, it is possible to have both - * msg_received and tx_complete flags set for a given PRL sm - * run. Since prl_rx runs prior to the tx state machines, clear - * the tx_complete flag as the next chunk has already been - * received. - */ - if (PDMSG_CHK_FLAG(port, PRL_FLAGS_TX_COMPLETE)) - PDMSG_CLR_FLAG(port, PRL_FLAGS_TX_COMPLETE); - - /* - * Leave PRL_FLAGS_MSG_RECEIVED flag set just in case an error - * is detected. If an error is detected, PRL_FLAGS_MSG_RECEIVED - * will be cleared in rch_report_error state. - */ - - if (PD_HEADER_EXT(rx_emsg[port].header)) { - uint16_t exhdr = - GET_EXT_HEADER(pdmsg[port].rx_chk_buf[0]); - /* - * Other Message Received from Protocol Layer - */ - if (PD_EXT_HEADER_REQ_CHUNK(exhdr) || - !PD_EXT_HEADER_CHUNKED(exhdr)) { - rch[port].error = ERR_RCH_CHUNKED; - set_state_rch(port, RCH_REPORT_ERROR); - } - /* - * Chunk response Received from Protocol Layer - */ - else { - /* - * No error was detected, so clear - * PRL_FLAGS_MSG_RECEIVED flag. - */ - RCH_CLR_FLAG(port, PRL_FLAGS_MSG_RECEIVED); - set_state_rch(port, - RCH_PROCESSING_EXTENDED_MESSAGE); - } - } - } - /* - * ChunkSenderResponseTimer Timeout - */ - else if (pd_timer_is_expired(port, PR_TIMER_CHUNK_SENDER_RESPONSE)) { - rch[port].error = ERR_RCH_CHUNK_WAIT_TIMEOUT; - set_state_rch(port, RCH_REPORT_ERROR); - } -} - -static void rch_waiting_chunk_exit(int port) -{ - pd_timer_disable(port, PR_TIMER_CHUNK_SENDER_RESPONSE); -} - -/* - * RchReportError - */ -static void rch_report_error_entry(const int port) -{ - print_current_rch_state(port); - - /* - * If the state was entered because a message was received, - * this message is passed to the Policy Engine. - */ - if (RCH_CHK_FLAG(port, PRL_FLAGS_MSG_RECEIVED)) { - RCH_CLR_FLAG(port, PRL_FLAGS_MSG_RECEIVED); - - /* Copy chunk to extended buffer */ - copy_chunk_to_ext(port); - /* Pass Message to Policy Engine */ - pe_message_received(port); - /* Report error */ - pe_report_error(port, ERR_RCH_MSG_REC, prl_rx[port].sop); - } else { - pe_report_error(port, rch[port].error, prl_rx[port].sop); - } -} - -static void rch_report_error_run(const int port) -{ - set_state_rch(port, RCH_WAIT_FOR_MESSAGE_FROM_PROTOCOL_LAYER); -} - -/* - * Chunked Tx State Machine - */ - -/* - * TchWaitForMessageRequestFromPe - */ -static void tch_wait_for_message_request_from_pe_entry(const int port) -{ - print_current_tch_state(port); - - /* Clear Abort flag */ - PDMSG_CLR_FLAG(port, PRL_FLAGS_ABORT); - - /* All Messages are chunked */ - tch[port].flags = PRL_FLAGS_CHUNKING; -} - -static void tch_wait_for_message_request_from_pe_run(const int port) -{ - /* - * Any message received and not in state TCH_Wait_Chunk_Request - */ - if (TCH_CHK_FLAG(port, PRL_FLAGS_MSG_RECEIVED)) { - TCH_CLR_FLAG(port, PRL_FLAGS_MSG_RECEIVED); - set_state_tch(port, TCH_MESSAGE_RECEIVED); - } else if (TCH_CHK_FLAG(port, PRL_FLAGS_MSG_XMIT)) { - TCH_CLR_FLAG(port, PRL_FLAGS_MSG_XMIT); - /* - * Rx Chunking State != RCH_Wait_For_Message_From_Protocol_Layer - * & Abort Supported - * - * Discard the Message - */ - if (rch_get_state(port) != - RCH_WAIT_FOR_MESSAGE_FROM_PROTOCOL_LAYER) { - tch[port].error = ERR_TCH_XMIT; - set_state_tch(port, TCH_REPORT_ERROR); - } else { - /* - * Extended Message Request & Chunking - */ - if (pdmsg_xmit_type_is_rev30(port) - && pdmsg[port].ext - && TCH_CHK_FLAG(port, PRL_FLAGS_CHUNKING)) { - /* - * NOTE: TCH_Prepare_To_Send_Chunked_Message - * embedded here. - */ - pdmsg[port].send_offset = 0; - pdmsg[port].chunk_number_to_send = 0; - set_state_tch(port, - TCH_CONSTRUCT_CHUNKED_MESSAGE); - } else - /* - * Non-Extended Message Request - */ - { - /* NOTE: TCH_Pass_Down_Message embedded here */ - prl_copy_msg_to_buffer(port); - - /* Pass Message to Protocol Layer */ - PRL_TX_SET_FLAG(port, PRL_FLAGS_MSG_XMIT); - set_state_tch(port, - TCH_WAIT_FOR_TRANSMISSION_COMPLETE); - } - } - } -} - -/* - * TchWaitForTransmissionComplete - */ -static void tch_wait_for_transmission_complete_entry(const int port) -{ - print_current_tch_state(port); -} - -static void tch_wait_for_transmission_complete_run(const int port) -{ - /* - * Inform Policy Engine that Message was sent. - */ - if (PDMSG_CHK_FLAG(port, PRL_FLAGS_TX_COMPLETE)) { - PDMSG_CLR_FLAG(port, PRL_FLAGS_TX_COMPLETE); - set_state_tch(port, TCH_MESSAGE_SENT); - return; - } - /* - * Inform Policy Engine of Tx Error - */ - else if (PDMSG_CHK_FLAG(port, PRL_FLAGS_TX_ERROR)) { - PDMSG_CLR_FLAG(port, PRL_FLAGS_TX_ERROR); - tch[port].error = ERR_TCH_XMIT; - set_state_tch(port, TCH_REPORT_ERROR); - return; - } - /* - * A message was received while TCH is waiting for the phy to complete - * sending a tx message. - * - * Because of our prl_sm architecture and I2C access delays for TCPCs, - * it's possible to have a message received and the prl_tx state not be - * in its default waiting state. To avoid a false protocol error, only - * jump to TCH_MESSAGE_RECEIVED if the phy layer has not indicated that - * the tx message was sent successfully. - */ - if (TCH_CHK_FLAG(port, PRL_FLAGS_MSG_RECEIVED) && - prl_tx[port].xmit_status != TCPC_TX_COMPLETE_SUCCESS) { - TCH_CLR_FLAG(port, PRL_FLAGS_MSG_RECEIVED); - set_state_tch(port, TCH_MESSAGE_RECEIVED); - return; - } -} - -/* - * TchConstructChunkedMessage - */ -static void tch_construct_chunked_message_entry(const int port) -{ - uint16_t *ext_hdr; - uint8_t *data; - uint16_t num; - - print_current_tch_state(port); - - /* - * Any message received and not in state TCH_Wait_Chunk_Request - */ - if (TCH_CHK_FLAG(port, PRL_FLAGS_MSG_RECEIVED)) { - TCH_CLR_FLAG(port, PRL_FLAGS_MSG_RECEIVED); - set_state_tch(port, TCH_MESSAGE_RECEIVED); - return; - } - - /* Prepare to copy chunk into chk_buf */ - - ext_hdr = (uint16_t *)pdmsg[port].tx_chk_buf; - data = ((uint8_t *)pdmsg[port].tx_chk_buf + 2); - num = tx_emsg[port].len - pdmsg[port].send_offset; - - if (num > PD_MAX_EXTENDED_MSG_CHUNK_LEN) - num = PD_MAX_EXTENDED_MSG_CHUNK_LEN; - - /* Set the chunks extended header */ - *ext_hdr = PD_EXT_HEADER(pdmsg[port].chunk_number_to_send, - 0, /* Chunk Request */ - tx_emsg[port].len); - - /* Copy the message chunk into chk_buf */ - memset(data, 0, 28); - memcpy(data, tx_emsg[port].buf + pdmsg[port].send_offset, num); - pdmsg[port].send_offset += num; - - /* - * Add in 2 bytes for extended header - * pad out to 4-byte boundary - * convert to number of 4-byte words - * Since the value is shifted right by 2, - * no need to explicitly clear the lower - * 2-bits. - */ - pdmsg[port].data_objs = (num + 2 + 3) >> 2; - - /* Pass message chunk to Protocol Layer */ - PRL_TX_SET_FLAG(port, PRL_FLAGS_MSG_XMIT); -} - -static void tch_construct_chunked_message_run(const int port) -{ - if (PDMSG_CHK_FLAG(port, PRL_FLAGS_ABORT)) - set_state_tch(port, TCH_WAIT_FOR_MESSAGE_REQUEST_FROM_PE); - else - set_state_tch(port, TCH_SENDING_CHUNKED_MESSAGE); -} - -/* - * TchSendingChunkedMessage - */ -static void tch_sending_chunked_message_entry(const int port) -{ - print_current_tch_state(port); -} - -static void tch_sending_chunked_message_run(const int port) -{ - /* - * Transmission Error - */ - if (PDMSG_CHK_FLAG(port, PRL_FLAGS_TX_ERROR)) { - tch[port].error = ERR_TCH_XMIT; - set_state_tch(port, TCH_REPORT_ERROR); - } - /* - * Message Transmitted from Protocol Layer & - * Last Chunk - */ - else if (tx_emsg[port].len == pdmsg[port].send_offset) - set_state_tch(port, TCH_MESSAGE_SENT); - /* - * Any message received and not in state TCH_Wait_Chunk_Request - */ - else if (TCH_CHK_FLAG(port, PRL_FLAGS_MSG_RECEIVED)) { - TCH_CLR_FLAG(port, PRL_FLAGS_MSG_RECEIVED); - set_state_tch(port, TCH_MESSAGE_RECEIVED); - } - /* - * Message Transmitted from Protocol Layer & - * Not Last Chunk - */ - else - set_state_tch(port, TCH_WAIT_CHUNK_REQUEST); -} - -/* - * TchWaitChunkRequest - */ -static void tch_wait_chunk_request_entry(const int port) -{ - print_current_tch_state(port); - - /* Increment Chunk Number to Send */ - pdmsg[port].chunk_number_to_send++; - /* Start Chunk Sender Request Timer */ - pd_timer_enable(port, PR_TIMER_CHUNK_SENDER_REQUEST, - PD_T_CHUNK_SENDER_REQUEST); -} - -static void tch_wait_chunk_request_run(const int port) -{ - if (TCH_CHK_FLAG(port, PRL_FLAGS_MSG_RECEIVED)) { - TCH_CLR_FLAG(port, PRL_FLAGS_MSG_RECEIVED); - - if (PD_HEADER_EXT(rx_emsg[port].header)) { - uint16_t exthdr; - - exthdr = GET_EXT_HEADER(pdmsg[port].rx_chk_buf[0]); - if (PD_EXT_HEADER_REQ_CHUNK(exthdr)) { - /* - * Chunk Request Received & - * Chunk Number = Chunk Number to Send - */ - if (PD_EXT_HEADER_CHUNK_NUM(exthdr) == - pdmsg[port].chunk_number_to_send) { - set_state_tch(port, - TCH_CONSTRUCT_CHUNKED_MESSAGE); - } - /* - * Chunk Request Received & - * Chunk Number != Chunk Number to Send - */ - else { - tch[port].error = ERR_TCH_CHUNKED; - set_state_tch(port, TCH_REPORT_ERROR); - } - return; - } - } - - /* - * Other message received - */ - set_state_tch(port, TCH_MESSAGE_RECEIVED); - } - /* - * ChunkSenderRequestTimer timeout - */ - else if (pd_timer_is_expired(port, PR_TIMER_CHUNK_SENDER_REQUEST)) - set_state_tch(port, TCH_MESSAGE_SENT); -} - -static void tch_wait_chunk_request_exit(int port) -{ - pd_timer_disable(port, PR_TIMER_CHUNK_SENDER_REQUEST); -} - -/* - * TchMessageReceived - */ -static void tch_message_received_entry(const int port) -{ - print_current_tch_state(port); - - /* Pass message to chunked Rx */ - RCH_SET_FLAG(port, PRL_FLAGS_MSG_RECEIVED); - - /* Clear extended message objects */ - if (TCH_CHK_FLAG(port, PRL_FLAGS_MSG_XMIT)) { - TCH_CLR_FLAG(port, PRL_FLAGS_MSG_XMIT); - pe_report_discard(port); - } - pdmsg[port].data_objs = 0; -} - -static void tch_message_received_run(const int port) -{ - set_state_tch(port, TCH_WAIT_FOR_MESSAGE_REQUEST_FROM_PE); -} - -/* - * TchMessageSent - */ -static void tch_message_sent_entry(const int port) -{ - print_current_tch_state(port); - - /* Tell PE message was sent */ - pe_message_sent(port); - - /* - * Any message received and not in state TCH_Wait_Chunk_Request - * MUST be checked after notifying PE - */ - if (TCH_CHK_FLAG(port, PRL_FLAGS_MSG_RECEIVED)) { - TCH_CLR_FLAG(port, PRL_FLAGS_MSG_RECEIVED); - set_state_tch(port, TCH_MESSAGE_RECEIVED); - return; - } - - - - set_state_tch(port, TCH_WAIT_FOR_MESSAGE_REQUEST_FROM_PE); -} - -/* - * TchReportError - */ -static void tch_report_error_entry(const int port) -{ - print_current_tch_state(port); - - /* Report Error To Policy Engine */ - pe_report_error(port, tch[port].error, prl_tx[port].last_xmit_type); - - /* - * Any message received and not in state TCH_Wait_Chunk_Request - * MUST be checked after notifying PE - */ - if (TCH_CHK_FLAG(port, PRL_FLAGS_MSG_RECEIVED)) { - TCH_CLR_FLAG(port, PRL_FLAGS_MSG_RECEIVED); - set_state_tch(port, TCH_MESSAGE_RECEIVED); - return; - } - - - set_state_tch(port, TCH_WAIT_FOR_MESSAGE_REQUEST_FROM_PE); -} -#endif /* CONFIG_USB_PD_EXTENDED_MESSAGES */ - -/* - * Protocol Layer Message Reception State Machine - */ -static void prl_rx_wait_for_phy_message(const int port, int evt) -{ - uint32_t header; - uint8_t type; - uint8_t cnt; - int8_t msid; - - /* - * If PD3, wait for the RX chunk SM to copy the pdmsg into the extended - * buffer before overwriting pdmsg. - */ - if (IS_ENABLED(CONFIG_USB_PD_EXTENDED_MESSAGES) && - RCH_CHK_FLAG(port, PRL_FLAGS_MSG_RECEIVED)) - return; - - /* If we don't have any message, just stop processing now. */ - if (!tcpm_has_pending_message(port) || - tcpm_dequeue_message(port, pdmsg[port].rx_chk_buf, &header)) - return; - - rx_emsg[port].header = header; - type = PD_HEADER_TYPE(header); - cnt = PD_HEADER_CNT(header); - msid = PD_HEADER_ID(header); - prl_rx[port].sop = PD_HEADER_GET_SOP(header); - - /* Make sure an incorrect count doesn't overflow the chunk buffer */ - if (cnt > CHK_BUF_SIZE) - cnt = CHK_BUF_SIZE; - - /* dump received packet content (only dump ping at debug level MAX) */ - if ((prl_debug_level >= DEBUG_LEVEL_2 && type != PD_CTRL_PING) || - prl_debug_level >= DEBUG_LEVEL_3) { - int p; - - ccprintf("C%d: RECV %04x/%d ", port, header, cnt); - for (p = 0; p < cnt; p++) - ccprintf("[%d]%08x ", p, pdmsg[port].rx_chk_buf[p]); - ccprintf("\n"); - } - - /* - * Ignore messages sent to the cable from our - * port partner if we aren't Vconn powered device. - */ - if (!IS_ENABLED(CONFIG_USB_CTVPD) && - !IS_ENABLED(CONFIG_USB_VPD) && - PD_HEADER_GET_SOP(header) != TCPCI_MSG_SOP && - PD_HEADER_PROLE(header) == PD_PLUG_FROM_DFP_UFP) - return; - - /* Handle incoming soft reset as special case */ - if (cnt == 0 && type == PD_CTRL_SOFT_RESET) { - /* Clear MessageIdCounter */ - prl_tx[port].msg_id_counter[prl_rx[port].sop] = 0; - /* Clear stored MessageID value */ - prl_rx[port].msg_id[prl_rx[port].sop] = -1; - - /* Soft Reset occurred */ - set_state_prl_tx(port, PRL_TX_PHY_LAYER_RESET); - - if (IS_ENABLED(CONFIG_USB_PD_EXTENDED_MESSAGES)) { - set_state_rch(port, - RCH_WAIT_FOR_MESSAGE_FROM_PROTOCOL_LAYER); - set_state_tch(port, - TCH_WAIT_FOR_MESSAGE_REQUEST_FROM_PE); - } - - /* - * Inform Policy Engine of Soft Reset. Note perform this after - * performing the protocol layer reset, otherwise we will lose - * the PE's outgoing ACCEPT message to the soft reset. - */ - pe_got_soft_reset(port); - - return; - } - - /* - * Ignore if this is a duplicate message. Stop processing. - */ - if (prl_rx[port].msg_id[prl_rx[port].sop] == msid) - return; - - /* - * Discard any pending tx message if this is - * not a ping message (length must be checked to verify this is a - * control message, rather than data) - */ - if ((cnt > 0) || (type != PD_CTRL_PING)) { - /* - * Note: Spec dictates that we always go into - * PRL_Tx_Discard_Message upon receivng a message. However, due - * to our TCPC architecture we may be receiving a transmit - * complete at the same time as a response so only do this if a - * message is pending. - */ - if (prl_tx[port].xmit_status != TCPC_TX_COMPLETE_SUCCESS || - PRL_TX_CHK_FLAG(port, PRL_FLAGS_MSG_XMIT)) - set_state_prl_tx(port, PRL_TX_DISCARD_MESSAGE); - } - - /* Store Message Id */ - prl_rx[port].msg_id[prl_rx[port].sop] = msid; - - if (IS_ENABLED(CONFIG_USB_PD_EXTENDED_MESSAGES)) { - /* RTR Chunked Message Router States. */ - /* - * Received Ping from Protocol Layer - */ - if (cnt == 0 && type == PD_CTRL_PING) { - /* NOTE: RTR_PING State embedded here. */ - rx_emsg[port].len = 0; - pe_message_received(port); - return; - } - /* - * Message (not Ping) Received from - * Protocol Layer & Doing Tx Chunks - * - * Also, handle the case where a message has been - * queued for sending but a message is received before - * tch_wait_for_message_request_from_pe has been run - */ - else if (tch_get_state(port) != - TCH_WAIT_FOR_MESSAGE_REQUEST_FROM_PE || - TCH_CHK_FLAG(port, PRL_FLAGS_MSG_XMIT)) { - /* NOTE: RTR_TX_CHUNKS State embedded here. */ - /* - * Send Message to Tx Chunk - * Chunk State Machine - */ - TCH_SET_FLAG(port, PRL_FLAGS_MSG_RECEIVED); - } - /* - * Message (not Ping) Received from - * Protocol Layer & Not Doing Tx Chunks - */ - else { - /* NOTE: RTR_RX_CHUNKS State embedded here. */ - /* - * Send Message to Rx - * Chunk State Machine - */ - RCH_SET_FLAG(port, PRL_FLAGS_MSG_RECEIVED); - } - } else { - /* Copy chunk to extended buffer */ - copy_chunk_to_ext(port); - /* Send message to Policy Engine */ - pe_message_received(port); - } - - task_wake(PD_PORT_TO_TASK_ID(port)); -} - -/* All necessary Protocol Transmit States (Section 6.11.2.2) */ -static __const_data const struct usb_state prl_tx_states[] = { - [PRL_TX_PHY_LAYER_RESET] = { - .entry = prl_tx_phy_layer_reset_entry, - }, - [PRL_TX_WAIT_FOR_MESSAGE_REQUEST] = { - .entry = prl_tx_wait_for_message_request_entry, - .run = prl_tx_wait_for_message_request_run, - }, - [PRL_TX_LAYER_RESET_FOR_TRANSMIT] = { - .entry = prl_tx_layer_reset_for_transmit_entry, - .run = prl_tx_layer_reset_for_transmit_run, - }, - [PRL_TX_WAIT_FOR_PHY_RESPONSE] = { - .entry = prl_tx_wait_for_phy_response_entry, - .run = prl_tx_wait_for_phy_response_run, - .exit = prl_tx_wait_for_phy_response_exit, - }, -#ifdef CONFIG_USB_PD_REV30 - [PRL_TX_SRC_SOURCE_TX] = { - .entry = prl_tx_src_source_tx_entry, - .run = prl_tx_src_source_tx_run, - }, - [PRL_TX_SNK_START_AMS] = { - .entry = prl_tx_snk_start_ams_entry, - .run = prl_tx_snk_start_ams_run, - }, -#endif /* CONFIG_USB_PD_REV30 */ - [PRL_TX_SRC_PENDING] = { - .entry = prl_tx_src_pending_entry, - .run = prl_tx_src_pending_run, - .exit = prl_tx_src_pending_exit, - }, - [PRL_TX_SNK_PENDING] = { - .entry = prl_tx_snk_pending_entry, - .run = prl_tx_snk_pending_run, - }, - [PRL_TX_DISCARD_MESSAGE] = { - .entry = prl_tx_discard_message_entry, - }, -}; - -/* All necessary Protocol Hard Reset States (Section 6.11.2.4) */ -static __const_data const struct usb_state prl_hr_states[] = { - [PRL_HR_WAIT_FOR_REQUEST] = { - .entry = prl_hr_wait_for_request_entry, - .run = prl_hr_wait_for_request_run, - }, - [PRL_HR_RESET_LAYER] = { - .entry = prl_hr_reset_layer_entry, - .run = prl_hr_reset_layer_run, - }, - [PRL_HR_WAIT_FOR_PHY_HARD_RESET_COMPLETE] = { - .entry = prl_hr_wait_for_phy_hard_reset_complete_entry, - .run = prl_hr_wait_for_phy_hard_reset_complete_run, - .exit = prl_hr_wait_for_phy_hard_reset_complete_exit, - }, - [PRL_HR_WAIT_FOR_PE_HARD_RESET_COMPLETE] = { - .entry = prl_hr_wait_for_pe_hard_reset_complete_entry, - .run = prl_hr_wait_for_pe_hard_reset_complete_run, - .exit = prl_hr_wait_for_pe_hard_reset_complete_exit, - }, -}; - -/* All necessary Chunked Rx states (Section 6.11.2.1.2) */ -__maybe_unused static const struct usb_state rch_states[] = { -#ifdef CONFIG_USB_PD_EXTENDED_MESSAGES - [RCH_WAIT_FOR_MESSAGE_FROM_PROTOCOL_LAYER] = { - .entry = rch_wait_for_message_from_protocol_layer_entry, - .run = rch_wait_for_message_from_protocol_layer_run, - }, - [RCH_PASS_UP_MESSAGE] = { - .entry = rch_pass_up_message_entry, - }, - [RCH_PROCESSING_EXTENDED_MESSAGE] = { - .entry = rch_processing_extended_message_entry, - .run = rch_processing_extended_message_run, - }, - [RCH_REQUESTING_CHUNK] = { - .entry = rch_requesting_chunk_entry, - .run = rch_requesting_chunk_run, - }, - [RCH_WAITING_CHUNK] = { - .entry = rch_waiting_chunk_entry, - .run = rch_waiting_chunk_run, - .exit = rch_waiting_chunk_exit, - }, - [RCH_REPORT_ERROR] = { - .entry = rch_report_error_entry, - .run = rch_report_error_run, - }, -#endif /* CONFIG_USB_PD_EXTENDED_MESSAGES */ -}; - -/* All necessary Chunked Tx states (Section 6.11.2.1.3) */ -__maybe_unused static const struct usb_state tch_states[] = { -#ifdef CONFIG_USB_PD_EXTENDED_MESSAGES - [TCH_WAIT_FOR_MESSAGE_REQUEST_FROM_PE] = { - .entry = tch_wait_for_message_request_from_pe_entry, - .run = tch_wait_for_message_request_from_pe_run, - }, - [TCH_WAIT_FOR_TRANSMISSION_COMPLETE] = { - .entry = tch_wait_for_transmission_complete_entry, - .run = tch_wait_for_transmission_complete_run, - }, - [TCH_CONSTRUCT_CHUNKED_MESSAGE] = { - .entry = tch_construct_chunked_message_entry, - .run = tch_construct_chunked_message_run, - }, - [TCH_SENDING_CHUNKED_MESSAGE] = { - .entry = tch_sending_chunked_message_entry, - .run = tch_sending_chunked_message_run, - }, - [TCH_WAIT_CHUNK_REQUEST] = { - .entry = tch_wait_chunk_request_entry, - .run = tch_wait_chunk_request_run, - .exit = tch_wait_chunk_request_exit, - }, - [TCH_MESSAGE_RECEIVED] = { - .entry = tch_message_received_entry, - .run = tch_message_received_run, - }, - [TCH_MESSAGE_SENT] = { - .entry = tch_message_sent_entry, - }, - [TCH_REPORT_ERROR] = { - .entry = tch_report_error_entry, - }, -#endif /* CONFIG_USB_PD_EXTENDED_MESSAGES */ -}; - -#ifdef TEST_BUILD - -const struct test_sm_data test_prl_sm_data[] = { - { - .base = prl_tx_states, - .size = ARRAY_SIZE(prl_tx_states), - .names = prl_tx_state_names, - .names_size = ARRAY_SIZE(prl_tx_state_names), - }, - { - .base = prl_hr_states, - .size = ARRAY_SIZE(prl_hr_states), - .names = prl_hr_state_names, - .names_size = ARRAY_SIZE(prl_hr_state_names), - }, -#ifdef CONFIG_USB_PD_EXTENDED_MESSAGES - { - .base = rch_states, - .size = ARRAY_SIZE(rch_states), - .names = rch_state_names, - .names_size = ARRAY_SIZE(rch_state_names), - }, - { - .base = tch_states, - .size = ARRAY_SIZE(tch_states), - .names = tch_state_names, - .names_size = ARRAY_SIZE(tch_state_names), - }, -#endif /* CONFIG_USB_PD_EXTENDED_MESSAGES */ -}; -BUILD_ASSERT(ARRAY_SIZE(prl_tx_states) == ARRAY_SIZE(prl_tx_state_names)); -BUILD_ASSERT(ARRAY_SIZE(prl_hr_states) == ARRAY_SIZE(prl_hr_state_names)); -#ifdef CONFIG_USB_PD_EXTENDED_MESSAGES -BUILD_ASSERT(ARRAY_SIZE(rch_states) == ARRAY_SIZE(rch_state_names)); -BUILD_ASSERT(ARRAY_SIZE(tch_states) == ARRAY_SIZE(tch_state_names)); -#endif /* CONFIG_USB_PD_EXTENDED_MESSAGES */ -const int test_prl_sm_data_size = ARRAY_SIZE(test_prl_sm_data); -#endif |