tcpm/it83xx: don't enable/disable Tx when Rx_enable() called

Register BMC PHY (00h bit4) enable/disable both Tx and Rx module,
and we shouldn't enable/disable Tx module when Rx_enable() called,
So I change to set Rx decode enable/disable only in Rx_enable().

Setting PD sleep mask shouldn't tie with Rx_enable(), so I change
to set sleep mask by HOOK_CONNECT/DISCONNECT. Enable deep sleep mode,
when all ITE ports are in Unattach.SRC/SNK state and other ports
aren't pd_capable(). Disable deep sleep mode, when one of ITE port is
in Attach.SRC/SNK state or one of other ports is pd_capable().

BUG=b:174151372
BRANCH=none
TEST=on drawcia, plug-in dongle and adapter:
     1.console cmd "pd 0 hard", hard reset tx done is set within 1ms.
     2.check PD sleep mask: nothing attached = 0, one port attached = 1
     3.lid close to G3(Rd_5.1k), then plug-in adapter, can go to
       SNK_READY state
     4.can send SOP' to E-mark cable
     5.console cmd "sysjump rw", can go to SNK/SRC_READY

Signed-off-by: Ruibin Chang <ruibin.chang@ite.com.tw>
Change-Id: Ibbf2f2d3d086be0bad4f3430c78f5ac3a26f8b1a
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2573667
Tested-by: Ruibin Chang <Ruibin.Chang@ite.com.tw>
Reviewed-by: Diana Z <dzigterman@chromium.org>
Reviewed-by: Aseda Aboagye <aaboagye@chromium.org>
Commit-Queue: Aseda Aboagye <aaboagye@chromium.org>
This commit is contained in:
Ruibin Chang 2020-12-04 18:05:14 +08:00 committed by Commit Bot
parent e92c7a2a33
commit d421419f1a
2 changed files with 96 additions and 64 deletions

View File

