Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

Merge branch 'fix-pch-refclk' into foo

parents 86a3073e 9fb526db
Loading
Loading
Loading
Loading
+5 −2
Original line number Diff line number Diff line
@@ -79,11 +79,11 @@ MODULE_PARM_DESC(lvds_downclock,
		"Use panel (LVDS/eDP) downclocking for power savings "
		"(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_PARM_DESC(lvds_use_ssc,
		"Use Spread Spectrum Clock with panels [LVDS/eDP] "
		"(default: true)");
		"(default: auto from VBT)");

int i915_vbt_sdvo_panel_type __read_mostly = -1;
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)
		error = i915_gem_init_ringbuffer(dev);
		mutex_unlock(&dev->struct_mutex);

		if (HAS_PCH_SPLIT(dev))
			ironlake_init_pch_refclk(dev);

		drm_mode_config_reset(dev);
		drm_irq_install(dev);

+2 −0
Original line number Diff line number Diff line
@@ -358,6 +358,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 display_clock_mode:1;
	int lvds_ssc_freq;
	struct {
		int rate;
@@ -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 void intel_disable_fbc(struct drm_device *dev);
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 gen6_set_rps(struct drm_device *dev, u8 val);
extern void intel_detect_pch(struct drm_device *dev);
+10 −3
Original line number Diff line number Diff line
/*
 * Copyright  2006 Intel Corporation
 * Copyright © 2006 Intel Corporation
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
@@ -309,6 +309,13 @@ parse_general_features(struct drm_i915_private *dev_priv,
		dev_priv->lvds_use_ssc = general->enable_ssc;
		dev_priv->lvds_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)
	/* Default to using SSC */
	dev_priv->lvds_use_ssc = 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 */
	dev_priv->edp.bpp = 18;
@@ -639,7 +646,7 @@ intel_parse_bios(struct drm_device *dev)
	if (dev_priv->opregion.vbt) {
		struct vbt_header *vbt = dev_priv->opregion.vbt;
		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);
			bdb = (struct bdb_header *)((char *)vbt + vbt->bdb_offset);
		} else
+7 −2
Original line number Diff line number Diff line
@@ -120,7 +120,9 @@ struct bdb_general_features {
	u8 ssc_freq:1;
	u8 enable_lfp_on_override: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 */
	u8 disable_smooth_vision:1;
@@ -133,7 +135,10 @@ struct bdb_general_features {
        /* bits 5 */
	u8 int_crt_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));

/* pre-915 */
+91 −53
Original line number Diff line number Diff line
@@ -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)
{
	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);
}

@@ -5108,36 +5110,52 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
	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_mode_config *mode_config = &dev->mode_config;
	struct drm_crtc *crtc;
	struct intel_encoder *encoder;
	struct intel_encoder *has_edp_encoder = NULL;
	u32 temp;
	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 */
	list_for_each_entry(crtc, &mode_config->crtc_list, head) {
		if (!crtc->enabled)
			continue;

	list_for_each_entry(encoder, &mode_config->encoder_list,
			    base.head) {
			if (encoder->base.crtc != crtc)
				continue;

		switch (encoder->type) {
		case INTEL_OUTPUT_LVDS:
			has_panel = true;
			has_lvds = true;
			break;
		case INTEL_OUTPUT_EDP:
				has_edp_encoder = encoder;
			has_panel = true;
			if (intel_encoder_is_pch_edp(&encoder->base))
				has_pch_edp = true;
			else
				has_cpu_edp = true;
			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
	 * enabling. This is only under driver's control after
	 * PCH B stepping, previous chipset stepping should be
@@ -5146,37 +5164,62 @@ static void ironlake_update_pch_refclk(struct drm_device *dev)
	temp = I915_READ(PCH_DREF_CONTROL);
	/* Always enable nonspread source */
	temp &= ~DREF_NONSPREAD_SOURCE_MASK;

	if (has_ck505)
		temp |= DREF_NONSPREAD_CK505_ENABLE;
	else
		temp |= DREF_NONSPREAD_SOURCE_ENABLE;

	if (has_panel) {
		temp &= ~DREF_SSC_SOURCE_MASK;
		temp |= DREF_SSC_SOURCE_ENABLE;
	I915_WRITE(PCH_DREF_CONTROL, temp);

	POSTING_READ(PCH_DREF_CONTROL);
	udelay(200);

	if (has_edp_encoder) {
		if (intel_panel_use_ssc(dev_priv)) {
		/* SSC must be turned on before enabling the CPU output  */
		if (intel_panel_use_ssc(dev_priv) && can_ssc) {
			DRM_DEBUG_KMS("Using SSC on panel\n");
			temp |= DREF_SSC1_ENABLE;
			I915_WRITE(PCH_DREF_CONTROL, temp);
		}

		/* 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;

		/* Enable CPU source on CPU attached eDP */
		if (!intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
			if (intel_panel_use_ssc(dev_priv))
		if (has_cpu_edp) {
			if (intel_panel_use_ssc(dev_priv) && can_ssc) {
				DRM_DEBUG_KMS("Using SSC on eDP\n");
				temp |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
			}
			else
				temp |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
		} else
			temp |= DREF_CPU_SOURCE_OUTPUT_DISABLE;

		I915_WRITE(PCH_DREF_CONTROL, temp);
		POSTING_READ(PCH_DREF_CONTROL);
		udelay(200);
	} else {
			/* Enable SSC on PCH eDP if needed */
			if (intel_panel_use_ssc(dev_priv)) {
				DRM_ERROR("enabling SSC on PCH\n");
				temp |= DREF_SUPERSPREAD_SOURCE_ENABLE;
			}
		}
		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);
		POSTING_READ(PCH_DREF_CONTROL);
		udelay(200);
@@ -5242,16 +5285,10 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
		num_connectors++;
	}

	if (is_lvds && intel_panel_use_ssc(dev_priv) && num_connectors < 2) {
		refclk = dev_priv->lvds_ssc_freq * 1000;
		DRM_DEBUG_KMS("using SSC reference clock of %d MHz\n",
			      refclk / 1000);
	} else {
		refclk = 96000;
		if (!has_edp_encoder ||
		    intel_encoder_is_pch_edp(&has_edp_encoder->base))
			refclk = 120000; /* 120Mhz refclk */
	}
	/*
	 * Every reference clock in a PCH system is 120MHz
	 */
	refclk = 120000;

	/*
	 * 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,
	ironlake_compute_m_n(intel_crtc->bpp, lane, target_clock, link_bw,
			     &m_n);

	ironlake_update_pch_refclk(dev);

	fp = clock.n << 16 | clock.m1 << 8 | clock.m2;
	if (has_reduced_clock)
		fp2 = reduced_clock.n << 16 | reduced_clock.m1 << 8 |
@@ -7376,6 +7411,9 @@ static void intel_setup_outputs(struct drm_device *dev)

	/* disable all the possible outputs/crtcs before entering KMS mode */
	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)