chocodile_vpdmcu: Firmware for chocodile mcu

Implement Chocodile Charge-Through Vconn Powered firmware for mcu
using new Type-C/PD State machine stack.

BUG=b:115626873
BRANCH=none
TEST=manual
  Charge-Through was tested on an Atlas running a DRP USB-C/PD state
  machine with CTUnattached.SNK and CTAttached.SNK states.

Signed-off-by: Sam Hurst <shurst@chromium.org>
Change-Id: I847f1bcd2fc3ce41e66edd133a10c943d5e8c819
Reviewed-on: https://chromium-review.googlesource.com/1225250
Commit-Ready: ChromeOS CL Exonerator Bot <chromiumos-cl-exonerator@appspot.gserviceaccount.com>
Tested-by: Sam Hurst <shurst@google.com>
Reviewed-by: Stefan Reinauer <reinauer@google.com>
This commit is contained in:
Sam Hurst 2018-09-13 09:27:08 -07:00 committed by chrome-bot
parent e097feb8b2
commit 0fe6147a9d
42 changed files with 12322 additions and 5 deletions

View File

@ -0,0 +1,70 @@
/* Copyright 2019 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.
*/
/* chocodile board configuration */
#include "adc.h"
#include "adc_chip.h"
#include "common.h"
#include "gpio.h"
#include "hooks.h"
#include "host_command.h"
#include "i2c.h"
#include "registers.h"
#include "switch.h"
#include "system.h"
#include "task.h"
#include "usb_pd.h"
#include "usb_pd_tcpc.h"
#include "util.h"
#include "vpd_api.h"
#define CPRINTS(format, args...) cprints(CC_USBCHARGE, format, ## args)
void board_config_pre_init(void)
{
/* enable SYSCFG clock */
STM32_RCC_APB2ENR |= 1 << 0;
}
#include "gpio_list.h"
/* Initialize board. */
static void board_init(void)
{
/* Do nothing */
}
DECLARE_HOOK(HOOK_INIT, board_init, HOOK_PRIO_DEFAULT);
/* ADC channels */
const struct adc_t adc_channels[] = {
/* USB PD CC lines sensing. Converted to mV (3300mV/4096). */
[ADC_VCONN_VSENSE] = {
"VCONN_VSENSE", 3000, 4096, 0, STM32_AIN(ADC_VCONN_VSENSE)},
[ADC_CC_VPDMCU] = {
"CC_VPDMCU", 3000, 4096, 0, STM32_AIN(ADC_CC_VPDMCU)},
[ADC_CC_RP3A0_RD_L] = {
"CC_RP3A0_RD_L", 3000, 4096, 0, STM32_AIN(ADC_CC_RP3A0_RD_L)},
[ADC_RDCONNECT_REF] = {
"RDCONNECT_REF", 3000, 4096, 0, STM32_AIN(ADC_RDCONNECT_REF)},
[ADC_CC1_RP3A0_RD_L] = {
"CC1_RP1A5_ODH", 3000, 4096, 0, STM32_AIN(ADC_CC1_RP3A0_RD_L)},
[ADC_CC2_RP3A0_RD_L] = {
"CC2_RP1A5_ODH", 3000, 4096, 0, STM32_AIN(ADC_CC2_RP3A0_RD_L)},
[ADC_HOST_VBUS_VSENSE] = {
"HOST_VBUS_VSENSE", 3000, 4096, 0, STM32_AIN(ADC_HOST_VBUS_VSENSE)},
[ADC_CHARGE_VBUS_VSENSE] = {
"CHARGE_VBUS_VSENSE", 3000, 4096, 0, STM32_AIN(ADC_CHARGE_VBUS_VSENSE)},
[ADC_CC1_RPUSB_ODH] = {
"CC1_RPUSB_ODH", 3000, 4096, 0, STM32_AIN(ADC_CC1_RPUSB_ODH)},
[ADC_CC2_RPUSB_ODH] = {
"CC2_RPUSB_ODH", 3000, 4096, 0, STM32_AIN(ADC_CC2_RPUSB_ODH)},
};
BUILD_ASSERT(ARRAY_SIZE(adc_channels) == ADC_CH_COUNT);
void tcpc_alert_clear(int port)
{
/* Do nothing */
}

View File

@ -0,0 +1,139 @@
/* Copyright 2019 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.
*/
/* chocodile_mcu board configuration */
#ifndef __CROS_EC_BOARD_H
#define __CROS_EC_BOARD_H
/*
* The console task is too big to include in both RO and RW images. Therefore,
* if the console task is defined, then only build an RW image. This can be
* useful for debugging to have a full console. Otherwise, without this task,
* a full RO and RW is built with a limited one-way output console.
*/
#ifdef HAS_TASK_CONSOLE
/*
* The flash size is only 32kB.
* No space for 2 partitions,
* put only RW at the beginning of the flash
*/
#undef CONFIG_FW_INCLUDE_RO
#undef CONFIG_RW_MEM_OFF
#define CONFIG_RW_MEM_OFF 0
#undef CONFIG_RO_SIZE
#define CONFIG_RO_SIZE 0
/* Fake full size if we had a RO partition */
#undef CONFIG_RW_SIZE
#define CONFIG_RW_SIZE CONFIG_FLASH_SIZE
#endif /* HAS_TASK_CONSOLE */
/* 48 MHz SYSCLK clock frequency */
#define CPU_CLOCK 48000000
/* the UART console is on USART1 (PA9/PA10) */
#undef CONFIG_UART_CONSOLE
#define CONFIG_UART_CONSOLE 1
/* Optional features */
#define CONFIG_ADC
#undef CONFIG_ADC_WATCHDOG
#define CONFIG_ADC_SAMPLE_TIME STM32_ADC_SMPR_41_5_CY
#define CONFIG_BOARD_PRE_INIT
#define CONFIG_COMMON_GPIO_SHORTNAMES
#undef CONFIG_DEBUG_ASSERT
#define CONFIG_FORCE_CONSOLE_RESUME
#define CONFIG_HIBERNATE
#undef CONFIG_HOSTCMD_EVENTS
#define CONFIG_HW_CRC
#undef CONFIG_LID_SWITCH
#define CONFIG_LOW_POWER_IDLE
#define CONFIG_LTO
#define CONFIG_STM_HWTIMER32
#undef CONFIG_TASK_PROFILING
#undef CONFIG_UART_TX_BUF_SIZE
#undef CONFIG_UART_TX_DMA
#undef CONFIG_UART_RX_DMA
#define CONFIG_UART_TX_BUF_SIZE 128
#define CONFIG_USB_PD_PORT_COUNT 1
#define CONFIG_USB_PD_TCPC
#define CONFIG_USB_PD_VBUS_DETECT_NONE
#define CONFIG_USB_PD_TCPM_STUB
#define CONFIG_USB_SM_FRAMEWORK
#define CONFIG_USB_TYPEC_CTVPD
#define CONFIG_USB_PD_DUAL_ROLE
#define CONFIG_USB_PD_INTERNAL_COMP
#define CONFIG_VBOOT_HASH
#define CONFIG_WATCHDOG
#undef CONFIG_WATCHDOG_HELP
#undef CONFIG_SM_NESTING_NUM
#define CONFIG_SM_NESTING_NUM 3
#define CONFIG_USB_PID 0x5036
#define VPD_HW_VERSION 0x0001
#define VPD_FW_VERSION 0x0001
/* USB bcdDevice */
#define USB_BCD_DEVICE 0
/* Vbus impedance in milliohms */
#define VPD_VBUS_IMPEDANCE 65
/* GND impedance in milliohms */
#define VPD_GND_IMPEDANCE 33
/*
* TODO(crosbug.com/p/50519): Remove CONFIG_SYSTEM_UNLOCKED prior to building
* MP FW.
*/
#define CONFIG_SYSTEM_UNLOCKED
#ifdef HAS_TASK_CONSOLE
#undef CONFIG_CONSOLE_HISTORY
#define CONFIG_CONSOLE_HISTORY 2
#else
#undef CONFIG_CONSOLE_CMDHELP
#define CONFIG_DEBUG_PRINTF
#define UARTN CONFIG_UART_CONSOLE
#define UARTN_BASE STM32_USART_BASE(CONFIG_UART_CONSOLE)
#endif /* HAS_TASK_CONSOLE */
/* Use PSTATE embedded in the RO image, not in its own erase block */
#undef CONFIG_FLASH_PSTATE_BANK
#undef CONFIG_FW_PSTATE_SIZE
#define CONFIG_FW_PSTATE_SIZE 0
#ifndef __ASSEMBLER__
/* Timer selection */
#define TIM_CLOCK32 2
#define TIM_ADC 3
#include "gpio_signal.h"
/* ADC signal */
enum adc_channel {
ADC_VCONN_VSENSE = 0,
ADC_CC_VPDMCU,
ADC_CC_RP3A0_RD_L,
ADC_RDCONNECT_REF,
ADC_CC1_RP3A0_RD_L,
ADC_CC2_RP3A0_RD_L,
ADC_HOST_VBUS_VSENSE,
ADC_CHARGE_VBUS_VSENSE,
ADC_CC1_RPUSB_ODH,
ADC_CC2_RPUSB_ODH,
/* Number of ADC channels */
ADC_CH_COUNT
};
/* 1.5A Rp */
#define PD_SRC_VNC PD_SRC_1_5_VNC_MV
#define PD_SRC_RD_THRESHOLD PD_SRC_1_5_RD_THRESH_MV
#endif /* !__ASSEMBLER__ */
#endif /* __CROS_EC_BOARD_H */

View File

@ -0,0 +1,16 @@
# -*- makefile -*-
# Copyright 2019 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.
#
# Board specific files build
# the IC is STmicro STM32F051K8U6TR
CHIP:=stm32
CHIP_FAMILY:=stm32f0
CHIP_VARIANT:=stm32f05x
board-y=board.o vpd_api.o
#
# This target builds RW only. Therefore, remove RO from dependencies.
all_deps=$(patsubst ro,,$(def_all_deps))

View File

@ -0,0 +1,22 @@
/* Copyright 2019 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.
*/
/**
* List of enabled tasks in the priority order
*
* The first one has the lowest priority.
*
* For each task, use the macro TASK_ALWAYS(n, r, d, s) for base tasks and
* TASK_NOTEST(n, r, d, s) for tasks that can be excluded in test binaries,
* where :
* 'n' in the name of the task
* 'r' in the main routine of the task
* 'd' in an opaque parameter passed to the routine at startup
* 's' is the stack size in bytes; must be a multiple of 8
*/
#define CONFIG_TASK_LIST \
TASK_ALWAYS(HOOKS, hook_task, NULL, LARGER_TASK_STACK_SIZE) \
TASK_ALWAYS(CONSOLE, console_task, NULL, TASK_STACK_SIZE) \
TASK_ALWAYS(PD_C0, pd_task, NULL, LARGER_TASK_STACK_SIZE)

View File

@ -0,0 +1,80 @@
/* -*- mode:c -*-
*
* Copyright 2019 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.
*/
/* Declare symbolic names for all the GPIOs that we care about.
* Note: Those with interrupt handlers must be declared first. */
/* Divided Vconn voltage sense */
GPIO(VCONN_VSENSE, PIN(A, 0), GPIO_ANALOG)
/* CC ADC, PD in comparator, or tx enable out (low) */
GPIO(CC_VPDMCU, PIN(A, 1), GPIO_ANALOG)
/* CC 0.2V comparator during charge-through, active Rd (low) or Rp3A0 (high) */
GPIO(CC_RP3A0_RD_L, PIN(A, 2), GPIO_ANALOG)
/* 0.2V resistor divider for various CC comapators */
GPIO(RDCONNECT_REF, PIN(A, 3), GPIO_ANALOG)
/* Charger CC1 0.2V comparator and ADC, drive a Rp3A0 (high) or Rd (low) */
GPIO(CC1_RP3A0_RD_L, PIN(A, 4), GPIO_ANALOG)
/* Charger CC2 0.2V comparator and ADC, drive a Rp3A0 (high) or Rd (low) */
GPIO(CC2_RP3A0_RD_L, PIN(A, 5), GPIO_ANALOG)
/* Divided host VBUS voltage sense */
GPIO(HOST_VBUS_VSENSE, PIN(A, 6), GPIO_ANALOG)
/* Divided charger VBUS voltage sense */
GPIO(CHARGER_VBUS_VSENSE, PIN(A, 7), GPIO_ANALOG)
/* Charger CC1 ADC, or drive a RpUSB (high) */
GPIO(CC1_RPUSB_ODH, PIN(B, 0), GPIO_ANALOG)
/* Charger CC2 ADC, or drive a RpUSB (high) */
GPIO(CC2_RPUSB_ODH, PIN(B, 1), GPIO_ANALOG)
/* PD TX data output */
GPIO(CC_TX_DATA, PIN(B, 4), GPIO_INPUT)
/* Enables the VBUS pass-through (high) */
GPIO(VBUS_PASS_EN, PIN(B, 2), GPIO_OUT_LOW)
/*
* Desired billboard state. One of "no billboard/nothing connected" (low),
* "source connected but not in charge-through" (pull-up), or "sink connected"
* (high)
*/
GPIO(PRESENT_BILLBOARD, PIN(A, 8), GPIO_OUT_LOW)
/* Enables cReceiver and the path to the PD RX/TX, RpUSB, and Rp1A5 */
GPIO(VPDMCU_CC_EN, PIN(A, 11), GPIO_OUT_LOW)
/* Disables dead battery Rd on host side (low) */
GPIO(CC_DB_EN_OD, PIN(A, 12), GPIO_ODR_HIGH)
/* RpUSB on host side (high) */
GPIO(CC_RPUSB_ODH, PIN(A, 13), GPIO_INPUT)
/*
* Controls the dead-battery pull-downs on charger side; either dead battery
* Rd (low) or Hi-Z (high)
*/
GPIO(CC1_CC2_DB_EN_L, PIN(A, 15), GPIO_OUT_LOW)
/* Chooses between Vconn (low) and VBUS (high) */
GPIO(VCONN_PWR_SEL_ODL, PIN(B, 6), GPIO_INPUT)
/* Passes CC1 to the host CC (high) */
GPIO(CC1_SEL, PIN(F, 0), GPIO_OUT_LOW)
/* Passes CC2 to the host CC (high) */
GPIO(CC2_SEL, PIN(F, 1), GPIO_OUT_LOW)
/* Debug red LED driver (low). Keep off for power measurements */
GPIO(DEBUG_LED_R_L, PIN(B, 5), GPIO_ODR_HIGH)
/* Debug green LED driver (low). Keep off for power measurements */
GPIO(DEBUG_LED_G_L, PIN(B, 7), GPIO_ODR_HIGH)
UNIMPLEMENTED(WP_L)
UNIMPLEMENTED(ENTERING_RW)
/* SCK(PB3): PD_TX_CLK_IN - Clock input for PD TX */
ALTERNATE(PIN_MASK(B, 0x0008), 0, MODULE_USB_PD, 0)
/* TIM16_CH1(PB8): PD_TX_CLK_OUT - Clock generator for PD TX */
ALTERNATE(PIN_MASK(B, 0x0100), 2, MODULE_USB_PD, 0)
/* USART1 (PA9/PA10): TX/RX for debug and programming */
ALTERNATE(PIN_MASK(A, 0x0600), 1, MODULE_UART, 0)

View File

