1 // SPDX-License-Identifier: GPL-2.0-only
3 * Test cases for the DRM DP MST helpers
8 #include <kunit/test.h>
10 #include <drm/display/drm_dp_mst_helper.h>
11 #include <drm/drm_print.h>
13 #include "../display/drm_dp_mst_topology_internal.h"
15 struct drm_dp_mst_calc_pbn_mode_test {
22 static const struct drm_dp_mst_calc_pbn_mode_test drm_dp_mst_calc_pbn_mode_cases[] = {
55 static void drm_test_dp_mst_calc_pbn_mode(struct kunit *test)
57 const struct drm_dp_mst_calc_pbn_mode_test *params = test->param_value;
59 KUNIT_EXPECT_EQ(test, drm_dp_calc_pbn_mode(params->clock, params->bpp, params->dsc),
63 static void dp_mst_calc_pbn_mode_desc(const struct drm_dp_mst_calc_pbn_mode_test *t, char *desc)
65 sprintf(desc, "Clock %d BPP %d DSC %s", t->clock, t->bpp, t->dsc ? "enabled" : "disabled");
68 KUNIT_ARRAY_PARAM(drm_dp_mst_calc_pbn_mode, drm_dp_mst_calc_pbn_mode_cases,
69 dp_mst_calc_pbn_mode_desc);
71 static u8 data[] = { 0xff, 0x00, 0xdd };
73 struct drm_dp_mst_sideband_msg_req_test {
75 const struct drm_dp_sideband_msg_req_body in;
78 static const struct drm_dp_mst_sideband_msg_req_test drm_dp_mst_sideband_msg_req_cases[] = {
80 .desc = "DP_ENUM_PATH_RESOURCES with port number",
82 .req_type = DP_ENUM_PATH_RESOURCES,
83 .u.port_num.port_number = 5,
87 .desc = "DP_POWER_UP_PHY with port number",
89 .req_type = DP_POWER_UP_PHY,
90 .u.port_num.port_number = 5,
94 .desc = "DP_POWER_DOWN_PHY with port number",
96 .req_type = DP_POWER_DOWN_PHY,
97 .u.port_num.port_number = 5,
101 .desc = "DP_ALLOCATE_PAYLOAD with SDP stream sinks",
103 .req_type = DP_ALLOCATE_PAYLOAD,
104 .u.allocate_payload.number_sdp_streams = 3,
105 .u.allocate_payload.sdp_stream_sink = { 1, 2, 3 },
109 .desc = "DP_ALLOCATE_PAYLOAD with port number",
111 .req_type = DP_ALLOCATE_PAYLOAD,
112 .u.allocate_payload.port_number = 0xf,
116 .desc = "DP_ALLOCATE_PAYLOAD with VCPI",
118 .req_type = DP_ALLOCATE_PAYLOAD,
119 .u.allocate_payload.vcpi = 0x7f,
123 .desc = "DP_ALLOCATE_PAYLOAD with PBN",
125 .req_type = DP_ALLOCATE_PAYLOAD,
126 .u.allocate_payload.pbn = U16_MAX,
130 .desc = "DP_QUERY_PAYLOAD with port number",
132 .req_type = DP_QUERY_PAYLOAD,
133 .u.query_payload.port_number = 0xf,
137 .desc = "DP_QUERY_PAYLOAD with VCPI",
139 .req_type = DP_QUERY_PAYLOAD,
140 .u.query_payload.vcpi = 0x7f,
144 .desc = "DP_REMOTE_DPCD_READ with port number",
146 .req_type = DP_REMOTE_DPCD_READ,
147 .u.dpcd_read.port_number = 0xf,
151 .desc = "DP_REMOTE_DPCD_READ with DPCD address",
153 .req_type = DP_REMOTE_DPCD_READ,
154 .u.dpcd_read.dpcd_address = 0xfedcb,
158 .desc = "DP_REMOTE_DPCD_READ with max number of bytes",
160 .req_type = DP_REMOTE_DPCD_READ,
161 .u.dpcd_read.num_bytes = U8_MAX,
165 .desc = "DP_REMOTE_DPCD_WRITE with port number",
167 .req_type = DP_REMOTE_DPCD_WRITE,
168 .u.dpcd_write.port_number = 0xf,
172 .desc = "DP_REMOTE_DPCD_WRITE with DPCD address",
174 .req_type = DP_REMOTE_DPCD_WRITE,
175 .u.dpcd_write.dpcd_address = 0xfedcb,
179 .desc = "DP_REMOTE_DPCD_WRITE with data array",
181 .req_type = DP_REMOTE_DPCD_WRITE,
182 .u.dpcd_write.num_bytes = ARRAY_SIZE(data),
183 .u.dpcd_write.bytes = data,
187 .desc = "DP_REMOTE_I2C_READ with port number",
189 .req_type = DP_REMOTE_I2C_READ,
190 .u.i2c_read.port_number = 0xf,
194 .desc = "DP_REMOTE_I2C_READ with I2C device ID",
196 .req_type = DP_REMOTE_I2C_READ,
197 .u.i2c_read.read_i2c_device_id = 0x7f,
201 .desc = "DP_REMOTE_I2C_READ with transactions array",
203 .req_type = DP_REMOTE_I2C_READ,
204 .u.i2c_read.num_transactions = 3,
205 .u.i2c_read.num_bytes_read = ARRAY_SIZE(data) * 3,
206 .u.i2c_read.transactions = {
207 { .bytes = data, .num_bytes = ARRAY_SIZE(data), .i2c_dev_id = 0x7f,
208 .i2c_transaction_delay = 0xf, },
209 { .bytes = data, .num_bytes = ARRAY_SIZE(data), .i2c_dev_id = 0x7e,
210 .i2c_transaction_delay = 0xe, },
211 { .bytes = data, .num_bytes = ARRAY_SIZE(data), .i2c_dev_id = 0x7d,
212 .i2c_transaction_delay = 0xd, },
217 .desc = "DP_REMOTE_I2C_WRITE with port number",
219 .req_type = DP_REMOTE_I2C_WRITE,
220 .u.i2c_write.port_number = 0xf,
224 .desc = "DP_REMOTE_I2C_WRITE with I2C device ID",
226 .req_type = DP_REMOTE_I2C_WRITE,
227 .u.i2c_write.write_i2c_device_id = 0x7f,
231 .desc = "DP_REMOTE_I2C_WRITE with data array",
233 .req_type = DP_REMOTE_I2C_WRITE,
234 .u.i2c_write.num_bytes = ARRAY_SIZE(data),
235 .u.i2c_write.bytes = data,
239 .desc = "DP_QUERY_STREAM_ENC_STATUS with stream ID",
241 .req_type = DP_QUERY_STREAM_ENC_STATUS,
242 .u.enc_status.stream_id = 1,
246 .desc = "DP_QUERY_STREAM_ENC_STATUS with client ID",
248 .req_type = DP_QUERY_STREAM_ENC_STATUS,
249 .u.enc_status.client_id = { 0x4f, 0x7f, 0xb4, 0x00, 0x8c, 0x0d, 0x67 },
253 .desc = "DP_QUERY_STREAM_ENC_STATUS with stream event",
255 .req_type = DP_QUERY_STREAM_ENC_STATUS,
256 .u.enc_status.stream_event = 3,
260 .desc = "DP_QUERY_STREAM_ENC_STATUS with valid stream event",
262 .req_type = DP_QUERY_STREAM_ENC_STATUS,
263 .u.enc_status.valid_stream_event = 0,
267 .desc = "DP_QUERY_STREAM_ENC_STATUS with stream behavior",
269 .req_type = DP_QUERY_STREAM_ENC_STATUS,
270 .u.enc_status.stream_behavior = 3,
274 .desc = "DP_QUERY_STREAM_ENC_STATUS with a valid stream behavior",
276 .req_type = DP_QUERY_STREAM_ENC_STATUS,
277 .u.enc_status.valid_stream_behavior = 1,
283 sideband_msg_req_equal(const struct drm_dp_sideband_msg_req_body *in,
284 const struct drm_dp_sideband_msg_req_body *out)
286 const struct drm_dp_remote_i2c_read_tx *txin, *txout;
289 if (in->req_type != out->req_type)
292 switch (in->req_type) {
294 * Compare struct members manually for request types which can't be
295 * compared simply using memcmp(). This is because said request types
296 * contain pointers to other allocated structs
298 case DP_REMOTE_I2C_READ:
299 #define IN in->u.i2c_read
300 #define OUT out->u.i2c_read
301 if (IN.num_bytes_read != OUT.num_bytes_read ||
302 IN.num_transactions != OUT.num_transactions ||
303 IN.port_number != OUT.port_number ||
304 IN.read_i2c_device_id != OUT.read_i2c_device_id)
307 for (i = 0; i < IN.num_transactions; i++) {
308 txin = &IN.transactions[i];
309 txout = &OUT.transactions[i];
311 if (txin->i2c_dev_id != txout->i2c_dev_id ||
312 txin->no_stop_bit != txout->no_stop_bit ||
313 txin->num_bytes != txout->num_bytes ||
314 txin->i2c_transaction_delay !=
315 txout->i2c_transaction_delay)
318 if (memcmp(txin->bytes, txout->bytes,
319 txin->num_bytes) != 0)
326 case DP_REMOTE_DPCD_WRITE:
327 #define IN in->u.dpcd_write
328 #define OUT out->u.dpcd_write
329 if (IN.dpcd_address != OUT.dpcd_address ||
330 IN.num_bytes != OUT.num_bytes ||
331 IN.port_number != OUT.port_number)
334 return memcmp(IN.bytes, OUT.bytes, IN.num_bytes) == 0;
338 case DP_REMOTE_I2C_WRITE:
339 #define IN in->u.i2c_write
340 #define OUT out->u.i2c_write
341 if (IN.port_number != OUT.port_number ||
342 IN.write_i2c_device_id != OUT.write_i2c_device_id ||
343 IN.num_bytes != OUT.num_bytes)
346 return memcmp(IN.bytes, OUT.bytes, IN.num_bytes) == 0;
351 return memcmp(in, out, sizeof(*in)) == 0;
357 static void drm_test_dp_mst_msg_printf(struct drm_printer *p, struct va_format *vaf)
359 struct kunit *test = p->arg;
361 kunit_err(test, "%pV", vaf);
364 static void drm_test_dp_mst_sideband_msg_req_decode(struct kunit *test)
366 const struct drm_dp_mst_sideband_msg_req_test *params = test->param_value;
367 const struct drm_dp_sideband_msg_req_body *in = ¶ms->in;
368 struct drm_dp_sideband_msg_req_body *out;
369 struct drm_dp_sideband_msg_tx *txmsg;
370 struct drm_printer p = {
371 .printfn = drm_test_dp_mst_msg_printf,
376 out = kunit_kzalloc(test, sizeof(*out), GFP_KERNEL);
377 KUNIT_ASSERT_NOT_NULL(test, out);
379 txmsg = kunit_kzalloc(test, sizeof(*txmsg), GFP_KERNEL);
380 KUNIT_ASSERT_NOT_NULL(test, txmsg);
382 drm_dp_encode_sideband_req(in, txmsg);
383 KUNIT_EXPECT_GE_MSG(test, drm_dp_decode_sideband_req(txmsg, out), 0,
384 "Failed to decode sideband request");
386 if (!sideband_msg_req_equal(in, out)) {
387 KUNIT_FAIL(test, "Encode/decode failed");
388 kunit_err(test, "Expected:");
389 drm_dp_dump_sideband_msg_req_body(in, 1, &p);
390 kunit_err(test, "Got:");
391 drm_dp_dump_sideband_msg_req_body(out, 1, &p);
394 switch (in->req_type) {
395 case DP_REMOTE_DPCD_WRITE:
396 kfree(out->u.dpcd_write.bytes);
398 case DP_REMOTE_I2C_READ:
399 for (i = 0; i < out->u.i2c_read.num_transactions; i++)
400 kfree(out->u.i2c_read.transactions[i].bytes);
402 case DP_REMOTE_I2C_WRITE:
403 kfree(out->u.i2c_write.bytes);
409 drm_dp_mst_sideband_msg_req_desc(const struct drm_dp_mst_sideband_msg_req_test *t, char *desc)
411 strcpy(desc, t->desc);
414 KUNIT_ARRAY_PARAM(drm_dp_mst_sideband_msg_req, drm_dp_mst_sideband_msg_req_cases,
415 drm_dp_mst_sideband_msg_req_desc);
417 static struct kunit_case drm_dp_mst_helper_tests[] = {
418 KUNIT_CASE_PARAM(drm_test_dp_mst_calc_pbn_mode, drm_dp_mst_calc_pbn_mode_gen_params),
419 KUNIT_CASE_PARAM(drm_test_dp_mst_sideband_msg_req_decode,
420 drm_dp_mst_sideband_msg_req_gen_params),
424 static struct kunit_suite drm_dp_mst_helper_test_suite = {
425 .name = "drm_dp_mst_helper",
426 .test_cases = drm_dp_mst_helper_tests,
429 kunit_test_suite(drm_dp_mst_helper_test_suite);
431 MODULE_LICENSE("GPL");