Skip to contentSkip to conversation

drm/i915 Avoid long delays when reading EDID on eDP

PATCH In review Egbert Eich 4 participants 11 messages Nov 24, 2014 – Nov 26, 2014

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

cover drm/i915 Avoid long delays when reading EDID on eDP

For eDP in the Intel driver pps_lock()/unlock() need to be called before initiating an I2C/AUX channel transfer. These operations can be quite expensive - especially on values for HZ lower than 1000.
It is therefore better to perfrom this locking/unlocking only once, ie at the beginning and at the end of the entire I2C transfer. The current design of drm_dp_helper.c doesn't allow this. This patchset modifies drm_dp_helper.c and moves the locking/unlocking operation to the top.
This fixes the long delay observed in
https://bugs.freedesktop.org/show_bug.cgi?id=86201

Egbert Eich (4):
drm/DP: Create pointer to generic DPCD access function drm/DP: Export drm_dp_i2c_xfer() DP helper function drm/DP: Export drm_dp_dpcd_access() DP helper function drm/i915/eDP: Move pps_lock() and edp_panel_vdd_on() to top

Ville Syrjälä (1):
drm/i915: Try to avoid pps_{lock,unlock}() on DP ports

 drivers/gpu/drm/drm_dp_helper.c  |  11 ++--
 drivers/gpu/drm/i915/intel_dp.c  | 132 +++++++++++++++++++++++++++++++--------
 drivers/gpu/drm/i915/intel_drv.h |   5 ++
 include/drm/drm_dp_helper.h      |  14 +++++
 4 files changed, 133 insertions(+), 29 deletions(-)
Signature · 6 lines
1.8.4.5

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
#1 lore raw

PATCH 1/5 drm/i915: Try to avoid pps_{lock, unlock}() on DP ports

From: Ville Syrjälä <[email protected]>

---
 drivers/gpu/drm/i915/intel_dp.c | 48 ++++++++++++++++++++++++-----------------
 1 file changed, 28 insertions(+), 20 deletions(-)
drivers/gpu/drm/i915/intel_dp.c +28 -20
index 81f959d..a24c8cc7 100644
@@ -807,17 +807,19 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
 	uint32_t status;
 	int try, clock = 0;
 	bool has_aux_irq = HAS_AUX_IRQ(dev);
-	bool vdd;
+	bool vdd = false;
 
