Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

video: Add generic HDMI infoframe helpers

Add generic helpers to pack HDMI infoframes into binary buffers.

Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de>
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>

+543
+3
drivers/video/Kconfig
··· 52 52 help 53 53 helper to get videomodes from the devicetree 54 54 55 + config HDMI 56 + bool 57 + 55 58 menuconfig FB 56 59 tristate "Support for frame buffer devices" 57 60 ---help---
+1
drivers/video/Makefile
··· 5 5 # Each configuration option enables a list of files. 6 6 7 7 obj-$(CONFIG_VGASTATE) += vgastate.o 8 + obj-$(CONFIG_HDMI) += hdmi.o 8 9 obj-y += fb_notify.o 9 10 obj-$(CONFIG_FB) += fb.o 10 11 fb-y := fbmem.o fbmon.o fbcmap.o fbsysfs.o \
+308
drivers/video/hdmi.c
··· 1 + /* 2 + * Copyright (C) 2012 Avionic Design GmbH 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 as 6 + * published by the Free Software Foundation. 7 + */ 8 + 9 + #include <linux/bitops.h> 10 + #include <linux/errno.h> 11 + #include <linux/export.h> 12 + #include <linux/hdmi.h> 13 + #include <linux/string.h> 14 + 15 + static void hdmi_infoframe_checksum(void *buffer, size_t size) 16 + { 17 + u8 *ptr = buffer; 18 + u8 csum = 0; 19 + size_t i; 20 + 21 + /* compute checksum */ 22 + for (i = 0; i < size; i++) 23 + csum += ptr[i]; 24 + 25 + ptr[3] = 256 - csum; 26 + } 27 + 28 + /** 29 + * hdmi_avi_infoframe_init() - initialize an HDMI AVI infoframe 30 + * @frame: HDMI AVI infoframe 31 + * 32 + * Returns 0 on success or a negative error code on failure. 33 + */ 34 + int hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame) 35 + { 36 + memset(frame, 0, sizeof(*frame)); 37 + 38 + frame->type = HDMI_INFOFRAME_TYPE_AVI; 39 + frame->version = 2; 40 + frame->length = 13; 41 + 42 + return 0; 43 + } 44 + EXPORT_SYMBOL(hdmi_avi_infoframe_init); 45 + 46 + /** 47 + * hdmi_avi_infoframe_pack() - write HDMI AVI infoframe to binary buffer 48 + * @frame: HDMI AVI infoframe 49 + * @buffer: destination buffer 50 + * @size: size of buffer 51 + * 52 + * Packs the information contained in the @frame structure into a binary 53 + * representation that can be written into the corresponding controller 54 + * registers. Also computes the checksum as required by section 5.3.5 of 55 + * the HDMI 1.4 specification. 56 + * 57 + * Returns the number of bytes packed into the binary buffer or a negative 58 + * error code on failure. 59 + */ 60 + ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer, 61 + size_t size) 62 + { 63 + u8 *ptr = buffer; 64 + size_t length; 65 + 66 + length = HDMI_INFOFRAME_HEADER_SIZE + frame->length; 67 + 68 + if (size < length) 69 + return -ENOSPC; 70 + 71 + memset(buffer, 0, length); 72 + 73 + ptr[0] = frame->type; 74 + ptr[1] = frame->version; 75 + ptr[2] = frame->length; 76 + ptr[3] = 0; /* checksum */ 77 + 78 + /* start infoframe payload */ 79 + ptr += HDMI_INFOFRAME_HEADER_SIZE; 80 + 81 + ptr[0] = ((frame->colorspace & 0x3) << 5) | (frame->scan_mode & 0x3); 82 + 83 + if (frame->active_info_valid) 84 + ptr[0] |= BIT(4); 85 + 86 + if (frame->horizontal_bar_valid) 87 + ptr[0] |= BIT(3); 88 + 89 + if (frame->vertical_bar_valid) 90 + ptr[0] |= BIT(2); 91 + 92 + ptr[1] = ((frame->colorimetry & 0x3) << 6) | 93 + ((frame->picture_aspect & 0x3) << 4) | 94 + (frame->active_aspect & 0xf); 95 + 96 + ptr[2] = ((frame->extended_colorimetry & 0x7) << 4) | 97 + ((frame->quantization_range & 0x3) << 2) | 98 + (frame->nups & 0x3); 99 + 100 + if (frame->itc) 101 + ptr[2] |= BIT(7); 102 + 103 + ptr[3] = frame->video_code & 0x7f; 104 + 105 + ptr[4] = ((frame->ycc_quantization_range & 0x3) << 6) | 106 + ((frame->content_type & 0x3) << 4) | 107 + (frame->pixel_repeat & 0xf); 108 + 109 + ptr[5] = frame->top_bar & 0xff; 110 + ptr[6] = (frame->top_bar >> 8) & 0xff; 111 + ptr[7] = frame->bottom_bar & 0xff; 112 + ptr[8] = (frame->bottom_bar >> 8) & 0xff; 113 + ptr[9] = frame->left_bar & 0xff; 114 + ptr[10] = (frame->left_bar >> 8) & 0xff; 115 + ptr[11] = frame->right_bar & 0xff; 116 + ptr[12] = (frame->right_bar >> 8) & 0xff; 117 + 118 + hdmi_infoframe_checksum(buffer, length); 119 + 120 + return length; 121 + } 122 + EXPORT_SYMBOL(hdmi_avi_infoframe_pack); 123 + 124 + /** 125 + * hdmi_spd_infoframe_init() - initialize an HDMI SPD infoframe 126 + * @frame: HDMI SPD infoframe 127 + * @vendor: vendor string 128 + * @product: product string 129 + * 130 + * Returns 0 on success or a negative error code on failure. 131 + */ 132 + int hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame, 133 + const char *vendor, const char *product) 134 + { 135 + memset(frame, 0, sizeof(*frame)); 136 + 137 + frame->type = HDMI_INFOFRAME_TYPE_SPD; 138 + frame->version = 1; 139 + frame->length = 25; 140 + 141 + strncpy(frame->vendor, vendor, sizeof(frame->vendor)); 142 + strncpy(frame->product, product, sizeof(frame->product)); 143 + 144 + return 0; 145 + } 146 + EXPORT_SYMBOL(hdmi_spd_infoframe_init); 147 + 148 + /** 149 + * hdmi_spd_infoframe_pack() - write HDMI SPD infoframe to binary buffer 150 + * @frame: HDMI SPD infoframe 151 + * @buffer: destination buffer 152 + * @size: size of buffer 153 + * 154 + * Packs the information contained in the @frame structure into a binary 155 + * representation that can be written into the corresponding controller 156 + * registers. Also computes the checksum as required by section 5.3.5 of 157 + * the HDMI 1.4 specification. 158 + * 159 + * Returns the number of bytes packed into the binary buffer or a negative 160 + * error code on failure. 161 + */ 162 + ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer, 163 + size_t size) 164 + { 165 + u8 *ptr = buffer; 166 + size_t length; 167 + 168 + length = HDMI_INFOFRAME_HEADER_SIZE + frame->length; 169 + 170 + if (size < length) 171 + return -ENOSPC; 172 + 173 + memset(buffer, 0, length); 174 + 175 + ptr[0] = frame->type; 176 + ptr[1] = frame->version; 177 + ptr[2] = frame->length; 178 + ptr[3] = 0; /* checksum */ 179 + 180 + /* start infoframe payload */ 181 + ptr += HDMI_INFOFRAME_HEADER_SIZE; 182 + 183 + memcpy(ptr, frame->vendor, sizeof(frame->vendor)); 184 + memcpy(ptr + 8, frame->product, sizeof(frame->product)); 185 + 186 + ptr[24] = frame->sdi; 187 + 188 + hdmi_infoframe_checksum(buffer, length); 189 + 190 + return length; 191 + } 192 + EXPORT_SYMBOL(hdmi_spd_infoframe_pack); 193 + 194 + /** 195 + * hdmi_audio_infoframe_init() - initialize an HDMI audio infoframe 196 + * @frame: HDMI audio infoframe 197 + * 198 + * Returns 0 on success or a negative error code on failure. 199 + */ 200 + int hdmi_audio_infoframe_init(struct hdmi_audio_infoframe *frame) 201 + { 202 + memset(frame, 0, sizeof(*frame)); 203 + 204 + frame->type = HDMI_INFOFRAME_TYPE_AUDIO; 205 + frame->version = 1; 206 + frame->length = 10; 207 + 208 + return 0; 209 + } 210 + EXPORT_SYMBOL(hdmi_audio_infoframe_init); 211 + 212 + /** 213 + * hdmi_audio_infoframe_pack() - write HDMI audio infoframe to binary buffer 214 + * @frame: HDMI audio infoframe 215 + * @buffer: destination buffer 216 + * @size: size of buffer 217 + * 218 + * Packs the information contained in the @frame structure into a binary 219 + * representation that can be written into the corresponding controller 220 + * registers. Also computes the checksum as required by section 5.3.5 of 221 + * the HDMI 1.4 specification. 222 + * 223 + * Returns the number of bytes packed into the binary buffer or a negative 224 + * error code on failure. 225 + */ 226 + ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame, 227 + void *buffer, size_t size) 228 + { 229 + unsigned char channels; 230 + u8 *ptr = buffer; 231 + size_t length; 232 + 233 + length = HDMI_INFOFRAME_HEADER_SIZE + frame->length; 234 + 235 + if (size < length) 236 + return -ENOSPC; 237 + 238 + memset(buffer, 0, length); 239 + 240 + if (frame->channels >= 2) 241 + channels = frame->channels - 1; 242 + else 243 + channels = 0; 244 + 245 + ptr[0] = frame->type; 246 + ptr[1] = frame->version; 247 + ptr[2] = frame->length; 248 + ptr[3] = 0; /* checksum */ 249 + 250 + /* start infoframe payload */ 251 + ptr += HDMI_INFOFRAME_HEADER_SIZE; 252 + 253 + ptr[0] = ((frame->coding_type & 0xf) << 4) | (channels & 0x7); 254 + ptr[1] = ((frame->sample_frequency & 0x7) << 2) | 255 + (frame->sample_size & 0x3); 256 + ptr[2] = frame->coding_type_ext & 0x1f; 257 + ptr[3] = frame->channel_allocation; 258 + ptr[4] = (frame->level_shift_value & 0xf) << 3; 259 + 260 + if (frame->downmix_inhibit) 261 + ptr[4] |= BIT(7); 262 + 263 + hdmi_infoframe_checksum(buffer, length); 264 + 265 + return length; 266 + } 267 + EXPORT_SYMBOL(hdmi_audio_infoframe_pack); 268 + 269 + /** 270 + * hdmi_vendor_infoframe_pack() - write a HDMI vendor infoframe to binary 271 + * buffer 272 + * @frame: HDMI vendor infoframe 273 + * @buffer: destination buffer 274 + * @size: size of buffer 275 + * 276 + * Packs the information contained in the @frame structure into a binary 277 + * representation that can be written into the corresponding controller 278 + * registers. Also computes the checksum as required by section 5.3.5 of 279 + * the HDMI 1.4 specification. 280 + * 281 + * Returns the number of bytes packed into the binary buffer or a negative 282 + * error code on failure. 283 + */ 284 + ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame, 285 + void *buffer, size_t size) 286 + { 287 + u8 *ptr = buffer; 288 + size_t length; 289 + 290 + length = HDMI_INFOFRAME_HEADER_SIZE + frame->length; 291 + 292 + if (size < length) 293 + return -ENOSPC; 294 + 295 + memset(buffer, 0, length); 296 + 297 + ptr[0] = frame->type; 298 + ptr[1] = frame->version; 299 + ptr[2] = frame->length; 300 + ptr[3] = 0; /* checksum */ 301 + 302 + memcpy(&ptr[HDMI_INFOFRAME_HEADER_SIZE], frame->data, frame->length); 303 + 304 + hdmi_infoframe_checksum(buffer, length); 305 + 306 + return length; 307 + } 308 + EXPORT_SYMBOL(hdmi_vendor_infoframe_pack);
+231
include/linux/hdmi.h
··· 1 + /* 2 + * Copyright (C) 2012 Avionic Design GmbH 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 as 6 + * published by the Free Software Foundation. 7 + */ 8 + 9 + #ifndef __LINUX_HDMI_H_ 10 + #define __LINUX_HDMI_H_ 11 + 12 + #include <linux/types.h> 13 + 14 + enum hdmi_infoframe_type { 15 + HDMI_INFOFRAME_TYPE_VENDOR = 0x81, 16 + HDMI_INFOFRAME_TYPE_AVI = 0x82, 17 + HDMI_INFOFRAME_TYPE_SPD = 0x83, 18 + HDMI_INFOFRAME_TYPE_AUDIO = 0x84, 19 + }; 20 + 21 + #define HDMI_INFOFRAME_HEADER_SIZE 4 22 + #define HDMI_AVI_INFOFRAME_SIZE 13 23 + #define HDMI_SPD_INFOFRAME_SIZE 25 24 + #define HDMI_AUDIO_INFOFRAME_SIZE 10 25 + 26 + enum hdmi_colorspace { 27 + HDMI_COLORSPACE_RGB, 28 + HDMI_COLORSPACE_YUV422, 29 + HDMI_COLORSPACE_YUV444, 30 + }; 31 + 32 + enum hdmi_scan_mode { 33 + HDMI_SCAN_MODE_NONE, 34 + HDMI_SCAN_MODE_OVERSCAN, 35 + HDMI_SCAN_MODE_UNDERSCAN, 36 + }; 37 + 38 + enum hdmi_colorimetry { 39 + HDMI_COLORIMETRY_NONE, 40 + HDMI_COLORIMETRY_ITU_601, 41 + HDMI_COLORIMETRY_ITU_709, 42 + HDMI_COLORIMETRY_EXTENDED, 43 + }; 44 + 45 + enum hdmi_picture_aspect { 46 + HDMI_PICTURE_ASPECT_NONE, 47 + HDMI_PICTURE_ASPECT_4_3, 48 + HDMI_PICTURE_ASPECT_16_9, 49 + }; 50 + 51 + enum hdmi_active_aspect { 52 + HDMI_ACTIVE_ASPECT_16_9_TOP = 2, 53 + HDMI_ACTIVE_ASPECT_14_9_TOP = 3, 54 + HDMI_ACTIVE_ASPECT_16_9_CENTER = 4, 55 + HDMI_ACTIVE_ASPECT_PICTURE = 8, 56 + HDMI_ACTIVE_ASPECT_4_3 = 9, 57 + HDMI_ACTIVE_ASPECT_16_9 = 10, 58 + HDMI_ACTIVE_ASPECT_14_9 = 11, 59 + HDMI_ACTIVE_ASPECT_4_3_SP_14_9 = 13, 60 + HDMI_ACTIVE_ASPECT_16_9_SP_14_9 = 14, 61 + HDMI_ACTIVE_ASPECT_16_9_SP_4_3 = 15, 62 + }; 63 + 64 + enum hdmi_extended_colorimetry { 65 + HDMI_EXTENDED_COLORIMETRY_XV_YCC_601, 66 + HDMI_EXTENDED_COLORIMETRY_XV_YCC_709, 67 + HDMI_EXTENDED_COLORIMETRY_S_YCC_601, 68 + HDMI_EXTENDED_COLORIMETRY_ADOBE_YCC_601, 69 + HDMI_EXTENDED_COLORIMETRY_ADOBE_RGB, 70 + }; 71 + 72 + enum hdmi_quantization_range { 73 + HDMI_QUANTIZATION_RANGE_DEFAULT, 74 + HDMI_QUANTIZATION_RANGE_LIMITED, 75 + HDMI_QUANTIZATION_RANGE_FULL, 76 + }; 77 + 78 + /* non-uniform picture scaling */ 79 + enum hdmi_nups { 80 + HDMI_NUPS_UNKNOWN, 81 + HDMI_NUPS_HORIZONTAL, 82 + HDMI_NUPS_VERTICAL, 83 + HDMI_NUPS_BOTH, 84 + }; 85 + 86 + enum hdmi_ycc_quantization_range { 87 + HDMI_YCC_QUANTIZATION_RANGE_LIMITED, 88 + HDMI_YCC_QUANTIZATION_RANGE_FULL, 89 + }; 90 + 91 + enum hdmi_content_type { 92 + HDMI_CONTENT_TYPE_NONE, 93 + HDMI_CONTENT_TYPE_PHOTO, 94 + HDMI_CONTENT_TYPE_CINEMA, 95 + HDMI_CONTENT_TYPE_GAME, 96 + }; 97 + 98 + struct hdmi_avi_infoframe { 99 + enum hdmi_infoframe_type type; 100 + unsigned char version; 101 + unsigned char length; 102 + enum hdmi_colorspace colorspace; 103 + bool active_info_valid; 104 + bool horizontal_bar_valid; 105 + bool vertical_bar_valid; 106 + enum hdmi_scan_mode scan_mode; 107 + enum hdmi_colorimetry colorimetry; 108 + enum hdmi_picture_aspect picture_aspect; 109 + enum hdmi_active_aspect active_aspect; 110 + bool itc; 111 + enum hdmi_extended_colorimetry extended_colorimetry; 112 + enum hdmi_quantization_range quantization_range; 113 + enum hdmi_nups nups; 114 + unsigned char video_code; 115 + enum hdmi_ycc_quantization_range ycc_quantization_range; 116 + enum hdmi_content_type content_type; 117 + unsigned char pixel_repeat; 118 + unsigned short top_bar; 119 + unsigned short bottom_bar; 120 + unsigned short left_bar; 121 + unsigned short right_bar; 122 + }; 123 + 124 + int hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame); 125 + ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer, 126 + size_t size); 127 + 128 + enum hdmi_spd_sdi { 129 + HDMI_SPD_SDI_UNKNOWN, 130 + HDMI_SPD_SDI_DSTB, 131 + HDMI_SPD_SDI_DVDP, 132 + HDMI_SPD_SDI_DVHS, 133 + HDMI_SPD_SDI_HDDVR, 134 + HDMI_SPD_SDI_DVC, 135 + HDMI_SPD_SDI_DSC, 136 + HDMI_SPD_SDI_VCD, 137 + HDMI_SPD_SDI_GAME, 138 + HDMI_SPD_SDI_PC, 139 + HDMI_SPD_SDI_BD, 140 + HDMI_SPD_SDI_SACD, 141 + HDMI_SPD_SDI_HDDVD, 142 + HDMI_SPD_SDI_PMP, 143 + }; 144 + 145 + struct hdmi_spd_infoframe { 146 + enum hdmi_infoframe_type type; 147 + unsigned char version; 148 + unsigned char length; 149 + char vendor[8]; 150 + char product[16]; 151 + enum hdmi_spd_sdi sdi; 152 + }; 153 + 154 + int hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame, 155 + const char *vendor, const char *product); 156 + ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer, 157 + size_t size); 158 + 159 + enum hdmi_audio_coding_type { 160 + HDMI_AUDIO_CODING_TYPE_STREAM, 161 + HDMI_AUDIO_CODING_TYPE_PCM, 162 + HDMI_AUDIO_CODING_TYPE_AC3, 163 + HDMI_AUDIO_CODING_TYPE_MPEG1, 164 + HDMI_AUDIO_CODING_TYPE_MP3, 165 + HDMI_AUDIO_CODING_TYPE_MPEG2, 166 + HDMI_AUDIO_CODING_TYPE_AAC_LC, 167 + HDMI_AUDIO_CODING_TYPE_DTS, 168 + HDMI_AUDIO_CODING_TYPE_ATRAC, 169 + HDMI_AUDIO_CODING_TYPE_DSD, 170 + HDMI_AUDIO_CODING_TYPE_EAC3, 171 + HDMI_AUDIO_CODING_TYPE_DTS_HD, 172 + HDMI_AUDIO_CODING_TYPE_MLP, 173 + HDMI_AUDIO_CODING_TYPE_DST, 174 + HDMI_AUDIO_CODING_TYPE_WMA_PRO, 175 + }; 176 + 177 + enum hdmi_audio_sample_size { 178 + HDMI_AUDIO_SAMPLE_SIZE_STREAM, 179 + HDMI_AUDIO_SAMPLE_SIZE_16, 180 + HDMI_AUDIO_SAMPLE_SIZE_20, 181 + HDMI_AUDIO_SAMPLE_SIZE_24, 182 + }; 183 + 184 + enum hdmi_audio_sample_frequency { 185 + HDMI_AUDIO_SAMPLE_FREQUENCY_STREAM, 186 + HDMI_AUDIO_SAMPLE_FREQUENCY_32000, 187 + HDMI_AUDIO_SAMPLE_FREQUENCY_44100, 188 + HDMI_AUDIO_SAMPLE_FREQUENCY_48000, 189 + HDMI_AUDIO_SAMPLE_FREQUENCY_88200, 190 + HDMI_AUDIO_SAMPLE_FREQUENCY_96000, 191 + HDMI_AUDIO_SAMPLE_FREQUENCY_176400, 192 + HDMI_AUDIO_SAMPLE_FREQUENCY_192000, 193 + }; 194 + 195 + enum hdmi_audio_coding_type_ext { 196 + HDMI_AUDIO_CODING_TYPE_EXT_STREAM, 197 + HDMI_AUDIO_CODING_TYPE_EXT_HE_AAC, 198 + HDMI_AUDIO_CODING_TYPE_EXT_HE_AAC_V2, 199 + HDMI_AUDIO_CODING_TYPE_EXT_MPEG_SURROUND, 200 + }; 201 + 202 + struct hdmi_audio_infoframe { 203 + enum hdmi_infoframe_type type; 204 + unsigned char version; 205 + unsigned char length; 206 + unsigned char channels; 207 + enum hdmi_audio_coding_type coding_type; 208 + enum hdmi_audio_sample_size sample_size; 209 + enum hdmi_audio_sample_frequency sample_frequency; 210 + enum hdmi_audio_coding_type_ext coding_type_ext; 211 + unsigned char channel_allocation; 212 + unsigned char level_shift_value; 213 + bool downmix_inhibit; 214 + 215 + }; 216 + 217 + int hdmi_audio_infoframe_init(struct hdmi_audio_infoframe *frame); 218 + ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame, 219 + void *buffer, size_t size); 220 + 221 + struct hdmi_vendor_infoframe { 222 + enum hdmi_infoframe_type type; 223 + unsigned char version; 224 + unsigned char length; 225 + u8 data[27]; 226 + }; 227 + 228 + ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame, 229 + void *buffer, size_t size); 230 + 231 + #endif /* _DRM_HDMI_H */