summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTodd Broch <tbroch@chromium.org>2014-10-10 11:16:02 -0700
committerchrome-internal-fetch <chrome-internal-fetch@google.com>2014-10-21 22:44:45 +0000
commitcefb58066d2a706ad34726aff977be3a584fc001 (patch)
tree8c1eb1efaac6beb6ae9bca6507ba79a45d580686
parent3e2f1329abfa729fe6786ff64d9545e6ce94f042 (diff)
downloadchrome-ec-cefb58066d2a706ad34726aff977be3a584fc001.tar.gz
pd: Add DisplayPort status and configure SVDMs.
Per revisements to the DisplayPort Alternate mode specification there are two additional SVDMs for DPout support: status & configure. This CL adds those SVDMs and calls them (status then config) after finding a device that supports DP Alternate mode. Future CLs will use these SVDMs to complete providing HPD over CC support. BRANCH=none BUG=chrome-os-partner:31192,chrome-os-partner:31193 TEST=manual, plug hoho/dingdong into samus and see: 1. Additional DP status [16] & DP configure [17] 2. Drives DPout properly Change-Id: I52b373085ddc330e4afb1d1883d2621bc2e4ee95 Signed-off-by: Todd Broch <tbroch@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/223260 Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
-rw-r--r--board/dingdong/usb_pd_policy.c54
-rw-r--r--board/fruitpie/usb_pd_policy.c30
-rw-r--r--board/hoho/usb_pd_policy.c51
-rw-r--r--board/samus_pd/usb_pd_policy.c40
-rw-r--r--common/usb_pd_policy.c23
-rw-r--r--include/usb_pd.h66
6 files changed, 229 insertions, 35 deletions
diff --git a/board/dingdong/usb_pd_policy.c b/board/dingdong/usb_pd_policy.c
index 61a3bd8f33..64663172f3 100644
--- a/board/dingdong/usb_pd_policy.c
+++ b/board/dingdong/usb_pd_policy.c
@@ -143,35 +143,67 @@ static int svdm_response_modes(int port, uint32_t *payload)
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);
+}
+
+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 */
+ gpio_get_level(GPIO_PD_SBU_ENABLE),
+ 0, /* power low */
+ (ufp_dp_sts | 0x2));
+ return 2;
+}
+
+static int dp_config(int port, uint32_t *payload)
+{
+ if (PD_DP_CFG_DPON(payload[1])) {
+ gpio_set_level(GPIO_PD_SBU_ENABLE, 1);
+ payload[1] = 0;
+ }
+ return 2;
+}
+
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))
- return 1; /* will generate a NAK */
-
- gpio_set_level(GPIO_PD_SBU_ENABLE, 1);
- payload[1] = 0;
+ return 0; /* will generate NAK */
return 1;
}
static int svdm_exit_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))
- return 1; /* will generate a NAK */
-
gpio_set_level(GPIO_PD_SBU_ENABLE, 0);
- payload[1] = 0;
- return 1;
+ return 1; /* Must return ACK */
}
+static struct amode_fx dp_fx = {
+ .status = &dp_status,
+ .config = &dp_config,
+};
+
const struct svdm_response svdm_rsp = {
.identity = &svdm_response_identity,
.svids = &svdm_response_svids,
.modes = &svdm_response_modes,
.enter_mode = &svdm_enter_mode,
+ .amode = &dp_fx,
.exit_mode = &svdm_exit_mode,
};
diff --git a/board/fruitpie/usb_pd_policy.c b/board/fruitpie/usb_pd_policy.c
index 1cceb0b6b6..8a80175c4f 100644
--- a/board/fruitpie/usb_pd_policy.c
+++ b/board/fruitpie/usb_pd_policy.c
@@ -192,6 +192,34 @@ static void svdm_enter_dp_mode(int port, uint32_t mode_caps)
CPRINTF("Entering mode w/ vdo = %08x\n", mode_caps);
}
+static int dp_on;
+
+static int svdm_dp_status(int port, uint32_t *payload)
+{
+ payload[0] = VDO(USB_SID_DISPLAYPORT, 1, CMD_DP_STATUS);
+ payload[1] = VDO_DP_STATUS(0, /* HPD IRQ ... not applicable */
+ 0, /* HPD level ... not applicable */
+ 0, /* exit DP? ... no */
+ 0, /* usb mode? ... no */
+ 0, /* multi-function ... no */
+ dp_on,
+ 0, /* power low? ... no */
+ 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);
+ payload[1] = VDO_DP_CFG(MODE_DP_PIN_E, /* sink pins */
+ MODE_DP_PIN_E, /* src pins */
+ 0, /* signalling unspec'd */
+ 2); /* UFP connected */
+ return 2;
+};
+
static void svdm_exit_dp_mode(int port)
{
CPRINTF("Exiting mode\n");
@@ -202,6 +230,8 @@ const struct svdm_amode_fx supported_modes[] = {
{
.svid = USB_SID_DISPLAYPORT,
.enter = &svdm_enter_dp_mode,
+ .status = &svdm_dp_status,
+ .config = &svdm_dp_config,
.exit = &svdm_exit_dp_mode,
},
};
diff --git a/board/hoho/usb_pd_policy.c b/board/hoho/usb_pd_policy.c
index dd94ed1413..7560821c1d 100644
--- a/board/hoho/usb_pd_policy.c
+++ b/board/hoho/usb_pd_policy.c
@@ -143,35 +143,64 @@ static int svdm_response_modes(int port, uint32_t *payload)
return mode_cnt + 1;
}
-static int svdm_enter_mode(int port, uint32_t *payload)
+static int hpd_get_irq(int port)
{
- /* SID & mode request is valid */
- if ((PD_VDO_VID(payload[0]) != USB_SID_DISPLAYPORT) ||
- (PD_VDO_OPOS(payload[0]) != 1))
- return 1; /* will generate a NAK */
+ /* TODO(tbroch) FIXME */
+ return 0;
+}
+
+static enum hpd_level hpd_get_level(int port)
+{
+ return gpio_get_level(GPIO_DP_HPD);
+}
+
+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 */
+ gpio_get_level(GPIO_PD_SBU_ENABLE),
+ 0, /* power low */
+ (ufp_dp_sts | 0x2));
+ return 2;
+}
- gpio_set_level(GPIO_PD_SBU_ENABLE, 1);
- payload[1] = 0;
+static int dp_config(int port, uint32_t *payload)
+{
+ if (PD_DP_CFG_DPON(payload[1]))
+ gpio_set_level(GPIO_PD_SBU_ENABLE, 1);
return 1;
}
-static int svdm_exit_mode(int port, uint32_t *payload)
+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))
- return 1; /* will generate a NAK */
+ return 0; /* will generate a NAK */
+ return 1;
+}
+static int svdm_exit_mode(int port, uint32_t *payload)
+{
gpio_set_level(GPIO_PD_SBU_ENABLE, 0);
- payload[1] = 0;
- return 1;
+ return 1; /* Must return ACK */
}
+static struct amode_fx dp_fx = {
+ .status = &dp_status,
+ .config = &dp_config,
+};
+
const struct svdm_response svdm_rsp = {
.identity = &svdm_response_identity,
.svids = &svdm_response_svids,
.modes = &svdm_response_modes,
.enter_mode = &svdm_enter_mode,
+ .amode = &dp_fx,
.exit_mode = &svdm_exit_mode,
};
diff --git a/board/samus_pd/usb_pd_policy.c b/board/samus_pd/usb_pd_policy.c
index 4d5b4e4d12..403adb9af1 100644
--- a/board/samus_pd/usb_pd_policy.c
+++ b/board/samus_pd/usb_pd_policy.c
@@ -218,20 +218,56 @@ int pd_vdm(int port, int cnt, uint32_t *payload, uint32_t **rpayload)
return pd_custom_vdm(port, cnt, payload, rpayload);
}
+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));
+}
+
static void svdm_enter_dp_mode(int port, uint32_t mode_caps)
{
- board_set_usb_mux(port, TYPEC_MUX_DP, pd_get_polarity(port));
+ svdm_safe_dp_mode(port);
}
+static int dp_on;
+
+static int svdm_dp_status(int port, uint32_t *payload)
+{
+ payload[0] = VDO(USB_SID_DISPLAYPORT, 1, CMD_DP_STATUS);
+ payload[1] = VDO_DP_STATUS(0, /* HPD IRQ ... not applicable */
+ 0, /* HPD level ... not applicable */
+ 0, /* exit DP? ... no */
+ 0, /* usb mode? ... no */
+ 0, /* multi-function ... no */
+ dp_on,
+ 0, /* power low? ... no */
+ 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);
+ payload[1] = VDO_DP_CFG(MODE_DP_PIN_E, /* sink pins */
+ MODE_DP_PIN_E, /* src pins */
+ 0, /* signalling unspec'd */
+ 2); /* UFP connected */
+ return 2;
+};
+
static void svdm_exit_dp_mode(int port)
{
- board_set_usb_mux(port, TYPEC_MUX_NONE, pd_get_polarity(port));
+ svdm_safe_dp_mode(port);
}
const struct svdm_amode_fx supported_modes[] = {
{
.svid = USB_SID_DISPLAYPORT,
.enter = &svdm_enter_dp_mode,
+ .status = &svdm_dp_status,
+ .config = &svdm_dp_config,
.exit = &svdm_exit_dp_mode,
},
};
diff --git a/common/usb_pd_policy.c b/common/usb_pd_policy.c
index abb763fe4b..837ef2f5fd 100644
--- a/common/usb_pd_policy.c
+++ b/common/usb_pd_policy.c
@@ -225,6 +225,12 @@ int pd_svdm(int port, int cnt, uint32_t *payload, uint32_t **rpayload)
case CMD_ENTER_MODE:
func = svdm_rsp.enter_mode;
break;
+ case CMD_DP_STATUS:
+ func = svdm_rsp.amode->status;
+ break;
+ case CMD_DP_CONFIG:
+ func = svdm_rsp.amode->config;
+ break;
case CMD_EXIT_MODE:
func = svdm_rsp.exit_mode;
break;
@@ -232,12 +238,13 @@ int pd_svdm(int port, int cnt, uint32_t *payload, uint32_t **rpayload)
if (func)
rsize = func(port, payload);
else /* not supported : NACK it */
- rsize = 1;
- if (rsize > 1)
+ rsize = 0;
+ if (rsize >= 1)
payload[0] |= VDO_CMDT(CMDT_RSP_ACK);
- else if (rsize == 1)
+ else if (!rsize) {
payload[0] |= VDO_CMDT(CMDT_RSP_NAK);
- else {
+ rsize = 1;
+ } else {
payload[0] |= VDO_CMDT(CMDT_RSP_BUSY);
rsize = 1;
}
@@ -259,6 +266,14 @@ 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)
+ rsize = pe[port].amode.fx->status(port,
+ payload);
+ break;
+ case CMD_DP_STATUS:
+ rsize = pe[port].amode.fx->config(port, payload);
+ break;
+ case CMD_DP_CONFIG:
rsize = 0;
break;
case CMD_EXIT_MODE:
diff --git a/include/usb_pd.h b/include/usb_pd.h
index 48acbb0f6c..29c0165ad2 100644
--- a/include/usb_pd.h
+++ b/include/usb_pd.h
@@ -106,6 +106,12 @@ enum pd_errors {
/* TODO(tbroch) is there a finite number for these in the spec */
#define SVID_DISCOVERY_MAX 16
+/* function table for entered mode */
+struct amode_fx {
+ int (*status)(int port, uint32_t *payload);
+ int (*config)(int port, uint32_t *payload);
+};
+
/* function table for alternate mode capable responders */
struct svdm_response {
int (*identity)(int port, uint32_t *payload);
@@ -113,6 +119,7 @@ struct svdm_response {
int (*modes)(int port, uint32_t *payload);
int (*enter_mode)(int port, uint32_t *payload);
int (*exit_mode)(int port, uint32_t *payload);
+ struct amode_fx *amode;
};
struct svdm_svid_data {
@@ -124,6 +131,8 @@ struct svdm_svid_data {
struct svdm_amode_fx {
uint16_t svid;
void (*enter)(int port, uint32_t mode_caps);
+ int (*status)(int port, uint32_t *payload);
+ int (*config)(int port, uint32_t *payload);
void (*exit)(int port);
};
@@ -140,6 +149,12 @@ struct svdm_amode_data {
uint32_t mode_caps;
};
+enum hpd_level {
+ hpd_unknown = -1,
+ hpd_low = 0,
+ hpd_high,
+};
+
/* Policy structure for driving alternate mode */
struct pd_policy {
/* index of svid currently being operated on */
@@ -162,7 +177,7 @@ struct pd_policy {
* ----------
* <31:16> :: SVID
* <15> :: VDM type ( 1b == structured, 0b == unstructured )
- * <14:13> :: Structured VDM version
+ * <14:13> :: Structured VDM version (can only be 00 == 1.0 currently)
* <12:11> :: reserved
* <10:8> :: object position (1-7 valid ... used for enter/exit mode only)
* <7:6> :: command type (SVDM only?)
@@ -191,12 +206,15 @@ struct pd_policy {
#define VDO_SRC_INITIATOR (0 << 5)
#define VDO_SRC_RESPONDER (1 << 5)
-#define CMD_DISCOVER_IDENT 1
-#define CMD_DISCOVER_SVID 2
-#define CMD_DISCOVER_MODES 3
-#define CMD_ENTER_MODE 4
-#define CMD_EXIT_MODE 5
-#define CMD_ATTENTION 6
+#define CMD_DISCOVER_IDENT 1
+#define CMD_DISCOVER_SVID 2
+#define CMD_DISCOVER_MODES 3
+#define CMD_ENTER_MODE 4
+#define CMD_EXIT_MODE 5
+#define CMD_ATTENTION 6
+#define CMD_DP_STATUS 16
+#define CMD_DP_CONFIG 17
+
#define VDO_CMD_VENDOR(x) (((10 + (x)) & 0x1f))
/* ChromeOS specific commands */
@@ -371,6 +389,40 @@ struct pd_policy {
#define MODE_DP_BOTH 0x3
/*
+ * DisplayPort Status VDO
+ * ----------------------
+ * <31:9> : SBZ
+ * <8> : IRQ_HPD : 1 == irq arrived since last message otherwise 0.
+ * <7> : HPD state : 0 = HPD_LOW, 1 == HPD_HIGH
+ * <6> : Exit DP Alt mode: 0 == maintain, 1 == exit
+ * <5> : USB config : 0 == maintain current, 1 == switch to USB from DP
+ * <4> : Multi-function preference : 0 == no pref, 1 == MF preferred.
+ * <3> : enabled : is DPout on/off.
+ * <2> : power low : 0 == normal or LPM disabled, 1 == DP disabled for LPM
+ * <1:0> : connect status : 00b == no (DFP|UFP)_D is connected or disabled.
+ * 01b == DFP_D connected, 10b == UFP_D connected, 11b == both.
+ */
+#define VDO_DP_STATUS(irq, lvl, amode, usbc, mf, en, lp, conn) \
+ (((irq) & 1) << 8 | ((lvl) & 1) << 7 | ((amode) & 1) << 6 \
+ | ((usbc) & 1) << 5 | ((mf) & 1) << 4 | ((en) & 1) << 3 \
+ | ((lp) & 1) << 2 | ((conn & 0x3) << 0))
+/*
+ * DisplayPort Configure VDO
+ * -------------------------
+ * <31:24> : SBZ
+ * <23:16> : sink pin assignment supported (same as mode caps)
+ * <15:8> : source pin assignment supported (same as mode caps)
+ * <7:6> : SBZ
+ * <5:2> : signalling : 0h == unspec'd, 1h == dp v1.3,
+ * 2h == USB gen2, remaining rsv
+ * <1:0> : cfg : 00 == USB, 01|10 == DP, 11 == reserved
+ */
+#define VDO_DP_CFG(snkp, srcp, sig, cfg) \
+ (((snkp) & 0xff) << 16 | ((srcp) & 0xff) << 8 \
+ | ((sig) & 0x7) << 2 | ((cfg) & 0x3))
+
+#define PD_DP_CFG_DPON(x) (((x & 0x3) == 1) || ((x & 0x3) == 2))
+/*
* ChromeOS specific PD device Hardware IDs. Used to identify unique
* products and used in VDO_INFO. Note this field is 10 bits.
*/