summaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorShaohua Li <shaohua.li@intel.com>2009-04-07 11:02:28 +0800
committerEric Anholt <eric@anholt.net>2009-05-14 16:00:26 -0700
commit0ba0e9e1f173a59ba402a253d356612c821b7a14 (patch)
tree942e1852a2beb7b0ad020c935a4fd18d3d750553 /drivers/gpu
parent13f4c435ebf2a7c150ffa714f3b23b8e4e8cb42f (diff)
downloadlinux-0ba0e9e1f173a59ba402a253d356612c821b7a14.tar.bz2
drm/i915: workaround IGD i2c bus issue in kernel side (v2)
In IGD, DPCUNIT_CLOCK_GATE_DISABLE bit should be set, otherwise i2c access will be wrong. v2: Disable CLOCK_GATE_DISABLE bit after bit bashing as suggested by Eric. Signed-off-by: Shaohua Li <shaohua.li@intel.com> Signed-off-by: Eric Anholt <eric@anholt.net>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/i915/i915_reg.h1
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h2
-rw-r--r--drivers/gpu/drm/i915/intel_i2c.c17
-rw-r--r--drivers/gpu/drm/i915/intel_modes.c6
4 files changed, 25 insertions, 1 deletions
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 521194732266..15da44cf21b1 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -526,6 +526,7 @@
#define DPLLA_INPUT_BUFFER_ENABLE (1 << 0)
#define D_STATE 0x6104
#define CG_2D_DIS 0x6200
+#define DPCUNIT_CLOCK_GATE_DISABLE (1 << 24)
#define CG_3D_DIS 0x6204
/*
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 957daef8edff..cf2943028936 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -109,7 +109,7 @@ struct intel_i2c_chan *intel_i2c_create(struct drm_device *dev, const u32 reg,
void intel_i2c_destroy(struct intel_i2c_chan *chan);
int intel_ddc_get_modes(struct intel_output *intel_output);
extern bool intel_ddc_probe(struct intel_output *intel_output);
-
+void intel_i2c_quirk_set(struct drm_device *dev, bool enable);
extern void intel_crt_init(struct drm_device *dev);
extern void intel_hdmi_init(struct drm_device *dev, int sdvox_reg);
extern bool intel_sdvo_init(struct drm_device *dev, int output_device);
diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c
index 5ee9d4c25753..f7061f68d050 100644
--- a/drivers/gpu/drm/i915/intel_i2c.c
+++ b/drivers/gpu/drm/i915/intel_i2c.c
@@ -34,6 +34,21 @@
#include "i915_drm.h"
#include "i915_drv.h"
+void intel_i2c_quirk_set(struct drm_device *dev, bool enable)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ /* When using bit bashing for I2C, this bit needs to be set to 1 */
+ if (!IS_IGD(dev))
+ return;
+ if (enable)
+ I915_WRITE(CG_2D_DIS,
+ I915_READ(CG_2D_DIS) | DPCUNIT_CLOCK_GATE_DISABLE);
+ else
+ I915_WRITE(CG_2D_DIS,
+ I915_READ(CG_2D_DIS) & (~DPCUNIT_CLOCK_GATE_DISABLE));
+}
+
/*
* Intel GPIO access functions
*/
@@ -153,8 +168,10 @@ struct intel_i2c_chan *intel_i2c_create(struct drm_device *dev, const u32 reg,
goto out_free;
/* JJJ: raise SCL and SDA? */
+ intel_i2c_quirk_set(dev, true);
set_data(chan, 1);
set_clock(chan, 1);
+ intel_i2c_quirk_set(dev, false);
udelay(20);
return chan;
diff --git a/drivers/gpu/drm/i915/intel_modes.c b/drivers/gpu/drm/i915/intel_modes.c
index 07d7ec976168..e0910fefce87 100644
--- a/drivers/gpu/drm/i915/intel_modes.c
+++ b/drivers/gpu/drm/i915/intel_modes.c
@@ -27,6 +27,7 @@
#include <linux/fb.h>
#include "drmP.h"
#include "intel_drv.h"
+#include "i915_drv.h"
/**
* intel_ddc_probe
@@ -52,7 +53,10 @@ bool intel_ddc_probe(struct intel_output *intel_output)
}
};
+ intel_i2c_quirk_set(intel_output->ddc_bus->drm_dev, true);
ret = i2c_transfer(&intel_output->ddc_bus->adapter, msgs, 2);
+ intel_i2c_quirk_set(intel_output->ddc_bus->drm_dev, false);
+
if (ret == 2)
return true;
@@ -70,8 +74,10 @@ int intel_ddc_get_modes(struct intel_output *intel_output)
struct edid *edid;
int ret = 0;
+ intel_i2c_quirk_set(intel_output->ddc_bus->drm_dev, true);
edid = drm_get_edid(&intel_output->base,
&intel_output->ddc_bus->adapter);
+ intel_i2c_quirk_set(intel_output->ddc_bus->drm_dev, false);
if (edid) {
drm_mode_connector_update_edid_property(&intel_output->base,
edid);