summaryrefslogtreecommitdiff
path: root/common/usbc
diff options
context:
space:
mode:
Diffstat (limited to 'common/usbc')
-rw-r--r--common/usbc/build.mk2
-rw-r--r--common/usbc/usb_retimer_fw_update.c159
-rw-r--r--common/usbc/usb_tc_drp_acc_trysrc_sm.c36
3 files changed, 196 insertions, 1 deletions
diff --git a/common/usbc/build.mk b/common/usbc/build.mk
index c39d1a57e6..00f5d87867 100644
--- a/common/usbc/build.mk
+++ b/common/usbc/build.mk
@@ -36,6 +36,8 @@ 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
endif # CONFIG_USB_PD_TCPMV2
# For testing
diff --git a/common/usbc/usb_retimer_fw_update.c b/common/usbc/usb_retimer_fw_update.c
new file mode 100644
index 0000000000..7ae833b8c9
--- /dev/null
+++ b/common/usbc/usb_retimer_fw_update.c
@@ -0,0 +1,159 @@
+/* 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 "atomic.h"
+#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.
+ *
+ */
+
+/* Track current port AP requested to update retimer firmware */
+static int cur_port;
+static int last_op; /* Operation received from AP via ACPI_WRITE */
+/* MUX value returned to ACPI_READ */
+static int last_mux_result = USB_RETIMER_FW_UPDATE_INVALID_MUX;
+
+__overridable int usb_retimer_fw_update_query_port(void)
+{
+ return 0;
+}
+
+int usb_retimer_fw_update_get_result(void)
+{
+ int result = 0;
+
+ switch (last_op) {
+ case USB_RETIMER_FW_UPDATE_SUSPEND_PD:
+ case USB_RETIMER_FW_UPDATE_RESUME_PD:
+ result = pd_is_port_enabled(cur_port);
+ break;
+ case USB_RETIMER_FW_UPDATE_QUERY_PORT:
+ result = usb_retimer_fw_update_query_port();
+ 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_mux_result;
+ break;
+ default:
+ break;
+ }
+
+ return result;
+}
+
+void usb_retimer_fw_update_process_op_cb(int port)
+{
+ switch (last_op) {
+ case USB_RETIMER_FW_UPDATE_SUSPEND_PD:
+ pd_set_suspend(port, 1);
+ break;
+ case USB_RETIMER_FW_UPDATE_RESUME_PD:
+ pd_set_suspend(port, 0);
+ break;
+ case USB_RETIMER_FW_UPDATE_GET_MUX:
+ last_mux_result = 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_mux_result = usb_mux_get(port);
+ break;
+ case USB_RETIMER_FW_UPDATE_SET_SAFE:
+ usb_mux_set_safe_mode(port);
+ last_mux_result = 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_mux_result = 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_mux_result = 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_mux_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_mux_result = USB_RETIMER_FW_UPDATE_ERR;
+ } else {
+ last_mux_result = USB_RETIMER_FW_UPDATE_INVALID_MUX;
+ tc_usb_firmware_fw_update_limited_run(port);
+ }
+ break;
+ default:
+ break;
+ }
+}
diff --git a/common/usbc/usb_tc_drp_acc_trysrc_sm.c b/common/usbc/usb_tc_drp_acc_trysrc_sm.c
index 9ddce4e2f5..1d6b9b995f 100644
--- a/common/usbc/usb_tc_drp_acc_trysrc_sm.c
+++ b/common/usbc/usb_tc_drp_acc_trysrc_sm.c
@@ -120,9 +120,12 @@ void print_flag(int port, int set_or_clear, int flag);
#define TC_FLAGS_UPDATE_CURRENT BIT(19)
/* Flag to indicate USB mux should be updated */
#define TC_FLAGS_UPDATE_USB_MUX BIT(20)
+/* Flag for retimer firmware update */
+#define TC_FLAGS_USB_RETIMER_FW_UPDATE_RUN BIT(21)
+#define TC_FLAGS_USB_RETIMER_FW_UPDATE_LTD_RUN BIT(22)
/* For checking flag_bit_names[] array */
-#define TC_FLAGS_COUNT 21
+#define TC_FLAGS_COUNT 23
/* On disconnect, clear most of the flags. */
#define CLR_FLAGS_ON_DISCONNECT(port) TC_CLR_FLAG(port, \
@@ -307,6 +310,10 @@ static struct bit_name flag_bit_names[] = {
{ 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" },
};
BUILD_ASSERT(ARRAY_SIZE(flag_bit_names) == TC_FLAGS_COUNT);
@@ -3570,6 +3577,18 @@ void tc_set_debug_level(enum 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);
+ tc_start_event_loop(port);
+}
+
+void tc_usb_firmware_fw_update_run(int port)
+{
+ TC_SET_FLAG(port, TC_FLAGS_USB_RETIMER_FW_UPDATE_RUN);
+ tc_start_event_loop(port);
+}
+
void tc_run(const int port)
{
/*
@@ -3585,6 +3604,21 @@ void tc_run(const int port)
set_state_tc(port, TC_DISABLED);
}
+ if (IS_ENABLED(CONFIG_USBC_RETIMER_FW_UPDATE)) {
+ if (TC_CHK_FLAG(port, TC_FLAGS_SUSPENDED) &&
+ 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);
+ }
+
+ 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);
}