mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2025-12-27 18:25:05 +00:00
samus_pd: Request different DP pin modes including multi-function.
Previously samus_pd just picked pin mode E without regard to what the UFP was requesting. This change surveys the UFP's DP pin capabilities and then requests the appropriate pin config. Additionally if the UFP supports multi-function and has preferred it during the initial DP status message, samus will configure its type-c mux in 'dock' mode. Signed-off-by: Todd Broch <tbroch@chromium.org> BRANCH=samus BUG=chrome-os-partner:38728 TEST=manual, 1. hoho + samus, pin mode = 'C' 2. dingdong + samus, pin mode = 'E'. 3. apple type-C HDMI multiport + samus, pin mode = 'D' and USB device enumerates as SuperSpeed. 4. plankton + samus w/ patch asserting alternate mode with multi-function preferred sets config to 'F' now and only drives DP out on 2 lanes w/ other two allowing USB key to be seen. Change-Id: Ie4764c33f108e8a88f0052b64ddb96cb92e5a78b Reviewed-on: https://chromium-review.googlesource.com/267796 Commit-Queue: Todd Broch <tbroch@chromium.org> Tested-by: Todd Broch <tbroch@chromium.org> Reviewed-by: Alec Berg <alecaberg@chromium.org> Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
This commit is contained in:
committed by
ChromeOS Commit Bot
parent
fab26ee891
commit
63786f247e
@@ -259,12 +259,15 @@ int pd_custom_vdm(int port, int cnt, uint32_t *payload,
|
||||
}
|
||||
|
||||
static int dp_flags[PD_PORT_COUNT];
|
||||
/* DP Status VDM as returned by UFP */
|
||||
static uint32_t dp_status[PD_PORT_COUNT];
|
||||
|
||||
static void svdm_safe_dp_mode(int port)
|
||||
{
|
||||
/* make DP interface safe until configure */
|
||||
board_set_usb_mux(port, TYPEC_MUX_NONE, pd_get_polarity(port));
|
||||
dp_flags[port] = 0;
|
||||
dp_status[port] = 0;
|
||||
}
|
||||
|
||||
static int svdm_enter_dp_mode(int port, uint32_t mode_caps)
|
||||
@@ -297,10 +300,18 @@ static int svdm_dp_status(int port, uint32_t *payload)
|
||||
static int svdm_dp_config(int port, uint32_t *payload)
|
||||
{
|
||||
int opos = pd_alt_mode(port, USB_SID_DISPLAYPORT);
|
||||
board_set_usb_mux(port, TYPEC_MUX_DP, pd_get_polarity(port));
|
||||
int mf_pref = PD_VDO_DPSTS_MF_PREF(dp_status[port]);
|
||||
int pin_mode = pd_dfp_dp_get_pin_mode(port, dp_status[port]);
|
||||
|
||||
if (!pin_mode)
|
||||
return 0;
|
||||
|
||||
board_set_usb_mux(port, mf_pref ? TYPEC_MUX_DOCK : TYPEC_MUX_DP,
|
||||
pd_get_polarity(port));
|
||||
|
||||
payload[0] = VDO(USB_SID_DISPLAYPORT, 1,
|
||||
CMD_DP_CONFIG | VDO_OPOS(opos));
|
||||
payload[1] = VDO_DP_CFG(MODE_DP_PIN_E, /* UFP_U as UFP_D */
|
||||
payload[1] = VDO_DP_CFG(pin_mode, /* UFP_U as UFP_D */
|
||||
0, /* UFP_U as DFP_D */
|
||||
1, /* DPv1.3 signaling */
|
||||
2); /* UFP_U connected as UFP_D */
|
||||
@@ -335,11 +346,13 @@ DECLARE_DEFERRED(hpd1_irq_deferred);
|
||||
static int svdm_dp_attention(int port, uint32_t *payload)
|
||||
{
|
||||
int cur_lvl;
|
||||
int lvl = PD_VDO_HPD_LVL(payload[1]);
|
||||
int irq = PD_VDO_HPD_IRQ(payload[1]);
|
||||
int lvl = PD_VDO_DPSTS_HPD_LVL(payload[1]);
|
||||
int irq = PD_VDO_DPSTS_HPD_IRQ(payload[1]);
|
||||
enum gpio_signal hpd = PORT_TO_HPD(port);
|
||||
cur_lvl = gpio_get_level(hpd);
|
||||
|
||||
dp_status[port] = payload[1];
|
||||
|
||||
/* Its initial DP status message prior to config */
|
||||
if (!(dp_flags[port] & DP_FLAGS_DP_ON)) {
|
||||
if (lvl)
|
||||
|
||||
@@ -406,6 +406,53 @@ static void dfp_consume_attention(int port, uint32_t *payload)
|
||||
modep->fx->attention(port, payload);
|
||||
}
|
||||
|
||||
/*
|
||||
* This algorithm defaults to choosing higher pin config over lower ones. Pin
|
||||
* configs are organized in pairs with the following breakdown.
|
||||
*
|
||||
* 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 someone creates a multi-output dongle presumably they would need
|
||||
* to either offer different mode capabilities depending upon connection type or
|
||||
* the DFP would need additional system policy to expose those options.
|
||||
*/
|
||||
int pd_dfp_dp_get_pin_mode(int port, uint32_t status)
|
||||
{
|
||||
struct svdm_amode_data *modep = get_modep(port, USB_SID_DISPLAYPORT);
|
||||
uint32_t mode_caps;
|
||||
uint32_t pin_caps;
|
||||
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_VDO_MODE_DP_SRCP(mode_caps);
|
||||
|
||||
/* if don't want multi-function then ignore those pin configs */
|
||||
if (!PD_VDO_DPSTS_MF_PREF(status))
|
||||
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;
|
||||
|
||||
/* get_next_bit returns undefined for zero */
|
||||
if (!pin_caps)
|
||||
return 0;
|
||||
|
||||
return 1 << get_next_bit(&pin_caps);
|
||||
}
|
||||
|
||||
int pd_dfp_exit_mode(int port, uint16_t svid, int opos)
|
||||
{
|
||||
struct svdm_amode_data *modep;
|
||||
|
||||
@@ -487,12 +487,22 @@ struct pd_policy {
|
||||
(((snkp) & 0xff) << 16 | ((srcp) & 0xff) << 8 \
|
||||
| ((usb) & 1) << 7 | ((gdr) & 1) << 6 | ((sign) & 0xF) << 2 \
|
||||
| ((sdir) & 0x3))
|
||||
#define PD_VDO_MODE_DP_SNKP(x) (((x) >> 16) & 0x3f)
|
||||
#define PD_VDO_MODE_DP_SRCP(x) (((x) >> 8) & 0x3f)
|
||||
|
||||
#define MODE_DP_PIN_A 0x01
|
||||
#define MODE_DP_PIN_B 0x02
|
||||
#define MODE_DP_PIN_C 0x04
|
||||
#define MODE_DP_PIN_D 0x08
|
||||
#define MODE_DP_PIN_E 0x10
|
||||
#define MODE_DP_PIN_F 0x20
|
||||
|
||||
/* Pin configs B/D/F support multi-function */
|
||||
#define MODE_DP_PIN_MF_MASK 0x2a
|
||||
/* Pin configs A/B support BR2 signaling levels */
|
||||
#define MODE_DP_PIN_BR2_MASK 0x3
|
||||
/* Pin configs C/D/E/F support DP signaling levels */
|
||||
#define MODE_DP_PIN_DP_MASK 0x3c
|
||||
|
||||
#define MODE_DP_V13 0x1
|
||||
#define MODE_DP_GEN2 0x2
|
||||
@@ -520,8 +530,9 @@ struct pd_policy {
|
||||
| ((usbc) & 1) << 5 | ((mf) & 1) << 4 | ((en) & 1) << 3 \
|
||||
| ((lp) & 1) << 2 | ((conn & 0x3) << 0))
|
||||
|
||||
#define PD_VDO_HPD_IRQ(x) ((x >> 8) & 1)
|
||||
#define PD_VDO_HPD_LVL(x) ((x >> 7) & 1)
|
||||
#define PD_VDO_DPSTS_HPD_IRQ(x) (((x) >> 8) & 1)
|
||||
#define PD_VDO_DPSTS_HPD_LVL(x) (((x) >> 7) & 1)
|
||||
#define PD_VDO_DPSTS_MF_PREF(x) (((x) >> 4) & 1)
|
||||
|
||||
#define HPD_DEBOUNCE_LVL (100*MSEC)
|
||||
#define HPD_DEBOUNCE_IRQ (2*MSEC)
|
||||
@@ -1018,6 +1029,15 @@ int pd_custom_flash_vdm(int port, int cnt, uint32_t *payload);
|
||||
*/
|
||||
uint32_t pd_dfp_enter_mode(int port, uint16_t svid, int opos);
|
||||
|
||||
/**
|
||||
* Get DisplayPort pin mode for DFP to request from UFP's capabilities.
|
||||
*
|
||||
* @param port USB-C port number.
|
||||
* @param status DisplayPort Status VDO.
|
||||
* @return one-hot PIN config to request.
|
||||
*/
|
||||
int pd_dfp_dp_get_pin_mode(int port, uint32_t status);
|
||||
|
||||
/**
|
||||
* Exit alternate mode on DFP
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user