diff options
author | Sam Hurst <shurst@google.com> | 2017-03-15 10:36:06 -0700 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2017-05-03 23:17:46 -0700 |
commit | e13695c0175dcb7854de74ed7c69e6054b0481dc (patch) | |
tree | a66e832c8c080a99172e053b50fb0d9b6ad83427 /util | |
parent | 4444702e858a8fa3d51c948f509450e136a9482a (diff) | |
download | chrome-ec-e13695c0175dcb7854de74ed7c69e6054b0481dc.tar.gz |
pd: Support auto generation of USB Type-C VIF
Create an app to extract relevant information
from the EC code base that's used to create Vendor
Information Files (VIFs) needed for USB Type-C
compliance testing.
BUG=chromium:701852
BRANCH=none
TEST=make -j buildall
Compared generated VIFs to expected values
Change-Id: I600ca78b9fb5d2de78aa65a58264c6f79b36ea17
Reviewed-on: https://chromium-review.googlesource.com/455280
Commit-Ready: Sam Hurst <shurst@google.com>
Tested-by: Sam Hurst <shurst@google.com>
Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
Diffstat (limited to 'util')
-rw-r--r-- | util/build.mk | 15 | ||||
-rw-r--r-- | util/genvif.c | 547 |
2 files changed, 562 insertions, 0 deletions
diff --git a/util/build.mk b/util/build.mk index 89772f9746..a21fb29561 100644 --- a/util/build.mk +++ b/util/build.mk @@ -22,3 +22,18 @@ ec_sb_firmware_update-objs+=powerd_lock.o lbplay-objs=lbplay.o $(comm-objs) ec_parse_panicinfo-objs=ec_parse_panicinfo.o ec_panicinfo.o + +# USB type-C Vendor Information File generation +ifeq ($(CONFIG_USB_POWER_DELIVERY),y) +build-util-bin+=genvif +build-util-art+=$(BOARD)_vif.txt +$(out)/util/genvif: $(out)/util/usb_pd_policy.o board/$(BOARD)/board.h \ + include/usb_pd.h include/usb_pd_tcpm.h +$(out)/util/genvif: BUILD_LDFLAGS+=$(out)/util/usb_pd_policy.o -flto + +STANDALONE_FLAGS=-ffreestanding -fno-builtin -nostdinc -Ibuiltin/ -D"__keep= " +$(out)/util/usb_pd_policy.o: board/$(BOARD)/usb_pd_policy.c + $(BUILDCC) $(BUILD_CFLAGS) $(STANDALONE_FLAGS) \ + -MMD -MF $@.d -c $< -flto -o $@ +deps += $(out)/util/usb_pd_policy.o.d +endif # CONFIG_USB_POWER_DELIVERY diff --git a/util/genvif.c b/util/genvif.c new file mode 100644 index 0000000000..e9e7223019 --- /dev/null +++ b/util/genvif.c @@ -0,0 +1,547 @@ +/* Copyright 2017 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. + */ + +#define _GNU_SOURCE /* for asprintf */ + +#include <errno.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <stdlib.h> +#include <getopt.h> +#include <dirent.h> +#include <stdint.h> +#include <limits.h> + +#include "config.h" +#include "usb_pd.h" +#include "usb_pd_tcpm.h" +#include "charge_manager.h" + +#define PD_REV_2_0 1 +#define PD_REV_3_0 2 + +#define VIF_SPEC "Revision 1.11, Version 1.0" +#define VENDOR_NAME "Google" +#define PD_SPEC_REV PD_REV_2_0 + +enum dtype {SNK = 0, SRC = 3, DRP = 4}; + +const uint32_t vdo_idh __attribute__((weak)) = 0; + +const uint32_t *src_pdo; +uint32_t src_pdo_cnt; + +char *yes_no(int val) +{ + return val ? "YES" : "NO"; +} + +static void init_src_pdos(void) +{ +#ifdef CONFIG_USB_PD_DYNAMIC_SRC_CAP + src_pdo_cnt = charge_manager_get_source_pdo(&src_pdo); +#else + src_pdo_cnt = pd_src_pdo_cnt; + src_pdo = pd_src_pdo; +#endif +} + +static int is_src(void) +{ + return src_pdo_cnt; +} + +static int is_snk(void) +{ +#ifdef CONFIG_USB_PD_DUAL_ROLE + return pd_snk_pdo_cnt; +#else + return 0; +#endif +} + +static int is_extpwr(void) +{ + if (is_src()) + return !!(src_pdo[0] & PDO_FIXED_EXTERNAL); + else + return 0; +} + +static int is_drp(void) +{ + if (is_src()) + return !!(src_pdo[0] & PDO_FIXED_DUAL_ROLE); + else + return 0; +} + +#ifdef CONFIG_USB_PD_DUAL_ROLE +static char *giveback(void) +{ +#ifdef CONFIG_USB_PD_GIVE_BACK + return "YES"; +#else + return "NO"; +#endif +} +#endif + +static char *is_comms_cap(void) +{ + if (is_src()) + return yes_no(src_pdo[0] & PDO_FIXED_COMM_CAP); + else + return "NO"; +} + +static char *dr_swap_to_ufp_supported(void) +{ + if (src_pdo[0] & PDO_FIXED_DATA_SWAP) + return yes_no(pd_check_data_swap(0, PD_ROLE_DFP)); + + return "NO"; +} + +static char *dr_swap_to_dfp_supported(void) +{ + if (src_pdo[0] & PDO_FIXED_DATA_SWAP) + return yes_no(pd_check_data_swap(0, PD_ROLE_UFP)); + + return "NO"; +} + +static char *vconn_swap(void) +{ +#ifdef CONFIG_USBC_VCONN_SWAP + return "YES"; +#else + return "NO"; +#endif +} + +static char *try_src(void) +{ +#ifdef CONFIG_USB_PD_TRY_SRC + return "YES"; +#else + return "NO"; +#endif +} + +static char *can_act_as_host(void) +{ +#ifdef CONFIG_VIF_TYPE_C_CAN_ACT_AS_HOST + return "YES"; +#else + return "NO"; +#endif +} + +static char *can_act_as_device(void) +{ +#ifdef CONFIG_USB + return "YES"; +#else + return "NO"; +#endif +} + +static char *captive_cable(void) +{ +#ifdef CONFIG_VIF_CAPTIVE_CABLE + return "YES"; +#else + return "NO"; +#endif +} + +static char *sources_vconn(void) +{ +#ifdef CONFIG_USBC_VCONN + return "YES"; +#else + return "NO"; +#endif +} + +static char *battery_powered(void) +{ +#if defined(CONFIG_BATTERY_BQ20Z453) || defined(CONFIG_BATTERY_BQ27541) || \ + defined(CONFIG_BATTERY_BQ27621) || defined(CONFIG_BATTERY_RYU) || \ + defined(CONFIG_BATTERY_SAMUS) || defined(CONFIG_BATTERY_SMART) + return "YES"; +#else + return "NO"; +#endif +} + +static uint32_t product_type(void) +{ + return PD_IDH_PTYPE(vdo_idh); +} + +static uint32_t pid_sop(void) +{ +#ifdef CONFIG_USB_PID + return CONFIG_USB_PID; +#else + return 0; +#endif +} + +static uint32_t rp_value(void) +{ +#ifdef CONFIG_USB_PD_MAX_SINGLE_SOURCE_CURRENT + return CONFIG_USB_PD_MAX_SINGLE_SOURCE_CURRENT; +#else + return 0; +#endif +} + +static char *attempts_discov_sop(enum dtype type) +{ +#ifdef CONFIG_USB_PD_SIMPLE_DFP + if (type == SRC) + return "NO"; + else + return "YES"; +#else + return "YES"; +#endif +} + +static uint32_t bcddevice_sop(void) +{ +#ifdef CONFIG_USB_BCD_DEV + return CONFIG_USB_BCD_DEV; +#else + return 0; +#endif +} + +static uint32_t write_pdo_to_vif(FILE *vif, uint32_t pdo, + enum dtype type, uint32_t pnum) +{ + uint32_t power; + + if ((pdo & PDO_TYPE_MASK) == PDO_TYPE_FIXED) { + uint32_t current = pdo & 0x3ff; + uint32_t voltage = (pdo >> 10) & 0x3ff; + + power = ((current * 10) * (voltage * 50)) / 1000; + + fprintf(vif, "%s_PDO_Supply_Type%d: 0\r\n", + (type == SRC) ? "Src" : "Snk", pnum); + if (type == SRC) + fprintf(vif, "Src_PDO_Peak_Current%d: 0\r\n", pnum); + fprintf(vif, "%s_PDO_Voltage%d: %d\r\n", + (type == SRC) ? "Src" : "Snk", pnum, voltage); + if (type == SRC) + fprintf(vif, "Src_PDO_Max_Current%d: %d\r\n", + pnum, current); + else + fprintf(vif, "Snk_PDO_Op_Current%d: %d\r\n", + pnum, current); + } else if ((pdo & PDO_TYPE_MASK) == PDO_TYPE_BATTERY) { + uint32_t max_voltage = (pdo >> 20) & 0x3ff; + uint32_t min_voltage = (pdo >> 10) & 0x3ff; + + power = pdo & 0x3ff; + + fprintf(vif, "%s_PDO_Supply_Type%d: 1\r\n", + (type == SRC) ? "Src" : "Snk", pnum); + fprintf(vif, "%s_PDO_Min_Voltage%d: %d\r\n", + (type == SRC) ? "Src" : "Snk", pnum, min_voltage); + fprintf(vif, "%s_PDO_Max_Voltage%d: %d\r\n", + (type == SRC) ? "Src" : "Snk", pnum, max_voltage); + if (type == SRC) + fprintf(vif, "Src_PDO_Max_Power%d: %d\r\n", + pnum, power); + else + fprintf(vif, "Snk_PDO_Op_Power%d: %d\r\n", + pnum, power); + } else if ((pdo & PDO_TYPE_MASK) == PDO_TYPE_VARIABLE) { + uint32_t max_voltage = (pdo >> 20) & 0x3ff; + uint32_t min_voltage = (pdo >> 10) & 0x3ff; + uint32_t current = pdo & 0x3ff; + + power = ((current * 10) * (max_voltage * 50)) / 1000; + + fprintf(vif, "%s_PDO_Supply_Type%d: 2\r\n", + (type == SRC) ? "Src" : "Snk", pnum); + if (type == SRC) + fprintf(vif, "Src_PDO_Peak_Current%d: 0\r\n", pnum); + fprintf(vif, "%s_PDO_Min_Voltage%d: %d\r\n", + (type == SRC) ? "Src" : "Snk", pnum, min_voltage); + fprintf(vif, "%s_PDO_Max_Voltage%d: %d\r\n", + (type == SRC) ? "Src" : "Snk", pnum, max_voltage); + if (type == SRC) + fprintf(vif, "Src_PDO_Max_Current%d: %d\r\n", + pnum, current); + else + fprintf(vif, "Snk_PDO_Op_Current%d: %d\r\n", + pnum, current); + } + + return power; +} + +/** + * Carriage and line feed, '\r\n', is needed because the file is processed + * on a Windows machine. + */ +static int gen_vif(const char *name, const char *board, + const char *vif_producer) +{ + FILE *vif; + enum dtype type; + + if (is_drp()) + type = DRP; + else if (is_src() && is_snk()) + /* No DRP with SRC and SNK PDOs detected. So ignore. */ + /* ie. Twinki or Plankton */ + return 0; + else if (is_src()) + type = SRC; + else if (is_snk()) + type = SNK; + else + return 1; + + /* Create VIF */ + vif = fopen(name, "w+"); + if (vif == NULL) + return 1; + + /* Write VIF Header */ + fprintf(vif, "$VIF_Specification: \"%s\"\r\n", VIF_SPEC); + fprintf(vif, "$VIF_Producer: \"%s\"\r\n", vif_producer); + fprintf(vif, "$Vendor_name: \"%s\"\r\n", VENDOR_NAME); + fprintf(vif, "$Product_Name: \"%s\"\r\n", board); + + fprintf(vif, "PD_Specification_Revision: %d\r\n", PD_SPEC_REV); + fprintf(vif, "UUT_Device_Type: %d\r\n", type); + fprintf(vif, "USB_Comms_Capable: %s\r\n", is_comms_cap()); + fprintf(vif, "DR_Swap_To_DFP_Supported: %s\r\n", + dr_swap_to_dfp_supported()); + fprintf(vif, "DR_Swap_To_UFP_Supported: %s\r\n", + dr_swap_to_ufp_supported()); + fprintf(vif, "Externally_Powered: %s\r\n", yes_no(is_extpwr())); + fprintf(vif, "VCONN_Swap_To_On_Supported: %s\r\n", vconn_swap()); + fprintf(vif, "VCONN_Swap_To_Off_Supported: %s\r\n", vconn_swap()); + fprintf(vif, "Responds_To_Discov_SOP: YES\r\n"); + fprintf(vif, "Attempts_Discov_SOP: %s\r\n", attempts_discov_sop(type)); + fprintf(vif, "SOP_Capable: YES\r\n"); + fprintf(vif, "SOP_P_Capable: NO\r\n"); + fprintf(vif, "SOP_PP_Capable: NO\r\n"); + fprintf(vif, "SOP_P_Debug_Capable: NO\r\n"); + fprintf(vif, "SOP_PP_Debug_Capable: NO\r\n"); + + /* Write Source Fields */ + if (type == DRP || type == SRC) { + uint32_t max_power = 0; + + fprintf(vif, "USB_Suspend_May_Be_Cleared: YES\r\n"); + fprintf(vif, "Sends_Pings: NO\r\n"); + fprintf(vif, "Num_Src_PDOs: %d\r\n", src_pdo_cnt); + + /* Write Source PDOs */ + { + int i; + uint32_t pwr; + + for (i = 0; i < src_pdo_cnt; i++) { + pwr = write_pdo_to_vif(vif, src_pdo[i], + SRC, i+1); + if (pwr > max_power) + max_power = pwr; + } + } + + fprintf(vif, "PD_Power_as_Source: %d\r\n", max_power); + } + + /* Write Sink Fields */ +#ifdef CONFIG_USB_PD_DUAL_ROLE + if (type == DRP || type == SNK) { + uint32_t max_power = 0; + uint32_t pwr; + int i; + + fprintf(vif, "USB_Suspend_May_Be_Cleared: NO\r\n"); + fprintf(vif, "GiveBack_May_Be_Set: %s\r\n", giveback()); + fprintf(vif, "Higher_Capability_Set: NO\r\n"); + fprintf(vif, "Num_Snk_PDOs: %d\r\n", pd_snk_pdo_cnt); + + /* Write Sink PDOs */ + for (i = 0; i < pd_snk_pdo_cnt; i++) { + pwr = write_pdo_to_vif(vif, pd_snk_pdo[i], SNK, i+1); + if (pwr > max_power) + max_power = pwr; + } + + fprintf(vif, "PD_Power_as_Sink: %d\r\n", max_power); + } + + /* Write DRP Fields */ + if (type == DRP) { + fprintf(vif, "Accepts_PR_Swap_As_Src: YES\r\n"); + fprintf(vif, "Accepts_PR_Swap_As_Snk: YES\r\n"); + fprintf(vif, "Requests_PR_Swap_As_Src: YES\r\n"); + fprintf(vif, "Requests_PR_Swap_As_Snk: YES\r\n"); + } +#endif + + /* SOP Discovery Fields */ + fprintf(vif, "Structured_VDM_Version_SOP: 0\r\n"); + fprintf(vif, "XID_SOP: 0\r\n"); + fprintf(vif, "Data_Capable_as_USB_Host_SOP: %s\r\n", + can_act_as_host()); + fprintf(vif, "Data_Capable_as_USB_Device_SOP: %s\r\n", + can_act_as_device()); + fprintf(vif, "Product_Type_SOP: %d\r\n", product_type()); + fprintf(vif, "Modal_Operation_Supported_SOP: YES\r\n"); + fprintf(vif, "USB_VID_SOP: 0x%04x\r\n", USB_VID_GOOGLE); + fprintf(vif, "PID_SOP: 0x%04x\r\n", pid_sop()); + fprintf(vif, "bcdDevice_SOP: 0x%04x\r\n", bcddevice_sop()); + + fprintf(vif, "SVID1_SOP: 0x%04x\r\n", USB_VID_GOOGLE); + fprintf(vif, "SVID1_num_modes_min_SOP: 1\r\n"); + fprintf(vif, "SVID1_num_modes_max_SOP: 1\r\n"); + fprintf(vif, "SVID1_num_modes_fixed_SOP: YES\r\n"); + fprintf(vif, "SVID1_mode1_enter_SOP: YES\r\n"); + +#ifdef USB_SID_DISPLAYPORT + fprintf(vif, "SVID2_SOP: 0x%04x\r\n", USB_SID_DISPLAYPORT); + fprintf(vif, "SVID2_num_modes_min_SOP: 2\r\n"); + fprintf(vif, "SVID2_num_modes_max_SOP: 2\r\n"); + fprintf(vif, "SVID2_num_modes_fixed_SOP: YES\r\n"); + fprintf(vif, "SVID2_mode1_enter_SOP: YES\r\n"); + fprintf(vif, "SVID2_mode2_enter_SOP: YES\r\n"); + + fprintf(vif, "Num_SVIDs_min_SOP: 2\r\n"); + fprintf(vif, "Num_SVIDs_max_SOP: 2\r\n"); + fprintf(vif, "SVID_fixed_SOP: YES\r\n"); +#else + fprintf(vif, "Num_SVIDs_min_SOP: 1\r\n"); + fprintf(vif, "Num_SVIDs_max_SOP: 1\r\n"); + fprintf(vif, "SVID_fixed_SOP: YES\r\n"); +#endif + + /* set Type_C_State_Machine */ + { + int typec; + + switch (type) { + case DRP: + typec = 2; + break; + + case SNK: + typec = 1; + break; + + default: + typec = 0; + } + + fprintf(vif, "Type_C_State_Machine: %d\r\n", typec); + } + + fprintf(vif, "Type_C_Implements_Try_SRC: %s\r\n", try_src()); + fprintf(vif, "Type_C_Implements_Try_SNK: NO\r\n"); + fprintf(vif, "Rp_Value: %d\r\n", rp_value()); + /* None of the current devices send SOP' / SOP", so NO.*/ + fprintf(vif, "Type_C_Supports_VCONN_Powered_Accessory: NO\r\n"); + fprintf(vif, "Type_C_Is_VCONN_Powered_Accessory: NO\r\n"); + fprintf(vif, "Type_C_Can_Act_As_Host: %s\r\n", can_act_as_host()); + fprintf(vif, "Type_C_Host_Speed: 4\r\n"); + fprintf(vif, "Type_C_Can_Act_As_Device: %s\r\n", can_act_as_device()); + fprintf(vif, "Type_C_Device_Speed: 4\r\n"); + fprintf(vif, "Type_C_Power_Source: 2\r\n"); + fprintf(vif, "Type_C_BC_1_2_Support: 1\r\n"); + fprintf(vif, "Type_C_Battery_Powered: %s\r\n", battery_powered()); + fprintf(vif, "Type_C_Port_On_Hub: NO\r\n"); + fprintf(vif, "Type_C_Supports_Audio_Accessory: NO\r\n"); + fprintf(vif, "Captive_Cable: %s\r\n", captive_cable()); + fprintf(vif, "Type_C_Source_Vconn: %s\r\n", sources_vconn()); + + fclose(vif); + return 0; +} + +int main(int argc, char **argv) +{ + int nopt; + int ret; + const char *out; + const char *board; + const char *vif_producer; + DIR *vifdir; + char *name; + int name_size; + const char * const short_opt = "hb:o:"; + const struct option long_opts[] = { + { "help", 0, NULL, 'h' }, + { "board", 1, NULL, 'b' }, + { "out", 1, NULL, 'o' }, + { NULL } + }; + + vif_producer = argv[0]; + + do { + nopt = getopt_long(argc, argv, short_opt, long_opts, NULL); + switch (nopt) { + case 'h': /* -h or --help */ + printf("USAGE: %s -b <board name> -o <out directory>\n", + vif_producer); + return 1; + + case 'b': /* -b or --board */ + board = optarg; + break; + + case 'o': /* -o or --out */ + out = optarg; + break; + + case -1: + break; + + default: + abort(); + } + } while (nopt != -1); + + if (out == NULL || board == NULL) + return 1; + + /* Make sure VIF directory exists */ + vifdir = opendir(out); + if (vifdir == NULL) { + fprintf(stderr, "ERROR: %s directory does not exist.\n", out); + return 1; + } + closedir(vifdir); + + init_src_pdos(); + + name_size = asprintf(&name, "%s/%s_vif.txt", out, board); + if (name_size < 0) { + fprintf(stderr, "ERROR: Out of memory.\n"); + return 1; + } + + ret = gen_vif(name, board, vif_producer); + + free(name); + + return ret; +} |