Files
OpenCellular/test/usb_pd.c
Todd Broch a194bede19 pd: VDM Alternate mode support.
Successfully communicate SVDM for discovery (identity, svids, modes)
and enter mode.

Still need to:
- Add same functionality on when power role is sink too.
- determine what connected events would require exit mode.
- do proper cleanup on disconnect.
- implement real display port 'enter' mode for samus_pd
- test & cleanup

Additionally the USB Billboard class functionality needs to be added
but will likely do that in a separate CL.

BRANCH=none
BUG=chrome-os-partner:28342
TEST=manual,

From fruitpie,
    [Image: RO, fruitpie_v1.1.2263-d79140d-dirty 2014-09-29 17:44:15 tbroch@brisket.mtv.corp.google.com]
    [0.000383 Inits done]
    C0 st2
    Console is enabled; type HELP for help.
    > [0.250551 USB PD initialized]
    pd dualrole source
    C0 st8
    > [8.366335 PD TMOUT RX 1/1]
    RX ERR (-1)
    [8.478308 PD TMOUT RX 1/1]
    RX ERR (-1)
    [8.590280 PD TMOUT RX 1/1]
    RX ERR (-1)
    C0 st9
    Switch to 5000 V 3000 mA (for 3000/3000 mA)
    C0 st10
    C0 st11
    C0 st12
    8.867593] SVDM/4 [1] ff008081 340018d1 00000000 17000008
    8.867906] DONE
    8.871006] SVDM/2 [2] ff008082 ff010000
    8.871224] DONE
    8.875092] SVDM/7 [3] ff018083 00100081 00000000 00000000 00000000 00000000 00000000
    Entering mode w/ vdo = 00100081
    8.875492] DONE
    8.878435] SVDM/1 [4] ff018144
    8.878612] DONE

    > pe 0 dump
    SVID[0]: ff01 [0] 00100081 [1] 00000000 [2] 00000000 [3] 00000000 [4] 00000000 [5] 00000000
    MODE[0]: svid:ff01 mode:1 caps:00100081

From hoho,
    [Image: RO, hoho_v1.1.2263-d79140d-dirty 2014-09-29 17:54:59 tbroch@brisket.mtv.corp.google.com]
    [0.000375 Inits done]
    C0 st2
    Console is enabled; type HELP for help.
    > [0.250542 USB PD initialized]
    C0 st3
    [0.264637 PD TMOUT RX 1/1]
    RX ERR (-1)
    Request [1] 5V 3000mA
    C0 st4
    C0 st5
    C0 st6
    0.487451] SVDM/1 [1] ff008001
    0.487628] DONE
    0.491190] SVDM/1 [2] ff008002
    0.491346] DONE
    0.494510] SVDM/1 [3] ff018003
    0.494667] DONE
    0.498777] SVDM/1 [4] ff018104
    0.498934] DONE

Change-Id: I5e2b7802c66b8aaad97e5120dca7a02820086bc1
Signed-off-by: Todd Broch <tbroch@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/219513
Reviewed-by: Alec Berg <alecaberg@chromium.org>
2014-10-09 20:44:43 +00:00

218 lines
4.8 KiB
C

/* 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;
}
int pd_vdm(int port, int cnt, uint32_t *payload, uint32_t **rpayload)
{
return 0;
}
/* 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] = 400; /* V_rd */
}
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));
task_wait_event(100 * MSEC);
TEST_ASSERT(pd_port[0].polarity == 0);
/* We're in SNK_DISCOVERY now. Let's send the source cap. */
simulate_source_cap(0);
task_wait_event(30 * MSEC);
TEST_ASSERT(verify_goodcrc(0, PD_ROLE_SINK, pd_port[0].msg_rx_id));
/* Wait for the power request */
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);
/* We're done */
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);
/* The source cap should be sent */
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));
/* Looks good. Ack the source cap. */
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);
/* We're done */
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();
}