@ -40,6 +40,10 @@
#define PD_IT83XX_VCONN_TURN_OFF_DELAY_US 500
#endif
int rx_en[IT83XX_USBPD_PHY_PORT_COUNT];
STATIC_IF(CONFIG_USB_PD_DECODE_SOP)
bool sop_prime_en[IT83XX_USBPD_PHY_PORT_COUNT];
const struct usbpd_ctrl_t usbpd_ctrl_regs[] = {
{&IT83XX_GPIO_GPCRF4, &IT83XX_GPIO_GPCRF5, IT83XX_IRQ_USBPD0},
{&IT83XX_GPIO_GPCRH1, &IT83XX_GPIO_GPCRH2, IT83XX_IRQ_USBPD1},
@ -256,10 +260,13 @@ static enum tcpc_transmit_complete it83xx_send_hw_reset(enum usbpd_port port,
USBPD_SEND_HARD_RESET(port);
usleep(MSEC);
if (IT83XX_USBPD_MTSR0(port) & USBPD_REG_MASK_SEND_HW_RESET)
return TCPC_TX_COMPLETE_FAILED;
if (USBPD_IS_HARD_CABLE_RESET_TX_DONE(port)) {
IT83XX_USBPD_ISR(port) =
USBPD_REG_MASK_HARD_CABLE_RESET_TX_DONE;
return TCPC_TX_COMPLETE_SUCCESS;
}
return TCPC_TX_COMPLETE_SUCCESS;
return TCPC_TX_COMPLETE_FAILED;
}
static void it83xx_send_bist_mode2_pattern(enum usbpd_port port)
@ -404,12 +411,6 @@ static void it83xx_init(enum usbpd_port port, int role)
*/
IT83XX_USBPD_BMCSR(port) = (IT83XX_USBPD_BMCSR(port) & ~0x70) |
((CONFIG_PD_RETRY_COUNT + 1) << 4);
/* set SOP: receive SOP message only.
* bit[7]: SOP" support enable.
* bit[6]: SOP' support enable.
* bit[5]: SOP support enable.
*/
IT83XX_USBPD_PDMSR(port) = USBPD_REG_MASK_SOP_ENABLE;
/* W/C status */
IT83XX_USBPD_ISR(port) = 0xff;
/* enable cc, select cc1 and Rd. */
@ -559,12 +560,19 @@ static int it83xx_tcpm_set_polarity(int port, enum tcpc_cc_polarity polarity)
__maybe_unused static int it83xx_tcpm_decode_sop_prime_enable(int port,
bool enable)
{
if (enable)
IT83XX_USBPD_PDMSR(port) |= (USBPD_REG_MASK_SOPP_ENABLE |
USBPD_REG_MASK_SOPPP_ENABLE);
else
IT83XX_USBPD_PDMSR(port) &= ~(USBPD_REG_MASK_SOPP_ENABLE |
USBPD_REG_MASK_SOPPP_ENABLE);
/* Save SOP'/SOP'' enable state */
sop_prime_en[port] = enable;
if (rx_en[port]) {
if (enable)
IT83XX_USBPD_PDMSR(port) |=
(USBPD_REG_MASK_SOPP_ENABLE |
USBPD_REG_MASK_SOPPP_ENABLE);
else
IT83XX_USBPD_PDMSR(port) &=
~(USBPD_REG_MASK_SOPP_ENABLE |
USBPD_REG_MASK_SOPPP_ENABLE);
}
return EC_SUCCESS;
}
@ -584,9 +592,7 @@ static int it83xx_tcpm_set_vconn(int port, int enable)
it83xx_enable_vconn(port, enable);
if (IS_ENABLED(CONFIG_USB_PD_DECODE_SOP))
/* Enable tcpc receive SOP' and SOP'' packet */
IT83XX_USBPD_PDMSR(port) |=
(USBPD_REG_MASK_SOPP_ENABLE |
USBPD_REG_MASK_SOPPP_ENABLE);
it83xx_tcpm_decode_sop_prime_enable(port, true);
}
/* Turn on/off vconn power switch. */
@ -633,54 +639,24 @@ static int it83xx_tcpm_set_msg_header(int port, int power_role, int data_role)
static int it83xx_tcpm_set_rx_enable(int port, int enable)
{
int i;
bool prevent_deep_sleep = false;
/* Save rx_on */
rx_en[port] = enable;
if (enable) {
IT83XX_USBPD_IMR(port) &= ~USBPD_REG_MASK_MSG_RX_DONE;
USBPD_ENABLE_BMC_PHY(port);
IT83XX_USBPD_PDMSR(port) |= USBPD_REG_MASK_SOP_ENABLE;
IT83XX_USBPD_VDMMCSR(port) |= USBPD_REG_MASK_HARD_RESET_DECODE;
if (IS_ENABLED(CONFIG_USB_PD_DECODE_SOP))
it83xx_tcpm_decode_sop_prime_enable(port,
sop_prime_en[port]);
} else {
IT83XX_USBPD_IMR(port) |= USBPD_REG_MASK_MSG_RX_DONE;
USBPD_DISABLE_BMC_PHY(port);
IT83XX_USBPD_PDMSR(port) &= ~(USBPD_REG_MASK_SOP_ENABLE |
USBPD_REG_MASK_SOPP_ENABLE |
USBPD_REG_MASK_SOPPP_ENABLE);
IT83XX_USBPD_VDMMCSR(port) &= ~USBPD_REG_MASK_HARD_RESET_DECODE;
}
/*
* TCPMv1/TCPMv2 handle SLEEP_MASK_USB_PD and Rx_enable order for deep
* sleep mode:
* 1.Exit deep sleep mode, Rx enable -> deep sleep disable:
* In deep sleep mode, ITE TCPC clock is turned off, so we should
* disable deep sleep to leave the mode first then enable Rx, otherwise
* we'll miss packet in the mode.
* 2.Enter deep sleep mode, deep sleep enable -> Rx disable:
* This is OK, but before set Rx disable, our Rx is disabled in deep
* sleep mode period.
*
* So now, we set the SLEEP_MASK_USB_PD only by ITE driver. If any ITE
* PD port Rx is enabled, then disable EC deep sleep.
*/
for (i = 0; i < CONFIG_USB_PD_ITE_ACTIVE_PORT_COUNT; ++i) {
if (IT83XX_USBPD_GCR(i) & USBPD_REG_MASK_BMC_PHY) {
prevent_deep_sleep = true;
break;
}
}
/*
* Check if any other ports have a PD port partner connected. Deep
* sleep is forbidden if any PD port partner is connected. Above, we
* only checked for the ITE ports.
*/
if (!prevent_deep_sleep) {
for (; i < board_get_usb_pd_port_count(); i++)
if (pd_capable(i))
prevent_deep_sleep = true;
}
if (prevent_deep_sleep)
disable_sleep(SLEEP_MASK_USB_PD);
else
enable_sleep(SLEEP_MASK_USB_PD);
return EC_SUCCESS;
}
@ -735,10 +711,12 @@ static int it83xx_tcpm_get_chip_info(int port, int live,
static int it83xx_tcpm_enter_low_power_mode(int port)
{
/*
* ITE embedded TCPC do low power mode in idle_task(), when all ITE
* ports are Rx disabled (means not in Attach.SRC/SNK state or
* pd_disabled_mask be set). In deep sleep mode, the timer wakeup PD
* task every 5ms, then PD task change the CC lines termination.
* ITE embedded TCPC SLEEP_MASK_USB_PD flag is only controlled by
* it83xx driver in set_pd_sleep_mask(), and do low power mode in
* idle_task().
* In deep sleep mode, ITE TCPC clock is turned off, and the
* timer every 5ms to exit the mode and wakeup PD task to run
* (ex. change the CC lines termination).
*/
return EC_SUCCESS;
}
@ -783,6 +761,42 @@ void switch_plug_out_type(enum usbpd_port port)
it83xx_tcpm_switch_plug_out_type(port);
}
void set_pd_sleep_mask(int port)
{
int i;
bool prevent_deep_sleep = false;
/*
* Set SLEEP_MASK_USB_PD for deep sleep mode in TCPMv2:
* 1.Enable deep sleep mode, when all ITE ports are in Unattach.SRC/SNK
* state (HOOK_DISCONNECT called) and other ports aren't pd_capable().
* 2.Disable deep sleep mode, when one of ITE port is in Attach.SRC/SNK
* state (HOOK_CONNECT called) or one of other ports is pd_capable().
*/
for (i = 0; i < CONFIG_USB_PD_ITE_ACTIVE_PORT_COUNT; ++i) {
if (IT83XX_USBPD_GCR(i) & USBPD_REG_MASK_BMC_PHY) {
prevent_deep_sleep = true;
break;
}
}
/*
* Check if any other ports have a PD port partner connected. Deep
* sleep is forbidden if any PD port partner is connected. Above, we
* only checked for the ITE ports.
*/
if (!prevent_deep_sleep) {
for (; i < board_get_usb_pd_port_count(); i++)
if (pd_capable(i))
prevent_deep_sleep = true;
}
if (prevent_deep_sleep)
disable_sleep(SLEEP_MASK_USB_PD);
else
enable_sleep(SLEEP_MASK_USB_PD);
}
#ifdef CONFIG_USB_PD_TCPMV2
static void it83xx_tcpm_hook_connect(void)
{
@ -806,6 +820,10 @@ static void it83xx_tcpm_hook_connect(void)
* out or the SNK disable detect, so TCPMv1 needn't hook connection.
*/
it83xx_tcpm_switch_plug_out_type(port);
/* Enable PD PHY Tx and Rx module since type-c has connected. */
USBPD_ENABLE_BMC_PHY(port);
set_pd_sleep_mask(port);
}
DECLARE_HOOK(HOOK_USB_PD_CONNECT, it83xx_tcpm_hook_connect, HOOK_PRIO_DEFAULT);
@ -825,6 +843,16 @@ static void it83xx_tcpm_sw_reset(void)
/* exit BIST test data mode */
USBPD_SW_RESET(port);
/*
* Init rx status and disable PD PHY Tx and Rx module for better power
* consumption since type-c has disconnected.
*/
rx_en[port] = 0;
if (IS_ENABLED(CONFIG_USB_PD_DECODE_SOP))
sop_prime_en[port] = 0;
USBPD_DISABLE_BMC_PHY(port);
set_pd_sleep_mask(port);
}
DECLARE_HOOK(HOOK_USB_PD_DISCONNECT, it83xx_tcpm_sw_reset, HOOK_PRIO_DEFAULT);

