summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--common/usb_pd_protocol.c122
-rw-r--r--include/usb_pd.h4
2 files changed, 85 insertions, 41 deletions
diff --git a/common/usb_pd_protocol.c b/common/usb_pd_protocol.c
index 3a4a2951b2..5c46774d85 100644
--- a/common/usb_pd_protocol.c
+++ b/common/usb_pd_protocol.c
@@ -1106,21 +1106,27 @@ 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)
+static void set_usb_mux_with_current_data_role(int port)
{
- 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
+ /*
+ * If the SoC is down, then we disconnect the MUX to save power since
+ * no one cares about the data lines.
+ */
+#ifdef CONFIG_POWER_COMMON
+ if (chipset_in_or_transitioning_to_state(CHIPSET_STATE_ANY_OFF)) {
+ usb_mux_set(port, TYPEC_MUX_NONE, USB_SWITCH_DISCONNECT,
+ pd[port].polarity);
+ return;
+ }
+#endif /* CONFIG_POWER_COMMON */
+
#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)
+ if (pd[port].data_role == PD_ROLE_DFP)
usb_mux_set(port, TYPEC_MUX_USB, USB_SWITCH_CONNECT,
pd[port].polarity);
else
@@ -1129,8 +1135,19 @@ static void pd_set_data_role(int port, int role)
#else
usb_mux_set(port, TYPEC_MUX_USB, USB_SWITCH_CONNECT,
pd[port].polarity);
-#endif
-#endif
+#endif /* CONFIG_USBC_SS_MUX_DFP_ONLY */
+#endif /* CONFIG_USBC_SS_MUX */
+}
+
+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);
+
+ set_usb_mux_with_current_data_role(port);
pd_update_roles(port);
}
@@ -1997,6 +2014,38 @@ int pd_dev_store_rw_hash(int port, uint16_t dev_id, uint32_t *rw_hash,
return 0;
}
+#ifdef CONFIG_POWER_COMMON /* Needed b/c CONFIG_POWER_COMMON is only caller */
+static void exit_dp_mode(int port)
+{
+#ifdef CONFIG_USB_PD_ALT_MODE_DFP
+ int opos = pd_alt_mode(port, USB_SID_DISPLAYPORT);
+
+ if (opos <= 0)
+ return;
+
+ CPRINTS("C%d Exiting DP mode", port);
+ if (!pd_dfp_exit_mode(port, USB_SID_DISPLAYPORT, opos))
+ return;
+ pd_send_vdm(port, USB_SID_DISPLAYPORT,
+ CMD_EXIT_MODE | VDO_OPOS(opos), NULL, 0);
+ pd_vdm_send_state_machine(port);
+ /* Have to wait for ACK */
+#endif /* CONFIG_USB_PD_ALT_MODE_DFP */
+}
+#endif /* CONFIG_POWER_COMMON */
+
+#ifdef CONFIG_POWER_COMMON
+static void handle_new_power_state(int port)
+{
+ if (chipset_in_or_transitioning_to_state(CHIPSET_STATE_ANY_OFF))
+ /* The SoC will negotiated DP mode again when it boots up */
+ exit_dp_mode(port);
+
+ /* Ensure mux is set properly after chipset transition */
+ set_usb_mux_with_current_data_role(port);
+}
+#endif /* CONFIG_POWER_COMMON */
+
#ifdef CONFIG_USB_PD_DUAL_ROLE
enum pd_dual_role_states pd_get_dual_role(int port)
{
@@ -2047,39 +2096,26 @@ static void pd_update_try_source(void)
DECLARE_HOOK(HOOK_BATTERY_SOC_CHANGE, pd_update_try_source, HOOK_PRIO_DEFAULT);
#endif
-void pd_set_dual_role(int port, enum pd_dual_role_states state)
+static inline void pd_set_dual_role_no_wakeup(int port,
+ enum pd_dual_role_states state)
{
- int i;
-
drp_state[port] = state;
#ifdef CONFIG_USB_PD_TRY_SRC
pd_update_try_source();
#endif
-
- /* Inform PD tasks of dual role change. */
- for (i = 0; i < CONFIG_USB_PD_PORT_COUNT; i++)
- task_set_event(PD_PORT_TO_TASK_ID(i),
- PD_EVENT_UPDATE_DUAL_ROLE, 0);
}
-static void exit_dp_mode(int port)
+void pd_set_dual_role(int port, enum pd_dual_role_states state)
{
-#ifdef CONFIG_USB_PD_ALT_MODE_DFP
- int opos = pd_alt_mode(port, USB_SID_DISPLAYPORT);
- if (opos <= 0)
- return;
- CPRINTS("C%d Exiting DP mode", port);
- if (!pd_dfp_exit_mode(port, USB_SID_DISPLAYPORT, opos))
- return;
- pd_send_vdm(port, USB_SID_DISPLAYPORT,
- CMD_EXIT_MODE | VDO_OPOS(opos), NULL, 0);
- pd_vdm_send_state_machine(port);
- /* Have to wait for ACK */
-#endif
+ pd_set_dual_role_no_wakeup(port, state);
+
+ /* Wake task up to process change */
+ task_set_event(PD_PORT_TO_TASK_ID(port),
+ PD_EVENT_UPDATE_DUAL_ROLE, 0);
}
-void pd_update_dual_role_config(int port)
+static void pd_update_dual_role_config(int port)
{
/*
* Change to sink if port is currently a source AND (new DRP
@@ -2470,7 +2506,8 @@ void pd_task(void *u)
* present. This flag is used to maintain a PD connection after a
* reset by sending a soft reset.
*/
- pd[port].flags = pd_is_vbus_present(port) ? PD_FLAGS_VBUS_NEVER_LOW : 0;
+ pd[port].flags |=
+ pd_is_vbus_present(port) ? PD_FLAGS_VBUS_NEVER_LOW : 0;
#endif
/* Disable TCPC RX until connection is established */
@@ -2580,10 +2617,11 @@ void pd_task(void *u)
if (evt & PD_EVENT_DEVICE_ACCESSED)
handle_device_access(port);
#endif
-
+#ifdef CONFIG_POWER_COMMON
+ if (evt & PD_EVENT_POWER_STATE_CHANGE)
+ handle_new_power_state(port);
+#endif
#ifdef CONFIG_USB_PD_DUAL_ROLE
- if (evt & PD_EVENT_DP_DISCONNECT)
- exit_dp_mode(port);
if (evt & PD_EVENT_UPDATE_DUAL_ROLE)
pd_update_dual_role_config(port);
#endif
@@ -3944,8 +3982,12 @@ static void pd_chipset_startup(void)
int i;
for (i = 0; i < CONFIG_USB_PD_PORT_COUNT; i++) {
- pd_set_dual_role(i, PD_DRP_TOGGLE_OFF);
+ pd_set_dual_role_no_wakeup(i, PD_DRP_TOGGLE_OFF);
pd[i].flags |= PD_FLAGS_CHECK_IDENTITY;
+ task_set_event(PD_PORT_TO_TASK_ID(i),
+ PD_EVENT_POWER_STATE_CHANGE |
+ PD_EVENT_UPDATE_DUAL_ROLE,
+ 0);
}
CPRINTS("PD:S5->S3");
}
@@ -3956,9 +3998,11 @@ static void pd_chipset_shutdown(void)
int i;
for (i = 0; i < CONFIG_USB_PD_PORT_COUNT; i++) {
+ pd_set_dual_role_no_wakeup(i, PD_DRP_FORCE_SINK);
task_set_event(PD_PORT_TO_TASK_ID(i),
- PD_EVENT_DP_DISCONNECT, 0);
- pd_set_dual_role(i, PD_DRP_FORCE_SINK);
+ PD_EVENT_POWER_STATE_CHANGE |
+ PD_EVENT_UPDATE_DUAL_ROLE,
+ 0);
}
CPRINTS("PD:S3->S5");
}
diff --git a/include/usb_pd.h b/include/usb_pd.h
index 64b9d51c82..0bf3b15ffe 100644
--- a/include/usb_pd.h
+++ b/include/usb_pd.h
@@ -46,8 +46,8 @@ enum pd_rx_errors {
* A task, other than the task owning the PD port, accessed the TCPC. The task
* that owns the port does not send itself this event.
*/
-#define PD_EVENT_DEVICE_ACCESSED (1<<7)
-#define PD_EVENT_DP_DISCONNECT (1<<8) /* DisplayPort disconnect requested */
+#define PD_EVENT_DEVICE_ACCESSED (1<<7)
+#define PD_EVENT_POWER_STATE_CHANGE (1<<8) /* Chipset power state changed */
/* --- PD data message helpers --- */
#define PDO_MAX_OBJECTS 7