diff options
author | Ruibin Chang <ruibin.chang@ite.com.tw> | 2020-07-28 10:57:55 +0800 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2020-07-31 05:24:29 +0000 |
commit | d986075dc3c41748556170dd3ef3b67adb64578b (patch) | |
tree | 02c45d67a7c72297436619ec1861d6b8eaf8bb6b /driver/tcpm | |
parent | 7e36bc92e96b9bf7a64f1b0abb51c67cf967ad54 (diff) | |
download | chrome-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.c | 80 | ||||
-rw-r--r-- | driver/tcpm/it83xx_pd.h | 7 | ||||
-rw-r--r-- | driver/tcpm/it8xxx2.c | 86 |
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); } |