@ -0,0 +1,163 @@
/* Copyright 2019 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 "adc.h"
#include "chip/stm32/registers.h"
#include "ec_commands.h"
#include "gpio.h"
#include "vpd_api.h"
/* USB Power delivery board configuration */
#ifndef __CROS_EC_USB_PD_CONFIG_H
#define __CROS_EC_USB_PD_CONFIG_H
/* Timer selection for baseband PD communication */
#define TIM_CLOCK_PD_TX_C0 16
#define TIM_CLOCK_PD_RX_C0 1
#define TIM_CLOCK_PD_TX(p) TIM_CLOCK_PD_TX_C0
#define TIM_CLOCK_PD_RX(p) TIM_CLOCK_PD_RX_C0
/* Timer channel */
#define TIM_TX_CCR_C0 1
#define TIM_RX_CCR_C0 1
/* RX timer capture/compare register */
#define TIM_CCR_C0 (&STM32_TIM_CCRx(TIM_CLOCK_PD_RX_C0, TIM_RX_CCR_C0))
#define TIM_RX_CCR_REG(p) TIM_CCR_C0
/* TX and RX timer register */
#define TIM_REG_TX_C0 (STM32_TIM_BASE(TIM_CLOCK_PD_TX_C0))
#define TIM_REG_RX_C0 (STM32_TIM_BASE(TIM_CLOCK_PD_RX_C0))
#define TIM_REG_TX(p) TIM_REG_TX_C0
#define TIM_REG_RX(p) TIM_REG_RX_C0
/* use the hardware accelerator for CRC */
#define CONFIG_HW_CRC
/* TX uses SPI1 on PB3-4 for port C0 */
#define SPI_REGS(p) STM32_SPI1_REGS
static inline void spi_enable_clock(int port)
{
STM32_RCC_APB2ENR |= STM32_RCC_PB2_SPI1;
}
/* SPI1_TX no remap needed */
#define DMAC_SPI_TX(p) STM32_DMAC_CH3
/* RX is using COMP1 triggering TIM1 CH1 */
#define CMP1OUTSEL STM32_COMP_CMP1OUTSEL_TIM1_IC1
#define CMP2OUTSEL 0
#define TIM_TX_CCR_IDX(p) TIM_TX_CCR_C0
#define TIM_RX_CCR_IDX(p) TIM_RX_CCR_C0
#define TIM_CCR_CS 1
/* EXTI line 21 is connected to the CMP1 output */
#define EXTI_COMP1_MASK (1 << 21)
/* EXTI line 22 is connected to the CMP1 output */
#define EXTI_COMP2_MASK (1 << 22)
#define EXTI_COMP_MASK(p) (EXTI_COMP1_MASK | EXTI_COMP2_MASK)
#define IRQ_COMP STM32_IRQ_COMP
/* triggers packet detection on comparator falling edge */
#define EXTI_XTSR STM32_EXTI_FTSR
/* TIM1_CH1 no remap needed */
#define DMAC_TIM_RX(p) STM32_DMAC_CH2
/* the pins used for communication need to be hi-speed */
static inline void pd_set_pins_speed(int port)
{
/*
* 40 MHz pin speed on SPI PB3&4,
* (USB_C0_TX_CLKIN & USB_C0_CC1_TX_DATA)
*
* 40 MHz pin speed on TIM17_CH1 (PB7),
* (PD_TX_CLK_OUT)
*/
STM32_GPIO_OSPEEDR(GPIO_B) |= 0x0000C3C0;
}
/* Reset SPI peripheral used for TX */
static inline void pd_tx_spi_reset(int port)
{
/* Reset SPI1 */
STM32_RCC_APB2RSTR |= (1 << 12);
STM32_RCC_APB2RSTR &= ~(1 << 12);
}
/* Drive the CC line from the TX block */
static inline void pd_tx_enable(int port, int polarity)
{
/* USB_CC_TX_DATA: PB4 is SPI1 MISO */
STM32_GPIO_MODER(GPIO_B) = (STM32_GPIO_MODER(GPIO_B)
& ~(3 << (2*4))) /* PB4 disable ADC */
| (2 << (2*4)); /* Set as SPI1_MISO */
/* MCU ADC PA1 pin output low */
STM32_GPIO_MODER(GPIO_A) = (STM32_GPIO_MODER(GPIO_A)
& ~(3 << (2*1))) /* PA1 disable ADC */
| (1 << (2*1)); /* Set as GPO */
gpio_set_level(GPIO_CC_VPDMCU, 0);
}
/* Put the TX driver in Hi-Z state */
static inline void pd_tx_disable(int port, int polarity)
{
/* Set CC_TX_DATA to Hi-Z, PB4 is SPI1 MISO */
STM32_GPIO_MODER(GPIO_B) = (STM32_GPIO_MODER(GPIO_B)
& ~(3 << (2*4)));
/* set ADC PA1 pin to ADC function (Hi-Z) */
STM32_GPIO_MODER(GPIO_A) = (STM32_GPIO_MODER(GPIO_A)
| (3 << (2*1))); /* PA1 as ADC */
}
/* we know the plug polarity, do the right configuration */
static inline void pd_select_polarity(int port, int polarity)
{
/*
* use the right comparator : CC1 -> PA1 (COMP1 INP)
* use VrefInt / 2 as INM (about 600mV)
*/
STM32_COMP_CSR = (STM32_COMP_CSR & ~STM32_COMP_CMP1INSEL_MASK)
| STM32_COMP_CMP1EN | STM32_COMP_CMP1INSEL_VREF12;
}
/* Initialize pins used for TX and put them in Hi-Z */
static inline void pd_tx_init(void)
{
gpio_config_module(MODULE_USB_PD, 1);
}
static inline void pd_set_host_mode(int port, int enable)
{
/* Do nothing */
}
/**
* Initialize various GPIOs and interfaces to safe state at start of pd_task.
*
* These include:
* Physical layer CC transmit.
*
* @param port USB-C port number
* @param power_role Power role of device
*/
static inline void pd_config_init(int port, uint8_t power_role)
{
/* Initialize TX pins and put them in Hi-Z */
pd_tx_init();
pd_tx_disable(0, 0);
}
static inline int pd_adc_read(int port, int cc)
{
return 0;
}
#endif /* __CROS_EC_USB_PD_CONFIG_H */

View File

@ -0,0 +1,531 @@
/* Copyright 2019 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 "adc.h"
#include "gpio.h"
#include "registers.h"
#include "vpd_api.h"
#include "driver/tcpm/tcpm.h"
/*
* Polarity based on 'DFP Perspective' (see table 4-10 USB Type-C Cable and
* Connector Specification Release 1.3)
*
* CC1 CC2 STATE POSITION
* ----------------------------------------
* open open NC N/A
* Rd open UFP attached 1
* open Rd UFP attached 2
* open Ra pwr cable no UFP N/A
* Ra open pwr cable no UFP N/A
* Rd Ra pwr cable & UFP 1
* Ra Rd pwr cable & UFP 2
* Rd Rd dbg accessory N/A
* Ra Ra audio accessory N/A
*
* Note, V(Rd) > V(Ra)
*/
#ifndef PD_SRC_RD_THRESHOLD
#define PD_SRC_RD_THRESHOLD PD_SRC_DEF_RD_THRESH_MV
#endif
#ifndef PD_SRC_VNC
#define PD_SRC_VNC PD_SRC_DEF_VNC_MV
#endif
#undef CC_RA
#define CC_RA(cc, sel) (cc < pd_src_rd_threshold[sel])
#undef CC_RD
#define CC_RD(cc, sel) ((cc >= pd_src_rd_threshold[sel]) && (cc < PD_SRC_VNC))
/* (15.8K / (100K + 15.8K)) * 1000 = 136.4 */
#define VBUS_SCALE_FACTOR 136
/* (118K / (100K + 118K)) * 1000 = 541.3 */
#define VCONN_SCALE_FACTOR 541
#define VBUS_DETECT_THRESHOLD 2500 /* mV */
#define VCONN_DETECT_THRESHOLD 2500 /* mV */
#define SCALE(vmeas, sfactor) (((vmeas) * 1000) / (sfactor))
/*
* Type C power source charge current limits are identified by their cc
* voltage (set by selecting the proper Rd resistor). Any voltage below
* TYPE_C_SRC_500_THRESHOLD will not be identified as a type C charger.
*/
#define TYPE_C_SRC_DEFAULT_THRESHOLD 200 /* mV */
#define TYPE_C_SRC_1500_THRESHOLD 660 /* mV */
#define TYPE_C_SRC_3000_THRESHOLD 1230 /* mV */
/* Charge-Through pull up/down enabled */
static int ct_cc_pull;
/* Charge-Through pull up value */
static int ct_cc_rp_value;
/* Charge-Through pull up/down enabled */
static int host_cc_pull;
/* Charge-Through pull up value */
static int host_cc_rp_value;
/* Voltage thresholds for Ra attach in normal SRC mode */
static int pd_src_rd_threshold[TYPEC_RP_RESERVED] = {
PD_SRC_DEF_RD_THRESH_MV,
PD_SRC_1_5_RD_THRESH_MV,
PD_SRC_3_0_RD_THRESH_MV,
};
/* Convert CC voltage to CC status */
static int vpd_cc_voltage_to_status(int cc_volt, int cc_pull)
{
/* If we have a pull-up, then we are source, check for Rd. */
if (cc_pull == TYPEC_CC_RP) {
if (CC_RD(cc_volt, ct_cc_rp_value))
return TYPEC_CC_RD;
else if (CC_RA(cc_volt, ct_cc_rp_value))
return TYPEC_CC_VOLT_RA;
else
return TYPEC_CC_VOLT_OPEN;
/* If we have a pull-down, then we are sink, check for Rp. */
} else if (cc_pull == TYPEC_CC_RD || cc_pull == TYPEC_CC_RA_RD) {
if (cc_volt >= TYPE_C_SRC_3000_THRESHOLD)
return TYPEC_CC_VOLT_RP_3_0;
else if (cc_volt >= TYPE_C_SRC_1500_THRESHOLD)
return TYPEC_CC_VOLT_RP_1_5;
else if (cc_volt >= TYPE_C_SRC_DEFAULT_THRESHOLD)
return TYPEC_CC_VOLT_RP_DEF;
else
return TYPEC_CC_VOLT_OPEN;
} else {
/* If we are open, then always return 0 */
return 0;
}
}
void vpd_ct_set_pull(int pull, int rp_value)
{
ct_cc_pull = pull;
switch (pull) {
case TYPEC_CC_RP:
ct_cc_rp_value = rp_value;
vpd_cc1_cc2_db_en_l(GPO_HIGH);
switch (rp_value) {
case TYPEC_RP_USB:
vpd_config_cc1_rp3a0_rd_l(PIN_ADC, 0);
vpd_config_cc2_rp3a0_rd_l(PIN_ADC, 0);
vpd_config_cc1_rpusb_odh(PIN_GPO, 1);
vpd_config_cc2_rpusb_odh(PIN_GPO, 1);
break;
case TYPEC_RP_3A0:
vpd_config_cc1_rpusb_odh(PIN_ADC, 0);
vpd_config_cc2_rpusb_odh(PIN_ADC, 0);
vpd_config_cc1_rp3a0_rd_l(PIN_GPO, 1);
vpd_config_cc2_rp3a0_rd_l(PIN_GPO, 1);
break;
}
break;
case TYPEC_CC_RD:
vpd_config_cc1_rpusb_odh(PIN_ADC, 0);
vpd_config_cc2_rpusb_odh(PIN_ADC, 0);
vpd_config_cc1_rp3a0_rd_l(PIN_GPO, 0);
vpd_config_cc2_rp3a0_rd_l(PIN_GPO, 0);
vpd_cc1_cc2_db_en_l(GPO_HIGH);
break;
case TYPEC_CC_OPEN:
vpd_cc1_cc2_db_en_l(GPO_HIGH);
vpd_config_cc1_rpusb_odh(PIN_ADC, 0);
vpd_config_cc2_rpusb_odh(PIN_ADC, 0);
vpd_config_cc1_rp3a0_rd_l(PIN_ADC, 0);
vpd_config_cc2_rp3a0_rd_l(PIN_ADC, 0);
break;
}
}
void vpd_ct_get_cc(int *cc1, int *cc2)
{
int cc1_v;
int cc2_v;
switch (ct_cc_pull) {
case TYPEC_CC_RP:
switch (ct_cc_rp_value) {
case TYPEC_RP_USB:
cc1_v = adc_read_channel(ADC_CC1_RP3A0_RD_L);
cc2_v = adc_read_channel(ADC_CC2_RP3A0_RD_L);
break;
case TYPEC_RP_3A0:
cc1_v = adc_read_channel(ADC_CC1_RPUSB_ODH);
cc2_v = adc_read_channel(ADC_CC2_RPUSB_ODH);
break;
}
break;
case TYPEC_CC_RD:
cc1_v = adc_read_channel(ADC_CC1_RPUSB_ODH);
cc2_v = adc_read_channel(ADC_CC2_RPUSB_ODH);
break;
case TYPEC_CC_OPEN:
*cc1 = 0;
*cc2 = 0;
return;
}
*cc1 = vpd_cc_voltage_to_status(cc1_v, ct_cc_pull);
*cc2 = vpd_cc_voltage_to_status(cc2_v, ct_cc_pull);
}
void vpd_host_set_pull(int pull, int rp_value)
{
host_cc_pull = pull;
switch (pull) {
case TYPEC_CC_RP:
vpd_cc_db_en_od(GPO_LOW);
host_cc_rp_value = rp_value;
switch (rp_value) {
case TYPEC_RP_USB:
vpd_config_cc_rp3a0_rd_l(PIN_CMP, 0);
vpd_cc_rpusb_odh(GPO_HIGH);
break;
case TYPEC_RP_3A0:
vpd_cc_rpusb_odh(GPO_HZ);
vpd_config_cc_rp3a0_rd_l(PIN_GPO, 1);
break;
}
break;
case TYPEC_CC_RD:
vpd_cc_rpusb_odh(GPO_HZ);
vpd_cc_db_en_od(GPO_LOW);
vpd_config_cc_rp3a0_rd_l(PIN_GPO, 0);
break;
case TYPEC_CC_RA_RD:
vpd_cc_rpusb_odh(GPO_HZ);
vpd_config_cc_rp3a0_rd_l(PIN_GPO, 0);
/*
* RA is connected to VCONN
* RD is connected to CC
*/
vpd_cc_db_en_od(GPO_HZ);
break;
case TYPEC_CC_OPEN:
vpd_cc_rpusb_odh(GPO_HZ);
vpd_config_cc_rp3a0_rd_l(PIN_CMP, 0);
vpd_cc_db_en_od(GPO_LOW);
break;
}
}
void vpd_host_get_cc(int *cc)
{
*cc = vpd_cc_voltage_to_status(
adc_read_channel(ADC_CC_VPDMCU), host_cc_pull);
}
void vpd_rx_enable(int en)
{
tcpm_set_rx_enable(0, en);
}
/*
* PA2: Configure as COMP2_INM6 or GPO
*/
void vpd_config_cc_rp3a0_rd_l(enum vpd_pin cfg, int en)
{
if (cfg == PIN_GPO) {
/* Set output value in register */
gpio_set_level(GPIO_CC_RP3A0_RD_L, en ? 1 : 0);
/* Disable Analog mode and Enable GPO */
STM32_GPIO_MODER(GPIO_A) = (STM32_GPIO_MODER(GPIO_A)
& ~(3 << (2*2))) /* PA2 disable ADC */
| (1 << (2*2)); /* Set as GPO */
} else {
/* Set PA2 pin to ANALOG function */
STM32_GPIO_MODER(GPIO_A) = (STM32_GPIO_MODER(GPIO_A)
| (3 << (2*2))); /* PA2 in ANALOG mode */
/* Set PA3 pin to ANALOG function */
STM32_GPIO_MODER(GPIO_A) = (STM32_GPIO_MODER(GPIO_A)
| (3 << (2*3))); /* PA3 in ANALOG mode */
/* Disable Window Mode. Select PA3 */
STM32_COMP_CSR &= ~STM32_COMP_WNDWEN;
/* No output selection. We will use Interrupt */
STM32_COMP_CSR &= ~STM32_COMP_CMP2OUTSEL_NONE;
/* Not inverting */
STM32_COMP_CSR &= ~STM32_COMP_CMP2POL;
/* Select COMP2_INM6 (PA2) */
STM32_COMP_CSR |= STM32_COMP_CMP2INSEL_INM6;
/* COMP Enable */
STM32_COMP_CSR |= STM32_COMP_CMP2EN;
}
}
/*
* PA4: Configure as ADC, CMP, or GPO
*/
void vpd_config_cc1_rp3a0_rd_l(enum vpd_pin cfg, int en)
{
if (cfg == PIN_GPO) {
/* Default high. Enable cc1 Rp3A0 pullup */
gpio_set_level(GPIO_CC1_RP3A0_RD_L, en ? 1 : 0);
/* Disable Analog mode and Enable GPO */
STM32_GPIO_MODER(GPIO_A) = (STM32_GPIO_MODER(GPIO_A)
& ~(3 << (2*4))) /* PA4 disable ADC */
| (1 << (2*4)); /* Set as GPO */
}
if (cfg == PIN_ADC || cfg == PIN_CMP) {
/* Disable COMP2 */
STM32_COMP_CSR &= ~STM32_COMP_CMP2EN;
/* Set PA4 pin to Analog mode */
STM32_GPIO_MODER(GPIO_A) = (STM32_GPIO_MODER(GPIO_A)
| (3 << (2*4))); /* PA4 in ANALOG mode */
if (cfg == PIN_CMP) {
/* Set PA3 pin to ANALOG function */
STM32_GPIO_MODER(GPIO_A) = (STM32_GPIO_MODER(GPIO_A)
| (3 << (2*3))); /* PA3 in ANALOG mode */
/* Disable Window Mode. Select PA3*/
STM32_COMP_CSR &= ~STM32_COMP_WNDWEN;
/* No output selection. We will use Interrupt */
STM32_COMP_CSR &= ~STM32_COMP_CMP2OUTSEL_NONE;
/* Select COMP2_INM4 (PA4) */
STM32_COMP_CSR |= STM32_COMP_CMP2INSEL_INM4;
/* COMP2 Enable */
STM32_COMP_CSR |= STM32_COMP_CMP2EN;
}
}
}
/*
* PA5: Configure as ADC, COMP, or GPO
*/
void vpd_config_cc2_rp3a0_rd_l(enum vpd_pin cfg, int en)
{
if (cfg == PIN_GPO) {
/* Set output value in register */
gpio_set_level(GPIO_CC2_RP3A0_RD_L, en ? 1 : 0);
/* Disable Analog mode and Enable GPO */
STM32_GPIO_MODER(GPIO_A) = (STM32_GPIO_MODER(GPIO_A)
& ~(3 << (2*5))) /* PA5 disable ADC */
| (1 << (2*5)); /* Set as GPO */
}
if (cfg == PIN_ADC || cfg == PIN_CMP) {
/* Disable COMP2 */
STM32_COMP_CSR &= ~STM32_COMP_CMP2EN;
/* Set PA5 pin to ANALOG function */
STM32_GPIO_MODER(GPIO_A) = (STM32_GPIO_MODER(GPIO_A)
| (3 << (2*5))); /* PA5 in ANALOG mode */
if (cfg == PIN_CMP) {
/* Set PA3 pin to ANALOG function */
STM32_GPIO_MODER(GPIO_A) = (STM32_GPIO_MODER(GPIO_A)
| (3 << (2*3))); /* PA3 in ANALOG mode */
/* Disable Window Mode. */
STM32_COMP_CSR &= ~STM32_COMP_WNDWEN;
/* No output selection. We will use Interrupt */
STM32_COMP_CSR &= ~STM32_COMP_CMP2OUTSEL_NONE;
/* Select COMP2_INM5 (PA5) */
STM32_COMP_CSR |= STM32_COMP_CMP2INSEL_INM5;
/* COMP2 Enable */
STM32_COMP_CSR |= STM32_COMP_CMP2EN;
}
}
}
/*
* PB0: Configure as ADC or GPO
*/
void vpd_config_cc1_rpusb_odh(enum vpd_pin cfg, int en)
{
if (cfg == PIN_GPO) {
/* Set output value in register */
gpio_set_level(GPIO_CC1_RPUSB_ODH, en ? 1 : 0);
/* Disable Analog mode and Enable GPO */
STM32_GPIO_MODER(GPIO_B) = (STM32_GPIO_MODER(GPIO_B)
& ~(3 << (2*0))) /* PB0 disable ADC */
| (1 << (2*0)); /* Set as GPO */
} else {
/* Enable Analog mode */
STM32_GPIO_MODER(GPIO_B) = (STM32_GPIO_MODER(GPIO_B)
| (3 << (2*0))); /* PB0 in ANALOG mode */
}
}
/*
* PB1: Configure as ADC or GPO
*/
void vpd_config_cc2_rpusb_odh(enum vpd_pin cfg, int en)
{
if (cfg == PIN_GPO) {
/* Set output value in register */
gpio_set_level(GPIO_CC2_RPUSB_ODH, en ? 1 : 0);
/* Disable Analog mode and Enable GPO */
STM32_GPIO_MODER(GPIO_B) = (STM32_GPIO_MODER(GPIO_B)
& ~(3 << (2*1))) /* PB1 disable ADC */
| (1 << (2*1)); /* Set as GPO */
} else {
/* Enable Analog mode */
STM32_GPIO_MODER(GPIO_B) = (STM32_GPIO_MODER(GPIO_B)
| (3 << (2*1))); /* PB1 in ANALOG mode */
}
}
inline int vpd_read_cc_vpdmcu(void)
{
return adc_read_channel(ADC_CC_VPDMCU);
}
inline int vpd_read_host_vbus(void)
{
return SCALE(adc_read_channel(ADC_HOST_VBUS_VSENSE), VBUS_SCALE_FACTOR);
}
inline int vpd_read_ct_vbus(void)
{
return SCALE(adc_read_channel(ADC_CHARGE_VBUS_VSENSE),
VBUS_SCALE_FACTOR);
}
inline int vpd_read_vconn(void)
{
return SCALE(adc_read_channel(ADC_VCONN_VSENSE), VCONN_SCALE_FACTOR);
}
inline int vpd_is_host_vbus_present(void)
{
return (vpd_read_host_vbus() >= VBUS_DETECT_THRESHOLD);
}
inline int vpd_is_ct_vbus_present(void)
{
return (vpd_read_ct_vbus() >= VBUS_DETECT_THRESHOLD);
}
inline int vpd_is_vconn_present(void)
{
return (vpd_read_vconn() >= VCONN_DETECT_THRESHOLD);
}
inline int vpd_read_rdconnect_ref(void)
{
return adc_read_channel(ADC_RDCONNECT_REF);
}
void vpd_red_led(int on)
{
gpio_set_level(GPIO_DEBUG_LED_R_L, (on) ? 0 : 1);
}
void vpd_green_led(int on)
{
gpio_set_level(GPIO_DEBUG_LED_G_L, (on) ? 0 : 1);
}
void vpd_vbus_pass_en(int en)
{
gpio_set_level(GPIO_VBUS_PASS_EN, (en) ? 1 : 0);
}
void vpd_present_billboard(enum vpd_billboard bb)
{
switch (bb) {
case BB_NONE:
gpio_set_level(GPIO_PRESENT_BILLBOARD, 0);
gpio_set_flags(GPIO_PRESENT_BILLBOARD, GPIO_OUTPUT);
break;
case BB_SRC:
gpio_set_flags(GPIO_PRESENT_BILLBOARD, GPIO_INPUT);
/* Enable Pull-up on PA8 */
STM32_GPIO_PUPDR(GPIO_A) |= (1 << (2 * 8));
break;
case BB_SNK:
gpio_set_level(GPIO_PRESENT_BILLBOARD, 1);
gpio_set_flags(GPIO_PRESENT_BILLBOARD, GPIO_OUTPUT);
break;
}
}
void vpd_mcu_cc_en(int en)
{
gpio_set_level(GPIO_VPDMCU_CC_EN, (en) ? 1 : 0);
}
void vpd_ct_cc_sel(enum vpd_cc sel)
{
switch (sel) {
case CT_OPEN:
gpio_set_level(GPIO_CC1_SEL, 0);
gpio_set_level(GPIO_CC2_SEL, 0);
break;
case CT_CC1:
gpio_set_level(GPIO_CC2_SEL, 0);
gpio_set_level(GPIO_CC1_SEL, 1);
break;
case CT_CC2:
gpio_set_level(GPIO_CC1_SEL, 0);
gpio_set_level(GPIO_CC2_SEL, 1);
break;
}
}
/* Set as GPO High, GPO Low, or High-Z */
void vpd_cc_db_en_od(enum vpd_gpo val)
{
if (val == GPO_HZ) {
gpio_set_flags(GPIO_CC_DB_EN_OD, GPIO_INPUT);
} else {
if (val == GPO_HIGH)
gpio_set_level(GPIO_CC_DB_EN_OD, 1);
else
gpio_set_level(GPIO_CC_DB_EN_OD, 0);
gpio_set_flags(GPIO_CC_DB_EN_OD, GPIO_OUTPUT);
}
}
void vpd_cc_rpusb_odh(enum vpd_gpo val)
{
if (val == GPO_HZ) {
gpio_set_flags(GPIO_CC_RPUSB_ODH, GPIO_INPUT);
} else {
gpio_set_level(GPIO_CC_RPUSB_ODH, (val == GPO_HIGH) ? 1 : 0);
gpio_set_flags(GPIO_CC_RPUSB_ODH, GPIO_OUTPUT);
}
}
void vpd_cc1_cc2_db_en_l(enum vpd_gpo val)
{
if (val == GPO_HZ) {
gpio_set_flags(GPIO_CC1_CC2_DB_EN_L, GPIO_INPUT);
} else {
gpio_set_level(GPIO_CC1_CC2_DB_EN_L, (val == GPO_HIGH) ? 1 : 0);
gpio_set_flags(GPIO_CC1_CC2_DB_EN_L, GPIO_OUTPUT);
}
}
void vpd_vconn_pwr_sel_odl(enum vpd_pwr en)
{
gpio_set_level(GPIO_VCONN_PWR_SEL_ODL, (en == PWR_VBUS) ? 1 : 0);
}

