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 <[email protected]>
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 
drm_test_dp_mst_calc_pbn_mode(struct kunit * test)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 
dp_mst_calc_pbn_mode_desc(const struct drm_dp_mst_calc_pbn_mode_test * t,char * desc)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 
drm_test_dp_mst_calc_pbn_div(struct kunit * test)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 
203 	KUNIT_EXPECT_EQ(test, drm_dp_get_vc_payload_bw(params->link_rate, params->lane_count).full,
204 			params->expected.full);
205 }
206 
dp_mst_calc_pbn_div_desc(const struct drm_dp_mst_calc_pbn_div_test * t,char * desc)207 static void dp_mst_calc_pbn_div_desc(const struct drm_dp_mst_calc_pbn_div_test *t, char *desc)
208 {
209 	sprintf(desc, "Link rate %d lane count %d", t->link_rate, t->lane_count);
210 }
211 
212 KUNIT_ARRAY_PARAM(drm_dp_mst_calc_pbn_div, drm_dp_mst_calc_pbn_div_dp1_4_cases,
213 		  dp_mst_calc_pbn_div_desc);
214 
215 static u8 data[] = { 0xff, 0x00, 0xdd };
216 
217 struct drm_dp_mst_sideband_msg_req_test {
218 	const char *desc;
219 	const struct drm_dp_sideband_msg_req_body in;
220 };
221 
222 static const struct drm_dp_mst_sideband_msg_req_test drm_dp_mst_sideband_msg_req_cases[] = {
223 	{
224 		.desc = "DP_ENUM_PATH_RESOURCES with port number",
225 		.in = {
226 			.req_type = DP_ENUM_PATH_RESOURCES,
227 			.u.port_num.port_number = 5,
228 		},
229 	},
230 	{
231 		.desc = "DP_POWER_UP_PHY with port number",
232 		.in = {
233 			.req_type = DP_POWER_UP_PHY,
234 			.u.port_num.port_number = 5,
235 		},
236 	},
237 	{
238 		.desc = "DP_POWER_DOWN_PHY with port number",
239 		.in = {
240 			.req_type = DP_POWER_DOWN_PHY,
241 			.u.port_num.port_number = 5,
242 		},
243 	},
244 	{
245 		.desc = "DP_ALLOCATE_PAYLOAD with SDP stream sinks",
246 		.in = {
247 			.req_type = DP_ALLOCATE_PAYLOAD,
248 			.u.allocate_payload.number_sdp_streams = 3,
249 			.u.allocate_payload.sdp_stream_sink = { 1, 2, 3 },
250 		},
251 	},
252 	{
253 		.desc = "DP_ALLOCATE_PAYLOAD with port number",
254 		.in = {
255 			.req_type = DP_ALLOCATE_PAYLOAD,
256 			.u.allocate_payload.port_number = 0xf,
257 		},
258 	},
259 	{
260 		.desc = "DP_ALLOCATE_PAYLOAD with VCPI",
261 		.in = {
262 			.req_type = DP_ALLOCATE_PAYLOAD,
263 			.u.allocate_payload.vcpi = 0x7f,
264 		},
265 	},
266 	{
267 		.desc = "DP_ALLOCATE_PAYLOAD with PBN",
268 		.in = {
269 			.req_type = DP_ALLOCATE_PAYLOAD,
270 			.u.allocate_payload.pbn = U16_MAX,
271 		},
272 	},
273 	{
274 		.desc = "DP_QUERY_PAYLOAD with port number",
275 		.in = {
276 			.req_type = DP_QUERY_PAYLOAD,
277 			.u.query_payload.port_number = 0xf,
278 		},
279 	},
280 	{
281 		.desc = "DP_QUERY_PAYLOAD with VCPI",
282 		.in = {
283 			.req_type = DP_QUERY_PAYLOAD,
284 			.u.query_payload.vcpi = 0x7f,
285 		},
286 	},
287 	{
288 		.desc = "DP_REMOTE_DPCD_READ with port number",
289 		.in = {
290 			.req_type = DP_REMOTE_DPCD_READ,
291 			.u.dpcd_read.port_number = 0xf,
292 		},
293 	},
294 	{
295 		.desc = "DP_REMOTE_DPCD_READ with DPCD address",
296 		.in = {
297 			.req_type = DP_REMOTE_DPCD_READ,
298 			.u.dpcd_read.dpcd_address = 0xfedcb,
299 		},
300 	},
301 	{
302 		.desc = "DP_REMOTE_DPCD_READ with max number of bytes",
303 		.in = {
304 			.req_type = DP_REMOTE_DPCD_READ,
305 			.u.dpcd_read.num_bytes = U8_MAX,
306 		},
307 	},
308 	{
309 		.desc = "DP_REMOTE_DPCD_WRITE with port number",
310 		.in = {
311 			.req_type = DP_REMOTE_DPCD_WRITE,
312 			.u.dpcd_write.port_number = 0xf,
313 		},
314 	},
315 	{
316 		.desc = "DP_REMOTE_DPCD_WRITE with DPCD address",
317 		.in = {
318 			.req_type = DP_REMOTE_DPCD_WRITE,
319 			.u.dpcd_write.dpcd_address = 0xfedcb,
320 		},
321 	},
322 	{
323 		.desc = "DP_REMOTE_DPCD_WRITE with data array",
324 		.in = {
325 			.req_type = DP_REMOTE_DPCD_WRITE,
326 			.u.dpcd_write.num_bytes = ARRAY_SIZE(data),
327 			.u.dpcd_write.bytes = data,
328 		},
329 	},
330 	{
331 		.desc = "DP_REMOTE_I2C_READ with port number",
332 		.in = {
333 			.req_type = DP_REMOTE_I2C_READ,
334 			.u.i2c_read.port_number = 0xf,
335 		},
336 	},
337 	{
338 		.desc = "DP_REMOTE_I2C_READ with I2C device ID",
339 		.in = {
340 			.req_type = DP_REMOTE_I2C_READ,
341 			.u.i2c_read.read_i2c_device_id = 0x7f,
342 		},
343 	},
344 	{
345 		.desc = "DP_REMOTE_I2C_READ with transactions array",
346 		.in = {
347 			.req_type = DP_REMOTE_I2C_READ,
348 			.u.i2c_read.num_transactions = 3,
349 			.u.i2c_read.num_bytes_read = ARRAY_SIZE(data) * 3,
350 			.u.i2c_read.transactions = {
351 				{ .bytes = data, .num_bytes = ARRAY_SIZE(data), .i2c_dev_id = 0x7f,
352 				  .i2c_transaction_delay = 0xf, },
353 				{ .bytes = data, .num_bytes = ARRAY_SIZE(data), .i2c_dev_id = 0x7e,
354 				  .i2c_transaction_delay = 0xe, },
355 				{ .bytes = data, .num_bytes = ARRAY_SIZE(data), .i2c_dev_id = 0x7d,
356 				  .i2c_transaction_delay = 0xd, },
357 			},
358 		},
359 	},
360 	{
361 		.desc = "DP_REMOTE_I2C_WRITE with port number",
362 		.in = {
363 			.req_type = DP_REMOTE_I2C_WRITE,
364 			.u.i2c_write.port_number = 0xf,
365 		},
366 	},
367 	{
368 		.desc = "DP_REMOTE_I2C_WRITE with I2C device ID",
369 		.in = {
370 			.req_type = DP_REMOTE_I2C_WRITE,
371 			.u.i2c_write.write_i2c_device_id = 0x7f,
372 		},
373 	},
374 	{
375 		.desc = "DP_REMOTE_I2C_WRITE with data array",
376 		.in = {
377 			.req_type = DP_REMOTE_I2C_WRITE,
378 			.u.i2c_write.num_bytes = ARRAY_SIZE(data),
379 			.u.i2c_write.bytes = data,
380 		},
381 	},
382 	{
383 		.desc = "DP_QUERY_STREAM_ENC_STATUS with stream ID",
384 		.in = {
385 			.req_type = DP_QUERY_STREAM_ENC_STATUS,
386 			.u.enc_status.stream_id = 1,
387 		},
388 	},
389 	{
390 		.desc = "DP_QUERY_STREAM_ENC_STATUS with client ID",
391 		.in = {
392 			.req_type = DP_QUERY_STREAM_ENC_STATUS,
393 			.u.enc_status.client_id = { 0x4f, 0x7f, 0xb4, 0x00, 0x8c, 0x0d, 0x67 },
394 		},
395 	},
396 	{
397 		.desc = "DP_QUERY_STREAM_ENC_STATUS with stream event",
398 		.in = {
399 			.req_type = DP_QUERY_STREAM_ENC_STATUS,
400 			.u.enc_status.stream_event = 3,
401 		},
402 	},
403 	{
404 		.desc = "DP_QUERY_STREAM_ENC_STATUS with valid stream event",
405 		.in = {
406 			.req_type = DP_QUERY_STREAM_ENC_STATUS,
407 			.u.enc_status.valid_stream_event = 0,
408 		},
409 	},
410 	{
411 		.desc = "DP_QUERY_STREAM_ENC_STATUS with stream behavior",
412 		.in = {
413 			.req_type = DP_QUERY_STREAM_ENC_STATUS,
414 			.u.enc_status.stream_behavior = 3,
415 		},
416 	},
417 	{
418 		.desc = "DP_QUERY_STREAM_ENC_STATUS with a valid stream behavior",
419 		.in = {
420 			.req_type = DP_QUERY_STREAM_ENC_STATUS,
421 			.u.enc_status.valid_stream_behavior = 1,
422 		}
423 	},
424 };
425 
426 static bool
sideband_msg_req_equal(const struct drm_dp_sideband_msg_req_body * in,const struct drm_dp_sideband_msg_req_body * out)427 sideband_msg_req_equal(const struct drm_dp_sideband_msg_req_body *in,
428 		       const struct drm_dp_sideband_msg_req_body *out)
429 {
430 	const struct drm_dp_remote_i2c_read_tx *txin, *txout;
431 	int i;
432 
433 	if (in->req_type != out->req_type)
434 		return false;
435 
436 	switch (in->req_type) {
437 	/*
438 	 * Compare struct members manually for request types which can't be
439 	 * compared simply using memcmp(). This is because said request types
440 	 * contain pointers to other allocated structs
441 	 */
442 	case DP_REMOTE_I2C_READ:
443 #define IN in->u.i2c_read
444 #define OUT out->u.i2c_read
445 		if (IN.num_bytes_read != OUT.num_bytes_read ||
446 		    IN.num_transactions != OUT.num_transactions ||
447 		    IN.port_number != OUT.port_number ||
448 		    IN.read_i2c_device_id != OUT.read_i2c_device_id)
449 			return false;
450 
451 		for (i = 0; i < IN.num_transactions; i++) {
452 			txin = &IN.transactions[i];
453 			txout = &OUT.transactions[i];
454 
455 			if (txin->i2c_dev_id != txout->i2c_dev_id ||
456 			    txin->no_stop_bit != txout->no_stop_bit ||
457 			    txin->num_bytes != txout->num_bytes ||
458 			    txin->i2c_transaction_delay !=
459 			    txout->i2c_transaction_delay)
460 				return false;
461 
462 			if (memcmp(txin->bytes, txout->bytes,
463 				   txin->num_bytes) != 0)
464 				return false;
465 		}
466 		break;
467 #undef IN
468 #undef OUT
469 
470 	case DP_REMOTE_DPCD_WRITE:
471 #define IN in->u.dpcd_write
472 #define OUT out->u.dpcd_write
473 		if (IN.dpcd_address != OUT.dpcd_address ||
474 		    IN.num_bytes != OUT.num_bytes ||
475 		    IN.port_number != OUT.port_number)
476 			return false;
477 
478 		return memcmp(IN.bytes, OUT.bytes, IN.num_bytes) == 0;
479 #undef IN
480 #undef OUT
481 
482 	case DP_REMOTE_I2C_WRITE:
483 #define IN in->u.i2c_write
484 #define OUT out->u.i2c_write
485 		if (IN.port_number != OUT.port_number ||
486 		    IN.write_i2c_device_id != OUT.write_i2c_device_id ||
487 		    IN.num_bytes != OUT.num_bytes)
488 			return false;
489 
490 		return memcmp(IN.bytes, OUT.bytes, IN.num_bytes) == 0;
491 #undef IN
492 #undef OUT
493 
494 	default:
495 		return memcmp(in, out, sizeof(*in)) == 0;
496 	}
497 
498 	return true;
499 }
500 
drm_test_dp_mst_msg_printf(struct drm_printer * p,struct va_format * vaf)501 static void drm_test_dp_mst_msg_printf(struct drm_printer *p, struct va_format *vaf)
502 {
503 	struct kunit *test = p->arg;
504 
505 	kunit_err(test, "%pV", vaf);
506 }
507 
drm_test_dp_mst_sideband_msg_req_decode(struct kunit * test)508 static void drm_test_dp_mst_sideband_msg_req_decode(struct kunit *test)
509 {
510 	const struct drm_dp_mst_sideband_msg_req_test *params = test->param_value;
511 	const struct drm_dp_sideband_msg_req_body *in = &params->in;
512 	struct drm_dp_sideband_msg_req_body *out;
513 	struct drm_dp_sideband_msg_tx *txmsg;
514 	struct drm_printer p = {
515 		.printfn = drm_test_dp_mst_msg_printf,
516 		.arg = test
517 	};
518 	int i;
519 
520 	out = kunit_kzalloc(test, sizeof(*out), GFP_KERNEL);
521 	KUNIT_ASSERT_NOT_NULL(test, out);
522 
523 	txmsg = kunit_kzalloc(test, sizeof(*txmsg), GFP_KERNEL);
524 	KUNIT_ASSERT_NOT_NULL(test, txmsg);
525 
526 	drm_dp_encode_sideband_req(in, txmsg);
527 	KUNIT_EXPECT_GE_MSG(test, drm_dp_decode_sideband_req(txmsg, out), 0,
528 			    "Failed to decode sideband request");
529 
530 	if (!sideband_msg_req_equal(in, out)) {
531 		KUNIT_FAIL(test, "Encode/decode failed");
532 		kunit_err(test, "Expected:");
533 		drm_dp_dump_sideband_msg_req_body(in, 1, &p);
534 		kunit_err(test, "Got:");
535 		drm_dp_dump_sideband_msg_req_body(out, 1, &p);
536 	}
537 
538 	switch (in->req_type) {
539 	case DP_REMOTE_DPCD_WRITE:
540 		kfree(out->u.dpcd_write.bytes);
541 		break;
542 	case DP_REMOTE_I2C_READ:
543 		for (i = 0; i < out->u.i2c_read.num_transactions; i++)
544 			kfree(out->u.i2c_read.transactions[i].bytes);
545 		break;
546 	case DP_REMOTE_I2C_WRITE:
547 		kfree(out->u.i2c_write.bytes);
548 		break;
549 	}
550 }
551 
552 static void
drm_dp_mst_sideband_msg_req_desc(const struct drm_dp_mst_sideband_msg_req_test * t,char * desc)553 drm_dp_mst_sideband_msg_req_desc(const struct drm_dp_mst_sideband_msg_req_test *t, char *desc)
554 {
555 	strcpy(desc, t->desc);
556 }
557 
558 KUNIT_ARRAY_PARAM(drm_dp_mst_sideband_msg_req, drm_dp_mst_sideband_msg_req_cases,
559 		  drm_dp_mst_sideband_msg_req_desc);
560 
561 static struct kunit_case drm_dp_mst_helper_tests[] = {
562 	KUNIT_CASE_PARAM(drm_test_dp_mst_calc_pbn_mode, drm_dp_mst_calc_pbn_mode_gen_params),
563 	KUNIT_CASE_PARAM(drm_test_dp_mst_calc_pbn_div, drm_dp_mst_calc_pbn_div_gen_params),
564 	KUNIT_CASE_PARAM(drm_test_dp_mst_sideband_msg_req_decode,
565 			 drm_dp_mst_sideband_msg_req_gen_params),
566 	{ }
567 };
568 
569 static struct kunit_suite drm_dp_mst_helper_test_suite = {
570 	.name = "drm_dp_mst_helper",
571 	.test_cases = drm_dp_mst_helper_tests,
572 };
573 
574 kunit_test_suite(drm_dp_mst_helper_test_suite);
575 
576 MODULE_DESCRIPTION("Test cases for the DRM DP MST helpers");
577 MODULE_LICENSE("GPL");
578