1f142d3bdSThierry Reding /*
2f142d3bdSThierry Reding * Copyright (C) 2012 Avionic Design GmbH
3f142d3bdSThierry Reding *
496d672e0SThierry Reding * Permission is hereby granted, free of charge, to any person obtaining a
596d672e0SThierry Reding * copy of this software and associated documentation files (the "Software"),
696d672e0SThierry Reding * to deal in the Software without restriction, including without limitation
796d672e0SThierry Reding * the rights to use, copy, modify, merge, publish, distribute, sub license,
896d672e0SThierry Reding * and/or sell copies of the Software, and to permit persons to whom the
996d672e0SThierry Reding * Software is furnished to do so, subject to the following conditions:
1096d672e0SThierry Reding *
1196d672e0SThierry Reding * The above copyright notice and this permission notice (including the
1296d672e0SThierry Reding * next paragraph) shall be included in all copies or substantial portions
1396d672e0SThierry Reding * of the Software.
1496d672e0SThierry Reding *
1596d672e0SThierry Reding * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1696d672e0SThierry Reding * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1796d672e0SThierry Reding * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
1896d672e0SThierry Reding * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1996d672e0SThierry Reding * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
2096d672e0SThierry Reding * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
2196d672e0SThierry Reding * DEALINGS IN THE SOFTWARE.
22f142d3bdSThierry Reding */
23f142d3bdSThierry Reding
24*f89aa0b6SMarkus Schneider-Pargmann #include <drm/display/drm_dp.h>
25f142d3bdSThierry Reding #include <linux/bitops.h>
2672b09896SDamien Lespiau #include <linux/bug.h>
27f142d3bdSThierry Reding #include <linux/errno.h>
28f142d3bdSThierry Reding #include <linux/export.h>
29f142d3bdSThierry Reding #include <linux/hdmi.h>
30f142d3bdSThierry Reding #include <linux/string.h>
312c676f37SMartin Bugge #include <linux/device.h>
32f142d3bdSThierry Reding
332c676f37SMartin Bugge #define hdmi_log(fmt, ...) dev_printk(level, dev, fmt, ##__VA_ARGS__)
342c676f37SMartin Bugge
hdmi_infoframe_checksum(const u8 * ptr,size_t size)35f26e1de5SVille Syrjälä static u8 hdmi_infoframe_checksum(const u8 *ptr, size_t size)
36f142d3bdSThierry Reding {
37f142d3bdSThierry Reding u8 csum = 0;
38f142d3bdSThierry Reding size_t i;
39f142d3bdSThierry Reding
40f142d3bdSThierry Reding /* compute checksum */
41f142d3bdSThierry Reding for (i = 0; i < size; i++)
42f142d3bdSThierry Reding csum += ptr[i];
43f142d3bdSThierry Reding
442c676f37SMartin Bugge return 256 - csum;
452c676f37SMartin Bugge }
462c676f37SMartin Bugge
hdmi_infoframe_set_checksum(void * buffer,size_t size)472c676f37SMartin Bugge static void hdmi_infoframe_set_checksum(void *buffer, size_t size)
482c676f37SMartin Bugge {
492c676f37SMartin Bugge u8 *ptr = buffer;
502c676f37SMartin Bugge
512c676f37SMartin Bugge ptr[3] = hdmi_infoframe_checksum(buffer, size);
52f142d3bdSThierry Reding }
53f142d3bdSThierry Reding
54f142d3bdSThierry Reding /**
55f142d3bdSThierry Reding * hdmi_avi_infoframe_init() - initialize an HDMI AVI infoframe
56f142d3bdSThierry Reding * @frame: HDMI AVI infoframe
57f142d3bdSThierry Reding */
hdmi_avi_infoframe_init(struct hdmi_avi_infoframe * frame)585ee0caf1SLaurent Pinchart void hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame)
59f142d3bdSThierry Reding {
60f142d3bdSThierry Reding memset(frame, 0, sizeof(*frame));
61f142d3bdSThierry Reding
62f142d3bdSThierry Reding frame->type = HDMI_INFOFRAME_TYPE_AVI;
63f142d3bdSThierry Reding frame->version = 2;
643c6b054dSDamien Lespiau frame->length = HDMI_AVI_INFOFRAME_SIZE;
65f142d3bdSThierry Reding }
66f142d3bdSThierry Reding EXPORT_SYMBOL(hdmi_avi_infoframe_init);
67f142d3bdSThierry Reding
hdmi_avi_infoframe_check_only(const struct hdmi_avi_infoframe * frame)68c5e69ab3SVille Syrjälä static int hdmi_avi_infoframe_check_only(const struct hdmi_avi_infoframe *frame)
69c5e69ab3SVille Syrjälä {
70c5e69ab3SVille Syrjälä if (frame->type != HDMI_INFOFRAME_TYPE_AVI ||
71c5e69ab3SVille Syrjälä frame->version != 2 ||
72c5e69ab3SVille Syrjälä frame->length != HDMI_AVI_INFOFRAME_SIZE)
73c5e69ab3SVille Syrjälä return -EINVAL;
74c5e69ab3SVille Syrjälä
75c5e69ab3SVille Syrjälä if (frame->picture_aspect > HDMI_PICTURE_ASPECT_16_9)
76c5e69ab3SVille Syrjälä return -EINVAL;
77c5e69ab3SVille Syrjälä
78c5e69ab3SVille Syrjälä return 0;
79c5e69ab3SVille Syrjälä }
80c5e69ab3SVille Syrjälä
81f142d3bdSThierry Reding /**
82c5e69ab3SVille Syrjälä * hdmi_avi_infoframe_check() - check a HDMI AVI infoframe
83c5e69ab3SVille Syrjälä * @frame: HDMI AVI infoframe
84c5e69ab3SVille Syrjälä *
85c5e69ab3SVille Syrjälä * Validates that the infoframe is consistent and updates derived fields
86c5e69ab3SVille Syrjälä * (eg. length) based on other fields.
87c5e69ab3SVille Syrjälä *
88c5e69ab3SVille Syrjälä * Returns 0 on success or a negative error code on failure.
89c5e69ab3SVille Syrjälä */
hdmi_avi_infoframe_check(struct hdmi_avi_infoframe * frame)90c5e69ab3SVille Syrjälä int hdmi_avi_infoframe_check(struct hdmi_avi_infoframe *frame)
91c5e69ab3SVille Syrjälä {
92c5e69ab3SVille Syrjälä return hdmi_avi_infoframe_check_only(frame);
93c5e69ab3SVille Syrjälä }
94c5e69ab3SVille Syrjälä EXPORT_SYMBOL(hdmi_avi_infoframe_check);
95c5e69ab3SVille Syrjälä
96c5e69ab3SVille Syrjälä /**
97c5e69ab3SVille Syrjälä * hdmi_avi_infoframe_pack_only() - write HDMI AVI infoframe to binary buffer
98f142d3bdSThierry Reding * @frame: HDMI AVI infoframe
99f142d3bdSThierry Reding * @buffer: destination buffer
100f142d3bdSThierry Reding * @size: size of buffer
101f142d3bdSThierry Reding *
102f142d3bdSThierry Reding * Packs the information contained in the @frame structure into a binary
103f142d3bdSThierry Reding * representation that can be written into the corresponding controller
104f142d3bdSThierry Reding * registers. Also computes the checksum as required by section 5.3.5 of
105f142d3bdSThierry Reding * the HDMI 1.4 specification.
106f142d3bdSThierry Reding *
107f142d3bdSThierry Reding * Returns the number of bytes packed into the binary buffer or a negative
108f142d3bdSThierry Reding * error code on failure.
109f142d3bdSThierry Reding */
hdmi_avi_infoframe_pack_only(const struct hdmi_avi_infoframe * frame,void * buffer,size_t size)110c5e69ab3SVille Syrjälä ssize_t hdmi_avi_infoframe_pack_only(const struct hdmi_avi_infoframe *frame,
111c5e69ab3SVille Syrjälä void *buffer, size_t size)
112f142d3bdSThierry Reding {
113f142d3bdSThierry Reding u8 *ptr = buffer;
114f142d3bdSThierry Reding size_t length;
115c5e69ab3SVille Syrjälä int ret;
116c5e69ab3SVille Syrjälä
117c5e69ab3SVille Syrjälä ret = hdmi_avi_infoframe_check_only(frame);
118c5e69ab3SVille Syrjälä if (ret)
119c5e69ab3SVille Syrjälä return ret;
120f142d3bdSThierry Reding
121f142d3bdSThierry Reding length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
122f142d3bdSThierry Reding
123f142d3bdSThierry Reding if (size < length)
124f142d3bdSThierry Reding return -ENOSPC;
125f142d3bdSThierry Reding
1263b390f62SDamien Lespiau memset(buffer, 0, size);
127f142d3bdSThierry Reding
128f142d3bdSThierry Reding ptr[0] = frame->type;
129f142d3bdSThierry Reding ptr[1] = frame->version;
130f142d3bdSThierry Reding ptr[2] = frame->length;
131f142d3bdSThierry Reding ptr[3] = 0; /* checksum */
132f142d3bdSThierry Reding
133f142d3bdSThierry Reding /* start infoframe payload */
134f142d3bdSThierry Reding ptr += HDMI_INFOFRAME_HEADER_SIZE;
135f142d3bdSThierry Reding
136f142d3bdSThierry Reding ptr[0] = ((frame->colorspace & 0x3) << 5) | (frame->scan_mode & 0x3);
137f142d3bdSThierry Reding
138a5ad3dcfSLespiau, Damien /*
139a5ad3dcfSLespiau, Damien * Data byte 1, bit 4 has to be set if we provide the active format
140a5ad3dcfSLespiau, Damien * aspect ratio
141a5ad3dcfSLespiau, Damien */
142a5ad3dcfSLespiau, Damien if (frame->active_aspect & 0xf)
143f142d3bdSThierry Reding ptr[0] |= BIT(4);
144f142d3bdSThierry Reding
145974e0701SLespiau, Damien /* Bit 3 and 2 indicate if we transmit horizontal/vertical bar data */
146974e0701SLespiau, Damien if (frame->top_bar || frame->bottom_bar)
147f142d3bdSThierry Reding ptr[0] |= BIT(3);
148f142d3bdSThierry Reding
149974e0701SLespiau, Damien if (frame->left_bar || frame->right_bar)
150f142d3bdSThierry Reding ptr[0] |= BIT(2);
151f142d3bdSThierry Reding
152f142d3bdSThierry Reding ptr[1] = ((frame->colorimetry & 0x3) << 6) |
153f142d3bdSThierry Reding ((frame->picture_aspect & 0x3) << 4) |
154f142d3bdSThierry Reding (frame->active_aspect & 0xf);
155f142d3bdSThierry Reding
156f142d3bdSThierry Reding ptr[2] = ((frame->extended_colorimetry & 0x7) << 4) |
157f142d3bdSThierry Reding ((frame->quantization_range & 0x3) << 2) |
158f142d3bdSThierry Reding (frame->nups & 0x3);
159f142d3bdSThierry Reding
160f142d3bdSThierry Reding if (frame->itc)
161f142d3bdSThierry Reding ptr[2] |= BIT(7);
162f142d3bdSThierry Reding
163f142d3bdSThierry Reding ptr[3] = frame->video_code & 0x7f;
164f142d3bdSThierry Reding
165f142d3bdSThierry Reding ptr[4] = ((frame->ycc_quantization_range & 0x3) << 6) |
166f142d3bdSThierry Reding ((frame->content_type & 0x3) << 4) |
167f142d3bdSThierry Reding (frame->pixel_repeat & 0xf);
168f142d3bdSThierry Reding
169f142d3bdSThierry Reding ptr[5] = frame->top_bar & 0xff;
170f142d3bdSThierry Reding ptr[6] = (frame->top_bar >> 8) & 0xff;
171f142d3bdSThierry Reding ptr[7] = frame->bottom_bar & 0xff;
172f142d3bdSThierry Reding ptr[8] = (frame->bottom_bar >> 8) & 0xff;
173f142d3bdSThierry Reding ptr[9] = frame->left_bar & 0xff;
174f142d3bdSThierry Reding ptr[10] = (frame->left_bar >> 8) & 0xff;
175f142d3bdSThierry Reding ptr[11] = frame->right_bar & 0xff;
176f142d3bdSThierry Reding ptr[12] = (frame->right_bar >> 8) & 0xff;
177f142d3bdSThierry Reding
1782c676f37SMartin Bugge hdmi_infoframe_set_checksum(buffer, length);
179f142d3bdSThierry Reding
180f142d3bdSThierry Reding return length;
181f142d3bdSThierry Reding }
182c5e69ab3SVille Syrjälä EXPORT_SYMBOL(hdmi_avi_infoframe_pack_only);
183c5e69ab3SVille Syrjälä
184c5e69ab3SVille Syrjälä /**
185c5e69ab3SVille Syrjälä * hdmi_avi_infoframe_pack() - check a HDMI AVI infoframe,
186c5e69ab3SVille Syrjälä * and write it to binary buffer
187c5e69ab3SVille Syrjälä * @frame: HDMI AVI infoframe
188c5e69ab3SVille Syrjälä * @buffer: destination buffer
189c5e69ab3SVille Syrjälä * @size: size of buffer
190c5e69ab3SVille Syrjälä *
191c5e69ab3SVille Syrjälä * Validates that the infoframe is consistent and updates derived fields
192c5e69ab3SVille Syrjälä * (eg. length) based on other fields, after which it packs the information
193c5e69ab3SVille Syrjälä * contained in the @frame structure into a binary representation that
194c5e69ab3SVille Syrjälä * can be written into the corresponding controller registers. This function
195c5e69ab3SVille Syrjälä * also computes the checksum as required by section 5.3.5 of the HDMI 1.4
196c5e69ab3SVille Syrjälä * specification.
197c5e69ab3SVille Syrjälä *
198c5e69ab3SVille Syrjälä * Returns the number of bytes packed into the binary buffer or a negative
199c5e69ab3SVille Syrjälä * error code on failure.
200c5e69ab3SVille Syrjälä */
hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe * frame,void * buffer,size_t size)201c5e69ab3SVille Syrjälä ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame,
202c5e69ab3SVille Syrjälä void *buffer, size_t size)
203c5e69ab3SVille Syrjälä {
204c5e69ab3SVille Syrjälä int ret;
205c5e69ab3SVille Syrjälä
206c5e69ab3SVille Syrjälä ret = hdmi_avi_infoframe_check(frame);
207c5e69ab3SVille Syrjälä if (ret)
208c5e69ab3SVille Syrjälä return ret;
209c5e69ab3SVille Syrjälä
210c5e69ab3SVille Syrjälä return hdmi_avi_infoframe_pack_only(frame, buffer, size);
211c5e69ab3SVille Syrjälä }
212f142d3bdSThierry Reding EXPORT_SYMBOL(hdmi_avi_infoframe_pack);
213f142d3bdSThierry Reding
214f142d3bdSThierry Reding /**
215f142d3bdSThierry Reding * hdmi_spd_infoframe_init() - initialize an HDMI SPD infoframe
216f142d3bdSThierry Reding * @frame: HDMI SPD infoframe
217f142d3bdSThierry Reding * @vendor: vendor string
218f142d3bdSThierry Reding * @product: product string
219f142d3bdSThierry Reding *
220f142d3bdSThierry Reding * Returns 0 on success or a negative error code on failure.
221f142d3bdSThierry Reding */
hdmi_spd_infoframe_init(struct hdmi_spd_infoframe * frame,const char * vendor,const char * product)222f142d3bdSThierry Reding int hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame,
223f142d3bdSThierry Reding const char *vendor, const char *product)
224f142d3bdSThierry Reding {
22535bed3faSThomas Zimmermann size_t len;
22635bed3faSThomas Zimmermann
227f142d3bdSThierry Reding memset(frame, 0, sizeof(*frame));
228f142d3bdSThierry Reding
229f142d3bdSThierry Reding frame->type = HDMI_INFOFRAME_TYPE_SPD;
230f142d3bdSThierry Reding frame->version = 1;
2313c6b054dSDamien Lespiau frame->length = HDMI_SPD_INFOFRAME_SIZE;
232f142d3bdSThierry Reding
23335bed3faSThomas Zimmermann len = strlen(vendor);
23435bed3faSThomas Zimmermann memcpy(frame->vendor, vendor, min(len, sizeof(frame->vendor)));
23535bed3faSThomas Zimmermann len = strlen(product);
23635bed3faSThomas Zimmermann memcpy(frame->product, product, min(len, sizeof(frame->product)));
237f142d3bdSThierry Reding
238f142d3bdSThierry Reding return 0;
239f142d3bdSThierry Reding }
240f142d3bdSThierry Reding EXPORT_SYMBOL(hdmi_spd_infoframe_init);
241f142d3bdSThierry Reding
hdmi_spd_infoframe_check_only(const struct hdmi_spd_infoframe * frame)242c5e69ab3SVille Syrjälä static int hdmi_spd_infoframe_check_only(const struct hdmi_spd_infoframe *frame)
243c5e69ab3SVille Syrjälä {
244c5e69ab3SVille Syrjälä if (frame->type != HDMI_INFOFRAME_TYPE_SPD ||
245c5e69ab3SVille Syrjälä frame->version != 1 ||
246c5e69ab3SVille Syrjälä frame->length != HDMI_SPD_INFOFRAME_SIZE)
247c5e69ab3SVille Syrjälä return -EINVAL;
248c5e69ab3SVille Syrjälä
249c5e69ab3SVille Syrjälä return 0;
250c5e69ab3SVille Syrjälä }
251c5e69ab3SVille Syrjälä
252f142d3bdSThierry Reding /**
253c5e69ab3SVille Syrjälä * hdmi_spd_infoframe_check() - check a HDMI SPD infoframe
254c5e69ab3SVille Syrjälä * @frame: HDMI SPD infoframe
255c5e69ab3SVille Syrjälä *
256c5e69ab3SVille Syrjälä * Validates that the infoframe is consistent and updates derived fields
257c5e69ab3SVille Syrjälä * (eg. length) based on other fields.
258c5e69ab3SVille Syrjälä *
259c5e69ab3SVille Syrjälä * Returns 0 on success or a negative error code on failure.
260c5e69ab3SVille Syrjälä */
hdmi_spd_infoframe_check(struct hdmi_spd_infoframe * frame)261c5e69ab3SVille Syrjälä int hdmi_spd_infoframe_check(struct hdmi_spd_infoframe *frame)
262c5e69ab3SVille Syrjälä {
263c5e69ab3SVille Syrjälä return hdmi_spd_infoframe_check_only(frame);
264c5e69ab3SVille Syrjälä }
265c5e69ab3SVille Syrjälä EXPORT_SYMBOL(hdmi_spd_infoframe_check);
266c5e69ab3SVille Syrjälä
267c5e69ab3SVille Syrjälä /**
268c5e69ab3SVille Syrjälä * hdmi_spd_infoframe_pack_only() - write HDMI SPD infoframe to binary buffer
269f142d3bdSThierry Reding * @frame: HDMI SPD infoframe
270f142d3bdSThierry Reding * @buffer: destination buffer
271f142d3bdSThierry Reding * @size: size of buffer
272f142d3bdSThierry Reding *
273f142d3bdSThierry Reding * Packs the information contained in the @frame structure into a binary
274f142d3bdSThierry Reding * representation that can be written into the corresponding controller
275f142d3bdSThierry Reding * registers. Also computes the checksum as required by section 5.3.5 of
276f142d3bdSThierry Reding * the HDMI 1.4 specification.
277f142d3bdSThierry Reding *
278f142d3bdSThierry Reding * Returns the number of bytes packed into the binary buffer or a negative
279f142d3bdSThierry Reding * error code on failure.
280f142d3bdSThierry Reding */
hdmi_spd_infoframe_pack_only(const struct hdmi_spd_infoframe * frame,void * buffer,size_t size)281c5e69ab3SVille Syrjälä ssize_t hdmi_spd_infoframe_pack_only(const struct hdmi_spd_infoframe *frame,
282c5e69ab3SVille Syrjälä void *buffer, size_t size)
283f142d3bdSThierry Reding {
284f142d3bdSThierry Reding u8 *ptr = buffer;
285f142d3bdSThierry Reding size_t length;
286c5e69ab3SVille Syrjälä int ret;
287c5e69ab3SVille Syrjälä
288c5e69ab3SVille Syrjälä ret = hdmi_spd_infoframe_check_only(frame);
289c5e69ab3SVille Syrjälä if (ret)
290c5e69ab3SVille Syrjälä return ret;
291f142d3bdSThierry Reding
292f142d3bdSThierry Reding length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
293f142d3bdSThierry Reding
294f142d3bdSThierry Reding if (size < length)
295f142d3bdSThierry Reding return -ENOSPC;
296f142d3bdSThierry Reding
2973b390f62SDamien Lespiau memset(buffer, 0, size);
298f142d3bdSThierry Reding
299f142d3bdSThierry Reding ptr[0] = frame->type;
300f142d3bdSThierry Reding ptr[1] = frame->version;
301f142d3bdSThierry Reding ptr[2] = frame->length;
302f142d3bdSThierry Reding ptr[3] = 0; /* checksum */
303f142d3bdSThierry Reding
304f142d3bdSThierry Reding /* start infoframe payload */
305f142d3bdSThierry Reding ptr += HDMI_INFOFRAME_HEADER_SIZE;
306f142d3bdSThierry Reding
307f142d3bdSThierry Reding memcpy(ptr, frame->vendor, sizeof(frame->vendor));
308f142d3bdSThierry Reding memcpy(ptr + 8, frame->product, sizeof(frame->product));
309f142d3bdSThierry Reding
310f142d3bdSThierry Reding ptr[24] = frame->sdi;
311f142d3bdSThierry Reding
3122c676f37SMartin Bugge hdmi_infoframe_set_checksum(buffer, length);
313f142d3bdSThierry Reding
314f142d3bdSThierry Reding return length;
315f142d3bdSThierry Reding }
316c5e69ab3SVille Syrjälä EXPORT_SYMBOL(hdmi_spd_infoframe_pack_only);
317c5e69ab3SVille Syrjälä
318c5e69ab3SVille Syrjälä /**
319c5e69ab3SVille Syrjälä * hdmi_spd_infoframe_pack() - check a HDMI SPD infoframe,
320c5e69ab3SVille Syrjälä * and write it to binary buffer
321c5e69ab3SVille Syrjälä * @frame: HDMI SPD infoframe
322c5e69ab3SVille Syrjälä * @buffer: destination buffer
323c5e69ab3SVille Syrjälä * @size: size of buffer
324c5e69ab3SVille Syrjälä *
325c5e69ab3SVille Syrjälä * Validates that the infoframe is consistent and updates derived fields
326c5e69ab3SVille Syrjälä * (eg. length) based on other fields, after which it packs the information
327c5e69ab3SVille Syrjälä * contained in the @frame structure into a binary representation that
328c5e69ab3SVille Syrjälä * can be written into the corresponding controller registers. This function
329c5e69ab3SVille Syrjälä * also computes the checksum as required by section 5.3.5 of the HDMI 1.4
330c5e69ab3SVille Syrjälä * specification.
331c5e69ab3SVille Syrjälä *
332c5e69ab3SVille Syrjälä * Returns the number of bytes packed into the binary buffer or a negative
333c5e69ab3SVille Syrjälä * error code on failure.
334c5e69ab3SVille Syrjälä */
hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe * frame,void * buffer,size_t size)335c5e69ab3SVille Syrjälä ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame,
336c5e69ab3SVille Syrjälä void *buffer, size_t size)
337c5e69ab3SVille Syrjälä {
338c5e69ab3SVille Syrjälä int ret;
339c5e69ab3SVille Syrjälä
340c5e69ab3SVille Syrjälä ret = hdmi_spd_infoframe_check(frame);
341c5e69ab3SVille Syrjälä if (ret)
342c5e69ab3SVille Syrjälä return ret;
343c5e69ab3SVille Syrjälä
344c5e69ab3SVille Syrjälä return hdmi_spd_infoframe_pack_only(frame, buffer, size);
345c5e69ab3SVille Syrjälä }
346f142d3bdSThierry Reding EXPORT_SYMBOL(hdmi_spd_infoframe_pack);
347f142d3bdSThierry Reding
348f142d3bdSThierry Reding /**
349f142d3bdSThierry Reding * hdmi_audio_infoframe_init() - initialize an HDMI audio infoframe
350f142d3bdSThierry Reding * @frame: HDMI audio infoframe
351f142d3bdSThierry Reding *
352f142d3bdSThierry Reding * Returns 0 on success or a negative error code on failure.
353f142d3bdSThierry Reding */
hdmi_audio_infoframe_init(struct hdmi_audio_infoframe * frame)354f142d3bdSThierry Reding int hdmi_audio_infoframe_init(struct hdmi_audio_infoframe *frame)
355f142d3bdSThierry Reding {
356f142d3bdSThierry Reding memset(frame, 0, sizeof(*frame));
357f142d3bdSThierry Reding
358f142d3bdSThierry Reding frame->type = HDMI_INFOFRAME_TYPE_AUDIO;
359f142d3bdSThierry Reding frame->version = 1;
3603c6b054dSDamien Lespiau frame->length = HDMI_AUDIO_INFOFRAME_SIZE;
361f142d3bdSThierry Reding
362f142d3bdSThierry Reding return 0;
363f142d3bdSThierry Reding }
364f142d3bdSThierry Reding EXPORT_SYMBOL(hdmi_audio_infoframe_init);
365f142d3bdSThierry Reding
hdmi_audio_infoframe_check_only(const struct hdmi_audio_infoframe * frame)366c5e69ab3SVille Syrjälä static int hdmi_audio_infoframe_check_only(const struct hdmi_audio_infoframe *frame)
367c5e69ab3SVille Syrjälä {
368c5e69ab3SVille Syrjälä if (frame->type != HDMI_INFOFRAME_TYPE_AUDIO ||
369c5e69ab3SVille Syrjälä frame->version != 1 ||
370c5e69ab3SVille Syrjälä frame->length != HDMI_AUDIO_INFOFRAME_SIZE)
371c5e69ab3SVille Syrjälä return -EINVAL;
372c5e69ab3SVille Syrjälä
373c5e69ab3SVille Syrjälä return 0;
374c5e69ab3SVille Syrjälä }
375c5e69ab3SVille Syrjälä
376f142d3bdSThierry Reding /**
377c5e69ab3SVille Syrjälä * hdmi_audio_infoframe_check() - check a HDMI audio infoframe
378c5e69ab3SVille Syrjälä * @frame: HDMI audio infoframe
379c5e69ab3SVille Syrjälä *
380c5e69ab3SVille Syrjälä * Validates that the infoframe is consistent and updates derived fields
381c5e69ab3SVille Syrjälä * (eg. length) based on other fields.
382c5e69ab3SVille Syrjälä *
383c5e69ab3SVille Syrjälä * Returns 0 on success or a negative error code on failure.
384c5e69ab3SVille Syrjälä */
hdmi_audio_infoframe_check(const struct hdmi_audio_infoframe * frame)385*f89aa0b6SMarkus Schneider-Pargmann int hdmi_audio_infoframe_check(const struct hdmi_audio_infoframe *frame)
386c5e69ab3SVille Syrjälä {
387c5e69ab3SVille Syrjälä return hdmi_audio_infoframe_check_only(frame);
388c5e69ab3SVille Syrjälä }
389c5e69ab3SVille Syrjälä EXPORT_SYMBOL(hdmi_audio_infoframe_check);
390c5e69ab3SVille Syrjälä
391*f89aa0b6SMarkus Schneider-Pargmann static void
hdmi_audio_infoframe_pack_payload(const struct hdmi_audio_infoframe * frame,u8 * buffer)392*f89aa0b6SMarkus Schneider-Pargmann hdmi_audio_infoframe_pack_payload(const struct hdmi_audio_infoframe *frame,
393*f89aa0b6SMarkus Schneider-Pargmann u8 *buffer)
394*f89aa0b6SMarkus Schneider-Pargmann {
395*f89aa0b6SMarkus Schneider-Pargmann u8 channels;
396*f89aa0b6SMarkus Schneider-Pargmann
397*f89aa0b6SMarkus Schneider-Pargmann if (frame->channels >= 2)
398*f89aa0b6SMarkus Schneider-Pargmann channels = frame->channels - 1;
399*f89aa0b6SMarkus Schneider-Pargmann else
400*f89aa0b6SMarkus Schneider-Pargmann channels = 0;
401*f89aa0b6SMarkus Schneider-Pargmann
402*f89aa0b6SMarkus Schneider-Pargmann buffer[0] = ((frame->coding_type & 0xf) << 4) | (channels & 0x7);
403*f89aa0b6SMarkus Schneider-Pargmann buffer[1] = ((frame->sample_frequency & 0x7) << 2) |
404*f89aa0b6SMarkus Schneider-Pargmann (frame->sample_size & 0x3);
405*f89aa0b6SMarkus Schneider-Pargmann buffer[2] = frame->coding_type_ext & 0x1f;
406*f89aa0b6SMarkus Schneider-Pargmann buffer[3] = frame->channel_allocation;
407*f89aa0b6SMarkus Schneider-Pargmann buffer[4] = (frame->level_shift_value & 0xf) << 3;
408*f89aa0b6SMarkus Schneider-Pargmann
409*f89aa0b6SMarkus Schneider-Pargmann if (frame->downmix_inhibit)
410*f89aa0b6SMarkus Schneider-Pargmann buffer[4] |= BIT(7);
411*f89aa0b6SMarkus Schneider-Pargmann }
412*f89aa0b6SMarkus Schneider-Pargmann
413c5e69ab3SVille Syrjälä /**
414c5e69ab3SVille Syrjälä * hdmi_audio_infoframe_pack_only() - write HDMI audio infoframe to binary buffer
415f142d3bdSThierry Reding * @frame: HDMI audio infoframe
416f142d3bdSThierry Reding * @buffer: destination buffer
417f142d3bdSThierry Reding * @size: size of buffer
418f142d3bdSThierry Reding *
419f142d3bdSThierry Reding * Packs the information contained in the @frame structure into a binary
420f142d3bdSThierry Reding * representation that can be written into the corresponding controller
421f142d3bdSThierry Reding * registers. Also computes the checksum as required by section 5.3.5 of
422f142d3bdSThierry Reding * the HDMI 1.4 specification.
423f142d3bdSThierry Reding *
424f142d3bdSThierry Reding * Returns the number of bytes packed into the binary buffer or a negative
425f142d3bdSThierry Reding * error code on failure.
426f142d3bdSThierry Reding */
hdmi_audio_infoframe_pack_only(const struct hdmi_audio_infoframe * frame,void * buffer,size_t size)427c5e69ab3SVille Syrjälä ssize_t hdmi_audio_infoframe_pack_only(const struct hdmi_audio_infoframe *frame,
428f142d3bdSThierry Reding void *buffer, size_t size)
429f142d3bdSThierry Reding {
430f142d3bdSThierry Reding u8 *ptr = buffer;
431f142d3bdSThierry Reding size_t length;
432c5e69ab3SVille Syrjälä int ret;
433c5e69ab3SVille Syrjälä
434c5e69ab3SVille Syrjälä ret = hdmi_audio_infoframe_check_only(frame);
435c5e69ab3SVille Syrjälä if (ret)
436c5e69ab3SVille Syrjälä return ret;
437f142d3bdSThierry Reding
438f142d3bdSThierry Reding length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
439f142d3bdSThierry Reding
440f142d3bdSThierry Reding if (size < length)
441f142d3bdSThierry Reding return -ENOSPC;
442f142d3bdSThierry Reding
4433b390f62SDamien Lespiau memset(buffer, 0, size);
444f142d3bdSThierry Reding
445f142d3bdSThierry Reding ptr[0] = frame->type;
446f142d3bdSThierry Reding ptr[1] = frame->version;
447f142d3bdSThierry Reding ptr[2] = frame->length;
448f142d3bdSThierry Reding ptr[3] = 0; /* checksum */
449f142d3bdSThierry Reding
450*f89aa0b6SMarkus Schneider-Pargmann hdmi_audio_infoframe_pack_payload(frame,
451*f89aa0b6SMarkus Schneider-Pargmann ptr + HDMI_INFOFRAME_HEADER_SIZE);
452f142d3bdSThierry Reding
4532c676f37SMartin Bugge hdmi_infoframe_set_checksum(buffer, length);
454f142d3bdSThierry Reding
455f142d3bdSThierry Reding return length;
456f142d3bdSThierry Reding }
457c5e69ab3SVille Syrjälä EXPORT_SYMBOL(hdmi_audio_infoframe_pack_only);
458c5e69ab3SVille Syrjälä
459c5e69ab3SVille Syrjälä /**
460c5e69ab3SVille Syrjälä * hdmi_audio_infoframe_pack() - check a HDMI Audio infoframe,
461c5e69ab3SVille Syrjälä * and write it to binary buffer
462c5e69ab3SVille Syrjälä * @frame: HDMI Audio infoframe
463c5e69ab3SVille Syrjälä * @buffer: destination buffer
464c5e69ab3SVille Syrjälä * @size: size of buffer
465c5e69ab3SVille Syrjälä *
466c5e69ab3SVille Syrjälä * Validates that the infoframe is consistent and updates derived fields
467c5e69ab3SVille Syrjälä * (eg. length) based on other fields, after which it packs the information
468c5e69ab3SVille Syrjälä * contained in the @frame structure into a binary representation that
469c5e69ab3SVille Syrjälä * can be written into the corresponding controller registers. This function
470c5e69ab3SVille Syrjälä * also computes the checksum as required by section 5.3.5 of the HDMI 1.4
471c5e69ab3SVille Syrjälä * specification.
472c5e69ab3SVille Syrjälä *
473c5e69ab3SVille Syrjälä * Returns the number of bytes packed into the binary buffer or a negative
474c5e69ab3SVille Syrjälä * error code on failure.
475c5e69ab3SVille Syrjälä */
hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe * frame,void * buffer,size_t size)476c5e69ab3SVille Syrjälä ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
477c5e69ab3SVille Syrjälä void *buffer, size_t size)
478c5e69ab3SVille Syrjälä {
479c5e69ab3SVille Syrjälä int ret;
480c5e69ab3SVille Syrjälä
481c5e69ab3SVille Syrjälä ret = hdmi_audio_infoframe_check(frame);
482c5e69ab3SVille Syrjälä if (ret)
483c5e69ab3SVille Syrjälä return ret;
484c5e69ab3SVille Syrjälä
485c5e69ab3SVille Syrjälä return hdmi_audio_infoframe_pack_only(frame, buffer, size);
486c5e69ab3SVille Syrjälä }
487f142d3bdSThierry Reding EXPORT_SYMBOL(hdmi_audio_infoframe_pack);
488f142d3bdSThierry Reding
489f142d3bdSThierry Reding /**
490*f89aa0b6SMarkus Schneider-Pargmann * hdmi_audio_infoframe_pack_for_dp - Pack a HDMI Audio infoframe for DisplayPort
491*f89aa0b6SMarkus Schneider-Pargmann *
492*f89aa0b6SMarkus Schneider-Pargmann * @frame: HDMI Audio infoframe
493*f89aa0b6SMarkus Schneider-Pargmann * @sdp: Secondary data packet for DisplayPort.
494*f89aa0b6SMarkus Schneider-Pargmann * @dp_version: DisplayPort version to be encoded in the header
495*f89aa0b6SMarkus Schneider-Pargmann *
496*f89aa0b6SMarkus Schneider-Pargmann * Packs a HDMI Audio Infoframe to be sent over DisplayPort. This function
497*f89aa0b6SMarkus Schneider-Pargmann * fills the secondary data packet to be used for DisplayPort.
498*f89aa0b6SMarkus Schneider-Pargmann *
499*f89aa0b6SMarkus Schneider-Pargmann * Return: Number of total written bytes or a negative errno on failure.
500*f89aa0b6SMarkus Schneider-Pargmann */
501*f89aa0b6SMarkus Schneider-Pargmann ssize_t
hdmi_audio_infoframe_pack_for_dp(const struct hdmi_audio_infoframe * frame,struct dp_sdp * sdp,u8 dp_version)502*f89aa0b6SMarkus Schneider-Pargmann hdmi_audio_infoframe_pack_for_dp(const struct hdmi_audio_infoframe *frame,
503*f89aa0b6SMarkus Schneider-Pargmann struct dp_sdp *sdp, u8 dp_version)
504*f89aa0b6SMarkus Schneider-Pargmann {
505*f89aa0b6SMarkus Schneider-Pargmann int ret;
506*f89aa0b6SMarkus Schneider-Pargmann
507*f89aa0b6SMarkus Schneider-Pargmann ret = hdmi_audio_infoframe_check(frame);
508*f89aa0b6SMarkus Schneider-Pargmann if (ret)
509*f89aa0b6SMarkus Schneider-Pargmann return ret;
510*f89aa0b6SMarkus Schneider-Pargmann
511*f89aa0b6SMarkus Schneider-Pargmann memset(sdp->db, 0, sizeof(sdp->db));
512*f89aa0b6SMarkus Schneider-Pargmann
513*f89aa0b6SMarkus Schneider-Pargmann /* Secondary-data packet header */
514*f89aa0b6SMarkus Schneider-Pargmann sdp->sdp_header.HB0 = 0;
515*f89aa0b6SMarkus Schneider-Pargmann sdp->sdp_header.HB1 = frame->type;
516*f89aa0b6SMarkus Schneider-Pargmann sdp->sdp_header.HB2 = DP_SDP_AUDIO_INFOFRAME_HB2;
517*f89aa0b6SMarkus Schneider-Pargmann sdp->sdp_header.HB3 = (dp_version & 0x3f) << 2;
518*f89aa0b6SMarkus Schneider-Pargmann
519*f89aa0b6SMarkus Schneider-Pargmann hdmi_audio_infoframe_pack_payload(frame, sdp->db);
520*f89aa0b6SMarkus Schneider-Pargmann
521*f89aa0b6SMarkus Schneider-Pargmann /* Return size = frame length + four HB for sdp_header */
522*f89aa0b6SMarkus Schneider-Pargmann return frame->length + 4;
523*f89aa0b6SMarkus Schneider-Pargmann }
524*f89aa0b6SMarkus Schneider-Pargmann EXPORT_SYMBOL(hdmi_audio_infoframe_pack_for_dp);
525*f89aa0b6SMarkus Schneider-Pargmann
526*f89aa0b6SMarkus Schneider-Pargmann /**
527ae84b900SLespiau, Damien * hdmi_vendor_infoframe_init() - initialize an HDMI vendor infoframe
5287d27becbSLespiau, Damien * @frame: HDMI vendor infoframe
5297d27becbSLespiau, Damien *
5307d27becbSLespiau, Damien * Returns 0 on success or a negative error code on failure.
5317d27becbSLespiau, Damien */
hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe * frame)532ae84b900SLespiau, Damien int hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame)
5337d27becbSLespiau, Damien {
5347d27becbSLespiau, Damien memset(frame, 0, sizeof(*frame));
5357d27becbSLespiau, Damien
5367d27becbSLespiau, Damien frame->type = HDMI_INFOFRAME_TYPE_VENDOR;
5377d27becbSLespiau, Damien frame->version = 1;
5387d27becbSLespiau, Damien
5396cb3b7f1SLespiau, Damien frame->oui = HDMI_IEEE_OUI;
540af3e95b4SLespiau, Damien
5417d27becbSLespiau, Damien /*
5427d27becbSLespiau, Damien * 0 is a valid value for s3d_struct, so we use a special "not set"
5437d27becbSLespiau, Damien * value
5447d27becbSLespiau, Damien */
5457d27becbSLespiau, Damien frame->s3d_struct = HDMI_3D_STRUCTURE_INVALID;
546d43be255SBernard Zhao frame->length = HDMI_VENDOR_INFOFRAME_SIZE;
5477d27becbSLespiau, Damien
5487d27becbSLespiau, Damien return 0;
5497d27becbSLespiau, Damien }
550ae84b900SLespiau, Damien EXPORT_SYMBOL(hdmi_vendor_infoframe_init);
5517d27becbSLespiau, Damien
hdmi_vendor_infoframe_length(const struct hdmi_vendor_infoframe * frame)552593f4b19SVille Syrjälä static int hdmi_vendor_infoframe_length(const struct hdmi_vendor_infoframe *frame)
553593f4b19SVille Syrjälä {
554593f4b19SVille Syrjälä /* for side by side (half) we also need to provide 3D_Ext_Data */
555593f4b19SVille Syrjälä if (frame->s3d_struct >= HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF)
556593f4b19SVille Syrjälä return 6;
557593f4b19SVille Syrjälä else if (frame->vic != 0 || frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID)
558593f4b19SVille Syrjälä return 5;
559593f4b19SVille Syrjälä else
560593f4b19SVille Syrjälä return 4;
561593f4b19SVille Syrjälä }
562593f4b19SVille Syrjälä
hdmi_vendor_infoframe_check_only(const struct hdmi_vendor_infoframe * frame)563c5e69ab3SVille Syrjälä static int hdmi_vendor_infoframe_check_only(const struct hdmi_vendor_infoframe *frame)
564c5e69ab3SVille Syrjälä {
565c5e69ab3SVille Syrjälä if (frame->type != HDMI_INFOFRAME_TYPE_VENDOR ||
566c5e69ab3SVille Syrjälä frame->version != 1 ||
567c5e69ab3SVille Syrjälä frame->oui != HDMI_IEEE_OUI)
568c5e69ab3SVille Syrjälä return -EINVAL;
569c5e69ab3SVille Syrjälä
570c5e69ab3SVille Syrjälä /* only one of those can be supplied */
571c5e69ab3SVille Syrjälä if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID)
572c5e69ab3SVille Syrjälä return -EINVAL;
573c5e69ab3SVille Syrjälä
574c5e69ab3SVille Syrjälä if (frame->length != hdmi_vendor_infoframe_length(frame))
575c5e69ab3SVille Syrjälä return -EINVAL;
576c5e69ab3SVille Syrjälä
577c5e69ab3SVille Syrjälä return 0;
578c5e69ab3SVille Syrjälä }
579c5e69ab3SVille Syrjälä
5807d27becbSLespiau, Damien /**
581c5e69ab3SVille Syrjälä * hdmi_vendor_infoframe_check() - check a HDMI vendor infoframe
582c5e69ab3SVille Syrjälä * @frame: HDMI infoframe
583c5e69ab3SVille Syrjälä *
584c5e69ab3SVille Syrjälä * Validates that the infoframe is consistent and updates derived fields
585c5e69ab3SVille Syrjälä * (eg. length) based on other fields.
586c5e69ab3SVille Syrjälä *
587c5e69ab3SVille Syrjälä * Returns 0 on success or a negative error code on failure.
588c5e69ab3SVille Syrjälä */
hdmi_vendor_infoframe_check(struct hdmi_vendor_infoframe * frame)589c5e69ab3SVille Syrjälä int hdmi_vendor_infoframe_check(struct hdmi_vendor_infoframe *frame)
590c5e69ab3SVille Syrjälä {
591c5e69ab3SVille Syrjälä frame->length = hdmi_vendor_infoframe_length(frame);
592c5e69ab3SVille Syrjälä
593c5e69ab3SVille Syrjälä return hdmi_vendor_infoframe_check_only(frame);
594c5e69ab3SVille Syrjälä }
595c5e69ab3SVille Syrjälä EXPORT_SYMBOL(hdmi_vendor_infoframe_check);
596c5e69ab3SVille Syrjälä
597c5e69ab3SVille Syrjälä /**
598c5e69ab3SVille Syrjälä * hdmi_vendor_infoframe_pack_only() - write a HDMI vendor infoframe to binary buffer
5997d27becbSLespiau, Damien * @frame: HDMI infoframe
6007d27becbSLespiau, Damien * @buffer: destination buffer
6017d27becbSLespiau, Damien * @size: size of buffer
6027d27becbSLespiau, Damien *
6037d27becbSLespiau, Damien * Packs the information contained in the @frame structure into a binary
6047d27becbSLespiau, Damien * representation that can be written into the corresponding controller
6057d27becbSLespiau, Damien * registers. Also computes the checksum as required by section 5.3.5 of
6067d27becbSLespiau, Damien * the HDMI 1.4 specification.
6077d27becbSLespiau, Damien *
6087d27becbSLespiau, Damien * Returns the number of bytes packed into the binary buffer or a negative
6097d27becbSLespiau, Damien * error code on failure.
6107d27becbSLespiau, Damien */
hdmi_vendor_infoframe_pack_only(const struct hdmi_vendor_infoframe * frame,void * buffer,size_t size)611c5e69ab3SVille Syrjälä ssize_t hdmi_vendor_infoframe_pack_only(const struct hdmi_vendor_infoframe *frame,
6127d27becbSLespiau, Damien void *buffer, size_t size)
6137d27becbSLespiau, Damien {
6147d27becbSLespiau, Damien u8 *ptr = buffer;
6157d27becbSLespiau, Damien size_t length;
616c5e69ab3SVille Syrjälä int ret;
6177d27becbSLespiau, Damien
618c5e69ab3SVille Syrjälä ret = hdmi_vendor_infoframe_check_only(frame);
619c5e69ab3SVille Syrjälä if (ret)
620c5e69ab3SVille Syrjälä return ret;
6217d27becbSLespiau, Damien
6227d27becbSLespiau, Damien length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
6237d27becbSLespiau, Damien
6247d27becbSLespiau, Damien if (size < length)
6257d27becbSLespiau, Damien return -ENOSPC;
6267d27becbSLespiau, Damien
6277d27becbSLespiau, Damien memset(buffer, 0, size);
6287d27becbSLespiau, Damien
6297d27becbSLespiau, Damien ptr[0] = frame->type;
6307d27becbSLespiau, Damien ptr[1] = frame->version;
6317d27becbSLespiau, Damien ptr[2] = frame->length;
6327d27becbSLespiau, Damien ptr[3] = 0; /* checksum */
6337d27becbSLespiau, Damien
6347d27becbSLespiau, Damien /* HDMI OUI */
6357d27becbSLespiau, Damien ptr[4] = 0x03;
6367d27becbSLespiau, Damien ptr[5] = 0x0c;
6377d27becbSLespiau, Damien ptr[6] = 0x00;
6387d27becbSLespiau, Damien
639593f4b19SVille Syrjälä if (frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID) {
6407d27becbSLespiau, Damien ptr[7] = 0x2 << 5; /* video format */
6417d27becbSLespiau, Damien ptr[8] = (frame->s3d_struct & 0xf) << 4;
6427d27becbSLespiau, Damien if (frame->s3d_struct >= HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF)
6437d27becbSLespiau, Damien ptr[9] = (frame->s3d_ext_data & 0xf) << 4;
644593f4b19SVille Syrjälä } else if (frame->vic) {
645593f4b19SVille Syrjälä ptr[7] = 0x1 << 5; /* video format */
646593f4b19SVille Syrjälä ptr[8] = frame->vic;
647593f4b19SVille Syrjälä } else {
648593f4b19SVille Syrjälä ptr[7] = 0x0 << 5; /* video format */
6497d27becbSLespiau, Damien }
6507d27becbSLespiau, Damien
6512c676f37SMartin Bugge hdmi_infoframe_set_checksum(buffer, length);
6527d27becbSLespiau, Damien
6537d27becbSLespiau, Damien return length;
6547d27becbSLespiau, Damien }
655c5e69ab3SVille Syrjälä EXPORT_SYMBOL(hdmi_vendor_infoframe_pack_only);
656c5e69ab3SVille Syrjälä
657c5e69ab3SVille Syrjälä /**
658c5e69ab3SVille Syrjälä * hdmi_vendor_infoframe_pack() - check a HDMI Vendor infoframe,
659c5e69ab3SVille Syrjälä * and write it to binary buffer
660c5e69ab3SVille Syrjälä * @frame: HDMI Vendor infoframe
661c5e69ab3SVille Syrjälä * @buffer: destination buffer
662c5e69ab3SVille Syrjälä * @size: size of buffer
663c5e69ab3SVille Syrjälä *
664c5e69ab3SVille Syrjälä * Validates that the infoframe is consistent and updates derived fields
665c5e69ab3SVille Syrjälä * (eg. length) based on other fields, after which it packs the information
666c5e69ab3SVille Syrjälä * contained in the @frame structure into a binary representation that
667c5e69ab3SVille Syrjälä * can be written into the corresponding controller registers. This function
668c5e69ab3SVille Syrjälä * also computes the checksum as required by section 5.3.5 of the HDMI 1.4
669c5e69ab3SVille Syrjälä * specification.
670c5e69ab3SVille Syrjälä *
671c5e69ab3SVille Syrjälä * Returns the number of bytes packed into the binary buffer or a negative
672c5e69ab3SVille Syrjälä * error code on failure.
673c5e69ab3SVille Syrjälä */
hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe * frame,void * buffer,size_t size)674c5e69ab3SVille Syrjälä ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
675c5e69ab3SVille Syrjälä void *buffer, size_t size)
676c5e69ab3SVille Syrjälä {
677c5e69ab3SVille Syrjälä int ret;
678c5e69ab3SVille Syrjälä
679c5e69ab3SVille Syrjälä ret = hdmi_vendor_infoframe_check(frame);
680c5e69ab3SVille Syrjälä if (ret)
681c5e69ab3SVille Syrjälä return ret;
682c5e69ab3SVille Syrjälä
683c5e69ab3SVille Syrjälä return hdmi_vendor_infoframe_pack_only(frame, buffer, size);
684c5e69ab3SVille Syrjälä }
685ae84b900SLespiau, Damien EXPORT_SYMBOL(hdmi_vendor_infoframe_pack);
6867d27becbSLespiau, Damien
687c5e69ab3SVille Syrjälä static int
hdmi_vendor_any_infoframe_check_only(const union hdmi_vendor_any_infoframe * frame)688c5e69ab3SVille Syrjälä hdmi_vendor_any_infoframe_check_only(const union hdmi_vendor_any_infoframe *frame)
689c5e69ab3SVille Syrjälä {
690c5e69ab3SVille Syrjälä if (frame->any.type != HDMI_INFOFRAME_TYPE_VENDOR ||
691c5e69ab3SVille Syrjälä frame->any.version != 1)
692c5e69ab3SVille Syrjälä return -EINVAL;
693c5e69ab3SVille Syrjälä
694c5e69ab3SVille Syrjälä return 0;
695c5e69ab3SVille Syrjälä }
696c5e69ab3SVille Syrjälä
6972cdbfd66SUma Shankar /**
6982cdbfd66SUma Shankar * hdmi_drm_infoframe_init() - initialize an HDMI Dynaminc Range and
6992cdbfd66SUma Shankar * mastering infoframe
7002cdbfd66SUma Shankar * @frame: HDMI DRM infoframe
7012cdbfd66SUma Shankar *
7022cdbfd66SUma Shankar * Returns 0 on success or a negative error code on failure.
7032cdbfd66SUma Shankar */
hdmi_drm_infoframe_init(struct hdmi_drm_infoframe * frame)7042cdbfd66SUma Shankar int hdmi_drm_infoframe_init(struct hdmi_drm_infoframe *frame)
7052cdbfd66SUma Shankar {
7062cdbfd66SUma Shankar memset(frame, 0, sizeof(*frame));
7072cdbfd66SUma Shankar
7082cdbfd66SUma Shankar frame->type = HDMI_INFOFRAME_TYPE_DRM;
7092cdbfd66SUma Shankar frame->version = 1;
7102cdbfd66SUma Shankar frame->length = HDMI_DRM_INFOFRAME_SIZE;
7112cdbfd66SUma Shankar
7122cdbfd66SUma Shankar return 0;
7132cdbfd66SUma Shankar }
7142cdbfd66SUma Shankar EXPORT_SYMBOL(hdmi_drm_infoframe_init);
7152cdbfd66SUma Shankar
hdmi_drm_infoframe_check_only(const struct hdmi_drm_infoframe * frame)7162cdbfd66SUma Shankar static int hdmi_drm_infoframe_check_only(const struct hdmi_drm_infoframe *frame)
7172cdbfd66SUma Shankar {
7182cdbfd66SUma Shankar if (frame->type != HDMI_INFOFRAME_TYPE_DRM ||
7192cdbfd66SUma Shankar frame->version != 1)
7202cdbfd66SUma Shankar return -EINVAL;
7212cdbfd66SUma Shankar
7222cdbfd66SUma Shankar if (frame->length != HDMI_DRM_INFOFRAME_SIZE)
7232cdbfd66SUma Shankar return -EINVAL;
7242cdbfd66SUma Shankar
7252cdbfd66SUma Shankar return 0;
7262cdbfd66SUma Shankar }
7272cdbfd66SUma Shankar
7282cdbfd66SUma Shankar /**
7292cdbfd66SUma Shankar * hdmi_drm_infoframe_check() - check a HDMI DRM infoframe
7302cdbfd66SUma Shankar * @frame: HDMI DRM infoframe
7312cdbfd66SUma Shankar *
7322cdbfd66SUma Shankar * Validates that the infoframe is consistent.
7332cdbfd66SUma Shankar * Returns 0 on success or a negative error code on failure.
7342cdbfd66SUma Shankar */
hdmi_drm_infoframe_check(struct hdmi_drm_infoframe * frame)7352cdbfd66SUma Shankar int hdmi_drm_infoframe_check(struct hdmi_drm_infoframe *frame)
7362cdbfd66SUma Shankar {
7372cdbfd66SUma Shankar return hdmi_drm_infoframe_check_only(frame);
7382cdbfd66SUma Shankar }
7392cdbfd66SUma Shankar EXPORT_SYMBOL(hdmi_drm_infoframe_check);
7402cdbfd66SUma Shankar
7412cdbfd66SUma Shankar /**
7422cdbfd66SUma Shankar * hdmi_drm_infoframe_pack_only() - write HDMI DRM infoframe to binary buffer
7432cdbfd66SUma Shankar * @frame: HDMI DRM infoframe
7442cdbfd66SUma Shankar * @buffer: destination buffer
7452cdbfd66SUma Shankar * @size: size of buffer
7462cdbfd66SUma Shankar *
7472cdbfd66SUma Shankar * Packs the information contained in the @frame structure into a binary
7482cdbfd66SUma Shankar * representation that can be written into the corresponding controller
7492cdbfd66SUma Shankar * registers. Also computes the checksum as required by section 5.3.5 of
7502cdbfd66SUma Shankar * the HDMI 1.4 specification.
7512cdbfd66SUma Shankar *
7522cdbfd66SUma Shankar * Returns the number of bytes packed into the binary buffer or a negative
7532cdbfd66SUma Shankar * error code on failure.
7542cdbfd66SUma Shankar */
hdmi_drm_infoframe_pack_only(const struct hdmi_drm_infoframe * frame,void * buffer,size_t size)7552cdbfd66SUma Shankar ssize_t hdmi_drm_infoframe_pack_only(const struct hdmi_drm_infoframe *frame,
7562cdbfd66SUma Shankar void *buffer, size_t size)
7572cdbfd66SUma Shankar {
7582cdbfd66SUma Shankar u8 *ptr = buffer;
7592cdbfd66SUma Shankar size_t length;
7602cdbfd66SUma Shankar int i;
7612cdbfd66SUma Shankar
7622cdbfd66SUma Shankar length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
7632cdbfd66SUma Shankar
7642cdbfd66SUma Shankar if (size < length)
7652cdbfd66SUma Shankar return -ENOSPC;
7662cdbfd66SUma Shankar
7672cdbfd66SUma Shankar memset(buffer, 0, size);
7682cdbfd66SUma Shankar
7692cdbfd66SUma Shankar ptr[0] = frame->type;
7702cdbfd66SUma Shankar ptr[1] = frame->version;
7712cdbfd66SUma Shankar ptr[2] = frame->length;
7722cdbfd66SUma Shankar ptr[3] = 0; /* checksum */
7732cdbfd66SUma Shankar
7742cdbfd66SUma Shankar /* start infoframe payload */
7752cdbfd66SUma Shankar ptr += HDMI_INFOFRAME_HEADER_SIZE;
7762cdbfd66SUma Shankar
7772cdbfd66SUma Shankar *ptr++ = frame->eotf;
7782cdbfd66SUma Shankar *ptr++ = frame->metadata_type;
7792cdbfd66SUma Shankar
7802cdbfd66SUma Shankar for (i = 0; i < 3; i++) {
7812cdbfd66SUma Shankar *ptr++ = frame->display_primaries[i].x;
7822cdbfd66SUma Shankar *ptr++ = frame->display_primaries[i].x >> 8;
7832cdbfd66SUma Shankar *ptr++ = frame->display_primaries[i].y;
7842cdbfd66SUma Shankar *ptr++ = frame->display_primaries[i].y >> 8;
7852cdbfd66SUma Shankar }
7862cdbfd66SUma Shankar
7872cdbfd66SUma Shankar *ptr++ = frame->white_point.x;
7882cdbfd66SUma Shankar *ptr++ = frame->white_point.x >> 8;
7892cdbfd66SUma Shankar
7902cdbfd66SUma Shankar *ptr++ = frame->white_point.y;
7912cdbfd66SUma Shankar *ptr++ = frame->white_point.y >> 8;
7922cdbfd66SUma Shankar
7932cdbfd66SUma Shankar *ptr++ = frame->max_display_mastering_luminance;
7942cdbfd66SUma Shankar *ptr++ = frame->max_display_mastering_luminance >> 8;
7952cdbfd66SUma Shankar
7962cdbfd66SUma Shankar *ptr++ = frame->min_display_mastering_luminance;
7972cdbfd66SUma Shankar *ptr++ = frame->min_display_mastering_luminance >> 8;
7982cdbfd66SUma Shankar
7992cdbfd66SUma Shankar *ptr++ = frame->max_cll;
8002cdbfd66SUma Shankar *ptr++ = frame->max_cll >> 8;
8012cdbfd66SUma Shankar
8022cdbfd66SUma Shankar *ptr++ = frame->max_fall;
8032cdbfd66SUma Shankar *ptr++ = frame->max_fall >> 8;
8042cdbfd66SUma Shankar
8052cdbfd66SUma Shankar hdmi_infoframe_set_checksum(buffer, length);
8062cdbfd66SUma Shankar
8072cdbfd66SUma Shankar return length;
8082cdbfd66SUma Shankar }
8092cdbfd66SUma Shankar EXPORT_SYMBOL(hdmi_drm_infoframe_pack_only);
8102cdbfd66SUma Shankar
8112cdbfd66SUma Shankar /**
8122cdbfd66SUma Shankar * hdmi_drm_infoframe_pack() - check a HDMI DRM infoframe,
8132cdbfd66SUma Shankar * and write it to binary buffer
8142cdbfd66SUma Shankar * @frame: HDMI DRM infoframe
8152cdbfd66SUma Shankar * @buffer: destination buffer
8162cdbfd66SUma Shankar * @size: size of buffer
8172cdbfd66SUma Shankar *
8182cdbfd66SUma Shankar * Validates that the infoframe is consistent and updates derived fields
8192cdbfd66SUma Shankar * (eg. length) based on other fields, after which it packs the information
8202cdbfd66SUma Shankar * contained in the @frame structure into a binary representation that
8212cdbfd66SUma Shankar * can be written into the corresponding controller registers. This function
8222cdbfd66SUma Shankar * also computes the checksum as required by section 5.3.5 of the HDMI 1.4
8232cdbfd66SUma Shankar * specification.
8242cdbfd66SUma Shankar *
8252cdbfd66SUma Shankar * Returns the number of bytes packed into the binary buffer or a negative
8262cdbfd66SUma Shankar * error code on failure.
8272cdbfd66SUma Shankar */
hdmi_drm_infoframe_pack(struct hdmi_drm_infoframe * frame,void * buffer,size_t size)8282cdbfd66SUma Shankar ssize_t hdmi_drm_infoframe_pack(struct hdmi_drm_infoframe *frame,
8292cdbfd66SUma Shankar void *buffer, size_t size)
8302cdbfd66SUma Shankar {
8312cdbfd66SUma Shankar int ret;
8322cdbfd66SUma Shankar
8332cdbfd66SUma Shankar ret = hdmi_drm_infoframe_check(frame);
8342cdbfd66SUma Shankar if (ret)
8352cdbfd66SUma Shankar return ret;
8362cdbfd66SUma Shankar
8372cdbfd66SUma Shankar return hdmi_drm_infoframe_pack_only(frame, buffer, size);
8382cdbfd66SUma Shankar }
8392cdbfd66SUma Shankar EXPORT_SYMBOL(hdmi_drm_infoframe_pack);
8402cdbfd66SUma Shankar
841af3e95b4SLespiau, Damien /*
842c5e69ab3SVille Syrjälä * hdmi_vendor_any_infoframe_check() - check a vendor infoframe
843c5e69ab3SVille Syrjälä */
844c5e69ab3SVille Syrjälä static int
hdmi_vendor_any_infoframe_check(union hdmi_vendor_any_infoframe * frame)845c5e69ab3SVille Syrjälä hdmi_vendor_any_infoframe_check(union hdmi_vendor_any_infoframe *frame)
846c5e69ab3SVille Syrjälä {
847c5e69ab3SVille Syrjälä int ret;
848c5e69ab3SVille Syrjälä
849c5e69ab3SVille Syrjälä ret = hdmi_vendor_any_infoframe_check_only(frame);
850c5e69ab3SVille Syrjälä if (ret)
851c5e69ab3SVille Syrjälä return ret;
852c5e69ab3SVille Syrjälä
853c5e69ab3SVille Syrjälä /* we only know about HDMI vendor infoframes */
854c5e69ab3SVille Syrjälä if (frame->any.oui != HDMI_IEEE_OUI)
855c5e69ab3SVille Syrjälä return -EINVAL;
856c5e69ab3SVille Syrjälä
857c5e69ab3SVille Syrjälä return hdmi_vendor_infoframe_check(&frame->hdmi);
858c5e69ab3SVille Syrjälä }
859c5e69ab3SVille Syrjälä
860c5e69ab3SVille Syrjälä /*
861c5e69ab3SVille Syrjälä * hdmi_vendor_any_infoframe_pack_only() - write a vendor infoframe to binary buffer
862c5e69ab3SVille Syrjälä */
863c5e69ab3SVille Syrjälä static ssize_t
hdmi_vendor_any_infoframe_pack_only(const union hdmi_vendor_any_infoframe * frame,void * buffer,size_t size)864c5e69ab3SVille Syrjälä hdmi_vendor_any_infoframe_pack_only(const union hdmi_vendor_any_infoframe *frame,
865c5e69ab3SVille Syrjälä void *buffer, size_t size)
866c5e69ab3SVille Syrjälä {
867c5e69ab3SVille Syrjälä int ret;
868c5e69ab3SVille Syrjälä
869c5e69ab3SVille Syrjälä ret = hdmi_vendor_any_infoframe_check_only(frame);
870c5e69ab3SVille Syrjälä if (ret)
871c5e69ab3SVille Syrjälä return ret;
872c5e69ab3SVille Syrjälä
873c5e69ab3SVille Syrjälä /* we only know about HDMI vendor infoframes */
874c5e69ab3SVille Syrjälä if (frame->any.oui != HDMI_IEEE_OUI)
875c5e69ab3SVille Syrjälä return -EINVAL;
876c5e69ab3SVille Syrjälä
877c5e69ab3SVille Syrjälä return hdmi_vendor_infoframe_pack_only(&frame->hdmi, buffer, size);
878c5e69ab3SVille Syrjälä }
879c5e69ab3SVille Syrjälä
880c5e69ab3SVille Syrjälä /*
881c5e69ab3SVille Syrjälä * hdmi_vendor_any_infoframe_pack() - check a vendor infoframe,
882c5e69ab3SVille Syrjälä * and write it to binary buffer
883f142d3bdSThierry Reding */
884ae84b900SLespiau, Damien static ssize_t
hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe * frame,void * buffer,size_t size)885ae84b900SLespiau, Damien hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
886f142d3bdSThierry Reding void *buffer, size_t size)
887f142d3bdSThierry Reding {
888c5e69ab3SVille Syrjälä int ret;
889f142d3bdSThierry Reding
890c5e69ab3SVille Syrjälä ret = hdmi_vendor_any_infoframe_check(frame);
891c5e69ab3SVille Syrjälä if (ret)
892c5e69ab3SVille Syrjälä return ret;
893c5e69ab3SVille Syrjälä
894c5e69ab3SVille Syrjälä return hdmi_vendor_any_infoframe_pack_only(frame, buffer, size);
895f142d3bdSThierry Reding }
89672b09896SDamien Lespiau
89772b09896SDamien Lespiau /**
898c5e69ab3SVille Syrjälä * hdmi_infoframe_check() - check a HDMI infoframe
899c5e69ab3SVille Syrjälä * @frame: HDMI infoframe
900c5e69ab3SVille Syrjälä *
901c5e69ab3SVille Syrjälä * Validates that the infoframe is consistent and updates derived fields
902c5e69ab3SVille Syrjälä * (eg. length) based on other fields.
903c5e69ab3SVille Syrjälä *
904c5e69ab3SVille Syrjälä * Returns 0 on success or a negative error code on failure.
905c5e69ab3SVille Syrjälä */
906c5e69ab3SVille Syrjälä int
hdmi_infoframe_check(union hdmi_infoframe * frame)907c5e69ab3SVille Syrjälä hdmi_infoframe_check(union hdmi_infoframe *frame)
908c5e69ab3SVille Syrjälä {
909c5e69ab3SVille Syrjälä switch (frame->any.type) {
910c5e69ab3SVille Syrjälä case HDMI_INFOFRAME_TYPE_AVI:
911c5e69ab3SVille Syrjälä return hdmi_avi_infoframe_check(&frame->avi);
912c5e69ab3SVille Syrjälä case HDMI_INFOFRAME_TYPE_SPD:
913c5e69ab3SVille Syrjälä return hdmi_spd_infoframe_check(&frame->spd);
914c5e69ab3SVille Syrjälä case HDMI_INFOFRAME_TYPE_AUDIO:
915c5e69ab3SVille Syrjälä return hdmi_audio_infoframe_check(&frame->audio);
916c5e69ab3SVille Syrjälä case HDMI_INFOFRAME_TYPE_VENDOR:
917c5e69ab3SVille Syrjälä return hdmi_vendor_any_infoframe_check(&frame->vendor);
918c5e69ab3SVille Syrjälä default:
919c5e69ab3SVille Syrjälä WARN(1, "Bad infoframe type %d\n", frame->any.type);
920c5e69ab3SVille Syrjälä return -EINVAL;
921c5e69ab3SVille Syrjälä }
922c5e69ab3SVille Syrjälä }
923c5e69ab3SVille Syrjälä EXPORT_SYMBOL(hdmi_infoframe_check);
924c5e69ab3SVille Syrjälä
925c5e69ab3SVille Syrjälä /**
926c5e69ab3SVille Syrjälä * hdmi_infoframe_pack_only() - write a HDMI infoframe to binary buffer
92772b09896SDamien Lespiau * @frame: HDMI infoframe
92872b09896SDamien Lespiau * @buffer: destination buffer
92972b09896SDamien Lespiau * @size: size of buffer
93072b09896SDamien Lespiau *
93172b09896SDamien Lespiau * Packs the information contained in the @frame structure into a binary
93272b09896SDamien Lespiau * representation that can be written into the corresponding controller
93372b09896SDamien Lespiau * registers. Also computes the checksum as required by section 5.3.5 of
93472b09896SDamien Lespiau * the HDMI 1.4 specification.
93572b09896SDamien Lespiau *
93672b09896SDamien Lespiau * Returns the number of bytes packed into the binary buffer or a negative
93772b09896SDamien Lespiau * error code on failure.
93872b09896SDamien Lespiau */
93972b09896SDamien Lespiau ssize_t
hdmi_infoframe_pack_only(const union hdmi_infoframe * frame,void * buffer,size_t size)940c5e69ab3SVille Syrjälä hdmi_infoframe_pack_only(const union hdmi_infoframe *frame, void *buffer, size_t size)
941c5e69ab3SVille Syrjälä {
942c5e69ab3SVille Syrjälä ssize_t length;
943c5e69ab3SVille Syrjälä
944c5e69ab3SVille Syrjälä switch (frame->any.type) {
945c5e69ab3SVille Syrjälä case HDMI_INFOFRAME_TYPE_AVI:
946c5e69ab3SVille Syrjälä length = hdmi_avi_infoframe_pack_only(&frame->avi,
947c5e69ab3SVille Syrjälä buffer, size);
948c5e69ab3SVille Syrjälä break;
9492cdbfd66SUma Shankar case HDMI_INFOFRAME_TYPE_DRM:
9502cdbfd66SUma Shankar length = hdmi_drm_infoframe_pack_only(&frame->drm,
9512cdbfd66SUma Shankar buffer, size);
9522cdbfd66SUma Shankar break;
953c5e69ab3SVille Syrjälä case HDMI_INFOFRAME_TYPE_SPD:
954c5e69ab3SVille Syrjälä length = hdmi_spd_infoframe_pack_only(&frame->spd,
955c5e69ab3SVille Syrjälä buffer, size);
956c5e69ab3SVille Syrjälä break;
957c5e69ab3SVille Syrjälä case HDMI_INFOFRAME_TYPE_AUDIO:
958c5e69ab3SVille Syrjälä length = hdmi_audio_infoframe_pack_only(&frame->audio,
959c5e69ab3SVille Syrjälä buffer, size);
960c5e69ab3SVille Syrjälä break;
961c5e69ab3SVille Syrjälä case HDMI_INFOFRAME_TYPE_VENDOR:
962c5e69ab3SVille Syrjälä length = hdmi_vendor_any_infoframe_pack_only(&frame->vendor,
963c5e69ab3SVille Syrjälä buffer, size);
964c5e69ab3SVille Syrjälä break;
965c5e69ab3SVille Syrjälä default:
966c5e69ab3SVille Syrjälä WARN(1, "Bad infoframe type %d\n", frame->any.type);
967c5e69ab3SVille Syrjälä length = -EINVAL;
968c5e69ab3SVille Syrjälä }
969c5e69ab3SVille Syrjälä
970c5e69ab3SVille Syrjälä return length;
971c5e69ab3SVille Syrjälä }
972c5e69ab3SVille Syrjälä EXPORT_SYMBOL(hdmi_infoframe_pack_only);
973c5e69ab3SVille Syrjälä
974c5e69ab3SVille Syrjälä /**
975c5e69ab3SVille Syrjälä * hdmi_infoframe_pack() - check a HDMI infoframe,
976c5e69ab3SVille Syrjälä * and write it to binary buffer
977c5e69ab3SVille Syrjälä * @frame: HDMI infoframe
978c5e69ab3SVille Syrjälä * @buffer: destination buffer
979c5e69ab3SVille Syrjälä * @size: size of buffer
980c5e69ab3SVille Syrjälä *
981c5e69ab3SVille Syrjälä * Validates that the infoframe is consistent and updates derived fields
982c5e69ab3SVille Syrjälä * (eg. length) based on other fields, after which it packs the information
983c5e69ab3SVille Syrjälä * contained in the @frame structure into a binary representation that
984c5e69ab3SVille Syrjälä * can be written into the corresponding controller registers. This function
985c5e69ab3SVille Syrjälä * also computes the checksum as required by section 5.3.5 of the HDMI 1.4
986c5e69ab3SVille Syrjälä * specification.
987c5e69ab3SVille Syrjälä *
988c5e69ab3SVille Syrjälä * Returns the number of bytes packed into the binary buffer or a negative
989c5e69ab3SVille Syrjälä * error code on failure.
990c5e69ab3SVille Syrjälä */
991c5e69ab3SVille Syrjälä ssize_t
hdmi_infoframe_pack(union hdmi_infoframe * frame,void * buffer,size_t size)992c5e69ab3SVille Syrjälä hdmi_infoframe_pack(union hdmi_infoframe *frame,
993c5e69ab3SVille Syrjälä void *buffer, size_t size)
99472b09896SDamien Lespiau {
99572b09896SDamien Lespiau ssize_t length;
99672b09896SDamien Lespiau
99772b09896SDamien Lespiau switch (frame->any.type) {
99872b09896SDamien Lespiau case HDMI_INFOFRAME_TYPE_AVI:
99972b09896SDamien Lespiau length = hdmi_avi_infoframe_pack(&frame->avi, buffer, size);
100072b09896SDamien Lespiau break;
10012cdbfd66SUma Shankar case HDMI_INFOFRAME_TYPE_DRM:
10022cdbfd66SUma Shankar length = hdmi_drm_infoframe_pack(&frame->drm, buffer, size);
10032cdbfd66SUma Shankar break;
100472b09896SDamien Lespiau case HDMI_INFOFRAME_TYPE_SPD:
100572b09896SDamien Lespiau length = hdmi_spd_infoframe_pack(&frame->spd, buffer, size);
100672b09896SDamien Lespiau break;
100772b09896SDamien Lespiau case HDMI_INFOFRAME_TYPE_AUDIO:
100872b09896SDamien Lespiau length = hdmi_audio_infoframe_pack(&frame->audio, buffer, size);
100972b09896SDamien Lespiau break;
101072b09896SDamien Lespiau case HDMI_INFOFRAME_TYPE_VENDOR:
1011ae84b900SLespiau, Damien length = hdmi_vendor_any_infoframe_pack(&frame->vendor,
101272b09896SDamien Lespiau buffer, size);
101372b09896SDamien Lespiau break;
101472b09896SDamien Lespiau default:
101572b09896SDamien Lespiau WARN(1, "Bad infoframe type %d\n", frame->any.type);
101672b09896SDamien Lespiau length = -EINVAL;
101772b09896SDamien Lespiau }
101872b09896SDamien Lespiau
101972b09896SDamien Lespiau return length;
102072b09896SDamien Lespiau }
102172b09896SDamien Lespiau EXPORT_SYMBOL(hdmi_infoframe_pack);
10222c676f37SMartin Bugge
hdmi_infoframe_type_get_name(enum hdmi_infoframe_type type)10232c676f37SMartin Bugge static const char *hdmi_infoframe_type_get_name(enum hdmi_infoframe_type type)
10242c676f37SMartin Bugge {
10252c676f37SMartin Bugge if (type < 0x80 || type > 0x9f)
10262c676f37SMartin Bugge return "Invalid";
10272c676f37SMartin Bugge switch (type) {
10282c676f37SMartin Bugge case HDMI_INFOFRAME_TYPE_VENDOR:
10292c676f37SMartin Bugge return "Vendor";
10302c676f37SMartin Bugge case HDMI_INFOFRAME_TYPE_AVI:
10312c676f37SMartin Bugge return "Auxiliary Video Information (AVI)";
10322c676f37SMartin Bugge case HDMI_INFOFRAME_TYPE_SPD:
10332c676f37SMartin Bugge return "Source Product Description (SPD)";
10342c676f37SMartin Bugge case HDMI_INFOFRAME_TYPE_AUDIO:
10352c676f37SMartin Bugge return "Audio";
10362cdbfd66SUma Shankar case HDMI_INFOFRAME_TYPE_DRM:
10372cdbfd66SUma Shankar return "Dynamic Range and Mastering";
10382c676f37SMartin Bugge }
10392c676f37SMartin Bugge return "Reserved";
10402c676f37SMartin Bugge }
10412c676f37SMartin Bugge
hdmi_infoframe_log_header(const char * level,struct device * dev,const struct hdmi_any_infoframe * frame)10422c676f37SMartin Bugge static void hdmi_infoframe_log_header(const char *level,
10432c676f37SMartin Bugge struct device *dev,
1044468d6a49SVille Syrjälä const struct hdmi_any_infoframe *frame)
10452c676f37SMartin Bugge {
10462c676f37SMartin Bugge hdmi_log("HDMI infoframe: %s, version %u, length %u\n",
10472c676f37SMartin Bugge hdmi_infoframe_type_get_name(frame->type),
10482c676f37SMartin Bugge frame->version, frame->length);
10492c676f37SMartin Bugge }
10502c676f37SMartin Bugge
hdmi_colorspace_get_name(enum hdmi_colorspace colorspace)10512c676f37SMartin Bugge static const char *hdmi_colorspace_get_name(enum hdmi_colorspace colorspace)
10522c676f37SMartin Bugge {
10532c676f37SMartin Bugge switch (colorspace) {
10542c676f37SMartin Bugge case HDMI_COLORSPACE_RGB:
10552c676f37SMartin Bugge return "RGB";
10562c676f37SMartin Bugge case HDMI_COLORSPACE_YUV422:
10572c676f37SMartin Bugge return "YCbCr 4:2:2";
10582c676f37SMartin Bugge case HDMI_COLORSPACE_YUV444:
10592c676f37SMartin Bugge return "YCbCr 4:4:4";
10602c676f37SMartin Bugge case HDMI_COLORSPACE_YUV420:
10612c676f37SMartin Bugge return "YCbCr 4:2:0";
10622c676f37SMartin Bugge case HDMI_COLORSPACE_RESERVED4:
10632c676f37SMartin Bugge return "Reserved (4)";
10642c676f37SMartin Bugge case HDMI_COLORSPACE_RESERVED5:
10652c676f37SMartin Bugge return "Reserved (5)";
10662c676f37SMartin Bugge case HDMI_COLORSPACE_RESERVED6:
10672c676f37SMartin Bugge return "Reserved (6)";
10682c676f37SMartin Bugge case HDMI_COLORSPACE_IDO_DEFINED:
10692c676f37SMartin Bugge return "IDO Defined";
10702c676f37SMartin Bugge }
10712c676f37SMartin Bugge return "Invalid";
10722c676f37SMartin Bugge }
10732c676f37SMartin Bugge
hdmi_scan_mode_get_name(enum hdmi_scan_mode scan_mode)10742c676f37SMartin Bugge static const char *hdmi_scan_mode_get_name(enum hdmi_scan_mode scan_mode)
10752c676f37SMartin Bugge {
10762c676f37SMartin Bugge switch (scan_mode) {
10772c676f37SMartin Bugge case HDMI_SCAN_MODE_NONE:
10782c676f37SMartin Bugge return "No Data";
10792c676f37SMartin Bugge case HDMI_SCAN_MODE_OVERSCAN:
10802c676f37SMartin Bugge return "Overscan";
10812c676f37SMartin Bugge case HDMI_SCAN_MODE_UNDERSCAN:
10822c676f37SMartin Bugge return "Underscan";
10832c676f37SMartin Bugge case HDMI_SCAN_MODE_RESERVED:
10842c676f37SMartin Bugge return "Reserved";
10852c676f37SMartin Bugge }
10862c676f37SMartin Bugge return "Invalid";
10872c676f37SMartin Bugge }
10882c676f37SMartin Bugge
hdmi_colorimetry_get_name(enum hdmi_colorimetry colorimetry)10892c676f37SMartin Bugge static const char *hdmi_colorimetry_get_name(enum hdmi_colorimetry colorimetry)
10902c676f37SMartin Bugge {
10912c676f37SMartin Bugge switch (colorimetry) {
10922c676f37SMartin Bugge case HDMI_COLORIMETRY_NONE:
10932c676f37SMartin Bugge return "No Data";
10942c676f37SMartin Bugge case HDMI_COLORIMETRY_ITU_601:
10952c676f37SMartin Bugge return "ITU601";
10962c676f37SMartin Bugge case HDMI_COLORIMETRY_ITU_709:
10972c676f37SMartin Bugge return "ITU709";
10982c676f37SMartin Bugge case HDMI_COLORIMETRY_EXTENDED:
10992c676f37SMartin Bugge return "Extended";
11002c676f37SMartin Bugge }
11012c676f37SMartin Bugge return "Invalid";
11022c676f37SMartin Bugge }
11032c676f37SMartin Bugge
11042c676f37SMartin Bugge static const char *
hdmi_picture_aspect_get_name(enum hdmi_picture_aspect picture_aspect)11052c676f37SMartin Bugge hdmi_picture_aspect_get_name(enum hdmi_picture_aspect picture_aspect)
11062c676f37SMartin Bugge {
11072c676f37SMartin Bugge switch (picture_aspect) {
11082c676f37SMartin Bugge case HDMI_PICTURE_ASPECT_NONE:
11092c676f37SMartin Bugge return "No Data";
11102c676f37SMartin Bugge case HDMI_PICTURE_ASPECT_4_3:
11112c676f37SMartin Bugge return "4:3";
11122c676f37SMartin Bugge case HDMI_PICTURE_ASPECT_16_9:
11132c676f37SMartin Bugge return "16:9";
1114a6e78b3eSShashank Sharma case HDMI_PICTURE_ASPECT_64_27:
1115a6e78b3eSShashank Sharma return "64:27";
1116a6e78b3eSShashank Sharma case HDMI_PICTURE_ASPECT_256_135:
1117a6e78b3eSShashank Sharma return "256:135";
11182c676f37SMartin Bugge case HDMI_PICTURE_ASPECT_RESERVED:
11192c676f37SMartin Bugge return "Reserved";
11202c676f37SMartin Bugge }
11212c676f37SMartin Bugge return "Invalid";
11222c676f37SMartin Bugge }
11232c676f37SMartin Bugge
11242c676f37SMartin Bugge static const char *
hdmi_active_aspect_get_name(enum hdmi_active_aspect active_aspect)11252c676f37SMartin Bugge hdmi_active_aspect_get_name(enum hdmi_active_aspect active_aspect)
11262c676f37SMartin Bugge {
11272c676f37SMartin Bugge if (active_aspect < 0 || active_aspect > 0xf)
11282c676f37SMartin Bugge return "Invalid";
11292c676f37SMartin Bugge
11302c676f37SMartin Bugge switch (active_aspect) {
11312c676f37SMartin Bugge case HDMI_ACTIVE_ASPECT_16_9_TOP:
11322c676f37SMartin Bugge return "16:9 Top";
11332c676f37SMartin Bugge case HDMI_ACTIVE_ASPECT_14_9_TOP:
11342c676f37SMartin Bugge return "14:9 Top";
11352c676f37SMartin Bugge case HDMI_ACTIVE_ASPECT_16_9_CENTER:
11362c676f37SMartin Bugge return "16:9 Center";
11372c676f37SMartin Bugge case HDMI_ACTIVE_ASPECT_PICTURE:
11382c676f37SMartin Bugge return "Same as Picture";
11392c676f37SMartin Bugge case HDMI_ACTIVE_ASPECT_4_3:
11402c676f37SMartin Bugge return "4:3";
11412c676f37SMartin Bugge case HDMI_ACTIVE_ASPECT_16_9:
11422c676f37SMartin Bugge return "16:9";
11432c676f37SMartin Bugge case HDMI_ACTIVE_ASPECT_14_9:
11442c676f37SMartin Bugge return "14:9";
11452c676f37SMartin Bugge case HDMI_ACTIVE_ASPECT_4_3_SP_14_9:
11462c676f37SMartin Bugge return "4:3 SP 14:9";
11472c676f37SMartin Bugge case HDMI_ACTIVE_ASPECT_16_9_SP_14_9:
11482c676f37SMartin Bugge return "16:9 SP 14:9";
11492c676f37SMartin Bugge case HDMI_ACTIVE_ASPECT_16_9_SP_4_3:
11502c676f37SMartin Bugge return "16:9 SP 4:3";
11512c676f37SMartin Bugge }
11522c676f37SMartin Bugge return "Reserved";
11532c676f37SMartin Bugge }
11542c676f37SMartin Bugge
11552c676f37SMartin Bugge static const char *
hdmi_extended_colorimetry_get_name(enum hdmi_extended_colorimetry ext_col)11562c676f37SMartin Bugge hdmi_extended_colorimetry_get_name(enum hdmi_extended_colorimetry ext_col)
11572c676f37SMartin Bugge {
11582c676f37SMartin Bugge switch (ext_col) {
11592c676f37SMartin Bugge case HDMI_EXTENDED_COLORIMETRY_XV_YCC_601:
11602c676f37SMartin Bugge return "xvYCC 601";
11612c676f37SMartin Bugge case HDMI_EXTENDED_COLORIMETRY_XV_YCC_709:
11622c676f37SMartin Bugge return "xvYCC 709";
11632c676f37SMartin Bugge case HDMI_EXTENDED_COLORIMETRY_S_YCC_601:
11642c676f37SMartin Bugge return "sYCC 601";
1165463659a0SHans Verkuil case HDMI_EXTENDED_COLORIMETRY_OPYCC_601:
1166463659a0SHans Verkuil return "opYCC 601";
1167463659a0SHans Verkuil case HDMI_EXTENDED_COLORIMETRY_OPRGB:
1168463659a0SHans Verkuil return "opRGB";
11692c676f37SMartin Bugge case HDMI_EXTENDED_COLORIMETRY_BT2020_CONST_LUM:
11702c676f37SMartin Bugge return "BT.2020 Constant Luminance";
11712c676f37SMartin Bugge case HDMI_EXTENDED_COLORIMETRY_BT2020:
11722c676f37SMartin Bugge return "BT.2020";
11732c676f37SMartin Bugge case HDMI_EXTENDED_COLORIMETRY_RESERVED:
11742c676f37SMartin Bugge return "Reserved";
11752c676f37SMartin Bugge }
11762c676f37SMartin Bugge return "Invalid";
11772c676f37SMartin Bugge }
11782c676f37SMartin Bugge
11792c676f37SMartin Bugge static const char *
hdmi_quantization_range_get_name(enum hdmi_quantization_range qrange)11802c676f37SMartin Bugge hdmi_quantization_range_get_name(enum hdmi_quantization_range qrange)
11812c676f37SMartin Bugge {
11822c676f37SMartin Bugge switch (qrange) {
11832c676f37SMartin Bugge case HDMI_QUANTIZATION_RANGE_DEFAULT:
11842c676f37SMartin Bugge return "Default";
11852c676f37SMartin Bugge case HDMI_QUANTIZATION_RANGE_LIMITED:
11862c676f37SMartin Bugge return "Limited";
11872c676f37SMartin Bugge case HDMI_QUANTIZATION_RANGE_FULL:
11882c676f37SMartin Bugge return "Full";
11892c676f37SMartin Bugge case HDMI_QUANTIZATION_RANGE_RESERVED:
11902c676f37SMartin Bugge return "Reserved";
11912c676f37SMartin Bugge }
11922c676f37SMartin Bugge return "Invalid";
11932c676f37SMartin Bugge }
11942c676f37SMartin Bugge
hdmi_nups_get_name(enum hdmi_nups nups)11952c676f37SMartin Bugge static const char *hdmi_nups_get_name(enum hdmi_nups nups)
11962c676f37SMartin Bugge {
11972c676f37SMartin Bugge switch (nups) {
11982c676f37SMartin Bugge case HDMI_NUPS_UNKNOWN:
11992c676f37SMartin Bugge return "Unknown Non-uniform Scaling";
12002c676f37SMartin Bugge case HDMI_NUPS_HORIZONTAL:
12012c676f37SMartin Bugge return "Horizontally Scaled";
12022c676f37SMartin Bugge case HDMI_NUPS_VERTICAL:
12032c676f37SMartin Bugge return "Vertically Scaled";
12042c676f37SMartin Bugge case HDMI_NUPS_BOTH:
12052c676f37SMartin Bugge return "Horizontally and Vertically Scaled";
12062c676f37SMartin Bugge }
12072c676f37SMartin Bugge return "Invalid";
12082c676f37SMartin Bugge }
12092c676f37SMartin Bugge
12102c676f37SMartin Bugge static const char *
hdmi_ycc_quantization_range_get_name(enum hdmi_ycc_quantization_range qrange)12112c676f37SMartin Bugge hdmi_ycc_quantization_range_get_name(enum hdmi_ycc_quantization_range qrange)
12122c676f37SMartin Bugge {
12132c676f37SMartin Bugge switch (qrange) {
12142c676f37SMartin Bugge case HDMI_YCC_QUANTIZATION_RANGE_LIMITED:
12152c676f37SMartin Bugge return "Limited";
12162c676f37SMartin Bugge case HDMI_YCC_QUANTIZATION_RANGE_FULL:
12172c676f37SMartin Bugge return "Full";
12182c676f37SMartin Bugge }
12192c676f37SMartin Bugge return "Invalid";
12202c676f37SMartin Bugge }
12212c676f37SMartin Bugge
12222c676f37SMartin Bugge static const char *
hdmi_content_type_get_name(enum hdmi_content_type content_type)12232c676f37SMartin Bugge hdmi_content_type_get_name(enum hdmi_content_type content_type)
12242c676f37SMartin Bugge {
12252c676f37SMartin Bugge switch (content_type) {
12262c676f37SMartin Bugge case HDMI_CONTENT_TYPE_GRAPHICS:
12272c676f37SMartin Bugge return "Graphics";
12282c676f37SMartin Bugge case HDMI_CONTENT_TYPE_PHOTO:
12292c676f37SMartin Bugge return "Photo";
12302c676f37SMartin Bugge case HDMI_CONTENT_TYPE_CINEMA:
12312c676f37SMartin Bugge return "Cinema";
12322c676f37SMartin Bugge case HDMI_CONTENT_TYPE_GAME:
12332c676f37SMartin Bugge return "Game";
12342c676f37SMartin Bugge }
12352c676f37SMartin Bugge return "Invalid";
12362c676f37SMartin Bugge }
12372c676f37SMartin Bugge
hdmi_avi_infoframe_log(const char * level,struct device * dev,const struct hdmi_avi_infoframe * frame)12382c676f37SMartin Bugge static void hdmi_avi_infoframe_log(const char *level,
12392c676f37SMartin Bugge struct device *dev,
1240468d6a49SVille Syrjälä const struct hdmi_avi_infoframe *frame)
12412c676f37SMartin Bugge {
12422c676f37SMartin Bugge hdmi_infoframe_log_header(level, dev,
1243468d6a49SVille Syrjälä (const struct hdmi_any_infoframe *)frame);
12442c676f37SMartin Bugge
12452c676f37SMartin Bugge hdmi_log(" colorspace: %s\n",
12462c676f37SMartin Bugge hdmi_colorspace_get_name(frame->colorspace));
12472c676f37SMartin Bugge hdmi_log(" scan mode: %s\n",
12482c676f37SMartin Bugge hdmi_scan_mode_get_name(frame->scan_mode));
12492c676f37SMartin Bugge hdmi_log(" colorimetry: %s\n",
12502c676f37SMartin Bugge hdmi_colorimetry_get_name(frame->colorimetry));
12512c676f37SMartin Bugge hdmi_log(" picture aspect: %s\n",
12522c676f37SMartin Bugge hdmi_picture_aspect_get_name(frame->picture_aspect));
12532c676f37SMartin Bugge hdmi_log(" active aspect: %s\n",
12542c676f37SMartin Bugge hdmi_active_aspect_get_name(frame->active_aspect));
12552c676f37SMartin Bugge hdmi_log(" itc: %s\n", frame->itc ? "IT Content" : "No Data");
12562c676f37SMartin Bugge hdmi_log(" extended colorimetry: %s\n",
12572c676f37SMartin Bugge hdmi_extended_colorimetry_get_name(frame->extended_colorimetry));
12582c676f37SMartin Bugge hdmi_log(" quantization range: %s\n",
12592c676f37SMartin Bugge hdmi_quantization_range_get_name(frame->quantization_range));
12602c676f37SMartin Bugge hdmi_log(" nups: %s\n", hdmi_nups_get_name(frame->nups));
12612c676f37SMartin Bugge hdmi_log(" video code: %u\n", frame->video_code);
12622c676f37SMartin Bugge hdmi_log(" ycc quantization range: %s\n",
12632c676f37SMartin Bugge hdmi_ycc_quantization_range_get_name(frame->ycc_quantization_range));
12642c676f37SMartin Bugge hdmi_log(" hdmi content type: %s\n",
12652c676f37SMartin Bugge hdmi_content_type_get_name(frame->content_type));
12662c676f37SMartin Bugge hdmi_log(" pixel repeat: %u\n", frame->pixel_repeat);
12672c676f37SMartin Bugge hdmi_log(" bar top %u, bottom %u, left %u, right %u\n",
12682c676f37SMartin Bugge frame->top_bar, frame->bottom_bar,
12692c676f37SMartin Bugge frame->left_bar, frame->right_bar);
12702c676f37SMartin Bugge }
12712c676f37SMartin Bugge
hdmi_spd_sdi_get_name(enum hdmi_spd_sdi sdi)12722c676f37SMartin Bugge static const char *hdmi_spd_sdi_get_name(enum hdmi_spd_sdi sdi)
12732c676f37SMartin Bugge {
12742c676f37SMartin Bugge if (sdi < 0 || sdi > 0xff)
12752c676f37SMartin Bugge return "Invalid";
12762c676f37SMartin Bugge switch (sdi) {
12772c676f37SMartin Bugge case HDMI_SPD_SDI_UNKNOWN:
12782c676f37SMartin Bugge return "Unknown";
12792c676f37SMartin Bugge case HDMI_SPD_SDI_DSTB:
12802c676f37SMartin Bugge return "Digital STB";
12812c676f37SMartin Bugge case HDMI_SPD_SDI_DVDP:
12822c676f37SMartin Bugge return "DVD Player";
12832c676f37SMartin Bugge case HDMI_SPD_SDI_DVHS:
12842c676f37SMartin Bugge return "D-VHS";
12852c676f37SMartin Bugge case HDMI_SPD_SDI_HDDVR:
12862c676f37SMartin Bugge return "HDD Videorecorder";
12872c676f37SMartin Bugge case HDMI_SPD_SDI_DVC:
12882c676f37SMartin Bugge return "DVC";
12892c676f37SMartin Bugge case HDMI_SPD_SDI_DSC:
12902c676f37SMartin Bugge return "DSC";
12912c676f37SMartin Bugge case HDMI_SPD_SDI_VCD:
12922c676f37SMartin Bugge return "Video CD";
12932c676f37SMartin Bugge case HDMI_SPD_SDI_GAME:
12942c676f37SMartin Bugge return "Game";
12952c676f37SMartin Bugge case HDMI_SPD_SDI_PC:
12962c676f37SMartin Bugge return "PC General";
12972c676f37SMartin Bugge case HDMI_SPD_SDI_BD:
12982c676f37SMartin Bugge return "Blu-Ray Disc (BD)";
12992c676f37SMartin Bugge case HDMI_SPD_SDI_SACD:
13002c676f37SMartin Bugge return "Super Audio CD";
13012c676f37SMartin Bugge case HDMI_SPD_SDI_HDDVD:
13022c676f37SMartin Bugge return "HD DVD";
13032c676f37SMartin Bugge case HDMI_SPD_SDI_PMP:
13042c676f37SMartin Bugge return "PMP";
13052c676f37SMartin Bugge }
13062c676f37SMartin Bugge return "Reserved";
13072c676f37SMartin Bugge }
13082c676f37SMartin Bugge
hdmi_spd_infoframe_log(const char * level,struct device * dev,const struct hdmi_spd_infoframe * frame)13092c676f37SMartin Bugge static void hdmi_spd_infoframe_log(const char *level,
13102c676f37SMartin Bugge struct device *dev,
1311468d6a49SVille Syrjälä const struct hdmi_spd_infoframe *frame)
13122c676f37SMartin Bugge {
13132c676f37SMartin Bugge u8 buf[17];
13142c676f37SMartin Bugge
13152c676f37SMartin Bugge hdmi_infoframe_log_header(level, dev,
1316468d6a49SVille Syrjälä (const struct hdmi_any_infoframe *)frame);
13172c676f37SMartin Bugge
13182c676f37SMartin Bugge memset(buf, 0, sizeof(buf));
13192c676f37SMartin Bugge
13202c676f37SMartin Bugge strncpy(buf, frame->vendor, 8);
13212c676f37SMartin Bugge hdmi_log(" vendor: %s\n", buf);
13222c676f37SMartin Bugge strncpy(buf, frame->product, 16);
13232c676f37SMartin Bugge hdmi_log(" product: %s\n", buf);
13242c676f37SMartin Bugge hdmi_log(" source device information: %s (0x%x)\n",
13252c676f37SMartin Bugge hdmi_spd_sdi_get_name(frame->sdi), frame->sdi);
13262c676f37SMartin Bugge }
13272c676f37SMartin Bugge
13282c676f37SMartin Bugge static const char *
hdmi_audio_coding_type_get_name(enum hdmi_audio_coding_type coding_type)13292c676f37SMartin Bugge hdmi_audio_coding_type_get_name(enum hdmi_audio_coding_type coding_type)
13302c676f37SMartin Bugge {
13312c676f37SMartin Bugge switch (coding_type) {
13322c676f37SMartin Bugge case HDMI_AUDIO_CODING_TYPE_STREAM:
13332c676f37SMartin Bugge return "Refer to Stream Header";
13342c676f37SMartin Bugge case HDMI_AUDIO_CODING_TYPE_PCM:
13352c676f37SMartin Bugge return "PCM";
13362c676f37SMartin Bugge case HDMI_AUDIO_CODING_TYPE_AC3:
13372c676f37SMartin Bugge return "AC-3";
13382c676f37SMartin Bugge case HDMI_AUDIO_CODING_TYPE_MPEG1:
13392c676f37SMartin Bugge return "MPEG1";
13402c676f37SMartin Bugge case HDMI_AUDIO_CODING_TYPE_MP3:
13412c676f37SMartin Bugge return "MP3";
13422c676f37SMartin Bugge case HDMI_AUDIO_CODING_TYPE_MPEG2:
13432c676f37SMartin Bugge return "MPEG2";
13442c676f37SMartin Bugge case HDMI_AUDIO_CODING_TYPE_AAC_LC:
13452c676f37SMartin Bugge return "AAC";
13462c676f37SMartin Bugge case HDMI_AUDIO_CODING_TYPE_DTS:
13472c676f37SMartin Bugge return "DTS";
13482c676f37SMartin Bugge case HDMI_AUDIO_CODING_TYPE_ATRAC:
13492c676f37SMartin Bugge return "ATRAC";
13502c676f37SMartin Bugge case HDMI_AUDIO_CODING_TYPE_DSD:
13512c676f37SMartin Bugge return "One Bit Audio";
13522c676f37SMartin Bugge case HDMI_AUDIO_CODING_TYPE_EAC3:
13532c676f37SMartin Bugge return "Dolby Digital +";
13542c676f37SMartin Bugge case HDMI_AUDIO_CODING_TYPE_DTS_HD:
13552c676f37SMartin Bugge return "DTS-HD";
13562c676f37SMartin Bugge case HDMI_AUDIO_CODING_TYPE_MLP:
13572c676f37SMartin Bugge return "MAT (MLP)";
13582c676f37SMartin Bugge case HDMI_AUDIO_CODING_TYPE_DST:
13592c676f37SMartin Bugge return "DST";
13602c676f37SMartin Bugge case HDMI_AUDIO_CODING_TYPE_WMA_PRO:
13612c676f37SMartin Bugge return "WMA PRO";
13622c676f37SMartin Bugge case HDMI_AUDIO_CODING_TYPE_CXT:
13632c676f37SMartin Bugge return "Refer to CXT";
13642c676f37SMartin Bugge }
13652c676f37SMartin Bugge return "Invalid";
13662c676f37SMartin Bugge }
13672c676f37SMartin Bugge
13682c676f37SMartin Bugge static const char *
hdmi_audio_sample_size_get_name(enum hdmi_audio_sample_size sample_size)13692c676f37SMartin Bugge hdmi_audio_sample_size_get_name(enum hdmi_audio_sample_size sample_size)
13702c676f37SMartin Bugge {
13712c676f37SMartin Bugge switch (sample_size) {
13722c676f37SMartin Bugge case HDMI_AUDIO_SAMPLE_SIZE_STREAM:
13732c676f37SMartin Bugge return "Refer to Stream Header";
13742c676f37SMartin Bugge case HDMI_AUDIO_SAMPLE_SIZE_16:
13752c676f37SMartin Bugge return "16 bit";
13762c676f37SMartin Bugge case HDMI_AUDIO_SAMPLE_SIZE_20:
13772c676f37SMartin Bugge return "20 bit";
13782c676f37SMartin Bugge case HDMI_AUDIO_SAMPLE_SIZE_24:
13792c676f37SMartin Bugge return "24 bit";
13802c676f37SMartin Bugge }
13812c676f37SMartin Bugge return "Invalid";
13822c676f37SMartin Bugge }
13832c676f37SMartin Bugge
13842c676f37SMartin Bugge static const char *
hdmi_audio_sample_frequency_get_name(enum hdmi_audio_sample_frequency freq)13852c676f37SMartin Bugge hdmi_audio_sample_frequency_get_name(enum hdmi_audio_sample_frequency freq)
13862c676f37SMartin Bugge {
13872c676f37SMartin Bugge switch (freq) {
13882c676f37SMartin Bugge case HDMI_AUDIO_SAMPLE_FREQUENCY_STREAM:
13892c676f37SMartin Bugge return "Refer to Stream Header";
13902c676f37SMartin Bugge case HDMI_AUDIO_SAMPLE_FREQUENCY_32000:
13912c676f37SMartin Bugge return "32 kHz";
13922c676f37SMartin Bugge case HDMI_AUDIO_SAMPLE_FREQUENCY_44100:
13932c676f37SMartin Bugge return "44.1 kHz (CD)";
13942c676f37SMartin Bugge case HDMI_AUDIO_SAMPLE_FREQUENCY_48000:
13952c676f37SMartin Bugge return "48 kHz";
13962c676f37SMartin Bugge case HDMI_AUDIO_SAMPLE_FREQUENCY_88200:
13972c676f37SMartin Bugge return "88.2 kHz";
13982c676f37SMartin Bugge case HDMI_AUDIO_SAMPLE_FREQUENCY_96000:
13992c676f37SMartin Bugge return "96 kHz";
14002c676f37SMartin Bugge case HDMI_AUDIO_SAMPLE_FREQUENCY_176400:
14012c676f37SMartin Bugge return "176.4 kHz";
14022c676f37SMartin Bugge case HDMI_AUDIO_SAMPLE_FREQUENCY_192000:
14032c676f37SMartin Bugge return "192 kHz";
14042c676f37SMartin Bugge }
14052c676f37SMartin Bugge return "Invalid";
14062c676f37SMartin Bugge }
14072c676f37SMartin Bugge
14082c676f37SMartin Bugge static const char *
hdmi_audio_coding_type_ext_get_name(enum hdmi_audio_coding_type_ext ctx)14092c676f37SMartin Bugge hdmi_audio_coding_type_ext_get_name(enum hdmi_audio_coding_type_ext ctx)
14102c676f37SMartin Bugge {
14112c676f37SMartin Bugge if (ctx < 0 || ctx > 0x1f)
14122c676f37SMartin Bugge return "Invalid";
14132c676f37SMartin Bugge
14142c676f37SMartin Bugge switch (ctx) {
1415dc189053SHans Verkuil case HDMI_AUDIO_CODING_TYPE_EXT_CT:
14162c676f37SMartin Bugge return "Refer to CT";
14172c676f37SMartin Bugge case HDMI_AUDIO_CODING_TYPE_EXT_HE_AAC:
14182c676f37SMartin Bugge return "HE AAC";
14192c676f37SMartin Bugge case HDMI_AUDIO_CODING_TYPE_EXT_HE_AAC_V2:
14202c676f37SMartin Bugge return "HE AAC v2";
14212c676f37SMartin Bugge case HDMI_AUDIO_CODING_TYPE_EXT_MPEG_SURROUND:
14222c676f37SMartin Bugge return "MPEG SURROUND";
14232c676f37SMartin Bugge case HDMI_AUDIO_CODING_TYPE_EXT_MPEG4_HE_AAC:
14242c676f37SMartin Bugge return "MPEG-4 HE AAC";
14252c676f37SMartin Bugge case HDMI_AUDIO_CODING_TYPE_EXT_MPEG4_HE_AAC_V2:
14262c676f37SMartin Bugge return "MPEG-4 HE AAC v2";
14272c676f37SMartin Bugge case HDMI_AUDIO_CODING_TYPE_EXT_MPEG4_AAC_LC:
14282c676f37SMartin Bugge return "MPEG-4 AAC LC";
14292c676f37SMartin Bugge case HDMI_AUDIO_CODING_TYPE_EXT_DRA:
14302c676f37SMartin Bugge return "DRA";
14312c676f37SMartin Bugge case HDMI_AUDIO_CODING_TYPE_EXT_MPEG4_HE_AAC_SURROUND:
14322c676f37SMartin Bugge return "MPEG-4 HE AAC + MPEG Surround";
14332c676f37SMartin Bugge case HDMI_AUDIO_CODING_TYPE_EXT_MPEG4_AAC_LC_SURROUND:
14342c676f37SMartin Bugge return "MPEG-4 AAC LC + MPEG Surround";
14352c676f37SMartin Bugge }
14362c676f37SMartin Bugge return "Reserved";
14372c676f37SMartin Bugge }
14382c676f37SMartin Bugge
hdmi_audio_infoframe_log(const char * level,struct device * dev,const struct hdmi_audio_infoframe * frame)14392c676f37SMartin Bugge static void hdmi_audio_infoframe_log(const char *level,
14402c676f37SMartin Bugge struct device *dev,
1441468d6a49SVille Syrjälä const struct hdmi_audio_infoframe *frame)
14422c676f37SMartin Bugge {
14432c676f37SMartin Bugge hdmi_infoframe_log_header(level, dev,
1444468d6a49SVille Syrjälä (const struct hdmi_any_infoframe *)frame);
14452c676f37SMartin Bugge
14462c676f37SMartin Bugge if (frame->channels)
14472c676f37SMartin Bugge hdmi_log(" channels: %u\n", frame->channels - 1);
14482c676f37SMartin Bugge else
14492c676f37SMartin Bugge hdmi_log(" channels: Refer to stream header\n");
14502c676f37SMartin Bugge hdmi_log(" coding type: %s\n",
14512c676f37SMartin Bugge hdmi_audio_coding_type_get_name(frame->coding_type));
14522c676f37SMartin Bugge hdmi_log(" sample size: %s\n",
14532c676f37SMartin Bugge hdmi_audio_sample_size_get_name(frame->sample_size));
14542c676f37SMartin Bugge hdmi_log(" sample frequency: %s\n",
14552c676f37SMartin Bugge hdmi_audio_sample_frequency_get_name(frame->sample_frequency));
14562c676f37SMartin Bugge hdmi_log(" coding type ext: %s\n",
14572c676f37SMartin Bugge hdmi_audio_coding_type_ext_get_name(frame->coding_type_ext));
14582c676f37SMartin Bugge hdmi_log(" channel allocation: 0x%x\n",
14592c676f37SMartin Bugge frame->channel_allocation);
14602c676f37SMartin Bugge hdmi_log(" level shift value: %u dB\n",
14612c676f37SMartin Bugge frame->level_shift_value);
14622c676f37SMartin Bugge hdmi_log(" downmix inhibit: %s\n",
14632c676f37SMartin Bugge frame->downmix_inhibit ? "Yes" : "No");
14642c676f37SMartin Bugge }
14652c676f37SMartin Bugge
hdmi_drm_infoframe_log(const char * level,struct device * dev,const struct hdmi_drm_infoframe * frame)14662cdbfd66SUma Shankar static void hdmi_drm_infoframe_log(const char *level,
14672cdbfd66SUma Shankar struct device *dev,
14682cdbfd66SUma Shankar const struct hdmi_drm_infoframe *frame)
14692cdbfd66SUma Shankar {
14702cdbfd66SUma Shankar int i;
14712cdbfd66SUma Shankar
14722cdbfd66SUma Shankar hdmi_infoframe_log_header(level, dev,
14732cdbfd66SUma Shankar (struct hdmi_any_infoframe *)frame);
14742cdbfd66SUma Shankar hdmi_log("length: %d\n", frame->length);
14752cdbfd66SUma Shankar hdmi_log("metadata type: %d\n", frame->metadata_type);
14762cdbfd66SUma Shankar hdmi_log("eotf: %d\n", frame->eotf);
14772cdbfd66SUma Shankar for (i = 0; i < 3; i++) {
14782cdbfd66SUma Shankar hdmi_log("x[%d]: %d\n", i, frame->display_primaries[i].x);
14792cdbfd66SUma Shankar hdmi_log("y[%d]: %d\n", i, frame->display_primaries[i].y);
14802cdbfd66SUma Shankar }
14812cdbfd66SUma Shankar
14822cdbfd66SUma Shankar hdmi_log("white point x: %d\n", frame->white_point.x);
14832cdbfd66SUma Shankar hdmi_log("white point y: %d\n", frame->white_point.y);
14842cdbfd66SUma Shankar
14852cdbfd66SUma Shankar hdmi_log("max_display_mastering_luminance: %d\n",
14862cdbfd66SUma Shankar frame->max_display_mastering_luminance);
14872cdbfd66SUma Shankar hdmi_log("min_display_mastering_luminance: %d\n",
14882cdbfd66SUma Shankar frame->min_display_mastering_luminance);
14892cdbfd66SUma Shankar
14902cdbfd66SUma Shankar hdmi_log("max_cll: %d\n", frame->max_cll);
14912cdbfd66SUma Shankar hdmi_log("max_fall: %d\n", frame->max_fall);
14922cdbfd66SUma Shankar }
14932cdbfd66SUma Shankar
14942c676f37SMartin Bugge static const char *
hdmi_3d_structure_get_name(enum hdmi_3d_structure s3d_struct)14952c676f37SMartin Bugge hdmi_3d_structure_get_name(enum hdmi_3d_structure s3d_struct)
14962c676f37SMartin Bugge {
14972c676f37SMartin Bugge if (s3d_struct < 0 || s3d_struct > 0xf)
14982c676f37SMartin Bugge return "Invalid";
14992c676f37SMartin Bugge
15002c676f37SMartin Bugge switch (s3d_struct) {
15012c676f37SMartin Bugge case HDMI_3D_STRUCTURE_FRAME_PACKING:
15022c676f37SMartin Bugge return "Frame Packing";
15032c676f37SMartin Bugge case HDMI_3D_STRUCTURE_FIELD_ALTERNATIVE:
15042c676f37SMartin Bugge return "Field Alternative";
15052c676f37SMartin Bugge case HDMI_3D_STRUCTURE_LINE_ALTERNATIVE:
15062c676f37SMartin Bugge return "Line Alternative";
15072c676f37SMartin Bugge case HDMI_3D_STRUCTURE_SIDE_BY_SIDE_FULL:
15082c676f37SMartin Bugge return "Side-by-side (Full)";
15092c676f37SMartin Bugge case HDMI_3D_STRUCTURE_L_DEPTH:
15102c676f37SMartin Bugge return "L + Depth";
15112c676f37SMartin Bugge case HDMI_3D_STRUCTURE_L_DEPTH_GFX_GFX_DEPTH:
15122c676f37SMartin Bugge return "L + Depth + Graphics + Graphics-depth";
15132c676f37SMartin Bugge case HDMI_3D_STRUCTURE_TOP_AND_BOTTOM:
15142c676f37SMartin Bugge return "Top-and-Bottom";
15152c676f37SMartin Bugge case HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF:
15162c676f37SMartin Bugge return "Side-by-side (Half)";
15172c676f37SMartin Bugge default:
15182c676f37SMartin Bugge break;
15192c676f37SMartin Bugge }
15202c676f37SMartin Bugge return "Reserved";
15212c676f37SMartin Bugge }
15222c676f37SMartin Bugge
15232c676f37SMartin Bugge static void
hdmi_vendor_any_infoframe_log(const char * level,struct device * dev,const union hdmi_vendor_any_infoframe * frame)15242c676f37SMartin Bugge hdmi_vendor_any_infoframe_log(const char *level,
15252c676f37SMartin Bugge struct device *dev,
1526468d6a49SVille Syrjälä const union hdmi_vendor_any_infoframe *frame)
15272c676f37SMartin Bugge {
1528468d6a49SVille Syrjälä const struct hdmi_vendor_infoframe *hvf = &frame->hdmi;
15292c676f37SMartin Bugge
15302c676f37SMartin Bugge hdmi_infoframe_log_header(level, dev,
1531468d6a49SVille Syrjälä (const struct hdmi_any_infoframe *)frame);
15322c676f37SMartin Bugge
15332c676f37SMartin Bugge if (frame->any.oui != HDMI_IEEE_OUI) {
15342c676f37SMartin Bugge hdmi_log(" not a HDMI vendor infoframe\n");
15352c676f37SMartin Bugge return;
15362c676f37SMartin Bugge }
15372c676f37SMartin Bugge if (hvf->vic == 0 && hvf->s3d_struct == HDMI_3D_STRUCTURE_INVALID) {
15382c676f37SMartin Bugge hdmi_log(" empty frame\n");
15392c676f37SMartin Bugge return;
15402c676f37SMartin Bugge }
15412c676f37SMartin Bugge
15422c676f37SMartin Bugge if (hvf->vic)
15432c676f37SMartin Bugge hdmi_log(" HDMI VIC: %u\n", hvf->vic);
15442c676f37SMartin Bugge if (hvf->s3d_struct != HDMI_3D_STRUCTURE_INVALID) {
15452c676f37SMartin Bugge hdmi_log(" 3D structure: %s\n",
15462c676f37SMartin Bugge hdmi_3d_structure_get_name(hvf->s3d_struct));
15472c676f37SMartin Bugge if (hvf->s3d_struct >= HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF)
15482c676f37SMartin Bugge hdmi_log(" 3D extension data: %d\n",
15492c676f37SMartin Bugge hvf->s3d_ext_data);
15502c676f37SMartin Bugge }
15512c676f37SMartin Bugge }
15522c676f37SMartin Bugge
15532c676f37SMartin Bugge /**
15542c676f37SMartin Bugge * hdmi_infoframe_log() - log info of HDMI infoframe
15552c676f37SMartin Bugge * @level: logging level
15562c676f37SMartin Bugge * @dev: device
15572c676f37SMartin Bugge * @frame: HDMI infoframe
15582c676f37SMartin Bugge */
hdmi_infoframe_log(const char * level,struct device * dev,const union hdmi_infoframe * frame)15592c676f37SMartin Bugge void hdmi_infoframe_log(const char *level,
15602c676f37SMartin Bugge struct device *dev,
1561468d6a49SVille Syrjälä const union hdmi_infoframe *frame)
15622c676f37SMartin Bugge {
15632c676f37SMartin Bugge switch (frame->any.type) {
15642c676f37SMartin Bugge case HDMI_INFOFRAME_TYPE_AVI:
15652c676f37SMartin Bugge hdmi_avi_infoframe_log(level, dev, &frame->avi);
15662c676f37SMartin Bugge break;
15672c676f37SMartin Bugge case HDMI_INFOFRAME_TYPE_SPD:
15682c676f37SMartin Bugge hdmi_spd_infoframe_log(level, dev, &frame->spd);
15692c676f37SMartin Bugge break;
15702c676f37SMartin Bugge case HDMI_INFOFRAME_TYPE_AUDIO:
15712c676f37SMartin Bugge hdmi_audio_infoframe_log(level, dev, &frame->audio);
15722c676f37SMartin Bugge break;
15732c676f37SMartin Bugge case HDMI_INFOFRAME_TYPE_VENDOR:
15742c676f37SMartin Bugge hdmi_vendor_any_infoframe_log(level, dev, &frame->vendor);
15752c676f37SMartin Bugge break;
15762cdbfd66SUma Shankar case HDMI_INFOFRAME_TYPE_DRM:
15772cdbfd66SUma Shankar hdmi_drm_infoframe_log(level, dev, &frame->drm);
15782cdbfd66SUma Shankar break;
15792c676f37SMartin Bugge }
15802c676f37SMartin Bugge }
15812c676f37SMartin Bugge EXPORT_SYMBOL(hdmi_infoframe_log);
15822c676f37SMartin Bugge
15832c676f37SMartin Bugge /**
15842c676f37SMartin Bugge * hdmi_avi_infoframe_unpack() - unpack binary buffer to a HDMI AVI infoframe
15852c676f37SMartin Bugge * @frame: HDMI AVI infoframe
1586480b8b3eSVille Syrjälä * @buffer: source buffer
1587480b8b3eSVille Syrjälä * @size: size of buffer
15882c676f37SMartin Bugge *
15892c676f37SMartin Bugge * Unpacks the information contained in binary @buffer into a structured
15902c676f37SMartin Bugge * @frame of the HDMI Auxiliary Video (AVI) information frame.
15912c676f37SMartin Bugge * Also verifies the checksum as required by section 5.3.5 of the HDMI 1.4
15922c676f37SMartin Bugge * specification.
15932c676f37SMartin Bugge *
15942c676f37SMartin Bugge * Returns 0 on success or a negative error code on failure.
15952c676f37SMartin Bugge */
hdmi_avi_infoframe_unpack(struct hdmi_avi_infoframe * frame,const void * buffer,size_t size)15962c676f37SMartin Bugge static int hdmi_avi_infoframe_unpack(struct hdmi_avi_infoframe *frame,
1597480b8b3eSVille Syrjälä const void *buffer, size_t size)
15982c676f37SMartin Bugge {
1599f26e1de5SVille Syrjälä const u8 *ptr = buffer;
16002c676f37SMartin Bugge
1601480b8b3eSVille Syrjälä if (size < HDMI_INFOFRAME_SIZE(AVI))
1602480b8b3eSVille Syrjälä return -EINVAL;
1603480b8b3eSVille Syrjälä
16042c676f37SMartin Bugge if (ptr[0] != HDMI_INFOFRAME_TYPE_AVI ||
16052c676f37SMartin Bugge ptr[1] != 2 ||
16062c676f37SMartin Bugge ptr[2] != HDMI_AVI_INFOFRAME_SIZE)
16072c676f37SMartin Bugge return -EINVAL;
16082c676f37SMartin Bugge
16092c676f37SMartin Bugge if (hdmi_infoframe_checksum(buffer, HDMI_INFOFRAME_SIZE(AVI)) != 0)
16102c676f37SMartin Bugge return -EINVAL;
16112c676f37SMartin Bugge
16125ee0caf1SLaurent Pinchart hdmi_avi_infoframe_init(frame);
16132c676f37SMartin Bugge
16142c676f37SMartin Bugge ptr += HDMI_INFOFRAME_HEADER_SIZE;
16152c676f37SMartin Bugge
16162c676f37SMartin Bugge frame->colorspace = (ptr[0] >> 5) & 0x3;
16172c676f37SMartin Bugge if (ptr[0] & 0x10)
16182c676f37SMartin Bugge frame->active_aspect = ptr[1] & 0xf;
16192c676f37SMartin Bugge if (ptr[0] & 0x8) {
16206039f37dSVille Syrjälä frame->top_bar = (ptr[6] << 8) | ptr[5];
16216039f37dSVille Syrjälä frame->bottom_bar = (ptr[8] << 8) | ptr[7];
16222c676f37SMartin Bugge }
16232c676f37SMartin Bugge if (ptr[0] & 0x4) {
16246039f37dSVille Syrjälä frame->left_bar = (ptr[10] << 8) | ptr[9];
16256039f37dSVille Syrjälä frame->right_bar = (ptr[12] << 8) | ptr[11];
16262c676f37SMartin Bugge }
16272c676f37SMartin Bugge frame->scan_mode = ptr[0] & 0x3;
16282c676f37SMartin Bugge
16292c676f37SMartin Bugge frame->colorimetry = (ptr[1] >> 6) & 0x3;
16302c676f37SMartin Bugge frame->picture_aspect = (ptr[1] >> 4) & 0x3;
16312c676f37SMartin Bugge frame->active_aspect = ptr[1] & 0xf;
16322c676f37SMartin Bugge
16332c676f37SMartin Bugge frame->itc = ptr[2] & 0x80 ? true : false;
16342c676f37SMartin Bugge frame->extended_colorimetry = (ptr[2] >> 4) & 0x7;
16352c676f37SMartin Bugge frame->quantization_range = (ptr[2] >> 2) & 0x3;
16362c676f37SMartin Bugge frame->nups = ptr[2] & 0x3;
16372c676f37SMartin Bugge
16382c676f37SMartin Bugge frame->video_code = ptr[3] & 0x7f;
16392c676f37SMartin Bugge frame->ycc_quantization_range = (ptr[4] >> 6) & 0x3;
16402c676f37SMartin Bugge frame->content_type = (ptr[4] >> 4) & 0x3;
16412c676f37SMartin Bugge
16422c676f37SMartin Bugge frame->pixel_repeat = ptr[4] & 0xf;
16432c676f37SMartin Bugge
16442c676f37SMartin Bugge return 0;
16452c676f37SMartin Bugge }
16462c676f37SMartin Bugge
16472c676f37SMartin Bugge /**
16482c676f37SMartin Bugge * hdmi_spd_infoframe_unpack() - unpack binary buffer to a HDMI SPD infoframe
16492c676f37SMartin Bugge * @frame: HDMI SPD infoframe
1650480b8b3eSVille Syrjälä * @buffer: source buffer
1651480b8b3eSVille Syrjälä * @size: size of buffer
16522c676f37SMartin Bugge *
16532c676f37SMartin Bugge * Unpacks the information contained in binary @buffer into a structured
16542c676f37SMartin Bugge * @frame of the HDMI Source Product Description (SPD) information frame.
16552c676f37SMartin Bugge * Also verifies the checksum as required by section 5.3.5 of the HDMI 1.4
16562c676f37SMartin Bugge * specification.
16572c676f37SMartin Bugge *
16582c676f37SMartin Bugge * Returns 0 on success or a negative error code on failure.
16592c676f37SMartin Bugge */
hdmi_spd_infoframe_unpack(struct hdmi_spd_infoframe * frame,const void * buffer,size_t size)16602c676f37SMartin Bugge static int hdmi_spd_infoframe_unpack(struct hdmi_spd_infoframe *frame,
1661480b8b3eSVille Syrjälä const void *buffer, size_t size)
16622c676f37SMartin Bugge {
1663f26e1de5SVille Syrjälä const u8 *ptr = buffer;
16642c676f37SMartin Bugge int ret;
16652c676f37SMartin Bugge
1666480b8b3eSVille Syrjälä if (size < HDMI_INFOFRAME_SIZE(SPD))
1667480b8b3eSVille Syrjälä return -EINVAL;
1668480b8b3eSVille Syrjälä
16692c676f37SMartin Bugge if (ptr[0] != HDMI_INFOFRAME_TYPE_SPD ||
16702c676f37SMartin Bugge ptr[1] != 1 ||
16712c676f37SMartin Bugge ptr[2] != HDMI_SPD_INFOFRAME_SIZE) {
16722c676f37SMartin Bugge return -EINVAL;
16732c676f37SMartin Bugge }
16742c676f37SMartin Bugge
16752c676f37SMartin Bugge if (hdmi_infoframe_checksum(buffer, HDMI_INFOFRAME_SIZE(SPD)) != 0)
16762c676f37SMartin Bugge return -EINVAL;
16772c676f37SMartin Bugge
16782c676f37SMartin Bugge ptr += HDMI_INFOFRAME_HEADER_SIZE;
16792c676f37SMartin Bugge
16802c676f37SMartin Bugge ret = hdmi_spd_infoframe_init(frame, ptr, ptr + 8);
16812c676f37SMartin Bugge if (ret)
16822c676f37SMartin Bugge return ret;
16832c676f37SMartin Bugge
16842c676f37SMartin Bugge frame->sdi = ptr[24];
16852c676f37SMartin Bugge
16862c676f37SMartin Bugge return 0;
16872c676f37SMartin Bugge }
16882c676f37SMartin Bugge
16892c676f37SMartin Bugge /**
16902c676f37SMartin Bugge * hdmi_audio_infoframe_unpack() - unpack binary buffer to a HDMI AUDIO infoframe
16912c676f37SMartin Bugge * @frame: HDMI Audio infoframe
1692480b8b3eSVille Syrjälä * @buffer: source buffer
1693480b8b3eSVille Syrjälä * @size: size of buffer
16942c676f37SMartin Bugge *
16952c676f37SMartin Bugge * Unpacks the information contained in binary @buffer into a structured
16962c676f37SMartin Bugge * @frame of the HDMI Audio information frame.
16972c676f37SMartin Bugge * Also verifies the checksum as required by section 5.3.5 of the HDMI 1.4
16982c676f37SMartin Bugge * specification.
16992c676f37SMartin Bugge *
17002c676f37SMartin Bugge * Returns 0 on success or a negative error code on failure.
17012c676f37SMartin Bugge */
hdmi_audio_infoframe_unpack(struct hdmi_audio_infoframe * frame,const void * buffer,size_t size)17022c676f37SMartin Bugge static int hdmi_audio_infoframe_unpack(struct hdmi_audio_infoframe *frame,
1703480b8b3eSVille Syrjälä const void *buffer, size_t size)
17042c676f37SMartin Bugge {
1705f26e1de5SVille Syrjälä const u8 *ptr = buffer;
17062c676f37SMartin Bugge int ret;
17072c676f37SMartin Bugge
1708480b8b3eSVille Syrjälä if (size < HDMI_INFOFRAME_SIZE(AUDIO))
1709480b8b3eSVille Syrjälä return -EINVAL;
1710480b8b3eSVille Syrjälä
17112c676f37SMartin Bugge if (ptr[0] != HDMI_INFOFRAME_TYPE_AUDIO ||
17122c676f37SMartin Bugge ptr[1] != 1 ||
17132c676f37SMartin Bugge ptr[2] != HDMI_AUDIO_INFOFRAME_SIZE) {
17142c676f37SMartin Bugge return -EINVAL;
17152c676f37SMartin Bugge }
17162c676f37SMartin Bugge
17172c676f37SMartin Bugge if (hdmi_infoframe_checksum(buffer, HDMI_INFOFRAME_SIZE(AUDIO)) != 0)
17182c676f37SMartin Bugge return -EINVAL;
17192c676f37SMartin Bugge
17202c676f37SMartin Bugge ret = hdmi_audio_infoframe_init(frame);
17212c676f37SMartin Bugge if (ret)
17222c676f37SMartin Bugge return ret;
17232c676f37SMartin Bugge
17242c676f37SMartin Bugge ptr += HDMI_INFOFRAME_HEADER_SIZE;
17252c676f37SMartin Bugge
17262c676f37SMartin Bugge frame->channels = ptr[0] & 0x7;
17272c676f37SMartin Bugge frame->coding_type = (ptr[0] >> 4) & 0xf;
17282c676f37SMartin Bugge frame->sample_size = ptr[1] & 0x3;
17292c676f37SMartin Bugge frame->sample_frequency = (ptr[1] >> 2) & 0x7;
17302c676f37SMartin Bugge frame->coding_type_ext = ptr[2] & 0x1f;
17312c676f37SMartin Bugge frame->channel_allocation = ptr[3];
17322c676f37SMartin Bugge frame->level_shift_value = (ptr[4] >> 3) & 0xf;
17332c676f37SMartin Bugge frame->downmix_inhibit = ptr[4] & 0x80 ? true : false;
17342c676f37SMartin Bugge
17352c676f37SMartin Bugge return 0;
17362c676f37SMartin Bugge }
17372c676f37SMartin Bugge
17382c676f37SMartin Bugge /**
1739250fe9a5SMauro Carvalho Chehab * hdmi_vendor_any_infoframe_unpack() - unpack binary buffer to a HDMI
1740250fe9a5SMauro Carvalho Chehab * vendor infoframe
17412c676f37SMartin Bugge * @frame: HDMI Vendor infoframe
1742480b8b3eSVille Syrjälä * @buffer: source buffer
1743480b8b3eSVille Syrjälä * @size: size of buffer
17442c676f37SMartin Bugge *
17452c676f37SMartin Bugge * Unpacks the information contained in binary @buffer into a structured
17462c676f37SMartin Bugge * @frame of the HDMI Vendor information frame.
17472c676f37SMartin Bugge * Also verifies the checksum as required by section 5.3.5 of the HDMI 1.4
17482c676f37SMartin Bugge * specification.
17492c676f37SMartin Bugge *
17502c676f37SMartin Bugge * Returns 0 on success or a negative error code on failure.
17512c676f37SMartin Bugge */
17522c676f37SMartin Bugge static int
hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe * frame,const void * buffer,size_t size)17532c676f37SMartin Bugge hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
1754480b8b3eSVille Syrjälä const void *buffer, size_t size)
17552c676f37SMartin Bugge {
1756f26e1de5SVille Syrjälä const u8 *ptr = buffer;
17572c676f37SMartin Bugge size_t length;
17582c676f37SMartin Bugge int ret;
17592c676f37SMartin Bugge u8 hdmi_video_format;
17602c676f37SMartin Bugge struct hdmi_vendor_infoframe *hvf = &frame->hdmi;
17612c676f37SMartin Bugge
1762480b8b3eSVille Syrjälä if (size < HDMI_INFOFRAME_HEADER_SIZE)
1763480b8b3eSVille Syrjälä return -EINVAL;
1764480b8b3eSVille Syrjälä
17652c676f37SMartin Bugge if (ptr[0] != HDMI_INFOFRAME_TYPE_VENDOR ||
17662c676f37SMartin Bugge ptr[1] != 1 ||
1767593f4b19SVille Syrjälä (ptr[2] != 4 && ptr[2] != 5 && ptr[2] != 6))
17682c676f37SMartin Bugge return -EINVAL;
17692c676f37SMartin Bugge
17702c676f37SMartin Bugge length = ptr[2];
17712c676f37SMartin Bugge
1772480b8b3eSVille Syrjälä if (size < HDMI_INFOFRAME_HEADER_SIZE + length)
1773480b8b3eSVille Syrjälä return -EINVAL;
1774480b8b3eSVille Syrjälä
17752c676f37SMartin Bugge if (hdmi_infoframe_checksum(buffer,
17762c676f37SMartin Bugge HDMI_INFOFRAME_HEADER_SIZE + length) != 0)
17772c676f37SMartin Bugge return -EINVAL;
17782c676f37SMartin Bugge
17792c676f37SMartin Bugge ptr += HDMI_INFOFRAME_HEADER_SIZE;
17802c676f37SMartin Bugge
17812c676f37SMartin Bugge /* HDMI OUI */
17822c676f37SMartin Bugge if ((ptr[0] != 0x03) ||
17832c676f37SMartin Bugge (ptr[1] != 0x0c) ||
17842c676f37SMartin Bugge (ptr[2] != 0x00))
17852c676f37SMartin Bugge return -EINVAL;
17862c676f37SMartin Bugge
17872c676f37SMartin Bugge hdmi_video_format = ptr[3] >> 5;
17882c676f37SMartin Bugge
17892c676f37SMartin Bugge if (hdmi_video_format > 0x2)
17902c676f37SMartin Bugge return -EINVAL;
17912c676f37SMartin Bugge
17922c676f37SMartin Bugge ret = hdmi_vendor_infoframe_init(hvf);
17932c676f37SMartin Bugge if (ret)
17942c676f37SMartin Bugge return ret;
17952c676f37SMartin Bugge
17962c676f37SMartin Bugge hvf->length = length;
17972c676f37SMartin Bugge
1798593f4b19SVille Syrjälä if (hdmi_video_format == 0x2) {
1799593f4b19SVille Syrjälä if (length != 5 && length != 6)
1800593f4b19SVille Syrjälä return -EINVAL;
18012c676f37SMartin Bugge hvf->s3d_struct = ptr[4] >> 4;
18022c676f37SMartin Bugge if (hvf->s3d_struct >= HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF) {
1803593f4b19SVille Syrjälä if (length != 6)
18042c676f37SMartin Bugge return -EINVAL;
1805593f4b19SVille Syrjälä hvf->s3d_ext_data = ptr[5] >> 4;
18062c676f37SMartin Bugge }
1807593f4b19SVille Syrjälä } else if (hdmi_video_format == 0x1) {
1808593f4b19SVille Syrjälä if (length != 5)
1809593f4b19SVille Syrjälä return -EINVAL;
1810593f4b19SVille Syrjälä hvf->vic = ptr[4];
1811593f4b19SVille Syrjälä } else {
1812593f4b19SVille Syrjälä if (length != 4)
1813593f4b19SVille Syrjälä return -EINVAL;
18142c676f37SMartin Bugge }
18152c676f37SMartin Bugge
18162c676f37SMartin Bugge return 0;
18172c676f37SMartin Bugge }
18182c676f37SMartin Bugge
18192c676f37SMartin Bugge /**
1820f45ce933SGwan-gyeong Mun * hdmi_drm_infoframe_unpack_only() - unpack binary buffer of CTA-861-G DRM
1821f45ce933SGwan-gyeong Mun * infoframe DataBytes to a HDMI DRM
1822f45ce933SGwan-gyeong Mun * infoframe
1823270afb37SUma Shankar * @frame: HDMI DRM infoframe
1824270afb37SUma Shankar * @buffer: source buffer
1825270afb37SUma Shankar * @size: size of buffer
1826270afb37SUma Shankar *
1827f45ce933SGwan-gyeong Mun * Unpacks CTA-861-G DRM infoframe DataBytes contained in the binary @buffer
1828f45ce933SGwan-gyeong Mun * into a structured @frame of the HDMI Dynamic Range and Mastering (DRM)
1829f45ce933SGwan-gyeong Mun * infoframe.
1830270afb37SUma Shankar *
1831270afb37SUma Shankar * Returns 0 on success or a negative error code on failure.
1832270afb37SUma Shankar */
hdmi_drm_infoframe_unpack_only(struct hdmi_drm_infoframe * frame,const void * buffer,size_t size)1833f45ce933SGwan-gyeong Mun int hdmi_drm_infoframe_unpack_only(struct hdmi_drm_infoframe *frame,
1834270afb37SUma Shankar const void *buffer, size_t size)
1835270afb37SUma Shankar {
1836270afb37SUma Shankar const u8 *ptr = buffer;
1837270afb37SUma Shankar const u8 *temp;
1838270afb37SUma Shankar u8 x_lsb, x_msb;
1839270afb37SUma Shankar u8 y_lsb, y_msb;
1840270afb37SUma Shankar int ret;
1841270afb37SUma Shankar int i;
1842270afb37SUma Shankar
1843f45ce933SGwan-gyeong Mun if (size < HDMI_DRM_INFOFRAME_SIZE)
1844270afb37SUma Shankar return -EINVAL;
1845270afb37SUma Shankar
1846270afb37SUma Shankar ret = hdmi_drm_infoframe_init(frame);
1847270afb37SUma Shankar if (ret)
1848270afb37SUma Shankar return ret;
1849270afb37SUma Shankar
1850270afb37SUma Shankar frame->eotf = ptr[0] & 0x7;
1851270afb37SUma Shankar frame->metadata_type = ptr[1] & 0x7;
1852270afb37SUma Shankar
1853270afb37SUma Shankar temp = ptr + 2;
1854270afb37SUma Shankar for (i = 0; i < 3; i++) {
1855270afb37SUma Shankar x_lsb = *temp++;
1856270afb37SUma Shankar x_msb = *temp++;
1857270afb37SUma Shankar frame->display_primaries[i].x = (x_msb << 8) | x_lsb;
1858270afb37SUma Shankar y_lsb = *temp++;
1859270afb37SUma Shankar y_msb = *temp++;
1860270afb37SUma Shankar frame->display_primaries[i].y = (y_msb << 8) | y_lsb;
1861270afb37SUma Shankar }
1862270afb37SUma Shankar
1863270afb37SUma Shankar frame->white_point.x = (ptr[15] << 8) | ptr[14];
1864270afb37SUma Shankar frame->white_point.y = (ptr[17] << 8) | ptr[16];
1865270afb37SUma Shankar
1866270afb37SUma Shankar frame->max_display_mastering_luminance = (ptr[19] << 8) | ptr[18];
1867270afb37SUma Shankar frame->min_display_mastering_luminance = (ptr[21] << 8) | ptr[20];
1868270afb37SUma Shankar frame->max_cll = (ptr[23] << 8) | ptr[22];
1869270afb37SUma Shankar frame->max_fall = (ptr[25] << 8) | ptr[24];
1870270afb37SUma Shankar
1871270afb37SUma Shankar return 0;
1872270afb37SUma Shankar }
1873f45ce933SGwan-gyeong Mun EXPORT_SYMBOL(hdmi_drm_infoframe_unpack_only);
1874f45ce933SGwan-gyeong Mun
1875f45ce933SGwan-gyeong Mun /**
1876f45ce933SGwan-gyeong Mun * hdmi_drm_infoframe_unpack() - unpack binary buffer to a HDMI DRM infoframe
1877f45ce933SGwan-gyeong Mun * @frame: HDMI DRM infoframe
1878f45ce933SGwan-gyeong Mun * @buffer: source buffer
1879f45ce933SGwan-gyeong Mun * @size: size of buffer
1880f45ce933SGwan-gyeong Mun *
1881f45ce933SGwan-gyeong Mun * Unpacks the CTA-861-G DRM infoframe contained in the binary @buffer into
1882f45ce933SGwan-gyeong Mun * a structured @frame of the HDMI Dynamic Range and Mastering (DRM)
1883f45ce933SGwan-gyeong Mun * infoframe. It also verifies the checksum as required by section 5.3.5 of
1884f45ce933SGwan-gyeong Mun * the HDMI 1.4 specification.
1885f45ce933SGwan-gyeong Mun *
1886f45ce933SGwan-gyeong Mun * Returns 0 on success or a negative error code on failure.
1887f45ce933SGwan-gyeong Mun */
hdmi_drm_infoframe_unpack(struct hdmi_drm_infoframe * frame,const void * buffer,size_t size)1888f45ce933SGwan-gyeong Mun static int hdmi_drm_infoframe_unpack(struct hdmi_drm_infoframe *frame,
1889f45ce933SGwan-gyeong Mun const void *buffer, size_t size)
1890f45ce933SGwan-gyeong Mun {
1891f45ce933SGwan-gyeong Mun const u8 *ptr = buffer;
1892f45ce933SGwan-gyeong Mun int ret;
1893f45ce933SGwan-gyeong Mun
1894f45ce933SGwan-gyeong Mun if (size < HDMI_INFOFRAME_SIZE(DRM))
1895f45ce933SGwan-gyeong Mun return -EINVAL;
1896f45ce933SGwan-gyeong Mun
1897f45ce933SGwan-gyeong Mun if (ptr[0] != HDMI_INFOFRAME_TYPE_DRM ||
1898f45ce933SGwan-gyeong Mun ptr[1] != 1 ||
1899f45ce933SGwan-gyeong Mun ptr[2] != HDMI_DRM_INFOFRAME_SIZE)
1900f45ce933SGwan-gyeong Mun return -EINVAL;
1901f45ce933SGwan-gyeong Mun
1902f45ce933SGwan-gyeong Mun if (hdmi_infoframe_checksum(buffer, HDMI_INFOFRAME_SIZE(DRM)) != 0)
1903f45ce933SGwan-gyeong Mun return -EINVAL;
1904f45ce933SGwan-gyeong Mun
1905f45ce933SGwan-gyeong Mun ret = hdmi_drm_infoframe_unpack_only(frame, ptr + HDMI_INFOFRAME_HEADER_SIZE,
1906f45ce933SGwan-gyeong Mun size - HDMI_INFOFRAME_HEADER_SIZE);
1907f45ce933SGwan-gyeong Mun return ret;
1908f45ce933SGwan-gyeong Mun }
1909270afb37SUma Shankar
1910270afb37SUma Shankar /**
19112c676f37SMartin Bugge * hdmi_infoframe_unpack() - unpack binary buffer to a HDMI infoframe
19122c676f37SMartin Bugge * @frame: HDMI infoframe
1913480b8b3eSVille Syrjälä * @buffer: source buffer
1914480b8b3eSVille Syrjälä * @size: size of buffer
19152c676f37SMartin Bugge *
19162c676f37SMartin Bugge * Unpacks the information contained in binary buffer @buffer into a structured
19172c676f37SMartin Bugge * @frame of a HDMI infoframe.
19182c676f37SMartin Bugge * Also verifies the checksum as required by section 5.3.5 of the HDMI 1.4
19192c676f37SMartin Bugge * specification.
19202c676f37SMartin Bugge *
19212c676f37SMartin Bugge * Returns 0 on success or a negative error code on failure.
19222c676f37SMartin Bugge */
hdmi_infoframe_unpack(union hdmi_infoframe * frame,const void * buffer,size_t size)1923f26e1de5SVille Syrjälä int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
1924480b8b3eSVille Syrjälä const void *buffer, size_t size)
19252c676f37SMartin Bugge {
19262c676f37SMartin Bugge int ret;
1927f26e1de5SVille Syrjälä const u8 *ptr = buffer;
19282c676f37SMartin Bugge
1929480b8b3eSVille Syrjälä if (size < HDMI_INFOFRAME_HEADER_SIZE)
1930480b8b3eSVille Syrjälä return -EINVAL;
1931480b8b3eSVille Syrjälä
19322c676f37SMartin Bugge switch (ptr[0]) {
19332c676f37SMartin Bugge case HDMI_INFOFRAME_TYPE_AVI:
1934480b8b3eSVille Syrjälä ret = hdmi_avi_infoframe_unpack(&frame->avi, buffer, size);
19352c676f37SMartin Bugge break;
1936270afb37SUma Shankar case HDMI_INFOFRAME_TYPE_DRM:
1937270afb37SUma Shankar ret = hdmi_drm_infoframe_unpack(&frame->drm, buffer, size);
1938270afb37SUma Shankar break;
19392c676f37SMartin Bugge case HDMI_INFOFRAME_TYPE_SPD:
1940480b8b3eSVille Syrjälä ret = hdmi_spd_infoframe_unpack(&frame->spd, buffer, size);
19412c676f37SMartin Bugge break;
19422c676f37SMartin Bugge case HDMI_INFOFRAME_TYPE_AUDIO:
1943480b8b3eSVille Syrjälä ret = hdmi_audio_infoframe_unpack(&frame->audio, buffer, size);
19442c676f37SMartin Bugge break;
19452c676f37SMartin Bugge case HDMI_INFOFRAME_TYPE_VENDOR:
1946480b8b3eSVille Syrjälä ret = hdmi_vendor_any_infoframe_unpack(&frame->vendor, buffer, size);
19472c676f37SMartin Bugge break;
19482c676f37SMartin Bugge default:
19492c676f37SMartin Bugge ret = -EINVAL;
19502c676f37SMartin Bugge break;
19512c676f37SMartin Bugge }
19522c676f37SMartin Bugge
19532c676f37SMartin Bugge return ret;
19542c676f37SMartin Bugge }
19552c676f37SMartin Bugge EXPORT_SYMBOL(hdmi_infoframe_unpack);
1956