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 = ¶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, 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