summaryrefslogtreecommitdiff
path: root/common
diff options
context:
space:
mode:
authorSam Hurst <shurst@google.com>2019-05-22 14:13:40 -0700
committerCommit Bot <commit-bot@chromium.org>2019-06-05 21:43:03 +0000
commitd76c396bf65e912c2aa2ca1e905daa74996cdb27 (patch)
treec34654adeebeb793d548215c2eaf6f4f4ba3bdfe /common
parent184701a33a0f77dfbe38d231d05741db1f8ddbc6 (diff)
downloadchrome-ec-d76c396bf65e912c2aa2ca1e905daa74996cdb27.tar.gz
chocodile_vpdmcu: Firmware refactoring
Move code in header files into c source files. BUG=b:133341676 BRANCH=none TEST=manual Charge-Through was tested on an Atlas running a DRP USB-C/PD state machine with CTUnattached.SNK and CTAttached.SNK states. Change-Id: Ib1b51a778b937e02908f0bc8866bc91a39831163 Signed-off-by: Sam Hurst <shurst@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/1626036 Reviewed-by: Jett Rink <jettrink@chromium.org> Commit-Queue: Sam Hurst <shurst@google.com> Tested-by: Sam Hurst <shurst@google.com>
Diffstat (limited to 'common')
-rw-r--r--common/build.mk7
-rw-r--r--common/usb_pe_ctvpd_sm.c207
-rw-r--r--common/usb_pe_sm.c12
-rw-r--r--common/usb_prl_sm.c307
-rw-r--r--common/usb_sm.c11
-rw-r--r--common/usb_tc_ctvpd_sm.c1736
-rw-r--r--common/usb_tc_sm.c43
-rw-r--r--common/usb_tc_vpd_sm.c358
8 files changed, 2357 insertions, 324 deletions
diff --git a/common/build.mk b/common/build.mk
index 3faeaae6e4..19dcbd98af 100644
--- a/common/build.mk
+++ b/common/build.mk
@@ -138,7 +138,12 @@ else
common-$(CONFIG_USB_SM_FRAMEWORK)+=usb_sm.o
common-$(CONFIG_USB_TYPEC_SM)+=usb_tc_sm.o
common-$(CONFIG_USB_PRL_SM)+=usb_prl_sm.o
-common-$(CONFIG_USB_PE_SM)+=usb_pe_sm.o
+ifneq ($(CONFIG_USB_PE_SM),)
+common-$(CONFIG_USB_TYPEC_VPD)+=usb_pe_ctvpd_sm.o
+common-$(CONFIG_USB_TYPEC_CTVPD)+=usb_pe_ctvpd_sm.o
+endif
+common-$(CONFIG_USB_TYPEC_VPD)+=usb_tc_vpd_sm.o
+common-$(CONFIG_USB_TYPEC_CTVPD)+=usb_tc_ctvpd_sm.o
endif
common-$(CONFIG_USB_PD_LOGGING)+=event_log.o pd_log.o
common-$(CONFIG_USB_PD_TCPC)+=usb_pd_tcpc.o
diff --git a/common/usb_pe_ctvpd_sm.c b/common/usb_pe_ctvpd_sm.c
new file mode 100644
index 0000000000..a8b1b1f0fe
--- /dev/null
+++ b/common/usb_pe_ctvpd_sm.c
@@ -0,0 +1,207 @@
+/* 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 "common.h"
+#include "console.h"
+#include "task.h"
+#include "util.h"
+#include "usb_pd.h"
+#include "usb_pd_tcpm.h"
+#include "usb_pe_sm.h"
+#include "usb_prl_sm.h"
+#include "usb_tc_sm.h"
+#include "usb_emsg.h"
+#include "usb_sm.h"
+
+/* USB Policy Engine Charge-Through VCONN Powered Device module */
+
+/* Policy Engine Flags */
+#define PE_FLAGS_MSG_RECEIVED (1 << 0)
+
+enum l_state {
+ PE_INIT,
+ PE_RUN,
+ PE_PAUSED
+};
+
+static enum l_state local_state = PE_INIT;
+
+/**
+ * This is the PE Port object that contains information needed to
+ * implement a VCONN and Charge-Through VCONN Powered Device.
+ */
+static struct policy_engine {
+ /*
+ * struct sm_obj must be first. This is the state machine
+ * object that keeps track of the current and last state
+ * of the state machine.
+ */
+ struct sm_obj obj;
+ /* port flags, see PE_FLAGS_* */
+ uint32_t flags;
+} pe[CONFIG_USB_PD_PORT_COUNT];
+
+/* Policy Engine states */
+DECLARE_STATE(pe, request, NOOP_EXIT);
+
+void pe_init(int port)
+{
+ pe[port].flags = 0;
+ init_state(port, PE_OBJ(port), pe_request);
+}
+
+void policy_engine(int port, int evt, int en)
+{
+ switch (local_state) {
+ case PE_INIT:
+ pe_init(port);
+ local_state = PE_RUN;
+ /* fall through */
+ case PE_RUN:
+ if (!en) {
+ local_state = PE_PAUSED;
+ break;
+ }
+
+ exe_state(port, PE_OBJ(port), RUN_SIG);
+ break;
+ case PE_PAUSED:
+ if (en)
+ local_state = PE_INIT;
+ break;
+ }
+}
+
+void pe_pass_up_message(int port)
+{
+ pe[port].flags |= PE_FLAGS_MSG_RECEIVED;
+ task_set_event(PD_PORT_TO_TASK_ID(port), PD_EVENT_SM, 0);
+}
+
+void pe_hard_reset_sent(int port)
+{
+ /* Do nothing */
+}
+
+void pe_got_hard_reset(int port)
+{
+ /* Do nothing */
+}
+
+void pe_report_error(int port, enum pe_error e)
+{
+ /* Do nothing */
+}
+
+void pe_got_soft_reset(int port)
+{
+ /* Do nothing */
+}
+
+void pe_message_sent(int port)
+{
+ /* Do nothing */
+}
+
+static unsigned int pe_request(int port, enum signal sig)
+{
+ int ret;
+
+ ret = (*pe_request_sig[sig])(port);
+ return SUPER(ret, sig, 0);
+}
+
+static unsigned int pe_request_entry(int port)
+{
+ return 0;
+}
+
+static unsigned int pe_request_run(int port)
+{
+ uint32_t *payload = (uint32_t *)emsg[port].buf;
+ uint32_t header = emsg[port].header;
+ uint32_t vdo = payload[0];
+
+ if (pe[port].flags & PE_FLAGS_MSG_RECEIVED) {
+ pe[port].flags &= ~PE_FLAGS_MSG_RECEIVED;
+
+ /*
+ * Only support Structured VDM Discovery
+ * Identity message
+ */
+
+ if (PD_HEADER_TYPE(header) != PD_DATA_VENDOR_DEF)
+ return 0;
+
+ if (PD_HEADER_CNT(header) == 0)
+ return 0;
+
+ if (!PD_VDO_SVDM(vdo))
+ return 0;
+
+ if (PD_VDO_CMD(vdo) != CMD_DISCOVER_IDENT)
+ return 0;
+
+#ifdef CONFIG_USB_TYPEC_CTVPD
+ /*
+ * We have a valid DISCOVER IDENTITY message.
+ * Attempt to reset support timer
+ */
+ tc_reset_support_timer(port);
+#endif
+ /* Prepare to send ACK */
+
+ /* VDM Header */
+ payload[0] = VDO(
+ USB_VID_GOOGLE,
+ 1, /* Structured VDM */
+ VDO_SVDM_VERS(1) |
+ VDO_CMDT(CMDT_RSP_ACK) |
+ CMD_DISCOVER_IDENT);
+
+ /* ID Header VDO */
+ payload[1] = VDO_IDH(
+ 0, /* Not a USB Host */
+ 1, /* Capable of being enumerated as USB Device */
+ IDH_PTYPE_VPD,
+ 0, /* Modal Operation Not Supported */
+ USB_VID_GOOGLE);
+
+ /* Cert State VDO */
+ payload[2] = 0;
+
+ /* Product VDO */
+ payload[3] = VDO_PRODUCT(
+ CONFIG_USB_PID,
+ USB_BCD_DEVICE);
+
+ /* VPD VDO */
+ payload[4] = VDO_VPD(
+ VPD_HW_VERSION,
+ VPD_FW_VERSION,
+ VPD_MAX_VBUS_20V,
+ VPD_VBUS_IMP(VPD_VBUS_IMPEDANCE),
+ VPD_GND_IMP(VPD_GND_IMPEDANCE),
+#ifdef CONFIG_USB_TYPEC_CTVPD
+ VPD_CTS_SUPPORTED
+#else
+ VPD_CTS_NOT_SUPPORTED
+#endif
+ );
+
+ /* 20 bytes, 5 data objects */
+ emsg[port].len = 20;
+
+ /* Set to highest revision supported by both ports. */
+ prl_set_rev(port, (PD_HEADER_REV(header) > PD_REV30) ?
+ PD_REV30 : PD_HEADER_REV(header));
+
+ /* Send the ACK */
+ prl_send_data_msg(port, TCPC_TX_SOP_PRIME,
+ PD_DATA_VENDOR_DEF);
+ }
+
+ return 0;
+}
diff --git a/common/usb_pe_sm.c b/common/usb_pe_sm.c
deleted file mode 100644
index 91f8b587ed..0000000000
--- a/common/usb_pe_sm.c
+++ /dev/null
@@ -1,12 +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 "common.h"
-
-/* Include USB PD Policy Engine State Machine */
-#if defined(CONFIG_USB_TYPEC_VPD) || defined(CONFIG_USB_TYPEC_CTVPD)
-#include "usb_pe_ctvpd_sm.h"
-#else
-#error "A USB PD Policy Engine State Machine must be defined."
-#endif
diff --git a/common/usb_prl_sm.c b/common/usb_prl_sm.c
index 42b4ee3c24..ec29b66fbb 100644
--- a/common/usb_prl_sm.c
+++ b/common/usb_prl_sm.c
@@ -153,292 +153,43 @@ struct extended_msg emsg[CONFIG_USB_PD_PORT_COUNT];
/* Common Protocol Layer Message Transmission */
static void prl_tx_construct_message(int port);
-static unsigned int prl_tx_phy_layer_reset(int port, enum signal sig);
-static unsigned int prl_tx_phy_layer_reset_entry(int port);
-static unsigned int prl_tx_phy_layer_reset_run(int port);
-
-static unsigned int prl_tx_wait_for_message_request(int port, enum signal sig);
-static unsigned int prl_tx_wait_for_message_request_entry(int port);
-static unsigned int prl_tx_wait_for_message_request_run(int port);
-
-static unsigned int prl_tx_layer_reset_for_transmit(int port, enum signal sig);
-static unsigned int prl_tx_layer_reset_for_transmit_entry(int port);
-static unsigned int prl_tx_layer_reset_for_transmit_run(int port);
-
-static unsigned int prl_tx_wait_for_phy_response(int port, enum signal sig);
-static unsigned int prl_tx_wait_for_phy_response_entry(int port);
-static unsigned int prl_tx_wait_for_phy_response_run(int port);
-static unsigned int prl_tx_wait_for_phy_response_exit(int port);
-
-static unsigned int prl_tx_src_source_tx(int port, enum signal sig);
-static unsigned int prl_tx_src_source_tx_entry(int port);
-static unsigned int prl_tx_src_source_tx_run(int port);
-
-static unsigned int prl_tx_snk_start_ams(int port, enum signal sig);
-static unsigned int prl_tx_snk_start_ams_entry(int port);
-static unsigned int prl_tx_snk_start_ams_run(int port);
+DECLARE_STATE(prl, tx_phy_layer_reset, NOOP_EXIT);
+DECLARE_STATE(prl, tx_wait_for_message_request, NOOP_EXIT);
+DECLARE_STATE(prl, tx_layer_reset_for_transmit, NOOP_EXIT);
+DECLARE_STATE(prl, tx_wait_for_phy_response, WITH_EXIT);
+DECLARE_STATE(prl, tx_src_source_tx, NOOP_EXIT);
+DECLARE_STATE(prl, tx_snk_start_ams, NOOP_EXIT);
/* Source Protocol Layser Message Transmission */
-static unsigned int prl_tx_src_pending(int port, enum signal sig);
-static unsigned int prl_tx_src_pending_entry(int port);
-static unsigned int prl_tx_src_pending_run(int port);
+DECLARE_STATE(prl, tx_src_pending, NOOP_EXIT);
/* Sink Protocol Layer Message Transmission */
-static unsigned int prl_tx_snk_pending(int port, enum signal sig);
-static unsigned int prl_tx_snk_pending_entry(int port);
-static unsigned int prl_tx_snk_pending_run(int port);
-
-static unsigned int prl_tx_discard_message(int port, enum signal sig);
-static unsigned int prl_tx_discard_message_entry(int port);
-static unsigned int prl_tx_discard_message_run(int port);
+DECLARE_STATE(prl, tx_snk_pending, NOOP_EXIT);
+DECLARE_STATE(prl, tx_discard_message, NOOP_EXIT);
/* Protocol Layer Message Reception */
static unsigned int prl_rx_wait_for_phy_message(int port, int evt);
/* Hard Reset Operation */
-static unsigned int prl_hr_wait_for_request(int port, enum signal sig);
-static unsigned int prl_hr_wait_for_request_entry(int port);
-static unsigned int prl_hr_wait_for_request_run(int port);
-
-static unsigned int prl_hr_reset_layer(int port, enum signal sig);
-static unsigned int prl_hr_reset_layer_entry(int port);
-static unsigned int prl_hr_reset_layer_run(int port);
-
-static unsigned int
- prl_hr_wait_for_phy_hard_reset_complete(int port, enum signal sig);
-static unsigned int prl_hr_wait_for_phy_hard_reset_complete_entry(int port);
-static unsigned int prl_hr_wait_for_phy_hard_reset_complete_run(int port);
-
-static unsigned int
- prl_hr_wait_for_pe_hard_reset_complete(int port, enum signal sig);
-static unsigned int prl_hr_wait_for_pe_hard_reset_complete_entry(int port);
-static unsigned int prl_hr_wait_for_pe_hard_reset_complete_run(int port);
-static unsigned int prl_hr_wait_for_pe_hard_reset_complete_exit(int port);
+DECLARE_STATE(prl, hr_wait_for_request, NOOP_EXIT);
+DECLARE_STATE(prl, hr_reset_layer, NOOP_EXIT);
+DECLARE_STATE(prl, hr_wait_for_phy_hard_reset_complete, NOOP_EXIT);
+DECLARE_STATE(prl, hr_wait_for_pe_hard_reset_complete, WITH_EXIT);
/* Chunked Rx */
-static unsigned int
- rch_wait_for_message_from_protocol_layer(int port, enum signal sig);
-static unsigned int rch_wait_for_message_from_protocol_layer_entry(int port);
-static unsigned int rch_wait_for_message_from_protocol_layer_run(int port);
-
-static unsigned int rch_processing_extended_message(int port, enum signal sig);
-static unsigned int rch_processing_extended_message_entry(int port);
-static unsigned int rch_processing_extended_message_run(int port);
-
-static unsigned int rch_requesting_chunk(int port, enum signal sig);
-static unsigned int rch_requesting_chunk_entry(int port);
-static unsigned int rch_requesting_chunk_run(int port);
-
-static unsigned int rch_waiting_chunk(int port, enum signal sig);
-static unsigned int rch_waiting_chunk_entry(int port);
-static unsigned int rch_waiting_chunk_run(int port);
-
-static unsigned int rch_report_error(int port, enum signal sig);
-static unsigned int rch_report_error_entry(int port);
-static unsigned int rch_report_error_run(int port);
+DECLARE_STATE(rch, wait_for_message_from_protocol_layer, NOOP_EXIT);
+DECLARE_STATE(rch, processing_extended_message, NOOP_EXIT);
+DECLARE_STATE(rch, requesting_chunk, NOOP_EXIT);
+DECLARE_STATE(rch, waiting_chunk, NOOP_EXIT);
+DECLARE_STATE(rch, report_error, NOOP_EXIT);
/* Chunked Tx */
-static unsigned int
- tch_wait_for_message_request_from_pe(int port, enum signal sig);
-static unsigned int tch_wait_for_message_request_from_pe_entry(int port);
-static unsigned int tch_wait_for_message_request_from_pe_run(int port);
-
-static unsigned int
- tch_wait_for_transmission_complete(int port, enum signal sig);
-static unsigned int tch_wait_for_transmission_complete_entry(int port);
-static unsigned int tch_wait_for_transmission_complete_run(int port);
-
-static unsigned int tch_construct_chunked_message(int port, enum signal sig);
-static unsigned int tch_construct_chunked_message_entry(int port);
-static unsigned int tch_construct_chunked_message_run(int port);
-
-static unsigned int tch_sending_chunked_message(int port, enum signal sig);
-static unsigned int tch_sending_chunked_message_entry(int port);
-static unsigned int tch_sending_chunked_message_run(int port);
-
-static unsigned int tch_wait_chunk_request(int port, enum signal sig);
-static unsigned int tch_wait_chunk_request_entry(int port);
-static unsigned int tch_wait_chunk_request_run(int port);
-
-static unsigned int tch_message_received(int port, enum signal sig);
-static unsigned int tch_message_received_entry(int port);
-static unsigned int tch_message_received_run(int port);
-
-static unsigned int do_nothing_exit(int port);
-static unsigned int get_super_state(int port);
-
-static const state_sig prl_tx_phy_layer_reset_sig[] = {
- prl_tx_phy_layer_reset_entry,
- prl_tx_phy_layer_reset_run,
- do_nothing_exit,
- get_super_state
-};
-
-static const state_sig prl_tx_wait_for_message_request_sig[] = {
- prl_tx_wait_for_message_request_entry,
- prl_tx_wait_for_message_request_run,
- do_nothing_exit,
- get_super_state
-};
-
-static const state_sig prl_tx_layer_reset_for_transmit_sig[] = {
- prl_tx_layer_reset_for_transmit_entry,
- prl_tx_layer_reset_for_transmit_run,
- do_nothing_exit,
- get_super_state
-};
-
-static const state_sig prl_tx_wait_for_phy_response_sig[] = {
- prl_tx_wait_for_phy_response_entry,
- prl_tx_wait_for_phy_response_run,
- prl_tx_wait_for_phy_response_exit,
- get_super_state
-};
-
-static const state_sig prl_tx_src_source_tx_sig[] = {
- prl_tx_src_source_tx_entry,
- prl_tx_src_source_tx_run,
- do_nothing_exit,
- get_super_state
-};
-
-static const state_sig prl_tx_snk_start_ams_sig[] = {
- prl_tx_snk_start_ams_entry,
- prl_tx_snk_start_ams_run,
- do_nothing_exit,
- get_super_state
-};
-
-/* Source Protocol Layser Message Transmission */
-static const state_sig prl_tx_src_pending_sig[] = {
- prl_tx_src_pending_entry,
- prl_tx_src_pending_run,
- do_nothing_exit,
- get_super_state
-};
-
-/* Sink Protocol Layer Message Transmission */
-static const state_sig prl_tx_snk_pending_sig[] = {
- prl_tx_snk_pending_entry,
- prl_tx_snk_pending_run,
- do_nothing_exit,
- get_super_state
-};
-
-static const state_sig prl_tx_discard_message_sig[] = {
- prl_tx_discard_message_entry,
- prl_tx_discard_message_run,
- do_nothing_exit,
- get_super_state
-};
-
-/* Hard Reset Operation */
-static const state_sig prl_hr_wait_for_request_sig[] = {
- prl_hr_wait_for_request_entry,
- prl_hr_wait_for_request_run,
- do_nothing_exit,
- get_super_state
-};
-
-static const state_sig prl_hr_reset_layer_sig[] = {
- prl_hr_reset_layer_entry,
- prl_hr_reset_layer_run,
- do_nothing_exit,
- get_super_state
-};
-
-static const state_sig prl_hr_wait_for_phy_hard_reset_complete_sig[] = {
- prl_hr_wait_for_phy_hard_reset_complete_entry,
- prl_hr_wait_for_phy_hard_reset_complete_run,
- do_nothing_exit,
- get_super_state
-};
-
-static const state_sig prl_hr_wait_for_pe_hard_reset_complete_sig[] = {
- prl_hr_wait_for_pe_hard_reset_complete_entry,
- prl_hr_wait_for_pe_hard_reset_complete_run,
- prl_hr_wait_for_pe_hard_reset_complete_exit,
- get_super_state
-};
-
-/* Chunked Rx */
-static const state_sig rch_wait_for_message_from_protocol_layer_sig[] = {
- rch_wait_for_message_from_protocol_layer_entry,
- rch_wait_for_message_from_protocol_layer_run,
- do_nothing_exit,
- get_super_state
-};
-
-static const state_sig rch_processing_extended_message_sig[] = {
- rch_processing_extended_message_entry,
- rch_processing_extended_message_run,
- do_nothing_exit,
- get_super_state
-};
-
-static const state_sig rch_requesting_chunk_sig[] = {
- rch_requesting_chunk_entry,
- rch_requesting_chunk_run,
- do_nothing_exit,
- get_super_state
-};
-
-static const state_sig rch_waiting_chunk_sig[] = {
- rch_waiting_chunk_entry,
- rch_waiting_chunk_run,
- do_nothing_exit,
- get_super_state
-};
-
-static const state_sig rch_report_error_sig[] = {
- rch_report_error_entry,
- rch_report_error_run,
- do_nothing_exit,
- get_super_state
-};
-
-/* Chunked Tx */
-static const state_sig tch_wait_for_message_request_from_pe_sig[] = {
- tch_wait_for_message_request_from_pe_entry,
- tch_wait_for_message_request_from_pe_run,
- do_nothing_exit,
- get_super_state
-};
-
-static const state_sig tch_wait_for_transmission_complete_sig[] = {
- tch_wait_for_transmission_complete_entry,
- tch_wait_for_transmission_complete_run,
- do_nothing_exit,
- get_super_state
-};
-
-static const state_sig tch_construct_chunked_message_sig[] = {
- tch_construct_chunked_message_entry,
- tch_construct_chunked_message_run,
- do_nothing_exit,
- get_super_state
-};
-
-static const state_sig tch_sending_chunked_message_sig[] = {
- tch_sending_chunked_message_entry,
- tch_sending_chunked_message_run,
- do_nothing_exit,
- get_super_state
-};
-
-static const state_sig tch_wait_chunk_request_sig[] = {
- tch_wait_chunk_request_entry,
- tch_wait_chunk_request_run,
- do_nothing_exit,
- get_super_state
-};
-
-static const state_sig tch_message_received_sig[] = {
- tch_message_received_entry,
- tch_message_received_run,
- do_nothing_exit,
- get_super_state
-};
+DECLARE_STATE(tch, wait_for_message_request_from_pe, NOOP_EXIT);
+DECLARE_STATE(tch, wait_for_transmission_complete, NOOP_EXIT);
+DECLARE_STATE(tch, construct_chunked_message, NOOP_EXIT);
+DECLARE_STATE(tch, sending_chunked_message, NOOP_EXIT);
+DECLARE_STATE(tch, wait_chunk_request, NOOP_EXIT);
+DECLARE_STATE(tch, message_received, NOOP_EXIT);
void pd_transmit_complete(int port, int status)
{
@@ -2151,13 +1902,3 @@ static unsigned int prl_rx_wait_for_phy_message(int port, int evt)
return 0;
}
-
-static unsigned int do_nothing_exit(int port)
-{
- return 0;
-}
-
-static unsigned int get_super_state(int port)
-{
- return RUN_SUPER;
-}
diff --git a/common/usb_sm.c b/common/usb_sm.c
index 6d3cacdb3b..de6d7959e3 100644
--- a/common/usb_sm.c
+++ b/common/usb_sm.c
@@ -164,3 +164,14 @@ void exe_state(int port, struct sm_obj *obj, enum signal sig)
obj->task_state(port, sig);
#endif
}
+
+unsigned int do_nothing_exit(int port)
+{
+ return 0;
+}
+
+unsigned int get_super_state(int port)
+{
+ return RUN_SUPER;
+}
+
diff --git a/common/usb_tc_ctvpd_sm.c b/common/usb_tc_ctvpd_sm.c
new file mode 100644
index 0000000000..5b471cf330
--- /dev/null
+++ b/common/usb_tc_ctvpd_sm.c
@@ -0,0 +1,1736 @@
+/* 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 "common.h"
+#include "console.h"
+#include "system.h"
+#include "task.h"
+#include "tcpm.h"
+#include "usb_pd.h"
+#include "usb_tc_ctvpd_sm.h"
+#include "usb_tc_sm.h"
+#include "vpd_api.h"
+
+/* USB Type-C CTVPD module */
+
+#ifdef CONFIG_COMMON_RUNTIME
+#define CPRINTF(format, args...) cprintf(CC_HOOK, format, ## args)
+#define CPRINTS(format, args...) cprints(CC_HOOK, format, ## args)
+#else /* CONFIG_COMMON_RUNTIME */
+#define CPRINTF(format, args...)
+#define CPRINTS(format, args...)
+#endif
+
+/* Type-C Layer Flags */
+#define TC_FLAGS_VCONN_ON (1 << 0)
+
+#undef PD_DEFAULT_STATE
+/* Port default state at startup */
+#define PD_DEFAULT_STATE(port) tc_unattached_snk
+
+#define SUPPORT_TIMER_RESET_INIT 0
+#define SUPPORT_TIMER_RESET_REQUEST 1
+#define SUPPORT_TIMER_RESET_COMPLETE 2
+
+/**
+ * This is the Type-C Port object that contains information needed to
+ * implement a Charge Through VCONN Powered Device.
+ */
+struct type_c tc[CONFIG_USB_PD_PORT_COUNT];
+
+/* Type-C states */
+DECLARE_STATE(tc, disabled, WITH_EXIT);
+DECLARE_STATE(tc, error_recovery, NOOP_EXIT);
+DECLARE_STATE(tc, unattached_snk, NOOP_EXIT);
+DECLARE_STATE(tc, attach_wait_snk, NOOP_EXIT);
+DECLARE_STATE(tc, attached_snk, WITH_EXIT);
+DECLARE_STATE(tc, try_snk, NOOP_EXIT);
+DECLARE_STATE(tc, unattached_src, NOOP_EXIT);
+DECLARE_STATE(tc, attach_wait_src, NOOP_EXIT);
+DECLARE_STATE(tc, try_wait_src, NOOP_EXIT);
+DECLARE_STATE(tc, attached_src, NOOP_EXIT);
+DECLARE_STATE(tc, ct_try_snk, WITH_EXIT);
+DECLARE_STATE(tc, ct_attach_wait_unsupported, WITH_EXIT);
+DECLARE_STATE(tc, ct_attached_unsupported, WITH_EXIT);
+DECLARE_STATE(tc, ct_unattached_unsupported, WITH_EXIT);
+DECLARE_STATE(tc, ct_unattached_vpd, WITH_EXIT);
+DECLARE_STATE(tc, ct_disabled_vpd, NOOP_EXIT);
+DECLARE_STATE(tc, ct_attached_vpd, NOOP_EXIT);
+DECLARE_STATE(tc, ct_attach_wait_vpd, WITH_EXIT);
+
+/* Super States */
+DECLARE_STATE(tc, host_rard_ct_rd, NOOP_EXIT);
+DECLARE_STATE(tc, host_open_ct_open, NOOP_EXIT);
+DECLARE_STATE(tc, vbus_cc_iso, NOOP_EXIT);
+DECLARE_STATE(tc, host_rp3_ct_rd, NOOP_EXIT);
+DECLARE_STATE(tc, host_rp3_ct_rpu, NOOP_EXIT);
+DECLARE_STATE(tc, host_rpu_ct_rd, NOOP_EXIT);
+
+void tc_reset_support_timer(int port)
+{
+ tc[port].support_timer_reset |= SUPPORT_TIMER_RESET_REQUEST;
+}
+
+void tc_state_init(int port)
+{
+ int res = 0;
+ sm_state this_state;
+
+ res = tc_restart_tcpc(port);
+
+ CPRINTS("TCPC p%d init %s", port, res ? "failed" : "ready");
+ this_state = res ? tc_disabled : PD_DEFAULT_STATE(port);
+
+ init_state(port, TC_OBJ(port), this_state);
+
+ /* Disable pd state machines */
+ tc[port].pd_enable = 0;
+ tc[port].evt_timeout = 10*MSEC;
+ tc[port].power_role = PD_PLUG_CABLE_VPD;
+ tc[port].data_role = 0; /* Reserved for VPD */
+ tc[port].billboard_presented = 0;
+ tc[port].flags = 0;
+}
+
+void tc_event_check(int port, int evt)
+{
+ /* Do Nothing */
+}
+
+/**
+ * Disabled
+ *
+ * Super State Entry Actions:
+ * Isolate the Host-side port from the Charge-Through port
+ * Enable mcu communication
+ * Remove the terminations from Host
+ * Remove the terminations from Charge-Through
+ */
+static unsigned int tc_disabled(int port, enum signal sig)
+{
+ int ret = 0;
+
+ ret = (*tc_disabled_sig[sig])(port);
+ return SUPER(ret, sig, tc_host_open_ct_open);
+}
+
+static unsigned int tc_disabled_entry(int port)
+{
+ tc[port].state_id = DISABLED;
+ CPRINTS("C%d: %s", port, tc_state_names[tc[port].state_id]);
+ return 0;
+}
+
+static unsigned int tc_disabled_run(int port)
+{
+ task_wait_event(-1);
+ return RUN_SUPER;
+}
+
+static unsigned int tc_disabled_exit(int port)
+{
+#ifndef CONFIG_USB_PD_TCPC
+ if (tc_restart_tcpc(port) != 0) {
+ CPRINTS("TCPC p%d restart failed!", port);
+ return 0;
+ }
+#endif
+ CPRINTS("TCPC p%d resumed!", port);
+ set_state(port, TC_OBJ(port), tc_unattached_snk);
+
+ return 0;
+}
+
+/**
+ * ErrorRecovery
+ *
+ * Super State Entry Actions:
+ * Isolate the Host-side port from the Charge-Through port
+ * Enable mcu communication
+ * Remove the terminations from Host
+ * Remove the terminations from Charge-Through
+ */
+static unsigned int tc_error_recovery(int port, enum signal sig)
+{
+ int ret = 0;
+
+ ret = (*tc_error_recovery_sig[sig])(port);
+ return SUPER(ret, sig, tc_host_open_ct_open);
+}
+
+static unsigned int tc_error_recovery_entry(int port)
+{
+ tc[port].state_id = ERROR_RECOVERY;
+ CPRINTS("C%d: %s", port, tc_state_names[tc[port].state_id]);
+ /* Use cc_debounce state variable for error recovery timeout */
+ tc[port].cc_debounce = get_time().val + PD_T_ERROR_RECOVERY;
+ return 0;
+}
+
+static unsigned int tc_error_recovery_run(int port)
+{
+ if (get_time().val > tc[port].cc_debounce) {
+ set_state(port, TC_OBJ(port), tc_unattached_snk);
+ return 0;
+ }
+
+ return RUN_SUPER;
+}
+
+/**
+ * Unattached.SNK
+ *
+ * Super State Entry Actions:
+ * Isolate the Host-side port from the Charge-Through port
+ * Enable mcu communication
+ * Place Ra on VCONN and Rd on Host CC
+ * Place Rd on Charge-Through CCs
+ */
+static unsigned int tc_unattached_snk(int port, enum signal sig)
+{
+ int ret = 0;
+
+ ret = (*tc_unattached_snk_sig[sig])(port);
+ return SUPER(ret, sig, tc_host_rard_ct_rd);
+}
+
+static unsigned int tc_unattached_snk_entry(int port)
+{
+ tc[port].state_id = UNATTACHED_SNK;
+ if (tc[port].obj.last_state != tc_unattached_src)
+ CPRINTS("C%d: %s", port, tc_state_names[tc[port].state_id]);
+
+ tc[port].flags &= ~TC_FLAGS_VCONN_ON;
+ tc[port].cc_state = PD_CC_UNSET;
+
+ return 0;
+}
+
+static unsigned int tc_unattached_snk_run(int port)
+{
+ int host_cc;
+ int new_cc_state;
+ int cc1;
+ int cc2;
+
+ /* Check Host CC for connection */
+ vpd_host_get_cc(&host_cc);
+
+ /*
+ * Transition to AttachWait.SNK when a Source connection is
+ * detected, as indicated by the SNK.Rp state on its Host-side
+ * port’s CC pin.
+ */
+ if (cc_is_rp(host_cc)) {
+ set_state(port, TC_OBJ(port), tc_attach_wait_snk);
+ return 0;
+ }
+
+ /* Check Charge-Through CCs for connection */
+ vpd_ct_get_cc(&cc1, &cc2);
+
+ if (cc_is_rp(cc1) != cc_is_rp(cc2))
+ new_cc_state = PD_CC_DFP_ATTACHED;
+ else
+ new_cc_state = PD_CC_NONE;
+
+ /* Debounce Charge-Through CC state */
+ if (tc[port].cc_state != new_cc_state) {
+ tc[port].cc_state = new_cc_state;
+ tc[port].cc_debounce = get_time().val + PD_T_CC_DEBOUNCE;
+ }
+
+ /* If we are here, Host CC must be open */
+
+ /* Wait for Charge-Through CC debounce */
+ if (get_time().val < tc[port].cc_debounce)
+ return 0;
+
+ /*
+ * A Charge-Through VCONN-Powered USB Device shall transition to
+ * Unattached.SRC when the state of the Host-side port’s CC pin is
+ * SNK.Open for tDRP − dcSRC.DRP ∙ tDRP and both of the following
+ * is detected on the Charge-Through port.
+ * 1) SNK.Rp state is detected on exactly one of the CC1 or CC2
+ * pins for at least tCCDebounce
+ * 2) VBUS is detected
+ */
+ if (vpd_is_ct_vbus_present() &&
+ tc[port].cc_state == PD_CC_DFP_ATTACHED) {
+ set_state(port, TC_OBJ(port), tc_unattached_src);
+ return 0;
+ }
+
+ return RUN_SUPER;
+}
+
+/**
+ * AttachWait.SNK
+ *
+ * Super State Entry Actions:
+ * Isolate the Host-side port from the Charge-Through port
+ * Enable mcu communication
+ * Place Ra on VCONN and Rd on Host CC
+ * Place Rd on Charge-Through CCs
+ */
+static unsigned int tc_attach_wait_snk(int port, enum signal sig)
+{
+ int ret;
+
+ ret = (*tc_attach_wait_snk_sig[sig])(port);
+ return SUPER(ret, sig, tc_host_rard_ct_rd);
+}
+
+static unsigned int tc_attach_wait_snk_entry(int port)
+{
+ tc[port].state_id = ATTACH_WAIT_SNK;
+ CPRINTS("C%d: %s", port, tc_state_names[tc[port].state_id]);
+ tc[port].host_cc_state = PD_CC_UNSET;
+
+ return 0;
+}
+
+static unsigned int tc_attach_wait_snk_run(int port)
+{
+ int host_new_cc_state;
+ int host_cc;
+
+ /* Check Host CC for connection */
+ vpd_host_get_cc(&host_cc);
+
+ if (cc_is_rp(host_cc))
+ host_new_cc_state = PD_CC_DFP_ATTACHED;
+ else
+ host_new_cc_state = PD_CC_NONE;
+
+ /* Debounce the Host CC state */
+ if (tc[port].host_cc_state != host_new_cc_state) {
+ tc[port].host_cc_state = host_new_cc_state;
+ if (host_new_cc_state == PD_CC_DFP_ATTACHED)
+ tc[port].host_cc_debounce = get_time().val +
+ PD_T_CC_DEBOUNCE;
+ else
+ tc[port].host_cc_debounce = get_time().val +
+ PD_T_PD_DEBOUNCE;
+ return 0;
+ }
+
+ /* Wait for Host CC debounce */
+ if (get_time().val < tc[port].host_cc_debounce)
+ return 0;
+
+ /*
+ * A Charge-Through VCONN-Powered USB Device shall transition to
+ * Attached.SNK after the state of the Host-side port’s CC pin is
+ * SNK.Rp for at least tCCDebounce and either host-side VCONN or
+ * VBUS is detected.
+ *
+ * Transition to Unattached.SNK when the state of both the CC1 and
+ * CC2 pins is SNK.Open for at least tPDDebounce.
+ */
+ if (tc[port].host_cc_state == PD_CC_DFP_ATTACHED &&
+ (vpd_is_vconn_present() || vpd_is_host_vbus_present()))
+ set_state(port, TC_OBJ(port), tc_attached_snk);
+ else if (tc[port].host_cc_state == PD_CC_NONE)
+ set_state(port, TC_OBJ(port), tc_unattached_snk);
+
+ return 0;
+}
+
+/**
+ * Attached.SNK
+ */
+static unsigned int tc_attached_snk(int port, enum signal sig)
+{
+ int ret;
+
+ ret = (*tc_attached_snk_sig[sig])(port);
+ return SUPER(ret, sig, 0);
+}
+
+static unsigned int tc_attached_snk_entry(int port)
+{
+ tc[port].state_id = ATTACHED_SNK;
+ CPRINTS("C%d: %s", port, tc_state_names[tc[port].state_id]);
+
+ /* Enable PD */
+ tc[port].pd_enable = 1;
+ set_polarity(port, 0);
+
+ /*
+ * This state can only be entered from states AttachWait.SNK
+ * and Try.SNK. So the Host port is isolated from the
+ * Charge-Through port. We only need to High-Z the
+ * Charge-Through ports CC1 and CC2 pins.
+ */
+ vpd_ct_set_pull(TYPEC_CC_OPEN, 0);
+
+ tc[port].host_cc_state = PD_CC_UNSET;
+
+ /* Start Charge-Through support timer */
+ tc[port].support_timer_reset = SUPPORT_TIMER_RESET_INIT;
+ tc[port].support_timer = get_time().val + PD_T_AME;
+
+ /* Sample host CC every 2ms */
+ tc_set_timeout(port, 2*MSEC);
+
+ return 0;
+}
+
+static unsigned int tc_attached_snk_run(int port)
+{
+ int host_new_cc_state;
+ int host_cc;
+
+ /* Has host vbus and vconn been removed */
+ if (!vpd_is_host_vbus_present() && !vpd_is_vconn_present()) {
+ set_state(port, TC_OBJ(port), tc_unattached_snk);
+ return 0;
+ }
+
+ /*
+ * Reset the Charge-Through Support Timer when it first
+ * receives any USB PD Structured VDM Command it supports,
+ * which is the Discover Identity command. And this is only
+ * done one time.
+ */
+ if (tc[port].support_timer_reset == SUPPORT_TIMER_RESET_REQUEST) {
+ tc[port].support_timer_reset |= SUPPORT_TIMER_RESET_COMPLETE;
+ tc[port].support_timer = get_time().val + PD_T_AME;
+ }
+
+ /* Check Host CC for connection */
+ vpd_host_get_cc(&host_cc);
+
+ if (cc_is_rp(host_cc))
+ host_new_cc_state = PD_CC_DFP_ATTACHED;
+ else
+ host_new_cc_state = PD_CC_NONE;
+
+ /* Debounce the Host CC state */
+ if (tc[port].host_cc_state != host_new_cc_state) {
+ tc[port].host_cc_state = host_new_cc_state;
+ tc[port].host_cc_debounce = get_time().val + PD_T_VPDCTDD;
+ return 0;
+ }
+
+ /* Wait for Host CC debounce */
+ if (get_time().val < tc[port].host_cc_debounce)
+ return 0;
+
+ if (vpd_is_vconn_present()) {
+ if (!(tc[port].flags & TC_FLAGS_VCONN_ON)) {
+ /* VCONN detected. Remove RA */
+ vpd_host_set_pull(TYPEC_CC_RD, 0);
+ tc[port].flags |= TC_FLAGS_VCONN_ON;
+ }
+
+ /*
+ * A Charge-Through VCONN-Powered USB Device shall transition
+ * to CTUnattached.VPD if VCONN is present and the state of
+ * its Host-side port’s CC pin is SNK.Open for tVPDCTDD.
+ */
+ if (tc[port].host_cc_state == PD_CC_NONE) {
+ set_state(port, TC_OBJ(port), tc_ct_unattached_vpd);
+ return 0;
+ }
+ }
+
+ /* Check the Support Timer */
+ if (get_time().val > tc[port].support_timer &&
+ !tc[port].billboard_presented) {
+ /*
+ * Present USB Billboard Device Class interface
+ * indicating that Charge-Through is not supported
+ */
+ tc[port].billboard_presented = 1;
+ vpd_present_billboard(BB_SNK);
+ }
+
+ return 0;
+}
+
+static unsigned int tc_attached_snk_exit(int port)
+{
+ /* Reset timeout value to 10ms */
+ tc_set_timeout(port, 10*MSEC);
+ tc[port].billboard_presented = 0;
+ vpd_present_billboard(BB_NONE);
+
+ return 0;
+}
+
+/**
+ * Super State HOST_RA_CT_RD
+ */
+static unsigned int tc_host_rard_ct_rd(int port, enum signal sig)
+{
+ int ret;
+
+ ret = (*tc_host_rard_ct_rd_sig[sig])(port);
+ return SUPER(ret, sig, tc_vbus_cc_iso);
+}
+
+static unsigned int tc_host_rard_ct_rd_entry(int port)
+{
+ /* Place Ra on VCONN and Rd on Host CC */
+ vpd_host_set_pull(TYPEC_CC_RA_RD, 0);
+
+ /* Place Rd on Charge-Through CCs */
+ vpd_ct_set_pull(TYPEC_CC_RD, 0);
+
+ return 0;
+}
+
+static unsigned int tc_host_rard_ct_rd_run(int port)
+{
+ return RUN_SUPER;
+}
+
+/**
+ * Super State HOST_OPEN_CT_OPEN
+ */
+static unsigned int tc_host_open_ct_open(int port, enum signal sig)
+{
+ int ret;
+
+ ret = (*tc_host_open_ct_open_sig[sig])(port);
+ return SUPER(ret, sig, tc_vbus_cc_iso);
+}
+
+static unsigned int tc_host_open_ct_open_entry(int port)
+{
+ /* Remove the terminations from Host */
+ vpd_host_set_pull(TYPEC_CC_OPEN, 0);
+
+ /* Remove the terminations from Charge-Through */
+ vpd_ct_set_pull(TYPEC_CC_OPEN, 0);
+
+ return 0;
+}
+
+static unsigned int tc_host_open_ct_open_run(int port)
+{
+ return RUN_SUPER;
+}
+
+/**
+ * Super State VBUS_CC_ISO
+ */
+static unsigned int tc_vbus_cc_iso(int port, enum signal sig)
+{
+ int ret;
+
+ ret = (*tc_vbus_cc_iso_sig[sig])(port);
+ return SUPER(ret, sig, 0);
+}
+
+static unsigned int tc_vbus_cc_iso_entry(int port)
+{
+ /* Isolate the Host-side port from the Charge-Through port */
+ vpd_vbus_pass_en(0);
+
+ /* Remove Charge-Through side port CCs */
+ vpd_ct_cc_sel(CT_OPEN);
+
+ /* Enable mcu communication and cc */
+ vpd_mcu_cc_en(1);
+
+ return 0;
+}
+
+static unsigned int tc_vbus_cc_iso_run(int port)
+{
+ return 0;
+}
+
+/**
+ * Unattached.SRC
+ *
+ * Super State Entry Actions:
+ * Isolate the Host-side port from the Charge-Through port
+ * Enable mcu communication
+ * Place RpUSB on Host CC
+ * Place Rd on Charge-Through CCs
+ */
+static unsigned int tc_unattached_src(int port, enum signal sig)
+{
+ int ret;
+
+ ret = (*tc_unattached_src_sig[sig])(port);
+ return SUPER(ret, sig, tc_host_rpu_ct_rd);
+}
+
+static unsigned int tc_unattached_src_entry(int port)
+{
+ tc[port].state_id = UNATTACHED_SRC;
+ if (tc[port].obj.last_state != tc_unattached_snk)
+ CPRINTS("C%d: %s", port, tc_state_names[tc[port].state_id]);
+
+ /* Get power from VBUS */
+ vpd_vconn_pwr_sel_odl(PWR_VBUS);
+
+ /* Make sure it's the Charge-Through Port's VBUS */
+ if (!vpd_is_ct_vbus_present()) {
+ set_state(port, TC_OBJ(port), tc_error_recovery);
+ return 0;
+ }
+
+ tc[port].next_role_swap = get_time().val + PD_T_DRP_SRC;
+
+ return 0;
+}
+
+static unsigned int tc_unattached_src_run(int port)
+{
+ int host_cc;
+
+ /* Check Host CC for connection */
+ vpd_host_get_cc(&host_cc);
+
+ /*
+ * Transition to AttachWait.SRC when host-side VBUS is
+ * vSafe0V and SRC.Rd state is detected on the Host-side
+ * port’s CC pin.
+ */
+ if (!vpd_is_host_vbus_present() && host_cc == TYPEC_CC_VOLT_RD) {
+ set_state(port, TC_OBJ(port), tc_attach_wait_src);
+ return 0;
+ }
+
+ /*
+ * Transition to Unattached.SNK within tDRPTransition or
+ * if Charge-Through VBUS is removed.
+ */
+ if (!vpd_is_ct_vbus_present() ||
+ get_time().val > tc[port].next_role_swap) {
+ set_state(port, TC_OBJ(port), tc_unattached_snk);
+ return 0;
+ }
+
+ return RUN_SUPER;
+}
+
+/**
+ * AttachWait.SRC
+ *
+ * Super State Entry Actions:
+ * Isolate the Host-side port from the Charge-Through port
+ * Enable mcu communication
+ * Place RpUSB on Host CC
+ * Place Rd on Charge-Through CCs
+ */
+static unsigned int tc_attach_wait_src(int port, enum signal sig)
+{
+ int ret;
+
+ ret = (*tc_attach_wait_src_sig[sig])(port);
+ return SUPER(ret, sig, tc_host_rpu_ct_rd);
+}
+
+static unsigned int tc_attach_wait_src_entry(int port)
+{
+ tc[port].state_id = ATTACH_WAIT_SRC;
+ CPRINTS("C%d: %s", port, tc_state_names[tc[port].state_id]);
+
+ tc[port].host_cc_state = PD_CC_UNSET;
+
+ return 0;
+}
+
+static unsigned int tc_attach_wait_src_run(int port)
+{
+ int host_new_cc_state;
+ int host_cc;
+
+ /* Check Host CC for connection */
+ vpd_host_get_cc(&host_cc);
+
+ if (host_cc == TYPEC_CC_VOLT_RD)
+ host_new_cc_state = PD_CC_UFP_ATTACHED;
+ else
+ host_new_cc_state = PD_CC_NONE;
+
+ /*
+ * A Charge-Through VCONN-Powered USB Device shall transition
+ * to Unattached.SNK when the SRC.Open state is detected on the
+ * Host-side port’s CC or if Charge-Through VBUS falls below
+ * vSinkDisconnect. The Charge-Through VCONN-Powered USB Device
+ * shall detect the SRC.Open state within tSRCDisconnect, but
+ * should detect it as quickly as possible.
+ */
+ if (host_new_cc_state == PD_CC_NONE || !vpd_is_ct_vbus_present()) {
+ set_state(port, TC_OBJ(port), tc_unattached_snk);
+ return 0;
+ }
+
+ /* Debounce the Host CC state */
+ if (tc[port].host_cc_state != host_new_cc_state) {
+ tc[port].host_cc_state = host_new_cc_state;
+ tc[port].cc_debounce = get_time().val + PD_T_CC_DEBOUNCE;
+ return 0;
+ }
+
+ /* Wait for Host CC debounce */
+ if (get_time().val < tc[port].cc_debounce)
+ return 0;
+
+ /*
+ * A Charge-Through VCONN-Powered USB Device shall transition to
+ * Try.SNK when the host-side VBUS is at vSafe0V and the SRC.Rd
+ * state is on the Host-side port’s CC pin for at least tCCDebounce.
+ */
+ if (tc[port].host_cc_state == PD_CC_UFP_ATTACHED &&
+ !vpd_is_host_vbus_present()) {
+ set_state(port, TC_OBJ(port), tc_try_snk);
+ return 0;
+ }
+
+ return RUN_SUPER;
+}
+
+/**
+ * Attached.SRC
+ */
+static unsigned int tc_attached_src(int port, enum signal sig)
+{
+ int ret;
+
+ ret = (*tc_attached_src_sig[sig])(port);
+ return SUPER(ret, sig, 0);
+}
+
+static unsigned int tc_attached_src_entry(int port)
+{
+ tc[port].state_id = ATTACHED_SRC;
+ CPRINTS("C%d: %s", port, tc_state_names[tc[port].state_id]);
+
+ /* Enable PD */
+ tc[port].pd_enable = 1;
+ set_polarity(port, 0);
+
+ /* Connect Charge-Through VBUS to Host VBUS */
+ vpd_vbus_pass_en(1);
+
+ /*
+ * Get power from VBUS. No need to test because
+ * the Host VBUS is connected to the Charge-Through
+ * VBUS
+ */
+ vpd_vconn_pwr_sel_odl(PWR_VBUS);
+
+ return 0;
+}
+
+static unsigned int tc_attached_src_run(int port)
+{
+ int host_cc;
+
+ /* Check Host CC for connection */
+ vpd_host_get_cc(&host_cc);
+
+ /*
+ * A Charge-Through VCONN-Powered USB Device shall transition to
+ * Unattached.SNK when VBUS falls below vSinkDisconnect or the
+ * Host-side port’s CC pin is SRC.Open. The Charge-Through
+ * VCONNPowered USB Device shall detect the SRC.Open state within
+ * tSRCDisconnect, but should detect it as quickly as possible.
+ */
+ if (!vpd_is_ct_vbus_present() || host_cc == TYPEC_CC_VOLT_OPEN)
+ set_state(port, TC_OBJ(port), tc_unattached_snk);
+
+ return 0;
+}
+
+/**
+ * Super State HOST_RPU_CT_RD
+ */
+static unsigned int tc_host_rpu_ct_rd(int port, enum signal sig)
+{
+ int ret;
+
+ ret = (*tc_host_rpu_ct_rd_sig[sig])(port);
+ return SUPER(ret, sig, tc_vbus_cc_iso);
+}
+
+static unsigned int tc_host_rpu_ct_rd_entry(int port)
+{
+ /* Place RpUSB on Host CC */
+ vpd_host_set_pull(TYPEC_CC_RP, TYPEC_RP_USB);
+
+ /* Place Rd on Charge-Through CCs */
+ vpd_ct_set_pull(TYPEC_CC_RD, 0);
+
+ return 0;
+}
+
+static unsigned int tc_host_rpu_ct_rd_run(int port)
+{
+ return RUN_SUPER;
+}
+
+/**
+ * Try.SNK
+ *
+ * Super State Entry Actions:
+ * Isolate the Host-side port from the Charge-Through port
+ * Enable mcu communication
+ * Place Ra on VCONN and Rd on Host CC
+ * Place Rd on Charge-Through CCs
+ */
+static unsigned int tc_try_snk(int port, enum signal sig)
+{
+ int ret;
+
+ ret = (*tc_try_snk_sig[sig])(port);
+ return SUPER(ret, sig, tc_host_rard_ct_rd);
+}
+
+static unsigned int tc_try_snk_entry(int port)
+{
+ tc[port].state_id = TRY_SNK;
+ CPRINTS("C%d: %s", port, tc_state_names[tc[port].state_id]);
+
+ /* Get power from VBUS */
+ vpd_vconn_pwr_sel_odl(PWR_VBUS);
+
+ /* Make sure it's the Charge-Through Port's VBUS */
+ if (!vpd_is_ct_vbus_present()) {
+ set_state(port, TC_OBJ(port), tc_error_recovery);
+ return 0;
+ }
+
+ tc[port].host_cc_state = PD_CC_UNSET;
+
+ /* Using next_role_swap timer as try_src timer */
+ tc[port].next_role_swap = get_time().val + PD_T_DRP_TRY;
+
+ return 0;
+}
+
+static unsigned int tc_try_snk_run(int port)
+{
+ int host_new_cc_state;
+ int host_cc;
+
+ /*
+ * Wait for tDRPTry before monitoring the Charge-Through
+ * port’s CC pins for the SNK.Rp
+ */
+ if (get_time().val < tc[port].next_role_swap)
+ return 0;
+
+ /* Check Host CC for connection */
+ vpd_host_get_cc(&host_cc);
+
+ if (cc_is_rp(host_cc))
+ host_new_cc_state = PD_CC_DFP_ATTACHED;
+ else
+ host_new_cc_state = PD_CC_NONE;
+
+ /* Debounce the Host CC state */
+ if (tc[port].host_cc_state != host_new_cc_state) {
+ tc[port].host_cc_state = host_new_cc_state;
+ tc[port].cc_debounce = get_time().val + PD_T_DEBOUNCE;
+ return 0;
+ }
+
+ /* Wait for Host CC debounce */
+ if (get_time().val < tc[port].cc_debounce)
+ return 0;
+
+ /*
+ * The Charge-Through VCONN-Powered USB Device shall then transition to
+ * Attached.SNK when the SNK.Rp state is detected on the Host-side
+ * port’s CC pin for at least tTryCCDebounce and VBUS or VCONN is
+ * detected on Host-side port.
+ *
+ * Alternatively, the Charge-Through VCONN-Powered USB Device shall
+ * transition to TryWait.SRC if Host-side SNK.Rp state is not detected
+ * for tTryCCDebounce.
+ */
+ if (tc[port].host_cc_state == PD_CC_DFP_ATTACHED &&
+ (vpd_is_host_vbus_present() || vpd_is_vconn_present()))
+ set_state(port, TC_OBJ(port), tc_attached_snk);
+ else if (tc[port].host_cc_state == PD_CC_NONE)
+ set_state(port, TC_OBJ(port), tc_try_wait_src);
+
+ return 0;
+}
+
+/**
+ * TryWait.SRC
+ *
+ * Super State Entry Actions:
+ * Isolate the Host-side port from the Charge-Through port
+ * Enable mcu communication
+ * Place RpUSB on Host CC
+ * Place Rd on Charge-Through CCs
+ */
+static unsigned int tc_try_wait_src(int port, enum signal sig)
+{
+ int ret;
+
+ ret = (*tc_try_wait_src_sig[sig])(port);
+ return SUPER(ret, sig, tc_host_rpu_ct_rd);
+}
+
+static unsigned int tc_try_wait_src_entry(int port)
+{
+ tc[port].state_id = TRY_WAIT_SRC;
+ CPRINTS("C%d: %s", port, tc_state_names[tc[port].state_id]);
+
+ tc[port].host_cc_state = PD_CC_UNSET;
+ tc[port].next_role_swap = get_time().val + PD_T_DRP_TRY;
+
+ return 0;
+}
+
+static unsigned int tc_try_wait_src_run(int port)
+{
+ int host_new_cc_state;
+ int host_cc;
+
+ /* Check Host CC for connection */
+ vpd_host_get_cc(&host_cc);
+
+ if (host_cc == TYPEC_CC_VOLT_RD)
+ host_new_cc_state = PD_CC_UFP_ATTACHED;
+ else
+ host_new_cc_state = PD_CC_NONE;
+
+ /* Debounce the Host CC state */
+ if (tc[port].host_cc_state != host_new_cc_state) {
+ tc[port].host_cc_state = host_new_cc_state;
+ tc[port].host_cc_debounce =
+ get_time().val + PD_T_TRY_CC_DEBOUNCE;
+ return 0;
+ }
+
+ if (get_time().val > tc[port].host_cc_debounce) {
+ /*
+ * A Charge-Through VCONN-Powered USB Device shall transition
+ * to Attached.SRC when host-side VBUS is at vSafe0V and the
+ * SRC.Rd state is detected on the Host-side port’s CC pin for
+ * at least tTryCCDebounce.
+ */
+ if (tc[port].host_cc_state == PD_CC_UFP_ATTACHED &&
+ !vpd_is_host_vbus_present()) {
+ set_state(port, TC_OBJ(port), tc_attached_src);
+ return 0;
+ }
+ }
+
+ if (get_time().val > tc[port].next_role_swap) {
+ /*
+ * The Charge-Through VCONN-Powered USB Device shall transition
+ * to Unattached.SNK after tDRPTry if the Host-side port’s CC
+ * pin is not in the SRC.Rd state.
+ */
+ if (tc[port].host_cc_state == PD_CC_NONE) {
+ set_state(port, TC_OBJ(port), tc_unattached_snk);
+ return 0;
+ }
+ }
+
+ return RUN_SUPER;
+}
+
+/**
+ * CTTry.SNK
+ *
+ * Super State Entry Actions:
+ * Isolate the Host-side port from the Charge-Through port
+ * Enable mcu communication
+ * Place RP3A0 on Host CC
+ * Connect Charge-Through Rd
+ * Get power from VCONN
+ */
+static unsigned int tc_ct_try_snk(int port, enum signal sig)
+{
+ int ret;
+
+ ret = (*tc_ct_try_snk_sig[sig])(port);
+ return SUPER(ret, sig, tc_host_rp3_ct_rd);
+}
+
+static unsigned int tc_ct_try_snk_entry(int port)
+{
+ tc[port].state_id = CTTRY_SNK;
+ CPRINTS("C%d: %s", port, tc_state_names[tc[port].state_id]);
+
+ /* Enable PD */
+ tc[port].pd_enable = 1;
+ set_polarity(port, 0);
+
+ tc[port].cc_state = PD_CC_UNSET;
+ tc[port].next_role_swap = get_time().val + PD_T_DRP_TRY;
+
+ return 0;
+}
+
+static unsigned int tc_ct_try_snk_run(int port)
+{
+ int new_cc_state;
+ int cc1;
+ int cc2;
+
+ /*
+ * Wait for tDRPTry before monitoring the Charge-Through
+ * port’s CC pins for the SNK.Rp
+ */
+ if (get_time().val < tc[port].next_role_swap)
+ return 0;
+
+ /* Check CT CC for connection */
+ vpd_ct_get_cc(&cc1, &cc2);
+
+ if (cc_is_rp(cc1) || cc_is_rp(cc2))
+ new_cc_state = PD_CC_DFP_ATTACHED;
+ else
+ new_cc_state = PD_CC_NONE;
+
+ /*
+ * The Charge-Through VCONN-Powered USB Device shall transition
+ * to Unattached.SNK if VCONN falls below vVCONNDisconnect.
+ */
+ if (!vpd_is_vconn_present()) {
+ set_state(port, TC_OBJ(port), tc_unattached_snk);
+ return 0;
+ }
+
+ /* Debounce the CT CC state */
+ if (tc[port].cc_state != new_cc_state) {
+ tc[port].cc_state = new_cc_state;
+ tc[port].cc_debounce = get_time().val + PD_T_DEBOUNCE;
+ tc[port].try_wait_debounce = get_time().val + PD_T_TRY_WAIT;
+
+ return 0;
+ }
+
+ if (get_time().val > tc[port].cc_debounce) {
+ /*
+ * The Charge-Through VCONN-Powered USB Device shall then
+ * transition to CTAttached.VPD when the SNK.Rp state is
+ * detected on the Charge-Through port’s CC pins for at
+ * least tTryCCDebounce and VBUS is detected on
+ * Charge-Through port.
+ */
+ if (tc[port].cc_state == PD_CC_DFP_ATTACHED &&
+ vpd_is_ct_vbus_present()) {
+ set_state(port, TC_OBJ(port), tc_ct_attached_vpd);
+ return 0;
+ }
+ }
+
+ if (get_time().val > tc[port].try_wait_debounce) {
+ /*
+ * A Charge-Through VCONN-Powered USB Device shall transition
+ * to CTAttached.Unsupported if SNK.Rp state is not detected
+ * for tDRPTryWait.
+ */
+ if (tc[port].cc_state == PD_CC_NONE) {
+ set_state(port, TC_OBJ(port),
+ tc_ct_attached_unsupported);
+ return 0;
+ }
+ }
+
+ return RUN_SUPER;
+}
+
+static unsigned int tc_ct_try_snk_exit(int port)
+{
+ /* Disable PD */
+ tc[port].pd_enable = 0;
+
+ return 0;
+}
+
+/**
+ * CTAttachWait.Unsupported
+ *
+ * Super State Entry Actions:
+ * Isolate the Host-side port from the Charge-Through port
+ * Enable mcu communication
+ * Place RP3A0 on Host CC
+ * Place RPUSB on Charge-Through CC
+ * Get power from VCONN
+ */
+static unsigned int tc_ct_attach_wait_unsupported(int port, enum signal sig)
+{
+ int ret;
+
+ ret = (*tc_ct_attach_wait_unsupported_sig[sig])(port);
+ return SUPER(ret, sig, tc_host_rp3_ct_rpu);
+}
+
+static unsigned int tc_ct_attach_wait_unsupported_entry(int port)
+{
+ tc[port].state_id = CTATTACH_WAIT_UNSUPPORTED;
+ CPRINTS("C%d: %s", port, tc_state_names[tc[port].state_id]);
+
+ /* Enable PD */
+ tc[port].pd_enable = 1;
+ set_polarity(port, 0);
+
+ tc[port].cc_state = PD_CC_UNSET;
+
+ return 0;
+}
+
+static unsigned int tc_ct_attach_wait_unsupported_run(int port)
+{
+ int new_cc_state;
+ int cc1;
+ int cc2;
+
+ /* Check CT CC for connection */
+ vpd_ct_get_cc(&cc1, &cc2);
+
+ if (cc_is_at_least_one_rd(cc1, cc2))
+ new_cc_state = PD_CC_DFP_ATTACHED;
+ else if (cc_is_audio_acc(cc1, cc2))
+ new_cc_state = PD_CC_AUDIO_ACC;
+ else /* (cc1 == TYPEC_CC_VOLT_OPEN or cc2 == TYPEC_CC_VOLT_OPEN */
+ new_cc_state = PD_CC_NONE;
+
+ /*
+ * A Charge-Through VCONN-Powered USB Device shall transition to
+ * Unattached.SNK if VCONN falls below vVCONNDisconnect.
+ */
+ if (!vpd_is_vconn_present()) {
+ set_state(port, TC_OBJ(port), tc_unattached_snk);
+ return 0;
+ }
+
+ /* Debounce the cc state */
+ if (tc[port].cc_state != new_cc_state) {
+ tc[port].cc_state = new_cc_state;
+ tc[port].cc_debounce = get_time().val + PD_T_CC_DEBOUNCE;
+ return 0;
+ }
+
+ /* Wait for CC debounce */
+ if (get_time().val < tc[port].cc_debounce)
+ return 0;
+
+ /*
+ * A Charge-Through VCONN-Powered USB Device shall transition to
+ * CTUnattached.VPD when the state of either the Charge-Through
+ * Port’s CC1 or CC2 pin is SRC.Open for at least tCCDebounce.
+ *
+ * A Charge-Through VCONN-Powered USB Device shall transition to
+ * CTTry.SNK if the state of at least one of the Charge-Through
+ * port’s CC pins is SRC.Rd, or if the state of both the CC1 and CC2
+ * pins is SRC.Ra. for at least tCCDebounce.
+ */
+ if (new_cc_state == PD_CC_NONE)
+ set_state(port, TC_OBJ(port), tc_ct_unattached_vpd);
+ else /* PD_CC_DFP_ATTACHED or PD_CC_AUDIO_ACC */
+ set_state(port, TC_OBJ(port), tc_ct_try_snk);
+
+ return 0;
+}
+
+static unsigned int tc_ct_attach_wait_unsupported_exit(int port)
+{
+ /* Disable PD */
+ tc[port].pd_enable = 0;
+
+ return 0;
+}
+
+/**
+ * CTAttached.Unsupported
+ *
+ * Super State Entry Actions:
+ * Isolate the Host-side port from the Charge-Through port
+ * Enable mcu communication
+ * Place RP3A0 on Host CC
+ * Place RPUSB on Charge-Through CC
+ * Get power from VCONN
+ */
+static unsigned int tc_ct_attached_unsupported(int port, enum signal sig)
+{
+ int ret;
+
+ ret = (*tc_ct_attached_unsupported_sig[sig])(port);
+ return SUPER(ret, sig, tc_host_rp3_ct_rpu);
+}
+
+static unsigned int tc_ct_attached_unsupported_entry(int port)
+{
+ tc[port].state_id = CTATTACHED_UNSUPPORTED;
+ CPRINTS("C%d: %s", port, tc_state_names[tc[port].state_id]);
+
+ /* Present Billboard device */
+ vpd_present_billboard(BB_SNK);
+
+ return 0;
+}
+
+static unsigned int tc_ct_attached_unsupported_run(int port)
+{
+ int cc1;
+ int cc2;
+
+ /* Check CT CC for connection */
+ vpd_ct_get_cc(&cc1, &cc2);
+
+ if (!vpd_is_vconn_present()) {
+ set_state(port, TC_OBJ(port), tc_unattached_snk);
+ return 0;
+ }
+
+ /*
+ * The Charge-Through VCONN-Powered USB Device shall transition to
+ * CTUnattached.VPD when SRC.Open state is detected on both the
+ * Charge-Through port’s CC pins or the SRC.Open state is detected
+ * on one CC pin and SRC.Ra is detected on the other CC pin.
+ */
+ if ((cc1 == TYPEC_CC_VOLT_OPEN && cc2 == TYPEC_CC_VOLT_OPEN) ||
+ (cc1 == TYPEC_CC_VOLT_OPEN && cc2 == TYPEC_CC_VOLT_RA) ||
+ (cc1 == TYPEC_CC_VOLT_RA && cc2 == TYPEC_CC_VOLT_OPEN)) {
+ set_state(port, TC_OBJ(port), tc_ct_unattached_vpd);
+ return 0;
+ }
+
+ return RUN_SUPER;
+}
+
+static unsigned int tc_ct_attached_unsupported_exit(int port)
+{
+ vpd_present_billboard(BB_NONE);
+
+ return 0;
+}
+
+/**
+ * CTUnattached.Unsupported
+ *
+ * Super State Entry Actions:
+ * Isolate the Host-side port from the Charge-Through port
+ * Enable mcu communication
+ * Place RP3A0 on Host CC
+ * Place RPUSB on Charge-Through CC
+ * Get power from VCONN
+ */
+static unsigned int tc_ct_unattached_unsupported(int port, enum signal sig)
+{
+ int ret;
+
+ ret = (*tc_ct_unattached_unsupported_sig[sig])(port);
+ return SUPER(ret, sig, tc_host_rp3_ct_rpu);
+}
+
+static unsigned int tc_ct_unattached_unsupported_entry(int port)
+{
+ tc[port].state_id = CTUNATTACHED_UNSUPPORTED;
+ if (tc[port].obj.last_state != tc_ct_unattached_vpd)
+ CPRINTS("C%d: %s", port, tc_state_names[tc[port].state_id]);
+
+ /* Enable PD */
+ tc[port].pd_enable = 1;
+ set_polarity(port, 0);
+
+ tc[port].next_role_swap = get_time().val + PD_T_DRP_SRC;
+
+ return 0;
+}
+
+static unsigned int tc_ct_unattached_unsupported_run(int port)
+{
+ int cc1;
+ int cc2;
+
+ /* Check CT CC for connection */
+ vpd_ct_get_cc(&cc1, &cc2);
+
+ /*
+ * A Charge-Through VCONN-Powered USB Device shall transition to
+ * CTAttachWait.Unsupported when a Sink connection is detected on
+ * the Charge-Through port, as indicated by the SRC.Rd state on at
+ * least one of the Charge-Through port’s CC pins or SRC.Ra state
+ * on both the CC1 and CC2 pins.
+ */
+ if (cc_is_at_least_one_rd(cc1, cc2) || cc_is_audio_acc(cc1, cc2)) {
+ set_state(port, TC_OBJ(port),
+ tc_ct_attach_wait_unsupported);
+ return 0;
+ }
+
+ /*
+ * A Charge-Through VCONN-Powered USB Device shall transition to
+ * Unattached.SNK if VCONN falls below vVCONNDisconnect.
+ */
+ if (!vpd_is_vconn_present()) {
+ set_state(port, TC_OBJ(port), tc_unattached_snk);
+ return 0;
+ }
+
+ /*
+ * A Charge-Through VCONN-Powered USB Device shall transition to
+ * CTUnattached.VPD within tDRPTransition after dcSRC.DRP ∙ tDRP.
+ */
+ if (get_time().val > tc[port].next_role_swap) {
+ set_state(port, TC_OBJ(port), tc_ct_unattached_vpd);
+ return 0;
+ }
+
+ return RUN_SUPER;
+}
+
+static unsigned int tc_ct_unattached_unsupported_exit(int port)
+{
+ /* Disable PD */
+ tc[port].pd_enable = 0;
+
+ return 0;
+}
+
+/**
+ * CTUnattached.VPD
+ *
+ * Super State Entry Actions:
+ * Isolate the Host-side port from the Charge-Through port
+ * Enable mcu communication
+ * Place RP3A0 on Host CC
+ * Connect Charge-Through Rd
+ * Get power from VCONN
+ */
+static unsigned int tc_ct_unattached_vpd(int port, enum signal sig)
+{
+ int ret;
+
+ ret = (*tc_ct_unattached_vpd_sig[sig])(port);
+ return SUPER(ret, sig, tc_host_rp3_ct_rd);
+}
+
+static unsigned int tc_ct_unattached_vpd_entry(int port)
+{
+ tc[port].state_id = CTUNATTACHED_VPD;
+ if (tc[port].obj.last_state != tc_ct_unattached_unsupported)
+ CPRINTS("C%d: %s", port, tc_state_names[tc[port].state_id]);
+
+ /* Enable PD */
+ tc[port].pd_enable = 1;
+ set_polarity(port, 0);
+
+ tc[port].cc_state = PD_CC_UNSET;
+
+ return 0;
+}
+
+static unsigned int tc_ct_unattached_vpd_run(int port)
+{
+ int new_cc_state;
+ int cc1;
+ int cc2;
+
+ /* Check CT CC for connection */
+ vpd_ct_get_cc(&cc1, &cc2);
+
+ if (cc_is_rp(cc1) != cc_is_rp(cc2))
+ new_cc_state = PD_CC_DFP_ATTACHED;
+ else if (!cc_is_rp(cc1) && !cc_is_rp(cc2))
+ new_cc_state = PD_CC_NONE;
+ else
+ new_cc_state = PD_CC_UNSET;
+
+ /*
+ * A Charge-Through VCONN-Powered USB Device shall transition to
+ * CTAttachWait.VPD when a Source connection is detected on the
+ * Charge-Through port, as indicated by the SNK.Rp state on
+ * exactly one of the Charge-Through port’s CC pins.
+ */
+ if (new_cc_state == PD_CC_DFP_ATTACHED) {
+ set_state(port, TC_OBJ(port),
+ tc_ct_attach_wait_vpd);
+ return 0;
+ }
+
+ /*
+ * A Charge-Through VCONN-Powered USB Device shall transition to
+ * Unattached.SNK if VCONN falls below vVCONNDisconnect.
+ */
+ if (!vpd_is_vconn_present()) {
+ set_state(port, TC_OBJ(port),
+ tc_unattached_snk);
+ return 0;
+ }
+
+ /* Debounce the cc state */
+ if (new_cc_state != tc[port].cc_state) {
+ tc[port].cc_state = new_cc_state;
+ tc[port].cc_debounce = get_time().val + PD_T_DRP_SRC;
+ return 0;
+ }
+
+ if (get_time().val < tc[port].cc_debounce)
+ return 0;
+
+ /*
+ * A Charge-Through VCONN-Powered USB Device shall transition to
+ * CTUnattached.Unsupported within tDRPTransition after the state
+ * of both the Charge-Through port’s CC1 and CC2 pins is SNK.Open
+ * for tDRP-dcSRC.DRP ∙ tDRP, or if directed.
+ */
+ if (tc[port].cc_state == PD_CC_NONE) {
+ set_state(port, TC_OBJ(port),
+ tc_ct_unattached_unsupported);
+ return 0;
+ }
+
+ return RUN_SUPER;
+}
+
+static unsigned int tc_ct_unattached_vpd_exit(int port)
+{
+ /* Disable PD */
+ tc[port].pd_enable = 0;
+
+ return 0;
+}
+
+/**
+ * CTDisabled.VPD
+ *
+ * Super State Entry Actions:
+ * Isolate the Host-side port from the Charge-Through port
+ * Enable mcu communication
+ * Remove the terminations from Host
+ * Remove the terminations from Charge-Through
+ */
+static unsigned int tc_ct_disabled_vpd(int port, enum signal sig)
+{
+ int ret;
+
+ ret = (*tc_ct_disabled_vpd_sig[sig])(port);
+ return SUPER(ret, sig, tc_host_open_ct_open);
+}
+
+static unsigned int tc_ct_disabled_vpd_entry(int port)
+{
+ tc[port].state_id = CTDISABLED_VPD;
+ CPRINTS("C%d: %s", port, tc_state_names[tc[port].state_id]);
+
+ /* Get power from VBUS */
+ vpd_vconn_pwr_sel_odl(PWR_VBUS);
+
+ tc[port].next_role_swap = get_time().val + PD_T_VPDDISABLE;
+
+ return 0;
+}
+
+static unsigned int tc_ct_disabled_vpd_run(int port)
+{
+ /*
+ * A Charge-Through VCONN-Powered USB Device shall transition
+ * to Unattached.SNK after tVPDDisable.
+ */
+ if (get_time().val > tc[port].next_role_swap)
+ set_state(port, TC_OBJ(port), tc_unattached_snk);
+
+ return 0;
+}
+
+/**
+ * CTAttached.VPD
+ */
+static unsigned int tc_ct_attached_vpd(int port, enum signal sig)
+{
+ int ret;
+
+ ret = (*tc_ct_attached_vpd_sig[sig])(port);
+ return SUPER(ret, sig, 0);
+}
+
+static unsigned int tc_ct_attached_vpd_entry(int port)
+{
+ int cc1;
+ int cc2;
+
+ tc[port].state_id = CTATTACHED_VPD;
+ CPRINTS("C%d: %s", port, tc_state_names[tc[port].state_id]);
+
+ /* Get power from VCONN */
+ vpd_vconn_pwr_sel_odl(PWR_VCONN);
+
+ /*
+ * Detect which of the Charge-Through port’s CC1 or CC2
+ * pins is connected through the cable
+ */
+ vpd_ct_get_cc(&cc1, &cc2);
+ tc[port].ct_cc = cc_is_rp(cc2) ? CT_CC2 : CT_CC1;
+
+ /*
+ * 1. Remove or reduce any additional capacitance on the
+ * Host-side CC port
+ */
+ vpd_mcu_cc_en(0);
+
+ /*
+ * 2. Disable the Rp termination advertising 3.0 A on the
+ * host port’s CC pin
+ */
+ vpd_host_set_pull(TYPEC_CC_OPEN, 0);
+
+ /*
+ * 3. Passively multiplex the detected Charge-Through port’s
+ * CC pin through to the host port’s CC
+ */
+ vpd_ct_cc_sel(tc[port].ct_cc);
+
+ /*
+ * 4. Disable the Rd on the Charge-Through port’s CC1 and CC2
+ * pins
+ */
+ vpd_ct_set_pull(TYPEC_CC_OPEN, 0);
+
+ /*
+ * 5. Connect the Charge-Through port’s VBUS through to the
+ * host port’s VBUS
+ */
+ vpd_vbus_pass_en(1);
+
+ tc[port].cc_state = PD_CC_UNSET;
+
+ return 0;
+}
+
+static unsigned int tc_ct_attached_vpd_run(int port)
+{
+ int new_cc_state;
+ int cc1;
+ int cc2;
+
+ /*
+ * A Charge-Through VCONN-Powered USB Device shall transition to
+ * CTDisabled.VPD if VCONN falls below vVCONNDisconnect.
+ */
+ if (!vpd_is_vconn_present()) {
+ set_state(port, TC_OBJ(port), tc_ct_disabled_vpd);
+ return 0;
+ }
+
+ /* Check CT CC for connection */
+ vpd_ct_get_cc(&cc1, &cc2);
+ if ((tc[port].ct_cc ? cc2 : cc1) == TYPEC_CC_VOLT_OPEN)
+ new_cc_state = PD_CC_NONE;
+ else
+ new_cc_state = PD_CC_DFP_ATTACHED;
+
+ /* Debounce the cc state */
+ if (new_cc_state != tc[port].cc_state) {
+ tc[port].cc_state = new_cc_state;
+ tc[port].cc_debounce = get_time().val + PD_T_VPDCTDD;
+ return 0;
+ }
+
+ if (get_time().val < tc[port].pd_debounce)
+ return 0;
+
+ /*
+ * A Charge-Through VCONN-Powered USB Device shall transition to
+ * CTUnattached.VPD when VBUS falls below vSinkDisconnect and the
+ * state of the passed-through CC pin is SNK.Open for tVPDCTDD.
+ */
+ if (tc[port].cc_state == PD_CC_NONE && !vpd_is_ct_vbus_present())
+ set_state(port, TC_OBJ(port), tc_ct_unattached_vpd);
+
+ return 0;
+}
+
+/**
+ * CTAttachWait.VPD
+ *
+ * Super State Entry Actions:
+ * Isolate the Host-side port from the Charge-Through port
+ * Enable mcu communication
+ * Place RP3A0 on Host CC
+ * Connect Charge-Through Rd
+ * Get power from VCONN
+ */
+static unsigned int tc_ct_attach_wait_vpd(int port, enum signal sig)
+{
+ int ret;
+
+ ret = (*tc_ct_attach_wait_vpd_sig[sig])(port);
+ return SUPER(ret, sig, tc_host_rp3_ct_rd);
+}
+
+static unsigned int tc_ct_attach_wait_vpd_entry(int port)
+{
+ tc[port].state_id = CTATTACH_WAIT_VPD;
+ CPRINTS("C%d: %s", port, tc_state_names[tc[port].state_id]);
+
+ /* Enable PD */
+ tc[port].pd_enable = 1;
+ set_polarity(port, 0);
+
+ tc[port].cc_state = PD_CC_UNSET;
+
+ /* Sample CCs every 2ms */
+ tc_set_timeout(port, 2 * MSEC);
+ return 0;
+}
+
+static unsigned int tc_ct_attach_wait_vpd_run(int port)
+{
+ int new_cc_state;
+ int cc1;
+ int cc2;
+
+ /* Check CT CC for connection */
+ vpd_ct_get_cc(&cc1, &cc2);
+
+ if (cc_is_rp(cc1) != cc_is_rp(cc2))
+ new_cc_state = PD_CC_DFP_ATTACHED;
+ else if (!cc_is_rp(cc1) && !cc_is_rp(cc2))
+ new_cc_state = PD_CC_NONE;
+ else
+ new_cc_state = PD_CC_UNSET;
+
+ /*
+ * A Charge-Through VCONN-Powered USB Device shall transition to
+ * CTDisabled.VPD if VCONN falls below vVCONNDisconnect.
+ */
+ if (!vpd_is_vconn_present()) {
+ set_state(port, TC_OBJ(port), tc_ct_disabled_vpd);
+ return 0;
+ }
+
+ /* Debounce the cc state */
+ if (new_cc_state != tc[port].cc_state) {
+ tc[port].cc_state = new_cc_state;
+ tc[port].cc_debounce = get_time().val +
+ PD_T_CC_DEBOUNCE;
+ tc[port].pd_debounce = get_time().val +
+ PD_T_PD_DEBOUNCE;
+ return 0;
+ }
+
+ if (get_time().val > tc[port].pd_debounce) {
+ /*
+ * A Charge-Through VCONN-Powered USB Device shall transition
+ * to CTUnattached.VPD when the state of both the Charge-Through
+ * port’s CC1 and CC2 pins are SNK.Open for at least
+ * tPDDebounce.
+ */
+ if (tc[port].cc_state == PD_CC_NONE) {
+ set_state(port, TC_OBJ(port),
+ tc_ct_unattached_vpd);
+ return 0;
+ }
+ }
+
+ if (get_time().val > tc[port].cc_debounce) {
+ /*
+ * A Charge-Through VCONN-Powered USB Device shall transition to
+ * CTAttached.VPD after the state of only one of the
+ * Charge-Through port’s CC1 or CC2 pins is SNK.Rp for at
+ * least tCCDebounce and VBUS on the Charge-Through port is
+ * detected.
+ */
+ if (tc[port].cc_state == PD_CC_DFP_ATTACHED &&
+ vpd_is_ct_vbus_present()) {
+ set_state(port, TC_OBJ(port), tc_ct_attached_vpd);
+ return 0;
+ }
+ }
+
+ return RUN_SUPER;
+}
+
+static unsigned int tc_ct_attach_wait_vpd_exit(int port)
+{
+ /* Disable PD */
+ tc[port].pd_enable = 0;
+
+ /* Reset timeout value to 10ms */
+ tc_set_timeout(port, 10 * MSEC);
+
+ return 0;
+}
+
+/**
+ * Super State HOST_RP3_CT_RD
+ */
+static unsigned int tc_host_rp3_ct_rd(int port, enum signal sig)
+{
+ int ret;
+
+ ret = (*tc_host_rp3_ct_rd_sig[sig])(port);
+
+ return SUPER(ret, sig, tc_vbus_cc_iso);
+}
+
+static unsigned int tc_host_rp3_ct_rd_entry(int port)
+{
+ /* Place RP3A0 on Host CC */
+ vpd_host_set_pull(TYPEC_CC_RP, TYPEC_RP_3A0);
+
+ /* Connect Charge-Through Rd */
+ vpd_ct_set_pull(TYPEC_CC_RD, 0);
+
+ /*
+ * A Charge-Through VCONN-Powered USB Device shall
+ * ensure that it is powered by VCONN
+ */
+
+ /* Make sure vconn is on */
+ if (!vpd_is_vconn_present())
+ set_state(port, TC_OBJ(port), tc_error_recovery);
+
+ /* Get power from VCONN */
+ vpd_vconn_pwr_sel_odl(PWR_VCONN);
+
+ return 0;
+}
+
+static unsigned int tc_host_rp3_ct_rd_run(int port)
+{
+ return 0;
+}
+
+/**
+ * Super State HOST_RP3_CT_RPU
+ */
+static unsigned int tc_host_rp3_ct_rpu(int port, enum signal sig)
+{
+ int ret;
+
+ ret = (*tc_host_rp3_ct_rpu_sig[sig])(port);
+ return SUPER(ret, sig, tc_vbus_cc_iso);
+}
+
+static unsigned int tc_host_rp3_ct_rpu_entry(int port)
+{
+ /* Place RP3A0 on Host CC */
+ vpd_host_set_pull(TYPEC_CC_RP, TYPEC_RP_3A0);
+
+ /* Place RPUSB on Charge-Through CC */
+ vpd_ct_set_pull(TYPEC_CC_RP, TYPEC_RP_USB);
+
+ /*
+ * A Charge-Through VCONN-Powered USB Device shall
+ * ensure that it is powered by VCONN
+ */
+
+ /* Make sure vconn is on */
+ if (!vpd_is_vconn_present())
+ set_state(port, TC_OBJ(port), tc_error_recovery);
+
+ /* Get power from VCONN */
+ vpd_vconn_pwr_sel_odl(PWR_VCONN);
+
+ return 0;
+}
+
+static unsigned int tc_host_rp3_ct_rpu_run(int port)
+{
+ return 0;
+}
diff --git a/common/usb_tc_sm.c b/common/usb_tc_sm.c
index 4f7039a546..68912b0c63 100644
--- a/common/usb_tc_sm.c
+++ b/common/usb_tc_sm.c
@@ -23,7 +23,6 @@
#include "usb_charge.h"
#include "usb_mux.h"
#include "usb_pd.h"
-#include "usb_pd_tcpm.h"
#include "usb_prl_sm.h"
#include "tcpm.h"
#include "usb_pe_sm.h"
@@ -32,23 +31,25 @@
#include "usb_tc_sm.h"
#include "version.h"
+/* Include USB Type-C State Machine Header File */
+#if defined(CONFIG_USB_TYPEC_CTVPD)
+#include "usb_tc_ctvpd_sm.h"
+#elif defined(CONFIG_USB_TYPEC_VPD)
+#include "usb_tc_vpd_sm.h"
+#else
+#error "A USB Type-C State Machine must be defined."
+#endif
+
#ifdef CONFIG_COMMON_RUNTIME
-#define CPRINTF(format, args...) cprintf(CC_HOOK, format, ## args)
-#define CPRINTS(format, args...) cprints(CC_HOOK, format, ## args)
+#define CPRINTF(format, args...) cprintf(CC_USB, format, ## args)
+#define CPRINTS(format, args...) cprints(CC_USB, format, ## args)
#else /* CONFIG_COMMON_RUNTIME */
#define CPRINTF(format, args...)
#define CPRINTS(format, args...)
#endif
-/* Private Function Prototypes */
-
-static inline int cc_is_rp(int cc);
-static inline enum pd_cc_polarity_type get_snk_polarity(int cc1, int cc2);
-static int tc_restart_tcpc(int port);
-static void set_polarity(int port, int polarity);
-
#ifdef CONFIG_COMMON_RUNTIME
-static const char * const tc_state_names[] = {
+const char * const tc_state_names[] = {
"Disabled",
"Unattached.SNK",
"AttachWait.SNK",
@@ -85,15 +86,6 @@ static const char * const tc_state_names[] = {
BUILD_ASSERT(ARRAY_SIZE(tc_state_names) == TC_STATE_COUNT);
#endif
-/* Include USB Type-C State Machine */
-#if defined(CONFIG_USB_TYPEC_CTVPD)
-#include "usb_tc_ctvpd_sm.h"
-#elif defined(CONFIG_USB_TYPEC_VPD)
-#include "usb_tc_vpd_sm.h"
-#else
-#error "A USB Type-C State Machine must be defined."
-#endif
-
/* Public Functions */
int tc_get_power_role(int port)
@@ -116,8 +108,6 @@ enum typec_state_id get_typec_state_id(int port)
return tc[port].state_id;
}
-/* Private Functions */
-
/*
* CC values for regular sources and Debug sources (aka DTS)
*
@@ -131,10 +121,7 @@ enum typec_state_id get_typec_state_id(int port)
* DTS USB-C @ 3 A Rp3A0 RpUSB
*/
-/**
- * Returns the polarity of a Sink.
- */
-static inline enum pd_cc_polarity_type get_snk_polarity(int cc1, int cc2)
+inline enum pd_cc_polarity_type get_snk_polarity(int cc1, int cc2)
{
/* the following assumes:
* TYPEC_CC_VOLT_RP_3_0 > TYPEC_CC_VOLT_RP_1_5
@@ -144,12 +131,12 @@ static inline enum pd_cc_polarity_type get_snk_polarity(int cc1, int cc2)
return (cc2 > cc1) ? POLARITY_CC2 : POLARITY_CC1;
}
-static int tc_restart_tcpc(int port)
+int tc_restart_tcpc(int port)
{
return tcpm_init(port);
}
-static void set_polarity(int port, int polarity)
+void set_polarity(int port, int polarity)
{
tcpm_set_polarity(port, polarity);
#ifdef CONFIG_USBC_PPC_POLARITY
diff --git a/common/usb_tc_vpd_sm.c b/common/usb_tc_vpd_sm.c
new file mode 100644
index 0000000000..33762257a0
--- /dev/null
+++ b/common/usb_tc_vpd_sm.c
@@ -0,0 +1,358 @@
+/* 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 "common.h"
+#include "console.h"
+#include "system.h"
+#include "task.h"
+#include "tcpm.h"
+#include "usb_pd.h"
+#include "usb_tc_sm.h"
+#include "usb_tc_vpd_sm.h"
+#include "vpd_api.h"
+
+/* USB Type-C VCONN Powered Device module */
+
+#ifdef CONFIG_COMMON_RUNTIME
+#define CPRINTF(format, args...) cprintf(CC_USB, format, ## args)
+#define CPRINTS(format, args...) cprints(CC_USB, format, ## args)
+#else /* CONFIG_COMMON_RUNTIME */
+#define CPRINTF(format, args...)
+#define CPRINTS(format, args...)
+#endif
+
+/* Type-C Layer Flags */
+#define TC_FLAGS_VCONN_ON BIT(0)
+
+#undef PD_DEFAULT_STATE
+/* Port default state at startup */
+#define PD_DEFAULT_STATE(port) tc_unattached_snk
+
+/**
+ * This is the Type-C Port object that contains information needed to
+ * implement a VCONN Powered Device.
+ */
+struct type_c tc[CONFIG_USB_PD_PORT_COUNT];
+
+/* Type-C states */
+DECLARE_STATE(tc, disabled, WITH_EXIT);
+DECLARE_STATE(tc, unattached_snk, NOOP_EXIT);
+DECLARE_STATE(tc, attach_wait_snk, NOOP_EXIT);
+DECLARE_STATE(tc, attached_snk, WITH_EXIT);
+
+/* Super States */
+DECLARE_STATE(tc, host_rard, NOOP_EXIT);
+DECLARE_STATE(tc, host_open, NOOP_EXIT);
+DECLARE_STATE(tc, vbus_cc_iso, NOOP_EXIT);
+
+void tc_state_init(int port)
+{
+ int res = 0;
+ sm_state this_state;
+
+ res = tc_restart_tcpc(port);
+
+ CPRINTS("TCPC p%d init %s", port, res ? "failed" : "ready");
+ this_state = res ? tc_disabled : PD_DEFAULT_STATE(port);
+
+ /* Disable TCPC RX until connection is established */
+ tcpm_set_rx_enable(port, 0);
+
+ init_state(port, TC_OBJ(port), this_state);
+
+ /* Disable pd state machines */
+ tc[port].pd_enable = 0;
+ tc[port].evt_timeout = 10*MSEC;
+ tc[port].power_role = PD_PLUG_CABLE_VPD;
+ tc[port].data_role = 0; /* Reserved for VPD */
+ tc[port].flags = 0;
+}
+
+void tc_event_check(int port, int evt)
+{
+ /* Do Nothing */
+}
+
+/**
+ * Disabled
+ *
+ * Super State Entries:
+ * Enable mcu communication
+ * Remove the terminations from Host CC
+ */
+static unsigned int tc_disabled(int port, enum signal sig)
+{
+ int ret = 0;
+
+ ret = (*tc_disabled_sig[sig])(port);
+ return SUPER(ret, sig, tc_host_open);
+}
+
+static unsigned int tc_disabled_entry(int port)
+{
+ tc[port].state_id = DISABLED;
+ CPRINTS("C%d: %s", port, tc_state_names[tc[port].state_id]);
+
+ return 0;
+}
+
+static unsigned int tc_disabled_run(int port)
+{
+ task_wait_event(-1);
+
+ return RUN_SUPER;
+}
+
+static unsigned int tc_disabled_exit(int port)
+{
+#ifndef CONFIG_USB_PD_TCPC
+ if (tc_restart_tcpc(port) != 0) {
+ CPRINTS("TCPC p%d restart failed!", port);
+ return 0;
+ }
+#endif
+ CPRINTS("TCPC p%d resumed!", port);
+ set_state(port, TC_OBJ(port), tc_unattached_snk);
+
+ return 0;
+}
+
+/**
+ * Unattached.SNK
+ *
+ * Super State Entry:
+ * Enable mcu communication
+ * Place Ra on VCONN and Rd on Host CC
+ */
+static unsigned int tc_unattached_snk(int port, enum signal sig)
+{
+ int ret;
+
+ ret = (*tc_unattached_snk_sig[sig])(port);
+ return SUPER(ret, sig, tc_host_rard);
+}
+
+static unsigned int tc_unattached_snk_entry(int port)
+{
+ tc[port].state_id = UNATTACHED_SNK;
+ CPRINTS("C%d: %s", port, tc_state_names[tc[port].state_id]);
+
+ return 0;
+}
+
+static unsigned int tc_unattached_snk_run(int port)
+{
+ int host_cc;
+
+ /* Check Host CC for connection */
+ vpd_host_get_cc(&host_cc);
+
+ /*
+ * Transition to AttachWait.SNK when a Source connection is
+ * detected, as indicated by the SNK.Rp state on its Host-side
+ * port’s CC pin.
+ */
+ if (cc_is_rp(host_cc)) {
+ set_state(port, TC_OBJ(port), tc_attach_wait_snk);
+ return 0;
+ }
+
+ return RUN_SUPER;
+}
+
+/**
+ * AttachedWait.SNK
+ *
+ * Super State Entry:
+ * Enable mcu communication
+ * Place Ra on VCONN and Rd on Host CC
+ */
+static unsigned int tc_attach_wait_snk(int port, enum signal sig)
+{
+ int ret = 0;
+
+ ret = (*tc_attach_wait_snk_sig[sig])(port);
+ return SUPER(ret, sig, tc_host_rard);
+}
+
+static unsigned int tc_attach_wait_snk_entry(int port)
+{
+ tc[port].state_id = ATTACH_WAIT_SNK;
+ CPRINTS("C%d: %s", port, tc_state_names[tc[port].state_id]);
+ tc[port].host_cc_state = PD_CC_UNSET;
+
+ return 0;
+}
+
+static unsigned int tc_attach_wait_snk_run(int port)
+{
+ int host_new_cc_state;
+ int host_cc;
+
+ /* Check Host CC for connection */
+ vpd_host_get_cc(&host_cc);
+
+ if (cc_is_rp(host_cc))
+ host_new_cc_state = PD_CC_DFP_ATTACHED;
+ else
+ host_new_cc_state = PD_CC_NONE;
+
+ /* Debounce the Host CC state */
+ if (tc[port].host_cc_state != host_new_cc_state) {
+ tc[port].host_cc_state = host_new_cc_state;
+ if (host_new_cc_state == PD_CC_DFP_ATTACHED)
+ tc[port].cc_debounce = get_time().val +
+ PD_T_CC_DEBOUNCE;
+ else
+ tc[port].cc_debounce = get_time().val +
+ PD_T_PD_DEBOUNCE;
+
+ return 0;
+ }
+
+ /* Wait for Host CC debounce */
+ if (get_time().val < tc[port].cc_debounce)
+ return 0;
+
+ /*
+ * A VCONN-Powered USB Device shall transition to
+ * Attached.SNK after the state of the Host-side port’s CC pin is
+ * SNK.Rp for at least tCCDebounce and either host-side VCONN or
+ * VBUS is detected.
+ *
+ * Transition to Unattached.SNK when the state of both the CC1 and
+ * CC2 pins is SNK.Open for at least tPDDebounce.
+ */
+ if (tc[port].host_cc_state == PD_CC_DFP_ATTACHED &&
+ (vpd_is_vconn_present() || vpd_is_host_vbus_present()))
+ set_state(port, TC_OBJ(port), tc_attached_snk);
+ else if (tc[port].host_cc_state == PD_CC_NONE)
+ set_state(port, TC_OBJ(port), tc_unattached_snk);
+
+ return 0;
+}
+
+/**
+ * Attached.SNK
+ */
+static unsigned int tc_attached_snk(int port, enum signal sig)
+{
+ int ret;
+
+ ret = (*tc_attached_snk_sig[sig])(port);
+ return SUPER(ret, sig, 0);
+}
+
+static unsigned int tc_attached_snk_entry(int port)
+{
+ tc[port].state_id = ATTACHED_SNK;
+ CPRINTS("C%d: %s", port, tc_state_names[tc[port].state_id]);
+
+ /* Enable PD */
+ tc[port].pd_enable = 1;
+ set_polarity(port, 0);
+
+ return 0;
+}
+
+static unsigned int tc_attached_snk_run(int port)
+{
+ /* Has host vbus and vconn been removed */
+ if (!vpd_is_host_vbus_present() && !vpd_is_vconn_present()) {
+ set_state(port, TC_OBJ(port), tc_unattached_snk);
+ return 0;
+ }
+
+ if (vpd_is_vconn_present()) {
+ if (!(tc[port].flags & TC_FLAGS_VCONN_ON)) {
+ /* VCONN detected. Remove RA */
+ vpd_host_set_pull(TYPEC_CC_RD, 0);
+ tc[port].flags |= TC_FLAGS_VCONN_ON;
+ }
+ }
+
+ return 0;
+}
+
+static unsigned int tc_attached_snk_exit(int port)
+{
+ /* Disable PD */
+ tc[port].pd_enable = 0;
+ tc[port].flags &= ~TC_FLAGS_VCONN_ON;
+
+ return 0;
+}
+
+/**
+ * Super State HOST_RARD
+ */
+static unsigned int tc_host_rard(int port, enum signal sig)
+{
+ int ret;
+
+ ret = (*tc_host_rard_sig[sig])(port);
+ return SUPER(ret, sig, tc_vbus_cc_iso);
+}
+
+static unsigned int tc_host_rard_entry(int port)
+{
+ /* Place Ra on VCONN and Rd on Host CC */
+ vpd_host_set_pull(TYPEC_CC_RA_RD, 0);
+
+ return 0;
+}
+
+static unsigned int tc_host_rard_run(int port)
+{
+ return RUN_SUPER;
+}
+
+/**
+ * Super State HOST_OPEN
+ */
+static unsigned int tc_host_open(int port, enum signal sig)
+{
+ int ret;
+
+ ret = (*tc_host_open_sig[sig])(port);
+ return SUPER(ret, sig, tc_vbus_cc_iso);
+}
+
+static unsigned int tc_host_open_entry(int port)
+{
+ /* Remove the terminations from Host CC */
+ vpd_host_set_pull(TYPEC_CC_OPEN, 0);
+
+ return 0;
+}
+
+static unsigned int tc_host_open_run(int port)
+{
+ return RUN_SUPER;
+}
+
+/**
+ * Super State VBUS_CC_ISO
+ */
+static unsigned int tc_vbus_cc_iso(int port, enum signal sig)
+{
+ int ret;
+
+ ret = (*tc_vbus_cc_iso_sig[sig])(port);
+ return SUPER(ret, sig, 0);
+}
+
+static unsigned int tc_vbus_cc_iso_entry(int port)
+{
+ /* Enable mcu communication and cc */
+ vpd_mcu_cc_en(1);
+
+ return 0;
+}
+
+static unsigned int tc_vbus_cc_iso_run(int port)
+{
+ return 0;
+}