xref: /linux/drivers/gpu/drm/tests/drm_dp_mst_helper_test.c (revision 4b660dbd9ee2059850fd30e0df420ca7a38a1856)
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 #include <kunit/test.h>
9 
10 #include <drm/display/drm_dp_mst_helper.h>
11 #include <drm/drm_print.h>
12 
13 #include "../display/drm_dp_mst_topology_internal.h"
14 
15 struct drm_dp_mst_calc_pbn_mode_test {
16 	const int clock;
17 	const int bpp;
18 	const bool dsc;
19 	const int expected;
20 };
21 
22 static const struct drm_dp_mst_calc_pbn_mode_test drm_dp_mst_calc_pbn_mode_cases[] = {
23 	{
24 		.clock = 154000,
25 		.bpp = 30,
26 		.dsc = false,
27 		.expected = 689
28 	},
29 	{
30 		.clock = 234000,
31 		.bpp = 30,
32 		.dsc = false,
33 		.expected = 1047
34 	},
35 	{
36 		.clock = 297000,
37 		.bpp = 24,
38 		.dsc = false,
39 		.expected = 1063
40 	},
41 	{
42 		.clock = 332880,
43 		.bpp = 24,
44 		.dsc = true,
45 		.expected = 1191
46 	},
47 	{
48 		.clock = 324540,
49 		.bpp = 24,
50 		.dsc = true,
51 		.expected = 1161
52 	},
53 };
54 
55 static void drm_test_dp_mst_calc_pbn_mode(struct kunit *test)
56 {
57 	const struct drm_dp_mst_calc_pbn_mode_test *params = test->param_value;
58 
59 	KUNIT_EXPECT_EQ(test, drm_dp_calc_pbn_mode(params->clock, params->bpp << 4),
60 			params->expected);
61 }
62 
63 static void dp_mst_calc_pbn_mode_desc(const struct drm_dp_mst_calc_pbn_mode_test *t, char *desc)
64 {
65 	sprintf(desc, "Clock %d BPP %d DSC %s", t->clock, t->bpp, t->dsc ? "enabled" : "disabled");
66 }
67 
68 KUNIT_ARRAY_PARAM(drm_dp_mst_calc_pbn_mode, drm_dp_mst_calc_pbn_mode_cases,
69 		  dp_mst_calc_pbn_mode_desc);
70 
71 struct drm_dp_mst_calc_pbn_div_test {
72 	int link_rate;
73 	int lane_count;
74 	fixed20_12 expected;
75 };
76 
77 #define fp_init(__int, __frac) { \
78 	.full = (__int) * (1 << 12) + \
79 		(__frac) * (1 << 12) / 100000 \
80 }
81 
82 static const struct drm_dp_mst_calc_pbn_div_test drm_dp_mst_calc_pbn_div_dp1_4_cases[] = {
83 	/*
84 	 * UHBR rates (DP Standard v2.1 2.7.6.3, specifying the rounded to
85 	 *             closest value to 2 decimal places):
86 	 * .expected = .link_rate * .lane_count * 0.9671 / 8 / 54 / 100
87 	 * DP1.4 rates (DP Standard v2.1 2.6.4.2):
88 	 * .expected = .link_rate * .lane_count * 0.8000 / 8 / 54 / 100
89 	 *
90 	 * truncated to 5 decimal places.
91 	 */
92 	{
93 		.link_rate = 2000000,
94 		.lane_count = 4,
95 		.expected = fp_init(179,  9259),  /* 179.09259 */
96 	},
97 	{
98 		.link_rate = 2000000,
99 		.lane_count = 2,
100 		.expected = fp_init(89, 54629),
101 	},
102 	{
103 		.link_rate = 2000000,
104 		.lane_count = 1,
105 		.expected = fp_init(44, 77314),
106 	},
107 	{
108 		.link_rate = 1350000,
109 		.lane_count = 4,
110 		.expected = fp_init(120, 88750),
111 	},
112 	{
113 		.link_rate = 1350000,
114 		.lane_count = 2,
115 		.expected = fp_init(60, 44375),
116 	},
117 	{
118 		.link_rate = 1350000,
119 		.lane_count = 1,
120 		.expected = fp_init(30, 22187),
121 	},
122 	{
123 		.link_rate = 1000000,
124 		.lane_count = 4,
125 		.expected = fp_init(89, 54629),
126 	},
127 	{
128 		.link_rate = 1000000,
129 		.lane_count = 2,
130 		.expected = fp_init(44, 77314),
131 	},
132 	{
133 		.link_rate = 1000000,
134 		.lane_count = 1,
135 		.expected = fp_init(22, 38657),
136 	},
137 	{
138 		.link_rate = 810000,
139 		.lane_count = 4,
140 		.expected = fp_init(60, 0),
141 	},
142 	{
143 		.link_rate = 810000,
144 		.lane_count = 2,
145 		.expected = fp_init(30, 0),
146 	},
147 	{
148 		.link_rate = 810000,
149 		.lane_count = 1,
150 		.expected = fp_init(15, 0),
151 	},
152 	{
153 		.link_rate = 540000,
154 		.lane_count = 4,
155 		.expected = fp_init(40, 0),
156 	},
157 	{
158 		.link_rate = 540000,
159 		.lane_count = 2,
160 		.expected = fp_init(20, 0),
161 	},
162 	{
163 		.link_rate = 540000,
164 		.lane_count = 1,
165 		.expected = fp_init(10, 0),
166 	},
167 	{
168 		.link_rate = 270000,
169 		.lane_count = 4,
170 		.expected = fp_init(20, 0),
171 	},
172 	{
173 		.link_rate = 270000,
174 		.lane_count = 2,
175 		.expected = fp_init(10, 0),
176 	},
177 	{
178 		.link_rate = 270000,
179 		.lane_count = 1,
180 		.expected = fp_init(5, 0),
181 	},
182 	{
183 		.link_rate = 162000,
184 		.lane_count = 4,
185 		.expected = fp_init(12, 0),
186 	},
187 	{
188 		.link_rate = 162000,
189 		.lane_count = 2,
190 		.expected = fp_init(6, 0),
191 	},
192 	{
193 		.link_rate = 162000,
194 		.lane_count = 1,
195 		.expected = fp_init(3, 0),
196 	},
197 };
198 
199 static void drm_test_dp_mst_calc_pbn_div(struct kunit *test)
200 {
201 	const struct drm_dp_mst_calc_pbn_div_test *params = test->param_value;
202 	/* mgr->dev is only needed by drm_dbg_kms(), but it's not called for the test cases. */
203 	struct drm_dp_mst_topology_mgr *mgr = test->priv;
204 
205 	KUNIT_EXPECT_EQ(test, drm_dp_get_vc_payload_bw(mgr, params->link_rate, params->lane_count).full,
206 			params->expected.full);
207 }
208 
209 static void dp_mst_calc_pbn_div_desc(const struct drm_dp_mst_calc_pbn_div_test *t, char *desc)
210 {
211 	sprintf(desc, "Link rate %d lane count %d", t->link_rate, t->lane_count);
212 }
213 
214 KUNIT_ARRAY_PARAM(drm_dp_mst_calc_pbn_div, drm_dp_mst_calc_pbn_div_dp1_4_cases,
215 		  dp_mst_calc_pbn_div_desc);
216 
217 static u8 data[] = { 0xff, 0x00, 0xdd };
218 
219 struct drm_dp_mst_sideband_msg_req_test {
220 	const char *desc;
221 	const struct drm_dp_sideband_msg_req_body in;
222 };
223 
224 static const struct drm_dp_mst_sideband_msg_req_test drm_dp_mst_sideband_msg_req_cases[] = {
225 	{
226 		.desc = "DP_ENUM_PATH_RESOURCES with port number",
227 		.in = {
228 			.req_type = DP_ENUM_PATH_RESOURCES,
229 			.u.port_num.port_number = 5,
230 		},
231 	},
232 	{
233 		.desc = "DP_POWER_UP_PHY with port number",
234 		.in = {
235 			.req_type = DP_POWER_UP_PHY,
236 			.u.port_num.port_number = 5,
237 		},
238 	},
239 	{
240 		.desc = "DP_POWER_DOWN_PHY with port number",
241 		.in = {
242 			.req_type = DP_POWER_DOWN_PHY,
243 			.u.port_num.port_number = 5,
244 		},
245 	},
246 	{
247 		.desc = "DP_ALLOCATE_PAYLOAD with SDP stream sinks",
248 		.in = {
249 			.req_type = DP_ALLOCATE_PAYLOAD,
250 			.u.allocate_payload.number_sdp_streams = 3,
251 			.u.allocate_payload.sdp_stream_sink = { 1, 2, 3 },
252 		},
253 	},
254 	{
255 		.desc = "DP_ALLOCATE_PAYLOAD with port number",
256 		.in = {
257 			.req_type = DP_ALLOCATE_PAYLOAD,
258 			.u.allocate_payload.port_number = 0xf,
259 		},
260 	},
261 	{
262 		.desc = "DP_ALLOCATE_PAYLOAD with VCPI",
263 		.in = {
264 			.req_type = DP_ALLOCATE_PAYLOAD,
265 			.u.allocate_payload.vcpi = 0x7f,
266 		},
267 	},
268 	{
269 		.desc = "DP_ALLOCATE_PAYLOAD with PBN",
270 		.in = {
271 			.req_type = DP_ALLOCATE_PAYLOAD,
272 			.u.allocate_payload.pbn = U16_MAX,
273 		},
274 	},
275 	{
276 		.desc = "DP_QUERY_PAYLOAD with port number",
277 		.in = {
278 			.req_type = DP_QUERY_PAYLOAD,
279 			.u.query_payload.port_number = 0xf,
280 		},
281 	},
282 	{
283 		.desc = "DP_QUERY_PAYLOAD with VCPI",
284 		.in = {
285 			.req_type = DP_QUERY_PAYLOAD,
286 			.u.query_payload.vcpi = 0x7f,
287 		},
288 	},
289 	{
290 		.desc = "DP_REMOTE_DPCD_READ with port number",
291 		.in = {
292 			.req_type = DP_REMOTE_DPCD_READ,
293 			.u.dpcd_read.port_number = 0xf,
294 		},
295 	},
296 	{
297 		.desc = "DP_REMOTE_DPCD_READ with DPCD address",
298 		.in = {
299 			.req_type = DP_REMOTE_DPCD_READ,
300 			.u.dpcd_read.dpcd_address = 0xfedcb,
301 		},
302 	},
303 	{
304 		.desc = "DP_REMOTE_DPCD_READ with max number of bytes",
305 		.in = {
306 			.req_type = DP_REMOTE_DPCD_READ,
307 			.u.dpcd_read.num_bytes = U8_MAX,
308 		},
309 	},
310 	{
311 		.desc = "DP_REMOTE_DPCD_WRITE with port number",
312 		.in = {
313 			.req_type = DP_REMOTE_DPCD_WRITE,
314 			.u.dpcd_write.port_number = 0xf,
315 		},
316 	},
317 	{
318 		.desc = "DP_REMOTE_DPCD_WRITE with DPCD address",
319 		.in = {
320 			.req_type = DP_REMOTE_DPCD_WRITE,
321 			.u.dpcd_write.dpcd_address = 0xfedcb,
322 		},
323 	},
324 	{
325 		.desc = "DP_REMOTE_DPCD_WRITE with data array",
326 		.in = {
327 			.req_type = DP_REMOTE_DPCD_WRITE,
328 			.u.dpcd_write.num_bytes = ARRAY_SIZE(data),
329 			.u.dpcd_write.bytes = data,
330 		},
331 	},
332 	{
333 		.desc = "DP_REMOTE_I2C_READ with port number",
334 		.in = {
335 			.req_type = DP_REMOTE_I2C_READ,
336 			.u.i2c_read.port_number = 0xf,
337 		},
338 	},
339 	{
340 		.desc = "DP_REMOTE_I2C_READ with I2C device ID",
341 		.in = {
342 			.req_type = DP_REMOTE_I2C_READ,
343 			.u.i2c_read.read_i2c_device_id = 0x7f,
344 		},
345 	},
346 	{
347 		.desc = "DP_REMOTE_I2C_READ with transactions array",
348 		.in = {
349 			.req_type = DP_REMOTE_I2C_READ,
350 			.u.i2c_read.num_transactions = 3,
351 			.u.i2c_read.num_bytes_read = ARRAY_SIZE(data) * 3,
352 			.u.i2c_read.transactions = {
353 				{ .bytes = data, .num_bytes = ARRAY_SIZE(data), .i2c_dev_id = 0x7f,
354 				  .i2c_transaction_delay = 0xf, },
355 				{ .bytes = data, .num_bytes = ARRAY_SIZE(data), .i2c_dev_id = 0x7e,
356 				  .i2c_transaction_delay = 0xe, },
357 				{ .bytes = data, .num_bytes = ARRAY_SIZE(data), .i2c_dev_id = 0x7d,
358 				  .i2c_transaction_delay = 0xd, },
359 			},
360 		},
361 	},
362 	{
363 		.desc = "DP_REMOTE_I2C_WRITE with port number",
364 		.in = {
365 			.req_type = DP_REMOTE_I2C_WRITE,
366 			.u.i2c_write.port_number = 0xf,
367 		},
368 	},
369 	{
370 		.desc = "DP_REMOTE_I2C_WRITE with I2C device ID",
371 		.in = {
372 			.req_type = DP_REMOTE_I2C_WRITE,
373 			.u.i2c_write.write_i2c_device_id = 0x7f,
374 		},
375 	},
376 	{
377 		.desc = "DP_REMOTE_I2C_WRITE with data array",
378 		.in = {
379 			.req_type = DP_REMOTE_I2C_WRITE,
380 			.u.i2c_write.num_bytes = ARRAY_SIZE(data),
381 			.u.i2c_write.bytes = data,
382 		},
383 	},
384 	{
385 		.desc = "DP_QUERY_STREAM_ENC_STATUS with stream ID",
386 		.in = {
387 			.req_type = DP_QUERY_STREAM_ENC_STATUS,
388 			.u.enc_status.stream_id = 1,
389 		},
390 	},
391 	{
392 		.desc = "DP_QUERY_STREAM_ENC_STATUS with client ID",
393 		.in = {
394 			.req_type = DP_QUERY_STREAM_ENC_STATUS,
395 			.u.enc_status.client_id = { 0x4f, 0x7f, 0xb4, 0x00, 0x8c, 0x0d, 0x67 },
396 		},
397 	},
398 	{
399 		.desc = "DP_QUERY_STREAM_ENC_STATUS with stream event",
400 		.in = {
401 			.req_type = DP_QUERY_STREAM_ENC_STATUS,
402 			.u.enc_status.stream_event = 3,
403 		},
404 	},
405 	{
406 		.desc = "DP_QUERY_STREAM_ENC_STATUS with valid stream event",
407 		.in = {
408 			.req_type = DP_QUERY_STREAM_ENC_STATUS,
409 			.u.enc_status.valid_stream_event = 0,
410 		},
411 	},
412 	{
413 		.desc = "DP_QUERY_STREAM_ENC_STATUS with stream behavior",
414 		.in = {
415 			.req_type = DP_QUERY_STREAM_ENC_STATUS,
416 			.u.enc_status.stream_behavior = 3,
417 		},
418 	},
419 	{
420 		.desc = "DP_QUERY_STREAM_ENC_STATUS with a valid stream behavior",
421 		.in = {
422 			.req_type = DP_QUERY_STREAM_ENC_STATUS,
423 			.u.enc_status.valid_stream_behavior = 1,
424 		}
425 	},
426 };
427 
428 static bool
429 sideband_msg_req_equal(const struct drm_dp_sideband_msg_req_body *in,
430 		       const struct drm_dp_sideband_msg_req_body *out)
431 {
432 	const struct drm_dp_remote_i2c_read_tx *txin, *txout;
433 	int i;
434 
435 	if (in->req_type != out->req_type)
436 		return false;
437 
438 	switch (in->req_type) {
439 	/*
440 	 * Compare struct members manually for request types which can't be
441 	 * compared simply using memcmp(). This is because said request types
442 	 * contain pointers to other allocated structs
443 	 */
444 	case DP_REMOTE_I2C_READ:
445 #define IN in->u.i2c_read
446 #define OUT out->u.i2c_read
447 		if (IN.num_bytes_read != OUT.num_bytes_read ||
448 		    IN.num_transactions != OUT.num_transactions ||
449 		    IN.port_number != OUT.port_number ||
450 		    IN.read_i2c_device_id != OUT.read_i2c_device_id)
451 			return false;
452 
453 		for (i = 0; i < IN.num_transactions; i++) {
454 			txin = &IN.transactions[i];
455 			txout = &OUT.transactions[i];
456 
457 			if (txin->i2c_dev_id != txout->i2c_dev_id ||
458 			    txin->no_stop_bit != txout->no_stop_bit ||
459 			    txin->num_bytes != txout->num_bytes ||
460 			    txin->i2c_transaction_delay !=
461 			    txout->i2c_transaction_delay)
462 				return false;
463 
464 			if (memcmp(txin->bytes, txout->bytes,
465 				   txin->num_bytes) != 0)
466 				return false;
467 		}
468 		break;
469 #undef IN
470 #undef OUT
471 
472 	case DP_REMOTE_DPCD_WRITE:
473 #define IN in->u.dpcd_write
474 #define OUT out->u.dpcd_write
475 		if (IN.dpcd_address != OUT.dpcd_address ||
476 		    IN.num_bytes != OUT.num_bytes ||
477 		    IN.port_number != OUT.port_number)
478 			return false;
479 
480 		return memcmp(IN.bytes, OUT.bytes, IN.num_bytes) == 0;
481 #undef IN
482 #undef OUT
483 
484 	case DP_REMOTE_I2C_WRITE:
485 #define IN in->u.i2c_write
486 #define OUT out->u.i2c_write
487 		if (IN.port_number != OUT.port_number ||
488 		    IN.write_i2c_device_id != OUT.write_i2c_device_id ||
489 		    IN.num_bytes != OUT.num_bytes)
490 			return false;
491 
492 		return memcmp(IN.bytes, OUT.bytes, IN.num_bytes) == 0;
493 #undef IN
494 #undef OUT
495 
496 	default:
497 		return memcmp(in, out, sizeof(*in)) == 0;
498 	}
499 
500 	return true;
501 }
502 
503 static void drm_test_dp_mst_msg_printf(struct drm_printer *p, struct va_format *vaf)
504 {
505 	struct kunit *test = p->arg;
506 
507 	kunit_err(test, "%pV", vaf);
508 }
509 
510 static void drm_test_dp_mst_sideband_msg_req_decode(struct kunit *test)
511 {
512 	const struct drm_dp_mst_sideband_msg_req_test *params = test->param_value;
513 	const struct drm_dp_sideband_msg_req_body *in = &params->in;
514 	struct drm_dp_sideband_msg_req_body *out;
515 	struct drm_dp_sideband_msg_tx *txmsg;
516 	struct drm_printer p = {
517 		.printfn = drm_test_dp_mst_msg_printf,
518 		.arg = test
519 	};
520 	int i;
521 
522 	out = kunit_kzalloc(test, sizeof(*out), GFP_KERNEL);
523 	KUNIT_ASSERT_NOT_NULL(test, out);
524 
525 	txmsg = kunit_kzalloc(test, sizeof(*txmsg), GFP_KERNEL);
526 	KUNIT_ASSERT_NOT_NULL(test, txmsg);
527 
528 	drm_dp_encode_sideband_req(in, txmsg);
529 	KUNIT_EXPECT_GE_MSG(test, drm_dp_decode_sideband_req(txmsg, out), 0,
530 			    "Failed to decode sideband request");
531 
532 	if (!sideband_msg_req_equal(in, out)) {
533 		KUNIT_FAIL(test, "Encode/decode failed");
534 		kunit_err(test, "Expected:");
535 		drm_dp_dump_sideband_msg_req_body(in, 1, &p);
536 		kunit_err(test, "Got:");
537 		drm_dp_dump_sideband_msg_req_body(out, 1, &p);
538 	}
539 
540 	switch (in->req_type) {
541 	case DP_REMOTE_DPCD_WRITE:
542 		kfree(out->u.dpcd_write.bytes);
543 		break;
544 	case DP_REMOTE_I2C_READ:
545 		for (i = 0; i < out->u.i2c_read.num_transactions; i++)
546 			kfree(out->u.i2c_read.transactions[i].bytes);
547 		break;
548 	case DP_REMOTE_I2C_WRITE:
549 		kfree(out->u.i2c_write.bytes);
550 		break;
551 	}
552 }
553 
554 static void
555 drm_dp_mst_sideband_msg_req_desc(const struct drm_dp_mst_sideband_msg_req_test *t, char *desc)
556 {
557 	strcpy(desc, t->desc);
558 }
559 
560 KUNIT_ARRAY_PARAM(drm_dp_mst_sideband_msg_req, drm_dp_mst_sideband_msg_req_cases,
561 		  drm_dp_mst_sideband_msg_req_desc);
562 
563 static struct kunit_case drm_dp_mst_helper_tests[] = {
564 	KUNIT_CASE_PARAM(drm_test_dp_mst_calc_pbn_mode, drm_dp_mst_calc_pbn_mode_gen_params),
565 	KUNIT_CASE_PARAM(drm_test_dp_mst_calc_pbn_div, drm_dp_mst_calc_pbn_div_gen_params),
566 	KUNIT_CASE_PARAM(drm_test_dp_mst_sideband_msg_req_decode,
567 			 drm_dp_mst_sideband_msg_req_gen_params),
568 	{ }
569 };
570 
571 static int drm_dp_mst_helper_tests_init(struct kunit *test)
572 {
573 	struct drm_dp_mst_topology_mgr *mgr;
574 
575 	mgr = kunit_kzalloc(test, sizeof(*mgr), GFP_KERNEL);
576 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mgr);
577 
578 	test->priv = mgr;
579 
580 	return 0;
581 }
582 
583 static struct kunit_suite drm_dp_mst_helper_test_suite = {
584 	.name = "drm_dp_mst_helper",
585 	.init = drm_dp_mst_helper_tests_init,
586 	.test_cases = drm_dp_mst_helper_tests,
587 };
588 
589 kunit_test_suite(drm_dp_mst_helper_test_suite);
590 
591 MODULE_LICENSE("GPL");
592