diff options
author | Todd Broch <tbroch@chromium.org> | 2014-11-20 17:24:27 -0800 |
---|---|---|
committer | ChromeOS Commit Bot <chromeos-commit-bot@chromium.org> | 2015-01-16 07:16:13 +0000 |
commit | abecc13a87fe445bb52194bc105cd70093bc8739 (patch) | |
tree | e78eaa663ef779694ef0551b6f400f90467c7c05 | |
parent | 16655133eeb1c77fafa2bc19a064c5b07e74aadc (diff) | |
download | chrome-ec-abecc13a87fe445bb52194bc105cd70093bc8739.tar.gz |
Add USB-PD mode commands.
These commands (pdgetmode & pdsetmode) will provide host with ability
to identify USB-PD alternate mode devices SVIDs and supported modes.
It will also allow host to set mode on devices which support multiple
alternate modes.
Signed-off-by: Todd Broch <tbroch@chromium.org>
BRANCH=samus
BUG=chrome-os-partner:33946
TEST=manual
Plug hoho/dingdong into samus at port <port>
ectool --name cros_pd pdgetmode <port>
*SVID:0xff01 *0x00001085 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
SVID:0x18d1 0x00000001 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
ectool --name cros_pd pdsetmode <port> 0x18d1 1
ectool --name cros_pd pdgetmode <port>
SVID:0xff01 0x00001085 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
*SVID:0x18d1 *0x00000001 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
ectool --name cros_pd infopddev <port>
Port:1 DevId:4.1 Hash: 0x042cc79c 0x30cc12e3 0xe27a36e5 0x3f7eba5f 0x053c91d1
Port:1 ptype:5 vid:0x18d1 pid:0x5010
Also from samus_pd console see proper result for 'typec <port>'
typec 1
Port C1: CC1 178 mV CC2 427 mV (polarity:CC2)
No Superspeed connection
Also visually inspect packets via twinkie.
Change-Id: I4e442bcb39ec1ff3cb6efff196a660819077ad76
Reviewed-on: https://chromium-review.googlesource.com/231834
Tested-by: Todd Broch <tbroch@chromium.org>
Reviewed-by: Alec Berg <alecaberg@chromium.org>
-rw-r--r-- | common/usb_pd_policy.c | 63 | ||||
-rw-r--r-- | common/usb_pd_protocol.c | 37 | ||||
-rw-r--r-- | include/ec_commands.h | 22 | ||||
-rw-r--r-- | util/ectool.c | 76 |
4 files changed, 185 insertions, 13 deletions
diff --git a/common/usb_pd_policy.c b/common/usb_pd_policy.c index a450272338..b95ef726d0 100644 --- a/common/usb_pd_policy.c +++ b/common/usb_pd_policy.c @@ -260,20 +260,23 @@ int pd_alt_mode(int port) return pe[port].amode.index + 1; } -/* TODO(tbroch) this function likely needs to move up the stack to where system - * policy decisions are made. */ -static int dfp_enter_mode(int port, uint32_t *payload) +/* Enter default mode or attempt to enter mode via svid & index arguments */ +static int dfp_enter_mode(int port, uint32_t *payload, int use_payload) { int i, j, done; struct svdm_amode_data *modep = &pe[port].amode; + uint16_t svid = (use_payload) ? PD_VDO_VID(payload[0]) : 0; + uint8_t opos = (use_payload) ? PD_VDO_OPOS(payload[0]) : 0; + 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) + struct svdm_svid_data *svidp = &pe[port].svids[j]; + if ((svidp->svid != supported_modes[i].svid) || + (svid && (svidp->svid != svid))) continue; - pe[port].amode.fx = &supported_modes[i]; - pe[port].amode.mode_caps = - pe[port].svids[j].mode_vdo[0]; - pe[port].amode.index = 0; + modep->fx = &supported_modes[i]; + modep->mode_caps = pe[port].svids[j].mode_vdo[0]; + modep->index = (opos && (opos < 7)) ? opos - 1 : 0; done = 1; break; } @@ -478,16 +481,19 @@ int pd_svdm(int port, int cnt, uint32_t *payload, uint32_t **rpayload) dfp_consume_modes(port, cnt, payload); rsize = dfp_discover_modes(port, payload); if (!rsize) - rsize = dfp_enter_mode(port, payload); + rsize = dfp_enter_mode(port, payload, 0); break; case CMD_ENTER_MODE: + /* + * TODO(crosbug.com/p/33946): Fix won't allow multiple + * mode entry. + */ + if (!AMODE_VALID(port)) + dfp_enter_mode(port, payload, 1); if (AMODE_VALID(port)) { rsize = pe[port].amode.fx->status(port, payload); - payload[0] |= - VDO_OPOS(pd_alt_mode(port)); - } else { - rsize = 0; + payload[0] |= VDO_OPOS(pd_alt_mode(port)); } break; case CMD_DP_STATUS: @@ -602,6 +608,37 @@ static int hc_remote_pd_discovery(struct host_cmd_handler_args *args) DECLARE_HOST_COMMAND(EC_CMD_USB_PD_DISCOVERY, hc_remote_pd_discovery, EC_VER_MASK(0)); + +static int hc_remote_pd_get_amode(struct host_cmd_handler_args *args) +{ + const struct ec_params_usb_pd_get_mode_request *p = args->params; + struct ec_params_usb_pd_get_mode_response *r = args->response; + + if (p->port >= PD_PORT_COUNT) + return EC_RES_INVALID_PARAM; + + /* no more to send */ + if (p->svid_idx >= pe[p->port].svid_cnt) { + r->svid = 0; + args->response_size = sizeof(r->svid); + return EC_RES_SUCCESS; + } + + r->svid = pe[p->port].svids[p->svid_idx].svid; + r->active = 0; + memcpy(r->vdo, pe[p->port].svids[p->svid_idx].mode_vdo, 24); + + if (AMODE_VALID(p->port) && pe[p->port].amode.fx->svid == r->svid) { + r->active = 1; + r->idx = pd_alt_mode(p->port) - 1; + } + args->response_size = sizeof(*r); + return EC_RES_SUCCESS; +} +DECLARE_HOST_COMMAND(EC_CMD_USB_PD_GET_AMODE, + hc_remote_pd_get_amode, + EC_VER_MASK(0)); + #endif #define FW_RW_END (CONFIG_FW_RW_OFF + CONFIG_FW_RW_SIZE) diff --git a/common/usb_pd_protocol.c b/common/usb_pd_protocol.c index 5ec8fea6ec..1b45d5e0c4 100644 --- a/common/usb_pd_protocol.c +++ b/common/usb_pd_protocol.c @@ -1726,6 +1726,11 @@ void pd_task(void) /* Initialize physical layer */ pd_hw_init(port); +#ifdef CONFIG_USB_PD_ALT_MODE_DFP + /* Initialize PD Policy engine */ + pd_dfp_pe_init(port); +#endif + while (1) { /* process VDM messages last */ pd_vdm_send_state_machine(port); @@ -3375,4 +3380,36 @@ DECLARE_HOST_COMMAND(EC_CMD_USB_PD_DEV_INFO, hc_remote_pd_dev_info, EC_VER_MASK(0)); +#ifdef CONFIG_USB_PD_ALT_MODE_DFP +static int hc_remote_pd_set_amode(struct host_cmd_handler_args *args) +{ + const struct ec_params_usb_pd_set_mode_request *p = args->params; + + if (p->port >= PD_PORT_COUNT) + return EC_RES_INVALID_PARAM; + + /* if in a mode exit it */ + /* TODO(crosbug.com/p/33946): allow entry of multiple modes */ + if (pd_alt_mode(p->port)) { + uint32_t vdo = pd_dfp_exit_mode(p->port); + if (vdo) { + queue_vdm(p->port, &vdo, NULL, 0); + task_wake(PORT_TO_TASK_ID(p->port)); + /* Wait until exit VDM is done */ + while (pd[p->port].vdm_state > 0) + task_wait_event(PD_T_VDM_E_MODE); + } + } + + /* now try to enter new one. */ + pd_send_vdm(p->port, p->svid, + CMD_ENTER_MODE | VDO_OPOS(p->opos), NULL, 0); + + return EC_RES_SUCCESS; +} +DECLARE_HOST_COMMAND(EC_CMD_USB_PD_SET_AMODE, + hc_remote_pd_set_amode, + EC_VER_MASK(0)); +#endif /* CONFIG_USB_PD_ALT_MODE_DFP */ + #endif /* CONFIG_COMMON_RUNTIME */ diff --git a/include/ec_commands.h b/include/ec_commands.h index 357c1de432..1c4efdfdcc 100644 --- a/include/ec_commands.h +++ b/include/ec_commands.h @@ -2920,6 +2920,28 @@ struct ec_response_pd_log { #define PS_FAULT_OVP 3 #define PS_FAULT_DISCH 4 +/* Get/Set USB-PD Alternate mode info */ +#define EC_CMD_USB_PD_GET_AMODE 0x116 +struct ec_params_usb_pd_get_mode_request { + uint16_t svid_idx; /* SVID index to get */ + uint8_t port; /* port */ +} __packed; + +struct ec_params_usb_pd_get_mode_response { + uint16_t svid; /* SVID */ + uint8_t active; /* Active SVID */ + uint8_t idx; /* Index of active mode VDO. Ignored if !active */ + uint32_t vdo[6]; /* Mode VDOs */ +} __packed; + +#define EC_CMD_USB_PD_SET_AMODE 0x117 +struct ec_params_usb_pd_set_mode_request { + int opos; /* Object Position */ + int svid_idx; /* Index of svid to get */ + uint16_t svid; /* SVID to set */ + uint8_t port; /* port */ +} __packed; + #endif /* !__ACPI__ */ /*****************************************************************************/ diff --git a/util/ectool.c b/util/ectool.c index 142c248d3f..e78ef5d65f 100644 --- a/util/ectool.c +++ b/util/ectool.c @@ -140,6 +140,10 @@ const char help_str[] = " Whether or not the AP should pause in S5 on shutdown\n" " pdlog\n" " Prints the PD event log entries\n" + " pdgetmode <port>\n" + " Get All USB-PD alternate SVIDs and modes on <port>\n" + " pdsetmode <port> <svid> <opos>\n" + " Set USB-PD alternate SVID and mode on <port>\n" " port80flood\n" " Rapidly write bytes to port 80\n" " port80read\n" @@ -1000,6 +1004,76 @@ pd_flash_error: return -1; } +int cmd_pd_set_amode(int argc, char *argv[]) +{ + char *e; + struct ec_params_usb_pd_set_mode_request *p = + (struct ec_params_usb_pd_set_mode_request *)ec_outbuf; + + if (argc < 4) { + fprintf(stderr, "Usage: %s <port> <svid> <opos>\n", argv[0]); + return -1; + } + + p->port = strtol(argv[1], &e, 0); + if (e && *e) { + fprintf(stderr, "Bad port\n"); + return -1; + } + + p->svid = strtol(argv[2], &e, 0); + if (e && *e) { + fprintf(stderr, "Bad svid\n"); + return -1; + } + + p->opos = strtol(argv[3], &e, 0); + if (e && *e) { + fprintf(stderr, "Bad mode\n"); + return -1; + } + + return ec_command(EC_CMD_USB_PD_SET_AMODE, 0, p, sizeof(*p), NULL, 0); +} + +int cmd_pd_get_amode(int argc, char *argv[]) +{ + int i; + char *e; + struct ec_params_usb_pd_get_mode_request *p = + (struct ec_params_usb_pd_get_mode_request *)ec_outbuf; + struct ec_params_usb_pd_get_mode_response *r = + (struct ec_params_usb_pd_get_mode_response *)ec_inbuf; + + if (argc < 2) { + fprintf(stderr, "Usage: %s <port>\n", argv[0]); + return -1; + } + + p->port = strtol(argv[1], &e, 0); + if (e && *e) { + fprintf(stderr, "Bad port\n"); + return -1; + } + + p->svid_idx = 0; + do { + ec_command(EC_CMD_USB_PD_GET_AMODE, 0, p, sizeof(*p), + ec_inbuf, ec_max_insize); + if (!r->svid) + break; + printf("%cSVID:0x%04x ", (r->active) ? '*' : ' ', + r->svid); + for (i = 0; i < PDO_MODES; i++) { + printf("%c0x%08x ", (r->active && (r->idx == i)) ? + '*' : ' ', r->vdo[i]); + } + printf("\n"); + p->svid_idx++; + } while (p->svid_idx < SVID_DISCOVERY_MAX); + return -1; +} + #ifdef __x86_64 #include <sys/io.h> @@ -5334,6 +5408,8 @@ const struct command commands[] = { {"nextevent", cmd_next_event}, {"panicinfo", cmd_panic_info}, {"pause_in_s5", cmd_s5}, + {"pdgetmode", cmd_pd_get_amode}, + {"pdsetmode", cmd_pd_set_amode}, {"port80read", cmd_port80_read}, {"pdlog", cmd_pd_log}, {"powerinfo", cmd_power_info}, |