diff options
Diffstat (limited to 'baseboard/honeybuns/usb_pd_policy.c')
-rw-r--r-- | baseboard/honeybuns/usb_pd_policy.c | 638 |
1 files changed, 0 insertions, 638 deletions
diff --git a/baseboard/honeybuns/usb_pd_policy.c b/baseboard/honeybuns/usb_pd_policy.c deleted file mode 100644 index ef2350a03d..0000000000 --- a/baseboard/honeybuns/usb_pd_policy.c +++ /dev/null @@ -1,638 +0,0 @@ -/* Copyright 2020 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#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 "hooks.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 "usb_tc_sm.h" -#include "usbc_ppc.h" - -#define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args) -#define CPRINTS(format, args...) cprints(CC_USBPD, format, ## args) - -#define MP4245_VOLTAGE_WINDOW BIT(2) -#define MP4245_VOLTAGE_WINDOW_MASK (MP4245_VOLTAGE_WINDOW - 1) - -#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); - -#ifdef BOARD_C1_1A5_LIMIT -const uint32_t pd_src_display_pdo[] = { - [PDO_IDX_5V] = PDO_FIXED(5000, 1500, PDO_FIXED_FLAGS), -}; -#else -const uint32_t pd_src_display_pdo[] = { - [PDO_IDX_5V] = PDO_FIXED(5000, 3000, PDO_FIXED_FLAGS), -}; -#endif - -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); - -static int src_host_pdo_cnt_override; - -#define PD_DR_SWAP_ATTEMPT_MAX 3 -static int pd_dr_swap_attempt_count[CONFIG_USB_PD_PORT_MAX_COUNT]; - -static int command_hostpdo(int argc, char **argv) -{ - char *e; - int limit; - - if (argc >= 2) { - - limit = strtoi(argv[1], &e, 10); - if ((limit < 0) || (limit > PDO_IDX_COUNT)) - return EC_ERROR_PARAM1; - - src_host_pdo_cnt_override = limit; - } - ccprintf("src host pdo override = %d\n", src_host_pdo_cnt_override); - - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(hostpdo, command_hostpdo, - "<0|1|2|3|4>", - "Limit number of PDOs for C0"); - -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); - /* - * This override is only active via a console command. Only used - * for debug to limit the level of VBUS offered to port partner - * if desired. The console command only allows 0 -> - * PDO_IDX_COUNT for this value. - */ - if (src_host_pdo_cnt_override) - pdo_cnt = src_host_pdo_cnt_override; - } else { - *src_pdo = pd_src_display_pdo; - pdo_cnt = ARRAY_SIZE(pd_src_display_pdo); - } - - return pdo_cnt; -} - -/* - * Default Port Discovery DR Swap Policy. - * - * 1) If port == 0 and port data role is DFP, transition to pe_drs_send_swap - * 2) If port == 1 and port data role is UFP, transition to pe_drs_send_swap - */ -__override bool port_discovery_dr_swap_policy(int port, - enum pd_data_role dr, bool dr_swap_flag) -{ - /* - * Port0: test if role is DFP - * Port1: test if role is UFP - */ - enum pd_data_role role_test = - (port == USB_PD_PORT_HOST) ? PD_ROLE_DFP : PD_ROLE_UFP; - - /* - * Request data role swap if not in the port's desired data role and if - * the attempt count is less than the max allowed. This function is - * called for each PE run once in a PD contract. If the port partner - * rejects data role swap requests (eg compliance tester), want to limit - * how many DR swap requests are attempted. - */ - if (dr == role_test && (pd_dr_swap_attempt_count[port]++ < - PD_DR_SWAP_ATTEMPT_MAX)) - return true; - - /* Do not perform a DR swap */ - return false; -} - -/* - * Default Port Discovery VCONN Swap Policy. - * - * 1) No need to Vconn swap. This board does not require any cable information. - */ -__override bool port_discovery_vconn_swap_policy(int port, - bool vconn_swap_flag) -{ - return false; -} - -int pd_check_vconn_swap(int port) -{ - /*TODO: Dock is the Vconn source */ - return 1; -} - -void pd_power_supply_reset(int port) -{ - int prev_en; - - if (port < 0 || port >= CONFIG_USB_PD_PORT_MAX_COUNT) - return; - - if (IS_ENABLED(BOARD_C1_NO_PPC) && port) { - prev_en = c1_ps8805_is_sourcing_vbus(port); - /* Disable VBUS via PPC. */ - c1_ps8805_vbus_source_enable(port, 0); - } else { - prev_en = ppc_is_sourcing_vbus(port); - /* Disable VBUS via PPC. */ - ppc_vbus_source_enable(port, 0); - } - - /* Enable discharge if we were previously sourcing 5V */ - if (prev_en) - pd_set_vbus_discharge(port, 1); - - if (port == USB_PD_PORT_HOST) { - int mv; - int ma; - int unused_mv; - - /* - * Because VBUS on C0 is turned on/off via the PPC, the - * voltage from the mp4245 does not need to be turned off, or - * set to 0V. Instead, reset VBUS voltage to default value - * (fixed 5V SRC_CAP) so VBUS is ready to be applied at the next - * attached.src condition. - */ - pd_extract_pdo_power(pd_src_host_pdo[0], &ma, &mv, - &unused_mv); - mp4245_set_voltage_out(mv); - /* Ensure voltage is back to 5V */ - pd_transition_voltage(1); - } -} - -int pd_set_power_supply_ready(int port) -{ - int rv; - - /* - * Note: For host port, the mp4245 output voltage is set for 5V by - * default and each time VBUS is turned off. VOUT from the mp4245 is - * left enabled as there is a switch (either PPC or discrete) to turn - * VBUS on/off on the wire. - */ - if (IS_ENABLED(BOARD_C1_NO_PPC) && port) - rv = c1_ps8805_vbus_source_enable(port, 1); - else - rv = ppc_vbus_source_enable(port, 1); - - if (rv) - return rv; - - return EC_SUCCESS; -} - -void pd_transition_voltage(int idx) -{ - int port = TASK_ID_TO_PD_PORT(task_get_current()); - int mv; - int target_mv; - int mv_average = 0; - int ma; - int vbus_hi; - int vbus_lo; - int i; - int mv_buffer[MP4245_VOLTAGE_WINDOW]; - - /* Only C0 can provide more than 5V */ - if (port != USB_PD_PORT_HOST) - return; - - /* - * 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, &target_mv, - &mv); - - /* Initialize sample delay buffer */ - for (i = 0; i < MP4245_VOLTAGE_WINDOW; i++) - mv_buffer[i] = 0; - - /* Set VBUS level to value specified in the requested PDO */ - mp4245_set_voltage_out(target_mv); - /* Wait for vbus to be within ~5% of its target value */ - vbus_hi = target_mv + (target_mv >> 4); - vbus_lo = target_mv - (target_mv >> 4); - - for (i = 0; i < 20; i++) { - /* Read current sample */ - mv = 0; - mp3245_get_vbus(&mv, &ma); - /* Add new sample to cicrcular delay buffer */ - mv_buffer[i & MP4245_VOLTAGE_WINDOW_MASK] = mv; - /* - * Don't compute average until sample delay buffer is - * full. - */ - if (i >= (MP4245_VOLTAGE_WINDOW_MASK)) { - int sum = 0; - int j; - - /* Sum the voltage samples */ - for (j = 0; j < MP4245_VOLTAGE_WINDOW; j++) - sum += mv_buffer[j]; - /* Add rounding */ - sum += MP4245_VOLTAGE_WINDOW / 2; - mv_average = sum / MP4245_VOLTAGE_WINDOW; - /* - * Check if average is within the target - * voltage range. - */ - if ((mv_average >= vbus_lo) && - (mv_average <= vbus_hi)) { - CPRINTS("usbc[%d]: VBUS to %d mV in %d steps", - port, target_mv, i); - return; - } - } - - /* - * The voltage ramp from 5V to 20V requires ~30 - * msec. The max loop count and this sleep time gives plenty - * of time for this change. - */ - msleep(2); - } - - CPRINTS("usbc[%d]: Vbus transition timeout: target = %d, measure = %d", - port, target_mv, mv_average); -} - -int pd_snk_is_vbus_provided(int port) -{ - if (IS_ENABLED(BOARD_C1_NO_PPC) && port) - return c1_ps8805_is_vbus_present(port); - else - return ppc_is_vbus_present(port); -} - -__override bool pd_check_vbus_level(int port, enum vbus_level level) -{ - if (level == VBUS_PRESENT) - return pd_snk_is_vbus_provided(port); - else - return !pd_snk_is_vbus_provided(port); -} - -int board_vbus_source_enabled(int port) -{ - if (IS_ENABLED(BOARD_C1_NO_PPC) && port) - return c1_ps8805_is_sourcing_vbus(port); - else - return ppc_is_sourcing_vbus(port); -} - -void pd_set_input_current_limit(int port, uint32_t max_ma, - uint32_t supply_voltage) -{ - -} - -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); - else if (port == 1) - swap = (data_role == PD_ROLE_UFP); - - return swap; -} - -int pd_check_power_swap(int port) -{ - - if (pd_get_power_role(port) == PD_ROLE_SINK) - return 1; - - return 0; -} - -#ifdef BOARD_C1_1A5_LIMIT -__override int typec_get_default_current_limit_rp(int port) -{ - int rp = TYPEC_RP_USB; - - if (port == USB_PD_PORT_HOST) - rp = TYPEC_RP_3A0; - else if (port == USB_PD_PORT_DP) - rp = TYPEC_RP_1A5; - - return rp; -} -#endif - -static void usb_tc_connect(void) -{ - int port = TASK_ID_TO_PD_PORT(task_get_current()); - - /* - * The EC needs to indicate to the USB hub when the host port is - * attached so that the USB-EP can be properly enumerated. GPIO_BPWR_DET - * is used for this purpose. - */ - if (port == USB_PD_PORT_HOST) { - gpio_set_level(GPIO_BPWR_DET, 1); -#ifdef GPIO_UFP_PLUG_DET - gpio_set_level(GPIO_UFP_PLUG_DET, 0); -#endif - } - - /* Clear data role swap attempt counter at each usbc attach */ - pd_dr_swap_attempt_count[port] = 0; -} -DECLARE_HOOK(HOOK_USB_PD_CONNECT, usb_tc_connect, HOOK_PRIO_DEFAULT); - -static void usb_tc_disconnect(void) -{ - int port = TASK_ID_TO_PD_PORT(task_get_current()); - - /* Only the host port disconnect is relevant */ - if (port == USB_PD_PORT_HOST) { - gpio_set_level(GPIO_BPWR_DET, 0); -#ifdef GPIO_UFP_PLUG_DET - gpio_set_level(GPIO_UFP_PLUG_DET, 1); -#endif - } -} -DECLARE_HOOK(HOOK_USB_PD_DISCONNECT, usb_tc_disconnect, HOOK_PRIO_DEFAULT); - -__override bool pd_can_charge_from_device(int port, const int pdo_cnt, - const uint32_t *pdos) -{ - /* - * This function is called to determine if this port can be charged by - * the port partner. We always want to be a power role source, so always - * return false. - */ - - return false; -} - -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, TCPCI_MSG_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_E, - 0, /* DFP pin cfg supported */ - 0, /* usb2.0 signalling in AMode may be req */ - 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); - int mf = dock_get_mf_preference(); - - 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; - /* - * Make sure the MST_LANE_CONTROL gpio is set to match the DP - * pin configuration selected by the host. Note that the mf - * passed into this function reflects the pin configuration - * selected by the host and not the user mf preference which is - * stored in bit 0 of CBI fw_config. - */ - baseboard_set_mst_lane_control(mf); - CPRINTS("DP[%d]: DFP-D selected pin config %s", - port, mf ? "D" : "C"); - } 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); - /* Notify hpd->pd conv that a DP_CONFIG message has been received */ - pd_ufp_enable_hpd_send(port); - - 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; -} |