summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin K Wong <kevin.k.wong@intel.com>2017-04-06 22:39:01 -0700
committerchrome-bot <chrome-bot@chromium.org>2017-05-29 03:28:25 -0700
commit03a665939f8adef0f8fd5a170f859210f65d2c54 (patch)
treeb9da51dc9bdecefebc13ffae238de8a895a60cf4
parent6bbcf5b3f8fac6c6d4f8ea9edef470cf4887f1a7 (diff)
downloadchrome-ec-03a665939f8adef0f8fd5a170f859210f65d2c54.tar.gz
pd: ensure tighter timings for IRQ_HPD pulse
In order to ensure we are always meeting the deadlines for the IRQ_HPD pulse, increase the priority of the processing by moving the rising edge from the low-priority HOOK task (in a deferred function) to the caller task (which is the high-priority PD task). The downside is we are now sleeping in the PD task blocking the processing of the PD messages during this time. Changed HPD_DSTREAM_DEBOUNCE_IRQ to 500us instead of 750us. According to DP spec, the IRQ_HPD pulse width is between 500us and 1000us. Ensure there is a minimum of 2ms delay in between each IRQ_HPD as specified by the DP spec, by sleeping before sending the next pulse if needed. (in practice, this should not wait if we are not too off processing the messages) BUG=chromium:711334 BRANCH=glados strago reef oak TEST=manual, on SKL platform with kernel 3.18 and MST, verify display is functional on USB-C dock. Change-Id: Ib2e9dd608c5f1c671cc5a0fd979a5742101375ff Signed-off-by: Kevin K Wong <kevin.k.wong@intel.com> Signed-off-by: Vincent Palatin <vpalatin@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/508629 Reviewed-by: Todd Broch <tbroch@chromium.org>
-rw-r--r--board/chell/usb_pd_policy.c38
-rw-r--r--board/glados/usb_pd_policy.c38
-rw-r--r--board/oak/board.c24
-rw-r--r--board/strago/usb_pd_policy.c30
-rw-r--r--board/wheatley/usb_pd_policy.c38
-rw-r--r--driver/tcpm/anx74xx.c15
-rw-r--r--driver/tcpm/ps8751.c16
-rw-r--r--include/usb_pd.h2
8 files changed, 129 insertions, 72 deletions
diff --git a/board/chell/usb_pd_policy.c b/board/chell/usb_pd_policy.c
index efe2b953c5..9c2218dd5a 100644
--- a/board/chell/usb_pd_policy.c
+++ b/board/chell/usb_pd_policy.c
@@ -281,6 +281,12 @@ 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)
{
@@ -289,24 +295,11 @@ static void svdm_dp_post_config(int port)
return;
gpio_set_level(PORT_TO_HPD(port), 1);
-}
-
-static void hpd0_irq_deferred(void)
-{
- gpio_set_level(GPIO_USB_C0_DP_HPD, 1);
-}
-static void hpd1_irq_deferred(void)
-{
- gpio_set_level(GPIO_USB_C1_DP_HPD, 1);
+ /* set the minimum time delay (2ms) for the next HPD IRQ */
+ hpd_deadline[port] = get_time().val + HPD_USTREAM_DEBOUNCE_LVL;
}
-DECLARE_DEFERRED(hpd0_irq_deferred);
-DECLARE_DEFERRED(hpd1_irq_deferred);
-#define PORT_TO_HPD_IRQ_DEFERRED(port) ((port) ? \
- &hpd1_irq_deferred_data : \
- &hpd0_irq_deferred_data)
-
static int svdm_dp_attention(int port, uint32_t *payload)
{
int cur_lvl;
@@ -325,14 +318,25 @@ static int svdm_dp_attention(int port, uint32_t *payload)
}
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);
- hook_call_deferred(PORT_TO_HPD_IRQ_DEFERRED(port),
- HPD_DSTREAM_DEBOUNCE_IRQ);
+ 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) {
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;
}
/* ack */
return 1;
diff --git a/board/glados/usb_pd_policy.c b/board/glados/usb_pd_policy.c
index 9e25021328..59bf0d7545 100644
--- a/board/glados/usb_pd_policy.c
+++ b/board/glados/usb_pd_policy.c
@@ -291,6 +291,12 @@ 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)
{
@@ -299,24 +305,11 @@ static void svdm_dp_post_config(int port)
return;
gpio_set_level(PORT_TO_HPD(port), 1);
-}
-
-static void hpd0_irq_deferred(void)
-{
- gpio_set_level(GPIO_USB_C0_DP_HPD, 1);
-}
-static void hpd1_irq_deferred(void)
-{
- gpio_set_level(GPIO_USB_C1_DP_HPD, 1);
+ /* set the minimum time delay (2ms) for the next HPD IRQ */
+ hpd_deadline[port] = get_time().val + HPD_USTREAM_DEBOUNCE_LVL;
}
-DECLARE_DEFERRED(hpd0_irq_deferred);
-DECLARE_DEFERRED(hpd1_irq_deferred);
-#define PORT_TO_HPD_IRQ_DEFERRED(port) ((port) ? \
- &hpd1_irq_deferred_data : \
- &hpd0_irq_deferred_data)
-
static int svdm_dp_attention(int port, uint32_t *payload)
{
int cur_lvl;
@@ -335,14 +328,25 @@ static int svdm_dp_attention(int port, uint32_t *payload)
}
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);
- hook_call_deferred(PORT_TO_HPD_IRQ_DEFERRED(port),
- HPD_DSTREAM_DEBOUNCE_IRQ);
+ 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) {
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;
}
/* ack */
return 1;
diff --git a/board/oak/board.c b/board/oak/board.c
index 1c4ee791f7..df81a3ea7a 100644
--- a/board/oak/board.c
+++ b/board/oak/board.c
@@ -354,6 +354,12 @@ int board_get_ramp_current_limit(int supplier, int sup_curr)
}
}
+/*
+ * 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];
+
static void board_typec_set_dp_hpd(int port, int level)
{
#if BOARD_REV >= OAK_REV5
@@ -362,15 +368,8 @@ static void board_typec_set_dp_hpd(int port, int level)
#endif
gpio_set_level(GPIO_USB_DP_HPD, level);
-
}
-static void hpd_irq_deferred(void)
-{
- board_typec_set_dp_hpd(dp_hw_port, 1);
-}
-DECLARE_DEFERRED(hpd_irq_deferred);
-
/**
* Turn on DP hardware on type-C port.
*/
@@ -388,11 +387,18 @@ void board_typec_dp_on(int port)
if (!gpio_get_level(GPIO_USB_DP_HPD)) {
board_typec_set_dp_hpd(port, 1);
} else {
+ uint64_t now = get_time().val;
+ /* wait for the minimum spacing between IRQ_HPD */
+ if (now < hpd_deadline[port])
+ usleep(hpd_deadline[port] - now);
+
board_typec_set_dp_hpd(port, 0);
- hook_call_deferred(&hpd_irq_deferred_data,
- HPD_DSTREAM_DEBOUNCE_IRQ);
+ usleep(HPD_DSTREAM_DEBOUNCE_IRQ);
+ board_typec_set_dp_hpd(port, 1);
}
}
+ /* enforce 2-ms delay between HPD pulses */
+ hpd_deadline[port] = get_time().val + HPD_USTREAM_DEBOUNCE_LVL;
mutex_unlock(&dp_hw_lock);
}
diff --git a/board/strago/usb_pd_policy.c b/board/strago/usb_pd_policy.c
index 214d52295e..e252f98dc9 100644
--- a/board/strago/usb_pd_policy.c
+++ b/board/strago/usb_pd_policy.c
@@ -263,6 +263,12 @@ 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];
+
static void svdm_dp_post_config(int port)
{
dp_flags |= DP_FLAGS_DP_ON;
@@ -270,15 +276,10 @@ static void svdm_dp_post_config(int port)
return;
gpio_set_level(GPIO_USB_C0_DP_HPD, 1);
+ /* set the minimum time delay (2ms) for the next HPD IRQ */
+ hpd_deadline[port] = get_time().val + HPD_USTREAM_DEBOUNCE_LVL;
}
-static void hpd0_irq_deferred(void)
-{
- gpio_set_level(GPIO_USB_C0_DP_HPD, 1);
-}
-
-DECLARE_DEFERRED(hpd0_irq_deferred);
-
static int svdm_dp_attention(int port, uint32_t *payload)
{
int cur_lvl;
@@ -297,14 +298,25 @@ static int svdm_dp_attention(int port, uint32_t *payload)
}
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);
- hook_call_deferred(&hpd0_irq_deferred_data,
- HPD_DSTREAM_DEBOUNCE_IRQ);
+ usleep(HPD_DSTREAM_DEBOUNCE_IRQ);
+ gpio_set_level(GPIO_USB_C0_DP_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) {
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;
}
/* ack */
return 1;
diff --git a/board/wheatley/usb_pd_policy.c b/board/wheatley/usb_pd_policy.c
index 923cdcbbec..e0bdef8e20 100644
--- a/board/wheatley/usb_pd_policy.c
+++ b/board/wheatley/usb_pd_policy.c
@@ -274,6 +274,12 @@ 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)
{
@@ -282,24 +288,11 @@ static void svdm_dp_post_config(int port)
return;
gpio_set_level(PORT_TO_HPD(port), 1);
-}
-
-static void hpd0_irq_deferred(void)
-{
- gpio_set_level(GPIO_USB_C0_DP_HPD, 1);
-}
-static void hpd1_irq_deferred(void)
-{
- gpio_set_level(GPIO_USB_C1_DP_HPD, 1);
+ /* set the minimum time delay (2ms) for the next HPD IRQ */
+ hpd_deadline[port] = get_time().val + HPD_USTREAM_DEBOUNCE_LVL;
}
-DECLARE_DEFERRED(hpd0_irq_deferred);
-DECLARE_DEFERRED(hpd1_irq_deferred);
-#define PORT_TO_HPD_IRQ_DEFERRED(port) ((port) ? \
- &hpd1_irq_deferred_data : \
- &hpd0_irq_deferred_data)
-
static int svdm_dp_attention(int port, uint32_t *payload)
{
int cur_lvl;
@@ -318,14 +311,25 @@ static int svdm_dp_attention(int port, uint32_t *payload)
}
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);
- hook_call_deferred(PORT_TO_HPD_IRQ_DEFERRED(port),
- HPD_DSTREAM_DEBOUNCE_IRQ);
+ 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) {
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;
}
/* ack */
return 1;
diff --git a/driver/tcpm/anx74xx.c b/driver/tcpm/anx74xx.c
index 4a32fc4864..4c3fd41410 100644
--- a/driver/tcpm/anx74xx.c
+++ b/driver/tcpm/anx74xx.c
@@ -176,6 +176,12 @@ static void anx74xx_tcpc_discharge_vbus(int port, int enable)
}
#endif
+/*
+ * 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];
+
void anx74xx_tcpc_update_hpd_status(int port, int hpd_lvl, int hpd_irq)
{
int reg;
@@ -188,13 +194,20 @@ void anx74xx_tcpc_update_hpd_status(int port, int hpd_lvl, int hpd_irq)
tcpc_write(port, ANX74XX_REG_HPD_CTRL_0, reg);
if (hpd_irq) {
+ 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);
+
tcpc_read(port, ANX74XX_REG_HPD_CTRL_0, &reg);
reg &= ~ANX74XX_REG_HPD_OUT_DATA;
tcpc_write(port, ANX74XX_REG_HPD_CTRL_0, reg);
- msleep(1);
+ usleep(HPD_DSTREAM_DEBOUNCE_IRQ);
reg |= ANX74XX_REG_HPD_OUT_DATA;
tcpc_write(port, ANX74XX_REG_HPD_CTRL_0, reg);
}
+ /* enforce 2-ms delay between HPD pulses */
+ hpd_deadline[port] = get_time().val + HPD_USTREAM_DEBOUNCE_LVL;
}
void anx74xx_tcpc_clear_hpd_status(int port)
diff --git a/driver/tcpm/ps8751.c b/driver/tcpm/ps8751.c
index 66b895696e..1fb1660407 100644
--- a/driver/tcpm/ps8751.c
+++ b/driver/tcpm/ps8751.c
@@ -9,6 +9,7 @@
#include "ps8751.h"
#include "tcpm.h"
#include "timer.h"
+#include "usb_pd.h"
#if !defined(CONFIG_USB_PD_TCPM_TCPCI) || \
!defined(CONFIG_USB_PD_TCPM_MUX) || \
@@ -19,6 +20,12 @@
#endif
+/*
+ * 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];
+
static int dp_set_hpd(int port, int enable)
{
int reg;
@@ -55,10 +62,17 @@ void ps8751_tcpc_update_hpd_status(int port, int hpd_lvl, int hpd_irq)
dp_set_hpd(port, hpd_lvl);
if (hpd_irq) {
+ 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);
+
dp_set_irq(port, 0);
- msleep(1);
+ usleep(HPD_DSTREAM_DEBOUNCE_IRQ);
dp_set_irq(port, hpd_irq);
}
+ /* enforce 2-ms delay between HPD pulses */
+ hpd_deadline[port] = get_time().val + HPD_USTREAM_DEBOUNCE_LVL;
}
int ps8751_tcpc_get_fw_version(int port, int *version)
diff --git a/include/usb_pd.h b/include/usb_pd.h
index 4f7ce8c52b..8eb53c93c3 100644
--- a/include/usb_pd.h
+++ b/include/usb_pd.h
@@ -563,7 +563,7 @@ struct pd_policy {
/* Per DisplayPort Spec v1.3 Section 3.3 */
#define HPD_USTREAM_DEBOUNCE_LVL (2*MSEC)
#define HPD_USTREAM_DEBOUNCE_IRQ (250)
-#define HPD_DSTREAM_DEBOUNCE_IRQ (750) /* between 500-1000us */
+#define HPD_DSTREAM_DEBOUNCE_IRQ (500) /* between 500-1000us */
/*
* DisplayPort Configure VDO