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 | |
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>
-rw-r--r-- | Makefile.rules | 10 | ||||
-rw-r--r-- | include/config.h | 13 | ||||
-rw-r--r-- | util/build.mk | 15 | ||||
-rw-r--r-- | util/genvif.c | 547 |
4 files changed, 584 insertions, 1 deletions
diff --git a/Makefile.rules b/Makefile.rules index d8bfd68bc7..5ab474ab78 100644 --- a/Makefile.rules +++ b/Makefile.rules @@ -12,6 +12,7 @@ BUILD_DIR := $(firstword $(subst /, ,$(out))) build-utils := $(foreach u,$(build-util-bin),$(out)/util/$(u)) host-utils := $(foreach u,$(host-util-bin),$(out)/util/$(u)) +build-art := $(foreach u,$(build-util-art),$(out)/$(u)) build-srcs := $(foreach u,$(build-util-bin),$(sort $($(u)-objs:%.o=util/%.c) util/$(u).c)) host-srcs := $(foreach u,$(host-util-bin),$(sort $($(u)-objs:%.o=util/%.c) util/$(u).c)) @@ -82,6 +83,7 @@ cmd_cxx_to_host = $(HOSTCXX) -std=c++0x $(COMMON_WARN) $(HOST_CXXFLAGS)\ -I ./$($(notdir $@)_ROOT) -o $@ $(filter %.cc,$^) $($(notdir $@)_LIBS) cmd_host_test = ./util/run_host_test $* $(silent) cmd_version = ./util/getversion.sh > $@ +cmd_vif = $(out)/util/genvif -b $(BOARD) -o $(out) cmd_mv_from_tmp = mv $(out)/$*.bin.tmp $(out)/$*.bin cmd_extractrw-y = dd if=$(out)/$(PROJECT).bin.tmp of=$(out)/$(PROJECT).RW.bin \ bs=1 count=$(_rw_size) skip=$(_rw_off) $(silent_err) @@ -172,6 +174,9 @@ hex-y := $(out)/RO/$(PROJECT).RO.hex $(out)/RW/$(PROJECT).RW.hex $(out)/$(PROJEC hex: $(hex-y) .PHONY: hex +.PHONY: utils-art +utils-art: $(build-art) + .PHONY: utils-host utils-host: $(host-utils) @@ -179,7 +184,7 @@ utils-host: $(host-utils) utils-build: $(build-utils) .PHONY: utils -utils: utils-host utils-build +utils: utils-host utils-build utils-art # On board test binaries test-targets=$(foreach t,$(test-list-y),test-$(t)) @@ -279,6 +284,9 @@ $(out)/%.bin: $(out)/%.obj $(call quiet,copyrw-y,COPY_RW)) $(call quiet,mv_from_tmp,MV ) +$(out)/$(BOARD)_vif.txt: $(out)/util/genvif + $(call quiet,vif,VIF ) + flat-y := $(out)/RW/$(PROJECT).RW.flat flat-$(CONFIG_FW_INCLUDE_RO) += $(out)/RO/$(PROJECT).RO.flat diff --git a/include/config.h b/include/config.h index 00e1f50e4b..5f3f3b5493 100644 --- a/include/config.h +++ b/include/config.h @@ -2404,6 +2404,19 @@ /* USB Device version of product */ #undef CONFIG_USB_BCD_DEV +/* + * Used during generation of VIF for USB Type-C Compliance Testing. + * Indicates whether the UUT can communicate with USB 2.0 or USB 3.1 as a host + * or as the Downstream Facing Port of a hub. + */ +#undef CONFIG_VIF_TYPE_C_CAN_ACT_AS_HOST + +/* + * Used during generation of VIF for USB Type-C Compliance Testing. + * Indicates whether the UUT has a captive cable. + */ +#undef CONFIG_VIF_CAPTIVE_CABLE + /*****************************************************************************/ /* Compile chip support for the USB device controller */ 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; +} |