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