PD: Make current USB PD Stack REV 3 compliant

Implement the following required features in the USB PD Rev. 3.0
specification.

Not_supported control message: Inform a port partner that a
particular message is not supported.
Battery capabilities extended message: Report battery design
capacity and last full charge capacity.
Battery status data message: Report battery state of charge
Collision avoidance: New scheme to avoid collisions caused when both
source and sink want to send messages.

Cable communication: Only the VCONN source can communicate with the
cable plug. This is NOT implemented because although the drivers have
the capability of communicating with a cable plug, the PD stack doesn't
currently need to talk to a cable plug. This is okay since the current
PD design doesn't source or sink more than 3 amps and all Type-C cables
are required to be 3 amp capable.

BUG=b:64411727
BRANCH=None
TEST=`make -j buildall`
Passed relevant PD Rev 2.0 compliance tests
Successful PD negotiation with PD Rev 2.0 and 3.0 chargers
Tested with low power none PD charger.
Modified a Kevin to operate as a PD 3.0 charger and sent
all required messages and verified the return messages.
Also tested collision avoidance by verifying that a sink only
transmits when the source indicates it's okay.
Used Twinkie to verify that PD was operating as v3.0.
Signed-off-by: Sam Hurst <shurst@chromium.org>

Change-Id: Ifd77e92ec4e9106236f9221393d2bfb97263d979
Reviewed-on: https://chromium-review.googlesource.com/603003
Commit-Ready: Sam Hurst <shurst@google.com>
Tested-by: Sam Hurst <shurst@google.com>
Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
This commit is contained in:
Sam Hurst 2017-08-05 13:24:40 -07:00 committed by chrome-bot
parent 5fd1540e62
commit c91dbb26d8
9 changed files with 750 additions and 57 deletions

View File

