summaryrefslogtreecommitdiff
path: root/zephyr/test/drivers/usbc_ctvpd/src/main.c
blob: 0bd6639d8361f6902bc081fa5527707d7ac670f8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
/* Copyright 2022 The ChromiumOS Authors
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "ec_commands.h"
#include "ec_tasks.h"
#include "emul/emul_isl923x.h"
#include "emul/tcpc/emul_tcpci.h"
#include "emul/tcpc/emul_tcpci_partner_common.h"
#include "emul/tcpc/emul_tcpci_partner_snk.h"
#include "emul/tcpc/emul_tcpci_partner_src.h"
#include "host_command.h"
#include "tcpm/tcpci.h"
#include "test/drivers/stubs.h"
#include "test/drivers/test_state.h"
#include "test/drivers/utils.h"
#include "test_usbc_ctvpd.h"
#include "usb_pd_vdo.h"

#include <stdint.h>

#include <zephyr/drivers/gpio/gpio_emul.h>
#include <zephyr/kernel.h>
#include <zephyr/ztest.h>

#define TEST_PORT 0
BUILD_ASSERT(TEST_PORT == USBC_PORT_C0);

struct tcpci_cable_data charge_through_vpd = {
	.identity_vdm[VDO_INDEX_HDR] =
		VDO(USB_SID_PD, /* structured VDM */ true,
		    VDO_CMDT(CMDT_RSP_ACK) | CMD_DISCOVER_IDENT),
	.identity_vdm[VDO_INDEX_IDH] = VDO_IDH(
		/* USB host */ false, /* USB device */ false, IDH_PTYPE_VPD,
		/* modal operation */ false, USB_VID_GOOGLE),
	.identity_vdm[VDO_INDEX_CSTAT] = 0xabcdabcd,
	.identity_vdm[VDO_INDEX_PRODUCT] = VDO_PRODUCT(0x1234, 0xabcd),
	/* Hardware version 1, firmware version 2 */
	.identity_vdm[VDO_INDEX_PTYPE_UFP1_VDO] =
		VDO_VPD(1, 2, VPD_MAX_VBUS_20V, VPD_CT_CURRENT_3A,
			VPD_VBUS_IMP(10), VPD_GND_IMP(10), VPD_CTS_SUPPORTED),
	.identity_vdos = VDO_INDEX_PTYPE_UFP1_VDO + 1,
};

static void disconnect_partner_from_port(const struct emul *tcpc_emul,
					 const struct emul *charger_emul)
{
	zassert_ok(tcpci_emul_disconnect_partner(tcpc_emul));
	isl923x_emul_set_adc_vbus(charger_emul, 0);
	k_sleep(K_SECONDS(1));
}

static void add_discovery_responses(struct tcpci_partner_data *partner)
{
	partner->cable = &charge_through_vpd;
	struct tcpci_cable_data *cable = partner->cable;

	/* Add Discover Identity response */
	cable->identity_vdm[VDO_INDEX_HDR] =
		VDO(USB_SID_PD, /* structured VDM */ true,
		    VDO_CMDT(CMDT_RSP_ACK) | CMD_DISCOVER_IDENT);
	cable->identity_vdm[VDO_INDEX_IDH] = VDO_IDH(
		/* USB host */ false, /* USB device */ false, IDH_PTYPE_VPD,
		/* modal operation */ false, USB_VID_GOOGLE);
	cable->identity_vdm[VDO_INDEX_CSTAT] = 0xabcdabcd;
	cable->identity_vdm[VDO_INDEX_PRODUCT] = VDO_PRODUCT(0x1234, 0x5678);
	/* Hardware version 1, firmware version 2 */
	cable->identity_vdm[VDO_INDEX_PTYPE_UFP1_VDO] =
		VDO_VPD(1, 2, VPD_MAX_VBUS_20V, VPD_CT_CURRENT_3A,
			VPD_VBUS_IMP(10), VPD_GND_IMP(10), VPD_CTS_SUPPORTED);
	cable->identity_vdos = VDO_INDEX_PTYPE_UFP1_VDO + 1;
}

