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 #define PREFIX_STR "[drm_dp_mst_helper]" 9 10 #include <kunit/test.h> 11 12 #include <linux/random.h> 13 14 #include <drm/display/drm_dp_mst_helper.h> 15 #include <drm/drm_print.h> 16 17 #include "../display/drm_dp_mst_topology_internal.h" 18 19 static void drm_test_dp_mst_calc_pbn_mode(struct kunit *test) 20 { 21 int pbn, i; 22 const struct { 23 int rate; 24 int bpp; 25 int expected; 26 bool dsc; 27 } test_params[] = { 28 { 154000, 30, 689, false }, 29 { 234000, 30, 1047, false }, 30 { 297000, 24, 1063, false }, 31 { 332880, 24, 50, true }, 32 { 324540, 24, 49, true }, 33 }; 34 35 for (i = 0; i < ARRAY_SIZE(test_params); i++) { 36 pbn = drm_dp_calc_pbn_mode(test_params[i].rate, 37 test_params[i].bpp, 38 test_params[i].dsc); 39 KUNIT_EXPECT_EQ_MSG(test, pbn, test_params[i].expected, 40 "Expected PBN %d for clock %d bpp %d, got %d\n", 41 test_params[i].expected, test_params[i].rate, 42 test_params[i].bpp, pbn); 43 } 44 } 45 46 static bool 47 sideband_msg_req_equal(const struct drm_dp_sideband_msg_req_body *in, 48 const struct drm_dp_sideband_msg_req_body *out) 49 { 50 const struct drm_dp_remote_i2c_read_tx *txin, *txout; 51 int i; 52 53 if (in->req_type != out->req_type) 54 return false; 55 56 switch (in->req_type) { 57 /* 58 * Compare struct members manually for request types which can't be 59 * compared simply using memcmp(). This is because said request types 60 * contain pointers to other allocated structs 61 */ 62 case DP_REMOTE_I2C_READ: 63 #define IN in->u.i2c_read 64 #define OUT out->u.i2c_read 65 if (IN.num_bytes_read != OUT.num_bytes_read || 66 IN.num_transactions != OUT.num_transactions || 67 IN.port_number != OUT.port_number || 68 IN.read_i2c_device_id != OUT.read_i2c_device_id) 69 return false; 70 71 for (i = 0; i < IN.num_transactions; i++) { 72 txin = &IN.transactions[i]; 73 txout = &OUT.transactions[i]; 74 75 if (txin->i2c_dev_id != txout->i2c_dev_id || 76 txin->no_stop_bit != txout->no_stop_bit || 77 txin->num_bytes != txout->num_bytes || 78 txin->i2c_transaction_delay != 79 txout->i2c_transaction_delay) 80 return false; 81 82 if (memcmp(txin->bytes, txout->bytes, 83 txin->num_bytes) != 0) 84 return false; 85 } 86 break; 87 #undef IN 88 #undef OUT 89 90 case DP_REMOTE_DPCD_WRITE: 91 #define IN in->u.dpcd_write 92 #define OUT out->u.dpcd_write 93 if (IN.dpcd_address != OUT.dpcd_address || 94 IN.num_bytes != OUT.num_bytes || 95 IN.port_number != OUT.port_number) 96 return false; 97 98 return memcmp(IN.bytes, OUT.bytes, IN.num_bytes) == 0; 99 #undef IN 100 #undef OUT 101 102 case DP_REMOTE_I2C_WRITE: 103 #define IN in->u.i2c_write 104 #define OUT out->u.i2c_write 105 if (IN.port_number != OUT.port_number || 106 IN.write_i2c_device_id != OUT.write_i2c_device_id || 107 IN.num_bytes != OUT.num_bytes) 108 return false; 109 110 return memcmp(IN.bytes, OUT.bytes, IN.num_bytes) == 0; 111 #undef IN 112 #undef OUT 113 114 default: 115 return memcmp(in, out, sizeof(*in)) == 0; 116 } 117 118 return true; 119 } 120 121 static bool 122 sideband_msg_req_encode_decode(struct drm_dp_sideband_msg_req_body *in) 123 { 124 struct drm_dp_sideband_msg_req_body *out; 125 struct drm_printer p = drm_err_printer(PREFIX_STR); 126 struct drm_dp_sideband_msg_tx *txmsg; 127 int i, ret; 128 bool result = true; 129 130 out = kzalloc(sizeof(*out), GFP_KERNEL); 131 if (!out) 132 return false; 133 134 txmsg = kzalloc(sizeof(*txmsg), GFP_KERNEL); 135 if (!txmsg) { 136 kfree(out); 137 return false; 138 } 139 140 drm_dp_encode_sideband_req(in, txmsg); 141 ret = drm_dp_decode_sideband_req(txmsg, out); 142 if (ret < 0) { 143 drm_printf(&p, "Failed to decode sideband request: %d\n", 144 ret); 145 result = false; 146 goto out; 147 } 148 149 if (!sideband_msg_req_equal(in, out)) { 150 drm_printf(&p, "Encode/decode failed, expected:\n"); 151 drm_dp_dump_sideband_msg_req_body(in, 1, &p); 152 drm_printf(&p, "Got:\n"); 153 drm_dp_dump_sideband_msg_req_body(out, 1, &p); 154 result = false; 155 goto out; 156 } 157 158 switch (in->req_type) { 159 case DP_REMOTE_DPCD_WRITE: 160 kfree(out->u.dpcd_write.bytes); 161 break; 162 case DP_REMOTE_I2C_READ: 163 for (i = 0; i < out->u.i2c_read.num_transactions; i++) 164 kfree(out->u.i2c_read.transactions[i].bytes); 165 break; 166 case DP_REMOTE_I2C_WRITE: 167 kfree(out->u.i2c_write.bytes); 168 break; 169 } 170 171 /* Clear everything but the req_type for the input */ 172 memset(&in->u, 0, sizeof(in->u)); 173 174 out: 175 kfree(out); 176 kfree(txmsg); 177 return result; 178 } 179 180 static void drm_test_dp_mst_sideband_msg_req_decode(struct kunit *test) 181 { 182 struct drm_dp_sideband_msg_req_body in = { 0 }; 183 u8 data[] = { 0xff, 0x0, 0xdd }; 184 int i; 185 186 in.req_type = DP_ENUM_PATH_RESOURCES; 187 in.u.port_num.port_number = 5; 188 KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); 189 190 in.req_type = DP_POWER_UP_PHY; 191 in.u.port_num.port_number = 5; 192 KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); 193 194 in.req_type = DP_POWER_DOWN_PHY; 195 in.u.port_num.port_number = 5; 196 KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); 197 198 in.req_type = DP_ALLOCATE_PAYLOAD; 199 in.u.allocate_payload.number_sdp_streams = 3; 200 for (i = 0; i < in.u.allocate_payload.number_sdp_streams; i++) 201 in.u.allocate_payload.sdp_stream_sink[i] = i + 1; 202 KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); 203 in.u.allocate_payload.port_number = 0xf; 204 KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); 205 in.u.allocate_payload.vcpi = 0x7f; 206 KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); 207 in.u.allocate_payload.pbn = U16_MAX; 208 KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); 209 210 in.req_type = DP_QUERY_PAYLOAD; 211 in.u.query_payload.port_number = 0xf; 212 KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); 213 in.u.query_payload.vcpi = 0x7f; 214 KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); 215 216 in.req_type = DP_REMOTE_DPCD_READ; 217 in.u.dpcd_read.port_number = 0xf; 218 KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); 219 in.u.dpcd_read.dpcd_address = 0xfedcb; 220 KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); 221 in.u.dpcd_read.num_bytes = U8_MAX; 222 KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); 223 224 in.req_type = DP_REMOTE_DPCD_WRITE; 225 in.u.dpcd_write.port_number = 0xf; 226 KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); 227 in.u.dpcd_write.dpcd_address = 0xfedcb; 228 KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); 229 in.u.dpcd_write.num_bytes = ARRAY_SIZE(data); 230 in.u.dpcd_write.bytes = data; 231 KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); 232 233 in.req_type = DP_REMOTE_I2C_READ; 234 in.u.i2c_read.port_number = 0xf; 235 KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); 236 in.u.i2c_read.read_i2c_device_id = 0x7f; 237 KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); 238 in.u.i2c_read.num_transactions = 3; 239 in.u.i2c_read.num_bytes_read = ARRAY_SIZE(data) * 3; 240 for (i = 0; i < in.u.i2c_read.num_transactions; i++) { 241 in.u.i2c_read.transactions[i].bytes = data; 242 in.u.i2c_read.transactions[i].num_bytes = ARRAY_SIZE(data); 243 in.u.i2c_read.transactions[i].i2c_dev_id = 0x7f & ~i; 244 in.u.i2c_read.transactions[i].i2c_transaction_delay = 0xf & ~i; 245 } 246 KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); 247 248 in.req_type = DP_REMOTE_I2C_WRITE; 249 in.u.i2c_write.port_number = 0xf; 250 KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); 251 in.u.i2c_write.write_i2c_device_id = 0x7f; 252 KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); 253 in.u.i2c_write.num_bytes = ARRAY_SIZE(data); 254 in.u.i2c_write.bytes = data; 255 KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); 256 257 in.req_type = DP_QUERY_STREAM_ENC_STATUS; 258 in.u.enc_status.stream_id = 1; 259 KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); 260 get_random_bytes(in.u.enc_status.client_id, 261 sizeof(in.u.enc_status.client_id)); 262 KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); 263 in.u.enc_status.stream_event = 3; 264 KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); 265 in.u.enc_status.valid_stream_event = 0; 266 KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); 267 in.u.enc_status.stream_behavior = 3; 268 KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); 269 in.u.enc_status.valid_stream_behavior = 1; 270 KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); 271 } 272 273 static struct kunit_case drm_dp_mst_helper_tests[] = { 274 KUNIT_CASE(drm_test_dp_mst_calc_pbn_mode), 275 KUNIT_CASE(drm_test_dp_mst_sideband_msg_req_decode), 276 { } 277 }; 278 279 static struct kunit_suite drm_dp_mst_helper_test_suite = { 280 .name = "drm_dp_mst_helper", 281 .test_cases = drm_dp_mst_helper_tests, 282 }; 283 284 kunit_test_suite(drm_dp_mst_helper_test_suite); 285 286 MODULE_LICENSE("GPL"); 287