servo_v4: Support to enable Type C DTS mode

- Defined the config option CONFIG_USB_PD_DTS to board.h.
- Added ccd_set_mode function in board.c
- Removed ccd attach/detach functions from board.c as that function is
- now integrated in the the usb_pd state machine.
- Removed the fixed polarity that was being used in usb_pd_config.h so
  that the DUT port could connect as a SNK device.
- Defined PD_ROLE_DEFAULT to override the value in usb_Pd.h so that
  CHG is SNK and DUT is SRC

This set of changes allows servo_v4 to act like a suzyq. Hoever, PD
messaging is still not supported. The CHG port can still connect as a
SNK device, but VBUS on the DUT is only being provided by the host and
not the CHG port.

BUG=chrome-os-partner:61878
BRANCH=None
TEST=Manual Connected zinger to CHG port and verifed via servo_v4
console that it reached SNK_READY. Connected DUT port to Reef and
verified that it reached SRC_ACCESSORY state and that the correct SBU
polarity was selected and that lsusb shows H1 as a USB device.
Bus 003 Device 042: ID 18d1:5014 Google Inc.

Change-Id: I4a0ab2468f383a3ba4db3a3236bb18df6a2c405a
Signed-off-by: Scott <scollyer@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/428309
Commit-Ready: Scott Collyer <scollyer@chromium.org>
Tested-by: Scott Collyer <scollyer@chromium.org>
Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
This commit is contained in:
Scott
2017-01-13 17:48:31 -08:00
committed by chrome-bot
parent 11704ae6e9
commit a185dee8ca
4 changed files with 122 additions and 275 deletions

View File

