diff options
-rw-r--r-- | board/plankton/board.c | 87 |
1 files changed, 75 insertions, 12 deletions
diff --git a/board/plankton/board.c b/board/plankton/board.c index 2e5f64418a..d52f94bca5 100644 --- a/board/plankton/board.c +++ b/board/plankton/board.c @@ -40,6 +40,7 @@ static enum typec_cable cable; static int active_cc; static int host_mode; +static int drp_enable; static int sn75dp130_dpcd_init(void); @@ -127,6 +128,7 @@ enum usbc_action { USBC_ACT_CABLE_POLARITY0, USBC_ACT_CABLE_POLARITY1, USBC_ACT_CCD_EN, + USBC_ACT_DRP_TOGGLE, /* Number of USBC actions */ USBC_ACT_COUNT @@ -147,18 +149,27 @@ static void set_active_cc(int cc) { active_cc = cc; + /* + * If DRP mode is enabled, then set both CC lines based + * on the current value of host_mode. If DRP mode is + * disabled then only set the active CC line. + */ /* Pull-up on CC2 */ gpio_set_flags(GPIO_USBC_CC2_HOST, - (cc && host_mode) ? GPIO_OUT_HIGH : GPIO_INPUT); + ((cc || drp_enable) && host_mode) ? + GPIO_OUT_HIGH : GPIO_INPUT); /* Pull-down on CC2 */ gpio_set_flags(GPIO_USBC_CC2_DEVICE_ODL, - (cc && !host_mode) ? GPIO_OUT_LOW : GPIO_INPUT); + ((cc || drp_enable) && !host_mode) ? + GPIO_OUT_LOW : GPIO_INPUT); /* Pull-up on CC1 */ gpio_set_flags(GPIO_USBC_CC1_HOST, - (!cc && host_mode) ? GPIO_OUT_HIGH : GPIO_INPUT); + ((!cc || drp_enable) && host_mode) ? + GPIO_OUT_HIGH : GPIO_INPUT); /* Pull-down on CC1 */ gpio_set_flags(GPIO_USBC_CC1_DEVICE_ODL, - (!cc && !host_mode) ? GPIO_OUT_LOW : GPIO_INPUT); + ((!cc || drp_enable) && !host_mode) ? + GPIO_OUT_LOW : GPIO_INPUT); } /** @@ -235,6 +246,39 @@ static void fake_disconnect_start(void) } DECLARE_DEFERRED(fake_disconnect_start); +/** + * Enable or disable dualrole mode operation. By default Plankton has + * dualrole mode disabled and attempts to connect in a sink role. Console + * commands/button presses can cause it to switch to source_only/sink_only + * modes. + */ +static void update_usbc_dual_role(int dual_role) +{ + if (dual_role == PD_DRP_TOGGLE_ON) { + drp_enable = 1; + /* + * Cable detect is not needed when operating in dualrole mode + * since both CC lines are used and SRC/SNK changes are dictated + * by the USB PD protocol state machine. + */ + hook_call_deferred(detect_cc_cable, -1); + /* Need to make sure both CC lines are set for SNK or SRC. */ + set_active_cc(host_mode); + /* Ensure that PD communication is enabled. */ + pd_comm_enable(1); + } else { + drp_enable = 0; + /* + * Dualrole mode is not active, resume cable detect function + * which controls which CC line is active. + */ + hook_call_deferred(detect_cc_cable, 0); + } + /* Update dual role setting used in USB PD protocol state machine */ + pd_set_dual_role(dual_role); + cprintf(CC_USBPD, "DRP = %d, host_mode = %d\n", drp_enable, host_mode); +} + static void set_usbc_action(enum usbc_action act) { int need_soft_reset; @@ -246,12 +290,12 @@ static void set_usbc_action(enum usbc_action act) case USBC_ACT_20V_TO_DUT: need_soft_reset = gpio_get_level(GPIO_VBUS_CHARGER_EN); board_set_source_cap(src_cap_mapping[act]); - pd_set_dual_role(PD_DRP_FORCE_SOURCE); + update_usbc_dual_role(PD_DRP_FORCE_SOURCE); if (need_soft_reset) pd_soft_reset(); break; case USBC_ACT_DEVICE: - pd_set_dual_role(PD_DRP_FORCE_SINK); + update_usbc_dual_role(PD_DRP_FORCE_SINK); break; case USBC_ACT_USBDP_TOGGLE: was_usb_mode = gpio_get_level(GPIO_USBC_SS_USB_MODE); @@ -314,6 +358,11 @@ static void set_usbc_action(enum usbc_action act) gpio_set_level(GPIO_CASE_CLOSE_EN, 1); gpio_set_level(GPIO_CASE_CLOSE_DFU_L, 1); break; + case USBC_ACT_DRP_TOGGLE: + /* Toggle dualrole mode setting. */ + update_usbc_dual_role(drp_enable ? + PD_DRP_TOGGLE_OFF : PD_DRP_TOGGLE_ON); + break; default: break; } @@ -520,6 +569,8 @@ static int cmd_usbc_action(int argc, char *argv[]) act = USBC_ACT_CABLE_POLARITY0; else if (!strcasecmp(argv[1], "pol1")) act = USBC_ACT_CABLE_POLARITY1; + else if (!strcasecmp(argv[1], "drp")) + act = USBC_ACT_DRP_TOGGLE; else return EC_ERROR_PARAM1; @@ -528,7 +579,7 @@ static int cmd_usbc_action(int argc, char *argv[]) return EC_SUCCESS; } DECLARE_CONSOLE_COMMAND(usbc_action, cmd_usbc_action, - "<5v|12v|20v|ccd|dev|usb|dp|flip|pol0|pol1>", + "<5v|12v|20v|ccd|dev|usb|dp|flip|pol0|pol1|drp>", "Set Plankton type-C port state", NULL); @@ -590,12 +641,20 @@ int board_fake_pd_adc_read(int cc) /* Always disconnected */ return fake_pd_host_mode ? 3000 : 0; } else { - /* Only read the active CC line, fake disconnected on other */ - if (active_cc == cc) + if (drp_enable) { + /* Always read the req CC line when in drp mode */ return adc_read_channel(cc ? ADC_CH_CC2_PD : ADC_CH_CC1_PD); - else - return host_mode ? 3000 : 0; + } else { + /* + * Only read the active CC line, fake disconnected + * on other CC line. */ + if (active_cc == cc) + return adc_read_channel(cc ? ADC_CH_CC2_PD : + ADC_CH_CC1_PD); + else + return host_mode ? 3000 : 0; + } } } @@ -607,7 +666,8 @@ static void board_update_fake_adc_value(int host_mode) void board_pd_set_host_mode(int enable) { - cprintf(CC_USBPD, "Host mode: %d\n", enable); + if (!drp_enable) + cprintf(CC_USBPD, "Host mode: %d\n", enable); if (board_pd_fake_disconnected()) { board_update_fake_adc_value(enable); @@ -647,6 +707,9 @@ static void board_init(void) hpd_prev_ts = now.val; gpio_enable_interrupt(GPIO_DPSRC_HPD); + /* Start up with dualrole mode off */ + drp_enable = 0; + /* Enable interrupts on VBUS transitions. */ gpio_enable_interrupt(GPIO_VBUS_WAKE); |