diff options
author | Todd Broch <tbroch@chromium.org> | 2015-01-07 21:18:01 -0800 |
---|---|---|
committer | ChromeOS Commit Bot <chromeos-commit-bot@chromium.org> | 2015-01-09 05:40:13 +0000 |
commit | a2720a0f68bbadfabdacfad3411175733c0c4098 (patch) | |
tree | 989f167a05b2db5d41a21db0df1cc6f0b47e0b90 | |
parent | ccb46f6d8e9c141f22c9d9cfe25dfcd1d433e8a4 (diff) | |
download | chrome-ec-a2720a0f68bbadfabdacfad3411175733c0c4098.tar.gz |
pd: Queue initial DFP HPD till after DP Config VDM.
VESA DisplayPort Alt Mode on USB Type-C Standard specifies:
When DisplayPort Configuration is not selected (and the converter is
driving its HPD output low), the converter shall track the current
state of HPD, ready for appropriate indication when DisplayPort
Configuration is subsequently selected.
Not only are we violating specification here but it also causes a race
between enabling DPout muxes to AUX line which in turn causes GPU to
timeout trying to read EDID/DPCD on occasion.
Change adds post_config function for DFPs alternate mode and in the
case of DP it sets the dp_on flag there. This allows attention
function to correctly defer HPD_HI that may accompany 'DP status' VDM
to be queued (deferred) until such time that AUX muxes are enabled
properly.
Signed-off-by: Todd Broch <tbroch@chromium.org>
BRANCH=samus
BUG=chrome-os-partner:35219
TEST=manual, using hoho & dingdong
With kernel bootarg drm.debug=0x6 following cases all show these
drm debug lines:
[drm:i915_hotplug_work_func], Connector DP-2 (pin 5) received
hotplug event.
[drm:intel_dp_get_dpcd], DPCD: 12 14 c4 01 01 00 01 00 02 02 06 00
00 00 00
[drm:intel_hpd_irq_event], [CONNECTOR:38:DP-2] status updated from
disconnected to connected
case1: boot connected to external display
case2: attach dongle to external display then samus
case3: attach dongle to samus then to external display
case4: connect/disconnect rapidly on type-C side
case5: connect/disconnect rapidly on external display side.
Change-Id: I40eab797fdd5090c8ad13fae2cd053b740d9a307
Reviewed-on: https://chromium-review.googlesource.com/239420
Trybot-Ready: Todd Broch <tbroch@chromium.org>
Tested-by: Todd Broch <tbroch@chromium.org>
Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
Commit-Queue: Todd Broch <tbroch@chromium.org>
-rw-r--r-- | board/samus_pd/usb_pd_policy.c | 32 | ||||
-rw-r--r-- | common/usb_pd_policy.c | 3 | ||||
-rw-r--r-- | include/usb_pd.h | 5 |
3 files changed, 35 insertions, 5 deletions
diff --git a/board/samus_pd/usb_pd_policy.c b/board/samus_pd/usb_pd_policy.c index 8ba4d7a327..ca16c5759d 100644 --- a/board/samus_pd/usb_pd_policy.c +++ b/board/samus_pd/usb_pd_policy.c @@ -17,6 +17,7 @@ #include "timer.h" #include "util.h" #include "usb_pd.h" +#include "usb_pd_config.h" #define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args) #define CPRINTS(format, args...) cprints(CC_USBPD, format, ## args) @@ -215,10 +216,13 @@ int pd_custom_vdm(int port, int cnt, uint32_t *payload, return 0; } +static int dp_flags[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; } static int svdm_enter_dp_mode(int port, uint32_t mode_caps) @@ -232,8 +236,6 @@ static int svdm_enter_dp_mode(int port, uint32_t mode_caps) return -1; } -static int dp_on; - static int svdm_dp_status(int port, uint32_t *payload) { payload[0] = VDO(USB_SID_DISPLAYPORT, 1, @@ -243,16 +245,15 @@ static int svdm_dp_status(int port, uint32_t *payload) 0, /* exit DP? ... no */ 0, /* usb mode? ... no */ 0, /* multi-function ... no */ - dp_on, + (!!(dp_flags[port] & DP_FLAGS_DP_ON)), 0, /* power low? ... no */ - dp_on); + (!!(dp_flags[port] & DP_FLAGS_DP_ON))); return 2; }; static int svdm_dp_config(int port, uint32_t *payload) { board_set_usb_mux(port, TYPEC_MUX_DP, pd_get_polarity(port)); - dp_on = 1; payload[0] = VDO(USB_SID_DISPLAYPORT, 1, CMD_DP_CONFIG | VDO_OPOS(pd_alt_mode(port))); payload[1] = VDO_DP_CFG(MODE_DP_PIN_E, /* sink pins */ @@ -262,6 +263,18 @@ static int svdm_dp_config(int port, uint32_t *payload) return 2; }; +static void svdm_dp_post_config(int port) +{ + dp_flags[port] |= DP_FLAGS_DP_ON; + if (!(dp_flags[port] & DP_FLAGS_HPD_HI_PENDING)) + return; + + if (port) + gpio_set_level(GPIO_USB_C1_DP_HPD, 1); + else + gpio_set_level(GPIO_USB_C0_DP_HPD, 1); +} + static void hpd0_irq_deferred(void) { gpio_set_level(GPIO_USB_C0_DP_HPD, 1); @@ -284,6 +297,14 @@ static int svdm_dp_attention(int port, uint32_t *payload) int irq = PD_VDO_HPD_IRQ(payload[1]); enum gpio_signal hpd = PORT_TO_HPD(port); cur_lvl = gpio_get_level(hpd); + + /* 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; + } + if (irq & cur_lvl) { gpio_set_level(hpd, 0); /* 250 usecs is minimum, 2msec is max */ @@ -343,6 +364,7 @@ const struct svdm_amode_fx supported_modes[] = { .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, }, diff --git a/common/usb_pd_policy.c b/common/usb_pd_policy.c index b9ac431d58..05c9363de8 100644 --- a/common/usb_pd_policy.c +++ b/common/usb_pd_policy.c @@ -509,6 +509,9 @@ int pd_svdm(int port, int cnt, uint32_t *payload, uint32_t **rpayload) rsize = 0; break; case CMD_DP_CONFIG: + if (AMODE_VALID(port) && + pe[port].amode.fx->post_config) + pe[port].amode.fx->post_config(port); /* no response after DFPs ack */ rsize = 0; break; diff --git a/include/usb_pd.h b/include/usb_pd.h index 8e7fac1c66..7220f74d7d 100644 --- a/include/usb_pd.h +++ b/include/usb_pd.h @@ -176,6 +176,7 @@ struct svdm_amode_fx { int (*enter)(int port, uint32_t mode_caps); int (*status)(int port, uint32_t *payload); int (*config)(int port, uint32_t *payload); + void (*post_config)(int port); int (*attention)(int port, uint32_t *payload); void (*exit)(int port); }; @@ -200,6 +201,10 @@ enum hpd_event { hpd_irq, }; +/* DisplayPort flags */ +#define DP_FLAGS_DP_ON (1 << 0) /* Display port mode is on */ +#define DP_FLAGS_HPD_HI_PENDING (1 << 1) /* Pending HPD_HI */ + /* Policy structure for driving alternate mode */ struct pd_policy { /* index of svid currently being operated on */ |