summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWai-Hong Tam <waihong@google.com>2019-03-28 10:25:46 -0700
committerCommit Bot <commit-bot@chromium.org>2019-06-18 22:39:01 +0000
commit604e42d766c7e903db7b9c9f752a18697744875a (patch)
tree4d939afbcb7ee3a19b8ed1a1e60d3b7085d00362
parent8948d56916c3b72798e14e2c429f2e06bbf599d7 (diff)
downloadchrome-ec-604e42d766c7e903db7b9c9f752a18697744875a.tar.gz
servo_v4: Implement CC detach and fakedisconnect on servo v4
The DUT may have multiple USB Type-C ports. In order to identify a pair of PD port partners, the PD FAFT tests asks one partner to emulate a detach and then checks the other partner if it sees a proper status. This requires to implement a CC detach on servo v4. A console command 'fakedisconnect' (similar to plankton) is introduced to disconnect for a given period and then connect back. BUG=b:131840808 BRANCH=servo TEST=Manuall tested the commands on servo v4 console to emulate detach. . > cc . cc: on . dts mode: on . chg mode: on . chg allowed: on . > pd 1 state . Port C1 CC1, Ena - Role: SRC-UFP State: 23(SRC_READY), Flags: 0x1415e . > cc off . cc: off . dts mode: on . chg mode: on . chg allowed: off . > pd 1 state . Port C1 CC1, Dis - Role: SNK-UFP State: 2(SNK_DISCONNECTED), . Flags: 0x0000 Checked the DUT EC console to verify the port status as detached. . > pd 0 state . Port C0 CC2, Ena - Role: SNK-DFP State: DRP_AUTO_TOGGLE, Flags: 0x0020 Made the servo v4 connect back. . > cc srcdts . cc: on . dts mode: on . chg mode: on . chg allowed: on . > pd 1 state . Port C1 CC1, Ena - Role: SRC-UFP State: 23(SRC_READY), Flags: 0x1415e Checked the DUT EC console to verify the port status as connected. . > pd 0 state . Port C0 CC2, Ena - Role: SNK-DFP State: SNK_READY, Flags: 0x14946 Typed 'fakedisconnect' command to disconnect for a period. . > fakedisconnect 1000 2000 . Fake disconnect for 2000 ms starting in 1000 ms. Verified DUT got disconnected and then connected back. Change-Id: Ie29cfd4f55ac48b593f71d580762ff5e77ee9602 Signed-off-by: Wai-Hong Tam <waihong@google.com> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/1603469 Reviewed-by: Aseda Aboagye <aaboagye@chromium.org> (cherry picked from commit bf5323de2d1a4d184532b9f4af708f314c5d3047) Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/1666348
-rw-r--r--board/servo_v4/usb_pd_config.h12
-rw-r--r--board/servo_v4/usb_pd_policy.c157
2 files changed, 131 insertions, 38 deletions
diff --git a/board/servo_v4/usb_pd_config.h b/board/servo_v4/usb_pd_config.h
index 56c8d3aa02..0e3e0ebc6e 100644
--- a/board/servo_v4/usb_pd_config.h
+++ b/board/servo_v4/usb_pd_config.h
@@ -275,17 +275,7 @@ static inline void pd_config_init(int port, uint8_t power_role)
}
-static inline int pd_adc_read(int port, int cc)
-{
- int mv;
-
- if (port == 0)
- mv = adc_read_channel(cc ? ADC_CHG_CC2_PD : ADC_CHG_CC1_PD);
- else
- mv = adc_read_channel(cc ? ADC_DUT_CC2_PD : ADC_DUT_CC1_PD);
-
- return mv;
-}
+int pd_adc_read(int port, int cc);
#endif /* __CROS_EC_USB_PD_CONFIG_H */
diff --git a/board/servo_v4/usb_pd_policy.c b/board/servo_v4/usb_pd_policy.c
index cb3332a017..3217806308 100644
--- a/board/servo_v4/usb_pd_policy.c
+++ b/board/servo_v4/usb_pd_policy.c
@@ -61,6 +61,8 @@ static int active_charge_port = CHARGE_PORT_NONE;
static enum charge_supplier active_charge_supplier;
static uint8_t vbus_rp = TYPEC_RP_RESERVED;
+/* Flag to emulate detach, i.e. making both CC lines open. */
+static int disable_cc;
/*
* DTS mode: enabled connects resistors to both CC line to activate cr50,
* disabled connects to one only as in the standard USBC cable.
@@ -94,6 +96,9 @@ static int pd_src_rd_threshold[TYPEC_RP_RESERVED] = {
PD_SRC_3_0_RD_THRESH_MV,
};
+/* Saved value for the duration of faking PD disconnect */
+static int fake_pd_disconnect_duration_us;
+
/*
* Set the USB PD max voltage to value appropriate for the board version.
* The red/blue versions of servo_v4 have an ESD between VBUS and CC1/CC2
@@ -308,6 +313,30 @@ int pd_tcpc_cc_ra(int port, int cc_volt, int cc_sel)
return ra;
}
+int pd_adc_read(int port, int cc)
+{
+ int mv;
+
+ if (port == 0)
+ mv = adc_read_channel(cc ? ADC_CHG_CC2_PD : ADC_CHG_CC1_PD);
+ else if (!disable_cc)
+ mv = adc_read_channel(cc ? ADC_DUT_CC2_PD : ADC_DUT_CC1_PD);
+ else {
+ /*
+ * When disable_cc, fake the voltage on CC to 0 to avoid
+ * triggering some debounce logic.
+ *
+ * The servo v4 makes Rd/Rp open but the DUT may present Rd/Rp
+ * alternatively that makes the voltage on CC falls into some
+ * unexpected range and triggers the PD state machine switching
+ * between SNK_DISCONNECTED and SNK_DISCONNECTED_DEBOUNCE.
+ */
+ mv = 0;
+ }
+
+ return mv;
+}
+
static int board_set_rp(int rp)
{
if (disable_dts_mode) {
@@ -389,6 +418,10 @@ int pd_set_rp_rd(int port, int cc_pull, int rp_value)
if (port != 1)
return EC_ERROR_UNIMPLEMENTED;
+ /* CC is disabled for emulating detach. Don't change Rd/Rp. */
+ if (disable_cc)
+ return EC_SUCCESS;
+
/* By default disconnect all Rp/Rd resistors from both CC lines */
/* Set Rd for CC1/CC2 to High-Z. */
gpio_set_flags(GPIO_USB_DUT_CC1_RD, GPIO_INPUT);
@@ -650,6 +683,7 @@ const int supported_modes_cnt = ARRAY_SIZE(supported_modes);
static void print_cc_mode(void)
{
/* Get current CCD status */
+ ccprintf("cc: %s\n", disable_cc ? "off" : "on");
ccprintf("dts mode: %s\n", disable_dts_mode ? "off" : "on");
ccprintf("chg mode: %s\n",
pd_get_dual_role(DUT) == PD_DRP_FORCE_SOURCE ?
@@ -658,44 +692,56 @@ static void print_cc_mode(void)
}
-static void do_cc(int disable_dts_new, int allow_src_new)
+static void do_cc(int disable_cc_new, int disable_dts_new, int allow_src_new)
{
int dualrole;
- if ((disable_dts_new != disable_dts_mode) ||
+ if ((disable_cc_new != disable_cc) ||
+ (disable_dts_new != disable_dts_mode) ||
(allow_src_new != allow_src_mode)) {
- /* Force detach */
- pd_power_supply_reset(DUT);
- /* Always set to 0 here so both CC lines are changed */
- disable_dts_mode = 0;
- allow_src_mode = 0;
+ if (!disable_cc) {
+ /* Force detach */
+ pd_power_supply_reset(DUT);
+ /* Always set to 0 here so both CC lines are changed */
+ disable_dts_mode = 0;
+ allow_src_mode = 0;
- /* Remove Rp/Rd on both CC lines */
- pd_comm_enable(DUT, 0);
- pd_set_rp_rd(DUT, TYPEC_CC_RP, TYPEC_RP_RESERVED);
+ /* Remove Rp/Rd on both CC lines */
+ pd_comm_enable(DUT, 0);
+ pd_set_rp_rd(DUT, TYPEC_CC_RP, TYPEC_RP_RESERVED);
- /* Some time for DUT to detach, use tErrorRecovery */
- msleep(25);
+ /*
+ * If just changing mode (cc keeps enabled), give some
+ * time for DUT to detach, use tErrorRecovery.
+ */
+ if (!disable_cc_new)
+ usleep(PD_T_ERROR_RECOVERY);
+ }
- /* Accept new dts/src value */
+ /* Accept new cc/dts/src value */
+ disable_cc = disable_cc_new;
disable_dts_mode = disable_dts_new;
allow_src_mode = allow_src_new;
- /* Can we charge? */
- dualrole = allow_src_mode && charge_port_is_active();
- pd_set_dual_role(DUT, dualrole ?
- PD_DRP_FORCE_SOURCE : PD_DRP_FORCE_SINK);
+ if (!disable_cc) {
+ /* Can we charge? */
+ dualrole = allow_src_mode && charge_port_is_active();
+ pd_set_dual_role(DUT, dualrole ?
+ PD_DRP_FORCE_SOURCE : PD_DRP_FORCE_SINK);
- /* Present Rp or Rd on CC1 and CC2 based on disable_dts_mode */
- pd_config_init(DUT, dualrole);
- pd_comm_enable(DUT, dualrole);
+ /*
+ * Present Rp or Rd on CC1 and CC2 based on
+ * disable_dts_mode
+ */
+ pd_config_init(DUT, dualrole);
+ pd_comm_enable(DUT, dualrole);
+ }
}
-
- print_cc_mode();
}
static int command_cc(int argc, char **argv)
{
+ int disable_cc_new;
int disable_dts_new;
int allow_src_new;
@@ -704,28 +750,37 @@ static int command_cc(int argc, char **argv)
return EC_SUCCESS;
}
- if (!strcasecmp(argv[1], "src")) {
+ if (!strcasecmp(argv[1], "off")) {
+ disable_cc_new = 1;
+ disable_dts_new = 0;
+ allow_src_new = 0;
+ } else if (!strcasecmp(argv[1], "src")) {
+ disable_cc_new = 0;
disable_dts_new = 1;
allow_src_new = 1;
} else if (!strcasecmp(argv[1], "snk")) {
+ disable_cc_new = 0;
disable_dts_new = 1;
allow_src_new = 0;
} else if (!strcasecmp(argv[1], "srcdts")) {
+ disable_cc_new = 0;
disable_dts_new = 0;
allow_src_new = 1;
} else if (!strcasecmp(argv[1], "snkdts")) {
+ disable_cc_new = 0;
disable_dts_new = 0;
allow_src_new = 0;
} else {
- ccprintf("Try one of src, snk, srcdts, snkdts\n");
+ ccprintf("Try one of off, src, snk, srcdts, snkdts\n");
return EC_ERROR_PARAM2;
}
- do_cc(disable_dts_new, allow_src_new);
+ do_cc(disable_cc_new, disable_dts_new, allow_src_new);
+ print_cc_mode();
return EC_SUCCESS;
}
DECLARE_CONSOLE_COMMAND(cc, command_cc,
- "src|snk|srcdts|snkdts",
+ "off|src|snk|srcdts|snkdts",
"Servo_v4 DTS and CHG mode");
@@ -745,10 +800,58 @@ static int command_dts(int argc, char **argv)
disable_dts_new = val ^ 1;
/* Change dts without changing src. */
- do_cc(disable_dts_new, allow_src_mode);
+ do_cc(disable_cc, disable_dts_new, allow_src_mode);
+ print_cc_mode();
return EC_SUCCESS;
}
DECLARE_CONSOLE_COMMAND(dts, command_dts,
"off|on",
"Servo_v4 DTS mode on/off");
+
+static void fake_disconnect_end(void)
+{
+ /* Reenable CC lines with previous dts and src modes */
+ do_cc(0, disable_dts_mode, allow_src_mode);
+}
+DECLARE_DEFERRED(fake_disconnect_end);
+
+static void fake_disconnect_start(void)
+{
+ /* Disable CC lines */
+ do_cc(1, disable_dts_mode, allow_src_mode);
+
+ hook_call_deferred(&fake_disconnect_end_data,
+ fake_pd_disconnect_duration_us);
+}
+DECLARE_DEFERRED(fake_disconnect_start);
+
+static int cmd_fake_disconnect(int argc, char *argv[])
+{
+ int delay_ms, duration_ms;
+ char *e;
+
+ if (argc < 3)
+ return EC_ERROR_PARAM_COUNT;
+
+ delay_ms = strtoi(argv[1], &e, 0);
+ if (*e || delay_ms < 0)
+ return EC_ERROR_PARAM1;
+ duration_ms = strtoi(argv[2], &e, 0);
+ if (*e || duration_ms < 0)
+ return EC_ERROR_PARAM2;
+
+ /* Cancel any pending function calls */
+ hook_call_deferred(&fake_disconnect_start_data, -1);
+ hook_call_deferred(&fake_disconnect_end_data, -1);
+
+ fake_pd_disconnect_duration_us = duration_ms * MSEC;
+ hook_call_deferred(&fake_disconnect_start_data, delay_ms * MSEC);
+
+ ccprintf("Fake disconnect for %d ms starting in %d ms.\n",
+ duration_ms, delay_ms);
+
+ return EC_SUCCESS;
+}
+DECLARE_CONSOLE_COMMAND(fakedisconnect, cmd_fake_disconnect,
+ "<delay_ms> <duration_ms>", NULL);