-	pps_lock(intel_dp);
+	if (is_edp(intel_dp)) {
+		pps_lock(intel_dp);
 
-	/*
-	 * We will be called with VDD already enabled for dpcd/edid/oui reads.
-	 * In such cases we want to leave VDD enabled and it's up to upper layers
-	 * to turn it off. But for eg. i2c-dev access we need to turn it on/off
-	 * ourselves.
-	 */
-	vdd = edp_panel_vdd_on(intel_dp);
+		/*
+		 * We will be called with VDD already enabled for dpcd/edid/oui reads.
+		 * In such cases we want to leave VDD enabled and it's up to upper layers
+		 * to turn it off. But for eg. i2c-dev access we need to turn it on/off
+		 * ourselves.
+		 */
+		vdd = edp_panel_vdd_on(intel_dp);
+	}
 
 	/* dp aux is extremely sensitive to irq latency, hence request the
 	 * lowest possible wakeup latency and so prevent the cpu from going into
@@ -924,10 +926,12 @@ out:
 	pm_qos_update_request(&dev_priv->pm_qos, PM_QOS_DEFAULT_VALUE);
 	intel_aux_display_runtime_put(dev_priv);
 
-	if (vdd)
-		edp_panel_vdd_off(intel_dp, false);
+	if (is_edp(intel_dp)) {
+		if (vdd)
+			edp_panel_vdd_off(intel_dp, false);
 
-	pps_unlock(intel_dp);
+		pps_unlock(intel_dp);
+	}
 
 	return ret;
 }
@@ -2291,18 +2295,22 @@ static void intel_enable_dp(struct intel_encoder *encoder)
 	if (WARN_ON(dp_reg & DP_PORT_EN))
 		return;
 
-	pps_lock(intel_dp);
+	if (is_edp(intel_dp)) {
+		pps_lock(intel_dp);
 
-	if (IS_VALLEYVIEW(dev))
-		vlv_init_panel_power_sequencer(intel_dp);
+		if (IS_VALLEYVIEW(dev))
+			vlv_init_panel_power_sequencer(intel_dp);
 
-	intel_dp_enable_port(intel_dp);
+		intel_dp_enable_port(intel_dp);
 
-	edp_panel_vdd_on(intel_dp);
-	edp_panel_on(intel_dp);
-	edp_panel_vdd_off(intel_dp, true);
+		edp_panel_vdd_on(intel_dp);
+		edp_panel_on(intel_dp);
+		edp_panel_vdd_off(intel_dp, true);
 
-	pps_unlock(intel_dp);
+		pps_unlock(intel_dp);
+	} else {
+		intel_dp_enable_port(intel_dp);
+	}
 
 	if (IS_VALLEYVIEW(dev))
 		vlv_wait_port_ready(dev_priv, dp_to_dig_port(intel_dp));
Signature · 6 lines
1.8.4.5

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
maintainer
#2 lore raw

Re: [PATCH 1/5] drm/i915: Try to avoid pps_{lock, unlock}() on DP ports

Quoted 12 lines · Egbert Eich

From: Ville Syrjälä <[email protected]>

---
 drivers/gpu/drm/i915/intel_dp.c | 48 ++++++++++++++++++++++++-----------------
 1 file changed, 28 insertions(+), 20 deletions(-)
drivers/gpu/drm/i915/intel_dp.c +0 -0
index 81f959d..a24c8cc7 100644

drivers/gpu/drm/i915/intel_dp.c intel_dp_aux_ch(struct intel_dp *intel_dp, · line 813

Quoted 9 lines
drivers/gpu/drm/i915/intel_dp.c +3 -2
@@ -807,17 +807,19 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
 	uint32_t status;
 	int try, clock = 0;
 	bool has_aux_irq = HAS_AUX_IRQ(dev);
-	bool vdd;
+	bool vdd = false;
 
-	pps_lock(intel_dp);
+	if (is_edp(intel_dp)) {
+		pps_lock(intel_dp);

Why not add is_edp() into pps_lock()? The lockdep stuff in edp_panel_vdd_on() could be moved after the is_edp() check.

BR,
Jani.

Quoted 73 lines
drivers/gpu/drm/i915/intel_dp.c +25 -18
-	/*
-	 * We will be called with VDD already enabled for dpcd/edid/oui reads.
-	 * In such cases we want to leave VDD enabled and it's up to upper layers
-	 * to turn it off. But for eg. i2c-dev access we need to turn it on/off
-	 * ourselves.
-	 */
-	vdd = edp_panel_vdd_on(intel_dp);
+		/*
+		 * We will be called with VDD already enabled for dpcd/edid/oui reads.
+		 * In such cases we want to leave VDD enabled and it's up to upper layers
+		 * to turn it off. But for eg. i2c-dev access we need to turn it on/off
+		 * ourselves.
+		 */
+		vdd = edp_panel_vdd_on(intel_dp);
+	}
 
 	/* dp aux is extremely sensitive to irq latency, hence request the
 	 * lowest possible wakeup latency and so prevent the cpu from going into
@@ -924,10 +926,12 @@ out:
 	pm_qos_update_request(&dev_priv->pm_qos, PM_QOS_DEFAULT_VALUE);
 	intel_aux_display_runtime_put(dev_priv);
 
-	if (vdd)
-		edp_panel_vdd_off(intel_dp, false);
+	if (is_edp(intel_dp)) {
+		if (vdd)
+			edp_panel_vdd_off(intel_dp, false);
 
-	pps_unlock(intel_dp);
+		pps_unlock(intel_dp);
+	}
 
 	return ret;
 }
@@ -2291,18 +2295,22 @@ static void intel_enable_dp(struct intel_encoder *encoder)
 	if (WARN_ON(dp_reg & DP_PORT_EN))
 		return;
 
-	pps_lock(intel_dp);
+	if (is_edp(intel_dp)) {
+		pps_lock(intel_dp);
 
-	if (IS_VALLEYVIEW(dev))
-		vlv_init_panel_power_sequencer(intel_dp);
+		if (IS_VALLEYVIEW(dev))
+			vlv_init_panel_power_sequencer(intel_dp);
 
-	intel_dp_enable_port(intel_dp);
+		intel_dp_enable_port(intel_dp);
 
-	edp_panel_vdd_on(intel_dp);
-	edp_panel_on(intel_dp);
-	edp_panel_vdd_off(intel_dp, true);
+		edp_panel_vdd_on(intel_dp);
+		edp_panel_on(intel_dp);
+		edp_panel_vdd_off(intel_dp, true);
 
-	pps_unlock(intel_dp);
+		pps_unlock(intel_dp);
+	} else {
+		intel_dp_enable_port(intel_dp);
+	}
 
 	if (IS_VALLEYVIEW(dev))
 		vlv_wait_port_ready(dev_priv, dp_to_dig_port(intel_dp));
Signature · 6 lines
1.8.4.5

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Signature · 5 lines
Jani Nikula, Intel Open Source Technology Center
_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
#3 lore raw

PATCH 2/5 drm/DP: Create pointer to generic DPCD access function

In reply to Egbert Eich

This way a driver can replace this function with its own version.

---
 drivers/gpu/drm/drm_dp_helper.c | 5 +++--
 include/drm/drm_dp_helper.h     | 8 ++++++++
 2 files changed, 11 insertions(+), 2 deletions(-)
drivers/gpu/drm/drm_dp_helper.c +3 -2
index 959e207..d132838 100644
@@ -238,7 +238,7 @@ static int drm_dp_dpcd_access(struct drm_dp_aux *aux, u8 request,
 ssize_t drm_dp_dpcd_read(struct drm_dp_aux *aux, unsigned int offset,
 			 void *buffer, size_t size)
 {
-	return drm_dp_dpcd_access(aux, DP_AUX_NATIVE_READ, offset, buffer,
+	return aux->dpcd_access(aux, DP_AUX_NATIVE_READ, offset, buffer,
 				  size);
 }
 EXPORT_SYMBOL(drm_dp_dpcd_read);
@@ -260,7 +260,7 @@ EXPORT_SYMBOL(drm_dp_dpcd_read);
 ssize_t drm_dp_dpcd_write(struct drm_dp_aux *aux, unsigned int offset,
 			  void *buffer, size_t size)
 {
-	return drm_dp_dpcd_access(aux, DP_AUX_NATIVE_WRITE, offset, buffer,
+	return aux->dpcd_access(aux, DP_AUX_NATIVE_WRITE, offset, buffer,
 				  size);
 }
 EXPORT_SYMBOL(drm_dp_dpcd_write);
@@ -552,6 +552,7 @@ static const struct i2c_algorithm drm_dp_i2c_algo = {
 int drm_dp_aux_register(struct drm_dp_aux *aux)
 {
 	mutex_init(&aux->hw_mutex);
+	aux->dpcd_access = drm_dp_dpcd_access;
 
 	aux->ddc.algo = &drm_dp_i2c_algo;
 	aux->ddc.algo_data = aux;
include/drm/drm_dp_helper.h +8 -0
index 11f8c84..cd7b464 100644
@@ -497,6 +497,8 @@ struct drm_dp_aux_msg {
  * @dev: pointer to struct device that is the parent for this AUX channel
  * @hw_mutex: internal mutex used for locking transfers
  * @transfer: transfers a message representing a single AUX transaction
+ * @dp_dpcd_access: hook to optionally wrap or replace high level dpcd message
+ *                  function.
  *
  * The .dev field should be set to a pointer to the device that implements
  * the AUX channel.
@@ -519,6 +521,10 @@ struct drm_dp_aux_msg {
  * transactions. The drm_dp_aux_register_i2c_bus() function registers an
  * I2C adapter that can be passed to drm_probe_ddc(). Upon removal, drivers
  * should call drm_dp_aux_unregister_i2c_bus() to remove the I2C adapter.
+ * dpcd_access() can be used by the driver to wrap or replace the generic
+ * dpcd access function in case certain operations should be performed before
+ * a dpcd transaction is started if this cannot reasonably performed in
+ * .transfer(). It is initialized to its default value by drm_dp_aux_register().
  *
  * Note that the aux helper code assumes that the .transfer() function
  * only modifies the reply field of the drm_dp_aux_msg structure.  The
@@ -531,6 +537,8 @@ struct drm_dp_aux {
 	struct mutex hw_mutex;
 	ssize_t (*transfer)(struct drm_dp_aux *aux,
 			    struct drm_dp_aux_msg *msg);
+	int (*dpcd_access)(struct drm_dp_aux *aux, u8 request,
+			     unsigned int offset, void *buffer, size_t size);
 	unsigned i2c_nack_count, i2c_defer_count;
 };
 
Signature · 6 lines
1.8.4.5

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
#4 lore raw

PATCH 3/5 drm/DP: Export drm_dp_i2c_xfer() DP helper function

In reply to Egbert Eich

It may be required to wrap the generic DP I2C transfer function to perfrom certain operations before of after this function is called. Make this function available to the driver.

---
 drivers/gpu/drm/drm_dp_helper.c | 3 ++-
 include/drm/drm_dp_helper.h     | 2 ++
 2 files changed, 4 insertions(+), 1 deletion(-)
drivers/gpu/drm/drm_dp_helper.c +2 -1
index d132838..f17ac01 100644
@@ -481,7 +481,7 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
 	return -EREMOTEIO;
 }
 
-static int drm_dp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
+int drm_dp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
 			   int num)
 {
 	struct drm_dp_aux *aux = adapter->algo_data;
@@ -537,6 +537,7 @@ static int drm_dp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
 
 	return err;
 }
+EXPORT_SYMBOL(drm_dp_i2c_xfer);
 
 static const struct i2c_algorithm drm_dp_i2c_algo = {
 	.functionality = drm_dp_i2c_functionality,
include/drm/drm_dp_helper.h +2 -0
index cd7b464..0103b7f 100644
@@ -423,6 +423,8 @@ void drm_dp_link_train_channel_eq_delay(const u8 dpcd[DP_RECEIVER_CAP_SIZE]);
 
 u8 drm_dp_link_rate_to_bw_code(int link_rate);
 int drm_dp_bw_code_to_link_rate(u8 link_bw);
+int drm_dp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
+		    int num);
 
 struct edp_sdp_header {
 	u8 HB0; /* Secondary Data Packet ID */
