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