Commit 0ba0e9e1 authored by Shaohua Li's avatar Shaohua Li Committed by Eric Anholt

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: default avatarShaohua Li <shaohua.li@intel.com>
Signed-off-by: default avatarEric Anholt <eric@anholt.net>
parent 13f4c435
...@@ -526,6 +526,7 @@ ...@@ -526,6 +526,7 @@
#define DPLLA_INPUT_BUFFER_ENABLE (1 << 0) #define DPLLA_INPUT_BUFFER_ENABLE (1 << 0)
#define D_STATE 0x6104 #define D_STATE 0x6104
#define CG_2D_DIS 0x6200 #define CG_2D_DIS 0x6200
#define DPCUNIT_CLOCK_GATE_DISABLE (1 << 24)
#define CG_3D_DIS 0x6204 #define CG_3D_DIS 0x6204
/* /*
......
...@@ -109,7 +109,7 @@ struct intel_i2c_chan *intel_i2c_create(struct drm_device *dev, const u32 reg, ...@@ -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); void intel_i2c_destroy(struct intel_i2c_chan *chan);
int intel_ddc_get_modes(struct intel_output *intel_output); int intel_ddc_get_modes(struct intel_output *intel_output);
extern bool intel_ddc_probe(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_crt_init(struct drm_device *dev);
extern void intel_hdmi_init(struct drm_device *dev, int sdvox_reg); extern void intel_hdmi_init(struct drm_device *dev, int sdvox_reg);
extern bool intel_sdvo_init(struct drm_device *dev, int output_device); extern bool intel_sdvo_init(struct drm_device *dev, int output_device);
......
...@@ -34,6 +34,21 @@ ...@@ -34,6 +34,21 @@
#include "i915_drm.h" #include "i915_drm.h"
#include "i915_drv.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 * Intel GPIO access functions
*/ */
...@@ -153,8 +168,10 @@ struct intel_i2c_chan *intel_i2c_create(struct drm_device *dev, const u32 reg, ...@@ -153,8 +168,10 @@ struct intel_i2c_chan *intel_i2c_create(struct drm_device *dev, const u32 reg,
goto out_free; goto out_free;
/* JJJ: raise SCL and SDA? */ /* JJJ: raise SCL and SDA? */
intel_i2c_quirk_set(dev, true);
set_data(chan, 1); set_data(chan, 1);
set_clock(chan, 1); set_clock(chan, 1);
intel_i2c_quirk_set(dev, false);
udelay(20); udelay(20);
return chan; return chan;
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <linux/fb.h> #include <linux/fb.h>
#include "drmP.h" #include "drmP.h"
#include "intel_drv.h" #include "intel_drv.h"
#include "i915_drv.h"
/** /**
* intel_ddc_probe * intel_ddc_probe
...@@ -52,7 +53,10 @@ bool intel_ddc_probe(struct intel_output *intel_output) ...@@ -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); ret = i2c_transfer(&intel_output->ddc_bus->adapter, msgs, 2);
intel_i2c_quirk_set(intel_output->ddc_bus->drm_dev, false);
if (ret == 2) if (ret == 2)
return true; return true;
...@@ -70,8 +74,10 @@ int intel_ddc_get_modes(struct intel_output *intel_output) ...@@ -70,8 +74,10 @@ int intel_ddc_get_modes(struct intel_output *intel_output)
struct edid *edid; struct edid *edid;
int ret = 0; int ret = 0;
intel_i2c_quirk_set(intel_output->ddc_bus->drm_dev, true);
edid = drm_get_edid(&intel_output->base, edid = drm_get_edid(&intel_output->base,
&intel_output->ddc_bus->adapter); &intel_output->ddc_bus->adapter);
intel_i2c_quirk_set(intel_output->ddc_bus->drm_dev, false);
if (edid) { if (edid) {
drm_mode_connector_update_edid_property(&intel_output->base, drm_mode_connector_update_edid_property(&intel_output->base,
edid); edid);
......
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