Signature · 6 lines
1.8.4.5

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
#5 lore raw

PATCH 4/5 drm/DP: Export drm_dp_dpcd_access() DP helper function

In reply to Egbert Eich

It may be required to wrap the generic DP DPCD transfer function to perfrom certain operations before of after this function is called.

---
 drivers/gpu/drm/drm_dp_helper.c | 3 ++-
 include/drm/drm_dp_helper.h     | 4 ++++
 2 files changed, 6 insertions(+), 1 deletion(-)
drivers/gpu/drm/drm_dp_helper.c +2 -1
index f17ac01..2a731e6 100644
@@ -171,7 +171,7 @@ EXPORT_SYMBOL(drm_dp_bw_code_to_link_rate);
  * Both native and I2C-over-AUX transactions are supported.
  */
 
-static int drm_dp_dpcd_access(struct drm_dp_aux *aux, u8 request,
+int drm_dp_dpcd_access(struct drm_dp_aux *aux, u8 request,
 			      unsigned int offset, void *buffer, size_t size)
 {
 	struct drm_dp_aux_msg msg;
@@ -220,6 +220,7 @@ static int drm_dp_dpcd_access(struct drm_dp_aux *aux, u8 request,
 	DRM_DEBUG_KMS("too many retries, giving up\n");
 	return -EIO;
 }
+EXPORT_SYMBOL(drm_dp_dpcd_access);
 
 /**
  * drm_dp_dpcd_read() - read a series of bytes from the DPCD
include/drm/drm_dp_helper.h +4 -0
index 0103b7f..ad04f64 100644
@@ -405,6 +405,8 @@
 #define MODE_I2C_READ	4
 #define MODE_I2C_STOP	8
 
+struct drm_dp_aux;
+
 #define DP_LINK_STATUS_SIZE	   6
 bool drm_dp_channel_eq_ok(const u8 link_status[DP_LINK_STATUS_SIZE],
 			  int lane_count);
@@ -423,6 +425,8 @@ void drm_dp_link_train_channel_eq_delay(const u8 dpcd[DP_RECEIVER_CAP_SIZE]);
 
 u8 drm_dp_link_rate_to_bw_code(int link_rate);
 int drm_dp_bw_code_to_link_rate(u8 link_bw);
+int drm_dp_dpcd_access(struct drm_dp_aux *aux, u8 request,
+		       unsigned int offset, void *buffer, size_t size);
 int drm_dp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
 		    int num);
 
Signature · 6 lines
1.8.4.5

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
#6 lore raw

PATCH 5/5 drm/i915/eDP: Move pps_lock() and edp_panel_vdd_on() to top

In reply to Egbert Eich

On eDP each low level transfer is wrapped by pps_lock()/unlock() and edp_panel_vdd_on()/off(). Since PPS locking can be quite expensive and each call to master_xfer() or dpcd_access() may call these low level transfer functions many times it may introduce a considerable delay. Move locking/VDD enablement to the top so that it is performed only once per master_xfer() or dpcd_access().
This fixes https://bugs.freedesktop.org/show_bug.cgi?id=86201

---
 drivers/gpu/drm/i915/intel_dp.c  | 116 ++++++++++++++++++++++++++++++++-------
 drivers/gpu/drm/i915/intel_drv.h |   5 ++
 2 files changed, 100 insertions(+), 21 deletions(-)
drivers/gpu/drm/i915/intel_dp.c +95 -21
index a24c8cc7..164f80e 100644
@@ -807,19 +807,6 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
 	uint32_t status;
 	int try, clock = 0;
 	bool has_aux_irq = HAS_AUX_IRQ(dev);
-	bool vdd = false;
-
-	if (is_edp(intel_dp)) {
-		pps_lock(intel_dp);
-
-		/*
-		 * We will be called with VDD already enabled for dpcd/edid/oui reads.
-		 * In such cases we want to leave VDD enabled and it's up to upper layers
-		 * to turn it off. But for eg. i2c-dev access we need to turn it on/off
-		 * ourselves.
-		 */
-		vdd = edp_panel_vdd_on(intel_dp);
-	}
 
 	/* dp aux is extremely sensitive to irq latency, hence request the
 	 * lowest possible wakeup latency and so prevent the cpu from going into
@@ -926,13 +913,6 @@ out:
 	pm_qos_update_request(&dev_priv->pm_qos, PM_QOS_DEFAULT_VALUE);
 	intel_aux_display_runtime_put(dev_priv);
 
-	if (is_edp(intel_dp)) {
-		if (vdd)
-			edp_panel_vdd_off(intel_dp, false);
-
-		pps_unlock(intel_dp);
-	}
-
 	return ret;
 }
 
@@ -1001,6 +981,97 @@ intel_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
 	return ret;
 }
 
+int intel_edp_dpcd_access(struct drm_dp_aux *aux, u8 request,
+			      unsigned int offset, void *buffer, size_t size)
+{
+	struct intel_dp *intel_dp = container_of(aux, struct intel_dp, aux);
+	bool vdd = false;
+	int ret;
+
+	pps_lock(intel_dp);
+	/*
+	 * We will be called with VDD already enabled for dpcd/edid/oui reads.
+	 * In such cases we want to leave VDD enabled and it's up to upper
+	 * layers to turn it off. But for eg. i2c-dev access we need to turn
+	 * it on/off ourselves.
+	 */
+	vdd = edp_panel_vdd_on(intel_dp);
+
+	ret = drm_dp_dpcd_access(aux, request, offset, buffer, size);
+
+	if (vdd)
+		edp_panel_vdd_off(intel_dp, false);
+
+	pps_unlock(intel_dp);
+
+	return ret;
+}
+
+static int
+intel_edp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
+			  int num)
+{
+	struct drm_dp_aux *aux = adapter->algo_data;
+	struct intel_dp *intel_dp = container_of(aux, struct intel_dp, aux);
+	bool vdd = false;
+	int ret;
+
+	pps_lock(intel_dp);
+	/*
+	 * We will be called with VDD already enabled for dpcd/edid/oui reads.
+	 * In such cases we want to leave VDD enabled and it's up to upper
+	 * layers to turn it off. But for eg. i2c-dev access we need to turn
+	 * it on/off ourselves.
+	 */
+	vdd = edp_panel_vdd_on(intel_dp);
+
+	ret = drm_dp_i2c_xfer(adapter, msgs, num);
+
+	if (vdd)
+		edp_panel_vdd_off(intel_dp, false);
+
+	pps_unlock(intel_dp);
+
+	return ret;
+}
+
+static u32 intel_edp_i2c_functionality(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
+	       I2C_FUNC_SMBUS_READ_BLOCK_DATA |
+	       I2C_FUNC_SMBUS_BLOCK_PROC_CALL |
+	       I2C_FUNC_10BIT_ADDR;
+}
+
+static const struct i2c_algorithm intel_edp_i2c_algo = {
+	.functionality = intel_edp_i2c_functionality,
+	.master_xfer = intel_edp_i2c_xfer,
+};
+
+/*
+ * intel_edp_aux_register() - Intel replacement for
+ *                           drm_dp_aux_register().
+ */
+static int intel_edp_aux_register(struct drm_dp_aux *aux)
+{
+	mutex_init(&aux->hw_mutex);
+	aux->dpcd_access = intel_edp_dpcd_access;
+
+	aux->ddc.algo = &intel_edp_i2c_algo;
+	aux->ddc.algo_data = aux;
+	aux->ddc.retries = 3;
+
+	aux->ddc.class = I2C_CLASS_DDC;
+	aux->ddc.owner = THIS_MODULE;
+	aux->ddc.dev.parent = aux->dev;
+	aux->ddc.dev.of_node = aux->dev->of_node;
+
+	strlcpy(aux->ddc.name, aux->name ? aux->name : dev_name(aux->dev),
+		sizeof(aux->ddc.name));
+
+	return i2c_add_adapter(&aux->ddc);
+}
+
 static void
 intel_dp_aux_init(struct intel_dp *intel_dp, struct intel_connector *connector)
 {
@@ -1050,7 +1121,10 @@ intel_dp_aux_init(struct intel_dp *intel_dp, struct intel_connector *connector)
 	DRM_DEBUG_KMS("registering %s bus for %s\n", name,
 		      connector->base.kdev->kobj.name);
 
-	ret = drm_dp_aux_register(&intel_dp->aux);
+	if (!is_edp(intel_dp))
+		ret = drm_dp_aux_register(&intel_dp->aux);
+	else
+		ret = intel_edp_aux_register(&intel_dp->aux);
 	if (ret < 0) {
 		DRM_ERROR("drm_dp_aux_register() for %s failed (%d)\n",
 			  name, ret);
drivers/gpu/drm/i915/intel_drv.h +5 -0
index 44b153c5..783261a 100644
@@ -589,6 +589,11 @@ struct intel_dp {
 	uint8_t psr_dpcd[EDP_PSR_RECEIVER_CAP_SIZE];
 	uint8_t downstream_ports[DP_MAX_DOWNSTREAM_PORTS];
 	struct drm_dp_aux aux;
+	struct i2c_algorithm ddc_algo;
+	int (*aux_master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs,
+			   int num);
+	int (*dpcd_access)(struct drm_dp_aux *aux, u8 request,
+			   unsigned int offset, void *buffer, size_t size);
 	uint8_t train_set[4];
 	int panel_power_up_delay;
 	int panel_power_down_delay;
Signature · 6 lines
1.8.4.5

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
maintainer
#7 lore raw
In reply to Egbert Eich
Quoted 11 lines · Egbert Eich

For eDP in the Intel driver pps_lock()/unlock() need to be called before initiating an I2C/AUX channel transfer. These operations can be quite expensive - especially on values for HZ lower than 1000.
It is therefore better to perfrom this locking/unlocking only once, ie at the beginning and at the end of the entire I2C transfer. The current design of drm_dp_helper.c doesn't allow this. This patchset modifies drm_dp_helper.c and moves the locking/unlocking operation to the top.
This fixes the long delay observed in
https://bugs.freedesktop.org/show_bug.cgi?id=86201

Quoted 4 lines

Egbert Eich (4):
drm/DP: Create pointer to generic DPCD access function drm/DP: Export drm_dp_i2c_xfer() DP helper function drm/DP: Export drm_dp_dpcd_access() DP helper function

These three need to be sent to dri-devel, with cc: Thierry Reding <[email protected]>.

BR,
Jani.

Quoted 18 lines

drm/i915/eDP: Move pps_lock() and edp_panel_vdd_on() to top

Ville Syrjälä (1):
drm/i915: Try to avoid pps_{lock,unlock}() on DP ports

 drivers/gpu/drm/drm_dp_helper.c  |  11 ++--
 drivers/gpu/drm/i915/intel_dp.c  | 132 +++++++++++++++++++++++++++++++--------
 drivers/gpu/drm/i915/intel_drv.h |   5 ++
 include/drm/drm_dp_helper.h      |  14 +++++
 4 files changed, 133 insertions(+), 29 deletions(-)
Signature · 6 lines
1.8.4.5

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Signature · 5 lines
Jani Nikula, Intel Open Source Technology Center
_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
#8 lore raw
In reply to Egbert Eich
Quoted 11 lines · Egbert Eich

For eDP in the Intel driver pps_lock()/unlock() need to be called before initiating an I2C/AUX channel transfer. These operations can be quite expensive - especially on values for HZ lower than 1000.
It is therefore better to perfrom this locking/unlocking only once, ie at the beginning and at the end of the entire I2C transfer. The current design of drm_dp_helper.c doesn't allow this. This patchset modifies drm_dp_helper.c and moves the locking/unlocking operation to the top.
This fixes the long delay observed in
https://bugs.freedesktop.org/show_bug.cgi?id=86201

Quoted 8 lines

Egbert Eich (4):
drm/DP: Create pointer to generic DPCD access function drm/DP: Export drm_dp_i2c_xfer() DP helper function drm/DP: Export drm_dp_dpcd_access() DP helper function drm/i915/eDP: Move pps_lock() and edp_panel_vdd_on() to top

Ville Syrjälä (1):
drm/i915: Try to avoid pps_{lock,unlock}() on DP ports

Imo this approach with overwrite all the entry points won't scale since besides i2c and dpcd there will be more sooner or later (oui, dp mst, some debugfs userspace dp aux tools, ...).

I think what we need is the same as in the i2c layer has with the xfer_pre/post functions. To make this as painless as possible we should probably refcount that in the dp helper, protected by aux->hw_mutex. That way normal dp reads could just do the xfer_pre/post around the call to aux->transfer while i2c could do it around the entire i2c transaction. -Daniel

Quoted 14 lines
 drivers/gpu/drm/drm_dp_helper.c  |  11 ++--
 drivers/gpu/drm/i915/intel_dp.c  | 132 +++++++++++++++++++++++++++++++--------
 drivers/gpu/drm/i915/intel_drv.h |   5 ++
 include/drm/drm_dp_helper.h      |  14 +++++
 4 files changed, 133 insertions(+), 29 deletions(-)
Signature · 6 lines
1.8.4.5

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Signature · 7 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
#9 lore raw
Quoted 9 lines · Daniel Vetter

Imo this approach with overwrite all the entry points won't scale since besides i2c and dpcd there will be more sooner or later (oui, dp mst, some debugfs userspace dp aux tools, ...).

I think what we need is the same as in the i2c layer has with the xfer_pre/post functions. To make this as painless as possible we should probably refcount that in the dp helper, protected by aux->hw_mutex. That way normal dp reads could just do the xfer_pre/post around the call to aux->transfer while i2c could do it around the entire i2c transaction.

I agree with your idea of having xfer_pre/post functions.
I'm not sure though if I understand your idea about reference counters:
are you trying to protect from xfer_pre/post being called at different levels here?
With my proposal entire transactions (I2C) are serialized thru the pps_mutex lock. This is a side effect that's probably unwanted. Is this what you are trying to avoid by using ref counters?

Cheers,
Egbert.

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

#10 lore raw
Quoted 12 lines · Egbert Eich
Quoted 9 lines · Daniel Vetter

Imo this approach with overwrite all the entry points won't scale since besides i2c and dpcd there will be more sooner or later (oui, dp mst, some debugfs userspace dp aux tools, ...).

I think what we need is the same as in the i2c layer has with the xfer_pre/post functions. To make this as painless as possible we should probably refcount that in the dp helper, protected by aux->hw_mutex. That way normal dp reads could just do the xfer_pre/post around the call to aux->transfer while i2c could do it around the entire i2c transaction.

Quoted 7 lines

I agree with your idea of having xfer_pre/post functions.
I'm not sure though if I understand your idea about reference counters:
are you trying to protect from xfer_pre/post being called at different levels here?
With my proposal entire transactions (I2C) are serialized thru the pps_mutex lock. This is a side effect that's probably unwanted. Is this what you are trying to avoid by using ref counters?

Yeah I want to protect entire transactions at the highest levels with xfer_pre/post. The problem is that things nest and we can't grab sufficient locking to prevent that nesting. E.g. for i2c we should do the dp_aux xfer_pre/post calls from i2c xfer_pre/post (so that the entire edid read only has one pre/post, assuming no retries). But the i2c lock which protects that doesn't protect against concurrent dp aux transactions from someone else (e.g. dp mst is done without modeset locks, or if we ever get a userspace interface for debuggin db issues). So direct dp aux again needs to do xfer_pre/post. Same for dp mst, we might want to wrap an entire dp mst transaction with this, but the low-level code might not now.

Hence why I think we shold have a refcount for pre/post plus small helpers (atm just static, we can export once we need them) like this

drm_dp_aux_xfer_pre(dp_aux)

{
	mutex_lock(dp_aux->hw_lock)
	if (dp_aux->xfer_count++ == 0)
		dp_aux->xfer_pre();
	mutex_unlock(dp_aux->hw_lock)
}

Same for xfer_post. Then we could wire that up for i2c-over-dp and for the low-level dp xfer functions and it should all Just Work. And if there's a new perf critical case where we want to do this over an entire series of transactinos we can just call the two xfer_pre/post wrappers and done.

Cheers, Daniel

Signature · 7 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx