diff options
Diffstat (limited to 'common/usb_pd_alt_mode_dfp.c')
-rw-r--r-- | common/usb_pd_alt_mode_dfp.c | 1543 |
1 files changed, 0 insertions, 1543 deletions
diff --git a/common/usb_pd_alt_mode_dfp.c b/common/usb_pd_alt_mode_dfp.c deleted file mode 100644 index d7048f4c8e..0000000000 --- a/common/usb_pd_alt_mode_dfp.c +++ /dev/null @@ -1,1543 +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. - * - * Alternate Mode Downstream Facing Port (DFP) USB-PD module. - */ - -#include "chipset.h" -#include "console.h" -#include "task.h" -#include "task_id.h" -#include "timer.h" -#include "usb_common.h" -#include "usb_charge.h" -#include "usb_dp_alt_mode.h" -#include "usb_mux.h" -#include "usb_pd.h" -#include "usb_pd_tcpm.h" -#include "usb_tbt_alt_mode.h" -#include "usbc_ppc.h" -#include "util.h" - -#ifdef CONFIG_COMMON_RUNTIME -#define CPRINTS(format, args...) cprints(CC_USBPD, format, ## args) -#define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args) -#else -#define CPRINTS(format, args...) -#define CPRINTF(format, args...) -#endif - -#ifndef PORT_TO_HPD -#define PORT_TO_HPD(port) ((port) ? GPIO_USB_C1_DP_HPD : GPIO_USB_C0_DP_HPD) -#endif /* PORT_TO_HPD */ - -/* Tracker for which task is waiting on sysjump prep to finish */ -static volatile task_id_t sysjump_task_waiting = TASK_ID_INVALID; - -/* - * timestamp of the next possible toggle to ensure the 2-ms spacing - * between IRQ_HPD. Since this is used in overridable functions, this - * has to be global. - */ -uint64_t svdm_hpd_deadline[CONFIG_USB_PD_PORT_MAX_COUNT]; - -int dp_flags[CONFIG_USB_PD_PORT_MAX_COUNT]; - -uint32_t dp_status[CONFIG_USB_PD_PORT_MAX_COUNT]; - -/* Console command multi-function preference set for a PD port. */ - -__maybe_unused bool dp_port_mf_allow[CONFIG_USB_PD_PORT_MAX_COUNT] = { - [0 ... CONFIG_USB_PD_PORT_MAX_COUNT - 1] = true}; - - -__overridable const struct svdm_response svdm_rsp = { - .identity = NULL, - .svids = NULL, - .modes = NULL, -}; - -static int pd_get_mode_idx(int port, enum tcpci_msg_type type, - uint16_t svid) -{ - int amode_idx; - struct partner_active_modes *active = - pd_get_partner_active_modes(port, type); - - for (amode_idx = 0; amode_idx < PD_AMODE_COUNT; amode_idx++) { - if (active->amodes[amode_idx].fx && - (active->amodes[amode_idx].fx->svid == svid)) - return amode_idx; - } - return -1; -} - -static int pd_allocate_mode(int port, enum tcpci_msg_type type, - uint16_t svid) -{ - int i, j; - struct svdm_amode_data *modep; - int mode_idx = pd_get_mode_idx(port, type, svid); - const struct pd_discovery *disc = pd_get_am_discovery(port, type); - struct partner_active_modes *active = - pd_get_partner_active_modes(port, type); - assert(active); - - if (mode_idx != -1) - return mode_idx; - - /* There's no space to enter another mode */ - if (active->amode_idx == PD_AMODE_COUNT) { - CPRINTF("ERR:NO AMODE SPACE\n"); - return -1; - } - - /* Allocate ... if SVID == 0 enter default supported policy */ - for (i = 0; i < supported_modes_cnt; i++) { - for (j = 0; j < disc->svid_cnt; j++) { - const struct svid_mode_data *svidp = &disc->svids[j]; - - /* - * Looking for a match between supported_modes and - * discovered SVIDs; must also match the passed-in SVID - * if that was non-zero. Otherwise, go to the next - * discovered SVID. - * TODO(b/155890173): Support AP-directed mode entry - * where the mode is unknown to the TCPM. - */ - if ((svidp->svid != supported_modes[i].svid) || - (svid && (svidp->svid != svid))) - continue; - - modep = &active->amodes[active->amode_idx]; - modep->fx = &supported_modes[i]; - modep->data = &disc->svids[j]; - active->amode_idx++; - return active->amode_idx - 1; - } - } - return -1; -} - -static int validate_mode_request(struct svdm_amode_data *modep, - uint16_t svid, int opos) -{ - if (!modep->fx) - return 0; - - if (svid != modep->fx->svid) { - CPRINTF("ERR:svid r:0x%04x != c:0x%04x\n", - svid, modep->fx->svid); - return 0; - } - - if (opos != modep->opos) { - CPRINTF("ERR:opos r:%d != c:%d\n", - opos, modep->opos); - return 0; - } - - return 1; -} - -void pd_prepare_sysjump(void) -{ - int i; - - /* Exit modes before sysjump so we can cleanly enter again later */ - for (i = 0; i < board_get_usb_pd_port_count(); i++) { - /* - * If the port is not capable of Alternate mode no need to - * send the event. - */ - if (!pd_alt_mode_capable(i)) - continue; - - sysjump_task_waiting = task_get_current(); - task_set_event(PD_PORT_TO_TASK_ID(i), PD_EVENT_SYSJUMP); - task_wait_event_mask(TASK_EVENT_SYSJUMP_READY, -1); - sysjump_task_waiting = TASK_ID_INVALID; - } -} - -/* - * This algorithm defaults to choosing higher pin config over lower ones in - * order to prefer multi-function if desired. - * - * NAME | SIGNALING | OUTPUT TYPE | MULTI-FUNCTION | PIN CONFIG - * ------------------------------------------------------------- - * A | USB G2 | ? | no | 00_0001 - * B | USB G2 | ? | yes | 00_0010 - * C | DP | CONVERTED | no | 00_0100 - * D | PD | CONVERTED | yes | 00_1000 - * E | DP | DP | no | 01_0000 - * F | PD | DP | yes | 10_0000 - * - * if UFP has NOT asserted multi-function preferred code masks away B/D/F - * leaving only A/C/E. For single-output dongles that should leave only one - * possible pin config depending on whether its a converter DP->(VGA|HDMI) or DP - * output. If UFP is a USB-C receptacle it may assert C/D/E/F. The DFP USB-C - * receptacle must always choose C/D in those cases. - */ -int pd_dfp_dp_get_pin_mode(int port, uint32_t status) -{ - struct svdm_amode_data *modep = - pd_get_amode_data(port, TCPCI_MSG_SOP, USB_SID_DISPLAYPORT); - uint32_t mode_caps; - uint32_t pin_caps; - int mf_pref; - - /* - * Default dp_port_mf_allow is true, we allow mf operation - * if UFP_D supports it. - */ - - if (IS_ENABLED(CONFIG_CMD_MFALLOW)) - mf_pref = PD_VDO_DPSTS_MF_PREF(dp_status[port]) && - dp_port_mf_allow[port]; - else - mf_pref = PD_VDO_DPSTS_MF_PREF(dp_status[port]); - - if (!modep) - return 0; - - mode_caps = modep->data->mode_vdo[modep->opos - 1]; - - /* TODO(crosbug.com/p/39656) revisit with DFP that can be a sink */ - pin_caps = PD_DP_PIN_CAPS(mode_caps); - - /* if don't want multi-function then ignore those pin configs */ - if (!mf_pref) - pin_caps &= ~MODE_DP_PIN_MF_MASK; - - /* TODO(crosbug.com/p/39656) revisit if DFP drives USB Gen 2 signals */ - pin_caps &= ~MODE_DP_PIN_BR2_MASK; - - /* if C/D present they have precedence over E/F for USB-C->USB-C */ - if (pin_caps & (MODE_DP_PIN_C | MODE_DP_PIN_D)) - pin_caps &= ~(MODE_DP_PIN_E | MODE_DP_PIN_F); - - /* get_next_bit returns undefined for zero */ - if (!pin_caps) - return 0; - - return 1 << get_next_bit(&pin_caps); -} - -struct svdm_amode_data *pd_get_amode_data(int port, - enum tcpci_msg_type type, uint16_t svid) -{ - int idx = pd_get_mode_idx(port, type, svid); - struct partner_active_modes *active = - pd_get_partner_active_modes(port, type); - assert(active); - - return (idx == -1) ? NULL : &active->amodes[idx]; -} - -/* - * Enter default mode ( payload[0] == 0 ) or attempt to enter mode via svid & - * opos - */ -uint32_t pd_dfp_enter_mode(int port, enum tcpci_msg_type type, - uint16_t svid, int opos) -{ - int mode_idx = pd_allocate_mode(port, type, svid); - struct svdm_amode_data *modep; - uint32_t mode_caps; - - if (mode_idx == -1) - return 0; - modep = &pd_get_partner_active_modes(port, type)->amodes[mode_idx]; - - if (!opos) { - /* choose the lowest as default */ - modep->opos = 1; - } else if (opos <= modep->data->mode_cnt) { - modep->opos = opos; - } else { - CPRINTS("C%d: Invalid opos %d for SVID %x", port, opos, svid); - return 0; - } - - mode_caps = modep->data->mode_vdo[modep->opos - 1]; - if (modep->fx->enter(port, mode_caps) == -1) - return 0; - - /* - * Strictly speaking, this should only happen when the request - * has been ACKed. - * For TCPMV1, still set modal flag pre-emptively. For TCPMv2, the modal - * flag is set when the ENTER command is ACK'd for each alt mode that is - * supported. - */ - if (IS_ENABLED(CONFIG_USB_PD_TCPMV1)) - pd_set_dfp_enter_mode_flag(port, true); - - /* SVDM to send to UFP for mode entry */ - return VDO(modep->fx->svid, 1, CMD_ENTER_MODE | VDO_OPOS(modep->opos)); -} - -/* TODO(b/170372521) : Incorporate exit mode specific changes to DPM SM */ -int pd_dfp_exit_mode(int port, enum tcpci_msg_type type, uint16_t svid, - int opos) -{ - struct svdm_amode_data *modep; - struct partner_active_modes *active = - pd_get_partner_active_modes(port, type); - int idx; - - /* - * Empty svid signals we should reset DFP VDM state by exiting all - * entered modes then clearing state. This occurs when we've - * disconnected or for hard reset. - */ - if (!svid) { - for (idx = 0; idx < PD_AMODE_COUNT; idx++) - if (active->amodes[idx].fx) - active->amodes[idx].fx->exit(port); - - pd_dfp_mode_init(port); - return 0; - } - - /* - * TODO(crosbug.com/p/33946) : below needs revisited to allow multiple - * mode exit. Additionally it should honor OPOS == 7 as DFP's request - * to exit all modes. We currently don't have any UFPs that support - * multiple modes on one SVID. - */ - modep = pd_get_amode_data(port, type, svid); - if (!modep || !validate_mode_request(modep, svid, opos)) - return 0; - - /* call DFPs exit function */ - modep->fx->exit(port); - - pd_set_dfp_enter_mode_flag(port, false); - - /* exit the mode */ - modep->opos = 0; - return 1; -} - -/* - * Check if the SVID has been recorded previously. Some peripherals provide - * duplicated SVID. - */ -static bool is_svid_duplicated(const struct pd_discovery *disc, uint16_t svid) -{ - int i; - - for (i = 0; i < disc->svid_cnt; ++i) - if (disc->svids[i].svid == svid) { - CPRINTF("ERR:SVIDDUP\n"); - return true; - } - - return false; -} - -void dfp_consume_attention(int port, uint32_t *payload) -{ - uint16_t svid = PD_VDO_VID(payload[0]); - int opos = PD_VDO_OPOS(payload[0]); - struct svdm_amode_data *modep = - pd_get_amode_data(port, TCPCI_MSG_SOP, svid); - - if (!modep || !validate_mode_request(modep, svid, opos)) - return; - - if (modep->fx->attention) - modep->fx->attention(port, payload); -} - -void dfp_consume_identity(int port, enum tcpci_msg_type type, int cnt, - uint32_t *payload) -{ - int ptype; - struct pd_discovery *disc; - size_t identity_size; - - if (type == TCPCI_MSG_SOP_PRIME && - !IS_ENABLED(CONFIG_USB_PD_DECODE_SOP)) { - CPRINTF("ERR:Unexpected cable response\n"); - return; - } - - ptype = PD_IDH_PTYPE(payload[VDO_I(IDH)]); - disc = pd_get_am_discovery_and_notify_access(port, type); - identity_size = MIN(sizeof(union disc_ident_ack), - (cnt - 1) * sizeof(uint32_t)); - - /* Note: only store VDOs, not the VDM header */ - memcpy(disc->identity.raw_value, payload + 1, identity_size); - disc->identity_cnt = identity_size / sizeof(uint32_t); - - switch (ptype) { - case IDH_PTYPE_AMA: - /* Leave vbus ON if the following macro is false */ - if (IS_ENABLED(CONFIG_USB_PD_DUAL_ROLE) && - IS_ENABLED(CONFIG_USBC_VCONN_SWAP)) { - /* Adapter is requesting vconn, try to supply it */ - if (PD_VDO_AMA_VCONN_REQ(payload[VDO_I(AMA)])) - pd_try_vconn_src(port); - - /* Only disable vbus if vconn was requested */ - if (PD_VDO_AMA_VCONN_REQ(payload[VDO_I(AMA)]) && - !PD_VDO_AMA_VBUS_REQ(payload[VDO_I(AMA)])) - pd_power_supply_reset(port); - } - break; - default: - break; - } - pd_set_identity_discovery(port, type, PD_DISC_COMPLETE); -} - -void dfp_consume_svids(int port, enum tcpci_msg_type type, int cnt, - uint32_t *payload) -{ - int i; - uint32_t *ptr = payload + 1; - int vdo = 1; - uint16_t svid0, svid1; - struct pd_discovery *disc = - pd_get_am_discovery_and_notify_access(port, type); - - for (i = disc->svid_cnt; i < disc->svid_cnt + 12; i += 2) { - if (i >= SVID_DISCOVERY_MAX) { - CPRINTF("ERR:SVIDCNT\n"); - break; - } - /* - * Verify we're still within the valid packet (count will be one - * for the VDM header + xVDOs) - */ - if (vdo >= cnt) - break; - - svid0 = PD_VDO_SVID_SVID0(*ptr); - if (!svid0) - break; - - if (!is_svid_duplicated(disc, svid0)) - disc->svids[disc->svid_cnt++].svid = svid0; - - svid1 = PD_VDO_SVID_SVID1(*ptr); - if (!svid1) - break; - - if (!is_svid_duplicated(disc, svid1)) - disc->svids[disc->svid_cnt++].svid = svid1; - - ptr++; - vdo++; - } - /* TODO(tbroch) need to re-issue discover svids if > 12 */ - if (i && ((i % 12) == 0)) - CPRINTF("ERR:SVID+12\n"); - - pd_set_svids_discovery(port, type, PD_DISC_COMPLETE); -} - -void dfp_consume_modes(int port, enum tcpci_msg_type type, int cnt, - uint32_t *payload) -{ - int svid_idx; - struct svid_mode_data *mode_discovery = NULL; - struct pd_discovery *disc = - pd_get_am_discovery_and_notify_access(port, type); - uint16_t response_svid = (uint16_t) PD_VDO_VID(payload[0]); - - for (svid_idx = 0; svid_idx < disc->svid_cnt; ++svid_idx) { - uint16_t svid = disc->svids[svid_idx].svid; - - if (svid == response_svid) { - mode_discovery = &disc->svids[svid_idx]; - break; - } - } - if (!mode_discovery) { - const struct svid_mode_data *requested_mode_data = - pd_get_next_mode(port, type); - CPRINTF("C%d: Mode response for undiscovered SVID %x, but TCPM " - "requested SVID %x\n", - port, response_svid, requested_mode_data->svid); - /* - * Although SVIDs discovery seemed like it succeeded before, the - * partner is now responding with undiscovered SVIDs. Discovery - * cannot reasonably continue under these circumstances. - */ - pd_set_modes_discovery(port, type, requested_mode_data->svid, - PD_DISC_FAIL); - return; - } - - mode_discovery->mode_cnt = cnt - 1; - if (mode_discovery->mode_cnt < 1) { - CPRINTF("ERR:NOMODE\n"); - pd_set_modes_discovery(port, type, mode_discovery->svid, - PD_DISC_FAIL); - return; - } - - memcpy(mode_discovery->mode_vdo, &payload[1], - sizeof(uint32_t) * mode_discovery->mode_cnt); - disc->svid_idx++; - pd_set_modes_discovery(port, type, mode_discovery->svid, - PD_DISC_COMPLETE); -} - -int pd_alt_mode(int port, enum tcpci_msg_type type, uint16_t svid) -{ - struct svdm_amode_data *modep = pd_get_amode_data(port, type, svid); - - return (modep) ? modep->opos : -1; -} - -void pd_set_identity_discovery(int port, enum tcpci_msg_type type, - enum pd_discovery_state disc) -{ - struct pd_discovery *pd = - pd_get_am_discovery_and_notify_access(port, type); - - pd->identity_discovery = disc; -} - -enum pd_discovery_state pd_get_identity_discovery(int port, - enum tcpci_msg_type type) -{ - const struct pd_discovery *disc = pd_get_am_discovery(port, type); - - return disc->identity_discovery; -} - -const union disc_ident_ack *pd_get_identity_response(int port, - enum tcpci_msg_type type) -{ - if (type >= DISCOVERY_TYPE_COUNT) - return NULL; - - return &pd_get_am_discovery(port, type)->identity; -} - -uint16_t pd_get_identity_vid(int port) -{ - const union disc_ident_ack *resp = pd_get_identity_response(port, - TCPCI_MSG_SOP); - - return resp->idh.usb_vendor_id; -} - -uint16_t pd_get_identity_pid(int port) -{ - const union disc_ident_ack *resp = pd_get_identity_response(port, - TCPCI_MSG_SOP); - - return resp->product.product_id; -} - -uint8_t pd_get_product_type(int port) -{ - const union disc_ident_ack *resp = pd_get_identity_response(port, - TCPCI_MSG_SOP); - - return resp->idh.product_type; -} - -void pd_set_svids_discovery(int port, enum tcpci_msg_type type, - enum pd_discovery_state disc) -{ - struct pd_discovery *pd = - pd_get_am_discovery_and_notify_access(port, type); - - pd->svids_discovery = disc; -} - -enum pd_discovery_state pd_get_svids_discovery(int port, - enum tcpci_msg_type type) -{ - const struct pd_discovery *disc = pd_get_am_discovery(port, type); - - return disc->svids_discovery; -} - -int pd_get_svid_count(int port, enum tcpci_msg_type type) -{ - const struct pd_discovery *disc = pd_get_am_discovery(port, type); - - return disc->svid_cnt; -} - -uint16_t pd_get_svid(int port, uint16_t svid_idx, enum tcpci_msg_type type) -{ - const struct pd_discovery *disc = pd_get_am_discovery(port, type); - - return disc->svids[svid_idx].svid; -} - -void pd_set_modes_discovery(int port, enum tcpci_msg_type type, - uint16_t svid, enum pd_discovery_state disc) -{ - struct pd_discovery *pd = - pd_get_am_discovery_and_notify_access(port, type); - int svid_idx; - - for (svid_idx = 0; svid_idx < pd->svid_cnt; ++svid_idx) { - struct svid_mode_data *mode_data = &pd->svids[svid_idx]; - - if (mode_data->svid != svid) - continue; - - mode_data->discovery = disc; - return; - } -} - -enum pd_discovery_state pd_get_modes_discovery(int port, - enum tcpci_msg_type type) -{ - const struct svid_mode_data *mode_data = pd_get_next_mode(port, type); - - /* - * If there are no SVIDs for which to discover modes, mode discovery is - * trivially complete. - */ - if (!mode_data) - return PD_DISC_COMPLETE; - - return mode_data->discovery; -} - -int pd_get_mode_vdo_for_svid(int port, enum tcpci_msg_type type, - uint16_t svid, uint32_t *vdo_out) -{ - int idx; - const struct pd_discovery *disc; - - if (type >= DISCOVERY_TYPE_COUNT) - return 0; - - disc = pd_get_am_discovery(port, type); - - for (idx = 0; idx < disc->svid_cnt; ++idx) { - if (pd_get_svid(port, idx, type) == svid) { - memcpy(vdo_out, disc->svids[idx].mode_vdo, - sizeof(uint32_t) * disc->svids[idx].mode_cnt); - return disc->svids[idx].mode_cnt; - } - } - return 0; -} - -const struct svid_mode_data *pd_get_next_mode(int port, - enum tcpci_msg_type type) -{ - const struct pd_discovery *disc = pd_get_am_discovery(port, type); - const struct svid_mode_data *failed_mode_data = NULL; - bool svid_good_discovery = false; - int svid_idx; - - /* Walk through all of the discovery mode entries */ - for (svid_idx = 0; svid_idx < disc->svid_cnt; ++svid_idx) { - const struct svid_mode_data *mode_data = &disc->svids[svid_idx]; - - /* Discovery is needed, so send this one back now */ - if (mode_data->discovery == PD_DISC_NEEDED) - return mode_data; - - /* Discovery already succeeded, save that it was seen */ - if (mode_data->discovery == PD_DISC_COMPLETE) - svid_good_discovery = true; - /* Discovery already failed, save first failure */ - else if (!failed_mode_data) - failed_mode_data = mode_data; - } - - /* If no good entries were located, then return last failed */ - if (!svid_good_discovery) - return failed_mode_data; - - /* - * Mode discovery has been attempted for every discovered SVID (if - * any exist) - */ - return NULL; -} - -const uint32_t *pd_get_mode_vdo(int port, uint16_t svid_idx, - enum tcpci_msg_type type) -{ - const struct pd_discovery *disc = pd_get_am_discovery(port, type); - - return disc->svids[svid_idx].mode_vdo; -} - -bool pd_is_mode_discovered_for_svid(int port, enum tcpci_msg_type type, - uint16_t svid) -{ - const struct pd_discovery *disc = pd_get_am_discovery(port, type); - const struct svid_mode_data *mode_data; - - for (mode_data = disc->svids; mode_data < disc->svids + disc->svid_cnt; - ++mode_data) { - if (mode_data->svid == svid && - mode_data->discovery == PD_DISC_COMPLETE) - return true; - } - - return false; -} - -void notify_sysjump_ready(void) -{ - /* - * If event was set from pd_prepare_sysjump, wake the - * task waiting on us to complete. - */ - if (sysjump_task_waiting != TASK_ID_INVALID) - task_set_event(sysjump_task_waiting, TASK_EVENT_SYSJUMP_READY); -} - -static inline bool is_pd_rev3(int port, enum tcpci_msg_type type) -{ - return pd_get_rev(port, type) == PD_REV30; -} - -/* - * ############################################################################ - * - * (Charge Through) Vconn Powered Device functions - * - * ############################################################################ - */ -bool is_vpd_ct_supported(int port) -{ - const struct pd_discovery *disc = - pd_get_am_discovery(port, TCPCI_MSG_SOP_PRIME); - union vpd_vdo vpd = disc->identity.product_t1.vpd; - - return vpd.ct_support; -} - -uint8_t get_vpd_ct_gnd_impedance(int port) -{ - const struct pd_discovery *disc = - pd_get_am_discovery(port, TCPCI_MSG_SOP_PRIME); - union vpd_vdo vpd = disc->identity.product_t1.vpd; - - return vpd.gnd_impedance; -} - -uint8_t get_vpd_ct_vbus_impedance(int port) -{ - const struct pd_discovery *disc = - pd_get_am_discovery(port, TCPCI_MSG_SOP_PRIME); - union vpd_vdo vpd = disc->identity.product_t1.vpd; - - return vpd.vbus_impedance; -} - -uint8_t get_vpd_ct_current_support(int port) -{ - const struct pd_discovery *disc = - pd_get_am_discovery(port, TCPCI_MSG_SOP_PRIME); - union vpd_vdo vpd = disc->identity.product_t1.vpd; - - return vpd.ct_current_support; -} - -uint8_t get_vpd_ct_max_vbus_voltage(int port) -{ - const struct pd_discovery *disc = - pd_get_am_discovery(port, TCPCI_MSG_SOP_PRIME); - union vpd_vdo vpd = disc->identity.product_t1.vpd; - - return vpd.max_vbus_voltage; -} - -uint8_t get_vpd_ct_vdo_version(int port) -{ - const struct pd_discovery *disc = - pd_get_am_discovery(port, TCPCI_MSG_SOP_PRIME); - union vpd_vdo vpd = disc->identity.product_t1.vpd; - - return vpd.vdo_version; -} - -uint8_t get_vpd_ct_firmware_verion(int port) -{ - const struct pd_discovery *disc = - pd_get_am_discovery(port, TCPCI_MSG_SOP_PRIME); - union vpd_vdo vpd = disc->identity.product_t1.vpd; - - return vpd.firmware_version; -} - -uint8_t get_vpd_ct_hw_version(int port) -{ - const struct pd_discovery *disc = - pd_get_am_discovery(port, TCPCI_MSG_SOP_PRIME); - union vpd_vdo vpd = disc->identity.product_t1.vpd; - - return vpd.hw_version; -} - -/* - * ############################################################################ - * - * Cable communication functions - * - * ############################################################################ - */ -enum idh_ptype get_usb_pd_cable_type(int port) -{ - const struct pd_discovery *disc = - pd_get_am_discovery(port, TCPCI_MSG_SOP_PRIME); - - return disc->identity.idh.product_type; -} - -bool is_usb2_cable_support(int port) -{ - const struct pd_discovery *disc = - pd_get_am_discovery(port, TCPCI_MSG_SOP_PRIME); - - return disc->identity.idh.product_type == IDH_PTYPE_PCABLE || - pd_get_vdo_ver(port, TCPCI_MSG_SOP_PRIME) < VDM_VER20 || - disc->identity.product_t2.a2_rev30.usb_20_support == - USB2_SUPPORTED; -} - -bool is_cable_speed_gen2_capable(int port) -{ - const struct pd_discovery *disc = - pd_get_am_discovery(port, TCPCI_MSG_SOP_PRIME); - - switch (pd_get_rev(port, TCPCI_MSG_SOP_PRIME)) { - case PD_REV20: - return disc->identity.product_t1.p_rev20.ss == - USB_R20_SS_U31_GEN1_GEN2; - - case PD_REV30: - return disc->identity.product_t1.p_rev30.ss == - USB_R30_SS_U32_U40_GEN2 || - disc->identity.product_t1.p_rev30.ss == - USB_R30_SS_U40_GEN3; - default: - return false; - } -} - -bool is_active_cable_element_retimer(int port) -{ - const struct pd_discovery *disc = - pd_get_am_discovery(port, TCPCI_MSG_SOP_PRIME); - - /* Ref: USB PD Spec 2.0 Table 6-29 Active Cable VDO - * Revision 2 Active cables do not have Active element support. - */ - return is_pd_rev3(port, TCPCI_MSG_SOP_PRIME) && - disc->identity.idh.product_type == IDH_PTYPE_ACABLE && - disc->identity.product_t2.a2_rev30.active_elem == - ACTIVE_RETIMER; -} - -/* - * ############################################################################ - * - * Thunderbolt-Compatible functions - * - * ############################################################################ - */ - -uint32_t pd_get_tbt_mode_vdo(int port, enum tcpci_msg_type type) -{ - uint32_t tbt_mode_vdo[PDO_MODES]; - - return pd_get_mode_vdo_for_svid(port, type, USB_VID_INTEL, - tbt_mode_vdo) ? tbt_mode_vdo[0] : 0; -} - -/* TODO (b/148528713): Need to enable Thunderbolt-compatible mode on TCPMv2 */ -void set_tbt_compat_mode_ready(int port) -{ - if (IS_ENABLED(CONFIG_USBC_SS_MUX) && - IS_ENABLED(CONFIG_USB_PD_TBT_COMPAT_MODE)) { - /* Connect the SBU and USB lines to the connector. */ - if (IS_ENABLED(CONFIG_USBC_PPC_SBU)) - ppc_set_sbu(port, 1); - - /* Set usb mux to Thunderbolt-compatible mode */ - usb_mux_set(port, USB_PD_MUX_TBT_COMPAT_ENABLED, - USB_SWITCH_CONNECT, - polarity_rm_dts(pd_get_polarity(port))); - } -} - -/* - * Ref: USB Type-C Cable and Connector Specification - * Figure F-1 TBT3 Discovery Flow - */ -static bool is_tbt_cable_superspeed(int port) -{ - const struct pd_discovery *disc; - - if (!IS_ENABLED(CONFIG_USB_PD_TBT_COMPAT_MODE) || - !IS_ENABLED(CONFIG_USB_PD_DECODE_SOP)) - return false; - - disc = pd_get_am_discovery(port, TCPCI_MSG_SOP_PRIME); - - /* Product type is Active cable, hence don't check for speed */ - if (disc->identity.idh.product_type == IDH_PTYPE_ACABLE) - return true; - - if (disc->identity.idh.product_type != IDH_PTYPE_PCABLE) - return false; - - if (IS_ENABLED(CONFIG_USB_PD_REV30) && - is_pd_rev3(port, TCPCI_MSG_SOP_PRIME)) - return disc->identity.product_t1.p_rev30.ss == - USB_R30_SS_U32_U40_GEN1 || - disc->identity.product_t1.p_rev30.ss == - USB_R30_SS_U32_U40_GEN2 || - disc->identity.product_t1.p_rev30.ss == - USB_R30_SS_U40_GEN3; - - return disc->identity.product_t1.p_rev20.ss == - USB_R20_SS_U31_GEN1 || - disc->identity.product_t1.p_rev20.ss == - USB_R20_SS_U31_GEN1_GEN2; -} - -static enum tbt_compat_cable_speed usb_rev30_to_tbt_speed(enum usb_rev30_ss ss) -{ - switch (ss) { - case USB_R30_SS_U32_U40_GEN1: - return TBT_SS_U31_GEN1; - case USB_R30_SS_U32_U40_GEN2: - return TBT_SS_U32_GEN1_GEN2; - case USB_R30_SS_U40_GEN3: - return TBT_SS_TBT_GEN3; - default: - return TBT_SS_U32_GEN1_GEN2; - } -} - -enum tbt_compat_cable_speed get_tbt_cable_speed(int port) -{ - union tbt_mode_resp_cable cable_mode_resp; - enum tbt_compat_cable_speed max_tbt_speed; - enum tbt_compat_cable_speed cable_tbt_speed; - - if (!is_tbt_cable_superspeed(port)) - return TBT_SS_RES_0; - - cable_mode_resp.raw_value = - pd_get_tbt_mode_vdo(port, TCPCI_MSG_SOP_PRIME); - max_tbt_speed = board_get_max_tbt_speed(port); - - /* - * Ref: TBT4 PD Discovery Flow Application Notes Revision 0.9, Figure 2 - * For passive cable, if cable doesn't support USB_VID_INTEL, enter - * Thunderbolt alternate mode with speed from USB Highest Speed field of - * the Passive Cable VDO - * For active cable, if the cable doesn't support USB_VID_INTEL, do not - * enter Thunderbolt alternate mode. - */ - if (!cable_mode_resp.raw_value) { - const struct pd_discovery *disc; - - if (get_usb_pd_cable_type(port) == IDH_PTYPE_ACABLE) - return TBT_SS_RES_0; - - disc = pd_get_am_discovery(port, TCPCI_MSG_SOP_PRIME); - cable_tbt_speed = - usb_rev30_to_tbt_speed(disc->identity.product_t1.p_rev30.ss); - } else { - cable_tbt_speed = cable_mode_resp.tbt_cable_speed; - } - - return max_tbt_speed < cable_tbt_speed ? - max_tbt_speed : cable_tbt_speed; -} - -int enter_tbt_compat_mode(int port, enum tcpci_msg_type sop, - uint32_t *payload) -{ - union tbt_dev_mode_enter_cmd enter_dev_mode = { .raw_value = 0 }; - union tbt_mode_resp_device dev_mode_resp; - union tbt_mode_resp_cable cable_mode_resp; - enum tcpci_msg_type enter_mode_sop = - sop == TCPCI_MSG_SOP_PRIME_PRIME ? - TCPCI_MSG_SOP_PRIME : sop; - - /* Table F-12 TBT3 Cable Enter Mode Command */ - /* - * The port doesn't query Discover SOP'' to the cable so, the port - * doesn't have opos for SOP''. Hence, send Enter Mode SOP'' with same - * opos and revision as SOP'. - */ - payload[0] = pd_dfp_enter_mode(port, enter_mode_sop, USB_VID_INTEL, 0) | - VDO_CMDT(CMDT_INIT) | - VDO_SVDM_VERS(pd_get_vdo_ver(port, enter_mode_sop)); - - /* - * Enter safe mode before sending Enter mode SOP/SOP'/SOP'' - * Ref: Tiger Lake Platform PD Controller Interface Requirements for - * Integrated USB C, section A.1.2 TBT as DFP. - */ - usb_mux_set_safe_mode(port); - - /* For TBT3 Cable Enter Mode Command, number of Objects is 1 */ - if ((sop == TCPCI_MSG_SOP_PRIME) || - (sop == TCPCI_MSG_SOP_PRIME_PRIME)) - return 1; - - dev_mode_resp.raw_value = pd_get_tbt_mode_vdo(port, TCPCI_MSG_SOP); - cable_mode_resp.raw_value = - pd_get_tbt_mode_vdo(port, TCPCI_MSG_SOP_PRIME); - - /* Table F-13 TBT3 Device Enter Mode Command */ - enter_dev_mode.vendor_spec_b1 = dev_mode_resp.vendor_spec_b1; - enter_dev_mode.vendor_spec_b0 = dev_mode_resp.vendor_spec_b0; - enter_dev_mode.intel_spec_b0 = dev_mode_resp.intel_spec_b0; - - if (get_usb_pd_cable_type(port) == IDH_PTYPE_ACABLE || - cable_mode_resp.tbt_active_passive == TBT_CABLE_ACTIVE) - enter_dev_mode.cable = TBT_ENTER_ACTIVE_CABLE; - - enter_dev_mode.lsrx_comm = cable_mode_resp.lsrx_comm; - enter_dev_mode.retimer_type = cable_mode_resp.retimer_type; - enter_dev_mode.tbt_cable = cable_mode_resp.tbt_cable; - enter_dev_mode.tbt_rounded = cable_mode_resp.tbt_rounded; - enter_dev_mode.tbt_cable_speed = get_tbt_cable_speed(port); - enter_dev_mode.tbt_alt_mode = TBT_ALTERNATE_MODE; - - payload[1] = enter_dev_mode.raw_value; - - /* For TBT3 Device Enter Mode Command, number of Objects are 2 */ - return 2; -} - -enum tbt_compat_rounded_support get_tbt_rounded_support(int port) -{ - union tbt_mode_resp_cable cable_mode_resp = { - .raw_value = pd_get_tbt_mode_vdo(port, TCPCI_MSG_SOP_PRIME) }; - - /* tbt_rounded_support is zero when uninitialized */ - return cable_mode_resp.tbt_rounded; -} - -__overridable enum tbt_compat_cable_speed board_get_max_tbt_speed(int port) -{ - return TBT_SS_TBT_GEN3; -} -/* - * ############################################################################ - * - * USB4 functions - * - * ############################################################################ - */ - -/* - * For Cable rev 3.0: USB4 cable speed is set according to speed supported by - * the port and the response received from the cable, whichever is least. - * - * For Cable rev 2.0: If get_tbt_cable_speed() is less than - * TBT_SS_U31_GEN1, return USB_R30_SS_U2_ONLY speed since the board - * doesn't support superspeed else the USB4 cable speed is set according to - * the cable response. - */ -enum usb_rev30_ss get_usb4_cable_speed(int port) -{ - enum tbt_compat_cable_speed tbt_speed = get_tbt_cable_speed(port); - enum usb_rev30_ss max_usb4_speed; - - - if (tbt_speed < TBT_SS_U31_GEN1) - return USB_R30_SS_U2_ONLY; - - /* - * Converting Thunderbolt-Compatible board speed to equivalent USB4 - * speed. - */ - max_usb4_speed = tbt_speed == TBT_SS_TBT_GEN3 ? - USB_R30_SS_U40_GEN3 : USB_R30_SS_U32_U40_GEN2; - - if ((get_usb_pd_cable_type(port) == IDH_PTYPE_ACABLE) && - is_pd_rev3(port, TCPCI_MSG_SOP_PRIME)) { - const struct pd_discovery *disc = - pd_get_am_discovery(port, TCPCI_MSG_SOP_PRIME); - union active_cable_vdo1_rev30 a_rev30 = - disc->identity.product_t1.a_rev30; - - if (a_rev30.vdo_ver >= VDO_VERSION_1_3) { - return max_usb4_speed < a_rev30.ss ? - max_usb4_speed : a_rev30.ss; - } - } - - return max_usb4_speed; -} - -uint32_t get_enter_usb_msg_payload(int port) -{ - /* - * Ref: USB Power Delivery Specification Revision 3.0, Version 2.0 - * Table 6-47 Enter_USB Data Object - */ - union enter_usb_data_obj eudo; - const struct pd_discovery *disc; - union tbt_mode_resp_cable cable_mode_resp; - - if (!IS_ENABLED(CONFIG_USB_PD_USB4)) - return 0; - - disc = pd_get_am_discovery(port, TCPCI_MSG_SOP_PRIME); - eudo.mode = USB_PD_40; - eudo.usb4_drd_cap = IS_ENABLED(CONFIG_USB_PD_USB4_DRD); - eudo.usb3_drd_cap = IS_ENABLED(CONFIG_USB_PD_USB32_DRD); - eudo.cable_speed = get_usb4_cable_speed(port); - - if (disc->identity.idh.product_type == IDH_PTYPE_ACABLE) { - if (is_pd_rev3(port, TCPCI_MSG_SOP_PRIME)) { - enum retimer_active_element active_element = - disc->identity.product_t2.a2_rev30.active_elem; - eudo.cable_type = active_element == ACTIVE_RETIMER ? - CABLE_TYPE_ACTIVE_RETIMER : - CABLE_TYPE_ACTIVE_REDRIVER; - } else { - cable_mode_resp.raw_value = - pd_get_tbt_mode_vdo(port, TCPCI_MSG_SOP_PRIME); - - eudo.cable_type = - cable_mode_resp.retimer_type == USB_RETIMER ? - CABLE_TYPE_ACTIVE_RETIMER : - CABLE_TYPE_ACTIVE_REDRIVER; - } - } else { - cable_mode_resp.raw_value = - pd_get_tbt_mode_vdo(port, TCPCI_MSG_SOP_PRIME); - - eudo.cable_type = - cable_mode_resp.tbt_active_passive == TBT_CABLE_ACTIVE ? - CABLE_TYPE_ACTIVE_REDRIVER : CABLE_TYPE_PASSIVE; - } - - switch (disc->identity.product_t1.p_rev20.vbus_cur) { - case USB_VBUS_CUR_3A: - eudo.cable_current = USB4_CABLE_CURRENT_3A; - break; - case USB_VBUS_CUR_5A: - eudo.cable_current = USB4_CABLE_CURRENT_5A; - break; - default: - eudo.cable_current = USB4_CABLE_CURRENT_INVALID; - break; - } - eudo.pcie_supported = IS_ENABLED(CONFIG_USB_PD_PCIE_TUNNELING); - eudo.dp_supported = IS_ENABLED(CONFIG_USB_PD_ALT_MODE_DFP); - eudo.tbt_supported = IS_ENABLED(CONFIG_USB_PD_TBT_COMPAT_MODE); - eudo.host_present = 1; - - return eudo.raw_value; -} - -__overridable bool board_is_tbt_usb4_port(int port) -{ - return true; -} - -__overridable void svdm_safe_dp_mode(int port) -{ - /* make DP interface safe until configure */ - dp_flags[port] = 0; - dp_status[port] = 0; - - usb_mux_set_safe_mode(port); -} - -__overridable int svdm_enter_dp_mode(int port, uint32_t mode_caps) -{ - /* - * Don't enter the mode if the SoC is off. - * - * There's no need to enter the mode while the SoC is off; we'll - * actually enter the mode on the chipset resume hook. Entering DP Alt - * Mode twice will confuse some monitors and require and unplug/replug - * to get them to work again. The DP Alt Mode on USB-C spec says that - * if we don't need to maintain HPD connectivity info in a low power - * mode, then we shall exit DP Alt Mode. (This is why we don't enter - * when the SoC is off as opposed to suspend where adding a display - * could cause a wake up.) When in S5->S3 transition state, we - * should treat it as a SoC off state. - */ -#ifdef HAS_TASK_CHIPSET - if (!chipset_in_state(CHIPSET_STATE_ANY_SUSPEND | CHIPSET_STATE_ON)) - return -1; -#endif - - /* - * TCPMv2: Enable logging of CCD line state CCD_MODE_ODL. - * DisplayPort Alternate mode requires that the SBU lines are used for - * AUX communication. - * However, in Chromebooks SBU signals are repurposed as USB2 signals - * for CCD. This functionality is accomplished by override fets whose - * state is controlled by CCD_MODE_ODL. - * - * This condition helps in debugging unexpected AUX timeout issues by - * indicating the state of the CCD override fets. - */ -#ifdef GPIO_CCD_MODE_ODL - if (!gpio_get_level(GPIO_CCD_MODE_ODL)) - CPRINTS("WARNING: Tried to EnterMode DP with [CCD on AUX/SBU]"); -#endif - - /* Only enter mode if device is DFP_D capable */ - if (mode_caps & MODE_DP_SNK) { - svdm_safe_dp_mode(port); - - if (IS_ENABLED(CONFIG_MKBP_EVENT) && - chipset_in_state(CHIPSET_STATE_ANY_SUSPEND)) - /* - * Wake the system up since we're entering DP AltMode. - */ - pd_notify_dp_alt_mode_entry(port); - - return 0; - } - - return -1; -} - -__overridable int svdm_dp_status(int port, uint32_t *payload) -{ - int opos = pd_alt_mode(port, TCPCI_MSG_SOP, USB_SID_DISPLAYPORT); - - payload[0] = VDO(USB_SID_DISPLAYPORT, 1, - CMD_DP_STATUS | VDO_OPOS(opos)); - payload[1] = VDO_DP_STATUS(0, /* HPD IRQ ... not applicable */ - 0, /* HPD level ... not applicable */ - 0, /* exit DP? ... no */ - 0, /* usb mode? ... no */ - 0, /* multi-function ... no */ - (!!(dp_flags[port] & DP_FLAGS_DP_ON)), - 0, /* power low? ... no */ - (!!DP_FLAGS_DP_ON)); - return 2; -}; - -__overridable uint8_t get_dp_pin_mode(int port) -{ - return pd_dfp_dp_get_pin_mode(port, dp_status[port]); -} - -static mux_state_t svdm_dp_get_mux_mode(int port) -{ - int pin_mode = get_dp_pin_mode(port); - /* Default dp_port_mf_allow is true */ - int mf_pref; - - if (IS_ENABLED(CONFIG_CMD_MFALLOW)) - mf_pref = PD_VDO_DPSTS_MF_PREF(dp_status[port]) && - dp_port_mf_allow[port]; - else - mf_pref = PD_VDO_DPSTS_MF_PREF(dp_status[port]); - - /* - * Multi-function operation is only allowed if that pin config is - * supported. - */ - if ((pin_mode & MODE_DP_PIN_MF_MASK) && mf_pref) - return USB_PD_MUX_DOCK; - else - return USB_PD_MUX_DP_ENABLED; -} - -__overridable int svdm_dp_config(int port, uint32_t *payload) -{ - int opos = pd_alt_mode(port, TCPCI_MSG_SOP, USB_SID_DISPLAYPORT); - uint8_t pin_mode = get_dp_pin_mode(port); - mux_state_t mux_mode = svdm_dp_get_mux_mode(port); - /* Default dp_port_mf_allow is true */ - int mf_pref; - - if (IS_ENABLED(CONFIG_CMD_MFALLOW)) - mf_pref = PD_VDO_DPSTS_MF_PREF(dp_status[port]) && - dp_port_mf_allow[port]; - else - mf_pref = PD_VDO_DPSTS_MF_PREF(dp_status[port]); - - if (!pin_mode) - return 0; - - CPRINTS("pin_mode: %x, mf: %d, mux: %d", pin_mode, mf_pref, mux_mode); - - /* - * Place the USB Type-C pins that are to be re-configured to DisplayPort - * Configuration into the Safe state. For USB_PD_MUX_DOCK, the - * superspeed signals can remain connected. For USB_PD_MUX_DP_ENABLED, - * disconnect the superspeed signals here, before the pins are - * re-configured to DisplayPort (in svdm_dp_post_config, when we receive - * the config ack). - */ - if (mux_mode == USB_PD_MUX_DP_ENABLED) - usb_mux_set_safe_mode(port); - - payload[0] = VDO(USB_SID_DISPLAYPORT, 1, - CMD_DP_CONFIG | VDO_OPOS(opos)); - payload[1] = VDO_DP_CFG(pin_mode, /* pin mode */ - 1, /* DPv1.3 signaling */ - 2); /* UFP connected */ - return 2; -}; - -#if defined(CONFIG_USB_PD_DP_HPD_GPIO) && \ - !defined(CONFIG_USB_PD_DP_HPD_GPIO_CUSTOM) -void svdm_set_hpd_gpio(int port, int en) -{ - gpio_set_level(PORT_TO_HPD(port), en); -} - -int svdm_get_hpd_gpio(int port) -{ - return gpio_get_level(PORT_TO_HPD(port)); -} -#endif - -__overridable void svdm_dp_post_config(int port) -{ - mux_state_t mux_mode = svdm_dp_get_mux_mode(port); - /* Connect the SBU and USB lines to the connector. */ - if (IS_ENABLED(CONFIG_USBC_PPC_SBU)) - ppc_set_sbu(port, 1); - usb_mux_set(port, mux_mode, USB_SWITCH_CONNECT, - polarity_rm_dts(pd_get_polarity(port))); - - dp_flags[port] |= DP_FLAGS_DP_ON; - if (!(dp_flags[port] & DP_FLAGS_HPD_HI_PENDING)) - return; - -#ifdef CONFIG_USB_PD_DP_HPD_GPIO - svdm_set_hpd_gpio(port, 1); - - /* set the minimum time delay (2ms) for the next HPD IRQ */ - svdm_hpd_deadline[port] = get_time().val + HPD_USTREAM_DEBOUNCE_LVL; -#endif /* CONFIG_USB_PD_DP_HPD_GPIO */ - - usb_mux_hpd_update(port, USB_PD_MUX_HPD_LVL | - USB_PD_MUX_HPD_IRQ_DEASSERTED); - -#ifdef USB_PD_PORT_TCPC_MST - if (port == USB_PD_PORT_TCPC_MST) - baseboard_mst_enable_control(port, 1); -#endif -} - -__overridable int svdm_dp_attention(int port, uint32_t *payload) -{ - int lvl = PD_VDO_DPSTS_HPD_LVL(payload[1]); - int irq = PD_VDO_DPSTS_HPD_IRQ(payload[1]); -#ifdef CONFIG_USB_PD_DP_HPD_GPIO - int cur_lvl = svdm_get_hpd_gpio(port); -#endif /* CONFIG_USB_PD_DP_HPD_GPIO */ - mux_state_t mux_state; - - dp_status[port] = payload[1]; - - if (chipset_in_state(CHIPSET_STATE_ANY_SUSPEND) && - (irq || lvl)) - /* - * Wake up the AP. IRQ or level high indicates a DP sink is now - * present. - */ - if (IS_ENABLED(CONFIG_MKBP_EVENT)) - pd_notify_dp_alt_mode_entry(port); - - /* Its initial DP status message prior to config */ - if (!(dp_flags[port] & DP_FLAGS_DP_ON)) { - if (lvl) - dp_flags[port] |= DP_FLAGS_HPD_HI_PENDING; - return 1; - } - -#ifdef CONFIG_USB_PD_DP_HPD_GPIO - if (irq && !lvl) { - /* - * IRQ can only be generated when the level is high, because - * the IRQ is signaled by a short low pulse from the high level. - */ - CPRINTF("ERR:HPD:IRQ&LOW\n"); - return 0; /* nak */ - } - - if (irq && cur_lvl) { - uint64_t now = get_time().val; - /* wait for the minimum spacing between IRQ_HPD if needed */ - if (now < svdm_hpd_deadline[port]) - usleep(svdm_hpd_deadline[port] - now); - - /* generate IRQ_HPD pulse */ - svdm_set_hpd_gpio(port, 0); - usleep(HPD_DSTREAM_DEBOUNCE_IRQ); - svdm_set_hpd_gpio(port, 1); - } else { - svdm_set_hpd_gpio(port, lvl); - } - - /* set the minimum time delay (2ms) for the next HPD IRQ */ - svdm_hpd_deadline[port] = get_time().val + HPD_USTREAM_DEBOUNCE_LVL; -#endif /* CONFIG_USB_PD_DP_HPD_GPIO */ - - mux_state = (lvl ? USB_PD_MUX_HPD_LVL : USB_PD_MUX_HPD_LVL_DEASSERTED) | - (irq ? USB_PD_MUX_HPD_IRQ : USB_PD_MUX_HPD_IRQ_DEASSERTED); - usb_mux_hpd_update(port, mux_state); - -#ifdef USB_PD_PORT_TCPC_MST - if (port == USB_PD_PORT_TCPC_MST) - baseboard_mst_enable_control(port, lvl); -#endif - - /* ack */ - return 1; -} - -__overridable void svdm_exit_dp_mode(int port) -{ - dp_flags[port] = 0; - dp_status[port] = 0; -#ifdef CONFIG_USB_PD_DP_HPD_GPIO - svdm_set_hpd_gpio(port, 0); -#endif /* CONFIG_USB_PD_DP_HPD_GPIO */ - usb_mux_hpd_update(port, USB_PD_MUX_HPD_LVL_DEASSERTED | - USB_PD_MUX_HPD_IRQ_DEASSERTED); -#ifdef USB_PD_PORT_TCPC_MST - if (port == USB_PD_PORT_TCPC_MST) - baseboard_mst_enable_control(port, 0); -#endif -} - -__overridable int svdm_enter_gfu_mode(int port, uint32_t mode_caps) -{ - /* Always enter GFU mode */ - return 0; -} - -__overridable void svdm_exit_gfu_mode(int port) -{ -} - -__overridable int svdm_gfu_status(int port, uint32_t *payload) -{ - /* - * This is called after enter mode is successful, send unstructured - * VDM to read info. - */ - pd_send_vdm(port, USB_VID_GOOGLE, VDO_CMD_READ_INFO, NULL, 0); - return 0; -} - -__overridable int svdm_gfu_config(int port, uint32_t *payload) -{ - return 0; -} - -__overridable int svdm_gfu_attention(int port, uint32_t *payload) -{ - return 0; -} - -#ifdef CONFIG_USB_PD_TBT_COMPAT_MODE -__overridable int svdm_tbt_compat_enter_mode(int port, uint32_t mode_caps) -{ - return 0; -} - -__overridable void svdm_tbt_compat_exit_mode(int port) -{ -} - -__overridable int svdm_tbt_compat_status(int port, uint32_t *payload) -{ - return 0; -} - -__overridable int svdm_tbt_compat_config(int port, uint32_t *payload) -{ - return 0; -} - -__overridable int svdm_tbt_compat_attention(int port, uint32_t *payload) -{ - return 0; -} -#endif /* CONFIG_USB_PD_TBT_COMPAT_MODE */ - -/* - * TODO: b:169262276: For TCPMv2, move alternate mode specific entry, exit and - * configuration to Device Policy Manager. - */ -const struct svdm_amode_fx supported_modes[] = { - { - .svid = USB_SID_DISPLAYPORT, - .enter = &svdm_enter_dp_mode, - .status = &svdm_dp_status, - .config = &svdm_dp_config, - .post_config = &svdm_dp_post_config, - .attention = &svdm_dp_attention, - .exit = &svdm_exit_dp_mode, - }, - - { - .svid = USB_VID_GOOGLE, - .enter = &svdm_enter_gfu_mode, - .status = &svdm_gfu_status, - .config = &svdm_gfu_config, - .attention = &svdm_gfu_attention, - .exit = &svdm_exit_gfu_mode, - }, -#ifdef CONFIG_USB_PD_TBT_COMPAT_MODE - { - .svid = USB_VID_INTEL, - .enter = &svdm_tbt_compat_enter_mode, - .status = &svdm_tbt_compat_status, - .config = &svdm_tbt_compat_config, - .attention = &svdm_tbt_compat_attention, - .exit = &svdm_tbt_compat_exit_mode, - }, -#endif /* CONFIG_USB_PD_TBT_COMPAT_MODE */ -}; -const int supported_modes_cnt = ARRAY_SIZE(supported_modes); - -#ifdef CONFIG_CMD_MFALLOW -static int command_mfallow(int argc, char **argv) -{ - char *e; - int port; - - if (argc < 3) - return EC_ERROR_PARAM_COUNT; - - port = strtoi(argv[1], &e, 10); - if (*e || port >= board_get_usb_pd_port_count()) - return EC_ERROR_PARAM2; - - if (!strcasecmp(argv[2], "true")) - dp_port_mf_allow[port] = true; - else if (!strcasecmp(argv[2], "false")) - dp_port_mf_allow[port] = false; - else - return EC_ERROR_PARAM1; - - ccprintf("Port: %d multi function allowed is %s ", port, argv[2]); - return EC_SUCCESS; -} - -DECLARE_CONSOLE_COMMAND(mfallow, command_mfallow, "port [true | false]", - "Controls Multifunction choice during DP Altmode."); -#endif |