593 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Test cases for the DRM DP MST helpers4 *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 = 68928 },29 {30 .clock = 234000,31 .bpp = 30,32 .dsc = false,33 .expected = 104734 },35 {36 .clock = 297000,37 .bpp = 24,38 .dsc = false,39 .expected = 106340 },41 {42 .clock = 332880,43 .bpp = 24,44 .dsc = true,45 .expected = 119146 },47 {48 .clock = 324540,49 .bpp = 24,50 .dsc = true,51 .expected = 116152 },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 to85 * closest value to 2 decimal places):86 * .expected = .link_rate * .lane_count * 0.9671 / 8 / 54 / 10087 * DP1.4 rates (DP Standard v2.1 2.6.4.2):88 * .expected = .link_rate * .lane_count * 0.8000 / 8 / 54 / 10089 *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 bool429sideband_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 be441 * compared simply using memcmp(). This is because said request types442 * contain pointers to other allocated structs443 */444 case DP_REMOTE_I2C_READ:445#define IN in->u.i2c_read446#define OUT out->u.i2c_read447 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 IN470#undef OUT471 472 case DP_REMOTE_DPCD_WRITE:473#define IN in->u.dpcd_write474#define OUT out->u.dpcd_write475 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 IN482#undef OUT483 484 case DP_REMOTE_I2C_WRITE:485#define IN in->u.i2c_write486#define OUT out->u.i2c_write487 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 IN494#undef OUT495 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 = ¶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 = test519 };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 void555drm_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_DESCRIPTION("Test cases for the DRM DP MST helpers");592MODULE_LICENSE("GPL");593