mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2026-01-13 03:15:06 +00:00
pd: Properly assign data role on reset
According to PD spec: - Data role shall not be reset on soft reset. - Data role shall be reset to power-role default on hard reset. Implement the above. Even if both ports follow spec, it's still possible for a data role conflict to occur if, for example, data role swap occurs (data role mismatches power role default) followed by a hardware reset of one port (such that data role gets reset to power role default). Handle such cases by taking error recovery actions. BUG=b:71333840,chromium:805040 TEST=Connect scarlet to powered Apple accessory, verify scarlet comes up in SNK-DFP after soft reset and issuing "reboot" on EC console. After issuing a hard reset, the port comes up in SNK-UFP (which is the power-role default). BRANCH=None Signed-off-by: Shawn Nematbakhsh <shawnn@chromium.org> Signed-off-by: Aseda Aboagye <aaboagye@google.com> Change-Id: I65139f277d59a0612f8323d711080f52425ff5e7 Reviewed-on: https://chromium-review.googlesource.com/885462 Commit-Ready: Aseda Aboagye <aaboagye@chromium.org> Tested-by: Aseda Aboagye <aaboagye@chromium.org> Reviewed-by: Jett Rink <jettrink@chromium.org> Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
This commit is contained in:
committed by
chrome-bot
parent
d268930c75
commit
36980ec169
@@ -924,6 +924,34 @@ static void handle_vdm_request(int port, int cnt, uint32_t *payload)
|
||||
port, PD_VDO_VID(payload[0]), payload[0] & 0xFFFF);
|
||||
}
|
||||
|
||||
static void pd_set_data_role(int port, int role)
|
||||
{
|
||||
pd[port].data_role = role;
|
||||
#ifdef CONFIG_USB_PD_DUAL_ROLE
|
||||
pd_update_saved_port_flags(port, PD_BBRMFLG_DATA_ROLE, role);
|
||||
#endif /* defined(CONFIG_USB_PD_DUAL_ROLE) */
|
||||
pd_execute_data_swap(port, role);
|
||||
|
||||
#ifdef CONFIG_USBC_SS_MUX
|
||||
#ifdef CONFIG_USBC_SS_MUX_DFP_ONLY
|
||||
/*
|
||||
* Need to connect SS mux for if new data role is DFP.
|
||||
* If new data role is UFP, then disconnect the SS mux.
|
||||
*/
|
||||
if (role == PD_ROLE_DFP)
|
||||
usb_mux_set(port, TYPEC_MUX_USB, USB_SWITCH_CONNECT,
|
||||
pd[port].polarity);
|
||||
else
|
||||
usb_mux_set(port, TYPEC_MUX_NONE, USB_SWITCH_DISCONNECT,
|
||||
pd[port].polarity);
|
||||
#else
|
||||
usb_mux_set(port, TYPEC_MUX_USB, USB_SWITCH_CONNECT,
|
||||
pd[port].polarity);
|
||||
#endif
|
||||
#endif
|
||||
pd_update_roles(port);
|
||||
}
|
||||
|
||||
void pd_execute_hard_reset(int port)
|
||||
{
|
||||
if (pd[port].last_state == PD_STATE_HARD_RESET_SEND)
|
||||
@@ -957,6 +985,8 @@ void pd_execute_hard_reset(int port)
|
||||
pd_power_supply_reset(port);
|
||||
}
|
||||
|
||||
/* Set initial data role (matching power role) */
|
||||
pd_set_data_role(port, pd[port].power_role);
|
||||
if (pd[port].power_role == PD_ROLE_SINK) {
|
||||
/* Clear the input current limit */
|
||||
pd_set_input_current_limit(port, 0, 0);
|
||||
@@ -1277,31 +1307,6 @@ void pd_request_data_swap(int port)
|
||||
task_wake(PD_PORT_TO_TASK_ID(port));
|
||||
}
|
||||
|
||||
static void pd_set_data_role(int port, int role)
|
||||
{
|
||||
pd[port].data_role = role;
|
||||
pd_execute_data_swap(port, role);
|
||||
|
||||
#ifdef CONFIG_USBC_SS_MUX
|
||||
#ifdef CONFIG_USBC_SS_MUX_DFP_ONLY
|
||||
/*
|
||||
* Need to connect SS mux for if new data role is DFP.
|
||||
* If new data role is UFP, then disconnect the SS mux.
|
||||
*/
|
||||
if (role == PD_ROLE_DFP)
|
||||
usb_mux_set(port, TYPEC_MUX_USB, USB_SWITCH_CONNECT,
|
||||
pd[port].polarity);
|
||||
else
|
||||
usb_mux_set(port, TYPEC_MUX_NONE, USB_SWITCH_DISCONNECT,
|
||||
pd[port].polarity);
|
||||
#else
|
||||
usb_mux_set(port, TYPEC_MUX_USB, USB_SWITCH_CONNECT,
|
||||
pd[port].polarity);
|
||||
#endif
|
||||
#endif
|
||||
pd_update_roles(port);
|
||||
}
|
||||
|
||||
static void pd_set_power_role(int port, int role)
|
||||
{
|
||||
pd[port].power_role = role;
|
||||
@@ -1591,6 +1596,7 @@ static void handle_request(int port, uint16_t head,
|
||||
uint32_t *payload)
|
||||
{
|
||||
int cnt = PD_HEADER_CNT(head);
|
||||
int data_role = PD_HEADER_DROLE(head);
|
||||
int p;
|
||||
|
||||
/* dump received packet content (only dump ping at debug level 3) */
|
||||
@@ -1609,6 +1615,36 @@ static void handle_request(int port, uint16_t head,
|
||||
if (!pd_is_connected(port))
|
||||
set_state(port, PD_STATE_HARD_RESET_SEND);
|
||||
|
||||
/*
|
||||
* When a data role conflict is detected, USB-C ErrorRecovery
|
||||
* actions shall be performed, and transitioning to unattached state
|
||||
* is one such legal action.
|
||||
*/
|
||||
if (pd[port].data_role == data_role) {
|
||||
CPRINTF("C%d DR conflict!\n", port);
|
||||
/*
|
||||
* If the port doesn't support removing the terminations, just
|
||||
* go to the unattached state.
|
||||
*/
|
||||
if (tcpm_set_cc(port, TYPEC_CC_OPEN) == EC_SUCCESS) {
|
||||
/* Do not drive VBUS or VCONN. */
|
||||
pd_power_supply_reset(port);
|
||||
#ifdef CONFIG_USBC_VCONN
|
||||
set_vconn(port, 0);
|
||||
#endif /* defined(CONFIG_USBC_VCONN) */
|
||||
usleep(PD_T_ERROR_RECOVERY);
|
||||
|
||||
/* Restore terminations. */
|
||||
tcpm_set_cc(port, DUAL_ROLE_IF_ELSE(port, TYPEC_CC_RD,
|
||||
TYPEC_CC_RP));
|
||||
}
|
||||
set_state(port,
|
||||
DUAL_ROLE_IF_ELSE(port,
|
||||
PD_STATE_SNK_DISCONNECTED,
|
||||
PD_STATE_SRC_DISCONNECTED));
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
/* Check if this is an extended chunked data message. */
|
||||
if (pd[port].rev == PD_REV30 && PD_HEADER_EXT(head)) {
|
||||
|
||||
@@ -737,6 +737,7 @@ enum pd_states {
|
||||
/* Per-port battery backed RAM flags */
|
||||
#define PD_BBRMFLG_EXPLICIT_CONTRACT (1 << 0)
|
||||
#define PD_BBRMFLG_POWER_ROLE (1 << 1)
|
||||
#define PD_BBRMFLG_DATA_ROLE (1 << 2)
|
||||
|
||||
enum pd_cc_states {
|
||||
PD_CC_NONE,
|
||||
@@ -915,11 +916,12 @@ enum pd_data_msg_type {
|
||||
((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)
|
||||
#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)
|
||||
#define PD_HEADER_DROLE(header) (((header) >> 5) & 1)
|
||||
|
||||
/* Used for processing pd extended header */
|
||||
#define PD_EXT_HEADER_CHUNKED(header) (((header) >> 15) & 1)
|
||||
|
||||
Reference in New Issue
Block a user