From 57ed659cb9abdb659ee472cdd1c1f1069a3e2b6d Mon Sep 17 00:00:00 2001 From: Daisuke Nojiri Date: Mon, 12 Dec 2022 17:27:50 -0800 Subject: USB-PD: Update EC_CMD_TYPEC_STATUS for EPR Currently, EC_CMD_TYPEC_STATUS can carry up to 7 PDOs. With EPR, the max number of PDOs is 11. This patch adds version 1 of the command with the new response struct which has 11 slots for source caps and sink caps. BRANCH=None BUG=b:257320026 TEST=Tested v0 on Vell. v1 will be tested when time comes. Signed-off-by: Daisuke Nojiri Change-Id: I694b5897de7faee8e492c7cdc196ff94dd9c8fb4 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/4294392 Reviewed-by: Keith Short --- common/usbc/usb_pd_host.c | 100 ++++++++++++++++++++++++++++++++-------------- include/ec_commands.h | 54 ++++++++++++++++++++++++- 2 files changed, 123 insertions(+), 31 deletions(-) diff --git a/common/usbc/usb_pd_host.c b/common/usbc/usb_pd_host.c index 5f57393bb2..06da8a711c 100644 --- a/common/usbc/usb_pd_host.c +++ b/common/usbc/usb_pd_host.c @@ -178,40 +178,67 @@ static enum ec_status hc_typec_control(struct host_cmd_handler_args *args) } DECLARE_HOST_COMMAND(EC_CMD_TYPEC_CONTROL, hc_typec_control, EC_VER_MASK(0)); +/* + * Validate ec_response_typec_status_v0's binary compatibility with + * ec_response_typec_status, which is being deprecated. + */ +BUILD_ASSERT(offsetof(struct ec_response_typec_status_v0, + typec_status.sop_prime_revision) == + offsetof(struct ec_response_typec_status, sop_prime_revision)); +BUILD_ASSERT(offsetof(struct ec_response_typec_status_v0, source_cap_pdos) == + offsetof(struct ec_response_typec_status, source_cap_pdos)); +BUILD_ASSERT(sizeof(struct ec_response_typec_status_v0) == + sizeof(struct ec_response_typec_status)); + +/* + * Validate ec_response_typec_status_v0's binary compatibility with + * ec_response_typec_status_v1 with respect to typec_status. + */ +BUILD_ASSERT(offsetof(struct ec_response_typec_status_v0, + typec_status.pd_enabled) == + offsetof(struct ec_response_typec_status_v1, + typec_status.pd_enabled)); +BUILD_ASSERT(offsetof(struct ec_response_typec_status_v0, + typec_status.sop_prime_revision) == + offsetof(struct ec_response_typec_status_v1, + typec_status.sop_prime_revision)); + static enum ec_status hc_typec_status(struct host_cmd_handler_args *args) { const struct ec_params_typec_status *p = args->params; - struct ec_response_typec_status *r = args->response; + struct ec_response_typec_status_v1 *r1 = args->response; + struct ec_response_typec_status_v0 *r0 = args->response; + struct cros_ec_typec_status *cs = &r1->typec_status; const char *tc_state_name; if (p->port >= board_get_usb_pd_port_count()) return EC_RES_INVALID_PARAM; - if (args->response_max < sizeof(*r)) - return EC_RES_RESPONSE_TOO_BIG; + args->response_size = args->version == 0 ? sizeof(*r0) : sizeof(*r1); - args->response_size = sizeof(*r); + if (args->response_max < args->response_size) + return EC_RES_RESPONSE_TOO_BIG; - r->pd_enabled = pd_comm_is_enabled(p->port); - r->dev_connected = pd_is_connected(p->port); - r->sop_connected = pd_capable(p->port); + cs->pd_enabled = pd_comm_is_enabled(p->port); + cs->dev_connected = pd_is_connected(p->port); + cs->sop_connected = pd_capable(p->port); - r->power_role = pd_get_power_role(p->port); - r->data_role = pd_get_data_role(p->port); - r->vconn_role = pd_get_vconn_state(p->port) ? PD_ROLE_VCONN_SRC : - PD_ROLE_VCONN_OFF; - r->polarity = pd_get_polarity(p->port); - r->cc_state = pd_get_task_cc_state(p->port); - r->dp_pin = get_dp_pin_mode(p->port); - r->mux_state = usb_mux_get(p->port); + cs->power_role = pd_get_power_role(p->port); + cs->data_role = pd_get_data_role(p->port); + cs->vconn_role = pd_get_vconn_state(p->port) ? PD_ROLE_VCONN_SRC : + PD_ROLE_VCONN_OFF; + cs->polarity = pd_get_polarity(p->port); + cs->cc_state = pd_get_task_cc_state(p->port); + cs->dp_pin = get_dp_pin_mode(p->port); + cs->mux_state = usb_mux_get(p->port); tc_state_name = pd_get_task_state_name(p->port); - strzcpy(r->tc_state, tc_state_name, sizeof(r->tc_state)); + strzcpy(cs->tc_state, tc_state_name, sizeof(cs->tc_state)); - r->events = pd_get_events(p->port); + cs->events = pd_get_events(p->port); if (pd_get_partner_rmdo(p->port).major_rev != 0) { - r->sop_revision = + cs->sop_revision = PD_STATUS_RMDO_REV_SET_MAJOR( pd_get_partner_rmdo(p->port).major_rev) | PD_STATUS_RMDO_REV_SET_MINOR( @@ -220,28 +247,41 @@ static enum ec_status hc_typec_status(struct host_cmd_handler_args *args) pd_get_partner_rmdo(p->port).major_ver) | PD_STATUS_RMDO_VER_SET_MINOR( pd_get_partner_rmdo(p->port).minor_ver); - } else if (r->sop_connected) { - r->sop_revision = PD_STATUS_REV_SET_MAJOR( + } else if (cs->sop_connected) { + cs->sop_revision = PD_STATUS_REV_SET_MAJOR( pd_get_rev(p->port, TCPCI_MSG_SOP)); } else { - r->sop_revision = 0; + cs->sop_revision = 0; } - r->sop_prime_revision = + cs->sop_prime_revision = pd_get_identity_discovery(p->port, TCPCI_MSG_SOP_PRIME) == PD_DISC_COMPLETE ? PD_STATUS_REV_SET_MAJOR( pd_get_rev(p->port, TCPCI_MSG_SOP_PRIME)) : 0; - r->source_cap_count = pd_get_src_cap_cnt(p->port); - memcpy(r->source_cap_pdos, pd_get_src_caps(p->port), - r->source_cap_count * sizeof(uint32_t)); - - r->sink_cap_count = pd_get_snk_cap_cnt(p->port); - memcpy(r->sink_cap_pdos, pd_get_snk_caps(p->port), - r->sink_cap_count * sizeof(uint32_t)); + if (args->version == 0) { + cs->source_cap_count = MIN(pd_get_src_cap_cnt(p->port), + ARRAY_SIZE(r0->source_cap_pdos)); + memcpy(r0->source_cap_pdos, pd_get_src_caps(p->port), + cs->source_cap_count * sizeof(uint32_t)); + cs->sink_cap_count = MIN(pd_get_snk_cap_cnt(p->port), + ARRAY_SIZE(r0->sink_cap_pdos)); + memcpy(r0->sink_cap_pdos, pd_get_snk_caps(p->port), + cs->sink_cap_count * sizeof(uint32_t)); + } else { + cs->source_cap_count = MIN(pd_get_src_cap_cnt(p->port), + ARRAY_SIZE(r1->source_cap_pdos)); + memcpy(r1->source_cap_pdos, pd_get_src_caps(p->port), + cs->source_cap_count * sizeof(uint32_t)); + cs->sink_cap_count = MIN(pd_get_snk_cap_cnt(p->port), + ARRAY_SIZE(r1->sink_cap_pdos)); + memcpy(r1->sink_cap_pdos, pd_get_snk_caps(p->port), + cs->sink_cap_count * sizeof(uint32_t)); + } return EC_RES_SUCCESS; } -DECLARE_HOST_COMMAND(EC_CMD_TYPEC_STATUS, hc_typec_status, EC_VER_MASK(0)); +DECLARE_HOST_COMMAND(EC_CMD_TYPEC_STATUS, hc_typec_status, + EC_VER_MASK(0) | EC_VER_MASK(1)); diff --git a/include/ec_commands.h b/include/ec_commands.h index a74543bd93..ecf499eb84 100644 --- a/include/ec_commands.h +++ b/include/ec_commands.h @@ -7029,7 +7029,12 @@ struct ec_params_typec_status { uint8_t port; } __ec_align1; -struct ec_response_typec_status { +/* + * ec_response_typec_status is deprecated. Use ec_response_typec_status_v1. + * If you need to support old ECs who speak only v0, use + * ec_response_typec_status_v0 instead. They're binary-compatible. + */ +struct ec_response_typec_status /* DEPRECATED */ { uint8_t pd_enabled; /* PD communication enabled - bool */ uint8_t dev_connected; /* Device connected - bool */ uint8_t sop_connected; /* Device is SOP PD capable - bool */ @@ -7068,6 +7073,53 @@ struct ec_response_typec_status { uint32_t sink_cap_pdos[7]; /* Max 7 PDOs can be present */ } __ec_align1; +struct cros_ec_typec_status { + uint8_t pd_enabled; /* PD communication enabled - bool */ + uint8_t dev_connected; /* Device connected - bool */ + uint8_t sop_connected; /* Device is SOP PD capable - bool */ + uint8_t source_cap_count; /* Number of Source Cap PDOs */ + + uint8_t power_role; /* enum pd_power_role */ + uint8_t data_role; /* enum pd_data_role */ + uint8_t vconn_role; /* enum pd_vconn_role */ + uint8_t sink_cap_count; /* Number of Sink Cap PDOs */ + + uint8_t polarity; /* enum tcpc_cc_polarity */ + uint8_t cc_state; /* enum pd_cc_states */ + uint8_t dp_pin; /* DP pin mode (MODE_DP_IN_[A-E]) */ + uint8_t mux_state; /* USB_PD_MUX* - encoded mux state */ + + char tc_state[32]; /* TC state name */ + + uint32_t events; /* PD_STATUS_EVENT bitmask */ + + /* + * BCD PD revisions for partners + * + * The format has the PD major revision in the upper nibble, and the PD + * minor revision in the next nibble. The following two nibbles hold the + * major and minor specification version. If a partner does not support + * the Revision message, only the major revision will be given. + * ex. PD Revision 3.2 Version 1.9 would map to 0x3219 + * + * PD revision/version will be 0 if no PD device is connected. + */ + uint16_t sop_revision; + uint16_t sop_prime_revision; +} __ec_align1; + +struct ec_response_typec_status_v0 { + struct cros_ec_typec_status typec_status; + uint32_t source_cap_pdos[7]; /* Max 7 PDOs can be present */ + uint32_t sink_cap_pdos[7]; /* Max 7 PDOs can be present */ +} __ec_align1; + +struct ec_response_typec_status_v1 { + struct cros_ec_typec_status typec_status; + uint32_t source_cap_pdos[11]; /* Max 11 PDOs can be present */ + uint32_t sink_cap_pdos[11]; /* Max 11 PDOs can be present */ +} __ec_align1; + /** * Get the number of peripheral charge ports */ -- cgit v1.2.1