xref: /netbsd-src/sys/external/bsd/drm2/include/linux/hdmi.h (revision 53b02e147d4ed531c0d2a5ca9b3e8026ba3e99b5)
1 /*	$NetBSD: hdmi.h,v 1.14 2021/12/19 11:45:35 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_NONE			= 0,
54 	HDMI_ACTIVE_ASPECT_16_9_TOP		= 2,
55 	HDMI_ACTIVE_ASPECT_14_9_TOP		= 3,
56 	HDMI_ACTIVE_ASPECT_16_9_CENTER		= 4,
57 	HDMI_ACTIVE_ASPECT_PICTURE		= 8,
58 	HDMI_ACTIVE_ASPECT_4_3			= 9,
59 	HDMI_ACTIVE_ASPECT_16_9			= 10,
60 	HDMI_ACTIVE_ASPECT_14_9			= 11,
61 	HDMI_ACTIVE_ASPECT_4_3_SP_14_9		= 13,
62 	HDMI_ACTIVE_ASPECT_16_9_SP_14_9		= 14,
63 	HDMI_ACTIVE_ASPECT_16_9_SP_4_3		= 15,
64 };
65 
66 enum hdmi_audio_coding_type {
67 	HDMI_AUDIO_CODING_TYPE_STREAM		= 0,
68 	HDMI_AUDIO_CODING_TYPE_PCM		= 1,
69 	HDMI_AUDIO_CODING_TYPE_AC3		= 2,
70 	HDMI_AUDIO_CODING_TYPE_MPEG1		= 3,
71 	HDMI_AUDIO_CODING_TYPE_MP3		= 4,
72 	HDMI_AUDIO_CODING_TYPE_MPEG2		= 5,
73 	HDMI_AUDIO_CODING_TYPE_AAC_LC		= 6,
74 	HDMI_AUDIO_CODING_TYPE_DTS		= 7,
75 	HDMI_AUDIO_CODING_TYPE_ATRAC		= 8,
76 	HDMI_AUDIO_CODING_TYPE_DSD		= 9,
77 	HDMI_AUDIO_CODING_TYPE_EAC3		= 10,
78 	HDMI_AUDIO_CODING_TYPE_DTS_HD		= 11,
79 	HDMI_AUDIO_CODING_TYPE_MLP		= 12,
80 	HDMI_AUDIO_CODING_TYPE_DST		= 13,
81 	HDMI_AUDIO_CODING_TYPE_WMA_PRO		= 14,
82 };
83 
84 enum hdmi_audio_coding_type_ext {
85 	HDMI_AUDIO_CODING_TYPE_EXT_STREAM	= 0,
86 	HDMI_AUDIO_CODING_TYPE_EXT_HE_AAC	= 1,
87 	HDMI_AUDIO_CODING_TYPE_EXT_HE_AAC_V2	= 2,
88 	HDMI_AUDIO_CODING_TYPE_EXT_MPEG_SURROUND = 3,
89 };
90 
91 enum hdmi_audio_sample_frequency {
92 	HDMI_AUDIO_SAMPLE_FREQUENCY_STREAM	= 0,
93 	HDMI_AUDIO_SAMPLE_FREQUENCY_32000	= 1,
94 	HDMI_AUDIO_SAMPLE_FREQUENCY_44100	= 2,
95 	HDMI_AUDIO_SAMPLE_FREQUENCY_48000	= 3,
96 	HDMI_AUDIO_SAMPLE_FREQUENCY_88200	= 4,
97 	HDMI_AUDIO_SAMPLE_FREQUENCY_96000	= 5,
98 	HDMI_AUDIO_SAMPLE_FREQUENCY_176400	= 6,
99 	HDMI_AUDIO_SAMPLE_FREQUENCY_192000	= 7,
100 };
101 
102 enum hdmi_audio_sample_size {
103 	HDMI_AUDIO_SAMPLE_SIZE_STREAM		= 0,
104 	HDMI_AUDIO_SAMPLE_SIZE_16		= 1,
105 	HDMI_AUDIO_SAMPLE_SIZE_20		= 2,
106 	HDMI_AUDIO_SAMPLE_SIZE_24		= 3,
107 };
108 
109 enum hdmi_colorimetry {
110 	HDMI_COLORIMETRY_NONE			= 0,
111 	HDMI_COLORIMETRY_ITU_601		= 1,
112 	HDMI_COLORIMETRY_ITU_709		= 2,
113 	HDMI_COLORIMETRY_EXTENDED		= 3,
114 };
115 
116 enum hdmi_colorspace {
117 	HDMI_COLORSPACE_RGB			= 0,
118 	HDMI_COLORSPACE_YUV422			= 1,
119 	HDMI_COLORSPACE_YUV444			= 2,
120 	HDMI_COLORSPACE_YUV420			= 3,
121 	HDMI_COLORSPACE_IDO_DEFINED		= 7,
122 };
123 
124 enum hdmi_content_type {
125 	HDMI_CONTENT_TYPE_GRAPHICS		= 0,
126 	HDMI_CONTENT_TYPE_PHOTO			= 1,
127 	HDMI_CONTENT_TYPE_CINEMA		= 2,
128 	HDMI_CONTENT_TYPE_GAME			= 3,
129 };
130 
131 enum hdmi_extended_colorimetry {
132 	HDMI_EXTENDED_COLORIMETRY_XV_YCC_601	= 0,
133 	HDMI_EXTENDED_COLORIMETRY_XV_YCC_709	= 1,
134 	HDMI_EXTENDED_COLORIMETRY_S_YCC_601	= 2,
135 	HDMI_EXTENDED_COLORIMETRY_OPYCC_601	= 3,
136 	HDMI_EXTENDED_COLORIMETRY_OPRGB		= 4,
137 };
138 
139 enum hdmi_nups {
140 	HDMI_NUPS_UNKNOWN			= 0,
141 	HDMI_NUPS_HORIZONTAL			= 1,
142 	HDMI_NUPS_VERTICAL			= 2,
143 	HDMI_NUPS_BOTH				= 3,
144 };
145 
146 enum hdmi_picture_aspect {
147 	HDMI_PICTURE_ASPECT_NONE		= 0,
148 	HDMI_PICTURE_ASPECT_4_3			= 1,
149 	HDMI_PICTURE_ASPECT_16_9		= 2,
150 	HDMI_PICTURE_ASPECT_64_27		= 3,
151 	HDMI_PICTURE_ASPECT_256_135		= 4,
152 	HDMI_PICTURE_ASPECT_RESERVED		= 5,
153 };
154 
155 enum hdmi_quantization_range {
156 	HDMI_QUANTIZATION_RANGE_DEFAULT		= 0,
157 	HDMI_QUANTIZATION_RANGE_LIMITED		= 1,
158 	HDMI_QUANTIZATION_RANGE_FULL		= 2,
159 };
160 
161 enum hdmi_scan_mode {
162 	HDMI_SCAN_MODE_NONE			= 0,
163 	HDMI_SCAN_MODE_OVERSCAN			= 1,
164 	HDMI_SCAN_MODE_UNDERSCAN		= 2,
165 };
166 
167 enum hdmi_ycc_quantization_range {
168 	HDMI_YCC_QUANTIZATION_RANGE_LIMITED	= 0,
169 	HDMI_YCC_QUANTIZATION_RANGE_FULL	= 1,
170 };
171 
172 enum hdmi_packet_type {
173         HDMI_PACKET_TYPE_NULL = 0x00,
174         HDMI_PACKET_TYPE_AUDIO_CLOCK_REGEN	= 0x01,
175         HDMI_PACKET_TYPE_AUDIO_SAMPLE		= 0x02,
176         HDMI_PACKET_TYPE_GENERAL_CONTROL	= 0x03,
177         HDMI_PACKET_TYPE_ACP			= 0x04,
178         HDMI_PACKET_TYPE_ISRC1			= 0x05,
179         HDMI_PACKET_TYPE_ISRC2			= 0x06,
180         HDMI_PACKET_TYPE_ONE_BIT_AUDIO_SAMPLE	= 0x07,
181         HDMI_PACKET_TYPE_DST_AUDIO		= 0x08,
182         HDMI_PACKET_TYPE_HBR_AUDIO_STREAM	= 0x09,
183         HDMI_PACKET_TYPE_GAMUT_METADATA		= 0x0a,
184 };
185 
186 enum hdmi_infoframe_type {
187 	HDMI_INFOFRAME_TYPE_VENDOR		= 0x81,
188 	HDMI_INFOFRAME_TYPE_AVI			= 0x82,
189 	HDMI_INFOFRAME_TYPE_SPD			= 0x83,
190 	HDMI_INFOFRAME_TYPE_AUDIO		= 0x84,
191 	HDMI_INFOFRAME_TYPE_DRM			= 0x87,
192 };
193 
194 enum hdmi_eotf {
195 	HDMI_EOTF_TRADITIONAL_GAMMA_SDR		= 0,
196 	HDMI_EOTF_TRADITIONAL_GAMMA_HDR		= 1,
197 	HDMI_EOTF_SMPTE_ST2084			= 2,
198 	HDMI_EOTF_BT_2100_HLG			= 3,
199 };
200 
201 enum hdmi_metadata_type {
202 	HDMI_STATIC_METADATA_TYPE1		= 1,
203 };
204 
205 struct hdmi_type1 {
206 	enum hdmi_eotf			eotf;
207 	enum hdmi_metadata_type		metadata_type;
208 	uint16_t			min_cll;
209 	uint16_t			max_cll;
210 	uint16_t			max_fall;
211 };
212 
213 struct hdr_sink_metadata {
214 	struct hdmi_type1		hdmi_type1;
215 };
216 
217 #define	HDMI_INFOFRAME_SIZE(TYPE)					      \
218 	(HDMI_INFOFRAME_HEADER_SIZE + HDMI_##TYPE##_INFOFRAME_SIZE)
219 
220 #define	HDMI_INFOFRAME_HEADER_SIZE	4
221 struct hdmi_infoframe_header {
222 	enum hdmi_infoframe_type	type;
223 	uint8_t				version;
224 	uint8_t				length;
225 	/* checksum */
226 };
227 
228 static inline void
229 hdmi_infoframe_header_init(struct hdmi_infoframe_header *header,
230     enum hdmi_infoframe_type type, uint8_t vers, uint8_t length)
231 {
232 
233 	header->type = type;
234 	header->version = vers;
235 	header->length = length;
236 }
237 
238 static inline int
239 hdmi_infoframe_header_check(const struct hdmi_infoframe_header *header,
240     enum hdmi_infoframe_type type, uint8_t vers, uint8_t length)
241 {
242 
243 	if (header->type != type ||
244 	    header->version != vers ||
245 	    header->length != length)
246 		return -EINVAL;
247 	return 0;
248 }
249 
250 static inline int
251 hdmi_infoframe_header_pack(const struct hdmi_infoframe_header *header,
252     uint8_t length, void *buf, size_t size)
253 {
254 	uint8_t *const p = buf;
255 
256 	if (length < HDMI_INFOFRAME_HEADER_SIZE)
257 		return -ENOSPC;
258 	if (size < length)
259 		return -ENOSPC;
260 
261 	p[0] = header->type;
262 	p[1] = header->version;
263 	p[2] = (length - HDMI_INFOFRAME_HEADER_SIZE);
264 	p[3] = 0;		/* checksum */
265 
266 	return HDMI_INFOFRAME_HEADER_SIZE;
267 }
268 
269 static inline uint8_t
270 hdmi_infoframe_checksum(const void *buf, size_t length)
271 {
272 	const uint8_t *p = buf;
273 	uint8_t checksum = 0;
274 
275 	while (length--)
276 		checksum += *p++;
277 
278 	return 256 - checksum;
279 }
280 
281 static inline int
282 hdmi_infoframe_header_unpack(struct hdmi_infoframe_header *header,
283     const void *buf, size_t size)
284 {
285 	const uint8_t *const p = buf;
286 
287 	if (size < HDMI_INFOFRAME_HEADER_SIZE)
288 		return -EINVAL;
289 	if (p[2] > size - HDMI_INFOFRAME_HEADER_SIZE)
290 		return -EINVAL;
291 	if (hdmi_infoframe_checksum(buf, p[2] + HDMI_INFOFRAME_HEADER_SIZE))
292 		return -EINVAL;
293 
294 	hdmi_infoframe_header_init(header, p[0], p[1], p[2]);
295 	return HDMI_INFOFRAME_HEADER_SIZE;
296 }
297 
298 static inline void
299 hdmi_infoframe_set_checksum(void *buf, size_t length)
300 {
301 	uint8_t *p = buf;
302 
303 	p[3] = hdmi_infoframe_checksum(buf, length);
304 }
305 
306 #define	HDMI_AUDIO_INFOFRAME_SIZE	10
307 struct hdmi_audio_infoframe {
308 	struct hdmi_infoframe_header	header;
309 	uint8_t				channels;
310 	enum hdmi_audio_coding_type	coding_type;
311 	enum hdmi_audio_sample_size	sample_size;
312 	enum hdmi_audio_sample_frequency sample_frequency;
313 	enum hdmi_audio_coding_type_ext	coding_type_ext;
314 	uint8_t				channel_allocation;
315 	uint8_t				level_shift_value;
316 	bool				downmix_inhibit;
317 };
318 
319 static inline int
320 hdmi_audio_infoframe_init(struct hdmi_audio_infoframe *frame)
321 {
322 	static const struct hdmi_audio_infoframe zero_frame;
323 
324 	*frame = zero_frame;
325 
326 	hdmi_infoframe_header_init(&frame->header, HDMI_INFOFRAME_TYPE_AUDIO,
327 	    1, HDMI_AUDIO_INFOFRAME_SIZE);
328 
329 	return 0;
330 }
331 
332 static inline ssize_t
333 hdmi_audio_infoframe_pack(const struct hdmi_audio_infoframe *frame, void *buf,
334     size_t size)
335 {
336 	const size_t length = HDMI_INFOFRAME_HEADER_SIZE +
337 	    HDMI_AUDIO_INFOFRAME_SIZE;
338 	uint8_t channels = 0;
339 	uint8_t *p = buf;
340 	int ret;
341 
342 	KASSERT(frame->header.length == HDMI_AUDIO_INFOFRAME_SIZE);
343 
344 	ret = hdmi_infoframe_header_pack(&frame->header, length, p, size);
345 	if (ret < 0)
346 		return ret;
347 	KASSERT(ret == HDMI_INFOFRAME_HEADER_SIZE);
348 	p += HDMI_INFOFRAME_HEADER_SIZE;
349 	size -= HDMI_INFOFRAME_HEADER_SIZE;
350 
351 	if (frame->channels >= 2)
352 		channels = frame->channels - 1;
353 
354 	p[0] = __SHIFTIN(frame->coding_type, __BITS(7,4));
355 	p[0] |= __SHIFTIN(channels, __BITS(2,0));
356 
357 	p[1] = __SHIFTIN(frame->sample_frequency, __BITS(4,2));
358 	p[1] |= __SHIFTIN(frame->sample_size, __BITS(1,0));
359 
360 	p[2] = __SHIFTIN(frame->coding_type_ext, __BITS(5,0));
361 
362 	p[3] = __SHIFTIN(frame->level_shift_value, __BITS(6,3));
363 
364 	p[4] = __SHIFTIN(frame->downmix_inhibit? 1 : 0, __BIT(7));
365 
366 	/* PB6 to PB10 are reserved */
367 	p[5] = 0;
368 	p[6] = 0;
369 	p[7] = 0;
370 	p[8] = 0;
371 	p[9] = 0;
372 
373 	CTASSERT(HDMI_AUDIO_INFOFRAME_SIZE == 10);
374 
375 	hdmi_infoframe_set_checksum(buf, length);
376 
377 	return length;
378 }
379 
380 static inline int
381 hdmi_audio_infoframe_unpack(struct hdmi_audio_infoframe *frame,
382     const void *buf, size_t size)
383 {
384 	const uint8_t *p = buf;
385 	int ret;
386 
387 	memset(frame, 0, sizeof(*frame));
388 
389 	ret = hdmi_infoframe_header_unpack(&frame->header, p, size);
390 	if (ret)
391 		return ret;
392 	if (frame->header.length != HDMI_AUDIO_INFOFRAME_SIZE)
393 		return -EINVAL;
394 	p += HDMI_INFOFRAME_HEADER_SIZE;
395 	size -= HDMI_INFOFRAME_HEADER_SIZE;
396 
397 	frame->coding_type = __SHIFTOUT(p[0], __BITS(7,4));
398 	frame->channels = __SHIFTOUT(p[0], __BITS(2,0));
399 
400 	frame->sample_frequency = __SHIFTOUT(p[1], __BITS(4,2));
401 	frame->sample_size = __SHIFTOUT(p[1], __BITS(1,0));
402 
403 	frame->coding_type_ext = __SHIFTOUT(p[2], __BITS(5,0));
404 
405 	frame->level_shift_value = __SHIFTOUT(p[3], __BITS(6,3));
406 
407 	frame->downmix_inhibit = __SHIFTOUT(p[4], __BIT(7));
408 
409 	return 0;
410 }
411 
412 #define	HDMI_AVI_INFOFRAME_SIZE		13
413 struct hdmi_avi_infoframe {
414 	struct hdmi_infoframe_header	header;
415 	enum hdmi_colorspace		colorspace;
416 	enum hdmi_scan_mode		scan_mode;
417 	enum hdmi_colorimetry		colorimetry;
418 	enum hdmi_picture_aspect	picture_aspect;
419 	enum hdmi_active_aspect		active_aspect;
420 	bool				itc;
421 	enum hdmi_extended_colorimetry	extended_colorimetry;
422 	enum hdmi_quantization_range	quantization_range;
423 	enum hdmi_nups			nups;
424 	uint8_t				video_code;
425 	enum hdmi_ycc_quantization_range ycc_quantization_range;
426 	enum hdmi_content_type		content_type;
427 	uint8_t				pixel_repeat;
428 	uint16_t			top_bar;
429 	uint16_t			bottom_bar;
430 	uint16_t			left_bar;
431 	uint16_t			right_bar;
432 };
433 
434 static inline int
435 hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame)
436 {
437 	static const struct hdmi_avi_infoframe zero_frame;
438 
439 	*frame = zero_frame;
440 
441 	hdmi_infoframe_header_init(&frame->header, HDMI_INFOFRAME_TYPE_AVI, 2,
442 	    HDMI_AVI_INFOFRAME_SIZE);
443 
444 	return 0;
445 }
446 
447 static inline int
448 hdmi_avi_infoframe_check(const struct hdmi_avi_infoframe *frame)
449 {
450 	int ret;
451 
452 	ret = hdmi_infoframe_header_check(&frame->header,
453 	    HDMI_INFOFRAME_TYPE_AVI, 2, HDMI_AVI_INFOFRAME_SIZE);
454 	if (ret)
455 		return ret;
456 
457 	return 0;
458 }
459 
460 static inline ssize_t
461 hdmi_avi_infoframe_pack(const struct hdmi_avi_infoframe *frame, void *buf,
462     size_t size)
463 {
464 	const size_t length = HDMI_INFOFRAME_HEADER_SIZE +
465 	    HDMI_AVI_INFOFRAME_SIZE;
466 	uint8_t *p = buf;
467 	int ret;
468 
469 	KASSERT(frame->header.length == HDMI_AVI_INFOFRAME_SIZE);
470 
471 	ret = hdmi_infoframe_header_pack(&frame->header, length, p, size);
472 	if (ret < 0)
473 		return ret;
474 	KASSERT(ret == HDMI_INFOFRAME_HEADER_SIZE);
475 	p += HDMI_INFOFRAME_HEADER_SIZE;
476 	size -= HDMI_INFOFRAME_HEADER_SIZE;
477 
478 	p[0] = __SHIFTIN(frame->colorspace, __BITS(6,5));
479 	p[0] |= __SHIFTIN(frame->active_aspect & 0xf? 1 : 0, __BIT(4));
480 	p[0] |= __SHIFTIN(frame->top_bar || frame->bottom_bar, __BIT(3));
481 	p[0] |= __SHIFTIN(frame->left_bar || frame->right_bar, __BIT(2));
482 	p[0] |= __SHIFTIN(frame->scan_mode, __BITS(1,0));
483 
484 	p[1] = __SHIFTIN(frame->colorimetry, __BITS(7,6));
485 	p[1] |= __SHIFTIN(frame->picture_aspect, __BITS(5,4));
486 	p[1] |= __SHIFTIN(frame->active_aspect, __BITS(3,0));
487 
488 	p[2] = __SHIFTIN(frame->itc? 1 : 0, __BIT(7));
489 	p[2] |= __SHIFTIN(frame->extended_colorimetry, __BITS(6,4));
490 	p[2] |= __SHIFTIN(frame->quantization_range, __BITS(3,2));
491 	p[2] |= __SHIFTIN(frame->nups, __BITS(1,0));
492 
493 	p[3] = frame->video_code;
494 
495 	p[4] = __SHIFTIN(frame->ycc_quantization_range, __BITS(7,6));
496 	p[4] |= __SHIFTIN(frame->content_type, __BITS(5,4));
497 	p[4] |= __SHIFTIN(frame->pixel_repeat, __BITS(3,0));
498 
499 	le16enc(&p[5], frame->top_bar);
500 	le16enc(&p[7], frame->bottom_bar);
501 	le16enc(&p[9], frame->left_bar);
502 	le16enc(&p[11], frame->right_bar);
503 	CTASSERT(HDMI_AVI_INFOFRAME_SIZE == 13);
504 
505 	hdmi_infoframe_set_checksum(buf, length);
506 
507 	return length;
508 }
509 
510 static inline int
511 hdmi_avi_infoframe_unpack(struct hdmi_avi_infoframe *frame, const void *buf,
512     size_t size)
513 {
514 	const uint8_t *p = buf;
515 	int ret;
516 
517 	memset(frame, 0, sizeof(*frame));
518 
519 	ret = hdmi_infoframe_header_unpack(&frame->header, p, size);
520 	if (ret)
521 		return ret;
522 	if (frame->header.length != HDMI_AVI_INFOFRAME_SIZE)
523 		return -EINVAL;
524 	p += HDMI_INFOFRAME_HEADER_SIZE;
525 	size -= HDMI_INFOFRAME_HEADER_SIZE;
526 
527 	frame->colorspace = __SHIFTOUT(p[0], __BITS(6,5));
528 	frame->scan_mode = __SHIFTOUT(p[0], __BITS(1,0));
529 
530 	frame->colorimetry = __SHIFTOUT(p[1], __BITS(7,6));
531 	frame->picture_aspect = __SHIFTOUT(p[1], __BITS(5,4));
532 	if (p[0] & __BIT(4))
533 		frame->active_aspect = __SHIFTOUT(p[1], __BITS(3,0));
534 
535 	frame->itc = __SHIFTOUT(p[2], __BIT(7));
536 	frame->extended_colorimetry = __SHIFTOUT(p[2], __BITS(6,4));
537 	frame->quantization_range = __SHIFTOUT(p[2], __BITS(3,2));
538 	frame->nups = __SHIFTOUT(p[2], __BITS(1,0));
539 
540 	frame->video_code = p[3];
541 
542 	frame->ycc_quantization_range = __SHIFTOUT(p[4], __BITS(7,6));
543 	frame->content_type = __SHIFTOUT(p[4], __BITS(5,4));
544 	frame->pixel_repeat = __SHIFTOUT(p[4], __BITS(3,0));
545 
546 	if (p[0] & __BIT(3)) {
547 		frame->top_bar = le16dec(&p[5]);
548 		frame->bottom_bar = le16dec(&p[7]);
549 	}
550 	if (p[0] & __BIT(2)) {
551 		frame->left_bar = le16dec(&p[9]);
552 		frame->right_bar = le16dec(&p[11]);
553 	}
554 
555 	return 0;
556 }
557 
558 #define	HDMI_DRM_INFOFRAME_SIZE		26
559 struct hdmi_drm_infoframe {
560 	struct hdmi_infoframe_header	header;
561 	enum hdmi_eotf			eotf;
562 	enum hdmi_metadata_type		metadata_type;
563 	struct {
564 		uint16_t	x, y;
565 	}				display_primaries[3];
566 	struct {
567 		uint16_t	x, y;
568 	}				white_point;
569 	uint16_t			max_display_mastering_luminance;
570 	uint16_t			min_display_mastering_luminance;
571 	uint16_t			max_cll;
572 	uint16_t			max_fall;
573 };
574 
575 static inline int
576 hdmi_drm_infoframe_init(struct hdmi_drm_infoframe *frame)
577 {
578 	static const struct hdmi_drm_infoframe zero_frame;
579 
580 	*frame = zero_frame;
581 
582 	hdmi_infoframe_header_init(&frame->header, HDMI_INFOFRAME_TYPE_DRM,
583 	    1, HDMI_DRM_INFOFRAME_SIZE);
584 
585 	return 0;
586 }
587 
588 static inline int
589 hdmi_drm_infoframe_check(const struct hdmi_drm_infoframe *frame)
590 {
591 	int ret;
592 
593 	ret = hdmi_infoframe_header_check(&frame->header,
594 	    HDMI_INFOFRAME_TYPE_DRM, 1, HDMI_DRM_INFOFRAME_SIZE);
595 	if (ret)
596 		return ret;
597 
598 	return 0;
599 }
600 
601 #define	hdmi_drm_infoframe_pack_only	hdmi_drm_infoframe_pack /* XXX */
602 
603 static inline int
604 hdmi_drm_infoframe_pack(const struct hdmi_drm_infoframe *frame,
605     void *buf, size_t size)
606 {
607 	const size_t length = HDMI_INFOFRAME_HEADER_SIZE +
608 	    HDMI_DRM_INFOFRAME_SIZE;
609 	uint8_t *p = buf;
610 	unsigned i;
611 	int ret;
612 
613 	KASSERT(frame->header.length == HDMI_DRM_INFOFRAME_SIZE);
614 
615 	ret = hdmi_infoframe_header_pack(&frame->header, length, p, size);
616 	if (ret < 0)
617 		return ret;
618 	KASSERT(ret == HDMI_INFOFRAME_HEADER_SIZE);
619 	p += HDMI_INFOFRAME_HEADER_SIZE;
620 	size -= HDMI_INFOFRAME_HEADER_SIZE;
621 
622 	p[0] = frame->eotf;
623 	p[1] = frame->metadata_type;
624 	for (i = 0; i < __arraycount(frame->display_primaries); i++) {
625 		le16enc(&p[2 + 4*i], frame->display_primaries[i].x);
626 		le16enc(&p[2 + 4*i + 2], frame->display_primaries[i].y);
627 	}
628 	le16enc(&p[14], frame->white_point.x);
629 	le16enc(&p[16], frame->white_point.y);
630 	le16enc(&p[18], frame->min_display_mastering_luminance);
631 	le16enc(&p[20], frame->max_display_mastering_luminance);
632 	le16enc(&p[22], frame->max_cll);
633 	le16enc(&p[24], frame->max_fall);
634 	CTASSERT(HDMI_DRM_INFOFRAME_SIZE == 26);
635 
636 	hdmi_infoframe_set_checksum(buf, length);
637 
638 	return length;
639 }
640 
641 static inline int
642 hdmi_drm_infoframe_unpack(struct hdmi_drm_infoframe *frame, const void *buf,
643     size_t size)
644 {
645 	const uint8_t *p = buf;
646 	unsigned i;
647 	int ret;
648 
649 	memset(frame, 0, sizeof(*frame));
650 
651 	ret = hdmi_infoframe_header_unpack(&frame->header, p, size);
652 	if (ret)
653 		return ret;
654 	if (frame->header.length != HDMI_DRM_INFOFRAME_SIZE)
655 		return -EINVAL;
656 	p += HDMI_INFOFRAME_HEADER_SIZE;
657 	size -= HDMI_INFOFRAME_HEADER_SIZE;
658 
659 	frame->eotf = p[0];
660 	frame->metadata_type = p[1];
661 	for (i = 0; i < __arraycount(frame->display_primaries); i++) {
662 		frame->display_primaries[i].x = le16dec(&p[2 + 4*i]);
663 		frame->display_primaries[i].y = le16dec(&p[2 + 4*i + 2]);
664 	}
665 	frame->white_point.x = le16dec(&p[14]);
666 	frame->white_point.y = le16dec(&p[16]);
667 	frame->min_display_mastering_luminance = le16dec(&p[18]);
668 	frame->max_display_mastering_luminance = le16dec(&p[20]);
669 	frame->max_cll = le16dec(&p[22]);
670 	frame->max_fall = le16dec(&p[24]);
671 
672 	return 0;
673 }
674 
675 #define	HDMI_SPD_INFOFRAME_SIZE		25
676 struct hdmi_spd_infoframe {
677 	struct hdmi_infoframe_header	header;
678 	char				vendor[8];
679 	char				product[16];
680 	enum hdmi_spd_sdi {
681 	        HDMI_SPD_SDI_UNKNOWN	= 0,
682 		HDMI_SPD_SDI_DSTB	= 1,
683 		HDMI_SPD_SDI_DVDP	= 2,
684 		HDMI_SPD_SDI_DVHS	= 3,
685 		HDMI_SPD_SDI_HDDVR	= 4,
686 		HDMI_SPD_SDI_DVC	= 5,
687 		HDMI_SPD_SDI_DSC	= 6,
688 		HDMI_SPD_SDI_VCD	= 7,
689 		HDMI_SPD_SDI_GAME	= 8,
690 		HDMI_SPD_SDI_PC		= 9,
691 		HDMI_SPD_SDI_BD		= 10,
692 		HDMI_SPD_SDI_SACD	= 11,
693 		HDMI_SPD_SDI_HDDVD	= 12,
694 		HDMI_SPD_SDI_PMP	= 13,
695 	}				sdi;
696 };
697 
698 static inline int
699 hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame, const char *vendor,
700     const char *product)
701 {
702 	static const struct hdmi_spd_infoframe zero_frame;
703 
704 	*frame = zero_frame;
705 
706 	hdmi_infoframe_header_init(&frame->header, HDMI_INFOFRAME_TYPE_SPD,
707 	    1, HDMI_SPD_INFOFRAME_SIZE);
708 
709 	strncpy(frame->vendor, vendor, sizeof(frame->vendor));
710 	strncpy(frame->product, product, sizeof(frame->product));
711 
712 	return 0;
713 }
714 
715 static inline int
716 hdmi_spd_infoframe_check(const struct hdmi_spd_infoframe *frame)
717 {
718 	int ret;
719 
720 	ret = hdmi_infoframe_header_check(&frame->header,
721 	    HDMI_INFOFRAME_TYPE_SPD, 2, HDMI_SPD_INFOFRAME_SIZE);
722 	if (ret)
723 		return ret;
724 
725 	return 0;
726 }
727 
728 static inline ssize_t
729 hdmi_spd_infoframe_pack(const struct hdmi_spd_infoframe *frame, void *buf,
730     size_t size)
731 {
732 	const size_t length = HDMI_INFOFRAME_HEADER_SIZE +
733 	    HDMI_SPD_INFOFRAME_SIZE;
734 	uint8_t *p = buf;
735 	int ret;
736 
737 	KASSERT(frame->header.length == HDMI_SPD_INFOFRAME_SIZE);
738 
739 	ret = hdmi_infoframe_header_pack(&frame->header, length, p, size);
740 	if (ret < 0)
741 		return ret;
742 	KASSERT(ret == HDMI_INFOFRAME_HEADER_SIZE);
743 	p += HDMI_INFOFRAME_HEADER_SIZE;
744 	size -= HDMI_INFOFRAME_HEADER_SIZE;
745 
746 	memcpy(&p[0], frame->vendor, 8);
747 	memcpy(&p[8], frame->product, 16);
748 	p[24] = frame->sdi;
749 	CTASSERT(HDMI_SPD_INFOFRAME_SIZE == 25);
750 
751 	hdmi_infoframe_set_checksum(buf, length);
752 
753 	return length;
754 }
755 
756 static inline int
757 hdmi_spd_infoframe_unpack(struct hdmi_spd_infoframe *frame, const void *buf,
758     size_t size)
759 {
760 	const uint8_t *p = buf;
761 	int ret;
762 
763 	memset(frame, 0, sizeof(*frame));
764 
765 	ret = hdmi_infoframe_header_unpack(&frame->header, p, size);
766 	if (ret)
767 		return ret;
768 	if (frame->header.length != HDMI_SPD_INFOFRAME_SIZE)
769 		return -EINVAL;
770 	p += HDMI_INFOFRAME_HEADER_SIZE;
771 	size -= HDMI_INFOFRAME_HEADER_SIZE;
772 
773 	memcpy(frame->vendor, &p[0], 8);
774 	memcpy(frame->product, &p[8], 8);
775 	frame->sdi = p[24];
776 
777 	return 0;
778 }
779 
780 #define	HDMI_IEEE_OUI		0x000c03
781 #define	HDMI_FORUM_IEEE_OUI	0xc45dd8
782 
783 struct hdmi_vendor_infoframe {
784 	struct hdmi_infoframe_header	header;
785 	uint32_t			oui;
786 	uint8_t				vic;
787 	enum hdmi_3d_structure		s3d_struct;
788 	unsigned			s3d_ext_data;
789 };
790 
791 union hdmi_vendor_any_infoframe {
792 	struct {
793 		struct hdmi_infoframe_header	header;
794 		uint32_t			oui;
795 	}				any;
796 	struct hdmi_vendor_infoframe	hdmi;
797 };
798 
799 static inline int
800 hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame)
801 {
802 	static const struct hdmi_vendor_infoframe zero_frame;
803 
804 	*frame = zero_frame;
805 
806 	hdmi_infoframe_header_init(&frame->header, HDMI_INFOFRAME_TYPE_VENDOR,
807 	    1, 0 /* depends on s3d_struct */);
808 
809 	frame->oui = HDMI_IEEE_OUI;
810 	frame->s3d_struct = HDMI_3D_STRUCTURE_INVALID;
811 
812 	return 0;
813 }
814 
815 static inline size_t
816 hdmi_vendor_infoframe_length(const struct hdmi_vendor_infoframe *frame)
817 {
818 
819 	if (frame->vic) {
820 		return 5;
821 	} else if (frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID) {
822 		if (frame->s3d_struct < HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF)
823 			return 5;
824 		else
825 			return 6;
826 	} else {
827 		return 4;
828 	}
829 }
830 
831 static inline int
832 hdmi_vendor_infoframe_check(const struct hdmi_vendor_infoframe *frame)
833 {
834 
835 	if (frame->header.type != HDMI_INFOFRAME_TYPE_VENDOR ||
836 	    frame->header.version != 1)
837 		return -EINVAL;
838 	/* frame->header.length not used when packing */
839 
840 	/* At most one may be supplied.  */
841 	if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID)
842 		return -EINVAL;
843 
844 	return 0;
845 }
846 
847 static inline int
848 hdmi_vendor_infoframe_pack(const struct hdmi_vendor_infoframe *frame,
849     void *buf, size_t size)
850 {
851 	uint8_t *p = buf;
852 	size_t length;
853 	int ret;
854 
855 	/* At most one may be supplied.  */
856 	if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID)
857 		return -EINVAL;
858 
859 	length = HDMI_INFOFRAME_HEADER_SIZE;
860 	length += hdmi_vendor_infoframe_length(frame);
861 
862 	ret = hdmi_infoframe_header_pack(&frame->header, length, p, size);
863 	if (ret < 0)
864 		return ret;
865 	KASSERT(ret == HDMI_INFOFRAME_HEADER_SIZE);
866 	p += HDMI_INFOFRAME_HEADER_SIZE;
867 	size -= HDMI_INFOFRAME_HEADER_SIZE;
868 
869 	p[0] = 0x03;
870 	p[1] = 0x0c;
871 	p[2] = 0x00;
872 
873 	if (frame->vic) {
874 		p[3] = __SHIFTIN(0x1, __BITS(6,5));
875 		p[4] = frame->vic;
876 	} else if (frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID) {
877 		p[3] = __SHIFTIN(0x2, __BITS(6,5));
878 		p[4] = __SHIFTIN(frame->s3d_struct, __BITS(7,4));
879 		if (frame->s3d_struct >= HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF)
880 			p[5] = __SHIFTIN(frame->s3d_ext_data, __BITS(7,4));
881 	} else {
882 		p[3] = __SHIFTIN(0x0, __BITS(6,5));
883 	}
884 
885 	hdmi_infoframe_set_checksum(buf, length);
886 
887 	return length;
888 }
889 
890 static inline int
891 hdmi_vendor_infoframe_unpack(struct hdmi_vendor_infoframe *frame,
892     const void *buf, size_t size)
893 {
894 	const uint8_t *p = buf;
895 	int ret;
896 
897 	memset(frame, 0, sizeof(*frame));
898 
899 	ret = hdmi_infoframe_header_unpack(&frame->header, p, size);
900 	if (ret)
901 		return ret;
902 	if (frame->header.length < 4)
903 		return -EINVAL;
904 	p += HDMI_INFOFRAME_HEADER_SIZE;
905 	size -= HDMI_INFOFRAME_HEADER_SIZE;
906 
907 	if (p[0] != 0x03 || p[1] != 0x0c || p[2] != 0x00)
908 		return -EINVAL;
909 
910 	switch (__SHIFTOUT(p[3], __BITS(6,5))) {
911 	case 0x0:
912 		if (frame->header.length != 4)
913 			return -EINVAL;
914 		break;
915 	case 0x1:
916 		if (frame->header.length != 5)
917 			return -EINVAL;
918 		frame->vic = p[4];
919 		break;
920 	case 0x2:
921 		if (frame->header.length < 5)
922 			return -EINVAL;
923 		frame->s3d_struct = __SHIFTOUT(p[4], __BITS(7,4));
924 		if (frame->s3d_struct < HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF) {
925 			if (frame->header.length != 5)
926 				return -EINVAL;
927 		} else {
928 			if (frame->header.length != 6)
929 				return -EINVAL;
930 			frame->s3d_ext_data = __SHIFTOUT(p[5], __BITS(7,4));
931 		}
932 		break;
933 	default:
934 		return -EINVAL;
935 	}
936 
937 	return 0;
938 }
939 
940 union hdmi_infoframe {
941 	struct hdmi_infoframe_header	any;
942 	struct hdmi_avi_infoframe	avi;
943 	struct hdmi_drm_infoframe	drm;
944 	struct hdmi_spd_infoframe	spd;
945 	union hdmi_vendor_any_infoframe	vendor;
946 };
947 
948 #define	hdmi_infoframe_pack_only	hdmi_infoframe_pack /* XXX */
949 
950 static inline ssize_t
951 hdmi_infoframe_pack(const union hdmi_infoframe *frame, void *buf, size_t size)
952 {
953 
954 	switch (frame->any.type) {
955 	case HDMI_INFOFRAME_TYPE_AVI:
956 		return hdmi_avi_infoframe_pack(&frame->avi, buf, size);
957 	case HDMI_INFOFRAME_TYPE_DRM:
958 		return hdmi_drm_infoframe_pack(&frame->drm, buf, size);
959 	case HDMI_INFOFRAME_TYPE_SPD:
960 		return hdmi_spd_infoframe_pack(&frame->spd, buf, size);
961 	case HDMI_INFOFRAME_TYPE_VENDOR:
962 		return hdmi_vendor_infoframe_pack(&frame->vendor.hdmi, buf,
963 		    size);
964 	default:
965 		return -EINVAL;
966 	}
967 }
968 
969 static inline int
970 hdmi_infoframe_unpack(union hdmi_infoframe *frame, const void *buf,
971     size_t size)
972 {
973 	struct hdmi_infoframe_header header;
974 	int ret;
975 
976 	ret = hdmi_infoframe_header_unpack(&header, buf, size);
977 	if (ret)
978 		return ret;
979 	switch (header.type) {
980 	case HDMI_INFOFRAME_TYPE_AVI:
981 		return hdmi_avi_infoframe_unpack(&frame->avi, buf, size);
982 	case HDMI_INFOFRAME_TYPE_DRM:
983 		return hdmi_drm_infoframe_unpack(&frame->drm, buf, size);
984 	case HDMI_INFOFRAME_TYPE_SPD:
985 		return hdmi_spd_infoframe_unpack(&frame->spd, buf, size);
986 	case HDMI_INFOFRAME_TYPE_VENDOR:
987 		return hdmi_vendor_infoframe_unpack(&frame->vendor.hdmi, buf,
988 		    size);
989 	default:
990 		return -EINVAL;
991 	}
992 }
993 
994 static inline void
995 hdmi_infoframe_log(const char *level, struct device *device,
996     const union hdmi_infoframe *frame)
997 {
998 	/* XXX */
999 }
1000 
1001 #endif	/* _LINUX_HDMI_H_ */
1002