drm/i915: Reset GMBUS controller after NAK

Once a NAK has been asserted by the slave, we need to reset the GMBUS
controller in order to continue. This is done by asserting the Software
Clear Interrupt bit and then clearing it again to restore operations.

If we don't clear the NAK, then all future GMBUS xfers will fail,
including DDC probes and EDID retrieval.

v2: Add some comments as suggested by Keith Packard.

Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=35781
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Keith Packard <keithp@keithp.com>
Tested-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Tested-by: "Mengmeng Meng" <mengmeng.meng@intel.com>
This commit is contained in:
Chris Wilson 2011-03-30 16:20:43 +01:00
parent 9f01b25048
commit 7f58aabc36
1 changed files with 21 additions and 4 deletions

View File

@ -259,7 +259,7 @@ gmbus_xfer(struct i2c_adapter *adapter,
if (wait_for(I915_READ(GMBUS2 + reg_offset) & (GMBUS_SATOER | GMBUS_HW_RDY), 50)) if (wait_for(I915_READ(GMBUS2 + reg_offset) & (GMBUS_SATOER | GMBUS_HW_RDY), 50))
goto timeout; goto timeout;
if (I915_READ(GMBUS2 + reg_offset) & GMBUS_SATOER) if (I915_READ(GMBUS2 + reg_offset) & GMBUS_SATOER)
return 0; goto clear_err;
val = I915_READ(GMBUS3 + reg_offset); val = I915_READ(GMBUS3 + reg_offset);
do { do {
@ -287,7 +287,7 @@ gmbus_xfer(struct i2c_adapter *adapter,
if (wait_for(I915_READ(GMBUS2 + reg_offset) & (GMBUS_SATOER | GMBUS_HW_RDY), 50)) if (wait_for(I915_READ(GMBUS2 + reg_offset) & (GMBUS_SATOER | GMBUS_HW_RDY), 50))
goto timeout; goto timeout;
if (I915_READ(GMBUS2 + reg_offset) & GMBUS_SATOER) if (I915_READ(GMBUS2 + reg_offset) & GMBUS_SATOER)
return 0; goto clear_err;
val = loop = 0; val = loop = 0;
do { do {
@ -302,14 +302,31 @@ gmbus_xfer(struct i2c_adapter *adapter,
if (i + 1 < num && wait_for(I915_READ(GMBUS2 + reg_offset) & (GMBUS_SATOER | GMBUS_HW_WAIT_PHASE), 50)) if (i + 1 < num && wait_for(I915_READ(GMBUS2 + reg_offset) & (GMBUS_SATOER | GMBUS_HW_WAIT_PHASE), 50))
goto timeout; goto timeout;
if (I915_READ(GMBUS2 + reg_offset) & GMBUS_SATOER) if (I915_READ(GMBUS2 + reg_offset) & GMBUS_SATOER)
return 0; goto clear_err;
} }
return num; goto done;
clear_err:
/* Toggle the Software Clear Interrupt bit. This has the effect
* of resetting the GMBUS controller and so clearing the
* BUS_ERROR raised by the slave's NAK.
*/
I915_WRITE(GMBUS1 + reg_offset, GMBUS_SW_CLR_INT);
I915_WRITE(GMBUS1 + reg_offset, 0);
done:
/* Mark the GMBUS interface as disabled. We will re-enable it at the
* start of the next xfer, till then let it sleep.
*/
I915_WRITE(GMBUS0 + reg_offset, 0);
return i;
timeout: timeout:
DRM_INFO("GMBUS timed out, falling back to bit banging on pin %d [%s]\n", DRM_INFO("GMBUS timed out, falling back to bit banging on pin %d [%s]\n",
bus->reg0 & 0xff, bus->adapter.name); bus->reg0 & 0xff, bus->adapter.name);
I915_WRITE(GMBUS0 + reg_offset, 0);
/* Hardware may not support GMBUS over these pins? Try GPIO bitbanging instead. */ /* Hardware may not support GMBUS over these pins? Try GPIO bitbanging instead. */
bus->force_bit = intel_gpio_create(dev_priv, bus->reg0 & 0xff); bus->force_bit = intel_gpio_create(dev_priv, bus->reg0 & 0xff);
if (!bus->force_bit) if (!bus->force_bit)