18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (C) 2012 Avionic Design GmbH 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 58c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 68c2ecf20Sopenharmony_ci * to deal in the Software without restriction, including without limitation 78c2ecf20Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sub license, 88c2ecf20Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 98c2ecf20Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice (including the 128c2ecf20Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions 138c2ecf20Sopenharmony_ci * of the Software. 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 168c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 178c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 188c2ecf20Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 198c2ecf20Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 208c2ecf20Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 218c2ecf20Sopenharmony_ci * DEALINGS IN THE SOFTWARE. 228c2ecf20Sopenharmony_ci */ 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#include <linux/bitops.h> 258c2ecf20Sopenharmony_ci#include <linux/bug.h> 268c2ecf20Sopenharmony_ci#include <linux/errno.h> 278c2ecf20Sopenharmony_ci#include <linux/export.h> 288c2ecf20Sopenharmony_ci#include <linux/hdmi.h> 298c2ecf20Sopenharmony_ci#include <linux/string.h> 308c2ecf20Sopenharmony_ci#include <linux/device.h> 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#define hdmi_log(fmt, ...) dev_printk(level, dev, fmt, ##__VA_ARGS__) 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistatic u8 hdmi_infoframe_checksum(const u8 *ptr, size_t size) 358c2ecf20Sopenharmony_ci{ 368c2ecf20Sopenharmony_ci u8 csum = 0; 378c2ecf20Sopenharmony_ci size_t i; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci /* compute checksum */ 408c2ecf20Sopenharmony_ci for (i = 0; i < size; i++) 418c2ecf20Sopenharmony_ci csum += ptr[i]; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci return 256 - csum; 448c2ecf20Sopenharmony_ci} 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistatic void hdmi_infoframe_set_checksum(void *buffer, size_t size) 478c2ecf20Sopenharmony_ci{ 488c2ecf20Sopenharmony_ci u8 *ptr = buffer; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci ptr[3] = hdmi_infoframe_checksum(buffer, size); 518c2ecf20Sopenharmony_ci} 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci/** 548c2ecf20Sopenharmony_ci * hdmi_avi_infoframe_init() - initialize an HDMI AVI infoframe 558c2ecf20Sopenharmony_ci * @frame: HDMI AVI infoframe 568c2ecf20Sopenharmony_ci */ 578c2ecf20Sopenharmony_civoid hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci memset(frame, 0, sizeof(*frame)); 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci frame->type = HDMI_INFOFRAME_TYPE_AVI; 628c2ecf20Sopenharmony_ci frame->version = 2; 638c2ecf20Sopenharmony_ci frame->length = HDMI_AVI_INFOFRAME_SIZE; 648c2ecf20Sopenharmony_ci} 658c2ecf20Sopenharmony_ciEXPORT_SYMBOL(hdmi_avi_infoframe_init); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_cistatic int hdmi_avi_infoframe_check_only(const struct hdmi_avi_infoframe *frame) 688c2ecf20Sopenharmony_ci{ 698c2ecf20Sopenharmony_ci if (frame->type != HDMI_INFOFRAME_TYPE_AVI || 708c2ecf20Sopenharmony_ci frame->version != 2 || 718c2ecf20Sopenharmony_ci frame->length != HDMI_AVI_INFOFRAME_SIZE) 728c2ecf20Sopenharmony_ci return -EINVAL; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci if (frame->picture_aspect > HDMI_PICTURE_ASPECT_16_9) 758c2ecf20Sopenharmony_ci return -EINVAL; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci return 0; 788c2ecf20Sopenharmony_ci} 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci/** 818c2ecf20Sopenharmony_ci * hdmi_avi_infoframe_check() - check a HDMI AVI infoframe 828c2ecf20Sopenharmony_ci * @frame: HDMI AVI infoframe 838c2ecf20Sopenharmony_ci * 848c2ecf20Sopenharmony_ci * Validates that the infoframe is consistent and updates derived fields 858c2ecf20Sopenharmony_ci * (eg. length) based on other fields. 868c2ecf20Sopenharmony_ci * 878c2ecf20Sopenharmony_ci * Returns 0 on success or a negative error code on failure. 888c2ecf20Sopenharmony_ci */ 898c2ecf20Sopenharmony_ciint hdmi_avi_infoframe_check(struct hdmi_avi_infoframe *frame) 908c2ecf20Sopenharmony_ci{ 918c2ecf20Sopenharmony_ci return hdmi_avi_infoframe_check_only(frame); 928c2ecf20Sopenharmony_ci} 938c2ecf20Sopenharmony_ciEXPORT_SYMBOL(hdmi_avi_infoframe_check); 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci/** 968c2ecf20Sopenharmony_ci * hdmi_avi_infoframe_pack_only() - write HDMI AVI infoframe to binary buffer 978c2ecf20Sopenharmony_ci * @frame: HDMI AVI infoframe 988c2ecf20Sopenharmony_ci * @buffer: destination buffer 998c2ecf20Sopenharmony_ci * @size: size of buffer 1008c2ecf20Sopenharmony_ci * 1018c2ecf20Sopenharmony_ci * Packs the information contained in the @frame structure into a binary 1028c2ecf20Sopenharmony_ci * representation that can be written into the corresponding controller 1038c2ecf20Sopenharmony_ci * registers. Also computes the checksum as required by section 5.3.5 of 1048c2ecf20Sopenharmony_ci * the HDMI 1.4 specification. 1058c2ecf20Sopenharmony_ci * 1068c2ecf20Sopenharmony_ci * Returns the number of bytes packed into the binary buffer or a negative 1078c2ecf20Sopenharmony_ci * error code on failure. 1088c2ecf20Sopenharmony_ci */ 1098c2ecf20Sopenharmony_cissize_t hdmi_avi_infoframe_pack_only(const struct hdmi_avi_infoframe *frame, 1108c2ecf20Sopenharmony_ci void *buffer, size_t size) 1118c2ecf20Sopenharmony_ci{ 1128c2ecf20Sopenharmony_ci u8 *ptr = buffer; 1138c2ecf20Sopenharmony_ci size_t length; 1148c2ecf20Sopenharmony_ci int ret; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci ret = hdmi_avi_infoframe_check_only(frame); 1178c2ecf20Sopenharmony_ci if (ret) 1188c2ecf20Sopenharmony_ci return ret; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci length = HDMI_INFOFRAME_HEADER_SIZE + frame->length; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci if (size < length) 1238c2ecf20Sopenharmony_ci return -ENOSPC; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci memset(buffer, 0, size); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci ptr[0] = frame->type; 1288c2ecf20Sopenharmony_ci ptr[1] = frame->version; 1298c2ecf20Sopenharmony_ci ptr[2] = frame->length; 1308c2ecf20Sopenharmony_ci ptr[3] = 0; /* checksum */ 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci /* start infoframe payload */ 1338c2ecf20Sopenharmony_ci ptr += HDMI_INFOFRAME_HEADER_SIZE; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci ptr[0] = ((frame->colorspace & 0x3) << 5) | (frame->scan_mode & 0x3); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci /* 1388c2ecf20Sopenharmony_ci * Data byte 1, bit 4 has to be set if we provide the active format 1398c2ecf20Sopenharmony_ci * aspect ratio 1408c2ecf20Sopenharmony_ci */ 1418c2ecf20Sopenharmony_ci if (frame->active_aspect & 0xf) 1428c2ecf20Sopenharmony_ci ptr[0] |= BIT(4); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci /* Bit 3 and 2 indicate if we transmit horizontal/vertical bar data */ 1458c2ecf20Sopenharmony_ci if (frame->top_bar || frame->bottom_bar) 1468c2ecf20Sopenharmony_ci ptr[0] |= BIT(3); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci if (frame->left_bar || frame->right_bar) 1498c2ecf20Sopenharmony_ci ptr[0] |= BIT(2); 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci ptr[1] = ((frame->colorimetry & 0x3) << 6) | 1528c2ecf20Sopenharmony_ci ((frame->picture_aspect & 0x3) << 4) | 1538c2ecf20Sopenharmony_ci (frame->active_aspect & 0xf); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci ptr[2] = ((frame->extended_colorimetry & 0x7) << 4) | 1568c2ecf20Sopenharmony_ci ((frame->quantization_range & 0x3) << 2) | 1578c2ecf20Sopenharmony_ci (frame->nups & 0x3); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci if (frame->itc) 1608c2ecf20Sopenharmony_ci ptr[2] |= BIT(7); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci ptr[3] = frame->video_code & 0x7f; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci ptr[4] = ((frame->ycc_quantization_range & 0x3) << 6) | 1658c2ecf20Sopenharmony_ci ((frame->content_type & 0x3) << 4) | 1668c2ecf20Sopenharmony_ci (frame->pixel_repeat & 0xf); 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci ptr[5] = frame->top_bar & 0xff; 1698c2ecf20Sopenharmony_ci ptr[6] = (frame->top_bar >> 8) & 0xff; 1708c2ecf20Sopenharmony_ci ptr[7] = frame->bottom_bar & 0xff; 1718c2ecf20Sopenharmony_ci ptr[8] = (frame->bottom_bar >> 8) & 0xff; 1728c2ecf20Sopenharmony_ci ptr[9] = frame->left_bar & 0xff; 1738c2ecf20Sopenharmony_ci ptr[10] = (frame->left_bar >> 8) & 0xff; 1748c2ecf20Sopenharmony_ci ptr[11] = frame->right_bar & 0xff; 1758c2ecf20Sopenharmony_ci ptr[12] = (frame->right_bar >> 8) & 0xff; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci hdmi_infoframe_set_checksum(buffer, length); 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci return length; 1808c2ecf20Sopenharmony_ci} 1818c2ecf20Sopenharmony_ciEXPORT_SYMBOL(hdmi_avi_infoframe_pack_only); 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci/** 1848c2ecf20Sopenharmony_ci * hdmi_avi_infoframe_pack() - check a HDMI AVI infoframe, 1858c2ecf20Sopenharmony_ci * and write it to binary buffer 1868c2ecf20Sopenharmony_ci * @frame: HDMI AVI infoframe 1878c2ecf20Sopenharmony_ci * @buffer: destination buffer 1888c2ecf20Sopenharmony_ci * @size: size of buffer 1898c2ecf20Sopenharmony_ci * 1908c2ecf20Sopenharmony_ci * Validates that the infoframe is consistent and updates derived fields 1918c2ecf20Sopenharmony_ci * (eg. length) based on other fields, after which it packs the information 1928c2ecf20Sopenharmony_ci * contained in the @frame structure into a binary representation that 1938c2ecf20Sopenharmony_ci * can be written into the corresponding controller registers. This function 1948c2ecf20Sopenharmony_ci * also computes the checksum as required by section 5.3.5 of the HDMI 1.4 1958c2ecf20Sopenharmony_ci * specification. 1968c2ecf20Sopenharmony_ci * 1978c2ecf20Sopenharmony_ci * Returns the number of bytes packed into the binary buffer or a negative 1988c2ecf20Sopenharmony_ci * error code on failure. 1998c2ecf20Sopenharmony_ci */ 2008c2ecf20Sopenharmony_cissize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, 2018c2ecf20Sopenharmony_ci void *buffer, size_t size) 2028c2ecf20Sopenharmony_ci{ 2038c2ecf20Sopenharmony_ci int ret; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci ret = hdmi_avi_infoframe_check(frame); 2068c2ecf20Sopenharmony_ci if (ret) 2078c2ecf20Sopenharmony_ci return ret; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci return hdmi_avi_infoframe_pack_only(frame, buffer, size); 2108c2ecf20Sopenharmony_ci} 2118c2ecf20Sopenharmony_ciEXPORT_SYMBOL(hdmi_avi_infoframe_pack); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci/** 2148c2ecf20Sopenharmony_ci * hdmi_spd_infoframe_init() - initialize an HDMI SPD infoframe 2158c2ecf20Sopenharmony_ci * @frame: HDMI SPD infoframe 2168c2ecf20Sopenharmony_ci * @vendor: vendor string 2178c2ecf20Sopenharmony_ci * @product: product string 2188c2ecf20Sopenharmony_ci * 2198c2ecf20Sopenharmony_ci * Returns 0 on success or a negative error code on failure. 2208c2ecf20Sopenharmony_ci */ 2218c2ecf20Sopenharmony_ciint hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame, 2228c2ecf20Sopenharmony_ci const char *vendor, const char *product) 2238c2ecf20Sopenharmony_ci{ 2248c2ecf20Sopenharmony_ci memset(frame, 0, sizeof(*frame)); 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci frame->type = HDMI_INFOFRAME_TYPE_SPD; 2278c2ecf20Sopenharmony_ci frame->version = 1; 2288c2ecf20Sopenharmony_ci frame->length = HDMI_SPD_INFOFRAME_SIZE; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci strncpy(frame->vendor, vendor, sizeof(frame->vendor)); 2318c2ecf20Sopenharmony_ci strncpy(frame->product, product, sizeof(frame->product)); 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci return 0; 2348c2ecf20Sopenharmony_ci} 2358c2ecf20Sopenharmony_ciEXPORT_SYMBOL(hdmi_spd_infoframe_init); 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_cistatic int hdmi_spd_infoframe_check_only(const struct hdmi_spd_infoframe *frame) 2388c2ecf20Sopenharmony_ci{ 2398c2ecf20Sopenharmony_ci if (frame->type != HDMI_INFOFRAME_TYPE_SPD || 2408c2ecf20Sopenharmony_ci frame->version != 1 || 2418c2ecf20Sopenharmony_ci frame->length != HDMI_SPD_INFOFRAME_SIZE) 2428c2ecf20Sopenharmony_ci return -EINVAL; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci return 0; 2458c2ecf20Sopenharmony_ci} 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci/** 2488c2ecf20Sopenharmony_ci * hdmi_spd_infoframe_check() - check a HDMI SPD infoframe 2498c2ecf20Sopenharmony_ci * @frame: HDMI SPD infoframe 2508c2ecf20Sopenharmony_ci * 2518c2ecf20Sopenharmony_ci * Validates that the infoframe is consistent and updates derived fields 2528c2ecf20Sopenharmony_ci * (eg. length) based on other fields. 2538c2ecf20Sopenharmony_ci * 2548c2ecf20Sopenharmony_ci * Returns 0 on success or a negative error code on failure. 2558c2ecf20Sopenharmony_ci */ 2568c2ecf20Sopenharmony_ciint hdmi_spd_infoframe_check(struct hdmi_spd_infoframe *frame) 2578c2ecf20Sopenharmony_ci{ 2588c2ecf20Sopenharmony_ci return hdmi_spd_infoframe_check_only(frame); 2598c2ecf20Sopenharmony_ci} 2608c2ecf20Sopenharmony_ciEXPORT_SYMBOL(hdmi_spd_infoframe_check); 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci/** 2638c2ecf20Sopenharmony_ci * hdmi_spd_infoframe_pack_only() - write HDMI SPD infoframe to binary buffer 2648c2ecf20Sopenharmony_ci * @frame: HDMI SPD infoframe 2658c2ecf20Sopenharmony_ci * @buffer: destination buffer 2668c2ecf20Sopenharmony_ci * @size: size of buffer 2678c2ecf20Sopenharmony_ci * 2688c2ecf20Sopenharmony_ci * Packs the information contained in the @frame structure into a binary 2698c2ecf20Sopenharmony_ci * representation that can be written into the corresponding controller 2708c2ecf20Sopenharmony_ci * registers. Also computes the checksum as required by section 5.3.5 of 2718c2ecf20Sopenharmony_ci * the HDMI 1.4 specification. 2728c2ecf20Sopenharmony_ci * 2738c2ecf20Sopenharmony_ci * Returns the number of bytes packed into the binary buffer or a negative 2748c2ecf20Sopenharmony_ci * error code on failure. 2758c2ecf20Sopenharmony_ci */ 2768c2ecf20Sopenharmony_cissize_t hdmi_spd_infoframe_pack_only(const struct hdmi_spd_infoframe *frame, 2778c2ecf20Sopenharmony_ci void *buffer, size_t size) 2788c2ecf20Sopenharmony_ci{ 2798c2ecf20Sopenharmony_ci u8 *ptr = buffer; 2808c2ecf20Sopenharmony_ci size_t length; 2818c2ecf20Sopenharmony_ci int ret; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci ret = hdmi_spd_infoframe_check_only(frame); 2848c2ecf20Sopenharmony_ci if (ret) 2858c2ecf20Sopenharmony_ci return ret; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci length = HDMI_INFOFRAME_HEADER_SIZE + frame->length; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci if (size < length) 2908c2ecf20Sopenharmony_ci return -ENOSPC; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci memset(buffer, 0, size); 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci ptr[0] = frame->type; 2958c2ecf20Sopenharmony_ci ptr[1] = frame->version; 2968c2ecf20Sopenharmony_ci ptr[2] = frame->length; 2978c2ecf20Sopenharmony_ci ptr[3] = 0; /* checksum */ 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci /* start infoframe payload */ 3008c2ecf20Sopenharmony_ci ptr += HDMI_INFOFRAME_HEADER_SIZE; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci memcpy(ptr, frame->vendor, sizeof(frame->vendor)); 3038c2ecf20Sopenharmony_ci memcpy(ptr + 8, frame->product, sizeof(frame->product)); 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci ptr[24] = frame->sdi; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci hdmi_infoframe_set_checksum(buffer, length); 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci return length; 3108c2ecf20Sopenharmony_ci} 3118c2ecf20Sopenharmony_ciEXPORT_SYMBOL(hdmi_spd_infoframe_pack_only); 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci/** 3148c2ecf20Sopenharmony_ci * hdmi_spd_infoframe_pack() - check a HDMI SPD infoframe, 3158c2ecf20Sopenharmony_ci * and write it to binary buffer 3168c2ecf20Sopenharmony_ci * @frame: HDMI SPD infoframe 3178c2ecf20Sopenharmony_ci * @buffer: destination buffer 3188c2ecf20Sopenharmony_ci * @size: size of buffer 3198c2ecf20Sopenharmony_ci * 3208c2ecf20Sopenharmony_ci * Validates that the infoframe is consistent and updates derived fields 3218c2ecf20Sopenharmony_ci * (eg. length) based on other fields, after which it packs the information 3228c2ecf20Sopenharmony_ci * contained in the @frame structure into a binary representation that 3238c2ecf20Sopenharmony_ci * can be written into the corresponding controller registers. This function 3248c2ecf20Sopenharmony_ci * also computes the checksum as required by section 5.3.5 of the HDMI 1.4 3258c2ecf20Sopenharmony_ci * specification. 3268c2ecf20Sopenharmony_ci * 3278c2ecf20Sopenharmony_ci * Returns the number of bytes packed into the binary buffer or a negative 3288c2ecf20Sopenharmony_ci * error code on failure. 3298c2ecf20Sopenharmony_ci */ 3308c2ecf20Sopenharmony_cissize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, 3318c2ecf20Sopenharmony_ci void *buffer, size_t size) 3328c2ecf20Sopenharmony_ci{ 3338c2ecf20Sopenharmony_ci int ret; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci ret = hdmi_spd_infoframe_check(frame); 3368c2ecf20Sopenharmony_ci if (ret) 3378c2ecf20Sopenharmony_ci return ret; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci return hdmi_spd_infoframe_pack_only(frame, buffer, size); 3408c2ecf20Sopenharmony_ci} 3418c2ecf20Sopenharmony_ciEXPORT_SYMBOL(hdmi_spd_infoframe_pack); 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci/** 3448c2ecf20Sopenharmony_ci * hdmi_audio_infoframe_init() - initialize an HDMI audio infoframe 3458c2ecf20Sopenharmony_ci * @frame: HDMI audio infoframe 3468c2ecf20Sopenharmony_ci * 3478c2ecf20Sopenharmony_ci * Returns 0 on success or a negative error code on failure. 3488c2ecf20Sopenharmony_ci */ 3498c2ecf20Sopenharmony_ciint hdmi_audio_infoframe_init(struct hdmi_audio_infoframe *frame) 3508c2ecf20Sopenharmony_ci{ 3518c2ecf20Sopenharmony_ci memset(frame, 0, sizeof(*frame)); 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci frame->type = HDMI_INFOFRAME_TYPE_AUDIO; 3548c2ecf20Sopenharmony_ci frame->version = 1; 3558c2ecf20Sopenharmony_ci frame->length = HDMI_AUDIO_INFOFRAME_SIZE; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci return 0; 3588c2ecf20Sopenharmony_ci} 3598c2ecf20Sopenharmony_ciEXPORT_SYMBOL(hdmi_audio_infoframe_init); 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_cistatic int hdmi_audio_infoframe_check_only(const struct hdmi_audio_infoframe *frame) 3628c2ecf20Sopenharmony_ci{ 3638c2ecf20Sopenharmony_ci if (frame->type != HDMI_INFOFRAME_TYPE_AUDIO || 3648c2ecf20Sopenharmony_ci frame->version != 1 || 3658c2ecf20Sopenharmony_ci frame->length != HDMI_AUDIO_INFOFRAME_SIZE) 3668c2ecf20Sopenharmony_ci return -EINVAL; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci return 0; 3698c2ecf20Sopenharmony_ci} 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci/** 3728c2ecf20Sopenharmony_ci * hdmi_audio_infoframe_check() - check a HDMI audio infoframe 3738c2ecf20Sopenharmony_ci * @frame: HDMI audio infoframe 3748c2ecf20Sopenharmony_ci * 3758c2ecf20Sopenharmony_ci * Validates that the infoframe is consistent and updates derived fields 3768c2ecf20Sopenharmony_ci * (eg. length) based on other fields. 3778c2ecf20Sopenharmony_ci * 3788c2ecf20Sopenharmony_ci * Returns 0 on success or a negative error code on failure. 3798c2ecf20Sopenharmony_ci */ 3808c2ecf20Sopenharmony_ciint hdmi_audio_infoframe_check(struct hdmi_audio_infoframe *frame) 3818c2ecf20Sopenharmony_ci{ 3828c2ecf20Sopenharmony_ci return hdmi_audio_infoframe_check_only(frame); 3838c2ecf20Sopenharmony_ci} 3848c2ecf20Sopenharmony_ciEXPORT_SYMBOL(hdmi_audio_infoframe_check); 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci/** 3878c2ecf20Sopenharmony_ci * hdmi_audio_infoframe_pack_only() - write HDMI audio infoframe to binary buffer 3888c2ecf20Sopenharmony_ci * @frame: HDMI audio infoframe 3898c2ecf20Sopenharmony_ci * @buffer: destination buffer 3908c2ecf20Sopenharmony_ci * @size: size of buffer 3918c2ecf20Sopenharmony_ci * 3928c2ecf20Sopenharmony_ci * Packs the information contained in the @frame structure into a binary 3938c2ecf20Sopenharmony_ci * representation that can be written into the corresponding controller 3948c2ecf20Sopenharmony_ci * registers. Also computes the checksum as required by section 5.3.5 of 3958c2ecf20Sopenharmony_ci * the HDMI 1.4 specification. 3968c2ecf20Sopenharmony_ci * 3978c2ecf20Sopenharmony_ci * Returns the number of bytes packed into the binary buffer or a negative 3988c2ecf20Sopenharmony_ci * error code on failure. 3998c2ecf20Sopenharmony_ci */ 4008c2ecf20Sopenharmony_cissize_t hdmi_audio_infoframe_pack_only(const struct hdmi_audio_infoframe *frame, 4018c2ecf20Sopenharmony_ci void *buffer, size_t size) 4028c2ecf20Sopenharmony_ci{ 4038c2ecf20Sopenharmony_ci unsigned char channels; 4048c2ecf20Sopenharmony_ci u8 *ptr = buffer; 4058c2ecf20Sopenharmony_ci size_t length; 4068c2ecf20Sopenharmony_ci int ret; 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci ret = hdmi_audio_infoframe_check_only(frame); 4098c2ecf20Sopenharmony_ci if (ret) 4108c2ecf20Sopenharmony_ci return ret; 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci length = HDMI_INFOFRAME_HEADER_SIZE + frame->length; 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci if (size < length) 4158c2ecf20Sopenharmony_ci return -ENOSPC; 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci memset(buffer, 0, size); 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci if (frame->channels >= 2) 4208c2ecf20Sopenharmony_ci channels = frame->channels - 1; 4218c2ecf20Sopenharmony_ci else 4228c2ecf20Sopenharmony_ci channels = 0; 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci ptr[0] = frame->type; 4258c2ecf20Sopenharmony_ci ptr[1] = frame->version; 4268c2ecf20Sopenharmony_ci ptr[2] = frame->length; 4278c2ecf20Sopenharmony_ci ptr[3] = 0; /* checksum */ 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci /* start infoframe payload */ 4308c2ecf20Sopenharmony_ci ptr += HDMI_INFOFRAME_HEADER_SIZE; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci ptr[0] = ((frame->coding_type & 0xf) << 4) | (channels & 0x7); 4338c2ecf20Sopenharmony_ci ptr[1] = ((frame->sample_frequency & 0x7) << 2) | 4348c2ecf20Sopenharmony_ci (frame->sample_size & 0x3); 4358c2ecf20Sopenharmony_ci ptr[2] = frame->coding_type_ext & 0x1f; 4368c2ecf20Sopenharmony_ci ptr[3] = frame->channel_allocation; 4378c2ecf20Sopenharmony_ci ptr[4] = (frame->level_shift_value & 0xf) << 3; 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci if (frame->downmix_inhibit) 4408c2ecf20Sopenharmony_ci ptr[4] |= BIT(7); 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci hdmi_infoframe_set_checksum(buffer, length); 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci return length; 4458c2ecf20Sopenharmony_ci} 4468c2ecf20Sopenharmony_ciEXPORT_SYMBOL(hdmi_audio_infoframe_pack_only); 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci/** 4498c2ecf20Sopenharmony_ci * hdmi_audio_infoframe_pack() - check a HDMI Audio infoframe, 4508c2ecf20Sopenharmony_ci * and write it to binary buffer 4518c2ecf20Sopenharmony_ci * @frame: HDMI Audio infoframe 4528c2ecf20Sopenharmony_ci * @buffer: destination buffer 4538c2ecf20Sopenharmony_ci * @size: size of buffer 4548c2ecf20Sopenharmony_ci * 4558c2ecf20Sopenharmony_ci * Validates that the infoframe is consistent and updates derived fields 4568c2ecf20Sopenharmony_ci * (eg. length) based on other fields, after which it packs the information 4578c2ecf20Sopenharmony_ci * contained in the @frame structure into a binary representation that 4588c2ecf20Sopenharmony_ci * can be written into the corresponding controller registers. This function 4598c2ecf20Sopenharmony_ci * also computes the checksum as required by section 5.3.5 of the HDMI 1.4 4608c2ecf20Sopenharmony_ci * specification. 4618c2ecf20Sopenharmony_ci * 4628c2ecf20Sopenharmony_ci * Returns the number of bytes packed into the binary buffer or a negative 4638c2ecf20Sopenharmony_ci * error code on failure. 4648c2ecf20Sopenharmony_ci */ 4658c2ecf20Sopenharmony_cissize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame, 4668c2ecf20Sopenharmony_ci void *buffer, size_t size) 4678c2ecf20Sopenharmony_ci{ 4688c2ecf20Sopenharmony_ci int ret; 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci ret = hdmi_audio_infoframe_check(frame); 4718c2ecf20Sopenharmony_ci if (ret) 4728c2ecf20Sopenharmony_ci return ret; 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci return hdmi_audio_infoframe_pack_only(frame, buffer, size); 4758c2ecf20Sopenharmony_ci} 4768c2ecf20Sopenharmony_ciEXPORT_SYMBOL(hdmi_audio_infoframe_pack); 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci/** 4798c2ecf20Sopenharmony_ci * hdmi_vendor_infoframe_init() - initialize an HDMI vendor infoframe 4808c2ecf20Sopenharmony_ci * @frame: HDMI vendor infoframe 4818c2ecf20Sopenharmony_ci * 4828c2ecf20Sopenharmony_ci * Returns 0 on success or a negative error code on failure. 4838c2ecf20Sopenharmony_ci */ 4848c2ecf20Sopenharmony_ciint hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame) 4858c2ecf20Sopenharmony_ci{ 4868c2ecf20Sopenharmony_ci memset(frame, 0, sizeof(*frame)); 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci frame->type = HDMI_INFOFRAME_TYPE_VENDOR; 4898c2ecf20Sopenharmony_ci frame->version = 1; 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci frame->oui = HDMI_IEEE_OUI; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci /* 4948c2ecf20Sopenharmony_ci * 0 is a valid value for s3d_struct, so we use a special "not set" 4958c2ecf20Sopenharmony_ci * value 4968c2ecf20Sopenharmony_ci */ 4978c2ecf20Sopenharmony_ci frame->s3d_struct = HDMI_3D_STRUCTURE_INVALID; 4988c2ecf20Sopenharmony_ci frame->length = HDMI_VENDOR_INFOFRAME_SIZE; 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci return 0; 5018c2ecf20Sopenharmony_ci} 5028c2ecf20Sopenharmony_ciEXPORT_SYMBOL(hdmi_vendor_infoframe_init); 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_cistatic int hdmi_vendor_infoframe_length(const struct hdmi_vendor_infoframe *frame) 5058c2ecf20Sopenharmony_ci{ 5068c2ecf20Sopenharmony_ci /* for side by side (half) we also need to provide 3D_Ext_Data */ 5078c2ecf20Sopenharmony_ci if (frame->s3d_struct >= HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF) 5088c2ecf20Sopenharmony_ci return 6; 5098c2ecf20Sopenharmony_ci else if (frame->vic != 0 || frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID) 5108c2ecf20Sopenharmony_ci return 5; 5118c2ecf20Sopenharmony_ci else 5128c2ecf20Sopenharmony_ci return 4; 5138c2ecf20Sopenharmony_ci} 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_cistatic int hdmi_vendor_infoframe_check_only(const struct hdmi_vendor_infoframe *frame) 5168c2ecf20Sopenharmony_ci{ 5178c2ecf20Sopenharmony_ci if (frame->type != HDMI_INFOFRAME_TYPE_VENDOR || 5188c2ecf20Sopenharmony_ci frame->version != 1 || 5198c2ecf20Sopenharmony_ci frame->oui != HDMI_IEEE_OUI) 5208c2ecf20Sopenharmony_ci return -EINVAL; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci /* only one of those can be supplied */ 5238c2ecf20Sopenharmony_ci if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID) 5248c2ecf20Sopenharmony_ci return -EINVAL; 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci if (frame->length != hdmi_vendor_infoframe_length(frame)) 5278c2ecf20Sopenharmony_ci return -EINVAL; 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci return 0; 5308c2ecf20Sopenharmony_ci} 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci/** 5338c2ecf20Sopenharmony_ci * hdmi_vendor_infoframe_check() - check a HDMI vendor infoframe 5348c2ecf20Sopenharmony_ci * @frame: HDMI infoframe 5358c2ecf20Sopenharmony_ci * 5368c2ecf20Sopenharmony_ci * Validates that the infoframe is consistent and updates derived fields 5378c2ecf20Sopenharmony_ci * (eg. length) based on other fields. 5388c2ecf20Sopenharmony_ci * 5398c2ecf20Sopenharmony_ci * Returns 0 on success or a negative error code on failure. 5408c2ecf20Sopenharmony_ci */ 5418c2ecf20Sopenharmony_ciint hdmi_vendor_infoframe_check(struct hdmi_vendor_infoframe *frame) 5428c2ecf20Sopenharmony_ci{ 5438c2ecf20Sopenharmony_ci frame->length = hdmi_vendor_infoframe_length(frame); 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci return hdmi_vendor_infoframe_check_only(frame); 5468c2ecf20Sopenharmony_ci} 5478c2ecf20Sopenharmony_ciEXPORT_SYMBOL(hdmi_vendor_infoframe_check); 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci/** 5508c2ecf20Sopenharmony_ci * hdmi_vendor_infoframe_pack_only() - write a HDMI vendor infoframe to binary buffer 5518c2ecf20Sopenharmony_ci * @frame: HDMI infoframe 5528c2ecf20Sopenharmony_ci * @buffer: destination buffer 5538c2ecf20Sopenharmony_ci * @size: size of buffer 5548c2ecf20Sopenharmony_ci * 5558c2ecf20Sopenharmony_ci * Packs the information contained in the @frame structure into a binary 5568c2ecf20Sopenharmony_ci * representation that can be written into the corresponding controller 5578c2ecf20Sopenharmony_ci * registers. Also computes the checksum as required by section 5.3.5 of 5588c2ecf20Sopenharmony_ci * the HDMI 1.4 specification. 5598c2ecf20Sopenharmony_ci * 5608c2ecf20Sopenharmony_ci * Returns the number of bytes packed into the binary buffer or a negative 5618c2ecf20Sopenharmony_ci * error code on failure. 5628c2ecf20Sopenharmony_ci */ 5638c2ecf20Sopenharmony_cissize_t hdmi_vendor_infoframe_pack_only(const struct hdmi_vendor_infoframe *frame, 5648c2ecf20Sopenharmony_ci void *buffer, size_t size) 5658c2ecf20Sopenharmony_ci{ 5668c2ecf20Sopenharmony_ci u8 *ptr = buffer; 5678c2ecf20Sopenharmony_ci size_t length; 5688c2ecf20Sopenharmony_ci int ret; 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci ret = hdmi_vendor_infoframe_check_only(frame); 5718c2ecf20Sopenharmony_ci if (ret) 5728c2ecf20Sopenharmony_ci return ret; 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci length = HDMI_INFOFRAME_HEADER_SIZE + frame->length; 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci if (size < length) 5778c2ecf20Sopenharmony_ci return -ENOSPC; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci memset(buffer, 0, size); 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci ptr[0] = frame->type; 5828c2ecf20Sopenharmony_ci ptr[1] = frame->version; 5838c2ecf20Sopenharmony_ci ptr[2] = frame->length; 5848c2ecf20Sopenharmony_ci ptr[3] = 0; /* checksum */ 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci /* HDMI OUI */ 5878c2ecf20Sopenharmony_ci ptr[4] = 0x03; 5888c2ecf20Sopenharmony_ci ptr[5] = 0x0c; 5898c2ecf20Sopenharmony_ci ptr[6] = 0x00; 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci if (frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID) { 5928c2ecf20Sopenharmony_ci ptr[7] = 0x2 << 5; /* video format */ 5938c2ecf20Sopenharmony_ci ptr[8] = (frame->s3d_struct & 0xf) << 4; 5948c2ecf20Sopenharmony_ci if (frame->s3d_struct >= HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF) 5958c2ecf20Sopenharmony_ci ptr[9] = (frame->s3d_ext_data & 0xf) << 4; 5968c2ecf20Sopenharmony_ci } else if (frame->vic) { 5978c2ecf20Sopenharmony_ci ptr[7] = 0x1 << 5; /* video format */ 5988c2ecf20Sopenharmony_ci ptr[8] = frame->vic; 5998c2ecf20Sopenharmony_ci } else { 6008c2ecf20Sopenharmony_ci ptr[7] = 0x0 << 5; /* video format */ 6018c2ecf20Sopenharmony_ci } 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci hdmi_infoframe_set_checksum(buffer, length); 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci return length; 6068c2ecf20Sopenharmony_ci} 6078c2ecf20Sopenharmony_ciEXPORT_SYMBOL(hdmi_vendor_infoframe_pack_only); 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci/** 6108c2ecf20Sopenharmony_ci * hdmi_vendor_infoframe_pack() - check a HDMI Vendor infoframe, 6118c2ecf20Sopenharmony_ci * and write it to binary buffer 6128c2ecf20Sopenharmony_ci * @frame: HDMI Vendor infoframe 6138c2ecf20Sopenharmony_ci * @buffer: destination buffer 6148c2ecf20Sopenharmony_ci * @size: size of buffer 6158c2ecf20Sopenharmony_ci * 6168c2ecf20Sopenharmony_ci * Validates that the infoframe is consistent and updates derived fields 6178c2ecf20Sopenharmony_ci * (eg. length) based on other fields, after which it packs the information 6188c2ecf20Sopenharmony_ci * contained in the @frame structure into a binary representation that 6198c2ecf20Sopenharmony_ci * can be written into the corresponding controller registers. This function 6208c2ecf20Sopenharmony_ci * also computes the checksum as required by section 5.3.5 of the HDMI 1.4 6218c2ecf20Sopenharmony_ci * specification. 6228c2ecf20Sopenharmony_ci * 6238c2ecf20Sopenharmony_ci * Returns the number of bytes packed into the binary buffer or a negative 6248c2ecf20Sopenharmony_ci * error code on failure. 6258c2ecf20Sopenharmony_ci */ 6268c2ecf20Sopenharmony_cissize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame, 6278c2ecf20Sopenharmony_ci void *buffer, size_t size) 6288c2ecf20Sopenharmony_ci{ 6298c2ecf20Sopenharmony_ci int ret; 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci ret = hdmi_vendor_infoframe_check(frame); 6328c2ecf20Sopenharmony_ci if (ret) 6338c2ecf20Sopenharmony_ci return ret; 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci return hdmi_vendor_infoframe_pack_only(frame, buffer, size); 6368c2ecf20Sopenharmony_ci} 6378c2ecf20Sopenharmony_ciEXPORT_SYMBOL(hdmi_vendor_infoframe_pack); 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_cistatic int 6408c2ecf20Sopenharmony_cihdmi_vendor_any_infoframe_check_only(const union hdmi_vendor_any_infoframe *frame) 6418c2ecf20Sopenharmony_ci{ 6428c2ecf20Sopenharmony_ci if (frame->any.type != HDMI_INFOFRAME_TYPE_VENDOR || 6438c2ecf20Sopenharmony_ci frame->any.version != 1) 6448c2ecf20Sopenharmony_ci return -EINVAL; 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci return 0; 6478c2ecf20Sopenharmony_ci} 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci/** 6508c2ecf20Sopenharmony_ci * hdmi_drm_infoframe_init() - initialize an HDMI Dynaminc Range and 6518c2ecf20Sopenharmony_ci * mastering infoframe 6528c2ecf20Sopenharmony_ci * @frame: HDMI DRM infoframe 6538c2ecf20Sopenharmony_ci * 6548c2ecf20Sopenharmony_ci * Returns 0 on success or a negative error code on failure. 6558c2ecf20Sopenharmony_ci */ 6568c2ecf20Sopenharmony_ciint hdmi_drm_infoframe_init(struct hdmi_drm_infoframe *frame) 6578c2ecf20Sopenharmony_ci{ 6588c2ecf20Sopenharmony_ci memset(frame, 0, sizeof(*frame)); 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci frame->type = HDMI_INFOFRAME_TYPE_DRM; 6618c2ecf20Sopenharmony_ci frame->version = 1; 6628c2ecf20Sopenharmony_ci frame->length = HDMI_DRM_INFOFRAME_SIZE; 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci return 0; 6658c2ecf20Sopenharmony_ci} 6668c2ecf20Sopenharmony_ciEXPORT_SYMBOL(hdmi_drm_infoframe_init); 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_cistatic int hdmi_drm_infoframe_check_only(const struct hdmi_drm_infoframe *frame) 6698c2ecf20Sopenharmony_ci{ 6708c2ecf20Sopenharmony_ci if (frame->type != HDMI_INFOFRAME_TYPE_DRM || 6718c2ecf20Sopenharmony_ci frame->version != 1) 6728c2ecf20Sopenharmony_ci return -EINVAL; 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci if (frame->length != HDMI_DRM_INFOFRAME_SIZE) 6758c2ecf20Sopenharmony_ci return -EINVAL; 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci return 0; 6788c2ecf20Sopenharmony_ci} 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci/** 6818c2ecf20Sopenharmony_ci * hdmi_drm_infoframe_check() - check a HDMI DRM infoframe 6828c2ecf20Sopenharmony_ci * @frame: HDMI DRM infoframe 6838c2ecf20Sopenharmony_ci * 6848c2ecf20Sopenharmony_ci * Validates that the infoframe is consistent. 6858c2ecf20Sopenharmony_ci * Returns 0 on success or a negative error code on failure. 6868c2ecf20Sopenharmony_ci */ 6878c2ecf20Sopenharmony_ciint hdmi_drm_infoframe_check(struct hdmi_drm_infoframe *frame) 6888c2ecf20Sopenharmony_ci{ 6898c2ecf20Sopenharmony_ci return hdmi_drm_infoframe_check_only(frame); 6908c2ecf20Sopenharmony_ci} 6918c2ecf20Sopenharmony_ciEXPORT_SYMBOL(hdmi_drm_infoframe_check); 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci/** 6948c2ecf20Sopenharmony_ci * hdmi_drm_infoframe_pack_only() - write HDMI DRM infoframe to binary buffer 6958c2ecf20Sopenharmony_ci * @frame: HDMI DRM infoframe 6968c2ecf20Sopenharmony_ci * @buffer: destination buffer 6978c2ecf20Sopenharmony_ci * @size: size of buffer 6988c2ecf20Sopenharmony_ci * 6998c2ecf20Sopenharmony_ci * Packs the information contained in the @frame structure into a binary 7008c2ecf20Sopenharmony_ci * representation that can be written into the corresponding controller 7018c2ecf20Sopenharmony_ci * registers. Also computes the checksum as required by section 5.3.5 of 7028c2ecf20Sopenharmony_ci * the HDMI 1.4 specification. 7038c2ecf20Sopenharmony_ci * 7048c2ecf20Sopenharmony_ci * Returns the number of bytes packed into the binary buffer or a negative 7058c2ecf20Sopenharmony_ci * error code on failure. 7068c2ecf20Sopenharmony_ci */ 7078c2ecf20Sopenharmony_cissize_t hdmi_drm_infoframe_pack_only(const struct hdmi_drm_infoframe *frame, 7088c2ecf20Sopenharmony_ci void *buffer, size_t size) 7098c2ecf20Sopenharmony_ci{ 7108c2ecf20Sopenharmony_ci u8 *ptr = buffer; 7118c2ecf20Sopenharmony_ci size_t length; 7128c2ecf20Sopenharmony_ci int i; 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci length = HDMI_INFOFRAME_HEADER_SIZE + frame->length; 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci if (size < length) 7178c2ecf20Sopenharmony_ci return -ENOSPC; 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci memset(buffer, 0, size); 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci ptr[0] = frame->type; 7228c2ecf20Sopenharmony_ci ptr[1] = frame->version; 7238c2ecf20Sopenharmony_ci ptr[2] = frame->length; 7248c2ecf20Sopenharmony_ci ptr[3] = 0; /* checksum */ 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci /* start infoframe payload */ 7278c2ecf20Sopenharmony_ci ptr += HDMI_INFOFRAME_HEADER_SIZE; 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci *ptr++ = frame->eotf; 7308c2ecf20Sopenharmony_ci *ptr++ = frame->metadata_type; 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci for (i = 0; i < 3; i++) { 7338c2ecf20Sopenharmony_ci *ptr++ = frame->display_primaries[i].x; 7348c2ecf20Sopenharmony_ci *ptr++ = frame->display_primaries[i].x >> 8; 7358c2ecf20Sopenharmony_ci *ptr++ = frame->display_primaries[i].y; 7368c2ecf20Sopenharmony_ci *ptr++ = frame->display_primaries[i].y >> 8; 7378c2ecf20Sopenharmony_ci } 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci *ptr++ = frame->white_point.x; 7408c2ecf20Sopenharmony_ci *ptr++ = frame->white_point.x >> 8; 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci *ptr++ = frame->white_point.y; 7438c2ecf20Sopenharmony_ci *ptr++ = frame->white_point.y >> 8; 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci *ptr++ = frame->max_display_mastering_luminance; 7468c2ecf20Sopenharmony_ci *ptr++ = frame->max_display_mastering_luminance >> 8; 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci *ptr++ = frame->min_display_mastering_luminance; 7498c2ecf20Sopenharmony_ci *ptr++ = frame->min_display_mastering_luminance >> 8; 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci *ptr++ = frame->max_cll; 7528c2ecf20Sopenharmony_ci *ptr++ = frame->max_cll >> 8; 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci *ptr++ = frame->max_fall; 7558c2ecf20Sopenharmony_ci *ptr++ = frame->max_fall >> 8; 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci hdmi_infoframe_set_checksum(buffer, length); 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci return length; 7608c2ecf20Sopenharmony_ci} 7618c2ecf20Sopenharmony_ciEXPORT_SYMBOL(hdmi_drm_infoframe_pack_only); 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci/** 7648c2ecf20Sopenharmony_ci * hdmi_drm_infoframe_pack() - check a HDMI DRM infoframe, 7658c2ecf20Sopenharmony_ci * and write it to binary buffer 7668c2ecf20Sopenharmony_ci * @frame: HDMI DRM infoframe 7678c2ecf20Sopenharmony_ci * @buffer: destination buffer 7688c2ecf20Sopenharmony_ci * @size: size of buffer 7698c2ecf20Sopenharmony_ci * 7708c2ecf20Sopenharmony_ci * Validates that the infoframe is consistent and updates derived fields 7718c2ecf20Sopenharmony_ci * (eg. length) based on other fields, after which it packs the information 7728c2ecf20Sopenharmony_ci * contained in the @frame structure into a binary representation that 7738c2ecf20Sopenharmony_ci * can be written into the corresponding controller registers. This function 7748c2ecf20Sopenharmony_ci * also computes the checksum as required by section 5.3.5 of the HDMI 1.4 7758c2ecf20Sopenharmony_ci * specification. 7768c2ecf20Sopenharmony_ci * 7778c2ecf20Sopenharmony_ci * Returns the number of bytes packed into the binary buffer or a negative 7788c2ecf20Sopenharmony_ci * error code on failure. 7798c2ecf20Sopenharmony_ci */ 7808c2ecf20Sopenharmony_cissize_t hdmi_drm_infoframe_pack(struct hdmi_drm_infoframe *frame, 7818c2ecf20Sopenharmony_ci void *buffer, size_t size) 7828c2ecf20Sopenharmony_ci{ 7838c2ecf20Sopenharmony_ci int ret; 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci ret = hdmi_drm_infoframe_check(frame); 7868c2ecf20Sopenharmony_ci if (ret) 7878c2ecf20Sopenharmony_ci return ret; 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci return hdmi_drm_infoframe_pack_only(frame, buffer, size); 7908c2ecf20Sopenharmony_ci} 7918c2ecf20Sopenharmony_ciEXPORT_SYMBOL(hdmi_drm_infoframe_pack); 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci/* 7948c2ecf20Sopenharmony_ci * hdmi_vendor_any_infoframe_check() - check a vendor infoframe 7958c2ecf20Sopenharmony_ci */ 7968c2ecf20Sopenharmony_cistatic int 7978c2ecf20Sopenharmony_cihdmi_vendor_any_infoframe_check(union hdmi_vendor_any_infoframe *frame) 7988c2ecf20Sopenharmony_ci{ 7998c2ecf20Sopenharmony_ci int ret; 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci ret = hdmi_vendor_any_infoframe_check_only(frame); 8028c2ecf20Sopenharmony_ci if (ret) 8038c2ecf20Sopenharmony_ci return ret; 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci /* we only know about HDMI vendor infoframes */ 8068c2ecf20Sopenharmony_ci if (frame->any.oui != HDMI_IEEE_OUI) 8078c2ecf20Sopenharmony_ci return -EINVAL; 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci return hdmi_vendor_infoframe_check(&frame->hdmi); 8108c2ecf20Sopenharmony_ci} 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci/* 8138c2ecf20Sopenharmony_ci * hdmi_vendor_any_infoframe_pack_only() - write a vendor infoframe to binary buffer 8148c2ecf20Sopenharmony_ci */ 8158c2ecf20Sopenharmony_cistatic ssize_t 8168c2ecf20Sopenharmony_cihdmi_vendor_any_infoframe_pack_only(const union hdmi_vendor_any_infoframe *frame, 8178c2ecf20Sopenharmony_ci void *buffer, size_t size) 8188c2ecf20Sopenharmony_ci{ 8198c2ecf20Sopenharmony_ci int ret; 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci ret = hdmi_vendor_any_infoframe_check_only(frame); 8228c2ecf20Sopenharmony_ci if (ret) 8238c2ecf20Sopenharmony_ci return ret; 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci /* we only know about HDMI vendor infoframes */ 8268c2ecf20Sopenharmony_ci if (frame->any.oui != HDMI_IEEE_OUI) 8278c2ecf20Sopenharmony_ci return -EINVAL; 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci return hdmi_vendor_infoframe_pack_only(&frame->hdmi, buffer, size); 8308c2ecf20Sopenharmony_ci} 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci/* 8338c2ecf20Sopenharmony_ci * hdmi_vendor_any_infoframe_pack() - check a vendor infoframe, 8348c2ecf20Sopenharmony_ci * and write it to binary buffer 8358c2ecf20Sopenharmony_ci */ 8368c2ecf20Sopenharmony_cistatic ssize_t 8378c2ecf20Sopenharmony_cihdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame, 8388c2ecf20Sopenharmony_ci void *buffer, size_t size) 8398c2ecf20Sopenharmony_ci{ 8408c2ecf20Sopenharmony_ci int ret; 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci ret = hdmi_vendor_any_infoframe_check(frame); 8438c2ecf20Sopenharmony_ci if (ret) 8448c2ecf20Sopenharmony_ci return ret; 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci return hdmi_vendor_any_infoframe_pack_only(frame, buffer, size); 8478c2ecf20Sopenharmony_ci} 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci/** 8508c2ecf20Sopenharmony_ci * hdmi_infoframe_check() - check a HDMI infoframe 8518c2ecf20Sopenharmony_ci * @frame: HDMI infoframe 8528c2ecf20Sopenharmony_ci * 8538c2ecf20Sopenharmony_ci * Validates that the infoframe is consistent and updates derived fields 8548c2ecf20Sopenharmony_ci * (eg. length) based on other fields. 8558c2ecf20Sopenharmony_ci * 8568c2ecf20Sopenharmony_ci * Returns 0 on success or a negative error code on failure. 8578c2ecf20Sopenharmony_ci */ 8588c2ecf20Sopenharmony_ciint 8598c2ecf20Sopenharmony_cihdmi_infoframe_check(union hdmi_infoframe *frame) 8608c2ecf20Sopenharmony_ci{ 8618c2ecf20Sopenharmony_ci switch (frame->any.type) { 8628c2ecf20Sopenharmony_ci case HDMI_INFOFRAME_TYPE_AVI: 8638c2ecf20Sopenharmony_ci return hdmi_avi_infoframe_check(&frame->avi); 8648c2ecf20Sopenharmony_ci case HDMI_INFOFRAME_TYPE_SPD: 8658c2ecf20Sopenharmony_ci return hdmi_spd_infoframe_check(&frame->spd); 8668c2ecf20Sopenharmony_ci case HDMI_INFOFRAME_TYPE_AUDIO: 8678c2ecf20Sopenharmony_ci return hdmi_audio_infoframe_check(&frame->audio); 8688c2ecf20Sopenharmony_ci case HDMI_INFOFRAME_TYPE_VENDOR: 8698c2ecf20Sopenharmony_ci return hdmi_vendor_any_infoframe_check(&frame->vendor); 8708c2ecf20Sopenharmony_ci default: 8718c2ecf20Sopenharmony_ci WARN(1, "Bad infoframe type %d\n", frame->any.type); 8728c2ecf20Sopenharmony_ci return -EINVAL; 8738c2ecf20Sopenharmony_ci } 8748c2ecf20Sopenharmony_ci} 8758c2ecf20Sopenharmony_ciEXPORT_SYMBOL(hdmi_infoframe_check); 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci/** 8788c2ecf20Sopenharmony_ci * hdmi_infoframe_pack_only() - write a HDMI infoframe to binary buffer 8798c2ecf20Sopenharmony_ci * @frame: HDMI infoframe 8808c2ecf20Sopenharmony_ci * @buffer: destination buffer 8818c2ecf20Sopenharmony_ci * @size: size of buffer 8828c2ecf20Sopenharmony_ci * 8838c2ecf20Sopenharmony_ci * Packs the information contained in the @frame structure into a binary 8848c2ecf20Sopenharmony_ci * representation that can be written into the corresponding controller 8858c2ecf20Sopenharmony_ci * registers. Also computes the checksum as required by section 5.3.5 of 8868c2ecf20Sopenharmony_ci * the HDMI 1.4 specification. 8878c2ecf20Sopenharmony_ci * 8888c2ecf20Sopenharmony_ci * Returns the number of bytes packed into the binary buffer or a negative 8898c2ecf20Sopenharmony_ci * error code on failure. 8908c2ecf20Sopenharmony_ci */ 8918c2ecf20Sopenharmony_cissize_t 8928c2ecf20Sopenharmony_cihdmi_infoframe_pack_only(const union hdmi_infoframe *frame, void *buffer, size_t size) 8938c2ecf20Sopenharmony_ci{ 8948c2ecf20Sopenharmony_ci ssize_t length; 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci switch (frame->any.type) { 8978c2ecf20Sopenharmony_ci case HDMI_INFOFRAME_TYPE_AVI: 8988c2ecf20Sopenharmony_ci length = hdmi_avi_infoframe_pack_only(&frame->avi, 8998c2ecf20Sopenharmony_ci buffer, size); 9008c2ecf20Sopenharmony_ci break; 9018c2ecf20Sopenharmony_ci case HDMI_INFOFRAME_TYPE_DRM: 9028c2ecf20Sopenharmony_ci length = hdmi_drm_infoframe_pack_only(&frame->drm, 9038c2ecf20Sopenharmony_ci buffer, size); 9048c2ecf20Sopenharmony_ci break; 9058c2ecf20Sopenharmony_ci case HDMI_INFOFRAME_TYPE_SPD: 9068c2ecf20Sopenharmony_ci length = hdmi_spd_infoframe_pack_only(&frame->spd, 9078c2ecf20Sopenharmony_ci buffer, size); 9088c2ecf20Sopenharmony_ci break; 9098c2ecf20Sopenharmony_ci case HDMI_INFOFRAME_TYPE_AUDIO: 9108c2ecf20Sopenharmony_ci length = hdmi_audio_infoframe_pack_only(&frame->audio, 9118c2ecf20Sopenharmony_ci buffer, size); 9128c2ecf20Sopenharmony_ci break; 9138c2ecf20Sopenharmony_ci case HDMI_INFOFRAME_TYPE_VENDOR: 9148c2ecf20Sopenharmony_ci length = hdmi_vendor_any_infoframe_pack_only(&frame->vendor, 9158c2ecf20Sopenharmony_ci buffer, size); 9168c2ecf20Sopenharmony_ci break; 9178c2ecf20Sopenharmony_ci default: 9188c2ecf20Sopenharmony_ci WARN(1, "Bad infoframe type %d\n", frame->any.type); 9198c2ecf20Sopenharmony_ci length = -EINVAL; 9208c2ecf20Sopenharmony_ci } 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci return length; 9238c2ecf20Sopenharmony_ci} 9248c2ecf20Sopenharmony_ciEXPORT_SYMBOL(hdmi_infoframe_pack_only); 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci/** 9278c2ecf20Sopenharmony_ci * hdmi_infoframe_pack() - check a HDMI infoframe, 9288c2ecf20Sopenharmony_ci * and write it to binary buffer 9298c2ecf20Sopenharmony_ci * @frame: HDMI infoframe 9308c2ecf20Sopenharmony_ci * @buffer: destination buffer 9318c2ecf20Sopenharmony_ci * @size: size of buffer 9328c2ecf20Sopenharmony_ci * 9338c2ecf20Sopenharmony_ci * Validates that the infoframe is consistent and updates derived fields 9348c2ecf20Sopenharmony_ci * (eg. length) based on other fields, after which it packs the information 9358c2ecf20Sopenharmony_ci * contained in the @frame structure into a binary representation that 9368c2ecf20Sopenharmony_ci * can be written into the corresponding controller registers. This function 9378c2ecf20Sopenharmony_ci * also computes the checksum as required by section 5.3.5 of the HDMI 1.4 9388c2ecf20Sopenharmony_ci * specification. 9398c2ecf20Sopenharmony_ci * 9408c2ecf20Sopenharmony_ci * Returns the number of bytes packed into the binary buffer or a negative 9418c2ecf20Sopenharmony_ci * error code on failure. 9428c2ecf20Sopenharmony_ci */ 9438c2ecf20Sopenharmony_cissize_t 9448c2ecf20Sopenharmony_cihdmi_infoframe_pack(union hdmi_infoframe *frame, 9458c2ecf20Sopenharmony_ci void *buffer, size_t size) 9468c2ecf20Sopenharmony_ci{ 9478c2ecf20Sopenharmony_ci ssize_t length; 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci switch (frame->any.type) { 9508c2ecf20Sopenharmony_ci case HDMI_INFOFRAME_TYPE_AVI: 9518c2ecf20Sopenharmony_ci length = hdmi_avi_infoframe_pack(&frame->avi, buffer, size); 9528c2ecf20Sopenharmony_ci break; 9538c2ecf20Sopenharmony_ci case HDMI_INFOFRAME_TYPE_DRM: 9548c2ecf20Sopenharmony_ci length = hdmi_drm_infoframe_pack(&frame->drm, buffer, size); 9558c2ecf20Sopenharmony_ci break; 9568c2ecf20Sopenharmony_ci case HDMI_INFOFRAME_TYPE_SPD: 9578c2ecf20Sopenharmony_ci length = hdmi_spd_infoframe_pack(&frame->spd, buffer, size); 9588c2ecf20Sopenharmony_ci break; 9598c2ecf20Sopenharmony_ci case HDMI_INFOFRAME_TYPE_AUDIO: 9608c2ecf20Sopenharmony_ci length = hdmi_audio_infoframe_pack(&frame->audio, buffer, size); 9618c2ecf20Sopenharmony_ci break; 9628c2ecf20Sopenharmony_ci case HDMI_INFOFRAME_TYPE_VENDOR: 9638c2ecf20Sopenharmony_ci length = hdmi_vendor_any_infoframe_pack(&frame->vendor, 9648c2ecf20Sopenharmony_ci buffer, size); 9658c2ecf20Sopenharmony_ci break; 9668c2ecf20Sopenharmony_ci default: 9678c2ecf20Sopenharmony_ci WARN(1, "Bad infoframe type %d\n", frame->any.type); 9688c2ecf20Sopenharmony_ci length = -EINVAL; 9698c2ecf20Sopenharmony_ci } 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ci return length; 9728c2ecf20Sopenharmony_ci} 9738c2ecf20Sopenharmony_ciEXPORT_SYMBOL(hdmi_infoframe_pack); 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_cistatic const char *hdmi_infoframe_type_get_name(enum hdmi_infoframe_type type) 9768c2ecf20Sopenharmony_ci{ 9778c2ecf20Sopenharmony_ci if (type < 0x80 || type > 0x9f) 9788c2ecf20Sopenharmony_ci return "Invalid"; 9798c2ecf20Sopenharmony_ci switch (type) { 9808c2ecf20Sopenharmony_ci case HDMI_INFOFRAME_TYPE_VENDOR: 9818c2ecf20Sopenharmony_ci return "Vendor"; 9828c2ecf20Sopenharmony_ci case HDMI_INFOFRAME_TYPE_AVI: 9838c2ecf20Sopenharmony_ci return "Auxiliary Video Information (AVI)"; 9848c2ecf20Sopenharmony_ci case HDMI_INFOFRAME_TYPE_SPD: 9858c2ecf20Sopenharmony_ci return "Source Product Description (SPD)"; 9868c2ecf20Sopenharmony_ci case HDMI_INFOFRAME_TYPE_AUDIO: 9878c2ecf20Sopenharmony_ci return "Audio"; 9888c2ecf20Sopenharmony_ci case HDMI_INFOFRAME_TYPE_DRM: 9898c2ecf20Sopenharmony_ci return "Dynamic Range and Mastering"; 9908c2ecf20Sopenharmony_ci } 9918c2ecf20Sopenharmony_ci return "Reserved"; 9928c2ecf20Sopenharmony_ci} 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_cistatic void hdmi_infoframe_log_header(const char *level, 9958c2ecf20Sopenharmony_ci struct device *dev, 9968c2ecf20Sopenharmony_ci const struct hdmi_any_infoframe *frame) 9978c2ecf20Sopenharmony_ci{ 9988c2ecf20Sopenharmony_ci hdmi_log("HDMI infoframe: %s, version %u, length %u\n", 9998c2ecf20Sopenharmony_ci hdmi_infoframe_type_get_name(frame->type), 10008c2ecf20Sopenharmony_ci frame->version, frame->length); 10018c2ecf20Sopenharmony_ci} 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_cistatic const char *hdmi_colorspace_get_name(enum hdmi_colorspace colorspace) 10048c2ecf20Sopenharmony_ci{ 10058c2ecf20Sopenharmony_ci switch (colorspace) { 10068c2ecf20Sopenharmony_ci case HDMI_COLORSPACE_RGB: 10078c2ecf20Sopenharmony_ci return "RGB"; 10088c2ecf20Sopenharmony_ci case HDMI_COLORSPACE_YUV422: 10098c2ecf20Sopenharmony_ci return "YCbCr 4:2:2"; 10108c2ecf20Sopenharmony_ci case HDMI_COLORSPACE_YUV444: 10118c2ecf20Sopenharmony_ci return "YCbCr 4:4:4"; 10128c2ecf20Sopenharmony_ci case HDMI_COLORSPACE_YUV420: 10138c2ecf20Sopenharmony_ci return "YCbCr 4:2:0"; 10148c2ecf20Sopenharmony_ci case HDMI_COLORSPACE_RESERVED4: 10158c2ecf20Sopenharmony_ci return "Reserved (4)"; 10168c2ecf20Sopenharmony_ci case HDMI_COLORSPACE_RESERVED5: 10178c2ecf20Sopenharmony_ci return "Reserved (5)"; 10188c2ecf20Sopenharmony_ci case HDMI_COLORSPACE_RESERVED6: 10198c2ecf20Sopenharmony_ci return "Reserved (6)"; 10208c2ecf20Sopenharmony_ci case HDMI_COLORSPACE_IDO_DEFINED: 10218c2ecf20Sopenharmony_ci return "IDO Defined"; 10228c2ecf20Sopenharmony_ci } 10238c2ecf20Sopenharmony_ci return "Invalid"; 10248c2ecf20Sopenharmony_ci} 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_cistatic const char *hdmi_scan_mode_get_name(enum hdmi_scan_mode scan_mode) 10278c2ecf20Sopenharmony_ci{ 10288c2ecf20Sopenharmony_ci switch (scan_mode) { 10298c2ecf20Sopenharmony_ci case HDMI_SCAN_MODE_NONE: 10308c2ecf20Sopenharmony_ci return "No Data"; 10318c2ecf20Sopenharmony_ci case HDMI_SCAN_MODE_OVERSCAN: 10328c2ecf20Sopenharmony_ci return "Overscan"; 10338c2ecf20Sopenharmony_ci case HDMI_SCAN_MODE_UNDERSCAN: 10348c2ecf20Sopenharmony_ci return "Underscan"; 10358c2ecf20Sopenharmony_ci case HDMI_SCAN_MODE_RESERVED: 10368c2ecf20Sopenharmony_ci return "Reserved"; 10378c2ecf20Sopenharmony_ci } 10388c2ecf20Sopenharmony_ci return "Invalid"; 10398c2ecf20Sopenharmony_ci} 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_cistatic const char *hdmi_colorimetry_get_name(enum hdmi_colorimetry colorimetry) 10428c2ecf20Sopenharmony_ci{ 10438c2ecf20Sopenharmony_ci switch (colorimetry) { 10448c2ecf20Sopenharmony_ci case HDMI_COLORIMETRY_NONE: 10458c2ecf20Sopenharmony_ci return "No Data"; 10468c2ecf20Sopenharmony_ci case HDMI_COLORIMETRY_ITU_601: 10478c2ecf20Sopenharmony_ci return "ITU601"; 10488c2ecf20Sopenharmony_ci case HDMI_COLORIMETRY_ITU_709: 10498c2ecf20Sopenharmony_ci return "ITU709"; 10508c2ecf20Sopenharmony_ci case HDMI_COLORIMETRY_EXTENDED: 10518c2ecf20Sopenharmony_ci return "Extended"; 10528c2ecf20Sopenharmony_ci } 10538c2ecf20Sopenharmony_ci return "Invalid"; 10548c2ecf20Sopenharmony_ci} 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_cistatic const char * 10578c2ecf20Sopenharmony_cihdmi_picture_aspect_get_name(enum hdmi_picture_aspect picture_aspect) 10588c2ecf20Sopenharmony_ci{ 10598c2ecf20Sopenharmony_ci switch (picture_aspect) { 10608c2ecf20Sopenharmony_ci case HDMI_PICTURE_ASPECT_NONE: 10618c2ecf20Sopenharmony_ci return "No Data"; 10628c2ecf20Sopenharmony_ci case HDMI_PICTURE_ASPECT_4_3: 10638c2ecf20Sopenharmony_ci return "4:3"; 10648c2ecf20Sopenharmony_ci case HDMI_PICTURE_ASPECT_16_9: 10658c2ecf20Sopenharmony_ci return "16:9"; 10668c2ecf20Sopenharmony_ci case HDMI_PICTURE_ASPECT_64_27: 10678c2ecf20Sopenharmony_ci return "64:27"; 10688c2ecf20Sopenharmony_ci case HDMI_PICTURE_ASPECT_256_135: 10698c2ecf20Sopenharmony_ci return "256:135"; 10708c2ecf20Sopenharmony_ci case HDMI_PICTURE_ASPECT_RESERVED: 10718c2ecf20Sopenharmony_ci return "Reserved"; 10728c2ecf20Sopenharmony_ci } 10738c2ecf20Sopenharmony_ci return "Invalid"; 10748c2ecf20Sopenharmony_ci} 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_cistatic const char * 10778c2ecf20Sopenharmony_cihdmi_active_aspect_get_name(enum hdmi_active_aspect active_aspect) 10788c2ecf20Sopenharmony_ci{ 10798c2ecf20Sopenharmony_ci if (active_aspect < 0 || active_aspect > 0xf) 10808c2ecf20Sopenharmony_ci return "Invalid"; 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci switch (active_aspect) { 10838c2ecf20Sopenharmony_ci case HDMI_ACTIVE_ASPECT_16_9_TOP: 10848c2ecf20Sopenharmony_ci return "16:9 Top"; 10858c2ecf20Sopenharmony_ci case HDMI_ACTIVE_ASPECT_14_9_TOP: 10868c2ecf20Sopenharmony_ci return "14:9 Top"; 10878c2ecf20Sopenharmony_ci case HDMI_ACTIVE_ASPECT_16_9_CENTER: 10888c2ecf20Sopenharmony_ci return "16:9 Center"; 10898c2ecf20Sopenharmony_ci case HDMI_ACTIVE_ASPECT_PICTURE: 10908c2ecf20Sopenharmony_ci return "Same as Picture"; 10918c2ecf20Sopenharmony_ci case HDMI_ACTIVE_ASPECT_4_3: 10928c2ecf20Sopenharmony_ci return "4:3"; 10938c2ecf20Sopenharmony_ci case HDMI_ACTIVE_ASPECT_16_9: 10948c2ecf20Sopenharmony_ci return "16:9"; 10958c2ecf20Sopenharmony_ci case HDMI_ACTIVE_ASPECT_14_9: 10968c2ecf20Sopenharmony_ci return "14:9"; 10978c2ecf20Sopenharmony_ci case HDMI_ACTIVE_ASPECT_4_3_SP_14_9: 10988c2ecf20Sopenharmony_ci return "4:3 SP 14:9"; 10998c2ecf20Sopenharmony_ci case HDMI_ACTIVE_ASPECT_16_9_SP_14_9: 11008c2ecf20Sopenharmony_ci return "16:9 SP 14:9"; 11018c2ecf20Sopenharmony_ci case HDMI_ACTIVE_ASPECT_16_9_SP_4_3: 11028c2ecf20Sopenharmony_ci return "16:9 SP 4:3"; 11038c2ecf20Sopenharmony_ci } 11048c2ecf20Sopenharmony_ci return "Reserved"; 11058c2ecf20Sopenharmony_ci} 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_cistatic const char * 11088c2ecf20Sopenharmony_cihdmi_extended_colorimetry_get_name(enum hdmi_extended_colorimetry ext_col) 11098c2ecf20Sopenharmony_ci{ 11108c2ecf20Sopenharmony_ci switch (ext_col) { 11118c2ecf20Sopenharmony_ci case HDMI_EXTENDED_COLORIMETRY_XV_YCC_601: 11128c2ecf20Sopenharmony_ci return "xvYCC 601"; 11138c2ecf20Sopenharmony_ci case HDMI_EXTENDED_COLORIMETRY_XV_YCC_709: 11148c2ecf20Sopenharmony_ci return "xvYCC 709"; 11158c2ecf20Sopenharmony_ci case HDMI_EXTENDED_COLORIMETRY_S_YCC_601: 11168c2ecf20Sopenharmony_ci return "sYCC 601"; 11178c2ecf20Sopenharmony_ci case HDMI_EXTENDED_COLORIMETRY_OPYCC_601: 11188c2ecf20Sopenharmony_ci return "opYCC 601"; 11198c2ecf20Sopenharmony_ci case HDMI_EXTENDED_COLORIMETRY_OPRGB: 11208c2ecf20Sopenharmony_ci return "opRGB"; 11218c2ecf20Sopenharmony_ci case HDMI_EXTENDED_COLORIMETRY_BT2020_CONST_LUM: 11228c2ecf20Sopenharmony_ci return "BT.2020 Constant Luminance"; 11238c2ecf20Sopenharmony_ci case HDMI_EXTENDED_COLORIMETRY_BT2020: 11248c2ecf20Sopenharmony_ci return "BT.2020"; 11258c2ecf20Sopenharmony_ci case HDMI_EXTENDED_COLORIMETRY_RESERVED: 11268c2ecf20Sopenharmony_ci return "Reserved"; 11278c2ecf20Sopenharmony_ci } 11288c2ecf20Sopenharmony_ci return "Invalid"; 11298c2ecf20Sopenharmony_ci} 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_cistatic const char * 11328c2ecf20Sopenharmony_cihdmi_quantization_range_get_name(enum hdmi_quantization_range qrange) 11338c2ecf20Sopenharmony_ci{ 11348c2ecf20Sopenharmony_ci switch (qrange) { 11358c2ecf20Sopenharmony_ci case HDMI_QUANTIZATION_RANGE_DEFAULT: 11368c2ecf20Sopenharmony_ci return "Default"; 11378c2ecf20Sopenharmony_ci case HDMI_QUANTIZATION_RANGE_LIMITED: 11388c2ecf20Sopenharmony_ci return "Limited"; 11398c2ecf20Sopenharmony_ci case HDMI_QUANTIZATION_RANGE_FULL: 11408c2ecf20Sopenharmony_ci return "Full"; 11418c2ecf20Sopenharmony_ci case HDMI_QUANTIZATION_RANGE_RESERVED: 11428c2ecf20Sopenharmony_ci return "Reserved"; 11438c2ecf20Sopenharmony_ci } 11448c2ecf20Sopenharmony_ci return "Invalid"; 11458c2ecf20Sopenharmony_ci} 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_cistatic const char *hdmi_nups_get_name(enum hdmi_nups nups) 11488c2ecf20Sopenharmony_ci{ 11498c2ecf20Sopenharmony_ci switch (nups) { 11508c2ecf20Sopenharmony_ci case HDMI_NUPS_UNKNOWN: 11518c2ecf20Sopenharmony_ci return "Unknown Non-uniform Scaling"; 11528c2ecf20Sopenharmony_ci case HDMI_NUPS_HORIZONTAL: 11538c2ecf20Sopenharmony_ci return "Horizontally Scaled"; 11548c2ecf20Sopenharmony_ci case HDMI_NUPS_VERTICAL: 11558c2ecf20Sopenharmony_ci return "Vertically Scaled"; 11568c2ecf20Sopenharmony_ci case HDMI_NUPS_BOTH: 11578c2ecf20Sopenharmony_ci return "Horizontally and Vertically Scaled"; 11588c2ecf20Sopenharmony_ci } 11598c2ecf20Sopenharmony_ci return "Invalid"; 11608c2ecf20Sopenharmony_ci} 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_cistatic const char * 11638c2ecf20Sopenharmony_cihdmi_ycc_quantization_range_get_name(enum hdmi_ycc_quantization_range qrange) 11648c2ecf20Sopenharmony_ci{ 11658c2ecf20Sopenharmony_ci switch (qrange) { 11668c2ecf20Sopenharmony_ci case HDMI_YCC_QUANTIZATION_RANGE_LIMITED: 11678c2ecf20Sopenharmony_ci return "Limited"; 11688c2ecf20Sopenharmony_ci case HDMI_YCC_QUANTIZATION_RANGE_FULL: 11698c2ecf20Sopenharmony_ci return "Full"; 11708c2ecf20Sopenharmony_ci } 11718c2ecf20Sopenharmony_ci return "Invalid"; 11728c2ecf20Sopenharmony_ci} 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_cistatic const char * 11758c2ecf20Sopenharmony_cihdmi_content_type_get_name(enum hdmi_content_type content_type) 11768c2ecf20Sopenharmony_ci{ 11778c2ecf20Sopenharmony_ci switch (content_type) { 11788c2ecf20Sopenharmony_ci case HDMI_CONTENT_TYPE_GRAPHICS: 11798c2ecf20Sopenharmony_ci return "Graphics"; 11808c2ecf20Sopenharmony_ci case HDMI_CONTENT_TYPE_PHOTO: 11818c2ecf20Sopenharmony_ci return "Photo"; 11828c2ecf20Sopenharmony_ci case HDMI_CONTENT_TYPE_CINEMA: 11838c2ecf20Sopenharmony_ci return "Cinema"; 11848c2ecf20Sopenharmony_ci case HDMI_CONTENT_TYPE_GAME: 11858c2ecf20Sopenharmony_ci return "Game"; 11868c2ecf20Sopenharmony_ci } 11878c2ecf20Sopenharmony_ci return "Invalid"; 11888c2ecf20Sopenharmony_ci} 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_cistatic void hdmi_avi_infoframe_log(const char *level, 11918c2ecf20Sopenharmony_ci struct device *dev, 11928c2ecf20Sopenharmony_ci const struct hdmi_avi_infoframe *frame) 11938c2ecf20Sopenharmony_ci{ 11948c2ecf20Sopenharmony_ci hdmi_infoframe_log_header(level, dev, 11958c2ecf20Sopenharmony_ci (const struct hdmi_any_infoframe *)frame); 11968c2ecf20Sopenharmony_ci 11978c2ecf20Sopenharmony_ci hdmi_log(" colorspace: %s\n", 11988c2ecf20Sopenharmony_ci hdmi_colorspace_get_name(frame->colorspace)); 11998c2ecf20Sopenharmony_ci hdmi_log(" scan mode: %s\n", 12008c2ecf20Sopenharmony_ci hdmi_scan_mode_get_name(frame->scan_mode)); 12018c2ecf20Sopenharmony_ci hdmi_log(" colorimetry: %s\n", 12028c2ecf20Sopenharmony_ci hdmi_colorimetry_get_name(frame->colorimetry)); 12038c2ecf20Sopenharmony_ci hdmi_log(" picture aspect: %s\n", 12048c2ecf20Sopenharmony_ci hdmi_picture_aspect_get_name(frame->picture_aspect)); 12058c2ecf20Sopenharmony_ci hdmi_log(" active aspect: %s\n", 12068c2ecf20Sopenharmony_ci hdmi_active_aspect_get_name(frame->active_aspect)); 12078c2ecf20Sopenharmony_ci hdmi_log(" itc: %s\n", frame->itc ? "IT Content" : "No Data"); 12088c2ecf20Sopenharmony_ci hdmi_log(" extended colorimetry: %s\n", 12098c2ecf20Sopenharmony_ci hdmi_extended_colorimetry_get_name(frame->extended_colorimetry)); 12108c2ecf20Sopenharmony_ci hdmi_log(" quantization range: %s\n", 12118c2ecf20Sopenharmony_ci hdmi_quantization_range_get_name(frame->quantization_range)); 12128c2ecf20Sopenharmony_ci hdmi_log(" nups: %s\n", hdmi_nups_get_name(frame->nups)); 12138c2ecf20Sopenharmony_ci hdmi_log(" video code: %u\n", frame->video_code); 12148c2ecf20Sopenharmony_ci hdmi_log(" ycc quantization range: %s\n", 12158c2ecf20Sopenharmony_ci hdmi_ycc_quantization_range_get_name(frame->ycc_quantization_range)); 12168c2ecf20Sopenharmony_ci hdmi_log(" hdmi content type: %s\n", 12178c2ecf20Sopenharmony_ci hdmi_content_type_get_name(frame->content_type)); 12188c2ecf20Sopenharmony_ci hdmi_log(" pixel repeat: %u\n", frame->pixel_repeat); 12198c2ecf20Sopenharmony_ci hdmi_log(" bar top %u, bottom %u, left %u, right %u\n", 12208c2ecf20Sopenharmony_ci frame->top_bar, frame->bottom_bar, 12218c2ecf20Sopenharmony_ci frame->left_bar, frame->right_bar); 12228c2ecf20Sopenharmony_ci} 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_cistatic const char *hdmi_spd_sdi_get_name(enum hdmi_spd_sdi sdi) 12258c2ecf20Sopenharmony_ci{ 12268c2ecf20Sopenharmony_ci if (sdi < 0 || sdi > 0xff) 12278c2ecf20Sopenharmony_ci return "Invalid"; 12288c2ecf20Sopenharmony_ci switch (sdi) { 12298c2ecf20Sopenharmony_ci case HDMI_SPD_SDI_UNKNOWN: 12308c2ecf20Sopenharmony_ci return "Unknown"; 12318c2ecf20Sopenharmony_ci case HDMI_SPD_SDI_DSTB: 12328c2ecf20Sopenharmony_ci return "Digital STB"; 12338c2ecf20Sopenharmony_ci case HDMI_SPD_SDI_DVDP: 12348c2ecf20Sopenharmony_ci return "DVD Player"; 12358c2ecf20Sopenharmony_ci case HDMI_SPD_SDI_DVHS: 12368c2ecf20Sopenharmony_ci return "D-VHS"; 12378c2ecf20Sopenharmony_ci case HDMI_SPD_SDI_HDDVR: 12388c2ecf20Sopenharmony_ci return "HDD Videorecorder"; 12398c2ecf20Sopenharmony_ci case HDMI_SPD_SDI_DVC: 12408c2ecf20Sopenharmony_ci return "DVC"; 12418c2ecf20Sopenharmony_ci case HDMI_SPD_SDI_DSC: 12428c2ecf20Sopenharmony_ci return "DSC"; 12438c2ecf20Sopenharmony_ci case HDMI_SPD_SDI_VCD: 12448c2ecf20Sopenharmony_ci return "Video CD"; 12458c2ecf20Sopenharmony_ci case HDMI_SPD_SDI_GAME: 12468c2ecf20Sopenharmony_ci return "Game"; 12478c2ecf20Sopenharmony_ci case HDMI_SPD_SDI_PC: 12488c2ecf20Sopenharmony_ci return "PC General"; 12498c2ecf20Sopenharmony_ci case HDMI_SPD_SDI_BD: 12508c2ecf20Sopenharmony_ci return "Blu-Ray Disc (BD)"; 12518c2ecf20Sopenharmony_ci case HDMI_SPD_SDI_SACD: 12528c2ecf20Sopenharmony_ci return "Super Audio CD"; 12538c2ecf20Sopenharmony_ci case HDMI_SPD_SDI_HDDVD: 12548c2ecf20Sopenharmony_ci return "HD DVD"; 12558c2ecf20Sopenharmony_ci case HDMI_SPD_SDI_PMP: 12568c2ecf20Sopenharmony_ci return "PMP"; 12578c2ecf20Sopenharmony_ci } 12588c2ecf20Sopenharmony_ci return "Reserved"; 12598c2ecf20Sopenharmony_ci} 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_cistatic void hdmi_spd_infoframe_log(const char *level, 12628c2ecf20Sopenharmony_ci struct device *dev, 12638c2ecf20Sopenharmony_ci const struct hdmi_spd_infoframe *frame) 12648c2ecf20Sopenharmony_ci{ 12658c2ecf20Sopenharmony_ci u8 buf[17]; 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci hdmi_infoframe_log_header(level, dev, 12688c2ecf20Sopenharmony_ci (const struct hdmi_any_infoframe *)frame); 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_ci memset(buf, 0, sizeof(buf)); 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci strncpy(buf, frame->vendor, 8); 12738c2ecf20Sopenharmony_ci hdmi_log(" vendor: %s\n", buf); 12748c2ecf20Sopenharmony_ci strncpy(buf, frame->product, 16); 12758c2ecf20Sopenharmony_ci hdmi_log(" product: %s\n", buf); 12768c2ecf20Sopenharmony_ci hdmi_log(" source device information: %s (0x%x)\n", 12778c2ecf20Sopenharmony_ci hdmi_spd_sdi_get_name(frame->sdi), frame->sdi); 12788c2ecf20Sopenharmony_ci} 12798c2ecf20Sopenharmony_ci 12808c2ecf20Sopenharmony_cistatic const char * 12818c2ecf20Sopenharmony_cihdmi_audio_coding_type_get_name(enum hdmi_audio_coding_type coding_type) 12828c2ecf20Sopenharmony_ci{ 12838c2ecf20Sopenharmony_ci switch (coding_type) { 12848c2ecf20Sopenharmony_ci case HDMI_AUDIO_CODING_TYPE_STREAM: 12858c2ecf20Sopenharmony_ci return "Refer to Stream Header"; 12868c2ecf20Sopenharmony_ci case HDMI_AUDIO_CODING_TYPE_PCM: 12878c2ecf20Sopenharmony_ci return "PCM"; 12888c2ecf20Sopenharmony_ci case HDMI_AUDIO_CODING_TYPE_AC3: 12898c2ecf20Sopenharmony_ci return "AC-3"; 12908c2ecf20Sopenharmony_ci case HDMI_AUDIO_CODING_TYPE_MPEG1: 12918c2ecf20Sopenharmony_ci return "MPEG1"; 12928c2ecf20Sopenharmony_ci case HDMI_AUDIO_CODING_TYPE_MP3: 12938c2ecf20Sopenharmony_ci return "MP3"; 12948c2ecf20Sopenharmony_ci case HDMI_AUDIO_CODING_TYPE_MPEG2: 12958c2ecf20Sopenharmony_ci return "MPEG2"; 12968c2ecf20Sopenharmony_ci case HDMI_AUDIO_CODING_TYPE_AAC_LC: 12978c2ecf20Sopenharmony_ci return "AAC"; 12988c2ecf20Sopenharmony_ci case HDMI_AUDIO_CODING_TYPE_DTS: 12998c2ecf20Sopenharmony_ci return "DTS"; 13008c2ecf20Sopenharmony_ci case HDMI_AUDIO_CODING_TYPE_ATRAC: 13018c2ecf20Sopenharmony_ci return "ATRAC"; 13028c2ecf20Sopenharmony_ci case HDMI_AUDIO_CODING_TYPE_DSD: 13038c2ecf20Sopenharmony_ci return "One Bit Audio"; 13048c2ecf20Sopenharmony_ci case HDMI_AUDIO_CODING_TYPE_EAC3: 13058c2ecf20Sopenharmony_ci return "Dolby Digital +"; 13068c2ecf20Sopenharmony_ci case HDMI_AUDIO_CODING_TYPE_DTS_HD: 13078c2ecf20Sopenharmony_ci return "DTS-HD"; 13088c2ecf20Sopenharmony_ci case HDMI_AUDIO_CODING_TYPE_MLP: 13098c2ecf20Sopenharmony_ci return "MAT (MLP)"; 13108c2ecf20Sopenharmony_ci case HDMI_AUDIO_CODING_TYPE_DST: 13118c2ecf20Sopenharmony_ci return "DST"; 13128c2ecf20Sopenharmony_ci case HDMI_AUDIO_CODING_TYPE_WMA_PRO: 13138c2ecf20Sopenharmony_ci return "WMA PRO"; 13148c2ecf20Sopenharmony_ci case HDMI_AUDIO_CODING_TYPE_CXT: 13158c2ecf20Sopenharmony_ci return "Refer to CXT"; 13168c2ecf20Sopenharmony_ci } 13178c2ecf20Sopenharmony_ci return "Invalid"; 13188c2ecf20Sopenharmony_ci} 13198c2ecf20Sopenharmony_ci 13208c2ecf20Sopenharmony_cistatic const char * 13218c2ecf20Sopenharmony_cihdmi_audio_sample_size_get_name(enum hdmi_audio_sample_size sample_size) 13228c2ecf20Sopenharmony_ci{ 13238c2ecf20Sopenharmony_ci switch (sample_size) { 13248c2ecf20Sopenharmony_ci case HDMI_AUDIO_SAMPLE_SIZE_STREAM: 13258c2ecf20Sopenharmony_ci return "Refer to Stream Header"; 13268c2ecf20Sopenharmony_ci case HDMI_AUDIO_SAMPLE_SIZE_16: 13278c2ecf20Sopenharmony_ci return "16 bit"; 13288c2ecf20Sopenharmony_ci case HDMI_AUDIO_SAMPLE_SIZE_20: 13298c2ecf20Sopenharmony_ci return "20 bit"; 13308c2ecf20Sopenharmony_ci case HDMI_AUDIO_SAMPLE_SIZE_24: 13318c2ecf20Sopenharmony_ci return "24 bit"; 13328c2ecf20Sopenharmony_ci } 13338c2ecf20Sopenharmony_ci return "Invalid"; 13348c2ecf20Sopenharmony_ci} 13358c2ecf20Sopenharmony_ci 13368c2ecf20Sopenharmony_cistatic const char * 13378c2ecf20Sopenharmony_cihdmi_audio_sample_frequency_get_name(enum hdmi_audio_sample_frequency freq) 13388c2ecf20Sopenharmony_ci{ 13398c2ecf20Sopenharmony_ci switch (freq) { 13408c2ecf20Sopenharmony_ci case HDMI_AUDIO_SAMPLE_FREQUENCY_STREAM: 13418c2ecf20Sopenharmony_ci return "Refer to Stream Header"; 13428c2ecf20Sopenharmony_ci case HDMI_AUDIO_SAMPLE_FREQUENCY_32000: 13438c2ecf20Sopenharmony_ci return "32 kHz"; 13448c2ecf20Sopenharmony_ci case HDMI_AUDIO_SAMPLE_FREQUENCY_44100: 13458c2ecf20Sopenharmony_ci return "44.1 kHz (CD)"; 13468c2ecf20Sopenharmony_ci case HDMI_AUDIO_SAMPLE_FREQUENCY_48000: 13478c2ecf20Sopenharmony_ci return "48 kHz"; 13488c2ecf20Sopenharmony_ci case HDMI_AUDIO_SAMPLE_FREQUENCY_88200: 13498c2ecf20Sopenharmony_ci return "88.2 kHz"; 13508c2ecf20Sopenharmony_ci case HDMI_AUDIO_SAMPLE_FREQUENCY_96000: 13518c2ecf20Sopenharmony_ci return "96 kHz"; 13528c2ecf20Sopenharmony_ci case HDMI_AUDIO_SAMPLE_FREQUENCY_176400: 13538c2ecf20Sopenharmony_ci return "176.4 kHz"; 13548c2ecf20Sopenharmony_ci case HDMI_AUDIO_SAMPLE_FREQUENCY_192000: 13558c2ecf20Sopenharmony_ci return "192 kHz"; 13568c2ecf20Sopenharmony_ci } 13578c2ecf20Sopenharmony_ci return "Invalid"; 13588c2ecf20Sopenharmony_ci} 13598c2ecf20Sopenharmony_ci 13608c2ecf20Sopenharmony_cistatic const char * 13618c2ecf20Sopenharmony_cihdmi_audio_coding_type_ext_get_name(enum hdmi_audio_coding_type_ext ctx) 13628c2ecf20Sopenharmony_ci{ 13638c2ecf20Sopenharmony_ci if (ctx < 0 || ctx > 0x1f) 13648c2ecf20Sopenharmony_ci return "Invalid"; 13658c2ecf20Sopenharmony_ci 13668c2ecf20Sopenharmony_ci switch (ctx) { 13678c2ecf20Sopenharmony_ci case HDMI_AUDIO_CODING_TYPE_EXT_CT: 13688c2ecf20Sopenharmony_ci return "Refer to CT"; 13698c2ecf20Sopenharmony_ci case HDMI_AUDIO_CODING_TYPE_EXT_HE_AAC: 13708c2ecf20Sopenharmony_ci return "HE AAC"; 13718c2ecf20Sopenharmony_ci case HDMI_AUDIO_CODING_TYPE_EXT_HE_AAC_V2: 13728c2ecf20Sopenharmony_ci return "HE AAC v2"; 13738c2ecf20Sopenharmony_ci case HDMI_AUDIO_CODING_TYPE_EXT_MPEG_SURROUND: 13748c2ecf20Sopenharmony_ci return "MPEG SURROUND"; 13758c2ecf20Sopenharmony_ci case HDMI_AUDIO_CODING_TYPE_EXT_MPEG4_HE_AAC: 13768c2ecf20Sopenharmony_ci return "MPEG-4 HE AAC"; 13778c2ecf20Sopenharmony_ci case HDMI_AUDIO_CODING_TYPE_EXT_MPEG4_HE_AAC_V2: 13788c2ecf20Sopenharmony_ci return "MPEG-4 HE AAC v2"; 13798c2ecf20Sopenharmony_ci case HDMI_AUDIO_CODING_TYPE_EXT_MPEG4_AAC_LC: 13808c2ecf20Sopenharmony_ci return "MPEG-4 AAC LC"; 13818c2ecf20Sopenharmony_ci case HDMI_AUDIO_CODING_TYPE_EXT_DRA: 13828c2ecf20Sopenharmony_ci return "DRA"; 13838c2ecf20Sopenharmony_ci case HDMI_AUDIO_CODING_TYPE_EXT_MPEG4_HE_AAC_SURROUND: 13848c2ecf20Sopenharmony_ci return "MPEG-4 HE AAC + MPEG Surround"; 13858c2ecf20Sopenharmony_ci case HDMI_AUDIO_CODING_TYPE_EXT_MPEG4_AAC_LC_SURROUND: 13868c2ecf20Sopenharmony_ci return "MPEG-4 AAC LC + MPEG Surround"; 13878c2ecf20Sopenharmony_ci } 13888c2ecf20Sopenharmony_ci return "Reserved"; 13898c2ecf20Sopenharmony_ci} 13908c2ecf20Sopenharmony_ci 13918c2ecf20Sopenharmony_cistatic void hdmi_audio_infoframe_log(const char *level, 13928c2ecf20Sopenharmony_ci struct device *dev, 13938c2ecf20Sopenharmony_ci const struct hdmi_audio_infoframe *frame) 13948c2ecf20Sopenharmony_ci{ 13958c2ecf20Sopenharmony_ci hdmi_infoframe_log_header(level, dev, 13968c2ecf20Sopenharmony_ci (const struct hdmi_any_infoframe *)frame); 13978c2ecf20Sopenharmony_ci 13988c2ecf20Sopenharmony_ci if (frame->channels) 13998c2ecf20Sopenharmony_ci hdmi_log(" channels: %u\n", frame->channels - 1); 14008c2ecf20Sopenharmony_ci else 14018c2ecf20Sopenharmony_ci hdmi_log(" channels: Refer to stream header\n"); 14028c2ecf20Sopenharmony_ci hdmi_log(" coding type: %s\n", 14038c2ecf20Sopenharmony_ci hdmi_audio_coding_type_get_name(frame->coding_type)); 14048c2ecf20Sopenharmony_ci hdmi_log(" sample size: %s\n", 14058c2ecf20Sopenharmony_ci hdmi_audio_sample_size_get_name(frame->sample_size)); 14068c2ecf20Sopenharmony_ci hdmi_log(" sample frequency: %s\n", 14078c2ecf20Sopenharmony_ci hdmi_audio_sample_frequency_get_name(frame->sample_frequency)); 14088c2ecf20Sopenharmony_ci hdmi_log(" coding type ext: %s\n", 14098c2ecf20Sopenharmony_ci hdmi_audio_coding_type_ext_get_name(frame->coding_type_ext)); 14108c2ecf20Sopenharmony_ci hdmi_log(" channel allocation: 0x%x\n", 14118c2ecf20Sopenharmony_ci frame->channel_allocation); 14128c2ecf20Sopenharmony_ci hdmi_log(" level shift value: %u dB\n", 14138c2ecf20Sopenharmony_ci frame->level_shift_value); 14148c2ecf20Sopenharmony_ci hdmi_log(" downmix inhibit: %s\n", 14158c2ecf20Sopenharmony_ci frame->downmix_inhibit ? "Yes" : "No"); 14168c2ecf20Sopenharmony_ci} 14178c2ecf20Sopenharmony_ci 14188c2ecf20Sopenharmony_cistatic void hdmi_drm_infoframe_log(const char *level, 14198c2ecf20Sopenharmony_ci struct device *dev, 14208c2ecf20Sopenharmony_ci const struct hdmi_drm_infoframe *frame) 14218c2ecf20Sopenharmony_ci{ 14228c2ecf20Sopenharmony_ci int i; 14238c2ecf20Sopenharmony_ci 14248c2ecf20Sopenharmony_ci hdmi_infoframe_log_header(level, dev, 14258c2ecf20Sopenharmony_ci (struct hdmi_any_infoframe *)frame); 14268c2ecf20Sopenharmony_ci hdmi_log("length: %d\n", frame->length); 14278c2ecf20Sopenharmony_ci hdmi_log("metadata type: %d\n", frame->metadata_type); 14288c2ecf20Sopenharmony_ci hdmi_log("eotf: %d\n", frame->eotf); 14298c2ecf20Sopenharmony_ci for (i = 0; i < 3; i++) { 14308c2ecf20Sopenharmony_ci hdmi_log("x[%d]: %d\n", i, frame->display_primaries[i].x); 14318c2ecf20Sopenharmony_ci hdmi_log("y[%d]: %d\n", i, frame->display_primaries[i].y); 14328c2ecf20Sopenharmony_ci } 14338c2ecf20Sopenharmony_ci 14348c2ecf20Sopenharmony_ci hdmi_log("white point x: %d\n", frame->white_point.x); 14358c2ecf20Sopenharmony_ci hdmi_log("white point y: %d\n", frame->white_point.y); 14368c2ecf20Sopenharmony_ci 14378c2ecf20Sopenharmony_ci hdmi_log("max_display_mastering_luminance: %d\n", 14388c2ecf20Sopenharmony_ci frame->max_display_mastering_luminance); 14398c2ecf20Sopenharmony_ci hdmi_log("min_display_mastering_luminance: %d\n", 14408c2ecf20Sopenharmony_ci frame->min_display_mastering_luminance); 14418c2ecf20Sopenharmony_ci 14428c2ecf20Sopenharmony_ci hdmi_log("max_cll: %d\n", frame->max_cll); 14438c2ecf20Sopenharmony_ci hdmi_log("max_fall: %d\n", frame->max_fall); 14448c2ecf20Sopenharmony_ci} 14458c2ecf20Sopenharmony_ci 14468c2ecf20Sopenharmony_cistatic const char * 14478c2ecf20Sopenharmony_cihdmi_3d_structure_get_name(enum hdmi_3d_structure s3d_struct) 14488c2ecf20Sopenharmony_ci{ 14498c2ecf20Sopenharmony_ci if (s3d_struct < 0 || s3d_struct > 0xf) 14508c2ecf20Sopenharmony_ci return "Invalid"; 14518c2ecf20Sopenharmony_ci 14528c2ecf20Sopenharmony_ci switch (s3d_struct) { 14538c2ecf20Sopenharmony_ci case HDMI_3D_STRUCTURE_FRAME_PACKING: 14548c2ecf20Sopenharmony_ci return "Frame Packing"; 14558c2ecf20Sopenharmony_ci case HDMI_3D_STRUCTURE_FIELD_ALTERNATIVE: 14568c2ecf20Sopenharmony_ci return "Field Alternative"; 14578c2ecf20Sopenharmony_ci case HDMI_3D_STRUCTURE_LINE_ALTERNATIVE: 14588c2ecf20Sopenharmony_ci return "Line Alternative"; 14598c2ecf20Sopenharmony_ci case HDMI_3D_STRUCTURE_SIDE_BY_SIDE_FULL: 14608c2ecf20Sopenharmony_ci return "Side-by-side (Full)"; 14618c2ecf20Sopenharmony_ci case HDMI_3D_STRUCTURE_L_DEPTH: 14628c2ecf20Sopenharmony_ci return "L + Depth"; 14638c2ecf20Sopenharmony_ci case HDMI_3D_STRUCTURE_L_DEPTH_GFX_GFX_DEPTH: 14648c2ecf20Sopenharmony_ci return "L + Depth + Graphics + Graphics-depth"; 14658c2ecf20Sopenharmony_ci case HDMI_3D_STRUCTURE_TOP_AND_BOTTOM: 14668c2ecf20Sopenharmony_ci return "Top-and-Bottom"; 14678c2ecf20Sopenharmony_ci case HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF: 14688c2ecf20Sopenharmony_ci return "Side-by-side (Half)"; 14698c2ecf20Sopenharmony_ci default: 14708c2ecf20Sopenharmony_ci break; 14718c2ecf20Sopenharmony_ci } 14728c2ecf20Sopenharmony_ci return "Reserved"; 14738c2ecf20Sopenharmony_ci} 14748c2ecf20Sopenharmony_ci 14758c2ecf20Sopenharmony_cistatic void 14768c2ecf20Sopenharmony_cihdmi_vendor_any_infoframe_log(const char *level, 14778c2ecf20Sopenharmony_ci struct device *dev, 14788c2ecf20Sopenharmony_ci const union hdmi_vendor_any_infoframe *frame) 14798c2ecf20Sopenharmony_ci{ 14808c2ecf20Sopenharmony_ci const struct hdmi_vendor_infoframe *hvf = &frame->hdmi; 14818c2ecf20Sopenharmony_ci 14828c2ecf20Sopenharmony_ci hdmi_infoframe_log_header(level, dev, 14838c2ecf20Sopenharmony_ci (const struct hdmi_any_infoframe *)frame); 14848c2ecf20Sopenharmony_ci 14858c2ecf20Sopenharmony_ci if (frame->any.oui != HDMI_IEEE_OUI) { 14868c2ecf20Sopenharmony_ci hdmi_log(" not a HDMI vendor infoframe\n"); 14878c2ecf20Sopenharmony_ci return; 14888c2ecf20Sopenharmony_ci } 14898c2ecf20Sopenharmony_ci if (hvf->vic == 0 && hvf->s3d_struct == HDMI_3D_STRUCTURE_INVALID) { 14908c2ecf20Sopenharmony_ci hdmi_log(" empty frame\n"); 14918c2ecf20Sopenharmony_ci return; 14928c2ecf20Sopenharmony_ci } 14938c2ecf20Sopenharmony_ci 14948c2ecf20Sopenharmony_ci if (hvf->vic) 14958c2ecf20Sopenharmony_ci hdmi_log(" HDMI VIC: %u\n", hvf->vic); 14968c2ecf20Sopenharmony_ci if (hvf->s3d_struct != HDMI_3D_STRUCTURE_INVALID) { 14978c2ecf20Sopenharmony_ci hdmi_log(" 3D structure: %s\n", 14988c2ecf20Sopenharmony_ci hdmi_3d_structure_get_name(hvf->s3d_struct)); 14998c2ecf20Sopenharmony_ci if (hvf->s3d_struct >= HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF) 15008c2ecf20Sopenharmony_ci hdmi_log(" 3D extension data: %d\n", 15018c2ecf20Sopenharmony_ci hvf->s3d_ext_data); 15028c2ecf20Sopenharmony_ci } 15038c2ecf20Sopenharmony_ci} 15048c2ecf20Sopenharmony_ci 15058c2ecf20Sopenharmony_ci/** 15068c2ecf20Sopenharmony_ci * hdmi_infoframe_log() - log info of HDMI infoframe 15078c2ecf20Sopenharmony_ci * @level: logging level 15088c2ecf20Sopenharmony_ci * @dev: device 15098c2ecf20Sopenharmony_ci * @frame: HDMI infoframe 15108c2ecf20Sopenharmony_ci */ 15118c2ecf20Sopenharmony_civoid hdmi_infoframe_log(const char *level, 15128c2ecf20Sopenharmony_ci struct device *dev, 15138c2ecf20Sopenharmony_ci const union hdmi_infoframe *frame) 15148c2ecf20Sopenharmony_ci{ 15158c2ecf20Sopenharmony_ci switch (frame->any.type) { 15168c2ecf20Sopenharmony_ci case HDMI_INFOFRAME_TYPE_AVI: 15178c2ecf20Sopenharmony_ci hdmi_avi_infoframe_log(level, dev, &frame->avi); 15188c2ecf20Sopenharmony_ci break; 15198c2ecf20Sopenharmony_ci case HDMI_INFOFRAME_TYPE_SPD: 15208c2ecf20Sopenharmony_ci hdmi_spd_infoframe_log(level, dev, &frame->spd); 15218c2ecf20Sopenharmony_ci break; 15228c2ecf20Sopenharmony_ci case HDMI_INFOFRAME_TYPE_AUDIO: 15238c2ecf20Sopenharmony_ci hdmi_audio_infoframe_log(level, dev, &frame->audio); 15248c2ecf20Sopenharmony_ci break; 15258c2ecf20Sopenharmony_ci case HDMI_INFOFRAME_TYPE_VENDOR: 15268c2ecf20Sopenharmony_ci hdmi_vendor_any_infoframe_log(level, dev, &frame->vendor); 15278c2ecf20Sopenharmony_ci break; 15288c2ecf20Sopenharmony_ci case HDMI_INFOFRAME_TYPE_DRM: 15298c2ecf20Sopenharmony_ci hdmi_drm_infoframe_log(level, dev, &frame->drm); 15308c2ecf20Sopenharmony_ci break; 15318c2ecf20Sopenharmony_ci } 15328c2ecf20Sopenharmony_ci} 15338c2ecf20Sopenharmony_ciEXPORT_SYMBOL(hdmi_infoframe_log); 15348c2ecf20Sopenharmony_ci 15358c2ecf20Sopenharmony_ci/** 15368c2ecf20Sopenharmony_ci * hdmi_avi_infoframe_unpack() - unpack binary buffer to a HDMI AVI infoframe 15378c2ecf20Sopenharmony_ci * @frame: HDMI AVI infoframe 15388c2ecf20Sopenharmony_ci * @buffer: source buffer 15398c2ecf20Sopenharmony_ci * @size: size of buffer 15408c2ecf20Sopenharmony_ci * 15418c2ecf20Sopenharmony_ci * Unpacks the information contained in binary @buffer into a structured 15428c2ecf20Sopenharmony_ci * @frame of the HDMI Auxiliary Video (AVI) information frame. 15438c2ecf20Sopenharmony_ci * Also verifies the checksum as required by section 5.3.5 of the HDMI 1.4 15448c2ecf20Sopenharmony_ci * specification. 15458c2ecf20Sopenharmony_ci * 15468c2ecf20Sopenharmony_ci * Returns 0 on success or a negative error code on failure. 15478c2ecf20Sopenharmony_ci */ 15488c2ecf20Sopenharmony_cistatic int hdmi_avi_infoframe_unpack(struct hdmi_avi_infoframe *frame, 15498c2ecf20Sopenharmony_ci const void *buffer, size_t size) 15508c2ecf20Sopenharmony_ci{ 15518c2ecf20Sopenharmony_ci const u8 *ptr = buffer; 15528c2ecf20Sopenharmony_ci 15538c2ecf20Sopenharmony_ci if (size < HDMI_INFOFRAME_SIZE(AVI)) 15548c2ecf20Sopenharmony_ci return -EINVAL; 15558c2ecf20Sopenharmony_ci 15568c2ecf20Sopenharmony_ci if (ptr[0] != HDMI_INFOFRAME_TYPE_AVI || 15578c2ecf20Sopenharmony_ci ptr[1] != 2 || 15588c2ecf20Sopenharmony_ci ptr[2] != HDMI_AVI_INFOFRAME_SIZE) 15598c2ecf20Sopenharmony_ci return -EINVAL; 15608c2ecf20Sopenharmony_ci 15618c2ecf20Sopenharmony_ci if (hdmi_infoframe_checksum(buffer, HDMI_INFOFRAME_SIZE(AVI)) != 0) 15628c2ecf20Sopenharmony_ci return -EINVAL; 15638c2ecf20Sopenharmony_ci 15648c2ecf20Sopenharmony_ci hdmi_avi_infoframe_init(frame); 15658c2ecf20Sopenharmony_ci 15668c2ecf20Sopenharmony_ci ptr += HDMI_INFOFRAME_HEADER_SIZE; 15678c2ecf20Sopenharmony_ci 15688c2ecf20Sopenharmony_ci frame->colorspace = (ptr[0] >> 5) & 0x3; 15698c2ecf20Sopenharmony_ci if (ptr[0] & 0x10) 15708c2ecf20Sopenharmony_ci frame->active_aspect = ptr[1] & 0xf; 15718c2ecf20Sopenharmony_ci if (ptr[0] & 0x8) { 15728c2ecf20Sopenharmony_ci frame->top_bar = (ptr[6] << 8) | ptr[5]; 15738c2ecf20Sopenharmony_ci frame->bottom_bar = (ptr[8] << 8) | ptr[7]; 15748c2ecf20Sopenharmony_ci } 15758c2ecf20Sopenharmony_ci if (ptr[0] & 0x4) { 15768c2ecf20Sopenharmony_ci frame->left_bar = (ptr[10] << 8) | ptr[9]; 15778c2ecf20Sopenharmony_ci frame->right_bar = (ptr[12] << 8) | ptr[11]; 15788c2ecf20Sopenharmony_ci } 15798c2ecf20Sopenharmony_ci frame->scan_mode = ptr[0] & 0x3; 15808c2ecf20Sopenharmony_ci 15818c2ecf20Sopenharmony_ci frame->colorimetry = (ptr[1] >> 6) & 0x3; 15828c2ecf20Sopenharmony_ci frame->picture_aspect = (ptr[1] >> 4) & 0x3; 15838c2ecf20Sopenharmony_ci frame->active_aspect = ptr[1] & 0xf; 15848c2ecf20Sopenharmony_ci 15858c2ecf20Sopenharmony_ci frame->itc = ptr[2] & 0x80 ? true : false; 15868c2ecf20Sopenharmony_ci frame->extended_colorimetry = (ptr[2] >> 4) & 0x7; 15878c2ecf20Sopenharmony_ci frame->quantization_range = (ptr[2] >> 2) & 0x3; 15888c2ecf20Sopenharmony_ci frame->nups = ptr[2] & 0x3; 15898c2ecf20Sopenharmony_ci 15908c2ecf20Sopenharmony_ci frame->video_code = ptr[3] & 0x7f; 15918c2ecf20Sopenharmony_ci frame->ycc_quantization_range = (ptr[4] >> 6) & 0x3; 15928c2ecf20Sopenharmony_ci frame->content_type = (ptr[4] >> 4) & 0x3; 15938c2ecf20Sopenharmony_ci 15948c2ecf20Sopenharmony_ci frame->pixel_repeat = ptr[4] & 0xf; 15958c2ecf20Sopenharmony_ci 15968c2ecf20Sopenharmony_ci return 0; 15978c2ecf20Sopenharmony_ci} 15988c2ecf20Sopenharmony_ci 15998c2ecf20Sopenharmony_ci/** 16008c2ecf20Sopenharmony_ci * hdmi_spd_infoframe_unpack() - unpack binary buffer to a HDMI SPD infoframe 16018c2ecf20Sopenharmony_ci * @frame: HDMI SPD infoframe 16028c2ecf20Sopenharmony_ci * @buffer: source buffer 16038c2ecf20Sopenharmony_ci * @size: size of buffer 16048c2ecf20Sopenharmony_ci * 16058c2ecf20Sopenharmony_ci * Unpacks the information contained in binary @buffer into a structured 16068c2ecf20Sopenharmony_ci * @frame of the HDMI Source Product Description (SPD) information frame. 16078c2ecf20Sopenharmony_ci * Also verifies the checksum as required by section 5.3.5 of the HDMI 1.4 16088c2ecf20Sopenharmony_ci * specification. 16098c2ecf20Sopenharmony_ci * 16108c2ecf20Sopenharmony_ci * Returns 0 on success or a negative error code on failure. 16118c2ecf20Sopenharmony_ci */ 16128c2ecf20Sopenharmony_cistatic int hdmi_spd_infoframe_unpack(struct hdmi_spd_infoframe *frame, 16138c2ecf20Sopenharmony_ci const void *buffer, size_t size) 16148c2ecf20Sopenharmony_ci{ 16158c2ecf20Sopenharmony_ci const u8 *ptr = buffer; 16168c2ecf20Sopenharmony_ci int ret; 16178c2ecf20Sopenharmony_ci 16188c2ecf20Sopenharmony_ci if (size < HDMI_INFOFRAME_SIZE(SPD)) 16198c2ecf20Sopenharmony_ci return -EINVAL; 16208c2ecf20Sopenharmony_ci 16218c2ecf20Sopenharmony_ci if (ptr[0] != HDMI_INFOFRAME_TYPE_SPD || 16228c2ecf20Sopenharmony_ci ptr[1] != 1 || 16238c2ecf20Sopenharmony_ci ptr[2] != HDMI_SPD_INFOFRAME_SIZE) { 16248c2ecf20Sopenharmony_ci return -EINVAL; 16258c2ecf20Sopenharmony_ci } 16268c2ecf20Sopenharmony_ci 16278c2ecf20Sopenharmony_ci if (hdmi_infoframe_checksum(buffer, HDMI_INFOFRAME_SIZE(SPD)) != 0) 16288c2ecf20Sopenharmony_ci return -EINVAL; 16298c2ecf20Sopenharmony_ci 16308c2ecf20Sopenharmony_ci ptr += HDMI_INFOFRAME_HEADER_SIZE; 16318c2ecf20Sopenharmony_ci 16328c2ecf20Sopenharmony_ci ret = hdmi_spd_infoframe_init(frame, ptr, ptr + 8); 16338c2ecf20Sopenharmony_ci if (ret) 16348c2ecf20Sopenharmony_ci return ret; 16358c2ecf20Sopenharmony_ci 16368c2ecf20Sopenharmony_ci frame->sdi = ptr[24]; 16378c2ecf20Sopenharmony_ci 16388c2ecf20Sopenharmony_ci return 0; 16398c2ecf20Sopenharmony_ci} 16408c2ecf20Sopenharmony_ci 16418c2ecf20Sopenharmony_ci/** 16428c2ecf20Sopenharmony_ci * hdmi_audio_infoframe_unpack() - unpack binary buffer to a HDMI AUDIO infoframe 16438c2ecf20Sopenharmony_ci * @frame: HDMI Audio infoframe 16448c2ecf20Sopenharmony_ci * @buffer: source buffer 16458c2ecf20Sopenharmony_ci * @size: size of buffer 16468c2ecf20Sopenharmony_ci * 16478c2ecf20Sopenharmony_ci * Unpacks the information contained in binary @buffer into a structured 16488c2ecf20Sopenharmony_ci * @frame of the HDMI Audio information frame. 16498c2ecf20Sopenharmony_ci * Also verifies the checksum as required by section 5.3.5 of the HDMI 1.4 16508c2ecf20Sopenharmony_ci * specification. 16518c2ecf20Sopenharmony_ci * 16528c2ecf20Sopenharmony_ci * Returns 0 on success or a negative error code on failure. 16538c2ecf20Sopenharmony_ci */ 16548c2ecf20Sopenharmony_cistatic int hdmi_audio_infoframe_unpack(struct hdmi_audio_infoframe *frame, 16558c2ecf20Sopenharmony_ci const void *buffer, size_t size) 16568c2ecf20Sopenharmony_ci{ 16578c2ecf20Sopenharmony_ci const u8 *ptr = buffer; 16588c2ecf20Sopenharmony_ci int ret; 16598c2ecf20Sopenharmony_ci 16608c2ecf20Sopenharmony_ci if (size < HDMI_INFOFRAME_SIZE(AUDIO)) 16618c2ecf20Sopenharmony_ci return -EINVAL; 16628c2ecf20Sopenharmony_ci 16638c2ecf20Sopenharmony_ci if (ptr[0] != HDMI_INFOFRAME_TYPE_AUDIO || 16648c2ecf20Sopenharmony_ci ptr[1] != 1 || 16658c2ecf20Sopenharmony_ci ptr[2] != HDMI_AUDIO_INFOFRAME_SIZE) { 16668c2ecf20Sopenharmony_ci return -EINVAL; 16678c2ecf20Sopenharmony_ci } 16688c2ecf20Sopenharmony_ci 16698c2ecf20Sopenharmony_ci if (hdmi_infoframe_checksum(buffer, HDMI_INFOFRAME_SIZE(AUDIO)) != 0) 16708c2ecf20Sopenharmony_ci return -EINVAL; 16718c2ecf20Sopenharmony_ci 16728c2ecf20Sopenharmony_ci ret = hdmi_audio_infoframe_init(frame); 16738c2ecf20Sopenharmony_ci if (ret) 16748c2ecf20Sopenharmony_ci return ret; 16758c2ecf20Sopenharmony_ci 16768c2ecf20Sopenharmony_ci ptr += HDMI_INFOFRAME_HEADER_SIZE; 16778c2ecf20Sopenharmony_ci 16788c2ecf20Sopenharmony_ci frame->channels = ptr[0] & 0x7; 16798c2ecf20Sopenharmony_ci frame->coding_type = (ptr[0] >> 4) & 0xf; 16808c2ecf20Sopenharmony_ci frame->sample_size = ptr[1] & 0x3; 16818c2ecf20Sopenharmony_ci frame->sample_frequency = (ptr[1] >> 2) & 0x7; 16828c2ecf20Sopenharmony_ci frame->coding_type_ext = ptr[2] & 0x1f; 16838c2ecf20Sopenharmony_ci frame->channel_allocation = ptr[3]; 16848c2ecf20Sopenharmony_ci frame->level_shift_value = (ptr[4] >> 3) & 0xf; 16858c2ecf20Sopenharmony_ci frame->downmix_inhibit = ptr[4] & 0x80 ? true : false; 16868c2ecf20Sopenharmony_ci 16878c2ecf20Sopenharmony_ci return 0; 16888c2ecf20Sopenharmony_ci} 16898c2ecf20Sopenharmony_ci 16908c2ecf20Sopenharmony_ci/** 16918c2ecf20Sopenharmony_ci * hdmi_vendor_infoframe_unpack() - unpack binary buffer to a HDMI vendor infoframe 16928c2ecf20Sopenharmony_ci * @frame: HDMI Vendor infoframe 16938c2ecf20Sopenharmony_ci * @buffer: source buffer 16948c2ecf20Sopenharmony_ci * @size: size of buffer 16958c2ecf20Sopenharmony_ci * 16968c2ecf20Sopenharmony_ci * Unpacks the information contained in binary @buffer into a structured 16978c2ecf20Sopenharmony_ci * @frame of the HDMI Vendor information frame. 16988c2ecf20Sopenharmony_ci * Also verifies the checksum as required by section 5.3.5 of the HDMI 1.4 16998c2ecf20Sopenharmony_ci * specification. 17008c2ecf20Sopenharmony_ci * 17018c2ecf20Sopenharmony_ci * Returns 0 on success or a negative error code on failure. 17028c2ecf20Sopenharmony_ci */ 17038c2ecf20Sopenharmony_cistatic int 17048c2ecf20Sopenharmony_cihdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame, 17058c2ecf20Sopenharmony_ci const void *buffer, size_t size) 17068c2ecf20Sopenharmony_ci{ 17078c2ecf20Sopenharmony_ci const u8 *ptr = buffer; 17088c2ecf20Sopenharmony_ci size_t length; 17098c2ecf20Sopenharmony_ci int ret; 17108c2ecf20Sopenharmony_ci u8 hdmi_video_format; 17118c2ecf20Sopenharmony_ci struct hdmi_vendor_infoframe *hvf = &frame->hdmi; 17128c2ecf20Sopenharmony_ci 17138c2ecf20Sopenharmony_ci if (size < HDMI_INFOFRAME_HEADER_SIZE) 17148c2ecf20Sopenharmony_ci return -EINVAL; 17158c2ecf20Sopenharmony_ci 17168c2ecf20Sopenharmony_ci if (ptr[0] != HDMI_INFOFRAME_TYPE_VENDOR || 17178c2ecf20Sopenharmony_ci ptr[1] != 1 || 17188c2ecf20Sopenharmony_ci (ptr[2] != 4 && ptr[2] != 5 && ptr[2] != 6)) 17198c2ecf20Sopenharmony_ci return -EINVAL; 17208c2ecf20Sopenharmony_ci 17218c2ecf20Sopenharmony_ci length = ptr[2]; 17228c2ecf20Sopenharmony_ci 17238c2ecf20Sopenharmony_ci if (size < HDMI_INFOFRAME_HEADER_SIZE + length) 17248c2ecf20Sopenharmony_ci return -EINVAL; 17258c2ecf20Sopenharmony_ci 17268c2ecf20Sopenharmony_ci if (hdmi_infoframe_checksum(buffer, 17278c2ecf20Sopenharmony_ci HDMI_INFOFRAME_HEADER_SIZE + length) != 0) 17288c2ecf20Sopenharmony_ci return -EINVAL; 17298c2ecf20Sopenharmony_ci 17308c2ecf20Sopenharmony_ci ptr += HDMI_INFOFRAME_HEADER_SIZE; 17318c2ecf20Sopenharmony_ci 17328c2ecf20Sopenharmony_ci /* HDMI OUI */ 17338c2ecf20Sopenharmony_ci if ((ptr[0] != 0x03) || 17348c2ecf20Sopenharmony_ci (ptr[1] != 0x0c) || 17358c2ecf20Sopenharmony_ci (ptr[2] != 0x00)) 17368c2ecf20Sopenharmony_ci return -EINVAL; 17378c2ecf20Sopenharmony_ci 17388c2ecf20Sopenharmony_ci hdmi_video_format = ptr[3] >> 5; 17398c2ecf20Sopenharmony_ci 17408c2ecf20Sopenharmony_ci if (hdmi_video_format > 0x2) 17418c2ecf20Sopenharmony_ci return -EINVAL; 17428c2ecf20Sopenharmony_ci 17438c2ecf20Sopenharmony_ci ret = hdmi_vendor_infoframe_init(hvf); 17448c2ecf20Sopenharmony_ci if (ret) 17458c2ecf20Sopenharmony_ci return ret; 17468c2ecf20Sopenharmony_ci 17478c2ecf20Sopenharmony_ci hvf->length = length; 17488c2ecf20Sopenharmony_ci 17498c2ecf20Sopenharmony_ci if (hdmi_video_format == 0x2) { 17508c2ecf20Sopenharmony_ci if (length != 5 && length != 6) 17518c2ecf20Sopenharmony_ci return -EINVAL; 17528c2ecf20Sopenharmony_ci hvf->s3d_struct = ptr[4] >> 4; 17538c2ecf20Sopenharmony_ci if (hvf->s3d_struct >= HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF) { 17548c2ecf20Sopenharmony_ci if (length != 6) 17558c2ecf20Sopenharmony_ci return -EINVAL; 17568c2ecf20Sopenharmony_ci hvf->s3d_ext_data = ptr[5] >> 4; 17578c2ecf20Sopenharmony_ci } 17588c2ecf20Sopenharmony_ci } else if (hdmi_video_format == 0x1) { 17598c2ecf20Sopenharmony_ci if (length != 5) 17608c2ecf20Sopenharmony_ci return -EINVAL; 17618c2ecf20Sopenharmony_ci hvf->vic = ptr[4]; 17628c2ecf20Sopenharmony_ci } else { 17638c2ecf20Sopenharmony_ci if (length != 4) 17648c2ecf20Sopenharmony_ci return -EINVAL; 17658c2ecf20Sopenharmony_ci } 17668c2ecf20Sopenharmony_ci 17678c2ecf20Sopenharmony_ci return 0; 17688c2ecf20Sopenharmony_ci} 17698c2ecf20Sopenharmony_ci 17708c2ecf20Sopenharmony_ci/** 17718c2ecf20Sopenharmony_ci * hdmi_drm_infoframe_unpack_only() - unpack binary buffer of CTA-861-G DRM 17728c2ecf20Sopenharmony_ci * infoframe DataBytes to a HDMI DRM 17738c2ecf20Sopenharmony_ci * infoframe 17748c2ecf20Sopenharmony_ci * @frame: HDMI DRM infoframe 17758c2ecf20Sopenharmony_ci * @buffer: source buffer 17768c2ecf20Sopenharmony_ci * @size: size of buffer 17778c2ecf20Sopenharmony_ci * 17788c2ecf20Sopenharmony_ci * Unpacks CTA-861-G DRM infoframe DataBytes contained in the binary @buffer 17798c2ecf20Sopenharmony_ci * into a structured @frame of the HDMI Dynamic Range and Mastering (DRM) 17808c2ecf20Sopenharmony_ci * infoframe. 17818c2ecf20Sopenharmony_ci * 17828c2ecf20Sopenharmony_ci * Returns 0 on success or a negative error code on failure. 17838c2ecf20Sopenharmony_ci */ 17848c2ecf20Sopenharmony_ciint hdmi_drm_infoframe_unpack_only(struct hdmi_drm_infoframe *frame, 17858c2ecf20Sopenharmony_ci const void *buffer, size_t size) 17868c2ecf20Sopenharmony_ci{ 17878c2ecf20Sopenharmony_ci const u8 *ptr = buffer; 17888c2ecf20Sopenharmony_ci const u8 *temp; 17898c2ecf20Sopenharmony_ci u8 x_lsb, x_msb; 17908c2ecf20Sopenharmony_ci u8 y_lsb, y_msb; 17918c2ecf20Sopenharmony_ci int ret; 17928c2ecf20Sopenharmony_ci int i; 17938c2ecf20Sopenharmony_ci 17948c2ecf20Sopenharmony_ci if (size < HDMI_DRM_INFOFRAME_SIZE) 17958c2ecf20Sopenharmony_ci return -EINVAL; 17968c2ecf20Sopenharmony_ci 17978c2ecf20Sopenharmony_ci ret = hdmi_drm_infoframe_init(frame); 17988c2ecf20Sopenharmony_ci if (ret) 17998c2ecf20Sopenharmony_ci return ret; 18008c2ecf20Sopenharmony_ci 18018c2ecf20Sopenharmony_ci frame->eotf = ptr[0] & 0x7; 18028c2ecf20Sopenharmony_ci frame->metadata_type = ptr[1] & 0x7; 18038c2ecf20Sopenharmony_ci 18048c2ecf20Sopenharmony_ci temp = ptr + 2; 18058c2ecf20Sopenharmony_ci for (i = 0; i < 3; i++) { 18068c2ecf20Sopenharmony_ci x_lsb = *temp++; 18078c2ecf20Sopenharmony_ci x_msb = *temp++; 18088c2ecf20Sopenharmony_ci frame->display_primaries[i].x = (x_msb << 8) | x_lsb; 18098c2ecf20Sopenharmony_ci y_lsb = *temp++; 18108c2ecf20Sopenharmony_ci y_msb = *temp++; 18118c2ecf20Sopenharmony_ci frame->display_primaries[i].y = (y_msb << 8) | y_lsb; 18128c2ecf20Sopenharmony_ci } 18138c2ecf20Sopenharmony_ci 18148c2ecf20Sopenharmony_ci frame->white_point.x = (ptr[15] << 8) | ptr[14]; 18158c2ecf20Sopenharmony_ci frame->white_point.y = (ptr[17] << 8) | ptr[16]; 18168c2ecf20Sopenharmony_ci 18178c2ecf20Sopenharmony_ci frame->max_display_mastering_luminance = (ptr[19] << 8) | ptr[18]; 18188c2ecf20Sopenharmony_ci frame->min_display_mastering_luminance = (ptr[21] << 8) | ptr[20]; 18198c2ecf20Sopenharmony_ci frame->max_cll = (ptr[23] << 8) | ptr[22]; 18208c2ecf20Sopenharmony_ci frame->max_fall = (ptr[25] << 8) | ptr[24]; 18218c2ecf20Sopenharmony_ci 18228c2ecf20Sopenharmony_ci return 0; 18238c2ecf20Sopenharmony_ci} 18248c2ecf20Sopenharmony_ciEXPORT_SYMBOL(hdmi_drm_infoframe_unpack_only); 18258c2ecf20Sopenharmony_ci 18268c2ecf20Sopenharmony_ci/** 18278c2ecf20Sopenharmony_ci * hdmi_drm_infoframe_unpack() - unpack binary buffer to a HDMI DRM infoframe 18288c2ecf20Sopenharmony_ci * @frame: HDMI DRM infoframe 18298c2ecf20Sopenharmony_ci * @buffer: source buffer 18308c2ecf20Sopenharmony_ci * @size: size of buffer 18318c2ecf20Sopenharmony_ci * 18328c2ecf20Sopenharmony_ci * Unpacks the CTA-861-G DRM infoframe contained in the binary @buffer into 18338c2ecf20Sopenharmony_ci * a structured @frame of the HDMI Dynamic Range and Mastering (DRM) 18348c2ecf20Sopenharmony_ci * infoframe. It also verifies the checksum as required by section 5.3.5 of 18358c2ecf20Sopenharmony_ci * the HDMI 1.4 specification. 18368c2ecf20Sopenharmony_ci * 18378c2ecf20Sopenharmony_ci * Returns 0 on success or a negative error code on failure. 18388c2ecf20Sopenharmony_ci */ 18398c2ecf20Sopenharmony_cistatic int hdmi_drm_infoframe_unpack(struct hdmi_drm_infoframe *frame, 18408c2ecf20Sopenharmony_ci const void *buffer, size_t size) 18418c2ecf20Sopenharmony_ci{ 18428c2ecf20Sopenharmony_ci const u8 *ptr = buffer; 18438c2ecf20Sopenharmony_ci int ret; 18448c2ecf20Sopenharmony_ci 18458c2ecf20Sopenharmony_ci if (size < HDMI_INFOFRAME_SIZE(DRM)) 18468c2ecf20Sopenharmony_ci return -EINVAL; 18478c2ecf20Sopenharmony_ci 18488c2ecf20Sopenharmony_ci if (ptr[0] != HDMI_INFOFRAME_TYPE_DRM || 18498c2ecf20Sopenharmony_ci ptr[1] != 1 || 18508c2ecf20Sopenharmony_ci ptr[2] != HDMI_DRM_INFOFRAME_SIZE) 18518c2ecf20Sopenharmony_ci return -EINVAL; 18528c2ecf20Sopenharmony_ci 18538c2ecf20Sopenharmony_ci if (hdmi_infoframe_checksum(buffer, HDMI_INFOFRAME_SIZE(DRM)) != 0) 18548c2ecf20Sopenharmony_ci return -EINVAL; 18558c2ecf20Sopenharmony_ci 18568c2ecf20Sopenharmony_ci ret = hdmi_drm_infoframe_unpack_only(frame, ptr + HDMI_INFOFRAME_HEADER_SIZE, 18578c2ecf20Sopenharmony_ci size - HDMI_INFOFRAME_HEADER_SIZE); 18588c2ecf20Sopenharmony_ci return ret; 18598c2ecf20Sopenharmony_ci} 18608c2ecf20Sopenharmony_ci 18618c2ecf20Sopenharmony_ci/** 18628c2ecf20Sopenharmony_ci * hdmi_infoframe_unpack() - unpack binary buffer to a HDMI infoframe 18638c2ecf20Sopenharmony_ci * @frame: HDMI infoframe 18648c2ecf20Sopenharmony_ci * @buffer: source buffer 18658c2ecf20Sopenharmony_ci * @size: size of buffer 18668c2ecf20Sopenharmony_ci * 18678c2ecf20Sopenharmony_ci * Unpacks the information contained in binary buffer @buffer into a structured 18688c2ecf20Sopenharmony_ci * @frame of a HDMI infoframe. 18698c2ecf20Sopenharmony_ci * Also verifies the checksum as required by section 5.3.5 of the HDMI 1.4 18708c2ecf20Sopenharmony_ci * specification. 18718c2ecf20Sopenharmony_ci * 18728c2ecf20Sopenharmony_ci * Returns 0 on success or a negative error code on failure. 18738c2ecf20Sopenharmony_ci */ 18748c2ecf20Sopenharmony_ciint hdmi_infoframe_unpack(union hdmi_infoframe *frame, 18758c2ecf20Sopenharmony_ci const void *buffer, size_t size) 18768c2ecf20Sopenharmony_ci{ 18778c2ecf20Sopenharmony_ci int ret; 18788c2ecf20Sopenharmony_ci const u8 *ptr = buffer; 18798c2ecf20Sopenharmony_ci 18808c2ecf20Sopenharmony_ci if (size < HDMI_INFOFRAME_HEADER_SIZE) 18818c2ecf20Sopenharmony_ci return -EINVAL; 18828c2ecf20Sopenharmony_ci 18838c2ecf20Sopenharmony_ci switch (ptr[0]) { 18848c2ecf20Sopenharmony_ci case HDMI_INFOFRAME_TYPE_AVI: 18858c2ecf20Sopenharmony_ci ret = hdmi_avi_infoframe_unpack(&frame->avi, buffer, size); 18868c2ecf20Sopenharmony_ci break; 18878c2ecf20Sopenharmony_ci case HDMI_INFOFRAME_TYPE_DRM: 18888c2ecf20Sopenharmony_ci ret = hdmi_drm_infoframe_unpack(&frame->drm, buffer, size); 18898c2ecf20Sopenharmony_ci break; 18908c2ecf20Sopenharmony_ci case HDMI_INFOFRAME_TYPE_SPD: 18918c2ecf20Sopenharmony_ci ret = hdmi_spd_infoframe_unpack(&frame->spd, buffer, size); 18928c2ecf20Sopenharmony_ci break; 18938c2ecf20Sopenharmony_ci case HDMI_INFOFRAME_TYPE_AUDIO: 18948c2ecf20Sopenharmony_ci ret = hdmi_audio_infoframe_unpack(&frame->audio, buffer, size); 18958c2ecf20Sopenharmony_ci break; 18968c2ecf20Sopenharmony_ci case HDMI_INFOFRAME_TYPE_VENDOR: 18978c2ecf20Sopenharmony_ci ret = hdmi_vendor_any_infoframe_unpack(&frame->vendor, buffer, size); 18988c2ecf20Sopenharmony_ci break; 18998c2ecf20Sopenharmony_ci default: 19008c2ecf20Sopenharmony_ci ret = -EINVAL; 19018c2ecf20Sopenharmony_ci break; 19028c2ecf20Sopenharmony_ci } 19038c2ecf20Sopenharmony_ci 19048c2ecf20Sopenharmony_ci return ret; 19058c2ecf20Sopenharmony_ci} 19068c2ecf20Sopenharmony_ciEXPORT_SYMBOL(hdmi_infoframe_unpack); 1907