@@ -6,6 +6,7 @@
#include "adc.h"
#include "adc_chip.h"
#include "case_closed_debug.h"
#include "common.h"
#include "console.h"
#include "ec_version.h"
@@ -303,186 +304,63 @@ static void init_ioexpander(void)
i2c_write8(1, 0x40, 0x7, 0x0);
}
/* State of CC lines presented to DUT */
/* Dual Rd pulldown, classic debug device. */
#define CCD_ID_RDRD 0
/* RpUSB + Rp1A5, indicates a self powered dongle. */
#define CCD_ID_RPUSB 1
/* One Rd. Device w/o CCD */
#define CCD_ID_NONE 4
static int ccd_id = CCD_ID_NONE;
/* Set CC values according to requested mode. */
static void init_ccd(int mode)
{
int cc1_rd = GPIO_INPUT;
int cc2_rd = GPIO_INPUT;
int cc1_rpusb = GPIO_INPUT;
int cc2_rpusb = GPIO_INPUT;
int cc1_rp1a5 = GPIO_INPUT;
int cc2_rp1a5 = GPIO_INPUT;
int cc1_rp3a0 = GPIO_INPUT;
int cc2_rp3a0 = GPIO_INPUT;
switch (mode) {
case CCD_ID_RDRD:
cc1_rd = GPIO_OUT_LOW;
cc2_rd = GPIO_OUT_LOW;
break;
case CCD_ID_RPUSB:
cc1_rpusb = GPIO_OUT_HIGH;
cc2_rp1a5 = GPIO_OUT_HIGH;
break;
default:
cc1_rd = GPIO_OUT_LOW;
mode = CCD_ID_NONE;
break;
}
gpio_set_flags(GPIO_USB_DUT_CC1_RD, cc1_rd);
gpio_set_flags(GPIO_USB_DUT_CC2_RD, cc2_rd);
gpio_set_flags(GPIO_USB_DUT_CC1_RPUSB, cc1_rpusb);
gpio_set_flags(GPIO_USB_DUT_CC2_RPUSB, cc2_rpusb);
gpio_set_flags(GPIO_USB_DUT_CC1_RP1A5, cc1_rp1a5);
gpio_set_flags(GPIO_USB_DUT_CC2_RP1A5, cc2_rp1a5);
gpio_set_flags(GPIO_USB_DUT_CC1_RP3A0, cc1_rp3a0);
gpio_set_flags(GPIO_USB_DUT_CC2_RP3A0, cc2_rp3a0);
/* Disable CCD until we can detect orientation */
gpio_set_level(GPIO_SBU_MUX_EN, 0);
write_ioexpander(0, 0, 0);
ccd_id = mode;
}
/* Define voltage thresholds for CCD and SBU USB detection */
/* Define voltage thresholds for SBU USB detection */
#define GND_MAX_MV 350
#define PULL_0V35_MV 350
#define PULL_0V55_MV 550
#define PULL_0V9_MV 900
#define PULL_1V1_MV 1100
#define PULL_2V0_MV 2000
#define POWER_MIN_MV 3000
#define USB_HIGH_MV 1500
/* Tracks current state of ccd */
static int ccd_mode;
/* Check if presented CCD was accepted by the device */
static int check_ccd_request(int cc1, int cc2)
static void ccd_measure_sbu(void);
DECLARE_DEFERRED(ccd_measure_sbu);
static void ccd_measure_sbu(void)
{
if ((ccd_id == CCD_ID_RDRD) &&
(cc1 > PULL_0V35_MV) && (cc1 < PULL_0V55_MV) &&
(cc2 > PULL_0V35_MV) && (cc2 < PULL_0V55_MV))
return 1;
int sbu1;
int sbu2;
if ((ccd_id == CCD_ID_RPUSB) &&
(cc1 > PULL_0V35_MV) && (cc1 < PULL_0V55_MV) &&
(cc2 > PULL_0V9_MV) && (cc2 < PULL_1V1_MV))
return 1;
/* Read sbu voltage levels */
sbu1 = adc_read_channel(ADC_SBU1_DET);
sbu2 = adc_read_channel(ADC_SBU2_DET);
return 0;
}
/* Check if CC lines indicate an unplug event */
static int check_usb_disconnect(int cc1, int cc2)
{
if ((cc1 < GND_MAX_MV) && (cc2 < GND_MAX_MV))
return 1;
if ((cc1 > POWER_MIN_MV) && (cc2 > POWER_MIN_MV))
return 1;
return 0;
}
/* Current mode for CCD USB line connection */
/* Cable not plugged in */
#define CCD_MODE_DISCONNECTED 0
/* Cable plugged in, CCD detected in default orientation */
#define CCD_MODE_CONNECTED 1
/* Cable plugged in, CCD detected in flip orientation */
#define CCD_MODE_CONNECTED_FLIP 2
/* Cable plugged in, nothing detected on SBU lines */
#define CCD_MODE_CONNECTED_NONE 3
/* No type-c cable in servo. */
#define CCD_MODE_USBA 4
static int mode = CCD_MODE_DISCONNECTED;
/*
* We don't have an available interrupt, so we'll just check this
* every second. Update state every tick if necessary.
*/
static void usb_sbu_tick(void)
{
int cc1, cc2;
/* Check if we have a CCD cable */
if ((mode == CCD_MODE_USBA) || !gpio_get_level(GPIO_DONGLE_DET)) {
mode = CCD_MODE_USBA;
return;
}
/* Check CC lines via ADC */
cc1 = adc_read_channel(ADC_DUT_CC1_PD);
cc2 = adc_read_channel(ADC_DUT_CC2_PD);
if (mode == CCD_MODE_DISCONNECTED) {
/* Check if both CC lines are pulled, and we are connected */
if (check_ccd_request(cc1, cc2)) {
int sbu1;
int sbu2;
/*
* Give the onboard CCD micro 100ms
* to notice and enable USB, then check adc levels.
*/
usleep(100000);
sbu1 = adc_read_channel(ADC_SBU1_DET);
sbu2 = adc_read_channel(ADC_SBU2_DET);
CPRINTS("CCD: Plug detect cc1:%d cc2:%d "
"sbu1:%d, sbu2:%d",
cc1, cc2, sbu1, sbu2);
/* USB FS pulls one line high for connect request */
if ((sbu1 > USB_HIGH_MV) && (sbu2 < GND_MAX_MV)) {
/* SBU flip = 1 */
write_ioexpander(0, 2, 1);
usleep(10000);
gpio_set_level(GPIO_SBU_MUX_EN, 1);
mode = CCD_MODE_CONNECTED;
CPRINTS("CCD: connected flip");
} else if ((sbu2 > USB_HIGH_MV) &&
(sbu1 < GND_MAX_MV)) {
/* SBU flip = 0 */
write_ioexpander(0, 2, 0);
usleep(10000);
gpio_set_level(GPIO_SBU_MUX_EN, 1);
mode = CCD_MODE_CONNECTED_FLIP;
CPRINTS("CCD: connected noflip");
} else {
mode = CCD_MODE_CONNECTED_NONE;
CPRINTS("CCD: connected none");
}
}
/* USB FS pulls one line high for connect request */
if ((sbu1 > USB_HIGH_MV) && (sbu2 < GND_MAX_MV)) {
/* SBU flip = 1 */
write_ioexpander(0, 2, 1);
msleep(10);
gpio_set_level(GPIO_SBU_MUX_EN, 1);
ccd_mode = CCD_MODE_ENABLED;
CPRINTS("CCD: connected flip");
} else if ((sbu2 > USB_HIGH_MV) &&
(sbu1 < GND_MAX_MV)) {
/* SBU flip = 0 */
write_ioexpander(0, 2, 0);
msleep(10);
gpio_set_level(GPIO_SBU_MUX_EN, 1);
ccd_mode = CCD_MODE_ENABLED;
CPRINTS("CCD: connected noflip");
} else {
/* mode == CCD_MODE_CONNECTED[_FLIP] */
if (check_usb_disconnect(cc1, cc2)) {
/* We are not connected to anything */
/* Turn off CCD */
gpio_set_level(GPIO_SBU_MUX_EN, 0);
CPRINTS("CCD: disconnect");
mode = CCD_MODE_DISCONNECTED;
}
/* Measure again after 100 msec */
hook_call_deferred(&ccd_measure_sbu_data, 100 * MSEC);
}
}
DECLARE_HOOK(HOOK_TICK, usb_sbu_tick, HOOK_PRIO_DEFAULT);
void ccd_set_mode(enum ccd_mode new_mode)
{
if (new_mode == CCD_MODE_ENABLED) {
/* Allow some time following turning on of VBUS */
hook_call_deferred(&ccd_measure_sbu_data,
PD_POWER_SUPPLY_TURN_ON_DELAY);
} else if (new_mode == CCD_MODE_DISABLED) {
/* We are not connected to anything */
/* Disable ccd_measure_sbu deferred call always */
hook_call_deferred(&ccd_measure_sbu_data, -1);
/* Turn off CCD */
gpio_set_level(GPIO_SBU_MUX_EN, 0);
CPRINTS("CCD: disconnect");
ccd_mode = CCD_MODE_DISABLED;
}
}
static void board_init(void)
{
@@ -507,38 +385,7 @@ static void board_init(void)
init_ioexpander();
init_uservo_port();
/*
* TODO(crosbug.com/p/60828): The result of init_ccd() will be
* overwritten when the usb pd protocol state machine attempts to attach
* as SNK or SRC since it will modify the pullup/pulldown resistor on
* the chosen polarity CC line.
*/
/* Enable CCD if type-c */
if (gpio_get_level(GPIO_DONGLE_DET))
init_ccd(CCD_ID_RPUSB);
/* Initialize CCD mode and disable sbu mux. */
ccd_set_mode(CCD_MODE_DISABLED);
}
DECLARE_HOOK(HOOK_INIT, board_init, HOOK_PRIO_DEFAULT);
static int command_ccd(int argc, char **argv)
{
int mode = CCD_ID_NONE;
if (argc < 2)
return EC_ERROR_PARAM_COUNT;
/* Handle requested mode */
if (!strcasecmp(argv[1], "rdrd"))
mode = CCD_ID_RDRD;
else if (!strcasecmp(argv[1], "rpusb"))
mode = CCD_ID_RPUSB;
else if (!strcasecmp(argv[1], "off"))
mode = CCD_ID_NONE;
else
return EC_ERROR_PARAM1;
init_ccd(mode);
ccprintf("DUT CC lines set to %s\n", argv[1]);
return EC_SUCCESS;
}
DECLARE_CONSOLE_COMMAND(ccd, command_ccd,
"[rdrd|rpusb|off]", "Set pullups or pulldowns to indicate CCD");

View File

@@ -78,12 +78,16 @@
#undef CONFIG_TASK_PROFILING
#define CONFIG_USB_POWER_DELIVERY
#define CONFIG_USB_PD_DTS
#define CONFIG_USB_PD_DUAL_ROLE
#define CONFIG_USB_PD_INTERNAL_COMP
#define CONFIG_USB_PD_PORT_COUNT 2
#define CONFIG_USB_PD_TCPC
#define CONFIG_USB_PD_TCPM_STUB
/* Override PD_ROLE_DEFAULT in usb_pd.h */
#define PD_ROLE_DEFAULT(port) ((port) ? PD_ROLE_SOURCE : PD_ROLE_SINK)
/* 3.0A Standard-current Rp */
#define PD_SRC_VNC PD_SRC_DEF_VNC_MV
#define PD_SRC_RD_THRESHOLD PD_SRC_DEF_RD_THRESH_MV

View File

@@ -14,13 +14,6 @@
#ifndef __CROS_EC_USB_PD_CONFIG_H
#define __CROS_EC_USB_PD_CONFIG_H
/*
* For DUT PD port uses a fixed cable and both CC lines are connected. Need to
* choose a default polarity. DUT_CC_POLARITY is this selection.
*/
#define DUT_CC_POLARITY 0
/* NOTES: Servo V4 and glados equivalents:
* Glados Servo V4
* C0 CHG
@@ -226,49 +219,54 @@ static inline void pd_tx_init(void)
static inline void pd_set_host_mode(int port, int enable)
{
if (port == 0) {
/* CHG port. Rd is wired to 5k pulldown. */
/* Can't set host mode. */
/*
* CHG (port == 0) port has fixed Rd attached and therefore can only
* present as a SNK device. If port != DUT (port == 1), then nothing to
* do in this function.
*/
if (!port)
return;
if (enable) {
/*
* Servo_v4 in SRC mode acts as a DTS (debug test
* accessory) and needs to present Rp on both CC
* lines. In order to support orientation detection, the
* values of Rp1/Rp2 need to asymmetric with Rp1 > Rp2.
*/
/* Set Rd for CC1/CC2 to High-Z. */
gpio_set_flags(GPIO_USB_DUT_CC1_RD, GPIO_INPUT);
gpio_set_flags(GPIO_USB_DUT_CC2_RD, GPIO_INPUT);
/*
* TODO(crosbug.com/p/60794): Currently always advertising
* 1.5A. If CHG port is attached then can advertise 3A
* instead. Additionally, if CHG port is not attached and having
* to use host provided vbus, can 1.5A be advertised?
*/
/* Pull up for host mode */
gpio_set_flags(GPIO_USB_DUT_CC1_RP1A5, GPIO_OUTPUT);
gpio_set_level(GPIO_USB_DUT_CC1_RP1A5, 1);
gpio_set_flags(GPIO_USB_DUT_CC2_RPUSB, GPIO_OUTPUT);
gpio_set_level(GPIO_USB_DUT_CC2_RPUSB, 1);
/* Set TX Hi-Z */
gpio_set_flags(GPIO_USB_DUT_CC1_TX_DATA, GPIO_INPUT);
gpio_set_flags(GPIO_USB_DUT_CC2_TX_DATA, GPIO_INPUT);
} else {
if (enable) {
/*
* TODO(crosbug.com/p/60792): Similar to what's done for
* SNK mode, only want to adjust the CC line that
* matches the chosen polarity for the DUT port. Since
* DUT port uses a fixed cable and both CC lines are
* connected will only need to toggle 1 of the CC lines.
*/
/* High-Z is used for host mode. */
gpio_set_flags(GPIO_USB_DUT_CC1_RD, GPIO_INPUT);
gpio_set_flags(GPIO_USB_DUT_CC2_RD, GPIO_INPUT);
/* Pull up for host mode */
gpio_set_flags(GPIO_USB_DUT_CC1_RP1A5, GPIO_OUTPUT);
gpio_set_level(GPIO_USB_DUT_CC1_RP1A5, 1);
gpio_set_flags(GPIO_USB_DUT_CC2_RP1A5, GPIO_OUTPUT);
gpio_set_level(GPIO_USB_DUT_CC2_RP1A5, 1);
/* Set TX Hi-Z */
gpio_set_flags(GPIO_USB_DUT_CC1_TX_DATA, GPIO_INPUT);
gpio_set_flags(GPIO_USB_DUT_CC2_TX_DATA, GPIO_INPUT);
} else {
/* Set RD to High-Z for device mode. */
gpio_set_flags(GPIO_USB_DUT_CC1_RP1A5, GPIO_INPUT);
gpio_set_flags(GPIO_USB_DUT_CC2_RP1A5, GPIO_INPUT);
/*
* TODO(crosbug.com/p/60828): Undo what was done in
* init_ccd.
*/
gpio_set_flags(GPIO_USB_DUT_CC1_RPUSB, GPIO_INPUT);
gpio_set_flags(GPIO_USB_DUT_CC2_RPUSB, GPIO_INPUT);
if (DUT_CC_POLARITY == 0) {
gpio_set_flags(GPIO_USB_DUT_CC1_RD,
GPIO_OUTPUT);
gpio_set_level(GPIO_USB_DUT_CC1_RD, 0);
} else {
gpio_set_flags(GPIO_USB_DUT_CC2_RD,
GPIO_OUTPUT);
gpio_set_level(GPIO_USB_DUT_CC2_RD, 0);
}
}
/* Set Rp for CC1/CC2 to High-Z. */
gpio_set_flags(GPIO_USB_DUT_CC1_RP3A0, GPIO_INPUT);
gpio_set_flags(GPIO_USB_DUT_CC2_RP3A0, GPIO_INPUT);
gpio_set_flags(GPIO_USB_DUT_CC1_RP1A5, GPIO_INPUT);
gpio_set_flags(GPIO_USB_DUT_CC2_RP1A5, GPIO_INPUT);
gpio_set_flags(GPIO_USB_DUT_CC1_RPUSB, GPIO_INPUT);
gpio_set_flags(GPIO_USB_DUT_CC2_RPUSB, GPIO_INPUT);
/* DTS in SNK mode presents Rd on CC1/CC2 */
gpio_set_flags(GPIO_USB_DUT_CC1_RD, GPIO_OUTPUT);
gpio_set_flags(GPIO_USB_DUT_CC2_RD, GPIO_OUTPUT);
gpio_set_level(GPIO_USB_DUT_CC1_RD, 0);
gpio_set_level(GPIO_USB_DUT_CC2_RD, 0);
}
}
@@ -301,21 +299,8 @@ static inline int pd_adc_read(int port, int cc)
if (port == 0)
mv = adc_read_channel(cc ? ADC_CHG_CC2_PD : ADC_CHG_CC1_PD);
else {
/*
* TODO(crosbug.com/p/60792): Only want to read the CC line that
* matches the chosen polarity for DUT port. If not for the
* chosen polarity, then return 0. This only works when the DUT
* port is presenting as a SNK device. Need to fix this so that
* the returned value for the cc line that doesn't match the
* chosen polarity returns 0 for SNK and 3300 for SRC mode.
*/
if (cc == DUT_CC_POLARITY)
mv = adc_read_channel(cc ? ADC_DUT_CC2_PD :
ADC_DUT_CC1_PD);
else
mv = 0;
}
else
mv = adc_read_channel(cc ? ADC_DUT_CC2_PD : ADC_DUT_CC1_PD);
return mv;
}

