summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEdward Hill <ecgh@chromium.org>2018-01-29 11:27:56 -0700
committerchrome-bot <chrome-bot@chromium.org>2018-02-01 21:29:38 -0800
commit5bfeef6bb36f7fe450f87c14e7d2791e0a33406a (patch)
tree0287ab79d2111f7cb70ce9b1648c1793565bb514
parentebb34ee92f06eab6405397a6e5550dd13779c7d7 (diff)
downloadchrome-ec-5bfeef6bb36f7fe450f87c14e7d2791e0a33406a.tar.gz
grunt: Set USB-C DP HPD GPIOs correctly.
Change the EC to drive the Hotplug Detect (HPD) GPIOs. Grunt HW has these driven from EC to SOC, unlike coral which had the TCPCs drive the HPD signals to SOC. BUG=b:71810897 BRANCH=none TEST=external display works using USB-C to DP adapter on both ports Change-Id: I22ec9eecc5bdf9c6463dd3ce208d051faf15c57a Signed-off-by: Edward Hill <ecgh@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/892099 Reviewed-by: Aaron Durbin <adurbin@chromium.org> Reviewed-by: Jett Rink <jettrink@chromium.org>
-rw-r--r--board/grunt/usb_pd_policy.c56
1 files changed, 49 insertions, 7 deletions
diff --git a/board/grunt/usb_pd_policy.c b/board/grunt/usb_pd_policy.c
index 3f873beee4..52f9f9450c 100644
--- a/board/grunt/usb_pd_policy.c
+++ b/board/grunt/usb_pd_policy.c
@@ -313,39 +313,81 @@ static int svdm_dp_config(int port, uint32_t *payload)
return 2;
};
+/*
+ * timestamp of the next possible toggle to ensure the 2-ms spacing
+ * between IRQ_HPD.
+ */
+static uint64_t hpd_deadline[CONFIG_USB_PD_PORT_COUNT];
+
+#define PORT_TO_HPD(port) ((port) ? GPIO_USB_C1_DP_HPD : GPIO_USB_C0_DP_HPD)
static void svdm_dp_post_config(int port)
{
- const struct usb_mux *mux = &usb_muxes[port];
+ const struct usb_mux * const mux = &usb_muxes[port];
dp_flags[port] |= DP_FLAGS_DP_ON;
if (!(dp_flags[port] & DP_FLAGS_HPD_HI_PENDING))
return;
+
+ gpio_set_level(PORT_TO_HPD(port), 1);
+
+ /* set the minimum time delay (2ms) for the next HPD IRQ */
+ hpd_deadline[port] = get_time().val + HPD_USTREAM_DEBOUNCE_LVL;
mux->hpd_update(port, 1, 0);
}
static int svdm_dp_attention(int port, uint32_t *payload)
{
+ int cur_lvl;
int lvl = PD_VDO_DPSTS_HPD_LVL(payload[1]);
int irq = PD_VDO_DPSTS_HPD_IRQ(payload[1]);
- const struct usb_mux *mux = &usb_muxes[port];
+ enum gpio_signal hpd = PORT_TO_HPD(port);
+ const struct usb_mux * const mux = &usb_muxes[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)
dp_flags[port] |= DP_FLAGS_HPD_HI_PENDING;
- return 1;
+ return 1; /* ack */
}
- mux->hpd_update(port, lvl, irq);
- /* ack */
- return 1;
+ if (irq && cur_lvl) {
+ uint64_t now = get_time().val;
+ /* wait for the minimum spacing between IRQ_HPD if needed */
+ if (now < hpd_deadline[port])
+ usleep(hpd_deadline[port] - now);
+
+ /* generate IRQ_HPD pulse */
+ gpio_set_level(hpd, 0);
+ usleep(HPD_DSTREAM_DEBOUNCE_IRQ);
+ gpio_set_level(hpd, 1);
+
+ /* set the minimum time delay (2ms) for the next HPD IRQ */
+ hpd_deadline[port] = get_time().val + HPD_USTREAM_DEBOUNCE_LVL;
+ } else if (irq && !cur_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 */
+ } else {
+ gpio_set_level(hpd, lvl);
+ /* set the minimum time delay (2ms) for the next HPD IRQ */
+ hpd_deadline[port] = get_time().val + HPD_USTREAM_DEBOUNCE_LVL;
+ }
+ mux->hpd_update(port, lvl, irq);
+ return 1; /* ack */
}
static void svdm_exit_dp_mode(int port)
{
- const struct usb_mux *mux = &usb_muxes[port];
+ const struct usb_mux * const mux = &usb_muxes[port];
svdm_safe_dp_mode(port);
+ gpio_set_level(PORT_TO_HPD(port), 0);
mux->hpd_update(port, 0, 0);
}