summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDiana Z <dzigterman@chromium.org>2022-10-28 14:19:21 -0600
committerChromeos LUCI <chromeos-scoped@luci-project-accounts.iam.gserviceaccount.com>2022-12-13 22:43:14 +0000
commit3a705db54bc6f87df6e3b63db08fa379e9b02708 (patch)
treed5fffa2b5a471f9c5c306ecd44daf41dd8e166b6
parent29d14affe55ffc3a2bb9eee19c355b756aeb7f7e (diff)
downloadchrome-ec-3a705db54bc6f87df6e3b63db08fa379e9b02708.tar.gz
TCPMv2: Make VDM ACKs available to the AP
When the AP is supplying VDM REQ messages, the responses should be delivered to the AP after the message has either sent or failed to send. Add storage of the reply in the DPM. BRANCH=None BUG=b:208884535 TEST=./twister -T ./zephyr/test, on skyrim ensure VDM responses and events are seen for both successful and unsuccessful REQs Signed-off-by: Diana Z <dzigterman@chromium.org> Change-Id: Ica713c3b3f3f571f193c1458a0e28788cd205c72 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3990995 Reviewed-by: Abe Levkoy <alevkoy@chromium.org> Code-Coverage: Zoss <zoss-cl-coverage@prod.google.com>
-rw-r--r--common/usbc/usb_pd_dpm.c80
-rw-r--r--common/usbc/usb_pd_host.c29
-rw-r--r--include/ec_commands.h22
-rw-r--r--include/usb_pd_dpm_sm.h15
-rw-r--r--util/ectool.cc42
5 files changed, 182 insertions, 6 deletions
diff --git a/common/usbc/usb_pd_dpm.c b/common/usbc/usb_pd_dpm.c
index 13c84075f2..0c2bfe3b25 100644
--- a/common/usbc/usb_pd_dpm.c
+++ b/common/usbc/usb_pd_dpm.c
@@ -57,6 +57,11 @@ static struct {
enum tcpci_msg_type req_type;
mutex_t vdm_req_mutex;
enum dpm_pd_button_state pd_button_state;
+#ifdef CONFIG_USB_PD_VDM_AP_CONTROL
+ uint32_t vdm_reply[VDO_MAX_SIZE];
+ uint8_t vdm_reply_cnt;
+ enum tcpci_msg_type vdm_reply_type;
+#endif
} dpm[CONFIG_USB_PD_PORT_MAX_COUNT];
#define DPM_SET_FLAG(port, flag) atomic_or(&dpm[(port)].flags, (flag))
@@ -170,7 +175,7 @@ enum ec_status pd_request_vdm(int port, const uint32_t *data, int vdo_count,
/*
* Indicate to DPM that a REQ message needs to be sent. This flag
* will be cleared when the REQ message is sent to the policy
- * engine.
+ * engine (VDM:Attention), or when the reply is received (all others).
*/
DPM_SET_FLAG(port, DPM_FLAG_SEND_VDM_REQ);
@@ -224,6 +229,10 @@ void dpm_init(int port)
{
dpm[port].flags = 0;
dpm[port].pd_button_state = DPM_PD_BUTTON_IDLE;
+#ifdef CONFIG_USB_PD_VDM_AP_CONTROL
+ /* Clear any stored AP messages */
+ dpm[port].vdm_reply_cnt = 0;
+#endif
/* Ensure that DPM state machine gets reset */
set_state_dpm(port, DPM_WAITING);
@@ -297,10 +306,21 @@ static bool dpm_mode_entry_requested(int port, enum typec_mode mode)
void dpm_vdm_acked(int port, enum tcpci_msg_type type, int vdo_count,
uint32_t *vdm)
{
- const uint16_t svid = PD_VDO_VID(vdm[0]);
+ __maybe_unused const uint16_t svid = PD_VDO_VID(vdm[0]);
assert(vdo_count >= 1);
+ assert(vdo_count <= VDO_MAX_SIZE);
+#ifdef CONFIG_USB_PD_VDM_AP_CONTROL
+ /* Don't alert the modules, only store and notify the AP */
+ dpm[port].vdm_reply_cnt = vdo_count;
+ memcpy(dpm[port].vdm_reply, vdm, vdo_count * sizeof(uint32_t));
+ dpm[port].vdm_reply_type = type;
+ pd_notify_event(port, PD_STATUS_EVENT_VDM_REQ_REPLY);
+
+ /* Clear the flag now that reply fields are updated */
+ DPM_CLR_FLAG(port, DPM_FLAG_SEND_VDM_REQ);
+#else
switch (svid) {
case USB_SID_DISPLAYPORT:
dp_vdm_acked(port, type, vdo_count, vdm);
@@ -314,16 +334,33 @@ void dpm_vdm_acked(int port, enum tcpci_msg_type type, int vdo_count,
break;
#else
__fallthrough;
-#endif
+#endif /* CONFIG_USB_PD_TBT_COMPAT_MODE */
default:
CPRINTS("C%d: Received unexpected VDM ACK for SVID %d", port,
svid);
}
+#endif /* CONFIG_USB_PD_VDM_AP_CONTROL */
}
void dpm_vdm_naked(int port, enum tcpci_msg_type type, uint16_t svid,
uint8_t vdm_cmd, uint32_t vdm_header)
{
+#ifdef CONFIG_USB_PD_VDM_AP_CONTROL
+ /* Don't alert the modules, only store and notify the AP */
+ dpm[port].vdm_reply_type = type;
+
+ if (vdm_header != 0) {
+ dpm[port].vdm_reply_cnt = 1;
+ dpm[port].vdm_reply[0] = vdm_header;
+ pd_notify_event(port, PD_STATUS_EVENT_VDM_REQ_REPLY);
+ } else {
+ dpm[port].vdm_reply_cnt = 0;
+ pd_notify_event(port, PD_STATUS_EVENT_VDM_REQ_FAILED);
+ }
+
+ /* Clear the flag now that reply fields are updated */
+ DPM_CLR_FLAG(port, DPM_FLAG_SEND_VDM_REQ);
+#else
switch (svid) {
case USB_SID_DISPLAYPORT:
dp_vdm_naked(port, type, vdm_cmd);
@@ -337,11 +374,32 @@ void dpm_vdm_naked(int port, enum tcpci_msg_type type, uint16_t svid,
break;
#else
__fallthrough;
-#endif
+#endif /* CONFIG_USB_PD_TBT_COMPAT_MODE */
default:
CPRINTS("C%d: Received unexpected VDM NAK for SVID %d", port,
svid);
}
+#endif /* CONFIG_USB_PD_VDM_AP_CONTROL */
+}
+
+enum ec_status dpm_copy_vdm_reply(int port, uint8_t *type, uint8_t *size,
+ uint32_t *buf)
+{
+#ifdef CONFIG_USB_PD_VDM_AP_CONTROL
+ if (DPM_CHK_FLAG(port, DPM_FLAG_SEND_VDM_REQ))
+ return EC_RES_BUSY;
+
+ if (dpm[port].vdm_reply_cnt == 0)
+ return EC_RES_UNAVAILABLE;
+
+ *type = dpm[port].vdm_reply_type;
+ *size = dpm[port].vdm_reply_cnt;
+ memcpy(buf, dpm[port].vdm_reply, *size * sizeof(uint32_t));
+
+ return EC_RES_SUCCESS;
+#else
+ return EC_RES_INVALID_COMMAND;
+#endif /* CONFIG_USB_PD_VDM_AP_CONTROL */
}
static void dpm_send_req_vdm(int port)
@@ -352,8 +410,18 @@ static void dpm_send_req_vdm(int port)
/* Trigger PE to start a VDM command run */
pd_dpm_request(port, DPM_REQUEST_VDM);
- /* Clear flag after message is sent to PE layer */
- DPM_CLR_FLAG(port, DPM_FLAG_SEND_VDM_REQ);
+ /*
+ * Clear flag after message is sent to PE layer if it was Attention,
+ * which generates no reply.
+ *
+ * Otherwise, clear flag after message is ACK'd or NAK'd. The flag
+ * will serve as a guard to indicate that the VDM reply buffer is not
+ * yet ready to read.
+ *
+ */
+ if (PD_VDO_SVDM(dpm[port].vdm_req[0]) &&
+ (PD_VDO_CMD(dpm[port].vdm_req[0]) == CMD_ATTENTION))
+ DPM_CLR_FLAG(port, DPM_FLAG_SEND_VDM_REQ);
}
void dpm_handle_alert(int port, uint32_t ado)
diff --git a/common/usbc/usb_pd_host.c b/common/usbc/usb_pd_host.c
index 0b3958cd47..bf891cf5ed 100644
--- a/common/usbc/usb_pd_host.c
+++ b/common/usbc/usb_pd_host.c
@@ -232,3 +232,32 @@ static enum ec_status hc_typec_status(struct host_cmd_handler_args *args)
return EC_RES_SUCCESS;
}
DECLARE_HOST_COMMAND(EC_CMD_TYPEC_STATUS, hc_typec_status, EC_VER_MASK(0));
+
+#ifdef CONFIG_USB_PD_VDM_AP_CONTROL
+static enum ec_status hc_typec_vdm_response(struct host_cmd_handler_args *args)
+{
+ const struct ec_params_typec_vdm_response *p = args->params;
+ struct ec_response_typec_vdm_response *r = args->response;
+ uint32_t data[VDO_MAX_SIZE];
+ enum ec_status rv;
+
+ 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 = sizeof(*r);
+
+ rv = dpm_copy_vdm_reply(p->port, &r->partner_type, &r->vdm_data_objects,
+ data);
+
+ if (r->vdm_data_objects > 0)
+ memcpy(r->vdm_response, data,
+ r->vdm_data_objects * sizeof(uint32_t));
+
+ return rv;
+}
+DECLARE_HOST_COMMAND(EC_CMD_TYPEC_VDM_RESPONSE, hc_typec_vdm_response,
+ EC_VER_MASK(0));
+#endif /* CONFIG_USB_PD_VDM_AP_CONTROL */
diff --git a/include/ec_commands.h b/include/ec_commands.h
index 77bb285a0b..eaaa9fc8a8 100644
--- a/include/ec_commands.h
+++ b/include/ec_commands.h
@@ -6920,6 +6920,8 @@ enum tcpc_cc_polarity {
#define PD_STATUS_EVENT_DISCONNECTED BIT(3)
#define PD_STATUS_EVENT_MUX_0_SET_DONE BIT(4)
#define PD_STATUS_EVENT_MUX_1_SET_DONE BIT(5)
+#define PD_STATUS_EVENT_VDM_REQ_REPLY BIT(6)
+#define PD_STATUS_EVENT_VDM_REQ_FAILED BIT(7)
/*
* Encode and decode for BCD revision response
@@ -7336,6 +7338,26 @@ struct ec_params_rgbkbd_set_color {
struct rgb_s color[];
} __ec_align1;
+/*
+ * Gather the response to the most recent VDM REQ from the AP
+ */
+#define EC_CMD_TYPEC_VDM_RESPONSE 0x013C
+
+struct ec_params_typec_vdm_response {
+ uint8_t port;
+} __ec_align1;
+
+struct ec_response_typec_vdm_response {
+ /* Number of 32-bit fields filled in */
+ uint8_t vdm_data_objects;
+ /* Partner to address - see enum typec_partner_type */
+ uint8_t partner_type;
+ /* Reserved */
+ uint16_t reserved;
+ /* VDM data, including VDM header */
+ uint32_t vdm_response[VDO_MAX_SIZE];
+} __ec_align1;
+
/*****************************************************************************/
/* The command range 0x200-0x2FF is reserved for Rotor. */
diff --git a/include/usb_pd_dpm_sm.h b/include/usb_pd_dpm_sm.h
index 81ab4bdf16..df84ae5e49 100644
--- a/include/usb_pd_dpm_sm.h
+++ b/include/usb_pd_dpm_sm.h
@@ -84,6 +84,21 @@ void dpm_vdm_naked(int port, enum tcpci_msg_type type, uint16_t svid,
uint8_t vdm_cmd, uint32_t vdm_header);
/*
+ * Populates the information for the last reply received for a VDM REQ
+ * message sent by the AP.
+ *
+ * @param[in] port USB-C port number
+ * @param[out] type Transmit type (SOP, SOP') for request
+ * @param[out] size The number of uint32_t fields filled in
+ * @param[out] buf Buffer for VDM header and VDOs
+ * @return EC_RES_SUCCESS if reply is ready
+ * EC_RES_BUSY if command is in progress
+ * EC_RES_UNAVAILABLE if no reply is present
+ * EC_RES_INVALID_COMMAND if feature not enabled
+ */
+enum ec_status dpm_copy_vdm_reply(int port, uint8_t *type, uint8_t *size,
+ uint32_t *buf);
+/*
* Determines the current allocation for the connection, past the basic
* CONFIG_USB_PD_PULLUP value set by the TC (generally 1.5 A)
*
diff --git a/util/ectool.cc b/util/ectool.cc
index 3c4b190c3c..76e617e3ba 100644
--- a/util/ectool.cc
+++ b/util/ectool.cc
@@ -342,6 +342,8 @@ const char help_str[] =
" Get discovery information for port and type\n"
" typecstatus <port>\n"
" Get status information for port\n"
+ " typecvdmresponse <port>\n"
+ " Get last VDM response for AP-requested VDM\n"
" uptimeinfo\n"
" Get info about how long the EC has been running and the most\n"
" recent AP resets\n"
@@ -10600,6 +10602,45 @@ int cmd_typec_status(int argc, char *argv[])
return 0;
}
+int cmd_typec_vdm_response(int argc, char *argv[])
+{
+ struct ec_params_typec_vdm_response p;
+ struct ec_response_typec_vdm_response *r =
+ (ec_response_typec_vdm_response *)ec_inbuf;
+ char *endptr;
+ int rv, i;
+
+ if (argc != 2) {
+ fprintf(stderr,
+ "Usage: %s <port>\n"
+ " <port> is the type-c port to query\n",
+ argv[0]);
+ return -1;
+ }
+
+ p.port = strtol(argv[1], &endptr, 0);
+ if (endptr && *endptr) {
+ fprintf(stderr, "Bad port\n");
+ return -1;
+ }
+
+ rv = ec_command(EC_CMD_TYPEC_VDM_RESPONSE, 0, &p, sizeof(p), ec_inbuf,
+ ec_max_insize);
+ if (rv < 0)
+ return -1;
+
+ if (r->vdm_data_objects > 0) {
+ printf("VDM response from partner: %d", r->partner_type);
+ for (i = 0; i < r->vdm_data_objects; i++)
+ printf("\n 0x%08x", r->vdm_response[i]);
+ printf("\n");
+ } else {
+ printf("No VDM response found\n");
+ }
+
+ return 0;
+}
+
int cmd_tp_self_test(int argc, char *argv[])
{
int rv;
@@ -11078,6 +11119,7 @@ const struct command commands[] = {
{ "typeccontrol", cmd_typec_control },
{ "typecdiscovery", cmd_typec_discovery },
{ "typecstatus", cmd_typec_status },
+ { "typecvdmresponse", cmd_typec_vdm_response },
{ "uptimeinfo", cmd_uptimeinfo },
{ "usbchargemode", cmd_usb_charge_set_mode },
{ "usbmux", cmd_usb_mux },