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