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 203 KUNIT_EXPECT_EQ(test, drm_dp_get_vc_payload_bw(params->link_rate, params->lane_count).full, 204 params->expected.full); 205 } 206 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 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 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 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 = ¶ms->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 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