summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Yilun Lin <yllin@chromium.org>2022-03-23 11:19:14 +0800
committerChromeos LUCI <chromeos-scoped@luci-project-accounts.iam.gserviceaccount.com>2022-04-28 04:30:56 +0000
commitf421dae42d893c97fb41f8a2fb4731d2ba2c89c9 (patch)
tree1ddadd4327c9f563c225f658b51ab3ca06ea8bb2
parent95d12b1d877b3c0ac61f361cb81ed30e6342c26f (diff)
downloadchrome-ec-f421dae42d893c97fb41f8a2fb4731d2ba2c89c9.tar.gz
tcpc/rt1718s: disable FRS until valid FRS VBUS drop
`rt1718s_set_frs_enable` does three things: 1. enable/disable FRS RX detection 2. enable/disable auto asserting EN_SRC when FRS happened 3. enable/disable EN_FRS RT1718S EN_SRC GPIO auto-enablement is only working when EN_FRS is asserted and the VBUS drop below Vsafe5VMax. However, some of the FRS hubs have a higher capacitance, and this makes the VBUS discharging slowly, and currently, EN_FRS is disabled after we got FRS RX signal on CC line, and it might happen before the VBUS discharged to Vsafe5VMax, and the FRS won't source in that case because EN_FRS was deasserted at the moment. Also, some of the PPC (e.g. nx20p348x and hl5099) requiring the EN_FRS asserting longer even after the EN_SRC asserted (power is sourcing), so that the VBUS can be maintained. To fix these issues, we defer deasserting the EN_FRS for 5ms after RT1718S reports VBUS valid low (4.75V), and EN_SRC is asserted. The 5ms is recommended by HL5099 vendor to maintain the VBUS. BUG=b:223086905 b/228422539 TEST=kingler C1 FRS works BRANCH=none Change-Id: Idc1fc8614b30275b825a655d7af821c1a1c99ee0 Signed-off-by: Eric Yilun Lin <yllin@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3544748 Auto-Submit: Eric Yilun Lin <yllin@google.com> Reviewed-by: Ting Shen <phoenixshen@chromium.org> Tested-by: Eric Yilun Lin <yllin@google.com> Commit-Queue: Ting Shen <phoenixshen@chromium.org>
-rw-r--r--driver/ppc/rt1718s.c1
-rw-r--r--driver/tcpm/rt1718s.c111
-rw-r--r--driver/tcpm/rt1718s.h9
3 files changed, 114 insertions, 7 deletions
diff --git a/driver/ppc/rt1718s.c b/driver/ppc/rt1718s.c
index 5f6c73e13c..a7a378d934 100644
--- a/driver/ppc/rt1718s.c
+++ b/driver/ppc/rt1718s.c
@@ -10,6 +10,7 @@
#include "console.h"
#include "driver/ppc/rt1718s.h"
#include "driver/tcpm/tcpci.h"
+#include "usb_pe_sm.h"
#include "usbc_ppc.h"
#include "util.h"
diff --git a/driver/tcpm/rt1718s.c b/driver/tcpm/rt1718s.c
index 3211bacb03..175f471fe5 100644
--- a/driver/tcpm/rt1718s.c
+++ b/driver/tcpm/rt1718s.c
@@ -12,18 +12,27 @@
#include "driver/tcpm/tcpci.h"
#include "driver/tcpm/tcpm.h"
#include "gpio.h"
+#include "hooks.h"
#include "stdint.h"
#include "system.h"
#include "task.h"
#include "timer.h"
#include "usb_mux.h"
#include "usb_pd.h"
+#include "usb_pe_sm.h"
#include "util.h"
#define CPRINTS(format, args...) cprints(CC_USBCHARGE, format, ## args)
#define CPRINTF(format, args...) cprintf(CC_USBCHARGE, format, ## args)
-#define RT1718S_SW_RESET_DELAY_MS 2
+#define RT1718S_SW_RESET_DELAY_MS 2
+/* Time for delay deasserting EN_FRS after FRS VBUS drop. */
+#define RT1718S_FRS_DIS_DELAY (5 * MSEC)
+
+#define FLAG_FRS_ENABLED BIT(0)
+#define FLAG_FRS_RX_SIGNALLED BIT(1)
+#define FLAG_FRS_VBUS_VALID_FALL BIT(2)
+static atomic_t frs_flag[CONFIG_USB_PD_PORT_MAX_COUNT];
/* i2c_write function which won't wake TCPC from low power mode. */
static int rt1718s_write(int port, int reg, int val, int len)
@@ -257,10 +266,16 @@ static int rt1718s_init(int port)
TCPC_REG_ALERT_MASK_VENDOR_DEF,
MASK_SET));
- if (IS_ENABLED(CONFIG_USB_PD_FRS))
- /* Set Rx frs unmasked */
- RETURN_ERROR(rt1718s_update_bits8(port, RT1718S_RT_MASK1,
- RT1718S_RT_MASK1_M_RX_FRS, 0xFF));
+ if (IS_ENABLED(CONFIG_USB_PD_FRS)) {
+ memset(frs_flag, 0,
+ sizeof(atomic_t) * CONFIG_USB_PD_PORT_MAX_COUNT);
+ /* Set Rx frs and valid vbus fall unmasked */
+ RETURN_ERROR(rt1718s_update_bits8(
+ port, RT1718S_RT_MASK1,
+ RT1718S_RT_MASK1_M_RX_FRS |
+ RT1718S_RT_MASK1_M_VBUS_FRS_LOW,
+ 0xFF));
+ }
RETURN_ERROR(board_rt1718s_init(port));
@@ -363,6 +378,23 @@ static void rt1718s_bc12_usb_charger_task(const int port)
}
}
+static void frs_gpio_disable_deferred(void)
+{
+ int i;
+
+ for (i = 0; i < board_get_usb_pd_port_count(); ++i) {
+ if (frs_flag[i] & FLAG_FRS_VBUS_VALID_FALL) {
+ atomic_clear_bits(&frs_flag[i],
+ FLAG_FRS_RX_SIGNALLED |
+ FLAG_FRS_VBUS_VALID_FALL);
+ /* If the FRS gets enabled again, do not disable it. */
+ if (!(frs_flag[i] & FLAG_FRS_ENABLED))
+ board_rt1718s_set_frs_enable(i, 0);
+ }
+ }
+}
+DECLARE_DEFERRED(frs_gpio_disable_deferred);
+
void rt1718s_vendor_defined_alert(int port)
{
int rv, value;
@@ -378,11 +410,47 @@ void rt1718s_vendor_defined_alert(int port)
return;
if ((int1 & RT1718S_RT_INT1_INT_RX_FRS)) {
+ atomic_or(&frs_flag[port], FLAG_FRS_RX_SIGNALLED);
+ /* notify TCPM we got FRS signal */
pd_got_frs_signal(port);
+ }
+
+ if ((int1 & RT1718S_RT_INT1_INT_VBUS_FRS_LOW)) {
+ /*
+ * VBUS_FRS_LOW alert could be sent multiple times,
+ * filter it here.
+ */
+ if (!(frs_flag[port] & FLAG_FRS_VBUS_VALID_FALL)) {
+ atomic_or(&frs_flag[port],
+ FLAG_FRS_VBUS_VALID_FALL);
+ /*
+ * b/223086905:comment8&comment17
+ * We deferred the FRS disable
+ * (called to rt1718s_set_frs_enable()), now we
+ * can disable it after the VBUS fell.
+ */
+ rt1718s_set_frs_enable(port, 0);
+ /*
+ * b/228422539:comment4
+ * PPC HL5099 (pin-compatible to NX20P3483)
+ * suggested FRS gpio should be disabled after
+ * the SRC gpio enabled for 5ms to prevent the
+ * PPC from stopping sourcing the VBUS.
+ * Thought this is a workaround for HL5099, but
+ * it shouldn't affect other PPC chips since
+ * the DUT started sourcing the partner already.
+ */
+ hook_call_deferred(
+ &frs_gpio_disable_deferred_data,
+ RT1718S_FRS_DIS_DELAY);
+ }
+ }
+ /* ignore other interrupts for faster frs handling */
+ if (int1 & (RT1718S_RT_INT1_INT_RX_FRS |
+ RT1718S_RT_INT1_INT_VBUS_FRS_LOW)) {
tcpc_write16(port, TCPC_REG_ALERT,
- TCPC_REG_ALERT_VENDOR_DEF);
- /* ignore other interrupts for faster frs handling */
+ TCPC_REG_ALERT_VENDOR_DEF);
return;
}
}
@@ -523,6 +591,12 @@ out:
}
#ifdef CONFIG_USB_PD_FRS
+
+__overridable int board_rt1718s_set_frs_enable(int port, int enable)
+{
+ return EC_SUCCESS;
+}
+
int rt1718s_set_frs_enable(int port, int enable)
{
/*
@@ -532,15 +606,38 @@ int rt1718s_set_frs_enable(int port, int enable)
int frs_ctrl2 = 0x10, vbus_ctrl_en = 0x3F;
if (enable) {
+ atomic_or(&frs_flag[port], FLAG_FRS_ENABLED);
frs_ctrl2 |= RT1718S_FRS_CTRL2_RX_FRS_EN;
frs_ctrl2 |= RT1718S_FRS_CTRL2_VBUS_FRS_EN;
vbus_ctrl_en |= RT1718S_VBUS_CTRL_EN_GPIO2_VBUS_PATH_EN;
vbus_ctrl_en |= RT1718S_VBUS_CTRL_EN_GPIO1_VBUS_PATH_EN;
+ } else {
+ atomic_clear_bits(&frs_flag[port], FLAG_FRS_ENABLED);
+ if (FLAG_FRS_RX_SIGNALLED ==
+ (frs_flag[port] &
+ (FLAG_FRS_RX_SIGNALLED | FLAG_FRS_VBUS_VALID_FALL))) {
+ /*
+ * Skip disable if we had only FRS_RX_SIGNALLED, and
+ * deferred the FRS register disable process in
+ * rt1718s_vendor_defined_alert.
+ */
+ return EC_SUCCESS;
+ }
}
RETURN_ERROR(rt1718s_write8(port, RT1718S_FRS_CTRL2, frs_ctrl2));
RETURN_ERROR(rt1718s_write8(port, RT1718S_VBUS_CTRL_EN, vbus_ctrl_en));
+
+ /*
+ * b/223086905#comment13, b/228422539:comment4
+ * If this function gets called when FRS RX signalled, then
+ * we'll deferred the GPIO disabled until the VBUS valid drop. So
+ * don't disable it here.
+ */
+ if (enable || !(frs_flag[port] & FLAG_FRS_RX_SIGNALLED))
+ RETURN_ERROR(board_rt1718s_set_frs_enable(port, enable));
+
return EC_SUCCESS;
}
#endif
diff --git a/driver/tcpm/rt1718s.h b/driver/tcpm/rt1718s.h
index 04650cdffd..e108c41db2 100644
--- a/driver/tcpm/rt1718s.h
+++ b/driver/tcpm/rt1718s.h
@@ -256,6 +256,15 @@ int rt1718s_set_frs_enable(int port, int enable);
/**
+ * Board override for fast role swap.
+ *
+ * @param port USB-C port
+ * @param enable enable/disable FRS
+ * @return EC_SUCCESS if success, EC_ERROR_UNKNOWN otherwise.
+ */
+__override_proto int board_rt1718s_set_frs_enable(int port, int enable);
+
+/**
* Software reset RT1718S
*
* @param port USB-C port