Commit 9a1f5780 authored by Keith Packard's avatar Keith Packard

Merge branch 'fix-pch-refclk' into foo

parents 86a3073e 9fb526db
...@@ -79,11 +79,11 @@ MODULE_PARM_DESC(lvds_downclock, ...@@ -79,11 +79,11 @@ MODULE_PARM_DESC(lvds_downclock,
"Use panel (LVDS/eDP) downclocking for power savings " "Use panel (LVDS/eDP) downclocking for power savings "
"(default: false)"); "(default: false)");
unsigned int i915_panel_use_ssc __read_mostly = 1; unsigned int i915_panel_use_ssc __read_mostly = -1;
module_param_named(lvds_use_ssc, i915_panel_use_ssc, int, 0600); module_param_named(lvds_use_ssc, i915_panel_use_ssc, int, 0600);
MODULE_PARM_DESC(lvds_use_ssc, MODULE_PARM_DESC(lvds_use_ssc,
"Use Spread Spectrum Clock with panels [LVDS/eDP] " "Use Spread Spectrum Clock with panels [LVDS/eDP] "
"(default: true)"); "(default: auto from VBT)");
int i915_vbt_sdvo_panel_type __read_mostly = -1; int i915_vbt_sdvo_panel_type __read_mostly = -1;
module_param_named(vbt_sdvo_panel_type, i915_vbt_sdvo_panel_type, int, 0600); module_param_named(vbt_sdvo_panel_type, i915_vbt_sdvo_panel_type, int, 0600);
...@@ -471,6 +471,9 @@ static int i915_drm_thaw(struct drm_device *dev) ...@@ -471,6 +471,9 @@ static int i915_drm_thaw(struct drm_device *dev)
error = i915_gem_init_ringbuffer(dev); error = i915_gem_init_ringbuffer(dev);
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
if (HAS_PCH_SPLIT(dev))
ironlake_init_pch_refclk(dev);
drm_mode_config_reset(dev); drm_mode_config_reset(dev);
drm_irq_install(dev); drm_irq_install(dev);
......
...@@ -358,6 +358,7 @@ typedef struct drm_i915_private { ...@@ -358,6 +358,7 @@ typedef struct drm_i915_private {
unsigned int lvds_vbt:1; unsigned int lvds_vbt:1;
unsigned int int_crt_support:1; unsigned int int_crt_support:1;
unsigned int lvds_use_ssc:1; unsigned int lvds_use_ssc:1;
unsigned int display_clock_mode:1;
int lvds_ssc_freq; int lvds_ssc_freq;
struct { struct {
int rate; int rate;
...@@ -1301,6 +1302,7 @@ extern int intel_modeset_vga_set_state(struct drm_device *dev, bool state); ...@@ -1301,6 +1302,7 @@ extern int intel_modeset_vga_set_state(struct drm_device *dev, bool state);
extern bool intel_fbc_enabled(struct drm_device *dev); extern bool intel_fbc_enabled(struct drm_device *dev);
extern void intel_disable_fbc(struct drm_device *dev); extern void intel_disable_fbc(struct drm_device *dev);
extern bool ironlake_set_drps(struct drm_device *dev, u8 val); extern bool ironlake_set_drps(struct drm_device *dev, u8 val);
extern void ironlake_init_pch_refclk(struct drm_device *dev);
extern void ironlake_enable_rc6(struct drm_device *dev); extern void ironlake_enable_rc6(struct drm_device *dev);
extern void gen6_set_rps(struct drm_device *dev, u8 val); extern void gen6_set_rps(struct drm_device *dev, u8 val);
extern void intel_detect_pch(struct drm_device *dev); extern void intel_detect_pch(struct drm_device *dev);
......
/* /*
* Copyright 2006 Intel Corporation * Copyright © 2006 Intel Corporation
* *
* Permission is hereby granted, free of charge, to any person obtaining a * Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"), * copy of this software and associated documentation files (the "Software"),
...@@ -309,6 +309,13 @@ parse_general_features(struct drm_i915_private *dev_priv, ...@@ -309,6 +309,13 @@ parse_general_features(struct drm_i915_private *dev_priv,
dev_priv->lvds_use_ssc = general->enable_ssc; dev_priv->lvds_use_ssc = general->enable_ssc;
dev_priv->lvds_ssc_freq = dev_priv->lvds_ssc_freq =
intel_bios_ssc_frequency(dev, general->ssc_freq); intel_bios_ssc_frequency(dev, general->ssc_freq);
dev_priv->display_clock_mode = general->display_clock_mode;
DRM_DEBUG_KMS("BDB_GENERAL_FEATURES int_tv_support %d int_crt_support %d lvds_use_ssc %d lvds_ssc_freq %d display_clock_mode %d\n",
dev_priv->int_tv_support,
dev_priv->int_crt_support,
dev_priv->lvds_use_ssc,
dev_priv->lvds_ssc_freq,
dev_priv->display_clock_mode);
} }
} }
...@@ -610,7 +617,7 @@ init_vbt_defaults(struct drm_i915_private *dev_priv) ...@@ -610,7 +617,7 @@ init_vbt_defaults(struct drm_i915_private *dev_priv)
/* Default to using SSC */ /* Default to using SSC */
dev_priv->lvds_use_ssc = 1; dev_priv->lvds_use_ssc = 1;
dev_priv->lvds_ssc_freq = intel_bios_ssc_frequency(dev, 1); dev_priv->lvds_ssc_freq = intel_bios_ssc_frequency(dev, 1);
DRM_DEBUG("Set default to SSC at %dMHz\n", dev_priv->lvds_ssc_freq); DRM_DEBUG_KMS("Set default to SSC at %dMHz\n", dev_priv->lvds_ssc_freq);
/* eDP data */ /* eDP data */
dev_priv->edp.bpp = 18; dev_priv->edp.bpp = 18;
...@@ -639,7 +646,7 @@ intel_parse_bios(struct drm_device *dev) ...@@ -639,7 +646,7 @@ intel_parse_bios(struct drm_device *dev)
if (dev_priv->opregion.vbt) { if (dev_priv->opregion.vbt) {
struct vbt_header *vbt = dev_priv->opregion.vbt; struct vbt_header *vbt = dev_priv->opregion.vbt;
if (memcmp(vbt->signature, "$VBT", 4) == 0) { if (memcmp(vbt->signature, "$VBT", 4) == 0) {
DRM_DEBUG_DRIVER("Using VBT from OpRegion: %20s\n", DRM_DEBUG_KMS("Using VBT from OpRegion: %20s\n",
vbt->signature); vbt->signature);
bdb = (struct bdb_header *)((char *)vbt + vbt->bdb_offset); bdb = (struct bdb_header *)((char *)vbt + vbt->bdb_offset);
} else } else
......
...@@ -120,7 +120,9 @@ struct bdb_general_features { ...@@ -120,7 +120,9 @@ struct bdb_general_features {
u8 ssc_freq:1; u8 ssc_freq:1;
u8 enable_lfp_on_override:1; u8 enable_lfp_on_override:1;
u8 disable_ssc_ddt:1; u8 disable_ssc_ddt:1;
u8 rsvd8:3; /* finish byte */ u8 rsvd7:1;
u8 display_clock_mode:1;
u8 rsvd8:1; /* finish byte */
/* bits 3 */ /* bits 3 */
u8 disable_smooth_vision:1; u8 disable_smooth_vision:1;
...@@ -133,7 +135,10 @@ struct bdb_general_features { ...@@ -133,7 +135,10 @@ struct bdb_general_features {
/* bits 5 */ /* bits 5 */
u8 int_crt_support:1; u8 int_crt_support:1;
u8 int_tv_support:1; u8 int_tv_support:1;
u8 rsvd11:6; /* finish byte */ u8 int_efp_support:1;
u8 dp_ssc_enb:1; /* PCH attached eDP supports SSC */
u8 dp_ssc_freq:1; /* SSC freq for PCH attached eDP */
u8 rsvd11:3; /* finish byte */
} __attribute__((packed)); } __attribute__((packed));
/* pre-915 */ /* pre-915 */
......
...@@ -4585,7 +4585,9 @@ static void intel_update_watermarks(struct drm_device *dev) ...@@ -4585,7 +4585,9 @@ static void intel_update_watermarks(struct drm_device *dev)
static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv) static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv)
{ {
return dev_priv->lvds_use_ssc && i915_panel_use_ssc if (i915_panel_use_ssc >= 0)
return i915_panel_use_ssc != 0;
return dev_priv->lvds_use_ssc
&& !(dev_priv->quirks & QUIRK_LVDS_SSC_DISABLE); && !(dev_priv->quirks & QUIRK_LVDS_SSC_DISABLE);
} }
...@@ -5108,36 +5110,52 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc, ...@@ -5108,36 +5110,52 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
return ret; return ret;
} }
static void ironlake_update_pch_refclk(struct drm_device *dev) /*
* Initialize reference clocks when the driver loads
*/
void ironlake_init_pch_refclk(struct drm_device *dev)
{ {
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_mode_config *mode_config = &dev->mode_config; struct drm_mode_config *mode_config = &dev->mode_config;
struct drm_crtc *crtc;
struct intel_encoder *encoder; struct intel_encoder *encoder;
struct intel_encoder *has_edp_encoder = NULL;
u32 temp; u32 temp;
bool has_lvds = false; bool has_lvds = false;
bool has_cpu_edp = false;
bool has_pch_edp = false;
bool has_panel = false;
bool has_ck505 = false;
bool can_ssc = false;
/* We need to take the global config into account */ /* We need to take the global config into account */
list_for_each_entry(crtc, &mode_config->crtc_list, head) { list_for_each_entry(encoder, &mode_config->encoder_list,
if (!crtc->enabled) base.head) {
continue; switch (encoder->type) {
case INTEL_OUTPUT_LVDS:
list_for_each_entry(encoder, &mode_config->encoder_list, has_panel = true;
base.head) { has_lvds = true;
if (encoder->base.crtc != crtc) break;
continue; case INTEL_OUTPUT_EDP:
has_panel = true;
switch (encoder->type) { if (intel_encoder_is_pch_edp(&encoder->base))
case INTEL_OUTPUT_LVDS: has_pch_edp = true;
has_lvds = true; else
case INTEL_OUTPUT_EDP: has_cpu_edp = true;
has_edp_encoder = encoder; break;
break;
}
} }
} }
if (HAS_PCH_IBX(dev)) {
has_ck505 = dev_priv->display_clock_mode;
can_ssc = has_ck505;
} else {
has_ck505 = false;
can_ssc = true;
}
DRM_DEBUG_KMS("has_panel %d has_lvds %d has_pch_edp %d has_cpu_edp %d has_ck505 %d\n",
has_panel, has_lvds, has_pch_edp, has_cpu_edp,
has_ck505);
/* Ironlake: try to setup display ref clock before DPLL /* Ironlake: try to setup display ref clock before DPLL
* enabling. This is only under driver's control after * enabling. This is only under driver's control after
* PCH B stepping, previous chipset stepping should be * PCH B stepping, previous chipset stepping should be
...@@ -5146,37 +5164,62 @@ static void ironlake_update_pch_refclk(struct drm_device *dev) ...@@ -5146,37 +5164,62 @@ static void ironlake_update_pch_refclk(struct drm_device *dev)
temp = I915_READ(PCH_DREF_CONTROL); temp = I915_READ(PCH_DREF_CONTROL);
/* Always enable nonspread source */ /* Always enable nonspread source */
temp &= ~DREF_NONSPREAD_SOURCE_MASK; temp &= ~DREF_NONSPREAD_SOURCE_MASK;
temp |= DREF_NONSPREAD_SOURCE_ENABLE;
temp &= ~DREF_SSC_SOURCE_MASK;
temp |= DREF_SSC_SOURCE_ENABLE;
I915_WRITE(PCH_DREF_CONTROL, temp);
POSTING_READ(PCH_DREF_CONTROL); if (has_ck505)
udelay(200); temp |= DREF_NONSPREAD_CK505_ENABLE;
else
temp |= DREF_NONSPREAD_SOURCE_ENABLE;
if (has_edp_encoder) { if (has_panel) {
if (intel_panel_use_ssc(dev_priv)) { temp &= ~DREF_SSC_SOURCE_MASK;
temp |= DREF_SSC1_ENABLE; temp |= DREF_SSC_SOURCE_ENABLE;
I915_WRITE(PCH_DREF_CONTROL, temp);
POSTING_READ(PCH_DREF_CONTROL); /* SSC must be turned on before enabling the CPU output */
udelay(200); if (intel_panel_use_ssc(dev_priv) && can_ssc) {
DRM_DEBUG_KMS("Using SSC on panel\n");
temp |= DREF_SSC1_ENABLE;
} }
/* Get SSC going before enabling the outputs */
I915_WRITE(PCH_DREF_CONTROL, temp);
POSTING_READ(PCH_DREF_CONTROL);
udelay(200);
temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK; temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
/* Enable CPU source on CPU attached eDP */ /* Enable CPU source on CPU attached eDP */
if (!intel_encoder_is_pch_edp(&has_edp_encoder->base)) { if (has_cpu_edp) {
if (intel_panel_use_ssc(dev_priv)) if (intel_panel_use_ssc(dev_priv) && can_ssc) {
DRM_DEBUG_KMS("Using SSC on eDP\n");
temp |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD; temp |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
}
else else
temp |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD; temp |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
} else { } else
/* Enable SSC on PCH eDP if needed */ temp |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
if (intel_panel_use_ssc(dev_priv)) {
DRM_ERROR("enabling SSC on PCH\n"); I915_WRITE(PCH_DREF_CONTROL, temp);
temp |= DREF_SUPERSPREAD_SOURCE_ENABLE; POSTING_READ(PCH_DREF_CONTROL);
} udelay(200);
} } else {
DRM_DEBUG_KMS("Disabling SSC entirely\n");
temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
/* Turn off CPU output */
temp |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
I915_WRITE(PCH_DREF_CONTROL, temp);
POSTING_READ(PCH_DREF_CONTROL);
udelay(200);
/* Turn off the SSC source */
temp &= ~DREF_SSC_SOURCE_MASK;
temp |= DREF_SSC_SOURCE_DISABLE;
/* Turn off SSC1 */
temp &= ~ DREF_SSC1_ENABLE;
I915_WRITE(PCH_DREF_CONTROL, temp); I915_WRITE(PCH_DREF_CONTROL, temp);
POSTING_READ(PCH_DREF_CONTROL); POSTING_READ(PCH_DREF_CONTROL);
udelay(200); udelay(200);
...@@ -5242,16 +5285,10 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, ...@@ -5242,16 +5285,10 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
num_connectors++; num_connectors++;
} }
if (is_lvds && intel_panel_use_ssc(dev_priv) && num_connectors < 2) { /*
refclk = dev_priv->lvds_ssc_freq * 1000; * Every reference clock in a PCH system is 120MHz
DRM_DEBUG_KMS("using SSC reference clock of %d MHz\n", */
refclk / 1000); refclk = 120000;
} else {
refclk = 96000;
if (!has_edp_encoder ||
intel_encoder_is_pch_edp(&has_edp_encoder->base))
refclk = 120000; /* 120Mhz refclk */
}
/* /*
* Returns a set of divisors for the desired target clock with the given * Returns a set of divisors for the desired target clock with the given
...@@ -5378,8 +5415,6 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, ...@@ -5378,8 +5415,6 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
ironlake_compute_m_n(intel_crtc->bpp, lane, target_clock, link_bw, ironlake_compute_m_n(intel_crtc->bpp, lane, target_clock, link_bw,
&m_n); &m_n);
ironlake_update_pch_refclk(dev);
fp = clock.n << 16 | clock.m1 << 8 | clock.m2; fp = clock.n << 16 | clock.m1 << 8 | clock.m2;
if (has_reduced_clock) if (has_reduced_clock)
fp2 = reduced_clock.n << 16 | reduced_clock.m1 << 8 | fp2 = reduced_clock.n << 16 | reduced_clock.m1 << 8 |
...@@ -7376,6 +7411,9 @@ static void intel_setup_outputs(struct drm_device *dev) ...@@ -7376,6 +7411,9 @@ static void intel_setup_outputs(struct drm_device *dev)
/* disable all the possible outputs/crtcs before entering KMS mode */ /* disable all the possible outputs/crtcs before entering KMS mode */
drm_helper_disable_unused_functions(dev); drm_helper_disable_unused_functions(dev);
if (HAS_PCH_SPLIT(dev))
ironlake_init_pch_refclk(dev);
} }
static void intel_user_framebuffer_destroy(struct drm_framebuffer *fb) static void intel_user_framebuffer_destroy(struct drm_framebuffer *fb)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment