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>
This commit is contained in:
Родитель
13f4c435eb
Коммит
0ba0e9e1f1
|
@ -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
|
||||
|
||||
/*
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
Загрузка…
Ссылка в новой задаче