diff options
author | Shaohua Li <shaohua.li@intel.com> | 2009-04-06 23:02:28 -0400 |
---|---|---|
committer | Eric Anholt <eric@anholt.net> | 2009-05-14 19:00:26 -0400 |
commit | 0ba0e9e1f173a59ba402a253d356612c821b7a14 (patch) | |
tree | 942e1852a2beb7b0ad020c935a4fd18d3d750553 | |
parent | 13f4c435ebf2a7c150ffa714f3b23b8e4e8cb42f (diff) |
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>
-rw-r--r-- | drivers/gpu/drm/i915/i915_reg.h | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_drv.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_i2c.c | 17 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_modes.c | 6 |
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 @@ | |||
526 | #define DPLLA_INPUT_BUFFER_ENABLE (1 << 0) | 526 | #define DPLLA_INPUT_BUFFER_ENABLE (1 << 0) |
527 | #define D_STATE 0x6104 | 527 | #define D_STATE 0x6104 |
528 | #define CG_2D_DIS 0x6200 | 528 | #define CG_2D_DIS 0x6200 |
529 | #define DPCUNIT_CLOCK_GATE_DISABLE (1 << 24) | ||
529 | #define CG_3D_DIS 0x6204 | 530 | #define CG_3D_DIS 0x6204 |
530 | 531 | ||
531 | /* | 532 | /* |
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, | |||
109 | void intel_i2c_destroy(struct intel_i2c_chan *chan); | 109 | void intel_i2c_destroy(struct intel_i2c_chan *chan); |
110 | int intel_ddc_get_modes(struct intel_output *intel_output); | 110 | int intel_ddc_get_modes(struct intel_output *intel_output); |
111 | extern bool intel_ddc_probe(struct intel_output *intel_output); | 111 | extern bool intel_ddc_probe(struct intel_output *intel_output); |
112 | 112 | void intel_i2c_quirk_set(struct drm_device *dev, bool enable); | |
113 | extern void intel_crt_init(struct drm_device *dev); | 113 | extern void intel_crt_init(struct drm_device *dev); |
114 | extern void intel_hdmi_init(struct drm_device *dev, int sdvox_reg); | 114 | extern void intel_hdmi_init(struct drm_device *dev, int sdvox_reg); |
115 | extern bool intel_sdvo_init(struct drm_device *dev, int output_device); | 115 | 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 @@ | |||
34 | #include "i915_drm.h" | 34 | #include "i915_drm.h" |
35 | #include "i915_drv.h" | 35 | #include "i915_drv.h" |
36 | 36 | ||
37 | void intel_i2c_quirk_set(struct drm_device *dev, bool enable) | ||
38 | { | ||
39 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
40 | |||
41 | /* When using bit bashing for I2C, this bit needs to be set to 1 */ | ||
42 | if (!IS_IGD(dev)) | ||
43 | return; | ||
44 | if (enable) | ||
45 | I915_WRITE(CG_2D_DIS, | ||
46 | I915_READ(CG_2D_DIS) | DPCUNIT_CLOCK_GATE_DISABLE); | ||
47 | else | ||
48 | I915_WRITE(CG_2D_DIS, | ||
49 | I915_READ(CG_2D_DIS) & (~DPCUNIT_CLOCK_GATE_DISABLE)); | ||
50 | } | ||
51 | |||
37 | /* | 52 | /* |
38 | * Intel GPIO access functions | 53 | * Intel GPIO access functions |
39 | */ | 54 | */ |
@@ -153,8 +168,10 @@ struct intel_i2c_chan *intel_i2c_create(struct drm_device *dev, const u32 reg, | |||
153 | goto out_free; | 168 | goto out_free; |
154 | 169 | ||
155 | /* JJJ: raise SCL and SDA? */ | 170 | /* JJJ: raise SCL and SDA? */ |
171 | intel_i2c_quirk_set(dev, true); | ||
156 | set_data(chan, 1); | 172 | set_data(chan, 1); |
157 | set_clock(chan, 1); | 173 | set_clock(chan, 1); |
174 | intel_i2c_quirk_set(dev, false); | ||
158 | udelay(20); | 175 | udelay(20); |
159 | 176 | ||
160 | return chan; | 177 | 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 @@ | |||
27 | #include <linux/fb.h> | 27 | #include <linux/fb.h> |
28 | #include "drmP.h" | 28 | #include "drmP.h" |
29 | #include "intel_drv.h" | 29 | #include "intel_drv.h" |
30 | #include "i915_drv.h" | ||
30 | 31 | ||
31 | /** | 32 | /** |
32 | * intel_ddc_probe | 33 | * intel_ddc_probe |
@@ -52,7 +53,10 @@ bool intel_ddc_probe(struct intel_output *intel_output) | |||
52 | } | 53 | } |
53 | }; | 54 | }; |
54 | 55 | ||
56 | intel_i2c_quirk_set(intel_output->ddc_bus->drm_dev, true); | ||
55 | ret = i2c_transfer(&intel_output->ddc_bus->adapter, msgs, 2); | 57 | ret = i2c_transfer(&intel_output->ddc_bus->adapter, msgs, 2); |
58 | intel_i2c_quirk_set(intel_output->ddc_bus->drm_dev, false); | ||
59 | |||
56 | if (ret == 2) | 60 | if (ret == 2) |
57 | return true; | 61 | return true; |
58 | 62 | ||
@@ -70,8 +74,10 @@ int intel_ddc_get_modes(struct intel_output *intel_output) | |||
70 | struct edid *edid; | 74 | struct edid *edid; |
71 | int ret = 0; | 75 | int ret = 0; |
72 | 76 | ||
77 | intel_i2c_quirk_set(intel_output->ddc_bus->drm_dev, true); | ||
73 | edid = drm_get_edid(&intel_output->base, | 78 | edid = drm_get_edid(&intel_output->base, |
74 | &intel_output->ddc_bus->adapter); | 79 | &intel_output->ddc_bus->adapter); |
80 | intel_i2c_quirk_set(intel_output->ddc_bus->drm_dev, false); | ||
75 | if (edid) { | 81 | if (edid) { |
76 | drm_mode_connector_update_edid_property(&intel_output->base, | 82 | drm_mode_connector_update_edid_property(&intel_output->base, |
77 | edid); | 83 | edid); |