summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlec Berg <alecaberg@chromium.org>2014-07-31 15:52:37 -0700
committerchrome-internal-fetch <chrome-internal-fetch@google.com>2014-08-11 22:05:21 +0000
commit49ee1cb8727aa5826a12df44044ea0d4226b5273 (patch)
treef3fbe15eb034f649c701c096ee2cbd21ca3a630e
parentdc1834593ad379211b2d6922b85cd664b6110610 (diff)
downloadchrome-ec-49ee1cb8727aa5826a12df44044ea0d4226b5273.tar.gz
pd: modify PD to allow sending VDMs anytime
Change the VDM implementation in the PD task to allow for VDMs at any time when connected without disrupting any regular PD communications. BUG=none BRANCH=none TEST=load on a samus and on a zinger and test sending VDMs: pd 0 flash version pd 0 flash reboot Also, test using the flash_pd.py script to write zinger RW using VDMs. Change-Id: I48352978d8c45f78e8a5a7735d65b013a853f3e2 Signed-off-by: Alec Berg <alecaberg@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/210746 Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
-rw-r--r--common/usb_pd_protocol.c170
-rw-r--r--include/usb_pd.h20
-rwxr-xr-xutil/flash_pd.py4
3 files changed, 126 insertions, 68 deletions
diff --git a/common/usb_pd_protocol.c b/common/usb_pd_protocol.c
index 0df1c69605..cb3e28bd64 100644
--- a/common/usb_pd_protocol.c
+++ b/common/usb_pd_protocol.c
@@ -148,7 +148,6 @@ enum pd_states {
PD_STATE_SNK_REQUESTED,
PD_STATE_SNK_TRANSITION,
PD_STATE_SNK_READY,
- PD_STATE_VDM_COMM,
#endif /* CONFIG_USB_PD_DUAL_ROLE */
PD_STATE_SRC_DISCONNECTED,
@@ -162,6 +161,16 @@ enum pd_states {
PD_STATE_BIST,
};
+enum vdm_states {
+ VDM_STATE_ERR_BUSY = -3,
+ VDM_STATE_ERR_SEND = -2,
+ VDM_STATE_ERR_TMOUT = -1,
+ VDM_STATE_DONE = 0,
+ /* Anything >0 represents an active state */
+ VDM_STATE_READY = 1,
+ VDM_STATE_BUSY = 2,
+};
+
#ifdef CONFIG_USB_PD_DUAL_ROLE
/* Port dual-role state */
enum pd_dual_role_states drp_state = PD_DRP_TOGGLE_OFF;
@@ -193,6 +202,12 @@ static struct pd_protocol {
/* Current limit based on the last request message */
uint32_t curr_limit;
#endif
+
+ /* PD state for Vendor Defined Messages */
+ enum vdm_states vdm_state;
+ /* next Vendor Defined Message to send */
+ uint32_t vdo_data[VDO_MAX_SIZE];
+ uint8_t vdo_count;
} pd[PD_PORT_COUNT];
/*
@@ -448,10 +463,6 @@ static int send_request(int port, uint32_t rdo)
return bit_len;
}
-
-/* next Vendor Defined Message to send */
-static int vdo_count[PD_PORT_COUNT];
-static uint32_t vdo_data[PD_PORT_COUNT][7];
#endif /* CONFIG_USB_PD_DUAL_ROLE */
static int send_bist_cmd(int port)
@@ -531,9 +542,8 @@ static void handle_vdm_request(int port, int cnt, uint32_t *payload)
#endif
if (vid == USB_VID_GOOGLE) {
-#ifdef CONFIG_USB_PD_DUAL_ROLE
- vdo_count[port] = 0; /* Done */
-#endif
+ if (pd[port].vdm_state == VDM_STATE_BUSY)
+ pd[port].vdm_state = VDM_STATE_DONE;
#ifdef CONFIG_USB_PD_CUSTOM_VDM
rlen = pd_custom_vdm(port, cnt, payload, &rdata);
if (rlen > 0) {
@@ -893,9 +903,8 @@ static void execute_hard_reset(int port)
{
pd[port].msg_id = 0;
#ifdef CONFIG_USB_PD_DUAL_ROLE
- if (pd[port].task_state != PD_STATE_VDM_COMM)
- set_state(port, pd[port].role == PD_ROLE_SINK ?
- PD_STATE_SNK_DISCONNECTED : PD_STATE_SRC_DISCONNECTED);
+ set_state(port, pd[port].role == PD_ROLE_SINK ?
+ PD_STATE_SNK_DISCONNECTED : PD_STATE_SRC_DISCONNECTED);
/* Clear the input current limit */
pd_set_input_current_limit(0);
@@ -906,6 +915,57 @@ static void execute_hard_reset(int port)
CPRINTF("HARD RESET!\n");
}
+void pd_send_vdm(int port, uint32_t vid, int cmd, uint32_t *data, int count)
+{
+ int i;
+
+ pd[port].vdo_data[0] = VDO(vid, cmd);
+ pd[port].vdo_count = count + 1;
+ for (i = 1; i < count + 1; i++)
+ pd[port].vdo_data[i] = data[i-1];
+
+ /* Set ready, pd task will actually send */
+ pd[port].vdm_state = VDM_STATE_READY;
+ task_wake(PORT_TO_TASK_ID(port));
+}
+
+static void pd_vdm_send_state_machine(int port)
+{
+ int res;
+ uint16_t header;
+ static uint64_t vdm_timeout;
+
+ switch (pd[port].vdm_state) {
+ case VDM_STATE_READY:
+ /* Only transmit VDM if connected */
+ if (!pd_is_connected(port)) {
+ pd[port].vdm_state = VDM_STATE_ERR_BUSY;
+ break;
+ }
+
+ /* Prepare and send VDM */
+ header = PD_HEADER(PD_DATA_VENDOR_DEF, pd[port].role,
+ pd[port].msg_id, (int)pd[port].vdo_count);
+ res = send_validate_message(port, header,
+ pd[port].vdo_count,
+ pd[port].vdo_data);
+ if (res < 0) {
+ pd[port].vdm_state = VDM_STATE_ERR_SEND;
+ } else {
+ pd[port].vdm_state = VDM_STATE_BUSY;
+ vdm_timeout = get_time().val + 500*MSEC;
+ }
+ break;
+ case VDM_STATE_BUSY:
+ /* Wait for VDM response or timeout */
+ if (get_time().val > vdm_timeout)
+ pd[port].vdm_state = VDM_STATE_ERR_TMOUT;
+ break;
+ default:
+ break;
+ }
+}
+
#ifdef CONFIG_USB_PD_DUAL_ROLE
void pd_set_dual_role(enum pd_dual_role_states state)
{
@@ -973,6 +1033,7 @@ void pd_task(void)
/* Initialize PD protocol state variables for each port. */
pd[port].role = PD_ROLE_DEFAULT;
+ pd[port].vdm_state = VDM_STATE_DONE;
set_state(port, PD_DEFAULT_STATE);
/* Ensure the power supply is in the default state */
@@ -982,6 +1043,9 @@ void pd_task(void)
pd_hw_init(port);
while (1) {
+ /* process VDM messages last */
+ pd_vdm_send_state_machine(port);
+
/* monitor for incoming packet if in a connected state */
if (pd_is_connected(port) && pd_comm_enabled)
pd_rx_enable_monitoring(port);
@@ -1178,23 +1242,6 @@ void pd_task(void)
}
timeout = 100*MSEC;
break;
- case PD_STATE_VDM_COMM:
- if (vdo_count[port] > 7) { /* TIMEOUT */
- vdo_count[port] = -EC_ERROR_TIMEOUT;
- } else if (vdo_count[port] > 0) {
- int len;
- uint16_t header = PD_HEADER(PD_DATA_VENDOR_DEF,
- pd[port].role, pd[port].msg_id,
- vdo_count[port]);
- len = send_validate_message(port, header,
- vdo_count[port],
- vdo_data[port]);
- vdo_count[port] = 8; /* Transmitting */
- if (len < 0)
- vdo_count[port] = -EC_ERROR_BUSY;
- }
- timeout = 500*MSEC;
- break;
#endif /* CONFIG_USB_PD_DUAL_ROLE */
case PD_STATE_HARD_RESET:
send_hard_reset(port);
@@ -1242,14 +1289,12 @@ void pd_task(void)
#ifdef CONFIG_USB_PD_DUAL_ROLE
if (pd[port].role == PD_ROLE_SINK &&
!pd_snk_is_vbus_provided(port)) {
- if (pd[port].task_state != PD_STATE_VDM_COMM) {
- /* Sink: detect disconnect by monitoring VBUS */
- set_state(port, PD_STATE_SNK_DISCONNECTED);
- /* Clear the input current limit */
- pd_set_input_current_limit(0);
- /* set timeout small to reconnect fast */
- timeout = 5*MSEC;
- }
+ /* Sink: detect disconnect by monitoring VBUS */
+ set_state(port, PD_STATE_SNK_DISCONNECTED);
+ /* Clear the input current limit */
+ pd_set_input_current_limit(0);
+ /* set timeout small to reconnect fast */
+ timeout = 5*MSEC;
}
#endif /* CONFIG_USB_PD_DUAL_ROLE */
}
@@ -1292,60 +1337,61 @@ static int hex8tou32(char *str, uint32_t *val)
static int remote_flashing(int argc, char **argv)
{
- int port;
+ int port, cnt, cmd;
+ uint32_t data[VDO_MAX_SIZE-1];
char *e;
static int flash_offset[PD_PORT_COUNT];
- if (argc < 4)
+ if (argc < 4 || argc > (VDO_MAX_SIZE + 4 - 1))
return EC_ERROR_PARAM_COUNT;
port = strtoi(argv[1], &e, 10);
if (*e || port >= PD_PORT_COUNT)
return EC_ERROR_PARAM2;
+ cnt = 0;
if (!strcasecmp(argv[3], "erase")) {
- vdo_data[port][0] = VDO(USB_VID_GOOGLE, VDO_CMD_FLASH_ERASE);
- vdo_count[port] = 1;
+ cmd = VDO_CMD_FLASH_ERASE;
flash_offset[port] = 0;
ccprintf("ERASE ...");
} else if (!strcasecmp(argv[3], "reboot")) {
- vdo_data[port][0] = VDO(USB_VID_GOOGLE, VDO_CMD_REBOOT);
- vdo_count[port] = 1;
+ cmd = VDO_CMD_REBOOT;
ccprintf("REBOOT ...");
} else if (!strcasecmp(argv[3], "hash")) {
int i;
- for (i = 4; i < argc; i++)
- if (hex8tou32(argv[i], vdo_data[port] + i - 3))
+ argc -= 4;
+ for (i = 0; i < argc; i++)
+ if (hex8tou32(argv[i+4], data + i))
return EC_ERROR_INVAL;
- vdo_data[port][0] = VDO(USB_VID_GOOGLE, VDO_CMD_FLASH_HASH);
- vdo_count[port] = argc - 3;
+ cmd = VDO_CMD_FLASH_HASH;
+ cnt = argc;
ccprintf("HASH ...");
} else if (!strcasecmp(argv[3], "rw_hash")) {
- vdo_data[port][0] = VDO(USB_VID_GOOGLE, VDO_CMD_RW_HASH);
- vdo_count[port] = 1;
+ cmd = VDO_CMD_RW_HASH;
ccprintf("RW HASH...");
} else if (!strcasecmp(argv[3], "version")) {
- vdo_data[port][0] = VDO(USB_VID_GOOGLE, VDO_CMD_VERSION);
- vdo_count[port] = 1;
+ cmd = VDO_CMD_VERSION;
ccprintf("VERSION...");
} else {
int i;
- for (i = 3; i < argc; i++)
- if (hex8tou32(argv[i], vdo_data[port] + i - 2))
+ argc -= 3;
+ for (i = 0; i < argc; i++)
+ if (hex8tou32(argv[i+3], data + i))
return EC_ERROR_INVAL;
- vdo_data[port][0] = VDO(USB_VID_GOOGLE, VDO_CMD_FLASH_WRITE);
- vdo_count[port] = argc - 2;
- ccprintf("WRITE %d @%04x ...", (argc - 3) * 4,
+ cmd = VDO_CMD_FLASH_WRITE;
+ cnt = argc;
+ ccprintf("WRITE %d @%04x ...", argc * 4,
flash_offset[port]);
- flash_offset[port] += (argc - 3) * 4;
+ flash_offset[port] += argc * 4;
}
- set_state(port, PD_STATE_VDM_COMM);
- task_wake(PORT_TO_TASK_ID(port));
- /* Wait until VDO is done */
- while (vdo_count[port] > 0)
+ pd_send_vdm(port, USB_VID_GOOGLE, cmd, data, cnt);
+
+ /* Wait until VDM is done */
+ while (pd[port].vdm_state > 0)
task_wait_event(100*MSEC);
- ccprintf("DONE\n");
+
+ ccprintf("DONE %d\n", pd[port].vdm_state);
return EC_SUCCESS;
}
@@ -1461,7 +1507,7 @@ static int command_pd(int argc, char **argv)
const char * const state_names[] = {
"DISABLED", "SUSPENDED",
"SNK_DISCONNECTED", "SNK_DISCOVERY", "SNK_REQUESTED",
- "SNK_TRANSITION", "SNK_READY", "VDM_COMM",
+ "SNK_TRANSITION", "SNK_READY",
"SRC_DISCONNECTED", "SRC_DISCOVERY", "SRC_NEGOCIATE",
"SRC_ACCEPTED", "SRC_TRANSITION", "SRC_READY",
"HARD_RESET", "BIST",
diff --git a/include/usb_pd.h b/include/usb_pd.h
index 38f58f5888..60da419ba2 100644
--- a/include/usb_pd.h
+++ b/include/usb_pd.h
@@ -104,6 +104,7 @@ enum pd_errors {
/* VDO : Vendor Defined Message Object */
#define VDO(vid, custom) (((vid) << 16) | ((custom) & 0xFFFF))
+#define VDO_MAX_SIZE 7
#define VDO_ACK (0 << 6)
#define VDO_NAK (1 << 6)
@@ -275,7 +276,7 @@ void pd_set_input_current_limit(uint32_t max_ma);
*/
int pd_board_checks(void);
-/*
+/**
* Handle Vendor Defined Message with our vendor ID.
*
* @param port USB-C port number
@@ -286,13 +287,24 @@ int pd_board_checks(void);
*/
int pd_custom_vdm(int port, int cnt, uint32_t *payload, uint32_t **rpayload);
+/**
+ * Send Vendor Defined Message
+ *
+ * @param port USB-C port number
+ * @param vid Vendor ID
+ * @param cmd VDO command number
+ * @param data Pointer to payload to send
+ * @param data number of data objects in payload
+ */
+void pd_send_vdm(int port, uint32_t vid, int cmd, uint32_t *data, int count);
+
/* Power Data Objects for the source and the sink */
extern const uint32_t pd_src_pdo[];
extern const int pd_src_pdo_cnt;
extern const uint32_t pd_snk_pdo[];
extern const int pd_snk_pdo_cnt;
-/*
+/**
* Get PD source power data objects.
*
* @param src_pdo pointer to the data to return.
@@ -308,7 +320,7 @@ enum typec_mux {
TYPEC_MUX_DOCK,
};
-/*
+/**
* Configure superspeed muxes on type-C port.
*
* @param port port number.
@@ -317,7 +329,7 @@ enum typec_mux {
*/
void board_set_usb_mux(int port, enum typec_mux mux, int polarity);
-/*
+/**
* Query superspeed mux status on type-C port.
*
* @param port port number.
diff --git a/util/flash_pd.py b/util/flash_pd.py
index b93e2628cc..2ae64b730e 100755
--- a/util/flash_pd.py
+++ b/util/flash_pd.py
@@ -184,7 +184,7 @@ def flash_pd(options):
# reboot in RO
ec.flash_command('reboot')
# delay to give time to reboot
- time.sleep(0.5)
+ time.sleep(1.5)
# erase all RW partition
ec.flash_command('erase')
@@ -214,7 +214,7 @@ def flash_pd(options):
# reboot in RW
ec.flash_command('reboot')
# delay for reboot
- time.sleep(0.2)
+ time.sleep(1.5)
logging.info('Flashing DONE.')
logging.info('SHA-1: %s', sha_str)