View File

@ -0,0 +1,276 @@
/* Copyright 2019 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.
*/
/* Vconn Power Device API module */
#ifndef __CROS_EC_VPD_API_H
#define __CROS_EC_VPD_API_H
#include "adc.h"
#include "gpio.h"
#include "usb_pd.h"
enum vpd_pin {
PIN_ADC,
PIN_CMP,
PIN_GPO
};
enum vpd_gpo {
GPO_HZ,
GPO_HIGH,
GPO_LOW
};
enum vpd_pwr {
PWR_VCONN,
PWR_VBUS,
};
enum vpd_cc {
CT_OPEN,
CT_CC1,
CT_CC2
};
enum vpd_billboard {
BB_NONE,
BB_SRC,
BB_SNK
};
/**
* Set Charge-Through Rp or Rd on CC lines
*
* @param pull Either TYPEC_CC_RP or TYPEC_CC_RD
* @param rp_value When pull is RP, set this to
* TYPEC_RP_USB or TYPEC_RP_1A5. Ignored
* for TYPEC_CC_RD
*/
void vpd_ct_set_pull(int pull, int rp_value);
/**
* Get the status of the Charge-Through CC lines
*
* @param cc1 Either TYPEC_CC_VOLT_OPEN,
* TYPEC_CC_VOLT_RA,
* TYPEC_CC_VOLT_RD,
* any other value is considered RP
* @param cc2 Either TYPEC_CC_VOLT_OPEN,
* TYPEC_CC_VOLT_RA,
* TYPEC_CC_VOLT_RD,
* any other value is considered RP
*/
void vpd_ct_get_cc(int *cc1, int *cc2);
/**
* Set Host Rp or Rd on CC lines
*
* @param pull Either TYPEC_CC_RP or TYPEC_CC_RD
* @param rp_value When pull is RP, set this to
* TYPEC_RP_USB or TYPEC_RP_1A5. Ignored
* for TYPEC_CC_RD
*/
void vpd_host_set_pull(int pull, int rp_value);
/**
* Get the status of the Host CC line
*
* @param cc Either TYPEC_CC_VOLT_SNK_DEF, TYPEC_CC_VOLT_SNK_1_5,
* TYPEC_CC_VOLT_SNK_3_0, or TYPEC_CC_RD
*/
void vpd_host_get_cc(int *cc);
/**
* Set RX Enable flag
*
* @param en 1 for enable, 0 for disable
*/
void vpd_rx_enable(int en);
/**
* Configure the cc_rp3a0_rd_l pin as ADC, CMP, or GPO
*
* @param cfg PIN_ADC, PIN_CMP, or PIN_GPO
* @param en When cfg is PIN_GPO, 1 sets pin high
* and 0 sets pin low. Else ignored
*/
void vpd_config_cc_rp3a0_rd_l(enum vpd_pin cfg, int en);
/**
* Configure the cc1_rp3a0_rd_l pin as ADC, CMP, or GPO
*
* @param cfg PIN_ADC, PIN_CMP, or PIN_GPO
* @param en When cfg is PIN_GPO, 1 sets pin high
* and 0 sets pin low. Else ignored
*/
void vpd_config_cc1_rp3a0_rd_l(enum vpd_pin cfg, int en);
/**
* Configure the cc2_rp3a0_rd_l pin as ADC, CMP, or GPO
*
* @param cfg PIN_ADC, PIN_CMP, or PIN_GPO
* @param en When cfg is PIN_GPO, 1 sets pin high
* and 0 sets pin low. Else ignored
*/
void vpd_config_cc2_rp3a0_rd_l(enum vpd_pin cfg, int en);
/**
* Configure the cc1_rpusb_odh pin as ADC, CMP, or GPO
*
* @param cfg PIN_ADC, PIN_CMP, or PIN_GPO
* @param en When cfg is PIN_GPO, 1 sets pin high
* and 0 sets pin low. Else ignored
*/
void vpd_config_cc1_rpusb_odh(enum vpd_pin cfg, int en);
/**
* Configure the cc2_rpusb_odh pin as ADC, CMP, or GPO
*
* @param cfg PIN_ADC, PIN_CMP, or PIN_GPO
* @param en When cfg is PIN_GPO, 1 sets pin high
* and 0 sets pin low. Else ignored
*/
void vpd_config_cc2_rpusb_odh(enum vpd_pin cfg, int en);
/**
* Configure the cc_db_en_od pin to High-Impedance, low, or high
*
* @param val GPO_HZ, GPO_HIGH, GPO_LOW
*/
void vpd_cc_db_en_od(enum vpd_gpo val);
/**
* Configure the cc_rpusb_odh pin to High-Impedance, low, or high
*
* @param val GPO_HZ, GPO_HIGH, GPO_LOW
*/
void vpd_cc_rpusb_odh(enum vpd_gpo val);
/**
* Configure the cc_rp1a5_odh pin to High-Impedance, low, or high
*
* @param val GPO_HZ, GPO_HIGH, GPO_LOW
*/
void vpd_cc_rp1a5_odh(enum vpd_gpo val);
/**
* Configure the cc1_cc2_db_en_l pin to High-Impedance, low, or high
*
* @param val GPO_HZ, GPO_HIGH, GPO_LOW
*/
void vpd_cc1_cc2_db_en_l(enum vpd_gpo val);
/**
* Get status of host vbus
*
* @return 1 if host vbus is present, else 0
*/
int vpd_is_host_vbus_present(void);
/**
* Get status of charge-through vbus
*
* @return 1 if charge-through vbus is present, else 0
*/
int vpd_is_ct_vbus_present(void);
/**
* Get status of vconn
*
* @return 1 if vconn is present, else 0
*/
int vpd_is_vconn_present(void);
/**
* Read Host VBUS voltage. Range from 22000mV to 3000mV
*
* @return vbus voltage
*/
int vpd_read_host_vbus(void);
/**
* Read Host CC voltage.
*
* @return cc voltage
*/
int vpd_read_cc_host(void);
/**
* Read voltage on cc_vpdmcu pin
*
* @return cc_vpdmcu voltage
*/
int vpd_read_cc_vpdmcu(void);
/**
* Read charge-through VBUS voltage. Range from 22000mV to 3000mV
*
* @return charge-through vbus voltage
*/
int vpd_read_ct_vbus(void);
/**
* Read VCONN Voltage. Range from 5500mV to 3000mV
*
* @return vconn voltage
*/
int vpd_read_vconn(void);
/**
* Turn ON/OFF Red LED. Should be off when performing power
* measurements.
*
* @param on 0 turns LED off, any other value turns it ON
*/
void vpd_red_led(int on);
/**
* Turn ON/OFF Green LED. Should be off when performing power
* measurements.
*
* @param on 0 turns LED off, any other value turns it ON
*/
void vpd_green_led(int on);
/**
* Connects/Disconnects the Host VBUS to the Charge-Through VBUS.
*
* @param en 0 disconnectes the VBUS, any other value connects VBUS.
*/
void vpd_vbus_pass_en(int en);
/**
* Preset Billboard device
*
* @param bb BB_NONE no billboard presented,
* BB_SRC source connected but not in charge-through
* BB_SNK sink connected
*/
void vpd_present_billboard(enum vpd_billboard bb);
/**
* Enables the MCU to host cc communication
*
* @param en 1 enabled, 0 disabled
*/
void vpd_mcu_cc_en(int en);
/**
* Selects which supply to power the VPD from
*
* @param en PWR_VCONN or PWR_VBUS
*/
void vpd_vconn_pwr_sel_odl(enum vpd_pwr en);
/**
* Controls if the Charge-Through's CC1, CC2, or neither is
* connected to Host CC
*
* @param sel CT_OPEN neither, CT_CC1 cc1, CT_CC2 cc2
*/
void vpd_ct_cc_sel(enum vpd_cc sel);
#endif /* __CROS_EC_VPD_API_H */

View File

