hdmi.h revision 1.5 1 /* $NetBSD: hdmi.h,v 1.5 2014/11/24 01:27:07 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_NONE = 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 };
148
149 enum hdmi_quantization_range {
150 HDMI_QUANTIZATION_RANGE_DEFAULT = 0,
151 HDMI_QUANTIZATION_RANGE_LIMITED = 1,
152 HDMI_QUANTIZATION_RANGE_FULL = 2,
153 };
154
155 enum hdmi_scan_mode {
156 HDMI_SCAN_MODE_NONE = 0,
157 HDMI_SCAN_MODE_OVERSCAN = 1,
158 HDMI_SCAN_MODE_UNDERSCAN = 2,
159 };
160
161 enum hdmi_ycc_quantization_range {
162 HDMI_YCC_QUANTIZATION_RANGE_LIMITED = 0,
163 HDMI_YCC_QUANTIZATION_RANGE_FULL = 1,
164 };
165
166 enum hdmi_infoframe_type {
167 HDMI_INFOFRAME_TYPE_VENDOR = 0x81,
168 HDMI_INFOFRAME_TYPE_AVI = 0x82,
169 HDMI_INFOFRAME_TYPE_SPD = 0x83,
170 HDMI_INFOFRAME_TYPE_AUDIO = 0x84,
171 };
172
173 #define HDMI_INFOFRAME_SIZE(TYPE) \
174 (HDMI_INFOFRAME_HEADER_SIZE + HDMI_##TYPE##_INFOFRAME_SIZE)
175
176 #define HDMI_INFOFRAME_HEADER_SIZE 4
177 struct hdmi_infoframe_header {
178 enum hdmi_infoframe_type type;
179 uint8_t version;
180 uint8_t length;
181 /* checksum */
182 };
183
184 static inline void
185 hdmi_infoframe_header_init(struct hdmi_infoframe_header *header,
186 enum hdmi_infoframe_type type, uint8_t vers, uint8_t length)
187 {
188
189 header->type = type;
190 header->version = vers;
191 header->length = length;
192 }
193
194 static inline int
195 hdmi_infoframe_header_pack(const struct hdmi_infoframe_header *header,
196 uint8_t length, void *buf, size_t size)
197 {
198 uint8_t *const p = buf;
199
200 if (length < HDMI_INFOFRAME_HEADER_SIZE)
201 return -ENOSPC;
202 if (size < length)
203 return -ENOSPC;
204
205 p[0] = header->type;
206 p[1] = header->version;
207 p[2] = (length - HDMI_INFOFRAME_HEADER_SIZE);
208 p[3] = 0; /* checksum */
209
210 return HDMI_INFOFRAME_HEADER_SIZE;
211 }
212
213 static inline void
214 hdmi_infoframe_checksum(void *buf, size_t length)
215 {
216 uint8_t *p = buf;
217 uint8_t checksum = 0;
218
219 while (length--)
220 checksum = *p++;
221
222 p = buf;
223 p[3] = (256 - checksum);
224 }
225
226 #define HDMI_AUDIO_INFOFRAME_SIZE 10
227 struct hdmi_audio_infoframe {
228 struct hdmi_infoframe_header header;
229 uint8_t channels;
230 enum hdmi_audio_coding_type coding_type;
231 enum hdmi_audio_sample_size sample_size;
232 enum hdmi_audio_sample_frequency sample_frequency;
233 enum hdmi_audio_coding_type_ext coding_type_ext;
234 uint8_t channel_allocation;
235 uint8_t level_shift_value;
236 bool downmix_inhibit;
237 };
238
239 static inline int
240 hdmi_audio_infoframe_init(struct hdmi_audio_infoframe *frame)
241 {
242 static const struct hdmi_audio_infoframe zero_frame;
243
244 *frame = zero_frame;
245
246 hdmi_infoframe_header_init(&frame->header, HDMI_INFOFRAME_TYPE_AUDIO,
247 1, HDMI_AUDIO_INFOFRAME_SIZE);
248
249 return 0;
250 }
251
252 static inline ssize_t
253 hdmi_audio_infoframe_pack(const struct hdmi_audio_infoframe *frame, void *buf,
254 size_t size)
255 {
256 const size_t length = HDMI_INFOFRAME_HEADER_SIZE +
257 HDMI_AUDIO_INFOFRAME_SIZE;
258 uint8_t channels = 0;
259 uint8_t *p = buf;
260 int ret;
261
262 KASSERT(frame->header.length == HDMI_AUDIO_INFOFRAME_SIZE);
263
264 ret = hdmi_infoframe_header_pack(&frame->header, length, p, size);
265 if (ret < 0)
266 return ret;
267 KASSERT(ret == HDMI_INFOFRAME_HEADER_SIZE);
268 p += HDMI_INFOFRAME_HEADER_SIZE;
269 size -= HDMI_INFOFRAME_HEADER_SIZE;
270
271 if (frame->channels >= 2)
272 channels = frame->channels - 1;
273
274 p[0] = __SHIFTIN(frame->coding_type, __BITS(7,4));
275 p[0] |= __SHIFTIN(channels, __BITS(2,0));
276
277 p[1] = __SHIFTIN(frame->sample_frequency, __BITS(4,2));
278 p[1] |= __SHIFTIN(frame->sample_size, __BITS(1,0));
279
280 p[2] = __SHIFTIN(frame->coding_type_ext, __BITS(5,0));
281
282 p[3] = __SHIFTIN(frame->level_shift_value, __BITS(6, 3));
283
284 p[4] = __SHIFTIN(frame->downmix_inhibit? 1 : 0, __BIT(7));
285
286 /* XXX p[5], p[6], p[7], p[8], p[9]? */
287 CTASSERT(HDMI_AUDIO_INFOFRAME_SIZE == 10);
288
289 hdmi_infoframe_checksum(buf, length);
290
291 return length;
292 }
293
294 #define HDMI_AVI_INFOFRAME_SIZE 13
295 struct hdmi_avi_infoframe {
296 struct hdmi_infoframe_header header;
297 enum hdmi_colorspace colorspace;
298 enum hdmi_scan_mode scan_mode;
299 enum hdmi_colorimetry colorimetry;
300 enum hdmi_picture_aspect picture_aspect;
301 enum hdmi_active_aspect active_aspect;
302 bool itc;
303 enum hdmi_extended_colorimetry extended_colorimetry;
304 enum hdmi_quantization_range quantization_range;
305 enum hdmi_nups nups;
306 uint8_t video_code;
307 enum hdmi_ycc_quantization_range ycc_quantization_range;
308 enum hdmi_content_type content_type;
309 uint8_t pixel_repeat;
310 uint16_t top_bar;
311 uint16_t bottom_bar;
312 uint16_t left_bar;
313 uint16_t right_bar;
314 };
315
316 static inline int
317 hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame)
318 {
319 static const struct hdmi_avi_infoframe zero_frame;
320
321 *frame = zero_frame;
322
323 hdmi_infoframe_header_init(&frame->header, HDMI_INFOFRAME_TYPE_AVI, 2,
324 HDMI_AVI_INFOFRAME_SIZE);
325
326 return 0;
327 }
328
329 static inline ssize_t
330 hdmi_avi_infoframe_pack(const struct hdmi_avi_infoframe *frame, void *buf,
331 size_t size)
332 {
333 const size_t length = HDMI_INFOFRAME_HEADER_SIZE +
334 HDMI_AVI_INFOFRAME_SIZE;
335 uint8_t *p = buf;
336 int ret;
337
338 KASSERT(frame->header.length == HDMI_AVI_INFOFRAME_SIZE);
339
340 ret = hdmi_infoframe_header_pack(&frame->header, length, p, size);
341 if (ret < 0)
342 return ret;
343 KASSERT(ret == HDMI_INFOFRAME_HEADER_SIZE);
344 p += HDMI_INFOFRAME_HEADER_SIZE;
345 size -= HDMI_INFOFRAME_HEADER_SIZE;
346
347 p[0] = __SHIFTIN(frame->colorspace, __BITS(6,5));
348 p[0] |= __SHIFTIN(frame->active_aspect & 0xf? 1 : 0, __BIT(4));
349 p[0] |= __SHIFTIN(frame->top_bar || frame->bottom_bar, __BIT(3));
350 p[0] |= __SHIFTIN(frame->left_bar || frame->right_bar, __BIT(2));
351 p[0] |= __SHIFTIN(frame->scan_mode, __BITS(1,0));
352
353 p[1] = __SHIFTIN(frame->colorimetry, __BITS(7,6));
354 p[1] |= __SHIFTIN(frame->picture_aspect, __BITS(5,4));
355 p[1] |= __SHIFTIN(frame->active_aspect, __BITS(3,0));
356
357 p[2] = __SHIFTIN(frame->itc? 1 : 0, __BIT(7));
358 p[2] |= __SHIFTIN(frame->extended_colorimetry, __BITS(6,4));
359 p[2] |= __SHIFTIN(frame->quantization_range, __BITS(3,2));
360 p[2] |= __SHIFTIN(frame->nups, __BITS(1,0));
361
362 p[3] = frame->video_code;
363
364 p[4] = __SHIFTIN(frame->ycc_quantization_range, __BITS(7,6));
365 p[4] |= __SHIFTIN(frame->content_type, __BITS(5,4));
366 p[4] |= __SHIFTIN(frame->pixel_repeat, __BITS(3,0));
367
368 le16enc(&p[5], frame->top_bar);
369 le16enc(&p[7], frame->bottom_bar);
370 le16enc(&p[9], frame->left_bar);
371 le16enc(&p[11], frame->right_bar);
372 CTASSERT(HDMI_AVI_INFOFRAME_SIZE == 13);
373
374 hdmi_infoframe_checksum(buf, length);
375
376 return length;
377 }
378
379 #define HDMI_SPD_INFOFRAME_SIZE 25
380 struct hdmi_spd_infoframe {
381 struct hdmi_infoframe_header header;
382 char vendor[8];
383 char product[16];
384 enum hdmi_spd_sdi {
385 HDMI_SPD_SDI_UNKNOWN = 0,
386 HDMI_SPD_SDI_DSTB = 1,
387 HDMI_SPD_SDI_DVDP = 2,
388 HDMI_SPD_SDI_DVHS = 3,
389 HDMI_SPD_SDI_HDDVR = 4,
390 HDMI_SPD_SDI_DVC = 5,
391 HDMI_SPD_SDI_DSC = 6,
392 HDMI_SPD_SDI_VCD = 7,
393 HDMI_SPD_SDI_GAME = 8,
394 HDMI_SPD_SDI_PC = 9,
395 HDMI_SPD_SDI_BD = 10,
396 HDMI_SPD_SDI_SACD = 11,
397 HDMI_SPD_SDI_HDDVD = 12,
398 HDMI_SPD_SDI_PMP = 13,
399 } sdi;
400 };
401
402 static inline int
403 hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame, const char *vendor,
404 const char *product)
405 {
406 static const struct hdmi_spd_infoframe zero_frame;
407
408 *frame = zero_frame;
409
410 hdmi_infoframe_header_init(&frame->header, HDMI_INFOFRAME_TYPE_SPD,
411 1, HDMI_SPD_INFOFRAME_SIZE);
412
413 (void)strlcpy(frame->vendor, vendor, sizeof(frame->vendor));
414 (void)strlcpy(frame->product, product, sizeof(frame->product));
415
416 return 0;
417 }
418
419 static inline ssize_t
420 hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buf,
421 size_t size)
422 {
423 const size_t length = HDMI_INFOFRAME_HEADER_SIZE +
424 HDMI_SPD_INFOFRAME_SIZE;
425 uint8_t *p = buf;
426 int ret;
427
428 KASSERT(frame->header.length == HDMI_SPD_INFOFRAME_SIZE);
429
430 ret = hdmi_infoframe_header_pack(&frame->header, length, p, size);
431 if (ret < 0)
432 return ret;
433 KASSERT(ret == HDMI_INFOFRAME_HEADER_SIZE);
434 p += HDMI_INFOFRAME_HEADER_SIZE;
435 size -= HDMI_INFOFRAME_HEADER_SIZE;
436
437 (void)memcpy(&p[0], frame->vendor, 8);
438 (void)memcpy(&p[8], frame->product, 16);
439 p[24] = frame->sdi;
440
441 hdmi_infoframe_checksum(buf, length);
442
443 return length;
444 }
445
446 #define HDMI_IEEE_OUI 0x000c03
447
448 struct hdmi_vendor_infoframe {
449 struct hdmi_infoframe_header header;
450 uint32_t oui;
451 uint8_t vic;
452 enum hdmi_3d_structure s3d_struct;
453 unsigned s3d_ext_data;
454 };
455
456 union hdmi_vendor_any_infoframe {
457 struct {
458 struct hdmi_infoframe_header header;
459 uint32_t oui;
460 } any;
461 struct hdmi_vendor_infoframe hdmi;
462 };
463
464 static inline int
465 hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame)
466 {
467 static const struct hdmi_vendor_infoframe zero_frame;
468
469 *frame = zero_frame;
470
471 hdmi_infoframe_header_init(&frame->header, HDMI_INFOFRAME_TYPE_VENDOR,
472 1, 0 /* depends on s3d_struct */);
473
474 frame->oui = HDMI_IEEE_OUI;
475 frame->s3d_struct = HDMI_3D_STRUCTURE_INVALID;
476
477 return 0;
478 }
479
480 static inline int
481 hdmi_vendor_infoframe_pack(const struct hdmi_vendor_infoframe *frame,
482 void *buf, size_t size)
483 {
484 uint8_t *p = buf;
485 size_t length;
486 int ret;
487
488 /* Exactly one must be supplied. */
489 if ((frame->vic == 0) ==
490 (frame->s3d_struct == HDMI_3D_STRUCTURE_INVALID))
491 return -EINVAL;
492
493 length = HDMI_INFOFRAME_HEADER_SIZE + 6;
494 if (frame->s3d_struct >= HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF)
495 length += 1;
496
497 ret = hdmi_infoframe_header_pack(&frame->header, length, p, size);
498 if (ret < 0)
499 return ret;
500 KASSERT(ret == HDMI_INFOFRAME_HEADER_SIZE);
501 p += HDMI_INFOFRAME_HEADER_SIZE;
502 size -= HDMI_INFOFRAME_HEADER_SIZE;
503
504 p[0] = 0x03;
505 p[1] = 0x0c;
506 p[2] = 0x00;
507
508 if (frame->vic == 0) {
509 p[3] = __SHIFTIN(0x2, __BITS(6,5));
510 p[4] = __SHIFTIN(frame->s3d_struct, __BITS(7,4));
511 if (frame->s3d_struct >= HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF)
512 p[9] = __SHIFTIN(frame->s3d_ext_data, __BITS(7,4));
513 } else {
514 p[3] = __SHIFTIN(0x1, __BITS(6,5));
515 p[4] = frame->vic;
516 }
517
518 hdmi_infoframe_checksum(buf, length);
519
520 return length;
521 }
522
523 union hdmi_infoframe {
524 struct hdmi_infoframe_header any;
525 struct hdmi_avi_infoframe avi;
526 struct hdmi_spd_infoframe spd;
527 union hdmi_vendor_any_infoframe vendor;
528 };
529
530 static inline ssize_t
531 hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buf, size_t size)
532 {
533
534 switch (frame->any.type) {
535 case HDMI_INFOFRAME_TYPE_AVI:
536 return hdmi_avi_infoframe_pack(&frame->avi, buf, size);
537 case HDMI_INFOFRAME_TYPE_SPD:
538 return hdmi_spd_infoframe_pack(&frame->spd, buf, size);
539 case HDMI_INFOFRAME_TYPE_VENDOR:
540 return hdmi_vendor_infoframe_pack(&frame->vendor.hdmi, buf,
541 size);
542 default:
543 return -EINVAL;
544 }
545 }
546
547 #endif /* _LINUX_HDMI_H_ */
548