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