@ -40,7 +40,11 @@ static const struct adc_profile_t profile = {
/* Sample all channels once using DMA */
.cfgr1_reg = STM32_ADC_CFGR1_OVRMOD,
.cfgr2_reg = 0,
#ifdef CONFIG_ADC_SAMPLE_TIME
.smpr_reg = CONFIG_ADC_SAMPLE_TIME,
#else
.smpr_reg = STM32_ADC_SMPR_13_5_CY,
#endif
.ier_reg = 0,
.dma_option = &dma_single,
.dma_buffer_size = 1,
@ -60,7 +64,11 @@ static const struct adc_profile_t profile = {
STM32_ADC_CFGR1_CONT |
STM32_ADC_CFGR1_DMACFG,
.cfgr2_reg = 0,
#ifdef CONFIG_ADC_SAMPLE_TIME
.smpr_reg = CONFIG_ADC_SAMPLE_TIME,
#else
.smpr_reg = STM32_ADC_SMPR_1_5_CY,
#endif
/* Fire interrupt at end of sequence. */
.ier_reg = STM32_ADC_IER_EOSEQIE,
.dma_option = &dma_continuous,

View File

@ -452,6 +452,16 @@ void pd_rx_handler(void)
int next_idx;
pending = STM32_EXTI_PR;
#ifdef CONFIG_USB_TYPEC_CTVPD
/* Charge-Through Side detach event */
if (pending & EXTI_COMP2_MASK) {
task_set_event(PD_PORT_TO_TASK_ID(0), PD_EVENT_SM, 0);
/* Clear interrupt */
STM32_EXTI_PR = EXTI_COMP2_MASK;
pending &= ~EXTI_COMP2_MASK;
}
#endif
for (i = 0; i < CONFIG_USB_PD_PORT_COUNT; i++) {
if (pending & EXTI_COMP_MASK(i)) {
rx_edge_ts[i][rx_edge_ts_idx[i]].val = get_time().val;
@ -648,6 +658,7 @@ void pd_hw_init(int port, int role)
phy->tim_tx->ccmr1 = val;
else
phy->tim_tx->ccmr2 = val;
phy->tim_tx->ccer = 1 << ((TIM_TX_CCR_IDX(port) - 1) * 4);
phy->tim_tx->bdtr = 0x8000;
/* set prescaler to /1 */

View File

@ -128,7 +128,14 @@ common-$(CONFIG_USB_I2C)+=usb_i2c.o
common-$(CONFIG_USB_CHARGER)+=usb_charger.o
common-$(CONFIG_USB_PORT_POWER_DUMB)+=usb_port_power_dumb.o
common-$(CONFIG_USB_PORT_POWER_SMART)+=usb_port_power_smart.o
ifeq ($(CONFIG_USB_SM_FRAMEWORK),)
common-$(CONFIG_USB_POWER_DELIVERY)+=usb_pd_protocol.o usb_pd_policy.o
else
common-$(CONFIG_USB_SM_FRAMEWORK)+=usb_sm.o
common-$(CONFIG_USB_TYPEC_SM)+=usb_tc_sm.o
common-$(CONFIG_USB_PRL_SM)+=usb_prl_sm.o
common-$(CONFIG_USB_PE_SM)+=usb_pe_sm.o
endif
common-$(CONFIG_USB_PD_LOGGING)+=event_log.o pd_log.o
common-$(CONFIG_USB_PD_TCPC)+=usb_pd_tcpc.o
common-$(CONFIG_USB_UPDATE)+=usb_update.o update_fw.o

View File

@ -343,11 +343,19 @@ int prepare_message(int port, uint16_t header, uint8_t cnt,
int off, i;
/* 64-bit preamble */
off = pd_write_preamble(port);
#if defined(CONFIG_USB_TYPEC_VPD) || defined(CONFIG_USB_TYPEC_CTVPD)
/* Start Of Packet Prime: 2x Sync-1 + 2x Sync-3 */
off = pd_write_sym(port, off, BMC(PD_SYNC1));
off = pd_write_sym(port, off, BMC(PD_SYNC1));
off = pd_write_sym(port, off, BMC(PD_SYNC3));
off = pd_write_sym(port, off, BMC(PD_SYNC3));
#else
/* Start Of Packet: 3x Sync-1 + 1x Sync-2 */
off = pd_write_sym(port, off, BMC(PD_SYNC1));
off = pd_write_sym(port, off, BMC(PD_SYNC1));
off = pd_write_sym(port, off, BMC(PD_SYNC1));
off = pd_write_sym(port, off, BMC(PD_SYNC2));
#endif
/* header */
off = encode_short(port, off, header);
@ -682,6 +690,17 @@ int pd_analyze_rx(int port, uint32_t *payload)
/* Find the Start Of Packet sequence */
while (bit > 0) {
bit = pd_dequeue_bits(port, bit, 20, &val);
#if defined(CONFIG_USB_TYPEC_VPD) || defined(CONFIG_USB_TYPEC_CTVPD)
if (val == PD_SOP_PRIME) {
break;
} else if (val == PD_SOP) {
CPRINTF("SOP\n");
return PD_RX_ERR_UNSUPPORTED_SOP;
} else if (val == PD_SOP_PRIME_PRIME) {
CPRINTF("SOP''\n");
return PD_RX_ERR_UNSUPPORTED_SOP;
}
#else /* CONFIG_USB_TYPEC_VPD || CONFIG_USB_TYPEC_CTVPD */
#ifdef CONFIG_USB_PD_DECODE_SOP
if (val == PD_SOP || val == PD_SOP_PRIME ||
val == PD_SOP_PRIME_PRIME)
@ -696,7 +715,8 @@ int pd_analyze_rx(int port, uint32_t *payload)
CPRINTF("SOP''\n");
return PD_RX_ERR_UNSUPPORTED_SOP;
}
#endif
#endif /* CONFIG_USB_PD_DECODE_SOP */
#endif /* CONFIG_USB_TYPEC_VPD || CONFIG_USB_TYPEC_CTVPD */
}
if (bit < 0) {
#ifdef CONFIG_USB_PD_DECODE_SOP
@ -872,7 +892,11 @@ int tcpc_run(int port, int evt)
/* outgoing packet ? */
if ((evt & PD_EVENT_TX) && pd[port].rx_enabled) {
switch (pd[port].tx_type) {
#if defined(CONFIG_USB_TYPEC_VPD) || defined(CONFIG_USB_TYPEC_CTVPD)
case TCPC_TX_SOP_PRIME:
#else
case TCPC_TX_SOP:
#endif
res = send_validate_message(port,
pd[port].tx_head,
pd[port].tx_data);
@ -938,7 +962,7 @@ int tcpc_run(int port, int evt)
#endif
}
#ifndef CONFIG_USB_POWER_DELIVERY
#if !defined(CONFIG_USB_POWER_DELIVERY) && !defined(CONFIG_USB_SM_FRAMEWORK)
void pd_task(void *u)
{
int port = TASK_ID_TO_PD_PORT(task_get_current());

12
common/usb_pe_sm.c Normal file
View File

@ -0,0 +1,12 @@
/* Copyright 2019 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 "common.h"
/* Include USB PD Policy Engine State Machine */
#if defined(CONFIG_USB_TYPEC_VPD) || defined(CONFIG_USB_TYPEC_CTVPD)
#include "usb_pe_ctvpd_sm.h"
#else
#error "A USB PD Policy Engine State Machine must be defined."
#endif

2163
common/usb_prl_sm.c Normal file

File diff suppressed because it is too large Load Diff

166
common/usb_sm.c Normal file
View File

@ -0,0 +1,166 @@
/* Copyright 2019 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 "common.h"
#include "task.h"
#include "usb_pd.h"
#include "usb_sm.h"
#include "util.h"
#include "console.h"
void init_state(int port, struct sm_obj *obj, sm_state target)
{
#if (CONFIG_SM_NESTING_NUM > 0)
int i;
sm_state tmp_super[CONFIG_SM_NESTING_NUM];
#endif
obj->last_state = NULL;
obj->task_state = target;
#if (CONFIG_SM_NESTING_NUM > 0)
/* Prepare to execute all entry actions of the target's super states */
/*
* Get targets super state. This will be NULL if the target
* has no super state
*/
tmp_super[CONFIG_SM_NESTING_NUM - 1] =
(sm_state)(uintptr_t)target(port, SUPER_SIG);
/* Get all super states of the target */
for (i = CONFIG_SM_NESTING_NUM - 1; i > 0; i--) {
if (tmp_super[i] != NULL)
tmp_super[i - 1] =
(sm_state)(uintptr_t)tmp_super[i](port, SUPER_SIG);
else
tmp_super[i - 1] = NULL;
}
/* Execute all super state entry actions in forward order */
for (i = 0; i < CONFIG_SM_NESTING_NUM; i++)
if (tmp_super[i] != NULL)
tmp_super[i](port, ENTRY_SIG);
#endif
/* Now execute the target entry action */
target(port, ENTRY_SIG);
}
int set_state(int port, struct sm_obj *obj, sm_state target)
{
#if (CONFIG_SM_NESTING_NUM > 0)
int i;
int no_execute;
sm_state tmp_super[CONFIG_SM_NESTING_NUM];
sm_state target_super;
sm_state last_super;
sm_state super;
/* Execute all exit actions is reverse order */
/* Get target's super state */
target_super = (sm_state)(uintptr_t)target(port, SUPER_SIG);
tmp_super[0] = obj->task_state;
do {
/* Execute exit action */
tmp_super[0](port, EXIT_SIG);
/* Get super state */
tmp_super[0] =
(sm_state)(uintptr_t)tmp_super[0](port, SUPER_SIG);
/*
* No need to execute a super state's exit action that has
* shared ancestry with the target.
*/
super = target_super;
while (super != NULL) {
if (tmp_super[0] == super) {
tmp_super[0] = NULL;
break;
}
/* Get target state next super state if it exists */
super = (sm_state)(uintptr_t)super(port, SUPER_SIG);
}
} while (tmp_super[0] != NULL);
/* All done executing the exit actions */
#else
obj->task_state(port, EXIT_SIG);
#endif
/* update the state variables */
obj->last_state = obj->task_state;
obj->task_state = target;
#if (CONFIG_SM_NESTING_NUM > 0)
/* Prepare to execute all entry actions of the target's super states */
tmp_super[CONFIG_SM_NESTING_NUM - 1] =
(sm_state)(uintptr_t)target(port, SUPER_SIG);
/* Get all super states of the target */
for (i = CONFIG_SM_NESTING_NUM - 1; i > 0; i--) {
if (tmp_super[i] != NULL)
tmp_super[i - 1] =
(sm_state)(uintptr_t)tmp_super[i](port, SUPER_SIG);
else
tmp_super[i - 1] = NULL;
}
/* Get super state of last state */
last_super = (sm_state)(uintptr_t)obj->last_state(port, SUPER_SIG);
/* Execute all super state entry actions in forward order */
for (i = 0; i < CONFIG_SM_NESTING_NUM; i++) {
/* No super state */
if (tmp_super[i] == NULL)
continue;
/*
* We only want to execute the target state's super state entry
* action if it doesn't share a super state with the previous
* state.
*/
super = last_super;
no_execute = 0;
while (super != NULL) {
if (tmp_super[i] == super) {
no_execute = 1;
break;
}
/* Get last state's next super state if it exists */
super = (sm_state)(uintptr_t)super(port, SUPER_SIG);
}
/* Execute super state's entry */
if (!no_execute)
tmp_super[i](port, ENTRY_SIG);
}
#endif
/* Now execute the target entry action */
target(port, ENTRY_SIG);
return 0;
}
void exe_state(int port, struct sm_obj *obj, enum signal sig)
{
#if (CONFIG_SM_NESTING_NUM > 0)
sm_state state = obj->task_state;
do {
state = (sm_state)(uintptr_t)state(port, sig);
} while (state != NULL);
#else
obj->task_state(port, sig);
#endif
}

203
common/usb_tc_sm.c Normal file
View File

@ -0,0 +1,203 @@
/* Copyright 2019 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 "battery.h"
#include "battery_smart.h"
#include "board.h"
#include "charge_manager.h"
#include "charge_state.h"
#include "chipset.h"
#include "common.h"
#include "console.h"
#include "ec_commands.h"
#include "gpio.h"
#include "hooks.h"
#include "host_command.h"
#include "registers.h"
#include "system.h"
#include "task.h"
#include "timer.h"
#include "util.h"
#include "usb_charge.h"
#include "usb_mux.h"
#include "usb_pd.h"
#include "usb_pd_tcpm.h"
#include "usb_prl_sm.h"
#include "tcpm.h"
#include "usb_pe_sm.h"
#include "usb_prl_sm.h"
#include "usb_sm.h"
#include "usb_tc_sm.h"
#include "version.h"
#ifdef CONFIG_COMMON_RUNTIME
#define CPRINTF(format, args...) cprintf(CC_HOOK, format, ## args)
#define CPRINTS(format, args...) cprints(CC_HOOK, format, ## args)
#else /* CONFIG_COMMON_RUNTIME */
#define CPRINTF(format, args...)
#define CPRINTS(format, args...)
#endif
/* Private Function Prototypes */
static inline int cc_is_rp(int cc);
static inline enum pd_cc_polarity_type get_snk_polarity(int cc1, int cc2);
static int tc_restart_tcpc(int port);
static void set_polarity(int port, int polarity);
#ifdef CONFIG_COMMON_RUNTIME
static const char * const tc_state_names[] = {
"Disabled",
"Unattached.SNK",
"AttachWait.SNK",
"Attached.SNK",
#if !defined(CONFIG_USB_TYPEC_VPD)
"ErrorRecovery",
"Unattached.SRC",
"AttachWait.SRC",
"Attached.SRC",
#endif
#if !defined(CONFIG_USB_TYPEC_CTVPD) && !defined(CONFIG_USB_TYPEC_VPD)
"AudioAccessory",
"OrientedDebugAccessory.SRC",
"UnorientedDebugAccessory.SRC",
"DebugAccessory.SNK",
"Try.SRC",
"TryWait.SNK",
"CTUnattached.SNK",
"CTAttached.SNK",
#endif
#if defined(CONFIG_USB_TYPEC_CTVPD)
"CTTry.SNK",
"CTAttached.Unsupported",
"CTAttachWait.Unsupported",
"CTUnattached.Unsupported",
"CTUnattached.VPD",
"CTAttachWait.VPD",
"CTAttached.VPD",
"CTDisabled.VPD",
"Try.SNK",
"TryWait.SRC"
#endif
};
BUILD_ASSERT(ARRAY_SIZE(tc_state_names) == TC_STATE_COUNT);
#endif
/* Include USB Type-C State Machine */
#if defined(CONFIG_USB_TYPEC_CTVPD)
#include "usb_tc_ctvpd_sm.h"
#elif defined(CONFIG_USB_TYPEC_VPD)
#include "usb_tc_vpd_sm.h"
#else
#error "A USB Type-C State Machine must be defined."
#endif
/* Public Functions */
int tc_get_power_role(int port)
{
return tc[port].power_role;
}
int tc_get_data_role(int port)
{
return tc[port].data_role;
}
void tc_set_timeout(int port, uint64_t timeout)
{
tc[port].evt_timeout = timeout;
}
enum typec_state_id get_typec_state_id(int port)
{
return tc[port].state_id;
}
/* Private Functions */
/**
* 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_RP_DEF) || (cc == TYPEC_CC_VOLT_RP_1_5) ||
(cc == TYPEC_CC_VOLT_RP_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 enum pd_cc_polarity_type get_snk_polarity(int cc1, int cc2)
{
/* the following assumes:
* TYPEC_CC_VOLT_RP_3_0 > TYPEC_CC_VOLT_RP_1_5
* TYPEC_CC_VOLT_RP_1_5 > TYPEC_CC_VOLT_RP_DEF
* TYPEC_CC_VOLT_RP_DEF > TYPEC_CC_VOLT_OPEN
*/
return (cc2 > cc1) ? POLARITY_CC2 : POLARITY_CC1;
}
static int tc_restart_tcpc(int port)
{
return tcpm_init(port);
}
static void set_polarity(int port, int polarity)
{
tcpm_set_polarity(port, polarity);
#ifdef CONFIG_USBC_PPC_POLARITY
ppc_set_polarity(port, polarity);
#endif /* defined(CONFIG_USBC_PPC_POLARITY) */
}
void pd_task(void *u)
{
int port = TASK_ID_TO_PD_PORT(task_get_current());
tc_state_init(port);
while (1) {
/* wait for next event/packet or timeout expiration */
tc[port].evt = task_wait_event(tc[port].evt_timeout);
/* handle events that affect the state machine as a whole */
tc_event_check(port, tc[port].evt);
#ifdef CONFIG_USB_PD_TCPC
/*
* run port controller task to check CC and/or read incoming
* messages
*/
tcpc_run(port, tc[port].evt);
#endif
#ifdef CONFIG_USB_PE_SM
/* run policy engine state machine */
policy_engine(port, tc[port].evt, tc[port].pd_enable);
#endif /* CONFIG_USB_PE_SM */
#ifdef CONFIG_USB_PRL_SM
/* run protocol state machine */
protocol_layer(port, tc[port].evt, tc[port].pd_enable);
#endif /* CONFIG_USB_PRL_SM */
/* run state machine */
exe_state(port, TC_OBJ(port), RUN_SIG);
}
}

View File

@ -779,6 +779,33 @@
*/
#undef CONFIG_CHARGER_INPUT_CURRENT
/* Define to use Power Delivery State Machine Framework */
#undef CONFIG_USB_SM_FRAMEWORK
/*
* This is the maximum number of levels in the hierarchical
* state machine framework. Set to 0 for a flat state machine.
*/
#define CONFIG_SM_NESTING_NUM 3
/*
* Define to enable Type-C State Machine. Must be enabled
* with CONFIG_USB_SM_FRAMEWORK
*/
#define CONFIG_USB_TYPEC_SM
/*
* Define to enable Protocol Layer State Machine. Must be enabled
* with CONFIG_USB_SM_FRAMEWORK and CONFIG_USB_TYPEC_SM
*/
#define CONFIG_USB_PRL_SM
/*
* Define to enable Policy Engine State Machine. Must be enabled
* with CONFIG_USB_SM_FRAMEWORK and CONFIG_USB_TYPEC_SM
*/
#define CONFIG_USB_PE_SM
/*
* Board specific maximum input current limit, in mA.
*/
@ -3500,6 +3527,12 @@
/* Use DAC as reference for comparator at 850mV. */
#undef CONFIG_PD_USE_DAC_AS_REF
/* Type-C VCONN Powered Device */
#undef CONFIG_USB_TYPEC_VPD
/* Type-C Charge Through VCONN Powered Device */
#undef CONFIG_USB_TYPEC_CTVPD
/* USB Product ID. */
#undef CONFIG_USB_PID

23
include/usb_emsg.h Normal file
View File

@ -0,0 +1,23 @@
/* Copyright 2019 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 Extended message buffer */
#ifndef __CROS_EC_USB_EBUF_H
#define __CROS_EC_USB_EBUF_H
#define EXTENDED_BUFFER_SIZE 260
#define BUFFER_SIZE 28
struct extended_msg {
uint32_t header;
uint32_t len;
uint8_t buf[EXTENDED_BUFFER_SIZE];
};
/* Defined in usb_prl_sm.c */
extern struct extended_msg emsg[CONFIG_USB_PD_PORT_COUNT];
#endif /* __CROS_EC_USB_EBUF_H */

View File

@ -49,6 +49,7 @@ enum pd_rx_errors {
#define PD_EVENT_DEVICE_ACCESSED (1<<7)
#define PD_EVENT_POWER_STATE_CHANGE (1<<8) /* Chipset power state changed */
#define PD_EVENT_SEND_HARD_RESET (1<<9) /* Issue a Hard Reset. */
#define PD_EVENT_SM (1<<10) /* PD State machine event */
/* Ensure TCPC is out of low power mode before handling these events. */
#define PD_EXIT_LOW_POWER_EVENT_MASK \
@ -168,6 +169,7 @@ enum pd_rx_errors {
#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_TRY_CC_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 */
@ -181,6 +183,10 @@ enum pd_rx_errors {
#define PD_T_TRY_TIMEOUT (550*MSEC) /* between 550ms and 1100ms */
#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 */
#define PD_T_PD_DEBOUNCE (15*MSEC) /* between 10ms and 20ms */
#define PD_T_CHUNK_SENDER_RESPONSE (25*MSEC) /* 25ms */
#define PD_T_CHUNK_SENDER_REQUEST (25*MSEC) /* 25ms */
#define PD_T_SWAP_SOURCE_START (25*MSEC) /* Min of 20ms */
/* number of edges and time window to detect CC line is not idle */
#define PD_RX_TRANSITION_COUNT 3
@ -196,6 +202,11 @@ enum pd_rx_errors {
#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 */
/* CTVPD Timers ( USB Type-C ECN Table 4-27 ) */
#define PD_T_VPDDETACH (20*MSEC) /* max of 20*MSEC */
#define PD_T_VPDCTDD (4*MSEC) /* max of 4ms */
#define PD_T_VPDDISABLE (25*MSEC) /* min of 25ms */
/* function table for entered mode */
struct amode_fx {
int (*status)(int port, uint32_t *payload);
@ -391,6 +402,7 @@ struct pd_policy {
#define IDH_PTYPE_PCABLE 3
#define IDH_PTYPE_ACABLE 4
#define IDH_PTYPE_AMA 5
#define IDH_PTYPE_VPD 6
#define VDO_IDH(usbh, usbd, ptype, is_modal, vid) \
((usbh) << 31 | (usbd) << 30 | ((ptype) & 0x7) << 27 \
@ -490,6 +502,34 @@ struct pd_policy {
#define AMA_USBSS_U31_GEN2 2
#define AMA_USBSS_BBONLY 3
/*
* VPD VDO
* ---------
* <31:28> :: HW version
* <27:24> :: FW version
* <23:21> :: VDO version
* <20:17> :: SBZ
* <16:15> :: Maximum VBUS Voltage
* <14:13> :: SBZ
* <12:7> :: VBUS Impedance
* <6:1> :: Ground Impedance
* <0> :: Charge Through Support
*/
#define VDO_VPD(hw, fw, vbus, vbusz, gndz, cts) \
(((hw) & 0xf) << 28 | ((fw) & 0xf) << 24 \
| ((vbus) & 0x3) << 15 \
| ((vbusz) & 0x3f) << 7 \
| ((gndz) & 0x3f) << 1 | (cts))
#define VPD_MAX_VBUS_20V 0
#define VPD_MAX_VBUS_30V 1
#define VPD_MAX_VBUS_40V 2
#define VPD_MAX_VBUS_50V 3
#define VPD_VBUS_IMP(mo) ((mo + 1) >> 1)
#define VPD_GND_IMP(mo) (mo)
#define VPD_CTS_SUPPORTED 1
#define VPD_CTS_NOT_SUPPORTED 0
/*
* SVDM Discover SVIDs request -> response
*
@ -787,6 +827,9 @@ enum pd_states {
#define PD_BBRMFLG_DATA_ROLE BIT(2)
#define PD_BBRMFLG_VCONN_ROLE BIT(3)
/* Initial value for CC debounce variable */
#define PD_CC_UNSET -1
enum pd_cc_states {
PD_CC_NONE,
@ -912,14 +955,25 @@ enum pd_data_msg_type {
PD_DATA_VENDOR_DEF = 15,
};
/* CC Polarity type */
enum pd_cc_polarity_type {
POLARITY_CC1,
POLARITY_CC2
};
/* Protocol revision */
#define PD_REV10 0
#define PD_REV20 1
#define PD_REV30 2
enum pd_rev_type {
PD_REV10,
PD_REV20,
PD_REV30
};
/* Power role */
#define PD_ROLE_SINK 0
#define PD_ROLE_SOURCE 1
/* Cable plug */
#define PD_PLUG_DFP_UFP 0
#define PD_PLUG_CABLE_VPD 1
/* Data role */
#define PD_ROLE_UFP 0
#define PD_ROLE_DFP 1
@ -998,6 +1052,9 @@ enum pd_data_msg_type {
#define PD_EXT_HEADER_REQ_CHUNK(header) (((header) >> 10) & 1)
#define PD_EXT_HEADER_DATA_SIZE(header) ((header) & 0x1ff)
/* Used to get extended header from the first 32-bit word of the message */
#define GET_EXT_HEADER(msg) (msg & 0xffff)
/* K-codes for special symbols */
#define PD_SYNC1 0x18
#define PD_SYNC2 0x11

View File

@ -16,6 +16,9 @@
/* Time to wait for TCPC to complete transmit */
#define PD_T_TCPC_TX_TIMEOUT (100*MSEC)
/* Number of valid Transmit Types */
#define NUM_XMIT_TYPES (TCPC_TX_SOP_DEBUG_PRIME_PRIME + 1)
/* Detected resistor values of port partner */
enum tcpc_cc_voltage_status {
TYPEC_CC_VOLT_OPEN = 0,
@ -32,6 +35,7 @@ enum tcpc_cc_pull {
TYPEC_CC_RP = 1,
TYPEC_CC_RD = 2,
TYPEC_CC_OPEN = 3,
TYPEC_CC_RA_RD = 4, /* Powered cable with Sink */
};
/* Pull-up values we apply as a SRC to advertise different current limits */
@ -54,6 +58,7 @@ enum tcpm_transmit_type {
};
enum tcpc_transmit_complete {
TCPC_TX_UNSET = -1,
TCPC_TX_COMPLETE_SUCCESS = 0,
TCPC_TX_COMPLETE_DISCARDED = 1,
TCPC_TX_COMPLETE_FAILED = 2,

239
include/usb_pe_ctvpd_sm.h Normal file
View File

@ -0,0 +1,239 @@
/* Copyright 2019 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 "common.h"
#include "console.h"
#include "task.h"
#include "util.h"
#include "usb_pd.h"
#include "usb_pd_tcpm.h"
#include "usb_pe_sm.h"
#include "usb_prl_sm.h"
#include "usb_tc_sm.h"
#include "usb_emsg.h"
#include "usb_sm.h"
/* USB Policy Engine Charge-Through VCONN Powered Device module */
#ifndef __CROS_EC_USB_PE_CTVPD_H
#define __CROS_EC_USB_PE_CTVPD_H
/* Policy Engine Flags */
#define PE_FLAGS_MSG_RECEIVED (1 << 0)
enum l_state {
PE_INIT,
PE_RUN,
PE_PAUSED
};
static enum l_state local_state = PE_INIT;
/*
* PE_OBJ is a convenience macro to access struct sm_obj, which
* must be the first member of struct policy_engine.
*/
#define PE_OBJ(port) (SM_OBJ(pe[port]))
/**
* This is the PE Port object that contains information needed to
* implement a VCONN and Charge-Through VCONN Powered Device.
*/
static struct policy_engine {
/*
* struct sm_obj must be first. This is the state machine
* object that keeps track of the current and last state
* of the state machine.
*/
struct sm_obj obj;
/* port flags, see PE_FLAGS_* */
uint32_t flags;
} pe[CONFIG_USB_PD_PORT_COUNT];
static unsigned int pe_request(int port, enum signal sig);
static unsigned int pe_request_entry(int port);
static unsigned int pe_request_run(int port);
static unsigned int do_nothing_exit(int port);
static unsigned int get_super_state(int port);
static const state_sig pe_request_sig[] = {
pe_request_entry,
pe_request_run,
do_nothing_exit,
get_super_state
};
void pe_init(int port)
{
pe[port].flags = 0;
init_state(port, PE_OBJ(port), pe_request);
}
void policy_engine(int port, int evt, int en)
{
switch (local_state) {
case PE_INIT:
pe_init(port);
local_state = PE_RUN;
/* fall through */
case PE_RUN:
if (!en) {
local_state = PE_PAUSED;
break;
}
exe_state(port, PE_OBJ(port), RUN_SIG);
break;
case PE_PAUSED:
if (en)
local_state = PE_INIT;
break;
}
}
void pe_pass_up_message(int port)
{
pe[port].flags |= PE_FLAGS_MSG_RECEIVED;
task_set_event(PD_PORT_TO_TASK_ID(port), PD_EVENT_SM, 0);
}
void pe_hard_reset_sent(int port)
{
/* Do nothing */
}
void pe_got_hard_reset(int port)
{
/* Do nothing */
}
void pe_report_error(int port, enum pe_error e)
{
/* Do nothing */
}
void pe_got_soft_reset(int port)
{
/* Do nothing */
}
void pe_message_sent(int port)
{
/* Do nothing */
}
static unsigned int pe_request(int port, enum signal sig)
{
int ret;
ret = (*pe_request_sig[sig])(port);
return SUPER(ret, sig, 0);
}
static unsigned int pe_request_entry(int port)
{
return 0;
}
static unsigned int pe_request_run(int port)
{
uint32_t *payload = (uint32_t *)emsg[port].buf;
uint32_t header = emsg[port].header;
uint32_t vdo = payload[0];
if (pe[port].flags & PE_FLAGS_MSG_RECEIVED) {
pe[port].flags &= ~PE_FLAGS_MSG_RECEIVED;
/*
* Only support Structured VDM Discovery
* Identity message
*/
if (PD_HEADER_TYPE(header) != PD_DATA_VENDOR_DEF)
return 0;
if (PD_HEADER_CNT(header) == 0)
return 0;
if (!PD_VDO_SVDM(vdo))
return 0;
if (PD_VDO_CMD(vdo) != CMD_DISCOVER_IDENT)
return 0;
#ifdef CONFIG_USB_TYPEC_CTVPD
/*
* We have a valid DISCOVER IDENTITY message.
* Attempt to reset support timer
*/
tc_reset_support_timer(port);
#endif
/* Prepare to send ACK */
/* VDM Header */
payload[0] = VDO(
USB_VID_GOOGLE,
1, /* Structured VDM */
VDO_SVDM_VERS(1) |
VDO_CMDT(CMDT_RSP_ACK) |
CMD_DISCOVER_IDENT);
/* ID Header VDO */
payload[1] = VDO_IDH(
0, /* Not a USB Host */
1, /* Capable of being enumerated as USB Device */
IDH_PTYPE_VPD,
0, /* Modal Operation Not Supported */
USB_VID_GOOGLE);
/* Cert State VDO */
payload[2] = 0;
/* Product VDO */
payload[3] = VDO_PRODUCT(
CONFIG_USB_PID,
USB_BCD_DEVICE);
/* VPD VDO */
payload[4] = VDO_VPD(
VPD_HW_VERSION,
VPD_FW_VERSION,
VPD_MAX_VBUS_20V,
VPD_VBUS_IMP(VPD_VBUS_IMPEDANCE),
VPD_GND_IMP(VPD_GND_IMPEDANCE),
#ifdef CONFIG_USB_TYPEC_CTVPD
VPD_CTS_SUPPORTED
#else
VPD_CTS_NOT_SUPPORTED
#endif
);
/* 20 bytes, 5 data objects */
emsg[port].len = 20;
/* Set to highest revision supported by both ports. */
prl_set_rev(port, (PD_HEADER_REV(header) > PD_REV30) ?
PD_REV30 : PD_HEADER_REV(header));
/* Send the ACK */
prl_send_data_msg(port, TCPC_TX_SOP_PRIME,
PD_DATA_VENDOR_DEF);
}
return 0;
}
static unsigned int do_nothing_exit(int port)
{
return 0;
}
static unsigned int get_super_state(int port)
{
return RUN_SUPER;
}
#endif /* __CROS_EC_USB_PE_CTVPD_H */

79
include/usb_pe_sm.h Normal file
View File

@ -0,0 +1,79 @@
/* Copyright 2019 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 Policy Engine module */
#ifndef __CROS_EC_USB_PE_H
#define __CROS_EC_USB_PE_H
enum pe_error {
ERR_RCH_CHUNKED,
ERR_RCH_MSG_REC,
ERR_TCH_CHUNKED,
ERR_TCH_XMIT,
};
/**
* Initialize the Policy Engine State Machine
*
* @param port USB-C port number
*/
void pe_init(int port);
/**
* Runs the Policy Engine State Machine
*
* @param port USB-C port number
* @param evt system event, ie: PD_EVENT_RX
* @param en 0 to disable the machine, 1 to enable the machine
*/
void policy_engine(int port, int evt, int en);
/**
* Informs the Policy Engine that a message was successfully sent
*
* @param port USB-C port number
*/
void pe_message_sent(int port);
/**
* Informs the Policy Engine of an error.
*
* @param port USB-C port number
* @parm e error
*/
void pe_report_error(int port, enum pe_error e);
/**
* Informs the Policy Engine that a message has been received
*
* @param port USB-C port number
* @parm e error
*/
void pe_pass_up_message(int port);
/**
* Informs the Policy Engine that a hard reset was received.
*
* @param port USB-C port number
*/
void pe_got_hard_reset(int port);
/**
* Informs the Policy Engine that a soft reset was received.
*
* @param port USB-C port number
*/
void pe_got_soft_reset(int port);
/**
* Informs the Policy Engine that a hard reset was sent.
*
* @param port USB-C port number
*/
void pe_hard_reset_sent(int port);
#endif /* __CROS_EC_USB_PE_H */

213
include/usb_prl_sm.h Normal file
View File

@ -0,0 +1,213 @@
/* Copyright 2019 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 Protocol Layer module */
#ifndef __CROS_EC_USB_PRL_H
#define __CROS_EC_USB_PRL_H
#include "common.h"
#include "usb_pd.h"
#include "usb_pd_tcpm.h"
enum prl_tx_state_id {
PRL_TX_PHY_LAYER_RESET,
PRL_TX_WAIT_FOR_MESSAGE_REQUEST,
PRL_TX_LAYER_RESET_FOR_TRANSMIT,
PRL_TX_CONSTRUCT_MESSAGE,
PRL_TX_WAIT_FOR_PHY_RESPONSE,
PRL_TX_MATCH_MESSAGE_ID,
PRL_TX_MESSAGE_SENT,
PRL_TX_CHECK_RETRY_COUNTER,
PRL_TX_TRANSMISSION_ERROR,
PRL_TX_DISCARD_MESSAGE,
PRL_TX_SRC_SINK_TX,
PRL_TX_SRC_SOURCE_TX,
PRL_TX_SRC_PENDING,
PRL_TX_SNK_START_OF_AMS,
PRL_TX_SNK_PENDING,
};
enum prl_hr_state_id {
PRL_HR_WAIT_FOR_REQUEST,
PRL_HR_RESET_LAYER,
PRL_HR_INDICATE_HARD_RESET,
PRL_HR_WAIT_FOR_PHY_HARD_RESET_COMPLETE,
PRL_HR_PHY_HARD_RESET_REQUESTED,
PRL_HR_WAIT_FOR_PE_HARD_RESET_COMPLETE,
PRL_HR_PE_HARD_RESET_COMPLETE,
};
enum rch_state_id {
RCH_WAIT_FOR_MESSAGE_FROM_PROTOCOL_LAYER,
RCH_PASS_UP_MESSAGE,
RCH_PROCESSING_EXTENDED_MESSAGE,
RCH_REQUESTING_CHUNK,
RCH_WAITING_CHUNK,
RCH_REPORT_ERROR,
};
enum tch_state_id {
TCH_WAIT_FOR_MESSAGE_REQUEST_FROM_PE,
TCH_PASS_DOWN_MESSAGE,
TCH_WAIT_FOR_TRANSMISSION_COMPLETE,
TCH_MESSAGE_SENT,
TCH_PREPARE_TO_SEND_CHUNKED_MESSAGE,
TCH_CONSTRUCT_CHUNKED_MESSAGE,
TCH_SENDING_CHUNKED_MESSAGE,
TCH_WAIT_CHUNK_REQUEST,
TCH_MESSAGE_RECEIVED,
TCH_REPORT_ERROR,
};
/*
* Number of times the Protocol Layer will try to transmit a message
* before giving up and signaling an error
*/
#define N_RETRY_COUNT 2
/**
* Initialize the Protocol Layer State Machine
*
* @param port USB-C port number
*/
void prl_init(int port);
/**
* Resets the Protocol Layer State Machine
*
* @param port USB-C port number
*/
void prl_reset(int port);
/**
* Get Chunked Rx State Machine state id
*
* @param port USB-C port number
* @return id
*/
enum rch_state_id get_rch_state_id(int port);
/**
* Get Chunked Tx State Machine state id
*
* @param port USB-C port number
* @return id
*/
enum tch_state_id get_tch_state_id(int port);
/**
* Get Message Transmission State Machine state id
*
* @param port USB-C port number
* @return id
*/
enum prl_tx_state_id get_prl_tx_state_id(int port);
/**
* Get Hard Reset State Machine state id
*
* @param port USB-C port number
* @return id
*/
enum prl_hr_state_id get_prl_hr_state_id(int port);
/**
* Returns the state of the PRL state machine
* @return SM_INIT for initializing
* SM_RUN for running
* SM_PAUSED for paused
*/
enum sm_local_state prl_get_local_state(int port);
/**
* Runs the Protocol Layer State Machine
*
* @param port USB-C port number
* @param evt system event, ie: PD_EVENT_RX
* @param en 0 to disable the machine, 1 to enable the machine
*/
void protocol_layer(int port, int evt, int en);
/**
* Set the PD revision
*
* @param port USB-C port number
* @param rev revision
*/
void prl_set_rev(int port, enum pd_rev_type rev);
/**
* Get the PD revision
*
* @param port USB-C port number
* @return pd rev
*/
enum pd_rev_type prl_get_rev(int port);
/**
* Sends a PD control message
*
* @param port USB-C port number
* @param type Transmit type
* @param msg Control message type
* @return 0 on EC_SUCCESS, else EC_ERROR_BUSY
*/
void prl_send_ctrl_msg(int port, enum tcpm_transmit_type type,
enum pd_ctrl_msg_type msg);
/**
* Sends a PD data message
*
* @param port USB-C port number
* @param type Transmit type
* @param msg Data message type
* @return 0 on EC_SUCCESS, else EC_ERROR_BUSY
*/
void prl_send_data_msg(int port, enum tcpm_transmit_type type,
enum pd_data_msg_type msg);
/**
* Sends a PD extended data message
*
* @param port USB-C port number
* @param type Transmit type
* @param msg Extended data message type
* @return 0 on EC_SUCCESS, else EC_ERROR_BUSY
*/
void prl_send_ext_data_msg(int port, enum tcpm_transmit_type type,
enum pd_ext_msg_type msg);
/**
* Informs the Protocol Layer that a hard reset has completed
*
* @param port USB-C port number
*/
void prl_hard_reset_complete(int port);
/**
* Policy Engine calls this function to execute a hard reset.
*
* @param port USB-C port number
*/
void prl_execute_hard_reset(int port);
/**
* Informs the Protocol Layer to start an Atomic Message Sequence
*
* @param port USB-C port number
*/
void prl_start_ams(int port);
/**
* Informs the Protocol Layer to end an Atomic Message Sequence
*
* @param port USB-C port number
*/
void prl_end_ams(int port);
#endif /* __CROS_EC_USB_PRL_H */

67
include/usb_sm.h Normal file
View File

@ -0,0 +1,67 @@
/* Copyright 2019 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 State Machine Framework */
#ifndef __CROS_EC_USB_SM_H
#define __CROS_EC_USB_SM_H
#define SM_OBJ(smo) ((struct sm_obj *)&smo)
#define SUPER(r, sig, s) ((((r) == 0) || ((sig) == ENTRY_SIG) || \
((sig) == EXIT_SIG)) ? 0 : ((uintptr_t)(s)))
#define RUN_SUPER 1
/* Local state machine states */
enum sm_local_state {
SM_INIT,
SM_RUN,
SM_PAUSED
};
/* State Machine signals */
enum signal {
ENTRY_SIG = 0,
RUN_SIG,
EXIT_SIG,
SUPER_SIG,
};
typedef unsigned int (*state_sig)(int port);
typedef unsigned int (*sm_state)(int port, enum signal sig);
struct sm_obj {
sm_state task_state;
sm_state last_state;
};
/**
* Initialize a State Machine
*
* @param port USB-C port number
* @param obj State machine object
* @param target Initial state of state machine
*/
void init_state(int port, struct sm_obj *obj, sm_state target);
/**
* Changes a state machines state
*
* @param port USB-C port number
* @param obj State machine object
* @param target State to transition to
* @return 0
*/
int set_state(int port, struct sm_obj *obj, sm_state target);
/**
* Executes a state machine
*
* @param port USB-C port number
* @param obj State machine object
* @param sig State machine signal
*/
void exe_state(int port, struct sm_obj *obj, enum signal sig);
#endif /* __CROS_EC_USB_SM_H */

2039
include/usb_tc_ctvpd_sm.h Normal file

File diff suppressed because it is too large Load Diff

91
include/usb_tc_sm.h Normal file
View File

@ -0,0 +1,91 @@
/* Copyright 2019 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 Type-C module */
#ifndef __CROS_EC_USB_TC_H
#define __CROS_EC_USB_TC_H
enum typec_state_id {
DISABLED,
UNATTACHED_SNK,
ATTACH_WAIT_SNK,
ATTACHED_SNK,
#if !defined(CONFIG_USB_TYPEC_VPD)
ERROR_RECOVERY,
UNATTACHED_SRC,
ATTACH_WAIT_SRC,
ATTACHED_SRC,
#endif
#if !defined(CONFIG_USB_TYPEC_CTVPD) && !defined(CONFIG_USB_TYPEC_VPD)
AUDIO_ACCESSORY,
ORIENTED_DEBUG_ACCESSORY_SRC,
UNORIENTED_DEBUG_ACCESSORY_SRC,
DEBUG_ACCESSORY_SNK,
TRY_SRC,
TRY_WAIT_SNK,
CTUNATTACHED_SNK,
CTATTACHED_SNK,
#endif
#if defined(CONFIG_USB_TYPEC_CTVPD)
CTTRY_SNK,
CTATTACHED_UNSUPPORTED,
CTATTACH_WAIT_UNSUPPORTED,
CTUNATTACHED_UNSUPPORTED,
CTUNATTACHED_VPD,
CTATTACH_WAIT_VPD,
CTATTACHED_VPD,
CTDISABLED_VPD,
TRY_SNK,
TRY_WAIT_SRC,
#endif
/* Number of states. Not an actual state. */
TC_STATE_COUNT,
};
/**
* Get the id of the current Type-C state
*
* @param port USB-C port number
*/
enum typec_state_id get_typec_state_id(int port);
/**
* Get current data role
*
* @param port USB-C port number
* @return 0 for ufp, 1 for dfp, 2 for disconnected
*/
int tc_get_data_role(int port);
/**
* Get current power role
*
* @param port USB-C port number
* @return 0 for sink, 1 for source or vpd
*/
int tc_get_power_role(int port);
/**
* Set loop timeout value
*
* @param port USB-C port number
* @timeout time in ms
*/
void tc_set_timeout(int port, uint64_t timeout);
#ifdef CONFIG_USB_TYPEC_CTVPD
/**
* Resets the charge-through support timer. This can be
* called many times but the support timer will only
* reset once, while in the Attached.SNK state.
*
* @param port USB-C port number
*/
void tc_reset_support_timer(int port);
#endif /* CONFIG_USB_TYPEC_CTVPD */
#endif /* __CROS_EC_USB_TC_H */

486
include/usb_tc_vpd_sm.h Normal file
View File

@ -0,0 +1,486 @@
/* Copyright 2019 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 "vpd_api.h"
/* USB Type-C VCONN Powered Device module */
#ifndef __CROS_EC_USB_TC_VPD_H
#define __CROS_EC_USB_TC_VPD_H
/* Type-C Layer Flags */
#define TC_FLAGS_VCONN_ON BIT(0)
#undef PD_DEFAULT_STATE
/* Port default state at startup */
#define PD_DEFAULT_STATE(port) tc_state_unattached_snk
/*
* TC_OBJ is a convenience macro to access struct sm_obj, which
* must be the first member of struct type_c.
*/
#define TC_OBJ(port) (SM_OBJ(tc[port]))
/**
* This is the Type-C Port object that contains information needed to
* implement a VCONN Powered Device.
*/
static struct type_c {
/*
* struct sm_obj must be first. This is the state machine
* object that keeps track of the current and last state
* of the state machine.
*/
struct sm_obj obj;
/* state id */
enum typec_state_id state_id;
/* current port power role (VPD, SOURCE or SINK) */
uint8_t power_role;
/* current port data role (DFP or UFP) */
uint8_t data_role;
/* bool: enable power delivery state machines */
uint8_t pd_enable;
/* event timeout */
uint64_t evt_timeout;
/* state machine event */
int evt;
/* port flags, see TC_FLAGS_* */
uint32_t flags;
/* Time a port shall wait before it can determine it is attached */
uint64_t cc_debounce;
/* VPD host port cc state */
enum pd_cc_states host_cc_state;
uint8_t ct_cc;
} tc[CONFIG_USB_PD_PORT_COUNT];
/* Type-C states */
static unsigned int tc_state_disabled(int port, enum signal sig);
static unsigned int tc_state_disabled_entry(int port);
static unsigned int tc_state_disabled_run(int port);
static unsigned int tc_state_disabled_exit(int port);
static unsigned int tc_state_unattached_snk(int port, enum signal sig);
static unsigned int tc_state_unattached_snk_entry(int port);
static unsigned int tc_state_unattached_snk_run(int port);
static unsigned int tc_state_unattached_snk_exit(int port);
static unsigned int tc_state_attach_wait_snk(int port, enum signal sig);
static unsigned int tc_state_attach_wait_snk_entry(int port);
static unsigned int tc_state_attach_wait_snk_run(int port);
static unsigned int tc_state_attach_wait_snk_exit(int port);
static unsigned int tc_state_attached_snk(int port, enum signal sig);
static unsigned int tc_state_attached_snk_entry(int port);
static unsigned int tc_state_attached_snk_run(int port);
static unsigned int tc_state_attached_snk_exit(int port);
/* Super States */
static unsigned int tc_state_host_rard(int port, enum signal sig);
static unsigned int tc_state_host_rard_entry(int port);
static unsigned int tc_state_host_rard_run(int port);
static unsigned int tc_state_host_rard_exit(int port);
static unsigned int tc_state_host_open(int port, enum signal sig);
static unsigned int tc_state_host_open_entry(int port);
static unsigned int tc_state_host_open_run(int port);
static unsigned int tc_state_host_open_exit(int port);
static unsigned int tc_state_vbus_cc_iso(int port, enum signal sig);
static unsigned int tc_state_vbus_cc_iso_entry(int port);
static unsigned int tc_state_vbus_cc_iso_run(int port);
static unsigned int tc_state_vbus_cc_iso_exit(int port);
static unsigned int get_super_state(int port);
static const state_sig tc_state_disabled_sig[] = {
tc_state_disabled_entry,
tc_state_disabled_run,
tc_state_disabled_exit,
get_super_state
};
static const state_sig tc_state_unattached_snk_sig[] = {
tc_state_unattached_snk_entry,
tc_state_unattached_snk_run,
tc_state_unattached_snk_exit,
get_super_state
};
static const state_sig tc_state_attach_wait_snk_sig[] = {
tc_state_attach_wait_snk_entry,
tc_state_attach_wait_snk_run,
tc_state_attach_wait_snk_exit,
get_super_state
};
static const state_sig tc_state_attached_snk_sig[] = {
tc_state_attached_snk_entry,
tc_state_attached_snk_run,
tc_state_attached_snk_exit,
get_super_state
};
static const state_sig tc_state_host_rard_sig[] = {
tc_state_host_rard_entry,
tc_state_host_rard_run,
tc_state_host_rard_exit,
get_super_state
};
static const state_sig tc_state_host_open_sig[] = {
tc_state_host_open_entry,
tc_state_host_open_run,
tc_state_host_open_exit,
get_super_state
};
static const state_sig tc_state_vbus_cc_iso_sig[] = {
tc_state_vbus_cc_iso_entry,
tc_state_vbus_cc_iso_run,
tc_state_vbus_cc_iso_exit,
get_super_state
};
static void tc_state_init(int port)
{
int res = 0;
sm_state this_state;
res = tc_restart_tcpc(port);
CPRINTS("TCPC p%d init %s", port, res ? "failed" : "ready");
this_state = res ? tc_state_disabled : PD_DEFAULT_STATE(port);
/* Disable TCPC RX until connection is established */
tcpm_set_rx_enable(port, 0);
init_state(port, TC_OBJ(port), this_state);
/* Disable pd state machines */
tc[port].pd_enable = 0;
tc[port].evt_timeout = 10*MSEC;
tc[port].power_role = PD_PLUG_CABLE_VPD;
tc[port].data_role = 0; /* Reserved for VPD */
tc[port].flags = 0;
}
static void tc_event_check(int port, int evt)
{
/* Do Nothing */
}
/**
* Disabled
*
* Super State Entries:
* Enable mcu communication
* Remove the terminations from Host CC
*/
static unsigned int tc_state_disabled(int port, enum signal sig)
{
int ret = 0;
ret = (*tc_state_disabled_sig[sig])(port);
return SUPER(ret, sig, tc_state_host_open);
}
static unsigned int tc_state_disabled_entry(int port)
{
tc[port].state_id = DISABLED;
CPRINTS("C%d: %s", port, tc_state_names[tc[port].state_id]);
return 0;
}
static unsigned int tc_state_disabled_run(int port)
{
task_wait_event(-1);
return RUN_SUPER;
}
static unsigned int tc_state_disabled_exit(int port)
{
#ifndef CONFIG_USB_PD_TCPC
if (tc_restart_tcpc(port) != 0) {
CPRINTS("TCPC p%d restart failed!", port);
return 0;
}
#endif
CPRINTS("TCPC p%d resumed!", port);
set_state(port, TC_OBJ(port), tc_state_unattached_snk);
return 0;
}
/**
* Unattached.SNK
*
* Super State Entry:
* Enable mcu communication
* Place Ra on VCONN and Rd on Host CC
*/
static unsigned int tc_state_unattached_snk(int port, enum signal sig)
{
int ret;
ret = (*tc_state_unattached_snk_sig[sig])(port);
return SUPER(ret, sig, tc_state_host_rard);
}
static unsigned int tc_state_unattached_snk_entry(int port)
{
tc[port].state_id = UNATTACHED_SNK;
CPRINTS("C%d: %s", port, tc_state_names[tc[port].state_id]);
return 0;
}
static unsigned int tc_state_unattached_snk_run(int port)
{
int host_cc;
/* Check Host CC for connection */
vpd_host_get_cc(&host_cc);
/*
* Transition to AttachWait.SNK when a Source connection is
* detected, as indicated by the SNK.Rp state on its Host-side
* ports CC pin.
*/
if (cc_is_rp(host_cc)) {
set_state(port, TC_OBJ(port), tc_state_attach_wait_snk);
return 0;
}
return RUN_SUPER;
}
static unsigned int tc_state_unattached_snk_exit(int port)
{
return 0;
}
/**
* AttachedWait.SNK
*
* Super State Entry:
* Enable mcu communication
* Place Ra on VCONN and Rd on Host CC
*/
static unsigned int tc_state_attach_wait_snk(int port, enum signal sig)
{
int ret = 0;
ret = (*tc_state_attach_wait_snk_sig[sig])(port);
return SUPER(ret, sig, tc_state_host_rard);
}
static unsigned int tc_state_attach_wait_snk_entry(int port)
{
tc[port].state_id = ATTACH_WAIT_SNK;
CPRINTS("C%d: %s", port, tc_state_names[tc[port].state_id]);
tc[port].host_cc_state = PD_CC_UNSET;
return 0;
}
static unsigned int tc_state_attach_wait_snk_run(int port)
{
int host_new_cc_state;
int host_cc;
/* Check Host CC for connection */
vpd_host_get_cc(&host_cc);
if (cc_is_rp(host_cc))
host_new_cc_state = PD_CC_DFP_ATTACHED;
else
host_new_cc_state = PD_CC_NONE;
/* Debounce the Host CC state */
if (tc[port].host_cc_state != host_new_cc_state) {
tc[port].host_cc_state = host_new_cc_state;
if (host_new_cc_state == PD_CC_DFP_ATTACHED)
tc[port].cc_debounce = get_time().val +
PD_T_CC_DEBOUNCE;
else
tc[port].cc_debounce = get_time().val +
PD_T_PD_DEBOUNCE;
return 0;
}
/* Wait for Host CC debounce */
if (get_time().val < tc[port].cc_debounce)
return 0;
/*
* A VCONN-Powered USB Device shall transition to
* Attached.SNK after the state of the Host-side ports CC pin is
* SNK.Rp for at least tCCDebounce and either host-side VCONN or
* VBUS is detected.
*
* Transition to Unattached.SNK when the state of both the CC1 and
* CC2 pins is SNK.Open for at least tPDDebounce.
*/
if (tc[port].host_cc_state == PD_CC_DFP_ATTACHED &&
(vpd_is_vconn_present() || vpd_is_host_vbus_present()))
set_state(port, TC_OBJ(port), tc_state_attached_snk);
else if (tc[port].host_cc_state == PD_CC_NONE)
set_state(port, TC_OBJ(port), tc_state_unattached_snk);
return 0;
}
static unsigned int tc_state_attach_wait_snk_exit(int port)
{
return 0;
}
/**
* Attached.SNK
*/
static unsigned int tc_state_attached_snk(int port, enum signal sig)
{
int ret;
ret = (*tc_state_attached_snk_sig[sig])(port);
return SUPER(ret, sig, 0);
}
static unsigned int tc_state_attached_snk_entry(int port)
{
tc[port].state_id = ATTACHED_SNK;
CPRINTS("C%d: %s", port, tc_state_names[tc[port].state_id]);
/* Enable PD */
tc[port].pd_enable = 1;
set_polarity(port, 0);
return 0;
}
static unsigned int tc_state_attached_snk_run(int port)
{
/* Has host vbus and vconn been removed */
if (!vpd_is_host_vbus_present() && !vpd_is_vconn_present()) {
set_state(port, TC_OBJ(port), tc_state_unattached_snk);
return 0;
}
if (vpd_is_vconn_present()) {
if (!(tc[port].flags & TC_FLAGS_VCONN_ON)) {
/* VCONN detected. Remove RA */
vpd_host_set_pull(TYPEC_CC_RD, 0);
tc[port].flags |= TC_FLAGS_VCONN_ON;
}
}
return 0;
}
static unsigned int tc_state_attached_snk_exit(int port)
{
/* Disable PD */
tc[port].pd_enable = 0;
tc[port].flags &= ~TC_FLAGS_VCONN_ON;
return 0;
}
/**
* Super State HOST_RARD
*/
static unsigned int tc_state_host_rard(int port, enum signal sig)
{
int ret;
ret = (*tc_state_host_rard_sig[sig])(port);
return SUPER(ret, sig, tc_state_vbus_cc_iso);
}
static unsigned int tc_state_host_rard_entry(int port)
{
/* Place Ra on VCONN and Rd on Host CC */
vpd_host_set_pull(TYPEC_CC_RA_RD, 0);
return 0;
}
static unsigned int tc_state_host_rard_run(int port)
{
return RUN_SUPER;
}
static unsigned int tc_state_host_rard_exit(int port)
{
return 0;
}
/**
* Super State HOST_OPEN
*/
static unsigned int tc_state_host_open(int port, enum signal sig)
{
int ret;
ret = (*tc_state_host_open_sig[sig])(port);
return SUPER(ret, sig, tc_state_vbus_cc_iso);
}
static unsigned int tc_state_host_open_entry(int port)
{
/* Remove the terminations from Host CC */
vpd_host_set_pull(TYPEC_CC_OPEN, 0);
return 0;
}
static unsigned int tc_state_host_open_run(int port)
{
return RUN_SUPER;
}
static unsigned int tc_state_host_open_exit(int port)
{
return 0;
}
/**
* Super State VBUS_CC_ISO
*/
static unsigned int tc_state_vbus_cc_iso(int port, enum signal sig)
{
int ret;
ret = (*tc_state_vbus_cc_iso_sig[sig])(port);
return SUPER(ret, sig, 0);
}
static unsigned int tc_state_vbus_cc_iso_entry(int port)
{
/* Enable mcu communication and cc */
vpd_mcu_cc_en(1);
return 0;
}
static unsigned int tc_state_vbus_cc_iso_run(int port)
{
return 0;
}
static unsigned int tc_state_vbus_cc_iso_exit(int port)
{
return 0;
}
static unsigned int get_super_state(int port)
{
return RUN_SUPER;
}
#endif /*__CROS_EC_USB_TC_VPD_H */

View File

@ -65,6 +65,13 @@ test-list-host += timer_dos
test-list-host += usb_pd
test-list-host += usb_pd_giveback
test-list-host += usb_pd_rev30
test-list-host += usb_sm_framework_h3
test-list-host += usb_sm_framework_h2
test-list-host += usb_sm_framework_h1
test-list-host += usb_sm_framework_h0
test-list-host += usb_typec_vpd
test-list-host += usb_typec_ctvpd
test-list-host += usb_prl
test-list-host += utils
test-list-host += utils_str
test-list-host += vboot
@ -127,6 +134,13 @@ timer_dos-y=timer_dos.o
usb_pd-y=usb_pd.o
usb_pd_giveback-y=usb_pd.o
usb_pd_rev30-y=usb_pd.o
usb_sm_framework_h3-y=usb_sm_framework_h3.o
usb_sm_framework_h2-y=usb_sm_framework_h3.o
usb_sm_framework_h1-y=usb_sm_framework_h3.o
usb_sm_framework_h0-y=usb_sm_framework_h3.o
usb_typec_vpd-y=usb_typec_ctvpd.o vpd_api.o
usb_typec_ctvpd-y=usb_typec_ctvpd.o vpd_api.o
usb_prl-y=usb_prl.o
utils-y=utils.o
utils_str-y=utils_str.o
vboot-y=vboot.o

View File

@ -217,6 +217,93 @@ int ncp15wb_calculate_temp(uint16_t adc);
#define CONFIG_ALS_LIGHTBAR_DIMMING 0
#endif
#if defined(TEST_USB_SM_FRAMEWORK_H3)
#define CONFIG_USB_PD_PORT_COUNT 1
#undef CONFIG_USB_PRL_SM
#undef CONFIG_USB_PE_SM
#undef CONFIG_USB_TYPEC_SM
#undef CONFIG_SM_NESTING_NUM
#define CONFIG_SM_NESTING_NUM 3
#define CONFIG_USB_SM_FRAMEWORK
#endif
#if defined(TEST_USB_SM_FRAMEWORK_H2)
#define CONFIG_USB_PD_PORT_COUNT 1
#undef CONFIG_USB_PRL_SM
#undef CONFIG_USB_PE_SM
#undef CONFIG_USB_TYPEC_SM
#undef CONFIG_SM_NESTING_NUM
#define CONFIG_SM_NESTING_NUM 2
#define CONFIG_USB_SM_FRAMEWORK
#endif
#if defined(TEST_USB_SM_FRAMEWORK_H1)
#define CONFIG_USB_PD_PORT_COUNT 1
#undef CONFIG_USB_PRL_SM
#undef CONFIG_USB_PE_SM
#undef CONFIG_USB_TYPEC_SM
#undef CONFIG_SM_NESTING_NUM
#define CONFIG_SM_NESTING_NUM 1
#define CONFIG_USB_SM_FRAMEWORK
#endif
#if defined(TEST_USB_SM_FRAMEWORK_H0)
#define CONFIG_USB_PD_PORT_COUNT 1
#undef CONFIG_USB_PRL_SM
#undef CONFIG_USB_PE_SM
#undef CONFIG_USB_TYPEC_SM
#undef CONFIG_SM_NESTING_NUM
#define CONFIG_SM_NESTING_NUM 0
#define CONFIG_USB_SM_FRAMEWORK
#endif
#if defined(TEST_USB_PRL)
#undef CONFIG_SM_NESTING_NUM
#define CONFIG_SM_NESTING_NUM 3
#define CONFIG_USB_PD_PORT_COUNT 2
#define CONFIG_USB_SM_FRAMEWORK
#undef CONFIG_USB_PE_SM
#undef CONFIG_USB_TYPEC_SM
#define CONFIG_USB_PRL_SM
#define CONFIG_USB_PD_TCPC
#define CONFIG_USB_PD_TCPM_STUB
#define CONFIG_USB_POWER_DELIVERY
#define CONFIG_SHA256
#define CONFIG_SW_CRC
#endif
#if defined(TEST_USB_TYPEC_VPD) || defined(TEST_USB_TYPEC_CTVPD)
#if defined(TEST_USB_TYPEC_VPD)
#define CONFIG_USB_TYPEC_VPD
#else
#define CONFIG_USB_TYPEC_CTVPD
#endif
#undef CONFIG_SM_NESTING_NUM
#define CONFIG_SM_NESTING_NUM 3
#define CONFIG_USB_PID 0x5036
#define VPD_HW_VERSION 0x0001
#define VPD_FW_VERSION 0x0001
#define USB_BCD_DEVICE 0
/* Vbus impedance in milliohms */
#define VPD_VBUS_IMPEDANCE 65
/* GND impedance in milliohms */
#define VPD_GND_IMPEDANCE 33
#define CONFIG_USB_PD_PORT_COUNT 1
#define CONFIG_USB_SM_FRAMEWORK
#define CONFIG_USB_PE_SM
#define CONFIG_USB_PRL_SM
#define CONFIG_USB_TYPEC_SM
#define CONFIG_USB_PD_TCPC
#define CONFIG_USB_PD_TCPM_STUB
#define CONFIG_USB_POWER_DELIVERY
#define CONFIG_SHA256
#define CONFIG_SW_CRC
#endif /* TEST_USB_TYPEC_VPD or TEST_USB_TYPEC_CTVPD */
#if defined(TEST_USB_PD) || defined(TEST_USB_PD_GIVEBACK) || \
defined(TEST_USB_PD_REV30)
#define CONFIG_USB_POWER_DELIVERY

View File

@ -13,6 +13,7 @@ void pd_test_rx_set_preamble(int port, int has_preamble);
void pd_test_rx_msg_append_bits(int port, uint32_t bits, int nb);
void pd_test_rx_msg_append_kcode(int port, uint8_t kcode);
void pd_test_rx_msg_append_sop(int port);
void pd_test_rx_msg_append_sop_prime(int port);
void pd_test_rx_msg_append_eop(int port);
void pd_test_rx_msg_append_last_edge(int port);
void pd_test_rx_msg_append_4b(int port, uint8_t val);
@ -23,6 +24,7 @@ void pd_simulate_rx(int port);
/* Verify Tx message */
int pd_test_tx_msg_verify_kcode(int port, uint8_t kcode);
int pd_test_tx_msg_verify_sop(int port);
int pd_test_tx_msg_verify_sop_prime(int port);
int pd_test_tx_msg_verify_eop(int port);
int pd_test_tx_msg_verify_4b5b(int port, uint8_t b4);
int pd_test_tx_msg_verify_short(int port, uint16_t val);

1306
test/usb_prl.c Normal file

File diff suppressed because it is too large Load Diff

19
test/usb_prl.tasklist Normal file
View File

@ -0,0 +1,19 @@
/* Copyright (c) 2019 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.
*/
/**
* List of enabled tasks in the priority order
*
* The first one has the lowest priority.
*
* For each task, use the macro TASK_TEST(n, r, d, s) where :
* 'n' in the name of the task
* 'r' in the main routine of the task
* 'd' in an opaque parameter passed to the routine at startup
* 's' is the stack size in bytes; must be a multiple of 8
*/
#define CONFIG_TEST_TASK_LIST \
TASK_TEST(PD_C0, pd_task, NULL, LARGER_TASK_STACK_SIZE) \
TASK_TEST(PD_C1, pd_task, NULL, LARGER_TASK_STACK_SIZE)

View File

@ -0,0 +1 @@
usb_sm_framework_h3.tasklist

View File

@ -0,0 +1 @@
usb_sm_framework_h3.tasklist

View File

@ -0,0 +1 @@
usb_sm_framework_h3.tasklist

1219
test/usb_sm_framework_h3.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,18 @@
/* Copyright (c) 2019 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.
*/
/**
* List of enabled tasks in the priority order
*
* The first one has the lowest priority.
*
* For each task, use the macro TASK_TEST(n, r, d, s) where :
* 'n' in the name of the task
* 'r' in the main routine of the task
* 'd' in an opaque parameter passed to the routine at startup
* 's' is the stack size in bytes; must be a multiple of 8
*/
#define CONFIG_TEST_TASK_LIST \
TASK_TEST(TEST, test_task, NULL, LARGER_TASK_STACK_SIZE)

1488
test/usb_typec_ctvpd.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,18 @@
/* Copyright (c) 2019 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.
*/
/**
* List of enabled tasks in the priority order
*
* The first one has the lowest priority.
*
* For each task, use the macro TASK_TEST(n, r, d, s) where :
* 'n' in the name of the task
* 'r' in the main routine of the task
* 'd' in an opaque parameter passed to the routine at startup
* 's' is the stack size in bytes; must be a multiple of 8
*/
#define CONFIG_TEST_TASK_LIST \
TASK_TEST(PD_C0, pd_task, NULL, LARGER_TASK_STACK_SIZE)

1
test/usb_typec_vpd.tasklist Symbolic link
View File

@ -0,0 +1 @@
usb_typec_ctvpd.tasklist

586
test/vpd_api.c Normal file
View File

@ -0,0 +1,586 @@
/* Copyright 2019 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 "registers.h"
#include "vpd_api.h"
#include "driver/tcpm/tcpm.h"
#include "console.h"
/*
* Polarity based on 'DFP Perspective' (see table USB Type-C Cable and Connector
* Specification)
*
* CC1 CC2 STATE POSITION
* ----------------------------------------
* open open NC N/A
* Rd open UFP attached 1
* open Rd UFP attached 2
* open Ra pwr cable no UFP N/A
* Ra open pwr cable no UFP N/A
* Rd Ra pwr cable & UFP 1
* Ra Rd pwr cable & UFP 2
* Rd Rd dbg accessory N/A
* Ra Ra audio accessory N/A
*
* Note, V(Rd) > V(Ra)
*/
#ifndef PD_SRC_RD_THRESHOLD
#define PD_SRC_RD_THRESHOLD PD_SRC_DEF_RD_THRESH_MV
#endif
#ifndef PD_SRC_VNC
#define PD_SRC_VNC PD_SRC_DEF_VNC_MV
#endif
#ifndef CC_RA
#define CC_RA(port, cc, sel) (cc < pd_src_rd_threshold[ct_cc_rp_value])
#endif
#define CC_RD(cc) ((cc >= PD_SRC_RD_THRESHOLD) && (cc < PD_SRC_VNC))
#ifndef CC_NC
#define CC_NC(port, cc, sel) (cc >= PD_SRC_VNC)
#endif
/*
* Polarity based on 'UFP Perspective'.
*
* CC1 CC2 STATE POSITION
* ----------------------------------------
* open open NC N/A
* Rp open DFP attached 1
* open Rp DFP attached 2
* Rp Rp Accessory attached N/A
*/
#ifndef PD_SNK_VA
#define PD_SNK_VA PD_SNK_VA_MV
#endif
#define CC_RP(cc) (cc >= PD_SNK_VA)
/* Mock Board State */
static enum vpd_pwr mock_vconn_pwr_sel_odl;
static enum vpd_gpo mock_cc1_cc2_rd_l;
static enum vpd_gpo mock_cc_db_en_od;
static enum vpd_gpo mock_cc_rpusb_odh;
static enum vpd_cc mock_ct_cl_sel;
static int mock_mcu_cc_en;
static enum vpd_billboard mock_present_billboard;
static int mock_red_led;
static int mock_green_led;
static int mock_vbus_pass_en;
static int mock_read_host_vbus;
static int mock_read_ct_vbus;
static int mock_read_vconn;
static struct mock_pin mock_cc2_rpusb_odh;
static struct mock_pin mock_cc2_rp3a0_rd_l;
static struct mock_pin mock_cc1_rpusb_odh;
static struct mock_pin mock_cc1_rp3a0_rd_l;
static struct mock_pin mock_cc_vpdmcu;
static struct mock_pin mock_cc_rp3a0_rd_l;
/* Charge-Through pull up/down enabled */
static int ct_cc_pull;
/* Charge-Through pull up value */
static int ct_cc_rp_value;
/* Charge-Through pull up/down enabled */
static int host_cc_pull;
/* Charge-Through pull up value */
static int host_cc_rp_value;
/* Voltage thresholds for Ra attach in normal SRC mode */
static int pd_src_rd_threshold[TYPEC_RP_RESERVED] = {
PD_SRC_DEF_RD_THRESH_MV,
PD_SRC_1_5_RD_THRESH_MV,
PD_SRC_3_0_RD_THRESH_MV,
};
enum vpd_pwr mock_get_vconn_pwr_source(void)
{
return mock_vconn_pwr_sel_odl;
}
int mock_get_ct_cc1_rpusb(void)
{
return mock_cc1_rpusb_odh.value;
}
int mock_get_ct_cc2_rpusb(void)
{
return mock_cc2_rpusb_odh.value;
}
enum vpd_gpo mock_get_ct_rd(void)
{
return mock_cc1_cc2_rd_l;
}
enum vpd_gpo mock_get_cc_rpusb_odh(void)
{
return mock_cc_rpusb_odh;
}
enum vpd_gpo mock_get_cc_db_en_od(void)
{
return mock_cc_db_en_od;
}
enum vpd_cc moch_get_ct_cl_sel(void)
{
return mock_ct_cl_sel;
}
int mock_get_mcu_cc_en(void)
{
return mock_mcu_cc_en;
}
enum vpd_billboard mock_get_present_billboard(void)
{
return mock_present_billboard;
}
int mock_get_red_led(void)
{
return mock_red_led;
}
int mock_get_green_led(void)
{
return mock_green_led;
}
int mock_get_vbus_pass_en(void)
{
return mock_vbus_pass_en;
}
void mock_set_host_cc_sink_voltage(int v)
{
mock_cc_vpdmcu.value = v;
}
void mock_set_host_cc_source_voltage(int v)
{
mock_cc_vpdmcu.value2 = v;
}
void mock_set_host_vbus(int v)
{
mock_read_host_vbus = v;
}
void mock_set_ct_vbus(int v)
{
mock_read_ct_vbus = v;
}
void mock_set_vconn(int v)
{
mock_read_vconn = v;
}
int mock_get_cfg_cc2_rpusb_odh(void)
{
return mock_cc2_rpusb_odh.cfg;
}
int mock_set_cc2_rpusb_odh(int v)
{
if (mock_cc2_rpusb_odh.cfg == PIN_ADC) {
mock_cc2_rpusb_odh.value = v;
return 1;
}
return 0;
}
int mock_get_cfg_cc2_rp3a0_rd_l(void)
{
return mock_cc2_rp3a0_rd_l.cfg;
}
int mock_set_cc2_rp3a0_rd_l(int v)
{
if (mock_cc2_rp3a0_rd_l.cfg == PIN_ADC) {
mock_cc2_rp3a0_rd_l.value = v;
return 1;
}
return 0;
}
int mock_get_cc1_rpusb_odh(void)
{
return mock_cc1_rpusb_odh.cfg;
}
int mock_set_cc1_rpusb_odh(int v)
{
if (mock_cc1_rpusb_odh.cfg == PIN_ADC) {
mock_cc1_rpusb_odh.value = v;
return 1;
}
return 0;
}
int mock_get_cfg_cc_vpdmcu(void)
{
return mock_cc_vpdmcu.cfg;
}
enum vpd_pin mock_get_cfg_cc_rp3a0_rd_l(void)
{
return mock_cc_rp3a0_rd_l.cfg;
}
int mock_get_cc_rp3a0_rd_l(void)
{
return mock_cc_rp3a0_rd_l.value;
}
int mock_get_cfg_cc1_rp3a0_rd_l(void)
{
return mock_cc1_rp3a0_rd_l.cfg;
}
int mock_set_cc1_rp3a0_rd_l(int v)
{
if (mock_cc1_rp3a0_rd_l.cfg == PIN_ADC) {
mock_cc1_rp3a0_rd_l.value = v;
return 1;
}
return 0;
}
/* Convert CC voltage to CC status */
static int vpd_cc_voltage_to_status(int cc_volt, int cc_pull)
{
/* If we have a pull-up, then we are source, check for Rd. */
if (cc_pull == TYPEC_CC_RP) {
if (CC_NC(0, cc_volt, 0))
return TYPEC_CC_VOLT_OPEN;
else if (CC_RA(0, cc_volt, 0))
return TYPEC_CC_VOLT_RA;
else
return TYPEC_CC_VOLT_RD;
/* If we have a pull-down, then we are sink, check for Rp. */
} else if (cc_pull == TYPEC_CC_RD || cc_pull == TYPEC_CC_RA_RD) {
if (cc_volt >= TYPE_C_SRC_3000_THRESHOLD)
return TYPEC_CC_VOLT_RP_3_0;
else if (cc_volt >= TYPE_C_SRC_1500_THRESHOLD)
return TYPEC_CC_VOLT_RP_1_5;
else if (CC_RP(cc_volt))
return TYPEC_CC_VOLT_RP_DEF;
else
return TYPEC_CC_VOLT_OPEN;
} else {
/* If we are open, then always return 0 */
return 0;
}
}
void vpd_ct_set_pull(int pull, int rp_value)
{
ct_cc_pull = pull;
switch (pull) {
case TYPEC_CC_RP:
ct_cc_rp_value = rp_value;
vpd_cc1_cc2_db_en_l(GPO_HIGH);
switch (rp_value) {
case TYPEC_RP_USB:
vpd_config_cc1_rp3a0_rd_l(PIN_ADC, 0);
vpd_config_cc2_rp3a0_rd_l(PIN_ADC, 0);
vpd_config_cc1_rpusb_odh(PIN_GPO, 1);
vpd_config_cc2_rpusb_odh(PIN_GPO, 1);
break;
case TYPEC_RP_3A0:
vpd_config_cc1_rpusb_odh(PIN_ADC, 0);
vpd_config_cc2_rpusb_odh(PIN_ADC, 0);
vpd_config_cc1_rp3a0_rd_l(PIN_GPO, 1);
vpd_config_cc2_rp3a0_rd_l(PIN_GPO, 1);
break;
}
break;
case TYPEC_CC_RD:
vpd_config_cc1_rpusb_odh(PIN_ADC, 0);
vpd_config_cc2_rpusb_odh(PIN_ADC, 0);
vpd_config_cc1_rp3a0_rd_l(PIN_ADC, 0);
vpd_config_cc2_rp3a0_rd_l(PIN_ADC, 0);
vpd_cc1_cc2_db_en_l(GPO_LOW);
break;
case TYPEC_CC_OPEN:
vpd_cc1_cc2_db_en_l(GPO_HIGH);
vpd_config_cc1_rpusb_odh(PIN_ADC, 0);
vpd_config_cc2_rpusb_odh(PIN_ADC, 0);
vpd_config_cc1_rp3a0_rd_l(PIN_ADC, 0);
vpd_config_cc2_rp3a0_rd_l(PIN_ADC, 0);
break;
}
}
void vpd_ct_get_cc(int *cc1, int *cc2)
{
int cc1_v;
int cc2_v;
switch (ct_cc_pull) {
case TYPEC_CC_RP:
switch (ct_cc_rp_value) {
case TYPEC_RP_USB:
cc1_v = mock_cc1_rp3a0_rd_l.value;
cc2_v = mock_cc2_rp3a0_rd_l.value;
break;
case TYPEC_RP_3A0:
cc1_v = mock_cc1_rpusb_odh.value;
cc2_v = mock_cc2_rpusb_odh.value;
break;
}
if (!cc1_v && !cc2_v) {
cc1_v = PD_SRC_VNC;
cc2_v = PD_SRC_VNC;
}
break;
case TYPEC_CC_RD:
cc1_v = mock_cc1_rpusb_odh.value;
cc2_v = mock_cc2_rpusb_odh.value;
break;
case TYPEC_CC_OPEN:
*cc1 = 0;
*cc2 = 0;
return;
}
*cc1 = vpd_cc_voltage_to_status(cc1_v, ct_cc_pull);
*cc2 = vpd_cc_voltage_to_status(cc2_v, ct_cc_pull);
}
void vpd_host_set_pull(int pull, int rp_value)
{
host_cc_pull = pull;
switch (pull) {
case TYPEC_CC_RP:
vpd_cc_db_en_od(GPO_LOW);
host_cc_rp_value = rp_value;
switch (rp_value) {
case TYPEC_RP_USB:
vpd_config_cc_rp3a0_rd_l(PIN_CMP, 0);
vpd_cc_rpusb_odh(GPO_HIGH);
break;
case TYPEC_RP_3A0:
vpd_cc_rpusb_odh(GPO_HZ);
vpd_config_cc_rp3a0_rd_l(PIN_GPO, 1);
break;
}
break;
case TYPEC_CC_RD:
vpd_cc_rpusb_odh(GPO_HZ);
vpd_cc_db_en_od(GPO_LOW);
vpd_config_cc_rp3a0_rd_l(PIN_GPO, 0);
break;
case TYPEC_CC_RA_RD:
vpd_cc_rpusb_odh(GPO_HZ);
vpd_config_cc_rp3a0_rd_l(PIN_GPO, 0);
/*
* RA is connected to VCONN
* RD is connected to CC
*/
vpd_cc_db_en_od(GPO_HZ);
break;
case TYPEC_CC_OPEN:
vpd_cc_rpusb_odh(GPO_HZ);
vpd_config_cc_rp3a0_rd_l(PIN_CMP, 0);
vpd_cc_db_en_od(GPO_LOW);
/*
* Do nothing. CC is open on entry to this function
*/
break;
}
}
void vpd_host_get_cc(int *cc)
{
int v;
if (host_cc_pull == TYPEC_CC_OPEN) {
*cc = 0;
return;
} else if (host_cc_pull == TYPEC_CC_RP) {
v = mock_cc_vpdmcu.value;
} else {
v = mock_cc_vpdmcu.value2;
}
*cc = vpd_cc_voltage_to_status(v, host_cc_pull);
}
void vpd_rx_enable(int en)
{
if (en) {
mock_ct_cl_sel = 0;
mock_mcu_cc_en = 1;
}
tcpm_set_polarity(0, 0);
tcpm_set_rx_enable(0, en);
}
/*
* PA1: Configure as ADC, CMP, or GPO
*/
void vpd_config_cc_vpdmcu(enum vpd_pin cfg, int en)
{
mock_cc_vpdmcu.cfg = cfg;
if (cfg == PIN_GPO)
mock_cc_vpdmcu.value = en ? 1 : 0;
}
/*
* PA2: Configure as COMP2_INM6 or GPO
*/
void vpd_config_cc_rp3a0_rd_l(enum vpd_pin cfg, int en)
{
mock_cc_rp3a0_rd_l.cfg = cfg;
if (cfg == PIN_GPO)
mock_cc_rp3a0_rd_l.value = en ? 1 : 0;
}
/*
* PA4: Configure as ADC, CMP, or GPO
*/
void vpd_config_cc1_rp3a0_rd_l(enum vpd_pin cfg, int en)
{
mock_cc1_rp3a0_rd_l.cfg = cfg;
if (cfg == PIN_GPO)
mock_cc1_rp3a0_rd_l.value = en ? 1 : 0;
}
/*
* PA5: Configure as ADC, COMP, or GPO
*/
void vpd_config_cc2_rp3a0_rd_l(enum vpd_pin cfg, int en)
{
mock_cc2_rp3a0_rd_l.cfg = cfg;
if (cfg == PIN_GPO)
mock_cc2_rp3a0_rd_l.value = en ? 1 : 0;
}
/*
* PB0: Configure as ADC or GPO
*/
void vpd_config_cc1_rpusb_odh(enum vpd_pin cfg, int en)
{
mock_cc1_rpusb_odh.cfg = cfg;
if (cfg == PIN_GPO)
mock_cc1_rpusb_odh.value = en ? 1 : 0;
}
/*
* PB1: Configure as ADC or GPO
*/
void vpd_config_cc2_rpusb_odh(enum vpd_pin cfg, int en)
{
mock_cc2_rpusb_odh.cfg = cfg;
if (cfg == PIN_GPO)
mock_cc2_rpusb_odh.value = en ? 1 : 0;
}
int vpd_read_host_vbus(void)
{
return mock_read_host_vbus;
}
int vpd_read_ct_vbus(void)
{
return mock_read_ct_vbus;
}
int vpd_read_vconn(void)
{
return mock_read_vconn;
}
int vpd_is_host_vbus_present(void)
{
return (vpd_read_host_vbus() >= PD_SNK_VA);
}
int vpd_is_ct_vbus_present(void)
{
return (vpd_read_ct_vbus() >= PD_SNK_VA);
}
int vpd_is_vconn_present(void)
{
return (vpd_read_vconn() >= PD_SNK_VA);
}
int vpd_read_rdconnect_ref(void)
{
return 200; /* 200 mV */
}
void vpd_red_led(int on)
{
mock_red_led = on ? 0 : 1;
}
void vpd_green_led(int on)
{
mock_green_led = on ? 0 : 1;
}
void vpd_vbus_pass_en(int en)
{
mock_vbus_pass_en = en ? 1 : 0;
}
void vpd_present_billboard(enum vpd_billboard bb)
{
mock_present_billboard = bb;
}
void vpd_mcu_cc_en(int en)
{
mock_mcu_cc_en = en ? 1 : 0;
}
void vpd_ct_cc_sel(enum vpd_cc sel)
{
mock_ct_cl_sel = sel;
}
/* Set as GPO High, GPO Low, or High-Z */
void vpd_cc_db_en_od(enum vpd_gpo val)
{
mock_cc_db_en_od = val;
}
void vpd_cc_rpusb_odh(enum vpd_gpo val)
{
mock_cc_rpusb_odh = val;
}
void vpd_cc1_cc2_db_en_l(enum vpd_gpo val)
{
mock_cc1_cc2_rd_l = val;
}
void vpd_vconn_pwr_sel_odl(enum vpd_pwr en)
{
mock_vconn_pwr_sel_odl = en;
}

333
test/vpd_api.h Normal file
View File

@ -0,0 +1,333 @@
/* Copyright 2019 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.
*/
/* Vconn Power Device API module */
#ifndef __CROS_EC_VPD_API_H
#define __CROS_EC_VPD_API_H
#include "adc.h"
#include "gpio.h"
#include "usb_pd.h"
/*
* Type C power source charge current limits are identified by their cc
* voltage (set by selecting the proper Rd resistor). Any voltage below
* TYPE_C_SRC_DEFAULT_THRESHOLD will not be identified as a type C charger.
*/
#define TYPE_C_SRC_DEFAULT_THRESHOLD 200 /* mV */
#define TYPE_C_SRC_1500_THRESHOLD 660 /* mV */
#define TYPE_C_SRC_3000_THRESHOLD 1230 /* mV */
enum vpd_pin {
PIN_ADC,
PIN_CMP,
PIN_GPO
};
enum vpd_gpo {
GPO_HZ,
GPO_HIGH,
GPO_LOW
};
enum vpd_pwr {
PWR_VCONN,
PWR_VBUS,
};
enum vpd_cc {
CT_OPEN,
CT_CC1,
CT_CC2
};
enum vpd_billboard {
BB_NONE,
BB_SRC,
BB_SNK
};
struct mock_pin {
enum vpd_pin cfg;
int value;
int value2;
};
enum vpd_pwr mock_get_vconn_pwr_source(void);
enum vpd_gpo mock_get_ct_rd(void);
enum vpd_gpo mock_get_cc_rp1a5_odh(void);
enum vpd_gpo mock_get_cc_rpusb_odh(void);
enum vpd_gpo mock_get_cc_db_en_od(void);
enum vpd_cc moch_get_ct_cl_sel(void);
int mock_get_mcu_cc_en(void);
enum vpd_billboard mock_get_present_billboard(void);
int mock_get_red_led(void);
int mock_get_green_led(void);
int mock_get_vbus_pass_en(void);
int mock_set_cc_vpdmcu(int v);
void mock_set_host_vbus(int v);
void mock_set_ct_vbus(int v);
void mock_set_vconn(int v);
int mock_get_cfg_cc2_rpusb_odh(void);
int mock_set_cc2_rpusb_odh(int v);
int mock_get_cfg_cc2_rp3a0_rd_l(void);
int mock_set_cc2_rp3a0_rd_l(int v);
int mock_get_cfg_cc1_rpusb_odh(void);
int mock_set_cc1_rpusb_odh(int v);
int mock_get_cfg_cc_vpdmcu(void);
int mock_get_cc_vpdmcu(int v);
enum vpd_pin mock_get_cfg_cc_rp3a0_rd_l(void);
int mock_get_cc_rp3a0_rd_l(void);
int mock_get_cfg_cc1_rp3a0_rd_l(void);
int mock_set_cc1_rp3a0_rd_l(int v);
void mock_set_host_cc_sink_voltage(int v);
void mock_set_host_cc_source_voltage(int v);
int mock_get_ct_cc1_rpusb(void);
int mock_get_ct_cc2_rpusb(void);
/**
* Set Charge-Through Rp or Rd on CC lines
*
* @param pull Either TYPEC_CC_RP or TYPEC_CC_RD
* @param rp_value When pull is RP, set this to
* TYPEC_RP_USB or TYPEC_RP_1A5. Ignored
* for TYPEC_CC_RD
*/
void vpd_ct_set_pull(int pull, int rp_value);
/**
* Get the status of the Charge-Through CC lines
*
* @param cc1 Either TYPEC_CC_VOLT_OPEN,
* TYPEC_CC_VOLT_RA,
* TYPEC_CC_VOLT_RD,
* any other value is considered RP
* @param cc2 Either TYPEC_CC_VOLT_OPEN,
* TYPEC_CC_VOLT_RA,
* TYPEC_CC_VOLT_RD,
* any other value is considered RP
*/
void vpd_ct_get_cc(int *cc1, int *cc2);
/**
* Set Host Rp or Rd on CC lines
*
* @param pull Either TYPEC_CC_RP or TYPEC_CC_RD
* @param rp_value When pull is RP, set this to
* TYPEC_RP_USB or TYPEC_RP_1A5. Ignored
* for TYPEC_CC_RD
*/
void vpd_host_set_pull(int pull, int rp_value);
/**
* Get the status of the Host CC line
*
* @param cc Either TYPEC_CC_VOLT_SNK_DEF, TYPEC_CC_VOLT_SNK_1_5,
* TYPEC_CC_VOLT_SNK_3_0, or TYPEC_CC_RD
*/
void vpd_host_get_cc(int *cc);
/**
* Set RX Enable flag
*
* @param en 1 for enable, 0 for disable
*/
void vpd_rx_enable(int en);
/**
* Configure the cc_vpdmcu pin as ADC, CMP, or GPO
*
* @param cfg PIN_ADC, PIN_CMP, or PIN_GPO
* @param en When cfg is PIN_GPO, 1 sets pin high
* and 0 sets pin low. Else ignored
*/
void vpd_config_cc_vpdmcu(enum vpd_pin cfg, int en);
/**
* Configure the cc_rp3a0_rd_l pin as ADC, CMP, or GPO
*
* @param cfg PIN_ADC, PIN_CMP, or PIN_GPO
* @param en When cfg is PIN_GPO, 1 sets pin high
* and 0 sets pin low. Else ignored
*/
void vpd_config_cc_rp3a0_rd_l(enum vpd_pin cfg, int en);
/**
* Configure the cc1_rp3a0_rd_l pin as ADC, CMP, or GPO
*
* @param cfg PIN_ADC, PIN_CMP, or PIN_GPO
* @param en When cfg is PIN_GPO, 1 sets pin high
* and 0 sets pin low. Else ignored
*/
void vpd_config_cc1_rp3a0_rd_l(enum vpd_pin cfg, int en);
/**
* Configure the cc2_rp3a0_rd_l pin as ADC, CMP, or GPO
*
* @param cfg PIN_ADC, PIN_CMP, or PIN_GPO
* @param en When cfg is PIN_GPO, 1 sets pin high
* and 0 sets pin low. Else ignored
*/
void vpd_config_cc2_rp3a0_rd_l(enum vpd_pin cfg, int en);
/**
* Configure the cc1_rpusb_odh pin as ADC, CMP, or GPO
*
* @param cfg PIN_ADC, PIN_CMP, or PIN_GPO
* @param en When cfg is PIN_GPO, 1 sets pin high
* and 0 sets pin low. Else ignored
*/
void vpd_config_cc1_rpusb_odh(enum vpd_pin cfg, int en);
/**
* Configure the cc2_rpusb_odh pin as ADC, CMP, or GPO
*
* @param cfg PIN_ADC, PIN_CMP, or PIN_GPO
* @param en When cfg is PIN_GPO, 1 sets pin high
* and 0 sets pin low. Else ignored
*/
void vpd_config_cc2_rpusb_odh(enum vpd_pin cfg, int en);
/**
* Configure the cc_db_en_od pin to High-Impedance, low, or high
*
* @param val GPO_HZ, GPO_HIGH, GPO_LOW
*/
void vpd_cc_db_en_od(enum vpd_gpo val);
/**
* Configure the cc_rpusb_odh pin to High-Impedance, low, or high
*
* @param val GPO_HZ, GPO_HIGH, GPO_LOW
*/
void vpd_cc_rpusb_odh(enum vpd_gpo val);
/**
* Configure the cc_rp1a5_odh pin to High-Impedance, low, or high
*
* @param val GPO_HZ, GPO_HIGH, GPO_LOW
*/
void vpd_cc_rp1a5_odh(enum vpd_gpo val);
/**
* Configure the cc1_cc2_db_en_l pin to High-Impedance, low, or high
*
* @param val GPO_HZ, GPO_HIGH, GPO_LOW
*/
void vpd_cc1_cc2_db_en_l(enum vpd_gpo val);
/**
* Get status of host vbus
*
* @return 1 if host vbus is present, else 0
*/
int vpd_is_host_vbus_present(void);
/**
* Get status of charge-through vbus
*
* @return 1 if charge-through vbus is present, else 0
*/
int vpd_is_ct_vbus_present(void);
/**
* Get status of vconn
*
* @return 1 if vconn is present, else 0
*/
int vpd_is_vconn_present(void);
/**
* Read Host VBUS voltage. Range from 22000mV to 3000mV
*
* @return vbus voltage
*/
int vpd_read_host_vbus(void);
/**
* Read Host CC voltage.
*
* @return cc voltage
*/
int vpd_read_cc_host(void);
/**
* Read voltage on cc_vpdmcu pin
*
* @return cc_vpdmcu voltage
*/
int vpd_read_cc_vpdmcu(void);
/**
* Read charge-through VBUS voltage. Range from 22000mV to 3000mV
*
* @return charge-through vbus voltage
*/
int vpd_read_ct_vbus(void);
/**
* Read VCONN Voltage. Range from 5500mV to 3000mV
*
* @return vconn voltage
*/
int vpd_read_vconn(void);
/**
* Turn ON/OFF Red LED. Should be off when performing power
* measurements.
*
* @param on 0 turns LED off, any other value turns it ON
*/
void vpd_red_led(int on);
/**
* Turn ON/OFF Green LED. Should be off when performing power
* measurements.
*
* @param on 0 turns LED off, any other value turns it ON
*/
void vpd_green_led(int on);
/**
* Connects/Disconnects the Host VBUS to the Charge-Through VBUS.
*
* @param en 0 disconnectes the VBUS, any other value connects VBUS.
*/
void vpd_vbus_pass_en(int en);
/**
* Preset Billboard device
*
* @param bb BB_NONE no billboard presented,
* BB_SRC source connected but not in charge-through
* BB_SNK sink connected
*/
void vpd_present_billboard(enum vpd_billboard bb);
/**
* Enables the MCU to host cc communication
*
* @param en 1 enabled, 0 disabled
*/
void vpd_mcu_cc_en(int en);
/**
* Selects which supply to power the VPD from
*
* @param en PWR_VCONN or PWR_VBUS
*/
void vpd_vconn_pwr_sel_odl(enum vpd_pwr en);
/**
* Controls if the Charge-Through's CC1, CC2, or neither is
* connected to Host CC
*
* @param sel CT_OPEN neither, CT_CC1 cc1, CT_CC2 cc2
*/
void vpd_ct_cc_sel(enum vpd_cc sel);
#endif /* __CROS_EC_VPD_API_H */