All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/2] drm/i915: Take forcewake once for the entire GMBUS transaction
@ 2016-08-19 16:45 Chris Wilson
  2016-08-19 16:45 ` [PATCH 2/2] drm/i915: Try GPIO NAK discovery before GMBUS Chris Wilson
                   ` (2 more replies)
  0 siblings, 3 replies; 5+ messages in thread
From: Chris Wilson @ 2016-08-19 16:45 UTC (permalink / raw)
  To: intel-gfx

As we do many register reads within a very short period of time, hold
the GMBUS powerwell from start to finish.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: David Weinehall <david.weinehall@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_i2c.c | 131 +++++++++++++++++++--------------------
 1 file changed, 63 insertions(+), 68 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c
index 1f266d7df2ec..6841c41281a3 100644
--- a/drivers/gpu/drm/i915/intel_i2c.c
+++ b/drivers/gpu/drm/i915/intel_i2c.c
@@ -255,67 +255,59 @@ intel_gpio_setup(struct intel_gmbus *bus, unsigned int pin)
 	algo->data = bus;
 }
 
-static int
-gmbus_wait_hw_status(struct drm_i915_private *dev_priv,
-		     u32 gmbus2_status,
-		     u32 gmbus4_irq_en)
+static int gmbus_wait(struct drm_i915_private *dev_priv, u32 status, u32 irq_en)
 {
-	int i;
-	u32 gmbus2 = 0;
 	DEFINE_WAIT(wait);
-
-	if (!HAS_GMBUS_IRQ(dev_priv))
-		gmbus4_irq_en = 0;
+	u32 gmbus2;
+	int ret;
 
 	/* 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, gmbus4_irq_en);
-
-	for (i = 0; i < msecs_to_jiffies_timeout(50); i++) {
-		prepare_to_wait(&dev_priv->gmbus_wait_queue, &wait,
-				TASK_UNINTERRUPTIBLE);
+	 * need to wake up periodically and check that ourselves.
+	 */
+	if (!HAS_GMBUS_IRQ(dev_priv))
+		irq_en = 0;
 
-		gmbus2 = I915_READ_NOTRACE(GMBUS2);
-		if (gmbus2 & (GMBUS_SATOER | gmbus2_status))
-			break;
+	add_wait_queue(&dev_priv->gmbus_wait_queue, &wait);
+	I915_WRITE_FW(GMBUS4, irq_en);
 
-		schedule_timeout(1);
-	}
-	finish_wait(&dev_priv->gmbus_wait_queue, &wait);
+	status |= GMBUS_SATOER;
+	ret = wait_for_us((gmbus2 = I915_READ_FW(GMBUS2)) & status, 2);
+	if (ret)
+		ret = wait_for((gmbus2 = I915_READ_FW(GMBUS2)) & status, 50);
 
-	I915_WRITE(GMBUS4, 0);
+	I915_WRITE_FW(GMBUS4, 0);
+	remove_wait_queue(&dev_priv->gmbus_wait_queue, &wait);
 
 	if (gmbus2 & GMBUS_SATOER)
 		return -ENXIO;
-	if (gmbus2 & gmbus2_status)
-		return 0;
-	return -ETIMEDOUT;
+
+	return ret;
 }
 
 static int
 gmbus_wait_idle(struct drm_i915_private *dev_priv)
 {
+	DEFINE_WAIT(wait);
+	u32 irq_enable;
 	int ret;
 
-	if (!HAS_GMBUS_IRQ(dev_priv))
-		return intel_wait_for_register(dev_priv,
-					       GMBUS2, GMBUS_ACTIVE, 0,
-					       10);
-
 	/* Important: The hw handles only the first bit, so set only one! */
-	I915_WRITE(GMBUS4, GMBUS_IDLE_EN);
+	irq_enable = 0;
+	if (HAS_GMBUS_IRQ(dev_priv))
+		irq_enable = GMBUS_IDLE_EN;
 
-	ret = wait_event_timeout(dev_priv->gmbus_wait_queue,
-				 (I915_READ_NOTRACE(GMBUS2) & GMBUS_ACTIVE) == 0,
-				 msecs_to_jiffies_timeout(10));
+	add_wait_queue(&dev_priv->gmbus_wait_queue, &wait);
+	I915_WRITE_FW(GMBUS4, irq_enable);
 
-	I915_WRITE(GMBUS4, 0);
+	ret = intel_wait_for_register_fw(dev_priv,
+					 GMBUS2, GMBUS_ACTIVE, 0,
+					 10);
 
-	if (ret)
-		return 0;
-	else
-		return -ETIMEDOUT;
+	I915_WRITE_FW(GMBUS4, 0);
+	remove_wait_queue(&dev_priv->gmbus_wait_queue, &wait);
+
+	return ret;
 }
 
 static int
