summaryrefslogtreecommitdiff
path: root/common/usbc
diff options
context:
space:
mode:
Diffstat (limited to 'common/usbc')
-rw-r--r--common/usbc/build.mk51
-rw-r--r--common/usbc/dp_alt_mode.c292
-rw-r--r--common/usbc/tbt_alt_mode.c579
-rw-r--r--common/usbc/usb_mode.c311
-rw-r--r--common/usbc/usb_pd_console.c212
-rw-r--r--common/usbc/usb_pd_dp_ufp.c448
-rw-r--r--common/usbc/usb_pd_dpm.c704
-rw-r--r--common/usbc/usb_pd_host.c179
-rw-r--r--common/usbc/usb_pd_timer.c268
-rw-r--r--common/usbc/usb_pe_ctvpd_sm.c237
-rw-r--r--common/usbc/usb_pe_drp_sm.c7486
-rw-r--r--common/usbc/usb_prl_sm.c2471
-rw-r--r--common/usbc/usb_retimer_fw_update.c189
-rw-r--r--common/usbc/usb_sm.c202
-rw-r--r--common/usbc/usb_tc_ctvpd_sm.c1716
-rw-r--r--common/usbc/usb_tc_drp_acc_trysrc_sm.c4160
-rw-r--r--common/usbc/usb_tc_vpd_sm.c430
-rw-r--r--common/usbc/usbc_pd_policy.c48
-rw-r--r--common/usbc/usbc_task.c182
19 files changed, 0 insertions, 20165 deletions
diff --git a/common/usbc/build.mk b/common/usbc/build.mk
deleted file mode 100644
index 48ab5351b8..0000000000
--- a/common/usbc/build.mk
+++ /dev/null
@@ -1,51 +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.
-
-# Build for USB Type-C and Power Delivery
-
-# Note that this variable includes the trailing "/"
-_usbc_dir:=$(dir $(lastword $(MAKEFILE_LIST)))
-
-ifneq ($(CONFIG_USB_PD_TCPMV2),)
-all-obj-$(CONFIG_USB_PD_TCPMV2)+=$(_usbc_dir)usb_pd_timer.o
-all-obj-$(CONFIG_USB_PD_TCPMV2)+=$(_usbc_dir)usb_sm.o
-all-obj-$(CONFIG_USB_PD_TCPMV2)+=$(_usbc_dir)usbc_task.o
-
-# Type-C state machines
-ifneq ($(CONFIG_USB_TYPEC_SM),)
-all-obj-$(CONFIG_USB_VPD)+=$(_usbc_dir)usb_tc_vpd_sm.o
-all-obj-$(CONFIG_USB_CTVPD)+=$(_usbc_dir)usb_tc_ctvpd_sm.o
-all-obj-$(CONFIG_USB_DRP_ACC_TRYSRC)+=$(_usbc_dir)usb_tc_drp_acc_trysrc_sm.o
-endif # CONFIG_USB_TYPEC_SM
-
-# Protocol state machine
-ifneq ($(CONFIG_USB_PRL_SM),)
-all-obj-$(CONFIG_USB_PD_TCPMV2)+=$(_usbc_dir)usb_prl_sm.o
-endif # CONFIG_USB_PRL_SM
-
-# Policy Engine state machines
-ifneq ($(CONFIG_USB_PE_SM),)
-all-obj-$(CONFIG_USB_VPD)+=$(_usbc_dir)usb_pe_ctvpd_sm.o
-all-obj-$(CONFIG_USB_CTVPD)+=$(_usbc_dir)usb_pe_ctvpd_sm.o
-all-obj-$(CONFIG_USB_DRP_ACC_TRYSRC)+=$(_usbc_dir)usbc_pd_policy.o
-all-obj-$(CONFIG_USB_DRP_ACC_TRYSRC)+=$(_usbc_dir)usb_pe_drp_sm.o
-all-obj-$(CONFIG_USB_DRP_ACC_TRYSRC)+=$(_usbc_dir)usb_pd_dpm.o
-all-obj-$(CONFIG_USB_DRP_ACC_TRYSRC)+=$(_usbc_dir)dp_alt_mode.o
-all-obj-$(CONFIG_USB_PD_TBT_COMPAT_MODE)+=$(_usbc_dir)tbt_alt_mode.o
-all-obj-$(CONFIG_USB_PD_USB4)+=$(_usbc_dir)usb_mode.o
-all-obj-$(CONFIG_CMD_PD)+=$(_usbc_dir)usb_pd_console.o
-all-obj-$(CONFIG_USB_PD_HOST_CMD)+=$(_usbc_dir)usb_pd_host.o
-endif # CONFIG_USB_PE_SM
-
-# Retimer firmware update
-all-obj-$(CONFIG_USBC_RETIMER_FW_UPDATE)+=$(_usbc_dir)usb_retimer_fw_update.o
-
-# ALT-DP mode for UFP ports
-all-obj-$(CONFIG_USB_PD_ALT_MODE_UFP_DP)+=$(_usbc_dir)usb_pd_dp_ufp.o
-endif # CONFIG_USB_PD_TCPMV2
-
-# For testing
-all-obj-$(CONFIG_TEST_USB_PE_SM)+=$(_usbc_dir)usbc_pd_policy.o
-all-obj-$(CONFIG_TEST_USB_PE_SM)+=$(_usbc_dir)usb_pe_drp_sm.o
-all-obj-$(CONFIG_TEST_SM)+=$(_usbc_dir)usb_sm.o
diff --git a/common/usbc/dp_alt_mode.c b/common/usbc/dp_alt_mode.c
deleted file mode 100644
index 9a3493c6e1..0000000000
--- a/common/usbc/dp_alt_mode.c
+++ /dev/null
@@ -1,292 +0,0 @@
-/* Copyright 2020 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.
- */
-
-/*
- * DisplayPort alternate mode support
- * Refer to VESA DisplayPort Alt Mode on USB Type-C Standard, version 2.0,
- * section 5.2
- */
-
-#include <stdbool.h>
-#include <stdint.h>
-#include "assert.h"
-#include "usb_common.h"
-#include "usb_dp_alt_mode.h"
-#include "usb_pd.h"
-#include "usb_pd_tcpm.h"
-
-#ifdef CONFIG_COMMON_RUNTIME
-#define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args)
-#define CPRINTS(format, args...) cprints(CC_USBPD, format, ## args)
-#else
-#define CPRINTF(format, args...)
-#define CPRINTS(format, args...)
-#endif
-
-/* The state of the DP negotiation */
-enum dp_states {
- DP_START = 0,
- DP_ENTER_ACKED,
- DP_ENTER_NAKED,
- DP_STATUS_ACKED,
- DP_ACTIVE,
- DP_ENTER_RETRY,
- DP_INACTIVE,
- DP_STATE_COUNT
-};
-static enum dp_states dp_state[CONFIG_USB_PD_PORT_MAX_COUNT];
-
-/*
- * Map of states to expected VDM commands in responses.
- * Default of 0 indicates no command expected.
- */
-static const uint8_t state_vdm_cmd[DP_STATE_COUNT] = {
- [DP_START] = CMD_ENTER_MODE,
- [DP_ENTER_ACKED] = CMD_DP_STATUS,
- [DP_STATUS_ACKED] = CMD_DP_CONFIG,
- [DP_ACTIVE] = CMD_EXIT_MODE,
- [DP_ENTER_NAKED] = CMD_EXIT_MODE,
- [DP_ENTER_RETRY] = CMD_ENTER_MODE,
-};
-
-bool dp_is_active(int port)
-{
- return dp_state[port] == DP_ACTIVE;
-}
-
-void dp_init(int port)
-{
- dp_state[port] = DP_START;
-}
-
-bool dp_entry_is_done(int port)
-{
- return dp_state[port] == DP_ACTIVE ||
- dp_state[port] == DP_INACTIVE;
-}
-
-static void dp_entry_failed(int port)
-{
- CPRINTS("C%d: DP alt mode protocol failed!", port);
- dp_state[port] = DP_INACTIVE;
-}
-
-static bool dp_response_valid(int port, enum tcpci_msg_type type,
- char *cmdt, int vdm_cmd)
-{
- enum dp_states st = dp_state[port];
-
- /*
- * Check for an unexpected response.
- * If DP is inactive, ignore the command.
- */
- if (type != TCPCI_MSG_SOP ||
- (st != DP_INACTIVE && state_vdm_cmd[st] != vdm_cmd)) {
- CPRINTS("C%d: Received unexpected DP VDM %s (cmd %d) from"
- " %s in state %d", port, cmdt, vdm_cmd,
- type == TCPCI_MSG_SOP ? "port partner" : "cable plug",
- st);
- dp_entry_failed(port);
- return false;
- }
- return true;
-}
-
-static void dp_exit_to_usb_mode(int port)
-{
- int opos = pd_alt_mode(port, TCPCI_MSG_SOP, USB_SID_DISPLAYPORT);
-
- pd_dfp_exit_mode(port, TCPCI_MSG_SOP, USB_SID_DISPLAYPORT, opos);
- set_usb_mux_with_current_data_role(port);
-
- CPRINTS("C%d: Exited DP mode", port);
- /*
- * If the EC exits an alt mode autonomously, don't try to enter it again. If
- * the AP commands the EC to exit DP mode, it might command the EC to enter
- * again later, so leave the state machine ready for that possibility.
- */
- dp_state[port] = IS_ENABLED(CONFIG_USB_PD_REQUIRE_AP_MODE_ENTRY)
- ? DP_START : DP_INACTIVE;
-}
-
-void dp_vdm_acked(int port, enum tcpci_msg_type type, int vdo_count,
- uint32_t *vdm)
-{
- const struct svdm_amode_data *modep =
- pd_get_amode_data(port, type, USB_SID_DISPLAYPORT);
- const uint8_t vdm_cmd = PD_VDO_CMD(vdm[0]);
-
- if (!dp_response_valid(port, type, "ACK", vdm_cmd))
- return;
-
- /* TODO(b/155890173): Validate VDO count for specific commands */
-
- switch (dp_state[port]) {
- case DP_START:
- case DP_ENTER_RETRY:
- dp_state[port] = DP_ENTER_ACKED;
- /* Inform PE layer that alt mode is now active */
- pd_set_dfp_enter_mode_flag(port, true);
- break;
- case DP_ENTER_ACKED:
- /* DP status response & UFP's DP attention have same payload. */
- dfp_consume_attention(port, vdm);
- dp_state[port] = DP_STATUS_ACKED;
- break;
- case DP_STATUS_ACKED:
- if (modep && modep->opos && modep->fx->post_config)
- modep->fx->post_config(port);
- dp_state[port] = DP_ACTIVE;
- CPRINTS("C%d: Entered DP mode", port);
- break;
- case DP_ACTIVE:
- /*
- * Request to exit mode successful, so put the module in an
- * inactive state.
- */
- dp_exit_to_usb_mode(port);
- break;
- case DP_ENTER_NAKED:
- /*
- * The request to exit the mode was successful,
- * so try to enter the mode again.
- */
- dp_state[port] = DP_ENTER_RETRY;
- break;
- case DP_INACTIVE:
- /*
- * This can occur if the mode is shutdown because
- * the CPU is being turned off, and an exit mode
- * command has been sent.
- */
- break;
- default:
- /* Invalid or unexpected negotiation state */
- CPRINTF("%s called with invalid state %d\n",
- __func__, dp_state[port]);
- dp_entry_failed(port);
- break;
- }
-}
-
-void dp_vdm_naked(int port, enum tcpci_msg_type type, uint8_t vdm_cmd)
-{
- if (!dp_response_valid(port, type, "NAK", vdm_cmd))
- return;
-
- switch (dp_state[port]) {
- case DP_START:
- /*
- * If a request to enter DP mode is NAK'ed, this likely
- * means the partner is already in DP alt mode, so
- * request to exit the mode first before retrying
- * the enter command. This can happen if the EC
- * is restarted (e.g to go into recovery mode) while
- * DP alt mode is active.
- */
- dp_state[port] = DP_ENTER_NAKED;
- break;
- case DP_ENTER_RETRY:
- /*
- * Another NAK on the second attempt to enter DP mode.
- * Give up.
- */
- dp_entry_failed(port);
- break;
- case DP_ACTIVE:
- /* Treat an Exit Mode NAK the same as an Exit Mode ACK. */
- dp_exit_to_usb_mode(port);
- break;
- default:
- CPRINTS("C%d: NAK for cmd %d in state %d", port,
- vdm_cmd, dp_state[port]);
- dp_entry_failed(port);
- break;
- }
-}
-
-int dp_setup_next_vdm(int port, int vdo_count, uint32_t *vdm)
-{
- const struct svdm_amode_data *modep = pd_get_amode_data(port,
- TCPCI_MSG_SOP, USB_SID_DISPLAYPORT);
- int vdo_count_ret;
-
- if (vdo_count < VDO_MAX_SIZE)
- return -1;
-
- switch (dp_state[port]) {
- case DP_START:
- case DP_ENTER_RETRY:
- /* Enter the first supported mode for DisplayPort. */
- vdm[0] = pd_dfp_enter_mode(port, TCPCI_MSG_SOP,
- USB_SID_DISPLAYPORT, 0);
- if (vdm[0] == 0)
- return -1;
- /* CMDT_INIT is 0, so this is a no-op */
- vdm[0] |= VDO_CMDT(CMDT_INIT);
- vdm[0] |= VDO_SVDM_VERS(pd_get_vdo_ver(port, TCPCI_MSG_SOP));
- vdo_count_ret = 1;
- if (dp_state[port] == DP_START)
- CPRINTS("C%d: Attempting to enter DP mode", port);
- break;
- case DP_ENTER_ACKED:
- if (!(modep && modep->opos))
- return -1;
-
- vdo_count_ret = modep->fx->status(port, vdm);
- if (vdo_count_ret == 0)
- return -1;
- vdm[0] |= PD_VDO_OPOS(modep->opos);
- vdm[0] |= VDO_CMDT(CMDT_INIT);
- vdm[0] |= VDO_SVDM_VERS(pd_get_vdo_ver(port, TCPCI_MSG_SOP));
- break;
- case DP_STATUS_ACKED:
- if (!(modep && modep->opos))
- return -1;
-
- vdo_count_ret = modep->fx->config(port, vdm);
- if (vdo_count_ret == 0)
- return -1;
- vdm[0] |= VDO_CMDT(CMDT_INIT);
- vdm[0] |= VDO_SVDM_VERS(pd_get_vdo_ver(port, TCPCI_MSG_SOP));
- break;
- case DP_ENTER_NAKED:
- case DP_ACTIVE:
- /*
- * Called to exit DP alt mode, either when the mode
- * is active and the system is shutting down, or
- * when an initial request to enter the mode is NAK'ed.
- * This can happen if the EC is restarted (e.g to go
- * into recovery mode) while DP alt mode is active.
- * It would be good to invoke modep->fx->exit but
- * this doesn't set up the VDM, it clears state.
- * TODO(b/159856063): Clean up the API to the fx functions.
- */
- if (!(modep && modep->opos))
- return -1;
-
- usb_mux_set_safe_mode_exit(port);
-
- vdm[0] = VDO(USB_SID_DISPLAYPORT,
- 1, /* structured */
- CMD_EXIT_MODE);
-
- vdm[0] |= VDO_OPOS(modep->opos);
- vdm[0] |= VDO_CMDT(CMDT_INIT);
- vdm[0] |= VDO_SVDM_VERS(pd_get_vdo_ver(port, TCPCI_MSG_SOP));
- vdo_count_ret = 1;
- break;
- case DP_INACTIVE:
- /*
- * DP mode is inactive.
- */
- return -1;
- default:
- CPRINTF("%s called with invalid state %d\n",
- __func__, dp_state[port]);
- return -1;
- }
- return vdo_count_ret;
-}
diff --git a/common/usbc/tbt_alt_mode.c b/common/usbc/tbt_alt_mode.c
deleted file mode 100644
index 73e2796345..0000000000
--- a/common/usbc/tbt_alt_mode.c
+++ /dev/null
@@ -1,579 +0,0 @@
-/* Copyright 2020 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.
- */
-
-/*
- * Thunderbolt alternate mode support
- * Refer to USB Type-C Cable and Connector Specification Release 2.0 Section F
- */
-
-#include "atomic.h"
-#include <stdbool.h>
-#include <stdint.h>
-#include "compile_time_macros.h"
-#include "console.h"
-#include "tcpm/tcpm.h"
-#include "usb_common.h"
-#include "usb_mux.h"
-#include "usb_pd.h"
-#include "usb_pd_tbt.h"
-#include "usb_pd_tcpm.h"
-#include "usb_pe_sm.h"
-#include "usb_tbt_alt_mode.h"
-
-/*
- * Enter/Exit TBT mode with active cable
- *
- *
- * TBT_START |------------
- * retry_done = false | |
- * | v |
- * |<------------------| Exit Mode SOP |
- * | retry_done = true | | |
- * v | | ACK/NAK |
- * Enter Mode SOP' | --------|--------- |
- * ACK | NAK | Exit Mode SOP'' |
- * |------|------| | | |
- * | | | | ACK/NAK |
- * v | | --------|--------- |
- * Enter Mode SOP'' | | Exit Mode SOP' |
- * | | | | |
- * ACK | NAK | | | ACK/NAK |
- * |------|------| | | ------------------ |
- * | | | | retry_done == true? |
- * v | | | | |
- * Enter Mode SOP | | | No | |
- * | | | |----------- |
- * ACK | NAK | | |Yes |
- * |-------|------| | | v |
- * | | | | TBT_INACTIVE |
- * v | | | retry_done = false |
- * TBT_ACTIVE | | | |
- * retry_done = true | | | |
- * | | | | |
- * v v v v |
- * -----------------------------------------------------------------|
- */
-
-#ifdef CONFIG_COMMON_RUNTIME
-#define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args)
-#define CPRINTS(format, args...) cprints(CC_USBPD, format, ## args)
-#else
-#define CPRINTF(format, args...)
-#define CPRINTS(format, args...)
-#endif
-
-/*
- * If a partner sends an Enter Mode NAK, Exit Mode and try again. This has
- * happened when the EC loses state after previously entering an alt mode
- * with a partner. It may be fixed in b/159495742, in which case this
- * logic is unneeded.
- */
-#define TBT_FLAG_RETRY_DONE BIT(0)
-#define TBT_FLAG_EXIT_DONE BIT(1)
-#define TBT_FLAG_CABLE_ENTRY_DONE BIT(2)
-
-static uint8_t tbt_flags[CONFIG_USB_PD_PORT_MAX_COUNT];
-
-#define TBT_SET_FLAG(port, flag) (tbt_flags[port] |= (flag))
-#define TBT_CLR_FLAG(port, flag) (tbt_flags[port] &= (~flag))
-#define TBT_CHK_FLAG(port, flag) (tbt_flags[port] & (flag))
-
-static int tbt_prints(const char *string, int port)
-{
- return CPRINTS("C%d: TBT %s", port, string);
-}
-
-/* The states of Thunderbolt negotiation */
-enum tbt_states {
- TBT_START = 0,
- TBT_ENTER_SOP,
- TBT_ACTIVE,
- TBT_EXIT_SOP,
- TBT_INACTIVE,
- /* Active cable only */
- TBT_ENTER_SOP_PRIME,
- TBT_ENTER_SOP_PRIME_PRIME,
- TBT_EXIT_SOP_PRIME,
- TBT_EXIT_SOP_PRIME_PRIME,
- TBT_STATE_COUNT,
-};
-static enum tbt_states tbt_state[CONFIG_USB_PD_PORT_MAX_COUNT];
-
-static const uint8_t state_vdm_cmd[TBT_STATE_COUNT] = {
- [TBT_ENTER_SOP] = CMD_ENTER_MODE,
- [TBT_ACTIVE] = CMD_EXIT_MODE,
- [TBT_EXIT_SOP] = CMD_EXIT_MODE,
- /* Active cable only */
- [TBT_ENTER_SOP_PRIME] = CMD_ENTER_MODE,
- [TBT_ENTER_SOP_PRIME_PRIME] = CMD_ENTER_MODE,
- [TBT_EXIT_SOP_PRIME] = CMD_EXIT_MODE,
- [TBT_EXIT_SOP_PRIME_PRIME] = CMD_EXIT_MODE,
-};
-
-void tbt_init(int port)
-{
- tbt_state[port] = TBT_START;
- TBT_CLR_FLAG(port, TBT_FLAG_RETRY_DONE);
- TBT_SET_FLAG(port, TBT_FLAG_EXIT_DONE);
- TBT_CLR_FLAG(port, TBT_FLAG_CABLE_ENTRY_DONE);
-}
-
-bool tbt_is_active(int port)
-{
- return tbt_state[port] != TBT_INACTIVE &&
- tbt_state[port] != TBT_START;
-}
-
-bool tbt_entry_is_done(int port)
-{
- return tbt_state[port] == TBT_ACTIVE ||
- tbt_state[port] == TBT_INACTIVE;
-}
-
-bool tbt_cable_entry_is_done(int port)
-{
- return TBT_CHK_FLAG(port, TBT_FLAG_CABLE_ENTRY_DONE);
-}
-
-static void tbt_exit_done(int port)
-{
- /*
- * If the EC exits an alt mode autonomously, don't try to enter it again. If
- * the AP commands the EC to exit DP mode, it might command the EC to enter
- * again later, so leave the state machine ready for that possibility.
- */
- tbt_state[port] = IS_ENABLED(CONFIG_USB_PD_REQUIRE_AP_MODE_ENTRY)
- ? TBT_START : TBT_INACTIVE;
- TBT_CLR_FLAG(port, TBT_FLAG_RETRY_DONE);
- TBT_CLR_FLAG(port, TBT_FLAG_CABLE_ENTRY_DONE);
-
- if (!TBT_CHK_FLAG(port, TBT_FLAG_EXIT_DONE)) {
- TBT_SET_FLAG(port, TBT_FLAG_EXIT_DONE);
- tbt_prints("Exited alternate mode", port);
- return;
- }
-
- tbt_prints("alt mode protocol failed!", port);
-}
-
-void tbt_exit_mode_request(int port)
-{
- union tbt_mode_resp_cable cable_mode_resp;
-
- TBT_SET_FLAG(port, TBT_FLAG_RETRY_DONE);
- TBT_CLR_FLAG(port, TBT_FLAG_EXIT_DONE);
- /*
- * If the port has entered USB4 mode with Thunderbolt mode for the
- * cable, on request to exit, only exit Thunderbolt mode for the
- * cable.
- * TODO (b/156749387): Remove once data reset feature is in place.
- */
- if (tbt_state[port] == TBT_ENTER_SOP) {
- cable_mode_resp.raw_value =
- pd_get_tbt_mode_vdo(port, TCPCI_MSG_SOP_PRIME);
-
- /*
- * For Linear re-driver cables, the port enters USB4 mode
- * with Thunderbolt mode for SOP prime. Hence, on request to
- * exit, only exit Thunderbolt mode SOP prime
- */
- tbt_state[port] =
- cable_mode_resp.tbt_active_passive == TBT_CABLE_ACTIVE ?
- TBT_EXIT_SOP_PRIME : TBT_EXIT_SOP_PRIME_PRIME;
- }
-}
-
-static bool tbt_response_valid(int port, enum tcpci_msg_type type,
- char *cmdt, int vdm_cmd)
-{
- enum tbt_states st = tbt_state[port];
- union tbt_mode_resp_cable cable_mode_resp = {
- .raw_value = pd_get_tbt_mode_vdo(port, TCPCI_MSG_SOP_PRIME) };
-
- /*
- * Check for an unexpected response.
- * 1. invalid command
- * 2. invalid Tx type for passive cable
- * If Thunderbolt is inactive, ignore the command.
- */
- if ((st != TBT_INACTIVE && state_vdm_cmd[st] != vdm_cmd) ||
- (get_usb_pd_cable_type(port) == IDH_PTYPE_PCABLE &&
- cable_mode_resp.tbt_active_passive == TBT_CABLE_PASSIVE &&
- type != TCPCI_MSG_SOP)) {
- tbt_exit_done(port);
- return false;
- }
- return true;
-}
-
-/* Exit Mode process is complete, but retry Enter Mode process */
-static void tbt_retry_enter_mode(int port)
-{
- tbt_state[port] = TBT_START;
- TBT_SET_FLAG(port, TBT_FLAG_RETRY_DONE);
-}
-
-/* Send Exit Mode to SOP''(if supported), or SOP' */
-static void tbt_active_cable_exit_mode(int port)
-{
- const struct pd_discovery *disc;
-
- disc = pd_get_am_discovery(port, TCPCI_MSG_SOP_PRIME);
-
- if (disc->identity.product_t1.a_rev20.sop_p_p)
- tbt_state[port] = TBT_EXIT_SOP_PRIME_PRIME;
- else
- tbt_state[port] = TBT_EXIT_SOP_PRIME;
-}
-
-bool tbt_cable_entry_required_for_usb4(int port)
-{
- const struct pd_discovery *disc_sop_prime;
- union tbt_mode_resp_cable cable_mode_resp;
-
- /* Request to enter Thunderbolt mode for the cable prior to entering
- * USB4 mode if -
- * 1. Thunderbolt Mode SOP' VDO active/passive bit (B25) is
- * TBT_CABLE_ACTIVE or
- * 2. It's an active cable with VDM version < 2.0 or
- * VDO version < 1.3
- */
- if (tbt_cable_entry_is_done(port))
- return false;
-
- cable_mode_resp.raw_value =
- pd_get_tbt_mode_vdo(port, TCPCI_MSG_SOP_PRIME);
-
- if (cable_mode_resp.tbt_active_passive == TBT_CABLE_ACTIVE)
- return true;
-
- if (get_usb_pd_cable_type(port) == IDH_PTYPE_ACABLE) {
- disc_sop_prime = pd_get_am_discovery(port, TCPCI_MSG_SOP_PRIME);
- if (pd_get_vdo_ver(port, TCPCI_MSG_SOP_PRIME) < VDM_VER20 ||
- disc_sop_prime->identity.product_t1.a_rev30.vdo_ver <
- VDO_VERSION_1_3)
- return true;
- }
- return false;
-}
-
-void intel_vdm_acked(int port, enum tcpci_msg_type type, int vdo_count,
- uint32_t *vdm)
-{
- const struct pd_discovery *disc;
- const uint8_t vdm_cmd = PD_VDO_CMD(vdm[0]);
- int opos_sop, opos_sop_prime;
- union tbt_mode_resp_cable cable_mode_resp;
-
- if (!tbt_response_valid(port, type, "ACK", vdm_cmd))
- return;
-
- disc = pd_get_am_discovery(port, TCPCI_MSG_SOP_PRIME);
-
- switch (tbt_state[port]) {
- case TBT_ENTER_SOP_PRIME:
- tbt_prints("enter mode SOP'", port);
- cable_mode_resp.raw_value =
- pd_get_tbt_mode_vdo(port, TCPCI_MSG_SOP_PRIME);
- /* For LRD cables, Enter mode SOP' -> Enter mode SOP */
- if (disc->identity.product_t1.a_rev20.sop_p_p &&
- cable_mode_resp.tbt_active_passive != TBT_CABLE_ACTIVE) {
- tbt_state[port] = TBT_ENTER_SOP_PRIME_PRIME;
- } else {
- TBT_SET_FLAG(port, TBT_FLAG_CABLE_ENTRY_DONE);
- tbt_state[port] = TBT_ENTER_SOP;
- }
- break;
- case TBT_ENTER_SOP_PRIME_PRIME:
- tbt_prints("enter mode SOP''", port);
- TBT_SET_FLAG(port, TBT_FLAG_CABLE_ENTRY_DONE);
- tbt_state[port] = TBT_ENTER_SOP;
- break;
- case TBT_ENTER_SOP:
- set_tbt_compat_mode_ready(port);
- tbt_state[port] = TBT_ACTIVE;
- tbt_prints("enter mode SOP", port);
- TBT_SET_FLAG(port, TBT_FLAG_RETRY_DONE);
- /* Indicate to PE layer that alt mode is active */
- pd_set_dfp_enter_mode_flag(port, true);
- break;
- case TBT_ACTIVE:
- tbt_prints("exit mode SOP", port);
- opos_sop = pd_alt_mode(port, TCPCI_MSG_SOP, USB_VID_INTEL);
-
- /* Clear Thunderbolt related signals */
- pd_dfp_exit_mode(port, TCPCI_MSG_SOP, USB_VID_INTEL, opos_sop);
- set_usb_mux_with_current_data_role(port);
- if (get_usb_pd_cable_type(port) == IDH_PTYPE_ACABLE) {
- tbt_active_cable_exit_mode(port);
- } else {
- /*
- * Exit Mode process is complete; go to inactive state.
- */
- tbt_exit_done(port);
- }
- break;
- case TBT_EXIT_SOP:
- set_usb_mux_with_current_data_role(port);
- if (get_usb_pd_cable_type(port) == IDH_PTYPE_ACABLE)
- tbt_active_cable_exit_mode(port);
- else {
- if (TBT_CHK_FLAG(port, TBT_FLAG_RETRY_DONE))
- /* retried enter mode, still failed, give up */
- tbt_exit_done(port);
- else
- tbt_retry_enter_mode(port);
- }
- break;
- case TBT_EXIT_SOP_PRIME_PRIME:
- tbt_prints("exit mode SOP''", port);
- tbt_state[port] = TBT_EXIT_SOP_PRIME;
- set_usb_mux_with_current_data_role(port);
- break;
- case TBT_EXIT_SOP_PRIME:
- tbt_prints("exit mode SOP'", port);
- if (TBT_CHK_FLAG(port, TBT_FLAG_RETRY_DONE)) {
- /*
- * Exit mode process is complete; go to inactive state.
- */
- tbt_exit_done(port);
- opos_sop_prime =
- pd_alt_mode(port, TCPCI_MSG_SOP_PRIME,
- USB_VID_INTEL);
-
- /* Clear Thunderbolt related signals */
- pd_dfp_exit_mode(port, TCPCI_MSG_SOP_PRIME,
- USB_VID_INTEL, opos_sop_prime);
- set_usb_mux_with_current_data_role(port);
- } else {
- tbt_retry_enter_mode(port);
- }
- break;
- case TBT_INACTIVE:
- /*
- * This can occur if the mode is shutdown because
- * the CPU is being turned off, and an exit mode
- * command has been sent.
- */
- break;
- default:
- /* Invalid or unexpected negotiation state */
- CPRINTF("%s called with invalid state %d\n",
- __func__, tbt_state[port]);
- tbt_exit_done(port);
- break;
- }
-}
-
-void intel_vdm_naked(int port, enum tcpci_msg_type type, uint8_t vdm_cmd)
-{
- if (!tbt_response_valid(port, type, "NAK", vdm_cmd))
- return;
-
- switch (tbt_state[port]) {
- case TBT_ENTER_SOP_PRIME:
- case TBT_ENTER_SOP_PRIME_PRIME:
- case TBT_ENTER_SOP:
- /*
- * If a request to enter Thunderbolt mode is NAK'ed, this
- * likely means the partner is already in Thunderbolt alt mode,
- * so request to exit the mode first before retrying the enter
- * command. This can happen if the EC is restarted
- */
- tbt_state[port] = TBT_EXIT_SOP;
- break;
- case TBT_ACTIVE:
- /* Exit SOP got NAK'ed */
- set_usb_mux_with_current_data_role(port);
- if (get_usb_pd_cable_type(port) == IDH_PTYPE_ACABLE)
- tbt_active_cable_exit_mode(port);
- else {
- tbt_prints("exit mode SOP failed", port);
- tbt_state[port] = TBT_INACTIVE;
- TBT_CLR_FLAG(port, TBT_FLAG_RETRY_DONE);
- }
- break;
- case TBT_EXIT_SOP:
- /* Exit SOP got NAK'ed */
- tbt_prints("exit mode SOP failed", port);
- set_usb_mux_with_current_data_role(port);
- if (get_usb_pd_cable_type(port) == IDH_PTYPE_ACABLE)
- tbt_active_cable_exit_mode(port);
- else {
- if (TBT_CHK_FLAG(port, TBT_FLAG_RETRY_DONE))
- /* Retried enter mode, still failed, give up */
- tbt_exit_done(port);
- else
- tbt_retry_enter_mode(port);
- }
- break;
- case TBT_EXIT_SOP_PRIME_PRIME:
- set_usb_mux_with_current_data_role(port);
- tbt_prints("exit mode SOP'' failed", port);
- tbt_state[port] = TBT_EXIT_SOP_PRIME;
- break;
- case TBT_EXIT_SOP_PRIME:
- set_usb_mux_with_current_data_role(port);
- if (TBT_CHK_FLAG(port, TBT_FLAG_RETRY_DONE)) {
- /*
- * Exit mode process is complete; go to inactive state.
- */
- tbt_prints("exit mode SOP' failed", port);
- tbt_exit_done(port);
- } else {
- tbt_retry_enter_mode(port);
- }
- break;
- default:
- CPRINTS("C%d: NAK for cmd %d in state %d", port,
- vdm_cmd, tbt_state[port]);
- tbt_exit_done(port);
- break;
- }
-}
-
-static bool tbt_mode_is_supported(int port, int vdo_count)
-{
- const struct pd_discovery *disc =
- pd_get_am_discovery(port, TCPCI_MSG_SOP);
-
- if (!disc->identity.idh.modal_support)
- return false;
-
- if (get_tbt_cable_speed(port) < TBT_SS_U31_GEN1)
- return false;
-
- /*
- * TBT4 PD Discovery Flow Application Notes Revision 0.9:
- * Figure 2: for active cable, SOP' should support
- * SVID USB_VID_INTEL to enter Thunderbolt alt mode
- */
- if (get_usb_pd_cable_type(port) == IDH_PTYPE_ACABLE &&
- !pd_is_mode_discovered_for_svid(
- port, TCPCI_MSG_SOP_PRIME, USB_VID_INTEL))
- return false;
-
- return true;
-}
-
-int tbt_setup_next_vdm(int port, int vdo_count, uint32_t *vdm,
- enum tcpci_msg_type *tx_type)
-{
- struct svdm_amode_data *modep;
- int vdo_count_ret = 0;
- union tbt_mode_resp_cable cable_mode_resp;
-
- *tx_type = TCPCI_MSG_SOP;
-
- if (vdo_count < VDO_MAX_SIZE)
- return -1;
-
- switch (tbt_state[port]) {
- case TBT_START:
- if (!tbt_mode_is_supported(port, vdo_count))
- return 0;
-
- if (!TBT_CHK_FLAG(port, TBT_FLAG_RETRY_DONE))
- tbt_prints("attempt to enter mode", port);
- else
- tbt_prints("retry to enter mode", port);
-
- cable_mode_resp.raw_value =
- pd_get_tbt_mode_vdo(port, TCPCI_MSG_SOP_PRIME);
-
- /* Active cable and LRD cables send Enter Mode SOP' first */
- if (get_usb_pd_cable_type(port) == IDH_PTYPE_ACABLE ||
- cable_mode_resp.tbt_active_passive == TBT_CABLE_ACTIVE) {
- vdo_count_ret = enter_tbt_compat_mode(port,
- TCPCI_MSG_SOP_PRIME, vdm);
- *tx_type = TCPCI_MSG_SOP_PRIME;
- tbt_state[port] = TBT_ENTER_SOP_PRIME;
- } else {
- /* Passive cable send Enter Mode SOP */
- vdo_count_ret =
- enter_tbt_compat_mode(port, TCPCI_MSG_SOP, vdm);
- tbt_state[port] = TBT_ENTER_SOP;
- }
- break;
- case TBT_ENTER_SOP_PRIME:
- vdo_count_ret =
- enter_tbt_compat_mode(port, TCPCI_MSG_SOP_PRIME, vdm);
- *tx_type = TCPCI_MSG_SOP_PRIME;
- break;
- case TBT_ENTER_SOP_PRIME_PRIME:
- vdo_count_ret =
- enter_tbt_compat_mode(
- port, TCPCI_MSG_SOP_PRIME_PRIME, vdm);
- *tx_type = TCPCI_MSG_SOP_PRIME_PRIME;
- break;
- case TBT_ENTER_SOP:
- vdo_count_ret =
- enter_tbt_compat_mode(port, TCPCI_MSG_SOP, vdm);
- break;
- case TBT_EXIT_SOP:
- case TBT_ACTIVE:
- /*
- * Called to exit Thunderbolt alt mode, either when the mode is
- * active and the system is shutting down, or when an initial
- * request to enter the mode is NAK'ed. This can happen if EC
- * is restarted while Thunderbolt mode is active.
- */
- modep = pd_get_amode_data(port,
- TCPCI_MSG_SOP, USB_VID_INTEL);
- if (!(modep && modep->opos))
- return -1;
-
- usb_mux_set_safe_mode_exit(port);
-
- vdm[0] = VDO(USB_VID_INTEL, 1, CMD_EXIT_MODE) |
- VDO_OPOS(modep->opos) |
- VDO_CMDT(CMDT_INIT) |
- VDO_SVDM_VERS(
- pd_get_vdo_ver(port, TCPCI_MSG_SOP));
- vdo_count_ret = 1;
- break;
- case TBT_EXIT_SOP_PRIME_PRIME:
- modep = pd_get_amode_data(port,
- TCPCI_MSG_SOP_PRIME, USB_VID_INTEL);
- if (!(modep && modep->opos))
- return -1;
-
- usb_mux_set_safe_mode_exit(port);
-
- vdm[0] = VDO(USB_VID_INTEL, 1, CMD_EXIT_MODE) |
- VDO_OPOS(modep->opos) |
- VDO_CMDT(CMDT_INIT) |
- VDO_SVDM_VERS(pd_get_vdo_ver(port,
- TCPCI_MSG_SOP_PRIME_PRIME));
- vdo_count_ret = 1;
- *tx_type = TCPCI_MSG_SOP_PRIME_PRIME;
- break;
- case TBT_EXIT_SOP_PRIME:
- modep = pd_get_amode_data(port,
- TCPCI_MSG_SOP_PRIME, USB_VID_INTEL);
- if (!(modep && modep->opos))
- return -1;
-
- usb_mux_set_safe_mode_exit(port);
-
- vdm[0] = VDO(USB_VID_INTEL, 1, CMD_EXIT_MODE) |
- VDO_OPOS(modep->opos) |
- VDO_CMDT(CMDT_INIT) |
- VDO_SVDM_VERS(pd_get_vdo_ver(port,
- TCPCI_MSG_SOP_PRIME));
- vdo_count_ret = 1;
- *tx_type = TCPCI_MSG_SOP_PRIME;
- break;
- case TBT_INACTIVE:
- /* Thunderbolt mode is inactive */
- return 0;
- default:
- CPRINTF("%s called with invalid state %d\n",
- __func__, tbt_state[port]);
- return -1;
- }
-
- return vdo_count_ret;
-}
diff --git a/common/usbc/usb_mode.c b/common/usbc/usb_mode.c
deleted file mode 100644
index b9dc4973bc..0000000000
--- a/common/usbc/usb_mode.c
+++ /dev/null
@@ -1,311 +0,0 @@
-/* Copyright 2020 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.
- */
-
-/*
- * USB4 mode support
- * Refer USB Type-C Cable and Connector Specification Release 2.0 Section 5 and
- * USB Power Delivery Specification Revision 3.0, Version 2.0 Section 6.4.8
- */
-
-#include <stdbool.h>
-#include <stdint.h>
-#include "compile_time_macros.h"
-#include "console.h"
-#include "tcpm/tcpm.h"
-#include "usb_common.h"
-#include "usb_mode.h"
-#include "usb_mux.h"
-#include "usb_pd.h"
-#include "usb_pd_dpm.h"
-#include "usb_pd_tcpm.h"
-#include "usb_pe_sm.h"
-#include "usbc_ppc.h"
-
-#ifdef CONFIG_COMMON_RUNTIME
-#define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args)
-#define CPRINTS(format, args...) cprints(CC_USBPD, format, ## args)
-#else
-#define CPRINTF(format, args...)
-#define CPRINTS(format, args...)
-#endif
-
-enum usb4_mode_status {
- USB4_MODE_FAILURE,
- USB4_MODE_SUCCESS,
-};
-
-enum usb4_states {
- USB4_START,
- USB4_ENTER_SOP,
- USB4_ENTER_SOP_PRIME,
- USB4_ENTER_SOP_PRIME_PRIME,
- USB4_ACTIVE,
- USB4_INACTIVE,
- USB4_STATE_COUNT,
-};
-
-/*
- * USB4 PD flow:
- *
- * Cable type
- * |
- * |-------- Passive ---|---- Active -----|
- * | |
- * USB Highest Speed Structured VDM version
- * | (cable revision)-- <2.0---->|
- * --------|--------|------| | |
- * | | | | >=2.0 |
- * >=Gen3 Gen2 Gen1 USB2.0 | |
- * | | | | VDO version--- <1.3 ---> Modal op? -- N --|
- * Enter USB | | | (B21:23 of | |
- * SOP with | | | Discover ID SOP'- y |
- * Gen3 cable | | Skip Active cable VDO1) | |
- * speed | | USB4 | TBT SVID? -- N --|
- * | | mode >=1.3 | |
- * Is modal op? | entry | y |
- * | | Cable USB4 - N | |
- * y | support? | Gen4 cable? - N - Skip
- * | | | Skip USB4 | USB4
- * Is TBT SVID? -N- Enter | mode entry | mode
- * | USB4 SOP | | entry
- * y with Gen2 y |
- * | cable speed | |
- * | | |
- * Is Discover mode | |
- * SOP' B25? - N - Enter Enter USB4 mode |
- * | USB4 SOP (SOP, SOP', SOP'') |
- * | with speed |
- * y from TBT mode |
- * | SOP' VDO |
- * | |<-- NAK -- Enter mode TBT SOP'<---|
- * |---->Enter TBT SOP'-------NAK------>| | | |
- * | | | | ACK |
- * | ACK | | | |
- * | | | |<-- NAK -- Enter mode TBT SOP'' |
- * | Enter USB4 SOP | | | |
- * | with speed from Exit TBT mode SOP ACK |
- * | TBT mode SOP' VDO | | | |
- * | ACK/NAK Enter USB4 SOP |
- * | | | with speed from |
- * | Exit TBT mode SOP'' TBT mode SOP' VDO |
- * | | | |
- * | ACK/NAK |
- * | | | |
- * | Exit TBT mode SOP' |
- * | | | |
- * | ACK/NAK |
- * | | | |
- * |---- N ----Retry done? -------------| |--------Retry done? ---- N -------|
- * | |
- * y y
- * | |
- * Skip USB4 mode entry Skip USB4 mode entry
- */
-
-static enum usb4_states usb4_state[CONFIG_USB_PD_PORT_MAX_COUNT];
-
-static void usb4_debug_prints(int port, enum usb4_mode_status usb4_status)
-{
- CPRINTS("C%d: USB4: State:%d Status:%d", port, usb4_state[port],
- usb4_status);
-}
-
-bool enter_usb_entry_is_done(int port)
-{
- return usb4_state[port] == USB4_ACTIVE ||
- usb4_state[port] == USB4_INACTIVE;
-}
-
-void usb4_exit_mode_request(int port)
-{
- usb4_state[port] = USB4_START;
- usb_mux_set_safe_mode_exit(port);
- set_usb_mux_with_current_data_role(port);
-}
-
-void enter_usb_init(int port)
-{
- usb4_state[port] = USB4_START;
-}
-
-void enter_usb_failed(int port)
-{
- /*
- * Since Enter USB sets the mux state to SAFE mode, fall back
- * to USB mode on receiving a NAK.
- */
- usb_mux_set(port, USB_PD_MUX_USB_ENABLED, USB_SWITCH_CONNECT,
- polarity_rm_dts(pd_get_polarity(port)));
-
- usb4_debug_prints(port, USB4_MODE_FAILURE);
- usb4_state[port] = USB4_INACTIVE;
-}
-
-static bool enter_usb_response_valid(int port, enum tcpci_msg_type type)
-{
- /*
- * Check for an unexpected response.
- */
- if (get_usb_pd_cable_type(port) == IDH_PTYPE_PCABLE &&
- type != TCPCI_MSG_SOP) {
- enter_usb_failed(port);
- return false;
- }
- return true;
-}
-
-bool enter_usb_port_partner_is_capable(int port)
-{
- const struct pd_discovery *disc =
- pd_get_am_discovery(port, TCPCI_MSG_SOP);
-
- if (usb4_state[port] == USB4_INACTIVE)
- return false;
-
- if (!PD_PRODUCT_IS_USB4(disc->identity.product_t1.raw_value))
- return false;
-
- return true;
-}
-
-bool enter_usb_cable_is_capable(int port)
-{
- if (get_usb_pd_cable_type(port) == IDH_PTYPE_PCABLE) {
- if (get_usb4_cable_speed(port) < USB_R30_SS_U32_U40_GEN1)
- return false;
- } else if (get_usb_pd_cable_type(port) == IDH_PTYPE_ACABLE) {
- const struct pd_discovery *disc_sop_prime =
- pd_get_am_discovery(port, TCPCI_MSG_SOP_PRIME);
-
- if (pd_get_vdo_ver(port, TCPCI_MSG_SOP_PRIME) >= VDM_VER20 &&
- disc_sop_prime->identity.product_t1.a_rev30.vdo_ver >=
- VDO_VERSION_1_3) {
- union active_cable_vdo2_rev30 a2_rev30 =
- disc_sop_prime->identity.product_t2.a2_rev30;
- /*
- * For VDM version >= 2.0 and VD0 version is >= 1.3,
- * do not enter USB4 mode if the cable isn't USB4
- * capable.
- */
- if (a2_rev30.usb_40_support == USB4_NOT_SUPPORTED)
- return false;
- /*
- * For VDM version < 2.0 or VDO version < 1.3, do not enter USB4
- * mode if the cable -
- * doesn't support modal operation or
- * doesn't support Intel SVID or
- * doesn't have rounded support.
- */
- } else {
- const struct pd_discovery *disc =
- pd_get_am_discovery(port, TCPCI_MSG_SOP);
- union tbt_mode_resp_cable cable_mode_resp = {
- .raw_value = pd_get_tbt_mode_vdo(port,
- TCPCI_MSG_SOP_PRIME) };
-
- if (!disc->identity.idh.modal_support ||
- !pd_is_mode_discovered_for_svid(port,
- TCPCI_MSG_SOP_PRIME, USB_VID_INTEL) ||
- cable_mode_resp.tbt_rounded !=
- TBT_GEN3_GEN4_ROUNDED_NON_ROUNDED)
- return false;
- }
- } else {
- /* Not Emark cable */
- return false;
- }
-
- return true;
-}
-
-void enter_usb_accepted(int port, enum tcpci_msg_type type)
-{
- const struct pd_discovery *disc;
-
- if (!enter_usb_response_valid(port, type))
- return;
-
- switch (usb4_state[port]) {
- case USB4_ENTER_SOP_PRIME:
- disc = pd_get_am_discovery(port, TCPCI_MSG_SOP_PRIME);
- if (disc->identity.product_t1.a_rev20.sop_p_p)
- usb4_state[port] = USB4_ENTER_SOP_PRIME_PRIME;
- else
- usb4_state[port] = USB4_ENTER_SOP;
- break;
- case USB4_ENTER_SOP_PRIME_PRIME:
- usb4_state[port] = USB4_ENTER_SOP;
- break;
- case USB4_ENTER_SOP:
- /* Connect the SBU and USB lines to the connector */
- if (IS_ENABLED(CONFIG_USBC_PPC_SBU))
- ppc_set_sbu(port, 1);
-
- usb4_state[port] = USB4_ACTIVE;
-
- /* Set usb mux to USB4 mode */
- usb_mux_set(port, USB_PD_MUX_USB4_ENABLED, USB_SWITCH_CONNECT,
- polarity_rm_dts(pd_get_polarity(port)));
-
- usb4_debug_prints(port, USB4_MODE_SUCCESS);
- break;
- case USB4_ACTIVE:
- break;
- default:
- enter_usb_failed(port);
- }
-}
-
-void enter_usb_rejected(int port, enum tcpci_msg_type type)
-{
- if (!enter_usb_response_valid(port, type) ||
- usb4_state[port] == USB4_ACTIVE)
- return;
-
- enter_usb_failed(port);
-}
-
-uint32_t enter_usb_setup_next_msg(int port, enum tcpci_msg_type *type)
-{
- const struct pd_discovery *disc_sop_prime;
-
- switch (usb4_state[port]) {
- case USB4_START:
- disc_sop_prime = pd_get_am_discovery(port, TCPCI_MSG_SOP_PRIME);
- /*
- * Ref: Tiger Lake Platform PD Controller Interface Requirements
- * for Integrated USBC, section A.2.2: USB4 as DFP.
- * Enter safe mode before sending Enter USB SOP/SOP'/SOP''
- * TODO (b/156749387): Remove once data reset feature is in
- * place.
- */
- usb_mux_set_safe_mode(port);
-
- if (pd_get_vdo_ver(port, TCPCI_MSG_SOP_PRIME) < VDM_VER20 ||
- disc_sop_prime->identity.product_t1.a_rev30.vdo_ver <
- VDO_VERSION_1_3 ||
- get_usb_pd_cable_type(port) == IDH_PTYPE_PCABLE) {
- usb4_state[port] = USB4_ENTER_SOP;
- } else {
- usb4_state[port] = USB4_ENTER_SOP_PRIME;
- *type = TCPCI_MSG_SOP_PRIME;
- }
- break;
- case USB4_ENTER_SOP_PRIME:
- *type = TCPCI_MSG_SOP_PRIME;
- break;
- case USB4_ENTER_SOP_PRIME_PRIME:
- *type = TCPCI_MSG_SOP_PRIME_PRIME;
- break;
- case USB4_ENTER_SOP:
- *type = TCPCI_MSG_SOP;
- break;
- case USB4_ACTIVE:
- return -1;
- default:
- return 0;
- }
- return get_enter_usb_msg_payload(port);
-}
diff --git a/common/usbc/usb_pd_console.c b/common/usbc/usb_pd_console.c
deleted file mode 100644
index bbee776611..0000000000
--- a/common/usbc/usb_pd_console.c
+++ /dev/null
@@ -1,212 +0,0 @@
-/* Copyright 2020 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 "usb_common.h"
-#include "usb_pd_timer.h"
-#include "usb_pe_sm.h"
-#include "usb_prl_sm.h"
-#include "usb_tc_sm.h"
-#include "usb_pd.h"
-#include "util.h"
-
-test_export_static int command_pd(int argc, char **argv)
-{
- int port;
- char *e;
-
- if (argc < 2)
- return EC_ERROR_PARAM_COUNT;
-
- if (!strcasecmp(argv[1], "dump")) {
- if (argc >= 3) {
- int level = strtoi(argv[2], &e, 10);
-
- if (*e)
- return EC_ERROR_PARAM2;
-
- if (level < DEBUG_DISABLE)
- level = DEBUG_DISABLE;
- else if (level > DEBUG_LEVEL_MAX)
- level = DEBUG_LEVEL_MAX;
-
- prl_set_debug_level(level);
- pe_set_debug_level(level);
- tc_set_debug_level(level);
- ccprintf("debug=%d\n", level);
- return EC_SUCCESS;
- }
- } else if (IS_ENABLED(CONFIG_USB_PD_TRY_SRC) &&
- !strcasecmp(argv[1], "trysrc")) {
- enum try_src_override_t ov = tc_get_try_src_override();
-
- if (argc >= 3) {
- ov = strtoi(argv[2], &e, 10);
- if (*e || ov > TRY_SRC_NO_OVERRIDE)
- return EC_ERROR_PARAM3;
- tc_try_src_override(ov);
- }
-
- if (ov == TRY_SRC_NO_OVERRIDE)
- ccprintf("Try.SRC System controlled\n");
- else
- ccprintf("Try.SRC Forced %s\n", ov ? "ON" : "OFF");
-
- return EC_SUCCESS;
- } else if (!strcasecmp(argv[1], "version")) {
- ccprintf("%d\n", PD_STACK_VERSION);
- return EC_SUCCESS;
- }
-
- /* command: pd <port> <subcmd> [args] */
- port = strtoi(argv[1], &e, 10);
- if (argc < 3)
- return EC_ERROR_PARAM_COUNT;
-
- if (*e || port >= CONFIG_USB_PD_PORT_MAX_COUNT)
- return EC_ERROR_PARAM2;
-
- if (IS_ENABLED(CONFIG_USB_PD_DUAL_ROLE)) {
- if (!strcasecmp(argv[2], "tx")) {
- pd_dpm_request(port, DPM_REQUEST_SNK_STARTUP);
- } else if (!strcasecmp(argv[2], "charger")) {
- pd_dpm_request(port, DPM_REQUEST_SRC_STARTUP);
- } else if (!strcasecmp(argv[2], "dev")) {
- int max_volt;
-
- if (argc >= 4) {
- max_volt = strtoi(argv[3], &e, 10) * 1000;
- if (*e)
- return EC_ERROR_PARAM3;
- } else {
- max_volt = pd_get_max_voltage();
- }
- pd_request_source_voltage(port, max_volt);
- pd_dpm_request(port, DPM_REQUEST_NEW_POWER_LEVEL);
- ccprintf("max req: %dmV\n", max_volt);
- } else if (!strcasecmp(argv[2], "disable")) {
- pd_comm_enable(port, 0);
- ccprintf("Port C%d disable\n", port);
- return EC_SUCCESS;
- } else if (!strcasecmp(argv[2], "enable")) {
- pd_comm_enable(port, 1);
- ccprintf("Port C%d enabled\n", port);
- return EC_SUCCESS;
- } else if (!strcasecmp(argv[2], "hard")) {
- pd_dpm_request(port, DPM_REQUEST_HARD_RESET_SEND);
- } else if (!strcasecmp(argv[2], "soft")) {
- pd_dpm_request(port, DPM_REQUEST_SOFT_RESET_SEND);
- } else if (!strcasecmp(argv[2], "swap")) {
- if (argc < 4)
- return EC_ERROR_PARAM_COUNT;
-
- if (!strcasecmp(argv[3], "power"))
- pd_dpm_request(port, DPM_REQUEST_PR_SWAP);
- else if (!strcasecmp(argv[3], "data"))
- pd_dpm_request(port, DPM_REQUEST_DR_SWAP);
- else if (IS_ENABLED(CONFIG_USBC_VCONN_SWAP) &&
- !strcasecmp(argv[3], "vconn"))
- pd_dpm_request(port, DPM_REQUEST_VCONN_SWAP);
- else
- return EC_ERROR_PARAM3;
- } else if (!strcasecmp(argv[2], "dualrole")) {
- if (argc < 4) {
- cflush();
- ccprintf("dual-role toggling: ");
- switch (pd_get_dual_role(port)) {
- case PD_DRP_TOGGLE_ON:
- ccprintf("on\n");
- break;
- case PD_DRP_TOGGLE_OFF:
- ccprintf("off\n");
- break;
- case PD_DRP_FREEZE:
- ccprintf("freeze\n");
- break;
- case PD_DRP_FORCE_SINK:
- ccprintf("force sink\n");
- break;
- case PD_DRP_FORCE_SOURCE:
- ccprintf("force source\n");
- break;
- cflush();
- }
- } else {
- if (!strcasecmp(argv[3], "on"))
- pd_set_dual_role(port,
- PD_DRP_TOGGLE_ON);
- else if (!strcasecmp(argv[3], "off"))
- pd_set_dual_role(port,
- PD_DRP_TOGGLE_OFF);
- else if (!strcasecmp(argv[3], "freeze"))
- pd_set_dual_role(port, PD_DRP_FREEZE);
- else if (!strcasecmp(argv[3], "sink"))
- pd_set_dual_role(port,
- PD_DRP_FORCE_SINK);
- else if (!strcasecmp(argv[3], "source"))
- pd_set_dual_role(port,
- PD_DRP_FORCE_SOURCE);
- else
- return EC_ERROR_PARAM4;
- }
- return EC_SUCCESS;
- }
- }
-
- if (!strcasecmp(argv[2], "state")) {
- cflush();
- ccprintf("Port C%d CC%d, %s - Role: %s-%s",
- port, pd_get_polarity(port) + 1,
- pd_comm_is_enabled(port) ? "Enable" : "Disable",
- pd_get_power_role(port) ==
- PD_ROLE_SOURCE ? "SRC" : "SNK",
- pd_get_data_role(port) == PD_ROLE_DFP ? "DFP" : "UFP");
-
- if (IS_ENABLED(CONFIG_USBC_VCONN))
- ccprintf("%s ", tc_is_vconn_src(port) ? "-VC" : "");
-
- ccprintf("TC State: %s, Flags: 0x%04x",
- tc_get_current_state(port),
- tc_get_flags(port));
-
- if (IS_ENABLED(CONFIG_USB_PE_SM))
- ccprintf(" PE State: %s, Flags: 0x%04x\n",
- pe_get_current_state(port),
- pe_get_flags(port));
- else
- ccprintf("\n");
-
- cflush();
- } else if (!strcasecmp(argv[2], "srccaps")) {
- pd_srccaps_dump(port);
- }
-
- if (IS_ENABLED(CONFIG_CMD_PD_TIMER) &&
- !strcasecmp(argv[2], "timer")) {
- pd_timer_dump(port);
- }
-
- return EC_SUCCESS;
-}
-DECLARE_CONSOLE_COMMAND(pd, command_pd,
- "version"
- "\ndump [0|1|2|3]"
-#ifdef CONFIG_USB_PD_TRY_SRC
- "\ntrysrc [0|1|2]"
-#endif
- "\n\t<port> state"
- "\n\t<port> srccaps"
-#ifdef CONFIG_CMD_PD_TIMER
- "\n\t<port> timer"
-#endif /* CONFIG_CMD_PD_TIMER */
-#ifdef CONFIG_USB_PD_DUAL_ROLE
- "|tx|charger|dev"
- "\n\t<port> disable|enable|soft|hard"
- "\n\t<port> dualrole [on|off|freeze|sink|source]"
- "\n\t<port> swap [power|data|vconn]"
-#endif /* CONFIG_USB_PD_DUAL_ROLE */
- ,
- "USB PD");
diff --git a/common/usbc/usb_pd_dp_ufp.c b/common/usbc/usb_pd_dp_ufp.c
deleted file mode 100644
index 0009b5c710..0000000000
--- a/common/usbc/usb_pd_dp_ufp.c
+++ /dev/null
@@ -1,448 +0,0 @@
-/* Copyright 2021 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.
- */
-
-/*
- * Functions required for UFP_D operation
- */
-
-#include "console.h"
-#include "gpio.h"
-#include "hooks.h"
-#include "system.h"
-#include "task.h"
-#include "usb_pd.h"
-#include "usb_pd_dp_ufp.h"
-
-
-#define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args)
-#define CPRINTS(format, args...) cprints(CC_USBPD, format, ## args)
-
-enum hpd_state {
- LOW_WAIT,
- HIGH_CHECK,
- HIGH_WAIT,
- LOW_CHECK,
- IRQ_CHECK,
-};
-
-#define EDGE_QUEUE_DEPTH BIT(3)
-#define EDGE_QUEUE_MASK (EDGE_QUEUE_DEPTH - 1)
-#define HPD_QUEUE_DEPTH BIT(2)
-#define HPD_QUEUE_MASK (HPD_QUEUE_DEPTH - 1)
-#define HPD_T_IRQ_MIN_PULSE 250
-#define HPD_T_IRQ_MAX_PULSE (2 * MSEC)
-#define HPD_T_MIN_DP_ATTEN (10 * MSEC)
-
-struct hpd_mark {
- int level;
- uint64_t ts;
-};
-
-struct hpd_edge {
- int overflow;
- uint32_t head;
- uint32_t tail;
- struct hpd_mark buffer[EDGE_QUEUE_DEPTH];
-};
-
-struct hpd_info {
- enum hpd_state state;
- int count;
- int send_enable;
- uint64_t timer;
- uint64_t last_send_ts;
- enum hpd_event queue[HPD_QUEUE_DEPTH];
- struct hpd_edge edges;
-};
-
-static struct hpd_info hpd;
-static struct mutex hpd_mutex;
-
-static int alt_dp_mode_opos[CONFIG_USB_PD_PORT_MAX_COUNT];
-
-void pd_ufp_set_dp_opos(int port, int opos)
-{
- alt_dp_mode_opos[port] = opos;
-}
-
-int pd_ufp_get_dp_opos(int port)
-{
- return alt_dp_mode_opos[port];
-}
-
-void pd_ufp_enable_hpd_send(int port)
-{
- /*
- * This control is used ensure that a DP_ATTENTION message is not sent
- * to the DFP-D before a DP_CONFIG messaage has been received. This
- * control is not strictly required by the spec, but some port partners
- * will get confused if DP_ATTENTION is sent prior to DP_CONFIG.
- */
- hpd.send_enable = 1;
-}
-
-static void hpd_to_dp_attention(void)
-{
- int port = hpd_config.port;
- int evt_index = hpd.count - 1;
- uint32_t vdm[2];
- uint32_t svdm_header;
- enum hpd_event evt;
- int opos = pd_ufp_get_dp_opos(port);
-
- if (!opos)
- return;
-
- /* Get the next hpd event from the queue */
- evt = hpd.queue[evt_index];
- /* Save timestamp of when most recent DP attention message was sent */
- hpd.last_send_ts = get_time().val;
-
- /*
- * Construct DP Attention message. This consists of the VDM header and
- * the DP_STATUS VDO.
- */
- svdm_header = VDO_SVDM_VERS(pd_get_vdo_ver(port, TCPCI_MSG_SOP)) |
- VDO_OPOS(opos) | CMD_ATTENTION;
- vdm[0] = VDO(USB_SID_DISPLAYPORT, 1, svdm_header);
-
- vdm[1] = VDO_DP_STATUS((evt == hpd_irq), /* IRQ_HPD */
- (evt != hpd_low), /* HPD_HI|LOW */
- 0, /* request exit DP */
- 0, /* request exit USB */
- dock_get_mf_preference(), /* MF pref */
- 1, /* enabled */
- 0, /* power low */
- 0x2);
-
- /* Send request to DPM to send an attention VDM */
- pd_request_vdm_attention(port, vdm, ARRAY_SIZE(vdm));
-
- /* If there are still events, need to shift the buffer */
- if (--hpd.count) {
- int i;
-
- for (i = 0; i < hpd.count; i++)
- hpd.queue[i] = hpd.queue[i + 1];
- }
-}
-
-static void hpd_queue_event(enum hpd_event evt)
-{
- /*
- * HPD events are put into a queue. However, this queue is not a typical
- * FIFO queue. Instead there are special rules based on which type of
- * event is being added.
- * HPD_LOW -> always resets the queue and must be in slot 0
- * HPD_HIGH -> must follow a HPD_LOW, so can only be in slot 0 or
- * slot 1.
- * HPD_IRQ -> There shall never be more than 2 HPD_IRQ events
- * stored in the queue and HPD_IRQ must follow HPD_HIGH
- *
- * Worst case for queueing HPD events is 4 events in the queue:
- * 0 - HPD_LOW
- * 1 - HPD_HIGH
- * 2 - HPD_IRQ
- * 3 - HPD_IRQ
- *
- * The above rules mean that HPD_LOW and HPD_HIGH events can always be
- * added to the queue since high must follow low and a low event resets
- * the queue. HPD_IRQ events are checked to make sure that they don't
- * overflow the queue and to ensure that no more than 2 hpd_irq events
- * are kept in the queue.
- */
- if (evt == hpd_irq) {
- if ((hpd.count >= HPD_QUEUE_DEPTH) || ((hpd.count >= 2) &&
- (hpd.queue[hpd.count - 2] == hpd_irq))) {
- CPRINTS("hpd: discard hpd: count - %d",
- hpd.count);
- return;
- }
- }
-
- if (evt == hpd_low) {
- hpd.count = 0;
- }
-
- /* Add event to the queue */
- hpd.queue[hpd.count++] = evt;
-}
-
-static void hpd_to_pd_converter(int level, uint64_t ts)
-{
- /*
- * HPD edges are marked in the irq routine. The converter state machine
- * runs in the hooks task and so there will be some delay between when
- * the edge was captured and when that edge is processed here in the
- * state machine. This means that the delitch timer (250 uSec) may have
- * already expired or is about to expire.
- *
- * If transitioning to timing dependent state, need to ensure the state
- * machine is executed again. All timers are relative to the ts value
- * passed into this routine. The timestamps passed into this routine
- * are either the values latched in the irq routine, or the current
- * time latched by the calling function. From the perspective of the
- * state machine, ts represents the current time.
- *
- * Note that all hpd queue events are contingent on detecting edges
- * on the incoming hpd gpio signal. The hpd->dp attention converter is
- * enabled/disabled as part of the svdm dp enter/exit response handler
- * functions. When the converter is disabled, gpio interrupts for the
- * hpd gpio signal are disabled so it will never execute, unless the
- * converter is enabled, and the converter is only enabled when the
- * UFP-D is actively in ALT-DP mode.
- */
- switch (hpd.state) {
- case LOW_WAIT:
- /*
- * In this state only expected event is a level change from low
- * to high.
- */
- if (level) {
- hpd.state = HIGH_CHECK;
- hpd.timer = ts + HPD_T_IRQ_MIN_PULSE;
- }
- break;
- case HIGH_CHECK:
- /*
- * In this state if level is high and deglitch timer is
- * exceeded, then state advances to HIGH_WAIT, otherwise return
- * to LOW_WAIT state.
- */
- if (!level || (ts <= hpd.timer)) {
- hpd.state = LOW_WAIT;
- } else {
- hpd.state = HIGH_WAIT;
- hpd_queue_event(hpd_high);
- }
- break;
- case HIGH_WAIT:
- /*
- * In this state, only expected event is a level change from
- * high to low. If current level is low, then advance to
- * LOW_CHECK for deglitch checking.
- */
- if (!level) {
- hpd.state = LOW_CHECK;
- hpd.timer = ts + HPD_T_IRQ_MIN_PULSE;
- }
- break;
- case LOW_CHECK:
- /*
- * This state is used to deglitch high->low level
- * change. However, due to processing latency, it's possible to
- * detect hpd_irq event if level is high and low pulse width was
- * valid.
- */
- if (!level) {
- /* Still low, now wait for IRQ or LOW determination */
- hpd.timer = ts + (HPD_T_IRQ_MAX_PULSE -
- HPD_T_IRQ_MIN_PULSE);
- hpd.state = IRQ_CHECK;
-
- } else {
- uint64_t irq_ts = hpd.timer + HPD_T_IRQ_MAX_PULSE -
- HPD_T_IRQ_MIN_PULSE;
- /*
- * If hpd is high now, this must have been an edge
- * event, but still need to determine if the pulse width
- * is longer than hpd_irq min pulse width. State will
- * advance to HIGH_WAIT, but if pulse width is < 2 msec,
- * must send hpd_irq event.
- */
- if ((ts >= hpd.timer) && (ts <= irq_ts)) {
- /* hpd irq detected */
- hpd_queue_event(hpd_irq);
- }
- hpd.state = HIGH_WAIT;
- }
- break;
- case IRQ_CHECK:
- /*
- * In this state deglitch time has already passed. If current
- * level is low and hpd_irq timer has expired, then go to
- * LOW_WAIT as hpd_low event has been detected. If level is high
- * and low pulse is < hpd_irq, hpd_irq event has been detected.
- */
- if (level) {
- hpd.state = HIGH_WAIT;
- if (ts <= hpd.timer) {
- hpd_queue_event(hpd_irq);
- }
- } else if (ts > hpd.timer) {
- hpd.state = LOW_WAIT;
- hpd_queue_event(hpd_low);
- }
- break;
- }
-}
-
-static void manage_hpd(void);
-DECLARE_DEFERRED(manage_hpd);
-
-static void manage_hpd(void)
-{
- int level;
- uint64_t ts = get_time().val;
- uint32_t num_hpd_events = (hpd.edges.head - hpd.edges.tail) &
- EDGE_QUEUE_MASK;
-
- /*
- * HPD edges are detected via GPIO interrupts. The ISR routine adds edge
- * info to a queue and scheudles this routine. If this routine is called
- * without a new edge detected, then it is being called due to a timer
- * event.
- */
-
- /* First check to see overflow condition has occurred */
- if (hpd.edges.overflow) {
- /* Disable hpd interrupts */
- usb_pd_hpd_converter_enable(0);
- /* Re-enable hpd converter */
- usb_pd_hpd_converter_enable(1);
- }
-
- if (num_hpd_events) {
- while(num_hpd_events-- > 0) {
- int idx = hpd.edges.tail;
-
- level = hpd.edges.buffer[idx].level;
- ts = hpd.edges.buffer[idx].ts;
-
- hpd_to_pd_converter(level, ts);
- hpd.edges.tail = (hpd.edges.tail + 1) & EDGE_QUEUE_MASK;
- }
- } else {
- /* no new edge event, so get current time and level */
- level = gpio_get_level(hpd_config.signal);
- ts = get_time().val;
- hpd_to_pd_converter(level, ts);
- }
-
- /*
- * If min time spacing requirement is exceeded and a hpd_event is
- * queued, then send DP_ATTENTION message.
- */
- if (hpd.count > 0) {
- /*
- * If at least one hpd event is pending in the queue, send
- * a DP_ATTENTION message if a DP_CONFIG message has been
- * received and have passed the minimum spacing interval.
- */
- if (hpd.send_enable &&
- ((get_time().val - hpd.last_send_ts) >
- HPD_T_MIN_DP_ATTEN)) {
- /* Generate DP_ATTENTION event pending in queue */
- hpd_to_dp_attention();
- } else {
- uint32_t callback_us;
-
- /*
- * Need to wait until until min spacing requirement of
- * DP attention messages. Set callback time to the min
- * value required. This callback time could be changed
- * based on hpd interrupts.
- *
- * This wait is also used to prevent a DP_ATTENTION
- * message from being sent before at least one DP_CONFIG
- * message has been received. If DP_ATTENTION messages
- * need to be delayed for this reason, then just wait
- * the minimum time spacing.
- */
- callback_us = HPD_T_MIN_DP_ATTEN -
- (get_time().val - hpd.last_send_ts);
- if (callback_us <= 0 ||
- callback_us > HPD_T_MIN_DP_ATTEN)
- callback_us = HPD_T_MIN_DP_ATTEN;
- hook_call_deferred(&manage_hpd_data, callback_us);
- }
- }
-
- /*
- * Because of the delay between gpio edge irq, and when those edge
- * events are processed here, all timers must be done relative to the
- * timing marker stored in the hpd edge queue. If the state machine
- * required a new timer, then hpd.timer will be advanced relative to the
- * ts that was passed into the state machine.
- *
- * If the deglitch timer is active, then it can likely already have been
- * expired when the edge gets processed. So if the timer is active the
- * deferred callback must be requested.
- *.
- */
- if (hpd.timer > ts) {
- uint64_t callback_us = 0;
- uint64_t now = get_time().val;
-
- /* If timer is in the future, adjust the callback timer */
- if (now < hpd.timer)
- callback_us = (hpd.timer - now) & 0xffffffff;
-
- hook_call_deferred(&manage_hpd_data, callback_us);
- }
-}
-
-void usb_pd_hpd_converter_enable(int enable)
-{
- /*
- * The hpd converter should be enabled as part of the UFP-D enter mode
- * response function. Likewise, the converter should be disabled by the
- * exit mode function. In addition, the coverter may get disabled so
- * that it can be reset in the case that the input gpio edges queue
- * overflows. A muxtex must be used here since this function may be
- * called from the PD task (enter/exit response mode functions) or from
- * the hpd event handler state machine (hook task).
- */
- mutex_lock(&hpd_mutex);
-
- if (enable) {
- gpio_disable_interrupt(hpd_config.signal);
- /* Reset HPD event queue */
- hpd.state = LOW_WAIT;
- hpd.count = 0;
- hpd.timer = 0;
- hpd.last_send_ts = 0;
- hpd.send_enable = 0;
-
- /* Reset hpd signal edges queue */
- hpd.edges.head = 0;
- hpd.edges.tail = 0;
- hpd.edges.overflow = 0;
-
- /* If signal is high, need to ensure state machine executes */
- if (gpio_get_level(hpd_config.signal))
- hook_call_deferred(&manage_hpd_data, 0);
-
- /* Enable hpd edge detection */
- gpio_enable_interrupt(hpd_config.signal);
- } else {
- gpio_disable_interrupt(hpd_config.signal);
- hook_call_deferred(&manage_hpd_data, -1);
- }
-
- mutex_unlock(&hpd_mutex);
-}
-
-void usb_pd_hpd_edge_event(int signal)
-{
- int next_head = (hpd.edges.head + 1) & EDGE_QUEUE_MASK;
- struct hpd_mark mark;
-
- /* Get current timestamp and level */
- mark.ts = get_time().val;
- mark.level = gpio_get_level(hpd_config.signal);
-
- /* Add this edge to the buffer if there is space */
- if (next_head != hpd.edges.tail) {
- hpd.edges.buffer[hpd.edges.head].ts = mark.ts;
- hpd.edges.buffer[hpd.edges.head].level = mark.level;
- hpd.edges.head = next_head;
- } else {
- /* Edge queue is overflowing, need to reset the converter */
- hpd.edges.overflow = 1;
- }
- /* Schedule HPD state machine to run ASAP */
- hook_call_deferred(&manage_hpd_data, 0);
-}
diff --git a/common/usbc/usb_pd_dpm.c b/common/usbc/usb_pd_dpm.c
deleted file mode 100644
index eb2dfc52c0..0000000000
--- a/common/usbc/usb_pd_dpm.c
+++ /dev/null
@@ -1,704 +0,0 @@
-/* Copyright 2020 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.
- */
-
-/*
- * Device Policy Manager implementation
- * Refer to USB PD 3.0 spec, version 2.0, sections 8.2 and 8.3
- */
-
-#include "charge_state.h"
-#include "compile_time_macros.h"
-#include "console.h"
-#include "ec_commands.h"
-#include "hooks.h"
-#include "system.h"
-#include "task.h"
-#include "tcpm/tcpm.h"
-#include "usb_dp_alt_mode.h"
-#include "usb_mode.h"
-#include "usb_pd.h"
-#include "usb_pd_dpm.h"
-#include "usb_pd_tcpm.h"
-#include "usb_tbt_alt_mode.h"
-
-#ifdef CONFIG_COMMON_RUNTIME
-#define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args)
-#define CPRINTS(format, args...) cprints(CC_USBPD, format, ## args)
-#else
-#define CPRINTF(format, args...)
-#define CPRINTS(format, args...)
-#endif
-
-/* Max Attention length is header + 1 VDO */
-#define DPM_ATTENION_MAX_VDO 2
-
-static struct {
- uint32_t flags;
- uint32_t vdm_attention[DPM_ATTENION_MAX_VDO];
- int vdm_cnt;
- mutex_t vdm_attention_mutex;
-} dpm[CONFIG_USB_PD_PORT_MAX_COUNT];
-
-#define DPM_SET_FLAG(port, flag) atomic_or(&dpm[(port)].flags, (flag))
-#define DPM_CLR_FLAG(port, flag) atomic_clear_bits(&dpm[(port)].flags, (flag))
-#define DPM_CHK_FLAG(port, flag) (dpm[(port)].flags & (flag))
-
-/* Flags for internal DPM state */
-#define DPM_FLAG_MODE_ENTRY_DONE BIT(0)
-#define DPM_FLAG_EXIT_REQUEST BIT(1)
-#define DPM_FLAG_ENTER_DP BIT(2)
-#define DPM_FLAG_ENTER_TBT BIT(3)
-#define DPM_FLAG_ENTER_USB4 BIT(4)
-#define DPM_FLAG_SEND_ATTENTION BIT(5)
-
-#ifdef CONFIG_ZEPHYR
-static int init_vdm_attention_mutex(const struct device *dev)
-{
- int port;
-
- ARG_UNUSED(dev);
-
- for (port = 0; port < CONFIG_USB_PD_PORT_MAX_COUNT; port++)
- k_mutex_init(&dpm[port].vdm_attention_mutex);
-
- return 0;
-}
-SYS_INIT(init_vdm_attention_mutex, POST_KERNEL, 50);
-#endif /* CONFIG_ZEPHYR */
-
-enum ec_status pd_request_vdm_attention(int port, const uint32_t *data,
- int vdo_count)
-{
- mutex_lock(&dpm[port].vdm_attention_mutex);
-
- /* Only one Attention message may be pending */
- if (DPM_CHK_FLAG(port, DPM_FLAG_SEND_ATTENTION)) {
- mutex_unlock(&dpm[port].vdm_attention_mutex);
- return EC_RES_UNAVAILABLE;
- }
-
- /* SVDM Attention message must be 1 or 2 VDOs in length */
- if (!vdo_count || (vdo_count > DPM_ATTENION_MAX_VDO)) {
- mutex_unlock(&dpm[port].vdm_attention_mutex);
- return EC_RES_INVALID_PARAM;
- }
-
- /* Save contents of Attention message */
- memcpy(dpm[port].vdm_attention, data, vdo_count * sizeof(uint32_t));
- dpm[port].vdm_cnt = vdo_count;
-
- /*
- * Indicate to DPM that an Attention message needs to be sent. This flag
- * will be cleared when the Attention message is sent to the policy
- * engine.
- */
- DPM_SET_FLAG(port, DPM_FLAG_SEND_ATTENTION);
-
- mutex_unlock(&dpm[port].vdm_attention_mutex);
-
- return EC_RES_SUCCESS;
-}
-
-enum ec_status pd_request_enter_mode(int port, enum typec_mode mode)
-{
- if (port >= board_get_usb_pd_port_count())
- return EC_RES_INVALID_PARAM;
-
- /* Only one enter request may be active at a time. */
- if (DPM_CHK_FLAG(port, DPM_FLAG_ENTER_DP |
- DPM_FLAG_ENTER_TBT |
- DPM_FLAG_ENTER_USB4))
- return EC_RES_BUSY;
-
- switch (mode) {
- case TYPEC_MODE_DP:
- DPM_SET_FLAG(port, DPM_FLAG_ENTER_DP);
- break;
-#ifdef CONFIG_USB_PD_TBT_COMPAT_MODE
- case TYPEC_MODE_TBT:
- DPM_SET_FLAG(port, DPM_FLAG_ENTER_TBT);
- break;
-#endif /* CONFIG_USB_PD_TBT_COMPAT_MODE */
-#ifdef CONFIG_USB_PD_USB4
- case TYPEC_MODE_USB4:
- DPM_SET_FLAG(port, DPM_FLAG_ENTER_USB4);
- break;
-#endif
- default:
- return EC_RES_INVALID_PARAM;
- }
-
- DPM_CLR_FLAG(port, DPM_FLAG_MODE_ENTRY_DONE);
- DPM_CLR_FLAG(port, DPM_FLAG_EXIT_REQUEST);
-
- return EC_RES_SUCCESS;
-}
-
-void dpm_init(int port)
-{
- dpm[port].flags = 0;
-}
-
-static void dpm_set_mode_entry_done(int port)
-{
- DPM_SET_FLAG(port, DPM_FLAG_MODE_ENTRY_DONE);
- DPM_CLR_FLAG(port, DPM_FLAG_ENTER_DP | DPM_FLAG_ENTER_TBT |
- DPM_FLAG_ENTER_USB4);
-}
-
-void dpm_set_mode_exit_request(int port)
-{
- DPM_SET_FLAG(port, DPM_FLAG_EXIT_REQUEST);
-}
-
-static void dpm_clear_mode_exit_request(int port)
-{
- DPM_CLR_FLAG(port, DPM_FLAG_EXIT_REQUEST);
-}
-
-/*
- * Returns true if the current policy requests that the EC try to enter this
- * mode on this port. If the EC is in charge of policy, the answer is always
- * yes.
- */
-static bool dpm_mode_entry_requested(int port, enum typec_mode mode)
-{
- /* If the AP isn't controlling policy, the EC is. */
- if (!IS_ENABLED(CONFIG_USB_PD_REQUIRE_AP_MODE_ENTRY))
- return true;
-
- switch (mode) {
- case TYPEC_MODE_DP:
- return !!DPM_CHK_FLAG(port, DPM_FLAG_ENTER_DP);
- case TYPEC_MODE_TBT:
- return !!DPM_CHK_FLAG(port, DPM_FLAG_ENTER_TBT);
- case TYPEC_MODE_USB4:
- return !!DPM_CHK_FLAG(port, DPM_FLAG_ENTER_USB4);
- default:
- return false;
- }
-}
-
-void dpm_vdm_acked(int port, enum tcpci_msg_type type, int vdo_count,
- uint32_t *vdm)
-{
- const uint16_t svid = PD_VDO_VID(vdm[0]);
-
- assert(vdo_count >= 1);
-
- switch (svid) {
- case USB_SID_DISPLAYPORT:
- dp_vdm_acked(port, type, vdo_count, vdm);
- break;
- case USB_VID_INTEL:
- if (IS_ENABLED(CONFIG_USB_PD_TBT_COMPAT_MODE)) {
- intel_vdm_acked(port, type, vdo_count, vdm);
- break;
- }
- default:
- CPRINTS("C%d: Received unexpected VDM ACK for SVID %d", port,
- svid);
- }
-}
-
-void dpm_vdm_naked(int port, enum tcpci_msg_type type, uint16_t svid,
- uint8_t vdm_cmd)
-{
- switch (svid) {
- case USB_SID_DISPLAYPORT:
- dp_vdm_naked(port, type, vdm_cmd);
- break;
- case USB_VID_INTEL:
- if (IS_ENABLED(CONFIG_USB_PD_TBT_COMPAT_MODE)) {
- intel_vdm_naked(port, type, vdm_cmd);
- break;
- }
- default:
- CPRINTS("C%d: Received unexpected VDM NAK for SVID %d", port,
- svid);
- }
-}
-
-/*
- * Requests that the PE send one VDM, whichever is next in the mode entry
- * sequence. This only happens if preconditions for mode entry are met. If
- * CONFIG_USB_PD_REQUIRE_AP_MODE_ENTRY is enabled, this function waits for the
- * AP to direct mode entry.
- */
-static void dpm_attempt_mode_entry(int port)
-{
- int vdo_count = 0;
- uint32_t vdm[VDO_MAX_SIZE];
- enum tcpci_msg_type tx_type = TCPCI_MSG_SOP;
- bool enter_mode_requested =
- IS_ENABLED(CONFIG_USB_PD_REQUIRE_AP_MODE_ENTRY) ? false : true;
-
- if (pd_get_data_role(port) != PD_ROLE_DFP) {
- if (DPM_CHK_FLAG(port, DPM_FLAG_ENTER_DP |
- DPM_FLAG_ENTER_TBT |
- DPM_FLAG_ENTER_USB4))
- DPM_CLR_FLAG(port, DPM_FLAG_ENTER_DP |
- DPM_FLAG_ENTER_TBT |
- DPM_FLAG_ENTER_USB4);
- /*
- * TODO(b/168030639): Notify the AP that the enter mode request
- * failed.
- */
- return;
- }
-
-#ifdef HAS_TASK_CHIPSET
- /*
- * Do not try to enter mode while CPU is off.
- * CPU transitions (e.g b/158634281) can occur during the discovery
- * phase or during enter/exit negotiations, and the state
- * of the modes can get out of sync, causing the attempt to
- * enter the mode to fail prematurely.
- */
- if (chipset_in_or_transitioning_to_state(CHIPSET_STATE_ANY_OFF))
- return;
-#endif
- /*
- * If discovery has not occurred for modes, do not attempt to switch
- * to alt mode.
- */
- if (pd_get_svids_discovery(port, TCPCI_MSG_SOP) != PD_DISC_COMPLETE ||
- pd_get_modes_discovery(port, TCPCI_MSG_SOP) != PD_DISC_COMPLETE)
- return;
-
- if (dp_entry_is_done(port) ||
- (IS_ENABLED(CONFIG_USB_PD_TBT_COMPAT_MODE) &&
- tbt_entry_is_done(port)) ||
- (IS_ENABLED(CONFIG_USB_PD_USB4) && enter_usb_entry_is_done(port))) {
- dpm_set_mode_entry_done(port);
- return;
- }
-
- /* Check if port, port partner and cable support USB4. */
- if (IS_ENABLED(CONFIG_USB_PD_USB4) &&
- board_is_tbt_usb4_port(port) &&
- enter_usb_port_partner_is_capable(port) &&
- enter_usb_cable_is_capable(port) &&
- dpm_mode_entry_requested(port, TYPEC_MODE_USB4)) {
- /*
- * For certain cables, enter Thunderbolt alt mode with the
- * cable and USB4 mode with the port partner.
- */
- if (tbt_cable_entry_required_for_usb4(port)) {
- vdo_count = tbt_setup_next_vdm(port,
- ARRAY_SIZE(vdm), vdm, &tx_type);
- } else {
- pd_dpm_request(port, DPM_REQUEST_ENTER_USB);
- return;
- }
- }
-
- /* If not, check if they support Thunderbolt alt mode. */
- if (IS_ENABLED(CONFIG_USB_PD_TBT_COMPAT_MODE) &&
- board_is_tbt_usb4_port(port) &&
- pd_is_mode_discovered_for_svid(port, TCPCI_MSG_SOP,
- USB_VID_INTEL) &&
- dpm_mode_entry_requested(port, TYPEC_MODE_TBT)) {
- enter_mode_requested = true;
- vdo_count = tbt_setup_next_vdm(port,
- ARRAY_SIZE(vdm), vdm, &tx_type);
- }
-
- /* If not, check if they support DisplayPort alt mode. */
- if (vdo_count == 0 && !DPM_CHK_FLAG(port, DPM_FLAG_MODE_ENTRY_DONE) &&
- pd_is_mode_discovered_for_svid(port, TCPCI_MSG_SOP,
- USB_SID_DISPLAYPORT) &&
- dpm_mode_entry_requested(port, TYPEC_MODE_DP)) {
- enter_mode_requested = true;
- vdo_count = dp_setup_next_vdm(port, ARRAY_SIZE(vdm), vdm);
- }
-
- /*
- * If the PE didn't discover any supported (requested) alternate mode,
- * just mark setup done and get out of here.
- */
- if (vdo_count == 0 && !DPM_CHK_FLAG(port, DPM_FLAG_MODE_ENTRY_DONE)) {
- if (enter_mode_requested) {
- /*
- * TODO(b/168030639): Notify the AP that mode entry
- * failed.
- */
- CPRINTS("C%d: No supported alt mode discovered", port);
- }
- /*
- * If the AP did not request mode entry, it may do so in the
- * future, but the DPM is done trying for now.
- */
- dpm_set_mode_entry_done(port);
- return;
- }
-
- if (vdo_count < 0) {
- dpm_set_mode_entry_done(port);
- CPRINTS("C%d: Couldn't construct alt mode VDM", port);
- return;
- }
-
- /*
- * TODO(b/155890173): Provide a host command to request that the PE send
- * an arbitrary VDM via this mechanism.
- */
- if (!pd_setup_vdm_request(port, tx_type, vdm, vdo_count)) {
- dpm_set_mode_entry_done(port);
- return;
- }
-
- pd_dpm_request(port, DPM_REQUEST_VDM);
-}
-
-static void dpm_attempt_mode_exit(int port)
-{
- uint32_t vdm = 0;
- int vdo_count = 0;
- enum tcpci_msg_type tx_type = TCPCI_MSG_SOP;
-
- if (IS_ENABLED(CONFIG_USB_PD_USB4) &&
- enter_usb_entry_is_done(port)) {
- CPRINTS("C%d: USB4 teardown", port);
- usb4_exit_mode_request(port);
- }
- if (IS_ENABLED(CONFIG_USB_PD_TBT_COMPAT_MODE) &&
- tbt_is_active(port)) {
- /*
- * When the port is in USB4 mode and receives an exit request,
- * it leaves USB4 SOP in active state.
- * TODO(b/156749387): Support Data Reset for exiting USB4 SOP.
- */
- CPRINTS("C%d: TBT teardown", port);
- tbt_exit_mode_request(port);
- vdo_count = tbt_setup_next_vdm(port, VDO_MAX_SIZE, &vdm,
- &tx_type);
- } else if (dp_is_active(port)) {
- CPRINTS("C%d: DP teardown", port);
- vdo_count = dp_setup_next_vdm(port, VDO_MAX_SIZE, &vdm);
- } else {
- /* Clear exit mode request */
- dpm_clear_mode_exit_request(port);
- return;
- }
-
- if (!pd_setup_vdm_request(port, tx_type, &vdm, vdo_count)) {
- dpm_clear_mode_exit_request(port);
- return;
- }
-
- pd_dpm_request(port, DPM_REQUEST_VDM);
-}
-
-static void dpm_send_attention_vdm(int port)
-{
- /* Set up VDM ATTEN msg that was passed in previously */
- if (pd_setup_vdm_request(port, TCPCI_MSG_SOP, dpm[port].vdm_attention,
- dpm[port].vdm_cnt) == true)
- /* Trigger PE to start a VDM command run */
- pd_dpm_request(port, DPM_REQUEST_VDM);
-
- /* Clear flag after message is sent to PE layer */
- DPM_CLR_FLAG(port, DPM_FLAG_SEND_ATTENTION);
-}
-
-void dpm_run(int port)
-{
- if (pd_get_data_role(port) == PD_ROLE_DFP) {
- /* Run DFP related DPM requests */
- if (DPM_CHK_FLAG(port, DPM_FLAG_EXIT_REQUEST))
- dpm_attempt_mode_exit(port);
- else if (!DPM_CHK_FLAG(port, DPM_FLAG_MODE_ENTRY_DONE))
- dpm_attempt_mode_entry(port);
- } else {
- /* Run UFP related DPM requests */
- if (DPM_CHK_FLAG(port, DPM_FLAG_SEND_ATTENTION))
- dpm_send_attention_vdm(port);
- }
-}
-
-/*
- * Source-out policy variables and APIs
- *
- * Priority for the available 3.0 A ports is given in the following order:
- * - sink partners which report requiring > 1.5 A in their Sink_Capabilities
- */
-
-/*
- * Bitmasks of port numbers in each following category
- *
- * Note: request bitmasks should be accessed atomically as other ports may alter
- * them
- */
-static uint32_t max_current_claimed;
-K_MUTEX_DEFINE(max_current_claimed_lock);
-
-/* Ports with PD sink needing > 1.5 A */
-static uint32_t sink_max_pdo_requested;
-/* Ports with FRS source needing > 1.5 A */
-static uint32_t source_frs_max_requested;
-/* Ports with non-PD sinks, so current requirements are unknown */
-static uint32_t non_pd_sink_max_requested;
-
-#define LOWEST_PORT(p) __builtin_ctz(p) /* Undefined behavior if p == 0 */
-
-static int count_port_bits(uint32_t bitmask)
-{
- int i, total = 0;
-
- for (i = 0; i < board_get_usb_pd_port_count(); i++) {
- if (bitmask & BIT(i))
- total++;
- }
-
- return total;
-}
-
-/*
- * Centralized, mutex-controlled updates to the claimed 3.0 A ports
- */
-static void balance_source_ports(void);
-DECLARE_DEFERRED(balance_source_ports);
-
-static void balance_source_ports(void)
-{
- uint32_t removed_ports, new_ports;
- static bool deferred_waiting;
-
- if (task_get_current() == TASK_ID_HOOKS)
- deferred_waiting = false;
-
- /*
- * Ignore balance attempts while we're waiting for a downgraded port to
- * finish the downgrade.
- */
- if (deferred_waiting)
- return;
-
- mutex_lock(&max_current_claimed_lock);
-
- /* Remove any ports which no longer require 3.0 A */
- removed_ports = max_current_claimed & ~(sink_max_pdo_requested |
- source_frs_max_requested |
- non_pd_sink_max_requested);
- max_current_claimed &= ~removed_ports;
-
- /* Allocate 3.0 A to new PD sink ports that need it */
- new_ports = sink_max_pdo_requested & ~max_current_claimed;
- while (new_ports) {
- int new_max_port = LOWEST_PORT(new_ports);
-
- if (count_port_bits(max_current_claimed) <
- CONFIG_USB_PD_3A_PORTS) {
- max_current_claimed |= BIT(new_max_port);
- typec_select_src_current_limit_rp(new_max_port,
- TYPEC_RP_3A0);
- } else if (non_pd_sink_max_requested & max_current_claimed) {
- /* Always downgrade non-PD ports first */
- int rem_non_pd = LOWEST_PORT(non_pd_sink_max_requested &
- max_current_claimed);
- typec_select_src_current_limit_rp(rem_non_pd,
- typec_get_default_current_limit_rp(rem_non_pd));
- max_current_claimed &= ~BIT(rem_non_pd);
-
- /* Wait tSinkAdj before using current */
- deferred_waiting = true;
- hook_call_deferred(&balance_source_ports_data,
- PD_T_SINK_ADJ);
- goto unlock;
- } else if (source_frs_max_requested & max_current_claimed) {
- /* Downgrade lowest FRS port from 3.0 A slot */
- int rem_frs = LOWEST_PORT(source_frs_max_requested &
- max_current_claimed);
- pd_dpm_request(rem_frs, DPM_REQUEST_FRS_DET_DISABLE);
- max_current_claimed &= ~BIT(rem_frs);
-
- /* Give 20 ms for the PD task to process DPM flag */
- deferred_waiting = true;
- hook_call_deferred(&balance_source_ports_data,
- 20 * MSEC);
- goto unlock;
- } else {
- /* No lower priority ports to downgrade */
- goto unlock;
- }
- new_ports &= ~BIT(new_max_port);
- }
-
- /* Allocate 3.0 A to any new FRS ports that need it */
- new_ports = source_frs_max_requested & ~max_current_claimed;
- while (new_ports) {
- int new_frs_port = LOWEST_PORT(new_ports);
-
- if (count_port_bits(max_current_claimed) <
- CONFIG_USB_PD_3A_PORTS) {
- max_current_claimed |= BIT(new_frs_port);
- pd_dpm_request(new_frs_port,
- DPM_REQUEST_FRS_DET_ENABLE);
- } else if (non_pd_sink_max_requested & max_current_claimed) {
- int rem_non_pd = LOWEST_PORT(non_pd_sink_max_requested &
- max_current_claimed);
- typec_select_src_current_limit_rp(rem_non_pd,
- typec_get_default_current_limit_rp(rem_non_pd));
- max_current_claimed &= ~BIT(rem_non_pd);
-
- /* Wait tSinkAdj before using current */
- deferred_waiting = true;
- hook_call_deferred(&balance_source_ports_data,
- PD_T_SINK_ADJ);
- goto unlock;
- } else {
- /* No lower priority ports to downgrade */
- goto unlock;
- }
- new_ports &= ~BIT(new_frs_port);
- }
-
- /* Allocate 3.0 A to any non-PD ports which could need it */
- new_ports = non_pd_sink_max_requested & ~max_current_claimed;
- while (new_ports) {
- int new_max_port = LOWEST_PORT(new_ports);
-
- if (count_port_bits(max_current_claimed) <
- CONFIG_USB_PD_3A_PORTS) {
- max_current_claimed |= BIT(new_max_port);
- typec_select_src_current_limit_rp(new_max_port,
- TYPEC_RP_3A0);
- } else {
- /* No lower priority ports to downgrade */
- goto unlock;
- }
- new_ports &= ~BIT(new_max_port);
- }
-unlock:
- mutex_unlock(&max_current_claimed_lock);
-}
-
-/* Process port's first Sink_Capabilities PDO for port current consideration */
-void dpm_evaluate_sink_fixed_pdo(int port, uint32_t vsafe5v_pdo)
-{
- /* Verify partner supplied valid vSafe5V fixed object first */
- if ((vsafe5v_pdo & PDO_TYPE_MASK) != PDO_TYPE_FIXED)
- return;
-
- if (PDO_FIXED_VOLTAGE(vsafe5v_pdo) != 5000)
- return;
-
- if (pd_get_power_role(port) == PD_ROLE_SOURCE) {
- if (CONFIG_USB_PD_3A_PORTS == 0)
- return;
-
- /* Valid PDO to process, so evaluate whether >1.5A is needed */
- if (PDO_FIXED_CURRENT(vsafe5v_pdo) <= 1500)
- return;
-
- atomic_or(&sink_max_pdo_requested, BIT(port));
- } else {
- int frs_current = vsafe5v_pdo & PDO_FIXED_FRS_CURR_MASK;
-
- if (!IS_ENABLED(CONFIG_USB_PD_FRS))
- return;
-
- /* FRS is only supported in PD 3.0 and higher */
- if (pd_get_rev(port, TCPCI_MSG_SOP) == PD_REV20)
- return;
-
- if ((vsafe5v_pdo & PDO_FIXED_DUAL_ROLE) && frs_current) {
- /* Always enable FRS when 3.0 A is not needed */
- if (frs_current == PDO_FIXED_FRS_CURR_DFLT_USB_POWER ||
- frs_current == PDO_FIXED_FRS_CURR_1A5_AT_5V) {
- pd_dpm_request(port,
- DPM_REQUEST_FRS_DET_ENABLE);
- return;
- }
-
- if (CONFIG_USB_PD_3A_PORTS == 0)
- return;
-
- atomic_or(&source_frs_max_requested, BIT(port));
- } else {
- return;
- }
- }
-
- balance_source_ports();
-}
-
-void dpm_add_non_pd_sink(int port)
-{
- if (CONFIG_USB_PD_3A_PORTS == 0)
- return;
-
- atomic_or(&non_pd_sink_max_requested, BIT(port));
-
- balance_source_ports();
-}
-
-void dpm_remove_sink(int port)
-{
- if (CONFIG_USB_PD_3A_PORTS == 0)
- return;
-
- if (!(BIT(port) & sink_max_pdo_requested) &&
- !(BIT(port) & non_pd_sink_max_requested))
- return;
-
- atomic_clear_bits(&sink_max_pdo_requested, BIT(port));
- atomic_clear_bits(&non_pd_sink_max_requested, BIT(port));
-
- /* Restore selected default Rp on the port */
- typec_select_src_current_limit_rp(port,
- typec_get_default_current_limit_rp(port));
-
- balance_source_ports();
-}
-
-void dpm_remove_source(int port)
-{
- if (CONFIG_USB_PD_3A_PORTS == 0)
- return;
-
- if (!IS_ENABLED(CONFIG_USB_PD_FRS))
- return;
-
- if (!(BIT(port) & source_frs_max_requested))
- return;
-
- atomic_clear_bits(&source_frs_max_requested, BIT(port));
-
- balance_source_ports();
-}
-
-/*
- * Note: all ports receive the 1.5 A source offering until they are found to
- * match a criteria on the 3.0 A priority list (ex. through sink capability
- * probing), at which point they will be offered a new 3.0 A source capability.
- */
-__overridable int dpm_get_source_pdo(const uint32_t **src_pdo, const int port)
-{
- /* Max PDO may not exist on boards which don't offer 3 A */
-#if CONFIG_USB_PD_3A_PORTS > 0
- if (max_current_claimed & BIT(port)) {
- *src_pdo = pd_src_pdo_max;
- return pd_src_pdo_max_cnt;
- }
-#endif
-
- *src_pdo = pd_src_pdo;
- return pd_src_pdo_cnt;
-}
-
-int dpm_get_source_current(const int port)
-{
- if (pd_get_power_role(port) == PD_ROLE_SINK)
- return 0;
-
- if (max_current_claimed & BIT(port))
- return 3000;
- else if (typec_get_default_current_limit_rp(port) == TYPEC_RP_1A5)
- return 1500;
- else
- return 500;
-}
diff --git a/common/usbc/usb_pd_host.c b/common/usbc/usb_pd_host.c
deleted file mode 100644
index 4d0fadeec3..0000000000
--- a/common/usbc/usb_pd_host.c
+++ /dev/null
@@ -1,179 +0,0 @@
-/* Copyright 2020 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.
- *
- * Host commands for TCPMv2 USB PD module
- */
-
-#include <string.h>
-
-#include "console.h"
-#include "ec_commands.h"
-#include "host_command.h"
-#include "usb_mux.h"
-#include "usb_pd.h"
-#include "usb_pd_tcpm.h"
-#include "util.h"
-
-#define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args)
-#define CPRINTS(format, args...) cprints(CC_USBPD, format, ## args)
-
-/* Retrieve all discovery results for the given port and transmit type */
-static enum ec_status hc_typec_discovery(struct host_cmd_handler_args *args)
-{
- const struct ec_params_typec_discovery *p = args->params;
- struct ec_response_typec_discovery *r = args->response;
- const struct pd_discovery *disc;
- enum tcpci_msg_type type;
-
- /* Confirm the number of HC VDOs matches our stored VDOs */
- BUILD_ASSERT(sizeof(r->discovery_vdo) == sizeof(union disc_ident_ack));
-
- if (p->port >= board_get_usb_pd_port_count())
- return EC_RES_INVALID_PARAM;
-
- if (p->partner_type > TYPEC_PARTNER_SOP_PRIME)
- return EC_RES_INVALID_PARAM;
-
- type = p->partner_type == TYPEC_PARTNER_SOP ?
- TCPCI_MSG_SOP : TCPCI_MSG_SOP_PRIME;
-
- /*
- * Clear out access mask so we can track if tasks have touched data
- * since read started.
- */
- pd_discovery_access_clear(p->port, type);
-
- disc = pd_get_am_discovery_and_notify_access(p->port, type);
-
- /* Initialize return size to that of discovery with no SVIDs */
- args->response_size = sizeof(*r);
-
- if (pd_get_identity_discovery(p->port, type) == PD_DISC_COMPLETE) {
- r->identity_count = disc->identity_cnt;
- memcpy(r->discovery_vdo,
- pd_get_identity_response(p->port, type)->raw_value,
- sizeof(r->discovery_vdo));
- } else {
- r->identity_count = 0;
- return EC_RES_SUCCESS;
- }
-
- if (pd_get_modes_discovery(p->port, type) == PD_DISC_COMPLETE) {
- int svid_i;
- int max_resp_svids = (args->response_max - args->response_size)/
- sizeof(struct svid_mode_info);
-
- if (disc->svid_cnt > max_resp_svids) {
- CPRINTS("Warn: SVIDS exceeded HC response");
- r->svid_count = max_resp_svids;
- } else {
- r->svid_count = disc->svid_cnt;
- }
-
- for (svid_i = 0; svid_i < r->svid_count; svid_i++) {
- r->svids[svid_i].svid = disc->svids[svid_i].svid;
- r->svids[svid_i].mode_count =
- disc->svids[svid_i].mode_cnt;
- memcpy(r->svids[svid_i].mode_vdo,
- disc->svids[svid_i].mode_vdo,
- sizeof(r->svids[svid_i].mode_vdo));
- args->response_size += sizeof(struct svid_mode_info);
- }
- } else {
- r->svid_count = 0;
- }
-
- /*
- * Verify that another task did not access this data during the duration
- * of the copy. If the data was accessed, return BUSY so the AP will
- * try retrieving again and get the updated data.
- */
- if (!pd_discovery_access_validate(p->port, type)) {
- CPRINTS("[C%d] %s returns EC_RES_BUSY!!\n", p->port, __func__);
- return EC_RES_BUSY;
- }
-
- return EC_RES_SUCCESS;
-}
-DECLARE_HOST_COMMAND(EC_CMD_TYPEC_DISCOVERY,
- hc_typec_discovery,
- EC_VER_MASK(0));
-
-static enum ec_status hc_typec_control(struct host_cmd_handler_args *args)
-{
- const struct ec_params_typec_control *p = args->params;
-
- if (p->port >= board_get_usb_pd_port_count())
- return EC_RES_INVALID_PARAM;
-
- switch (p->command) {
- case TYPEC_CONTROL_COMMAND_EXIT_MODES:
- pd_dpm_request(p->port, DPM_REQUEST_EXIT_MODES);
- break;
- case TYPEC_CONTROL_COMMAND_CLEAR_EVENTS:
- pd_clear_events(p->port, p->clear_events_mask);
- break;
- case TYPEC_CONTROL_COMMAND_ENTER_MODE:
- return pd_request_enter_mode(p->port, p->mode_to_enter);
- default:
- return EC_RES_INVALID_PARAM;
- }
-
-
- return EC_RES_SUCCESS;
-}
-DECLARE_HOST_COMMAND(EC_CMD_TYPEC_CONTROL, hc_typec_control, EC_VER_MASK(0));
-
-static enum ec_status hc_typec_status(struct host_cmd_handler_args *args)
-{
- const struct ec_params_typec_status *p = args->params;
- struct ec_response_typec_status *r = args->response;
- const char *tc_state_name;
-
- if (p->port >= board_get_usb_pd_port_count())
- return EC_RES_INVALID_PARAM;
-
- if (args->response_max < sizeof(*r))
- return EC_RES_RESPONSE_TOO_BIG;
-
- args->response_size = sizeof(*r);
-
- r->pd_enabled = pd_comm_is_enabled(p->port);
- r->dev_connected = pd_is_connected(p->port);
- r->sop_connected = pd_capable(p->port);
-
- r->power_role = pd_get_power_role(p->port);
- r->data_role = pd_get_data_role(p->port);
- r->vconn_role = pd_get_vconn_state(p->port) ? PD_ROLE_VCONN_SRC :
- PD_ROLE_VCONN_OFF;
- r->polarity = pd_get_polarity(p->port);
- r->cc_state = pd_get_task_cc_state(p->port);
- r->dp_pin = get_dp_pin_mode(p->port);
- r->mux_state = usb_mux_get(p->port);
-
- tc_state_name = pd_get_task_state_name(p->port);
- strzcpy(r->tc_state, tc_state_name, sizeof(r->tc_state));
-
- r->events = pd_get_events(p->port);
-
- r->sop_revision = r->sop_connected ?
- PD_STATUS_REV_SET_MAJOR(pd_get_rev(p->port, TCPCI_MSG_SOP)) : 0;
- r->sop_prime_revision =
- pd_get_identity_discovery(p->port, TCPCI_MSG_SOP_PRIME) ==
- PD_DISC_COMPLETE ?
- PD_STATUS_REV_SET_MAJOR(pd_get_rev(p->port,
- TCPCI_MSG_SOP_PRIME))
- : 0;
-
- r->source_cap_count = pd_get_src_cap_cnt(p->port);
- memcpy(r->source_cap_pdos, pd_get_src_caps(p->port),
- r->source_cap_count * sizeof(uint32_t));
-
- r->sink_cap_count = pd_get_snk_cap_cnt(p->port);
- memcpy(r->sink_cap_pdos, pd_get_snk_caps(p->port),
- r->sink_cap_count * sizeof(uint32_t));
-
- return EC_RES_SUCCESS;
-}
-DECLARE_HOST_COMMAND(EC_CMD_TYPEC_STATUS, hc_typec_status, EC_VER_MASK(0));
diff --git a/common/usbc/usb_pd_timer.c b/common/usbc/usb_pd_timer.c
deleted file mode 100644
index 67a574904f..0000000000
--- a/common/usbc/usb_pd_timer.c
+++ /dev/null
@@ -1,268 +0,0 @@
-/* Copyright 2021 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 "assert.h"
-#include "common.h"
-#include "console.h"
-#include "limits.h"
-#include "system.h"
-#include "usb_pd_timer.h"
-#include "usb_tc_sm.h"
-
-#define MAX_PD_PORTS CONFIG_USB_PD_PORT_MAX_COUNT
-#define MAX_PD_TIMERS PD_TIMER_COUNT
-#define PD_TIMERS_ALL_MASK ((uint32_t)(((uint64_t)1 << PD_TIMER_COUNT) - 1))
-
-#define MAX_EXPIRE (0x7FFFFFFF)
-#define NO_TIMEOUT (-1)
-#define EXPIRE_NOW (0)
-
-#define PD_SET_ACTIVE(p, m) atomic_or(&timer_active[p], (m))
-#define PD_CLR_ACTIVE(p, m) atomic_clear_bits(&timer_active[p], (m))
-#define PD_CHK_ACTIVE(p, m) (timer_active[p] & (m))
-
-#define PD_SET_DISABLED(p, m) atomic_or(&timer_disabled[p], (m))
-#define PD_CLR_DISABLED(p, m) atomic_clear_bits(&timer_disabled[p], (m))
-#define PD_CHK_DISABLED(p, m) (timer_disabled[p] & (m))
-
-static uint32_t timer_active[MAX_PD_PORTS];
-static uint32_t timer_disabled[MAX_PD_PORTS];
-static uint64_t timer_expires[MAX_PD_PORTS][MAX_PD_TIMERS];
-
-/*
- * CONFIG_CMD_PD_TIMER debug variables
- */
-static int count[MAX_PD_PORTS];
-static int max_count[MAX_PD_PORTS];
-
-__maybe_unused static __const_data const char * const pd_timer_names[] = {
- [PE_TIMER_BIST_CONT_MODE] = "PE-BIST_CONT_MODE",
- [PE_TIMER_CHUNKING_NOT_SUPPORTED] = "PE-CHUNKING_NOT_SUPPORTED",
- [PE_TIMER_DISCOVER_IDENTITY] = "PE-DISCOVER_IDENTITY",
- [PE_TIMER_NO_RESPONSE] = "PE-NO_RESPONSE",
- [PE_TIMER_PR_SWAP_WAIT] = "PE-PR_SWAP_WAIT",
- [PE_TIMER_PS_HARD_RESET] = "PE-PS_HARD_RESET",
- [PE_TIMER_PS_SOURCE] = "PE-PS_SOURCE",
- [PE_TIMER_PS_TRANSITION] = "PE-PS_TRANSITION",
- [PE_TIMER_SENDER_RESPONSE] = "PE-SENDER_RESPONSE",
- [PE_TIMER_SINK_REQUEST] = "PE-SINK_REQUEST",
- [PE_TIMER_SOURCE_CAP] = "PE-SOURCE_CAP",
- [PE_TIMER_SRC_TRANSITION] = "PE-SRC_TRANSITION",
- [PE_TIMER_SWAP_SOURCE_START] = "PE-SWAP_SOURCE_START",
- [PE_TIMER_TIMEOUT] = "PE-TIMEOUT",
- [PE_TIMER_VCONN_ON] = "PE-VCONN_ON",
- [PE_TIMER_VDM_RESPONSE] = "PE-VDM_RESPONSE",
- [PE_TIMER_WAIT_AND_ADD_JITTER] = "PE-WAIT_AND_ADD_JITTER",
-
- [PR_TIMER_CHUNK_SENDER_REQUEST] = "PR-CHUNK_SENDER_REQUEST",
- [PR_TIMER_CHUNK_SENDER_RESPONSE] = "PR-CHUNK_SENDER_RESPONSE",
- [PR_TIMER_HARD_RESET_COMPLETE] = "PR-HARD_RESET_COMPLETE",
- [PR_TIMER_SINK_TX] = "PR-SINK_TX",
- [PR_TIMER_TCPC_TX_TIMEOUT] = "PR-TCPC_TX_TIMEOUT",
-
- [TC_TIMER_CC_DEBOUNCE] = "TC-CC_DEBOUNCE",
- [TC_TIMER_LOW_POWER_EXIT_TIME] = "TC-LOW_POWER_EXIT_TIME",
- [TC_TIMER_LOW_POWER_TIME] = "TC-LOW_POWER_TIME",
- [TC_TIMER_NEXT_ROLE_SWAP] = "TC-NEXT_ROLE_SWAP",
- [TC_TIMER_PD_DEBOUNCE] = "TC-PD_DEBOUNCE",
- [TC_TIMER_TIMEOUT] = "TC-TIMEOUT",
- [TC_TIMER_TRY_WAIT_DEBOUNCE] = "TC-TRY_WAIT_DEBOUNCE",
- [TC_TIMER_VBUS_DEBOUNCE] = "TC-VBUS_DEBOUNCE",
-};
-
-/*****************************************************************************
- * PD_TIMER private functions
- *
- * The view of timers to the outside world is enabled and disabled. Internally
- * timers that are enabled are in the active and inactive states. An active
- * timer has a valid timeout value that gets checked for expiration and can
- * adjust the task wakeup time. An inactive timer is assumed to have expired
- * already and will always return that it is still expired. This timer state
- * will not adjust the task scheduling timeout value.
- */
-static void pd_timer_inactive(int port, enum pd_task_timer timer)
-{
- uint32_t mask = 1 << timer;
-
- if (PD_CHK_ACTIVE(port, mask)) {
- PD_CLR_ACTIVE(port, mask);
-
- if (IS_ENABLED(CONFIG_CMD_PD_TIMER))
- count[port]--;
- }
- PD_CLR_DISABLED(port, mask);
-}
-
-static bool pd_timer_is_active(int port, enum pd_task_timer timer)
-{
- uint32_t mask = 1 << timer;
-
- return PD_CHK_ACTIVE(port, mask);
-}
-
-static bool pd_timer_is_inactive(int port, enum pd_task_timer timer)
-{
- uint32_t mask = 1 << timer;
-
- return !PD_CHK_ACTIVE(port, mask) && !PD_CHK_DISABLED(port, mask);
-}
-
-/*****************************************************************************
- * PD_TIMER public functions
- */
-void pd_timer_init(int port)
-{
- if (IS_ENABLED(CONFIG_CMD_PD_TIMER))
- count[port] = 0;
-
- PD_CLR_ACTIVE(port, PD_TIMERS_ALL_MASK);
- PD_SET_DISABLED(port, PD_TIMERS_ALL_MASK);
-}
-
-void pd_timer_enable(int port, enum pd_task_timer timer, uint32_t expires_us)
-{
- uint32_t mask = 1 << timer;
-
- if (!PD_CHK_ACTIVE(port, mask)) {
- PD_SET_ACTIVE(port, mask);
-
- if (IS_ENABLED(CONFIG_CMD_PD_TIMER)) {
- count[port]++;
- if (count[port] > max_count[port])
- max_count[port] = count[port];
- }
- }
- PD_CLR_DISABLED(port, mask);
- timer_expires[port][timer] = get_time().val + expires_us;
-}
-
-void pd_timer_disable(int port, enum pd_task_timer timer)
-{
- uint32_t mask = 1 << timer;
-
- if (PD_CHK_ACTIVE(port, mask)) {
- PD_CLR_ACTIVE(port, mask);
-
- if (IS_ENABLED(CONFIG_CMD_PD_TIMER))
- count[port]--;
- }
- PD_SET_DISABLED(port, mask);
-}
-
-void pd_timer_disable_range(int port, enum pd_timer_range range)
-{
- int start, end;
- enum pd_task_timer timer;
-
- switch (range) {
- case PE_TIMER_RANGE:
- start = PE_TIMER_START;
- end = PE_TIMER_END;
- break;
- case PR_TIMER_RANGE:
- start = PR_TIMER_START;
- end = PR_TIMER_END;
- break;
- case TC_TIMER_RANGE:
- start = TC_TIMER_START;
- end = TC_TIMER_END;
- break;
- default:
- return;
- }
-
- for (timer = start; timer <= end; ++timer)
- pd_timer_disable(port, timer);
-}
-
-bool pd_timer_is_disabled(int port, enum pd_task_timer timer)
-{
- uint32_t mask = 1 << timer;
-
- return PD_CHK_DISABLED(port, mask);
-}
-
-bool pd_timer_is_expired(int port, enum pd_task_timer timer)
-{
- if (pd_timer_is_active(port, timer)) {
- if (get_time().val >= timer_expires[port][timer]) {
- pd_timer_inactive(port, timer);
- return true;
- }
- return false;
- }
- return pd_timer_is_inactive(port, timer);
-}
-
-void pd_timer_manage_expired(int port)
-{
- int timer;
-
- if (timer_active[port])
- for (timer = 0; timer < MAX_PD_TIMERS; ++timer)
- if (pd_timer_is_active(port, timer) &&
- pd_timer_is_expired(port, timer))
- pd_timer_inactive(port, timer);
-}
-
-int pd_timer_next_expiration(int port)
-{
- int timer;
- int ret_value = MAX_EXPIRE;
- uint64_t now = get_time().val;
-
- for (timer = 0; timer < MAX_PD_TIMERS; ++timer) {
- /* Only use active timers for the next expired value */
- if (pd_timer_is_active(port, timer)) {
- int delta;
- uint64_t t_value = timer_expires[port][timer];
-
- if (t_value <= now) {
- ret_value = EXPIRE_NOW;
- break;
- }
-
- delta = t_value - now;
- if (ret_value > delta)
- ret_value = delta;
- }
- }
-
- if (ret_value == MAX_EXPIRE)
- ret_value = NO_TIMEOUT;
-
- return ret_value;
-}
-
-#ifdef CONFIG_CMD_PD_TIMER
-void pd_timer_dump(int port)
-{
- int timer;
- uint64_t now = get_time().val;
-
- ccprints("Timers(%d): cur=%d max=%d",
- port, count[port], max_count[port]);
-
- for (timer = 0; timer < MAX_PD_TIMERS; ++timer) {
- if (pd_timer_is_disabled(port, timer)) {
- continue;
- } else if (pd_timer_is_active(port, timer)) {
- uint32_t delta = 0;
-
- if (now < timer_expires[port][timer])
- delta = timer_expires[port][timer] - now;
-
- ccprints("[%2d] Active: %s (%d%s)",
- timer, pd_timer_names[timer], (uint32_t)delta,
- tc_event_loop_is_paused(port)
- ? "-PAUSED"
- : "");
- } else {
- ccprints("[%2d] Inactive: %s",
- timer, pd_timer_names[timer]);
- }
- }
-}
-#endif /* CONFIG_CMD_PD_TIMER */
diff --git a/common/usbc/usb_pe_ctvpd_sm.c b/common/usbc/usb_pe_ctvpd_sm.c
deleted file mode 100644
index 346a57a461..0000000000
--- a/common/usbc/usb_pe_ctvpd_sm.c
+++ /dev/null
@@ -1,237 +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 "console.h"
-#include "task.h"
-#include "util.h"
-#include "usb_pd.h"
-#include "usb_pd_tcpm.h"
-#include "usb_pe_sm.h"
-#include "usb_prl_sm.h"
-#include "usb_pd_tcpm.h"
-#include "usb_tc_sm.h"
-#include "usb_emsg.h"
-#include "usb_sm.h"
-
-/* USB Policy Engine Charge-Through VCONN Powered Device module */
-
-/* Policy Engine Flags */
-#define PE_FLAGS_MSG_RECEIVED BIT(0)
-
-/**
- * This is the PE Port object that contains information needed to
- * implement a VCONN and Charge-Through VCONN Powered Device.
- */
-static struct policy_engine {
- /* state machine context */
- struct sm_ctx ctx;
- /* port flags, see PE_FLAGS_* */
- uint32_t flags;
-} pe[CONFIG_USB_PD_PORT_MAX_COUNT];
-
-/* List of all policy-engine-level states */
-enum usb_pe_state {
- PE_REQUEST,
-};
-
-/* Forward declare the full list of states. This is indexed by usb_pe_states */
-static const struct usb_state pe_states[];
-
-static void set_state_pe(const int port, enum usb_pe_state new_state)
-{
- set_state(port, &pe[port].ctx, &pe_states[new_state]);
-}
-
-static void pe_init(int port)
-{
- const struct sm_ctx cleared = {};
-
- pe[port].flags = 0;
- pe[port].ctx = cleared;
- set_state_pe(port, PE_REQUEST);
-}
-
-bool pe_in_frs_mode(int port)
-{
- /* Will never be in FRS mode */
- return false;
-}
-
-bool pe_in_local_ams(int port)
-{
- /* We never start a local AMS */
- return false;
-}
-
-void pe_run(int port, int evt, int en)
-{
- static enum sm_local_state local_state[CONFIG_USB_PD_PORT_MAX_COUNT];
-
- switch (local_state[port]) {
- case SM_PAUSED:
- if (!en)
- break;
- /* fall through */
- case SM_INIT:
- pe_init(port);
- local_state[port] = SM_RUN;
- /* fall through */
- case SM_RUN:
- if (en)
- run_state(port, &pe[port].ctx);
- else
- local_state[port] = SM_PAUSED;
- break;
- }
-}
-
-void pe_message_received(int port)
-{
- pe[port].flags |= PE_FLAGS_MSG_RECEIVED;
- task_wake(PD_PORT_TO_TASK_ID(port));
-}
-
-/**
- * NOTE:
- * The Charge-Through Vconn Powered Device's Policy Engine is very
- * simple and no implementation is needed for the following functions
- * that might be called by the Protocol Layer.
- */
-
-void pe_hard_reset_sent(int port)
-{
- /* No implementation needed by this policy engine */
-}
-
-void pe_got_hard_reset(int port)
-{
- /* No implementation needed by this policy engine */
-}
-
-void pe_report_error(int port, enum pe_error e, enum tcpci_msg_type type)
-{
- /* No implementation needed by this policy engine */
-}
-
-void pe_report_discard(int port)
-{
- /* No implementation needed by this policy engine */
-}
-
-void pe_got_soft_reset(int port)
-{
- /* No implementation needed by this policy engine */
-}
-
-void pe_message_sent(int port)
-{
- /* No implementation needed by this policy engine */
-}
-
-static void pe_request_run(const int port)
-{
- uint32_t *payload = (uint32_t *)tx_emsg[port].buf;
- uint32_t header = rx_emsg[port].header;
- uint32_t vdo = *(uint32_t *)rx_emsg[port].buf;
-
- if (pe[port].flags & PE_FLAGS_MSG_RECEIVED) {
- pe[port].flags &= ~PE_FLAGS_MSG_RECEIVED;
-
- /*
- * Only support Structured VDM Discovery
- * Identity message
- */
-
- if (PD_HEADER_TYPE(header) != PD_DATA_VENDOR_DEF)
- return;
-
- if (PD_HEADER_CNT(header) == 0)
- return;
-
- if (!PD_VDO_SVDM(vdo))
- return;
-
- if (PD_VDO_CMD(vdo) != CMD_DISCOVER_IDENT)
- return;
-
-#ifdef CONFIG_USB_CTVPD
- /*
- * We have a valid DISCOVER IDENTITY message.
- * Attempt to reset support timer
- */
- tc_reset_support_timer(port);
-#endif
- /* Prepare to send ACK */
-
- /* VDM Header */
- payload[0] = VDO(
- USB_VID_GOOGLE,
- 1, /* Structured VDM */
- VDO_SVDM_VERS(1) |
- VDO_CMDT(CMDT_RSP_ACK) |
- CMD_DISCOVER_IDENT);
-
- /* ID Header VDO */
- payload[1] = VDO_IDH(
- 0, /* Not a USB Host */
- 1, /* Capable of being enumerated as USB Device */
- IDH_PTYPE_VPD,
- 0, /* Modal Operation Not Supported */
- USB_VID_GOOGLE);
-
- /* Cert State VDO */
- payload[2] = 0;
-
- /* Product VDO */
- payload[3] = VDO_PRODUCT(
- CONFIG_USB_PID,
- USB_BCD_DEVICE);
-
- /* VPD VDO */
- payload[4] = VDO_VPD(
- VPD_HW_VERSION,
- VPD_FW_VERSION,
- VPD_MAX_VBUS_20V,
- IS_ENABLED(CONFIG_USB_CTVPD) ? VPD_CT_CURRENT
- : 0,
- IS_ENABLED(CONFIG_USB_CTVPD) ? VPD_VBUS_IMP(
- VPD_VBUS_IMPEDANCE)
- : 0,
- IS_ENABLED(CONFIG_USB_CTVPD) ? VPD_GND_IMP(
- VPD_GND_IMPEDANCE)
- : 0,
- IS_ENABLED(CONFIG_USB_CTVPD) ? VPD_CTS_SUPPORTED
- : VPD_CTS_NOT_SUPPORTED);
-
- /* 20 bytes, 5 data objects */
- tx_emsg[port].len = 20;
-
- /* Set to highest revision supported by both ports. */
- prl_set_rev(port, TCPCI_MSG_SOP_PRIME,
- (PD_HEADER_REV(header) > PD_REV30) ?
- PD_REV30 : PD_HEADER_REV(header));
- /* Send the ACK */
- prl_send_data_msg(port, TCPCI_MSG_SOP_PRIME,
- PD_DATA_VENDOR_DEF);
- }
-}
-
-/* All policy-engine-level states. */
-static const struct usb_state pe_states[] = {
- [PE_REQUEST] = {
- .run = pe_request_run,
- },
-};
-
-#ifdef TEST_BUILD
-const struct test_sm_data test_pe_sm_data[] = {
- {
- .base = pe_states,
- .size = ARRAY_SIZE(pe_states),
- },
-};
-const int test_pe_sm_data_size = ARRAY_SIZE(test_pe_sm_data);
-#endif
diff --git a/common/usbc/usb_pe_drp_sm.c b/common/usbc/usb_pe_drp_sm.c
deleted file mode 100644
index 096f689b0a..0000000000
--- a/common/usbc/usb_pe_drp_sm.c
+++ /dev/null
@@ -1,7486 +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 "atomic.h"
-#include "battery.h"
-#include "battery_smart.h"
-#include "charge_manager.h"
-#include "charge_state.h"
-#include "common.h"
-#include "console.h"
-#include "dps.h"
-#include "driver/tcpm/tcpm.h"
-#include "ec_commands.h"
-#include "hooks.h"
-#include "host_command.h"
-#include "stdbool.h"
-#include "system.h"
-#include "task.h"
-#include "tcpm/tcpm.h"
-#include "util.h"
-#include "usb_common.h"
-#include "usb_dp_alt_mode.h"
-#include "usb_mode.h"
-#include "usb_pd_dpm.h"
-#include "usb_pd_policy.h"
-#include "usb_pd.h"
-#include "usb_pd_tcpm.h"
-#include "usb_pd_timer.h"
-#include "usb_pe_sm.h"
-#include "usb_tbt_alt_mode.h"
-#include "usb_prl_sm.h"
-#include "usb_tc_sm.h"
-#include "usb_emsg.h"
-#include "usb_sm.h"
-#include "usbc_ppc.h"
-
-/*
- * USB Policy Engine Sink / Source module
- *
- * Based on Revision 3.0, Version 1.2 of
- * the USB Power Delivery Specification.
- */
-
-#ifdef CONFIG_COMMON_RUNTIME
-#define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args)
-#define CPRINTS(format, args...) cprints(CC_USBPD, format, ## args)
-#else
-#define CPRINTF(format, args...)
-#define CPRINTS(format, args...)
-#endif
-
-#define CPRINTF_LX(x, format, args...) \
- do { \
- if (pe_debug_level >= x) \
- CPRINTF(format, ## args); \
- } while (0)
-#define CPRINTF_L1(format, args...) CPRINTF_LX(1, format, ## args)
-#define CPRINTF_L2(format, args...) CPRINTF_LX(2, format, ## args)
-#define CPRINTF_L3(format, args...) CPRINTF_LX(3, format, ## args)
-
-#define CPRINTS_LX(x, format, args...) \
- do { \
- if (pe_debug_level >= x) \
- CPRINTS(format, ## args); \
- } while (0)
-#define CPRINTS_L1(format, args...) CPRINTS_LX(1, format, ## args)
-#define CPRINTS_L2(format, args...) CPRINTS_LX(2, format, ## args)
-#define CPRINTS_L3(format, args...) CPRINTS_LX(3, format, ## args)
-
-#define PE_SET_FLAG(port, flag) atomic_or(&pe[port].flags, (flag))
-#define PE_CLR_FLAG(port, flag) atomic_clear_bits(&pe[port].flags, (flag))
-#define PE_CHK_FLAG(port, flag) (pe[port].flags & (flag))
-
-/*
- * These macros SET, CLEAR, and CHECK, a DPM (Device Policy Manager)
- * Request. The Requests are listed in usb_pe_sm.h.
- */
-#define PE_SET_DPM_REQUEST(port, req) atomic_or(&pe[port].dpm_request, (req))
-#define PE_CLR_DPM_REQUEST(port, req) \
- atomic_clear_bits(&pe[port].dpm_request, (req))
-#define PE_CHK_DPM_REQUEST(port, req) (pe[port].dpm_request & (req))
-
-/*
- * Policy Engine Layer Flags
- * These are reproduced in test/usb_pe.h. If they change here, they must change
- * there.
- */
-
-/* At least one successful PD communication packet received from port partner */
-#define PE_FLAGS_PD_CONNECTION BIT(0)
-/* Accept message received from port partner */
-#define PE_FLAGS_ACCEPT BIT(1)
-/* Power Supply Ready message received from port partner */
-#define PE_FLAGS_PS_READY BIT(2)
-/* Protocol Error was determined based on error recovery current state */
-#define PE_FLAGS_PROTOCOL_ERROR BIT(3)
-/* Set if we are in Modal Operation */
-#define PE_FLAGS_MODAL_OPERATION BIT(4)
-/* A message we requested to be sent has been transmitted */
-#define PE_FLAGS_TX_COMPLETE BIT(5)
-/* A message sent by a port partner has been received */
-#define PE_FLAGS_MSG_RECEIVED BIT(6)
-/* A hard reset has been requested but has not been sent, not currently used */
-#define PE_FLAGS_HARD_RESET_PENDING BIT(7)
-/* Port partner sent a Wait message. Wait before we resend our message */
-#define PE_FLAGS_WAIT BIT(8)
-/* An explicit contract is in place with our port partner */
-#define PE_FLAGS_EXPLICIT_CONTRACT BIT(9)
-/* Waiting for Sink Capabailities timed out. Used for retry error handling */
-#define PE_FLAGS_SNK_WAIT_CAP_TIMEOUT BIT(10)
-/* Power Supply voltage/current transition timed out */
-#define PE_FLAGS_PS_TRANSITION_TIMEOUT BIT(11)
-/* Flag to note current Atomic Message Sequence is interruptible */
-#define PE_FLAGS_INTERRUPTIBLE_AMS BIT(12)
-/* Flag to note Power Supply reset has completed */
-#define PE_FLAGS_PS_RESET_COMPLETE BIT(13)
-/* VCONN swap operation has completed */
-#define PE_FLAGS_VCONN_SWAP_COMPLETE BIT(14)
-/* Flag to note no more setup VDMs (discovery, etc.) should be sent */
-#define PE_FLAGS_VDM_SETUP_DONE BIT(15)
-/* Flag to note PR Swap just completed for Startup entry */
-#define PE_FLAGS_PR_SWAP_COMPLETE BIT(16)
-/* Flag to note Port Discovery port partner replied with BUSY */
-#define PE_FLAGS_VDM_REQUEST_BUSY BIT(17)
-/* Flag to note Port Discovery port partner replied with NAK */
-#define PE_FLAGS_VDM_REQUEST_NAKED BIT(18)
-/* Flag to note FRS/PRS context in shared state machine path */
-#define PE_FLAGS_FAST_ROLE_SWAP_PATH BIT(19)
-/* Flag to note if FRS listening is enabled */
-#define PE_FLAGS_FAST_ROLE_SWAP_ENABLED BIT(20)
-/* Flag to note TCPC passed on FRS signal from port partner */
-#define PE_FLAGS_FAST_ROLE_SWAP_SIGNALED BIT(21)
-/* TODO: POLICY decision: Triggers a DR SWAP attempt from UFP to DFP */
-#define PE_FLAGS_DR_SWAP_TO_DFP BIT(22)
-/*
- * TODO: POLICY decision
- * Flag to trigger a message resend after receiving a WAIT from port partner
- */
-#define PE_FLAGS_WAITING_PR_SWAP BIT(23)
-/* FLAG is set when an AMS is initiated locally. ie. AP requested a PR_SWAP */
-#define PE_FLAGS_LOCALLY_INITIATED_AMS BIT(24)
-/* Flag to note the first message sent in PE_SRC_READY and PE_SNK_READY */
-#define PE_FLAGS_FIRST_MSG BIT(25)
-/* Flag to continue a VDM request if it was interrupted */
-#define PE_FLAGS_VDM_REQUEST_CONTINUE BIT(26)
-/* TODO: POLICY decision: Triggers a Vconn SWAP attempt to on */
-#define PE_FLAGS_VCONN_SWAP_TO_ON BIT(27)
-/* FLAG to track that VDM request to port partner timed out */
-#define PE_FLAGS_VDM_REQUEST_TIMEOUT BIT(28)
-/* FLAG to note message was discarded due to incoming message */
-#define PE_FLAGS_MSG_DISCARDED BIT(29)
-/* FLAG to note that hard reset can't be performed due to battery low */
-#define PE_FLAGS_SNK_WAITING_BATT BIT(30)
-
-/* Message flags which should not persist on returning to ready state */
-#define PE_FLAGS_READY_CLR (PE_FLAGS_LOCALLY_INITIATED_AMS \
- | PE_FLAGS_MSG_DISCARDED \
- | PE_FLAGS_VDM_REQUEST_TIMEOUT \
- | PE_FLAGS_INTERRUPTIBLE_AMS)
-
-/*
- * Combination to check whether a reply to a message was received. Our message
- * should have sent (i.e. not been discarded) and a partner message is ready to
- * process.
- *
- * When chunking is disabled (ex. for PD 2.0), these flags will set
- * on the same run cycle. With chunking, received message will take an
- * additional cycle to be flagged.
- */
-#define PE_CHK_REPLY(port) (PE_CHK_FLAG(port, PE_FLAGS_MSG_RECEIVED) && \
- !PE_CHK_FLAG(port, PE_FLAGS_MSG_DISCARDED))
-
-/* 6.7.3 Hard Reset Counter */
-#define N_HARD_RESET_COUNT 2
-
-/* 6.7.4 Capabilities Counter */
-#define N_CAPS_COUNT 25
-
-/* 6.7.5 Discover Identity Counter */
-/*
- * NOTE: The Protocol Layer tries to send a message 3 time before giving up,
- * so a Discover Identity SOP' message will be sent 3*6 = 18 times (slightly
- * less than spec maximum of 20). This counter applies only to cable plug
- * discovery.
- */
-#define N_DISCOVER_IDENTITY_COUNT 6
-
-/*
- * It is permitted to send SOP' Discover Identity messages before a PD contract
- * is in place. However, this is only beneficial if the cable powers up quickly
- * solely from VCONN. Limit the number of retries without a contract to
- * ensure we attempt some cable discovery after a contract is in place.
- */
-#define N_DISCOVER_IDENTITY_PRECONTRACT_LIMIT 2
-
-/*
- * Once this limit of SOP' Discover Identity messages has been set, downgrade
- * to PD 2.0 in case the cable is non-compliant about GoodCRC-ing higher
- * revisions. This limit should be higher than the precontract limit.
- */
-#define N_DISCOVER_IDENTITY_PD3_0_LIMIT 4
-
-/*
- * tDiscoverIdentity is only defined while an explicit contract is in place, so
- * extend the interval between retries pre-contract.
- */
-#define PE_T_DISCOVER_IDENTITY_NO_CONTRACT (200*MSEC)
-
-/*
- * Only VCONN source can communicate with the cable plug. Hence, try VCONN swap
- * 3 times before giving up.
- *
- * Note: This is not a part of power delivery specification
- */
-#define N_VCONN_SWAP_COUNT 3
-
-/*
- * Counter to track how many times to attempt SRC to SNK PR swaps before giving
- * up.
- *
- * Note: This is not a part of power delivery specification
- */
-#define N_SNK_SRC_PR_SWAP_COUNT 5
-
-/*
- * ChromeOS policy:
- * For PD2.0, We must be DFP before sending Discover Identity message
- * to the port partner. Attempt to DR SWAP from UFP to DFP
- * N_DR_SWAP_ATTEMPT_COUNT times before giving up on sending a
- * Discover Identity message.
- */
-#define N_DR_SWAP_ATTEMPT_COUNT 5
-
-#define TIMER_DISABLED 0xffffffffffffffff /* Unreachable time in future */
-
-/*
- * The time that we allow the port partner to send any messages after an
- * explicit contract is established. 200ms was chosen somewhat arbitrarily as
- * it should be long enough for sources to decide to send a message if they were
- * going to, but not so long that a "low power charger connected" notification
- * would be shown in the chrome OS UI. Setting t0o large a delay can cause
- * problems if the PD discovery time exceeds 1s (tAMETimeout)
- */
-#define SRC_SNK_READY_HOLD_OFF_US (200 * MSEC)
-
-/*
- * Function pointer to a Structured Vendor Defined Message (SVDM) response
- * function defined in the board's usb_pd_policy.c file.
- */
-typedef int (*svdm_rsp_func)(int port, uint32_t *payload);
-
-/* List of all Policy Engine level states */
-enum usb_pe_state {
- /* Super States */
- PE_PRS_FRS_SHARED,
- PE_VDM_SEND_REQUEST,
-
- /* Normal States */
- PE_SRC_STARTUP,
- PE_SRC_DISCOVERY,
- PE_SRC_SEND_CAPABILITIES,
- PE_SRC_NEGOTIATE_CAPABILITY,
- PE_SRC_TRANSITION_SUPPLY,
- PE_SRC_READY,
- PE_SRC_DISABLED,
- PE_SRC_CAPABILITY_RESPONSE,
- PE_SRC_HARD_RESET,
- PE_SRC_HARD_RESET_RECEIVED,
- PE_SRC_TRANSITION_TO_DEFAULT,
- PE_SNK_STARTUP,
- PE_SNK_DISCOVERY,
- PE_SNK_WAIT_FOR_CAPABILITIES,
- PE_SNK_EVALUATE_CAPABILITY,
- PE_SNK_SELECT_CAPABILITY,
- PE_SNK_READY,
- PE_SNK_HARD_RESET,
- PE_SNK_TRANSITION_TO_DEFAULT,
- PE_SNK_GIVE_SINK_CAP,
- PE_SNK_GET_SOURCE_CAP,
- PE_SNK_TRANSITION_SINK,
- PE_SEND_SOFT_RESET,
- PE_SOFT_RESET,
- PE_SEND_NOT_SUPPORTED,
- PE_SRC_PING,
- PE_DRS_EVALUATE_SWAP,
- PE_DRS_CHANGE,
- PE_DRS_SEND_SWAP,
- PE_PRS_SRC_SNK_EVALUATE_SWAP,
- PE_PRS_SRC_SNK_TRANSITION_TO_OFF,
- PE_PRS_SRC_SNK_ASSERT_RD,
- PE_PRS_SRC_SNK_WAIT_SOURCE_ON,
- PE_PRS_SRC_SNK_SEND_SWAP,
- PE_PRS_SNK_SRC_EVALUATE_SWAP,
- PE_PRS_SNK_SRC_TRANSITION_TO_OFF,
- PE_PRS_SNK_SRC_ASSERT_RP,
- PE_PRS_SNK_SRC_SOURCE_ON,
- PE_PRS_SNK_SRC_SEND_SWAP,
- PE_VCS_EVALUATE_SWAP,
- PE_VCS_SEND_SWAP,
- PE_VCS_WAIT_FOR_VCONN_SWAP,
- PE_VCS_TURN_ON_VCONN_SWAP,
- PE_VCS_TURN_OFF_VCONN_SWAP,
- PE_VCS_SEND_PS_RDY_SWAP,
- PE_VCS_CBL_SEND_SOFT_RESET,
- PE_VDM_IDENTITY_REQUEST_CBL,
- PE_INIT_PORT_VDM_IDENTITY_REQUEST,
- PE_INIT_VDM_SVIDS_REQUEST,
- PE_INIT_VDM_MODES_REQUEST,
- PE_VDM_REQUEST_DPM,
- PE_VDM_RESPONSE,
- PE_HANDLE_CUSTOM_VDM_REQUEST,
- PE_WAIT_FOR_ERROR_RECOVERY,
- PE_BIST_TX,
- PE_DEU_SEND_ENTER_USB,
- PE_DR_GET_SINK_CAP,
- PE_DR_SNK_GIVE_SOURCE_CAP,
- PE_DR_SRC_GET_SOURCE_CAP,
-
- /* PD3.0 only states below here*/
- PE_FRS_SNK_SRC_START_AMS,
- PE_GIVE_BATTERY_CAP,
- PE_GIVE_BATTERY_STATUS,
- PE_SEND_ALERT,
- PE_SRC_CHUNK_RECEIVED,
- PE_SNK_CHUNK_RECEIVED,
- PE_VCS_FORCE_VCONN,
-};
-
-/*
- * The result of a previously sent DPM request; used by PE_VDM_SEND_REQUEST to
- * indicate to child states when they need to handle a response.
- */
-enum vdm_response_result {
- /* The parent state is still waiting for a response. */
- VDM_RESULT_WAITING,
- /*
- * The parent state parsed a message, but there is nothing for the child
- * to handle, e.g. BUSY.
- */
- VDM_RESULT_NO_ACTION,
- /* The parent state processed an ACK response. */
- VDM_RESULT_ACK,
- /*
- * The parent state processed a NAK-like response (NAK, Not Supported,
- * or response timeout.
- */
- VDM_RESULT_NAK,
-};
-
-/* Forward declare the full list of states. This is indexed by usb_pe_state */
-static const struct usb_state pe_states[];
-
-/*
- * We will use DEBUG LABELS if we will be able to print (COMMON RUNTIME)
- * and either CONFIG_USB_PD_DEBUG_LEVEL is not defined (no override) or
- * we are overriding and the level is not DISABLED.
- *
- * If we can't print or the CONFIG_USB_PD_DEBUG_LEVEL is defined to be 0
- * then the DEBUG LABELS will be removed from the build.
- */
-#if defined(CONFIG_COMMON_RUNTIME) && \
- (!defined(CONFIG_USB_PD_DEBUG_LEVEL) || \
- (CONFIG_USB_PD_DEBUG_LEVEL > 0))
-#define USB_PD_DEBUG_LABELS
-#endif
-
-/* List of human readable state names for console debugging */
-__maybe_unused static __const_data const char * const pe_state_names[] = {
- /* Super States */
-#ifdef CONFIG_USB_PD_REV30
- [PE_PRS_FRS_SHARED] = "SS:PE_PRS_FRS_SHARED",
-#endif
- [PE_VDM_SEND_REQUEST] = "SS:PE_VDM_Send_Request",
-
- /* Normal States */
- [PE_SRC_STARTUP] = "PE_SRC_Startup",
- [PE_SRC_DISCOVERY] = "PE_SRC_Discovery",
- [PE_SRC_SEND_CAPABILITIES] = "PE_SRC_Send_Capabilities",
- [PE_SRC_NEGOTIATE_CAPABILITY] = "PE_SRC_Negotiate_Capability",
- [PE_SRC_TRANSITION_SUPPLY] = "PE_SRC_Transition_Supply",
- [PE_SRC_READY] = "PE_SRC_Ready",
- [PE_SRC_DISABLED] = "PE_SRC_Disabled",
- [PE_SRC_CAPABILITY_RESPONSE] = "PE_SRC_Capability_Response",
- [PE_SRC_HARD_RESET] = "PE_SRC_Hard_Reset",
- [PE_SRC_HARD_RESET_RECEIVED] = "PE_SRC_Hard_Reset_Received",
- [PE_SRC_TRANSITION_TO_DEFAULT] = "PE_SRC_Transition_to_default",
- [PE_SNK_STARTUP] = "PE_SNK_Startup",
- [PE_SNK_DISCOVERY] = "PE_SNK_Discovery",
- [PE_SNK_WAIT_FOR_CAPABILITIES] = "PE_SNK_Wait_for_Capabilities",
- [PE_SNK_EVALUATE_CAPABILITY] = "PE_SNK_Evaluate_Capability",
- [PE_SNK_SELECT_CAPABILITY] = "PE_SNK_Select_Capability",
- [PE_SNK_READY] = "PE_SNK_Ready",
- [PE_SNK_HARD_RESET] = "PE_SNK_Hard_Reset",
- [PE_SNK_TRANSITION_TO_DEFAULT] = "PE_SNK_Transition_to_default",
- [PE_SNK_GIVE_SINK_CAP] = "PE_SNK_Give_Sink_Cap",
- [PE_SNK_GET_SOURCE_CAP] = "PE_SNK_Get_Source_Cap",
- [PE_SNK_TRANSITION_SINK] = "PE_SNK_Transition_Sink",
- [PE_SEND_SOFT_RESET] = "PE_Send_Soft_Reset",
- [PE_SOFT_RESET] = "PE_Soft_Reset",
- [PE_SEND_NOT_SUPPORTED] = "PE_Send_Not_Supported",
- [PE_SRC_PING] = "PE_SRC_Ping",
- [PE_DRS_EVALUATE_SWAP] = "PE_DRS_Evaluate_Swap",
- [PE_DRS_CHANGE] = "PE_DRS_Change",
- [PE_DRS_SEND_SWAP] = "PE_DRS_Send_Swap",
- [PE_PRS_SRC_SNK_EVALUATE_SWAP] = "PE_PRS_SRC_SNK_Evaluate_Swap",
- [PE_PRS_SRC_SNK_TRANSITION_TO_OFF] = "PE_PRS_SRC_SNK_Transition_To_Off",
- [PE_PRS_SRC_SNK_ASSERT_RD] = "PE_PRS_SRC_SNK_Assert_Rd",
- [PE_PRS_SRC_SNK_WAIT_SOURCE_ON] = "PE_PRS_SRC_SNK_Wait_Source_On",
- [PE_PRS_SRC_SNK_SEND_SWAP] = "PE_PRS_SRC_SNK_Send_Swap",
- [PE_PRS_SNK_SRC_EVALUATE_SWAP] = "PE_PRS_SNK_SRC_Evaluate_Swap",
- [PE_PRS_SNK_SRC_TRANSITION_TO_OFF] = "PE_PRS_SNK_SRC_Transition_To_Off",
- [PE_PRS_SNK_SRC_ASSERT_RP] = "PE_PRS_SNK_SRC_Assert_Rp",
- [PE_PRS_SNK_SRC_SOURCE_ON] = "PE_PRS_SNK_SRC_Source_On",
- [PE_PRS_SNK_SRC_SEND_SWAP] = "PE_PRS_SNK_SRC_Send_Swap",
-#ifdef CONFIG_USBC_VCONN
- [PE_VCS_EVALUATE_SWAP] = "PE_VCS_Evaluate_Swap",
- [PE_VCS_SEND_SWAP] = "PE_VCS_Send_Swap",
- [PE_VCS_WAIT_FOR_VCONN_SWAP] = "PE_VCS_Wait_For_Vconn_Swap",
- [PE_VCS_TURN_ON_VCONN_SWAP] = "PE_VCS_Turn_On_Vconn_Swap",
- [PE_VCS_TURN_OFF_VCONN_SWAP] = "PE_VCS_Turn_Off_Vconn_Swap",
- [PE_VCS_SEND_PS_RDY_SWAP] = "PE_VCS_Send_Ps_Rdy_Swap",
- [PE_VCS_CBL_SEND_SOFT_RESET] = "PE_VCS_CBL_Send_Soft_Reset",
-#endif
- [PE_VDM_IDENTITY_REQUEST_CBL] = "PE_VDM_Identity_Request_Cbl",
- [PE_INIT_PORT_VDM_IDENTITY_REQUEST] =
- "PE_INIT_PORT_VDM_Identity_Request",
- [PE_INIT_VDM_SVIDS_REQUEST] = "PE_INIT_VDM_SVIDs_Request",
- [PE_INIT_VDM_MODES_REQUEST] = "PE_INIT_VDM_Modes_Request",
- [PE_VDM_REQUEST_DPM] = "PE_VDM_Request_DPM",
- [PE_VDM_RESPONSE] = "PE_VDM_Response",
- [PE_HANDLE_CUSTOM_VDM_REQUEST] = "PE_Handle_Custom_Vdm_Request",
- [PE_WAIT_FOR_ERROR_RECOVERY] = "PE_Wait_For_Error_Recovery",
- [PE_BIST_TX] = "PE_Bist_TX",
- [PE_DEU_SEND_ENTER_USB] = "PE_DEU_Send_Enter_USB",
- [PE_DR_GET_SINK_CAP] = "PE_DR_Get_Sink_Cap",
- [PE_DR_SNK_GIVE_SOURCE_CAP] = "PE_DR_SNK_Give_Source_Cap",
- [PE_DR_SRC_GET_SOURCE_CAP] = "PE_DR_SRC_Get_Source_Cap",
-
- /* PD3.0 only states below here*/
-#ifdef CONFIG_USB_PD_REV30
- [PE_FRS_SNK_SRC_START_AMS] = "PE_FRS_SNK_SRC_Start_Ams",
-#ifdef CONFIG_USB_PD_EXTENDED_MESSAGES
- [PE_GIVE_BATTERY_CAP] = "PE_Give_Battery_Cap",
- [PE_GIVE_BATTERY_STATUS] = "PE_Give_Battery_Status",
- [PE_SEND_ALERT] = "PE_Send_Alert",
-#else
- [PE_SRC_CHUNK_RECEIVED] = "PE_SRC_Chunk_Received",
- [PE_SNK_CHUNK_RECEIVED] = "PE_SNK_Chunk_Received",
-#endif
-#ifdef CONFIG_USBC_VCONN
- [PE_VCS_FORCE_VCONN] = "PE_VCS_Force_Vconn",
-#endif
-#endif /* CONFIG_USB_PD_REV30 */
-};
-
-#ifndef CONFIG_USBC_VCONN
-GEN_NOT_SUPPORTED(PE_VCS_EVALUATE_SWAP);
-#define PE_VCS_EVALUATE_SWAP PE_VCS_EVALUATE_SWAP_NOT_SUPPORTED
-GEN_NOT_SUPPORTED(PE_VCS_SEND_SWAP);
-#define PE_VCS_SEND_SWAP PE_VCS_SEND_SWAP_NOT_SUPPORTED
-GEN_NOT_SUPPORTED(PE_VCS_WAIT_FOR_VCONN_SWAP);
-#define PE_VCS_WAIT_FOR_VCONN_SWAP PE_VCS_WAIT_FOR_VCONN_SWAP_NOT_SUPPORTED
-GEN_NOT_SUPPORTED(PE_VCS_TURN_ON_VCONN_SWAP);
-#define PE_VCS_TURN_ON_VCONN_SWAP PE_VCS_TURN_ON_VCONN_SWAP_NOT_SUPPORTED
-GEN_NOT_SUPPORTED(PE_VCS_TURN_OFF_VCONN_SWAP);
-#define PE_VCS_TURN_OFF_VCONN_SWAP PE_VCS_TURN_OFF_VCONN_SWAP_NOT_SUPPORTED
-GEN_NOT_SUPPORTED(PE_VCS_SEND_PS_RDY_SWAP);
-#define PE_VCS_SEND_PS_RDY_SWAP PE_VCS_SEND_PS_RDY_SWAP_NOT_SUPPORTED
-#endif /* CONFIG_USBC_VCONN */
-
-#ifndef CONFIG_USB_PD_REV30
-GEN_NOT_SUPPORTED(PE_FRS_SNK_SRC_START_AMS);
-#define PE_FRS_SNK_SRC_START_AMS PE_FRS_SNK_SRC_START_AMS_NOT_SUPPORTED
-GEN_NOT_SUPPORTED(PE_PRS_FRS_SHARED);
-#define PE_PRS_FRS_SHARED PE_PRS_FRS_SHARED_NOT_SUPPORTED
-GEN_NOT_SUPPORTED(PE_SRC_CHUNK_RECEIVED);
-#define PE_SRC_CHUNK_RECEIVED PE_SRC_CHUNK_RECEIVED_NOT_SUPPORTED
-GEN_NOT_SUPPORTED(PE_SNK_CHUNK_RECEIVED);
-#define PE_SNK_CHUNK_RECEIVED PE_SNK_CHUNK_RECEIVED_NOT_SUPPORTED
-#endif /* CONFIG_USB_PD_REV30 */
-
-#if !defined(CONFIG_USBC_VCONN) || !defined(CONFIG_USB_PD_REV30)
-GEN_NOT_SUPPORTED(PE_VCS_FORCE_VCONN);
-#define PE_VCS_FORCE_VCONN PE_VCS_FORCE_VCONN_NOT_SUPPORTED
-#endif
-
-#ifndef CONFIG_USB_PD_EXTENDED_MESSAGES
-GEN_NOT_SUPPORTED(PE_GIVE_BATTERY_CAP);
-#define PE_GIVE_BATTERY_CAP PE_GIVE_BATTERY_CAP_NOT_SUPPORTED
-GEN_NOT_SUPPORTED(PE_GIVE_BATTERY_STATUS);
-#define PE_GIVE_BATTERY_STATUS PE_GIVE_BATTERY_STATUS_NOT_SUPPORTED
-GEN_NOT_SUPPORTED(PE_SEND_ALERT);
-#define PE_SEND_ALERT PE_SEND_ALERT_NOT_SUPPORTED
-#endif /* CONFIG_USB_PD_EXTENDED_MESSAGES */
-
-#ifdef CONFIG_USB_PD_EXTENDED_MESSAGES
-GEN_NOT_SUPPORTED(PE_SRC_CHUNK_RECEIVED);
-#define PE_SRC_CHUNK_RECEIVED PE_SRC_CHUNK_RECEIVED_NOT_SUPPORTED
-GEN_NOT_SUPPORTED(PE_SNK_CHUNK_RECEIVED);
-#define PE_SNK_CHUNK_RECEIVED PE_SNK_CHUNK_RECEIVED_NOT_SUPPORTED
-#endif /* CONFIG_USB_PD_EXTENDED_MESSAGES */
-
-static enum sm_local_state local_state[CONFIG_USB_PD_PORT_MAX_COUNT];
-
-/*
- * Common message send checking
- *
- * PE_MSG_SEND_PENDING: A message has been requested to be sent. It has
- * not been GoodCRCed or Discarded.
- * PE_MSG_SEND_COMPLETED: The message that was requested has been sent.
- * This will only be returned one time and any other
- * request for message send status will just return
- * PE_MSG_SENT. This message actually includes both
- * The COMPLETED and the SENT bit for easier checking.
- * NOTE: PE_MSG_SEND_COMPLETED will only be returned
- * a single time, directly after TX_COMPLETE.
- * PE_MSG_SENT: The message that was requested to be sent has
- * successfully been transferred to the partner.
- * PE_MSG_DISCARDED: The message that was requested to be sent was
- * discarded. The partner did not receive it.
- * NOTE: PE_MSG_DISCARDED will only be returned
- * one time and it is up to the caller to process
- * what ever is needed to handle the Discard.
- * PE_MSG_DPM_DISCARDED: The message that was requested to be sent was
- * discarded and an active DRP_REQUEST was active.
- * The DRP_REQUEST that was current will be moved
- * back to the drp_requests so it can be performed
- * later if needed.
- * NOTE: PE_MSG_DPM_DISCARDED will only be returned
- * one time and it is up to the caller to process
- * what ever is needed to handle the Discard.
- */
-enum pe_msg_check {
- PE_MSG_SEND_PENDING = BIT(0),
- PE_MSG_SENT = BIT(1),
- PE_MSG_DISCARDED = BIT(2),
-
- PE_MSG_SEND_COMPLETED = BIT(3) | PE_MSG_SENT,
- PE_MSG_DPM_DISCARDED = BIT(4) | PE_MSG_DISCARDED,
-};
-static void pe_sender_response_msg_entry(const int port);
-static enum pe_msg_check pe_sender_response_msg_run(const int port);
-static void pe_sender_response_msg_exit(const int port);
-
-/* Debug log level - higher number == more log */
-#ifdef CONFIG_USB_PD_DEBUG_LEVEL
-static const enum debug_level pe_debug_level = CONFIG_USB_PD_DEBUG_LEVEL;
-#else
-static enum debug_level pe_debug_level = DEBUG_LEVEL_1;
-#endif
-
-/*
- * Policy Engine State Machine Object
- */
-static struct policy_engine {
- /* state machine context */
- struct sm_ctx ctx;
- /* current port power role (SOURCE or SINK) */
- enum pd_power_role power_role;
- /* current port data role (DFP or UFP) */
- enum pd_data_role data_role;
- /* state machine flags */
- uint32_t flags;
- /* Device Policy Manager Request */
- uint32_t dpm_request;
- uint32_t dpm_curr_request;
- /* last requested voltage PDO index */
- int requested_idx;
-
- /*
- * Port events - PD_STATUS_EVENT_* values
- * Set from PD task but may be cleared by host command
- */
- uint32_t events;
-
- /* port address where soft resets are sent */
- enum tcpci_msg_type soft_reset_sop;
-
- /* Current limit / voltage based on the last request message */
- uint32_t curr_limit;
- uint32_t supply_voltage;
-
- /* PD_VDO_INVALID is used when there is an invalid VDO */
- int32_t ama_vdo;
- int32_t vpd_vdo;
- /* Alternate mode discovery results */
- struct pd_discovery discovery[DISCOVERY_TYPE_COUNT];
- /* Active alternate modes */
- struct partner_active_modes partner_amodes[AMODE_TYPE_COUNT];
-
- /* Partner type to send */
- enum tcpci_msg_type tx_type;
-
- /* VDM - used to send information to shared VDM Request state */
- uint32_t vdm_cnt;
- uint32_t vdm_data[VDO_HDR_SIZE + VDO_MAX_SIZE];
- uint8_t vdm_ack_min_data_objects;
-
- /* Counters */
-
- /*
- * This counter is used to retry the Hard Reset whenever there is no
- * response from the remote device.
- */
- uint32_t hard_reset_counter;
-
- /*
- * This counter is used to count the number of Source_Capabilities
- * Messages which have been sent by a Source at power up or after a
- * Hard Reset.
- */
- uint32_t caps_counter;
-
- /*
- * This counter maintains a count of Discover Identity Messages sent
- * to a cable. If no GoodCRC messages are received after
- * nDiscoverIdentityCount, the port shall not send any further
- * SOP'/SOP'' messages.
- */
- uint32_t discover_identity_counter;
- /*
- * For PD2.0, we need to be a DFP before sending a discovery identity
- * message to our port partner. This counter keeps track of how
- * many attempts to DR SWAP from UFP to DFP.
- */
- uint32_t dr_swap_attempt_counter;
-
- /*
- * This counter tracks how many PR Swap messages are sent when the
- * partner responds with a Wait message. Only used during SRC to SNK
- * PR swaps
- */
- uint8_t src_snk_pr_swap_counter;
-
- /*
- * This counter maintains a count of VCONN swap requests. If VCONN swap
- * isn't successful after N_VCONN_SWAP_COUNT, the port calls
- * dpm_vdm_naked().
- */
- uint8_t vconn_swap_counter;
-
- /* Last received source cap */
- uint32_t src_caps[PDO_MAX_OBJECTS];
- int src_cap_cnt; /* -1 on error retrieving source caps */
-
- /* Last received sink cap */
- uint32_t snk_caps[PDO_MAX_OBJECTS];
- int snk_cap_cnt;
-
- /* Attached ChromeOS device id, RW hash, and current RO / RW image */
- uint16_t dev_id;
- uint32_t dev_rw_hash[PD_RW_HASH_SIZE/4];
- enum ec_image current_image;
-} pe[CONFIG_USB_PD_PORT_MAX_COUNT];
-
-test_export_static enum usb_pe_state get_state_pe(const int port);
-test_export_static void set_state_pe(const int port,
- const enum usb_pe_state new_state);
-static void pe_set_dpm_curr_request(const int port, const int request);
-/*
- * The spec. revision is used to index into this array.
- * PD 1.0 (VDO 1.0) - return VDM_VER10
- * PD 2.0 (VDO 1.0) - return VDM_VER10
- * PD 3.0 (VDO 2.0) - return VDM_VER20
- */
-static const uint8_t vdo_ver[] = {
- [PD_REV10] = VDM_VER10,
- [PD_REV20] = VDM_VER10,
- [PD_REV30] = VDM_VER20,
-};
-
-int pd_get_rev(int port, enum tcpci_msg_type type)
-{
- return prl_get_rev(port, type);
-}
-
-int pd_get_vdo_ver(int port, enum tcpci_msg_type type)
-{
- enum pd_rev_type rev = prl_get_rev(port, type);
-
- if (rev < PD_REV30)
- return vdo_ver[rev];
- else
- return VDM_VER20;
-}
-
-static void pe_set_ready_state(int port)
-{
- if (pe[port].power_role == PD_ROLE_SOURCE)
- set_state_pe(port, PE_SRC_READY);
- else
- set_state_pe(port, PE_SNK_READY);
-}
-
-static inline void send_data_msg(int port, enum tcpci_msg_type type,
- enum pd_data_msg_type msg)
-{
- /* Clear any previous TX status before sending a new message */
- PE_CLR_FLAG(port, PE_FLAGS_TX_COMPLETE);
- prl_send_data_msg(port, type, msg);
-}
-
-static __maybe_unused inline void send_ext_data_msg(
- int port, enum tcpci_msg_type type, enum pd_ext_msg_type msg)
-{
- /* Clear any previous TX status before sending a new message */
- PE_CLR_FLAG(port, PE_FLAGS_TX_COMPLETE);
- prl_send_ext_data_msg(port, type, msg);
-}
-
-static inline void send_ctrl_msg(int port, enum tcpci_msg_type type,
- enum pd_ctrl_msg_type msg)
-{
- /* Clear any previous TX status before sending a new message */
- PE_CLR_FLAG(port, PE_FLAGS_TX_COMPLETE);
- prl_send_ctrl_msg(port, type, msg);
-}
-
-static void set_cable_rev(int port)
-{
- /*
- * If port partner runs PD 2.0, cable communication must
- * also be PD 2.0
- */
- if (prl_get_rev(port, TCPCI_MSG_SOP) == PD_REV20) {
- /*
- * If the cable supports PD 3.0, but the port partner supports PD 2.0,
- * redo the cable discover with PD 2.0
- */
- if (prl_get_rev(port, TCPCI_MSG_SOP_PRIME) == PD_REV30 &&
- pd_get_identity_discovery(port, TCPCI_MSG_SOP_PRIME) ==
- PD_DISC_COMPLETE) {
- pd_set_identity_discovery(port, TCPCI_MSG_SOP_PRIME,
- PD_DISC_NEEDED);
- }
- prl_set_rev(port, TCPCI_MSG_SOP_PRIME, PD_REV20);
- }
-}
-
-/* Compile-time insurance to ensure this code does not call into prl directly */
-#define prl_send_data_msg DO_NOT_USE
-#define prl_send_ext_data_msg DO_NOT_USE
-#define prl_send_ctrl_msg DO_NOT_USE
-
-static void pe_init(int port)
-{
- pe[port].flags = 0;
- pe[port].dpm_request = 0;
- pe[port].dpm_curr_request = 0;
- pd_timer_disable_range(port, PE_TIMER_RANGE);
- pe[port].data_role = pd_get_data_role(port);
- pe[port].tx_type = TCPCI_MSG_INVALID;
- pe[port].events = 0;
-
- tc_pd_connection(port, 0);
-
- if (pd_get_power_role(port) == PD_ROLE_SOURCE)
- set_state_pe(port, PE_SRC_STARTUP);
- else
- set_state_pe(port, PE_SNK_STARTUP);
-}
-
-int pe_is_running(int port)
-{
- return local_state[port] == SM_RUN;
-}
-
-bool pe_in_frs_mode(int port)
-{
- return PE_CHK_FLAG(port, PE_FLAGS_FAST_ROLE_SWAP_PATH);
-}
-
-bool pe_in_local_ams(int port)
-{
- return !!PE_CHK_FLAG(port, PE_FLAGS_LOCALLY_INITIATED_AMS);
-}
-
-void pe_set_debug_level(enum debug_level debug_level)
-{
-#ifndef CONFIG_USB_PD_DEBUG_LEVEL
- pe_debug_level = debug_level;
-#endif
-}
-
-void pe_run(int port, int evt, int en)
-{
- switch (local_state[port]) {
- case SM_PAUSED:
- if (!en)
- break;
- /* fall through */
- case SM_INIT:
- pe_init(port);
- local_state[port] = SM_RUN;
- /* fall through */
- case SM_RUN:
- if (!en) {
- local_state[port] = SM_PAUSED;
- /*
- * While we are paused, exit all states and wait until
- * initialized again.
- */
- set_state(port, &pe[port].ctx, NULL);
- break;
- }
-
- /*
- * 8.3.3.3.8 PE_SNK_Hard_Reset State
- * The Policy Engine Shall transition to the PE_SNK_Hard_Reset
- * state from any state when:
- * - Hard Reset request from Device Policy Manager
- *
- * USB PD specification clearly states that we should go to
- * PE_SNK_Hard_Reset from ANY state (including states in which
- * port is source) when DPM requests that. This can lead to
- * execute Hard Reset path for sink when actually our power
- * role is source. In our implementation we will choose Hard
- * Reset path depending on current power role.
- */
- if (PE_CHK_DPM_REQUEST(port, DPM_REQUEST_HARD_RESET_SEND)) {
- pe_set_dpm_curr_request(port, DPM_REQUEST_HARD_RESET_SEND);
- if (pd_get_power_role(port) == PD_ROLE_SOURCE)
- set_state_pe(port, PE_SRC_HARD_RESET);
- else
- set_state_pe(port, PE_SNK_HARD_RESET);
- }
-
- /*
- * Check for Fast Role Swap signal
- * This is not a typical pattern for adding state changes.
- * I added this here because FRS SIGNALED can happen at any
- * state once we are listening for the signal and we want to
- * make sure to handle it immediately.
- */
- if (IS_ENABLED(CONFIG_USB_PD_REV30) &&
- PE_CHK_FLAG(port, PE_FLAGS_FAST_ROLE_SWAP_SIGNALED)) {
- PE_CLR_FLAG(port, PE_FLAGS_FAST_ROLE_SWAP_SIGNALED);
- set_state_pe(port, PE_FRS_SNK_SRC_START_AMS);
- }
-
- /* Run state machine */
- run_state(port, &pe[port].ctx);
- break;
- }
-}
-
-int pe_is_explicit_contract(int port)
-{
- return PE_CHK_FLAG(port, PE_FLAGS_EXPLICIT_CONTRACT);
-}
-
-void pe_message_received(int port)
-{
- /* This should only be called from the PD task */
- assert(port == TASK_ID_TO_PD_PORT(task_get_current()));
-
- PE_SET_FLAG(port, PE_FLAGS_MSG_RECEIVED);
- task_wake(PD_PORT_TO_TASK_ID(port));
-}
-
-void pe_hard_reset_sent(int port)
-{
- /* This should only be called from the PD task */
- assert(port == TASK_ID_TO_PD_PORT(task_get_current()));
-
- PE_CLR_FLAG(port, PE_FLAGS_HARD_RESET_PENDING);
-}
-
-void pe_got_hard_reset(int port)
-{
- /* This should only be called from the PD task */
- assert(port == TASK_ID_TO_PD_PORT(task_get_current()));
-
- /*
- * Transition from any state to the PE_SRC_Hard_Reset_Received or
- * PE_SNK_Transition_to_default state when:
- * 1) Hard Reset Signaling is detected.
- */
- pe[port].power_role = pd_get_power_role(port);
-
- /* Exit BIST Test mode, in case the TCPC entered it. */
- tcpc_set_bist_test_mode(port, false);
-
- if (pe[port].power_role == PD_ROLE_SOURCE)
- set_state_pe(port, PE_SRC_HARD_RESET_RECEIVED);
- else
- set_state_pe(port, PE_SNK_TRANSITION_TO_DEFAULT);
-}
-
-#ifdef CONFIG_USB_PD_REV30
-/*
- * pd_got_frs_signal
- *
- * Called by the handler that detects the FRS signal in order to
- * switch PE states to complete the FRS that the hardware has
- * started.
- *
- * If the PE is not running, generate an error recovery to turn off
- * Vbus and get the port back into a known state.
- */
-void pd_got_frs_signal(int port)
-{
- if (pe_is_running(port))
- PE_SET_FLAG(port, PE_FLAGS_FAST_ROLE_SWAP_SIGNALED);
- else
- pd_set_error_recovery(port);
-
- task_wake(PD_PORT_TO_TASK_ID(port));
-}
-#endif /* CONFIG_USB_PD_REV30 */
-
-/*
- * PE_Set_FRS_Enable
- *
- * This function should be called every time an explicit contract
- * is disabled, to disable FRS.
- *
- * Enabling an explicit contract is not enough to enable FRS, it
- * also requires a Sink Capability power requirement from a Source
- * that supports FRS so we can determine if this is something we
- * can handle.
- */
-static void pe_set_frs_enable(int port, int enable)
-{
- int current = PE_CHK_FLAG(port, PE_FLAGS_FAST_ROLE_SWAP_ENABLED);
-
- /* This should only be called from the PD task */
- if (!IS_ENABLED(TEST_BUILD))
- assert(port == TASK_ID_TO_PD_PORT(task_get_current()));
-
- if (!IS_ENABLED(CONFIG_USB_PD_FRS) || !IS_ENABLED(CONFIG_USB_PD_REV30))
- return;
-
- /* Request an FRS change, only if the state has changed */
- if (!!current == !!enable)
- return;
-
- pd_set_frs_enable(port, enable);
- if (enable) {
- int curr_limit = *pd_get_snk_caps(port)
- & PDO_FIXED_FRS_CURR_MASK;
-
- typec_select_src_current_limit_rp(port,
- curr_limit ==
- PDO_FIXED_FRS_CURR_3A0_AT_5V ?
- TYPEC_RP_3A0 : TYPEC_RP_1A5);
- PE_SET_FLAG(port, PE_FLAGS_FAST_ROLE_SWAP_ENABLED);
- } else {
- PE_CLR_FLAG(port, PE_FLAGS_FAST_ROLE_SWAP_ENABLED);
- }
-}
-
-void pe_set_explicit_contract(int port)
-{
- PE_SET_FLAG(port, PE_FLAGS_EXPLICIT_CONTRACT);
-
- /* Set Rp for collision avoidance */
- if (IS_ENABLED(CONFIG_USB_PD_REV30))
- typec_update_cc(port);
-}
-
-void pe_invalidate_explicit_contract(int port)
-{
- pe_set_frs_enable(port, 0);
-
- PE_CLR_FLAG(port, PE_FLAGS_EXPLICIT_CONTRACT);
-
- /* Set Rp for current limit if still attached */
- if (IS_ENABLED(CONFIG_USB_PD_REV30) && pd_is_connected(port))
- typec_update_cc(port);
-}
-
-void pd_notify_event(int port, uint32_t event_mask)
-{
- atomic_or(&pe[port].events, event_mask);
-
- /* Notify the host that new events are available to read */
- pd_send_host_event(PD_EVENT_TYPEC);
-}
-
-void pd_clear_events(int port, uint32_t clear_mask)
-{
- atomic_clear_bits(&pe[port].events, clear_mask);
-}
-
-uint32_t pd_get_events(int port)
-{
- return pe[port].events;
-}
-
-void pe_set_snk_caps(int port, int cnt, uint32_t *snk_caps)
-{
- pe[port].snk_cap_cnt = cnt;
-
- memcpy(pe[port].snk_caps, snk_caps, sizeof(uint32_t) * cnt);
-}
-
-const uint32_t * const pd_get_snk_caps(int port)
-{
- return pe[port].snk_caps;
-}
-
-uint8_t pd_get_snk_cap_cnt(int port)
-{
- return pe[port].snk_cap_cnt;
-}
-
-uint32_t pd_get_requested_voltage(int port)
-{
- return pe[port].supply_voltage;
-}
-
-uint32_t pd_get_requested_current(int port)
-{
- return pe[port].curr_limit;
-}
-
-/*
- * Determine if this port may communicate with the cable plug.
- *
- * In both PD 2.0 and 3.0 (2.5.4 SOP'/SOP'' Communication with Cable Plugs):
- *
- * When no Contract or an Implicit Contract is in place (e.g. after a Power Role
- * Swap or Fast Role Swap) only the Source port that is supplying Vconn is
- * allowed to send packets to a Cable Plug
- *
- * When in an explicit contract, PD 3.0 requires that a port be Vconn source to
- * communicate with the cable. PD 2.0 requires that a port be DFP to
- * communicate with the cable plug, with an implication that it must be Vconn
- * source as well (6.3.11 VCONN_Swap Message).
- */
-static bool pe_can_send_sop_prime(int port)
-{
- if (IS_ENABLED(CONFIG_USBC_VCONN)) {
- if (PE_CHK_FLAG(port, PE_FLAGS_EXPLICIT_CONTRACT)) {
- if (prl_get_rev(port, TCPCI_MSG_SOP) == PD_REV20)
- return tc_is_vconn_src(port) &&
- pe[port].data_role == PD_ROLE_DFP;
- else
- return tc_is_vconn_src(port);
- } else {
- return tc_is_vconn_src(port) &&
- pe[port].power_role == PD_ROLE_SOURCE;
- }
- } else {
- return false;
- }
-}
-
-/*
- * Determine if this port may send the given VDM type
- *
- * For PD 2.0, "Only the DFP Shall be an Initrator of Structured VDMs except for
- * the Attention Command that Shall only be initiated by the UFP"
- *
- * For PD 3.0, "Either port May be an Initiator of Structured VDMs except for
- * the Enter Mode and Exit Mode Commands which shall only be initiated by the
- * DFP" (6.4.4.2 Structured VDM)
- *
- * In both revisions, VDMs may only be initiated while in an explicit contract,
- * with the only exception being for cable plug discovery.
- */
-static bool pe_can_send_sop_vdm(int port, int vdm_cmd)
-{
- if (PE_CHK_FLAG(port, PE_FLAGS_EXPLICIT_CONTRACT)) {
- if (prl_get_rev(port, TCPCI_MSG_SOP) == PD_REV20) {
- if (pe[port].data_role == PD_ROLE_UFP &&
- vdm_cmd != CMD_ATTENTION) {
- return false;
- }
- } else {
- if (pe[port].data_role == PD_ROLE_UFP &&
- (vdm_cmd == CMD_ENTER_MODE ||
- vdm_cmd == CMD_EXIT_MODE)) {
- return false;
- }
- }
- return true;
- }
-
- return false;
-}
-
-static void pe_send_soft_reset(const int port, enum tcpci_msg_type type)
-{
- pe[port].soft_reset_sop = type;
- set_state_pe(port, PE_SEND_SOFT_RESET);
-}
-
-void pe_report_discard(int port)
-{
- /*
- * Clear local AMS indicator as our AMS message was discarded, and flag
- * the discard for the PE
- */
- PE_CLR_FLAG(port, PE_FLAGS_LOCALLY_INITIATED_AMS);
- PE_SET_FLAG(port, PE_FLAGS_MSG_DISCARDED);
-
- /* TODO(b/157228506): Ensure all states are checking discard */
-}
-
-/*
- * Utility function to check for an outgoing message discard during states which
- * send a message as a part of an AMS and wait for the transmit to complete.
- * Note these states should not be power transitioning.
- *
- * In these states, discard due to an incoming message is a protocol error.
- */
-static bool pe_check_outgoing_discard(int port)
-{
- /*
- * On outgoing discard, soft reset with SOP* of incoming message
- *
- * See Table 6-65 Response to an incoming Message (except VDM) in PD 3.0
- * Version 2.0 Specification.
- */
- if (PE_CHK_FLAG(port, PE_FLAGS_MSG_DISCARDED) &&
- PE_CHK_FLAG(port, PE_FLAGS_MSG_RECEIVED)) {
- enum tcpci_msg_type sop =
- PD_HEADER_GET_SOP(rx_emsg[port].header);
-
- PE_CLR_FLAG(port, PE_FLAGS_MSG_DISCARDED);
- PE_CLR_FLAG(port, PE_FLAGS_MSG_RECEIVED);
-
- pe_send_soft_reset(port, sop);
- return true;
- }
-
- return false;
-}
-
-void pe_report_error(int port, enum pe_error e, enum tcpci_msg_type type)
-{
- /* This should only be called from the PD task */
- assert(port == TASK_ID_TO_PD_PORT(task_get_current()));
-
- /*
- * If there is a timeout error while waiting for a chunk of a chunked
- * message, there is no requirement to trigger a soft reset.
- */
- if (e == ERR_RCH_CHUNK_WAIT_TIMEOUT)
- return;
-
- /*
- * Generate Hard Reset if Protocol Error occurred
- * while in PE_Send_Soft_Reset state.
- */
- if (get_state_pe(port) == PE_SEND_SOFT_RESET) {
- if (pe[port].power_role == PD_ROLE_SINK)
- set_state_pe(port, PE_SNK_HARD_RESET);
- else
- set_state_pe(port, PE_SRC_HARD_RESET);
- return;
- }
-
- /*
- * The following states require custom handling of protocol errors,
- * because they either need special handling of the no GoodCRC case
- * (cable identity request, send capabilities), occur before explicit
- * contract (discovery), or happen during a power transition.
- *
- * TODO(b/150774779): TCPMv2: Improve pe_error documentation
- */
- if ((get_state_pe(port) == PE_SRC_SEND_CAPABILITIES ||
- get_state_pe(port) == PE_SRC_TRANSITION_SUPPLY ||
- get_state_pe(port) == PE_PRS_SNK_SRC_EVALUATE_SWAP ||
- get_state_pe(port) == PE_PRS_SNK_SRC_SOURCE_ON ||
- get_state_pe(port) == PE_PRS_SRC_SNK_WAIT_SOURCE_ON ||
- get_state_pe(port) == PE_SRC_DISABLED ||
- get_state_pe(port) == PE_SRC_DISCOVERY ||
- get_state_pe(port) == PE_VCS_CBL_SEND_SOFT_RESET ||
- get_state_pe(port) == PE_VDM_IDENTITY_REQUEST_CBL) ||
- (pe_in_frs_mode(port) &&
- get_state_pe(port) == PE_PRS_SNK_SRC_SEND_SWAP)
- ) {
- PE_SET_FLAG(port, PE_FLAGS_PROTOCOL_ERROR);
- task_wake(PD_PORT_TO_TASK_ID(port));
- return;
- }
-
- /*
- * See section 8.3.3.4.1.1 PE_SRC_Send_Soft_Reset State:
- *
- * The PE_Send_Soft_Reset state shall be entered from
- * any state when
- * * A Protocol Error is detected by Protocol Layer during a
- * Non-Interruptible AMS or
- * * A message has not been sent after retries or
- * * When not in an explicit contract and
- * * Protocol Errors occurred on SOP during an Interruptible AMS or
- * * Protocol Errors occurred on SOP during any AMS where the first
- * Message in the sequence has not yet been sent i.e. an unexpected
- * Message is received instead of the expected GoodCRC Message
- * response.
- */
- /* All error types besides transmit errors are Protocol Errors. */
- if ((e != ERR_TCH_XMIT &&
- !PE_CHK_FLAG(port, PE_FLAGS_INTERRUPTIBLE_AMS))
- || e == ERR_TCH_XMIT
- || (!PE_CHK_FLAG(port, PE_FLAGS_EXPLICIT_CONTRACT) &&
- type == TCPCI_MSG_SOP)) {
- pe_send_soft_reset(port, type);
- }
- /*
- * Transition to PE_Snk_Ready or PE_Src_Ready by a Protocol
- * Error during an Interruptible AMS.
- */
- else {
- pe_set_ready_state(port);
- }
-}
-
-void pe_got_soft_reset(int port)
-{
- /* This should only be called from the PD task */
- assert(port == TASK_ID_TO_PD_PORT(task_get_current()));
-
- /*
- * The PE_SRC_Soft_Reset state Shall be entered from any state when a
- * Soft_Reset Message is received from the Protocol Layer.
- */
- set_state_pe(port, PE_SOFT_RESET);
-}
-
-__overridable bool pd_can_charge_from_device(int port, const int pdo_cnt,
- const uint32_t *pdos)
-{
- /*
- * Don't attempt to charge from a device we have no SrcCaps from. Or, if
- * drp_state is FORCE_SOURCE then don't attempt a PRS.
- */
- if (pdo_cnt == 0 || pd_get_dual_role(port) == PD_DRP_FORCE_SOURCE)
- return false;
-
- /*
- * Treat device as a dedicated charger (meaning we should charge
- * from it) if:
- * - it does not support power swap, or
- * - it is unconstrained power, or
- * - it presents at least 27 W of available power
- */
-
- /* Unconstrained Power or NOT Dual Role Power we can charge from */
- if (pdos[0] & PDO_FIXED_UNCONSTRAINED ||
- (pdos[0] & PDO_FIXED_DUAL_ROLE) == 0)
- return true;
-
- /* [virtual] allow_list */
- if (IS_ENABLED(CONFIG_CHARGE_MANAGER)) {
- uint32_t max_ma, max_mv, max_pdo, max_mw, unused;
-
- /*
- * Get max power that the partner offers (not necessarily what
- * this board will request)
- */
- pd_find_pdo_index(pdo_cnt, pdos,
- PD_REV3_MAX_VOLTAGE,
- &max_pdo);
- pd_extract_pdo_power(max_pdo, &max_ma, &max_mv, &unused);
- max_mw = max_ma * max_mv / 1000;
-
- if (max_mw >= PD_DRP_CHARGE_POWER_MIN)
- return true;
- }
- return false;
-}
-
-void pd_resume_check_pr_swap_needed(int port)
-{
- /*
- * Explicit contract, current power role of SNK, the device
- * indicates it should not power us, and device isn't selected
- * as the charging port (ex. through the GUI) then trigger a PR_Swap
- */
- if (pe_is_explicit_contract(port) &&
- pd_get_power_role(port) == PD_ROLE_SINK &&
- !pd_can_charge_from_device(port, pd_get_src_cap_cnt(port),
- pd_get_src_caps(port)) &&
- (!IS_ENABLED(CONFIG_CHARGE_MANAGER) ||
- charge_manager_get_active_charge_port() != port))
- pd_dpm_request(port, DPM_REQUEST_PR_SWAP);
-}
-
-void pd_dpm_request(int port, enum pd_dpm_request req)
-{
- PE_SET_DPM_REQUEST(port, req);
-}
-
-void pe_vconn_swap_complete(int port)
-{
- /* This should only be called from the PD task */
- assert(port == TASK_ID_TO_PD_PORT(task_get_current()));
-
- PE_SET_FLAG(port, PE_FLAGS_VCONN_SWAP_COMPLETE);
-}
-
-void pe_ps_reset_complete(int port)
-{
- /* This should only be called from the PD task */
- assert(port == TASK_ID_TO_PD_PORT(task_get_current()));
-
- PE_SET_FLAG(port, PE_FLAGS_PS_RESET_COMPLETE);
-}
-
-void pe_message_sent(int port)
-{
- /* This should only be called from the PD task */
- assert(port == TASK_ID_TO_PD_PORT(task_get_current()));
-
- PE_SET_FLAG(port, PE_FLAGS_TX_COMPLETE);
- task_wake(PD_PORT_TO_TASK_ID(port));
-}
-
-void pd_send_vdm(int port, uint32_t vid, int cmd, const uint32_t *data,
- int count)
-{
- /* Copy VDM Header */
- pe[port].vdm_data[0] =
- VDO(vid, ((vid & USB_SID_PD) == USB_SID_PD) ? 1 :
- (PD_VDO_CMD(cmd) <= CMD_ATTENTION),
- VDO_SVDM_VERS(pd_get_vdo_ver(port, TCPCI_MSG_SOP)) |
- cmd);
-
- /*
- * Copy VDOs after the VDM Header. Note that the count refers to VDO
- * count.
- */
- memcpy((pe[port].vdm_data + 1), data, count * sizeof(uint32_t));
-
- pe[port].vdm_cnt = count + 1;
-
- /*
- * The PE transmit routine assumes that tx_type was set already. Note,
- * that this function is likely called from outside the PD task.
- * (b/180465870)
- */
- pe[port].tx_type = TCPCI_MSG_SOP;
- pd_dpm_request(port, DPM_REQUEST_VDM);
-
- task_wake(PD_PORT_TO_TASK_ID(port));
-}
-
-#ifdef TEST_BUILD
-/*
- * Allow unit tests to access this function to clear internal state data between
- * runs
- */
-void pe_clear_port_data(int port)
-#else
-static void pe_clear_port_data(int port)
-#endif /* TEST_BUILD */
-{
- /*
- * PD 3.0 Section 8.3.3.3.8
- * Note: The HardResetCounter is reset on a power cycle or Detach.
- */
- pe[port].hard_reset_counter = 0;
-
- /* Reset port events */
- pd_clear_events(port, GENMASK(31, 0));
-
- /* But then set disconnected event */
- pd_notify_event(port, PD_STATUS_EVENT_DISCONNECTED);
-
- /* Tell Policy Engine to invalidate the explicit contract */
- pe_invalidate_explicit_contract(port);
-
- /*
- * Saved Source and Sink Capabilities are no longer valid on disconnect
- */
- pd_set_src_caps(port, 0, NULL);
- pe_set_snk_caps(port, 0, NULL);
-
- dpm_remove_sink(port);
- dpm_remove_source(port);
-
- /* Exit BIST Test mode, in case the TCPC entered it. */
- tcpc_set_bist_test_mode(port, false);
-}
-
-static void pe_handle_detach(void)
-{
- const int port = TASK_ID_TO_PD_PORT(task_get_current());
-
- pe_clear_port_data(port);
-}
-DECLARE_HOOK(HOOK_USB_PD_DISCONNECT, pe_handle_detach, HOOK_PRIO_DEFAULT);
-
-#ifdef CONFIG_USB_PD_RESET_MIN_BATT_SOC
-static void pe_update_waiting_batt_flag(void)
-{
- int i;
- int batt_soc = usb_get_battery_soc();
-
- if (batt_soc < CONFIG_USB_PD_RESET_MIN_BATT_SOC ||
- battery_get_disconnect_state() != BATTERY_NOT_DISCONNECTED)
- return;
-
- for (i = 0; i < board_get_usb_pd_port_count(); i++) {
- if (PE_CHK_FLAG(i, PE_FLAGS_SNK_WAITING_BATT)) {
- /*
- * Battery has gained sufficient charge to kick off PD
- * negotiation and withstand a hard reset. Clear the
- * flag and perform Hard Reset.
- */
- PE_CLR_FLAG(i, PE_FLAGS_SNK_WAITING_BATT);
- CPRINTS("C%d: Battery has enough charge (%d%%) " \
- "to withstand a hard reset", i, batt_soc);
- pd_dpm_request(i, DPM_REQUEST_HARD_RESET_SEND);
- }
- }
-}
-DECLARE_HOOK(HOOK_BATTERY_SOC_CHANGE, pe_update_waiting_batt_flag,
- HOOK_PRIO_DEFAULT);
-#endif
-
-/*
- * Private functions
- */
-static void pe_set_dpm_curr_request(const int port,
- const int request)
-{
- PE_CLR_DPM_REQUEST(port, request);
- pe[port].dpm_curr_request = request;
-}
-
-/* Set the TypeC state machine to a new state. */
-test_export_static void set_state_pe(const int port,
- const enum usb_pe_state new_state)
-{
- set_state(port, &pe[port].ctx, &pe_states[new_state]);
-}
-
-/* Get the current TypeC state. */
-test_export_static enum usb_pe_state get_state_pe(const int port)
-{
- return pe[port].ctx.current - &pe_states[0];
-}
-
-/*
- * Handle common DPM requests to both source and sink.
- *
- * Note: it is assumed the calling state set PE_FLAGS_LOCALLY_INITIATED_AMS
- *
- * Returns true if state was set and calling run state should now return.
- */
-static bool common_src_snk_dpm_requests(int port)
-{
- if (IS_ENABLED(CONFIG_USB_PD_EXTENDED_MESSAGES) &&
- PE_CHK_DPM_REQUEST(port, DPM_REQUEST_SEND_ALERT)) {
- pe_set_dpm_curr_request(port, DPM_REQUEST_SEND_ALERT);
- set_state_pe(port, PE_SEND_ALERT);
- return true;
- } else if (IS_ENABLED(CONFIG_USBC_VCONN) &&
- PE_CHK_DPM_REQUEST(port, DPM_REQUEST_VCONN_SWAP)) {
- pe_set_dpm_curr_request(port, DPM_REQUEST_VCONN_SWAP);
- set_state_pe(port, PE_VCS_SEND_SWAP);
- return true;
- } else if (PE_CHK_DPM_REQUEST(port,
- DPM_REQUEST_BIST_TX)) {
- pe_set_dpm_curr_request(port, DPM_REQUEST_BIST_TX);
- set_state_pe(port, PE_BIST_TX);
- return true;
- } else if (PE_CHK_DPM_REQUEST(port,
- DPM_REQUEST_SNK_STARTUP)) {
- pe_set_dpm_curr_request(port, DPM_REQUEST_SNK_STARTUP);
- set_state_pe(port, PE_SNK_STARTUP);
- return true;
- } else if (PE_CHK_DPM_REQUEST(port,
- DPM_REQUEST_SRC_STARTUP)) {
- pe_set_dpm_curr_request(port, DPM_REQUEST_SRC_STARTUP);
- set_state_pe(port, PE_SRC_STARTUP);
- return true;
- } else if (PE_CHK_DPM_REQUEST(port,
- DPM_REQUEST_SOFT_RESET_SEND)) {
- pe_set_dpm_curr_request(port, DPM_REQUEST_SOFT_RESET_SEND);
- /* Currently only support sending soft reset to SOP */
- pe_send_soft_reset(port, TCPCI_MSG_SOP);
- return true;
- } else if (PE_CHK_DPM_REQUEST(port, DPM_REQUEST_PORT_DISCOVERY)) {
- pe_set_dpm_curr_request(port, DPM_REQUEST_PORT_DISCOVERY);
- if (!PE_CHK_FLAG(port, PE_FLAGS_MODAL_OPERATION)) {
- /*
- * Clear counters and reset timer to trigger a
- * port discovery, and also clear any pending VDM send
- * requests.
- */
- pd_dfp_discovery_init(port);
- /*
- * TODO(b/189353401): Do not reinitialize modes when no
- * longer required.
- */
- pd_dfp_mode_init(port);
- pe[port].dr_swap_attempt_counter = 0;
- pe[port].discover_identity_counter = 0;
- pd_timer_enable(port, PE_TIMER_DISCOVER_IDENTITY,
- PD_T_DISCOVER_IDENTITY);
- PE_CLR_DPM_REQUEST(port, DPM_REQUEST_VDM);
- }
- return true;
- } else if (PE_CHK_DPM_REQUEST(port, DPM_REQUEST_VDM)) {
- pe_set_dpm_curr_request(port, DPM_REQUEST_VDM);
- /* Send previously set up SVDM. */
- set_state_pe(port, PE_VDM_REQUEST_DPM);
- return true;
- } else if (PE_CHK_DPM_REQUEST(port, DPM_REQUEST_ENTER_USB)) {
- pe_set_dpm_curr_request(port, DPM_REQUEST_ENTER_USB);
- set_state_pe(port, PE_DEU_SEND_ENTER_USB);
- return true;
- } else if (PE_CHK_DPM_REQUEST(port, DPM_REQUEST_EXIT_MODES)) {
- pe_set_dpm_curr_request(port, DPM_REQUEST_EXIT_MODES);
- dpm_set_mode_exit_request(port);
- return true;
- } else if (PE_CHK_DPM_REQUEST(port, DPM_REQUEST_GET_SNK_CAPS)) {
- pe_set_dpm_curr_request(port,
- DPM_REQUEST_GET_SNK_CAPS);
- set_state_pe(port, PE_DR_GET_SINK_CAP);
- return true;
- } else if (PE_CHK_DPM_REQUEST(port,
- DPM_REQUEST_SOP_PRIME_SOFT_RESET_SEND)) {
- pe_set_dpm_curr_request(port,
- DPM_REQUEST_SOP_PRIME_SOFT_RESET_SEND);
- pe[port].tx_type = TCPCI_MSG_SOP_PRIME;
- set_state_pe(port, PE_VCS_CBL_SEND_SOFT_RESET);
- return true;
- }
-
- return false;
-}
-
-/*
- * Handle source-specific DPM requests
- *
- * Returns true if state was set and calling run state should now return.
- */
-static bool source_dpm_requests(int port)
-{
- /*
- * Ignore sink-specific request:
- * DPM_REQUEST_NEW_POWER_LEVEL
- * DPM_REQUEST_SOURCE_CAP
- * DPM_REQUEST_FRS_DET_ENABLE
- * DPM_REQURST_FRS_DET_DISABLE
- */
- PE_CLR_DPM_REQUEST(port, DPM_REQUEST_NEW_POWER_LEVEL |
- DPM_REQUEST_SOURCE_CAP |
- DPM_REQUEST_FRS_DET_ENABLE |
- DPM_REQUEST_FRS_DET_DISABLE);
-
- if (pe[port].dpm_request) {
- uint32_t dpm_request = pe[port].dpm_request;
-
- PE_SET_FLAG(port, PE_FLAGS_LOCALLY_INITIATED_AMS);
-
- if (PE_CHK_DPM_REQUEST(port,
- DPM_REQUEST_DR_SWAP)) {
- pe_set_dpm_curr_request(port,
- DPM_REQUEST_DR_SWAP);
- if (PE_CHK_FLAG(port, PE_FLAGS_MODAL_OPERATION))
- set_state_pe(port, PE_SRC_HARD_RESET);
- else
- set_state_pe(port, PE_DRS_SEND_SWAP);
- return true;
- } else if (PE_CHK_DPM_REQUEST(port,
- DPM_REQUEST_PR_SWAP)) {
- pe_set_dpm_curr_request(port,
- DPM_REQUEST_PR_SWAP);
- set_state_pe(port, PE_PRS_SRC_SNK_SEND_SWAP);
- return true;
- } else if (PE_CHK_DPM_REQUEST(port,
- DPM_REQUEST_GOTO_MIN)) {
- pe_set_dpm_curr_request(port,
- DPM_REQUEST_GOTO_MIN);
- set_state_pe(port, PE_SRC_TRANSITION_SUPPLY);
- return true;
- } else if (PE_CHK_DPM_REQUEST(port,
- DPM_REQUEST_SRC_CAP_CHANGE)) {
- pe_set_dpm_curr_request(port,
- DPM_REQUEST_SRC_CAP_CHANGE);
- set_state_pe(port, PE_SRC_SEND_CAPABILITIES);
- return true;
- } else if (PE_CHK_DPM_REQUEST(port,
- DPM_REQUEST_GET_SRC_CAPS)) {
- pe_set_dpm_curr_request(port,
- DPM_REQUEST_GET_SRC_CAPS);
- set_state_pe(port, PE_DR_SRC_GET_SOURCE_CAP);
- return true;
- } else if (PE_CHK_DPM_REQUEST(port,
- DPM_REQUEST_SEND_PING)) {
- pe_set_dpm_curr_request(port,
- DPM_REQUEST_SEND_PING);
- set_state_pe(port, PE_SRC_PING);
- return true;
- } else if (common_src_snk_dpm_requests(port)) {
- return true;
- }
-
- CPRINTF("Unhandled DPM Request %x received\n",
- dpm_request);
- PE_CLR_DPM_REQUEST(port, dpm_request);
- PE_CLR_FLAG(port, PE_FLAGS_LOCALLY_INITIATED_AMS);
- }
- return false;
-}
-
-/*
- * Handle sink-specific DPM requests
- *
- * Returns true if state was set and calling run state should now return.
- */
-static bool sink_dpm_requests(int port)
-{
- /*
- * Ignore source specific requests:
- * DPM_REQUEST_GOTO_MIN
- * DPM_REQUEST_SRC_CAP_CHANGE,
- * DPM_REQUEST_SEND_PING
- */
- PE_CLR_DPM_REQUEST(port, DPM_REQUEST_GOTO_MIN |
- DPM_REQUEST_SRC_CAP_CHANGE |
- DPM_REQUEST_SEND_PING);
-
- if (pe[port].dpm_request) {
- uint32_t dpm_request = pe[port].dpm_request;
-
- PE_SET_FLAG(port, PE_FLAGS_LOCALLY_INITIATED_AMS);
-
- if (PE_CHK_DPM_REQUEST(port,
- DPM_REQUEST_DR_SWAP)) {
- pe_set_dpm_curr_request(port,
- DPM_REQUEST_DR_SWAP);
- if (PE_CHK_FLAG(port, PE_FLAGS_MODAL_OPERATION))
- set_state_pe(port, PE_SNK_HARD_RESET);
- else
- set_state_pe(port, PE_DRS_SEND_SWAP);
- return true;
- } else if (PE_CHK_DPM_REQUEST(port,
- DPM_REQUEST_PR_SWAP)) {
- pe_set_dpm_curr_request(port,
- DPM_REQUEST_PR_SWAP);
- set_state_pe(port, PE_PRS_SNK_SRC_SEND_SWAP);
- return true;
- } else if (PE_CHK_DPM_REQUEST(port,
- DPM_REQUEST_SOURCE_CAP)) {
- pe_set_dpm_curr_request(port,
- DPM_REQUEST_SOURCE_CAP);
- set_state_pe(port, PE_SNK_GET_SOURCE_CAP);
- return true;
- } else if (PE_CHK_DPM_REQUEST(port,
- DPM_REQUEST_NEW_POWER_LEVEL)) {
- pe_set_dpm_curr_request(port,
- DPM_REQUEST_NEW_POWER_LEVEL);
- set_state_pe(port, PE_SNK_SELECT_CAPABILITY);
- return true;
- } else if (PE_CHK_DPM_REQUEST(port,
- DPM_REQUEST_FRS_DET_ENABLE)) {
- pe_set_frs_enable(port, 1);
-
- /* Requires no state change, fall through to false */
- PE_CLR_DPM_REQUEST(port, DPM_REQUEST_FRS_DET_ENABLE);
- } else if (PE_CHK_DPM_REQUEST(port,
- DPM_REQUEST_FRS_DET_DISABLE)) {
- pe_set_frs_enable(port, 0);
- /* Restore a default port current limit */
- typec_select_src_current_limit_rp(port,
- CONFIG_USB_PD_PULLUP);
-
- /* Requires no state change, fall through to false */
- PE_CLR_DPM_REQUEST(port, DPM_REQUEST_FRS_DET_DISABLE);
- } else if (common_src_snk_dpm_requests(port)) {
- return true;
- } else {
- CPRINTF("Unhandled DPM Request %x received\n",
- dpm_request);
- PE_CLR_DPM_REQUEST(port, dpm_request);
- }
-
- PE_CLR_FLAG(port, PE_FLAGS_LOCALLY_INITIATED_AMS);
- }
- return false;
-}
-
-/* Get the previous TypeC state. */
-static enum usb_pe_state get_last_state_pe(const int port)
-{
- return pe[port].ctx.previous - &pe_states[0];
-}
-
-static void print_current_state(const int port)
-{
- const char *mode = "";
-
- if (IS_ENABLED(CONFIG_USB_PD_REV30) &&
- pe_in_frs_mode(port))
- mode = " FRS-MODE";
-
- if (IS_ENABLED(USB_PD_DEBUG_LABELS))
- CPRINTS_L1("C%d: %s%s", port,
- pe_state_names[get_state_pe(port)], mode);
- else
- CPRINTS("C%d: pe-st%d", port, get_state_pe(port));
-}
-
-static void send_source_cap(int port)
-{
- const uint32_t *src_pdo;
- const int src_pdo_cnt = dpm_get_source_pdo(&src_pdo, port);
-
- if (src_pdo_cnt == 0) {
- /* No source capabilities defined, sink only */
- send_ctrl_msg(port, TCPCI_MSG_SOP, PD_CTRL_REJECT);
- }
-
- tx_emsg[port].len = src_pdo_cnt * 4;
- memcpy(tx_emsg[port].buf, (uint8_t *)src_pdo, tx_emsg[port].len);
-
- send_data_msg(port, TCPCI_MSG_SOP, PD_DATA_SOURCE_CAP);
-}
-
-/*
- * Request desired charge voltage from source.
- */
-static void pe_send_request_msg(int port)
-{
- uint32_t vpd_vdo = 0;
- uint32_t rdo;
- uint32_t curr_limit;
- uint32_t supply_voltage;
-
- /*
- * If we are charging through a VPD, the requested voltage and current
- * might need adjusting.
- */
- if ((get_usb_pd_cable_type(port) == IDH_PTYPE_VPD) &&
- is_vpd_ct_supported(port)) {
- union vpd_vdo vpd = pd_get_am_discovery(port,
- TCPCI_MSG_SOP_PRIME)->identity.product_t1.vpd;
-
- /* The raw vpd_vdo is passed to pd_build_request */
- vpd_vdo = vpd.raw_value;
- }
-
- /* Build and send request RDO */
- pd_build_request(vpd_vdo, &rdo, &curr_limit,
- &supply_voltage, port);
-
- CPRINTF("C%d: Req [%d] %dmV %dmA", port, RDO_POS(rdo),
- supply_voltage, curr_limit);
- if (rdo & RDO_CAP_MISMATCH)
- CPRINTF(" Mismatch");
- CPRINTF("\n");
-
- pe[port].curr_limit = curr_limit;
- pe[port].supply_voltage = supply_voltage;
-
- tx_emsg[port].len = 4;
-
- memcpy(tx_emsg[port].buf, (uint8_t *)&rdo, tx_emsg[port].len);
- send_data_msg(port, TCPCI_MSG_SOP, PD_DATA_REQUEST);
-}
-
-static void pe_update_src_pdo_flags(int port, int pdo_cnt, uint32_t *pdos)
-{
- /*
- * Only parse PDO flags if type is fixed
- *
- * Note: From 6.4.1 Capabilities Message "The vSafe5V Fixed Supply
- * Object Shall always be the first object." so hitting this condition
- * would mean the partner is voilating spec.
- */
- if ((pdos[0] & PDO_TYPE_MASK) != PDO_TYPE_FIXED)
- return;
-
- if (IS_ENABLED(CONFIG_CHARGE_MANAGER)) {
- if (pd_can_charge_from_device(port, pdo_cnt, pdos)) {
- charge_manager_update_dualrole(port, CAP_DEDICATED);
- } else {
- charge_manager_update_dualrole(port, CAP_DUALROLE);
- }
- }
-}
-
-/*
- * Evaluate whether our PR role is in the middle of changing, meaning we our
- * current PR role is not the one we expect to have very shortly.
- */
-bool pe_is_pr_swapping(int port)
-{
- enum usb_pe_state cur_state = get_state_pe(port);
-
- if (cur_state == PE_PRS_SRC_SNK_EVALUATE_SWAP ||
- cur_state == PE_PRS_SRC_SNK_TRANSITION_TO_OFF ||
- cur_state == PE_PRS_SNK_SRC_EVALUATE_SWAP ||
- cur_state == PE_PRS_SNK_SRC_TRANSITION_TO_OFF)
- return true;
-
- return false;
-}
-
-void pd_request_power_swap(int port)
-{
- /* Ignore requests when the board does not wish to swap */
- if (!pd_check_power_swap(port))
- return;
-
- /* Ignore requests when our power role is transitioning */
- if (pe_is_pr_swapping(port))
- return;
-
- /*
- * Always reset the SRC to SNK PR swap counter when a PR swap is
- * requested by policy.
- */
- pe[port].src_snk_pr_swap_counter = 0;
- pd_dpm_request(port, DPM_REQUEST_PR_SWAP);
-}
-
-/* The function returns true if there is a PE state change, false otherwise */
-static bool port_try_vconn_swap(int port)
-{
- if (pe[port].vconn_swap_counter < N_VCONN_SWAP_COUNT) {
- pd_dpm_request(port, DPM_REQUEST_VCONN_SWAP);
- set_state_pe(port, get_last_state_pe(port));
- return true;
- }
- return false;
-}
-
-/*
- * Run discovery at our leisure from PE_SNK_Ready or PE_SRC_Ready, after
- * attempting to get into the desired default policy of DFP/Vconn source
- *
- * Return indicates whether set_state was called, in which case the calling
- * function should return as well.
- */
-__maybe_unused static bool pe_attempt_port_discovery(int port)
-{
- if (!IS_ENABLED(CONFIG_USB_PD_ALT_MODE_DFP))
- assert(0);
-
- /*
- * DONE set once modal entry is successful, discovery completes, or
- * discovery results in a NAK
- */
- if (PE_CHK_FLAG(port, PE_FLAGS_VDM_SETUP_DONE))
- return false;
-
- /* Apply Port Discovery DR Swap Policy */
- if (port_discovery_dr_swap_policy(port, pe[port].data_role,
- PE_CHK_FLAG(port, PE_FLAGS_DR_SWAP_TO_DFP))) {
- PE_SET_FLAG(port, PE_FLAGS_LOCALLY_INITIATED_AMS);
- PE_CLR_FLAG(port, PE_FLAGS_DR_SWAP_TO_DFP);
- set_state_pe(port, PE_DRS_SEND_SWAP);
- return true;
- }
-
- /* Apply Port Discovery VCONN Swap Policy */
- if (IS_ENABLED(CONFIG_USBC_VCONN) &&
- port_discovery_vconn_swap_policy(port,
- PE_CHK_FLAG(port, PE_FLAGS_VCONN_SWAP_TO_ON))) {
- PE_SET_FLAG(port, PE_FLAGS_LOCALLY_INITIATED_AMS);
- PE_CLR_FLAG(port, PE_FLAGS_VCONN_SWAP_TO_ON);
- set_state_pe(port, PE_VCS_SEND_SWAP);
- return true;
- }
-
- /* If mode entry was successful, disable the timer */
- if (PE_CHK_FLAG(port, PE_FLAGS_VDM_SETUP_DONE)) {
- pd_timer_disable(port, PE_TIMER_DISCOVER_IDENTITY);
- return false;
- }
-
- /*
- * Run discovery functions when the timer indicating either cable
- * discovery spacing or BUSY spacing runs out.
- */
- if (pd_timer_is_expired(port, PE_TIMER_DISCOVER_IDENTITY)) {
- if (pd_get_identity_discovery(port, TCPCI_MSG_SOP_PRIME) ==
- PD_DISC_NEEDED) {
- pe[port].tx_type = TCPCI_MSG_SOP_PRIME;
- set_state_pe(port, PE_VDM_IDENTITY_REQUEST_CBL);
- return true;
- } else if (pd_get_identity_discovery(port, TCPCI_MSG_SOP) ==
- PD_DISC_NEEDED &&
- pe_can_send_sop_vdm(port, CMD_DISCOVER_IDENT)) {
- pe[port].tx_type = TCPCI_MSG_SOP;
- set_state_pe(port,
- PE_INIT_PORT_VDM_IDENTITY_REQUEST);
- return true;
- } else if (pd_get_svids_discovery(port, TCPCI_MSG_SOP) ==
- PD_DISC_NEEDED &&
- pe_can_send_sop_vdm(port, CMD_DISCOVER_SVID)) {
- pe[port].tx_type = TCPCI_MSG_SOP;
- set_state_pe(port, PE_INIT_VDM_SVIDS_REQUEST);
- return true;
- } else if (pd_get_modes_discovery(port, TCPCI_MSG_SOP) ==
- PD_DISC_NEEDED &&
- pe_can_send_sop_vdm(port, CMD_DISCOVER_MODES)) {
- pe[port].tx_type = TCPCI_MSG_SOP;
- set_state_pe(port, PE_INIT_VDM_MODES_REQUEST);
- return true;
- } else if (pd_get_svids_discovery(port, TCPCI_MSG_SOP_PRIME)
- == PD_DISC_NEEDED) {
- pe[port].tx_type = TCPCI_MSG_SOP_PRIME;
- set_state_pe(port, PE_INIT_VDM_SVIDS_REQUEST);
- return true;
- } else if (pd_get_modes_discovery(port, TCPCI_MSG_SOP_PRIME) ==
- PD_DISC_NEEDED) {
- pe[port].tx_type = TCPCI_MSG_SOP_PRIME;
- set_state_pe(port, PE_INIT_VDM_MODES_REQUEST);
- return true;
- }
- }
-
- return false;
-}
-
-bool pd_setup_vdm_request(int port, enum tcpci_msg_type tx_type,
- uint32_t *vdm, uint32_t vdo_cnt)
-{
- if (vdo_cnt < VDO_HDR_SIZE || vdo_cnt > VDO_MAX_SIZE)
- return false;
-
- pe[port].tx_type = tx_type;
- memcpy(pe[port].vdm_data, vdm, vdo_cnt * sizeof(*vdm));
- pe[port].vdm_cnt = vdo_cnt;
-
- return true;
-}
-
-int pd_dev_store_rw_hash(int port, uint16_t dev_id, uint32_t *rw_hash,
- uint32_t current_image)
-{
- pe[port].dev_id = dev_id;
- memcpy(pe[port].dev_rw_hash, rw_hash, PD_RW_HASH_SIZE);
-#ifdef CONFIG_CMD_PD_DEV_DUMP_INFO
- pd_dev_dump_info(dev_id, rw_hash);
-#endif
- pe[port].current_image = current_image;
-
- if (IS_ENABLED(CONFIG_USB_PD_HOST_CMD)) {
- int i;
-
- /* Search table for matching device / hash */
- for (i = 0; i < RW_HASH_ENTRIES; i++)
- if (dev_id == rw_hash_table[i].dev_id)
- return !memcmp(rw_hash,
- rw_hash_table[i].dev_rw_hash,
- PD_RW_HASH_SIZE);
- }
-
- return 0;
-}
-
-void pd_dev_get_rw_hash(int port, uint16_t *dev_id, uint8_t *rw_hash,
- uint32_t *current_image)
-{
- *dev_id = pe[port].dev_id;
- *current_image = pe[port].current_image;
- if (*dev_id)
- memcpy(rw_hash, pe[port].dev_rw_hash, PD_RW_HASH_SIZE);
-}
-
-/*
- * This function must only be called from the PE_SNK_READY entry and
- * PE_SRC_READY entry State.
- *
- * TODO(b:181339670) Rethink jitter timer restart if this is the first
- * message but the partner gets a message in first, may not want to
- * disable and restart it.
- */
-static void pe_update_wait_and_add_jitter_timer(int port)
-{
- /*
- * In PD2.0 Mode
- *
- * For Source:
- * Give the sink some time to send any messages
- * before we may send messages of our own. Add
- * some jitter of up to ~345ms, to prevent
- * multiple collisions. This delay also allows
- * the sink device to request power role swap
- * and allow the the accept message to be sent
- * prior to CMD_DISCOVER_IDENT being sent in the
- * SRC_READY state.
- *
- * For Sink:
- * Give the source some time to send any messages before
- * we start our interrogation. Add some jitter of up to
- * ~345ms to prevent multiple collisions.
- */
- if (prl_get_rev(port, TCPCI_MSG_SOP) == PD_REV20 &&
- PE_CHK_FLAG(port, PE_FLAGS_FIRST_MSG) &&
- pd_timer_is_disabled(port, PE_TIMER_WAIT_AND_ADD_JITTER)) {
- pd_timer_enable(port, PE_TIMER_WAIT_AND_ADD_JITTER,
- SRC_SNK_READY_HOLD_OFF_US +
- (get_time().le.lo & 0xf) * 23 * MSEC);
- }
-}
-
-/**
- * Common sender response message handling
- *
- * This is setup like a pseudo state machine parent state. It
- * centralizes the SenderResponseTimer for the calling states, as
- * well as checking message send status.
- */
-/*
- * pe_sender_response_msg_entry
- * Initialization for handling sender response messages.
- *
- * @param port USB-C Port number
- */
-static void pe_sender_response_msg_entry(const int port)
-{
- /* Stop sender response timer */
- pd_timer_disable(port, PE_TIMER_SENDER_RESPONSE);
-}
-
-/*
- * pe_sender_response_msg_run
- * Check status of sender response messages.
- *
- * The normal progression of pe_sender_response_msg_entry is:
- * PENDING -> (COMPLETED/SENT) -> SENT -> SENT ...
- * or
- * PENDING -> DISCARDED
- * PENDING -> DPM_DISCARDED
- *
- * NOTE: it is not valid to call this function for a message after
- * receiving either PE_MSG_DISCARDED or PE_MSG_DPM_DISCARDED until
- * another message has been sent and pe_sender_response_msg_entry is called
- * again.
- *
- * @param port USB-C Port number
- * @return the current pe_msg_check
- */
-static enum pe_msg_check pe_sender_response_msg_run(const int port)
-{
- timestamp_t tx_success_ts;
- uint32_t offset;
- if (pd_timer_is_disabled(port, PE_TIMER_SENDER_RESPONSE)) {
- /* Check for Discard */
- if (PE_CHK_FLAG(port, PE_FLAGS_MSG_DISCARDED)) {
- int dpm_request = pe[port].dpm_curr_request;
-
- PE_CLR_FLAG(port, PE_FLAGS_MSG_DISCARDED);
- /* Restore the DPM Request */
- if (dpm_request) {
- PE_SET_DPM_REQUEST(port, dpm_request);
- return PE_MSG_DPM_DISCARDED;
- }
- return PE_MSG_DISCARDED;
- }
-
- /* Check for GoodCRC */
- if (PE_CHK_FLAG(port, PE_FLAGS_TX_COMPLETE)) {
- PE_CLR_FLAG(port, PE_FLAGS_TX_COMPLETE);
-
- /* TCPC TX success time stamp */
- tx_success_ts = prl_get_tcpc_tx_success_ts(port);
- /* Calculate the delay from TX success to PE */
- offset = time_since32(tx_success_ts);
-
- /*
- * Initialize and run the SenderResponseTimer by
- * offsetting it with TX transmit success time.
- * This would remove the effect of the latency from
- * propagating the TX status.
- */
- pd_timer_enable(port, PE_TIMER_SENDER_RESPONSE,
- PD_T_SENDER_RESPONSE - offset);
- return PE_MSG_SEND_COMPLETED;
- }
- return PE_MSG_SEND_PENDING;
- }
- return PE_MSG_SENT;
-}
-
-/*
- * pe_sender_response_msg_exit
- * Exit cleanup for handling sender response messages.
- *
- * @param port USB-C Port number
- */
-static void pe_sender_response_msg_exit(int port)
-{
- pd_timer_disable(port, PE_TIMER_SENDER_RESPONSE);
-}
-
-/**
- * PE_SRC_Startup
- */
-static void pe_src_startup_entry(int port)
-{
- print_current_state(port);
-
- /* Reset CapsCounter */
- pe[port].caps_counter = 0;
-
- /* Reset the protocol layer */
- prl_reset_soft(port);
-
- /* Set initial data role */
- pe[port].data_role = pd_get_data_role(port);
-
- /* Set initial power role */
- pe[port].power_role = PD_ROLE_SOURCE;
-
- /* Clear explicit contract. */
- pe_invalidate_explicit_contract(port);
-
- if (PE_CHK_FLAG(port, PE_FLAGS_PR_SWAP_COMPLETE)) {
- PE_CLR_FLAG(port, PE_FLAGS_PR_SWAP_COMPLETE);
- /*
- * Protocol layer reset clears the message IDs for all SOP
- * types. Indicate that a SOP' soft reset is required before any
- * other messages are sent to the cable.
- *
- * Note that other paths into this state are for the initial
- * connection and for a hard reset. In both cases the cable
- * should also automatically clear the message IDs so don't
- * generate an SOP' soft reset for those cases. Sending
- * unnecessary SOP' soft resets causes bad behavior with
- * some devices. See b/179325862.
- */
- pd_dpm_request(port, DPM_REQUEST_SOP_PRIME_SOFT_RESET_SEND);
-
- /* Start SwapSourceStartTimer */
- pd_timer_enable(port, PE_TIMER_SWAP_SOURCE_START,
- PD_T_SWAP_SOURCE_START);
-
- /*
- * Evaluate port's sink caps for preferred current, if
- * already available
- */
- if (pd_get_snk_cap_cnt(port) > 0)
- dpm_evaluate_sink_fixed_pdo(port,
- *pd_get_snk_caps(port));
-
- /*
- * Remove prior FRS claims to 3.0 A now that sink current has
- * been claimed, to avoid issues with lower priority ports
- * potentially receiving a 3.0 A claim between calls.
- */
- dpm_remove_source(port);
- } else {
- /*
- * SwapSourceStartTimer delay is not needed, so trigger now.
- * We can't use set_state_pe here, since we need to ensure that
- * the protocol layer is running again (done in run function).
- */
- pd_timer_enable(port, PE_TIMER_SWAP_SOURCE_START, 0);
-
- /*
- * Set DiscoverIdentityTimer to trigger when we enter
- * src_discovery for the first time. After initial startup
- * set, vdm_identity_request_cbl will handle the timer updates.
- */
- pd_timer_enable(port, PE_TIMER_DISCOVER_IDENTITY, 0);
-
- /* Clear port discovery/mode flags */
- pd_dfp_discovery_init(port);
- pd_dfp_mode_init(port);
- pe[port].ama_vdo = PD_VDO_INVALID;
- pe[port].vpd_vdo = PD_VDO_INVALID;
- pe[port].discover_identity_counter = 0;
-
- /* Reset dr swap attempt counter */
- pe[port].dr_swap_attempt_counter = 0;
-
- /* Reset VCONN swap counter */
- pe[port].vconn_swap_counter = 0;
-
- /* Request partner sink caps if a feature requires them */
- if (IS_ENABLED(CONFIG_USB_PD_HOST_CMD) ||
- CONFIG_USB_PD_3A_PORTS > 0 ||
- IS_ENABLED(CONFIG_USB_PD_FRS))
- pd_dpm_request(port, DPM_REQUEST_GET_SNK_CAPS);
- }
-}
-
-static void pe_src_startup_run(int port)
-{
- /* Wait until protocol layer is running */
- if (!prl_is_running(port))
- return;
-
- if (pd_timer_is_expired(port, PE_TIMER_SWAP_SOURCE_START))
- set_state_pe(port, PE_SRC_SEND_CAPABILITIES);
-}
-
-static void pe_src_startup_exit(int port)
-{
- pd_timer_disable(port, PE_TIMER_SWAP_SOURCE_START);
-}
-
-/**
- * PE_SRC_Discovery
- */
-static void pe_src_discovery_entry(int port)
-{
- print_current_state(port);
-
- /*
- * Initialize and run the SourceCapabilityTimer in order
- * to trigger sending a Source_Capabilities Message.
- *
- * The SourceCapabilityTimer Shall continue to run during
- * identity discover and Shall Not be initialized on re-entry
- * to PE_SRC_Discovery.
- *
- * Note: Cable identity is the only valid VDM to probe before a contract
- * is in place. All other probing must happen from ready states.
- */
- if (get_last_state_pe(port) != PE_VDM_IDENTITY_REQUEST_CBL)
- pd_timer_enable(port, PE_TIMER_SOURCE_CAP,
- PD_T_SEND_SOURCE_CAP);
-}
-
-static void pe_src_discovery_run(int port)
-{
- /*
- * Transition to the PE_SRC_Send_Capabilities state when:
- * 1) The SourceCapabilityTimer times out and
- * CapsCounter ≤ nCapsCount.
- *
- * Transition to the PE_SRC_Disabled state when:
- * 1) The Port Partners are not presently PD Connected
- * 2) And the SourceCapabilityTimer times out
- * 3) And CapsCounter > nCapsCount.
- *
- * Transition to the PE_SRC_VDM_Identity_request state when:
- * 1) DPM requests the identity of the cable plug and
- * 2) DiscoverIdentityCounter < nDiscoverIdentityCount
- */
- if (pd_timer_is_expired(port, PE_TIMER_SOURCE_CAP)) {
- if (pe[port].caps_counter <= N_CAPS_COUNT) {
- set_state_pe(port, PE_SRC_SEND_CAPABILITIES);
- return;
- } else if (!PE_CHK_FLAG(port, PE_FLAGS_PD_CONNECTION)) {
- set_state_pe(port, PE_SRC_DISABLED);
- return;
- }
- }
-
- /*
- * Note: While the DiscoverIdentityTimer is only required in an explicit
- * contract, we use it here to ensure we space any potential BUSY
- * requests properly.
- */
- if (pd_get_identity_discovery(port, TCPCI_MSG_SOP_PRIME) ==
- PD_DISC_NEEDED
- && pd_timer_is_expired(port, PE_TIMER_DISCOVER_IDENTITY)
- && pe_can_send_sop_prime(port)
- && (pe[port].discover_identity_counter <
- N_DISCOVER_IDENTITY_PRECONTRACT_LIMIT)) {
- pe[port].tx_type = TCPCI_MSG_SOP_PRIME;
- set_state_pe(port, PE_VDM_IDENTITY_REQUEST_CBL);
- return;
- }
-
- /*
- * Transition to the PE_SRC_Disabled state when:
- * 1) The Port Partners have not been PD Connected.
- * 2) And the NoResponseTimer times out.
- * 3) And the HardResetCounter > nHardResetCount.
- */
- if (!PE_CHK_FLAG(port, PE_FLAGS_PD_CONNECTION) &&
- pd_timer_is_expired(port, PE_TIMER_NO_RESPONSE) &&
- pe[port].hard_reset_counter > N_HARD_RESET_COUNT) {
- set_state_pe(port, PE_SRC_DISABLED);
- return;
- }
-}
-
-/**
- * PE_SRC_Send_Capabilities
- */
-static void pe_src_send_capabilities_entry(int port)
-{
- print_current_state(port);
-
- /* Send PD Capabilities message */
- send_source_cap(port);
- pe_sender_response_msg_entry(port);
-
- /* Increment CapsCounter */
- pe[port].caps_counter++;
-}
-
-static void pe_src_send_capabilities_run(int port)
-{
- enum pe_msg_check msg_check;
-
- /*
- * Check the state of the message sent
- */
- msg_check = pe_sender_response_msg_run(port);
-
- /*
- * Handle Discarded message
- * PE_SNK/SRC_READY if DPM_REQUEST
- * PE_SEND_SOFT_RESET otherwise
- */
- if (msg_check == PE_MSG_DPM_DISCARDED) {
- set_state_pe(port, PE_SRC_READY);
- return;
- } else if (msg_check == PE_MSG_DISCARDED) {
- pe_send_soft_reset(port, TCPCI_MSG_SOP);
- return;
- }
-
- /*
- * Handle message that was just sent
- */
- if (msg_check == PE_MSG_SEND_COMPLETED) {
- /*
- * If a GoodCRC Message is received then the Policy Engine
- * Shall:
- * 1) Stop the NoResponseTimer.
- * 2) Reset the HardResetCounter and CapsCounter to zero.
- * 3) Initialize and run the SenderResponseTimer.
- */
- /* Stop the NoResponseTimer */
- pd_timer_disable(port, PE_TIMER_NO_RESPONSE);
-
- /* Reset the HardResetCounter to zero */
- pe[port].hard_reset_counter = 0;
-
- /* Reset the CapsCounter to zero */
- pe[port].caps_counter = 0;
- }
-
- /*
- * Transition to the PE_SRC_Negotiate_Capability state when:
- * 1) A Request Message is received from the Sink
- */
- if ((msg_check & PE_MSG_SENT) &&
- PE_CHK_FLAG(port, PE_FLAGS_MSG_RECEIVED)) {
- PE_CLR_FLAG(port, PE_FLAGS_MSG_RECEIVED);
-
- /*
- * Request Message Received?
- */
- if (PD_HEADER_CNT(rx_emsg[port].header) > 0 &&
- PD_HEADER_TYPE(rx_emsg[port].header) ==
- PD_DATA_REQUEST) {
-
- /*
- * Set to highest revision supported by both
- * ports.
- */
- prl_set_rev(port, TCPCI_MSG_SOP,
- MIN(PD_REVISION, PD_HEADER_REV(rx_emsg[port].header)));
-
- set_cable_rev(port);
-
- /* We are PD connected */
- PE_SET_FLAG(port, PE_FLAGS_PD_CONNECTION);
- tc_pd_connection(port, 1);
-
- /*
- * Handle the Sink Request in
- * PE_SRC_Negotiate_Capability state
- */
- set_state_pe(port, PE_SRC_NEGOTIATE_CAPABILITY);
- return;
- }
-
- /*
- * We have a Protocol Error.
- * PE_SEND_SOFT_RESET
- */
- pe_send_soft_reset(port,
- PD_HEADER_GET_SOP(rx_emsg[port].header));
- return;
- }
-
- /*
- * Transition to the PE_SRC_Discovery state when:
- * 1) The Protocol Layer indicates that the Message has not been sent
- * and we are presently not Connected
- *
- * Send soft reset when:
- * 1) The Protocol Layer indicates that the Message has not been sent
- * and we are already Connected
- *
- * See section 8.3.3.4.1.1 PE_SRC_Send_Soft_Reset State and section
- * 8.3.3.2.3 PE_SRC_Send_Capabilities State.
- *
- * NOTE: The PE_FLAGS_PROTOCOL_ERROR is set if a GoodCRC Message
- * is not received.
- */
- if (PE_CHK_FLAG(port, PE_FLAGS_PROTOCOL_ERROR)) {
- PE_CLR_FLAG(port, PE_FLAGS_PROTOCOL_ERROR);
- if (!PE_CHK_FLAG(port, PE_FLAGS_PD_CONNECTION))
- set_state_pe(port, PE_SRC_DISCOVERY);
- else
- pe_send_soft_reset(port, TCPCI_MSG_SOP);
- return;
- }
-
- /*
- * Transition to the PE_SRC_Disabled state when:
- * 1) The Port Partners have not been PD Connected
- * 2) The NoResponseTimer times out
- * 3) And the HardResetCounter > nHardResetCount.
- *
- * Transition to the Error Recovery state when:
- * 1) The Port Partners have previously been PD Connected
- * 2) The NoResponseTimer times out
- * 3) And the HardResetCounter > nHardResetCount.
- */
- if (pd_timer_is_expired(port, PE_TIMER_NO_RESPONSE)) {
- if (pe[port].hard_reset_counter <= N_HARD_RESET_COUNT)
- set_state_pe(port, PE_SRC_HARD_RESET);
- else if (PE_CHK_FLAG(port, PE_FLAGS_PD_CONNECTION))
- set_state_pe(port, PE_WAIT_FOR_ERROR_RECOVERY);
- else
- set_state_pe(port, PE_SRC_DISABLED);
- return;
- }
-
- /*
- * Transition to the PE_SRC_Hard_Reset state when:
- * 1) The SenderResponseTimer times out.
- */
- if (pd_timer_is_expired(port, PE_TIMER_SENDER_RESPONSE)) {
- set_state_pe(port, PE_SRC_HARD_RESET);
- return;
- }
-}
-
-static void pe_src_send_capabilities_exit(int port)
-{
- pe_sender_response_msg_exit(port);
-}
-
-/**
- * PE_SRC_Negotiate_Capability
- */
-static void pe_src_negotiate_capability_entry(int port)
-{
- uint32_t payload;
-
- print_current_state(port);
-
- /* Get message payload */
- payload = *(uint32_t *)(&rx_emsg[port].buf);
-
- /*
- * Evaluate the Request from the Attached Sink
- */
-
- /*
- * Transition to the PE_SRC_Capability_Response state when:
- * 1) The Request cannot be met.
- * 2) Or the Request can be met later from the Power Reserve
- *
- * Transition to the PE_SRC_Transition_Supply state when:
- * 1) The Request can be met
- *
- */
- if (pd_check_requested_voltage(payload, port) != EC_SUCCESS) {
- set_state_pe(port, PE_SRC_CAPABILITY_RESPONSE);
- } else {
- PE_SET_FLAG(port, PE_FLAGS_ACCEPT);
- pe[port].requested_idx = RDO_POS(payload);
- set_state_pe(port, PE_SRC_TRANSITION_SUPPLY);
- }
-}
-
-/**
- * PE_SRC_Transition_Supply
- */
-static void pe_src_transition_supply_entry(int port)
-{
- print_current_state(port);
-
- /* Send a GotoMin Message or otherwise an Accept Message */
- if (PE_CHK_FLAG(port, PE_FLAGS_ACCEPT)) {
- PE_CLR_FLAG(port, PE_FLAGS_ACCEPT);
- send_ctrl_msg(port, TCPCI_MSG_SOP, PD_CTRL_ACCEPT);
- } else {
- send_ctrl_msg(port, TCPCI_MSG_SOP, PD_CTRL_GOTO_MIN);
- }
-}
-
-static void pe_src_transition_supply_run(int port)
-{
- /*
- * Transition to the PE_SRC_Ready state when:
- * 1) The power supply is ready.
- *
- * NOTE: This code block is executed twice:
- * First Pass)
- * When PE_FLAGS_TX_COMPLETE is set due to the
- * PD_CTRL_ACCEPT or PD_CTRL_GOTO_MIN messages
- * being sent.
- *
- * Second Pass)
- * When PE_FLAGS_TX_COMPLETE is set due to the
- * PD_CTRL_PS_RDY message being sent.
- */
- if (PE_CHK_FLAG(port, PE_FLAGS_TX_COMPLETE)) {
- PE_CLR_FLAG(port, PE_FLAGS_TX_COMPLETE);
-
- /*
- * NOTE: If a message was received,
- * pe_src_ready state will handle it.
- */
-
- if (PE_CHK_FLAG(port, PE_FLAGS_PS_READY)) {
- PE_CLR_FLAG(port, PE_FLAGS_PS_READY);
-
- /*
- * Set first message flag to trigger a wait and add
- * jitter delay when operating in PD2.0 mode. Skip
- * if we already have a contract.
- */
- if (!pe_is_explicit_contract(port)) {
- PE_SET_FLAG(port, PE_FLAGS_FIRST_MSG);
- pd_timer_disable(port,
- PE_TIMER_WAIT_AND_ADD_JITTER);
- }
-
- /* NOTE: Second pass through this code block */
- /* Explicit Contract is now in place */
- pe_set_explicit_contract(port);
-
- /*
- * Setup to get Device Policy Manager to request
- * Source Capabilities, if needed, for possible
- * PR_Swap. Get the number directly to avoid re-probing
- * if the partner generated an error and left -1 for the
- * count.
- */
- if (pe[port].src_cap_cnt == 0)
- pd_dpm_request(port, DPM_REQUEST_GET_SRC_CAPS);
-
- set_state_pe(port, PE_SRC_READY);
- } else {
- /* NOTE: First pass through this code block */
- /* Wait for tSrcTransition before changing supply. */
- pd_timer_enable(port, PE_TIMER_SRC_TRANSITION,
- PD_T_SRC_TRANSITION);
- }
-
- return;
- }
-
- if (pd_timer_is_expired(port, PE_TIMER_SRC_TRANSITION)) {
- pd_timer_disable(port, PE_TIMER_SRC_TRANSITION);
- /* Transition power supply and send PS_RDY. */
- pd_transition_voltage(pe[port].requested_idx);
- send_ctrl_msg(port, TCPCI_MSG_SOP, PD_CTRL_PS_RDY);
- PE_SET_FLAG(port, PE_FLAGS_PS_READY);
- }
-
- /*
- * Transition to the PE_SRC_Hard_Reset state when:
- * 1) A Protocol Error occurs.
- */
- if (PE_CHK_FLAG(port, PE_FLAGS_PROTOCOL_ERROR)) {
- PE_CLR_FLAG(port, PE_FLAGS_PROTOCOL_ERROR);
- set_state_pe(port, PE_SRC_HARD_RESET);
- }
-}
-
-static void pe_src_transition_supply_exit(int port)
-{
- pd_timer_disable(port, PE_TIMER_SRC_TRANSITION);
-}
-
-/*
- * Transitions state after receiving a Not Supported extended message. Under
- * appropriate conditions, transitions to a PE_{SRC,SNK}_Chunk_Received.
- */
-static void extended_message_not_supported(int port, uint32_t *payload)
-{
- uint16_t ext_header = GET_EXT_HEADER(*payload);
-
- if (IS_ENABLED(CONFIG_USB_PD_REV30) &&
- !IS_ENABLED(CONFIG_USB_PD_EXTENDED_MESSAGES) &&
- PD_EXT_HEADER_CHUNKED(ext_header) &&
- PD_EXT_HEADER_DATA_SIZE(ext_header) >
- PD_MAX_EXTENDED_MSG_CHUNK_LEN) {
- set_state_pe(port,
- pe[port].power_role == PD_ROLE_SOURCE ?
- PE_SRC_CHUNK_RECEIVED : PE_SNK_CHUNK_RECEIVED);
- return;
- }
-
- set_state_pe(port, PE_SEND_NOT_SUPPORTED);
-}
-
-/**
- * PE_SRC_Ready
- */
-static void pe_src_ready_entry(int port)
-{
- print_current_state(port);
-
- /* Ensure any message send flags are cleaned up */
- PE_CLR_FLAG(port, PE_FLAGS_READY_CLR);
-
- /* Clear DPM Current Request */
- pe[port].dpm_curr_request = 0;
-
- /*
- * Wait and add jitter if we are operating in PD2.0 mode and no messages
- * have been sent since enter this state.
- */
- pe_update_wait_and_add_jitter_timer(port);
-}
-
-static void pe_src_ready_run(int port)
-{
- /*
- * Handle incoming messages before discovery and DPMs other than hard
- * reset
- */
- if (PE_CHK_FLAG(port, PE_FLAGS_MSG_RECEIVED)) {
- uint8_t type = PD_HEADER_TYPE(rx_emsg[port].header);
- uint8_t cnt = PD_HEADER_CNT(rx_emsg[port].header);
- uint8_t ext = PD_HEADER_EXT(rx_emsg[port].header);
- uint32_t *payload = (uint32_t *)rx_emsg[port].buf;
-
- PE_CLR_FLAG(port, PE_FLAGS_MSG_RECEIVED);
-
- /* Extended Message Requests */
- if (ext > 0) {
- switch (type) {
-#if defined(CONFIG_USB_PD_EXTENDED_MESSAGES) && defined(CONFIG_BATTERY)
- case PD_EXT_GET_BATTERY_CAP:
- set_state_pe(port, PE_GIVE_BATTERY_CAP);
- break;
- case PD_EXT_GET_BATTERY_STATUS:
- set_state_pe(port, PE_GIVE_BATTERY_STATUS);
- break;
-#endif /* CONFIG_USB_PD_EXTENDED_MESSAGES && CONFIG_BATTERY */
- default:
- extended_message_not_supported(port, payload);
- }
- return;
- }
- /* Data Message Requests */
- else if (cnt > 0) {
- switch (type) {
- case PD_DATA_REQUEST:
- set_state_pe(port, PE_SRC_NEGOTIATE_CAPABILITY);
- return;
- case PD_DATA_SINK_CAP:
- break;
- case PD_DATA_VENDOR_DEF:
- if (PD_HEADER_TYPE(rx_emsg[port].header) ==
- PD_DATA_VENDOR_DEF) {
- if (PD_VDO_SVDM(*payload)) {
- set_state_pe(port,
- PE_VDM_RESPONSE);
- } else
- set_state_pe(port,
- PE_HANDLE_CUSTOM_VDM_REQUEST);
- }
- return;
- case PD_DATA_BIST:
- set_state_pe(port, PE_BIST_TX);
- return;
- default:
- set_state_pe(port, PE_SEND_NOT_SUPPORTED);
- return;
- }
- }
- /* Control Message Requests */
- else {
- switch (type) {
- case PD_CTRL_GOOD_CRC:
- break;
- case PD_CTRL_NOT_SUPPORTED:
- break;
- case PD_CTRL_PING:
- break;
- case PD_CTRL_GET_SOURCE_CAP:
- set_state_pe(port, PE_SRC_SEND_CAPABILITIES);
- return;
- case PD_CTRL_GET_SINK_CAP:
- set_state_pe(port, PE_SNK_GIVE_SINK_CAP);
- return;
- case PD_CTRL_GOTO_MIN:
- break;
- case PD_CTRL_PR_SWAP:
- set_state_pe(port,
- PE_PRS_SRC_SNK_EVALUATE_SWAP);
- return;
- case PD_CTRL_DR_SWAP:
- if (PE_CHK_FLAG(port,
- PE_FLAGS_MODAL_OPERATION)) {
- set_state_pe(port, PE_SRC_HARD_RESET);
- return;
- }
-
- set_state_pe(port, PE_DRS_EVALUATE_SWAP);
- return;
- case PD_CTRL_VCONN_SWAP:
- if (IS_ENABLED(CONFIG_USBC_VCONN))
- set_state_pe(port,
- PE_VCS_EVALUATE_SWAP);
- else
- set_state_pe(port,
- PE_SEND_NOT_SUPPORTED);
- return;
- /*
- * USB PD 3.0 6.8.1:
- * Receiving an unexpected message shall be responded
- * to with a soft reset message.
- */
- case PD_CTRL_ACCEPT:
- case PD_CTRL_REJECT:
- case PD_CTRL_WAIT:
- case PD_CTRL_PS_RDY:
- pe_send_soft_reset(port,
- PD_HEADER_GET_SOP(rx_emsg[port].header));
- return;
- /*
- * Receiving an unknown or unsupported message
- * shall be responded to with a not supported message.
- */
- default:
- set_state_pe(port, PE_SEND_NOT_SUPPORTED);
- return;
- }
- }
- }
-
- /*
- * Make sure the PRL layer isn't busy with receiving or transmitting
- * chunked messages before attempting to transmit a new message.
- */
- if (prl_is_busy(port))
- return;
-
- if (PE_CHK_FLAG(port, PE_FLAGS_VDM_REQUEST_CONTINUE)) {
- PE_CLR_FLAG(port, PE_FLAGS_VDM_REQUEST_CONTINUE);
- set_state_pe(port, PE_VDM_REQUEST_DPM);
- return;
- }
-
- if (PE_CHK_FLAG(port, PE_FLAGS_WAITING_PR_SWAP) &&
- pd_timer_is_expired(port, PE_TIMER_PR_SWAP_WAIT)) {
- PE_CLR_FLAG(port, PE_FLAGS_WAITING_PR_SWAP);
- PE_SET_DPM_REQUEST(port, DPM_REQUEST_PR_SWAP);
- }
-
- if (pd_timer_is_disabled(port, PE_TIMER_WAIT_AND_ADD_JITTER) ||
- pd_timer_is_expired(port, PE_TIMER_WAIT_AND_ADD_JITTER)) {
-
- PE_CLR_FLAG(port, PE_FLAGS_FIRST_MSG);
- pd_timer_disable(port, PE_TIMER_WAIT_AND_ADD_JITTER);
-
- /*
- * Handle Device Policy Manager Requests
- */
- if (source_dpm_requests(port))
- return;
-
- /*
- * Attempt discovery if possible, and return if state was
- * changed for that discovery.
- */
- if (pe_attempt_port_discovery(port))
- return;
-
- /* No DPM requests; attempt mode entry/exit if needed */
- dpm_run(port);
- }
-}
-
-/**
- * PE_SRC_Disabled
- */
-static void pe_src_disabled_entry(int port)
-{
- print_current_state(port);
-
- if ((get_usb_pd_cable_type(port) == IDH_PTYPE_VPD) &&
- is_vpd_ct_supported(port)) {
- /*
- * Inform the Device Policy Manager that a Charge-Through VCONN
- * Powered Device was detected.
- */
- tc_ctvpd_detected(port);
- }
-
- if (pd_get_power_role(port) == PD_ROLE_SOURCE)
- dpm_add_non_pd_sink(port);
-
- /*
- * Unresponsive to USB Power Delivery messaging, but not to Hard Reset
- * Signaling. See pe_got_hard_reset
- */
-}
-
-/**
- * PE_SRC_Capability_Response
- */
-static void pe_src_capability_response_entry(int port)
-{
- print_current_state(port);
-
- /* NOTE: Wait messaging should be implemented. */
-
- send_ctrl_msg(port, TCPCI_MSG_SOP, PD_CTRL_REJECT);
-}
-
-static void pe_src_capability_response_run(int port)
-{
- /*
- * Transition to the PE_SRC_Ready state when:
- * 1) There is an Explicit Contract and
- * 2) A Reject Message has been sent and the present Contract is still
- * Valid or
- * 3) A Wait Message has been sent.
- *
- * Transition to the PE_SRC_Hard_Reset state when:
- * 1) There is an Explicit Contract and
- * 2) The Reject Message has been sent and the present
- * Contract is Invalid
- *
- * Transition to the PE_SRC_Wait_New_Capabilities state when:
- * 1) There is no Explicit Contract and
- * 2) A Reject Message has been sent or
- * 3) A Wait Message has been sent.
- */
- if (PE_CHK_FLAG(port, PE_FLAGS_TX_COMPLETE)) {
- PE_CLR_FLAG(port, PE_FLAGS_TX_COMPLETE);
-
- if (PE_CHK_FLAG(port, PE_FLAGS_EXPLICIT_CONTRACT))
- /*
- * NOTE: The src capabilities listed in
- * board/xxx/usb_pd_policy.c will not
- * change so the present contract will
- * never be invalid.
- */
- set_state_pe(port, PE_SRC_READY);
- else
- /*
- * NOTE: The src capabilities listed in
- * board/xxx/usb_pd_policy.c will not
- * change, so no need to resending them
- * again. Transition to disabled state.
- */
- set_state_pe(port, PE_SRC_DISABLED);
- }
-}
-
-/**
- * PE_SRC_Hard_Reset
- */
-static void pe_src_hard_reset_entry(int port)
-{
- print_current_state(port);
-
- /* Generate Hard Reset Signal */
- prl_execute_hard_reset(port);
-
- /* Increment the HardResetCounter */
- pe[port].hard_reset_counter++;
-
- /* Start NoResponseTimer */
- pd_timer_enable(port, PE_TIMER_NO_RESPONSE, PD_T_NO_RESPONSE);
-
- /* Start PSHardResetTimer */
- pd_timer_enable(port, PE_TIMER_PS_HARD_RESET, PD_T_PS_HARD_RESET);
-
- /* Clear error flags */
- PE_CLR_FLAG(port, PE_FLAGS_VDM_REQUEST_NAKED |
- PE_FLAGS_PROTOCOL_ERROR |
- PE_FLAGS_VDM_REQUEST_BUSY);
-}
-
-static void pe_src_hard_reset_run(int port)
-{
- /*
- * Transition to the PE_SRC_Transition_to_default state when:
- * 1) The PSHardResetTimer times out.
- */
- if (pd_timer_is_expired(port, PE_TIMER_PS_HARD_RESET))
- set_state_pe(port, PE_SRC_TRANSITION_TO_DEFAULT);
-}
-
-static void pe_src_hard_reset_exit(int port)
-{
- pd_timer_disable(port, PE_TIMER_PS_HARD_RESET);
-}
-
-/**
- * PE_SRC_Hard_Reset_Received
- */
-static void pe_src_hard_reset_received_entry(int port)
-{
- print_current_state(port);
-
- /* Start NoResponseTimer */
- pd_timer_enable(port, PE_TIMER_NO_RESPONSE, PD_T_NO_RESPONSE);
-
- /* Start PSHardResetTimer */
- pd_timer_enable(port, PE_TIMER_PS_HARD_RESET, PD_T_PS_HARD_RESET);
-}
-
-static void pe_src_hard_reset_received_run(int port)
-{
- /*
- * Transition to the PE_SRC_Transition_to_default state when:
- * 1) The PSHardResetTimer times out.
- */
- if (pd_timer_is_expired(port, PE_TIMER_PS_HARD_RESET))
- set_state_pe(port, PE_SRC_TRANSITION_TO_DEFAULT);
-}
-
-static void pe_src_hard_reset_received_exit(int port)
-{
- pd_timer_disable(port, PE_TIMER_PS_HARD_RESET);
-}
-
-/**
- * PE_SRC_Transition_To_Default
- */
-static void pe_src_transition_to_default_entry(int port)
-{
- print_current_state(port);
-
- /* Reset flags */
- pe[port].flags = 0;
-
- /* Reset DPM Request */
- pe[port].dpm_request = 0;
-
- /*
- * Request Device Policy Manager to request power
- * supply Hard Resets to vSafe5V via vSafe0V
- * Reset local HW
- * Request Device Policy Manager to set Port Data
- * Role to DFP and turn off VCONN
- */
- tc_hard_reset_request(port);
-}
-
-static void pe_src_transition_to_default_run(int port)
-{
- /*
- * Transition to the PE_SRC_Startup state when:
- * 1) The power supply has reached the default level.
- */
- if (PE_CHK_FLAG(port, PE_FLAGS_PS_RESET_COMPLETE)) {
- PE_CLR_FLAG(port, PE_FLAGS_PS_RESET_COMPLETE);
- /* Inform the Protocol Layer that the Hard Reset is complete */
- prl_hard_reset_complete(port);
- set_state_pe(port, PE_SRC_STARTUP);
- }
-}
-
-/**
- * PE_SNK_Startup State
- */
-static void pe_snk_startup_entry(int port)
-{
- print_current_state(port);
-
- /* Reset the protocol layer */
- prl_reset_soft(port);
-
- /* Set initial data role */
- pe[port].data_role = pd_get_data_role(port);
-
- /* Set initial power role */
- pe[port].power_role = PD_ROLE_SINK;
-
- /* Invalidate explicit contract */
- pe_invalidate_explicit_contract(port);
-
- if (PE_CHK_FLAG(port, PE_FLAGS_PR_SWAP_COMPLETE)) {
- PE_CLR_FLAG(port, PE_FLAGS_PR_SWAP_COMPLETE);
- /*
- * Protocol layer reset clears the message IDs for all SOP
- * types. Indicate that a SOP' soft reset is required before any
- * other messages are sent to the cable.
- *
- * Note that other paths into this state are for the initial
- * connection and for a hard reset. In both cases the cable
- * should also automatically clear the message IDs so don't
- * generate an SOP' soft reset for those cases. Sending
- * unnecessary SOP' soft resets causes bad behavior with
- * some devices. See b/179325862.
- */
- pd_dpm_request(port, DPM_REQUEST_SOP_PRIME_SOFT_RESET_SEND);
-
- /*
- * Some port partners may violate spec and attempt to
- * communicate with the cable after power role swaps, despite
- * not being Vconn source. Disable our SOP' receiving here to
- * avoid GoodCRC-ing any erroneous cable probes, and re-enable
- * after our contract is in place.
- */
- if (tc_is_vconn_src(port))
- tcpm_sop_prime_enable(port, false);
-
- dpm_remove_sink(port);
- } else {
- /*
- * Set DiscoverIdentityTimer to trigger when we enter
- * snk_ready for the first time.
- */
- pd_timer_enable(port, PE_TIMER_DISCOVER_IDENTITY, 0);
-
- /* Clear port discovery/mode flags */
- pd_dfp_discovery_init(port);
- pd_dfp_mode_init(port);
- pe[port].discover_identity_counter = 0;
-
- /* Reset dr swap attempt counter */
- pe[port].dr_swap_attempt_counter = 0;
-
- /* Reset VCONN swap counter */
- pe[port].vconn_swap_counter = 0;
- /*
- * TODO: POLICY decision:
- * Mark that we'd like to try being Vconn source and DFP
- */
- PE_SET_FLAG(port, PE_FLAGS_DR_SWAP_TO_DFP);
- PE_SET_FLAG(port, PE_FLAGS_VCONN_SWAP_TO_ON);
- }
-
- /*
- * Request sink caps for FRS, output power consideration, or reporting
- * to the AP through host commands.
- *
- * On entry to the PE_SNK_Ready state if the Sink supports Fast Role
- * Swap, then the Policy Engine Shall do the following:
- * - Send a Get_Sink_Cap Message
- */
- if (IS_ENABLED(CONFIG_USB_PD_HOST_CMD) ||
- CONFIG_USB_PD_3A_PORTS > 0 ||
- IS_ENABLED(CONFIG_USB_PD_FRS))
- pd_dpm_request(port, DPM_REQUEST_GET_SNK_CAPS);
-
-}
-
-static void pe_snk_startup_run(int port)
-{
- /* Wait until protocol layer is running */
- if (!prl_is_running(port))
- return;
-
- /*
- * Once the reset process completes, the Policy Engine Shall
- * transition to the PE_SNK_Discovery state
- */
- set_state_pe(port, PE_SNK_DISCOVERY);
-}
-
-/**
- * PE_SNK_Discovery State
- */
-static void pe_snk_discovery_entry(int port)
-{
- print_current_state(port);
-}
-
-static void pe_snk_discovery_run(int port)
-{
- /*
- * Transition to the PE_SNK_Wait_for_Capabilities state when:
- * 1) VBUS has been detected
- */
- if (!pd_check_vbus_level(port, VBUS_REMOVED))
- set_state_pe(port, PE_SNK_WAIT_FOR_CAPABILITIES);
-}
-
-/**
- * PE_SNK_Wait_For_Capabilities State
- */
-static void pe_snk_wait_for_capabilities_entry(int port)
-{
- print_current_state(port);
-
- /* Initialize and start the SinkWaitCapTimer */
- pd_timer_enable(port, PE_TIMER_TIMEOUT, PD_T_SINK_WAIT_CAP);
-}
-
-static void pe_snk_wait_for_capabilities_run(int port)
-{
- uint8_t type;
- uint8_t cnt;
- uint8_t ext;
-
- /*
- * Transition to the PE_SNK_Evaluate_Capability state when:
- * 1) A Source_Capabilities Message is received.
- */
- if (PE_CHK_FLAG(port, PE_FLAGS_MSG_RECEIVED)) {
- PE_CLR_FLAG(port, PE_FLAGS_MSG_RECEIVED);
-
- type = PD_HEADER_TYPE(rx_emsg[port].header);
- cnt = PD_HEADER_CNT(rx_emsg[port].header);
- ext = PD_HEADER_EXT(rx_emsg[port].header);
-
- if ((ext == 0) && (cnt > 0) && (type == PD_DATA_SOURCE_CAP)) {
- set_state_pe(port, PE_SNK_EVALUATE_CAPABILITY);
- return;
- }
- }
-
- /* When the SinkWaitCapTimer times out, perform a Hard Reset. */
- if (pd_timer_is_expired(port, PE_TIMER_TIMEOUT)) {
- PE_SET_FLAG(port, PE_FLAGS_SNK_WAIT_CAP_TIMEOUT);
- set_state_pe(port, PE_SNK_HARD_RESET);
- }
-}
-
-static void pe_snk_wait_for_capabilities_exit(int port)
-{
- pd_timer_disable(port, PE_TIMER_TIMEOUT);
-}
-
-/**
- * PE_SNK_Evaluate_Capability State
- */
-static void pe_snk_evaluate_capability_entry(int port)
-{
- uint32_t *pdo = (uint32_t *)rx_emsg[port].buf;
- uint32_t num = rx_emsg[port].len >> 2;
-
- print_current_state(port);
-
- /* Reset Hard Reset counter to zero */
- pe[port].hard_reset_counter = 0;
-
- /* Set to highest revision supported by both ports. */
- prl_set_rev(port, TCPCI_MSG_SOP,
- MIN(PD_REVISION, PD_HEADER_REV(rx_emsg[port].header)));
-
- set_cable_rev(port);
-
- /* Parse source caps if they have changed */
- if (pe[port].src_cap_cnt != num ||
- memcmp(pdo, pe[port].src_caps, num << 2)) {
- /*
- * If port policy preference is to be a power role source,
- * then request a power role swap. If we'd previously queued a
- * PR swap but can now charge from this device, clear it.
- */
- if (!pd_can_charge_from_device(port, num, pdo))
- pd_request_power_swap(port);
- else
- PE_CLR_DPM_REQUEST(port, DPM_REQUEST_PR_SWAP);
- }
-
- pe_update_src_pdo_flags(port, num, pdo);
- pd_set_src_caps(port, num, pdo);
-
- /* Evaluate the options based on supplied capabilities */
- pd_process_source_cap(port, pe[port].src_cap_cnt, pe[port].src_caps);
-
- /* Device Policy Response Received */
- set_state_pe(port, PE_SNK_SELECT_CAPABILITY);
-
-#ifdef HAS_TASK_DPS
- /* Wake DPS task to evaluate the SrcCaps */
- task_wake(TASK_ID_DPS);
-#endif
-}
-
-/**
- * PE_SNK_Select_Capability State
- */
-static void pe_snk_select_capability_entry(int port)
-{
- print_current_state(port);
-
- /* Send Request */
- pe_send_request_msg(port);
- pe_sender_response_msg_entry(port);
-
- /* We are PD Connected */
- PE_SET_FLAG(port, PE_FLAGS_PD_CONNECTION);
- tc_pd_connection(port, 1);
-}
-
-static void pe_snk_select_capability_run(int port)
-{
- uint8_t type;
- uint8_t cnt;
- enum tcpci_msg_type sop;
- enum pe_msg_check msg_check;
-
- /*
- * Check the state of the message sent
- */
- msg_check = pe_sender_response_msg_run(port);
-
- /*
- * Handle discarded message
- */
- if (msg_check & PE_MSG_DISCARDED) {
- /*
- * The sent REQUEST message was discarded. This can be at
- * the start of an AMS or in the middle. Handle what to
- * do based on where we came from.
- * 1) SE_SNK_EVALUATE_CAPABILITY: sends SoftReset
- * 2) SE_SNK_READY: goes back to SNK Ready
- */
- if (get_last_state_pe(port) == PE_SNK_EVALUATE_CAPABILITY)
- pe_send_soft_reset(port, TCPCI_MSG_SOP);
- else
- set_state_pe(port, PE_SNK_READY);
- return;
- }
-
- if ((msg_check & PE_MSG_SENT) &&
- PE_CHK_FLAG(port, PE_FLAGS_MSG_RECEIVED)) {
- PE_CLR_FLAG(port, PE_FLAGS_MSG_RECEIVED);
- type = PD_HEADER_TYPE(rx_emsg[port].header);
- cnt = PD_HEADER_CNT(rx_emsg[port].header);
- sop = PD_HEADER_GET_SOP(rx_emsg[port].header);
-
- /*
- * Transition to the PE_SNK_Transition_Sink state when:
- * 1) An Accept Message is received from the Source.
- *
- * Transition to the PE_SNK_Wait_for_Capabilities state when:
- * 1) There is no Explicit Contract in place and
- * 2) A Reject Message is received from the Source or
- * 3) A Wait Message is received from the Source.
- *
- * Transition to the PE_SNK_Ready state when:
- * 1) There is an Explicit Contract in place and
- * 2) A Reject Message is received from the Source or
- * 3) A Wait Message is received from the Source.
- *
- * Transition to the PE_SNK_Hard_Reset state when:
- * 1) A SenderResponseTimer timeout occurs.
- */
-
- /* Only look at control messages */
- if (cnt == 0) {
- /*
- * Accept Message Received
- */
- if (type == PD_CTRL_ACCEPT) {
- /* explicit contract is now in place */
- pe_set_explicit_contract(port);
-
- set_state_pe(port, PE_SNK_TRANSITION_SINK);
-
- return;
- }
- /*
- * Reject or Wait Message Received
- */
- else if (type == PD_CTRL_REJECT ||
- type == PD_CTRL_WAIT) {
- if (type == PD_CTRL_WAIT)
- PE_SET_FLAG(port, PE_FLAGS_WAIT);
-
- pd_timer_disable(port, PE_TIMER_SINK_REQUEST);
-
- /*
- * We had a previous explicit contract, so
- * transition to PE_SNK_Ready
- */
- if (PE_CHK_FLAG(port,
- PE_FLAGS_EXPLICIT_CONTRACT))
- set_state_pe(port, PE_SNK_READY);
- /*
- * No previous explicit contract, so transition
- * to PE_SNK_Wait_For_Capabilities
- */
- else
- set_state_pe(port,
- PE_SNK_WAIT_FOR_CAPABILITIES);
- return;
- }
- /*
- * Unexpected Control Message Received
- */
- else {
- /* Send Soft Reset */
- pe_send_soft_reset(port, sop);
- return;
- }
- }
- /*
- * Unexpected Data Message
- */
- else {
- /* Send Soft Reset */
- pe_send_soft_reset(port, sop);
- return;
- }
- }
-
- /* SenderResponsetimer timeout */
- if (pd_timer_is_expired(port, PE_TIMER_SENDER_RESPONSE))
- set_state_pe(port, PE_SNK_HARD_RESET);
-}
-
-void pe_snk_select_capability_exit(int port)
-{
- pe_sender_response_msg_exit(port);
-}
-
-/**
- * PE_SNK_Transition_Sink State
- */
-static void pe_snk_transition_sink_entry(int port)
-{
- print_current_state(port);
-
- /* Initialize and run PSTransitionTimer */
- pd_timer_enable(port, PE_TIMER_PS_TRANSITION, PD_T_PS_TRANSITION);
-}
-
-static void pe_snk_transition_sink_run(int port)
-{
- /*
- * Transition to the PE_SNK_Ready state when:
- * 1) A PS_RDY Message is received from the Source.
- *
- * Transition to the PE_SNK_Hard_Reset state when:
- * 1) A Protocol Error occurs.
- */
-
- if (PE_CHK_FLAG(port, PE_FLAGS_MSG_RECEIVED)) {
- PE_CLR_FLAG(port, PE_FLAGS_MSG_RECEIVED);
-
- /*
- * PS_RDY message received
- */
- if ((PD_HEADER_CNT(rx_emsg[port].header) == 0) &&
- (PD_HEADER_TYPE(rx_emsg[port].header) ==
- PD_CTRL_PS_RDY)) {
- /*
- * Set first message flag to trigger a wait and add
- * jitter delay when operating in PD2.0 mode.
- */
- PE_SET_FLAG(port, PE_FLAGS_FIRST_MSG);
- pd_timer_disable(port, PE_TIMER_WAIT_AND_ADD_JITTER);
-
- /*
- * If we've successfully completed our new power
- * contract, ensure SOP' communication is enabled before
- * entering PE_SNK_READY. It may have been disabled
- * during a power role swap to avoid interoperability
- * issues with out-of-spec partners.
- */
- if (tc_is_vconn_src(port))
- tcpm_sop_prime_enable(port, true);
-
- /*
- * Evaluate port's sink caps for FRS current, if
- * already available
- */
- if (pd_get_snk_cap_cnt(port) > 0)
- dpm_evaluate_sink_fixed_pdo(port,
- *pd_get_snk_caps(port));
-
- set_state_pe(port, PE_SNK_READY);
- } else {
- /*
- * Protocol Error
- */
- set_state_pe(port, PE_SNK_HARD_RESET);
- }
- return;
- }
-
- /*
- * Timeout will lead to a Hard Reset
- */
- if (pd_timer_is_expired(port, PE_TIMER_PS_TRANSITION) &&
- pe[port].hard_reset_counter <= N_HARD_RESET_COUNT) {
- PE_SET_FLAG(port, PE_FLAGS_PS_TRANSITION_TIMEOUT);
-
- set_state_pe(port, PE_SNK_HARD_RESET);
- }
-}
-
-static void pe_snk_transition_sink_exit(int port)
-{
- /* Transition Sink's power supply to the new power level */
- pd_set_input_current_limit(port,
- pe[port].curr_limit, pe[port].supply_voltage);
-
- if (IS_ENABLED(CONFIG_CHARGE_MANAGER))
- /* Set ceiling based on what's negotiated */
- charge_manager_set_ceil(port,
- CEIL_REQUESTOR_PD, pe[port].curr_limit);
-
- pd_timer_disable(port, PE_TIMER_PS_TRANSITION);
-
- if (IS_ENABLED(CONFIG_USB_PD_DPS))
- if (charge_manager_get_active_charge_port() == port)
- dps_update_stabilized_time(port);
-}
-
-
-/**
- * PE_SNK_Ready State
- */
-static void pe_snk_ready_entry(int port)
-{
- print_current_state(port);
-
- /* Ensure any message send flags are cleaned up */
- PE_CLR_FLAG(port, PE_FLAGS_READY_CLR);
-
- /* Clear DPM Current Request */
- pe[port].dpm_curr_request = 0;
-
- /*
- * On entry to the PE_SNK_Ready state as the result of a wait,
- * then do the following:
- * 1) Initialize and run the SinkRequestTimer
- */
- if (PE_CHK_FLAG(port, PE_FLAGS_WAIT)) {
- PE_CLR_FLAG(port, PE_FLAGS_WAIT);
- pd_timer_enable(port, PE_TIMER_SINK_REQUEST,
- PD_T_SINK_REQUEST);
- }
-
- /*
- * Wait and add jitter if we are operating in PD2.0 mode and no messages
- * have been sent since enter this state.
- */
- pe_update_wait_and_add_jitter_timer(port);
-}
-
-static void pe_snk_ready_run(int port)
-{
- /*
- * Handle incoming messages before discovery and DPMs other than hard
- * reset
- */
- if (PE_CHK_FLAG(port, PE_FLAGS_MSG_RECEIVED)) {
- uint8_t type = PD_HEADER_TYPE(rx_emsg[port].header);
- uint8_t cnt = PD_HEADER_CNT(rx_emsg[port].header);
- uint8_t ext = PD_HEADER_EXT(rx_emsg[port].header);
- uint32_t *payload = (uint32_t *)rx_emsg[port].buf;
-
- PE_CLR_FLAG(port, PE_FLAGS_MSG_RECEIVED);
-
- /* Extended Message Request */
- if (ext > 0) {
- switch (type) {
-#if defined(CONFIG_USB_PD_EXTENDED_MESSAGES) && defined(CONFIG_BATTERY)
- case PD_EXT_GET_BATTERY_CAP:
- set_state_pe(port, PE_GIVE_BATTERY_CAP);
- break;
- case PD_EXT_GET_BATTERY_STATUS:
- set_state_pe(port, PE_GIVE_BATTERY_STATUS);
- break;
-#endif /* CONFIG_USB_PD_EXTENDED_MESSAGES && CONFIG_BATTERY */
- default:
- extended_message_not_supported(port, payload);
- }
- return;
- }
- /* Data Messages */
- else if (cnt > 0) {
- switch (type) {
- case PD_DATA_SOURCE_CAP:
- set_state_pe(port,
- PE_SNK_EVALUATE_CAPABILITY);
- break;
- case PD_DATA_VENDOR_DEF:
- if (PD_HEADER_TYPE(rx_emsg[port].header) ==
- PD_DATA_VENDOR_DEF) {
- if (PD_VDO_SVDM(*payload))
- set_state_pe(port,
- PE_VDM_RESPONSE);
- else
- set_state_pe(port,
- PE_HANDLE_CUSTOM_VDM_REQUEST);
- }
- break;
- case PD_DATA_BIST:
- set_state_pe(port, PE_BIST_TX);
- break;
- default:
- set_state_pe(port, PE_SEND_NOT_SUPPORTED);
- }
- return;
- }
- /* Control Messages */
- else {
- switch (type) {
- case PD_CTRL_GOOD_CRC:
- /* Do nothing */
- break;
- case PD_CTRL_PING:
- /* Do nothing */
- break;
- case PD_CTRL_GET_SOURCE_CAP:
- set_state_pe(port, PE_DR_SNK_GIVE_SOURCE_CAP);
- return;
- case PD_CTRL_GET_SINK_CAP:
- set_state_pe(port, PE_SNK_GIVE_SINK_CAP);
- return;
- case PD_CTRL_GOTO_MIN:
- set_state_pe(port, PE_SNK_TRANSITION_SINK);
- return;
- case PD_CTRL_PR_SWAP:
- set_state_pe(port,
- PE_PRS_SNK_SRC_EVALUATE_SWAP);
- return;
- case PD_CTRL_DR_SWAP:
- if (PE_CHK_FLAG(port, PE_FLAGS_MODAL_OPERATION))
- set_state_pe(port, PE_SNK_HARD_RESET);
- else
- set_state_pe(port,
- PE_DRS_EVALUATE_SWAP);
- return;
- case PD_CTRL_VCONN_SWAP:
- if (IS_ENABLED(CONFIG_USBC_VCONN))
- set_state_pe(port,
- PE_VCS_EVALUATE_SWAP);
- else
- set_state_pe(port,
- PE_SEND_NOT_SUPPORTED);
- return;
- case PD_CTRL_NOT_SUPPORTED:
- /* Do nothing */
- break;
- /*
- * USB PD 3.0 6.8.1:
- * Receiving an unexpected message shall be responded
- * to with a soft reset message.
- */
- case PD_CTRL_ACCEPT:
- case PD_CTRL_REJECT:
- case PD_CTRL_WAIT:
- case PD_CTRL_PS_RDY:
- pe_send_soft_reset(port,
- PD_HEADER_GET_SOP(rx_emsg[port].header));
- return;
- /*
- * Receiving an unknown or unsupported message
- * shall be responded to with a not supported message.
- */
- default:
- set_state_pe(port, PE_SEND_NOT_SUPPORTED);
- return;
- }
- }
- }
-
- /*
- * Make sure the PRL layer isn't busy with receiving or transmitting
- * chunked messages before attempting to transmit a new message.
- */
- if (prl_is_busy(port))
- return;
-
- if (PE_CHK_FLAG(port, PE_FLAGS_VDM_REQUEST_CONTINUE)) {
- PE_CLR_FLAG(port, PE_FLAGS_VDM_REQUEST_CONTINUE);
- set_state_pe(port, PE_VDM_REQUEST_DPM);
- return;
- }
-
- if (pd_timer_is_disabled(port, PE_TIMER_WAIT_AND_ADD_JITTER) ||
- pd_timer_is_expired(port, PE_TIMER_WAIT_AND_ADD_JITTER)) {
- PE_CLR_FLAG(port, PE_FLAGS_FIRST_MSG);
- pd_timer_disable(port, PE_TIMER_WAIT_AND_ADD_JITTER);
-
- if (pd_timer_is_expired(port, PE_TIMER_SINK_REQUEST)) {
- pd_timer_disable(port, PE_TIMER_SINK_REQUEST);
- set_state_pe(port, PE_SNK_SELECT_CAPABILITY);
- return;
- }
-
- /*
- * Handle Device Policy Manager Requests
- */
- if (sink_dpm_requests(port))
- return;
-
- /*
- * Attempt discovery if possible, and return if state was
- * changed for that discovery.
- */
- if (pe_attempt_port_discovery(port))
- return;
-
- /* No DPM requests; attempt mode entry/exit if needed */
- dpm_run(port);
-
- }
-}
-
-/**
- * PE_SNK_Hard_Reset
- */
-static void pe_snk_hard_reset_entry(int port)
-{
-#ifdef CONFIG_USB_PD_RESET_MIN_BATT_SOC
- int batt_soc;
-#endif
-
- print_current_state(port);
-
- /*
- * Note: If the SinkWaitCapTimer times out and the HardResetCounter is
- * greater than nHardResetCount the Sink Shall assume that the
- * Source is non-responsive.
- */
- if (PE_CHK_FLAG(port, PE_FLAGS_SNK_WAIT_CAP_TIMEOUT) &&
- pe[port].hard_reset_counter > N_HARD_RESET_COUNT) {
- set_state_pe(port, PE_SRC_DISABLED);
- return;
- }
-
- /*
- * If we're about to kill our active charge port and have no battery to
- * supply power, disable the PE layer instead. If we have no battery,
- * but we haven't determined our active charge port yet, also avoid
- * performing the HardReset. It might be that this port was our active
- * charge port.
- *
- * Note: On systems without batteries (ex. chromeboxes), it's preferable
- * to brown out rather than leave the port only semi-functional for a
- * customer. For systems which should have a battery, this condition is
- * not expected to be encountered by a customer.
- */
- if (IS_ENABLED(CONFIG_BATTERY) && (battery_is_present() == BP_NO) &&
- IS_ENABLED(CONFIG_CHARGE_MANAGER) &&
- ((port == charge_manager_get_active_charge_port() ||
- (charge_manager_get_active_charge_port() == CHARGE_PORT_NONE))) &&
- system_get_reset_flags() & EC_RESET_FLAG_SYSJUMP) {
- CPRINTS("C%d: Disabling port to avoid brown out, "
- "please reboot EC to enable port again", port);
- set_state_pe(port, PE_SRC_DISABLED);
- return;
-
- }
-
-#ifdef CONFIG_USB_PD_RESET_MIN_BATT_SOC
- /*
- * If the battery has not met a configured safe level for hard
- * resets, set state to PE_SRC_Disabled as a hard
- * reset could brown out the board.
- * Note this may mean that high-power chargers will stay at
- * 15W until a reset is sent, depending on boot timing.
- *
- * PE_FLAGS_SNK_WAITING_BATT flags will be cleared and
- * PE state will be switched to PE_SNK_Startup when
- * battery reaches CONFIG_USB_PD_RESET_MIN_BATT_SOC.
- * See pe_update_waiting_batt_flag() for more details.
- */
- batt_soc = usb_get_battery_soc();
-
- if (batt_soc < CONFIG_USB_PD_RESET_MIN_BATT_SOC ||
- battery_get_disconnect_state() != BATTERY_NOT_DISCONNECTED) {
- PE_SET_FLAG(port, PE_FLAGS_SNK_WAITING_BATT);
- CPRINTS("C%d: Battery low %d%%! Stay in disabled state " \
- "until battery level reaches %d%%", port, batt_soc,
- CONFIG_USB_PD_RESET_MIN_BATT_SOC);
- set_state_pe(port, PE_SRC_DISABLED);
- return;
- }
-#endif
-
- PE_CLR_FLAG(port, PE_FLAGS_SNK_WAIT_CAP_TIMEOUT |
- PE_FLAGS_VDM_REQUEST_NAKED |
- PE_FLAGS_PROTOCOL_ERROR |
- PE_FLAGS_VDM_REQUEST_BUSY);
-
- /* Request the generation of Hard Reset Signaling by the PHY Layer */
- prl_execute_hard_reset(port);
-
- /* Increment the HardResetCounter */
- pe[port].hard_reset_counter++;
-
- /*
- * Transition the Sink’s power supply to the new power level if
- * PSTransistionTimer timeout occurred.
- */
- if (PE_CHK_FLAG(port, PE_FLAGS_PS_TRANSITION_TIMEOUT)) {
- PE_CLR_FLAG(port, PE_FLAGS_PS_TRANSITION_TIMEOUT);
-
- /* Transition Sink's power supply to the new power level */
- pd_set_input_current_limit(port, pe[port].curr_limit,
- pe[port].supply_voltage);
- if (IS_ENABLED(CONFIG_CHARGE_MANAGER))
- /* Set ceiling based on what's negotiated */
- charge_manager_set_ceil(port, CEIL_REQUESTOR_PD,
- pe[port].curr_limit);
- }
-}
-
-static void pe_snk_hard_reset_run(int port)
-{
- /*
- * Transition to the PE_SNK_Transition_to_default state when:
- * 1) The Hard Reset is complete.
- */
- if (PE_CHK_FLAG(port, PE_FLAGS_HARD_RESET_PENDING))
- return;
-
- set_state_pe(port, PE_SNK_TRANSITION_TO_DEFAULT);
-}
-
-/**
- * PE_SNK_Transition_to_default
- */
-static void pe_snk_transition_to_default_entry(int port)
-{
- print_current_state(port);
-
- /* Reset flags */
- pe[port].flags = 0;
-
- /* Reset DPM Request */
- pe[port].dpm_request = 0;
-
- /* Inform the TC Layer of Hard Reset */
- tc_hard_reset_request(port);
-}
-
-static void pe_snk_transition_to_default_run(int port)
-{
- if (PE_CHK_FLAG(port, PE_FLAGS_PS_RESET_COMPLETE)) {
- PE_CLR_FLAG(port, PE_FLAGS_PS_RESET_COMPLETE);
- /* Inform the Protocol Layer that the Hard Reset is complete */
- prl_hard_reset_complete(port);
- set_state_pe(port, PE_SNK_STARTUP);
- }
-}
-
-/**
- * PE_SNK_Get_Source_Cap
- */
-static void pe_snk_get_source_cap_entry(int port)
-{
- print_current_state(port);
-
- /* Send a Get_Source_Cap Message */
- tx_emsg[port].len = 0;
- send_ctrl_msg(port, TCPCI_MSG_SOP, PD_CTRL_GET_SOURCE_CAP);
-}
-
-static void pe_snk_get_source_cap_run(int port)
-{
- if (PE_CHK_FLAG(port, PE_FLAGS_TX_COMPLETE)) {
- PE_CLR_FLAG(port, PE_FLAGS_TX_COMPLETE);
-
- set_state_pe(port, PE_SNK_READY);
- }
-}
-
-/**
- * PE_SNK_Send_Soft_Reset and PE_SRC_Send_Soft_Reset
- */
-static void pe_send_soft_reset_entry(int port)
-{
- print_current_state(port);
-
- /* Reset Protocol Layer (softly) */
- prl_reset_soft(port);
-
- pe_sender_response_msg_entry(port);
-
- /*
- * Mark the temporary timer PE_TIMER_TIMEOUT as expired to limit
- * to sending a single SoftReset message.
- */
- pd_timer_enable(port, PE_TIMER_TIMEOUT, 0);
-}
-
-static void pe_send_soft_reset_run(int port)
-{
- int type;
- int cnt;
- int ext;
- enum pe_msg_check msg_check;
-
- /* Wait until protocol layer is running */
- if (!prl_is_running(port))
- return;
-
- /*
- * Protocol layer is running, so need to send a single SoftReset.
- * Use temporary timer to act as a flag to keep this as a single
- * message send.
- */
- if (!pd_timer_is_disabled(port, PE_TIMER_TIMEOUT)) {
- pd_timer_disable(port, PE_TIMER_TIMEOUT);
-
- /*
- * TODO(b/150614211): Soft reset type should match
- * unexpected incoming message type
- */
- /* Send Soft Reset message */
- send_ctrl_msg(port,
- pe[port].soft_reset_sop, PD_CTRL_SOFT_RESET);
-
- return;
- }
-
- /*
- * Check the state of the message sent
- */
- msg_check = pe_sender_response_msg_run(port);
-
- /*
- * Handle discarded message
- */
- if (msg_check == PE_MSG_DISCARDED) {
- pe_set_ready_state(port);
- return;
- }
-
- /*
- * Transition to the PE_SNK_Send_Capabilities or
- * PE_SRC_Send_Capabilities state when:
- * 1) An Accept Message has been received.
- */
- if (msg_check == PE_MSG_SENT &&
- PE_CHK_FLAG(port, PE_FLAGS_MSG_RECEIVED)) {
- PE_CLR_FLAG(port, PE_FLAGS_MSG_RECEIVED);
-
- type = PD_HEADER_TYPE(rx_emsg[port].header);
- cnt = PD_HEADER_CNT(rx_emsg[port].header);
- ext = PD_HEADER_EXT(rx_emsg[port].header);
-
- if ((ext == 0) && (cnt == 0) && (type == PD_CTRL_ACCEPT)) {
- if (pe[port].power_role == PD_ROLE_SINK)
- set_state_pe(port,
- PE_SNK_WAIT_FOR_CAPABILITIES);
- else
- set_state_pe(port,
- PE_SRC_SEND_CAPABILITIES);
- return;
- }
- }
-
- /*
- * Transition to PE_SNK_Hard_Reset or PE_SRC_Hard_Reset on Sender
- * Response Timer Timeout or Protocol Layer or Protocol Error
- */
- if (pd_timer_is_expired(port, PE_TIMER_SENDER_RESPONSE) ||
- PE_CHK_FLAG(port, PE_FLAGS_PROTOCOL_ERROR)) {
- PE_CLR_FLAG(port, PE_FLAGS_PROTOCOL_ERROR);
-
- if (pe[port].power_role == PD_ROLE_SINK)
- set_state_pe(port, PE_SNK_HARD_RESET);
- else
- set_state_pe(port, PE_SRC_HARD_RESET);
- return;
- }
-}
-
-static void pe_send_soft_reset_exit(int port)
-{
- pe_sender_response_msg_exit(port);
- pd_timer_disable(port, PE_TIMER_TIMEOUT);
-}
-
-/**
- * PE_SNK_Soft_Reset and PE_SNK_Soft_Reset
- */
-static void pe_soft_reset_entry(int port)
-{
- print_current_state(port);
-
- send_ctrl_msg(port, TCPCI_MSG_SOP, PD_CTRL_ACCEPT);
-}
-
-static void pe_soft_reset_run(int port)
-{
- if (PE_CHK_FLAG(port, PE_FLAGS_TX_COMPLETE)) {
- PE_CLR_FLAG(port, PE_FLAGS_TX_COMPLETE);
-
- if (pe[port].power_role == PD_ROLE_SINK)
- set_state_pe(port, PE_SNK_WAIT_FOR_CAPABILITIES);
- else
- set_state_pe(port, PE_SRC_SEND_CAPABILITIES);
- } else if (PE_CHK_FLAG(port, PE_FLAGS_PROTOCOL_ERROR)) {
- PE_CLR_FLAG(port, PE_FLAGS_PROTOCOL_ERROR);
-
- if (pe[port].power_role == PD_ROLE_SINK)
- set_state_pe(port, PE_SNK_HARD_RESET);
- else
- set_state_pe(port, PE_SRC_HARD_RESET);
- }
-}
-
-/**
- * PE_SRC_Not_Supported and PE_SNK_Not_Supported
- *
- * 6.7.1 Soft Reset and Protocol Error (Revision 2.0, Version 1.3)
- * An unrecognized or unsupported Message (except for a Structured VDM),
- * received in the PE_SNK_Ready or PE_SRC_Ready states, Shall Not cause
- * a Soft_Reset Message to be generated but instead a Reject Message
- * Shall be generated.
- */
-static void pe_send_not_supported_entry(int port)
-{
- print_current_state(port);
-
- /* Request the Protocol Layer to send a Not_Supported Message. */
- if (prl_get_rev(port, TCPCI_MSG_SOP) > PD_REV20)
- send_ctrl_msg(port, TCPCI_MSG_SOP, PD_CTRL_NOT_SUPPORTED);
- else
- send_ctrl_msg(port, TCPCI_MSG_SOP, PD_CTRL_REJECT);
-}
-
-static void pe_send_not_supported_run(int port)
-{
- if (PE_CHK_FLAG(port, PE_FLAGS_TX_COMPLETE)) {
- PE_CLR_FLAG(port, PE_FLAGS_TX_COMPLETE);
- pe_set_ready_state(port);
-
- }
-}
-
-/**
- * PE_SRC_Chunk_Received and PE_SNK_Chunk_Received
- *
- * 6.11.2.1.1 Architecture of Device Including Chunking Layer (Revision 3.0,
- * Version 2.0): If a PD Device or Cable Marker has no requirement to handle any
- * message requiring more than one Chunk of any Extended Message, it May omit
- * the Chunking Layer. In this case it Shall implement the
- * ChunkingNotSupportedTimer to ensure compatible operation with partners which
- * support Chunking.
- *
- * See also:
- * 6.6.18.1 ChunkingNotSupportedTimer
- * 8.3.3.6 Not Supported Message State Diagrams
- */
-__maybe_unused static void pe_chunk_received_entry(int port)
-{
- if (!IS_ENABLED(CONFIG_USB_PD_REV30) ||
- IS_ENABLED(CONFIG_USB_PD_EXTENDED_MESSAGES))
- assert(0);
-
- print_current_state(port);
- pd_timer_enable(port, PE_TIMER_CHUNKING_NOT_SUPPORTED,
- PD_T_CHUNKING_NOT_SUPPORTED);
-}
-
-__maybe_unused static void pe_chunk_received_run(int port)
-{
- if (!IS_ENABLED(CONFIG_USB_PD_REV30) ||
- IS_ENABLED(CONFIG_USB_PD_EXTENDED_MESSAGES))
- assert(0);
-
- if (pd_timer_is_expired(port, PE_TIMER_CHUNKING_NOT_SUPPORTED))
- set_state_pe(port, PE_SEND_NOT_SUPPORTED);
-}
-
-__maybe_unused static void pe_chunk_received_exit(int port)
-{
- pd_timer_disable(port, PE_TIMER_CHUNKING_NOT_SUPPORTED);
-}
-
-/**
- * PE_SRC_Ping
- */
-static void pe_src_ping_entry(int port)
-{
- print_current_state(port);
- send_ctrl_msg(port, TCPCI_MSG_SOP, PD_CTRL_PING);
-}
-
-static void pe_src_ping_run(int port)
-{
- if (PE_CHK_FLAG(port, PE_FLAGS_TX_COMPLETE)) {
- PE_CLR_FLAG(port, PE_FLAGS_TX_COMPLETE);
- set_state_pe(port, PE_SRC_READY);
- }
-}
-
-#ifdef CONFIG_USB_PD_EXTENDED_MESSAGES
-/**
- * PE_Give_Battery_Cap
- */
-static void pe_give_battery_cap_entry(int port)
-{
- uint8_t *payload = rx_emsg[port].buf;
- uint16_t *msg = (uint16_t *)tx_emsg[port].buf;
-
- if (!IS_ENABLED(CONFIG_BATTERY))
- return;
- print_current_state(port);
-
- /* Set VID */
- msg[BCDB_VID] = USB_VID_GOOGLE;
-
- /* Set PID */
- msg[BCDB_PID] = CONFIG_USB_PID;
-
- if (battery_is_present()) {
- /*
- * We only have one fixed battery,
- * so make sure batt cap ref is 0.
- * This value is the first byte after the headers.
- */
- if (payload[0] != 0) {
- /* Invalid battery reference */
- msg[BCDB_DESIGN_CAP] = 0;
- msg[BCDB_FULL_CAP] = 0;
- /* Set invalid battery bit in response bit 0, byte 8 */
- msg[BCDB_BATT_TYPE] = 1;
- } else {
- /*
- * The Battery Design Capacity field shall return the
- * Battery’s design capacity in tenths of Wh. If the
- * Battery is Hot Swappable and is not present, the
- * Battery Design Capacity field shall be set to 0. If
- * the Battery is unable to report its Design Capacity,
- * it shall return 0xFFFF
- */
- msg[BCDB_DESIGN_CAP] = 0xffff;
-
- /*
- * The Battery Last Full Charge Capacity field shall
- * return the Battery’s last full charge capacity in
- * tenths of Wh. If the Battery is Hot Swappable and
- * is not present, the Battery Last Full Charge Capacity
- * field shall be set to 0. If the Battery is unable to
- * report its Design Capacity, the Battery Last Full
- * Charge Capacity field shall be set to 0xFFFF.
- */
- msg[BCDB_FULL_CAP] = 0xffff;
-
-
- if (IS_ENABLED(HAS_TASK_HOSTCMD) &&
- *host_get_memmap(EC_MEMMAP_BATTERY_VERSION) != 0) {
- int design_volt, design_cap, full_cap;
-
- design_volt = *(int *)host_get_memmap(
- EC_MEMMAP_BATT_DVLT);
- design_cap = *(int *)host_get_memmap(
- EC_MEMMAP_BATT_DCAP);
- full_cap = *(int *)host_get_memmap(
- EC_MEMMAP_BATT_LFCC);
-
- /*
- * Wh = (c * v) / 1000000
- * 10th of a Wh = Wh * 10
- */
- msg[BCDB_DESIGN_CAP] = DIV_ROUND_NEAREST(
- (design_cap * design_volt),
- 100000);
- /*
- * Wh = (c * v) / 1000000
- * 10th of a Wh = Wh * 10
- */
- msg[BCDB_FULL_CAP] = DIV_ROUND_NEAREST(
- (design_cap * full_cap),
- 100000);
- } else {
- uint32_t v;
- uint32_t c;
-
- if (battery_design_voltage(&v) == 0) {
- if (battery_design_capacity(&c) == 0) {
- /*
- * Wh = (c * v) / 1000000
- * 10th of a Wh = Wh * 10
- */
- msg[BCDB_DESIGN_CAP] =
- DIV_ROUND_NEAREST(
- (c * v),
- 100000);
- }
-
- if (battery_full_charge_capacity(&c)
- == 0) {
- /*
- * Wh = (c * v) / 1000000
- * 10th of a Wh = Wh * 10
- */
- msg[BCDB_FULL_CAP] =
- DIV_ROUND_NEAREST(
- (c * v),
- 100000);
- }
- }
-
- }
- /* Valid battery selected */
- msg[BCDB_BATT_TYPE] = 0;
- }
- } else {
- /* Battery not present indicated by 0's in the capacity */
- msg[BCDB_DESIGN_CAP] = 0;
- msg[BCDB_FULL_CAP] = 0;
- if (payload[0] != 0)
- msg[BCDB_BATT_TYPE] = 1;
- else
- msg[BCDB_BATT_TYPE] = 0;
- }
-
- /* Extended Battery Cap data is 9 bytes */
- tx_emsg[port].len = 9;
-
- send_ext_data_msg(port, TCPCI_MSG_SOP, PD_EXT_BATTERY_CAP);
-}
-
-static void pe_give_battery_cap_run(int port)
-{
- if (PE_CHK_FLAG(port, PE_FLAGS_TX_COMPLETE)) {
- PE_CLR_FLAG(port, PE_FLAGS_TX_COMPLETE);
- pe_set_ready_state(port);
- }
-}
-
-/**
- * PE_Give_Battery_Status
- */
-static void pe_give_battery_status_entry(int port)
-{
- uint8_t *payload = rx_emsg[port].buf;
- uint32_t *msg = (uint32_t *)tx_emsg[port].buf;
-
- if (!IS_ENABLED(CONFIG_BATTERY))
- return;
- print_current_state(port);
-
- if (battery_is_present()) {
- /*
- * We only have one fixed battery,
- * so make sure batt cap ref is 0.
- * This value is the first byte after the headers.
- */
- if (payload[0] != 0) {
- /* Invalid battery reference */
- *msg = BSDO_CAP(BSDO_CAP_UNKNOWN);
- *msg |= BSDO_INVALID;
- } else {
- uint32_t v;
- uint32_t c;
-
- *msg = BSDO_CAP(BSDO_CAP_UNKNOWN);
-
- if (IS_ENABLED(HAS_TASK_HOSTCMD) &&
- *host_get_memmap(EC_MEMMAP_BATTERY_VERSION) != 0) {
- v = *(int *)host_get_memmap(
- EC_MEMMAP_BATT_DVLT);
- c = *(int *)host_get_memmap(
- EC_MEMMAP_BATT_CAP);
-
- /*
- * Wh = (c * v) / 1000000
- * 10th of a Wh = Wh * 10
- */
- *msg = BSDO_CAP(DIV_ROUND_NEAREST((c * v),
- 100000));
- } else if (battery_design_voltage(&v) == 0 &&
- battery_remaining_capacity(&c) == 0) {
- /*
- * Wh = (c * v) / 1000000
- * 10th of a Wh = Wh * 10
- */
- *msg = BSDO_CAP(DIV_ROUND_NEAREST((c * v),
- 100000));
- }
-
- /* Battery is present */
- *msg |= BSDO_PRESENT;
-
- /*
- * For drivers that are not smart battery compliant,
- * battery_status() returns EC_ERROR_UNIMPLEMENTED and
- * the battery is assumed to be idle.
- */
- if (battery_status(&c) != 0) {
- *msg |= BSDO_IDLE; /* assume idle */
- } else {
- if (c & STATUS_FULLY_CHARGED)
- /* Fully charged */
- *msg |= BSDO_IDLE;
- else if (c & STATUS_DISCHARGING)
- /* Discharging */
- *msg |= BSDO_DISCHARGING;
- /* else battery is charging.*/
- }
- }
- } else {
- *msg = BSDO_CAP(BSDO_CAP_UNKNOWN);
- if (payload[0] != 0)
- *msg |= BSDO_INVALID;
- }
-
- /* Battery Status data is 4 bytes */
- tx_emsg[port].len = 4;
-
- send_data_msg(port, TCPCI_MSG_SOP, PD_DATA_BATTERY_STATUS);
-}
-
-static void pe_give_battery_status_run(int port)
-{
- if (PE_CHK_FLAG(port, PE_FLAGS_TX_COMPLETE)) {
- PE_CLR_FLAG(port, PE_FLAGS_TX_COMPLETE);
- set_state_pe(port, PE_SRC_READY);
- }
-}
-
-/**
- * PE_SRC_Send_Source_Alert and
- * PE_SNK_Send_Sink_Alert
- */
-static void pe_send_alert_entry(int port)
-{
- uint32_t *msg = (uint32_t *)tx_emsg[port].buf;
- uint32_t *len = &tx_emsg[port].len;
-
- print_current_state(port);
-
- if (pd_build_alert_msg(msg, len, pe[port].power_role) != EC_SUCCESS)
- pe_set_ready_state(port);
-
- /* Request the Protocol Layer to send Alert Message. */
- send_data_msg(port, TCPCI_MSG_SOP, PD_DATA_ALERT);
-}
-
-static void pe_send_alert_run(int port)
-{
- if (PE_CHK_FLAG(port, PE_FLAGS_TX_COMPLETE)) {
- PE_CLR_FLAG(port, PE_FLAGS_TX_COMPLETE);
- pe_set_ready_state(port);
- }
-}
-#endif /* CONFIG_USB_PD_EXTENDED_MESSAGES */
-
-/**
- * PE_DRS_Evaluate_Swap
- */
-static void pe_drs_evaluate_swap_entry(int port)
-{
- print_current_state(port);
-
- /* Get evaluation of Data Role Swap request from DPM */
- if (pd_check_data_swap(port, pe[port].data_role)) {
- PE_SET_FLAG(port, PE_FLAGS_ACCEPT);
- /*
- * PE_DRS_UFP_DFP_Evaluate_Swap and
- * PE_DRS_DFP_UFP_Evaluate_Swap states embedded here.
- */
- send_ctrl_msg(port, TCPCI_MSG_SOP, PD_CTRL_ACCEPT);
- } else {
- /*
- * PE_DRS_UFP_DFP_Reject_Swap and PE_DRS_DFP_UFP_Reject_Swap
- * states embedded here.
- */
- send_ctrl_msg(port, TCPCI_MSG_SOP, PD_CTRL_REJECT);
- }
-}
-
-static void pe_drs_evaluate_swap_run(int port)
-{
- if (PE_CHK_FLAG(port, PE_FLAGS_TX_COMPLETE)) {
- PE_CLR_FLAG(port, PE_FLAGS_TX_COMPLETE);
-
- /* Accept Message sent. Transtion to PE_DRS_Change */
- if (PE_CHK_FLAG(port, PE_FLAGS_ACCEPT)) {
- PE_CLR_FLAG(port, PE_FLAGS_ACCEPT);
- set_state_pe(port, PE_DRS_CHANGE);
- } else {
- /*
- * Message sent. Transition back to PE_SRC_Ready or
- * PE_SNK_Ready.
- */
- pe_set_ready_state(port);
- }
- }
-}
-
-/**
- * PE_DRS_Change
- */
-static void pe_drs_change_entry(int port)
-{
- print_current_state(port);
-
- /*
- * PE_DRS_UFP_DFP_Change_to_DFP and PE_DRS_DFP_UFP_Change_to_UFP
- * states embedded here.
- */
- /* Request DPM to change port data role */
- pd_request_data_swap(port);
-}
-
-static void pe_drs_change_run(int port)
-{
- /* Wait until the data role is changed */
- if (pe[port].data_role == pd_get_data_role(port))
- return;
-
- /* Update the data role */
- pe[port].data_role = pd_get_data_role(port);
-
- if (pe[port].data_role == PD_ROLE_DFP)
- PE_CLR_FLAG(port, PE_FLAGS_DR_SWAP_TO_DFP);
-
- /*
- * Port changed. Transition back to PE_SRC_Ready or
- * PE_SNK_Ready.
- */
- pe_set_ready_state(port);
-}
-
-/**
- * PE_DRS_Send_Swap
- */
-static void pe_drs_send_swap_entry(int port)
-{
- print_current_state(port);
-
- /*
- * PE_DRS_UFP_DFP_Send_Swap and PE_DRS_DFP_UFP_Send_Swap
- * states embedded here.
- */
- /* Request the Protocol Layer to send a DR_Swap Message */
- send_ctrl_msg(port, TCPCI_MSG_SOP, PD_CTRL_DR_SWAP);
- pe_sender_response_msg_entry(port);
-}
-
-static void pe_drs_send_swap_run(int port)
-{
- int type;
- int cnt;
- int ext;
- enum pe_msg_check msg_check;
-
- /*
- * Check the state of the message sent
- */
- msg_check = pe_sender_response_msg_run(port);
-
- /*
- * Transition to PE_DRS_Change when:
- * 1) An Accept Message is received.
- *
- * Transition to PE_SRC_Ready or PE_SNK_Ready state when:
- * 1) A Reject Message is received.
- * 2) Or a Wait Message is received.
- */
- if ((msg_check & PE_MSG_SENT) &&
- PE_CHK_FLAG(port, PE_FLAGS_MSG_RECEIVED)) {
- PE_CLR_FLAG(port, PE_FLAGS_MSG_RECEIVED);
-
- type = PD_HEADER_TYPE(rx_emsg[port].header);
- cnt = PD_HEADER_CNT(rx_emsg[port].header);
- ext = PD_HEADER_EXT(rx_emsg[port].header);
-
- if ((ext == 0) && (cnt == 0)) {
- if (type == PD_CTRL_ACCEPT) {
- set_state_pe(port, PE_DRS_CHANGE);
- return;
- } else if ((type == PD_CTRL_REJECT) ||
- (type == PD_CTRL_WAIT) ||
- (type == PD_CTRL_NOT_SUPPORTED)) {
- pe_set_ready_state(port);
- return;
- }
- }
- }
-
- /*
- * Transition to PE_SRC_Ready or PE_SNK_Ready state when:
- * 1) the SenderResponseTimer times out.
- * 2) Message was discarded.
- */
- if ((msg_check & PE_MSG_DISCARDED) ||
- pd_timer_is_expired(port, PE_TIMER_SENDER_RESPONSE))
- pe_set_ready_state(port);
-}
-
-static void pe_drs_send_swap_exit(int port)
-{
- pe_sender_response_msg_exit(port);
-}
-
-/**
- * PE_PRS_SRC_SNK_Evaluate_Swap
- */
-static void pe_prs_src_snk_evaluate_swap_entry(int port)
-{
- print_current_state(port);
-
- if (!pd_check_power_swap(port)) {
- /* PE_PRS_SRC_SNK_Reject_PR_Swap state embedded here */
- send_ctrl_msg(port, TCPCI_MSG_SOP, PD_CTRL_REJECT);
- } else {
- tc_request_power_swap(port);
- /* PE_PRS_SRC_SNK_Accept_Swap state embedded here */
- PE_SET_FLAG(port, PE_FLAGS_ACCEPT);
- send_ctrl_msg(port, TCPCI_MSG_SOP, PD_CTRL_ACCEPT);
- }
-}
-
-static void pe_prs_src_snk_evaluate_swap_run(int port)
-{
- if (PE_CHK_FLAG(port, PE_FLAGS_TX_COMPLETE)) {
- PE_CLR_FLAG(port, PE_FLAGS_TX_COMPLETE);
-
- if (PE_CHK_FLAG(port, PE_FLAGS_ACCEPT)) {
- PE_CLR_FLAG(port, PE_FLAGS_ACCEPT);
-
- /*
- * Clear any pending DPM power role swap request so we
- * don't trigger a power role swap request back to src
- * power role.
- */
- PE_CLR_DPM_REQUEST(port, DPM_REQUEST_PR_SWAP);
- /*
- * Power Role Swap OK, transition to
- * PE_PRS_SRC_SNK_Transition_to_off
- */
- set_state_pe(port, PE_PRS_SRC_SNK_TRANSITION_TO_OFF);
- } else {
- /* Message sent, return to PE_SRC_Ready */
- set_state_pe(port, PE_SRC_READY);
- }
- }
-}
-
-/**
- * PE_PRS_SRC_SNK_Transition_To_Off
- */
-static void pe_prs_src_snk_transition_to_off_entry(int port)
-{
- print_current_state(port);
-
- /* Contract is invalid */
- pe_invalidate_explicit_contract(port);
-
- /* Tell TypeC to power off the source */
- tc_src_power_off(port);
-
- pd_timer_enable(port, PE_TIMER_PS_SOURCE,
- PD_POWER_SUPPLY_TURN_OFF_DELAY);
-}
-
-static void pe_prs_src_snk_transition_to_off_run(int port)
-{
- /*
- * This is a non-interruptible AMS and power is transitioning - hard
- * reset on interruption.
- */
- if (PE_CHK_FLAG(port, PE_FLAGS_MSG_RECEIVED)) {
- PE_CLR_FLAG(port, PE_FLAGS_MSG_RECEIVED);
-
- tc_pr_swap_complete(port, 0);
- set_state_pe(port, PE_SRC_HARD_RESET);
- }
-
- /* Give time for supply to power off */
- if (pd_timer_is_expired(port, PE_TIMER_PS_SOURCE) &&
- pd_check_vbus_level(port, VBUS_SAFE0V))
- set_state_pe(port, PE_PRS_SRC_SNK_ASSERT_RD);
-}
-
-static void pe_prs_src_snk_transition_to_off_exit(int port)
-{
- pd_timer_disable(port, PE_TIMER_PS_SOURCE);
-}
-
-/**
- * PE_PRS_SRC_SNK_Assert_Rd
- */
-static void pe_prs_src_snk_assert_rd_entry(int port)
-{
- print_current_state(port);
-
- /* Tell TypeC to swap from Attached.SRC to Attached.SNK */
- tc_prs_src_snk_assert_rd(port);
-}
-
-static void pe_prs_src_snk_assert_rd_run(int port)
-{
- /* Wait until Rd is asserted */
- if (tc_is_attached_snk(port))
- set_state_pe(port, PE_PRS_SRC_SNK_WAIT_SOURCE_ON);
-}
-
-/**
- * PE_PRS_SRC_SNK_Wait_Source_On
- */
-static void pe_prs_src_snk_wait_source_on_entry(int port)
-{
- print_current_state(port);
- send_ctrl_msg(port, TCPCI_MSG_SOP, PD_CTRL_PS_RDY);
-}
-
-static void pe_prs_src_snk_wait_source_on_run(int port)
-{
- if (pd_timer_is_disabled(port, PE_TIMER_PS_SOURCE) &&
- PE_CHK_FLAG(port, PE_FLAGS_TX_COMPLETE)) {
- PE_CLR_FLAG(port, PE_FLAGS_TX_COMPLETE);
-
- /* Update pe power role */
- pe[port].power_role = pd_get_power_role(port);
- pd_timer_enable(port, PE_TIMER_PS_SOURCE, PD_T_PS_SOURCE_ON);
- }
-
- /*
- * Transition to PE_SNK_Startup when:
- * 1) A PS_RDY Message is received.
- */
- if (!pd_timer_is_disabled(port, PE_TIMER_PS_SOURCE) &&
- PE_CHK_FLAG(port, PE_FLAGS_MSG_RECEIVED)) {
- int type = PD_HEADER_TYPE(rx_emsg[port].header);
- int cnt = PD_HEADER_CNT(rx_emsg[port].header);
- int ext = PD_HEADER_EXT(rx_emsg[port].header);
-
- PE_CLR_FLAG(port, PE_FLAGS_MSG_RECEIVED);
-
- if ((ext == 0) && (cnt == 0) && (type == PD_CTRL_PS_RDY)) {
- PE_SET_FLAG(port, PE_FLAGS_PR_SWAP_COMPLETE);
- set_state_pe(port, PE_SNK_STARTUP);
- } else {
- int sop = PD_HEADER_GET_SOP(rx_emsg[port].header);
- /*
- * USB PD 3.0 6.8.1:
- * Receiving an unexpected message shall be responded
- * to with a soft reset message.
- */
- pe_send_soft_reset(port, sop);
- }
- return;
- }
-
- /*
- * Transition to ErrorRecovery state when:
- * 1) The PSSourceOnTimer times out.
- * 2) PS_RDY not sent after retries.
- */
- if (pd_timer_is_expired(port, PE_TIMER_PS_SOURCE) ||
- PE_CHK_FLAG(port, PE_FLAGS_PROTOCOL_ERROR)) {
- PE_CLR_FLAG(port, PE_FLAGS_PROTOCOL_ERROR);
-
- set_state_pe(port, PE_WAIT_FOR_ERROR_RECOVERY);
- return;
- }
-}
-
-static void pe_prs_src_snk_wait_source_on_exit(int port)
-{
- pd_timer_disable(port, PE_TIMER_PS_SOURCE);
- tc_pr_swap_complete(port,
- PE_CHK_FLAG(port, PE_FLAGS_PR_SWAP_COMPLETE));
-}
-
-/**
- * PE_PRS_SRC_SNK_Send_Swap
- */
-static void pe_prs_src_snk_send_swap_entry(int port)
-{
- print_current_state(port);
-
- /* Making an attempt to PR_Swap, clear we were possibly waiting */
- pd_timer_disable(port, PE_TIMER_PR_SWAP_WAIT);
-
- /* Request the Protocol Layer to send a PR_Swap Message. */
- send_ctrl_msg(port, TCPCI_MSG_SOP, PD_CTRL_PR_SWAP);
- pe_sender_response_msg_entry(port);
-}
-
-static void pe_prs_src_snk_send_swap_run(int port)
-{
- int type;
- int cnt;
- int ext;
- enum pe_msg_check msg_check;
-
- /*
- * Check the state of the message sent
- */
- msg_check = pe_sender_response_msg_run(port);
-
- /*
- * Transition to PE_PRS_SRC_SNK_Transition_To_Off when:
- * 1) An Accept Message is received.
- *
- * Transition to PE_SRC_Ready state when:
- * 1) A Reject Message is received.
- * 2) Or a Wait Message is received.
- */
- if ((msg_check & PE_MSG_SENT) &&
- PE_CHK_FLAG(port, PE_FLAGS_MSG_RECEIVED)) {
- PE_CLR_FLAG(port, PE_FLAGS_MSG_RECEIVED);
-
- type = PD_HEADER_TYPE(rx_emsg[port].header);
- cnt = PD_HEADER_CNT(rx_emsg[port].header);
- ext = PD_HEADER_EXT(rx_emsg[port].header);
-
- if ((ext == 0) && (cnt == 0)) {
- if (type == PD_CTRL_ACCEPT) {
- pe[port].src_snk_pr_swap_counter = 0;
- tc_request_power_swap(port);
- set_state_pe(port,
- PE_PRS_SRC_SNK_TRANSITION_TO_OFF);
- } else if (type == PD_CTRL_REJECT) {
- pe[port].src_snk_pr_swap_counter = 0;
- set_state_pe(port, PE_SRC_READY);
- } else if (type == PD_CTRL_WAIT) {
- if (pe[port].src_snk_pr_swap_counter <
- N_SNK_SRC_PR_SWAP_COUNT) {
- PE_SET_FLAG(port,
- PE_FLAGS_WAITING_PR_SWAP);
- pd_timer_enable(port,
- PE_TIMER_PR_SWAP_WAIT,
- PD_T_PR_SWAP_WAIT);
- }
- pe[port].src_snk_pr_swap_counter++;
- set_state_pe(port, PE_SRC_READY);
- }
- return;
- }
- }
-
- /*
- * Transition to PE_SRC_Ready state when:
- * 1) Or the SenderResponseTimer times out.
- * 2) Message was discarded.
- */
- if ((msg_check & PE_MSG_DISCARDED) ||
- pd_timer_is_expired(port, PE_TIMER_SENDER_RESPONSE))
- set_state_pe(port, PE_SRC_READY);
-}
-
-static void pe_prs_src_snk_send_swap_exit(int port)
-{
- pe_sender_response_msg_exit(port);
-}
-
-/**
- * PE_PRS_SNK_SRC_Evaluate_Swap
- */
-static void pe_prs_snk_src_evaluate_swap_entry(int port)
-{
- print_current_state(port);
-
- /*
- * Cancel any pending PR swap request due to a received Wait since the
- * partner just sent us a PR swap message.
- */
- PE_CLR_FLAG(port, PE_FLAGS_WAITING_PR_SWAP);
- pe[port].src_snk_pr_swap_counter = 0;
-
- if (!pd_check_power_swap(port)) {
- /* PE_PRS_SNK_SRC_Reject_Swap state embedded here */
- send_ctrl_msg(port, TCPCI_MSG_SOP, PD_CTRL_REJECT);
- } else {
- tc_request_power_swap(port);
- /* PE_PRS_SNK_SRC_Accept_Swap state embedded here */
- PE_SET_FLAG(port, PE_FLAGS_ACCEPT);
- send_ctrl_msg(port, TCPCI_MSG_SOP, PD_CTRL_ACCEPT);
- }
-}
-
-static void pe_prs_snk_src_evaluate_swap_run(int port)
-{
- if (PE_CHK_FLAG(port, PE_FLAGS_TX_COMPLETE)) {
- PE_CLR_FLAG(port, PE_FLAGS_TX_COMPLETE);
- if (PE_CHK_FLAG(port, PE_FLAGS_ACCEPT)) {
- PE_CLR_FLAG(port, PE_FLAGS_ACCEPT);
-
- /*
- * Clear any pending DPM power role swap request so we
- * don't trigger a power role swap request back to sink
- * power role.
- */
- PE_CLR_DPM_REQUEST(port, DPM_REQUEST_PR_SWAP);
- /*
- * Accept message sent, transition to
- * PE_PRS_SNK_SRC_Transition_to_off
- */
- set_state_pe(port, PE_PRS_SNK_SRC_TRANSITION_TO_OFF);
- } else {
- /* Message sent, return to PE_SNK_Ready */
- set_state_pe(port, PE_SNK_READY);
- }
- }
-
- if (PE_CHK_FLAG(port, PE_FLAGS_PROTOCOL_ERROR)) {
- PE_CLR_FLAG(port, PE_FLAGS_PROTOCOL_ERROR);
- /*
- * Protocol Error occurs while PR swap, this may
- * brown out if the port-parnter can't hold VBUS
- * for tSrcTransition. Notify TC that we end the PR
- * swap and start to watch VBUS.
- *
- * TODO(b:155181980): issue soft reset on protocol error.
- */
- tc_pr_swap_complete(port, 0);
- }
-}
-
-/**
- * PE_PRS_SNK_SRC_Transition_To_Off
- * PE_FRS_SNK_SRC_Transition_To_Off
- *
- * NOTE: Shared action code used for Power Role Swap and Fast Role Swap
- */
-static void pe_prs_snk_src_transition_to_off_entry(int port)
-{
- print_current_state(port);
-
- if (!IS_ENABLED(CONFIG_USB_PD_REV30) ||
- !pe_in_frs_mode(port))
- tc_snk_power_off(port);
-
- pd_timer_enable(port, PE_TIMER_PS_SOURCE, PD_T_PS_SOURCE_OFF);
-}
-
-static void pe_prs_snk_src_transition_to_off_run(int port)
-{
- int type;
- int cnt;
- int ext;
-
- /*
- * Transition to ErrorRecovery state when:
- * 1) The PSSourceOffTimer times out.
- */
- if (pd_timer_is_expired(port, PE_TIMER_PS_SOURCE))
- set_state_pe(port, PE_WAIT_FOR_ERROR_RECOVERY);
-
- /*
- * Transition to PE_PRS_SNK_SRC_Assert_Rp when:
- * 1) An PS_RDY Message is received.
- */
- else if (PE_CHK_FLAG(port, PE_FLAGS_MSG_RECEIVED)) {
- PE_CLR_FLAG(port, PE_FLAGS_MSG_RECEIVED);
-
- type = PD_HEADER_TYPE(rx_emsg[port].header);
- cnt = PD_HEADER_CNT(rx_emsg[port].header);
- ext = PD_HEADER_EXT(rx_emsg[port].header);
-
- if ((ext == 0) && (cnt == 0) && (type == PD_CTRL_PS_RDY)) {
- /*
- * FRS: We are always ready to drive vSafe5v, so just
- * skip PE_FRS_SNK_SRC_Vbus_Applied and go direct to
- * PE_FRS_SNK_SRC_Assert_Rp
- */
- set_state_pe(port, PE_PRS_SNK_SRC_ASSERT_RP);
- }
- }
-}
-
-static void pe_prs_snk_src_transition_to_off_exit(int port)
-{
- pd_timer_disable(port, PE_TIMER_PS_SOURCE);
-}
-
-/**
- * PE_PRS_SNK_SRC_Assert_Rp
- * PE_FRS_SNK_SRC_Assert_Rp
- *
- * NOTE: Shared action code used for Power Role Swap and Fast Role Swap
- */
-static void pe_prs_snk_src_assert_rp_entry(int port)
-{
- print_current_state(port);
-
- /*
- * Tell TypeC to Power/Fast Role Swap (PRS/FRS) from
- * Attached.SNK to Attached.SRC
- */
- tc_prs_snk_src_assert_rp(port);
-}
-
-static void pe_prs_snk_src_assert_rp_run(int port)
-{
- /* Wait until TypeC is in the Attached.SRC state */
- if (tc_is_attached_src(port)) {
- if (!IS_ENABLED(CONFIG_USB_PD_REV30) ||
- !pe_in_frs_mode(port)) {
- /* Contract is invalid now */
- pe_invalidate_explicit_contract(port);
- }
- set_state_pe(port, PE_PRS_SNK_SRC_SOURCE_ON);
- }
-}
-
-/**
- * PE_PRS_SNK_SRC_Source_On
- * PE_FRS_SNK_SRC_Source_On
- *
- * NOTE: Shared action code used for Power Role Swap and Fast Role Swap
- */
-static void pe_prs_snk_src_source_on_entry(int port)
-{
- print_current_state(port);
-
- /*
- * VBUS was enabled when the TypeC state machine entered
- * Attached.SRC state
- */
- pd_timer_enable(port, PE_TIMER_PS_SOURCE,
- PD_POWER_SUPPLY_TURN_ON_DELAY);
-}
-
-static void pe_prs_snk_src_source_on_run(int port)
-{
- /* Wait until power supply turns on */
- if (!pd_timer_is_disabled(port, PE_TIMER_PS_SOURCE)) {
- if (!pd_timer_is_expired(port, PE_TIMER_PS_SOURCE))
- return;
-
- /* update pe power role */
- pe[port].power_role = pd_get_power_role(port);
- send_ctrl_msg(port, TCPCI_MSG_SOP, PD_CTRL_PS_RDY);
- /* reset timer so PD_CTRL_PS_RDY isn't sent again */
- pd_timer_disable(port, PE_TIMER_PS_SOURCE);
- }
-
- /*
- * Transition to ErrorRecovery state when:
- * 1) On protocol error
- */
- else if (PE_CHK_FLAG(port, PE_FLAGS_PROTOCOL_ERROR)) {
- PE_CLR_FLAG(port, PE_FLAGS_PROTOCOL_ERROR);
- set_state_pe(port, PE_WAIT_FOR_ERROR_RECOVERY);
- }
-
- else if (PE_CHK_FLAG(port, PE_FLAGS_TX_COMPLETE)) {
- PE_CLR_FLAG(port, PE_FLAGS_TX_COMPLETE);
-
- /* Run swap source timer on entry to pe_src_startup */
- PE_SET_FLAG(port, PE_FLAGS_PR_SWAP_COMPLETE);
- set_state_pe(port, PE_SRC_STARTUP);
- }
-}
-
-static void pe_prs_snk_src_source_on_exit(int port)
-{
- pd_timer_disable(port, PE_TIMER_PS_SOURCE);
- tc_pr_swap_complete(port,
- PE_CHK_FLAG(port, PE_FLAGS_PR_SWAP_COMPLETE));
-}
-
-/**
- * PE_PRS_SNK_SRC_Send_Swap
- * PE_FRS_SNK_SRC_Send_Swap
- *
- * NOTE: Shared action code used for Power Role Swap and Fast Role Swap
- */
-static void pe_prs_snk_src_send_swap_entry(int port)
-{
- print_current_state(port);
-
- /*
- * PRS_SNK_SRC_SEND_SWAP
- * Request the Protocol Layer to send a PR_Swap Message.
- *
- * FRS_SNK_SRC_SEND_SWAP
- * Hardware should have turned off sink power and started
- * bringing Vbus to vSafe5.
- * Request the Protocol Layer to send a FR_Swap Message.
- */
- if (IS_ENABLED(CONFIG_USB_PD_REV30)) {
- send_ctrl_msg(port,
- TCPCI_MSG_SOP,
- pe_in_frs_mode(port)
- ? PD_CTRL_FR_SWAP
- : PD_CTRL_PR_SWAP);
- } else {
- send_ctrl_msg(port, TCPCI_MSG_SOP, PD_CTRL_PR_SWAP);
- }
- pe_sender_response_msg_entry(port);
-}
-
-static void pe_prs_snk_src_send_swap_run(int port)
-{
- int type;
- int cnt;
- int ext;
- enum pe_msg_check msg_check;
-
- /*
- * Check the state of the message sent
- */
- msg_check = pe_sender_response_msg_run(port);
-
- /*
- * Handle discarded message
- */
- if (msg_check & PE_MSG_DISCARDED) {
- if (pe_in_frs_mode(port))
- set_state_pe(port, PE_SNK_HARD_RESET);
- else
- set_state_pe(port, PE_SNK_READY);
- return;
- }
-
- /*
- * Transition to PE_PRS_SNK_SRC_Transition_to_off when:
- * 1) An Accept Message is received.
- *
- * PRS: Transition to PE_SNK_Ready state when:
- * FRS: Transition to ErrorRecovery state when:
- * 1) A Reject Message is received.
- * 2) Or a Wait Message is received.
- */
- if ((msg_check & PE_MSG_SENT) &&
- PE_CHK_FLAG(port, PE_FLAGS_MSG_RECEIVED)) {
- PE_CLR_FLAG(port, PE_FLAGS_MSG_RECEIVED);
-
- type = PD_HEADER_TYPE(rx_emsg[port].header);
- cnt = PD_HEADER_CNT(rx_emsg[port].header);
- ext = PD_HEADER_EXT(rx_emsg[port].header);
-
- if ((ext == 0) && (cnt == 0)) {
- if (type == PD_CTRL_ACCEPT) {
- tc_request_power_swap(port);
- set_state_pe(port,
- PE_PRS_SNK_SRC_TRANSITION_TO_OFF);
- } else if ((type == PD_CTRL_REJECT) ||
- (type == PD_CTRL_WAIT)) {
- if (IS_ENABLED(CONFIG_USB_PD_REV30))
- set_state_pe(port,
- pe_in_frs_mode(port)
- ? PE_WAIT_FOR_ERROR_RECOVERY
- : PE_SNK_READY);
- else
- set_state_pe(port, PE_SNK_READY);
- }
- return;
- }
- }
-
- /*
- * PRS: Transition to PE_SNK_Ready state when:
- * FRS: Transition to ErrorRecovery state when:
- * 1) The SenderResponseTimer times out.
- */
- if (pd_timer_is_expired(port, PE_TIMER_SENDER_RESPONSE)) {
- if (IS_ENABLED(CONFIG_USB_PD_REV30))
- set_state_pe(port,
- pe_in_frs_mode(port)
- ? PE_WAIT_FOR_ERROR_RECOVERY
- : PE_SNK_READY);
- else
- set_state_pe(port, PE_SNK_READY);
- return;
- }
- /*
- * FRS Only: Transition to ErrorRecovery state when:
- * 2) The FR_Swap Message is not sent after retries (a GoodCRC Message
- * has not been received). A soft reset Shall Not be initiated in
- * this case.
- */
- if (IS_ENABLED(CONFIG_USB_PD_REV30) &&
- pe_in_frs_mode(port) &&
- PE_CHK_FLAG(port, PE_FLAGS_PROTOCOL_ERROR)) {
- PE_CLR_FLAG(port, PE_FLAGS_PROTOCOL_ERROR);
- set_state_pe(port, PE_WAIT_FOR_ERROR_RECOVERY);
- }
-}
-
-static void pe_prs_snk_src_send_swap_exit(int port)
-{
- pe_sender_response_msg_exit(port);
-}
-
-/**
- * PE_FRS_SNK_SRC_Start_AMS
- */
-__maybe_unused static void pe_frs_snk_src_start_ams_entry(int port)
-{
- if (!IS_ENABLED(CONFIG_USB_PD_REV30))
- assert(0);
-
- print_current_state(port);
-
- /* Contract is invalid now */
- pe_invalidate_explicit_contract(port);
-
- /* Inform Protocol Layer this is start of AMS */
- PE_SET_FLAG(port, PE_FLAGS_LOCALLY_INITIATED_AMS);
-
- /* Shared PRS/FRS code, indicate FRS path */
- PE_SET_FLAG(port, PE_FLAGS_FAST_ROLE_SWAP_PATH);
- set_state_pe(port, PE_PRS_SNK_SRC_SEND_SWAP);
-}
-
-/**
- * PE_PRS_FRS_SHARED
- */
-__maybe_unused static void pe_prs_frs_shared_entry(int port)
-{
- if (!IS_ENABLED(CONFIG_USB_PD_REV30))
- assert(0);
-
- /*
- * Shared PRS/FRS code, assume PRS path
- *
- * This is the super state entry. It will be called before
- * the first entry state to get into the PRS/FRS path.
- * For FRS, PE_FRS_SNK_SRC_START_AMS entry will be called
- * after this and that will set for the FRS path.
- */
- PE_CLR_FLAG(port, PE_FLAGS_FAST_ROLE_SWAP_PATH);
-}
-
-__maybe_unused static void pe_prs_frs_shared_exit(int port)
-{
- if (!IS_ENABLED(CONFIG_USB_PD_REV30))
- assert(0);
-
- /*
- * Shared PRS/FRS code, when not in shared path
- * indicate PRS path
- */
- PE_CLR_FLAG(port, PE_FLAGS_FAST_ROLE_SWAP_PATH);
-}
-
-/**
- * PE_BIST_TX
- */
-static void pe_bist_tx_entry(int port)
-{
- uint32_t *payload = (uint32_t *)rx_emsg[port].buf;
- uint8_t mode = BIST_MODE(payload[0]);
- int vbus_mv;
- int ibus_ma;
-
- print_current_state(port);
-
- /* Get the current nominal VBUS value */
- if (pe[port].power_role == PD_ROLE_SOURCE) {
- const uint32_t *src_pdo;
- uint32_t unused;
-
- dpm_get_source_pdo(&src_pdo, port);
- pd_extract_pdo_power(src_pdo[pe[port].requested_idx - 1],
- &ibus_ma, &vbus_mv, &unused);
- } else {
- vbus_mv = pe[port].supply_voltage;
- }
-
- /* If VBUS is not at vSafe5V, then don't enter BIST test mode */
- if (vbus_mv != PD_V_SAFE5V_NOM) {
- pe_set_ready_state(port);
- return;
- }
-
- if (mode == BIST_CARRIER_MODE_2) {
- /*
- * PE_BIST_Carrier_Mode embedded here.
- * See PD 3.0 section 6.4.3.1 BIST Carrier Mode 2: With a BIST
- * Carrier Mode 2 BIST Data Object, the UUT Shall send out a
- * continuous string of BMC-encoded alternating "1"s and “0”s.
- * The UUT Shall exit the Continuous BIST Mode within
- * tBISTContMode of this Continuous BIST Mode being enabled.
- */
- send_ctrl_msg(port, TCPCI_MSG_TX_BIST_MODE_2, 0);
- pd_timer_enable(port, PE_TIMER_BIST_CONT_MODE,
- PD_T_BIST_CONT_MODE);
- } else if (mode == BIST_TEST_DATA) {
- /*
- * See PD 3.0 section 6.4.3.2 BIST Test Data:
- * With a BIST Test Data BIST Data Object, the UUT Shall return
- * a GoodCRC Message and Shall enter a test mode in which it
- * sends no further Messages except for GoodCRC Messages in
- * response to received Messages.... The test Shall be ended by
- * sending Hard Reset Signaling to reset the UUT.
- */
- if (tcpc_set_bist_test_mode(port, true) != EC_SUCCESS)
- CPRINTS("C%d: Failed to enter BIST Test Mode", port);
- } else {
- /* Ignore unsupported BIST messages. */
- pe_set_ready_state(port);
- return;
- }
-}
-
-static void pe_bist_tx_run(int port)
-{
- if (pd_timer_is_expired(port, PE_TIMER_BIST_CONT_MODE)) {
- /*
- * Entry point to disable BIST in TCPC if that's not already
- * handled automatically by the TCPC. Unless this method is
- * implemented in a TCPM driver, this function does nothing.
- */
- tcpm_reset_bist_type_2(port);
-
- if (pe[port].power_role == PD_ROLE_SOURCE)
- set_state_pe(port, PE_SRC_TRANSITION_TO_DEFAULT);
- else
- set_state_pe(port, PE_SNK_TRANSITION_TO_DEFAULT);
- } else {
- /*
- * We are in test data mode and no further Messages except for
- * GoodCRC Messages in response to received Messages will
- * be sent.
- */
- if (PE_CHK_FLAG(port, PE_FLAGS_MSG_RECEIVED))
- PE_CLR_FLAG(port, PE_FLAGS_MSG_RECEIVED);
- }
-}
-
-static void pe_bist_tx_exit(int port)
-{
- pd_timer_disable(port, PE_TIMER_BIST_CONT_MODE);
-}
-
-/**
- * Give_Sink_Cap Message
- */
-static void pe_snk_give_sink_cap_entry(int port)
-{
- print_current_state(port);
-
- /* Send a Sink_Capabilities Message */
- tx_emsg[port].len = pd_snk_pdo_cnt * 4;
- memcpy(tx_emsg[port].buf, (uint8_t *)pd_snk_pdo, tx_emsg[port].len);
- send_data_msg(port, TCPCI_MSG_SOP, PD_DATA_SINK_CAP);
-}
-
-static void pe_snk_give_sink_cap_run(int port)
-{
- if (PE_CHK_FLAG(port, PE_FLAGS_TX_COMPLETE)) {
- PE_CLR_FLAG(port, PE_FLAGS_TX_COMPLETE);
- pe_set_ready_state(port);
- return;
- }
-
- if (pe_check_outgoing_discard(port))
- return;
-}
-
-/**
- * Wait For Error Recovery
- */
-static void pe_wait_for_error_recovery_entry(int port)
-{
- print_current_state(port);
- tc_start_error_recovery(port);
-}
-
-static void pe_wait_for_error_recovery_run(int port)
-{
- /* Stay here until error recovery is complete */
-}
-
-/**
- * PE_Handle_Custom_Vdm_Request
- */
-static void pe_handle_custom_vdm_request_entry(int port)
-{
- /* Get the message */
- uint32_t *payload = (uint32_t *)rx_emsg[port].buf;
- int cnt = PD_HEADER_CNT(rx_emsg[port].header);
- int sop = PD_HEADER_GET_SOP(rx_emsg[port].header);
- int rlen = 0;
- uint32_t *rdata;
-
- print_current_state(port);
-
- /* This is an Interruptible AMS */
- PE_SET_FLAG(port, PE_FLAGS_INTERRUPTIBLE_AMS);
-
- rlen = pd_custom_vdm(port, cnt, payload, &rdata);
- if (rlen > 0) {
- tx_emsg[port].len = rlen * 4;
- memcpy(tx_emsg[port].buf, (uint8_t *)rdata, tx_emsg[port].len);
- send_data_msg(port, sop, PD_DATA_VENDOR_DEF);
- } else {
- if (prl_get_rev(port, TCPCI_MSG_SOP) > PD_REV20) {
- set_state_pe(port, PE_SEND_NOT_SUPPORTED);
- } else {
- PE_CLR_FLAG(port, PE_FLAGS_INTERRUPTIBLE_AMS);
- pe_set_ready_state(port);
- }
- }
-}
-
-static void pe_handle_custom_vdm_request_run(int port)
-{
- /* Wait for ACCEPT, WAIT or Reject message to send. */
- if (PE_CHK_FLAG(port, PE_FLAGS_TX_COMPLETE)) {
- PE_CLR_FLAG(port, PE_FLAGS_TX_COMPLETE);
-
- /*
- * Message sent. Transition back to
- * PE_SRC_Ready or PE_SINK_Ready
- */
- pe_set_ready_state(port);
- }
-}
-
-static void pe_handle_custom_vdm_request_exit(int port)
-{
- PE_CLR_FLAG(port, PE_FLAGS_INTERRUPTIBLE_AMS);
-}
-
-static enum vdm_response_result parse_vdm_response_common(int port)
-{
- /* Retrieve the message information */
- uint32_t *payload;
- int sop;
- uint8_t type;
- uint8_t cnt;
- uint8_t ext;
-
- if (!PE_CHK_REPLY(port))
- return VDM_RESULT_WAITING;
- PE_CLR_FLAG(port, PE_FLAGS_MSG_RECEIVED);
-
- payload = (uint32_t *)rx_emsg[port].buf;
- sop = PD_HEADER_GET_SOP(rx_emsg[port].header);
- type = PD_HEADER_TYPE(rx_emsg[port].header);
- cnt = PD_HEADER_CNT(rx_emsg[port].header);
- ext = PD_HEADER_EXT(rx_emsg[port].header);
-
- if (sop == pe[port].tx_type && type == PD_DATA_VENDOR_DEF && cnt >= 1
- && ext == 0) {
- if (PD_VDO_CMDT(payload[0]) == CMDT_RSP_ACK &&
- cnt >= pe[port].vdm_ack_min_data_objects) {
- /* Handle ACKs in state-specific code. */
- return VDM_RESULT_ACK;
- } else if (PD_VDO_CMDT(payload[0]) == CMDT_RSP_NAK) {
- /* Handle NAKs in state-specific code. */
- return VDM_RESULT_NAK;
- } else if (PD_VDO_CMDT(payload[0]) == CMDT_RSP_BUSY) {
- /*
- * Don't fill in the discovery field so we re-probe in
- * tVDMBusy
- */
- CPRINTS("C%d: Partner BUSY, request will be retried",
- port);
- pd_timer_enable(port, PE_TIMER_DISCOVER_IDENTITY,
- PD_T_VDM_BUSY);
-
- return VDM_RESULT_NO_ACTION;
- } else if (PD_VDO_CMDT(payload[0]) == CMDT_INIT) {
- /*
- * Unexpected VDM REQ received. Let Src.Ready or
- * Snk.Ready handle it.
- */
- PE_SET_FLAG(port, PE_FLAGS_MSG_RECEIVED);
- return VDM_RESULT_NO_ACTION;
- }
-
- /*
- * Partner gave us an incorrect size or command; mark discovery
- * as failed.
- */
- CPRINTS("C%d: Unexpected VDM response: 0x%04x 0x%04x",
- port, rx_emsg[port].header, payload[0]);
- return VDM_RESULT_NAK;
- } else if (sop == pe[port].tx_type && ext == 0 && cnt == 0 &&
- type == PD_CTRL_NOT_SUPPORTED) {
- /*
- * A NAK would be more expected here, but Not Supported is still
- * allowed with the same meaning.
- */
- return VDM_RESULT_NAK;
- }
-
- /* Unexpected Message Received. Src.Ready or Snk.Ready can handle it. */
- PE_SET_FLAG(port, PE_FLAGS_MSG_RECEIVED);
- return VDM_RESULT_NO_ACTION;
-}
-
-/**
- * PE_VDM_SEND_REQUEST
- * Shared parent to manage VDM timer and other shared parts of the VDM request
- * process
- */
-static void pe_vdm_send_request_entry(int port)
-{
- if (pe[port].tx_type == TCPCI_MSG_INVALID) {
- if (IS_ENABLED(USB_PD_DEBUG_LABELS))
- CPRINTS("C%d: %s: Tx type expected to be set, "
- "returning",
- port, pe_state_names[get_state_pe(port)]);
- set_state_pe(port, get_last_state_pe(port));
- return;
- }
-
- if ((pe[port].tx_type == TCPCI_MSG_SOP_PRIME ||
- pe[port].tx_type == TCPCI_MSG_SOP_PRIME_PRIME) &&
- !tc_is_vconn_src(port) && port_discovery_vconn_swap_policy(port,
- PE_FLAGS_VCONN_SWAP_TO_ON)) {
- if (port_try_vconn_swap(port))
- return;
- }
-
- /* All VDM sequences are Interruptible */
- PE_SET_FLAG(port, PE_FLAGS_LOCALLY_INITIATED_AMS |
- PE_FLAGS_INTERRUPTIBLE_AMS);
-}
-
-static void pe_vdm_send_request_run(int port)
-{
- if (PE_CHK_FLAG(port, PE_FLAGS_TX_COMPLETE) &&
- pd_timer_is_disabled(port, PE_TIMER_VDM_RESPONSE)) {
- /* Message was sent */
- PE_CLR_FLAG(port, PE_FLAGS_TX_COMPLETE);
-
- /* Start no response timer */
- /* TODO(b/155890173): Support DPM-supplied timeout */
- pd_timer_enable(port, PE_TIMER_VDM_RESPONSE,
- PD_T_VDM_SNDR_RSP);
- }
-
- if (PE_CHK_FLAG(port, PE_FLAGS_MSG_DISCARDED)) {
- /*
- * Go back to ready on first AMS message discard
- * (ready states will clear the discard flag)
- */
- pe_set_ready_state(port);
- return;
- }
-
- /*
- * Check the VDM timer, child will be responsible for processing
- * messages and reacting appropriately to unexpected messages.
- */
- if (pd_timer_is_expired(port, PE_TIMER_VDM_RESPONSE)) {
- CPRINTF("VDM %s Response Timeout\n",
- pe[port].tx_type == TCPCI_MSG_SOP ?
- "Port" : "Cable");
- /*
- * Flag timeout so child state can mark appropriate discovery
- * item as failed.
- */
- PE_SET_FLAG(port, PE_FLAGS_VDM_REQUEST_TIMEOUT);
-
- set_state_pe(port, get_last_state_pe(port));
- }
-}
-
-static void pe_vdm_send_request_exit(int port)
-{
- /*
- * Clear TX complete in case child called set_state_pe() before parent
- * could process transmission
- */
- PE_CLR_FLAG(port, PE_FLAGS_INTERRUPTIBLE_AMS);
-
- /* Invalidate TX type so it must be set before next call */
- pe[port].tx_type = TCPCI_MSG_INVALID;
-
- pd_timer_disable(port, PE_TIMER_VDM_RESPONSE);
-}
-
-/**
- * PE_VDM_IDENTITY_REQUEST_CBL
- * Combination of PE_INIT_PORT_VDM_Identity_Request State specific to the
- * cable and PE_SRC_VDM_Identity_Request State.
- * pe[port].tx_type must be set (to SOP') prior to entry.
- */
-static void pe_vdm_identity_request_cbl_entry(int port)
-{
- uint32_t *msg = (uint32_t *)tx_emsg[port].buf;
-
- print_current_state(port);
-
- if (!pe_can_send_sop_prime(port)) {
- /*
- * The parent state already tried to enable SOP' traffic. If it
- * is still disabled, there's nothing left to try.
- */
- pd_set_identity_discovery(port, pe[port].tx_type, PD_DISC_FAIL);
- set_state_pe(port, get_last_state_pe(port));
- return;
- }
-
- msg[0] = VDO(USB_SID_PD, 1,
- VDO_SVDM_VERS(pd_get_vdo_ver(port, pe[port].tx_type)) |
- CMD_DISCOVER_IDENT);
- tx_emsg[port].len = sizeof(uint32_t);
-
- send_data_msg(port, pe[port].tx_type, PD_DATA_VENDOR_DEF);
-
- pe[port].discover_identity_counter++;
-
- /*
- * Valid DiscoverIdentity responses should have at least 4 objects
- * (header, ID header, Cert Stat, Product VDO).
- */
- pe[port].vdm_ack_min_data_objects = 4;
-}
-
-static void pe_vdm_identity_request_cbl_run(int port)
-{
- /* Retrieve the message information */
- uint32_t *payload = (uint32_t *) rx_emsg[port].buf;
- int sop = PD_HEADER_GET_SOP(rx_emsg[port].header);
- uint8_t type = PD_HEADER_TYPE(rx_emsg[port].header);
- uint8_t cnt = PD_HEADER_CNT(rx_emsg[port].header);
- uint8_t ext = PD_HEADER_EXT(rx_emsg[port].header);
-
- switch (parse_vdm_response_common(port)) {
- case VDM_RESULT_WAITING:
- /*
- * The common code didn't parse a message. Handle protocol
- * errors; otherwise, continue waiting.
- */
- if (PE_CHK_FLAG(port, PE_FLAGS_PROTOCOL_ERROR)) {
- /*
- * No Good CRC: See section 6.4.4.3.1 - Discover
- * Identity.
- *
- * Discover Identity Command request sent to SOP' Shall
- * Not cause a Soft Reset if a GoodCRC Message response
- * is not returned since this can indicate a non-PD
- * Capable cable.
- */
- PE_CLR_FLAG(port, PE_FLAGS_PROTOCOL_ERROR);
- set_state_pe(port, get_last_state_pe(port));
- }
- return;
- case VDM_RESULT_NO_ACTION:
- /*
- * If the received message doesn't change the discovery state,
- * there is nothing to do but return to the previous ready
- * state.
- */
- if (get_last_state_pe(port) == PE_SRC_DISCOVERY &&
- (sop != pe[port].tx_type ||
- type != PD_DATA_VENDOR_DEF ||
- cnt == 0 || ext != 0)) {
- /*
- * Unexpected non-VDM received: Before an explicit
- * contract, an unexpected message shall generate a soft
- * reset using the SOP* of the incoming message.
- */
- pe_send_soft_reset(port, sop);
- return;
- }
- break;
- case VDM_RESULT_ACK:
- /* PE_INIT_PORT_VDM_Identity_ACKed embedded here */
- dfp_consume_identity(port, sop, cnt, payload);
-
- /*
- * Note: If port partner runs PD 2.0, we must use PD 2.0 to
- * communicate with the cable plug when in an explicit contract.
- *
- * PD Spec Table 6-2: Revision Interoperability during an
- * Explicit Contract
- */
- if (prl_get_rev(port, TCPCI_MSG_SOP) != PD_REV20)
- prl_set_rev(port, sop,
- PD_HEADER_REV(rx_emsg[port].header));
- break;
- case VDM_RESULT_NAK:
- /* PE_INIT_PORT_VDM_IDENTITY_NAKed embedded here */
- pd_set_identity_discovery(port, pe[port].tx_type, PD_DISC_FAIL);
- break;
- }
-
- /* Return to calling state (PE_{SRC,SNK}_Ready or PE_SRC_Discovery) */
- set_state_pe(port, get_last_state_pe(port));
-}
-
-static void pe_vdm_identity_request_cbl_exit(int port)
-{
- /*
- * When cable GoodCRCs but does not reply, down-rev to PD 2.0 and try
- * again.
- *
- * PD 3.0 Rev 2.0 6.2.1.1.5 Specification Revision
- *
- * "When a Cable Plug does not respond to a Revision 3.0 Discover
- * Identity REQ with a Discover Identity ACK or BUSY the Vconn Source
- * May repeat steps 1-4 using a Revision 2.0 Discover Identity REQ in
- * step 1 before establishing that there is no Cable Plug to
- * communicate with"
- */
- if (PE_CHK_FLAG(port, PE_FLAGS_VDM_REQUEST_TIMEOUT)) {
- PE_CLR_FLAG(port, PE_FLAGS_VDM_REQUEST_TIMEOUT);
- prl_set_rev(port, TCPCI_MSG_SOP_PRIME, PD_REV20);
- }
-
- /*
- * 6.6.15 DiscoverIdentityTimer
- *
- * No more than nDiscoverIdentityCount Discover Identity Messages
- * without a GoodCRC Message response Shall be sent. If no GoodCRC
- * Message response is received after nDiscoverIdentityCount Discover
- * Identity Command requests have been sent by a Port, the Port Shall
- * Not send any further SOP’/SOP’’ Messages.
- */
- if (pe[port].discover_identity_counter >= N_DISCOVER_IDENTITY_COUNT)
- pd_set_identity_discovery(port, pe[port].tx_type,
- PD_DISC_FAIL);
- else if (pe[port].discover_identity_counter ==
- N_DISCOVER_IDENTITY_PD3_0_LIMIT)
- /*
- * Downgrade to PD 2.0 if the partner hasn't replied before
- * all retries are exhausted in case the cable is
- * non-compliant about GoodCRC-ing higher revisions
- */
- prl_set_rev(port, TCPCI_MSG_SOP_PRIME, PD_REV20);
-
- /*
- * Set discover identity timer unless BUSY case already did so.
- */
- if (pd_get_identity_discovery(port, pe[port].tx_type) == PD_DISC_NEEDED
- && pd_timer_is_expired(port, PE_TIMER_DISCOVER_IDENTITY)) {
- /*
- * The tDiscoverIdentity timer is used during an explicit
- * contract when discovering whether a cable is PD capable.
- *
- * Pre-contract, slow the rate Discover Identity commands are
- * sent. This permits operation with captive cable devices that
- * power the SOP' responder from VBUS instead of VCONN.
- */
- pd_timer_enable(port, PE_TIMER_DISCOVER_IDENTITY,
- pe_is_explicit_contract(port)
- ? PD_T_DISCOVER_IDENTITY
- : PE_T_DISCOVER_IDENTITY_NO_CONTRACT);
- }
-
- /* Do not attempt further discovery if identity discovery failed. */
- if (pd_get_identity_discovery(port, pe[port].tx_type) == PD_DISC_FAIL) {
- pd_set_svids_discovery(port, pe[port].tx_type, PD_DISC_FAIL);
- pd_notify_event(port, pe[port].tx_type == TCPCI_MSG_SOP ?
- PD_STATUS_EVENT_SOP_DISC_DONE :
- PD_STATUS_EVENT_SOP_PRIME_DISC_DONE);
- }
-}
-
-/**
- * PE_INIT_PORT_VDM_Identity_Request
- *
- * Specific to SOP requests, as cables require additions for the discover
- * identity counter, must tolerate not receiving a GoodCRC, and need to set the
- * cable revision based on response.
- * pe[port].tx_type must be set (to SOP) prior to entry.
- */
-static void pe_init_port_vdm_identity_request_entry(int port)
-{
- uint32_t *msg = (uint32_t *)tx_emsg[port].buf;
-
- print_current_state(port);
-
- msg[0] = VDO(USB_SID_PD, 1,
- VDO_SVDM_VERS(pd_get_vdo_ver(port, pe[port].tx_type)) |
- CMD_DISCOVER_IDENT);
- tx_emsg[port].len = sizeof(uint32_t);
-
- send_data_msg(port, pe[port].tx_type, PD_DATA_VENDOR_DEF);
-
- /*
- * Valid DiscoverIdentity responses should have at least 4 objects
- * (header, ID header, Cert Stat, Product VDO).
- */
- pe[port].vdm_ack_min_data_objects = 4;
-}
-
-static void pe_init_port_vdm_identity_request_run(int port)
-{
- switch (parse_vdm_response_common(port)) {
- case VDM_RESULT_WAITING:
- /* If common code didn't parse a message, continue waiting. */
- return;
- case VDM_RESULT_NO_ACTION:
- /*
- * If the received message doesn't change the discovery state,
- * there is nothing to do but return to the previous ready
- * state.
- */
- break;
- case VDM_RESULT_ACK: {
- /* Retrieve the message information. */
- uint32_t *payload = (uint32_t *) rx_emsg[port].buf;
- int sop = PD_HEADER_GET_SOP(rx_emsg[port].header);
- uint8_t cnt = PD_HEADER_CNT(rx_emsg[port].header);
-
- /* PE_INIT_PORT_VDM_Identity_ACKed embedded here */
- dfp_consume_identity(port, sop, cnt, payload);
-
- break;
- }
- case VDM_RESULT_NAK:
- /* PE_INIT_PORT_VDM_IDENTITY_NAKed embedded here */
- pd_set_identity_discovery(port, pe[port].tx_type, PD_DISC_FAIL);
- break;
- }
-
- /* Return to calling state (PE_{SRC,SNK}_Ready) */
- set_state_pe(port, get_last_state_pe(port));
-}
-
-static void pe_init_port_vdm_identity_request_exit(int port)
-{
- if (PE_CHK_FLAG(port, PE_FLAGS_VDM_REQUEST_TIMEOUT)) {
- PE_CLR_FLAG(port, PE_FLAGS_VDM_REQUEST_TIMEOUT);
- /*
- * Mark failure to respond as discovery failure.
- *
- * For PD 2.0 partners (6.10.3 Applicability of Structured VDM
- * Commands Note 3):
- *
- * If Structured VDMs are not supported, a Structured VDM
- * Command received by a DFP or UFP Shall be Ignored.
- */
- pd_set_identity_discovery(port, pe[port].tx_type, PD_DISC_FAIL);
- }
-
- /* Do not attempt further discovery if identity discovery failed. */
- if (pd_get_identity_discovery(port, pe[port].tx_type) == PD_DISC_FAIL) {
- pd_set_svids_discovery(port, pe[port].tx_type, PD_DISC_FAIL);
- pd_notify_event(port, pe[port].tx_type == TCPCI_MSG_SOP ?
- PD_STATUS_EVENT_SOP_DISC_DONE :
- PD_STATUS_EVENT_SOP_PRIME_DISC_DONE);
- }
-}
-
-/**
- * PE_INIT_VDM_SVIDs_Request
- *
- * Used for SOP and SOP' requests, selected by pe[port].tx_type prior to entry.
- */
-static void pe_init_vdm_svids_request_entry(int port)
-{
- uint32_t *msg = (uint32_t *)tx_emsg[port].buf;
-
- print_current_state(port);
-
- if (pe[port].tx_type == TCPCI_MSG_SOP_PRIME &&
- !pe_can_send_sop_prime(port)) {
- /*
- * The parent state already tried to enable SOP' traffic. If it
- * is still disabled, there's nothing left to try.
- */
- pd_set_svids_discovery(port, pe[port].tx_type, PD_DISC_FAIL);
- set_state_pe(port, get_last_state_pe(port));
- return;
- }
-
- msg[0] = VDO(USB_SID_PD, 1,
- VDO_SVDM_VERS(pd_get_vdo_ver(port, pe[port].tx_type)) |
- CMD_DISCOVER_SVID);
- tx_emsg[port].len = sizeof(uint32_t);
-
- send_data_msg(port, pe[port].tx_type, PD_DATA_VENDOR_DEF);
-
- /*
- * Valid Discover SVIDs ACKs should have at least 2 objects (VDM header
- * and at least 1 SVID VDO).
- */
- pe[port].vdm_ack_min_data_objects = 2;
-}
-
-static void pe_init_vdm_svids_request_run(int port)
-{
- switch (parse_vdm_response_common(port)) {
- case VDM_RESULT_WAITING:
- /* If common code didn't parse a message, continue waiting. */
- return;
- case VDM_RESULT_NO_ACTION:
- /*
- * If the received message doesn't change the discovery state,
- * there is nothing to do but return to the previous ready
- * state.
- */
- break;
- case VDM_RESULT_ACK: {
- /* Retrieve the message information. */
- uint32_t *payload = (uint32_t *) rx_emsg[port].buf;
- int sop = PD_HEADER_GET_SOP(rx_emsg[port].header);
- uint8_t cnt = PD_HEADER_CNT(rx_emsg[port].header);
-
- /* PE_INIT_VDM_SVIDs_ACKed embedded here */
- dfp_consume_svids(port, sop, cnt, payload);
- break;
- }
- case VDM_RESULT_NAK:
- /* PE_INIT_VDM_SVIDs_NAKed embedded here */
- pd_set_svids_discovery(port, pe[port].tx_type, PD_DISC_FAIL);
- break;
- }
-
- /* Return to calling state (PE_{SRC,SNK}_Ready) */
- set_state_pe(port, get_last_state_pe(port));
-}
-
-static void pe_init_vdm_svids_request_exit(int port)
-{
- if (PE_CHK_FLAG(port, PE_FLAGS_VDM_REQUEST_TIMEOUT)) {
- PE_CLR_FLAG(port, PE_FLAGS_VDM_REQUEST_TIMEOUT);
- /*
- * Mark failure to respond as discovery failure.
- *
- * For PD 2.0 partners (6.10.3 Applicability of Structured VDM
- * Commands Note 3):
- *
- * If Structured VDMs are not supported, a Structured VDM
- * Command received by a DFP or UFP Shall be Ignored.
- */
- pd_set_svids_discovery(port, pe[port].tx_type, PD_DISC_FAIL);
- }
-
- /* If SVID discovery failed, discovery is done at this point */
- if (pd_get_svids_discovery(port, pe[port].tx_type) == PD_DISC_FAIL)
- pd_notify_event(port, pe[port].tx_type == TCPCI_MSG_SOP ?
- PD_STATUS_EVENT_SOP_DISC_DONE :
- PD_STATUS_EVENT_SOP_PRIME_DISC_DONE);
-}
-
-/**
- * PE_INIT_VDM_Modes_Request
- *
- * Used for SOP and SOP' requests, selected by pe[port].tx_type prior to entry.
- */
-static void pe_init_vdm_modes_request_entry(int port)
-{
- uint32_t *msg = (uint32_t *)tx_emsg[port].buf;
- const struct svid_mode_data *mode_data =
- pd_get_next_mode(port, pe[port].tx_type);
- uint16_t svid;
- /*
- * The caller should have checked that there was something to discover
- * before entering this state.
- */
- assert(mode_data);
- assert(mode_data->discovery == PD_DISC_NEEDED);
- svid = mode_data->svid;
-
- print_current_state(port);
-
- if (pe[port].tx_type == TCPCI_MSG_SOP_PRIME &&
- !pe_can_send_sop_prime(port)) {
- /*
- * The parent state already tried to enable SOP' traffic. If it
- * is still disabled, there's nothing left to try.
- */
- pd_set_modes_discovery(port, pe[port].tx_type, svid,
- PD_DISC_FAIL);
- set_state_pe(port, get_last_state_pe(port));
- return;
- }
-
- msg[0] = VDO((uint16_t) svid, 1,
- VDO_SVDM_VERS(pd_get_vdo_ver(port, pe[port].tx_type)) |
- CMD_DISCOVER_MODES);
- tx_emsg[port].len = sizeof(uint32_t);
-
- send_data_msg(port, pe[port].tx_type, PD_DATA_VENDOR_DEF);
-
- /*
- * Valid Discover Modes responses should have at least 2 objects (VDM
- * header and at least 1 mode VDO).
- */
- pe[port].vdm_ack_min_data_objects = 2;
-}
-
-static void pe_init_vdm_modes_request_run(int port)
-{
- const struct svid_mode_data *mode_data;
- uint16_t requested_svid;
-
- mode_data = pd_get_next_mode(port, pe[port].tx_type);
-
- assert(mode_data);
- assert(mode_data->discovery == PD_DISC_NEEDED);
- requested_svid = mode_data->svid;
-
- switch (parse_vdm_response_common(port)) {
- case VDM_RESULT_WAITING:
- /* If common code didn't parse a message, continue waiting. */
- return;
- case VDM_RESULT_NO_ACTION:
- /*
- * If the received message doesn't change the discovery state,
- * there is nothing to do but return to the previous ready
- * state.
- */
- break;
- case VDM_RESULT_ACK: {
- /* Retrieve the message information. */
- uint32_t *payload = (uint32_t *) rx_emsg[port].buf;
- int sop = PD_HEADER_GET_SOP(rx_emsg[port].header);
- uint8_t cnt = PD_HEADER_CNT(rx_emsg[port].header);
- uint16_t response_svid = (uint16_t) PD_VDO_VID(payload[0]);
-
- /*
- * Accept ACK if the request and response SVIDs are equal;
- * otherwise, treat this as a NAK of the request SVID.
- *
- * TODO(b:169242812): support valid mode checking in
- * dfp_consume_modes.
- */
- if (requested_svid == response_svid) {
- /* PE_INIT_VDM_Modes_ACKed embedded here */
- dfp_consume_modes(port, sop, cnt, payload);
- break;
- }
- }
- /* Fall Through */
- case VDM_RESULT_NAK:
- /* PE_INIT_VDM_Modes_NAKed embedded here */
- pd_set_modes_discovery(port, pe[port].tx_type, requested_svid,
- PD_DISC_FAIL);
- break;
- }
-
- /* Return to calling state (PE_{SRC,SNK}_Ready) */
- set_state_pe(port, get_last_state_pe(port));
-}
-
-static void pe_init_vdm_modes_request_exit(int port)
-{
- if (pd_get_modes_discovery(port, pe[port].tx_type) != PD_DISC_NEEDED)
- /* Mode discovery done, notify the AP */
- pd_notify_event(port, pe[port].tx_type == TCPCI_MSG_SOP ?
- PD_STATUS_EVENT_SOP_DISC_DONE :
- PD_STATUS_EVENT_SOP_PRIME_DISC_DONE);
-
-}
-
-/**
- * PE_VDM_REQUEST_DPM
- *
- * Makes a VDM request with contents and SOP* type previously set up by the DPM.
- */
-
-static void pe_vdm_request_dpm_entry(int port)
-{
- print_current_state(port);
-
- if ((pe[port].tx_type == TCPCI_MSG_SOP_PRIME ||
- pe[port].tx_type == TCPCI_MSG_SOP_PRIME_PRIME) &&
- !pe_can_send_sop_prime(port)) {
- /*
- * The parent state already tried to enable SOP' traffic. If it
- * is still disabled, there's nothing left to try.
- */
- dpm_vdm_naked(port, pe[port].tx_type,
- PD_VDO_VID(pe[port].vdm_data[0]),
- PD_VDO_CMD(pe[port].vdm_data[0]));
- set_state_pe(port, get_last_state_pe(port));
- return;
- }
-
- /* Copy Vendor Data Objects (VDOs) into message buffer */
- if (pe[port].vdm_cnt > 0) {
- /* Copy data after header */
- memcpy(&tx_emsg[port].buf,
- (uint8_t *)pe[port].vdm_data,
- pe[port].vdm_cnt * 4);
- /* Update len with the number of VDO bytes */
- tx_emsg[port].len = pe[port].vdm_cnt * 4;
- }
-
- /*
- * Clear the VDM nak'ed flag so that each request is
- * treated separately (NAKs are handled by the
- * DPM layer). Otherwise previous NAKs received will
- * cause the state to exit early.
- */
- PE_CLR_FLAG(port, PE_FLAGS_VDM_REQUEST_NAKED);
- send_data_msg(port, pe[port].tx_type, PD_DATA_VENDOR_DEF);
-
- /*
- * In general, valid VDM ACKs must have a VDM header. Other than that,
- * ACKs must be validated based on the command and SVID.
- */
- pe[port].vdm_ack_min_data_objects = 1;
-}
-
-static void pe_vdm_request_dpm_run(int port)
-{
- uint32_t vdm_hdr;
-
- switch (parse_vdm_response_common(port)) {
- case VDM_RESULT_WAITING:
- /*
- * USB-PD 3.0 Rev 1.1 - 6.4.4.2.5
- * Structured VDM command consists of a command request and a
- * command response (ACK, NAK, or BUSY). An exception is made
- * for the Attention command which shall have no response.
- *
- * Since Attention commands do not have an expected reply,
- * the SVDM command is complete once the Attention command
- * transmit is complete.
- */
- vdm_hdr = pe[port].vdm_data[0];
- if(PD_VDO_SVDM(vdm_hdr) &&
- (PD_VDO_CMD(vdm_hdr) == CMD_ATTENTION)) {
- if (PE_CHK_FLAG(port, PE_FLAGS_TX_COMPLETE)) {
- PE_CLR_FLAG(port, PE_FLAGS_TX_COMPLETE);
- break;
- }
- }
- /*
- * If common code didn't parse a message, and the VDM
- * just sent was not an Attention message, then continue
- * waiting.
- */
- return;
- case VDM_RESULT_NO_ACTION:
- /*
- * If the received message doesn't change the discovery state,
- * there is nothing to do but return to the previous ready
- * state. This includes Attention commands which have no
- * expected SVDM response.
- */
- break;
- case VDM_RESULT_ACK: {
- /* Retrieve the message information. */
- uint32_t *payload = (uint32_t *) rx_emsg[port].buf;
- int sop = PD_HEADER_GET_SOP(rx_emsg[port].header);
- uint8_t cnt = PD_HEADER_CNT(rx_emsg[port].header);
- uint16_t svid = PD_VDO_VID(payload[0]);
- uint8_t vdm_cmd = PD_VDO_CMD(payload[0]);
-
- /*
- * PE initiator VDM-ACKed state for requested VDM, like
- * PE_INIT_VDM_FOO_ACKed, embedded here.
- */
- dpm_vdm_acked(port, sop, cnt, payload);
-
- if (sop == TCPCI_MSG_SOP && svid == USB_SID_DISPLAYPORT &&
- vdm_cmd == CMD_DP_CONFIG) {
- PE_SET_FLAG(port, PE_FLAGS_VDM_SETUP_DONE);
- }
- break;
- }
- case VDM_RESULT_NAK:
- /*
- * PE initiator VDM-NAKed state for requested VDM, like
- * PE_INIT_VDM_FOO_NAKed, embedded here.
- */
- PE_SET_FLAG(port, PE_FLAGS_VDM_SETUP_DONE);
-
- /*
- * Because Not Supported messages or response timeouts are
- * treated as NAKs, there may not be a NAK message to parse.
- * Extract the needed information from the sent VDM.
- */
- dpm_vdm_naked(port, pe[port].tx_type,
- PD_VDO_VID(pe[port].vdm_data[0]),
- PD_VDO_CMD(pe[port].vdm_data[0]));
- break;
- }
-
- /* Return to calling state (PE_{SRC,SNK}_Ready) */
- set_state_pe(port, get_last_state_pe(port));
-}
-
-static void pe_vdm_request_dpm_exit(int port)
-{
- /*
- * Force Tx type to be reset before reentering a VDM state, unless the
- * current VDM request will be resumed.
- */
- if (!PE_CHK_FLAG(port, PE_FLAGS_VDM_REQUEST_CONTINUE))
- pe[port].tx_type = TCPCI_MSG_INVALID;
-}
-
-/**
- * PE_VDM_Response
- */
-static void pe_vdm_response_entry(int port)
-{
- int vdo_len = 0;
- uint32_t *rx_payload;
- uint32_t *tx_payload;
- uint8_t vdo_cmd;
- svdm_rsp_func func = NULL;
-
- print_current_state(port);
-
- /* This is an Interruptible AMS */
- PE_SET_FLAG(port, PE_FLAGS_INTERRUPTIBLE_AMS);
-
- /* Get the message */
- rx_payload = (uint32_t *)rx_emsg[port].buf;
-
- /* Extract VDM command from the VDM header */
- vdo_cmd = PD_VDO_CMD(rx_payload[0]);
- /* This must be a command request to proceed further */
- if (PD_VDO_CMDT(rx_payload[0]) != CMDT_INIT) {
- CPRINTF("ERR:CMDT:%d:%d\n", PD_VDO_CMDT(rx_payload[0]),
- vdo_cmd);
-
- pe_set_ready_state(port);
- return;
- }
-
- tx_payload = (uint32_t *)tx_emsg[port].buf;
- /*
- * Designed in TCPMv1, svdm_response functions use same
- * buffer to take received data and overwrite with response
- * data. To work with this interface, here copy rx data to
- * tx buffer and pass tx_payload to func.
- * TODO(b/166455363): change the interface to pass both rx
- * and tx buffer.
- *
- * The SVDM header is dependent on both VDM command request being
- * replied to and the result of response function. The SVDM command
- * message is copied into tx_payload. tx_payload[0] is the VDM header
- * for the response message. The SVDM response function takes the role
- * of the DPM layer and will indicate the response type (ACK/NAK/BUSY)
- * by its return value (vdo_len)
- * vdo_len > 0 --> ACK
- * vdo_len == 0 --> NAK
- * vdo_len < 0 --> BUSY
- */
- memcpy(tx_payload, rx_payload, PD_HEADER_CNT(rx_emsg[port].header) * 4);
- /*
- * Clear fields in SVDM response message that will be set based on the
- * result of the svdm response function.
- */
- tx_payload[0] &= ~VDO_CMDT_MASK;
- tx_payload[0] &= ~VDO_SVDM_VERS(0x3);
-
- /* Add SVDM structured version being used */
- tx_payload[0] |= VDO_SVDM_VERS(pd_get_vdo_ver(port, TCPCI_MSG_SOP));
-
- /* Use VDM command to select the response handler function */
- switch (vdo_cmd) {
- case CMD_DISCOVER_IDENT:
- func = svdm_rsp.identity;
- break;
- case CMD_DISCOVER_SVID:
- func = svdm_rsp.svids;
- break;
- case CMD_DISCOVER_MODES:
- func = svdm_rsp.modes;
- break;
- case CMD_ENTER_MODE:
- func = svdm_rsp.enter_mode;
- break;
- case CMD_DP_STATUS:
- if (svdm_rsp.amode)
- func = svdm_rsp.amode->status;
- break;
- case CMD_DP_CONFIG:
- if (svdm_rsp.amode)
- func = svdm_rsp.amode->config;
- break;
- case CMD_EXIT_MODE:
- func = svdm_rsp.exit_mode;
- break;
-#ifdef CONFIG_USB_PD_ALT_MODE_DFP
- case CMD_ATTENTION:
- /*
- * attention is only SVDM with no response
- * (just goodCRC) return zero here.
- */
- dfp_consume_attention(port, rx_payload);
- pe_set_ready_state(port);
- return;
-#endif
- default:
- CPRINTF("VDO ERR:CMD:%d\n", vdo_cmd);
- }
-
- /*
- * If the port partner is PD_REV20 and our data role is DFP, we must
- * reply to any SVDM command with a NAK. If the SVDM was an Attention
- * command, it does not have a response, and exits the function above.
- */
- if (func && (prl_get_rev(port, TCPCI_MSG_SOP) != PD_REV20 ||
- pe[port].data_role == PD_ROLE_UFP)) {
- /*
- * Execute SVDM response function selected above and set the
- * correct response type in the VDM header.
- */
- vdo_len = func(port, tx_payload);
- if (vdo_len > 0) {
- tx_payload[0] |= VDO_CMDT(CMDT_RSP_ACK);
- /*
- * If command response is an ACK and if the command was
- * either enter/exit mode, then update the PE modal flag
- * accordingly.
- */
- if (vdo_cmd == CMD_ENTER_MODE)
- PE_SET_FLAG(port, PE_FLAGS_MODAL_OPERATION);
- if (vdo_cmd == CMD_EXIT_MODE)
- PE_CLR_FLAG(port, PE_FLAGS_MODAL_OPERATION);
- } else if (!vdo_len) {
- tx_payload[0] |= VDO_CMDT(CMDT_RSP_NAK);
- vdo_len = 1;
- } else {
- tx_payload[0] |= VDO_CMDT(CMDT_RSP_BUSY);
- vdo_len = 1;
- }
- } else {
- /*
- * Received at VDM command which is not supported. PD 2.0 may
- * NAK or ignore the message (see TD.PD.VNDI.E1. VDM Identity
- * steps), but PD 3.0 must send Not_Supported (PD 3.0 Ver 2.0 +
- * ECNs 2020-12-10 Table 6-64 Response to an incoming
- * VDM or TD.PD.VNDI3.E3 VDM Identity steps)
- */
- if (prl_get_rev(port, TCPCI_MSG_SOP) == PD_REV30) {
- set_state_pe(port, PE_SEND_NOT_SUPPORTED);
- return;
- }
- tx_payload[0] |= VDO_CMDT(CMDT_RSP_NAK);
- vdo_len = 1;
- }
-
- /* Send response message. Note len is in bytes, not VDO objects */
- tx_emsg[port].len = (vdo_len * sizeof(uint32_t));
- send_data_msg(port, TCPCI_MSG_SOP, PD_DATA_VENDOR_DEF);
-}
-
-static void pe_vdm_response_run(int port)
-{
- /*
- * This state waits for a VDM response message to be sent. Return to the
- * ready state once the message has been sent, a protocol error was
- * detected, or if the VDM response msg was discarded based on being
- * interrupted by another rx message. Since VDM sequences are AMS
- * interruptible, there is no need to soft reset regardless of exit
- * reason.
- */
- if (PE_CHK_FLAG(port, PE_FLAGS_TX_COMPLETE) ||
- PE_CHK_FLAG(port, PE_FLAGS_PROTOCOL_ERROR) ||
- PE_CHK_FLAG(port, PE_FLAGS_MSG_DISCARDED)) {
-
- PE_CLR_FLAG(port, PE_FLAGS_TX_COMPLETE |
- PE_FLAGS_PROTOCOL_ERROR |
- PE_FLAGS_MSG_DISCARDED);
-
- pe_set_ready_state(port);
- }
-}
-
-static void pe_vdm_response_exit(int port)
-{
- PE_CLR_FLAG(port, PE_FLAGS_INTERRUPTIBLE_AMS);
-}
-
-/**
- * PE_DEU_SEND_ENTER_USB
- */
-static void pe_enter_usb_entry(int port)
-{
- uint32_t usb4_payload;
-
- print_current_state(port);
-
- if (!IS_ENABLED(CONFIG_USB_PD_USB4)) {
- pe_set_ready_state(port);
- return;
- }
-
- /* Port is already in USB4 mode, do not send enter USB message again */
- if (enter_usb_entry_is_done(port)) {
- pe_set_ready_state(port);
- return;
- }
-
- if ((pe[port].tx_type == TCPCI_MSG_SOP_PRIME ||
- pe[port].tx_type == TCPCI_MSG_SOP_PRIME_PRIME) &&
- !tc_is_vconn_src(port)) {
- if (port_try_vconn_swap(port))
- return;
- }
-
- pe[port].tx_type = TCPCI_MSG_SOP;
- usb4_payload = enter_usb_setup_next_msg(port, &pe[port].tx_type);
-
- if (!usb4_payload) {
- enter_usb_failed(port);
- pe_set_ready_state(port);
- return;
- }
-
- tx_emsg[port].len = sizeof(usb4_payload);
-
- memcpy(tx_emsg[port].buf, &usb4_payload, tx_emsg[port].len);
- send_data_msg(port, pe[port].tx_type, PD_DATA_ENTER_USB);
- pe_sender_response_msg_entry(port);
-}
-
-static void pe_enter_usb_run(int port)
-{
- enum pe_msg_check msg_check;
-
- if (!IS_ENABLED(CONFIG_USB_PD_USB4)) {
- pe_set_ready_state(port);
- return;
- }
-
- /*
- * Check the state of the message sent
- */
- msg_check = pe_sender_response_msg_run(port);
-
- /*
- * Handle Discarded message, return to PE_SNK/SRC_READY
- */
- if (msg_check & PE_MSG_DISCARDED) {
- pe_set_ready_state(port);
- return;
- } else if (msg_check == PE_MSG_SEND_PENDING) {
- /* Wait until message is sent */
- return;
- }
-
- if (pd_timer_is_expired(port, PE_TIMER_SENDER_RESPONSE)) {
- pe_set_ready_state(port);
- enter_usb_failed(port);
- return;
- }
-
- if (PE_CHK_FLAG(port, PE_FLAGS_MSG_RECEIVED)) {
- int cnt = PD_HEADER_CNT(rx_emsg[port].header);
- int type = PD_HEADER_TYPE(rx_emsg[port].header);
- int sop = PD_HEADER_GET_SOP(rx_emsg[port].header);
-
- PE_CLR_FLAG(port, PE_FLAGS_MSG_RECEIVED);
-
- /* Only look at control messages */
- if (cnt == 0) {
- /* Accept message received */
- if (type == PD_CTRL_ACCEPT) {
- enter_usb_accepted(port, sop);
- } else if (type == PD_CTRL_REJECT) {
- enter_usb_rejected(port, sop);
- } else {
- /*
- * Unexpected control message received.
- * Send Soft Reset.
- */
- pe_send_soft_reset(port, sop);
- return;
- }
- } else {
- /* Unexpected data message received. Send Soft reset */
- pe_send_soft_reset(port, sop);
- return;
- }
- pe_set_ready_state(port);
- }
-}
-
-static void pe_enter_usb_exit(int port)
-{
- pe_sender_response_msg_exit(port);
-}
-
-#ifdef CONFIG_USBC_VCONN
-/*
- * PE_VCS_Evaluate_Swap
- */
-static void pe_vcs_evaluate_swap_entry(int port)
-{
- print_current_state(port);
-
- /*
- * Request the DPM for an evaluation of the VCONN Swap request.
- * Note: Ports that are presently the VCONN Source must always
- * accept a VCONN
- */
-
- /*
- * Transition to the PE_VCS_Accept_Swap state when:
- * 1) The Device Policy Manager indicates that a VCONN Swap is ok.
- *
- * Transition to the PE_VCS_Reject_Swap state when:
- * 1) Port is not presently the VCONN Source and
- * 2) The DPM indicates that a VCONN Swap is not ok or
- * 3) The DPM indicates that a VCONN Swap cannot be done at this time.
- */
-
- /* DPM rejects a VCONN Swap and port is not a VCONN source*/
- if (!tc_check_vconn_swap(port) && tc_is_vconn_src(port) < 1) {
- /* NOTE: PE_VCS_Reject_Swap State embedded here */
- send_ctrl_msg(port, TCPCI_MSG_SOP, PD_CTRL_REJECT);
- }
- /* Port is not ready to perform a VCONN swap */
- else if (tc_is_vconn_src(port) < 0) {
- /* NOTE: PE_VCS_Reject_Swap State embedded here */
- send_ctrl_msg(port, TCPCI_MSG_SOP, PD_CTRL_WAIT);
- }
- /* Port is ready to perform a VCONN swap */
- else {
- /* NOTE: PE_VCS_Accept_Swap State embedded here */
- PE_SET_FLAG(port, PE_FLAGS_ACCEPT);
- send_ctrl_msg(port, TCPCI_MSG_SOP, PD_CTRL_ACCEPT);
- }
-}
-
-static void pe_vcs_evaluate_swap_run(int port)
-{
- /* Wait for ACCEPT, WAIT or Reject message to send. */
- if (PE_CHK_FLAG(port, PE_FLAGS_TX_COMPLETE)) {
- PE_CLR_FLAG(port, PE_FLAGS_TX_COMPLETE);
-
- if (PE_CHK_FLAG(port, PE_FLAGS_ACCEPT)) {
- PE_CLR_FLAG(port, PE_FLAGS_ACCEPT);
- /* Accept Message sent and Presently VCONN Source */
- if (tc_is_vconn_src(port))
- set_state_pe(port, PE_VCS_WAIT_FOR_VCONN_SWAP);
- /* Accept Message sent and Not presently VCONN Source */
- else
- set_state_pe(port, PE_VCS_TURN_ON_VCONN_SWAP);
- } else {
- /*
- * Message sent. Transition back to PE_SRC_Ready or
- * PE_SINK_Ready
- */
- pe_set_ready_state(port);
- }
- return;
- }
-
- if (pe_check_outgoing_discard(port))
- return;
-}
-
-/*
- * PE_VCS_Send_Swap
- */
-static void pe_vcs_send_swap_entry(int port)
-{
- print_current_state(port);
-
- /* Send a VCONN_Swap Message */
- send_ctrl_msg(port, TCPCI_MSG_SOP, PD_CTRL_VCONN_SWAP);
- pe_sender_response_msg_entry(port);
-}
-
-static void pe_vcs_send_swap_run(int port)
-{
- uint8_t type;
- uint8_t cnt;
- enum tcpci_msg_type sop;
- enum pe_msg_check msg_check;
-
- /*
- * Check the state of the message sent
- */
- msg_check = pe_sender_response_msg_run(port);
-
- if ((msg_check & PE_MSG_SENT) &&
- PE_CHK_FLAG(port, PE_FLAGS_MSG_RECEIVED)) {
- PE_CLR_FLAG(port, PE_FLAGS_MSG_RECEIVED);
-
- /* Increment once message has successfully sent */
- pe[port].vconn_swap_counter++;
-
- type = PD_HEADER_TYPE(rx_emsg[port].header);
- cnt = PD_HEADER_CNT(rx_emsg[port].header);
- sop = PD_HEADER_GET_SOP(rx_emsg[port].header);
-
- /* Only look at control messages */
- if (cnt == 0) {
- /*
- * Transition to the PE_VCS_Wait_For_VCONN state when:
- * 1) Accept Message Received and
- * 2) The Port is presently the VCONN Source.
- *
- * Transition to the PE_VCS_Turn_On_VCONN state when:
- * 1) Accept Message Received and
- * 2) The Port is not presently the VCONN Source.
- */
- if (type == PD_CTRL_ACCEPT) {
- if (tc_is_vconn_src(port)) {
- set_state_pe(port,
- PE_VCS_WAIT_FOR_VCONN_SWAP);
- } else {
- set_state_pe(port,
- PE_VCS_TURN_ON_VCONN_SWAP);
- }
- return;
- }
- /*
- * Transition back to either the PE_SRC_Ready or
- * PE_SNK_Ready state when:
- * 2) Reject message is received or
- * 3) Wait message Received.
- */
- if (type == PD_CTRL_REJECT || type == PD_CTRL_WAIT) {
- pe_set_ready_state(port);
- return;
- }
-
- /*
- * The Policy Engine May transition to the
- * PE_VCS_Force_Vconn state when:
- * - A Not_Supported Message is received and
- * - The Port is not presently the VCONN Source
- */
- if (type == PD_CTRL_NOT_SUPPORTED) {
- if (IS_ENABLED(CONFIG_USB_PD_REV30) &&
- !tc_is_vconn_src(port))
- set_state_pe(port, PE_VCS_FORCE_VCONN);
- else
- pe_set_ready_state(port);
- return;
- }
- }
- /*
- * Unexpected Message Received, send soft reset with SOP* of
- * incoming message.
- */
- pe_send_soft_reset(port, sop);
- return;
- }
-
- /*
- * Transition back to either the PE_SRC_Ready or
- * PE_SNK_Ready state when:
- * 1) SenderResponseTimer Timeout
- * 2) Message was discarded.
- */
- if ((msg_check & PE_MSG_DISCARDED) ||
- pd_timer_is_expired(port, PE_TIMER_SENDER_RESPONSE))
- pe_set_ready_state(port);
-}
-
-static void pe_vcs_send_swap_exit(int port)
-{
- pe_sender_response_msg_exit(port);
-}
-
-/*
- * PE_VCS_Wait_for_VCONN_Swap
- */
-static void pe_vcs_wait_for_vconn_swap_entry(int port)
-{
- print_current_state(port);
-
- /* Start the VCONNOnTimer */
- pd_timer_enable(port, PE_TIMER_VCONN_ON, PD_T_VCONN_SOURCE_ON);
-
- /*
- * The USB PD 3.0 spec indicates that the initial VCONN source
- * shall cease sourcing VCONN within tVCONNSourceOff (25ms)
- * after receiving the PS_RDY message. However, some partners
- * begin sending SOP' messages only 1 ms after sending PS_RDY
- * during VCONN swap.
- *
- * Preemptively disable receipt of SOP' and SOP'' messages while
- * we wait for PS_RDY so we don't attempt to process messages
- * directed at the cable.
- *
- * We continue to source VCONN while we wait as required by the
- * spec.
- */
- tcpm_sop_prime_enable(port, false);
-}
-
-static void pe_vcs_wait_for_vconn_swap_run(int port)
-{
- /*
- * Transition to the PE_VCS_Turn_Off_VCONN state when:
- * 1) A PS_RDY Message is received.
- */
- if (PE_CHK_FLAG(port, PE_FLAGS_MSG_RECEIVED)) {
- /*
- * PS_RDY message received
- *
- * Note: intentionally leave the receive flag set to indicate
- * our route on exit when PS_RDY is received.
- */
- if ((PD_HEADER_CNT(rx_emsg[port].header) == 0) &&
- (PD_HEADER_EXT(rx_emsg[port].header) == 0) &&
- (PD_HEADER_TYPE(rx_emsg[port].header) == PD_CTRL_PS_RDY)) {
- set_state_pe(port, PE_VCS_TURN_OFF_VCONN_SWAP);
- return;
- } else {
- /*
- * Unexpected message received - reset with the SOP* of
- * the incoming message.
- */
- PE_CLR_FLAG(port, PE_FLAGS_MSG_RECEIVED);
- pe_send_soft_reset(port,
- PD_HEADER_GET_SOP(rx_emsg[port].header));
- return;
- }
- }
-
- /*
- * Transition to either the PE_SRC_Hard_Reset or
- * PE_SNK_Hard_Reset state when:
- * 1) The VCONNOnTimer times out.
- */
- if (pd_timer_is_expired(port, PE_TIMER_VCONN_ON)) {
- if (pe[port].power_role == PD_ROLE_SOURCE)
- set_state_pe(port, PE_SRC_HARD_RESET);
- else
- set_state_pe(port, PE_SNK_HARD_RESET);
- }
-}
-
-static void pe_vcs_wait_for_vconn_swap_exit(int port)
-{
- /*
- * If we exited without getting PS_RDY, re-enable SOP' messaging since
- * we are still the Vconn source.
- */
- if (PE_CHK_FLAG(port, PE_FLAGS_MSG_RECEIVED))
- PE_CLR_FLAG(port, PE_FLAGS_MSG_RECEIVED);
- else
- tcpm_sop_prime_enable(port, true);
-
- pd_timer_disable(port, PE_TIMER_VCONN_ON);
-}
-
-/*
- * PE_VCS_Turn_On_VCONN_Swap
- */
-static void pe_vcs_turn_on_vconn_swap_entry(int port)
-{
- print_current_state(port);
-
- /* Request DPM to turn on VCONN */
- pd_request_vconn_swap_on(port);
-}
-
-static void pe_vcs_turn_on_vconn_swap_run(int port)
-{
-
- /*
- * Transition to the PE_VCS_Send_Ps_Rdy state when:
- * 1) The Port’s VCONN is on.
- */
- if (pd_timer_is_disabled(port, PE_TIMER_TIMEOUT) &&
- PE_CHK_FLAG(port, PE_FLAGS_VCONN_SWAP_COMPLETE)) {
- PE_CLR_FLAG(port, PE_FLAGS_VCONN_SWAP_COMPLETE);
- pd_timer_enable(port, PE_TIMER_TIMEOUT,
- CONFIG_USBC_VCONN_SWAP_DELAY_US);
- }
-
- if (pd_timer_is_expired(port, PE_TIMER_TIMEOUT))
- set_state_pe(port, PE_VCS_SEND_PS_RDY_SWAP);
-}
-
-static void pe_vcs_turn_on_vconn_swap_exit(int port)
-{
- pd_timer_disable(port, PE_TIMER_TIMEOUT);
-}
-
-/*
- * PE_VCS_Turn_Off_VCONN_Swap
- */
-static void pe_vcs_turn_off_vconn_swap_entry(int port)
-{
- print_current_state(port);
-
- /* Request DPM to turn off VCONN */
- pd_request_vconn_swap_off(port);
-}
-
-static void pe_vcs_turn_off_vconn_swap_run(int port)
-{
- /* Wait for VCONN to turn off */
- if (PE_CHK_FLAG(port, PE_FLAGS_VCONN_SWAP_COMPLETE)) {
- PE_CLR_FLAG(port, PE_FLAGS_VCONN_SWAP_COMPLETE);
-
- /*
- * A VCONN Swap Shall reset the DiscoverIdentityCounter
- * to zero
- */
- pe[port].discover_identity_counter = 0;
- pe[port].dr_swap_attempt_counter = 0;
-
- pe_set_ready_state(port);
- return;
- }
-}
-
-/*
- * PE_VCS_Send_PS_Rdy_Swap
- */
-static void pe_vcs_send_ps_rdy_swap_entry(int port)
-{
- print_current_state(port);
-
- /* Check for any interruptions to this non-interruptible AMS */
- if (PE_CHK_FLAG(port, PE_FLAGS_MSG_RECEIVED)) {
- enum tcpci_msg_type sop =
- PD_HEADER_GET_SOP(rx_emsg[port].header);
-
- PE_CLR_FLAG(port, PE_FLAGS_MSG_RECEIVED);
-
- /* Soft reset with the SOP* of the incoming message */
- pe_send_soft_reset(port, sop);
- return;
- }
-
- /* Send a PS_RDY Message */
- send_ctrl_msg(port, TCPCI_MSG_SOP, PD_CTRL_PS_RDY);
-}
-
-static void pe_vcs_send_ps_rdy_swap_run(int port)
-{
- /*
- * After a VCONN Swap the VCONN Source needs to reset
- * the Cable Plug’s Protocol Layer in order to ensure
- * MessageID synchronization.
- */
- if (PE_CHK_FLAG(port, PE_FLAGS_TX_COMPLETE)) {
- PE_CLR_FLAG(port, PE_FLAGS_TX_COMPLETE);
- /*
- * A VCONN Swap Shall reset the
- * DiscoverIdentityCounter to zero
- */
- pe[port].discover_identity_counter = 0;
- pe[port].dr_swap_attempt_counter = 0;
-
- /* A SOP' soft reset is required after VCONN swap */
- pd_dpm_request(port, DPM_REQUEST_SOP_PRIME_SOFT_RESET_SEND);
- pe_set_ready_state(port);
- }
-
- if (pe_check_outgoing_discard(port))
- return;
-
- if (PE_CHK_FLAG(port, PE_FLAGS_PROTOCOL_ERROR)) {
- PE_CLR_FLAG(port, PE_FLAGS_PROTOCOL_ERROR);
- /* PS_RDY didn't send, soft reset */
- pe_send_soft_reset(port, TCPCI_MSG_SOP);
- }
-}
-
-/*
- * PE_VCS_Force_Vconn
- */
-__maybe_unused static void pe_vcs_force_vconn_entry(int port)
-{
- print_current_state(port);
-
- /* Request DPM to turn on VCONN */
- pd_request_vconn_swap_on(port);
-}
-
-__maybe_unused static void pe_vcs_force_vconn_run(int port)
-{
- /*
- * The Policy Engine Shall transition back to either the PE_SRC_Ready
- * or PE_SNK_Ready state when:
- * 1) The Port’s VCONN is on.
- *
- * Note we'll wait CONFIG_USBC_VCONN_SWAP_DELAY_US, as defined by the
- * board, to ensure Vconn is on.
- */
- if (pd_timer_is_disabled(port, PE_TIMER_TIMEOUT) &&
- PE_CHK_FLAG(port, PE_FLAGS_VCONN_SWAP_COMPLETE)) {
- PE_CLR_FLAG(port, PE_FLAGS_VCONN_SWAP_COMPLETE);
- pd_timer_enable(port, PE_TIMER_TIMEOUT,
- CONFIG_USBC_VCONN_SWAP_DELAY_US);
- }
-
- if (pd_timer_is_expired(port, PE_TIMER_TIMEOUT)) {
- /*
- * Note: A cable soft reset shouldn't be necessary as a
- * Not_Supported reply means the partner doesn't support
- * sourcing Vconn and did not communicate with the cable.
- */
- pe_set_ready_state(port);
- return;
- }
-}
-
-__maybe_unused static void pe_vcs_force_vconn_exit(int port)
-{
- pd_timer_disable(port, PE_TIMER_TIMEOUT);
-}
-
-/*
- * PE_VCS_CBL_SEND_SOFT_RESET
- * Note - Entry is only when directed by the DPM. Protocol errors are handled
- * by the PE_SEND_SOFT_RESET state.
- */
-static void pe_vcs_cbl_send_soft_reset_entry(int port)
-{
- print_current_state(port);
-
- if (!pe_can_send_sop_prime(port)) {
- /*
- * If we're not VCONN source, return the appropriate state.
- * A VCONN swap re-triggers sending SOP' soft reset
- */
- if (pe_is_explicit_contract(port)) {
- /* Return to PE_{SRC,SNK}_Ready state */
- pe_set_ready_state(port);
- } else {
- /*
- * Not in Explicit Contract, so we must be a SRC,
- * return to PE_Src_Send_Capabilities.
- */
- set_state_pe(port, PE_SRC_SEND_CAPABILITIES);
- }
- return;
- }
-
- send_ctrl_msg(port, TCPCI_MSG_SOP_PRIME, PD_CTRL_SOFT_RESET);
- pe_sender_response_msg_entry(port);
-}
-
-static void pe_vcs_cbl_send_soft_reset_run(int port)
-{
- bool cable_soft_reset_complete = false;
- enum pe_msg_check msg_check;
-
- msg_check = pe_sender_response_msg_run(port);
-
- /* Got ACCEPT or REJECT from Cable Plug */
- if ((msg_check & PE_MSG_SENT) &&
- PE_CHK_FLAG(port, PE_FLAGS_MSG_RECEIVED)) {
- PE_CLR_FLAG(port, PE_FLAGS_MSG_RECEIVED);
- cable_soft_reset_complete = true;
-
- /*
- * Note: If port partner runs PD 2.0, we must use PD 2.0 to
- * communicate with the cable plug when in an explicit contract.
- *
- * PD Spec Table 6-2: Revision Interoperability during an
- * Explicit Contract
- */
- if (prl_get_rev(port, TCPCI_MSG_SOP) != PD_REV20)
- prl_set_rev(port, TCPCI_MSG_SOP_PRIME,
- PD_HEADER_REV(rx_emsg[port].header));
- }
-
- /* No GoodCRC received, cable is not present */
- if (PE_CHK_FLAG(port, PE_FLAGS_PROTOCOL_ERROR)) {
- PE_CLR_FLAG(port, PE_FLAGS_PROTOCOL_ERROR);
- /*
- * TODO(b/171823328): TCPMv2: Implement cable reset
- * Cable reset will only be done here if we know for certain
- * a cable is present (we've received the SOP' DiscId response).
- */
- cable_soft_reset_complete = true;
- }
-
- if (cable_soft_reset_complete ||
- pd_timer_is_expired(port, PE_TIMER_SENDER_RESPONSE) ||
- (msg_check & PE_MSG_DISCARDED)) {
- if (pe_is_explicit_contract(port)) {
- /* Return to PE_{SRC,SNK}_Ready state */
- pe_set_ready_state(port);
- } else {
- /*
- * Not in Explicit Contract, so we must be a SRC,
- * return to PE_Src_Send_Capabilities.
- */
- set_state_pe(port, PE_SRC_SEND_CAPABILITIES);
- }
- }
-}
-
-static void pe_vcs_cbl_send_soft_reset_exit(int port)
-{
- pe_sender_response_msg_exit(port);
-}
-
-#endif /* CONFIG_USBC_VCONN */
-
-/*
- * PE_DR_SNK_Get_Sink_Cap and PE_SRC_Get_Sink_Cap State (shared)
- */
-static void pe_dr_get_sink_cap_entry(int port)
-{
- print_current_state(port);
-
- /* Send a Get Sink Cap Message */
- send_ctrl_msg(port, TCPCI_MSG_SOP, PD_CTRL_GET_SINK_CAP);
- pe_sender_response_msg_entry(port);
-}
-
-static void pe_dr_get_sink_cap_run(int port)
-{
- int type;
- int cnt;
- int ext;
- enum pe_msg_check msg_check;
- enum tcpci_msg_type sop;
-
- /*
- * Check the state of the message sent
- */
- msg_check = pe_sender_response_msg_run(port);
-
- /*
- * Transition to PE_[SRC,SNK]_Ready when:
- * 1) A Sink_Capabilities Message is received
- * 2) Or SenderResponseTimer times out
- * 3) Or a Reject Message is received.
- *
- * Transition to PE_SEND_SOFT_RESET state when:
- * 1) An unexpected message is received
- */
- if ((msg_check & PE_MSG_SENT) &&
- PE_CHK_FLAG(port, PE_FLAGS_MSG_RECEIVED)) {
- PE_CLR_FLAG(port, PE_FLAGS_MSG_RECEIVED);
-
- type = PD_HEADER_TYPE(rx_emsg[port].header);
- cnt = PD_HEADER_CNT(rx_emsg[port].header);
- ext = PD_HEADER_EXT(rx_emsg[port].header);
- sop = PD_HEADER_GET_SOP(rx_emsg[port].header);
-
- if (ext == 0 && sop == TCPCI_MSG_SOP) {
- if ((cnt > 0) && (type == PD_DATA_SINK_CAP)) {
- uint32_t *payload =
- (uint32_t *)rx_emsg[port].buf;
- uint8_t cap_cnt = rx_emsg[port].len /
- sizeof(uint32_t);
-
- pe_set_snk_caps(port, cap_cnt, payload);
-
- dpm_evaluate_sink_fixed_pdo(port, payload[0]);
- pe_set_ready_state(port);
- return;
- } else if (cnt == 0 && (type == PD_CTRL_REJECT ||
- type == PD_CTRL_NOT_SUPPORTED)) {
- pe_set_ready_state(port);
- return;
- }
- /* Unexpected messages fall through to soft reset */
- }
-
- pe_send_soft_reset(port, sop);
- return;
- }
-
- /*
- * Transition to PE_[SRC,SNK]_Ready state when:
- * 1) SenderResponseTimer times out.
- * 2) Message was discarded.
- */
- if ((msg_check & PE_MSG_DISCARDED) ||
- pd_timer_is_expired(port, PE_TIMER_SENDER_RESPONSE))
- pe_set_ready_state(port);
-}
-
-static void pe_dr_get_sink_cap_exit(int port)
-{
- pe_sender_response_msg_exit(port);
-}
-
-/*
- * PE_DR_SNK_Give_Source_Cap
- */
-static void pe_dr_snk_give_source_cap_entry(int port)
-{
- print_current_state(port);
-
- /* Send source capabilities. */
- send_source_cap(port);
-}
-
-static void pe_dr_snk_give_source_cap_run(int port)
-{
- /*
- * Transition back to PE_SNK_Ready when the Source_Capabilities message
- * has been successfully sent.
- *
- * Get Source Capabilities AMS is uninterruptible, but in case the
- * partner violates the spec then send a soft reset rather than get
- * stuck here.
- */
- if (PE_CHK_FLAG(port, PE_FLAGS_TX_COMPLETE)) {
- PE_CLR_FLAG(port, PE_FLAGS_TX_COMPLETE);
- set_state_pe(port, PE_SNK_READY);
- } else if (PE_CHK_FLAG(port, PE_FLAGS_MSG_DISCARDED)) {
- pe_send_soft_reset(port, TCPCI_MSG_SOP);
- }
-}
-
-/*
- * PE_DR_SRC_Get_Source_Cap
- */
-static void pe_dr_src_get_source_cap_entry(int port)
-{
- print_current_state(port);
-
- /* Send a Get_Source_Cap Message */
- tx_emsg[port].len = 0;
- send_ctrl_msg(port, TCPCI_MSG_SOP, PD_CTRL_GET_SOURCE_CAP);
- pe_sender_response_msg_entry(port);
-}
-
-static void pe_dr_src_get_source_cap_run(int port)
-{
- int type;
- int cnt;
- int ext;
- enum pe_msg_check msg_check;
-
- /*
- * Check the state of the message sent
- */
- msg_check = pe_sender_response_msg_run(port);
-
- /*
- * Transition to PE_SRC_Ready when:
- * 1) A Source Capabilities Message is received.
- * 2) A Reject Message is received.
- */
- if ((msg_check & PE_MSG_SENT) &&
- PE_CHK_FLAG(port, PE_FLAGS_MSG_RECEIVED)) {
- PE_CLR_FLAG(port, PE_FLAGS_MSG_RECEIVED);
-
- type = PD_HEADER_TYPE(rx_emsg[port].header);
- cnt = PD_HEADER_CNT(rx_emsg[port].header);
- ext = PD_HEADER_EXT(rx_emsg[port].header);
-
- if (ext == 0) {
- if ((cnt > 0) && (type == PD_DATA_SOURCE_CAP)) {
- uint32_t *payload =
- (uint32_t *)rx_emsg[port].buf;
-
- pd_set_src_caps(port, cnt, payload);
-
- /*
- * If we'd prefer to charge from this partner,
- * then propose a PR swap.
- */
- if (pd_can_charge_from_device(port, cnt,
- payload))
- pd_request_power_swap(port);
-
- /*
- * Report dual role power capability to the
- * charge manager if present
- */
- if (IS_ENABLED(CONFIG_CHARGE_MANAGER) &&
- pd_get_partner_dual_role_power(port))
- charge_manager_update_dualrole(port,
- CAP_DUALROLE);
-
- set_state_pe(port, PE_SRC_READY);
- } else if ((cnt == 0) && (type == PD_CTRL_REJECT ||
- type == PD_CTRL_NOT_SUPPORTED)) {
- pd_set_src_caps(port, -1, NULL);
- set_state_pe(port, PE_SRC_READY);
- } else {
- /*
- * On protocol error, consider source cap
- * retrieval a failure
- */
- pd_set_src_caps(port, -1, NULL);
- set_state_pe(port, PE_SEND_SOFT_RESET);
- }
- return;
- } else {
- pd_set_src_caps(port, -1, NULL);
- set_state_pe(port, PE_SEND_SOFT_RESET);
- return;
- }
- }
-
- /*
- * Transition to PE_SRC_Ready state when:
- * 1) the SenderResponseTimer times out.
- * 2) Message was discarded.
- */
- if ((msg_check & PE_MSG_DISCARDED) ||
- pd_timer_is_expired(port, PE_TIMER_SENDER_RESPONSE))
- set_state_pe(port, PE_SRC_READY);
-}
-
-static void pe_dr_src_get_source_cap_exit(int port)
-{
- pe_sender_response_msg_exit(port);
-}
-
-const uint32_t * const pd_get_src_caps(int port)
-{
- return pe[port].src_caps;
-}
-
-void pd_set_src_caps(int port, int cnt, uint32_t *src_caps)
-{
- int i;
-
- pe[port].src_cap_cnt = cnt;
-
- for (i = 0; i < cnt; i++)
- pe[port].src_caps[i] = *src_caps++;
-}
-
-uint8_t pd_get_src_cap_cnt(int port)
-{
- if (pe[port].src_cap_cnt > 0)
- return pe[port].src_cap_cnt;
-
- return 0;
-}
-
-/* Track access to the PD discovery structures during HC execution */
-uint32_t task_access[CONFIG_USB_PD_PORT_MAX_COUNT][DISCOVERY_TYPE_COUNT];
-
-void pd_dfp_discovery_init(int port)
-{
- atomic_or(&task_access[port][TCPCI_MSG_SOP], BIT(task_get_current()));
- atomic_or(&task_access[port][TCPCI_MSG_SOP_PRIME],
- BIT(task_get_current()));
-
- memset(pe[port].discovery, 0, sizeof(pe[port].discovery));
-
-}
-
-void pd_dfp_mode_init(int port)
-{
- /*
- * Clear the VDM Setup Done and Modal Operation flags so we will
- * have a fresh discovery
- */
- PE_CLR_FLAG(port, PE_FLAGS_VDM_SETUP_DONE |
- PE_FLAGS_MODAL_OPERATION);
-
- memset(pe[port].partner_amodes, 0, sizeof(pe[port].partner_amodes));
-
- /* Reset the DPM and DP modules to enable alternate mode entry. */
- dpm_init(port);
- dp_init(port);
-
- if (IS_ENABLED(CONFIG_USB_PD_TBT_COMPAT_MODE))
- tbt_init(port);
-
- if (IS_ENABLED(CONFIG_USB_PD_USB4))
- enter_usb_init(port);
-
- if (IS_ENABLED(CONFIG_USB_PD_ALT_MODE_UFP_DP))
- pd_ufp_set_dp_opos(port, 0);
-}
-
-__maybe_unused void pd_discovery_access_clear(int port,
- enum tcpci_msg_type type)
-{
- if (!IS_ENABLED(CONFIG_USB_PD_ALT_MODE_DFP))
- assert(0);
-
- atomic_clear_bits(&task_access[port][type], 0xFFFFFFFF);
-}
-
-__maybe_unused bool pd_discovery_access_validate(int port,
- enum tcpci_msg_type type)
-{
- if (!IS_ENABLED(CONFIG_USB_PD_ALT_MODE_DFP))
- assert(0);
-
- return !(task_access[port][type] & ~BIT(task_get_current()));
-}
-
-__maybe_unused struct pd_discovery *pd_get_am_discovery_and_notify_access(
- int port, enum tcpci_msg_type type)
-{
- atomic_or(&task_access[port][type], BIT(task_get_current()));
- return (struct pd_discovery *)pd_get_am_discovery(port, type);
-}
-
-__maybe_unused const struct pd_discovery *pd_get_am_discovery(int port,
- enum tcpci_msg_type type)
-{
- if (!IS_ENABLED(CONFIG_USB_PD_ALT_MODE_DFP))
- assert(0);
- ASSERT(type < DISCOVERY_TYPE_COUNT);
-
- return &pe[port].discovery[type];
-}
-
-__maybe_unused struct partner_active_modes *pd_get_partner_active_modes(
- int port, enum tcpci_msg_type type)
-{
- if (!IS_ENABLED(CONFIG_USB_PD_ALT_MODE_DFP))
- assert(0);
- ASSERT(type < AMODE_TYPE_COUNT);
- return &pe[port].partner_amodes[type];
-}
-
-__maybe_unused void pd_set_dfp_enter_mode_flag(int port, bool set)
-{
- if (!IS_ENABLED(CONFIG_USB_PD_ALT_MODE_DFP))
- assert(0);
-
- if (set)
- PE_SET_FLAG(port, PE_FLAGS_MODAL_OPERATION);
- else
- PE_CLR_FLAG(port, PE_FLAGS_MODAL_OPERATION);
-}
-
-const char *pe_get_current_state(int port)
-{
- if (pe_is_running(port) && IS_ENABLED(USB_PD_DEBUG_LABELS))
- return pe_state_names[get_state_pe(port)];
- else
- return "";
-}
-
-uint32_t pe_get_flags(int port)
-{
- return pe[port].flags;
-}
-
-static __const_data const struct usb_state pe_states[] = {
- /* Super States */
-#ifdef CONFIG_USB_PD_REV30
- [PE_PRS_FRS_SHARED] = {
- .entry = pe_prs_frs_shared_entry,
- .exit = pe_prs_frs_shared_exit,
- },
-#endif
- [PE_VDM_SEND_REQUEST] = {
- .entry = pe_vdm_send_request_entry,
- .run = pe_vdm_send_request_run,
- .exit = pe_vdm_send_request_exit,
- },
-
- /* Normal States */
- [PE_SRC_STARTUP] = {
- .entry = pe_src_startup_entry,
- .run = pe_src_startup_run,
- .exit = pe_src_startup_exit,
- },
- [PE_SRC_DISCOVERY] = {
- .entry = pe_src_discovery_entry,
- .run = pe_src_discovery_run,
- },
- [PE_SRC_SEND_CAPABILITIES] = {
- .entry = pe_src_send_capabilities_entry,
- .run = pe_src_send_capabilities_run,
- .exit = pe_src_send_capabilities_exit,
- },
- [PE_SRC_NEGOTIATE_CAPABILITY] = {
- .entry = pe_src_negotiate_capability_entry,
- },
- [PE_SRC_TRANSITION_SUPPLY] = {
- .entry = pe_src_transition_supply_entry,
- .run = pe_src_transition_supply_run,
- .exit = pe_src_transition_supply_exit,
- },
- [PE_SRC_READY] = {
- .entry = pe_src_ready_entry,
- .run = pe_src_ready_run,
- },
- [PE_SRC_DISABLED] = {
- .entry = pe_src_disabled_entry,
- },
- [PE_SRC_CAPABILITY_RESPONSE] = {
- .entry = pe_src_capability_response_entry,
- .run = pe_src_capability_response_run,
- },
- [PE_SRC_HARD_RESET] = {
- .entry = pe_src_hard_reset_entry,
- .run = pe_src_hard_reset_run,
- .exit = pe_src_hard_reset_exit,
- },
- [PE_SRC_HARD_RESET_RECEIVED] = {
- .entry = pe_src_hard_reset_received_entry,
- .run = pe_src_hard_reset_received_run,
- .exit = pe_src_hard_reset_received_exit,
- },
- [PE_SRC_TRANSITION_TO_DEFAULT] = {
- .entry = pe_src_transition_to_default_entry,
- .run = pe_src_transition_to_default_run,
- },
- [PE_SNK_STARTUP] = {
- .entry = pe_snk_startup_entry,
- .run = pe_snk_startup_run,
- },
- [PE_SNK_DISCOVERY] = {
- .entry = pe_snk_discovery_entry,
- .run = pe_snk_discovery_run,
- },
- [PE_SNK_WAIT_FOR_CAPABILITIES] = {
- .entry = pe_snk_wait_for_capabilities_entry,
- .run = pe_snk_wait_for_capabilities_run,
- .exit = pe_snk_wait_for_capabilities_exit,
- },
- [PE_SNK_EVALUATE_CAPABILITY] = {
- .entry = pe_snk_evaluate_capability_entry,
- },
- [PE_SNK_SELECT_CAPABILITY] = {
- .entry = pe_snk_select_capability_entry,
- .run = pe_snk_select_capability_run,
- .exit = pe_snk_select_capability_exit,
- },
- [PE_SNK_READY] = {
- .entry = pe_snk_ready_entry,
- .run = pe_snk_ready_run,
- },
- [PE_SNK_HARD_RESET] = {
- .entry = pe_snk_hard_reset_entry,
- .run = pe_snk_hard_reset_run,
- },
- [PE_SNK_TRANSITION_TO_DEFAULT] = {
- .entry = pe_snk_transition_to_default_entry,
- .run = pe_snk_transition_to_default_run,
- },
- [PE_SNK_GIVE_SINK_CAP] = {
- .entry = pe_snk_give_sink_cap_entry,
- .run = pe_snk_give_sink_cap_run,
- },
- [PE_SNK_GET_SOURCE_CAP] = {
- .entry = pe_snk_get_source_cap_entry,
- .run = pe_snk_get_source_cap_run,
- },
- [PE_SNK_TRANSITION_SINK] = {
- .entry = pe_snk_transition_sink_entry,
- .run = pe_snk_transition_sink_run,
- .exit = pe_snk_transition_sink_exit,
- },
- [PE_SEND_SOFT_RESET] = {
- .entry = pe_send_soft_reset_entry,
- .run = pe_send_soft_reset_run,
- .exit = pe_send_soft_reset_exit,
- },
- [PE_SOFT_RESET] = {
- .entry = pe_soft_reset_entry,
- .run = pe_soft_reset_run,
- },
- [PE_SEND_NOT_SUPPORTED] = {
- .entry = pe_send_not_supported_entry,
- .run = pe_send_not_supported_run,
- },
- [PE_SRC_PING] = {
- .entry = pe_src_ping_entry,
- .run = pe_src_ping_run,
- },
- [PE_DRS_EVALUATE_SWAP] = {
- .entry = pe_drs_evaluate_swap_entry,
- .run = pe_drs_evaluate_swap_run,
- },
- [PE_DRS_CHANGE] = {
- .entry = pe_drs_change_entry,
- .run = pe_drs_change_run,
- },
- [PE_DRS_SEND_SWAP] = {
- .entry = pe_drs_send_swap_entry,
- .run = pe_drs_send_swap_run,
- .exit = pe_drs_send_swap_exit,
- },
- [PE_PRS_SRC_SNK_EVALUATE_SWAP] = {
- .entry = pe_prs_src_snk_evaluate_swap_entry,
- .run = pe_prs_src_snk_evaluate_swap_run,
- },
- [PE_PRS_SRC_SNK_TRANSITION_TO_OFF] = {
- .entry = pe_prs_src_snk_transition_to_off_entry,
- .run = pe_prs_src_snk_transition_to_off_run,
- .exit = pe_prs_src_snk_transition_to_off_exit,
- },
- [PE_PRS_SRC_SNK_ASSERT_RD] = {
- .entry = pe_prs_src_snk_assert_rd_entry,
- .run = pe_prs_src_snk_assert_rd_run,
- },
- [PE_PRS_SRC_SNK_WAIT_SOURCE_ON] = {
- .entry = pe_prs_src_snk_wait_source_on_entry,
- .run = pe_prs_src_snk_wait_source_on_run,
- .exit = pe_prs_src_snk_wait_source_on_exit,
- },
- [PE_PRS_SRC_SNK_SEND_SWAP] = {
- .entry = pe_prs_src_snk_send_swap_entry,
- .run = pe_prs_src_snk_send_swap_run,
- .exit = pe_prs_src_snk_send_swap_exit,
- },
- [PE_PRS_SNK_SRC_EVALUATE_SWAP] = {
- .entry = pe_prs_snk_src_evaluate_swap_entry,
- .run = pe_prs_snk_src_evaluate_swap_run,
- },
- /*
- * Some of the Power Role Swap actions are shared with the very
- * similar actions of Fast Role Swap.
- */
- /* State actions are shared with PE_FRS_SNK_SRC_TRANSITION_TO_OFF */
- [PE_PRS_SNK_SRC_TRANSITION_TO_OFF] = {
- .entry = pe_prs_snk_src_transition_to_off_entry,
- .run = pe_prs_snk_src_transition_to_off_run,
- .exit = pe_prs_snk_src_transition_to_off_exit,
-#ifdef CONFIG_USB_PD_REV30
- .parent = &pe_states[PE_PRS_FRS_SHARED],
-#endif /* CONFIG_USB_PD_REV30 */
- },
- /* State actions are shared with PE_FRS_SNK_SRC_ASSERT_RP */
- [PE_PRS_SNK_SRC_ASSERT_RP] = {
- .entry = pe_prs_snk_src_assert_rp_entry,
- .run = pe_prs_snk_src_assert_rp_run,
-#ifdef CONFIG_USB_PD_REV30
- .parent = &pe_states[PE_PRS_FRS_SHARED],
-#endif /* CONFIG_USB_PD_REV30 */
- },
- /* State actions are shared with PE_FRS_SNK_SRC_SOURCE_ON */
- [PE_PRS_SNK_SRC_SOURCE_ON] = {
- .entry = pe_prs_snk_src_source_on_entry,
- .run = pe_prs_snk_src_source_on_run,
- .exit = pe_prs_snk_src_source_on_exit,
-#ifdef CONFIG_USB_PD_REV30
- .parent = &pe_states[PE_PRS_FRS_SHARED],
-#endif /* CONFIG_USB_PD_REV30 */
- },
- /* State actions are shared with PE_FRS_SNK_SRC_SEND_SWAP */
- [PE_PRS_SNK_SRC_SEND_SWAP] = {
- .entry = pe_prs_snk_src_send_swap_entry,
- .run = pe_prs_snk_src_send_swap_run,
- .exit = pe_prs_snk_src_send_swap_exit,
-#ifdef CONFIG_USB_PD_REV30
- .parent = &pe_states[PE_PRS_FRS_SHARED],
-#endif /* CONFIG_USB_PD_REV30 */
- },
-#ifdef CONFIG_USBC_VCONN
- [PE_VCS_EVALUATE_SWAP] = {
- .entry = pe_vcs_evaluate_swap_entry,
- .run = pe_vcs_evaluate_swap_run,
- },
- [PE_VCS_SEND_SWAP] = {
- .entry = pe_vcs_send_swap_entry,
- .run = pe_vcs_send_swap_run,
- .exit = pe_vcs_send_swap_exit,
- },
- [PE_VCS_WAIT_FOR_VCONN_SWAP] = {
- .entry = pe_vcs_wait_for_vconn_swap_entry,
- .run = pe_vcs_wait_for_vconn_swap_run,
- .exit = pe_vcs_wait_for_vconn_swap_exit,
- },
- [PE_VCS_TURN_ON_VCONN_SWAP] = {
- .entry = pe_vcs_turn_on_vconn_swap_entry,
- .run = pe_vcs_turn_on_vconn_swap_run,
- .exit = pe_vcs_turn_on_vconn_swap_exit,
- },
- [PE_VCS_TURN_OFF_VCONN_SWAP] = {
- .entry = pe_vcs_turn_off_vconn_swap_entry,
- .run = pe_vcs_turn_off_vconn_swap_run,
- },
- [PE_VCS_SEND_PS_RDY_SWAP] = {
- .entry = pe_vcs_send_ps_rdy_swap_entry,
- .run = pe_vcs_send_ps_rdy_swap_run,
- },
- [PE_VCS_CBL_SEND_SOFT_RESET] = {
- .entry = pe_vcs_cbl_send_soft_reset_entry,
- .run = pe_vcs_cbl_send_soft_reset_run,
- .exit = pe_vcs_cbl_send_soft_reset_exit,
- },
-#endif /* CONFIG_USBC_VCONN */
- [PE_VDM_IDENTITY_REQUEST_CBL] = {
- .entry = pe_vdm_identity_request_cbl_entry,
- .run = pe_vdm_identity_request_cbl_run,
- .exit = pe_vdm_identity_request_cbl_exit,
- .parent = &pe_states[PE_VDM_SEND_REQUEST],
- },
- [PE_INIT_PORT_VDM_IDENTITY_REQUEST] = {
- .entry = pe_init_port_vdm_identity_request_entry,
- .run = pe_init_port_vdm_identity_request_run,
- .exit = pe_init_port_vdm_identity_request_exit,
- .parent = &pe_states[PE_VDM_SEND_REQUEST],
- },
- [PE_INIT_VDM_SVIDS_REQUEST] = {
- .entry = pe_init_vdm_svids_request_entry,
- .run = pe_init_vdm_svids_request_run,
- .exit = pe_init_vdm_svids_request_exit,
- .parent = &pe_states[PE_VDM_SEND_REQUEST],
- },
- [PE_INIT_VDM_MODES_REQUEST] = {
- .entry = pe_init_vdm_modes_request_entry,
- .run = pe_init_vdm_modes_request_run,
- .exit = pe_init_vdm_modes_request_exit,
- .parent = &pe_states[PE_VDM_SEND_REQUEST],
- },
- [PE_VDM_REQUEST_DPM] = {
- .entry = pe_vdm_request_dpm_entry,
- .run = pe_vdm_request_dpm_run,
- .exit = pe_vdm_request_dpm_exit,
- .parent = &pe_states[PE_VDM_SEND_REQUEST],
- },
- [PE_VDM_RESPONSE] = {
- .entry = pe_vdm_response_entry,
- .run = pe_vdm_response_run,
- .exit = pe_vdm_response_exit,
- },
- [PE_HANDLE_CUSTOM_VDM_REQUEST] = {
- .entry = pe_handle_custom_vdm_request_entry,
- .run = pe_handle_custom_vdm_request_run,
- .exit = pe_handle_custom_vdm_request_exit,
- },
- [PE_DEU_SEND_ENTER_USB] = {
- .entry = pe_enter_usb_entry,
- .run = pe_enter_usb_run,
- .exit = pe_enter_usb_exit,
- },
- [PE_WAIT_FOR_ERROR_RECOVERY] = {
- .entry = pe_wait_for_error_recovery_entry,
- .run = pe_wait_for_error_recovery_run,
- },
- [PE_BIST_TX] = {
- .entry = pe_bist_tx_entry,
- .run = pe_bist_tx_run,
- .exit = pe_bist_tx_exit,
- },
- [PE_DR_GET_SINK_CAP] = {
- .entry = pe_dr_get_sink_cap_entry,
- .run = pe_dr_get_sink_cap_run,
- .exit = pe_dr_get_sink_cap_exit,
- },
- [PE_DR_SNK_GIVE_SOURCE_CAP] = {
- .entry = pe_dr_snk_give_source_cap_entry,
- .run = pe_dr_snk_give_source_cap_run,
- },
- [PE_DR_SRC_GET_SOURCE_CAP] = {
- .entry = pe_dr_src_get_source_cap_entry,
- .run = pe_dr_src_get_source_cap_run,
- .exit = pe_dr_src_get_source_cap_exit,
- },
-#ifdef CONFIG_USB_PD_REV30
- [PE_FRS_SNK_SRC_START_AMS] = {
- .entry = pe_frs_snk_src_start_ams_entry,
- .parent = &pe_states[PE_PRS_FRS_SHARED],
- },
-#ifdef CONFIG_USB_PD_EXTENDED_MESSAGES
- [PE_GIVE_BATTERY_CAP] = {
- .entry = pe_give_battery_cap_entry,
- .run = pe_give_battery_cap_run,
- },
- [PE_GIVE_BATTERY_STATUS] = {
- .entry = pe_give_battery_status_entry,
- .run = pe_give_battery_status_run,
- },
- [PE_SEND_ALERT] = {
- .entry = pe_send_alert_entry,
- .run = pe_send_alert_run,
- },
-#else
- [PE_SRC_CHUNK_RECEIVED] = {
- .entry = pe_chunk_received_entry,
- .run = pe_chunk_received_run,
- .exit = pe_chunk_received_exit,
- },
- [PE_SNK_CHUNK_RECEIVED] = {
- .entry = pe_chunk_received_entry,
- .run = pe_chunk_received_run,
- .exit = pe_chunk_received_exit,
- },
-#endif /* CONFIG_USB_PD_EXTENDED_MESSAGES */
-#ifdef CONFIG_USBC_VCONN
- [PE_VCS_FORCE_VCONN] = {
- .entry = pe_vcs_force_vconn_entry,
- .run = pe_vcs_force_vconn_run,
- .exit = pe_vcs_force_vconn_exit,
- },
-#endif /* CONFIG_USBC_VCONN */
-#endif /* CONFIG_USB_PD_REV30 */
-};
-
-#ifdef TEST_BUILD
-/* TODO(b/173791979): Unit tests shouldn't need to access internal states */
-const struct test_sm_data test_pe_sm_data[] = {
- {
- .base = pe_states,
- .size = ARRAY_SIZE(pe_states),
- .names = pe_state_names,
- .names_size = ARRAY_SIZE(pe_state_names),
- },
-};
-BUILD_ASSERT(ARRAY_SIZE(pe_states) == ARRAY_SIZE(pe_state_names));
-const int test_pe_sm_data_size = ARRAY_SIZE(test_pe_sm_data);
-
-void pe_set_flag(int port, int flag)
-{
- PE_SET_FLAG(port, flag);
-}
-void pe_clr_flag(int port, int flag)
-{
- PE_CLR_FLAG(port, flag);
-}
-int pe_chk_flag(int port, int flag)
-{
- return PE_CHK_FLAG(port, flag);
-}
-int pe_get_all_flags(int port)
-{
- return pe[port].flags;
-}
-void pe_set_all_flags(int port, int flags)
-{
- pe[port].flags = flags;
-}
-void pe_clr_dpm_requests(int port)
-{
- pe[port].dpm_request = 0;
-}
-#endif
diff --git a/common/usbc/usb_prl_sm.c b/common/usbc/usb_prl_sm.c
deleted file mode 100644
index a58a579775..0000000000
--- a/common/usbc/usb_prl_sm.c
+++ /dev/null
@@ -1,2471 +0,0 @@
-/* Copyright 2019 The Chromium OS Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "battery.h"
-#include "battery_smart.h"
-#include "board.h"
-#include "charge_manager.h"
-#include "charge_state.h"
-#include "chipset.h"
-#include "common.h"
-#include "console.h"
-#include "cros_version.h"
-#include "ec_commands.h"
-#include "gpio.h"
-#include "hooks.h"
-#include "host_command.h"
-#include "registers.h"
-#include "system.h"
-#include "task.h"
-#include "tcpm/tcpm.h"
-#include "util.h"
-#include "usb_charge.h"
-#include "usb_mux.h"
-#include "usb_pd.h"
-#include "usb_pd_timer.h"
-#include "usb_pe_sm.h"
-#include "usb_prl_sm.h"
-#include "usb_tc_sm.h"
-#include "usb_emsg.h"
-#include "usb_sm.h"
-#include "vpd_api.h"
-
-#ifdef CONFIG_COMMON_RUNTIME
-#define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args)
-#define CPRINTS(format, args...) cprints(CC_USBPD, format, ## args)
-#else
-#define CPRINTF(format, args...)
-#define CPRINTS(format, args...)
-#endif
-
-/*
- * Define DEBUG_PRINT_FLAG_NAMES to print flag names when set and cleared.
- */
-#undef DEBUG_PRINT_FLAG_NAMES
-
-#ifdef DEBUG_PRINT_FLAG_NAMES
-__maybe_unused static void print_flag(const char *group,
- int set_or_clear,
- int flag);
-#define SET_FLAG(group, flags, flag) \
- do { \
- print_flag(group, 1, flag); \
- atomic_or(flags, (flag)); \
- } while (0)
-#define CLR_FLAG(group, flags, flag) \
- do { \
- int before = *flags; \
- atomic_clear_bits(flags, (flag)); \
- if (*flags != before) \
- print_flag(group, 0, flag); \
- } while (0)
-#else
-#define SET_FLAG(group, flags, flag) atomic_or(flags, (flag))
-#define CLR_FLAG(group, flags, flag) atomic_clear_bits(flags, (flag))
-#endif
-
-
-#define RCH_SET_FLAG(port, flag) SET_FLAG("RCH", &rch[port].flags, (flag))
-#define RCH_CLR_FLAG(port, flag) CLR_FLAG("RCH", &rch[port].flags, (flag))
-#define RCH_CHK_FLAG(port, flag) (rch[port].flags & (flag))
-
-#define TCH_SET_FLAG(port, flag) SET_FLAG("TCH", &tch[port].flags, (flag))
-#define TCH_CLR_FLAG(port, flag) CLR_FLAG("TCH", &tch[port].flags, (flag))
-#define TCH_CHK_FLAG(port, flag) (tch[port].flags & (flag))
-
-#define PRL_TX_SET_FLAG(port, flag) \
- SET_FLAG("PRL_TX", &prl_tx[port].flags, (flag))
-#define PRL_TX_CLR_FLAG(port, flag) \
- CLR_FLAG("PRL_TX", &prl_tx[port].flags, (flag))
-#define PRL_TX_CHK_FLAG(port, flag) (prl_tx[port].flags & (flag))
-
-#define PRL_HR_SET_FLAG(port, flag) \
- SET_FLAG("PRL_HR", &prl_hr[port].flags, (flag))
-#define PRL_HR_CLR_FLAG(port, flag) \
- CLR_FLAG("PRL_HR", &prl_hr[port].flags, (flag))
-#define PRL_HR_CHK_FLAG(port, flag) (prl_hr[port].flags & (flag))
-
-#define PDMSG_SET_FLAG(port, flag) SET_FLAG("PDMSG", &pdmsg[port].flags, (flag))
-#define PDMSG_CLR_FLAG(port, flag) CLR_FLAG("PDMSG", &pdmsg[port].flags, (flag))
-#define PDMSG_CHK_FLAG(port, flag) (pdmsg[port].flags & (flag))
-
-/* Protocol Layer Flags */
-/*
- * NOTE:
- * These flags are used in multiple state machines and could have
- * different meanings in each state machine.
- */
-/* Flag to note message transmission completed */
-#define PRL_FLAGS_TX_COMPLETE BIT(0)
-/* Flag to note that PRL requested to set SINK_NG CC state */
-#define PRL_FLAGS_SINK_NG BIT(1)
-/* Flag to note PRL waited for SINK_OK CC state before transmitting */
-#define PRL_FLAGS_WAIT_SINK_OK BIT(2)
-/* Flag to note transmission error occurred */
-#define PRL_FLAGS_TX_ERROR BIT(3)
-/* Flag to note PE triggered a hard reset */
-#define PRL_FLAGS_PE_HARD_RESET BIT(4)
-/* Flag to note hard reset has completed */
-#define PRL_FLAGS_HARD_RESET_COMPLETE BIT(5)
-/* Flag to note port partner sent a hard reset */
-#define PRL_FLAGS_PORT_PARTNER_HARD_RESET BIT(6)
-/*
- * Flag to note a message transmission has been requested. It is only cleared
- * when we send the message to the TCPC layer.
- */
-#define PRL_FLAGS_MSG_XMIT BIT(7)
-/* Flag to note a message was received */
-#define PRL_FLAGS_MSG_RECEIVED BIT(8)
-/* Flag to note aborting current TX message, not currently set */
-#define PRL_FLAGS_ABORT BIT(9)
-/* Flag to note current TX message uses chunking */
-#define PRL_FLAGS_CHUNKING BIT(10)
-
-struct bit_name {
- int value;
- const char *name;
-};
-
-static __const_data struct bit_name flag_bit_names[] = {
- { PRL_FLAGS_TX_COMPLETE, "PRL_FLAGS_TX_COMPLETE" },
- { PRL_FLAGS_SINK_NG, "PRL_FLAGS_SINK_NG" },
- { PRL_FLAGS_WAIT_SINK_OK, "PRL_FLAGS_WAIT_SINK_OK" },
- { PRL_FLAGS_TX_ERROR, "PRL_FLAGS_TX_ERROR" },
- { PRL_FLAGS_PE_HARD_RESET, "PRL_FLAGS_PE_HARD_RESET" },
- { PRL_FLAGS_HARD_RESET_COMPLETE, "PRL_FLAGS_HARD_RESET_COMPLETE" },
- { PRL_FLAGS_PORT_PARTNER_HARD_RESET,
- "PRL_FLAGS_PORT_PARTNER_HARD_RESET" },
- { PRL_FLAGS_MSG_XMIT, "PRL_FLAGS_MSG_XMIT" },
- { PRL_FLAGS_MSG_RECEIVED, "PRL_FLAGS_MSG_RECEIVED" },
- { PRL_FLAGS_ABORT, "PRL_FLAGS_ABORT" },
- { PRL_FLAGS_CHUNKING, "PRL_FLAGS_CHUNKING" },
-};
-
-__maybe_unused static void print_bits(const char *group,
- const char *desc,
- int value,
- struct bit_name *names,
- int names_size)
-{
- int i;
-
- CPRINTF("%s %s 0x%x : ", group, desc, value);
- for (i = 0; i < names_size; i++) {
- if (value & names[i].value)
- CPRINTF("%s | ", names[i].name);
- value &= ~names[i].value;
- }
- if (value != 0)
- CPRINTF("0x%x", value);
- CPRINTF("\n");
-}
-
-__maybe_unused static void print_flag(const char *group,
- int set_or_clear,
- int flag)
-{
- print_bits(group, set_or_clear ? "Set" : "Clr", flag, flag_bit_names,
- ARRAY_SIZE(flag_bit_names));
-}
-
-/* PD counter definitions */
-#define PD_MESSAGE_ID_COUNT 7
-
-/* Size of PDMSG Chunk Buffer */
-#define CHK_BUF_SIZE 7
-#define CHK_BUF_SIZE_BYTES 28
-
-/*
- * Debug log level - higher number == more log
- * Level 0: disabled
- * Level 1: not currently used
- * Level 2: plus non-ping messages
- * Level 3: plus ping packet and PRL states
- *
- * Note that higher log level causes timing changes and thus may affect
- * performance.
- */
-#ifdef CONFIG_USB_PD_DEBUG_LEVEL
-static const enum debug_level prl_debug_level = CONFIG_USB_PD_DEBUG_LEVEL;
-#else
-static enum debug_level prl_debug_level = DEBUG_LEVEL_1;
-#endif
-
-static enum sm_local_state local_state[CONFIG_USB_PD_PORT_MAX_COUNT];
-
-/* Protocol Transmit States (Section 6.11.2.2) */
-enum usb_prl_tx_state {
- PRL_TX_PHY_LAYER_RESET,
- PRL_TX_WAIT_FOR_MESSAGE_REQUEST,
- PRL_TX_LAYER_RESET_FOR_TRANSMIT,
- PRL_TX_WAIT_FOR_PHY_RESPONSE,
- PRL_TX_SRC_SOURCE_TX,
- PRL_TX_SNK_START_AMS,
- PRL_TX_SRC_PENDING,
- PRL_TX_SNK_PENDING,
- PRL_TX_DISCARD_MESSAGE,
-};
-
-/* Protocol Hard Reset States (Section 6.11.2.4) */
-enum usb_prl_hr_state {
- PRL_HR_WAIT_FOR_REQUEST,
- PRL_HR_RESET_LAYER,
- PRL_HR_WAIT_FOR_PHY_HARD_RESET_COMPLETE,
- PRL_HR_WAIT_FOR_PE_HARD_RESET_COMPLETE,
-};
-
-/* Chunked Rx states (Section 6.11.2.1.2) */
-enum usb_rch_state {
- RCH_WAIT_FOR_MESSAGE_FROM_PROTOCOL_LAYER,
- RCH_PASS_UP_MESSAGE,
- RCH_PROCESSING_EXTENDED_MESSAGE,
- RCH_REQUESTING_CHUNK,
- RCH_WAITING_CHUNK,
- RCH_REPORT_ERROR,
-};
-
-/* Chunked Tx states (Section 6.11.2.1.3) */
-enum usb_tch_state {
- TCH_WAIT_FOR_MESSAGE_REQUEST_FROM_PE,
- TCH_WAIT_FOR_TRANSMISSION_COMPLETE,
- TCH_CONSTRUCT_CHUNKED_MESSAGE,
- TCH_SENDING_CHUNKED_MESSAGE,
- TCH_WAIT_CHUNK_REQUEST,
- TCH_MESSAGE_RECEIVED,
- TCH_MESSAGE_SENT,
- TCH_REPORT_ERROR,
-};
-
-static const char * const prl_tx_state_names[] = {
- [PRL_TX_PHY_LAYER_RESET] = "PRL_TX_PHY_LAYER_RESET",
- [PRL_TX_WAIT_FOR_MESSAGE_REQUEST] = "PRL_TX_WAIT_FOR_MESSAGE_REQUEST",
- [PRL_TX_LAYER_RESET_FOR_TRANSMIT] = "PRL_TX_LAYER_RESET_FOR_TRANSMIT",
- [PRL_TX_WAIT_FOR_PHY_RESPONSE] = "PRL_TX_WAIT_FOR_PHY_RESPONSE",
- [PRL_TX_SRC_SOURCE_TX] = "PRL_TX_SRC_SOURCE_TX",
- [PRL_TX_SNK_START_AMS] = "PRL_TX_SNK_START_AMS",
- [PRL_TX_SRC_PENDING] = "PRL_TX_SRC_PENDING",
- [PRL_TX_SNK_PENDING] = "PRL_TX_SNK_PENDING",
- [PRL_TX_DISCARD_MESSAGE] = "PRL_TX_DISCARD_MESSAGE",
-};
-
-static const char * const prl_hr_state_names[] = {
- [PRL_HR_WAIT_FOR_REQUEST] = "PRL_HR_WAIT_FOR_REQUEST",
- [PRL_HR_RESET_LAYER] = "PRL_HR_RESET_LAYER",
- [PRL_HR_WAIT_FOR_PHY_HARD_RESET_COMPLETE]
- = "PRL_HR_WAIT_FOR_PHY_HARD_RESET_COMPLETE",
- [PRL_HR_WAIT_FOR_PE_HARD_RESET_COMPLETE]
- = "PRL_HR_WAIT_FOR_PE_HARD_RESET_COMPLETE",
-};
-
-__maybe_unused static const char * const rch_state_names[] = {
- [RCH_WAIT_FOR_MESSAGE_FROM_PROTOCOL_LAYER]
- = "RCH_WAIT_FOR_MESSAGE_FROM_PROTOCOL_LAYER",
- [RCH_PASS_UP_MESSAGE] = "RCH_PASS_UP_MESSAGE",
- [RCH_PROCESSING_EXTENDED_MESSAGE] = "RCH_PROCESSING_EXTENDED_MESSAGE",
- [RCH_REQUESTING_CHUNK] = "RCH_REQUESTING_CHUNK",
- [RCH_WAITING_CHUNK] = "RCH_WAITING_CHUNK",
- [RCH_REPORT_ERROR] = "RCH_REPORT_ERROR",
-};
-
-__maybe_unused static const char * const tch_state_names[] = {
- [TCH_WAIT_FOR_MESSAGE_REQUEST_FROM_PE]
- = "TCH_WAIT_FOR_MESSAGE_REQUEST_FROM_PE",
- [TCH_WAIT_FOR_TRANSMISSION_COMPLETE]
- = "TCH_WAIT_FOR_TRANSMISSION_COMPLETE",
- [TCH_CONSTRUCT_CHUNKED_MESSAGE] = "TCH_CONSTRUCT_CHUNKED_MESSAGE",
- [TCH_SENDING_CHUNKED_MESSAGE] = "TCH_SENDING_CHUNKED_MESSAGE",
- [TCH_WAIT_CHUNK_REQUEST] = "TCH_WAIT_CHUNK_REQUEST",
- [TCH_MESSAGE_RECEIVED] = "TCH_MESSAGE_RECEIVED",
- [TCH_MESSAGE_SENT] = "TCH_MESSAGE_SENT",
- [TCH_REPORT_ERROR] = "TCH_REPORT_ERROR",
-};
-
-/* Forward declare full list of states. Index by above enums. */
-static const struct usb_state prl_tx_states[];
-static const struct usb_state prl_hr_states[];
-
-__maybe_unused static const struct usb_state rch_states[];
-__maybe_unused static const struct usb_state tch_states[];
-
-/* Chunked Rx State Machine Object */
-static struct rx_chunked {
- /* state machine context */
- struct sm_ctx ctx;
- /* PRL_FLAGS */
- uint32_t flags;
- /* error to report when moving to rch_report_error state */
- enum pe_error error;
-} rch[CONFIG_USB_PD_PORT_MAX_COUNT];
-
-/* Chunked Tx State Machine Object */
-static struct tx_chunked {
- /* state machine context */
- struct sm_ctx ctx;
- /* state machine flags */
- uint32_t flags;
- /* error to report when moving to tch_report_error state */
- enum pe_error error;
-} tch[CONFIG_USB_PD_PORT_MAX_COUNT];
-
-/* Message Reception State Machine Object */
-static struct protocol_layer_rx {
- /* received message type */
- enum tcpci_msg_type sop;
- /* message ids for all valid port partners */
- int msg_id[NUM_SOP_STAR_TYPES];
-} prl_rx[CONFIG_USB_PD_PORT_MAX_COUNT];
-
-/* Message Transmission State Machine Object */
-static struct protocol_layer_tx {
- /* state machine context */
- struct sm_ctx ctx;
- /* state machine flags */
- uint32_t flags;
- /* last message type we transmitted */
- enum tcpci_msg_type last_xmit_type;
- /* message id counters for all 6 port partners */
- uint32_t msg_id_counter[NUM_SOP_STAR_TYPES];
- /* transmit status */
- int xmit_status;
-} prl_tx[CONFIG_USB_PD_PORT_MAX_COUNT];
-
-/* Hard Reset State Machine Object */
-static struct protocol_hard_reset {
- /* state machine context */
- struct sm_ctx ctx;
- /* state machine flags */
- uint32_t flags;
-} prl_hr[CONFIG_USB_PD_PORT_MAX_COUNT];
-
-/* Chunking Message Object */
-static struct pd_message {
- /* message status flags */
- uint32_t flags;
- /* SOP* */
- enum tcpci_msg_type xmit_type;
- /* type of message */
- uint8_t msg_type;
- /* PD revision */
- enum pd_rev_type rev[NUM_SOP_STAR_TYPES];
- /* Number of 32-bit objects in chk_buf */
- uint16_t data_objs;
- /* temp chunk buffer */
- uint32_t tx_chk_buf[CHK_BUF_SIZE];
- uint32_t rx_chk_buf[CHK_BUF_SIZE];
- uint32_t chunk_number_expected;
- uint32_t num_bytes_received;
-#ifdef CONFIG_USB_PD_EXTENDED_MESSAGES
- /* extended message */
- uint8_t ext;
- uint32_t chunk_number_to_send;
- uint32_t send_offset;
-#endif /* CONFIG_USB_PD_EXTENDED_MESSAGES */
-} pdmsg[CONFIG_USB_PD_PORT_MAX_COUNT];
-
-struct extended_msg rx_emsg[CONFIG_USB_PD_PORT_MAX_COUNT];
-struct extended_msg tx_emsg[CONFIG_USB_PD_PORT_MAX_COUNT];
-
-/* Common Protocol Layer Message Transmission */
-static void prl_tx_construct_message(int port);
-static void prl_rx_wait_for_phy_message(const int port, int evt);
-static void prl_copy_msg_to_buffer(int port);
-
-#ifndef CONFIG_USB_PD_REV30
-GEN_NOT_SUPPORTED(PRL_TX_SRC_SOURCE_TX);
-#define PRL_TX_SRC_SOURCE_TX PRL_TX_SRC_SOURCE_TX_NOT_SUPPORTED
-GEN_NOT_SUPPORTED(PRL_TX_SNK_START_AMS);
-#define PRL_TX_SNK_START_AMS PRL_TX_SNK_START_AMS_NOT_SUPPORTED
-
-GEN_NOT_SUPPORTED(RCH_WAIT_FOR_MESSAGE_FROM_PROTOCOL_LAYER);
-#define RCH_WAIT_FOR_MESSAGE_FROM_PROTOCOL_LAYER \
- RCH_WAIT_FOR_MESSAGE_FROM_PROTOCOL_LAYER_NOT_SUPPORTED
-GEN_NOT_SUPPORTED(RCH_PASS_UP_MESSAGE);
-#define RCH_PASS_UP_MESSAGE RCH_PASS_UP_MESSAGE_NOT_SUPPORTED
-GEN_NOT_SUPPORTED(RCH_PROCESSING_EXTENDED_MESSAGE);
-#define RCH_PROCESSING_EXTENDED_MESSAGE \
- RCH_PROCESSING_EXTENDED_MESSAGE_NOT_SUPPORTED
-GEN_NOT_SUPPORTED(RCH_REQUESTING_CHUNK);
-#define RCH_REQUESTING_CHUNK RCH_REQUESTING_CHUNK_NOT_SUPPORTED
-GEN_NOT_SUPPORTED(RCH_WAITING_CHUNK);
-#define RCH_WAITING_CHUNK RCH_WAITING_CHUNK_NOT_SUPPORTED
-GEN_NOT_SUPPORTED(RCH_REPORT_ERROR);
-#define RCH_REPORT_ERROR RCH_REPORT_ERROR_NOT_SUPPORTED
-
-GEN_NOT_SUPPORTED(TCH_WAIT_FOR_MESSAGE_REQUEST_FROM_PE);
-#define TCH_WAIT_FOR_MESSAGE_REQUEST_FROM_PE \
- TCH_WAIT_FOR_MESSAGE_REQUEST_FROM_PE_NOT_SUPPORTED
-GEN_NOT_SUPPORTED(TCH_WAIT_FOR_TRANSMISSION_COMPLETE);
-#define TCH_WAIT_FOR_TRANSMISSION_COMPLETE \
- TCH_WAIT_FOR_TRANSMISSION_COMPLETE_NOT_SUPPORTED
-GEN_NOT_SUPPORTED(TCH_CONSTRUCT_CHUNKED_MESSAGE);
-#define TCH_CONSTRUCT_CHUNKED_MESSAGE \
- TCH_CONSTRUCT_CHUNKED_MESSAGE_NOT_SUPPORTED
-GEN_NOT_SUPPORTED(TCH_SENDING_CHUNKED_MESSAGE);
-#define TCH_SENDING_CHUNKED_MESSAGE TCH_SENDING_CHUNKED_MESSAGE_NOT_SUPPORTED
-GEN_NOT_SUPPORTED(TCH_WAIT_CHUNK_REQUEST);
-#define TCH_WAIT_CHUNK_REQUEST TCH_WAIT_CHUNK_REQUEST_NOT_SUPPORTED
-GEN_NOT_SUPPORTED(TCH_MESSAGE_RECEIVED);
-#define TCH_MESSAGE_RECEIVED TCH_MESSAGE_RECEIVED_NOT_SUPPORTED
-GEN_NOT_SUPPORTED(TCH_MESSAGE_SENT);
-#define TCH_MESSAGE_SENT TCH_MESSAGE_SENT_NOT_SUPPORTED
-GEN_NOT_SUPPORTED(TCH_REPORT_ERROR);
-#define TCH_REPORT_ERROR TCH_REPORT_ERROR_NOT_SUPPORTED
-#endif /* !CONFIG_USB_PD_REV30 */
-
-/* To store the time stamp when TCPC sets TX Complete Success */
-static timestamp_t tcpc_tx_success_ts[CONFIG_USB_PD_PORT_MAX_COUNT];
-
-/* Set the protocol transmit statemachine to a new state. */
-static void set_state_prl_tx(const int port,
- const enum usb_prl_tx_state new_state)
-{
- set_state(port, &prl_tx[port].ctx, &prl_tx_states[new_state]);
-}
-
-/* Get the protocol transmit statemachine's current state. */
-test_export_static enum usb_prl_tx_state prl_tx_get_state(const int port)
-{
- return prl_tx[port].ctx.current - &prl_tx_states[0];
-}
-
-/* Print the protocol transmit statemachine's current state. */
-static void print_current_prl_tx_state(const int port)
-{
- if (prl_debug_level >= DEBUG_LEVEL_3)
- CPRINTS("C%d: %s", port,
- prl_tx_state_names[prl_tx_get_state(port)]);
-}
-
-/* Set the hard reset statemachine to a new state. */
-static void set_state_prl_hr(const int port,
- const enum usb_prl_hr_state new_state)
-{
- set_state(port, &prl_hr[port].ctx, &prl_hr_states[new_state]);
-}
-
-/* Get the hard reset statemachine's current state. */
-enum usb_prl_hr_state prl_hr_get_state(const int port)
-{
- return prl_hr[port].ctx.current - &prl_hr_states[0];
-}
-
-/* Print the hard reset statemachine's current state. */
-static void print_current_prl_hr_state(const int port)
-{
- if (prl_debug_level >= DEBUG_LEVEL_3)
- CPRINTS("C%d: %s", port,
- prl_hr_state_names[prl_hr_get_state(port)]);
-}
-
-/* Set the chunked Rx statemachine to a new state. */
-static void set_state_rch(const int port, const enum usb_rch_state new_state)
-{
- if (IS_ENABLED(CONFIG_USB_PD_EXTENDED_MESSAGES))
- set_state(port, &rch[port].ctx, &rch_states[new_state]);
-}
-
-#ifdef CONFIG_USB_PD_EXTENDED_MESSAGES
-/* Get the chunked Rx statemachine's current state. */
-test_export_static enum usb_rch_state rch_get_state(const int port)
-{
- return rch[port].ctx.current - &rch_states[0];
-}
-
-/* Print the chunked Rx statemachine's current state. */
-static void print_current_rch_state(const int port)
-{
- if (prl_debug_level >= DEBUG_LEVEL_3)
- CPRINTS("C%d: %s", port,
- rch_state_names[rch_get_state(port)]);
-}
-#endif /* CONFIG_USB_PD_EXTENDED_MESSAGES */
-
-/* Set the chunked Tx statemachine to a new state. */
-static void set_state_tch(const int port, const enum usb_tch_state new_state)
-{
- if (IS_ENABLED(CONFIG_USB_PD_EXTENDED_MESSAGES))
- set_state(port, &tch[port].ctx, &tch_states[new_state]);
-}
-
-/* Get the chunked Tx statemachine's current state. */
-test_export_static enum usb_tch_state tch_get_state(const int port)
-{
- if (IS_ENABLED(CONFIG_USB_PD_EXTENDED_MESSAGES))
- return tch[port].ctx.current - &tch_states[0];
- else
- return 0;
-}
-
-#ifdef CONFIG_USB_PD_EXTENDED_MESSAGES
-/* Print the chunked Tx statemachine's current state. */
-static void print_current_tch_state(const int port)
-{
- if (prl_debug_level >= DEBUG_LEVEL_3)
- CPRINTS("C%d: %s", port,
- tch_state_names[tch_get_state(port)]);
-}
-#endif /* CONFIG_USB_PD_EXTENDED_MESSAGES */
-
-
-timestamp_t prl_get_tcpc_tx_success_ts(int port)
-{
- return tcpc_tx_success_ts[port];
-}
-
-/* Sets the time stamp when TCPC reports TX success. */
-static void set_tcpc_tx_success_ts(int port)
-{
- tcpc_tx_success_ts[port] = get_time();
-}
-
-void pd_transmit_complete(int port, int status)
-{
- if (status == TCPC_TX_COMPLETE_SUCCESS)
- set_tcpc_tx_success_ts(port);
- prl_tx[port].xmit_status = status;
-}
-
-void pd_execute_hard_reset(int port)
-{
- /* Only allow async. function calls when state machine is running */
- if (!prl_is_running(port))
- return;
-
- PRL_HR_SET_FLAG(port, PRL_FLAGS_PORT_PARTNER_HARD_RESET);
- set_state_prl_hr(port, PRL_HR_RESET_LAYER);
- task_wake(PD_PORT_TO_TASK_ID(port));
-}
-
-void prl_execute_hard_reset(int port)
-{
- /* Only allow async. function calls when state machine is running */
- if (!prl_is_running(port))
- return;
-
- PRL_HR_SET_FLAG(port, PRL_FLAGS_PE_HARD_RESET);
- set_state_prl_hr(port, PRL_HR_RESET_LAYER);
- task_wake(PD_PORT_TO_TASK_ID(port));
-}
-
-int prl_is_running(int port)
-{
- return local_state[port] == SM_RUN;
-}
-
-static void prl_init(int port)
-{
- int i;
- const struct sm_ctx cleared = {};
-
- /*
- * flags without PRL_FLAGS_SINK_NG present means we are initially
- * in SinkTxOK state
- */
- prl_tx[port].flags = 0;
- if (IS_ENABLED(CONFIG_USB_PD_REV30))
- typec_select_src_collision_rp(port, SINK_TX_OK);
- prl_tx[port].last_xmit_type = TCPCI_MSG_SOP;
- prl_tx[port].xmit_status = TCPC_TX_UNSET;
-
- if (IS_ENABLED(CONFIG_USB_PD_REV30)) {
- tch[port].flags = 0;
- rch[port].flags = 0;
- }
-
- pdmsg[port].flags = 0;
-
- prl_hr[port].flags = 0;
-
- for (i = 0; i < NUM_SOP_STAR_TYPES; i++) {
- prl_rx[port].msg_id[i] = -1;
- prl_tx[port].msg_id_counter[i] = 0;
- }
-
- pd_timer_disable_range(port, PR_TIMER_RANGE);
-
- /* Clear state machines and set initial states */
- prl_tx[port].ctx = cleared;
- set_state_prl_tx(port, PRL_TX_PHY_LAYER_RESET);
-
- if (IS_ENABLED(CONFIG_USB_PD_EXTENDED_MESSAGES)) {
- rch[port].ctx = cleared;
- set_state_rch(port, RCH_WAIT_FOR_MESSAGE_FROM_PROTOCOL_LAYER);
-
- tch[port].ctx = cleared;
- set_state_tch(port, TCH_WAIT_FOR_MESSAGE_REQUEST_FROM_PE);
- }
-
- prl_hr[port].ctx = cleared;
- set_state_prl_hr(port, PRL_HR_WAIT_FOR_REQUEST);
-}
-
-bool prl_is_busy(int port)
-{
-#ifdef CONFIG_USB_PD_EXTENDED_MESSAGES
- return rch_get_state(port) !=
- RCH_WAIT_FOR_MESSAGE_FROM_PROTOCOL_LAYER ||
- tch_get_state(port) !=
- TCH_WAIT_FOR_MESSAGE_REQUEST_FROM_PE;
-#else
- return false;
-#endif /* CONFIG_USB_PD_EXTENDED_MESSAGES */
-}
-
-void prl_set_debug_level(enum debug_level debug_level)
-{
-#ifndef CONFIG_USB_PD_DEBUG_LEVEL
- prl_debug_level = debug_level;
-#endif
-}
-
-void prl_hard_reset_complete(int port)
-{
- PRL_HR_SET_FLAG(port, PRL_FLAGS_HARD_RESET_COMPLETE);
- task_wake(PD_PORT_TO_TASK_ID(port));
-}
-
-void prl_send_ctrl_msg(int port,
- enum tcpci_msg_type type,
- enum pd_ctrl_msg_type msg)
-{
- pdmsg[port].xmit_type = type;
- pdmsg[port].msg_type = msg;
- pdmsg[port].data_objs = 0;
- tx_emsg[port].len = 0;
-
-#ifdef CONFIG_USB_PD_EXTENDED_MESSAGES
- pdmsg[port].ext = 0;
-
- TCH_SET_FLAG(port, PRL_FLAGS_MSG_XMIT);
-#else
- PRL_TX_SET_FLAG(port, PRL_FLAGS_MSG_XMIT);
-#endif /* CONFIG_USB_PD_EXTENDED_MESSAGES */
-
- task_wake(PD_PORT_TO_TASK_ID(port));
-}
-
-void prl_send_data_msg(int port,
- enum tcpci_msg_type type,
- enum pd_data_msg_type msg)
-{
- pdmsg[port].xmit_type = type;
- pdmsg[port].msg_type = msg;
-
-#ifdef CONFIG_USB_PD_EXTENDED_MESSAGES
- pdmsg[port].ext = 0;
-
- TCH_SET_FLAG(port, PRL_FLAGS_MSG_XMIT);
-#else
- prl_copy_msg_to_buffer(port);
- PRL_TX_SET_FLAG(port, PRL_FLAGS_MSG_XMIT);
-#endif /* CONFIG_USB_PD_EXTENDED_MESSAGES */
-
- task_wake(PD_PORT_TO_TASK_ID(port));
-}
-
-#ifdef CONFIG_USB_PD_EXTENDED_MESSAGES
-void prl_send_ext_data_msg(int port,
- enum tcpci_msg_type type,
- enum pd_ext_msg_type msg)
-{
- pdmsg[port].xmit_type = type;
- pdmsg[port].msg_type = msg;
- pdmsg[port].ext = 1;
-
- TCH_SET_FLAG(port, PRL_FLAGS_MSG_XMIT);
- task_wake(PD_PORT_TO_TASK_ID(port));
-}
-#endif /* CONFIG_USB_PD_EXTENDED_MESSAGES */
-
-void prl_set_default_pd_revision(int port)
-{
- /*
- * Initialize to highest revision supported. If the port or cable
- * partner doesn't support this revision, the Protocol Engine will
- * lower this value to the revision supported by the partner.
- */
- pdmsg[port].rev[TCPCI_MSG_SOP] = PD_REVISION;
- pdmsg[port].rev[TCPCI_MSG_SOP_PRIME] = PD_REVISION;
- pdmsg[port].rev[TCPCI_MSG_SOP_PRIME_PRIME] = PD_REVISION;
- pdmsg[port].rev[TCPCI_MSG_SOP_DEBUG_PRIME] = PD_REVISION;
- pdmsg[port].rev[TCPCI_MSG_SOP_DEBUG_PRIME_PRIME] = PD_REVISION;
-}
-
-void prl_reset_soft(int port)
-{
- /* Do not change negotiated PD Revision Specification level */
- local_state[port] = SM_INIT;
-
- /* Ensure we process the reset quickly */
- task_wake(PD_PORT_TO_TASK_ID(port));
-}
-
-void prl_run(int port, int evt, int en)
-{
- switch (local_state[port]) {
- case SM_PAUSED:
- if (!en)
- break;
- /* fall through */
- case SM_INIT:
- prl_init(port);
- local_state[port] = SM_RUN;
- /* fall through */
- case SM_RUN:
- if (!en) {
- /* Disable RX */
- if (IS_ENABLED(CONFIG_USB_CTVPD) ||
- IS_ENABLED(CONFIG_USB_VPD))
- vpd_rx_enable(0);
- else
- tcpm_set_rx_enable(port, 0);
-
- local_state[port] = SM_PAUSED;
- break;
- }
-
- /* Run Protocol Layer Hard Reset state machine */
- run_state(port, &prl_hr[port].ctx);
-
- /*
- * If the Hard Reset state machine is active, then there is no
- * need to execute any other PRL state machines. When the hard
- * reset is complete, all PRL state machines will have been
- * reset.
- */
- if (prl_hr_get_state(port) == PRL_HR_WAIT_FOR_REQUEST) {
-
- /* Run Protocol Layer Message Reception */
- prl_rx_wait_for_phy_message(port, evt);
-
-
- if (IS_ENABLED(CONFIG_USB_PD_EXTENDED_MESSAGES)) {
- /*
- * Run RX Chunked state machine after prl_rx.
- * This is what informs the PE of incoming
- * message. Its input is prl_rx
- */
- run_state(port, &rch[port].ctx);
-
- /*
- * Run TX Chunked state machine before prl_tx
- * in case we need to split an extended message
- * and prl_tx can send it for us
- */
- run_state(port, &tch[port].ctx);
- }
-
- /* Run Protocol Layer Message Tx state machine */
- run_state(port, &prl_tx[port].ctx);
-
- if (IS_ENABLED(CONFIG_USB_PD_EXTENDED_MESSAGES))
- /*
- * Run TX Chunked state machine again after
- * prl_tx so we can handle passing TX_COMPLETE
- * (or failure) up to PE in a single iteration.
- */
- run_state(port, &tch[port].ctx);
- }
- break;
- }
-}
-
-void prl_set_rev(int port, enum tcpci_msg_type type,
- enum pd_rev_type rev)
-{
- /* We only store revisions for SOP* types. */
- ASSERT(type < NUM_SOP_STAR_TYPES);
-
- pdmsg[port].rev[type] = rev;
-}
-
-enum pd_rev_type prl_get_rev(int port, enum tcpci_msg_type type)
-{
- /* We only store revisions for SOP* types. */
- ASSERT(type < NUM_SOP_STAR_TYPES);
-
- return pdmsg[port].rev[type];
-}
-
-static void prl_copy_msg_to_buffer(int port)
-{
- /*
- * Control Messages will have a length of 0 and
- * no need to spend time with the tx_chk_buf
- * for this path
- */
- if (tx_emsg[port].len == 0) {
- pdmsg[port].data_objs = 0;
- return;
- }
-
- /*
- * Make sure the Policy Engine isn't sending
- * more than CHK_BUF_SIZE_BYTES. If so,
- * truncate len. This will surely send a
- * malformed packet resulting in the port
- * partner soft\hard resetting us.
- */
- if (tx_emsg[port].len > CHK_BUF_SIZE_BYTES)
- tx_emsg[port].len = CHK_BUF_SIZE_BYTES;
-
- /* Copy message to chunked buffer */
- memset((uint8_t *)pdmsg[port].tx_chk_buf, 0, CHK_BUF_SIZE_BYTES);
- memcpy((uint8_t *)pdmsg[port].tx_chk_buf, (uint8_t *)tx_emsg[port].buf,
- tx_emsg[port].len);
- /*
- * Pad length to 4-byte boundary and
- * convert to number of 32-bit objects.
- * Since the value is shifted right by 2,
- * no need to explicitly clear the lower
- * 2-bits.
- */
- pdmsg[port].data_objs = (tx_emsg[port].len + 3) >> 2;
-}
-
-static __maybe_unused int pdmsg_xmit_type_is_rev30(const int port)
-{
- if (IS_ENABLED(CONFIG_USB_PD_REV30))
- return ((pdmsg[port].xmit_type < NUM_SOP_STAR_TYPES)
- && (prl_get_rev(port, pdmsg[port].xmit_type) == PD_REV30));
- else
- return 0;
-}
-
-/* Returns true if the SOP port partner operates at PD rev3.0 */
-static bool is_sop_rev30(const int port)
-{
- return IS_ENABLED(CONFIG_USB_PD_REV30) &&
- prl_get_rev(port, TCPCI_MSG_SOP) == PD_REV30;
-}
-
-/* Common Protocol Layer Message Transmission */
-static void prl_tx_phy_layer_reset_entry(const int port)
-{
- print_current_prl_tx_state(port);
-
- if (IS_ENABLED(CONFIG_USB_CTVPD)
- || IS_ENABLED(CONFIG_USB_VPD)) {
- vpd_rx_enable(pd_is_connected(port));
- } else {
- /* Note: can't clear PHY messages due to TCPC architecture */
- /* Enable communications*/
- tcpm_set_rx_enable(port, pd_is_connected(port));
- }
- set_state_prl_tx(port, PRL_TX_WAIT_FOR_MESSAGE_REQUEST);
-}
-
-static void prl_tx_wait_for_message_request_entry(const int port)
-{
- /* No phy layer response is pending */
- prl_tx[port].xmit_status = TCPC_TX_UNSET;
- print_current_prl_tx_state(port);
-}
-
-static void prl_tx_wait_for_message_request_run(const int port)
-{
- /* Clear any AMS flags and state if we are no longer in an AMS */
- if (IS_ENABLED(CONFIG_USB_PD_REV30) && !pe_in_local_ams(port)) {
- /* Note PRL_Tx_Src_Sink_Tx is embedded here. */
- if (PRL_TX_CHK_FLAG(port, PRL_FLAGS_SINK_NG)) {
- typec_select_src_collision_rp(port, SINK_TX_OK);
- typec_update_cc(port);
- }
- PRL_TX_CLR_FLAG(port,
- PRL_FLAGS_SINK_NG | PRL_FLAGS_WAIT_SINK_OK);
- }
-
- /*
- * Check if we are starting an AMS and need to wait and/or set the CC
- * lines appropriately.
- */
- if (IS_ENABLED(CONFIG_USB_PD_REV30) && is_sop_rev30(port) &&
- pe_in_local_ams(port)) {
- if (PRL_TX_CHK_FLAG(port, PRL_FLAGS_SINK_NG |
- PRL_FLAGS_WAIT_SINK_OK)) {
- /*
- * If we are already in an AMS then allow the
- * multi-message AMS to continue, even if we
- * swap power roles.
- *
- * Fall Through using the current AMS
- */
- } else {
- /*
- * Start of SRC AMS notification received from
- * Policy Engine
- */
- if (pd_get_power_role(port) == PD_ROLE_SOURCE) {
- PRL_TX_SET_FLAG(port, PRL_FLAGS_SINK_NG);
- set_state_prl_tx(port, PRL_TX_SRC_SOURCE_TX);
- } else {
- PRL_TX_SET_FLAG(port, PRL_FLAGS_WAIT_SINK_OK);
- set_state_prl_tx(port, PRL_TX_SNK_START_AMS);
- }
- return;
- }
- }
-
- /* Handle non Rev 3.0 or subsequent messages in AMS sequence */
- if (PRL_TX_CHK_FLAG(port, PRL_FLAGS_MSG_XMIT)) {
- PRL_TX_CLR_FLAG(port, PRL_FLAGS_MSG_XMIT);
- /*
- * Soft Reset Message Message pending
- */
- if ((pdmsg[port].msg_type == PD_CTRL_SOFT_RESET) &&
- (tx_emsg[port].len == 0)) {
- set_state_prl_tx(port, PRL_TX_LAYER_RESET_FOR_TRANSMIT);
- }
- /*
- * Message pending (except Soft Reset)
- */
- else {
- /* NOTE: PRL_TX_Construct_Message State embedded here */
- prl_tx_construct_message(port);
- set_state_prl_tx(port, PRL_TX_WAIT_FOR_PHY_RESPONSE);
- }
-
- return;
- }
-}
-
-static void increment_msgid_counter(int port)
-{
- /* If the last message wasn't an SOP* message, no need to increment */
- if (prl_tx[port].last_xmit_type >= NUM_SOP_STAR_TYPES)
- return;
-
- prl_tx[port].msg_id_counter[prl_tx[port].last_xmit_type] =
- (prl_tx[port].msg_id_counter[prl_tx[port].last_xmit_type] + 1) &
- PD_MESSAGE_ID_COUNT;
-}
-
-/*
- * PrlTxDiscard
- */
-static void prl_tx_discard_message_entry(const int port)
-{
- print_current_prl_tx_state(port);
-
- /*
- * Discard queued message
- * Note: We differ from spec here, which allows us to not discard on
- * incoming SOP' or SOP''. However this would get the TCH out of sync.
- *
- * prl_tx will be set to this state following message reception in
- * prl_rx. So this path will be entered following each rx message. If
- * this state is entered, and there is either a message from the PE
- * pending, or if a message was passed to the phy and there is either no
- * response yet, or it was discarded in the phy layer, then a tx message
- * discard event has been detected.
- */
- if (PRL_TX_CHK_FLAG(port, PRL_FLAGS_MSG_XMIT) ||
- prl_tx[port].xmit_status == TCPC_TX_WAIT ||
- prl_tx[port].xmit_status == TCPC_TX_COMPLETE_DISCARDED) {
- PRL_TX_CLR_FLAG(port, PRL_FLAGS_MSG_XMIT);
- increment_msgid_counter(port);
- pe_report_discard(port);
- }
-
- set_state_prl_tx(port, PRL_TX_PHY_LAYER_RESET);
-}
-
-#ifdef CONFIG_USB_PD_REV30
-/*
- * PrlTxSrcSourceTx
- */
-static void prl_tx_src_source_tx_entry(const int port)
-{
- print_current_prl_tx_state(port);
-
- /* Set Rp = SinkTxNG */
- typec_select_src_collision_rp(port, SINK_TX_NG);
- typec_update_cc(port);
-}
-
-static void prl_tx_src_source_tx_run(const int port)
-{
- if (PRL_TX_CHK_FLAG(port, PRL_FLAGS_MSG_XMIT)) {
- /*
- * Don't clear pending XMIT flag here. Wait until we send so
- * we can detect if we dropped this message or not.
- */
- set_state_prl_tx(port, PRL_TX_SRC_PENDING);
- }
-}
-
-/*
- * PrlTxSnkStartAms
- */
-static void prl_tx_snk_start_ams_entry(const int port)
-{
- print_current_prl_tx_state(port);
-}
-
-static void prl_tx_snk_start_ams_run(const int port)
-{
- if (PRL_TX_CHK_FLAG(port, PRL_FLAGS_MSG_XMIT)) {
- /*
- * Don't clear pending XMIT flag here. Wait until we send so
- * we can detect if we dropped this message or not.
- */
- set_state_prl_tx(port, PRL_TX_SNK_PENDING);
- }
-}
-#endif /* CONFIG_USB_PD_REV30 */
-
-/*
- * PrlTxLayerResetForTransmit
- */
-static void prl_tx_layer_reset_for_transmit_entry(const int port)
-{
- print_current_prl_tx_state(port);
-
- if (pdmsg[port].xmit_type < NUM_SOP_STAR_TYPES) {
- /*
- * This state is only used during soft resets. Reset only the
- * matching message type.
- *
- * From section 6.3.13 Soft Reset Message in the USB PD 3.0
- * v2.0 spec, Soft_Reset Message Shall be targeted at a
- * specific entity depending on the type of SOP* Packet used.
- */
- prl_tx[port].msg_id_counter[pdmsg[port].xmit_type] = 0;
-
- /*
- * From section 6.11.2.3.2, the MessageID should be cleared
- * from the PRL_Rx_Layer_Reset_for_Receive state. However, we
- * don't implement a full state machine for PRL RX states so
- * clear the MessageID here.
- */
- prl_rx[port].msg_id[pdmsg[port].xmit_type] = -1;
- }
-}
-
-static void prl_tx_layer_reset_for_transmit_run(const int port)
-{
- /* NOTE: PRL_Tx_Construct_Message State embedded here */
- prl_tx_construct_message(port);
- set_state_prl_tx(port, PRL_TX_WAIT_FOR_PHY_RESPONSE);
-}
-
-static uint32_t get_sop_star_header(const int port)
-{
- const int is_sop_packet = pdmsg[port].xmit_type == TCPCI_MSG_SOP;
- int ext;
-
-#ifdef CONFIG_USB_PD_EXTENDED_MESSAGES
- ext = pdmsg[port].ext;
-#else
- ext = 0;
-#endif
-
- /* SOP vs SOP'/SOP" headers are different. Replace fields as needed */
- return PD_HEADER(
- pdmsg[port].msg_type,
- is_sop_packet ?
- pd_get_power_role(port) : tc_get_cable_plug(port),
- is_sop_packet ?
- pd_get_data_role(port) : 0,
- prl_tx[port].msg_id_counter[pdmsg[port].xmit_type],
- pdmsg[port].data_objs,
- pdmsg[port].rev[pdmsg[port].xmit_type],
- ext);
-}
-
-static void prl_tx_construct_message(const int port)
-{
- /* The header is unused for hard reset, etc. */
- const uint32_t header = pdmsg[port].xmit_type < NUM_SOP_STAR_TYPES ?
- get_sop_star_header(port) : 0;
-
- /* Save SOP* so the correct msg_id_counter can be incremented */
- prl_tx[port].last_xmit_type = pdmsg[port].xmit_type;
-
- /* Indicate that a tx message is being passed to the phy layer */
- prl_tx[port].xmit_status = TCPC_TX_WAIT;
- /*
- * PRL_FLAGS_TX_COMPLETE could be set if this function is called before
- * the Policy Engine is informed of the previous transmission. Clear the
- * flag so that this message can be sent.
- */
- PDMSG_CLR_FLAG(port, PRL_FLAGS_TX_COMPLETE);
-
- /*
- * Pass message to PHY Layer. It handles retries in hardware as the EC
- * cannot handle the required timing ~ 1ms (tReceive + tRetry).
- *
- * Note if we ever start sending large, extendend messages, then we
- * should not retry those messages. We do not support that and probably
- * never will (since we support chunking).
- */
- tcpm_transmit(port, pdmsg[port].xmit_type, header,
- pdmsg[port].tx_chk_buf);
-}
-
-/*
- * PrlTxWaitForPhyResponse
- */
-static void prl_tx_wait_for_phy_response_entry(const int port)
-{
- print_current_prl_tx_state(port);
-
- pd_timer_enable(port, PR_TIMER_TCPC_TX_TIMEOUT, PD_T_TCPC_TX_TIMEOUT);
-}
-
-static void prl_tx_wait_for_phy_response_run(const int port)
-{
- /* Wait until TX is complete */
-
- /*
- * NOTE: The TCPC will set xmit_status to TCPC_TX_COMPLETE_DISCARDED
- * when a GoodCRC containing an incorrect MessageID is received.
- * This condition satisfies the PRL_Tx_Match_MessageID state
- * requirement.
- */
-
- if (prl_tx[port].xmit_status == TCPC_TX_COMPLETE_SUCCESS) {
- /* NOTE: PRL_TX_Message_Sent State embedded here. */
- /* Increment messageId counter */
- increment_msgid_counter(port);
-
- /* Inform Policy Engine Message was sent */
- if (IS_ENABLED(CONFIG_USB_PD_EXTENDED_MESSAGES))
- PDMSG_SET_FLAG(port, PRL_FLAGS_TX_COMPLETE);
- else
- pe_message_sent(port);
-
- /*
- * This event reduces the time of informing the policy engine of
- * the transmission by one state machine cycle
- */
- task_wake(PD_PORT_TO_TASK_ID(port));
- set_state_prl_tx(port, PRL_TX_WAIT_FOR_MESSAGE_REQUEST);
- } else if (pd_timer_is_expired(port, PR_TIMER_TCPC_TX_TIMEOUT) ||
- prl_tx[port].xmit_status == TCPC_TX_COMPLETE_FAILED) {
- /*
- * NOTE: PRL_Tx_Transmission_Error State embedded
- * here.
- */
-
- if (IS_ENABLED(CONFIG_USB_PD_EXTENDED_MESSAGES)) {
- /*
- * State tch_wait_for_transmission_complete will
- * inform policy engine of error
- */
- PDMSG_SET_FLAG(port, PRL_FLAGS_TX_ERROR);
- } else {
- /* Report Error To Policy Engine */
- pe_report_error(port, ERR_TCH_XMIT,
- prl_tx[port].last_xmit_type);
- }
-
- /* Increment message id counter */
- increment_msgid_counter(port);
- set_state_prl_tx(port, PRL_TX_WAIT_FOR_MESSAGE_REQUEST);
- }
-}
-
-static void prl_tx_wait_for_phy_response_exit(const int port)
-{
- pd_timer_disable(port, PR_TIMER_TCPC_TX_TIMEOUT);
-}
-
-/* Source Protocol Layer Message Transmission */
-/*
- * PrlTxSrcPending
- */
-static void prl_tx_src_pending_entry(const int port)
-{
- print_current_prl_tx_state(port);
-
- /* Start SinkTxTimer */
- pd_timer_enable(port, PR_TIMER_SINK_TX, PD_T_SINK_TX);
-}
-
-static void prl_tx_src_pending_run(const int port)
-{
- if (pd_timer_is_expired(port, PR_TIMER_SINK_TX)) {
- /*
- * We clear the pending XMIT flag here right before we send so
- * we can detect if we discarded this message or not
- */
- PRL_TX_CLR_FLAG(port, PRL_FLAGS_MSG_XMIT);
-
- /*
- * Soft Reset Message pending &
- * SinkTxTimer timeout
- */
- if ((tx_emsg[port].len == 0) &&
- (pdmsg[port].msg_type == PD_CTRL_SOFT_RESET)) {
- set_state_prl_tx(port, PRL_TX_LAYER_RESET_FOR_TRANSMIT);
- }
- /* Message pending (except Soft Reset) &
- * SinkTxTimer timeout
- */
- else {
- prl_tx_construct_message(port);
- set_state_prl_tx(port, PRL_TX_WAIT_FOR_PHY_RESPONSE);
- }
-
- return;
- }
-}
-
-static void prl_tx_src_pending_exit(int port)
-{
- pd_timer_disable(port, PR_TIMER_SINK_TX);
-}
-
-/*
- * PrlTxSnkPending
- */
-static void prl_tx_snk_pending_entry(const int port)
-{
- print_current_prl_tx_state(port);
-}
-
-static void prl_tx_snk_pending_run(const int port)
-{
- bool start_tx = false;
-
- /*
- * Wait unit the SRC applies SINK_TX_OK so we can transmit. In FRS mode,
- * don't wait for SINK_TX_OK since either the source (and Rp) could be
- * gone or the TCPC CC_STATUS update time could be too long to meet
- * tFRSwapInit.
- */
- if (pe_in_frs_mode(port)) {
- /* shortcut to save some i2c_xfer calls on the FRS path. */
- start_tx = true;
- } else {
- enum tcpc_cc_voltage_status cc1, cc2;
-
- tcpm_get_cc(port, &cc1, &cc2);
- start_tx = (cc1 == TYPEC_CC_VOLT_RP_3_0 ||
- cc2 == TYPEC_CC_VOLT_RP_3_0);
- }
- if (start_tx) {
- /*
- * We clear the pending XMIT flag here right before we send so
- * we can detect if we discarded this message or not
- */
- PRL_TX_CLR_FLAG(port, PRL_FLAGS_MSG_XMIT);
-
- /*
- * Soft Reset Message Message pending &
- * Rp = SinkTxOk
- */
- if ((pdmsg[port].msg_type == PD_CTRL_SOFT_RESET) &&
- (tx_emsg[port].len == 0)) {
- set_state_prl_tx(port, PRL_TX_LAYER_RESET_FOR_TRANSMIT);
- }
- /*
- * Message pending (except Soft Reset) &
- * Rp = SinkTxOk
- */
- else {
- prl_tx_construct_message(port);
- set_state_prl_tx(port, PRL_TX_WAIT_FOR_PHY_RESPONSE);
- }
- return;
- }
-}
-
-/* Hard Reset Operation */
-void prl_hr_send_msg_to_phy(const int port)
-{
- /* Header is not used for hard reset */
- const uint32_t header = 0;
-
- pdmsg[port].xmit_type = TCPCI_MSG_TX_HARD_RESET;
-
- /*
- * These flags could be set if this function is called before the
- * Policy Engine is informed of the previous transmission. Clear the
- * flags so that this message can be sent.
- */
- prl_tx[port].xmit_status = TCPC_TX_UNSET;
- PDMSG_CLR_FLAG(port, PRL_FLAGS_TX_COMPLETE);
-
- /* Pass message to PHY Layer */
- tcpm_transmit(port, pdmsg[port].xmit_type, header,
- pdmsg[port].tx_chk_buf);
-}
-
-static void prl_hr_wait_for_request_entry(const int port)
-{
- print_current_prl_hr_state(port);
-
- prl_hr[port].flags = 0;
-}
-
-static void prl_hr_wait_for_request_run(const int port)
-{
- if (PRL_HR_CHK_FLAG(port, PRL_FLAGS_PE_HARD_RESET |
- PRL_FLAGS_PORT_PARTNER_HARD_RESET))
- set_state_prl_hr(port, PRL_HR_RESET_LAYER);
-}
-
-/*
- * PrlHrResetLayer
- */
-static void prl_hr_reset_layer_entry(const int port)
-{
- int i;
-
- print_current_prl_hr_state(port);
-
- if (IS_ENABLED(CONFIG_USB_PD_EXTENDED_MESSAGES)) {
- tch[port].flags = 0;
- rch[port].flags = 0;
- }
-
- pdmsg[port].flags = 0;
-
- /* Hard reset resets messageIDCounters for all TX types */
- for (i = 0; i < NUM_SOP_STAR_TYPES; i++) {
- prl_rx[port].msg_id[i] = -1;
- prl_tx[port].msg_id_counter[i] = 0;
- }
-
- /* Disable RX */
- if (IS_ENABLED(CONFIG_USB_CTVPD) ||
- IS_ENABLED(CONFIG_USB_VPD))
- vpd_rx_enable(0);
- else
- tcpm_set_rx_enable(port, 0);
-
- /*
- * PD r3.0 v2.0, ss6.2.1.1.5:
- * After a physical or logical (USB Type-C Error Recovery) Attach, a
- * Port discovers the common Specification Revision level between itself
- * and its Port Partner and/or the Cable Plug(s), and uses this
- * Specification Revision level until a Detach, Hard Reset or Error
- * Recovery happens.
- *
- * This covers the Hard Reset case.
- */
- prl_set_default_pd_revision(port);
-
- /* Inform the AP of Hard Reset */
- if (IS_ENABLED(CONFIG_USB_PD_HOST_CMD))
- pd_notify_event(port, PD_STATUS_EVENT_HARD_RESET);
-
- /*
- * Protocol Layer message transmission transitions to
- * PRL_Tx_Wait_For_Message_Request state.
- */
- set_state_prl_tx(port, PRL_TX_WAIT_FOR_MESSAGE_REQUEST);
-
- return;
-}
-
-static void prl_hr_reset_layer_run(const int port)
-{
- /*
- * Protocol Layer reset Complete &
- * Hard Reset was initiated by Policy Engine
- */
- if (PRL_HR_CHK_FLAG(port, PRL_FLAGS_PE_HARD_RESET)) {
- /*
- * Request PHY to perform a Hard Reset. Note
- * PRL_HR_Request_Reset state is embedded here.
- */
- prl_hr_send_msg_to_phy(port);
- set_state_prl_hr(port, PRL_HR_WAIT_FOR_PHY_HARD_RESET_COMPLETE);
- }
- /*
- * Protocol Layer reset complete &
- * Hard Reset was initiated by Port Partner
- */
- else {
- /* Inform Policy Engine of the Hard Reset */
- pe_got_hard_reset(port);
- set_state_prl_hr(port, PRL_HR_WAIT_FOR_PE_HARD_RESET_COMPLETE);
- }
-}
-
-/*
- * PrlHrWaitForPhyHardResetComplete
- */
-static void prl_hr_wait_for_phy_hard_reset_complete_entry(const int port)
-{
- print_current_prl_hr_state(port);
-
- /* Start HardResetCompleteTimer */
- pd_timer_enable(port, PR_TIMER_HARD_RESET_COMPLETE,
- PD_T_PS_HARD_RESET);
-}
-
-static void prl_hr_wait_for_phy_hard_reset_complete_run(const int port)
-{
- /*
- * Wait for hard reset from PHY
- * or timeout
- */
- if (PDMSG_CHK_FLAG(port, PRL_FLAGS_TX_COMPLETE) ||
- pd_timer_is_expired(port, PR_TIMER_HARD_RESET_COMPLETE)) {
- /* PRL_HR_PHY_Hard_Reset_Requested */
-
- /* Inform Policy Engine Hard Reset was sent */
- pe_hard_reset_sent(port);
- set_state_prl_hr(port, PRL_HR_WAIT_FOR_PE_HARD_RESET_COMPLETE);
-
- return;
- }
-}
-
-static void prl_hr_wait_for_phy_hard_reset_complete_exit(int port)
-{
- pd_timer_disable(port, PR_TIMER_HARD_RESET_COMPLETE);
-}
-
-/*
- * PrlHrWaitForPeHardResetComplete
- */
-static void prl_hr_wait_for_pe_hard_reset_complete_entry(const int port)
-{
- print_current_prl_hr_state(port);
-}
-
-static void prl_hr_wait_for_pe_hard_reset_complete_run(const int port)
-{
- /*
- * Wait for Hard Reset complete indication from Policy Engine
- */
- if (PRL_HR_CHK_FLAG(port, PRL_FLAGS_HARD_RESET_COMPLETE))
- set_state_prl_hr(port, PRL_HR_WAIT_FOR_REQUEST);
-}
-
-static void prl_hr_wait_for_pe_hard_reset_complete_exit(const int port)
-{
- /* Exit from Hard Reset */
-
- set_state_prl_tx(port, PRL_TX_PHY_LAYER_RESET);
- if (IS_ENABLED(CONFIG_USB_PD_EXTENDED_MESSAGES)) {
- set_state_rch(port, RCH_WAIT_FOR_MESSAGE_FROM_PROTOCOL_LAYER);
- set_state_tch(port, TCH_WAIT_FOR_MESSAGE_REQUEST_FROM_PE);
- }
-}
-
-static void copy_chunk_to_ext(int port)
-{
- /* Calculate number of bytes */
- pdmsg[port].num_bytes_received =
- (PD_HEADER_CNT(rx_emsg[port].header) * 4);
-
- /* Copy chunk into extended message */
- memcpy((uint8_t *)rx_emsg[port].buf, (uint8_t *)pdmsg[port].rx_chk_buf,
- pdmsg[port].num_bytes_received);
-
- /* Set extended message length */
- rx_emsg[port].len = pdmsg[port].num_bytes_received;
-}
-
-#ifdef CONFIG_USB_PD_EXTENDED_MESSAGES
-/*
- * Chunked Rx State Machine
- */
-/*
- * RchWaitForMessageFromProtocolLayer
- */
-static void rch_wait_for_message_from_protocol_layer_entry(const int port)
-{
- print_current_rch_state(port);
-
- /* Clear Abort flag */
- PDMSG_CLR_FLAG(port, PRL_FLAGS_ABORT);
-
- /* All Messages are chunked */
- rch[port].flags = PRL_FLAGS_CHUNKING;
-}
-
-static void rch_wait_for_message_from_protocol_layer_run(const int port)
-{
- if (RCH_CHK_FLAG(port, PRL_FLAGS_MSG_RECEIVED)) {
- RCH_CLR_FLAG(port, PRL_FLAGS_MSG_RECEIVED);
- /*
- * Are we communicating with a PD3.0 device and is
- * this an extended message?
- */
- if (pdmsg_xmit_type_is_rev30(port)
- && PD_HEADER_EXT(rx_emsg[port].header)) {
- uint16_t exhdr =
- GET_EXT_HEADER(*pdmsg[port].rx_chk_buf);
- uint8_t chunked = PD_EXT_HEADER_CHUNKED(exhdr);
-
- /*
- * Received Extended Message &
- * (Chunking = 1 & Chunked = 1)
- */
- if ((RCH_CHK_FLAG(port, PRL_FLAGS_CHUNKING)) &&
- chunked) {
- /*
- * RCH_Processing_Extended_Message first chunk
- * entry processing embedded here
- *
- * This is the first chunk:
- * Set Chunk_number_expected = 0 and
- * Num_Bytes_Received = 0
- */
- pdmsg[port].chunk_number_expected = 0;
- pdmsg[port].num_bytes_received = 0;
- pdmsg[port].msg_type =
- PD_HEADER_TYPE(rx_emsg[port].header);
-
- set_state_rch(port,
- RCH_PROCESSING_EXTENDED_MESSAGE);
- }
- /*
- * (Received Extended Message &
- * (Chunking = 0 & Chunked = 0))
- */
- else if (!RCH_CHK_FLAG(port, PRL_FLAGS_CHUNKING) &&
- !chunked) {
- /* Copy chunk to extended buffer */
- copy_chunk_to_ext(port);
- set_state_rch(port, RCH_PASS_UP_MESSAGE);
- }
- /*
- * Chunked != Chunking
- */
- else {
- rch[port].error = ERR_RCH_CHUNKED;
- set_state_rch(port, RCH_REPORT_ERROR);
- }
- }
- /*
- * Received Non-Extended Message
- */
- else if (!PD_HEADER_EXT(rx_emsg[port].header)) {
- /* Copy chunk to extended buffer */
- copy_chunk_to_ext(port);
- set_state_rch(port, RCH_PASS_UP_MESSAGE);
- }
- /*
- * Received an Extended Message while communicating at a
- * revision lower than PD3.0
- */
- else {
- rch[port].error = ERR_RCH_CHUNKED;
- set_state_rch(port, RCH_REPORT_ERROR);
- }
- }
-}
-
-/*
- * RchPassUpMessage
- */
-static void rch_pass_up_message_entry(const int port)
-{
- print_current_rch_state(port);
-
- /* Pass Message to Policy Engine */
- pe_message_received(port);
- set_state_rch(port, RCH_WAIT_FOR_MESSAGE_FROM_PROTOCOL_LAYER);
-}
-
-/*
- * RchProcessingExtendedMessage
- */
-static void rch_processing_extended_message_entry(const int port)
-{
- print_current_rch_state(port);
-}
-
-static void rch_processing_extended_message_run(const int port)
-{
- uint16_t exhdr = GET_EXT_HEADER(pdmsg[port].rx_chk_buf[0]);
- uint8_t chunk_num = PD_EXT_HEADER_CHUNK_NUM(exhdr);
- uint32_t data_size = PD_EXT_HEADER_DATA_SIZE(exhdr);
- uint32_t byte_num;
-
- /*
- * Abort Flag Set
- */
- if (PDMSG_CHK_FLAG(port, PRL_FLAGS_ABORT))
- set_state_rch(port, RCH_WAIT_FOR_MESSAGE_FROM_PROTOCOL_LAYER);
-
- /*
- * If expected Chunk Number:
- * Append data to Extended_Message_Buffer
- * Increment Chunk_number_Expected
- * Adjust Num Bytes Received
- */
- else if (chunk_num == pdmsg[port].chunk_number_expected) {
- byte_num = data_size - pdmsg[port].num_bytes_received;
-
- if (byte_num >= PD_MAX_EXTENDED_MSG_CHUNK_LEN)
- byte_num = PD_MAX_EXTENDED_MSG_CHUNK_LEN;
-
- /* Make sure extended message buffer does not overflow */
- if (pdmsg[port].num_bytes_received +
- byte_num > EXTENDED_BUFFER_SIZE) {
- rch[port].error = ERR_RCH_CHUNKED;
- set_state_rch(port, RCH_REPORT_ERROR);
- return;
- }
-
- /* Append data */
- /* Add 2 to chk_buf to skip over extended message header */
- memcpy(((uint8_t *)rx_emsg[port].buf +
- pdmsg[port].num_bytes_received),
- (uint8_t *)pdmsg[port].rx_chk_buf + 2,
- byte_num);
- /* increment chunk number expected */
- pdmsg[port].chunk_number_expected++;
- /* adjust num bytes received */
- pdmsg[port].num_bytes_received += byte_num;
-
- /* Was that the last chunk? */
- if (pdmsg[port].num_bytes_received >= data_size) {
- rx_emsg[port].len = pdmsg[port].num_bytes_received;
- /* Pass Message to Policy Engine */
- set_state_rch(port, RCH_PASS_UP_MESSAGE);
- }
- /*
- * Message not Complete
- */
- else
- set_state_rch(port, RCH_REQUESTING_CHUNK);
- }
- /*
- * Unexpected Chunk Number
- */
- else {
- rch[port].error = ERR_RCH_CHUNKED;
- set_state_rch(port, RCH_REPORT_ERROR);
- }
-}
-
-/*
- * RchRequestingChunk
- */
-static void rch_requesting_chunk_entry(const int port)
-{
- print_current_rch_state(port);
-
- /*
- * Send Chunk Request to Protocol Layer
- * with chunk number = Chunk_Number_Expected
- */
- pdmsg[port].tx_chk_buf[0] = PD_EXT_HEADER(
- pdmsg[port].chunk_number_expected,
- 1, /* Request Chunk */
- 0 /* Data Size */
- );
-
- pdmsg[port].data_objs = 1;
- pdmsg[port].ext = 1;
- pdmsg[port].xmit_type = prl_rx[port].sop;
- PRL_TX_SET_FLAG(port, PRL_FLAGS_MSG_XMIT);
- task_set_event(PD_PORT_TO_TASK_ID(port), PD_EVENT_TX);
-}
-
-static void rch_requesting_chunk_run(const int port)
-{
- /*
- * Message Transmitted received from Protocol Layer
- */
- if (PDMSG_CHK_FLAG(port, PRL_FLAGS_TX_COMPLETE)) {
- PDMSG_CLR_FLAG(port, PRL_FLAGS_TX_COMPLETE);
- set_state_rch(port, RCH_WAITING_CHUNK);
- } else if (PDMSG_CHK_FLAG(port, PRL_FLAGS_TX_ERROR)) {
- /* Transmission Error from Protocol Layer detetected */
- rch[port].error = ERR_RCH_CHUNKED;
- set_state_rch(port, RCH_REPORT_ERROR);
- } else if (RCH_CHK_FLAG(port, PRL_FLAGS_MSG_RECEIVED)) {
- /*
- * It is possible to have both message received and the chunk
- * request transmit complete before a full PRL SM run. But, the
- * PRL_RX state machine runs prior to RCH, but before PRL_TX, so
- * PRL_FLAGS_MSG_RECEIVED can be set without
- * PRL_FLAGS_TX_COMPLETE set at this point (though it will be
- * set as soon as PRL_TX is executed next.
- */
- set_state_rch(port, RCH_WAITING_CHUNK);
- }
-}
-
-/*
- * RchWaitingChunk
- */
-static void rch_waiting_chunk_entry(const int port)
-{
- print_current_rch_state(port);
-
- /*
- * Start ChunkSenderResponseTimer
- */
- pd_timer_enable(port, PR_TIMER_CHUNK_SENDER_RESPONSE,
- PD_T_CHUNK_SENDER_RESPONSE);
-}
-
-static void rch_waiting_chunk_run(const int port)
-{
- if (RCH_CHK_FLAG(port, PRL_FLAGS_MSG_RECEIVED)) {
- /*
- * Because of the 5 msec tick time, it is possible to have both
- * msg_received and tx_complete flags set for a given PRL sm
- * run. Since prl_rx runs prior to the tx state machines, clear
- * the tx_complete flag as the next chunk has already been
- * received.
- */
- if (PDMSG_CHK_FLAG(port, PRL_FLAGS_TX_COMPLETE))
- PDMSG_CLR_FLAG(port, PRL_FLAGS_TX_COMPLETE);
-
- /*
- * Leave PRL_FLAGS_MSG_RECEIVED flag set just in case an error
- * is detected. If an error is detected, PRL_FLAGS_MSG_RECEIVED
- * will be cleared in rch_report_error state.
- */
-
- if (PD_HEADER_EXT(rx_emsg[port].header)) {
- uint16_t exhdr =
- GET_EXT_HEADER(pdmsg[port].rx_chk_buf[0]);
- /*
- * Other Message Received from Protocol Layer
- */
- if (PD_EXT_HEADER_REQ_CHUNK(exhdr) ||
- !PD_EXT_HEADER_CHUNKED(exhdr)) {
- rch[port].error = ERR_RCH_CHUNKED;
- set_state_rch(port, RCH_REPORT_ERROR);
- }
- /*
- * Chunk response Received from Protocol Layer
- */
- else {
- /*
- * No error was detected, so clear
- * PRL_FLAGS_MSG_RECEIVED flag.
- */
- RCH_CLR_FLAG(port, PRL_FLAGS_MSG_RECEIVED);
- set_state_rch(port,
- RCH_PROCESSING_EXTENDED_MESSAGE);
- }
- }
- }
- /*
- * ChunkSenderResponseTimer Timeout
- */
- else if (pd_timer_is_expired(port, PR_TIMER_CHUNK_SENDER_RESPONSE)) {
- rch[port].error = ERR_RCH_CHUNK_WAIT_TIMEOUT;
- set_state_rch(port, RCH_REPORT_ERROR);
- }
-}
-
-static void rch_waiting_chunk_exit(int port)
-{
- pd_timer_disable(port, PR_TIMER_CHUNK_SENDER_RESPONSE);
-}
-
-/*
- * RchReportError
- */
-static void rch_report_error_entry(const int port)
-{
- print_current_rch_state(port);
-
- /*
- * If the state was entered because a message was received,
- * this message is passed to the Policy Engine.
- */
- if (RCH_CHK_FLAG(port, PRL_FLAGS_MSG_RECEIVED)) {
- RCH_CLR_FLAG(port, PRL_FLAGS_MSG_RECEIVED);
-
- /* Copy chunk to extended buffer */
- copy_chunk_to_ext(port);
- /* Pass Message to Policy Engine */
- pe_message_received(port);
- /* Report error */
- pe_report_error(port, ERR_RCH_MSG_REC, prl_rx[port].sop);
- } else {
- pe_report_error(port, rch[port].error, prl_rx[port].sop);
- }
-}
-
-static void rch_report_error_run(const int port)
-{
- set_state_rch(port, RCH_WAIT_FOR_MESSAGE_FROM_PROTOCOL_LAYER);
-}
-
-/*
- * Chunked Tx State Machine
- */
-
-/*
- * TchWaitForMessageRequestFromPe
- */
-static void tch_wait_for_message_request_from_pe_entry(const int port)
-{
- print_current_tch_state(port);
-
- /* Clear Abort flag */
- PDMSG_CLR_FLAG(port, PRL_FLAGS_ABORT);
-
- /* All Messages are chunked */
- tch[port].flags = PRL_FLAGS_CHUNKING;
-}
-
-static void tch_wait_for_message_request_from_pe_run(const int port)
-{
- /*
- * Any message received and not in state TCH_Wait_Chunk_Request
- */
- if (TCH_CHK_FLAG(port, PRL_FLAGS_MSG_RECEIVED)) {
- TCH_CLR_FLAG(port, PRL_FLAGS_MSG_RECEIVED);
- set_state_tch(port, TCH_MESSAGE_RECEIVED);
- } else if (TCH_CHK_FLAG(port, PRL_FLAGS_MSG_XMIT)) {
- TCH_CLR_FLAG(port, PRL_FLAGS_MSG_XMIT);
- /*
- * Rx Chunking State != RCH_Wait_For_Message_From_Protocol_Layer
- * & Abort Supported
- *
- * Discard the Message
- */
- if (rch_get_state(port) !=
- RCH_WAIT_FOR_MESSAGE_FROM_PROTOCOL_LAYER) {
- tch[port].error = ERR_TCH_XMIT;
- set_state_tch(port, TCH_REPORT_ERROR);
- } else {
- /*
- * Extended Message Request & Chunking
- */
- if (pdmsg_xmit_type_is_rev30(port)
- && pdmsg[port].ext
- && TCH_CHK_FLAG(port, PRL_FLAGS_CHUNKING)) {
- /*
- * NOTE: TCH_Prepare_To_Send_Chunked_Message
- * embedded here.
- */
- pdmsg[port].send_offset = 0;
- pdmsg[port].chunk_number_to_send = 0;
- set_state_tch(port,
- TCH_CONSTRUCT_CHUNKED_MESSAGE);
- } else
- /*
- * Non-Extended Message Request
- */
- {
- /* NOTE: TCH_Pass_Down_Message embedded here */
- prl_copy_msg_to_buffer(port);
-
- /* Pass Message to Protocol Layer */
- PRL_TX_SET_FLAG(port, PRL_FLAGS_MSG_XMIT);
- set_state_tch(port,
- TCH_WAIT_FOR_TRANSMISSION_COMPLETE);
- }
- }
- }
-}
-
-/*
- * TchWaitForTransmissionComplete
- */
-static void tch_wait_for_transmission_complete_entry(const int port)
-{
- print_current_tch_state(port);
-}
-
-static void tch_wait_for_transmission_complete_run(const int port)
-{
- /*
- * Inform Policy Engine that Message was sent.
- */
- if (PDMSG_CHK_FLAG(port, PRL_FLAGS_TX_COMPLETE)) {
- PDMSG_CLR_FLAG(port, PRL_FLAGS_TX_COMPLETE);
- set_state_tch(port, TCH_MESSAGE_SENT);
- return;
- }
- /*
- * Inform Policy Engine of Tx Error
- */
- else if (PDMSG_CHK_FLAG(port, PRL_FLAGS_TX_ERROR)) {
- PDMSG_CLR_FLAG(port, PRL_FLAGS_TX_ERROR);
- tch[port].error = ERR_TCH_XMIT;
- set_state_tch(port, TCH_REPORT_ERROR);
- return;
- }
- /*
- * A message was received while TCH is waiting for the phy to complete
- * sending a tx message.
- *
- * Because of our prl_sm architecture and I2C access delays for TCPCs,
- * it's possible to have a message received and the prl_tx state not be
- * in its default waiting state. To avoid a false protocol error, only
- * jump to TCH_MESSAGE_RECEIVED if the phy layer has not indicated that
- * the tx message was sent successfully.
- */
- if (TCH_CHK_FLAG(port, PRL_FLAGS_MSG_RECEIVED) &&
- prl_tx[port].xmit_status != TCPC_TX_COMPLETE_SUCCESS) {
- TCH_CLR_FLAG(port, PRL_FLAGS_MSG_RECEIVED);
- set_state_tch(port, TCH_MESSAGE_RECEIVED);
- return;
- }
-}
-
-/*
- * TchConstructChunkedMessage
- */
-static void tch_construct_chunked_message_entry(const int port)
-{
- uint16_t *ext_hdr;
- uint8_t *data;
- uint16_t num;
-
- print_current_tch_state(port);
-
- /*
- * Any message received and not in state TCH_Wait_Chunk_Request
- */
- if (TCH_CHK_FLAG(port, PRL_FLAGS_MSG_RECEIVED)) {
- TCH_CLR_FLAG(port, PRL_FLAGS_MSG_RECEIVED);
- set_state_tch(port, TCH_MESSAGE_RECEIVED);
- return;
- }
-
- /* Prepare to copy chunk into chk_buf */
-
- ext_hdr = (uint16_t *)pdmsg[port].tx_chk_buf;
- data = ((uint8_t *)pdmsg[port].tx_chk_buf + 2);
- num = tx_emsg[port].len - pdmsg[port].send_offset;
-
- if (num > PD_MAX_EXTENDED_MSG_CHUNK_LEN)
- num = PD_MAX_EXTENDED_MSG_CHUNK_LEN;
-
- /* Set the chunks extended header */
- *ext_hdr = PD_EXT_HEADER(pdmsg[port].chunk_number_to_send,
- 0, /* Chunk Request */
- tx_emsg[port].len);
-
- /* Copy the message chunk into chk_buf */
- memset(data, 0, 28);
- memcpy(data, tx_emsg[port].buf + pdmsg[port].send_offset, num);
- pdmsg[port].send_offset += num;
-
- /*
- * Add in 2 bytes for extended header
- * pad out to 4-byte boundary
- * convert to number of 4-byte words
- * Since the value is shifted right by 2,
- * no need to explicitly clear the lower
- * 2-bits.
- */
- pdmsg[port].data_objs = (num + 2 + 3) >> 2;
-
- /* Pass message chunk to Protocol Layer */
- PRL_TX_SET_FLAG(port, PRL_FLAGS_MSG_XMIT);
-}
-
-static void tch_construct_chunked_message_run(const int port)
-{
- if (PDMSG_CHK_FLAG(port, PRL_FLAGS_ABORT))
- set_state_tch(port, TCH_WAIT_FOR_MESSAGE_REQUEST_FROM_PE);
- else
- set_state_tch(port, TCH_SENDING_CHUNKED_MESSAGE);
-}
-
-/*
- * TchSendingChunkedMessage
- */
-static void tch_sending_chunked_message_entry(const int port)
-{
- print_current_tch_state(port);
-}
-
-static void tch_sending_chunked_message_run(const int port)
-{
- /*
- * Transmission Error
- */
- if (PDMSG_CHK_FLAG(port, PRL_FLAGS_TX_ERROR)) {
- tch[port].error = ERR_TCH_XMIT;
- set_state_tch(port, TCH_REPORT_ERROR);
- }
- /*
- * Message Transmitted from Protocol Layer &
- * Last Chunk
- */
- else if (tx_emsg[port].len == pdmsg[port].send_offset)
- set_state_tch(port, TCH_MESSAGE_SENT);
- /*
- * Any message received and not in state TCH_Wait_Chunk_Request
- */
- else if (TCH_CHK_FLAG(port, PRL_FLAGS_MSG_RECEIVED)) {
- TCH_CLR_FLAG(port, PRL_FLAGS_MSG_RECEIVED);
- set_state_tch(port, TCH_MESSAGE_RECEIVED);
- }
- /*
- * Message Transmitted from Protocol Layer &
- * Not Last Chunk
- */
- else
- set_state_tch(port, TCH_WAIT_CHUNK_REQUEST);
-}
-
-/*
- * TchWaitChunkRequest
- */
-static void tch_wait_chunk_request_entry(const int port)
-{
- print_current_tch_state(port);
-
- /* Increment Chunk Number to Send */
- pdmsg[port].chunk_number_to_send++;
- /* Start Chunk Sender Request Timer */
- pd_timer_enable(port, PR_TIMER_CHUNK_SENDER_REQUEST,
- PD_T_CHUNK_SENDER_REQUEST);
-}
-
-static void tch_wait_chunk_request_run(const int port)
-{
- if (TCH_CHK_FLAG(port, PRL_FLAGS_MSG_RECEIVED)) {
- TCH_CLR_FLAG(port, PRL_FLAGS_MSG_RECEIVED);
-
- if (PD_HEADER_EXT(rx_emsg[port].header)) {
- uint16_t exthdr;
-
- exthdr = GET_EXT_HEADER(pdmsg[port].rx_chk_buf[0]);
- if (PD_EXT_HEADER_REQ_CHUNK(exthdr)) {
- /*
- * Chunk Request Received &
- * Chunk Number = Chunk Number to Send
- */
- if (PD_EXT_HEADER_CHUNK_NUM(exthdr) ==
- pdmsg[port].chunk_number_to_send) {
- set_state_tch(port,
- TCH_CONSTRUCT_CHUNKED_MESSAGE);
- }
- /*
- * Chunk Request Received &
- * Chunk Number != Chunk Number to Send
- */
- else {
- tch[port].error = ERR_TCH_CHUNKED;
- set_state_tch(port, TCH_REPORT_ERROR);
- }
- return;
- }
- }
-
- /*
- * Other message received
- */
- set_state_tch(port, TCH_MESSAGE_RECEIVED);
- }
- /*
- * ChunkSenderRequestTimer timeout
- */
- else if (pd_timer_is_expired(port, PR_TIMER_CHUNK_SENDER_REQUEST))
- set_state_tch(port, TCH_MESSAGE_SENT);
-}
-
-static void tch_wait_chunk_request_exit(int port)
-{
- pd_timer_disable(port, PR_TIMER_CHUNK_SENDER_REQUEST);
-}
-
-/*
- * TchMessageReceived
- */
-static void tch_message_received_entry(const int port)
-{
- print_current_tch_state(port);
-
- /* Pass message to chunked Rx */
- RCH_SET_FLAG(port, PRL_FLAGS_MSG_RECEIVED);
-
- /* Clear extended message objects */
- if (TCH_CHK_FLAG(port, PRL_FLAGS_MSG_XMIT)) {
- TCH_CLR_FLAG(port, PRL_FLAGS_MSG_XMIT);
- pe_report_discard(port);
- }
- pdmsg[port].data_objs = 0;
-}
-
-static void tch_message_received_run(const int port)
-{
- set_state_tch(port, TCH_WAIT_FOR_MESSAGE_REQUEST_FROM_PE);
-}
-
-/*
- * TchMessageSent
- */
-static void tch_message_sent_entry(const int port)
-{
- print_current_tch_state(port);
-
- /* Tell PE message was sent */
- pe_message_sent(port);
-
- /*
- * Any message received and not in state TCH_Wait_Chunk_Request
- * MUST be checked after notifying PE
- */
- if (TCH_CHK_FLAG(port, PRL_FLAGS_MSG_RECEIVED)) {
- TCH_CLR_FLAG(port, PRL_FLAGS_MSG_RECEIVED);
- set_state_tch(port, TCH_MESSAGE_RECEIVED);
- return;
- }
-
-
-
- set_state_tch(port, TCH_WAIT_FOR_MESSAGE_REQUEST_FROM_PE);
-}
-
-/*
- * TchReportError
- */
-static void tch_report_error_entry(const int port)
-{
- print_current_tch_state(port);
-
- /* Report Error To Policy Engine */
- pe_report_error(port, tch[port].error, prl_tx[port].last_xmit_type);
-
- /*
- * Any message received and not in state TCH_Wait_Chunk_Request
- * MUST be checked after notifying PE
- */
- if (TCH_CHK_FLAG(port, PRL_FLAGS_MSG_RECEIVED)) {
- TCH_CLR_FLAG(port, PRL_FLAGS_MSG_RECEIVED);
- set_state_tch(port, TCH_MESSAGE_RECEIVED);
- return;
- }
-
-
- set_state_tch(port, TCH_WAIT_FOR_MESSAGE_REQUEST_FROM_PE);
-}
-#endif /* CONFIG_USB_PD_EXTENDED_MESSAGES */
-
-/*
- * Protocol Layer Message Reception State Machine
- */
-static void prl_rx_wait_for_phy_message(const int port, int evt)
-{
- uint32_t header;
- uint8_t type;
- uint8_t cnt;
- int8_t msid;
-
- /*
- * If PD3, wait for the RX chunk SM to copy the pdmsg into the extended
- * buffer before overwriting pdmsg.
- */
- if (IS_ENABLED(CONFIG_USB_PD_EXTENDED_MESSAGES) &&
- RCH_CHK_FLAG(port, PRL_FLAGS_MSG_RECEIVED))
- return;
-
- /* If we don't have any message, just stop processing now. */
- if (!tcpm_has_pending_message(port) ||
- tcpm_dequeue_message(port, pdmsg[port].rx_chk_buf, &header))
- return;
-
- rx_emsg[port].header = header;
- type = PD_HEADER_TYPE(header);
- cnt = PD_HEADER_CNT(header);
- msid = PD_HEADER_ID(header);
- prl_rx[port].sop = PD_HEADER_GET_SOP(header);
-
- /* Make sure an incorrect count doesn't overflow the chunk buffer */
- if (cnt > CHK_BUF_SIZE)
- cnt = CHK_BUF_SIZE;
-
- /* dump received packet content (only dump ping at debug level MAX) */
- if ((prl_debug_level >= DEBUG_LEVEL_2 && type != PD_CTRL_PING) ||
- prl_debug_level >= DEBUG_LEVEL_3) {
- int p;
-
- ccprintf("C%d: RECV %04x/%d ", port, header, cnt);
- for (p = 0; p < cnt; p++)
- ccprintf("[%d]%08x ", p, pdmsg[port].rx_chk_buf[p]);
- ccprintf("\n");
- }
-
- /*
- * Ignore messages sent to the cable from our
- * port partner if we aren't Vconn powered device.
- */
- if (!IS_ENABLED(CONFIG_USB_CTVPD) &&
- !IS_ENABLED(CONFIG_USB_VPD) &&
- PD_HEADER_GET_SOP(header) != TCPCI_MSG_SOP &&
- PD_HEADER_PROLE(header) == PD_PLUG_FROM_DFP_UFP)
- return;
-
- /* Handle incoming soft reset as special case */
- if (cnt == 0 && type == PD_CTRL_SOFT_RESET) {
- /* Clear MessageIdCounter */
- prl_tx[port].msg_id_counter[prl_rx[port].sop] = 0;
- /* Clear stored MessageID value */
- prl_rx[port].msg_id[prl_rx[port].sop] = -1;
-
- /* Soft Reset occurred */
- set_state_prl_tx(port, PRL_TX_PHY_LAYER_RESET);
-
- if (IS_ENABLED(CONFIG_USB_PD_EXTENDED_MESSAGES)) {
- set_state_rch(port,
- RCH_WAIT_FOR_MESSAGE_FROM_PROTOCOL_LAYER);
- set_state_tch(port,
- TCH_WAIT_FOR_MESSAGE_REQUEST_FROM_PE);
- }
-
- /*
- * Inform Policy Engine of Soft Reset. Note perform this after
- * performing the protocol layer reset, otherwise we will lose
- * the PE's outgoing ACCEPT message to the soft reset.
- */
- pe_got_soft_reset(port);
-
- return;
- }
-
- /*
- * Ignore if this is a duplicate message. Stop processing.
- */
- if (prl_rx[port].msg_id[prl_rx[port].sop] == msid)
- return;
-
- /*
- * Discard any pending tx message if this is
- * not a ping message (length must be checked to verify this is a
- * control message, rather than data)
- */
- if ((cnt > 0) || (type != PD_CTRL_PING)) {
- /*
- * Note: Spec dictates that we always go into
- * PRL_Tx_Discard_Message upon receivng a message. However, due
- * to our TCPC architecture we may be receiving a transmit
- * complete at the same time as a response so only do this if a
- * message is pending.
- */
- if (prl_tx[port].xmit_status != TCPC_TX_COMPLETE_SUCCESS ||
- PRL_TX_CHK_FLAG(port, PRL_FLAGS_MSG_XMIT))
- set_state_prl_tx(port, PRL_TX_DISCARD_MESSAGE);
- }
-
- /* Store Message Id */
- prl_rx[port].msg_id[prl_rx[port].sop] = msid;
-
- if (IS_ENABLED(CONFIG_USB_PD_EXTENDED_MESSAGES)) {
- /* RTR Chunked Message Router States. */
- /*
- * Received Ping from Protocol Layer
- */
- if (cnt == 0 && type == PD_CTRL_PING) {
- /* NOTE: RTR_PING State embedded here. */
- rx_emsg[port].len = 0;
- pe_message_received(port);
- return;
- }
- /*
- * Message (not Ping) Received from
- * Protocol Layer & Doing Tx Chunks
- *
- * Also, handle the case where a message has been
- * queued for sending but a message is received before
- * tch_wait_for_message_request_from_pe has been run
- */
- else if (tch_get_state(port) !=
- TCH_WAIT_FOR_MESSAGE_REQUEST_FROM_PE ||
- TCH_CHK_FLAG(port, PRL_FLAGS_MSG_XMIT)) {
- /* NOTE: RTR_TX_CHUNKS State embedded here. */
- /*
- * Send Message to Tx Chunk
- * Chunk State Machine
- */
- TCH_SET_FLAG(port, PRL_FLAGS_MSG_RECEIVED);
- }
- /*
- * Message (not Ping) Received from
- * Protocol Layer & Not Doing Tx Chunks
- */
- else {
- /* NOTE: RTR_RX_CHUNKS State embedded here. */
- /*
- * Send Message to Rx
- * Chunk State Machine
- */
- RCH_SET_FLAG(port, PRL_FLAGS_MSG_RECEIVED);
- }
- } else {
- /* Copy chunk to extended buffer */
- copy_chunk_to_ext(port);
- /* Send message to Policy Engine */
- pe_message_received(port);
- }
-
- task_wake(PD_PORT_TO_TASK_ID(port));
-}
-
-/* All necessary Protocol Transmit States (Section 6.11.2.2) */
-static __const_data const struct usb_state prl_tx_states[] = {
- [PRL_TX_PHY_LAYER_RESET] = {
- .entry = prl_tx_phy_layer_reset_entry,
- },
- [PRL_TX_WAIT_FOR_MESSAGE_REQUEST] = {
- .entry = prl_tx_wait_for_message_request_entry,
- .run = prl_tx_wait_for_message_request_run,
- },
- [PRL_TX_LAYER_RESET_FOR_TRANSMIT] = {
- .entry = prl_tx_layer_reset_for_transmit_entry,
- .run = prl_tx_layer_reset_for_transmit_run,
- },
- [PRL_TX_WAIT_FOR_PHY_RESPONSE] = {
- .entry = prl_tx_wait_for_phy_response_entry,
- .run = prl_tx_wait_for_phy_response_run,
- .exit = prl_tx_wait_for_phy_response_exit,
- },
-#ifdef CONFIG_USB_PD_REV30
- [PRL_TX_SRC_SOURCE_TX] = {
- .entry = prl_tx_src_source_tx_entry,
- .run = prl_tx_src_source_tx_run,
- },
- [PRL_TX_SNK_START_AMS] = {
- .entry = prl_tx_snk_start_ams_entry,
- .run = prl_tx_snk_start_ams_run,
- },
-#endif /* CONFIG_USB_PD_REV30 */
- [PRL_TX_SRC_PENDING] = {
- .entry = prl_tx_src_pending_entry,
- .run = prl_tx_src_pending_run,
- .exit = prl_tx_src_pending_exit,
- },
- [PRL_TX_SNK_PENDING] = {
- .entry = prl_tx_snk_pending_entry,
- .run = prl_tx_snk_pending_run,
- },
- [PRL_TX_DISCARD_MESSAGE] = {
- .entry = prl_tx_discard_message_entry,
- },
-};
-
-/* All necessary Protocol Hard Reset States (Section 6.11.2.4) */
-static __const_data const struct usb_state prl_hr_states[] = {
- [PRL_HR_WAIT_FOR_REQUEST] = {
- .entry = prl_hr_wait_for_request_entry,
- .run = prl_hr_wait_for_request_run,
- },
- [PRL_HR_RESET_LAYER] = {
- .entry = prl_hr_reset_layer_entry,
- .run = prl_hr_reset_layer_run,
- },
- [PRL_HR_WAIT_FOR_PHY_HARD_RESET_COMPLETE] = {
- .entry = prl_hr_wait_for_phy_hard_reset_complete_entry,
- .run = prl_hr_wait_for_phy_hard_reset_complete_run,
- .exit = prl_hr_wait_for_phy_hard_reset_complete_exit,
- },
- [PRL_HR_WAIT_FOR_PE_HARD_RESET_COMPLETE] = {
- .entry = prl_hr_wait_for_pe_hard_reset_complete_entry,
- .run = prl_hr_wait_for_pe_hard_reset_complete_run,
- .exit = prl_hr_wait_for_pe_hard_reset_complete_exit,
- },
-};
-
-/* All necessary Chunked Rx states (Section 6.11.2.1.2) */
-__maybe_unused static const struct usb_state rch_states[] = {
-#ifdef CONFIG_USB_PD_EXTENDED_MESSAGES
- [RCH_WAIT_FOR_MESSAGE_FROM_PROTOCOL_LAYER] = {
- .entry = rch_wait_for_message_from_protocol_layer_entry,
- .run = rch_wait_for_message_from_protocol_layer_run,
- },
- [RCH_PASS_UP_MESSAGE] = {
- .entry = rch_pass_up_message_entry,
- },
- [RCH_PROCESSING_EXTENDED_MESSAGE] = {
- .entry = rch_processing_extended_message_entry,
- .run = rch_processing_extended_message_run,
- },
- [RCH_REQUESTING_CHUNK] = {
- .entry = rch_requesting_chunk_entry,
- .run = rch_requesting_chunk_run,
- },
- [RCH_WAITING_CHUNK] = {
- .entry = rch_waiting_chunk_entry,
- .run = rch_waiting_chunk_run,
- .exit = rch_waiting_chunk_exit,
- },
- [RCH_REPORT_ERROR] = {
- .entry = rch_report_error_entry,
- .run = rch_report_error_run,
- },
-#endif /* CONFIG_USB_PD_EXTENDED_MESSAGES */
-};
-
-/* All necessary Chunked Tx states (Section 6.11.2.1.3) */
-__maybe_unused static const struct usb_state tch_states[] = {
-#ifdef CONFIG_USB_PD_EXTENDED_MESSAGES
- [TCH_WAIT_FOR_MESSAGE_REQUEST_FROM_PE] = {
- .entry = tch_wait_for_message_request_from_pe_entry,
- .run = tch_wait_for_message_request_from_pe_run,
- },
- [TCH_WAIT_FOR_TRANSMISSION_COMPLETE] = {
- .entry = tch_wait_for_transmission_complete_entry,
- .run = tch_wait_for_transmission_complete_run,
- },
- [TCH_CONSTRUCT_CHUNKED_MESSAGE] = {
- .entry = tch_construct_chunked_message_entry,
- .run = tch_construct_chunked_message_run,
- },
- [TCH_SENDING_CHUNKED_MESSAGE] = {
- .entry = tch_sending_chunked_message_entry,
- .run = tch_sending_chunked_message_run,
- },
- [TCH_WAIT_CHUNK_REQUEST] = {
- .entry = tch_wait_chunk_request_entry,
- .run = tch_wait_chunk_request_run,
- .exit = tch_wait_chunk_request_exit,
- },
- [TCH_MESSAGE_RECEIVED] = {
- .entry = tch_message_received_entry,
- .run = tch_message_received_run,
- },
- [TCH_MESSAGE_SENT] = {
- .entry = tch_message_sent_entry,
- },
- [TCH_REPORT_ERROR] = {
- .entry = tch_report_error_entry,
- },
-#endif /* CONFIG_USB_PD_EXTENDED_MESSAGES */
-};
-
-#ifdef TEST_BUILD
-
-const struct test_sm_data test_prl_sm_data[] = {
- {
- .base = prl_tx_states,
- .size = ARRAY_SIZE(prl_tx_states),
- .names = prl_tx_state_names,
- .names_size = ARRAY_SIZE(prl_tx_state_names),
- },
- {
- .base = prl_hr_states,
- .size = ARRAY_SIZE(prl_hr_states),
- .names = prl_hr_state_names,
- .names_size = ARRAY_SIZE(prl_hr_state_names),
- },
-#ifdef CONFIG_USB_PD_EXTENDED_MESSAGES
- {
- .base = rch_states,
- .size = ARRAY_SIZE(rch_states),
- .names = rch_state_names,
- .names_size = ARRAY_SIZE(rch_state_names),
- },
- {
- .base = tch_states,
- .size = ARRAY_SIZE(tch_states),
- .names = tch_state_names,
- .names_size = ARRAY_SIZE(tch_state_names),
- },
-#endif /* CONFIG_USB_PD_EXTENDED_MESSAGES */
-};
-BUILD_ASSERT(ARRAY_SIZE(prl_tx_states) == ARRAY_SIZE(prl_tx_state_names));
-BUILD_ASSERT(ARRAY_SIZE(prl_hr_states) == ARRAY_SIZE(prl_hr_state_names));
-#ifdef CONFIG_USB_PD_EXTENDED_MESSAGES
-BUILD_ASSERT(ARRAY_SIZE(rch_states) == ARRAY_SIZE(rch_state_names));
-BUILD_ASSERT(ARRAY_SIZE(tch_states) == ARRAY_SIZE(tch_state_names));
-#endif /* CONFIG_USB_PD_EXTENDED_MESSAGES */
-const int test_prl_sm_data_size = ARRAY_SIZE(test_prl_sm_data);
-#endif
diff --git a/common/usbc/usb_retimer_fw_update.c b/common/usbc/usb_retimer_fw_update.c
deleted file mode 100644
index 1ff198c78f..0000000000
--- a/common/usbc/usb_retimer_fw_update.c
+++ /dev/null
@@ -1,189 +0,0 @@
-/* Copyright 2021 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 <stdbool.h>
-#include <stdint.h>
-#include "compile_time_macros.h"
-#include "console.h"
-#include "hooks.h"
-#include "timer.h"
-#include "usb_common.h"
-#include "usb_mux.h"
-#include "usb_tc_sm.h"
-
-#ifdef CONFIG_COMMON_RUNTIME
-#define CPRINTS(format, args...) cprints(CC_USBPD, format, ## args)
-#define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args)
-#else
-#define CPRINTS(format, args...)
-#define CPRINTF(format, args...)
-#endif
-
-/*
- * Retimer firmware update is initiated by AP.
- * The operations requested by AP are:
- * 0 - USB_RETIMER_FW_UPDATE_QUERY_PORT
- * 1 - USB_RETIMER_FW_UPDATE_SUSPEND_PD
- * 2 - USB_RETIMER_FW_UPDATE_RESUME_PD
- * 3 - USB_RETIMER_FW_UPDATE_GET_MUX
- * 4 - USB_RETIMER_FW_UPDATE_SET_USB
- * 5 - USB_RETIMER_FW_UPDATE_SET_SAFE
- * 6 - USB_RETIMER_FW_UPDATE_SET_TBT
- * 7 - USB_RETIMER_FW_UPDATE_DISCONNECT
- *
- * Operation 0 is processed immediately.
- * Operations 1 to 7 are deferred and processed inside tc_run().
- * Operations 1/2/3 can be processed any time; while 4/5/6/7 have
- * to be processed when PD task is suspended.
- * Two TC flags are created for this situation.
- * If Op 1/2/3 is received, TC_FLAGS_USB_RETIMER_FW_UPDATE_RUN
- * is set, PD task will be waken up and process it.
- * If 4/5/6/7 is received, TC_FLAGS_USB_RETIMER_FW_UPDATE_LTD_RUN is
- * set, PD task should be in suspended mode and process it.
- *
- */
-
-#define SUSPEND 1
-#define RESUME 0
-
-/* Track current port AP requested to update retimer firmware */
-static int cur_port;
-static int last_op; /* Operation received from AP via ACPI_WRITE */
-/* Operation result returned to ACPI_READ */
-static int last_result;
-
-int usb_retimer_fw_update_get_result(void)
-{
- int result = 0;
-
- switch (last_op) {
- case USB_RETIMER_FW_UPDATE_SUSPEND_PD:
- if (last_result == USB_RETIMER_FW_UPDATE_ERR) {
- result = last_result;
- break;
- }
- /* fall through */
- case USB_RETIMER_FW_UPDATE_RESUME_PD:
- result = pd_is_port_enabled(cur_port);
- break;
- case USB_RETIMER_FW_UPDATE_QUERY_PORT:
- result = usb_mux_retimer_fw_update_port_info();
- break;
- case USB_RETIMER_FW_UPDATE_GET_MUX:
- case USB_RETIMER_FW_UPDATE_SET_USB:
- case USB_RETIMER_FW_UPDATE_SET_SAFE:
- case USB_RETIMER_FW_UPDATE_SET_TBT:
- case USB_RETIMER_FW_UPDATE_DISCONNECT:
- result = last_result;
- break;
- default:
- break;
- }
-
- return result;
-}
-
-static void deferred_pd_suspend(void)
-{
- pd_set_suspend(cur_port, SUSPEND);
-}
-DECLARE_DEFERRED(deferred_pd_suspend);
-
-static inline mux_state_t retimer_fw_update_usb_mux_get(int port)
-{
- return usb_mux_get(port) & USB_RETIMER_FW_UPDATE_MUX_MASK;
-}
-
-void usb_retimer_fw_update_process_op_cb(int port)
-{
- switch (last_op) {
- case USB_RETIMER_FW_UPDATE_SUSPEND_PD:
- last_result = 0;
- /*
- * Do not perform retimer firmware update process
- * if battery is not present, or battery level is low.
- */
- if (!pd_firmware_upgrade_check_power_readiness(port)) {
- last_result = USB_RETIMER_FW_UPDATE_ERR;
- break;
- }
-
- /*
- * If the port has entered low power mode, the PD task
- * is paused and will not complete processing of
- * pd_set_suspend(). Move pd_set_suspend() into a deferred
- * call so that it runs from the HOOKS task and can generate
- * a wake event to the PD task and enter suspended mode.
- */
- hook_call_deferred(&deferred_pd_suspend_data, 0);
- break;
- case USB_RETIMER_FW_UPDATE_RESUME_PD:
- pd_set_suspend(port, RESUME);
- break;
- case USB_RETIMER_FW_UPDATE_GET_MUX:
- last_result = retimer_fw_update_usb_mux_get(port);
- break;
- case USB_RETIMER_FW_UPDATE_SET_USB:
- usb_mux_set(port, USB_PD_MUX_USB_ENABLED,
- USB_SWITCH_CONNECT, pd_get_polarity(port));
- last_result = retimer_fw_update_usb_mux_get(port);
- break;
- case USB_RETIMER_FW_UPDATE_SET_SAFE:
- usb_mux_set_safe_mode(port);
- last_result = retimer_fw_update_usb_mux_get(port);
- break;
- case USB_RETIMER_FW_UPDATE_SET_TBT:
- usb_mux_set(port, USB_PD_MUX_TBT_COMPAT_ENABLED,
- USB_SWITCH_CONNECT, pd_get_polarity(port));
- last_result = retimer_fw_update_usb_mux_get(port);
- break;
- case USB_RETIMER_FW_UPDATE_DISCONNECT:
- usb_mux_set(port, USB_PD_MUX_NONE,
- USB_SWITCH_DISCONNECT, pd_get_polarity(port));
- last_result = retimer_fw_update_usb_mux_get(port);
- break;
- default:
- break;
- }
-}
-
-void usb_retimer_fw_update_process_op(int port, int op)
-{
- ASSERT(port >= 0 && port < CONFIG_USB_PD_PORT_MAX_COUNT);
-
- /*
- * TODO(b/179220036): check not overlapping requests;
- * not change cur_port if retimer scan is in progress
- */
- last_op = op;
-
- switch (op) {
- case USB_RETIMER_FW_UPDATE_QUERY_PORT:
- break;
- /* Operations can't be processed in ISR, defer to later */
- case USB_RETIMER_FW_UPDATE_GET_MUX:
- last_result = USB_RETIMER_FW_UPDATE_INVALID_MUX;
- tc_usb_firmware_fw_update_run(port);
- break;
- case USB_RETIMER_FW_UPDATE_SUSPEND_PD:
- case USB_RETIMER_FW_UPDATE_RESUME_PD:
- cur_port = port;
- tc_usb_firmware_fw_update_run(port);
- break;
- case USB_RETIMER_FW_UPDATE_SET_USB:
- case USB_RETIMER_FW_UPDATE_SET_SAFE:
- case USB_RETIMER_FW_UPDATE_SET_TBT:
- case USB_RETIMER_FW_UPDATE_DISCONNECT:
- if (pd_is_port_enabled(port)) {
- last_result = USB_RETIMER_FW_UPDATE_ERR;
- } else {
- last_result = USB_RETIMER_FW_UPDATE_INVALID_MUX;
- tc_usb_firmware_fw_update_limited_run(port);
- }
- break;
- default:
- break;
- }
-}
diff --git a/common/usbc/usb_sm.c b/common/usbc/usb_sm.c
deleted file mode 100644
index 04b7193c0f..0000000000
--- a/common/usbc/usb_sm.c
+++ /dev/null
@@ -1,202 +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 "console.h"
-#include "stdbool.h"
-#include "task.h"
-#include "usb_pd.h"
-#include "usb_sm.h"
-#include "util.h"
-
-#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
-
-/* Private structure (to this file) used to track state machine context */
-struct internal_ctx {
- usb_state_ptr last_entered;
- uint32_t running : 1;
- uint32_t enter : 1;
- uint32_t exit : 1;
-};
-BUILD_ASSERT(sizeof(struct internal_ctx) ==
- member_size(struct sm_ctx, internal));
-
-/* Gets the first shared parent state between a and b (inclusive) */
-static usb_state_ptr shared_parent_state(usb_state_ptr a, usb_state_ptr b)
-{
- const usb_state_ptr orig_b = b;
-
- /* There are no common ancestors */
- if (b == NULL)
- return NULL;
-
- /* This assumes that both A and B are NULL terminated without cycles */
- while (a != NULL) {
- /* We found a match return */
- if (a == b)
- return a;
-
- /*
- * Otherwise, increment b down the list for comparison until we
- * run out, then increment a and start over on b for comparison
- */
- if (b->parent == NULL) {
- a = a->parent;
- b = orig_b;
- } else {
- b = b->parent;
- }
- }
-
- return NULL;
-}
-
-/*
- * Call all entry functions of parents before children. If set_state is called
- * during one of the entry functions, then do not call any remaining entry
- * functions.
- */
-static void call_entry_functions(const int port,
- struct internal_ctx *const internal,
- const usb_state_ptr stop,
- const usb_state_ptr current)
-{
- if (current == stop)
- return;
-
- call_entry_functions(port, internal, stop, current->parent);
-
- /*
- * If the previous entry function called set_state, then don't enter
- * remaining states.
- */
- if (!internal->enter)
- return;
-
- /* Track the latest state that was entered, so we can exit properly. */
- internal->last_entered = current;
- if (current->entry)
- current->entry(port);
-}
-
-/*
- * Call all exit functions of children before parents. Note set_state is ignored
- * during an exit function.
- */
-static void call_exit_functions(const int port, const usb_state_ptr stop,
- const usb_state_ptr current)
-{
- if (current == stop)
- return;
-
- if (current->exit)
- current->exit(port);
-
- call_exit_functions(port, stop, current->parent);
-}
-
-void set_state(const int port, struct sm_ctx *const ctx,
- const usb_state_ptr new_state)
-{
- struct internal_ctx * const internal = (void *) ctx->internal;
- usb_state_ptr last_state;
- usb_state_ptr shared_parent;
-
- /*
- * It does not make sense to call set_state in an exit phase of a state
- * since we are already in a transition; we would always ignore the
- * intended state to transition into.
- */
- if (internal->exit) {
- CPRINTF("C%d: Ignoring set state to 0x%pP within 0x%pP",
- port, new_state, ctx->current);
- return;
- }
-
- /*
- * Determine the last state that was entered. Normally it is current,
- * but we could have called set_state within an entry phase, so we
- * shouldn't exit any states that weren't fully entered.
- */
- last_state = internal->enter ? internal->last_entered : ctx->current;
-
- /* We don't exit and re-enter shared parent states */
- shared_parent = shared_parent_state(last_state, new_state);
-
- /*
- * Exit all of the non-common states from the last state.
- */
- internal->exit = true;
- call_exit_functions(port, shared_parent, last_state);
- internal->exit = false;
-
- ctx->previous = ctx->current;
- ctx->current = new_state;
-
- /*
- * Enter all new non-common states. last_entered will contain the last
- * state that successfully entered before another set_state was called.
- */
- internal->last_entered = NULL;
- internal->enter = true;
- call_entry_functions(port, internal, shared_parent, ctx->current);
- /*
- * Setting enter to false ensures that all pending entry calls will be
- * skipped (in the case of a parent state calling set_state, which means
- * we should not enter any child states)
- */
- internal->enter = false;
-
- /*
- * If we set_state while we are running a child state, then stop running
- * any remaining parent states.
- */
- internal->running = false;
-
- /*
- * Since we are changing states, we want to ensure that we process the
- * next state's run method as soon as we can to ensure that we don't
- * delay important processing until the next task interval.
- */
- if (IS_ENABLED(HAS_TASK_PD_C0))
- task_wake(PD_PORT_TO_TASK_ID(port));
-}
-
-/*
- * Call all run functions of children before parents. If set_state is called
- * during one of the entry functions, then do not call any remaining entry
- * functions.
- */
-static void call_run_functions(const int port,
- const struct internal_ctx *const internal,
- const usb_state_ptr current)
-{
- if (!current)
- return;
-
- /* If set_state is called during run, don't call remain functions. */
- if (!internal->running)
- return;
-
- if (current->run)
- current->run(port);
-
- call_run_functions(port, internal, current->parent);
-}
-
-void run_state(const int port, struct sm_ctx *const ctx)
-{
- struct internal_ctx * const internal = (void *) ctx->internal;
-
- internal->running = true;
- call_run_functions(port, internal, ctx->current);
- internal->running = false;
-}
diff --git a/common/usbc/usb_tc_ctvpd_sm.c b/common/usbc/usb_tc_ctvpd_sm.c
deleted file mode 100644
index a2babe754a..0000000000
--- a/common/usbc/usb_tc_ctvpd_sm.c
+++ /dev/null
@@ -1,1716 +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 "console.h"
-#include "system.h"
-#include "task.h"
-#include "tcpm/tcpm.h"
-#include "usb_pd.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_USBPD, format, ## args)
-#define CPRINTS(format, args...) cprints(CC_USBPD, 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)
-
-#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.
- */
-static struct type_c {
- /* state machine context */
- struct sm_ctx ctx;
- /* Higher-level power deliver state machines are enabled if true. */
- uint8_t pd_enable;
- /* port flags, see TC_FLAGS_* */
- uint32_t flags;
- /*
- * Time a charge-through port shall wait before it can determine it
- * is attached
- */
- uint64_t cc_debounce;
- /* Time a host port shall wait before it can determine it is attached */
- uint64_t host_cc_debounce;
- /* Time a Sink port shall wait before it can determine it is detached
- * due to the potential for USB PD signaling on CC as described in
- * the state definitions.
- */
- uint64_t pd_debounce;
- /* Maintains state of billboard device */
- int billboard_presented;
- /*
- * Time a port shall wait before it can determine it is
- * re-attached during the try-wait process.
- */
- uint64_t try_wait_debounce;
- /* charge-through support timer */
- uint64_t support_timer;
- /* reset the charge-through support timer */
- uint8_t support_timer_reset;
- /* VPD host port cc state */
- enum pd_cc_states host_cc_state;
- uint8_t ct_cc;
- /* The cc state */
- enum pd_cc_states cc_state;
- uint64_t next_role_swap;
-} tc[CONFIG_USB_PD_PORT_MAX_COUNT];
-
-/* List of all TypeC-level states */
-enum usb_tc_state {
- /* Normal States */
- TC_DISABLED,
- TC_UNATTACHED_SNK,
- TC_ATTACH_WAIT_SNK,
- TC_ATTACHED_SNK,
- TC_ERROR_RECOVERY,
- TC_TRY_SNK,
- TC_UNATTACHED_SRC,
- TC_ATTACH_WAIT_SRC,
- TC_TRY_WAIT_SRC,
- TC_ATTACHED_SRC,
- TC_CT_TRY_SNK,
- TC_CT_ATTACH_WAIT_UNSUPPORTED,
- TC_CT_ATTACHED_UNSUPPORTED,
- TC_CT_UNATTACHED_UNSUPPORTED,
- TC_CT_UNATTACHED_VPD,
- TC_CT_DISABLED_VPD,
- TC_CT_ATTACHED_VPD,
- TC_CT_ATTACH_WAIT_VPD,
- /* Super States */
- TC_VBUS_CC_ISO,
- TC_HOST_RARD_CT_RD,
- TC_HOST_OPEN_CT_OPEN,
- TC_HOST_RP3_CT_RD,
- TC_HOST_RP3_CT_RPU,
- TC_HOST_RPU_CT_RD,
-};
-
-/* Forward declare the full list of states. This is indexed by usb_tc_state */
-static const struct usb_state tc_states[];
-
-
-/* List of human readable state names for console debugging */
-__maybe_unused const char * const tc_state_names[] = {
-#ifdef CONFIG_COMMON_RUNTIME
- [TC_DISABLED] = "Disabled",
- [TC_UNATTACHED_SNK] = "Unattached.SNK",
- [TC_ATTACH_WAIT_SNK] = "AttachWait.SNK",
- [TC_ATTACHED_SNK] = "Attached.SNK",
- [TC_ERROR_RECOVERY] = "ErrorRecovery",
- [TC_TRY_SNK] = "Try.SNK",
- [TC_UNATTACHED_SRC] = "Unattached.SRC",
- [TC_ATTACH_WAIT_SRC] = "AttachWait.SRC",
- [TC_TRY_WAIT_SRC] = "TryWait.SRC",
- [TC_ATTACHED_SRC] = "Attached.SRC",
- [TC_CT_TRY_SNK] = "CTTry.SNK",
- [TC_CT_ATTACH_WAIT_UNSUPPORTED] = "CTAttachWait.Unsupported",
- [TC_CT_ATTACHED_UNSUPPORTED] = "CTAttached.Unsupported",
- [TC_CT_UNATTACHED_UNSUPPORTED] = "CTUnattached.Unsupported",
- [TC_CT_UNATTACHED_VPD] = "CTUnattached.VPD",
- [TC_CT_DISABLED_VPD] = "CTDisabled.VPD",
- [TC_CT_ATTACHED_VPD] = "CTAttached.VPD",
- [TC_CT_ATTACH_WAIT_VPD] = "CTAttachWait.VPD",
-#endif
-};
-
-/* Forward declare private, common functions */
-static void set_state_tc(const int port, enum usb_tc_state new_state);
-
-/* Public TypeC functions */
-
-enum pd_power_role pd_get_power_role(int port)
-{
- /* Vconn power device is always the sink */
- return PD_ROLE_SINK;
-}
-
-enum pd_cable_plug tc_get_cable_plug(int port)
-{
- /* Vconn power device is always the cable */
- return PD_PLUG_FROM_CABLE;
-}
-
-enum pd_data_role pd_get_data_role(int port)
-{
- /* Vconn power device doesn't have a data role, but UFP matches SNK */
- return PD_ROLE_UFP;
-}
-
-/* Note tc_set_power_role and tc_set_data_role are unimplemented */
-
-uint8_t tc_get_polarity(int port)
-{
- /* Does not track polarity */
- return 0;
-}
-
-uint8_t tc_get_pd_enabled(int port)
-{
- return tc[port].pd_enable;
-}
-
-void tc_reset_support_timer(int port)
-{
- tc[port].support_timer_reset |= SUPPORT_TIMER_RESET_REQUEST;
-}
-
-/*
- * TCPC CC/Rp management
- *
- * Stub for linking purposes.
- * This is not supported for ctvpd, we are never the SOP partner.
- */
-void typec_select_pull(int port, enum tcpc_cc_pull pull)
-{
-}
-void typec_select_src_current_limit_rp(int port, enum tcpc_rp_value rp)
-{
-}
-void typec_select_src_collision_rp(int port, enum tcpc_rp_value rp)
-{
-}
-int typec_update_cc(int port)
-{
- return EC_SUCCESS;
-}
-
-void tc_state_init(int port)
-{
- int res = 0;
-
- res = tcpm_init(port);
-
- CPRINTS("C%d: init %s", port, res ? "failed" : "ready");
-
- /* Disable if restart failed, otherwise start in default state. */
- set_state_tc(port, res ? TC_DISABLED : TC_UNATTACHED_SNK);
-
- /* Disable pd state machines */
- tc[port].pd_enable = 0;
- tc[port].billboard_presented = 0;
- tc[port].flags = 0;
-}
-
-void tc_event_check(int port, int evt)
-{
- /* Do Nothing */
-}
-
-void tc_run(const int port)
-{
- run_state(port, &tc[port].ctx);
-}
-
-/* Internal Functions */
-
-/* Set the TypeC state machine to a new state. */
-static void set_state_tc(const int port, enum usb_tc_state new_state)
-{
- set_state(port, &tc[port].ctx, &tc_states[new_state]);
-}
-
-/* Get the current TypeC state. */
-test_export_static enum usb_tc_state get_state_tc(const int port)
-{
- return tc[port].ctx.current - &tc_states[0];
-}
-
-/* Get the previous TypeC state. */
-static enum usb_tc_state get_last_state_tc(const int port)
-{
- return tc[port].ctx.previous - &tc_states[0];
-}
-
-test_mockable_static void print_current_state(const int port)
-{
- CPRINTS("C%d: %s", port, tc_state_names[get_state_tc(port)]);
-}
-
-int pd_is_connected(int port)
-{
- return (get_state_tc(port) == TC_ATTACHED_SNK) ||
- (get_state_tc(port) == TC_ATTACHED_SRC) ||
- (get_state_tc(port) == TC_CT_ATTACHED_UNSUPPORTED) ||
- (get_state_tc(port) == TC_CT_ATTACHED_VPD);
-}
-
-bool pd_is_disconnected(int port)
-{
- return !pd_is_connected(port);
-}
-
-/**
- * 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 void tc_disabled_entry(const int port)
-{
- print_current_state(port);
-}
-
-static void tc_disabled_run(const int port)
-{
- task_wait_event(-1);
-}
-
-static void tc_disabled_exit(const int port)
-{
- if (!IS_ENABLED(CONFIG_USB_PD_TCPC)) {
- if (tcpm_init(port) != 0) {
- CPRINTS("C%d: restart failed!", port);
- return;
- }
- }
-
- CPRINTS("C%d: resumed!", port);
-}
-
-void pd_set_suspend(int port, int suspend)
-{
- /*
- * This shouldn't happen. If it does, we need to send an event to the
- * PD task to put the SM into the disabled state. It is not safe to
- * directly set_state here since this may be in another task.
- */
- assert(false);
-}
-
-/**
- * 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 void tc_error_recovery_entry(const int port)
-{
- print_current_state(port);
- /* Use cc_debounce state variable for error recovery timeout */
- tc[port].cc_debounce = get_time().val + PD_T_ERROR_RECOVERY;
-}
-
-static void tc_error_recovery_run(const int port)
-{
- if (get_time().val > tc[port].cc_debounce)
- set_state_tc(port, TC_UNATTACHED_SNK);
-}
-
-/**
- * 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 void tc_unattached_snk_entry(const int port)
-{
- if (get_last_state_tc(port) != TC_UNATTACHED_SRC)
- print_current_state(port);
-
- tc[port].flags &= ~TC_FLAGS_VCONN_ON;
- tc[port].cc_state = PD_CC_UNSET;
-}
-
-static void tc_unattached_snk_run(const 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_tc(port, TC_ATTACH_WAIT_SNK);
- return;
- }
-
- /* 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;
-
- /*
- * 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_tc(port, TC_UNATTACHED_SRC);
- return;
- }
-}
-
-/**
- * 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 void tc_attach_wait_snk_entry(const int port)
-{
- print_current_state(port);
- tc[port].host_cc_state = PD_CC_UNSET;
-}
-
-static void tc_attach_wait_snk_run(const 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;
- }
-
- /* Wait for Host CC debounce */
- if (get_time().val < tc[port].host_cc_debounce)
- return;
-
- /*
- * 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_tc(port, TC_ATTACHED_SNK);
- else if (tc[port].host_cc_state == PD_CC_NONE)
- set_state_tc(port, TC_UNATTACHED_SNK);
-}
-
-/**
- * Attached.SNK
- */
-static void tc_attached_snk_entry(const int port)
-{
- print_current_state(port);
-
- /* Enable PD */
- tc[port].pd_enable = 1;
- pd_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;
-}
-
-static void tc_attached_snk_run(const 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_tc(port, TC_UNATTACHED_SNK);
- return;
- }
-
- /*
- * 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;
- }
-
- /* Wait for Host CC debounce */
- if (get_time().val < tc[port].host_cc_debounce)
- return;
-
- 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_tc(port, TC_CT_UNATTACHED_VPD);
- return;
- }
- }
-
- /* 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);
- }
-}
-
-static void tc_attached_snk_exit(const int port)
-{
- tc[port].billboard_presented = 0;
- vpd_present_billboard(BB_NONE);
-}
-
-/**
- * Super State HOST_RA_CT_RD
- */
-static void tc_host_rard_ct_rd_entry(const 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);
-}
-
-/**
- * Super State HOST_OPEN_CT_OPEN
- */
-static void tc_host_open_ct_open_entry(const 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);
-}
-
-/**
- * Super State VBUS_CC_ISO
- */
-static void tc_vbus_cc_iso_entry(const 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);
-}
-
-/**
- * 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 void tc_unattached_src_entry(const int port)
-{
- if (get_last_state_tc(port) != TC_UNATTACHED_SNK)
- print_current_state(port);
-
- /* 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_tc(port, TC_ERROR_RECOVERY);
- return;
- }
-
- tc[port].next_role_swap = get_time().val + PD_T_DRP_SRC;
-}
-
-static void tc_unattached_src_run(const 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_tc(port, TC_ATTACH_WAIT_SRC);
- return;
- }
-
- /*
- * 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_tc(port, TC_UNATTACHED_SNK);
- return;
- }
-}
-
-/**
- * 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 void tc_attach_wait_src_entry(const int port)
-{
- print_current_state(port);
-
- tc[port].host_cc_state = PD_CC_UNSET;
-}
-
-static void tc_attach_wait_src_run(const 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_tc(port, TC_UNATTACHED_SNK);
- return;
- }
-
- /* 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;
- }
-
- /* Wait for Host CC debounce */
- if (get_time().val < tc[port].cc_debounce)
- return;
-
- /*
- * 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_tc(port, TC_TRY_SNK);
- return;
- }
-}
-
-/**
- * Attached.SRC
- */
-static void tc_attached_src_entry(const int port)
-{
- print_current_state(port);
-
- /* Enable PD */
- tc[port].pd_enable = 1;
- pd_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);
-}
-
-static void tc_attached_src_run(const 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_tc(port, TC_UNATTACHED_SNK);
-}
-
-/**
- * Super State HOST_RPU_CT_RD
- */
-static void tc_host_rpu_ct_rd_entry(const 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);
-}
-
-/**
- * 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 void tc_try_snk_entry(const int port)
-{
- print_current_state(port);
-
- /* 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_tc(port, TC_ERROR_RECOVERY);
- return;
- }
-
- 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;
-}
-
-static void tc_try_snk_run(const 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;
-
- /* 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;
- }
-
- /* Wait for Host CC debounce */
- if (get_time().val < tc[port].cc_debounce)
- return;
-
- /*
- * 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_tc(port, TC_ATTACHED_SNK);
- else if (tc[port].host_cc_state == PD_CC_NONE)
- set_state_tc(port, TC_TRY_WAIT_SRC);
-}
-
-/**
- * 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 void tc_try_wait_src_entry(const int port)
-{
- print_current_state(port);
-
- tc[port].host_cc_state = PD_CC_UNSET;
- tc[port].next_role_swap = get_time().val + PD_T_DRP_TRY;
-}
-
-static void tc_try_wait_src_run(const 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;
- }
-
- 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_tc(port, TC_ATTACHED_SRC);
- return;
- }
- }
-
- 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_tc(port, TC_UNATTACHED_SNK);
- return;
- }
- }
-}
-
-/**
- * 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 void tc_ct_try_snk_entry(const int port)
-{
- print_current_state(port);
-
- /* Enable PD */
- tc[port].pd_enable = 1;
- pd_set_polarity(port, 0);
-
- tc[port].cc_state = PD_CC_UNSET;
- tc[port].next_role_swap = get_time().val + PD_T_DRP_TRY;
-}
-
-static void tc_ct_try_snk_run(const 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;
-
- /* 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_tc(port, TC_UNATTACHED_SNK);
- return;
- }
-
- /* 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;
- }
-
- 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_tc(port, TC_CT_ATTACHED_VPD);
- return;
- }
- }
-
- 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_tc(port,
- TC_CT_ATTACHED_UNSUPPORTED);
- return;
- }
- }
-}
-
-static void tc_ct_try_snk_exit(const int port)
-{
- /* Disable PD */
- tc[port].pd_enable = 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 void tc_ct_attach_wait_unsupported_entry(const int port)
-{
- print_current_state(port);
-
- /* Enable PD */
- tc[port].pd_enable = 1;
- pd_set_polarity(port, 0);
-
- tc[port].cc_state = PD_CC_UNSET;
-}
-
-static void tc_ct_attach_wait_unsupported_run(const 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_UFP_ATTACHED;
- else if (cc_is_audio_acc(cc1, cc2))
- new_cc_state = PD_CC_UFP_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_tc(port, TC_UNATTACHED_SNK);
- return;
- }
-
- /* 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;
- }
-
- /* Wait for CC debounce */
- if (get_time().val < tc[port].cc_debounce)
- return;
-
- /*
- * 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_tc(port, TC_CT_UNATTACHED_VPD);
- else /* PD_CC_UFP_ATTACHED or PD_CC_UFP_AUDIO_ACC */
- set_state_tc(port, TC_CT_TRY_SNK);
-}
-
-static void tc_ct_attach_wait_unsupported_exit(const int port)
-{
- /* Disable PD */
- tc[port].pd_enable = 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 void tc_ct_attached_unsupported_entry(const int port)
-{
- print_current_state(port);
-
- /* Present Billboard device */
- vpd_present_billboard(BB_SNK);
-}
-
-static void tc_ct_attached_unsupported_run(const int port)
-{
- int cc1;
- int cc2;
-
- /* Check CT CC for connection */
- vpd_ct_get_cc(&cc1, &cc2);
-
- if (!vpd_is_vconn_present()) {
- set_state_tc(port, TC_UNATTACHED_SNK);
- return;
- }
-
- /*
- * 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_tc(port, TC_CT_UNATTACHED_VPD);
- return;
- }
-}
-
-static void tc_ct_attached_unsupported_exit(const int port)
-{
- vpd_present_billboard(BB_NONE);
-}
-
-/**
- * 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 void tc_ct_unattached_unsupported_entry(const int port)
-{
- if (get_last_state_tc(port) != TC_CT_UNATTACHED_VPD)
- print_current_state(port);
-
- /* Enable PD */
- tc[port].pd_enable = 1;
- pd_set_polarity(port, 0);
-
- tc[port].next_role_swap = get_time().val + PD_T_DRP_SRC;
-}
-
-static void tc_ct_unattached_unsupported_run(const 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_tc(port,
- TC_CT_ATTACH_WAIT_UNSUPPORTED);
- return;
- }
-
- /*
- * A Charge-Through VCONN-Powered USB Device shall transition to
- * Unattached.SNK if VCONN falls below vVCONNDisconnect.
- */
- if (!vpd_is_vconn_present()) {
- set_state_tc(port, TC_UNATTACHED_SNK);
- return;
- }
-
- /*
- * 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_tc(port, TC_CT_UNATTACHED_VPD);
- return;
- }
-}
-
-static void tc_ct_unattached_unsupported_exit(const int port)
-{
- /* Disable PD */
- tc[port].pd_enable = 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 void tc_ct_unattached_vpd_entry(const int port)
-{
- if (get_last_state_tc(port) != TC_CT_UNATTACHED_UNSUPPORTED)
- print_current_state(port);
-
- /* Enable PD */
- tc[port].pd_enable = 1;
- pd_set_polarity(port, 0);
-
- tc[port].cc_state = PD_CC_UNSET;
-}
-
-static void tc_ct_unattached_vpd_run(const 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_tc(port, TC_CT_ATTACH_WAIT_VPD);
- return;
- }
-
- /*
- * A Charge-Through VCONN-Powered USB Device shall transition to
- * Unattached.SNK if VCONN falls below vVCONNDisconnect.
- */
- if (!vpd_is_vconn_present()) {
- set_state_tc(port, TC_UNATTACHED_SNK);
- return;
- }
-
- /* 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;
- }
-
- if (get_time().val < tc[port].cc_debounce)
- return;
-
- /*
- * 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_tc(port, TC_CT_UNATTACHED_UNSUPPORTED);
- return;
- }
-}
-
-static void tc_ct_unattached_vpd_exit(const int port)
-{
- /* Disable PD */
- tc[port].pd_enable = 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 void tc_ct_disabled_vpd_entry(const int port)
-{
- print_current_state(port);
-
- /* Get power from VBUS */
- vpd_vconn_pwr_sel_odl(PWR_VBUS);
-
- tc[port].next_role_swap = get_time().val + PD_T_VPDDISABLE;
-}
-
-static void tc_ct_disabled_vpd_run(const 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_tc(port, TC_UNATTACHED_SNK);
-}
-
-/**
- * CTAttached.VPD
- */
-static void tc_ct_attached_vpd_entry(const int port)
-{
- int cc1;
- int cc2;
- print_current_state(port);
-
- /* 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;
-}
-
-static void tc_ct_attached_vpd_run(const 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_tc(port, TC_CT_DISABLED_VPD);
- return;
- }
-
- /* 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;
- }
-
- if (get_time().val < tc[port].pd_debounce)
- return;
-
- /*
- * 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_tc(port, TC_CT_UNATTACHED_VPD);
-}
-
-/**
- * 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 void tc_ct_attach_wait_vpd_entry(const int port)
-{
- print_current_state(port);
-
- /* Enable PD */
- tc[port].pd_enable = 1;
- pd_set_polarity(port, 0);
-
- tc[port].cc_state = PD_CC_UNSET;
-}
-
-static void tc_ct_attach_wait_vpd_run(const 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_tc(port, TC_CT_DISABLED_VPD);
- return;
- }
-
- /* 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;
- }
-
- 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_tc(port, TC_CT_UNATTACHED_VPD);
- return;
- }
- }
-
- 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_tc(port, TC_CT_ATTACHED_VPD);
- return;
- }
- }
-}
-
-static void tc_ct_attach_wait_vpd_exit(const int port)
-{
- /* Disable PD */
- tc[port].pd_enable = 0;
-}
-
-/**
- * Super State HOST_RP3_CT_RD
- */
-static void tc_host_rp3_ct_rd_entry(const 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_tc(port, TC_ERROR_RECOVERY);
-
- /* Get power from VCONN */
- vpd_vconn_pwr_sel_odl(PWR_VCONN);
-}
-
-/**
- * Super State HOST_RP3_CT_RPU
- */
-static void tc_host_rp3_ct_rpu_entry(const 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_tc(port, TC_ERROR_RECOVERY);
-
- /* Get power from VCONN */
- vpd_vconn_pwr_sel_odl(PWR_VCONN);
-}
-
-/* All necessary Type-C states */
-
-/*
- * Type-C State Hierarchy (Sub-States are listed inside the boxes)
- *
- * | TC_VBUS_CC_ISO ------------------------------------------------------|
- * | |
- * | | TC_HOST_RARD_CT_RD -----------| | TC_HOST_OPEN_CT_OPEN ---------| |
- * | | | | | |
- * | | TC_UNATTACHED_SNK | | TC_DISABLED | |
- * | | TC_ATTACH_WAIT_SNK | | TC_ERROR_RECOVERY | |
- * | | TC_TRY_SNK | |-------------------------------| |
- * | |-------------------------------| |
- * | |
- * | | TC_HOST_RP3_CT_RD ------------| | TC_HOST_RPU_CT_RD ------------| |
- * | | | | | |
- * | | TC_CT_TRY_SNK | | TC_UNATTACHED_SRC | |
- * | | TC_CT_UNATTACHED_VPD | | TC_ATTACH_WAIT_SRC | |
- * | | TC_CT_ATTACH_WAIT_VPD | | TC_TRY_WAIT_SR | |
- * | |-------------------------------| |-------------------------------| |
- * | |
- * | | TC_HOST_RP3_CT_RPU -----------| |
- * | | | |
- * | | TC_CT_ATTACH_WAIT_UNSUPPORTED | |
- * | | TC_CT_ATTACHED_UNSUPPORTED | |
- * | | TC_CT_UNATTACHED_UNSUPPORTED | |
- * | |-------------------------------| |
- * |----------------------------------------------------------------------|
- *
- * TC_ATTACHED_SNK
- * TC_ATTACHED_SRC
- * TC_CT_ATTACHED_VPD
- *
- */
-static const struct usb_state tc_states[] = {
- /* Super States */
- [TC_VBUS_CC_ISO] = {
- .entry = tc_vbus_cc_iso_entry,
- },
- [TC_HOST_RARD_CT_RD] = {
- .entry = tc_host_rard_ct_rd_entry,
- .parent = &tc_states[TC_VBUS_CC_ISO],
- },
- [TC_HOST_OPEN_CT_OPEN] = {
- .entry = tc_host_open_ct_open_entry,
- .parent = &tc_states[TC_VBUS_CC_ISO],
- },
- [TC_HOST_RP3_CT_RD] = {
- .entry = tc_host_rp3_ct_rd_entry,
- .parent = &tc_states[TC_VBUS_CC_ISO],
- },
- [TC_HOST_RP3_CT_RPU] = {
- .entry = tc_host_rp3_ct_rpu_entry,
- .parent = &tc_states[TC_VBUS_CC_ISO],
- },
- [TC_HOST_RPU_CT_RD] = {
- .entry = tc_host_rpu_ct_rd_entry,
- .parent = &tc_states[TC_VBUS_CC_ISO],
- },
- /* Normal States */
- [TC_DISABLED] = {
- .entry = tc_disabled_entry,
- .run = tc_disabled_run,
- .exit = tc_disabled_exit,
- .parent = &tc_states[TC_HOST_OPEN_CT_OPEN],
- },
- [TC_UNATTACHED_SNK] = {
- .entry = tc_unattached_snk_entry,
- .run = tc_unattached_snk_run,
- .parent = &tc_states[TC_HOST_RARD_CT_RD],
- },
- [TC_ATTACH_WAIT_SNK] = {
- .entry = tc_attach_wait_snk_entry,
- .run = tc_attach_wait_snk_run,
- .parent = &tc_states[TC_HOST_RARD_CT_RD],
- },
- [TC_ATTACHED_SNK] = {
- .entry = tc_attached_snk_entry,
- .run = tc_attached_snk_run,
- .exit = tc_attached_snk_exit,
- },
- [TC_ERROR_RECOVERY] = {
- .entry = tc_error_recovery_entry,
- .run = tc_error_recovery_run,
- .parent = &tc_states[TC_HOST_OPEN_CT_OPEN],
- },
- [TC_TRY_SNK] = {
- .entry = tc_try_snk_entry,
- .run = tc_try_snk_run,
- .parent = &tc_states[TC_HOST_RARD_CT_RD],
- },
- [TC_UNATTACHED_SRC] = {
- .entry = tc_unattached_src_entry,
- .run = tc_unattached_src_run,
- .parent = &tc_states[TC_HOST_RPU_CT_RD],
- },
- [TC_ATTACH_WAIT_SRC] = {
- .entry = tc_attach_wait_src_entry,
- .run = tc_attach_wait_src_run,
- .parent = &tc_states[TC_HOST_RPU_CT_RD],
- },
- [TC_TRY_WAIT_SRC] = {
- .entry = tc_try_wait_src_entry,
- .run = tc_try_wait_src_run,
- .parent = &tc_states[TC_HOST_RPU_CT_RD],
- },
- [TC_ATTACHED_SRC] = {
- .entry = tc_attached_src_entry,
- .run = tc_attached_src_run,
- },
- [TC_CT_TRY_SNK] = {
- .entry = tc_ct_try_snk_entry,
- .run = tc_ct_try_snk_run,
- .exit = tc_ct_try_snk_exit,
- .parent = &tc_states[TC_HOST_RP3_CT_RD],
- },
- [TC_CT_ATTACH_WAIT_UNSUPPORTED] = {
- .entry = tc_ct_attach_wait_unsupported_entry,
- .run = tc_ct_attach_wait_unsupported_run,
- .exit = tc_ct_attach_wait_unsupported_exit,
- .parent = &tc_states[TC_HOST_RP3_CT_RPU],
- },
- [TC_CT_ATTACHED_UNSUPPORTED] = {
- .entry = tc_ct_attached_unsupported_entry,
- .run = tc_ct_attached_unsupported_run,
- .exit = tc_ct_attached_unsupported_exit,
- .parent = &tc_states[TC_HOST_RP3_CT_RPU],
- },
- [TC_CT_UNATTACHED_UNSUPPORTED] = {
- .entry = tc_ct_unattached_unsupported_entry,
- .run = tc_ct_unattached_unsupported_run,
- .exit = tc_ct_unattached_unsupported_exit,
- .parent = &tc_states[TC_HOST_RP3_CT_RPU],
- },
- [TC_CT_UNATTACHED_VPD] = {
- .entry = tc_ct_unattached_vpd_entry,
- .run = tc_ct_unattached_vpd_run,
- .exit = tc_ct_unattached_vpd_exit,
- .parent = &tc_states[TC_HOST_RP3_CT_RD],
- },
- [TC_CT_DISABLED_VPD] = {
- .entry = tc_ct_disabled_vpd_entry,
- .run = tc_ct_disabled_vpd_run,
- .parent = &tc_states[TC_HOST_OPEN_CT_OPEN],
- },
- [TC_CT_ATTACHED_VPD] = {
- .entry = tc_ct_attached_vpd_entry,
- .run = tc_ct_attached_vpd_run,
- },
- [TC_CT_ATTACH_WAIT_VPD] = {
- .entry = tc_ct_attach_wait_vpd_entry,
- .run = tc_ct_attach_wait_vpd_run,
- .exit = tc_ct_attach_wait_vpd_exit,
- .parent = &tc_states[TC_HOST_RP3_CT_RD],
- },
-};
-
-#ifdef TEST_BUILD
-const struct test_sm_data test_tc_sm_data[] = {
- {
- .base = tc_states,
- .size = ARRAY_SIZE(tc_states),
- .names = tc_state_names,
- .names_size = ARRAY_SIZE(tc_state_names),
- },
-};
-const int test_tc_sm_data_size = ARRAY_SIZE(test_tc_sm_data);
-#endif
diff --git a/common/usbc/usb_tc_drp_acc_trysrc_sm.c b/common/usbc/usb_tc_drp_acc_trysrc_sm.c
deleted file mode 100644
index 182ea686ec..0000000000
--- a/common/usbc/usb_tc_drp_acc_trysrc_sm.c
+++ /dev/null
@@ -1,4160 +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 "charge_manager.h"
-#include "charge_state.h"
-#include "common.h"
-#include "console.h"
-#include "hooks.h"
-#include "system.h"
-#include "task.h"
-#include "tcpm/tcpm.h"
-#include "usb_common.h"
-#include "usb_mux.h"
-#include "usb_pd.h"
-#include "usb_pd_dpm.h"
-#include "usb_pd_tcpm.h"
-#include "usb_pd_timer.h"
-#include "usb_pe_sm.h"
-#include "usb_prl_sm.h"
-#include "usb_sm.h"
-#include "usb_tc_sm.h"
-#include "usbc_ocp.h"
-#include "usbc_ppc.h"
-#include "vboot.h"
-
-/*
- * USB Type-C DRP with Accessory and Try.SRC module
- * See Figure 4-16 in Release 1.4 of USB Type-C Spec.
- */
-#ifdef CONFIG_COMMON_RUNTIME
-#define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args)
-#define CPRINTS(format, args...) cprints(CC_USBPD, format, ## args)
-#else /* CONFIG_COMMON_RUNTIME */
-#define CPRINTF(format, args...)
-#define CPRINTS(format, args...)
-#endif
-
-#define CPRINTF_LX(x, format, args...) \
- do { \
- if (tc_debug_level >= x) \
- CPRINTF(format, ## args); \
- } while (0)
-#define CPRINTF_L1(format, args...) CPRINTF_LX(1, format, ## args)
-#define CPRINTF_L2(format, args...) CPRINTF_LX(2, format, ## args)
-#define CPRINTF_L3(format, args...) CPRINTF_LX(3, format, ## args)
-
-#define CPRINTS_LX(x, format, args...) \
- do { \
- if (tc_debug_level >= x) \
- CPRINTS(format, ## args); \
- } while (0)
-#define CPRINTS_L1(format, args...) CPRINTS_LX(1, format, ## args)
-#define CPRINTS_L2(format, args...) CPRINTS_LX(2, format, ## args)
-#define CPRINTS_L3(format, args...) CPRINTS_LX(3, format, ## args)
-
-/*
- * Define DEBUG_PRINT_FLAG_AND_EVENT_NAMES to print flag names when set and
- * cleared, and event names when handled by tc_event_check().
- */
-#undef DEBUG_PRINT_FLAG_AND_EVENT_NAMES
-
-#ifdef DEBUG_PRINT_FLAG_AND_EVENT_NAMES
-void print_flag(int port, int set_or_clear, int flag);
-#define TC_SET_FLAG(port, flag) \
- do { \
- print_flag(port, 1, flag); \
- atomic_or(&tc[port].flags, (flag)); \
- } while (0)
-#define TC_CLR_FLAG(port, flag) \
- do { \
- print_flag(port, 0, flag); \
- atomic_clear_bits(&tc[port].flags, (flag)); \
- } while (0)
-#else
-#define TC_SET_FLAG(port, flag) atomic_or(&tc[port].flags, (flag))
-#define TC_CLR_FLAG(port, flag) atomic_clear_bits(&tc[port].flags, (flag))
-#endif
-#define TC_CHK_FLAG(port, flag) (tc[port].flags & (flag))
-
-/* Type-C Layer Flags */
-/* Flag to note we are sourcing VCONN */
-#define TC_FLAGS_VCONN_ON BIT(0)
-/* Flag to note port partner has Rp/Rp or Rd/Rd */
-#define TC_FLAGS_TS_DTS_PARTNER BIT(1)
-/* Flag to note VBus input has never been low */
-#define TC_FLAGS_VBUS_NEVER_LOW BIT(2)
-/* Flag to note Low Power Mode transition is currently happening */
-#define TC_FLAGS_LPM_TRANSITION BIT(3)
-/* Flag to note Low Power Mode is currently on */
-#define TC_FLAGS_LPM_ENGAGED BIT(4)
-/* Flag to note CVTPD has been detected */
-#define TC_FLAGS_CTVPD_DETECTED BIT(5)
-/* Flag to note request to swap to VCONN on */
-#define TC_FLAGS_REQUEST_VC_SWAP_ON BIT(6)
-/* Flag to note request to swap to VCONN off */
-#define TC_FLAGS_REQUEST_VC_SWAP_OFF BIT(7)
-/* Flag to note request to swap VCONN is being rejected */
-#define TC_FLAGS_REJECT_VCONN_SWAP BIT(8)
-/* Flag to note request to power role swap */
-#define TC_FLAGS_REQUEST_PR_SWAP BIT(9)
-/* Flag to note request to data role swap */
-#define TC_FLAGS_REQUEST_DR_SWAP BIT(10)
-/* Flag to note request to power off sink */
-#define TC_FLAGS_POWER_OFF_SNK BIT(11)
-/* Flag to note port partner is Power Delivery capable */
-#define TC_FLAGS_PARTNER_PD_CAPABLE BIT(12)
-/* Flag to note hard reset has been requested */
-#define TC_FLAGS_HARD_RESET_REQUESTED BIT(13)
-/* Flag to note we are currently performing PR Swap */
-#define TC_FLAGS_PR_SWAP_IN_PROGRESS BIT(14)
-/* Flag to note we should check for connection */
-#define TC_FLAGS_CHECK_CONNECTION BIT(15)
-/* Flag to note request from pd_set_suspend to enter TC_DISABLED state */
-#define TC_FLAGS_REQUEST_SUSPEND BIT(16)
-/* Flag to note we are in TC_DISABLED state */
-#define TC_FLAGS_SUSPENDED BIT(17)
-/* Flag to indicate the port current limit has changed */
-#define TC_FLAGS_UPDATE_CURRENT BIT(18)
-/* Flag to indicate USB mux should be updated */
-#define TC_FLAGS_UPDATE_USB_MUX BIT(19)
-/* Flag for retimer firmware update */
-#define TC_FLAGS_USB_RETIMER_FW_UPDATE_RUN BIT(20)
-#define TC_FLAGS_USB_RETIMER_FW_UPDATE_LTD_RUN BIT(21)
-/* Flag for asynchronous call to request Error Recovery */
-#define TC_FLAGS_REQUEST_ERROR_RECOVERY BIT(22)
-
-/* For checking flag_bit_names[] array */
-#define TC_FLAGS_COUNT 23
-
-/* On disconnect, clear most of the flags. */
-#define CLR_FLAGS_ON_DISCONNECT(port) TC_CLR_FLAG(port, \
- ~(TC_FLAGS_LPM_ENGAGED | TC_FLAGS_REQUEST_SUSPEND | TC_FLAGS_SUSPENDED))
-
-/*
- * 10 ms is enough time for any TCPC transaction to complete
- *
- * This value must be below ~39.7 ms to put ANX7447 into LPM due to bug in
- * silicon (see b/77544959 and b/149761477 for more details).
- */
-#define PD_LPM_DEBOUNCE_US (10 * MSEC)
-
-/*
- * This delay is not part of the USB Type-C specification or the USB port
- * controller specification. Some TCPCs require extra time before the CC_STATUS
- * register is updated when exiting low power mode.
- *
- * This delay can be possibly shortened or removed by checking VBUS state
- * before trying to re-enter LPM.
- *
- * TODO(b/162347811): TCPMv2: Wait for debounce on Vbus and CC lines
- */
-#define PD_LPM_EXIT_DEBOUNCE_US CONFIG_USB_PD_TCPC_LPM_EXIT_DEBOUNCE
-
-/*
- * The TypeC state machine uses this bit to disable/enable PD
- * This bit corresponds to bit-0 of pd_disabled_mask
- */
-#define PD_DISABLED_NO_CONNECTION BIT(0)
-/*
- * Console and Host commands use this bit to override the
- * PD_DISABLED_NO_CONNECTION bit that was set by the TypeC
- * state machine.
- * This bit corresponds to bit-1 of pd_disabled_mask
- */
-#define PD_DISABLED_BY_POLICY BIT(1)
-
-/* Unreachable time in future */
-#define TIMER_DISABLED 0xffffffffffffffff
-
-enum ps_reset_sequence {
- PS_STATE0,
- PS_STATE1,
- PS_STATE2,
-};
-
-/* List of all TypeC-level states */
-enum usb_tc_state {
- /* Super States */
- TC_CC_OPEN,
- TC_CC_RD,
- TC_CC_RP,
- /* Normal States */
- TC_DISABLED,
- TC_ERROR_RECOVERY,
- TC_UNATTACHED_SNK,
- TC_ATTACH_WAIT_SNK,
- TC_ATTACHED_SNK,
- TC_UNATTACHED_SRC,
- TC_ATTACH_WAIT_SRC,
- TC_ATTACHED_SRC,
- TC_TRY_SRC,
- TC_TRY_WAIT_SNK,
- TC_DRP_AUTO_TOGGLE,
- TC_LOW_POWER_MODE,
- TC_CT_UNATTACHED_SNK,
- TC_CT_ATTACHED_SNK,
-
- TC_STATE_COUNT,
-};
-/* Forward declare the full list of states. This is indexed by usb_tc_state */
-static const struct usb_state tc_states[];
-
-/*
- * Remove all of the states that aren't support at link time. This allows
- * IS_ENABLED to work.
- */
-#ifndef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE
-GEN_NOT_SUPPORTED(TC_DRP_AUTO_TOGGLE);
-#define TC_DRP_AUTO_TOGGLE TC_DRP_AUTO_TOGGLE_NOT_SUPPORTED
-#endif /* CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE */
-
-#ifndef CONFIG_USB_PD_TCPC_LOW_POWER
-GEN_NOT_SUPPORTED(TC_LOW_POWER_MODE);
-#define TC_LOW_POWER_MODE TC_LOW_POWER_MODE_NOT_SUPPORTED
-#endif /* CONFIG_USB_PD_TCPC_LOW_POWER */
-
-#ifndef CONFIG_USB_PE_SM
-GEN_NOT_SUPPORTED(TC_CT_UNATTACHED_SNK);
-#define TC_CT_UNATTACHED_SNK TC_CT_UNATTACHED_SNK_NOT_SUPPORTED
-GEN_NOT_SUPPORTED(TC_CT_ATTACHED_SNK);
-#define TC_CT_ATTACHED_SNK TC_CT_ATTACHED_SNK_NOT_SUPPORTED
-#endif /* CONFIG_USB_PE_SM */
-
-/*
- * If CONFIG_ASSERT_CCD_MODE_ON_DTS_CONNECT is not defined then
- * _GPIO_CCD_MODE_ODL is not needed. Declare as extern so IS_ENABLED will work.
- */
-#ifndef CONFIG_ASSERT_CCD_MODE_ON_DTS_CONNECT
-extern int _GPIO_CCD_MODE_ODL;
-#else
-#define _GPIO_CCD_MODE_ODL GPIO_CCD_MODE_ODL
-#endif /* CONFIG_ASSERT_CCD_MODE_ON_DTS_CONNECT */
-
-/*
- * We will use DEBUG LABELS if we will be able to print (COMMON RUNTIME)
- * and either CONFIG_USB_PD_DEBUG_LEVEL is not defined (no override) or
- * we are overriding and the level is not DISABLED.
- *
- * If we can't print or the CONFIG_USB_PD_DEBUG_LEVEL is defined to be 0
- * then the DEBUG LABELS will be removed from the build.
- */
-#if defined(CONFIG_COMMON_RUNTIME) && \
- (!defined(CONFIG_USB_PD_DEBUG_LEVEL) || \
- (CONFIG_USB_PD_DEBUG_LEVEL > 0))
-#define USB_PD_DEBUG_LABELS
-#endif
-
-/*
- * Helper Macro to determine if the machine is in state
- * TC_ATTACHED_SRC
- */
-#define IS_ATTACHED_SRC(port) (get_state_tc(port) == TC_ATTACHED_SRC)
-
-/*
- * Helper Macro to determine if the machine is in state
- * TC_ATTACHED_SNK
- */
-#define IS_ATTACHED_SNK(port) (get_state_tc(port) == TC_ATTACHED_SNK)
-
-
-/* List of human readable state names for console debugging */
-__maybe_unused static __const_data const char * const tc_state_names[] = {
-#ifdef USB_PD_DEBUG_LABELS
- [TC_DISABLED] = "Disabled",
- [TC_ERROR_RECOVERY] = "ErrorRecovery",
- [TC_UNATTACHED_SNK] = "Unattached.SNK",
- [TC_ATTACH_WAIT_SNK] = "AttachWait.SNK",
- [TC_ATTACHED_SNK] = "Attached.SNK",
- [TC_UNATTACHED_SRC] = "Unattached.SRC",
- [TC_ATTACH_WAIT_SRC] = "AttachWait.SRC",
- [TC_ATTACHED_SRC] = "Attached.SRC",
- [TC_TRY_SRC] = "Try.SRC",
- [TC_TRY_WAIT_SNK] = "TryWait.SNK",
-#ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE
- [TC_DRP_AUTO_TOGGLE] = "DRPAutoToggle",
-#endif
-#ifdef CONFIG_USB_PD_TCPC_LOW_POWER
- [TC_LOW_POWER_MODE] = "LowPowerMode",
-#endif
-#ifdef CONFIG_USB_PE_SM
- [TC_CT_UNATTACHED_SNK] = "CTUnattached.SNK",
- [TC_CT_ATTACHED_SNK] = "CTAttached.SNK",
-#endif
- /* Super States */
- [TC_CC_OPEN] = "SS:CC_OPEN",
- [TC_CC_RD] = "SS:CC_RD",
- [TC_CC_RP] = "SS:CC_RP",
-
- [TC_STATE_COUNT] = "",
-#endif
-};
-
-/* Debug log level - higher number == more log */
-#ifdef CONFIG_USB_PD_DEBUG_LEVEL
-static const enum debug_level tc_debug_level = CONFIG_USB_PD_DEBUG_LEVEL;
-#else
-static enum debug_level tc_debug_level = DEBUG_LEVEL_1;
-#endif
-
-#ifdef DEBUG_PRINT_FLAG_AND_EVENT_NAMES
-struct bit_name {
- int value;
- const char *name;
-};
-
-static struct bit_name flag_bit_names[] = {
- { TC_FLAGS_VCONN_ON, "VCONN_ON" },
- { TC_FLAGS_TS_DTS_PARTNER, "TS_DTS_PARTNER" },
- { TC_FLAGS_VBUS_NEVER_LOW, "VBUS_NEVER_LOW" },
- { TC_FLAGS_LPM_TRANSITION, "LPM_TRANSITION" },
- { TC_FLAGS_LPM_ENGAGED, "LPM_ENGAGED" },
- { TC_FLAGS_CTVPD_DETECTED, "CTVPD_DETECTED" },
- { TC_FLAGS_REQUEST_VC_SWAP_ON, "REQUEST_VC_SWAP_ON" },
- { TC_FLAGS_REQUEST_VC_SWAP_OFF, "REQUEST_VC_SWAP_OFF" },
- { TC_FLAGS_REJECT_VCONN_SWAP, "REJECT_VCONN_SWAP" },
- { TC_FLAGS_REQUEST_PR_SWAP, "REQUEST_PR_SWAP" },
- { TC_FLAGS_REQUEST_DR_SWAP, "REQUEST_DR_SWAP" },
- { TC_FLAGS_POWER_OFF_SNK, "POWER_OFF_SNK" },
- { TC_FLAGS_PARTNER_PD_CAPABLE, "PARTNER_PD_CAPABLE" },
- { TC_FLAGS_HARD_RESET_REQUESTED, "HARD_RESET_REQUESTED" },
- { TC_FLAGS_PR_SWAP_IN_PROGRESS, "PR_SWAP_IN_PROGRESS" },
- { TC_FLAGS_CHECK_CONNECTION, "CHECK_CONNECTION" },
- { TC_FLAGS_REQUEST_SUSPEND, "REQUEST_SUSPEND" },
- { TC_FLAGS_SUSPENDED, "SUSPENDED" },
- { TC_FLAGS_UPDATE_CURRENT, "UPDATE_CURRENT" },
- { TC_FLAGS_UPDATE_USB_MUX, "UPDATE_USB_MUX" },
- { TC_FLAGS_USB_RETIMER_FW_UPDATE_RUN,
- "USB_RETIMER_FW_UPDATE_RUN" },
- { TC_FLAGS_USB_RETIMER_FW_UPDATE_LTD_RUN,
- "USB_RETIMER_FW_UPDATE_LTD_RUN" },
- { TC_FLAGS_REQUEST_ERROR_RECOVERY, "REQUEST_ERROR_RECOCVERY"},
-};
-BUILD_ASSERT(ARRAY_SIZE(flag_bit_names) == TC_FLAGS_COUNT);
-
-static struct bit_name event_bit_names[] = {
- { TASK_EVENT_SYSJUMP_READY, "SYSJUMP_READY" },
- { TASK_EVENT_IPC_READY, "IPC_READY" },
- { TASK_EVENT_PD_AWAKE, "PD_AWAKE" },
- { TASK_EVENT_PECI_DONE, "PECI_DONE" },
- { TASK_EVENT_I2C_IDLE, "I2C_IDLE" },
-#ifdef TASK_EVENT_PS2_DONE
- { TASK_EVENT_PS2_DONE, "PS2_DONE" },
-#endif
- { TASK_EVENT_DMA_TC, "DMA_TC" },
- { TASK_EVENT_ADC_DONE, "ADC_DONE" },
- { TASK_EVENT_RESET_DONE, "RESET_DONE" },
- { TASK_EVENT_WAKE, "WAKE" },
- { TASK_EVENT_MUTEX, "MUTEX" },
- { TASK_EVENT_TIMER, "TIMER" },
- { PD_EVENT_TX, "TX" },
- { PD_EVENT_CC, "CC" },
- { PD_EVENT_TCPC_RESET, "TCPC_RESET" },
- { PD_EVENT_UPDATE_DUAL_ROLE, "UPDATE_DUAL_ROLE" },
- { PD_EVENT_DEVICE_ACCESSED, "DEVICE_ACCESSED" },
- { PD_EVENT_POWER_STATE_CHANGE, "POWER_STATE_CHANGE" },
- { PD_EVENT_SEND_HARD_RESET, "SEND_HARD_RESET" },
- { PD_EVENT_SYSJUMP, "SYSJUMP" },
-};
-
-static void print_bits(int port, const char *desc, int value,
- struct bit_name *names, int names_size)
-{
- int i;
-
- CPRINTF("C%d: %s 0x%x : ", port, desc, value);
- for (i = 0; i < names_size; i++) {
- if (value & names[i].value)
- CPRINTF("%s | ", names[i].name);
- value &= ~names[i].value;
- }
- if (value != 0)
- CPRINTF("0x%x", value);
- CPRINTF("\n");
-}
-
-void print_flag(int port, int set_or_clear, int flag)
-{
- print_bits(port, set_or_clear ? "Set" : "Clr", flag, flag_bit_names,
- ARRAY_SIZE(flag_bit_names));
-}
-#endif /* DEBUG_PRINT_FLAG_AND_EVENT_NAMES */
-
-#ifndef CONFIG_USB_PD_TRY_SRC
-extern int TC_TRY_SRC_UNDEFINED;
-extern int TC_TRY_WAIT_SNK_UNDEFINED;
-#define TC_TRY_SRC TC_TRY_SRC_UNDEFINED
-#define TC_TRY_WAIT_SNK TC_TRY_WAIT_SNK_UNDEFINED
-#endif
-
-static struct type_c {
- /* state machine context */
- struct sm_ctx ctx;
- /* current port power role (SOURCE or SINK) */
- enum pd_power_role power_role;
- /* current port data role (DFP or UFP) */
- enum pd_data_role data_role;
- /*
- * Higher-level power deliver state machines are enabled if false,
- * else they're disabled if bits PD_DISABLED_NO_CONNECTION or
- * PD_DISABLED_BY_POLICY are set.
- */
- uint32_t pd_disabled_mask;
- /*
- * Timer for handling TOGGLE_OFF/FORCE_SINK mode when auto-toggle
- * enabled. See drp_auto_toggle_next_state() for details.
- */
- uint64_t drp_sink_time;
-#ifdef CONFIG_USB_PE_SM
- /* Power supply reset sequence during a hard reset */
- enum ps_reset_sequence ps_reset_state;
-#endif
- /* Port polarity */
- enum tcpc_cc_polarity polarity;
- /* port flags, see TC_FLAGS_* */
- uint32_t flags;
- /* The cc state */
- enum pd_cc_states cc_state;
- /* Tasks to notify after TCPC has been reset */
- int tasks_waiting_on_reset;
- /* Tasks preventing TCPC from entering low power mode */
- int tasks_preventing_lpm;
- /* Voltage on CC pin */
- enum tcpc_cc_voltage_status cc_voltage;
- /* Type-C current */
- typec_current_t typec_curr;
- /* Type-C current change */
- typec_current_t typec_curr_change;
-
- /* Selected TCPC CC/Rp values */
- enum tcpc_cc_pull select_cc_pull;
- enum tcpc_rp_value select_current_limit_rp;
- enum tcpc_rp_value select_collision_rp;
-} tc[CONFIG_USB_PD_PORT_MAX_COUNT];
-
-/* Port dual-role state */
-static volatile __maybe_unused
-enum pd_dual_role_states drp_state[CONFIG_USB_PD_PORT_MAX_COUNT] = {
- [0 ... (CONFIG_USB_PD_PORT_MAX_COUNT - 1)] =
- CONFIG_USB_PD_INITIAL_DRP_STATE};
-
-static void set_vconn(int port, int enable);
-
-/* Forward declare common, private functions */
-static __maybe_unused int reset_device_and_notify(int port);
-static __maybe_unused void check_drp_connection(const int port);
-static void sink_power_sub_states(int port);
-static void set_ccd_mode(int port, bool enable);
-
-__maybe_unused static void handle_new_power_state(int port);
-
-static void pd_update_dual_role_config(int port);
-
-/* Forward declare common, private functions */
-static void set_state_tc(const int port, const enum usb_tc_state new_state);
-test_export_static enum usb_tc_state get_state_tc(const int port);
-
-/* Enable variable for Try.SRC states */
-static uint32_t pd_try_src;
-static volatile enum try_src_override_t pd_try_src_override;
-static void pd_update_try_source(void);
-
-static void sink_stop_drawing_current(int port);
-
-__maybe_unused static bool is_try_src_enabled(int port)
-{
- if (!IS_ENABLED(CONFIG_USB_PD_TRY_SRC))
- assert(0);
-
- return ((pd_try_src_override == TRY_SRC_OVERRIDE_ON) ||
- (pd_try_src_override == TRY_SRC_NO_OVERRIDE && pd_try_src));
-}
-
-/*
- * Public Functions
- *
- * NOTE: Functions prefixed with pd_ are defined in usb_pd.h
- * Functions prefixed with tc_ are defined int usb_tc_sm.h
- */
-
-#ifndef CONFIG_USB_PRL_SM
-
-/*
- * These pd_ functions are implemented in common/usb_prl_sm.c
- */
-
-void pd_transmit_complete(int port, int status)
-{
- /* DO NOTHING */
-}
-
-void pd_execute_hard_reset(int port)
-{
- /* DO NOTHING */
-}
-
-__overridable void pd_set_vbus_discharge(int port, int enable)
-{
- /* DO NOTHING */
-}
-
-#endif /* !CONFIG_USB_PRL_SM */
-
-#ifndef CONFIG_USB_PE_SM
-
-/*
- * These pd_ functions are implemented in the PE layer
- */
-const uint32_t * const pd_get_src_caps(int port)
-{
- return NULL;
-}
-
-uint8_t pd_get_src_cap_cnt(int port)
-{
- return 0;
-}
-
-const uint32_t * const pd_get_snk_caps(int port)
-{
- return NULL;
-}
-
-uint8_t pd_get_snk_cap_cnt(int port)
-{
- return 0;
-}
-
-void pd_set_src_caps(int port, int cnt, uint32_t *src_caps)
-{
-}
-
-int pd_get_rev(int port, enum tcpci_msg_type type)
-{
- return PD_REV30;
-}
-
-#endif /* !CONFIG_USB_PR_SM */
-
-#ifndef HAS_TASK_CHIPSET
-__overridable enum pd_dual_role_states board_tc_get_initial_drp_mode(int port)
-{
- /*
- * DRP state is typically adjusted as the chipset state is changed. For
- * projects which don't include an AP this function can be used for to
- * specify what the starting DRP state should be.
- */
- return PD_DRP_FORCE_SINK;
-}
-#endif
-
-void pd_update_contract(int port)
-{
- if (IS_ENABLED(CONFIG_USB_PE_SM)) {
- if (IS_ATTACHED_SRC(port))
- pd_dpm_request(port, DPM_REQUEST_SRC_CAP_CHANGE);
- }
-}
-
-void pd_request_source_voltage(int port, int mv)
-{
- if (IS_ENABLED(CONFIG_USB_PE_SM)) {
- pd_set_max_voltage(mv);
-
- if (IS_ATTACHED_SNK(port))
- pd_dpm_request(port, DPM_REQUEST_NEW_POWER_LEVEL);
- else
- pd_dpm_request(port, DPM_REQUEST_PR_SWAP);
-
- task_wake(PD_PORT_TO_TASK_ID(port));
- }
-}
-
-void pd_set_external_voltage_limit(int port, int mv)
-{
- if (IS_ENABLED(CONFIG_USB_PE_SM)) {
- pd_set_max_voltage(mv);
-
- /* Must be in Attached.SNK when this function is called */
- if (get_state_tc(port) == TC_ATTACHED_SNK)
- pd_dpm_request(port, DPM_REQUEST_NEW_POWER_LEVEL);
-
- task_wake(PD_PORT_TO_TASK_ID(port));
- }
-}
-
-void pd_set_new_power_request(int port)
-{
- if (IS_ENABLED(CONFIG_USB_PE_SM)) {
- /* Must be in Attached.SNK when this function is called */
- if (get_state_tc(port) == TC_ATTACHED_SNK)
- pd_dpm_request(port, DPM_REQUEST_NEW_POWER_LEVEL);
- }
-}
-
-void tc_request_power_swap(int port)
-{
- if (IS_ENABLED(CONFIG_USB_PE_SM)) {
- /*
- * Must be in Attached.SRC or Attached.SNK
- */
- if (IS_ATTACHED_SRC(port) || IS_ATTACHED_SNK(port)) {
- TC_SET_FLAG(port, TC_FLAGS_PR_SWAP_IN_PROGRESS);
-
- /* Let tc_pr_swap_complete start the Vbus debounce */
- pd_timer_disable(port, TC_TIMER_VBUS_DEBOUNCE);
- }
-
- /*
- * TCPCI Rev2 V1.1 4.4.5.4.4
- * Disconnect Detection by the Sink TCPC during a Connection
- *
- * Upon reception of or prior to transmitting a PR_Swap
- * message, the TCPM acting as a Sink shall disable the Sink
- * disconnect detection to retain PD message delivery when
- * Power Role Swap happens. Disable AutoDischargeDisconnect.
- */
- if (IS_ATTACHED_SNK(port))
- tcpm_enable_auto_discharge_disconnect(port, 0);
- }
-}
-
-/* Flag to indicate PD comm is disabled on init */
-static int pd_disabled_on_init;
-
-static void pd_update_pd_comm(void)
-{
- int i;
-
- /*
- * Some batteries take much longer time to report its SOC.
- * The init function disabled PD comm on startup. Need this
- * hook to enable PD comm when the battery level is enough.
- */
- if (pd_disabled_on_init && pd_is_battery_capable()) {
- for (i = 0; i < CONFIG_USB_PD_PORT_MAX_COUNT; i++)
- pd_comm_enable(i, 1);
- pd_disabled_on_init = 0;
- }
-}
-DECLARE_HOOK(HOOK_BATTERY_SOC_CHANGE, pd_update_pd_comm, HOOK_PRIO_DEFAULT);
-
-static bool pd_comm_allowed_by_policy(void)
-{
- if (system_is_in_rw())
- return true;
-
- if (vboot_allow_usb_pd())
- return true;
-
- /*
- * If enable PD in RO on a non-EFS2 device, a hard reset will be issued
- * when sysjump to RW that makes the device brownout on the dead-battery
- * case. Disable PD for this special case as a workaround.
- */
- if (!system_is_locked()) {
- if (IS_ENABLED(CONFIG_VBOOT_EFS2))
- return true;
-
- if (pd_is_battery_capable())
- return true;
-
- pd_disabled_on_init = 1;
- }
-
- return false;
-}
-
-static void tc_policy_pd_enable(int port, int en)
-{
- if (en)
- atomic_clear_bits(&tc[port].pd_disabled_mask,
- PD_DISABLED_BY_POLICY);
- else
- atomic_or(&tc[port].pd_disabled_mask, PD_DISABLED_BY_POLICY);
-
- CPRINTS("C%d: PD comm policy %sabled", port, en ? "en" : "dis");
-}
-
-static void tc_enable_pd(int port, int en)
-{
- if (en)
- atomic_clear_bits(&tc[port].pd_disabled_mask,
- PD_DISABLED_NO_CONNECTION);
- else
- atomic_or(&tc[port].pd_disabled_mask,
- PD_DISABLED_NO_CONNECTION);
-}
-
-__maybe_unused static void tc_enable_try_src(int en)
-{
- if (!IS_ENABLED(CONFIG_USB_PD_TRY_SRC))
- assert(0);
-
- if (en)
- atomic_or(&pd_try_src, 1);
- else
- atomic_clear_bits(&pd_try_src, 1);
-}
-
-/*
- * Exit all modes due to a detach event
- * Note: this skips the ExitMode VDM steps in the PE because it is assumed the
- * partner is not present to receive them, and the PE will no longer be running.
- */
-static void tc_set_modes_exit(int port)
-{
- if (IS_ENABLED(CONFIG_USB_PE_SM) &&
- IS_ENABLED(CONFIG_USB_PD_ALT_MODE_DFP)) {
- pd_dfp_exit_mode(port, TCPCI_MSG_SOP, 0, 0);
- pd_dfp_exit_mode(port, TCPCI_MSG_SOP_PRIME, 0, 0);
- pd_dfp_exit_mode(port, TCPCI_MSG_SOP_PRIME_PRIME, 0, 0);
- }
-}
-
-static void tc_detached(int port)
-{
- TC_CLR_FLAG(port, TC_FLAGS_TS_DTS_PARTNER);
- hook_notify(HOOK_USB_PD_DISCONNECT);
- tc_pd_connection(port, 0);
- tcpm_debug_accessory(port, 0);
- set_ccd_mode(port, 0);
- tc_set_modes_exit(port);
- if (IS_ENABLED(CONFIG_USB_PRL_SM))
- prl_set_default_pd_revision(port);
-
- /* Clear any mux connection on detach */
- if (IS_ENABLED(CONFIG_USBC_SS_MUX))
- usb_mux_set(port, USB_PD_MUX_NONE,
- USB_SWITCH_DISCONNECT, tc[port].polarity);
-}
-
-static inline void pd_set_dual_role_and_event(int port,
- enum pd_dual_role_states state, uint32_t event)
-{
- drp_state[port] = state;
-
- if (IS_ENABLED(CONFIG_USB_PD_TRY_SRC))
- pd_update_try_source();
-
- if (event != 0)
- task_set_event(PD_PORT_TO_TASK_ID(port), event);
-}
-
-void pd_set_dual_role(int port, enum pd_dual_role_states state)
-{
- pd_set_dual_role_and_event(port, state, PD_EVENT_UPDATE_DUAL_ROLE);
-}
-
-int pd_comm_is_enabled(int port)
-{
- return tc_get_pd_enabled(port);
-}
-
-void pd_request_data_swap(int port)
-{
- /*
- * Must be in Attached.SRC, Attached.SNK, DebugAccessory.SNK,
- * or UnorientedDebugAccessory.SRC when this function
- * is called
- */
- if (IS_ATTACHED_SRC(port) || IS_ATTACHED_SNK(port)) {
- TC_SET_FLAG(port, TC_FLAGS_REQUEST_DR_SWAP);
- task_wake(PD_PORT_TO_TASK_ID(port));
- }
-}
-
-/* Return true if partner port is known to be PD capable. */
-bool pd_capable(int port)
-{
- return !!TC_CHK_FLAG(port, TC_FLAGS_PARTNER_PD_CAPABLE);
-}
-
-/*
- * Return true if we transition through Unattached.SNK, but we're still waiting
- * to receive source caps from the partner. This indicates that the PD
- * capabilities are not yet known.
- */
-bool pd_waiting_on_partner_src_caps(int port)
-{
- return !pd_get_src_cap_cnt(port);
-}
-
-enum pd_dual_role_states pd_get_dual_role(int port)
-{
- return drp_state[port];
-}
-
-#ifdef CONFIG_CMD_PD_DEV_DUMP_INFO
-static inline void pd_dev_dump_info(uint16_t dev_id, uint32_t *hash)
-{
- int j;
-
- ccprintf("DevId:%d.%d Hash:", HW_DEV_ID_MAJ(dev_id),
- HW_DEV_ID_MIN(dev_id));
- for (j = 0; j < PD_RW_HASH_SIZE / 4; j++)
- ccprintf(" %08x ", hash[j]);
- ccprintf("\n");
-}
-#endif /* CONFIG_CMD_PD_DEV_DUMP_INFO */
-
-const char *tc_get_current_state(int port)
-{
- if (IS_ENABLED(USB_PD_DEBUG_LABELS))
- return tc_state_names[get_state_tc(port)];
- else
- return "";
-}
-
-uint32_t tc_get_flags(int port)
-{
- return tc[port].flags;
-}
-
-int tc_is_attached_src(int port)
-{
- return IS_ATTACHED_SRC(port);
-}
-
-int tc_is_attached_snk(int port)
-{
- return IS_ATTACHED_SNK(port);
-}
-
-void tc_pd_connection(int port, int en)
-{
- if (en) {
- bool new_pd_capable = false;
-
- if (!TC_CHK_FLAG(port, TC_FLAGS_PARTNER_PD_CAPABLE))
- new_pd_capable = true;
-
- TC_SET_FLAG(port, TC_FLAGS_PARTNER_PD_CAPABLE);
- /* If a PD device is attached then disable deep sleep */
- if (IS_ENABLED(CONFIG_LOW_POWER_IDLE) &&
- !IS_ENABLED(CONFIG_USB_PD_TCPC_ON_CHIP)) {
- disable_sleep(SLEEP_MASK_USB_PD);
- }
-
- /*
- * Update the mux state, only when the PD capable flag
- * transitions from 0 to 1. This ensures that PD charger
- * devices, without data capability are not marked as having
- * USB.
- */
- if (new_pd_capable)
- set_usb_mux_with_current_data_role(port);
- } else {
- TC_CLR_FLAG(port, TC_FLAGS_PARTNER_PD_CAPABLE);
- /* If a PD device isn't attached then enable deep sleep */
- if (IS_ENABLED(CONFIG_LOW_POWER_IDLE) &&
- !IS_ENABLED(CONFIG_USB_PD_TCPC_ON_CHIP)) {
- int i;
-
- /* If all ports are not connected, allow the sleep */
- for (i = 0; i < board_get_usb_pd_port_count(); i++) {
- if (pd_capable(i))
- break;
- }
- if (i == board_get_usb_pd_port_count())
- enable_sleep(SLEEP_MASK_USB_PD);
- }
- }
-}
-
-void tc_ctvpd_detected(int port)
-{
- TC_SET_FLAG(port, TC_FLAGS_CTVPD_DETECTED);
-}
-
-void pd_try_vconn_src(int port)
-{
- set_vconn(port, 1);
-}
-
-int tc_check_vconn_swap(int port)
-{
- if (IS_ENABLED(CONFIG_USBC_VCONN)) {
- if (TC_CHK_FLAG(port, TC_FLAGS_REJECT_VCONN_SWAP))
- return 0;
-
- return pd_check_vconn_swap(port);
- } else
- return 0;
-}
-
-void tc_pr_swap_complete(int port, bool success)
-{
- if (IS_ATTACHED_SNK(port)) {
- /*
- * Give the ADCs in the TCPC or PPC time to react following
- * a PS_RDY message received during a SRC to SNK swap.
- * Note: This is empirically determined, not strictly
- * part of the USB PD spec.
- * Note: Swap in progress should not be cleared until the
- * debounce is completed.
- */
- pd_timer_enable(port, TC_TIMER_VBUS_DEBOUNCE, PD_T_DEBOUNCE);
- } else {
- /* PR Swap is no longer in progress */
- TC_CLR_FLAG(port, TC_FLAGS_PR_SWAP_IN_PROGRESS);
-
- /*
- * AutoDischargeDisconnect was turned off near the SNK->SRC
- * PR-Swap message. If the swap was a success, Vbus should be
- * valid, so re-enable AutoDischargeDisconnect
- */
- if (success)
- tcpm_enable_auto_discharge_disconnect(port, 1);
- }
-}
-
-void tc_prs_src_snk_assert_rd(int port)
-{
- /*
- * Must be in Attached.SRC or UnorientedDebugAccessory.SRC
- * when this function is called
- */
- if (IS_ATTACHED_SRC(port)) {
- /*
- * Transition to Attached.SNK to
- * DebugAccessory.SNK assert Rd
- */
- TC_SET_FLAG(port, TC_FLAGS_REQUEST_PR_SWAP);
- task_wake(PD_PORT_TO_TASK_ID(port));
- }
-}
-
-void tc_prs_snk_src_assert_rp(int port)
-{
- /*
- * Must be in Attached.SNK or DebugAccessory.SNK
- * when this function is called
- */
- if (IS_ATTACHED_SNK(port)) {
- /*
- * Transition to Attached.SRC or
- * UnorientedDebugAccessory.SRC to assert Rp
- */
- TC_SET_FLAG(port, TC_FLAGS_REQUEST_PR_SWAP);
- task_wake(PD_PORT_TO_TASK_ID(port));
- }
-}
-
-/*
- * Hard Reset is being requested. This should not allow a TC connection
- * to go to an unattached state until the connection is recovered from
- * the hard reset. It is possible for a Hard Reset to cause a timeout
- * in trying to recover and an additional Hard Reset would be issued.
- * During this entire process it is important that the TC is not allowed
- * to go to an unattached state.
- *
- * Type-C Spec Rev 2.0 section 4.5.2.2.5.2
- * Exiting from Attached.SNK State
- * A port that is not a V CONN-Powered USB Device and is not in the
- * process of a USB PD PR_Swap or a USB PD Hard Reset or a USB PD
- * FR_Swap shall transition to Unattached.SNK
- */
-void tc_hard_reset_request(int port)
-{
- TC_SET_FLAG(port, TC_FLAGS_HARD_RESET_REQUESTED);
- task_wake(PD_PORT_TO_TASK_ID(port));
-}
-
-void tc_try_src_override(enum try_src_override_t ov)
-{
- if (!IS_ENABLED(CONFIG_USB_PD_TRY_SRC))
- assert(0);
-
- if (IS_ENABLED(CONFIG_USB_PD_TRY_SRC)) {
- switch (ov) {
- case TRY_SRC_OVERRIDE_OFF: /* 0 */
- pd_try_src_override = TRY_SRC_OVERRIDE_OFF;
- break;
- case TRY_SRC_OVERRIDE_ON: /* 1 */
- pd_try_src_override = TRY_SRC_OVERRIDE_ON;
- break;
- default:
- pd_try_src_override = TRY_SRC_NO_OVERRIDE;
- }
- }
-}
-
-enum try_src_override_t tc_get_try_src_override(void)
-{
- if (!IS_ENABLED(CONFIG_USB_PD_TRY_SRC))
- assert(0);
-
- return pd_try_src_override;
-}
-
-void tc_snk_power_off(int port)
-{
- if (IS_ATTACHED_SNK(port)) {
- TC_SET_FLAG(port, TC_FLAGS_POWER_OFF_SNK);
- sink_stop_drawing_current(port);
- }
-}
-
-int tc_src_power_on(int port)
-{
- /*
- * Check our OC event counter. If we've exceeded our threshold, then
- * let's latch our source path off to prevent continuous cycling. When
- * the PD state machine detects a disconnection on the CC lines, we will
- * reset our OC event counter.
- */
- if (IS_ENABLED(CONFIG_USBC_OCP) && usbc_ocp_is_port_latched_off(port))
- return EC_ERROR_ACCESS_DENIED;
-
- if (IS_ATTACHED_SRC(port))
- return pd_set_power_supply_ready(port);
-
- return 0;
-}
-
-void tc_src_power_off(int port)
-{
- /* Remove VBUS */
- pd_power_supply_reset(port);
-
- if (IS_ENABLED(CONFIG_CHARGE_MANAGER))
- charge_manager_set_ceil(port, CEIL_REQUESTOR_PD,
- CHARGE_CEIL_NONE);
-}
-
-/* Set what role the partner is right now, for the PPC and OCP module */
-static void tc_set_partner_role(int port, enum ppc_device_role role)
-{
- if (IS_ENABLED(CONFIG_USBC_PPC))
- ppc_dev_is_connected(port, role);
-
- if (IS_ENABLED(CONFIG_USBC_OCP)) {
- usbc_ocp_snk_is_connected(port, role == PPC_DEV_SNK);
- /*
- * Clear the overcurrent event counter
- * since we've detected a disconnect.
- */
- if (role == PPC_DEV_DISCONNECTED)
- usbc_ocp_clear_event_counter(port);
- }
-}
-
-/*
- * Depending on the load on the processor and the tasks running
- * it can take a while for the task associated with this port
- * to run. So build in 1ms delays, for up to 300ms, to wait for
- * the suspend to actually happen.
- */
-#define SUSPEND_SLEEP_DELAY 1
-#define SUSPEND_SLEEP_RETRIES 300
-
-void pd_set_suspend(int port, int suspend)
-{
- if (pd_is_port_enabled(port) == !suspend)
- return;
-
- /* Track if we are suspended or not */
- if (suspend) {
- int wait = 0;
-
- TC_SET_FLAG(port, TC_FLAGS_REQUEST_SUSPEND);
-
- /*
- * Avoid deadlock when running from task
- * which we are going to suspend
- */
- if (PD_PORT_TO_TASK_ID(port) == task_get_current())
- return;
-
- task_wake(PD_PORT_TO_TASK_ID(port));
-
- /* Sleep this task if we are not suspended */
- while (pd_is_port_enabled(port)) {
- if (++wait > SUSPEND_SLEEP_RETRIES) {
- CPRINTS("C%d: NOT SUSPENDED after %dms",
- port, wait * SUSPEND_SLEEP_DELAY);
- return;
- }
- msleep(SUSPEND_SLEEP_DELAY);
- }
- } else {
- TC_CLR_FLAG(port, TC_FLAGS_REQUEST_SUSPEND);
- task_wake(PD_PORT_TO_TASK_ID(port));
- }
-}
-
-void pd_set_error_recovery(int port)
-{
- TC_SET_FLAG(port, TC_FLAGS_REQUEST_ERROR_RECOVERY);
-}
-
-int pd_is_port_enabled(int port)
-{
- /*
- * Checking get_state_tc(port) from another task isn't safe since it
- * can return TC_DISABLED before tc_cc_open_entry and tc_disabled_entry
- * are complete. So check TC_FLAGS_SUSPENDED instead.
- */
- return !TC_CHK_FLAG(port, TC_FLAGS_SUSPENDED);
-}
-
-int pd_fetch_acc_log_entry(int port)
-{
- if (IS_ENABLED(CONFIG_USB_PE_SM))
- pd_send_vdm(port, USB_VID_GOOGLE, VDO_CMD_GET_LOG, NULL, 0);
-
- return EC_RES_SUCCESS;
-}
-
-enum tcpc_cc_polarity pd_get_polarity(int port)
-{
- return tc[port].polarity;
-}
-
-enum pd_data_role pd_get_data_role(int port)
-{
- return tc[port].data_role;
-}
-
-enum pd_power_role pd_get_power_role(int port)
-{
- return tc[port].power_role;
-}
-
-enum pd_cc_states pd_get_task_cc_state(int port)
-{
- return tc[port].cc_state;
-}
-
-uint8_t pd_get_task_state(int port)
-{
- return get_state_tc(port);
-}
-
-bool pd_get_vconn_state(int port)
-{
- return !!TC_CHK_FLAG(port, TC_FLAGS_VCONN_ON);
-}
-
-const char *pd_get_task_state_name(int port)
-{
- return tc_get_current_state(port);
-}
-
-void pd_vbus_low(int port)
-{
- TC_CLR_FLAG(port, TC_FLAGS_VBUS_NEVER_LOW);
-}
-
-int pd_is_connected(int port)
-{
- return (IS_ATTACHED_SRC(port) ||
- (IS_ENABLED(CONFIG_USB_PE_SM) &&
- ((get_state_tc(port) == TC_CT_UNATTACHED_SNK) ||
- (get_state_tc(port) == TC_CT_ATTACHED_SNK))) ||
- IS_ATTACHED_SNK(port));
-}
-
-bool pd_is_disconnected(int port)
-{
- return !pd_is_connected(port);
-}
-
-/*
- * PD functions which query our fixed PDO flags. Both the source and sink
- * capabilities can present these values, and they should match between the two
- * for compliant partners.
- */
-static bool pd_check_fixed_flag(int port, uint32_t flag)
-{
- uint32_t fixed_pdo;
-
- if (pd_get_src_cap_cnt(port) != 0)
- fixed_pdo = *pd_get_src_caps(port);
- else if (pd_get_snk_cap_cnt(port) != 0)
- fixed_pdo = *pd_get_snk_caps(port);
- else
- return false;
-
- /*
- * Error check that first PDO is fixed, as 6.4.1 Capabilities requires
- * in the Power Delivery Specification.
- * "The vSafe5V Fixed Supply Object Shall always be the first object"
- */
- if ((fixed_pdo & PDO_TYPE_MASK) != PDO_TYPE_FIXED)
- return false;
-
- return fixed_pdo & flag;
-}
-
-bool pd_get_partner_data_swap_capable(int port)
-{
- return pd_check_fixed_flag(port, PDO_FIXED_DATA_SWAP);
-}
-
-bool pd_get_partner_usb_comm_capable(int port)
-{
- return pd_check_fixed_flag(port, PDO_FIXED_COMM_CAP);
-}
-
-bool pd_get_partner_dual_role_power(int port)
-{
- return pd_check_fixed_flag(port, PDO_FIXED_DUAL_ROLE);
-}
-
-bool pd_get_partner_unconstr_power(int port)
-{
- return pd_check_fixed_flag(port, PDO_FIXED_UNCONSTRAINED);
-}
-
-static void bc12_role_change_handler(int port, enum pd_data_role prev_data_role,
- enum pd_data_role data_role)
-{
- int event = 0;
- int task_id = USB_CHG_PORT_TO_TASK_ID(port);
- bool role_changed = (data_role != prev_data_role);
-
- if (!IS_ENABLED(CONFIG_BC12_DETECT_DATA_ROLE_TRIGGER))
- return;
-
- /* Get the data role of our device */
- switch (data_role) {
- case PD_ROLE_UFP:
- /* Only trigger BC12 detection on a role change */
- if (role_changed)
- event = USB_CHG_EVENT_DR_UFP;
- break;
- case PD_ROLE_DFP:
- /* Only trigger BC12 host mode on a role change */
- if (role_changed)
- event = USB_CHG_EVENT_DR_DFP;
- break;
- case PD_ROLE_DISCONNECTED:
- event = USB_CHG_EVENT_CC_OPEN;
- break;
- default:
- return;
- }
-
- if (event)
- task_set_event(task_id, event);
-}
-
-/*
- * TCPC CC/Rp management
- */
-static void typec_select_pull(int port, enum tcpc_cc_pull pull)
-{
- tc[port].select_cc_pull = pull;
-}
-void typec_select_src_current_limit_rp(int port, enum tcpc_rp_value rp)
-{
- tc[port].select_current_limit_rp = rp;
- if (IS_ATTACHED_SRC(port))
- TC_SET_FLAG(port, TC_FLAGS_UPDATE_CURRENT);
-}
-__overridable int typec_get_default_current_limit_rp(int port)
-{
- return CONFIG_USB_PD_PULLUP;
-}
-void typec_select_src_collision_rp(int port, enum tcpc_rp_value rp)
-{
- tc[port].select_collision_rp = rp;
-}
-static enum tcpc_rp_value typec_get_active_select_rp(int port)
-{
- /* Explicit contract will use the collision Rp */
- if (IS_ENABLED(CONFIG_USB_PD_REV30) &&
- pe_is_explicit_contract(port))
- return tc[port].select_collision_rp;
- return tc[port].select_current_limit_rp;
-}
-int typec_update_cc(int port)
-{
- int rv;
- enum tcpc_cc_pull pull = tc[port].select_cc_pull;
- enum tcpc_rp_value rp = typec_get_active_select_rp(port);
-
- rv = tcpm_select_rp_value(port, rp);
- if (rv)
- return rv;
-
- return tcpm_set_cc(port, pull);
-}
-
-#ifdef CONFIG_USB_PE_SM
-/*
- * This function performs a source hard reset. It should be called
- * repeatedly until a true value is returned, signaling that the
- * source hard reset is complete. A false value is returned otherwise.
- */
-static bool tc_perform_src_hard_reset(int port)
-{
- switch (tc[port].ps_reset_state) {
- case PS_STATE0:
- /* Remove VBUS */
- tc_src_power_off(port);
-
- /* Turn off VCONN */
- set_vconn(port, 0);
-
- /* Set role to DFP */
- tc_set_data_role(port, PD_ROLE_DFP);
-
- tc[port].ps_reset_state = PS_STATE1;
- pd_timer_enable(port, TC_TIMER_TIMEOUT, PD_T_SRC_RECOVER);
- return false;
- case PS_STATE1:
- /* Enable VBUS */
- tc_src_power_on(port);
-
- /* Update the Rp Value */
- typec_update_cc(port);
-
- /* Turn off VCONN */
- set_vconn(port, 1);
-
- tc[port].ps_reset_state = PS_STATE2;
- pd_timer_enable(port, TC_TIMER_TIMEOUT,
- PD_POWER_SUPPLY_TURN_ON_DELAY);
- return false;
- case PS_STATE2:
- /* Tell Policy Engine Hard Reset is complete */
- pe_ps_reset_complete(port);
-
- tc[port].ps_reset_state = PS_STATE0;
- return true;
- }
-
- /*
- * This return is added to appease the compiler. It should
- * never be reached because the switch handles all possible
- * cases of the enum ps_reset_sequence type.
- */
- return true;
-}
-
-/*
- * Wait for recovery after a hard reset. Call repeatedly until true is
- * returned, signaling that the hard reset is complete.
- */
-static bool tc_perform_snk_hard_reset(int port)
-{
- switch (tc[port].ps_reset_state) {
- case PS_STATE0:
- /* Hard reset sets us back to default data role */
- tc_set_data_role(port, PD_ROLE_UFP);
-
- /*
- * When VCONN is supported, the Hard Reset Shall cause
- * the Port with the Rd resistor asserted to turn off
- * VCONN.
- */
- if (IS_ENABLED(CONFIG_USBC_VCONN) &&
- TC_CHK_FLAG(port, TC_FLAGS_VCONN_ON))
- set_vconn(port, 0);
-
- /* Wait up to tVSafe0V for Vbus to disappear */
- tc[port].ps_reset_state = PS_STATE1;
- pd_timer_enable(port, TC_TIMER_TIMEOUT, PD_T_SAFE_0V);
- return false;
- case PS_STATE1:
- if (pd_check_vbus_level(port, VBUS_SAFE0V)) {
- /*
- * Partner dropped Vbus, reduce our current consumption
- * and await its return.
- */
- sink_stop_drawing_current(port);
-
- tcpm_enable_auto_discharge_disconnect(port, 0);
-
- /* Move on to waiting for the return of Vbus */
- tc[port].ps_reset_state = PS_STATE2;
- pd_timer_enable(port, TC_TIMER_TIMEOUT,
- PD_T_SRC_RECOVER_MAX +
- PD_T_SRC_TURN_ON);
- }
-
- if (pd_timer_is_expired(port, TC_TIMER_TIMEOUT)) {
- /*
- * No Vbus drop likely indicates a non-PD port partner,
- * move to the next stage anyway.
- */
- tc[port].ps_reset_state = PS_STATE2;
- pd_timer_enable(port, TC_TIMER_TIMEOUT,
- PD_T_SRC_RECOVER_MAX +
- PD_T_SRC_TURN_ON);
- }
- return false;
- case PS_STATE2:
- /*
- * Look for the voltage to be above disconnect. Since we didn't
- * drop our draw on non-PD partners, they may have dipped below
- * vSafe5V but still be in a valid connected voltage.
- */
- if (!pd_check_vbus_level(port, VBUS_REMOVED)) {
- /*
- * Inform policy engine that power supply
- * reset is complete
- */
- tc[port].ps_reset_state = PS_STATE0;
- pe_ps_reset_complete(port);
-
- /*
- * Now that VBUS is back, let's notify charge manager
- * regarding the source's current capabilities.
- * sink_power_sub_states() reacts to changes in CC
- * terminations, however during a HardReset, the
- * terminations of a non-PD port partner will not
- * change. Therefore, set the debounce time to right
- * now, such that we'll actually reset the correct input
- * current limit.
- */
- pd_timer_enable(port, TC_TIMER_CC_DEBOUNCE, 0);
- sink_power_sub_states(port);
-
- /* Power is back, Enable AutoDischargeDisconnect */
- tcpm_enable_auto_discharge_disconnect(port, 1);
- return true;
- }
- /*
- * If Vbus isn't back after wait + tSrcTurnOn, go unattached
- */
- if (pd_timer_is_expired(port, TC_TIMER_TIMEOUT)) {
- tc[port].ps_reset_state = PS_STATE0;
- set_state_tc(port, TC_UNATTACHED_SNK);
- return true;
- }
- }
-
- return false;
-}
-#endif /* CONFIG_USB_PE_SM */
-
-void tc_start_error_recovery(int port)
-{
- assert(port == TASK_ID_TO_PD_PORT(task_get_current()));
-
- /*
- * The port should transition to the ErrorRecovery state
- * from any other state when directed.
- */
- set_state_tc(port, TC_ERROR_RECOVERY);
-}
-
-static void restart_tc_sm(int port, enum usb_tc_state start_state)
-{
- int res;
-
- /* Clear flags before we transitions states */
- tc[port].flags = 0;
-
- res = tcpm_init(port);
-
- CPRINTS("C%d: TCPC init %s", port, res ? "failed" : "ready");
-
- /*
- * Update the Rp Value. We don't need to update CC lines though as that
- * happens in below set_state transition.
- */
- typec_select_src_current_limit_rp(port,
- typec_get_default_current_limit_rp(port));
-
- /* Disable if restart failed, otherwise start in default state. */
- set_state_tc(port, res ? TC_DISABLED : start_state);
-
- if (IS_ENABLED(CONFIG_USBC_SS_MUX))
- /* Initialize USB mux to its default state */
- usb_mux_init(port);
-
- if (IS_ENABLED(CONFIG_USBC_PPC)) {
- /*
- * Wait to initialize the PPC after tcpc, which sets
- * the correct Rd values; otherwise the TCPC might
- * not be pulling the CC lines down when the PPC connects the
- * CC lines from the USB connector to the TCPC cause the source
- * to drop Vbus causing a brown out.
- */
- ppc_init(port);
- }
-
- if (IS_ENABLED(CONFIG_CHARGE_MANAGER)) {
- /*
- * Only initialize PD supplier current limit to 0.
- * Defer initializing type-C supplier current limit
- * to Unattached.SNK or Attached.SNK.
- */
- pd_set_input_current_limit(port, 0, 0);
- charge_manager_update_dualrole(port, CAP_UNKNOWN);
- }
-
- /*
- * PD r3.0 v2.0, ss6.2.1.1.5:
- * After a physical or logical (USB Type-C Error Recovery) Attach, a
- * Port discovers the common Specification Revision level between itself
- * and its Port Partner and/or the Cable Plug(s), and uses this
- * Specification Revision level until a Detach, Hard Reset or Error
- * Recovery happens.
- *
- * This covers the Error Recovery case, because TC_ERROR_RECOVERY
- * reinitializes the TC state machine. This also covers the implicit
- * case when PD is suspended and resumed or when the state machine is
- * first initialized.
- */
- if (IS_ENABLED(CONFIG_USB_PRL_SM))
- prl_set_default_pd_revision(port);
-
-#ifdef CONFIG_USB_PE_SM
- tc_enable_pd(port, 0);
- tc[port].ps_reset_state = PS_STATE0;
-#endif
-}
-
-void tc_state_init(int port)
-{
- enum usb_tc_state first_state;
-
- /* For test builds, replicate static initialization */
- if (IS_ENABLED(TEST_BUILD)) {
- int i;
-
- for (i = 0; i < CONFIG_USB_PD_PORT_MAX_COUNT; ++i) {
- memset(&tc[i], 0, sizeof(tc[i]));
- drp_state[i] = CONFIG_USB_PD_INITIAL_DRP_STATE;
- }
- }
-
- /* If port is not available, there is nothing to initialize */
- if (port >= board_get_usb_pd_port_count()) {
- tc_enable_pd(port, 0);
- TC_SET_FLAG(port, TC_FLAGS_REQUEST_SUSPEND);
- return;
- }
-
-
- /* Allow system to set try src enable */
- if (IS_ENABLED(CONFIG_USB_PD_TRY_SRC))
- tc_try_src_override(TRY_SRC_NO_OVERRIDE);
-
- /*
- * Set initial PD communication policy.
- */
- tc_policy_pd_enable(port, pd_comm_allowed_by_policy());
-
-#ifdef HAS_TASK_CHIPSET
- /* Set dual-role state based on chipset power state */
- if (chipset_in_state(CHIPSET_STATE_ANY_OFF))
- pd_set_dual_role_and_event(port, PD_DRP_FORCE_SINK, 0);
- else if (chipset_in_state(CHIPSET_STATE_ANY_SUSPEND))
- pd_set_dual_role_and_event(port, pd_get_drp_state_in_suspend(), 0);
- else /* CHIPSET_STATE_ON */
- pd_set_dual_role_and_event(port, PD_DRP_TOGGLE_ON, 0);
-#else
- pd_set_dual_role_and_event(port, board_tc_get_initial_drp_mode(port), 0);
-#endif
-
- /*
- * We are going to apply CC open (start with ErrorRecovery state)
- * unless there is something which forbids us to do that (one of
- * conditions below is true)
- */
- first_state = TC_ERROR_RECOVERY;
-
- /*
- * If we just lost power, don't apply CC open. Otherwise we would boot
- * loop, and if this is a fresh power on, then we know there isn't any
- * stale PD state as well.
- */
- if (system_get_reset_flags() &
- (EC_RESET_FLAG_BROWNOUT | EC_RESET_FLAG_POWER_ON)) {
- first_state = TC_UNATTACHED_SNK;
- }
-
- /*
- * If this is non-EFS2 device, battery is not present and EC RO doesn't
- * keep power-on reset flag after reset caused by H1, then don't apply
- * CC open because it will cause brown out.
- *
- * Please note that we are checking if CONFIG_BOARD_RESET_AFTER_POWER_ON
- * is defined now, but actually we need to know if it was enabled in
- * EC RO! It was assumed that if CONFIG_BOARD_RESET_AFTER_POWER_ON is
- * defined now it was defined in EC RO too.
- */
- if (!IS_ENABLED(CONFIG_BOARD_RESET_AFTER_POWER_ON) &&
- !IS_ENABLED(CONFIG_VBOOT_EFS2) && IS_ENABLED(CONFIG_BATTERY) &&
- (battery_is_present() == BP_NO)) {
- first_state = TC_UNATTACHED_SNK;
- }
-
- if (first_state == TC_UNATTACHED_SNK) {
- /* Turn off any previous sourcing */
- tc_src_power_off(port);
- set_vconn(port, 0);
- }
-
-#ifdef CONFIG_USB_PD_TCPC_BOARD_INIT
- /* Board specific TCPC init */
- board_tcpc_init();
-#endif
-
- /*
- * Start with ErrorRecovery state if we can to put us in
- * a clean state from any previous boots.
- */
- restart_tc_sm(port, first_state);
-}
-
-enum pd_cable_plug tc_get_cable_plug(int port)
-{
- /*
- * Messages sent by this state machine are always from a DFP/UFP,
- * i.e. the chromebook.
- */
- return PD_PLUG_FROM_DFP_UFP;
-}
-
-void pd_comm_enable(int port, int en)
-{
- tc_policy_pd_enable(port, en);
-}
-
-uint8_t tc_get_polarity(int port)
-{
- return tc[port].polarity;
-}
-
-uint8_t tc_get_pd_enabled(int port)
-{
- return !tc[port].pd_disabled_mask;
-}
-
-bool pd_alt_mode_capable(int port)
-{
- return IS_ENABLED(CONFIG_USB_PE_SM) && tc_get_pd_enabled(port);
-}
-
-void tc_set_power_role(int port, enum pd_power_role role)
-{
- tc[port].power_role = role;
-}
-
-/*
- * Private Functions
- */
-
-/* Set GPIO_CCD_MODE_ODL gpio */
-static void set_ccd_mode(const int port, const bool enable)
-{
- if (IS_ENABLED(CONFIG_ASSERT_CCD_MODE_ON_DTS_CONNECT) &&
- port == CONFIG_CCD_USBC_PORT_NUMBER) {
- if (enable)
- CPRINTS("Asserting GPIO_CCD_MODE_ODL");
- gpio_set_level(_GPIO_CCD_MODE_ODL, !enable);
- }
-}
-
-/* Set the TypeC state machine to a new state. */
-static void set_state_tc(const int port, const enum usb_tc_state new_state)
-{
- assert(port == TASK_ID_TO_PD_PORT(task_get_current()));
-
- set_state(port, &tc[port].ctx, &tc_states[new_state]);
-}
-
-/* Get the current TypeC state. */
-test_export_static enum usb_tc_state get_state_tc(const int port)
-{
- /* Default to returning TC_STATE_COUNT if no state has been set */
- if (tc[port].ctx.current == NULL)
- return TC_STATE_COUNT;
- else
- return tc[port].ctx.current - &tc_states[0];
-}
-
-/* Get the previous TypeC state. */
-static enum usb_tc_state get_last_state_tc(const int port)
-{
- return tc[port].ctx.previous - &tc_states[0];
-}
-
-static void print_current_state(const int port)
-{
- if (IS_ENABLED(USB_PD_DEBUG_LABELS))
- CPRINTS_L1("C%d: %s", port, tc_state_names[get_state_tc(port)]);
- else
- CPRINTS("C%d: tc-st%d", port, get_state_tc(port));
-}
-
-static void handle_device_access(int port)
-{
- if (IS_ENABLED(CONFIG_USB_PD_TCPC_LOW_POWER) &&
- get_state_tc(port) == TC_LOW_POWER_MODE) {
- tc_start_event_loop(port);
- pd_timer_enable(port, TC_TIMER_LOW_POWER_TIME,
- PD_LPM_DEBOUNCE_US);
- }
-}
-
-void tc_event_check(int port, int evt)
-{
-#ifdef DEBUG_PRINT_FLAG_AND_EVENT_NAMES
- if (evt != TASK_EVENT_TIMER)
- print_bits(port, "Event", evt, event_bit_names,
- ARRAY_SIZE(event_bit_names));
-#endif
-
- if (evt & PD_EXIT_LOW_POWER_EVENT_MASK)
- TC_SET_FLAG(port, TC_FLAGS_CHECK_CONNECTION);
-
- if (evt & PD_EVENT_DEVICE_ACCESSED)
- handle_device_access(port);
-
- if (evt & PD_EVENT_TCPC_RESET)
- reset_device_and_notify(port);
-
- if (evt & PD_EVENT_RX_HARD_RESET)
- pd_execute_hard_reset(port);
-
- if (evt & PD_EVENT_SEND_HARD_RESET) {
- /* Pass Hard Reset request to PE layer if available */
- if (IS_ENABLED(CONFIG_USB_PE_SM) && tc_get_pd_enabled(port))
- pd_dpm_request(port, DPM_REQUEST_HARD_RESET_SEND);
- }
-
-#ifdef CONFIG_POWER_COMMON
- if (IS_ENABLED(CONFIG_POWER_COMMON)) {
- if (evt & PD_EVENT_POWER_STATE_CHANGE)
- handle_new_power_state(port);
- }
-#endif /* CONFIG_POWER_COMMON */
-
- if (IS_ENABLED(CONFIG_USB_PD_ALT_MODE_DFP)) {
- int i;
-
- /*
- * Notify all ports of sysjump
- */
- if (evt & PD_EVENT_SYSJUMP) {
- for (i = 0; i <
- CONFIG_USB_PD_PORT_MAX_COUNT; i++)
- dpm_set_mode_exit_request(i);
- notify_sysjump_ready();
- }
- }
-
- if (evt & PD_EVENT_UPDATE_DUAL_ROLE)
- pd_update_dual_role_config(port);
-}
-
-/*
- * CC values for regular sources and Debug sources (aka DTS)
- *
- * Source type Mode of Operation CC1 CC2
- * ---------------------------------------------
- * Regular Default USB Power RpUSB Open
- * Regular USB-C @ 1.5 A Rp1A5 Open
- * Regular USB-C @ 3 A Rp3A0 Open
- * DTS Default USB Power Rp3A0 Rp1A5
- * DTS USB-C @ 1.5 A Rp1A5 RpUSB
- * DTS USB-C @ 3 A Rp3A0 RpUSB
- */
-
-void tc_set_data_role(int port, enum pd_data_role role)
-{
- enum pd_data_role prev_data_role;
-
- prev_data_role = tc[port].data_role;
- tc[port].data_role = role;
-
- if (IS_ENABLED(CONFIG_USBC_SS_MUX))
- set_usb_mux_with_current_data_role(port);
-
- /*
- * Run any board-specific code for role swap (e.g. setting OTG signals
- * to SoC).
- */
- pd_execute_data_swap(port, role);
-
- /*
- * For BC1.2 detection that is triggered on data role change events
- * instead of VBUS changes, need to set an event to wake up the USB_CHG
- * task and indicate the current data role.
- */
- bc12_role_change_handler(port, prev_data_role, tc[port].data_role);
-
- /* Notify TCPC of role update */
- tcpm_set_msg_header(port, tc[port].power_role, tc[port].data_role);
-}
-
-static void sink_stop_drawing_current(int port)
-{
- pd_set_input_current_limit(port, 0, 0);
-
- if (IS_ENABLED(CONFIG_CHARGE_MANAGER)) {
- typec_set_input_current_limit(port, 0, 0);
- charge_manager_set_ceil(port,
- CEIL_REQUESTOR_PD, CHARGE_CEIL_NONE);
- }
-}
-
-static void pd_update_try_source(void)
-{
-#ifdef CONFIG_USB_PD_TRY_SRC
- tc_enable_try_src(pd_is_try_source_capable());
-#endif
-}
-DECLARE_HOOK(HOOK_BATTERY_SOC_CHANGE, pd_update_try_source, HOOK_PRIO_DEFAULT);
-
-static void set_vconn(int port, int enable)
-{
- if (enable)
- TC_SET_FLAG(port, TC_FLAGS_VCONN_ON);
- else
- TC_CLR_FLAG(port, TC_FLAGS_VCONN_ON);
-
- /*
- * Check our OC event counter. If we've exceeded our threshold, then
- * let's latch our source path off to prevent continuous cycling. When
- * the PD state machine detects a disconnection on the CC lines, we will
- * reset our OC event counter.
- */
- if (IS_ENABLED(CONFIG_USBC_OCP) &&
- enable && usbc_ocp_is_port_latched_off(port))
- return;
-
- /*
- * Disable PPC Vconn first then TCPC in case the voltage feeds back
- * to TCPC and damages.
- */
- if (IS_ENABLED(CONFIG_USBC_PPC_VCONN) && !enable)
- ppc_set_vconn(port, 0);
-
- /*
- * Some TCPCs/PPC combinations can trigger OVP if the TCPC doesn't
- * source VCONN. This happens if the TCPC will trip OVP with 5V, and the
- * PPC doesn't isolate the TCPC from VCONN when sourcing. But, some PPCs
- * which do isolate the TCPC can't handle 5V on its host-side CC pins,
- * so the TCPC shouldn't source VCONN in those cases.
- *
- * In the first case, both TCPC and PPC will potentially source Vconn,
- * but that should be okay since Vconn has "make before break"
- * electrical requirements when swapping anyway.
- *
- * See b/72961003 and b/180973460
- */
- tcpm_set_vconn(port, enable);
-
- if (IS_ENABLED(CONFIG_USBC_PPC_VCONN) && enable)
- ppc_set_vconn(port, 1);
-}
-
-/* This must only be called from the PD task */
-static void pd_update_dual_role_config(int port)
-{
- if (tc[port].power_role == PD_ROLE_SOURCE &&
- (drp_state[port] == PD_DRP_FORCE_SINK ||
- (drp_state[port] == PD_DRP_TOGGLE_OFF &&
- get_state_tc(port) == TC_UNATTACHED_SRC))) {
- /*
- * Change to sink if port is currently a source AND (new DRP
- * state is force sink OR new DRP state is toggle off and we are
- * in the source disconnected state).
- */
- set_state_tc(port, TC_UNATTACHED_SNK);
- } else if (tc[port].power_role == PD_ROLE_SINK &&
- drp_state[port] == PD_DRP_FORCE_SOURCE) {
- /*
- * Change to source if port is currently a sink and the
- * new DRP state is force source.
- */
- set_state_tc(port, TC_UNATTACHED_SRC);
- }
-}
-
-__maybe_unused static void handle_new_power_state(int port)
-{
- if (!IS_ENABLED(CONFIG_POWER_COMMON))
- assert(0);
-
- if (IS_ENABLED(CONFIG_POWER_COMMON) &&
- IS_ENABLED(CONFIG_USB_PE_SM)) {
- if (chipset_in_or_transitioning_to_state(
- CHIPSET_STATE_ANY_OFF)) {
- /*
- * The SoC will negotiate alternate mode again when it
- * boots up
- */
- dpm_set_mode_exit_request(port);
- }
- }
-
- /*
- * If the sink port was sourcing Vconn, and can no longer, request a
- * hard reset on this port to restore Vconn to the source.
- */
- if (IS_ENABLED(CONFIG_USB_PE_SM)) {
- if (tc_is_vconn_src(port) && tc_is_attached_snk(port) &&
- !pd_check_vconn_swap(port))
- pd_dpm_request(port, DPM_REQUEST_HARD_RESET_SEND);
- }
-
- /*
- * TC_FLAGS_UPDATE_USB_MUX is set on chipset startup and shutdown.
- * Set the USB mux according to the new power state. If the chipset
- * is transitioning to OFF, this disconnects USB and DP mux.
- *
- * Transitions to and from suspend states do not change the USB mux
- * or the alternate mode configuration.
- */
- if (TC_CHK_FLAG(port, TC_FLAGS_UPDATE_USB_MUX)) {
- TC_CLR_FLAG(port, TC_FLAGS_UPDATE_USB_MUX);
- set_usb_mux_with_current_data_role(port);
- }
-}
-
-#ifdef CONFIG_USBC_VCONN_SWAP
-void pd_request_vconn_swap_off(int port)
-{
- if (get_state_tc(port) == TC_ATTACHED_SRC ||
- get_state_tc(port) == TC_ATTACHED_SNK) {
- TC_SET_FLAG(port, TC_FLAGS_REQUEST_VC_SWAP_OFF);
- task_wake(PD_PORT_TO_TASK_ID(port));
- }
-}
-
-void pd_request_vconn_swap_on(int port)
-{
- if (get_state_tc(port) == TC_ATTACHED_SRC ||
- get_state_tc(port) == TC_ATTACHED_SNK) {
- TC_SET_FLAG(port, TC_FLAGS_REQUEST_VC_SWAP_ON);
- task_wake(PD_PORT_TO_TASK_ID(port));
- }
-}
-
-void pd_request_vconn_swap(int port)
-{
- pd_dpm_request(port, DPM_REQUEST_VCONN_SWAP);
-}
-#endif
-
-int tc_is_vconn_src(int port)
-{
- if (IS_ENABLED(CONFIG_USBC_VCONN))
- return TC_CHK_FLAG(port, TC_FLAGS_VCONN_ON);
- else
- return 0;
-}
-
-static __maybe_unused int reset_device_and_notify(int port)
-{
- int rv;
- int task, waiting_tasks;
-
- /* This should only be called from the PD task */
- assert(port == TASK_ID_TO_PD_PORT(task_get_current()));
-
- TC_SET_FLAG(port, TC_FLAGS_LPM_TRANSITION);
- rv = tcpm_init(port);
- TC_CLR_FLAG(port, TC_FLAGS_LPM_TRANSITION);
- TC_CLR_FLAG(port, TC_FLAGS_LPM_ENGAGED);
- tc_start_event_loop(port);
-
- CPRINTS("C%d: TCPC init %s", port, rv ? "failed!" : "ready");
-
- /*
- * Before getting the other tasks that are waiting, clear the reset
- * event from this PD task to prevent multiple reset/init events
- * occurring.
- *
- * The double reset event happens when the higher priority PD interrupt
- * task gets an interrupt during the above tcpm_init function. When that
- * occurs, the higher priority task waits correctly for us to finish
- * waking the TCPC, but it has also set PD_EVENT_TCPC_RESET again, which
- * would result in a second, unnecessary init.
- */
- atomic_clear_bits(task_get_event_bitmap(task_get_current()),
- PD_EVENT_TCPC_RESET);
-
- waiting_tasks = atomic_clear(&tc[port].tasks_waiting_on_reset);
-
- /* Wake up all waiting tasks. */
- while (waiting_tasks) {
- task = __fls(waiting_tasks);
- waiting_tasks &= ~BIT(task);
- task_set_event(task, TASK_EVENT_PD_AWAKE);
- }
-
- return rv;
-}
-
-#ifdef CONFIG_USB_PD_TCPC_LOW_POWER
-void pd_wait_exit_low_power(int port)
-{
- if (!TC_CHK_FLAG(port, TC_FLAGS_LPM_ENGAGED))
- return;
-
- if (port == TASK_ID_TO_PD_PORT(task_get_current())) {
- if (!TC_CHK_FLAG(port, TC_FLAGS_LPM_TRANSITION))
- reset_device_and_notify(port);
- } else {
- /* Otherwise, we need to wait for the TCPC reset to complete */
- atomic_or(&tc[port].tasks_waiting_on_reset,
- 1 << task_get_current());
- /*
- * NOTE: We could be sending the PD task the reset event while
- * it is already processing the reset event. If that occurs,
- * then we will reset the TCPC multiple times, which is
- * undesirable but most likely benign. Empirically, this doesn't
- * happen much, but it if starts occurring, we can add a guard
- * to prevent/reduce it.
- */
- task_set_event(PD_PORT_TO_TASK_ID(port), PD_EVENT_TCPC_RESET);
- task_wait_event_mask(TASK_EVENT_PD_AWAKE, -1);
- }
-}
-
-/*
- * This can be called from any task. If we are in the PD task, we can handle
- * immediately. Otherwise, we need to notify the PD task via event.
- */
-void pd_device_accessed(int port)
-{
- if (port == TASK_ID_TO_PD_PORT(task_get_current()))
- handle_device_access(port);
- else
- task_set_event(PD_PORT_TO_TASK_ID(port),
- PD_EVENT_DEVICE_ACCESSED);
-}
-
-/*
- * TODO(b/137493121): Move this function to a separate file that's shared
- * between the this and the original stack.
- */
-void pd_prevent_low_power_mode(int port, int prevent)
-{
- const int current_task_mask = (1 << task_get_current());
-
- if (prevent)
- atomic_or(&tc[port].tasks_preventing_lpm, current_task_mask);
- else
- atomic_clear_bits(&tc[port].tasks_preventing_lpm,
- current_task_mask);
-}
-#endif /* CONFIG_USB_PD_TCPC_LOW_POWER */
-
-static void sink_power_sub_states(int port)
-{
- enum tcpc_cc_voltage_status cc1, cc2, cc;
- enum tcpc_cc_voltage_status new_cc_voltage;
-
- tcpm_get_cc(port, &cc1, &cc2);
-
- cc = polarity_rm_dts(tc[port].polarity) ? cc2 : cc1;
-
- if (cc == TYPEC_CC_VOLT_RP_DEF)
- new_cc_voltage = TYPEC_CC_VOLT_RP_DEF;
- else if (cc == TYPEC_CC_VOLT_RP_1_5)
- new_cc_voltage = TYPEC_CC_VOLT_RP_1_5;
- else if (cc == TYPEC_CC_VOLT_RP_3_0)
- new_cc_voltage = TYPEC_CC_VOLT_RP_3_0;
- else
- new_cc_voltage = TYPEC_CC_VOLT_OPEN;
-
- /* Debounce the cc state */
- if (new_cc_voltage != tc[port].cc_voltage) {
- tc[port].cc_voltage = new_cc_voltage;
- pd_timer_enable(port, TC_TIMER_CC_DEBOUNCE,
- PD_T_RP_VALUE_CHANGE);
- return;
- }
-
- if (!pd_timer_is_disabled(port, TC_TIMER_CC_DEBOUNCE)) {
- if (!pd_timer_is_expired(port, TC_TIMER_CC_DEBOUNCE))
- return;
-
- pd_timer_disable(port, TC_TIMER_CC_DEBOUNCE);
-
- if (IS_ENABLED(CONFIG_CHARGE_MANAGER)) {
- tc[port].typec_curr = usb_get_typec_current_limit(
- tc[port].polarity, cc1, cc2);
-
- typec_set_input_current_limit(port,
- tc[port].typec_curr, TYPE_C_VOLTAGE);
- charge_manager_update_dualrole(port, CAP_DEDICATED);
- }
- }
-}
-
-
-/*
- * TYPE-C State Implementations
- */
-
-/**
- * Disabled
- *
- * Super State Entry Actions:
- * Remove the terminations from CC
- * Set VBUS and VCONN off
- */
-static void tc_disabled_entry(const int port)
-{
- print_current_state(port);
- /*
- * We have completed tc_cc_open_entry (our super state), so set flag
- * to indicate to pd_is_port_enabled that we are now suspended.
- */
- TC_SET_FLAG(port, TC_FLAGS_SUSPENDED);
-}
-
-static void tc_disabled_run(const int port)
-{
- /* If pd_set_suspend clears the request, go to TC_UNATTACHED_SNK/SRC. */
- if (!TC_CHK_FLAG(port, TC_FLAGS_REQUEST_SUSPEND)) {
- set_state_tc(port, drp_state[port] == PD_DRP_FORCE_SOURCE ?
- TC_UNATTACHED_SRC : TC_UNATTACHED_SNK);
- } else {
- if (IS_ENABLED(CONFIG_USBC_RETIMER_FW_UPDATE)) {
- if (TC_CHK_FLAG(port,
- TC_FLAGS_USB_RETIMER_FW_UPDATE_LTD_RUN)) {
- TC_CLR_FLAG(port,
- TC_FLAGS_USB_RETIMER_FW_UPDATE_LTD_RUN);
- usb_retimer_fw_update_process_op_cb(port);
- }
- }
- tc_pause_event_loop(port);
- }
-}
-
-static void tc_disabled_exit(const int port)
-{
- int rv;
-
- tc_start_event_loop(port);
- TC_CLR_FLAG(port, TC_FLAGS_SUSPENDED);
-
- rv = tcpm_init(port);
- CPRINTS("C%d: TCPC init %s", port, rv ? "failed!" : "ready");
-}
-
-/**
- * ErrorRecovery
- *
- * Super State Entry Actions:
- * Remove the terminations from CC
- * Set's VBUS and VCONN off
- */
-static void tc_error_recovery_entry(const int port)
-{
- print_current_state(port);
-
- pd_timer_enable(port, TC_TIMER_TIMEOUT, PD_T_ERROR_RECOVERY);
-
- TC_CLR_FLAG(port, TC_FLAGS_REQUEST_ERROR_RECOVERY);
-}
-
-static void tc_error_recovery_run(const int port)
-{
- enum usb_tc_state start_state;
-
- if (!pd_timer_is_expired(port, TC_TIMER_TIMEOUT))
- return;
-
- /*
- * If we transitioned to error recovery as the first state and we
- * didn't brown out, we don't need to reinitialized the tc statemachine
- * because we just did that. So transition to the state directly.
- */
- if (tc[port].ctx.previous == NULL) {
- set_state_tc(port, drp_state[port] == PD_DRP_FORCE_SOURCE ?
- TC_UNATTACHED_SRC : TC_UNATTACHED_SNK);
- return;
- }
-
- /*
- * If try src support is active (e.g. in S0). Then try to become the
- * SRC, otherwise we should try to be the sink.
- */
- start_state = TC_UNATTACHED_SNK;
- if (IS_ENABLED(CONFIG_USB_PD_TRY_SRC))
- if (is_try_src_enabled(port) ||
- drp_state[port] == PD_DRP_FORCE_SOURCE)
- start_state = TC_UNATTACHED_SRC;
-
- restart_tc_sm(port, start_state);
-}
-
-static void tc_error_recovery_exit(const int port)
-{
- pd_timer_disable(port, TC_TIMER_TIMEOUT);
-}
-
-/**
- * Unattached.SNK
- */
-static void tc_unattached_snk_entry(const int port)
-{
- enum pd_data_role prev_data_role;
-
- if (get_last_state_tc(port) != TC_UNATTACHED_SRC) {
- tc_detached(port);
- print_current_state(port);
- }
-
- /*
- * We are in an unattached state and considering to be a SNK
- * searching for a SRC partner. We set the CC pull value to
- * to indicate our intent to be SNK in hopes a partner SRC
- * will is there to attach to.
- *
- * Both CC1 and CC2 pins shall be independently terminated to
- * ground through Rd.
- *
- * Restore default current limit Rp in case we swap to source
- *
- * Run any debug detaches needed before setting CC, as some TCPCs may
- * require we set CC Open before changing power roles with a debug
- * accessory.
- */
- tcpm_debug_detach(port);
- typec_select_pull(port, TYPEC_CC_RD);
- typec_select_src_current_limit_rp(port,
- typec_get_default_current_limit_rp(port));
- typec_update_cc(port);
-
-
- prev_data_role = tc[port].data_role;
- tc[port].data_role = PD_ROLE_DISCONNECTED;
- /*
- * When data role set events are used to enable BC1.2, then CC
- * detach events are used to notify BC1.2 that it can be powered
- * down.
- */
- bc12_role_change_handler(port, prev_data_role, tc[port].data_role);
-
- if (IS_ENABLED(CONFIG_CHARGE_MANAGER))
- charge_manager_update_dualrole(port, CAP_UNKNOWN);
-
- tc_set_partner_role(port, PPC_DEV_DISCONNECTED);
-
- /*
- * Indicate that the port is disconnected so the board
- * can restore state from any previous data swap.
- */
- pd_execute_data_swap(port, PD_ROLE_DISCONNECTED);
- pd_timer_enable(port, TC_TIMER_NEXT_ROLE_SWAP, PD_T_DRP_SNK);
-
- if (IS_ENABLED(CONFIG_USB_PE_SM)) {
- CLR_FLAGS_ON_DISCONNECT(port);
- tc_enable_pd(port, 0);
- }
-}
-
-static void tc_unattached_snk_run(const int port)
-{
- enum tcpc_cc_voltage_status cc1, cc2;
-
- /*
- * TODO(b/137498392): Add wait before sampling the CC
- * status after role changes
- */
-
- if (IS_ENABLED(CONFIG_USB_PE_SM)) {
- if (TC_CHK_FLAG(port, TC_FLAGS_HARD_RESET_REQUESTED)) {
- TC_CLR_FLAG(port, TC_FLAGS_HARD_RESET_REQUESTED);
- tc_set_data_role(port, PD_ROLE_UFP);
- /* Inform Policy Engine that hard reset is complete */
- pe_ps_reset_complete(port);
- }
- }
-
- /* Check for connection */
- tcpm_get_cc(port, &cc1, &cc2);
-
- /*
- * The port shall transition to AttachWait.SNK when a Source
- * connection is detected, as indicated by the SNK.Rp state
- * on at least one of its CC pins.
- *
- * A DRP shall transition to Unattached.SRC within tDRPTransition
- * after the state of both CC pins is SNK.Open for
- * tDRP − dcSRC.DRP ∙ tDRP.
- */
- if (cc_is_rp(cc1) || cc_is_rp(cc2)) {
- /* Connection Detected */
- set_state_tc(port, TC_ATTACH_WAIT_SNK);
- return;
- }
-
- /*
- * Debounce the CC open status. Some TCPC needs time to get the CC
- * status valid. Before that, CC open is reported by default. Wait
- * to make sure the CC is really open. Reuse the role toggle timer.
- */
- if (!pd_timer_is_expired(port, TC_TIMER_NEXT_ROLE_SWAP))
- return;
-
- /*
- * Initialize type-C supplier current limits to 0. The charge
- * manage is now seeded if it was not.
- */
- if (IS_ENABLED(CONFIG_CHARGE_MANAGER))
- typec_set_input_current_limit(port, 0, 0);
-
- /*
- * Attempt TCPC auto DRP toggle if it is
- * not already auto toggling.
- */
- if (IS_ENABLED(CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE) &&
- drp_state[port] == PD_DRP_TOGGLE_ON &&
- tcpm_auto_toggle_supported(port)) {
- set_state_tc(port, TC_DRP_AUTO_TOGGLE);
- } else if (drp_state[port] == PD_DRP_TOGGLE_ON) {
- /* DRP Toggle. The timer was checked above. */
- set_state_tc(port, TC_UNATTACHED_SRC);
- } else if (IS_ENABLED(CONFIG_USB_PD_TCPC_LOW_POWER) &&
- (drp_state[port] == PD_DRP_FORCE_SINK ||
- drp_state[port] == PD_DRP_TOGGLE_OFF)) {
- set_state_tc(port, TC_LOW_POWER_MODE);
- }
-}
-
-static void tc_unattached_snk_exit(const int port)
-{
- pd_timer_disable(port, TC_TIMER_NEXT_ROLE_SWAP);
-}
-
-/**
- * AttachWait.SNK
- *
- * Super State Entry Actions:
- * Vconn Off
- * Place Rd on CC
- * Set power role to SINK
- */
-static void tc_attach_wait_snk_entry(const int port)
-{
- print_current_state(port);
-
- tc[port].cc_state = PD_CC_UNSET;
-}
-
-static void tc_attach_wait_snk_run(const int port)
-{
- enum tcpc_cc_voltage_status cc1, cc2;
- enum pd_cc_states new_cc_state;
-
- /* Check for connection */
- tcpm_get_cc(port, &cc1, &cc2);
-
- if (cc_is_rp(cc1) && cc_is_rp(cc2) && board_is_dts_port(port))
- new_cc_state = PD_CC_DFP_DEBUG_ACC;
- else if (cc_is_rp(cc1) || cc_is_rp(cc2))
- new_cc_state = PD_CC_DFP_ATTACHED;
- else
- new_cc_state = PD_CC_NONE;
-
- /* Debounce the cc state */
- if (new_cc_state != tc[port].cc_state) {
- pd_timer_enable(port, TC_TIMER_CC_DEBOUNCE, PD_T_CC_DEBOUNCE);
- pd_timer_enable(port, TC_TIMER_PD_DEBOUNCE, PD_T_PD_DEBOUNCE);
- tc[port].cc_state = new_cc_state;
- return;
- }
-
- /*
- * A DRP shall transition to Unattached.SRC when the state of both
- * the CC1 and CC2 pins is SNK.Open for at least tPDDebounce, however
- * when DRP state prevents switch to SRC the next state should be
- * Unattached.SNK.
- */
- if (new_cc_state == PD_CC_NONE &&
- pd_timer_is_expired(port, TC_TIMER_PD_DEBOUNCE)) {
- /* We are detached */
- if (drp_state[port] == PD_DRP_TOGGLE_OFF
- || drp_state[port] == PD_DRP_FREEZE
- || drp_state[port] == PD_DRP_FORCE_SINK)
- set_state_tc(port, TC_UNATTACHED_SNK);
- else
- set_state_tc(port, TC_UNATTACHED_SRC);
- return;
- }
-
- /* Wait for CC debounce */
- if (!pd_timer_is_expired(port, TC_TIMER_CC_DEBOUNCE))
- return;
-
- /*
- * The port shall transition to Attached.SNK after the state of only
- * one of the CC1 or CC2 pins is SNK.Rp for at least tCCDebounce and
- * VBUS is detected.
- *
- * A DRP that strongly prefers the Source role may optionally
- * transition to Try.SRC instead of Attached.SNK when the state of only
- * one CC pin has been SNK.Rp for at least tCCDebounce and VBUS is
- * detected.
- *
- * If the port supports Debug Accessory Mode, the port shall transition
- * to DebugAccessory.SNK if the state of both the CC1 and CC2 pins is
- * SNK.Rp for at least tCCDebounce and VBUS is detected.
- */
- if (pd_is_vbus_present(port)) {
- if (new_cc_state == PD_CC_DFP_ATTACHED) {
- if (IS_ENABLED(CONFIG_USB_PD_TRY_SRC) &&
- is_try_src_enabled(port))
- set_state_tc(port, TC_TRY_SRC);
- else
- set_state_tc(port, TC_ATTACHED_SNK);
- } else {
- /* new_cc_state is PD_CC_DFP_DEBUG_ACC */
- CPRINTS("C%d: Debug accessory detected", port);
- TC_SET_FLAG(port, TC_FLAGS_TS_DTS_PARTNER);
- set_state_tc(port, TC_ATTACHED_SNK);
- }
-
- if (IS_ENABLED(CONFIG_USB_PE_SM) &&
- IS_ENABLED(CONFIG_USB_PD_ALT_MODE_DFP)) {
- hook_call_deferred(&pd_usb_billboard_deferred_data,
- PD_T_AME);
- }
- }
-}
-
-static void tc_attach_wait_snk_exit(const int port)
-{
- pd_timer_disable(port, TC_TIMER_CC_DEBOUNCE);
- pd_timer_disable(port, TC_TIMER_PD_DEBOUNCE);
-}
-
-/**
- * Attached.SNK, shared with Debug Accessory.SNK
- */
-static void tc_attached_snk_entry(const int port)
-{
- enum tcpc_cc_voltage_status cc1, cc2;
-
- print_current_state(port);
-
- /*
- * Known state of attach is SNK. We need to apply this pull value
- * to make it set in hardware at the correct time but set the common
- * pull here.
- *
- * Both CC1 and CC2 pins shall be independently terminated to
- * ground through Rd.
- */
- typec_select_pull(port, TYPEC_CC_RD);
-
- /* Inform the PPC and OCP module that a source is connected */
- tc_set_partner_role(port, PPC_DEV_SRC);
-
- if (IS_ENABLED(CONFIG_USB_PE_SM) &&
- TC_CHK_FLAG(port, TC_FLAGS_PR_SWAP_IN_PROGRESS)) {
- /* Flipping power role - Disable AutoDischargeDisconnect */
- tcpm_enable_auto_discharge_disconnect(port, 0);
-
- /* Apply Rd */
- typec_update_cc(port);
-
- /* Change role to sink */
- tc_set_power_role(port, PD_ROLE_SINK);
- tcpm_set_msg_header(port, tc[port].power_role,
- tc[port].data_role);
-
- /*
- * Maintain VCONN supply state, whether ON or OFF, and its
- * data role / usb mux connections. Do not re-enable
- * AutoDischargeDisconnect until the swap is completed
- * and tc_pr_swap_complete is called.
- */
- } else {
- /* Get connector orientation */
- tcpm_get_cc(port, &cc1, &cc2);
- tc[port].polarity = get_snk_polarity(cc1, cc2);
- pd_set_polarity(port, tc[port].polarity);
-
- tc_set_data_role(port, PD_ROLE_UFP);
-
- hook_notify(HOOK_USB_PD_CONNECT);
-
- if (IS_ENABLED(CONFIG_CHARGE_MANAGER)) {
- tc[port].typec_curr =
- usb_get_typec_current_limit(tc[port].polarity,
- cc1, cc2);
- typec_set_input_current_limit(port,
- tc[port].typec_curr, TYPE_C_VOLTAGE);
- /*
- * Start new connections as dedicated until source caps
- * are received, at which point the PE will update the
- * flag.
- */
- charge_manager_update_dualrole(port, CAP_DEDICATED);
- }
-
- /* Apply Rd */
- typec_update_cc(port);
-
- /*
- * Attached.SNK - enable AutoDischargeDisconnect
- * Do this after applying Rd to CC lines to avoid
- * TCPC_REG_FAULT_STATUS_AUTO_DISCHARGE_FAIL (b/171567398)
- */
- tcpm_enable_auto_discharge_disconnect(port, 1);
- }
-
- pd_timer_disable(port, TC_TIMER_CC_DEBOUNCE);
-
- /* Enable PD */
- if (IS_ENABLED(CONFIG_USB_PE_SM))
- tc_enable_pd(port, 1);
-
- if (TC_CHK_FLAG(port, TC_FLAGS_TS_DTS_PARTNER)) {
- tcpm_debug_accessory(port, 1);
- set_ccd_mode(port, 1);
- }
-}
-
-/*
- * Check whether Vbus has been removed on this port, accounting for some Vbus
- * debounce if FRS is enabled.
- *
- * Returns true if a new state was set and the calling run should exit.
- */
-static bool tc_snk_check_vbus_removed(const int port)
-{
- if (IS_ENABLED(CONFIG_USB_PD_FRS)) {
- /*
- * Debounce Vbus presence when FRS is enabled. Note that we may
- * lose Vbus before the FRS signal comes in to let us know
- * we're PR swapping, but we must still transition to unattached
- * within tSinkDisconnect.
- *
- * We may safely re-use the Vbus debounce timer here
- * since a PR swap would no longer be in progress when Vbus
- * removal is checked.
- */
- if (pd_check_vbus_level(port, VBUS_REMOVED)) {
- if (pd_timer_is_disabled(port,
- TC_TIMER_VBUS_DEBOUNCE)) {
- pd_timer_enable(port, TC_TIMER_VBUS_DEBOUNCE,
- PD_T_FRS_VBUS_DEBOUNCE);
- } else if (pd_timer_is_expired(port,
- TC_TIMER_VBUS_DEBOUNCE)) {
- set_state_tc(port, TC_UNATTACHED_SNK);
- return true;
- }
- } else {
- pd_timer_disable(port, TC_TIMER_VBUS_DEBOUNCE);
- }
- } else if (pd_check_vbus_level(port, VBUS_REMOVED)) {
- set_state_tc(port, TC_UNATTACHED_SNK);
- return true;
- }
-
- return false;
-}
-
-static void tc_attached_snk_run(const int port)
-{
-#ifdef CONFIG_USB_PE_SM
- /*
- * Perform Hard Reset
- */
- if (TC_CHK_FLAG(port, TC_FLAGS_HARD_RESET_REQUESTED)) {
- /*
- * Wait to clear the hard reset request until Vbus has returned
- * to default (or, if it didn't return, we transition to
- * unattached)
- */
- if (tc_perform_snk_hard_reset(port))
- TC_CLR_FLAG(port, TC_FLAGS_HARD_RESET_REQUESTED);
-
- return;
- }
-
- /*
- * From 4.5.2.2.5.2 Exiting from Attached.SNK State:
- *
- * "A port that is not a Vconn-Powered USB Device and is not in the
- * process of a USB PD PR_Swap or a USB PD Hard Reset or a USB PD
- * FR_Swap shall transition to Unattached.SNK within tSinkDisconnect
- * when Vbus falls below vSinkDisconnect for Vbus operating at or
- * below 5 V or below vSinkDisconnectPD when negotiated by USB PD
- * to operate above 5 V."
- *
- * TODO(b/149530538): Use vSinkDisconnectPD when above 5V
- */
-
- /*
- * Debounce Vbus before we drop that we are doing a PR_Swap
- */
- if (TC_CHK_FLAG(port, TC_FLAGS_PR_SWAP_IN_PROGRESS) &&
- pd_timer_is_expired(port, TC_TIMER_VBUS_DEBOUNCE)) {
- /* PR Swap is no longer in progress */
- TC_CLR_FLAG(port, TC_FLAGS_PR_SWAP_IN_PROGRESS);
- pd_timer_disable(port, TC_TIMER_VBUS_DEBOUNCE);
-
- /*
- * AutoDischargeDisconnect was turned off when we
- * hit Safe0V on SRC->SNK PR-Swap. We now are done
- * with the swap and should have Vbus, so re-enable
- * AutoDischargeDisconnect.
- */
- if (!pd_check_vbus_level(port, VBUS_REMOVED))
- tcpm_enable_auto_discharge_disconnect(port, 1);
- }
-
- /*
- * The sink will be powered off during a power role swap but we don't
- * want to trigger a disconnect.
- */
- if (!TC_CHK_FLAG(port, TC_FLAGS_POWER_OFF_SNK) &&
- !TC_CHK_FLAG(port, TC_FLAGS_PR_SWAP_IN_PROGRESS)) {
- /*
- * Detach detection
- */
- if (tc_snk_check_vbus_removed(port))
- return;
-
- if (!pe_is_explicit_contract(port))
- sink_power_sub_states(port);
- }
-
- /*
- * PD swap commands
- */
- if (tc_get_pd_enabled(port) && prl_is_running(port)) {
- /*
- * Power Role Swap
- */
- if (TC_CHK_FLAG(port, TC_FLAGS_REQUEST_PR_SWAP)) {
- /*
- * We may want to verify partner is applying Rd before
- * we swap. However, some TCPCs (such as TUSB422) will
- * not report the correct CC status before VBUS falls to
- * vSafe0V, so this will be problematic in the FRS case.
- */
- set_state_tc(port, TC_ATTACHED_SRC);
- return;
- }
-
- /*
- * Data Role Swap
- */
- if (TC_CHK_FLAG(port, TC_FLAGS_REQUEST_DR_SWAP)) {
- TC_CLR_FLAG(port, TC_FLAGS_REQUEST_DR_SWAP);
-
- /* Perform Data Role Swap */
- tc_set_data_role(port,
- tc[port].data_role == PD_ROLE_UFP ?
- PD_ROLE_DFP : PD_ROLE_UFP);
- }
-
- /*
- * VCONN Swap
- * UnorientedDebugAccessory.SRC shall not drive Vconn
- */
- if (IS_ENABLED(CONFIG_USBC_VCONN) &&
- !TC_CHK_FLAG(port, TC_FLAGS_TS_DTS_PARTNER)) {
- if (TC_CHK_FLAG(port, TC_FLAGS_REQUEST_VC_SWAP_ON)) {
- TC_CLR_FLAG(port, TC_FLAGS_REQUEST_VC_SWAP_ON);
-
- set_vconn(port, 1);
- /*
- * Inform policy engine that vconn swap is
- * complete
- */
- pe_vconn_swap_complete(port);
- } else if (TC_CHK_FLAG(port,
- TC_FLAGS_REQUEST_VC_SWAP_OFF)) {
- TC_CLR_FLAG(port, TC_FLAGS_REQUEST_VC_SWAP_OFF);
-
- set_vconn(port, 0);
- /*
- * Inform policy engine that vconn swap is
- * complete
- */
- pe_vconn_swap_complete(port);
- }
- }
-
- if (!TC_CHK_FLAG(port, TC_FLAGS_TS_DTS_PARTNER)) {
- /*
- * If the port supports Charge-Through VCONN-Powered USB
- * devices, and an explicit PD contract has failed to be
- * negotiated, the port shall query the identity of the
- * cable via USB PD on SOP’
- */
- if (!pe_is_explicit_contract(port) &&
- TC_CHK_FLAG(port, TC_FLAGS_CTVPD_DETECTED)) {
- /*
- * A port that via SOP’ has detected an
- * attached Charge-Through VCONN-Powered USB
- * device shall transition to Unattached.SRC
- * if an explicit PD contract has failed to
- * be negotiated.
- */
- /* CTVPD detected */
- set_state_tc(port, TC_UNATTACHED_SRC);
- }
- }
- }
-
-#else /* CONFIG_USB_PE_SM */
-
- /* Detach detection */
- if (tc_snk_check_vbus_removed(port))
- return;
-
- /* Run Sink Power Sub-State */
- sink_power_sub_states(port);
-#endif /* CONFIG_USB_PE_SM */
-}
-
-static void tc_attached_snk_exit(const int port)
-{
- if (!TC_CHK_FLAG(port, TC_FLAGS_REQUEST_PR_SWAP)) {
- /*
- * If supplying VCONN, the port shall cease to supply
- * it within tVCONNOFF of exiting Attached.SNK if not
- * PR swapping.
- */
- if (TC_CHK_FLAG(port, TC_FLAGS_VCONN_ON))
- set_vconn(port, 0);
-
- /*
- * Attached.SNK exit - disable AutoDischargeDisconnect
- * NOTE: This should not happen if we are suspending. It will
- * happen in tc_cc_open_entry if that is the path we are
- * taking.
- */
- if (!TC_CHK_FLAG(port, TC_FLAGS_REQUEST_SUSPEND))
- tcpm_enable_auto_discharge_disconnect(port, 0);
- }
-
- /* Clear flags after checking Vconn status */
- TC_CLR_FLAG(port, TC_FLAGS_REQUEST_PR_SWAP | TC_FLAGS_POWER_OFF_SNK);
-
- /* Stop drawing power */
- sink_stop_drawing_current(port);
-
- if (TC_CHK_FLAG(port, TC_FLAGS_TS_DTS_PARTNER))
- tcpm_debug_detach(port);
-
- pd_timer_disable(port, TC_TIMER_CC_DEBOUNCE);
- pd_timer_disable(port, TC_TIMER_TIMEOUT);
- pd_timer_disable(port, TC_TIMER_VBUS_DEBOUNCE);
-}
-
-/**
- * Unattached.SRC
- */
-static void tc_unattached_src_entry(const int port)
-{
- enum pd_data_role prev_data_role;
-
- if (get_last_state_tc(port) != TC_UNATTACHED_SNK) {
- tc_detached(port);
- print_current_state(port);
- }
-
- /*
- * We are in an unattached state and considering to be a SRC
- * searching for a SNK partner. We set the CC pull value to
- * to indicate our intent to be SRC in hopes a partner SNK
- * will is there to attach to.
- *
- * Both CC1 and CC2 pins shall be independently terminated to
- * ground through Rp.
- *
- * Restore default current limit Rp.
- *
- * Run any debug detaches needed before setting CC, as some TCPCs may
- * require we set CC Open before changing power roles with a debug
- * accessory.
- */
- tcpm_debug_detach(port);
- typec_select_pull(port, TYPEC_CC_RP);
- typec_select_src_current_limit_rp(port,
- typec_get_default_current_limit_rp(port));
- typec_update_cc(port);
-
- prev_data_role = tc[port].data_role;
- tc[port].data_role = PD_ROLE_DISCONNECTED;
-
- /*
- * When data role set events are used to enable BC1.2, then CC
- * detach events are used to notify BC1.2 that it can be powered
- * down.
- */
- bc12_role_change_handler(port, prev_data_role, tc[port].data_role);
-
- tc_set_partner_role(port, PPC_DEV_DISCONNECTED);
-
- if (IS_ENABLED(CONFIG_CHARGE_MANAGER))
- charge_manager_update_dualrole(port, CAP_UNKNOWN);
-
- if (IS_ENABLED(CONFIG_USB_PE_SM)) {
- CLR_FLAGS_ON_DISCONNECT(port);
- tc_enable_pd(port, 0);
- }
-
- pd_timer_enable(port, TC_TIMER_NEXT_ROLE_SWAP, PD_T_DRP_SRC);
-}
-
-static void tc_unattached_src_run(const int port)
-{
- enum tcpc_cc_voltage_status cc1, cc2;
-
- if (IS_ENABLED(CONFIG_USB_PE_SM)) {
- if (TC_CHK_FLAG(port, TC_FLAGS_HARD_RESET_REQUESTED)) {
- TC_CLR_FLAG(port, TC_FLAGS_HARD_RESET_REQUESTED);
- tc_set_data_role(port, PD_ROLE_DFP);
- /* Inform Policy Engine that hard reset is complete */
- pe_ps_reset_complete(port);
- }
- }
-
- if (IS_ENABLED(CONFIG_USBC_OCP)) {
- /*
- * If the port is latched off, just continue to
- * monitor for a detach.
- */
- if (usbc_ocp_is_port_latched_off(port))
- return;
- }
-
- /* Check for connection */
- tcpm_get_cc(port, &cc1, &cc2);
-
- /*
- * Transition to AttachWait.SRC when:
- * 1) The SRC.Rd state is detected on either CC1 or CC2 pin or
- * 2) The SRC.Ra state is detected on both the CC1 and CC2 pins.
- *
- * A DRP shall transition to Unattached.SNK within tDRPTransition
- * after dcSRC.DRP ∙ tDRP
- */
- if (cc_is_at_least_one_rd(cc1, cc2) || cc_is_audio_acc(cc1, cc2))
- set_state_tc(port, TC_ATTACH_WAIT_SRC);
- else if (pd_timer_is_expired(port, TC_TIMER_NEXT_ROLE_SWAP) &&
- drp_state[port] != PD_DRP_FORCE_SOURCE &&
- drp_state[port] != PD_DRP_FREEZE)
- set_state_tc(port, TC_UNATTACHED_SNK);
- /*
- * Attempt TCPC auto DRP toggle
- */
- else if (IS_ENABLED(CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE) &&
- drp_state[port] == PD_DRP_TOGGLE_ON &&
- tcpm_auto_toggle_supported(port) && cc_is_open(cc1, cc2))
- set_state_tc(port, TC_DRP_AUTO_TOGGLE);
- else if (IS_ENABLED(CONFIG_USB_PD_TCPC_LOW_POWER) &&
- (drp_state[port] == PD_DRP_FORCE_SOURCE ||
- drp_state[port] == PD_DRP_TOGGLE_OFF))
- set_state_tc(port, TC_LOW_POWER_MODE);
-}
-
-static void tc_unattached_src_exit(const int port)
-{
- pd_timer_disable(port, TC_TIMER_NEXT_ROLE_SWAP);
-}
-
-/**
- * AttachWait.SRC
- *
- * Super State Entry Actions:
- * Vconn Off
- * Place Rp on CC
- * Set power role to SOURCE
- */
-static void tc_attach_wait_src_entry(const int port)
-{
- print_current_state(port);
-
- tc[port].cc_state = PD_CC_UNSET;
-}
-
-static void tc_attach_wait_src_run(const int port)
-{
- enum tcpc_cc_voltage_status cc1, cc2;
- enum pd_cc_states new_cc_state;
-
- /* Check for connection */
- tcpm_get_cc(port, &cc1, &cc2);
-
- if (cc_is_snk_dbg_acc(cc1, cc2) && board_is_dts_port(port)) {
- /*
- * Debug accessory.
- * A debug accessory in a non-DTS port will be
- * recognized by at_least_one_rd as UFP attached.
- */
- new_cc_state = PD_CC_UFP_DEBUG_ACC;
- } else if (cc_is_at_least_one_rd(cc1, cc2)) {
- /* UFP attached */
- new_cc_state = PD_CC_UFP_ATTACHED;
- } else if (cc_is_audio_acc(cc1, cc2)) {
- /* AUDIO Accessory not supported. Just ignore */
- new_cc_state = PD_CC_UFP_AUDIO_ACC;
- } else {
- /* No UFP */
- if (drp_state[port] == PD_DRP_FORCE_SOURCE)
- set_state_tc(port, TC_UNATTACHED_SRC);
- else
- set_state_tc(port, TC_UNATTACHED_SNK);
- return;
- }
-
- /* Debounce the cc state */
- if (new_cc_state != tc[port].cc_state) {
- pd_timer_enable(port, TC_TIMER_CC_DEBOUNCE, PD_T_CC_DEBOUNCE);
- tc[port].cc_state = new_cc_state;
- return;
- }
-
- /* Wait for CC debounce */
- if (!pd_timer_is_expired(port, TC_TIMER_CC_DEBOUNCE))
- return;
-
- /*
- * The port shall transition to Attached.SRC when VBUS is at vSafe0V
- * and the SRC.Rd state is detected on exactly one of the CC1 or CC2
- * pins for at least tCCDebounce.
- *
- * If the port supports Debug Accessory Mode, it shall transition to
- * UnorientedDebugAccessory.SRC when VBUS is at vSafe0V and the SRC.Rd
- * state is detected on both the CC1 and CC2 pins for at least
- * tCCDebounce.
- */
- if (pd_check_vbus_level(port, VBUS_SAFE0V)) {
- if (new_cc_state == PD_CC_UFP_ATTACHED) {
- set_state_tc(port, TC_ATTACHED_SRC);
- return;
- } else if (new_cc_state == PD_CC_UFP_DEBUG_ACC) {
- CPRINTS("C%d: Debug accessory detected", port);
- TC_SET_FLAG(port, TC_FLAGS_TS_DTS_PARTNER);
- set_state_tc(port, TC_ATTACHED_SRC);
- return;
- }
- }
-}
-
-static void tc_attach_wait_src_exit(const int port)
-{
- pd_timer_disable(port, TC_TIMER_CC_DEBOUNCE);
-}
-
-/**
- * Attached.SRC, shared with UnorientedDebugAccessory.SRC
- */
-static void tc_attached_src_entry(const int port)
-{
- enum tcpc_cc_voltage_status cc1, cc2;
-
- print_current_state(port);
-
- pd_timer_disable(port, TC_TIMER_TIMEOUT);
-
- /*
- * Known state of attach is SRC. We need to apply this pull value
- * to make it set in hardware at the correct time but set the common
- * pull here.
- *
- * Both CC1 and CC2 pins shall be independently terminated to
- * pulled up through Rp.
- *
- * Set selected current limit in the hardware.
- */
- typec_select_pull(port, TYPEC_CC_RP);
- typec_set_source_current_limit(port, tc[port].select_current_limit_rp);
-
- if (IS_ENABLED(CONFIG_USB_PE_SM)) {
- if (TC_CHK_FLAG(port, TC_FLAGS_PR_SWAP_IN_PROGRESS)) {
- /* Change role to source */
- tc_set_power_role(port, PD_ROLE_SOURCE);
- tcpm_set_msg_header(port,
- tc[port].power_role,
- tc[port].data_role);
-
- /* Enable VBUS */
- tc_src_power_on(port);
-
- /* Apply Rp */
- typec_update_cc(port);
-
- /*
- * Maintain VCONN supply state, whether ON or OFF, and
- * its data role / usb mux connections. Do not
- * re-enable AutoDischargeDisconnect until the swap is
- * completed and tc_pr_swap_complete is called.
- */
- } else {
- /*
- * Set up CC's, Vconn, and ADD before Vbus, as per
- * Figure 4-24. DRP Initialization and Connection
- * Detection in TCPCI r2 v1.2 specification.
- */
-
- /* Get connector orientation */
- tcpm_get_cc(port, &cc1, &cc2);
- tc[port].polarity = get_src_polarity(cc1, cc2);
- pd_set_polarity(port, tc[port].polarity);
-
- /* Attached.SRC - enable AutoDischargeDisconnect */
- tcpm_enable_auto_discharge_disconnect(port, 1);
-
- /* Apply Rp */
- typec_update_cc(port);
-
- /*
- * Initial data role for sink is DFP
- * This also sets the usb mux
- */
- tc_set_data_role(port, PD_ROLE_DFP);
-
- /*
- * Start sourcing Vconn before Vbus to ensure
- * we are within USB Type-C Spec 1.4 tVconnON
- *
- * UnorientedDebugAccessory.SRC shall not drive Vconn
- */
- if (IS_ENABLED(CONFIG_USBC_VCONN) &&
- !TC_CHK_FLAG(port, TC_FLAGS_TS_DTS_PARTNER))
- set_vconn(port, 1);
-
- /* Enable VBUS */
- if (tc_src_power_on(port)) {
- /* Stop sourcing Vconn if Vbus failed */
- if (IS_ENABLED(CONFIG_USBC_VCONN))
- set_vconn(port, 0);
-
- if (IS_ENABLED(CONFIG_USBC_SS_MUX))
- usb_mux_set(port,
- USB_PD_MUX_NONE,
- USB_SWITCH_DISCONNECT,
- tc[port].polarity);
- }
-
- tc_enable_pd(port, 0);
- pd_timer_enable(port, TC_TIMER_TIMEOUT,
- MAX(PD_POWER_SUPPLY_TURN_ON_DELAY,
- PD_T_VCONN_STABLE));
- }
- } else {
- /*
- * Set up CC's, Vconn, and ADD before Vbus, as per
- * Figure 4-24. DRP Initialization and Connection
- * Detection in TCPCI r2 v1.2 specification.
- */
-
- /* Get connector orientation */
- tcpm_get_cc(port, &cc1, &cc2);
- tc[port].polarity = get_src_polarity(cc1, cc2);
- pd_set_polarity(port, tc[port].polarity);
-
- /* Attached.SRC - enable AutoDischargeDisconnect */
- tcpm_enable_auto_discharge_disconnect(port, 1);
-
- /* Apply Rp */
- typec_update_cc(port);
-
- /*
- * Initial data role for sink is DFP
- * This also sets the usb mux
- */
- tc_set_data_role(port, PD_ROLE_DFP);
-
- /*
- * Start sourcing Vconn before Vbus to ensure
- * we are within USB Type-C Spec 1.4 tVconnON
- *
- * UnorientedDebugAccessory.SRC shall not drive Vconn
- */
- if (IS_ENABLED(CONFIG_USBC_VCONN) &&
- !TC_CHK_FLAG(port, TC_FLAGS_TS_DTS_PARTNER))
- set_vconn(port, 1);
-
- /* Enable VBUS */
- if (tc_src_power_on(port)) {
- /* Stop sourcing Vconn if Vbus failed */
- if (IS_ENABLED(CONFIG_USBC_VCONN))
- set_vconn(port, 0);
-
- if (IS_ENABLED(CONFIG_USBC_SS_MUX))
- usb_mux_set(port, USB_PD_MUX_NONE,
- USB_SWITCH_DISCONNECT, tc[port].polarity);
- }
- }
-
- /* Inform PPC and OCP module that a sink is connected. */
- tc_set_partner_role(port, PPC_DEV_SNK);
-
- /* Initialize type-C supplier to seed the charge manger */
- if (IS_ENABLED(CONFIG_CHARGE_MANAGER))
- typec_set_input_current_limit(port, 0, 0);
-
- /*
- * Only notify if we're not performing a power role swap. During a
- * power role swap, the port partner is not disconnecting/connecting.
- */
- if (!TC_CHK_FLAG(port, TC_FLAGS_PR_SWAP_IN_PROGRESS)) {
- hook_notify(HOOK_USB_PD_CONNECT);
- }
-
- if (TC_CHK_FLAG(port, TC_FLAGS_TS_DTS_PARTNER)) {
- tcpm_debug_accessory(port, 1);
- set_ccd_mode(port, 1);
- }
-
- /*
- * Some TCPCs require time to correctly return CC status after
- * changing the ROLE_CONTROL register. Due to that, we have to ignore
- * CC_NONE state until PD_T_SRC_DISCONNECT delay has elapsed.
- * From the "Universal Serial Bus Type-C Cable and Connector
- * Specification" Release 2.0 paragraph 4.5.2.2.9.2:
- * The Source shall detect the SRC.Open state within tSRCDisconnect,
- * but should detect it as quickly as possible
- */
- pd_timer_enable(port, TC_TIMER_CC_DEBOUNCE, PD_T_SRC_DISCONNECT);
-}
-
-static void tc_attached_src_run(const int port)
-{
- enum tcpc_cc_voltage_status cc1, cc2;
-
- /* Check for connection */
- tcpm_get_cc(port, &cc1, &cc2);
-
- if (polarity_rm_dts(tc[port].polarity))
- cc1 = cc2;
-
- if (cc1 == TYPEC_CC_VOLT_OPEN)
- tc[port].cc_state = PD_CC_NONE;
- else
- tc[port].cc_state = PD_CC_UFP_ATTACHED;
-
- /*
- * When the SRC.Open state is detected on the monitored CC pin, a DRP
- * shall transition to Unattached.SNK unless it strongly prefers the
- * Source role. In that case, it shall transition to TryWait.SNK.
- * This transition to TryWait.SNK is needed so that two devices that
- * both prefer the Source role do not loop endlessly between Source
- * and Sink. In other words, a DRP that would enter Try.SRC from
- * AttachWait.SNK shall enter TryWait.SNK for a Sink detach from
- * Attached.SRC.
- */
- if (tc[port].cc_state == PD_CC_NONE &&
- pd_timer_is_expired(port, TC_TIMER_CC_DEBOUNCE)) {
- bool tryWait;
- enum usb_tc_state new_tc_state = TC_UNATTACHED_SNK;
-
- if (IS_ENABLED(CONFIG_USB_PD_TRY_SRC))
- tryWait = is_try_src_enabled(port) &&
- !TC_CHK_FLAG(port, TC_FLAGS_TS_DTS_PARTNER);
-
- if (drp_state[port] == PD_DRP_FORCE_SOURCE)
- new_tc_state = TC_UNATTACHED_SRC;
- else if(IS_ENABLED(CONFIG_USB_PD_TRY_SRC))
- new_tc_state = tryWait ?
- TC_TRY_WAIT_SNK : TC_UNATTACHED_SNK;
-
- set_state_tc(port, new_tc_state);
- return;
- }
-
-#ifdef CONFIG_USB_PE_SM
- /*
- * Enable PD communications after power supply has fully
- * turned on
- */
- if (pd_timer_is_expired(port, TC_TIMER_TIMEOUT)) {
- tc_enable_pd(port, 1);
- pd_timer_disable(port, TC_TIMER_TIMEOUT);
- }
-
- if (!tc_get_pd_enabled(port))
- return;
-
- /*
- * Handle Hard Reset from Policy Engine
- */
- if (TC_CHK_FLAG(port, TC_FLAGS_HARD_RESET_REQUESTED)) {
- /* Ignoring Hard Resets while the power supply is resetting.*/
- if (!pd_timer_is_disabled(port, TC_TIMER_TIMEOUT) &&
- !pd_timer_is_expired(port, TC_TIMER_TIMEOUT))
- return;
-
- if (tc_perform_src_hard_reset(port))
- TC_CLR_FLAG(port, TC_FLAGS_HARD_RESET_REQUESTED);
-
- return;
- }
-
- /*
- * PD swap commands
- */
- if (tc_get_pd_enabled(port) && prl_is_running(port)) {
- /*
- * Power Role Swap Request
- */
- if (TC_CHK_FLAG(port, TC_FLAGS_REQUEST_PR_SWAP)) {
- /* Clear TC_FLAGS_REQUEST_PR_SWAP on exit */
- return set_state_tc(port, TC_ATTACHED_SNK);
- }
-
- /*
- * Data Role Swap Request
- */
- if (TC_CHK_FLAG(port, TC_FLAGS_REQUEST_DR_SWAP)) {
- TC_CLR_FLAG(port, TC_FLAGS_REQUEST_DR_SWAP);
-
- /* Perform Data Role Swap */
- tc_set_data_role(port,
- tc[port].data_role == PD_ROLE_DFP ?
- PD_ROLE_UFP : PD_ROLE_DFP);
- }
-
- /*
- * Vconn Swap Request
- * UnorientedDebugAccessory.SRC shall not drive Vconn
- */
- if (IS_ENABLED(CONFIG_USBC_VCONN) &&
- !TC_CHK_FLAG(port, TC_FLAGS_TS_DTS_PARTNER)) {
- /*
- * VCONN Swap Request
- */
- if (TC_CHK_FLAG(port, TC_FLAGS_REQUEST_VC_SWAP_ON)) {
- TC_CLR_FLAG(port, TC_FLAGS_REQUEST_VC_SWAP_ON);
- set_vconn(port, 1);
- pe_vconn_swap_complete(port);
- } else if (TC_CHK_FLAG(port,
- TC_FLAGS_REQUEST_VC_SWAP_OFF)) {
- TC_CLR_FLAG(port, TC_FLAGS_REQUEST_VC_SWAP_OFF);
- set_vconn(port, 0);
- pe_vconn_swap_complete(port);
- }
- }
-
- /*
- * A DRP that supports Charge-Through VCONN-Powered USB Devices
- * shall transition to CTUnattached.SNK if the connected device
- * identifies itself as a Charge-Through VCONN-Powered USB
- * Device in its Discover Identity Command response.
- */
-
- /*
- * A DRP that supports Charge-Through VCONN-Powered USB Devices
- * shall transition to CTUnattached.SNK if the connected device
- * identifies itself as a Charge-Through VCONN-Powered USB
- * Device in its Discover Identity Command response.
- *
- * If it detects that it is connected to a VCONN-Powered USB
- * Device, the port may remove VBUS and discharge it to
- * vSafe0V, while continuing to remain in this state with VCONN
- * applied.
- */
- if (!TC_CHK_FLAG(port, TC_FLAGS_TS_DTS_PARTNER) &&
- TC_CHK_FLAG(port, TC_FLAGS_CTVPD_DETECTED)) {
-
- set_state_tc(port, TC_CT_UNATTACHED_SNK);
- }
- }
-#endif
-
- if (TC_CHK_FLAG(port, TC_FLAGS_UPDATE_CURRENT)) {
- TC_CLR_FLAG(port, TC_FLAGS_UPDATE_CURRENT);
- typec_set_source_current_limit(port,
- tc[port].select_current_limit_rp);
- pd_update_contract(port);
-
- /* Update Rp if no contract is present */
- if (!IS_ENABLED(CONFIG_USB_PE_SM) ||
- !pe_is_explicit_contract(port))
- typec_update_cc(port);
- }
-}
-
-static void tc_attached_src_exit(const int port)
-{
- /*
- * A port shall cease to supply VBUS within tVBUSOFF of exiting
- * Attached.SRC.
- */
- tc_src_power_off(port);
-
- if (!TC_CHK_FLAG(port, TC_FLAGS_REQUEST_PR_SWAP)) {
- /* Attached.SRC exit - disable AutoDischargeDisconnect */
- tcpm_enable_auto_discharge_disconnect(port, 0);
-
- /*
- * Disable VCONN if not power role swapping and
- * a CTVPD was not detected
- */
- if (TC_CHK_FLAG(port, TC_FLAGS_VCONN_ON) &&
- !TC_CHK_FLAG(port, TC_FLAGS_CTVPD_DETECTED))
- set_vconn(port, 0);
- }
-
- /* Clear CTVPD detected after checking for Vconn */
- TC_CLR_FLAG(port, TC_FLAGS_CTVPD_DETECTED);
-
- /* Clear PR swap flag after checking for Vconn */
- TC_CLR_FLAG(port, TC_FLAGS_REQUEST_PR_SWAP);
-
- if (TC_CHK_FLAG(port, TC_FLAGS_TS_DTS_PARTNER))
- tcpm_debug_detach(port);
-
- pd_timer_disable(port, TC_TIMER_CC_DEBOUNCE);
- pd_timer_disable(port, TC_TIMER_TIMEOUT);
-}
-
-static __maybe_unused void check_drp_connection(const int port)
-{
- enum pd_drp_next_states next_state;
- enum tcpc_cc_voltage_status cc1, cc2;
-
- TC_CLR_FLAG(port, TC_FLAGS_CHECK_CONNECTION);
-
- /* Check for connection */
- tcpm_get_cc(port, &cc1, &cc2);
-
- tc[port].drp_sink_time = get_time().val;
-
- /* Get the next toggle state */
- next_state = drp_auto_toggle_next_state(&tc[port].drp_sink_time,
- tc[port].power_role, drp_state[port], cc1, cc2,
- tcpm_auto_toggle_supported(port));
-
- if (next_state == DRP_TC_DEFAULT)
- next_state = (PD_ROLE_DEFAULT(port) == PD_ROLE_SOURCE)
- ? DRP_TC_UNATTACHED_SRC
- : DRP_TC_UNATTACHED_SNK;
-
- switch (next_state) {
- case DRP_TC_UNATTACHED_SNK:
- set_state_tc(port, TC_UNATTACHED_SNK);
- break;
- case DRP_TC_ATTACHED_WAIT_SNK:
- set_state_tc(port, TC_ATTACH_WAIT_SNK);
- break;
- case DRP_TC_UNATTACHED_SRC:
- set_state_tc(port, TC_UNATTACHED_SRC);
- break;
- case DRP_TC_ATTACHED_WAIT_SRC:
- set_state_tc(port, TC_ATTACH_WAIT_SRC);
- break;
-
-#ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE
- case DRP_TC_DRP_AUTO_TOGGLE:
- set_state_tc(port, TC_DRP_AUTO_TOGGLE);
- break;
-#endif
-
- default:
- CPRINTS("C%d: Error: DRP next state %d", port, next_state);
- break;
- }
-}
-
-/**
- * DrpAutoToggle
- */
-__maybe_unused static void tc_drp_auto_toggle_entry(const int port)
-{
- if (!IS_ENABLED(CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE))
- assert(0);
-
- print_current_state(port);
-
- /*
- * We need to ensure that we are waiting in the previous Rd or Rp state
- * for the minimum of DRP SNK or SRC so the first toggle cause by
- * transition into auto toggle doesn't violate spec timing.
- */
- pd_timer_enable(port, TC_TIMER_TIMEOUT,
- MAX(PD_T_DRP_SNK, PD_T_DRP_SRC));
-}
-
-__maybe_unused static void tc_drp_auto_toggle_run(const int port)
-{
- if (!IS_ENABLED(CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE))
- assert(0);
-
- /*
- * A timer is running, but if a connection comes in while waiting
- * then allow that to take higher priority.
- */
- if (TC_CHK_FLAG(port, TC_FLAGS_CHECK_CONNECTION))
- check_drp_connection(port);
-
- else if (!pd_timer_is_disabled(port, TC_TIMER_TIMEOUT)) {
- if (!pd_timer_is_expired(port, TC_TIMER_TIMEOUT))
- return;
-
- pd_timer_disable(port, TC_TIMER_TIMEOUT);
- tcpm_enable_drp_toggle(port);
-
- if (IS_ENABLED(CONFIG_USB_PD_TCPC_LOW_POWER)) {
- set_state_tc(port, TC_LOW_POWER_MODE);
- }
- }
-}
-
-__maybe_unused static void tc_drp_auto_toggle_exit(const int port)
-{
- pd_timer_disable(port, TC_TIMER_TIMEOUT);
-}
-
-__maybe_unused static void tc_low_power_mode_entry(const int port)
-{
- if (!IS_ENABLED(CONFIG_USB_PD_TCPC_LOW_POWER))
- assert(0);
-
- print_current_state(port);
- pd_timer_enable(port, TC_TIMER_LOW_POWER_TIME, PD_LPM_DEBOUNCE_US);
-}
-
-__maybe_unused static void tc_low_power_mode_run(const int port)
-{
- if (!IS_ENABLED(CONFIG_USB_PD_TCPC_LOW_POWER))
- assert(0);
-
- if (TC_CHK_FLAG(port, TC_FLAGS_CHECK_CONNECTION)) {
- tc_start_event_loop(port);
- if (pd_timer_is_disabled(port, TC_TIMER_LOW_POWER_EXIT_TIME)) {
- pd_timer_enable(port, TC_TIMER_LOW_POWER_EXIT_TIME,
- PD_LPM_EXIT_DEBOUNCE_US);
- } else if (pd_timer_is_expired(port,
- TC_TIMER_LOW_POWER_EXIT_TIME)) {
- CPRINTS("C%d: Exit Low Power Mode", port);
- check_drp_connection(port);
- }
- return;
- }
-
- if (tc[port].tasks_preventing_lpm)
- pd_timer_enable(port, TC_TIMER_LOW_POWER_TIME,
- PD_LPM_DEBOUNCE_US);
-
- if (pd_timer_is_expired(port, TC_TIMER_LOW_POWER_TIME)) {
- CPRINTS("C%d: TCPC Enter Low Power Mode", port);
- TC_SET_FLAG(port, TC_FLAGS_LPM_ENGAGED);
- TC_SET_FLAG(port, TC_FLAGS_LPM_TRANSITION);
- tcpm_enter_low_power_mode(port);
- TC_CLR_FLAG(port, TC_FLAGS_LPM_TRANSITION);
- tc_pause_event_loop(port);
-
- pd_timer_disable(port, TC_TIMER_LOW_POWER_EXIT_TIME);
- }
-}
-
-__maybe_unused static void tc_low_power_mode_exit(const int port)
-{
- pd_timer_disable(port, TC_TIMER_LOW_POWER_TIME);
- pd_timer_disable(port, TC_TIMER_LOW_POWER_EXIT_TIME);
-}
-
-/**
- * Try.SRC
- *
- * Super State Entry Actions:
- * Vconn Off
- * Place Rp on CC
- * Set power role to SOURCE
- */
-#ifdef CONFIG_USB_PD_TRY_SRC
-static void tc_try_src_entry(const int port)
-{
- print_current_state(port);
-
- tc[port].cc_state = PD_CC_UNSET;
- pd_timer_enable(port, TC_TIMER_TRY_WAIT_DEBOUNCE, PD_T_DRP_TRY);
- pd_timer_enable(port, TC_TIMER_TIMEOUT, PD_T_TRY_TIMEOUT);
-
- /*
- * We are a SNK but would prefer to be a SRC. Set the pull to
- * indicate we want to be a SRC and looking for a SNK.
- *
- * Both CC1 and CC2 pins shall be independently terminated to
- * ground through Rp.
- */
- typec_select_pull(port, TYPEC_CC_RP);
-
- typec_select_src_current_limit_rp(port,
- typec_get_default_current_limit_rp(port));
-
- /* Apply Rp */
- typec_update_cc(port);
-}
-
-static void tc_try_src_run(const int port)
-{
- enum tcpc_cc_voltage_status cc1, cc2;
- enum pd_cc_states new_cc_state;
-
- /* Check for connection */
- tcpm_get_cc(port, &cc1, &cc2);
-
- if ((cc1 == TYPEC_CC_VOLT_RD && cc2 != TYPEC_CC_VOLT_RD) ||
- (cc1 != TYPEC_CC_VOLT_RD && cc2 == TYPEC_CC_VOLT_RD))
- new_cc_state = PD_CC_UFP_ATTACHED;
- else
- new_cc_state = PD_CC_NONE;
-
- /* Debounce the cc state */
- if (new_cc_state != tc[port].cc_state) {
- tc[port].cc_state = new_cc_state;
- pd_timer_enable(port, TC_TIMER_CC_DEBOUNCE, PD_T_CC_DEBOUNCE);
- }
-
- /*
- * The port shall transition to Attached.SRC when the SRC.Rd state is
- * detected on exactly one of the CC1 or CC2 pins for at least
- * tTryCCDebounce.
- */
- if (new_cc_state == PD_CC_UFP_ATTACHED &&
- pd_timer_is_expired(port, TC_TIMER_CC_DEBOUNCE))
- set_state_tc(port, TC_ATTACHED_SRC);
-
- /*
- * The port shall transition to TryWait.SNK after tDRPTry and the
- * SRC.Rd state has not been detected and VBUS is within vSafe0V,
- * or after tTryTimeout and the SRC.Rd state has not been detected.
- */
- if (new_cc_state == PD_CC_NONE) {
- if ((pd_timer_is_expired(port, TC_TIMER_TRY_WAIT_DEBOUNCE) &&
- pd_check_vbus_level(port, VBUS_SAFE0V)) ||
- pd_timer_is_expired(port, TC_TIMER_TIMEOUT)) {
- set_state_tc(port, TC_TRY_WAIT_SNK);
- }
- }
-}
-
-static void tc_try_src_exit(const int port)
-{
- pd_timer_disable(port, TC_TIMER_CC_DEBOUNCE);
- pd_timer_disable(port, TC_TIMER_TIMEOUT);
- pd_timer_disable(port, TC_TIMER_TRY_WAIT_DEBOUNCE);
-}
-
-/**
- * TryWait.SNK
- *
- * Super State Entry Actions:
- * Vconn Off
- * Place Rd on CC
- * Set power role to SINK
- */
-static void tc_try_wait_snk_entry(const int port)
-{
- print_current_state(port);
-
- tc_enable_pd(port, 0);
- tc[port].cc_state = PD_CC_UNSET;
- pd_timer_enable(port, TC_TIMER_TRY_WAIT_DEBOUNCE, PD_T_CC_DEBOUNCE);
-
- /*
- * We were a SNK, tried to be a SRC and it didn't work out. Try to
- * go back to being a SNK. Set the pull to indicate we want to be
- * a SNK and looking for a SRC.
- *
- * Both CC1 and CC2 pins shall be independently terminated to
- * ground through Rd.
- */
- typec_select_pull(port, TYPEC_CC_RD);
-
- /* Apply Rd */
- typec_update_cc(port);
-}
-
-static void tc_try_wait_snk_run(const int port)
-{
- enum tcpc_cc_voltage_status cc1, cc2;
- enum pd_cc_states new_cc_state;
-
- /* Check for connection */
- tcpm_get_cc(port, &cc1, &cc2);
-
- /* We only care about CCs being open */
- if (cc1 == TYPEC_CC_VOLT_OPEN && cc2 == TYPEC_CC_VOLT_OPEN)
- new_cc_state = PD_CC_NONE;
- else
- new_cc_state = PD_CC_UNSET;
-
- /* Debounce the cc state */
- if (new_cc_state != tc[port].cc_state) {
- tc[port].cc_state = new_cc_state;
- pd_timer_enable(port, TC_TIMER_PD_DEBOUNCE, PD_T_PD_DEBOUNCE);
- }
-
- /*
- * The port shall transition to Unattached.SNK when the state of both
- * of the CC1 and CC2 pins is SNK.Open for at least tPDDebounce.
- */
- if (new_cc_state == PD_CC_NONE &&
- pd_timer_is_expired(port, TC_TIMER_PD_DEBOUNCE)) {
- set_state_tc(port, TC_UNATTACHED_SNK);
- return;
- }
-
- /*
- * The port shall transition to Attached.SNK after tCCDebounce if or
- * when VBUS is detected.
- */
- if (pd_timer_is_expired(port, TC_TIMER_TRY_WAIT_DEBOUNCE) &&
- pd_is_vbus_present(port))
- set_state_tc(port, TC_ATTACHED_SNK);
-}
-
-static void tc_try_wait_snk_exit(const int port)
-{
- pd_timer_disable(port, TC_TIMER_PD_DEBOUNCE);
- pd_timer_disable(port, TC_TIMER_TRY_WAIT_DEBOUNCE);
-}
-#endif
-
-/*
- * CTUnattached.SNK
- */
-__maybe_unused static void tc_ct_unattached_snk_entry(int port)
-{
- if (!IS_ENABLED(CONFIG_USB_PE_SM))
- assert(0);
-
- print_current_state(port);
-
- /*
- * Both CC1 and CC2 pins shall be independently terminated to
- * ground through Rd.
- */
- typec_select_pull(port, TYPEC_CC_RD);
- typec_update_cc(port);
-
- tc[port].cc_state = PD_CC_UNSET;
-
- /* Set power role to sink */
- tc_set_power_role(port, PD_ROLE_SINK);
- tcpm_set_msg_header(port, tc[port].power_role, tc[port].data_role);
-
- /*
- * The policy engine is in the disabled state. Disable PD and
- * re-enable it
- */
- tc_enable_pd(port, 0);
-
- pd_timer_enable(port, TC_TIMER_TIMEOUT, PD_POWER_SUPPLY_TURN_ON_DELAY);
-}
-
-__maybe_unused static void tc_ct_unattached_snk_run(int port)
-{
- enum tcpc_cc_voltage_status cc1;
- enum tcpc_cc_voltage_status cc2;
- enum pd_cc_states new_cc_state;
-
- if (!IS_ENABLED(CONFIG_USB_PE_SM))
- assert(0);
-
- if (!pd_timer_is_disabled(port, TC_TIMER_TIMEOUT)) {
- if (pd_timer_is_expired(port, TC_TIMER_TIMEOUT)) {
- tc_enable_pd(port, 1);
- pd_timer_disable(port, TC_TIMER_TIMEOUT);
- } else {
- return;
- }
- }
-
- /* Wait until Protocol Layer is ready */
- if (!prl_is_running(port))
- return;
-
- /*
- * Hard Reset is sent when the PE layer is disabled due to a
- * CTVPD connection.
- */
- if (TC_CHK_FLAG(port, TC_FLAGS_HARD_RESET_REQUESTED)) {
- TC_CLR_FLAG(port, TC_FLAGS_HARD_RESET_REQUESTED);
- /* Nothing to do. Just signal hard reset completion */
- pe_ps_reset_complete(port);
- }
-
- /* Check for connection */
- tcpm_get_cc(port, &cc1, &cc2);
-
- /* We only care about CCs being open */
- if (cc1 == TYPEC_CC_VOLT_OPEN && cc2 == TYPEC_CC_VOLT_OPEN)
- new_cc_state = PD_CC_NONE;
- else
- new_cc_state = PD_CC_UNSET;
-
- /* Debounce the cc state */
- if (new_cc_state != tc[port].cc_state) {
- tc[port].cc_state = new_cc_state;
- pd_timer_enable(port, TC_TIMER_CC_DEBOUNCE, PD_T_VPDDETACH);
- }
-
- /*
- * The port shall transition to Unattached.SNK if the state of
- * the CC pin is SNK.Open for tVPDDetach after VBUS is vSafe0V.
- */
- else if (pd_timer_is_expired(port, TC_TIMER_CC_DEBOUNCE)) {
- if (new_cc_state == PD_CC_NONE &&
- pd_check_vbus_level(port, VBUS_SAFE0V)) {
- set_state_tc(port, TC_UNATTACHED_SNK);
- return;
- }
- }
-
- /*
- * The port shall transition to CTAttached.SNK when VBUS is detected.
- */
- if (pd_is_vbus_present(port))
- set_state_tc(port, TC_CT_ATTACHED_SNK);
-}
-
-__maybe_unused static void tc_ct_unattached_snk_exit(int port)
-{
- pd_timer_disable(port, TC_TIMER_CC_DEBOUNCE);
- pd_timer_disable(port, TC_TIMER_TIMEOUT);
-}
-
-/**
- * CTAttached.SNK
- */
-__maybe_unused static void tc_ct_attached_snk_entry(int port)
-{
- if (!IS_ENABLED(CONFIG_USB_PE_SM))
- assert(0);
-
- print_current_state(port);
-
- /* The port shall reject a VCONN swap request. */
- TC_SET_FLAG(port, TC_FLAGS_REJECT_VCONN_SWAP);
-}
-
-__maybe_unused static void tc_ct_attached_snk_run(int port)
-{
- if (!IS_ENABLED(CONFIG_USB_PE_SM))
- assert(0);
-
- /*
- * Hard Reset is sent when the PE layer is disabled due to a
- * CTVPD connection.
- */
- if (TC_CHK_FLAG(port, TC_FLAGS_HARD_RESET_REQUESTED)) {
- TC_CLR_FLAG(port, TC_FLAGS_HARD_RESET_REQUESTED);
- /* Nothing to do. Just signal hard reset completion */
- pe_ps_reset_complete(port);
- }
-
- /*
- * A port that is not in the process of a USB PD Hard Reset shall
- * transition to CTUnattached.SNK within tSinkDisconnect when VBUS
- * falls below vSinkDisconnect
- */
- if (pd_check_vbus_level(port, VBUS_REMOVED)) {
- set_state_tc(port, TC_CT_UNATTACHED_SNK);
- return;
- }
-
- /*
- * The port shall operate in one of the Sink Power Sub-States
- * and remain within the Sink Power Sub-States, until either VBUS is
- * removed or a USB PD contract is established with the source.
- */
- if (!pe_is_explicit_contract(port))
- sink_power_sub_states(port);
-}
-
-__maybe_unused static void tc_ct_attached_snk_exit(int port)
-{
- if (!IS_ENABLED(CONFIG_USB_PE_SM))
- assert(0);
-
- /* Stop drawing power */
- sink_stop_drawing_current(port);
-
- TC_CLR_FLAG(port, TC_FLAGS_REJECT_VCONN_SWAP);
-}
-
-/**
- * Super State CC_RD
- */
-static void tc_cc_rd_entry(const int port)
-{
- /* Disable VCONN */
- if (IS_ENABLED(CONFIG_USBC_VCONN))
- set_vconn(port, 0);
-
- /* Set power role to sink */
- tc_set_power_role(port, PD_ROLE_SINK);
- tcpm_set_msg_header(port, tc[port].power_role, tc[port].data_role);
-}
-
-
-/**
- * Super State CC_RP
- */
-static void tc_cc_rp_entry(const int port)
-{
- /* Disable VCONN */
- if (IS_ENABLED(CONFIG_USBC_VCONN))
- set_vconn(port, 0);
-
- /* Set power role to source */
- tc_set_power_role(port, PD_ROLE_SOURCE);
- tcpm_set_msg_header(port, tc[port].power_role, tc[port].data_role);
-}
-
-/**
- * Super State CC_OPEN
- */
-static void tc_cc_open_entry(const int port)
-{
- /* Ensure we are not sourcing Vbus */
- tc_src_power_off(port);
-
- /* Disable VCONN */
- set_vconn(port, 0);
-
- /*
- * Ensure we disable discharging before setting CC lines to open.
- * If we were sourcing above, then we already drained Vbus. If partner
- * is sourcing Vbus they will drain Vbus if they are PD-capable. This
- * should only be done if a battery is present as a batteryless
- * device will brown out when AutoDischargeDisconnect is disabled and
- * we do not want this to happen until the set_cc open/open to make
- * sure the TCPC has managed its internal states for disconnecting
- * the only source of power it has.
- */
- if (battery_is_present())
- tcpm_enable_auto_discharge_disconnect(port, 0);
-
- /*
- * We may brown out after applying CC open, so flush console first.
- * Console flush can take a long time, so if we aren't in danger of
- * browning out, don't do it so we can meet certain compliance timing
- * requirements.
- */
- CPRINTS("C%d: Applying CC Open!", port);
- if (!battery_is_present())
- cflush();
-
- /* Remove terminations from CC */
- typec_select_pull(port, TYPEC_CC_OPEN);
- typec_update_cc(port);
-
- tc_set_partner_role(port, PPC_DEV_DISCONNECTED);
- tc_detached(port);
-}
-
-void tc_set_debug_level(enum debug_level debug_level)
-{
-#ifndef CONFIG_USB_PD_DEBUG_LEVEL
- tc_debug_level = debug_level;
-#endif
-}
-
-void tc_usb_firmware_fw_update_limited_run(int port)
-{
- TC_SET_FLAG(port, TC_FLAGS_USB_RETIMER_FW_UPDATE_LTD_RUN);
- task_wake(PD_PORT_TO_TASK_ID(port));
-}
-
-void tc_usb_firmware_fw_update_run(int port)
-{
- TC_SET_FLAG(port, TC_FLAGS_USB_RETIMER_FW_UPDATE_RUN);
- task_wake(PD_PORT_TO_TASK_ID(port));
-}
-
-void tc_run(const int port)
-{
- /*
- * If pd_set_suspend set TC_FLAGS_REQUEST_SUSPEND, go directly to
- * TC_DISABLED.
- */
- if (get_state_tc(port) != TC_DISABLED
- && TC_CHK_FLAG(port, TC_FLAGS_REQUEST_SUSPEND)) {
- /* Invalidate a contract, if there is one */
- if (IS_ENABLED(CONFIG_USB_PE_SM))
- pe_invalidate_explicit_contract(port);
-
- set_state_tc(port, TC_DISABLED);
- }
-
- /* If error recovery has been requested, transition now */
- if (TC_CHK_FLAG(port, TC_FLAGS_REQUEST_ERROR_RECOVERY)) {
- if (IS_ENABLED(CONFIG_USB_PE_SM))
- pe_invalidate_explicit_contract(port);
- set_state_tc(port, TC_ERROR_RECOVERY);
- }
-
- if (IS_ENABLED(CONFIG_USBC_RETIMER_FW_UPDATE)) {
- if (TC_CHK_FLAG(port, TC_FLAGS_USB_RETIMER_FW_UPDATE_RUN)) {
- TC_CLR_FLAG(port, TC_FLAGS_USB_RETIMER_FW_UPDATE_RUN);
- usb_retimer_fw_update_process_op_cb(port);
- }
- }
-
- run_state(port, &tc[port].ctx);
-}
-
-static void pd_chipset_resume(void)
-{
- int i;
-
- for (i = 0; i < CONFIG_USB_PD_PORT_MAX_COUNT; i++) {
- if(IS_ENABLED(CONFIG_USB_PE_SM))
- pd_resume_check_pr_swap_needed(i);
-
- pd_set_dual_role_and_event(i,
- PD_DRP_TOGGLE_ON,
- PD_EVENT_UPDATE_DUAL_ROLE
- | PD_EVENT_POWER_STATE_CHANGE);
- }
-
- CPRINTS("PD:S3->S0");
-}
-DECLARE_HOOK(HOOK_CHIPSET_RESUME, pd_chipset_resume, HOOK_PRIO_DEFAULT);
-
-static void pd_chipset_suspend(void)
-{
- int i;
-
- for (i = 0; i < CONFIG_USB_PD_PORT_MAX_COUNT; i++) {
- pd_set_dual_role_and_event(i,
- pd_get_drp_state_in_suspend(),
- PD_EVENT_UPDATE_DUAL_ROLE
- | PD_EVENT_POWER_STATE_CHANGE);
- }
-
- CPRINTS("PD:S0->S3");
-}
-DECLARE_HOOK(HOOK_CHIPSET_SUSPEND, pd_chipset_suspend, HOOK_PRIO_DEFAULT);
-
-static void pd_chipset_reset(void)
-{
- int i;
-
- if (!IS_ENABLED(CONFIG_USB_PE_SM))
- return;
-
- for (i = 0; i < board_get_usb_pd_port_count(); i++) {
- enum tcpci_msg_type tx;
-
- /* Do not notify the AP of irrelevant past Hard Resets. */
- pd_clear_events(i, PD_STATUS_EVENT_HARD_RESET);
-
- /*
- * Re-set events for SOP and SOP' discovery complete so the
- * kernel knows to consume discovery information for them.
- */
- for (tx = TCPCI_MSG_SOP; tx <= TCPCI_MSG_SOP_PRIME; tx++) {
- if (pd_get_identity_discovery(i, tx) != PD_DISC_NEEDED
- && pd_get_svids_discovery(i, tx) != PD_DISC_NEEDED
- && pd_get_modes_discovery(i, tx) != PD_DISC_NEEDED)
- pd_notify_event(i, tx == TCPCI_MSG_SOP ?
- PD_STATUS_EVENT_SOP_DISC_DONE :
- PD_STATUS_EVENT_SOP_PRIME_DISC_DONE);
- }
-
- /* Exit mode so AP can enter mode again after reset */
- if (IS_ENABLED(CONFIG_USB_PD_REQUIRE_AP_MODE_ENTRY))
- dpm_set_mode_exit_request(i);
- }
-}
-DECLARE_HOOK(HOOK_CHIPSET_RESET, pd_chipset_reset, HOOK_PRIO_DEFAULT);
-
-static void pd_chipset_startup(void)
-{
- int i;
-
- for (i = 0; i < CONFIG_USB_PD_PORT_MAX_COUNT; i++) {
- TC_SET_FLAG(i, TC_FLAGS_UPDATE_USB_MUX);
- pd_set_dual_role_and_event(i,
- pd_get_drp_state_in_suspend(),
- PD_EVENT_UPDATE_DUAL_ROLE
- | PD_EVENT_POWER_STATE_CHANGE);
- /*
- * Request port discovery to restore any
- * alt modes.
- * TODO(b/158042116): Do not start port discovery if there
- * is an existing connection.
- */
- if (IS_ENABLED(CONFIG_USB_PE_SM))
- pd_dpm_request(i, DPM_REQUEST_PORT_DISCOVERY);
- }
-
- CPRINTS("PD:S5->S3");
-}
-DECLARE_HOOK(HOOK_CHIPSET_STARTUP, pd_chipset_startup, HOOK_PRIO_DEFAULT);
-
-static void pd_chipset_shutdown(void)
-{
- int i;
-
- for (i = 0; i < CONFIG_USB_PD_PORT_MAX_COUNT; i++) {
- TC_SET_FLAG(i, TC_FLAGS_UPDATE_USB_MUX);
- pd_set_dual_role_and_event(i,
- PD_DRP_FORCE_SINK,
- PD_EVENT_UPDATE_DUAL_ROLE
- | PD_EVENT_POWER_STATE_CHANGE);
- }
-
- CPRINTS("PD:S3->S5");
-}
-DECLARE_HOOK(HOOK_CHIPSET_SHUTDOWN, pd_chipset_shutdown, HOOK_PRIO_DEFAULT);
-
-static void pd_set_power_change(void)
-{
- int i;
-
- for (i = 0; i < CONFIG_USB_PD_PORT_MAX_COUNT; i++) {
- task_set_event(PD_PORT_TO_TASK_ID(i),
- PD_EVENT_POWER_STATE_CHANGE);
- }
-}
-DECLARE_DEFERRED(pd_set_power_change);
-
-static void pd_chipset_hard_off(void)
-{
- /*
- * Wait 1 second to check our Vconn sourcing status, as the power rails
- * which were supporting it may take some time to change after entering
- * G3.
- */
- hook_call_deferred(&pd_set_power_change_data, 1 * SECOND);
-}
-DECLARE_HOOK(HOOK_CHIPSET_HARD_OFF, pd_chipset_hard_off, HOOK_PRIO_DEFAULT);
-
-/*
- * Type-C State Hierarchy (Sub-States are listed inside the boxes)
- *
- * |TC_CC_RD --------------| |TC_CC_RP ------------------------|
- * | | | |
- * | TC_UNATTACHED_SNK | | TC_UNATTACHED_SRC |
- * | TC_ATTACH_WAIT_SNK | | TC_ATTACH_WAIT_SRC |
- * | TC_TRY_WAIT_SNK | | TC_TRY_SRC |
- * |-----------------------| |---------------------------------|
- *
- * |TC_CC_OPEN -----------|
- * | |
- * | TC_DISABLED |
- * | TC_ERROR_RECOVERY |
- * |----------------------|
- *
- * TC_ATTACHED_SNK TC_ATTACHED_SRC TC_DRP_AUTO_TOGGLE TC_LOW_POWER_MODE
- *
- */
-static __const_data const struct usb_state tc_states[] = {
- /* Super States */
- [TC_CC_OPEN] = {
- .entry = tc_cc_open_entry,
- },
- [TC_CC_RD] = {
- .entry = tc_cc_rd_entry,
- },
- [TC_CC_RP] = {
- .entry = tc_cc_rp_entry,
- },
- /* Normal States */
- [TC_DISABLED] = {
- .entry = tc_disabled_entry,
- .run = tc_disabled_run,
- .exit = tc_disabled_exit,
- .parent = &tc_states[TC_CC_OPEN],
- },
- [TC_ERROR_RECOVERY] = {
- .entry = tc_error_recovery_entry,
- .run = tc_error_recovery_run,
- .exit = tc_error_recovery_exit,
- .parent = &tc_states[TC_CC_OPEN],
- },
- [TC_UNATTACHED_SNK] = {
- .entry = tc_unattached_snk_entry,
- .run = tc_unattached_snk_run,
- .exit = tc_unattached_snk_exit,
- .parent = &tc_states[TC_CC_RD],
- },
- [TC_ATTACH_WAIT_SNK] = {
- .entry = tc_attach_wait_snk_entry,
- .run = tc_attach_wait_snk_run,
- .exit = tc_attach_wait_snk_exit,
- .parent = &tc_states[TC_CC_RD],
- },
- [TC_ATTACHED_SNK] = {
- .entry = tc_attached_snk_entry,
- .run = tc_attached_snk_run,
- .exit = tc_attached_snk_exit,
- },
- [TC_UNATTACHED_SRC] = {
- .entry = tc_unattached_src_entry,
- .run = tc_unattached_src_run,
- .exit = tc_unattached_src_exit,
- .parent = &tc_states[TC_CC_RP],
- },
- [TC_ATTACH_WAIT_SRC] = {
- .entry = tc_attach_wait_src_entry,
- .run = tc_attach_wait_src_run,
- .exit = tc_attach_wait_src_exit,
- .parent = &tc_states[TC_CC_RP],
- },
- [TC_ATTACHED_SRC] = {
- .entry = tc_attached_src_entry,
- .run = tc_attached_src_run,
- .exit = tc_attached_src_exit,
- },
-#ifdef CONFIG_USB_PD_TRY_SRC
- [TC_TRY_SRC] = {
- .entry = tc_try_src_entry,
- .run = tc_try_src_run,
- .exit = tc_try_src_exit,
- .parent = &tc_states[TC_CC_RP],
- },
- [TC_TRY_WAIT_SNK] = {
- .entry = tc_try_wait_snk_entry,
- .run = tc_try_wait_snk_run,
- .exit = tc_try_wait_snk_exit,
- .parent = &tc_states[TC_CC_RD],
- },
-#endif /* CONFIG_USB_PD_TRY_SRC */
-#ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE
- [TC_DRP_AUTO_TOGGLE] = {
- .entry = tc_drp_auto_toggle_entry,
- .run = tc_drp_auto_toggle_run,
- .exit = tc_drp_auto_toggle_exit,
- },
-#endif /* CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE */
-#ifdef CONFIG_USB_PD_TCPC_LOW_POWER
- [TC_LOW_POWER_MODE] = {
- .entry = tc_low_power_mode_entry,
- .run = tc_low_power_mode_run,
- .exit = tc_low_power_mode_exit,
- },
-#endif /* CONFIG_USB_PD_TCPC_LOW_POWER */
-#ifdef CONFIG_USB_PE_SM
- [TC_CT_UNATTACHED_SNK] = {
- .entry = tc_ct_unattached_snk_entry,
- .run = tc_ct_unattached_snk_run,
- .exit = tc_ct_unattached_snk_exit,
- },
- [TC_CT_ATTACHED_SNK] = {
- .entry = tc_ct_attached_snk_entry,
- .run = tc_ct_attached_snk_run,
- .exit = tc_ct_attached_snk_exit,
- },
-#endif
-};
-
-#if defined(TEST_BUILD) && defined(USB_PD_DEBUG_LABELS)
-const struct test_sm_data test_tc_sm_data[] = {
- {
- .base = tc_states,
- .size = ARRAY_SIZE(tc_states),
- .names = tc_state_names,
- .names_size = ARRAY_SIZE(tc_state_names),
- },
-};
-const int test_tc_sm_data_size = ARRAY_SIZE(test_tc_sm_data);
-#endif
diff --git a/common/usbc/usb_tc_vpd_sm.c b/common/usbc/usb_tc_vpd_sm.c
deleted file mode 100644
index f230d15003..0000000000
--- a/common/usbc/usb_tc_vpd_sm.c
+++ /dev/null
@@ -1,430 +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 "console.h"
-#include "system.h"
-#include "task.h"
-#include "tcpm/tcpm.h"
-#include "usb_pd.h"
-#include "usb_tc_sm.h"
-#include "usb_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)
-
-/**
- * This is the Type-C Port object that contains information needed to
- * implement a VCONN Powered Device.
- */
-static struct type_c {
- /* state machine context */
- struct sm_ctx ctx;
- /* Higher-level power deliver state machines are enabled if true. */
- uint8_t pd_enable;
- /* port flags, see TC_FLAGS_* */
- uint32_t flags;
- /* Time a port shall wait before it can determine it is attached */
- uint64_t cc_debounce;
- /* VPD host port cc state */
- enum pd_cc_states host_cc_state;
- uint8_t ct_cc;
-} tc[CONFIG_USB_PD_PORT_MAX_COUNT];
-
-/* List of all TypeC-level states */
-enum usb_tc_state {
- /* Normal States */
- TC_DISABLED,
- TC_UNATTACHED_SNK,
- TC_ATTACH_WAIT_SNK,
- TC_ATTACHED_SNK,
- /* Super States */
- TC_VBUS_CC_ISO,
- TC_HOST_RARD,
- TC_HOST_OPEN,
-};
-/* Forward declare the full list of states. This is indexed by usb_tc_state */
-static const struct usb_state tc_states[];
-
-/* List of human readable state names for console debugging */
-__maybe_unused static const char * const tc_state_names[] = {
-#ifdef CONFIG_COMMON_RUNTIME
- [TC_DISABLED] = "Disabled",
- [TC_UNATTACHED_SNK] = "Unattached.SNK",
- [TC_ATTACH_WAIT_SNK] = "AttachWait.SNK",
- [TC_ATTACHED_SNK] = "Attached.SNK",
-#endif
-};
-
-/* Forward declare private, common functions */
-static void set_state_tc(const int port, enum usb_tc_state new_state);
-
-/*
- * TCPC CC/Rp management
- *
- * Stub for linking purposes.
- * This is not supported for vpd, it uses a different mechanism to update
- * cc values.
- */
-void typec_select_pull(int port, enum tcpc_cc_pull pull)
-{
-}
-void typec_select_src_current_limit_rp(int port, enum tcpc_rp_value rp)
-{
-}
-void typec_select_src_collision_rp(int port, enum tcpc_rp_value rp)
-{
-}
-int typec_update_cc(int port)
-{
- return EC_SUCCESS;
-}
-
-/* Public TypeC functions */
-
-void tc_state_init(int port)
-{
- int res = 0;
-
- res = tcpm_init(port);
-
- CPRINTS("C%d: init %s", port, res ? "failed" : "ready");
-
- /* Disable TCPC RX until connection is established */
- tcpm_set_rx_enable(port, 0);
-
- set_state_tc(port, res ? TC_DISABLED : TC_UNATTACHED_SNK);
-
- /* Disable pd state machines */
- tc[port].pd_enable = 0;
- tc[port].flags = 0;
-}
-
-enum pd_power_role pd_get_power_role(int port)
-{
- /* Vconn power device is always the sink */
- return PD_ROLE_SINK;
-}
-
-enum pd_cable_plug tc_get_cable_plug(int port)
-{
- /* Vconn power device is always the cable */
- return PD_PLUG_FROM_CABLE;
-}
-
-enum pd_data_role pd_get_data_role(int port)
-{
- /* Vconn power device doesn't have a data role, but UFP match SNK */
- return PD_ROLE_UFP;
-}
-
-/* Note tc_set_power_role and tc_set_data_role are unimplemented */
-
-uint8_t tc_get_polarity(int port)
-{
- /* Does not track polarity yet */
- return 0;
-}
-
-uint8_t tc_get_pd_enabled(int port)
-{
- return tc[port].pd_enable;
-}
-
-void tc_event_check(int port, int evt)
-{
- /* Do Nothing */
-}
-
-/*
- * Private Functions
- */
-
-/* Set the TypeC state machine to a new state. */
-static void set_state_tc(const int port, const enum usb_tc_state new_state)
-{
- set_state(port, &tc[port].ctx, &tc_states[new_state]);
-}
-
-/* Get the current TypeC state. */
-test_export_static enum usb_tc_state get_state_tc(const int port)
-{
- return tc[port].ctx.current - &tc_states[0];
-}
-
-test_mockable_static void print_current_state(const int port)
-{
- CPRINTS("C%d: %s", port, tc_state_names[get_state_tc(port)]);
-}
-
-/**
- * Disabled
- *
- * Super State Entries:
- * Enable mcu communication
- * Remove the terminations from Host CC
- */
-static void tc_disabled_entry(const int port)
-{
- print_current_state(port);
-}
-
-static void tc_disabled_run(const int port)
-{
- task_wait_event(-1);
-}
-
-void pd_set_suspend(int port, int suspend)
-{
- /*
- * This shouldn't happen. If it does, we need to send an event to the
- * PD task to put the SM into the disabled state. It is not safe to
- * directly set_state here since this may be in another task.
- */
- assert(false);
-}
-
-static void tc_disabled_exit(const int port)
-{
- if (!IS_ENABLED(CONFIG_USB_PD_TCPC)) {
- if (tcpm_init(port) != 0) {
- CPRINTS("C%d: restart failed!", port);
- return;
- }
- }
-
- CPRINTS("C%d: resumed!", port);
-}
-
-/**
- * Unattached.SNK
- *
- * Super State Entry:
- * Enable mcu communication
- * Place Ra on VCONN and Rd on Host CC
- */
-static void tc_unattached_snk_entry(const int port)
-{
- print_current_state(port);
-}
-
-static void tc_unattached_snk_run(const 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_tc(port, TC_ATTACH_WAIT_SNK);
-}
-
-/**
- * AttachedWait.SNK
- *
- * Super State Entry:
- * Enable mcu communication
- * Place Ra on VCONN and Rd on Host CC
- */
-static void tc_attach_wait_snk_entry(const int port)
-{
- print_current_state(port);
-
- /* Forces an initial debounce in run function */
- tc[port].host_cc_state = -1;
-}
-
-static void tc_attach_wait_snk_run(const 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;
- }
-
- /* Wait for Host CC debounce */
- if (get_time().val < tc[port].cc_debounce)
- return;
-
- /*
- * 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_tc(port, TC_ATTACHED_SNK);
- else if (tc[port].host_cc_state == PD_CC_NONE)
- set_state_tc(port, TC_UNATTACHED_SNK);
-}
-
-/**
- * Attached.SNK
- */
-static void tc_attached_snk_entry(const int port)
-{
- print_current_state(port);
-
- /* Enable PD */
- tc[port].pd_enable = 1;
- pd_set_polarity(port, 0);
-}
-
-static void tc_attached_snk_run(const int port)
-{
- /* Has host vbus and vconn been removed */
- if (!vpd_is_host_vbus_present() && !vpd_is_vconn_present()) {
- set_state_tc(port, TC_UNATTACHED_SNK);
- return;
- }
-
- 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;
- }
- }
-}
-
-static void tc_attached_snk_exit(const int port)
-{
- /* Disable PD */
- tc[port].pd_enable = 0;
- tc[port].flags &= ~TC_FLAGS_VCONN_ON;
-}
-
-/**
- * Super State HOST_RARD
- */
-static void tc_host_rard_entry(const int port)
-{
- /* Place Ra on VCONN and Rd on Host CC */
- vpd_host_set_pull(TYPEC_CC_RA_RD, 0);
-}
-
-/**
- * Super State HOST_OPEN
- */
-static void tc_host_open_entry(const int port)
-{
- /* Remove the terminations from Host CC */
- vpd_host_set_pull(TYPEC_CC_OPEN, 0);
-}
-
-/**
- * Super State VBUS_CC_ISO
- */
-static void tc_vbus_cc_iso_entry(const int port)
-{
- /* Enable mcu communication and cc */
- vpd_mcu_cc_en(1);
-}
-
-void tc_run(const int port)
-{
- run_state(port, &tc[port].ctx);
-}
-
-/*
- * Type-C State Hierarchy (Sub-States are listed inside the boxes)
- *
- * | TC_VBUS_CC_ISO ----------------------------------------|
- * | |
- * | | TC_HOST_RARD -----------| | TC_HOST_OPEN ---------| |
- * | | | | | |
- * | | TC_UNATTACHED_SNK | | TC_DISABLED | |
- * | | TC_ATTACH_WAIT_SNK | |-----------------------| |
- * | |-------------------------| |
- * |--------------------------------------------------------|
- *
- * TC_ATTACHED_SNK
- */
-static const struct usb_state tc_states[] = {
- /* Super States */
- [TC_VBUS_CC_ISO] = {
- .entry = tc_vbus_cc_iso_entry,
- },
- [TC_HOST_RARD] = {
- .entry = tc_host_rard_entry,
- .parent = &tc_states[TC_VBUS_CC_ISO],
- },
- [TC_HOST_OPEN] = {
- .entry = tc_host_open_entry,
- .parent = &tc_states[TC_VBUS_CC_ISO],
- },
- /* Normal States */
- [TC_DISABLED] = {
- .entry = tc_disabled_entry,
- .run = tc_disabled_run,
- .exit = tc_disabled_exit,
- .parent = &tc_states[TC_HOST_OPEN],
- },
- [TC_UNATTACHED_SNK] = {
- .entry = tc_unattached_snk_entry,
- .run = tc_unattached_snk_run,
- .parent = &tc_states[TC_HOST_RARD],
- },
- [TC_ATTACH_WAIT_SNK] = {
- .entry = tc_attach_wait_snk_entry,
- .run = tc_attach_wait_snk_run,
- .parent = &tc_states[TC_HOST_RARD],
- },
- [TC_ATTACHED_SNK] = {
- .entry = tc_attached_snk_entry,
- .run = tc_attached_snk_run,
- .exit = tc_attached_snk_exit,
- },
-};
-
-#ifdef TEST_BUILD
-const struct test_sm_data test_tc_sm_data[] = {
- {
- .base = tc_states,
- .size = ARRAY_SIZE(tc_states),
- .names = tc_state_names,
- .names_size = ARRAY_SIZE(tc_state_names),
- },
-};
-const int test_tc_sm_data_size = ARRAY_SIZE(test_tc_sm_data);
-#endif
diff --git a/common/usbc/usbc_pd_policy.c b/common/usbc/usbc_pd_policy.c
deleted file mode 100644
index 6a06d4014f..0000000000
--- a/common/usbc/usbc_pd_policy.c
+++ /dev/null
@@ -1,48 +0,0 @@
-/* Copyright 2021 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 "console.h"
-#include "ec_commands.h"
-#include "usb_pe_sm.h"
-#include "usb_tc_sm.h"
-
-/*
- * TODO(b:159715784): Implement a more robust solution
- * to managing PD Policies.
- */
-
-/*
- * Default Port Discovery DR Swap Policy.
- *
- * 1) If dr_swap_to_dfp_flag == true and port data role is UFP,
- * transition to pe_drs_send_swap
- */
-__overridable bool port_discovery_dr_swap_policy(int port,
- enum pd_data_role dr, bool dr_swap_flag)
-{
- if (dr_swap_flag && dr == PD_ROLE_UFP)
- return true;
-
- /* Do not perform a DR swap */
- return false;
-}
-
-/*
- * Default Port Discovery VCONN Swap Policy.
- *
- * 1) If vconn_swap_to_on_flag == true, and vconn is currently off,
- * 2) Sourcing VCONN is possible
- * then transition to pe_vcs_send_swap
- */
-__overridable bool port_discovery_vconn_swap_policy(int port,
- bool vconn_swap_flag)
-{
- if (IS_ENABLED(CONFIG_USBC_VCONN) && vconn_swap_flag &&
- !tc_is_vconn_src(port) && tc_check_vconn_swap(port))
- return true;
-
- /* Do not perform a VCONN swap */
- return false;
-}
diff --git a/common/usbc/usbc_task.c b/common/usbc/usbc_task.c
deleted file mode 100644
index 09be36cd5e..0000000000
--- a/common/usbc/usbc_task.c
+++ /dev/null
@@ -1,182 +0,0 @@
-/* Copyright 2019 The Chromium OS Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "battery.h"
-#include "battery_smart.h"
-#include "board.h"
-#include "charge_manager.h"
-#include "charge_state.h"
-#include "chipset.h"
-#include "common.h"
-#include "console.h"
-#include "cros_version.h"
-#include "ec_commands.h"
-#include "gpio.h"
-#include "hooks.h"
-#include "host_command.h"
-#include "registers.h"
-#include "system.h"
-#include "task.h"
-#include "timer.h"
-#include "util.h"
-#include "usb_charge.h"
-#include "usb_mux.h"
-#include "usb_pd.h"
-#include "usb_pd_timer.h"
-#include "usb_prl_sm.h"
-#include "tcpm/tcpm.h"
-#include "usb_pe_sm.h"
-#include "usb_prl_sm.h"
-#include "usb_sm.h"
-#include "usb_tc_sm.h"
-#include "usbc_ppc.h"
-
-#define USBC_EVENT_TIMEOUT (5 * MSEC)
-#define USBC_MIN_EVENT_TIMEOUT (1 * MSEC)
-
-#define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args)
-#define CPRINTS(format, args...) cprints(CC_USBPD, format, ## args)
-
-/*
- * If CONFIG_ASSERT_CCD_MODE_ON_DTS_CONNECT is not defined then
- * _GPIO_CCD_MODE_ODL is not needed. Declare as extern so IS_ENABLED will work.
- */
-#ifndef CONFIG_ASSERT_CCD_MODE_ON_DTS_CONNECT
-extern int _GPIO_CCD_MODE_ODL;
-#else
-#define _GPIO_CCD_MODE_ODL GPIO_CCD_MODE_ODL
-#endif /* CONFIG_ASSERT_CCD_MODE_ON_DTS_CONNECT */
-
-static uint8_t paused[CONFIG_USB_PD_PORT_MAX_COUNT];
-
-void tc_pause_event_loop(int port)
-{
- paused[port] = 1;
-}
-
-bool tc_event_loop_is_paused(int port)
-{
- return paused[port];
-}
-
-void tc_start_event_loop(int port)
-{
- /*
- * Only generate TASK_EVENT_WAKE event if state
- * machine is transitioning to un-paused
- */
- if (paused[port]) {
- paused[port] = 0;
- task_set_event(PD_PORT_TO_TASK_ID(port), TASK_EVENT_WAKE);
- }
-}
-
-static void pd_task_init(int port)
-{
- if (IS_ENABLED(CONFIG_USB_TYPEC_SM))
- tc_state_init(port);
- paused[port] = 0;
-
- /*
- * Since most boards configure the TCPC interrupt as edge
- * and it is possible that the interrupt line was asserted between init
- * and calling set_state, we need to process any pending interrupts now.
- * Otherwise future interrupts will never fire because another edge
- * never happens. Note this needs to happen after set_state() is called.
- */
- if (IS_ENABLED(CONFIG_HAS_TASK_PD_INT))
- schedule_deferred_pd_interrupt(port);
-
- /*
- * GPIO_CCD_MODE_ODL must be initialized with GPIO_ODR_HIGH
- * when CONFIG_ASSERT_CCD_MODE_ON_DTS_CONNECT is enabled
- */
- if (IS_ENABLED(CONFIG_ASSERT_CCD_MODE_ON_DTS_CONNECT))
- ASSERT(gpio_get_default_flags(_GPIO_CCD_MODE_ODL) &
- GPIO_ODR_HIGH);
-}
-
-static int pd_task_timeout(int port)
-{
- int timeout;
-
- if (paused[port])
- timeout = -1;
- else {
- timeout = pd_timer_next_expiration(port);
- if (timeout < 0 || timeout > USBC_EVENT_TIMEOUT)
- timeout = USBC_EVENT_TIMEOUT;
- else if (timeout < USBC_MIN_EVENT_TIMEOUT)
- timeout = USBC_MIN_EVENT_TIMEOUT;
- }
- return timeout;
-}
-
-static bool pd_task_loop(int port)
-{
- /* wait for next event/packet or timeout expiration */
- const uint32_t evt = task_wait_event(pd_task_timeout(port));
-
- /* Manage expired PD Timers on timeouts */
- if (evt & TASK_EVENT_TIMER)
- pd_timer_manage_expired(port);
-
- /*
- * Re-use TASK_EVENT_RESET_DONE in tests to restart the USB task
- * if this code is running in a unit test.
- */
- if (IS_ENABLED(TEST_BUILD) && (evt & TASK_EVENT_RESET_DONE))
- return false;
-
- /* handle events that affect the state machine as a whole */
- if (IS_ENABLED(CONFIG_USB_TYPEC_SM))
- tc_event_check(port, evt);
-
- /*
- * run port controller task to check CC and/or read incoming
- * messages
- */
- if (IS_ENABLED(CONFIG_USB_PD_TCPC))
- tcpc_run(port, evt);
-
- /* Run policy engine state machine */
- if (IS_ENABLED(CONFIG_USB_PE_SM))
- pe_run(port, evt, tc_get_pd_enabled(port));
-
- /* Run protocol state machine */
- if (IS_ENABLED(CONFIG_USB_PRL_SM) || IS_ENABLED(CONFIG_TEST_USB_PE_SM))
- prl_run(port, evt, tc_get_pd_enabled(port));
-
- /* Run TypeC state machine */
- if (IS_ENABLED(CONFIG_USB_TYPEC_SM))
- tc_run(port);
-
- return true;
-}
-
-void pd_task(void *u)
-{
- int port = TASK_ID_TO_PD_PORT(task_get_current());
-
- /*
- * If port does not exist, return
- */
- if (port >= board_get_usb_pd_port_count())
- return;
-
- while (1) {
- pd_timer_init(port);
- pd_task_init(port);
-
- /* As long as pd_task_loop returns true, keep running the loop.
- * pd_task_loop returns false when the code needs to re-init
- * the task, so once the code breaks out of the inner while
- * loop, the re-init code at the top of the outer while loop
- * will run.
- */
- while (pd_task_loop(port))
- continue;
- }
-}