From patchwork Wed Sep 12 17:47:15 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Damien Lespiau X-Patchwork-Id: 1445861 Return-Path: X-Original-To: patchwork-intel-gfx@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork2.kernel.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by patchwork2.kernel.org (Postfix) with ESMTP id E93A6DF238 for ; Wed, 12 Sep 2012 17:52:41 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id EA3339E9CD for ; Wed, 12 Sep 2012 10:52:41 -0700 (PDT) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from mail-wi0-f177.google.com (mail-wi0-f177.google.com [209.85.212.177]) by gabe.freedesktop.org (Postfix) with ESMTP id 8F0AF9E872; Wed, 12 Sep 2012 10:47:45 -0700 (PDT) Received: by wibhn17 with SMTP id hn17so1926205wib.12 for ; Wed, 12 Sep 2012 10:47:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:subject:date:message-id:x-mailer:in-reply-to:references; bh=KtaUpWRDM8ZxOHbLmmXuii6qHAZh6du40WqL0hmi0vs=; b=DJh5PfOFn3lGqdNYJdZlQ+4osresx6JTruGGcx4+WMkehp69pn+R6PZSPndRXe+xJe iJsSse2m0cPl2+S7/AEuTR+oWk/U98ovBHC5T6DvyeZUpyF0SJyDt3kuCTLLwhDPx5co qaMBeRCdQmxC/a/oSJMQ3XFozCs6TWnc92J+wy8qBz7Wh/XdYGkV7IzLb/zkeaOUfYOc qmVmjNc6CnSJGos8kfre0lB771cXkltf3D/SwBoUF3WNVUR2D0AlltgFP5t0b07bnpgV nGdgXjP+Tn7Si0sciiXjm47DF8Kw7KbatjEwyfhnHK+TBURbx3qV/SBpoS8jS4TgndnA 1laQ== Received: by 10.180.81.193 with SMTP id c1mr34345688wiy.12.1347472064560; Wed, 12 Sep 2012 10:47:44 -0700 (PDT) Received: from localhost.localdomain ([83.217.123.106]) by mx.google.com with ESMTPS id do5sm13660675wib.10.2012.09.12.10.47.43 (version=TLSv1/SSLv3 cipher=OTHER); Wed, 12 Sep 2012 10:47:43 -0700 (PDT) From: Damien Lespiau To: intel-gfx@lists.freedesktop.org, dri-devel@lists.freedesktop.org Date: Wed, 12 Sep 2012 18:47:15 +0100 Message-Id: <1347472035-2816-4-git-send-email-damien.lespiau@gmail.com> X-Mailer: git-send-email 1.7.11.4 In-Reply-To: <1347472035-2816-1-git-send-email-damien.lespiau@gmail.com> References: <1347472035-2816-1-git-send-email-damien.lespiau@gmail.com> Subject: [Intel-gfx] [PATCH 3/3] drm/i915: Add HDMI vendor info frame support X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.13 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: intel-gfx-bounces+patchwork-intel-gfx=patchwork.kernel.org@lists.freedesktop.org Errors-To: intel-gfx-bounces+patchwork-intel-gfx=patchwork.kernel.org@lists.freedesktop.org From: Damien Lespiau When scanning out a 3D framebuffer, send the corresponding infoframe to the HDMI sink. See http://www.hdmi.org/manufacturer/specification.aspx for details. Signed-off-by: Damien Lespiau --- drivers/gpu/drm/i915/intel_drv.h | 14 ++++++++ drivers/gpu/drm/i915/intel_hdmi.c | 71 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 84 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index cd54cf8..76d488e 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -263,6 +263,13 @@ struct cxsr_latency { #define DIP_SPD_BD 0xa #define DIP_SPD_SCD 0xb +#define DIP_TYPE_VENDOR 0x81 +#define DIP_VERSION_VENDOR 0x1 +#define DIP_HDMI_3D_PRESENT (0x2<<4) +#define DIP_HDMI_3D_STRUCT_FP (0x0<<4) +#define DIP_HDMI_3D_STRUCT_TB (0x6<<4) +#define DIP_HDMI_3D_STRUCT_SBSH (0x8<<4) + struct dip_infoframe { uint8_t type; /* HB0 */ uint8_t ver; /* HB1 */ @@ -292,6 +299,12 @@ struct dip_infoframe { uint8_t pd[16]; uint8_t sdi; } __attribute__ ((packed)) spd; + struct { + uint8_t vendor_id[3]; + uint8_t video_format; + uint8_t s3d_struct; + uint8_t s3d_ext_data; + } __attribute__ ((packed)) hdmi; uint8_t payload[27]; } __attribute__ ((packed)) body; } __attribute__((packed)); @@ -305,6 +318,7 @@ struct intel_hdmi { bool has_hdmi_sink; bool has_audio; enum hdmi_force_audio force_audio; + unsigned int s3d_mode; void (*write_infoframe)(struct drm_encoder *encoder, struct dip_infoframe *frame); void (*set_infoframes)(struct drm_encoder *encoder, diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 98f6024..ab0553d 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -83,6 +83,8 @@ static u32 g4x_infoframe_index(struct dip_infoframe *frame) return VIDEO_DIP_SELECT_AVI; case DIP_TYPE_SPD: return VIDEO_DIP_SELECT_SPD; + case DIP_TYPE_VENDOR: + return VIDEO_DIP_SELECT_VENDOR; default: DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type); return 0; @@ -96,6 +98,8 @@ static u32 g4x_infoframe_enable(struct dip_infoframe *frame) return VIDEO_DIP_ENABLE_AVI; case DIP_TYPE_SPD: return VIDEO_DIP_ENABLE_SPD; + case DIP_TYPE_VENDOR: + return VIDEO_DIP_ENABLE_VENDOR; default: DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type); return 0; @@ -338,6 +342,51 @@ static void intel_hdmi_set_spd_infoframe(struct drm_encoder *encoder) intel_set_infoframe(encoder, &spd_if); } +static void intel_hdmi_set_hdmi_infoframe(struct drm_encoder *encoder) +{ + struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); + struct dip_infoframe hdmi_if; + + /* We really only need to send a HDMI vendor info frame when having + * a 3D format to describe */ + if (!intel_hdmi->s3d_mode) + return; + + memset(&hdmi_if, 0, sizeof(hdmi_if)); + hdmi_if.type = DIP_TYPE_VENDOR; + hdmi_if.ver = DIP_VERSION_VENDOR; + /* HDMI IEEE registration id, least significant bit first */ + hdmi_if.body.hdmi.vendor_id[0] = 0x03; + hdmi_if.body.hdmi.vendor_id[1] = 0xc0; + hdmi_if.body.hdmi.vendor_id[2] = 0x00; + hdmi_if.body.hdmi.video_format = DIP_HDMI_3D_PRESENT; + if (intel_hdmi->s3d_mode & DRM_MODE_FLAG_3D_FRAME_PACKING) + hdmi_if.body.hdmi.s3d_struct = DIP_HDMI_3D_STRUCT_FP; + else if (intel_hdmi->s3d_mode & DRM_MODE_FLAG_3D_TOP_BOTTOM) + hdmi_if.body.hdmi.s3d_struct = DIP_HDMI_3D_STRUCT_TB; + else if (intel_hdmi->s3d_mode & DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF) + hdmi_if.body.hdmi.s3d_struct = DIP_HDMI_3D_STRUCT_SBSH; + /* len is the payload len, not including checksum. Side by side (half) + * has an extra byte for 3D_Ext_Data */ + if (intel_hdmi->s3d_mode & DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF) { + hdmi_if.len = 6; + /* SBSH is subsampled by a factor of 2 */ + hdmi_if.body.hdmi.s3d_ext_data = 2 << 4; + } else + hdmi_if.len = 5; + + DRM_DEBUG_DRIVER("3D payload (len %d) %02x %02x %02x %02x %02x %02x\n", + hdmi_if.len, + hdmi_if.body.payload[0], + hdmi_if.body.payload[1], + hdmi_if.body.payload[2], + hdmi_if.body.payload[3], + hdmi_if.body.payload[4], + hdmi_if.body.payload[5]); + + intel_set_infoframe(encoder, &hdmi_if); +} + static void g4x_set_infoframes(struct drm_encoder *encoder, struct drm_display_mode *adjusted_mode) { @@ -398,6 +447,7 @@ static void g4x_set_infoframes(struct drm_encoder *encoder, intel_hdmi_set_avi_infoframe(encoder, adjusted_mode); intel_hdmi_set_spd_infoframe(encoder); + intel_hdmi_set_hdmi_infoframe(encoder); } static void ibx_set_infoframes(struct drm_encoder *encoder, @@ -457,6 +507,7 @@ static void ibx_set_infoframes(struct drm_encoder *encoder, intel_hdmi_set_avi_infoframe(encoder, adjusted_mode); intel_hdmi_set_spd_infoframe(encoder); + intel_hdmi_set_hdmi_infoframe(encoder); } static void cpt_set_infoframes(struct drm_encoder *encoder, @@ -492,6 +543,7 @@ static void cpt_set_infoframes(struct drm_encoder *encoder, intel_hdmi_set_avi_infoframe(encoder, adjusted_mode); intel_hdmi_set_spd_infoframe(encoder); + intel_hdmi_set_hdmi_infoframe(encoder); } static void vlv_set_infoframes(struct drm_encoder *encoder, @@ -526,6 +578,7 @@ static void vlv_set_infoframes(struct drm_encoder *encoder, intel_hdmi_set_avi_infoframe(encoder, adjusted_mode); intel_hdmi_set_spd_infoframe(encoder); + intel_hdmi_set_hdmi_infoframe(encoder); } static void hsw_set_infoframes(struct drm_encoder *encoder, @@ -792,7 +845,8 @@ intel_hdmi_set_property(struct drm_connector *connector, uint64_t val) { struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector); - struct drm_i915_private *dev_priv = connector->dev->dev_private; + struct drm_device *dev = connector->dev; + struct drm_i915_private *dev_priv = dev->dev_private; int ret; ret = drm_connector_property_set_value(connector, property, val); @@ -828,6 +882,15 @@ intel_hdmi_set_property(struct drm_connector *connector, goto done; } + + if (property == dev->mode_config.s3d_select_mode_property) { + if (val == intel_hdmi->s3d_mode) + return 0; + + intel_hdmi->s3d_mode = val; + goto done; + } + return -EINVAL; done: @@ -885,8 +948,14 @@ static const struct drm_encoder_funcs intel_hdmi_enc_funcs = { static void intel_hdmi_add_properties(struct intel_hdmi *intel_hdmi, struct drm_connector *connector) { + struct drm_device *dev = connector->dev; + intel_attach_force_audio_property(connector); intel_attach_broadcast_rgb_property(connector); + drm_mode_create_3d_property(dev); + drm_object_attach_property(&connector->base, + dev->mode_config.s3d_select_mode_property, + 0); } void intel_hdmi_init(struct drm_device *dev, int sdvox_reg)