1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Test cases for the DRM DP MST helpers
4  *
5  * Copyright (c) 2022 Maíra Canal <mairacanal@riseup.net>
6  */
7 
8 #define PREFIX_STR "[drm_dp_mst_helper]"
9 
10 #include <kunit/test.h>
11 
12 #include <linux/random.h>
13 
14 #include <drm/display/drm_dp_mst_helper.h>
15 #include <drm/drm_print.h>
16 
17 #include "../display/drm_dp_mst_topology_internal.h"
18 
19 static void drm_test_dp_mst_calc_pbn_mode(struct kunit *test)
20 {
21 	int pbn, i;
22 	const struct {
23 		int rate;
24 		int bpp;
25 		int expected;
26 		bool dsc;
27 	} test_params[] = {
28 		{ 154000, 30, 689, false },
29 		{ 234000, 30, 1047, false },
30 		{ 297000, 24, 1063, false },
31 		{ 332880, 24, 50, true },
32 		{ 324540, 24, 49, true },
33 	};
34 
35 	for (i = 0; i < ARRAY_SIZE(test_params); i++) {
36 		pbn = drm_dp_calc_pbn_mode(test_params[i].rate,
37 					   test_params[i].bpp,
38 					   test_params[i].dsc);
39 		KUNIT_EXPECT_EQ_MSG(test, pbn, test_params[i].expected,
40 				    "Expected PBN %d for clock %d bpp %d, got %d\n",
41 		     test_params[i].expected, test_params[i].rate,
42 		     test_params[i].bpp, pbn);
43 	}
44 }
45 
46 static bool
47 sideband_msg_req_equal(const struct drm_dp_sideband_msg_req_body *in,
48 		       const struct drm_dp_sideband_msg_req_body *out)
49 {
50 	const struct drm_dp_remote_i2c_read_tx *txin, *txout;
51 	int i;
52 
53 	if (in->req_type != out->req_type)
54 		return false;
55 
56 	switch (in->req_type) {
57 	/*
58 	 * Compare struct members manually for request types which can't be
59 	 * compared simply using memcmp(). This is because said request types
60 	 * contain pointers to other allocated structs
61 	 */
62 	case DP_REMOTE_I2C_READ:
63 #define IN in->u.i2c_read
64 #define OUT out->u.i2c_read
65 		if (IN.num_bytes_read != OUT.num_bytes_read ||
66 		    IN.num_transactions != OUT.num_transactions ||
67 		    IN.port_number != OUT.port_number ||
68 		    IN.read_i2c_device_id != OUT.read_i2c_device_id)
69 			return false;
70 
71 		for (i = 0; i < IN.num_transactions; i++) {
72 			txin = &IN.transactions[i];
73 			txout = &OUT.transactions[i];
74 
75 			if (txin->i2c_dev_id != txout->i2c_dev_id ||
76 			    txin->no_stop_bit != txout->no_stop_bit ||
77 			    txin->num_bytes != txout->num_bytes ||
78 			    txin->i2c_transaction_delay !=
79 			    txout->i2c_transaction_delay)
80 				return false;
81 
82 			if (memcmp(txin->bytes, txout->bytes,
83 				   txin->num_bytes) != 0)
84 				return false;
85 		}
86 		break;
87 #undef IN
88 #undef OUT
89 
90 	case DP_REMOTE_DPCD_WRITE:
91 #define IN in->u.dpcd_write
92 #define OUT out->u.dpcd_write
93 		if (IN.dpcd_address != OUT.dpcd_address ||
94 		    IN.num_bytes != OUT.num_bytes ||
95 		    IN.port_number != OUT.port_number)
96 			return false;
97 
98 		return memcmp(IN.bytes, OUT.bytes, IN.num_bytes) == 0;
99 #undef IN
100 #undef OUT
101 
102 	case DP_REMOTE_I2C_WRITE:
103 #define IN in->u.i2c_write
104 #define OUT out->u.i2c_write
105 		if (IN.port_number != OUT.port_number ||
106 		    IN.write_i2c_device_id != OUT.write_i2c_device_id ||
107 		    IN.num_bytes != OUT.num_bytes)
108 			return false;
109 
110 		return memcmp(IN.bytes, OUT.bytes, IN.num_bytes) == 0;
111 #undef IN
112 #undef OUT
113 
114 	default:
115 		return memcmp(in, out, sizeof(*in)) == 0;
116 	}
117 
118 	return true;
119 }
120 
121 static bool
122 sideband_msg_req_encode_decode(struct drm_dp_sideband_msg_req_body *in)
123 {
124 	struct drm_dp_sideband_msg_req_body *out;
125 	struct drm_printer p = drm_err_printer(PREFIX_STR);
126 	struct drm_dp_sideband_msg_tx *txmsg;
127 	int i, ret;
128 	bool result = true;
129 
130 	out = kzalloc(sizeof(*out), GFP_KERNEL);
131 	if (!out)
132 		return false;
133 
134 	txmsg = kzalloc(sizeof(*txmsg), GFP_KERNEL);
135 	if (!txmsg) {
136 		kfree(out);
137 		return false;
138 	}
139 
140 	drm_dp_encode_sideband_req(in, txmsg);
141 	ret = drm_dp_decode_sideband_req(txmsg, out);
142 	if (ret < 0) {
143 		drm_printf(&p, "Failed to decode sideband request: %d\n",
144 			   ret);
145 		result = false;
146 		goto out;
147 	}
148 
149 	if (!sideband_msg_req_equal(in, out)) {
150 		drm_printf(&p, "Encode/decode failed, expected:\n");
151 		drm_dp_dump_sideband_msg_req_body(in, 1, &p);
152 		drm_printf(&p, "Got:\n");
153 		drm_dp_dump_sideband_msg_req_body(out, 1, &p);
154 		result = false;
155 		goto out;
156 	}
157 
158 	switch (in->req_type) {
159 	case DP_REMOTE_DPCD_WRITE:
160 		kfree(out->u.dpcd_write.bytes);
161 		break;
162 	case DP_REMOTE_I2C_READ:
163 		for (i = 0; i < out->u.i2c_read.num_transactions; i++)
164 			kfree(out->u.i2c_read.transactions[i].bytes);
165 		break;
166 	case DP_REMOTE_I2C_WRITE:
167 		kfree(out->u.i2c_write.bytes);
168 		break;
169 	}
170 
171 	/* Clear everything but the req_type for the input */
172 	memset(&in->u, 0, sizeof(in->u));
173 
174 out:
175 	kfree(out);
176 	kfree(txmsg);
177 	return result;
178 }
179 
180 static void drm_test_dp_mst_sideband_msg_req_decode(struct kunit *test)
181 {
182 	struct drm_dp_sideband_msg_req_body in = { 0 };
183 	u8 data[] = { 0xff, 0x0, 0xdd };
184 	int i;
185 
186 	in.req_type = DP_ENUM_PATH_RESOURCES;
187 	in.u.port_num.port_number = 5;
188 	KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in));
189 
190 	in.req_type = DP_POWER_UP_PHY;
191 	in.u.port_num.port_number = 5;
192 	KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in));
193 
194 	in.req_type = DP_POWER_DOWN_PHY;
195 	in.u.port_num.port_number = 5;
196 	KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in));
197 
198 	in.req_type = DP_ALLOCATE_PAYLOAD;
199 	in.u.allocate_payload.number_sdp_streams = 3;
200 	for (i = 0; i < in.u.allocate_payload.number_sdp_streams; i++)
201 		in.u.allocate_payload.sdp_stream_sink[i] = i + 1;
202 	KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in));
203 	in.u.allocate_payload.port_number = 0xf;
204 	KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in));
205 	in.u.allocate_payload.vcpi = 0x7f;
206 	KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in));
207 	in.u.allocate_payload.pbn = U16_MAX;
208 	KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in));
209 
210 	in.req_type = DP_QUERY_PAYLOAD;
211 	in.u.query_payload.port_number = 0xf;
212 	KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in));
213 	in.u.query_payload.vcpi = 0x7f;
214 	KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in));
215 
216 	in.req_type = DP_REMOTE_DPCD_READ;
217 	in.u.dpcd_read.port_number = 0xf;
218 	KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in));
219 	in.u.dpcd_read.dpcd_address = 0xfedcb;
220 	KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in));
221 	in.u.dpcd_read.num_bytes = U8_MAX;
222 	KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in));
223 
224 	in.req_type = DP_REMOTE_DPCD_WRITE;
225 	in.u.dpcd_write.port_number = 0xf;
226 	KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in));
227 	in.u.dpcd_write.dpcd_address = 0xfedcb;
228 	KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in));
229 	in.u.dpcd_write.num_bytes = ARRAY_SIZE(data);
230 	in.u.dpcd_write.bytes = data;
231 	KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in));
232 
233 	in.req_type = DP_REMOTE_I2C_READ;
234 	in.u.i2c_read.port_number = 0xf;
235 	KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in));
236 	in.u.i2c_read.read_i2c_device_id = 0x7f;
237 	KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in));
238 	in.u.i2c_read.num_transactions = 3;
239 	in.u.i2c_read.num_bytes_read = ARRAY_SIZE(data) * 3;
240 	for (i = 0; i < in.u.i2c_read.num_transactions; i++) {
241 		in.u.i2c_read.transactions[i].bytes = data;
242 		in.u.i2c_read.transactions[i].num_bytes = ARRAY_SIZE(data);
243 		in.u.i2c_read.transactions[i].i2c_dev_id = 0x7f & ~i;
244 		in.u.i2c_read.transactions[i].i2c_transaction_delay = 0xf & ~i;
245 	}
246 	KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in));
247 
248 	in.req_type = DP_REMOTE_I2C_WRITE;
249 	in.u.i2c_write.port_number = 0xf;
250 	KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in));
251 	in.u.i2c_write.write_i2c_device_id = 0x7f;
252 	KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in));
253 	in.u.i2c_write.num_bytes = ARRAY_SIZE(data);
254 	in.u.i2c_write.bytes = data;
255 	KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in));
256 
257 	in.req_type = DP_QUERY_STREAM_ENC_STATUS;
258 	in.u.enc_status.stream_id = 1;
259 	KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in));
260 	get_random_bytes(in.u.enc_status.client_id,
261 			 sizeof(in.u.enc_status.client_id));
262 	KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in));
263 	in.u.enc_status.stream_event = 3;
264 	KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in));
265 	in.u.enc_status.valid_stream_event = 0;
266 	KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in));
267 	in.u.enc_status.stream_behavior = 3;
268 	KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in));
269 	in.u.enc_status.valid_stream_behavior = 1;
270 	KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in));
271 }
272 
273 static struct kunit_case drm_dp_mst_helper_tests[] = {
274 	KUNIT_CASE(drm_test_dp_mst_calc_pbn_mode),
275 	KUNIT_CASE(drm_test_dp_mst_sideband_msg_req_decode),
276 	{ }
277 };
278 
279 static struct kunit_suite drm_dp_mst_helper_test_suite = {
280 	.name = "drm_dp_mst_helper",
281 	.test_cases = drm_dp_mst_helper_tests,
282 };
283 
284 kunit_test_suite(drm_dp_mst_helper_test_suite);
285 
286 MODULE_LICENSE("GPL");
287