diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-02-25 16:46:44 -0800 | 
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-02-25 16:46:44 -0800 | 
| commit | fffddfd6c8e0c10c42c6e2cc54ba880fcc36ebbb (patch) | |
| tree | 71bc5e597124dbaf7550f1e089d675718b3ed5c0 /drivers/gpu/drm/i915/intel_i2c.c | |
| parent | 69086a78bdc973ec0b722be790b146e84ba8a8c4 (diff) | |
| parent | be88298b0a3f771a4802f20c5e66af74bfd1dff1 (diff) | |
| download | olio-linux-3.10-fffddfd6c8e0c10c42c6e2cc54ba880fcc36ebbb.tar.xz olio-linux-3.10-fffddfd6c8e0c10c42c6e2cc54ba880fcc36ebbb.zip  | |
Merge branch 'drm-next' of git://people.freedesktop.org/~airlied/linux
Pull drm merge from Dave Airlie:
 "Highlights:
   - TI LCD controller KMS driver
   - TI OMAP KMS driver merged from staging
   - drop gma500 stub driver
   - the fbcon locking fixes
   - the vgacon dirty like zebra fix.
   - open firmware videomode and hdmi common code helpers
   - major locking rework for kms object handling - pageflip/cursor
     won't block on polling anymore!
   - fbcon helper and prime helper cleanups
   - i915: all over the map, haswell power well enhancements, valleyview
     macro horrors cleaned up, killing lots of legacy GTT code,
   - radeon: CS ioctl unification, deprecated UMS support, gpu reset
     rework, VM fixes
   - nouveau: reworked thermal code, external dp/tmds encoder support
     (anx9805), fences sleep instead of polling,
   - exynos: all over the driver fixes."
Lovely conflict in radeon/evergreen_cs.c between commit de0babd60d8d
("drm/radeon: enforce use of radeon_get_ib_value when reading user cmd")
and the new changes that modified that evergreen_dma_cs_parse()
function.
* 'drm-next' of git://people.freedesktop.org/~airlied/linux: (508 commits)
  drm/tilcdc: only build on arm
  drm/i915: Revert hdmi HDP pin checks
  drm/tegra: Add list of framebuffers to debugfs
  drm/tegra: Fix color expansion
  drm/tegra: Split DC_CMD_STATE_CONTROL register write
  drm/tegra: Implement page-flipping support
  drm/tegra: Implement VBLANK support
  drm/tegra: Implement .mode_set_base()
  drm/tegra: Add plane support
  drm/tegra: Remove bogus tegra_framebuffer structure
  drm: Add consistency check for page-flipping
  drm/radeon: Use generic HDMI infoframe helpers
  drm/tegra: Use generic HDMI infoframe helpers
  drm: Add EDID helper documentation
  drm: Add HDMI infoframe helpers
  video: Add generic HDMI infoframe helpers
  drm: Add some missing forward declarations
  drm: Move mode tables to drm_edid.c
  drm: Remove duplicate drm_mode_cea_vic()
  gma500: Fix n, m1 and m2 clock limits for sdvo and lvds
  ...
