diff options
Diffstat (limited to 'baseboard/honeybuns/usbc_support.c')
-rw-r--r-- | baseboard/honeybuns/usbc_support.c | 480 |
1 files changed, 0 insertions, 480 deletions
diff --git a/baseboard/honeybuns/usbc_support.c b/baseboard/honeybuns/usbc_support.c deleted file mode 100644 index 4d7049ad37..0000000000 --- a/baseboard/honeybuns/usbc_support.c +++ /dev/null @@ -1,480 +0,0 @@ -/* Copyright 2021 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. - */ - -/* USBC functions for RO */ - -#include "common.h" -#include "console.h" -#include "driver/tcpm/tcpci.h" -#include "driver/tcpm/ps8xxx.h" -#include "sn5s330.h" -#include "hooks.h" -#include "i2c.h" -#include "system.h" -#include "timer.h" -#include "usb_charge.h" -#include "usb_pd_tcpm.h" -#include "usb_pd.h" -#include "usbc_ppc.h" -#include "util.h" -#include "registers.h" -#include "ucpd-stm32gx.h" - -#define CPRINTS(format, args...) cprints(CC_SYSTEM, format, ## args) -#define CPRINTF(format, args...) cprintf(CC_SYSTEM, format, ## args) - -enum usbc_states { - UNATTACHED_SNK, - ATTACH_WAIT_SNK, - ATTACHED_SNK, -}; - -/* Variables used to manage the simple usbc state machine */ -static int usbc_port; -static int usbc_state; -static int usbc_vbus; -static enum tcpc_cc_voltage_status cc1_v; -static enum tcpc_cc_voltage_status cc2_v; - -__maybe_unused static __const_data const char * const usbc_state_names[] = { - [UNATTACHED_SNK] = "Unattached.SNK", - [ATTACH_WAIT_SNK] = "AttachWait.SNK", - [ATTACHED_SNK] = "Attached.SNK", -}; - -static int read_reg(uint8_t port, int reg, int *regval) -{ - return i2c_read8(ppc_chips[port].i2c_port, - ppc_chips[port].i2c_addr_flags, - reg, - regval); -} - -static int write_reg(uint8_t port, int reg, int regval) -{ - return i2c_write8(ppc_chips[port].i2c_port, - ppc_chips[port].i2c_addr_flags, - reg, - regval); -} - -static int baseboard_ppc_enable_sink_path(int port) -{ - int regval; - int status; - int retries; - - /* - * It seems that sometimes setting the FUNC_SET1 register fails - * initially. Therefore, we'll retry a couple of times. - */ - retries = 0; - do { - status = write_reg(port, SN5S330_FUNC_SET1, SN5S330_ILIM_3_06); - if (status) { - retries++; - msleep(1); - } else { - break; - } - } while (retries < 10); - - /* Turn off dead battery resistors, turn on CC FETs */ - status = read_reg(port, SN5S330_FUNC_SET4, ®val); - if (!status) { - regval |= SN5S330_CC_EN; - status = write_reg(port, SN5S330_FUNC_SET4, regval); - } - if (status) { - return status; - } - - /* Enable sink path via PP2 */ - status = read_reg(port, SN5S330_FUNC_SET3, ®val); - if (!status) { - regval &= ~SN5S330_PP1_EN; - regval |= SN5S330_PP2_EN; - status = write_reg(port, SN5S330_FUNC_SET3, regval); - } - if (status) { - return status; - } - - return EC_SUCCESS; -} - -static void baseboard_ucpd_apply_rd(int port) -{ - uint32_t cfgr1_reg; - uint32_t moder_reg; - uint32_t cr; - - /* Ensure that clock to UCPD is enabled */ - STM32_RCC_APB1ENR2 |= STM32_RCC_APB1ENR2_UPCD1EN; - - /* Make sure CC1/CC2 pins PB4/PB6 are set for analog mode */ - moder_reg = STM32_GPIO_MODER(GPIO_B); - moder_reg |= 0x3300; - STM32_GPIO_MODER(GPIO_B) = moder_reg; - /* - * CFGR1 must be written when UCPD peripheral is disabled. Note that - * disabling ucpd causes the peripheral to quit any ongoing activity and - * sets all ucpd registers back their default values. - */ - - cfgr1_reg = STM32_UCPD_CFGR1_PSC_CLK_VAL(UCPD_PSC_DIV - 1) | - STM32_UCPD_CFGR1_TRANSWIN_VAL(UCPD_TRANSWIN_CNT - 1) | - STM32_UCPD_CFGR1_IFRGAP_VAL(UCPD_IFRGAP_CNT - 1) | - STM32_UCPD_CFGR1_HBITCLKD_VAL(UCPD_HBIT_DIV - 1); - STM32_UCPD_CFGR1(port) = cfgr1_reg; - - /* Enable ucpd */ - STM32_UCPD_CFGR1(port) |= STM32_UCPD_CFGR1_UCPDEN; - - /* Apply Rd to both CC lines */ - cr = STM32_UCPD_CR(port); - cr |= STM32_UCPD_CR_ANAMODE | STM32_UCPD_CR_CCENABLE_MASK; - STM32_UCPD_CR(port) = cr; - - /* - * After exiting reset, stm32gx will have dead battery mode enabled by - * default which connects Rd to CC1/CC2. This should be disabled when EC - * is powered up. - */ - STM32_PWR_CR3 |= STM32_PWR_CR3_UCPD1_DBDIS; -} - - -static void baseboard_ucpd_get_cc(int port, enum tcpc_cc_voltage_status *cc1, - enum tcpc_cc_voltage_status *cc2) -{ - int vstate_cc1; - int vstate_cc2; - int anamode; - uint32_t sr; - - /* - * cc_voltage_status is determined from vstate_cc bit field in the - * status register. The meaning of the value vstate_cc depends on - * current value of ANAMODE (src/snk). - * - * vstate_cc maps directly to cc_state from tcpci spec when ANAMODE = 1, - * but needs to be modified slightly for case ANAMODE = 0. - * - * If presenting Rp (source), then need to to a circular shift of - * vstate_ccx value: - * vstate_cc | cc_state - * ------------------ - * 0 -> 1 - * 1 -> 2 - * 2 -> 0 - */ - - /* Get vstate_ccx values and power role */ - sr = STM32_UCPD_SR(port); - /* Get Rp or Rd active */ - anamode = !!(STM32_UCPD_CR(port) & STM32_UCPD_CR_ANAMODE); - vstate_cc1 = (sr & STM32_UCPD_SR_VSTATE_CC1_MASK) >> - STM32_UCPD_SR_VSTATE_CC1_SHIFT; - vstate_cc2 = (sr & STM32_UCPD_SR_VSTATE_CC2_MASK) >> - STM32_UCPD_SR_VSTATE_CC2_SHIFT; - - /* Do circular shift if port == source */ - if (anamode) { - if (vstate_cc1 != STM32_UCPD_SR_VSTATE_RA) - vstate_cc1 += 4; - if (vstate_cc2 != STM32_UCPD_SR_VSTATE_RA) - vstate_cc2 += 4; - } else { - if (vstate_cc1 != STM32_UCPD_SR_VSTATE_OPEN) - vstate_cc1 = (vstate_cc1 + 1) % 3; - if (vstate_cc2 != STM32_UCPD_SR_VSTATE_OPEN) - vstate_cc2 = (vstate_cc2 + 1) % 3; - } - - *cc1 = vstate_cc1; - *cc2 = vstate_cc2; -} - -static int baseboard_rp_is_present(enum tcpc_cc_voltage_status cc1, - enum tcpc_cc_voltage_status cc2) -{ - return (cc1 >= TYPEC_CC_VOLT_RP_DEF || cc2 >= TYPEC_CC_VOLT_RP_DEF); -} - -static void baseboard_usbc_check_connect(void); -DECLARE_DEFERRED(baseboard_usbc_check_connect); - -static void baseboard_usbc_check_connect(void) -{ - enum tcpc_cc_voltage_status cc1; - enum tcpc_cc_voltage_status cc2; - int ppc_reg; - enum usbc_states enter_state = usbc_state; - - /* - * In RO, the only usbc related requirement is to enable the stm32g4 - * USB-EP to be enumerated by the host attached to C0. To prevent D+ - * being pulled high prior to VBUS presence, the EC uses GPIO_BPWR_DET - * to signal the USB hub that VBUS is present. Therefore, we need a - * simple usbc state machine to detect an attach (Rp and VBUS) event so - * this GPIO signal is properly controlled in RO. - * - * Note that RO only runs until the RWSIG timer expires and jumps to RW, - * and in RW, the full usb-pd stack is initialized and run. - */ - - /* Get current CC voltage levels */ - baseboard_ucpd_get_cc(usbc_port, &cc1, &cc2); - /* Update VBUS state */ - if (!read_reg(usbc_port, SN5S330_INT_STATUS_REG3, &ppc_reg)) - usbc_vbus = ppc_reg & SN5S330_VBUS_GOOD; - - switch (usbc_state) { - case UNATTACHED_SNK: - /* - * Require either CC1 or CC2 to have a valid Rp CC voltage level - * to advance to ATTACH_WAIT_SNK. - */ - if (baseboard_rp_is_present(cc1, cc2)) - usbc_state = ATTACH_WAIT_SNK; - break; - case ATTACH_WAIT_SNK: - /* - * This state handles debounce by ensuring the CC voltages are - * the same between two state machine iterations. If this - * condition is met, and VBUS is present, then advance to - * ATTACHED_SNK and set GPIO_BPWR_DET. - * - * If Rp voltage is no longer detected, then return to - * UNATTACHED_SNK. - */ - if (usbc_vbus && cc1 == cc1_v && cc2 == cc2_v) { - usbc_state = ATTACHED_SNK; - gpio_set_level(GPIO_BPWR_DET, 1); - } else if (!baseboard_rp_is_present(cc1, cc2)) { - usbc_state = UNATTACHED_SNK; - } - break; - case ATTACHED_SNK: - /* - * In this state, only checking for VBUS going away to indicate - * a detach event and inform the USB hub via GPIO_BPWR_DET. - */ - if (!usbc_vbus) { - usbc_state = UNATTACHED_SNK; - gpio_set_level(GPIO_BPWR_DET, 0); - } - break; - } - - /* Save CC voltage for debounce check */ - cc1_v = cc1; - cc2_v = cc2; - - if (enter_state != usbc_state) - CPRINTS("%s: cc1 = %d, cc2 = %d vbus = %d", - usbc_state_names[usbc_state], cc1, cc2, usbc_vbus); - - hook_call_deferred(&baseboard_usbc_check_connect_data, - PD_T_TRY_CC_DEBOUNCE); -} - -int baseboard_usbc_init(int port) -{ - int rv; - - /* Initialize ucpd and apply Rd to CC lines */ - baseboard_ucpd_apply_rd(port); - /* Initialize ppc to enable sink path */ - rv = baseboard_ppc_enable_sink_path(port); - if (rv) - CPRINTS("ppc init failed!"); - /* Save host port value */ - usbc_port = port; - /* Start RO usbc attach state machine */ - gpio_set_level(GPIO_BPWR_DET, 0); - /* Start simple usbc state machine */ - baseboard_usbc_check_connect(); - - return rv; -} - -#ifdef SECTION_IS_RW -int c1_ps8805_is_vbus_present(int port) -{ - int vbus; - - vbus = tcpm_check_vbus_level(port, VBUS_PRESENT); - - return vbus; -} - -int c1_ps8805_is_sourcing_vbus(int port) -{ - int rv; - int level; - - rv = ps8805_gpio_get_level(port, PS8805_GPIO_1, &level); - if (rv) - return 0; - - return level; -} - - -int c1_ps8805_vbus_source_enable(int port, int enable) -{ - - return ps8805_gpio_set_level(port, PS8805_GPIO_1, enable); -} - -__override bool usb_ufp_check_usb3_enable(int port) -{ - /* USB3.1 mux should be enabled based on UFP data role */ - return port == USB_PD_PORT_HOST; -} - -#ifdef GPIO_USBC_UF_ATTACHED_SRC -static int ppc_ocp_count; - -static void baseboard_usb3_manage_vbus(void) -{ - int level = gpio_get_level(GPIO_USBC_UF_ATTACHED_SRC); - - /* - * GPIO_USBC_UF_MUX_VBUS_EN is an output from the PS8803 which tracks if - * C2 is attached. When it's attached, this signal will be high. Use - * this level to control PPC VBUS on/off. - */ - ppc_vbus_source_enable(USB_PD_PORT_USB3, level); - CPRINTS("C2: State = %s", level ? "Attached.SRC " : "Unattached.SRC"); - - /* Reset OCP event counter for detach */ - if (!level) { - ppc_ocp_count = 0; - -#ifdef GPIO_USB_HUB_OCP_NOTIFY - /* - * In the case of an OCP event on this port, the usb hub should be - * notified via a GPIO signal. Following, an OCP, the attached.src state - * for the usb3 only port is checked again. If it's attached, then make - * sure the OCP notify signal is reset. - */ - gpio_set_level(GPIO_USB_HUB_OCP_NOTIFY, 1); -#endif - } -} -DECLARE_DEFERRED(baseboard_usb3_manage_vbus); - -void baseboard_usb3_check_state(void) -{ - hook_call_deferred(&baseboard_usb3_manage_vbus_data, 0); -} - -void baseboard_usbc_usb3_enable_interrupts(int enable) -{ - if (enable) { - /* Enable VBUS control interrupt for C2 */ - gpio_enable_interrupt(GPIO_USBC_UF_ATTACHED_SRC); - /* Enable PPC interrupt */ - gpio_enable_interrupt(GPIO_USBC_UF_PPC_INT_ODL); - } else { - /* Disable VBUS control interrupt for C2 */ - gpio_disable_interrupt(GPIO_USBC_UF_ATTACHED_SRC); - /* Disable PPC interrupt */ - gpio_disable_interrupt(GPIO_USBC_UF_PPC_INT_ODL); - } -} - -int baseboard_config_usbc_usb3_ppc(void) -{ - int rv; - - /* - * This port is not usb-pd capable, but there is a ppc which must be - * initialized, and keep the VBUS switch enabled. - */ - rv = ppc_init(USB_PD_PORT_USB3); - if (rv) - return rv; - - /* Need to set current limit to 3A to match advertised value */ - ppc_set_vbus_source_current_limit(USB_PD_PORT_USB3, TYPEC_RP_3A0); - /* Reset OCP event counter */ - ppc_ocp_count = 0; - - /* Check state at init time */ - baseboard_usb3_manage_vbus(); - - /* Enable attached.src and PPC interrupts */ - baseboard_usbc_usb3_enable_interrupts(1); - - return EC_SUCCESS; -} - -static void baseboard_usbc_usb3_handle_interrupt(void) -{ - int port = USB_PD_PORT_USB3; - - /* - * SN5S330's /INT pin is level, so process interrupts until it - * deasserts if the chip has a dedicated interrupt pin. - */ - while (gpio_get_level(GPIO_USBC_UF_PPC_INT_ODL) == 0) { - int rise = 0; - int fall = 0; - - read_reg(port, SN5S330_INT_TRIP_RISE_REG1, &rise); - read_reg(port, SN5S330_INT_TRIP_FALL_REG1, &fall); - - /* Notify the system about the overcurrent event. */ - if (rise & SN5S330_ILIM_PP1_MASK) { - CPRINTS("usb3_ppc: VBUS OC!"); - gpio_set_level(GPIO_USB_HUB_OCP_NOTIFY, 0); - if (++ppc_ocp_count < 5) - hook_call_deferred(&baseboard_usb3_manage_vbus_data, - USB_HUB_OCP_RESET_MSEC); - else - CPRINTS("usb3_ppc: VBUS OC limit reached!"); - } - - /* Clear the interrupt sources. */ - write_reg(port, SN5S330_INT_TRIP_RISE_REG1, rise); - write_reg(port, SN5S330_INT_TRIP_FALL_REG1, fall); - - read_reg(port, SN5S330_INT_TRIP_RISE_REG2, &rise); - read_reg(port, SN5S330_INT_TRIP_FALL_REG2, &fall); - - /* - * VCONN may be latched off due to an overcurrent. Indicate - * when the VCONN overcurrent happens. - */ - if (rise & SN5S330_VCONN_ILIM) - CPRINTS("usb3_ppc: VCONN OC!"); - - /* - * CC overvoltage event. There is not action to take here, but - * log the event. - */ - if (rise & SN5S330_CC1_CON || rise & SN5S330_CC2_CON) - CPRINTS("usb3_ppc: CC OV!"); - - /* Clear the interrupt sources. */ - write_reg(port, SN5S330_INT_TRIP_RISE_REG2, rise); - write_reg(port, SN5S330_INT_TRIP_FALL_REG2, fall); - - } -} -DECLARE_DEFERRED(baseboard_usbc_usb3_handle_interrupt); - -void baseboard_usbc_usb3_irq(void) -{ - hook_call_deferred(&baseboard_usbc_usb3_handle_interrupt_data, 0); -} - -#endif /* defined(GPIO_USBC_UF_ATTACHED_SRC) */ -#endif /* defined(SECTION_IS_RW) */ - |