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
15struct 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
22static 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
55static 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
63static 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
68KUNIT_ARRAY_PARAM(drm_dp_mst_calc_pbn_mode, drm_dp_mst_calc_pbn_mode_cases,
69		  dp_mst_calc_pbn_mode_desc);
70
71struct 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
82static 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
199static 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
209static 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
214KUNIT_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
217static u8 data[] = { 0xff, 0x00, 0xdd };
218
219struct drm_dp_mst_sideband_msg_req_test {
220	const char *desc;
221	const struct drm_dp_sideband_msg_req_body in;
222};
223
224static 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
428static bool
429sideband_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
503static 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
510static 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
554static void
555drm_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
560KUNIT_ARRAY_PARAM(drm_dp_mst_sideband_msg_req, drm_dp_mst_sideband_msg_req_cases,
561		  drm_dp_mst_sideband_msg_req_desc);
562
563static 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
571static 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
583static 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
589kunit_test_suite(drm_dp_mst_helper_test_suite);
590
591MODULE_LICENSE("GPL");
592