1c349dbc7Sjsg /*
2c349dbc7Sjsg * Copyright (C) 2012 Avionic Design GmbH
3c349dbc7Sjsg *
4c349dbc7Sjsg * Permission is hereby granted, free of charge, to any person obtaining a
5c349dbc7Sjsg * copy of this software and associated documentation files (the "Software"),
6c349dbc7Sjsg * to deal in the Software without restriction, including without limitation
7c349dbc7Sjsg * the rights to use, copy, modify, merge, publish, distribute, sub license,
8c349dbc7Sjsg * and/or sell copies of the Software, and to permit persons to whom the
9c349dbc7Sjsg * Software is furnished to do so, subject to the following conditions:
10c349dbc7Sjsg *
11c349dbc7Sjsg * The above copyright notice and this permission notice (including the
12c349dbc7Sjsg * next paragraph) shall be included in all copies or substantial portions
13c349dbc7Sjsg * of the Software.
14c349dbc7Sjsg *
15c349dbc7Sjsg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16c349dbc7Sjsg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17c349dbc7Sjsg * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
18c349dbc7Sjsg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19c349dbc7Sjsg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20c349dbc7Sjsg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21c349dbc7Sjsg * DEALINGS IN THE SOFTWARE.
22c349dbc7Sjsg */
23c349dbc7Sjsg
24*1bb76ff1Sjsg #include <drm/display/drm_dp.h>
25c349dbc7Sjsg #include <linux/bitops.h>
26c349dbc7Sjsg #include <linux/bug.h>
27c349dbc7Sjsg #include <linux/errno.h>
28c349dbc7Sjsg #include <linux/export.h>
29c349dbc7Sjsg #include <linux/hdmi.h>
30c349dbc7Sjsg #include <linux/string.h>
31c349dbc7Sjsg #include <linux/device.h>
32c349dbc7Sjsg
33c349dbc7Sjsg #define hdmi_log(fmt, ...) dev_printk(level, dev, fmt, ##__VA_ARGS__)
34c349dbc7Sjsg
hdmi_infoframe_checksum(const u8 * ptr,size_t size)35c349dbc7Sjsg static u8 hdmi_infoframe_checksum(const u8 *ptr, size_t size)
36c349dbc7Sjsg {
37c349dbc7Sjsg u8 csum = 0;
38c349dbc7Sjsg size_t i;
39c349dbc7Sjsg
40c349dbc7Sjsg /* compute checksum */
41c349dbc7Sjsg for (i = 0; i < size; i++)
42c349dbc7Sjsg csum += ptr[i];
43c349dbc7Sjsg
44c349dbc7Sjsg return 256 - csum;
45c349dbc7Sjsg }
46c349dbc7Sjsg
hdmi_infoframe_set_checksum(void * buffer,size_t size)47c349dbc7Sjsg static void hdmi_infoframe_set_checksum(void *buffer, size_t size)
48c349dbc7Sjsg {
49c349dbc7Sjsg u8 *ptr = buffer;
50c349dbc7Sjsg
51c349dbc7Sjsg ptr[3] = hdmi_infoframe_checksum(buffer, size);
52c349dbc7Sjsg }
53c349dbc7Sjsg
54c349dbc7Sjsg /**
55c349dbc7Sjsg * hdmi_avi_infoframe_init() - initialize an HDMI AVI infoframe
56c349dbc7Sjsg * @frame: HDMI AVI infoframe
57c349dbc7Sjsg */
hdmi_avi_infoframe_init(struct hdmi_avi_infoframe * frame)58c349dbc7Sjsg void hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame)
59c349dbc7Sjsg {
60c349dbc7Sjsg memset(frame, 0, sizeof(*frame));
61c349dbc7Sjsg
62c349dbc7Sjsg frame->type = HDMI_INFOFRAME_TYPE_AVI;
63c349dbc7Sjsg frame->version = 2;
64c349dbc7Sjsg frame->length = HDMI_AVI_INFOFRAME_SIZE;
65c349dbc7Sjsg }
66c349dbc7Sjsg EXPORT_SYMBOL(hdmi_avi_infoframe_init);
67c349dbc7Sjsg
hdmi_avi_infoframe_check_only(const struct hdmi_avi_infoframe * frame)68c349dbc7Sjsg static int hdmi_avi_infoframe_check_only(const struct hdmi_avi_infoframe *frame)
69c349dbc7Sjsg {
70c349dbc7Sjsg if (frame->type != HDMI_INFOFRAME_TYPE_AVI ||
71c349dbc7Sjsg frame->version != 2 ||
72c349dbc7Sjsg frame->length != HDMI_AVI_INFOFRAME_SIZE)
73c349dbc7Sjsg return -EINVAL;
74c349dbc7Sjsg
75c349dbc7Sjsg if (frame->picture_aspect > HDMI_PICTURE_ASPECT_16_9)
76c349dbc7Sjsg return -EINVAL;
77c349dbc7Sjsg
78c349dbc7Sjsg return 0;
79c349dbc7Sjsg }
80c349dbc7Sjsg
81c349dbc7Sjsg /**
82c349dbc7Sjsg * hdmi_avi_infoframe_check() - check a HDMI AVI infoframe
83c349dbc7Sjsg * @frame: HDMI AVI infoframe
84c349dbc7Sjsg *
85c349dbc7Sjsg * Validates that the infoframe is consistent and updates derived fields
86c349dbc7Sjsg * (eg. length) based on other fields.
87c349dbc7Sjsg *
88c349dbc7Sjsg * Returns 0 on success or a negative error code on failure.
89c349dbc7Sjsg */
hdmi_avi_infoframe_check(struct hdmi_avi_infoframe * frame)90c349dbc7Sjsg int hdmi_avi_infoframe_check(struct hdmi_avi_infoframe *frame)
91c349dbc7Sjsg {
92c349dbc7Sjsg return hdmi_avi_infoframe_check_only(frame);
93c349dbc7Sjsg }
94c349dbc7Sjsg EXPORT_SYMBOL(hdmi_avi_infoframe_check);
95c349dbc7Sjsg
96c349dbc7Sjsg /**
97c349dbc7Sjsg * hdmi_avi_infoframe_pack_only() - write HDMI AVI infoframe to binary buffer
98c349dbc7Sjsg * @frame: HDMI AVI infoframe
99c349dbc7Sjsg * @buffer: destination buffer
100c349dbc7Sjsg * @size: size of buffer
101c349dbc7Sjsg *
102c349dbc7Sjsg * Packs the information contained in the @frame structure into a binary
103c349dbc7Sjsg * representation that can be written into the corresponding controller
104c349dbc7Sjsg * registers. Also computes the checksum as required by section 5.3.5 of
105c349dbc7Sjsg * the HDMI 1.4 specification.
106c349dbc7Sjsg *
107c349dbc7Sjsg * Returns the number of bytes packed into the binary buffer or a negative
108c349dbc7Sjsg * error code on failure.
109c349dbc7Sjsg */
hdmi_avi_infoframe_pack_only(const struct hdmi_avi_infoframe * frame,void * buffer,size_t size)110c349dbc7Sjsg ssize_t hdmi_avi_infoframe_pack_only(const struct hdmi_avi_infoframe *frame,
111c349dbc7Sjsg void *buffer, size_t size)
112c349dbc7Sjsg {
113c349dbc7Sjsg u8 *ptr = buffer;
114c349dbc7Sjsg size_t length;
115c349dbc7Sjsg int ret;
116c349dbc7Sjsg
117c349dbc7Sjsg ret = hdmi_avi_infoframe_check_only(frame);
118c349dbc7Sjsg if (ret)
119c349dbc7Sjsg return ret;
120c349dbc7Sjsg
121c349dbc7Sjsg length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
122c349dbc7Sjsg
123c349dbc7Sjsg if (size < length)
124c349dbc7Sjsg return -ENOSPC;
125c349dbc7Sjsg
126c349dbc7Sjsg memset(buffer, 0, size);
127c349dbc7Sjsg
128c349dbc7Sjsg ptr[0] = frame->type;
129c349dbc7Sjsg ptr[1] = frame->version;
130c349dbc7Sjsg ptr[2] = frame->length;
131c349dbc7Sjsg ptr[3] = 0; /* checksum */
132c349dbc7Sjsg
133c349dbc7Sjsg /* start infoframe payload */
134c349dbc7Sjsg ptr += HDMI_INFOFRAME_HEADER_SIZE;
135c349dbc7Sjsg
136c349dbc7Sjsg ptr[0] = ((frame->colorspace & 0x3) << 5) | (frame->scan_mode & 0x3);
137c349dbc7Sjsg
138c349dbc7Sjsg /*
139c349dbc7Sjsg * Data byte 1, bit 4 has to be set if we provide the active format
140c349dbc7Sjsg * aspect ratio
141c349dbc7Sjsg */
142c349dbc7Sjsg if (frame->active_aspect & 0xf)
143c349dbc7Sjsg ptr[0] |= BIT(4);
144c349dbc7Sjsg
145c349dbc7Sjsg /* Bit 3 and 2 indicate if we transmit horizontal/vertical bar data */
146c349dbc7Sjsg if (frame->top_bar || frame->bottom_bar)
147c349dbc7Sjsg ptr[0] |= BIT(3);
148c349dbc7Sjsg
149c349dbc7Sjsg if (frame->left_bar || frame->right_bar)
150c349dbc7Sjsg ptr[0] |= BIT(2);
151c349dbc7Sjsg
152c349dbc7Sjsg ptr[1] = ((frame->colorimetry & 0x3) << 6) |
153c349dbc7Sjsg ((frame->picture_aspect & 0x3) << 4) |
154c349dbc7Sjsg (frame->active_aspect & 0xf);
155c349dbc7Sjsg
156c349dbc7Sjsg ptr[2] = ((frame->extended_colorimetry & 0x7) << 4) |
157c349dbc7Sjsg ((frame->quantization_range & 0x3) << 2) |
158c349dbc7Sjsg (frame->nups & 0x3);
159c349dbc7Sjsg
160c349dbc7Sjsg if (frame->itc)
161c349dbc7Sjsg ptr[2] |= BIT(7);
162c349dbc7Sjsg
163c349dbc7Sjsg ptr[3] = frame->video_code & 0x7f;
164c349dbc7Sjsg
165c349dbc7Sjsg ptr[4] = ((frame->ycc_quantization_range & 0x3) << 6) |
166c349dbc7Sjsg ((frame->content_type & 0x3) << 4) |
167c349dbc7Sjsg (frame->pixel_repeat & 0xf);
168c349dbc7Sjsg
169c349dbc7Sjsg ptr[5] = frame->top_bar & 0xff;
170c349dbc7Sjsg ptr[6] = (frame->top_bar >> 8) & 0xff;
171c349dbc7Sjsg ptr[7] = frame->bottom_bar & 0xff;
172c349dbc7Sjsg ptr[8] = (frame->bottom_bar >> 8) & 0xff;
173c349dbc7Sjsg ptr[9] = frame->left_bar & 0xff;
174c349dbc7Sjsg ptr[10] = (frame->left_bar >> 8) & 0xff;
175c349dbc7Sjsg ptr[11] = frame->right_bar & 0xff;
176c349dbc7Sjsg ptr[12] = (frame->right_bar >> 8) & 0xff;
177c349dbc7Sjsg
178c349dbc7Sjsg hdmi_infoframe_set_checksum(buffer, length);
179c349dbc7Sjsg
180c349dbc7Sjsg return length;
181c349dbc7Sjsg }
182c349dbc7Sjsg EXPORT_SYMBOL(hdmi_avi_infoframe_pack_only);
183c349dbc7Sjsg
184c349dbc7Sjsg /**
185c349dbc7Sjsg * hdmi_avi_infoframe_pack() - check a HDMI AVI infoframe,
186c349dbc7Sjsg * and write it to binary buffer
187c349dbc7Sjsg * @frame: HDMI AVI infoframe
188c349dbc7Sjsg * @buffer: destination buffer
189c349dbc7Sjsg * @size: size of buffer
190c349dbc7Sjsg *
191c349dbc7Sjsg * Validates that the infoframe is consistent and updates derived fields
192c349dbc7Sjsg * (eg. length) based on other fields, after which it packs the information
193c349dbc7Sjsg * contained in the @frame structure into a binary representation that
194c349dbc7Sjsg * can be written into the corresponding controller registers. This function
195c349dbc7Sjsg * also computes the checksum as required by section 5.3.5 of the HDMI 1.4
196c349dbc7Sjsg * specification.
197c349dbc7Sjsg *
198c349dbc7Sjsg * Returns the number of bytes packed into the binary buffer or a negative
199c349dbc7Sjsg * error code on failure.
200c349dbc7Sjsg */
hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe * frame,void * buffer,size_t size)201c349dbc7Sjsg ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame,
202c349dbc7Sjsg void *buffer, size_t size)
203c349dbc7Sjsg {
204c349dbc7Sjsg int ret;
205c349dbc7Sjsg
206c349dbc7Sjsg ret = hdmi_avi_infoframe_check(frame);
207c349dbc7Sjsg if (ret)
208c349dbc7Sjsg return ret;
209c349dbc7Sjsg
210c349dbc7Sjsg return hdmi_avi_infoframe_pack_only(frame, buffer, size);
211c349dbc7Sjsg }
212c349dbc7Sjsg EXPORT_SYMBOL(hdmi_avi_infoframe_pack);
213c349dbc7Sjsg
214c349dbc7Sjsg /**
215c349dbc7Sjsg * hdmi_spd_infoframe_init() - initialize an HDMI SPD infoframe
216c349dbc7Sjsg * @frame: HDMI SPD infoframe
217c349dbc7Sjsg * @vendor: vendor string
218c349dbc7Sjsg * @product: product string
219c349dbc7Sjsg *
220c349dbc7Sjsg * Returns 0 on success or a negative error code on failure.
221c349dbc7Sjsg */
hdmi_spd_infoframe_init(struct hdmi_spd_infoframe * frame,const char * vendor,const char * product)222c349dbc7Sjsg int hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame,
223c349dbc7Sjsg const char *vendor, const char *product)
224c349dbc7Sjsg {
2255ca02815Sjsg size_t len;
2265ca02815Sjsg
227c349dbc7Sjsg memset(frame, 0, sizeof(*frame));
228c349dbc7Sjsg
229c349dbc7Sjsg frame->type = HDMI_INFOFRAME_TYPE_SPD;
230c349dbc7Sjsg frame->version = 1;
231c349dbc7Sjsg frame->length = HDMI_SPD_INFOFRAME_SIZE;
232c349dbc7Sjsg
2335ca02815Sjsg len = strlen(vendor);
2345ca02815Sjsg memcpy(frame->vendor, vendor, min(len, sizeof(frame->vendor)));
2355ca02815Sjsg len = strlen(product);
2365ca02815Sjsg memcpy(frame->product, product, min(len, sizeof(frame->product)));
237c349dbc7Sjsg
238c349dbc7Sjsg return 0;
239c349dbc7Sjsg }
240c349dbc7Sjsg EXPORT_SYMBOL(hdmi_spd_infoframe_init);
241c349dbc7Sjsg
hdmi_spd_infoframe_check_only(const struct hdmi_spd_infoframe * frame)242c349dbc7Sjsg static int hdmi_spd_infoframe_check_only(const struct hdmi_spd_infoframe *frame)
243c349dbc7Sjsg {
244c349dbc7Sjsg if (frame->type != HDMI_INFOFRAME_TYPE_SPD ||
245c349dbc7Sjsg frame->version != 1 ||
246c349dbc7Sjsg frame->length != HDMI_SPD_INFOFRAME_SIZE)
247c349dbc7Sjsg return -EINVAL;
248c349dbc7Sjsg
249c349dbc7Sjsg return 0;
250c349dbc7Sjsg }
251c349dbc7Sjsg
252c349dbc7Sjsg /**
253c349dbc7Sjsg * hdmi_spd_infoframe_check() - check a HDMI SPD infoframe
254c349dbc7Sjsg * @frame: HDMI SPD infoframe
255c349dbc7Sjsg *
256c349dbc7Sjsg * Validates that the infoframe is consistent and updates derived fields
257c349dbc7Sjsg * (eg. length) based on other fields.
258c349dbc7Sjsg *
259c349dbc7Sjsg * Returns 0 on success or a negative error code on failure.
260c349dbc7Sjsg */
hdmi_spd_infoframe_check(struct hdmi_spd_infoframe * frame)261c349dbc7Sjsg int hdmi_spd_infoframe_check(struct hdmi_spd_infoframe *frame)
262c349dbc7Sjsg {
263c349dbc7Sjsg return hdmi_spd_infoframe_check_only(frame);
264c349dbc7Sjsg }
265c349dbc7Sjsg EXPORT_SYMBOL(hdmi_spd_infoframe_check);
266c349dbc7Sjsg
267c349dbc7Sjsg /**
268c349dbc7Sjsg * hdmi_spd_infoframe_pack_only() - write HDMI SPD infoframe to binary buffer
269c349dbc7Sjsg * @frame: HDMI SPD infoframe
270c349dbc7Sjsg * @buffer: destination buffer
271c349dbc7Sjsg * @size: size of buffer
272c349dbc7Sjsg *
273c349dbc7Sjsg * Packs the information contained in the @frame structure into a binary
274c349dbc7Sjsg * representation that can be written into the corresponding controller
275c349dbc7Sjsg * registers. Also computes the checksum as required by section 5.3.5 of
276c349dbc7Sjsg * the HDMI 1.4 specification.
277c349dbc7Sjsg *
278c349dbc7Sjsg * Returns the number of bytes packed into the binary buffer or a negative
279c349dbc7Sjsg * error code on failure.
280c349dbc7Sjsg */
hdmi_spd_infoframe_pack_only(const struct hdmi_spd_infoframe * frame,void * buffer,size_t size)281c349dbc7Sjsg ssize_t hdmi_spd_infoframe_pack_only(const struct hdmi_spd_infoframe *frame,
282c349dbc7Sjsg void *buffer, size_t size)
283c349dbc7Sjsg {
284c349dbc7Sjsg u8 *ptr = buffer;
285c349dbc7Sjsg size_t length;
286c349dbc7Sjsg int ret;
287c349dbc7Sjsg
288c349dbc7Sjsg ret = hdmi_spd_infoframe_check_only(frame);
289c349dbc7Sjsg if (ret)
290c349dbc7Sjsg return ret;
291c349dbc7Sjsg
292c349dbc7Sjsg length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
293c349dbc7Sjsg
294c349dbc7Sjsg if (size < length)
295c349dbc7Sjsg return -ENOSPC;
296c349dbc7Sjsg
297c349dbc7Sjsg memset(buffer, 0, size);
298c349dbc7Sjsg
299c349dbc7Sjsg ptr[0] = frame->type;
300c349dbc7Sjsg ptr[1] = frame->version;
301c349dbc7Sjsg ptr[2] = frame->length;
302c349dbc7Sjsg ptr[3] = 0; /* checksum */
303c349dbc7Sjsg
304c349dbc7Sjsg /* start infoframe payload */
305c349dbc7Sjsg ptr += HDMI_INFOFRAME_HEADER_SIZE;
306c349dbc7Sjsg
307c349dbc7Sjsg memcpy(ptr, frame->vendor, sizeof(frame->vendor));
308c349dbc7Sjsg memcpy(ptr + 8, frame->product, sizeof(frame->product));
309c349dbc7Sjsg
310c349dbc7Sjsg ptr[24] = frame->sdi;
311c349dbc7Sjsg
312c349dbc7Sjsg hdmi_infoframe_set_checksum(buffer, length);
313c349dbc7Sjsg
314c349dbc7Sjsg return length;
315c349dbc7Sjsg }
316c349dbc7Sjsg EXPORT_SYMBOL(hdmi_spd_infoframe_pack_only);
317c349dbc7Sjsg
318c349dbc7Sjsg /**
319c349dbc7Sjsg * hdmi_spd_infoframe_pack() - check a HDMI SPD infoframe,
320c349dbc7Sjsg * and write it to binary buffer
321c349dbc7Sjsg * @frame: HDMI SPD infoframe
322c349dbc7Sjsg * @buffer: destination buffer
323c349dbc7Sjsg * @size: size of buffer
324c349dbc7Sjsg *
325c349dbc7Sjsg * Validates that the infoframe is consistent and updates derived fields
326c349dbc7Sjsg * (eg. length) based on other fields, after which it packs the information
327c349dbc7Sjsg * contained in the @frame structure into a binary representation that
328c349dbc7Sjsg * can be written into the corresponding controller registers. This function
329c349dbc7Sjsg * also computes the checksum as required by section 5.3.5 of the HDMI 1.4
330c349dbc7Sjsg * specification.
331c349dbc7Sjsg *
332c349dbc7Sjsg * Returns the number of bytes packed into the binary buffer or a negative
333c349dbc7Sjsg * error code on failure.
334c349dbc7Sjsg */
hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe * frame,void * buffer,size_t size)335c349dbc7Sjsg ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame,
336c349dbc7Sjsg void *buffer, size_t size)
337c349dbc7Sjsg {
338c349dbc7Sjsg int ret;
339c349dbc7Sjsg
340c349dbc7Sjsg ret = hdmi_spd_infoframe_check(frame);
341c349dbc7Sjsg if (ret)
342c349dbc7Sjsg return ret;
343c349dbc7Sjsg
344c349dbc7Sjsg return hdmi_spd_infoframe_pack_only(frame, buffer, size);
345c349dbc7Sjsg }
346c349dbc7Sjsg EXPORT_SYMBOL(hdmi_spd_infoframe_pack);
347c349dbc7Sjsg
348c349dbc7Sjsg /**
349c349dbc7Sjsg * hdmi_audio_infoframe_init() - initialize an HDMI audio infoframe
350c349dbc7Sjsg * @frame: HDMI audio infoframe
351c349dbc7Sjsg *
352c349dbc7Sjsg * Returns 0 on success or a negative error code on failure.
353c349dbc7Sjsg */
hdmi_audio_infoframe_init(struct hdmi_audio_infoframe * frame)354c349dbc7Sjsg int hdmi_audio_infoframe_init(struct hdmi_audio_infoframe *frame)
355c349dbc7Sjsg {
356c349dbc7Sjsg memset(frame, 0, sizeof(*frame));
357c349dbc7Sjsg
358c349dbc7Sjsg frame->type = HDMI_INFOFRAME_TYPE_AUDIO;
359c349dbc7Sjsg frame->version = 1;
360c349dbc7Sjsg frame->length = HDMI_AUDIO_INFOFRAME_SIZE;
361c349dbc7Sjsg
362c349dbc7Sjsg return 0;
363c349dbc7Sjsg }
364c349dbc7Sjsg EXPORT_SYMBOL(hdmi_audio_infoframe_init);
365c349dbc7Sjsg
hdmi_audio_infoframe_check_only(const struct hdmi_audio_infoframe * frame)366c349dbc7Sjsg static int hdmi_audio_infoframe_check_only(const struct hdmi_audio_infoframe *frame)
367c349dbc7Sjsg {
368c349dbc7Sjsg if (frame->type != HDMI_INFOFRAME_TYPE_AUDIO ||
369c349dbc7Sjsg frame->version != 1 ||
370c349dbc7Sjsg frame->length != HDMI_AUDIO_INFOFRAME_SIZE)
371c349dbc7Sjsg return -EINVAL;
372c349dbc7Sjsg
373c349dbc7Sjsg return 0;
374c349dbc7Sjsg }
375c349dbc7Sjsg
376c349dbc7Sjsg /**
377c349dbc7Sjsg * hdmi_audio_infoframe_check() - check a HDMI audio infoframe
378c349dbc7Sjsg * @frame: HDMI audio infoframe
379c349dbc7Sjsg *
380c349dbc7Sjsg * Validates that the infoframe is consistent and updates derived fields
381c349dbc7Sjsg * (eg. length) based on other fields.
382c349dbc7Sjsg *
383c349dbc7Sjsg * Returns 0 on success or a negative error code on failure.
384c349dbc7Sjsg */
hdmi_audio_infoframe_check(const struct hdmi_audio_infoframe * frame)385*1bb76ff1Sjsg int hdmi_audio_infoframe_check(const struct hdmi_audio_infoframe *frame)
386c349dbc7Sjsg {
387c349dbc7Sjsg return hdmi_audio_infoframe_check_only(frame);
388c349dbc7Sjsg }
389c349dbc7Sjsg EXPORT_SYMBOL(hdmi_audio_infoframe_check);
390c349dbc7Sjsg
391*1bb76ff1Sjsg static void
hdmi_audio_infoframe_pack_payload(const struct hdmi_audio_infoframe * frame,u8 * buffer)392*1bb76ff1Sjsg hdmi_audio_infoframe_pack_payload(const struct hdmi_audio_infoframe *frame,
393*1bb76ff1Sjsg u8 *buffer)
394*1bb76ff1Sjsg {
395*1bb76ff1Sjsg u8 channels;
396*1bb76ff1Sjsg
397*1bb76ff1Sjsg if (frame->channels >= 2)
398*1bb76ff1Sjsg channels = frame->channels - 1;
399*1bb76ff1Sjsg else
400*1bb76ff1Sjsg channels = 0;
401*1bb76ff1Sjsg
402*1bb76ff1Sjsg buffer[0] = ((frame->coding_type & 0xf) << 4) | (channels & 0x7);
403*1bb76ff1Sjsg buffer[1] = ((frame->sample_frequency & 0x7) << 2) |
404*1bb76ff1Sjsg (frame->sample_size & 0x3);
405*1bb76ff1Sjsg buffer[2] = frame->coding_type_ext & 0x1f;
406*1bb76ff1Sjsg buffer[3] = frame->channel_allocation;
407*1bb76ff1Sjsg buffer[4] = (frame->level_shift_value & 0xf) << 3;
408*1bb76ff1Sjsg
409*1bb76ff1Sjsg if (frame->downmix_inhibit)
410*1bb76ff1Sjsg buffer[4] |= BIT(7);
411*1bb76ff1Sjsg }
412*1bb76ff1Sjsg
413c349dbc7Sjsg /**
414c349dbc7Sjsg * hdmi_audio_infoframe_pack_only() - write HDMI audio infoframe to binary buffer
415c349dbc7Sjsg * @frame: HDMI audio infoframe
416c349dbc7Sjsg * @buffer: destination buffer
417c349dbc7Sjsg * @size: size of buffer
418c349dbc7Sjsg *
419c349dbc7Sjsg * Packs the information contained in the @frame structure into a binary
420c349dbc7Sjsg * representation that can be written into the corresponding controller
421c349dbc7Sjsg * registers. Also computes the checksum as required by section 5.3.5 of
422c349dbc7Sjsg * the HDMI 1.4 specification.
423c349dbc7Sjsg *
424c349dbc7Sjsg * Returns the number of bytes packed into the binary buffer or a negative
425c349dbc7Sjsg * error code on failure.
426c349dbc7Sjsg */
hdmi_audio_infoframe_pack_only(const struct hdmi_audio_infoframe * frame,void * buffer,size_t size)427c349dbc7Sjsg ssize_t hdmi_audio_infoframe_pack_only(const struct hdmi_audio_infoframe *frame,
428c349dbc7Sjsg void *buffer, size_t size)
429c349dbc7Sjsg {
430c349dbc7Sjsg u8 *ptr = buffer;
431c349dbc7Sjsg size_t length;
432c349dbc7Sjsg int ret;
433c349dbc7Sjsg
434c349dbc7Sjsg ret = hdmi_audio_infoframe_check_only(frame);
435c349dbc7Sjsg if (ret)
436c349dbc7Sjsg return ret;
437c349dbc7Sjsg
438c349dbc7Sjsg length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
439c349dbc7Sjsg
440c349dbc7Sjsg if (size < length)
441c349dbc7Sjsg return -ENOSPC;
442c349dbc7Sjsg
443c349dbc7Sjsg memset(buffer, 0, size);
444c349dbc7Sjsg
445c349dbc7Sjsg ptr[0] = frame->type;
446c349dbc7Sjsg ptr[1] = frame->version;
447c349dbc7Sjsg ptr[2] = frame->length;
448c349dbc7Sjsg ptr[3] = 0; /* checksum */
449c349dbc7Sjsg
450*1bb76ff1Sjsg hdmi_audio_infoframe_pack_payload(frame,
451*1bb76ff1Sjsg ptr + HDMI_INFOFRAME_HEADER_SIZE);
452c349dbc7Sjsg
453c349dbc7Sjsg hdmi_infoframe_set_checksum(buffer, length);
454c349dbc7Sjsg
455c349dbc7Sjsg return length;
456c349dbc7Sjsg }
457c349dbc7Sjsg EXPORT_SYMBOL(hdmi_audio_infoframe_pack_only);
458c349dbc7Sjsg
459c349dbc7Sjsg /**
460c349dbc7Sjsg * hdmi_audio_infoframe_pack() - check a HDMI Audio infoframe,
461c349dbc7Sjsg * and write it to binary buffer
462c349dbc7Sjsg * @frame: HDMI Audio infoframe
463c349dbc7Sjsg * @buffer: destination buffer
464c349dbc7Sjsg * @size: size of buffer
465c349dbc7Sjsg *
466c349dbc7Sjsg * Validates that the infoframe is consistent and updates derived fields
467c349dbc7Sjsg * (eg. length) based on other fields, after which it packs the information
468c349dbc7Sjsg * contained in the @frame structure into a binary representation that
469c349dbc7Sjsg * can be written into the corresponding controller registers. This function
470c349dbc7Sjsg * also computes the checksum as required by section 5.3.5 of the HDMI 1.4
471c349dbc7Sjsg * specification.
472c349dbc7Sjsg *
473c349dbc7Sjsg * Returns the number of bytes packed into the binary buffer or a negative
474c349dbc7Sjsg * error code on failure.
475c349dbc7Sjsg */
hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe * frame,void * buffer,size_t size)476c349dbc7Sjsg ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
477c349dbc7Sjsg void *buffer, size_t size)
478c349dbc7Sjsg {
479c349dbc7Sjsg int ret;
480c349dbc7Sjsg
481c349dbc7Sjsg ret = hdmi_audio_infoframe_check(frame);
482c349dbc7Sjsg if (ret)
483c349dbc7Sjsg return ret;
484c349dbc7Sjsg
485c349dbc7Sjsg return hdmi_audio_infoframe_pack_only(frame, buffer, size);
486c349dbc7Sjsg }
487c349dbc7Sjsg EXPORT_SYMBOL(hdmi_audio_infoframe_pack);
488c349dbc7Sjsg
489c349dbc7Sjsg /**
490*1bb76ff1Sjsg * hdmi_audio_infoframe_pack_for_dp - Pack a HDMI Audio infoframe for DisplayPort
491*1bb76ff1Sjsg *
492*1bb76ff1Sjsg * @frame: HDMI Audio infoframe
493*1bb76ff1Sjsg * @sdp: Secondary data packet for DisplayPort.
494*1bb76ff1Sjsg * @dp_version: DisplayPort version to be encoded in the header
495*1bb76ff1Sjsg *
496*1bb76ff1Sjsg * Packs a HDMI Audio Infoframe to be sent over DisplayPort. This function
497*1bb76ff1Sjsg * fills the secondary data packet to be used for DisplayPort.
498*1bb76ff1Sjsg *
499*1bb76ff1Sjsg * Return: Number of total written bytes or a negative errno on failure.
500*1bb76ff1Sjsg */
501*1bb76ff1Sjsg ssize_t
hdmi_audio_infoframe_pack_for_dp(const struct hdmi_audio_infoframe * frame,struct dp_sdp * sdp,u8 dp_version)502*1bb76ff1Sjsg hdmi_audio_infoframe_pack_for_dp(const struct hdmi_audio_infoframe *frame,
503*1bb76ff1Sjsg struct dp_sdp *sdp, u8 dp_version)
504*1bb76ff1Sjsg {
505*1bb76ff1Sjsg int ret;
506*1bb76ff1Sjsg
507*1bb76ff1Sjsg ret = hdmi_audio_infoframe_check(frame);
508*1bb76ff1Sjsg if (ret)
509*1bb76ff1Sjsg return ret;
510*1bb76ff1Sjsg
511*1bb76ff1Sjsg memset(sdp->db, 0, sizeof(sdp->db));
512*1bb76ff1Sjsg
513*1bb76ff1Sjsg /* Secondary-data packet header */
514*1bb76ff1Sjsg sdp->sdp_header.HB0 = 0;
515*1bb76ff1Sjsg sdp->sdp_header.HB1 = frame->type;
516*1bb76ff1Sjsg sdp->sdp_header.HB2 = DP_SDP_AUDIO_INFOFRAME_HB2;
517*1bb76ff1Sjsg sdp->sdp_header.HB3 = (dp_version & 0x3f) << 2;
518*1bb76ff1Sjsg
519*1bb76ff1Sjsg hdmi_audio_infoframe_pack_payload(frame, sdp->db);
520*1bb76ff1Sjsg
521*1bb76ff1Sjsg /* Return size = frame length + four HB for sdp_header */
522*1bb76ff1Sjsg return frame->length + 4;
523*1bb76ff1Sjsg }
524*1bb76ff1Sjsg EXPORT_SYMBOL(hdmi_audio_infoframe_pack_for_dp);
525*1bb76ff1Sjsg
526*1bb76ff1Sjsg /**
527c349dbc7Sjsg * hdmi_vendor_infoframe_init() - initialize an HDMI vendor infoframe
528c349dbc7Sjsg * @frame: HDMI vendor infoframe
529c349dbc7Sjsg *
530c349dbc7Sjsg * Returns 0 on success or a negative error code on failure.
531c349dbc7Sjsg */
hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe * frame)532c349dbc7Sjsg int hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame)
533c349dbc7Sjsg {
534c349dbc7Sjsg memset(frame, 0, sizeof(*frame));
535c349dbc7Sjsg
536c349dbc7Sjsg frame->type = HDMI_INFOFRAME_TYPE_VENDOR;
537c349dbc7Sjsg frame->version = 1;
538c349dbc7Sjsg
539c349dbc7Sjsg frame->oui = HDMI_IEEE_OUI;
540c349dbc7Sjsg
541c349dbc7Sjsg /*
542c349dbc7Sjsg * 0 is a valid value for s3d_struct, so we use a special "not set"
543c349dbc7Sjsg * value
544c349dbc7Sjsg */
545c349dbc7Sjsg frame->s3d_struct = HDMI_3D_STRUCTURE_INVALID;
546ad8b1aafSjsg frame->length = HDMI_VENDOR_INFOFRAME_SIZE;
547c349dbc7Sjsg
548c349dbc7Sjsg return 0;
549c349dbc7Sjsg }
550c349dbc7Sjsg EXPORT_SYMBOL(hdmi_vendor_infoframe_init);
551c349dbc7Sjsg
hdmi_vendor_infoframe_length(const struct hdmi_vendor_infoframe * frame)552c349dbc7Sjsg static int hdmi_vendor_infoframe_length(const struct hdmi_vendor_infoframe *frame)
553c349dbc7Sjsg {
554c349dbc7Sjsg /* for side by side (half) we also need to provide 3D_Ext_Data */
555c349dbc7Sjsg if (frame->s3d_struct >= HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF)
556c349dbc7Sjsg return 6;
557c349dbc7Sjsg else if (frame->vic != 0 || frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID)
558c349dbc7Sjsg return 5;
559c349dbc7Sjsg else
560c349dbc7Sjsg return 4;
561c349dbc7Sjsg }
562c349dbc7Sjsg
hdmi_vendor_infoframe_check_only(const struct hdmi_vendor_infoframe * frame)563c349dbc7Sjsg static int hdmi_vendor_infoframe_check_only(const struct hdmi_vendor_infoframe *frame)
564c349dbc7Sjsg {
565c349dbc7Sjsg if (frame->type != HDMI_INFOFRAME_TYPE_VENDOR ||
566c349dbc7Sjsg frame->version != 1 ||
567c349dbc7Sjsg frame->oui != HDMI_IEEE_OUI)
568c349dbc7Sjsg return -EINVAL;
569c349dbc7Sjsg
570c349dbc7Sjsg /* only one of those can be supplied */
571c349dbc7Sjsg if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID)
572c349dbc7Sjsg return -EINVAL;
573c349dbc7Sjsg
574c349dbc7Sjsg if (frame->length != hdmi_vendor_infoframe_length(frame))
575c349dbc7Sjsg return -EINVAL;
576c349dbc7Sjsg
577c349dbc7Sjsg return 0;
578c349dbc7Sjsg }
579c349dbc7Sjsg
580c349dbc7Sjsg /**
581c349dbc7Sjsg * hdmi_vendor_infoframe_check() - check a HDMI vendor infoframe
582c349dbc7Sjsg * @frame: HDMI infoframe
583c349dbc7Sjsg *
584c349dbc7Sjsg * Validates that the infoframe is consistent and updates derived fields
585c349dbc7Sjsg * (eg. length) based on other fields.
586c349dbc7Sjsg *
587c349dbc7Sjsg * Returns 0 on success or a negative error code on failure.
588c349dbc7Sjsg */
hdmi_vendor_infoframe_check(struct hdmi_vendor_infoframe * frame)589c349dbc7Sjsg int hdmi_vendor_infoframe_check(struct hdmi_vendor_infoframe *frame)
590c349dbc7Sjsg {
591c349dbc7Sjsg frame->length = hdmi_vendor_infoframe_length(frame);
592c349dbc7Sjsg
593c349dbc7Sjsg return hdmi_vendor_infoframe_check_only(frame);
594c349dbc7Sjsg }
595c349dbc7Sjsg EXPORT_SYMBOL(hdmi_vendor_infoframe_check);
596c349dbc7Sjsg
597c349dbc7Sjsg /**
598c349dbc7Sjsg * hdmi_vendor_infoframe_pack_only() - write a HDMI vendor infoframe to binary buffer
599c349dbc7Sjsg * @frame: HDMI infoframe
600c349dbc7Sjsg * @buffer: destination buffer
601c349dbc7Sjsg * @size: size of buffer
602c349dbc7Sjsg *
603c349dbc7Sjsg * Packs the information contained in the @frame structure into a binary
604c349dbc7Sjsg * representation that can be written into the corresponding controller
605c349dbc7Sjsg * registers. Also computes the checksum as required by section 5.3.5 of
606c349dbc7Sjsg * the HDMI 1.4 specification.
607c349dbc7Sjsg *
608c349dbc7Sjsg * Returns the number of bytes packed into the binary buffer or a negative
609c349dbc7Sjsg * error code on failure.
610c349dbc7Sjsg */
hdmi_vendor_infoframe_pack_only(const struct hdmi_vendor_infoframe * frame,void * buffer,size_t size)611c349dbc7Sjsg ssize_t hdmi_vendor_infoframe_pack_only(const struct hdmi_vendor_infoframe *frame,
612c349dbc7Sjsg void *buffer, size_t size)
613c349dbc7Sjsg {
614c349dbc7Sjsg u8 *ptr = buffer;
615c349dbc7Sjsg size_t length;
616c349dbc7Sjsg int ret;
617c349dbc7Sjsg
618c349dbc7Sjsg ret = hdmi_vendor_infoframe_check_only(frame);
619c349dbc7Sjsg if (ret)
620c349dbc7Sjsg return ret;
621c349dbc7Sjsg
622c349dbc7Sjsg length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
623c349dbc7Sjsg
624c349dbc7Sjsg if (size < length)
625c349dbc7Sjsg return -ENOSPC;
626c349dbc7Sjsg
627c349dbc7Sjsg memset(buffer, 0, size);
628c349dbc7Sjsg
629c349dbc7Sjsg ptr[0] = frame->type;
630c349dbc7Sjsg ptr[1] = frame->version;
631c349dbc7Sjsg ptr[2] = frame->length;
632c349dbc7Sjsg ptr[3] = 0; /* checksum */
633c349dbc7Sjsg
634c349dbc7Sjsg /* HDMI OUI */
635c349dbc7Sjsg ptr[4] = 0x03;
636c349dbc7Sjsg ptr[5] = 0x0c;
637c349dbc7Sjsg ptr[6] = 0x00;
638c349dbc7Sjsg
639c349dbc7Sjsg if (frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID) {
640c349dbc7Sjsg ptr[7] = 0x2 << 5; /* video format */
641c349dbc7Sjsg ptr[8] = (frame->s3d_struct & 0xf) << 4;
642c349dbc7Sjsg if (frame->s3d_struct >= HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF)
643c349dbc7Sjsg ptr[9] = (frame->s3d_ext_data & 0xf) << 4;
644c349dbc7Sjsg } else if (frame->vic) {
645c349dbc7Sjsg ptr[7] = 0x1 << 5; /* video format */
646c349dbc7Sjsg ptr[8] = frame->vic;
647c349dbc7Sjsg } else {
648c349dbc7Sjsg ptr[7] = 0x0 << 5; /* video format */
649c349dbc7Sjsg }
650c349dbc7Sjsg
651c349dbc7Sjsg hdmi_infoframe_set_checksum(buffer, length);
652c349dbc7Sjsg
653c349dbc7Sjsg return length;
654c349dbc7Sjsg }
655c349dbc7Sjsg EXPORT_SYMBOL(hdmi_vendor_infoframe_pack_only);
656c349dbc7Sjsg
657c349dbc7Sjsg /**
658c349dbc7Sjsg * hdmi_vendor_infoframe_pack() - check a HDMI Vendor infoframe,
659c349dbc7Sjsg * and write it to binary buffer
660c349dbc7Sjsg * @frame: HDMI Vendor infoframe
661c349dbc7Sjsg * @buffer: destination buffer
662c349dbc7Sjsg * @size: size of buffer
663c349dbc7Sjsg *
664c349dbc7Sjsg * Validates that the infoframe is consistent and updates derived fields
665c349dbc7Sjsg * (eg. length) based on other fields, after which it packs the information
666c349dbc7Sjsg * contained in the @frame structure into a binary representation that
667c349dbc7Sjsg * can be written into the corresponding controller registers. This function
668c349dbc7Sjsg * also computes the checksum as required by section 5.3.5 of the HDMI 1.4
669c349dbc7Sjsg * specification.
670c349dbc7Sjsg *
671c349dbc7Sjsg * Returns the number of bytes packed into the binary buffer or a negative
672c349dbc7Sjsg * error code on failure.
673c349dbc7Sjsg */
hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe * frame,void * buffer,size_t size)674c349dbc7Sjsg ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
675c349dbc7Sjsg void *buffer, size_t size)
676c349dbc7Sjsg {
677c349dbc7Sjsg int ret;
678c349dbc7Sjsg
679c349dbc7Sjsg ret = hdmi_vendor_infoframe_check(frame);
680c349dbc7Sjsg if (ret)
681c349dbc7Sjsg return ret;
682c349dbc7Sjsg
683c349dbc7Sjsg return hdmi_vendor_infoframe_pack_only(frame, buffer, size);
684c349dbc7Sjsg }
685c349dbc7Sjsg EXPORT_SYMBOL(hdmi_vendor_infoframe_pack);
686c349dbc7Sjsg
687c349dbc7Sjsg static int
hdmi_vendor_any_infoframe_check_only(const union hdmi_vendor_any_infoframe * frame)688c349dbc7Sjsg hdmi_vendor_any_infoframe_check_only(const union hdmi_vendor_any_infoframe *frame)
689c349dbc7Sjsg {
690c349dbc7Sjsg if (frame->any.type != HDMI_INFOFRAME_TYPE_VENDOR ||
691c349dbc7Sjsg frame->any.version != 1)
692c349dbc7Sjsg return -EINVAL;
693c349dbc7Sjsg
694c349dbc7Sjsg return 0;
695c349dbc7Sjsg }
696c349dbc7Sjsg
697c349dbc7Sjsg /**
698c349dbc7Sjsg * hdmi_drm_infoframe_init() - initialize an HDMI Dynaminc Range and
699c349dbc7Sjsg * mastering infoframe
700c349dbc7Sjsg * @frame: HDMI DRM infoframe
701c349dbc7Sjsg *
702c349dbc7Sjsg * Returns 0 on success or a negative error code on failure.
703c349dbc7Sjsg */
hdmi_drm_infoframe_init(struct hdmi_drm_infoframe * frame)704c349dbc7Sjsg int hdmi_drm_infoframe_init(struct hdmi_drm_infoframe *frame)
705c349dbc7Sjsg {
706c349dbc7Sjsg memset(frame, 0, sizeof(*frame));
707c349dbc7Sjsg
708c349dbc7Sjsg frame->type = HDMI_INFOFRAME_TYPE_DRM;
709c349dbc7Sjsg frame->version = 1;
710c349dbc7Sjsg frame->length = HDMI_DRM_INFOFRAME_SIZE;
711c349dbc7Sjsg
712c349dbc7Sjsg return 0;
713c349dbc7Sjsg }
714c349dbc7Sjsg EXPORT_SYMBOL(hdmi_drm_infoframe_init);
715c349dbc7Sjsg
hdmi_drm_infoframe_check_only(const struct hdmi_drm_infoframe * frame)716c349dbc7Sjsg static int hdmi_drm_infoframe_check_only(const struct hdmi_drm_infoframe *frame)
717c349dbc7Sjsg {
718c349dbc7Sjsg if (frame->type != HDMI_INFOFRAME_TYPE_DRM ||
719c349dbc7Sjsg frame->version != 1)
720c349dbc7Sjsg return -EINVAL;
721c349dbc7Sjsg
722c349dbc7Sjsg if (frame->length != HDMI_DRM_INFOFRAME_SIZE)
723c349dbc7Sjsg return -EINVAL;
724c349dbc7Sjsg
725c349dbc7Sjsg return 0;
726c349dbc7Sjsg }
727c349dbc7Sjsg
728c349dbc7Sjsg /**
729c349dbc7Sjsg * hdmi_drm_infoframe_check() - check a HDMI DRM infoframe
730c349dbc7Sjsg * @frame: HDMI DRM infoframe
731c349dbc7Sjsg *
732c349dbc7Sjsg * Validates that the infoframe is consistent.
733c349dbc7Sjsg * Returns 0 on success or a negative error code on failure.
734c349dbc7Sjsg */
hdmi_drm_infoframe_check(struct hdmi_drm_infoframe * frame)735c349dbc7Sjsg int hdmi_drm_infoframe_check(struct hdmi_drm_infoframe *frame)
736c349dbc7Sjsg {
737c349dbc7Sjsg return hdmi_drm_infoframe_check_only(frame);
738c349dbc7Sjsg }
739c349dbc7Sjsg EXPORT_SYMBOL(hdmi_drm_infoframe_check);
740c349dbc7Sjsg
741c349dbc7Sjsg /**
742c349dbc7Sjsg * hdmi_drm_infoframe_pack_only() - write HDMI DRM infoframe to binary buffer
743c349dbc7Sjsg * @frame: HDMI DRM infoframe
744c349dbc7Sjsg * @buffer: destination buffer
745c349dbc7Sjsg * @size: size of buffer
746c349dbc7Sjsg *
747c349dbc7Sjsg * Packs the information contained in the @frame structure into a binary
748c349dbc7Sjsg * representation that can be written into the corresponding controller
749c349dbc7Sjsg * registers. Also computes the checksum as required by section 5.3.5 of
750c349dbc7Sjsg * the HDMI 1.4 specification.
751c349dbc7Sjsg *
752c349dbc7Sjsg * Returns the number of bytes packed into the binary buffer or a negative
753c349dbc7Sjsg * error code on failure.
754c349dbc7Sjsg */
hdmi_drm_infoframe_pack_only(const struct hdmi_drm_infoframe * frame,void * buffer,size_t size)755c349dbc7Sjsg ssize_t hdmi_drm_infoframe_pack_only(const struct hdmi_drm_infoframe *frame,
756c349dbc7Sjsg void *buffer, size_t size)
757c349dbc7Sjsg {
758c349dbc7Sjsg u8 *ptr = buffer;
759c349dbc7Sjsg size_t length;
760c349dbc7Sjsg int i;
761c349dbc7Sjsg
762c349dbc7Sjsg length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
763c349dbc7Sjsg
764c349dbc7Sjsg if (size < length)
765c349dbc7Sjsg return -ENOSPC;
766c349dbc7Sjsg
767c349dbc7Sjsg memset(buffer, 0, size);
768c349dbc7Sjsg
769c349dbc7Sjsg ptr[0] = frame->type;
770c349dbc7Sjsg ptr[1] = frame->version;
771c349dbc7Sjsg ptr[2] = frame->length;
772c349dbc7Sjsg ptr[3] = 0; /* checksum */
773c349dbc7Sjsg
774c349dbc7Sjsg /* start infoframe payload */
775c349dbc7Sjsg ptr += HDMI_INFOFRAME_HEADER_SIZE;
776c349dbc7Sjsg
777c349dbc7Sjsg *ptr++ = frame->eotf;
778c349dbc7Sjsg *ptr++ = frame->metadata_type;
779c349dbc7Sjsg
780c349dbc7Sjsg for (i = 0; i < 3; i++) {
781c349dbc7Sjsg *ptr++ = frame->display_primaries[i].x;
782c349dbc7Sjsg *ptr++ = frame->display_primaries[i].x >> 8;
783c349dbc7Sjsg *ptr++ = frame->display_primaries[i].y;
784c349dbc7Sjsg *ptr++ = frame->display_primaries[i].y >> 8;
785c349dbc7Sjsg }
786c349dbc7Sjsg
787c349dbc7Sjsg *ptr++ = frame->white_point.x;
788c349dbc7Sjsg *ptr++ = frame->white_point.x >> 8;
789c349dbc7Sjsg
790c349dbc7Sjsg *ptr++ = frame->white_point.y;
791c349dbc7Sjsg *ptr++ = frame->white_point.y >> 8;
792c349dbc7Sjsg
793c349dbc7Sjsg *ptr++ = frame->max_display_mastering_luminance;
794c349dbc7Sjsg *ptr++ = frame->max_display_mastering_luminance >> 8;
795c349dbc7Sjsg
796c349dbc7Sjsg *ptr++ = frame->min_display_mastering_luminance;
797c349dbc7Sjsg *ptr++ = frame->min_display_mastering_luminance >> 8;
798c349dbc7Sjsg
799c349dbc7Sjsg *ptr++ = frame->max_cll;
800c349dbc7Sjsg *ptr++ = frame->max_cll >> 8;
801c349dbc7Sjsg
802c349dbc7Sjsg *ptr++ = frame->max_fall;
803c349dbc7Sjsg *ptr++ = frame->max_fall >> 8;
804c349dbc7Sjsg
805c349dbc7Sjsg hdmi_infoframe_set_checksum(buffer, length);
806c349dbc7Sjsg
807c349dbc7Sjsg return length;
808c349dbc7Sjsg }
809c349dbc7Sjsg EXPORT_SYMBOL(hdmi_drm_infoframe_pack_only);
810c349dbc7Sjsg
811c349dbc7Sjsg /**
812c349dbc7Sjsg * hdmi_drm_infoframe_pack() - check a HDMI DRM infoframe,
813c349dbc7Sjsg * and write it to binary buffer
814c349dbc7Sjsg * @frame: HDMI DRM infoframe
815c349dbc7Sjsg * @buffer: destination buffer
816c349dbc7Sjsg * @size: size of buffer
817c349dbc7Sjsg *
818c349dbc7Sjsg * Validates that the infoframe is consistent and updates derived fields
819c349dbc7Sjsg * (eg. length) based on other fields, after which it packs the information
820c349dbc7Sjsg * contained in the @frame structure into a binary representation that
821c349dbc7Sjsg * can be written into the corresponding controller registers. This function
822c349dbc7Sjsg * also computes the checksum as required by section 5.3.5 of the HDMI 1.4
823c349dbc7Sjsg * specification.
824c349dbc7Sjsg *
825c349dbc7Sjsg * Returns the number of bytes packed into the binary buffer or a negative
826c349dbc7Sjsg * error code on failure.
827c349dbc7Sjsg */
hdmi_drm_infoframe_pack(struct hdmi_drm_infoframe * frame,void * buffer,size_t size)828c349dbc7Sjsg ssize_t hdmi_drm_infoframe_pack(struct hdmi_drm_infoframe *frame,
829c349dbc7Sjsg void *buffer, size_t size)
830c349dbc7Sjsg {
831c349dbc7Sjsg int ret;
832c349dbc7Sjsg
833c349dbc7Sjsg ret = hdmi_drm_infoframe_check(frame);
834c349dbc7Sjsg if (ret)
835c349dbc7Sjsg return ret;
836c349dbc7Sjsg
837c349dbc7Sjsg return hdmi_drm_infoframe_pack_only(frame, buffer, size);
838c349dbc7Sjsg }
839c349dbc7Sjsg EXPORT_SYMBOL(hdmi_drm_infoframe_pack);
840c349dbc7Sjsg
841c349dbc7Sjsg /*
842c349dbc7Sjsg * hdmi_vendor_any_infoframe_check() - check a vendor infoframe
843c349dbc7Sjsg */
844c349dbc7Sjsg static int
hdmi_vendor_any_infoframe_check(union hdmi_vendor_any_infoframe * frame)845c349dbc7Sjsg hdmi_vendor_any_infoframe_check(union hdmi_vendor_any_infoframe *frame)
846c349dbc7Sjsg {
847c349dbc7Sjsg int ret;
848c349dbc7Sjsg
849c349dbc7Sjsg ret = hdmi_vendor_any_infoframe_check_only(frame);
850c349dbc7Sjsg if (ret)
851c349dbc7Sjsg return ret;
852c349dbc7Sjsg
853c349dbc7Sjsg /* we only know about HDMI vendor infoframes */
854c349dbc7Sjsg if (frame->any.oui != HDMI_IEEE_OUI)
855c349dbc7Sjsg return -EINVAL;
856c349dbc7Sjsg
857c349dbc7Sjsg return hdmi_vendor_infoframe_check(&frame->hdmi);
858c349dbc7Sjsg }
859c349dbc7Sjsg
860c349dbc7Sjsg /*
861c349dbc7Sjsg * hdmi_vendor_any_infoframe_pack_only() - write a vendor infoframe to binary buffer
862c349dbc7Sjsg */
863c349dbc7Sjsg static ssize_t
hdmi_vendor_any_infoframe_pack_only(const union hdmi_vendor_any_infoframe * frame,void * buffer,size_t size)864c349dbc7Sjsg hdmi_vendor_any_infoframe_pack_only(const union hdmi_vendor_any_infoframe *frame,
865c349dbc7Sjsg void *buffer, size_t size)
866c349dbc7Sjsg {
867c349dbc7Sjsg int ret;
868c349dbc7Sjsg
869c349dbc7Sjsg ret = hdmi_vendor_any_infoframe_check_only(frame);
870c349dbc7Sjsg if (ret)
871c349dbc7Sjsg return ret;
872c349dbc7Sjsg
873c349dbc7Sjsg /* we only know about HDMI vendor infoframes */
874c349dbc7Sjsg if (frame->any.oui != HDMI_IEEE_OUI)
875c349dbc7Sjsg return -EINVAL;
876c349dbc7Sjsg
877c349dbc7Sjsg return hdmi_vendor_infoframe_pack_only(&frame->hdmi, buffer, size);
878c349dbc7Sjsg }
879c349dbc7Sjsg
880c349dbc7Sjsg /*
881c349dbc7Sjsg * hdmi_vendor_any_infoframe_pack() - check a vendor infoframe,
882c349dbc7Sjsg * and write it to binary buffer
883c349dbc7Sjsg */
884c349dbc7Sjsg static ssize_t
hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe * frame,void * buffer,size_t size)885c349dbc7Sjsg hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
886c349dbc7Sjsg void *buffer, size_t size)
887c349dbc7Sjsg {
888c349dbc7Sjsg int ret;
889c349dbc7Sjsg
890c349dbc7Sjsg ret = hdmi_vendor_any_infoframe_check(frame);
891c349dbc7Sjsg if (ret)
892c349dbc7Sjsg return ret;
893c349dbc7Sjsg
894c349dbc7Sjsg return hdmi_vendor_any_infoframe_pack_only(frame, buffer, size);
895c349dbc7Sjsg }
896c349dbc7Sjsg
897c349dbc7Sjsg /**
898c349dbc7Sjsg * hdmi_infoframe_check() - check a HDMI infoframe
899c349dbc7Sjsg * @frame: HDMI infoframe
900c349dbc7Sjsg *
901c349dbc7Sjsg * Validates that the infoframe is consistent and updates derived fields
902c349dbc7Sjsg * (eg. length) based on other fields.
903c349dbc7Sjsg *
904c349dbc7Sjsg * Returns 0 on success or a negative error code on failure.
905c349dbc7Sjsg */
906c349dbc7Sjsg int
hdmi_infoframe_check(union hdmi_infoframe * frame)907c349dbc7Sjsg hdmi_infoframe_check(union hdmi_infoframe *frame)
908c349dbc7Sjsg {
909c349dbc7Sjsg switch (frame->any.type) {
910c349dbc7Sjsg case HDMI_INFOFRAME_TYPE_AVI:
911c349dbc7Sjsg return hdmi_avi_infoframe_check(&frame->avi);
912c349dbc7Sjsg case HDMI_INFOFRAME_TYPE_SPD:
913c349dbc7Sjsg return hdmi_spd_infoframe_check(&frame->spd);
914c349dbc7Sjsg case HDMI_INFOFRAME_TYPE_AUDIO:
915c349dbc7Sjsg return hdmi_audio_infoframe_check(&frame->audio);
916c349dbc7Sjsg case HDMI_INFOFRAME_TYPE_VENDOR:
917c349dbc7Sjsg return hdmi_vendor_any_infoframe_check(&frame->vendor);
918c349dbc7Sjsg default:
919c349dbc7Sjsg WARN(1, "Bad infoframe type %d\n", frame->any.type);
920c349dbc7Sjsg return -EINVAL;
921c349dbc7Sjsg }
922c349dbc7Sjsg }
923c349dbc7Sjsg EXPORT_SYMBOL(hdmi_infoframe_check);
924c349dbc7Sjsg
925c349dbc7Sjsg /**
926c349dbc7Sjsg * hdmi_infoframe_pack_only() - write a HDMI infoframe to binary buffer
927c349dbc7Sjsg * @frame: HDMI infoframe
928c349dbc7Sjsg * @buffer: destination buffer
929c349dbc7Sjsg * @size: size of buffer
930c349dbc7Sjsg *
931c349dbc7Sjsg * Packs the information contained in the @frame structure into a binary
932c349dbc7Sjsg * representation that can be written into the corresponding controller
933c349dbc7Sjsg * registers. Also computes the checksum as required by section 5.3.5 of
934c349dbc7Sjsg * the HDMI 1.4 specification.
935c349dbc7Sjsg *
936c349dbc7Sjsg * Returns the number of bytes packed into the binary buffer or a negative
937c349dbc7Sjsg * error code on failure.
938c349dbc7Sjsg */
939c349dbc7Sjsg ssize_t
hdmi_infoframe_pack_only(const union hdmi_infoframe * frame,void * buffer,size_t size)940c349dbc7Sjsg hdmi_infoframe_pack_only(const union hdmi_infoframe *frame, void *buffer, size_t size)
941c349dbc7Sjsg {
942c349dbc7Sjsg ssize_t length;
943c349dbc7Sjsg
944c349dbc7Sjsg switch (frame->any.type) {
945c349dbc7Sjsg case HDMI_INFOFRAME_TYPE_AVI:
946c349dbc7Sjsg length = hdmi_avi_infoframe_pack_only(&frame->avi,
947c349dbc7Sjsg buffer, size);
948c349dbc7Sjsg break;
949c349dbc7Sjsg case HDMI_INFOFRAME_TYPE_DRM:
950c349dbc7Sjsg length = hdmi_drm_infoframe_pack_only(&frame->drm,
951c349dbc7Sjsg buffer, size);
952c349dbc7Sjsg break;
953c349dbc7Sjsg case HDMI_INFOFRAME_TYPE_SPD:
954c349dbc7Sjsg length = hdmi_spd_infoframe_pack_only(&frame->spd,
955c349dbc7Sjsg buffer, size);
956c349dbc7Sjsg break;
957c349dbc7Sjsg case HDMI_INFOFRAME_TYPE_AUDIO:
958c349dbc7Sjsg length = hdmi_audio_infoframe_pack_only(&frame->audio,
959c349dbc7Sjsg buffer, size);
960c349dbc7Sjsg break;
961c349dbc7Sjsg case HDMI_INFOFRAME_TYPE_VENDOR:
962c349dbc7Sjsg length = hdmi_vendor_any_infoframe_pack_only(&frame->vendor,
963c349dbc7Sjsg buffer, size);
964c349dbc7Sjsg break;
965c349dbc7Sjsg default:
966c349dbc7Sjsg WARN(1, "Bad infoframe type %d\n", frame->any.type);
967c349dbc7Sjsg length = -EINVAL;
968c349dbc7Sjsg }
969c349dbc7Sjsg
970c349dbc7Sjsg return length;
971c349dbc7Sjsg }
972c349dbc7Sjsg EXPORT_SYMBOL(hdmi_infoframe_pack_only);
973c349dbc7Sjsg
974c349dbc7Sjsg /**
975c349dbc7Sjsg * hdmi_infoframe_pack() - check a HDMI infoframe,
976c349dbc7Sjsg * and write it to binary buffer
977c349dbc7Sjsg * @frame: HDMI infoframe
978c349dbc7Sjsg * @buffer: destination buffer
979c349dbc7Sjsg * @size: size of buffer
980c349dbc7Sjsg *
981c349dbc7Sjsg * Validates that the infoframe is consistent and updates derived fields
982c349dbc7Sjsg * (eg. length) based on other fields, after which it packs the information
983c349dbc7Sjsg * contained in the @frame structure into a binary representation that
984c349dbc7Sjsg * can be written into the corresponding controller registers. This function
985c349dbc7Sjsg * also computes the checksum as required by section 5.3.5 of the HDMI 1.4
986c349dbc7Sjsg * specification.
987c349dbc7Sjsg *
988c349dbc7Sjsg * Returns the number of bytes packed into the binary buffer or a negative
989c349dbc7Sjsg * error code on failure.
990c349dbc7Sjsg */
991c349dbc7Sjsg ssize_t
hdmi_infoframe_pack(union hdmi_infoframe * frame,void * buffer,size_t size)992c349dbc7Sjsg hdmi_infoframe_pack(union hdmi_infoframe *frame,
993c349dbc7Sjsg void *buffer, size_t size)
994c349dbc7Sjsg {
995c349dbc7Sjsg ssize_t length;
996c349dbc7Sjsg
997c349dbc7Sjsg switch (frame->any.type) {
998c349dbc7Sjsg case HDMI_INFOFRAME_TYPE_AVI:
999c349dbc7Sjsg length = hdmi_avi_infoframe_pack(&frame->avi, buffer, size);
1000c349dbc7Sjsg break;
1001c349dbc7Sjsg case HDMI_INFOFRAME_TYPE_DRM:
1002c349dbc7Sjsg length = hdmi_drm_infoframe_pack(&frame->drm, buffer, size);
1003c349dbc7Sjsg break;
1004c349dbc7Sjsg case HDMI_INFOFRAME_TYPE_SPD:
1005c349dbc7Sjsg length = hdmi_spd_infoframe_pack(&frame->spd, buffer, size);
1006c349dbc7Sjsg break;
1007c349dbc7Sjsg case HDMI_INFOFRAME_TYPE_AUDIO:
1008c349dbc7Sjsg length = hdmi_audio_infoframe_pack(&frame->audio, buffer, size);
1009c349dbc7Sjsg break;
1010c349dbc7Sjsg case HDMI_INFOFRAME_TYPE_VENDOR:
1011c349dbc7Sjsg length = hdmi_vendor_any_infoframe_pack(&frame->vendor,
1012c349dbc7Sjsg buffer, size);
1013c349dbc7Sjsg break;
1014c349dbc7Sjsg default:
1015c349dbc7Sjsg WARN(1, "Bad infoframe type %d\n", frame->any.type);
1016c349dbc7Sjsg length = -EINVAL;
1017c349dbc7Sjsg }
1018c349dbc7Sjsg
1019c349dbc7Sjsg return length;
1020c349dbc7Sjsg }
1021c349dbc7Sjsg EXPORT_SYMBOL(hdmi_infoframe_pack);
1022c349dbc7Sjsg
hdmi_infoframe_type_get_name(enum hdmi_infoframe_type type)1023c349dbc7Sjsg static const char *hdmi_infoframe_type_get_name(enum hdmi_infoframe_type type)
1024c349dbc7Sjsg {
1025c349dbc7Sjsg if (type < 0x80 || type > 0x9f)
1026c349dbc7Sjsg return "Invalid";
1027c349dbc7Sjsg switch (type) {
1028c349dbc7Sjsg case HDMI_INFOFRAME_TYPE_VENDOR:
1029c349dbc7Sjsg return "Vendor";
1030c349dbc7Sjsg case HDMI_INFOFRAME_TYPE_AVI:
1031c349dbc7Sjsg return "Auxiliary Video Information (AVI)";
1032c349dbc7Sjsg case HDMI_INFOFRAME_TYPE_SPD:
1033c349dbc7Sjsg return "Source Product Description (SPD)";
1034c349dbc7Sjsg case HDMI_INFOFRAME_TYPE_AUDIO:
1035c349dbc7Sjsg return "Audio";
1036c349dbc7Sjsg case HDMI_INFOFRAME_TYPE_DRM:
1037c349dbc7Sjsg return "Dynamic Range and Mastering";
1038c349dbc7Sjsg }
1039c349dbc7Sjsg return "Reserved";
1040c349dbc7Sjsg }
1041c349dbc7Sjsg
hdmi_infoframe_log_header(const char * level,struct device * dev,const struct hdmi_any_infoframe * frame)1042c349dbc7Sjsg static void hdmi_infoframe_log_header(const char *level,
1043c349dbc7Sjsg struct device *dev,
1044c349dbc7Sjsg const struct hdmi_any_infoframe *frame)
1045c349dbc7Sjsg {
1046c349dbc7Sjsg hdmi_log("HDMI infoframe: %s, version %u, length %u\n",
1047c349dbc7Sjsg hdmi_infoframe_type_get_name(frame->type),
1048c349dbc7Sjsg frame->version, frame->length);
1049c349dbc7Sjsg }
1050c349dbc7Sjsg
hdmi_colorspace_get_name(enum hdmi_colorspace colorspace)1051c349dbc7Sjsg static const char *hdmi_colorspace_get_name(enum hdmi_colorspace colorspace)
1052c349dbc7Sjsg {
1053c349dbc7Sjsg switch (colorspace) {
1054c349dbc7Sjsg case HDMI_COLORSPACE_RGB:
1055c349dbc7Sjsg return "RGB";
1056c349dbc7Sjsg case HDMI_COLORSPACE_YUV422:
1057c349dbc7Sjsg return "YCbCr 4:2:2";
1058c349dbc7Sjsg case HDMI_COLORSPACE_YUV444:
1059c349dbc7Sjsg return "YCbCr 4:4:4";
1060c349dbc7Sjsg case HDMI_COLORSPACE_YUV420:
1061c349dbc7Sjsg return "YCbCr 4:2:0";
1062c349dbc7Sjsg case HDMI_COLORSPACE_RESERVED4:
1063c349dbc7Sjsg return "Reserved (4)";
1064c349dbc7Sjsg case HDMI_COLORSPACE_RESERVED5:
1065c349dbc7Sjsg return "Reserved (5)";
1066c349dbc7Sjsg case HDMI_COLORSPACE_RESERVED6:
1067c349dbc7Sjsg return "Reserved (6)";
1068c349dbc7Sjsg case HDMI_COLORSPACE_IDO_DEFINED:
1069c349dbc7Sjsg return "IDO Defined";
1070c349dbc7Sjsg }
1071c349dbc7Sjsg return "Invalid";
1072c349dbc7Sjsg }
1073c349dbc7Sjsg
hdmi_scan_mode_get_name(enum hdmi_scan_mode scan_mode)1074c349dbc7Sjsg static const char *hdmi_scan_mode_get_name(enum hdmi_scan_mode scan_mode)
1075c349dbc7Sjsg {
1076c349dbc7Sjsg switch (scan_mode) {
1077c349dbc7Sjsg case HDMI_SCAN_MODE_NONE:
1078c349dbc7Sjsg return "No Data";
1079c349dbc7Sjsg case HDMI_SCAN_MODE_OVERSCAN:
1080c349dbc7Sjsg return "Overscan";
1081c349dbc7Sjsg case HDMI_SCAN_MODE_UNDERSCAN:
1082c349dbc7Sjsg return "Underscan";
1083c349dbc7Sjsg case HDMI_SCAN_MODE_RESERVED:
1084c349dbc7Sjsg return "Reserved";
1085c349dbc7Sjsg }
1086c349dbc7Sjsg return "Invalid";
1087c349dbc7Sjsg }
1088c349dbc7Sjsg
hdmi_colorimetry_get_name(enum hdmi_colorimetry colorimetry)1089c349dbc7Sjsg static const char *hdmi_colorimetry_get_name(enum hdmi_colorimetry colorimetry)
1090c349dbc7Sjsg {
1091c349dbc7Sjsg switch (colorimetry) {
1092c349dbc7Sjsg case HDMI_COLORIMETRY_NONE:
1093c349dbc7Sjsg return "No Data";
1094c349dbc7Sjsg case HDMI_COLORIMETRY_ITU_601:
1095c349dbc7Sjsg return "ITU601";
1096c349dbc7Sjsg case HDMI_COLORIMETRY_ITU_709:
1097c349dbc7Sjsg return "ITU709";
1098c349dbc7Sjsg case HDMI_COLORIMETRY_EXTENDED:
1099c349dbc7Sjsg return "Extended";
1100c349dbc7Sjsg }
1101c349dbc7Sjsg return "Invalid";
1102c349dbc7Sjsg }
1103c349dbc7Sjsg
1104c349dbc7Sjsg static const char *
hdmi_picture_aspect_get_name(enum hdmi_picture_aspect picture_aspect)1105c349dbc7Sjsg hdmi_picture_aspect_get_name(enum hdmi_picture_aspect picture_aspect)
1106c349dbc7Sjsg {
1107c349dbc7Sjsg switch (picture_aspect) {
1108c349dbc7Sjsg case HDMI_PICTURE_ASPECT_NONE:
1109c349dbc7Sjsg return "No Data";
1110c349dbc7Sjsg case HDMI_PICTURE_ASPECT_4_3:
1111c349dbc7Sjsg return "4:3";
1112c349dbc7Sjsg case HDMI_PICTURE_ASPECT_16_9:
1113c349dbc7Sjsg return "16:9";
1114c349dbc7Sjsg case HDMI_PICTURE_ASPECT_64_27:
1115c349dbc7Sjsg return "64:27";
1116c349dbc7Sjsg case HDMI_PICTURE_ASPECT_256_135:
1117c349dbc7Sjsg return "256:135";
1118c349dbc7Sjsg case HDMI_PICTURE_ASPECT_RESERVED:
1119c349dbc7Sjsg return "Reserved";
1120c349dbc7Sjsg }
1121c349dbc7Sjsg return "Invalid";
1122c349dbc7Sjsg }
1123c349dbc7Sjsg
1124c349dbc7Sjsg static const char *
hdmi_active_aspect_get_name(enum hdmi_active_aspect active_aspect)1125c349dbc7Sjsg hdmi_active_aspect_get_name(enum hdmi_active_aspect active_aspect)
1126c349dbc7Sjsg {
1127c349dbc7Sjsg if (active_aspect < 0 || active_aspect > 0xf)
1128c349dbc7Sjsg return "Invalid";
1129c349dbc7Sjsg
1130c349dbc7Sjsg switch (active_aspect) {
1131c349dbc7Sjsg case HDMI_ACTIVE_ASPECT_16_9_TOP:
1132c349dbc7Sjsg return "16:9 Top";
1133c349dbc7Sjsg case HDMI_ACTIVE_ASPECT_14_9_TOP:
1134c349dbc7Sjsg return "14:9 Top";
1135c349dbc7Sjsg case HDMI_ACTIVE_ASPECT_16_9_CENTER:
1136c349dbc7Sjsg return "16:9 Center";
1137c349dbc7Sjsg case HDMI_ACTIVE_ASPECT_PICTURE:
1138c349dbc7Sjsg return "Same as Picture";
1139c349dbc7Sjsg case HDMI_ACTIVE_ASPECT_4_3:
1140c349dbc7Sjsg return "4:3";
1141c349dbc7Sjsg case HDMI_ACTIVE_ASPECT_16_9:
1142c349dbc7Sjsg return "16:9";
1143c349dbc7Sjsg case HDMI_ACTIVE_ASPECT_14_9:
1144c349dbc7Sjsg return "14:9";
1145c349dbc7Sjsg case HDMI_ACTIVE_ASPECT_4_3_SP_14_9:
1146c349dbc7Sjsg return "4:3 SP 14:9";
1147c349dbc7Sjsg case HDMI_ACTIVE_ASPECT_16_9_SP_14_9:
1148c349dbc7Sjsg return "16:9 SP 14:9";
1149c349dbc7Sjsg case HDMI_ACTIVE_ASPECT_16_9_SP_4_3:
1150c349dbc7Sjsg return "16:9 SP 4:3";
1151c349dbc7Sjsg }
1152c349dbc7Sjsg return "Reserved";
1153c349dbc7Sjsg }
1154c349dbc7Sjsg
1155c349dbc7Sjsg static const char *
hdmi_extended_colorimetry_get_name(enum hdmi_extended_colorimetry ext_col)1156c349dbc7Sjsg hdmi_extended_colorimetry_get_name(enum hdmi_extended_colorimetry ext_col)
1157c349dbc7Sjsg {
1158c349dbc7Sjsg switch (ext_col) {
1159c349dbc7Sjsg case HDMI_EXTENDED_COLORIMETRY_XV_YCC_601:
1160c349dbc7Sjsg return "xvYCC 601";
1161c349dbc7Sjsg case HDMI_EXTENDED_COLORIMETRY_XV_YCC_709:
1162c349dbc7Sjsg return "xvYCC 709";
1163c349dbc7Sjsg case HDMI_EXTENDED_COLORIMETRY_S_YCC_601:
1164c349dbc7Sjsg return "sYCC 601";
1165c349dbc7Sjsg case HDMI_EXTENDED_COLORIMETRY_OPYCC_601:
1166c349dbc7Sjsg return "opYCC 601";
1167c349dbc7Sjsg case HDMI_EXTENDED_COLORIMETRY_OPRGB:
1168c349dbc7Sjsg return "opRGB";
1169c349dbc7Sjsg case HDMI_EXTENDED_COLORIMETRY_BT2020_CONST_LUM:
1170c349dbc7Sjsg return "BT.2020 Constant Luminance";
1171c349dbc7Sjsg case HDMI_EXTENDED_COLORIMETRY_BT2020:
1172c349dbc7Sjsg return "BT.2020";
1173c349dbc7Sjsg case HDMI_EXTENDED_COLORIMETRY_RESERVED:
1174c349dbc7Sjsg return "Reserved";
1175c349dbc7Sjsg }
1176c349dbc7Sjsg return "Invalid";
1177c349dbc7Sjsg }
1178c349dbc7Sjsg
1179c349dbc7Sjsg static const char *
hdmi_quantization_range_get_name(enum hdmi_quantization_range qrange)1180c349dbc7Sjsg hdmi_quantization_range_get_name(enum hdmi_quantization_range qrange)
1181c349dbc7Sjsg {
1182c349dbc7Sjsg switch (qrange) {
1183c349dbc7Sjsg case HDMI_QUANTIZATION_RANGE_DEFAULT:
1184c349dbc7Sjsg return "Default";
1185c349dbc7Sjsg case HDMI_QUANTIZATION_RANGE_LIMITED:
1186c349dbc7Sjsg return "Limited";
1187c349dbc7Sjsg case HDMI_QUANTIZATION_RANGE_FULL:
1188c349dbc7Sjsg return "Full";
1189c349dbc7Sjsg case HDMI_QUANTIZATION_RANGE_RESERVED:
1190c349dbc7Sjsg return "Reserved";
1191c349dbc7Sjsg }
1192c349dbc7Sjsg return "Invalid";
1193c349dbc7Sjsg }
1194c349dbc7Sjsg
hdmi_nups_get_name(enum hdmi_nups nups)1195c349dbc7Sjsg static const char *hdmi_nups_get_name(enum hdmi_nups nups)
1196c349dbc7Sjsg {
1197c349dbc7Sjsg switch (nups) {
1198c349dbc7Sjsg case HDMI_NUPS_UNKNOWN:
1199c349dbc7Sjsg return "Unknown Non-uniform Scaling";
1200c349dbc7Sjsg case HDMI_NUPS_HORIZONTAL:
1201c349dbc7Sjsg return "Horizontally Scaled";
1202c349dbc7Sjsg case HDMI_NUPS_VERTICAL:
1203c349dbc7Sjsg return "Vertically Scaled";
1204c349dbc7Sjsg case HDMI_NUPS_BOTH:
1205c349dbc7Sjsg return "Horizontally and Vertically Scaled";
1206c349dbc7Sjsg }
1207c349dbc7Sjsg return "Invalid";
1208c349dbc7Sjsg }
1209c349dbc7Sjsg
1210c349dbc7Sjsg static const char *
hdmi_ycc_quantization_range_get_name(enum hdmi_ycc_quantization_range qrange)1211c349dbc7Sjsg hdmi_ycc_quantization_range_get_name(enum hdmi_ycc_quantization_range qrange)
1212c349dbc7Sjsg {
1213c349dbc7Sjsg switch (qrange) {
1214c349dbc7Sjsg case HDMI_YCC_QUANTIZATION_RANGE_LIMITED:
1215c349dbc7Sjsg return "Limited";
1216c349dbc7Sjsg case HDMI_YCC_QUANTIZATION_RANGE_FULL:
1217c349dbc7Sjsg return "Full";
1218c349dbc7Sjsg }
1219c349dbc7Sjsg return "Invalid";
1220c349dbc7Sjsg }
1221c349dbc7Sjsg
1222c349dbc7Sjsg static const char *
hdmi_content_type_get_name(enum hdmi_content_type content_type)1223c349dbc7Sjsg hdmi_content_type_get_name(enum hdmi_content_type content_type)
1224c349dbc7Sjsg {
1225c349dbc7Sjsg switch (content_type) {
1226c349dbc7Sjsg case HDMI_CONTENT_TYPE_GRAPHICS:
1227c349dbc7Sjsg return "Graphics";
1228c349dbc7Sjsg case HDMI_CONTENT_TYPE_PHOTO:
1229c349dbc7Sjsg return "Photo";
1230c349dbc7Sjsg case HDMI_CONTENT_TYPE_CINEMA:
1231c349dbc7Sjsg return "Cinema";
1232c349dbc7Sjsg case HDMI_CONTENT_TYPE_GAME:
1233c349dbc7Sjsg return "Game";
1234c349dbc7Sjsg }
1235c349dbc7Sjsg return "Invalid";
1236c349dbc7Sjsg }
1237c349dbc7Sjsg
hdmi_avi_infoframe_log(const char * level,struct device * dev,const struct hdmi_avi_infoframe * frame)1238c349dbc7Sjsg static void hdmi_avi_infoframe_log(const char *level,
1239c349dbc7Sjsg struct device *dev,
1240c349dbc7Sjsg const struct hdmi_avi_infoframe *frame)
1241c349dbc7Sjsg {
1242c349dbc7Sjsg hdmi_infoframe_log_header(level, dev,
1243c349dbc7Sjsg (const struct hdmi_any_infoframe *)frame);
1244c349dbc7Sjsg
1245c349dbc7Sjsg hdmi_log(" colorspace: %s\n",
1246c349dbc7Sjsg hdmi_colorspace_get_name(frame->colorspace));
1247c349dbc7Sjsg hdmi_log(" scan mode: %s\n",
1248c349dbc7Sjsg hdmi_scan_mode_get_name(frame->scan_mode));
1249c349dbc7Sjsg hdmi_log(" colorimetry: %s\n",
1250c349dbc7Sjsg hdmi_colorimetry_get_name(frame->colorimetry));
1251c349dbc7Sjsg hdmi_log(" picture aspect: %s\n",
1252c349dbc7Sjsg hdmi_picture_aspect_get_name(frame->picture_aspect));
1253c349dbc7Sjsg hdmi_log(" active aspect: %s\n",
1254c349dbc7Sjsg hdmi_active_aspect_get_name(frame->active_aspect));
1255c349dbc7Sjsg hdmi_log(" itc: %s\n", frame->itc ? "IT Content" : "No Data");
1256c349dbc7Sjsg hdmi_log(" extended colorimetry: %s\n",
1257c349dbc7Sjsg hdmi_extended_colorimetry_get_name(frame->extended_colorimetry));
1258c349dbc7Sjsg hdmi_log(" quantization range: %s\n",
1259c349dbc7Sjsg hdmi_quantization_range_get_name(frame->quantization_range));
1260c349dbc7Sjsg hdmi_log(" nups: %s\n", hdmi_nups_get_name(frame->nups));
1261c349dbc7Sjsg hdmi_log(" video code: %u\n", frame->video_code);
1262c349dbc7Sjsg hdmi_log(" ycc quantization range: %s\n",
1263c349dbc7Sjsg hdmi_ycc_quantization_range_get_name(frame->ycc_quantization_range));
1264c349dbc7Sjsg hdmi_log(" hdmi content type: %s\n",
1265c349dbc7Sjsg hdmi_content_type_get_name(frame->content_type));
1266c349dbc7Sjsg hdmi_log(" pixel repeat: %u\n", frame->pixel_repeat);
1267c349dbc7Sjsg hdmi_log(" bar top %u, bottom %u, left %u, right %u\n",
1268c349dbc7Sjsg frame->top_bar, frame->bottom_bar,
1269c349dbc7Sjsg frame->left_bar, frame->right_bar);
1270c349dbc7Sjsg }
1271c349dbc7Sjsg
hdmi_spd_sdi_get_name(enum hdmi_spd_sdi sdi)1272c349dbc7Sjsg static const char *hdmi_spd_sdi_get_name(enum hdmi_spd_sdi sdi)
1273c349dbc7Sjsg {
1274c349dbc7Sjsg if (sdi < 0 || sdi > 0xff)
1275c349dbc7Sjsg return "Invalid";
1276c349dbc7Sjsg switch (sdi) {
1277c349dbc7Sjsg case HDMI_SPD_SDI_UNKNOWN:
1278c349dbc7Sjsg return "Unknown";
1279c349dbc7Sjsg case HDMI_SPD_SDI_DSTB:
1280c349dbc7Sjsg return "Digital STB";
1281c349dbc7Sjsg case HDMI_SPD_SDI_DVDP:
1282c349dbc7Sjsg return "DVD Player";
1283c349dbc7Sjsg case HDMI_SPD_SDI_DVHS:
1284c349dbc7Sjsg return "D-VHS";
1285c349dbc7Sjsg case HDMI_SPD_SDI_HDDVR:
1286c349dbc7Sjsg return "HDD Videorecorder";
1287c349dbc7Sjsg case HDMI_SPD_SDI_DVC:
1288c349dbc7Sjsg return "DVC";
1289c349dbc7Sjsg case HDMI_SPD_SDI_DSC:
1290c349dbc7Sjsg return "DSC";
1291c349dbc7Sjsg case HDMI_SPD_SDI_VCD:
1292c349dbc7Sjsg return "Video CD";
1293c349dbc7Sjsg case HDMI_SPD_SDI_GAME:
1294c349dbc7Sjsg return "Game";
1295c349dbc7Sjsg case HDMI_SPD_SDI_PC:
1296c349dbc7Sjsg return "PC General";
1297c349dbc7Sjsg case HDMI_SPD_SDI_BD:
1298c349dbc7Sjsg return "Blu-Ray Disc (BD)";
1299c349dbc7Sjsg case HDMI_SPD_SDI_SACD:
1300c349dbc7Sjsg return "Super Audio CD";
1301c349dbc7Sjsg case HDMI_SPD_SDI_HDDVD:
1302c349dbc7Sjsg return "HD DVD";
1303c349dbc7Sjsg case HDMI_SPD_SDI_PMP:
1304c349dbc7Sjsg return "PMP";
1305c349dbc7Sjsg }
1306c349dbc7Sjsg return "Reserved";
1307c349dbc7Sjsg }
1308c349dbc7Sjsg
hdmi_spd_infoframe_log(const char * level,struct device * dev,const struct hdmi_spd_infoframe * frame)1309c349dbc7Sjsg static void hdmi_spd_infoframe_log(const char *level,
1310c349dbc7Sjsg struct device *dev,
1311c349dbc7Sjsg const struct hdmi_spd_infoframe *frame)
1312c349dbc7Sjsg {
1313c349dbc7Sjsg u8 buf[17];
1314c349dbc7Sjsg
1315c349dbc7Sjsg hdmi_infoframe_log_header(level, dev,
1316c349dbc7Sjsg (const struct hdmi_any_infoframe *)frame);
1317c349dbc7Sjsg
1318c349dbc7Sjsg memset(buf, 0, sizeof(buf));
1319c349dbc7Sjsg
1320c349dbc7Sjsg strncpy(buf, frame->vendor, 8);
1321c349dbc7Sjsg hdmi_log(" vendor: %s\n", buf);
1322c349dbc7Sjsg strncpy(buf, frame->product, 16);
1323c349dbc7Sjsg hdmi_log(" product: %s\n", buf);
1324c349dbc7Sjsg hdmi_log(" source device information: %s (0x%x)\n",
1325c349dbc7Sjsg hdmi_spd_sdi_get_name(frame->sdi), frame->sdi);
1326c349dbc7Sjsg }
1327c349dbc7Sjsg
1328c349dbc7Sjsg static const char *
hdmi_audio_coding_type_get_name(enum hdmi_audio_coding_type coding_type)1329c349dbc7Sjsg hdmi_audio_coding_type_get_name(enum hdmi_audio_coding_type coding_type)
1330c349dbc7Sjsg {
1331c349dbc7Sjsg switch (coding_type) {
1332c349dbc7Sjsg case HDMI_AUDIO_CODING_TYPE_STREAM:
1333c349dbc7Sjsg return "Refer to Stream Header";
1334c349dbc7Sjsg case HDMI_AUDIO_CODING_TYPE_PCM:
1335c349dbc7Sjsg return "PCM";
1336c349dbc7Sjsg case HDMI_AUDIO_CODING_TYPE_AC3:
1337c349dbc7Sjsg return "AC-3";
1338c349dbc7Sjsg case HDMI_AUDIO_CODING_TYPE_MPEG1:
1339c349dbc7Sjsg return "MPEG1";
1340c349dbc7Sjsg case HDMI_AUDIO_CODING_TYPE_MP3:
1341c349dbc7Sjsg return "MP3";
1342c349dbc7Sjsg case HDMI_AUDIO_CODING_TYPE_MPEG2:
1343c349dbc7Sjsg return "MPEG2";
1344c349dbc7Sjsg case HDMI_AUDIO_CODING_TYPE_AAC_LC:
1345c349dbc7Sjsg return "AAC";
1346c349dbc7Sjsg case HDMI_AUDIO_CODING_TYPE_DTS:
1347c349dbc7Sjsg return "DTS";
1348c349dbc7Sjsg case HDMI_AUDIO_CODING_TYPE_ATRAC:
1349c349dbc7Sjsg return "ATRAC";
1350c349dbc7Sjsg case HDMI_AUDIO_CODING_TYPE_DSD:
1351c349dbc7Sjsg return "One Bit Audio";
1352c349dbc7Sjsg case HDMI_AUDIO_CODING_TYPE_EAC3:
1353c349dbc7Sjsg return "Dolby Digital +";
1354c349dbc7Sjsg case HDMI_AUDIO_CODING_TYPE_DTS_HD:
1355c349dbc7Sjsg return "DTS-HD";
1356c349dbc7Sjsg case HDMI_AUDIO_CODING_TYPE_MLP:
1357c349dbc7Sjsg return "MAT (MLP)";
1358c349dbc7Sjsg case HDMI_AUDIO_CODING_TYPE_DST:
1359c349dbc7Sjsg return "DST";
1360c349dbc7Sjsg case HDMI_AUDIO_CODING_TYPE_WMA_PRO:
1361c349dbc7Sjsg return "WMA PRO";
1362c349dbc7Sjsg case HDMI_AUDIO_CODING_TYPE_CXT:
1363c349dbc7Sjsg return "Refer to CXT";
1364c349dbc7Sjsg }
1365c349dbc7Sjsg return "Invalid";
1366c349dbc7Sjsg }
1367c349dbc7Sjsg
1368c349dbc7Sjsg static const char *
hdmi_audio_sample_size_get_name(enum hdmi_audio_sample_size sample_size)1369c349dbc7Sjsg hdmi_audio_sample_size_get_name(enum hdmi_audio_sample_size sample_size)
1370c349dbc7Sjsg {
1371c349dbc7Sjsg switch (sample_size) {
1372c349dbc7Sjsg case HDMI_AUDIO_SAMPLE_SIZE_STREAM:
1373c349dbc7Sjsg return "Refer to Stream Header";
1374c349dbc7Sjsg case HDMI_AUDIO_SAMPLE_SIZE_16:
1375c349dbc7Sjsg return "16 bit";
1376c349dbc7Sjsg case HDMI_AUDIO_SAMPLE_SIZE_20:
1377c349dbc7Sjsg return "20 bit";
1378c349dbc7Sjsg case HDMI_AUDIO_SAMPLE_SIZE_24:
1379c349dbc7Sjsg return "24 bit";
1380c349dbc7Sjsg }
1381c349dbc7Sjsg return "Invalid";
1382c349dbc7Sjsg }
1383c349dbc7Sjsg
1384c349dbc7Sjsg static const char *
hdmi_audio_sample_frequency_get_name(enum hdmi_audio_sample_frequency freq)1385c349dbc7Sjsg hdmi_audio_sample_frequency_get_name(enum hdmi_audio_sample_frequency freq)
1386c349dbc7Sjsg {
1387c349dbc7Sjsg switch (freq) {
1388c349dbc7Sjsg case HDMI_AUDIO_SAMPLE_FREQUENCY_STREAM:
1389c349dbc7Sjsg return "Refer to Stream Header";
1390c349dbc7Sjsg case HDMI_AUDIO_SAMPLE_FREQUENCY_32000:
1391c349dbc7Sjsg return "32 kHz";
1392c349dbc7Sjsg case HDMI_AUDIO_SAMPLE_FREQUENCY_44100:
1393c349dbc7Sjsg return "44.1 kHz (CD)";
1394c349dbc7Sjsg case HDMI_AUDIO_SAMPLE_FREQUENCY_48000:
1395c349dbc7Sjsg return "48 kHz";
1396c349dbc7Sjsg case HDMI_AUDIO_SAMPLE_FREQUENCY_88200:
1397c349dbc7Sjsg return "88.2 kHz";
1398c349dbc7Sjsg case HDMI_AUDIO_SAMPLE_FREQUENCY_96000:
1399c349dbc7Sjsg return "96 kHz";
1400c349dbc7Sjsg case HDMI_AUDIO_SAMPLE_FREQUENCY_176400:
1401c349dbc7Sjsg return "176.4 kHz";
1402c349dbc7Sjsg case HDMI_AUDIO_SAMPLE_FREQUENCY_192000:
1403c349dbc7Sjsg return "192 kHz";
1404c349dbc7Sjsg }
1405c349dbc7Sjsg return "Invalid";
1406c349dbc7Sjsg }
1407c349dbc7Sjsg
1408c349dbc7Sjsg static const char *
hdmi_audio_coding_type_ext_get_name(enum hdmi_audio_coding_type_ext ctx)1409c349dbc7Sjsg hdmi_audio_coding_type_ext_get_name(enum hdmi_audio_coding_type_ext ctx)
1410c349dbc7Sjsg {
1411c349dbc7Sjsg if (ctx < 0 || ctx > 0x1f)
1412c349dbc7Sjsg return "Invalid";
1413c349dbc7Sjsg
1414c349dbc7Sjsg switch (ctx) {
1415c349dbc7Sjsg case HDMI_AUDIO_CODING_TYPE_EXT_CT:
1416c349dbc7Sjsg return "Refer to CT";
1417c349dbc7Sjsg case HDMI_AUDIO_CODING_TYPE_EXT_HE_AAC:
1418c349dbc7Sjsg return "HE AAC";
1419c349dbc7Sjsg case HDMI_AUDIO_CODING_TYPE_EXT_HE_AAC_V2:
1420c349dbc7Sjsg return "HE AAC v2";
1421c349dbc7Sjsg case HDMI_AUDIO_CODING_TYPE_EXT_MPEG_SURROUND:
1422c349dbc7Sjsg return "MPEG SURROUND";
1423c349dbc7Sjsg case HDMI_AUDIO_CODING_TYPE_EXT_MPEG4_HE_AAC:
1424c349dbc7Sjsg return "MPEG-4 HE AAC";
1425c349dbc7Sjsg case HDMI_AUDIO_CODING_TYPE_EXT_MPEG4_HE_AAC_V2:
1426c349dbc7Sjsg return "MPEG-4 HE AAC v2";
1427c349dbc7Sjsg case HDMI_AUDIO_CODING_TYPE_EXT_MPEG4_AAC_LC:
1428c349dbc7Sjsg return "MPEG-4 AAC LC";
1429c349dbc7Sjsg case HDMI_AUDIO_CODING_TYPE_EXT_DRA:
1430c349dbc7Sjsg return "DRA";
1431c349dbc7Sjsg case HDMI_AUDIO_CODING_TYPE_EXT_MPEG4_HE_AAC_SURROUND:
1432c349dbc7Sjsg return "MPEG-4 HE AAC + MPEG Surround";
1433c349dbc7Sjsg case HDMI_AUDIO_CODING_TYPE_EXT_MPEG4_AAC_LC_SURROUND:
1434c349dbc7Sjsg return "MPEG-4 AAC LC + MPEG Surround";
1435c349dbc7Sjsg }
1436c349dbc7Sjsg return "Reserved";
1437c349dbc7Sjsg }
1438c349dbc7Sjsg
hdmi_audio_infoframe_log(const char * level,struct device * dev,const struct hdmi_audio_infoframe * frame)1439c349dbc7Sjsg static void hdmi_audio_infoframe_log(const char *level,
1440c349dbc7Sjsg struct device *dev,
1441c349dbc7Sjsg const struct hdmi_audio_infoframe *frame)
1442c349dbc7Sjsg {
1443c349dbc7Sjsg hdmi_infoframe_log_header(level, dev,
1444c349dbc7Sjsg (const struct hdmi_any_infoframe *)frame);
1445c349dbc7Sjsg
1446c349dbc7Sjsg if (frame->channels)
1447c349dbc7Sjsg hdmi_log(" channels: %u\n", frame->channels - 1);
1448c349dbc7Sjsg else
1449c349dbc7Sjsg hdmi_log(" channels: Refer to stream header\n");
1450c349dbc7Sjsg hdmi_log(" coding type: %s\n",
1451c349dbc7Sjsg hdmi_audio_coding_type_get_name(frame->coding_type));
1452c349dbc7Sjsg hdmi_log(" sample size: %s\n",
1453c349dbc7Sjsg hdmi_audio_sample_size_get_name(frame->sample_size));
1454c349dbc7Sjsg hdmi_log(" sample frequency: %s\n",
1455c349dbc7Sjsg hdmi_audio_sample_frequency_get_name(frame->sample_frequency));
1456c349dbc7Sjsg hdmi_log(" coding type ext: %s\n",
1457c349dbc7Sjsg hdmi_audio_coding_type_ext_get_name(frame->coding_type_ext));
1458c349dbc7Sjsg hdmi_log(" channel allocation: 0x%x\n",
1459c349dbc7Sjsg frame->channel_allocation);
1460c349dbc7Sjsg hdmi_log(" level shift value: %u dB\n",
1461c349dbc7Sjsg frame->level_shift_value);
1462c349dbc7Sjsg hdmi_log(" downmix inhibit: %s\n",
1463c349dbc7Sjsg frame->downmix_inhibit ? "Yes" : "No");
1464c349dbc7Sjsg }
1465c349dbc7Sjsg
hdmi_drm_infoframe_log(const char * level,struct device * dev,const struct hdmi_drm_infoframe * frame)1466c349dbc7Sjsg static void hdmi_drm_infoframe_log(const char *level,
1467c349dbc7Sjsg struct device *dev,
1468c349dbc7Sjsg const struct hdmi_drm_infoframe *frame)
1469c349dbc7Sjsg {
1470c349dbc7Sjsg int i;
1471c349dbc7Sjsg
1472c349dbc7Sjsg hdmi_infoframe_log_header(level, dev,
1473c349dbc7Sjsg (struct hdmi_any_infoframe *)frame);
1474c349dbc7Sjsg hdmi_log("length: %d\n", frame->length);
1475c349dbc7Sjsg hdmi_log("metadata type: %d\n", frame->metadata_type);
1476c349dbc7Sjsg hdmi_log("eotf: %d\n", frame->eotf);
1477c349dbc7Sjsg for (i = 0; i < 3; i++) {
1478c349dbc7Sjsg hdmi_log("x[%d]: %d\n", i, frame->display_primaries[i].x);
1479c349dbc7Sjsg hdmi_log("y[%d]: %d\n", i, frame->display_primaries[i].y);
1480c349dbc7Sjsg }
1481c349dbc7Sjsg
1482c349dbc7Sjsg hdmi_log("white point x: %d\n", frame->white_point.x);
1483c349dbc7Sjsg hdmi_log("white point y: %d\n", frame->white_point.y);
1484c349dbc7Sjsg
1485c349dbc7Sjsg hdmi_log("max_display_mastering_luminance: %d\n",
1486c349dbc7Sjsg frame->max_display_mastering_luminance);
1487c349dbc7Sjsg hdmi_log("min_display_mastering_luminance: %d\n",
1488c349dbc7Sjsg frame->min_display_mastering_luminance);
1489c349dbc7Sjsg
1490c349dbc7Sjsg hdmi_log("max_cll: %d\n", frame->max_cll);
1491c349dbc7Sjsg hdmi_log("max_fall: %d\n", frame->max_fall);
1492c349dbc7Sjsg }
1493c349dbc7Sjsg
1494c349dbc7Sjsg static const char *
hdmi_3d_structure_get_name(enum hdmi_3d_structure s3d_struct)1495c349dbc7Sjsg hdmi_3d_structure_get_name(enum hdmi_3d_structure s3d_struct)
1496c349dbc7Sjsg {
1497c349dbc7Sjsg if (s3d_struct < 0 || s3d_struct > 0xf)
1498c349dbc7Sjsg return "Invalid";
1499c349dbc7Sjsg
1500c349dbc7Sjsg switch (s3d_struct) {
1501c349dbc7Sjsg case HDMI_3D_STRUCTURE_FRAME_PACKING:
1502c349dbc7Sjsg return "Frame Packing";
1503c349dbc7Sjsg case HDMI_3D_STRUCTURE_FIELD_ALTERNATIVE:
1504c349dbc7Sjsg return "Field Alternative";
1505c349dbc7Sjsg case HDMI_3D_STRUCTURE_LINE_ALTERNATIVE:
1506c349dbc7Sjsg return "Line Alternative";
1507c349dbc7Sjsg case HDMI_3D_STRUCTURE_SIDE_BY_SIDE_FULL:
1508c349dbc7Sjsg return "Side-by-side (Full)";
1509c349dbc7Sjsg case HDMI_3D_STRUCTURE_L_DEPTH:
1510c349dbc7Sjsg return "L + Depth";
1511c349dbc7Sjsg case HDMI_3D_STRUCTURE_L_DEPTH_GFX_GFX_DEPTH:
1512c349dbc7Sjsg return "L + Depth + Graphics + Graphics-depth";
1513c349dbc7Sjsg case HDMI_3D_STRUCTURE_TOP_AND_BOTTOM:
1514c349dbc7Sjsg return "Top-and-Bottom";
1515c349dbc7Sjsg case HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF:
1516c349dbc7Sjsg return "Side-by-side (Half)";
1517c349dbc7Sjsg default:
1518c349dbc7Sjsg break;
1519c349dbc7Sjsg }
1520c349dbc7Sjsg return "Reserved";
1521c349dbc7Sjsg }
1522c349dbc7Sjsg
1523c349dbc7Sjsg static void
hdmi_vendor_any_infoframe_log(const char * level,struct device * dev,const union hdmi_vendor_any_infoframe * frame)1524c349dbc7Sjsg hdmi_vendor_any_infoframe_log(const char *level,
1525c349dbc7Sjsg struct device *dev,
1526c349dbc7Sjsg const union hdmi_vendor_any_infoframe *frame)
1527c349dbc7Sjsg {
1528c349dbc7Sjsg const struct hdmi_vendor_infoframe *hvf = &frame->hdmi;
1529c349dbc7Sjsg
1530c349dbc7Sjsg hdmi_infoframe_log_header(level, dev,
1531c349dbc7Sjsg (const struct hdmi_any_infoframe *)frame);
1532c349dbc7Sjsg
1533c349dbc7Sjsg if (frame->any.oui != HDMI_IEEE_OUI) {
1534c349dbc7Sjsg hdmi_log(" not a HDMI vendor infoframe\n");
1535c349dbc7Sjsg return;
1536c349dbc7Sjsg }
1537c349dbc7Sjsg if (hvf->vic == 0 && hvf->s3d_struct == HDMI_3D_STRUCTURE_INVALID) {
1538c349dbc7Sjsg hdmi_log(" empty frame\n");
1539c349dbc7Sjsg return;
1540c349dbc7Sjsg }
1541c349dbc7Sjsg
1542c349dbc7Sjsg if (hvf->vic)
1543c349dbc7Sjsg hdmi_log(" HDMI VIC: %u\n", hvf->vic);
1544c349dbc7Sjsg if (hvf->s3d_struct != HDMI_3D_STRUCTURE_INVALID) {
1545c349dbc7Sjsg hdmi_log(" 3D structure: %s\n",
1546c349dbc7Sjsg hdmi_3d_structure_get_name(hvf->s3d_struct));
1547c349dbc7Sjsg if (hvf->s3d_struct >= HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF)
1548c349dbc7Sjsg hdmi_log(" 3D extension data: %d\n",
1549c349dbc7Sjsg hvf->s3d_ext_data);
1550c349dbc7Sjsg }
1551c349dbc7Sjsg }
1552c349dbc7Sjsg
1553c349dbc7Sjsg /**
1554c349dbc7Sjsg * hdmi_infoframe_log() - log info of HDMI infoframe
1555c349dbc7Sjsg * @level: logging level
1556c349dbc7Sjsg * @dev: device
1557c349dbc7Sjsg * @frame: HDMI infoframe
1558c349dbc7Sjsg */
hdmi_infoframe_log(const char * level,struct device * dev,const union hdmi_infoframe * frame)1559c349dbc7Sjsg void hdmi_infoframe_log(const char *level,
1560c349dbc7Sjsg struct device *dev,
1561c349dbc7Sjsg const union hdmi_infoframe *frame)
1562c349dbc7Sjsg {
1563c349dbc7Sjsg switch (frame->any.type) {
1564c349dbc7Sjsg case HDMI_INFOFRAME_TYPE_AVI:
1565c349dbc7Sjsg hdmi_avi_infoframe_log(level, dev, &frame->avi);
1566c349dbc7Sjsg break;
1567c349dbc7Sjsg case HDMI_INFOFRAME_TYPE_SPD:
1568c349dbc7Sjsg hdmi_spd_infoframe_log(level, dev, &frame->spd);
1569c349dbc7Sjsg break;
1570c349dbc7Sjsg case HDMI_INFOFRAME_TYPE_AUDIO:
1571c349dbc7Sjsg hdmi_audio_infoframe_log(level, dev, &frame->audio);
1572c349dbc7Sjsg break;
1573c349dbc7Sjsg case HDMI_INFOFRAME_TYPE_VENDOR:
1574c349dbc7Sjsg hdmi_vendor_any_infoframe_log(level, dev, &frame->vendor);
1575c349dbc7Sjsg break;
1576c349dbc7Sjsg case HDMI_INFOFRAME_TYPE_DRM:
1577c349dbc7Sjsg hdmi_drm_infoframe_log(level, dev, &frame->drm);
1578c349dbc7Sjsg break;
1579c349dbc7Sjsg }
1580c349dbc7Sjsg }
1581c349dbc7Sjsg EXPORT_SYMBOL(hdmi_infoframe_log);
1582c349dbc7Sjsg
1583c349dbc7Sjsg /**
1584c349dbc7Sjsg * hdmi_avi_infoframe_unpack() - unpack binary buffer to a HDMI AVI infoframe
1585c349dbc7Sjsg * @frame: HDMI AVI infoframe
1586c349dbc7Sjsg * @buffer: source buffer
1587c349dbc7Sjsg * @size: size of buffer
1588c349dbc7Sjsg *
1589c349dbc7Sjsg * Unpacks the information contained in binary @buffer into a structured
1590c349dbc7Sjsg * @frame of the HDMI Auxiliary Video (AVI) information frame.
1591c349dbc7Sjsg * Also verifies the checksum as required by section 5.3.5 of the HDMI 1.4
1592c349dbc7Sjsg * specification.
1593c349dbc7Sjsg *
1594c349dbc7Sjsg * Returns 0 on success or a negative error code on failure.
1595c349dbc7Sjsg */
hdmi_avi_infoframe_unpack(struct hdmi_avi_infoframe * frame,const void * buffer,size_t size)1596c349dbc7Sjsg static int hdmi_avi_infoframe_unpack(struct hdmi_avi_infoframe *frame,
1597c349dbc7Sjsg const void *buffer, size_t size)
1598c349dbc7Sjsg {
1599c349dbc7Sjsg const u8 *ptr = buffer;
1600c349dbc7Sjsg
1601c349dbc7Sjsg if (size < HDMI_INFOFRAME_SIZE(AVI))
1602c349dbc7Sjsg return -EINVAL;
1603c349dbc7Sjsg
1604c349dbc7Sjsg if (ptr[0] != HDMI_INFOFRAME_TYPE_AVI ||
1605c349dbc7Sjsg ptr[1] != 2 ||
1606c349dbc7Sjsg ptr[2] != HDMI_AVI_INFOFRAME_SIZE)
1607c349dbc7Sjsg return -EINVAL;
1608c349dbc7Sjsg
1609c349dbc7Sjsg if (hdmi_infoframe_checksum(buffer, HDMI_INFOFRAME_SIZE(AVI)) != 0)
1610c349dbc7Sjsg return -EINVAL;
1611c349dbc7Sjsg
1612c349dbc7Sjsg hdmi_avi_infoframe_init(frame);
1613c349dbc7Sjsg
1614c349dbc7Sjsg ptr += HDMI_INFOFRAME_HEADER_SIZE;
1615c349dbc7Sjsg
1616c349dbc7Sjsg frame->colorspace = (ptr[0] >> 5) & 0x3;
1617c349dbc7Sjsg if (ptr[0] & 0x10)
1618c349dbc7Sjsg frame->active_aspect = ptr[1] & 0xf;
1619c349dbc7Sjsg if (ptr[0] & 0x8) {
1620c349dbc7Sjsg frame->top_bar = (ptr[6] << 8) | ptr[5];
1621c349dbc7Sjsg frame->bottom_bar = (ptr[8] << 8) | ptr[7];
1622c349dbc7Sjsg }
1623c349dbc7Sjsg if (ptr[0] & 0x4) {
1624c349dbc7Sjsg frame->left_bar = (ptr[10] << 8) | ptr[9];
1625c349dbc7Sjsg frame->right_bar = (ptr[12] << 8) | ptr[11];
1626c349dbc7Sjsg }
1627c349dbc7Sjsg frame->scan_mode = ptr[0] & 0x3;
1628c349dbc7Sjsg
1629c349dbc7Sjsg frame->colorimetry = (ptr[1] >> 6) & 0x3;
1630c349dbc7Sjsg frame->picture_aspect = (ptr[1] >> 4) & 0x3;
1631c349dbc7Sjsg frame->active_aspect = ptr[1] & 0xf;
1632c349dbc7Sjsg
1633c349dbc7Sjsg frame->itc = ptr[2] & 0x80 ? true : false;
1634c349dbc7Sjsg frame->extended_colorimetry = (ptr[2] >> 4) & 0x7;
1635c349dbc7Sjsg frame->quantization_range = (ptr[2] >> 2) & 0x3;
1636c349dbc7Sjsg frame->nups = ptr[2] & 0x3;
1637c349dbc7Sjsg
1638c349dbc7Sjsg frame->video_code = ptr[3] & 0x7f;
1639c349dbc7Sjsg frame->ycc_quantization_range = (ptr[4] >> 6) & 0x3;
1640c349dbc7Sjsg frame->content_type = (ptr[4] >> 4) & 0x3;
1641c349dbc7Sjsg
1642c349dbc7Sjsg frame->pixel_repeat = ptr[4] & 0xf;
1643c349dbc7Sjsg
1644c349dbc7Sjsg return 0;
1645c349dbc7Sjsg }
1646c349dbc7Sjsg
1647c349dbc7Sjsg /**
1648c349dbc7Sjsg * hdmi_spd_infoframe_unpack() - unpack binary buffer to a HDMI SPD infoframe
1649c349dbc7Sjsg * @frame: HDMI SPD infoframe
1650c349dbc7Sjsg * @buffer: source buffer
1651c349dbc7Sjsg * @size: size of buffer
1652c349dbc7Sjsg *
1653c349dbc7Sjsg * Unpacks the information contained in binary @buffer into a structured
1654c349dbc7Sjsg * @frame of the HDMI Source Product Description (SPD) information frame.
1655c349dbc7Sjsg * Also verifies the checksum as required by section 5.3.5 of the HDMI 1.4
1656c349dbc7Sjsg * specification.
1657c349dbc7Sjsg *
1658c349dbc7Sjsg * Returns 0 on success or a negative error code on failure.
1659c349dbc7Sjsg */
hdmi_spd_infoframe_unpack(struct hdmi_spd_infoframe * frame,const void * buffer,size_t size)1660c349dbc7Sjsg static int hdmi_spd_infoframe_unpack(struct hdmi_spd_infoframe *frame,
1661c349dbc7Sjsg const void *buffer, size_t size)
1662c349dbc7Sjsg {
1663c349dbc7Sjsg const u8 *ptr = buffer;
1664c349dbc7Sjsg int ret;
1665c349dbc7Sjsg
1666c349dbc7Sjsg if (size < HDMI_INFOFRAME_SIZE(SPD))
1667c349dbc7Sjsg return -EINVAL;
1668c349dbc7Sjsg
1669c349dbc7Sjsg if (ptr[0] != HDMI_INFOFRAME_TYPE_SPD ||
1670c349dbc7Sjsg ptr[1] != 1 ||
1671c349dbc7Sjsg ptr[2] != HDMI_SPD_INFOFRAME_SIZE) {
1672c349dbc7Sjsg return -EINVAL;
1673c349dbc7Sjsg }
1674c349dbc7Sjsg
1675c349dbc7Sjsg if (hdmi_infoframe_checksum(buffer, HDMI_INFOFRAME_SIZE(SPD)) != 0)
1676c349dbc7Sjsg return -EINVAL;
1677c349dbc7Sjsg
1678c349dbc7Sjsg ptr += HDMI_INFOFRAME_HEADER_SIZE;
1679c349dbc7Sjsg
1680c349dbc7Sjsg ret = hdmi_spd_infoframe_init(frame, ptr, ptr + 8);
1681c349dbc7Sjsg if (ret)
1682c349dbc7Sjsg return ret;
1683c349dbc7Sjsg
1684c349dbc7Sjsg frame->sdi = ptr[24];
1685c349dbc7Sjsg
1686c349dbc7Sjsg return 0;
1687c349dbc7Sjsg }
1688c349dbc7Sjsg
1689c349dbc7Sjsg /**
1690c349dbc7Sjsg * hdmi_audio_infoframe_unpack() - unpack binary buffer to a HDMI AUDIO infoframe
1691c349dbc7Sjsg * @frame: HDMI Audio infoframe
1692c349dbc7Sjsg * @buffer: source buffer
1693c349dbc7Sjsg * @size: size of buffer
1694c349dbc7Sjsg *
1695c349dbc7Sjsg * Unpacks the information contained in binary @buffer into a structured
1696c349dbc7Sjsg * @frame of the HDMI Audio information frame.
1697c349dbc7Sjsg * Also verifies the checksum as required by section 5.3.5 of the HDMI 1.4
1698c349dbc7Sjsg * specification.
1699c349dbc7Sjsg *
1700c349dbc7Sjsg * Returns 0 on success or a negative error code on failure.
1701c349dbc7Sjsg */
hdmi_audio_infoframe_unpack(struct hdmi_audio_infoframe * frame,const void * buffer,size_t size)1702c349dbc7Sjsg static int hdmi_audio_infoframe_unpack(struct hdmi_audio_infoframe *frame,
1703c349dbc7Sjsg const void *buffer, size_t size)
1704c349dbc7Sjsg {
1705c349dbc7Sjsg const u8 *ptr = buffer;
1706c349dbc7Sjsg int ret;
1707c349dbc7Sjsg
1708c349dbc7Sjsg if (size < HDMI_INFOFRAME_SIZE(AUDIO))
1709c349dbc7Sjsg return -EINVAL;
1710c349dbc7Sjsg
1711c349dbc7Sjsg if (ptr[0] != HDMI_INFOFRAME_TYPE_AUDIO ||
1712c349dbc7Sjsg ptr[1] != 1 ||
1713c349dbc7Sjsg ptr[2] != HDMI_AUDIO_INFOFRAME_SIZE) {
1714c349dbc7Sjsg return -EINVAL;
1715c349dbc7Sjsg }
1716c349dbc7Sjsg
1717c349dbc7Sjsg if (hdmi_infoframe_checksum(buffer, HDMI_INFOFRAME_SIZE(AUDIO)) != 0)
1718c349dbc7Sjsg return -EINVAL;
1719c349dbc7Sjsg
1720c349dbc7Sjsg ret = hdmi_audio_infoframe_init(frame);
1721c349dbc7Sjsg if (ret)
1722c349dbc7Sjsg return ret;
1723c349dbc7Sjsg
1724c349dbc7Sjsg ptr += HDMI_INFOFRAME_HEADER_SIZE;
1725c349dbc7Sjsg
1726c349dbc7Sjsg frame->channels = ptr[0] & 0x7;
1727c349dbc7Sjsg frame->coding_type = (ptr[0] >> 4) & 0xf;
1728c349dbc7Sjsg frame->sample_size = ptr[1] & 0x3;
1729c349dbc7Sjsg frame->sample_frequency = (ptr[1] >> 2) & 0x7;
1730c349dbc7Sjsg frame->coding_type_ext = ptr[2] & 0x1f;
1731c349dbc7Sjsg frame->channel_allocation = ptr[3];
1732c349dbc7Sjsg frame->level_shift_value = (ptr[4] >> 3) & 0xf;
1733c349dbc7Sjsg frame->downmix_inhibit = ptr[4] & 0x80 ? true : false;
1734c349dbc7Sjsg
1735c349dbc7Sjsg return 0;
1736c349dbc7Sjsg }
1737c349dbc7Sjsg
1738c349dbc7Sjsg /**
17395ca02815Sjsg * hdmi_vendor_any_infoframe_unpack() - unpack binary buffer to a HDMI
17405ca02815Sjsg * vendor infoframe
1741c349dbc7Sjsg * @frame: HDMI Vendor infoframe
1742c349dbc7Sjsg * @buffer: source buffer
1743c349dbc7Sjsg * @size: size of buffer
1744c349dbc7Sjsg *
1745c349dbc7Sjsg * Unpacks the information contained in binary @buffer into a structured
1746c349dbc7Sjsg * @frame of the HDMI Vendor information frame.
1747c349dbc7Sjsg * Also verifies the checksum as required by section 5.3.5 of the HDMI 1.4
1748c349dbc7Sjsg * specification.
1749c349dbc7Sjsg *
1750c349dbc7Sjsg * Returns 0 on success or a negative error code on failure.
1751c349dbc7Sjsg */
1752c349dbc7Sjsg static int
hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe * frame,const void * buffer,size_t size)1753c349dbc7Sjsg hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
1754c349dbc7Sjsg const void *buffer, size_t size)
1755c349dbc7Sjsg {
1756c349dbc7Sjsg const u8 *ptr = buffer;
1757c349dbc7Sjsg size_t length;
1758c349dbc7Sjsg int ret;
1759c349dbc7Sjsg u8 hdmi_video_format;
1760c349dbc7Sjsg struct hdmi_vendor_infoframe *hvf = &frame->hdmi;
1761c349dbc7Sjsg
1762c349dbc7Sjsg if (size < HDMI_INFOFRAME_HEADER_SIZE)
1763c349dbc7Sjsg return -EINVAL;
1764c349dbc7Sjsg
1765c349dbc7Sjsg if (ptr[0] != HDMI_INFOFRAME_TYPE_VENDOR ||
1766c349dbc7Sjsg ptr[1] != 1 ||
1767c349dbc7Sjsg (ptr[2] != 4 && ptr[2] != 5 && ptr[2] != 6))
1768c349dbc7Sjsg return -EINVAL;
1769c349dbc7Sjsg
1770c349dbc7Sjsg length = ptr[2];
1771c349dbc7Sjsg
1772c349dbc7Sjsg if (size < HDMI_INFOFRAME_HEADER_SIZE + length)
1773c349dbc7Sjsg return -EINVAL;
1774c349dbc7Sjsg
1775c349dbc7Sjsg if (hdmi_infoframe_checksum(buffer,
1776c349dbc7Sjsg HDMI_INFOFRAME_HEADER_SIZE + length) != 0)
1777c349dbc7Sjsg return -EINVAL;
1778c349dbc7Sjsg
1779c349dbc7Sjsg ptr += HDMI_INFOFRAME_HEADER_SIZE;
1780c349dbc7Sjsg
1781c349dbc7Sjsg /* HDMI OUI */
1782c349dbc7Sjsg if ((ptr[0] != 0x03) ||
1783c349dbc7Sjsg (ptr[1] != 0x0c) ||
1784c349dbc7Sjsg (ptr[2] != 0x00))
1785c349dbc7Sjsg return -EINVAL;
1786c349dbc7Sjsg
1787c349dbc7Sjsg hdmi_video_format = ptr[3] >> 5;
1788c349dbc7Sjsg
1789c349dbc7Sjsg if (hdmi_video_format > 0x2)
1790c349dbc7Sjsg return -EINVAL;
1791c349dbc7Sjsg
1792c349dbc7Sjsg ret = hdmi_vendor_infoframe_init(hvf);
1793c349dbc7Sjsg if (ret)
1794c349dbc7Sjsg return ret;
1795c349dbc7Sjsg
1796c349dbc7Sjsg hvf->length = length;
1797c349dbc7Sjsg
1798c349dbc7Sjsg if (hdmi_video_format == 0x2) {
1799c349dbc7Sjsg if (length != 5 && length != 6)
1800c349dbc7Sjsg return -EINVAL;
1801c349dbc7Sjsg hvf->s3d_struct = ptr[4] >> 4;
1802c349dbc7Sjsg if (hvf->s3d_struct >= HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF) {
1803c349dbc7Sjsg if (length != 6)
1804c349dbc7Sjsg return -EINVAL;
1805c349dbc7Sjsg hvf->s3d_ext_data = ptr[5] >> 4;
1806c349dbc7Sjsg }
1807c349dbc7Sjsg } else if (hdmi_video_format == 0x1) {
1808c349dbc7Sjsg if (length != 5)
1809c349dbc7Sjsg return -EINVAL;
1810c349dbc7Sjsg hvf->vic = ptr[4];
1811c349dbc7Sjsg } else {
1812c349dbc7Sjsg if (length != 4)
1813c349dbc7Sjsg return -EINVAL;
1814c349dbc7Sjsg }
1815c349dbc7Sjsg
1816c349dbc7Sjsg return 0;
1817c349dbc7Sjsg }
1818c349dbc7Sjsg
1819c349dbc7Sjsg /**
1820ad8b1aafSjsg * hdmi_drm_infoframe_unpack_only() - unpack binary buffer of CTA-861-G DRM
1821ad8b1aafSjsg * infoframe DataBytes to a HDMI DRM
1822ad8b1aafSjsg * infoframe
1823c349dbc7Sjsg * @frame: HDMI DRM infoframe
1824c349dbc7Sjsg * @buffer: source buffer
1825c349dbc7Sjsg * @size: size of buffer
1826c349dbc7Sjsg *
1827ad8b1aafSjsg * Unpacks CTA-861-G DRM infoframe DataBytes contained in the binary @buffer
1828ad8b1aafSjsg * into a structured @frame of the HDMI Dynamic Range and Mastering (DRM)
1829ad8b1aafSjsg * infoframe.
1830c349dbc7Sjsg *
1831c349dbc7Sjsg * Returns 0 on success or a negative error code on failure.
1832c349dbc7Sjsg */
hdmi_drm_infoframe_unpack_only(struct hdmi_drm_infoframe * frame,const void * buffer,size_t size)1833ad8b1aafSjsg int hdmi_drm_infoframe_unpack_only(struct hdmi_drm_infoframe *frame,
1834c349dbc7Sjsg const void *buffer, size_t size)
1835c349dbc7Sjsg {
1836c349dbc7Sjsg const u8 *ptr = buffer;
1837c349dbc7Sjsg const u8 *temp;
1838c349dbc7Sjsg u8 x_lsb, x_msb;
1839c349dbc7Sjsg u8 y_lsb, y_msb;
1840c349dbc7Sjsg int ret;
1841c349dbc7Sjsg int i;
1842c349dbc7Sjsg
1843ad8b1aafSjsg if (size < HDMI_DRM_INFOFRAME_SIZE)
1844c349dbc7Sjsg return -EINVAL;
1845c349dbc7Sjsg
1846c349dbc7Sjsg ret = hdmi_drm_infoframe_init(frame);
1847c349dbc7Sjsg if (ret)
1848c349dbc7Sjsg return ret;
1849c349dbc7Sjsg
1850c349dbc7Sjsg frame->eotf = ptr[0] & 0x7;
1851c349dbc7Sjsg frame->metadata_type = ptr[1] & 0x7;
1852c349dbc7Sjsg
1853c349dbc7Sjsg temp = ptr + 2;
1854c349dbc7Sjsg for (i = 0; i < 3; i++) {
1855c349dbc7Sjsg x_lsb = *temp++;
1856c349dbc7Sjsg x_msb = *temp++;
1857c349dbc7Sjsg frame->display_primaries[i].x = (x_msb << 8) | x_lsb;
1858c349dbc7Sjsg y_lsb = *temp++;
1859c349dbc7Sjsg y_msb = *temp++;
1860c349dbc7Sjsg frame->display_primaries[i].y = (y_msb << 8) | y_lsb;
1861c349dbc7Sjsg }
1862c349dbc7Sjsg
1863c349dbc7Sjsg frame->white_point.x = (ptr[15] << 8) | ptr[14];
1864c349dbc7Sjsg frame->white_point.y = (ptr[17] << 8) | ptr[16];
1865c349dbc7Sjsg
1866c349dbc7Sjsg frame->max_display_mastering_luminance = (ptr[19] << 8) | ptr[18];
1867c349dbc7Sjsg frame->min_display_mastering_luminance = (ptr[21] << 8) | ptr[20];
1868c349dbc7Sjsg frame->max_cll = (ptr[23] << 8) | ptr[22];
1869c349dbc7Sjsg frame->max_fall = (ptr[25] << 8) | ptr[24];
1870c349dbc7Sjsg
1871c349dbc7Sjsg return 0;
1872c349dbc7Sjsg }
1873ad8b1aafSjsg EXPORT_SYMBOL(hdmi_drm_infoframe_unpack_only);
1874ad8b1aafSjsg
1875ad8b1aafSjsg /**
1876ad8b1aafSjsg * hdmi_drm_infoframe_unpack() - unpack binary buffer to a HDMI DRM infoframe
1877ad8b1aafSjsg * @frame: HDMI DRM infoframe
1878ad8b1aafSjsg * @buffer: source buffer
1879ad8b1aafSjsg * @size: size of buffer
1880ad8b1aafSjsg *
1881ad8b1aafSjsg * Unpacks the CTA-861-G DRM infoframe contained in the binary @buffer into
1882ad8b1aafSjsg * a structured @frame of the HDMI Dynamic Range and Mastering (DRM)
1883ad8b1aafSjsg * infoframe. It also verifies the checksum as required by section 5.3.5 of
1884ad8b1aafSjsg * the HDMI 1.4 specification.
1885ad8b1aafSjsg *
1886ad8b1aafSjsg * Returns 0 on success or a negative error code on failure.
1887ad8b1aafSjsg */
hdmi_drm_infoframe_unpack(struct hdmi_drm_infoframe * frame,const void * buffer,size_t size)1888ad8b1aafSjsg static int hdmi_drm_infoframe_unpack(struct hdmi_drm_infoframe *frame,
1889ad8b1aafSjsg const void *buffer, size_t size)
1890ad8b1aafSjsg {
1891ad8b1aafSjsg const u8 *ptr = buffer;
1892ad8b1aafSjsg int ret;
1893ad8b1aafSjsg
1894ad8b1aafSjsg if (size < HDMI_INFOFRAME_SIZE(DRM))
1895ad8b1aafSjsg return -EINVAL;
1896ad8b1aafSjsg
1897ad8b1aafSjsg if (ptr[0] != HDMI_INFOFRAME_TYPE_DRM ||
1898ad8b1aafSjsg ptr[1] != 1 ||
1899ad8b1aafSjsg ptr[2] != HDMI_DRM_INFOFRAME_SIZE)
1900ad8b1aafSjsg return -EINVAL;
1901ad8b1aafSjsg
1902ad8b1aafSjsg if (hdmi_infoframe_checksum(buffer, HDMI_INFOFRAME_SIZE(DRM)) != 0)
1903ad8b1aafSjsg return -EINVAL;
1904ad8b1aafSjsg
1905ad8b1aafSjsg ret = hdmi_drm_infoframe_unpack_only(frame, ptr + HDMI_INFOFRAME_HEADER_SIZE,
1906ad8b1aafSjsg size - HDMI_INFOFRAME_HEADER_SIZE);
1907ad8b1aafSjsg return ret;
1908ad8b1aafSjsg }
1909c349dbc7Sjsg
1910c349dbc7Sjsg /**
1911c349dbc7Sjsg * hdmi_infoframe_unpack() - unpack binary buffer to a HDMI infoframe
1912c349dbc7Sjsg * @frame: HDMI infoframe
1913c349dbc7Sjsg * @buffer: source buffer
1914c349dbc7Sjsg * @size: size of buffer
1915c349dbc7Sjsg *
1916c349dbc7Sjsg * Unpacks the information contained in binary buffer @buffer into a structured
1917c349dbc7Sjsg * @frame of a HDMI infoframe.
1918c349dbc7Sjsg * Also verifies the checksum as required by section 5.3.5 of the HDMI 1.4
1919c349dbc7Sjsg * specification.
1920c349dbc7Sjsg *
1921c349dbc7Sjsg * Returns 0 on success or a negative error code on failure.
1922c349dbc7Sjsg */
hdmi_infoframe_unpack(union hdmi_infoframe * frame,const void * buffer,size_t size)1923c349dbc7Sjsg int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
1924c349dbc7Sjsg const void *buffer, size_t size)
1925c349dbc7Sjsg {
1926c349dbc7Sjsg int ret;
1927c349dbc7Sjsg const u8 *ptr = buffer;
1928c349dbc7Sjsg
1929c349dbc7Sjsg if (size < HDMI_INFOFRAME_HEADER_SIZE)
1930c349dbc7Sjsg return -EINVAL;
1931c349dbc7Sjsg
1932c349dbc7Sjsg switch (ptr[0]) {
1933c349dbc7Sjsg case HDMI_INFOFRAME_TYPE_AVI:
1934c349dbc7Sjsg ret = hdmi_avi_infoframe_unpack(&frame->avi, buffer, size);
1935c349dbc7Sjsg break;
1936c349dbc7Sjsg case HDMI_INFOFRAME_TYPE_DRM:
1937c349dbc7Sjsg ret = hdmi_drm_infoframe_unpack(&frame->drm, buffer, size);
1938c349dbc7Sjsg break;
1939c349dbc7Sjsg case HDMI_INFOFRAME_TYPE_SPD:
1940c349dbc7Sjsg ret = hdmi_spd_infoframe_unpack(&frame->spd, buffer, size);
1941c349dbc7Sjsg break;
1942c349dbc7Sjsg case HDMI_INFOFRAME_TYPE_AUDIO:
1943c349dbc7Sjsg ret = hdmi_audio_infoframe_unpack(&frame->audio, buffer, size);
1944c349dbc7Sjsg break;
1945c349dbc7Sjsg case HDMI_INFOFRAME_TYPE_VENDOR:
1946c349dbc7Sjsg ret = hdmi_vendor_any_infoframe_unpack(&frame->vendor, buffer, size);
1947c349dbc7Sjsg break;
1948c349dbc7Sjsg default:
1949c349dbc7Sjsg ret = -EINVAL;
1950c349dbc7Sjsg break;
1951c349dbc7Sjsg }
1952c349dbc7Sjsg
1953c349dbc7Sjsg return ret;
1954c349dbc7Sjsg }
1955c349dbc7Sjsg EXPORT_SYMBOL(hdmi_infoframe_unpack);
1956