diff options
-rw-r--r-- | common/build.mk | 7 | ||||
-rw-r--r-- | common/usb_pe_ctvpd_sm.c (renamed from include/usb_pe_ctvpd_sm.h) | 36 | ||||
-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 | ||||
-rw-r--r-- | include/usb_pe_sm.h | 8 | ||||
-rw-r--r-- | include/usb_sm.h | 72 | ||||
-rw-r--r-- | include/usb_tc_ctvpd_sm.h | 1993 | ||||
-rw-r--r-- | include/usb_tc_sm.h | 72 | ||||
-rw-r--r-- | include/usb_tc_vpd_sm.h | 454 | ||||
-rw-r--r-- | test/usb_sm_framework_h3.c | 7 |
14 files changed, 2322 insertions, 2794 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/include/usb_pe_ctvpd_sm.h b/common/usb_pe_ctvpd_sm.c index e2b2cde8c4..a8b1b1f0fe 100644 --- a/include/usb_pe_ctvpd_sm.h +++ b/common/usb_pe_ctvpd_sm.c @@ -17,9 +17,6 @@ /* USB Policy Engine Charge-Through VCONN Powered Device module */ -#ifndef __CROS_EC_USB_PE_CTVPD_H -#define __CROS_EC_USB_PE_CTVPD_H - /* Policy Engine Flags */ #define PE_FLAGS_MSG_RECEIVED (1 << 0) @@ -31,12 +28,6 @@ enum l_state { static enum l_state local_state = PE_INIT; -/* - * PE_OBJ is a convenience macro to access struct sm_obj, which - * must be the first member of struct policy_engine. - */ -#define PE_OBJ(port) (SM_OBJ(pe[port])) - /** * This is the PE Port object that contains information needed to * implement a VCONN and Charge-Through VCONN Powered Device. @@ -52,19 +43,8 @@ static struct policy_engine { uint32_t flags; } pe[CONFIG_USB_PD_PORT_COUNT]; -static unsigned int pe_request(int port, enum signal sig); -static unsigned int pe_request_entry(int port); -static unsigned int pe_request_run(int port); - -static unsigned int do_nothing_exit(int port); -static unsigned int get_super_state(int port); - -static const state_sig pe_request_sig[] = { - pe_request_entry, - pe_request_run, - do_nothing_exit, - get_super_state -}; +/* Policy Engine states */ +DECLARE_STATE(pe, request, NOOP_EXIT); void pe_init(int port) { @@ -225,15 +205,3 @@ static unsigned int pe_request_run(int port) return 0; } - -static unsigned int do_nothing_exit(int port) -{ - return 0; -} - -static unsigned int get_super_state(int port) -{ - return RUN_SUPER; -} - -#endif /* __CROS_EC_USB_PE_CTVPD_H */ 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; +} diff --git a/include/usb_pe_sm.h b/include/usb_pe_sm.h index a8fd59b08c..ae925c270e 100644 --- a/include/usb_pe_sm.h +++ b/include/usb_pe_sm.h @@ -8,6 +8,8 @@ #ifndef __CROS_EC_USB_PE_H #define __CROS_EC_USB_PE_H +#include "usb_sm.h" + enum pe_error { ERR_RCH_CHUNKED, ERR_RCH_MSG_REC, @@ -15,6 +17,12 @@ enum pe_error { ERR_TCH_XMIT, }; +/* + * PE_OBJ is a convenience macro to access struct sm_obj, which + * must be the first member of struct policy_engine. + */ +#define PE_OBJ(port) (SM_OBJ(pe[port])) + /** * Initialize the Policy Engine State Machine * diff --git a/include/usb_sm.h b/include/usb_sm.h index 15de5f9ef4..1fd6688a1f 100644 --- a/include/usb_sm.h +++ b/include/usb_sm.h @@ -8,6 +8,62 @@ #ifndef __CROS_EC_USB_SM_H #define __CROS_EC_USB_SM_H +#define DECLARE_SM_FUNC_(prefix, name, exit) \ + DECLARE_SM_FUNC_##exit(prefix, name) +#define DECLARE_SM_FUNC_WITH_EXIT(prefix, name) static unsigned int \ + prefix##_##name##_exit(int port) +#define DECLARE_SM_FUNC_NOOP_EXIT(prefix, name) + +#define DECLARE_SM_SIG_(prefix, name, exit) DECLARE_SM_##exit(prefix, name) +#define DECLARE_SM_WITH_EXIT(prefix, name) prefix##_##name##_exit +#define DECLARE_SM_NOOP_EXIT(prefix, name) do_nothing_exit + + +/* + * Helper macro for the declaration of states. + * + * @param prefix - prefix of state function name + * @param name - name of state + * @param exit - if WITH_EXIT, generates an exit state function name + * if NOOP_EXIT, generates do_nothing_exit function name + * + * EXAMPLE: + * + * DECLARE_STATE(tc, test, WITH_EXIT); generates the following: + * + * static unsigned int tc_test(int port, enum signal sig); + * static unsigned int tc_test_entry(int port); + * static unsigned int tc_test_run(int port); + * static unsigned int tc_test_exit(int port); + * static const state_sig tc_test_sig[] = { + * tc_test_entry, + * tc_test_run, + * tc_test_exit, + * get_super_state }; + * + * DECLARE_STATE(tc, test, NOOP_EXIT); generates the following: + * + * static unsigned int tc_test(int port, enum signal sig); + * static unsigned int tc_test_entry(int port); + * static unsigned int tc_test_run(int port); + * static const state_sig tc_test_sig[] = { + * tc_test_entry, + * tc_test_run, + * do_nothing_exit, + * get_super_state }; + */ +#define DECLARE_STATE(prefix, name, exit) \ +static unsigned int prefix##_##name(int port, enum signal sig); \ +static unsigned int prefix##_##name##_entry(int port); \ +static unsigned int prefix##_##name##_run(int port); \ +DECLARE_SM_FUNC_(prefix, name, exit); \ +static const state_sig prefix##_##name##_sig[] = { \ +prefix##_##name##_entry, \ +prefix##_##name##_run, \ +DECLARE_SM_SIG_(prefix, name, exit), \ +get_super_state \ +} + #define SM_OBJ(smo) ((struct sm_obj *)&smo) #define SUPER(r, sig, s) ((((r) == 0) || ((sig) == ENTRY_SIG) || \ ((sig) == EXIT_SIG)) ? 0 : ((uintptr_t)(s))) @@ -64,4 +120,20 @@ int set_state(int port, struct sm_obj *obj, sm_state target); */ void exe_state(int port, struct sm_obj *obj, enum signal sig); +/** + * Substitute this function for states that do not implement an exit state. + * + * @param port USB-C port number + * @return 0 + */ +unsigned int do_nothing_exit(int port); + +/** + * Called by the state machine framework to execute a states super state. + * + * @param port USB-C port number + * @return RUN_SUPER + */ +unsigned int get_super_state(int port); + #endif /* __CROS_EC_USB_SM_H */ diff --git a/include/usb_tc_ctvpd_sm.h b/include/usb_tc_ctvpd_sm.h index 8e0e1eaf2f..72ce16f317 100644 --- a/include/usb_tc_ctvpd_sm.h +++ b/include/usb_tc_ctvpd_sm.h @@ -3,29 +3,17 @@ * found in the LICENSE file. */ -#include "vpd_api.h" +#ifndef __CROS_EC_USB_TC_CTVPD_SM_H +#define __CROS_EC_USB_TC_CTVPD_SM_H -/* USB Type-C CTVPD module */ +#include "usb_sm.h" +#include "usb_tc_sm.h" -#ifndef __CROS_EC_USB_TC_VPD_H -#define __CROS_EC_USB_TC_VPD_H - -/* 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_state_unattached_snk - -#define TC_OBJ(port) (SM_OBJ(tc[port])) -#define TC_TEST_OBJ(port) (SM_OBJ(tc[(port)].obj)) - -#define SUPPORT_TIMER_RESET_INIT 0 -#define SUPPORT_TIMER_RESET_REQUEST 1 -#define SUPPORT_TIMER_RESET_COMPLETE 2 - -static struct type_c { +/** + * This is the Type-C Port object that contains information needed to + * implement a Charge Through VCONN Powered Device. + */ +struct type_c { /* struct sm_obj must be first */ struct sm_obj obj; /* state id */ @@ -71,1967 +59,8 @@ static struct type_c { /* The cc state */ enum pd_cc_states cc_state; uint64_t next_role_swap; -} tc[CONFIG_USB_PD_PORT_COUNT]; - -/* Type-C states */ -static unsigned int tc_state_disabled(int port, enum signal sig); -static unsigned int tc_state_disabled_entry(int port); -static unsigned int tc_state_disabled_run(int port); -static unsigned int tc_state_disabled_exit(int port); - -static unsigned int tc_state_error_recovery(int port, enum signal sig); -static unsigned int tc_state_error_recovery_entry(int port); -static unsigned int tc_state_error_recovery_run(int port); - -static unsigned int tc_state_unattached_snk(int port, enum signal sig); -static unsigned int tc_state_unattached_snk_entry(int port); -static unsigned int tc_state_unattached_snk_run(int port); - -static unsigned int tc_state_attach_wait_snk(int port, enum signal sig); -static unsigned int tc_state_attach_wait_snk_entry(int port); -static unsigned int tc_state_attach_wait_snk_run(int port); - -static unsigned int tc_state_attached_snk(int port, enum signal sig); -static unsigned int tc_state_attached_snk_entry(int port); -static unsigned int tc_state_attached_snk_run(int port); -static unsigned int tc_state_attached_snk_exit(int port); - -static unsigned int tc_state_try_snk(int port, enum signal sig); -static unsigned int tc_state_try_snk_entry(int port); -static unsigned int tc_state_try_snk_run(int port); - -static unsigned int tc_state_unattached_src(int port, enum signal sig); -static unsigned int tc_state_unattached_src_entry(int port); -static unsigned int tc_state_unattached_src_run(int port); - -static unsigned int tc_state_attach_wait_src(int port, enum signal sig); -static unsigned int tc_state_attach_wait_src_entry(int port); -static unsigned int tc_state_attach_wait_src_run(int port); - -static unsigned int tc_state_try_wait_src(int port, enum signal sig); -static unsigned int tc_state_try_wait_src_entry(int port); -static unsigned int tc_state_try_wait_src_run(int port); - -static unsigned int tc_state_attached_src(int port, enum signal sig); -static unsigned int tc_state_attached_src_entry(int port); -static unsigned int tc_state_attached_src_run(int port); - -static unsigned int tc_state_ct_try_snk(int port, enum signal sig); -static unsigned int tc_state_ct_try_snk_entry(int port); -static unsigned int tc_state_ct_try_snk_run(int port); -static unsigned int tc_state_ct_try_snk_exit(int port); - -static unsigned int - tc_state_ct_attach_wait_unsupported(int port, enum signal sig); -static unsigned int tc_state_ct_attach_wait_unsupported_entry(int port); -static unsigned int tc_state_ct_attach_wait_unsupported_run(int port); -static unsigned int tc_state_ct_attach_wait_unsupported_exit(int port); - -static unsigned int tc_state_ct_attached_unsupported(int port, enum signal sig); -static unsigned int tc_state_ct_attached_unsupported_entry(int port); -static unsigned int tc_state_ct_attached_unsupported_run(int port); -static unsigned int tc_state_ct_attached_unsupported_exit(int port); - -static unsigned int - tc_state_ct_unattached_unsupported(int port, enum signal sig); -static unsigned int tc_state_ct_unattached_unsupported_entry(int port); -static unsigned int tc_state_ct_unattached_unsupported_run(int port); -static unsigned int tc_state_ct_unattached_unsupported_exit(int port); - -static unsigned int tc_state_ct_unattached_vpd(int port, enum signal sig); -static unsigned int tc_state_ct_unattached_vpd_entry(int port); -static unsigned int tc_state_ct_unattached_vpd_run(int port); -static unsigned int tc_state_ct_unattached_vpd_exit(int port); - -static unsigned int tc_state_ct_disabled_vpd(int port, enum signal sig); -static unsigned int tc_state_ct_disabled_vpd_entry(int port); -static unsigned int tc_state_ct_disabled_vpd_run(int port); - -static unsigned int tc_state_ct_attached_vpd(int port, enum signal sig); -static unsigned int tc_state_ct_attached_vpd_entry(int port); -static unsigned int tc_state_ct_attached_vpd_run(int port); - -static unsigned int tc_state_ct_attach_wait_vpd(int port, enum signal sig); -static unsigned int tc_state_ct_attach_wait_vpd_entry(int port); -static unsigned int tc_state_ct_attach_wait_vpd_run(int port); -static unsigned int tc_state_ct_attach_wait_vpd_exit(int port); - - -/* Super States */ -static unsigned int tc_state_host_rard_ct_rd(int port, enum signal sig); -static unsigned int tc_state_host_rard_ct_rd_entry(int port); -static unsigned int tc_state_host_rard_ct_rd_run(int port); - -static unsigned int tc_state_host_open_ct_open(int port, enum signal sig); -static unsigned int tc_state_host_open_ct_open_entry(int port); -static unsigned int tc_state_host_open_ct_open_run(int port); - -static unsigned int tc_state_vbus_cc_iso(int port, enum signal sig); -static unsigned int tc_state_vbus_cc_iso_entry(int port); -static unsigned int tc_state_vbus_cc_iso_run(int port); - -static unsigned int tc_state_host_rp3_ct_rd(int port, enum signal sig); -static unsigned int tc_state_host_rp3_ct_rd_entry(int port); -static unsigned int tc_state_host_rp3_ct_rd_run(int port); - -static unsigned int tc_state_host_rp3_ct_rpu(int port, enum signal sig); -static unsigned int tc_state_host_rp3_ct_rpu_entry(int port); -static unsigned int tc_state_host_rp3_ct_rpu_run(int port); - -static unsigned int tc_state_host_rpu_ct_rd(int port, enum signal sig); -static unsigned int tc_state_host_rpu_ct_rd_entry(int port); -static unsigned int tc_state_host_rpu_ct_rd_run(int port); - -static unsigned int do_nothing_exit(int port); -static unsigned int get_super_state(int port); - - -static const state_sig tc_state_disabled_sig[] = { - tc_state_disabled_entry, - tc_state_disabled_run, - tc_state_disabled_exit, - get_super_state -}; - -static const state_sig tc_state_error_recovery_sig[] = { - tc_state_error_recovery_entry, - tc_state_error_recovery_run, - do_nothing_exit, - get_super_state -}; - -static const state_sig tc_state_unattached_snk_sig[] = { - tc_state_unattached_snk_entry, - tc_state_unattached_snk_run, - do_nothing_exit, - get_super_state -}; - -static const state_sig tc_state_attach_wait_snk_sig[] = { - tc_state_attach_wait_snk_entry, - tc_state_attach_wait_snk_run, - do_nothing_exit, - get_super_state -}; - -static const state_sig tc_state_attached_snk_sig[] = { - tc_state_attached_snk_entry, - tc_state_attached_snk_run, - tc_state_attached_snk_exit, - get_super_state -}; - -static const state_sig tc_state_try_snk_sig[] = { - tc_state_try_snk_entry, - tc_state_try_snk_run, - do_nothing_exit, - get_super_state -}; - -static const state_sig tc_state_unattached_src_sig[] = { - tc_state_unattached_src_entry, - tc_state_unattached_src_run, - do_nothing_exit, - get_super_state }; -static const state_sig tc_state_attach_wait_src_sig[] = { - tc_state_attach_wait_src_entry, - tc_state_attach_wait_src_run, - do_nothing_exit, - get_super_state -}; - -static const state_sig tc_state_try_wait_src_sig[] = { - tc_state_try_wait_src_entry, - tc_state_try_wait_src_run, - do_nothing_exit, - get_super_state -}; - -static const state_sig tc_state_attached_src_sig[] = { - tc_state_attached_src_entry, - tc_state_attached_src_run, - do_nothing_exit, - get_super_state -}; - -static const state_sig tc_state_ct_try_snk_sig[] = { - tc_state_ct_try_snk_entry, - tc_state_ct_try_snk_run, - tc_state_ct_try_snk_exit, - get_super_state -}; - -static const state_sig tc_state_ct_attach_wait_unsupported_sig[] = { - tc_state_ct_attach_wait_unsupported_entry, - tc_state_ct_attach_wait_unsupported_run, - tc_state_ct_attach_wait_unsupported_exit, - get_super_state -}; - -static const state_sig tc_state_ct_attached_unsupported_sig[] = { - tc_state_ct_attached_unsupported_entry, - tc_state_ct_attached_unsupported_run, - tc_state_ct_attached_unsupported_exit, - get_super_state -}; - -static const state_sig tc_state_ct_unattached_unsupported_sig[] = { - tc_state_ct_unattached_unsupported_entry, - tc_state_ct_unattached_unsupported_run, - tc_state_ct_unattached_unsupported_exit, - get_super_state -}; - -static const state_sig tc_state_ct_unattached_vpd_sig[] = { - tc_state_ct_unattached_vpd_entry, - tc_state_ct_unattached_vpd_run, - tc_state_ct_unattached_vpd_exit, - get_super_state -}; - -static const state_sig tc_state_ct_disabled_vpd_sig[] = { - tc_state_ct_disabled_vpd_entry, - tc_state_ct_disabled_vpd_run, - do_nothing_exit, - get_super_state -}; - -static const state_sig tc_state_ct_attached_vpd_sig[] = { - tc_state_ct_attached_vpd_entry, - tc_state_ct_attached_vpd_run, - do_nothing_exit, - get_super_state -}; - -static const state_sig tc_state_ct_attach_wait_vpd_sig[] = { - tc_state_ct_attach_wait_vpd_entry, - tc_state_ct_attach_wait_vpd_run, - tc_state_ct_attach_wait_vpd_exit, - get_super_state -}; - -static const state_sig tc_state_host_rard_ct_rd_sig[] = { - tc_state_host_rard_ct_rd_entry, - tc_state_host_rard_ct_rd_run, - do_nothing_exit, - get_super_state -}; - -static const state_sig tc_state_host_open_ct_open_sig[] = { - tc_state_host_open_ct_open_entry, - tc_state_host_open_ct_open_run, - do_nothing_exit, - get_super_state -}; - -static const state_sig tc_state_vbus_cc_iso_sig[] = { - tc_state_vbus_cc_iso_entry, - tc_state_vbus_cc_iso_run, - do_nothing_exit, - get_super_state -}; - -static const state_sig tc_state_host_rp3_ct_rd_sig[] = { - tc_state_host_rp3_ct_rd_entry, - tc_state_host_rp3_ct_rd_run, - do_nothing_exit, - get_super_state -}; - -static const state_sig tc_state_host_rp3_ct_rpu_sig[] = { - tc_state_host_rp3_ct_rpu_entry, - tc_state_host_rp3_ct_rpu_run, - do_nothing_exit, - get_super_state -}; - -static const state_sig tc_state_host_rpu_ct_rd_sig[] = { - tc_state_host_rpu_ct_rd_entry, - tc_state_host_rpu_ct_rd_run, - do_nothing_exit, - get_super_state -}; - -void tc_reset_support_timer(int port) -{ - tc[port].support_timer_reset |= SUPPORT_TIMER_RESET_REQUEST; -} - -static 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_state_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; -} - -static 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_state_disabled(int port, enum signal sig) -{ - int ret = 0; - - ret = (*tc_state_disabled_sig[sig])(port); - return SUPER(ret, sig, tc_state_host_open_ct_open); -} - -static unsigned int tc_state_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_state_disabled_run(int port) -{ - task_wait_event(-1); - return RUN_SUPER; -} - -static unsigned int tc_state_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_state_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_state_error_recovery(int port, enum signal sig) -{ - int ret = 0; - - ret = (*tc_state_error_recovery_sig[sig])(port); - return SUPER(ret, sig, tc_state_host_open_ct_open); -} - -static unsigned int tc_state_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_state_error_recovery_run(int port) -{ - if (get_time().val > tc[port].cc_debounce) { - set_state(port, TC_OBJ(port), tc_state_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_state_unattached_snk(int port, enum signal sig) -{ - int ret = 0; - - ret = (*tc_state_unattached_snk_sig[sig])(port); - return SUPER(ret, sig, tc_state_host_rard_ct_rd); -} - -static unsigned int tc_state_unattached_snk_entry(int port) -{ - tc[port].state_id = UNATTACHED_SNK; - if (tc[port].obj.last_state != tc_state_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_state_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_state_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_state_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_state_attach_wait_snk(int port, enum signal sig) -{ - int ret; - - ret = (*tc_state_attach_wait_snk_sig[sig])(port); - return SUPER(ret, sig, tc_state_host_rard_ct_rd); -} - -static unsigned int tc_state_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_state_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_state_attached_snk); - else if (tc[port].host_cc_state == PD_CC_NONE) - set_state(port, TC_OBJ(port), tc_state_unattached_snk); - - return 0; -} - -/** - * Attached.SNK - */ -static unsigned int tc_state_attached_snk(int port, enum signal sig) -{ - int ret; - - ret = (*tc_state_attached_snk_sig[sig])(port); - return SUPER(ret, sig, 0); -} - -static unsigned int tc_state_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_state_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_state_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_state_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_state_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_state_host_rard_ct_rd(int port, enum signal sig) -{ - int ret; - - ret = (*tc_state_host_rard_ct_rd_sig[sig])(port); - return SUPER(ret, sig, tc_state_vbus_cc_iso); -} - -static unsigned int tc_state_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_state_host_rard_ct_rd_run(int port) -{ - return RUN_SUPER; -} - -/** - * Super State HOST_OPEN_CT_OPEN - */ -static unsigned int tc_state_host_open_ct_open(int port, enum signal sig) -{ - int ret; - - ret = (*tc_state_host_open_ct_open_sig[sig])(port); - return SUPER(ret, sig, tc_state_vbus_cc_iso); -} - -static unsigned int tc_state_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_state_host_open_ct_open_run(int port) -{ - return RUN_SUPER; -} - -/** - * Super State VBUS_CC_ISO - */ -static unsigned int tc_state_vbus_cc_iso(int port, enum signal sig) -{ - int ret; - - ret = (*tc_state_vbus_cc_iso_sig[sig])(port); - return SUPER(ret, sig, 0); -} - -static unsigned int tc_state_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_state_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_state_unattached_src(int port, enum signal sig) -{ - int ret; - - ret = (*tc_state_unattached_src_sig[sig])(port); - return SUPER(ret, sig, tc_state_host_rpu_ct_rd); -} - -static unsigned int tc_state_unattached_src_entry(int port) -{ - tc[port].state_id = UNATTACHED_SRC; - if (tc[port].obj.last_state != tc_state_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_state_error_recovery); - return 0; - } - - tc[port].next_role_swap = get_time().val + PD_T_DRP_SRC; - - return 0; -} - -static unsigned int tc_state_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_state_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_state_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_state_attach_wait_src(int port, enum signal sig) -{ - int ret; - - ret = (*tc_state_attach_wait_src_sig[sig])(port); - return SUPER(ret, sig, tc_state_host_rpu_ct_rd); -} - -static unsigned int tc_state_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_state_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_state_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_state_try_snk); - return 0; - } - - return RUN_SUPER; -} - -/** - * Attached.SRC - */ -static unsigned int tc_state_attached_src(int port, enum signal sig) -{ - int ret; - - ret = (*tc_state_attached_src_sig[sig])(port); - return SUPER(ret, sig, 0); -} - -static unsigned int tc_state_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_state_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_state_unattached_snk); - - return 0; -} - -/** - * Super State HOST_RPU_CT_RD - */ -static unsigned int tc_state_host_rpu_ct_rd(int port, enum signal sig) -{ - int ret; - - ret = (*tc_state_host_rpu_ct_rd_sig[sig])(port); - return SUPER(ret, sig, tc_state_vbus_cc_iso); -} - -static unsigned int tc_state_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_state_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_state_try_snk(int port, enum signal sig) -{ - int ret; - - ret = (*tc_state_try_snk_sig[sig])(port); - return SUPER(ret, sig, tc_state_host_rard_ct_rd); -} - -static unsigned int tc_state_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_state_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_state_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_state_attached_snk); - else if (tc[port].host_cc_state == PD_CC_NONE) - set_state(port, TC_OBJ(port), tc_state_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_state_try_wait_src(int port, enum signal sig) -{ - int ret; - - ret = (*tc_state_try_wait_src_sig[sig])(port); - return SUPER(ret, sig, tc_state_host_rpu_ct_rd); -} - -static unsigned int tc_state_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_state_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_state_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_state_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_state_ct_try_snk(int port, enum signal sig) -{ - int ret; - - ret = (*tc_state_ct_try_snk_sig[sig])(port); - return SUPER(ret, sig, tc_state_host_rp3_ct_rd); -} - -static unsigned int tc_state_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_state_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_state_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_state_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_state_ct_attached_unsupported); - return 0; - } - } - - return RUN_SUPER; -} - -static unsigned int tc_state_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_state_ct_attach_wait_unsupported(int port, enum signal sig) -{ - int ret; - - ret = (*tc_state_ct_attach_wait_unsupported_sig[sig])(port); - return SUPER(ret, sig, tc_state_host_rp3_ct_rpu); -} - -static unsigned int tc_state_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_state_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_state_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_state_ct_unattached_vpd); - else /* PD_CC_DFP_ATTACHED or PD_CC_AUDIO_ACC */ - set_state(port, TC_OBJ(port), tc_state_ct_try_snk); - - return 0; -} - -static unsigned int tc_state_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_state_ct_attached_unsupported(int port, enum signal sig) -{ - int ret; - - ret = (*tc_state_ct_attached_unsupported_sig[sig])(port); - return SUPER(ret, sig, tc_state_host_rp3_ct_rpu); -} - -static unsigned int tc_state_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_state_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_state_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_state_ct_unattached_vpd); - return 0; - } - - return RUN_SUPER; -} - -static unsigned int tc_state_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_state_ct_unattached_unsupported(int port, enum signal sig) -{ - int ret; - - ret = (*tc_state_ct_unattached_unsupported_sig[sig])(port); - return SUPER(ret, sig, tc_state_host_rp3_ct_rpu); -} - -static unsigned int tc_state_ct_unattached_unsupported_entry(int port) -{ - tc[port].state_id = CTUNATTACHED_UNSUPPORTED; - if (tc[port].obj.last_state != tc_state_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_state_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_state_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_state_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_state_ct_unattached_vpd); - return 0; - } - - return RUN_SUPER; -} - -static unsigned int tc_state_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_state_ct_unattached_vpd(int port, enum signal sig) -{ - int ret; - - ret = (*tc_state_ct_unattached_vpd_sig[sig])(port); - return SUPER(ret, sig, tc_state_host_rp3_ct_rd); -} - -static unsigned int tc_state_ct_unattached_vpd_entry(int port) -{ - tc[port].state_id = CTUNATTACHED_VPD; - if (tc[port].obj.last_state != tc_state_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_state_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_state_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_state_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_state_ct_unattached_unsupported); - return 0; - } - - return RUN_SUPER; -} - -static unsigned int tc_state_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_state_ct_disabled_vpd(int port, enum signal sig) -{ - int ret; - - ret = (*tc_state_ct_disabled_vpd_sig[sig])(port); - return SUPER(ret, sig, tc_state_host_open_ct_open); -} - -static unsigned int tc_state_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_state_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_state_unattached_snk); - - return 0; -} - -/** - * CTAttached.VPD - */ -static unsigned int tc_state_ct_attached_vpd(int port, enum signal sig) -{ - int ret; - - ret = (*tc_state_ct_attached_vpd_sig[sig])(port); - return SUPER(ret, sig, 0); -} - -static unsigned int tc_state_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_state_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_state_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_state_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_state_ct_attach_wait_vpd(int port, enum signal sig) -{ - int ret; - - ret = (*tc_state_ct_attach_wait_vpd_sig[sig])(port); - return SUPER(ret, sig, tc_state_host_rp3_ct_rd); -} - -static unsigned int tc_state_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_state_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_state_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_state_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_state_ct_attached_vpd); - return 0; - } - } - - return RUN_SUPER; -} - -static unsigned int tc_state_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_state_host_rp3_ct_rd(int port, enum signal sig) -{ - int ret; - - ret = (*tc_state_host_rp3_ct_rd_sig[sig])(port); - - return SUPER(ret, sig, tc_state_vbus_cc_iso); -} - -static unsigned int tc_state_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_state_error_recovery); - - /* Get power from VCONN */ - vpd_vconn_pwr_sel_odl(PWR_VCONN); - - return 0; -} - -static unsigned int tc_state_host_rp3_ct_rd_run(int port) -{ - return 0; -} - -/** - * Super State HOST_RP3_CT_RPU - */ -static unsigned int tc_state_host_rp3_ct_rpu(int port, enum signal sig) -{ - int ret; - - ret = (*tc_state_host_rp3_ct_rpu_sig[sig])(port); - return SUPER(ret, sig, tc_state_vbus_cc_iso); -} - -static unsigned int tc_state_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_state_error_recovery); - - /* Get power from VCONN */ - vpd_vconn_pwr_sel_odl(PWR_VCONN); - - return 0; -} - -static unsigned int tc_state_host_rp3_ct_rpu_run(int port) -{ - return 0; -} - -static unsigned int do_nothing_exit(int port) -{ - return 0; -} - -static unsigned int get_super_state(int port) -{ - return RUN_SUPER; -} +extern struct type_c tc[]; -#endif /* CONFIG_USB_TYPEC_CTVPD */ +#endif /* __CROS_EC_USB_TC_CTVPD_SM_H */ diff --git a/include/usb_tc_sm.h b/include/usb_tc_sm.h index 08e9ebbf54..4a2af0fa6f 100644 --- a/include/usb_tc_sm.h +++ b/include/usb_tc_sm.h @@ -8,6 +8,8 @@ #ifndef __CROS_EC_USB_TC_H #define __CROS_EC_USB_TC_H +#include "usb_sm.h" + enum typec_state_id { DISABLED, UNATTACHED_SNK, @@ -45,6 +47,34 @@ enum typec_state_id { TC_STATE_COUNT, }; +extern const char * const tc_state_names[]; + +#define TC_SET_FLAG(port, flag) atomic_or(&tc[port].flags, (flag)) +#define TC_CLR_FLAG(port, flag) atomic_clear(&tc[port].flags, (flag)) +#define TC_CHK_FLAG(port, flag) (tc[port].flags & (flag)) + +/* + * TC_OBJ is a convenience macro to access struct sm_obj, which + * must be the first member of struct type_c. + */ +#define TC_OBJ(port) (SM_OBJ(tc[port])) + +/* + * Type C supply voltage (mV) + * + * This is the maximum voltage a sink can request + * while charging. + */ +#define TYPE_C_VOLTAGE 5000 /* mV */ + +/* + * Type C default sink current (mA) + * + * This is the maximum current a sink can draw if charging + * while in the Audio Accessory State. + */ +#define TYPE_C_AUDIO_ACC_CURRENT 500 /* mA */ + /** * Get the id of the current Type-C state * @@ -76,6 +106,48 @@ int tc_get_power_role(int port); */ void tc_set_timeout(int port, uint64_t timeout); +/** + * Returns the polarity of a Sink. + * + * @param cc1 value of CC1 set by tcpm_get_cc + * @param cc2 value of CC2 set by tcpm_get_cc + * @return 0 if cc1 is connected, else 1 for cc2 + */ +enum pd_cc_polarity_type get_snk_polarity(int cc1, int cc2); + +/** + * Restarts the TCPC + * + * @param port USB-C port number + * @returns EC_SUCCESS on success + */ +int tc_restart_tcpc(int port); + +/** + * Sets the polarity of the port + * + * @param port USB-C port number + * @param polarity 0 for CC1, else 1 for CC2 + */ +void set_polarity(int port, int polarity); + +/** + * Called by the state machine framework to initialize the + * TypeC state machine + * + * @param port USB-C port number + */ +void tc_state_init(int port); + +/** + * Called by the state machine framework to handle events + * that affect the state machine as a whole + * + * @param port USB-C port number + * @param evt event + */ +void tc_event_check(int port, int evt); + #ifdef CONFIG_USB_TYPEC_CTVPD /** * Resets the charge-through support timer. This can be diff --git a/include/usb_tc_vpd_sm.h b/include/usb_tc_vpd_sm.h index c8a4dd48a3..cd564cb3ce 100644 --- a/include/usb_tc_vpd_sm.h +++ b/include/usb_tc_vpd_sm.h @@ -3,31 +3,17 @@ * found in the LICENSE file. */ -#include "vpd_api.h" +#ifndef __CROS_EC_USB_TC_VPD_SM_H +#define __CROS_EC_USB_TC_VPD_SM_H -/* USB Type-C VCONN Powered Device module */ - -#ifndef __CROS_EC_USB_TC_VPD_H -#define __CROS_EC_USB_TC_VPD_H - -/* 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_state_unattached_snk - -/* - * TC_OBJ is a convenience macro to access struct sm_obj, which - * must be the first member of struct type_c. - */ -#define TC_OBJ(port) (SM_OBJ(tc[port])) +#include "usb_sm.h" +#include "usb_tc_sm.h" /** * This is the Type-C Port object that contains information needed to * implement a VCONN Powered Device. */ -static struct type_c { +struct type_c { /* * struct sm_obj must be first. This is the state machine * object that keeps track of the current and last state @@ -53,434 +39,8 @@ static struct type_c { /* VPD host port cc state */ enum pd_cc_states host_cc_state; uint8_t ct_cc; -} tc[CONFIG_USB_PD_PORT_COUNT]; - -/* Type-C states */ -static unsigned int tc_state_disabled(int port, enum signal sig); -static unsigned int tc_state_disabled_entry(int port); -static unsigned int tc_state_disabled_run(int port); -static unsigned int tc_state_disabled_exit(int port); - -static unsigned int tc_state_unattached_snk(int port, enum signal sig); -static unsigned int tc_state_unattached_snk_entry(int port); -static unsigned int tc_state_unattached_snk_run(int port); -static unsigned int tc_state_unattached_snk_exit(int port); - -static unsigned int tc_state_attach_wait_snk(int port, enum signal sig); -static unsigned int tc_state_attach_wait_snk_entry(int port); -static unsigned int tc_state_attach_wait_snk_run(int port); -static unsigned int tc_state_attach_wait_snk_exit(int port); - -static unsigned int tc_state_attached_snk(int port, enum signal sig); -static unsigned int tc_state_attached_snk_entry(int port); -static unsigned int tc_state_attached_snk_run(int port); -static unsigned int tc_state_attached_snk_exit(int port); - -/* Super States */ -static unsigned int tc_state_host_rard(int port, enum signal sig); -static unsigned int tc_state_host_rard_entry(int port); -static unsigned int tc_state_host_rard_run(int port); -static unsigned int tc_state_host_rard_exit(int port); - -static unsigned int tc_state_host_open(int port, enum signal sig); -static unsigned int tc_state_host_open_entry(int port); -static unsigned int tc_state_host_open_run(int port); -static unsigned int tc_state_host_open_exit(int port); - -static unsigned int tc_state_vbus_cc_iso(int port, enum signal sig); -static unsigned int tc_state_vbus_cc_iso_entry(int port); -static unsigned int tc_state_vbus_cc_iso_run(int port); -static unsigned int tc_state_vbus_cc_iso_exit(int port); - -static unsigned int get_super_state(int port); - -static const state_sig tc_state_disabled_sig[] = { - tc_state_disabled_entry, - tc_state_disabled_run, - tc_state_disabled_exit, - get_super_state }; -static const state_sig tc_state_unattached_snk_sig[] = { - tc_state_unattached_snk_entry, - tc_state_unattached_snk_run, - tc_state_unattached_snk_exit, - get_super_state -}; - -static const state_sig tc_state_attach_wait_snk_sig[] = { - tc_state_attach_wait_snk_entry, - tc_state_attach_wait_snk_run, - tc_state_attach_wait_snk_exit, - get_super_state -}; - -static const state_sig tc_state_attached_snk_sig[] = { - tc_state_attached_snk_entry, - tc_state_attached_snk_run, - tc_state_attached_snk_exit, - get_super_state -}; - -static const state_sig tc_state_host_rard_sig[] = { - tc_state_host_rard_entry, - tc_state_host_rard_run, - tc_state_host_rard_exit, - get_super_state -}; - -static const state_sig tc_state_host_open_sig[] = { - tc_state_host_open_entry, - tc_state_host_open_run, - tc_state_host_open_exit, - get_super_state -}; - -static const state_sig tc_state_vbus_cc_iso_sig[] = { - tc_state_vbus_cc_iso_entry, - tc_state_vbus_cc_iso_run, - tc_state_vbus_cc_iso_exit, - get_super_state -}; - -static 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_state_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; -} - -static 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_state_disabled(int port, enum signal sig) -{ - int ret = 0; - - ret = (*tc_state_disabled_sig[sig])(port); - return SUPER(ret, sig, tc_state_host_open); -} - -static unsigned int tc_state_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_state_disabled_run(int port) -{ - task_wait_event(-1); - - return RUN_SUPER; -} - -static unsigned int tc_state_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_state_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_state_unattached_snk(int port, enum signal sig) -{ - int ret; - - ret = (*tc_state_unattached_snk_sig[sig])(port); - return SUPER(ret, sig, tc_state_host_rard); -} - -static unsigned int tc_state_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_state_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_state_attach_wait_snk); - return 0; - } - - return RUN_SUPER; -} - -static unsigned int tc_state_unattached_snk_exit(int port) -{ - return 0; -} - -/** - * AttachedWait.SNK - * - * Super State Entry: - * Enable mcu communication - * Place Ra on VCONN and Rd on Host CC - */ -static unsigned int tc_state_attach_wait_snk(int port, enum signal sig) -{ - int ret = 0; - - ret = (*tc_state_attach_wait_snk_sig[sig])(port); - return SUPER(ret, sig, tc_state_host_rard); -} - -static unsigned int tc_state_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_state_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_state_attached_snk); - else if (tc[port].host_cc_state == PD_CC_NONE) - set_state(port, TC_OBJ(port), tc_state_unattached_snk); - - return 0; -} - -static unsigned int tc_state_attach_wait_snk_exit(int port) -{ - return 0; -} - -/** - * Attached.SNK - */ -static unsigned int tc_state_attached_snk(int port, enum signal sig) -{ - int ret; - - ret = (*tc_state_attached_snk_sig[sig])(port); - return SUPER(ret, sig, 0); -} - -static unsigned int tc_state_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_state_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_state_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_state_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_state_host_rard(int port, enum signal sig) -{ - int ret; - - ret = (*tc_state_host_rard_sig[sig])(port); - return SUPER(ret, sig, tc_state_vbus_cc_iso); -} - -static unsigned int tc_state_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_state_host_rard_run(int port) -{ - return RUN_SUPER; -} - -static unsigned int tc_state_host_rard_exit(int port) -{ - return 0; -} - -/** - * Super State HOST_OPEN - */ -static unsigned int tc_state_host_open(int port, enum signal sig) -{ - int ret; - - ret = (*tc_state_host_open_sig[sig])(port); - return SUPER(ret, sig, tc_state_vbus_cc_iso); -} - -static unsigned int tc_state_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_state_host_open_run(int port) -{ - return RUN_SUPER; -} - -static unsigned int tc_state_host_open_exit(int port) -{ - return 0; -} - -/** - * Super State VBUS_CC_ISO - */ -static unsigned int tc_state_vbus_cc_iso(int port, enum signal sig) -{ - int ret; - - ret = (*tc_state_vbus_cc_iso_sig[sig])(port); - return SUPER(ret, sig, 0); -} - -static unsigned int tc_state_vbus_cc_iso_entry(int port) -{ - /* Enable mcu communication and cc */ - vpd_mcu_cc_en(1); - - return 0; -} - -static unsigned int tc_state_vbus_cc_iso_run(int port) -{ - return 0; -} - -static unsigned int tc_state_vbus_cc_iso_exit(int port) -{ - return 0; -} - -static unsigned int get_super_state(int port) -{ - return RUN_SUPER; -} +extern struct type_c tc[]; -#endif /*__CROS_EC_USB_TC_VPD_H */ +#endif /* __CROS_EC_USB_TC_VPD_SM_H */ diff --git a/test/usb_sm_framework_h3.c b/test/usb_sm_framework_h3.c index db88338387..37266517ce 100644 --- a/test/usb_sm_framework_h3.c +++ b/test/usb_sm_framework_h3.c @@ -200,8 +200,6 @@ static unsigned int sm_test_C_entry(int port); static unsigned int sm_test_C_run(int port); static unsigned int sm_test_C_exit(int port); -static unsigned int get_super_state(int port); - #if defined(TEST_USB_SM_FRAMEWORK_H3) static const state_sig sm_test_super_A1_sig[] = { sm_test_super_A1_entry, @@ -774,11 +772,6 @@ static unsigned int sm_test_B6_exit(int port) return 0; } -static unsigned int get_super_state(int port) -{ - return RUN_SUPER; -} - static unsigned int sm_test_C(int port, enum signal sig) { int ret; |