Diffstat (limited to 'drivers/gpu/drm/i915/intel_i2c.c')
| -rw-r--r-- | drivers/gpu/drm/i915/intel_i2c.c | 103 | 
1 files changed, 78 insertions, 25 deletions
diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index 3ef5af15b81..acf8aec9ada 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -63,6 +63,7 @@ intel_i2c_reset(struct drm_device *dev)  {  	struct drm_i915_private *dev_priv = dev->dev_private;  	I915_WRITE(dev_priv->gpio_mmio_base + GMBUS0, 0); +	I915_WRITE(dev_priv->gpio_mmio_base + GMBUS4, 0);  }  static void intel_i2c_quirk_set(struct drm_i915_private *dev_priv, bool enable) @@ -202,6 +203,68 @@ intel_gpio_setup(struct intel_gmbus *bus, u32 pin)  	algo->data = bus;  } +#define HAS_GMBUS_IRQ(dev) (INTEL_INFO(dev)->gen >= 4) +static int +gmbus_wait_hw_status(struct drm_i915_private *dev_priv, +		     u32 gmbus2_status, +		     u32 gmbus4_irq_en) +{ +	int i; +	int reg_offset = dev_priv->gpio_mmio_base; +	u32 gmbus2 = 0; +	DEFINE_WAIT(wait); + +	/* Important: The hw handles only the first bit, so set only one! Since +	 * we also need to check for NAKs besides the hw ready/idle signal, we +	 * need to wake up periodically and check that ourselves. */ +	I915_WRITE(GMBUS4 + reg_offset, gmbus4_irq_en); + +	for (i = 0; i < msecs_to_jiffies(50) + 1; i++) { +		prepare_to_wait(&dev_priv->gmbus_wait_queue, &wait, +				TASK_UNINTERRUPTIBLE); + +		gmbus2 = I915_READ_NOTRACE(GMBUS2 + reg_offset); +		if (gmbus2 & (GMBUS_SATOER | gmbus2_status)) +			break; + +		schedule_timeout(1); +	} +	finish_wait(&dev_priv->gmbus_wait_queue, &wait); + +	I915_WRITE(GMBUS4 + reg_offset, 0); + +	if (gmbus2 & GMBUS_SATOER) +		return -ENXIO; +	if (gmbus2 & gmbus2_status) +		return 0; +	return -ETIMEDOUT; +} + +static int +gmbus_wait_idle(struct drm_i915_private *dev_priv) +{ +	int ret; +	int reg_offset = dev_priv->gpio_mmio_base; + +#define C ((I915_READ_NOTRACE(GMBUS2 + reg_offset) & GMBUS_ACTIVE) == 0) + +	if (!HAS_GMBUS_IRQ(dev_priv->dev)) +		return wait_for(C, 10); + +	/* Important: The hw handles only the first bit, so set only one! */ +	I915_WRITE(GMBUS4 + reg_offset, GMBUS_IDLE_EN); + +	ret = wait_event_timeout(dev_priv->gmbus_wait_queue, C, 10); + +	I915_WRITE(GMBUS4 + reg_offset, 0); + +	if (ret) +		return 0; +	else +		return -ETIMEDOUT; +#undef C +} +  static int  gmbus_xfer_read(struct drm_i915_private *dev_priv, struct i2c_msg *msg,  		u32 gmbus1_index) @@ -219,15 +282,11 @@ gmbus_xfer_read(struct drm_i915_private *dev_priv, struct i2c_msg *msg,  	while (len) {  		int ret;  		u32 val, loop = 0; -		u32 gmbus2; -		ret = wait_for((gmbus2 = I915_READ(GMBUS2 + reg_offset)) & -			       (GMBUS_SATOER | GMBUS_HW_RDY), -			       50); +		ret = gmbus_wait_hw_status(dev_priv, GMBUS_HW_RDY, +					   GMBUS_HW_RDY_EN);  		if (ret) -			return -ETIMEDOUT; -		if (gmbus2 & GMBUS_SATOER) -			return -ENXIO; +			return ret;  		val = I915_READ(GMBUS3 + reg_offset);  		do { @@ -261,7 +320,6 @@ gmbus_xfer_write(struct drm_i915_private *dev_priv, struct i2c_msg *msg)  		   GMBUS_SLAVE_WRITE | GMBUS_SW_RDY);  	while (len) {  		int ret; -		u32 gmbus2;  		val = loop = 0;  		do { @@ -270,13 +328,10 @@ gmbus_xfer_write(struct drm_i915_private *dev_priv, struct i2c_msg *msg)  		I915_WRITE(GMBUS3 + reg_offset, val); -		ret = wait_for((gmbus2 = I915_READ(GMBUS2 + reg_offset)) & -			       (GMBUS_SATOER | GMBUS_HW_RDY), -			       50); +		ret = gmbus_wait_hw_status(dev_priv, GMBUS_HW_RDY, +					   GMBUS_HW_RDY_EN);  		if (ret) -			return -ETIMEDOUT; -		if (gmbus2 & GMBUS_SATOER) -			return -ENXIO; +			return ret;  	}  	return 0;  } @@ -345,8 +400,6 @@ gmbus_xfer(struct i2c_adapter *adapter,  	I915_WRITE(GMBUS0 + reg_offset, bus->reg0);  	for (i = 0; i < num; i++) { -		u32 gmbus2; -  		if (gmbus_is_index_read(msgs, i, num)) {  			ret = gmbus_xfer_index_read(dev_priv, &msgs[i]);  			i += 1;  /* set i to the index of the read xfer */ @@ -361,13 +414,12 @@ gmbus_xfer(struct i2c_adapter *adapter,  		if (ret == -ENXIO)  			goto clear_err; -		ret = wait_for((gmbus2 = I915_READ(GMBUS2 + reg_offset)) & -			       (GMBUS_SATOER | GMBUS_HW_WAIT_PHASE), -			       50); +		ret = gmbus_wait_hw_status(dev_priv, GMBUS_HW_WAIT_PHASE, +					   GMBUS_HW_WAIT_EN); +		if (ret == -ENXIO) +			goto clear_err;  		if (ret)  			goto timeout; -		if (gmbus2 & GMBUS_SATOER) -			goto clear_err;  	}  	/* Generate a STOP condition on the bus. Note that gmbus can't generata @@ -380,8 +432,7 @@ gmbus_xfer(struct i2c_adapter *adapter,  	 * We will re-enable it at the start of the next xfer,  	 * till then let it sleep.  	 */ -	if (wait_for((I915_READ(GMBUS2 + reg_offset) & GMBUS_ACTIVE) == 0, -		     10)) { +	if (gmbus_wait_idle(dev_priv)) {  		DRM_DEBUG_KMS("GMBUS [%s] timed out waiting for idle\n",  			 adapter->name);  		ret = -ETIMEDOUT; @@ -405,8 +456,7 @@ clear_err:  	 * it's slow responding and only answers on the 2nd retry.  	 */  	ret = -ENXIO; -	if (wait_for((I915_READ(GMBUS2 + reg_offset) & GMBUS_ACTIVE) == 0, -		     10)) { +	if (gmbus_wait_idle(dev_priv)) {  		DRM_DEBUG_KMS("GMBUS [%s] timed out after NAK\n",  			      adapter->name);  		ret = -ETIMEDOUT; @@ -465,10 +515,13 @@ int intel_setup_gmbus(struct drm_device *dev)  	if (HAS_PCH_SPLIT(dev))  		dev_priv->gpio_mmio_base = PCH_GPIOA - GPIOA; +	else if (IS_VALLEYVIEW(dev)) +		dev_priv->gpio_mmio_base = VLV_DISPLAY_BASE;  	else  		dev_priv->gpio_mmio_base = 0;  	mutex_init(&dev_priv->gmbus_mutex); +	init_waitqueue_head(&dev_priv->gmbus_wait_queue);  	for (i = 0; i < GMBUS_NUM_PORTS; i++) {  		struct intel_gmbus *bus = &dev_priv->gmbus[i];  |