summaryrefslogtreecommitdiff
path: root/common/usbc
diff options
context:
space:
mode:
authorJack Rosenthal <jrosenth@chromium.org>2021-11-04 12:11:58 -0600
committerCommit Bot <commit-bot@chromium.org>2021-11-05 04:22:34 +0000
commit252457d4b21f46889eebad61d4c0a65331919cec (patch)
tree01856c4d31d710b20e85a74c8d7b5836e35c3b98 /common/usbc
parent08f5a1e6fc2c9467230444ac9b582dcf4d9f0068 (diff)
downloadchrome-ec-stabilize-14333.B-ish.tar.gz
In the interest of making long-term branch maintenance incur as little technical debt on us as possible, we should not maintain any files on the branch we are not actually using. This has the added effect of making it extremely clear when merging CLs from the main branch when changes have the possibility to affect us. The follow-on CL adds a convenience script to actually pull updates from the main branch and generate a CL for the update. BUG=b:204206272 BRANCH=ish TEST=make BOARD=arcada_ish && make BOARD=drallion_ish Signed-off-by: Jack Rosenthal <jrosenth@chromium.org> Change-Id: I17e4694c38219b5a0823e0a3e55a28d1348f4b18 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3262038 Reviewed-by: Jett Rink <jettrink@chromium.org> Reviewed-by: Tom Hughes <tomhughes@chromium.org>
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;
- }
-}