@@ -323,22 +315,21 @@ gmbus_xfer_read_chunk(struct drm_i915_private *dev_priv,
 		      unsigned short addr, u8 *buf, unsigned int len,
 		      u32 gmbus1_index)
 {
-	I915_WRITE(GMBUS1,
-		   gmbus1_index |
-		   GMBUS_CYCLE_WAIT |
-		   (len << GMBUS_BYTE_COUNT_SHIFT) |
-		   (addr << GMBUS_SLAVE_ADDR_SHIFT) |
-		   GMBUS_SLAVE_READ | GMBUS_SW_RDY);
+	I915_WRITE_FW(GMBUS1,
+		      gmbus1_index |
+		      GMBUS_CYCLE_WAIT |
+		      (len << GMBUS_BYTE_COUNT_SHIFT) |
+		      (addr << GMBUS_SLAVE_ADDR_SHIFT) |
+		      GMBUS_SLAVE_READ | GMBUS_SW_RDY);
 	while (len) {
 		int ret;
 		u32 val, loop = 0;
 
-		ret = gmbus_wait_hw_status(dev_priv, GMBUS_HW_RDY,
-					   GMBUS_HW_RDY_EN);
+		ret = gmbus_wait(dev_priv, GMBUS_HW_RDY, GMBUS_HW_RDY_EN);
 		if (ret)
 			return ret;
 
-		val = I915_READ(GMBUS3);
+		val = I915_READ_FW(GMBUS3);
 		do {
 			*buf++ = val & 0xff;
 			val >>= 8;
@@ -385,12 +376,12 @@ gmbus_xfer_write_chunk(struct drm_i915_private *dev_priv,
 		len -= 1;
 	}
 
-	I915_WRITE(GMBUS3, val);
-	I915_WRITE(GMBUS1,
-		   GMBUS_CYCLE_WAIT |
-		   (chunk_size << GMBUS_BYTE_COUNT_SHIFT) |
-		   (addr << GMBUS_SLAVE_ADDR_SHIFT) |
-		   GMBUS_SLAVE_WRITE | GMBUS_SW_RDY);
+	I915_WRITE_FW(GMBUS3, val);
+	I915_WRITE_FW(GMBUS1,
+		      GMBUS_CYCLE_WAIT |
+		      (chunk_size << GMBUS_BYTE_COUNT_SHIFT) |
+		      (addr << GMBUS_SLAVE_ADDR_SHIFT) |
+		      GMBUS_SLAVE_WRITE | GMBUS_SW_RDY);
 	while (len) {
 		int ret;
 
@@ -399,10 +390,9 @@ gmbus_xfer_write_chunk(struct drm_i915_private *dev_priv,
 			val |= *buf++ << (8 * loop);
 		} while (--len && ++loop < 4);
 
-		I915_WRITE(GMBUS3, val);
+		I915_WRITE_FW(GMBUS3, val);
 
-		ret = gmbus_wait_hw_status(dev_priv, GMBUS_HW_RDY,
-					   GMBUS_HW_RDY_EN);
+		ret = gmbus_wait(dev_priv, GMBUS_HW_RDY, GMBUS_HW_RDY_EN);
 		if (ret)
 			return ret;
 	}
@@ -460,13 +450,13 @@ gmbus_xfer_index_read(struct drm_i915_private *dev_priv, struct i2c_msg *msgs)
 
 	/* GMBUS5 holds 16-bit index */
 	if (gmbus5)
-		I915_WRITE(GMBUS5, gmbus5);
+		I915_WRITE_FW(GMBUS5, gmbus5);
 
 	ret = gmbus_xfer_read(dev_priv, &msgs[1], gmbus1_index);
 
 	/* Clear GMBUS5 after each index transfer */
 	if (gmbus5)
-		I915_WRITE(GMBUS5, 0);
+		I915_WRITE_FW(GMBUS5, 0);
 
 	return ret;
 }
@@ -478,11 +468,15 @@ do_gmbus_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
 					       struct intel_gmbus,
 					       adapter);
 	struct drm_i915_private *dev_priv = bus->dev_priv;
+	const unsigned int fw =
+		intel_uncore_forcewake_for_reg(dev_priv, GMBUS0,
+					       FW_REG_READ | FW_REG_WRITE);
 	int i = 0, inc, try = 0;
 	int ret = 0;
 
+	intel_uncore_forcewake_get(dev_priv, fw);
 retry:
-	I915_WRITE(GMBUS0, bus->reg0);
+	I915_WRITE_FW(GMBUS0, bus->reg0);
 
 	for (; i < num; i += inc) {
 		inc = 1;
@@ -496,8 +490,8 @@ retry:
 		}
 
 		if (!ret)
-			ret = gmbus_wait_hw_status(dev_priv, GMBUS_HW_WAIT_PHASE,
-						   GMBUS_HW_WAIT_EN);
+			ret = gmbus_wait(dev_priv,
+					 GMBUS_HW_WAIT_PHASE, GMBUS_HW_WAIT_EN);
 		if (ret == -ETIMEDOUT)
 			goto timeout;
 		else if (ret)
@@ -508,7 +502,7 @@ retry:
 	 * a STOP on the very first cycle. To simplify the code we
 	 * unconditionally generate the STOP condition with an additional gmbus
 	 * cycle. */
-	I915_WRITE(GMBUS1, GMBUS_CYCLE_STOP | GMBUS_SW_RDY);
+	I915_WRITE_FW(GMBUS1, GMBUS_CYCLE_STOP | GMBUS_SW_RDY);
 
 	/* Mark the GMBUS interface as disabled after waiting for idle.
 	 * We will re-enable it at the start of the next xfer,
@@ -519,7 +513,7 @@ retry:
 			 adapter->name);
 		ret = -ETIMEDOUT;
 	}
-	I915_WRITE(GMBUS0, 0);
+	I915_WRITE_FW(GMBUS0, 0);
 	ret = ret ?: i;
 	goto out;
 
@@ -548,9 +542,9 @@ clear_err:
 	 * of resetting the GMBUS controller and so clearing the
 	 * BUS_ERROR raised by the slave's NAK.
 	 */
-	I915_WRITE(GMBUS1, GMBUS_SW_CLR_INT);
-	I915_WRITE(GMBUS1, 0);
-	I915_WRITE(GMBUS0, 0);
+	I915_WRITE_FW(GMBUS1, GMBUS_SW_CLR_INT);
+	I915_WRITE_FW(GMBUS1, 0);
+	I915_WRITE_FW(GMBUS0, 0);
 
 	DRM_DEBUG_KMS("GMBUS [%s] NAK for addr: %04x %c(%d)\n",
 			 adapter->name, msgs[i].addr,
@@ -573,7 +567,7 @@ clear_err:
 timeout:
 	DRM_DEBUG_KMS("GMBUS [%s] timed out, falling back to bit banging on pin %d\n",
 		      bus->adapter.name, bus->reg0 & 0xff);
-	I915_WRITE(GMBUS0, 0);
+	I915_WRITE_FW(GMBUS0, 0);
 
 	/*
 	 * Hardware may not support GMBUS over these pins? Try GPIO bitbanging
@@ -582,6 +576,7 @@ timeout:
 	ret = -EAGAIN;
 
 out:
+	intel_uncore_forcewake_put(dev_priv, fw);
 	return ret;
 }
 
-- 
2.9.3

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 2/2] drm/i915: Try GPIO NAK discovery before GMBUS
  2016-08-19 16:45 [PATCH 1/2] drm/i915: Take forcewake once for the entire GMBUS transaction Chris Wilson
@ 2016-08-19 16:45 ` Chris Wilson
  2016-08-22 16:52   ` David Weinehall
  2016-08-19 17:11 ` ✗ Ro.CI.BAT: failure for series starting with [1/2] drm/i915: Take forcewake once for the entire GMBUS transaction Patchwork
  2016-08-22 16:42 ` [PATCH 1/2] " David Weinehall
  2 siblings, 1 reply; 5+ messages in thread
From: Chris Wilson @ 2016-08-19 16:45 UTC (permalink / raw)
  To: intel-gfx

Some GMBUS devices fail to report NAKs (even recent Skylakes), resulting
in us hitting the 50ms timeout every time we try to read an EDID on a
disconnected device. Try a quick GPIO discovery first by setting the
clock line and seeing if the device responds.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: David Weinehall <david.weinehall@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_i2c.c | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c
index 6841c41281a3..72945a7c5547 100644
--- a/drivers/gpu/drm/i915/intel_i2c.c
+++ b/drivers/gpu/drm/i915/intel_i2c.c
@@ -461,6 +461,22 @@ gmbus_xfer_index_read(struct drm_i915_private *dev_priv, struct i2c_msg *msgs)
 	return ret;
 }
 
+static bool gpio_is_alive(struct intel_gmbus *bus)
+{
+	bool result = true;
+
+	intel_i2c_quirk_set(bus->dev_priv, true);
+	set_clock(bus, 1);
+
+	if (wait_for_us(get_clock(bus), 10) && wait_for(get_clock(bus), 2))
+		result = false;
+
+	set_clock(bus, 0);
+	intel_i2c_quirk_set(bus->dev_priv, false);
+
+	return result;
+}
+
 static int
 do_gmbus_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
 {
@@ -474,6 +490,13 @@ do_gmbus_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
 	int i = 0, inc, try = 0;
 	int ret = 0;
 
+	/* Some GMBUS devices fail to report NAKs and so we hit the 50ms
+	 * timeout, every time. Try a quick GPIO discovery first by seeing
+	 * if the device responds to setting the clock line high.
+	 */
+	if (!gpio_is_alive(bus))
+		return -ENXIO;
+
 	intel_uncore_forcewake_get(dev_priv, fw);
 retry:
 	I915_WRITE_FW(GMBUS0, bus->reg0);
-- 
2.9.3

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* ✗ Ro.CI.BAT: failure for series starting with [1/2] drm/i915: Take forcewake once for the entire GMBUS transaction
  2016-08-19 16:45 [PATCH 1/2] drm/i915: Take forcewake once for the entire GMBUS transaction Chris Wilson
  2016-08-19 16:45 ` [PATCH 2/2] drm/i915: Try GPIO NAK discovery before GMBUS Chris Wilson
@ 2016-08-19 17:11 ` Patchwork
  2016-08-22 16:42 ` [PATCH 1/2] " David Weinehall
  2 siblings, 0 replies; 5+ messages in thread
From: Patchwork @ 2016-08-19 17:11 UTC (permalink / raw)
  To: Chris Wilson; +Cc: intel-gfx

== Series Details ==

Series: series starting with [1/2] drm/i915: Take forcewake once for the entire GMBUS transaction
URL   : https://patchwork.freedesktop.org/series/11332/
State : failure

== Summary ==

Series 11332v1 Series without cover letter
http://patchwork.freedesktop.org/api/1.0/series/11332/revisions/1/mbox

Test gem_exec_gttfill:
        Subgroup basic:
                pass       -> SKIP       (fi-snb-i7-2600)
Test kms_cursor_legacy:
        Subgroup basic-cursor-vs-flip-legacy:
                dmesg-warn -> PASS       (ro-bdw-i5-5250u)
        Subgroup basic-cursor-vs-flip-varying-size:
                dmesg-warn -> PASS       (ro-bdw-i5-5250u)
        Subgroup basic-flip-vs-cursor-varying-size:
                pass       -> FAIL       (ro-skl3-i5-6260u)
Test kms_pipe_crc_basic:
        Subgroup suspend-read-crc-pipe-b:
                dmesg-warn -> SKIP       (ro-bdw-i5-5250u)
        Subgroup suspend-read-crc-pipe-c:
                skip       -> PASS       (fi-hsw-i7-4770k)
                pass       -> DMESG-WARN (ro-bdw-i7-5600u)

fi-hsw-i7-4770k  total:244  pass:222  dwarn:0   dfail:0   fail:0   skip:22 
fi-kbl-qkkr      total:244  pass:185  dwarn:30  dfail:0   fail:2   skip:27 
fi-snb-i7-2600   total:244  pass:201  dwarn:0   dfail:0   fail:0   skip:43 
ro-bdw-i5-5250u  total:240  pass:220  dwarn:1   dfail:0   fail:0   skip:19 
ro-bdw-i7-5600u  total:240  pass:205  dwarn:1   dfail:0   fail:2   skip:32 
ro-bsw-n3050     total:240  pass:195  dwarn:0   dfail:0   fail:3   skip:42 
ro-byt-n2820     total:240  pass:196  dwarn:0   dfail:0   fail:4   skip:40 
ro-hsw-i3-4010u  total:240  pass:213  dwarn:0   dfail:0   fail:1   skip:26 
ro-hsw-i7-4770r  total:240  pass:185  dwarn:0   dfail:0   fail:0   skip:55 
ro-ilk1-i5-650   total:235  pass:174  dwarn:0   dfail:0   fail:2   skip:59 
ro-ivb-i7-3770   total:240  pass:204  dwarn:0   dfail:0   fail:1   skip:35 
ro-ivb2-i7-3770  total:240  pass:208  dwarn:0   dfail:0   fail:1   skip:31 
ro-skl3-i5-6260u total:240  pass:222  dwarn:0   dfail:0   fail:4   skip:14 
fi-skl-i7-6700k failed to connect after reboot
ro-bdw-i7-5557U failed to connect after reboot

Results at /archive/results/CI_IGT_test/RO_Patchwork_1946/

f53a8d1 drm-intel-nightly: 2016y-08m-19d-16h-24m-21s UTC integration manifest
dc57725 drm/i915: Try GPIO NAK discovery before GMBUS
b9da26f drm/i915: Take forcewake once for the entire GMBUS transaction

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 1/2] drm/i915: Take forcewake once for the entire GMBUS transaction
  2016-08-19 16:45 [PATCH 1/2] drm/i915: Take forcewake once for the entire GMBUS transaction Chris Wilson
  2016-08-19 16:45 ` [PATCH 2/2] drm/i915: Try GPIO NAK discovery before GMBUS Chris Wilson
  2016-08-19 17:11 ` ✗ Ro.CI.BAT: failure for series starting with [1/2] drm/i915: Take forcewake once for the entire GMBUS transaction Patchwork
@ 2016-08-22 16:42 ` David Weinehall
  2 siblings, 0 replies; 5+ messages in thread
From: David Weinehall @ 2016-08-22 16:42 UTC (permalink / raw)
  To: Chris Wilson; +Cc: intel-gfx

On Fri, Aug 19, 2016 at 05:45:02PM +0100, Chris Wilson wrote:
> As we do many register reads within a very short period of time, hold
> the GMBUS powerwell from start to finish.
> 
> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> Cc: David Weinehall <david.weinehall@linux.intel.com>

Looks good, works well.

Reviewed-by: David Weinehall <david.weinehall@linux.intel.com>

> ---
>  drivers/gpu/drm/i915/intel_i2c.c | 131 +++++++++++++++++++--------------------
>  1 file changed, 63 insertions(+), 68 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c
> index 1f266d7df2ec..6841c41281a3 100644
> --- a/drivers/gpu/drm/i915/intel_i2c.c
> +++ b/drivers/gpu/drm/i915/intel_i2c.c
> @@ -255,67 +255,59 @@ intel_gpio_setup(struct intel_gmbus *bus, unsigned int pin)
>  	algo->data = bus;
>  }
>  
> -static int
> -gmbus_wait_hw_status(struct drm_i915_private *dev_priv,
> -		     u32 gmbus2_status,
> -		     u32 gmbus4_irq_en)
> +static int gmbus_wait(struct drm_i915_private *dev_priv, u32 status, u32 irq_en)
>  {
> -	int i;
> -	u32 gmbus2 = 0;
>  	DEFINE_WAIT(wait);
> -
> -	if (!HAS_GMBUS_IRQ(dev_priv))
> -		gmbus4_irq_en = 0;
> +	u32 gmbus2;
> +	int ret;
>  
>  	/* 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, gmbus4_irq_en);
> -
> -	for (i = 0; i < msecs_to_jiffies_timeout(50); i++) {
> -		prepare_to_wait(&dev_priv->gmbus_wait_queue, &wait,
> -				TASK_UNINTERRUPTIBLE);
> +	 * need to wake up periodically and check that ourselves.
> +	 */
> +	if (!HAS_GMBUS_IRQ(dev_priv))
> +		irq_en = 0;
>  
> -		gmbus2 = I915_READ_NOTRACE(GMBUS2);
> -		if (gmbus2 & (GMBUS_SATOER | gmbus2_status))
> -			break;
> +	add_wait_queue(&dev_priv->gmbus_wait_queue, &wait);
> +	I915_WRITE_FW(GMBUS4, irq_en);
>  
> -		schedule_timeout(1);
> -	}
> -	finish_wait(&dev_priv->gmbus_wait_queue, &wait);
> +	status |= GMBUS_SATOER;
> +	ret = wait_for_us((gmbus2 = I915_READ_FW(GMBUS2)) & status, 2);
> +	if (ret)
> +		ret = wait_for((gmbus2 = I915_READ_FW(GMBUS2)) & status, 50);
>  
> -	I915_WRITE(GMBUS4, 0);
> +	I915_WRITE_FW(GMBUS4, 0);
> +	remove_wait_queue(&dev_priv->gmbus_wait_queue, &wait);
>  
>  	if (gmbus2 & GMBUS_SATOER)
>  		return -ENXIO;
> -	if (gmbus2 & gmbus2_status)
> -		return 0;
> -	return -ETIMEDOUT;
> +
> +	return ret;
>  }
>  
>  static int
>  gmbus_wait_idle(struct drm_i915_private *dev_priv)
>  {
> +	DEFINE_WAIT(wait);
> +	u32 irq_enable;
>  	int ret;
>  
> -	if (!HAS_GMBUS_IRQ(dev_priv))
> -		return intel_wait_for_register(dev_priv,
> -					       GMBUS2, GMBUS_ACTIVE, 0,
> -					       10);
> -
>  	/* Important: The hw handles only the first bit, so set only one! */
> -	I915_WRITE(GMBUS4, GMBUS_IDLE_EN);
> +	irq_enable = 0;
> +	if (HAS_GMBUS_IRQ(dev_priv))
> +		irq_enable = GMBUS_IDLE_EN;
>  
> -	ret = wait_event_timeout(dev_priv->gmbus_wait_queue,
> -				 (I915_READ_NOTRACE(GMBUS2) & GMBUS_ACTIVE) == 0,
> -				 msecs_to_jiffies_timeout(10));
> +	add_wait_queue(&dev_priv->gmbus_wait_queue, &wait);
> +	I915_WRITE_FW(GMBUS4, irq_enable);
>  
> -	I915_WRITE(GMBUS4, 0);
> +	ret = intel_wait_for_register_fw(dev_priv,
> +					 GMBUS2, GMBUS_ACTIVE, 0,
> +					 10);
>  
> -	if (ret)
> -		return 0;
> -	else
> -		return -ETIMEDOUT;
> +	I915_WRITE_FW(GMBUS4, 0);
> +	remove_wait_queue(&dev_priv->gmbus_wait_queue, &wait);
> +
> +	return ret;
>  }
>  
>  static int
> @@ -323,22 +315,21 @@ gmbus_xfer_read_chunk(struct drm_i915_private *dev_priv,
>  		      unsigned short addr, u8 *buf, unsigned int len,
>  		      u32 gmbus1_index)
>  {
> -	I915_WRITE(GMBUS1,
> -		   gmbus1_index |
> -		   GMBUS_CYCLE_WAIT |
> -		   (len << GMBUS_BYTE_COUNT_SHIFT) |
> -		   (addr << GMBUS_SLAVE_ADDR_SHIFT) |
> -		   GMBUS_SLAVE_READ | GMBUS_SW_RDY);
> +	I915_WRITE_FW(GMBUS1,
> +		      gmbus1_index |
> +		      GMBUS_CYCLE_WAIT |
> +		      (len << GMBUS_BYTE_COUNT_SHIFT) |
> +		      (addr << GMBUS_SLAVE_ADDR_SHIFT) |
> +		      GMBUS_SLAVE_READ | GMBUS_SW_RDY);
>  	while (len) {
>  		int ret;
>  		u32 val, loop = 0;
>  
> -		ret = gmbus_wait_hw_status(dev_priv, GMBUS_HW_RDY,
> -					   GMBUS_HW_RDY_EN);
> +		ret = gmbus_wait(dev_priv, GMBUS_HW_RDY, GMBUS_HW_RDY_EN);
>  		if (ret)
>  			return ret;
>  
> -		val = I915_READ(GMBUS3);
> +		val = I915_READ_FW(GMBUS3);
>  		do {
>  			*buf++ = val & 0xff;
>  			val >>= 8;
> @@ -385,12 +376,12 @@ gmbus_xfer_write_chunk(struct drm_i915_private *dev_priv,
>  		len -= 1;
>  	}
>  
> -	I915_WRITE(GMBUS3, val);
> -	I915_WRITE(GMBUS1,
> -		   GMBUS_CYCLE_WAIT |
> -		   (chunk_size << GMBUS_BYTE_COUNT_SHIFT) |
> -		   (addr << GMBUS_SLAVE_ADDR_SHIFT) |
> -		   GMBUS_SLAVE_WRITE | GMBUS_SW_RDY);
> +	I915_WRITE_FW(GMBUS3, val);
> +	I915_WRITE_FW(GMBUS1,
> +		      GMBUS_CYCLE_WAIT |
> +		      (chunk_size << GMBUS_BYTE_COUNT_SHIFT) |
> +		      (addr << GMBUS_SLAVE_ADDR_SHIFT) |
> +		      GMBUS_SLAVE_WRITE | GMBUS_SW_RDY);
>  	while (len) {
>  		int ret;
>  
> @@ -399,10 +390,9 @@ gmbus_xfer_write_chunk(struct drm_i915_private *dev_priv,
>  			val |= *buf++ << (8 * loop);
>  		} while (--len && ++loop < 4);
>  
> -		I915_WRITE(GMBUS3, val);
> +		I915_WRITE_FW(GMBUS3, val);
>  
> -		ret = gmbus_wait_hw_status(dev_priv, GMBUS_HW_RDY,
> -					   GMBUS_HW_RDY_EN);
> +		ret = gmbus_wait(dev_priv, GMBUS_HW_RDY, GMBUS_HW_RDY_EN);
>  		if (ret)
>  			return ret;
>  	}
> @@ -460,13 +450,13 @@ gmbus_xfer_index_read(struct drm_i915_private *dev_priv, struct i2c_msg *msgs)
>  
>  	/* GMBUS5 holds 16-bit index */
>  	if (gmbus5)
> -		I915_WRITE(GMBUS5, gmbus5);
> +		I915_WRITE_FW(GMBUS5, gmbus5);
>  
>  	ret = gmbus_xfer_read(dev_priv, &msgs[1], gmbus1_index);
>  
>  	/* Clear GMBUS5 after each index transfer */
>  	if (gmbus5)
> -		I915_WRITE(GMBUS5, 0);
> +		I915_WRITE_FW(GMBUS5, 0);
>  
>  	return ret;
>  }
> @@ -478,11 +468,15 @@ do_gmbus_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
>  					       struct intel_gmbus,
>  					       adapter);
>  	struct drm_i915_private *dev_priv = bus->dev_priv;
> +	const unsigned int fw =
> +		intel_uncore_forcewake_for_reg(dev_priv, GMBUS0,
> +					       FW_REG_READ | FW_REG_WRITE);
>  	int i = 0, inc, try = 0;
>  	int ret = 0;
>  
> +	intel_uncore_forcewake_get(dev_priv, fw);
>  retry:
> -	I915_WRITE(GMBUS0, bus->reg0);
> +	I915_WRITE_FW(GMBUS0, bus->reg0);
>  
>  	for (; i < num; i += inc) {
>  		inc = 1;
> @@ -496,8 +490,8 @@ retry:
>  		}
>  
>  		if (!ret)
> -			ret = gmbus_wait_hw_status(dev_priv, GMBUS_HW_WAIT_PHASE,
> -						   GMBUS_HW_WAIT_EN);
> +			ret = gmbus_wait(dev_priv,
> +					 GMBUS_HW_WAIT_PHASE, GMBUS_HW_WAIT_EN);
>  		if (ret == -ETIMEDOUT)
>  			goto timeout;
>  		else if (ret)
> @@ -508,7 +502,7 @@ retry:
>  	 * a STOP on the very first cycle. To simplify the code we
>  	 * unconditionally generate the STOP condition with an additional gmbus
>  	 * cycle. */
> -	I915_WRITE(GMBUS1, GMBUS_CYCLE_STOP | GMBUS_SW_RDY);
> +	I915_WRITE_FW(GMBUS1, GMBUS_CYCLE_STOP | GMBUS_SW_RDY);
>  
>  	/* Mark the GMBUS interface as disabled after waiting for idle.
>  	 * We will re-enable it at the start of the next xfer,
> @@ -519,7 +513,7 @@ retry:
>  			 adapter->name);
>  		ret = -ETIMEDOUT;
>  	}
> -	I915_WRITE(GMBUS0, 0);
> +	I915_WRITE_FW(GMBUS0, 0);
>  	ret = ret ?: i;
>  	goto out;
>  
> @@ -548,9 +542,9 @@ clear_err:
>  	 * of resetting the GMBUS controller and so clearing the
>  	 * BUS_ERROR raised by the slave's NAK.
>  	 */
> -	I915_WRITE(GMBUS1, GMBUS_SW_CLR_INT);
> -	I915_WRITE(GMBUS1, 0);
> -	I915_WRITE(GMBUS0, 0);
> +	I915_WRITE_FW(GMBUS1, GMBUS_SW_CLR_INT);
> +	I915_WRITE_FW(GMBUS1, 0);
> +	I915_WRITE_FW(GMBUS0, 0);
>  
>  	DRM_DEBUG_KMS("GMBUS [%s] NAK for addr: %04x %c(%d)\n",
>  			 adapter->name, msgs[i].addr,
> @@ -573,7 +567,7 @@ clear_err:
>  timeout:
>  	DRM_DEBUG_KMS("GMBUS [%s] timed out, falling back to bit banging on pin %d\n",
>  		      bus->adapter.name, bus->reg0 & 0xff);
> -	I915_WRITE(GMBUS0, 0);
> +	I915_WRITE_FW(GMBUS0, 0);
>  
>  	/*
>  	 * Hardware may not support GMBUS over these pins? Try GPIO bitbanging
> @@ -582,6 +576,7 @@ timeout:
>  	ret = -EAGAIN;
>  
>  out:
> +	intel_uncore_forcewake_put(dev_priv, fw);
>  	return ret;
>  }
>  
> -- 
> 2.9.3
> 
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 2/2] drm/i915: Try GPIO NAK discovery before GMBUS
  2016-08-19 16:45 ` [PATCH 2/2] drm/i915: Try GPIO NAK discovery before GMBUS Chris Wilson
@ 2016-08-22 16:52   ` David Weinehall
  0 siblings, 0 replies; 5+ messages in thread
From: David Weinehall @ 2016-08-22 16:52 UTC (permalink / raw)
  To: Chris Wilson; +Cc: intel-gfx

On Fri, Aug 19, 2016 at 05:45:03PM +0100, Chris Wilson wrote:
> Some GMBUS devices fail to report NAKs (even recent Skylakes), resulting
> in us hitting the 50ms timeout every time we try to read an EDID on a
> disconnected device. Try a quick GPIO discovery first by setting the
> clock line and seeing if the device responds.

Sadly doesn't work.  Doesn't make a difference on the problematic port
(HDMI-A-2 on a ThinkPad 13) -- still very slow, nor on the
non-problematic port (HDMI-A-1 on the same laptop) -- still fast,
but seems to make things a lot worse on HDMI-A-1 when there *is*
a display connected -- incredibly slow.

So, ironically I'd say NAK to the NAK-patch.


Kind regards, David Weinehall

> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> Cc: David Weinehall <david.weinehall@linux.intel.com>
> ---
>  drivers/gpu/drm/i915/intel_i2c.c | 23 +++++++++++++++++++++++
>  1 file changed, 23 insertions(+)
> 
> diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c
> index 6841c41281a3..72945a7c5547 100644
> --- a/drivers/gpu/drm/i915/intel_i2c.c
> +++ b/drivers/gpu/drm/i915/intel_i2c.c
> @@ -461,6 +461,22 @@ gmbus_xfer_index_read(struct drm_i915_private *dev_priv, struct i2c_msg *msgs)
>  	return ret;
>  }
>  
> +static bool gpio_is_alive(struct intel_gmbus *bus)
> +{
> +	bool result = true;
> +
> +	intel_i2c_quirk_set(bus->dev_priv, true);
> +	set_clock(bus, 1);
> +
> +	if (wait_for_us(get_clock(bus), 10) && wait_for(get_clock(bus), 2))
> +		result = false;
> +
> +	set_clock(bus, 0);
> +	intel_i2c_quirk_set(bus->dev_priv, false);
> +
> +	return result;
> +}
> +
>  static int
>  do_gmbus_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
>  {
> @@ -474,6 +490,13 @@ do_gmbus_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
>  	int i = 0, inc, try = 0;
>  	int ret = 0;
>  
> +	/* Some GMBUS devices fail to report NAKs and so we hit the 50ms
> +	 * timeout, every time. Try a quick GPIO discovery first by seeing
> +	 * if the device responds to setting the clock line high.
> +	 */
> +	if (!gpio_is_alive(bus))
> +		return -ENXIO;
> +
>  	intel_uncore_forcewake_get(dev_priv, fw);
>  retry:
>  	I915_WRITE_FW(GMBUS0, bus->reg0);
> -- 
> 2.9.3
> 
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2016-08-22 16:52 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-08-19 16:45 [PATCH 1/2] drm/i915: Take forcewake once for the entire GMBUS transaction Chris Wilson
2016-08-19 16:45 ` [PATCH 2/2] drm/i915: Try GPIO NAK discovery before GMBUS Chris Wilson
2016-08-22 16:52   ` David Weinehall
2016-08-19 17:11 ` ✗ Ro.CI.BAT: failure for series starting with [1/2] drm/i915: Take forcewake once for the entire GMBUS transaction Patchwork
2016-08-22 16:42 ` [PATCH 1/2] " David Weinehall

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.