diff options
author | Todd Broch <tbroch@chromium.org> | 2015-04-28 14:42:59 -0700 |
---|---|---|
committer | ChromeOS Commit Bot <chromeos-commit-bot@chromium.org> | 2015-04-30 02:31:18 +0000 |
commit | 63786f247e2f8a058465b75cd476ef0c7ec5979f (patch) | |
tree | 8c380b1dbf448fc70b159d9872329f1d0eabd6ae | |
parent | fab26ee8914ad9f111d982388aeec61c13d6b1c6 (diff) | |
download | chrome-ec-63786f247e2f8a058465b75cd476ef0c7ec5979f.tar.gz |
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>
-rw-r--r-- | board/samus_pd/usb_pd_policy.c | 21 | ||||
-rw-r--r-- | common/usb_pd_policy.c | 47 | ||||
-rw-r--r-- | include/usb_pd.h | 24 |
3 files changed, 86 insertions, 6 deletions
diff --git a/board/samus_pd/usb_pd_policy.c b/board/samus_pd/usb_pd_policy.c index 59530116c9..a8b1f1a4b5 100644 --- a/board/samus_pd/usb_pd_policy.c +++ b/board/samus_pd/usb_pd_policy.c @@ -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) diff --git a/common/usb_pd_policy.c b/common/usb_pd_policy.c index 9d12b48434..bd0915a50b 100644 --- a/common/usb_pd_policy.c +++ b/common/usb_pd_policy.c @@ -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; diff --git a/include/usb_pd.h b/include/usb_pd.h index 3c0c48e07a..30e25d949a 100644 --- a/include/usb_pd.h +++ b/include/usb_pd.h @@ -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) @@ -1019,6 +1030,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 * * @param port USB-C port number |