File Index
Files and directories
Sign in
FILE

drm_dp_mst_helper_test.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/tests/drm_dp_mst_helper_test.c C
  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
203	KUNIT_EXPECT_EQ(test, drm_dp_get_vc_payload_bw(params->link_rate, params->lane_count).full,
204			params->expected.full);
205}
206
207static 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
212KUNIT_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
215static u8 data[] = { 0xff, 0x00, 0xdd };
216
217struct drm_dp_mst_sideband_msg_req_test {
218	const char *desc;
219	const struct drm_dp_sideband_msg_req_body in;
220};
221
222static 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
426static bool
427sideband_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
501static 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
508static 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
552static void
553drm_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
558KUNIT_ARRAY_PARAM(drm_dp_mst_sideband_msg_req, drm_dp_mst_sideband_msg_req_cases,
559		  drm_dp_mst_sideband_msg_req_desc);
560
561static 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
569static 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
574kunit_test_suite(drm_dp_mst_helper_test_suite);
575
576MODULE_DESCRIPTION("Test cases for the DRM DP MST helpers");
577MODULE_LICENSE("GPL");
~/ Read-only file preview.