1 // SPDX-License-Identifier: GPL-2.0-only
3 * Test cases for the DRM DP MST helpers
8 #include <kunit/test.h>
10 #include <drm/display/drm_dp_mst_helper.h>
11 #include <drm/drm_print.h>
13 #include "../display/drm_dp_mst_topology_internal.h"
15 struct drm_dp_mst_calc_pbn_mode_test {
22 static const struct drm_dp_mst_calc_pbn_mode_test drm_dp_mst_calc_pbn_mode_cases[] = {
55 static void drm_test_dp_mst_calc_pbn_mode(struct kunit *test)
57 const struct drm_dp_mst_calc_pbn_mode_test *params = test->param_value;
59 KUNIT_EXPECT_EQ(test, drm_dp_calc_pbn_mode(params->clock, params->bpp << 4),
63 static void dp_mst_calc_pbn_mode_desc(const struct drm_dp_mst_calc_pbn_mode_test *t, char *desc)
65 sprintf(desc, "Clock %d BPP %d DSC %s", t->clock, t->bpp, t->dsc ? "enabled" : "disabled");
68 KUNIT_ARRAY_PARAM(drm_dp_mst_calc_pbn_mode, drm_dp_mst_calc_pbn_mode_cases,
69 dp_mst_calc_pbn_mode_desc);
71 struct drm_dp_mst_calc_pbn_div_test {
77 #define fp_init(__int, __frac) { \
78 .full = (__int) * (1 << 12) + \
79 (__frac) * (1 << 12) / 100000 \
82 static const struct drm_dp_mst_calc_pbn_div_test drm_dp_mst_calc_pbn_div_dp1_4_cases[] = {
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
90 * truncated to 5 decimal places.
95 .expected = fp_init(179, 9259), /* 179.09259 */
100 .expected = fp_init(89, 54629),
103 .link_rate = 2000000,
105 .expected = fp_init(44, 77314),
108 .link_rate = 1350000,
110 .expected = fp_init(120, 88750),
113 .link_rate = 1350000,
115 .expected = fp_init(60, 44375),
118 .link_rate = 1350000,
120 .expected = fp_init(30, 22187),
123 .link_rate = 1000000,
125 .expected = fp_init(89, 54629),
128 .link_rate = 1000000,
130 .expected = fp_init(44, 77314),
133 .link_rate = 1000000,
135 .expected = fp_init(22, 38657),
140 .expected = fp_init(60, 0),
145 .expected = fp_init(30, 0),
150 .expected = fp_init(15, 0),
155 .expected = fp_init(40, 0),
160 .expected = fp_init(20, 0),
165 .expected = fp_init(10, 0),
170 .expected = fp_init(20, 0),
175 .expected = fp_init(10, 0),
180 .expected = fp_init(5, 0),
185 .expected = fp_init(12, 0),
190 .expected = fp_init(6, 0),
195 .expected = fp_init(3, 0),
199 static void drm_test_dp_mst_calc_pbn_div(struct kunit *test)
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;
205 KUNIT_EXPECT_EQ(test, drm_dp_get_vc_payload_bw(mgr, params->link_rate, params->lane_count).full,
206 params->expected.full);
209 static void dp_mst_calc_pbn_div_desc(const struct drm_dp_mst_calc_pbn_div_test *t, char *desc)
211 sprintf(desc, "Link rate %d lane count %d", t->link_rate, t->lane_count);
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);
217 static u8 data[] = { 0xff, 0x00, 0xdd };
219 struct drm_dp_mst_sideband_msg_req_test {
221 const struct drm_dp_sideband_msg_req_body in;
224 static const struct drm_dp_mst_sideband_msg_req_test drm_dp_mst_sideband_msg_req_cases[] = {
226 .desc = "DP_ENUM_PATH_RESOURCES with port number",
228 .req_type = DP_ENUM_PATH_RESOURCES,
229 .u.port_num.port_number = 5,
233 .desc = "DP_POWER_UP_PHY with port number",
235 .req_type = DP_POWER_UP_PHY,
236 .u.port_num.port_number = 5,
240 .desc = "DP_POWER_DOWN_PHY with port number",
242 .req_type = DP_POWER_DOWN_PHY,
243 .u.port_num.port_number = 5,
247 .desc = "DP_ALLOCATE_PAYLOAD with SDP stream sinks",
249 .req_type = DP_ALLOCATE_PAYLOAD,
250 .u.allocate_payload.number_sdp_streams = 3,
251 .u.allocate_payload.sdp_stream_sink = { 1, 2, 3 },
255 .desc = "DP_ALLOCATE_PAYLOAD with port number",
257 .req_type = DP_ALLOCATE_PAYLOAD,
258 .u.allocate_payload.port_number = 0xf,
262 .desc = "DP_ALLOCATE_PAYLOAD with VCPI",
264 .req_type = DP_ALLOCATE_PAYLOAD,
265 .u.allocate_payload.vcpi = 0x7f,
269 .desc = "DP_ALLOCATE_PAYLOAD with PBN",
271 .req_type = DP_ALLOCATE_PAYLOAD,
272 .u.allocate_payload.pbn = U16_MAX,
276 .desc = "DP_QUERY_PAYLOAD with port number",
278 .req_type = DP_QUERY_PAYLOAD,
279 .u.query_payload.port_number = 0xf,
283 .desc = "DP_QUERY_PAYLOAD with VCPI",
285 .req_type = DP_QUERY_PAYLOAD,
286 .u.query_payload.vcpi = 0x7f,
290 .desc = "DP_REMOTE_DPCD_READ with port number",
292 .req_type = DP_REMOTE_DPCD_READ,
293 .u.dpcd_read.port_number = 0xf,
297 .desc = "DP_REMOTE_DPCD_READ with DPCD address",
299 .req_type = DP_REMOTE_DPCD_READ,
300 .u.dpcd_read.dpcd_address = 0xfedcb,
304 .desc = "DP_REMOTE_DPCD_READ with max number of bytes",
306 .req_type = DP_REMOTE_DPCD_READ,
307 .u.dpcd_read.num_bytes = U8_MAX,
311 .desc = "DP_REMOTE_DPCD_WRITE with port number",
313 .req_type = DP_REMOTE_DPCD_WRITE,
314 .u.dpcd_write.port_number = 0xf,
318 .desc = "DP_REMOTE_DPCD_WRITE with DPCD address",
320 .req_type = DP_REMOTE_DPCD_WRITE,
321 .u.dpcd_write.dpcd_address = 0xfedcb,
325 .desc = "DP_REMOTE_DPCD_WRITE with data array",
327 .req_type = DP_REMOTE_DPCD_WRITE,
328 .u.dpcd_write.num_bytes = ARRAY_SIZE(data),
329 .u.dpcd_write.bytes = data,
333 .desc = "DP_REMOTE_I2C_READ with port number",
335 .req_type = DP_REMOTE_I2C_READ,
336 .u.i2c_read.port_number = 0xf,
340 .desc = "DP_REMOTE_I2C_READ with I2C device ID",
342 .req_type = DP_REMOTE_I2C_READ,
343 .u.i2c_read.read_i2c_device_id = 0x7f,
347 .desc = "DP_REMOTE_I2C_READ with transactions array",
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, },
363 .desc = "DP_REMOTE_I2C_WRITE with port number",
365 .req_type = DP_REMOTE_I2C_WRITE,
366 .u.i2c_write.port_number = 0xf,
370 .desc = "DP_REMOTE_I2C_WRITE with I2C device ID",
372 .req_type = DP_REMOTE_I2C_WRITE,
373 .u.i2c_write.write_i2c_device_id = 0x7f,
377 .desc = "DP_REMOTE_I2C_WRITE with data array",
379 .req_type = DP_REMOTE_I2C_WRITE,
380 .u.i2c_write.num_bytes = ARRAY_SIZE(data),
381 .u.i2c_write.bytes = data,
385 .desc = "DP_QUERY_STREAM_ENC_STATUS with stream ID",
387 .req_type = DP_QUERY_STREAM_ENC_STATUS,
388 .u.enc_status.stream_id = 1,
392 .desc = "DP_QUERY_STREAM_ENC_STATUS with client ID",
394 .req_type = DP_QUERY_STREAM_ENC_STATUS,
395 .u.enc_status.client_id = { 0x4f, 0x7f, 0xb4, 0x00, 0x8c, 0x0d, 0x67 },
399 .desc = "DP_QUERY_STREAM_ENC_STATUS with stream event",
401 .req_type = DP_QUERY_STREAM_ENC_STATUS,
402 .u.enc_status.stream_event = 3,
406 .desc = "DP_QUERY_STREAM_ENC_STATUS with valid stream event",
408 .req_type = DP_QUERY_STREAM_ENC_STATUS,
409 .u.enc_status.valid_stream_event = 0,
413 .desc = "DP_QUERY_STREAM_ENC_STATUS with stream behavior",
415 .req_type = DP_QUERY_STREAM_ENC_STATUS,
416 .u.enc_status.stream_behavior = 3,
420 .desc = "DP_QUERY_STREAM_ENC_STATUS with a valid stream behavior",
422 .req_type = DP_QUERY_STREAM_ENC_STATUS,
423 .u.enc_status.valid_stream_behavior = 1,
429 sideband_msg_req_equal(const struct drm_dp_sideband_msg_req_body *in,
430 const struct drm_dp_sideband_msg_req_body *out)
432 const struct drm_dp_remote_i2c_read_tx *txin, *txout;
435 if (in->req_type != out->req_type)
438 switch (in->req_type) {
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
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)
453 for (i = 0; i < IN.num_transactions; i++) {
454 txin = &IN.transactions[i];
455 txout = &OUT.transactions[i];
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)
464 if (memcmp(txin->bytes, txout->bytes,
465 txin->num_bytes) != 0)
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)
480 return memcmp(IN.bytes, OUT.bytes, IN.num_bytes) == 0;
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)
492 return memcmp(IN.bytes, OUT.bytes, IN.num_bytes) == 0;
497 return memcmp(in, out, sizeof(*in)) == 0;
503 static void drm_test_dp_mst_msg_printf(struct drm_printer *p, struct va_format *vaf)
505 struct kunit *test = p->arg;
507 kunit_err(test, "%pV", vaf);
510 static void drm_test_dp_mst_sideband_msg_req_decode(struct kunit *test)
512 const struct drm_dp_mst_sideband_msg_req_test *params = test->param_value;
513 const struct drm_dp_sideband_msg_req_body *in = ¶ms->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,
522 out = kunit_kzalloc(test, sizeof(*out), GFP_KERNEL);
523 KUNIT_ASSERT_NOT_NULL(test, out);
525 txmsg = kunit_kzalloc(test, sizeof(*txmsg), GFP_KERNEL);
526 KUNIT_ASSERT_NOT_NULL(test, txmsg);
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");
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);
540 switch (in->req_type) {
541 case DP_REMOTE_DPCD_WRITE:
542 kfree(out->u.dpcd_write.bytes);
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);
548 case DP_REMOTE_I2C_WRITE:
549 kfree(out->u.i2c_write.bytes);
555 drm_dp_mst_sideband_msg_req_desc(const struct drm_dp_mst_sideband_msg_req_test *t, char *desc)
557 strcpy(desc, t->desc);
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);
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),
571 static int drm_dp_mst_helper_tests_init(struct kunit *test)
573 struct drm_dp_mst_topology_mgr *mgr;
575 mgr = kunit_kzalloc(test, sizeof(*mgr), GFP_KERNEL);
576 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mgr);
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,
589 kunit_test_suite(drm_dp_mst_helper_test_suite);
591 MODULE_DESCRIPTION("Test cases for the DRM DP MST helpers");
592 MODULE_LICENSE("GPL");