From patchwork Fri Dec 4 08:35:04 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Enric Balletbo Serra X-Patchwork-Id: 7766141 Return-Path: X-Original-To: patchwork-dri-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id DA65A9F7B5 for ; Fri, 4 Dec 2015 08:35:26 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id AB885204AF for ; Fri, 4 Dec 2015 08:35:25 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by mail.kernel.org (Postfix) with ESMTP id 688EC2041C for ; Fri, 4 Dec 2015 08:35:23 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 7CF928A75E; Fri, 4 Dec 2015 00:35:22 -0800 (PST) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from mail-wm0-f47.google.com (mail-wm0-f47.google.com [74.125.82.47]) by gabe.freedesktop.org (Postfix) with ESMTPS id 930768A75B for ; Fri, 4 Dec 2015 00:35:20 -0800 (PST) Received: by wmuu63 with SMTP id u63so52374777wmu.0 for ; Fri, 04 Dec 2015 00:35:19 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-type:content-transfer-encoding; bh=5hdJPS7XfreumuSoj/9/p8uZ508jSkizIrYQ/W8qLD8=; b=oktD5xX/N5FBPi8cTZ3hVCP0faZk1InqzuGH48956mY1j/JiZCaVBtagCPBdgxBAcB hhhMB7Wr3EREOMZd6Gd94IAs3Qn9LfLbUd+Xoz7WeR7szrpL+WEgQM3CvJSYhKxsXQxD fYua6mdBPenIshsmGW8fLk5FLKm7uD88i0j9Gaqc1U9vlmdUtP7r01AJkhGlxICRnysl E4p3CDCsi9Nq771ns9twPD60CEYyk6ENOnXBbbhpNIvzo3fARw3EmghAcPI8fIyqcM3o 45TMRie6MHCLd0cIpwTge6nv8bPojXDzzzfS/KS7jIsHLDgREH/KorzpOZATDmWysFLt 4NHA== X-Received: by 10.194.142.203 with SMTP id ry11mr15729017wjb.132.1449218119368; Fri, 04 Dec 2015 00:35:19 -0800 (PST) Received: from localhost.localdomain ([84.236.220.225]) by smtp.gmail.com with ESMTPSA id c194sm2456731wmd.13.2015.12.04.00.35.17 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Fri, 04 Dec 2015 00:35:18 -0800 (PST) From: Enric Balletbo i Serra X-Google-Original-From: Enric Balletbo i Serra To: devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, devel@driverdev.osuosl.org, treding@nvidia.com Subject: [PATCHv6 2/5] hdmi: added functions for MPEG InfoFrames Date: Fri, 4 Dec 2015 09:35:04 +0100 Message-Id: <1449218107-6590-3-git-send-email-enric.balletbo@collabora.com> X-Mailer: git-send-email 2.1.0 In-Reply-To: <1449218107-6590-1-git-send-email-enric.balletbo@collabora.com> References: <1449218107-6590-1-git-send-email-enric.balletbo@collabora.com> MIME-Version: 1.0 Cc: mark.rutland@arm.com, drinkcat@chromium.org, laurent.pinchart@ideasonboard.com, pawel.moll@arm.com, ijc+devicetree@hellion.org.uk, gregkh@linuxfoundation.org, emil.l.velikov@gmail.com, cawa.cheng@mediatek.com, jb.tsai@mediatek.com, sjoerd.simons@collabora.co.uk, robh+dt@kernel.org, span@analogixsemi.com, galak@codeaurora.org, javier@dowhile0.org, eddie.huang@mediatek.com, cjiao@analogixsemi.com, dan.carpenter@oracle.com, nathan.chung@mediatek.com X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" X-Spam-Status: No, score=-4.1 required=5.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_MED, T_DKIM_INVALID, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP The MPEG Source (MS) InfoFrame is in EIA/CEA-861B. It describes aspects of the compressed video stream that were used to produce the uncompressed video. The patch adds functions to work with MPEG InfoFrames. Signed-off-by: Enric Balletbo i Serra --- Changes since last version (requested by Thierry Redding) - hdmi_infoframe_pack: Fix missing break - hdmi_mpeg_picture_get_name: return NULL instead of "Reserved" - hdmi_mpeg_picture_get_name: use more canonical names "I-Frame", "P-Frame", etc - hdmi_mpeg_infoframe_unpack: remove braces that aren't needed - hdmi_vendor_any_infoframe: s/mpeg/MPEG/ drivers/video/hdmi.c | 156 +++++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/hdmi.h | 24 ++++++++ 2 files changed, 180 insertions(+) diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c index 1626892..47121a6 100644 --- a/drivers/video/hdmi.c +++ b/drivers/video/hdmi.c @@ -388,6 +388,81 @@ ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame, } EXPORT_SYMBOL(hdmi_vendor_infoframe_pack); +/** + * hdmi_mpeg_infoframe_init() - initialize an HDMI MPEG infoframe + * @frame: HDMI MPEG infoframe + * + * Returns 0 on success or a negative error code on failure. + */ +int hdmi_mpeg_infoframe_init(struct hdmi_mpeg_infoframe *frame) +{ + memset(frame, 0, sizeof(*frame)); + + frame->type = HDMI_INFOFRAME_TYPE_MPEG; + frame->version = 1; + frame->length = HDMI_MPEG_INFOFRAME_SIZE; + + return 0; +} +EXPORT_SYMBOL(hdmi_mpeg_infoframe_init); + +/** + * hdmi_mpeg_infoframe_pack() - write HDMI MPEG infoframe to binary buffer + * @frame: HDMI MPEG 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_mpeg_infoframe_pack(struct hdmi_mpeg_infoframe *frame, + void *buffer, size_t size) +{ + u8 *ptr = buffer; + size_t length; + + 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 */ + + /* start infoframe payload */ + ptr += HDMI_INFOFRAME_HEADER_SIZE; + + /* + * The MPEG Bit Rate is stored as a 32-bit number and is expressed in + * Hertz. MB#0 contains the least significant byte while MB#3 contains + * the most significant byte. If the MPEG Bit Rate is unknown or this + * field doesn’t apply, then all of the bits in Data Bytes 1-4 shall + * be set to 0. + */ + ptr[0] = frame->bitrate & 0x000000ff; + ptr[1] = (frame->bitrate & 0x0000ff00) >> 8; + ptr[2] = (frame->bitrate & 0x00ff0000) >> 16; + ptr[3] = (frame->bitrate & 0xff000000) >> 24; + + ptr[4] = frame->frame_type; + if (frame->repeated) + ptr[4] |= BIT(4); + + hdmi_infoframe_set_checksum(buffer, length); + + return length; +} +EXPORT_SYMBOL(hdmi_mpeg_infoframe_pack); + /* * hdmi_vendor_any_infoframe_pack() - write a vendor infoframe to binary buffer */ @@ -435,6 +510,9 @@ hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size) length = hdmi_vendor_any_infoframe_pack(&frame->vendor, buffer, size); break; + case HDMI_INFOFRAME_TYPE_MPEG: + length = hdmi_mpeg_infoframe_pack(&frame->mpeg, buffer, size); + break; default: WARN(1, "Bad infoframe type %d\n", frame->any.type); length = -EINVAL; @@ -457,6 +535,8 @@ static const char *hdmi_infoframe_type_get_name(enum hdmi_infoframe_type type) return "Source Product Description (SPD)"; case HDMI_INFOFRAME_TYPE_AUDIO: return "Audio"; + case HDMI_INFOFRAME_TYPE_MPEG: + return "MPEG"; } return "Reserved"; } @@ -899,6 +979,41 @@ static void hdmi_audio_infoframe_log(const char *level, frame->downmix_inhibit ? "Yes" : "No"); } +static const char *hdmi_mpeg_picture_get_name(enum hdmi_mpeg_frame_type type) +{ + switch (type) { + case HDMI_MPEG_UNKNOWN_FRAME: + return "Unknown"; + case HDMI_MPEG_I_FRAME: + return "Intra-coded picture"; + case HDMI_MPEG_B_FRAME: + return "Bi-predictive picture"; + case HDMI_MPEG_P_FRAME: + return "Predicted picture"; + } + return NULL; +} + +/** + * hdmi_mpeg_infoframe_log() - log info of HDMI MPEG infoframe + * @level: logging level + * @dev: device + * @frame: HDMI MPEG infoframe + */ +static void hdmi_mpeg_infoframe_log(const char *level, + struct device *dev, + struct hdmi_mpeg_infoframe *frame) +{ + hdmi_infoframe_log_header(level, dev, + (struct hdmi_any_infoframe *)frame); + + hdmi_log(" bit rate: %d Hz\n", frame->bitrate); + hdmi_log(" frame type: %s\n", + hdmi_mpeg_picture_get_name(frame->frame_type)); + hdmi_log(" repeated frame: %s\n", + frame->repeated ? "Yes" : "No"); +} + static const char * hdmi_3d_structure_get_name(enum hdmi_3d_structure s3d_struct) { @@ -987,6 +1102,9 @@ void hdmi_infoframe_log(const char *level, case HDMI_INFOFRAME_TYPE_VENDOR: hdmi_vendor_any_infoframe_log(level, dev, &frame->vendor); break; + case HDMI_INFOFRAME_TYPE_MPEG: + hdmi_mpeg_infoframe_log(level, dev, &frame->mpeg); + break; } } EXPORT_SYMBOL(hdmi_infoframe_log); @@ -1138,6 +1256,41 @@ static int hdmi_audio_infoframe_unpack(struct hdmi_audio_infoframe *frame, } /** + * hdmi_mpeg_infoframe_unpack() - unpack binary buffer to a HDMI MPEG infoframe + * @buffer: source buffer + * @frame: HDMI MPEG infoframe + * + * Unpacks the information contained in binary @buffer into a structured + * @frame of the HDMI MPEG information frame. Also verifies the checksum as + * required by section 5.3.5 of the HDMI 1.4 specification. + * + * Returns 0 on success or a negative error code on failure. + */ +static int hdmi_mpeg_infoframe_unpack(struct hdmi_mpeg_infoframe *frame, + void *buffer) +{ + u8 *ptr = buffer; + + if (ptr[0] != HDMI_INFOFRAME_TYPE_MPEG || + ptr[1] != 1 || + ptr[2] != HDMI_MPEG_INFOFRAME_SIZE) + return -EINVAL; + + if (hdmi_infoframe_checksum(buffer, HDMI_INFOFRAME_SIZE(MPEG)) != 0) + return -EINVAL; + + ptr += HDMI_INFOFRAME_HEADER_SIZE; + + frame->bitrate = (ptr[3] << 24) | (ptr[2] << 16) | + (ptr[1] << 8) | ptr[0]; + + frame->frame_type = ptr[4] & 0x03; + frame->repeated = ptr[4] & BIT(4) ? true : false; + + return 0; +} + +/** * hdmi_vendor_infoframe_unpack() - unpack binary buffer to a HDMI vendor infoframe * @buffer: source buffer * @frame: HDMI Vendor infoframe @@ -1234,6 +1387,9 @@ int hdmi_infoframe_unpack(union hdmi_infoframe *frame, void *buffer) case HDMI_INFOFRAME_TYPE_VENDOR: ret = hdmi_vendor_any_infoframe_unpack(&frame->vendor, buffer); break; + case HDMI_INFOFRAME_TYPE_MPEG: + ret = hdmi_mpeg_infoframe_unpack(&frame->mpeg, buffer); + break; default: ret = -EINVAL; break; diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h index e974420..c033554 100644 --- a/include/linux/hdmi.h +++ b/include/linux/hdmi.h @@ -32,11 +32,13 @@ enum hdmi_infoframe_type { HDMI_INFOFRAME_TYPE_AVI = 0x82, HDMI_INFOFRAME_TYPE_SPD = 0x83, HDMI_INFOFRAME_TYPE_AUDIO = 0x84, + HDMI_INFOFRAME_TYPE_MPEG = 0x85, }; #define HDMI_IEEE_OUI 0x000c03 #define HDMI_INFOFRAME_HEADER_SIZE 4 #define HDMI_AVI_INFOFRAME_SIZE 13 +#define HDMI_MPEG_INFOFRAME_SIZE 10 #define HDMI_SPD_INFOFRAME_SIZE 25 #define HDMI_AUDIO_INFOFRAME_SIZE 10 @@ -297,6 +299,26 @@ int hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame); ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame, void *buffer, size_t size); +enum hdmi_mpeg_frame_type { + HDMI_MPEG_UNKNOWN_FRAME = 0x00, + HDMI_MPEG_I_FRAME = 0x01, + HDMI_MPEG_B_FRAME = 0x02, + HDMI_MPEG_P_FRAME = 0x03, +}; + +struct hdmi_mpeg_infoframe { + enum hdmi_infoframe_type type; + unsigned char version; + unsigned char length; + u32 bitrate; + enum hdmi_mpeg_frame_type frame_type; + bool repeated; +}; + +int hdmi_mpeg_infoframe_init(struct hdmi_mpeg_infoframe *frame); +ssize_t hdmi_mpeg_infoframe_pack(struct hdmi_mpeg_infoframe *frame, + void *buffer, size_t size); + union hdmi_vendor_any_infoframe { struct { enum hdmi_infoframe_type type; @@ -314,6 +336,7 @@ union hdmi_vendor_any_infoframe { * @spd: spd infoframe * @vendor: union of all vendor infoframes * @audio: audio infoframe + * @mpeg: MPEG infoframe * * This is used by the generic pack function. This works since all infoframes * have the same header which also indicates which type of infoframe should be @@ -325,6 +348,7 @@ union hdmi_infoframe { struct hdmi_spd_infoframe spd; union hdmi_vendor_any_infoframe vendor; struct hdmi_audio_infoframe audio; + struct hdmi_mpeg_infoframe mpeg; }; ssize_t