summaryrefslogtreecommitdiff
path: root/baseboard/honeybuns
diff options
context:
space:
mode:
authorScott Collyer <scollyer@google.com>2021-02-16 13:38:33 -0800
committerCommit Bot <commit-bot@chromium.org>2021-03-24 23:33:07 +0000
commit2cee0e2eb293cea2ccc1ae782de85480dc04d808 (patch)
treeaf410ddfd0b033f7029aafadc8de03effbb65e67 /baseboard/honeybuns
parent1403ddcbbdea6a55db88465659af5f0cc79ace82 (diff)
downloadchrome-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.c8
-rw-r--r--baseboard/honeybuns/baseboard.h31
-rw-r--r--baseboard/honeybuns/usb_pd_policy.c345
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;
+}