chrome-ec/test/vpd_api.c

587 lines
11 KiB
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.
*/
#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;
}