summaryrefslogtreecommitdiff
path: root/common/usb_pd_policy.c
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 /common/usb_pd_policy.c
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>
Diffstat (limited to 'common/usb_pd_policy.c')
-rw-r--r--common/usb_pd_policy.c82
1 files changed, 69 insertions, 13 deletions
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;