diff options
Diffstat (limited to 'common/usbc')
-rw-r--r-- | common/usbc/build.mk | 2 | ||||
-rw-r--r-- | common/usbc/usb_retimer_fw_update.c | 159 | ||||
-rw-r--r-- | common/usbc/usb_tc_drp_acc_trysrc_sm.c | 36 |
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); } |