summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTodd Broch <tbroch@chromium.org>2014-10-13 17:50:33 -0700
committerchrome-internal-fetch <chrome-internal-fetch@google.com>2014-10-25 08:14:10 +0000
commitcadce20c1ac866833d15ad7d8360cda17ea344e2 (patch)
treee9d27e61d9bb1583f7768a2c11da041cfbced5a2
parentbf8335a0a329f8d40fe3c4e911c9f9bb144ca2ad (diff)
downloadchrome-ec-cadce20c1ac866833d15ad7d8360cda17ea344e2.tar.gz
pd: Add DFP parsing for alternate mode status & attention.
Once alternate mode is entered the DFP will make an initial status request to the UFP. Future status changes on the UFP are then sent to the DFP via the attention command. This VDM consists of the VDM header plus another VDO containing mode specific information. CL adds ability of DFP to consume the attention VDMs status message and in the case of DisplayPort SID toggle the necessary HPD gpio accordingly. BRANCH=samus BUG=chrome-os-partner:30645 TEST=manual, for DFP w/ HPD over CC see HPD toggle correctly without manually driving it providing cable connected when AMA is inserted. Change-Id: Ifef60b5d0170cbcc1b518e3b13e84bac99a17e32 Signed-off-by: Todd Broch <tbroch@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/224769 Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
-rw-r--r--board/dingdong/usb_pd_policy.c46
-rw-r--r--board/fruitpie/usb_pd_policy.c7
-rw-r--r--board/hoho/usb_pd_policy.c46
-rw-r--r--board/samus_pd/usb_pd_policy.c42
-rw-r--r--common/usb_pd_policy.c82
-rw-r--r--common/usb_pd_protocol.c6
-rw-r--r--include/usb_pd.h5
7 files changed, 171 insertions, 63 deletions
diff --git a/board/dingdong/usb_pd_policy.c b/board/dingdong/usb_pd_policy.c
index fa0894e509..97504a1cbf 100644
--- a/board/dingdong/usb_pd_policy.c
+++ b/board/dingdong/usb_pd_policy.c
@@ -124,7 +124,14 @@ static int svdm_response_svids(int port, uint32_t *payload)
return 2;
}
-const uint32_t vdo_dp_mode[1] = {
+/* Will only ever be a single mode for this UFP_D device as it has no USB
+ * support (2.0 or 3.0) making it only PIN_E configureable nor does it have any
+ * source functionality.
+ */
+#define MODE_CNT 1
+#define OPOS 1
+
+const uint32_t vdo_dp_mode[MODE_CNT] = {
VDO_MODE_DP(0, /* UFP pin cfg supported : none */
MODE_DP_PIN_E, /* DFP pin cfg supported */
1, /* no usb2.0 signalling in AMode */
@@ -135,57 +142,46 @@ const uint32_t vdo_dp_mode[1] = {
static int svdm_response_modes(int port, uint32_t *payload)
{
- int mode_cnt = ARRAY_SIZE(vdo_dp_mode);
-
if (PD_VDO_VID(payload[0]) != USB_SID_DISPLAYPORT) {
/* TODO(tbroch) USB billboard enabled here then */
return 1; /* will generate a NAK */
}
memcpy(payload + 1, vdo_dp_mode, sizeof(vdo_dp_mode));
- return mode_cnt + 1;
-}
-
-static int hpd_get_irq(int port)
-{
- /* TODO(tbroch) FIXME */
- return 0;
-}
-
-static enum hpd_level hpd_get_level(int port)
-{
- /* TODO(tbroch) FIXME: needs debounce */
- return gpio_get_level(GPIO_DP_HPD);
+ return MODE_CNT + 1;
}
static int dp_status(int port, uint32_t *payload)
{
- uint32_t ufp_dp_sts = payload[1] & 0x3;
- payload[1] = VDO_DP_STATUS(hpd_get_irq(port), /* IRQ_HPD */
- hpd_get_level(port), /* HPD_HI|LOW */
+ int opos = PD_VDO_OPOS(payload[0]);
+ int hpd = gpio_get_level(GPIO_DP_HPD);
+ if (opos != OPOS)
+ return 0; /* nak */
+
+ payload[1] = VDO_DP_STATUS(0, /* IRQ_HPD */
+ (hpd == 1), /* HPD_HI|LOW */
0, /* request exit DP */
0, /* request exit USB */
0, /* MF pref */
gpio_get_level(GPIO_PD_SBU_ENABLE),
0, /* power low */
- (ufp_dp_sts | 0x2));
+ 0x2);
return 2;
}
static int dp_config(int port, uint32_t *payload)
{
- if (PD_DP_CFG_DPON(payload[1])) {
+ if (PD_DP_CFG_DPON(payload[1]))
gpio_set_level(GPIO_PD_SBU_ENABLE, 1);
- payload[1] = 0;
- }
- return 2;
+
+ return 1;
}
static int svdm_enter_mode(int port, uint32_t *payload)
{
/* SID & mode request is valid */
if ((PD_VDO_VID(payload[0]) != USB_SID_DISPLAYPORT) ||
- (PD_VDO_OPOS(payload[0]) != 1))
+ (PD_VDO_OPOS(payload[0]) != OPOS))
return 0; /* will generate NAK */
return 1;
}
diff --git a/board/fruitpie/usb_pd_policy.c b/board/fruitpie/usb_pd_policy.c
index 6caea5692f..aa63911cc9 100644
--- a/board/fruitpie/usb_pd_policy.c
+++ b/board/fruitpie/usb_pd_policy.c
@@ -224,6 +224,12 @@ static int svdm_dp_config(int port, uint32_t *payload)
return 2;
};
+static int svdm_dp_attention(int port, uint32_t *payload)
+{
+ CPRINTF("dp sts:%08x\n", payload[1]);
+ return 1; /* ack */
+}
+
static void svdm_exit_dp_mode(int port)
{
CPRINTF("Exiting mode\n");
@@ -236,6 +242,7 @@ const struct svdm_amode_fx supported_modes[] = {
.enter = &svdm_enter_dp_mode,
.status = &svdm_dp_status,
.config = &svdm_dp_config,
+ .attention = &svdm_dp_attention,
.exit = &svdm_exit_dp_mode,
},
};
diff --git a/board/hoho/usb_pd_policy.c b/board/hoho/usb_pd_policy.c
index 61457d3d6c..b747766aa9 100644
--- a/board/hoho/usb_pd_policy.c
+++ b/board/hoho/usb_pd_policy.c
@@ -124,7 +124,14 @@ static int svdm_response_svids(int port, uint32_t *payload)
return 2;
}
-const uint32_t vdo_dp_mode[1] = {
+/* Will only ever be a single mode for this UFP_D device as it has no USB
+ * support (2.0 or 3.0) making it only PIN_E configureable nor does it have any
+ * source functionality.
+ */
+#define MODE_CNT 1
+#define OPOS 1
+
+const uint32_t vdo_dp_mode[MODE_CNT] = {
VDO_MODE_DP(0, /* UFP pin cfg supported : none */
MODE_DP_PIN_C, /* DFP pin cfg supported */
1, /* no usb2.0 signalling in AMode */
@@ -135,39 +142,30 @@ const uint32_t vdo_dp_mode[1] = {
static int svdm_response_modes(int port, uint32_t *payload)
{
- int mode_cnt = ARRAY_SIZE(vdo_dp_mode);
-
if (PD_VDO_VID(payload[0]) != USB_SID_DISPLAYPORT) {
/* TODO(tbroch) USB billboard enabled here then */
return 1; /* will generate a NAK */
}
memcpy(payload + 1, vdo_dp_mode, sizeof(vdo_dp_mode));
- return mode_cnt + 1;
-}
-
-static int hpd_get_irq(int port)
-{
- /* TODO(tbroch) FIXME */
- return 0;
-}
-
-static enum hpd_level hpd_get_level(int port)
-{
- return gpio_get_level(GPIO_DP_HPD);
+ return MODE_CNT + 1;
}
static int dp_status(int port, uint32_t *payload)
{
- uint32_t ufp_dp_sts = payload[1] & 0x3;
- payload[1] = VDO_DP_STATUS(hpd_get_irq(port), /* IRQ_HPD */
- hpd_get_level(port), /* HPD_HI|LOW */
- 0, /* request exit DP */
- 0, /* request exit USB */
- 0, /* MF pref */
+ int opos = PD_VDO_OPOS(payload[0]);
+ int hpd = gpio_get_level(GPIO_DP_HPD);
+ if (opos != OPOS)
+ return 0; /* nak */
+
+ payload[1] = VDO_DP_STATUS(0, /* IRQ_HPD */
+ (hpd == 1), /* HPD_HI|LOW */
+ 0, /* request exit DP */
+ 0, /* request exit USB */
+ 0, /* MF pref */
gpio_get_level(GPIO_PD_SBU_ENABLE),
- 0, /* power low */
- (ufp_dp_sts | 0x2));
+ 0, /* power low */
+ 0x2);
return 2;
}
@@ -182,7 +180,7 @@ static int svdm_enter_mode(int port, uint32_t *payload)
{
/* SID & mode request is valid */
if ((PD_VDO_VID(payload[0]) != USB_SID_DISPLAYPORT) ||
- (PD_VDO_OPOS(payload[0]) != 1))
+ (PD_VDO_OPOS(payload[0]) != OPOS))
return 0; /* will generate a NAK */
return 1;
}
diff --git a/board/samus_pd/usb_pd_policy.c b/board/samus_pd/usb_pd_policy.c
index e8ffd2a886..507c6d3bce 100644
--- a/board/samus_pd/usb_pd_policy.c
+++ b/board/samus_pd/usb_pd_policy.c
@@ -7,6 +7,7 @@
#include "common.h"
#include "console.h"
#include "gpio.h"
+#include "hooks.h"
#include "host_command.h"
#include "registers.h"
#include "task.h"
@@ -275,9 +276,49 @@ static int svdm_dp_config(int port, uint32_t *payload)
return 2;
};
+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);
+}
+
+DECLARE_DEFERRED(hpd0_irq_deferred);
+DECLARE_DEFERRED(hpd1_irq_deferred);
+
+#define PORT_TO_HPD(port) ((port) ? GPIO_USB_C1_DP_HPD : GPIO_USB_C0_DP_HPD)
+
+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]);
+ enum gpio_signal hpd = PORT_TO_HPD(port);
+ cur_lvl = gpio_get_level(hpd);
+ if (irq & cur_lvl) {
+ gpio_set_level(hpd, 0);
+ /* 250 usecs is minimum, 2msec is max */
+ if (port)
+ hook_call_deferred(hpd1_irq_deferred, 300);
+ else
+ hook_call_deferred(hpd0_irq_deferred, 300);
+ } else if (irq & !cur_lvl) {
+ CPRINTF("PE ERR: IRQ_HPD w/ HPD_LOW\n");
+ return 0; /* nak */
+ } else {
+ gpio_set_level(hpd, lvl);
+ }
+ /* ack */
+ return 1;
+}
+
static void svdm_exit_dp_mode(int port)
{
svdm_safe_dp_mode(port);
+ gpio_set_level(PORT_TO_HPD(port), 0);
}
const struct svdm_amode_fx supported_modes[] = {
@@ -286,6 +327,7 @@ const struct svdm_amode_fx supported_modes[] = {
.enter = &svdm_enter_dp_mode,
.status = &svdm_dp_status,
.config = &svdm_dp_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 837ef2f5fd..87f6984c88 100644
--- a/common/usb_pd_policy.c
+++ b/common/usb_pd_policy.c
@@ -23,11 +23,14 @@
#ifdef CONFIG_USB_PD_ALT_MODE_DFP
-struct pd_policy pe[PD_PORT_COUNT];
+static struct pd_policy pe[PD_PORT_COUNT];
+
+#define AMODE_VALID(port) (pe[port].amode.index != -1)
static void pe_init(int port)
{
- memset(pe, 0, sizeof(struct pd_policy) * PD_PORT_COUNT);
+ memset(&pe[port], 0, sizeof(struct pd_policy));
+ pe[port].amode.index = -1;
}
static void dfp_consume_identity(int port, uint32_t *payload)
@@ -114,7 +117,6 @@ static int dfp_enter_mode(int port, uint32_t *payload)
{
int i, j, done;
struct svdm_amode_data *modep = &pe[port].amode;
- pe[port].amode.index = -1; /* Error condition */
for (i = 0, done = 0; !done && (i < supported_modes_cnt); i++) {
for (j = 0; j < pe[port].svid_cnt; j++) {
if (pe[port].svids[j].svid != supported_modes[i].svid)
@@ -127,7 +129,7 @@ static int dfp_enter_mode(int port, uint32_t *payload)
break;
}
}
- if (modep->index == -1)
+ if (!AMODE_VALID(port))
return 0;
modep->fx->enter(port, modep->mode_caps);
@@ -137,13 +139,40 @@ static int dfp_enter_mode(int port, uint32_t *payload)
return 1;
}
+static int dfp_consume_attention(int port, uint32_t *payload)
+{
+ int svid = PD_VDO_VID(payload[0]);
+ int opos = PD_VDO_OPOS(payload[0]);
+
+ if (!AMODE_VALID(port))
+ return 0;
+ if (svid != pe[port].amode.fx->svid) {
+ CPRINTF("PE ERR: svid s:0x%04x != m:0x%04x\n",
+ svid, pe[port].amode.fx->svid);
+ return 0; /* NAK */
+ }
+ if (opos != pe[port].amode.index + 1) {
+ CPRINTF("PE ERR: opos s:%d != m:%d\n",
+ opos, pe[port].amode.index + 1);
+ return 0; /* NAK */
+ }
+ if (!pe[port].amode.fx->attention)
+ return 0;
+ return pe[port].amode.fx->attention(port, payload);
+}
+
int pd_exit_mode(int port, uint32_t *payload)
{
struct svdm_amode_data *modep = &pe[port].amode;
+ if (!modep->fx)
+ return 0;
+
modep->fx->exit(port);
- payload[0] = VDO(modep->fx->svid, 1,
- CMD_EXIT_MODE |
- VDO_OPOS((modep->index + 1)));
+
+ if (payload)
+ payload[0] = VDO(modep->fx->svid, 1,
+ CMD_EXIT_MODE | VDO_OPOS((modep->index + 1)));
+ modep->index = -1;
return 1;
}
@@ -163,7 +192,7 @@ static void dump_pe(int port)
pe[port].svids[i].mode_vdo[j]);
ccprintf("\n");
}
- if (pe[port].amode.index == -1) {
+ if (!AMODE_VALID(port)) {
ccprintf("No mode chosen yet.\n");
return;
}
@@ -234,6 +263,15 @@ int pd_svdm(int port, int cnt, uint32_t *payload, uint32_t **rpayload)
case CMD_EXIT_MODE:
func = svdm_rsp.exit_mode;
break;
+#ifdef CONFIG_USB_PD_ALT_MODE_DFP
+ case CMD_ATTENTION:
+ /* This is DFP response */
+ func = &dfp_consume_attention;
+ break;
+#endif
+ default:
+ CPRINTF("PE ERR: unknown command %d\n", cmd);
+ rsize = 0;
}
if (func)
rsize = func(port, payload);
@@ -266,23 +304,42 @@ int pd_svdm(int port, int cnt, uint32_t *payload, uint32_t **rpayload)
rsize = dfp_enter_mode(port, payload);
break;
case CMD_ENTER_MODE:
- if (pe[port].amode.index != -1)
+ if (AMODE_VALID(port)) {
rsize = pe[port].amode.fx->status(port,
payload);
+ payload[0] |=
+ VDO_OPOS((pe[port].amode.index + 1));
+ } else {
+ rsize = 0;
+ }
break;
case CMD_DP_STATUS:
- rsize = pe[port].amode.fx->config(port, payload);
+ /* DP status response & UFP's DP attention have same
+ payload */
+ dfp_consume_attention(port, payload);
+ if (AMODE_VALID(port))
+ rsize = pe[port].amode.fx->config(port,
+ payload);
+ else
+ rsize = 0;
break;
case CMD_DP_CONFIG:
+ /* no response after DFPs ack */
rsize = 0;
break;
case CMD_EXIT_MODE:
- rsize = pd_exit_mode(port, payload);
+ /* no response after DFPs ack */
+ rsize = 0;
+ break;
+ case CMD_ATTENTION:
+ /* no response after DFPs ack */
+ rsize = 0;
break;
default:
+ CPRINTF("PE ERR: unknown command %d\n", cmd);
rsize = 0;
}
- payload[0] &= ~VDO_CMDT(0);
+
payload[0] |= VDO_CMDT(CMDT_INIT);
} else if (cmd_type == CMDT_RSP_BUSY) {
switch (cmd) {
@@ -290,7 +347,6 @@ int pd_svdm(int port, int cnt, uint32_t *payload, uint32_t **rpayload)
case CMD_DISCOVER_SVID:
case CMD_DISCOVER_MODES:
/* resend if its discovery */
- payload[0] &= ~VDO_CMDT(0);
payload[0] |= VDO_CMDT(CMDT_INIT);
rsize = 1;
break;
diff --git a/common/usb_pd_protocol.c b/common/usb_pd_protocol.c
index 3c4106afb8..fa85ac5643 100644
--- a/common/usb_pd_protocol.c
+++ b/common/usb_pd_protocol.c
@@ -302,10 +302,14 @@ static inline void set_state(int port, enum pd_states next_state)
if (next_state == PD_STATE_SRC_DISCONNECTED) {
pd[port].dev_id = 0;
+#ifdef CONFIG_USB_PD_ALT_MODE_DFP
+ pd_exit_mode(port, NULL);
+#else
#ifdef CONFIG_USBC_SS_MUX
board_set_usb_mux(port, TYPEC_MUX_NONE,
pd[port].polarity);
#endif
+#endif
#ifdef CONFIG_USBC_VCONN
pd_set_vconn(port, pd[port].polarity, 0);
#endif
@@ -1559,7 +1563,7 @@ void pd_task(void)
hard_reset_count++;
#endif
- pd_exit_mode(port, payload);
+ pd_exit_mode(port, NULL);
send_hard_reset(port);
/* reset our own state machine */
execute_hard_reset(port);
diff --git a/include/usb_pd.h b/include/usb_pd.h
index 4518d2e88b..2184f19230 100644
--- a/include/usb_pd.h
+++ b/include/usb_pd.h
@@ -133,6 +133,7 @@ struct svdm_amode_fx {
void (*enter)(int port, uint32_t mode_caps);
int (*status)(int port, uint32_t *payload);
int (*config)(int port, uint32_t *payload);
+ int (*attention)(int port, uint32_t *payload);
void (*exit)(int port);
};
@@ -194,6 +195,7 @@ struct pd_policy {
#define VDO_SVDM_VERS(x) (x << 13)
#define VDO_OPOS(x) (x << 8)
#define VDO_CMDT(x) (x << 6)
+#define VDO_OPOS_MASK VDO_OPOS(0x7)
#define VDO_CMDT_MASK VDO_CMDT(0x3)
#define CMDT_INIT 0
@@ -409,6 +411,9 @@ struct pd_policy {
(((irq) & 1) << 8 | ((lvl) & 1) << 7 | ((amode) & 1) << 6 \
| ((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)
/*
* DisplayPort Configure VDO
* -------------------------