@ -722,6 +722,7 @@ int pd_svdm(int port, int cnt, uint32_t *payload, uint32_t **rpayload)
payload[0] |= VDO_CMDT(CMDT_RSP_BUSY);
rsize = 1;
}
payload[0] |= VDO_SVDM_VERS(pd_get_vdo_ver(port));
} else if (cmd_type == CMDT_RSP_ACK) {
#ifdef CONFIG_USB_PD_ALT_MODE_DFP
struct svdm_amode_data *modep;
@ -798,6 +799,7 @@ int pd_svdm(int port, int cnt, uint32_t *payload, uint32_t **rpayload)
}
payload[0] |= VDO_CMDT(CMDT_INIT);
payload[0] |= VDO_SVDM_VERS(pd_get_vdo_ver(port));
#ifdef CONFIG_USB_PD_ALT_MODE_DFP
} else if (cmd_type == CMDT_RSP_BUSY) {
switch (cmd) {

View File

@ -4,6 +4,7 @@
*/
#include "battery.h"
#include "battery_smart.h"
#include "board.h"
#include "charge_manager.h"
#include "charge_state.h"
@ -100,6 +101,34 @@ enum pd_dual_role_states drp_state = CONFIG_USB_PD_INITIAL_DRP_STATE;
static uint8_t pd_try_src_enable;
#endif
#ifdef CONFIG_USB_PD_REV30
/*
* The spec. revision is used to index into this array.
* Rev 0 (PD 1.0) - return PD_CTRL_REJECT
* Rev 1 (PD 2.0) - return PD_CTRL_REJECT
* Rev 2 (PD 3.0) - return PD_CTRL_NOT_SUPPORTED
*/
static const uint8_t refuse[] = {
PD_CTRL_REJECT, PD_CTRL_REJECT, PD_CTRL_NOT_SUPPORTED};
#define REFUSE(r) refuse[r]
#else
#define REFUSE(r) PD_CTRL_REJECT
#endif
#ifdef CONFIG_USB_PD_REV30
/*
* The spec. revision is used to index into this array.
* Rev 0 (VDO 1.0) - return VDM_VER10
* Rev 1 (VDO 1.0) - return VDM_VER10
* Rev 2 (VDO 2.0) - return VDM_VER20
*/
static const uint8_t vdo_ver[] = {
VDM_VER10, VDM_VER10, VDM_VER20};
#define VDO_VER(v) vdo_ver[v]
#else
#define VDO_VER(v) VDM_VER10
#endif
static struct pd_protocol {
/* current port power role (SOURCE or SINK) */
uint8_t power_role;
@ -158,6 +187,15 @@ static struct pd_protocol {
uint16_t dev_id;
uint32_t dev_rw_hash[PD_RW_HASH_SIZE/4];
enum ec_current_image current_image;
#ifdef CONFIG_USB_PD_REV30
/* PD Collision avoidance buffer */
uint16_t ca_buffered;
uint16_t ca_header;
uint32_t ca_buffer[PDO_MAX_OBJECTS];
enum tcpm_transmit_type ca_type;
/* protocol revision */
uint8_t rev;
#endif
} pd[CONFIG_USB_PD_PORT_COUNT];
#ifdef CONFIG_COMMON_RUNTIME
@ -215,6 +253,18 @@ static inline void set_state_timeout(int port,
pd[port].timeout_state = timeout_state;
}
#ifdef CONFIG_USB_PD_REV30
int pd_get_rev(int port)
{
return pd[port].rev;
}
int pd_get_vdo_ver(int port)
{
return vdo_ver[pd[port].rev];
}
#endif
/* Return flag for pd state is connected */
int pd_is_connected(int port)
{
@ -303,10 +353,27 @@ static inline void set_state(int port, enum pd_states next_state)
#else /* CONFIG_USB_PD_DUAL_ROLE */
if (next_state == PD_STATE_SRC_DISCONNECTED) {
#endif
/* If we are source, make sure VBUS is off */
if (pd[port].power_role == PD_ROLE_SOURCE)
/*
* If we are source, make sure VBUS is off and
* if PD REV3.0, restore RP.
*/
if (pd[port].power_role == PD_ROLE_SOURCE) {
/*
* Rp is restored by pd_power_supply_reset if
* CONFIG_USB_PD_MAX_SINGLE_SOURCE_CURRENT is defined.
*/
pd_power_supply_reset(port);
#if !defined(CONFIG_USB_PD_MAX_SINGLE_SOURCE_CURRENT) && \
defined(CONFIG_USB_PD_REV30)
/* Restore Rp */
tcpm_select_rp_value(port, CONFIG_USB_PD_PULLUP);
tcpm_set_cc(port, TYPEC_CC_RP);
#endif
}
#ifdef CONFIG_USB_PD_REV30
/* Adjust rev to highest level*/
pd[port].rev = PD_REV30;
#endif
pd[port].dev_id = 0;
pd[port].flags &= ~PD_FLAGS_RESET_ON_DISCONNECT_MASK;
#ifdef CONFIG_CHARGE_MANAGER
@ -348,6 +415,19 @@ static void inc_id(int port)
pd[port].msg_id = (pd[port].msg_id + 1) & PD_MESSAGE_ID_COUNT;
}
#ifdef CONFIG_USB_PD_REV30
static void sink_can_xmit(int port, int rp)
{
tcpm_select_rp_value(port, rp);
tcpm_set_cc(port, TYPEC_CC_RP);
}
static inline void pd_ca_reset(int port)
{
pd[port].ca_buffered = 0;
}
#endif
void pd_transmit_complete(int port, int status)
{
if (status == TCPC_TX_COMPLETE_SUCCESS)
@ -365,12 +445,76 @@ static int pd_transmit(int port, enum tcpm_transmit_type type,
/* If comms are disabled, do not transmit, return error */
if (!pd_comm_is_enabled(port))
return -1;
#ifdef CONFIG_USB_PD_REV30
/* Source-coordinated collision avoidance */
/*
* In order to avoid message collisions due to asynchronous Messaging
* sent from the Sink, the Source sets Rp to SinkTxOk to indicate to
* the Sink that it is ok to initiate an AMS. When the Source wishes
* to initiate an AMS it sets Rp to SinkTxNG. When the Sink detects
* that Rp is set to SinkTxOk it May initiate an AMS. When the Sink
* detects that Rp is set to SinkTxNG it Shall Not initiate an AMS
* and Shall only send Messages that are part of an AMS the Source has
* initiated. Note that this restriction applies to SOP* AMSs i.e.
* for both Port to Port and Port to Cable Plug communications.
*
* This starts after an Explicit Contract is in place
* PD R3 V1.1 Section 2.5.2.
*
* Note: a Sink can still send Hard Reset signaling at any time.
*/
if ((pd[port].rev == PD_REV30) &&
(pd[port].flags & PD_FLAGS_EXPLICIT_CONTRACT)) {
if (pd[port].power_role == PD_ROLE_SOURCE) {
/*
* Inform Sink that it can't transmit. If a sink
* transmition is in progress and a collsion occurs,
* a reset is generated. This should be rare because
* all extended messages are chunked. This effectively
* defaults to PD REV 2.0 collision avoidance.
*/
sink_can_xmit(port, SINK_TX_NG);
} else if (type != TCPC_TX_HARD_RESET) {
int cc1;
int cc2;
tcpm_get_cc(port, &cc1, &cc2);
if (cc1 == TYPEC_CC_VOLT_SNK_1_5 ||
cc2 == TYPEC_CC_VOLT_SNK_1_5) {
/* Sink can't transmit now. */
/* Check if message is already buffered. */
if (pd[port].ca_buffered)
return -1;
/* Buffer message and send later. */
pd[port].ca_type = type;
pd[port].ca_header = header;
memcpy(pd[port].ca_buffer,
data, sizeof(uint32_t) *
PD_HEADER_CNT(header));
pd[port].ca_buffered = 1;
return 1;
}
}
}
#endif
tcpm_transmit(port, type, header, data);
/* Wait until TX is complete */
evt = task_wait_event_mask(PD_EVENT_TX, PD_T_TCPC_TX_TIMEOUT);
#ifdef CONFIG_USB_PD_REV30
/*
* If the source just completed a transmit, tell
* the sink it can transmit if it wants to.
*/
if ((pd[port].rev == PD_REV30) &&
(pd[port].power_role == PD_ROLE_SOURCE) &&
(pd[port].flags & PD_FLAGS_EXPLICIT_CONTRACT)) {
sink_can_xmit(port, SINK_TX_OK);
}
#endif
if (evt & TASK_EVENT_TIMER)
return -1;
@ -378,6 +522,29 @@ static int pd_transmit(int port, enum tcpm_transmit_type type,
return pd[port].tx_status == TCPC_TX_COMPLETE_SUCCESS ? 1 : -1;
}
#ifdef CONFIG_USB_PD_REV30
static void pd_ca_send_pending(int port)
{
int cc1;
int cc2;
/* Check if a message has been buffered. */
if (!pd[port].ca_buffered)
return;
tcpm_get_cc(port, &cc1, &cc2);
if ((cc1 != TYPEC_CC_VOLT_SNK_1_5) &&
(cc2 != TYPEC_CC_VOLT_SNK_1_5))
if (pd_transmit(port, pd[port].ca_type,
pd[port].ca_header,
pd[port].ca_buffer) < 0)
return;
/* Message was sent, so free up the buffer. */
pd[port].ca_buffered = 0;
}
#endif
static void pd_update_roles(int port)
{
/* Notify TCPC of role update */
@ -388,7 +555,8 @@ static int send_control(int port, int type)
{
int bit_len;
uint16_t header = PD_HEADER(type, pd[port].power_role,
pd[port].data_role, pd[port].msg_id, 0);
pd[port].data_role, pd[port].msg_id, 0,
pd_get_rev(port), 0);
bit_len = pd_transmit(port, TCPC_TX_SOP, header, NULL);
if (debug_level >= 2)
@ -413,10 +581,12 @@ static int send_source_cap(int port)
if (src_pdo_cnt == 0)
/* No source capabilities defined, sink only */
header = PD_HEADER(PD_CTRL_REJECT, pd[port].power_role,
pd[port].data_role, pd[port].msg_id, 0);
pd[port].data_role, pd[port].msg_id, 0,
pd_get_rev(port), 0);
else
header = PD_HEADER(PD_DATA_SOURCE_CAP, pd[port].power_role,
pd[port].data_role, pd[port].msg_id, src_pdo_cnt);
pd[port].data_role, pd[port].msg_id, src_pdo_cnt,
pd_get_rev(port), 0);
bit_len = pd_transmit(port, TCPC_TX_SOP, header, src_pdo);
if (debug_level >= 2)
@ -425,12 +595,168 @@ static int send_source_cap(int port)
return bit_len;
}
#ifdef CONFIG_USB_PD_REV30
static int send_battery_cap(int port, uint32_t *payload)
{
int bit_len;
uint16_t msg[6] = {0, 0, 0, 0, 0, 0};
uint16_t header = PD_HEADER(PD_EXT_BATTERY_CAP,
pd[port].power_role,
pd[port].data_role,
pd[port].msg_id,
3, /* Number of Data Objects */
pd[port].rev,
1 /* This is an exteded message */
);
/* Set extended header */
msg[0] = PD_EXT_HEADER(0, /* Chunk Number */
0, /* Request Chunk */
9 /* Data Size in bytes */
);
/* Set VID */
msg[1] = USB_VID_GOOGLE;
/* Set PID */
msg[2] = CONFIG_USB_PID;
if (battery_is_present()) {
/*
* We only have one fixed battery,
* so make sure batt cap ref is 0.
*/
if (BATT_CAP_REF(payload[0]) != 0) {
/* Invalid battery reference */
msg[5] = 1;
} else {
uint32_t v;
uint32_t c;
/*
* The Battery Design Capacity field shall return the
* Batterys design capacity in tenths of Wh. If the
* Battery is Hot Swappable and is not present, the
* Battery Design Capacity field shall be set to 0. If
* the Battery is unable to report its Design Capacity,
* it shall return 0xFFFF
*/
msg[3] = 0xffff;
/*
* The Battery Last Full Charge Capacity field shall
* return the Batterys last full charge capacity in
* tenths of Wh. If the Battery is Hot Swappable and
* is not present, the Battery Last Full Charge Capacity
* field shall be set to 0. If the Battery is unable to
* report its Design Capacity, the Battery Last Full
* Charge Capacity field shall be set to 0xFFFF.
*/
msg[4] = 0xffff;
if (battery_design_voltage(&v) == 0) {
if (battery_design_capacity(&c) == 0) {
/*
* Wh = (c * v) / 1000000
* 10th of a Wh = Wh * 10
*/
msg[3] = DIV_ROUND_NEAREST((c * v),
100000);
}
if (battery_full_charge_capacity(&c) == 0) {
/*
* Wh = (c * v) / 1000000
* 10th of a Wh = Wh * 10
*/
msg[4] = DIV_ROUND_NEAREST((c * v),
100000);
}
}
}
}
bit_len = pd_transmit(port, TCPC_TX_SOP, header, (uint32_t *)msg);
if (debug_level >= 2)
CPRINTF("batCap>%d\n", bit_len);
return bit_len;
}
static int send_battery_status(int port, uint32_t *payload)
{
int bit_len;
uint32_t msg = 0;
uint16_t header = PD_HEADER(PD_DATA_BATTERY_STATUS,
pd[port].power_role,
pd[port].data_role,
pd[port].msg_id,
1, /* Number of Data Objects */
pd[port].rev,
0 /* This is NOT an extended message */
);
if (battery_is_present()) {
/*
* We only have one fixed battery,
* so make sure batt cap ref is 0.
*/
if (BATT_CAP_REF(payload[0]) != 0) {
/* Invalid battery reference */
msg |= BSDO_INVALID;
} else {
uint32_t v;
uint32_t c;
if (battery_design_voltage(&v) != 0 ||
battery_remaining_capacity(&c) != 0) {
msg |= BSDO_CAP(BSDO_CAP_UNKNOWN);
} else {
/*
* Wh = (c * v) / 1000000
* 10th of a Wh = Wh * 10
*/
msg |= BSDO_CAP(DIV_ROUND_NEAREST((c * v),
100000));
}
/* Battery is present */
msg |= BSDO_PRESENT;
/*
* For drivers that are not smart battery compliant,
* battery_status() returns EC_ERROR_UNIMPLEMENTED and
* the battery is assumed to be idle.
*/
if (battery_status(&c) != 0) {
msg |= BSDO_IDLE; /* assume idle */
} else {
if (c & STATUS_FULLY_CHARGED)
/* Fully charged */
msg |= BSDO_IDLE;
else if (c & STATUS_DISCHARGING)
/* Discharging */
msg |= BSDO_DISCHARGING;
/* else battery is charging.*/
}
}
} else {
msg = BSDO_CAP(BSDO_CAP_UNKNOWN);
}
bit_len = pd_transmit(port, TCPC_TX_SOP, header, &msg);
if (debug_level >= 2)
CPRINTF("batStat>%d\n", bit_len);
return bit_len;
}
#endif
#ifdef CONFIG_USB_PD_DUAL_ROLE
static void send_sink_cap(int port)
{
int bit_len;
uint16_t header = PD_HEADER(PD_DATA_SINK_CAP, pd[port].power_role,
pd[port].data_role, pd[port].msg_id, pd_snk_pdo_cnt);
pd[port].data_role, pd[port].msg_id, pd_snk_pdo_cnt,
pd_get_rev(port), 0);
bit_len = pd_transmit(port, TCPC_TX_SOP, header, pd_snk_pdo);
if (debug_level >= 2)
@ -441,7 +767,8 @@ static int send_request(int port, uint32_t rdo)
{
int bit_len;
uint16_t header = PD_HEADER(PD_DATA_REQUEST, pd[port].power_role,
pd[port].data_role, pd[port].msg_id, 1);
pd[port].data_role, pd[port].msg_id, 1,
pd_get_rev(port), 0);
bit_len = pd_transmit(port, TCPC_TX_SOP, header, &rdo);
if (debug_level >= 2)
@ -477,7 +804,8 @@ static int send_bist_cmd(int port)
uint32_t bdo = BDO(BDO_MODE_CARRIER2, 0);
int bit_len;
uint16_t header = PD_HEADER(PD_DATA_BIST, pd[port].power_role,
pd[port].data_role, pd[port].msg_id, 1);
pd[port].data_role, pd[port].msg_id, 1,
pd_get_rev(port), 0);
bit_len = pd_transmit(port, TCPC_TX_SOP, header, &bdo);
CPRINTF("BIST>%d\n", bit_len);
@ -541,6 +869,10 @@ void pd_execute_hard_reset(int port)
pd_dfp_exit_mode(port, 0, 0);
#endif
#ifdef CONFIG_USB_PD_REV30
pd[port].rev = PD_REV30;
pd_ca_reset(port);
#endif
/*
* Fake set last state to hard reset to make sure that the next
* state to run knows that we just did a hard reset.
@ -737,6 +1069,13 @@ static void handle_data_request(int port, uint16_t head,
PD_STATE_SNK_HARD_RESET_RECOVER)
#endif
|| (pd[port].task_state == PD_STATE_SNK_READY)) {
#ifdef CONFIG_USB_PD_REV30
/*
* Only adjust sink rev if source rev is higher.
*/
if (PD_HEADER_REV(head) < pd[port].rev)
pd[port].rev = PD_HEADER_REV(head);
#endif
/* Port partner is now known to be PD capable */
pd[port].flags |= PD_FLAGS_PREVIOUS_PD_CONN;
@ -751,7 +1090,14 @@ static void handle_data_request(int port, uint16_t head,
break;
#endif /* CONFIG_USB_PD_DUAL_ROLE */
case PD_DATA_REQUEST:
if ((pd[port].power_role == PD_ROLE_SOURCE) && (cnt == 1))
if ((pd[port].power_role == PD_ROLE_SOURCE) && (cnt == 1)) {
#ifdef CONFIG_USB_PD_REV30
/*
* Adjust the rev level to what the sink supports. If
* they're equal, no harm done.
*/
pd[port].rev = PD_HEADER_REV(head);
#endif
if (!pd_check_requested_voltage(payload[0], port)) {
if (send_control(port, PD_CTRL_ACCEPT) < 0)
/*
@ -763,6 +1109,15 @@ static void handle_data_request(int port, uint16_t head,
/* explicit contract is now in place */
pd[port].flags |= PD_FLAGS_EXPLICIT_CONTRACT;
#ifdef CONFIG_USB_PD_REV30
/*
* Start Source-coordinated collision
* avoidance
*/
if (pd[port].rev == PD_REV30 &&
pd[port].power_role == PD_ROLE_SOURCE)
sink_can_xmit(port, SINK_TX_OK);
#endif
#ifdef CONFIG_USB_PD_DUAL_ROLE
pd_set_saved_active(port, 1);
#endif
@ -770,6 +1125,7 @@ static void handle_data_request(int port, uint16_t head,
set_state(port, PD_STATE_SRC_ACCEPTED);
return;
}
}
/* the message was incorrect or cannot be satisfied */
send_control(port, PD_CTRL_REJECT);
/* keep last contract in place (whether implicit or explicit) */
@ -799,6 +1155,10 @@ static void handle_data_request(int port, uint16_t head,
if (pd[port].task_state == PD_STATE_SRC_GET_SINK_CAP)
set_state(port, PD_STATE_SRC_READY);
break;
#ifdef CONFIG_USB_PD_REV30
case PD_DATA_BATTERY_STATUS:
break;
#endif
case PD_DATA_VENDOR_DEF:
handle_vdm_request(port, cnt, payload);
break;
@ -903,7 +1263,7 @@ static void handle_ctrl_request(int port, uint16_t head,
#ifdef CONFIG_USB_PD_DUAL_ROLE
send_sink_cap(port);
#else
send_control(port, PD_CTRL_REJECT);
send_control(port, REFUSE(pd[port].rev));
#endif
break;
#ifdef CONFIG_USB_PD_DUAL_ROLE
@ -1075,10 +1435,10 @@ static void handle_ctrl_request(int port, uint16_t head,
PD_STATE_SNK_SWAP_SNK_DISABLE,
PD_STATE_SRC_SWAP_SNK_DISABLE));
} else {
send_control(port, PD_CTRL_REJECT);
send_control(port, REFUSE(pd[port].rev));
}
#else
send_control(port, PD_CTRL_REJECT);
send_control(port, REFUSE(pd[port].rev));
#endif
break;
case PD_CTRL_DR_SWAP:
@ -1092,7 +1452,8 @@ static void handle_ctrl_request(int port, uint16_t head,
if (send_control(port, PD_CTRL_ACCEPT) >= 0)
pd_dr_swap(port);
} else {
send_control(port, PD_CTRL_REJECT);
send_control(port, REFUSE(pd[port].rev));
}
break;
case PD_CTRL_VCONN_SWAP:
@ -1104,18 +1465,41 @@ static void handle_ctrl_request(int port, uint16_t head,
set_state(port,
PD_STATE_VCONN_SWAP_INIT);
} else {
send_control(port, PD_CTRL_REJECT);
send_control(port, REFUSE(pd[port].rev));
}
}
#else
send_control(port, PD_CTRL_REJECT);
send_control(port, REFUSE(pd[port].rev));
#endif
break;
default:
#ifdef CONFIG_USB_PD_REV30
send_control(port, PD_CTRL_NOT_SUPPORTED);
#endif
CPRINTF("Unhandled ctrl message type %d\n", type);
}
}
#ifdef CONFIG_USB_PD_REV30
static void handle_ext_request(int port, uint16_t head, uint32_t *payload)
{
int type = PD_HEADER_TYPE(head);
switch (type) {
case PD_EXT_GET_BATTERY_CAP:
send_battery_cap(port, payload);
break;
case PD_EXT_GET_BATTERY_STATUS:
send_battery_status(port, payload);
break;
case PD_EXT_BATTERY_CAP:
break;
default:
send_control(port, PD_CTRL_NOT_SUPPORTED);
}
}
#endif
static void handle_request(int port, uint16_t head,
uint32_t *payload)
{
@ -1138,6 +1522,13 @@ static void handle_request(int port, uint16_t head,
if (!pd_is_connected(port))
set_state(port, PD_STATE_HARD_RESET_SEND);
#ifdef CONFIG_USB_PD_REV30
/* Check if this is an extended chunked data message. */
if (pd[port].rev == PD_REV30 && PD_HEADER_EXT(head)) {
handle_ext_request(port, head, payload);
return;
}
#endif
if (cnt)
handle_data_request(port, head, payload);
else
@ -1155,6 +1546,9 @@ void pd_send_vdm(int port, uint32_t vid, int cmd, const uint32_t *data,
/* set VDM header with VID & CMD */
pd[port].vdo_data[0] = VDO(vid, ((vid & USB_SID_PD) == USB_SID_PD) ?
1 : (PD_VDO_CMD(cmd) <= CMD_ATTENTION), cmd);
#ifdef CONFIG_USB_PD_REV30
pd[port].vdo_data[0] |= VDO_SVDM_VERS(vdo_ver[pd[port].rev]);
#endif
queue_vdm(port, pd[port].vdo_data, data, count);
task_wake(PD_PORT_TO_TASK_ID(port));
@ -1223,7 +1617,8 @@ static void pd_vdm_send_state_machine(int port)
/* Prepare and send VDM */
header = PD_HEADER(PD_DATA_VENDOR_DEF, pd[port].power_role,
pd[port].data_role, pd[port].msg_id,
(int)pd[port].vdo_count);
(int)pd[port].vdo_count,
pd_get_rev(port), 0);
res = pd_transmit(port, TCPC_TX_SOP, header,
pd[port].vdo_data);
if (res < 0) {
@ -1664,6 +2059,12 @@ void pd_task(void *u)
}
#endif
#ifdef CONFIG_USB_PD_REV30
/* Set Revision to highest */
pd[port].rev = PD_REV30;
pd_ca_reset(port);
#endif
#ifdef CONFIG_USB_PD_DUAL_ROLE
/*
* If VBUS is high, then initialize flag for VBUS has always been
@ -1707,6 +2108,10 @@ void pd_task(void *u)
#endif
while (1) {
#ifdef CONFIG_USB_PD_REV30
/* send any pending messages */
pd_ca_send_pending(port);
#endif
/* process VDM messages last */
pd_vdm_send_state_machine(port);
@ -1796,7 +2201,6 @@ void pd_task(void *u)
case PD_STATE_SRC_DISCONNECTED:
timeout = 10*MSEC;
tcpm_get_cc(port, &cc1, &cc2);
#ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE
/*
* Attempt TCPC auto DRP toggle if it is

View File

@ -439,7 +439,7 @@ static int send_validate_message(int port, uint16_t header,
static void send_goodcrc(int port, int id)
{
uint16_t header = PD_HEADER(PD_CTRL_GOOD_CRC, pd[port].power_role,
pd[port].data_role, id, 0);
pd[port].data_role, id, 0, 0, 0);
int bit_len = prepare_message(port, header, 0, NULL);
if (pd_start_tx(port, pd[port].polarity, bit_len) < 0)

View File

@ -2538,6 +2538,9 @@
/* Define if this board, operating as a sink, can give power back to a source */
#undef CONFIG_USB_PD_GIVE_BACK
/* Enable USB PD Rev3.0 features */
#undef CONFIG_USB_PD_REV30
/* Major and Minor ChromeOS specific PD device Hardware IDs. */
#undef CONFIG_USB_PD_HW_DEV_ID_BOARD_MAJOR
#undef CONFIG_USB_PD_HW_DEV_ID_BOARD_MINOR

View File

@ -137,6 +137,9 @@ enum pd_rx_errors {
#define SVID_DISCOVERY_MAX 16
/* Timers */
#define PD_T_SINK_TX (18*MSEC) /* between 16ms and 20 */
#define PD_T_CHUNK_SENDER_RSP (24*MSEC) /* between 24ms and 30ms */
#define PD_T_CHUNK_SENDER_REQ (24*MSEC) /* between 24ms and 30ms */
#define PD_T_SEND_SOURCE_CAP (100*MSEC) /* between 100ms and 200ms */
#define PD_T_SINK_WAIT_CAP (600*MSEC) /* between 310ms and 620ms */
#define PD_T_SINK_TRANSITION (35*MSEC) /* between 20ms and 35ms */
@ -267,23 +270,27 @@ struct pd_policy {
* VDM object is minimum of VDM header + 6 additional data objects.
*/
#define VDO_MAX_SIZE 7
#define VDM_VER10 0
#define VDM_VER20 1
/*
* VDM header
* ----------
* <31:16> :: SVID
* <15> :: VDM type ( 1b == structured, 0b == unstructured )
* <14:13> :: Structured VDM version (can only be 00 == 1.0 currently)
* <14:13> :: Structured VDM version (00b == Rev 2.0, 01b == Rev 3.0 )
* <12:11> :: reserved
* <10:8> :: object position (1-7 valid ... used for enter/exit mode only)
* <7:6> :: command type (SVDM only?)
* <5> :: reserved (SVDM), command type (UVDM)
* <4:0> :: command
*/
#define VDO_MAX_SIZE 7
#define VDO(vid, type, custom) \
(((vid) << 16) | \
((type) << 15) | \
((custom) & 0x7FFF))
#define VDO(vid, type, custom) \
(((vid) << 16) | \
((type) << 15) | \
((custom) & 0x7FFF))
#define VDO_SVDM_TYPE (1 << 15)
#define VDO_SVDM_VERS(x) (x << 13)
@ -793,6 +800,46 @@ enum pd_ctrl_msg_type {
PD_CTRL_WAIT = 12,
PD_CTRL_SOFT_RESET = 13,
/* 14-15 Reserved */
/* Used for REV 3.0 */
PD_CTRL_NOT_SUPPORTED = 16,
PD_CTRL_GET_SOURCE_CAP_EXT = 17,
PD_CTRL_GET_STATUS = 18,
PD_CTRL_FR_SWAP = 19,
PD_CTRL_GET_PPS_STATUS = 20,
PD_CTRL_GET_COUNTRY_CODES = 21,
/* 22-31 Reserved */
};
/* Battery Status Data Object fields for REV 3.0 */
#define BSDO_CAP_UNKNOWN 0xffff
#define BSDO_CAP(n) (((n) & 0xffff) << 16)
#define BSDO_INVALID (1 << 8)
#define BSDO_PRESENT (1 << 9)
#define BSDO_DISCHARGING (1 << 10)
#define BSDO_IDLE (1 << 11)
/* Get Battery Cap Message fields for REV 3.0 */
#define BATT_CAP_REF(n) (((n) >> 16) & 0xff)
/* Extended message type for REV 3.0 */
enum pd_ext_msg_type {
/* 0 Reserved */
PD_EXT_SOURCE_CAP = 1,
PD_EXT_STATUS = 2,
PD_EXT_GET_BATTERY_CAP = 3,
PD_EXT_GET_BATTERY_STATUS = 4,
PD_EXT_BATTERY_CAP = 5,
PD_EXT_GET_MANUFACTURER_INFO = 6,
PD_EXT_MANUFACTURER_INFO = 7,
PD_EXT_SECURITY_REQUEST = 8,
PD_EXT_SECURITY_RESPONSE = 9,
PD_EXT_FIRMWARE_UPDATE_REQUEST = 10,
PD_EXT_FIRMWARE_UPDATE_RESPONSE = 11,
PD_EXT_PPS_STATUS = 12,
PD_EXT_COUNTRY_INFO = 13,
PD_EXT_COUNTRY_CODES = 14,
/* 15-31 Reserved */
};
/* Data message type */
@ -802,13 +849,18 @@ enum pd_data_msg_type {
PD_DATA_REQUEST = 2,
PD_DATA_BIST = 3,
PD_DATA_SINK_CAP = 4,
/* 5-14 Reserved */
/* 5-14 Reserved for REV 2.0 */
PD_DATA_BATTERY_STATUS = 5,
PD_DATA_ALERT = 6,
PD_DATA_GET_COUNTRY_INFO = 7,
/* 8-14 Reserved for REV 3.0 */
PD_DATA_VENDOR_DEF = 15,
};
/* Protocol revision */
#define PD_REV10 0
#define PD_REV20 1
#define PD_REV30 2
/* Power role */
#define PD_ROLE_SINK 0
@ -820,6 +872,14 @@ enum pd_data_msg_type {
#define PD_ROLE_VCONN_OFF 0
#define PD_ROLE_VCONN_ON 1
/* chunk is a request or response in REV 3.0 */
#define CHUNK_RESPONSE 0
#define CHUNK_REQUEST 1
/* collision avoidance Rp values in REV 3.0 */
#define SINK_TX_OK TYPEC_RP_3A0
#define SINK_TX_NG TYPEC_RP_1A5
/* Port role at startup */
#ifndef PD_ROLE_DEFAULT
#ifdef CONFIG_USB_PD_DUAL_ROLE
@ -838,15 +898,30 @@ enum pd_data_msg_type {
#define PD_DEFAULT_STATE(port) PD_STATE_SRC_DISCONNECTED
#endif
/* build message header */
#define PD_HEADER(type, prole, drole, id, cnt) \
((type) | (PD_REV20 << 6) | \
((drole) << 5) | ((prole) << 8) | \
((id) << 9) | ((cnt) << 12))
/* build extended message header */
/* All extended messages are chunked, so set bit 15 */
#define PD_EXT_HEADER(cnum, rchk, dsize) \
((1 << 15) | ((cnum) << 11) | \
((rchk) << 10) | (dsize))
/* build message header */
#define PD_HEADER(type, prole, drole, id, cnt, rev, ext) \
((type) | ((rev) << 6) | \
((drole) << 5) | ((prole) << 8) | \
((id) << 9) | ((cnt) << 12) | ((ext) << 15))
/* Used for processing pd header */
#define PD_HEADER_EXT(header) (((header) >> 15) & 1)
#define PD_HEADER_CNT(header) (((header) >> 12) & 7)
#define PD_HEADER_TYPE(header) ((header) & 0xF)
#define PD_HEADER_ID(header) (((header) >> 9) & 7)
#define PD_HEADER_REV(header) (((header) >> 6) & 3)
/* Used for processing pd extended header */
#define PD_EXT_HEADER_CHUNKED(header) (((header) >> 15) & 1)
#define PD_EXT_HEADER_CHUNK_NUM(header) (((header) >> 11) & 0xf)
#define PD_EXT_HEADER_REQ_CHUNK(header) (((header) >> 10) & 1)
#define PD_EXT_HEADER_DATA_SIZE(header) ((header) & 0x1ff)
/* K-codes for special symbols */
#define PD_SYNC1 0x18
@ -883,6 +958,26 @@ enum pd_request_type {
PD_REQUEST_MAX,
};
#ifdef CONFIG_USB_PD_REV30
/**
* Get current PD Revision
*
* @param port USB-C port number
* @return 0 for PD_REV1.0, 1 for PD_REV2.0, 2 for PD_REV3.0
*/
int pd_get_rev(int port);
/**
* Get current PD VDO Version
*
* @param port USB-C port number
* @return 0 for PD_REV1.0, 1 for PD_REV2.0
*/
int pd_get_vdo_ver(int port);
#else
#define pd_get_rev(n) PD_REV20
#define pd_get_vdo_ver(n) VDM_VER10
#endif
/**
* Decide which PDO to choose from the source capabilities.
*

View File

@ -76,6 +76,7 @@ test-list-host += thermal
test-list-host += timer_dos
test-list-host += usb_pd
test-list-host += usb_pd_giveback
test-list-host += usb_pd_rev30
test-list-host += utils
test-list-host += utils_str
test-list-host += vboot
@ -130,6 +131,7 @@ timer_calib-y=timer_calib.o
timer_dos-y=timer_dos.o
usb_pd-y=usb_pd.o
usb_pd_giveback-y=usb_pd.o
usb_pd_rev30-y=usb_pd.o
utils-y=utils.o
utils_str-y=utils_str.o
vboot-y=vboot.o

View File

@ -167,7 +167,8 @@ int ncp15wb_calculate_temp(uint16_t adc);
#define CONFIG_ALS_LIGHTBAR_DIMMING 0
#endif
#if defined(TEST_USB_PD) || defined(TEST_USB_PD_GIVEBACK)
#if defined(TEST_USB_PD) || defined(TEST_USB_PD_GIVEBACK) || \
defined(TEST_USB_PD_REV30)
#define CONFIG_USB_POWER_DELIVERY
#define CONFIG_USB_PD_CUSTOM_VDM
#define CONFIG_USB_PD_DUAL_ROLE
@ -176,10 +177,14 @@ int ncp15wb_calculate_temp(uint16_t adc);
#define CONFIG_USB_PD_TCPM_STUB
#define CONFIG_SHA256
#define CONFIG_SW_CRC
#ifdef TEST_USB_PD_REV30
#define CONFIG_USB_PD_REV30
#define CONFIG_USB_PID 0x5000
#endif
#ifdef TEST_USB_PD_GIVEBACK
#define CONFIG_USB_PD_GIVE_BACK
#endif
#endif /* TEST_USB_PD || TEST_USB_PD_GIVEBACK */
#endif /* TEST_USB_PD || TEST_USB_PD_GIVEBACK || TEST_USB_PD_REV30 */
#if defined(TEST_CHARGE_MANAGER) || defined(TEST_CHARGE_MANAGER_DRP_CHARGING)
#define CONFIG_CHARGE_MANAGER

View File

@ -4,7 +4,7 @@
*
* Test USB PD module.
*/
#include "battery.h"
#include "common.h"
#include "crc.h"
#include "task.h"
@ -17,6 +17,11 @@
#define PORT0 0
#define PORT1 1
#define BATTERY_DESIGN_VOLTAGE 7600
#define BATTERY_DESIGN_CAPACITY 5131
#define BATTERY_FULL_CHARGE_CAPACITY 5131
#define BATTERY_REMAINING_CAPACITY 2566
struct pd_port_t {
int host_mode;
int has_vbus;
@ -25,11 +30,60 @@ struct pd_port_t {
int polarity;
int partner_role; /* -1 for none */
int partner_polarity;
int rev;
} pd_port[CONFIG_USB_PD_PORT_COUNT];
static int give_back_called;
/* Mock functions */
#ifdef CONFIG_USB_PD_REV30
uint16_t pd_get_identity_vid(int port)
{
return 0;
}
uint16_t pd_get_identity_pid(int port)
{
return 0;
}
enum battery_present battery_is_present(void)
{
return BP_YES;
}
int battery_status(int *status)
{
*status = 1;
return 0;
}
int battery_remaining_capacity(int *capacity)
{
*capacity = BATTERY_REMAINING_CAPACITY;
return 0;
}
int battery_full_charge_capacity(int *capacity)
{
*capacity = BATTERY_FULL_CHARGE_CAPACITY;
return 0;
}
int battery_design_capacity(int *capacity)
{
*capacity = BATTERY_DESIGN_CAPACITY;
return 0;
}
int battery_design_voltage(int *voltage)
{
*voltage = BATTERY_DESIGN_VOLTAGE;
return 0;
}
#endif
int pd_adc_read(int port, int cc)
{
@ -97,6 +151,11 @@ static void init_ports(void)
pd_port[i].host_mode = 0;
pd_port[i].partner_role = -1;
pd_port[i].has_vbus = 0;
#ifdef CONFIG_USB_PD_REV30
pd_port[i].rev = PD_REV30;
#else
pd_port[i].rev = PD_REV20;
#endif
}
}
@ -127,7 +186,7 @@ static void simulate_wait(int port)
{
uint16_t header = PD_HEADER(PD_CTRL_WAIT, PD_ROLE_SOURCE,
PD_ROLE_DFP, pd_port[port].msg_rx_id,
0);
0, pd_port[port].rev, 0);
simulate_rx_msg(port, header, 0, NULL);
}
@ -136,7 +195,7 @@ static void simulate_accept(int port)
{
uint16_t header = PD_HEADER(PD_CTRL_ACCEPT, PD_ROLE_SOURCE,
PD_ROLE_DFP, pd_port[port].msg_rx_id,
0);
0, pd_port[port].rev, 0);
simulate_rx_msg(port, header, 0, NULL);
}
@ -145,35 +204,71 @@ static void simulate_reject(int port)
{
uint16_t header = PD_HEADER(PD_CTRL_REJECT, PD_ROLE_SOURCE,
PD_ROLE_DFP, pd_port[port].msg_rx_id,
0);
0, pd_port[port].rev, 0);
simulate_rx_msg(port, header, 0, NULL);
}
#ifdef CONFIG_USB_PD_REV30
static void simulate_get_bat_cap(int port)
{
uint16_t msg[2];
uint16_t header = PD_HEADER(PD_EXT_GET_BATTERY_CAP, PD_ROLE_SOURCE,
PD_ROLE_DFP, pd_port[port].msg_rx_id,
1, pd_port[port].rev, 1);
/* set extended header */
msg[0] = PD_EXT_HEADER(0, 0, 1);
/* set battery status ref */
msg[1] = 0;
simulate_rx_msg(port, header, 1, (const uint32_t *)msg);
}
static void simulate_get_bat_status(int port)
{
uint16_t msg[2];
uint16_t header = PD_HEADER(PD_EXT_GET_BATTERY_STATUS, PD_ROLE_SOURCE,
PD_ROLE_DFP, pd_port[port].msg_rx_id,
1, pd_port[port].rev, 1);
/* set extended header */
msg[0] = PD_EXT_HEADER(0, 0, 1);
/* set battery status ref */
msg[1] = 0;
simulate_rx_msg(port, header, 1, (const uint32_t *)msg);
}
#endif
static void simulate_source_cap(int port, uint32_t cnt)
{
uint32_t src_pdo_cnt = (cnt == 0) ? 1 : pd_src_pdo_cnt;
uint16_t header = PD_HEADER(PD_DATA_SOURCE_CAP, PD_ROLE_SOURCE,
PD_ROLE_DFP, pd_port[port].msg_rx_id,
src_pdo_cnt);
src_pdo_cnt, pd_port[port].rev, 0);
simulate_rx_msg(port, header, src_pdo_cnt, pd_src_pdo);
}
static void simulate_goodcrc(int port, int role, int id)
{
simulate_rx_msg(port, PD_HEADER(PD_CTRL_GOOD_CRC, role, role, id, 0),
0, NULL);
simulate_rx_msg(port, PD_HEADER(PD_CTRL_GOOD_CRC, role, role, id, 0,
pd_port[port].rev, 0), 0, NULL);
}
static int verify_goodcrc(int port, int role, int id)
{
return pd_test_tx_msg_verify_sop(port) &&
pd_test_tx_msg_verify_short(port, PD_HEADER(PD_CTRL_GOOD_CRC,
role, role, id, 0)) &&
pd_test_tx_msg_verify_crc(port) &&
pd_test_tx_msg_verify_eop(port);
pd_test_tx_msg_verify_short(port, PD_HEADER(PD_CTRL_GOOD_CRC,
role, role, id, 0, 0, 0)) &&
pd_test_tx_msg_verify_crc(port) &&
pd_test_tx_msg_verify_eop(port);
}
static void plug_in_source(int port, int polarity)
@ -210,7 +305,7 @@ static void simulate_ps_rdy(int port)
{
uint16_t header = PD_HEADER(PD_CTRL_PS_RDY, PD_ROLE_SOURCE,
PD_ROLE_DFP, pd_port[port].msg_rx_id,
0);
0, pd_port[port].rev, 0);
simulate_rx_msg(port, header, 0, NULL);
}
@ -218,13 +313,34 @@ static void simulate_ps_rdy(int port)
static void simulate_goto_min(int port)
{
uint16_t header = PD_HEADER(PD_CTRL_GOTO_MIN, PD_ROLE_SOURCE,
PD_ROLE_DFP, pd_port[port].msg_rx_id, 0);
PD_ROLE_DFP, pd_port[port].msg_rx_id, 0, pd_port[port].rev, 0);
simulate_rx_msg(port, header, 0, NULL);
}
static int test_request_with_wait_and_contract(void)
{
#ifdef CONFIG_USB_PD_REV30
uint32_t expected_status_bsdo =
BSDO_CAP(DIV_ROUND_NEAREST(BATTERY_REMAINING_CAPACITY *
BATTERY_DESIGN_VOLTAGE, 100000)) |
BSDO_PRESENT;
uint16_t expected_cap_hdr = PD_EXT_HEADER(0, 0, 9);
uint16_t expected_cap_vid = USB_VID_GOOGLE;
#ifdef CONFIG_USB_PID
uint16_t expected_cap_pid = CONFIG_USB_PID;
#else
uint16_t expected_cap_pid = 0;
#endif
uint16_t expected_cap_des =
DIV_ROUND_NEAREST(BATTERY_DESIGN_CAPACITY *
BATTERY_DESIGN_VOLTAGE, 100000);
uint16_t expected_cap_ful =
DIV_ROUND_NEAREST(BATTERY_FULL_CHARGE_CAPACITY *
BATTERY_DESIGN_VOLTAGE, 100000);
uint16_t expected_cap_type = 0;
#endif
#ifdef CONFIG_USB_PD_GIVE_BACK
uint32_t expected_rdo =
RDO_FIXED(2, 3000, PD_MIN_CURRENT_MA, RDO_GIVE_BACK);
@ -253,7 +369,7 @@ static int test_request_with_wait_and_contract(void)
TEST_ASSERT(pd_test_tx_msg_verify_sop(port));
TEST_ASSERT(pd_test_tx_msg_verify_short(port,
PD_HEADER(PD_DATA_REQUEST, PD_ROLE_SINK, PD_ROLE_UFP,
pd_port[port].msg_tx_id, 1)));
pd_port[port].msg_tx_id, 1, pd_port[port].rev, 0)));
TEST_ASSERT(pd_test_tx_msg_verify_word(port, expected_rdo));
TEST_ASSERT(pd_test_tx_msg_verify_crc(port));
TEST_ASSERT(pd_test_tx_msg_verify_eop(port));
@ -294,7 +410,7 @@ static int test_request_with_wait_and_contract(void)
TEST_ASSERT(pd_test_tx_msg_verify_sop(port));
TEST_ASSERT(pd_test_tx_msg_verify_short(port,
PD_HEADER(PD_DATA_REQUEST, PD_ROLE_SINK, PD_ROLE_UFP,
pd_port[port].msg_tx_id, 1)));
pd_port[port].msg_tx_id, 1, pd_port[port].rev, 0)));
TEST_ASSERT(pd_test_tx_msg_verify_word(port, expected_rdo));
TEST_ASSERT(pd_test_tx_msg_verify_crc(port));
TEST_ASSERT(pd_test_tx_msg_verify_eop(port));
@ -326,7 +442,9 @@ static int test_request_with_wait_and_contract(void)
TEST_ASSERT(pd_test_tx_msg_verify_sop(port));
TEST_ASSERT(pd_test_tx_msg_verify_short(port,
PD_HEADER(PD_DATA_REQUEST, PD_ROLE_SINK, PD_ROLE_UFP,
pd_port[port].msg_tx_id, 1)));
pd_port[port].msg_tx_id, 1,
pd_port[port].rev, 0
)));
TEST_ASSERT(pd_test_tx_msg_verify_word(port, expected_rdo));
TEST_ASSERT(pd_test_tx_msg_verify_crc(port));
TEST_ASSERT(pd_test_tx_msg_verify_eop(port));
@ -358,6 +476,69 @@ static int test_request_with_wait_and_contract(void)
task_wait_event(30 * MSEC);
inc_rx_id(port);
/*
* Test Extended Get_Battery_Cap and Get_Battery_Status messages.
*/
#ifdef CONFIG_USB_PD_REV30
/* We're in SNK_READY. Send get battery cap. */
simulate_get_bat_cap(port);
task_wait_event(30 * MSEC);
TEST_ASSERT(verify_goodcrc(0, PD_ROLE_SINK, pd_port[port].msg_rx_id));
task_wake(PD_PORT_TO_TASK_ID(port));
task_wait_event(30 * MSEC);
inc_rx_id(port);
/* Process the request */
TEST_ASSERT(pd_test_tx_msg_verify_sop(port));
TEST_ASSERT(pd_test_tx_msg_verify_short(port,
PD_HEADER(PD_EXT_BATTERY_CAP, PD_ROLE_SINK, PD_ROLE_UFP,
pd_port[port].msg_tx_id, 3, pd_port[port].rev, 1)));
TEST_ASSERT(pd_test_tx_msg_verify_short(port, expected_cap_hdr));
TEST_ASSERT(pd_test_tx_msg_verify_short(port, expected_cap_vid));
TEST_ASSERT(pd_test_tx_msg_verify_short(port, expected_cap_pid));
TEST_ASSERT(pd_test_tx_msg_verify_short(port, expected_cap_des));
TEST_ASSERT(pd_test_tx_msg_verify_short(port, expected_cap_ful));
TEST_ASSERT(pd_test_tx_msg_verify_short(port, expected_cap_type));
TEST_ASSERT(pd_test_tx_msg_verify_crc(port));
TEST_ASSERT(pd_test_tx_msg_verify_eop(port));
task_wake(PD_PORT_TO_TASK_ID(port));
task_wait_event(30 * MSEC);
/* Request was good. Send GoodCRC */
simulate_goodcrc(port, PD_ROLE_SOURCE, pd_port[port].msg_tx_id);
task_wake(PD_PORT_TO_TASK_ID(port));
task_wait_event(30 * MSEC);
inc_tx_id(port);
/* Send get battery status. */
simulate_get_bat_status(port);
task_wait_event(30 * MSEC);
TEST_ASSERT(verify_goodcrc(0, PD_ROLE_SINK, pd_port[port].msg_rx_id));
task_wake(PD_PORT_TO_TASK_ID(port));
task_wait_event(30 * MSEC);
inc_rx_id(port);
/* Process the request */
TEST_ASSERT(pd_test_tx_msg_verify_sop(port));
TEST_ASSERT(pd_test_tx_msg_verify_short(port,
PD_HEADER(PD_DATA_BATTERY_STATUS, PD_ROLE_SINK, PD_ROLE_UFP,
pd_port[port].msg_tx_id, 1, pd_port[port].rev, 0)));
TEST_ASSERT(pd_test_tx_msg_verify_word(port, expected_status_bsdo));
TEST_ASSERT(pd_test_tx_msg_verify_crc(port));
TEST_ASSERT(pd_test_tx_msg_verify_eop(port));
task_wake(PD_PORT_TO_TASK_ID(port));
task_wait_event(30 * MSEC);
/* Request was good. Send GoodCRC */
simulate_goodcrc(port, PD_ROLE_SOURCE, pd_port[port].msg_tx_id);
task_wake(PD_PORT_TO_TASK_ID(port));
task_wait_event(30 * MSEC);
inc_tx_id(port);
#endif
/* We're in SNK_READY. Send goto_min */
simulate_goto_min(port);
task_wait_event(30 * MSEC);
@ -372,7 +553,6 @@ static int test_request_with_wait_and_contract(void)
#else
TEST_ASSERT(!give_back_called);
#endif
/* We're done */
unplug(port);
@ -409,7 +589,7 @@ static int test_request_with_wait(void)
TEST_ASSERT(pd_test_tx_msg_verify_sop(port));
TEST_ASSERT(pd_test_tx_msg_verify_short(port,
PD_HEADER(PD_DATA_REQUEST, PD_ROLE_SINK, PD_ROLE_UFP,
pd_port[port].msg_tx_id, 1)));
pd_port[port].msg_tx_id, 1, pd_port[port].rev, 0)));
TEST_ASSERT(pd_test_tx_msg_verify_word(port, expected_rdo));
TEST_ASSERT(pd_test_tx_msg_verify_crc(port));
TEST_ASSERT(pd_test_tx_msg_verify_eop(port));
@ -448,7 +628,7 @@ static int test_request_with_wait(void)
TEST_ASSERT(pd_test_tx_msg_verify_sop(port));
TEST_ASSERT(pd_test_tx_msg_verify_short(port,
PD_HEADER(PD_DATA_REQUEST, PD_ROLE_SINK, PD_ROLE_UFP,
pd_port[port].msg_tx_id, 1)));
pd_port[port].msg_tx_id, 1, pd_port[port].rev, 0)));
TEST_ASSERT(pd_test_tx_msg_verify_word(port, expected_rdo));
TEST_ASSERT(pd_test_tx_msg_verify_crc(port));
TEST_ASSERT(pd_test_tx_msg_verify_eop(port));
@ -497,7 +677,7 @@ static int test_request_with_reject(void)
TEST_ASSERT(pd_test_tx_msg_verify_sop(port));
TEST_ASSERT(pd_test_tx_msg_verify_short(port,
PD_HEADER(PD_DATA_REQUEST, PD_ROLE_SINK, PD_ROLE_UFP,
pd_port[port].msg_tx_id, 1)));
pd_port[port].msg_tx_id, 1, pd_port[port].rev, 0)));
TEST_ASSERT(pd_test_tx_msg_verify_word(port, expected_rdo));
TEST_ASSERT(pd_test_tx_msg_verify_crc(port));
TEST_ASSERT(pd_test_tx_msg_verify_eop(port));
@ -535,7 +715,7 @@ static int test_request_with_reject(void)
TEST_ASSERT(pd_test_tx_msg_verify_sop(port));
TEST_ASSERT(pd_test_tx_msg_verify_short(port,
PD_HEADER(PD_DATA_REQUEST, PD_ROLE_SINK, PD_ROLE_UFP,
pd_port[port].msg_tx_id, 1)));
pd_port[port].msg_tx_id, 1, pd_port[port].rev, 0)));
TEST_ASSERT(pd_test_tx_msg_verify_word(port, expected_rdo));
TEST_ASSERT(pd_test_tx_msg_verify_crc(port));
TEST_ASSERT(pd_test_tx_msg_verify_eop(port));
@ -575,7 +755,7 @@ static int test_request(void)
TEST_ASSERT(pd_test_tx_msg_verify_sop(port));
TEST_ASSERT(pd_test_tx_msg_verify_short(port,
PD_HEADER(PD_DATA_REQUEST, PD_ROLE_SINK, PD_ROLE_UFP,
pd_port[port].msg_tx_id, 1)));
pd_port[port].msg_tx_id, 1, pd_port[port].rev, 0)));
TEST_ASSERT(pd_test_tx_msg_verify_word(port, expected_rdo));
TEST_ASSERT(pd_test_tx_msg_verify_crc(port));
TEST_ASSERT(pd_test_tx_msg_verify_eop(port));
@ -595,7 +775,6 @@ static int test_request(void)
return EC_SUCCESS;
}
static int test_sink(void)
{
int i;
@ -611,7 +790,8 @@ static int test_sink(void)
TEST_ASSERT(pd_test_tx_msg_verify_short(port,
PD_HEADER(PD_DATA_SOURCE_CAP, PD_ROLE_SOURCE,
PD_ROLE_DFP, pd_port[port].msg_tx_id,
pd_src_pdo_cnt)));
pd_src_pdo_cnt, pd_port[port].rev, 0)));
for (i = 0; i < pd_src_pdo_cnt; ++i)
TEST_ASSERT(pd_test_tx_msg_verify_word(port, pd_src_pdo[i]));
@ -646,5 +826,6 @@ void run_test(void)
RUN_TEST(test_request_with_wait);
RUN_TEST(test_request_with_wait_and_contract);
RUN_TEST(test_request_with_reject);
test_print_result();
}

1
test/usb_pd_rev30.tasklist Symbolic link
View File

@ -0,0 +1 @@
usb_pd.tasklist