summaryrefslogtreecommitdiff
path: root/util/genvif.c
diff options
context:
space:
mode:
authorSam Hurst <shurst@google.com>2017-03-15 10:36:06 -0700
committerchrome-bot <chrome-bot@chromium.org>2017-05-03 23:17:46 -0700
commite13695c0175dcb7854de74ed7c69e6054b0481dc (patch)
treea66e832c8c080a99172e053b50fb0d9b6ad83427 /util/genvif.c
parent4444702e858a8fa3d51c948f509450e136a9482a (diff)
downloadchrome-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/genvif.c')
-rw-r--r--util/genvif.c547
1 files changed, 547 insertions, 0 deletions
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;
+}