static void common_before(struct common_fixture *common)
{
	/* Set chipset to ON, this will set TCPM to DRP */
	test_set_chipset_to_s0();

	/* TODO(b/214401892): Check why need to give time TCPM to spin */
	k_sleep(K_SECONDS(1));

	connect_sink_to_port(&common->partner, common->tcpci_emul,
			     common->charger_emul);
}

static void common_after(struct common_fixture *common)
{
	disconnect_partner_from_port(common->tcpci_emul, common->charger_emul);
}

static void *usbc_ctvpd_setup(void)
{
	static struct usbc_ctvpd_fixture fixture;
	struct common_fixture *common = &fixture.common;
	struct tcpci_partner_data *partner = &common->partner;
	struct tcpci_vpd_emul_data *vpd_ext = &common->vpd_ext;

	tcpci_partner_init(partner, PD_REV30);
	partner->extensions = tcpci_vpd_emul_init(vpd_ext, partner, NULL);

	/* Get references for the emulators */
	common->tcpci_emul = EMUL_GET_USBC_BINDING(TEST_PORT, tcpc);
	common->charger_emul = EMUL_GET_USBC_BINDING(TEST_PORT, chg);

	add_discovery_responses(partner);

	return &fixture;
}

static void usbc_ctvpd_before(void *data)
{
	struct usbc_ctvpd_fixture *fixture = data;

	common_before(&fixture->common);
}

static void usbc_ctvpd_after(void *data)
{
	struct usbc_ctvpd_fixture *fixture = data;

	common_after(&fixture->common);
}

ZTEST_SUITE(usbc_ctvpd, drivers_predicate_post_main, usbc_ctvpd_setup,
	    usbc_ctvpd_before, usbc_ctvpd_after, NULL);

ZTEST_USER_F(usbc_ctvpd, verify_discovery)
{
	uint8_t response_buffer[EC_LPC_HOST_PACKET_SIZE];
	struct ec_response_typec_discovery *discovery =
		(struct ec_response_typec_discovery *)response_buffer;
	struct common_fixture *common = &fixture->common;

	host_cmd_typec_discovery(TEST_PORT, TYPEC_PARTNER_SOP_PRIME,
				 response_buffer, sizeof(response_buffer));

	/* The host command does not count the VDM header in identity_count. */
	zassert_equal(discovery->identity_count,
		      common->partner.cable->identity_vdos - 1,
		      "Expected %d identity VDOs, got %d",
		      common->partner.cable->identity_vdos - 1,
		      discovery->identity_count);
	zassert_mem_equal(discovery->discovery_vdo,
			  common->partner.cable->identity_vdm + 1,
			  discovery->identity_count *
				  sizeof(*discovery->discovery_vdo),
			  "Discovered SOP identity ACK did not match");
}

ZTEST_USER_F(usbc_ctvpd, verify_no_vconn_swap)
{
	struct ec_response_typec_status status =
		host_cmd_typec_status(TEST_PORT);
	enum pd_vconn_role initial_vconn_role = status.vconn_role;

	/* Upon initial attachment to the host port of a CT-VPD, the host (TCPM)
	 * should be Source and thus VCONN Source. After entry into
	 * CTAttached.SNK, the host should remain VCONN Source.
	 */
	zassert_equal(initial_vconn_role, PD_ROLE_VCONN_SRC);

	/* The TCPM should refuse to VCONN Swap while in CTAttached.SNK. */
	zassert_ok(tcpci_partner_send_control_msg(&fixture->common.partner,
						  PD_CTRL_VCONN_SWAP, 0));
	k_sleep(K_SECONDS(1));
	status = host_cmd_typec_status(TEST_PORT);
	zassert_equal(status.vconn_role, initial_vconn_role);
}