1 // SPDX-License-Identifier: MIT
3 * Copyright 2024 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
5 * Author: Hans Verkuil <hverkuil-cisco@xs4all.nl>
19 #include <sys/ioctl.h>
20 #include <sys/epoll.h>
27 #include <linux/i2c-dev.h>
28 #include <linux/i2c.h>
29 #include <linux/types.h>
31 #include "edid-decode.h"
33 // i2c addresses for edid
34 #define EDID_ADDR 0x50
35 #define SEGMENT_POINTER_ADDR 0x30
37 // i2c address for SCDC
38 #define SCDC_ADDR 0x54
40 // i2c addresses for HDCP
41 #define HDCP_PRIM_ADDR 0x3a
42 #define HDCP_SEC_ADDR 0x3b
44 int request_i2c_adapter(unsigned adapnr
)
46 std::string i2c_adapter
= "/dev/i2c-" + std::to_string(adapnr
);
47 int fd
= open(i2c_adapter
.c_str(), O_RDWR
);
51 fprintf(stderr
, "Error accessing i2c adapter %s\n", i2c_adapter
.c_str());
55 static int read_edid_block(int adapter_fd
, __u8
*edid
,
56 uint8_t segment
, uint8_t offset
, uint8_t blocks
)
58 struct i2c_rdwr_ioctl_data data
;
59 struct i2c_msg write_message
;
60 struct i2c_msg read_message
;
61 struct i2c_msg seg_message
;
65 .addr
= SEGMENT_POINTER_ADDR
,
77 .len
= (__u16
)(blocks
* EDID_PAGE_SIZE
),
82 struct i2c_msg msgs
[2] = { seg_message
, read_message
};
85 data
.nmsgs
= ARRAY_SIZE(msgs
);
86 err
= ioctl(adapter_fd
, I2C_RDWR
, &data
);
88 struct i2c_msg msgs
[2] = { write_message
, read_message
};
91 data
.nmsgs
= ARRAY_SIZE(msgs
);
92 err
= ioctl(adapter_fd
, I2C_RDWR
, &data
);
96 fprintf(stderr
, "Unable to read edid: %s\n", strerror(errno
));
102 int read_edid(int adapter_fd
, unsigned char *edid
)
104 unsigned n_extension_blocks
;
107 err
= read_edid_block(adapter_fd
, edid
, 0, 0, 2);
110 n_extension_blocks
= edid
[126];
111 if (!n_extension_blocks
)
113 for (unsigned i
= 2; i
<= n_extension_blocks
; i
+= 2) {
114 err
= read_edid_block(adapter_fd
, edid
+ i
* 128, i
/ 2, 0,
115 (i
+ 1 > n_extension_blocks
? 1 : 2));
119 return n_extension_blocks
+ 1;
122 static int read_hdcp_registers(int adapter_fd
, __u8
*hdcp_prim
, __u8
*hdcp_sec
, __u8
*ksv_fifo
)
124 struct i2c_rdwr_ioctl_data data
;
125 struct i2c_msg write_message
;
126 struct i2c_msg read_message
;
128 __u8 ksv_fifo_offset
= 0x43;
132 .addr
= HDCP_PRIM_ADDR
,
137 .addr
= HDCP_PRIM_ADDR
,
143 struct i2c_msg msgs
[2] = { write_message
, read_message
};
146 data
.nmsgs
= ARRAY_SIZE(msgs
);
147 err
= ioctl(adapter_fd
, I2C_RDWR
, &data
);
150 fprintf(stderr
, "Unable to read Primary Link HDCP: %s\n",
156 .addr
= HDCP_PRIM_ADDR
,
158 .buf
= &ksv_fifo_offset
161 .addr
= HDCP_PRIM_ADDR
,
163 .len
= (__u16
)((hdcp_prim
[0x41] & 0x7f) * 5),
167 if (read_message
.len
) {
168 struct i2c_msg ksv_fifo_msgs
[2] = { write_message
, read_message
};
170 data
.msgs
= ksv_fifo_msgs
;
171 data
.nmsgs
= ARRAY_SIZE(msgs
);
172 err
= ioctl(adapter_fd
, I2C_RDWR
, &data
);
174 fprintf(stderr
, "Unable to read KSV FIFO: %s\n",
181 .addr
= HDCP_SEC_ADDR
,
186 .addr
= HDCP_SEC_ADDR
,
192 struct i2c_msg sec_msgs
[2] = { write_message
, read_message
};
193 data
.msgs
= sec_msgs
;
194 data
.nmsgs
= ARRAY_SIZE(msgs
);
195 ioctl(adapter_fd
, I2C_RDWR
, &data
);
200 int read_hdcp(int adapter_fd
)
204 __u8 ksv_fifo
[128 * 5];
208 if (read_hdcp_registers(adapter_fd
, hdcp_prim
, hdcp_sec
, ksv_fifo
))
210 printf("HDCP Primary Link Hex Dump:\n\n");
211 hex_block("", hdcp_prim
, 128, false);
213 hex_block("", hdcp_prim
+ 128, 128, false);
215 if (hdcp_sec
[5] != 0xdd) {
216 printf("HDCP Secondary Link Hex Dump:\n\n");
217 hex_block("", hdcp_sec
, 128, false);
219 hex_block("", hdcp_sec
+ 128, 128, false);
222 printf("HDCP Primary Link:\n\n");
223 printf("Bksv: %02x %02x %02x %02x %02x\n",
224 hdcp_prim
[0], hdcp_prim
[1], hdcp_prim
[2], hdcp_prim
[3], hdcp_prim
[4]);
225 printf("Ri': %02x %02x\n", hdcp_prim
[9], hdcp_prim
[8]);
226 printf("Pj': %02x\n", hdcp_prim
[0x0a]);
227 printf("Aksv: %02x %02x %02x %02x %02x\n",
228 hdcp_prim
[0x10], hdcp_prim
[0x11], hdcp_prim
[0x12], hdcp_prim
[0x13], hdcp_prim
[0x14]);
229 printf("Ainfo: %02x\n", hdcp_prim
[0x15]);
230 printf("An: %02x %02x %02x %02x %02x %02x %02x %02x\n",
231 hdcp_prim
[0x18], hdcp_prim
[0x19], hdcp_prim
[0x1a], hdcp_prim
[0x1b],
232 hdcp_prim
[0x1c], hdcp_prim
[0x1d], hdcp_prim
[0x1e], hdcp_prim
[0x1f]);
233 printf("V'.H0: %02x %02x %02x %02x\n",
234 hdcp_prim
[0x20], hdcp_prim
[0x21], hdcp_prim
[0x22], hdcp_prim
[0x23]);
235 printf("V'.H1: %02x %02x %02x %02x\n",
236 hdcp_prim
[0x24], hdcp_prim
[0x25], hdcp_prim
[0x26], hdcp_prim
[0x27]);
237 printf("V'.H2: %02x %02x %02x %02x\n",
238 hdcp_prim
[0x28], hdcp_prim
[0x29], hdcp_prim
[0x2a], hdcp_prim
[0x2b]);
239 printf("V'.H3: %02x %02x %02x %02x\n",
240 hdcp_prim
[0x2c], hdcp_prim
[0x2d], hdcp_prim
[0x2e], hdcp_prim
[0x2f]);
241 printf("V'.H4: %02x %02x %02x %02x\n",
242 hdcp_prim
[0x30], hdcp_prim
[0x31], hdcp_prim
[0x32], hdcp_prim
[0x33]);
243 __u8 v
= hdcp_prim
[0x40];
244 printf("Bcaps: %02x\n", v
);
246 printf("\tFAST_REAUTHENTICATION\n");
248 printf("\t1.1_FEATURES\n");
254 printf("\tREPEATER\n");
255 __u16 vv
= hdcp_prim
[0x41] | (hdcp_prim
[0x42] << 8);
256 printf("Bstatus: %04x\n", vv
);
257 printf("\tDEVICE_COUNT: %u\n", vv
& 0x7f);
259 printf("\tMAX_DEVS_EXCEEDED\n");
260 printf("\tDEPTH: %u\n", (vv
>> 8) & 0x07);
262 printf("\tMAX_CASCADE_EXCEEDED\n");
264 printf("\tHDMI_MODE\n");
266 printf("KSV FIFO:\n");
267 for (unsigned i
= 0; i
< (vv
& 0x7f); i
++)
268 printf("\t%03u: %02x %02x %02x %02x %02x\n", i
,
269 ksv_fifo
[i
* 5], ksv_fifo
[i
* 5 + 1],
270 ksv_fifo
[i
* 5 + 2], ksv_fifo
[i
* 5 + 3],
271 ksv_fifo
[i
* 5 + 4]);
274 printf("HDCP2Version: %02x\n", v
);
276 printf("\tHDCP2.2\n");
277 vv
= hdcp_prim
[0x70] | (hdcp_prim
[0x71] << 8);
278 printf("RxStatus: %04x\n", vv
);
280 printf("\tMessage_Size: %u\n", vv
& 0x3ff);
284 printf("\tREAUTH_REQ\n");
286 if (hdcp_sec
[5] == 0xdd)
289 printf("HDCP Secondary Link:\n\n");
290 printf("Bksv: %02x %02x %02x %02x %02x\n",
291 hdcp_sec
[0], hdcp_sec
[1], hdcp_sec
[2], hdcp_sec
[3], hdcp_sec
[4]);
292 printf("Ri': %02x %02x\n", hdcp_sec
[9], hdcp_sec
[9]);
293 printf("Pj': %02x\n", hdcp_sec
[0x0a]);
294 printf("Aksv: %02x %02x %02x %02x %02x\n",
295 hdcp_sec
[0x10], hdcp_sec
[0x11], hdcp_sec
[0x12], hdcp_sec
[0x13], hdcp_sec
[0x14]);
296 printf("Ainfo: %02x\n", hdcp_sec
[0x15]);
297 printf("An: %02x %02x %02x %02x %02x %02x %02x %02x\n",
298 hdcp_sec
[0x18], hdcp_sec
[0x19], hdcp_sec
[0x1a], hdcp_sec
[0x1b],
299 hdcp_sec
[0x1c], hdcp_sec
[0x1d], hdcp_sec
[0x1e], hdcp_sec
[0x1f]);
303 static int read_hdcp_ri_register(int adapter_fd
, __u16
*v
)
305 struct i2c_rdwr_ioctl_data data
;
306 struct i2c_msg write_message
;
307 struct i2c_msg read_message
;
313 .addr
= HDCP_PRIM_ADDR
,
318 .addr
= HDCP_PRIM_ADDR
,
324 struct i2c_msg msgs
[2] = { write_message
, read_message
};
327 data
.nmsgs
= ARRAY_SIZE(msgs
);
328 err
= ioctl(adapter_fd
, I2C_RDWR
, &data
);
331 fprintf(stderr
, "Unable to read Ri: %s\n", strerror(errno
));
333 *v
= ri
[1] << 8 | ri
[0];
335 return err
< 0 ? err
: 0;
338 int read_hdcp_ri(int adapter_fd
, double ri_time
)
343 if (!read_hdcp_ri_register(adapter_fd
, &ri
))
344 printf("Ri': %04x\n", ri
);
345 usleep(ri_time
* 1000000);