diff options
-rw-r--r-- | common/usbc/usb_pd_dpm.c | 81 | ||||
-rw-r--r-- | common/usbc/usb_pe_drp_sm.c | 5 | ||||
-rw-r--r-- | include/usb_pd.h | 31 | ||||
-rw-r--r-- | include/usb_pe_sm.h | 8 |
4 files changed, 122 insertions, 3 deletions
diff --git a/common/usbc/usb_pd_dpm.c b/common/usbc/usb_pd_dpm.c index 45d41b6b1f..734fe53926 100644 --- a/common/usbc/usb_pd_dpm.c +++ b/common/usbc/usb_pd_dpm.c @@ -13,6 +13,7 @@ #include "console.h" #include "ec_commands.h" #include "hooks.h" +#include "power.h" #include "system.h" #include "task.h" #include "tcpm/tcpm.h" @@ -24,6 +25,7 @@ #include "usb_pd_dpm.h" #include "usb_pd_tcpm.h" #include "usb_pd_pdo.h" +#include "usb_pe_sm.h" #include "usb_tbt_alt_mode.h" #ifdef CONFIG_ZEPHYR @@ -818,6 +820,24 @@ int dpm_get_source_current(const int port) return 500; } +__overridable enum pd_sdb_power_indicator board_get_pd_sdb_power_indicator( +enum pd_sdb_power_state power_state) +{ + /* + * LED on for S0 and blinking for S0ix/S3. + * LED off for all other power states (S4, S5, G3, NOT_SUPPORTED) + */ + switch (power_state) { + case PD_SDB_POWER_STATE_S0: + return PD_SDB_POWER_INDICATOR_ON; + case PD_SDB_POWER_STATE_MODERN_STANDBY: + case PD_SDB_POWER_STATE_S3: + return PD_SDB_POWER_INDICATOR_BLINKING; + default: + return PD_SDB_POWER_INDICATOR_OFF; + } +} + static uint8_t get_status_internal_temp(void) { /* @@ -863,9 +883,56 @@ static enum pd_sdb_temperature_status get_status_temp_status(void) #endif } +static uint8_t get_status_power_state_change(void) +{ + enum pd_sdb_power_state ret = PD_SDB_POWER_STATE_NOT_SUPPORTED; + +#ifdef HAS_TASK_CHIPSET + switch (power_get_state()) { + case POWER_G3: + case POWER_S5G3: + ret = PD_SDB_POWER_STATE_G3; + break; + case POWER_S5: + case POWER_G3S5: + case POWER_S3S5: + case POWER_S4S5: + ret = PD_SDB_POWER_STATE_S5; + break; + case POWER_S4: + case POWER_S3S4: + case POWER_S5S4: + ret = PD_SDB_POWER_STATE_S4; + break; + case POWER_S3: + case POWER_S5S3: + case POWER_S0S3: + case POWER_S4S3: + ret = PD_SDB_POWER_STATE_S3; + break; + case POWER_S0: + case POWER_S3S0: +#ifdef CONFIG_POWER_S0IX + case POWER_S0ixS0: +#endif /* CONFIG_POWER_S0IX */ + ret = PD_SDB_POWER_STATE_S0; + break; +#ifdef CONFIG_POWER_S0IX + case POWER_S0ix: + case POWER_S0S0ix: + ret = PD_SDB_POWER_STATE_MODERN_STANDBY; + break; +#endif /* CONFIG_POWER_S0IX */ + } +#endif /* HAS_TASK_CHIPSET */ + + return ret | board_get_pd_sdb_power_indicator(ret); +} + int dpm_get_status_msg(int port, uint8_t *msg, uint32_t *len) { struct pd_sdb sdb; + struct rmdo partner_rmdo; /* TODO(b/227236917): Fill in fields of Status message */ @@ -887,10 +954,18 @@ int dpm_get_status_msg(int port, uint8_t *msg, uint32_t *len) /* Power Status */ sdb.power_status = 0x0; - /* USB PD Rev 3.0: 6.5.2 Status Message */ - *len = 6; + partner_rmdo = pe_get_partner_rmdo(port); + if ((partner_rmdo.major_rev == 3 && partner_rmdo.minor_rev >= 1) || + partner_rmdo.major_rev > 3) { + /* USB PD Rev 3.1: 6.5.2 Status Message */ + sdb.power_state_change = get_status_power_state_change(); + *len = 7; + } else { + /* USB PD Rev 3.0: 6.5.2 Status Message */ + sdb.power_state_change = 0; + *len = 6; + } memcpy(msg, &sdb, *len); - return EC_SUCCESS; } diff --git a/common/usbc/usb_pe_drp_sm.c b/common/usbc/usb_pe_drp_sm.c index 6906c4c6f8..654748a8bd 100644 --- a/common/usbc/usb_pe_drp_sm.c +++ b/common/usbc/usb_pe_drp_sm.c @@ -1433,6 +1433,11 @@ void pe_clear_ado(int port) mutex_unlock(&pe[port].ado_lock); } +struct rmdo pe_get_partner_rmdo(int port) +{ + return pe[port].partner_rmdo; +} + static void pe_handle_detach(void) { const int port = TASK_ID_TO_PD_PORT(task_get_current()); diff --git a/include/usb_pd.h b/include/usb_pd.h index 12e34520bc..62a8330c54 100644 --- a/include/usb_pd.h +++ b/include/usb_pd.h @@ -1217,12 +1217,32 @@ enum pd_sdb_temperature_status { BUILD_ASSERT(sizeof(enum pd_sdb_temperature_status) == 1); struct pd_sdb { + /* SDB Fields for PD REV 3.0 */ uint8_t internal_temp; uint8_t present_input; uint8_t present_battery_input; uint8_t event_flags; enum pd_sdb_temperature_status temperature_status; uint8_t power_status; + /* SDB Fields for PD REV 3.1 */ + uint8_t power_state_change; +}; + +enum pd_sdb_power_state { + PD_SDB_POWER_STATE_NOT_SUPPORTED = 0, + PD_SDB_POWER_STATE_S0 = 1, + PD_SDB_POWER_STATE_MODERN_STANDBY = 2, + PD_SDB_POWER_STATE_S3 = 3, + PD_SDB_POWER_STATE_S4 = 4, + PD_SDB_POWER_STATE_S5 = 5, + PD_SDB_POWER_STATE_G3 = 6, +}; + +enum pd_sdb_power_indicator { + PD_SDB_POWER_INDICATOR_OFF = (0 << 3), + PD_SDB_POWER_INDICATOR_ON = (1 << 3), + PD_SDB_POWER_INDICATOR_BLINKING = (2 << 3), + PD_SDB_POWER_INDICATOR_BREATHING = (3 << 3), }; /* Extended message type for REV 3.0 */ @@ -3515,6 +3535,17 @@ void typec_select_src_collision_rp(int port, enum tcpc_rp_value rp); * @return 0 on success else failure */ int typec_update_cc(int port); + +/** + * Defines the New power state indicator bits in the Power State Change + * field of the Status Data Block (SDB) in USB PD Revision 3.1 and above. + * + * @param pd_sdb_power_state enum defining the New Power State field of the SDB + * @return pd_sdb_power_indicator enum for the SDB + */ +__override_proto enum pd_sdb_power_indicator board_get_pd_sdb_power_indicator( +enum pd_sdb_power_state power_state); + /****************************************************************************/ #endif /* __CROS_EC_USB_PD_H */ diff --git a/include/usb_pe_sm.h b/include/usb_pe_sm.h index aef262ef49..4018f16322 100644 --- a/include/usb_pe_sm.h +++ b/include/usb_pe_sm.h @@ -192,6 +192,14 @@ int pe_set_ado(int port, uint32_t data); */ void pe_clear_ado(int port); +/** + * Gets port partner's RMDO from the PE state. + * + * @param port USB-C port number + * @return port partner's Revision Message Data Object (RMDO). + */ +struct rmdo pe_get_partner_rmdo(int port); + #ifdef TEST_BUILD /** * Clears all internal port data, as we would on a detach event |