diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 47ecb61..af1d2b1 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -219,6 +219,7 @@ typedef struct drm_i915_private { unsigned int lvds_vbt:1; unsigned int int_crt_support:1; unsigned int lvds_use_ssc:1; + unsigned int lvds_dual_channel:1; int lvds_ssc_freq; struct drm_i915_fence_reg fence_regs[16]; /* assume 965 */ diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index da22863..8fc45c4 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -32,6 +32,7 @@ #define SLAVE_ADDR1 0x70 #define SLAVE_ADDR2 0x72 +#define LVDS_DUAL_CHANNEL 0x2 static void * find_section(struct bdb_header *bdb, int section_id) @@ -104,19 +105,29 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv, struct lvds_dvo_timing *dvo_timing; struct drm_display_mode *panel_fixed_mode; int lfp_data_size; + uint32_t channel_bits; /* Defaults if we can't find VBT info */ dev_priv->lvds_dither = 0; dev_priv->lvds_vbt = 0; + dev_priv->lvds_dual_channel = 0; lvds_options = find_section(bdb, BDB_LVDS_OPTIONS); if (!lvds_options) return; + /* Fetch lvds channel info */ + channel_bits = lvds_options->lvds_channel_bits & + (3 << lvds_options->panel_type); + if (channel_bits) { + channel_bits = channel_bits >> lvds_options->panel_type; + if (channel_bits == LVDS_DUAL_CHANNEL) + dev_priv->lvds_dual_channel = 1; + } + dev_priv->lvds_dither = lvds_options->pixel_dither; if (lvds_options->panel_type == 0xff) return; - lvds_lfp_data = find_section(bdb, BDB_LVDS_LFP_DATA); if (!lvds_lfp_data) return; diff --git a/drivers/gpu/drm/i915/intel_bios.h b/drivers/gpu/drm/i915/intel_bios.h index fe72e1c..520afd8 100644 --- a/drivers/gpu/drm/i915/intel_bios.h +++ b/drivers/gpu/drm/i915/intel_bios.h @@ -255,6 +255,7 @@ struct bdb_lvds_options { u8 lvds_edid:1; u8 rsvd2:1; u8 rsvd4; + u32 lvds_channel_bits; } __attribute__((packed)); /* LFP pointer table contains entries to the struct below */ diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 508838e..7c63a0f 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -510,11 +510,11 @@ static const intel_limit_t *intel_g4x_limit(struct drm_crtc *crtc) if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { if ((I915_READ(LVDS) & LVDS_CLKB_POWER_MASK) == - LVDS_CLKB_POWER_UP) + LVDS_CLKB_POWER_UP || dev_priv->lvds_dual_channel) /* LVDS with dual channel */ limit = &intel_limits_g4x_dual_channel_lvds; else - /* LVDS with dual channel */ + /* LVDS with single channel */ limit = &intel_limits_g4x_single_channel_lvds; } else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_HDMI) || intel_pipe_has_type(crtc, INTEL_OUTPUT_ANALOG)) { @@ -645,7 +645,8 @@ intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, int err = target; if (IS_I9XX(dev) && intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) && - (I915_READ(LVDS) & LVDS_PORT_EN) != 0) { + ((I915_READ(LVDS) & LVDS_PORT_EN) != 0 || + dev_priv->lvds_dual_channel)) { /* * For LVDS, if the panel is on, just rely on its current * settings for dual-channel. We haven't figured out how to @@ -765,7 +766,7 @@ intel_igdng_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { if ((I915_READ(LVDS) & LVDS_CLKB_POWER_MASK) == - LVDS_CLKB_POWER_UP) + LVDS_CLKB_POWER_UP || dev_priv->lvds_dual_channel) clock.p2 = limit->p2.p2_fast; else clock.p2 = limit->p2.p2_slow;