From 0739074fbf735cffefdac7ff6d086084449f6493 Mon Sep 17 00:00:00 2001 From: Vic Yang Date: Fri, 8 Aug 2014 10:59:17 -0700 Subject: Add unit test for usb_pd Initial commit of usb_pd unit test. The test cases are very simple. We'll add more test cases in similar format. BUG=chrome-os-partner:31200 TEST=Pass usb_pd test BRANCH=None Change-Id: I9e3de5b2c032ee1d3670cde6d8227ce0378ae8a0 Signed-off-by: Vic Yang Reviewed-on: https://chromium-review.googlesource.com/211643 Reviewed-by: Vincent Palatin --- board/host/board.h | 5 + board/host/build.mk | 1 + board/host/ec.tasklist | 4 +- board/host/usb_pd_config.c | 35 ++++++ board/host/usb_pd_config.h | 41 +++++++ board/host/usb_pd_policy.c | 122 +++++++++++++++++++ chip/host/build.mk | 1 + chip/host/usb_pd_phy.c | 289 +++++++++++++++++++++++++++++++++++++++++++++ test/build.mk | 8 +- test/usb_pd.c | 204 ++++++++++++++++++++++++++++++++ test/usb_pd.tasklist | 17 +++ test/usb_pd_test_util.h | 31 +++++ 12 files changed, 754 insertions(+), 4 deletions(-) create mode 100644 board/host/usb_pd_config.c create mode 100644 board/host/usb_pd_config.h create mode 100644 board/host/usb_pd_policy.c create mode 100644 chip/host/usb_pd_phy.c create mode 100644 test/usb_pd.c create mode 100644 test/usb_pd.tasklist create mode 100644 test/usb_pd_test_util.h diff --git a/board/host/board.h b/board/host/board.h index b8ce98513a..e2fb3fbb9a 100644 --- a/board/host/board.h +++ b/board/host/board.h @@ -16,6 +16,11 @@ #undef CONFIG_WATCHDOG #define CONFIG_SWITCH +#define CONFIG_USB_POWER_DELIVERY +#define CONFIG_USB_PD_CUSTOM_VDM +#define CONFIG_USB_PD_DUAL_ROLE +#define CONFIG_SW_CRC + #undef CONFIG_CONSOLE_HISTORY #define CONFIG_CONSOLE_HISTORY 4 diff --git a/board/host/build.mk b/board/host/build.mk index 9b50c501ae..91451188a7 100644 --- a/board/host/build.mk +++ b/board/host/build.mk @@ -12,3 +12,4 @@ board-y=board.o board-$(HAS_TASK_CHIPSET)+=chipset.o board-$(CONFIG_BATTERY_MOCK)+=battery.o charger.o board-$(CONFIG_FANS)+=fan.o +board-$(CONFIG_USB_POWER_DELIVERY)+=usb_pd_policy.o usb_pd_config.o diff --git a/board/host/ec.tasklist b/board/host/ec.tasklist index dc03085807..939cac3efc 100644 --- a/board/host/ec.tasklist +++ b/board/host/ec.tasklist @@ -20,4 +20,6 @@ #define CONFIG_TASK_LIST \ TASK_ALWAYS(HOOKS, hook_task, NULL, TASK_STACK_SIZE) \ TASK_ALWAYS(HOSTCMD, host_command_task, NULL, TASK_STACK_SIZE) \ - TASK_ALWAYS(CONSOLE, console_task, NULL, TASK_STACK_SIZE) + TASK_ALWAYS(CONSOLE, console_task, NULL, TASK_STACK_SIZE) \ + TASK_ALWAYS(PD_C0, pd_task, NULL, LARGER_TASK_STACK_SIZE) \ + TASK_ALWAYS(PD_C1, pd_task, NULL, LARGER_TASK_STACK_SIZE) diff --git a/board/host/usb_pd_config.c b/board/host/usb_pd_config.c new file mode 100644 index 0000000000..aec495a0c9 --- /dev/null +++ b/board/host/usb_pd_config.c @@ -0,0 +1,35 @@ +/* Copyright (c) 2014 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 Power delivery board configuration */ + +#include "test_util.h" + +test_mockable void pd_select_polarity(int port, int polarity) +{ + /* Not implemented */ +} + +test_mockable void pd_tx_init(void) +{ + /* Not implemented */ +} + +test_mockable void pd_set_host_mode(int port, int enable) +{ + /* Not implemented */ +} + +test_mockable int pd_adc_read(int port, int cc) +{ + /* Not implemented */ + return 0; +} + +test_mockable int pd_snk_is_vbus_provided(int port) +{ + /* Not implemented */ + return 1; +} diff --git a/board/host/usb_pd_config.h b/board/host/usb_pd_config.h new file mode 100644 index 0000000000..6770b8e11d --- /dev/null +++ b/board/host/usb_pd_config.h @@ -0,0 +1,41 @@ +/* Copyright (c) 2014 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 Power delivery board configuration */ + +#ifndef __USB_PD_CONFIG_H +#define __USB_PD_CONFIG_H + +/* Port and task configuration */ +#define PD_PORT_COUNT 2 +#define PORT_TO_TASK_ID(port) ((port) ? TASK_ID_PD_C1 : TASK_ID_PD_C0) +#define TASK_ID_TO_PORT(id) ((id) == TASK_ID_PD_C0 ? 0 : 1) + +/* Use software CRC */ +#define CONFIG_SW_CRC + +void pd_select_polarity(int port, int polarity); + +void pd_tx_init(void); + +void pd_set_host_mode(int port, int enable); + +int pd_adc_read(int port, int cc); + +int pd_snk_is_vbus_provided(int port); + +/* Standard-current DFP : no-connect voltage is 1.55V */ +#define PD_SRC_VNC 1550 /* mV */ + +/* UFP-side : threshold for DFP connection detection */ +#define PD_SNK_VA 200 /* mV */ + +/* start as a sink in case we have no other power supply/battery */ +#define PD_DEFAULT_STATE PD_STATE_SNK_DISCONNECTED + +/* delay necessary for the voltage transition on the power supply */ +#define PD_POWER_SUPPLY_TRANSITION_DELAY 50000 /* us */ + +#endif /* __USB_PD_CONFIG_H */ diff --git a/board/host/usb_pd_policy.c b/board/host/usb_pd_policy.c new file mode 100644 index 0000000000..ffa6d53be9 --- /dev/null +++ b/board/host/usb_pd_policy.c @@ -0,0 +1,122 @@ +/* Copyright (c) 2014 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 "usb_pd.h" +#include "util.h" + +const uint32_t pd_src_pdo[] = { + PDO_FIXED(5000, 500, PDO_FIXED_EXTERNAL), + PDO_FIXED(5000, 900, 0), +}; +const int pd_src_pdo_cnt = ARRAY_SIZE(pd_src_pdo); + +const uint32_t pd_snk_pdo[] = { + PDO_BATT(4500, 5500, 15000), + PDO_BATT(11500, 12500, 36000), +}; +const int pd_snk_pdo_cnt = ARRAY_SIZE(pd_snk_pdo); + +/* Cap on the max voltage requested as a sink (in millivolts) */ +static unsigned max_mv = -1; /* no cap */ + +int pd_choose_voltage(int cnt, uint32_t *src_caps, uint32_t *rdo) +{ + int i; + int sel_mv; + int max_uw = 0; + int max_i = -1; + + /* Get max power */ + for (i = 0; i < cnt; i++) { + int uw; + int mv = ((src_caps[i] >> 10) & 0x3FF) * 50; + if ((src_caps[i] & PDO_TYPE_MASK) == PDO_TYPE_BATTERY) { + uw = 250000 * (src_caps[i] & 0x3FF); + } else { + int ma = (src_caps[i] & 0x3FF) * 10; + uw = ma * mv; + } + if ((uw > max_uw) && (mv <= max_mv)) { + max_i = i; + max_uw = uw; + sel_mv = mv; + } + } + if (max_i < 0) + return -EC_ERROR_UNKNOWN; + + /* request all the power ... */ + if ((src_caps[max_i] & PDO_TYPE_MASK) == PDO_TYPE_BATTERY) { + int uw = 250000 * (src_caps[max_i] & 0x3FF); + *rdo = RDO_BATT(max_i + 1, uw/2, uw, 0); + ccprintf("Request [%d] %dV %d/%d mW\n", + max_i, sel_mv/1000, uw/1000, uw/1000); + } else { + int ma = 10 * (src_caps[max_i] & 0x3FF); + *rdo = RDO_FIXED(max_i + 1, ma / 2, ma, 0); + ccprintf("Request [%d] %dV %d/%d mA\n", + max_i, sel_mv/1000, max_i, ma/2, ma); + } + return EC_SUCCESS; +} + +void pd_set_max_voltage(unsigned mv) +{ + max_mv = mv; +} + +int pd_request_voltage(uint32_t rdo) +{ + int op_ma = rdo & 0x3FF; + int max_ma = (rdo >> 10) & 0x3FF; + int idx = rdo >> 28; + uint32_t pdo; + uint32_t pdo_ma; + + if (!idx || idx > pd_src_pdo_cnt) + return EC_ERROR_INVAL; /* Invalid index */ + + /* check current ... */ + pdo = pd_src_pdo[idx - 1]; + pdo_ma = (pdo & 0x3ff); + if (op_ma > pdo_ma) + return EC_ERROR_INVAL; /* too much op current */ + if (max_ma > pdo_ma) + return EC_ERROR_INVAL; /* too much max current */ + + ccprintf("Switch to %d V %d mA (for %d/%d mA)\n", + ((pdo >> 10) & 0x3ff) * 50, (pdo & 0x3ff) * 10, + ((rdo >> 10) & 0x3ff) * 10, (rdo & 0x3ff) * 10); + + return EC_SUCCESS; +} + +int pd_set_power_supply_ready(int port) +{ + /* Not implemented */ + return EC_SUCCESS; +} + +void pd_power_supply_reset(int port) +{ + /* Not implemented */ +} + +void pd_set_input_current_limit(uint32_t max_ma) +{ + /* Not implemented */ +} + +int pd_board_checks(void) +{ + return EC_SUCCESS; +} + +int pd_custom_vdm(int port, int cnt, uint32_t *payload, uint32_t **rpayload) +{ + return 0; +} diff --git a/chip/host/build.mk b/chip/host/build.mk index 56b091b8cf..40d2604fcb 100644 --- a/chip/host/build.mk +++ b/chip/host/build.mk @@ -11,3 +11,4 @@ CORE:=host chip-y=system.o gpio.o uart.o persistence.o flash.o lpc.o reboot.o i2c.o \ clock.o chip-$(HAS_TASK_KEYSCAN)+=keyboard_raw.o +chip-$(CONFIG_USB_POWER_DELIVERY)+=usb_pd_phy.o diff --git a/chip/host/usb_pd_phy.c b/chip/host/usb_pd_phy.c new file mode 100644 index 0000000000..1cb770bf8d --- /dev/null +++ b/chip/host/usb_pd_phy.c @@ -0,0 +1,289 @@ +/* Copyright 2014 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 "crc.h" +#include "task.h" +#include "usb_pd.h" +#include "usb_pd_config.h" +#include "util.h" + +#define PREAMBLE_OFFSET 60 /* Any number should do */ + +/* + * Maximum size of a Power Delivery packet (in bits on the wire) : + * 16-bit header + 0..7 32-bit data objects (+ 4b5b encoding) + * 64-bit preamble + SOP (4x 5b) + message in 4b5b + 32-bit CRC + EOP (1x 5b) + * = 64 + 4*5 + 16 * 5/4 + 7 * 32 * 5/4 + 32 * 5/4 + 5 + */ +#define PD_BIT_LEN 429 + +static struct pd_physical { + int hw_init_done; + + uint8_t bits[PD_BIT_LEN]; + int total; + int has_preamble; + int rx_started; + int rx_monitoring; + + int preamble_written; + int has_msg; + int last_edge_written; + uint8_t out_msg[PD_BIT_LEN / 5]; + int verified_idx; +} pd_phy[PD_PORT_COUNT]; + +static const uint16_t enc4b5b[] = { + 0x1E, 0x09, 0x14, 0x15, 0x0A, 0x0B, 0x0E, 0x0F, 0x12, 0x13, 0x16, + 0x17, 0x1A, 0x1B, 0x1C, 0x1D}; + +/* Test utilities */ + +void pd_test_rx_set_preamble(int port, int has_preamble) +{ + pd_phy[port].has_preamble = has_preamble; +} + +void pd_test_rx_msg_append_bits(int port, uint32_t bits, int nb) +{ + int i; + + for (i = 0; i < nb; ++i) { + pd_phy[port].bits[pd_phy[port].total++] = bits & 1; + bits >>= 1; + } +} + +void pd_test_rx_msg_append_kcode(int port, uint8_t kcode) +{ + pd_test_rx_msg_append_bits(port, kcode, 5); +} + +void pd_test_rx_msg_append_sop(int port) +{ + pd_test_rx_msg_append_kcode(port, PD_SYNC1); + pd_test_rx_msg_append_kcode(port, PD_SYNC1); + pd_test_rx_msg_append_kcode(port, PD_SYNC1); + pd_test_rx_msg_append_kcode(port, PD_SYNC2); +} + +void pd_test_rx_msg_append_eop(int port) +{ + pd_test_rx_msg_append_kcode(port, PD_EOP); +} + +void pd_test_rx_msg_append_4b(int port, uint8_t val) +{ + pd_test_rx_msg_append_bits(port, enc4b5b[val & 0xF], 5); +} + +void pd_test_rx_msg_append_short(int port, uint16_t val) +{ + pd_test_rx_msg_append_4b(port, (val >> 0) & 0xF); + pd_test_rx_msg_append_4b(port, (val >> 4) & 0xF); + pd_test_rx_msg_append_4b(port, (val >> 8) & 0xF); + pd_test_rx_msg_append_4b(port, (val >> 12) & 0xF); +} + +void pd_test_rx_msg_append_word(int port, uint32_t val) +{ + pd_test_rx_msg_append_short(port, val & 0xFFFF); + pd_test_rx_msg_append_short(port, val >> 16); +} + +void pd_simulate_rx(int port) +{ + if (!pd_phy[port].rx_monitoring) + return; + pd_rx_start(port); + pd_rx_disable_monitoring(port); + pd_rx_event(port); +} + +static int pd_test_tx_msg_verify(int port, uint8_t raw) +{ + int verified_idx = pd_phy[port].verified_idx++; + return pd_phy[port].out_msg[verified_idx] == raw; +} + +int pd_test_tx_msg_verify_kcode(int port, uint8_t kcode) +{ + return pd_test_tx_msg_verify(port, kcode); +} + +int pd_test_tx_msg_verify_sop(int port) +{ + crc32_init(); + return pd_test_tx_msg_verify_kcode(port, PD_SYNC1) && + pd_test_tx_msg_verify_kcode(port, PD_SYNC1) && + pd_test_tx_msg_verify_kcode(port, PD_SYNC1) && + pd_test_tx_msg_verify_kcode(port, PD_SYNC2); +} + +int pd_test_tx_msg_verify_eop(int port) +{ + return pd_test_tx_msg_verify_kcode(port, PD_EOP); +} + +int pd_test_tx_msg_verify_4b5b(int port, uint8_t b4) +{ + return pd_test_tx_msg_verify(port, enc4b5b[b4]); +} + +int pd_test_tx_msg_verify_short(int port, uint16_t val) +{ + crc32_hash16(val); + return pd_test_tx_msg_verify_4b5b(port, (val >> 0) & 0xF) && + pd_test_tx_msg_verify_4b5b(port, (val >> 4) & 0xF) && + pd_test_tx_msg_verify_4b5b(port, (val >> 8) & 0xF) && + pd_test_tx_msg_verify_4b5b(port, (val >> 12) & 0xF); +} + +int pd_test_tx_msg_verify_word(int port, uint32_t val) +{ + return pd_test_tx_msg_verify_short(port, val & 0xFFFF) && + pd_test_tx_msg_verify_short(port, val >> 16); +} + +int pd_test_tx_msg_verify_crc(int port) +{ + return pd_test_tx_msg_verify_word(port, crc32_result()); +} + + +/* Mock functions */ + +void pd_init_dequeue(int port) +{ +} + +int pd_dequeue_bits(int port, int off, int len, uint32_t *val) +{ + int i; + + /* Rx must have started to receive message */ + ASSERT(pd_phy[port].rx_started); + + if (pd_phy[port].total <= off + len - PREAMBLE_OFFSET) + return -1; + *val = 0; + for (i = 0; i < len; ++i) + *val |= pd_phy[port].bits[off + i - PREAMBLE_OFFSET] << i; + return off + len; +} + +int pd_find_preamble(int port) +{ + return pd_phy[port].has_preamble ? PREAMBLE_OFFSET : -1; +} + +int pd_write_preamble(int port) +{ + ASSERT(pd_phy[port].preamble_written == 0); + pd_phy[port].preamble_written = 1; + ASSERT(pd_phy[port].has_msg == 0); + return 0; +} + +static uint8_t decode_bmc(uint32_t val10) +{ + uint8_t ret = 0; + int i; + + for (i = 0; i < 5; ++i) + if (!!(val10 & (1 << (2 * i))) != + !!(val10 & (1 << (2 * i + 1)))) + ret |= (1 << i); + return ret; +} + +int pd_write_sym(int port, int bit_off, uint32_t val10) +{ + pd_phy[port].out_msg[bit_off] = decode_bmc(val10); + pd_phy[port].has_msg = 1; + return bit_off + 1; +} + +int pd_write_last_edge(int port, int bit_off) +{ + pd_phy[port].last_edge_written = 1; + return bit_off; +} + +void pd_dump_packet(int port, const char *msg) +{ + /* Not implemented */ +} + +void pd_tx_set_circular_mode(int port) +{ + /* Not implemented */ +} + +void pd_start_tx(int port, int polarity, int bit_len) +{ + ASSERT(pd_phy[port].hw_init_done); + pd_phy[port].has_msg = 0; + pd_phy[port].preamble_written = 0; + pd_phy[port].verified_idx = 0; + + /* + * Hand over to test runner. The test runner must wake us after + * processing the packet. + */ + task_wake(TASK_ID_TEST_RUNNER); + task_wait_event(-1); +} + +void pd_tx_done(int port, int polarity) +{ + /* Nothing to do */ +} + +void pd_rx_start(int port) +{ + ASSERT(pd_phy[port].hw_init_done); + pd_phy[port].rx_started = 1; +} + +void pd_rx_complete(int port) +{ + ASSERT(pd_phy[port].hw_init_done); + pd_phy[port].rx_started = 0; +} + +int pd_rx_started(int port) +{ + return pd_phy[port].rx_started; +} + +void pd_rx_enable_monitoring(int port) +{ + ASSERT(pd_phy[port].hw_init_done); + pd_phy[port].rx_monitoring = 1; +} + +void pd_rx_disable_monitoring(int port) +{ + ASSERT(pd_phy[port].hw_init_done); + pd_phy[port].rx_monitoring = 0; +} + +void pd_hw_release(int port) +{ + pd_phy[port].hw_init_done = 0; +} + +void pd_hw_init(int port) +{ + pd_phy[port].hw_init_done = 1; +} + +void pd_set_clock(int port, int freq) +{ + /* Not implemented */ +} diff --git a/test/build.mk b/test/build.mk index cb1ced36b1..e87e3fcd88 100644 --- a/test/build.mk +++ b/test/build.mk @@ -31,18 +31,20 @@ test-list-host+=thermal flash queue kb_8042 extpwr_gpio console_edit system test-list-host+=sbs_charging adapter host_command thermal_falco led_spring test-list-host+=bklight_lid bklight_passthru interrupt timer_dos button test-list-host+=motion_sense math_util sbs_charging_v2 battery_get_params_smart +test-list-host+=usb_pd adapter-y=adapter.o -button-y=button.o +battery_get_params_smart-y=battery_get_params_smart.o bklight_lid-y=bklight_lid.o bklight_passthru-y=bklight_passthru.o +button-y=button.o console_edit-y=console_edit.o extpwr_gpio-y=extpwr_gpio.o flash-y=flash.o hooks-y=hooks.o host_command-y=host_command.o -kb_8042-y=kb_8042.o interrupt-y=interrupt.o +kb_8042-y=kb_8042.o kb_mkbp-y=kb_mkbp.o kb_scan-y=kb_scan.o led_spring-y=led_spring.o led_spring_impl.o @@ -62,5 +64,5 @@ thermal-y=thermal.o thermal_falco-y=thermal_falco.o timer_calib-y=timer_calib.o timer_dos-y=timer_dos.o +usb_pd-y=usb_pd.o utils-y=utils.o -battery_get_params_smart-y=battery_get_params_smart.o diff --git a/test/usb_pd.c b/test/usb_pd.c new file mode 100644 index 0000000000..fd10d44840 --- /dev/null +++ b/test/usb_pd.c @@ -0,0 +1,204 @@ +/* Copyright 2014 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. + * + * Test USB PD module. + */ + +#include "common.h" +#include "crc.h" +#include "task.h" +#include "test_util.h" +#include "timer.h" +#include "usb_pd.h" +#include "usb_pd_config.h" +#include "usb_pd_test_util.h" +#include "util.h" + +struct pd_port_t { + int host_mode; + int cc_volt[2]; /* -1 for Hi-Z */ + int has_vbus; + int msg_tx_id; + int msg_rx_id; + int polarity; +} pd_port[PD_PORT_COUNT]; + +/* Mock functions */ + +int pd_adc_read(int port, int cc) +{ + int val = pd_port[port].cc_volt[cc]; + if (val == -1) + return pd_port[port].host_mode ? 3000 : 0; + return val; +} + +int pd_snk_is_vbus_provided(int port) +{ + return pd_port[port].has_vbus; +} + +void pd_set_host_mode(int port, int enable) +{ + pd_port[port].host_mode = enable; +} + +void pd_select_polarity(int port, int polarity) +{ + pd_port[port].polarity = polarity; +} + +/* Tests */ + +void inc_tx_id(int port) +{ + pd_port[port].msg_tx_id = (pd_port[port].msg_tx_id + 1) % 7; +} + +void inc_rx_id(int port) +{ + pd_port[port].msg_rx_id = (pd_port[port].msg_rx_id + 1) % 7; +} + +static void init_ports(void) +{ + int i; + + for (i = 0; i < PD_PORT_COUNT; ++i) { + pd_port[i].host_mode = 0; + pd_port[i].cc_volt[0] = pd_port[i].cc_volt[1] = -1; + pd_port[i].has_vbus = 0; + } +} + +static void simulate_rx_msg(int port, uint16_t header, int cnt, + const uint32_t *data) +{ + int i; + + pd_test_rx_set_preamble(port, 1); + pd_test_rx_msg_append_sop(port); + pd_test_rx_msg_append_short(port, header); + + crc32_init(); + crc32_hash16(header); + for (i = 0; i < cnt; ++i) { + pd_test_rx_msg_append_word(port, data[i]); + crc32_hash32(data[i]); + } + pd_test_rx_msg_append_word(port, crc32_result()); + + pd_test_rx_msg_append_eop(port); + + pd_simulate_rx(port); +} + +static void simulate_source_cap(int port) +{ + uint16_t header = PD_HEADER(PD_DATA_SOURCE_CAP, PD_ROLE_SOURCE, + pd_port[port].msg_rx_id, pd_src_pdo_cnt); + simulate_rx_msg(port, header, pd_src_pdo_cnt, pd_src_pdo); +} + +static void simulate_goodcrc(int port, int role, int id) +{ + simulate_rx_msg(port, PD_HEADER(PD_CTRL_GOOD_CRC, role, id, 0), + 0, NULL); +} + +static int verify_goodcrc(int port, int role, int id) +{ + return pd_test_tx_msg_verify_sop(0) && + pd_test_tx_msg_verify_short(0, PD_HEADER(PD_CTRL_GOOD_CRC, + role, id, 0)) && + pd_test_tx_msg_verify_crc(0) && + pd_test_tx_msg_verify_eop(0); +} + +static void plug_in_source(int port, int polarity) +{ + pd_port[port].has_vbus = 1; + pd_port[port].cc_volt[polarity] = 3000; +} + +static void plug_in_sink(int port, int polarity) +{ + pd_port[port].has_vbus = 0; + pd_port[port].cc_volt[polarity] = 0; +} + +static void unplug(int port) +{ + pd_port[port].has_vbus = 0; + pd_port[port].cc_volt[0] = -1; + pd_port[port].cc_volt[1] = -1; + task_wake(PORT_TO_TASK_ID(port)); + usleep(30 * MSEC); +} + +static int test_request(void) +{ + plug_in_source(0, 0); + task_wake(PORT_TO_TASK_ID(0)); + usleep(30 * MSEC); + TEST_ASSERT(pd_port[0].polarity == 0); + + simulate_source_cap(0); + task_wait_event(3 * MSEC); + TEST_ASSERT(verify_goodcrc(0, PD_ROLE_SINK, pd_port[0].msg_rx_id)); + task_wake(PORT_TO_TASK_ID(0)); + task_wait_event(35 * MSEC); /* tSenderResponse: 24~30 ms */ + inc_rx_id(0); + + /* Process the request */ + TEST_ASSERT(pd_test_tx_msg_verify_sop(0)); + TEST_ASSERT(pd_test_tx_msg_verify_short(0, + PD_HEADER(PD_DATA_REQUEST, PD_ROLE_SINK, + pd_port[0].msg_tx_id, 1))); + TEST_ASSERT(pd_test_tx_msg_verify_word(0, RDO_FIXED(2, 450, 900, 0))); + TEST_ASSERT(pd_test_tx_msg_verify_crc(0)); + TEST_ASSERT(pd_test_tx_msg_verify_eop(0)); + inc_tx_id(0); + unplug(0); + return EC_SUCCESS; +} + +static int test_sink(void) +{ + int i; + + plug_in_sink(1, 1); + task_wake(PORT_TO_TASK_ID(1)); + task_wait_event(250 * MSEC); /* tTypeCSinkWaitCap: 210~250 ms */ + TEST_ASSERT(pd_port[1].polarity == 1); + + TEST_ASSERT(pd_test_tx_msg_verify_sop(1)); + TEST_ASSERT(pd_test_tx_msg_verify_short(1, + PD_HEADER(PD_DATA_SOURCE_CAP, PD_ROLE_SOURCE, + pd_port[1].msg_tx_id, pd_src_pdo_cnt))); + for (i = 0; i < pd_src_pdo_cnt; ++i) + TEST_ASSERT(pd_test_tx_msg_verify_word(1, pd_src_pdo[i])); + TEST_ASSERT(pd_test_tx_msg_verify_crc(1)); + TEST_ASSERT(pd_test_tx_msg_verify_eop(1)); + + simulate_goodcrc(1, PD_ROLE_SINK, pd_port[1].msg_tx_id); + task_wake(PORT_TO_TASK_ID(1)); + usleep(30 * MSEC); + inc_tx_id(1); + + unplug(1); + return EC_SUCCESS; +} + +void run_test(void) +{ + test_reset(); + init_ports(); + pd_set_dual_role(PD_DRP_TOGGLE_ON); + + RUN_TEST(test_request); + RUN_TEST(test_sink); + + test_print_result(); +} diff --git a/test/usb_pd.tasklist b/test/usb_pd.tasklist new file mode 100644 index 0000000000..356ef4de39 --- /dev/null +++ b/test/usb_pd.tasklist @@ -0,0 +1,17 @@ +/* Copyright (c) 2013 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 diff --git a/test/usb_pd_test_util.h b/test/usb_pd_test_util.h new file mode 100644 index 0000000000..5be8e0984a --- /dev/null +++ b/test/usb_pd_test_util.h @@ -0,0 +1,31 @@ +/* Copyright 2014 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. + * + * Test utilities for USB PD unit test. + */ + +#ifndef __USB_PD_TEST_UTIL_H +#define __USB_PD_TEST_UTIL_H + +/* Simulate Rx message */ +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_eop(int port); +void pd_test_rx_msg_append_4b(int port, uint8_t val); +void pd_test_rx_msg_append_short(int port, uint16_t val); +void pd_test_rx_msg_append_word(int port, uint32_t val); +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_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); +int pd_test_tx_msg_verify_word(int port, uint32_t val); +int pd_test_tx_msg_verify_crc(int port); + +#endif /* __USB_PD_TEST_UTIL_H */ -- cgit v1.2.1