diff options
Diffstat (limited to 'drivers/usb/pd/richtek/pd_policy_engine.c')
-rw-r--r-- | drivers/usb/pd/richtek/pd_policy_engine.c | 782 |
1 files changed, 782 insertions, 0 deletions
diff --git a/drivers/usb/pd/richtek/pd_policy_engine.c b/drivers/usb/pd/richtek/pd_policy_engine.c new file mode 100644 index 000000000000..ceded2cbd665 --- /dev/null +++ b/drivers/usb/pd/richtek/pd_policy_engine.c @@ -0,0 +1,782 @@ +/* + * Copyright (C) 2016 Richtek Technology Corp. + * + * Power Delivery Policy Engine Driver + * + * Author: TH <tsunghan_tsai@richtek.com> + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/hisi/usb/pd/richtek/pd_core.h> +#include <linux/hisi/usb/pd/richtek/pd_dpm_core.h> +#include <linux/hisi/usb/pd/richtek/tcpci.h> +#include <linux/hisi/usb/pd/richtek/pd_process_evt.h> +#include <linux/hisi/usb/pd/richtek/pd_policy_engine.h> +#include <linux/hisi/usb/pd/richtek/rt1711h.h> + +/* ---- Policy Engine State ---- */ + +#if PE_STATE_FULL_NAME + +static const char *const pe_state_name[] = { + "PE_SRC_STARTUP", + "PE_SRC_DISCOVERY", + "PE_SRC_SEND_CAPABILITIES", + "PE_SRC_NEGOTIATE_CAPABILITIES", + "PE_SRC_TRANSITION_SUPPLY", + "PE_SRC_TRANSITION_SUPPLY2", + "PE_SRC_READY", + "PE_SRC_DISABLED", + "PE_SRC_CAPABILITY_RESPONSE", + "PE_SRC_HARD_RESET", + "PE_SRC_HARD_RESET_RECEIVED", + "PE_SRC_TRANSITION_TO_DEFAULT", + "PE_SRC_GIVE_SOURCE_CAP", + "PE_SRC_GET_SINK_CAP", + "PE_SRC_WAIT_NEW_CAPABILITIES", + + "PE_SRC_SEND_SOFT_RESET", + "PE_SRC_SOFT_RESET", + "PE_SRC_PING", + +#ifdef CONFIG_USB_PD_SRC_STARTUP_DISCOVER_ID + "PE_SRC_VDM_IDENTITY_REQUEST", + "PE_SRC_VDM_IDENTITY_ACKED", + "PE_SRC_VDM_IDENTITY_NAKED", +#endif /* CONFIG_USB_PD_SRC_STARTUP_DISCOVER_ID */ + + "PE_SNK_STARTUP", + "PE_SNK_DISCOVERY", + "PE_SNK_WAIT_FOR_CAPABILITIES", + "PE_SNK_EVALUATE_CAPABILITY", + "PE_SNK_SELECT_CAPABILITY", + "PE_SNK_TRANSITION_SINK", + "PE_SNK_READY", + "PE_SNK_HARD_RESET", + "PE_SNK_TRANSITION_TO_DEFAULT", + "PE_SNK_GIVE_SINK_CAP", + "PE_SNK_GET_SOURCE_CAP", + + "PE_SNK_SEND_SOFT_RESET", + "PE_SNK_SOFT_RESET", + + "PE_DRS_DFP_UFP_EVALUATE_DR_SWAP", + "PE_DRS_DFP_UFP_ACCEPT_DR_SWAP", + "PE_DRS_DFP_UFP_CHANGE_TO_UFP", + "PE_DRS_DFP_UFP_SEND_DR_SWAP", + "PE_DRS_DFP_UFP_REJECT_DR_SWAP", + + "PE_DRS_UFP_DFP_EVALUATE_DR_SWAP", + "PE_DRS_UFP_DFP_ACCEPT_DR_SWAP", + "PE_DRS_UFP_DFP_CHANGE_TO_DFP", + "PE_DRS_UFP_DFP_SEND_SWAP", + "PE_DRS_UFP_DFP_REJECT_DR_SWAP", + + "PE_PRS_SRC_SNK_EVALUATE_PR_SWAP", + "PE_PRS_SRC_SNK_ACCEPT_PR_SWAP", + "PE_PRS_SRC_SNK_TRANSITION_TO_OFF", + "PE_PRS_SRC_SNK_ASSERT_RD", + "PE_PRS_SRC_SNK_WAIT_SOURCE_ON", + "PE_PRS_SRC_SNK_SEND_SWAP", + "PE_PRS_SRC_SNK_REJECT_PR_SWAP", + + "PE_PRS_SNK_SRC_EVALUATE_PR_SWAP", + "PE_PRS_SNK_SRC_ACCEPT_PR_SWAP", + "PE_PRS_SNK_SRC_TRANSITION_TO_OFF", + "PE_PRS_SNK_SRC_ASSERT_RP", + "PE_PRS_SNK_SRC_SOURCE_ON", + "PE_PRS_SNK_SRC_SEND_PR_SWAP", + "PE_PRS_SNK_SRC_REJECT_SWAP", + + "PE_DR_SRC_GET_SOURCE_CAP", + + "PE_DR_SRC_GIVE_SINK_CAP", + + "PE_DR_SNK_GET_SINK_CAP", + + "PE_DR_SNK_GIVE_SOURCE_CAP", + + "PE_VCS_SEND_SWAP", + "PE_VCS_EVALUATE_SWAP", + "PE_VCS_ACCEPT_SWAP", + "PE_VCS_REJECT_SWAP", + "PE_VCS_WAIT_FOR_VCONN", + "PE_VCS_TURN_OFF_VCONN", + "PE_VCS_TURN_ON_VCONN", + "PE_VCS_SEND_PS_RDY", + + "PE_UFP_VDM_GET_IDENTITY", + "PE_UFP_VDM_SEND_IDENTITY", + "PE_UFP_VDM_GET_IDENTITY_NAK", + + "PE_UFP_VDM_GET_SVIDS", + "PE_UFP_VDM_SEND_SVIDS", + "PE_UFP_VDM_GET_SVIDS_NAK", + + "PE_UFP_VDM_GET_MODES", + "PE_UFP_VDM_SEND_MODES", + "PE_UFP_VDM_GET_MODES_NAK", + + "PE_UFP_VDM_EVALUATE_MODE_ENTRY", + "PE_UFP_VDM_MODE_ENTRY_ACK", + "PE_UFP_VDM_MODE_ENTRY_NAK", + + "PE_UFP_VDM_MODE_EXIT", + "PE_UFP_VDM_MODE_EXIT_ACK", + "PE_UFP_VDM_MODE_EXIT_NAK", + + "PE_UFP_VDM_ATTENTION_REQUEST", + + "PE_DFP_UFP_VDM_IDENTITY_REQUEST", + "PE_DFP_UFP_VDM_IDENTITY_ACKED", + "PE_DFP_UFP_VDM_IDENTITY_NAKED", + + "PE_DFP_CBL_VDM_IDENTITY_REQUEST", + "PE_DFP_CBL_VDM_IDENTITY_ACKED", + "PE_DFP_CBL_VDM_IDENTITY_NAKED", + + "PE_DFP_VDM_SVIDS_REQUEST", + "PE_DFP_VDM_SVIDS_ACKED", + "PE_DFP_VDM_SVIDS_NAKED", + + "PE_DFP_VDM_MODES_REQUEST", + "PE_DFP_VDM_MODES_ACKED", + "PE_DFP_VDM_MODES_NAKED", + + "PE_DFP_VDM_MODE_ENTRY_REQUEST", + "PE_DFP_VDM_MODE_ENTRY_ACKED", + "PE_DFP_VDM_MODE_ENTRY_NAKED", + + "PE_DFP_VDM_MODE_EXIT_REQUEST", + "PE_DFP_VDM_MODE_EXIT_ACKED", + + "PE_DFP_VDM_ATTENTION_REQUEST", + +#ifdef CONFIG_USB_PD_CUSTOM_DBGACC + "PE_DBG_READY", +#endif /* CONFIG_USB_PD_CUSTOM_DBGACC */ + + "PE_BIST_TEST_DATA", + "PE_BIST_CARRIER_MODE_2", + + "PE_IDLE1", + "PE_IDLE2", + + "PE_VIRT_HARD_RESET", + "PE_VIRT_READY", +}; +#else + +static const char *const pe_state_name[] = { + "SRC_START", + "SRC_DISCOVERY", + "SRC_SEND_CAP", + "SRC_NEG_CAP", + "SRC_TRANS_SUPPLY", + "SRC_TRANS_SUPPLY2", + "SRC_READY", + "SRC_DISABLED", + "SRC_CAP_RESP", + "SRC_HRESET", + "SRC_HRESET_RECV", + "SRC_TRANS_DFT", + "SRC_GIVE_CAP", + "SRC_GET_CAP", + "SRC_WAIT_CAP", + + "SRC_SEND_SRESET", + "SRC_SRESET", + "SRC_PING", + +#ifdef CONFIG_USB_PD_SRC_STARTUP_DISCOVER_ID + "SRC_VDM_ID_REQ", + "SRC_VDM_ID_ACK", + "SRC_VDM_ID_NAK", +#endif /* CONFIG_USB_PD_SRC_STARTUP_DISCOVER_ID */ + + "SNK_START", + "SNK_DISCOVERY", + "SNK_WAIT_CAP", + "SNK_EVA_CAP", + "SNK_SEL_CAP", + "SNK_TRANS_SINK", + "SNK_READY", + "SNK_HRESET", + "SNK_TRANS_DFT", + "SNK_GIVE_CAP", + "SNK_GET_CAP", + + "SNK_SEND_SRESET", + "SNK_SRESET", + + "D_DFP_EVALUATE", + "D_DFP_ACCEPT", + "D_DFP_CHANGE", + "D_DFP_SEND", + "D_DFP_REJECT", + + "D_UFP_EVALUATE", + "D_UFP_ACCEPT", + "D_UFP_CHANGE", + "D_UFP_SEND", + "D_UFP_REJECT", + + "P_SRC_EVALUATE", + "P_SRC_ACCEPT", + "P_SRC_TRANS_OFF", + "P_SRC_ASSERT", + "P_SRC_WAIT_ON", + "P_SRC_SEND", + "P_SRC_REJECT", + + "P_SNK_EVALUATE", + "P_SNK_ACCEPT", + "P_SNK_TRANS_OFF", + "P_SNK_ASSERT", + "P_SNK_SOURCE_ON", + "P_SNK_SEND", + "P_SNK_REJECT", + + "DR_SRC_GET_CAP", /* get source cap */ + "DR_SRC_GIVE_CAP", /* give sink cap */ + "DR_SNK_GET_CAP", /* get sink cap */ + "DR_SNK_GIVE_CAP", /* give source cap */ + + "V_SEND", + "V_EVALUATE", + "V_ACCEPT", + "V_REJECT", + "V_WAIT_VCONN", + "V_TURN_OFF", + "V_TURN_ON", + "V_PS_RDY", + + "U_GET_ID", + "U_SEND_ID", + "U_GET_ID_N", + + "U_GET_SVID", + "U_SEND_SVID", + "U_GET_SVID_N", + + "U_GET_MODE", + "U_SEND_MODE", + "U_GET_MODE_N", + + "U_EVA_MODE", + "U_MODE_EN_A", + "U_MODE_EN_N", + + "U_MODE_EX", + "U_MODE_EX_A", + "U_MODE_EX_N", + + "U_ATTENTION", + + "D_UID_REQ", + "D_UID_A", + "D_UID_N", + + "D_CID_REQ", + "D_CID_ACK", + "D_CID_NAK", + + "D_SVID_REQ", + "D_SVID_ACK", + "D_SVID_NAK", + + "D_MODE_REQ", + "D_MODE_ACK", + "D_MODE_NAK", + + "D_MODE_EN_REQ", + "D_MODE_EN_ACK", + "D_MODE_EN_NAK", + + "D_MODE_EX_REQ", + "D_MODE_EX_ACK", + + "D_ATTENTION", + +#ifdef CONFIG_USB_PD_CUSTOM_DBGACC + "DBG_READY", +#endif /* CONFIG_USB_PD_CUSTOM_DBGACC */ + + "ERR_RECOVERY", + + "BIST_TD", + "BIST_C2", + + "IDLE1", + "IDLE2", + + "VIRT_HARD_RESET", + "VIRT_READY", +}; + +#endif + +typedef void (*pe_state_action_fcn_t) + (pd_port_t *pd_port, pd_event_t *pd_event); + +typedef struct __pe_state_actions { + const pe_state_action_fcn_t entry_action; + /* const pd_pe_state_action_fcn_t exit_action; */ +} pe_state_actions_t; + +#define PE_STATE_ACTIONS(state) { .entry_action = state##_entry, } + +/* + * Policy Engine General State Activity + */ + +/* extern int rt1711_set_bist_carrier_mode( */ +/* struct tcpc_device *tcpc_dev, uint8_t pattern); */ +static void pe_idle_reset_data(pd_port_t *pd_port) +{ + pd_reset_pe_timer(pd_port); + pd_reset_svid_data(pd_port); + + pd_port->pd_prev_connected = false; + pd_port->state_machine = PE_STATE_MACHINE_IDLE; + + switch (pd_port->pe_state_curr) { + case PE_BIST_TEST_DATA: + pd_enable_bist_test_mode(pd_port, false); + break; + + case PE_BIST_CARRIER_MODE_2: + pd_disable_bist_mode2(pd_port); + break; + } + + pd_unlock_msg_output(pd_port); +} + +static void pe_idle1_entry(pd_port_t *pd_port, pd_event_t *pd_event) +{ + pe_idle_reset_data(pd_port); + + pd_try_put_pe_idle_event(pd_port); +} + +static void pe_idle2_entry(pd_port_t *pd_port, pd_event_t *pd_event) +{ + pd_set_rx_enable(pd_port, PD_RX_CAP_PE_IDLE); + pd_notify_pe_idle(pd_port); +} + +void pe_error_recovery_entry(pd_port_t *pd_port, pd_event_t *pd_event) +{ + pe_idle_reset_data(pd_port); + + pd_set_rx_enable(pd_port, PD_RX_CAP_PE_IDLE); + pd_notify_pe_error_recovery(pd_port); + pd_free_pd_event(pd_port, pd_event); +} + +void pe_bist_test_data_entry(pd_port_t *pd_port, pd_event_t *pd_event) +{ + pd_enable_bist_test_mode(pd_port, true); + pd_free_pd_event(pd_port, pd_event); +} + +void pe_bist_test_data_exit(pd_port_t *pd_port, pd_event_t *pd_event) +{ + pd_enable_bist_test_mode(pd_port, false); +} + +void pe_bist_carrier_mode_2_entry(pd_port_t *pd_port, pd_event_t *pd_event) +{ + pd_send_bist_mode2(pd_port); + pd_enable_timer(pd_port, PD_TIMER_BIST_CONT_MODE); + pd_free_pd_event(pd_port, pd_event); +} + +void pe_bist_carrier_mode_2_exit(pd_port_t *pd_port, pd_event_t *pd_event) +{ + pd_disable_timer(pd_port, PD_TIMER_BIST_CONT_MODE); + pd_disable_bist_mode2(pd_port); +} + +/* + * Policy Engine Share State Activity + */ + +void pe_power_ready_entry(pd_port_t *pd_port, pd_event_t *pd_event) +{ + pd_port->during_swap = false; + pd_port->explicit_contract = true; + + if (pd_port->data_role == PD_ROLE_UFP) + pd_set_rx_enable(pd_port, PD_RX_CAP_PE_READY_UFP); + else + pd_set_rx_enable(pd_port, PD_RX_CAP_PE_READY_DFP); + + pd_dpm_notify_pe_ready(pd_port, pd_event); + pd_free_pd_event(pd_port, pd_event); +} + +static const pe_state_actions_t pe_state_actions[] = { + /* src activity */ + PE_STATE_ACTIONS(pe_src_startup), + PE_STATE_ACTIONS(pe_src_discovery), + PE_STATE_ACTIONS(pe_src_send_capabilities), + PE_STATE_ACTIONS(pe_src_negotiate_capabilities), + PE_STATE_ACTIONS(pe_src_transition_supply), + PE_STATE_ACTIONS(pe_src_transition_supply2), + PE_STATE_ACTIONS(pe_src_ready), + PE_STATE_ACTIONS(pe_src_disabled), + PE_STATE_ACTIONS(pe_src_capability_response), + PE_STATE_ACTIONS(pe_src_hard_reset), + PE_STATE_ACTIONS(pe_src_hard_reset_received), + PE_STATE_ACTIONS(pe_src_transition_to_default), + PE_STATE_ACTIONS(pe_src_give_source_cap), + PE_STATE_ACTIONS(pe_src_get_sink_cap), + PE_STATE_ACTIONS(pe_src_wait_new_capabilities), + + PE_STATE_ACTIONS(pe_src_send_soft_reset), + PE_STATE_ACTIONS(pe_src_soft_reset), + PE_STATE_ACTIONS(pe_src_ping), + +#ifdef CONFIG_USB_PD_SRC_STARTUP_DISCOVER_ID + PE_STATE_ACTIONS(pe_src_vdm_identity_request), + PE_STATE_ACTIONS(pe_src_vdm_identity_acked), + PE_STATE_ACTIONS(pe_src_vdm_identity_naked), +#endif + + /* snk activity */ + PE_STATE_ACTIONS(pe_snk_startup), + PE_STATE_ACTIONS(pe_snk_discovery), + PE_STATE_ACTIONS(pe_snk_wait_for_capabilities), + PE_STATE_ACTIONS(pe_snk_evaluate_capability), + PE_STATE_ACTIONS(pe_snk_select_capability), + PE_STATE_ACTIONS(pe_snk_transition_sink), + PE_STATE_ACTIONS(pe_snk_ready), + PE_STATE_ACTIONS(pe_snk_hard_reset), + PE_STATE_ACTIONS(pe_snk_transition_to_default), + PE_STATE_ACTIONS(pe_snk_give_sink_cap), + PE_STATE_ACTIONS(pe_snk_get_source_cap), + + PE_STATE_ACTIONS(pe_snk_send_soft_reset), + PE_STATE_ACTIONS(pe_snk_soft_reset), + + /* drs dfp activity */ + PE_STATE_ACTIONS(pe_drs_dfp_ufp_evaluate_dr_swap), + PE_STATE_ACTIONS(pe_drs_dfp_ufp_accept_dr_swap), + PE_STATE_ACTIONS(pe_drs_dfp_ufp_change_to_ufp), + PE_STATE_ACTIONS(pe_drs_dfp_ufp_send_dr_swap), + PE_STATE_ACTIONS(pe_drs_dfp_ufp_reject_dr_swap), + + /* drs ufp activity */ + PE_STATE_ACTIONS(pe_drs_ufp_dfp_evaluate_dr_swap), + PE_STATE_ACTIONS(pe_drs_ufp_dfp_accept_dr_swap), + PE_STATE_ACTIONS(pe_drs_ufp_dfp_change_to_dfp), + PE_STATE_ACTIONS(pe_drs_ufp_dfp_send_dr_swap), + PE_STATE_ACTIONS(pe_drs_ufp_dfp_reject_dr_swap), + + /* prs src activity */ + PE_STATE_ACTIONS(pe_prs_src_snk_evaluate_pr_swap), + PE_STATE_ACTIONS(pe_prs_src_snk_accept_pr_swap), + PE_STATE_ACTIONS(pe_prs_src_snk_transition_to_off), + PE_STATE_ACTIONS(pe_prs_src_snk_assert_rd), + PE_STATE_ACTIONS(pe_prs_src_snk_wait_source_on), + PE_STATE_ACTIONS(pe_prs_src_snk_send_swap), + PE_STATE_ACTIONS(pe_prs_src_snk_reject_pr_swap), + + /* prs snk activity */ + PE_STATE_ACTIONS(pe_prs_snk_src_evaluate_pr_swap), + PE_STATE_ACTIONS(pe_prs_snk_src_accept_pr_swap), + PE_STATE_ACTIONS(pe_prs_snk_src_transition_to_off), + PE_STATE_ACTIONS(pe_prs_snk_src_assert_rp), + PE_STATE_ACTIONS(pe_prs_snk_src_source_on), + PE_STATE_ACTIONS(pe_prs_snk_src_send_swap), + PE_STATE_ACTIONS(pe_prs_snk_src_reject_swap), + + /* dr src activity */ + PE_STATE_ACTIONS(pe_dr_src_get_source_cap), + PE_STATE_ACTIONS(pe_dr_src_give_sink_cap), + + /* dr snk activity */ + PE_STATE_ACTIONS(pe_dr_snk_get_sink_cap), + PE_STATE_ACTIONS(pe_dr_snk_give_source_cap), + + /* vcs activity */ + PE_STATE_ACTIONS(pe_vcs_send_swap), + PE_STATE_ACTIONS(pe_vcs_evaluate_swap), + PE_STATE_ACTIONS(pe_vcs_accept_swap), + PE_STATE_ACTIONS(pe_vcs_reject_vconn_swap), + PE_STATE_ACTIONS(pe_vcs_wait_for_vconn), + PE_STATE_ACTIONS(pe_vcs_turn_off_vconn), + PE_STATE_ACTIONS(pe_vcs_turn_on_vconn), + PE_STATE_ACTIONS(pe_vcs_send_ps_rdy), + + /* ufp structured vdm activity */ + PE_STATE_ACTIONS(pe_ufp_vdm_get_identity), + PE_STATE_ACTIONS(pe_ufp_vdm_send_identity), + PE_STATE_ACTIONS(pe_ufp_vdm_get_identity_nak), + + PE_STATE_ACTIONS(pe_ufp_vdm_get_svids), + PE_STATE_ACTIONS(pe_ufp_vdm_send_svids), + PE_STATE_ACTIONS(pe_ufp_vdm_get_svids_nak), + + PE_STATE_ACTIONS(pe_ufp_vdm_get_modes), + PE_STATE_ACTIONS(pe_ufp_vdm_send_modes), + PE_STATE_ACTIONS(pe_ufp_vdm_get_modes_nak), + + PE_STATE_ACTIONS(pe_ufp_vdm_evaluate_mode_entry), + PE_STATE_ACTIONS(pe_ufp_vdm_mode_entry_ack), + PE_STATE_ACTIONS(pe_ufp_vdm_mode_entry_nak), + + PE_STATE_ACTIONS(pe_ufp_vdm_mode_exit), + PE_STATE_ACTIONS(pe_ufp_vdm_mode_exit_ack), + PE_STATE_ACTIONS(pe_ufp_vdm_mode_exit_nak), + + PE_STATE_ACTIONS(pe_ufp_vdm_attention_request), + + /* dfp structured vdm */ + PE_STATE_ACTIONS(pe_dfp_ufp_vdm_identity_request), + PE_STATE_ACTIONS(pe_dfp_ufp_vdm_identity_acked), + PE_STATE_ACTIONS(pe_dfp_ufp_vdm_identity_naked), + + PE_STATE_ACTIONS(pe_dfp_cbl_vdm_identity_request), + PE_STATE_ACTIONS(pe_dfp_cbl_vdm_identity_acked), + PE_STATE_ACTIONS(pe_dfp_cbl_vdm_identity_naked), + + PE_STATE_ACTIONS(pe_dfp_vdm_svids_request), + PE_STATE_ACTIONS(pe_dfp_vdm_svids_acked), + PE_STATE_ACTIONS(pe_dfp_vdm_svids_naked), + + PE_STATE_ACTIONS(pe_dfp_vdm_modes_request), + PE_STATE_ACTIONS(pe_dfp_vdm_modes_acked), + PE_STATE_ACTIONS(pe_dfp_vdm_modes_naked), + + PE_STATE_ACTIONS(pe_dfp_vdm_mode_entry_request), + PE_STATE_ACTIONS(pe_dfp_vdm_mode_entry_acked), + PE_STATE_ACTIONS(pe_dfp_vdm_mode_entry_naked), + + PE_STATE_ACTIONS(pe_dfp_vdm_mode_exit_request), + PE_STATE_ACTIONS(pe_dfp_vdm_mode_exit_acked), + + PE_STATE_ACTIONS(pe_dfp_vdm_attention_request), + + /* general activity */ +#ifdef CONFIG_USB_PD_CUSTOM_DBGACC + PE_STATE_ACTIONS(pe_dbg_ready), +#endif /* CONFIG_USB_PD_CUSTOM_DBGACC */ + PE_STATE_ACTIONS(pe_error_recovery), + + PE_STATE_ACTIONS(pe_bist_test_data), + PE_STATE_ACTIONS(pe_bist_carrier_mode_2), + + PE_STATE_ACTIONS(pe_idle1), + PE_STATE_ACTIONS(pe_idle2), +}; + +static void pe_exit_action_disable_sender_response( + pd_port_t *pd_port, pd_event_t *pd_event) +{ + pd_disable_timer(pd_port, PD_TIMER_SENDER_RESPONSE); +} + +pe_state_action_fcn_t pe_get_exit_action(uint8_t pe_state) +{ + pe_state_action_fcn_t retval = NULL; + + switch (pe_state) { + /* Source */ + case PE_SRC_SEND_CAPABILITIES: + retval = pe_src_send_capabilities_exit; + break; + case PE_SRC_TRANSITION_SUPPLY: + retval = pe_src_transition_supply_exit; + break; + case PE_SRC_TRANSITION_TO_DEFAULT: + retval = pe_src_transition_to_default_exit; + break; + case PE_SRC_GET_SINK_CAP: + retval = pe_src_get_sink_cap_exit; + break; + + /* Sink */ + case PE_SNK_WAIT_FOR_CAPABILITIES: + retval = pe_snk_wait_for_capabilities_exit; + break; + case PE_SNK_SELECT_CAPABILITY: + retval = pe_snk_select_capability_exit; + break; + case PE_SNK_TRANSITION_SINK: + retval = pe_snk_transition_sink_exit; + break; + case PE_SNK_TRANSITION_TO_DEFAULT: + retval = pe_snk_transition_to_default_exit; + break; + + case PE_DR_SRC_GET_SOURCE_CAP: + retval = pe_dr_src_get_source_cap_exit; + break; + case PE_DR_SNK_GET_SINK_CAP: + retval = pe_dr_snk_get_sink_cap_exit; + break; + + case PE_BIST_TEST_DATA: + retval = pe_bist_test_data_exit; + break; + + case PE_BIST_CARRIER_MODE_2: + retval = pe_bist_carrier_mode_2_exit; + break; + + case PE_VCS_SEND_SWAP: + case PE_PRS_SRC_SNK_SEND_SWAP: + case PE_PRS_SNK_SRC_SEND_SWAP: + case PE_DRS_DFP_UFP_SEND_DR_SWAP: + case PE_DRS_UFP_DFP_SEND_DR_SWAP: + retval = pe_exit_action_disable_sender_response; + break; + + case PE_PRS_SRC_SNK_WAIT_SOURCE_ON: + retval = pe_prs_src_snk_wait_source_on_exit; + break; + + case PE_PRS_SNK_SRC_SOURCE_ON: + retval = pe_prs_snk_src_source_on_exit; + break; + + case PE_PRS_SNK_SRC_TRANSITION_TO_OFF: + retval = pe_prs_snk_src_transition_to_off_exit; + break; + + case PE_VCS_WAIT_FOR_VCONN: + retval = pe_vcs_wait_for_vconn_exit; + break; + } + + return retval; +} + +static void pd_pe_state_change( + pd_port_t *pd_port, pd_event_t *pd_event, bool vdm_evt) +{ + pe_state_action_fcn_t prev_exit_action; + pe_state_action_fcn_t next_entry_action; + + u8 old_state = pd_port->pe_state_curr; + u8 new_state = pd_port->pe_state_next; + char buf[1024] = { 0 }; + + if ((old_state >= PD_NR_PE_STATES) || (new_state >= PD_NR_PE_STATES)) + snprintf(buf, sizeof(buf), "the pd nr pe states\n"); + if ((new_state == PE_IDLE1) || (new_state == PE_IDLE2)) + prev_exit_action = NULL; + else + prev_exit_action = pe_get_exit_action(old_state); + + next_entry_action = pe_state_actions[new_state].entry_action; + + /* + * Source (P, Provider), Sink (C, Consumer) + * DFP (D), UFP (U) + * Vconn Source (Y/N) + */ + +#if PE_DBG_ENABLE + PE_DBG("%s -> %s (%c%c%c)\r\n", + vdm_evt ? "VDM" : "PD", pe_state_name[new_state], + pd_port->power_role ? 'P' : 'C', + pd_port->data_role ? 'D' : 'U', + pd_port->vconn_source ? 'Y' : 'N'); +#else + if (!vdm_evt) { + PE_STATE_INFO("%s-> %s\r\n", + vdm_evt ? "VDM" : "PD", pe_state_name[new_state]); + } +#endif + + if (prev_exit_action) + prev_exit_action(pd_port, pd_event); + + if (next_entry_action) + next_entry_action(pd_port, pd_event); + + if (vdm_evt) + pd_port->pe_vdm_state = new_state; + else + pd_port->pe_pd_state = new_state; +} + +static int pd_handle_event( + pd_port_t *pd_port, pd_event_t *pd_event, bool vdm_evt) +{ + if (vdm_evt) { + if (pd_port->reset_vdm_state) { + pd_port->reset_vdm_state = false; + pd_port->pe_vdm_state = pd_port->pe_pd_state; + } + + pd_port->pe_state_curr = pd_port->pe_vdm_state; + } else { + pd_port->pe_state_curr = pd_port->pe_pd_state; + } + + if (pd_process_event(pd_port, pd_event, vdm_evt)) + pd_pe_state_change(pd_port, pd_event, vdm_evt); + else + pd_free_pd_event(pd_port, pd_event); + + return 1; +} + +static inline int pd_put_dpm_ack_immediately( + pd_port_t *pd_port, bool vdm_evt) +{ + pd_event_t pd_event = { + .event_type = PD_EVT_DPM_MSG, + .msg = PD_DPM_ACK, + .pd_msg = NULL, + }; + + pd_handle_event(pd_port, &pd_event, vdm_evt); + + PE_DBG("ACK_Immediately\r\n"); + pd_port->dpm_ack_immediately = false; + return 1; +} + +int pd_policy_engine_run(struct tcpc_device *tcpc_dev) +{ + bool vdm_evt = false; + pd_event_t pd_event; + pd_port_t *pd_port = &tcpc_dev->pd_port; + + if (!pd_get_event(tcpc_dev, &pd_event)) { + switch (pd_port->pe_pd_state) { + case PE_SNK_READY: + case PE_SRC_READY: + case PE_SRC_STARTUP: + case PE_SRC_DISCOVERY: + vdm_evt = pd_get_vdm_event(tcpc_dev, &pd_event); + break; + } + + if (!vdm_evt) + return 0; + } + mutex_lock(&pd_port->pd_lock); + + pd_handle_event(pd_port, &pd_event, vdm_evt); + + if (pd_port->dpm_ack_immediately) + pd_put_dpm_ack_immediately(pd_port, vdm_evt); + + mutex_unlock(&pd_port->pd_lock); + + return 1; +} |