From patchwork Thu Sep 9 21:00:01 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?b?RGF2aWQgSMODwqRyZGVtYW4=?= X-Patchwork-Id: 165501 Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id o89L0SoV025730 for ; Thu, 9 Sep 2010 21:01:04 GMT Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 58FE09E84C for ; Thu, 9 Sep 2010 14:00:28 -0700 (PDT) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from palpatine.hardeman.nu (1-1-12-13a.han.sth.bostream.se [82.182.30.168]) by gabe.freedesktop.org (Postfix) with ESMTP id A9BBA9E78B for ; Thu, 9 Sep 2010 14:00:06 -0700 (PDT) Received: from basil.haag.hardeman.nu (host-88-217-225-61.customer.m-online.net [88.217.225.61]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by palpatine.hardeman.nu (Postfix) with ESMTPSA id B5E82165D; Thu, 9 Sep 2010 23:00:03 +0200 (CEST) Received: by basil.haag.hardeman.nu (Postfix, from userid 1000) id 4584D1A05B4; Thu, 9 Sep 2010 23:00:01 +0200 (CEST) To: intel-gfx@lists.freedesktop.org From: David =?utf-8?b?SMOkcmRlbWFu?= Date: Thu, 09 Sep 2010 23:00:01 +0200 Message-ID: <20100909210001.11985.1244.stgit@localhost.localdomain> User-Agent: StGit/0.15 MIME-Version: 1.0 Cc: jesse.barnes@intel.com Subject: [Intel-gfx] [PATCH] i915: enable AVI infoframe for intel_hdmi.c [v2] X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.11 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , 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 X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter1.kernel.org [140.211.167.41]); Thu, 09 Sep 2010 21:01:04 +0000 (UTC) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 67e3ec1..6c2d9a6 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1330,6 +1330,22 @@ #define LVDS_B0B3_POWER_DOWN (0 << 2) #define LVDS_B0B3_POWER_UP (3 << 2) +/* Video Data Island Packet control */ +#define VIDEO_DIP_DATA 0x61178 +#define VIDEO_DIP_CTL 0x61170 +#define VIDEO_DIP_ENABLE (1 << 31) +#define VIDEO_DIP_PORT_B (1 << 29) +#define VIDEO_DIP_PORT_C (2 << 29) +#define VIDEO_DIP_ENABLE_AVI (1 << 21) +#define VIDEO_DIP_ENABLE_VENDOR (2 << 21) +#define VIDEO_DIP_ENABLE_SPD (8 << 21) +#define VIDEO_DIP_SELECT_AVI (0 << 19) +#define VIDEO_DIP_SELECT_VENDOR (1 << 19) +#define VIDEO_DIP_SELECT_SPD (3 << 19) +#define VIDEO_DIP_FREQ_ONCE (0 << 16) +#define VIDEO_DIP_FREQ_VSYNC (1 << 16) +#define VIDEO_DIP_FREQ_2VSYNC (2 << 16) + /* Panel power sequencing */ #define PP_STATUS 0x61200 #define PP_ON (1 << 31) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 0e92aa0..f5808e7 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -176,6 +176,30 @@ struct intel_crtc { #define enc_to_intel_encoder(x) container_of(x, struct intel_encoder, enc) #define to_intel_framebuffer(x) container_of(x, struct intel_framebuffer, base) +#define DIP_TYPE_AVI 0x82 +#define DIP_VERSION_AVI 0x2 +#define DIP_LEN_AVI 13 + +struct dip_infoframe { + uint8_t type; /* HB0 */ + uint8_t ver; /* HB1 */ + uint8_t len; /* HB2 - body len, not including checksum */ + uint8_t ecc; /* HW specific, not part of the infoframe */ + uint8_t checksum; /* PB0 */ + uint8_t Y_A_B_S; /* PB1 - Y 6:5, A 4:4, B 3:2, S 1:0 */ + uint8_t C_M_R; /* PB2 - C 7:6, M 5:4, R 3:0 */ + uint8_t ITC_EC_Q_SC; /* PB3 - ITC 7:7, EC 6:4, Q 3:2, SC 1:0 */ + uint8_t VIC; /* PB4 - VIC 6:0 */ + uint8_t PR; /* PB5 - PR 3:0 */ + /* PB6 - PB13 */ + uint16_t top_bar_end; + uint16_t bottom_bar_start; + uint16_t left_bar_end; + uint16_t right_bar_start; + /* Pad to 32-bit */ + uint16_t padding; +} __attribute__((packed)); + struct i2c_adapter *intel_i2c_create(struct drm_device *dev, const u32 reg, const char *name); void intel_i2c_destroy(struct i2c_adapter *adapter); @@ -186,6 +210,9 @@ void intel_i2c_reset_gmbus(struct drm_device *dev); extern void intel_crt_init(struct drm_device *dev); extern void intel_hdmi_init(struct drm_device *dev, int sdvox_reg); +extern bool intel_hdmi_proc_infoframe(struct drm_encoder *encoder, + struct dip_infoframe *avi_if, + bool (*write_func)(struct drm_encoder *, uint8_t *)); extern bool intel_sdvo_init(struct drm_device *dev, int output_device); extern void intel_dvo_init(struct drm_device *dev); extern void intel_tv_init(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index ccd4c97..4fc323c 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -48,6 +48,79 @@ static struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder) return container_of(enc_to_intel_encoder(encoder), struct intel_hdmi, base); } +static void intel_hdmi_calc_infoframe_csum(struct dip_infoframe *avi_if) +{ + uint8_t *data = (uint8_t *)avi_if; + uint8_t sum = 0; + unsigned i; + + avi_if->checksum = 0; + avi_if->ecc = 0; + avi_if->padding = 0; + + for (i = 0; i < sizeof(*avi_if); i++) + sum += data[i]; + + avi_if->checksum = 0x100 - sum; +} + +static bool intel_hdmi_write_avi_infoframe(struct drm_encoder *encoder, + uint8_t *data) +{ + struct drm_device *dev = encoder->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + + I915_WRITE(VIDEO_DIP_DATA, *((u32 *)data)); + return true; +} + +bool intel_hdmi_proc_infoframe(struct drm_encoder *encoder, + struct dip_infoframe *avi_if, + bool (*write_func)(struct drm_encoder *, uint8_t *)) +{ + unsigned size; + uint8_t *data = (uint8_t *)avi_if; + + intel_hdmi_calc_infoframe_csum(avi_if); + for (size = sizeof(*avi_if); size > 0; size -= 4) { + if (!write_func(encoder, data)) + return false; + data += 4; + } + return true; +} + +static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder) +{ + struct dip_infoframe avi_if = { + .type = DIP_TYPE_AVI, + .ver = DIP_VERSION_AVI, + .len = DIP_LEN_AVI, + .Y_A_B_S = 0x02, + .C_M_R = 0x28, + }; + struct drm_device *dev = encoder->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); + u32 port; + + if (!intel_hdmi->has_hdmi_sink) + return; + + if (intel_hdmi->sdvox_reg == SDVOB) + port = VIDEO_DIP_PORT_B; + else if (intel_hdmi->sdvox_reg == SDVOC) + port = VIDEO_DIP_PORT_C; + else + return; + + I915_WRITE(VIDEO_DIP_CTL, VIDEO_DIP_ENABLE | port | VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC); + POSTING_READ(VIDEO_DIP_ENABLE); + intel_hdmi_proc_infoframe(encoder, &avi_if, intel_hdmi_write_avi_infoframe); + I915_WRITE(VIDEO_DIP_CTL, VIDEO_DIP_ENABLE | port | VIDEO_DIP_ENABLE_AVI | VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC); + POSTING_READ(VIDEO_DIP_ENABLE); +} + static void intel_hdmi_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) @@ -67,6 +140,7 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder, if (intel_hdmi->has_hdmi_sink) { sdvox |= SDVO_AUDIO_ENABLE; + sdvox |= SDVO_NULL_PACKETS_DURING_VSYNC; if (HAS_PCH_CPT(dev)) sdvox |= HDMI_MODE_SELECT; } @@ -80,6 +154,8 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder, I915_WRITE(intel_hdmi->sdvox_reg, sdvox); POSTING_READ(intel_hdmi->sdvox_reg); + + intel_hdmi_set_avi_infoframe(encoder); } static void intel_hdmi_dpms(struct drm_encoder *encoder, int mode) diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 093e914..b99ec72 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -874,115 +874,32 @@ static void intel_sdvo_dump_hdmi_buf(struct intel_sdvo *intel_sdvo) } #endif -static bool intel_sdvo_set_hdmi_buf(struct intel_sdvo *intel_sdvo, - int index, - uint8_t *data, int8_t size, uint8_t tx_rate) +static bool intel_sdvo_write_avi_infoframe(struct drm_encoder *encoder, + uint8_t *data) { - uint8_t set_buf_index[2]; - - set_buf_index[0] = index; - set_buf_index[1] = 0; - - if (!intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_INDEX, - set_buf_index, 2)) - return false; - - for (; size > 0; size -= 8) { - if (!intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_DATA, data, 8)) - return false; - - data += 8; - } - - return intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_TXRATE, &tx_rate, 1); -} - -static uint8_t intel_sdvo_calc_hbuf_csum(uint8_t *data, uint8_t size) -{ - uint8_t csum = 0; - int i; - - for (i = 0; i < size; i++) - csum += data[i]; + struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); - return 0x100 - csum; + return intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_DATA, data, 4); } -#define DIP_TYPE_AVI 0x82 -#define DIP_VERSION_AVI 0x2 -#define DIP_LEN_AVI 13 - -struct dip_infoframe { - uint8_t type; - uint8_t version; - uint8_t len; - uint8_t checksum; - union { - struct { - /* Packet Byte #1 */ - uint8_t S:2; - uint8_t B:2; - uint8_t A:1; - uint8_t Y:2; - uint8_t rsvd1:1; - /* Packet Byte #2 */ - uint8_t R:4; - uint8_t M:2; - uint8_t C:2; - /* Packet Byte #3 */ - uint8_t SC:2; - uint8_t Q:2; - uint8_t EC:3; - uint8_t ITC:1; - /* Packet Byte #4 */ - uint8_t VIC:7; - uint8_t rsvd2:1; - /* Packet Byte #5 */ - uint8_t PR:4; - uint8_t rsvd3:4; - /* Packet Byte #6~13 */ - uint16_t top_bar_end; - uint16_t bottom_bar_start; - uint16_t left_bar_end; - uint16_t right_bar_start; - } avi; - struct { - /* Packet Byte #1 */ - uint8_t channel_count:3; - uint8_t rsvd1:1; - uint8_t coding_type:4; - /* Packet Byte #2 */ - uint8_t sample_size:2; /* SS0, SS1 */ - uint8_t sample_frequency:3; - uint8_t rsvd2:3; - /* Packet Byte #3 */ - uint8_t coding_type_private:5; - uint8_t rsvd3:3; - /* Packet Byte #4 */ - uint8_t channel_allocation; - /* Packet Byte #5 */ - uint8_t rsvd4:3; - uint8_t level_shift:4; - uint8_t downmix_inhibit:1; - } audio; - uint8_t payload[28]; - } __attribute__ ((packed)) u; -} __attribute__((packed)); - -static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo, - struct drm_display_mode * mode) +static bool intel_sdvo_set_avi_infoframe(struct drm_encoder *encoder) { + struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); struct dip_infoframe avi_if = { .type = DIP_TYPE_AVI, - .version = DIP_VERSION_AVI, + .ver = DIP_VERSION_AVI, .len = DIP_LEN_AVI, }; + uint8_t buf[2] = { 1, 0 }; + + if (!intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_INDEX, buf, 2)) + return false; + + if (!intel_hdmi_proc_infoframe(encoder, &avi_if, intel_sdvo_write_avi_infoframe)) + return false; - avi_if.checksum = intel_sdvo_calc_hbuf_csum((uint8_t *)&avi_if, - 4 + avi_if.len); - return intel_sdvo_set_hdmi_buf(intel_sdvo, 1, (uint8_t *)&avi_if, - 4 + avi_if.len, - SDVO_HBUF_TX_VSYNC); + buf[0] = SDVO_HBUF_TX_VSYNC; + return intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_TXRATE, buf, 1); } static bool intel_sdvo_set_tv_format(struct intel_sdvo *intel_sdvo) @@ -1114,7 +1031,7 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, return; if (intel_sdvo->is_hdmi) { - if (!intel_sdvo_set_avi_infoframe(intel_sdvo, mode)) + if (!intel_sdvo_set_avi_infoframe(encoder)) return; sdvox |= SDVO_AUDIO_ENABLE;