summaryrefslogtreecommitdiff
path: root/driver/tcpm
diff options
context:
space:
mode:
authorRuibin Chang <ruibin.chang@ite.com.tw>2020-07-28 10:57:55 +0800
committerCommit Bot <commit-bot@chromium.org>2020-07-31 05:24:29 +0000
commitd986075dc3c41748556170dd3ef3b67adb64578b (patch)
tree02c45d67a7c72297436619ec1861d6b8eaf8bb6b /driver/tcpm
parent7e36bc92e96b9bf7a64f1b0abb51c67cf967ad54 (diff)
downloadchrome-ec-d986075dc3c41748556170dd3ef3b67adb64578b.tar.gz
chip/it83xx, it8xxx2: implement detect cc disconnection interrupt for SRC role
Implement detect cc disconnection interrupt for source. When TCPC detect SNK/audio/debug device plug out (cc lines open), TCPC can interrupt pd task to update cc state. BUG=b:160548079 BRANCH=none TEST=test on board reef_it8320, it81202_pdevb with TCPMv1, TCPMv2. Connect to dongle, adapter and DRP, check 1.Plug in/out interrupt fire correctly. 2.Power role swap can state to SRC_READY and SNK_READY. 3.When partner disconnect, we discharge Vconn within tVconnOFF(35ms). Signed-off-by: Ruibin Chang <Ruibin.Chang@ite.com.tw> Change-Id: I58bc8a5a9289df4ea4e8b3efec000d3a9ab1cb5d Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2294626 Reviewed-by: Jett Rink <jettrink@chromium.org>
Diffstat (limited to 'driver/tcpm')
-rw-r--r--driver/tcpm/it83xx.c80
-rw-r--r--driver/tcpm/it83xx_pd.h7
-rw-r--r--driver/tcpm/it8xxx2.c86
3 files changed, 157 insertions, 16 deletions
diff --git a/driver/tcpm/it83xx.c b/driver/tcpm/it83xx.c
index 57f517f136..4a53f14a2f 100644
--- a/driver/tcpm/it83xx.c
+++ b/driver/tcpm/it83xx.c
@@ -396,7 +396,7 @@ static void it83xx_init(enum usbpd_port port, int role)
/* enable tx done and reset detect interrupt */
IT83XX_USBPD_IMR(port) &= ~(USBPD_REG_MASK_MSG_TX_DONE |
USBPD_REG_MASK_HARD_RESET_DETECT);
-#ifdef IT83XX_INTC_PLUG_IN_SUPPORT
+#ifdef IT83XX_INTC_PLUG_IN_OUT_SUPPORT
/*
* when tcpc detect type-c plug in (cc lines voltage change), it will
* interrupt fw to wake pd task, so task can react immediately.
@@ -657,17 +657,85 @@ static int it83xx_tcpm_get_chip_info(int port, int live,
return EC_SUCCESS;
}
-static void it83xx_tcpm_sw_reset(void)
+static void it83xx_tcpm_switch_plug_out_type(int port)
+{
+ enum tcpc_cc_voltage_status cc1, cc2;
+
+ /* Check what do we and partner cc assert */
+ it83xx_tcpm_get_cc(port, &cc1, &cc2);
+
+ if ((cc1 == TYPEC_CC_VOLT_RD && cc2 == TYPEC_CC_VOLT_RD) ||
+ (cc1 == TYPEC_CC_VOLT_RA && cc2 == TYPEC_CC_VOLT_RA))
+ /* We're source, switch to detect audio/debug plug out. */
+ IT83XX_USBPD_TCDCR(port) = (IT83XX_USBPD_TCDCR(port) &
+ ~USBPD_REG_PLUG_IN_OUT_DETECT_DISABLE) |
+ USBPD_REG_PLUG_OUT_DETECT_TYPE_SELECT |
+ USBPD_REG_PLUG_OUT_SELECT;
+ else if (cc1 == TYPEC_CC_VOLT_RD || cc2 == TYPEC_CC_VOLT_RD)
+ /* We're source, switch to detect sink plug out. */
+ IT83XX_USBPD_TCDCR(port) = (IT83XX_USBPD_TCDCR(port) &
+ ~USBPD_REG_PLUG_IN_OUT_DETECT_DISABLE &
+ ~USBPD_REG_PLUG_OUT_DETECT_TYPE_SELECT) |
+ USBPD_REG_PLUG_OUT_SELECT;
+ else if (cc1 >= TYPEC_CC_VOLT_RP_DEF || cc2 >= TYPEC_CC_VOLT_RP_DEF)
+ /*
+ * We're sink, disable detect interrupt, so messages on cc line
+ * won't trigger interrupt.
+ * NOTE: Plug out is detected by TCPM polling Vbus.
+ */
+ IT83XX_USBPD_TCDCR(port) |=
+ USBPD_REG_PLUG_IN_OUT_DETECT_DISABLE;
+ /*
+ * If not above cases, plug in interrupt will fire again,
+ * and call switch_plug_out_type() to set the right state.
+ */
+}
+
+void switch_plug_out_type(enum usbpd_port port)
+{
+ it83xx_tcpm_switch_plug_out_type(port);
+}
+
+#ifdef CONFIG_USB_PD_TCPMV2
+static void it83xx_tcpm_hook_connect(void)
{
int port = TASK_ID_TO_PD_PORT(task_get_current());
-#ifdef IT83XX_INTC_PLUG_IN_SUPPORT
/*
- * Enable detect type-c plug in interrupt, since the pd task has
- * detected a type-c physical disconnected.
+ * There are five cases that hook_connect() be called by TCPMv2:
+ * 1)AttachWait.SNK -> Attached.SNK: disable detect interrupt.
+ * 2)AttachWait.SRC -> Attached.SRC: enable detect plug out.
+ * 3)AttachWait.SNK -> Try.SRC -> TryWait.SNK -> Attached.SNK: we do
+ * Try.SRC fail, disable detect interrupt.
+ * 4)AttachWait.SNK -> Try.SRC -> Attached.SRC: we do Try.SRC
+ * successfully, need to switch to detect plug out.
+ * 5)Attached.SRC -> TryWait.SNK -> Attached.SNK: partner do Try.SRC
+ * successfully, disable detect interrupt.
+ *
+ * NOTE: Try.SRC and TryWait.SNK are embedded respectively in
+ * SRC_DISCONNECT and SNK_DISCONNECT in TCPMv1. Every time we go to
+ * Try.SRC/TryWait.SNK state, the plug in interrupt will be enabled and
+ * fire for 3), 4), 5) cases, then set correctly for the SRC detect plug
+ * out or the SNK disable detect, so TCPMv1 needn't hook connection.
*/
- IT83XX_USBPD_TCDCR(port) &= ~USBPD_REG_PLUG_IN_OUT_DETECT_DISABLE;
+ it83xx_tcpm_switch_plug_out_type(port);
+}
+
+DECLARE_HOOK(HOOK_USB_PD_CONNECT, it83xx_tcpm_hook_connect, HOOK_PRIO_DEFAULT);
#endif
+
+static void it83xx_tcpm_sw_reset(void)
+{
+ int port = TASK_ID_TO_PD_PORT(task_get_current());
+
+ if (IS_ENABLED(IT83XX_INTC_PLUG_IN_OUT_SUPPORT))
+ /*
+ * Switch to detect plug in and enable detect plug in interrupt,
+ * since pd task has detected a type-c physical disconnected.
+ */
+ IT83XX_USBPD_TCDCR(port) &= ~(USBPD_REG_PLUG_OUT_SELECT |
+ USBPD_REG_PLUG_IN_OUT_DETECT_DISABLE);
+
/* exit BIST test data mode */
USBPD_SW_RESET(port);
}
diff --git a/driver/tcpm/it83xx_pd.h b/driver/tcpm/it83xx_pd.h
index ed45f1be6e..aa729b9c79 100644
--- a/driver/tcpm/it83xx_pd.h
+++ b/driver/tcpm/it83xx_pd.h
@@ -90,7 +90,7 @@
#define IT83XX_USBPD_TCDCR(p) REG8(IT83XX_USBPD_BASE(p)+0x67)
#define USBPD_REG_PLUG_OUT_DETECT_TYPE_SELECT BIT(7)
#define USBPD_REG_MASK_TYPEC_PLUG_IN_OUT_ISR BIT(4)
-#define USBPD_REG_PLUG_IN_OUT_SELECT BIT(3)
+#define USBPD_REG_PLUG_OUT_SELECT BIT(3)
#define USBPD_REG_PLUG_IN_OUT_DETECT_DISABLE BIT(1)
#define USBPD_REG_PLUG_IN_OUT_DETECT_STAT BIT(0)
#define IT83XX_USBPD_PDQSCR(p) REG8(IT83XX_USBPD_BASE(p)+0x70)
@@ -195,7 +195,7 @@
#define USBPD_REG_MASK_BMC_RX_THRESHOLD_SNK BIT(1)
#define IT83XX_USBPD_TCDCR(p) REG8(IT83XX_USBPD_BASE(p)+0x67)
#define USBPD_REG_PLUG_OUT_DETECT_TYPE_SELECT BIT(7)
-#define USBPD_REG_PLUG_IN_OUT_SELECT BIT(6)
+#define USBPD_REG_PLUG_OUT_SELECT BIT(6)
#define USBPD_REG_PD3_0_SNK_TX_OK_DISABLE BIT(5)
#define USBPD_REG_PD3_0_SNK_TX_NG_DISABLE BIT(3)
#define USBPD_REG_PLUG_IN_OUT_DETECT_DISABLE BIT(1)
@@ -353,6 +353,8 @@
IS_MASK_SET(IT83XX_USBPD_ISR(port), USBPD_REG_MASK_MSG_RX_DONE)
#define USBPD_IS_PLUG_IN_OUT_DETECT(port)\
IS_MASK_SET(IT83XX_USBPD_TCDCR(port), USBPD_REG_PLUG_IN_OUT_DETECT_STAT)
+#define USBPD_IS_PLUG_IN(port) \
+ IS_MASK_CLEAR(IT83XX_USBPD_TCDCR(port), USBPD_REG_PLUG_OUT_SELECT)
#if defined(CONFIG_USB_PD_TCPM_DRIVER_IT83XX)
#define USBPD_IS_FAST_SWAP_DETECT(port) \
IS_MASK_SET(IT83XX_USBPD_PD30IR(port), USBPD_REG_FAST_SWAP_DETECT_STAT)
@@ -403,5 +405,6 @@ void it83xx_disable_pd_module(int port);
void it83xx_clear_tx_error_status(enum usbpd_port port);
void it83xx_get_tx_error_status(enum usbpd_port port);
#endif
+void switch_plug_out_type(enum usbpd_port port);
#endif /* __CROS_EC_DRIVER_TCPM_IT83XX_H */
diff --git a/driver/tcpm/it8xxx2.c b/driver/tcpm/it8xxx2.c
index 10ca883c10..af04871017 100644
--- a/driver/tcpm/it8xxx2.c
+++ b/driver/tcpm/it8xxx2.c
@@ -627,6 +627,45 @@ static int it83xx_tcpm_set_frs_enable(int port, int enable)
}
#endif
+static void it83xx_tcpm_switch_plug_out_type(int port)
+{
+ enum tcpc_cc_voltage_status cc1, cc2;
+
+ /* Check what do we and partner cc assert */
+ it83xx_tcpm_get_cc(port, &cc1, &cc2);
+
+ if ((cc1 == TYPEC_CC_VOLT_RD && cc2 == TYPEC_CC_VOLT_RD) ||
+ (cc1 == TYPEC_CC_VOLT_RA && cc2 == TYPEC_CC_VOLT_RA))
+ /* We're source, switch to detect audio/debug plug out. */
+ IT83XX_USBPD_TCDCR(port) = (IT83XX_USBPD_TCDCR(port) &
+ ~USBPD_REG_PLUG_IN_OUT_DETECT_DISABLE) |
+ USBPD_REG_PLUG_OUT_DETECT_TYPE_SELECT |
+ USBPD_REG_PLUG_OUT_SELECT;
+ else if (cc1 == TYPEC_CC_VOLT_RD || cc2 == TYPEC_CC_VOLT_RD)
+ /* We're source, switch to detect sink plug out. */
+ IT83XX_USBPD_TCDCR(port) = (IT83XX_USBPD_TCDCR(port) &
+ ~USBPD_REG_PLUG_IN_OUT_DETECT_DISABLE &
+ ~USBPD_REG_PLUG_OUT_DETECT_TYPE_SELECT) |
+ USBPD_REG_PLUG_OUT_SELECT;
+ else if (cc1 >= TYPEC_CC_VOLT_RP_DEF || cc2 >= TYPEC_CC_VOLT_RP_DEF)
+ /*
+ * We're sink, disable detect interrupt, so messages on cc line
+ * won't trigger interrupt.
+ * NOTE: Plug out is detected by TCPM polling Vbus.
+ */
+ IT83XX_USBPD_TCDCR(port) |=
+ USBPD_REG_PLUG_IN_OUT_DETECT_DISABLE;
+ /*
+ * If not above cases, plug in interrupt will fire again,
+ * and call switch_plug_out_type() to set the right state.
+ */
+}
+
+void switch_plug_out_type(enum usbpd_port port)
+{
+ it83xx_tcpm_switch_plug_out_type(port);
+}
+
static void it83xx_init(enum usbpd_port port, int role)
{
uint8_t cc_config = (port == USBPD_PORT_C ?
@@ -661,15 +700,17 @@ static void it83xx_init(enum usbpd_port port, int role)
/* Enable tx done and hard reset detect interrupt */
IT83XX_USBPD_IMR(port) &= ~(USBPD_REG_MASK_MSG_TX_DONE |
USBPD_REG_MASK_HARD_RESET_DETECT);
-#ifdef IT83XX_INTC_PLUG_IN_SUPPORT
+#ifdef IT83XX_INTC_PLUG_IN_OUT_SUPPORT
/*
* When tcpc detect type-c plug in (cc lines voltage change), it will
* interrupt fw to wake pd task, so task can react immediately.
*
* W/C status and enable type-c plug-in detect interrupt.
*/
- IT83XX_USBPD_TCDCR(port) |= USBPD_REG_PLUG_IN_OUT_DETECT_STAT;
- IT83XX_USBPD_TCDCR(port) &= ~USBPD_REG_PLUG_IN_OUT_DETECT_DISABLE;
+ IT83XX_USBPD_TCDCR(port) = (IT83XX_USBPD_TCDCR(port) &
+ ~(USBPD_REG_PLUG_IN_OUT_DETECT_DISABLE |
+ USBPD_REG_PLUG_OUT_SELECT)) |
+ USBPD_REG_PLUG_IN_OUT_DETECT_STAT;
#endif
/* Set cc1/cc2 pins alternate mode */
*usbpd_ctrl_regs[port].cc1 = cc_config;
@@ -687,17 +728,46 @@ static int it83xx_tcpm_init(int port)
return EC_SUCCESS;
}
-static void it83xx_tcpm_sw_reset(void)
+#ifdef CONFIG_USB_PD_TCPMV2
+static void it83xx_tcpm_hook_connect(void)
{
int port = TASK_ID_TO_PD_PORT(task_get_current());
-#ifdef IT83XX_INTC_PLUG_IN_SUPPORT
/*
- * Enable detect type-c plug in interrupt, since the pd task has
- * detected a type-c physical disconnected.
+ * There are five cases that hook_connect() be called by TCPMv2:
+ * 1)AttachWait.SNK -> Attached.SNK: disable detect interrupt.
+ * 2)AttachWait.SRC -> Attached.SRC: enable detect plug out.
+ * 3)AttachWait.SNK -> Try.SRC -> TryWait.SNK -> Attached.SNK: we do
+ * Try.SRC fail, disable detect interrupt.
+ * 4)AttachWait.SNK -> Try.SRC -> Attached.SRC: we do Try.SRC
+ * successfully, need to switch to detect plug out.
+ * 5)Attached.SRC -> TryWait.SNK -> Attached.SNK: partner do Try.SRC
+ * successfully, disable detect interrupt.
+ *
+ * NOTE: Try.SRC and TryWait.SNK are embedded respectively in
+ * SRC_DISCONNECT and SNK_DISCONNECT in TCPMv1. Every time we go to
+ * Try.SRC/TryWait.SNK state, the plug in interrupt will be enabled and
+ * fire for 3), 4), 5) cases, then set correctly for the SRC detect plug
+ * out or the SNK disable detect, so TCPMv1 needn't hook connection.
*/
- IT83XX_USBPD_TCDCR(port) &= ~USBPD_REG_PLUG_IN_OUT_DETECT_DISABLE;
+ it83xx_tcpm_switch_plug_out_type(port);
+}
+
+DECLARE_HOOK(HOOK_USB_PD_CONNECT, it83xx_tcpm_hook_connect, HOOK_PRIO_DEFAULT);
#endif
+
+static void it83xx_tcpm_sw_reset(void)
+{
+ int port = TASK_ID_TO_PD_PORT(task_get_current());
+
+ if (IS_ENABLED(IT83XX_INTC_PLUG_IN_OUT_SUPPORT))
+ /*
+ * Switch to detect plug in and enable detect plug in interrupt,
+ * since pd task has detected a type-c physical disconnected.
+ */
+ IT83XX_USBPD_TCDCR(port) &= ~(USBPD_REG_PLUG_OUT_SELECT |
+ USBPD_REG_PLUG_IN_OUT_DETECT_DISABLE);
+
/* Exit BIST test data mode */
USBPD_SW_RESET(port);
}