summaryrefslogtreecommitdiff
path: root/common/usbc/usb_pd_timer.c
diff options
context:
space:
mode:
authorDenis Brockus <dbrockus@google.com>2021-02-17 12:18:28 -0700
committerCommit Bot <commit-bot@chromium.org>2021-03-01 22:49:49 +0000
commit2bdefef51a36f80c56f95278bffba743c501f9a8 (patch)
tree81f6026831e8b46f94758e808925bcebda06e495 /common/usbc/usb_pd_timer.c
parent1aa5f1d725aa778834ef6d92e70c5a479020dc86 (diff)
downloadchrome-ec-2bdefef51a36f80c56f95278bffba743c501f9a8.tar.gz
TCPMv2: PD Timers - Base Timer framework
Add in the basic framework. There are optimizations for using less timers but want to get the basics working before I invest more time in this. BUG=b:178029034 BRANCH=none TEST=make-runtests Signed-off-by: Denis Brockus <dbrockus@google.com> Change-Id: Icf93e3074b02cc3e0f7ee62e026b0d8ba10c7709 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2707804 Reviewed-by: Denis Brockus <dbrockus@chromium.org> Commit-Queue: Denis Brockus <dbrockus@chromium.org> Tested-by: Denis Brockus <dbrockus@chromium.org>
Diffstat (limited to 'common/usbc/usb_pd_timer.c')
-rw-r--r--common/usbc/usb_pd_timer.c238
1 files changed, 238 insertions, 0 deletions
diff --git a/common/usbc/usb_pd_timer.c b/common/usbc/usb_pd_timer.c
new file mode 100644
index 0000000000..0bbf06f0e4
--- /dev/null
+++ b/common/usbc/usb_pd_timer.c
@@ -0,0 +1,238 @@
+/* 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"
+
+#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);
+}
+
+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)",
+ timer, pd_timer_names[timer], (uint32_t)delta);
+ } else {
+ ccprints("[%2d] Inactive: %s",
+ timer, pd_timer_names[timer]);
+ }
+ }
+}
+#endif /* CONFIG_CMD_PD_TIMER */