]> Git Repo - linux.git/blob - drivers/gpu/drm/tests/drm_dp_mst_helper_test.c
Merge tag 'bootconfig-fixes-v6.13' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux.git] / drivers / gpu / drm / tests / drm_dp_mst_helper_test.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 <[email protected]>
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 = &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
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");
This page took 0.065168 seconds and 4 git commands to generate.