diff options
Diffstat (limited to 'board/plankton/usb_pd_policy.c')
-rw-r--r-- | board/plankton/usb_pd_policy.c | 156 |
1 files changed, 155 insertions, 1 deletions
diff --git a/board/plankton/usb_pd_policy.c b/board/plankton/usb_pd_policy.c index 59a37c6922..f510dc7268 100644 --- a/board/plankton/usb_pd_policy.c +++ b/board/plankton/usb_pd_policy.c @@ -14,6 +14,7 @@ #include "timer.h" #include "util.h" #include "usb_pd.h" +#include "version.h" #define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args) #define CPRINTS(format, args...) cprints(CC_USBPD, format, ## args) @@ -45,6 +46,9 @@ const uint32_t pd_snk_pdo[] = { }; const int pd_snk_pdo_cnt = ARRAY_SIZE(pd_snk_pdo); +/* Whether alternate mode has been entered or not */ +static int alt_mode; + void board_set_source_cap(enum board_src_cap cap) { pd_src_pdo_idx = cap; @@ -155,7 +159,157 @@ void pd_check_dr_role(int port, int dr_role, int flags) pd_request_data_swap(port); } +/* ----------------- Vendor Defined Messages ------------------ */ +const uint32_t vdo_idh = VDO_IDH(0, /* data caps as USB host */ + 0, /* data caps as USB device */ + IDH_PTYPE_AMA, /* Alternate mode */ + 1, /* supports alt modes */ + USB_VID_GOOGLE); + +const uint32_t vdo_product = VDO_PRODUCT(CONFIG_USB_PID, CONFIG_USB_BCD_DEV); + +const uint32_t vdo_ama = VDO_AMA(CONFIG_USB_PD_IDENTITY_HW_VERS, + CONFIG_USB_PD_IDENTITY_SW_VERS, + 0, 0, 0, 0, /* SS[TR][12] */ + 0, /* Vconn power */ + 0, /* Vconn power required */ + 1, /* Vbus power required */ + AMA_USBSS_BBONLY /* USB SS support */); + +static int svdm_response_identity(int port, uint32_t *payload) +{ + payload[VDO_I(IDH)] = vdo_idh; + payload[VDO_I(CSTAT)] = VDO_CSTAT(0); + payload[VDO_I(PRODUCT)] = vdo_product; + payload[VDO_I(AMA)] = vdo_ama; + return VDO_I(AMA) + 1; +} + +static int svdm_response_svids(int port, uint32_t *payload) +{ + payload[1] = VDO_SVID(USB_SID_DISPLAYPORT, 0); + return 2; +} + +/* + * Will only ever be a single mode for this UFP_D device as it has no real USB + * support making it only PIN_E configureable + */ +#define MODE_CNT 1 +#define OPOS 1 + +const uint32_t vdo_dp_mode[MODE_CNT] = { + VDO_MODE_DP(0, /* UFP pin cfg supported : none */ + MODE_DP_PIN_E, /* DFP pin cfg supported */ + 1, /* no usb2.0 signalling in AMode */ + CABLE_PLUG, /* its a plug */ + 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 (gpio_get_level(GPIO_USBC_SS_USB_MODE)) + return 0; /* nak */ + + if (PD_VDO_VID(payload[0]) != USB_SID_DISPLAYPORT) + return 0; /* nak */ + + memcpy(payload + 1, vdo_dp_mode, sizeof(vdo_dp_mode)); + return MODE_CNT + 1; +} + +static int dp_status(int port, uint32_t *payload) +{ + int opos = PD_VDO_OPOS(payload[0]); + int hpd = gpio_get_level(GPIO_DPSRC_HPD); + if (opos != OPOS) + return 0; /* nak */ + + payload[1] = VDO_DP_STATUS(0, /* IRQ_HPD */ + (hpd == 1), /* HPD_HI|LOW */ + 0, /* request exit DP */ + 0, /* request exit USB */ + 0, /* MF pref */ + !gpio_get_level(GPIO_USBC_SS_USB_MODE), + 0, /* power low */ + 0x2); + return 2; +} + +static int dp_config(int port, uint32_t *payload) +{ + if (PD_DP_CFG_DPON(payload[1])) + gpio_set_level(GPIO_USBC_SS_USB_MODE, 0); + return 1; +} + +static int svdm_enter_mode(int port, uint32_t *payload) +{ + int usb_mode = gpio_get_level(GPIO_USBC_SS_USB_MODE); + + /* SID & mode request is valid */ + if ((PD_VDO_VID(payload[0]) != USB_SID_DISPLAYPORT) || + (PD_VDO_OPOS(payload[0]) != OPOS)) + return 0; /* will generate NAK */ + + if (usb_mode) { + CPRINTS("Toggle USB_MODE if you want DP & re-connect"); + return 0; + } + + alt_mode = OPOS; + return 1; +} + +int pd_alt_mode(int port, uint16_t svid) +{ + return alt_mode; +} + +static int svdm_exit_mode(int port, uint32_t *payload) +{ + alt_mode = 0; + /* + * Don't actually toggle GPIO_USBC_SS_USB_MODE since its manually + * controlled by operator. + */ + return 1; /* Must return ACK */ +} + +static struct amode_fx dp_fx = { + .status = &dp_status, + .config = &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) { - return 0; + int cmd = PD_VDO_CMD(payload[0]); + int rsize = 1; + CPRINTF("VDM/%d [%d] %08x\n", cnt, cmd, payload[0]); + + *rpayload = payload; + switch (cmd) { + case VDO_CMD_VERSION: + memcpy(payload + 1, &version_data.version, 24); + rsize = 7; + break; + default: + rsize = 0; + } + + CPRINTS("DONE"); + /* respond (positively) to the request */ + payload[0] |= VDO_SRC_RESPONDER; + + return rsize; } |