drm/tests: helpers: Add atomic helpers
[linux-2.6-microblaze.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 <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 = &params->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");