View File

@@ -59,21 +59,32 @@ void pd_transition_voltage(int idx)
int pd_set_power_supply_ready(int port)
{
/* Port 0 can never provide vbus. */
if (!port)
return EC_ERROR_INVAL;
/*
* TODO(crosbug.com/p/60794): Will likely need to set the GPIOs
* DUT_CHG_EN and HOST_OR_CHG_CTL which control whether DUT port
* provides VBUS from Host or CHG port.
* TODO(crosbug.com/p/60794): For now always assume VBUS is supplied by
* host. No support yet for using CHG VBUS passthru mode.
*/
/*
* Select Host as source for VBUS.
* To select host, set GPIO_HOST_OR_CHG_CTL low. To select CHG as VBUS
* source, then set GPIO_HOST_OR_CHG_CTL high.
*/
gpio_set_level(GPIO_HOST_OR_CHG_CTL, 0);
/* Enable VBUS from the source selected above. */
gpio_set_level(GPIO_DUT_CHG_EN, 1);
return EC_SUCCESS; /* we are ready */
}
void pd_power_supply_reset(int port)
{
/*
* TODO(crosbug.com/p/60794): Will need to set the GPIOs
* DUT_CHG_EN and HOST_OR_CHG_CTL which control whether DUT port
* provides VBUS from Host or CHG port.
*/
/* Disable VBUS */
gpio_set_level(GPIO_DUT_CHG_EN, 0);
}
void pd_set_input_current_limit(int port, uint32_t max_ma,