diff --git a/workspace/TS100/Core/BSP/BSP.h b/workspace/TS100/Core/BSP/BSP.h index 8c8ce624..2cc0f522 100644 --- a/workspace/TS100/Core/BSP/BSP.h +++ b/workspace/TS100/Core/BSP/BSP.h @@ -51,6 +51,8 @@ uint8_t showBootLogoIfavailable(); void delay_ms(uint16_t count); //Used to allow knowledge of if usb_pd is being used uint8_t usb_pd_detect(); +//Returns 0 when the irq line is pulled down +uint8_t pd_irq_read(); #ifdef __cplusplus } #endif diff --git a/workspace/TS100/Core/BSP/Miniware/Pins.h b/workspace/TS100/Core/BSP/Miniware/Pins.h index ea30222f..ff6586b6 100644 --- a/workspace/TS100/Core/BSP/Miniware/Pins.h +++ b/workspace/TS100/Core/BSP/Miniware/Pins.h @@ -81,6 +81,8 @@ #define SCL2_GPIO_Port GPIOA #define SDA2_Pin GPIO_PIN_1 #define SDA2_GPIO_Port GPIOA +#define INT_PD_Pin GPIO_PIN_9 +#define INT_PD_GPIO_Port GPIOA #endif diff --git a/workspace/TS100/Core/BSP/Miniware/Power.cpp b/workspace/TS100/Core/BSP/Miniware/Power.cpp index cd552479..4421151e 100644 --- a/workspace/TS100/Core/BSP/Miniware/Power.cpp +++ b/workspace/TS100/Core/BSP/Miniware/Power.cpp @@ -2,7 +2,8 @@ #include "BSP_Power.h" #include "QC3.h" #include "Settings.h" -#include "FUSB302.h" +#include "Pins.h" +#include "fusbpd.h" bool FUSB302_present = false; void power_probe() { // If TS80 probe for QC @@ -20,13 +21,6 @@ void power_probe() { void power_check() { #ifdef MODEL_TS80 QC_resync(); - if (FUSB302_present) { - pd_run_state_machine(); - if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_9) == GPIO_PIN_RESET) { - tcpc_alert(); - } - } - #endif } uint8_t usb_pd_detect() { @@ -44,3 +38,10 @@ uint8_t usb_pd_detect() { #endif return false; } +uint8_t pd_irq_read() { +#ifdef MODEL_TS80 + return HAL_GPIO_ReadPin(INT_PD_GPIO_Port, INT_PD_Pin) == GPIO_PIN_SET ? + 1 : 0; +#endif + return 0; +} diff --git a/workspace/TS100/Core/BSP/Miniware/postRTOS.cpp b/workspace/TS100/Core/BSP/Miniware/postRTOS.cpp index 7b596758..7255f201 100644 --- a/workspace/TS100/Core/BSP/Miniware/postRTOS.cpp +++ b/workspace/TS100/Core/BSP/Miniware/postRTOS.cpp @@ -8,14 +8,8 @@ #include "stdlib.h" #include "task.h" #include "I2C_Wrapper.hpp" -#include "USBC_TCPM/tcpm.h" + void postRToSInit() { // Any after RTos setup FRToSI2C::FRToSInit(); -#ifdef MODEL_TS80 - tcpm_init(); - osDelay(50); - pd_init(); - osDelay(50); -#endif } diff --git a/workspace/TS100/Core/BSP/Miniware/preRTOS.cpp b/workspace/TS100/Core/BSP/Miniware/preRTOS.cpp index 674a850c..2e81642a 100644 --- a/workspace/TS100/Core/BSP/Miniware/preRTOS.cpp +++ b/workspace/TS100/Core/BSP/Miniware/preRTOS.cpp @@ -10,6 +10,7 @@ #include "Setup.h" #include "Pins.h" #include "I2CBB.hpp" +#include "fusbpd.h" void preRToSInit() { /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ @@ -19,5 +20,9 @@ void preRToSInit() { HAL_Delay(50); HAL_GPIO_WritePin(OLED_RESET_GPIO_Port, OLED_RESET_Pin, GPIO_PIN_SET); HAL_Delay(50); +#ifdef MODEL_TS80 I2CBB::init(); + //Spawn all of the USB-C processors + fusb302_start_processing(); +#endif } diff --git a/workspace/TS100/Core/Drivers/FUSB302/FUSB302.cpp b/workspace/TS100/Core/Drivers/FUSB302/FUSB302.cpp deleted file mode 100644 index f4f657bb..00000000 --- a/workspace/TS100/Core/Drivers/FUSB302/FUSB302.cpp +++ /dev/null @@ -1,935 +0,0 @@ -/* - FUSB302.c - Library for interacting with the FUSB302B chip. - Copyright 2015 The Chromium OS Authors - Copyright 2017 Jason Cerundolo - Released under an MIT license. See LICENSE file. - */ - -#include "FUSB302.h" -#include "USBC_TCPM/usb_pd_tcpm.h" -#include "USBC_TCPM/tcpm.h" -#include "USBC_PD/usb_pd.h" -#include -#include "cmsis_os.h" -#include "I2C_Wrapper.hpp" -#define PACKET_IS_GOOD_CRC(head) (PD_HEADER_TYPE(head) == PD_CTRL_GOOD_CRC && \ - PD_HEADER_CNT(head) == 0) -const struct tcpc_config_t tcpc_config = { -fusb302_I2C_SLAVE_ADDR, &fusb302_tcpm_drv }; -static struct fusb302_chip_state { - int cc_polarity; - int vconn_enabled; - /* 1 = pulling up (DFP) 0 = pulling down (UFP) */ - int pulling_up; - int rx_enable; - uint8_t mdac_vnc; - uint8_t mdac_rd; -} state; - -/* - * Bring the FUSB302 out of reset after Hard Reset signaling. This will - * automatically flush both the Rx and Tx FIFOs. - */ -static void fusb302_pd_reset() { - - tcpc_write( TCPC_REG_RESET, TCPC_REG_RESET_PD_RESET); - -} - -/* - * Flush our Rx FIFO. To prevent packet framing issues, this function should - * only be called when Rx is disabled. - */ -static void fusb302_flush_rx_fifo() { - /* - * other bits in the register _should_ be 0 - * until the day we support other SOP* types... - * then we'll have to keep a shadow of what this register - * value should be so we don't clobber it here! - */ - - tcpc_write( TCPC_REG_CONTROL1, TCPC_REG_CONTROL1_RX_FLUSH); - -} - -static void fusb302_flush_tx_fifo() { - int reg; - - tcpc_read( TCPC_REG_CONTROL0, ®); - reg |= TCPC_REG_CONTROL0_TX_FLUSH; - tcpc_write( TCPC_REG_CONTROL0, reg); - -} - -static void fusb302_auto_goodcrc_enable(int enable) { - int reg; - - tcpc_read( TCPC_REG_SWITCHES1, ®); - - if (enable) - reg |= TCPC_REG_SWITCHES1_AUTO_GCRC; - else - reg &= ~TCPC_REG_SWITCHES1_AUTO_GCRC; - - tcpc_write( TCPC_REG_SWITCHES1, reg); - -} - -/* Convert BC LVL values (in FUSB302) to Type-C CC Voltage Status */ -static int convert_bc_lvl(int bc_lvl) { - /* assume OPEN unless one of the following conditions is true... */ - int ret = TYPEC_CC_VOLT_OPEN; - - if (state.pulling_up) { - if (bc_lvl == 0x00) - ret = TYPEC_CC_VOLT_RA; - else if (bc_lvl < 0x3) - ret = TYPEC_CC_VOLT_RD; - } else { - if (bc_lvl == 0x1) - ret = TYPEC_CC_VOLT_SNK_DEF; - else if (bc_lvl == 0x2) - ret = TYPEC_CC_VOLT_SNK_1_5; - else if (bc_lvl == 0x3) - ret = TYPEC_CC_VOLT_SNK_3_0; - } - - return ret; -} - -static int measure_cc_pin_source(int cc_measure) { - int switches0_reg; - int reg; - int cc_lvl; - - /* Read status register */ - tcpc_read( TCPC_REG_SWITCHES0, ®); - /* Save current value */ - switches0_reg = reg; - /* Clear pull-up register settings and measure bits */ - reg &= ~(TCPC_REG_SWITCHES0_MEAS_CC1 | TCPC_REG_SWITCHES0_MEAS_CC2); - /* Set desired pullup register bit */ - if (cc_measure == TCPC_REG_SWITCHES0_MEAS_CC1) - reg |= TCPC_REG_SWITCHES0_CC1_PU_EN; - else - reg |= TCPC_REG_SWITCHES0_CC2_PU_EN; - /* Set CC measure bit */ - reg |= cc_measure; - - /* Set measurement switch */ - tcpc_write( TCPC_REG_SWITCHES0, reg); - - /* Set MDAC for Open vs Rd/Ra comparison */ - tcpc_write( TCPC_REG_MEASURE, state.mdac_vnc); - - /* Wait on measurement */ - usleep(250); - - /* Read status register */ - tcpc_read( TCPC_REG_STATUS0, ®); - - /* Assume open */ - cc_lvl = TYPEC_CC_VOLT_OPEN; - - /* CC level is below the 'no connect' threshold (vOpen) */ - if ((reg & TCPC_REG_STATUS0_COMP) == 0) { - /* Set MDAC for Rd vs Ra comparison */ - tcpc_write( TCPC_REG_MEASURE, state.mdac_rd); - - /* Wait on measurement */ - usleep(250); - - /* Read status register */ - tcpc_read( TCPC_REG_STATUS0, ®); - - cc_lvl = - (reg & TCPC_REG_STATUS0_COMP) ? - TYPEC_CC_VOLT_RD : TYPEC_CC_VOLT_RA; - } - - /* Restore SWITCHES0 register to its value prior */ - tcpc_write( TCPC_REG_SWITCHES0, switches0_reg); - - return cc_lvl; -} - -/* Determine cc pin state for source when in manual detect mode */ -static void detect_cc_pin_source_manual(int *cc1_lvl, int *cc2_lvl) { - int cc1_measure = TCPC_REG_SWITCHES0_MEAS_CC1; - int cc2_measure = TCPC_REG_SWITCHES0_MEAS_CC2; - - if (state.vconn_enabled) { - /* If VCONN enabled, measure cc_pin that matches polarity */ - if (state.cc_polarity) - *cc2_lvl = measure_cc_pin_source(cc2_measure); - else - *cc1_lvl = measure_cc_pin_source(cc1_measure); - } else { - /* If VCONN not enabled, measure both cc1 and cc2 */ - *cc1_lvl = measure_cc_pin_source(cc1_measure); - *cc2_lvl = measure_cc_pin_source(cc2_measure); - } - -} - -/* Determine cc pin state for sink */ -static void detect_cc_pin_sink(int *cc1, int *cc2) { - int reg; - int orig_meas_cc1; - int orig_meas_cc2; - int bc_lvl_cc1; - int bc_lvl_cc2; - - /* - * Measure CC1 first. - */ - tcpc_read( TCPC_REG_SWITCHES0, ®); - - /* save original state to be returned to later... */ - if (reg & TCPC_REG_SWITCHES0_MEAS_CC1) - orig_meas_cc1 = 1; - else - orig_meas_cc1 = 0; - - if (reg & TCPC_REG_SWITCHES0_MEAS_CC2) - orig_meas_cc2 = 1; - else - orig_meas_cc2 = 0; - - /* Disable CC2 measurement switch, enable CC1 measurement switch */ - reg &= ~TCPC_REG_SWITCHES0_MEAS_CC2; - reg |= TCPC_REG_SWITCHES0_MEAS_CC1; - - tcpc_write( TCPC_REG_SWITCHES0, reg); - - /* CC1 is now being measured by FUSB302. */ - - /* Wait on measurement */ - usleep(250); - - tcpc_read( TCPC_REG_STATUS0, &bc_lvl_cc1); - - /* mask away unwanted bits */ - bc_lvl_cc1 &= (TCPC_REG_STATUS0_BC_LVL0 | TCPC_REG_STATUS0_BC_LVL1); - - /* - * Measure CC2 next. - */ - - tcpc_read( TCPC_REG_SWITCHES0, ®); - - /* Disable CC1 measurement switch, enable CC2 measurement switch */ - reg &= ~TCPC_REG_SWITCHES0_MEAS_CC1; - reg |= TCPC_REG_SWITCHES0_MEAS_CC2; - - tcpc_write( TCPC_REG_SWITCHES0, reg); - - /* CC2 is now being measured by FUSB302. */ - - /* Wait on measurement */ - usleep(250); - - tcpc_read( TCPC_REG_STATUS0, &bc_lvl_cc2); - - /* mask away unwanted bits */ - bc_lvl_cc2 &= (TCPC_REG_STATUS0_BC_LVL0 | TCPC_REG_STATUS0_BC_LVL1); - - *cc1 = convert_bc_lvl(bc_lvl_cc1); - *cc2 = convert_bc_lvl(bc_lvl_cc2); - - /* return MEAS_CC1/2 switches to original state */ - tcpc_read( TCPC_REG_SWITCHES0, ®); - if (orig_meas_cc1) - reg |= TCPC_REG_SWITCHES0_MEAS_CC1; - else - reg &= ~TCPC_REG_SWITCHES0_MEAS_CC1; - if (orig_meas_cc2) - reg |= TCPC_REG_SWITCHES0_MEAS_CC2; - else - reg &= ~TCPC_REG_SWITCHES0_MEAS_CC2; - - tcpc_write( TCPC_REG_SWITCHES0, reg); - -} - -/* Parse header bytes for the size of packet */ -static int get_num_bytes(uint16_t header) { - int rv; - - /* Grab the Number of Data Objects field.*/ - rv = PD_HEADER_CNT(header); - - /* Multiply by four to go from 32-bit words -> bytes */ - rv *= 4; - - /* Plus 2 for header */ - rv += 2; - - return rv; -} - -static int fusb302_send_message(uint16_t header, const uint32_t *data, - uint8_t *buf, int buf_pos) { - int rv; - int reg; - int len; - - len = get_num_bytes(header); - - /* - * packsym tells the TXFIFO that the next X bytes are payload, - * and should not be interpreted as special tokens. - * The 5 LSBs represent X, the number of bytes. - */ - reg = fusb302_TKN_PACKSYM; - reg |= (len & 0x1F); - - buf[buf_pos++] = reg; - - /* write in the header */ - reg = header; - buf[buf_pos++] = reg & 0xFF; - - reg >>= 8; - buf[buf_pos++] = reg & 0xFF; - - /* header is done, subtract from length to make this for-loop simpler */ - len -= 2; - - /* write data objects, if present */ - memcpy(&buf[buf_pos], data, len); - buf_pos += len; - - /* put in the CRC */ - buf[buf_pos++] = fusb302_TKN_JAMCRC; - - /* put in EOP */ - buf[buf_pos++] = fusb302_TKN_EOP; - - /* Turn transmitter off after sending message */ - buf[buf_pos++] = fusb302_TKN_TXOFF; - - /* Start transmission */ - reg = fusb302_TKN_TXON; - buf[buf_pos++] = fusb302_TKN_TXON; - - /* burst write for speed! */ - - rv = tcpc_xfer(buf, buf_pos, 0, 0, I2C_XFER_SINGLE); - - return rv; -} - -static int fusb302_tcpm_select_rp_value(int rp) { - int reg; - int rv; - uint8_t vnc, rd; - - rv = tcpc_read( TCPC_REG_CONTROL0, ®); - if (rv) - return rv; - - /* Set the current source for Rp value */ - reg &= ~TCPC_REG_CONTROL0_HOST_CUR_MASK; - switch (rp) { - case TYPEC_RP_1A5: - reg |= TCPC_REG_CONTROL0_HOST_CUR_1A5; - vnc = TCPC_REG_MEASURE_MDAC_MV(PD_SRC_1_5_VNC_MV); - rd = TCPC_REG_MEASURE_MDAC_MV(PD_SRC_1_5_RD_THRESH_MV); - break; - case TYPEC_RP_3A0: - reg |= TCPC_REG_CONTROL0_HOST_CUR_3A0; - vnc = TCPC_REG_MEASURE_MDAC_MV(PD_SRC_3_0_VNC_MV); - rd = TCPC_REG_MEASURE_MDAC_MV(PD_SRC_3_0_RD_THRESH_MV); - break; - case TYPEC_RP_USB: - default: - reg |= TCPC_REG_CONTROL0_HOST_CUR_USB; - vnc = TCPC_REG_MEASURE_MDAC_MV(PD_SRC_DEF_VNC_MV); - rd = TCPC_REG_MEASURE_MDAC_MV(PD_SRC_DEF_RD_THRESH_MV); - } - state.mdac_vnc = vnc; - state.mdac_rd = rd; - rv = tcpc_write( TCPC_REG_CONTROL0, reg); - - return rv; -} - -static int fusb302_tcpm_init() { - int reg; - - /* set default */ - state.cc_polarity = -1; - - /* set the voltage threshold for no connect detection (vOpen) */ - state.mdac_vnc = TCPC_REG_MEASURE_MDAC_MV(PD_SRC_DEF_VNC_MV); - /* set the voltage threshold for Rd vs Ra detection */ - state.mdac_rd = TCPC_REG_MEASURE_MDAC_MV(PD_SRC_DEF_RD_THRESH_MV); - - /* all other variables assumed to default to 0 */ - - /* Restore default settings */ - tcpc_write( TCPC_REG_RESET, TCPC_REG_RESET_SW_RESET); - - /* Turn on retries and set number of retries */ - tcpc_read( TCPC_REG_CONTROL3, ®); - reg |= TCPC_REG_CONTROL3_AUTO_RETRY; - reg |= (PD_RETRY_COUNT & 0x3) << - TCPC_REG_CONTROL3_N_RETRIES_POS; - tcpc_write( TCPC_REG_CONTROL3, reg); - - /* Create interrupt masks */ - reg = 0xFF; - /* CC level changes */ - reg &= ~TCPC_REG_MASK_BC_LVL; - /* collisions */ - reg &= ~TCPC_REG_MASK_COLLISION; - /* misc alert */ - reg &= ~TCPC_REG_MASK_ALERT; - /* packet received with correct CRC */ - reg &= ~TCPC_REG_MASK_CRC_CHK; - tcpc_write( TCPC_REG_MASK, reg); - - reg = 0xFF; - /* when all pd message retries fail... */ - reg &= ~TCPC_REG_MASKA_RETRYFAIL; - /* when fusb302 send a hard reset. */ - reg &= ~TCPC_REG_MASKA_HARDSENT; - /* when fusb302 receives GoodCRC ack for a pd message */ - reg &= ~TCPC_REG_MASKA_TX_SUCCESS; - /* when fusb302 receives a hard reset */ - reg &= ~TCPC_REG_MASKA_HARDRESET; - tcpc_write( TCPC_REG_MASKA, reg); - - reg = 0xFF; - /* when fusb302 sends GoodCRC to ack a pd message */ - reg &= ~TCPC_REG_MASKB_GCRCSENT; - tcpc_write( TCPC_REG_MASKB, reg); - - /* Interrupt Enable */ - tcpc_read( TCPC_REG_CONTROL0, ®); - reg &= ~TCPC_REG_CONTROL0_INT_MASK; - tcpc_write( TCPC_REG_CONTROL0, reg); - - /* Set VCONN switch defaults */ - tcpm_set_polarity(0); - tcpm_set_vconn(0); - - /* Turn on the power! */ - /* TODO: Reduce power consumption */ - tcpc_write( TCPC_REG_POWER, TCPC_REG_POWER_PWR_ALL); - - return 0; -} - -static int fusb302_tcpm_release() { - return EC_ERROR_UNIMPLEMENTED; -} - -static int fusb302_tcpm_get_cc(int *cc1, int *cc2) { - if (state.pulling_up) { - /* Source mode? */ - detect_cc_pin_source_manual(cc1, cc2); - } else { - /* Sink mode? */ - detect_cc_pin_sink(cc1, cc2); - } - - return 0; -} - -static int fusb302_tcpm_set_cc(int pull) { - int reg; - - /* NOTE: FUSB302 toggles a single pull-up between CC1 and CC2 */ - /* NOTE: FUSB302 Does not support Ra. */ - switch (pull) { - case TYPEC_CC_RP: - /* enable the pull-up we know to be necessary */ - tcpc_read( TCPC_REG_SWITCHES0, ®); - - reg &= ~(TCPC_REG_SWITCHES0_CC2_PU_EN | - TCPC_REG_SWITCHES0_CC1_PU_EN | - TCPC_REG_SWITCHES0_CC1_PD_EN | - TCPC_REG_SWITCHES0_CC2_PD_EN | - TCPC_REG_SWITCHES0_VCONN_CC1 | - TCPC_REG_SWITCHES0_VCONN_CC2); - - reg |= TCPC_REG_SWITCHES0_CC1_PU_EN | - TCPC_REG_SWITCHES0_CC2_PU_EN; - - if (state.vconn_enabled) - reg |= state.cc_polarity ? - TCPC_REG_SWITCHES0_VCONN_CC1 : - TCPC_REG_SWITCHES0_VCONN_CC2; - - tcpc_write( TCPC_REG_SWITCHES0, reg); - - state.pulling_up = 1; - break; - case TYPEC_CC_RD: - /* Enable UFP Mode */ - - /* turn off toggle */ - tcpc_read( TCPC_REG_CONTROL2, ®); - reg &= ~TCPC_REG_CONTROL2_TOGGLE; - tcpc_write( TCPC_REG_CONTROL2, reg); - - /* enable pull-downs, disable pullups */ - tcpc_read( TCPC_REG_SWITCHES0, ®); - - reg &= ~(TCPC_REG_SWITCHES0_CC2_PU_EN); - reg &= ~(TCPC_REG_SWITCHES0_CC1_PU_EN); - reg |= (TCPC_REG_SWITCHES0_CC1_PD_EN); - reg |= (TCPC_REG_SWITCHES0_CC2_PD_EN); - tcpc_write( TCPC_REG_SWITCHES0, reg); - - state.pulling_up = 0; - break; - case TYPEC_CC_OPEN: - /* Disable toggling */ - tcpc_read( TCPC_REG_CONTROL2, ®); - reg &= ~TCPC_REG_CONTROL2_TOGGLE; - tcpc_write( TCPC_REG_CONTROL2, reg); - - /* Ensure manual switches are opened */ - tcpc_read( TCPC_REG_SWITCHES0, ®); - reg &= ~TCPC_REG_SWITCHES0_CC1_PU_EN; - reg &= ~TCPC_REG_SWITCHES0_CC2_PU_EN; - reg &= ~TCPC_REG_SWITCHES0_CC1_PD_EN; - reg &= ~TCPC_REG_SWITCHES0_CC2_PD_EN; - tcpc_write( TCPC_REG_SWITCHES0, reg); - - state.pulling_up = 0; - break; - default: - /* Unsupported... */ - return EC_ERROR_UNIMPLEMENTED; - } - - return 0; -} - -static int fusb302_tcpm_set_polarity(int polarity) { - /* Port polarity : 0 => CC1 is CC line, 1 => CC2 is CC line */ - int reg; - - tcpc_read( TCPC_REG_SWITCHES0, ®); - - /* clear VCONN switch bits */ - reg &= ~TCPC_REG_SWITCHES0_VCONN_CC1; - reg &= ~TCPC_REG_SWITCHES0_VCONN_CC2; - - if (state.vconn_enabled) { - /* set VCONN switch to be non-CC line */ - if (polarity) - reg |= TCPC_REG_SWITCHES0_VCONN_CC1; - else - reg |= TCPC_REG_SWITCHES0_VCONN_CC2; - } - - /* clear meas_cc bits (RX line select) */ - reg &= ~TCPC_REG_SWITCHES0_MEAS_CC1; - reg &= ~TCPC_REG_SWITCHES0_MEAS_CC2; - - /* set rx polarity */ - if (polarity) - reg |= TCPC_REG_SWITCHES0_MEAS_CC2; - else - reg |= TCPC_REG_SWITCHES0_MEAS_CC1; - - tcpc_write( TCPC_REG_SWITCHES0, reg); - - tcpc_read( TCPC_REG_SWITCHES1, ®); - - /* clear tx_cc bits */ - reg &= ~TCPC_REG_SWITCHES1_TXCC1_EN; - reg &= ~TCPC_REG_SWITCHES1_TXCC2_EN; - - /* set tx polarity */ - if (polarity) - reg |= TCPC_REG_SWITCHES1_TXCC2_EN; - else - reg |= TCPC_REG_SWITCHES1_TXCC1_EN; - - tcpc_write( TCPC_REG_SWITCHES1, reg); - - /* Save the polarity for later */ - state.cc_polarity = polarity; - - return 0; -} - -static int fusb302_tcpm_set_vconn(int enable) { - /* - * FUSB302 does not have dedicated VCONN Enable switch. - * We'll get through this by disabling both of the - * VCONN - CC* switches to disable, and enabling the - * saved polarity when enabling. - * Therefore at startup, tcpm_set_polarity should be called first, - * or else live with the default put into tcpm_init. - */ - int reg; - - /* save enable state for later use */ - state.vconn_enabled = enable; - - if (enable) { - /* set to saved polarity */ - tcpm_set_polarity(state.cc_polarity); - } else { - - tcpc_read( TCPC_REG_SWITCHES0, ®); - - /* clear VCONN switch bits */ - reg &= ~TCPC_REG_SWITCHES0_VCONN_CC1; - reg &= ~TCPC_REG_SWITCHES0_VCONN_CC2; - - tcpc_write( TCPC_REG_SWITCHES0, reg); - - } - - return 0; -} - -static int fusb302_tcpm_set_msg_header(int power_role, int data_role) { - int reg; - - tcpc_read( TCPC_REG_SWITCHES1, ®); - - reg &= ~TCPC_REG_SWITCHES1_POWERROLE; - reg &= ~TCPC_REG_SWITCHES1_DATAROLE; - - if (power_role) - reg |= TCPC_REG_SWITCHES1_POWERROLE; - if (data_role) - reg |= TCPC_REG_SWITCHES1_DATAROLE; - - tcpc_write( TCPC_REG_SWITCHES1, reg); - - return 0; -} - -static int fusb302_tcpm_set_rx_enable(int enable) { - int reg; - - state.rx_enable = enable; - - /* Get current switch state */ - tcpc_read( TCPC_REG_SWITCHES0, ®); - - /* Clear CC1/CC2 measure bits */ - reg &= ~TCPC_REG_SWITCHES0_MEAS_CC1; - reg &= ~TCPC_REG_SWITCHES0_MEAS_CC2; - - if (enable) { - switch (state.cc_polarity) { - /* if CC polarity hasnt been determined, can't enable */ - case -1: - return EC_ERROR_UNKNOWN; - case 0: - reg |= TCPC_REG_SWITCHES0_MEAS_CC1; - break; - case 1: - reg |= TCPC_REG_SWITCHES0_MEAS_CC2; - break; - default: - /* "shouldn't get here" */ - return EC_ERROR_UNKNOWN; - } - tcpc_write( TCPC_REG_SWITCHES0, reg); - - /* Disable BC_LVL interrupt when enabling PD comm */ - if (!tcpc_read( TCPC_REG_MASK, ®)) - tcpc_write( TCPC_REG_MASK, reg | TCPC_REG_MASK_BC_LVL); - - /* flush rx fifo in case messages have been coming our way */ - fusb302_flush_rx_fifo(); - - } else { - tcpc_write( TCPC_REG_SWITCHES0, reg); - - /* Enable BC_LVL interrupt when disabling PD comm */ - if (!tcpc_read( TCPC_REG_MASK, ®)) - tcpc_write( TCPC_REG_MASK, reg & ~TCPC_REG_MASK_BC_LVL); - } - - fusb302_auto_goodcrc_enable(enable); - - return 0; -} - -/* Return true if our Rx FIFO is empty */ -static int fusb302_rx_fifo_is_empty() { - int reg, ret; - - ret = (!tcpc_read( TCPC_REG_STATUS1, ®)) - && (reg & TCPC_REG_STATUS1_RX_EMPTY); - - return ret; -} - -static int fusb302_tcpm_get_message(uint32_t *payload, int *head) { - /* - * This is the buffer that will get the burst-read data - * from the fusb302. - * - * It's re-used in a couple different spots, the worst of which - * is the PD packet (not header) and CRC. - * maximum size necessary = 28 + 4 = 32 - */ - uint8_t buf[32]; - int rv, len; - - /* If our FIFO is empty then we have no packet */ - if (fusb302_rx_fifo_is_empty()) - return EC_ERROR_UNKNOWN; - - /* Read until we have a non-GoodCRC packet or an empty FIFO */ - do { - buf[0] = TCPC_REG_FIFOS; - - /* - * PART 1 OF BURST READ: Write in register address. - * Issue a START, no STOP. - */ - rv = tcpc_xfer(buf, 1, 0, 0, I2C_XFER_START); - - /* - * PART 2 OF BURST READ: Read up to the header. - * Issue a repeated START, no STOP. - * only grab three bytes so we can get the header - * and determine how many more bytes we need to read. - * TODO: Check token to ensure valid packet. - */ - rv |= tcpc_xfer(0, 0, buf, 3, I2C_XFER_START); - - /* Grab the header */ - *head = (buf[1] & 0xFF); - *head |= ((buf[2] << 8) & 0xFF00); - - /* figure out packet length, subtract header bytes */ - len = get_num_bytes(*head) - 2; - - /* - * PART 3 OF BURST READ: Read everything else. - * No START, but do issue a STOP at the end. - * add 4 to len to read CRC out - */ - rv |= tcpc_xfer(0, 0, buf, len + 4, I2C_XFER_STOP); - - } while (!rv && PACKET_IS_GOOD_CRC(*head) && !fusb302_rx_fifo_is_empty()); - - if (!rv) { - /* Discard GoodCRC packets */ - if (PACKET_IS_GOOD_CRC(*head)) - rv = EC_ERROR_UNKNOWN; - else - memcpy(payload, buf, len); - } - - /* - * If our FIFO is non-empty then we may have a packet, we may get - * fewer interrupts than packets due to interrupt latency. - */ - //if (!fusb302_rx_fifo_is_empty(port)) - // task_set_event(PD_PORT_TO_TASK_ID(port), PD_EVENT_RX, 0); - return rv; -} - -static int fusb302_tcpm_transmit(enum tcpm_transmit_type type, uint16_t header, - const uint32_t *data) { - /* - * this is the buffer that will be burst-written into the fusb302 - * maximum size necessary = - * 1: FIFO register address - * 4: SOP* tokens - * 1: Token that signifies "next X bytes are not tokens" - * 30: 2 for header and up to 7*4 = 28 for rest of message - * 1: "Insert CRC" Token - * 1: EOP Token - * 1: "Turn transmitter off" token - * 1: "Star Transmission" Command - * - - * 40: 40 bytes worst-case - */ - uint8_t buf[40]; - int buf_pos = 0; - - int reg; - - /* Flush the TXFIFO */ - fusb302_flush_tx_fifo (); - - switch (type) { - case TCPC_TX_SOP: - - /* put register address first for of burst tcpc write */ - buf[buf_pos++] = TCPC_REG_FIFOS; - - /* Write the SOP Ordered Set into TX FIFO */ - buf[buf_pos++] = fusb302_TKN_SYNC1; - buf[buf_pos++] = fusb302_TKN_SYNC1; - buf[buf_pos++] = fusb302_TKN_SYNC1; - buf[buf_pos++] = fusb302_TKN_SYNC2; - - fusb302_send_message(header, data, buf, buf_pos); -// wait for the GoodCRC to come back before we let the rest -// of the code do stuff like change polarity and miss it -// delay_us(600); - osDelay(1); - break; - case TCPC_TX_HARD_RESET: - - /* Simply hit the SEND_HARD_RESET bit */ - tcpc_read( TCPC_REG_CONTROL3, ®); - reg |= TCPC_REG_CONTROL3_SEND_HARDRESET; - tcpc_write( TCPC_REG_CONTROL3, reg); - - break; - case TCPC_TX_BIST_MODE_2: - - /* Hit the BIST_MODE2 bit and start TX */ - tcpc_read( TCPC_REG_CONTROL1, ®); - reg |= TCPC_REG_CONTROL1_BIST_MODE2; - tcpc_write( TCPC_REG_CONTROL1, reg); - - tcpc_read( TCPC_REG_CONTROL0, ®); - reg |= TCPC_REG_CONTROL0_TX_START; - tcpc_write( TCPC_REG_CONTROL0, reg); - -//task_wait_event(PD_T_BIST_TRANSMIT); - - /* Clear BIST mode bit, TX_START is self-clearing */ - tcpc_read( TCPC_REG_CONTROL1, ®); - reg &= ~TCPC_REG_CONTROL1_BIST_MODE2; - tcpc_write( TCPC_REG_CONTROL1, reg); - - break; - default: - return EC_ERROR_UNIMPLEMENTED; - } - - return 0; -} - -#ifdef CONFIG_USB_PD_VBUS_DETECT_TCPC -static int fusb302_tcpm_get_vbus_level() -{ - int reg; - - /* Read status register */ - - tcpc_read( TCPC_REG_STATUS0, ®); - - return (reg & TCPC_REG_STATUS0_VBUSOK) ? 1 : 0; -} -#endif - -void fusb302_tcpc_alert() { - /* interrupt has been received */ - int interrupt; - int interrupta; - int interruptb; - - /* reading interrupt registers clears them */ - - tcpc_read( TCPC_REG_INTERRUPT, &interrupt); - tcpc_read( TCPC_REG_INTERRUPTA, &interrupta); - tcpc_read( TCPC_REG_INTERRUPTB, &interruptb); - - /* - * Ignore BC_LVL changes when transmitting / receiving PD, - * since CC level will constantly change. - */ - if (state.rx_enable) - interrupt &= ~TCPC_REG_INTERRUPT_BC_LVL; - - if (interrupt & TCPC_REG_INTERRUPT_BC_LVL) { - /* CC Status change */ -//task_set_event(PD_PORT_TO_TASK_ID(port), PD_EVENT_CC, 0); - } - - if (interrupt & TCPC_REG_INTERRUPT_COLLISION) { - /* packet sending collided */ - pd_transmit_complete(TCPC_TX_COMPLETE_FAILED); - } - - /* GoodCRC was received, our FIFO is now non-empty */ - if (interrupta & TCPC_REG_INTERRUPTA_TX_SUCCESS) { -//task_set_event(PD_PORT_TO_TASK_ID(port), -// PD_EVENT_RX, 0); - - pd_transmit_complete(TCPC_TX_COMPLETE_SUCCESS); - } - - if (interrupta & TCPC_REG_INTERRUPTA_RETRYFAIL) { - /* all retries have failed to get a GoodCRC */ - pd_transmit_complete(TCPC_TX_COMPLETE_FAILED); - } - - if (interrupta & TCPC_REG_INTERRUPTA_HARDSENT) { - /* hard reset has been sent */ - - /* bring FUSB302 out of reset */ - fusb302_pd_reset(); - - pd_transmit_complete(TCPC_TX_COMPLETE_SUCCESS); - } - - if (interrupta & TCPC_REG_INTERRUPTA_HARDRESET) { - /* hard reset has been received */ - - /* bring FUSB302 out of reset */ - fusb302_pd_reset(); - - pd_execute_hard_reset (); - -//task_wake(PD_PORT_TO_TASK_ID(port)); - } - - if (interruptb & TCPC_REG_INTERRUPTB_GCRCSENT) { - /* Packet received and GoodCRC sent */ - /* (this interrupt fires after the GoodCRC finishes) */ - if (state.rx_enable) { - //task_set_event(PD_PORT_TO_TASK_ID(port), - // PD_EVENT_RX, 0); - } else { - /* flush rx fifo if rx isn't enabled */ - fusb302_flush_rx_fifo(); - } - } -} - -/* For BIST receiving */ -void tcpm_set_bist_test_data() { - int reg; - - /* Read control3 register */ - tcpc_read( TCPC_REG_CONTROL3, ®); - - /* Set the BIST_TMODE bit (Clears on Hard Reset) */ - reg |= TCPC_REG_CONTROL3_BIST_TMODE; - - /* Write the updated value */ - tcpc_write( TCPC_REG_CONTROL3, reg); - -} - -const struct tcpm_drv fusb302_tcpm_drv = { &fusb302_tcpm_init, //init - &fusb302_tcpm_release, //.release - &fusb302_tcpm_get_cc, //get_cc - NULL, //get_vbus_level - &fusb302_tcpm_select_rp_value, //select_rp_value - &fusb302_tcpm_set_cc, //set_cc - &fusb302_tcpm_set_polarity, //set_polarity - &fusb302_tcpm_set_vconn, //set_vconn - &fusb302_tcpm_set_msg_header, //set_msg_header - &fusb302_tcpm_set_rx_enable, //set_rx_enable - &fusb302_tcpm_get_message, //get_message - &fusb302_tcpm_transmit, //transmit - &fusb302_tcpc_alert, //tcpc_alert - NULL, //tcpc_discharge_vbus - NULL, //get_chip_info - }; - diff --git a/workspace/TS100/Core/Drivers/FUSB302/FUSB302.h b/workspace/TS100/Core/Drivers/FUSB302/FUSB302.h deleted file mode 100644 index 5a0455aa..00000000 --- a/workspace/TS100/Core/Drivers/FUSB302/FUSB302.h +++ /dev/null @@ -1,217 +0,0 @@ -/* - FUSB302.h - Library for interacting with the FUSB302B chip. - Copyright 2010 The Chromium OS Authors - Copyright 2017 Jason Cerundolo - Released under an MIT license. See LICENSE file. -*/ - -#ifndef fusb302_H -#define fusb302_H - -#include -#include "USBC_TCPM/usb_pd_tcpm.h" -#include "USBC_PD/usb_pd.h" - -/* Chip Device ID - 302A or 302B */ -#define fusb302_DEVID_302A 0x08 -#define fusb302_DEVID_302B 0x09 - -/* I2C slave address varies by part number */ -/* FUSB302BUCX / FUSB302BMPX */ -#define fusb302_I2C_SLAVE_ADDR 0x22<<1 // 7-bit address -/* FUSB302B01MPX */ -#define fusb302_I2C_SLAVE_ADDR_B01 0x23<<1 -/* FUSB302B10MPX */ -#define fusb302_I2C_SLAVE_ADDR_B10 0x24<<1 -/* FUSB302B11MPX */ -#define fusb302_I2C_SLAVE_ADDR_B11 0x25<<1 - -/* Default retry count for transmitting */ -#define PD_RETRY_COUNT 3 - -/* Time to wait for TCPC to complete transmit */ -#define PD_T_TCPC_TX_TIMEOUT (100*MSEC) - -#define TCPC_REG_DEVICE_ID 0x01 - -#define TCPC_REG_SWITCHES0 0x02 -#define TCPC_REG_SWITCHES0_CC2_PU_EN (1<<7) -#define TCPC_REG_SWITCHES0_CC1_PU_EN (1<<6) -#define TCPC_REG_SWITCHES0_VCONN_CC2 (1<<5) -#define TCPC_REG_SWITCHES0_VCONN_CC1 (1<<4) -#define TCPC_REG_SWITCHES0_MEAS_CC2 (1<<3) -#define TCPC_REG_SWITCHES0_MEAS_CC1 (1<<2) -#define TCPC_REG_SWITCHES0_CC2_PD_EN (1<<1) -#define TCPC_REG_SWITCHES0_CC1_PD_EN (1<<0) - -#define TCPC_REG_SWITCHES1 0x03 -#define TCPC_REG_SWITCHES1_POWERROLE (1<<7) -#define TCPC_REG_SWITCHES1_SPECREV1 (1<<6) -#define TCPC_REG_SWITCHES1_SPECREV0 (1<<5) -#define TCPC_REG_SWITCHES1_DATAROLE (1<<4) -#define TCPC_REG_SWITCHES1_AUTO_GCRC (1<<2) -#define TCPC_REG_SWITCHES1_TXCC2_EN (1<<1) -#define TCPC_REG_SWITCHES1_TXCC1_EN (1<<0) - -#define TCPC_REG_MEASURE 0x04 -#define TCPC_REG_MEASURE_VBUS (1<<6) -#define TCPC_REG_MEASURE_MDAC_MV(mv) (((mv)/42) & 0x3f) - -#define TCPC_REG_CONTROL0 0x06 -#define TCPC_REG_CONTROL0_TX_FLUSH (1<<6) -#define TCPC_REG_CONTROL0_INT_MASK (1<<5) -#define TCPC_REG_CONTROL0_HOST_CUR_MASK (3<<2) -#define TCPC_REG_CONTROL0_HOST_CUR_3A0 (3<<2) -#define TCPC_REG_CONTROL0_HOST_CUR_1A5 (2<<2) -#define TCPC_REG_CONTROL0_HOST_CUR_USB (1<<2) -#define TCPC_REG_CONTROL0_TX_START (1<<0) - -#define TCPC_REG_CONTROL1 0x07 -#define TCPC_REG_CONTROL1_ENSOP2DB (1<<6) -#define TCPC_REG_CONTROL1_ENSOP1DB (1<<5) -#define TCPC_REG_CONTROL1_BIST_MODE2 (1<<4) -#define TCPC_REG_CONTROL1_RX_FLUSH (1<<2) -#define TCPC_REG_CONTROL1_ENSOP2 (1<<1) -#define TCPC_REG_CONTROL1_ENSOP1 (1<<0) - -#define TCPC_REG_CONTROL2 0x08 -/* two-bit field, valid values below */ -#define TCPC_REG_CONTROL2_MODE (1<<1) -#define TCPC_REG_CONTROL2_MODE_DFP (0x3) -#define TCPC_REG_CONTROL2_MODE_UFP (0x2) -#define TCPC_REG_CONTROL2_MODE_DRP (0x1) -#define TCPC_REG_CONTROL2_MODE_POS (1) -#define TCPC_REG_CONTROL2_TOGGLE (1<<0) - -#define TCPC_REG_CONTROL3 0x09 -#define TCPC_REG_CONTROL3_SEND_HARDRESET (1<<6) -#define TCPC_REG_CONTROL3_BIST_TMODE (1<<5) /* 302B Only */ -#define TCPC_REG_CONTROL3_AUTO_HARDRESET (1<<4) -#define TCPC_REG_CONTROL3_AUTO_SOFTRESET (1<<3) -/* two-bit field */ -#define TCPC_REG_CONTROL3_N_RETRIES (1<<1) -#define TCPC_REG_CONTROL3_N_RETRIES_POS (1) -#define TCPC_REG_CONTROL3_N_RETRIES_SIZE (2) -#define TCPC_REG_CONTROL3_AUTO_RETRY (1<<0) - -#define TCPC_REG_MASK 0x0A -#define TCPC_REG_MASK_VBUSOK (1<<7) -#define TCPC_REG_MASK_ACTIVITY (1<<6) -#define TCPC_REG_MASK_COMP_CHNG (1<<5) -#define TCPC_REG_MASK_CRC_CHK (1<<4) -#define TCPC_REG_MASK_ALERT (1<<3) -#define TCPC_REG_MASK_WAKE (1<<2) -#define TCPC_REG_MASK_COLLISION (1<<1) -#define TCPC_REG_MASK_BC_LVL (1<<0) - -#define TCPC_REG_POWER 0x0B -#define TCPC_REG_POWER_PWR (1<<0) /* four-bit field */ -#define TCPC_REG_POWER_PWR_LOW 0x1 /* Bandgap + Wake circuitry */ -#define TCPC_REG_POWER_PWR_MEDIUM 0x3 /* LOW + Receiver + Current refs */ -#define TCPC_REG_POWER_PWR_HIGH 0x7 /* MEDIUM + Measure block */ -#define TCPC_REG_POWER_PWR_ALL 0xF /* HIGH + Internal Oscillator */ - -#define TCPC_REG_RESET 0x0C -#define TCPC_REG_RESET_PD_RESET (1<<1) -#define TCPC_REG_RESET_SW_RESET (1<<0) - -#define TCPC_REG_MASKA 0x0E -#define TCPC_REG_MASKA_OCP_TEMP (1<<7) -#define TCPC_REG_MASKA_TOGDONE (1<<6) -#define TCPC_REG_MASKA_SOFTFAIL (1<<5) -#define TCPC_REG_MASKA_RETRYFAIL (1<<4) -#define TCPC_REG_MASKA_HARDSENT (1<<3) -#define TCPC_REG_MASKA_TX_SUCCESS (1<<2) -#define TCPC_REG_MASKA_SOFTRESET (1<<1) -#define TCPC_REG_MASKA_HARDRESET (1<<0) - -#define TCPC_REG_MASKB 0x0F -#define TCPC_REG_MASKB_GCRCSENT (1<<0) - -#define TCPC_REG_STATUS0A 0x3C -#define TCPC_REG_STATUS0A_SOFTFAIL (1<<5) -#define TCPC_REG_STATUS0A_RETRYFAIL (1<<4) -#define TCPC_REG_STATUS0A_POWER (1<<2) /* two-bit field */ -#define TCPC_REG_STATUS0A_RX_SOFT_RESET (1<<1) -#define TCPC_REG_STATUS0A_RX_HARD_RESET (1<<0) - -#define TCPC_REG_STATUS1A 0x3D -/* three-bit field, valid values below */ -#define TCPC_REG_STATUS1A_TOGSS (1<<3) -#define TCPC_REG_STATUS1A_TOGSS_RUNNING 0x0 -#define TCPC_REG_STATUS1A_TOGSS_SRC1 0x1 -#define TCPC_REG_STATUS1A_TOGSS_SRC2 0x2 -#define TCPC_REG_STATUS1A_TOGSS_SNK1 0x5 -#define TCPC_REG_STATUS1A_TOGSS_SNK2 0x6 -#define TCPC_REG_STATUS1A_TOGSS_AA 0x7 -#define TCPC_REG_STATUS1A_TOGSS_POS (3) -#define TCPC_REG_STATUS1A_TOGSS_MASK (0x7) - -#define TCPC_REG_STATUS1A_RXSOP2DB (1<<2) -#define TCPC_REG_STATUS1A_RXSOP1DB (1<<1) -#define TCPC_REG_STATUS1A_RXSOP (1<<0) - -#define TCPC_REG_INTERRUPTA 0x3E -#define TCPC_REG_INTERRUPTA_OCP_TEMP (1<<7) -#define TCPC_REG_INTERRUPTA_TOGDONE (1<<6) -#define TCPC_REG_INTERRUPTA_SOFTFAIL (1<<5) -#define TCPC_REG_INTERRUPTA_RETRYFAIL (1<<4) -#define TCPC_REG_INTERRUPTA_HARDSENT (1<<3) -#define TCPC_REG_INTERRUPTA_TX_SUCCESS (1<<2) -#define TCPC_REG_INTERRUPTA_SOFTRESET (1<<1) -#define TCPC_REG_INTERRUPTA_HARDRESET (1<<0) - -#define TCPC_REG_INTERRUPTB 0x3F -#define TCPC_REG_INTERRUPTB_GCRCSENT (1<<0) - -#define TCPC_REG_STATUS0 0x40 -#define TCPC_REG_STATUS0_VBUSOK (1<<7) -#define TCPC_REG_STATUS0_ACTIVITY (1<<6) -#define TCPC_REG_STATUS0_COMP (1<<5) -#define TCPC_REG_STATUS0_CRC_CHK (1<<4) -#define TCPC_REG_STATUS0_ALERT (1<<3) -#define TCPC_REG_STATUS0_WAKE (1<<2) -#define TCPC_REG_STATUS0_BC_LVL1 (1<<1) /* two-bit field */ -#define TCPC_REG_STATUS0_BC_LVL0 (1<<0) /* two-bit field */ - -#define TCPC_REG_STATUS1 0x41 -#define TCPC_REG_STATUS1_RXSOP2 (1<<7) -#define TCPC_REG_STATUS1_RXSOP1 (1<<6) -#define TCPC_REG_STATUS1_RX_EMPTY (1<<5) -#define TCPC_REG_STATUS1_RX_FULL (1<<4) -#define TCPC_REG_STATUS1_TX_EMPTY (1<<3) -#define TCPC_REG_STATUS1_TX_FULL (1<<2) - -#define TCPC_REG_INTERRUPT 0x42 -#define TCPC_REG_INTERRUPT_VBUSOK (1<<7) -#define TCPC_REG_INTERRUPT_ACTIVITY (1<<6) -#define TCPC_REG_INTERRUPT_COMP_CHNG (1<<5) -#define TCPC_REG_INTERRUPT_CRC_CHK (1<<4) -#define TCPC_REG_INTERRUPT_ALERT (1<<3) -#define TCPC_REG_INTERRUPT_WAKE (1<<2) -#define TCPC_REG_INTERRUPT_COLLISION (1<<1) -#define TCPC_REG_INTERRUPT_BC_LVL (1<<0) - -#define TCPC_REG_FIFOS 0x43 - -/* Tokens defined for the FUSB302 TX FIFO */ -enum fusb302_txfifo_tokens { - fusb302_TKN_TXON = 0xA1, - fusb302_TKN_SYNC1 = 0x12, - fusb302_TKN_SYNC2 = 0x13, - fusb302_TKN_SYNC3 = 0x1B, - fusb302_TKN_RST1 = 0x15, - fusb302_TKN_RST2 = 0x16, - fusb302_TKN_PACKSYM = 0x80, - fusb302_TKN_JAMCRC = 0xFF, - fusb302_TKN_EOP = 0x14, - fusb302_TKN_TXOFF = 0xFE, -}; - -extern const struct tcpm_drv fusb302_tcpm_drv; - -//returns 1 if the FUSB302 is on the I2C bus -uint8_t fusb302_detect(); - -#endif /* fusb302_H */ - diff --git a/workspace/TS100/Core/Drivers/FUSB302/USBC_PD/usb_pd.h b/workspace/TS100/Core/Drivers/FUSB302/USBC_PD/usb_pd.h deleted file mode 100644 index e863e5ff..00000000 --- a/workspace/TS100/Core/Drivers/FUSB302/USBC_PD/usb_pd.h +++ /dev/null @@ -1,1797 +0,0 @@ -/* Copyright (c) 2014 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -/* USB Power delivery module */ - -#ifndef __USB_PD_H -#define __USB_PD_H - -#include "tcpm_driver.h" -#include "usb_pd_driver.h" - -/* Time units in microseconds */ -#define MSEC (1000) -#define SECOND (1000000) -#define MINUTE (60000000) -#define HOUR (3600000000ull) /* Too big to fit in a signed int */ - -/* PD Host command timeout */ -#define PD_HOST_COMMAND_TIMEOUT_US SECOND - -#ifdef CONFIG_USB_PD_PORT_COUNT -/* - * Define PD_PORT_TO_TASK_ID() and TASK_ID_TO_PD_PORT() macros to - * go between PD port number and task ID. Assume that TASK_ID_PD_C0 is the - * lowest task ID and IDs are on a continuous range. - */ -#ifdef HAS_TASK_PD_C0 -#define PD_PORT_TO_TASK_ID(port) (TASK_ID_PD_C0 + (port)) -#define TASK_ID_TO_PD_PORT(id) ((id) - TASK_ID_PD_C0) -#else -#define PD_PORT_TO_TASK_ID(port) -1 /* dummy task ID */ -#define TASK_ID_TO_PD_PORT(id) 0 -#endif /* CONFIG_COMMON_RUNTIME */ -#endif /* CONFIG_USB_PD_PORT_COUNT */ - -enum pd_rx_errors { - PD_RX_ERR_INVAL = -1, /* Invalid packet */ - PD_RX_ERR_HARD_RESET = -2, /* Got a Hard-Reset packet */ - PD_RX_ERR_CRC = -3, /* CRC mismatch */ - PD_RX_ERR_ID = -4, /* Invalid ID number */ - PD_RX_ERR_UNSUPPORTED_SOP = -5, /* Unsupported SOP */ - PD_RX_ERR_CABLE_RESET = -6 /* Got a Cable-Reset packet */ -}; - -/* Events for USB PD task */ -#define PD_EVENT_RX (1<<2) /* Incoming packet event */ -#define PD_EVENT_TX (1<<3) /* Outgoing packet event */ -#define PD_EVENT_CC (1<<4) /* CC line change event */ -#define PD_EVENT_TCPC_RESET (1<<5) /* TCPC has reset */ -#define PD_EVENT_UPDATE_DUAL_ROLE (1<<6) /* DRP state has changed */ - -/* --- PD data message helpers --- */ -#define PDO_MAX_OBJECTS 7 -#define PDO_MODES (PDO_MAX_OBJECTS - 1) - -/* PDO : Power Data Object */ -/* - * 1. The vSafe5V Fixed Supply Object shall always be the first object. - * 2. The remaining Fixed Supply Objects, - * if present, shall be sent in voltage order; lowest to highest. - * 3. The Battery Supply Objects, - * if present shall be sent in Minimum Voltage order; lowest to highest. - * 4. The Variable Supply (non battery) Objects, - * if present, shall be sent in Minimum Voltage order; lowest to highest. - * 5. (PD3.0) The Augmented PDO is defined to allow extension beyond the 4 PDOs - * above by examining bits <29:28> to determine the additional PDO function. - */ -#define PDO_TYPE_FIXED (0 << 30) -#define PDO_TYPE_BATTERY (1 << 30) -#define PDO_TYPE_VARIABLE (2 << 30) -#define PDO_TYPE_AUGMENTED (3 << 30) -#define PDO_TYPE_MASK (3 << 30) - -#define PDO_FIXED_DUAL_ROLE (1 << 29) /* Dual role device */ -#define PDO_FIXED_SUSPEND (1 << 28) /* USB Suspend supported */ -#define PDO_FIXED_EXTERNAL (1 << 27) /* Externally powered */ -#define PDO_FIXED_COMM_CAP (1 << 26) /* USB Communications Capable */ -#define PDO_FIXED_DATA_SWAP (1 << 25) /* Data role swap command supported */ -#define PDO_FIXED_PEAK_CURR () /* [21..20] Peak current */ -#define PDO_FIXED_VOLT(mv) (((mv)/50) << 10) /* Voltage in 50mV units */ -#define PDO_FIXED_CURR(ma) (((ma)/10) << 0) /* Max current in 10mA units */ - -#define PDO_FIXED(mv, ma, flags) (PDO_FIXED_VOLT(mv) |\ - PDO_FIXED_CURR(ma) | (flags)) - -#define PDO_VAR_MAX_VOLT(mv) ((((mv) / 50) & 0x3FF) << 20) -#define PDO_VAR_MIN_VOLT(mv) ((((mv) / 50) & 0x3FF) << 10) -#define PDO_VAR_OP_CURR(ma) ((((ma) / 10) & 0x3FF) << 0) - -#define PDO_VAR(min_mv, max_mv, op_ma) \ - (PDO_VAR_MIN_VOLT(min_mv) | \ - PDO_VAR_MAX_VOLT(max_mv) | \ - PDO_VAR_OP_CURR(op_ma) | \ - PDO_TYPE_VARIABLE) - -#define PDO_BATT_MAX_VOLT(mv) ((((mv) / 50) & 0x3FF) << 20) -#define PDO_BATT_MIN_VOLT(mv) ((((mv) / 50) & 0x3FF) << 10) -#define PDO_BATT_OP_POWER(mw) ((((mw) / 250) & 0x3FF) << 0) - -#define PDO_BATT(min_mv, max_mv, op_mw) \ - (PDO_BATT_MIN_VOLT(min_mv) | \ - PDO_BATT_MAX_VOLT(max_mv) | \ - PDO_BATT_OP_POWER(op_mw) | \ - PDO_TYPE_BATTERY) - -/* RDO : Request Data Object */ -#define RDO_OBJ_POS(n) (((n) & 0x7) << 28) -#define RDO_POS(rdo) (((rdo) >> 28) & 0x7) -#define RDO_GIVE_BACK (1 << 27) -#define RDO_CAP_MISMATCH (1 << 26) -#define RDO_COMM_CAP (1 << 25) -#define RDO_NO_SUSPEND (1 << 24) -#define RDO_FIXED_VAR_OP_CURR(ma) ((((ma) / 10) & 0x3FF) << 10) -#define RDO_FIXED_VAR_MAX_CURR(ma) ((((ma) / 10) & 0x3FF) << 0) - -#define RDO_BATT_OP_POWER(mw) ((((mw) / 250) & 0x3FF) << 10) -#define RDO_BATT_MAX_POWER(mw) ((((mw) / 250) & 0x3FF) << 10) - -#define RDO_FIXED(n, op_ma, max_ma, flags) \ - (RDO_OBJ_POS(n) | (flags) | \ - RDO_FIXED_VAR_OP_CURR(op_ma) | \ - RDO_FIXED_VAR_MAX_CURR(max_ma)) - - -#define RDO_BATT(n, op_mw, max_mw, flags) \ - (RDO_OBJ_POS(n) | (flags) | \ - RDO_BATT_OP_POWER(op_mw) | \ - RDO_BATT_MAX_POWER(max_mw)) - -/* BDO : BIST Data Object */ -#define BDO_MODE_RECV (0 << 28) -#define BDO_MODE_TRANSMIT (1 << 28) -#define BDO_MODE_COUNTERS (2 << 28) -#define BDO_MODE_CARRIER0 (3 << 28) -#define BDO_MODE_CARRIER1 (4 << 28) -#define BDO_MODE_CARRIER2 (5 << 28) -#define BDO_MODE_CARRIER3 (6 << 28) -#define BDO_MODE_EYE (7 << 28) - -#define BDO(mode, cnt) ((mode) | ((cnt) & 0xFFFF)) - -#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 */ -#define PD_T_SOURCE_ACTIVITY (45*MSEC) /* between 40ms and 50ms */ -//#define PD_T_SENDER_RESPONSE (30*MSEC) /* between 24ms and 30ms */ -#define PD_T_SENDER_RESPONSE (100*MSEC) /* between 24ms and 30ms */ -#define PD_T_PS_TRANSITION (500*MSEC) /* between 450ms and 550ms */ -#define PD_T_PS_SOURCE_ON (480*MSEC) /* between 390ms and 480ms */ -#define PD_T_PS_SOURCE_OFF (920*MSEC) /* between 750ms and 920ms */ -#define PD_T_PS_HARD_RESET (25*MSEC) /* between 25ms and 35ms */ -#define PD_T_ERROR_RECOVERY (25*MSEC) /* 25ms */ -#define PD_T_CC_DEBOUNCE (100*MSEC) /* between 100ms and 200ms */ -/* DRP_SNK + DRP_SRC must be between 50ms and 100ms with 30%-70% duty cycle */ -#define PD_T_DRP_SNK (40*MSEC) /* toggle time for sink DRP */ -#define PD_T_DRP_SRC (30*MSEC) /* toggle time for source DRP */ -#define PD_T_DEBOUNCE (15*MSEC) /* between 10ms and 20ms */ -#define PD_T_SINK_ADJ (55*MSEC) /* between PD_T_DEBOUNCE and 60ms */ -#define PD_T_SRC_RECOVER (760*MSEC) /* between 660ms and 1000ms */ -#define PD_T_SRC_RECOVER_MAX (1000*MSEC) /* 1000ms */ -#define PD_T_SRC_TURN_ON (275*MSEC) /* 275ms */ -#define PD_T_SAFE_0V (650*MSEC) /* 650ms */ -#define PD_T_NO_RESPONSE (5500*MSEC) /* between 4.5s and 5.5s */ -#define PD_T_BIST_TRANSMIT (50*MSEC) /* 50ms (used for task_wait arg) */ -#define PD_T_BIST_RECEIVE (60*MSEC) /* 60ms (max time to process bist) */ -#define PD_T_VCONN_SOURCE_ON (100*MSEC) /* 100ms */ -#define PD_T_TRY_SRC (125*MSEC) /* Max time for Try.SRC state */ -#define PD_T_TRY_WAIT (600*MSEC) /* Max time for TryWait.SNK state */ -#define PD_T_SINK_REQUEST (100*MSEC) /* Wait 100ms before next request */ - -/* number of edges and time window to detect CC line is not idle */ -#define PD_RX_TRANSITION_COUNT 3 -#define PD_RX_TRANSITION_WINDOW 20 /* between 12us and 20us */ - -/* from USB Type-C Specification Table 5-1 */ -#define PD_T_AME (1*SECOND) /* timeout from UFP attach to Alt Mode Entry */ - -/* VDM Timers ( USB PD Spec Rev2.0 Table 6-30 )*/ -#define PD_T_VDM_BUSY (100*MSEC) /* at least 100ms */ -#define PD_T_VDM_E_MODE (25*MSEC) /* enter/exit the same max */ -#define PD_T_VDM_RCVR_RSP (15*MSEC) /* max of 15ms */ -#define PD_T_VDM_SNDR_RSP (30*MSEC) /* max of 30ms */ -#define PD_T_VDM_WAIT_MODE_E (100*MSEC) /* enter/exit the same max */ - -/* function table for entered mode */ -struct amode_fx { - int (*status)( uint32_t *payload); - int (*config)( uint32_t *payload); -}; - -/* function table for alternate mode capable responders */ -struct svdm_response { - int (*identity)( uint32_t *payload); - int (*svids)( uint32_t *payload); - int (*modes)( uint32_t *payload); - int (*enter_mode)( uint32_t *payload); - int (*exit_mode)( uint32_t *payload); - struct amode_fx *amode; -}; - -struct svdm_svid_data { - uint16_t svid; - int mode_cnt; - uint32_t mode_vdo[PDO_MODES]; -}; - -struct svdm_amode_fx { - uint16_t svid; - int (*enter)( uint32_t mode_caps); - int (*status)( uint32_t *payload); - int (*config)( uint32_t *payload); - void (*post_config)(); - int (*attention)( uint32_t *payload); - void (*exit)(); -}; - -/* defined in /usb_pd_policy.c */ -/* All UFP_U should have */ -extern const struct svdm_response svdm_rsp; -/* All DFP_U should have */ -extern const struct svdm_amode_fx supported_modes[]; -extern const int supported_modes_cnt; - -/* DFP data needed to support alternate mode entry and exit */ -struct svdm_amode_data { - const struct svdm_amode_fx *fx; - /* VDM object position */ - int opos; - /* mode capabilities specific to SVID amode. */ - struct svdm_svid_data *data; -}; - -enum hpd_event { - hpd_none, - hpd_low, - hpd_high, - hpd_irq, -}; - -/* DisplayPort flags */ -#define DP_FLAGS_DP_ON (1 << 0) /* Display port mode is on */ -#define DP_FLAGS_HPD_HI_PENDING (1 << 1) /* Pending HPD_HI */ - -/* supported alternate modes */ -enum pd_alternate_modes { - /* not a real mode */ - PD_AMODE_COUNT, -}; - -/* Policy structure for driving alternate mode */ -struct pd_policy { - /* index of svid currently being operated on */ - int svid_idx; - /* count of svids discovered */ - int svid_cnt; - /* SVDM identity info (Id, Cert Stat, 0-4 Typec specific) */ - uint32_t identity[PDO_MAX_OBJECTS - 1]; - /* supported svids & corresponding vdo mode data */ - struct svdm_svid_data svids[SVID_DISCOVERY_MAX]; - /* active modes */ - struct svdm_amode_data amodes[PD_AMODE_COUNT]; - /* Next index to insert DFP alternate mode into amodes */ - int amode_idx; -}; - -/* - * VDO : Vendor Defined Message Object - * 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 (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(vid, type, custom) \ - (((vid) << 16) | \ - ((type) << 15) | \ - ((custom) & 0x7FFF)) - -#define VDO_SVDM_TYPE (1 << 15) -#define VDO_SVDM_VERS(x) (x << 13) -#define VDO_OPOS(x) (x << 8) -#define VDO_CMDT(x) (x << 6) -#define VDO_OPOS_MASK VDO_OPOS(0x7) -#define VDO_CMDT_MASK VDO_CMDT(0x3) - -#define CMDT_INIT 0 -#define CMDT_RSP_ACK 1 -#define CMDT_RSP_NAK 2 -#define CMDT_RSP_BUSY 3 - - -/* reserved for SVDM ... for Google UVDM */ -#define VDO_SRC_INITIATOR (0 << 5) -#define VDO_SRC_RESPONDER (1 << 5) - -#define CMD_DISCOVER_IDENT 1 -#define CMD_DISCOVER_SVID 2 -#define CMD_DISCOVER_MODES 3 -#define CMD_ENTER_MODE 4 -#define CMD_EXIT_MODE 5 -#define CMD_ATTENTION 6 -#define CMD_DP_STATUS 16 -#define CMD_DP_CONFIG 17 - -#define VDO_CMD_VENDOR(x) (((10 + (x)) & 0x1f)) - -/* ChromeOS specific commands */ -#define VDO_CMD_VERSION VDO_CMD_VENDOR(0) -#define VDO_CMD_SEND_INFO VDO_CMD_VENDOR(1) -#define VDO_CMD_READ_INFO VDO_CMD_VENDOR(2) -#define VDO_CMD_REBOOT VDO_CMD_VENDOR(5) -#define VDO_CMD_FLASH_ERASE VDO_CMD_VENDOR(6) -#define VDO_CMD_FLASH_WRITE VDO_CMD_VENDOR(7) -#define VDO_CMD_ERASE_SIG VDO_CMD_VENDOR(8) -#define VDO_CMD_PING_ENABLE VDO_CMD_VENDOR(10) -#define VDO_CMD_CURRENT VDO_CMD_VENDOR(11) -#define VDO_CMD_FLIP VDO_CMD_VENDOR(12) -#define VDO_CMD_GET_LOG VDO_CMD_VENDOR(13) -#define VDO_CMD_CCD_EN VDO_CMD_VENDOR(14) - -#define PD_VDO_VID(vdo) ((vdo) >> 16) -#define PD_VDO_SVDM(vdo) (((vdo) >> 15) & 1) -#define PD_VDO_OPOS(vdo) (((vdo) >> 8) & 0x7) -#define PD_VDO_CMD(vdo) ((vdo) & 0x1f) -#define PD_VDO_CMDT(vdo) (((vdo) >> 6) & 0x3) - -/* - * SVDM Identity request -> response - * - * Request is simply properly formatted SVDM header - * - * Response is 4 data objects: - * [0] :: SVDM header - * [1] :: Identitiy header - * [2] :: Cert Stat VDO - * [3] :: (Product | Cable) VDO - * [4] :: AMA VDO - * - */ -#define VDO_INDEX_HDR 0 -#define VDO_INDEX_IDH 1 -#define VDO_INDEX_CSTAT 2 -#define VDO_INDEX_CABLE 3 -#define VDO_INDEX_PRODUCT 3 -#define VDO_INDEX_AMA 4 -#define VDO_I(name) VDO_INDEX_##name - -/* - * SVDM Identity Header - * -------------------- - * <31> :: data capable as a USB host - * <30> :: data capable as a USB device - * <29:27> :: product type - * <26> :: modal operation supported (1b == yes) - * <25:16> :: SBZ - * <15:0> :: USB-IF assigned VID for this cable vendor - */ -#define IDH_PTYPE_UNDEF 0 -#define IDH_PTYPE_HUB 1 -#define IDH_PTYPE_PERIPH 2 -#define IDH_PTYPE_PCABLE 3 -#define IDH_PTYPE_ACABLE 4 -#define IDH_PTYPE_AMA 5 - -#define VDO_IDH(usbh, usbd, ptype, is_modal, vid) \ - ((usbh) << 31 | (usbd) << 30 | ((ptype) & 0x7) << 27 \ - | (is_modal) << 26 | ((vid) & 0xffff)) - -#define PD_IDH_PTYPE(vdo) (((vdo) >> 27) & 0x7) -#define PD_IDH_VID(vdo) ((vdo) & 0xffff) - -/* - * Cert Stat VDO - * ------------- - * <31:20> : SBZ - * <19:0> : USB-IF assigned TID for this cable - */ -#define VDO_CSTAT(tid) ((tid) & 0xfffff) -#define PD_CSTAT_TID(vdo) ((vdo) & 0xfffff) - -/* - * Product VDO - * ----------- - * <31:16> : USB Product ID - * <15:0> : USB bcdDevice - */ -#define VDO_PRODUCT(pid, bcd) (((pid) & 0xffff) << 16 | ((bcd) & 0xffff)) -#define PD_PRODUCT_PID(vdo) (((vdo) >> 16) & 0xffff) - -/* - * Cable VDO - * --------- - * <31:28> :: Cable HW version - * <27:24> :: Cable FW version - * <23:20> :: SBZ - * <19:18> :: type-C to Type-A/B/C (00b == A, 01 == B, 10 == C) - * <17> :: Type-C to Plug/Receptacle (0b == plug, 1b == receptacle) - * <16:13> :: cable latency (0001 == <10ns(~1m length)) - * <12:11> :: cable termination type (11b == both ends active VCONN req) - * <10> :: SSTX1 Directionality support (0b == fixed, 1b == cfgable) - * <9> :: SSTX2 Directionality support - * <8> :: SSRX1 Directionality support - * <7> :: SSRX2 Directionality support - * <6:5> :: Vbus current handling capability - * <4> :: Vbus through cable (0b == no, 1b == yes) - * <3> :: SOP" controller present? (0b == no, 1b == yes) - * <2:0> :: USB SS Signaling support - */ -#define CABLE_ATYPE 0 -#define CABLE_BTYPE 1 -#define CABLE_CTYPE 2 -#define CABLE_PLUG 0 -#define CABLE_RECEPTACLE 1 -#define CABLE_CURR_1A5 0 -#define CABLE_CURR_3A 1 -#define CABLE_CURR_5A 2 -#define CABLE_USBSS_U2_ONLY 0 -#define CABLE_USBSS_U31_GEN1 1 -#define CABLE_USBSS_U31_GEN2 2 -#define VDO_CABLE(hw, fw, cbl, gdr, lat, term, tx1d, tx2d, rx1d, rx2d, cur, vps, sopp, usbss) \ - (((hw) & 0x7) << 28 | ((fw) & 0x7) << 24 | ((cbl) & 0x3) << 18 \ - | (gdr) << 17 | ((lat) & 0x7) << 13 | ((term) & 0x3) << 11 \ - | (tx1d) << 10 | (tx2d) << 9 | (rx1d) << 8 | (rx2d) << 7 \ - | ((cur) & 0x3) << 5 | (vps) << 4 | (sopp) << 3 \ - | ((usbss) & 0x7)) - -/* - * AMA VDO - * --------- - * <31:28> :: Cable HW version - * <27:24> :: Cable FW version - * <23:12> :: SBZ - * <11> :: SSTX1 Directionality support (0b == fixed, 1b == cfgable) - * <10> :: SSTX2 Directionality support - * <9> :: SSRX1 Directionality support - * <8> :: SSRX2 Directionality support - * <7:5> :: Vconn power - * <4> :: Vconn power required - * <3> :: Vbus power required - * <2:0> :: USB SS Signaling support - */ -#define VDO_AMA(hw, fw, tx1d, tx2d, rx1d, rx2d, vcpwr, vcr, vbr, usbss) \ - (((hw) & 0x7) << 28 | ((fw) & 0x7) << 24 \ - | (tx1d) << 11 | (tx2d) << 10 | (rx1d) << 9 | (rx2d) << 8 \ - | ((vcpwr) & 0x3) << 5 | (vcr) << 4 | (vbr) << 3 \ - | ((usbss) & 0x7)) - -#define PD_VDO_AMA_VCONN_REQ(vdo) (((vdo) >> 4) & 1) -#define PD_VDO_AMA_VBUS_REQ(vdo) (((vdo) >> 3) & 1) - -#define AMA_VCONN_PWR_1W 0 -#define AMA_VCONN_PWR_1W5 1 -#define AMA_VCONN_PWR_2W 2 -#define AMA_VCONN_PWR_3W 3 -#define AMA_VCONN_PWR_4W 4 -#define AMA_VCONN_PWR_5W 5 -#define AMA_VCONN_PWR_6W 6 -#define AMA_USBSS_U2_ONLY 0 -#define AMA_USBSS_U31_GEN1 1 -#define AMA_USBSS_U31_GEN2 2 -#define AMA_USBSS_BBONLY 3 - -/* - * SVDM Discover SVIDs request -> response - * - * Request is properly formatted VDM Header with discover SVIDs command. - * Response is a set of SVIDs of all all supported SVIDs with all zero's to - * mark the end of SVIDs. If more than 12 SVIDs are supported command SHOULD be - * repeated. - */ -#define VDO_SVID(svid0, svid1) (((svid0) & 0xffff) << 16 | ((svid1) & 0xffff)) -#define PD_VDO_SVID_SVID0(vdo) ((vdo) >> 16) -#define PD_VDO_SVID_SVID1(vdo) ((vdo) & 0xffff) - -/* - * Google modes capabilities - * <31:8> : reserved - * <7:0> : mode - */ -#define VDO_MODE_GOOGLE(mode) (mode & 0xff) - -#define MODE_GOOGLE_FU 1 /* Firmware Update mode */ - -/* - * Mode Capabilities - * - * Number of VDOs supplied is SID dependent (but <= 6 VDOS?) - */ -#define VDO_MODE_CNT_DISPLAYPORT 1 - -/* - * DisplayPort modes capabilities - * ------------------------------- - * <31:24> : SBZ - * <23:16> : UFP_D pin assignment supported - * <15:8> : DFP_D pin assignment supported - * <7> : USB 2.0 signaling (0b=yes, 1b=no) - * <6> : Plug | Receptacle (0b == plug, 1b == receptacle) - * <5:2> : xxx1: Supports DPv1.3, xx1x Supports USB Gen 2 signaling - * Other bits are reserved. - * <1:0> : signal direction ( 00b=rsv, 01b=sink, 10b=src 11b=both ) - */ -#define VDO_MODE_DP(snkp, srcp, usb, gdr, sign, sdir) \ - (((snkp) & 0xff) << 16 | ((srcp) & 0xff) << 8 \ - | ((usb) & 1) << 7 | ((gdr) & 1) << 6 | ((sign) & 0xF) << 2 \ - | ((sdir) & 0x3)) -#define PD_DP_PIN_CAPS(x) ((((x) >> 6) & 0x1) ? (((x) >> 16) & 0x3f) \ - : (((x) >> 8) & 0x3f)) - -#define MODE_DP_PIN_A 0x01 -#define MODE_DP_PIN_B 0x02 -#define MODE_DP_PIN_C 0x04 -#define MODE_DP_PIN_D 0x08 -#define MODE_DP_PIN_E 0x10 -#define MODE_DP_PIN_F 0x20 - -/* Pin configs B/D/F support multi-function */ -#define MODE_DP_PIN_MF_MASK 0x2a -/* Pin configs A/B support BR2 signaling levels */ -#define MODE_DP_PIN_BR2_MASK 0x3 -/* Pin configs C/D/E/F support DP signaling levels */ -#define MODE_DP_PIN_DP_MASK 0x3c - -#define MODE_DP_V13 0x1 -#define MODE_DP_GEN2 0x2 - -#define MODE_DP_SNK 0x1 -#define MODE_DP_SRC 0x2 -#define MODE_DP_BOTH 0x3 - -/* - * DisplayPort Status VDO - * ---------------------- - * <31:9> : SBZ - * <8> : IRQ_HPD : 1 == irq arrived since last message otherwise 0. - * <7> : HPD state : 0 = HPD_LOW, 1 == HPD_HIGH - * <6> : Exit DP Alt mode: 0 == maintain, 1 == exit - * <5> : USB config : 0 == maintain current, 1 == switch to USB from DP - * <4> : Multi-function preference : 0 == no pref, 1 == MF preferred. - * <3> : enabled : is DPout on/off. - * <2> : power low : 0 == normal or LPM disabled, 1 == DP disabled for LPM - * <1:0> : connect status : 00b == no (DFP|UFP)_D is connected or disabled. - * 01b == DFP_D connected, 10b == UFP_D connected, 11b == both. - */ -#define VDO_DP_STATUS(irq, lvl, amode, usbc, mf, en, lp, conn) \ - (((irq) & 1) << 8 | ((lvl) & 1) << 7 | ((amode) & 1) << 6 \ - | ((usbc) & 1) << 5 | ((mf) & 1) << 4 | ((en) & 1) << 3 \ - | ((lp) & 1) << 2 | ((conn & 0x3) << 0)) - -#define PD_VDO_DPSTS_HPD_IRQ(x) (((x) >> 8) & 1) -#define PD_VDO_DPSTS_HPD_LVL(x) (((x) >> 7) & 1) -#define PD_VDO_DPSTS_MF_PREF(x) (((x) >> 4) & 1) - -/* Per DisplayPort Spec v1.3 Section 3.3 */ -#define HPD_USTREAM_DEBOUNCE_LVL (2*MSEC) -#define HPD_USTREAM_DEBOUNCE_IRQ (250) -#define HPD_DSTREAM_DEBOUNCE_IRQ (500) /* between 500-1000us */ - -/* - * DisplayPort Configure VDO - * ------------------------- - * <31:24> : SBZ - * <23:16> : SBZ - * <15:8> : Pin assignment requested. Choose one from mode caps. - * <7:6> : SBZ - * <5:2> : signalling : 1h == DP v1.3, 2h == Gen 2 - * Oh is only for USB, remaining values are reserved - * <1:0> : cfg : 00 == USB, 01 == DFP_D, 10 == UFP_D, 11 == reserved - */ -#define VDO_DP_CFG(pin, sig, cfg) \ - (((pin) & 0xff) << 8 | ((sig) & 0xf) << 2 | ((cfg) & 0x3)) - -#define PD_DP_CFG_DPON(x) (((x & 0x3) == 1) || ((x & 0x3) == 2)) -/* - * Get the pin assignment mask - * for backward compatibility, if it is null, - * get the former sink pin assignment we used to be in <23:16>. - */ -#define PD_DP_CFG_PIN(x) ((((x) >> 8) & 0xff) ? (((x) >> 8) & 0xff) \ - : (((x) >> 16) & 0xff)) -/* - * ChromeOS specific PD device Hardware IDs. Used to identify unique - * products and used in VDO_INFO. Note this field is 10 bits. - */ -#define USB_PD_HW_DEV_ID_RESERVED 0 -#define USB_PD_HW_DEV_ID_ZINGER 1 -#define USB_PD_HW_DEV_ID_MINIMUFFIN 2 -#define USB_PD_HW_DEV_ID_DINGDONG 3 -#define USB_PD_HW_DEV_ID_HOHO 4 -#define USB_PD_HW_DEV_ID_HONEYBUNS 5 - -/* - * ChromeOS specific VDO_CMD_READ_INFO responds with device info including: - * RW Hash: First 20 bytes of SHA-256 of RW (20 bytes) - * HW Device ID: unique descriptor for each ChromeOS model (2 bytes) - * top 6 bits are minor revision, bottom 10 bits are major - * SW Debug Version: Software version useful for debugging (15 bits) - * IS RW: True if currently in RW, False otherwise (1 bit) - */ -#define VDO_INFO(id, id_minor, ver, is_rw) ((id_minor) << 26 \ - | ((id) & 0x3ff) << 16 \ - | ((ver) & 0x7fff) << 1 \ - | ((is_rw) & 1)) -#define VDO_INFO_HW_DEV_ID(x) ((x) >> 16) -#define VDO_INFO_SW_DBG_VER(x) (((x) >> 1) & 0x7fff) -#define VDO_INFO_IS_RW(x) ((x) & 1) - -#define HW_DEV_ID_MAJ(x) (x & 0x3ff) -#define HW_DEV_ID_MIN(x) ((x) >> 10) - -/* USB-IF SIDs */ -#define USB_SID_PD 0xff00 /* power delivery */ -#define USB_SID_DISPLAYPORT 0xff01 - -#define USB_GOOGLE_TYPEC_URL "http://www.google.com/chrome/devices/typec" -/* USB Vendor ID assigned to Google Inc. */ -#define USB_VID_GOOGLE 0x18d1 - -/* Other Vendor IDs */ -#define USB_VID_APPLE 0x05ac - -/* Timeout for message receive in microseconds */ -#define USB_PD_RX_TMOUT_US 1800 - -/* --- Protocol layer functions --- */ - -enum pd_states { - PD_STATE_DISABLED, - PD_STATE_SUSPENDED, -#ifdef CONFIG_USB_PD_DUAL_ROLE - PD_STATE_SNK_DISCONNECTED, - PD_STATE_SNK_DISCONNECTED_DEBOUNCE, - PD_STATE_SNK_HARD_RESET_RECOVER, - PD_STATE_SNK_DISCOVERY, - PD_STATE_SNK_REQUESTED, - PD_STATE_SNK_TRANSITION, - PD_STATE_SNK_READY, - - PD_STATE_SNK_SWAP_INIT, - PD_STATE_SNK_SWAP_SNK_DISABLE, - PD_STATE_SNK_SWAP_SRC_DISABLE, - PD_STATE_SNK_SWAP_STANDBY, - PD_STATE_SNK_SWAP_COMPLETE, -#endif /* CONFIG_USB_PD_DUAL_ROLE */ - - PD_STATE_SRC_DISCONNECTED, - PD_STATE_SRC_DISCONNECTED_DEBOUNCE, - PD_STATE_SRC_HARD_RESET_RECOVER, - PD_STATE_SRC_STARTUP, - PD_STATE_SRC_DISCOVERY, - PD_STATE_SRC_NEGOCIATE, - PD_STATE_SRC_ACCEPTED, - PD_STATE_SRC_POWERED, - PD_STATE_SRC_TRANSITION, - PD_STATE_SRC_READY, - PD_STATE_SRC_GET_SINK_CAP, - PD_STATE_DR_SWAP, - -#ifdef CONFIG_USB_PD_DUAL_ROLE - PD_STATE_SRC_SWAP_INIT, - PD_STATE_SRC_SWAP_SNK_DISABLE, - PD_STATE_SRC_SWAP_SRC_DISABLE, - PD_STATE_SRC_SWAP_STANDBY, - -#ifdef CONFIG_USBC_VCONN_SWAP - PD_STATE_VCONN_SWAP_SEND, - PD_STATE_VCONN_SWAP_INIT, - PD_STATE_VCONN_SWAP_READY, -#endif /* CONFIG_USBC_VCONN_SWAP */ -#endif /* CONFIG_USB_PD_DUAL_ROLE */ - - PD_STATE_SOFT_RESET, - PD_STATE_HARD_RESET_SEND, - PD_STATE_HARD_RESET_EXECUTE, -#ifdef CONFIG_COMMON_RUNTIME - PD_STATE_BIST_RX, - PD_STATE_BIST_TX, -#endif - -#ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE - PD_STATE_DRP_AUTO_TOGGLE, -#endif - /* Number of states. Not an actual state. */ - PD_STATE_COUNT, -}; - -#define PD_FLAGS_PING_ENABLED (1 << 0) /* SRC_READY pings enabled */ -#define PD_FLAGS_PARTNER_DR_POWER (1 << 1) /* port partner is dualrole power */ -#define PD_FLAGS_PARTNER_DR_DATA (1 << 2) /* port partner is dualrole data */ -#define PD_FLAGS_CHECK_IDENTITY (1 << 3) /* discover identity in READY */ -#define PD_FLAGS_SNK_CAP_RECVD (1 << 4) /* sink capabilities received */ -#define PD_FLAGS_TCPC_DRP_TOGGLE (1 << 5) /* TCPC-controlled DRP toggling */ -#define PD_FLAGS_EXPLICIT_CONTRACT (1 << 6) /* explicit pwr contract in place */ -#define PD_FLAGS_VBUS_NEVER_LOW (1 << 7) /* VBUS input has never been low */ -#define PD_FLAGS_PREVIOUS_PD_CONN (1 << 8) /* previously PD connected */ -#define PD_FLAGS_CHECK_PR_ROLE (1 << 9) /* check power role in READY */ -#define PD_FLAGS_CHECK_DR_ROLE (1 << 10)/* check data role in READY */ -#define PD_FLAGS_PARTNER_EXTPOWER (1 << 11)/* port partner has external pwr */ -#define PD_FLAGS_VCONN_ON (1 << 12)/* vconn is being sourced */ -#define PD_FLAGS_TRY_SRC (1 << 13)/* Try.SRC states are active */ -#define PD_FLAGS_PARTNER_USB_COMM (1 << 14)/* port partner is USB comms */ -#define PD_FLAGS_UPDATE_SRC_CAPS (1 << 15)/* send new source capabilities */ -#define PD_FLAGS_TS_DTS_PARTNER (1 << 16)/* partner has rp/rp or rd/rd */ -/* Flags to clear on a disconnect */ -#define PD_FLAGS_RESET_ON_DISCONNECT_MASK (PD_FLAGS_PARTNER_DR_POWER | \ - PD_FLAGS_PARTNER_DR_DATA | \ - PD_FLAGS_CHECK_IDENTITY | \ - PD_FLAGS_SNK_CAP_RECVD | \ - PD_FLAGS_TCPC_DRP_TOGGLE | \ - PD_FLAGS_EXPLICIT_CONTRACT | \ - PD_FLAGS_PREVIOUS_PD_CONN | \ - PD_FLAGS_CHECK_PR_ROLE | \ - PD_FLAGS_CHECK_DR_ROLE | \ - PD_FLAGS_PARTNER_EXTPOWER | \ - PD_FLAGS_VCONN_ON | \ - PD_FLAGS_TRY_SRC | \ - PD_FLAGS_PARTNER_USB_COMM | \ - PD_FLAGS_UPDATE_SRC_CAPS | \ - PD_FLAGS_TS_DTS_PARTNER) - -enum pd_cc_states { - PD_CC_NONE, - - /* From DFP perspective */ - PD_CC_NO_UFP, - PD_CC_AUDIO_ACC, - PD_CC_DEBUG_ACC, - PD_CC_UFP_ATTACHED, - - /* From UFP perspective */ - PD_CC_DFP_ATTACHED -}; - -#ifdef CONFIG_USB_PD_DUAL_ROLE -enum pd_dual_role_states { - /* While disconnected, toggle between src and sink */ - PD_DRP_TOGGLE_ON, - /* Stay in src until disconnect, then stay in sink forever */ - PD_DRP_TOGGLE_OFF, - /* Stay in current power role, don't switch. No auto-toggle support */ - PD_DRP_FREEZE, - /* Switch to sink */ - PD_DRP_FORCE_SINK, - /* Switch to source */ - PD_DRP_FORCE_SOURCE, -}; -/** - * Get dual role state - * - * @return Current dual-role state, from enum pd_dual_role_states - */ -enum pd_dual_role_states pd_get_dual_role(void); -/** - * Set dual role state, from among enum pd_dual_role_states - * - * @param state New state of dual-role port, selected from - * enum pd_dual_role_states - */ -void pd_set_dual_role(enum pd_dual_role_states state); - -/** - * Get role, from among PD_ROLE_SINK and PD_ROLE_SOURCE - * - * @param port Port number from which to get role - */ -int pd_get_role(); - -#endif - -/* Control Message type */ -enum pd_ctrl_msg_type { - /* 0 Reserved */ - PD_CTRL_GOOD_CRC = 1, - PD_CTRL_GOTO_MIN = 2, - PD_CTRL_ACCEPT = 3, - PD_CTRL_REJECT = 4, - PD_CTRL_PING = 5, - PD_CTRL_PS_RDY = 6, - PD_CTRL_GET_SOURCE_CAP = 7, - PD_CTRL_GET_SINK_CAP = 8, - PD_CTRL_DR_SWAP = 9, - PD_CTRL_PR_SWAP = 10, - PD_CTRL_VCONN_SWAP = 11, - 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 */ -enum pd_data_msg_type { - /* 0 Reserved */ - PD_DATA_SOURCE_CAP = 1, - PD_DATA_REQUEST = 2, - PD_DATA_BIST = 3, - PD_DATA_SINK_CAP = 4, - /* 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 -#define PD_ROLE_SOURCE 1 -/* Data role */ -#define PD_ROLE_UFP 0 -#define PD_ROLE_DFP 1 -/* Vconn role */ -#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 -#define PD_ROLE_DEFAULT(port) PD_ROLE_SINK -#else -#define PD_ROLE_DEFAULT(port) PD_ROLE_SOURCE -#endif -#endif - -/* Port default state at startup */ -#ifdef CONFIG_USB_PD_DUAL_ROLE -#define PD_DEFAULT_STATE(port) ((PD_ROLE_DEFAULT(port) == PD_ROLE_SOURCE) ? \ - PD_STATE_SRC_DISCONNECTED : \ - PD_STATE_SNK_DISCONNECTED) -#else -#define PD_DEFAULT_STATE(port) PD_STATE_SRC_DISCONNECTED -#endif - -/* 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 -#define PD_SYNC2 0x11 -#define PD_SYNC3 0x06 -#define PD_RST1 0x07 -#define PD_RST2 0x19 -#define PD_EOP 0x0D - -/* Minimum PD supply current (mA) */ -#define PD_MIN_MA 500 - -/* Minimum PD voltage (mV) */ -#define PD_MIN_MV 5000 - -/* No connect voltage threshold for sources based on Rp */ -#define PD_SRC_DEF_VNC_MV 1600 -#define PD_SRC_1_5_VNC_MV 1600 -#define PD_SRC_3_0_VNC_MV 2600 - -/* Rd voltage threshold for sources based on Rp */ -#define PD_SRC_DEF_RD_THRESH_MV 200 -#define PD_SRC_1_5_RD_THRESH_MV 400 -#define PD_SRC_3_0_RD_THRESH_MV 800 - -/* Voltage threshold to detect connection when presenting Rd */ -#define PD_SNK_VA_MV 250 - -/* --- Policy layer functions --- */ - -/* Request types for pd_build_request() */ -enum pd_request_type { - PD_REQUEST_VSAFE5V, - 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(); - -/** - * 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(); -#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. - * - * @param port USB-C port number - * @param rdo requested Request Data Object. - * @param ma selected current limit (stored on success) - * @param mv selected supply voltage (stored on success) - * @param req_type request type - * @return <0 if invalid, else EC_SUCCESS - */ -int pd_build_request( uint32_t *rdo, uint32_t *ma, uint32_t *mv, - enum pd_request_type req_type); - -/** - * Check if max voltage request is allowed (only used if - * CONFIG_USB_PD_CHECK_MAX_REQUEST_ALLOWED is defined). - * - * @return True if max voltage request allowed, False otherwise - */ -int pd_is_max_request_allowed(void); - -/** - * Callback with source capabilities packet - * - * @param port USB-C port number - * @param cnt the number of Power Data Objects. - * @param src_caps Power Data Objects representing the source capabilities. - */ -void pd_process_source_cap_callback( int cnt, uint32_t *src_caps); - -/** - * Process source capabilities packet - * - * @param port USB-C port number - * @param cnt the number of Power Data Objects. - * @param src_caps Power Data Objects representing the source capabilities. - */ -void pd_process_source_cap( int cnt, uint32_t *src_caps); - -/** - * Find PDO index that offers the most amount of power and stays within - * max_mv voltage. - * - * @param port USB-C port number - * @param max_mv maximum voltage (or -1 if no limit) - * @param pdo raw pdo corresponding to index, or index 0 on error (output) - * @return index of PDO within source cap packet - */ -int pd_find_pdo_index( int max_mv, uint32_t *pdo); - -/** - * Extract power information out of a Power Data Object (PDO) - * - * @param pdo raw pdo to extract - * @param ma current of the PDO (output) - * @param mv voltage of the PDO (output) - */ -void pd_extract_pdo_power(uint32_t pdo, uint32_t *ma, uint32_t *mv); - -/** - * Reduce the sink power consumption to a minimum value. - * - * @param port USB-C port number - * @param ma reduce current to minimum value. - * @param mv reduce voltage to minimum value. - */ -void pd_snk_give_back( uint32_t * const ma, uint32_t * const mv); - -/** - * Put a cap on the max voltage requested as a sink. - * @param mv maximum voltage in millivolts. - */ -void pd_set_max_voltage(unsigned mv); - -/** - * Get the max voltage that can be requested as set by pd_set_max_voltage(). - * @return max voltage - */ -unsigned pd_get_max_voltage(void); - -/** - * Check if this board supports the given input voltage. - * - * @mv input voltage - * @return 1 if voltage supported, 0 if not - */ -int pd_is_valid_input_voltage(int mv); - -/** - * Request a new operating voltage. - * - * @param rdo Request Data Object with the selected operating point. - * @param port The port which the request came in on. - * @return EC_SUCCESS if we can get the requested voltage/OP, <0 else. - */ -int pd_check_requested_voltage(uint32_t rdo, const int port); - -/** - * Run board specific checks on request message - * - * @param rdo the request data object word sent by the sink. - * @param pdo_cnt the total number of source PDOs. - * @return EC_SUCCESS if request is ok , <0 else. - */ -int pd_board_check_request(uint32_t rdo, int pdo_cnt); - -/** - * Select a new output voltage. - * - * param idx index of the new voltage in the source PDO table. - */ -void pd_transition_voltage(int idx); - -/** - * Go back to the default/safe state of the power supply - * - * @param port USB-C port number - */ -void pd_power_supply_reset(); - -/** - * Enable or disable VBUS discharge for a given port. - * - * @param port USB-C port number - * @enable 1 if enabling discharge, 0 if disabling - */ -void pd_set_vbus_discharge( int enable); - -/** - * Enable the power supply output after the ready delay. - * - * @param port USB-C port number - * @return EC_SUCCESS if the power supply is ready, <0 else. - */ -int pd_set_power_supply_ready(); - -/** - * Ask the specified voltage from the PD source. - * - * It triggers a new negotiation sequence with the source. - * @param port USB-C port number - * @param mv request voltage in millivolts. - */ -void pd_request_source_voltage( int mv); - -/** - * Set a voltage limit from the PD source. - * - * If the source is currently active, it triggers a new negotiation. - * @param port USB-C port number - * @param mv limit voltage in millivolts. - */ -void pd_set_external_voltage_limit( int mv); - -/** - * Set the PD input current limit. - * - * @param port USB-C port number - * @param max_ma Maximum current limit - * @param supply_voltage Voltage at which current limit is applied - */ -void pd_set_input_current_limit( uint32_t max_ma, - uint32_t supply_voltage); - - -/** - * Update the power contract if it exists. - * - * @param port USB-C port number. - */ -void pd_update_contract(); - -/* Encode DTS status of port partner in current limit parameter */ -typedef uint32_t typec_current_t; -#define TYPEC_CURRENT_DTS_MASK (1 << 31) -#define TYPEC_CURRENT_ILIM_MASK (~TYPEC_CURRENT_DTS_MASK) - -/** - * Set the type-C input current limit. - * - * @param port USB-C port number - * @param max_ma Maximum current limit - * @param supply_voltage Voltage at which current limit is applied - */ -void typec_set_input_current_limit( typec_current_t max_ma, - uint32_t supply_voltage); - -/** - * Set the type-C current limit when sourcing current.. - * - * @param port USB-C port number - * @param rp One of enum tcpc_rp_value (eg TYPEC_RP_3A0) defining the limit. - */ -void typec_set_source_current_limit( int rp); - -/** - * Verify board specific health status : current, voltages... - * - * @return EC_SUCCESS if the board is good, <0 else. - */ -int pd_board_checks(void); - -/** - * Return if VBUS is detected on type-C port - * - * @param port USB-C port number - * @return VBUS is detected - */ -int pd_snk_is_vbus_provided(); - -/** - * Notify PD protocol that VBUS has gone low - * - * @param port USB-C port number - */ -void pd_vbus_low(); - -/** - * Check if power swap is allowed. - * - * @param port USB-C port number - * @return True if power swap is allowed, False otherwise - */ -int pd_check_power_swap(); - -/** - * Check if data swap is allowed. - * - * @param port USB-C port number - * @param data_role current data role - * @return True if data swap is allowed, False otherwise - */ -int pd_check_data_swap( int data_role); - -/** - * Check if vconn swap is allowed. - * - * @param port USB-C port number - * @return True if vconn swap is allowed, False otherwise - */ - -int pd_check_vconn_swap(); - -/** - * Check current power role for potential power swap - * - * @param port USB-C port number - * @param pr_role Our power role - * @param flags PD flags - */ -void pd_check_pr_role( int pr_role, int flags); - -/** - * Check current data role for potential data swap - * - * @param port USB-C port number - * @param dr_role Our data role - * @param flags PD flags - */ -void pd_check_dr_role( int dr_role, int flags); - -/** - * Check if we should charge from this device. This is - * basically a white-list for chargers that are dual-role, - * don't set the externally powered bit, but we should charge - * from by default. - * - * @param vid Port partner Vendor ID - * @param pid Port partner Product ID - */ -int pd_charge_from_device(uint16_t vid, uint16_t pid); - -/** - * Execute data swap. - * - * @param port USB-C port number - * @param data_role new data role - */ -void pd_execute_data_swap( int data_role); - -/** - * Get PD device info used for VDO_CMD_SEND_INFO / VDO_CMD_READ_INFO - * - * @param info_data pointer to info data array - */ -void pd_get_info(uint32_t *info_data); - -/** - * Handle Vendor Defined Messages - * - * @param port USB-C port number - * @param cnt number of data objects in the payload. - * @param payload payload data. - * @param rpayload pointer to the data to send back. - * @return if >0, number of VDOs to send back. - */ -int pd_custom_vdm( int cnt, uint32_t *payload, uint32_t **rpayload); - -/** - * Handle Structured Vendor Defined Messages - * - * @param port USB-C port number - * @param cnt number of data objects in the payload. - * @param payload payload data. - * @param rpayload pointer to the data to send back. - * @return if >0, number of VDOs to send back. - */ -int pd_svdm( int cnt, uint32_t *payload, uint32_t **rpayload); - -/** - * Handle Custom VDMs for flashing. - * - * @param port USB-C port number - * @param cnt number of data objects in the payload. - * @param payload payload data. - * @return if >0, number of VDOs to send back. - */ -int pd_custom_flash_vdm( int cnt, uint32_t *payload); - -/** - * Enter alternate mode on DFP - * - * @param port USB-C port number - * @param svid USB standard or vendor id to exit or zero for DFP amode reset. - * @param opos object position of mode to exit. - * @return vdm for UFP to be sent to enter mode or zero if not. - */ -uint32_t pd_dfp_enter_mode( uint16_t svid, int opos); - -/** - * Get DisplayPort pin mode for DFP to request from UFP's capabilities. - * - * @param port USB-C port number. - * @param status DisplayPort Status VDO. - * @return one-hot PIN config to request. - */ -int pd_dfp_dp_get_pin_mode( uint32_t status); - -/** - * Exit alternate mode on DFP - * - * @param port USB-C port number - * @param svid USB standard or vendor id to exit or zero for DFP amode reset. - * @param opos object position of mode to exit. - * @return 1 if UFP should be sent exit mode VDM. - */ -int pd_dfp_exit_mode( uint16_t svid, int opos); - -/** - * Initialize policy engine for DFP - * - * @param port USB-C port number - */ -void pd_dfp_pe_init(); - -/** - * Return the VID of the USB PD accessory connected to a specified port - * - * @param port USB-C port number - * @return the USB Vendor Identifier or 0 if it doesn't exist - */ -uint16_t pd_get_identity_vid(); - -/** - * Return the PID of the USB PD accessory connected to a specified port - * - * @param port USB-C port number - * @return the USB Product Identifier or 0 if it doesn't exist - */ -uint16_t pd_get_identity_pid(); - -/** - * Store Device ID & RW hash of device - * - * @param port USB-C port number - * @param dev_id device identifier - * @param rw_hash pointer to rw_hash - * @param current_image current image: RW or RO - * @return true if the dev / hash match an existing hash - * in our table, false otherwise - */ -int pd_dev_store_rw_hash( uint16_t dev_id, uint32_t *rw_hash, - uint32_t ec_current_image); - -/** - * Try to fetch one PD log entry from accessory - * - * @param port USB-C accessory port number - * @return EC_RES_SUCCESS if the VDM was sent properly else error code - */ -int pd_fetch_acc_log_entry(); - -/** - * Analyze the log entry received as the VDO_CMD_GET_LOG payload. - * - * @param port USB-C accessory port number - * @param cnt number of data objects in payload - * @param payload payload data - */ -void pd_log_recv_vdm( int cnt, uint32_t *payload); - -/** - * Send Vendor Defined Message - * - * @param port USB-C port number - * @param vid Vendor ID - * @param cmd VDO command number - * @param data Pointer to payload to send - * @param count number of data objects in payload - */ -void pd_send_vdm( uint32_t vid, int cmd, const uint32_t *data, - int count); - -/* Power Data Objects for the source and the sink */ -extern const uint32_t pd_src_pdo[]; -extern const int pd_src_pdo_cnt; -extern const uint32_t pd_src_pdo_max[]; -extern const int pd_src_pdo_max_cnt; -extern const uint32_t pd_snk_pdo[]; -extern const int pd_snk_pdo_cnt; - -/** - * Request that a host event be sent to notify the AP of a PD power event. - * - * @param mask host event mask. - */ -#if defined(HAS_TASK_HOSTCMD) && !defined(TEST_BUILD) -void pd_send_host_event(int mask); -#else -static inline void pd_send_host_event(int mask) { } -#endif - -/** - * Determine if in alternate mode or not. - * - * @param port port number. - * @param svid USB standard or vendor id - * @return object position of mode chosen in alternate mode otherwise zero. - */ -int pd_alt_mode( uint16_t svid); - -/** - * Send hpd over USB PD. - * - * @param port port number. - * @param hpd hotplug detect type. - */ -void pd_send_hpd( enum hpd_event hpd); - -/** - * Enable USB Billboard Device. - */ -extern const struct deferred_data pd_usb_billboard_deferred_data; -/* --- Physical layer functions : chip specific --- */ - -/* Packet preparation/retrieval */ - -/** - * Prepare packet reading state machine. - * - * @param port USB-C port number - */ -void pd_init_dequeue(); - -/** - * Prepare packet reading state machine. - * - * @param port USB-C port number - * @param off current position in the packet buffer. - * @param len minimum size to read in bits. - * @param val the read bits. - * @return new position in the packet buffer. - */ -int pd_dequeue_bits( int off, int len, uint32_t *val); - -/** - * Advance until the end of the preamble. - * - * @param port USB-C port number - * @return new position in the packet buffer. - */ -int pd_find_preamble(); - -/** - * Write the preamble in the TX buffer. - * - * @param port USB-C port number - * @return new position in the packet buffer. - */ -int pd_write_preamble(); - -/** - * Write one 10-period symbol in the TX packet. - * corresponding to a quartet with 4b5b encoding - * and Biphase Mark Coding. - * - * @param port USB-C port number - * @param bit_off current position in the packet buffer. - * @param val10 the 10-bit integer. - * @return new position in the packet buffer. - */ -int pd_write_sym( int bit_off, uint32_t val10); - - -/** - * Ensure that we have an edge after EOP and we end up at level 0, - * also fill the last byte. - * - * @param port USB-C port number - * @param bit_off current position in the packet buffer. - * @return new position in the packet buffer. - */ -int pd_write_last_edge( int bit_off); - -/** - * Do 4B5B encoding on a 32-bit word. - * - * @param port USB-C port number - * @param off current offset in bits inside the message - * @param val32 32-bit word value to encode - * @return new offset in the message in bits. - */ -int encode_word( int off, uint32_t val32); - -/** - * Ensure that we have an edge after EOP and we end up at level 0, - * also fill the last byte. - * - * @param port USB-C port number - * @param header PD packet header - * @param cnt number of payload words - * @param data payload content - * @return length of the message in bits. - */ -int prepare_message( uint16_t header, uint8_t cnt, - const uint32_t *data); - -/** - * Dump the current PD packet on the console for debug. - * - * @param port USB-C port number - * @param msg context string. - */ -void pd_dump_packet( const char *msg); - -/** - * Change the TX data clock frequency. - * - * @param port USB-C port number - * @param freq frequency in hertz. - */ -void pd_set_clock( int freq); - -/* TX/RX callbacks */ - -/** - * Start sending over the wire the prepared packet. - * - * @param port USB-C port number - * @param polarity plug polarity (0=CC1, 1=CC2). - * @param bit_len size of the packet in bits. - * @return length transmitted or negative if error - */ -int pd_start_tx( int polarity, int bit_len); - -/** - * Set PD TX DMA to use circular mode. Call this before pd_start_tx() to - * continually loop over the transmit buffer given in pd_start_tx(). - * - * @param port USB-C port number - */ -void pd_tx_set_circular_mode(); - -/** - * Stop PD TX DMA circular mode transaction already in progress. - * - * @param port USB-C port number - */ -void pd_tx_clear_circular_mode(); - -/** - * Call when we are done sending a packet. - * - * @param port USB-C port number - * @param polarity plug polarity (0=CC1, 1=CC2). - */ -void pd_tx_done( int polarity); - -/** - * Check whether the PD reception is started. - * - * @param port USB-C port number - * @return true if the reception is on-going. - */ -int pd_rx_started(); - -/** - * Suspend the PD task. - * @param port USB-C port number - * @param enable pass 0 to resume, anything else to suspend - */ -void pd_set_suspend( int enable); - -/** - * Check if the port has been initialized and PD task has not been - * suspended. - * - * @param port USB-C port number - * @return true if the PD task is not suspended. - */ -int pd_is_port_enabled(); - -/* Callback when the hardware has detected an incoming packet */ -void pd_rx_event(); -/* Start sampling the CC line for reception */ -void pd_rx_start(); -/* Call when we are done reading a packet */ -void pd_rx_complete(); - -/* restart listening to the CC wire */ -void pd_rx_enable_monitoring(); -/* stop listening to the CC wire during transmissions */ -void pd_rx_disable_monitoring(); - -/* get time since last RX edge interrupt */ -uint64_t get_time_since_last_edge(); - -/** - * Deinitialize the hardware used for PD. - * - * @param port USB-C port number - */ -void pd_hw_release(); - -/** - * Initialize the hardware used for PD RX/TX. - * - * @param port USB-C port number - * @param role Role to initialize pins in - */ -void pd_hw_init( int role); - -/** - * Initialize the reception side of hardware used for PD. - * - * This is a subset of pd_hw_init() including only : - * the comparators + the RX edge delay timer + the RX DMA. - * - * @param port USB-C port number - */ -void pd_hw_init_rx(); - -/** - * Initialize the Power Delivery state machine - */ -void pd_init(); - -/** - * Run the state machine. This function must be called regularly - * to iterate through the state machine. It uses get_time() to - * determine what actions to take each call. - */ -void pd_run_state_machine(); - -/* --- Protocol layer functions --- */ - -/** - * Decode a raw packet in the RX buffer. - * - * @param port USB-C port number - * @param payload buffer to store the packet payload (must be 7x 32-bit) - * @return the packet header or <0 in case of error - */ -int pd_analyze_rx( uint32_t *payload); - -/** - * Check if PD communication is enabled - * - * @return true if it's enabled or false otherwise - */ -int pd_comm_is_enabled(); - -/** - * Get connected state - * - * @param port USB-C port number - * @return True if port is in connected state - */ -int pd_is_connected(); - -/** - * Execute a hard reset - * - * @param port USB-C port number - */ -void pd_execute_hard_reset(); - -/** - * Signal to protocol layer that PD transmit is complete - * - * @param port USB-C port number - * @param status status of the transmission - */ -void pd_transmit_complete( int status); - -/** - * Get port polarity. - * - * @param port USB-C port number - */ -int pd_get_polarity(); - -/** - * Get port partner data swap capable status - * - * @param port USB-C port number - */ -int pd_get_partner_data_swap_capable(); - -/** - * Request power swap command to be issued - * - * @param port USB-C port number - */ -void pd_request_power_swap(); - -/** - * Try to become the VCONN source, if we are not already the source and the - * other side is willing to accept a VCONN swap. - * - * @param port USB-C port number - */ -void pd_try_vconn_src(); - -/** - * Request data swap command to be issued - * - * @param port USB-C port number - */ -void pd_request_data_swap(); - -/** - * Set the PD communication enabled flag. When communication is disabled, - * the port can still detect connection and source power but will not - * send or respond to any PD communication. - * - * @param port USB-C port number - * @param enable Enable flag to set - */ -void pd_comm_enable( int enable); - -/** - * Set the PD pings enabled flag. When source has negotiated power over - * PD successfully, it can optionally send pings periodically based on - * this enable flag. - * - * @param port USB-C port number - * @param enable Enable flag to set - */ -void pd_ping_enable( int enable); - -/* Issue PD soft reset */ -void pd_soft_reset(void); - -/* Prepare PD communication for reset */ -void pd_prepare_reset(void); - -/** - * Signal power request to indicate a charger update that affects the port. - * - * @param port USB-C port number - */ -void pd_set_new_power_request(); - -/** - * Return true if partner port is a DTS or TS capable of entering debug - * mode (eg. is presenting Rp/Rp or Rd/Rd). - * - * @param port USB-C port number - */ -int pd_ts_dts_plugged(); - -/* ----- Logging ----- */ -#ifdef CONFIG_USB_PD_LOGGING -/** - * Record one event in the PD logging FIFO. - * - * @param type event type as defined by PD_EVENT_xx in ec_commands.h - * @param size_port payload size and port num (defined by PD_LOG_PORT_SIZE) - * @param data type-defined information - * @param payload pointer to the optional payload (0..16 bytes) - */ -void pd_log_event(uint8_t type, uint8_t size_port, - uint16_t data, void *payload); - -/** - * Retrieve one logged event and prepare a VDM with it. - * - * Used to answer the VDO_CMD_GET_LOG unstructured VDM. - * - * @param payload pointer to the payload data buffer (must be 7 words) - * @return number of 32-bit words in the VDM payload. - */ -int pd_vdm_get_log_entry(uint32_t *payload); -#else /* CONFIG_USB_PD_LOGGING */ -static inline void pd_log_event(uint8_t type, uint8_t size_port, - uint16_t data, void *payload) {} -static inline int pd_vdm_get_log_entry(uint32_t *payload) { return 0; } -#endif /* CONFIG_USB_PD_LOGGING */ - -#endif /* __CROS_EC_USB_PD_H */ diff --git a/workspace/TS100/Core/Drivers/FUSB302/USBC_PD/usb_pd_policy.cpp b/workspace/TS100/Core/Drivers/FUSB302/USBC_PD/usb_pd_policy.cpp deleted file mode 100644 index d70f7c3c..00000000 --- a/workspace/TS100/Core/Drivers/FUSB302/USBC_PD/usb_pd_policy.cpp +++ /dev/null @@ -1,882 +0,0 @@ -/* Copyright (c) 2014 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "USBC_TCPM/tcpm.h" -#include "usb_pd.h" -#include -#ifdef CONFIG_COMMON_RUNTIME -#define CPRINTS(format, args...) cprints(CC_USBPD, format, ## args) -#define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args) -#else -#define CPRINTS(format, args...) -#define CPRINTF(format, args...) -#endif - -static int rw_flash_changed = 1; - -int pd_check_requested_voltage(uint32_t rdo, const int port) { - //No source - return EC_ERROR_INVAL; -} - -#ifdef CONFIG_USB_PD_DUAL_ROLE -/* Last received source cap */ -static uint32_t pd_src_caps[PDO_MAX_OBJECTS]; -static uint8_t pd_src_cap_cnt; - -/* Cap on the max voltage requested as a sink (in millivolts) */ -static unsigned max_request_mv = PD_MAX_VOLTAGE_MV; /* no cap */ - -int pd_find_pdo_index(int max_mv, uint32_t *selected_pdo) { - int i, uw, mv, ma; - int ret = 0; - int __attribute__((unused)) cur_mv = 0; - int cur_uw = 0; - int prefer_cur; - const uint32_t *src_caps = pd_src_caps; - - /* max voltage is always limited by this boards max request */ - max_mv = MIN(max_mv, PD_MAX_VOLTAGE_MV); - - /* Get max power that is under our max voltage input */ - for (i = 0; i < pd_src_cap_cnt; i++) { - /* its an unsupported Augmented PDO (PD3.0) */ - if ((src_caps[i] & PDO_TYPE_MASK) == PDO_TYPE_AUGMENTED) - continue; - - mv = ((src_caps[i] >> 10) & 0x3FF) * 50; - /* Skip invalid voltage */ - if (!mv) - continue; - /* Skip any voltage not supported by this board */ - if (!pd_is_valid_input_voltage(mv)) - continue; - - if ((src_caps[i] & PDO_TYPE_MASK) == PDO_TYPE_BATTERY) { - uw = 250000 * (src_caps[i] & 0x3FF); - } else { - ma = (src_caps[i] & 0x3FF) * 10; - ma = MIN(ma, PD_MAX_CURRENT_MA); - uw = ma * mv; - } - - if (mv > max_mv) - continue; - uw = MIN(uw, PD_MAX_POWER_MW * 1000); - prefer_cur = 0; - - /* Apply special rules in case of 'tie' */ -#ifdef PD_PREFER_LOW_VOLTAGE - if (uw == cur_uw && mv < cur_mv) - prefer_cur = 1; -#elif defined(PD_PREFER_HIGH_VOLTAGE) - if (uw == cur_uw && mv > cur_mv) - prefer_cur = 1; -#endif - /* Prefer higher power, except for tiebreaker */ - if (uw > cur_uw || prefer_cur) { - ret = i; - cur_uw = uw; - cur_mv = mv; - } - } - - if (selected_pdo) - *selected_pdo = src_caps[ret]; - - return ret; -} - -void pd_extract_pdo_power(uint32_t pdo, uint32_t *ma, uint32_t *mv) { - int max_ma, uw; - - *mv = ((pdo >> 10) & 0x3FF) * 50; - - if (*mv == 0) { - CPRINTF("ERR:PDO mv=0\n"); - *ma = 0; - return; - } - - if ((pdo & PDO_TYPE_MASK) == PDO_TYPE_BATTERY) { - uw = 250000 * (pdo & 0x3FF); - max_ma = 1000 * MIN(1000 * uw, PD_MAX_POWER_MW) / *mv; - } else { - max_ma = 10 * (pdo & 0x3FF); - max_ma = MIN(max_ma, PD_MAX_POWER_MW * 1000 / *mv); - } - - *ma = MIN(max_ma, PD_MAX_CURRENT_MA); -} - -int pd_build_request(uint32_t *rdo, uint32_t *ma, uint32_t *mv, - enum pd_request_type req_type) { - uint32_t pdo; - int pdo_index, flags = 0; - int uw; - int max_or_min_ma; - int max_or_min_mw; - - if (req_type == PD_REQUEST_VSAFE5V) { - /* src cap 0 should be vSafe5V */ - pdo_index = 0; - pdo = pd_src_caps[0]; - } else { - /* find pdo index for max voltage we can request */ - pdo_index = pd_find_pdo_index(max_request_mv, &pdo); - } - - pd_extract_pdo_power(pdo, ma, mv); - uw = *ma * *mv; - /* Mismatch bit set if less power offered than the operating power */ - if (uw < (1000 * PD_OPERATING_POWER_MW)) - flags |= RDO_CAP_MISMATCH; - -#ifdef CONFIG_USB_PD_GIVE_BACK - /* Tell source we are give back capable. */ - flags |= RDO_GIVE_BACK; - - /* - * BATTERY PDO: Inform the source that the sink will reduce - * power to this minimum level on receipt of a GotoMin Request. - */ - max_or_min_mw = PD_MIN_POWER_MW; - - /* - * FIXED or VARIABLE PDO: Inform the source that the sink will reduce - * current to this minimum level on receipt of a GotoMin Request. - */ - max_or_min_ma = PD_MIN_CURRENT_MA; -#else - /* - * Can't give back, so set maximum current and power to operating - * level. - */ - max_or_min_ma = *ma; - max_or_min_mw = uw / 1000; -#endif - - if ((pdo & PDO_TYPE_MASK) == PDO_TYPE_BATTERY) { - int mw = uw / 1000; - *rdo = RDO_BATT(pdo_index + 1, mw, max_or_min_mw, flags); - } else { - *rdo = RDO_FIXED(pdo_index + 1, *ma, max_or_min_ma, flags); - } - return EC_SUCCESS; -} - -void pd_process_source_cap(int cnt, uint32_t *src_caps) { -#ifdef CONFIG_CHARGE_MANAGER - uint32_t ma, mv, pdo; -#endif - int i; - - pd_src_cap_cnt = cnt; - for (i = 0; i < cnt; i++) - pd_src_caps[i] = *src_caps++; - -#ifdef CONFIG_CHARGE_MANAGER - /* Get max power info that we could request */ - pd_find_pdo_index( PD_MAX_VOLTAGE_MV, &pdo); - pd_extract_pdo_power(pdo, &ma, &mv); - - /* Set max. limit, but apply 500mA ceiling */ - //charge_manager_set_ceil( CEIL_REQUESTOR_PD, PD_MIN_MA); - pd_set_input_current_limit(ma, mv); -#endif -} - -#pragma weak pd_process_source_cap_callback -void pd_process_source_cap_callback(int cnt, uint32_t *src_caps) { -} - -void pd_set_max_voltage(unsigned mv) { - max_request_mv = mv; -} - -unsigned pd_get_max_voltage(void) { - return max_request_mv; -} - -int pd_charge_from_device(uint16_t vid, uint16_t pid) { - /* TODO: rewrite into table if we get more of these */ - /* - * White-list Apple charge-through accessory since it doesn't set - * externally powered bit, but we still need to charge from it when - * we are a sink. - */ - return (vid == USB_VID_APPLE && (pid == 0x1012 || pid == 0x1013)); -} -#endif /* CONFIG_USB_PD_DUAL_ROLE */ - -#ifdef CONFIG_USB_PD_ALT_MODE - -#ifdef CONFIG_USB_PD_ALT_MODE_DFP - -static struct pd_policy pe[CONFIG_USB_PD_PORT_COUNT]; - -void pd_dfp_pe_init(int port) -{ - memset(&pe, 0, sizeof(struct pd_policy)); -} - -static void dfp_consume_identity( int cnt, uint32_t *payload) -{ - int ptype = PD_IDH_PTYPE(payload[VDO_I(IDH)]); - size_t identity_size = MIN(sizeof(pe.identity), - (cnt - 1) * sizeof(uint32_t)); - pd_dfp_pe_init(port); - memcpy(&pe.identity, payload + 1, identity_size); - switch (ptype) { - case IDH_PTYPE_AMA: - /* TODO(tbroch) do I disable VBUS here if power contract - * requested it - */ - if (!PD_VDO_AMA_VBUS_REQ(payload[VDO_I(AMA)])) - pd_power_supply_reset(port); - -#if defined(CONFIG_USB_PD_DUAL_ROLE) && defined(CONFIG_USBC_VCONN_SWAP) - /* Adapter is requesting vconn, try to supply it */ - if (PD_VDO_AMA_VCONN_REQ(payload[VDO_I(AMA)])) - pd_try_vconn_src(port); -#endif - break; - default: - break; - } -} - -static int dfp_discover_svids( uint32_t *payload) -{ - payload[0] = VDO(USB_SID_PD, 1, CMD_DISCOVER_SVID); - return 1; -} - -static void dfp_consume_svids( uint32_t *payload) -{ - int i; - uint32_t *ptr = payload + 1; - uint16_t svid0, svid1; - - for (i = pe.svid_cnt; i < pe.svid_cnt + 12; i += 2) { - if (i == SVID_DISCOVERY_MAX) { - CPRINTF("ERR:SVIDCNT\n"); - break; - } - - svid0 = PD_VDO_SVID_SVID0(*ptr); - if (!svid0) - break; - pe.svids[i].svid = svid0; - pe.svid_cnt++; - - svid1 = PD_VDO_SVID_SVID1(*ptr); - if (!svid1) - break; - pe.svids[i + 1].svid = svid1; - pe.svid_cnt++; - ptr++; - } - /* TODO(tbroch) need to re-issue discover svids if > 12 */ - if (i && ((i % 12) == 0)) - CPRINTF("ERR:SVID+12\n"); -} - -static int dfp_discover_modes( uint32_t *payload) -{ - uint16_t svid = pe.svids[pe.svid_idx].svid; - if (pe.svid_idx >= pe.svid_cnt) - return 0; - payload[0] = VDO(svid, 1, CMD_DISCOVER_MODES); - return 1; -} - -static void dfp_consume_modes( int cnt, uint32_t *payload) -{ - int idx = pe.svid_idx; - pe.svids[idx].mode_cnt = cnt - 1; - if (pe.svids[idx].mode_cnt < 0) { - CPRINTF("ERR:NOMODE\n"); - } else { - memcpy(pe.svids[pe.svid_idx].mode_vdo, &payload[1], - sizeof(uint32_t) * pe.svids[idx].mode_cnt); - } - - pe.svid_idx++; -} - -static int get_mode_idx( uint16_t svid) -{ - int i; - - for (i = 0; i < PD_AMODE_COUNT; i++) { - if (pe.amodes[i].fx->svid == svid) - return i; - } - return -1; -} - -static struct svdm_amode_data *get_modep( uint16_t svid) -{ - int idx = get_mode_idx( svid); - - return (idx == -1) ? NULL : &pe.amodes[idx]; -} - -int pd_alt_mode( uint16_t svid) -{ - struct svdm_amode_data *modep = get_modep( svid); - - return (modep) ? modep->opos : -1; -} - -int allocate_mode( uint16_t svid) -{ - int i, j; - struct svdm_amode_data *modep; - int mode_idx = get_mode_idx( svid); - - if (mode_idx != -1) - return mode_idx; - - /* There's no space to enter another mode */ - if (pe.amode_idx == PD_AMODE_COUNT) { - CPRINTF("ERR:NO AMODE SPACE\n"); - return -1; - } - - /* Allocate ... if SVID == 0 enter default supported policy */ - for (i = 0; i < supported_modes_cnt; i++) { - if (!&supported_modes[i]) - continue; - - for (j = 0; j < pe.svid_cnt; j++) { - struct svdm_svid_data *svidp = &pe.svids[j]; - if ((svidp->svid != supported_modes[i].svid) || - (svid && (svidp->svid != svid))) - continue; - - modep = &pe.amodes[pe.amode_idx]; - modep->fx = &supported_modes[i]; - modep->data = &pe.svids[j]; - pe.amode_idx++; - return pe.amode_idx - 1; - } - } - return -1; -} - -/* - * Enter default mode ( payload[0] == 0 ) or attempt to enter mode via svid & - * opos -*/ -uint32_t pd_dfp_enter_mode( uint16_t svid, int opos) -{ - int mode_idx = allocate_mode( svid); - struct svdm_amode_data *modep; - uint32_t mode_caps; - - if (mode_idx == -1) - return 0; - modep = &pe.amodes[mode_idx]; - - if (!opos) { - /* choose the lowest as default */ - modep->opos = 1; - } else if (opos <= modep->data->mode_cnt) { - modep->opos = opos; - } else { - CPRINTF("opos error\n"); - return 0; - } - - mode_caps = modep->data->mode_vdo[modep->opos - 1]; - if (modep->fx->enter( mode_caps) == -1) - return 0; - - /* SVDM to send to UFP for mode entry */ - return VDO(modep->fx->svid, 1, CMD_ENTER_MODE | VDO_OPOS(modep->opos)); -} - -static int validate_mode_request(struct svdm_amode_data *modep, - uint16_t svid, int opos) -{ - if (!modep->fx) - return 0; - - if (svid != modep->fx->svid) { - CPRINTF("ERR:svid r:0x%04x != c:0x%04x\n", - svid, modep->fx->svid); - return 0; - } - - if (opos != modep->opos) { - CPRINTF("ERR:opos r:%d != c:%d\n", - opos, modep->opos); - return 0; - } - - return 1; -} - -static void dfp_consume_attention( uint32_t *payload) -{ - uint16_t svid = PD_VDO_VID(payload[0]); - int opos = PD_VDO_OPOS(payload[0]); - struct svdm_amode_data *modep = get_modep( svid); - - if (!modep || !validate_mode_request(modep, svid, opos)) - return; - - if (modep->fx->attention) - modep->fx->attention( payload); -} - -/* - * This algorithm defaults to choosing higher pin config over lower ones in - * order to prefer multi-function if desired. - * - * NAME | SIGNALING | OUTPUT TYPE | MULTI-FUNCTION | PIN CONFIG - * ------------------------------------------------------------- - * A | USB G2 | ? | no | 00_0001 - * B | USB G2 | ? | yes | 00_0010 - * C | DP | CONVERTED | no | 00_0100 - * D | PD | CONVERTED | yes | 00_1000 - * E | DP | DP | no | 01_0000 - * F | PD | DP | yes | 10_0000 - * - * if UFP has NOT asserted multi-function preferred code masks away B/D/F - * leaving only A/C/E. For single-output dongles that should leave only one - * possible pin config depending on whether its a converter DP->(VGA|HDMI) or DP - * output. If UFP is a USB-C receptacle it may assert C/D/E/F. The DFP USB-C - * receptacle must always choose C/D in those cases. - */ -int pd_dfp_dp_get_pin_mode( uint32_t status) -{ - struct svdm_amode_data *modep = get_modep( USB_SID_DISPLAYPORT); - uint32_t mode_caps; - uint32_t pin_caps; - if (!modep) - return 0; - - mode_caps = modep->data->mode_vdo[modep->opos - 1]; - - /* TODO(crosbug.com/p/39656) revisit with DFP that can be a sink */ - pin_caps = PD_DP_PIN_CAPS(mode_caps); - - /* if don't want multi-function then ignore those pin configs */ - if (!PD_VDO_DPSTS_MF_PREF(status)) - pin_caps &= ~MODE_DP_PIN_MF_MASK; - - /* TODO(crosbug.com/p/39656) revisit if DFP drives USB Gen 2 signals */ - pin_caps &= ~MODE_DP_PIN_BR2_MASK; - - /* if C/D present they have precedence over E/F for USB-C->USB-C */ - if (pin_caps & (MODE_DP_PIN_C | MODE_DP_PIN_D)) - pin_caps &= ~(MODE_DP_PIN_E | MODE_DP_PIN_F); - - /* get_next_bit returns undefined for zero */ - if (!pin_caps) - return 0; - - return 1 << get_next_bit(&pin_caps); -} - -int pd_dfp_exit_mode( uint16_t svid, int opos) -{ - struct svdm_amode_data *modep; - int idx; - - /* - * Empty svid signals we should reset DFP VDM state by exiting all - * entered modes then clearing state. This occurs when we've - * disconnected or for hard reset. - */ - if (!svid) { - for (idx = 0; idx < PD_AMODE_COUNT; idx++) - if (pe.amodes[idx].fx) - pe.amodes[idx].fx->exit(port); - - pd_dfp_pe_init(port); - return 0; - } - - /* - * TODO(crosbug.com/p/33946) : below needs revisited to allow multiple - * mode exit. Additionally it should honor OPOS == 7 as DFP's request - * to exit all modes. We currently don't have any UFPs that support - * multiple modes on one SVID. - */ - modep = get_modep( svid); - if (!modep || !validate_mode_request(modep, svid, opos)) - return 0; - - /* call DFPs exit function */ - modep->fx->exit(port); - /* exit the mode */ - modep->opos = 0; - return 1; -} - -uint16_t pd_get_identity_vid(int port) -{ - return PD_IDH_VID(pe.identity[0]); -} - -uint16_t pd_get_identity_pid(int port) -{ - return PD_PRODUCT_PID(pe.identity[2]); -} - -#ifdef CONFIG_CMD_USB_PD_PE -static void dump_pe(int port) -{ - const char * const idh_ptype_names[] = { - "UNDEF", "Hub", "Periph", "PCable", "ACable", "AMA", - "RSV6", "RSV7"}; - - int i, j, idh_ptype; - struct svdm_amode_data *modep; - uint32_t mode_caps; - - if (pe.identity[0] == 0) { - ccprintf("No identity discovered yet.\n"); - return; - } - idh_ptype = PD_IDH_PTYPE(pe.identity[0]); - ccprintf("IDENT:\n"); - ccprintf("\t[ID Header] %08x :: %s, VID:%04x\n", pe.identity[0], - idh_ptype_names[idh_ptype], pd_get_identity_vid(port)); - ccprintf("\t[Cert Stat] %08x\n", pe.identity[1]); - for (i = 2; i < ARRAY_SIZE(pe.identity); i++) { - ccprintf("\t"); - if (pe.identity[i]) - ccprintf("[%d] %08x ", i, pe.identity[i]); - } - ccprintf("\n"); - - if (pe.svid_cnt < 1) { - ccprintf("No SVIDS discovered yet.\n"); - return; - } - - for (i = 0; i < pe.svid_cnt; i++) { - ccprintf("SVID[%d]: %04x MODES:", i, pe.svids[i].svid); - for (j = 0; j < pe.svids[j].mode_cnt; j++) - ccprintf(" [%d] %08x", j + 1, - pe.svids[i].mode_vdo[j]); - ccprintf("\n"); - modep = get_modep( pe.svids[i].svid); - if (modep) { - mode_caps = modep->data->mode_vdo[modep->opos - 1]; - ccprintf("MODE[%d]: svid:%04x caps:%08x\n", modep->opos, - modep->fx->svid, mode_caps); - } - } -} - -static int command_pe(int argc, char **argv) -{ - int port; - char *e; - if (argc < 3) - return EC_ERROR_PARAM_COUNT; - /* command: pe */ - port = strtoi(argv[1], &e, 10); - if (*e || port >= CONFIG_USB_PD_PORT_COUNT) - return EC_ERROR_PARAM2; - if (!strncasecmp(argv[2], "dump", 4)) - dump_pe(port); - - return EC_SUCCESS; -} - -DECLARE_CONSOLE_COMMAND(pe, command_pe, - " dump", - "USB PE"); -#endif /* CONFIG_CMD_USB_PD_PE */ - -#endif /* CONFIG_USB_PD_ALT_MODE_DFP */ - -int pd_svdm(int cnt, uint32_t *payload, uint32_t **rpayload) { - int cmd = PD_VDO_CMD(payload[0]); - int cmd_type = PD_VDO_CMDT(payload[0]); - int (*func)(uint32_t *payload) = NULL; - - int rsize = 1; /* VDM header at a minimum */ - - payload[0] &= ~VDO_CMDT_MASK; - *rpayload = payload; - - if (cmd_type == CMDT_INIT) { - switch (cmd) { - case CMD_DISCOVER_IDENT: - func = svdm_rsp.identity; - break; - case CMD_DISCOVER_SVID: - func = svdm_rsp.svids; - break; - case CMD_DISCOVER_MODES: - func = svdm_rsp.modes; - break; - case CMD_ENTER_MODE: - func = svdm_rsp.enter_mode; - break; - case CMD_DP_STATUS: - func = svdm_rsp.amode->status; - break; - case CMD_DP_CONFIG: - func = svdm_rsp.amode->config; - break; - case CMD_EXIT_MODE: - func = svdm_rsp.exit_mode; - break; -#ifdef CONFIG_USB_PD_ALT_MODE_DFP - case CMD_ATTENTION: - /* - * attention is only SVDM with no response - * (just goodCRC) return zero here. - */ - dfp_consume_attention( payload); - return 0; -#endif - default: - CPRINTF("ERR:CMD:%d\n", cmd); - rsize = 0; - } - if (func) - rsize = func(payload); - else - /* not supported : NACK it */ - rsize = 0; - if (rsize >= 1) - payload[0] |= VDO_CMDT(CMDT_RSP_ACK); - else if (!rsize) { - payload[0] |= VDO_CMDT(CMDT_RSP_NAK); - rsize = 1; - } else { - 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; - - modep = get_modep( PD_VDO_VID(payload[0])); -#endif - switch (cmd) { -#ifdef CONFIG_USB_PD_ALT_MODE_DFP - case CMD_DISCOVER_IDENT: - dfp_consume_identity( cnt, payload); - rsize = dfp_discover_svids( payload); -#ifdef CONFIG_CHARGE_MANAGER - if (pd_charge_from_device(pd_get_identity_vid(port), - pd_get_identity_pid(port))) - charge_manager_update_dualrole( - CAP_DEDICATED); -#endif - break; - case CMD_DISCOVER_SVID: - dfp_consume_svids( payload); - rsize = dfp_discover_modes( payload); - break; - case CMD_DISCOVER_MODES: - dfp_consume_modes( cnt, payload); - rsize = dfp_discover_modes( payload); - /* enter the default mode for DFP */ - if (!rsize) { - payload[0] = pd_dfp_enter_mode( 0, 0); - if (payload[0]) - rsize = 1; - } - break; - case CMD_ENTER_MODE: - if (!modep) { - rsize = 0; - } else { - if (!modep->opos) - pd_dfp_enter_mode( 0, 0); - - if (modep->opos) { - rsize = modep->fx->status( - payload); - payload[0] |= PD_VDO_OPOS(modep->opos); - } - } - break; - case CMD_DP_STATUS: - /* DP status response & UFP's DP attention have same - payload */ - dfp_consume_attention( payload); - if (modep && modep->opos) - rsize = modep->fx->config( payload); - else - rsize = 0; - break; - case CMD_DP_CONFIG: - if (modep && modep->opos && modep->fx->post_config) - modep->fx->post_config(port); - /* no response after DFPs ack */ - rsize = 0; - break; - case CMD_EXIT_MODE: - /* no response after DFPs ack */ - rsize = 0; - break; -#endif - case CMD_ATTENTION: - /* no response after DFPs ack */ - rsize = 0; - break; - default: - CPRINTF("ERR:CMD:%d\n", cmd); - rsize = 0; - } - - 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) { - case CMD_DISCOVER_IDENT: - case CMD_DISCOVER_SVID: - case CMD_DISCOVER_MODES: - /* resend if its discovery */ - rsize = 1; - break; - case CMD_ENTER_MODE: - /* Error */ - CPRINTF("ERR:ENTBUSY\n"); - rsize = 0; - break; - case CMD_EXIT_MODE: - rsize = 0; - break; - default: - rsize = 0; - } - } else if (cmd_type == CMDT_RSP_NAK) { - /* nothing to do */ - rsize = 0; -#endif /* CONFIG_USB_PD_ALT_MODE_DFP */ - } else { - CPRINTF("ERR:CMDT:%d\n", cmd); - /* do not answer */ - rsize = 0; - } - return rsize; -} - -#else - -int pd_svdm( int cnt, uint32_t *payload, uint32_t **rpayload) -{ - return 0; -} - -#endif /* CONFIG_USB_PD_ALT_MODE */ - -#ifndef CONFIG_USB_PD_CUSTOM_VDM -int pd_vdm(int cnt, uint32_t *payload, uint32_t **rpayload) { - return 0; -} -#endif /* !CONFIG_USB_PD_CUSTOM_VDM */ - -static void pd_usb_billboard_deferred(void) { -#if defined(CONFIG_USB_PD_ALT_MODE) && !defined(CONFIG_USB_PD_ALT_MODE_DFP) \ - && !defined(CONFIG_USB_PD_SIMPLE_DFP) && defined(CONFIG_USB_BOS) - - /* - * TODO(tbroch) - * 1. Will we have multiple type-C port UFPs - * 2. Will there be other modes applicable to DFPs besides DP - */ - if (!pd_alt_mode(0, USB_SID_DISPLAYPORT)) - usb_connect(); - -#endif -} - -#ifdef CONFIG_USB_PD_ALT_MODE_DFP -static int hc_remote_pd_discovery(struct host_cmd_handler_args *args) -{ - const uint8_t *port = args->params; - struct ec_params_usb_pd_discovery_entry *r = args->response; - - if (*port >= CONFIG_USB_PD_PORT_COUNT) - return EC_RES_INVALID_PARAM; - - r->vid = pd_get_identity_vid(*port); - r->ptype = PD_IDH_PTYPE(pe[*port].identity[0]); - /* pid only included if vid is assigned */ - if (r->vid) - r->pid = PD_PRODUCT_PID(pe[*port].identity[2]); - - args->response_size = sizeof(*r); - return EC_RES_SUCCESS; -} -DECLARE_HOST_COMMAND(EC_CMD_USB_PD_DISCOVERY, - hc_remote_pd_discovery, - EC_VER_MASK(0)); - -static int hc_remote_pd_get_amode(struct host_cmd_handler_args *args) -{ - struct svdm_amode_data *modep; - const struct ec_params_usb_pd_get_mode_request *p = args->params; - struct ec_params_usb_pd_get_mode_response *r = args->response; - - if (p->port >= CONFIG_USB_PD_PORT_COUNT) - return EC_RES_INVALID_PARAM; - - /* no more to send */ - if (p->svid_idx >= pe[p->port].svid_cnt) { - r->svid = 0; - args->response_size = sizeof(r->svid); - return EC_RES_SUCCESS; - } - - r->svid = pe[p->port].svids[p->svid_idx].svid; - r->opos = 0; - memcpy(r->vdo, pe[p->port].svids[p->svid_idx].mode_vdo, 24); - modep = get_modep(p->port, r->svid); - - if (modep) - r->opos = pd_alt_mode(p->port, r->svid); - - args->response_size = sizeof(*r); - return EC_RES_SUCCESS; -} -DECLARE_HOST_COMMAND(EC_CMD_USB_PD_GET_AMODE, - hc_remote_pd_get_amode, - EC_VER_MASK(0)); - -#endif - -#define FW_RW_END (CONFIG_EC_WRITABLE_STORAGE_OFF + \ - CONFIG_RW_STORAGE_OFF + CONFIG_RW_SIZE) - -#ifdef CONFIG_USB_PD_DISCHARGE -void pd_set_vbus_discharge( int enable) -{ - static struct mutex discharge_lock[CONFIG_USB_PD_PORT_COUNT]; - - mutex_lock(&discharge_lock); - enable &= !board_vbus_source_enabled(port); -#ifdef CONFIG_USB_PD_DISCHARGE_GPIO - if (!port) - gpio_set_level(GPIO_USB_C0_DISCHARGE, enable); -#if CONFIG_USB_PD_PORT_COUNT > 1 - else - gpio_set_level(GPIO_USB_C1_DISCHARGE, enable); -#endif /* CONFIG_USB_PD_PORT_COUNT */ -#elif defined(CONFIG_USB_PD_DISCHARGE_TCPC) - tcpc_discharge_vbus( enable); -#else -#error "PD discharge implementation not defined" -#endif - mutex_unlock(&discharge_lock); -} -#endif /* CONFIG_USB_PD_DISCHARGE */ diff --git a/workspace/TS100/Core/Drivers/FUSB302/USBC_PD/usb_pd_protocol.cpp b/workspace/TS100/Core/Drivers/FUSB302/USBC_PD/usb_pd_protocol.cpp deleted file mode 100644 index 1ef96807..00000000 --- a/workspace/TS100/Core/Drivers/FUSB302/USBC_PD/usb_pd_protocol.cpp +++ /dev/null @@ -1,4029 +0,0 @@ -/* Copyright (c) 2014 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "usb_pd.h" -#include "USBC_TCPM/usb_pd_tcpm.h" -#include "USBC_TCPM/tcpm.h" -#include "usb_pd_driver.h" -#include -#include -#ifdef CONFIG_COMMON_RUNTIME -#define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args) -#define CPRINTS(format, args...) cprints(CC_USBPD, format, ## args) - -BUILD_ASSERT(CONFIG_USB_PD_PORT_COUNT <= EC_USB_PD_MAX_PORTS); - -/* - * Debug log level - higher number == more log - * Level 0: Log state transitions - * Level 1: Level 0, plus state name - * Level 2: Level 1, plus packet info - * Level 3: Level 2, plus ping packet and packet dump on error - * - * Note that higher log level causes timing changes and thus may affect - * performance. - * - * Can be limited to constant debug_level by CONFIG_USB_PD_DEBUG_LEVEL - */ -#ifdef CONFIG_USB_PD_DEBUG_LEVEL -static const int debug_level = CONFIG_USB_PD_DEBUG_LEVEL; -#else -static int debug_level; -#endif - -/* - * PD communication enabled flag. When false, PD state machine still - * detects source/sink connection and disconnection, and will still - * provide VBUS, but never sends any PD communication. - */ -static uint8_t pd_comm_enabled[CONFIG_USB_PD_PORT_COUNT]; -#else /* CONFIG_COMMON_RUNTIME */ -#define CPRINTF(format, args...) -#define CPRINTS(format, args...) -static const int debug_level = 0; -#endif - -#ifdef CONFIG_USB_PD_DUAL_ROLE -#define DUAL_ROLE_IF_ELSE( sink_clause, src_clause) \ - (pd.power_role == PD_ROLE_SINK ? (sink_clause) : (src_clause)) -#else -#define DUAL_ROLE_IF_ELSE( sink_clause, src_clause) (src_clause) -#endif - -#define READY_RETURN_STATE() DUAL_ROLE_IF_ELSE( PD_STATE_SNK_READY, \ - PD_STATE_SRC_READY) - -/* Type C supply voltage (mV) */ -#define TYPE_C_VOLTAGE 5000 /* mV */ - -/* PD counter definitions */ -#define PD_MESSAGE_ID_COUNT 7 -#define PD_HARD_RESET_COUNT 2 -#define PD_CAPS_COUNT 50 -#define PD_SNK_CAP_RETRIES 3 - -enum vdm_states { - VDM_STATE_ERR_BUSY = -3, - VDM_STATE_ERR_SEND = -2, - VDM_STATE_ERR_TMOUT = -1, - VDM_STATE_DONE = 0, - /* Anything >0 represents an active state */ - VDM_STATE_READY = 1, - VDM_STATE_BUSY = 2, - VDM_STATE_WAIT_RSP_BUSY = 3, -}; - -#ifdef CONFIG_USB_PD_DUAL_ROLE -/* Port dual-role state */ -enum pd_dual_role_states drp_state = CONFIG_USB_PD_INITIAL_DRP_STATE; - -/* Enable variable for Try.SRC states */ -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 - -// variables that used to be pd_task, but had to be promoted -// so both pd_init and pd_run_state_machine can see them -static int head; -static int port = TASK_ID_TO_PD_PORT(task_get_current()); -static uint32_t payload[7]; -static int timeout = 10 * MSEC; -static int cc1, cc2; -static int res, incoming_packet = 0; -static int hard_reset_count = 0; -#ifdef CONFIG_USB_PD_DUAL_ROLE -static uint64_t next_role_swap = PD_T_DRP_SNK; -#ifndef CONFIG_USB_PD_VBUS_DETECT_NONE -static int snk_hard_reset_vbus_off = 0; -#endif -#ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE -static const int auto_toggle_supported = tcpm_auto_toggle_supported(); -#endif -#if defined(CONFIG_CHARGE_MANAGER) -static typec_current_t typec_curr = 0, typec_curr_change = 0; -#endif /* CONFIG_CHARGE_MANAGER */ -#endif /* CONFIG_USB_PD_DUAL_ROLE */ -static enum pd_states this_state; -static enum pd_cc_states new_cc_state; -static timestamp_t now; -static int caps_count = 0, hard_reset_sent = 0; -static int snk_cap_count = 0; -static int evt; - -static struct pd_protocol { - /* current port power role (SOURCE or SINK) */ - uint8_t power_role; - /* current port data role (DFP or UFP) */ - uint8_t data_role; - /* 3-bit rolling message ID counter */ - uint8_t msg_id; - /* Port polarity : 0 => CC1 is CC line, 1 => CC2 is CC line */ - uint8_t polarity; - /* PD state for port */ - enum pd_states task_state; - /* PD state when we run state handler the last time */ - enum pd_states last_state; - /* bool: request state change to SUSPENDED */ - uint8_t req_suspend_state; - /* The state to go to after timeout */ - enum pd_states timeout_state; - /* port flags, see PD_FLAGS_* */ - uint32_t flags; - /* Timeout for the current state. Set to 0 for no timeout. */ - uint64_t timeout; - /* Time for source recovery after hard reset */ - uint64_t src_recover; - /* Time for CC debounce end */ - uint64_t cc_debounce; - /* The cc state */ - enum pd_cc_states cc_state; - /* status of last transmit */ - uint8_t tx_status; - - /* last requested voltage PDO index */ - int requested_idx; -#ifdef CONFIG_USB_PD_DUAL_ROLE - /* Current limit / voltage based on the last request message */ - uint32_t curr_limit; - uint32_t supply_voltage; - /* Signal charging update that affects the port */ - int new_power_request; - /* Store previously requested voltage request */ - int prev_request_mv; - /* Time for Try.SRC states */ - uint64_t try_src_marker; -#endif - - /* PD state for Vendor Defined Messages */ - enum vdm_states vdm_state; - /* Timeout for the current vdm state. Set to 0 for no timeout. */ - timestamp_t vdm_timeout; - /* next Vendor Defined Message to send */ - uint32_t vdo_data[VDO_MAX_SIZE]; - uint8_t vdo_count; - /* VDO to retry if UFP responder replied busy. */ - uint32_t vdo_retry; - -#ifdef CONFIG_USB_PD_CHROMEOS - /* Attached ChromeOS device id, RW hash, and current RO / RW image */ - uint16_t dev_id; - uint32_t dev_rw_hash[PD_RW_HASH_SIZE/4]; - enum ec_current_image current_image; -#endif -#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; - -#ifdef CONFIG_COMMON_RUNTIME -static const char * const pd_state_names[] = { - "DISABLED", "SUSPENDED", -#ifdef CONFIG_USB_PD_DUAL_ROLE - "SNK_DISCONNECTED", "SNK_DISCONNECTED_DEBOUNCE", - "SNK_HARD_RESET_RECOVER", - "SNK_DISCOVERY", "SNK_REQUESTED", "SNK_TRANSITION", "SNK_READY", - "SNK_SWAP_INIT", "SNK_SWAP_SNK_DISABLE", - "SNK_SWAP_SRC_DISABLE", "SNK_SWAP_STANDBY", "SNK_SWAP_COMPLETE", -#endif /* CONFIG_USB_PD_DUAL_ROLE */ - "SRC_DISCONNECTED", "SRC_DISCONNECTED_DEBOUNCE", - "SRC_HARD_RESET_RECOVER", "SRC_STARTUP", - "SRC_DISCOVERY", "SRC_NEGOCIATE", "SRC_ACCEPTED", "SRC_POWERED", - "SRC_TRANSITION", "SRC_READY", "SRC_GET_SNK_CAP", "DR_SWAP", -#ifdef CONFIG_USB_PD_DUAL_ROLE - "SRC_SWAP_INIT", "SRC_SWAP_SNK_DISABLE", "SRC_SWAP_SRC_DISABLE", - "SRC_SWAP_STANDBY", -#ifdef CONFIG_USBC_VCONN_SWAP - "VCONN_SWAP_SEND", "VCONN_SWAP_INIT", "VCONN_SWAP_READY", -#endif /* CONFIG_USBC_VCONN_SWAP */ -#endif /* CONFIG_USB_PD_DUAL_ROLE */ - "SOFT_RESET", "HARD_RESET_SEND", "HARD_RESET_EXECUTE", "BIST_RX", - "BIST_TX", -#ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE - "DRP_AUTO_TOGGLE", -#endif -}; -BUILD_ASSERT(ARRAY_SIZE(pd_state_names) == PD_STATE_COUNT); -#endif - -/* - * 4 entry rw_hash table of type-C devices that AP has firmware updates for. - */ -#ifdef CONFIG_COMMON_RUNTIME -#define RW_HASH_ENTRIES 4 -static struct ec_params_usb_pd_rw_hash_entry rw_hash_table[RW_HASH_ENTRIES]; -#endif - -int pd_comm_is_enabled() { -#ifdef CONFIG_COMMON_RUNTIME - return pd_comm_enabled[port]; -#else - return 1; -#endif -} - -static inline void set_state_timeout(uint64_t timeout, - enum pd_states timeout_state) { - pd.timeout = timeout; - pd.timeout_state = timeout_state; -} - -#ifdef CONFIG_USB_PD_REV30 -int pd_get_rev() -{ - return pd.rev; -} - -int pd_get_vdo_ver() -{ - return vdo_ver[pd.rev]; -} -#endif - -/* Return flag for pd state is connected */ -int pd_is_connected() { - if (pd.task_state == PD_STATE_DISABLED) - return 0; - -#ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE - if (pd.task_state == PD_STATE_DRP_AUTO_TOGGLE) - return 0; -#endif - - return DUAL_ROLE_IF_ELSE( - /* sink */ - pd.task_state != PD_STATE_SNK_DISCONNECTED && pd.task_state != PD_STATE_SNK_DISCONNECTED_DEBOUNCE, - /* source */ - pd.task_state != PD_STATE_SRC_DISCONNECTED && pd.task_state != PD_STATE_SRC_DISCONNECTED_DEBOUNCE); -} - -/* - * Return true if partner port is a DTS or TS capable of entering debug - * mode (eg. is presenting Rp/Rp or Rd/Rd). - */ -int pd_ts_dts_plugged() { - return pd.flags & PD_FLAGS_TS_DTS_PARTNER; -} - -#ifdef CONFIG_USB_PD_DUAL_ROLE -void pd_vbus_low() { - pd.flags &= ~PD_FLAGS_VBUS_NEVER_LOW; -} - -static inline int pd_is_vbus_present() { -#ifdef CONFIG_USB_PD_VBUS_DETECT_TCPC - return tcpm_get_vbus_level(); -#else - return pd_snk_is_vbus_provided(); -#endif -} -#endif - -static inline void set_state(enum pd_states next_state) { - enum pd_states last_state = pd.task_state; -#ifdef CONFIG_LOW_POWER_IDLE - int i; -#endif - - set_state_timeout(0, PD_STATE_DISABLED); - pd.task_state = next_state; - - if (last_state == next_state) - return; - -#ifdef CONFIG_USB_PD_DUAL_ROLE -#ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE - /* Clear flag to allow DRP auto toggle when possible */ - if (last_state != PD_STATE_DRP_AUTO_TOGGLE) - pd.flags &= ~PD_FLAGS_TCPC_DRP_TOGGLE; -#endif - - /* Ignore dual-role toggling between sink and source */ - if ((last_state == PD_STATE_SNK_DISCONNECTED - && next_state == PD_STATE_SRC_DISCONNECTED) - || (last_state == PD_STATE_SRC_DISCONNECTED - && next_state == PD_STATE_SNK_DISCONNECTED)) - return; - - if (next_state == PD_STATE_SRC_DISCONNECTED - || next_state == PD_STATE_SNK_DISCONNECTED) { - /* Clear the input current limit */ - pd_set_input_current_limit(0, 0); -#ifdef CONFIG_CHARGE_MANAGER - //typec_set_input_current_limit( 0, 0); - //charge_manager_set_ceil( - // CEIL_REQUESTOR_PD, - // CHARGE_CEIL_NONE); -#endif -#ifdef CONFIG_USBC_VCONN - tcpm_set_vconn( 0); -#endif -#else /* CONFIG_USB_PD_DUAL_ROLE */ - if (next_state == PD_STATE_SRC_DISCONNECTED) { -#endif - -#ifdef CONFIG_USB_PD_REV30 - /* Adjust rev to highest level*/ - pd.rev = PD_REV30; -#endif -#ifdef CONFIG_USB_PD_CHROMEOS - pd.dev_id = 0; - pd.flags &= ~PD_FLAGS_RESET_ON_DISCONNECT_MASK; -#endif -#ifdef CONFIG_CHARGE_MANAGER - //charge_manager_update_dualrole( CAP_UNKNOWN); -#endif -#ifdef CONFIG_USB_PD_ALT_MODE_DFP - pd_dfp_exit_mode( 0, 0); -#endif -#ifdef CONFIG_USBC_SS_MUX - usb_mux_set( TYPEC_MUX_NONE, USB_SWITCH_DISCONNECT, - pd.polarity); -#endif - /* Disable TCPC RX */ - tcpm_set_rx_enable(0); - } - -#ifdef CONFIG_LOW_POWER_IDLE - /* If a PD device is attached then disable deep sleep */ - for (i = 0; i < CONFIG_USB_PD_PORT_COUNT; i++) { - if (pd[i].flags & PD_FLAGS_PREVIOUS_PD_CONN) - break; - } - if (i == CONFIG_USB_PD_PORT_COUNT) - enable_sleep(SLEEP_MASK_USB_PD); - else - disable_sleep(SLEEP_MASK_USB_PD); -#endif - - if (debug_level >= 1) - CPRINTF("C%d st%d %s\n", port, next_state, - pd_state_names[next_state]); - else - CPRINTF("C%d st%d\n", port, next_state); -} - -/* increment message ID counter */ -static void inc_id() { - pd.msg_id = (pd.msg_id + 1) & PD_MESSAGE_ID_COUNT; -} - -#ifdef CONFIG_USB_PD_REV30 -static void sink_can_xmit( int rp) -{ - tcpm_select_rp_value( rp); - tcpm_set_cc( TYPEC_CC_RP); -} - -static inline void pd_ca_reset() -{ - pd.ca_buffered = 0; -} -#endif - -void pd_transmit_complete(int status) { - if (status == TCPC_TX_COMPLETE_SUCCESS) - inc_id(); - - pd.tx_status = status; - //task_set_event(PD_PORT_TO_TASK_ID(), PD_EVENT_TX, 0); - pd_task_set_event(PD_EVENT_TX, 0); -} - -static int pd_transmit(enum tcpm_transmit_type type, uint16_t header, - const uint32_t *data) { - int evt; - - /* If comms are disabled, do not transmit, return error */ - if (!pd_comm_is_enabled()) - 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* AMS’s 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.rev == PD_REV30) && - (pd.flags & PD_FLAGS_EXPLICIT_CONTRACT)) { - if (pd.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( SINK_TX_NG); - } else if (type != TCPC_TX_HARD_RESET) { - int cc1; - int cc2; - - tcpm_get_cc( &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.ca_buffered) - return -1; - - /* Buffer message and send later. */ - pd.ca_type = type; - pd.ca_header = header; - memcpy(pd.ca_buffer, - data, sizeof(uint32_t) * - PD_HEADER_CNT(header)); - pd.ca_buffered = 1; - return 1; - } - } - } -#endif - tcpm_transmit(type, header, data); - - /* Wait until TX is complete */ - // Would wait, except that we're making tcpm_transmit blocking - //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.rev == PD_REV30) && - (pd.power_role == PD_ROLE_SOURCE) && - (pd.flags & PD_FLAGS_EXPLICIT_CONTRACT)) { - sink_can_xmit( SINK_TX_OK); - } -#endif - - // removing task-based stuff from the library - //if (evt & TASK_EVENT_TIMER) - // return -1; - - /* TODO: give different error condition for failed vs discarded */ - return pd.tx_status == TCPC_TX_COMPLETE_SUCCESS ? 1 : -1; -} - -#ifdef CONFIG_USB_PD_REV30 -static void pd_ca_send_pending() -{ - int cc1; - int cc2; - - /* Check if a message has been buffered. */ - if (!pd.ca_buffered) - return; - - tcpm_get_cc( &cc1, &cc2); - if ((cc1 != TYPEC_CC_VOLT_SNK_1_5) && - (cc2 != TYPEC_CC_VOLT_SNK_1_5)) - if (pd_transmit( pd.ca_type, - pd.ca_header, - pd.ca_buffer) < 0) - return; - - /* Message was sent, so free up the buffer. */ - pd.ca_buffered = 0; -} -#endif - -static void pd_update_roles() { - /* Notify TCPC of role update */ - tcpm_set_msg_header(pd.power_role, pd.data_role); -} - -static int send_control(int type) { - int bit_len; - uint16_t header = PD_HEADER(type, pd.power_role, pd.data_role, pd.msg_id, 0, - pd_get_rev(), 0); - - bit_len = pd_transmit(TCPC_TX_SOP, header, NULL); - if (debug_level >= 2) - CPRINTF("CTRL[%d]>%d\n", type, bit_len); - - return bit_len; -} - -static int send_source_cap() { - int bit_len; -#if defined(CONFIG_USB_PD_DYNAMIC_SRC_CAP) || \ - defined(CONFIG_USB_PD_MAX_SINGLE_SOURCE_CURRENT) - const uint32_t *src_pdo; - const int src_pdo_cnt = charge_manager_get_source_pdo(&src_pdo, port); -#else - const uint32_t *src_pdo = pd_src_pdo; - const int src_pdo_cnt = pd_src_pdo_cnt; -#endif - uint16_t header; - - if (src_pdo_cnt == 0) - /* No source capabilities defined, sink only */ - header = PD_HEADER(PD_CTRL_REJECT, pd.power_role, pd.data_role, - pd.msg_id, 0, pd_get_rev(), 0); - else - header = PD_HEADER(PD_DATA_SOURCE_CAP, pd.power_role, pd.data_role, - pd.msg_id, src_pdo_cnt, pd_get_rev(), 0); - - bit_len = pd_transmit(TCPC_TX_SOP, header, src_pdo); - if (debug_level >= 2) - CPRINTF("srcCAP>%d\n", bit_len); - - return bit_len; -} - -#ifdef CONFIG_USB_PD_REV30 -static int send_battery_cap( 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.power_role, - pd.data_role, - pd.msg_id, - 3, /* Number of Data Objects */ - pd.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 - * Battery’s 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 Battery’s 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( 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( uint32_t *payload) -{ - int bit_len; - uint32_t msg = 0; - uint16_t header = PD_HEADER(PD_DATA_BATTERY_STATUS, - pd.power_role, - pd.data_role, - pd.msg_id, - 1, /* Number of Data Objects */ - pd.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( 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 bit_len; - uint16_t header = PD_HEADER(PD_DATA_SINK_CAP, pd.power_role, - pd.data_role, pd.msg_id, pd_snk_pdo_cnt, pd_get_rev(), - 0); - - bit_len = pd_transmit(TCPC_TX_SOP, header, pd_snk_pdo); - if (debug_level >= 2) - CPRINTF("snkCAP>%d\n", bit_len); -} - -static int send_request(uint32_t rdo) { - int bit_len; - uint16_t header = PD_HEADER(PD_DATA_REQUEST, pd.power_role, - pd.data_role, pd.msg_id, 1, pd_get_rev(), 0); - - bit_len = pd_transmit(TCPC_TX_SOP, header, &rdo); - if (debug_level >= 2) - CPRINTF("REQ%d>\n", bit_len); - - return bit_len; -} -#ifdef CONFIG_BBRAM -static int pd_get_saved_active() -{ - uint8_t val; - - if (system_get_bbram(port ? SYSTEM_BBRAM_IDX_PD1 : - SYSTEM_BBRAM_IDX_PD0, &val)) { - CPRINTS("PD NVRAM FAIL"); - return 0; - } - return !!val; -} - -static void pd_set_saved_active( int val) -{ - if (system_set_bbram(port ? SYSTEM_BBRAM_IDX_PD1 : - SYSTEM_BBRAM_IDX_PD0, val)) - CPRINTS("PD NVRAM FAIL"); -} -#endif // CONFIG_BBRAM -#endif /* CONFIG_USB_PD_DUAL_ROLE */ - -#ifdef CONFIG_COMMON_RUNTIME -static int send_bist_cmd() -{ - /* currently only support sending bist carrier 2 */ - uint32_t bdo = BDO(BDO_MODE_CARRIER2, 0); - int bit_len; - uint16_t header = PD_HEADER(PD_DATA_BIST, pd.power_role, - pd.data_role, pd.msg_id, 1, - pd_get_rev(), 0); - - bit_len = pd_transmit( TCPC_TX_SOP, header, &bdo); - CPRINTF("BIST>%d\n", bit_len); - - return bit_len; -} -#endif - -static void queue_vdm(uint32_t *header, const uint32_t *data, int data_cnt) { - pd.vdo_count = data_cnt + 1; - pd.vdo_data[0] = header[0]; - memcpy(&pd.vdo_data[1], data, sizeof(uint32_t) * data_cnt); - /* Set ready, pd task will actually send */ - pd.vdm_state = VDM_STATE_READY; -} - -static void handle_vdm_request(int cnt, uint32_t *payload) { - int rlen = 0; - uint32_t *rdata; - - if (pd.vdm_state == VDM_STATE_BUSY) { - /* If UFP responded busy retry after timeout */ - if (PD_VDO_CMDT(payload[0]) == CMDT_RSP_BUSY) { - pd.vdm_timeout.val = get_time().val + - PD_T_VDM_BUSY; - pd.vdm_state = VDM_STATE_WAIT_RSP_BUSY; - pd.vdo_retry = (payload[0] & ~VDO_CMDT_MASK) | - CMDT_INIT; - return; - } else { - pd.vdm_state = VDM_STATE_DONE; - } - } - - if (PD_VDO_SVDM(payload[0])) - rlen = pd_svdm(cnt, payload, &rdata); - - if (rlen > 0) { - queue_vdm(rdata, &rdata[1], rlen - 1); - return; - } - if (debug_level >= 2) - CPRINTF("Unhandled VDM VID %04x CMD %04x\n", - PD_VDO_VID(payload[0]), payload[0] & 0xFFFF); -} - -void pd_execute_hard_reset() { - if (pd.last_state == PD_STATE_HARD_RESET_SEND) - CPRINTF("C%d HARD RST TX\n", port); - else - CPRINTF("C%d HARD RST RX\n", port); - - pd.msg_id = 0; -#ifdef CONFIG_USB_PD_ALT_MODE_DFP - pd_dfp_exit_mode( 0, 0); -#endif - -#ifdef CONFIG_USB_PD_REV30 - pd.rev = PD_REV30; - pd_ca_reset(); -#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. - */ - pd.last_state = PD_STATE_HARD_RESET_EXECUTE; - -#ifdef CONFIG_USB_PD_DUAL_ROLE - /* - * If we are swapping to a source and have changed to Rp, restore back - * to Rd and turn off vbus to match our power_role. - */ - if (pd.task_state == PD_STATE_SNK_SWAP_STANDBY - || pd.task_state == PD_STATE_SNK_SWAP_COMPLETE) { - tcpm_set_cc(TYPEC_CC_RD); - pd_power_supply_reset(); - } - - if (pd.power_role == PD_ROLE_SINK) { - /* Clear the input current limit */ - pd_set_input_current_limit(0, 0); -#ifdef CONFIG_CHARGE_MANAGER - //charge_manager_set_ceil( - // CEIL_REQUESTOR_PD, - // CHARGE_CEIL_NONE); -#endif /* CONFIG_CHARGE_MANAGER */ - - set_state (PD_STATE_SNK_HARD_RESET_RECOVER); - return; - } -#endif /* CONFIG_USB_PD_DUAL_ROLE */ - - /* We are a source, cut power */ - pd_power_supply_reset(); - pd.src_recover = get_time().val + PD_T_SRC_RECOVER; - set_state(PD_STATE_SRC_HARD_RESET_RECOVER); -} - -static void execute_soft_reset() { - pd.msg_id = 0; - set_state( - DUAL_ROLE_IF_ELSE(PD_STATE_SNK_DISCOVERY, PD_STATE_SRC_DISCOVERY)); - CPRINTF("C%d Soft Rst\n", port); -} - -void pd_soft_reset(void) { - int i; - - if (pd_is_connected()) { - set_state(PD_STATE_SOFT_RESET); - // getting rid of task stuff - //task_wake(PD_PORT_TO_TASK_ID(i)); - } -} - -#ifdef CONFIG_USB_PD_DUAL_ROLE -/* - * Request desired charge voltage from source. - * Returns EC_SUCCESS on success or non-zero on failure. - */ -static int pd_send_request_msg(int always_send_request) { - uint32_t rdo, curr_limit, supply_voltage; - int res; - -#ifdef CONFIG_CHARGE_MANAGER - //int charging = (charge_manager_get_active_charge_port() == port); - const int charging = 1; -#else - const int charging = 1; -#endif - -#ifdef CONFIG_USB_PD_CHECK_MAX_REQUEST_ALLOWED - int max_request_allowed = pd_is_max_request_allowed(); -#else - const int max_request_allowed = 1; -#endif - - /* Clear new power request */ - pd.new_power_request = 0; - - /* Build and send request RDO */ - /* - * If this port is not actively charging or we are not allowed to - * request the max voltage, then select vSafe5V - */ - res = pd_build_request(&rdo, &curr_limit, &supply_voltage, - charging && max_request_allowed ? - PD_REQUEST_MAX : PD_REQUEST_VSAFE5V); - - if (res != EC_SUCCESS) - /* - * If fail to choose voltage, do nothing, let source re-send - * source cap - */ - return -1; - - if (!always_send_request) { - /* Don't re-request the same voltage */ - if (pd.prev_request_mv == supply_voltage) - return EC_SUCCESS; -#ifdef CONFIG_CHARGE_MANAGER - /* Limit current to PD_MIN_MA during transition */ - //else - // charge_manager_force_ceil( PD_MIN_MA); -#endif - } - - CPRINTF("Req C%d [%d] %dmV %dmA", port, RDO_POS(rdo), - supply_voltage, curr_limit); - if (rdo & RDO_CAP_MISMATCH) - CPRINTF(" Mismatch");CPRINTF("\n"); - - pd.curr_limit = curr_limit; - pd.supply_voltage = supply_voltage; - pd.prev_request_mv = supply_voltage; - res = send_request(rdo); - if (res < 0) - return res; - set_state (PD_STATE_SNK_REQUESTED); - return EC_SUCCESS; -} -#endif - -static void pd_update_pdo_flags(uint32_t pdo) { -#ifdef CONFIG_CHARGE_MANAGER -#ifdef CONFIG_USB_PD_ALT_MODE_DFP - int charge_whitelisted = - (pd.power_role == PD_ROLE_SINK && - pd_charge_from_device(pd_get_identity_vid(), - pd_get_identity_pid())); -#else - const int charge_whitelisted = 0; -#endif -#endif - - /* can only parse PDO flags if type is fixed */ - if ((pdo & PDO_TYPE_MASK) != PDO_TYPE_FIXED) - return; - -#ifdef CONFIG_USB_PD_DUAL_ROLE - if (pdo & PDO_FIXED_DUAL_ROLE) - pd.flags |= PD_FLAGS_PARTNER_DR_POWER; - else - pd.flags &= ~PD_FLAGS_PARTNER_DR_POWER; - - if (pdo & PDO_FIXED_EXTERNAL) - pd.flags |= PD_FLAGS_PARTNER_EXTPOWER; - else - pd.flags &= ~PD_FLAGS_PARTNER_EXTPOWER; - - if (pdo & PDO_FIXED_COMM_CAP) - pd.flags |= PD_FLAGS_PARTNER_USB_COMM; - else - pd.flags &= ~PD_FLAGS_PARTNER_USB_COMM; -#endif - - if (pdo & PDO_FIXED_DATA_SWAP) - pd.flags |= PD_FLAGS_PARTNER_DR_DATA; - else - pd.flags &= ~PD_FLAGS_PARTNER_DR_DATA; - -#ifdef CONFIG_CHARGE_MANAGER - /* - * Treat device as a dedicated charger (meaning we should charge - * from it) if it does not support power swap, or if it is externally - * powered, or if we are a sink and the device identity matches a - * charging white-list. - */ - /* - if (!(pd.flags & PD_FLAGS_PARTNER_DR_POWER) || - (pd.flags & PD_FLAGS_PARTNER_EXTPOWER) || - charge_whitelisted) - charge_manager_update_dualrole( CAP_DEDICATED); - else - charge_manager_update_dualrole( CAP_DUALROLE); - */ -#endif -} - -static void handle_data_request(uint16_t head, uint32_t *payload) { - int type = PD_HEADER_TYPE(head); - int cnt = PD_HEADER_CNT(head); - - switch (type) { -#ifdef CONFIG_USB_PD_DUAL_ROLE - case PD_DATA_SOURCE_CAP: - if ((pd.task_state == PD_STATE_SNK_DISCOVERY) - || (pd.task_state == PD_STATE_SNK_TRANSITION) -#ifdef CONFIG_USB_PD_VBUS_DETECT_NONE - || (pd.task_state == - PD_STATE_SNK_HARD_RESET_RECOVER) -#endif - || (pd.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.rev) - pd.rev = PD_HEADER_REV(head); -#endif - /* Port partner is now known to be PD capable */ - pd.flags |= PD_FLAGS_PREVIOUS_PD_CONN; - - /* src cap 0 should be fixed PDO */ - pd_update_pdo_flags(payload[0]); - - pd_process_source_cap(cnt, payload); - - /* Source will resend source cap on failure */ - pd_send_request_msg(1); - - // We call the callback after we send the request - // because the timing on Request seems to be sensitive - // User code can take the time until PS_RDY to do stuff - pd_process_source_cap_callback(cnt, payload); - } - break; -#endif /* CONFIG_USB_PD_DUAL_ROLE */ - case PD_DATA_REQUEST: - - /* the message was incorrect or cannot be satisfied */ - send_control(PD_CTRL_REJECT); - /* keep last contract in place (whether implicit or explicit) */ - set_state(PD_STATE_SRC_READY); - break; - case PD_DATA_BIST: - /* If not in READY state, then don't start BIST */ - if (DUAL_ROLE_IF_ELSE(pd.task_state == PD_STATE_SNK_READY, - pd.task_state == PD_STATE_SRC_READY)) { - /* currently only support sending bist carrier mode 2 */ - if ((payload[0] >> 28) == 5) { - /* bist data object mode is 2 */ - pd_transmit(TCPC_TX_BIST_MODE_2, 0, - NULL); - /* Set to appropriate port disconnected state */ - set_state( - DUAL_ROLE_IF_ELSE(PD_STATE_SNK_DISCONNECTED, - PD_STATE_SRC_DISCONNECTED)); - } - } - break; - case PD_DATA_SINK_CAP: - pd.flags |= PD_FLAGS_SNK_CAP_RECVD; - /* snk cap 0 should be fixed PDO */ - pd_update_pdo_flags(payload[0]); - if (pd.task_state == PD_STATE_SRC_GET_SINK_CAP) - set_state(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(cnt, payload); - break; - default: - CPRINTF("Unhandled data message type %d\n", type); - } -} - -#ifdef CONFIG_USB_PD_DUAL_ROLE -void pd_request_power_swap() { - if (pd.task_state == PD_STATE_SRC_READY) - set_state (PD_STATE_SRC_SWAP_INIT); - else if (pd.task_state == PD_STATE_SNK_READY) - set_state (PD_STATE_SNK_SWAP_INIT); - // getting rid of task stuff - //task_wake(PD_PORT_TO_TASK_ID()); -} - -#ifdef CONFIG_USBC_VCONN_SWAP -static void pd_request_vconn_swap() -{ - if (pd.task_state == PD_STATE_SRC_READY || - pd.task_state == PD_STATE_SNK_READY) - set_state( PD_STATE_VCONN_SWAP_SEND); - // getting rid of task stuff - //task_wake(PD_PORT_TO_TASK_ID()); -} - -void pd_try_vconn_src() -{ - /* - * If we don't currently provide vconn, and we can supply it, send - * a vconn swap request. - */ - if (!(pd.flags & PD_FLAGS_VCONN_ON)) { - if (pd_check_vconn_swap()) - pd_request_vconn_swap(); - } -} -#endif -#endif /* CONFIG_USB_PD_DUAL_ROLE */ - -void pd_request_data_swap() { - if (DUAL_ROLE_IF_ELSE(pd.task_state == PD_STATE_SNK_READY, - pd.task_state == PD_STATE_SRC_READY)) - set_state(PD_STATE_DR_SWAP); - // getting rid of task stuff - //task_wake(PD_PORT_TO_TASK_ID()); -} - -static void pd_set_data_role(int role) { - pd.data_role = role; - pd_execute_data_swap(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( TYPEC_MUX_USB, USB_SWITCH_CONNECT, - pd.polarity); - else - usb_mux_set( TYPEC_MUX_NONE, USB_SWITCH_DISCONNECT, - pd.polarity); -#else - usb_mux_set( TYPEC_MUX_USB, USB_SWITCH_CONNECT, - pd.polarity); -#endif -#endif - pd_update_roles(); -} - -static void pd_dr_swap() { - pd_set_data_role(!pd.data_role); - pd.flags |= PD_FLAGS_CHECK_IDENTITY; -} - -static void handle_ctrl_request(uint16_t head, uint32_t *payload) { - int type = PD_HEADER_TYPE(head); - int res; - - switch (type) { - case PD_CTRL_GOOD_CRC: - /* should not get it */ - break; - case PD_CTRL_PING: - /* Nothing else to do */ - break; - case PD_CTRL_GET_SOURCE_CAP: - res = send_source_cap(); - if ((res >= 0) && (pd.task_state == PD_STATE_SRC_DISCOVERY)) - set_state(PD_STATE_SRC_NEGOCIATE); - break; - case PD_CTRL_GET_SINK_CAP: -#ifdef CONFIG_USB_PD_DUAL_ROLE - send_sink_cap(); -#else - send_control(REFUSE(pd.rev)); -#endif - break; -#ifdef CONFIG_USB_PD_DUAL_ROLE - case PD_CTRL_GOTO_MIN: -#ifdef CONFIG_USB_PD_GIVE_BACK - if (pd.task_state == PD_STATE_SNK_READY) { - /* - * Reduce power consumption now! - * - * The source will restore power to this sink - * by sending a new source cap message at a - * later time. - */ - pd_snk_give_back( &pd.curr_limit, - &pd.supply_voltage); - set_state( PD_STATE_SNK_TRANSITION); - } -#endif - - break; - case PD_CTRL_PS_RDY: - if (pd.task_state == PD_STATE_SNK_SWAP_SRC_DISABLE) { - set_state (PD_STATE_SNK_SWAP_STANDBY); - } else if (pd.task_state == PD_STATE_SRC_SWAP_STANDBY) { - /* reset message ID and swap roles */ - pd.msg_id = 0; - pd.power_role = PD_ROLE_SINK; - pd_update_roles(); - set_state (PD_STATE_SNK_DISCOVERY); -#ifdef CONFIG_USBC_VCONN_SWAP - } else if (pd.task_state == PD_STATE_VCONN_SWAP_INIT) { - /* - * If VCONN is on, then this PS_RDY tells us it's - * ok to turn VCONN off - */ - if (pd.flags & PD_FLAGS_VCONN_ON) - set_state( PD_STATE_VCONN_SWAP_READY); -#endif - } else if (pd.task_state == PD_STATE_SNK_DISCOVERY) { - /* Don't know what power source is ready. Reset. */ - set_state(PD_STATE_HARD_RESET_SEND); - } else if (pd.task_state == PD_STATE_SNK_SWAP_STANDBY) { - /* Do nothing, assume this is a redundant PD_RDY */ - } else if (pd.power_role == PD_ROLE_SINK) { - set_state (PD_STATE_SNK_READY); - pd_set_input_current_limit(pd.curr_limit, - pd.supply_voltage); -#ifdef CONFIG_CHARGE_MANAGER - /* Set ceiling based on what's negotiated */ - //charge_manager_set_ceil( - // CEIL_REQUESTOR_PD, - // pd.curr_limit); -#endif - } - break; -#endif - case PD_CTRL_REJECT: - case PD_CTRL_WAIT: - if (pd.task_state == PD_STATE_DR_SWAP) - set_state(READY_RETURN_STATE()); -#ifdef CONFIG_USBC_VCONN_SWAP - else if (pd.task_state == PD_STATE_VCONN_SWAP_SEND) - set_state( READY_RETURN_STATE()); -#endif -#ifdef CONFIG_USB_PD_DUAL_ROLE - else if (pd.task_state == PD_STATE_SRC_SWAP_INIT) - set_state(PD_STATE_SRC_READY); - else if (pd.task_state == PD_STATE_SNK_SWAP_INIT) - set_state (PD_STATE_SNK_READY); - else if (pd.task_state == PD_STATE_SNK_REQUESTED) { - /* - * Explicit Contract in place - * - * On reception of a WAIT message, transition to - * PD_STATE_SNK_READY after PD_T_SINK_REQUEST ms to - * send another reqest. - * - * On reception of a REJECT messag, transition to - * PD_STATE_SNK_READY but don't resend the request. - * - * NO Explicit Contract in place - * - * On reception of a WAIT or REJECT message, - * transition to PD_STATE_SNK_DISCOVERY - */ - if (pd.flags & PD_FLAGS_EXPLICIT_CONTRACT) { - /* We have an explicit contract */ - if (type == PD_CTRL_WAIT) { - /* - * Trigger a new power request when - * we enter PD_STATE_SNK_READY - */ - pd.new_power_request = 1; - - /* - * After the request is triggered, - * make sure the request is sent. - */ - pd.prev_request_mv = 0; - - /* - * Transition to PD_STATE_SNK_READY - * after PD_T_SINK_REQUEST ms. - */ - set_state_timeout(get_time().val + - PD_T_SINK_REQUEST, PD_STATE_SNK_READY); - } else { - /* The request was rejected */ - set_state(PD_STATE_SNK_READY); - } - } else { - /* No explicit contract */ - set_state (PD_STATE_SNK_DISCOVERY); - } - } -#endif - break; - case PD_CTRL_ACCEPT: - if (pd.task_state == PD_STATE_SOFT_RESET) { - /* - * For the case that we sent soft reset in SNK_DISCOVERY - * on startup due to VBUS never low, clear the flag. - */ - pd.flags &= ~PD_FLAGS_VBUS_NEVER_LOW; - execute_soft_reset(); - } else if (pd.task_state == PD_STATE_DR_SWAP) { - /* switch data role */ - pd_dr_swap(); - set_state(READY_RETURN_STATE()); -#ifdef CONFIG_USB_PD_DUAL_ROLE -#ifdef CONFIG_USBC_VCONN_SWAP - } else if (pd.task_state == PD_STATE_VCONN_SWAP_SEND) { - /* switch vconn */ - set_state( PD_STATE_VCONN_SWAP_INIT); -#endif - } else if (pd.task_state == PD_STATE_SRC_SWAP_INIT) { - /* explicit contract goes away for power swap */ - pd.flags &= ~PD_FLAGS_EXPLICIT_CONTRACT; - set_state (PD_STATE_SRC_SWAP_SNK_DISABLE); - } else if (pd.task_state == PD_STATE_SNK_SWAP_INIT) { - /* explicit contract goes away for power swap */ - pd.flags &= ~PD_FLAGS_EXPLICIT_CONTRACT; - set_state (PD_STATE_SNK_SWAP_SNK_DISABLE); - } else if (pd.task_state == PD_STATE_SNK_REQUESTED) { - /* explicit contract is now in place */ - pd.flags |= PD_FLAGS_EXPLICIT_CONTRACT; -#ifdef CONFIG_BBRAM - pd_set_saved_active( 1); -#endif - set_state (PD_STATE_SNK_TRANSITION); -#endif - } - break; - case PD_CTRL_SOFT_RESET: - execute_soft_reset(); - /* We are done, acknowledge with an Accept packet */ - send_control(PD_CTRL_ACCEPT); - break; - case PD_CTRL_PR_SWAP: -#ifdef CONFIG_USB_PD_DUAL_ROLE - if (pd_check_power_swap()) { - send_control(PD_CTRL_ACCEPT); - /* - * Clear flag for checking power role to avoid - * immediately requesting another swap. - */ - pd.flags &= ~PD_FLAGS_CHECK_PR_ROLE; - set_state( - DUAL_ROLE_IF_ELSE(PD_STATE_SNK_SWAP_SNK_DISABLE, - PD_STATE_SRC_SWAP_SNK_DISABLE)); - } else { - send_control(REFUSE(pd.rev)); - } -#else - send_control(REFUSE(pd.rev)); -#endif - break; - case PD_CTRL_DR_SWAP: - if (pd_check_data_swap(pd.data_role)) { - /* - * Accept switch and perform data swap. Clear - * flag for checking data role to avoid - * immediately requesting another swap. - */ - pd.flags &= ~PD_FLAGS_CHECK_DR_ROLE; - if (send_control(PD_CTRL_ACCEPT) >= 0) - pd_dr_swap(); - } else { - send_control(REFUSE(pd.rev)); - - } - break; - case PD_CTRL_VCONN_SWAP: -#ifdef CONFIG_USBC_VCONN_SWAP - if (pd.task_state == PD_STATE_SRC_READY || - pd.task_state == PD_STATE_SNK_READY) { - if (pd_check_vconn_swap()) { - if (send_control( PD_CTRL_ACCEPT) > 0) - set_state( - PD_STATE_VCONN_SWAP_INIT); - } else { - send_control( REFUSE(pd.rev)); - } - } -#else - send_control(REFUSE(pd.rev)); -#endif - break; - default: -#ifdef CONFIG_USB_PD_REV30 - send_control( PD_CTRL_NOT_SUPPORTED); -#endif - CPRINTF("Unhandled ctrl message type %d\n", type); - } -} - -#ifdef CONFIG_USB_PD_REV30 -static void handle_ext_request( uint16_t head, uint32_t *payload) -{ - int type = PD_HEADER_TYPE(head); - - switch (type) { - case PD_EXT_GET_BATTERY_CAP: - send_battery_cap( payload); - break; - case PD_EXT_GET_BATTERY_STATUS: - send_battery_status( payload); - break; - case PD_EXT_BATTERY_CAP: - break; - default: - send_control( PD_CTRL_NOT_SUPPORTED); - } -} -#endif - -static void handle_request(uint16_t head, uint32_t *payload) { - int cnt = PD_HEADER_CNT(head); - int p; - - /* dump received packet content (only dump ping at debug level 3) */ - if ((debug_level == 2 && PD_HEADER_TYPE(head) != PD_CTRL_PING) - || debug_level >= 3) { - CPRINTF("RECV %04x/%d ", head, cnt); - for (p = 0; p < cnt; p++) - CPRINTF("[%d]%08x ", p, payload[p]);CPRINTF("\n"); - } - - /* - * If we are in disconnected state, we shouldn't get a request. - * Ignore it if we get one. - */ - if (!pd_is_connected()) - return; - -#ifdef CONFIG_USB_PD_REV30 - /* Check if this is an extended chunked data message. */ - if (pd.rev == PD_REV30 && PD_HEADER_EXT(head)) { - handle_ext_request( head, payload); - return; - } -#endif - if (cnt) - handle_data_request(head, payload); - else - handle_ctrl_request(head, payload); -} - -void pd_send_vdm(uint32_t vid, int cmd, const uint32_t *data, int count) { - if (count > VDO_MAX_SIZE - 1) { - CPRINTF("VDM over max size\n"); - return; - } - - /* set VDM header with VID & CMD */ - pd.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.vdo_data[0] |= VDO_SVDM_VERS(vdo_ver[pd.rev]); -#endif - queue_vdm(pd.vdo_data, data, count); - - // getting rid of task stuff - //task_wake(PD_PORT_TO_TASK_ID()); -} - -static inline int pdo_busy() { - /* - * Note, main PDO state machine (pd_task) uses READY state exclusively - * to denote port partners have successfully negociated a contract. All - * other protocol actions force state transitions. - */ - int rv = (pd.task_state != PD_STATE_SRC_READY); -#ifdef CONFIG_USB_PD_DUAL_ROLE - rv &= (pd.task_state != PD_STATE_SNK_READY); -#endif - return rv; -} - -static uint64_t vdm_get_ready_timeout(uint32_t vdm_hdr) { - uint64_t timeout; - int cmd = PD_VDO_CMD(vdm_hdr); - - /* its not a structured VDM command */ - if (!PD_VDO_SVDM(vdm_hdr)) - return 500 * MSEC; - - switch (PD_VDO_CMDT(vdm_hdr)) { - case CMDT_INIT: - if ((cmd == CMD_ENTER_MODE) || (cmd == CMD_EXIT_MODE)) - timeout = PD_T_VDM_WAIT_MODE_E; - else - timeout = PD_T_VDM_SNDR_RSP; - break; - default: - if ((cmd == CMD_ENTER_MODE) || (cmd == CMD_EXIT_MODE)) - timeout = PD_T_VDM_E_MODE; - else - timeout = PD_T_VDM_RCVR_RSP; - break; - } - return timeout; -} - -static void pd_vdm_send_state_machine() { - int res; - uint16_t header; - - switch (pd.vdm_state) { - case VDM_STATE_READY: - /* Only transmit VDM if connected. */ - if (!pd_is_connected()) { - pd.vdm_state = VDM_STATE_ERR_BUSY; - break; - } - - /* - * if there's traffic or we're not in PDO ready state don't send - * a VDM. - */ - if (pdo_busy()) - break; - - /* Prepare and send VDM */ - header = PD_HEADER(PD_DATA_VENDOR_DEF, pd.power_role, pd.data_role, - pd.msg_id, (int )pd.vdo_count, pd_get_rev(), 0); - res = pd_transmit(TCPC_TX_SOP, header, pd.vdo_data); - if (res < 0) { - pd.vdm_state = VDM_STATE_ERR_SEND; - } else { - pd.vdm_state = VDM_STATE_BUSY; - pd.vdm_timeout.val = get_time().val - + vdm_get_ready_timeout(pd.vdo_data[0]); - } - break; - case VDM_STATE_WAIT_RSP_BUSY: - /* wait and then initiate request again */ - if (get_time().val > pd.vdm_timeout.val) { - pd.vdo_data[0] = pd.vdo_retry; - pd.vdo_count = 1; - pd.vdm_state = VDM_STATE_READY; - } - break; - case VDM_STATE_BUSY: - /* Wait for VDM response or timeout */ - if (pd.vdm_timeout.val && (get_time().val > pd.vdm_timeout.val)) { - pd.vdm_state = VDM_STATE_ERR_TMOUT; - } - break; - default: - break; - } -} - -#ifdef CONFIG_CMD_PD_DEV_DUMP_INFO -static inline void pd_dev_dump_info(uint16_t dev_id, uint8_t *hash) -{ - int j; - ccprintf("DevId:%d.%d Hash:", HW_DEV_ID_MAJ(dev_id), - HW_DEV_ID_MIN(dev_id)); - for (j = 0; j < PD_RW_HASH_SIZE; j += 4) { - ccprintf(" 0x%02x%02x%02x%02x", hash[j + 3], hash[j + 2], - hash[j + 1], hash[j]); - } - ccprintf("\n"); -} -#endif /* CONFIG_CMD_PD_DEV_DUMP_INFO */ - -int pd_dev_store_rw_hash(uint16_t dev_id, uint32_t *rw_hash, - uint32_t current_image) { -#ifdef CONFIG_COMMON_RUNTIME - int i; -#endif - -#ifdef CONFIG_USB_PD_CHROMEOS - pd.dev_id = dev_id; - memcpy(pd.dev_rw_hash, rw_hash, PD_RW_HASH_SIZE); -#endif -#ifdef CONFIG_CMD_PD_DEV_DUMP_INFO - if (debug_level >= 2) - pd_dev_dump_info(dev_id, (uint8_t *)rw_hash); -#endif -#ifdef CONFIG_USB_PD_CHROMEOS - pd.current_image = current_image; -#endif - -#ifdef CONFIG_COMMON_RUNTIME - /* Search table for matching device / hash */ - for (i = 0; i < RW_HASH_ENTRIES; i++) - if (dev_id == rw_hash_table[i].dev_id) - return !memcmp(rw_hash, - rw_hash_table[i].dev_rw_hash, - PD_RW_HASH_SIZE); -#endif - return 0; -} - -#ifdef CONFIG_USB_PD_DUAL_ROLE -enum pd_dual_role_states pd_get_dual_role(void) { - return drp_state; -} - -#ifdef CONFIG_USB_PD_TRY_SRC -static void pd_update_try_source(void) -{ - int i; - -#ifndef CONFIG_CHARGER - int batt_soc = board_get_battery_soc(); -#else - int batt_soc = charge_get_percent(); -#endif - - /* - * Enable try source when dual-role toggling AND battery is present - * and at some minimum percentage. - */ - pd_try_src_enable = drp_state == PD_DRP_TOGGLE_ON && - batt_soc >= CONFIG_USB_PD_TRY_SRC_MIN_BATT_SOC; -#if defined(CONFIG_BATTERY_PRESENT_CUSTOM) || \ - defined(CONFIG_BATTERY_PRESENT_GPIO) - /* - * When battery is cutoff in ship mode it may not be reliable to - * check if battery is present with its state of charge. - * Also check if battery is initialized and ready to provide power. - */ - pd_try_src_enable &= (battery_is_present() == BP_YES); -#endif - - /* - * Clear this flag to cover case where a TrySrc - * mode went from enabled to disabled and trying_source - * was active at that time. - */ - for (i = 0; i < CONFIG_USB_PD_PORT_COUNT; i++) - pd[i].flags &= ~PD_FLAGS_TRY_SRC; - -} -DECLARE_HOOK(HOOK_BATTERY_SOC_CHANGE, pd_update_try_source, HOOK_PRIO_DEFAULT); -#endif - -void pd_set_dual_role(enum pd_dual_role_states state) { - int i; - drp_state = 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++) - // getting rid of task stuff - //task_set_event(PD_PORT_TO_TASK_ID(i), - // PD_EVENT_UPDATE_DUAL_ROLE, 0); - ; -} - -void pd_update_dual_role_config() { - /* - * Change to sink if port is currently a source AND (new DRP - * state is force sink OR new DRP state is either toggle off - * or debug accessory toggle only and we are in the source - * disconnected state). - */ - if (pd.power_role == PD_ROLE_SOURCE - && ((drp_state == PD_DRP_FORCE_SINK && !pd_ts_dts_plugged()) - || (drp_state == PD_DRP_TOGGLE_OFF - && pd.task_state == PD_STATE_SRC_DISCONNECTED))) { - pd.power_role = PD_ROLE_SINK; - set_state (PD_STATE_SNK_DISCONNECTED); - tcpm_set_cc(TYPEC_CC_RD); - /* Make sure we're not sourcing VBUS. */ - pd_power_supply_reset(); - } - - /* - * Change to source if port is currently a sink and the - * new DRP state is force source. - */ - if (pd.power_role == PD_ROLE_SINK - && drp_state == PD_DRP_FORCE_SOURCE) { - pd.power_role = PD_ROLE_SOURCE; - set_state(PD_STATE_SRC_DISCONNECTED); - tcpm_set_cc(TYPEC_CC_RP); - } - -#if defined(CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE) && \ - defined(CONFIG_USB_PD_TCPC_LOW_POWER) - /* When switching drp mode, make sure tcpc is out of standby mode */ - tcpm_set_drp_toggle( 0); -#endif -} - -int pd_get_role() { - return pd.power_role; -} - -static int pd_is_power_swapping() { - /* return true if in the act of swapping power roles */ - return pd.task_state == PD_STATE_SNK_SWAP_SNK_DISABLE - || pd.task_state == PD_STATE_SNK_SWAP_SRC_DISABLE - || pd.task_state == PD_STATE_SNK_SWAP_STANDBY - || pd.task_state == PD_STATE_SNK_SWAP_COMPLETE - || pd.task_state == PD_STATE_SRC_SWAP_SNK_DISABLE - || pd.task_state == PD_STATE_SRC_SWAP_SRC_DISABLE - || pd.task_state == PD_STATE_SRC_SWAP_STANDBY; -} - -/* - * Provide Rp to ensure the partner port is in a known state (eg. not - * PD negotiated, not sourcing 20V). - */ -static void pd_partner_port_reset() { - uint64_t timeout; - -#ifdef CONFIG_BBRAM - /* - * Check our battery-backed previous port state. If PD comms were - * active, and we didn't just lose power, make sure we - * don't boot into RO with a pre-existing power contract. - */ - if (!pd_get_saved_active() || - system_get_image_copy() != SYSTEM_IMAGE_RO || - system_get_reset_flags() & - (RESET_FLAG_BROWNOUT | RESET_FLAG_POWER_ON)) - return; -#endif // CONFIG_BBRAM - /* Provide Rp for 100 msec. or until we no longer have VBUS. */ - tcpm_set_cc(TYPEC_CC_RP); - timeout = get_time().val + 100 * MSEC; - - while (get_time().val < timeout && pd_is_vbus_present()) - msleep(10); -#ifdef CONFIG_BBRAM - pd_set_saved_active( 0); -#endif -} -#endif /* CONFIG_USB_PD_DUAL_ROLE */ - -int pd_get_polarity() { - return pd.polarity; -} - -int pd_get_partner_data_swap_capable() { - /* return data swap capable status of port partner */ - return pd.flags & PD_FLAGS_PARTNER_DR_DATA; -} - -#ifdef CONFIG_COMMON_RUNTIME -void pd_comm_enable( int enable) -{ - /* We don't check port >= CONFIG_USB_PD_PORT_COUNT deliberately */ - pd_comm_enabled[port] = enable; - - /* If type-C connection, then update the TCPC RX enable */ - if (pd_is_connected()) - tcpm_set_rx_enable( enable); - -#ifdef CONFIG_USB_PD_DUAL_ROLE - /* - * If communications are enabled, start hard reset timer for - * any port in PD_SNK_DISCOVERY. - */ - if (enable && pd.task_state == PD_STATE_SNK_DISCOVERY) - set_state_timeout( - get_time().val + PD_T_SINK_WAIT_CAP, - PD_STATE_HARD_RESET_SEND); -#endif -} -#endif - -void pd_ping_enable(int enable) { - if (enable) - pd.flags |= PD_FLAGS_PING_ENABLED; - else - pd.flags &= ~PD_FLAGS_PING_ENABLED; -} - -/** - * Returns whether the sink has detected a Rp resistor on the other side. - */ -static inline int cc_is_rp(int cc) { - return (cc == TYPEC_CC_VOLT_SNK_DEF) || (cc == TYPEC_CC_VOLT_SNK_1_5) - || (cc == TYPEC_CC_VOLT_SNK_3_0); -} - -/* - * CC values for regular sources and Debug sources (aka DTS) - * - * Source type Mode of Operation CC1 CC2 - * --------------------------------------------- - * Regular Default USB Power RpUSB Open - * Regular USB-C @ 1.5 A Rp1A5 Open - * Regular USB-C @ 3 A Rp3A0 Open - * DTS Default USB Power Rp3A0 Rp1A5 - * DTS USB-C @ 1.5 A Rp1A5 RpUSB - * DTS USB-C @ 3 A Rp3A0 RpUSB - */ - -/** - * Returns the polarity of a Sink. - */ -static inline int get_snk_polarity(int cc1, int cc2) { - /* the following assumes: - * TYPEC_CC_VOLT_SNK_3_0 > TYPEC_CC_VOLT_SNK_1_5 - * TYPEC_CC_VOLT_SNK_1_5 > TYPEC_CC_VOLT_SNK_DEF - * TYPEC_CC_VOLT_SNK_DEF > TYPEC_CC_VOLT_OPEN - */ - return (cc2 > cc1); -} - -#if defined(CONFIG_CHARGE_MANAGER) -/** - * Returns type C current limit (mA) based upon cc_voltage (mV). - */ -static typec_current_t get_typec_current_limit(int polarity, int cc1, int cc2) { - typec_current_t charge; - int cc = polarity ? cc2 : cc1; - int cc_alt = polarity ? cc1 : cc2; - - if (cc == TYPEC_CC_VOLT_SNK_3_0 && cc_alt != TYPEC_CC_VOLT_SNK_1_5) - charge = 3000; - else if (cc == TYPEC_CC_VOLT_SNK_1_5) - charge = 1500; - else - charge = 0; - - if (cc_is_rp(cc_alt)) - charge |= TYPEC_CURRENT_DTS_MASK; - - return charge; -} - -/** - * Signal power request to indicate a charger update that affects the port. - */ -void pd_set_new_power_request() { -// pd.new_power_request = 1; - // getting rid of task stuff - //task_wake(PD_PORT_TO_TASK_ID()); -} -#endif /* CONFIG_CHARGE_MANAGER */ - -#if defined(CONFIG_USBC_BACKWARDS_COMPATIBLE_DFP) && defined(CONFIG_USBC_SS_MUX) -/* - * Backwards compatible DFP does not support USB SS because it applies VBUS - * before debouncing CC and setting USB SS muxes, but SS detection will fail - * before we are done debouncing CC. - */ -#error "Backwards compatible DFP does not support USB" -#endif - -#ifdef CONFIG_COMMON_RUNTIME - -/* Initialize globals based on system state. */ -static void pd_init_tasks(void) -{ - static int initialized; - int enable = 1; - int i; - - /* Initialize globals once, for all PD tasks. */ - if (initialized) - return; - -#if defined(HAS_TASK_CHIPSET) && defined(CONFIG_USB_PD_DUAL_ROLE) - /* Set dual-role state based on chipset power state */ - if (chipset_in_state(CHIPSET_STATE_ANY_OFF)) - drp_state = PD_DRP_FORCE_SINK; - else if (chipset_in_state(CHIPSET_STATE_SUSPEND)) - drp_state = PD_DRP_TOGGLE_OFF; - else /* CHIPSET_STATE_ON */ - drp_state = PD_DRP_TOGGLE_ON; -#endif - -#if defined(CONFIG_USB_PD_COMM_DISABLED) - enable = 0; -#elif defined(CONFIG_USB_PD_COMM_LOCKED) - /* Disable PD communication at init if we're in RO and locked. */ - if (!system_is_in_rw() && system_is_locked()) - enable = 0; -#endif - for (i = 0; i < CONFIG_USB_PD_PORT_COUNT; i++) - pd_comm_enabled[i] = enable; - CPRINTS("PD comm %sabled", enable ? "en" : "dis"); - - initialized = 1; -} -#endif /* CONFIG_COMMON_RUNTIME */ - -#ifndef CONFIG_USB_PD_TCPC -static int pd_restart_tcpc() { - if (board_set_tcpc_power_mode) { - /* force chip reset */ - board_set_tcpc_power_mode(0); - } - return tcpm_init(); -} -#endif - -void pd_init() { -#ifdef CONFIG_COMMON_RUNTIME - pd_init_tasks(); -#endif - - /* Ensure the power supply is in the default state */ - pd_power_supply_reset(); - -#ifdef CONFIG_USB_PD_TCPC_BOARD_INIT - /* Board specific TCPC init */ - board_tcpc_init(); -#endif - - /* Initialize TCPM driver and wait for TCPC to be ready */ - res = tcpm_init(); - -#ifdef CONFIG_USB_PD_DUAL_ROLE - //pd_partner_port_reset(); -#endif - - CPRINTS("TCPC p%d init %s", port, res ? "failed" : "ready"); - this_state = res ? PD_STATE_SUSPENDED : PD_DEFAULT_STATE(); -#ifndef CONFIG_USB_PD_TCPC - if (!res) { - struct ec_response_pd_chip_info *info; - tcpm_get_chip_info(0, &info); - CPRINTS("TCPC p%d VID:0x%x PID:0x%x DID:0x%x FWV:0x%lx", - port, info->vendor_id, info->product_id, - info->device_id, info->fw_version_number); - } -#endif - -#ifdef CONFIG_USB_PD_REV30 - /* Set Revision to highest */ - pd.rev = PD_REV30; - pd_ca_reset(); -#endif - -#ifdef CONFIG_USB_PD_DUAL_ROLE - /* - * If VBUS is high, then initialize flag for VBUS has always been - * present. This flag is used to maintain a PD connection after a - * reset by sending a soft reset. - */ - //pd.flags = pd_is_vbus_present() ? PD_FLAGS_VBUS_NEVER_LOW : 0; - pd.flags = 0; -#endif - - /* Disable TCPC RX until connection is established */ - tcpm_set_rx_enable(0); - -#ifdef CONFIG_USBC_SS_MUX - /* Initialize USB mux to its default state */ - usb_mux_init(); -#endif - - /* Initialize PD protocol state variables for each port. */ - pd.power_role = PD_ROLE_DEFAULT(); - pd.vdm_state = VDM_STATE_DONE; - set_state(this_state); -#ifdef CONFIG_USB_PD_MAX_SINGLE_SOURCE_CURRENT - ASSERT(PD_ROLE_DEFAULT() == PD_ROLE_SINK); - tcpm_select_rp_value( CONFIG_USB_PD_MAX_SINGLE_SOURCE_CURRENT); -#else - tcpm_select_rp_value( CONFIG_USB_PD_PULLUP); -#endif - tcpm_set_cc( - PD_ROLE_DEFAULT() == PD_ROLE_SOURCE ? TYPEC_CC_RP : TYPEC_CC_RD); - -#ifdef CONFIG_USB_PD_ALT_MODE_DFP - /* Initialize PD Policy engine */ - pd_dfp_pe_init(); -#endif - -#ifdef CONFIG_CHARGE_MANAGER - /* Initialize PD and type-C supplier current limits to 0 */ - pd_set_input_current_limit(0, 0); - //typec_set_input_current_limit( 0, 0); - //charge_manager_update_dualrole( CAP_UNKNOWN); -#endif -} - -void pd_run_state_machine() { -#ifdef CONFIG_USB_PD_REV30 - /* send any pending messages */ - pd_ca_send_pending(); -#endif - /* process VDM messages last */ - pd_vdm_send_state_machine(); - - /* Verify board specific health status : current, voltages... */ - res = pd_board_checks(); - if (res != EC_SUCCESS) { - /* cut the power */ - pd_execute_hard_reset(); - /* notify the other side of the issue */ - pd_transmit(TCPC_TX_HARD_RESET, 0, NULL); - } - - /* wait for next event/packet or timeout expiration */ - // getting rid of task stuff - //evt = task_wait_event(timeout); -#ifdef CONFIG_USB_PD_DUAL_ROLE - if (evt & PD_EVENT_UPDATE_DUAL_ROLE) - pd_update_dual_role_config(); -#endif - -#ifdef CONFIG_USB_PD_TCPC - /* - * run port controller task to check CC and/or read incoming - * messages - */ - tcpc_run( evt); -#else - /* if TCPC has reset, then need to initialize it again */ - if (evt & PD_EVENT_TCPC_RESET) { - CPRINTS("TCPC p%d reset!", port); - if (tcpm_init() != EC_SUCCESS) - CPRINTS("TCPC p%d init failed", port); -#ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE - } - - if ((evt & PD_EVENT_TCPC_RESET) && - (pd.task_state != PD_STATE_DRP_AUTO_TOGGLE)) { -#endif - /* Ensure CC termination is default */ - tcpm_set_cc( PD_ROLE_DEFAULT() == - PD_ROLE_SOURCE ? TYPEC_CC_RP : TYPEC_CC_RD); - - /* - * If we have a stable contract in the default role, - * then simply update TCPC with some missing info - * so that we can continue without resetting PD comms. - * Otherwise, go to the default disconnected state - * and force renegotiation. - */ - if (pd.vdm_state == VDM_STATE_DONE - && ( -#ifdef CONFIG_USB_PD_DUAL_ROLE - (PD_ROLE_DEFAULT() == PD_ROLE_SINK - && pd.task_state == PD_STATE_SNK_READY) - || -#endif - (PD_ROLE_DEFAULT() == PD_ROLE_SOURCE - && pd.task_state == PD_STATE_SRC_READY))) { - tcpm_set_polarity(pd.polarity); - tcpm_set_msg_header(pd.power_role, pd.data_role); - tcpm_set_rx_enable(1); - } else { - /* Ensure state variables are at default */ - pd.power_role = PD_ROLE_DEFAULT(); - pd.vdm_state = VDM_STATE_DONE; - set_state(PD_DEFAULT_STATE()); - } - } -#endif - - /* process any potential incoming message */ - incoming_packet = evt & PD_EVENT_RX; - //if (incoming_packet) { - if (!tcpm_get_message(payload, &head)) - handle_request(head, payload); - //} - - if (pd.req_suspend_state) - set_state(PD_STATE_SUSPENDED); - - /* if nothing to do, verify the state of the world in 500ms */ - this_state = pd.task_state; - timeout = 500 * MSEC; - switch (this_state) { - case PD_STATE_DISABLED: - /* Nothing to do */ - break; - case PD_STATE_SRC_DISCONNECTED: - timeout = 10 * MSEC; - tcpm_get_cc(&cc1, &cc2); -#ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE - /* - * Attempt TCPC auto DRP toggle if it is - * not already auto toggling and not try.src - */ - if (auto_toggle_supported && - !(pd.flags & PD_FLAGS_TCPC_DRP_TOGGLE) && - !(pd.flags & PD_FLAGS_TRY_SRC) && - (cc1 == TYPEC_CC_VOLT_OPEN && - cc2 == TYPEC_CC_VOLT_OPEN)) { - set_state( PD_STATE_DRP_AUTO_TOGGLE); - timeout = 2*MSEC; - break; - } -#endif - - /* Vnc monitoring */ - if ((cc1 == TYPEC_CC_VOLT_RD || cc2 == TYPEC_CC_VOLT_RD) - || (cc1 == TYPEC_CC_VOLT_RA && cc2 == TYPEC_CC_VOLT_RA)) { -#ifdef CONFIG_USBC_BACKWARDS_COMPATIBLE_DFP - /* Enable VBUS */ - if (pd_set_power_supply_ready()) - break; -#endif - pd.cc_state = PD_CC_NONE; - set_state(PD_STATE_SRC_DISCONNECTED_DEBOUNCE); - } -#if defined(CONFIG_USB_PD_DUAL_ROLE) - /* - * Try.SRC state is embedded here. Wait for SNK - * detect, or if timer expires, transition to - * SNK_DISCONNETED. - * - * If Try.SRC state is not active, then this block - * handles the normal DRP toggle from SRC->SNK - */ - else if ((pd.flags & PD_FLAGS_TRY_SRC - && get_time().val >= pd.try_src_marker) - || (!(pd.flags & PD_FLAGS_TRY_SRC) - && drp_state != PD_DRP_FORCE_SOURCE - && drp_state != PD_DRP_FREEZE - && get_time().val >= next_role_swap)) { - pd.power_role = PD_ROLE_SINK; - set_state (PD_STATE_SNK_DISCONNECTED); - tcpm_set_cc(TYPEC_CC_RD); - next_role_swap = get_time().val + PD_T_DRP_SNK; - pd.try_src_marker = get_time().val + PD_T_TRY_WAIT; - - /* Swap states quickly */ - timeout = 2 * MSEC; - } -#endif - break; - case PD_STATE_SRC_DISCONNECTED_DEBOUNCE: - timeout = 20 * MSEC; - tcpm_get_cc(&cc1, &cc2); - - if (cc1 == TYPEC_CC_VOLT_RD && cc2 == TYPEC_CC_VOLT_RD) { - /* Debug accessory */ - new_cc_state = PD_CC_DEBUG_ACC; - } else if (cc1 == TYPEC_CC_VOLT_RD || cc2 == TYPEC_CC_VOLT_RD) { - /* UFP attached */ - new_cc_state = PD_CC_UFP_ATTACHED; - } else if (cc1 == TYPEC_CC_VOLT_RA && cc2 == TYPEC_CC_VOLT_RA) { - /* Audio accessory */ - new_cc_state = PD_CC_AUDIO_ACC; - } else { - /* No UFP */ - set_state(PD_STATE_SRC_DISCONNECTED); - timeout = 5 * MSEC; - break; - } - /* If in Try.SRC state, then don't need to debounce */ - if (!(pd.flags & PD_FLAGS_TRY_SRC)) { - /* Debounce the cc state */ - if (new_cc_state != pd.cc_state) { - pd.cc_debounce = get_time().val + - PD_T_CC_DEBOUNCE; - pd.cc_state = new_cc_state; - break; - } else if (get_time().val < pd.cc_debounce) { - break; - } - } - - /* Debounce complete */ - /* UFP is attached */ - if (new_cc_state == PD_CC_UFP_ATTACHED - || new_cc_state == PD_CC_DEBUG_ACC) { - pd.polarity = (cc1 != TYPEC_CC_VOLT_RD); - tcpm_set_polarity(pd.polarity); - - /* initial data role for source is DFP */ - pd_set_data_role( PD_ROLE_DFP); - - if (new_cc_state == PD_CC_DEBUG_ACC) - pd.flags |= - PD_FLAGS_TS_DTS_PARTNER; - -#ifndef CONFIG_USBC_BACKWARDS_COMPATIBLE_DFP - /* Enable VBUS */ - if (pd_set_power_supply_ready()) { -#ifdef CONFIG_USBC_SS_MUX - usb_mux_set( TYPEC_MUX_NONE, - USB_SWITCH_DISCONNECT, - pd.polarity); -#endif - break; - } -#endif - /* If PD comm is enabled, enable TCPC RX */ - if (pd_comm_is_enabled()) - tcpm_set_rx_enable(1); - -#ifdef CONFIG_USBC_VCONN - tcpm_set_vconn( 1); - pd.flags |= PD_FLAGS_VCONN_ON; -#endif - - pd.flags |= PD_FLAGS_CHECK_PR_ROLE | - PD_FLAGS_CHECK_DR_ROLE; - hard_reset_count = 0; - timeout = 5 * MSEC; - set_state(PD_STATE_SRC_STARTUP); - } - /* - * AUDIO_ACC will remain in this state indefinitely - * until disconnect. - */ - break; - case PD_STATE_SRC_HARD_RESET_RECOVER: - /* Do not continue until hard reset recovery time */ - if (get_time().val < pd.src_recover) { - timeout = 50 * MSEC; - break; - } - - /* Enable VBUS */ - timeout = 10 * MSEC; - if (pd_set_power_supply_ready()) { - set_state(PD_STATE_SRC_DISCONNECTED); - break; - } -#ifdef CONFIG_USB_PD_TCPM_TCPCI - /* - * After transmitting hard reset, TCPM writes - * to RECEIVE_DETECT register to enable - * PD message passing. - */ - if (pd_comm_is_enabled()) - tcpm_set_rx_enable( 1); -#endif /* CONFIG_USB_PD_TCPM_TCPCI */ - - set_state(PD_STATE_SRC_STARTUP); - break; - case PD_STATE_SRC_STARTUP: - /* Wait for power source to enable */ - if (pd.last_state != pd.task_state) { - pd.flags |= PD_FLAGS_CHECK_IDENTITY; - /* reset various counters */ - caps_count = 0; - pd.msg_id = 0; - snk_cap_count = 0; - set_state_timeout( -#ifdef CONFIG_USBC_BACKWARDS_COMPATIBLE_DFP - /* - * delay for power supply to start up. - * subtract out debounce time if coming - * from debounce state since vbus is - * on during debounce. - */ - get_time().val + - PD_POWER_SUPPLY_TURN_ON_DELAY - - (pd.last_state == - PD_STATE_SRC_DISCONNECTED_DEBOUNCE - ? PD_T_CC_DEBOUNCE : 0), -#else - get_time().val + - PD_POWER_SUPPLY_TURN_ON_DELAY, -#endif - PD_STATE_SRC_DISCOVERY); - } - break; - case PD_STATE_SRC_DISCOVERY: - if (pd.last_state != pd.task_state) { - /* - * If we have had PD connection with this port - * partner, then start NoResponseTimer. - */ - if (pd.flags & PD_FLAGS_PREVIOUS_PD_CONN) - set_state_timeout(get_time().val + - PD_T_NO_RESPONSE, - hard_reset_count < - PD_HARD_RESET_COUNT ? - PD_STATE_HARD_RESET_SEND : - PD_STATE_SRC_DISCONNECTED); - } - - /* Send source cap some minimum number of times */ - if (caps_count < PD_CAPS_COUNT) { - /* Query capabilities of the other side */ - res = send_source_cap(); - /* packet was acked => PD capable device) */ - if (res >= 0) { - set_state(PD_STATE_SRC_NEGOCIATE); - timeout = 10 * MSEC; - hard_reset_count = 0; - caps_count = 0; - /* Port partner is PD capable */ - pd.flags |= - PD_FLAGS_PREVIOUS_PD_CONN; - } else { /* failed, retry later */ - timeout = PD_T_SEND_SOURCE_CAP; - caps_count++; - } - } - break; - case PD_STATE_SRC_NEGOCIATE: - /* wait for a "Request" message */ - if (pd.last_state != pd.task_state) - set_state_timeout(get_time().val + - PD_T_SENDER_RESPONSE, PD_STATE_HARD_RESET_SEND); - break; - case PD_STATE_SRC_ACCEPTED: - /* Accept sent, wait for enabling the new voltage */ - if (pd.last_state != pd.task_state) - set_state_timeout(get_time().val + - PD_T_SINK_TRANSITION, PD_STATE_SRC_POWERED); - break; - case PD_STATE_SRC_POWERED: - /* Switch to the new requested voltage */ - if (pd.last_state != pd.task_state) { - pd_transition_voltage(pd.requested_idx); - set_state_timeout(get_time().val + - PD_POWER_SUPPLY_TURN_ON_DELAY, PD_STATE_SRC_TRANSITION); - } - break; - case PD_STATE_SRC_TRANSITION: - /* the voltage output is good, notify the source */ - res = send_control(PD_CTRL_PS_RDY); - if (res >= 0) { - timeout = 10 * MSEC; - /* it'a time to ping regularly the sink */ - set_state(PD_STATE_SRC_READY); - } else { - /* The sink did not ack, cut the power... */ - set_state(PD_STATE_SRC_DISCONNECTED); - } - break; - case PD_STATE_SRC_READY: - timeout = PD_T_SOURCE_ACTIVITY; - - /* - * Don't send any PD traffic if we woke up due to - * incoming packet or if VDO response pending to avoid - * collisions. - */ - if (incoming_packet || (pd.vdm_state == VDM_STATE_BUSY)) - break; - - /* Send updated source capabilities to our partner */ - if (pd.flags & PD_FLAGS_UPDATE_SRC_CAPS) { - res = send_source_cap(); - if (res >= 0) { - set_state(PD_STATE_SRC_NEGOCIATE); - pd.flags &= ~PD_FLAGS_UPDATE_SRC_CAPS; - } - break; - } - - /* Send get sink cap if haven't received it yet */ - if (!(pd.flags & PD_FLAGS_SNK_CAP_RECVD)) { - if (++snk_cap_count <= PD_SNK_CAP_RETRIES) { - /* Get sink cap to know if dual-role device */ - send_control(PD_CTRL_GET_SINK_CAP); - set_state(PD_STATE_SRC_GET_SINK_CAP); - break; - } else if (debug_level >= 2 - && snk_cap_count == PD_SNK_CAP_RETRIES + 1) { - CPRINTF("ERR SNK_CAP\n"); - } - } - - /* Check power role policy, which may trigger a swap */ - if (pd.flags & PD_FLAGS_CHECK_PR_ROLE) { - pd_check_pr_role( PD_ROLE_SOURCE, pd.flags); - pd.flags &= ~PD_FLAGS_CHECK_PR_ROLE; - break; - } - - /* Check data role policy, which may trigger a swap */ - if (pd.flags & PD_FLAGS_CHECK_DR_ROLE) { - pd_check_dr_role(pd.data_role, pd.flags); - pd.flags &= ~PD_FLAGS_CHECK_DR_ROLE; - break; - } - - /* Send discovery SVDMs last */ - if (pd.data_role == PD_ROLE_DFP - && (pd.flags & PD_FLAGS_CHECK_IDENTITY)) { -#ifndef CONFIG_USB_PD_SIMPLE_DFP - pd_send_vdm( USB_SID_PD, - CMD_DISCOVER_IDENT, NULL, 0); -#endif - pd.flags &= ~PD_FLAGS_CHECK_IDENTITY; - break; - } - - if (!(pd.flags & PD_FLAGS_PING_ENABLED)) - break; - - /* Verify that the sink is alive */ - res = send_control(PD_CTRL_PING); - if (res >= 0) - break; - - /* Ping dropped. Try soft reset. */ - set_state(PD_STATE_SOFT_RESET); - timeout = 10 * MSEC; - break; - case PD_STATE_SRC_GET_SINK_CAP: - if (pd.last_state != pd.task_state) - set_state_timeout(get_time().val + - PD_T_SENDER_RESPONSE, PD_STATE_SRC_READY); - break; - case PD_STATE_DR_SWAP: - if (pd.last_state != pd.task_state) { - res = send_control(PD_CTRL_DR_SWAP); - if (res < 0) { - timeout = 10 * MSEC; - /* - * If failed to get goodCRC, send - * soft reset, otherwise ignore - * failure. - */ - set_state( - res == -1 ? PD_STATE_SOFT_RESET : READY_RETURN_STATE()); - break; - } - /* Wait for accept or reject */ - set_state_timeout(get_time().val + - PD_T_SENDER_RESPONSE, READY_RETURN_STATE()); - } - break; -#ifdef CONFIG_USB_PD_DUAL_ROLE - case PD_STATE_SRC_SWAP_INIT: - if (pd.last_state != pd.task_state) { - res = send_control(PD_CTRL_PR_SWAP); - if (res < 0) { - timeout = 10 * MSEC; - /* - * If failed to get goodCRC, send - * soft reset, otherwise ignore - * failure. - */ - set_state(res == -1 ? PD_STATE_SOFT_RESET : PD_STATE_SRC_READY); - break; - } - /* Wait for accept or reject */ - set_state_timeout(get_time().val + - PD_T_SENDER_RESPONSE, PD_STATE_SRC_READY); - } - break; - case PD_STATE_SRC_SWAP_SNK_DISABLE: - /* Give time for sink to stop drawing current */ - if (pd.last_state != pd.task_state) - set_state_timeout(get_time().val + - PD_T_SINK_TRANSITION, PD_STATE_SRC_SWAP_SRC_DISABLE); - break; - case PD_STATE_SRC_SWAP_SRC_DISABLE: - /* Turn power off */ - if (pd.last_state != pd.task_state) { - pd_power_supply_reset(); - set_state_timeout(get_time().val + - PD_POWER_SUPPLY_TURN_OFF_DELAY, PD_STATE_SRC_SWAP_STANDBY); - } - break; - case PD_STATE_SRC_SWAP_STANDBY: - /* Send PS_RDY to let sink know our power is off */ - if (pd.last_state != pd.task_state) { - /* Send PS_RDY */ - res = send_control(PD_CTRL_PS_RDY); - if (res < 0) { - timeout = 10 * MSEC; - set_state(PD_STATE_SRC_DISCONNECTED); - break; - } - /* Switch to Rd and swap roles to sink */ - tcpm_set_cc(TYPEC_CC_RD); - pd.power_role = PD_ROLE_SINK; - /* Wait for PS_RDY from new source */ - set_state_timeout(get_time().val + - PD_T_PS_SOURCE_ON, PD_STATE_SNK_DISCONNECTED); - } - break; - case PD_STATE_SUSPENDED: { -#ifndef CONFIG_USB_PD_TCPC - int rstatus; -#endif - CPRINTS("TCPC p%d suspended!", port); - pd.req_suspend_state = 0; -#ifdef CONFIG_USB_PD_TCPC - pd_rx_disable_monitoring(); - pd_hw_release(); - pd_power_supply_reset(); -#else - rstatus = tcpm_release(); - if (rstatus != 0 && rstatus != EC_ERROR_UNIMPLEMENTED) - CPRINTS("TCPC p%d release failed!", port); -#endif - /* Wait for resume */ - // getting rid of task stuff - //while (pd.task_state == PD_STATE_SUSPENDED) - // task_wait_event(-1); -#ifdef CONFIG_USB_PD_TCPC - pd_hw_init( PD_ROLE_DEFAULT()); - CPRINTS("TCPC p%d resumed!", port); -#else - if (rstatus != EC_ERROR_UNIMPLEMENTED && pd_restart_tcpc() != 0) { - /* stay in PD_STATE_SUSPENDED */ - CPRINTS("TCPC p%d restart failed!", port); - break; - } - set_state(PD_DEFAULT_STATE()); - CPRINTS("TCPC p%d resumed!", port); -#endif - break; - } - case PD_STATE_SNK_DISCONNECTED: -#ifdef CONFIG_USB_PD_LOW_POWER - timeout = drp_state != PD_DRP_TOGGLE_ON ? SECOND - : 10*MSEC; -#else - timeout = 10 * MSEC; -#endif - tcpm_get_cc(&cc1, &cc2); - -#ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE - /* - * Attempt TCPC auto DRP toggle if it is - * not already auto toggling and not try.src - */ - if (auto_toggle_supported && - !(pd.flags & PD_FLAGS_TCPC_DRP_TOGGLE) && - !(pd.flags & PD_FLAGS_TRY_SRC) && - (cc1 == TYPEC_CC_VOLT_OPEN && - cc2 == TYPEC_CC_VOLT_OPEN)) { - set_state( PD_STATE_DRP_AUTO_TOGGLE); - timeout = 2*MSEC; - break; - } -#endif - - /* Source connection monitoring */ - if (cc1 != TYPEC_CC_VOLT_OPEN || cc2 != TYPEC_CC_VOLT_OPEN) { - pd.cc_state = PD_CC_NONE; - hard_reset_count = 0; - new_cc_state = PD_CC_NONE; - pd.cc_debounce = get_time().val + - PD_T_CC_DEBOUNCE; - set_state (PD_STATE_SNK_DISCONNECTED_DEBOUNCE); - timeout = 10 * MSEC; - break; - } - - /* - * If Try.SRC is active and failed to detect a SNK, - * then it transitions to TryWait.SNK. Need to prevent - * normal dual role toggle until tDRPTryWait timer - * expires. - */ - if (pd.flags & PD_FLAGS_TRY_SRC) { - if (get_time().val > pd.try_src_marker) - pd.flags &= ~PD_FLAGS_TRY_SRC; - break; - } - - /* If no source detected, check for role toggle. */ - if (drp_state == PD_DRP_TOGGLE_ON && get_time().val >= next_role_swap) { - /* Swap roles to source */ - pd.power_role = PD_ROLE_SOURCE; - set_state(PD_STATE_SRC_DISCONNECTED); - tcpm_set_cc(TYPEC_CC_RP); - next_role_swap = get_time().val + PD_T_DRP_SRC; - - /* Swap states quickly */ - timeout = 2 * MSEC; - } - break; - case PD_STATE_SNK_DISCONNECTED_DEBOUNCE: - tcpm_get_cc(&cc1, &cc2); - - if (cc_is_rp(cc1) && cc_is_rp(cc2)) { - /* Debug accessory */ - new_cc_state = PD_CC_DEBUG_ACC; - } else if (cc_is_rp(cc1) || cc_is_rp(cc2)) { - new_cc_state = PD_CC_DFP_ATTACHED; - } else { - /* No connection any more */ - set_state (PD_STATE_SNK_DISCONNECTED); - timeout = 5 * MSEC; - break; - } - - timeout = 20 * MSEC; - - /* Debounce the cc state */ - if (new_cc_state != pd.cc_state) { - pd.cc_debounce = get_time().val + - PD_T_CC_DEBOUNCE; - pd.cc_state = new_cc_state; - break; - } - /* Wait for CC debounce and VBUS present */ - if (get_time().val < pd.cc_debounce || !pd_is_vbus_present()) - break; - - if (pd_try_src_enable && !(pd.flags & PD_FLAGS_TRY_SRC)) { - /* - * If TRY_SRC is enabled, but not active, - * then force attempt to connect as source. - */ - pd.try_src_marker = get_time().val + PD_T_TRY_SRC; - /* Swap roles to source */ - pd.power_role = PD_ROLE_SOURCE; - tcpm_set_cc(TYPEC_CC_RP); - timeout = 2 * MSEC; - set_state(PD_STATE_SRC_DISCONNECTED); - /* Set flag after the state change */ - pd.flags |= PD_FLAGS_TRY_SRC; - break; - } - - /* We are attached */ - pd.polarity = get_snk_polarity(cc1, cc2); - tcpm_set_polarity(pd.polarity); - /* reset message ID on connection */ - pd.msg_id = 0; - /* initial data role for sink is UFP */ - pd_set_data_role( PD_ROLE_UFP); -#if defined(CONFIG_CHARGE_MANAGER) - typec_curr = get_typec_current_limit(pd.polarity, cc1, cc2); - //typec_set_input_current_limit( - // port, typec_curr, TYPE_C_VOLTAGE); -#endif - /* If PD comm is enabled, enable TCPC RX */ - if (pd_comm_is_enabled()) - tcpm_set_rx_enable(1); - - /* DFP is attached */ - if (new_cc_state == PD_CC_DFP_ATTACHED - || new_cc_state == PD_CC_DEBUG_ACC) { - pd.flags |= PD_FLAGS_CHECK_PR_ROLE | - PD_FLAGS_CHECK_DR_ROLE | - PD_FLAGS_CHECK_IDENTITY; - if (new_cc_state == PD_CC_DEBUG_ACC) - pd.flags |= - PD_FLAGS_TS_DTS_PARTNER; - send_control(PD_CTRL_GET_SOURCE_CAP); - set_state (PD_STATE_SNK_DISCOVERY); - timeout = 10 * MSEC; - //hook_call_deferred( - // &pd_usb_billboard_deferred_data, - // PD_T_AME); - } - break; - case PD_STATE_SNK_HARD_RESET_RECOVER: - if (pd.last_state != pd.task_state) - pd.flags |= PD_FLAGS_CHECK_IDENTITY; -#ifdef CONFIG_USB_PD_VBUS_DETECT_NONE - /* - * Can't measure vbus state so this is the maximum - * recovery time for the source. - */ - if (pd.last_state != pd.task_state) - set_state_timeout( get_time().val + - PD_T_SAFE_0V + - PD_T_SRC_RECOVER_MAX + - PD_T_SRC_TURN_ON, - PD_STATE_SNK_DISCONNECTED); -#else - /* Wait for VBUS to go low and then high*/ - if (pd.last_state != pd.task_state) { - snk_hard_reset_vbus_off = 0; - set_state_timeout(get_time().val + - PD_T_SAFE_0V, - hard_reset_count < - PD_HARD_RESET_COUNT ? - PD_STATE_HARD_RESET_SEND : PD_STATE_SNK_DISCOVERY); - } - - if (!pd_is_vbus_present() && !snk_hard_reset_vbus_off) { - /* VBUS has gone low, reset timeout */ - snk_hard_reset_vbus_off = 1; - set_state_timeout(get_time().val + - PD_T_SRC_RECOVER_MAX + - PD_T_SRC_TURN_ON, PD_STATE_SNK_DISCONNECTED); - } - if (pd_is_vbus_present() && snk_hard_reset_vbus_off) { -#ifdef CONFIG_USB_PD_TCPM_TCPCI - /* - * After transmitting hard reset, TCPM writes - * to RECEIVE_MESSAGE register to enable - * PD message passing. - */ - if (pd_comm_is_enabled()) - tcpm_set_rx_enable( 1); -#endif /* CONFIG_USB_PD_TCPM_TCPCI */ - - /* VBUS went high again */ - set_state (PD_STATE_SNK_DISCOVERY); - timeout = 10 * MSEC; - } - - /* - * Don't need to set timeout because VBUS changing - * will trigger an interrupt and wake us up. - */ -#endif - break; - case PD_STATE_SNK_DISCOVERY: - /* Wait for source cap expired only if we are enabled */ - if ((pd.last_state != pd.task_state) - && pd_comm_is_enabled()) { - /* - * If VBUS has never been low, and we timeout - * waiting for source cap, try a soft reset - * first, in case we were already in a stable - * contract before this boot. - */ - if (pd.flags & PD_FLAGS_VBUS_NEVER_LOW) - set_state_timeout(get_time().val + - PD_T_SINK_WAIT_CAP, PD_STATE_SOFT_RESET); - /* - * If we haven't passed hard reset counter, - * start SinkWaitCapTimer, otherwise start - * NoResponseTimer. - */ - else if (hard_reset_count < PD_HARD_RESET_COUNT) - set_state_timeout(get_time().val + - PD_T_SINK_WAIT_CAP, PD_STATE_HARD_RESET_SEND); - else if (pd.flags & - PD_FLAGS_PREVIOUS_PD_CONN) - /* ErrorRecovery */ - set_state_timeout(get_time().val + - PD_T_NO_RESPONSE, PD_STATE_SNK_DISCONNECTED); -#if defined(CONFIG_CHARGE_MANAGER) - /* - * If we didn't come from disconnected, must - * have come from some path that did not set - * typec current limit. So, set to 0 so that - * we guarantee this is revised below. - */ - if (pd.last_state != PD_STATE_SNK_DISCONNECTED_DEBOUNCE) - typec_curr = 0; -#endif - } - -#if defined(CONFIG_CHARGE_MANAGER) - timeout = PD_T_SINK_ADJ - PD_T_DEBOUNCE; - - /* Check if CC pull-up has changed */ - tcpm_get_cc(&cc1, &cc2); - if (typec_curr - != get_typec_current_limit(pd.polarity, cc1, cc2)) { - /* debounce signal by requiring two reads */ - if (typec_curr_change) { - /* set new input current limit */ - typec_curr = get_typec_current_limit(pd.polarity, cc1, - cc2); - //typec_set_input_current_limit( - // port, typec_curr, TYPE_C_VOLTAGE); - } else { - /* delay for debounce */ - timeout = PD_T_DEBOUNCE; - } - typec_curr_change = !typec_curr_change; - } else { - typec_curr_change = 0; - } -#endif - break; - case PD_STATE_SNK_REQUESTED: - /* Wait for ACCEPT or REJECT */ - if (pd.last_state != pd.task_state) { - hard_reset_count = 0; - set_state_timeout(get_time().val + - PD_T_SENDER_RESPONSE, PD_STATE_HARD_RESET_SEND); - } - break; - case PD_STATE_SNK_TRANSITION: - /* Wait for PS_RDY */ - if (pd.last_state != pd.task_state) - set_state_timeout(get_time().val + - PD_T_PS_TRANSITION, PD_STATE_HARD_RESET_SEND); - break; - case PD_STATE_SNK_READY: - timeout = 20 * MSEC; - - /* - * Don't send any PD traffic if we woke up due to - * incoming packet or if VDO response pending to avoid - * collisions. - */ - if (incoming_packet || (pd.vdm_state == VDM_STATE_BUSY)) - break; - - /* Check for new power to request */ - if (pd.new_power_request) { - if (pd_send_request_msg(0) != EC_SUCCESS) - set_state(PD_STATE_SOFT_RESET); - break; - } - - /* Check power role policy, which may trigger a swap */ - if (pd.flags & PD_FLAGS_CHECK_PR_ROLE) { - pd_check_pr_role( PD_ROLE_SINK, pd.flags); - pd.flags &= ~PD_FLAGS_CHECK_PR_ROLE; - break; - } - - /* Check data role policy, which may trigger a swap */ - if (pd.flags & PD_FLAGS_CHECK_DR_ROLE) { - pd_check_dr_role(pd.data_role, pd.flags); - pd.flags &= ~PD_FLAGS_CHECK_DR_ROLE; - break; - } - - /* If DFP, send discovery SVDMs */ - if (pd.data_role == PD_ROLE_DFP - && (pd.flags & PD_FLAGS_CHECK_IDENTITY)) { - pd_send_vdm( USB_SID_PD, - CMD_DISCOVER_IDENT, NULL, 0); - pd.flags &= ~PD_FLAGS_CHECK_IDENTITY; - break; - } - - /* Sent all messages, don't need to wake very often */ - timeout = 200 * MSEC; - break; - case PD_STATE_SNK_SWAP_INIT: - if (pd.last_state != pd.task_state) { - res = send_control(PD_CTRL_PR_SWAP); - if (res < 0) { - timeout = 10 * MSEC; - /* - * If failed to get goodCRC, send - * soft reset, otherwise ignore - * failure. - */ - set_state(res == -1 ? PD_STATE_SOFT_RESET : PD_STATE_SNK_READY); - break; - } - /* Wait for accept or reject */ - set_state_timeout(get_time().val + - PD_T_SENDER_RESPONSE, PD_STATE_SNK_READY); - } - break; - case PD_STATE_SNK_SWAP_SNK_DISABLE: - /* Stop drawing power */ - pd_set_input_current_limit(0, 0); -#ifdef CONFIG_CHARGE_MANAGER - //typec_set_input_current_limit( 0, 0); - //charge_manager_set_ceil( - // CEIL_REQUESTOR_PD, - // CHARGE_CEIL_NONE); -#endif - set_state (PD_STATE_SNK_SWAP_SRC_DISABLE); - timeout = 10 * MSEC; - break; - case PD_STATE_SNK_SWAP_SRC_DISABLE: - /* Wait for PS_RDY */ - if (pd.last_state != pd.task_state) - set_state_timeout(get_time().val + - PD_T_PS_SOURCE_OFF, PD_STATE_HARD_RESET_SEND); - break; - case PD_STATE_SNK_SWAP_STANDBY: - if (pd.last_state != pd.task_state) { - /* Switch to Rp and enable power supply */ - tcpm_set_cc(TYPEC_CC_RP); - if (pd_set_power_supply_ready()) { - /* Restore Rd */ - tcpm_set_cc(TYPEC_CC_RD); - timeout = 10 * MSEC; - set_state (PD_STATE_SNK_DISCONNECTED); - break; - } - /* Wait for power supply to turn on */ - set_state_timeout(get_time().val + - PD_POWER_SUPPLY_TURN_ON_DELAY, PD_STATE_SNK_SWAP_COMPLETE); - } - break; - case PD_STATE_SNK_SWAP_COMPLETE: - /* Send PS_RDY and change to source role */ - res = send_control(PD_CTRL_PS_RDY); - if (res < 0) { - /* Restore Rd */ - tcpm_set_cc(TYPEC_CC_RD); - pd_power_supply_reset(); - timeout = 10 * MSEC; - set_state (PD_STATE_SNK_DISCONNECTED); - break; - } - - /* Don't send GET_SINK_CAP on swap */ - snk_cap_count = PD_SNK_CAP_RETRIES + 1; - caps_count = 0; - pd.msg_id = 0; - pd.power_role = PD_ROLE_SOURCE; - pd_update_roles(); - set_state(PD_STATE_SRC_DISCOVERY); - timeout = 10 * MSEC; - break; -#ifdef CONFIG_USBC_VCONN_SWAP - case PD_STATE_VCONN_SWAP_SEND: - if (pd.last_state != pd.task_state) { - res = send_control( PD_CTRL_VCONN_SWAP); - if (res < 0) { - timeout = 10*MSEC; - /* - * If failed to get goodCRC, send - * soft reset, otherwise ignore - * failure. - */ - set_state( res == -1 ? - PD_STATE_SOFT_RESET : - READY_RETURN_STATE()); - break; - } - /* Wait for accept or reject */ - set_state_timeout( - get_time().val + - PD_T_SENDER_RESPONSE, - READY_RETURN_STATE()); - } - break; - case PD_STATE_VCONN_SWAP_INIT: - if (pd.last_state != pd.task_state) { - if (!(pd.flags & PD_FLAGS_VCONN_ON)) { - /* Turn VCONN on and wait for it */ - tcpm_set_vconn( 1); - set_state_timeout( - get_time().val + PD_VCONN_SWAP_DELAY, - PD_STATE_VCONN_SWAP_READY); - } else { - set_state_timeout( - get_time().val + PD_T_VCONN_SOURCE_ON, - READY_RETURN_STATE()); - } - } - break; - case PD_STATE_VCONN_SWAP_READY: - if (pd.last_state != pd.task_state) { - if (!(pd.flags & PD_FLAGS_VCONN_ON)) { - /* VCONN is now on, send PS_RDY */ - pd.flags |= PD_FLAGS_VCONN_ON; - res = send_control( - PD_CTRL_PS_RDY); - if (res == -1) { - timeout = 10*MSEC; - /* - * If failed to get goodCRC, - * send soft reset - */ - set_state( - PD_STATE_SOFT_RESET); - break; - } - set_state( - READY_RETURN_STATE()); - } else { - /* Turn VCONN off and wait for it */ - tcpm_set_vconn( 0); - pd.flags &= ~PD_FLAGS_VCONN_ON; - set_state_timeout( - get_time().val + PD_VCONN_SWAP_DELAY, - READY_RETURN_STATE()); - } - } - break; -#endif /* CONFIG_USBC_VCONN_SWAP */ -#endif /* CONFIG_USB_PD_DUAL_ROLE */ - case PD_STATE_SOFT_RESET: - if (pd.last_state != pd.task_state) { - /* Message ID of soft reset is always 0 */ - pd.msg_id = 0; - res = send_control(PD_CTRL_SOFT_RESET); - - /* if soft reset failed, try hard reset. */ - if (res < 0) { - set_state(PD_STATE_HARD_RESET_SEND); - timeout = 5 * MSEC; - break; - } - - set_state_timeout(get_time().val + PD_T_SENDER_RESPONSE, - PD_STATE_HARD_RESET_SEND); - } - break; - case PD_STATE_HARD_RESET_SEND: - hard_reset_count++; - if (pd.last_state != pd.task_state) - hard_reset_sent = 0; -#ifdef CONFIG_CHARGE_MANAGER -// if (pd.last_state == PD_STATE_SNK_DISCOVERY -// || (pd.last_state == PD_STATE_SOFT_RESET -// && (pd.flags & PD_FLAGS_VBUS_NEVER_LOW))) { -// pd.flags &= ~PD_FLAGS_VBUS_NEVER_LOW; -// /* -// * If discovery timed out, assume that we -// * have a dedicated charger attached. This -// * may not be a correct assumption according -// * to the specification, but it generally -// * works in practice and the harmful -// * effects of a wrong assumption here -// * are minimal. -// */ -// //charge_manager_update_dualrole( -// // CAP_DEDICATED); -// } -#endif - - /* try sending hard reset until it succeeds */ - if (!hard_reset_sent) { - if (pd_transmit(TCPC_TX_HARD_RESET, 0, NULL) < 0) { - timeout = 10 * MSEC; - break; - } - - /* successfully sent hard reset */ - hard_reset_sent = 1; - /* - * If we are source, delay before cutting power - * to allow sink time to get hard reset. - */ - - set_state(PD_STATE_HARD_RESET_EXECUTE); - timeout = 10 * MSEC; - - } - break; - case PD_STATE_HARD_RESET_EXECUTE: -#ifdef CONFIG_USB_PD_DUAL_ROLE - /* - * If hard reset while in the last stages of power - * swap, then we need to restore our CC resistor. - */ - if (pd.last_state == PD_STATE_SNK_SWAP_STANDBY) - tcpm_set_cc(TYPEC_CC_RD); -#endif - - /* reset our own state machine */ - pd_execute_hard_reset(); - timeout = 10 * MSEC; - break; -#ifdef CONFIG_COMMON_RUNTIME - case PD_STATE_BIST_RX: - send_bist_cmd(); - /* Delay at least enough for partner to finish BIST */ - timeout = PD_T_BIST_RECEIVE + 20*MSEC; - /* Set to appropriate port disconnected state */ - set_state( DUAL_ROLE_IF_ELSE( - PD_STATE_SNK_DISCONNECTED, - PD_STATE_SRC_DISCONNECTED)); - break; - case PD_STATE_BIST_TX: - pd_transmit( TCPC_TX_BIST_MODE_2, 0, NULL); - /* Delay at least enough to finish sending BIST */ - timeout = PD_T_BIST_TRANSMIT + 20*MSEC; - /* Set to appropriate port disconnected state */ - set_state( DUAL_ROLE_IF_ELSE( - PD_STATE_SNK_DISCONNECTED, - PD_STATE_SRC_DISCONNECTED)); - break; -#endif -#ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE - case PD_STATE_DRP_AUTO_TOGGLE: - { - enum pd_states next_state; - - assert(auto_toggle_supported); - - /* Check for connection */ - tcpm_get_cc( &cc1, &cc2); - - /* Set to appropriate port state */ - if (cc1 == TYPEC_CC_VOLT_OPEN && - cc2 == TYPEC_CC_VOLT_OPEN) - /* nothing connected, keep toggling*/ - next_state = PD_STATE_DRP_AUTO_TOGGLE; - else if ((cc_is_rp(cc1) || cc_is_rp(cc2)) && - drp_state != PD_DRP_FORCE_SOURCE) - /* SNK allowed unless ForceSRC */ - next_state = PD_STATE_SNK_DISCONNECTED; - else if (((cc1 == TYPEC_CC_VOLT_RD || - cc2 == TYPEC_CC_VOLT_RD) || - (cc1 == TYPEC_CC_VOLT_RA && - cc2 == TYPEC_CC_VOLT_RA)) && - (drp_state != PD_DRP_TOGGLE_OFF && - drp_state != PD_DRP_FORCE_SINK)) - /* SRC allowed unless ForceSNK or Toggle Off */ - next_state = PD_STATE_SRC_DISCONNECTED; - else - /* Anything else, keep toggling */ - next_state = PD_STATE_DRP_AUTO_TOGGLE; - - if (next_state != PD_STATE_DRP_AUTO_TOGGLE) { - tcpm_set_drp_toggle( 0); -#ifdef CONFIG_USB_PD_TCPC_LOW_POWER - CPRINTS("TCPC p%d Exit Low Power Mode", port); -#endif - } - - if (next_state == PD_STATE_SNK_DISCONNECTED) { - tcpm_set_cc( TYPEC_CC_RD); - pd.power_role = PD_ROLE_SINK; - timeout = 2*MSEC; - } else if (next_state == PD_STATE_SRC_DISCONNECTED) { - tcpm_set_cc( TYPEC_CC_RP); - pd.power_role = PD_ROLE_SOURCE; - timeout = 2*MSEC; - } else { - tcpm_set_drp_toggle( 1); - pd.flags |= PD_FLAGS_TCPC_DRP_TOGGLE; - timeout = -1; -#ifdef CONFIG_USB_PD_TCPC_LOW_POWER - CPRINTS("TCPC p%d Low Power Mode", port); -#endif - } - set_state( next_state); - - break; - } -#endif - default: - break; - } - - pd.last_state = this_state; - - /* - * Check for state timeout, and if not check if need to adjust - * timeout value to wake up on the next state timeout. - */ - now = get_time(); - if (pd.timeout) { - if (now.val >= pd.timeout) { - set_state(pd.timeout_state); - /* On a state timeout, run next state soon */ - timeout = timeout < 10 * MSEC ? timeout : 10 * MSEC; - } else if (pd.timeout - now.val < timeout) { - timeout = pd.timeout - now.val; - } - } - - /* Check for disconnection if we're connected */ - if (!pd_is_connected()) - return; -#ifdef CONFIG_USB_PD_DUAL_ROLE - if (pd_is_power_swapping()) - return; -#endif - -#ifdef CONFIG_USB_PD_DUAL_ROLE - /* - * Sink disconnect if VBUS is low and we are not recovering - * a hard reset. - */ - if (pd.power_role == PD_ROLE_SINK && !pd_is_vbus_present() - && pd.task_state != PD_STATE_SNK_HARD_RESET_RECOVER - && pd.task_state != PD_STATE_HARD_RESET_EXECUTE) { - /* Sink: detect disconnect by monitoring VBUS */ - set_state (PD_STATE_SNK_DISCONNECTED); - /* set timeout small to reconnect fast */ - timeout = 5 * MSEC; - } -#endif /* CONFIG_USB_PD_DUAL_ROLE */ -} - -#ifdef CONFIG_USB_PD_DUAL_ROLE -//extern "C" { -//static void dual_role_on(void) { -// int i; -// -// for (i = 0; i < CONFIG_USB_PD_PORT_COUNT; i++) { -//#ifdef CONFIG_CHARGE_MANAGER -// //if (charge_manager_get_active_charge_port() != i) -//#endif -// pd[i].flags |= PD_FLAGS_CHECK_PR_ROLE | -// PD_FLAGS_CHECK_DR_ROLE; -// -// pd[i].flags |= PD_FLAGS_CHECK_IDENTITY; -// } -// -// pd_set_dual_role(PD_DRP_TOGGLE_ON); -// CPRINTS("chipset -> S0"); -//} -//} -//DECLARE_HOOK(HOOK_CHIPSET_RESUME, dual_role_on, HOOK_PRIO_DEFAULT); -// -//static void dual_role_off(void) { -// pd_set_dual_role(PD_DRP_TOGGLE_OFF); -// CPRINTS("chipset -> S3"); -//} -//DECLARE_HOOK(HOOK_CHIPSET_SUSPEND, dual_role_off, HOOK_PRIO_DEFAULT); -//DECLARE_HOOK(HOOK_CHIPSET_STARTUP, dual_role_off, HOOK_PRIO_DEFAULT); -// -//static void dual_role_force_sink(void) { -// pd_set_dual_role(PD_DRP_FORCE_SINK); -// CPRINTS("chipset -> S5"); -//} -//DECLARE_HOOK(HOOK_CHIPSET_SHUTDOWN, dual_role_force_sink, HOOK_PRIO_DEFAULT); - -#endif /* CONFIG_USB_PD_DUAL_ROLE */ - -#ifdef CONFIG_COMMON_RUNTIME - -/* - * (enable=1) request pd_task transition to the suspended state. hang - * around for a while until we observe the state change. this can - * take a while (like 300ms) on startup when pd_task is sleeping in - * tcpci_tcpm_init. - * - * (enable=0) force pd_task out of the suspended state and into the - * port's default state. - */ - -void pd_set_suspend( int enable) -{ - int tries = 300; - - if (enable) { - pd.req_suspend_state = 1; - do { - // getting rid of task stuff - //task_wake(PD_PORT_TO_TASK_ID()); - if (pd.task_state == PD_STATE_SUSPENDED) - break; - msleep(1); - } while (--tries != 0); - if (!tries) - CPRINTS("TCPC p%d set_suspend failed!", port); - } else { - if (pd.task_state != PD_STATE_SUSPENDED) - CPRINTS("TCPC p%d suspend disable request " - "while not suspended!", port); - set_state( PD_DEFAULT_STATE()); - // getting rid of task stuff - //task_wake(PD_PORT_TO_TASK_ID()); - } -} - -int pd_is_port_enabled() -{ - switch (pd.task_state) { - case PD_STATE_DISABLED: - case PD_STATE_SUSPENDED: - return 0; - default: - return 1; - } -} - -#if defined(CONFIG_CMD_PD) && defined(CONFIG_CMD_PD_FLASH) -static int hex8tou32(char *str, uint32_t *val) -{ - char *ptr = str; - uint32_t tmp = 0; - - while (*ptr) { - char c = *ptr++; - if (c >= '0' && c <= '9') - tmp = (tmp << 4) + (c - '0'); - else if (c >= 'A' && c <= 'F') - tmp = (tmp << 4) + (c - 'A' + 10); - else if (c >= 'a' && c <= 'f') - tmp = (tmp << 4) + (c - 'a' + 10); - else - return EC_ERROR_INVAL; - } - if (ptr != str + 8) - return EC_ERROR_INVAL; - *val = tmp; - return EC_SUCCESS; -} - -static int remote_flashing(int argc, char **argv) -{ - int port, cnt, cmd; - uint32_t data[VDO_MAX_SIZE-1]; - char *e; - static int flash_offset[CONFIG_USB_PD_PORT_COUNT]; - - if (argc < 4 || argc > (VDO_MAX_SIZE + 4 - 1)) - return EC_ERROR_PARAM_COUNT; - - port = strtoi(argv[1], &e, 10); - if (*e || port >= CONFIG_USB_PD_PORT_COUNT) - return EC_ERROR_PARAM2; - - cnt = 0; - if (!strcasecmp(argv[3], "erase")) { - cmd = VDO_CMD_FLASH_ERASE; - flash_offset[port] = 0; - ccprintf("ERASE ..."); - } else if (!strcasecmp(argv[3], "reboot")) { - cmd = VDO_CMD_REBOOT; - ccprintf("REBOOT ..."); - } else if (!strcasecmp(argv[3], "signature")) { - cmd = VDO_CMD_ERASE_SIG; - ccprintf("ERASE SIG ..."); - } else if (!strcasecmp(argv[3], "info")) { - cmd = VDO_CMD_READ_INFO; - ccprintf("INFO..."); - } else if (!strcasecmp(argv[3], "version")) { - cmd = VDO_CMD_VERSION; - ccprintf("VERSION..."); - } else { - int i; - argc -= 3; - for (i = 0; i < argc; i++) - if (hex8tou32(argv[i+3], data + i)) - return EC_ERROR_INVAL; - cmd = VDO_CMD_FLASH_WRITE; - cnt = argc; - ccprintf("WRITE %d @%04x ...", argc * 4, - flash_offset[port]); - flash_offset[port] += argc * 4; - } - - pd_send_vdm( USB_VID_GOOGLE, cmd, data, cnt); - - /* Wait until VDM is done */ - while (pd.vdm_state > 0) - task_wait_event(100*MSEC); - - ccprintf("DONE %d\n", pd.vdm_state); - return EC_SUCCESS; -} -#endif /* defined(CONFIG_CMD_PD) && defined(CONFIG_CMD_PD_FLASH) */ - -#if defined(CONFIG_USB_PD_ALT_MODE) && !defined(CONFIG_USB_PD_ALT_MODE_DFP) -void pd_send_hpd( enum hpd_event hpd) -{ - uint32_t data[1]; - int opos = pd_alt_mode( USB_SID_DISPLAYPORT); - if (!opos) - return; - - data[0] = VDO_DP_STATUS((hpd == hpd_irq), /* IRQ_HPD */ - (hpd != hpd_low), /* HPD_HI|LOW */ - 0, /* request exit DP */ - 0, /* request exit USB */ - 0, /* MF pref */ - 1, /* enabled */ - 0, /* power low */ - 0x2); - pd_send_vdm( USB_SID_DISPLAYPORT, - VDO_OPOS(opos) | CMD_ATTENTION, data, 1); - /* Wait until VDM is done. */ - while (pd[0].vdm_state > 0) - task_wait_event(USB_PD_RX_TMOUT_US * (PD_RETRY_COUNT + 1)); -} -#endif - -int pd_fetch_acc_log_entry() -{ - timestamp_t timeout; - - /* Cannot send a VDM now, the host should retry */ - if (pd.vdm_state > 0) - return pd.vdm_state == VDM_STATE_BUSY ? - EC_RES_BUSY : EC_RES_UNAVAILABLE; - - pd_send_vdm( USB_VID_GOOGLE, VDO_CMD_GET_LOG, NULL, 0); - timeout.val = get_time().val + 75*MSEC; - - /* Wait until VDM is done */ - while ((pd.vdm_state > 0) && - (get_time().val < timeout.val)) - task_wait_event(10*MSEC); - - if (pd.vdm_state > 0) - return EC_RES_TIMEOUT; - else if (pd.vdm_state < 0) - return EC_RES_ERROR; - - return EC_RES_SUCCESS; -} - -#ifdef CONFIG_USB_PD_DUAL_ROLE -void pd_request_source_voltage( int mv) -{ - pd_set_max_voltage(mv); - - if (pd.task_state == PD_STATE_SNK_READY || - pd.task_state == PD_STATE_SNK_TRANSITION) { - /* Set flag to send new power request in pd_task */ - pd.new_power_request = 1; - } else { - pd.power_role = PD_ROLE_SINK; - tcpm_set_cc( TYPEC_CC_RD); - set_state( PD_STATE_SNK_DISCONNECTED); - } - - // getting rid of task stuff - //task_wake(PD_PORT_TO_TASK_ID()); -} - -void pd_set_external_voltage_limit( int mv) -{ - pd_set_max_voltage(mv); - - if (pd.task_state == PD_STATE_SNK_READY || - pd.task_state == PD_STATE_SNK_TRANSITION) { - /* Set flag to send new power request in pd_task */ - pd.new_power_request = 1; - // getting rid of task stuff - //task_wake(PD_PORT_TO_TASK_ID()); - } -} - -void pd_update_contract() -{ - if ((pd.task_state >= PD_STATE_SRC_NEGOCIATE) && - (pd.task_state <= PD_STATE_SRC_GET_SINK_CAP)) { - pd.flags |= PD_FLAGS_UPDATE_SRC_CAPS; - // getting rid of task stuff - //task_wake(PD_PORT_TO_TASK_ID()); - } -} - -#endif /* CONFIG_USB_PD_DUAL_ROLE */ - -static int command_pd(int argc, char **argv) -{ - int port; - char *e; - - if (argc < 2) - return EC_ERROR_PARAM_COUNT; - -#if defined(CONFIG_CMD_PD) && defined(CONFIG_USB_PD_DUAL_ROLE) - /* command: pd */ - if (!strcasecmp(argv[1], "dualrole")) { - if (argc < 3) { - ccprintf("dual-role toggling: "); - switch (drp_state) { - case PD_DRP_TOGGLE_ON: - ccprintf("on\n"); - break; - case PD_DRP_TOGGLE_OFF: - ccprintf("off\n"); - break; - case PD_DRP_FREEZE: - ccprintf("freeze\n"); - break; - case PD_DRP_FORCE_SINK: - ccprintf("force sink\n"); - break; - case PD_DRP_FORCE_SOURCE: - ccprintf("force source\n"); - break; - } - } else { - if (!strcasecmp(argv[2], "on")) - pd_set_dual_role(PD_DRP_TOGGLE_ON); - else if (!strcasecmp(argv[2], "off")) - pd_set_dual_role(PD_DRP_TOGGLE_OFF); - else if (!strcasecmp(argv[2], "freeze")) - pd_set_dual_role(PD_DRP_FREEZE); - else if (!strcasecmp(argv[2], "sink")) - pd_set_dual_role(PD_DRP_FORCE_SINK); - else if (!strcasecmp(argv[2], "source")) - pd_set_dual_role(PD_DRP_FORCE_SOURCE); - else - return EC_ERROR_PARAM3; - } - return EC_SUCCESS; - } else -#endif - if (!strcasecmp(argv[1], "dump")) { -#ifndef CONFIG_USB_PD_DEBUG_LEVEL - int level; - - if (argc >= 3) { - level = strtoi(argv[2], &e, 10); - if (*e) - return EC_ERROR_PARAM2; - debug_level = level; - } else -#endif - ccprintf("dump level: %d\n", debug_level); - - return EC_SUCCESS; - } -#ifdef CONFIG_CMD_PD -#ifdef CONFIG_CMD_PD_DEV_DUMP_INFO - else if (!strncasecmp(argv[1], "rwhashtable", 3)) { - int i; - struct ec_params_usb_pd_rw_hash_entry *p; - for (i = 0; i < RW_HASH_ENTRIES; i++) { - p = &rw_hash_table[i]; - pd_dev_dump_info(p->dev_id, p->dev_rw_hash); - } - return EC_SUCCESS; - } -#endif /* CONFIG_CMD_PD_DEV_DUMP_INFO */ -#ifdef CONFIG_USB_PD_TRY_SRC - else if (!strncasecmp(argv[1], "trysrc", 6)) { - int enable; - - if (argc < 2) { - return EC_ERROR_PARAM_COUNT; - } else if (argc >= 3) { - enable = strtoi(argv[2], &e, 10); - if (*e) - return EC_ERROR_PARAM3; - pd_try_src_enable = enable ? 1 : 0; - } - - ccprintf("Try.SRC %s\n", pd_try_src_enable ? "on" : "off"); - return EC_SUCCESS; - } -#endif -#endif - /* command: pd [args] */ - port = strtoi(argv[1], &e, 10); - if (argc < 3) - return EC_ERROR_PARAM_COUNT; - if (*e || port >= CONFIG_USB_PD_PORT_COUNT) - return EC_ERROR_PARAM2; -#if defined(CONFIG_CMD_PD) && defined(CONFIG_USB_PD_DUAL_ROLE) - - if (!strcasecmp(argv[2], "tx")) { - set_state( PD_STATE_SNK_DISCOVERY); - // getting rid of task stuff - //task_wake(PD_PORT_TO_TASK_ID()); - } else if (!strcasecmp(argv[2], "bist_rx")) { - set_state( PD_STATE_BIST_RX); - // getting rid of task stuff - //task_wake(PD_PORT_TO_TASK_ID()); - } else if (!strcasecmp(argv[2], "bist_tx")) { - if (*e) - return EC_ERROR_PARAM3; - set_state( PD_STATE_BIST_TX); - // getting rid of task stuff - //task_wake(PD_PORT_TO_TASK_ID()); - } else if (!strcasecmp(argv[2], "charger")) { - pd.power_role = PD_ROLE_SOURCE; - tcpm_set_cc( TYPEC_CC_RP); - set_state( PD_STATE_SRC_DISCONNECTED); - // getting rid of task stuff - //task_wake(PD_PORT_TO_TASK_ID()); - } else if (!strncasecmp(argv[2], "dev", 3)) { - int max_volt; - if (argc >= 4) - max_volt = strtoi(argv[3], &e, 10) * 1000; - else - max_volt = pd_get_max_voltage(); - - pd_request_source_voltage( max_volt); - ccprintf("max req: %dmV\n", max_volt); - } else if (!strcasecmp(argv[2], "disable")) { - pd_comm_enable( 0); - ccprintf("Port C%d disable\n", port); - return EC_SUCCESS; - } else if (!strcasecmp(argv[2], "enable")) { - pd_comm_enable( 1); - ccprintf("Port C%d enabled\n", port); - return EC_SUCCESS; - } else if (!strncasecmp(argv[2], "hard", 4)) { - set_state( PD_STATE_HARD_RESET_SEND); - // getting rid of task stuff - //task_wake(PD_PORT_TO_TASK_ID()); - } else if (!strncasecmp(argv[2], "info", 4)) { - int i; - ccprintf("Hash "); - for (i = 0; i < PD_RW_HASH_SIZE / 4; i++) - ccprintf("%08x ", pd.dev_rw_hash[i]); - ccprintf("\nImage %s\n", system_image_copy_t_to_string( - pd.current_image)); - } else if (!strncasecmp(argv[2], "soft", 4)) { - set_state( PD_STATE_SOFT_RESET); - // getting rid of task stuff - //task_wake(PD_PORT_TO_TASK_ID()); - } else if (!strncasecmp(argv[2], "swap", 4)) { - if (argc < 4) - return EC_ERROR_PARAM_COUNT; - - if (!strncasecmp(argv[3], "power", 5)) - pd_request_power_swap(); - else if (!strncasecmp(argv[3], "data", 4)) - pd_request_data_swap(); -#ifdef CONFIG_USBC_VCONN_SWAP - else if (!strncasecmp(argv[3], "vconn", 5)) - pd_request_vconn_swap(); -#endif - else - return EC_ERROR_PARAM3; - } else if (!strncasecmp(argv[2], "ping", 4)) { - int enable; - - if (argc > 3) { - enable = strtoi(argv[3], &e, 10); - if (*e) - return EC_ERROR_PARAM3; - pd_ping_enable( enable); - } - - ccprintf("Pings %s\n", - (pd.flags & PD_FLAGS_PING_ENABLED) ? - "on" : "off"); - } else if (!strncasecmp(argv[2], "vdm", 3)) { - if (argc < 4) - return EC_ERROR_PARAM_COUNT; - - if (!strncasecmp(argv[3], "ping", 4)) { - uint32_t enable; - if (argc < 5) - return EC_ERROR_PARAM_COUNT; - enable = strtoi(argv[4], &e, 10); - if (*e) - return EC_ERROR_PARAM4; - pd_send_vdm( USB_VID_GOOGLE, VDO_CMD_PING_ENABLE, - &enable, 1); - } else if (!strncasecmp(argv[3], "curr", 4)) { - pd_send_vdm( USB_VID_GOOGLE, VDO_CMD_CURRENT, - NULL, 0); - } else if (!strncasecmp(argv[3], "vers", 4)) { - pd_send_vdm( USB_VID_GOOGLE, VDO_CMD_VERSION, - NULL, 0); - } else { - return EC_ERROR_PARAM_COUNT; - } -#if defined(CONFIG_CMD_PD) && defined(CONFIG_CMD_PD_FLASH) - } else if (!strncasecmp(argv[2], "flash", 4)) { - return remote_flashing(argc, argv); -#endif - } else -#endif - if (!strncasecmp(argv[2], "state", 5)) { - ccprintf("Port C%d CC%d, %s - Role: %s-%s%s " - "State: %s, Flags: 0x%04x\n", - port, pd.polarity + 1, - pd_comm_is_enabled() ? "Ena" : "Dis", - pd.power_role == PD_ROLE_SOURCE ? "SRC" : "SNK", - pd.data_role == PD_ROLE_DFP ? "DFP" : "UFP", - (pd.flags & PD_FLAGS_VCONN_ON) ? "-VC" : "", - pd_state_names[pd.task_state], - pd.flags); - } else { - return EC_ERROR_PARAM1; - } - - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(pd, command_pd, - "dualrole|dump|rwhashtable" - "|trysrc [0|1]\n\t " - "[tx|bist_rx|bist_tx|charger|clock|dev|disable|enable" - "|soft|hash|hard|ping|state|swap [power|data]|" - "vdm [ping | curr | vers]]", - "USB PD"); - -#ifdef HAS_TASK_HOSTCMD - -static int hc_pd_ports(struct host_cmd_handler_args *args) -{ - struct ec_response_usb_pd_ports *r = args->response; - r->num_ports = CONFIG_USB_PD_PORT_COUNT; - - args->response_size = sizeof(*r); - return EC_RES_SUCCESS; -} -DECLARE_HOST_COMMAND(EC_CMD_USB_PD_PORTS, - hc_pd_ports, - EC_VER_MASK(0)); - -static const enum pd_dual_role_states dual_role_map[USB_PD_CTRL_ROLE_COUNT] = { - [USB_PD_CTRL_ROLE_TOGGLE_ON] = PD_DRP_TOGGLE_ON, - [USB_PD_CTRL_ROLE_TOGGLE_OFF] = PD_DRP_TOGGLE_OFF, - [USB_PD_CTRL_ROLE_FORCE_SINK] = PD_DRP_FORCE_SINK, - [USB_PD_CTRL_ROLE_FORCE_SOURCE] = PD_DRP_FORCE_SOURCE, - [USB_PD_CTRL_ROLE_FREEZE] = PD_DRP_FREEZE, -}; - -#ifdef CONFIG_USBC_SS_MUX -static const enum typec_mux typec_mux_map[USB_PD_CTRL_MUX_COUNT] = { - [USB_PD_CTRL_MUX_NONE] = TYPEC_MUX_NONE, - [USB_PD_CTRL_MUX_USB] = TYPEC_MUX_USB, - [USB_PD_CTRL_MUX_AUTO] = TYPEC_MUX_DP, - [USB_PD_CTRL_MUX_DP] = TYPEC_MUX_DP, - [USB_PD_CTRL_MUX_DOCK] = TYPEC_MUX_DOCK, -}; -#endif - -static int hc_usb_pd_control(struct host_cmd_handler_args *args) -{ - const struct ec_params_usb_pd_control *p = args->params; - struct ec_response_usb_pd_control_v1 *r_v1 = args->response; - struct ec_response_usb_pd_control *r = args->response; - - if (p->port >= CONFIG_USB_PD_PORT_COUNT) - return EC_RES_INVALID_PARAM; - - if (p->role >= USB_PD_CTRL_ROLE_COUNT || - p->mux >= USB_PD_CTRL_MUX_COUNT) - return EC_RES_INVALID_PARAM; - - if (p->role != USB_PD_CTRL_ROLE_NO_CHANGE) - pd_set_dual_role(dual_role_map[p->role]); - -#ifdef CONFIG_USBC_SS_MUX - if (p->mux != USB_PD_CTRL_MUX_NO_CHANGE) - usb_mux_set(p->port, typec_mux_map[p->mux], - typec_mux_map[p->mux] == TYPEC_MUX_NONE ? - USB_SWITCH_DISCONNECT : - USB_SWITCH_CONNECT, - pd_get_polarity(p->port)); -#endif /* CONFIG_USBC_SS_MUX */ - - if (p->swap == USB_PD_CTRL_SWAP_DATA) - pd_request_data_swap(p->port); -#ifdef CONFIG_USB_PD_DUAL_ROLE - else if (p->swap == USB_PD_CTRL_SWAP_POWER) - pd_request_power_swap(p->port); -#ifdef CONFIG_USBC_VCONN_SWAP - else if (p->swap == USB_PD_CTRL_SWAP_VCONN) - pd_request_vconn_swap(p->port); -#endif -#endif - - if (args->version == 0) { - r->enabled = pd_comm_is_enabled(p->port); - r->role = pd[p->port].power_role; - r->polarity = pd[p->port].polarity; - r->state = pd[p->port].task_state; - args->response_size = sizeof(*r); - } else { - r_v1->enabled = - (pd_comm_is_enabled(p->port) ? - PD_CTRL_RESP_ENABLED_COMMS : 0) | - (pd_is_connected(p->port) ? - PD_CTRL_RESP_ENABLED_CONNECTED : 0) | - ((pd[p->port].flags & PD_FLAGS_PREVIOUS_PD_CONN) ? - PD_CTRL_RESP_ENABLED_PD_CAPABLE : 0); - r_v1->role = - (pd[p->port].power_role ? PD_CTRL_RESP_ROLE_POWER : 0) | - (pd[p->port].data_role ? PD_CTRL_RESP_ROLE_DATA : 0) | - ((pd[p->port].flags & PD_FLAGS_VCONN_ON) ? - PD_CTRL_RESP_ROLE_VCONN : 0) | - ((pd[p->port].flags & PD_FLAGS_PARTNER_DR_POWER) ? - PD_CTRL_RESP_ROLE_DR_POWER : 0) | - ((pd[p->port].flags & PD_FLAGS_PARTNER_DR_DATA) ? - PD_CTRL_RESP_ROLE_DR_DATA : 0) | - ((pd[p->port].flags & PD_FLAGS_PARTNER_USB_COMM) ? - PD_CTRL_RESP_ROLE_USB_COMM : 0) | - ((pd[p->port].flags & PD_FLAGS_PARTNER_EXTPOWER) ? - PD_CTRL_RESP_ROLE_EXT_POWERED : 0); - r_v1->polarity = pd[p->port].polarity; - strzcpy(r_v1->state, - pd_state_names[pd[p->port].task_state], - sizeof(r_v1->state)); - args->response_size = sizeof(*r_v1); - } - return EC_RES_SUCCESS; -} -DECLARE_HOST_COMMAND(EC_CMD_USB_PD_CONTROL, - hc_usb_pd_control, - EC_VER_MASK(0) | EC_VER_MASK(1)); - -static int hc_remote_flash(struct host_cmd_handler_args *args) -{ - const struct ec_params_usb_pd_fw_update *p = args->params; - int port = p->port; - const uint32_t *data = &(p->size) + 1; - int i, size, rv = EC_RES_SUCCESS; - timestamp_t timeout; - - if (port >= CONFIG_USB_PD_PORT_COUNT) - return EC_RES_INVALID_PARAM; - - if (p->size + sizeof(*p) > args->params_size) - return EC_RES_INVALID_PARAM; - -#if defined(CONFIG_BATTERY_PRESENT_CUSTOM) || \ - defined(CONFIG_BATTERY_PRESENT_GPIO) - /* - * Do not allow PD firmware update if no battery and this port - * is sinking power, because we will lose power. - */ - if (battery_is_present() != BP_YES && - charge_manager_get_active_charge_port() == port) - return EC_RES_UNAVAILABLE; -#endif - - /* - * Busy still with a VDM that host likely generated. 1 deep VDM queue - * so just return for retry logic on host side to deal with. - */ - if (pd.vdm_state > 0) - return EC_RES_BUSY; - - switch (p->cmd) { - case USB_PD_FW_REBOOT: - pd_send_vdm( USB_VID_GOOGLE, VDO_CMD_REBOOT, NULL, 0); - - /* - * Return immediately to free pending i2c bus. Host needs to - * manage this delay. - */ - return EC_RES_SUCCESS; - - case USB_PD_FW_FLASH_ERASE: - pd_send_vdm( USB_VID_GOOGLE, VDO_CMD_FLASH_ERASE, NULL, 0); - - /* - * Return immediately. Host needs to manage delays here which - * can be as long as 1.2 seconds on 64KB RW flash. - */ - return EC_RES_SUCCESS; - - case USB_PD_FW_ERASE_SIG: - pd_send_vdm( USB_VID_GOOGLE, VDO_CMD_ERASE_SIG, NULL, 0); - timeout.val = get_time().val + 500*MSEC; - break; - - case USB_PD_FW_FLASH_WRITE: - /* Data size must be a multiple of 4 */ - if (!p->size || p->size % 4) - return EC_RES_INVALID_PARAM; - - size = p->size / 4; - for (i = 0; i < size; i += VDO_MAX_SIZE - 1) { - pd_send_vdm( USB_VID_GOOGLE, VDO_CMD_FLASH_WRITE, - data + i, MIN(size - i, VDO_MAX_SIZE - 1)); - timeout.val = get_time().val + 500*MSEC; - - /* Wait until VDM is done */ - while ((pd.vdm_state > 0) && - (get_time().val < timeout.val)) - task_wait_event(10*MSEC); - - if (pd.vdm_state > 0) - return EC_RES_TIMEOUT; - } - return EC_RES_SUCCESS; - - default: - return EC_RES_INVALID_PARAM; - break; - } - - /* Wait until VDM is done or timeout */ - while ((pd.vdm_state > 0) && (get_time().val < timeout.val)) - task_wait_event(50*MSEC); - - if ((pd.vdm_state > 0) || - (pd.vdm_state == VDM_STATE_ERR_TMOUT)) - rv = EC_RES_TIMEOUT; - else if (pd.vdm_state < 0) - rv = EC_RES_ERROR; - - return rv; -} -DECLARE_HOST_COMMAND(EC_CMD_USB_PD_FW_UPDATE, - hc_remote_flash, - EC_VER_MASK(0)); - -static int hc_remote_rw_hash_entry(struct host_cmd_handler_args *args) -{ - int i, idx = 0, found = 0; - const struct ec_params_usb_pd_rw_hash_entry *p = args->params; - static int rw_hash_next_idx; - - if (!p->dev_id) - return EC_RES_INVALID_PARAM; - - for (i = 0; i < RW_HASH_ENTRIES; i++) { - if (p->dev_id == rw_hash_table[i].dev_id) { - idx = i; - found = 1; - break; - } - } - if (!found) { - idx = rw_hash_next_idx; - rw_hash_next_idx = rw_hash_next_idx + 1; - if (rw_hash_next_idx == RW_HASH_ENTRIES) - rw_hash_next_idx = 0; - } - memcpy(&rw_hash_table[idx], p, sizeof(*p)); - - return EC_RES_SUCCESS; -} -DECLARE_HOST_COMMAND(EC_CMD_USB_PD_RW_HASH_ENTRY, - hc_remote_rw_hash_entry, - EC_VER_MASK(0)); - -static int hc_remote_pd_dev_info(struct host_cmd_handler_args *args) -{ - const uint8_t *port = args->params; - struct ec_params_usb_pd_rw_hash_entry *r = args->response; - - if (*port >= CONFIG_USB_PD_PORT_COUNT) - return EC_RES_INVALID_PARAM; - - r->dev_id = pd[*port].dev_id; - - if (r->dev_id) { - memcpy(r->dev_rw_hash, pd[*port].dev_rw_hash, - PD_RW_HASH_SIZE); - } - - r->current_image = pd[*port].current_image; - - args->response_size = sizeof(*r); - return EC_RES_SUCCESS; -} - -DECLARE_HOST_COMMAND(EC_CMD_USB_PD_DEV_INFO, - hc_remote_pd_dev_info, - EC_VER_MASK(0)); - -#ifndef CONFIG_USB_PD_TCPC -#ifdef CONFIG_EC_CMD_PD_CHIP_INFO -static int hc_remote_pd_chip_info(struct host_cmd_handler_args *args) -{ - const struct ec_params_pd_chip_info *p = args->params; - struct ec_response_pd_chip_info *r = args->response, *info; - - if (p->port >= CONFIG_USB_PD_PORT_COUNT) - return EC_RES_INVALID_PARAM; - - if (tcpm_get_chip_info(p->port, p->renew, &info)) - return EC_RES_ERROR; - - memcpy(r, info, sizeof(*r)); - args->response_size = sizeof(*r); - - return EC_RES_SUCCESS; -} -DECLARE_HOST_COMMAND(EC_CMD_PD_CHIP_INFO, - hc_remote_pd_chip_info, - EC_VER_MASK(0)); -#endif -#endif - -#ifdef CONFIG_USB_PD_ALT_MODE_DFP -static int hc_remote_pd_set_amode(struct host_cmd_handler_args *args) -{ - const struct ec_params_usb_pd_set_mode_request *p = args->params; - - if ((p->port >= CONFIG_USB_PD_PORT_COUNT) || (!p->svid) || (!p->opos)) - return EC_RES_INVALID_PARAM; - - switch (p->cmd) { - case PD_EXIT_MODE: - if (pd_dfp_exit_mode(p->port, p->svid, p->opos)) - pd_send_vdm(p->port, p->svid, - CMD_EXIT_MODE | VDO_OPOS(p->opos), NULL, 0); - else { - CPRINTF("Failed exit mode\n"); - return EC_RES_ERROR; - } - break; - case PD_ENTER_MODE: - if (pd_dfp_enter_mode(p->port, p->svid, p->opos)) - pd_send_vdm(p->port, p->svid, CMD_ENTER_MODE | - VDO_OPOS(p->opos), NULL, 0); - break; - default: - return EC_RES_INVALID_PARAM; - } - return EC_RES_SUCCESS; -} -DECLARE_HOST_COMMAND(EC_CMD_USB_PD_SET_AMODE, - hc_remote_pd_set_amode, - EC_VER_MASK(0)); -#endif /* CONFIG_USB_PD_ALT_MODE_DFP */ - -#endif /* HAS_TASK_HOSTCMD */ - -#ifdef CONFIG_CMD_PD_CONTROL - -static int pd_control(struct host_cmd_handler_args *args) -{ - static int pd_control_disabled[CONFIG_USB_PD_PORT_COUNT]; - const struct ec_params_pd_control *cmd = args->params; - int enable = 0; - - if (cmd->chip >= CONFIG_USB_PD_PORT_COUNT) - return EC_RES_INVALID_PARAM; - - /* Always allow disable command */ - if (cmd->subcmd == PD_CONTROL_DISABLE) { - pd_control_disabled[cmd->chip] = 1; - return EC_RES_SUCCESS; - } - - if (pd_control_disabled[cmd->chip]) - return EC_RES_ACCESS_DENIED; - - if (cmd->subcmd == PD_SUSPEND) { - enable = 0; - } else if (cmd->subcmd == PD_RESUME) { - enable = 1; - } else if (cmd->subcmd == PD_RESET) { -#ifdef HAS_TASK_PDCMD - board_reset_pd_mcu(); -#else - return EC_RES_INVALID_COMMAND; -#endif - } else if (cmd->subcmd == PD_CHIP_ON && board_set_tcpc_power_mode) { - board_set_tcpc_power_mode(cmd->chip, 1); - return EC_RES_SUCCESS; - } else { - return EC_RES_INVALID_COMMAND; - } - - pd_comm_enable(cmd->chip, enable); - pd_set_suspend(cmd->chip, !enable); - - return EC_RES_SUCCESS; -} - -DECLARE_HOST_COMMAND(EC_CMD_PD_CONTROL, pd_control, EC_VER_MASK(0)); -#endif /* CONFIG_CMD_PD_CONTROL */ - -#endif /* CONFIG_COMMON_RUNTIME */ diff --git a/workspace/TS100/Core/Drivers/FUSB302/USBC_TCPM/tcpm.h b/workspace/TS100/Core/Drivers/FUSB302/USBC_TCPM/tcpm.h deleted file mode 100644 index e44504fb..00000000 --- a/workspace/TS100/Core/Drivers/FUSB302/USBC_TCPM/tcpm.h +++ /dev/null @@ -1,258 +0,0 @@ -/* Copyright 2015 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -/* USB Power delivery port management - common header for TCPM drivers */ - -#ifndef __CROS_EC_USB_PD_TCPM_TCPM_H -#define __CROS_EC_USB_PD_TCPM_TCPM_H - -#include "tcpm_driver.h" -#include "usb_pd_tcpm.h" - -#if defined(CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE) && \ - !defined(CONFIG_USB_PD_DUAL_ROLE) -#error "DRP auto toggle requires board to have DRP support" -#error "Please upgrade your board configuration" -#endif - -#ifndef CONFIG_USB_PD_TCPC -extern const struct tcpc_config_t tcpc_config; - -/* I2C wrapper functions - get I2C port / slave addr from config struct. */ -int tcpc_write(int reg, int val); -int tcpc_write16(int reg, int val); -int tcpc_read(int reg, int *val); -int tcpc_read16(int reg, int *val); -int tcpc_xfer(const uint8_t *out, int out_size, uint8_t *in, int in_size, - int flags); - -/* TCPM driver wrapper function */ -static inline int tcpm_init() { - int rv; - - rv = tcpc_config.drv->init(); - if (rv) - return rv; - - /* Board specific post TCPC init */ - if (board_tcpc_post_init) - rv = board_tcpc_post_init(); - - return rv; -} - -static inline int tcpm_release() { - return tcpc_config.drv->release(); -} - -static inline int tcpm_get_cc(int *cc1, int *cc2) { - return tcpc_config.drv->get_cc(cc1, cc2); -} - -static inline int tcpm_get_vbus_level() { - return tcpc_config.drv->get_vbus_level(); -} - -static inline int tcpm_select_rp_value(int rp) { - return tcpc_config.drv->select_rp_value(rp); -} - -static inline int tcpm_set_cc(int pull) { - return tcpc_config.drv->set_cc(pull); -} - -static inline int tcpm_set_polarity(int polarity) { - return tcpc_config.drv->set_polarity(polarity); -} - -static inline int tcpm_set_vconn(int enable) { - return tcpc_config.drv->set_vconn(enable); -} - -static inline int tcpm_set_msg_header(int power_role, int data_role) { - return tcpc_config.drv->set_msg_header(power_role, data_role); -} - -static inline int tcpm_set_rx_enable(int enable) { - return tcpc_config.drv->set_rx_enable(enable); -} - -static inline int tcpm_get_message(uint32_t *payload, int *head) { - return tcpc_config.drv->get_message(payload, head); -} - -static inline int tcpm_transmit(enum tcpm_transmit_type type, uint16_t header, - const uint32_t *data) { - return tcpc_config.drv->transmit(type, header, data); -} - -static inline void tcpc_alert() { - tcpc_config.drv->tcpc_alert(); -} - -static inline void tcpc_discharge_vbus(int enable) { - tcpc_config.drv->tcpc_discharge_vbus(enable); -} - -#ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE -static inline int tcpm_auto_toggle_supported() -{ - return !!tcpc_config.drv->drp_toggle; -} - -static inline int tcpm_set_drp_toggle( int enable) -{ - return tcpc_config.drv->drp_toggle( enable); -} -#endif - -#ifdef CONFIG_CMD_I2C_STRESS_TEST_TCPC -static inline int tcpc_i2c_read(const int port, const int addr, - const int reg, int *data) -{ - return tcpc_read( reg, data); -} - -static inline int tcpc_i2c_write(const int port, const int addr, - const int reg, int data) -{ - return tcpc_write( reg, data); -} -#endif - -static inline int tcpm_get_chip_info(int renew, - struct ec_response_pd_chip_info **info) { - if (tcpc_config.drv->get_chip_info) - return tcpc_config.drv->get_chip_info(renew, info); - return EC_ERROR_UNIMPLEMENTED; -} - -#else - -/** - * Initialize TCPM driver and wait for TCPC readiness. - * - * @param port Type-C port number - * - * @return EC_SUCCESS or error - */ -int tcpm_init(); - -/** - * Read the CC line status. - * - * @param port Type-C port number - * @param cc1 pointer to CC status for CC1 - * @param cc2 pointer to CC status for CC2 - * - * @return EC_SUCCESS or error - */ -int tcpm_get_cc( int *cc1, int *cc2); - -/** - * Read VBUS - * - * @param port Type-C port number - * - * @return 0 => VBUS not detected, 1 => VBUS detected - */ -int tcpm_get_vbus_level(); - -/** - * Set the value of the CC pull-up used when we are a source. - * - * @param port Type-C port number - * @param rp One of enum tcpc_rp_value - * - * @return EC_SUCCESS or error - */ -int tcpm_select_rp_value( int rp); - -/** - * Set the CC pull resistor. This sets our role as either source or sink. - * - * @param port Type-C port number - * @param pull One of enum tcpc_cc_pull - * - * @return EC_SUCCESS or error - */ -int tcpm_set_cc( int pull); - -/** - * Set polarity - * - * @param port Type-C port number - * @param polarity 0=> transmit on CC1, 1=> transmit on CC2 - * - * @return EC_SUCCESS or error - */ -int tcpm_set_polarity( int polarity); - -/** - * Set Vconn. - * - * @param port Type-C port number - * @param polarity Polarity of the CC line to read - * - * @return EC_SUCCESS or error - */ -int tcpm_set_vconn( int enable); - -/** - * Set PD message header to use for goodCRC - * - * @param port Type-C port number - * @param power_role Power role to use in header - * @param data_role Data role to use in header - * - * @return EC_SUCCESS or error - */ -int tcpm_set_msg_header( int power_role, int data_role); - -/** - * Set RX enable flag - * - * @param port Type-C port number - * @enable true for enable, false for disable - * - * @return EC_SUCCESS or error - */ -int tcpm_set_rx_enable( int enable); - -/** - * Read last received PD message. - * - * @param port Type-C port number - * @param payload Pointer to location to copy payload of message - * @param header of message - * - * @return EC_SUCCESS or error - */ -int tcpm_get_message( uint32_t *payload, int *head); - -/** - * Transmit PD message - * - * @param port Type-C port number - * @param type Transmit type - * @param header Packet header - * @param cnt Number of bytes in payload - * @param data Payload - * - * @return EC_SUCCESS or error - */ -int tcpm_transmit( enum tcpm_transmit_type type, uint16_t header, - const uint32_t *data); - -/** - * TCPC is asserting alert - * - * @param port Type-C port number - */ -void tcpc_alert(); - -#endif - -#endif diff --git a/workspace/TS100/Core/Drivers/FUSB302/USBC_TCPM/usb_pd_tcpm.h b/workspace/TS100/Core/Drivers/FUSB302/USBC_TCPM/usb_pd_tcpm.h deleted file mode 100644 index 86a4fbb3..00000000 --- a/workspace/TS100/Core/Drivers/FUSB302/USBC_TCPM/usb_pd_tcpm.h +++ /dev/null @@ -1,344 +0,0 @@ -/* Copyright 2015 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -/* USB Power delivery port management */ - -#ifndef __CROS_EC_USB_PD_TCPM_H -#define __CROS_EC_USB_PD_TCPM_H - -/* List of common error codes that can be returned */ -enum ec_error_list { - /* Success - no error */ - EC_SUCCESS = 0, - /* Unknown error */ - EC_ERROR_UNKNOWN = 1, - /* Function not implemented yet */ - EC_ERROR_UNIMPLEMENTED = 2, - /* Overflow error; too much input provided. */ - EC_ERROR_OVERFLOW = 3, - /* Timeout */ - EC_ERROR_TIMEOUT = 4, - /* Invalid argument */ - EC_ERROR_INVAL = 5, - /* Already in use, or not ready yet */ - EC_ERROR_BUSY = 6, - /* Access denied */ - EC_ERROR_ACCESS_DENIED = 7, - /* Failed because component does not have power */ - EC_ERROR_NOT_POWERED = 8, - /* Failed because component is not calibrated */ - EC_ERROR_NOT_CALIBRATED = 9, - /* Failed because CRC error */ - EC_ERROR_CRC = 10, - /* Invalid console command param (PARAMn means parameter n is bad) */ - EC_ERROR_PARAM1 = 11, - EC_ERROR_PARAM2 = 12, - EC_ERROR_PARAM3 = 13, - EC_ERROR_PARAM4 = 14, - EC_ERROR_PARAM5 = 15, - EC_ERROR_PARAM6 = 16, - EC_ERROR_PARAM7 = 17, - EC_ERROR_PARAM8 = 18, - EC_ERROR_PARAM9 = 19, - /* Wrong number of params */ - EC_ERROR_PARAM_COUNT = 20, - /* Interrupt event not handled */ - EC_ERROR_NOT_HANDLED = 21, - /* Data has not changed */ - EC_ERROR_UNCHANGED = 22, - /* Memory allocation */ - EC_ERROR_MEMORY_ALLOCATION = 23, - - /* Verified boot errors */ - EC_ERROR_VBOOT_SIGNATURE = 0x1000, /* 4096 */ - EC_ERROR_VBOOT_SIG_MAGIC = 0x1001, - EC_ERROR_VBOOT_SIG_SIZE = 0x1002, - EC_ERROR_VBOOT_SIG_ALGORITHM = 0x1003, - EC_ERROR_VBOOT_HASH_ALGORITHM = 0x1004, - EC_ERROR_VBOOT_SIG_OFFSET = 0x1005, - EC_ERROR_VBOOT_DATA_SIZE = 0x1006, - - /* Verified boot key errors */ - EC_ERROR_VBOOT_KEY = 0x1100, - EC_ERROR_VBOOT_KEY_MAGIC = 0x1101, - EC_ERROR_VBOOT_KEY_SIZE = 0x1102, - - /* Verified boot data errors */ - EC_ERROR_VBOOT_DATA = 0x1200, - EC_ERROR_VBOOT_DATA_VERIFY = 0x1201, - - /* Module-internal error codes may use this range. */ - EC_ERROR_INTERNAL_FIRST = 0x10000, - EC_ERROR_INTERNAL_LAST = 0x1FFFF -}; - -/* Flags for i2c_xfer() */ -#define I2C_XFER_START (1 << 0) /* Start smbus session from idle state */ -#define I2C_XFER_STOP (1 << 1) /* Terminate smbus session with stop bit */ -#define I2C_XFER_SINGLE (I2C_XFER_START | I2C_XFER_STOP) /* One transaction */ - -/* Default retry count for transmitting */ -#define PD_RETRY_COUNT 3 - -/* Time to wait for TCPC to complete transmit */ -#define PD_T_TCPC_TX_TIMEOUT (100*MSEC) - -enum tcpc_cc_voltage_status { - TYPEC_CC_VOLT_OPEN = 0, - TYPEC_CC_VOLT_RA = 1, - TYPEC_CC_VOLT_RD = 2, - TYPEC_CC_VOLT_SNK_DEF = 5, - TYPEC_CC_VOLT_SNK_1_5 = 6, - TYPEC_CC_VOLT_SNK_3_0 = 7, -}; - -enum tcpc_cc_pull { - TYPEC_CC_RA = 0, TYPEC_CC_RP = 1, TYPEC_CC_RD = 2, TYPEC_CC_OPEN = 3, -}; - -enum tcpc_rp_value { - TYPEC_RP_USB = 0, TYPEC_RP_1A5 = 1, TYPEC_RP_3A0 = 2, TYPEC_RP_RESERVED = 3, -}; - -enum tcpm_transmit_type { - TCPC_TX_SOP = 0, - TCPC_TX_SOP_PRIME = 1, - TCPC_TX_SOP_PRIME_PRIME = 2, - TCPC_TX_SOP_DEBUG_PRIME = 3, - TCPC_TX_SOP_DEBUG_PRIME_PRIME = 4, - TCPC_TX_HARD_RESET = 5, - TCPC_TX_CABLE_RESET = 6, - TCPC_TX_BIST_MODE_2 = 7 -}; - -enum tcpc_transmit_complete { - TCPC_TX_COMPLETE_SUCCESS = 0, - TCPC_TX_COMPLETE_DISCARDED = 1, - TCPC_TX_COMPLETE_FAILED = 2, -}; - -struct tcpm_drv { - /** - * Initialize TCPM driver and wait for TCPC readiness. - * - * @param port Type-C port number - * - * @return EC_SUCCESS or error - */ - int (*init)(); - - /** - * Release the TCPM hardware and disconnect the driver. - * Only .init() can be called after .release(). - * - * @param port Type-C port number - * - * @return EC_SUCCESS or error - */ - int (*release)(); - - /** - * Read the CC line status. - * - * @param port Type-C port number - * @param cc1 pointer to CC status for CC1 - * @param cc2 pointer to CC status for CC2 - * - * @return EC_SUCCESS or error - */ - int (*get_cc)(int *cc1, int *cc2); - - /** - * Read VBUS - * - * @param port Type-C port number - * - * @return 0 => VBUS not detected, 1 => VBUS detected - */ - int (*get_vbus_level)(); - - /** - * Set the value of the CC pull-up used when we are a source. - * - * @param port Type-C port number - * @param rp One of enum tcpc_rp_value - * - * @return EC_SUCCESS or error - */ - int (*select_rp_value)(int rp); - - /** - * Set the CC pull resistor. This sets our role as either source or sink. - * - * @param port Type-C port number - * @param pull One of enum tcpc_cc_pull - * - * @return EC_SUCCESS or error - */ - int (*set_cc)(int pull); - - /** - * Set polarity - * - * @param port Type-C port number - * @param polarity 0=> transmit on CC1, 1=> transmit on CC2 - * - * @return EC_SUCCESS or error - */ - int (*set_polarity)(int polarity); - - /** - * Set Vconn. - * - * @param port Type-C port number - * @param polarity Polarity of the CC line to read - * - * @return EC_SUCCESS or error - */ - int (*set_vconn)(int enable); - - /** - * Set PD message header to use for goodCRC - * - * @param port Type-C port number - * @param power_role Power role to use in header - * @param data_role Data role to use in header - * - * @return EC_SUCCESS or error - */ - int (*set_msg_header)(int power_role, int data_role); - - /** - * Set RX enable flag - * - * @param port Type-C port number - * @enable true for enable, false for disable - * - * @return EC_SUCCESS or error - */ - int (*set_rx_enable)(int enable); - - /** - * Read last received PD message. - * - * @param port Type-C port number - * @param payload Pointer to location to copy payload of message - * @param header of message - * - * @return EC_SUCCESS or error - */ - int (*get_message)(uint32_t *payload, int *head); - - /** - * Transmit PD message - * - * @param port Type-C port number - * @param type Transmit type - * @param header Packet header - * @param cnt Number of bytes in payload - * @param data Payload - * - * @return EC_SUCCESS or error - */ - int (*transmit)(enum tcpm_transmit_type type, uint16_t header, - const uint32_t *data); - - /** - * TCPC is asserting alert - * - * @param port Type-C port number - */ - void (*tcpc_alert)(); - - /** - * Discharge PD VBUS on src/sink disconnect & power role swap - * - * @param port Type-C port number - * @param enable Discharge enable or disable - */ - void (*tcpc_discharge_vbus)(int enable); - -#ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE - /** - * Enable TCPC auto DRP toggling. - * - * @param port Type-C port number - * @param enable 1: Enable 0: Disable - * - * @return EC_SUCCESS or error - */ - int (*drp_toggle)( int enable); -#endif - - /** - * Get firmware version. - * - * @param port Type-C port number - * @param renew Force renewal - * @param info Pointer to pointer to PD chip info - * - * @return EC_SUCCESS or error - */ - int (*get_chip_info)(int renew, struct ec_response_pd_chip_info **info); -}; - -enum tcpc_alert_polarity { - TCPC_ALERT_ACTIVE_LOW, TCPC_ALERT_ACTIVE_HIGH, -}; - -struct tcpc_config_t { - int i2c_slave_addr; - const struct tcpm_drv *drv; -}; - -/** - * Returns the PD_STATUS_TCPC_ALERT_* mask corresponding to the TCPC ports - * that are currently asserting ALERT. - * - * @return PD_STATUS_TCPC_ALERT_* mask. - */ -uint16_t tcpc_get_alert_status(void); - -/** - * Optional, set the TCPC power mode. - * - * @param port Type-C port number - * @param mode 0: off/sleep, 1: on/awake - */ -void board_set_tcpc_power_mode(int mode) __attribute__((weak)); - -/** - * Initialize TCPC. - * - * @param port Type-C port number - */ -void tcpc_init(); - -/** - * TCPC is asserting alert - * - * @param port Type-C port number - */ -void tcpc_alert_clear(); - -/** - * Run TCPC task once. This checks for incoming messages, processes - * any outgoing messages, and reads CC lines. - * - * @param port Type-C port number - * @param evt Event type that woke up this task - */ -int tcpc_run(int evt); - -/** - * Initialize board specific TCPC functions post TCPC initialization. - * - * @param port Type-C port number - * - * @return EC_SUCCESS or error - */ -int board_tcpc_post_init() __attribute__((weak)); - -#endif /* __CROS_EC_USB_PD_TCPM_H */ diff --git a/workspace/TS100/Core/Drivers/FUSB302/fusb302b.cpp b/workspace/TS100/Core/Drivers/FUSB302/fusb302b.cpp new file mode 100644 index 00000000..46956178 --- /dev/null +++ b/workspace/TS100/Core/Drivers/FUSB302/fusb302b.cpp @@ -0,0 +1,204 @@ +/* + * PD Buddy Firmware Library - USB Power Delivery for everyone + * Copyright 2017-2018 Clayton G. Hobbs + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "fusb302b.h" +#include "I2CBB.hpp" +#include + +/* + * Read a single byte from the FUSB302B + * + * cfg: The FUSB302B to communicate with + * addr: The memory address from which to read + * + * Returns the value read from addr. + */ +static uint8_t fusb_read_byte(uint8_t addr) { + uint8_t data[1]; + I2CBB::Mem_Read(FUSB302B_ADDR, addr, (uint8_t*) data, 1); + return data[0]; +} + +/* + * Read multiple bytes from the FUSB302B + * + * cfg: The FUSB302B to communicate with + * addr: The memory address from which to read + * size: The number of bytes to read + * buf: The buffer into which data will be read + */ +static void fusb_read_buf(uint8_t addr, uint8_t size, uint8_t *buf) { + I2CBB::Mem_Read(FUSB302B_ADDR, addr, (uint8_t*) buf, size); + +} + +/* + * Write a single byte to the FUSB302B + * + * cfg: The FUSB302B to communicate with + * addr: The memory address to which we will write + * byte: The value to write + */ +static void fusb_write_byte(uint8_t addr, uint8_t byte) { + I2CBB::Mem_Write(FUSB302B_ADDR, addr, (uint8_t*) &byte, 1); + +} + +/* + * Write multiple bytes to the FUSB302B + * + * cfg: The FUSB302B to communicate with + * addr: The memory address to which we will write + * size: The number of bytes to write + * buf: The buffer to write + */ +static void fusb_write_buf(uint8_t addr, uint8_t size, const uint8_t *buf) { + I2CBB::Mem_Write(FUSB302B_ADDR, addr, (uint8_t*) &buf, size); + +} + +void fusb_send_message(const union pd_msg *msg) { + /* Token sequences for the FUSB302B */ + static uint8_t sop_seq[5] = { + FUSB_FIFO_TX_SOP1, + FUSB_FIFO_TX_SOP1, + FUSB_FIFO_TX_SOP1, + FUSB_FIFO_TX_SOP2, + FUSB_FIFO_TX_PACKSYM }; + static const uint8_t eop_seq[4] = { + FUSB_FIFO_TX_JAM_CRC, + FUSB_FIFO_TX_EOP, + FUSB_FIFO_TX_TXOFF, + FUSB_FIFO_TX_TXON }; + + /* Take the I2C2 mutex now so there can't be a race condition on sop_seq */ + /* Get the length of the message: a two-octet header plus NUMOBJ four-octet + * data objects */ + uint8_t msg_len = 2 + 4 * PD_NUMOBJ_GET(msg); + + /* Set the number of bytes to be transmitted in the packet */ + sop_seq[4] = FUSB_FIFO_TX_PACKSYM | msg_len; + + /* Write all three parts of the message to the TX FIFO */ + fusb_write_buf( FUSB_FIFOS, 5, sop_seq); + fusb_write_buf( FUSB_FIFOS, msg_len, msg->bytes); + fusb_write_buf( FUSB_FIFOS, 4, eop_seq); + +} + +uint8_t fusb_read_message(union pd_msg *msg) { + uint8_t garbage[4]; + uint8_t numobj; + + /* If this isn't an SOP message, return error. + * Because of our configuration, we should be able to assume this means the + * buffer is empty, and not try to read past a non-SOP message. */ + if ((fusb_read_byte( FUSB_FIFOS) & FUSB_FIFO_RX_TOKEN_BITS) + != FUSB_FIFO_RX_SOP) { + return 1; + } + /* Read the message header into msg */ + fusb_read_buf( FUSB_FIFOS, 2, msg->bytes); + /* Get the number of data objects */ + numobj = PD_NUMOBJ_GET(msg); + /* If there is at least one data object, read the data objects */ + if (numobj > 0) { + fusb_read_buf( FUSB_FIFOS, numobj * 4, msg->bytes + 2); + } + /* Throw the CRC32 in the garbage, since the PHY already checked it. */ + fusb_read_buf( FUSB_FIFOS, 4, garbage); + + return 0; +} + +void fusb_send_hardrst() { + + /* Send a hard reset */ + fusb_write_byte( FUSB_CONTROL3, 0x07 | FUSB_CONTROL3_SEND_HARD_RESET); + +} + +void fusb_setup() { + + /* Fully reset the FUSB302B */ + fusb_write_byte( FUSB_RESET, FUSB_RESET_SW_RES); + + /* Turn on all power */ + fusb_write_byte( FUSB_POWER, 0x0F); + + /* Set interrupt masks */ + fusb_write_byte( FUSB_MASK1, 0x00); + fusb_write_byte( FUSB_MASKA, 0x00); + fusb_write_byte( FUSB_MASKB, 0x00); + fusb_write_byte( FUSB_CONTROL0, 0x04); + + /* Enable automatic retransmission */ + fusb_write_byte( FUSB_CONTROL3, 0x07); + + /* Flush the RX buffer */ + fusb_write_byte( FUSB_CONTROL1, FUSB_CONTROL1_RX_FLUSH); + + /* Measure CC1 */ + fusb_write_byte( FUSB_SWITCHES0, 0x07); + osDelay(1); + uint8_t cc1 = fusb_read_byte( FUSB_STATUS0) & FUSB_STATUS0_BC_LVL; + + /* Measure CC2 */ + fusb_write_byte( FUSB_SWITCHES0, 0x0B); + osDelay(1); + uint8_t cc2 = fusb_read_byte( FUSB_STATUS0) & FUSB_STATUS0_BC_LVL; + + /* Select the correct CC line for BMC signaling; also enable AUTO_CRC */ + if (cc1 > cc2) { + fusb_write_byte( FUSB_SWITCHES1, 0x25); + fusb_write_byte( FUSB_SWITCHES0, 0x07); + } else { + fusb_write_byte( FUSB_SWITCHES1, 0x26); + fusb_write_byte( FUSB_SWITCHES0, 0x0B); + } + + /* Reset the PD logic */ + fusb_write_byte( FUSB_RESET, FUSB_RESET_PD_RESET); + +} + +void fusb_get_status(union fusb_status *status) { + + /* Read the interrupt and status flags into status */ + fusb_read_buf( FUSB_STATUS0A, 7, status->bytes); + +} + +enum fusb_typec_current fusb_get_typec_current() { + + /* Read the BC_LVL into a variable */ + enum fusb_typec_current bc_lvl = (enum fusb_typec_current) (fusb_read_byte( + FUSB_STATUS0) & FUSB_STATUS0_BC_LVL); + + return bc_lvl; +} + +void fusb_reset() { + + /* Flush the TX buffer */ + fusb_write_byte( FUSB_CONTROL0, 0x44); + /* Flush the RX buffer */ + fusb_write_byte( FUSB_CONTROL1, FUSB_CONTROL1_RX_FLUSH); + /* Reset the PD logic */ + fusb_write_byte( FUSB_RESET, FUSB_RESET_PD_RESET); + +} diff --git a/workspace/TS100/Core/Drivers/FUSB302/fusb302b.h b/workspace/TS100/Core/Drivers/FUSB302/fusb302b.h new file mode 100644 index 00000000..7bb4ed2c --- /dev/null +++ b/workspace/TS100/Core/Drivers/FUSB302/fusb302b.h @@ -0,0 +1,303 @@ +/* + * PD Buddy Firmware Library - USB Power Delivery for everyone + * Copyright 2017-2018 Clayton G. Hobbs + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef PDB_FUSB302B_H +#define PDB_FUSB302B_H + +#include + +#include "pd.h" +#include + +/* I2C addresses of the FUSB302B chips */ +#define FUSB302B_ADDR 0x22 +#define FUSB302B01_ADDR 0x23 +#define FUSB302B10_ADDR 0x24 +#define FUSB302B11_ADDR 0x25 + +/* Device ID register */ +#define FUSB_DEVICE_ID 0x01 +#define FUSB_DEVICE_ID_VERSION_ID_SHIFT 4 +#define FUSB_DEVICE_ID_VERSION_ID (0xF << FUSB_DEVICE_ID_VERSION_ID_SHIFT) +#define FUSB_DEVICE_ID_PRODUCT_ID_SHIFT 2 +#define FUSB_DEVICE_ID_PRODUCT_ID (0x3 << FUSB_DEVICE_ID_PRODUCT_ID_SHIFT) +#define FUSB_DEVICE_ID_REVISION_ID_SHIFT 0 +#define FUSB_DEVICE_ID_REVISION_ID (0x3 << FUSB_DEVICE_ID_REVISION_ID_SHIFT) + +/* Switches0 register */ +#define FUSB_SWITCHES0 0x02 +#define FUSB_SWITCHES0_PU_EN2 (1 << 7) +#define FUSB_SWITCHES0_PU_EN1 (1 << 6) +#define FUSB_SWITCHES0_VCONN_CC2 (1 << 5) +#define FUSB_SWITCHES0_VCONN_CC1 (1 << 4) +#define FUSB_SWITCHES0_MEAS_CC2 (1 << 3) +#define FUSB_SWITCHES0_MEAS_CC1 (1 << 2) +#define FUSB_SWITCHES0_PDWN_2 (1 << 1) +#define FUSB_SWITCHES0_PDWN_1 1 + +/* Switches1 register */ +#define FUSB_SWITCHES1 0x03 +#define FUSB_SWITCHES1_POWERROLE (1 << 7) +#define FUSB_SWITCHES1_SPECREV_SHIFT 5 +#define FUSB_SWITCHES1_SPECREV (0x3 << FUSB_SWITCHES1_SPECREV_SHIFT) +#define FUSB_SWITCHES1_DATAROLE (1 << 4) +#define FUSB_SWITCHES1_AUTO_CRC (1 << 2) +#define FUSB_SWITCHES1_TXCC2 (1 << 1) +#define FUSB_SWITCHES1_TXCC1 1 + +/* Measure register */ +#define FUSB_MEASURE 0x04 +#define FUSB_MEASURE_MEAS_VBUS (1 << 6) +#define FUSB_MEASURE_MDAC_SHIFT 0 +#define FUSB_MEASURE_MDAC (0x3F << FUSB_MEASURE_MDAC_SHIFT) + +/* Slice register */ +#define FUSB_SLICE 0x05 +#define FUSB_SLICE_SDAC_HYS_SHIFT 6 +#define FUSB_SLICE_SDAC_HYS (0x3 << FUSB_SLICE_SDAC_HYS_SHIFT) +#define FUSB_SLICE_SDAC_SHIFT 0 +#define FUSB_SLICE_SDAC (0x3F << FUSB_SLICE_SDAC_SHIFT) + +/* Control0 register */ +#define FUSB_CONTROL0 0x06 +#define FUSB_CONTROL0_TX_FLUSH (1 << 6) +#define FUSB_CONTROL0_INT_MASK (1 << 5) +#define FUSB_CONTROL0_HOST_CUR_SHIFT 2 +#define FUSB_CONTROL0_HOST_CUR (0x3 << FUSB_CONTROL0_HOST_CUR_SHIFT) +#define FUSB_CONTROL0_AUTO_PRE (1 << 1) +#define FUSB_CONTROL0_TX_START 1 + +/* Control1 register */ +#define FUSB_CONTROL1 0x07 +#define FUSB_CONTROL1_ENSOP2DB (1 << 6) +#define FUSB_CONTROL1_ENSOP1DB (1 << 5) +#define FUSB_CONTROL1_BIST_MODE2 (1 << 4) +#define FUSB_CONTROL1_RX_FLUSH (1 << 2) +#define FUSB_CONTROL1_ENSOP2 (1 << 1) +#define FUSB_CONTROL1_ENSOP1 1 + +/* Control2 register */ +#define FUSB_CONTROL2 0x08 +#define FUSB_CONTROL2_TOG_SAVE_PWR_SHIFT 6 +#define FUSB_CONTROL2_TOG_SAVE_PWR (0x3 << FUSB_CONTROL2_TOG_SAVE_PWR) +#define FUSB_CONTROL2_TOG_RD_ONLY (1 << 5) +#define FUSB_CONTROL2_WAKE_EN (1 << 3) +#define FUSB_CONTROL2_MODE_SHIFT 1 +#define FUSB_CONTROL2_MODE (0x3 << FUSB_CONTROL2_MODE_SHIFT) +#define FUSB_CONTROL2_TOGGLE 1 + +/* Control3 register */ +#define FUSB_CONTROL3 0x09 +#define FUSB_CONTROL3_SEND_HARD_RESET (1 << 6) +#define FUSB_CONTROL3_BIST_TMODE (1 << 5) +#define FUSB_CONTROL3_AUTO_HARDRESET (1 << 4) +#define FUSB_CONTROL3_AUTO_SOFTRESET (1 << 3) +#define FUSB_CONTROL3_N_RETRIES_SHIFT 1 +#define FUSB_CONTROL3_N_RETRIES (0x3 << FUSB_CONTROL3_N_RETRIES_SHIFT) +#define FUSB_CONTROL3_AUTO_RETRY 1 + +/* Mask1 register */ +#define FUSB_MASK1 0x0A +#define FUSB_MASK1_M_VBUSOK (1 << 7) +#define FUSB_MASK1_M_ACTIVITY (1 << 6) +#define FUSB_MASK1_M_COMP_CHNG (1 << 5) +#define FUSB_MASK1_M_CRC_CHK (1 << 4) +#define FUSB_MASK1_M_ALERT (1 << 3) +#define FUSB_MASK1_M_WAKE (1 << 2) +#define FUSB_MASK1_M_COLLISION (1 << 1) +#define FUSB_MASK1_M_BC_LVL (1 << 0) + +/* Power register */ +#define FUSB_POWER 0x0B +#define FUSB_POWER_PWR3 (1 << 3) +#define FUSB_POWER_PWR2 (1 << 2) +#define FUSB_POWER_PWR1 (1 << 1) +#define FUSB_POWER_PWR0 1 + +/* Reset register */ +#define FUSB_RESET 0x0C +#define FUSB_RESET_PD_RESET (1 << 1) +#define FUSB_RESET_SW_RES 1 + +/* OCPreg register */ +#define FUSB_OCPREG 0x0D +#define FUSB_OCPREG_OCP_RANGE (1 << 3) +#define FUSB_OCPREG_OCP_CUR_SHIFT 0 +#define FUSB_OCPREG_OCP_CUR (0x7 << FUSB_OCPREG_OCP_CUR_SHIFT) + +/* Maska register */ +#define FUSB_MASKA 0x0E +#define FUSB_MASKA_M_OCP_TEMP (1 << 7) +#define FUSB_MASKA_M_TOGDONE (1 << 6) +#define FUSB_MASKA_M_SOFTFAIL (1 << 5) +#define FUSB_MASKA_M_RETRYFAIL (1 << 4) +#define FUSB_MASKA_M_HARDSENT (1 << 3) +#define FUSB_MASKA_M_TXSENT (1 << 2) +#define FUSB_MASKA_M_SOFTRST (1 << 1) +#define FUSB_MASKA_M_HARDRST 1 + +/* Maskb register */ +#define FUSB_MASKB 0x0F +#define FUSB_MASKB_M_GCRCSENT 1 + +/* Control4 register */ +#define FUSB_CONTROL4 0x10 +#define FUSB_CONTROL4_TOG_EXIT_AUD 1 + +/* Status0a register */ +#define FUSB_STATUS0A 0x3C +#define FUSB_STATUS0A_SOFTFAIL (1 << 5) +#define FUSB_STATUS0A_RETRYFAIL (1 << 4) +#define FUSB_STATUS0A_POWER3 (1 << 3) +#define FUSB_STATUS0A_POWER2 (1 << 2) +#define FUSB_STATUS0A_SOFTRST (1 << 1) +#define FUSB_STATUS0A_HARDRST 1 + +/* Status1a register */ +#define FUSB_STATUS1A 0x3D +#define FUSB_STATUS1A_TOGSS_SHIFT 3 +#define FUSB_STATUS1A_TOGSS (0x7 << FUSB_STATUS1A_TOGSS_SHIFT) +#define FUSB_STATUS1A_RXSOP2DB (1 << 2) +#define FUSB_STATUS1A_RXSOP1DB (1 << 1) +#define FUSB_STATUS1A_RXSOP 1 + +/* Interrupta register */ +#define FUSB_INTERRUPTA 0x3E +#define FUSB_INTERRUPTA_I_OCP_TEMP (1 << 7) +#define FUSB_INTERRUPTA_I_TOGDONE (1 << 6) +#define FUSB_INTERRUPTA_I_SOFTFAIL (1 << 5) +#define FUSB_INTERRUPTA_I_RETRYFAIL (1 << 4) +#define FUSB_INTERRUPTA_I_HARDSENT (1 << 3) +#define FUSB_INTERRUPTA_I_TXSENT (1 << 2) +#define FUSB_INTERRUPTA_I_SOFTRST (1 << 1) +#define FUSB_INTERRUPTA_I_HARDRST 1 + +/* Interruptb register */ +#define FUSB_INTERRUPTB 0x3F +#define FUSB_INTERRUPTB_I_GCRCSENT 1 + +/* Status0 register */ +#define FUSB_STATUS0 0x40 +#define FUSB_STATUS0_VBUSOK (1 << 7) +#define FUSB_STATUS0_ACTIVITY (1 << 6) +#define FUSB_STATUS0_COMP (1 << 5) +#define FUSB_STATUS0_CRC_CHK (1 << 4) +#define FUSB_STATUS0_ALERT (1 << 3) +#define FUSB_STATUS0_WAKE (1 << 2) +#define FUSB_STATUS0_BC_LVL_SHIFT 0 +#define FUSB_STATUS0_BC_LVL (0x3 << FUSB_STATUS0_BC_LVL_SHIFT) + +/* Status1 register */ +#define FUSB_STATUS1 0x41 +#define FUSB_STATUS1_RXSOP2 (1 << 7) +#define FUSB_STATUS1_RXSOP1 (1 << 6) +#define FUSB_STATUS1_RX_EMPTY (1 << 5) +#define FUSB_STATUS1_RX_FULL (1 << 4) +#define FUSB_STATUS1_TX_EMPTY (1 << 3) +#define FUSB_STATUS1_TX_FULL (1 << 2) +#define FUSB_STATUS1_OVRTEMP (1 << 1) +#define FUSB_STATUS1_OCP 1 + +/* Interrupt register */ +#define FUSB_INTERRUPT 0x42 +#define FUSB_INTERRUPT_I_VBUSOK (1 << 7) +#define FUSB_INTERRUPT_I_ACTIVITY (1 << 6) +#define FUSB_INTERRUPT_I_COMP_CHNG (1 << 5) +#define FUSB_INTERRUPT_I_CRC_CHK (1 << 4) +#define FUSB_INTERRUPT_I_ALERT (1 << 3) +#define FUSB_INTERRUPT_I_WAKE (1 << 2) +#define FUSB_INTERRUPT_I_COLLISION (1 << 1) +#define FUSB_INTERRUPT_I_BC_LVL 1 + +/* FIFOs register */ +#define FUSB_FIFOS 0x43 + +#define FUSB_FIFO_TX_TXON 0xA1 +#define FUSB_FIFO_TX_SOP1 0x12 +#define FUSB_FIFO_TX_SOP2 0x13 +#define FUSB_FIFO_TX_SOP3 0x1B +#define FUSB_FIFO_TX_RESET1 0x15 +#define FUSB_FIFO_TX_RESET2 0x16 +#define FUSB_FIFO_TX_PACKSYM 0x80 +#define FUSB_FIFO_TX_JAM_CRC 0xFF +#define FUSB_FIFO_TX_EOP 0x14 +#define FUSB_FIFO_TX_TXOFF 0xFE + +#define FUSB_FIFO_RX_TOKEN_BITS 0xE0 +#define FUSB_FIFO_RX_SOP 0xE0 +#define FUSB_FIFO_RX_SOP1 0xC0 +#define FUSB_FIFO_RX_SOP2 0xA0 +#define FUSB_FIFO_RX_SOP1DB 0x80 +#define FUSB_FIFO_RX_SOP2DB 0x60 + +/* + * FUSB status union + * + * Provides a nicer structure than just an array of uint8_t for working with + * the FUSB302B status and interrupt flags. + */ +union fusb_status { + uint8_t bytes[7]; + struct { + uint8_t status0a; + uint8_t status1a; + uint8_t interrupta; + uint8_t interruptb; + uint8_t status0; + uint8_t status1; + uint8_t interrupt; + }; +}; + +/* FUSB functions */ + +/* + * Send a USB Power Delivery message to the FUSB302B + */ +void fusb_send_message(const union pd_msg *msg); + +/* + * Read a USB Power Delivery message from the FUSB302B + */ +uint8_t fusb_read_message(union pd_msg *msg); + +/* + * Tell the FUSB302B to send a hard reset signal + */ +void fusb_send_hardrst(); + +/* + * Read the FUSB302B status and interrupt flags into *status + */ +void fusb_get_status(union fusb_status *status); + +/* + * Read the FUSB302B BC_LVL as an enum fusb_typec_current + */ +enum fusb_typec_current fusb_get_typec_current(); + +/* + * Initialization routine for the FUSB302B + */ +void fusb_setup(); + +/* + * Reset the FUSB302B + */ +void fusb_reset(); + +#endif /* PDB_FUSB302B_H */ diff --git a/workspace/TS100/Core/Drivers/FUSB302/fusbpd.cpp b/workspace/TS100/Core/Drivers/FUSB302/fusbpd.cpp new file mode 100644 index 00000000..00b84e96 --- /dev/null +++ b/workspace/TS100/Core/Drivers/FUSB302/fusbpd.cpp @@ -0,0 +1,38 @@ +/* + * fusbpd.cpp + * + * Created on: 13 Jun 2020 + * Author: Ralim + */ + +#include +#include +#include "I2CBB.hpp" +#include "fusb302b.h" +#include "policy_engine.h" +#include "protocol_rx.h" +#include "protocol_tx.h" +#include "int_n.h" +#include "hard_reset.h" + +uint8_t fusb302_detect() { + //Probe the I2C bus for its address + return I2CBB::probe(FUSB302B_ADDR); +} + +void fusb302_start_processing() { + + /* Initialize the FUSB302B */ + fusb_setup(); + + /* Create the policy engine thread. */ + PolicyEngine::init(); + + /* Create the protocol layer threads. */ + ProtocolReceive::init(); + ProtocolTransmit::init(); + ResetHandler::init(); + + /* Create the INT_N thread. */ + InterruptHandler::init(); +} diff --git a/workspace/TS100/Core/Drivers/FUSB302/fusbpd.h b/workspace/TS100/Core/Drivers/FUSB302/fusbpd.h new file mode 100644 index 00000000..b48dfc4e --- /dev/null +++ b/workspace/TS100/Core/Drivers/FUSB302/fusbpd.h @@ -0,0 +1,18 @@ +/* + * fusbpd.h + * + * Created on: 13 Jun 2020 + * Author: Ralim + */ + +#ifndef DRIVERS_FUSB302_FUSBPD_H_ +#define DRIVERS_FUSB302_FUSBPD_H_ +//Wrapper for all of the FUSB302 PD work +extern struct pdb_config pdb_config_data; +#include + +//returns 1 if the FUSB302 is on the I2C bus +uint8_t fusb302_detect(); + +void fusb302_start_processing(); +#endif /* DRIVERS_FUSB302_FUSBPD_H_ */ diff --git a/workspace/TS100/Core/Drivers/FUSB302/hard_reset.cpp b/workspace/TS100/Core/Drivers/FUSB302/hard_reset.cpp new file mode 100644 index 00000000..648a7f4e --- /dev/null +++ b/workspace/TS100/Core/Drivers/FUSB302/hard_reset.cpp @@ -0,0 +1,148 @@ +/* + * PD Buddy Firmware Library - USB Power Delivery for everyone + * Copyright 2017-2018 Clayton G. Hobbs + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "hard_reset.h" +#include "fusbpd.h" +#include +#include "policy_engine.h" +#include "protocol_rx.h" +#include "protocol_tx.h" +#include "fusb302b.h" + +osThreadId ResetHandler::TaskHandle; +uint32_t ResetHandler::TaskBuffer[ResetHandler::TaskStackSize]; +osStaticThreadDef_t ResetHandler::TaskControlBlock; + +/* + * PRL_HR_Reset_Layer state + */ +ResetHandler::hardrst_state ResetHandler::hardrst_reset_layer() { + /* First, wait for the signal to run a hard reset. */ + eventmask_t evt = waitForEvent( + PDB_EVT_HARDRST_RESET | PDB_EVT_HARDRST_I_HARDRST); + + /* Reset the Protocol RX machine */ + ProtocolReceive::notify( PDB_EVT_PRLRX_RESET); + taskYIELD(); + + /* Reset the Protocol TX machine */ + ProtocolTransmit::notify(PDB_EVT_PRLTX_RESET); + taskYIELD(); + + /* Continue the process based on what event started the reset. */ + if (evt & PDB_EVT_HARDRST_RESET) { + /* Policy Engine started the reset. */ + return PRLHRRequestHardReset; + } else { + /* PHY started the reset */ + return PRLHRIndicateHardReset; + } +} + +ResetHandler::hardrst_state ResetHandler::hardrst_indicate_hard_reset() { + /* Tell the PE that we're doing a hard reset */ + PolicyEngine::notify( PDB_EVT_PE_RESET); + + return PRLHRWaitPE; +} + +ResetHandler::hardrst_state ResetHandler::hardrst_request_hard_reset() { + /* Tell the PHY to send a hard reset */ + fusb_send_hardrst(); + + return PRLHRWaitPHY; +} + +ResetHandler::hardrst_state ResetHandler::hardrst_wait_phy() { + /* Wait for the PHY to tell us that it's done sending the hard reset */ + waitForEvent(PDB_EVT_HARDRST_I_HARDSENT, PD_T_HARD_RESET_COMPLETE); + + /* Move on no matter what made us stop waiting. */ + return PRLHRHardResetRequested; +} + +ResetHandler::hardrst_state ResetHandler::hardrst_hard_reset_requested() { + /* Tell the PE that the hard reset was sent */ + PolicyEngine::notify( PDB_EVT_PE_HARD_SENT); + + return PRLHRWaitPE; +} + +ResetHandler::hardrst_state ResetHandler::hardrst_wait_pe() { + /* Wait for the PE to tell us that it's done */ + waitForEvent(PDB_EVT_HARDRST_DONE); + + return PRLHRComplete; +} + +ResetHandler::hardrst_state ResetHandler::hardrst_complete() { + /* I'm not aware of anything we have to tell the FUSB302B, so just finish + * the reset routine. */ + return PRLHRResetLayer; +} + +void ResetHandler::init() { + osThreadStaticDef(Task, Thread, PDB_PRIO_PE, 0, TaskStackSize, TaskBuffer, + &TaskControlBlock); + TaskHandle = osThreadCreate(osThread(Task), NULL); +} + +void ResetHandler::notify(uint32_t notification) { + xTaskNotify(TaskHandle, notification, + eNotifyAction::eSetValueWithOverwrite); +} + +void ResetHandler::Thread(const void *arg) { + (void) arg; + ResetHandler::hardrst_state state = PRLHRResetLayer; + + while (true) { + switch (state) { + case PRLHRResetLayer: + state = hardrst_reset_layer(); + break; + case PRLHRIndicateHardReset: + state = hardrst_indicate_hard_reset(); + break; + case PRLHRRequestHardReset: + state = hardrst_request_hard_reset(); + break; + case PRLHRWaitPHY: + state = hardrst_wait_phy(); + break; + case PRLHRHardResetRequested: + state = hardrst_hard_reset_requested(); + break; + case PRLHRWaitPE: + state = hardrst_wait_pe(); + break; + case PRLHRComplete: + state = hardrst_complete(); + break; + default: + /* This is an error. It really shouldn't happen. We might + * want to handle it anyway, though. */ + break; + } + } +} + +uint32_t ResetHandler::waitForEvent(uint32_t mask, uint32_t ticksToWait) { + uint32_t pulNotificationValue; + xTaskNotifyWait(0x00, mask, &pulNotificationValue, ticksToWait); + return pulNotificationValue; +} diff --git a/workspace/TS100/Core/Drivers/FUSB302/hard_reset.h b/workspace/TS100/Core/Drivers/FUSB302/hard_reset.h new file mode 100644 index 00000000..46ab9bd8 --- /dev/null +++ b/workspace/TS100/Core/Drivers/FUSB302/hard_reset.h @@ -0,0 +1,63 @@ +/* + * PD Buddy Firmware Library - USB Power Delivery for everyone + * Copyright 2017-2018 Clayton G. Hobbs + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef PDB_HARD_RESET_H +#define PDB_HARD_RESET_H + +#include + +/* Events for the Hard Reset thread */ +#define PDB_EVT_HARDRST_RESET EVENT_MASK(0) +#define PDB_EVT_HARDRST_I_HARDRST EVENT_MASK(1) +#define PDB_EVT_HARDRST_I_HARDSENT EVENT_MASK(2) +#define PDB_EVT_HARDRST_DONE EVENT_MASK(3) + +class ResetHandler { +public: + static void init(); + static void notify(uint32_t notification); +private: + static void Thread(const void *arg); + static osThreadId TaskHandle; + static const size_t TaskStackSize = 1024 / 4; + static uint32_t TaskBuffer[TaskStackSize]; + static osStaticThreadDef_t TaskControlBlock; + static uint32_t waitForEvent(uint32_t mask, uint32_t ticksToWait = + portMAX_DELAY); + + /* + * Hard Reset machine states + */ + enum hardrst_state { + PRLHRResetLayer, + PRLHRIndicateHardReset, + PRLHRRequestHardReset, + PRLHRWaitPHY, + PRLHRHardResetRequested, + PRLHRWaitPE, + PRLHRComplete + }; + static hardrst_state hardrst_reset_layer(); + static hardrst_state hardrst_indicate_hard_reset(); + static hardrst_state hardrst_request_hard_reset(); + static hardrst_state hardrst_wait_phy(); + static hardrst_state hardrst_hard_reset_requested(); + static hardrst_state hardrst_wait_pe(); + static hardrst_state hardrst_complete(); +}; + +#endif /* PDB_HARD_RESET_H */ diff --git a/workspace/TS100/Core/Drivers/FUSB302/int_n.cpp b/workspace/TS100/Core/Drivers/FUSB302/int_n.cpp new file mode 100644 index 00000000..58ea1b9d --- /dev/null +++ b/workspace/TS100/Core/Drivers/FUSB302/int_n.cpp @@ -0,0 +1,97 @@ +/* + * PD Buddy Firmware Library - USB Power Delivery for everyone + * Copyright 2017-2018 Clayton G. Hobbs + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "int_n.h" +#include "fusbpd.h" +#include +#include "fusb302b.h" +#include "protocol_rx.h" +#include "protocol_tx.h" +#include "hard_reset.h" +#include "policy_engine.h" +#include "protocol_rx.h" +#include "protocol_tx.h" +#include "BSP.h" + +osThreadId InterruptHandler::TaskHandle; +uint32_t InterruptHandler::TaskBuffer[InterruptHandler::TaskStackSize]; +osStaticThreadDef_t InterruptHandler::TaskControlBlock; + +void InterruptHandler::init() { + osThreadStaticDef(Task, Thread, PDB_PRIO_PE, 0, TaskStackSize, TaskBuffer, + &TaskControlBlock); + TaskHandle = osThreadCreate(osThread(Task), NULL); +} + +void InterruptHandler::Thread(const void *arg) { + (void) arg; + union fusb_status status; + eventmask_t events; + //TODO use IRQ task notification to unblock this thread to stop it spinning + while (true) { + /* If the INT_N line is low */ + if (pd_irq_read() == 0) { + /* Read the FUSB302B status and interrupt registers */ + fusb_get_status(&status); + //Check for rx alerts + { + /* If the I_GCRCSENT flag is set, tell the Protocol RX thread */ + if (status.interruptb & FUSB_INTERRUPTB_I_GCRCSENT) { + ProtocolReceive::notify(PDB_EVT_PRLRX_I_GCRCSENT); + } + } + /* If the I_TXSENT or I_RETRYFAIL flag is set, tell the Protocol TX + * thread */ + { + events = 0; + if (status.interrupta & FUSB_INTERRUPTA_I_RETRYFAIL) { + events |= PDB_EVT_PRLTX_I_RETRYFAIL; + } + if (status.interrupta & FUSB_INTERRUPTA_I_TXSENT) { + events |= PDB_EVT_PRLTX_I_TXSENT; + } + if (events) { + ProtocolTransmit::notify(events); + } + } + /* If the I_HARDRST or I_HARDSENT flag is set, tell the Hard Reset + * thread */ + { + events = 0; + if (status.interrupta & FUSB_INTERRUPTA_I_HARDRST) { + events |= PDB_EVT_HARDRST_I_HARDRST; + } + if (status.interrupta & FUSB_INTERRUPTA_I_HARDSENT) { + events |= PDB_EVT_HARDRST_I_HARDSENT; + } + if (events) { + ResetHandler::notify(events); + } + } + { + /* If the I_OCP_TEMP and OVRTEMP flags are set, tell the Policy + * Engine thread */ + if (status.interrupta & FUSB_INTERRUPTA_I_OCP_TEMP + && status.status1 & FUSB_STATUS1_OVRTEMP) { + PolicyEngine::notify(PDB_EVT_PE_I_OVRTEMP); + } + } + + } + osDelay(1); + } +} diff --git a/workspace/TS100/Core/Drivers/FUSB302/int_n.h b/workspace/TS100/Core/Drivers/FUSB302/int_n.h new file mode 100644 index 00000000..68dc04d8 --- /dev/null +++ b/workspace/TS100/Core/Drivers/FUSB302/int_n.h @@ -0,0 +1,56 @@ +/* + * PD Buddy Firmware Library - USB Power Delivery for everyone + * Copyright 2017-2018 Clayton G. Hobbs + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef PDB_INT_N_OLD_H +#define PDB_INT_N_OLD_H + +#include + +class InterruptHandler { +public: + //Creates the thread to handle the Interrupt pin + static void init(); + //TODO handle irq callbacks instead of polling the pin + +private: + static void Thread(const void *arg); + static osThreadId TaskHandle; + static const size_t TaskStackSize = 1024 / 4; + static uint32_t TaskBuffer[TaskStackSize]; + static osStaticThreadDef_t TaskControlBlock; + /* + * Hard Reset machine states + */ + enum hardrst_state { + PRLHRResetLayer, + PRLHRIndicateHardReset, + PRLHRRequestHardReset, + PRLHRWaitPHY, + PRLHRHardResetRequested, + PRLHRWaitPE, + PRLHRComplete + }; + static enum hardrst_state hardrst_reset_layer(); + static enum hardrst_state hardrst_indicate_hard_reset(); + static enum hardrst_state hardrst_request_hard_reset(); + static enum hardrst_state hardrst_wait_phy(); + static enum hardrst_state hardrst_hard_reset_requested(); + static enum hardrst_state hardrst_wait_pe(); + static enum hardrst_state hardrst_complete(); +}; + +#endif /* PDB_INT_N_OLD_H */ diff --git a/workspace/TS100/Core/Drivers/FUSB302/pd.h b/workspace/TS100/Core/Drivers/FUSB302/pd.h new file mode 100644 index 00000000..c6b94c6c --- /dev/null +++ b/workspace/TS100/Core/Drivers/FUSB302/pd.h @@ -0,0 +1,402 @@ +/* + * PD Buddy Firmware Library - USB Power Delivery for everyone + * Copyright 2017-2018 Clayton G. Hobbs + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef PDB_PD_H +#define PDB_PD_H + +#include +#include "FreeRTOS.h" +#include "pdb_msg.h" +#include "cmsis_os.h" +#include "pdb_conf.h" +/* + * Macros for working with USB Power Delivery messages. + * + * This file is mostly written from the PD Rev. 2.0 spec, but the header is + * written from the Rev. 3.0 spec. + */ + +/* + * PD Header + */ +#define PD_HDR_MSGTYPE_SHIFT 0 +#define PD_HDR_MSGTYPE (0x1F << PD_HDR_MSGTYPE_SHIFT) +#define PD_HDR_DATAROLE_SHIFT 5 +#define PD_HDR_DATAROLE (0x1 << PD_HDR_DATAROLE_SHIFT) +#define PD_HDR_SPECREV_SHIFT 6 +#define PD_HDR_SPECREV (0x3 << PD_HDR_SPECREV_SHIFT) +#define PD_HDR_POWERROLE_SHIFT 8 +#define PD_HDR_POWERROLE (1 << PD_HDR_POWERROLE_SHIFT) +#define PD_HDR_MESSAGEID_SHIFT 9 +#define PD_HDR_MESSAGEID (0x7 << PD_HDR_MESSAGEID_SHIFT) +#define PD_HDR_NUMOBJ_SHIFT 12 +#define PD_HDR_NUMOBJ (0x7 << PD_HDR_NUMOBJ_SHIFT) +#define PD_HDR_EXT (1 << 15) + +/* Message types */ +#define PD_MSGTYPE_GET(msg) (((msg)->hdr & PD_HDR_MSGTYPE) >> PD_HDR_MSGTYPE_SHIFT) +/* Control Message */ +#define PD_MSGTYPE_GOODCRC 0x01 +#define PD_MSGTYPE_GOTOMIN 0x02 +#define PD_MSGTYPE_ACCEPT 0x03 +#define PD_MSGTYPE_REJECT 0x04 +#define PD_MSGTYPE_PING 0x05 +#define PD_MSGTYPE_PS_RDY 0x06 +#define PD_MSGTYPE_GET_SOURCE_CAP 0x07 +#define PD_MSGTYPE_GET_SINK_CAP 0x08 +#define PD_MSGTYPE_DR_SWAP 0x09 +#define PD_MSGTYPE_PR_SWAP 0x0A +#define PD_MSGTYPE_VCONN_SWAP 0x0B +#define PD_MSGTYPE_WAIT 0x0C +#define PD_MSGTYPE_SOFT_RESET 0x0D +#define PD_MSGTYPE_NOT_SUPPORTED 0x10 +#define PD_MSGTYPE_GET_SOURCE_CAP_EXTENDED 0x11 +#define PD_MSGTYPE_GET_STATUS 0x12 +#define PD_MSGTYPE_FR_SWAP 0x13 +#define PD_MSGTYPE_GET_PPS_STATUS 0x14 +#define PD_MSGTYPE_GET_COUNTRY_CODES 0x15 +/* Data Message */ +#define PD_MSGTYPE_SOURCE_CAPABILITIES 0x01 +#define PD_MSGTYPE_REQUEST 0x02 +#define PD_MSGTYPE_BIST 0x03 +#define PD_MSGTYPE_SINK_CAPABILITIES 0x04 +#define PD_MSGTYPE_BATTERY_STATUS 0x05 +#define PD_MSGTYPE_ALERT 0x06 +#define PD_MSGTYPE_GET_COUNTRY_INFO 0x07 +#define PD_MSGTYPE_VENDOR_DEFINED 0x0F +/* Extended Message */ +#define PD_MSGTYPE_SOURCE_CAPABILITIES_EXTENDED 0x01 +#define PD_MSGTYPE_STATUS 0x02 +#define PD_MSGTYPE_GET_BATTERY_CAP 0x03 +#define PD_MSGTYPE_GET_BATTERY_STATUS 0x04 +#define PD_MSGTYPE_BATTERY_CAPABILITIES 0x05 +#define PD_MSGTYPE_GET_MANUFACTURER_INFO 0x06 +#define PD_MSGTYPE_MANUFACTURER_INFO 0x07 +#define PD_MSGTYPE_SECURITY_REQUEST 0x08 +#define PD_MSGTYPE_SECURITY_RESPONSE 0x09 +#define PD_MSGTYPE_FIRMWARE_UPDATE_REQUEST 0x0A +#define PD_MSGTYPE_FIRMWARE_UPDATE_RESPONSE 0x0B +#define PD_MSGTYPE_PPS_STATUS 0x0C +#define PD_MSGTYPE_COUNTRY_INFO 0x0D +#define PD_MSGTYPE_COUNTRY_CODES 0x0E + +/* Data roles */ +#define PD_DATAROLE_UFP (0x0 << PD_HDR_DATAROLE_SHIFT) +#define PD_DATAROLE_DFP (0x1 << PD_HDR_DATAROLE_SHIFT) + +/* Specification revisions */ +#define PD_SPECREV_1_0 (0x0 << PD_HDR_SPECREV_SHIFT) +#define PD_SPECREV_2_0 (0x1 << PD_HDR_SPECREV_SHIFT) +#define PD_SPECREV_3_0 (0x2 << PD_HDR_SPECREV_SHIFT) + +/* Port power roles */ +#define PD_POWERROLE_SINK (0x0 << PD_HDR_POWERROLE_SHIFT) +#define PD_POWERROLE_SOURCE (0x1 << PD_HDR_POWERROLE_SHIFT) + +/* Message ID */ +#define PD_MESSAGEID_GET(msg) (((msg)->hdr & PD_HDR_MESSAGEID) >> PD_HDR_MESSAGEID_SHIFT) + +/* Number of data objects */ +#define PD_NUMOBJ(n) (((n) << PD_HDR_NUMOBJ_SHIFT) & PD_HDR_NUMOBJ) +#define PD_NUMOBJ_GET(msg) (((msg)->hdr & PD_HDR_NUMOBJ) >> PD_HDR_NUMOBJ_SHIFT) + +/* + * PD Extended Message Header + */ +#define PD_EXTHDR_DATA_SIZE_SHIFT 0 +#define PD_EXTHDR_DATA_SIZE (0x1FF << PD_EXTHDR_DATA_SIZE_SHIFT) +#define PD_EXTHDR_REQUEST_CHUNK_SHIFT 10 +#define PD_EXTHDR_REQUEST_CHUNK (1 << PD_EXTHDR_REQUEST_CHUNK_SHIFT) +#define PD_EXTHDR_CHUNK_NUMBER_SHIFT 11 +#define PD_EXTHDR_CHUNK_NUMBER (0xF << PD_EXTHDR_CHUNK_NUMBER_SHIFT) +#define PD_EXTHDR_CHUNKED_SHIFT 15 +#define PD_EXTHDR_CHUNKED (1 << PD_EXTHDR_CHUNKED_SHIFT) + +/* Data size */ +#define PD_DATA_SIZE(n) (((n) << PD_EXTHDR_DATA_SIZE_SHIFT) & PD_EXTHDR_DATA_SIZE) +#define PD_DATA_SIZE_GET(msg) (((msg)->exthdr & PD_EXTHDR_DATA_SIZE) >> PD_EXTHDR_DATA_SIZE_SHIFT) + +/* Chunk number */ +#define PD_CHUNK_NUMBER(n) (((n) << PD_EXTHDR_CHUNK_NUMBER_SHIFT) & PD_EXTHDR_CHUNK_NUMBER) +#define PD_CHUNK_NUMBER_GET(msg) (((msg)->exthdr & PD_EXTHDR_CHUNK_NUMBER) >> PD_EXTHDR_CHUNK_NUMBER_SHIFT) + +/* + * PD Power Data Object + */ +#define PD_PDO_TYPE_SHIFT 30 +#define PD_PDO_TYPE (0x3 << PD_PDO_TYPE_SHIFT) + +/* PDO types */ +#define PD_PDO_TYPE_FIXED ((unsigned) (0x0 << PD_PDO_TYPE_SHIFT)) +#define PD_PDO_TYPE_BATTERY ((unsigned) (0x1 << PD_PDO_TYPE_SHIFT)) +#define PD_PDO_TYPE_VARIABLE ((unsigned) (0x2 << PD_PDO_TYPE_SHIFT)) +#define PD_PDO_TYPE_AUGMENTED ((unsigned) (0x3 << PD_PDO_TYPE_SHIFT)) + +#define PD_APDO_TYPE_SHIFT 28 +#define PD_APDO_TYPE (0x3 << PD_APDO_TYPE_SHIFT) + +/* APDO types */ +#define PD_APDO_TYPE_PPS (0x0 << PD_APDO_TYPE_SHIFT) + +/* PD Source Fixed PDO */ +#define PD_PDO_SRC_FIXED_DUAL_ROLE_PWR_SHIFT 29 +#define PD_PDO_SRC_FIXED_DUAL_ROLE_PWR (1 << PD_PDO_SRC_FIXED_DUAL_ROLE_PWR_SHIFT) +#define PD_PDO_SRC_FIXED_USB_SUSPEND_SHIFT 28 +#define PD_PDO_SRC_FIXED_USB_SUSPEND (1 << PD_PDO_SRC_FIXED_USB_SUSPEND_SHIFT) +#define PD_PDO_SRC_FIXED_UNCONSTRAINED_SHIFT 27 +#define PD_PDO_SRC_FIXED_UNCONSTRAINED (1 << PD_PDO_SRC_FIXED_UNCONSTRAINED_SHIFT) +#define PD_PDO_SRC_FIXED_USB_COMMS_SHIFT 26 +#define PD_PDO_SRC_FIXED_USB_COMMS (1 << PD_PDO_SRC_FIXED_USB_COMMS_SHIFT) +#define PD_PDO_SRC_FIXED_DUAL_ROLE_DATA_SHIFT 25 +#define PD_PDO_SRC_FIXED_DUAL_ROLE_DATA (1 << PD_PDO_SRC_FIXED_DUAL_ROLE_DATA_SHIFT) +#define PD_PDO_SRC_FIXED_UNCHUNKED_EXT_MSG_SHIFT 24 +#define PD_PDO_SRC_FIXED_UNCHUNKED_EXT_MSG (1 << PD_PDO_SRC_FIXED_UNCHUNKED_EXT_MSG_SHIFT) +#define PD_PDO_SRC_FIXED_PEAK_CURRENT_SHIFT 20 +#define PD_PDO_SRC_FIXED_PEAK_CURRENT (0x3 << PD_PDO_SRC_FIXED_PEAK_CURRENT_SHIFT) +#define PD_PDO_SRC_FIXED_VOLTAGE_SHIFT 10 +#define PD_PDO_SRC_FIXED_VOLTAGE (0x3FF << PD_PDO_SRC_FIXED_VOLTAGE_SHIFT) +#define PD_PDO_SRC_FIXED_CURRENT_SHIFT 0 +#define PD_PDO_SRC_FIXED_CURRENT (0x3FF << PD_PDO_SRC_FIXED_CURRENT_SHIFT) + +/* PD Source Fixed PDO current */ +#define PD_PDO_SRC_FIXED_CURRENT_GET(pdo) (((pdo) & PD_PDO_SRC_FIXED_CURRENT) >> PD_PDO_SRC_FIXED_CURRENT_SHIFT) + +/* PD Source Fixed PDO voltage */ +#define PD_PDO_SRC_FIXED_VOLTAGE_GET(pdo) (((pdo) & PD_PDO_SRC_FIXED_VOLTAGE) >> PD_PDO_SRC_FIXED_VOLTAGE_SHIFT) + +/* PD Programmable Power Supply APDO */ +#define PD_APDO_PPS_MAX_VOLTAGE_SHIFT 17 +#define PD_APDO_PPS_MAX_VOLTAGE (0xFF << PD_APDO_PPS_MAX_VOLTAGE_SHIFT) +#define PD_APDO_PPS_MIN_VOLTAGE_SHIFT 8 +#define PD_APDO_PPS_MIN_VOLTAGE (0xFF << PD_APDO_PPS_MIN_VOLTAGE_SHIFT) +#define PD_APDO_PPS_CURRENT_SHIFT 0 +#define PD_APDO_PPS_CURRENT (0x7F << PD_APDO_PPS_CURRENT_SHIFT) + +/* PD Programmable Power Supply APDO voltages */ +#define PD_APDO_PPS_MAX_VOLTAGE_GET(pdo) (((pdo) & PD_APDO_PPS_MAX_VOLTAGE) >> PD_APDO_PPS_MAX_VOLTAGE_SHIFT) +#define PD_APDO_PPS_MIN_VOLTAGE_GET(pdo) (((pdo) & PD_APDO_PPS_MIN_VOLTAGE) >> PD_APDO_PPS_MIN_VOLTAGE_SHIFT) + +#define PD_APDO_PPS_MAX_VOLTAGE_SET(v) (((v) << PD_APDO_PPS_MAX_VOLTAGE_SHIFT) & PD_APDO_PPS_MAX_VOLTAGE) +#define PD_APDO_PPS_MIN_VOLTAGE_SET(v) (((v) << PD_APDO_PPS_MIN_VOLTAGE_SHIFT) & PD_APDO_PPS_MIN_VOLTAGE) + +/* PD Programmable Power Supply APDO current */ +#define PD_APDO_PPS_CURRENT_GET(pdo) ((uint8_t) (((pdo) & PD_APDO_PPS_CURRENT) >> PD_APDO_PPS_CURRENT_SHIFT)) + +#define PD_APDO_PPS_CURRENT_SET(i) (((i) << PD_APDO_PPS_CURRENT_SHIFT) & PD_APDO_PPS_CURRENT) + + +/* PD Sink Fixed PDO */ +#define PD_PDO_SNK_FIXED_DUAL_ROLE_PWR_SHIFT 29 +#define PD_PDO_SNK_FIXED_DUAL_ROLE_PWR (1 << PD_PDO_SNK_FIXED_DUAL_ROLE_PWR_SHIFT) +#define PD_PDO_SNK_FIXED_HIGHER_CAP_SHIFT 28 +#define PD_PDO_SNK_FIXED_HIGHER_CAP (1 << PD_PDO_SNK_FIXED_HIGHER_CAP_SHIFT) +#define PD_PDO_SNK_FIXED_UNCONSTRAINED_SHIFT 27 +#define PD_PDO_SNK_FIXED_UNCONSTRAINED (1 << PD_PDO_SNK_FIXED_UNCONSTRAINED_SHIFT) +#define PD_PDO_SNK_FIXED_USB_COMMS_SHIFT 26 +#define PD_PDO_SNK_FIXED_USB_COMMS (1 << PD_PDO_SNK_FIXED_USB_COMMS_SHIFT) +#define PD_PDO_SNK_FIXED_DUAL_ROLE_DATA_SHIFT 25 +#define PD_PDO_SNK_FIXED_DUAL_ROLE_DATA (1 << PD_PDO_SNK_FIXED_DUAL_ROLE_DATA_SHIFT) +#define PD_PDO_SNK_FIXED_VOLTAGE_SHIFT 10 +#define PD_PDO_SNK_FIXED_VOLTAGE (0x3FF << PD_PDO_SNK_FIXED_VOLTAGE_SHIFT) +#define PD_PDO_SNK_FIXED_CURRENT_SHIFT 0 +#define PD_PDO_SNK_FIXED_CURRENT (0x3FF << PD_PDO_SNK_FIXED_CURRENT_SHIFT) + +/* PD Sink Fixed PDO current */ +#define PD_PDO_SNK_FIXED_CURRENT_SET(i) (((i) << PD_PDO_SNK_FIXED_CURRENT_SHIFT) & PD_PDO_SNK_FIXED_CURRENT) + +/* PD Sink Fixed PDO voltage */ +#define PD_PDO_SNK_FIXED_VOLTAGE_SET(v) (((v) << PD_PDO_SNK_FIXED_VOLTAGE_SHIFT) & PD_PDO_SNK_FIXED_VOLTAGE) + + +/* + * PD Request Data Object + */ +#define PD_RDO_OBJPOS_SHIFT 28 +#define PD_RDO_OBJPOS (0x7 << PD_RDO_OBJPOS_SHIFT) +#define PD_RDO_GIVEBACK_SHIFT 27 +#define PD_RDO_GIVEBACK (1 << PD_RDO_GIVEBACK_SHIFT) +#define PD_RDO_CAP_MISMATCH_SHIFT 26 +#define PD_RDO_CAP_MISMATCH (1 << PD_RDO_CAP_MISMATCH_SHIFT) +#define PD_RDO_USB_COMMS_SHIFT 25 +#define PD_RDO_USB_COMMS (1 << PD_RDO_USB_COMMS_SHIFT) +#define PD_RDO_NO_USB_SUSPEND_SHIFT 24 +#define PD_RDO_NO_USB_SUSPEND (1 << PD_RDO_NO_USB_SUSPEND_SHIFT) +#define PD_RDO_UNCHUNKED_EXT_MSG_SHIFT 23 +#define PD_RDO_UNCHUNKED_EXT_MSG (1 << PD_RDO_UNCHUNKED_EXT_MSG_SHIFT) + +#define PD_RDO_OBJPOS_SET(i) (((i) << PD_RDO_OBJPOS_SHIFT) & PD_RDO_OBJPOS) +#define PD_RDO_OBJPOS_GET(msg) (((msg)->obj[0] & PD_RDO_OBJPOS) >> PD_RDO_OBJPOS_SHIFT) + +/* Fixed and Variable RDO, no GiveBack support */ +#define PD_RDO_FV_CURRENT_SHIFT 10 +#define PD_RDO_FV_CURRENT (0x3FF << PD_RDO_FV_CURRENT_SHIFT) +#define PD_RDO_FV_MAX_CURRENT_SHIFT 0 +#define PD_RDO_FV_MAX_CURRENT (0x3FF << PD_RDO_FV_MAX_CURRENT_SHIFT) + +#define PD_RDO_FV_CURRENT_SET(i) (((i) << PD_RDO_FV_CURRENT_SHIFT) & PD_RDO_FV_CURRENT) +#define PD_RDO_FV_MAX_CURRENT_SET(i) (((i) << PD_RDO_FV_MAX_CURRENT_SHIFT) & PD_RDO_FV_MAX_CURRENT) + +/* Fixed and Variable RDO with GiveBack support */ +#define PD_RDO_FV_MIN_CURRENT_SHIFT 0 +#define PD_RDO_FV_MIN_CURRENT (0x3FF << PD_RDO_FV_MIN_CURRENT_SHIFT) + +#define PD_RDO_FV_MIN_CURRENT_SET(i) (((i) << PD_RDO_FV_MIN_CURRENT_SHIFT) & PD_RDO_FV_MIN_CURRENT) + +/* TODO: Battery RDOs */ + +/* Programmable RDO */ +#define PD_RDO_PROG_VOLTAGE_SHIFT 9 +#define PD_RDO_PROG_VOLTAGE (0x7FF << PD_RDO_PROG_VOLTAGE_SHIFT) +#define PD_RDO_PROG_CURRENT_SHIFT 0 +#define PD_RDO_PROG_CURRENT (0x7F << PD_RDO_PROG_CURRENT_SHIFT) + +#define PD_RDO_PROG_VOLTAGE_SET(i) (((i) << PD_RDO_PROG_VOLTAGE_SHIFT) & PD_RDO_PROG_VOLTAGE) +#define PD_RDO_PROG_CURRENT_SET(i) (((i) << PD_RDO_PROG_CURRENT_SHIFT) & PD_RDO_PROG_CURRENT) + +/* + * Time values + * + * Where a range is specified, the middle of the range (rounded down to the + * nearest millisecond) is used. + */ +#define PD_T_CHUNKING_NOT_SUPPORTED (45) +#define PD_T_HARD_RESET_COMPLETE (4) +#define PD_T_PS_TRANSITION (500) +#define PD_T_SENDER_RESPONSE (27) +#define PD_T_SINK_REQUEST (100) +#define PD_T_TYPEC_SINK_WAIT_CAP (465) +#define PD_T_PPS_REQUEST TIME_S2I(10) +/* This is actually from Type-C, not Power Delivery, but who cares? */ +#define PD_T_PD_DEBOUNCE (15) + +/* + * Counter maximums + */ +#define PD_N_HARD_RESET_COUNT 2 + +/* + * Value parameters + */ +#define PD_MAX_EXT_MSG_LEN 260 +#define PD_MAX_EXT_MSG_CHUNK_LEN 26 +#define PD_MAX_EXT_MSG_LEGACY_LEN 26 + +/* + * Unit conversions + * + * V: volt + * CV: centivolt + * MV: millivolt + * PRV: Programmable RDO voltage unit (20 mV) + * PDV: Power Delivery voltage unit (50 mV) + * PAV: PPS APDO voltage unit (100 mV) + * + * A: ampere + * CA: centiampere + * MA: milliampere + * PDI: Power Delivery current unit (10 mA) + * PAI: PPS APDO current unit (50 mA) + * + * W: watt + * CW: centiwatt + * MW: milliwatt + * + * O: ohm + * CO: centiohm + * MO: milliohm + */ +#define PD_MV2PRV(mv) ((mv) / 20) +#define PD_MV2PDV(mv) ((mv) / 50) +#define PD_MV2PAV(mv) ((mv) / 100) +#define PD_PRV2MV(prv) ((prv) * 20) +#define PD_PDV2MV(pdv) ((pdv) * 50) +#define PD_PAV2MV(pav) ((pav) * 100) + +#define PD_MA2CA(ma) (((ma) + 10 - 1) / 10) +#define PD_MA2PDI(ma) (((ma) + 10 - 1) / 10) +#define PD_MA2PAI(ma) (((ma) + 50 - 1) / 50) +#define PD_CA2PAI(ca) (((ca) + 5 - 1) / 5) +#define PD_PDI2MA(pdi) ((pdi) * 10) +#define PD_PAI2MA(pai) ((pai) * 50) +#define PD_PAI2CA(pai) ((pai) * 5) + +#define PD_MW2CW(mw) ((mw) / 10) + +#define PD_MO2CO(mo) ((mo) / 10) + +/* Get portions of a voltage in more normal units */ +#define PD_MV_V(mv) ((mv) / 1000) +#define PD_MV_MV(mv) ((mv) % 1000) + +#define PD_PDV_V(pdv) ((pdv) / 20) +#define PD_PDV_CV(pdv) (5 * ((pdv) % 20)) + +#define PD_PAV_V(pav) ((pav) / 10) +#define PD_PAV_CV(pav) (10 * ((pav) % 10)) + +/* Get portions of a PD current in more normal units */ +#define PD_PDI_A(pdi) ((pdi) / 100) +#define PD_PDI_CA(pdi) ((pdi) % 100) + +#define PD_PAI_A(pai) ((pai) / 20) +#define PD_PAI_CA(pai) (5 * ((pai) % 20)) + +/* Get portions of a power in more normal units */ +#define PD_CW_W(cw) ((cw) / 100) +#define PD_CW_CW(cw) ((cw) % 100) + +/* Get portions of a resistance in more normal units */ +#define PD_CO_O(co) ((co) / 100) +#define PD_CO_CO(co) ((co) % 100) + +/* + * Unit constants + */ +#define PD_MV_MIN 0 +#define PD_MV_MAX 21000 +#define PD_PDV_MIN PD_MV2PDV(PD_MV_MIN) +#define PD_PDV_MAX PD_MV2PDV(PD_MV_MAX) + +#define PD_MA_MIN 0 +#define PD_MA_MAX 5000 +#define PD_CA_MIN PD_MA2CA(PD_MA_MIN) +#define PD_CA_MAX PD_MA2CA(PD_MA_MAX) +#define PD_PDI_MIN PD_MA2PDI(PD_MA_MIN) +#define PD_PDI_MAX PD_MA2PDI(PD_MA_MAX) + +#define PD_MW_MIN 0 +#define PD_MW_MAX 100000 + +#define PD_MO_MIN 500 +#define PD_MO_MAX 655350 + + +/* + * FUSB Type-C Current level enum + */ +enum fusb_typec_current { + fusb_tcc_none = 0, + fusb_tcc_default = 1, + fusb_tcc_1_5 = 2, + fusb_sink_tx_ng = 2, + fusb_tcc_3_0 = 3, + fusb_sink_tx_ok = 3 +}; + + + +#endif /* PDB_PD_H */ diff --git a/workspace/TS100/Core/Drivers/FUSB302/pdb_conf.h b/workspace/TS100/Core/Drivers/FUSB302/pdb_conf.h new file mode 100644 index 00000000..ef733c3d --- /dev/null +++ b/workspace/TS100/Core/Drivers/FUSB302/pdb_conf.h @@ -0,0 +1,47 @@ +/* + * PD Buddy Firmware Library - USB Power Delivery for everyone + * Copyright 2017-2018 Clayton G. Hobbs + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef PDB_CONF_H +#define PDB_CONF_H + + +/* Number of messages in the message pool */ +#define PDB_MSG_POOL_SIZE 4 + +/* Size of the Policy Engine thread's working area */ +#define PDB_PE_WA_SIZE 256 + +/* Size of the protocol layer RX thread's working area */ +#define PDB_PRLRX_WA_SIZE 256 + +/* Size of the protocol layer TX thread's working area */ +#define PDB_PRLTX_WA_SIZE 256 + +/* Size of the protocol layer hard reset thread's working area */ +#define PDB_HARDRST_WA_SIZE 256 + +/* Size of the INT_N thread's working area */ +#define PDB_INT_N_WA_SIZE 128 + +#define EVENT_MASK(x) (1< + + + +/* + * PD message union + * + * This can be safely read from or written to in any form without any + * transformations because everything in the system is little-endian. + * + * Two bytes of padding are required at the start to prevent problems due to + * alignment. Specifically, without the padding, &obj[0] != &bytes[2], making + * the statement in the previous paragraph invalid. + */ +union pd_msg { + struct { + uint8_t _pad1[2]; + uint8_t bytes[30]; + } __attribute__((packed)); + struct { + uint8_t _pad2[2]; + uint16_t hdr; + union { + uint32_t obj[7]; + struct { + uint16_t exthdr; + uint8_t data[26]; + }; + }; + } __attribute__((packed)); +}; + + + +#endif /* PDB_MSG_H */ diff --git a/workspace/TS100/Core/Drivers/FUSB302/policy_engine.cpp b/workspace/TS100/Core/Drivers/FUSB302/policy_engine.cpp new file mode 100644 index 00000000..fa076ba7 --- /dev/null +++ b/workspace/TS100/Core/Drivers/FUSB302/policy_engine.cpp @@ -0,0 +1,799 @@ +/* + * PD Buddy Firmware Library - USB Power Delivery for everyone + * Copyright 2017-2018 Clayton G. Hobbs + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "policy_engine.h" +#include + +#include +#include "protocol_tx.h" +#include "hard_reset.h" +#include "fusb302b.h" +bool PolicyEngine::pdNegotiationComplete; +bool PolicyEngine::pdHasEnteredLowPower; +int PolicyEngine::current_voltage_mv; +int PolicyEngine::_requested_voltage; +bool PolicyEngine::_unconstrained_power; +union pd_msg PolicyEngine::currentMessage; +uint16_t PolicyEngine::hdr_template; +bool PolicyEngine::_explicit_contract; +bool PolicyEngine::_min_power; +int8_t PolicyEngine::_hard_reset_counter; +int8_t PolicyEngine::_old_tcc_match; +uint8_t PolicyEngine::_pps_index; +uint8_t PolicyEngine::_last_pps; +osThreadId PolicyEngine::TaskHandle; +uint32_t PolicyEngine::TaskBuffer[PolicyEngine::TaskStackSize]; +osStaticThreadDef_t PolicyEngine::TaskControlBlock; +union pd_msg PolicyEngine::tempMessage; +union pd_msg PolicyEngine::_last_dpm_request; +StaticQueue_t PolicyEngine::xStaticQueue; +uint8_t PolicyEngine::ucQueueStorageArea[PDB_MSG_POOL_SIZE + * sizeof(union pd_msg)]; +QueueHandle_t PolicyEngine::messagesWaiting; +void PolicyEngine::init() { + messagesWaiting = xQueueCreateStatic(PDB_MSG_POOL_SIZE, + sizeof(union pd_msg), ucQueueStorageArea, &xStaticQueue); + //Create static thread at PDB_PRIO_PE priority + osThreadStaticDef(Task, pe_task, PDB_PRIO_PE, 0, TaskStackSize, TaskBuffer, + &TaskControlBlock); + TaskHandle = osThreadCreate(osThread(Task), NULL); +} + +void PolicyEngine::notify(uint32_t notification) { + xTaskNotify(TaskHandle, notification, + eNotifyAction::eSetValueWithOverwrite); +} + +void PolicyEngine::pe_task(const void *arg) { + (void) arg; +//Internal thread loop + hdr_template = PD_DATAROLE_UFP | PD_POWERROLE_SINK; + /* Initialize the old_tcc_match */ + _old_tcc_match = -1; + /* Initialize the pps_index */ + _pps_index = 8; + /* Initialize the last_pps */ + _last_pps = 8; + PolicyEngine::policy_engine_state state = PESinkStartup; + for (;;) { + //Loop based on state + switch (state) { + case PESinkStartup: + state = pe_sink_startup(); + break; + case PESinkDiscovery: + state = pe_sink_discovery(); + break; + case PESinkWaitCap: + state = pe_sink_wait_cap(); + break; + case PESinkEvalCap: + state = pe_sink_eval_cap(); + break; + case PESinkSelectCap: + state = pe_sink_select_cap(); + break; + case PESinkTransitionSink: + state = pe_sink_transition_sink(); + break; + case PESinkReady: + state = pe_sink_ready(); + break; + case PESinkGetSourceCap: + state = pe_sink_get_source_cap(); + break; + case PESinkGiveSinkCap: + state = pe_sink_give_sink_cap(); + break; + case PESinkHardReset: + state = pe_sink_hard_reset(); + break; + case PESinkTransitionDefault: + state = pe_sink_transition_default(); + break; + case PESinkSoftReset: + state = pe_sink_soft_reset(); + break; + case PESinkSendSoftReset: + state = pe_sink_send_soft_reset(); + break; + case PESinkSendNotSupported: + state = pe_sink_send_not_supported(); + break; + case PESinkChunkReceived: + state = pe_sink_chunk_received(); + break; + case PESinkSourceUnresponsive: + state = pe_sink_source_unresponsive(); + break; + case PESinkNotSupportedReceived: + state = pe_sink_not_supported_received(); + break; + default: + state = PESinkStartup; + break; + } + } +} + +PolicyEngine::policy_engine_state PolicyEngine::pe_sink_startup() { + /* We don't have an explicit contract currently */ + _explicit_contract = false; + +//If desired could send an alert that PD is starting + + /* No need to reset the protocol layer here. There are two ways into this + * state: startup and exiting hard reset. On startup, the protocol layer + * is reset by the startup procedure. When exiting hard reset, the + * protocol layer is reset by the hard reset state machine. Since it's + * already done somewhere else, there's no need to do it again here. */ + + return PESinkDiscovery; +} + +PolicyEngine::policy_engine_state PolicyEngine::pe_sink_discovery() { + /* Wait for VBUS. Since it's our only power source, we already know that + * we have it, so just move on. */ + + return PESinkWaitCap; +} + +PolicyEngine::policy_engine_state PolicyEngine::pe_sink_wait_cap() { + /* Fetch a message from the protocol layer */ + eventmask_t evt = waitForEvent( + PDB_EVT_PE_MSG_RX | PDB_EVT_PE_I_OVRTEMP | PDB_EVT_PE_RESET, + PD_T_TYPEC_SINK_WAIT_CAP); + /* If we timed out waiting for Source_Capabilities, send a hard reset */ + if (evt == 0) { + return PESinkHardReset; + } + /* If we got reset signaling, transition to default */ + if (evt & PDB_EVT_PE_RESET) { + return PESinkTransitionDefault; + } + /* If we're too hot, we shouldn't negotiate power yet */ + if (evt & PDB_EVT_PE_I_OVRTEMP) { + return PESinkWaitCap; + } + + /* If we got a message */ + if (evt & PDB_EVT_PE_MSG_RX) { + /* Get the message */ + readMessage(); + /* If we got a Source_Capabilities message, read it. */ + if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_SOURCE_CAPABILITIES + && PD_NUMOBJ_GET(&tempMessage) > 0) { + /* First, determine what PD revision we're using */ + if ((hdr_template & PD_HDR_SPECREV) == PD_SPECREV_1_0) { + /* If the other end is using at least version 3.0, we'll + * use version 3.0. */ + if ((tempMessage.hdr & PD_HDR_SPECREV) >= PD_SPECREV_3_0) { + hdr_template |= PD_SPECREV_3_0; + /* Otherwise, use 2.0. Don't worry about the 1.0 case + * because we don't have hardware for PD 1.0 signaling. */ + } else { + hdr_template |= PD_SPECREV_2_0; + } + } + return PESinkEvalCap; + /* If the message was a Soft_Reset, do the soft reset procedure */ + } else if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_SOFT_RESET + && PD_NUMOBJ_GET(&tempMessage) == 0) { + + return PESinkSoftReset; + /* If we got an unexpected message, reset */ + } else { + /* Free the received message */ + return PESinkHardReset; + + } + } + + /* If we failed to get a message, send a hard reset */ + return PESinkHardReset; +} + +PolicyEngine::policy_engine_state PolicyEngine::pe_sink_eval_cap() { + /* If we have a Source_Capabilities message, remember the index of the + * first PPS APDO so we can check if the request is for a PPS APDO in + * PE_SNK_Select_Cap. */ + /* Start by assuming we won't find a PPS APDO (set the index greater + * than the maximum possible) */ + _pps_index = 8; + /* Search for the first PPS APDO */ + for (int8_t i = 0; i < PD_NUMOBJ_GET(&tempMessage); i++) { + if ((tempMessage.obj[i] & PD_PDO_TYPE) == PD_PDO_TYPE_AUGMENTED + && (tempMessage.obj[i] & PD_APDO_TYPE) == PD_APDO_TYPE_PPS) { + _pps_index = i + 1; + break; + } + } + /* New capabilities also means we can't be making a request from the + * same PPS APDO */ + _last_pps = 8; + /* Get a message object for the request if we don't have one already */ + + /* Remember the last PDO we requested if it was a PPS APDO */ + if (PD_RDO_OBJPOS_GET(&_last_dpm_request) >= _pps_index) { + _last_pps = PD_RDO_OBJPOS_GET(&_last_dpm_request); + /* Otherwise, forget any PPS APDO we had requested */ + } else { + _last_pps = 8; + } + + /* Ask the DPM what to request */ + pdbs_dpm_evaluate_capability(&tempMessage, &_last_dpm_request); + + return PESinkSelectCap; +} + +PolicyEngine::policy_engine_state PolicyEngine::pe_sink_select_cap() { + /* Transmit the request */ + ProtocolTransmit::pushMessage(&_last_dpm_request); +//Send indication that there is a message pending + ProtocolTransmit::notify( PDB_EVT_PRLTX_MSG_TX); + eventmask_t evt = waitForEvent( + PDB_EVT_PE_TX_DONE | PDB_EVT_PE_TX_ERR | PDB_EVT_PE_RESET); + /* Don't free the request; we might need it again */ + /* If we got reset signaling, transition to default */ + if (evt & PDB_EVT_PE_RESET) { + return PESinkTransitionDefault; + } + /* If the message transmission failed, send a hard reset */ + if ((evt & PDB_EVT_PE_TX_DONE) == 0) { + return PESinkHardReset; + } + + /* If we're using PD 3.0 */ + if ((hdr_template & PD_HDR_SPECREV) == PD_SPECREV_3_0) { + /* If the request was for a PPS APDO, start SinkPPSPeriodicTimer */ + if (PD_RDO_OBJPOS_GET(&_last_dpm_request) >= _pps_index) { + start_pps_timer(); + /* Otherwise, stop SinkPPSPeriodicTimer */ + } else { + stop_pps_timer(); + } + } + /* This will use a virtual timer to send an event flag to this thread after + * PD_T_PPS_REQUEST */ + + /* Wait for a response */ + evt = waitForEvent(PDB_EVT_PE_MSG_RX | PDB_EVT_PE_RESET, + PD_T_SENDER_RESPONSE); + /* If we got reset signaling, transition to default */ + if (evt & PDB_EVT_PE_RESET) { + return PESinkTransitionDefault; + } + /* If we didn't get a response before the timeout, send a hard reset */ + if (evt == 0) { + return PESinkHardReset; + } + + /* Get the response message */ + if (messageWaiting()) { + readMessage(); + /* If the source accepted our request, wait for the new power */ + if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_ACCEPT + && PD_NUMOBJ_GET(&tempMessage) == 0) { + /* Transition to Sink Standby if necessary */ + if (PD_RDO_OBJPOS_GET(&_last_dpm_request) != _last_pps) { + pdbs_dpm_transition_standby(); + } + + _min_power = false; + return PESinkTransitionSink; + /* If the message was a Soft_Reset, do the soft reset procedure */ + } else if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_SOFT_RESET + && PD_NUMOBJ_GET(&tempMessage) == 0) { + return PESinkSoftReset; + /* If the message was Wait or Reject */ + } else if ((PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_REJECT + || PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_WAIT) + && PD_NUMOBJ_GET(&tempMessage) == 0) { + /* If we don't have an explicit contract, wait for capabilities */ + if (!_explicit_contract) { + return PESinkWaitCap; + /* If we do have an explicit contract, go to the ready state */ + } else { + /* If we got here from a Wait message, we Should run + * SinkRequestTimer in the Ready state. */ + _min_power = (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_WAIT); + + return PESinkReady; + } + } else { + return PESinkSendSoftReset; + } + } + return PESinkHardReset; +} + +PolicyEngine::policy_engine_state PolicyEngine::pe_sink_transition_sink() { + /* Wait for the PS_RDY message */ + eventmask_t evt = waitForEvent(PDB_EVT_PE_MSG_RX | PDB_EVT_PE_RESET, + PD_T_PS_TRANSITION); + /* If we got reset signaling, transition to default */ + if (evt & PDB_EVT_PE_RESET) { + return PESinkTransitionDefault; + } + /* If no message was received, send a hard reset */ + if (evt == 0) { + return PESinkHardReset; + } + + /* If we received a message, read it */ + if (messageWaiting()) { + readMessage(); + /* If we got a PS_RDY, handle it */ + if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_PS_RDY + && PD_NUMOBJ_GET(&tempMessage) == 0) { + /* We just finished negotiating an explicit contract */ + _explicit_contract = true; + + /* Set the output appropriately */ + if (!_min_power) { + pdbs_dpm_transition_requested(); + } + + return PESinkReady; + /* If there was a protocol error, send a hard reset */ + } else { + /* Turn off the power output before this hard reset to make sure we + * don't supply an incorrect voltage to the device we're powering. + */ + pdbs_dpm_transition_default(); + + return PESinkHardReset; + } + } + + return PESinkHardReset; +} + +PolicyEngine::policy_engine_state PolicyEngine::pe_sink_ready() { + eventmask_t evt; + + /* Wait for an event */ + if (_min_power) { + evt = waitForEvent( + PDB_EVT_PE_MSG_RX | PDB_EVT_PE_RESET | PDB_EVT_PE_I_OVRTEMP + | PDB_EVT_PE_GET_SOURCE_CAP | PDB_EVT_PE_NEW_POWER + | PDB_EVT_PE_PPS_REQUEST, + PD_T_SINK_REQUEST); + } else { + evt = waitForEvent( + PDB_EVT_PE_MSG_RX | PDB_EVT_PE_RESET | PDB_EVT_PE_I_OVRTEMP + | PDB_EVT_PE_GET_SOURCE_CAP | PDB_EVT_PE_NEW_POWER + | PDB_EVT_PE_PPS_REQUEST); + } + + /* If we got reset signaling, transition to default */ + if (evt & PDB_EVT_PE_RESET) { + return PESinkTransitionDefault; + } + + /* If we overheated, send a hard reset */ + if (evt & PDB_EVT_PE_I_OVRTEMP) { + return PESinkHardReset; + } + + /* If the DPM wants us to, send a Get_Source_Cap message */ + if (evt & PDB_EVT_PE_GET_SOURCE_CAP) { + /* Tell the protocol layer we're starting an AMS */ + ProtocolTransmit::notify( PDB_EVT_PRLTX_START_AMS); + return PESinkGetSourceCap; + } + + /* If the DPM wants new power, let it figure out what power it wants + * exactly. This isn't exactly the transition from the spec (that would be + * SelectCap, not EvalCap), but this works better with the particular + * design of this firmware. */ + if (evt & PDB_EVT_PE_NEW_POWER) { + /* Tell the protocol layer we're starting an AMS */ + ProtocolTransmit::notify( PDB_EVT_PRLTX_START_AMS); + return PESinkEvalCap; + } + + /* If SinkPPSPeriodicTimer ran out, send a new request */ + if (evt & PDB_EVT_PE_PPS_REQUEST) { + /* Tell the protocol layer we're starting an AMS */ + ProtocolTransmit::notify( PDB_EVT_PRLTX_START_AMS); + return PESinkSelectCap; + } + + /* If no event was received, the timer ran out. */ + if (evt == 0) { + /* Repeat our Request message */ + return PESinkSelectCap; + } + + /* If we received a message */ + if (evt & PDB_EVT_PE_MSG_RX) { + if (messageWaiting()) { + readMessage(); + /* Ignore vendor-defined messages */ + if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_VENDOR_DEFINED + && PD_NUMOBJ_GET(&tempMessage) > 0) { + + return PESinkReady; + /* Ignore Ping messages */ + } else if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_PING + && PD_NUMOBJ_GET(&tempMessage) == 0) { + + return PESinkReady; + /* DR_Swap messages are not supported */ + } else if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_DR_SWAP + && PD_NUMOBJ_GET(&tempMessage) == 0) { + + return PESinkSendNotSupported; + /* Get_Source_Cap messages are not supported */ + } else if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_GET_SOURCE_CAP + && PD_NUMOBJ_GET(&tempMessage) == 0) { + + return PESinkSendNotSupported; + /* PR_Swap messages are not supported */ + } else if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_PR_SWAP + && PD_NUMOBJ_GET(&tempMessage) == 0) { + + return PESinkSendNotSupported; + /* VCONN_Swap messages are not supported */ + } else if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_VCONN_SWAP + && PD_NUMOBJ_GET(&tempMessage) == 0) { + + return PESinkSendNotSupported; + /* Request messages are not supported */ + } else if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_REQUEST + && PD_NUMOBJ_GET(&tempMessage) > 0) { + + return PESinkSendNotSupported; + /* Sink_Capabilities messages are not supported */ + } else if (PD_MSGTYPE_GET(&tempMessage) + == PD_MSGTYPE_SINK_CAPABILITIES + && PD_NUMOBJ_GET(&tempMessage) > 0) { + + return PESinkSendNotSupported; + /* Handle GotoMin messages */ + } else if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_GOTOMIN + && PD_NUMOBJ_GET(&tempMessage) == 0) { + if (pdbs_dpm_giveback_enabled()) { + /* Transition to the minimum current level */ + pdbs_dpm_transition_min(); + _min_power = true; + return PESinkTransitionSink; + } else { + /* GiveBack is not supported */ + + return PESinkSendNotSupported; + } + /* Evaluate new Source_Capabilities */ + } else if (PD_MSGTYPE_GET(&tempMessage) + == PD_MSGTYPE_SOURCE_CAPABILITIES + && PD_NUMOBJ_GET(&tempMessage) > 0) { + /* Don't free the message: we need to keep the + * Source_Capabilities message so we can evaluate it. */ + return PESinkEvalCap; + /* Give sink capabilities when asked */ + } else if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_GET_SINK_CAP + && PD_NUMOBJ_GET(&tempMessage) == 0) { + + return PESinkGiveSinkCap; + /* If the message was a Soft_Reset, do the soft reset procedure */ + } else if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_SOFT_RESET + && PD_NUMOBJ_GET(&tempMessage) == 0) { + + return PESinkSoftReset; + /* PD 3.0 messges */ + } else if ((hdr_template & PD_HDR_SPECREV) == PD_SPECREV_3_0) { + /* If the message is a multi-chunk extended message, let it + * time out. */ + if ((tempMessage.hdr & PD_HDR_EXT) + && (PD_DATA_SIZE_GET(&tempMessage) + > PD_MAX_EXT_MSG_LEGACY_LEN)) { + + return PESinkChunkReceived; + /* Tell the DPM a message we sent got a response of + * Not_Supported. */ + } else if (PD_MSGTYPE_GET(&tempMessage) + == PD_MSGTYPE_NOT_SUPPORTED + && PD_NUMOBJ_GET(&tempMessage) == 0) { + + return PESinkNotSupportedReceived; + /* If we got an unknown message, send a soft reset */ + } else { + + return PESinkSendSoftReset; + } + /* If we got an unknown message, send a soft reset ??? */ + } else { + + return PESinkSendSoftReset; + } + } + } + + return PESinkReady; +} + +PolicyEngine::policy_engine_state PolicyEngine::pe_sink_get_source_cap() { + /* Get a message object */ + union pd_msg *get_source_cap = &tempMessage; + /* Make a Get_Source_Cap message */ + get_source_cap->hdr = hdr_template | PD_MSGTYPE_GET_SOURCE_CAP + | PD_NUMOBJ(0); + /* Transmit the Get_Source_Cap */ + ProtocolTransmit::pushMessage(get_source_cap); + ProtocolTransmit::notify( PDB_EVT_PRLTX_MSG_TX); + eventmask_t evt = waitForEvent( + PDB_EVT_PE_TX_DONE | PDB_EVT_PE_TX_ERR | PDB_EVT_PE_RESET); + /* Free the sent message */ + /* If we got reset signaling, transition to default */ + if (evt & PDB_EVT_PE_RESET) { + return PESinkTransitionDefault; + } + /* If the message transmission failed, send a hard reset */ + if ((evt & PDB_EVT_PE_TX_DONE) == 0) { + return PESinkHardReset; + } + + return PESinkReady; +} + +PolicyEngine::policy_engine_state PolicyEngine::pe_sink_give_sink_cap() { + /* Get a message object */ + union pd_msg *snk_cap = &tempMessage; + /* Get our capabilities from the DPM */ + pdbs_dpm_get_sink_capability(snk_cap); + + /* Transmit our capabilities */ + ProtocolTransmit::pushMessage(snk_cap); + ProtocolTransmit::notify( PDB_EVT_PRLTX_MSG_TX); + eventmask_t evt = waitForEvent( + PDB_EVT_PE_TX_DONE | PDB_EVT_PE_TX_ERR | PDB_EVT_PE_RESET); + + /* Free the Sink_Capabilities message */ + + /* If we got reset signaling, transition to default */ + if (evt & PDB_EVT_PE_RESET) { + return PESinkTransitionDefault; + } + /* If the message transmission failed, send a hard reset */ + if ((evt & PDB_EVT_PE_TX_DONE) == 0) { + return PESinkHardReset; + } + + return PESinkReady; +} + +PolicyEngine::policy_engine_state PolicyEngine::pe_sink_hard_reset() { + /* If we've already sent the maximum number of hard resets, assume the + * source is unresponsive. */ + if (_hard_reset_counter > PD_N_HARD_RESET_COUNT) { + return PESinkSourceUnresponsive; + } + + /* Generate a hard reset signal */ + ResetHandler::notify(PDB_EVT_HARDRST_RESET); + waitForEvent(PDB_EVT_PE_HARD_SENT); + + /* Increment HardResetCounter */ + _hard_reset_counter++; + + return PESinkTransitionDefault; +} + +PolicyEngine::policy_engine_state PolicyEngine::pe_sink_transition_default() { + _explicit_contract = false; + + /* Tell the DPM to transition to default power */ + pdbs_dpm_transition_default(); + + /* There is no local hardware to reset. */ + /* Since we never change our data role from UFP, there is no reason to set + * it here. */ + + /* Tell the protocol layer we're done with the reset */ + ResetHandler::notify( PDB_EVT_HARDRST_DONE); + + return PESinkStartup; +} + +PolicyEngine::policy_engine_state PolicyEngine::pe_sink_soft_reset() { + /* No need to explicitly reset the protocol layer here. It resets itself + * when a Soft_Reset message is received. */ + + /* Get a message object */ + union pd_msg accept; + /* Make an Accept message */ + accept.hdr = hdr_template | PD_MSGTYPE_ACCEPT | PD_NUMOBJ(0); + /* Transmit the Accept */ + ProtocolTransmit::pushMessage(&accept); + ProtocolTransmit::notify( PDB_EVT_PRLTX_MSG_TX); + eventmask_t evt = waitForEvent( + PDB_EVT_PE_TX_DONE | PDB_EVT_PE_TX_ERR | PDB_EVT_PE_RESET); + /* Free the sent message */ + + /* If we got reset signaling, transition to default */ + if (evt & PDB_EVT_PE_RESET) { + return PESinkTransitionDefault; + } + /* If the message transmission failed, send a hard reset */ + if ((evt & PDB_EVT_PE_TX_DONE) == 0) { + return PESinkHardReset; + } + + return PESinkWaitCap; +} + +PolicyEngine::policy_engine_state PolicyEngine::pe_sink_send_soft_reset() { + /* No need to explicitly reset the protocol layer here. It resets itself + * just before a Soft_Reset message is transmitted. */ + + /* Get a message object */ + union pd_msg *softrst = &tempMessage; + /* Make a Soft_Reset message */ + softrst->hdr = hdr_template | PD_MSGTYPE_SOFT_RESET | PD_NUMOBJ(0); + /* Transmit the soft reset */ + ProtocolTransmit::pushMessage(softrst); + ProtocolTransmit::notify( PDB_EVT_PRLTX_MSG_TX); + eventmask_t evt = waitForEvent( + PDB_EVT_PE_TX_DONE | PDB_EVT_PE_TX_ERR | PDB_EVT_PE_RESET); + /* If we got reset signaling, transition to default */ + if (evt & PDB_EVT_PE_RESET) { + return PESinkTransitionDefault; + } + /* If the message transmission failed, send a hard reset */ + if ((evt & PDB_EVT_PE_TX_DONE) == 0) { + return PESinkHardReset; + } + + /* Wait for a response */ + evt = waitForEvent(PDB_EVT_PE_MSG_RX | PDB_EVT_PE_RESET, + PD_T_SENDER_RESPONSE); + /* If we got reset signaling, transition to default */ + if (evt & PDB_EVT_PE_RESET) { + return PESinkTransitionDefault; + } + /* If we didn't get a response before the timeout, send a hard reset */ + if (evt == 0) { + return PESinkHardReset; + } + + /* Get the response message */ + if (messageWaiting()) { + readMessage(); + /* If the source accepted our soft reset, wait for capabilities. */ + if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_ACCEPT + && PD_NUMOBJ_GET(&tempMessage) == 0) { + + return PESinkWaitCap; + /* If the message was a Soft_Reset, do the soft reset procedure */ + } else if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_SOFT_RESET + && PD_NUMOBJ_GET(&tempMessage) == 0) { + + return PESinkSoftReset; + /* Otherwise, send a hard reset */ + } else { + + return PESinkHardReset; + } + } + return PESinkHardReset; +} + +PolicyEngine::policy_engine_state PolicyEngine::pe_sink_send_not_supported() { + /* Get a message object */ + union pd_msg *not_supported = &tempMessage; + + if ((hdr_template & PD_HDR_SPECREV) == PD_SPECREV_2_0) { + /* Make a Reject message */ + not_supported->hdr = hdr_template | PD_MSGTYPE_REJECT | PD_NUMOBJ(0); + } else if ((hdr_template & PD_HDR_SPECREV) == PD_SPECREV_3_0) { + /* Make a Not_Supported message */ + not_supported->hdr = hdr_template | PD_MSGTYPE_NOT_SUPPORTED + | PD_NUMOBJ(0); + } + + /* Transmit the message */ + ProtocolTransmit::pushMessage(not_supported); + ProtocolTransmit::notify( PDB_EVT_PRLTX_MSG_TX); + eventmask_t evt = waitForEvent( + PDB_EVT_PE_TX_DONE | PDB_EVT_PE_TX_ERR | PDB_EVT_PE_RESET); + + /* If we got reset signaling, transition to default */ + if (evt & PDB_EVT_PE_RESET) { + return PESinkTransitionDefault; + } + /* If the message transmission failed, send a soft reset */ + if ((evt & PDB_EVT_PE_TX_DONE) == 0) { + return PESinkSendSoftReset; + } + + return PESinkReady; +} + +PolicyEngine::policy_engine_state PolicyEngine::pe_sink_chunk_received() { + + /* Wait for tChunkingNotSupported */ + eventmask_t evt = waitForEvent(PDB_EVT_PE_RESET, + PD_T_CHUNKING_NOT_SUPPORTED); + /* If we got reset signaling, transition to default */ + if (evt & PDB_EVT_PE_RESET) { + return PESinkTransitionDefault; + } + + return PESinkSendNotSupported; +} + +PolicyEngine::policy_engine_state PolicyEngine::pe_sink_not_supported_received() { + /* Inform the Device Policy Manager that we received a Not_Supported + * message. */ + + return PESinkReady; +} + +PolicyEngine::policy_engine_state PolicyEngine::pe_sink_source_unresponsive() { + /* If the DPM can evaluate the Type-C Current advertisement */ + //TS80P doesnt +// if (cfg->dpm.evaluate_typec_current != NULL) { +// /* Make the DPM evaluate the Type-C Current advertisement */ +// int tcc_match = cfg->dpm.evaluate_typec_current(cfg, +// fusb_get_typec_current(&cfg->fusb)); +// +// /* If the last two readings are the same, set the output */ +// if (_old_tcc_match == tcc_match) { +// cfg->dpm.transition_typec(cfg); +// } +// +// /* Remember whether or not the last measurement succeeded */ +// _old_tcc_match = tcc_match; +// } + /* Wait tPDDebounce between measurements */ + osDelay(PD_T_PD_DEBOUNCE); + + return PESinkSourceUnresponsive; +} + +void PolicyEngine::PPSTimerCallBack() { + notify(PDB_EVT_PE_PPS_REQUEST); +} + +bool PolicyEngine::pdHasNegotiated() { + return pdNegotiationComplete; +} + +bool PolicyEngine::heatingAllowed() { + if (pdHasNegotiated()) + return !pdHasEnteredLowPower; + //Not pd -- pass through + return true; +} + +uint32_t PolicyEngine::waitForEvent(uint32_t mask, uint32_t ticksToWait) { + uint32_t pulNotificationValue; + xTaskNotifyWait(0x00, mask, &pulNotificationValue, ticksToWait); + return pulNotificationValue; +} + +bool PolicyEngine::isPD3_0() { + return (hdr_template & PD_HDR_SPECREV) == PD_SPECREV_3_0; +} + +void PolicyEngine::start_pps_timer() { +} + +void PolicyEngine::stop_pps_timer() { +} diff --git a/workspace/TS100/Core/Drivers/FUSB302/policy_engine.h b/workspace/TS100/Core/Drivers/FUSB302/policy_engine.h new file mode 100644 index 00000000..781158ed --- /dev/null +++ b/workspace/TS100/Core/Drivers/FUSB302/policy_engine.h @@ -0,0 +1,197 @@ +/* + * PD Buddy Firmware Library - USB Power Delivery for everyone + * Copyright 2017-2018 Clayton G. Hobbs + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef PDB_POLICY_ENGINE_H +#define PDB_POLICY_ENGINE_H + +#include + +/* + * Events for the Policy Engine thread, used internally + sent by user code + * + */ +/* Tell the PE to send a Get_Source_Cap message */ +#define PDB_EVT_PE_GET_SOURCE_CAP EVENT_MASK(7) +/* Tell the PE that new power is required */ +#define PDB_EVT_PE_NEW_POWER EVENT_MASK(8) + +#define PDB_EVT_PE_RESET EVENT_MASK(0) +#define PDB_EVT_PE_MSG_RX EVENT_MASK(1) +#define PDB_EVT_PE_TX_DONE EVENT_MASK(2) +#define PDB_EVT_PE_TX_ERR EVENT_MASK(3) +#define PDB_EVT_PE_HARD_SENT EVENT_MASK(4) +#define PDB_EVT_PE_I_OVRTEMP EVENT_MASK(5) +#define PDB_EVT_PE_PPS_REQUEST EVENT_MASK(6) + +class PolicyEngine { +public: + //Sets up internal state and registers the thread + static void init(); + //Push an incoming message to the Policy Engine + static void handleMessage(union pd_msg *msg); + //Send a notification + static void notify(uint32_t notification); + //Returns true if headers indicate PD3.0 compliant + static bool isPD3_0(); + + static void PPSTimerCallBack(); + //Has pd negotiation completed + static bool pdHasNegotiated(); + //Used in case the USB-C PD source requests minimum power + static bool heatingAllowed(); +private: + static bool pdNegotiationComplete; + static bool pdHasEnteredLowPower; + static int current_voltage_mv; //The current voltage PD is expecting + static int _requested_voltage; //The voltage the unit wanted to requests + static bool _unconstrained_power; // If the source is unconstrained + //Current message being handled + static union pd_msg currentMessage; + /* PD message header template */ + static uint16_t hdr_template; + /* Whether or not we have an explicit contract */ + static bool _explicit_contract; + /* Whether or not we're receiving minimum power */ + static bool _min_power; + /* The number of hard resets we've sent */ + static int8_t _hard_reset_counter; + /* The result of the last Type-C Current match comparison */ + static int8_t _old_tcc_match; + /* The index of the first PPS APDO */ + static uint8_t _pps_index; + /* The index of the just-requested PPS APDO */ + static uint8_t _last_pps; + static void pe_task(const void *arg); + enum policy_engine_state { + PESinkStartup, + PESinkDiscovery, + PESinkWaitCap, + PESinkEvalCap, + PESinkSelectCap, + PESinkTransitionSink, + PESinkReady, + PESinkGetSourceCap, + PESinkGiveSinkCap, + PESinkHardReset, + PESinkTransitionDefault, + PESinkSoftReset, + PESinkSendSoftReset, + PESinkSendNotSupported, + PESinkChunkReceived, + PESinkNotSupportedReceived, + PESinkSourceUnresponsive + }; + static enum policy_engine_state pe_sink_startup(); + static enum policy_engine_state pe_sink_discovery(); + static enum policy_engine_state pe_sink_wait_cap(); + static enum policy_engine_state pe_sink_eval_cap(); + static enum policy_engine_state pe_sink_select_cap(); + static enum policy_engine_state pe_sink_transition_sink(); + static enum policy_engine_state pe_sink_ready(); + static enum policy_engine_state pe_sink_get_source_cap(); + static enum policy_engine_state pe_sink_give_sink_cap(); + static enum policy_engine_state pe_sink_hard_reset(); + static enum policy_engine_state pe_sink_transition_default(); + static enum policy_engine_state pe_sink_soft_reset(); + static enum policy_engine_state pe_sink_send_soft_reset(); + static enum policy_engine_state pe_sink_send_not_supported(); + static enum policy_engine_state pe_sink_chunk_received(); + static enum policy_engine_state pe_sink_not_supported_received(); + static enum policy_engine_state pe_sink_source_unresponsive(); + static uint32_t waitForEvent(uint32_t mask, uint32_t ticksToWait = + portMAX_DELAY); + //Task resources + static osThreadId TaskHandle; + static const size_t TaskStackSize = 1024 / 4; + static uint32_t TaskBuffer[TaskStackSize]; + static osStaticThreadDef_t TaskControlBlock; + static union pd_msg tempMessage; + static union pd_msg _last_dpm_request; + //queue of up to PDB_MSG_POOL_SIZE messages to send + static StaticQueue_t xStaticQueue; + /* The array to use as the queue's storage area. This must be at least + uxQueueLength * uxItemSize bytes. */ + static uint8_t ucQueueStorageArea[PDB_MSG_POOL_SIZE * sizeof(union pd_msg)]; + static QueueHandle_t messagesWaiting; + static bool messageWaiting(); +//Read a pending message into the temp message + static void readMessage(); + static void start_pps_timer(); + static void stop_pps_timer(); + + // These callbacks are called to implement the logic for the iron to select the desired voltage + + /* + * Create a Request message based on the given Source_Capabilities message. If + * capabilities is NULL, the last non-null Source_Capabilities message passes + * is used. If none has been provided, the behavior is undefined. + * + * Returns true if sufficient power is available, false otherwise. + */ + static bool pdbs_dpm_evaluate_capability(const union pd_msg *capabilities, + union pd_msg *request); + + /* + * Create a Sink_Capabilities message for our current capabilities. + */ + static void pdbs_dpm_get_sink_capability(union pd_msg *cap); + + /* + * Return whether or not GiveBack support is enabled. + */ + static bool pdbs_dpm_giveback_enabled(); + + /* + * Evaluate whether or not the currently offered Type-C Current can fulfill our + * power needs. + * + * Returns true if sufficient power is available, false otherwise. + */ + static bool pdbs_dpm_evaluate_typec_current(enum fusb_typec_current tcc); + + /* + * Indicate that power negotiations are starting. + */ + static void pdbs_dpm_pd_start(); + + /* + * Transition the sink to default power. + */ + static void pdbs_dpm_transition_default(); + + /* + * Transition to the requested minimum current. + */ + static void pdbs_dpm_transition_min(); + + /* + * Transition to Sink Standby if necessary. + */ + static void pdbs_dpm_transition_standby(); + + /* + * Transition to the requested power level + */ + static void pdbs_dpm_transition_requested(); + + /* + * Transition to the Type-C Current power level + */ + static void pdbs_dpm_transition_typec(); +}; + +#endif /* PDB_POLICY_ENGINE_H */ diff --git a/workspace/TS100/Core/Drivers/FUSB302/policy_engine_user.cpp b/workspace/TS100/Core/Drivers/FUSB302/policy_engine_user.cpp new file mode 100644 index 00000000..72364ae3 --- /dev/null +++ b/workspace/TS100/Core/Drivers/FUSB302/policy_engine_user.cpp @@ -0,0 +1,305 @@ +/* + * policy_engine_user.cpp + * + * Created on: 14 Jun 2020 + * Author: Ralim + */ +#include "pd.h" +#include "policy_engine.h" + +/* The current draw when the output is disabled */ +#define DPM_MIN_CURRENT PD_MA2PDI(50) +/* + * Find the index of the first PDO from capabilities in the voltage range, + * using the desired order. + * + * If there is no such PDO, returns -1 instead. + */ +static int8_t dpm_get_range_fixed_pdo_index(const union pd_msg *caps) { + /* Get the number of PDOs */ + uint8_t numobj = PD_NUMOBJ_GET(caps); + + /* Get ready to iterate over the PDOs */ + int8_t i; + int8_t step; + i = numobj - 1; + step = -1; + uint16_t current = 100; // in centiamps + uint16_t voltagemin = 8000; + uint16_t voltagemax = 10000; + /* Look at the PDOs to see if one falls in our voltage range. */ + while (0 <= i && i < numobj) { + /* If we have a fixed PDO, its V is within our range, and its I is at + * least our desired I */ + uint16_t v = PD_PDO_SRC_FIXED_VOLTAGE_GET(caps->obj[i]); + if ((caps->obj[i] & PD_PDO_TYPE) == PD_PDO_TYPE_FIXED) { + if ( PD_PDO_SRC_FIXED_CURRENT_GET(caps->obj[i]) >= current) { + if (v >= PD_MV2PDV(voltagemin) && v <= PD_MV2PDV(voltagemax)) { + return i; + } + } + } + i += step; + } + return -1; +} +bool PolicyEngine::pdbs_dpm_evaluate_capability( + const union pd_msg *capabilities, union pd_msg *request) { + + /* Get the number of PDOs */ + uint8_t numobj = PD_NUMOBJ_GET(capabilities); + + /* Get whether or not the power supply is constrained */ + _unconstrained_power = + capabilities->obj[0] & PD_PDO_SRC_FIXED_UNCONSTRAINED; + + /* Make sure we have configuration */ + /* Look at the PDOs to see if one matches our desires */ + for (uint8_t i = 0; i < numobj; i++) { + /* If we have a fixed PDO, its V equals our desired V, and its I is + * at least our desired I */ + if ((capabilities->obj[i] & PD_PDO_TYPE) == PD_PDO_TYPE_FIXED) { + //This is a fixed PDO entry + int voltage = PD_PDV2MV( + PD_PDO_SRC_FIXED_VOLTAGE_GET(capabilities->obj[i])); + int current = PD_PDO_SRC_FIXED_CURRENT_GET(capabilities->obj[i]); + if (voltage == 9000) { + + /* We got what we wanted, so build a request for that */ + request->hdr = hdr_template | PD_MSGTYPE_REQUEST | PD_NUMOBJ(1); + + /* GiveBack disabled */ + request->obj[0] = PD_RDO_FV_MAX_CURRENT_SET( + current) | PD_RDO_FV_CURRENT_SET(current) + | PD_RDO_NO_USB_SUSPEND | PD_RDO_OBJPOS_SET(i + 1); + + request->obj[0] |= PD_RDO_USB_COMMS; + + /* Update requested voltage */ + _requested_voltage = voltage; + + return true; + } + } + /* If we have a PPS APDO, our desired V lies within its range, and + * its I is at least our desired I */ + if ((capabilities->obj[i] & PD_PDO_TYPE) == PD_PDO_TYPE_AUGMENTED + && (capabilities->obj[i] & PD_APDO_TYPE) == PD_APDO_TYPE_PPS) { + int min_mv = PD_PAV2MV( + PD_APDO_PPS_MIN_VOLTAGE_GET(capabilities->obj[i])); + int max_mv = PD_PAV2MV( + PD_APDO_PPS_MAX_VOLTAGE_GET(capabilities->obj[i])); + int current = PD_CA2PAI( + PD_APDO_PPS_CURRENT_GET(capabilities->obj[i])); + /* We got what we wanted, so build a request for that */ +// +// request->hdr = hdr_template | PD_MSGTYPE_REQUEST | PD_NUMOBJ(1); +// +// /* Build a request */ +// request->obj[0] = +// PD_RDO_PROG_CURRENT_SET( +// PD_CA2PAI(current)) | PD_RDO_PROG_VOLTAGE_SET(PD_MV2PRV(voltage)) +// | PD_RDO_NO_USB_SUSPEND | PD_RDO_OBJPOS_SET(i + 1); +// +// request->obj[0] |= PD_RDO_USB_COMMS; +// +// /* Update requested voltage */ +// _requested_voltage = PD_PRV2MV(PD_MV2PRV(voltage)); +// +// return true; + } + } + /* If there's a PDO in the voltage range, use it */ +// int8_t i = dpm_get_range_fixed_pdo_index(caps, scfg); +// if (i >= 0) { +// /* We got what we wanted, so build a request for that */ +// request->hdr = hdr_template | PD_MSGTYPE_REQUEST | PD_NUMOBJ(1); +// /* Get the current we need at this voltage */ +// current = dpm_get_current(scfg, +// PD_PDV2MV(PD_PDO_SRC_FIXED_VOLTAGE_GET(caps->obj[i]))); +// if (scfg->flags & PDBS_CONFIG_FLAGS_GIVEBACK) { +// /* GiveBack enabled */ +// request->obj[0] = +// PD_RDO_FV_MIN_CURRENT_SET( +// DPM_MIN_CURRENT) | PD_RDO_FV_CURRENT_SET(current) | PD_RDO_NO_USB_SUSPEND +// | PD_RDO_GIVEBACK | PD_RDO_OBJPOS_SET(i + 1); +// } else { +// /* GiveBack disabled */ +// request->obj[0] = +// PD_RDO_FV_MAX_CURRENT_SET( +// current) | PD_RDO_FV_CURRENT_SET(current) | PD_RDO_NO_USB_SUSPEND +// | PD_RDO_OBJPOS_SET(i + 1); +// } +// if (usb_comms) { +// request->obj[0] |= PD_RDO_USB_COMMS; +// } +// +// /* Update requested voltage */ +// _requested_voltage = PD_PDV2MV( +// PD_PDO_SRC_FIXED_VOLTAGE_GET(caps->obj[i])); +// +// _capability_match = true; +// return true; +// } + /* Nothing matched (or no configuration), so get 5 V at low current */ + request->hdr = hdr_template | PD_MSGTYPE_REQUEST | PD_NUMOBJ(1); + request->obj[0] = + PD_RDO_FV_MAX_CURRENT_SET( + DPM_MIN_CURRENT) | PD_RDO_FV_CURRENT_SET(DPM_MIN_CURRENT) | PD_RDO_NO_USB_SUSPEND + | PD_RDO_OBJPOS_SET(1); + /* If the output is enabled and we got here, it must be a capability + * mismatch. */ + if (pdNegotiationComplete) { + request->obj[0] |= PD_RDO_CAP_MISMATCH; + } + /* If we can do USB communications, tell the power supply */ + request->obj[0] |= PD_RDO_USB_COMMS; + + /* Update requested voltage */ + _requested_voltage = 5000; + + /* At this point, we have a capability match iff the output is disabled */ + return false; +} + +void PolicyEngine::pdbs_dpm_get_sink_capability(union pd_msg *cap) { + /* Keep track of how many PDOs we've added */ + int numobj = 0; + + /* If we have no configuration or want something other than 5 V, add a PDO + * for vSafe5V */ + /* Minimum current, 5 V, and higher capability. */ + cap->obj[numobj++] = + PD_PDO_TYPE_FIXED + | PD_PDO_SNK_FIXED_VOLTAGE_SET( + PD_MV2PDV(5000)) | PD_PDO_SNK_FIXED_CURRENT_SET(DPM_MIN_CURRENT); + + /* Get the current we want */ + uint16_t current = 100; // In centi-amps + uint16_t voltage = 9000; // in mv + /* Add a PDO for the desired power. */ + cap->obj[numobj++] = PD_PDO_TYPE_FIXED + | PD_PDO_SNK_FIXED_VOLTAGE_SET( + PD_MV2PDV(voltage)) | PD_PDO_SNK_FIXED_CURRENT_SET(current); + + /* Get the PDO from the voltage range */ + int8_t i = dpm_get_range_fixed_pdo_index(cap); + + /* If it's vSafe5V, set our vSafe5V's current to what we want */ + if (i == 0) { + cap->obj[0] &= ~PD_PDO_SNK_FIXED_CURRENT; + cap->obj[0] |= PD_PDO_SNK_FIXED_CURRENT_SET(current); + } else { + /* If we want more than 5 V, set the Higher Capability flag */ + if (PD_MV2PDV(voltage) != PD_MV2PDV(5000)) { + cap->obj[0] |= PD_PDO_SNK_FIXED_HIGHER_CAP; + } + + /* If the range PDO is a different voltage than the preferred + * voltage, add it to the array. */ + if (i + > 0&& PD_PDO_SRC_FIXED_VOLTAGE_GET(cap->obj[i]) != PD_MV2PDV(voltage)) { + cap->obj[numobj++] = + PD_PDO_TYPE_FIXED + | PD_PDO_SNK_FIXED_VOLTAGE_SET( + PD_PDO_SRC_FIXED_VOLTAGE_GET(cap->obj[i])) | PD_PDO_SNK_FIXED_CURRENT_SET( + PD_PDO_SRC_FIXED_CURRENT_GET(cap->obj[i])); + } + + /* If we have three PDOs at this point, make sure the last two are + * sorted by voltage. */ + if (numobj == 3 + && (cap->obj[1] & PD_PDO_SNK_FIXED_VOLTAGE) + > (cap->obj[2] & PD_PDO_SNK_FIXED_VOLTAGE)) { + cap->obj[1] ^= cap->obj[2]; + cap->obj[2] ^= cap->obj[1]; + cap->obj[1] ^= cap->obj[2]; + } + } + + /* If we're using PD 3.0, add a PPS APDO for our desired voltage */ + if (isPD3_0()) { + cap->obj[numobj++] = + PD_PDO_TYPE_AUGMENTED | PD_APDO_TYPE_PPS + | PD_APDO_PPS_MAX_VOLTAGE_SET( + PD_MV2PAV(voltage)) | PD_APDO_PPS_MIN_VOLTAGE_SET(PD_MV2PAV(voltage)) + | PD_APDO_PPS_CURRENT_SET(PD_CA2PAI(current)); + } + + /* Set the unconstrained power flag. */ + if (_unconstrained_power) { + cap->obj[0] |= PD_PDO_SNK_FIXED_UNCONSTRAINED; + } + /* Set the USB communications capable flag. */ + cap->obj[0] |= PD_PDO_SNK_FIXED_USB_COMMS; + + /* Set the Sink_Capabilities message header */ + cap->hdr = hdr_template | PD_MSGTYPE_SINK_CAPABILITIES | PD_NUMOBJ(numobj); +} + +bool PolicyEngine::pdbs_dpm_giveback_enabled() { + return false; +//We do not support giveback +} + +bool PolicyEngine::pdbs_dpm_evaluate_typec_current( + enum fusb_typec_current tcc) { +//This is for evaluating 5V static current advertised by resistors + /* We don't control the voltage anymore; it will always be 5 V. */ + current_voltage_mv = _requested_voltage = 5000; +//For the soldering iron we accept this as a fallback, but it sucks + return true; +} + +void PolicyEngine::pdbs_dpm_pd_start() { +//PD neg is starting +} + +void PolicyEngine::pdbs_dpm_transition_default() { + /* Cast the dpm_data to the right type */ + + /* Pretend we requested 5 V */ + current_voltage_mv = 5000; + /* Turn the output off */ + pdNegotiationComplete = false; + pdHasEnteredLowPower = true; +} + +void PolicyEngine::pdbs_dpm_transition_min() { + pdHasEnteredLowPower = true; +} + +void PolicyEngine::pdbs_dpm_transition_standby() { + /* If the voltage is changing, enter Sink Standby */ + if (_requested_voltage != current_voltage_mv) { + /* For the PD Buddy Sink, entering Sink Standby is equivalent to + * turning the output off. However, we don't want to change the LED + * state for standby mode. */ + pdHasEnteredLowPower = true; + } +} + +void PolicyEngine::pdbs_dpm_transition_requested() { + /* Cast the dpm_data to the right type */ + pdNegotiationComplete = true; + pdHasEnteredLowPower = false; +} + +void PolicyEngine::handleMessage(union pd_msg *msg) { + xQueueSend(messagesWaiting, msg, 100); +} + +bool PolicyEngine::messageWaiting() { + return uxQueueMessagesWaiting(messagesWaiting) > 0; +} + +void PolicyEngine::readMessage() { + xQueueReceive(messagesWaiting, &tempMessage, 1); +} + +void PolicyEngine::pdbs_dpm_transition_typec() { +//This means PD failed, so we either have a dump 5V only type C or a QC charger +//For now; treat this as failed neg + pdNegotiationComplete = false; + pdHasEnteredLowPower = false; +} diff --git a/workspace/TS100/Core/Drivers/FUSB302/protocol_rx.cpp b/workspace/TS100/Core/Drivers/FUSB302/protocol_rx.cpp new file mode 100644 index 00000000..a3ebb2b2 --- /dev/null +++ b/workspace/TS100/Core/Drivers/FUSB302/protocol_rx.cpp @@ -0,0 +1,171 @@ +/* + * PD Buddy Firmware Library - USB Power Delivery for everyone + * Copyright 2017-2018 Clayton G. Hobbs + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "protocol_rx.h" + +#include + +#include +#include "policy_engine.h" +#include "protocol_tx.h" +#include "fusb302b.h" +osThreadId ProtocolReceive::TaskHandle; +uint32_t ProtocolReceive::TaskBuffer[ProtocolReceive::TaskStackSize]; +osStaticThreadDef_t ProtocolReceive::TaskControlBlock; +union pd_msg ProtocolReceive::tempMessage; +uint8_t ProtocolReceive::_rx_messageid; +uint8_t ProtocolReceive::_tx_messageidcounter; +/* + * PRL_Rx_Wait_for_PHY_Message state + */ +ProtocolReceive::protocol_rx_state ProtocolReceive::protocol_rx_wait_phy() { + /* Wait for an event */ + eventmask_t evt = waitForEvent(0xFFFFFFFF); + + /* If we got a reset event, reset */ + if (evt & PDB_EVT_PRLRX_RESET) { + return PRLRxWaitPHY; + } + /* If we got an I_GCRCSENT event, read the message and decide what to do */ + if (evt & PDB_EVT_PRLRX_I_GCRCSENT) { + /* Get a buffer to read the message into. Guaranteed to not fail + * because we have a big enough pool and are careful. */ + union pd_msg *_rx_message = &tempMessage; + /* Read the message */ + fusb_read_message(_rx_message); + /* If it's a Soft_Reset, go to the soft reset state */ + if (PD_MSGTYPE_GET(_rx_message) == PD_MSGTYPE_SOFT_RESET + && PD_NUMOBJ_GET(_rx_message) == 0) { + return PRLRxReset; + } else { + /* Otherwise, check the message ID */ + return PRLRxCheckMessageID; + } + } + + return PRLRxWaitPHY; +} + +/* + * PRL_Rx_Layer_Reset_for_Receive state + */ +ProtocolReceive::protocol_rx_state ProtocolReceive::protocol_rx_reset() { + /* Reset MessageIDCounter */ + _tx_messageidcounter = 0; + + /* Clear stored MessageID */ + _rx_messageid = -1; + + /* TX transitions to its reset state */ + ProtocolTransmit::notify( PDB_EVT_PRLTX_RESET); + taskYIELD(); + + /* If we got a RESET signal, reset the machine */ + if (waitForEvent(PDB_EVT_PRLRX_RESET) != 0) { + return PRLRxWaitPHY; + } + + /* Go to the Check_MessageID state */ + return PRLRxCheckMessageID; +} + +/* + * PRL_Rx_Check_MessageID state + */ +ProtocolReceive::protocol_rx_state ProtocolReceive::protocol_rx_check_messageid() { + /* If we got a RESET signal, reset the machine */ + if (waitForEvent(PDB_EVT_PRLRX_RESET) != 0) { + + return PRLRxWaitPHY; + } + + /* If the message has the stored ID, we've seen this message before. Free + * it and don't pass it to the policy engine. */ + if (PD_MESSAGEID_GET(&tempMessage) == _rx_messageid) { + return PRLRxWaitPHY; + /* Otherwise, there's either no stored ID or this message has an ID we + * haven't just seen. Transition to the Store_MessageID state. */ + } else { + return PRLRxStoreMessageID; + } +} + +/* + * PRL_Rx_Store_MessageID state + */ +ProtocolReceive::protocol_rx_state ProtocolReceive::protocol_rx_store_messageid() { + /* Tell ProtocolTX to discard the message being transmitted */ + + ProtocolTransmit::notify( PDB_EVT_PRLTX_DISCARD); + taskYIELD(); + + /* Update the stored MessageID */ + _rx_messageid = PD_MESSAGEID_GET(&tempMessage); + + /* Pass the message to the policy engine. */ + + PolicyEngine::handleMessage(&tempMessage); + PolicyEngine::notify( PDB_EVT_PE_MSG_RX); + + /* Don't check if we got a RESET because we'd do nothing different. */ + + return PRLRxWaitPHY; +} + +void ProtocolReceive::init() { + osThreadStaticDef(Task, thread, PDB_PRIO_PRL, 0, TaskStackSize, TaskBuffer, + &TaskControlBlock); + TaskHandle = osThreadCreate(osThread(Task), NULL); +} + +void ProtocolReceive::thread(const void *args) { + (void) args; + ProtocolReceive::protocol_rx_state state = PRLRxWaitPHY; + + while (true) { + switch (state) { + case PRLRxWaitPHY: + state = protocol_rx_wait_phy(); + break; + case PRLRxReset: + state = protocol_rx_reset(); + break; + case PRLRxCheckMessageID: + state = protocol_rx_check_messageid(); + break; + case PRLRxStoreMessageID: + state = protocol_rx_store_messageid(); + break; + default: + /* This is an error. It really shouldn't happen. We might + * want to handle it anyway, though. */ + state = PRLRxWaitPHY; + break; + } + } +} + +void ProtocolReceive::notify(uint32_t notification) { + xTaskNotify(TaskHandle, notification, + eNotifyAction::eSetValueWithOverwrite); +} + +uint32_t ProtocolReceive::waitForEvent(uint32_t mask, uint32_t ticksToWait) { + uint32_t pulNotificationValue; + xTaskNotifyWait(0x00, mask, &pulNotificationValue, ticksToWait); + return pulNotificationValue; +} diff --git a/workspace/TS100/Core/Drivers/FUSB302/protocol_rx.h b/workspace/TS100/Core/Drivers/FUSB302/protocol_rx.h new file mode 100644 index 00000000..920e80a2 --- /dev/null +++ b/workspace/TS100/Core/Drivers/FUSB302/protocol_rx.h @@ -0,0 +1,61 @@ +/* + * PD Buddy Firmware Library - USB Power Delivery for everyone + * Copyright 2017-2018 Clayton G. Hobbs + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef PDB_PROTOCOL_RX_H +#define PDB_PROTOCOL_RX_H + +#include + +#include + +/* Events for the Protocol RX thread */ +#define PDB_EVT_PRLRX_RESET EVENT_MASK(0) +#define PDB_EVT_PRLRX_I_GCRCSENT EVENT_MASK(1) + +class ProtocolReceive { +public: + static void init(); + static void notify(uint32_t notification); +private: + static void thread(const void *args); + + static osThreadId TaskHandle; + static const size_t TaskStackSize = 512 / 4; + static uint32_t TaskBuffer[TaskStackSize]; + static osStaticThreadDef_t TaskControlBlock; + /* + * Protocol RX machine states + * + * There is no Send_GoodCRC state because the PHY sends the GoodCRC for us. + * All transitions that would go to that state instead go to Check_MessageID. + */ + enum protocol_rx_state { + PRLRxWaitPHY, PRLRxReset, PRLRxCheckMessageID, PRLRxStoreMessageID + }; + static protocol_rx_state protocol_rx_store_messageid(); + static protocol_rx_state protocol_rx_check_messageid(); + static protocol_rx_state protocol_rx_reset(); + static protocol_rx_state protocol_rx_wait_phy(); + static union pd_msg tempMessage; + static uint8_t _rx_messageid; + static uint8_t _tx_messageidcounter; + static uint32_t waitForEvent(uint32_t mask, uint32_t ticksToWait = + portMAX_DELAY); + +}; + +#endif /* PDB_PROTOCOL_RX_H */ diff --git a/workspace/TS100/Core/Drivers/FUSB302/protocol_tx.cpp b/workspace/TS100/Core/Drivers/FUSB302/protocol_tx.cpp new file mode 100644 index 00000000..759cb003 --- /dev/null +++ b/workspace/TS100/Core/Drivers/FUSB302/protocol_tx.cpp @@ -0,0 +1,285 @@ +/* + * PD Buddy Firmware Library - USB Power Delivery for everyone + * Copyright 2017-2018 Clayton G. Hobbs + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "protocol_tx.h" +#include +#include "policy_engine.h" +#include "protocol_rx.h" +#include "fusb302b.h" +#include "fusbpd.h" + +osThreadId ProtocolTransmit::TaskHandle; +uint32_t ProtocolTransmit::TaskBuffer[ProtocolTransmit::TaskStackSize]; +osStaticThreadDef_t ProtocolTransmit::TaskControlBlock; +StaticQueue_t ProtocolTransmit::xStaticQueue; + +uint8_t ProtocolTransmit::ucQueueStorageArea[PDB_MSG_POOL_SIZE + * sizeof(union pd_msg)]; +QueueHandle_t ProtocolTransmit::messagesWaiting; +uint8_t ProtocolTransmit::_tx_messageidcounter; +union pd_msg ProtocolTransmit::temp_msg; +/* + * PRL_Tx_PHY_Layer_Reset state + */ +ProtocolTransmit::protocol_tx_state ProtocolTransmit::protocol_tx_phy_reset() { + /* Reset the PHY */ + fusb_reset(); + + /* If a message was pending when we got here, tell the policy engine that + * we failed to send it */ + if (messagePending()) { + /* Tell the policy engine that we failed */ + PolicyEngine::notify( PDB_EVT_PE_TX_ERR); + /* Finish failing to send the message */ + getMessage(); //Discard + } + + /* Wait for a message request */ + return PRLTxWaitMessage; +} + +/* + * PRL_Tx_Wait_for_Message_Request state + */ +ProtocolTransmit::protocol_tx_state ProtocolTransmit::protocol_tx_wait_message() { + /* Wait for an event */ + eventmask_t evt = waitForEvent( + PDB_EVT_PRLTX_RESET | PDB_EVT_PRLTX_DISCARD | PDB_EVT_PRLTX_MSG_TX); + + if (evt & PDB_EVT_PRLTX_RESET) { + return PRLTxPHYReset; + } + if (evt & PDB_EVT_PRLTX_DISCARD) { + return PRLTxDiscardMessage; + } + + /* If the policy engine is trying to send a message */ + if (evt & PDB_EVT_PRLTX_MSG_TX) { + /* Get the message */ + getMessage(); + + /* If it's a Soft_Reset, reset the TX layer first */ + if (PD_MSGTYPE_GET(&temp_msg) == PD_MSGTYPE_SOFT_RESET + && PD_NUMOBJ_GET(&(temp_msg)) == 0) { + return PRLTxReset; + /* Otherwise, just send the message */ + } else { + return PRLTxConstructMessage; + } + } + + /* Silence the compiler warning */ + return PRLTxDiscardMessage; +} + +ProtocolTransmit::protocol_tx_state ProtocolTransmit::protocol_tx_reset() { + /* Clear MessageIDCounter */ + _tx_messageidcounter = 0; + + /* Tell the Protocol RX thread to reset */ + ProtocolReceive::notify( PDB_EVT_PRLRX_RESET); + taskYIELD(); + + return PRLTxConstructMessage; +} + +/* + * PRL_Tx_Construct_Message state + */ +ProtocolTransmit::protocol_tx_state ProtocolTransmit::protocol_tx_construct_message() { + /* Make sure nobody wants us to reset */ + eventmask_t evt = waitForEvent( + PDB_EVT_PRLTX_RESET | PDB_EVT_PRLTX_DISCARD); + + if (evt & PDB_EVT_PRLTX_RESET) { + return PRLTxPHYReset; + } + if (evt & PDB_EVT_PRLTX_DISCARD) { + return PRLTxDiscardMessage; + } + + /* Set the correct MessageID in the message */ + temp_msg.hdr &= ~PD_HDR_MESSAGEID; + temp_msg.hdr |= (_tx_messageidcounter % 8) << PD_HDR_MESSAGEID_SHIFT; + + /* PD 3.0 collision avoidance */ + if (PolicyEngine::isPD3_0()) { + /* If we're starting an AMS, wait for permission to transmit */ + evt = waitForEvent(PDB_EVT_PRLTX_START_AMS); + if (evt & PDB_EVT_PRLTX_START_AMS) { + while (fusb_get_typec_current() != fusb_sink_tx_ok) { + osDelay(1); + } + } + } + + /* Send the message to the PHY */ + fusb_send_message(&temp_msg); + + return PRLTxWaitResponse; +} + +/* + * PRL_Tx_Wait_for_PHY_Response state + */ +ProtocolTransmit::protocol_tx_state ProtocolTransmit::protocol_tx_wait_response() { + /* Wait for an event. There is no need to run CRCReceiveTimer, since the + * FUSB302B handles that as part of its retry mechanism. */ + eventmask_t evt = waitForEvent( + PDB_EVT_PRLTX_RESET | PDB_EVT_PRLTX_DISCARD | PDB_EVT_PRLTX_I_TXSENT + | PDB_EVT_PRLTX_I_RETRYFAIL); + + if (evt & PDB_EVT_PRLTX_RESET) { + return PRLTxPHYReset; + } + if (evt & PDB_EVT_PRLTX_DISCARD) { + return PRLTxDiscardMessage; + } + + /* If the message was sent successfully */ + if (evt & PDB_EVT_PRLTX_I_TXSENT) { + return PRLTxMatchMessageID; + } + /* If the message failed to be sent */ + if (evt & PDB_EVT_PRLTX_I_RETRYFAIL) { + return PRLTxTransmissionError; + } + + /* Silence the compiler warning */ + return PRLTxDiscardMessage; +} + +/* + * PRL_Tx_Match_MessageID state + */ +ProtocolTransmit::protocol_tx_state ProtocolTransmit::protocol_tx_match_messageid() { + union pd_msg goodcrc; + + /* Read the GoodCRC */ + fusb_read_message(&goodcrc); + + /* Check that the message is correct */ + if (PD_MSGTYPE_GET(&goodcrc) == PD_MSGTYPE_GOODCRC + && PD_NUMOBJ_GET(&goodcrc) == 0 + && PD_MESSAGEID_GET(&goodcrc) == _tx_messageidcounter) { + return PRLTxMessageSent; + } else { + return PRLTxTransmissionError; + } +} + +ProtocolTransmit::protocol_tx_state ProtocolTransmit::protocol_tx_transmission_error() { + /* Increment MessageIDCounter */ + _tx_messageidcounter = (_tx_messageidcounter + 1) % 8; + + /* Tell the policy engine that we failed */ + PolicyEngine::notify( PDB_EVT_PE_TX_ERR); + + return PRLTxWaitMessage; +} + +ProtocolTransmit::protocol_tx_state ProtocolTransmit::protocol_tx_message_sent() { + /* Increment MessageIDCounter */ + _tx_messageidcounter = (_tx_messageidcounter + 1) % 8; + + /* Tell the policy engine that we succeeded */ + PolicyEngine::notify( PDB_EVT_PE_TX_DONE); + + return PRLTxWaitMessage; +} + +ProtocolTransmit::protocol_tx_state ProtocolTransmit::protocol_tx_discard_message() { + /* If we were working on sending a message, increment MessageIDCounter */ + _tx_messageidcounter = (_tx_messageidcounter + 1) % 8; + + return PRLTxPHYReset; +} + +void ProtocolTransmit::thread(const void *args) { + (void) args; + ProtocolTransmit::protocol_tx_state state = PRLTxPHYReset; + + //Init the incoming message queue + + while (true) { + switch (state) { + case PRLTxPHYReset: + state = protocol_tx_phy_reset(); + break; + case PRLTxWaitMessage: + state = protocol_tx_wait_message(); + break; + case PRLTxReset: + state = protocol_tx_reset(); + break; + case PRLTxConstructMessage: + state = protocol_tx_construct_message(); + break; + case PRLTxWaitResponse: + state = protocol_tx_wait_response(); + break; + case PRLTxMatchMessageID: + state = protocol_tx_match_messageid(); + break; + case PRLTxTransmissionError: + state = protocol_tx_transmission_error(); + break; + case PRLTxMessageSent: + state = protocol_tx_message_sent(); + break; + case PRLTxDiscardMessage: + state = protocol_tx_discard_message(); + break; + default: + state = PRLTxPHYReset; + break; + } + } +} + +void ProtocolTransmit::notify(uint32_t notification) { + xTaskNotify(TaskHandle, notification, + eNotifyAction::eSetValueWithOverwrite); +} + +void ProtocolTransmit::init() { + messagesWaiting = xQueueCreateStatic(PDB_MSG_POOL_SIZE, + sizeof(union pd_msg), ucQueueStorageArea, &xStaticQueue); + + osThreadStaticDef(pd_txTask, thread, PDB_PRIO_PRL, 0, TaskStackSize, + TaskBuffer, &TaskControlBlock); + TaskHandle = osThreadCreate(osThread(pd_txTask), NULL); +} + +void ProtocolTransmit::pushMessage(union pd_msg *msg) { + xQueueSend(messagesWaiting, msg, 100); +} + +bool ProtocolTransmit::messagePending() { + return uxQueueMessagesWaiting(messagesWaiting) > 0; +} + +void ProtocolTransmit::getMessage() { + //Loads the pending message into the buffer + xQueueReceive(messagesWaiting, &temp_msg, 1); +} + +uint32_t ProtocolTransmit::waitForEvent(uint32_t mask, uint32_t ticksToWait) { + uint32_t pulNotificationValue; + xTaskNotifyWait(0x00, mask, &pulNotificationValue, ticksToWait); + return pulNotificationValue; +} diff --git a/workspace/TS100/Core/Drivers/FUSB302/protocol_tx.h b/workspace/TS100/Core/Drivers/FUSB302/protocol_tx.h new file mode 100644 index 00000000..bab49336 --- /dev/null +++ b/workspace/TS100/Core/Drivers/FUSB302/protocol_tx.h @@ -0,0 +1,91 @@ +/* + * PD Buddy Firmware Library - USB Power Delivery for everyone + * Copyright 2017-2018 Clayton G. Hobbs + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef PDB_PROTOCOL_TX_H +#define PDB_PROTOCOL_TX_H + +#include +#include "policy_engine.h" +#include "protocol_rx.h" +#include + +/* Events for the Protocol TX thread */ +#define PDB_EVT_PRLTX_RESET EVENT_MASK(0) +#define PDB_EVT_PRLTX_I_TXSENT EVENT_MASK(1) +#define PDB_EVT_PRLTX_I_RETRYFAIL EVENT_MASK(2) +#define PDB_EVT_PRLTX_DISCARD EVENT_MASK(3) +#define PDB_EVT_PRLTX_MSG_TX EVENT_MASK(4) +#define PDB_EVT_PRLTX_START_AMS EVENT_MASK(5) + +class ProtocolTransmit { +public: + static void init(); + //Push a message to the queue to be sent out the pd comms bus + static void pushMessage(union pd_msg *msg); + static void notify(uint32_t notification); +private: + static void thread(const void *args); + + static osThreadId TaskHandle; + static const size_t TaskStackSize = 512 / 4; + static uint32_t TaskBuffer[TaskStackSize]; + static osStaticThreadDef_t TaskControlBlock; + /* + * Protocol TX machine states + * + * Because the PHY can automatically send retries, the Check_RetryCounter state + * has been removed, transitions relating to it are modified appropriately, and + * we don't even keep a RetryCounter. + */ + enum protocol_tx_state { + PRLTxPHYReset, + PRLTxWaitMessage, + PRLTxReset, + PRLTxConstructMessage, + PRLTxWaitResponse, + PRLTxMatchMessageID, + PRLTxTransmissionError, + PRLTxMessageSent, + PRLTxDiscardMessage + }; + //Internal states + static protocol_tx_state protocol_tx_discard_message(); + static protocol_tx_state protocol_tx_message_sent(); + static protocol_tx_state protocol_tx_transmission_error(); + static protocol_tx_state protocol_tx_match_messageid(); + static protocol_tx_state protocol_tx_wait_response(); + static protocol_tx_state protocol_tx_construct_message(); + static protocol_tx_state protocol_tx_reset(); + static protocol_tx_state protocol_tx_wait_message(); + static protocol_tx_state protocol_tx_phy_reset(); + //queue of up to PDB_MSG_POOL_SIZE messages to send + static StaticQueue_t xStaticQueue; + /* The array to use as the queue's storage area. This must be at least + uxQueueLength * uxItemSize bytes. */ + static uint8_t ucQueueStorageArea[PDB_MSG_POOL_SIZE * sizeof(union pd_msg)]; + static QueueHandle_t messagesWaiting; + static uint8_t _tx_messageidcounter; + static bool messagePending(); + //Reads a message off the queue into the temp message + static void getMessage(); + static union pd_msg temp_msg; + static uint32_t waitForEvent(uint32_t mask, uint32_t ticksToWait = + portMAX_DELAY); + +}; + +#endif /* PDB_PROTOCOL_TX_H */ diff --git a/workspace/TS100/Core/Drivers/FUSB302/tcpm_driver.cpp b/workspace/TS100/Core/Drivers/FUSB302/tcpm_driver.cpp deleted file mode 100644 index bf8b60fb..00000000 --- a/workspace/TS100/Core/Drivers/FUSB302/tcpm_driver.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/* - * tcpm_driver.c - * - * Created: 11/11/2017 18:42:26 - * Author: jason - */ - -#include "tcpm_driver.h" -#include "I2C_Wrapper.hpp" -#include "I2CBB.hpp" -extern const struct tcpc_config_t tcpc_config; -#define STATUS_OK 0 -/* I2C wrapper functions - get I2C port / slave addr from config struct. */ -int tcpc_write(int reg, int val) { - - I2CBB::Mem_Write(tcpc_config.i2c_slave_addr, reg, (uint8_t*) &val, 1); - return STATUS_OK; -} - -int tcpc_write16(int reg, int val) { - uint8_t data[2]; - data[0] = (0xFF) & val; - data[1] = (0xFF) & (val >> 8); - I2CBB::Mem_Write(tcpc_config.i2c_slave_addr, reg, (uint8_t*) data, 2); - return STATUS_OK; -} - -int tcpc_read(int reg, int *val) { - uint8_t data[1]; - - I2CBB::Mem_Read(tcpc_config.i2c_slave_addr, reg, (uint8_t*) data, 1); - - *val = data[0]; - - return STATUS_OK; -} - -int tcpc_read16(int reg, int *val) { - uint8_t data[2]; - I2CBB::Mem_Write(tcpc_config.i2c_slave_addr, reg, (uint8_t*) data, 2); - - *val = data[0]; - *val |= (data[1] << 8); - - return STATUS_OK; -} - -int tcpc_xfer(const uint8_t *out, int out_size, uint8_t *in, int in_size, - int flags) { - // Write out the I2C port to the given slave address - // Write out the out byte array to the device (sending a stop if the flag is set) - // Then issue a read from the device - - if (flags & I2C_XFER_STOP) { - //Issuing a stop between the requests - //Send as a Tx followed by a Rx - I2CBB::Transmit(tcpc_config.i2c_slave_addr, (uint8_t*) out, - out_size); - I2CBB::Receive(tcpc_config.i2c_slave_addr, in, in_size); - } else { - //issue as a continious transmit & recieve - I2CBB::TransmitReceive(tcpc_config.i2c_slave_addr, (uint8_t*) out, - out_size, in, in_size); - } - - return STATUS_OK; -} - -uint8_t fusb302_detect() { - //Probe the I2C bus for its address - return I2CBB::probe(fusb302_I2C_SLAVE_ADDR); -} diff --git a/workspace/TS100/Core/Drivers/FUSB302/tcpm_driver.h b/workspace/TS100/Core/Drivers/FUSB302/tcpm_driver.h deleted file mode 100644 index f3180f9f..00000000 --- a/workspace/TS100/Core/Drivers/FUSB302/tcpm_driver.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * tcpm_driver.h - * - * Created: 11/11/2017 18:42:39 - * Author: jason - */ - - -#ifndef TCPM_DRIVER_H_ -#define TCPM_DRIVER_H_ - -#include - -// USB-C Stuff -#include "USBC_TCPM/tcpm.h" -#include "FUSB302.h" -#define CONFIG_USB_PD_PORT_COUNT 1 -extern struct i2c_master_module i2c_master_instance; - - - -#endif /* TCPM_DRIVER_H_ */ diff --git a/workspace/TS100/Core/Drivers/FUSB302/usb_pd_driver.cpp b/workspace/TS100/Core/Drivers/FUSB302/usb_pd_driver.cpp deleted file mode 100644 index 7036633d..00000000 --- a/workspace/TS100/Core/Drivers/FUSB302/usb_pd_driver.cpp +++ /dev/null @@ -1,258 +0,0 @@ -/* - * usb_pd_driver.c - * - * Created: 11/11/2017 23:55:12 - * Author: jason - */ - -#include "usb_pd_driver.h" -#include "USBC_PD/usb_pd.h" -#include -#ifndef ARRAY_SIZE -#define ARRAY_SIZE(t) (sizeof(t) / sizeof(t[0])) -#endif - -extern struct tc_module tc_instance; -extern uint32_t g_us_timestamp_upper_32bit; - -uint32_t pd_task_set_event(uint32_t event, int wait_for_reply) { - switch (event) { - case PD_EVENT_TX: - break; - default: - break; - } - return 0; -} - -const uint32_t pd_src_pdo[] = { PDO_FIXED(5000, 1500, PDO_FIXED_FLAGS), }; - -const int pd_src_pdo_cnt = ARRAY_SIZE(pd_src_pdo); - -const uint32_t pd_snk_pdo[] = { PDO_FIXED(5000, 1000, PDO_FIXED_FLAGS), - PDO_FIXED(9000, 1500, PDO_FIXED_FLAGS), PDO_FIXED(12000, 3500, - PDO_FIXED_FLAGS), }; -const int pd_snk_pdo_cnt = ARRAY_SIZE(pd_snk_pdo); - -void pd_set_input_current_limit(uint32_t max_ma, uint32_t supply_voltage) { - -} - -int pd_is_valid_input_voltage(int mv) { - return 1; -} - -int pd_snk_is_vbus_provided() { - return 1; -} - -timestamp_t get_time(void) { - timestamp_t t; - //TODO -// -// system_interrupt_enter_critical_section(); -// t.le.lo = tc_get_count_value(&tc_instance); -// t.le.hi = g_us_timestamp_upper_32bit; -// system_interrupt_leave_critical_section(); - - return t; -} - -void pd_power_supply_reset() { - return; -} - -void pd_execute_data_swap(int data_role) { - /* Do nothing */ -} - -int pd_check_data_swap(int data_role) { - // Never allow data swap - return 0; -} - -int pd_check_power_swap() { - /* Always refuse power swap */ - return 0; -} - -int pd_board_checks(void) { - return EC_SUCCESS; -} - -int pd_set_power_supply_ready() { -//Tells other device if we can supply power - return EC_SUCCESS; /* we are ready */ -} - -void pd_transition_voltage(int idx) { - /* No-operation: we are always 5V */ - -#if 0 - timestamp_t deadline; - uint32_t mv = src_pdo_charge[idx - 1].mv; - - /* Is this a transition to a new voltage? */ - if (charge_port_is_active() && vbus[CHG].mv != mv) { - /* - * Alter voltage limit on charge port, this should cause - * the port to select the desired PDO. - */ - pd_set_external_voltage_limit(CHG, mv); - - /* Wait for CHG transition */ - deadline.val = get_time().val + PD_T_PS_TRANSITION; - CPRINTS("Waiting for CHG port transition"); - while (charge_port_is_active() && - vbus[CHG].mv != mv && - get_time().val < deadline.val) - msleep(10); - - if (vbus[CHG].mv != mv) { - CPRINTS("Missed CHG transition, resetting DUT"); - pd_power_supply_reset(DUT); - return; - } - - CPRINTS("CHG transitioned"); - } - - vbus[DUT].mv = vbus[CHG].mv; - vbus[DUT].ma = vbus[CHG].ma; -#endif // if 0 - -} - -void pd_check_dr_role(int dr_role, int flags) { -#if 0 - /* If UFP, try to switch to DFP */ - if ((flags & PD_FLAGS_PARTNER_DR_DATA) && dr_role == PD_ROLE_UFP) - pd_request_data_swap(port); -#endif -} - -void pd_check_pr_role(int pr_role, int flags) { -#if 0 - /* - * If partner is dual-role power and dualrole toggling is on, consider - * if a power swap is necessary. - */ - if ((flags & PD_FLAGS_PARTNER_DR_POWER) && - pd_get_dual_role() == PD_DRP_TOGGLE_ON) { - /* - * If we are a sink and partner is not externally powered, then - * swap to become a source. If we are source and partner is - * externally powered, swap to become a sink. - */ - int partner_extpower = flags & PD_FLAGS_PARTNER_EXTPOWER; - - if ((!partner_extpower && pr_role == PD_ROLE_SINK) || - (partner_extpower && pr_role == PD_ROLE_SOURCE)) - pd_request_power_swap(port); - } -#endif // if 0 -} - -void pd_process_source_cap_callback(int cnt, uint32_t *src_caps) { - char str[256]; - int i; - uint32_t ma, mv, pdo; - - for (i = 0; i < cnt; i++) { - pd_extract_pdo_power(src_caps[i], &ma, &mv); - //Charger can supply power at mv & mA - //TODO we want to ask for the charger to select the closest to our ideal (12V) - //And fall back to 9V - } - -//TODO Handle information on supported voltages? -} - -/* ----------------- Vendor Defined Messages ------------------ */ -/* Holds valid object position (opos) for entered mode */ - -const uint32_t vdo_idh = VDO_IDH(0, /* data caps as USB host */ -1, /* data caps as USB device */ -IDH_PTYPE_PERIPH, /* Alternate mode */ -0, /* Does not support alt modes */ -USB_VID_GOOGLE); - -const uint32_t vdo_product = VDO_PRODUCT(CONFIG_USB_PID, CONFIG_USB_BCD_DEV); - -const uint32_t vdo_ama = VDO_AMA(CONFIG_USB_PD_IDENTITY_HW_VERS, - CONFIG_USB_PD_IDENTITY_SW_VERS, 0, 0, 0, 0, /* SS[TR][12] */ - 0, /* Vconn power */ - 0, /* Vconn power required */ - 1, /* Vbus power required */ - AMA_USBSS_U2_ONLY /* USB 2.0 support */); - -static int svdm_response_identity(uint32_t *payload) { - payload[VDO_I(IDH)] = vdo_idh; - payload[VDO_I(CSTAT)] = VDO_CSTAT(0); - payload[VDO_I(PRODUCT)] = vdo_product; - payload[VDO_I(AMA)] = vdo_ama; - return VDO_I(AMA) + 1; -} -//No custom svdm -static int svdm_response_svids(uint32_t *payload) { - payload[1] = 0; - return 2; -} - -#define OPOS_DP 1 -#define OPOS_GFU 1 - -const uint32_t vdo_dp_modes[1] = { VDO_MODE_DP(0, /* UFP pin cfg supported : none */ -MODE_DP_PIN_C, /* DFP pin cfg supported */ -1, /* no usb2.0 signalling in AMode */ -CABLE_PLUG, /* its a plug */ -MODE_DP_V13, /* DPv1.3 Support, no Gen2 */ -MODE_DP_SNK) /* Its a sink only */ -}; - -static int svdm_response_modes(uint32_t *payload) { - return 0; /* nak */ -} - -static int dp_status(uint32_t *payload) { - int opos = PD_VDO_OPOS(payload[0]); - int hpd = 0; // gpio_get_level(GPIO_DP_HPD); - if (opos != OPOS_DP) - return 0; /* nak */ - - payload[1] = VDO_DP_STATUS(0, /* IRQ_HPD */ - (hpd == 1), /* HPD_HI|LOW */ - 0, /* request exit DP */ - 0, /* request exit USB */ - 0, /* MF pref */ - 0, //gpio_get_level(GPIO_PD_SBU_ENABLE), - 0, /* power low */ - 0x2); - return 2; -} - -static int dp_config(uint32_t *payload) { - return 1; -} - -static int svdm_enter_mode(uint32_t *payload) { - int rv = 0; /* will generate a NAK */ - - return rv; -} - -int pd_alt_mode(uint16_t svid) { - - return 0; -} - -static int svdm_exit_mode(uint32_t *payload) { - return 1; /* Must return ACK */ -} - -static struct amode_fx dp_fx = { .status = &dp_status, .config = &dp_config, }; - -const struct svdm_response svdm_rsp = { &svdm_response_identity, - &svdm_response_svids, &svdm_response_modes, &svdm_enter_mode, - &svdm_exit_mode, &dp_fx, }; - diff --git a/workspace/TS100/Core/Drivers/FUSB302/usb_pd_driver.h b/workspace/TS100/Core/Drivers/FUSB302/usb_pd_driver.h deleted file mode 100644 index 18100253..00000000 --- a/workspace/TS100/Core/Drivers/FUSB302/usb_pd_driver.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * usb_pd_driver.h - * - * Created: 11/11/2017 23:55:25 - * Author: jason - */ - - -#ifndef USB_PD_DRIVER_H_ -#define USB_PD_DRIVER_H_ - -#include "USBC_PD/usb_pd.h" -#include "cmsis_os.h" -#include - -//#define CONFIG_BBRAM -#define CONFIG_CHARGE_MANAGER -//#define CONFIG_USBC_BACKWARDS_COMPATIBLE_DFP -//#define CONFIG_USBC_VCONN_SWAP -//#define CONFIG_USB_PD_ALT_MODE -//#define CONFIG_USB_PD_CHROMEOS -//#define CONFIG_USB_PD_DUAL_ROLE -//#define CONFIG_USB_PD_GIVE_BACK -//#define CONFIG_USB_PD_SIMPLE_DFP -//#define CONFIG_USB_PD_TCPM_TCPCI -#define PD_PREFER_HIGH_VOLTAGE - -/* Default pull-up value on the USB-C ports when they are used as source. */ -#define CONFIG_USB_PD_PULLUP TYPEC_RP_USB - -/* Override PD_ROLE_DEFAULT in usb_pd.h */ -#define PD_ROLE_DEFAULT(port) (PD_ROLE_SINK) - -/* Don't automatically change roles */ -#undef CONFIG_USB_PD_INITIAL_DRP_STATE -#define CONFIG_USB_PD_INITIAL_DRP_STATE PD_DRP_FREEZE - -/* Prefer higher voltage, and more importantly, lower current */ -#define PD_PREFER_HIGH_VOLTAGE -//#define PD_PREFER_LOW_VOLTAGE - -/* board specific type-C power constants */ -/* - * delay to turn on the power supply max is ~16ms. - * delay to turn off the power supply max is about ~180ms. - */ -#define PD_POWER_SUPPLY_TURN_ON_DELAY 10000 /* us */ -#define PD_POWER_SUPPLY_TURN_OFF_DELAY 20000 /* us */ - -/* Define typical operating power and max power */ -#define PD_OPERATING_POWER_MW 15000 -#define PD_MAX_POWER_MW 100000 -#define PD_MAX_CURRENT_MA 5000 -#define PD_MAX_VOLTAGE_MV 20000 - -#define PDO_FIXED_FLAGS (PDO_FIXED_DUAL_ROLE | PDO_FIXED_DATA_SWAP |\ -PDO_FIXED_COMM_CAP) - -/* USB configuration */ -#define CONFIG_USB_PID 0x502f // Stolen, so should change for anything useful -#define CONFIG_USB_BCD_DEV 0x0001 /* v 0.01 */ - -/* Optional features */ -#define CONFIG_USB_PD_IDENTITY_HW_VERS 1 -#define CONFIG_USB_PD_IDENTITY_SW_VERS 1 - -#define usleep(us) (osDelay(1)) -#define msleep(us) (osDelay(us)) - -typedef union { - uint64_t val; - struct { - uint32_t lo; - uint32_t hi; - } le /* little endian words */; - } timestamp_t; - -uint32_t pd_task_set_event(uint32_t event, int wait_for_reply); -void pd_power_supply_reset(int port); - -// Get the current timestamp from the system timer. -timestamp_t get_time(void); - -/* Standard macros / definitions */ -#ifndef MAX -#define MAX(a, b) \ -({ \ - __typeof__(a) temp_a = (a); \ - __typeof__(b) temp_b = (b); \ - \ - temp_a > temp_b ? temp_a : temp_b; \ -}) -#endif -#ifndef MIN -#define MIN(a, b) \ -({ \ - __typeof__(a) temp_a = (a); \ - __typeof__(b) temp_b = (b); \ - \ - temp_a < temp_b ? temp_a : temp_b; \ -}) -#endif - -#endif /* USB_PD_DRIVER_H_ */ diff --git a/workspace/TS100/Core/Inc/FreeRTOSConfig.h b/workspace/TS100/Core/Inc/FreeRTOSConfig.h index 8989a8d8..ae12d43d 100644 --- a/workspace/TS100/Core/Inc/FreeRTOSConfig.h +++ b/workspace/TS100/Core/Inc/FreeRTOSConfig.h @@ -1,173 +1,171 @@ -/* - FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. - All rights reserved - - VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. - - This file is part of the FreeRTOS distribution. - - FreeRTOS 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 >>!AND MODIFIED BY!<< the FreeRTOS exception. - - *************************************************************************** - >>! NOTE: The modification to the GPL is included to allow you to !<< - >>! distribute a combined work that includes FreeRTOS without being !<< - >>! obliged to provide the source code for proprietary components !<< - >>! outside of the FreeRTOS kernel. !<< - *************************************************************************** - - FreeRTOS 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. Full license text is available on the following - link: http://www.freertos.org/a00114.html - - *************************************************************************** - * * - * FreeRTOS provides completely free yet professionally developed, * - * robust, strictly quality controlled, supported, and cross * - * platform software that is more than just the market leader, it * - * is the industry's de facto standard. * - * * - * Help yourself get started quickly while simultaneously helping * - * to support the FreeRTOS project by purchasing a FreeRTOS * - * tutorial book, reference manual, or both: * - * http://www.FreeRTOS.org/Documentation * - * * - *************************************************************************** - - http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading - the FAQ page "My application does not run, what could be wrong?". Have you - defined configASSERT()? - - http://www.FreeRTOS.org/support - In return for receiving this top quality - embedded software for free we request you assist our global community by - participating in the support forum. - - http://www.FreeRTOS.org/training - Investing in training allows your team to - be as productive as possible as early as possible. Now you can receive - FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers - Ltd, and the world's leading authority on the world's leading RTOS. - - http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, - including FreeRTOS+Trace - an indispensable productivity tool, a DOS - compatible FAT file system, and our tiny thread aware UDP/IP stack. - - http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. - Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. - - http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High - Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS - licenses offer ticketed support, indemnification and commercial middleware. - - http://www.SafeRTOS.com - High Integrity Systems also provide a safety - engineered and independently SIL3 certified version for use in safety and - mission critical applications that require provable dependability. - - 1 tab == 4 spaces! -*/ - -#ifndef FREERTOS_CONFIG_H -#define FREERTOS_CONFIG_H - -/*----------------------------------------------------------- - * Application specific definitions. - * - * These definitions should be adjusted for your particular hardware and - * application requirements. - * - * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE - * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. - * - * See http://www.freertos.org/a00110.html. - *----------------------------------------------------------*/ - -/* USER CODE BEGIN Includes */ -/* Section where include file can be added */ -/* USER CODE END Includes */ - -/* Ensure stdint is only used by the compiler, and not the assembler. */ -#if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__) - #include - extern uint32_t SystemCoreClock; -#endif - -#define configUSE_PREEMPTION 1 -#define configSUPPORT_STATIC_ALLOCATION 1 -#define configSUPPORT_DYNAMIC_ALLOCATION 0 -#define configUSE_IDLE_HOOK 1 -#define configUSE_TICK_HOOK 0 -#define configCPU_CLOCK_HZ ( SystemCoreClock ) -#define configTICK_RATE_HZ ((TickType_t)100) -#define configMAX_PRIORITIES ( 4 ) -#define configMINIMAL_STACK_SIZE ((uint16_t)256) -#define configTOTAL_HEAP_SIZE ((size_t)1024*14) /*Currently use about 9000*/ -#define configMAX_TASK_NAME_LEN ( 24 ) -#define configUSE_16_BIT_TICKS 0 -#define configUSE_MUTEXES 1 -#define configQUEUE_REGISTRY_SIZE 8 -#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1 -#define configCHECK_FOR_STACK_OVERFLOW 2 /*Bump this to 2 during development and bug hunting*/ - - -/* Co-routine definitions. */ -#define configUSE_CO_ROUTINES 0 -#define configMAX_CO_ROUTINE_PRIORITIES ( 2 ) - -/* Set the following definitions to 1 to include the API function, or zero -to exclude the API function. */ -#define INCLUDE_vTaskPrioritySet 1 -#define INCLUDE_uxTaskPriorityGet 0 -#define INCLUDE_vTaskDelete 0 -#define INCLUDE_vTaskCleanUpResources 0 -#define INCLUDE_vTaskSuspend 0 -#define INCLUDE_vTaskDelayUntil 0 -#define INCLUDE_vTaskDelay 1 -#define INCLUDE_xTaskGetSchedulerState 1 -#define INCLUDE_uxTaskGetStackHighWaterMark 1 - -/* Cortex-M specific definitions. */ -#ifdef __NVIC_PRIO_BITS - /* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */ - #define configPRIO_BITS __NVIC_PRIO_BITS -#else - #define configPRIO_BITS 4 -#endif - -/* The lowest interrupt priority that can be used in a call to a "set priority" -function. */ -#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 15 - -/* The highest interrupt priority that can be used by any interrupt service -routine that makes calls to interrupt safe FreeRTOS API functions. DO NOT CALL -INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER -PRIORITY THAN THIS! (higher priorities are lower numeric values. */ -#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5 - -/* Interrupt priorities used by the kernel port layer itself. These are generic -to all Cortex-M ports, and do not rely on any particular library functions. */ -#define configKERNEL_INTERRUPT_PRIORITY ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) ) -/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!! -See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */ -#define configMAX_SYSCALL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) ) - -/* Normal assert() semantics without relying on the provision of an assert.h -header file. */ -/* USER CODE BEGIN 1 */ -#define configASSERT( x ) if ((x) == 0) {taskDISABLE_INTERRUPTS(); for( ;; );} -/* USER CODE END 1 */ - -/* Definitions that map the FreeRTOS port interrupt handlers to their CMSIS -standard names. */ -#define vPortSVCHandler SVC_Handler -#define xPortPendSVHandler PendSV_Handler - -/* IMPORTANT: This define MUST be commented when used with STM32Cube firmware, - to prevent overwriting SysTick_Handler defined within STM32Cube HAL */ -/* #define xPortSysTickHandler SysTick_Handler */ - -/* USER CODE BEGIN Defines */ -/* Section where parameter definitions can be added (for instance, to override default ones in FreeRTOS.h) */ -/* USER CODE END Defines */ - -#endif /* FREERTOS_CONFIG_H */ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>!AND MODIFIED BY!<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS 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. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! + */ + +#ifndef FREERTOS_CONFIG_H +#define FREERTOS_CONFIG_H + +/*----------------------------------------------------------- + * Application specific definitions. + * + * These definitions should be adjusted for your particular hardware and + * application requirements. + * + * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE + * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. + * + * See http://www.freertos.org/a00110.html. + *----------------------------------------------------------*/ + +/* USER CODE BEGIN Includes */ +/* Section where include file can be added */ +/* USER CODE END Includes */ + +/* Ensure stdint is only used by the compiler, and not the assembler. */ +#if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__) +#include +extern uint32_t SystemCoreClock; +#endif + +#define configUSE_PREEMPTION 1 +#define configSUPPORT_STATIC_ALLOCATION 1 +#define configSUPPORT_DYNAMIC_ALLOCATION 0 +#define configUSE_IDLE_HOOK 1 +#define configUSE_TICK_HOOK 0 +#define configCPU_CLOCK_HZ ( SystemCoreClock ) +#define configTICK_RATE_HZ ((TickType_t)100) +#define configMAX_PRIORITIES ( 6 ) +#define configMINIMAL_STACK_SIZE ((uint16_t)256) +#define configTOTAL_HEAP_SIZE ((size_t)1024*14) /*Currently use about 9000*/ +#define configMAX_TASK_NAME_LEN ( 24 ) +#define configUSE_16_BIT_TICKS 0 +#define configUSE_MUTEXES 1 +#define configQUEUE_REGISTRY_SIZE 8 +#define configUSE_TIMERS 1 /* Required for PD 10ms callback for PPS mode*/ +#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1 +#define configCHECK_FOR_STACK_OVERFLOW 2 /*Bump this to 2 during development and bug hunting*/ + +/* Co-routine definitions. */ +#define configUSE_CO_ROUTINES 0 +#define configMAX_CO_ROUTINE_PRIORITIES ( 2 ) + +/* Set the following definitions to 1 to include the API function, or zero + to exclude the API function. */ +#define INCLUDE_vTaskPrioritySet 1 +#define INCLUDE_uxTaskPriorityGet 0 +#define INCLUDE_vTaskDelete 0 +#define INCLUDE_vTaskCleanUpResources 0 +#define INCLUDE_vTaskSuspend 0 +#define INCLUDE_vTaskDelayUntil 0 +#define INCLUDE_vTaskDelay 1 +#define INCLUDE_xTaskGetSchedulerState 1 +#define INCLUDE_uxTaskGetStackHighWaterMark 1 + +/* Cortex-M specific definitions. */ +#ifdef __NVIC_PRIO_BITS + /* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */ + #define configPRIO_BITS __NVIC_PRIO_BITS +#else +#define configPRIO_BITS 4 +#endif + +/* The lowest interrupt priority that can be used in a call to a "set priority" + function. */ +#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 15 + +/* The highest interrupt priority that can be used by any interrupt service + routine that makes calls to interrupt safe FreeRTOS API functions. DO NOT CALL + INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER + PRIORITY THAN THIS! (higher priorities are lower numeric values. */ +#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5 + +/* Interrupt priorities used by the kernel port layer itself. These are generic + to all Cortex-M ports, and do not rely on any particular library functions. */ +#define configKERNEL_INTERRUPT_PRIORITY ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) ) +/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!! + See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */ +#define configMAX_SYSCALL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) ) + +/* Normal assert() semantics without relying on the provision of an assert.h + header file. */ +/* USER CODE BEGIN 1 */ +#define configASSERT( x ) if ((x) == 0) {taskDISABLE_INTERRUPTS(); for( ;; );} +/* USER CODE END 1 */ + +/* Definitions that map the FreeRTOS port interrupt handlers to their CMSIS + standard names. */ +#define vPortSVCHandler SVC_Handler +#define xPortPendSVHandler PendSV_Handler + +#if configUSE_TIMERS +#define configTIMER_TASK_PRIORITY 2 +#define configTIMER_QUEUE_LENGTH 8 +#define configTIMER_TASK_STACK_DEPTH (512/4) +#endif + +#endif /* FREERTOS_CONFIG_H */ diff --git a/workspace/TS100/Core/Src/FreeRTOSHooks.c b/workspace/TS100/Core/Src/FreeRTOSHooks.c index 1e9c3dc6..4807480a 100644 --- a/workspace/TS100/Core/Src/FreeRTOSHooks.c +++ b/workspace/TS100/Core/Src/FreeRTOSHooks.c @@ -22,6 +22,16 @@ void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer, *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE; /* place for user code */ } +static StaticTask_t xTimerTaskTCBBuffer; +static StackType_t xTimerStack[configTIMER_TASK_STACK_DEPTH]; + +void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer, + StackType_t **ppxTimerTaskStackBuffer, uint32_t *pulTimerTaskStackSize) { + *ppxTimerTaskTCBBuffer = &xTimerTaskTCBBuffer; + *ppxTimerTaskStackBuffer = &xTimerStack[0]; + *pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH; + /* place for user code */ +} void vApplicationStackOverflowHook(xTaskHandle *pxTask, signed portCHAR *pcTaskName) {