From b8723d58a8f624a2dfee3a3d7f28030dcd926d68 Mon Sep 17 00:00:00 2001 From: Denis Brockus Date: Mon, 3 Aug 2020 09:21:21 -0600 Subject: [PATCH] nct38xx: hard disable sinking when cc is set to open/open zork's TCPC does not want to go into CC OPEN/OPEN when it is powered solely by the power that it will be cutting off. This should have caused the system to brown out and reboot but the TCPC keeps enough of the power connection to not allow a brown out but locks up the rest of the system from continuing. By disabling the SNKEN bit in CONTROL_OUT register, this condition goes away and we will brown out on batteryless cold reboot as expected. BUG=b:162016100 BRANCH=none TEST=ectool reboot_ec cold (without a battery attached) Signed-off-by: Denis Brockus Change-Id: Idb9597c978a9ba18f79ff158db6463af156707b5 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2333120 Tested-by: Denis Brockus Commit-Queue: Edward Hill Reviewed-by: Edward Hill Auto-Submit: Denis Brockus --- common/usbc/usb_tc_drp_acc_trysrc_sm.c | 20 ++++++++++++--- driver/tcpm/nct38xx.c | 34 +++++++++++++++++++++++++- 2 files changed, 49 insertions(+), 5 deletions(-) diff --git a/common/usbc/usb_tc_drp_acc_trysrc_sm.c b/common/usbc/usb_tc_drp_acc_trysrc_sm.c index 790bcd8127..7491250088 100644 --- a/common/usbc/usb_tc_drp_acc_trysrc_sm.c +++ b/common/usbc/usb_tc_drp_acc_trysrc_sm.c @@ -2292,8 +2292,14 @@ static void tc_attached_snk_exit(const int port) if (TC_CHK_FLAG(port, TC_FLAGS_VCONN_ON)) set_vconn(port, 0); - /* Attached.SNK exit - disable AutoDischargeDisconnect */ - tcpm_enable_auto_discharge_disconnect(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_SUSPEND)) + tcpm_enable_auto_discharge_disconnect(port, 0); } /* Clear flags after checking Vconn status */ @@ -3261,9 +3267,15 @@ static void tc_cc_open_entry(const int port) /* * 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. + * 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. */ - tcpm_enable_auto_discharge_disconnect(port, 0); + if (battery_is_present()) + tcpm_enable_auto_discharge_disconnect(port, 0); /* We may brown out after applying CC open, so flush console first. */ CPRINTS("C%d: Applying CC Open!", port); diff --git a/driver/tcpm/nct38xx.c b/driver/tcpm/nct38xx.c index 5e35bfba22..ffd2a15b68 100644 --- a/driver/tcpm/nct38xx.c +++ b/driver/tcpm/nct38xx.c @@ -109,6 +109,38 @@ static int nct38xx_tcpm_init(int port) return nct38xx_init(port); } +int nct38xx_tcpm_set_cc(int port, int pull) +{ + /* + * Setting the CC lines to open/open requires that the NCT CTRL_OUT + * register has sink disabled. Otherwise the following happens, as + * described by Nuvoton: + * + * 1. You set CC lines to Open/Open. This is physically happening on + * the CC line. + * 2. Since CC is now Open/Open, the internal TCPC HW state machine + * is no longer in Attached.Snk and therefore our TCPC HW + * automatically opens the sink switch (de-assert the VBSNK_EN pin) + * 3. Since sink switch is open, the TCPC VCC voltage starts to drop. + * 4. When TCPC VCC gets below ~2.7V the TCPC will reset and therefore + * it will present Rd/Rd on the CC lines. Also the VBSNK_EN pin + * after reset is Hi-Z, so the sink switch will get closed again. + */ + if (pull == TYPEC_CC_OPEN) { + int rv; + + /* Disable SNKEN, it will be re-enabled in tcpm_init path */ + rv = tcpc_update8(port, + NCT38XX_REG_CTRL_OUT_EN, + NCT38XX_REG_CTRL_OUT_EN_SNKEN, + MASK_CLR); + if (rv) + return rv; + } + + return tcpci_tcpm_set_cc(port, pull); +} + static void nct38xx_tcpc_alert(int port) { int alert, rv; @@ -167,7 +199,7 @@ const struct tcpm_drv nct38xx_tcpm_drv = { .check_vbus_level = &tcpci_tcpm_check_vbus_level, #endif .select_rp_value = &tcpci_tcpm_select_rp_value, - .set_cc = &tcpci_tcpm_set_cc, + .set_cc = &nct38xx_tcpm_set_cc, .set_polarity = &tcpci_tcpm_set_polarity, .set_vconn = &tcpci_tcpm_set_vconn, .set_msg_header = &tcpci_tcpm_set_msg_header,