diff options
author | Sam Hurst <shurst@google.com> | 2019-05-22 14:13:40 -0700 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2019-06-05 21:43:03 +0000 |
commit | d76c396bf65e912c2aa2ca1e905daa74996cdb27 (patch) | |
tree | c34654adeebeb793d548215c2eaf6f4f4ba3bdfe /common | |
parent | 184701a33a0f77dfbe38d231d05741db1f8ddbc6 (diff) | |
download | chrome-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.mk | 7 | ||||
-rw-r--r-- | common/usb_pe_ctvpd_sm.c | 207 | ||||
-rw-r--r-- | common/usb_pe_sm.c | 12 | ||||
-rw-r--r-- | common/usb_prl_sm.c | 307 | ||||
-rw-r--r-- | common/usb_sm.c | 11 | ||||
-rw-r--r-- | common/usb_tc_ctvpd_sm.c | 1736 | ||||
-rw-r--r-- | common/usb_tc_sm.c | 43 | ||||
-rw-r--r-- | common/usb_tc_vpd_sm.c | 358 |
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; +} |