| From 64e96dc8bf364ec5c71bef620b170964fc29173a Mon Sep 17 00:00:00 2001 |
| From: "Lespiau, Damien" <damien.lespiau@intel.com> |
| Date: Mon, 19 Aug 2013 16:58:58 +0100 |
| Subject: video/hdmi: Introduce helpers for the HDMI vendor specific infoframe |
| MIME-Version: 1.0 |
| Content-Type: text/plain; charset=UTF-8 |
| Content-Transfer-Encoding: 8bit |
| |
| Provide the same programming model than the other infoframe types. |
| |
| The generic _pack() function can't handle those yet as we need to move |
| the vendor OUI in the generic hdmi_vendor_infoframe structure to know |
| which kind of vendor infoframe we are dealing with. |
| |
| v2: Fix the value of Side-by-side (half), hmdi typo, pack 3D_Ext_Data |
| (Ville Syrjälä) |
| v3: Future proof the sending of 3D_Ext_Data (Ville Syrjälä), Fix |
| multi-lines comment style (Thierry Reding) |
| |
| Signed-off-by: Damien Lespiau <damien.lespiau@intel.com> |
| Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> |
| Reviewed-by: Thierry Reding <treding@nvidia.com> |
| Signed-off-by: Dave Airlie <airlied@gmail.com> |
| (cherry picked from commit 7d27becb3532d881378846e72864031977be511a) |
| Signed-off-by: Darren Hart <dvhart@linux.intel.com> |
| --- |
| drivers/video/hdmi.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| include/linux/hdmi.h | 26 +++++++++++++++ |
| 2 files changed, 116 insertions(+) |
| |
| diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c |
| index 060337b393db..82c663a8961e 100644 |
| --- a/drivers/video/hdmi.c |
| +++ b/drivers/video/hdmi.c |
| @@ -288,6 +288,96 @@ ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame, |
| EXPORT_SYMBOL(hdmi_audio_infoframe_pack); |
| |
| /** |
| + * hdmi_hdmi_infoframe_init() - initialize an HDMI vendor infoframe |
| + * @frame: HDMI vendor infoframe |
| + * |
| + * Returns 0 on success or a negative error code on failure. |
| + */ |
| +int hdmi_hdmi_infoframe_init(struct hdmi_hdmi_infoframe *frame) |
| +{ |
| + memset(frame, 0, sizeof(*frame)); |
| + |
| + frame->type = HDMI_INFOFRAME_TYPE_VENDOR; |
| + frame->version = 1; |
| + |
| + /* |
| + * 0 is a valid value for s3d_struct, so we use a special "not set" |
| + * value |
| + */ |
| + frame->s3d_struct = HDMI_3D_STRUCTURE_INVALID; |
| + |
| + return 0; |
| +} |
| +EXPORT_SYMBOL(hdmi_hdmi_infoframe_init); |
| + |
| +/** |
| + * hdmi_hdmi_infoframe_pack() - write a HDMI vendor infoframe to binary buffer |
| + * @frame: HDMI infoframe |
| + * @buffer: destination buffer |
| + * @size: size of buffer |
| + * |
| + * Packs the information contained in the @frame structure into a binary |
| + * representation that can be written into the corresponding controller |
| + * registers. Also computes the checksum as required by section 5.3.5 of |
| + * the HDMI 1.4 specification. |
| + * |
| + * Returns the number of bytes packed into the binary buffer or a negative |
| + * error code on failure. |
| + */ |
| +ssize_t hdmi_hdmi_infoframe_pack(struct hdmi_hdmi_infoframe *frame, |
| + void *buffer, size_t size) |
| +{ |
| + u8 *ptr = buffer; |
| + size_t length; |
| + |
| + /* empty info frame */ |
| + if (frame->vic == 0 && frame->s3d_struct == HDMI_3D_STRUCTURE_INVALID) |
| + return -EINVAL; |
| + |
| + /* only one of those can be supplied */ |
| + if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID) |
| + return -EINVAL; |
| + |
| + /* for side by side (half) we also need to provide 3D_Ext_Data */ |
| + if (frame->s3d_struct >= HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF) |
| + frame->length = 6; |
| + else |
| + frame->length = 5; |
| + |
| + length = HDMI_INFOFRAME_HEADER_SIZE + frame->length; |
| + |
| + if (size < length) |
| + return -ENOSPC; |
| + |
| + memset(buffer, 0, size); |
| + |
| + ptr[0] = frame->type; |
| + ptr[1] = frame->version; |
| + ptr[2] = frame->length; |
| + ptr[3] = 0; /* checksum */ |
| + |
| + /* HDMI OUI */ |
| + ptr[4] = 0x03; |
| + ptr[5] = 0x0c; |
| + ptr[6] = 0x00; |
| + |
| + if (frame->vic) { |
| + ptr[7] = 0x1 << 5; /* video format */ |
| + ptr[8] = frame->vic; |
| + } else { |
| + ptr[7] = 0x2 << 5; /* video format */ |
| + ptr[8] = (frame->s3d_struct & 0xf) << 4; |
| + if (frame->s3d_struct >= HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF) |
| + ptr[9] = (frame->s3d_ext_data & 0xf) << 4; |
| + } |
| + |
| + hdmi_infoframe_checksum(buffer, length); |
| + |
| + return length; |
| +} |
| +EXPORT_SYMBOL(hdmi_hdmi_infoframe_pack); |
| + |
| +/** |
| * hdmi_vendor_infoframe_pack() - write a HDMI vendor infoframe to binary |
| * buffer |
| * @frame: HDMI vendor infoframe |
| diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h |
| index b98340b82e05..e733252c2b5d 100644 |
| --- a/include/linux/hdmi.h |
| +++ b/include/linux/hdmi.h |
| @@ -234,11 +234,37 @@ struct hdmi_vendor_infoframe { |
| ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame, |
| void *buffer, size_t size); |
| |
| +enum hdmi_3d_structure { |
| + HDMI_3D_STRUCTURE_INVALID = -1, |
| + HDMI_3D_STRUCTURE_FRAME_PACKING = 0, |
| + HDMI_3D_STRUCTURE_FIELD_ALTERNATIVE, |
| + HDMI_3D_STRUCTURE_LINE_ALTERNATIVE, |
| + HDMI_3D_STRUCTURE_SIDE_BY_SIDE_FULL, |
| + HDMI_3D_STRUCTURE_L_DEPTH, |
| + HDMI_3D_STRUCTURE_L_DEPTH_GFX_GFX_DEPTH, |
| + HDMI_3D_STRUCTURE_TOP_AND_BOTTOM, |
| + HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF = 8, |
| +}; |
| + |
| +struct hdmi_hdmi_infoframe { |
| + enum hdmi_infoframe_type type; |
| + unsigned char version; |
| + unsigned char length; |
| + u8 vic; |
| + enum hdmi_3d_structure s3d_struct; |
| + unsigned int s3d_ext_data; |
| +}; |
| + |
| +int hdmi_hdmi_infoframe_init(struct hdmi_hdmi_infoframe *frame); |
| +ssize_t hdmi_hdmi_infoframe_pack(struct hdmi_hdmi_infoframe *frame, |
| + void *buffer, size_t size); |
| + |
| union hdmi_infoframe { |
| struct hdmi_any_infoframe any; |
| struct hdmi_avi_infoframe avi; |
| struct hdmi_spd_infoframe spd; |
| struct hdmi_vendor_infoframe vendor; |
| + struct hdmi_hdmi_infoframe hdmi; |
| struct hdmi_audio_infoframe audio; |
| }; |
| |
| -- |
| 1.8.5.rc3 |
| |