diff options
author | Todd Broch <tbroch@chromium.org> | 2014-10-10 11:16:02 -0700 |
---|---|---|
committer | chrome-internal-fetch <chrome-internal-fetch@google.com> | 2014-10-21 22:44:45 +0000 |
commit | cefb58066d2a706ad34726aff977be3a584fc001 (patch) | |
tree | 8c1eb1efaac6beb6ae9bca6507ba79a45d580686 | |
parent | 3e2f1329abfa729fe6786ff64d9545e6ce94f042 (diff) | |
download | chrome-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.c | 54 | ||||
-rw-r--r-- | board/fruitpie/usb_pd_policy.c | 30 | ||||
-rw-r--r-- | board/hoho/usb_pd_policy.c | 51 | ||||
-rw-r--r-- | board/samus_pd/usb_pd_policy.c | 40 | ||||
-rw-r--r-- | common/usb_pd_policy.c | 23 | ||||
-rw-r--r-- | include/usb_pd.h | 66 |
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. */ |