diff options
author | Scott Collyer <scollyer@google.com> | 2021-02-16 13:38:33 -0800 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2021-03-24 23:33:07 +0000 |
commit | 2cee0e2eb293cea2ccc1ae782de85480dc04d808 (patch) | |
tree | af410ddfd0b033f7029aafadc8de03effbb65e67 /baseboard/honeybuns | |
parent | 1403ddcbbdea6a55db88465659af5f0cc79ace82 (diff) | |
download | chrome-ec-2cee0e2eb293cea2ccc1ae782de85480dc04d808.tar.gz |
honeybuns: Add full usb-pd support for C0
This CL adds config options and board level structs to fully support
USB-PD on port C0 for both gingerbread and quiche.
This includes all the svdm response functions required for support of
DP Alt-mode as a UFP_D. This also includes honeybuns specific version
of usb-pd policy functions.
BUG=b:175660576
BRANCH=None
TEST=Verify that C0 port can establish PD contract, enter ALT-DP mode
and extend display over DP/HDMI connectors.
Signed-off-by: Scott Collyer <scollyer@google.com>
Change-Id: I11edee85e63381f00114e9fbe012a37fd8174279
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2699455
Tested-by: Scott Collyer <scollyer@chromium.org>
Reviewed-by: Diana Z <dzigterman@chromium.org>
Commit-Queue: Scott Collyer <scollyer@chromium.org>
Diffstat (limited to 'baseboard/honeybuns')
-rw-r--r-- | baseboard/honeybuns/baseboard.c | 8 | ||||
-rw-r--r-- | baseboard/honeybuns/baseboard.h | 31 | ||||
-rw-r--r-- | baseboard/honeybuns/usb_pd_policy.c | 345 |
3 files changed, 365 insertions, 19 deletions
diff --git a/baseboard/honeybuns/baseboard.c b/baseboard/honeybuns/baseboard.c index 4b256b6aa3..3edbc2bf3e 100644 --- a/baseboard/honeybuns/baseboard.c +++ b/baseboard/honeybuns/baseboard.c @@ -8,7 +8,10 @@ #include "gpio.h" #include "hooks.h" #include "i2c.h" +#include "usb_pd.h" +#include "system.h" #include "timer.h" +#include "util.h" #define CPRINTS(format, args...) cprints(CC_SYSTEM, format, ## args) #define CPRINTF(format, args...) cprintf(CC_SYSTEM, format, ## args) @@ -42,7 +45,10 @@ static void baseboard_init(void) CPRINTS("board: Power rails enabled"); #ifdef SECTION_IS_RW - + /* Force TC state machine to start in TC_ERROR_RECOVERY */ + system_clear_reset_flags(EC_RESET_FLAG_POWER_ON); + /* Make certain SN5S330 PPC does full initialization */ + system_set_reset_flags(EC_RESET_FLAG_EFS); #else /* Set up host port usbc to present Rd on CC lines */ if(baseboard_usbc_init(USB_PD_PORT_HOST)) diff --git a/baseboard/honeybuns/baseboard.h b/baseboard/honeybuns/baseboard.h index 32ecf32d23..1e7a7faba1 100644 --- a/baseboard/honeybuns/baseboard.h +++ b/baseboard/honeybuns/baseboard.h @@ -87,6 +87,7 @@ #define CONFIG_CROS_BOARD_INFO #define CONFIG_BOARD_VERSION_CBI #define CONFIG_CMD_CBI +#define CONFIG_CMD_CBI_SET /* USB Configuration */ #define CONFIG_USB @@ -127,30 +128,34 @@ enum usb_strings { #define CONFIG_USB_DRP_ACC_TRYSRC /* No AP on any honeybuns variants */ #undef CONFIG_USB_PD_HOST_CMD - -/* TODO(b/167711550): Temporarily support type-c mode only */ -#undef CONFIG_USB_PRL_SM -#undef CONFIG_USB_PE_SM - -#define CONFIG_USB_PD_DUAL_ROLE #define CONFIG_USB_PD_PORT_MAX_COUNT 1 +#define CONFIG_USB_PD_ALT_MODE +#define CONFIG_USB_PD_ALT_MODE_DFP +#define CONFIG_USB_PD_CUSTOM_PDO +#define CONFIG_USB_PD_ALT_MODE_UFP_DP +#define CONFIG_USB_PD_DUAL_ROLE +#define CONFIG_USB_PD_REV30 #define CONFIG_USB_PD_TCPM_MUX +#define CONFIG_USB_PD_TCPM_PS8805 #define CONFIG_USB_PD_TCPM_STM32GX #define CONFIG_USB_PD_TCPM_TCPCI #define CONFIG_USB_PD_DECODE_SOP - #define CONFIG_USB_PD_VBUS_DETECT_PPC #define CONFIG_USB_PD_DISCHARGE_PPC #define CONFIG_USBC_PPC_SN5S330 #define CONFIG_USBC_PPC_VCONN #define CONFIG_USBC_PPC_DEDICATED_INT -#define CONFIG_CMD_PPC_DUMP +#define CONFIG_USBC_VCONN +#define CONFIG_USBC_VCONN_SWAP +#define CONFIG_USBC_SS_MUX +#define CONFIG_USBC_SS_MUX_UFP_USB3 +#define CONFIG_HAS_TASK_PD_INT #define CONFIG_STM32G4_UCPD_DEBUG +#define CONFIG_CMD_PPC_DUMP +#define CONFIG_CMD_TCPC_DUMP -/* TODO(b/167711550): Temporary, will be replaced by correct mux config */ -#define CONFIG_USBC_SS_MUX -#define CONFIG_USB_MUX_VIRTUAL +#define CONFIG_MP4245 #else /* RO Specific Config Options */ @@ -179,9 +184,9 @@ enum usb_strings { #define CONFIG_SHA256 /* Define typical operating power and max power. */ -#define PD_MAX_VOLTAGE_MV 20000 +#define PD_MAX_VOLTAGE_MV 5000 #define PD_MAX_CURRENT_MA 3000 -#define PD_MAX_POWER_MW 45000 +#define PD_MAX_POWER_MW 15000 #define PD_OPERATING_POWER_MW 15000 /* TODO(b:147314141): Verify these timings */ diff --git a/baseboard/honeybuns/usb_pd_policy.c b/baseboard/honeybuns/usb_pd_policy.c index 0bf90995de..b638b8536d 100644 --- a/baseboard/honeybuns/usb_pd_policy.c +++ b/baseboard/honeybuns/usb_pd_policy.c @@ -5,18 +5,60 @@ #include "common.h" #include "console.h" +#include "chip/stm32/ucpd-stm32gx.h" +#include "cros_board_info.h" +#include "driver/mp4245.h" #include "driver/tcpm/tcpci.h" +#include "driver/mp4245.h" +#include "task.h" +#include "timer.h" +#include "usb_common.h" +#include "usb_mux.h" #include "usb_pd.h" +#include "usb_pd_dp_ufp.h" #include "usbc_ppc.h" #define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args) #define CPRINTS(format, args...) cprints(CC_USBPD, format, ## args) -/* - * TODO(b/167711550): These 4 functions need to be implemented for honeybuns - * and are required to build with TCPMv2 enabled. Currently, they only allow the - * build to work. They will be implemented in a subsequent CL. - */ +#define PDO_FIXED_FLAGS (PDO_FIXED_DUAL_ROLE | PDO_FIXED_DATA_SWAP |\ + PDO_FIXED_COMM_CAP | PDO_FIXED_UNCONSTRAINED) + +/* Voltage indexes for the PDOs */ +enum volt_idx { + PDO_IDX_5V = 0, + PDO_IDX_9V = 1, + PDO_IDX_15V = 2, + PDO_IDX_20V = 3, + PDO_IDX_COUNT +}; + +/* PDOs */ +const uint32_t pd_src_host_pdo[] = { + [PDO_IDX_5V] = PDO_FIXED(5000, 3000, PDO_FIXED_FLAGS), + [PDO_IDX_9V] = PDO_FIXED(9000, 3000, 0), + [PDO_IDX_15V] = PDO_FIXED(15000, 3000, 0), + [PDO_IDX_20V] = PDO_FIXED(20000, 3000, 0), +}; +BUILD_ASSERT(ARRAY_SIZE(pd_src_host_pdo) == PDO_IDX_COUNT); + +/* PDOs */ +const uint32_t pd_snk_pdo[] = { + [PDO_IDX_5V] = PDO_FIXED(5000, 0, PDO_FIXED_FLAGS), +}; +const int pd_snk_pdo_cnt = ARRAY_SIZE(pd_snk_pdo); + +int dpm_get_source_pdo(const uint32_t **src_pdo, const int port) +{ + int pdo_cnt = 0; + + if (port == USB_PD_PORT_HOST) { + *src_pdo = pd_src_host_pdo; + pdo_cnt = ARRAY_SIZE(pd_src_host_pdo); + } + + return pdo_cnt; +} int pd_check_vconn_swap(int port) { @@ -39,12 +81,25 @@ void pd_power_supply_reset(int port) /* Enable discharge if we were previously sourcing 5V */ if (prev_en) pd_set_vbus_discharge(port, 1); + + if (port == USB_PD_PORT_HOST) { + /* Turn off voltage output from buck-boost */ + mp4245_votlage_out_enable(0); + /* Reset VBUS voltage to default value (fixed 5V SRC_CAP) */ + pd_transition_voltage(1); + } } int pd_set_power_supply_ready(int port) { int rv; + if (port == USB_PD_PORT_HOST) { + /* Ensure buck-boost is enabled and Vout is on */ + mp4245_votlage_out_enable(1); + msleep(MP4245_VOUT_5V_DELAY_MS); + } + /* * Default operation of buck-boost is 5v/3.6A. * Turn on the PPC Provide Vbus. @@ -56,6 +111,43 @@ int pd_set_power_supply_ready(int port) return EC_SUCCESS; } +void pd_transition_voltage(int idx) +{ + int port = TASK_ID_TO_PD_PORT(task_get_current()); + + if (port == USB_PD_PORT_HOST) { + int mv; + int ma; + int vbus_hi; + int vbus_lo; + int i; + + /* + * Set the VBUS output voltage and current limit to the values specified + * by the PDO requested by sink. Note that USB PD uses idx = 1 for 1st + * PDO of SRC_CAP which must always be 5V fixed supply. + */ + pd_extract_pdo_power(pd_src_host_pdo[idx - 1], &ma, &mv); + + /* Set VBUS level to value specified in the requested PDO */ + mp4245_set_voltage_out(mv); + /* Wait for vbus to be within ~5% of its target value */ + vbus_hi = mv + (mv >> 4); + vbus_lo = mv - (mv >> 4); + + for (i = 0; i < 20; i++) { + int rv; + + rv = mp3245_get_vbus(&mv, &ma); + if ((rv == EC_SUCCESS) && (mv >= vbus_lo) && + (mv <= vbus_hi)) + return; + + msleep(2); + } + } +} + int pd_snk_is_vbus_provided(int port) { return ppc_is_vbus_present(port); @@ -71,3 +163,246 @@ void pd_set_input_current_limit(int port, uint32_t max_ma, { } + +int pd_check_data_swap(int port, + enum pd_data_role data_role) +{ + int swap = 0; + + if (port == 0) + swap = (data_role == PD_ROLE_DFP); + + return swap; +} + +int pd_check_power_swap(int port) +{ + + if (pd_get_power_role(port) == PD_ROLE_SINK) + return 1; + + return 0; +} + +static int vdm_is_dp_enabled(int port) +{ + mux_state_t mux_state = usb_mux_get(port); + + return !!(mux_state & USB_PD_MUX_DP_ENABLED); +} + +/* ----------------- Vendor Defined Messages ------------------ */ + +const uint32_t vdo_idh = VDO_IDH(0, /* data caps as USB host */ + 1, /* data caps as USB device */ + IDH_PTYPE_HUB, /* UFP product type usbpd hub */ + 1, /* supports alt modes */ + USB_VID_GOOGLE); + +static const uint32_t vdo_idh_rev30 = VDO_IDH_REV30( + 0, /* Data caps as USB host */ + 1, /* Data caps as USB device */ + IDH_PTYPE_HUB, + 1, /* Supports alt modes */ + IDH_PTYPE_DFP_UNDEFINED, + USB_TYPEC_RECEPTACLE, + USB_VID_GOOGLE); + +const uint32_t vdo_product = VDO_PRODUCT(CONFIG_USB_PID, CONFIG_USB_BCD_DEV); + +static const uint32_t vdo_ufp1 = VDO_UFP1( + (VDO_UFP1_CAPABILITY_USB20 + | VDO_UFP1_CAPABILITY_USB32), + USB_TYPEC_RECEPTACLE, + VDO_UFP1_ALT_MODE_RECONFIGURE, + USB_R30_SS_U32_U40_GEN2); + +static int svdm_response_identity(int port, uint32_t *payload) +{ + int vdo_count; + + /* Verify that SVID is PD SID */ + if (PD_VDO_VID(payload[0]) != USB_SID_PD) { + return 0; + } + + /* Cstat and Product VDOs don't depend on spec revision */ + payload[VDO_INDEX_CSTAT] = VDO_CSTAT(0); + payload[VDO_INDEX_PRODUCT] = vdo_product; + + if (pd_get_rev(port, TCPC_TX_SOP) == PD_REV30) { + /* PD Revision 3.0 */ + payload[VDO_INDEX_IDH] = vdo_idh_rev30; + payload[VDO_INDEX_PTYPE_UFP1_VDO] = vdo_ufp1; + vdo_count = VDO_INDEX_PTYPE_UFP1_VDO; + } else { + payload[VDO_INDEX_IDH] = vdo_idh; + vdo_count = VDO_INDEX_PRODUCT; + } + + /* Adjust VDO count for VDM header */ + return vdo_count + 1; +} + +static int svdm_response_svids(int port, uint32_t *payload) +{ + /* Verify that SVID is PD SID */ + if (PD_VDO_VID(payload[0]) != USB_SID_PD) { + return 0; + } + + payload[1] = USB_SID_DISPLAYPORT << 16; + /* number of data objects VDO header + 1 SVID for DP */ + return 2; +} + +#define OPOS_DP 1 + +const uint32_t vdo_dp_modes[1] = { + VDO_MODE_DP(/* Must support C and E. D is required for 2 lanes */ + MODE_DP_PIN_C | MODE_DP_PIN_D | MODE_DP_PIN_D, + 0, /* DFP pin cfg supported */ + 1, /* no usb2.0 signalling in AMode */ + CABLE_RECEPTACLE, /* its a receptacle */ + MODE_DP_V13, /* DPv1.3 Support, no Gen2 */ + MODE_DP_SNK) /* Its a sink only */ +}; + +static int svdm_response_modes(int port, uint32_t *payload) +{ + if (PD_VDO_VID(payload[0]) == USB_SID_DISPLAYPORT) { + memcpy(payload + 1, vdo_dp_modes, sizeof(vdo_dp_modes)); + return ARRAY_SIZE(vdo_dp_modes) + 1; + } else { + return 0; /* nak */ + } +} + +static int amode_dp_status(int port, uint32_t *payload) +{ + int opos = PD_VDO_OPOS(payload[0]); + int hpd = gpio_get_level(GPIO_DP_HPD); + uint32_t fw_config; + int mf = 0; + int rv; + + /* MF (multi function) preferece is indicated by bit 0 of the fw_config + * data field. If this data field does not exist, then default to 4 lane + * mode. + */ + rv = cbi_get_fw_config(&fw_config); + if (!rv) + mf = fw_config & 1; + + if (opos != OPOS_DP) + return 0; /* nak */ + + payload[1] = VDO_DP_STATUS(0, /* IRQ_HPD */ + (hpd == 1), /* HPD_HI|LOW */ + 0, /* request exit DP */ + 0, /* request exit USB */ + mf, /* MF pref */ + vdm_is_dp_enabled(port), + 0, /* power low */ + 0x2); + return 2; +} + +static void svdm_configure_demux(int port, int enable, int mf) +{ + mux_state_t demux = usb_mux_get(port); + + if (enable) { + demux |= USB_PD_MUX_DP_ENABLED; + /* 4 lane mode if MF is not preferred */ + if (!mf) + demux &= ~USB_PD_MUX_USB_ENABLED; + } else { + demux &= ~USB_PD_MUX_DP_ENABLED; + demux |= USB_PD_MUX_USB_ENABLED; + } + + /* Configure demux for 2/4 lane DP and USB3 configuration */ + usb_mux_set(port, demux, USB_SWITCH_CONNECT, pd_get_polarity(port)); +} + +static int amode_dp_config(int port, uint32_t *payload) +{ + uint32_t dp_config = payload[1]; + int mf; + + /* + * Check pin assignment selected by DFP_D to determine if 2 lane or 4 + * lane DP ALT-MODe is required. (note PIN_C is for 4 lane and PIN_D is + * for 2 lane mode). + */ + mf = ((dp_config >> 8) & 0xff) == MODE_DP_PIN_D ? 1 : 0; + /* Configure demux for DP mode */ + svdm_configure_demux(port, 1, mf); + + return 1; +} + +static int svdm_enter_mode(int port, uint32_t *payload) +{ + int rv = 0; /* will generate a NAK */ + + /* SID & mode request is valid */ + if ((PD_VDO_VID(payload[0]) == USB_SID_DISPLAYPORT) && + (PD_VDO_OPOS(payload[0]) == OPOS_DP)) { + + /* Store valid object position to indicate mode is active */ + pd_ufp_set_dp_opos(port, OPOS_DP); + + /* Entering ALT-DP mode, enable DP connection in demux */ + usb_pd_hpd_converter_enable(1); + + /* ACK response has 1 VDO */ + rv = 1; + } + + CPRINTS("svdm_enter[%d]: svid = %x, ret = %d", port, + PD_VDO_VID(payload[0]), rv); + + return rv; +} + +static int svdm_exit_mode(int port, uint32_t *payload) +{ + int opos = pd_ufp_get_dp_opos(port); + + if ((PD_VDO_VID(payload[0]) == USB_SID_DISPLAYPORT) && + (opos == OPOS_DP)) { + /* Clear mode active object position */ + pd_ufp_set_dp_opos(port, 0); + /* Configure demux to disable DP mode */ + svdm_configure_demux(port, 0, 0); + usb_pd_hpd_converter_enable(0); + + return 1; + } else { + CPRINTF("Unknown exit mode req:0x%08x\n", payload[0]); + return 0; + } +} + +static struct amode_fx dp_fx = { + .status = &amode_dp_status, + .config = &amode_dp_config, +}; + +const struct svdm_response svdm_rsp = { + .identity = &svdm_response_identity, + .svids = &svdm_response_svids, + .modes = &svdm_response_modes, + .enter_mode = &svdm_enter_mode, + .amode = &dp_fx, + .exit_mode = &svdm_exit_mode, +}; + +int pd_custom_vdm(int port, int cnt, uint32_t *payload, + uint32_t **rpayload) +{ + /* We don't support, so ignore this message */ + return 0; +} |