hdmi.h revision 1.11 1 /* $NetBSD: hdmi.h,v 1.11 2021/12/19 11:38:27 riastradh Exp $ */
2
3 /*-
4 * Copyright (c) 2014 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Taylor R. Campbell.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #ifndef _LINUX_HDMI_H_
33 #define _LINUX_HDMI_H_
34
35 #include <sys/types.h>
36 #include <sys/param.h>
37 #include <sys/errno.h>
38 #include <sys/systm.h>
39
40 enum hdmi_3d_structure {
41 HDMI_3D_STRUCTURE_INVALID = -1,
42 HDMI_3D_STRUCTURE_FRAME_PACKING = 0,
43 HDMI_3D_STRUCTURE_FIELD_ALTERNATIVE = 1,
44 HDMI_3D_STRUCTURE_LINE_ALTERNATIVE = 2,
45 HDMI_3D_STRUCTURE_SIDE_BY_SIDE_FULL = 3,
46 HDMI_3D_STRUCTURE_L_DEPTH = 4,
47 HDMI_3D_STRUCTURE_L_DEPTH_GFX_GFX_DEPTH = 5,
48 HDMI_3D_STRUCTURE_TOP_AND_BOTTOM = 6,
49 HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF = 8,
50 };
51
52 enum hdmi_active_aspect {
53 HDMI_ACTIVE_ASPECT_16_9_TOP = 2,
54 HDMI_ACTIVE_ASPECT_14_9_TOP = 3,
55 HDMI_ACTIVE_ASPECT_16_9_CENTER = 4,
56 HDMI_ACTIVE_ASPECT_PICTURE = 8,
57 HDMI_ACTIVE_ASPECT_4_3 = 9,
58 HDMI_ACTIVE_ASPECT_16_9 = 10,
59 HDMI_ACTIVE_ASPECT_14_9 = 11,
60 HDMI_ACTIVE_ASPECT_4_3_SP_14_9 = 13,
61 HDMI_ACTIVE_ASPECT_16_9_SP_14_9 = 14,
62 HDMI_ACTIVE_ASPECT_16_9_SP_4_3 = 15,
63 };
64
65 enum hdmi_audio_coding_type {
66 HDMI_AUDIO_CODING_TYPE_STREAM = 0,
67 HDMI_AUDIO_CODING_TYPE_PCM = 1,
68 HDMI_AUDIO_CODING_TYPE_AC3 = 2,
69 HDMI_AUDIO_CODING_TYPE_MPEG1 = 3,
70 HDMI_AUDIO_CODING_TYPE_MP3 = 4,
71 HDMI_AUDIO_CODING_TYPE_MPEG2 = 5,
72 HDMI_AUDIO_CODING_TYPE_AAC_LC = 6,
73 HDMI_AUDIO_CODING_TYPE_DTS = 7,
74 HDMI_AUDIO_CODING_TYPE_ATRAC = 8,
75 HDMI_AUDIO_CODING_TYPE_DSD = 9,
76 HDMI_AUDIO_CODING_TYPE_EAC3 = 10,
77 HDMI_AUDIO_CODING_TYPE_DTS_HD = 11,
78 HDMI_AUDIO_CODING_TYPE_MLP = 12,
79 HDMI_AUDIO_CODING_TYPE_DST = 13,
80 HDMI_AUDIO_CODING_TYPE_WMA_PRO = 14,
81 };
82
83 enum hdmi_audio_coding_type_ext {
84 HDMI_AUDIO_CODING_TYPE_EXT_STREAM = 0,
85 HDMI_AUDIO_CODING_TYPE_EXT_HE_AAC = 1,
86 HDMI_AUDIO_CODING_TYPE_EXT_HE_AAC_V2 = 2,
87 HDMI_AUDIO_CODING_TYPE_EXT_MPEG_SURROUND = 3,
88 };
89
90 enum hdmi_audio_sample_frequency {
91 HDMI_AUDIO_SAMPLE_FREQUENCY_STREAM = 0,
92 HDMI_AUDIO_SAMPLE_FREQUENCY_32000 = 1,
93 HDMI_AUDIO_SAMPLE_FREQUENCY_44100 = 2,
94 HDMI_AUDIO_SAMPLE_FREQUENCY_48000 = 3,
95 HDMI_AUDIO_SAMPLE_FREQUENCY_88200 = 4,
96 HDMI_AUDIO_SAMPLE_FREQUENCY_96000 = 5,
97 HDMI_AUDIO_SAMPLE_FREQUENCY_176400 = 6,
98 HDMI_AUDIO_SAMPLE_FREQUENCY_192000 = 7,
99 };
100
101 enum hdmi_audio_sample_size {
102 HDMI_AUDIO_SAMPLE_SIZE_STREAM = 0,
103 HDMI_AUDIO_SAMPLE_SIZE_16 = 1,
104 HDMI_AUDIO_SAMPLE_SIZE_20 = 2,
105 HDMI_AUDIO_SAMPLE_SIZE_24 = 3,
106 };
107
108 enum hdmi_colorimetry {
109 HDMI_COLORIMETRY_NONE = 0,
110 HDMI_COLORIMETRY_ITU_601 = 1,
111 HDMI_COLORIMETRY_ITU_709 = 2,
112 HDMI_COLORIMETRY_EXTENDED = 3,
113 };
114
115 enum hdmi_colorspace {
116 HDMI_COLORSPACE_RGB = 0,
117 HDMI_COLORSPACE_YUV422 = 1,
118 HDMI_COLORSPACE_YUV444 = 2,
119 };
120
121 enum hdmi_content_type {
122 HDMI_CONTENT_TYPE_GRAPHICS = 0,
123 HDMI_CONTENT_TYPE_PHOTO = 1,
124 HDMI_CONTENT_TYPE_CINEMA = 2,
125 HDMI_CONTENT_TYPE_GAME = 3,
126 };
127
128 enum hdmi_extended_colorimetry {
129 HDMI_EXTENDED_COLORIMETRY_XV_YCC_601 = 0,
130 HDMI_EXTENDED_COLORIMETRY_XV_YCC_709 = 1,
131 HDMI_EXTENDED_COLORIMETRY_S_YCC_601 = 2,
132 HDMI_EXTENDED_COLORIMETRY_ADOBE_YCC_601 = 3,
133 HDMI_EXTENDED_COLORIMETRY_ADOBE_RGB = 4,
134 };
135
136 enum hdmi_nups {
137 HDMI_NUPS_UNKNOWN = 0,
138 HDMI_NUPS_HORIZONTAL = 1,
139 HDMI_NUPS_VERTICAL = 2,
140 HDMI_NUPS_BOTH = 3,
141 };
142
143 enum hdmi_picture_aspect {
144 HDMI_PICTURE_ASPECT_NONE = 0,
145 HDMI_PICTURE_ASPECT_4_3 = 1,
146 HDMI_PICTURE_ASPECT_16_9 = 2,
147 HDMI_PICTURE_ASPECT_64_27 = 3,
148 HDMI_PICTURE_ASPECT_256_135 = 4,
149 HDMI_PICTURE_ASPECT_RESERVED = 5,
150 };
151
152 enum hdmi_quantization_range {
153 HDMI_QUANTIZATION_RANGE_DEFAULT = 0,
154 HDMI_QUANTIZATION_RANGE_LIMITED = 1,
155 HDMI_QUANTIZATION_RANGE_FULL = 2,
156 };
157
158 enum hdmi_scan_mode {
159 HDMI_SCAN_MODE_NONE = 0,
160 HDMI_SCAN_MODE_OVERSCAN = 1,
161 HDMI_SCAN_MODE_UNDERSCAN = 2,
162 };
163
164 enum hdmi_ycc_quantization_range {
165 HDMI_YCC_QUANTIZATION_RANGE_LIMITED = 0,
166 HDMI_YCC_QUANTIZATION_RANGE_FULL = 1,
167 };
168
169 enum hdmi_packet_type {
170 HDMI_PACKET_TYPE_NULL = 0x00,
171 HDMI_PACKET_TYPE_AUDIO_CLOCK_REGEN = 0x01,
172 HDMI_PACKET_TYPE_AUDIO_SAMPLE = 0x02,
173 HDMI_PACKET_TYPE_GENERAL_CONTROL = 0x03,
174 HDMI_PACKET_TYPE_ACP = 0x04,
175 HDMI_PACKET_TYPE_ISRC1 = 0x05,
176 HDMI_PACKET_TYPE_ISRC2 = 0x06,
177 HDMI_PACKET_TYPE_ONE_BIT_AUDIO_SAMPLE = 0x07,
178 HDMI_PACKET_TYPE_DST_AUDIO = 0x08,
179 HDMI_PACKET_TYPE_HBR_AUDIO_STREAM = 0x09,
180 HDMI_PACKET_TYPE_GAMUT_METADATA = 0x0a,
181 };
182
183 enum hdmi_infoframe_type {
184 HDMI_INFOFRAME_TYPE_VENDOR = 0x81,
185 HDMI_INFOFRAME_TYPE_AVI = 0x82,
186 HDMI_INFOFRAME_TYPE_SPD = 0x83,
187 HDMI_INFOFRAME_TYPE_AUDIO = 0x84,
188 HDMI_INFOFRAME_TYPE_DRM = 0x87,
189 };
190
191 enum hdmi_eotf {
192 HDMI_EOTF_TRADITIONAL_GAMMA_SDR,
193 HDMI_EOTF_TRADITIONAL_GAMMA_HDR,
194 HDMI_EOTF_SMPTE_ST2084,
195 HDMI_EOTF_BT_2100_HLG,
196 };
197
198 enum hdmi_metadata_type {
199 HDMI_STATIC_METADATA_TYPE1 = 1,
200 };
201
202 struct hdmi_type1 {
203 enum hdmi_eotf eotf;
204 enum hdmi_metadata_type metadata_type;
205 uint16_t min_cll;
206 uint16_t max_cll;
207 uint16_t max_fall;
208 };
209
210 struct hdr_sink_metadata {
211 struct hdmi_type1 hdmi_type1;
212 };
213
214 #define HDMI_INFOFRAME_SIZE(TYPE) \
215 (HDMI_INFOFRAME_HEADER_SIZE + HDMI_##TYPE##_INFOFRAME_SIZE)
216
217 #define HDMI_INFOFRAME_HEADER_SIZE 4
218 struct hdmi_infoframe_header {
219 enum hdmi_infoframe_type type;
220 uint8_t version;
221 uint8_t length;
222 /* checksum */
223 };
224
225 static inline void
226 hdmi_infoframe_header_init(struct hdmi_infoframe_header *header,
227 enum hdmi_infoframe_type type, uint8_t vers, uint8_t length)
228 {
229
230 header->type = type;
231 header->version = vers;
232 header->length = length;
233 }
234
235 static inline int
236 hdmi_infoframe_header_pack(const struct hdmi_infoframe_header *header,
237 uint8_t length, void *buf, size_t size)
238 {
239 uint8_t *const p = buf;
240
241 if (length < HDMI_INFOFRAME_HEADER_SIZE)
242 return -ENOSPC;
243 if (size < length)
244 return -ENOSPC;
245
246 p[0] = header->type;
247 p[1] = header->version;
248 p[2] = (length - HDMI_INFOFRAME_HEADER_SIZE);
249 p[3] = 0; /* checksum */
250
251 return HDMI_INFOFRAME_HEADER_SIZE;
252 }
253
254 static inline void
255 hdmi_infoframe_checksum(void *buf, size_t length)
256 {
257 uint8_t *p = buf;
258 uint8_t checksum = 0;
259
260 while (length--)
261 checksum += *p++;
262
263 p = buf;
264 p[3] = (256 - checksum);
265 }
266
267 #define HDMI_AUDIO_INFOFRAME_SIZE 10
268 struct hdmi_audio_infoframe {
269 struct hdmi_infoframe_header header;
270 uint8_t channels;
271 enum hdmi_audio_coding_type coding_type;
272 enum hdmi_audio_sample_size sample_size;
273 enum hdmi_audio_sample_frequency sample_frequency;
274 enum hdmi_audio_coding_type_ext coding_type_ext;
275 uint8_t channel_allocation;
276 uint8_t level_shift_value;
277 bool downmix_inhibit;
278 };
279
280 static inline int
281 hdmi_audio_infoframe_init(struct hdmi_audio_infoframe *frame)
282 {
283 static const struct hdmi_audio_infoframe zero_frame;
284
285 *frame = zero_frame;
286
287 hdmi_infoframe_header_init(&frame->header, HDMI_INFOFRAME_TYPE_AUDIO,
288 1, HDMI_AUDIO_INFOFRAME_SIZE);
289
290 return 0;
291 }
292
293 static inline ssize_t
294 hdmi_audio_infoframe_pack(const struct hdmi_audio_infoframe *frame, void *buf,
295 size_t size)
296 {
297 const size_t length = HDMI_INFOFRAME_HEADER_SIZE +
298 HDMI_AUDIO_INFOFRAME_SIZE;
299 uint8_t channels = 0;
300 uint8_t *p = buf;
301 int ret;
302
303 KASSERT(frame->header.length == HDMI_AUDIO_INFOFRAME_SIZE);
304
305 ret = hdmi_infoframe_header_pack(&frame->header, length, p, size);
306 if (ret < 0)
307 return ret;
308 KASSERT(ret == HDMI_INFOFRAME_HEADER_SIZE);
309 p += HDMI_INFOFRAME_HEADER_SIZE;
310 size -= HDMI_INFOFRAME_HEADER_SIZE;
311
312 if (frame->channels >= 2)
313 channels = frame->channels - 1;
314
315 p[0] = __SHIFTIN(frame->coding_type, __BITS(7,4));
316 p[0] |= __SHIFTIN(channels, __BITS(2,0));
317
318 p[1] = __SHIFTIN(frame->sample_frequency, __BITS(4,2));
319 p[1] |= __SHIFTIN(frame->sample_size, __BITS(1,0));
320
321 p[2] = __SHIFTIN(frame->coding_type_ext, __BITS(5,0));
322
323 p[3] = __SHIFTIN(frame->level_shift_value, __BITS(6, 3));
324
325 p[4] = __SHIFTIN(frame->downmix_inhibit? 1 : 0, __BIT(7));
326
327 /* PB6 to PB10 are reserved */
328 p[5] = 0;
329 p[6] = 0;
330 p[7] = 0;
331 p[8] = 0;
332 p[9] = 0;
333
334 CTASSERT(HDMI_AUDIO_INFOFRAME_SIZE == 10);
335
336 hdmi_infoframe_checksum(buf, length);
337
338 return length;
339 }
340
341 #define HDMI_AVI_INFOFRAME_SIZE 13
342 struct hdmi_avi_infoframe {
343 struct hdmi_infoframe_header header;
344 enum hdmi_colorspace colorspace;
345 enum hdmi_scan_mode scan_mode;
346 enum hdmi_colorimetry colorimetry;
347 enum hdmi_picture_aspect picture_aspect;
348 enum hdmi_active_aspect active_aspect;
349 bool itc;
350 enum hdmi_extended_colorimetry extended_colorimetry;
351 enum hdmi_quantization_range quantization_range;
352 enum hdmi_nups nups;
353 uint8_t video_code;
354 enum hdmi_ycc_quantization_range ycc_quantization_range;
355 enum hdmi_content_type content_type;
356 uint8_t pixel_repeat;
357 uint16_t top_bar;
358 uint16_t bottom_bar;
359 uint16_t left_bar;
360 uint16_t right_bar;
361 };
362
363 static inline int
364 hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame)
365 {
366 static const struct hdmi_avi_infoframe zero_frame;
367
368 *frame = zero_frame;
369
370 hdmi_infoframe_header_init(&frame->header, HDMI_INFOFRAME_TYPE_AVI, 2,
371 HDMI_AVI_INFOFRAME_SIZE);
372
373 return 0;
374 }
375
376 static inline ssize_t
377 hdmi_avi_infoframe_pack(const struct hdmi_avi_infoframe *frame, void *buf,
378 size_t size)
379 {
380 const size_t length = HDMI_INFOFRAME_HEADER_SIZE +
381 HDMI_AVI_INFOFRAME_SIZE;
382 uint8_t *p = buf;
383 int ret;
384
385 KASSERT(frame->header.length == HDMI_AVI_INFOFRAME_SIZE);
386
387 ret = hdmi_infoframe_header_pack(&frame->header, length, p, size);
388 if (ret < 0)
389 return ret;
390 KASSERT(ret == HDMI_INFOFRAME_HEADER_SIZE);
391 p += HDMI_INFOFRAME_HEADER_SIZE;
392 size -= HDMI_INFOFRAME_HEADER_SIZE;
393
394 p[0] = __SHIFTIN(frame->colorspace, __BITS(6,5));
395 p[0] |= __SHIFTIN(frame->active_aspect & 0xf? 1 : 0, __BIT(4));
396 p[0] |= __SHIFTIN(frame->top_bar || frame->bottom_bar, __BIT(3));
397 p[0] |= __SHIFTIN(frame->left_bar || frame->right_bar, __BIT(2));
398 p[0] |= __SHIFTIN(frame->scan_mode, __BITS(1,0));
399
400 p[1] = __SHIFTIN(frame->colorimetry, __BITS(7,6));
401 p[1] |= __SHIFTIN(frame->picture_aspect, __BITS(5,4));
402 p[1] |= __SHIFTIN(frame->active_aspect, __BITS(3,0));
403
404 p[2] = __SHIFTIN(frame->itc? 1 : 0, __BIT(7));
405 p[2] |= __SHIFTIN(frame->extended_colorimetry, __BITS(6,4));
406 p[2] |= __SHIFTIN(frame->quantization_range, __BITS(3,2));
407 p[2] |= __SHIFTIN(frame->nups, __BITS(1,0));
408
409 p[3] = frame->video_code;
410
411 p[4] = __SHIFTIN(frame->ycc_quantization_range, __BITS(7,6));
412 p[4] |= __SHIFTIN(frame->content_type, __BITS(5,4));
413 p[4] |= __SHIFTIN(frame->pixel_repeat, __BITS(3,0));
414
415 le16enc(&p[5], frame->top_bar);
416 le16enc(&p[7], frame->bottom_bar);
417 le16enc(&p[9], frame->left_bar);
418 le16enc(&p[11], frame->right_bar);
419 CTASSERT(HDMI_AVI_INFOFRAME_SIZE == 13);
420
421 hdmi_infoframe_checksum(buf, length);
422
423 return length;
424 }
425
426 #define HDMI_SPD_INFOFRAME_SIZE 25
427 struct hdmi_spd_infoframe {
428 struct hdmi_infoframe_header header;
429 char vendor[8];
430 char product[16];
431 enum hdmi_spd_sdi {
432 HDMI_SPD_SDI_UNKNOWN = 0,
433 HDMI_SPD_SDI_DSTB = 1,
434 HDMI_SPD_SDI_DVDP = 2,
435 HDMI_SPD_SDI_DVHS = 3,
436 HDMI_SPD_SDI_HDDVR = 4,
437 HDMI_SPD_SDI_DVC = 5,
438 HDMI_SPD_SDI_DSC = 6,
439 HDMI_SPD_SDI_VCD = 7,
440 HDMI_SPD_SDI_GAME = 8,
441 HDMI_SPD_SDI_PC = 9,
442 HDMI_SPD_SDI_BD = 10,
443 HDMI_SPD_SDI_SACD = 11,
444 HDMI_SPD_SDI_HDDVD = 12,
445 HDMI_SPD_SDI_PMP = 13,
446 } sdi;
447 };
448
449 static inline int
450 hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame, const char *vendor,
451 const char *product)
452 {
453 static const struct hdmi_spd_infoframe zero_frame;
454
455 *frame = zero_frame;
456
457 hdmi_infoframe_header_init(&frame->header, HDMI_INFOFRAME_TYPE_SPD,
458 1, HDMI_SPD_INFOFRAME_SIZE);
459
460 (void)strlcpy(frame->vendor, vendor, sizeof(frame->vendor));
461 (void)strlcpy(frame->product, product, sizeof(frame->product));
462
463 return 0;
464 }
465
466 static inline ssize_t
467 hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buf,
468 size_t size)
469 {
470 const size_t length = HDMI_INFOFRAME_HEADER_SIZE +
471 HDMI_SPD_INFOFRAME_SIZE;
472 uint8_t *p = buf;
473 int ret;
474
475 KASSERT(frame->header.length == HDMI_SPD_INFOFRAME_SIZE);
476
477 ret = hdmi_infoframe_header_pack(&frame->header, length, p, size);
478 if (ret < 0)
479 return ret;
480 KASSERT(ret == HDMI_INFOFRAME_HEADER_SIZE);
481 p += HDMI_INFOFRAME_HEADER_SIZE;
482 size -= HDMI_INFOFRAME_HEADER_SIZE;
483
484 (void)memcpy(&p[0], frame->vendor, 8);
485 (void)memcpy(&p[8], frame->product, 16);
486 p[24] = frame->sdi;
487 CTASSERT(HDMI_SPD_INFOFRAME_SIZE == 25);
488
489 hdmi_infoframe_checksum(buf, length);
490
491 return length;
492 }
493
494 #define HDMI_IEEE_OUI 0x000c03
495 #define HDMI_FORUM_IEEE_OUI 0xc45dd8
496
497 struct hdmi_vendor_infoframe {
498 struct hdmi_infoframe_header header;
499 uint32_t oui;
500 uint8_t vic;
501 enum hdmi_3d_structure s3d_struct;
502 unsigned s3d_ext_data;
503 };
504
505 union hdmi_vendor_any_infoframe {
506 struct {
507 struct hdmi_infoframe_header header;
508 uint32_t oui;
509 } any;
510 struct hdmi_vendor_infoframe hdmi;
511 };
512
513 static inline int
514 hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame)
515 {
516 static const struct hdmi_vendor_infoframe zero_frame;
517
518 *frame = zero_frame;
519
520 hdmi_infoframe_header_init(&frame->header, HDMI_INFOFRAME_TYPE_VENDOR,
521 1, 0 /* depends on s3d_struct */);
522
523 frame->oui = HDMI_IEEE_OUI;
524 frame->s3d_struct = HDMI_3D_STRUCTURE_INVALID;
525
526 return 0;
527 }
528
529 static inline int
530 hdmi_vendor_infoframe_pack(const struct hdmi_vendor_infoframe *frame,
531 void *buf, size_t size)
532 {
533 uint8_t *p = buf;
534 size_t length;
535 int ret;
536
537 /* Exactly one must be supplied. */
538 if ((frame->vic == 0) ==
539 (frame->s3d_struct == HDMI_3D_STRUCTURE_INVALID))
540 return -EINVAL;
541
542 length = HDMI_INFOFRAME_HEADER_SIZE + 6;
543 if (frame->s3d_struct >= HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF)
544 length += 1;
545
546 ret = hdmi_infoframe_header_pack(&frame->header, length, p, size);
547 if (ret < 0)
548 return ret;
549 KASSERT(ret == HDMI_INFOFRAME_HEADER_SIZE);
550 p += HDMI_INFOFRAME_HEADER_SIZE;
551 size -= HDMI_INFOFRAME_HEADER_SIZE;
552
553 p[0] = 0x03;
554 p[1] = 0x0c;
555 p[2] = 0x00;
556
557 if (frame->vic == 0) {
558 p[3] = __SHIFTIN(0x2, __BITS(6,5));
559 p[4] = __SHIFTIN(frame->s3d_struct, __BITS(7,4));
560 if (frame->s3d_struct >= HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF)
561 p[9] = __SHIFTIN(frame->s3d_ext_data, __BITS(7,4));
562 } else {
563 p[3] = __SHIFTIN(0x1, __BITS(6,5));
564 p[4] = frame->vic;
565 }
566
567 hdmi_infoframe_checksum(buf, length);
568
569 return length;
570 }
571
572 #define HDMI_DRM_INFOFRAME_SIZE 26
573 struct hdmi_drm_infoframe {
574 struct hdmi_infoframe_header header;
575 enum hdmi_eotf eotf;
576 enum hdmi_metadata_type metadata_type;
577 struct {
578 uint16_t x, y;
579 } display_primaries[3];
580 struct {
581 uint16_t x, y;
582 } white_point;
583 uint16_t max_display_mastering_luminance;
584 uint16_t min_display_mastering_luminance;
585 uint16_t max_cll;
586 uint16_t max_fall;
587 };
588
589 static inline int
590 hdmi_drm_infoframe_init(struct hdmi_drm_infoframe *frame)
591 {
592 static const struct hdmi_drm_infoframe zero_frame;
593
594 *frame = zero_frame;
595
596 hdmi_infoframe_header_init(&frame->header, HDMI_INFOFRAME_TYPE_DRM,
597 1, HDMI_DRM_INFOFRAME_SIZE);
598
599 return 0;
600 }
601
602 #define hdmi_drm_infoframe_pack_only hdmi_drm_infoframe_pack /* XXX */
603
604 static inline int
605 hdmi_drm_infoframe_pack(const struct hdmi_drm_infoframe *frame,
606 void *buf, size_t size)
607 {
608 const size_t length = HDMI_INFOFRAME_HEADER_SIZE +
609 HDMI_DRM_INFOFRAME_SIZE;
610 uint8_t *p = buf;
611 unsigned i;
612 int ret;
613
614 KASSERT(frame->header.length == HDMI_DRM_INFOFRAME_SIZE);
615
616 ret = hdmi_infoframe_header_pack(&frame->header, length, p, size);
617 if (ret < 0)
618 return ret;
619 KASSERT(ret == HDMI_INFOFRAME_HEADER_SIZE);
620 p += HDMI_INFOFRAME_HEADER_SIZE;
621 size -= HDMI_INFOFRAME_HEADER_SIZE;
622
623 p[0] = frame->eotf;
624 p[1] = frame->metadata_type;
625 for (i = 0; i < __arraycount(frame->display_primaries); i++) {
626 le16enc(&p[2 + 4*i], frame->display_primaries[i].x);
627 le16enc(&p[2 + 4*i + 1], frame->display_primaries[i].y);
628 }
629 le16enc(&p[14], frame->white_point.x);
630 le16enc(&p[16], frame->white_point.y);
631 le16enc(&p[18], frame->min_display_mastering_luminance);
632 le16enc(&p[20], frame->max_display_mastering_luminance);
633 le16enc(&p[22], frame->max_cll);
634 le16enc(&p[24], frame->max_fall);
635 CTASSERT(HDMI_DRM_INFOFRAME_SIZE == 26);
636
637 hdmi_infoframe_checksum(buf, length);
638
639 return length;
640 }
641
642 union hdmi_infoframe {
643 struct hdmi_infoframe_header any;
644 struct hdmi_avi_infoframe avi;
645 struct hdmi_drm_infoframe drm;
646 struct hdmi_spd_infoframe spd;
647 union hdmi_vendor_any_infoframe vendor;
648 };
649
650 static inline ssize_t
651 hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buf, size_t size)
652 {
653
654 switch (frame->any.type) {
655 case HDMI_INFOFRAME_TYPE_AVI:
656 return hdmi_avi_infoframe_pack(&frame->avi, buf, size);
657 case HDMI_INFOFRAME_TYPE_DRM:
658 return hdmi_drm_infoframe_pack(&frame->drm, buf, size);
659 case HDMI_INFOFRAME_TYPE_SPD:
660 return hdmi_spd_infoframe_pack(&frame->spd, buf, size);
661 case HDMI_INFOFRAME_TYPE_VENDOR:
662 return hdmi_vendor_infoframe_pack(&frame->vendor.hdmi, buf,
663 size);
664 default:
665 return -EINVAL;
666 }
667 }
668
669 static inline void
670 hdmi_infoframe_log(const char *level, struct device *device,
671 const union hdmi_infoframe *frame)
672 {
673 /* XXX */
674 }
675
676 #endif /* _LINUX_HDMI_H_ */
677