xref: /dflybsd-src/sys/dev/drm/linux_hdmi.c (revision 3f2dd94a569761201b5b0a18b2f697f97fe1b9dc)
128ba7809SMichael Neumann /*
228ba7809SMichael Neumann  * Copyright (C) 2012 Avionic Design GmbH
328ba7809SMichael Neumann  *
428ba7809SMichael Neumann  * Permission is hereby granted, free of charge, to any person obtaining a
528ba7809SMichael Neumann  * copy of this software and associated documentation files (the "Software"),
628ba7809SMichael Neumann  * to deal in the Software without restriction, including without limitation
728ba7809SMichael Neumann  * the rights to use, copy, modify, merge, publish, distribute, sub license,
828ba7809SMichael Neumann  * and/or sell copies of the Software, and to permit persons to whom the
928ba7809SMichael Neumann  * Software is furnished to do so, subject to the following conditions:
1028ba7809SMichael Neumann  *
1128ba7809SMichael Neumann  * The above copyright notice and this permission notice (including the
1228ba7809SMichael Neumann  * next paragraph) shall be included in all copies or substantial portions
1328ba7809SMichael Neumann  * of the Software.
1428ba7809SMichael Neumann  *
1528ba7809SMichael Neumann  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1628ba7809SMichael Neumann  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1728ba7809SMichael Neumann  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
1828ba7809SMichael Neumann  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1928ba7809SMichael Neumann  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
2028ba7809SMichael Neumann  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
2128ba7809SMichael Neumann  * DEALINGS IN THE SOFTWARE.
2228ba7809SMichael Neumann  */
2328ba7809SMichael Neumann 
2428ba7809SMichael Neumann #include <linux/bitops.h>
2528ba7809SMichael Neumann #include <linux/bug.h>
2628ba7809SMichael Neumann #include <linux/errno.h>
2728ba7809SMichael Neumann #include <linux/export.h>
2828ba7809SMichael Neumann #include <linux/hdmi.h>
29*3f2dd94aSFrançois Tigeot #include <linux/string.h>
3028ba7809SMichael Neumann #include <linux/device.h>
3128ba7809SMichael Neumann 
3228ba7809SMichael Neumann #define hdmi_log(fmt, ...) dev_printk(level, dev, fmt, ##__VA_ARGS__)
3328ba7809SMichael Neumann 
hdmi_infoframe_checksum(u8 * ptr,size_t size)3428ba7809SMichael Neumann static u8 hdmi_infoframe_checksum(u8 *ptr, size_t size)
3528ba7809SMichael Neumann {
3628ba7809SMichael Neumann 	u8 csum = 0;
3728ba7809SMichael Neumann 	size_t i;
3828ba7809SMichael Neumann 
3928ba7809SMichael Neumann 	/* compute checksum */
4028ba7809SMichael Neumann 	for (i = 0; i < size; i++)
4128ba7809SMichael Neumann 		csum += ptr[i];
4228ba7809SMichael Neumann 
4328ba7809SMichael Neumann 	return 256 - csum;
4428ba7809SMichael Neumann }
4528ba7809SMichael Neumann 
hdmi_infoframe_set_checksum(void * buffer,size_t size)4628ba7809SMichael Neumann static void hdmi_infoframe_set_checksum(void *buffer, size_t size)
4728ba7809SMichael Neumann {
4828ba7809SMichael Neumann 	u8 *ptr = buffer;
4928ba7809SMichael Neumann 
5028ba7809SMichael Neumann 	ptr[3] = hdmi_infoframe_checksum(buffer, size);
5128ba7809SMichael Neumann }
5228ba7809SMichael Neumann 
5328ba7809SMichael Neumann /**
5428ba7809SMichael Neumann  * hdmi_avi_infoframe_init() - initialize an HDMI AVI infoframe
5528ba7809SMichael Neumann  * @frame: HDMI AVI infoframe
5628ba7809SMichael Neumann  *
5728ba7809SMichael Neumann  * Returns 0 on success or a negative error code on failure.
5828ba7809SMichael Neumann  */
hdmi_avi_infoframe_init(struct hdmi_avi_infoframe * frame)5928ba7809SMichael Neumann int hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame)
6028ba7809SMichael Neumann {
6128ba7809SMichael Neumann 	memset(frame, 0, sizeof(*frame));
6228ba7809SMichael Neumann 
6328ba7809SMichael Neumann 	frame->type = HDMI_INFOFRAME_TYPE_AVI;
6428ba7809SMichael Neumann 	frame->version = 2;
6528ba7809SMichael Neumann 	frame->length = HDMI_AVI_INFOFRAME_SIZE;
6628ba7809SMichael Neumann 
6728ba7809SMichael Neumann 	return 0;
6828ba7809SMichael Neumann }
6928ba7809SMichael Neumann EXPORT_SYMBOL(hdmi_avi_infoframe_init);
7028ba7809SMichael Neumann 
7128ba7809SMichael Neumann /**
7228ba7809SMichael Neumann  * hdmi_avi_infoframe_pack() - write HDMI AVI infoframe to binary buffer
7328ba7809SMichael Neumann  * @frame: HDMI AVI infoframe
7428ba7809SMichael Neumann  * @buffer: destination buffer
7528ba7809SMichael Neumann  * @size: size of buffer
7628ba7809SMichael Neumann  *
7728ba7809SMichael Neumann  * Packs the information contained in the @frame structure into a binary
7828ba7809SMichael Neumann  * representation that can be written into the corresponding controller
7928ba7809SMichael Neumann  * registers. Also computes the checksum as required by section 5.3.5 of
8028ba7809SMichael Neumann  * the HDMI 1.4 specification.
8128ba7809SMichael Neumann  *
8228ba7809SMichael Neumann  * Returns the number of bytes packed into the binary buffer or a negative
8328ba7809SMichael Neumann  * error code on failure.
8428ba7809SMichael Neumann  */
hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe * frame,void * buffer,size_t size)8528ba7809SMichael Neumann ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer,
8628ba7809SMichael Neumann 				size_t size)
8728ba7809SMichael Neumann {
8828ba7809SMichael Neumann 	u8 *ptr = buffer;
8928ba7809SMichael Neumann 	size_t length;
9028ba7809SMichael Neumann 
9128ba7809SMichael Neumann 	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
9228ba7809SMichael Neumann 
9328ba7809SMichael Neumann 	if (size < length)
9428ba7809SMichael Neumann 		return -ENOSPC;
9528ba7809SMichael Neumann 
9628ba7809SMichael Neumann 	memset(buffer, 0, size);
9728ba7809SMichael Neumann 
9828ba7809SMichael Neumann 	ptr[0] = frame->type;
9928ba7809SMichael Neumann 	ptr[1] = frame->version;
10028ba7809SMichael Neumann 	ptr[2] = frame->length;
10128ba7809SMichael Neumann 	ptr[3] = 0; /* checksum */
10228ba7809SMichael Neumann 
10328ba7809SMichael Neumann 	/* start infoframe payload */
10428ba7809SMichael Neumann 	ptr += HDMI_INFOFRAME_HEADER_SIZE;
10528ba7809SMichael Neumann 
10628ba7809SMichael Neumann 	ptr[0] = ((frame->colorspace & 0x3) << 5) | (frame->scan_mode & 0x3);
10728ba7809SMichael Neumann 
10828ba7809SMichael Neumann 	/*
10928ba7809SMichael Neumann 	 * Data byte 1, bit 4 has to be set if we provide the active format
11028ba7809SMichael Neumann 	 * aspect ratio
11128ba7809SMichael Neumann 	 */
11228ba7809SMichael Neumann 	if (frame->active_aspect & 0xf)
11328ba7809SMichael Neumann 		ptr[0] |= BIT(4);
11428ba7809SMichael Neumann 
11528ba7809SMichael Neumann 	/* Bit 3 and 2 indicate if we transmit horizontal/vertical bar data */
11628ba7809SMichael Neumann 	if (frame->top_bar || frame->bottom_bar)
11728ba7809SMichael Neumann 		ptr[0] |= BIT(3);
11828ba7809SMichael Neumann 
11928ba7809SMichael Neumann 	if (frame->left_bar || frame->right_bar)
12028ba7809SMichael Neumann 		ptr[0] |= BIT(2);
12128ba7809SMichael Neumann 
12228ba7809SMichael Neumann 	ptr[1] = ((frame->colorimetry & 0x3) << 6) |
12328ba7809SMichael Neumann 		 ((frame->picture_aspect & 0x3) << 4) |
12428ba7809SMichael Neumann 		 (frame->active_aspect & 0xf);
12528ba7809SMichael Neumann 
12628ba7809SMichael Neumann 	ptr[2] = ((frame->extended_colorimetry & 0x7) << 4) |
12728ba7809SMichael Neumann 		 ((frame->quantization_range & 0x3) << 2) |
12828ba7809SMichael Neumann 		 (frame->nups & 0x3);
12928ba7809SMichael Neumann 
13028ba7809SMichael Neumann 	if (frame->itc)
13128ba7809SMichael Neumann 		ptr[2] |= BIT(7);
13228ba7809SMichael Neumann 
13328ba7809SMichael Neumann 	ptr[3] = frame->video_code & 0x7f;
13428ba7809SMichael Neumann 
13528ba7809SMichael Neumann 	ptr[4] = ((frame->ycc_quantization_range & 0x3) << 6) |
13628ba7809SMichael Neumann 		 ((frame->content_type & 0x3) << 4) |
13728ba7809SMichael Neumann 		 (frame->pixel_repeat & 0xf);
13828ba7809SMichael Neumann 
13928ba7809SMichael Neumann 	ptr[5] = frame->top_bar & 0xff;
14028ba7809SMichael Neumann 	ptr[6] = (frame->top_bar >> 8) & 0xff;
14128ba7809SMichael Neumann 	ptr[7] = frame->bottom_bar & 0xff;
14228ba7809SMichael Neumann 	ptr[8] = (frame->bottom_bar >> 8) & 0xff;
14328ba7809SMichael Neumann 	ptr[9] = frame->left_bar & 0xff;
14428ba7809SMichael Neumann 	ptr[10] = (frame->left_bar >> 8) & 0xff;
14528ba7809SMichael Neumann 	ptr[11] = frame->right_bar & 0xff;
14628ba7809SMichael Neumann 	ptr[12] = (frame->right_bar >> 8) & 0xff;
14728ba7809SMichael Neumann 
14828ba7809SMichael Neumann 	hdmi_infoframe_set_checksum(buffer, length);
14928ba7809SMichael Neumann 
15028ba7809SMichael Neumann 	return length;
15128ba7809SMichael Neumann }
15228ba7809SMichael Neumann EXPORT_SYMBOL(hdmi_avi_infoframe_pack);
15328ba7809SMichael Neumann 
15428ba7809SMichael Neumann /**
15528ba7809SMichael Neumann  * hdmi_spd_infoframe_init() - initialize an HDMI SPD infoframe
15628ba7809SMichael Neumann  * @frame: HDMI SPD infoframe
15728ba7809SMichael Neumann  * @vendor: vendor string
15828ba7809SMichael Neumann  * @product: product string
15928ba7809SMichael Neumann  *
16028ba7809SMichael Neumann  * Returns 0 on success or a negative error code on failure.
16128ba7809SMichael Neumann  */
hdmi_spd_infoframe_init(struct hdmi_spd_infoframe * frame,const char * vendor,const char * product)16228ba7809SMichael Neumann int hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame,
16328ba7809SMichael Neumann 			    const char *vendor, const char *product)
16428ba7809SMichael Neumann {
16528ba7809SMichael Neumann 	memset(frame, 0, sizeof(*frame));
16628ba7809SMichael Neumann 
16728ba7809SMichael Neumann 	frame->type = HDMI_INFOFRAME_TYPE_SPD;
16828ba7809SMichael Neumann 	frame->version = 1;
16928ba7809SMichael Neumann 	frame->length = HDMI_SPD_INFOFRAME_SIZE;
17028ba7809SMichael Neumann 
17128ba7809SMichael Neumann 	strncpy(frame->vendor, vendor, sizeof(frame->vendor));
17228ba7809SMichael Neumann 	strncpy(frame->product, product, sizeof(frame->product));
17328ba7809SMichael Neumann 
17428ba7809SMichael Neumann 	return 0;
17528ba7809SMichael Neumann }
17628ba7809SMichael Neumann EXPORT_SYMBOL(hdmi_spd_infoframe_init);
17728ba7809SMichael Neumann 
17828ba7809SMichael Neumann /**
17928ba7809SMichael Neumann  * hdmi_spd_infoframe_pack() - write HDMI SPD infoframe to binary buffer
18028ba7809SMichael Neumann  * @frame: HDMI SPD infoframe
18128ba7809SMichael Neumann  * @buffer: destination buffer
18228ba7809SMichael Neumann  * @size: size of buffer
18328ba7809SMichael Neumann  *
18428ba7809SMichael Neumann  * Packs the information contained in the @frame structure into a binary
18528ba7809SMichael Neumann  * representation that can be written into the corresponding controller
18628ba7809SMichael Neumann  * registers. Also computes the checksum as required by section 5.3.5 of
18728ba7809SMichael Neumann  * the HDMI 1.4 specification.
18828ba7809SMichael Neumann  *
18928ba7809SMichael Neumann  * Returns the number of bytes packed into the binary buffer or a negative
19028ba7809SMichael Neumann  * error code on failure.
19128ba7809SMichael Neumann  */
hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe * frame,void * buffer,size_t size)19228ba7809SMichael Neumann ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
19328ba7809SMichael Neumann 				size_t size)
19428ba7809SMichael Neumann {
19528ba7809SMichael Neumann 	u8 *ptr = buffer;
19628ba7809SMichael Neumann 	size_t length;
19728ba7809SMichael Neumann 
19828ba7809SMichael Neumann 	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
19928ba7809SMichael Neumann 
20028ba7809SMichael Neumann 	if (size < length)
20128ba7809SMichael Neumann 		return -ENOSPC;
20228ba7809SMichael Neumann 
20328ba7809SMichael Neumann 	memset(buffer, 0, size);
20428ba7809SMichael Neumann 
20528ba7809SMichael Neumann 	ptr[0] = frame->type;
20628ba7809SMichael Neumann 	ptr[1] = frame->version;
20728ba7809SMichael Neumann 	ptr[2] = frame->length;
20828ba7809SMichael Neumann 	ptr[3] = 0; /* checksum */
20928ba7809SMichael Neumann 
21028ba7809SMichael Neumann 	/* start infoframe payload */
21128ba7809SMichael Neumann 	ptr += HDMI_INFOFRAME_HEADER_SIZE;
21228ba7809SMichael Neumann 
21328ba7809SMichael Neumann 	memcpy(ptr, frame->vendor, sizeof(frame->vendor));
21428ba7809SMichael Neumann 	memcpy(ptr + 8, frame->product, sizeof(frame->product));
21528ba7809SMichael Neumann 
21628ba7809SMichael Neumann 	ptr[24] = frame->sdi;
21728ba7809SMichael Neumann 
21828ba7809SMichael Neumann 	hdmi_infoframe_set_checksum(buffer, length);
21928ba7809SMichael Neumann 
22028ba7809SMichael Neumann 	return length;
22128ba7809SMichael Neumann }
22228ba7809SMichael Neumann EXPORT_SYMBOL(hdmi_spd_infoframe_pack);
22328ba7809SMichael Neumann 
22428ba7809SMichael Neumann /**
22528ba7809SMichael Neumann  * hdmi_audio_infoframe_init() - initialize an HDMI audio infoframe
22628ba7809SMichael Neumann  * @frame: HDMI audio infoframe
22728ba7809SMichael Neumann  *
22828ba7809SMichael Neumann  * Returns 0 on success or a negative error code on failure.
22928ba7809SMichael Neumann  */
hdmi_audio_infoframe_init(struct hdmi_audio_infoframe * frame)23028ba7809SMichael Neumann int hdmi_audio_infoframe_init(struct hdmi_audio_infoframe *frame)
23128ba7809SMichael Neumann {
23228ba7809SMichael Neumann 	memset(frame, 0, sizeof(*frame));
23328ba7809SMichael Neumann 
23428ba7809SMichael Neumann 	frame->type = HDMI_INFOFRAME_TYPE_AUDIO;
23528ba7809SMichael Neumann 	frame->version = 1;
23628ba7809SMichael Neumann 	frame->length = HDMI_AUDIO_INFOFRAME_SIZE;
23728ba7809SMichael Neumann 
23828ba7809SMichael Neumann 	return 0;
23928ba7809SMichael Neumann }
24028ba7809SMichael Neumann EXPORT_SYMBOL(hdmi_audio_infoframe_init);
24128ba7809SMichael Neumann 
24228ba7809SMichael Neumann /**
24328ba7809SMichael Neumann  * hdmi_audio_infoframe_pack() - write HDMI audio infoframe to binary buffer
24428ba7809SMichael Neumann  * @frame: HDMI audio infoframe
24528ba7809SMichael Neumann  * @buffer: destination buffer
24628ba7809SMichael Neumann  * @size: size of buffer
24728ba7809SMichael Neumann  *
24828ba7809SMichael Neumann  * Packs the information contained in the @frame structure into a binary
24928ba7809SMichael Neumann  * representation that can be written into the corresponding controller
25028ba7809SMichael Neumann  * registers. Also computes the checksum as required by section 5.3.5 of
25128ba7809SMichael Neumann  * the HDMI 1.4 specification.
25228ba7809SMichael Neumann  *
25328ba7809SMichael Neumann  * Returns the number of bytes packed into the binary buffer or a negative
25428ba7809SMichael Neumann  * error code on failure.
25528ba7809SMichael Neumann  */
hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe * frame,void * buffer,size_t size)25628ba7809SMichael Neumann ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
25728ba7809SMichael Neumann 				  void *buffer, size_t size)
25828ba7809SMichael Neumann {
25928ba7809SMichael Neumann 	unsigned char channels;
26028ba7809SMichael Neumann 	u8 *ptr = buffer;
26128ba7809SMichael Neumann 	size_t length;
26228ba7809SMichael Neumann 
26328ba7809SMichael Neumann 	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
26428ba7809SMichael Neumann 
26528ba7809SMichael Neumann 	if (size < length)
26628ba7809SMichael Neumann 		return -ENOSPC;
26728ba7809SMichael Neumann 
26828ba7809SMichael Neumann 	memset(buffer, 0, size);
26928ba7809SMichael Neumann 
27028ba7809SMichael Neumann 	if (frame->channels >= 2)
27128ba7809SMichael Neumann 		channels = frame->channels - 1;
27228ba7809SMichael Neumann 	else
27328ba7809SMichael Neumann 		channels = 0;
27428ba7809SMichael Neumann 
27528ba7809SMichael Neumann 	ptr[0] = frame->type;
27628ba7809SMichael Neumann 	ptr[1] = frame->version;
27728ba7809SMichael Neumann 	ptr[2] = frame->length;
27828ba7809SMichael Neumann 	ptr[3] = 0; /* checksum */
27928ba7809SMichael Neumann 
28028ba7809SMichael Neumann 	/* start infoframe payload */
28128ba7809SMichael Neumann 	ptr += HDMI_INFOFRAME_HEADER_SIZE;
28228ba7809SMichael Neumann 
28328ba7809SMichael Neumann 	ptr[0] = ((frame->coding_type & 0xf) << 4) | (channels & 0x7);
28428ba7809SMichael Neumann 	ptr[1] = ((frame->sample_frequency & 0x7) << 2) |
28528ba7809SMichael Neumann 		 (frame->sample_size & 0x3);
28628ba7809SMichael Neumann 	ptr[2] = frame->coding_type_ext & 0x1f;
28728ba7809SMichael Neumann 	ptr[3] = frame->channel_allocation;
28828ba7809SMichael Neumann 	ptr[4] = (frame->level_shift_value & 0xf) << 3;
28928ba7809SMichael Neumann 
29028ba7809SMichael Neumann 	if (frame->downmix_inhibit)
29128ba7809SMichael Neumann 		ptr[4] |= BIT(7);
29228ba7809SMichael Neumann 
29328ba7809SMichael Neumann 	hdmi_infoframe_set_checksum(buffer, length);
29428ba7809SMichael Neumann 
29528ba7809SMichael Neumann 	return length;
29628ba7809SMichael Neumann }
29728ba7809SMichael Neumann EXPORT_SYMBOL(hdmi_audio_infoframe_pack);
29828ba7809SMichael Neumann 
29928ba7809SMichael Neumann /**
30028ba7809SMichael Neumann  * hdmi_vendor_infoframe_init() - initialize an HDMI vendor infoframe
30128ba7809SMichael Neumann  * @frame: HDMI vendor infoframe
30228ba7809SMichael Neumann  *
30328ba7809SMichael Neumann  * Returns 0 on success or a negative error code on failure.
30428ba7809SMichael Neumann  */
hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe * frame)30528ba7809SMichael Neumann int hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame)
30628ba7809SMichael Neumann {
30728ba7809SMichael Neumann 	memset(frame, 0, sizeof(*frame));
30828ba7809SMichael Neumann 
30928ba7809SMichael Neumann 	frame->type = HDMI_INFOFRAME_TYPE_VENDOR;
31028ba7809SMichael Neumann 	frame->version = 1;
31128ba7809SMichael Neumann 
31228ba7809SMichael Neumann 	frame->oui = HDMI_IEEE_OUI;
31328ba7809SMichael Neumann 
31428ba7809SMichael Neumann 	/*
31528ba7809SMichael Neumann 	 * 0 is a valid value for s3d_struct, so we use a special "not set"
31628ba7809SMichael Neumann 	 * value
31728ba7809SMichael Neumann 	 */
31828ba7809SMichael Neumann 	frame->s3d_struct = HDMI_3D_STRUCTURE_INVALID;
31928ba7809SMichael Neumann 
32028ba7809SMichael Neumann 	return 0;
32128ba7809SMichael Neumann }
32228ba7809SMichael Neumann EXPORT_SYMBOL(hdmi_vendor_infoframe_init);
32328ba7809SMichael Neumann 
32428ba7809SMichael Neumann /**
32528ba7809SMichael Neumann  * hdmi_vendor_infoframe_pack() - write a HDMI vendor infoframe to binary buffer
32628ba7809SMichael Neumann  * @frame: HDMI infoframe
32728ba7809SMichael Neumann  * @buffer: destination buffer
32828ba7809SMichael Neumann  * @size: size of buffer
32928ba7809SMichael Neumann  *
33028ba7809SMichael Neumann  * Packs the information contained in the @frame structure into a binary
33128ba7809SMichael Neumann  * representation that can be written into the corresponding controller
33228ba7809SMichael Neumann  * registers. Also computes the checksum as required by section 5.3.5 of
33328ba7809SMichael Neumann  * the HDMI 1.4 specification.
33428ba7809SMichael Neumann  *
33528ba7809SMichael Neumann  * Returns the number of bytes packed into the binary buffer or a negative
33628ba7809SMichael Neumann  * error code on failure.
33728ba7809SMichael Neumann  */
hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe * frame,void * buffer,size_t size)33828ba7809SMichael Neumann ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
33928ba7809SMichael Neumann 				 void *buffer, size_t size)
34028ba7809SMichael Neumann {
34128ba7809SMichael Neumann 	u8 *ptr = buffer;
34228ba7809SMichael Neumann 	size_t length;
34328ba7809SMichael Neumann 
34428ba7809SMichael Neumann 	/* empty info frame */
34528ba7809SMichael Neumann 	if (frame->vic == 0 && frame->s3d_struct == HDMI_3D_STRUCTURE_INVALID)
34628ba7809SMichael Neumann 		return -EINVAL;
34728ba7809SMichael Neumann 
34828ba7809SMichael Neumann 	/* only one of those can be supplied */
34928ba7809SMichael Neumann 	if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID)
35028ba7809SMichael Neumann 		return -EINVAL;
35128ba7809SMichael Neumann 
35228ba7809SMichael Neumann 	/* for side by side (half) we also need to provide 3D_Ext_Data */
35328ba7809SMichael Neumann 	if (frame->s3d_struct >= HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF)
35428ba7809SMichael Neumann 		frame->length = 6;
35528ba7809SMichael Neumann 	else
35628ba7809SMichael Neumann 		frame->length = 5;
35728ba7809SMichael Neumann 
35828ba7809SMichael Neumann 	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
35928ba7809SMichael Neumann 
36028ba7809SMichael Neumann 	if (size < length)
36128ba7809SMichael Neumann 		return -ENOSPC;
36228ba7809SMichael Neumann 
36328ba7809SMichael Neumann 	memset(buffer, 0, size);
36428ba7809SMichael Neumann 
36528ba7809SMichael Neumann 	ptr[0] = frame->type;
36628ba7809SMichael Neumann 	ptr[1] = frame->version;
36728ba7809SMichael Neumann 	ptr[2] = frame->length;
36828ba7809SMichael Neumann 	ptr[3] = 0; /* checksum */
36928ba7809SMichael Neumann 
37028ba7809SMichael Neumann 	/* HDMI OUI */
37128ba7809SMichael Neumann 	ptr[4] = 0x03;
37228ba7809SMichael Neumann 	ptr[5] = 0x0c;
37328ba7809SMichael Neumann 	ptr[6] = 0x00;
37428ba7809SMichael Neumann 
37528ba7809SMichael Neumann 	if (frame->vic) {
37628ba7809SMichael Neumann 		ptr[7] = 0x1 << 5;	/* video format */
37728ba7809SMichael Neumann 		ptr[8] = frame->vic;
37828ba7809SMichael Neumann 	} else {
37928ba7809SMichael Neumann 		ptr[7] = 0x2 << 5;	/* video format */
38028ba7809SMichael Neumann 		ptr[8] = (frame->s3d_struct & 0xf) << 4;
38128ba7809SMichael Neumann 		if (frame->s3d_struct >= HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF)
38228ba7809SMichael Neumann 			ptr[9] = (frame->s3d_ext_data & 0xf) << 4;
38328ba7809SMichael Neumann 	}
38428ba7809SMichael Neumann 
38528ba7809SMichael Neumann 	hdmi_infoframe_set_checksum(buffer, length);
38628ba7809SMichael Neumann 
38728ba7809SMichael Neumann 	return length;
38828ba7809SMichael Neumann }
38928ba7809SMichael Neumann EXPORT_SYMBOL(hdmi_vendor_infoframe_pack);
39028ba7809SMichael Neumann 
39128ba7809SMichael Neumann /*
39228ba7809SMichael Neumann  * hdmi_vendor_any_infoframe_pack() - write a vendor infoframe to binary buffer
39328ba7809SMichael Neumann  */
39428ba7809SMichael Neumann static ssize_t
hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe * frame,void * buffer,size_t size)39528ba7809SMichael Neumann hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
39628ba7809SMichael Neumann 			   void *buffer, size_t size)
39728ba7809SMichael Neumann {
39828ba7809SMichael Neumann 	/* we only know about HDMI vendor infoframes */
39928ba7809SMichael Neumann 	if (frame->any.oui != HDMI_IEEE_OUI)
40028ba7809SMichael Neumann 		return -EINVAL;
40128ba7809SMichael Neumann 
40228ba7809SMichael Neumann 	return hdmi_vendor_infoframe_pack(&frame->hdmi, buffer, size);
40328ba7809SMichael Neumann }
40428ba7809SMichael Neumann 
40528ba7809SMichael Neumann /**
40628ba7809SMichael Neumann  * hdmi_infoframe_pack() - write a HDMI infoframe to binary buffer
40728ba7809SMichael Neumann  * @frame: HDMI infoframe
40828ba7809SMichael Neumann  * @buffer: destination buffer
40928ba7809SMichael Neumann  * @size: size of buffer
41028ba7809SMichael Neumann  *
41128ba7809SMichael Neumann  * Packs the information contained in the @frame structure into a binary
41228ba7809SMichael Neumann  * representation that can be written into the corresponding controller
41328ba7809SMichael Neumann  * registers. Also computes the checksum as required by section 5.3.5 of
41428ba7809SMichael Neumann  * the HDMI 1.4 specification.
41528ba7809SMichael Neumann  *
41628ba7809SMichael Neumann  * Returns the number of bytes packed into the binary buffer or a negative
41728ba7809SMichael Neumann  * error code on failure.
41828ba7809SMichael Neumann  */
41928ba7809SMichael Neumann ssize_t
hdmi_infoframe_pack(union hdmi_infoframe * frame,void * buffer,size_t size)42028ba7809SMichael Neumann hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size)
42128ba7809SMichael Neumann {
42228ba7809SMichael Neumann 	ssize_t length;
42328ba7809SMichael Neumann 
42428ba7809SMichael Neumann 	switch (frame->any.type) {
42528ba7809SMichael Neumann 	case HDMI_INFOFRAME_TYPE_AVI:
42628ba7809SMichael Neumann 		length = hdmi_avi_infoframe_pack(&frame->avi, buffer, size);
42728ba7809SMichael Neumann 		break;
42828ba7809SMichael Neumann 	case HDMI_INFOFRAME_TYPE_SPD:
42928ba7809SMichael Neumann 		length = hdmi_spd_infoframe_pack(&frame->spd, buffer, size);
43028ba7809SMichael Neumann 		break;
43128ba7809SMichael Neumann 	case HDMI_INFOFRAME_TYPE_AUDIO:
43228ba7809SMichael Neumann 		length = hdmi_audio_infoframe_pack(&frame->audio, buffer, size);
43328ba7809SMichael Neumann 		break;
43428ba7809SMichael Neumann 	case HDMI_INFOFRAME_TYPE_VENDOR:
43528ba7809SMichael Neumann 		length = hdmi_vendor_any_infoframe_pack(&frame->vendor,
43628ba7809SMichael Neumann 							buffer, size);
43728ba7809SMichael Neumann 		break;
43828ba7809SMichael Neumann 	default:
43928ba7809SMichael Neumann 		WARN(1, "Bad infoframe type %d\n", frame->any.type);
44028ba7809SMichael Neumann 		length = -EINVAL;
44128ba7809SMichael Neumann 	}
44228ba7809SMichael Neumann 
44328ba7809SMichael Neumann 	return length;
44428ba7809SMichael Neumann }
44528ba7809SMichael Neumann EXPORT_SYMBOL(hdmi_infoframe_pack);
44628ba7809SMichael Neumann 
hdmi_infoframe_type_get_name(enum hdmi_infoframe_type type)44728ba7809SMichael Neumann static const char *hdmi_infoframe_type_get_name(enum hdmi_infoframe_type type)
44828ba7809SMichael Neumann {
44928ba7809SMichael Neumann 	if (type < 0x80 || type > 0x9f)
45028ba7809SMichael Neumann 		return "Invalid";
45128ba7809SMichael Neumann 	switch (type) {
45228ba7809SMichael Neumann 	case HDMI_INFOFRAME_TYPE_VENDOR:
45328ba7809SMichael Neumann 		return "Vendor";
45428ba7809SMichael Neumann 	case HDMI_INFOFRAME_TYPE_AVI:
45528ba7809SMichael Neumann 		return "Auxiliary Video Information (AVI)";
45628ba7809SMichael Neumann 	case HDMI_INFOFRAME_TYPE_SPD:
45728ba7809SMichael Neumann 		return "Source Product Description (SPD)";
45828ba7809SMichael Neumann 	case HDMI_INFOFRAME_TYPE_AUDIO:
45928ba7809SMichael Neumann 		return "Audio";
46028ba7809SMichael Neumann 	}
46128ba7809SMichael Neumann 	return "Reserved";
46228ba7809SMichael Neumann }
46328ba7809SMichael Neumann 
hdmi_infoframe_log_header(const char * level,struct device * dev,struct hdmi_any_infoframe * frame)46428ba7809SMichael Neumann static void hdmi_infoframe_log_header(const char *level,
46528ba7809SMichael Neumann 				      struct device *dev,
46628ba7809SMichael Neumann 				      struct hdmi_any_infoframe *frame)
46728ba7809SMichael Neumann {
46828ba7809SMichael Neumann 	hdmi_log("HDMI infoframe: %s, version %u, length %u\n",
46928ba7809SMichael Neumann 		hdmi_infoframe_type_get_name(frame->type),
47028ba7809SMichael Neumann 		frame->version, frame->length);
47128ba7809SMichael Neumann }
47228ba7809SMichael Neumann 
hdmi_colorspace_get_name(enum hdmi_colorspace colorspace)47328ba7809SMichael Neumann static const char *hdmi_colorspace_get_name(enum hdmi_colorspace colorspace)
47428ba7809SMichael Neumann {
47528ba7809SMichael Neumann 	switch (colorspace) {
47628ba7809SMichael Neumann 	case HDMI_COLORSPACE_RGB:
47728ba7809SMichael Neumann 		return "RGB";
47828ba7809SMichael Neumann 	case HDMI_COLORSPACE_YUV422:
47928ba7809SMichael Neumann 		return "YCbCr 4:2:2";
48028ba7809SMichael Neumann 	case HDMI_COLORSPACE_YUV444:
48128ba7809SMichael Neumann 		return "YCbCr 4:4:4";
48228ba7809SMichael Neumann 	case HDMI_COLORSPACE_YUV420:
48328ba7809SMichael Neumann 		return "YCbCr 4:2:0";
48428ba7809SMichael Neumann 	case HDMI_COLORSPACE_RESERVED4:
48528ba7809SMichael Neumann 		return "Reserved (4)";
48628ba7809SMichael Neumann 	case HDMI_COLORSPACE_RESERVED5:
48728ba7809SMichael Neumann 		return "Reserved (5)";
48828ba7809SMichael Neumann 	case HDMI_COLORSPACE_RESERVED6:
48928ba7809SMichael Neumann 		return "Reserved (6)";
49028ba7809SMichael Neumann 	case HDMI_COLORSPACE_IDO_DEFINED:
49128ba7809SMichael Neumann 		return "IDO Defined";
49228ba7809SMichael Neumann 	}
49328ba7809SMichael Neumann 	return "Invalid";
49428ba7809SMichael Neumann }
49528ba7809SMichael Neumann 
hdmi_scan_mode_get_name(enum hdmi_scan_mode scan_mode)49628ba7809SMichael Neumann static const char *hdmi_scan_mode_get_name(enum hdmi_scan_mode scan_mode)
49728ba7809SMichael Neumann {
49828ba7809SMichael Neumann 	switch (scan_mode) {
49928ba7809SMichael Neumann 	case HDMI_SCAN_MODE_NONE:
50028ba7809SMichael Neumann 		return "No Data";
50128ba7809SMichael Neumann 	case HDMI_SCAN_MODE_OVERSCAN:
50228ba7809SMichael Neumann 		return "Overscan";
50328ba7809SMichael Neumann 	case HDMI_SCAN_MODE_UNDERSCAN:
50428ba7809SMichael Neumann 		return "Underscan";
50528ba7809SMichael Neumann 	case HDMI_SCAN_MODE_RESERVED:
50628ba7809SMichael Neumann 		return "Reserved";
50728ba7809SMichael Neumann 	}
50828ba7809SMichael Neumann 	return "Invalid";
50928ba7809SMichael Neumann }
51028ba7809SMichael Neumann 
hdmi_colorimetry_get_name(enum hdmi_colorimetry colorimetry)51128ba7809SMichael Neumann static const char *hdmi_colorimetry_get_name(enum hdmi_colorimetry colorimetry)
51228ba7809SMichael Neumann {
51328ba7809SMichael Neumann 	switch (colorimetry) {
51428ba7809SMichael Neumann 	case HDMI_COLORIMETRY_NONE:
51528ba7809SMichael Neumann 		return "No Data";
51628ba7809SMichael Neumann 	case HDMI_COLORIMETRY_ITU_601:
51728ba7809SMichael Neumann 		return "ITU601";
51828ba7809SMichael Neumann 	case HDMI_COLORIMETRY_ITU_709:
51928ba7809SMichael Neumann 		return "ITU709";
52028ba7809SMichael Neumann 	case HDMI_COLORIMETRY_EXTENDED:
52128ba7809SMichael Neumann 		return "Extended";
52228ba7809SMichael Neumann 	}
52328ba7809SMichael Neumann 	return "Invalid";
52428ba7809SMichael Neumann }
52528ba7809SMichael Neumann 
52628ba7809SMichael Neumann static const char *
hdmi_picture_aspect_get_name(enum hdmi_picture_aspect picture_aspect)52728ba7809SMichael Neumann hdmi_picture_aspect_get_name(enum hdmi_picture_aspect picture_aspect)
52828ba7809SMichael Neumann {
52928ba7809SMichael Neumann 	switch (picture_aspect) {
53028ba7809SMichael Neumann 	case HDMI_PICTURE_ASPECT_NONE:
53128ba7809SMichael Neumann 		return "No Data";
53228ba7809SMichael Neumann 	case HDMI_PICTURE_ASPECT_4_3:
53328ba7809SMichael Neumann 		return "4:3";
53428ba7809SMichael Neumann 	case HDMI_PICTURE_ASPECT_16_9:
53528ba7809SMichael Neumann 		return "16:9";
536*3f2dd94aSFrançois Tigeot 	case HDMI_PICTURE_ASPECT_64_27:
537*3f2dd94aSFrançois Tigeot 		return "64:27";
538*3f2dd94aSFrançois Tigeot 	case HDMI_PICTURE_ASPECT_256_135:
539*3f2dd94aSFrançois Tigeot 		return "256:135";
54028ba7809SMichael Neumann 	case HDMI_PICTURE_ASPECT_RESERVED:
54128ba7809SMichael Neumann 		return "Reserved";
54228ba7809SMichael Neumann 	}
54328ba7809SMichael Neumann 	return "Invalid";
54428ba7809SMichael Neumann }
54528ba7809SMichael Neumann 
54628ba7809SMichael Neumann static const char *
hdmi_active_aspect_get_name(enum hdmi_active_aspect active_aspect)54728ba7809SMichael Neumann hdmi_active_aspect_get_name(enum hdmi_active_aspect active_aspect)
54828ba7809SMichael Neumann {
54928ba7809SMichael Neumann 	if (active_aspect < 0 || active_aspect > 0xf)
55028ba7809SMichael Neumann 		return "Invalid";
55128ba7809SMichael Neumann 
55228ba7809SMichael Neumann 	switch (active_aspect) {
55328ba7809SMichael Neumann 	case HDMI_ACTIVE_ASPECT_16_9_TOP:
55428ba7809SMichael Neumann 		return "16:9 Top";
55528ba7809SMichael Neumann 	case HDMI_ACTIVE_ASPECT_14_9_TOP:
55628ba7809SMichael Neumann 		return "14:9 Top";
55728ba7809SMichael Neumann 	case HDMI_ACTIVE_ASPECT_16_9_CENTER:
55828ba7809SMichael Neumann 		return "16:9 Center";
55928ba7809SMichael Neumann 	case HDMI_ACTIVE_ASPECT_PICTURE:
56028ba7809SMichael Neumann 		return "Same as Picture";
56128ba7809SMichael Neumann 	case HDMI_ACTIVE_ASPECT_4_3:
56228ba7809SMichael Neumann 		return "4:3";
56328ba7809SMichael Neumann 	case HDMI_ACTIVE_ASPECT_16_9:
56428ba7809SMichael Neumann 		return "16:9";
56528ba7809SMichael Neumann 	case HDMI_ACTIVE_ASPECT_14_9:
56628ba7809SMichael Neumann 		return "14:9";
56728ba7809SMichael Neumann 	case HDMI_ACTIVE_ASPECT_4_3_SP_14_9:
56828ba7809SMichael Neumann 		return "4:3 SP 14:9";
56928ba7809SMichael Neumann 	case HDMI_ACTIVE_ASPECT_16_9_SP_14_9:
57028ba7809SMichael Neumann 		return "16:9 SP 14:9";
57128ba7809SMichael Neumann 	case HDMI_ACTIVE_ASPECT_16_9_SP_4_3:
57228ba7809SMichael Neumann 		return "16:9 SP 4:3";
57328ba7809SMichael Neumann 	}
57428ba7809SMichael Neumann 	return "Reserved";
57528ba7809SMichael Neumann }
57628ba7809SMichael Neumann 
57728ba7809SMichael Neumann static const char *
hdmi_extended_colorimetry_get_name(enum hdmi_extended_colorimetry ext_col)57828ba7809SMichael Neumann hdmi_extended_colorimetry_get_name(enum hdmi_extended_colorimetry ext_col)
57928ba7809SMichael Neumann {
58028ba7809SMichael Neumann 	switch (ext_col) {
58128ba7809SMichael Neumann 	case HDMI_EXTENDED_COLORIMETRY_XV_YCC_601:
58228ba7809SMichael Neumann 		return "xvYCC 601";
58328ba7809SMichael Neumann 	case HDMI_EXTENDED_COLORIMETRY_XV_YCC_709:
58428ba7809SMichael Neumann 		return "xvYCC 709";
58528ba7809SMichael Neumann 	case HDMI_EXTENDED_COLORIMETRY_S_YCC_601:
58628ba7809SMichael Neumann 		return "sYCC 601";
58728ba7809SMichael Neumann 	case HDMI_EXTENDED_COLORIMETRY_ADOBE_YCC_601:
58828ba7809SMichael Neumann 		return "Adobe YCC 601";
58928ba7809SMichael Neumann 	case HDMI_EXTENDED_COLORIMETRY_ADOBE_RGB:
59028ba7809SMichael Neumann 		return "Adobe RGB";
59128ba7809SMichael Neumann 	case HDMI_EXTENDED_COLORIMETRY_BT2020_CONST_LUM:
59228ba7809SMichael Neumann 		return "BT.2020 Constant Luminance";
59328ba7809SMichael Neumann 	case HDMI_EXTENDED_COLORIMETRY_BT2020:
59428ba7809SMichael Neumann 		return "BT.2020";
59528ba7809SMichael Neumann 	case HDMI_EXTENDED_COLORIMETRY_RESERVED:
59628ba7809SMichael Neumann 		return "Reserved";
59728ba7809SMichael Neumann 	}
59828ba7809SMichael Neumann 	return "Invalid";
59928ba7809SMichael Neumann }
60028ba7809SMichael Neumann 
60128ba7809SMichael Neumann static const char *
hdmi_quantization_range_get_name(enum hdmi_quantization_range qrange)60228ba7809SMichael Neumann hdmi_quantization_range_get_name(enum hdmi_quantization_range qrange)
60328ba7809SMichael Neumann {
60428ba7809SMichael Neumann 	switch (qrange) {
60528ba7809SMichael Neumann 	case HDMI_QUANTIZATION_RANGE_DEFAULT:
60628ba7809SMichael Neumann 		return "Default";
60728ba7809SMichael Neumann 	case HDMI_QUANTIZATION_RANGE_LIMITED:
60828ba7809SMichael Neumann 		return "Limited";
60928ba7809SMichael Neumann 	case HDMI_QUANTIZATION_RANGE_FULL:
61028ba7809SMichael Neumann 		return "Full";
61128ba7809SMichael Neumann 	case HDMI_QUANTIZATION_RANGE_RESERVED:
61228ba7809SMichael Neumann 		return "Reserved";
61328ba7809SMichael Neumann 	}
61428ba7809SMichael Neumann 	return "Invalid";
61528ba7809SMichael Neumann }
61628ba7809SMichael Neumann 
hdmi_nups_get_name(enum hdmi_nups nups)61728ba7809SMichael Neumann static const char *hdmi_nups_get_name(enum hdmi_nups nups)
61828ba7809SMichael Neumann {
61928ba7809SMichael Neumann 	switch (nups) {
62028ba7809SMichael Neumann 	case HDMI_NUPS_UNKNOWN:
62128ba7809SMichael Neumann 		return "Unknown Non-uniform Scaling";
62228ba7809SMichael Neumann 	case HDMI_NUPS_HORIZONTAL:
62328ba7809SMichael Neumann 		return "Horizontally Scaled";
62428ba7809SMichael Neumann 	case HDMI_NUPS_VERTICAL:
62528ba7809SMichael Neumann 		return "Vertically Scaled";
62628ba7809SMichael Neumann 	case HDMI_NUPS_BOTH:
62728ba7809SMichael Neumann 		return "Horizontally and Vertically Scaled";
62828ba7809SMichael Neumann 	}
62928ba7809SMichael Neumann 	return "Invalid";
63028ba7809SMichael Neumann }
63128ba7809SMichael Neumann 
63228ba7809SMichael Neumann static const char *
hdmi_ycc_quantization_range_get_name(enum hdmi_ycc_quantization_range qrange)63328ba7809SMichael Neumann hdmi_ycc_quantization_range_get_name(enum hdmi_ycc_quantization_range qrange)
63428ba7809SMichael Neumann {
63528ba7809SMichael Neumann 	switch (qrange) {
63628ba7809SMichael Neumann 	case HDMI_YCC_QUANTIZATION_RANGE_LIMITED:
63728ba7809SMichael Neumann 		return "Limited";
63828ba7809SMichael Neumann 	case HDMI_YCC_QUANTIZATION_RANGE_FULL:
63928ba7809SMichael Neumann 		return "Full";
64028ba7809SMichael Neumann 	}
64128ba7809SMichael Neumann 	return "Invalid";
64228ba7809SMichael Neumann }
64328ba7809SMichael Neumann 
64428ba7809SMichael Neumann static const char *
hdmi_content_type_get_name(enum hdmi_content_type content_type)64528ba7809SMichael Neumann hdmi_content_type_get_name(enum hdmi_content_type content_type)
64628ba7809SMichael Neumann {
64728ba7809SMichael Neumann 	switch (content_type) {
64828ba7809SMichael Neumann 	case HDMI_CONTENT_TYPE_GRAPHICS:
64928ba7809SMichael Neumann 		return "Graphics";
65028ba7809SMichael Neumann 	case HDMI_CONTENT_TYPE_PHOTO:
65128ba7809SMichael Neumann 		return "Photo";
65228ba7809SMichael Neumann 	case HDMI_CONTENT_TYPE_CINEMA:
65328ba7809SMichael Neumann 		return "Cinema";
65428ba7809SMichael Neumann 	case HDMI_CONTENT_TYPE_GAME:
65528ba7809SMichael Neumann 		return "Game";
65628ba7809SMichael Neumann 	}
65728ba7809SMichael Neumann 	return "Invalid";
65828ba7809SMichael Neumann }
65928ba7809SMichael Neumann 
66028ba7809SMichael Neumann /**
66128ba7809SMichael Neumann  * hdmi_avi_infoframe_log() - log info of HDMI AVI infoframe
66228ba7809SMichael Neumann  * @level: logging level
66328ba7809SMichael Neumann  * @dev: device
66428ba7809SMichael Neumann  * @frame: HDMI AVI infoframe
66528ba7809SMichael Neumann  */
hdmi_avi_infoframe_log(const char * level,struct device * dev,struct hdmi_avi_infoframe * frame)66628ba7809SMichael Neumann static void hdmi_avi_infoframe_log(const char *level,
66728ba7809SMichael Neumann 				   struct device *dev,
66828ba7809SMichael Neumann 				   struct hdmi_avi_infoframe *frame)
66928ba7809SMichael Neumann {
67028ba7809SMichael Neumann 	hdmi_infoframe_log_header(level, dev,
67128ba7809SMichael Neumann 				  (struct hdmi_any_infoframe *)frame);
67228ba7809SMichael Neumann 
67328ba7809SMichael Neumann 	hdmi_log("    colorspace: %s\n",
67428ba7809SMichael Neumann 			hdmi_colorspace_get_name(frame->colorspace));
67528ba7809SMichael Neumann 	hdmi_log("    scan mode: %s\n",
67628ba7809SMichael Neumann 			hdmi_scan_mode_get_name(frame->scan_mode));
67728ba7809SMichael Neumann 	hdmi_log("    colorimetry: %s\n",
67828ba7809SMichael Neumann 			hdmi_colorimetry_get_name(frame->colorimetry));
67928ba7809SMichael Neumann 	hdmi_log("    picture aspect: %s\n",
68028ba7809SMichael Neumann 			hdmi_picture_aspect_get_name(frame->picture_aspect));
68128ba7809SMichael Neumann 	hdmi_log("    active aspect: %s\n",
68228ba7809SMichael Neumann 			hdmi_active_aspect_get_name(frame->active_aspect));
68328ba7809SMichael Neumann 	hdmi_log("    itc: %s\n", frame->itc ? "IT Content" : "No Data");
68428ba7809SMichael Neumann 	hdmi_log("    extended colorimetry: %s\n",
68528ba7809SMichael Neumann 			hdmi_extended_colorimetry_get_name(frame->extended_colorimetry));
68628ba7809SMichael Neumann 	hdmi_log("    quantization range: %s\n",
68728ba7809SMichael Neumann 			hdmi_quantization_range_get_name(frame->quantization_range));
68828ba7809SMichael Neumann 	hdmi_log("    nups: %s\n", hdmi_nups_get_name(frame->nups));
68928ba7809SMichael Neumann 	hdmi_log("    video code: %u\n", frame->video_code);
69028ba7809SMichael Neumann 	hdmi_log("    ycc quantization range: %s\n",
69128ba7809SMichael Neumann 			hdmi_ycc_quantization_range_get_name(frame->ycc_quantization_range));
69228ba7809SMichael Neumann 	hdmi_log("    hdmi content type: %s\n",
69328ba7809SMichael Neumann 			hdmi_content_type_get_name(frame->content_type));
69428ba7809SMichael Neumann 	hdmi_log("    pixel repeat: %u\n", frame->pixel_repeat);
69528ba7809SMichael Neumann 	hdmi_log("    bar top %u, bottom %u, left %u, right %u\n",
69628ba7809SMichael Neumann 			frame->top_bar, frame->bottom_bar,
69728ba7809SMichael Neumann 			frame->left_bar, frame->right_bar);
69828ba7809SMichael Neumann }
69928ba7809SMichael Neumann 
hdmi_spd_sdi_get_name(enum hdmi_spd_sdi sdi)70028ba7809SMichael Neumann static const char *hdmi_spd_sdi_get_name(enum hdmi_spd_sdi sdi)
70128ba7809SMichael Neumann {
70228ba7809SMichael Neumann 	if (sdi < 0 || sdi > 0xff)
70328ba7809SMichael Neumann 		return "Invalid";
70428ba7809SMichael Neumann 	switch (sdi) {
70528ba7809SMichael Neumann 	case HDMI_SPD_SDI_UNKNOWN:
70628ba7809SMichael Neumann 		return "Unknown";
70728ba7809SMichael Neumann 	case HDMI_SPD_SDI_DSTB:
70828ba7809SMichael Neumann 		return "Digital STB";
70928ba7809SMichael Neumann 	case HDMI_SPD_SDI_DVDP:
71028ba7809SMichael Neumann 		return "DVD Player";
71128ba7809SMichael Neumann 	case HDMI_SPD_SDI_DVHS:
71228ba7809SMichael Neumann 		return "D-VHS";
71328ba7809SMichael Neumann 	case HDMI_SPD_SDI_HDDVR:
71428ba7809SMichael Neumann 		return "HDD Videorecorder";
71528ba7809SMichael Neumann 	case HDMI_SPD_SDI_DVC:
71628ba7809SMichael Neumann 		return "DVC";
71728ba7809SMichael Neumann 	case HDMI_SPD_SDI_DSC:
71828ba7809SMichael Neumann 		return "DSC";
71928ba7809SMichael Neumann 	case HDMI_SPD_SDI_VCD:
72028ba7809SMichael Neumann 		return "Video CD";
72128ba7809SMichael Neumann 	case HDMI_SPD_SDI_GAME:
72228ba7809SMichael Neumann 		return "Game";
72328ba7809SMichael Neumann 	case HDMI_SPD_SDI_PC:
72428ba7809SMichael Neumann 		return "PC General";
72528ba7809SMichael Neumann 	case HDMI_SPD_SDI_BD:
72628ba7809SMichael Neumann 		return "Blu-Ray Disc (BD)";
72728ba7809SMichael Neumann 	case HDMI_SPD_SDI_SACD:
72828ba7809SMichael Neumann 		return "Super Audio CD";
72928ba7809SMichael Neumann 	case HDMI_SPD_SDI_HDDVD:
73028ba7809SMichael Neumann 		return "HD DVD";
73128ba7809SMichael Neumann 	case HDMI_SPD_SDI_PMP:
73228ba7809SMichael Neumann 		return "PMP";
73328ba7809SMichael Neumann 	}
73428ba7809SMichael Neumann 	return "Reserved";
73528ba7809SMichael Neumann }
73628ba7809SMichael Neumann 
73728ba7809SMichael Neumann /**
73828ba7809SMichael Neumann  * hdmi_spd_infoframe_log() - log info of HDMI SPD infoframe
73928ba7809SMichael Neumann  * @level: logging level
74028ba7809SMichael Neumann  * @dev: device
74128ba7809SMichael Neumann  * @frame: HDMI SPD infoframe
74228ba7809SMichael Neumann  */
hdmi_spd_infoframe_log(const char * level,struct device * dev,struct hdmi_spd_infoframe * frame)74328ba7809SMichael Neumann static void hdmi_spd_infoframe_log(const char *level,
74428ba7809SMichael Neumann 				   struct device *dev,
74528ba7809SMichael Neumann 				   struct hdmi_spd_infoframe *frame)
74628ba7809SMichael Neumann {
74728ba7809SMichael Neumann 	u8 buf[17];
74828ba7809SMichael Neumann 
74928ba7809SMichael Neumann 	hdmi_infoframe_log_header(level, dev,
75028ba7809SMichael Neumann 				  (struct hdmi_any_infoframe *)frame);
75128ba7809SMichael Neumann 
75228ba7809SMichael Neumann 	memset(buf, 0, sizeof(buf));
75328ba7809SMichael Neumann 
75428ba7809SMichael Neumann 	strncpy(buf, frame->vendor, 8);
75528ba7809SMichael Neumann 	hdmi_log("    vendor: %s\n", buf);
75628ba7809SMichael Neumann 	strncpy(buf, frame->product, 16);
75728ba7809SMichael Neumann 	hdmi_log("    product: %s\n", buf);
75828ba7809SMichael Neumann 	hdmi_log("    source device information: %s (0x%x)\n",
75928ba7809SMichael Neumann 		hdmi_spd_sdi_get_name(frame->sdi), frame->sdi);
76028ba7809SMichael Neumann }
76128ba7809SMichael Neumann 
76228ba7809SMichael Neumann static const char *
hdmi_audio_coding_type_get_name(enum hdmi_audio_coding_type coding_type)76328ba7809SMichael Neumann hdmi_audio_coding_type_get_name(enum hdmi_audio_coding_type coding_type)
76428ba7809SMichael Neumann {
76528ba7809SMichael Neumann 	switch (coding_type) {
76628ba7809SMichael Neumann 	case HDMI_AUDIO_CODING_TYPE_STREAM:
76728ba7809SMichael Neumann 		return "Refer to Stream Header";
76828ba7809SMichael Neumann 	case HDMI_AUDIO_CODING_TYPE_PCM:
76928ba7809SMichael Neumann 		return "PCM";
77028ba7809SMichael Neumann 	case HDMI_AUDIO_CODING_TYPE_AC3:
77128ba7809SMichael Neumann 		return "AC-3";
77228ba7809SMichael Neumann 	case HDMI_AUDIO_CODING_TYPE_MPEG1:
77328ba7809SMichael Neumann 		return "MPEG1";
77428ba7809SMichael Neumann 	case HDMI_AUDIO_CODING_TYPE_MP3:
77528ba7809SMichael Neumann 		return "MP3";
77628ba7809SMichael Neumann 	case HDMI_AUDIO_CODING_TYPE_MPEG2:
77728ba7809SMichael Neumann 		return "MPEG2";
77828ba7809SMichael Neumann 	case HDMI_AUDIO_CODING_TYPE_AAC_LC:
77928ba7809SMichael Neumann 		return "AAC";
78028ba7809SMichael Neumann 	case HDMI_AUDIO_CODING_TYPE_DTS:
78128ba7809SMichael Neumann 		return "DTS";
78228ba7809SMichael Neumann 	case HDMI_AUDIO_CODING_TYPE_ATRAC:
78328ba7809SMichael Neumann 		return "ATRAC";
78428ba7809SMichael Neumann 	case HDMI_AUDIO_CODING_TYPE_DSD:
78528ba7809SMichael Neumann 		return "One Bit Audio";
78628ba7809SMichael Neumann 	case HDMI_AUDIO_CODING_TYPE_EAC3:
78728ba7809SMichael Neumann 		return "Dolby Digital +";
78828ba7809SMichael Neumann 	case HDMI_AUDIO_CODING_TYPE_DTS_HD:
78928ba7809SMichael Neumann 		return "DTS-HD";
79028ba7809SMichael Neumann 	case HDMI_AUDIO_CODING_TYPE_MLP:
79128ba7809SMichael Neumann 		return "MAT (MLP)";
79228ba7809SMichael Neumann 	case HDMI_AUDIO_CODING_TYPE_DST:
79328ba7809SMichael Neumann 		return "DST";
79428ba7809SMichael Neumann 	case HDMI_AUDIO_CODING_TYPE_WMA_PRO:
79528ba7809SMichael Neumann 		return "WMA PRO";
79628ba7809SMichael Neumann 	case HDMI_AUDIO_CODING_TYPE_CXT:
79728ba7809SMichael Neumann 		return "Refer to CXT";
79828ba7809SMichael Neumann 	}
79928ba7809SMichael Neumann 	return "Invalid";
80028ba7809SMichael Neumann }
80128ba7809SMichael Neumann 
80228ba7809SMichael Neumann static const char *
hdmi_audio_sample_size_get_name(enum hdmi_audio_sample_size sample_size)80328ba7809SMichael Neumann hdmi_audio_sample_size_get_name(enum hdmi_audio_sample_size sample_size)
80428ba7809SMichael Neumann {
80528ba7809SMichael Neumann 	switch (sample_size) {
80628ba7809SMichael Neumann 	case HDMI_AUDIO_SAMPLE_SIZE_STREAM:
80728ba7809SMichael Neumann 		return "Refer to Stream Header";
80828ba7809SMichael Neumann 	case HDMI_AUDIO_SAMPLE_SIZE_16:
80928ba7809SMichael Neumann 		return "16 bit";
81028ba7809SMichael Neumann 	case HDMI_AUDIO_SAMPLE_SIZE_20:
81128ba7809SMichael Neumann 		return "20 bit";
81228ba7809SMichael Neumann 	case HDMI_AUDIO_SAMPLE_SIZE_24:
81328ba7809SMichael Neumann 		return "24 bit";
81428ba7809SMichael Neumann 	}
81528ba7809SMichael Neumann 	return "Invalid";
81628ba7809SMichael Neumann }
81728ba7809SMichael Neumann 
81828ba7809SMichael Neumann static const char *
hdmi_audio_sample_frequency_get_name(enum hdmi_audio_sample_frequency freq)81928ba7809SMichael Neumann hdmi_audio_sample_frequency_get_name(enum hdmi_audio_sample_frequency freq)
82028ba7809SMichael Neumann {
82128ba7809SMichael Neumann 	switch (freq) {
82228ba7809SMichael Neumann 	case HDMI_AUDIO_SAMPLE_FREQUENCY_STREAM:
82328ba7809SMichael Neumann 		return "Refer to Stream Header";
82428ba7809SMichael Neumann 	case HDMI_AUDIO_SAMPLE_FREQUENCY_32000:
82528ba7809SMichael Neumann 		return "32 kHz";
82628ba7809SMichael Neumann 	case HDMI_AUDIO_SAMPLE_FREQUENCY_44100:
82728ba7809SMichael Neumann 		return "44.1 kHz (CD)";
82828ba7809SMichael Neumann 	case HDMI_AUDIO_SAMPLE_FREQUENCY_48000:
82928ba7809SMichael Neumann 		return "48 kHz";
83028ba7809SMichael Neumann 	case HDMI_AUDIO_SAMPLE_FREQUENCY_88200:
83128ba7809SMichael Neumann 		return "88.2 kHz";
83228ba7809SMichael Neumann 	case HDMI_AUDIO_SAMPLE_FREQUENCY_96000:
83328ba7809SMichael Neumann 		return "96 kHz";
83428ba7809SMichael Neumann 	case HDMI_AUDIO_SAMPLE_FREQUENCY_176400:
83528ba7809SMichael Neumann 		return "176.4 kHz";
83628ba7809SMichael Neumann 	case HDMI_AUDIO_SAMPLE_FREQUENCY_192000:
83728ba7809SMichael Neumann 		return "192 kHz";
83828ba7809SMichael Neumann 	}
83928ba7809SMichael Neumann 	return "Invalid";
84028ba7809SMichael Neumann }
84128ba7809SMichael Neumann 
84228ba7809SMichael Neumann static const char *
hdmi_audio_coding_type_ext_get_name(enum hdmi_audio_coding_type_ext ctx)84328ba7809SMichael Neumann hdmi_audio_coding_type_ext_get_name(enum hdmi_audio_coding_type_ext ctx)
84428ba7809SMichael Neumann {
84528ba7809SMichael Neumann 	if (ctx < 0 || ctx > 0x1f)
84628ba7809SMichael Neumann 		return "Invalid";
84728ba7809SMichael Neumann 
84828ba7809SMichael Neumann 	switch (ctx) {
84928ba7809SMichael Neumann 	case HDMI_AUDIO_CODING_TYPE_EXT_CT:
85028ba7809SMichael Neumann 		return "Refer to CT";
85128ba7809SMichael Neumann 	case HDMI_AUDIO_CODING_TYPE_EXT_HE_AAC:
85228ba7809SMichael Neumann 		return "HE AAC";
85328ba7809SMichael Neumann 	case HDMI_AUDIO_CODING_TYPE_EXT_HE_AAC_V2:
85428ba7809SMichael Neumann 		return "HE AAC v2";
85528ba7809SMichael Neumann 	case HDMI_AUDIO_CODING_TYPE_EXT_MPEG_SURROUND:
85628ba7809SMichael Neumann 		return "MPEG SURROUND";
85728ba7809SMichael Neumann 	case HDMI_AUDIO_CODING_TYPE_EXT_MPEG4_HE_AAC:
85828ba7809SMichael Neumann 		return "MPEG-4 HE AAC";
85928ba7809SMichael Neumann 	case HDMI_AUDIO_CODING_TYPE_EXT_MPEG4_HE_AAC_V2:
86028ba7809SMichael Neumann 		return "MPEG-4 HE AAC v2";
86128ba7809SMichael Neumann 	case HDMI_AUDIO_CODING_TYPE_EXT_MPEG4_AAC_LC:
86228ba7809SMichael Neumann 		return "MPEG-4 AAC LC";
86328ba7809SMichael Neumann 	case HDMI_AUDIO_CODING_TYPE_EXT_DRA:
86428ba7809SMichael Neumann 		return "DRA";
86528ba7809SMichael Neumann 	case HDMI_AUDIO_CODING_TYPE_EXT_MPEG4_HE_AAC_SURROUND:
86628ba7809SMichael Neumann 		return "MPEG-4 HE AAC + MPEG Surround";
86728ba7809SMichael Neumann 	case HDMI_AUDIO_CODING_TYPE_EXT_MPEG4_AAC_LC_SURROUND:
86828ba7809SMichael Neumann 		return "MPEG-4 AAC LC + MPEG Surround";
86928ba7809SMichael Neumann 	}
87028ba7809SMichael Neumann 	return "Reserved";
87128ba7809SMichael Neumann }
87228ba7809SMichael Neumann 
87328ba7809SMichael Neumann /**
87428ba7809SMichael Neumann  * hdmi_audio_infoframe_log() - log info of HDMI AUDIO infoframe
87528ba7809SMichael Neumann  * @level: logging level
87628ba7809SMichael Neumann  * @dev: device
87728ba7809SMichael Neumann  * @frame: HDMI AUDIO infoframe
87828ba7809SMichael Neumann  */
hdmi_audio_infoframe_log(const char * level,struct device * dev,struct hdmi_audio_infoframe * frame)87928ba7809SMichael Neumann static void hdmi_audio_infoframe_log(const char *level,
88028ba7809SMichael Neumann 				     struct device *dev,
88128ba7809SMichael Neumann 				     struct hdmi_audio_infoframe *frame)
88228ba7809SMichael Neumann {
88328ba7809SMichael Neumann 	hdmi_infoframe_log_header(level, dev,
88428ba7809SMichael Neumann 				  (struct hdmi_any_infoframe *)frame);
88528ba7809SMichael Neumann 
88628ba7809SMichael Neumann 	if (frame->channels)
88728ba7809SMichael Neumann 		hdmi_log("    channels: %u\n", frame->channels - 1);
88828ba7809SMichael Neumann 	else
88928ba7809SMichael Neumann 		hdmi_log("    channels: Refer to stream header\n");
89028ba7809SMichael Neumann 	hdmi_log("    coding type: %s\n",
89128ba7809SMichael Neumann 			hdmi_audio_coding_type_get_name(frame->coding_type));
89228ba7809SMichael Neumann 	hdmi_log("    sample size: %s\n",
89328ba7809SMichael Neumann 			hdmi_audio_sample_size_get_name(frame->sample_size));
89428ba7809SMichael Neumann 	hdmi_log("    sample frequency: %s\n",
89528ba7809SMichael Neumann 			hdmi_audio_sample_frequency_get_name(frame->sample_frequency));
89628ba7809SMichael Neumann 	hdmi_log("    coding type ext: %s\n",
89728ba7809SMichael Neumann 			hdmi_audio_coding_type_ext_get_name(frame->coding_type_ext));
89828ba7809SMichael Neumann 	hdmi_log("    channel allocation: 0x%x\n",
89928ba7809SMichael Neumann 			frame->channel_allocation);
90028ba7809SMichael Neumann 	hdmi_log("    level shift value: %u dB\n",
90128ba7809SMichael Neumann 			frame->level_shift_value);
90228ba7809SMichael Neumann 	hdmi_log("    downmix inhibit: %s\n",
90328ba7809SMichael Neumann 			frame->downmix_inhibit ? "Yes" : "No");
90428ba7809SMichael Neumann }
90528ba7809SMichael Neumann 
90628ba7809SMichael Neumann static const char *
hdmi_3d_structure_get_name(enum hdmi_3d_structure s3d_struct)90728ba7809SMichael Neumann hdmi_3d_structure_get_name(enum hdmi_3d_structure s3d_struct)
90828ba7809SMichael Neumann {
90928ba7809SMichael Neumann 	if (s3d_struct < 0 || s3d_struct > 0xf)
91028ba7809SMichael Neumann 		return "Invalid";
91128ba7809SMichael Neumann 
91228ba7809SMichael Neumann 	switch (s3d_struct) {
91328ba7809SMichael Neumann 	case HDMI_3D_STRUCTURE_FRAME_PACKING:
91428ba7809SMichael Neumann 		return "Frame Packing";
91528ba7809SMichael Neumann 	case HDMI_3D_STRUCTURE_FIELD_ALTERNATIVE:
91628ba7809SMichael Neumann 		return "Field Alternative";
91728ba7809SMichael Neumann 	case HDMI_3D_STRUCTURE_LINE_ALTERNATIVE:
91828ba7809SMichael Neumann 		return "Line Alternative";
91928ba7809SMichael Neumann 	case HDMI_3D_STRUCTURE_SIDE_BY_SIDE_FULL:
92028ba7809SMichael Neumann 		return "Side-by-side (Full)";
92128ba7809SMichael Neumann 	case HDMI_3D_STRUCTURE_L_DEPTH:
92228ba7809SMichael Neumann 		return "L + Depth";
92328ba7809SMichael Neumann 	case HDMI_3D_STRUCTURE_L_DEPTH_GFX_GFX_DEPTH:
92428ba7809SMichael Neumann 		return "L + Depth + Graphics + Graphics-depth";
92528ba7809SMichael Neumann 	case HDMI_3D_STRUCTURE_TOP_AND_BOTTOM:
92628ba7809SMichael Neumann 		return "Top-and-Bottom";
92728ba7809SMichael Neumann 	case HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF:
92828ba7809SMichael Neumann 		return "Side-by-side (Half)";
92928ba7809SMichael Neumann 	default:
93028ba7809SMichael Neumann 		break;
93128ba7809SMichael Neumann 	}
93228ba7809SMichael Neumann 	return "Reserved";
93328ba7809SMichael Neumann }
93428ba7809SMichael Neumann 
93528ba7809SMichael Neumann /**
93628ba7809SMichael Neumann  * hdmi_vendor_infoframe_log() - log info of HDMI VENDOR infoframe
93728ba7809SMichael Neumann  * @level: logging level
93828ba7809SMichael Neumann  * @dev: device
93928ba7809SMichael Neumann  * @frame: HDMI VENDOR infoframe
94028ba7809SMichael Neumann  */
94128ba7809SMichael Neumann static void
hdmi_vendor_any_infoframe_log(const char * level,struct device * dev,union hdmi_vendor_any_infoframe * frame)94228ba7809SMichael Neumann hdmi_vendor_any_infoframe_log(const char *level,
94328ba7809SMichael Neumann 			      struct device *dev,
94428ba7809SMichael Neumann 			      union hdmi_vendor_any_infoframe *frame)
94528ba7809SMichael Neumann {
94628ba7809SMichael Neumann 	struct hdmi_vendor_infoframe *hvf = &frame->hdmi;
94728ba7809SMichael Neumann 
94828ba7809SMichael Neumann 	hdmi_infoframe_log_header(level, dev,
94928ba7809SMichael Neumann 				  (struct hdmi_any_infoframe *)frame);
95028ba7809SMichael Neumann 
95128ba7809SMichael Neumann 	if (frame->any.oui != HDMI_IEEE_OUI) {
95228ba7809SMichael Neumann 		hdmi_log("    not a HDMI vendor infoframe\n");
95328ba7809SMichael Neumann 		return;
95428ba7809SMichael Neumann 	}
95528ba7809SMichael Neumann 	if (hvf->vic == 0 && hvf->s3d_struct == HDMI_3D_STRUCTURE_INVALID) {
95628ba7809SMichael Neumann 		hdmi_log("    empty frame\n");
95728ba7809SMichael Neumann 		return;
95828ba7809SMichael Neumann 	}
95928ba7809SMichael Neumann 
96028ba7809SMichael Neumann 	if (hvf->vic)
96128ba7809SMichael Neumann 		hdmi_log("    HDMI VIC: %u\n", hvf->vic);
96228ba7809SMichael Neumann 	if (hvf->s3d_struct != HDMI_3D_STRUCTURE_INVALID) {
96328ba7809SMichael Neumann 		hdmi_log("    3D structure: %s\n",
96428ba7809SMichael Neumann 				hdmi_3d_structure_get_name(hvf->s3d_struct));
96528ba7809SMichael Neumann 		if (hvf->s3d_struct >= HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF)
96628ba7809SMichael Neumann 			hdmi_log("    3D extension data: %d\n",
96728ba7809SMichael Neumann 					hvf->s3d_ext_data);
96828ba7809SMichael Neumann 	}
96928ba7809SMichael Neumann }
97028ba7809SMichael Neumann 
97128ba7809SMichael Neumann /**
97228ba7809SMichael Neumann  * hdmi_infoframe_log() - log info of HDMI infoframe
97328ba7809SMichael Neumann  * @level: logging level
97428ba7809SMichael Neumann  * @dev: device
97528ba7809SMichael Neumann  * @frame: HDMI infoframe
97628ba7809SMichael Neumann  */
hdmi_infoframe_log(const char * level,struct device * dev,union hdmi_infoframe * frame)97728ba7809SMichael Neumann void hdmi_infoframe_log(const char *level,
97828ba7809SMichael Neumann 			struct device *dev,
97928ba7809SMichael Neumann 			union hdmi_infoframe *frame)
98028ba7809SMichael Neumann {
98128ba7809SMichael Neumann 	switch (frame->any.type) {
98228ba7809SMichael Neumann 	case HDMI_INFOFRAME_TYPE_AVI:
98328ba7809SMichael Neumann 		hdmi_avi_infoframe_log(level, dev, &frame->avi);
98428ba7809SMichael Neumann 		break;
98528ba7809SMichael Neumann 	case HDMI_INFOFRAME_TYPE_SPD:
98628ba7809SMichael Neumann 		hdmi_spd_infoframe_log(level, dev, &frame->spd);
98728ba7809SMichael Neumann 		break;
98828ba7809SMichael Neumann 	case HDMI_INFOFRAME_TYPE_AUDIO:
98928ba7809SMichael Neumann 		hdmi_audio_infoframe_log(level, dev, &frame->audio);
99028ba7809SMichael Neumann 		break;
99128ba7809SMichael Neumann 	case HDMI_INFOFRAME_TYPE_VENDOR:
99228ba7809SMichael Neumann 		hdmi_vendor_any_infoframe_log(level, dev, &frame->vendor);
99328ba7809SMichael Neumann 		break;
99428ba7809SMichael Neumann 	}
99528ba7809SMichael Neumann }
99628ba7809SMichael Neumann EXPORT_SYMBOL(hdmi_infoframe_log);
99728ba7809SMichael Neumann 
99828ba7809SMichael Neumann /**
99928ba7809SMichael Neumann  * hdmi_avi_infoframe_unpack() - unpack binary buffer to a HDMI AVI infoframe
100028ba7809SMichael Neumann  * @buffer: source buffer
100128ba7809SMichael Neumann  * @frame: HDMI AVI infoframe
100228ba7809SMichael Neumann  *
100328ba7809SMichael Neumann  * Unpacks the information contained in binary @buffer into a structured
100428ba7809SMichael Neumann  * @frame of the HDMI Auxiliary Video (AVI) information frame.
100528ba7809SMichael Neumann  * Also verifies the checksum as required by section 5.3.5 of the HDMI 1.4
100628ba7809SMichael Neumann  * specification.
100728ba7809SMichael Neumann  *
100828ba7809SMichael Neumann  * Returns 0 on success or a negative error code on failure.
100928ba7809SMichael Neumann  */
hdmi_avi_infoframe_unpack(struct hdmi_avi_infoframe * frame,void * buffer)101028ba7809SMichael Neumann static int hdmi_avi_infoframe_unpack(struct hdmi_avi_infoframe *frame,
101128ba7809SMichael Neumann 				     void *buffer)
101228ba7809SMichael Neumann {
101328ba7809SMichael Neumann 	u8 *ptr = buffer;
101428ba7809SMichael Neumann 	int ret;
101528ba7809SMichael Neumann 
101628ba7809SMichael Neumann 	if (ptr[0] != HDMI_INFOFRAME_TYPE_AVI ||
101728ba7809SMichael Neumann 	    ptr[1] != 2 ||
101828ba7809SMichael Neumann 	    ptr[2] != HDMI_AVI_INFOFRAME_SIZE)
101928ba7809SMichael Neumann 		return -EINVAL;
102028ba7809SMichael Neumann 
102128ba7809SMichael Neumann 	if (hdmi_infoframe_checksum(buffer, HDMI_INFOFRAME_SIZE(AVI)) != 0)
102228ba7809SMichael Neumann 		return -EINVAL;
102328ba7809SMichael Neumann 
102428ba7809SMichael Neumann 	ret = hdmi_avi_infoframe_init(frame);
102528ba7809SMichael Neumann 	if (ret)
102628ba7809SMichael Neumann 		return ret;
102728ba7809SMichael Neumann 
102828ba7809SMichael Neumann 	ptr += HDMI_INFOFRAME_HEADER_SIZE;
102928ba7809SMichael Neumann 
103028ba7809SMichael Neumann 	frame->colorspace = (ptr[0] >> 5) & 0x3;
103128ba7809SMichael Neumann 	if (ptr[0] & 0x10)
103228ba7809SMichael Neumann 		frame->active_aspect = ptr[1] & 0xf;
103328ba7809SMichael Neumann 	if (ptr[0] & 0x8) {
103428ba7809SMichael Neumann 		frame->top_bar = (ptr[5] << 8) + ptr[6];
103528ba7809SMichael Neumann 		frame->bottom_bar = (ptr[7] << 8) + ptr[8];
103628ba7809SMichael Neumann 	}
103728ba7809SMichael Neumann 	if (ptr[0] & 0x4) {
103828ba7809SMichael Neumann 		frame->left_bar = (ptr[9] << 8) + ptr[10];
103928ba7809SMichael Neumann 		frame->right_bar = (ptr[11] << 8) + ptr[12];
104028ba7809SMichael Neumann 	}
104128ba7809SMichael Neumann 	frame->scan_mode = ptr[0] & 0x3;
104228ba7809SMichael Neumann 
104328ba7809SMichael Neumann 	frame->colorimetry = (ptr[1] >> 6) & 0x3;
104428ba7809SMichael Neumann 	frame->picture_aspect = (ptr[1] >> 4) & 0x3;
104528ba7809SMichael Neumann 	frame->active_aspect = ptr[1] & 0xf;
104628ba7809SMichael Neumann 
104728ba7809SMichael Neumann 	frame->itc = ptr[2] & 0x80 ? true : false;
104828ba7809SMichael Neumann 	frame->extended_colorimetry = (ptr[2] >> 4) & 0x7;
104928ba7809SMichael Neumann 	frame->quantization_range = (ptr[2] >> 2) & 0x3;
105028ba7809SMichael Neumann 	frame->nups = ptr[2] & 0x3;
105128ba7809SMichael Neumann 
105228ba7809SMichael Neumann 	frame->video_code = ptr[3] & 0x7f;
105328ba7809SMichael Neumann 	frame->ycc_quantization_range = (ptr[4] >> 6) & 0x3;
105428ba7809SMichael Neumann 	frame->content_type = (ptr[4] >> 4) & 0x3;
105528ba7809SMichael Neumann 
105628ba7809SMichael Neumann 	frame->pixel_repeat = ptr[4] & 0xf;
105728ba7809SMichael Neumann 
105828ba7809SMichael Neumann 	return 0;
105928ba7809SMichael Neumann }
106028ba7809SMichael Neumann 
106128ba7809SMichael Neumann /**
106228ba7809SMichael Neumann  * hdmi_spd_infoframe_unpack() - unpack binary buffer to a HDMI SPD infoframe
106328ba7809SMichael Neumann  * @buffer: source buffer
106428ba7809SMichael Neumann  * @frame: HDMI SPD infoframe
106528ba7809SMichael Neumann  *
106628ba7809SMichael Neumann  * Unpacks the information contained in binary @buffer into a structured
106728ba7809SMichael Neumann  * @frame of the HDMI Source Product Description (SPD) information frame.
106828ba7809SMichael Neumann  * Also verifies the checksum as required by section 5.3.5 of the HDMI 1.4
106928ba7809SMichael Neumann  * specification.
107028ba7809SMichael Neumann  *
107128ba7809SMichael Neumann  * Returns 0 on success or a negative error code on failure.
107228ba7809SMichael Neumann  */
hdmi_spd_infoframe_unpack(struct hdmi_spd_infoframe * frame,void * buffer)107328ba7809SMichael Neumann static int hdmi_spd_infoframe_unpack(struct hdmi_spd_infoframe *frame,
107428ba7809SMichael Neumann 				     void *buffer)
107528ba7809SMichael Neumann {
107628ba7809SMichael Neumann 	u8 *ptr = buffer;
107728ba7809SMichael Neumann 	int ret;
107828ba7809SMichael Neumann 
107928ba7809SMichael Neumann 	if (ptr[0] != HDMI_INFOFRAME_TYPE_SPD ||
108028ba7809SMichael Neumann 	    ptr[1] != 1 ||
108128ba7809SMichael Neumann 	    ptr[2] != HDMI_SPD_INFOFRAME_SIZE) {
108228ba7809SMichael Neumann 		return -EINVAL;
108328ba7809SMichael Neumann 	}
108428ba7809SMichael Neumann 
108528ba7809SMichael Neumann 	if (hdmi_infoframe_checksum(buffer, HDMI_INFOFRAME_SIZE(SPD)) != 0)
108628ba7809SMichael Neumann 		return -EINVAL;
108728ba7809SMichael Neumann 
108828ba7809SMichael Neumann 	ptr += HDMI_INFOFRAME_HEADER_SIZE;
108928ba7809SMichael Neumann 
109028ba7809SMichael Neumann 	ret = hdmi_spd_infoframe_init(frame, ptr, ptr + 8);
109128ba7809SMichael Neumann 	if (ret)
109228ba7809SMichael Neumann 		return ret;
109328ba7809SMichael Neumann 
109428ba7809SMichael Neumann 	frame->sdi = ptr[24];
109528ba7809SMichael Neumann 
109628ba7809SMichael Neumann 	return 0;
109728ba7809SMichael Neumann }
109828ba7809SMichael Neumann 
109928ba7809SMichael Neumann /**
110028ba7809SMichael Neumann  * hdmi_audio_infoframe_unpack() - unpack binary buffer to a HDMI AUDIO infoframe
110128ba7809SMichael Neumann  * @buffer: source buffer
110228ba7809SMichael Neumann  * @frame: HDMI Audio infoframe
110328ba7809SMichael Neumann  *
110428ba7809SMichael Neumann  * Unpacks the information contained in binary @buffer into a structured
110528ba7809SMichael Neumann  * @frame of the HDMI Audio information frame.
110628ba7809SMichael Neumann  * Also verifies the checksum as required by section 5.3.5 of the HDMI 1.4
110728ba7809SMichael Neumann  * specification.
110828ba7809SMichael Neumann  *
110928ba7809SMichael Neumann  * Returns 0 on success or a negative error code on failure.
111028ba7809SMichael Neumann  */
hdmi_audio_infoframe_unpack(struct hdmi_audio_infoframe * frame,void * buffer)111128ba7809SMichael Neumann static int hdmi_audio_infoframe_unpack(struct hdmi_audio_infoframe *frame,
111228ba7809SMichael Neumann 				       void *buffer)
111328ba7809SMichael Neumann {
111428ba7809SMichael Neumann 	u8 *ptr = buffer;
111528ba7809SMichael Neumann 	int ret;
111628ba7809SMichael Neumann 
111728ba7809SMichael Neumann 	if (ptr[0] != HDMI_INFOFRAME_TYPE_AUDIO ||
111828ba7809SMichael Neumann 	    ptr[1] != 1 ||
111928ba7809SMichael Neumann 	    ptr[2] != HDMI_AUDIO_INFOFRAME_SIZE) {
112028ba7809SMichael Neumann 		return -EINVAL;
112128ba7809SMichael Neumann 	}
112228ba7809SMichael Neumann 
112328ba7809SMichael Neumann 	if (hdmi_infoframe_checksum(buffer, HDMI_INFOFRAME_SIZE(AUDIO)) != 0)
112428ba7809SMichael Neumann 		return -EINVAL;
112528ba7809SMichael Neumann 
112628ba7809SMichael Neumann 	ret = hdmi_audio_infoframe_init(frame);
112728ba7809SMichael Neumann 	if (ret)
112828ba7809SMichael Neumann 		return ret;
112928ba7809SMichael Neumann 
113028ba7809SMichael Neumann 	ptr += HDMI_INFOFRAME_HEADER_SIZE;
113128ba7809SMichael Neumann 
113228ba7809SMichael Neumann 	frame->channels = ptr[0] & 0x7;
113328ba7809SMichael Neumann 	frame->coding_type = (ptr[0] >> 4) & 0xf;
113428ba7809SMichael Neumann 	frame->sample_size = ptr[1] & 0x3;
113528ba7809SMichael Neumann 	frame->sample_frequency = (ptr[1] >> 2) & 0x7;
113628ba7809SMichael Neumann 	frame->coding_type_ext = ptr[2] & 0x1f;
113728ba7809SMichael Neumann 	frame->channel_allocation = ptr[3];
113828ba7809SMichael Neumann 	frame->level_shift_value = (ptr[4] >> 3) & 0xf;
113928ba7809SMichael Neumann 	frame->downmix_inhibit = ptr[4] & 0x80 ? true : false;
114028ba7809SMichael Neumann 
114128ba7809SMichael Neumann 	return 0;
114228ba7809SMichael Neumann }
114328ba7809SMichael Neumann 
114428ba7809SMichael Neumann /**
114528ba7809SMichael Neumann  * hdmi_vendor_infoframe_unpack() - unpack binary buffer to a HDMI vendor infoframe
114628ba7809SMichael Neumann  * @buffer: source buffer
114728ba7809SMichael Neumann  * @frame: HDMI Vendor infoframe
114828ba7809SMichael Neumann  *
114928ba7809SMichael Neumann  * Unpacks the information contained in binary @buffer into a structured
115028ba7809SMichael Neumann  * @frame of the HDMI Vendor information frame.
115128ba7809SMichael Neumann  * Also verifies the checksum as required by section 5.3.5 of the HDMI 1.4
115228ba7809SMichael Neumann  * specification.
115328ba7809SMichael Neumann  *
115428ba7809SMichael Neumann  * Returns 0 on success or a negative error code on failure.
115528ba7809SMichael Neumann  */
115628ba7809SMichael Neumann static int
hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe * frame,void * buffer)115728ba7809SMichael Neumann hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
115828ba7809SMichael Neumann 				 void *buffer)
115928ba7809SMichael Neumann {
116028ba7809SMichael Neumann 	u8 *ptr = buffer;
116128ba7809SMichael Neumann 	size_t length;
116228ba7809SMichael Neumann 	int ret;
116328ba7809SMichael Neumann 	u8 hdmi_video_format;
116428ba7809SMichael Neumann 	struct hdmi_vendor_infoframe *hvf = &frame->hdmi;
116528ba7809SMichael Neumann 
116628ba7809SMichael Neumann 	if (ptr[0] != HDMI_INFOFRAME_TYPE_VENDOR ||
116728ba7809SMichael Neumann 	    ptr[1] != 1 ||
116828ba7809SMichael Neumann 	    (ptr[2] != 5 && ptr[2] != 6))
116928ba7809SMichael Neumann 		return -EINVAL;
117028ba7809SMichael Neumann 
117128ba7809SMichael Neumann 	length = ptr[2];
117228ba7809SMichael Neumann 
117328ba7809SMichael Neumann 	if (hdmi_infoframe_checksum(buffer,
117428ba7809SMichael Neumann 				    HDMI_INFOFRAME_HEADER_SIZE + length) != 0)
117528ba7809SMichael Neumann 		return -EINVAL;
117628ba7809SMichael Neumann 
117728ba7809SMichael Neumann 	ptr += HDMI_INFOFRAME_HEADER_SIZE;
117828ba7809SMichael Neumann 
117928ba7809SMichael Neumann 	/* HDMI OUI */
118028ba7809SMichael Neumann 	if ((ptr[0] != 0x03) ||
118128ba7809SMichael Neumann 	    (ptr[1] != 0x0c) ||
118228ba7809SMichael Neumann 	    (ptr[2] != 0x00))
118328ba7809SMichael Neumann 		return -EINVAL;
118428ba7809SMichael Neumann 
118528ba7809SMichael Neumann 	hdmi_video_format = ptr[3] >> 5;
118628ba7809SMichael Neumann 
118728ba7809SMichael Neumann 	if (hdmi_video_format > 0x2)
118828ba7809SMichael Neumann 		return -EINVAL;
118928ba7809SMichael Neumann 
119028ba7809SMichael Neumann 	ret = hdmi_vendor_infoframe_init(hvf);
119128ba7809SMichael Neumann 	if (ret)
119228ba7809SMichael Neumann 		return ret;
119328ba7809SMichael Neumann 
119428ba7809SMichael Neumann 	hvf->length = length;
119528ba7809SMichael Neumann 
119628ba7809SMichael Neumann 	if (hdmi_video_format == 0x1) {
119728ba7809SMichael Neumann 		hvf->vic = ptr[4];
119828ba7809SMichael Neumann 	} else if (hdmi_video_format == 0x2) {
119928ba7809SMichael Neumann 		hvf->s3d_struct = ptr[4] >> 4;
120028ba7809SMichael Neumann 		if (hvf->s3d_struct >= HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF) {
120128ba7809SMichael Neumann 			if (length == 6)
120228ba7809SMichael Neumann 				hvf->s3d_ext_data = ptr[5] >> 4;
120328ba7809SMichael Neumann 			else
120428ba7809SMichael Neumann 				return -EINVAL;
120528ba7809SMichael Neumann 		}
120628ba7809SMichael Neumann 	}
120728ba7809SMichael Neumann 
120828ba7809SMichael Neumann 	return 0;
120928ba7809SMichael Neumann }
121028ba7809SMichael Neumann 
121128ba7809SMichael Neumann /**
121228ba7809SMichael Neumann  * hdmi_infoframe_unpack() - unpack binary buffer to a HDMI infoframe
121328ba7809SMichael Neumann  * @buffer: source buffer
121428ba7809SMichael Neumann  * @frame: HDMI infoframe
121528ba7809SMichael Neumann  *
121628ba7809SMichael Neumann  * Unpacks the information contained in binary buffer @buffer into a structured
121728ba7809SMichael Neumann  * @frame of a HDMI infoframe.
121828ba7809SMichael Neumann  * Also verifies the checksum as required by section 5.3.5 of the HDMI 1.4
121928ba7809SMichael Neumann  * specification.
122028ba7809SMichael Neumann  *
122128ba7809SMichael Neumann  * Returns 0 on success or a negative error code on failure.
122228ba7809SMichael Neumann  */
hdmi_infoframe_unpack(union hdmi_infoframe * frame,void * buffer)122328ba7809SMichael Neumann int hdmi_infoframe_unpack(union hdmi_infoframe *frame, void *buffer)
122428ba7809SMichael Neumann {
122528ba7809SMichael Neumann 	int ret;
122628ba7809SMichael Neumann 	u8 *ptr = buffer;
122728ba7809SMichael Neumann 
122828ba7809SMichael Neumann 	switch (ptr[0]) {
122928ba7809SMichael Neumann 	case HDMI_INFOFRAME_TYPE_AVI:
123028ba7809SMichael Neumann 		ret = hdmi_avi_infoframe_unpack(&frame->avi, buffer);
123128ba7809SMichael Neumann 		break;
123228ba7809SMichael Neumann 	case HDMI_INFOFRAME_TYPE_SPD:
123328ba7809SMichael Neumann 		ret = hdmi_spd_infoframe_unpack(&frame->spd, buffer);
123428ba7809SMichael Neumann 		break;
123528ba7809SMichael Neumann 	case HDMI_INFOFRAME_TYPE_AUDIO:
123628ba7809SMichael Neumann 		ret = hdmi_audio_infoframe_unpack(&frame->audio, buffer);
123728ba7809SMichael Neumann 		break;
123828ba7809SMichael Neumann 	case HDMI_INFOFRAME_TYPE_VENDOR:
123928ba7809SMichael Neumann 		ret = hdmi_vendor_any_infoframe_unpack(&frame->vendor, buffer);
124028ba7809SMichael Neumann 		break;
124128ba7809SMichael Neumann 	default:
124228ba7809SMichael Neumann 		ret = -EINVAL;
124328ba7809SMichael Neumann 		break;
124428ba7809SMichael Neumann 	}
124528ba7809SMichael Neumann 
124628ba7809SMichael Neumann 	return ret;
124728ba7809SMichael Neumann }
124828ba7809SMichael Neumann EXPORT_SYMBOL(hdmi_infoframe_unpack);
1249