View File

@ -51,7 +51,7 @@
#define USBPD_REG_MASK_HARD_RESET_DETECT BIT(5)
#define USBPD_REG_MASK_MSG_RX_DONE BIT(4)
#define USBPD_REG_MASK_AUTO_SOFT_RESET_TX_DONE BIT(3)
#define USBPD_REG_MASK_HARD_RESET_TX_DONE BIT(2)
#define USBPD_REG_MASK_HARD_CABLE_RESET_TX_DONE BIT(2)
#define USBPD_REG_MASK_MSG_TX_DONE BIT(1)
#define USBPD_REG_MASK_TIMER_TIMEOUT BIT(0)
#define IT83XX_USBPD_IMR(p) REG8(IT83XX_USBPD_BASE(p)+0x15)
@ -71,6 +71,7 @@
#define USBPD_REG_MASK_SEND_BIST_MODE_2 BIT(5)
#define IT83XX_USBPD_MTSR1(p) REG8(IT83XX_USBPD_BASE(p)+0x1A)
#define IT83XX_USBPD_VDMMCSR(p) REG8(IT83XX_USBPD_BASE(p)+0x1B)
#define USBPD_REG_MASK_HARD_RESET_DECODE BIT(0)
#define IT83XX_USBPD_MRSR(p) REG8(IT83XX_USBPD_BASE(p)+0x1C)
#define USBPD_REG_GET_SOP_TYPE_RX(mrsr) (((mrsr) >> 4) & 0x7)
#define USBPD_REG_MASK_RX_MSG_VALID BIT(0)
@ -350,6 +351,9 @@
/* macros for PD ISR */
#define USBPD_IS_HARD_RESET_DETECT(port) \
IS_MASK_SET(IT83XX_USBPD_ISR(port), USBPD_REG_MASK_HARD_RESET_DETECT)
#define USBPD_IS_HARD_CABLE_RESET_TX_DONE(port) \
IS_MASK_SET(IT83XX_USBPD_ISR(port), \
USBPD_REG_MASK_HARD_CABLE_RESET_TX_DONE)
#define USBPD_IS_TX_DONE(port) \
IS_MASK_SET(IT83XX_USBPD_ISR(port), USBPD_REG_MASK_MSG_TX_DONE)
#define USBPD_IS_RX_DONE(port) \