Skip to contentSkip to conversation

drm/i2c: adv7511: ADV7533 support

PATCH Superseded Archit Taneja 10 participants 89 messages Jul 27, 2015 – Jun 17, 2016 2 messages not in the archive

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

cover drm/i2c: adv7511: ADV7533 support

ADV7533 is a DSI to HDMI encoder chip. It's like ADV7511, but with an additional DSI RX block that takes in DSI video mode output.

This series adds support for ADV7533. Unlike ADV7511 that's modelled as a drm i2c slave encoder, ADV7533 is a drm_bridge object. The bridge ops further create a HDMI type connector device for the chip's output.

In order to pass DSI specific parameters to the host, the driver creates a dummy DSI device, which it registers to a DSI host as specified via DT.

The first patch in the series is a minor fix, the rest add ADV7533 support. They depend on the series I posted sometime back:

"drm/dsi: DSI for devices with different control bus"
https://lkml.org/lkml/2015/6/30/42

Archit Taneja (4):
drm/i2c: adv7511: Fix mutex deadlock when interrupts are disabled drm/i2c: adv7511: Refactor encoder slave functions drm/i2c: adv7511: Add drm_bridge/connector for ADV7533 drm/i2c: adv7511: Create mipi_dsi_device for ADV7533

Lars-Peter Clausen (1):
drm/i2c: adv7511: Initial support for adv7533

 drivers/gpu/drm/i2c/adv7511.c | 486 +++++++++++++++++++++++++++++++++++++-----
 1 file changed, 437 insertions(+), 49 deletions(-)
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
#1 lore raw

PATCH 1/5 drm/i2c: adv7511: Fix mutex deadlock when interrupts are disabled

When the adv7511 i2c client doesn't have an interrupt line, we observe a deadlock on caused by trying to lock drm device's mode_config.mutex twice in the same context.

Here is the sequence that causes it:

ioctl DRM_IOCTL_MODE_GETCONNECTOR from userspace
drm_mode_getconnector (acquires mode_config mutex)

    connector->fill_modes()
    drm_helper_probe_single_connector_modes
      connector_funcs->get_modes
	adv7511_encoder_get_modes
	  adv7511_get_edid_block
	    adv7511_irq_process
	      drm_helper_hpd_irq_event (acquires mode_config mutex again)

In adv7511_irq_process, don't call drm_helper_hpd_irq_event when not called from interrupt context. It doesn't serve any purpose there anyway.

---
 drivers/gpu/drm/i2c/adv7511.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/gpu/drm/i2c/adv7511.c +4 -4
index 2aaa3c8..cf5bb29 100644
@@ -422,7 +422,7 @@ static bool adv7511_hpd(struct adv7511 *adv7511)
 	return false;
 }
 
-static int adv7511_irq_process(struct adv7511 *adv7511)
+static int adv7511_irq_process(struct adv7511 *adv7511, bool process_hpd)
 {
 	unsigned int irq0, irq1;
 	int ret;
@@ -438,7 +438,7 @@ static int adv7511_irq_process(struct adv7511 *adv7511)
 	regmap_write(adv7511->regmap, ADV7511_REG_INT(0), irq0);
 	regmap_write(adv7511->regmap, ADV7511_REG_INT(1), irq1);
 
-	if (irq0 & ADV7511_INT0_HDP && adv7511->encoder)
+	if (process_hpd && irq0 & ADV7511_INT0_HDP && adv7511->encoder)
 		drm_helper_hpd_irq_event(adv7511->encoder->dev);
 
 	if (irq0 & ADV7511_INT0_EDID_READY || irq1 & ADV7511_INT1_DDC_ERROR) {
@@ -456,7 +456,7 @@ static irqreturn_t adv7511_irq_handler(int irq, void *devid)
 	struct adv7511 *adv7511 = devid;
 	int ret;
 
-	ret = adv7511_irq_process(adv7511);
+	ret = adv7511_irq_process(adv7511, true);
 	return ret < 0 ? IRQ_NONE : IRQ_HANDLED;
 }
 
@@ -473,7 +473,7 @@ static int adv7511_wait_for_edid(struct adv7511 *adv7511, int timeout)
 				adv7511->edid_read, msecs_to_jiffies(timeout));
 	} else {
 		for (; timeout > 0; timeout -= 25) {
-			ret = adv7511_irq_process(adv7511);
+			ret = adv7511_irq_process(adv7511, false);
 			if (ret < 0)
 				break;
 
Signature · 7 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

_______________________________________________
dri-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/dri-devel
#2 lore raw

PATCH 2/5 drm/i2c: adv7511: Initial support for adv7533

In reply to Archit Taneja

From: Lars-Peter Clausen <[email protected]>

ADV7533 is a DSI to HDMI encoder chip. It is a derivative of ADV7511, with additional blocks to translate input DSI data to parallel RGB data. Besides the ADV7511 i2c register map, it has additional registers that require to be configured to activate the DSI blocks.

Use DT compatible strings to populate the adv7533 type enum. Add minimal register configurations belonging to the DSI/CEC register map.

---
 drivers/gpu/drm/i2c/adv7511.c | 155 +++++++++++++++++++++++++++++++++++-------
 1 file changed, 131 insertions(+), 24 deletions(-)
drivers/gpu/drm/i2c/adv7511.c +131 -24
index cf5bb29..63a3d20 100644
@@ -20,12 +20,18 @@
 
 #include "adv7511.h"
 
+enum adv7511_type {
+	ADV7511,
+	ADV7533,
+};
+
 struct adv7511 {
 	struct i2c_client *i2c_main;
 	struct i2c_client *i2c_edid;
+	struct i2c_client *i2c_cec;
 
 	struct regmap *regmap;
-	struct regmap *packet_memory_regmap;
+	struct regmap *regmap_cec;
 	enum drm_connector_status status;
 	bool powered;
 
@@ -46,6 +52,8 @@ struct adv7511 {
 	struct edid *edid;
 
 	struct gpio_desc *gpio_pd;
+
+	enum adv7511_type type;
 };
 
 static struct adv7511 *encoder_to_adv7511(struct drm_encoder *encoder)
@@ -66,6 +74,23 @@ static const struct reg_default adv7511_fixed_registers[] = {
 	{ 0x55, 0x02 },
 };
 
+/* ADI recommended values for proper operation. */
+static const struct reg_default adv7533_fixed_registers[] = {
+	{ 0x16, 0x20 },
+	{ 0x9a, 0xe0 },
+	{ 0xba, 0x70 },
+	{ 0xde, 0x82 },
+	{ 0xe4, 0x40 },
+	{ 0xe5, 0x80 },
+};
+
+static const struct reg_default adv7533_cec_fixed_registers[] = {
+	{ 0x15, 0xd0 },
+	{ 0x17, 0xd0 },
+	{ 0x24, 0x20 },
+	{ 0x57, 0x11 },
+};
+
 /* -----------------------------------------------------------------------------
  * Register access
  */
@@ -158,6 +183,15 @@ static const struct regmap_config adv7511_regmap_config = {
 	.volatile_reg = adv7511_register_volatile,
 };
 
+static const struct regmap_config adv7533_cec_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.max_register = 0xff,
+	.cache_type = REGCACHE_RBTREE,
+};
+
+
 /* -----------------------------------------------------------------------------
  * Hardware configuration
  */
@@ -358,6 +392,25 @@ static void adv7511_set_link_config(struct adv7511 *adv7511,
 	adv7511->rgb = config->input_colorspace == HDMI_COLORSPACE_RGB;
 }
 
+static void adv7511_dsi_receiver_dpms(struct adv7511 *adv7511)
+{
+	if (adv7511->type != ADV7533)
+		return;
+
+	if (adv7511->powered) {
+		/* set number of dsi lanes (hardcoded to 4 for now) */
+		regmap_write(adv7511->regmap_cec, 0x1c, 0x4 << 4);
+		/* disable internal timing generator */
+		regmap_write(adv7511->regmap_cec, 0x27, 0x0b);
+		/* enable hdmi */
+		regmap_write(adv7511->regmap_cec, 0x03, 0x89);
+		/* disable test mode */
+		regmap_write(adv7511->regmap_cec, 0x55, 0x00);
+	} else {
+		regmap_write(adv7511->regmap_cec, 0x03, 0x0b);
+	}
+}
+
 static void adv7511_power_on(struct adv7511 *adv7511)
 {
 	adv7511->current_edid_segment = -1;
@@ -387,6 +440,8 @@ static void adv7511_power_on(struct adv7511 *adv7511)
 	regcache_sync(adv7511->regmap);
 
 	adv7511->powered = true;
+
+	adv7511_dsi_receiver_dpms(adv7511);
 }
 
 static void adv7511_power_off(struct adv7511 *adv7511)
@@ -398,6 +453,8 @@ static void adv7511_power_off(struct adv7511 *adv7511)
 	regcache_mark_dirty(adv7511->regmap);
 
 	adv7511->powered = false;
+
+	adv7511_dsi_receiver_dpms(adv7511);
 }
 
 /* -----------------------------------------------------------------------------
@@ -567,6 +624,9 @@ static int adv7511_get_modes(struct drm_encoder *encoder,
 
 	/* Reading the EDID only works if the device is powered */
 	if (!adv7511->powered) {
+		regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2,
+				   ADV7511_REG_POWER2_HDP_SRC_MASK,
+				   ADV7511_REG_POWER2_HDP_SRC_NONE);
 		regmap_write(adv7511->regmap, ADV7511_REG_INT(0),
 			     ADV7511_INT0_EDID_READY);
 		regmap_write(adv7511->regmap, ADV7511_REG_INT(1),
@@ -770,8 +830,6 @@ static int adv7511_parse_dt(struct device_node *np,
 	const char *str;
 	int ret;
 
-	memset(config, 0, sizeof(*config));
-
 	of_property_read_u32(np, "adi,input-depth", &config->input_color_depth);
 	if (config->input_color_depth != 8 && config->input_color_depth != 10 &&
 	    config->input_color_depth != 12)
@@ -853,6 +911,15 @@ static const int edid_i2c_addr = 0x7e;
 static const int packet_i2c_addr = 0x70;
 static const int cec_i2c_addr = 0x78;
 
+static const struct of_device_id adv7511_of_ids[] = {
+	{ .compatible = "adi,adv7511", .data = (void *) ADV7511 },
+	{ .compatible = "adi,adv7511w", .data = (void *) ADV7511 },
+	{ .compatible = "adi,adv7513", .data = (void *) ADV7511 },
+	{ .compatible = "adi,adv7533", .data = (void *) ADV7533 },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, adv7511_of_ids);
+
 static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
 {
 	struct adv7511_link_config link_config;
@@ -871,9 +938,22 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
 	adv7511->powered = false;
 	adv7511->status = connector_status_disconnected;
 
-	ret = adv7511_parse_dt(dev->of_node, &link_config);
-	if (ret)
-		return ret;
+	if (dev->of_node) {
+		const struct of_device_id *of_id;
+
+		of_id = of_match_node(adv7511_of_ids, dev->of_node);
+		adv7511->type = (enum adv7511_type) of_id->data;
+	} else {
+		adv7511->type = id->driver_data;
+	}
+
+	memset(&link_config, 0, sizeof(link_config));
+
+	if (adv7511->type == ADV7511) {
+		ret = adv7511_parse_dt(dev->of_node, &link_config);
+		if (ret)
+			return ret;
+	}
 
 	/*
 	 * The power down GPIO is optional. If present, toggle it from active to
@@ -897,10 +977,19 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
 		return ret;
 	dev_dbg(dev, "Rev. %d\n", val);
 
-	ret = regmap_register_patch(adv7511->regmap, adv7511_fixed_registers,
-				    ARRAY_SIZE(adv7511_fixed_registers));
-	if (ret)
-		return ret;
+	if (adv7511->type == ADV7511) {
+		ret = regmap_register_patch(adv7511->regmap,
+				adv7511_fixed_registers,
+				ARRAY_SIZE(adv7511_fixed_registers));
+		if (ret)
+			return ret;
+	} else {
+		ret = regmap_register_patch(adv7511->regmap,
+				adv7533_fixed_registers,
+				ARRAY_SIZE(adv7533_fixed_registers));
+		if (ret)
+			return ret;
+	}
 
 	regmap_write(adv7511->regmap, ADV7511_REG_EDID_I2C_ADDR, edid_i2c_addr);
 	regmap_write(adv7511->regmap, ADV7511_REG_PACKET_I2C_ADDR,
@@ -913,6 +1002,27 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
 	if (!adv7511->i2c_edid)
 		return -ENOMEM;
 
+	adv7511->i2c_cec = i2c_new_dummy(i2c->adapter, cec_i2c_addr >> 1);
+	if (!adv7511->i2c_cec) {
+		ret = -ENOMEM;
+		goto err_i2c_unregister_edid;
+	}
+
+	adv7511->regmap_cec = devm_regmap_init_i2c(adv7511->i2c_cec,
+					&adv7533_cec_regmap_config);
+	if (IS_ERR(adv7511->regmap_cec)) {
+		ret = PTR_ERR(adv7511->regmap_cec);
+		goto err_i2c_unregister_cec;
+	}
+
+	if (adv7511->type == ADV7533) {
+		ret = regmap_register_patch(adv7511->regmap_cec,
+				adv7533_cec_fixed_registers,
+				ARRAY_SIZE(adv7533_cec_fixed_registers));
+		if (ret)
+			return ret;
+	}
+
 	if (i2c->irq) {
 		init_waitqueue_head(&adv7511->wq);
 
@@ -921,7 +1031,7 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
 						IRQF_ONESHOT, dev_name(dev),
 						adv7511);
 		if (ret)
-			goto err_i2c_unregister_device;
+			goto err_i2c_unregister_cec;
 	}
 
 	/* CEC is unused for now */
@@ -932,11 +1042,14 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
 
 	i2c_set_clientdata(i2c, adv7511);
 
-	adv7511_set_link_config(adv7511, &link_config);
+	if (adv7511->type == ADV7511)
+		adv7511_set_link_config(adv7511, &link_config);
 
 	return 0;
 
-err_i2c_unregister_device:
+err_i2c_unregister_cec:
+	i2c_unregister_device(adv7511->i2c_cec);
+err_i2c_unregister_edid:
 	i2c_unregister_device(adv7511->i2c_edid);
 
 	return ret;
@@ -946,6 +1059,7 @@ static int adv7511_remove(struct i2c_client *i2c)
 {
 	struct adv7511 *adv7511 = i2c_get_clientdata(i2c);
 
+	i2c_unregister_device(adv7511->i2c_cec);
 	i2c_unregister_device(adv7511->i2c_edid);
 
 	kfree(adv7511->edid);
@@ -968,21 +1082,14 @@ static int adv7511_encoder_init(struct i2c_client *i2c, struct drm_device *dev,
 }
 
 static const struct i2c_device_id adv7511_i2c_ids[] = {
-	{ "adv7511", 0 },
-	{ "adv7511w", 0 },
-	{ "adv7513", 0 },
+	{ "adv7511", ADV7511 },
+	{ "adv7511w", ADV7511 },
+	{ "adv7513", ADV7511 },
+	{ "adv7533", ADV7533 },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, adv7511_i2c_ids);
 
-static const struct of_device_id adv7511_of_ids[] = {
-	{ .compatible = "adi,adv7511", },
-	{ .compatible = "adi,adv7511w", },
-	{ .compatible = "adi,adv7513", },
-	{ }
-};
-MODULE_DEVICE_TABLE(of, adv7511_of_ids);
-
 static struct drm_i2c_encoder_driver adv7511_driver = {
 	.i2c_driver = {
 		.driver = {
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
#3 lore raw

Re: [PATCH 2/5] drm/i2c: adv7511: Initial support for adv7533

Quoted 2 lines · Archit Taneja

From: Lars-Peter Clausen <[email protected]>

[..]

Quoted 1 line
drivers/gpu/drm/i2c/adv7511.c +0 -0

[..]

drivers/gpu/drm/i2c/adv7511.c static const int edid_i2c_addr = 0x7e; · line 921

Quoted 9 lines
drivers/gpu/drm/i2c/adv7511.c +8 -0
+static const struct of_device_id adv7511_of_ids[] = {
+	{ .compatible = "adi,adv7511", .data = (void *) ADV7511 },
+	{ .compatible = "adi,adv7511w", .data = (void *) ADV7511 },
+	{ .compatible = "adi,adv7513", .data = (void *) ADV7511 },
+	{ .compatible = "adi,adv7533", .data = (void *) ADV7533 },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, adv7511_of_ids);

Please leave this at the bottom.

Quoted 5 lines
drivers/gpu/drm/i2c/adv7511.c +1 -0
+
 static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
 {
 	struct adv7511_link_config link_config;

drivers/gpu/drm/i2c/adv7511.c static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id) · line 944

Quoted 10 lines
drivers/gpu/drm/i2c/adv7511.c +4 -3
@@ -871,9 +938,22 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
 	adv7511->powered = false;
 	adv7511->status = connector_status_disconnected;
 
-	ret = adv7511_parse_dt(dev->of_node, &link_config);
-	if (ret)
-		return ret;
+	if (dev->of_node) {
+		const struct of_device_id *of_id;
+
+		of_id = of_match_node(adv7511_of_ids, dev->of_node);

If you use of_device_get_match_data() instead you don't need to move the of_device_id table.

Quoted 5 lines
drivers/gpu/drm/i2c/adv7511.c +5 -0
+		adv7511->type = (enum adv7511_type) of_id->data;
+	} else {
+		adv7511->type = id->driver_data;
+	}
+

[..]

Quoted 11 lines

static const struct i2c_device_id adv7511_i2c_ids[] = {

drivers/gpu/drm/i2c/adv7511.c +4 -3
-	{ "adv7511", 0 },
-	{ "adv7511w", 0 },
-	{ "adv7513", 0 },
+	{ "adv7511", ADV7511 },
+	{ "adv7511w", ADV7511 },
+	{ "adv7513", ADV7511 },
+	{ "adv7533", ADV7533 },
 	{ }
 };

drivers/gpu/drm/i2c/adv7511.c static int adv7511_encoder_init(struct i2c_client *i2c, struct drm_device *dev, · line 985

Quoted 10 lines
drivers/gpu/drm/i2c/adv7511.c +0 -8
 MODULE_DEVICE_TABLE(i2c, adv7511_i2c_ids);
 
-static const struct of_device_id adv7511_of_ids[] = {
-	{ .compatible = "adi,adv7511", },
-	{ .compatible = "adi,adv7511w", },
-	{ .compatible = "adi,adv7513", },
-	{ }
-};
-MODULE_DEVICE_TABLE(of, adv7511_of_ids);
-

Regards,
Bjorn

#4 lore raw

Re: [PATCH 2/5] drm/i2c: adv7511: Initial support for adv7533

Quoted 29 lines · Bjorn Andersson
Quoted 2 lines · Archit Taneja

From: Lars-Peter Clausen <[email protected]>

[..]

Quoted 1 line
drivers/gpu/drm/i2c/adv7511.c +0 -0

[..]

drivers/gpu/drm/i2c/adv7511.c static const int edid_i2c_addr = 0x7e; · line 921

Quoted 9 lines
drivers/gpu/drm/i2c/adv7511.c +8 -0
+static const struct of_device_id adv7511_of_ids[] = {
+	{ .compatible = "adi,adv7511", .data = (void *) ADV7511 },
+	{ .compatible = "adi,adv7511w", .data = (void *) ADV7511 },
+	{ .compatible = "adi,adv7513", .data = (void *) ADV7511 },
+	{ .compatible = "adi,adv7533", .data = (void *) ADV7533 },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, adv7511_of_ids);

Please leave this at the bottom.

Quoted 8 lines
drivers/gpu/drm/i2c/adv7511.c +1 -0
+
  static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
  {
  	struct adv7511_link_config link_config;
@@ -871,9 +938,22 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
  	adv7511->powered = false;
  	adv7511->status = connector_status_disconnected;
 
Quoted 10 lines

drivers/gpu/drm/i2c/adv7511.c static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id) · line 944

Quoted 7 lines
drivers/gpu/drm/i2c/adv7511.c +4 -3
-	ret = adv7511_parse_dt(dev->of_node, &link_config);
-	if (ret)
-		return ret;
+	if (dev->of_node) {
+		const struct of_device_id *of_id;
+
+		of_id = of_match_node(adv7511_of_ids, dev->of_node);

If you use of_device_get_match_data() instead you don't need to move the of_device_id table.

Thanks, will use this in future revisions.

Archit

Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
#5 lore raw

PATCH 3/5 drm/i2c: adv7511: Refactor encoder slave functions

In reply to Archit Taneja

ADV7511 is represented as an i2c drm slave encoder device. ADV7533, on the other hand, is going be a normal i2c client device creating bridge and connector entities.

Move the code in encoder slave functions to generate helpers that are agnostic to the drm object type. These helpers will later also be used by bridge and connecter helper functions.

---
 drivers/gpu/drm/i2c/adv7511.c | 80 ++++++++++++++++++++++++++++++-------------
 1 file changed, 57 insertions(+), 23 deletions(-)
drivers/gpu/drm/i2c/adv7511.c +57 -23
index 63a3d20..46fb24d 100644
@@ -612,13 +612,11 @@ static int adv7511_get_edid_block(void *data, u8 *buf, unsigned int block,
 }
 
 /* -----------------------------------------------------------------------------
- * Encoder operations
+ * ADV75xx helpers
  */
-
-static int adv7511_get_modes(struct drm_encoder *encoder,
-			     struct drm_connector *connector)
+static int adv7511_get_modes(struct adv7511 *adv7511,
+		struct drm_connector *connector)
 {
-	struct adv7511 *adv7511 = encoder_to_adv7511(encoder);
 	struct edid *edid;
 	unsigned int count;
 
@@ -656,21 +654,10 @@ static int adv7511_get_modes(struct drm_encoder *encoder,
 	return count;
 }
 
-static void adv7511_encoder_dpms(struct drm_encoder *encoder, int mode)
-{
-	struct adv7511 *adv7511 = encoder_to_adv7511(encoder);
-
-	if (mode == DRM_MODE_DPMS_ON)
-		adv7511_power_on(adv7511);
-	else
-		adv7511_power_off(adv7511);
-}
-
 static enum drm_connector_status
-adv7511_encoder_detect(struct drm_encoder *encoder,
+adv7511_detect(struct adv7511 *adv7511,
 		       struct drm_connector *connector)
 {
-	struct adv7511 *adv7511 = encoder_to_adv7511(encoder);
 	enum drm_connector_status status;
 	unsigned int val;
 	bool hpd;
@@ -694,7 +681,7 @@ adv7511_encoder_detect(struct drm_encoder *encoder,
 	if (status == connector_status_connected && hpd && adv7511->powered) {
 		regcache_mark_dirty(adv7511->regmap);
 		adv7511_power_on(adv7511);
-		adv7511_get_modes(encoder, connector);
+		adv7511_get_modes(adv7511, connector);
 		if (adv7511->status == connector_status_connected)
 			status = connector_status_disconnected;
 	} else {
@@ -708,8 +695,8 @@ adv7511_encoder_detect(struct drm_encoder *encoder,
 	return status;
 }
 
-static int adv7511_encoder_mode_valid(struct drm_encoder *encoder,
-				      struct drm_display_mode *mode)
+static int adv7511_mode_valid(struct adv7511 *adv7511,
+				     const struct drm_display_mode *mode)
 {
 	if (mode->clock > 165000)
 		return MODE_CLOCK_HIGH;
@@ -717,11 +704,10 @@ static int adv7511_encoder_mode_valid(struct drm_encoder *encoder,
 	return MODE_OK;
 }
 
-static void adv7511_encoder_mode_set(struct drm_encoder *encoder,
+static void adv7511_mode_set(struct adv7511 *adv7511,
 				     struct drm_display_mode *mode,
 				     struct drm_display_mode *adj_mode)
 {
-	struct adv7511 *adv7511 = encoder_to_adv7511(encoder);
 	unsigned int low_refresh_rate;
 	unsigned int hsync_polarity = 0;
 	unsigned int vsync_polarity = 0;
@@ -812,12 +798,60 @@ static void adv7511_encoder_mode_set(struct drm_encoder *encoder,
 	adv7511->f_tmds = mode->clock;
 }
 
+/* -----------------------------------------------------------------------------
+ * Encoder operations
+ */
+
+static int adv7511_encoder_get_modes(struct drm_encoder *encoder,
+			     struct drm_connector *connector)
+{
+	struct adv7511 *adv7511 = encoder_to_adv7511(encoder);
+
+	return adv7511_get_modes(adv7511, connector);
+}
+
+static void adv7511_encoder_dpms(struct drm_encoder *encoder, int mode)
+{
+	struct adv7511 *adv7511 = encoder_to_adv7511(encoder);
+
+	if (mode == DRM_MODE_DPMS_ON)
+		adv7511_power_on(adv7511);
+	else
+		adv7511_power_off(adv7511);
+}
+
+static enum drm_connector_status
+adv7511_encoder_detect(struct drm_encoder *encoder,
+		       struct drm_connector *connector)
+{
+	struct adv7511 *adv7511 = encoder_to_adv7511(encoder);
+
+	return adv7511_detect(adv7511, connector);
+}
+
+static int adv7511_encoder_mode_valid(struct drm_encoder *encoder,
+				      struct drm_display_mode *mode)
+{
+	struct adv7511 *adv7511 = encoder_to_adv7511(encoder);
+
+	return adv7511_mode_valid(adv7511, mode);
+}
+
+static void adv7511_encoder_mode_set(struct drm_encoder *encoder,
+				     struct drm_display_mode *mode,
+				     struct drm_display_mode *adj_mode)
+{
+	struct adv7511 *adv7511 = encoder_to_adv7511(encoder);
+
+	adv7511_mode_set(adv7511, mode, adj_mode);
+}
+
 static struct drm_encoder_slave_funcs adv7511_encoder_funcs = {
 	.dpms = adv7511_encoder_dpms,
 	.mode_valid = adv7511_encoder_mode_valid,
 	.mode_set = adv7511_encoder_mode_set,
 	.detect = adv7511_encoder_detect,
-	.get_modes = adv7511_get_modes,
+	.get_modes = adv7511_encoder_get_modes,
 };
 
 /* -----------------------------------------------------------------------------
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
#6 lore raw

Re: [PATCH 3/5] drm/i2c: adv7511: Refactor encoder slave functions

Hi Archit,

(CC'ing Boris Brezillon)

Thank you for the patch.

Quoted 3 lines · On Monday 27 July 2015 11:46:57 Archit Taneja wrote:

ADV7511 is represented as an i2c drm slave encoder device. ADV7533, on the other hand, is going be a normal i2c client device creating bridge and connector entities.

Please, no. It's really time to stop piling hacks and fix the problem properly. There's no reason to have separate APIs for I2C slave encoders and DRM bridges. Those two APIs need to be merged, and then you'll find it much easier to implement ADV7533 support.

Boris, I know you were experimenting with that, do you have anything to report ?

Quoted 152 lines

Move the code in encoder slave functions to generate helpers that are agnostic to the drm object type. These helpers will later also be used by bridge and connecter helper functions.

---
 drivers/gpu/drm/i2c/adv7511.c | 80 +++++++++++++++++++++++++++------------
 1 file changed, 57 insertions(+), 23 deletions(-)
drivers/gpu/drm/i2c/adv7511.c +56 -28
index 63a3d20..46fb24d 100644
@@ -612,13 +612,11 @@ static int adv7511_get_edid_block(void *data, u8 *buf,
 unsigned int block, }
 
 /*
---------------------------------------------------------------------------
-- - * Encoder operations
+ * ADV75xx helpers
  */
-
-static int adv7511_get_modes(struct drm_encoder *encoder,
-			     struct drm_connector *connector)
+static int adv7511_get_modes(struct adv7511 *adv7511,
+		struct drm_connector *connector)
 {
-	struct adv7511 *adv7511 = encoder_to_adv7511(encoder);
 	struct edid *edid;
 	unsigned int count;
@@ -656,21 +654,10 @@ static int adv7511_get_modes(struct drm_encoder
 *encoder, return count;
 }
 
-static void adv7511_encoder_dpms(struct drm_encoder *encoder, int mode)
-{
-	struct adv7511 *adv7511 = encoder_to_adv7511(encoder);
-
-	if (mode == DRM_MODE_DPMS_ON)
-		adv7511_power_on(adv7511);
-	else
-		adv7511_power_off(adv7511);
-}
-
 static enum drm_connector_status
-adv7511_encoder_detect(struct drm_encoder *encoder,
+adv7511_detect(struct adv7511 *adv7511,
 		       struct drm_connector *connector)
 {
-	struct adv7511 *adv7511 = encoder_to_adv7511(encoder);
 	enum drm_connector_status status;
 	unsigned int val;
 	bool hpd;
@@ -694,7 +681,7 @@ adv7511_encoder_detect(struct drm_encoder *encoder,
 	if (status == connector_status_connected && hpd && adv7511->powered) {
 		regcache_mark_dirty(adv7511->regmap);
 		adv7511_power_on(adv7511);
-		adv7511_get_modes(encoder, connector);
+		adv7511_get_modes(adv7511, connector);
 		if (adv7511->status == connector_status_connected)
 			status = connector_status_disconnected;
 	} else {
@@ -708,8 +695,8 @@ adv7511_encoder_detect(struct drm_encoder *encoder,
 	return status;
 }
 
-static int adv7511_encoder_mode_valid(struct drm_encoder *encoder,
-				      struct drm_display_mode *mode)
+static int adv7511_mode_valid(struct adv7511 *adv7511,
+				     const struct drm_display_mode *mode)
 {
 	if (mode->clock > 165000)
 		return MODE_CLOCK_HIGH;
@@ -717,11 +704,10 @@ static int adv7511_encoder_mode_valid(struct
 drm_encoder *encoder, return MODE_OK;
 }
 
-static void adv7511_encoder_mode_set(struct drm_encoder *encoder,
+static void adv7511_mode_set(struct adv7511 *adv7511,
 				     struct drm_display_mode *mode,
 				     struct drm_display_mode *adj_mode)
 {
-	struct adv7511 *adv7511 = encoder_to_adv7511(encoder);
 	unsigned int low_refresh_rate;
 	unsigned int hsync_polarity = 0;
 	unsigned int vsync_polarity = 0;
@@ -812,12 +798,60 @@ static void adv7511_encoder_mode_set(struct
 drm_encoder *encoder, adv7511->f_tmds = mode->clock;
 }
 
+/*
---------------------------------------------------------------------------
-- + * Encoder operations
+ */
+
+static int adv7511_encoder_get_modes(struct drm_encoder *encoder,
+			     struct drm_connector *connector)
+{
+	struct adv7511 *adv7511 = encoder_to_adv7511(encoder);
+
+	return adv7511_get_modes(adv7511, connector);
+}
+
+static void adv7511_encoder_dpms(struct drm_encoder *encoder, int mode)
+{
+	struct adv7511 *adv7511 = encoder_to_adv7511(encoder);
+
+	if (mode == DRM_MODE_DPMS_ON)
+		adv7511_power_on(adv7511);
+	else
+		adv7511_power_off(adv7511);
+}
+
+static enum drm_connector_status
+adv7511_encoder_detect(struct drm_encoder *encoder,
+		       struct drm_connector *connector)
+{
+	struct adv7511 *adv7511 = encoder_to_adv7511(encoder);
+
+	return adv7511_detect(adv7511, connector);
+}
+
+static int adv7511_encoder_mode_valid(struct drm_encoder *encoder,
+				      struct drm_display_mode *mode)
+{
+	struct adv7511 *adv7511 = encoder_to_adv7511(encoder);
+
+	return adv7511_mode_valid(adv7511, mode);
+}
+
+static void adv7511_encoder_mode_set(struct drm_encoder *encoder,
+				     struct drm_display_mode *mode,
+				     struct drm_display_mode *adj_mode)
+{
+	struct adv7511 *adv7511 = encoder_to_adv7511(encoder);
+
+	adv7511_mode_set(adv7511, mode, adj_mode);
+}
+
 static struct drm_encoder_slave_funcs adv7511_encoder_funcs = {
 	.dpms = adv7511_encoder_dpms,
 	.mode_valid = adv7511_encoder_mode_valid,
 	.mode_set = adv7511_encoder_mode_set,
 	.detect = adv7511_encoder_detect,
-	.get_modes = adv7511_get_modes,
+	.get_modes = adv7511_encoder_get_modes,
 };
 
 /*
---------------------------------------------------------------------------
--
Signature · 3 lines
Regards,

Laurent Pinchart
#7 lore raw

Re: [PATCH 3/5] drm/i2c: adv7511: Refactor encoder slave functions

Hi,

Quoted 7 lines · Laurent Pinchart

Hi Archit,

(CC'ing Boris Brezillon)

Thank you for the patch.

On Monday 27 July 2015 11:46:57 Archit Taneja wrote:

Quoted 8 lines
Quoted 3 lines

ADV7511 is represented as an i2c drm slave encoder device. ADV7533, on the other hand, is going be a normal i2c client device creating bridge and connector entities.

Please, no. It's really time to stop piling hacks and fix the problem properly. There's no reason to have separate APIs for I2C slave encoders and DRM bridges. Those two APIs need to be merged, and then you'll find it much easier to implement ADV7533 support.

i2c slave encoders and bridges aren't exactly the same. slave encoders are used when the there is no real 'encoder' in the display chain. bridges are used when there is already an encoder available, and the bridge entity represents another encoder in the chain.

ADV7511 takes in RGB/MIPI DPI data, which is generally the output of a crtc for drm drivers.

ADV7533 takes in MIPI DSI data, which is generally the output of an encoder for drm drivers.

Therefore, having i2c slave encoder for the former and bridge for the latter made sense to me.

I do agree that it would be better if they were somehow merged. It would prevent the fragmentation we currently have among encoder chips.

One possible way would be to convert slave encoder to bridge. With this, an i2c slave encoder would be a 'dummy encoder' and a bridge. i2c slave encoders even now just tie the slave encoder helper funcs to encoder helper funcs. So it's not really any different.

Merging these 2 entities would be nice, but we're still shying away from the larger problem of creating generic encoder chains. The ideal solution would be for bridges and slave encoders to just be 'encoders', and the facility to connect on encoder output to the input of another. I don't know how easy it is to do this, and whether it'll break userspace.

Archit

Quoted 157 lines

Boris, I know you were experimenting with that, do you have anything to report ?

Quoted 152 lines

Move the code in encoder slave functions to generate helpers that are agnostic to the drm object type. These helpers will later also be used by bridge and connecter helper functions.

---
  drivers/gpu/drm/i2c/adv7511.c | 80 +++++++++++++++++++++++++++------------
  1 file changed, 57 insertions(+), 23 deletions(-)
drivers/gpu/drm/i2c/adv7511.c +56 -28
index 63a3d20..46fb24d 100644
@@ -612,13 +612,11 @@ static int adv7511_get_edid_block(void *data, u8 *buf,
 unsigned int block, }
 
  /*
---------------------------------------------------------------------------
-- - * Encoder operations
+ * ADV75xx helpers
   */
-
-static int adv7511_get_modes(struct drm_encoder *encoder,
-			     struct drm_connector *connector)
+static int adv7511_get_modes(struct adv7511 *adv7511,
+		struct drm_connector *connector)
  {
-	struct adv7511 *adv7511 = encoder_to_adv7511(encoder);
  	struct edid *edid;
  	unsigned int count;
@@ -656,21 +654,10 @@ static int adv7511_get_modes(struct drm_encoder
 *encoder, return count;
  }
 
-static void adv7511_encoder_dpms(struct drm_encoder *encoder, int mode)
-{
-	struct adv7511 *adv7511 = encoder_to_adv7511(encoder);
-
-	if (mode == DRM_MODE_DPMS_ON)
-		adv7511_power_on(adv7511);
-	else
-		adv7511_power_off(adv7511);
-}
-
  static enum drm_connector_status
-adv7511_encoder_detect(struct drm_encoder *encoder,
+adv7511_detect(struct adv7511 *adv7511,
  		       struct drm_connector *connector)
  {
-	struct adv7511 *adv7511 = encoder_to_adv7511(encoder);
  	enum drm_connector_status status;
  	unsigned int val;
  	bool hpd;
@@ -694,7 +681,7 @@ adv7511_encoder_detect(struct drm_encoder *encoder,
  	if (status == connector_status_connected && hpd && adv7511->powered) {
  		regcache_mark_dirty(adv7511->regmap);
  		adv7511_power_on(adv7511);
-		adv7511_get_modes(encoder, connector);
+		adv7511_get_modes(adv7511, connector);
  		if (adv7511->status == connector_status_connected)
  			status = connector_status_disconnected;
  	} else {
@@ -708,8 +695,8 @@ adv7511_encoder_detect(struct drm_encoder *encoder,
  	return status;
  }
 
-static int adv7511_encoder_mode_valid(struct drm_encoder *encoder,
-				      struct drm_display_mode *mode)
+static int adv7511_mode_valid(struct adv7511 *adv7511,
+				     const struct drm_display_mode *mode)
  {
  	if (mode->clock > 165000)
  		return MODE_CLOCK_HIGH;
@@ -717,11 +704,10 @@ static int adv7511_encoder_mode_valid(struct
 drm_encoder *encoder, return MODE_OK;
  }
 
-static void adv7511_encoder_mode_set(struct drm_encoder *encoder,
+static void adv7511_mode_set(struct adv7511 *adv7511,
  				     struct drm_display_mode *mode,
  				     struct drm_display_mode *adj_mode)
  {
-	struct adv7511 *adv7511 = encoder_to_adv7511(encoder);
  	unsigned int low_refresh_rate;
  	unsigned int hsync_polarity = 0;
  	unsigned int vsync_polarity = 0;
@@ -812,12 +798,60 @@ static void adv7511_encoder_mode_set(struct
 drm_encoder *encoder, adv7511->f_tmds = mode->clock;
  }
 
+/*
---------------------------------------------------------------------------
-- + * Encoder operations
+ */
+
+static int adv7511_encoder_get_modes(struct drm_encoder *encoder,
+			     struct drm_connector *connector)
+{
+	struct adv7511 *adv7511 = encoder_to_adv7511(encoder);
+
+	return adv7511_get_modes(adv7511, connector);
+}
+
+static void adv7511_encoder_dpms(struct drm_encoder *encoder, int mode)
+{
+	struct adv7511 *adv7511 = encoder_to_adv7511(encoder);
+
+	if (mode == DRM_MODE_DPMS_ON)
+		adv7511_power_on(adv7511);
+	else
+		adv7511_power_off(adv7511);
+}
+
+static enum drm_connector_status
+adv7511_encoder_detect(struct drm_encoder *encoder,
+		       struct drm_connector *connector)
+{
+	struct adv7511 *adv7511 = encoder_to_adv7511(encoder);
+
+	return adv7511_detect(adv7511, connector);
+}
+
+static int adv7511_encoder_mode_valid(struct drm_encoder *encoder,
+				      struct drm_display_mode *mode)
+{
+	struct adv7511 *adv7511 = encoder_to_adv7511(encoder);
+
+	return adv7511_mode_valid(adv7511, mode);
+}
+
+static void adv7511_encoder_mode_set(struct drm_encoder *encoder,
+				     struct drm_display_mode *mode,
+				     struct drm_display_mode *adj_mode)
+{
+	struct adv7511 *adv7511 = encoder_to_adv7511(encoder);
+
+	adv7511_mode_set(adv7511, mode, adj_mode);
+}
+
  static struct drm_encoder_slave_funcs adv7511_encoder_funcs = {
  	.dpms = adv7511_encoder_dpms,
  	.mode_valid = adv7511_encoder_mode_valid,
  	.mode_set = adv7511_encoder_mode_set,
  	.detect = adv7511_encoder_detect,
-	.get_modes = adv7511_get_modes,
+	.get_modes = adv7511_encoder_get_modes,
  };
 
  /*
---------------------------------------------------------------------------
--
Signature · 6 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
_______________________________________________
dri-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/dri-devel
#8 lore raw

Re: [PATCH 3/5] drm/i2c: adv7511: Refactor encoder slave functions

Archit, Laurent,

Quoted 42 lines · On Tue, 28 Jul 2015 13:47:37 +0530 Archit Taneja <[email protected]> wrote:

Hi,

Quoted 7 lines · Laurent Pinchart

Hi Archit,

(CC'ing Boris Brezillon)

Thank you for the patch.

On Monday 27 July 2015 11:46:57 Archit Taneja wrote:

Quoted 8 lines
Quoted 3 lines

ADV7511 is represented as an i2c drm slave encoder device. ADV7533, on the other hand, is going be a normal i2c client device creating bridge and connector entities.

Please, no. It's really time to stop piling hacks and fix the problem properly. There's no reason to have separate APIs for I2C slave encoders and DRM bridges. Those two APIs need to be merged, and then you'll find it much easier to implement ADV7533 support.

i2c slave encoders and bridges aren't exactly the same. slave encoders are used when the there is no real 'encoder' in the display chain. bridges are used when there is already an encoder available, and the bridge entity represents another encoder in the chain.

ADV7511 takes in RGB/MIPI DPI data, which is generally the output of a crtc for drm drivers.

ADV7533 takes in MIPI DSI data, which is generally the output of an encoder for drm drivers.

Therefore, having i2c slave encoder for the former and bridge for the latter made sense to me.

I do agree that it would be better if they were somehow merged. It would prevent the fragmentation we currently have among encoder chips.

One possible way would be to convert slave encoder to bridge. With this, an i2c slave encoder would be a 'dummy encoder' and a bridge. i2c slave encoders even now just tie the slave encoder helper funcs to encoder helper funcs. So it's not really any different.

Quoted 6 lines

Merging these 2 entities would be nice, but we're still shying away from the larger problem of creating generic encoder chains. The ideal solution would be for bridges and slave encoders to just be 'encoders', and the facility to connect on encoder output to the input of another. I don't know how easy it is to do this, and whether it'll break userspace.

Yes, that's pretty much what I was trying to do.
I'd also like to ease display pipelines creation by providing helper functions, so that display controller don't have to worry about encoders and connectors creation if these ones are attached to external encoders.

Quoted 6 lines

Archit

Quoted 3 lines

Boris, I know you were experimenting with that, do you have anything to report ?

Nope, I didn't work on it since last time we talked about it. I pushed my work here if you want to have a look [1].

Best Regards,

Boris

[1]https://github.com/bbrezillon/linux-at91/tree/drm-encoder-chain-WIP

Signature · 7 lines
Boris Brezillon, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
_______________________________________________
dri-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/dri-devel
#9 lore raw

Re: [PATCH 3/5] drm/i2c: adv7511: Refactor encoder slave functions

Hi Boris, Laurent,

Quoted 60 lines · Boris Brezillon

Archit, Laurent,

Quoted 42 lines · On Tue, 28 Jul 2015 13:47:37 +0530 Archit Taneja <[email protected]> wrote:

Hi,

Quoted 7 lines · Laurent Pinchart

Hi Archit,

(CC'ing Boris Brezillon)

Thank you for the patch.

On Monday 27 July 2015 11:46:57 Archit Taneja wrote:

Quoted 8 lines
Quoted 3 lines

ADV7511 is represented as an i2c drm slave encoder device. ADV7533, on the other hand, is going be a normal i2c client device creating bridge and connector entities.

Please, no. It's really time to stop piling hacks and fix the problem properly. There's no reason to have separate APIs for I2C slave encoders and DRM bridges. Those two APIs need to be merged, and then you'll find it much easier to implement ADV7533 support.

i2c slave encoders and bridges aren't exactly the same. slave encoders are used when the there is no real 'encoder' in the display chain. bridges are used when there is already an encoder available, and the bridge entity represents another encoder in the chain.

ADV7511 takes in RGB/MIPI DPI data, which is generally the output of a crtc for drm drivers.

ADV7533 takes in MIPI DSI data, which is generally the output of an encoder for drm drivers.

Therefore, having i2c slave encoder for the former and bridge for the latter made sense to me.

I do agree that it would be better if they were somehow merged. It would prevent the fragmentation we currently have among encoder chips.

One possible way would be to convert slave encoder to bridge. With this, an i2c slave encoder would be a 'dummy encoder' and a bridge. i2c slave encoders even now just tie the slave encoder helper funcs to encoder helper funcs. So it's not really any different.

Quoted 6 lines

Merging these 2 entities would be nice, but we're still shying away from the larger problem of creating generic encoder chains. The ideal solution would be for bridges and slave encoders to just be 'encoders', and the facility to connect on encoder output to the input of another. I don't know how easy it is to do this, and whether it'll break userspace.

Yes, that's pretty much what I was trying to do.
I'd also like to ease display pipelines creation by providing helper functions, so that display controller don't have to worry about encoders and connectors creation if these ones are attached to external encoders.

Quoted 1 line
Quoted 8 lines
Quoted 5 lines

Archit

Quoted 3 lines

Boris, I know you were experimenting with that, do you have anything to report ?

Nope, I didn't work on it since last time we talked about it. I pushed my work here if you want to have a look [1].

I went through the branch you shared. From what I understood, the encoder chain comprises of one 'real' encoder object (drm_encoder) in the 'drm_encoder_chain' struct. This drm_encoder encapsulates all the 'encoder elements' forming the chain.

I'm guessing the various dridge/slave encoder drivers would have to be changed to now create a drm_encoder_element object, replacing drm_bridge/drm_i2c_slave_encoder objects.

One problem I see with this approach is that we can't use this when the display controller already exposes a drm_encoder. I.e, it already creates a drm_encoder object. If we want the encoder chain to be connected to the output of this encoder, we'll need to link the 2 drm_encoders together, which isn't possible at the moment.

I guess we have two ways to go about this:

1) Have an approach like this where all the entities in the encoder chain connect to just one encoder. We define the sequence in which they are connected. The drm kms framework acts as if this chain doesn't exist, and assumes that this is what the encoder is outputting.

2) Make each element in the chain be a 'drm_encoder' object in itself. This would be a more intrusive change, since drm_encoders are expected to receive an input from crtc, and output to a connector. Furthermore, it may confuse userspace what encoder to chose.

For 1), we could either work more on your approach, or use drm_bridges. drm_bridges can already be chained to each other, and bridge ops of each bridge in the chain are called successively. It still relies on the device drivers to form the chain, which is something your
approach takes care of by itself. But that's something that can be
extended for bridges too.

Laurent,

Merging i2c slave encoders and bridges is possible, but there is no guarantee that the new solution would be future proof and work well with encoder chains. We needed more consensus from folks on dri-devel.

For ADV7533, could you please look at the other parts? Especially the one that creates a dummy mipi DSI device, and connecting to a dsi host. I'd previously posted a RFC to enable that:

http://lkml.iu.edu/hypermail/linux/kernel/1506.3/03249.html

Archit

Quoted 9 lines

Best Regards,

Boris

[1]https://github.com/bbrezillon/linux-at91/tree/drm-encoder-chain-WIP

Signature · 6 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
_______________________________________________
dri-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/dri-devel
#10 lore raw

Re: [PATCH 3/5] drm/i2c: adv7511: Refactor encoder slave functions

Hi Archit,

Quoted 81 lines · On Fri, 31 Jul 2015 10:56:20 +0530 Archit Taneja <[email protected]> wrote:

Hi Boris, Laurent,

Quoted 60 lines · Boris Brezillon

Archit, Laurent,

Quoted 42 lines · On Tue, 28 Jul 2015 13:47:37 +0530 Archit Taneja <[email protected]> wrote:

Hi,

Quoted 7 lines · Laurent Pinchart

Hi Archit,

(CC'ing Boris Brezillon)

Thank you for the patch.

On Monday 27 July 2015 11:46:57 Archit Taneja wrote:

Quoted 8 lines
Quoted 3 lines

ADV7511 is represented as an i2c drm slave encoder device. ADV7533, on the other hand, is going be a normal i2c client device creating bridge and connector entities.

Please, no. It's really time to stop piling hacks and fix the problem properly. There's no reason to have separate APIs for I2C slave encoders and DRM bridges. Those two APIs need to be merged, and then you'll find it much easier to implement ADV7533 support.

i2c slave encoders and bridges aren't exactly the same. slave encoders are used when the there is no real 'encoder' in the display chain. bridges are used when there is already an encoder available, and the bridge entity represents another encoder in the chain.

ADV7511 takes in RGB/MIPI DPI data, which is generally the output of a crtc for drm drivers.

ADV7533 takes in MIPI DSI data, which is generally the output of an encoder for drm drivers.

Therefore, having i2c slave encoder for the former and bridge for the latter made sense to me.

I do agree that it would be better if they were somehow merged. It would prevent the fragmentation we currently have among encoder chips.

One possible way would be to convert slave encoder to bridge. With this, an i2c slave encoder would be a 'dummy encoder' and a bridge. i2c slave encoders even now just tie the slave encoder helper funcs to encoder helper funcs. So it's not really any different.

Quoted 6 lines

Merging these 2 entities would be nice, but we're still shying away from the larger problem of creating generic encoder chains. The ideal solution would be for bridges and slave encoders to just be 'encoders', and the facility to connect on encoder output to the input of another. I don't know how easy it is to do this, and whether it'll break userspace.

Yes, that's pretty much what I was trying to do.
I'd also like to ease display pipelines creation by providing helper functions, so that display controller don't have to worry about encoders and connectors creation if these ones are attached to external encoders.

Quoted 1 line
Quoted 8 lines
Quoted 5 lines

Archit

Quoted 3 lines

Boris, I know you were experimenting with that, do you have anything to report ?

Nope, I didn't work on it since last time we talked about it. I pushed my work here if you want to have a look [1].

I went through the branch you shared. From what I understood, the encoder chain comprises of one 'real' encoder object (drm_encoder) in the 'drm_encoder_chain' struct. This drm_encoder encapsulates all the 'encoder elements' forming the chain.

I'm guessing the various dridge/slave encoder drivers would have to be changed to now create a drm_encoder_element object, replacing drm_bridge/drm_i2c_slave_encoder objects.

Quoted 5 lines

One problem I see with this approach is that we can't use this when the display controller already exposes a drm_encoder. I.e, it already creates a drm_encoder object. If we want the encoder chain to be connected to the output of this encoder, we'll need to link the 2 drm_encoders together, which isn't possible at the moment.

Actually my goal was to move everybody to the drm_encoder_element model, even the encoder directly provided by the display controller IP. If the internal encoder is actually directly connected to a connector, then the encoder chain will just contain one element, but everything should work fine.

Quoted 8 lines

I guess we have two ways to go about this:

1) Have an approach like this where all the entities in the encoder chain connect to just one encoder. We define the sequence in which they are connected. The drm kms framework acts as if this chain doesn't exist, and assumes that this is what the encoder is outputting.

Yep, that's pretty much what I've done. The main reason for doing that is to keep the interface with the userspace unchanged.

Quoted 5 lines

2) Make each element in the chain be a 'drm_encoder' object in itself. This would be a more intrusive change, since drm_encoders are expected to receive an input from crtc, and output to a connector. Furthermore, it may confuse userspace what encoder to chose.

That's why Laurent suggested to go for the 1st approach.

Quoted 7 lines

For 1), we could either work more on your approach, or use drm_bridges. drm_bridges can already be chained to each other, and bridge ops of each bridge in the chain are called successively. It still relies on the device drivers to form the chain, which is something your approach takes care of by itself. But that's something that can be extended for bridges too.

Can we really chain several bridges ?

Also note that I plan to automate the encoder chain creation, or at least provide helper functions so that in standard cases the display controller does not have to bother creating its encoder chain. This is particularly true for platforms supporting DT, the encoder chain + connector can be declared in a generic way, and the core could provide helper functions to parse and create the encoder chain and the endpoint connector.

Quoted 7 lines

Laurent,

Merging i2c slave encoders and bridges is possible, but there is no guarantee that the new solution would be future proof and work well with encoder chains. We needed more consensus from folks on dri-devel.

I'll let Laurent correct me if I'm wrong, but I think the plan was to move all slave encoders and bridges to the encoder element representation.

Best Regards,

Boris

Signature · 7 lines
Boris Brezillon, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
_______________________________________________
dri-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/dri-devel
#11 lore raw

Re: [PATCH 3/5] drm/i2c: adv7511: Refactor encoder slave functions

Quoted 92 lines · Boris Brezillon

Hi Archit,

Quoted 81 lines · On Fri, 31 Jul 2015 10:56:20 +0530 Archit Taneja <[email protected]> wrote:

Hi Boris, Laurent,

Quoted 60 lines · Boris Brezillon

Archit, Laurent,

Quoted 42 lines · On Tue, 28 Jul 2015 13:47:37 +0530 Archit Taneja <[email protected]> wrote:

Hi,

Quoted 7 lines · Laurent Pinchart

Hi Archit,

(CC'ing Boris Brezillon)

Thank you for the patch.

On Monday 27 July 2015 11:46:57 Archit Taneja wrote:

Quoted 8 lines
Quoted 3 lines

ADV7511 is represented as an i2c drm slave encoder device. ADV7533, on the other hand, is going be a normal i2c client device creating bridge and connector entities.

Please, no. It's really time to stop piling hacks and fix the problem properly. There's no reason to have separate APIs for I2C slave encoders and DRM bridges. Those two APIs need to be merged, and then you'll find it much easier to implement ADV7533 support.

i2c slave encoders and bridges aren't exactly the same. slave encoders are used when the there is no real 'encoder' in the display chain. bridges are used when there is already an encoder available, and the bridge entity represents another encoder in the chain.

ADV7511 takes in RGB/MIPI DPI data, which is generally the output of a crtc for drm drivers.

ADV7533 takes in MIPI DSI data, which is generally the output of an encoder for drm drivers.

Therefore, having i2c slave encoder for the former and bridge for the latter made sense to me.

I do agree that it would be better if they were somehow merged. It would prevent the fragmentation we currently have among encoder chips.

One possible way would be to convert slave encoder to bridge. With this, an i2c slave encoder would be a 'dummy encoder' and a bridge. i2c slave encoders even now just tie the slave encoder helper funcs to encoder helper funcs. So it's not really any different.

Quoted 6 lines

Merging these 2 entities would be nice, but we're still shying away from the larger problem of creating generic encoder chains. The ideal solution would be for bridges and slave encoders to just be 'encoders', and the facility to connect on encoder output to the input of another. I don't know how easy it is to do this, and whether it'll break userspace.

Yes, that's pretty much what I was trying to do.
I'd also like to ease display pipelines creation by providing helper functions, so that display controller don't have to worry about encoders and connectors creation if these ones are attached to external encoders.

Quoted 1 line
Quoted 8 lines
Quoted 5 lines

Archit

Quoted 3 lines

Boris, I know you were experimenting with that, do you have anything to report ?

Nope, I didn't work on it since last time we talked about it. I pushed my work here if you want to have a look [1].

I went through the branch you shared. From what I understood, the encoder chain comprises of one 'real' encoder object (drm_encoder) in the 'drm_encoder_chain' struct. This drm_encoder encapsulates all the 'encoder elements' forming the chain.

I'm guessing the various dridge/slave encoder drivers would have to be changed to now create a drm_encoder_element object, replacing drm_bridge/drm_i2c_slave_encoder objects.

Quoted 5 lines

One problem I see with this approach is that we can't use this when the display controller already exposes a drm_encoder. I.e, it already creates a drm_encoder object. If we want the encoder chain to be connected to the output of this encoder, we'll need to link the 2 drm_encoders together, which isn't possible at the moment.

Quoted 5 lines

Actually my goal was to move everybody to the drm_encoder_element model, even the encoder directly provided by the display controller IP. If the internal encoder is actually directly connected to a connector, then the encoder chain will just contain one element, but everything should work fine.

Okay. That approach makes sense.

It might be good to have a look at the current state of drm_bridge. We need to probably make a call between extending bridges or starting with encoder elements from scratch. Extending bridges might be less intrusive. Although, encoder elements is more uniform. In bridges, we'll be stuck with two entities: One encoder (drm_encoder), followed by a chain of bridges.

Quoted 22 lines
Quoted 9 lines

I guess we have two ways to go about this:

1) Have an approach like this where all the entities in the encoder chain connect to just one encoder. We define the sequence in which they are connected. The drm kms framework acts as if this chain doesn't exist, and assumes that this is what the encoder is outputting.

Yep, that's pretty much what I've done. The main reason for doing that is to keep the interface with the userspace unchanged.

Quoted 5 lines

2) Make each element in the chain be a 'drm_encoder' object in itself. This would be a more intrusive change, since drm_encoders are expected to receive an input from crtc, and output to a connector. Furthermore, it may confuse userspace what encoder to chose.

That's why Laurent suggested to go for the 1st approach.

Quoted 1 line
Quoted 8 lines
Quoted 6 lines

For 1), we could either work more on your approach, or use drm_bridges. drm_bridges can already be chained to each other, and bridge ops of each bridge in the chain are called successively. It still relies on the device drivers to form the chain, which is something your approach takes care of by itself. But that's something that can be extended for bridges too.

Can we really chain several bridges ?

Yes. The support was recently added. We can link one bridge to another via drm_bridge_attach(), by populating the bridge->next field.

The bridge helpers used in atomic_helper.c and crtc_helper.c recursively call all the bridges in the chain.

Quoted 8 lines

Also note that I plan to automate the encoder chain creation, or at least provide helper functions so that in standard cases the display controller does not have to bother creating its encoder chain. This is particularly true for platforms supporting DT, the encoder chain + connector can be declared in a generic way, and the core could provide helper functions to parse and create the encoder chain and the endpoint connector.

This would be quite useful.

Quoted 4 lines
Quoted 4 lines

Laurent,

Quoted 8 lines
Quoted 4 lines

Merging i2c slave encoders and bridges is possible, but there is no guarantee that the new solution would be future proof and work well with encoder chains. We needed more consensus from folks on dri-devel.

I'll let Laurent correct me if I'm wrong, but I think the plan was to move all slave encoders and bridges to the encoder element representation.

Some troubles I've had when working with encoder chains:

- There can be dependencies between two elements in the chain. For example, an element in the chain might provide interface clocks for the next element in the chain. The laterelement shouldn't even try to touch its registers if the previous element isn't enabled.

- The sequence in which each encoder element needs to be called. Some have to be first to last, others last to first.

- Some external encoder drivers(currently bridge, i2c slaves) create their own connectors within the driver. If such an encoder is placed in the middle of an encoder chain. It could lead to problems.

We might want to consider these (and probably more things) when working on the solution.

Thanks,
Archit

Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
#12 lore raw

Re: [PATCH 3/5] drm/i2c: adv7511: Refactor encoder slave functions

In reply to Boris Brezillon
Quoted 92 lines · Boris Brezillon

Hi Archit,

Quoted 81 lines · On Fri, 31 Jul 2015 10:56:20 +0530 Archit Taneja <[email protected]> wrote:

Hi Boris, Laurent,

Quoted 60 lines · Boris Brezillon

Archit, Laurent,

Quoted 42 lines · On Tue, 28 Jul 2015 13:47:37 +0530 Archit Taneja <[email protected]> wrote:

Hi,

Quoted 7 lines · Laurent Pinchart

Hi Archit,

(CC'ing Boris Brezillon)

Thank you for the patch.

On Monday 27 July 2015 11:46:57 Archit Taneja wrote:

Quoted 8 lines
Quoted 3 lines

ADV7511 is represented as an i2c drm slave encoder device. ADV7533, on the other hand, is going be a normal i2c client device creating bridge and connector entities.

Please, no. It's really time to stop piling hacks and fix the problem properly. There's no reason to have separate APIs for I2C slave encoders and DRM bridges. Those two APIs need to be merged, and then you'll find it much easier to implement ADV7533 support.

i2c slave encoders and bridges aren't exactly the same. slave encoders are used when the there is no real 'encoder' in the display chain. bridges are used when there is already an encoder available, and the bridge entity represents another encoder in the chain.

ADV7511 takes in RGB/MIPI DPI data, which is generally the output of a crtc for drm drivers.

ADV7533 takes in MIPI DSI data, which is generally the output of an encoder for drm drivers.

Therefore, having i2c slave encoder for the former and bridge for the latter made sense to me.

I do agree that it would be better if they were somehow merged. It would prevent the fragmentation we currently have among encoder chips.

One possible way would be to convert slave encoder to bridge. With this, an i2c slave encoder would be a 'dummy encoder' and a bridge. i2c slave encoders even now just tie the slave encoder helper funcs to encoder helper funcs. So it's not really any different.

Quoted 6 lines

Merging these 2 entities would be nice, but we're still shying away from the larger problem of creating generic encoder chains. The ideal solution would be for bridges and slave encoders to just be 'encoders', and the facility to connect on encoder output to the input of another. I don't know how easy it is to do this, and whether it'll break userspace.

Yes, that's pretty much what I was trying to do.
I'd also like to ease display pipelines creation by providing helper functions, so that display controller don't have to worry about encoders and connectors creation if these ones are attached to external encoders.

Quoted 1 line
Quoted 8 lines
Quoted 5 lines

Archit

Quoted 3 lines

Boris, I know you were experimenting with that, do you have anything to report ?

Nope, I didn't work on it since last time we talked about it. I pushed my work here if you want to have a look [1].

I went through the branch you shared. From what I understood, the encoder chain comprises of one 'real' encoder object (drm_encoder) in the 'drm_encoder_chain' struct. This drm_encoder encapsulates all the 'encoder elements' forming the chain.

I'm guessing the various dridge/slave encoder drivers would have to be changed to now create a drm_encoder_element object, replacing drm_bridge/drm_i2c_slave_encoder objects.

Quoted 5 lines

One problem I see with this approach is that we can't use this when the display controller already exposes a drm_encoder. I.e, it already creates a drm_encoder object. If we want the encoder chain to be connected to the output of this encoder, we'll need to link the 2 drm_encoders together, which isn't possible at the moment.

Quoted 5 lines

Actually my goal was to move everybody to the drm_encoder_element model, even the encoder directly provided by the display controller IP. If the internal encoder is actually directly connected to a connector, then the encoder chain will just contain one element, but everything should work fine.

so.. I'd be careful about changing the role of drm_encoder, as it does play a small role in the interface exposed to userspace.

If you do anything, I think you need to make i2c-encoder-slave stuff look like a drm_bridge + drm_connector, since bridge is not visible to userspace and can already be chained... which I think ends up making it more like how adv7533 looks w/ archit's patches.

That said, the adv7511 type case (raw parallel output) is kind of a better fit for the existing i2c-slave-encoder model, vs adv7533 where you already have a dsi encoder and is a better fit for the drm_bridge model. So maybe there is still a place for both.

At any rate, if we do unify, I think we should go towards the drm_bridge + drm_connector approach and migrate i2c-encoder users over to that. Which would make Archit's approach a reasonable transition step. We just drop the i2c-encoder part of it when none of the adv7511 users still depend on that.

BR,
-R

Quoted 54 lines
Quoted 8 lines

I guess we have two ways to go about this:

1) Have an approach like this where all the entities in the encoder chain connect to just one encoder. We define the sequence in which they are connected. The drm kms framework acts as if this chain doesn't exist, and assumes that this is what the encoder is outputting.

Yep, that's pretty much what I've done. The main reason for doing that is to keep the interface with the userspace unchanged.

Quoted 5 lines

2) Make each element in the chain be a 'drm_encoder' object in itself. This would be a more intrusive change, since drm_encoders are expected to receive an input from crtc, and output to a connector. Furthermore, it may confuse userspace what encoder to chose.

That's why Laurent suggested to go for the 1st approach.

Quoted 7 lines

For 1), we could either work more on your approach, or use drm_bridges. drm_bridges can already be chained to each other, and bridge ops of each bridge in the chain are called successively. It still relies on the device drivers to form the chain, which is something your approach takes care of by itself. But that's something that can be extended for bridges too.

Can we really chain several bridges ?

Also note that I plan to automate the encoder chain creation, or at least provide helper functions so that in standard cases the display controller does not have to bother creating its encoder chain. This is particularly true for platforms supporting DT, the encoder chain + connector can be declared in a generic way, and the core could provide helper functions to parse and create the encoder chain and the endpoint connector.

Quoted 7 lines

Laurent,

Merging i2c slave encoders and bridges is possible, but there is no guarantee that the new solution would be future proof and work well with encoder chains. We needed more consensus from folks on dri-devel.

I'll let Laurent correct me if I'm wrong, but I think the plan was to move all slave encoders and bridges to the encoder element representation.

Best Regards,

Boris

Quoted 8 lines

--
Boris Brezillon, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
_______________________________________________
dri-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/dri-devel

_______________________________________________
dri-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/dri-devel

#13 lore raw

Re: [PATCH 3/5] drm/i2c: adv7511: Refactor encoder slave functions

Hi Rob,

Quoted 16 lines · On Fri, 31 Jul 2015 08:13:59 -0400 Rob Clark <[email protected]> wrote:
Quoted 16 lines
Quoted 15 lines

I went through the branch you shared. From what I understood, the encoder chain comprises of one 'real' encoder object (drm_encoder) in the 'drm_encoder_chain' struct. This drm_encoder encapsulates all the 'encoder elements' forming the chain.

I'm guessing the various dridge/slave encoder drivers would have to be changed to now create a drm_encoder_element object, replacing drm_bridge/drm_i2c_slave_encoder objects.

One problem I see with this approach is that we can't use this when the display controller already exposes a drm_encoder. I.e, it already creates a drm_encoder object. If we want the encoder chain to be connected to the output of this encoder, we'll need to link the 2 drm_encoders together, which isn't possible at the moment.

Quoted 8 lines
Quoted 5 lines

Actually my goal was to move everybody to the drm_encoder_element model, even the encoder directly provided by the display controller IP. If the internal encoder is actually directly connected to a connector, then the encoder chain will just contain one element, but everything should work fine.

so.. I'd be careful about changing the role of drm_encoder, as it does play a small role in the interface exposed to userspace.

I don't think I changed the role of the drm_encoder in my approach. Actually I'm only exposing one encoder for the whole encoder chain. The encoder chain is containing one or several encoder elements, which are not exposed to userspace.

Quoted 5 lines

If you do anything, I think you need to make i2c-encoder-slave stuff look like a drm_bridge + drm_connector, since bridge is not visible to userspace and can already be chained... which I think ends up making it more like how adv7533 looks w/ archit's patches.

Okay, maybe we can do the same with drm bridges (I wasn't aware that these ones could be chained before Archit mentioned it).
I remember that I was missing a few features in the DRM bridge implementation (like the possibility to negotiate the format passed on the link between 2 encoders), but that's probably something we can add.

Quoted 5 lines

That said, the adv7511 type case (raw parallel output) is kind of a better fit for the existing i2c-slave-encoder model, vs adv7533 where you already have a dsi encoder and is a better fit for the drm_bridge model. So maybe there is still a place for both.

Excuse my ignorance, but I still don't get why the RGB/MIPI DPI are not represented as encoders. They are dummy encoders which just forwards the output of the display controller in raw RGB format, but still. IMHO, representing them as encoders in the chain would ease the whole thing.
Moreover, by doing that we would be able to link this RGB/DPI encoder to a bridge, and we wouldn't have to differentiate the encoder-slave and bridge elements.

Quoted 6 lines

At any rate, if we do unify, I think we should go towards the drm_bridge + drm_connector approach and migrate i2c-encoder users over to that. Which would make Archit's approach a reasonable transition step. We just drop the i2c-encoder part of it when none of the adv7511 users still depend on that.

Another problem I've seen with some drm bridge drivers is that they directly create their own connector, which, as Archit stated, is wrong if you decide to chain this bridge with another bridge. The other reason why the bridge should not create the connector by its own is that in some case the encoder supports different types of connectors (a TDMS encoder can be used to output HDMI or DVI), and thus, selecting the connector type should be left to the part responsible for creating the display pipelines.

This being said, I'm definitely not an expert in this area, so don't hesitate to show me where I'm wrong.

Best Regards,

Boris

Signature · 3 lines
Boris Brezillon, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
#14 lore raw

Re: [PATCH 3/5] drm/i2c: adv7511: Refactor encoder slave functions

Quoted 41 lines · Boris Brezillon

Hi Rob,

Quoted 16 lines · On Fri, 31 Jul 2015 08:13:59 -0400 Rob Clark <[email protected]> wrote:
Quoted 16 lines
Quoted 15 lines

I went through the branch you shared. From what I understood, the encoder chain comprises of one 'real' encoder object (drm_encoder) in the 'drm_encoder_chain' struct. This drm_encoder encapsulates all the 'encoder elements' forming the chain.

I'm guessing the various dridge/slave encoder drivers would have to be changed to now create a drm_encoder_element object, replacing drm_bridge/drm_i2c_slave_encoder objects.

One problem I see with this approach is that we can't use this when the display controller already exposes a drm_encoder. I.e, it already creates a drm_encoder object. If we want the encoder chain to be connected to the output of this encoder, we'll need to link the 2 drm_encoders together, which isn't possible at the moment.

Quoted 8 lines
Quoted 5 lines

Actually my goal was to move everybody to the drm_encoder_element model, even the encoder directly provided by the display controller IP. If the internal encoder is actually directly connected to a connector, then the encoder chain will just contain one element, but everything should work fine.

so.. I'd be careful about changing the role of drm_encoder, as it does play a small role in the interface exposed to userspace.

I don't think I changed the role of the drm_encoder in my approach. Actually I'm only exposing one encoder for the whole encoder chain. The encoder chain is containing one or several encoder elements, which are not exposed to userspace.

Quoted 5 lines

If you do anything, I think you need to make i2c-encoder-slave stuff look like a drm_bridge + drm_connector, since bridge is not visible to userspace and can already be chained... which I think ends up making it more like how adv7533 looks w/ archit's patches.

Quoted 5 lines

Okay, maybe we can do the same with drm bridges (I wasn't aware that these ones could be chained before Archit mentioned it).
I remember that I was missing a few features in the DRM bridge implementation (like the possibility to negotiate the format passed on the link between 2 encoders), but that's probably something we can add.

chaining bridges is very recent addition, fwiw

At any rate, extending bridge where needed seems preferable over adding new types of objects, I think.

Quoted 11 lines
Quoted 5 lines

That said, the adv7511 type case (raw parallel output) is kind of a better fit for the existing i2c-slave-encoder model, vs adv7533 where you already have a dsi encoder and is a better fit for the drm_bridge model. So maybe there is still a place for both.

Excuse my ignorance, but I still don't get why the RGB/MIPI DPI are not represented as encoders. They are dummy encoders which just forwards the output of the display controller in raw RGB format, but still. IMHO, representing them as encoders in the chain would ease the whole thing.

Yeah, creating a dummy encoder in the driver would be the approach to switch from i2c-encoder to bridge. I didn't mean to imply that this couldn't be done. The only point I was trying to make was that for simple cases don't need this currently. (The case I'm more familiar w/ is tilcdc -> tda998x but I guess other simple display controllers to adv7511 is probably similar)

I guess in the i2c-encoder case the driver ends up creating a sort of shim encoder/connector, so maybe it isn't that much different. It is a bunch of shuffling things around to change from i2c-encoder to bridge, and it ends up effecting a bunch of drivers (including some less simple ones like nouveau), so I'm not sure the best migration path. Exposing both i2c-encoder and bridge interfaces for a period of time seems unavoidable..

Quoted 11 lines

Moreover, by doing that we would be able to link this RGB/DPI encoder to a bridge, and we wouldn't have to differentiate the encoder-slave and bridge elements.

Quoted 6 lines

At any rate, if we do unify, I think we should go towards the drm_bridge + drm_connector approach and migrate i2c-encoder users over to that. Which would make Archit's approach a reasonable transition step. We just drop the i2c-encoder part of it when none of the adv7511 users still depend on that.

Quoted 3 lines

Another problem I've seen with some drm bridge drivers is that they directly create their own connector, which, as Archit stated, is wrong if you decide to chain this bridge with another bridge. The other

I agree with Archit on this. He took this approach w/ msm support for external bridges, and it seems sensible that the last bridge constructs the connector. (Plus presumably that is where hpd, ddc probing, etc, is happing)

Quoted 5 lines

reason why the bridge should not create the connector by its own is that in some case the encoder supports different types of connectors (a TDMS encoder can be used to output HDMI or DVI), and thus, selecting the connector type should be left to the part responsible for creating the display pipelines.

did you mean "should" instead of "should not"? Otherwise I don't think I understand..

BR,
-R

Quoted 11 lines

This being said, I'm definitely not an expert in this area, so don't hesitate to show me where I'm wrong.

Best Regards,

Boris

--
Boris Brezillon, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

#15 lore raw

Re: [PATCH 3/5] drm/i2c: adv7511: Refactor encoder slave functions

Hi,

Quoted 7 lines · Rob Clark
Quoted 5 lines · Boris Brezillon

Hi Rob,

On Fri, 31 Jul 2015 08:13:59 -0400
Rob Clark <[email protected]> wrote:

(...)

Quoted 9 lines
Quoted 4 lines

Another problem I've seen with some drm bridge drivers is that they directly create their own connector, which, as Archit stated, is wrong if you decide to chain this bridge with another bridge. The other

I agree with Archit on this. He took this approach w/ msm support for external bridges, and it seems sensible that the last bridge constructs the connector. (Plus presumably that is where hpd, ddc probing, etc, is happing)

With this approach many bridges should construct connector conditionally, depending if there is something behind them in pipeline (the same is true for encoders and even crtcs). It works, but for me there is lot of unnecessary code and all those conditional paths make things less friendly for development. Wouldn't be better to move creation of the connector to the main drm driver, it would require probably adding some opses/fields to drm_bridges but the drivers would be simpler, I guess.

Regards
Andrzej

Quoted 7 lines
Quoted 6 lines

reason why the bridge should not create the connector by its own is that in some case the encoder supports different types of connectors (a TDMS encoder can be used to output HDMI or DVI), and thus, selecting the connector type should be left to the part responsible for creating the display pipelines.

Quoted 17 lines

did you mean "should" instead of "should not"? Otherwise I don't think I understand..

BR,
-R

Quoted 11 lines

This being said, I'm definitely not an expert in this area, so don't hesitate to show me where I'm wrong.

Best Regards,

Boris

--
Boris Brezillon, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

_______________________________________________
dri-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/dri-devel

#16 lore raw

Re: [PATCH 3/5] drm/i2c: adv7511: Refactor encoder slave functions

Quoted 23 lines · Andrzej Hajda

Hi,

Quoted 7 lines · Rob Clark
Quoted 5 lines · Boris Brezillon

Hi Rob,

On Fri, 31 Jul 2015 08:13:59 -0400
Rob Clark <[email protected]> wrote:

(...)

Quoted 9 lines
Quoted 4 lines

Another problem I've seen with some drm bridge drivers is that they directly create their own connector, which, as Archit stated, is wrong if you decide to chain this bridge with another bridge. The other

I agree with Archit on this. He took this approach w/ msm support for external bridges, and it seems sensible that the last bridge constructs the connector. (Plus presumably that is where hpd, ddc probing, etc, is happing)

Quoted 7 lines

With this approach many bridges should construct connector conditionally, depending if there is something behind them in pipeline (the same is true for encoders and even crtcs). It works, but for me there is lot of unnecessary code and all those conditional paths make things less friendly for development. Wouldn't be better to move creation of the connector to the main drm driver, it would require probably adding some opses/fields to drm_bridges but the drivers would be simpler, I guess.

six of one, half dozen of the other.. you'd still need to implement
the hpd and ddc probe bits, and that sort of thing *somewhere*. Whether it is directly by implementing drm_connector in the bridge, or indirectly via some extra drm_bridge op's called by a shim connector in the main drm driver, doesn't really seem to change things..

BR,
-R

Quoted 29 lines

Regards
Andrzej

Quoted 24 lines
Quoted 6 lines

reason why the bridge should not create the connector by its own is that in some case the encoder supports different types of connectors (a TDMS encoder can be used to output HDMI or DVI), and thus, selecting the connector type should be left to the part responsible for creating the display pipelines.

did you mean "should" instead of "should not"? Otherwise I don't think I understand..

BR,
-R

Quoted 11 lines

This being said, I'm definitely not an expert in this area, so don't hesitate to show me where I'm wrong.

Best Regards,

Boris

--
Boris Brezillon, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

#17 lore raw

Re: [PATCH 3/5] drm/i2c: adv7511: Refactor encoder slave functions

Quoted 27 lines · Rob Clark
Quoted 19 lines · Andrzej Hajda

Hi,

Quoted 7 lines · Rob Clark
Quoted 5 lines · Boris Brezillon

Hi Rob,

On Fri, 31 Jul 2015 08:13:59 -0400
Rob Clark <[email protected]> wrote:

(...)

Quoted 7 lines
Quoted 3 lines

Another problem I've seen with some drm bridge drivers is that they directly create their own connector, which, as Archit stated, is wrong if you decide to chain this bridge with another bridge. The other

I agree with Archit on this. He took this approach w/ msm support for external bridges, and it seems sensible that the last bridge constructs the connector. (Plus presumably that is where hpd, ddc probing, etc, is happing)

Quoted 7 lines

With this approach many bridges should construct connector conditionally, depending if there is something behind them in pipeline (the same is true for encoders and even crtcs). It works, but for me there is lot of unnecessary code and all those conditional paths make things less friendly for development. Wouldn't be better to move creation of the connector to the main drm driver, it would require probably adding some opses/fields to drm_bridges but the drivers would be simpler, I guess.

Quoted 5 lines

six of one, half dozen of the other.. you'd still need to implement
the hpd and ddc probe bits, and that sort of thing *somewhere*. Whether it is directly by implementing drm_connector in the bridge, or indirectly via some extra drm_bridge op's called by a shim connector in the main drm driver, doesn't really seem to change things..

The difference is that instead of duplicating connector related code in every driver you will call one helper from the main drm driver/core.

Regards
Andrzej

Quoted 29 lines

BR,
-R

Quoted 25 lines

Regards
Andrzej

Quoted 22 lines
Quoted 5 lines

reason why the bridge should not create the connector by its own is that in some case the encoder supports different types of connectors (a TDMS encoder can be used to output HDMI or DVI), and thus, selecting the connector type should be left to the part responsible for creating the display pipelines.

did you mean "should" instead of "should not"? Otherwise I don't think I understand..

BR,
-R

Quoted 11 lines

This being said, I'm definitely not an expert in this area, so don't hesitate to show me where I'm wrong.

Best Regards,

Boris

--
Boris Brezillon, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

#18 lore raw

Re: [PATCH 3/5] drm/i2c: adv7511: Refactor encoder slave functions

Quoted 28 lines · Andrzej Hajda
Quoted 27 lines · Rob Clark
Quoted 26 lines · Andrzej Hajda

Hi,

Quoted 7 lines · Rob Clark
Quoted 5 lines · Boris Brezillon

Hi Rob,

On Fri, 31 Jul 2015 08:13:59 -0400
Rob Clark <[email protected]> wrote:

(...)

Quoted 7 lines
Quoted 3 lines

Another problem I've seen with some drm bridge drivers is that they directly create their own connector, which, as Archit stated, is wrong if you decide to chain this bridge with another bridge. The other

I agree with Archit on this. He took this approach w/ msm support for external bridges, and it seems sensible that the last bridge constructs the connector. (Plus presumably that is where hpd, ddc probing, etc, is happing)

With this approach many bridges should construct connector conditionally, depending if there is something behind them in pipeline (the same is true for encoders and even crtcs). It works, but for me there is lot of unnecessary code and all those conditional paths make things less friendly for development. Wouldn't be better to move creation of the connector to the main drm driver, it would require probably adding some opses/fields to drm_bridges but the drivers would be simpler, I guess.

Quoted 8 lines
Quoted 5 lines

six of one, half dozen of the other.. you'd still need to implement
the hpd and ddc probe bits, and that sort of thing *somewhere*. Whether it is directly by implementing drm_connector in the bridge, or indirectly via some extra drm_bridge op's called by a shim connector in the main drm driver, doesn't really seem to change things..

The difference is that instead of duplicating connector related code in every driver you will call one helper from the main drm driver/core.

Which isn't more than a few lines of code.. I mean, looking at a couple connectors, the bulk of the code is hpd and ddc related. That doesn't magically go away. There isn't that many lines of boilerplate, so meh.

BR,
-R

Quoted 33 lines

Regards
Andrzej

Quoted 29 lines

BR,
-R

Quoted 25 lines

Regards
Andrzej

Quoted 22 lines
Quoted 5 lines

reason why the bridge should not create the connector by its own is that in some case the encoder supports different types of connectors (a TDMS encoder can be used to output HDMI or DVI), and thus, selecting the connector type should be left to the part responsible for creating the display pipelines.

did you mean "should" instead of "should not"? Otherwise I don't think I understand..

BR,
-R

Quoted 11 lines

This being said, I'm definitely not an expert in this area, so don't hesitate to show me where I'm wrong.

Best Regards,

Boris

--
Boris Brezillon, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

#19 lore raw

Re: [PATCH 3/5] drm/i2c: adv7511: Refactor encoder slave functions

Quoted 35 lines · Rob Clark
Quoted 34 lines · Andrzej Hajda
Quoted 32 lines · Rob Clark
Quoted 19 lines · Andrzej Hajda

Hi,

Quoted 7 lines · Rob Clark
Quoted 5 lines · Boris Brezillon

Hi Rob,

On Fri, 31 Jul 2015 08:13:59 -0400
Rob Clark <[email protected]> wrote:

(...)

Quoted 7 lines
Quoted 3 lines

Another problem I've seen with some drm bridge drivers is that they directly create their own connector, which, as Archit stated, is wrong if you decide to chain this bridge with another bridge. The other

I agree with Archit on this. He took this approach w/ msm support for external bridges, and it seems sensible that the last bridge constructs the connector. (Plus presumably that is where hpd, ddc probing, etc, is happing)

Quoted 7 lines

With this approach many bridges should construct connector conditionally, depending if there is something behind them in pipeline (the same is true for encoders and even crtcs). It works, but for me there is lot of unnecessary code and all those conditional paths make things less friendly for development. Wouldn't be better to move creation of the connector to the main drm driver, it would require probably adding some opses/fields to drm_bridges but the drivers would be simpler, I guess.

six of one, half dozen of the other.. you'd still need to implement
the hpd and ddc probe bits, and that sort of thing *somewhere*. Whether it is directly by implementing drm_connector in the bridge, or indirectly via some extra drm_bridge op's called by a shim connector in the main drm driver, doesn't really seem to change things..

Quoted 7 lines
Quoted 2 lines

The difference is that instead of duplicating connector related code in every driver you will call one helper from the main drm driver/core.

Which isn't more than a few lines of code.. I mean, looking at a couple connectors, the bulk of the code is hpd and ddc related. That doesn't magically go away. There isn't that many lines of boilerplate, so meh.

Could we get to a consensus for this?

Is it okay for bridge and i2c_encoder to co-exist for now?

Thanks,
Archit

Quoted 37 lines

BR,
-R

Quoted 33 lines

Regards
Andrzej

Quoted 29 lines

BR,
-R

Quoted 25 lines

Regards
Andrzej

Quoted 22 lines
Quoted 5 lines

reason why the bridge should not create the connector by its own is that in some case the encoder supports different types of connectors (a TDMS encoder can be used to output HDMI or DVI), and thus, selecting the connector type should be left to the part responsible for creating the display pipelines.

did you mean "should" instead of "should not"? Otherwise I don't think I understand..

BR,
-R

Quoted 11 lines

This being said, I'm definitely not an expert in this area, so don't hesitate to show me where I'm wrong.

Best Regards,

Boris

--
Boris Brezillon, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
#20 lore raw

Re: [PATCH 3/5] drm/i2c: adv7511: Refactor encoder slave functions

In reply to Laurent Pinchart
Quoted 7 lines · Laurent Pinchart

Hi Archit,

(CC'ing Boris Brezillon)

Thank you for the patch.

On Monday 27 July 2015 11:46:57 Archit Taneja wrote:

Quoted 8 lines
Quoted 3 lines

ADV7511 is represented as an i2c drm slave encoder device. ADV7533, on the other hand, is going be a normal i2c client device creating bridge and connector entities.

Please, no. It's really time to stop piling hacks and fix the problem properly. There's no reason to have separate APIs for I2C slave encoders and DRM bridges. Those two APIs need to be merged, and then you'll find it much easier to implement ADV7533 support.

btw, what is the status here? I'd kind of lost track of the discussion, but I'm getting impatient that it is somehow taking ridiculously long to get adv7533 support merged. (It's good thing the x86/desktop folks don't bikeshed so much.. I'd hate to wait a year for my new laptop to be supported..)

Anyways, if needed, just copy/paste the adv7511/7533 code into a separate bridge-only driver, and we'll use that. Once the i2c-slave-encoder users for adv7511 are converted over, we can delete the original slave encoder driver. That seems like a sane transition plan to a bridge-only world.

BR,
-R

Quoted 159 lines

Boris, I know you were experimenting with that, do you have anything to report ?

Quoted 142 lines

Move the code in encoder slave functions to generate helpers that are agnostic to the drm object type. These helpers will later also be used by bridge and connecter helper functions.

---
 drivers/gpu/drm/i2c/adv7511.c | 80 +++++++++++++++++++++++++++------------
 1 file changed, 57 insertions(+), 23 deletions(-)
drivers/gpu/drm/i2c/adv7511.c +55 -25
index 63a3d20..46fb24d 100644
@@ -612,13 +612,11 @@ static int adv7511_get_edid_block(void *data, u8 *buf,
 unsigned int block, }
 
 /*
---------------------------------------------------------------------------
-- - * Encoder operations
+ * ADV75xx helpers
  */
-
-static int adv7511_get_modes(struct drm_encoder *encoder,
-                          struct drm_connector *connector)
+static int adv7511_get_modes(struct adv7511 *adv7511,
+             struct drm_connector *connector)
 {
-     struct adv7511 *adv7511 = encoder_to_adv7511(encoder);
      struct edid *edid;
      unsigned int count;
@@ -656,21 +654,10 @@ static int adv7511_get_modes(struct drm_encoder
 *encoder, return count;
 }
 
-static void adv7511_encoder_dpms(struct drm_encoder *encoder, int mode)
-{
-     struct adv7511 *adv7511 = encoder_to_adv7511(encoder);
-
-     if (mode == DRM_MODE_DPMS_ON)
-             adv7511_power_on(adv7511);
-     else
-             adv7511_power_off(adv7511);
-}
-
 static enum drm_connector_status
-adv7511_encoder_detect(struct drm_encoder *encoder,
+adv7511_detect(struct adv7511 *adv7511,
                     struct drm_connector *connector)
 {
-     struct adv7511 *adv7511 = encoder_to_adv7511(encoder);
      enum drm_connector_status status;
      unsigned int val;
      bool hpd;
@@ -694,7 +681,7 @@ adv7511_encoder_detect(struct drm_encoder *encoder,
      if (status == connector_status_connected && hpd && adv7511->powered) {
              regcache_mark_dirty(adv7511->regmap);
              adv7511_power_on(adv7511);
-             adv7511_get_modes(encoder, connector);
+             adv7511_get_modes(adv7511, connector);
              if (adv7511->status == connector_status_connected)
                      status = connector_status_disconnected;
      } else {
@@ -708,8 +695,8 @@ adv7511_encoder_detect(struct drm_encoder *encoder,
      return status;
 }
 
-static int adv7511_encoder_mode_valid(struct drm_encoder *encoder,
-                                   struct drm_display_mode *mode)
+static int adv7511_mode_valid(struct adv7511 *adv7511,
+                                  const struct drm_display_mode *mode)
 {
      if (mode->clock > 165000)
              return MODE_CLOCK_HIGH;
@@ -717,11 +704,10 @@ static int adv7511_encoder_mode_valid(struct
 drm_encoder *encoder, return MODE_OK;
 }
 
-static void adv7511_encoder_mode_set(struct drm_encoder *encoder,
+static void adv7511_mode_set(struct adv7511 *adv7511,
                                   struct drm_display_mode *mode,
                                   struct drm_display_mode *adj_mode)
 {
-     struct adv7511 *adv7511 = encoder_to_adv7511(encoder);
      unsigned int low_refresh_rate;
      unsigned int hsync_polarity = 0;
      unsigned int vsync_polarity = 0;
@@ -812,12 +798,60 @@ static void adv7511_encoder_mode_set(struct
 drm_encoder *encoder, adv7511->f_tmds = mode->clock;
 }
 
+/*
---------------------------------------------------------------------------
-- + * Encoder operations
+ */
+
+static int adv7511_encoder_get_modes(struct drm_encoder *encoder,
+                          struct drm_connector *connector)
+{
+     struct adv7511 *adv7511 = encoder_to_adv7511(encoder);
+
+     return adv7511_get_modes(adv7511, connector);
+}
+
+static void adv7511_encoder_dpms(struct drm_encoder *encoder, int mode)
+{
+     struct adv7511 *adv7511 = encoder_to_adv7511(encoder);
+
+     if (mode == DRM_MODE_DPMS_ON)
+             adv7511_power_on(adv7511);
+     else
+             adv7511_power_off(adv7511);
+}
+
+static enum drm_connector_status
+adv7511_encoder_detect(struct drm_encoder *encoder,
+                    struct drm_connector *connector)
+{
+     struct adv7511 *adv7511 = encoder_to_adv7511(encoder);
+
+     return adv7511_detect(adv7511, connector);
+}
+
+static int adv7511_encoder_mode_valid(struct drm_encoder *encoder,
+                                   struct drm_display_mode *mode)
+{
+     struct adv7511 *adv7511 = encoder_to_adv7511(encoder);
+
+     return adv7511_mode_valid(adv7511, mode);
+}
+
+static void adv7511_encoder_mode_set(struct drm_encoder *encoder,
+                                  struct drm_display_mode *mode,
+                                  struct drm_display_mode *adj_mode)
+{
+     struct adv7511 *adv7511 = encoder_to_adv7511(encoder);
+
+     adv7511_mode_set(adv7511, mode, adj_mode);
+}
+
 static struct drm_encoder_slave_funcs adv7511_encoder_funcs = {
      .dpms = adv7511_encoder_dpms,

drivers/gpu/drm/i2c/adv7511.c static void adv7511_encoder_mode_set(struct

Quoted 10 lines
drivers/gpu/drm/i2c/adv7511.c +1 -3
      .mode_valid = adv7511_encoder_mode_valid,
      .mode_set = adv7511_encoder_mode_set,
      .detect = adv7511_encoder_detect,
-     .get_modes = adv7511_get_modes,
+     .get_modes = adv7511_encoder_get_modes,
 };
 
 /*
---------------------------------------------------------------------------
--

--
Regards,

Quoted 6 lines

Laurent Pinchart

_______________________________________________
dri-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/dri-devel

_______________________________________________
dri-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/dri-devel

#21 lore raw

Re: [PATCH 3/5] drm/i2c: adv7511: Refactor encoder slave functions

Quoted 11 lines · On Thursday 03 December 2015 10:02:02 Rob Clark wrote:
Quoted 9 lines · Laurent Pinchart
Quoted 3 lines · On Monday 27 July 2015 11:46:57 Archit Taneja wrote:

ADV7511 is represented as an i2c drm slave encoder device. ADV7533, on the other hand, is going be a normal i2c client device creating bridge and connector entities.

Please, no. It's really time to stop piling hacks and fix the problem properly. There's no reason to have separate APIs for I2C slave encoders and DRM bridges. Those two APIs need to be merged, and then you'll find it much easier to implement ADV7533 support.

Quoted 5 lines

btw, what is the status here? I'd kind of lost track of the discussion, but I'm getting impatient that it is somehow taking ridiculously long to get adv7533 support merged. (It's good thing the x86/desktop folks don't bikeshed so much.. I'd hate to wait a year for my new laptop to be supported..)

I'd hardly call the overall architecture on which drivers rely a bikeshed (and maybe if x86/desktop folks cared more about embedded there would be more willingness to make the framework evolve in an embedded-friendly way).

Quoted 5 lines

Anyways, if needed, just copy/paste the adv7511/7533 code into a separate bridge-only driver, and we'll use that. Once the i2c-slave-encoder users for adv7511 are converted over, we can delete the original slave encoder driver. That seems like a sane transition plan to a bridge-only world.

It's a very sane way to make sure nobody will do the work and keep two copies of the same code for a long time, yes.

The path forward is pretty clear, the issue is to find someone who can do the work.

Signature · 3 lines
Regards,

Laurent Pinchart
#22 lore raw

Re: [PATCH 3/5] drm/i2c: adv7511: Refactor encoder slave functions

Quoted 18 lines · Laurent Pinchart
Quoted 11 lines · On Thursday 03 December 2015 10:02:02 Rob Clark wrote:
Quoted 9 lines · Laurent Pinchart
Quoted 3 lines · On Monday 27 July 2015 11:46:57 Archit Taneja wrote:

ADV7511 is represented as an i2c drm slave encoder device. ADV7533, on the other hand, is going be a normal i2c client device creating bridge and connector entities.

Please, no. It's really time to stop piling hacks and fix the problem properly. There's no reason to have separate APIs for I2C slave encoders and DRM bridges. Those two APIs need to be merged, and then you'll find it much easier to implement ADV7533 support.

Quoted 5 lines

btw, what is the status here? I'd kind of lost track of the discussion, but I'm getting impatient that it is somehow taking ridiculously long to get adv7533 support merged. (It's good thing the x86/desktop folks don't bikeshed so much.. I'd hate to wait a year for my new laptop to be supported..)

Quoted 3 lines

I'd hardly call the overall architecture on which drivers rely a bikeshed (and maybe if x86/desktop folks cared more about embedded there would be more willingness to make the framework evolve in an embedded-friendly way).

I don't know that we can blame this on the desktop folks like that.. after all i2c-slave was sufficient for embedded devices for some time, and it was an improvement over what came before when it comes to sharing external encoder support (ie. nothing)

But, as was the case with atomic, the framework evolves. And as atomic roll-out has shown, it doesn't require a flag-day if you accept some duplication.

Quoted 8 lines
Quoted 5 lines

Anyways, if needed, just copy/paste the adv7511/7533 code into a separate bridge-only driver, and we'll use that. Once the i2c-slave-encoder users for adv7511 are converted over, we can delete the original slave encoder driver. That seems like a sane transition plan to a bridge-only world.

It's a very sane way to make sure nobody will do the work and keep two copies of the same code for a long time, yes.

As opposed to a change everything at once approach, and corresponding updates to drivers for hw you don't have. That sounds like a *much* saner plan</sarcasm>

Seriously, the cost of duplicating a bit of code is low. Especially when the code you are duplicating is low churn. Duplicating lets other drivers that use adv75xx via slave-encoder migrate over at their own pace. Similar to how atomic was rolled out. To me that sounds like the much more practical way forward.

Quoted 2 lines

The path forward is pretty clear, the issue is to find someone who can do the work.

Maybe the end goal is clear. But apparently the path forward less so.

BR,
-R

Quoted 5 lines

--
Regards,

Laurent Pinchart

#23 lore raw

Re: [PATCH 3/5] drm/i2c: adv7511: Refactor encoder slave functions

Hi Rob,

Quoted 19 lines · On Thursday 03 December 2015 10:55:12 Rob Clark wrote:
Quoted 18 lines · Laurent Pinchart
Quoted 16 lines · On Thursday 03 December 2015 10:02:02 Rob Clark wrote:
Quoted 9 lines · Laurent Pinchart
Quoted 3 lines · On Monday 27 July 2015 11:46:57 Archit Taneja wrote:

ADV7511 is represented as an i2c drm slave encoder device. ADV7533, on the other hand, is going be a normal i2c client device creating bridge and connector entities.

Please, no. It's really time to stop piling hacks and fix the problem properly. There's no reason to have separate APIs for I2C slave encoders and DRM bridges. Those two APIs need to be merged, and then you'll find it much easier to implement ADV7533 support.

btw, what is the status here? I'd kind of lost track of the discussion, but I'm getting impatient that it is somehow taking ridiculously long to get adv7533 support merged. (It's good thing the x86/desktop folks don't bikeshed so much.. I'd hate to wait a year for my new laptop to be supported..)

Quoted 6 lines
Quoted 4 lines

I'd hardly call the overall architecture on which drivers rely a bikeshed (and maybe if x86/desktop folks cared more about embedded there would be more willingness to make the framework evolve in an embedded-friendly way).

I don't know that we can blame this on the desktop folks like that..

To be clear I'm not blaming anyone here, just pointing out that the grass isn't all green on the other side ;-)

Quoted 14 lines

after all i2c-slave was sufficient for embedded devices for some time, and it was an improvement over what came before when it comes to sharing external encoder support (ie. nothing)

But, as was the case with atomic, the framework evolves. And as atomic roll-out has shown, it doesn't require a flag-day if you accept some duplication.

Quoted 6 lines
Quoted 5 lines

Anyways, if needed, just copy/paste the adv7511/7533 code into a separate bridge-only driver, and we'll use that. Once the i2c-slave-encoder users for adv7511 are converted over, we can delete the original slave encoder driver. That seems like a sane transition plan to a bridge-only world.

Quoted 6 lines
Quoted 2 lines

It's a very sane way to make sure nobody will do the work and keep two copies of the same code for a long time, yes.

As opposed to a change everything at once approach, and corresponding updates to drivers for hw you don't have. That sounds like a *much* saner plan</sarcasm>

There's a single driver using the adv7511 I2C slave encoder, that's the rcar- du driver. I will make sure to update and test the driver.

Quoted 10 lines

Seriously, the cost of duplicating a bit of code is low. Especially when the code you are duplicating is low churn. Duplicating lets other drivers that use adv75xx via slave-encoder migrate over at their own pace. Similar to how atomic was rolled out. To me that sounds like the much more practical way forward.

Quoted 2 lines

The path forward is pretty clear, the issue is to find someone who can do the work.

Maybe the end goal is clear. But apparently the path forward less so.

Signature · 8 lines
Regards,

Laurent Pinchart

_______________________________________________
dri-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/dri-devel
#24 lore raw

Re: [PATCH 3/5] drm/i2c: adv7511: Refactor encoder slave functions

In reply to Rob Clark
Quoted 46 lines · Rob Clark
Quoted 18 lines · Laurent Pinchart
Quoted 11 lines · On Thursday 03 December 2015 10:02:02 Rob Clark wrote:
Quoted 9 lines · Laurent Pinchart
Quoted 3 lines · On Monday 27 July 2015 11:46:57 Archit Taneja wrote:

ADV7511 is represented as an i2c drm slave encoder device. ADV7533, on the other hand, is going be a normal i2c client device creating bridge and connector entities.

Please, no. It's really time to stop piling hacks and fix the problem properly. There's no reason to have separate APIs for I2C slave encoders and DRM bridges. Those two APIs need to be merged, and then you'll find it much easier to implement ADV7533 support.

Quoted 5 lines

btw, what is the status here? I'd kind of lost track of the discussion, but I'm getting impatient that it is somehow taking ridiculously long to get adv7533 support merged. (It's good thing the x86/desktop folks don't bikeshed so much.. I'd hate to wait a year for my new laptop to be supported..)

Quoted 3 lines

I'd hardly call the overall architecture on which drivers rely a bikeshed (and maybe if x86/desktop folks cared more about embedded there would be more willingness to make the framework evolve in an embedded-friendly way).

I don't know that we can blame this on the desktop folks like that.. after all i2c-slave was sufficient for embedded devices for some time, and it was an improvement over what came before when it comes to sharing external encoder support (ie. nothing)

But, as was the case with atomic, the framework evolves. And as atomic roll-out has shown, it doesn't require a flag-day if you accept some duplication.

Quoted 8 lines
Quoted 5 lines

Anyways, if needed, just copy/paste the adv7511/7533 code into a separate bridge-only driver, and we'll use that. Once the i2c-slave-encoder users for adv7511 are converted over, we can delete the original slave encoder driver. That seems like a sane transition plan to a bridge-only world.

It's a very sane way to make sure nobody will do the work and keep two copies of the same code for a long time, yes.

As opposed to a change everything at once approach, and corresponding updates to drivers for hw you don't have. That sounds like a *much* saner plan</sarcasm>

Quoted 8 lines

Seriously, the cost of duplicating a bit of code is low. Especially when the code you are duplicating is low churn. Duplicating lets other drivers that use adv75xx via slave-encoder migrate over at their own pace. Similar to how atomic was rolled out. To me that sounds like the much more practical way forward.

Quoted 2 lines

The path forward is pretty clear, the issue is to find someone who can do the work.

I volunteer (as tribute)!

Once we settle on the best way to do it.

Quoted 2 lines

Maybe the end goal is clear. But apparently the path forward less so.

Laurent, as we'd discussed in the past, I did an initial study of how we could map bridge ops to the encoder slave ops, and change it for the rcar kms driver (and others) that might use adv7511.

The drm_encoder_slave_funcs ops are a superset of bridge ops. The rcar-du driver uses a subset of these ops (encoder-like ops) to implement the hdmi encoder (rcar_du_hdmienc.c) and the other (connector-like ops)for implementing the hdmi connector (rcar_du_hdmicon.c)

We have two options:

1. If we want to use drm_bridge as it is, the rcar driver shouldn't create a hdmi connector anymore, and rely on the adv7511 driver to make a connector for it. This is the easiest way, but it will break the nice representation of the hardware in DT.

2. We add more drm_bridge ops (the ones that implement the connector ops), and make the hdmi connector created by rcar-du use these bridge ops.

Both these options have issues. The 2) one is the probably the better of the two, but I don't know if adding more ops to the bridge is the right way to go.

Therefore, I don't know how we can solve this straight away. If there is more debate needed on this, then it is probably easier to get adv7533 support in, and then figure out how two merge the two.

Archit

Quoted 9 lines

BR,
-R

Quoted 5 lines

--
Regards,

Laurent Pinchart

Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
#25 lore raw

Re: [PATCH 3/5] drm/i2c: adv7511: Refactor encoder slave functions

Hi Laurent,

Quoted 13 lines · Archit Taneja
Quoted 10 lines · Rob Clark
Quoted 8 lines · Laurent Pinchart
Quoted 7 lines · On Thursday 03 December 2015 10:02:02 Rob Clark wrote:
Quoted 6 lines · Laurent Pinchart
Quoted 5 lines · On Monday 27 July 2015 11:46:57 Archit Taneja wrote:

ADV7511 is represented as an i2c drm slave encoder device. ADV7533, on
the other hand, is going be a normal i2c client device creating bridge
and connector entities.

<snip>

Quoted 22 lines

Laurent, as we'd discussed in the past, I did an initial study of how we could map bridge ops to the encoder slave ops, and change it for the rcar kms driver (and others) that might use adv7511.

The drm_encoder_slave_funcs ops are a superset of bridge ops. The rcar-du driver uses a subset of these ops (encoder-like ops) to implement the hdmi encoder (rcar_du_hdmienc.c) and the other (connector-like ops)for implementing the hdmi connector (rcar_du_hdmicon.c)

We have two options:

1. If we want to use drm_bridge as it is, the rcar driver shouldn't create a hdmi connector anymore, and rely on the adv7511 driver to make a connector for it. This is the easiest way, but it will break the nice representation of the hardware in DT.

2. We add more drm_bridge ops (the ones that implement the connector ops), and make the hdmi connector created by rcar-du use these bridge ops.

Quoted 8 lines

Both these options have issues. The 2) one is the probably the better of the two, but I don't know if adding more ops to the bridge is the right way to go.

Therefore, I don't know how we can solve this straight away. If there is more debate needed on this, then it is probably easier to get adv7533 support in, and then figure out how two merge the two.

I gave approach (1) a try. I modified the rcar-du driver to use bridge instead of i2c slave encoder and posted a RFC [1]. The hdmi connector DT nodes (like in r8a7790-lager.dts) aren't really used by the rcar-du driver. Now, with the adv7511 driver creating its own connector, they mean even much less.

The adv7511 refactor from i2c slave encoder to bridge is done in [2].

[1] http://marc.info/?l=dri-devel&m=145235835902378&w=1
[2] http://marc.info/?l=dri-devel&m=145235823602353&w=1

Could you please review and test?

Thanks,
Archit

Quoted 11 lines
Quoted 10 lines

BR,
-R

Quoted 5 lines

--
Regards,

Laurent Pinchart

Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
#26 lore raw

PATCH 4/5 drm/i2c: adv7511: Add drm_bridge/connector for ADV7533

In reply to Archit Taneja

Create bridge and connector helper functions. These internally refer to the ADV75xx helper functions.

The driver registers a drm_bridge object during probe. The bridge, in turn registers a HDMI connector when a user attaches the bridge.

Therefore, when the device type is ADV7533, we create bridge and connector entities, and when it's ADV7511, we create a slave encoder as before.

Since the i2c driver is still wrapped around by the drm_i2c_slave_encoder struct. We make sure the encoder_init op returns an error when the device type is ADV7533.

---
 drivers/gpu/drm/i2c/adv7511.c | 155 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 155 insertions(+)
drivers/gpu/drm/i2c/adv7511.c +155 -0
index 46fb24d..10642e1 100644
@@ -17,6 +17,8 @@
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_edid.h>
 #include <drm/drm_encoder_slave.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
 
 #include "adv7511.h"
 
@@ -44,6 +46,9 @@ struct adv7511 {
 	wait_queue_head_t wq;
 	struct drm_encoder *encoder;
 
+	struct drm_connector connector;
+	struct drm_bridge bridge;
+
 	bool embedded_sync;
 	enum adv7511_sync_polarity vsync_polarity;
 	enum adv7511_sync_polarity hsync_polarity;
@@ -855,6 +860,139 @@ static struct drm_encoder_slave_funcs adv7511_encoder_funcs = {
 };
 
 /* -----------------------------------------------------------------------------
+ * Bridge and connector functions
+ */
+
+static struct adv7511 *connector_to_adv7511(struct drm_connector *connector)
+{
+	return container_of(connector, struct adv7511, connector);
+}
+
+/* Connector helper functions */
+static int adv7533_connector_get_modes(struct drm_connector *connector)
+{
+	struct adv7511 *adv = connector_to_adv7511(connector);
+
+	return adv7511_get_modes(adv, connector);
+}
+
+static struct drm_encoder *
+adv7533_connector_best_encoder(struct drm_connector *connector)
+{
+	struct adv7511 *adv = connector_to_adv7511(connector);
+
+	return adv->bridge.encoder;
+}
+
+static enum drm_mode_status
+adv7533_connector_mode_valid(struct drm_connector *connector,
+				struct drm_display_mode *mode)
+{
+	struct adv7511 *adv = connector_to_adv7511(connector);
+
+	return adv7511_mode_valid(adv, mode);
+}
+
+static struct drm_connector_helper_funcs adv7533_connector_helper_funcs = {
+	.get_modes = adv7533_connector_get_modes,
+	.best_encoder = adv7533_connector_best_encoder,
+	.mode_valid = adv7533_connector_mode_valid,
+};
+
+static enum drm_connector_status
+adv7533_connector_detect(struct drm_connector *connector, bool force)
+{
+	struct adv7511 *adv = connector_to_adv7511(connector);
+
+	return adv7511_detect(adv, connector);
+}
+
+static struct drm_connector_funcs adv7533_connector_funcs = {
+	.dpms = drm_helper_connector_dpms,
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.detect = adv7533_connector_detect,
+	.destroy = drm_connector_cleanup,
+	.reset = drm_atomic_helper_connector_reset,
+	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+/* Bridge funcs */
+static struct adv7511 *bridge_to_adv7511(struct drm_bridge *bridge)
+{
+	return container_of(bridge, struct adv7511, bridge);
+}
+
+static void adv7533_bridge_pre_enable(struct drm_bridge *bridge)
+{
+	struct adv7511 *adv = bridge_to_adv7511(bridge);
+
+	adv7511_power_on(adv);
+}
+
+static void adv7533_bridge_post_disable(struct drm_bridge *bridge)
+{
+	struct adv7511 *adv = bridge_to_adv7511(bridge);
+
+	adv7511_power_off(adv);
+}
+
+static void adv7533_bridge_enable(struct drm_bridge *bridge)
+{
+}
+
+static void adv7533_bridge_disable(struct drm_bridge *bridge)
+{
+}
+
+static void adv7533_bridge_mode_set(struct drm_bridge *bridge,
+				     struct drm_display_mode *mode,
+				     struct drm_display_mode *adj_mode)
+{
+	struct adv7511 *adv = bridge_to_adv7511(bridge);
+
+	adv7511_mode_set(adv, mode, adj_mode);
+}
+
+static int adv7533_bridge_attach(struct drm_bridge *bridge)
+{
+	struct adv7511 *adv = bridge_to_adv7511(bridge);
+	int ret;
+
+	adv->encoder = bridge->encoder;
+
+	if (!bridge->encoder) {
+		DRM_ERROR("Parent encoder object not found");
+		return -ENODEV;
+	}
+
+	adv->connector.polled = DRM_CONNECTOR_POLL_HPD;
+	ret = drm_connector_init(bridge->dev, &adv->connector,
+			&adv7533_connector_funcs, DRM_MODE_CONNECTOR_HDMIA);
+	if (ret) {
+		DRM_ERROR("Failed to initialize connector with drm\n");
+		return ret;
+	}
+	drm_connector_helper_add(&adv->connector,
+					&adv7533_connector_helper_funcs);
+	drm_connector_register(&adv->connector);
+	drm_mode_connector_attach_encoder(&adv->connector, adv->encoder);
+
+	drm_helper_hpd_irq_event(adv->connector.dev);
+
+	return ret;
+}
+
+static struct drm_bridge_funcs adv7533_bridge_funcs = {
+	.pre_enable = adv7533_bridge_pre_enable,
+	.enable = adv7533_bridge_enable,
+	.disable = adv7533_bridge_disable,
+	.post_disable = adv7533_bridge_post_disable,
+	.mode_set = adv7533_bridge_mode_set,
+	.attach = adv7533_bridge_attach,
+};
+
+/* -----------------------------------------------------------------------------
  * Probe & remove
  */
 
@@ -1079,6 +1217,17 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
 	if (adv7511->type == ADV7511)
 		adv7511_set_link_config(adv7511, &link_config);
 
+	if (adv7511->type == ADV7533) {
+		adv7511->bridge.funcs = &adv7533_bridge_funcs;
+		adv7511->bridge.of_node = dev->of_node;
+
+		ret = drm_bridge_add(&adv7511->bridge);
+		if (ret) {
+			dev_err(dev, "failed to add adv7533 bridge\n");
+			goto err_i2c_unregister_cec;
+		}
+	}
+
 	return 0;
 
 err_i2c_unregister_cec:
@@ -1098,6 +1247,9 @@ static int adv7511_remove(struct i2c_client *i2c)
 
 	kfree(adv7511->edid);
 
+	if (adv7511->type == ADV7533)
+		drm_bridge_remove(&adv7511->bridge);
+
 	return 0;
 }
 
@@ -1107,6 +1259,9 @@ static int adv7511_encoder_init(struct i2c_client *i2c, struct drm_device *dev,
 
 	struct adv7511 *adv7511 = i2c_get_clientdata(i2c);
 
+	if (adv7511->type == ADV7533)
+		return -ENODEV;
+
 	encoder->slave_priv = adv7511;
 	encoder->slave_funcs = &adv7511_encoder_funcs;
 
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
#27 lore raw

PATCH 5/5 drm/i2c: adv7511: Create mipi_dsi_device for ADV7533

In reply to Archit Taneja

In order to pass DSI specific parameters to the DSI host, we need the driver to create a mipi_dsi_device that attaches to the host.

Use of_graph helpers to get the DSI host DT node. Create a dummy dsi device using this host. Finally, attach this device to the host.

Populate few other DT parameters (number of data lanes etc) that are required for DSI RX to work correctly. Hardcode few other parameters (rgb, embedded_sync) for now.

---
 drivers/gpu/drm/i2c/adv7511.c | 106 +++++++++++++++++++++++++++++++++++++++---
 1 file changed, 99 insertions(+), 7 deletions(-)
drivers/gpu/drm/i2c/adv7511.c +99 -7
index 10642e1..ccb57a9 100644
@@ -12,6 +12,7 @@
 #include <linux/module.h>
 #include <linux/regmap.h>
 #include <linux/slab.h>
+#include <linux/of_graph.h>
 
 #include <drm/drmP.h>
 #include <drm/drm_crtc_helper.h>
@@ -19,6 +20,7 @@
 #include <drm/drm_encoder_slave.h>
 #include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
+#include <drm/drm_mipi_dsi.h>
 
 #include "adv7511.h"
 
@@ -58,6 +60,11 @@ struct adv7511 {
 
 	struct gpio_desc *gpio_pd;
 
+	/* ADV7533 DSI RX related params */
+	struct device_node *host_node;
+	struct mipi_dsi_device *dsi;
+	u8 num_dsi_lanes;
+
 	enum adv7511_type type;
 };
 
@@ -403,8 +410,10 @@ static void adv7511_dsi_receiver_dpms(struct adv7511 *adv7511)
 		return;
 
 	if (adv7511->powered) {
-		/* set number of dsi lanes (hardcoded to 4 for now) */
-		regmap_write(adv7511->regmap_cec, 0x1c, 0x4 << 4);
+		struct mipi_dsi_device *dsi = adv7511->dsi;
+
+		/* set number of dsi lanes */
+		regmap_write(adv7511->regmap_cec, 0x1c, dsi->lanes << 4);
 		/* disable internal timing generator */
 		regmap_write(adv7511->regmap_cec, 0x27, 0x0b);
 		/* enable hdmi */
@@ -954,6 +963,48 @@ static void adv7533_bridge_mode_set(struct drm_bridge *bridge,
 	adv7511_mode_set(adv, mode, adj_mode);
 }
 
+static int adv7533_attach_dsi(struct adv7511 *adv7511)
+{
+	struct device *dev = &adv7511->i2c_main->dev;
+	struct mipi_dsi_device *dsi;
+	struct mipi_dsi_host *host;
+	int ret;
+
+	host = of_find_mipi_dsi_host_by_node(adv7511->host_node);
+	if (!host) {
+		dev_err(dev, "failed to find dsi host\n");
+		return -EPROBE_DEFER;
+	}
+
+	/* can adv7533 virtual channel be non-zero? */
+	dsi = mipi_dsi_new_dummy(host, 0);
+	if (IS_ERR(dsi)) {
+		dev_err(dev, "failed to create dummy dsi device\n");
+		ret = PTR_ERR(dsi);
+		goto err_dsi_device;
+	}
+
+	adv7511->dsi = dsi;
+
+	dsi->lanes = adv7511->num_dsi_lanes;
+	dsi->format = MIPI_DSI_FMT_RGB888;
+	dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE
+			| MIPI_DSI_MODE_EOT_PACKET | MIPI_DSI_MODE_VIDEO_HSE;
+
+	ret = mipi_dsi_attach(dsi);
+	if (ret < 0) {
+		dev_err(dev, "failed to attach dsi to host\n");
+		goto err_dsi_attach;
+	}
+
+	return 0;
+
+err_dsi_attach:
+	mipi_dsi_unregister_device(dsi);
+err_dsi_device:
+	return ret;
+}
+
 static int adv7533_bridge_attach(struct drm_bridge *bridge)
 {
 	struct adv7511 *adv = bridge_to_adv7511(bridge);
@@ -980,6 +1031,8 @@ static int adv7533_bridge_attach(struct drm_bridge *bridge)
 
 	drm_helper_hpd_irq_event(adv->connector.dev);
 
+	adv7533_attach_dsi(adv);
+
 	return ret;
 }
 
@@ -1079,6 +1132,41 @@ static int adv7511_parse_dt(struct device_node *np,
 	return 0;
 }
 
+static int adv7533_parse_dt(struct device_node *np, struct adv7511 *adv7511)
+{
+	u32 num_lanes;
+	struct device_node *endpoint;
+
+	of_property_read_u32(np, "adi,dsi-lanes", &num_lanes);
+
+	if (num_lanes < 1 || num_lanes > 4)
+		return -EINVAL;
+
+	adv7511->num_dsi_lanes = num_lanes;
+
+	endpoint = of_graph_get_next_endpoint(np, NULL);
+	if (!endpoint) {
+		DRM_ERROR("adv dsi input endpoint not found\n");
+		return -ENODEV;
+	}
+
+	adv7511->host_node = of_graph_get_remote_port_parent(endpoint);
+	if (!adv7511->host_node) {
+		DRM_ERROR("dsi host node not found\n");
+		of_node_put(endpoint);
+		return -ENODEV;
+	}
+
+	of_node_put(endpoint);
+	of_node_put(adv7511->host_node);
+
+	/* TODO: Check if these need to be parsed by DT or not */
+	adv7511->rgb = true;
+	adv7511->embedded_sync = false;
+
+	return 0;
+}
+
 static const int edid_i2c_addr = 0x7e;
 static const int packet_i2c_addr = 0x70;
 static const int cec_i2c_addr = 0x78;
@@ -1121,11 +1209,12 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
 
 	memset(&link_config, 0, sizeof(link_config));
 
-	if (adv7511->type == ADV7511) {
+	if (adv7511->type == ADV7511)
 		ret = adv7511_parse_dt(dev->of_node, &link_config);
-		if (ret)
-			return ret;
-	}
+	else
+		ret = adv7533_parse_dt(dev->of_node, adv7511);
+	if (ret)
+		return ret;
 
 	/*
 	 * The power down GPIO is optional. If present, toggle it from active to
@@ -1247,8 +1336,11 @@ static int adv7511_remove(struct i2c_client *i2c)
 
 	kfree(adv7511->edid);
 
-	if (adv7511->type == ADV7533)
+	if (adv7511->type == ADV7533) {
+		mipi_dsi_detach(adv7511->dsi);
+		mipi_dsi_unregister_device(adv7511->dsi);
 		drm_bridge_remove(&adv7511->bridge);
+	}
 
 	return 0;
 }
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
#28 lore raw

v2 cover drm/i2c: adv7511: ADV7533 support

In reply to Archit Taneja

ADV7533 is a DSI to HDMI encoder chip. It's like ADV7511, but with an additional DSI RX block that takes in DSI video mode output.

This series adds support for ADV7533. Unlike ADV7511 that's modelled as a drm i2c slave encoder, ADV7533 is a drm_bridge object. The bridge ops further create a HDMI type connector device for the chip's output.

Changes in v2:

- The last patch in the series has changed completely. Instead of using the dummy mipi dsi device usage, we now have two separate drivers for i2c and dsi components of the chip. This was discussed in depth (without a final conclusion) here:

https://lkml.org/lkml/2015/6/30/42

With this approach, we wouldn't need to create dummy dsi devices, but we'd have two DT nodes for two different parts of the same chip

- Use of_device_get_match_data() to simplify things.

The older series (using dummy mipi dsi devices) is here:

http://lists.freedesktop.org/archives/dri-devel/2015-July/087088.html

Can we please decide on one of these approaches?

Archit Taneja (4):
drm/i2c: adv7511: Fix mutex deadlock when interrupts are disabled drm/i2c: adv7511: Refactor encoder slave functions drm/i2c: adv7511: Add drm_bridge/connector for ADV7533 drm/i2c: adv7511: Add dsi driver for adv7533

Lars-Peter Clausen (1):
drm/i2c: adv7511: Initial support for adv7533

 drivers/gpu/drm/i2c/adv7511.c | 480 ++++++++++++++++++++++++++++++++++++++----
 1 file changed, 434 insertions(+), 46 deletions(-)
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
#29 lore raw

PATCH v2 1/5 drm/i2c: adv7511: Fix mutex deadlock when interrupts are disabled

When the adv7511 i2c client doesn't have an interrupt line, we observe a deadlock on caused by trying to lock drm device's mode_config.mutex twice in the same context.

Here is the sequence that causes it:

ioctl DRM_IOCTL_MODE_GETCONNECTOR from userspace
drm_mode_getconnector (acquires mode_config mutex)

    connector->fill_modes()
    drm_helper_probe_single_connector_modes
      connector_funcs->get_modes
	adv7511_encoder_get_modes
	  adv7511_get_edid_block
	    adv7511_irq_process
	      drm_helper_hpd_irq_event (acquires mode_config mutex again)

In adv7511_irq_process, don't call drm_helper_hpd_irq_event when not called from interrupt context. It doesn't serve any purpose there anyway.

---
 drivers/gpu/drm/i2c/adv7511.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/gpu/drm/i2c/adv7511.c +4 -4
index 2aaa3c8..cf5bb29 100644
@@ -422,7 +422,7 @@ static bool adv7511_hpd(struct adv7511 *adv7511)
 	return false;
 }
 
-static int adv7511_irq_process(struct adv7511 *adv7511)
+static int adv7511_irq_process(struct adv7511 *adv7511, bool process_hpd)
 {
 	unsigned int irq0, irq1;
 	int ret;
@@ -438,7 +438,7 @@ static int adv7511_irq_process(struct adv7511 *adv7511)
 	regmap_write(adv7511->regmap, ADV7511_REG_INT(0), irq0);
 	regmap_write(adv7511->regmap, ADV7511_REG_INT(1), irq1);
 
-	if (irq0 & ADV7511_INT0_HDP && adv7511->encoder)
+	if (process_hpd && irq0 & ADV7511_INT0_HDP && adv7511->encoder)
 		drm_helper_hpd_irq_event(adv7511->encoder->dev);
 
 	if (irq0 & ADV7511_INT0_EDID_READY || irq1 & ADV7511_INT1_DDC_ERROR) {
@@ -456,7 +456,7 @@ static irqreturn_t adv7511_irq_handler(int irq, void *devid)
 	struct adv7511 *adv7511 = devid;
 	int ret;
 
-	ret = adv7511_irq_process(adv7511);
+	ret = adv7511_irq_process(adv7511, true);
 	return ret < 0 ? IRQ_NONE : IRQ_HANDLED;
 }
 
@@ -473,7 +473,7 @@ static int adv7511_wait_for_edid(struct adv7511 *adv7511, int timeout)
 				adv7511->edid_read, msecs_to_jiffies(timeout));
 	} else {
 		for (; timeout > 0; timeout -= 25) {
-			ret = adv7511_irq_process(adv7511);
+			ret = adv7511_irq_process(adv7511, false);
 			if (ret < 0)
 				break;
 
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
#30 lore raw

PATCH v2 2/5 drm/i2c: adv7511: Initial support for adv7533

In reply to Archit Taneja

From: Lars-Peter Clausen <[email protected]>

ADV7533 is a DSI to HDMI encoder chip. It is a derivative of ADV7511, with additional blocks to translate input DSI data to parallel RGB data. Besides the ADV7511 i2c register map, it has additional registers that require to be configured to activate the DSI blocks.

Use DT compatible strings to populate the adv7533 type enum. Add minimal register configurations belonging to the DSI/CEC register map.

---
 drivers/gpu/drm/i2c/adv7511.c | 141 ++++++++++++++++++++++++++++++++++++------
 1 file changed, 122 insertions(+), 19 deletions(-)
drivers/gpu/drm/i2c/adv7511.c +122 -19
index cf5bb29..cf5961d5 100644
@@ -20,12 +20,18 @@
 
 #include "adv7511.h"
 
+enum adv7511_type {
+	ADV7511,
+	ADV7533,
+};
+
 struct adv7511 {
 	struct i2c_client *i2c_main;
 	struct i2c_client *i2c_edid;
+	struct i2c_client *i2c_cec;
 
 	struct regmap *regmap;
-	struct regmap *packet_memory_regmap;
+	struct regmap *regmap_cec;
 	enum drm_connector_status status;
 	bool powered;
 
@@ -46,6 +52,8 @@ struct adv7511 {
 	struct edid *edid;
 
 	struct gpio_desc *gpio_pd;
+
+	enum adv7511_type type;
 };
 
 static struct adv7511 *encoder_to_adv7511(struct drm_encoder *encoder)
@@ -66,6 +74,23 @@ static const struct reg_default adv7511_fixed_registers[] = {
 	{ 0x55, 0x02 },
 };
 
+/* ADI recommended values for proper operation. */
+static const struct reg_default adv7533_fixed_registers[] = {
+	{ 0x16, 0x20 },
+	{ 0x9a, 0xe0 },
+	{ 0xba, 0x70 },
+	{ 0xde, 0x82 },
+	{ 0xe4, 0x40 },
+	{ 0xe5, 0x80 },
+};
+
+static const struct reg_default adv7533_cec_fixed_registers[] = {
+	{ 0x15, 0xd0 },
+	{ 0x17, 0xd0 },
+	{ 0x24, 0x20 },
+	{ 0x57, 0x11 },
+};
+
 /* -----------------------------------------------------------------------------
  * Register access
  */
@@ -158,6 +183,15 @@ static const struct regmap_config adv7511_regmap_config = {
 	.volatile_reg = adv7511_register_volatile,
 };
 
+static const struct regmap_config adv7533_cec_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.max_register = 0xff,
+	.cache_type = REGCACHE_RBTREE,
+};
+
+
 /* -----------------------------------------------------------------------------
  * Hardware configuration
  */
@@ -358,6 +392,25 @@ static void adv7511_set_link_config(struct adv7511 *adv7511,
 	adv7511->rgb = config->input_colorspace == HDMI_COLORSPACE_RGB;
 }
 
+static void adv7511_dsi_receiver_dpms(struct adv7511 *adv7511)
+{
+	if (adv7511->type != ADV7533)
+		return;
+
+	if (adv7511->powered) {
+		/* set number of dsi lanes (hardcoded to 4 for now) */
+		regmap_write(adv7511->regmap_cec, 0x1c, 0x4 << 4);
+		/* disable internal timing generator */
+		regmap_write(adv7511->regmap_cec, 0x27, 0x0b);
+		/* enable hdmi */
+		regmap_write(adv7511->regmap_cec, 0x03, 0x89);
+		/* disable test mode */
+		regmap_write(adv7511->regmap_cec, 0x55, 0x00);
+	} else {
+		regmap_write(adv7511->regmap_cec, 0x03, 0x0b);
+	}
+}
+
 static void adv7511_power_on(struct adv7511 *adv7511)
 {
 	adv7511->current_edid_segment = -1;
@@ -387,6 +440,8 @@ static void adv7511_power_on(struct adv7511 *adv7511)
 	regcache_sync(adv7511->regmap);
 
 	adv7511->powered = true;
+
+	adv7511_dsi_receiver_dpms(adv7511);
 }
 
 static void adv7511_power_off(struct adv7511 *adv7511)
@@ -398,6 +453,8 @@ static void adv7511_power_off(struct adv7511 *adv7511)
 	regcache_mark_dirty(adv7511->regmap);
 
 	adv7511->powered = false;
+
+	adv7511_dsi_receiver_dpms(adv7511);
 }
 
 /* -----------------------------------------------------------------------------
@@ -567,6 +624,9 @@ static int adv7511_get_modes(struct drm_encoder *encoder,
 
 	/* Reading the EDID only works if the device is powered */
 	if (!adv7511->powered) {
+		regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2,
+				   ADV7511_REG_POWER2_HDP_SRC_MASK,
+				   ADV7511_REG_POWER2_HDP_SRC_NONE);
 		regmap_write(adv7511->regmap, ADV7511_REG_INT(0),
 			     ADV7511_INT0_EDID_READY);
 		regmap_write(adv7511->regmap, ADV7511_REG_INT(1),
@@ -770,8 +830,6 @@ static int adv7511_parse_dt(struct device_node *np,
 	const char *str;
 	int ret;
 
-	memset(config, 0, sizeof(*config));
-
 	of_property_read_u32(np, "adi,input-depth", &config->input_color_depth);
 	if (config->input_color_depth != 8 && config->input_color_depth != 10 &&
 	    config->input_color_depth != 12)
@@ -871,9 +929,18 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
 	adv7511->powered = false;
 	adv7511->status = connector_status_disconnected;
 
-	ret = adv7511_parse_dt(dev->of_node, &link_config);
-	if (ret)
-		return ret;
+	if (dev->of_node)
+		adv7511->type = of_device_get_match_data(dev);
+	else
+		adv7511->type = id->driver_data;
+
+	memset(&link_config, 0, sizeof(link_config));
+
+	if (adv7511->type == ADV7511) {
+		ret = adv7511_parse_dt(dev->of_node, &link_config);
+		if (ret)
+			return ret;
+	}
 
 	/*
 	 * The power down GPIO is optional. If present, toggle it from active to
@@ -897,10 +964,19 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
 		return ret;
 	dev_dbg(dev, "Rev. %d\n", val);
 
-	ret = regmap_register_patch(adv7511->regmap, adv7511_fixed_registers,
-				    ARRAY_SIZE(adv7511_fixed_registers));
-	if (ret)
-		return ret;
+	if (adv7511->type == ADV7511) {
+		ret = regmap_register_patch(adv7511->regmap,
+				adv7511_fixed_registers,
+				ARRAY_SIZE(adv7511_fixed_registers));
+		if (ret)
+			return ret;
+	} else {
+		ret = regmap_register_patch(adv7511->regmap,
+				adv7533_fixed_registers,
+				ARRAY_SIZE(adv7533_fixed_registers));
+		if (ret)
+			return ret;
+	}
 
 	regmap_write(adv7511->regmap, ADV7511_REG_EDID_I2C_ADDR, edid_i2c_addr);
 	regmap_write(adv7511->regmap, ADV7511_REG_PACKET_I2C_ADDR,
@@ -913,6 +989,27 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
 	if (!adv7511->i2c_edid)
 		return -ENOMEM;
 
+	adv7511->i2c_cec = i2c_new_dummy(i2c->adapter, cec_i2c_addr >> 1);
+	if (!adv7511->i2c_cec) {
+		ret = -ENOMEM;
+		goto err_i2c_unregister_edid;
+	}
+
+	adv7511->regmap_cec = devm_regmap_init_i2c(adv7511->i2c_cec,
+					&adv7533_cec_regmap_config);
+	if (IS_ERR(adv7511->regmap_cec)) {
+		ret = PTR_ERR(adv7511->regmap_cec);
+		goto err_i2c_unregister_cec;
+	}
+
+	if (adv7511->type == ADV7533) {
+		ret = regmap_register_patch(adv7511->regmap_cec,
+				adv7533_cec_fixed_registers,
+				ARRAY_SIZE(adv7533_cec_fixed_registers));
+		if (ret)
+			return ret;
+	}
+
 	if (i2c->irq) {
 		init_waitqueue_head(&adv7511->wq);
 
@@ -921,7 +1018,7 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
 						IRQF_ONESHOT, dev_name(dev),
 						adv7511);
 		if (ret)
-			goto err_i2c_unregister_device;
+			goto err_i2c_unregister_cec;
 	}
 
 	/* CEC is unused for now */
@@ -932,11 +1029,14 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
 
 	i2c_set_clientdata(i2c, adv7511);
 
-	adv7511_set_link_config(adv7511, &link_config);
+	if (adv7511->type == ADV7511)
+		adv7511_set_link_config(adv7511, &link_config);
 
 	return 0;
 
-err_i2c_unregister_device:
+err_i2c_unregister_cec:
+	i2c_unregister_device(adv7511->i2c_cec);
+err_i2c_unregister_edid:
 	i2c_unregister_device(adv7511->i2c_edid);
 
 	return ret;
@@ -946,6 +1046,7 @@ static int adv7511_remove(struct i2c_client *i2c)
 {
 	struct adv7511 *adv7511 = i2c_get_clientdata(i2c);
 
+	i2c_unregister_device(adv7511->i2c_cec);
 	i2c_unregister_device(adv7511->i2c_edid);
 
 	kfree(adv7511->edid);
@@ -968,17 +1069,19 @@ static int adv7511_encoder_init(struct i2c_client *i2c, struct drm_device *dev,
 }
 
 static const struct i2c_device_id adv7511_i2c_ids[] = {
-	{ "adv7511", 0 },
-	{ "adv7511w", 0 },
-	{ "adv7513", 0 },
+	{ "adv7511", ADV7511 },
+	{ "adv7511w", ADV7511 },
+	{ "adv7513", ADV7511 },
+	{ "adv7533", ADV7533 },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, adv7511_i2c_ids);
 
 static const struct of_device_id adv7511_of_ids[] = {
-	{ .compatible = "adi,adv7511", },
-	{ .compatible = "adi,adv7511w", },
-	{ .compatible = "adi,adv7513", },
+	{ .compatible = "adi,adv7511", .data = (void *) ADV7511 },
+	{ .compatible = "adi,adv7511w", .data = (void *) ADV7511 },
+	{ .compatible = "adi,adv7513", .data = (void *) ADV7511 },
+	{ .compatible = "adi,adv7533-i2c", .data = (void *) ADV7533 },
 	{ }
 };
 MODULE_DEVICE_TABLE(of, adv7511_of_ids);
Signature · 7 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

_______________________________________________
dri-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/dri-devel
#31 lore raw

PATCH v2 3/5 drm/i2c: adv7511: Refactor encoder slave functions

In reply to Archit Taneja

ADV7511 is represented as an i2c drm slave encoder device. ADV7533, on the other hand, is going be a normal i2c client device creating bridge and connector entities.

Move the code in encoder slave functions to generate helpers that are agnostic to the drm object type. These helpers will later also be used by bridge and connecter helper functions.

---
 drivers/gpu/drm/i2c/adv7511.c | 80 ++++++++++++++++++++++++++++++-------------
 1 file changed, 57 insertions(+), 23 deletions(-)
drivers/gpu/drm/i2c/adv7511.c +57 -23
index cf5961d5..e35ad37 100644
@@ -612,13 +612,11 @@ static int adv7511_get_edid_block(void *data, u8 *buf, unsigned int block,
 }
 
 /* -----------------------------------------------------------------------------
- * Encoder operations
+ * ADV75xx helpers
  */
-
-static int adv7511_get_modes(struct drm_encoder *encoder,
-			     struct drm_connector *connector)
+static int adv7511_get_modes(struct adv7511 *adv7511,
+		struct drm_connector *connector)
 {
-	struct adv7511 *adv7511 = encoder_to_adv7511(encoder);
 	struct edid *edid;
 	unsigned int count;
 
@@ -656,21 +654,10 @@ static int adv7511_get_modes(struct drm_encoder *encoder,
 	return count;
 }
 
-static void adv7511_encoder_dpms(struct drm_encoder *encoder, int mode)
-{
-	struct adv7511 *adv7511 = encoder_to_adv7511(encoder);
-
-	if (mode == DRM_MODE_DPMS_ON)
-		adv7511_power_on(adv7511);
-	else
-		adv7511_power_off(adv7511);
-}
-
 static enum drm_connector_status
-adv7511_encoder_detect(struct drm_encoder *encoder,
+adv7511_detect(struct adv7511 *adv7511,
 		       struct drm_connector *connector)
 {
-	struct adv7511 *adv7511 = encoder_to_adv7511(encoder);
 	enum drm_connector_status status;
 	unsigned int val;
 	bool hpd;
@@ -694,7 +681,7 @@ adv7511_encoder_detect(struct drm_encoder *encoder,
 	if (status == connector_status_connected && hpd && adv7511->powered) {
 		regcache_mark_dirty(adv7511->regmap);
 		adv7511_power_on(adv7511);
-		adv7511_get_modes(encoder, connector);
+		adv7511_get_modes(adv7511, connector);
 		if (adv7511->status == connector_status_connected)
 			status = connector_status_disconnected;
 	} else {
@@ -708,8 +695,8 @@ adv7511_encoder_detect(struct drm_encoder *encoder,
 	return status;
 }
 
-static int adv7511_encoder_mode_valid(struct drm_encoder *encoder,
-				      struct drm_display_mode *mode)
+static int adv7511_mode_valid(struct adv7511 *adv7511,
+				     const struct drm_display_mode *mode)
 {
 	if (mode->clock > 165000)
 		return MODE_CLOCK_HIGH;
@@ -717,11 +704,10 @@ static int adv7511_encoder_mode_valid(struct drm_encoder *encoder,
 	return MODE_OK;
 }
 
-static void adv7511_encoder_mode_set(struct drm_encoder *encoder,
+static void adv7511_mode_set(struct adv7511 *adv7511,
 				     struct drm_display_mode *mode,
 				     struct drm_display_mode *adj_mode)
 {
-	struct adv7511 *adv7511 = encoder_to_adv7511(encoder);
 	unsigned int low_refresh_rate;
 	unsigned int hsync_polarity = 0;
 	unsigned int vsync_polarity = 0;
@@ -812,12 +798,60 @@ static void adv7511_encoder_mode_set(struct drm_encoder *encoder,
 	adv7511->f_tmds = mode->clock;
 }
 
+/* -----------------------------------------------------------------------------
+ * Encoder operations
+ */
+
+static int adv7511_encoder_get_modes(struct drm_encoder *encoder,
+			     struct drm_connector *connector)
+{
+	struct adv7511 *adv7511 = encoder_to_adv7511(encoder);
+
+	return adv7511_get_modes(adv7511, connector);
+}
+
+static void adv7511_encoder_dpms(struct drm_encoder *encoder, int mode)
+{
+	struct adv7511 *adv7511 = encoder_to_adv7511(encoder);
+
+	if (mode == DRM_MODE_DPMS_ON)
+		adv7511_power_on(adv7511);
+	else
+		adv7511_power_off(adv7511);
+}
+
+static enum drm_connector_status
+adv7511_encoder_detect(struct drm_encoder *encoder,
+		       struct drm_connector *connector)
+{
+	struct adv7511 *adv7511 = encoder_to_adv7511(encoder);
+
+	return adv7511_detect(adv7511, connector);
+}
+
+static int adv7511_encoder_mode_valid(struct drm_encoder *encoder,
+				      struct drm_display_mode *mode)
+{
+	struct adv7511 *adv7511 = encoder_to_adv7511(encoder);
+
+	return adv7511_mode_valid(adv7511, mode);
+}
+
+static void adv7511_encoder_mode_set(struct drm_encoder *encoder,
+				     struct drm_display_mode *mode,
+				     struct drm_display_mode *adj_mode)
+{
+	struct adv7511 *adv7511 = encoder_to_adv7511(encoder);
+
+	adv7511_mode_set(adv7511, mode, adj_mode);
+}
+
 static struct drm_encoder_slave_funcs adv7511_encoder_funcs = {
 	.dpms = adv7511_encoder_dpms,
 	.mode_valid = adv7511_encoder_mode_valid,
 	.mode_set = adv7511_encoder_mode_set,
 	.detect = adv7511_encoder_detect,
-	.get_modes = adv7511_get_modes,
+	.get_modes = adv7511_encoder_get_modes,
 };
 
 /* -----------------------------------------------------------------------------
Signature · 7 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

_______________________________________________
dri-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/dri-devel
#32 lore raw

PATCH v2 4/5 drm/i2c: adv7511: Add drm_bridge/connector for ADV7533

In reply to Archit Taneja

Create bridge and connector helper functions. These internally refer to the ADV75xx helper functions.

The driver registers a drm_bridge object during probe. The bridge, in turn registers a HDMI connector when a user attaches the bridge.

Therefore, when the device type is ADV7533, we create bridge and connector entities, and when it's ADV7511, we create a slave encoder as before.

Since the i2c driver is still wrapped around by the drm_i2c_slave_encoder struct. We make sure the encoder_init op returns an error when the device type is ADV7533.

---
 drivers/gpu/drm/i2c/adv7511.c | 155 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 155 insertions(+)
drivers/gpu/drm/i2c/adv7511.c +155 -0
index e35ad37..b6c80e3 100644
@@ -17,6 +17,8 @@
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_edid.h>
 #include <drm/drm_encoder_slave.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
 
 #include "adv7511.h"
 
@@ -44,6 +46,9 @@ struct adv7511 {
 	wait_queue_head_t wq;
 	struct drm_encoder *encoder;
 
+	struct drm_connector connector;
+	struct drm_bridge bridge;
+
 	bool embedded_sync;
 	enum adv7511_sync_polarity vsync_polarity;
 	enum adv7511_sync_polarity hsync_polarity;
@@ -855,6 +860,139 @@ static struct drm_encoder_slave_funcs adv7511_encoder_funcs = {
 };
 
 /* -----------------------------------------------------------------------------
+ * Bridge and connector functions
+ */
+
+static struct adv7511 *connector_to_adv7511(struct drm_connector *connector)
+{
+	return container_of(connector, struct adv7511, connector);
+}
+
+/* Connector helper functions */
+static int adv7533_connector_get_modes(struct drm_connector *connector)
+{
+	struct adv7511 *adv = connector_to_adv7511(connector);
+
+	return adv7511_get_modes(adv, connector);
+}
+
+static struct drm_encoder *
+adv7533_connector_best_encoder(struct drm_connector *connector)
+{
+	struct adv7511 *adv = connector_to_adv7511(connector);
+
+	return adv->bridge.encoder;
+}
+
+static enum drm_mode_status
+adv7533_connector_mode_valid(struct drm_connector *connector,
+				struct drm_display_mode *mode)
+{
+	struct adv7511 *adv = connector_to_adv7511(connector);
+
+	return adv7511_mode_valid(adv, mode);
+}
+
+static struct drm_connector_helper_funcs adv7533_connector_helper_funcs = {
+	.get_modes = adv7533_connector_get_modes,
+	.best_encoder = adv7533_connector_best_encoder,
+	.mode_valid = adv7533_connector_mode_valid,
+};
+
+static enum drm_connector_status
+adv7533_connector_detect(struct drm_connector *connector, bool force)
+{
+	struct adv7511 *adv = connector_to_adv7511(connector);
+
+	return adv7511_detect(adv, connector);
+}
+
+static struct drm_connector_funcs adv7533_connector_funcs = {
+	.dpms = drm_helper_connector_dpms,
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.detect = adv7533_connector_detect,
+	.destroy = drm_connector_cleanup,
+	.reset = drm_atomic_helper_connector_reset,
+	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+/* Bridge funcs */
+static struct adv7511 *bridge_to_adv7511(struct drm_bridge *bridge)
+{
+	return container_of(bridge, struct adv7511, bridge);
+}
+
+static void adv7533_bridge_pre_enable(struct drm_bridge *bridge)
+{
+	struct adv7511 *adv = bridge_to_adv7511(bridge);
+
+	adv7511_power_on(adv);
+}
+
+static void adv7533_bridge_post_disable(struct drm_bridge *bridge)
+{
+	struct adv7511 *adv = bridge_to_adv7511(bridge);
+
+	adv7511_power_off(adv);
+}
+
+static void adv7533_bridge_enable(struct drm_bridge *bridge)
+{
+}
+
+static void adv7533_bridge_disable(struct drm_bridge *bridge)
+{
+}
+
+static void adv7533_bridge_mode_set(struct drm_bridge *bridge,
+				     struct drm_display_mode *mode,
+				     struct drm_display_mode *adj_mode)
+{
+	struct adv7511 *adv = bridge_to_adv7511(bridge);
+
+	adv7511_mode_set(adv, mode, adj_mode);
+}
+
+static int adv7533_bridge_attach(struct drm_bridge *bridge)
+{
+	struct adv7511 *adv = bridge_to_adv7511(bridge);
+	int ret;
+
+	adv->encoder = bridge->encoder;
+
+	if (!bridge->encoder) {
+		DRM_ERROR("Parent encoder object not found");
+		return -ENODEV;
+	}
+
+	adv->connector.polled = DRM_CONNECTOR_POLL_HPD;
+	ret = drm_connector_init(bridge->dev, &adv->connector,
+			&adv7533_connector_funcs, DRM_MODE_CONNECTOR_HDMIA);
+	if (ret) {
+		DRM_ERROR("Failed to initialize connector with drm\n");
+		return ret;
+	}
+	drm_connector_helper_add(&adv->connector,
+					&adv7533_connector_helper_funcs);
+	drm_connector_register(&adv->connector);
+	drm_mode_connector_attach_encoder(&adv->connector, adv->encoder);
+
+	drm_helper_hpd_irq_event(adv->connector.dev);
+
+	return ret;
+}
+
+static struct drm_bridge_funcs adv7533_bridge_funcs = {
+	.pre_enable = adv7533_bridge_pre_enable,
+	.enable = adv7533_bridge_enable,
+	.disable = adv7533_bridge_disable,
+	.post_disable = adv7533_bridge_post_disable,
+	.mode_set = adv7533_bridge_mode_set,
+	.attach = adv7533_bridge_attach,
+};
+
+/* -----------------------------------------------------------------------------
  * Probe & remove
  */
 
@@ -1066,6 +1204,17 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
 	if (adv7511->type == ADV7511)
 		adv7511_set_link_config(adv7511, &link_config);
 
+	if (adv7511->type == ADV7533) {
+		adv7511->bridge.funcs = &adv7533_bridge_funcs;
+		adv7511->bridge.of_node = dev->of_node;
+
+		ret = drm_bridge_add(&adv7511->bridge);
+		if (ret) {
+			dev_err(dev, "failed to add adv7533 bridge\n");
+			goto err_i2c_unregister_cec;
+		}
+	}
+
 	return 0;
 
 err_i2c_unregister_cec:
@@ -1085,6 +1234,9 @@ static int adv7511_remove(struct i2c_client *i2c)
 
 	kfree(adv7511->edid);
 
+	if (adv7511->type == ADV7533)
+		drm_bridge_remove(&adv7511->bridge);
+
 	return 0;
 }
 
@@ -1094,6 +1246,9 @@ static int adv7511_encoder_init(struct i2c_client *i2c, struct drm_device *dev,
 
 	struct adv7511 *adv7511 = i2c_get_clientdata(i2c);
 
+	if (adv7511->type == ADV7533)
+		return -ENODEV;
+
 	encoder->slave_priv = adv7511;
 	encoder->slave_funcs = &adv7511_encoder_funcs;
 
Signature · 7 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

_______________________________________________
dri-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/dri-devel
#33 lore raw

PATCH v2 5/5 drm/i2c: adv7511: Add dsi driver for adv7533

In reply to Archit Taneja

Add a separate mipi_dsi_driver for adv7533. In the case of this chip, both the i2c and dsi drivers will operate together.

Both the drivers are expected to use the same per-device driver data struct. The i2c driver takes the responsibility of allocating the struct, and the dsi device gets a pointer to it by getting the corresponding i2c client device's data.

---
 drivers/gpu/drm/i2c/adv7511.c | 98 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 97 insertions(+), 1 deletion(-)
drivers/gpu/drm/i2c/adv7511.c +97 -1
index b6c80e3..8325913 100644
@@ -19,6 +19,7 @@
 #include <drm/drm_encoder_slave.h>
 #include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
+#include <drm/drm_mipi_dsi.h>
 
 #include "adv7511.h"
 
@@ -58,6 +59,9 @@ struct adv7511 {
 
 	struct gpio_desc *gpio_pd;
 
+	struct mipi_dsi_device *dsi;
+	int num_dsi_lanes;
+
 	enum adv7511_type type;
 };
 
@@ -403,8 +407,10 @@ static void adv7511_dsi_receiver_dpms(struct adv7511 *adv7511)
 		return;
 
 	if (adv7511->powered) {
+		struct mipi_dsi_device *dsi = adv7511->dsi;
+
 		/* set number of dsi lanes (hardcoded to 4 for now) */
-		regmap_write(adv7511->regmap_cec, 0x1c, 0x4 << 4);
+		regmap_write(adv7511->regmap_cec, 0x1c, dsi->lanes << 4);
 		/* disable internal timing generator */
 		regmap_write(adv7511->regmap_cec, 0x27, 0x0b);
 		/* enable hdmi */
@@ -1289,8 +1295,97 @@ static struct drm_i2c_encoder_driver adv7511_driver = {
 	.encoder_init = adv7511_encoder_init,
 };
 
+/* Driver for the DSI component within the chip */
+static int adv7533_parse_dt(struct device_node *np, struct adv7511 *adv7511)
+{
+	u32 num_lanes;
+
+	of_property_read_u32(np, "adi,dsi-lanes", &num_lanes);
+
+	if (num_lanes < 1 || num_lanes > 4)
+		return -EINVAL;
+
+	adv7511->num_dsi_lanes = num_lanes;
+
+	/* TODO: Check if these need to be parsed by DT or not */
+	adv7511->rgb = true;
+	adv7511->embedded_sync = false;
+
+	return 0;
+}
+
+static int adv7533_probe(struct mipi_dsi_device *dsi)
+{
+	struct device *dev = &dsi->dev;
+	struct adv7511 *adv7511;
+	struct device_node *np = dsi->dev.of_node;
+	struct device_node *i2c_node;
+	struct i2c_client *i2c;
+	int ret;
+
+	i2c_node = of_parse_phandle(np, "i2c-control", 0);
+	if (!i2c_node)
+		return -ENODEV;
+
+	i2c = of_find_i2c_device_by_node(i2c_node);
+	if (!i2c)
+		return -EPROBE_DEFER;
+
+	adv7511 = i2c_get_clientdata(i2c);
+	if (!adv7511)
+		return -ENODEV;
+
+	/* this sets up link with the i2c driver */
+	adv7511->dsi = dsi;
+
+	mipi_dsi_set_drvdata(dsi, adv7511);
+
+	ret = adv7533_parse_dt(np, adv7511);
+	if (ret)
+		return ret;
+
+	dsi->lanes = adv7511->num_dsi_lanes;
+	dsi->format = MIPI_DSI_FMT_RGB888;
+	dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE
+			| MIPI_DSI_MODE_EOT_PACKET | MIPI_DSI_MODE_VIDEO_HSE;
+
+	return mipi_dsi_attach(dsi);
+}
+
+static int adv7533_remove(struct mipi_dsi_device *dsi)
+{
+	mipi_dsi_detach(dsi);
+
+	return 0;
+}
+
+static const struct of_device_id adv7533_of_match[] = {
+	{ .compatible = "adi,adv7533-dsi" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, adv7533_of_match);
+
+static struct mipi_dsi_driver adv7533_driver = {
+	.probe = adv7533_probe,
+	.remove = adv7533_remove,
+	.driver = {
+		.name = "adv7533",
+		.of_match_table = adv7533_of_match,
+	},
+};
+
 static int __init adv7511_init(void)
 {
+	int ret;
+
+	/*
+	 * not bailing out here because adv7511 variant won't
+	 * need a DSI driver
+	 */
+	ret = mipi_dsi_driver_register(&adv7533_driver);
+	if (ret)
+		DRM_DEBUG("mipi driver register failed %d\n", ret);
+
 	return drm_i2c_encoder_register(THIS_MODULE, &adv7511_driver);
 }
 module_init(adv7511_init);
@@ -1298,6 +1393,7 @@ module_init(adv7511_init);
 static void __exit adv7511_exit(void)
 {
 	drm_i2c_encoder_unregister(&adv7511_driver);
+	mipi_dsi_driver_unregister(&adv7533_driver);
 }
 module_exit(adv7511_exit);
 
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
#34 lore raw

v3 cover drm/i2c: adv7511: ADV7533 support

In reply to Archit Taneja

ADV7533 is a DSI to HDMI encoder chip. It's like ADV7511, but with an additional DSI RX block that takes in DSI video mode output.

Trying to get this driver merged has had some challenges:

- ADV7533 has an I2C control bus, but acts as a DSI peripheral too. After discussions, it was concluded that we'd want to provide an API to create MIPI DSI devices, rather than expose two different interfaces on DT. The first version [1] tried the former approach the second version [2] showed how the driver would look like if exposed 2 DT nodes. This lateset patchset relies on the MIPI DSI device creation API provided by [3], this has been accepted and should be merged for 4.6.

- The driver was designed as an I2C slave encoder. When ADV7533 patches were posted [1], it was modelled as a bridge, but ADV7511 and others were still left as I2C slave encoders. This wasn't accepted. After discussions, it was decided that ADV7511 too would be converted into a bridge driver, and all the users of ADV7511 should assume it is a bridge. This bridge conversion was done in [4]. There is still some debate over whether the bridge driver be involved in the connector creation, or the KMS driver that has the whole view of the display pipeline. This discussion shouldn't affect this patch set, though.

This patch set enables ADV7533 support with the above two issues now resolved. It also incorporates ADV7533 specific features and fixes that we've discovered since the first version of this patch was posted.

Tested on ADV7533 chips on DB410c. It should work on the Hikey board too. I'd appreaciate if someone could test it on a ADV7511 platform since I don't have one.

[4]
https://lists.freedesktop.org/archives/dri-devel/2016-January/098287.html

[3]
https://lkml.org/lkml/2016/2/12/67

[2]
https://lists.freedesktop.org/archives/dri-devel/2015-September/089884.html

[1]:
https://lists.freedesktop.org/archives/dri-devel/2015-July/087088.html

Archit Taneja (7):
drm/i2c: adv7511: Convert to drm_bridge
drm/i2c: adv7511: Fix mutex deadlock when interrupts are disabled drm/i2c: adv7511: Initial support for ADV7533
drm/i2c: adv7511: Create a MIPI DSI device
drm/i2c: adv7511: Use internal timing generator drm/i2c: adv7511: Change number of DSI lanes dynamically
dt-bindings: drm/bridge: Update bindings for ADV7533

 .../bindings/display/bridge/adi,adv7511.txt        |  25 +-
 drivers/gpu/drm/i2c/adv7511.c                      | 539 +++++++++++++++++----
 2 files changed, 476 insertions(+), 88 deletions(-)
Signature · 7 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
#35 lore raw

PATCH v3 1/7 drm/i2c: adv7511: Convert to drm_bridge

We don't want to use the old i2c slave encoder interface anymore.

Remove that and make the i2c driver create a drm_bridge entity instead. Converting to bridges helps because the kms drivers don't need to exract encoder slave ops from this driver and use it within their own encoder/connector ops.

The driver now creates its own connector when a kms driver attaches itself to the bridge. Therefore, kms drivers don't need to create their own connectors anymore.

The old encoder slave ops are now used by the new bridge and connector entities.

---
v3:
- Remove calls to connector_register and hpd helper in bridge_attach
- Remove noop bridge ops

 drivers/gpu/drm/i2c/adv7511.c | 222 ++++++++++++++++++++++++++++--------------
 1 file changed, 148 insertions(+), 74 deletions(-)
drivers/gpu/drm/i2c/adv7511.c +148 -74
index a02112b..fec5627 100644
@@ -14,9 +14,10 @@
 #include <linux/slab.h>
 
 #include <drm/drmP.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_edid.h>
-#include <drm/drm_encoder_slave.h>
 
 #include "adv7511.h"
 
@@ -36,7 +37,8 @@ struct adv7511 {
 	bool edid_read;
 
 	wait_queue_head_t wq;
-	struct drm_encoder *encoder;
+	struct drm_bridge bridge;
+	struct drm_connector connector;
 
 	bool embedded_sync;
 	enum adv7511_sync_polarity vsync_polarity;
@@ -48,11 +50,6 @@ struct adv7511 {
 	struct gpio_desc *gpio_pd;
 };
 
-static struct adv7511 *encoder_to_adv7511(struct drm_encoder *encoder)
-{
-	return to_encoder_slave(encoder)->slave_priv;
-}
-
 /* ADI recommended values for proper operation. */
 static const struct reg_sequence adv7511_fixed_registers[] = {
 	{ 0x98, 0x03 },
@@ -446,8 +443,8 @@ static int adv7511_irq_process(struct adv7511 *adv7511)
 	regmap_write(adv7511->regmap, ADV7511_REG_INT(0), irq0);
 	regmap_write(adv7511->regmap, ADV7511_REG_INT(1), irq1);
 
-	if (irq0 & ADV7511_INT0_HPD && adv7511->encoder)
-		drm_helper_hpd_irq_event(adv7511->encoder->dev);
+	if (irq0 & ADV7511_INT0_HPD && adv7511->bridge.encoder)
+		drm_helper_hpd_irq_event(adv7511->connector.dev);
 
 	if (irq0 & ADV7511_INT0_EDID_READY || irq1 & ADV7511_INT1_DDC_ERROR) {
 		adv7511->edid_read = true;
@@ -563,13 +560,12 @@ static int adv7511_get_edid_block(void *data, u8 *buf, unsigned int block,
 }
 
 /* -----------------------------------------------------------------------------
- * Encoder operations
+ * ADV75xx helpers
  */
 
-static int adv7511_get_modes(struct drm_encoder *encoder,
+static int adv7511_get_modes(struct adv7511 *adv7511,
 			     struct drm_connector *connector)
 {
-	struct adv7511 *adv7511 = encoder_to_adv7511(encoder);
 	struct edid *edid;
 	unsigned int count;
 
@@ -606,21 +602,9 @@ static int adv7511_get_modes(struct drm_encoder *encoder,
 	return count;
 }
 
-static void adv7511_encoder_dpms(struct drm_encoder *encoder, int mode)
-{
-	struct adv7511 *adv7511 = encoder_to_adv7511(encoder);
-
-	if (mode == DRM_MODE_DPMS_ON)
-		adv7511_power_on(adv7511);
-	else
-		adv7511_power_off(adv7511);
-}
-
 static enum drm_connector_status
-adv7511_encoder_detect(struct drm_encoder *encoder,
-		       struct drm_connector *connector)
+adv7511_detect(struct adv7511 *adv7511, struct drm_connector *connector)
 {
-	struct adv7511 *adv7511 = encoder_to_adv7511(encoder);
 	enum drm_connector_status status;
 	unsigned int val;
 	bool hpd;
@@ -644,7 +628,7 @@ adv7511_encoder_detect(struct drm_encoder *encoder,
 	if (status == connector_status_connected && hpd && adv7511->powered) {
 		regcache_mark_dirty(adv7511->regmap);
 		adv7511_power_on(adv7511);
-		adv7511_get_modes(encoder, connector);
+		adv7511_get_modes(adv7511, connector);
 		if (adv7511->status == connector_status_connected)
 			status = connector_status_disconnected;
 	} else {
@@ -658,8 +642,8 @@ adv7511_encoder_detect(struct drm_encoder *encoder,
 	return status;
 }
 
-static int adv7511_encoder_mode_valid(struct drm_encoder *encoder,
-				      struct drm_display_mode *mode)
+static int adv7511_mode_valid(struct adv7511 *adv7511,
+			      struct drm_display_mode *mode)
 {
 	if (mode->clock > 165000)
 		return MODE_CLOCK_HIGH;
@@ -667,11 +651,10 @@ static int adv7511_encoder_mode_valid(struct drm_encoder *encoder,
 	return MODE_OK;
 }
 
-static void adv7511_encoder_mode_set(struct drm_encoder *encoder,
-				     struct drm_display_mode *mode,
-				     struct drm_display_mode *adj_mode)
+static void adv7511_mode_set(struct adv7511 *adv7511,
+			     struct drm_display_mode *mode,
+			     struct drm_display_mode *adj_mode)
 {
-	struct adv7511 *adv7511 = encoder_to_adv7511(encoder);
 	unsigned int low_refresh_rate;
 	unsigned int hsync_polarity = 0;
 	unsigned int vsync_polarity = 0;
@@ -762,12 +745,120 @@ static void adv7511_encoder_mode_set(struct drm_encoder *encoder,
 	adv7511->f_tmds = mode->clock;
 }
 
-static const struct drm_encoder_slave_funcs adv7511_encoder_funcs = {
-	.dpms = adv7511_encoder_dpms,
-	.mode_valid = adv7511_encoder_mode_valid,
-	.mode_set = adv7511_encoder_mode_set,
-	.detect = adv7511_encoder_detect,
-	.get_modes = adv7511_get_modes,
+/* Connector funcs */
+static struct adv7511 *connector_to_adv7511(struct drm_connector *connector)
+{
+	return container_of(connector, struct adv7511, connector);
+}
+
+static int adv7511_connector_get_modes(struct drm_connector *connector)
+{
+	struct adv7511 *adv = connector_to_adv7511(connector);
+
+	return adv7511_get_modes(adv, connector);
+}
+
+static struct drm_encoder *
+adv7511_connector_best_encoder(struct drm_connector *connector)
+{
+	struct adv7511 *adv = connector_to_adv7511(connector);
+
+	return adv->bridge.encoder;
+}
+
+static enum drm_mode_status
+adv7511_connector_mode_valid(struct drm_connector *connector,
+			     struct drm_display_mode *mode)
+{
+	struct adv7511 *adv = connector_to_adv7511(connector);
+
+	return adv7511_mode_valid(adv, mode);
+}
+
+static struct drm_connector_helper_funcs adv7511_connector_helper_funcs = {
+	.get_modes = adv7511_connector_get_modes,
+	.best_encoder = adv7511_connector_best_encoder,
+	.mode_valid = adv7511_connector_mode_valid,
+};
+
+static enum drm_connector_status
+adv7511_connector_detect(struct drm_connector *connector, bool force)
+{
+	struct adv7511 *adv = connector_to_adv7511(connector);
+
+	return adv7511_detect(adv, connector);
+}
+
+static struct drm_connector_funcs adv7511_connector_funcs = {
+	.dpms = drm_atomic_helper_connector_dpms,
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.detect = adv7511_connector_detect,
+	.destroy = drm_connector_cleanup,
+	.reset = drm_atomic_helper_connector_reset,
+	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+/* Bridge funcs */
+static struct adv7511 *bridge_to_adv7511(struct drm_bridge *bridge)
+{
+	return container_of(bridge, struct adv7511, bridge);
+}
+
+static void adv7511_bridge_enable(struct drm_bridge *bridge)
+{
+	struct adv7511 *adv = bridge_to_adv7511(bridge);
+
+	adv7511_power_on(adv);
+}
+
+static void adv7511_bridge_disable(struct drm_bridge *bridge)
+{
+	struct adv7511 *adv = bridge_to_adv7511(bridge);
+
+	adv7511_power_off(adv);
+}
+
+static void adv7511_bridge_mode_set(struct drm_bridge *bridge,
+				    struct drm_display_mode *mode,
+				    struct drm_display_mode *adj_mode)
+{
+	struct adv7511 *adv = bridge_to_adv7511(bridge);
+
+	adv7511_mode_set(adv, mode, adj_mode);
+}
+
+static int adv7511_bridge_attach(struct drm_bridge *bridge)
+{
+	struct adv7511 *adv = bridge_to_adv7511(bridge);
+	int ret;
+
+	if (!bridge->encoder) {
+		DRM_ERROR("Parent encoder object not found");
+		return -ENODEV;
+	}
+
+	adv->connector.polled = DRM_CONNECTOR_POLL_HPD;
+
+	ret = drm_connector_init(bridge->dev, &adv->connector,
+				 &adv7511_connector_funcs,
+				 DRM_MODE_CONNECTOR_HDMIA);
+	if (ret) {
+		DRM_ERROR("Failed to initialize connector with drm\n");
+		return ret;
+	}
+	drm_connector_helper_add(&adv->connector,
+				 &adv7511_connector_helper_funcs);
+	drm_mode_connector_attach_encoder(&adv->connector, bridge->encoder);
+
+	return ret;
+}
+
+static struct drm_bridge_funcs adv7511_bridge_funcs = {
+	.enable = adv7511_bridge_enable,
+	.disable = adv7511_bridge_disable,
+	.mode_set = adv7511_bridge_mode_set,
+	.attach = adv7511_bridge_attach,
 };
 
 /* -----------------------------------------------------------------------------
@@ -944,6 +1035,15 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
 
 	adv7511_set_link_config(adv7511, &link_config);
 
+	adv7511->bridge.funcs = &adv7511_bridge_funcs;
+	adv7511->bridge.of_node = dev->of_node;
+
+	ret = drm_bridge_add(&adv7511->bridge);
+	if (ret) {
+		dev_err(dev, "failed to add adv7511 bridge\n");
+		goto err_i2c_unregister_device;
+	}
+
 	return 0;
 
 err_i2c_unregister_device:
@@ -956,6 +1056,8 @@ static int adv7511_remove(struct i2c_client *i2c)
 {
 	struct adv7511 *adv7511 = i2c_get_clientdata(i2c);
 
+	drm_bridge_remove(&adv7511->bridge);
+
 	i2c_unregister_device(adv7511->i2c_edid);
 
 	kfree(adv7511->edid);
@@ -963,20 +1065,6 @@ static int adv7511_remove(struct i2c_client *i2c)
 	return 0;
 }
 
-static int adv7511_encoder_init(struct i2c_client *i2c, struct drm_device *dev,
-				struct drm_encoder_slave *encoder)
-{
-
-	struct adv7511 *adv7511 = i2c_get_clientdata(i2c);
-
-	encoder->slave_priv = adv7511;
-	encoder->slave_funcs = &adv7511_encoder_funcs;
-
-	adv7511->encoder = &encoder->base;
-
-	return 0;
-}
-
 static const struct i2c_device_id adv7511_i2c_ids[] = {
 	{ "adv7511", 0 },
 	{ "adv7511w", 0 },
@@ -993,31 +1081,17 @@ static const struct of_device_id adv7511_of_ids[] = {
 };
 MODULE_DEVICE_TABLE(of, adv7511_of_ids);
 
-static struct drm_i2c_encoder_driver adv7511_driver = {
-	.i2c_driver = {
-		.driver = {
-			.name = "adv7511",
-			.of_match_table = adv7511_of_ids,
-		},
-		.id_table = adv7511_i2c_ids,
-		.probe = adv7511_probe,
-		.remove = adv7511_remove,
+static struct i2c_driver adv7511_driver = {
+	.driver = {
+		.name = "adv7511",
+		.of_match_table = adv7511_of_ids,
 	},
-
-	.encoder_init = adv7511_encoder_init,
+	.id_table = adv7511_i2c_ids,
+	.probe = adv7511_probe,
+	.remove = adv7511_remove,
 };
 
-static int __init adv7511_init(void)
-{
-	return drm_i2c_encoder_register(THIS_MODULE, &adv7511_driver);
-}
-module_init(adv7511_init);
-
-static void __exit adv7511_exit(void)
-{
-	drm_i2c_encoder_unregister(&adv7511_driver);
-}
-module_exit(adv7511_exit);
+module_i2c_driver(adv7511_driver);
 
 MODULE_AUTHOR("Lars-Peter Clausen <[email protected]>");
 MODULE_DESCRIPTION("ADV7511 HDMI transmitter driver");
Signature · 7 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
#36 lore raw

PATCH v3 2/7 drm/i2c: adv7511: Fix mutex deadlock when interrupts are disabled

In reply to Archit Taneja

When the adv7511 i2c client doesn't have an interrupt line, we observe a deadlock on caused by trying to lock drm device's mode_config.mutex twice in the same context.

Here is the sequence that causes it:

ioctl DRM_IOCTL_MODE_GETCONNECTOR from userspace
drm_mode_getconnector (acquires mode_config mutex)

    connector->fill_modes()
    drm_helper_probe_single_connector_modes
      connector_funcs->get_modes
	adv7511_encoder_get_modes
	  adv7511_get_edid_block
	    adv7511_irq_process
	      drm_helper_hpd_irq_event (acquires mode_config mutex again)

In adv7511_irq_process, don't call drm_helper_hpd_irq_event when not called from the interrupt handler. It doesn't serve any purpose there anyway.

---
 drivers/gpu/drm/i2c/adv7511.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/gpu/drm/i2c/adv7511.c +4 -4
index fec5627..c00d11d 100644
@@ -427,7 +427,7 @@ static bool adv7511_hpd(struct adv7511 *adv7511)
 	return false;
 }
 
-static int adv7511_irq_process(struct adv7511 *adv7511)
+static int adv7511_irq_process(struct adv7511 *adv7511, bool process_hpd)
 {
 	unsigned int irq0, irq1;
 	int ret;
@@ -443,7 +443,7 @@ static int adv7511_irq_process(struct adv7511 *adv7511)
 	regmap_write(adv7511->regmap, ADV7511_REG_INT(0), irq0);
 	regmap_write(adv7511->regmap, ADV7511_REG_INT(1), irq1);
 
-	if (irq0 & ADV7511_INT0_HPD && adv7511->bridge.encoder)
+	if (process_hpd && irq0 & ADV7511_INT0_HPD && adv7511->bridge.encoder)
 		drm_helper_hpd_irq_event(adv7511->connector.dev);
 
 	if (irq0 & ADV7511_INT0_EDID_READY || irq1 & ADV7511_INT1_DDC_ERROR) {
@@ -461,7 +461,7 @@ static irqreturn_t adv7511_irq_handler(int irq, void *devid)
 	struct adv7511 *adv7511 = devid;
 	int ret;
 
-	ret = adv7511_irq_process(adv7511);
+	ret = adv7511_irq_process(adv7511, true);
 	return ret < 0 ? IRQ_NONE : IRQ_HANDLED;
 }
 
@@ -478,7 +478,7 @@ static int adv7511_wait_for_edid(struct adv7511 *adv7511, int timeout)
 				adv7511->edid_read, msecs_to_jiffies(timeout));
 	} else {
 		for (; timeout > 0; timeout -= 25) {
-			ret = adv7511_irq_process(adv7511);
+			ret = adv7511_irq_process(adv7511, false);
 			if (ret < 0)
 				break;
 
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
#37 lore raw

PATCH v3 3/7 drm/i2c: adv7511: Initial support for ADV7533

In reply to Archit Taneja

ADV7533 is a DSI to HDMI encoder chip. It is a derivative of ADV7511, with additional blocks to translate input DSI data to parallel RGB data. Besides the ADV7511 I2C register map, it has additional registers that require to be configured to activate the DSI Rx block.

Use DT compatible strings to populate the ADV7533 type enum. Add minimal register configurations belonging to the DSI/CEC register map.

Originally worked on by Lars-Peter Clausen <[email protected]>

---
 drivers/gpu/drm/i2c/adv7511.c | 138 ++++++++++++++++++++++++++++++++++++------
 1 file changed, 120 insertions(+), 18 deletions(-)
drivers/gpu/drm/i2c/adv7511.c +120 -18
index c00d11d..75be17c 100644
@@ -10,6 +10,7 @@
 #include <linux/gpio/consumer.h>
 #include <linux/i2c.h>
 #include <linux/module.h>
+#include <linux/of_device.h>
 #include <linux/regmap.h>
 #include <linux/slab.h>
 
@@ -21,12 +22,18 @@
 
 #include "adv7511.h"
 
+enum adv7511_type {
+	ADV7511,
+	ADV7533,
+};
+
 struct adv7511 {
 	struct i2c_client *i2c_main;
 	struct i2c_client *i2c_edid;
+	struct i2c_client *i2c_cec;
 
 	struct regmap *regmap;
-	struct regmap *packet_memory_regmap;
+	struct regmap *regmap_cec;
 	enum drm_connector_status status;
 	bool powered;
 
@@ -48,6 +55,8 @@ struct adv7511 {
 	struct edid *edid;
 
 	struct gpio_desc *gpio_pd;
+
+	enum adv7511_type type;
 };
 
 /* ADI recommended values for proper operation. */
@@ -63,6 +72,22 @@ static const struct reg_sequence adv7511_fixed_registers[] = {
 	{ 0x55, 0x02 },
 };
 
+static const struct reg_sequence adv7533_fixed_registers[] = {
+	{ 0x16, 0x20 },
+	{ 0x9a, 0xe0 },
+	{ 0xba, 0x70 },
+	{ 0xde, 0x82 },
+	{ 0xe4, 0x40 },
+	{ 0xe5, 0x80 },
+};
+
+static const struct reg_sequence adv7533_cec_fixed_registers[] = {
+	{ 0x15, 0xd0 },
+	{ 0x17, 0xd0 },
+	{ 0x24, 0x20 },
+	{ 0x57, 0x11 },
+};
+
 /* -----------------------------------------------------------------------------
  * Register access
  */
@@ -156,6 +181,15 @@ static const struct regmap_config adv7511_regmap_config = {
 	.volatile_reg = adv7511_register_volatile,
 };
 
+static const struct regmap_config adv7533_cec_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.max_register = 0xff,
+	.cache_type = REGCACHE_RBTREE,
+};
+
+
 /* -----------------------------------------------------------------------------
  * Hardware configuration
  */
@@ -356,6 +390,21 @@ static void adv7511_set_link_config(struct adv7511 *adv7511,
 	adv7511->rgb = config->input_colorspace == HDMI_COLORSPACE_RGB;
 }
 
+static void adv7533_dsi_power_on(struct adv7511 *adv)
+{
+	/* set number of dsi lanes (hardcoded to 4 for now) */
+	regmap_write(adv->regmap_cec, 0x1c, 0x4 << 4);
+	/* disable internal timing generator */
+	regmap_write(adv->regmap_cec, 0x27, 0x0b);
+	/* enable hdmi */
+	regmap_write(adv->regmap_cec, 0x03, 0x89);
+	/* disable test mode */
+	regmap_write(adv->regmap_cec, 0x55, 0x00);
+
+	regmap_register_patch(adv->regmap_cec, adv7533_cec_fixed_registers,
+			      ARRAY_SIZE(adv7533_cec_fixed_registers));
+}
+
 static void adv7511_power_on(struct adv7511 *adv7511)
 {
 	adv7511->current_edid_segment = -1;
@@ -391,9 +440,18 @@ static void adv7511_power_on(struct adv7511 *adv7511)
 	 */
 	regcache_sync(adv7511->regmap);
 
+	if (adv7511->type == ADV7533)
+		adv7533_dsi_power_on(adv7511);
+
 	adv7511->powered = true;
 }
 
+static void adv7533_dsi_power_off(struct adv7511 *adv)
+{
+	/* disable hdmi */
+	regmap_write(adv->regmap_cec, 0x03, 0x0b);
+}
+
 static void adv7511_power_off(struct adv7511 *adv7511)
 {
 	/* TODO: setup additional power down modes */
@@ -402,6 +460,9 @@ static void adv7511_power_off(struct adv7511 *adv7511)
 			   ADV7511_POWER_POWER_DOWN);
 	regcache_mark_dirty(adv7511->regmap);
 
+	if (adv7511->type == ADV7533)
+		adv7533_dsi_power_off(adv7511);
+
 	adv7511->powered = false;
 }
 
@@ -871,8 +932,6 @@ static int adv7511_parse_dt(struct device_node *np,
 	const char *str;
 	int ret;
 
-	memset(config, 0, sizeof(*config));
-
 	of_property_read_u32(np, "adi,input-depth", &config->input_color_depth);
 	if (config->input_color_depth != 8 && config->input_color_depth != 10 &&
 	    config->input_color_depth != 12)
@@ -972,9 +1031,18 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
 	adv7511->powered = false;
 	adv7511->status = connector_status_disconnected;
 
-	ret = adv7511_parse_dt(dev->of_node, &link_config);
-	if (ret)
-		return ret;
+	if (dev->of_node)
+		adv7511->type = (enum adv7511_type) of_device_get_match_data(dev);
+	else
+		adv7511->type = id->driver_data;
+
+	memset(&link_config, 0, sizeof(link_config));
+
+	if (adv7511->type == ADV7511) {
+		ret = adv7511_parse_dt(dev->of_node, &link_config);
+		if (ret)
+			return ret;
+	}
 
 	/*
 	 * The power down GPIO is optional. If present, toggle it from active to
@@ -998,8 +1066,15 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
 		return ret;
 	dev_dbg(dev, "Rev. %d\n", val);
 
-	ret = regmap_register_patch(adv7511->regmap, adv7511_fixed_registers,
-				    ARRAY_SIZE(adv7511_fixed_registers));
+	if (adv7511->type == ADV7511) {
+		ret = regmap_register_patch(adv7511->regmap,
+					adv7511_fixed_registers,
+					ARRAY_SIZE(adv7511_fixed_registers));
+	} else {
+		ret = regmap_register_patch(adv7511->regmap,
+					adv7533_fixed_registers,
+					ARRAY_SIZE(adv7533_fixed_registers));
+	}
 	if (ret)
 		return ret;
 
@@ -1014,6 +1089,27 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
 	if (!adv7511->i2c_edid)
 		return -ENOMEM;
 
+	adv7511->i2c_cec = i2c_new_dummy(i2c->adapter, cec_i2c_addr >> 1);
+	if (!adv7511->i2c_cec) {
+		ret = -ENOMEM;
+		goto err_i2c_unregister_edid;
+	}
+
+	adv7511->regmap_cec = devm_regmap_init_i2c(adv7511->i2c_cec,
+					&adv7533_cec_regmap_config);
+	if (IS_ERR(adv7511->regmap_cec)) {
+		ret = PTR_ERR(adv7511->regmap_cec);
+		goto err_i2c_unregister_cec;
+	}
+
+	if (adv7511->type == ADV7533) {
+		ret = regmap_register_patch(adv7511->regmap_cec,
+				adv7533_cec_fixed_registers,
+				ARRAY_SIZE(adv7533_cec_fixed_registers));
+		if (ret)
+			goto err_i2c_unregister_cec;
+	}
+
 	if (i2c->irq) {
 		init_waitqueue_head(&adv7511->wq);
 
@@ -1022,7 +1118,7 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
 						IRQF_ONESHOT, dev_name(dev),
 						adv7511);
 		if (ret)
-			goto err_i2c_unregister_device;
+			goto err_i2c_unregister_cec;
 	}
 
 	/* CEC is unused for now */
@@ -1033,7 +1129,8 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
 
 	i2c_set_clientdata(i2c, adv7511);
 
-	adv7511_set_link_config(adv7511, &link_config);
+	if (adv7511->type == ADV7511)
+		adv7511_set_link_config(adv7511, &link_config);
 
 	adv7511->bridge.funcs = &adv7511_bridge_funcs;
 	adv7511->bridge.of_node = dev->of_node;
@@ -1041,12 +1138,14 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
 	ret = drm_bridge_add(&adv7511->bridge);
 	if (ret) {
 		dev_err(dev, "failed to add adv7511 bridge\n");
-		goto err_i2c_unregister_device;
+		goto err_i2c_unregister_cec;
 	}
 
 	return 0;
 
-err_i2c_unregister_device:
+err_i2c_unregister_cec:
+	i2c_unregister_device(adv7511->i2c_cec);
+err_i2c_unregister_edid:
 	i2c_unregister_device(adv7511->i2c_edid);
 
 	return ret;
@@ -1058,6 +1157,7 @@ static int adv7511_remove(struct i2c_client *i2c)
 
 	drm_bridge_remove(&adv7511->bridge);
 
+	i2c_unregister_device(adv7511->i2c_cec);
 	i2c_unregister_device(adv7511->i2c_edid);
 
 	kfree(adv7511->edid);
@@ -1066,17 +1166,19 @@ static int adv7511_remove(struct i2c_client *i2c)
 }
 
 static const struct i2c_device_id adv7511_i2c_ids[] = {
-	{ "adv7511", 0 },
-	{ "adv7511w", 0 },
-	{ "adv7513", 0 },
+	{ "adv7511", ADV7511 },
+	{ "adv7511w", ADV7511 },
+	{ "adv7513", ADV7511 },
+	{ "adv7533", ADV7533 },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, adv7511_i2c_ids);
 
 static const struct of_device_id adv7511_of_ids[] = {
-	{ .compatible = "adi,adv7511", },
-	{ .compatible = "adi,adv7511w", },
-	{ .compatible = "adi,adv7513", },
+	{ .compatible = "adi,adv7511", .data = (void *)ADV7511 },
+	{ .compatible = "adi,adv7511w", .data = (void *)ADV7511 },
+	{ .compatible = "adi,adv7513", .data = (void *)ADV7511 },
+	{ .compatible = "adi,adv7533", .data = (void *)ADV7533 },
 	{ }
 };
 MODULE_DEVICE_TABLE(of, adv7511_of_ids);
Signature · 7 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
#38 lore raw

PATCH v3 4/7 drm/i2c: adv7511: Create a MIPI DSI device

In reply to Archit Taneja

In order to pass DSI specific parameters to the DSI host, we need the driver to create a mipi_dsi_device DSI device that attaches to the host.

Use of_graph helpers to get the DSI host DT node. Create a MIPI DSI device using this host. Finally, attach this device to the DSI host.

Populate DT parameters (number of data lanes for now) that are required for DSI RX to work correctly. Hardcode few other parameters (rgb, embedded_sync) for now.

---
 drivers/gpu/drm/i2c/adv7511.c | 130 +++++++++++++++++++++++++++++++++++++++---
 1 file changed, 123 insertions(+), 7 deletions(-)
drivers/gpu/drm/i2c/adv7511.c +123 -7
index 75be17c..6c2a89a 100644
@@ -11,6 +11,7 @@
 #include <linux/i2c.h>
 #include <linux/module.h>
 #include <linux/of_device.h>
+#include <linux/of_graph.h>
 #include <linux/regmap.h>
 #include <linux/slab.h>
 
@@ -19,6 +20,7 @@
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_edid.h>
+#include <drm/drm_mipi_dsi.h>
 
 #include "adv7511.h"
 
@@ -56,6 +58,11 @@ struct adv7511 {
 
 	struct gpio_desc *gpio_pd;
 
+	/* ADV7533 DSI RX related params */
+	struct device_node *host_node;
+	struct mipi_dsi_device *dsi;
+	u8 num_dsi_lanes;
+
 	enum adv7511_type type;
 };
 
@@ -392,8 +399,10 @@ static void adv7511_set_link_config(struct adv7511 *adv7511,
 
 static void adv7533_dsi_power_on(struct adv7511 *adv)
 {
-	/* set number of dsi lanes (hardcoded to 4 for now) */
-	regmap_write(adv->regmap_cec, 0x1c, 0x4 << 4);
+	struct mipi_dsi_device *dsi = adv->dsi;
+
+	/* set number of dsi lanes */
+	regmap_write(adv->regmap_cec, 0x1c, dsi->lanes << 4);
 	/* disable internal timing generator */
 	regmap_write(adv->regmap_cec, 0x27, 0x0b);
 	/* enable hdmi */
@@ -889,6 +898,51 @@ static void adv7511_bridge_mode_set(struct drm_bridge *bridge,
 	adv7511_mode_set(adv, mode, adj_mode);
 }
 
+static int adv7533_attach_dsi(struct adv7511 *adv)
+{
+	struct device *dev = &adv->i2c_main->dev;
+	struct mipi_dsi_host *host;
+	struct mipi_dsi_device *dsi;
+	int ret = 0;
+	const struct mipi_dsi_device_info info = { .type = "adv7533",
+						   .channel = 0,
+						   .node = NULL,
+						 };
+
+	host = of_find_mipi_dsi_host_by_node(adv->host_node);
+	if (!host) {
+		dev_err(dev, "failed to find dsi host\n");
+		return -EPROBE_DEFER;
+	}
+
+	dsi = mipi_dsi_device_register_full(host, &info);
+	if (IS_ERR(dsi)) {
+		dev_err(dev, "failed to create dsi device\n");
+		ret = PTR_ERR(dsi);
+		goto err_dsi_device;
+	}
+
+	adv->dsi = dsi;
+
+	dsi->lanes = adv->num_dsi_lanes;
+	dsi->format = MIPI_DSI_FMT_RGB888;
+	dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
+			  MIPI_DSI_MODE_EOT_PACKET | MIPI_DSI_MODE_VIDEO_HSE;
+
+	ret = mipi_dsi_attach(dsi);
+	if (ret < 0) {
+		dev_err(dev, "failed to attach dsi to host\n");
+		goto err_dsi_attach;
+	}
+
+	return 0;
+
+err_dsi_attach:
+	mipi_dsi_device_unregister(dsi);
+err_dsi_device:
+	return ret;
+}
+
 static int adv7511_bridge_attach(struct drm_bridge *bridge)
 {
 	struct adv7511 *adv = bridge_to_adv7511(bridge);
@@ -912,6 +966,9 @@ static int adv7511_bridge_attach(struct drm_bridge *bridge)
 				 &adv7511_connector_helper_funcs);
 	drm_mode_connector_attach_encoder(&adv->connector, bridge->encoder);
 
+	if (adv->type == ADV7533)
+		ret = adv7533_attach_dsi(adv);
+
 	return ret;
 }
 
@@ -1009,6 +1066,41 @@ static int adv7511_parse_dt(struct device_node *np,
 	return 0;
 }
 
+static int adv7533_parse_dt(struct device_node *np, struct adv7511 *adv)
+{
+	u32 num_lanes;
+	struct device_node *endpoint;
+
+	of_property_read_u32(np, "adi,dsi-lanes", &num_lanes);
+
+	if (num_lanes < 1 || num_lanes > 4)
+		return -EINVAL;
+
+	adv->num_dsi_lanes = num_lanes;
+
+	endpoint = of_graph_get_next_endpoint(np, NULL);
+	if (!endpoint) {
+		DRM_ERROR("ADV7533 DSI input endpoint not found\n");
+		return -ENODEV;
+	}
+
+	adv->host_node = of_graph_get_remote_port_parent(endpoint);
+	if (!adv->host_node) {
+		DRM_ERROR("DSI host node not found\n");
+		of_node_put(endpoint);
+		return -ENODEV;
+	}
+
+	of_node_put(endpoint);
+	of_node_put(adv->host_node);
+
+	/* TODO: Check if these need to be parsed by DT or not */
+	adv->rgb = true;
+	adv->embedded_sync = false;
+
+	return 0;
+}
+
 static const int edid_i2c_addr = 0x7e;
 static const int packet_i2c_addr = 0x70;
 static const int cec_i2c_addr = 0x78;
@@ -1038,11 +1130,12 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
 
 	memset(&link_config, 0, sizeof(link_config));
 
-	if (adv7511->type == ADV7511) {
+	if (adv7511->type == ADV7511)
 		ret = adv7511_parse_dt(dev->of_node, &link_config);
-		if (ret)
-			return ret;
-	}
+	else
+		ret = adv7533_parse_dt(dev->of_node, adv7511);
+	if (ret)
+		return ret;
 
 	/*
 	 * The power down GPIO is optional. If present, toggle it from active to
@@ -1155,6 +1248,11 @@ static int adv7511_remove(struct i2c_client *i2c)
 {
 	struct adv7511 *adv7511 = i2c_get_clientdata(i2c);
 
+	if (adv7511->type == ADV7533) {
+		mipi_dsi_detach(adv7511->dsi);
+		mipi_dsi_device_unregister(adv7511->dsi);
+	}
+
 	drm_bridge_remove(&adv7511->bridge);
 
 	i2c_unregister_device(adv7511->i2c_cec);
@@ -1183,6 +1281,10 @@ static const struct of_device_id adv7511_of_ids[] = {
 };
 MODULE_DEVICE_TABLE(of, adv7511_of_ids);
 
+static struct mipi_dsi_driver adv7533_dsi_driver = {
+	.driver.name = "adv7533",
+};
+
 static struct i2c_driver adv7511_driver = {
 	.driver = {
 		.name = "adv7511",
@@ -1193,7 +1295,21 @@ static struct i2c_driver adv7511_driver = {
 	.remove = adv7511_remove,
 };
 
-module_i2c_driver(adv7511_driver);
+static int __init adv7511_init(void)
+{
+	mipi_dsi_driver_register(&adv7533_dsi_driver);
+
+	return i2c_add_driver(&adv7511_driver);
+}
+module_init(adv7511_init);
+
+static void __exit adv7511_exit(void)
+{
+	i2c_del_driver(&adv7511_driver);
+
+	mipi_dsi_driver_unregister(&adv7533_dsi_driver);
+}
+module_exit(adv7511_exit);
 
 MODULE_AUTHOR("Lars-Peter Clausen <[email protected]>");
 MODULE_DESCRIPTION("ADV7511 HDMI transmitter driver");
Signature · 7 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
#39 lore raw

Re: [PATCH v3 4/7] drm/i2c: adv7511: Create a MIPI DSI device

Hi Archit,

Thank you for the patch.

Quoted 4 lines · On Wednesday 09 Mar 2016 16:27:15 Archit Taneja wrote:

In order to pass DSI specific parameters to the DSI host, we need the driver to create a mipi_dsi_device DSI device that attaches to the host.

Quoted 8 lines

Use of_graph helpers to get the DSI host DT node. Create a MIPI DSI device using this host. Finally, attach this device to the DSI host.

Populate DT parameters (number of data lanes for now) that are required for DSI RX to work correctly. Hardcode few other parameters (rgb, embedded_sync) for now.

This adds a hard dependency on CONFIG_DRM_MIPI_DSI, otherwise the kernel won't link. As the ADV7511 doesn't require DSI, could you make it optional with conditional compilation to avoid pulling in dead code ?

Quoted 218 lines
---
 drivers/gpu/drm/i2c/adv7511.c | 130 ++++++++++++++++++++++++++++++++++++---
 1 file changed, 123 insertions(+), 7 deletions(-)
drivers/gpu/drm/i2c/adv7511.c +11 -2
index 75be17c..6c2a89a 100644
@@ -11,6 +11,7 @@
 #include <linux/i2c.h>
 #include <linux/module.h>
 #include <linux/of_device.h>
+#include <linux/of_graph.h>
 #include <linux/regmap.h>
 #include <linux/slab.h>
 
@@ -19,6 +20,7 @@
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_edid.h>
+#include <drm/drm_mipi_dsi.h>
 
 #include "adv7511.h"
 
@@ -56,6 +58,11 @@ struct adv7511 {
 
 	struct gpio_desc *gpio_pd;
 
+	/* ADV7533 DSI RX related params */
+	struct device_node *host_node;
+	struct mipi_dsi_device *dsi;
+	u8 num_dsi_lanes;
+
 	enum adv7511_type type;
 };
 
@@ -392,8 +399,10 @@ static void adv7511_set_link_config(struct adv7511
 *adv7511,
 
 static void adv7533_dsi_power_on(struct adv7511 *adv)
 {
-	/* set number of dsi lanes (hardcoded to 4 for now) */
-	regmap_write(adv->regmap_cec, 0x1c, 0x4 << 4);
+	struct mipi_dsi_device *dsi = adv->dsi;
+
+	/* set number of dsi lanes */
+	regmap_write(adv->regmap_cec, 0x1c, dsi->lanes << 4);
 	/* disable internal timing generator */
 	regmap_write(adv->regmap_cec, 0x27, 0x0b);
drivers/gpu/drm/i2c/adv7511.c +88 -4
 	/* enable hdmi */
@@ -889,6 +898,51 @@ static void adv7511_bridge_mode_set(struct drm_bridge
 *bridge, adv7511_mode_set(adv, mode, adj_mode);
 }
 
+static int adv7533_attach_dsi(struct adv7511 *adv)
+{
+	struct device *dev = &adv->i2c_main->dev;
+	struct mipi_dsi_host *host;
+	struct mipi_dsi_device *dsi;
+	int ret = 0;
+	const struct mipi_dsi_device_info info = { .type = "adv7533",
+						   .channel = 0,
+						   .node = NULL,
+						 };
+
+	host = of_find_mipi_dsi_host_by_node(adv->host_node);
+	if (!host) {
+		dev_err(dev, "failed to find dsi host\n");
+		return -EPROBE_DEFER;
+	}
+
+	dsi = mipi_dsi_device_register_full(host, &info);
+	if (IS_ERR(dsi)) {
+		dev_err(dev, "failed to create dsi device\n");
+		ret = PTR_ERR(dsi);
+		goto err_dsi_device;
+	}
+
+	adv->dsi = dsi;
+
+	dsi->lanes = adv->num_dsi_lanes;
+	dsi->format = MIPI_DSI_FMT_RGB888;
+	dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
+			  MIPI_DSI_MODE_EOT_PACKET | MIPI_DSI_MODE_VIDEO_HSE;
+
+	ret = mipi_dsi_attach(dsi);
+	if (ret < 0) {
+		dev_err(dev, "failed to attach dsi to host\n");
+		goto err_dsi_attach;
+	}
+
+	return 0;
+
+err_dsi_attach:
+	mipi_dsi_device_unregister(dsi);
+err_dsi_device:
+	return ret;
+}
+
 static int adv7511_bridge_attach(struct drm_bridge *bridge)
 {
 	struct adv7511 *adv = bridge_to_adv7511(bridge);
@@ -912,6 +966,9 @@ static int adv7511_bridge_attach(struct drm_bridge
 *bridge) &adv7511_connector_helper_funcs);
 	drm_mode_connector_attach_encoder(&adv->connector, bridge->encoder);
 
+	if (adv->type == ADV7533)
+		ret = adv7533_attach_dsi(adv);
+
 	return ret;
 }
 
@@ -1009,6 +1066,41 @@ static int adv7511_parse_dt(struct device_node *np,
 	return 0;
 }
 
+static int adv7533_parse_dt(struct device_node *np, struct adv7511 *adv)
+{
+	u32 num_lanes;
+	struct device_node *endpoint;
+
+	of_property_read_u32(np, "adi,dsi-lanes", &num_lanes);
+
+	if (num_lanes < 1 || num_lanes > 4)
+		return -EINVAL;
+
+	adv->num_dsi_lanes = num_lanes;
+
+	endpoint = of_graph_get_next_endpoint(np, NULL);
+	if (!endpoint) {
+		DRM_ERROR("ADV7533 DSI input endpoint not found\n");
+		return -ENODEV;
+	}
+
+	adv->host_node = of_graph_get_remote_port_parent(endpoint);
+	if (!adv->host_node) {
+		DRM_ERROR("DSI host node not found\n");
+		of_node_put(endpoint);
+		return -ENODEV;
+	}
+
+	of_node_put(endpoint);
+	of_node_put(adv->host_node);
+
+	/* TODO: Check if these need to be parsed by DT or not */
+	adv->rgb = true;
+	adv->embedded_sync = false;
+
+	return 0;
+}
+
 static const int edid_i2c_addr = 0x7e;
 static const int packet_i2c_addr = 0x70;
 static const int cec_i2c_addr = 0x78;
@@ -1038,11 +1130,12 @@ static int adv7511_probe(struct i2c_client *i2c,
 const struct i2c_device_id *id)
 
 	memset(&link_config, 0, sizeof(link_config));
 
-	if (adv7511->type == ADV7511) {
+	if (adv7511->type == ADV7511)
 		ret = adv7511_parse_dt(dev->of_node, &link_config);
-		if (ret)
-			return ret;
-	}
+	else
+		ret = adv7533_parse_dt(dev->of_node, adv7511);
+	if (ret)
+		return ret;
 
 	/*
drivers/gpu/drm/i2c/adv7511.c +24 -1
 	 * The power down GPIO is optional. If present, toggle it from active to
@@ -1155,6 +1248,11 @@ static int adv7511_remove(struct i2c_client *i2c)
 {
 	struct adv7511 *adv7511 = i2c_get_clientdata(i2c);
 
+	if (adv7511->type == ADV7533) {
+		mipi_dsi_detach(adv7511->dsi);
+		mipi_dsi_device_unregister(adv7511->dsi);
+	}
+
 	drm_bridge_remove(&adv7511->bridge);
 
 	i2c_unregister_device(adv7511->i2c_cec);
@@ -1183,6 +1281,10 @@ static const struct of_device_id adv7511_of_ids[] = {
 };
 MODULE_DEVICE_TABLE(of, adv7511_of_ids);
 
+static struct mipi_dsi_driver adv7533_dsi_driver = {
+	.driver.name = "adv7533",
+};
+
 static struct i2c_driver adv7511_driver = {
 	.driver = {
 		.name = "adv7511",
@@ -1193,7 +1295,21 @@ static struct i2c_driver adv7511_driver = {
 	.remove = adv7511_remove,
 };
 
-module_i2c_driver(adv7511_driver);
+static int __init adv7511_init(void)
+{
+	mipi_dsi_driver_register(&adv7533_dsi_driver);
+
+	return i2c_add_driver(&adv7511_driver);
+}
+module_init(adv7511_init);
+
+static void __exit adv7511_exit(void)
+{
+	i2c_del_driver(&adv7511_driver);
+
+	mipi_dsi_driver_unregister(&adv7533_dsi_driver);
+}
+module_exit(adv7511_exit);
 
 MODULE_AUTHOR("Lars-Peter Clausen <[email protected]>");
 MODULE_DESCRIPTION("ADV7511 HDMI transmitter driver");
Signature · 8 lines
Regards,

Laurent Pinchart

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
#40 lore raw

Re: [PATCH v3 4/7] drm/i2c: adv7511: Create a MIPI DSI device

Hi Laurent,

Quoted 16 lines · Laurent Pinchart

Hi Archit,

Thank you for the patch.

Quoted 11 lines · On Wednesday 09 Mar 2016 16:27:15 Archit Taneja wrote:

In order to pass DSI specific parameters to the DSI host, we need the driver to create a mipi_dsi_device DSI device that attaches to the host.

Use of_graph helpers to get the DSI host DT node. Create a MIPI DSI device using this host. Finally, attach this device to the DSI host.

Populate DT parameters (number of data lanes for now) that are required for DSI RX to work correctly. Hardcode few other parameters (rgb, embedded_sync) for now.

Quoted 5 lines
Quoted 1 line

This adds a hard dependency on CONFIG_DRM_MIPI_DSI, otherwise the kernel won't link. As the ADV7511 doesn't require DSI, could you make it optional with conditional compilation to avoid pulling in dead code ?

You're right. The driver's Kconfig should at least select DRM_MIPI_DSI in the current state to make sure we don't break build.

Do you suggest we create another config option for ADV7533, which selects DRM_MIPI_DSI and builds the ADV7533 parts? Or did you mean something else?

Thanks for the review.

Archit

Quoted 220 lines
Quoted 219 lines
---
  drivers/gpu/drm/i2c/adv7511.c | 130 ++++++++++++++++++++++++++++++++++++---
  1 file changed, 123 insertions(+), 7 deletions(-)
drivers/gpu/drm/i2c/adv7511.c +11 -2
index 75be17c..6c2a89a 100644
@@ -11,6 +11,7 @@
  #include <linux/i2c.h>
  #include <linux/module.h>
  #include <linux/of_device.h>
+#include <linux/of_graph.h>
  #include <linux/regmap.h>
  #include <linux/slab.h>
 
@@ -19,6 +20,7 @@
  #include <drm/drm_atomic_helper.h>
  #include <drm/drm_crtc_helper.h>
  #include <drm/drm_edid.h>
+#include <drm/drm_mipi_dsi.h>
 
  #include "adv7511.h"
 
@@ -56,6 +58,11 @@ struct adv7511 {
 
  	struct gpio_desc *gpio_pd;
 
+	/* ADV7533 DSI RX related params */
+	struct device_node *host_node;
+	struct mipi_dsi_device *dsi;
+	u8 num_dsi_lanes;
+
  	enum adv7511_type type;
  };
 
@@ -392,8 +399,10 @@ static void adv7511_set_link_config(struct adv7511
 *adv7511,
 
  static void adv7533_dsi_power_on(struct adv7511 *adv)
  {
-	/* set number of dsi lanes (hardcoded to 4 for now) */
-	regmap_write(adv->regmap_cec, 0x1c, 0x4 << 4);
+	struct mipi_dsi_device *dsi = adv->dsi;
+
+	/* set number of dsi lanes */
+	regmap_write(adv->regmap_cec, 0x1c, dsi->lanes << 4);
  	/* disable internal timing generator */
  	regmap_write(adv->regmap_cec, 0x27, 0x0b);

/* enable hdmi */

drivers/gpu/drm/i2c/adv7511.c +88 -4
@@ -889,6 +898,51 @@ static void adv7511_bridge_mode_set(struct drm_bridge
 *bridge, adv7511_mode_set(adv, mode, adj_mode);
  }
 
+static int adv7533_attach_dsi(struct adv7511 *adv)
+{
+	struct device *dev = &adv->i2c_main->dev;
+	struct mipi_dsi_host *host;
+	struct mipi_dsi_device *dsi;
+	int ret = 0;
+	const struct mipi_dsi_device_info info = { .type = "adv7533",
+						   .channel = 0,
+						   .node = NULL,
+						 };
+
+	host = of_find_mipi_dsi_host_by_node(adv->host_node);
+	if (!host) {
+		dev_err(dev, "failed to find dsi host\n");
+		return -EPROBE_DEFER;
+	}
+
+	dsi = mipi_dsi_device_register_full(host, &info);
+	if (IS_ERR(dsi)) {
+		dev_err(dev, "failed to create dsi device\n");
+		ret = PTR_ERR(dsi);
+		goto err_dsi_device;
+	}
+
+	adv->dsi = dsi;
+
+	dsi->lanes = adv->num_dsi_lanes;
+	dsi->format = MIPI_DSI_FMT_RGB888;
+	dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
+			  MIPI_DSI_MODE_EOT_PACKET | MIPI_DSI_MODE_VIDEO_HSE;
+
+	ret = mipi_dsi_attach(dsi);
+	if (ret < 0) {
+		dev_err(dev, "failed to attach dsi to host\n");
+		goto err_dsi_attach;
+	}
+
+	return 0;
+
+err_dsi_attach:
+	mipi_dsi_device_unregister(dsi);
+err_dsi_device:
+	return ret;
+}
+
  static int adv7511_bridge_attach(struct drm_bridge *bridge)
  {
  	struct adv7511 *adv = bridge_to_adv7511(bridge);
@@ -912,6 +966,9 @@ static int adv7511_bridge_attach(struct drm_bridge
 *bridge) &adv7511_connector_helper_funcs);
  	drm_mode_connector_attach_encoder(&adv->connector, bridge->encoder);
 
+	if (adv->type == ADV7533)
+		ret = adv7533_attach_dsi(adv);
+
  	return ret;
  }
 
@@ -1009,6 +1066,41 @@ static int adv7511_parse_dt(struct device_node *np,
  	return 0;
  }
 
+static int adv7533_parse_dt(struct device_node *np, struct adv7511 *adv)
+{
+	u32 num_lanes;
+	struct device_node *endpoint;
+
+	of_property_read_u32(np, "adi,dsi-lanes", &num_lanes);
+
+	if (num_lanes < 1 || num_lanes > 4)
+		return -EINVAL;
+
+	adv->num_dsi_lanes = num_lanes;
+
+	endpoint = of_graph_get_next_endpoint(np, NULL);
+	if (!endpoint) {
+		DRM_ERROR("ADV7533 DSI input endpoint not found\n");
+		return -ENODEV;
+	}
+
+	adv->host_node = of_graph_get_remote_port_parent(endpoint);
+	if (!adv->host_node) {
+		DRM_ERROR("DSI host node not found\n");
+		of_node_put(endpoint);
+		return -ENODEV;
+	}
+
+	of_node_put(endpoint);
+	of_node_put(adv->host_node);
+
+	/* TODO: Check if these need to be parsed by DT or not */
+	adv->rgb = true;
+	adv->embedded_sync = false;
+
+	return 0;
+}
+
  static const int edid_i2c_addr = 0x7e;
  static const int packet_i2c_addr = 0x70;
  static const int cec_i2c_addr = 0x78;
@@ -1038,11 +1130,12 @@ static int adv7511_probe(struct i2c_client *i2c,
 const struct i2c_device_id *id)
 
  	memset(&link_config, 0, sizeof(link_config));
 
-	if (adv7511->type == ADV7511) {
+	if (adv7511->type == ADV7511)
  		ret = adv7511_parse_dt(dev->of_node, &link_config);
-		if (ret)
-			return ret;
-	}
+	else
+		ret = adv7533_parse_dt(dev->of_node, adv7511);
+	if (ret)
+		return ret;
 
  	/*

* The power down GPIO is optional. If present, toggle it from active to

drivers/gpu/drm/i2c/adv7511.c +24 -1
@@ -1155,6 +1248,11 @@ static int adv7511_remove(struct i2c_client *i2c)
  {
  	struct adv7511 *adv7511 = i2c_get_clientdata(i2c);
 
+	if (adv7511->type == ADV7533) {
+		mipi_dsi_detach(adv7511->dsi);
+		mipi_dsi_device_unregister(adv7511->dsi);
+	}
+
  	drm_bridge_remove(&adv7511->bridge);
 
  	i2c_unregister_device(adv7511->i2c_cec);
@@ -1183,6 +1281,10 @@ static const struct of_device_id adv7511_of_ids[] = {
 };
  MODULE_DEVICE_TABLE(of, adv7511_of_ids);
 
+static struct mipi_dsi_driver adv7533_dsi_driver = {
+	.driver.name = "adv7533",
+};
+
  static struct i2c_driver adv7511_driver = {
  	.driver = {
  		.name = "adv7511",
@@ -1193,7 +1295,21 @@ static struct i2c_driver adv7511_driver = {
  	.remove = adv7511_remove,
  };
 
-module_i2c_driver(adv7511_driver);
+static int __init adv7511_init(void)
+{
+	mipi_dsi_driver_register(&adv7533_dsi_driver);
+
+	return i2c_add_driver(&adv7511_driver);
+}
+module_init(adv7511_init);
+
+static void __exit adv7511_exit(void)
+{
+	i2c_del_driver(&adv7511_driver);
+
+	mipi_dsi_driver_unregister(&adv7533_dsi_driver);
+}
+module_exit(adv7511_exit);
 
  MODULE_AUTHOR("Lars-Peter Clausen <[email protected]>");
  MODULE_DESCRIPTION("ADV7511 HDMI transmitter driver");
Signature · 1 line
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, hosted by The Linux Foundation
#41 lore raw

Re: [PATCH v3 4/7] drm/i2c: adv7511: Create a MIPI DSI device

Hi Laurent,

Quoted 27 lines · Archit Taneja

Hi Laurent,

Quoted 16 lines · Laurent Pinchart

Hi Archit,

Thank you for the patch.

Quoted 11 lines · On Wednesday 09 Mar 2016 16:27:15 Archit Taneja wrote:

In order to pass DSI specific parameters to the DSI host, we need the driver to create a mipi_dsi_device DSI device that attaches to the host.

Use of_graph helpers to get the DSI host DT node. Create a MIPI DSI device using this host. Finally, attach this device to the DSI host.

Populate DT parameters (number of data lanes for now) that are required for DSI RX to work correctly. Hardcode few other parameters (rgb, embedded_sync) for now.

Quoted 6 lines
Quoted 1 line

This adds a hard dependency on CONFIG_DRM_MIPI_DSI, otherwise the kernel won't
link. As the ADV7511 doesn't require DSI, could you make it optional with conditional compilation to avoid pulling in dead code ?

Quoted 6 lines

You're right. The driver's Kconfig should at least select DRM_MIPI_DSI in the current state to make sure we don't break build.

Do you suggest we create another config option for ADV7533, which selects DRM_MIPI_DSI and builds the ADV7533 parts? Or did you mean something else?

Do you have any suggestions for this point? For the next revision, I've just selected DRM_MIPI_DSI in the Kconfig to ensure build doesn't break.

For this driver, to conditionally compile DRM_MIPI_DSI, it essentially means we allow conditional support for ADV7533. I would imagine us #ifdef-ing out the ADV7533 compatible string in the of_match_table. Is this something we want to do?

Thanks,
Archit

Quoted 231 lines
Quoted 230 lines
Quoted 229 lines

---
  drivers/gpu/drm/i2c/adv7511.c | 130
++++++++++++++++++++++++++++++++++++---
  1 file changed, 123 insertions(+), 7 deletions(-)
drivers/gpu/drm/i2c/adv7511.c +11 -2
index 75be17c..6c2a89a 100644
@@ -11,6 +11,7 @@
  #include <linux/i2c.h>
  #include <linux/module.h>
  #include <linux/of_device.h>
+#include <linux/of_graph.h>
  #include <linux/regmap.h>
  #include <linux/slab.h>
 
@@ -19,6 +20,7 @@
  #include <drm/drm_atomic_helper.h>
  #include <drm/drm_crtc_helper.h>
  #include <drm/drm_edid.h>
+#include <drm/drm_mipi_dsi.h>
 
  #include "adv7511.h"
 
@@ -56,6 +58,11 @@ struct adv7511 {
 
      struct gpio_desc *gpio_pd;
 
+    /* ADV7533 DSI RX related params */
+    struct device_node *host_node;
+    struct mipi_dsi_device *dsi;
+    u8 num_dsi_lanes;
+
      enum adv7511_type type;
  };
 
@@ -392,8 +399,10 @@ static void adv7511_set_link_config(struct adv7511
 *adv7511,
 
  static void adv7533_dsi_power_on(struct adv7511 *adv)
  {
-    /* set number of dsi lanes (hardcoded to 4 for now) */
-    regmap_write(adv->regmap_cec, 0x1c, 0x4 << 4);
+    struct mipi_dsi_device *dsi = adv->dsi;
+
+    /* set number of dsi lanes */
+    regmap_write(adv->regmap_cec, 0x1c, dsi->lanes << 4);
      /* disable internal timing generator */
      regmap_write(adv->regmap_cec, 0x27, 0x0b);
      /* enable hdmi */
drivers/gpu/drm/i2c/adv7511.c +0 -0
@@ -889,6 +898,51 @@ static void adv7511_bridge_mode_set(struct

drm_bridge
*bridge, adv7511_mode_set(adv, mode, adj_mode);
}

drivers/gpu/drm/i2c/adv7511.c +29 -0
+static int adv7533_attach_dsi(struct adv7511 *adv)
+{
+    struct device *dev = &adv->i2c_main->dev;
+    struct mipi_dsi_host *host;
+    struct mipi_dsi_device *dsi;
+    int ret = 0;
+    const struct mipi_dsi_device_info info = { .type = "adv7533",
+                           .channel = 0,
+                           .node = NULL,
+                         };
+
+    host = of_find_mipi_dsi_host_by_node(adv->host_node);
+    if (!host) {
+        dev_err(dev, "failed to find dsi host\n");
+        return -EPROBE_DEFER;
+    }
+
+    dsi = mipi_dsi_device_register_full(host, &info);
+    if (IS_ERR(dsi)) {
+        dev_err(dev, "failed to create dsi device\n");
+        ret = PTR_ERR(dsi);
+        goto err_dsi_device;
+    }
+
+    adv->dsi = dsi;
+
+    dsi->lanes = adv->num_dsi_lanes;
+    dsi->format = MIPI_DSI_FMT_RGB888;
+    dsi->mode_flags = MIPI_DSI_MODE_VIDEO |

MIPI_DSI_MODE_VIDEO_SYNC_PULSE |

drivers/gpu/drm/i2c/adv7511.c +54 -0
+              MIPI_DSI_MODE_EOT_PACKET | MIPI_DSI_MODE_VIDEO_HSE;
+
+    ret = mipi_dsi_attach(dsi);
+    if (ret < 0) {
+        dev_err(dev, "failed to attach dsi to host\n");
+        goto err_dsi_attach;
+    }
+
+    return 0;
+
+err_dsi_attach:
+    mipi_dsi_device_unregister(dsi);
+err_dsi_device:
+    return ret;
+}
+
  static int adv7511_bridge_attach(struct drm_bridge *bridge)
  {
      struct adv7511 *adv = bridge_to_adv7511(bridge);
@@ -912,6 +966,9 @@ static int adv7511_bridge_attach(struct drm_bridge
 *bridge) &adv7511_connector_helper_funcs);
      drm_mode_connector_attach_encoder(&adv->connector,
 bridge->encoder);
 
+    if (adv->type == ADV7533)
+        ret = adv7533_attach_dsi(adv);
+
      return ret;
  }
@@ -1009,6 +1066,41 @@ static int adv7511_parse_dt(struct device_node
 *np,
      return 0;
  }
 
+static int adv7533_parse_dt(struct device_node *np, struct adv7511
 *adv)
+{
+    u32 num_lanes;
+    struct device_node *endpoint;
+
+    of_property_read_u32(np, "adi,dsi-lanes", &num_lanes);
+
+    if (num_lanes < 1 || num_lanes > 4)
+        return -EINVAL;
+
+    adv->num_dsi_lanes = num_lanes;
+
+    endpoint = of_graph_get_next_endpoint(np, NULL);
+    if (!endpoint) {
+        DRM_ERROR("ADV7533 DSI input endpoint not found\n");
+        return -ENODEV;
+    }
+
+    adv->host_node = of_graph_get_remote_port_parent(endpoint);
+    if (!adv->host_node) {
+        DRM_ERROR("DSI host node not found\n");
+        of_node_put(endpoint);
+        return -ENODEV;
+    }
+
+    of_node_put(endpoint);
+    of_node_put(adv->host_node);
+
+    /* TODO: Check if these need to be parsed by DT or not */
+    adv->rgb = true;
+    adv->embedded_sync = false;
+
+    return 0;
+}
+
  static const int edid_i2c_addr = 0x7e;
  static const int packet_i2c_addr = 0x70;
  static const int cec_i2c_addr = 0x78;
drivers/gpu/drm/i2c/adv7511.c +5 -4
@@ -1038,11 +1130,12 @@ static int adv7511_probe(struct i2c_client *i2c,
 const struct i2c_device_id *id)
 
      memset(&link_config, 0, sizeof(link_config));
 
-    if (adv7511->type == ADV7511) {
+    if (adv7511->type == ADV7511)
          ret = adv7511_parse_dt(dev->of_node, &link_config);
-        if (ret)
-            return ret;
-    }
+    else
+        ret = adv7533_parse_dt(dev->of_node, adv7511);
+    if (ret)
+        return ret;
 
      /*

* The power down GPIO is optional. If present, toggle it from
active to

drivers/gpu/drm/i2c/adv7511.c +9 -0
@@ -1155,6 +1248,11 @@ static int adv7511_remove(struct i2c_client *i2c)
  {
      struct adv7511 *adv7511 = i2c_get_clientdata(i2c);
 
+    if (adv7511->type == ADV7533) {
+        mipi_dsi_detach(adv7511->dsi);
+        mipi_dsi_device_unregister(adv7511->dsi);
+    }
+
      drm_bridge_remove(&adv7511->bridge);
 
      i2c_unregister_device(adv7511->i2c_cec);
@@ -1183,6 +1281,10 @@ static const struct of_device_id
 adv7511_of_ids[] = {
 };
  MODULE_DEVICE_TABLE(of, adv7511_of_ids);
 
+static struct mipi_dsi_driver adv7533_dsi_driver = {
+    .driver.name = "adv7533",
+};
+
  static struct i2c_driver adv7511_driver = {
      .driver = {
          .name = "adv7511",
drivers/gpu/drm/i2c/adv7511.c +15 -1
@@ -1193,7 +1295,21 @@ static struct i2c_driver adv7511_driver = {
      .remove = adv7511_remove,
  };
 
-module_i2c_driver(adv7511_driver);
+static int __init adv7511_init(void)
+{
+    mipi_dsi_driver_register(&adv7533_dsi_driver);
+
+    return i2c_add_driver(&adv7511_driver);
+}
+module_init(adv7511_init);
+
+static void __exit adv7511_exit(void)
+{
+    i2c_del_driver(&adv7511_driver);
+
+    mipi_dsi_driver_unregister(&adv7533_dsi_driver);
+}
+module_exit(adv7511_exit);
 
  MODULE_AUTHOR("Lars-Peter Clausen <[email protected]>");
  MODULE_DESCRIPTION("ADV7511 HDMI transmitter driver");
Signature · 1 line
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, hosted by The Linux Foundation
#42 lore raw

Re: [PATCH v3 4/7] drm/i2c: adv7511: Create a MIPI DSI device

Hi Archit,

Quoted 27 lines · On Tuesday 03 May 2016 12:27:38 Archit Taneja wrote:
Quoted 19 lines · Archit Taneja
Quoted 12 lines · Laurent Pinchart
Quoted 11 lines · On Wednesday 09 Mar 2016 16:27:15 Archit Taneja wrote:

In order to pass DSI specific parameters to the DSI host, we need the driver to create a mipi_dsi_device DSI device that attaches to the host.

Use of_graph helpers to get the DSI host DT node. Create a MIPI DSI device using this host. Finally, attach this device to the DSI host.

Populate DT parameters (number of data lanes for now) that are required for DSI RX to work correctly. Hardcode few other parameters (rgb, embedded_sync) for now.

Quoted 5 lines
Quoted 1 line

This adds a hard dependency on CONFIG_DRM_MIPI_DSI, otherwise the kernel won't link. As the ADV7511 doesn't require DSI, could you make it optional with conditional compilation to avoid pulling in dead code ?

Quoted 6 lines

You're right. The driver's Kconfig should at least select DRM_MIPI_DSI in the current state to make sure we don't break build.

Do you suggest we create another config option for ADV7533, which selects DRM_MIPI_DSI and builds the ADV7533 parts? Or did you mean something else?

Quoted 7 lines

Do you have any suggestions for this point? For the next revision, I've just selected DRM_MIPI_DSI in the Kconfig to ensure build doesn't break.

For this driver, to conditionally compile DRM_MIPI_DSI, it essentially means we allow conditional support for ADV7533. I would imagine us #ifdef-ing out the ADV7533 compatible string in the of_match_table. Is this something we want to do?

If it's not much trouble I think that would be useful to avoid bloating the kernel with unused features, yes. You might want to add stub functions to include/drm/drm_mipi_dsi.h when CONFIG_DRM_MIPI_DSI is not defined to avoid sprinkling the driver with lots of #ifdefs.

Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines

---

drivers/gpu/drm/i2c/adv7511.c | 130 +++++++++++++++++++++++++++++++++---

 1 file changed, 123 insertions(+), 7 deletions(-)
Signature · 3 lines
Regards,

Laurent Pinchart
#43 lore raw

Re: [PATCH v3 4/7] drm/i2c: adv7511: Create a MIPI DSI device

Quoted 38 lines · Laurent Pinchart

Hi Archit,

Quoted 27 lines · On Tuesday 03 May 2016 12:27:38 Archit Taneja wrote:
Quoted 19 lines · Archit Taneja
Quoted 12 lines · Laurent Pinchart
Quoted 11 lines · On Wednesday 09 Mar 2016 16:27:15 Archit Taneja wrote:

In order to pass DSI specific parameters to the DSI host, we need the driver to create a mipi_dsi_device DSI device that attaches to the host.

Use of_graph helpers to get the DSI host DT node. Create a MIPI DSI device using this host. Finally, attach this device to the DSI host.

Populate DT parameters (number of data lanes for now) that are required for DSI RX to work correctly. Hardcode few other parameters (rgb, embedded_sync) for now.

Quoted 5 lines
Quoted 1 line

This adds a hard dependency on CONFIG_DRM_MIPI_DSI, otherwise the kernel won't link. As the ADV7511 doesn't require DSI, could you make it optional with conditional compilation to avoid pulling in dead code ?

Quoted 6 lines

You're right. The driver's Kconfig should at least select DRM_MIPI_DSI in the current state to make sure we don't break build.

Do you suggest we create another config option for ADV7533, which selects DRM_MIPI_DSI and builds the ADV7533 parts? Or did you mean something else?

Quoted 7 lines

Do you have any suggestions for this point? For the next revision, I've just selected DRM_MIPI_DSI in the Kconfig to ensure build doesn't break.

For this driver, to conditionally compile DRM_MIPI_DSI, it essentially means we allow conditional support for ADV7533. I would imagine us #ifdef-ing out the ADV7533 compatible string in the of_match_table. Is this something we want to do?

Quoted 4 lines

If it's not much trouble I think that would be useful to avoid bloating the kernel with unused features, yes. You might want to add stub functions to include/drm/drm_mipi_dsi.h when CONFIG_DRM_MIPI_DSI is not defined to avoid sprinkling the driver with lots of #ifdefs.

Yeah, I can do this. Now that there isn't a chance for it to get in the 4.7 merge window, there's plenty time.

Archit

Quoted 6 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines

---

drivers/gpu/drm/i2c/adv7511.c | 130 +++++++++++++++++++++++++++++++++---

  1 file changed, 123 insertions(+), 7 deletions(-)
Signature · 5 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, hosted by The Linux Foundation
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
#44 lore raw

PATCH v3 5/7 drm/i2c: adv7511: Use internal timing generator

In reply to Archit Taneja

ADV7533 provides an internal timing generator for certain modes that it can't use the DSI clock directly.

We've observed that HDMI is more stable with the internal timing generator, especially if there are instabilities in the DSI clock source. The data spec also seems to recommend the usage of the timing generator for all modes.

However, on some platforms, it's reported that enabling the timing generator causes instabilities with the HDMI output.

Create a DT parameter that lets a platform explicitly disable the timing generator. The timing generator is enabled by default.

---
 drivers/gpu/drm/i2c/adv7511.c | 65 +++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 63 insertions(+), 2 deletions(-)
drivers/gpu/drm/i2c/adv7511.c +63 -2
index 6c2a89a..88918ae 100644
@@ -39,6 +39,8 @@ struct adv7511 {
 	enum drm_connector_status status;
 	bool powered;
 
+	struct drm_display_mode curr_mode;
+
 	unsigned int f_tmds;
 
 	unsigned int current_edid_segment;
@@ -62,6 +64,7 @@ struct adv7511 {
 	struct device_node *host_node;
 	struct mipi_dsi_device *dsi;
 	u8 num_dsi_lanes;
+	bool use_timing_gen;
 
 	enum adv7511_type type;
 };
@@ -397,14 +400,65 @@ static void adv7511_set_link_config(struct adv7511 *adv7511,
 	adv7511->rgb = config->input_colorspace == HDMI_COLORSPACE_RGB;
 }
 
+static void adv7511_dsi_config_timing_gen(struct adv7511 *adv)
+{
+	struct mipi_dsi_device *dsi = adv->dsi;
+	struct drm_display_mode *mode = &adv->curr_mode;
+	unsigned int hsw, hfp, hbp, vsw, vfp, vbp;
+	u8 clock_div_by_lanes[] = { 6, 4, 3 };	/* 2, 3, 4 lanes */
+
+	hsw = mode->hsync_end - mode->hsync_start;
+	hfp = mode->hsync_start - mode->hdisplay;
+	hbp = mode->htotal - mode->hsync_end;
+	vsw = mode->vsync_end - mode->vsync_start;
+	vfp = mode->vsync_start - mode->vdisplay;
+	vbp = mode->vtotal - mode->vsync_end;
+
+	/* set pixel clock divider mode */
+	regmap_write(adv->regmap_cec, 0x16,
+		     clock_div_by_lanes[dsi->lanes - 2] << 3);
+
+	/* horizontal porch params */
+	regmap_write(adv->regmap_cec, 0x28, mode->htotal >> 4);
+	regmap_write(adv->regmap_cec, 0x29, (mode->htotal << 4) & 0xff);
+	regmap_write(adv->regmap_cec, 0x2a, hsw >> 4);
+	regmap_write(adv->regmap_cec, 0x2b, (hsw << 4) & 0xff);
+	regmap_write(adv->regmap_cec, 0x2c, hfp >> 4);
+	regmap_write(adv->regmap_cec, 0x2d, (hfp << 4) & 0xff);
+	regmap_write(adv->regmap_cec, 0x2e, hbp >> 4);
+	regmap_write(adv->regmap_cec, 0x2f, (hbp << 4) & 0xff);
+
+	/* vertical porch params */
+	regmap_write(adv->regmap_cec, 0x30, mode->vtotal >> 4);
+	regmap_write(adv->regmap_cec, 0x31, (mode->vtotal << 4) & 0xff);
+	regmap_write(adv->regmap_cec, 0x32, vsw >> 4);
+	regmap_write(adv->regmap_cec, 0x33, (vsw << 4) & 0xff);
+	regmap_write(adv->regmap_cec, 0x34, vfp >> 4);
+	regmap_write(adv->regmap_cec, 0x35, (vfp << 4) & 0xff);
+	regmap_write(adv->regmap_cec, 0x36, vbp >> 4);
+	regmap_write(adv->regmap_cec, 0x37, (vbp << 4) & 0xff);
+}
+
 static void adv7533_dsi_power_on(struct adv7511 *adv)
 {
 	struct mipi_dsi_device *dsi = adv->dsi;
 
+	if (adv->use_timing_gen)
+		adv7511_dsi_config_timing_gen(adv);
+
 	/* set number of dsi lanes */
 	regmap_write(adv->regmap_cec, 0x1c, dsi->lanes << 4);
-	/* disable internal timing generator */
-	regmap_write(adv->regmap_cec, 0x27, 0x0b);
+
+	if (adv->use_timing_gen) {
+		/* reset internal timing generator */
+		regmap_write(adv->regmap_cec, 0x27, 0xcb);
+		regmap_write(adv->regmap_cec, 0x27, 0x8b);
+		regmap_write(adv->regmap_cec, 0x27, 0xcb);
+	} else {
+		/* disable internal timing generator */
+		regmap_write(adv->regmap_cec, 0x27, 0x0b);
+	}
+
 	/* enable hdmi */
 	regmap_write(adv->regmap_cec, 0x03, 0x89);
 	/* disable test mode */
@@ -459,6 +513,8 @@ static void adv7533_dsi_power_off(struct adv7511 *adv)
 {
 	/* disable hdmi */
 	regmap_write(adv->regmap_cec, 0x03, 0x0b);
+	/* disable internal timing generator */
+	regmap_write(adv->regmap_cec, 0x27, 0x0b);
 }
 
 static void adv7511_power_off(struct adv7511 *adv7511)
@@ -807,6 +863,8 @@ static void adv7511_mode_set(struct adv7511 *adv7511,
 	regmap_update_bits(adv7511->regmap, 0x17,
 		0x60, (vsync_polarity << 6) | (hsync_polarity << 5));
 
+	drm_mode_copy(&adv7511->curr_mode, adj_mode);
+
 	/*
 	 * TODO Test first order 4:2:2 to 4:4:4 up conversion method, which is
 	 * supposed to give better results.
@@ -1094,6 +1152,9 @@ static int adv7533_parse_dt(struct device_node *np, struct adv7511 *adv)
 	of_node_put(endpoint);
 	of_node_put(adv->host_node);
 
+	adv->use_timing_gen = !of_property_read_bool(np,
+						"adi,disable-timing-generator");
+
 	/* TODO: Check if these need to be parsed by DT or not */
 	adv->rgb = true;
 	adv->embedded_sync = false;
Signature · 7 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
#45 lore raw

PATCH v3 6/7 drm/i2c: adv7511: Change number of DSI lanes dynamically

In reply to Archit Taneja

Lower modes on ADV7533 require lower number of DSI lanes for correct operation. If ADV7533 is being used with 4 DSI lanes, then switch the lanes to 3 when the target mode's pixel clock is less than 80 Mhz.

Based on patch by Andy Green <[email protected]>

---
 drivers/gpu/drm/i2c/adv7511.c | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)
drivers/gpu/drm/i2c/adv7511.c +20 -0
index 88918ae..ca9e862 100644
@@ -863,6 +863,26 @@ static void adv7511_mode_set(struct adv7511 *adv7511,
 	regmap_update_bits(adv7511->regmap, 0x17,
 		0x60, (vsync_polarity << 6) | (hsync_polarity << 5));
 
+	if (adv7511->type == ADV7533 && adv7511->num_dsi_lanes == 4) {
+		struct mipi_dsi_device *dsi = adv7511->dsi;
+		int lanes, ret;
+
+		if (adj_mode->clock > 80000)
+			lanes = 4;
+		else
+			lanes = 3;
+
+		if (lanes != dsi->lanes) {
+			mipi_dsi_detach(dsi);
+			dsi->lanes = lanes;
+			ret = mipi_dsi_attach(dsi);
+			if (ret) {
+				DRM_ERROR("Failed to change host lanes\n");
+				return;
+			}
+		}
+	}
+
 	drm_mode_copy(&adv7511->curr_mode, adj_mode);
 
 	/*
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

A message that is not in the archive (sent off-list or not yet received): 1457521038-5906-1-git-send-email-architt-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org

#47 lore raw

PATCH v3 7/7 dt-bindings: drm/bridge: Update bindings for ADV7533

Add description of ADV7533. Add the required and optional properties that are specific to it.

---
 .../bindings/display/bridge/adi,adv7511.txt        | 25 +++++++++++++++++-----
 1 file changed, 20 insertions(+), 5 deletions(-)
Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt +20 -5
index 96c25ee..420da5a 100644
@@ -1,13 +1,19 @@
-Analog Device ADV7511(W)/13 HDMI Encoders
+Analog Device ADV7511(W)/13/33 HDMI Encoders
 -----------------------------------------
 
-The ADV7511, ADV7511W and ADV7513 are HDMI audio and video transmitters
+The ADV7511, ADV7511W, ADV7513 and ADV7533 are HDMI audio and video transmitters
 compatible with HDMI 1.4 and DVI 1.0. They support color space conversion,
-S/PDIF, CEC and HDCP.
+S/PDIF, CEC and HDCP. ADV7533 supports the DSI interface for input pixels, while
+the others support RGB interface.
 
 Required properties:
 
-- compatible: Should be one of "adi,adv7511", "adi,adv7511w" or "adi,adv7513"
+- compatible: Should be one of:
+		"adi,adv7511"
+		"adi,adv7511w"
+		"adi,adv7513"
+		"adi,adv7533"
+
 - reg: I2C slave address
 
 The ADV7511 supports a large number of input data formats that differ by their
@@ -32,6 +38,11 @@ The following input format properties are required except in "rgb 1x" and
 - adi,input-justification: The input bit justification ("left", "evenly",
   "right").
 
+The following properties are required for ADV7533:
+
+- adi,dsi-lanes: Number of DSI data lanes connected to the DSI host. It should
+  be one of 1, 2, 3 or 4.
+
 Optional properties:
 
 - interrupts: Specifier for the ADV7511 interrupt
@@ -42,13 +53,17 @@ Optional properties:
 - adi,embedded-sync: The input uses synchronization signals embedded in the
   data stream (similar to BT.656). Defaults to separate H/V synchronization
   signals.
+- adi,disable-timing-generator: Only for ADV7533. Disables the internal timing
+  generator. The chip will rely on the sync signals in the DSI data lanes,
+  rather than generate its own timings for HDMI output.
 
 Required nodes:
 
 The ADV7511 has two video ports. Their connections are modelled using the OF
 graph bindings specified in Documentation/devicetree/bindings/graph.txt.
 
-- Video port 0 for the RGB or YUV input
+- Video port 0 for the RGB, YUV or DSI input. In the case of ADV7533, the
+  remote endpoint phandle should refer to a valid mipi_dsi_host device node.
 - Video port 1 for the HDMI output
 
 
Signature · 7 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
maintainer Acked-by on v3 7/7
#48 lore raw

Re: [PATCH v3 7/7] dt-bindings: drm/bridge: Update bindings for ADV7533

Quoted 10 lines · Archit Taneja

Add description of ADV7533. Add the required and optional properties that are specific to it.

---
 .../bindings/display/bridge/adi,adv7511.txt        | 25 +++++++++++++++++-----
 1 file changed, 20 insertions(+), 5 deletions(-)

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel

#49 lore raw

Re: [PATCH v3 7/7] dt-bindings: drm/bridge: Update bindings for ADV7533

In reply to Archit Taneja

Hi Archit,

Thank you for the patch.

Quoted 48 lines · On Wednesday 09 Mar 2016 16:27:18 Archit Taneja wrote:

Add description of ADV7533. Add the required and optional properties that are specific to it.

---
 .../bindings/display/bridge/adi,adv7511.txt        | 25 ++++++++++++++-----
 1 file changed, 20 insertions(+), 5 deletions(-)

diff --git a/Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt b/Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt index 96c25ee..420da5a 100644

Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt +2 -2
@@ -1,13 +1,19 @@
-Analog Device ADV7511(W)/13 HDMI Encoders
+Analog Device ADV7511(W)/13/33 HDMI Encoders
 -----------------------------------------
 
-The ADV7511, ADV7511W and ADV7513 are HDMI audio and video transmitters
+The ADV7511, ADV7511W, ADV7513 and ADV7533 are HDMI audio and video

transmitters compatible with HDMI 1.4 and DVI 1.0. They support color space conversion, -S/PDIF, CEC and HDCP.
+S/PDIF, CEC and HDCP. ADV7533 supports the DSI interface for input pixels, while +the others support RGB interface.

Required properties:

-- compatible: Should be one of "adi,adv7511", "adi,adv7511w" or "adi,adv7513" +- compatible: Should be one of:

Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt +5 -0
+		"adi,adv7511"
+		"adi,adv7511w"
+		"adi,adv7513"
+		"adi,adv7533"
+
 - reg: I2C slave address
 
 The ADV7511 supports a large number of input data formats that differ by

their @@ -32,6 +38,11 @@ The following input format properties are required except in "rgb 1x" and - adi,input-justification: The input bit justification ("left", "evenly", "right").

Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt +3 -0
+The following properties are required for ADV7533:
+
+- adi,dsi-lanes: Number of DSI data lanes connected to the DSI host. It
Quoted 1 line

should + be one of 1, 2, 3 or 4.

Does the ADV7533 support data lanes remapping ?

Quoted 10 lines

Optional properties:

- interrupts: Specifier for the ADV7511 interrupt

Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt +0 -0
@@ -42,13 +53,17 @@ Optional properties:
 - adi,embedded-sync: The input uses synchronization signals embedded in the

data stream (similar to BT.656). Defaults to separate H/V synchronization signals.

+- adi,disable-timing-generator: Only for ADV7533. Disables the internal
timing +  generator. The chip will rely on the sync signals in the DSI data
lanes, +  rather than generate its own timings for HDMI output.

Isn't that something that should be selectable at runtime ?

Quoted 8 lines

Required nodes:

The ADV7511 has two video ports. Their connections are modelled using the
OF graph bindings specified in Documentation/devicetree/bindings/graph.txt.

-- Video port 0 for the RGB or YUV input

+- Video port 0 for the RGB, YUV or DSI input. In the case of ADV7533, the
+  remote endpoint phandle should refer to a valid mipi_dsi_host device

Nitpicking, I would write "reference" instead of "refer to".

Quoted 1 line

node. - Video port 1 for the HDMI output

Signature · 8 lines
Regards,

Laurent Pinchart

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
#50 lore raw

Re: [PATCH v3 7/7] dt-bindings: drm/bridge: Update bindings for ADV7533

Quoted 50 lines · Laurent Pinchart

Hi Archit,

Thank you for the patch.

Quoted 45 lines · On Wednesday 09 Mar 2016 16:27:18 Archit Taneja wrote:

Add description of ADV7533. Add the required and optional properties that are specific to it.

---
  .../bindings/display/bridge/adi,adv7511.txt        | 25 ++++++++++++++-----
  1 file changed, 20 insertions(+), 5 deletions(-)

diff --git a/Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt b/Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt index 96c25ee..420da5a 100644

Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt +2 -2
@@ -1,13 +1,19 @@
-Analog Device ADV7511(W)/13 HDMI Encoders
+Analog Device ADV7511(W)/13/33 HDMI Encoders
  -----------------------------------------
 
-The ADV7511, ADV7511W and ADV7513 are HDMI audio and video transmitters
+The ADV7511, ADV7511W, ADV7513 and ADV7533 are HDMI audio and video

transmitters compatible with HDMI 1.4 and DVI 1.0. They support color space conversion, -S/PDIF, CEC and HDCP.
+S/PDIF, CEC and HDCP. ADV7533 supports the DSI interface for input pixels, while +the others support RGB interface.

Required properties:

-- compatible: Should be one of "adi,adv7511", "adi,adv7511w" or "adi,adv7513" +- compatible: Should be one of:

Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt +5 -0
+		"adi,adv7511"
+		"adi,adv7511w"
+		"adi,adv7513"
+		"adi,adv7533"
+
  - reg: I2C slave address
 
  The ADV7511 supports a large number of input data formats that differ by

their @@ -32,6 +38,11 @@ The following input format properties are required except in "rgb 1x" and - adi,input-justification: The input bit justification ("left", "evenly", "right").

Quoted 6 lines
Quoted 4 lines
Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt +3 -0
+The following properties are required for ADV7533:
+
+- adi,dsi-lanes: Number of DSI data lanes connected to the DSI host. It

should + be one of 1, 2, 3 or 4.

Does the ADV7533 support data lanes remapping ?

It doesn't support remapping of lanes. There is only one register field that allows us to select the number of lanes.

Quoted 13 lines
Quoted 11 lines

Optional properties:

- interrupts: Specifier for the ADV7511 interrupt

Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt +0 -0
@@ -42,13 +53,17 @@ Optional properties:
  - adi,embedded-sync: The input uses synchronization signals embedded in the

data stream (similar to BT.656). Defaults to separate H/V synchronization signals.

+- adi,disable-timing-generator: Only for ADV7533. Disables the internal
timing +  generator. The chip will rely on the sync signals in the DSI data
lanes, +  rather than generate its own timings for HDMI output.

Isn't that something that should be selectable at runtime ?

The timing generator can be enabled/disabled at runtime. Although, we don't have a way to tell the driver whether we want to keep it enabled or not.

It's a hardware feature that works well on most platforms, but not on
all. In particular, it works well on DB410c, but causes issues with
the Hikey 96 board. The DSI host on Hikey has different clock sources that generate the display controller's pixel clock and DSI byte clock, whereas the Qualcomm SoC uses the same source. My guess is that the
ADV7533's timing generator doesn't like it when the pixel data and
clock are out of phase or something.

Since it is a hardware feature which needs tweaking, I thought it qualified as a DT property.

Quoted 11 lines
Quoted 9 lines

Required nodes:

The ADV7511 has two video ports. Their connections are modelled using the
OF graph bindings specified in Documentation/devicetree/bindings/graph.txt.

-- Video port 0 for the RGB or YUV input

+- Video port 0 for the RGB, YUV or DSI input. In the case of ADV7533, the
+  remote endpoint phandle should refer to a valid mipi_dsi_host device

Nitpicking, I would write "reference" instead of "refer to".

I'll fix this in the next revision.

Thanks,
Archit

Signature · 1 line
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, hosted by The Linux Foundation

A message that is not in the archive (sent off-list or not yet received): [email protected]

#52 lore raw

Re: [PATCH v3 7/7] dt-bindings: drm/bridge: Update bindings for ADV7533

Hi Archit,

Quoted 20 lines · On Friday 22 Apr 2016 11:10:18 Archit Taneja wrote:
Quoted 19 lines · Laurent Pinchart
Quoted 18 lines · On Wednesday 09 Mar 2016 16:27:18 Archit Taneja wrote:

Add description of ADV7533. Add the required and optional properties that are specific to it.

---

.../bindings/display/bridge/adi,adv7511.txt | 25 ++++++++++++-----

1 file changed, 20 insertions(+), 5 deletions(-)

diff --git a/Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt b/Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt index 96c25ee..420da5a 100644

Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt +0 -0

[snip]

Quoted 20 lines
Quoted 7 lines
Quoted 5 lines

+- adi,disable-timing-generator: Only for ADV7533. Disables the internal timing
+ generator. The chip will rely on the sync signals in the DSI data lanes,
+ rather than generate its own timings for HDMI output.

Isn't that something that should be selectable at runtime ?

The timing generator can be enabled/disabled at runtime. Although, we don't have a way to tell the driver whether we want to keep it enabled or not.

It's a hardware feature that works well on most platforms, but not on all. In particular, it works well on DB410c, but causes issues with the Hikey 96 board. The DSI host on Hikey has different clock sources that generate the display controller's pixel clock and DSI byte clock, whereas the Qualcomm SoC uses the same source. My guess is that the ADV7533's timing generator doesn't like it when the pixel data and clock are out of phase or something.

Quoted 2 lines

Since it is a hardware feature which needs tweaking, I thought it qualified as a DT property.

The fact that a hardware generator is present is certainly describes the hardware, but I'm not sure whether to enable it or not also qualifies as a hardware feature.

Are there use cases for using the timing generator conditionally on a given board ? As you implement support for disabling it, I assume it's not mandatory. What feature(s) do we lose if we keep it disabled ?

Signature · 8 lines
Regards,

Laurent Pinchart

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#53 lore raw

Re: [PATCH v3 7/7] dt-bindings: drm/bridge: Update bindings for ADV7533

Quoted 49 lines · Laurent Pinchart

Hi Archit,

Quoted 20 lines · On Friday 22 Apr 2016 11:10:18 Archit Taneja wrote:
Quoted 19 lines · Laurent Pinchart
Quoted 18 lines · On Wednesday 09 Mar 2016 16:27:18 Archit Taneja wrote:

Add description of ADV7533. Add the required and optional properties that are specific to it.

---

.../bindings/display/bridge/adi,adv7511.txt | 25 ++++++++++++-----

1 file changed, 20 insertions(+), 5 deletions(-)

diff --git a/Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt b/Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt index 96c25ee..420da5a 100644

Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt +0 -0

[snip]

Quoted 20 lines
Quoted 7 lines
Quoted 5 lines

+- adi,disable-timing-generator: Only for ADV7533. Disables the internal timing
+ generator. The chip will rely on the sync signals in the DSI data lanes,
+ rather than generate its own timings for HDMI output.

Isn't that something that should be selectable at runtime ?

The timing generator can be enabled/disabled at runtime. Although, we don't have a way to tell the driver whether we want to keep it enabled or not.

It's a hardware feature that works well on most platforms, but not on all. In particular, it works well on DB410c, but causes issues with the Hikey 96 board. The DSI host on Hikey has different clock sources that generate the display controller's pixel clock and DSI byte clock, whereas the Qualcomm SoC uses the same source. My guess is that the ADV7533's timing generator doesn't like it when the pixel data and clock are out of phase or something.

Quoted 2 lines

Since it is a hardware feature which needs tweaking, I thought it qualified as a DT property.

Quoted 8 lines

The fact that a hardware generator is present is certainly describes the hardware, but I'm not sure whether to enable it or not also qualifies as a hardware feature.

Are there use cases for using the timing generator conditionally on a given board ? As you implement support for disabling it, I assume it's not mandatory. What feature(s) do we lose if we keep it disabled ?

The spec says it's recommended to use the internal timing generator. In the case of db410c, I observe an unstable output/flicker for certain modes if I don't enable it.

In the case of hikey platform, it's the other way round.

Xinliang, could you describe the problems you face when the timing generator is enabled?

Thanks,
Archit

Signature · 1 line
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, hosted by The Linux Foundation
#54 lore raw

Re: [PATCH v3 7/7] dt-bindings: drm/bridge: Update bindings for ADV7533

Quoted 74 lines · Archit Taneja
Quoted 61 lines · Laurent Pinchart

Hi Archit,

Quoted 26 lines · On Friday 22 Apr 2016 11:10:18 Archit Taneja wrote:
Quoted 24 lines · Laurent Pinchart
Quoted 22 lines · On Wednesday 09 Mar 2016 16:27:18 Archit Taneja wrote:

Add description of ADV7533. Add the required and optional properties that
are specific to it.

---

.../bindings/display/bridge/adi,adv7511.txt | 25
++++++++++++-----

1 file changed, 20 insertions(+), 5 deletions(-)

diff --git a/Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt b/Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt index
96c25ee..420da5a 100644

Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt +0 -0

[snip]

Quoted 23 lines
Quoted 9 lines
Quoted 6 lines

+- adi,disable-timing-generator: Only for ADV7533. Disables the internal
timing
+ generator. The chip will rely on the sync signals in the DSI data lanes,
+ rather than generate its own timings for HDMI output.

Isn't that something that should be selectable at runtime ?

The timing generator can be enabled/disabled at runtime. Although, we don't have a way to tell the driver whether we want to keep it enabled or not.

It's a hardware feature that works well on most platforms, but not on all. In particular, it works well on DB410c, but causes issues with the Hikey 96 board. The DSI host on Hikey has different clock sources that generate the display controller's pixel clock and DSI byte clock, whereas the Qualcomm SoC uses the same source. My guess is that the ADV7533's timing generator doesn't like it when the pixel data and clock are out of phase or something.

Quoted 2 lines

Since it is a hardware feature which needs tweaking, I thought it qualified as a DT property.

Quoted 9 lines

The fact that a hardware generator is present is certainly describes the hardware, but I'm not sure whether to enable it or not also qualifies as a hardware feature.

Are there use cases for using the timing generator conditionally on a given
board ? As you implement support for disabling it, I assume it's not mandatory. What feature(s) do we lose if we keep it disabled ?

Quoted 8 lines

The spec says it's recommended to use the internal timing generator. In the case of db410c, I observe an unstable output/flicker for certain modes if I don't enable it.

In the case of hikey platform, it's the other way round.

Xinliang, could you describe the problems you face when the timing generator is enabled?

Yes, opening the timing generator of ADV7533 can benefit the HDMI output signal.
But, for some circumstances, we need to disable timing generator:
To make modes work, the timing parameters (hfp, hbp, etc.) used by ADV7533 timing generator should match the ones used in DSI. If the timing parameters changed in DSI and these changing timing parameters can't pass to ADV7533, then it need to disable the timing generator of ADV7533 to make mode work.
Some modes in HiKey is in this case.

Thanks,
-xinliang

Quoted 8 lines

Thanks,
Archit

--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, hosted by The Linux Foundation

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel

#55 lore raw

Re: [PATCH v3 7/7] dt-bindings: drm/bridge: Update bindings for ADV7533

Quoted 84 lines · Xinliang Liu
Quoted 74 lines · Archit Taneja
Quoted 61 lines · Laurent Pinchart

Hi Archit,

Quoted 26 lines · On Friday 22 Apr 2016 11:10:18 Archit Taneja wrote:
Quoted 24 lines · Laurent Pinchart
Quoted 22 lines · On Wednesday 09 Mar 2016 16:27:18 Archit Taneja wrote:

Add description of ADV7533. Add the required and optional properties that
are specific to it.

---

.../bindings/display/bridge/adi,adv7511.txt | 25
++++++++++++-----

1 file changed, 20 insertions(+), 5 deletions(-)

diff --git a/Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt b/Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt index
96c25ee..420da5a 100644

Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt +0 -0

[snip]

Quoted 23 lines
Quoted 9 lines
Quoted 6 lines

+- adi,disable-timing-generator: Only for ADV7533. Disables the internal
timing
+ generator. The chip will rely on the sync signals in the DSI data lanes,
+ rather than generate its own timings for HDMI output.

Isn't that something that should be selectable at runtime ?

The timing generator can be enabled/disabled at runtime. Although, we don't have a way to tell the driver whether we want to keep it enabled or not.

It's a hardware feature that works well on most platforms, but not on all. In particular, it works well on DB410c, but causes issues with the Hikey 96 board. The DSI host on Hikey has different clock sources that generate the display controller's pixel clock and DSI byte clock, whereas the Qualcomm SoC uses the same source. My guess is that the ADV7533's timing generator doesn't like it when the pixel data and clock are out of phase or something.

Quoted 2 lines

Since it is a hardware feature which needs tweaking, I thought it qualified as a DT property.

Quoted 9 lines

The fact that a hardware generator is present is certainly describes the hardware, but I'm not sure whether to enable it or not also qualifies as a hardware feature.

Are there use cases for using the timing generator conditionally on a given
board ? As you implement support for disabling it, I assume it's not mandatory. What feature(s) do we lose if we keep it disabled ?

Quoted 8 lines

The spec says it's recommended to use the internal timing generator. In the case of db410c, I observe an unstable output/flicker for certain modes if I don't enable it.

In the case of hikey platform, it's the other way round.

Xinliang, could you describe the problems you face when the timing generator is enabled?

Quoted 9 lines

Yes, opening the timing generator of ADV7533 can benefit the HDMI output signal.
But, for some circumstances, we need to disable timing generator:
To make modes work, the timing parameters (hfp, hbp, etc.) used by ADV7533 timing generator should match the ones used in DSI. If the timing parameters changed in DSI and these changing timing parameters can't pass to ADV7533, then it need to disable the timing generator of ADV7533 to make mode work.
Some modes in HiKey is in this case.

The ADV7533 chip's DSI receiver supports the DSI Video mode
sub-mode: "Non-burst Mode with sync pulses". Ideally, a DSI receiver supporting this mode should be able to reconstruct the timings using packets embedded in the controller.

With DB410c, it seems to struggle without it, and with Hikey, we need to explicitly disable it because, as I understand, the DSI controller there tweaks some of the timings parameters in the mode it wants to set.

It would have been ideal to not expose this knob in DT, but we need it for ADV7533 to work across multiple platforms.

Laurent, do you have any more thoughts on this? I'd posted out a v4 of this patch set. Please have a look when you get the chance.

Thanks,
Archit

Signature · 5 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, hosted by The Linux Foundation
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
#56 lore raw
In reply to Archit Taneja

Hi Laurent,

Quoted 25 lines · Archit Taneja

ADV7533 is a DSI to HDMI encoder chip. It's like ADV7511, but with an additional DSI RX block that takes in DSI video mode output.

Trying to get this driver merged has had some challenges:

- ADV7533 has an I2C control bus, but acts as a DSI peripheral too. After discussions, it was concluded that we'd want to provide an API to create MIPI DSI devices, rather than expose two different interfaces on DT. The first version [1] tried the former approach the second version [2] showed how the driver would look like if exposed 2 DT nodes. This lateset patchset relies on the MIPI DSI device creation API provided by [3], this has been accepted and should be merged for 4.6.

- The driver was designed as an I2C slave encoder. When ADV7533 patches were posted [1], it was modelled as a bridge, but ADV7511 and others were still left as I2C slave encoders. This wasn't accepted. After discussions, it was decided that ADV7511 too would be converted into a bridge driver, and all the users of ADV7511 should assume it is a bridge. This bridge conversion was done in [4]. There is still some debate over whether the bridge driver be involved in the connector creation, or the KMS driver that has the whole view of the display pipeline. This discussion shouldn't affect this patch set, though.

Quoted 7 lines

This patch set enables ADV7533 support with the above two issues now resolved. It also incorporates ADV7533 specific features and fixes that we've discovered since the first version of this patch was posted.

Tested on ADV7533 chips on DB410c. It should work on the Hikey board too. I'd appreaciate if someone could test it on a ADV7511 platform since I don't have one.

Could you try this patch set on the rcar-du platform? It would help to verify if this doesn't break ADV7511.

Thanks,
Archit

Quoted 26 lines

[4]
https://lists.freedesktop.org/archives/dri-devel/2016-January/098287.html

[3]
https://lkml.org/lkml/2016/2/12/67

[2]
https://lists.freedesktop.org/archives/dri-devel/2015-September/089884.html

[1]:
https://lists.freedesktop.org/archives/dri-devel/2015-July/087088.html

Archit Taneja (7):
drm/i2c: adv7511: Convert to drm_bridge
drm/i2c: adv7511: Fix mutex deadlock when interrupts are disabled drm/i2c: adv7511: Initial support for ADV7533
drm/i2c: adv7511: Create a MIPI DSI device
drm/i2c: adv7511: Use internal timing generator drm/i2c: adv7511: Change number of DSI lanes dynamically
dt-bindings: drm/bridge: Update bindings for ADV7533

  .../bindings/display/bridge/adi,adv7511.txt        |  25 +-
  drivers/gpu/drm/i2c/adv7511.c                      | 539 +++++++++++++++++----
  2 files changed, 476 insertions(+), 88 deletions(-)
Signature · 6 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
reviewer Tested-by
#57 lore raw

Hi Archit,

Quoted 32 lines · On Thursday 14 Apr 2016 20:26:11 Archit Taneja wrote:
Quoted 31 lines · Archit Taneja

ADV7533 is a DSI to HDMI encoder chip. It's like ADV7511, but with an additional DSI RX block that takes in DSI video mode output.

Trying to get this driver merged has had some challenges:

- ADV7533 has an I2C control bus, but acts as a DSI peripheral too.

After discussions, it was concluded that we'd want to provide an API to create MIPI DSI devices, rather than expose two different interfaces on DT. The first version [1] tried the former approach the second version [2] showed how the driver would look like if exposed 2 DT nodes. This lateset patchset relies on the MIPI DSI device creation API provided by [3], this has been accepted and should be merged for 4.6.

- The driver was designed as an I2C slave encoder. When ADV7533

patches were posted [1], it was modelled as a bridge, but ADV7511 and others were still left as I2C slave encoders. This wasn't accepted. After discussions, it was decided that ADV7511 too would be converted into a bridge driver, and all the users of ADV7511 should assume it is a bridge. This bridge conversion was done in [4]. There is still some debate over whether the bridge driver be involved in the connector creation, or the KMS driver that has the whole view of the display pipeline. This discussion shouldn't affect this patch set, though.

This patch set enables ADV7533 support with the above two issues now resolved. It also incorporates ADV7533 specific features and fixes that we've discovered since the first version of this patch was posted.

Quoted 6 lines
Quoted 3 lines

Tested on ADV7533 chips on DB410c. It should work on the Hikey board too. I'd appreaciate if someone could test it on a ADV7511 platform since I don't have one.

Could you try this patch set on the rcar-du platform? It would help to verify if this doesn't break ADV7511.

Basic testing didn't show any regression. For the whole series,

Quoted 22 lines
Quoted 22 lines

[4]
https://lists.freedesktop.org/archives/dri-devel/2016-January/098287.html
[3]
https://lkml.org/lkml/2016/2/12/67
[2]
https://lists.freedesktop.org/archives/dri-devel/2015-September/089884.htm
l
[1]:
https://lists.freedesktop.org/archives/dri-devel/2015-July/087088.html

Archit Taneja (7):
drm/i2c: adv7511: Convert to drm_bridge
drm/i2c: adv7511: Fix mutex deadlock when interrupts are disabled drm/i2c: adv7511: Initial support for ADV7533
drm/i2c: adv7511: Create a MIPI DSI device
drm/i2c: adv7511: Use internal timing generator drm/i2c: adv7511: Change number of DSI lanes dynamically
dt-bindings: drm/bridge: Update bindings for ADV7533

  .../bindings/display/bridge/adi,adv7511.txt        |  25 +-
  drivers/gpu/drm/i2c/adv7511.c                      | 539 +++++++++++----
  2 files changed, 476 insertions(+), 88 deletions(-)
Signature · 8 lines
Regards,

Laurent Pinchart

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
#58 lore raw
Quoted 39 lines · Laurent Pinchart

Hi Archit,

Quoted 36 lines · On Thursday 14 Apr 2016 20:26:11 Archit Taneja wrote:
Quoted 34 lines · Archit Taneja

ADV7533 is a DSI to HDMI encoder chip. It's like ADV7511, but with an additional DSI RX block that takes in DSI video mode output.

Trying to get this driver merged has had some challenges:

- ADV7533 has an I2C control bus, but acts as a DSI peripheral too.

After discussions, it was concluded that we'd want to provide an API to create MIPI DSI devices, rather than expose two different interfaces on DT. The first version [1] tried the former approach the second version [2] showed how the driver would look like if exposed 2 DT nodes. This lateset patchset relies on the MIPI DSI device creation API provided by [3], this has been accepted and should be merged for 4.6.

- The driver was designed as an I2C slave encoder. When ADV7533

patches were posted [1], it was modelled as a bridge, but ADV7511 and others were still left as I2C slave encoders. This wasn't accepted. After discussions, it was decided that ADV7511 too would be converted into a bridge driver, and all the users of ADV7511 should assume it is a bridge. This bridge conversion was done in [4]. There is still some debate over whether the bridge driver be involved in the connector creation, or the KMS driver that has the whole view of the display pipeline. This discussion shouldn't affect this patch set, though.

This patch set enables ADV7533 support with the above two issues now resolved. It also incorporates ADV7533 specific features and fixes that we've discovered since the first version of this patch was posted.

Tested on ADV7533 chips on DB410c. It should work on the Hikey board too. I'd appreaciate if someone could test it on a ADV7511 platform since I don't have one.

Quoted 6 lines
Quoted 2 lines

Could you try this patch set on the rcar-du platform? It would help to verify if this doesn't break ADV7511.

Basic testing didn't show any regression. For the whole series,

Thanks!

Archit

Signature · 5 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, hosted by The Linux Foundation
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
#59 lore raw
In reply to Archit Taneja

Hi Archit,
Thank you for the patches.

Quoted 14 lines · Archit Taneja

ADV7533 is a DSI to HDMI encoder chip. It's like ADV7511, but with an additional DSI RX block that takes in DSI video mode output.

Trying to get this driver merged has had some challenges:

- ADV7533 has an I2C control bus, but acts as a DSI peripheral too. After discussions, it was concluded that we'd want to provide an API to create MIPI DSI devices, rather than expose two different interfaces on DT. The first version [1] tried the former approach the second version [2] showed how the driver would look like if exposed 2 DT nodes. This lateset patchset relies on the MIPI DSI device creation API provided by [3], this has been accepted and should be merged for 4.6.

Quoted 10 lines

- The driver was designed as an I2C slave encoder. When ADV7533 patches were posted [1], it was modelled as a bridge, but ADV7511 and others were still left as I2C slave encoders. This wasn't accepted. After discussions, it was decided that ADV7511 too would be converted into a bridge driver, and all the users of ADV7511 should assume it is a bridge. This bridge conversion was done in [4]. There is still some debate over whether the bridge driver be involved in the connector creation, or the KMS driver that has the whole view of the display pipeline. This discussion shouldn't affect this patch set, though.

I also agree with Laurent Pinchart that bridge driver shoudn't get involved in in the connector creation.
It is better for KMS driver that has the whole view of the display pipeline.

In this case, I mean creating bridge driver to support ADV7533. I think this is something look like panel driver. Maybe we need to add some callback to the bridge to avoid creating connector in bridge driver.
We can refer to panel entity to see what callbacks to be added. One callback I can see is the get_modes callback might be need.

Quoted 6 lines

This patch set enables ADV7533 support with the above two issues now resolved. It also incorporates ADV7533 specific features and fixes that we've discovered since the first version of this patch was posted.

Tested on ADV7533 chips on DB410c. It should work on the Hikey board too.

I have tested the this tracking branch :
https://git.linaro.org/landing-teams/working/qualcomm/kernel.git/shortlog/refs/heads/tracking-qcomlt-adv7511
it works for HiKey.
But it seems this patch set is a little different from the above branch. I think I need to tested this patch set.

Thanks,
-xinliang

Quoted 24 lines

I'd appreaciate if someone could test it on a ADV7511 platform since I don't have one.

[4]
https://lists.freedesktop.org/archives/dri-devel/2016-January/098287.html

[3]
https://lkml.org/lkml/2016/2/12/67

[2]
https://lists.freedesktop.org/archives/dri-devel/2015-September/089884.html

[1]:
https://lists.freedesktop.org/archives/dri-devel/2015-July/087088.html

Archit Taneja (7):
drm/i2c: adv7511: Convert to drm_bridge
drm/i2c: adv7511: Fix mutex deadlock when interrupts are disabled drm/i2c: adv7511: Initial support for ADV7533
drm/i2c: adv7511: Create a MIPI DSI device
drm/i2c: adv7511: Use internal timing generator drm/i2c: adv7511: Change number of DSI lanes dynamically
dt-bindings: drm/bridge: Update bindings for ADV7533

Quoted 8 lines
 .../bindings/display/bridge/adi,adv7511.txt        |  25 +-
 drivers/gpu/drm/i2c/adv7511.c                      | 539 +++++++++++++++++----
 2 files changed, 476 insertions(+), 88 deletions(-)

--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, hosted by The Linux Foundation

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel

#60 lore raw

Hi,

Quoted 29 lines · Xinliang Liu

Hi Archit,
Thank you for the patches.

Quoted 14 lines · Archit Taneja

ADV7533 is a DSI to HDMI encoder chip. It's like ADV7511, but with an additional DSI RX block that takes in DSI video mode output.

Trying to get this driver merged has had some challenges:

- ADV7533 has an I2C control bus, but acts as a DSI peripheral too. After discussions, it was concluded that we'd want to provide an API to create MIPI DSI devices, rather than expose two different interfaces on DT. The first version [1] tried the former approach the second version [2] showed how the driver would look like if exposed 2 DT nodes. This lateset patchset relies on the MIPI DSI device creation API provided by [3], this has been accepted and should be merged for 4.6.

Quoted 10 lines

- The driver was designed as an I2C slave encoder. When ADV7533 patches were posted [1], it was modelled as a bridge, but ADV7511 and others were still left as I2C slave encoders. This wasn't accepted. After discussions, it was decided that ADV7511 too would be converted into a bridge driver, and all the users of ADV7511 should assume it is a bridge. This bridge conversion was done in [4]. There is still some debate over whether the bridge driver be involved in the connector creation, or the KMS driver that has the whole view of the display pipeline. This discussion shouldn't affect this patch set, though.

Quoted 3 lines

I also agree with Laurent Pinchart that bridge driver shoudn't get involved in in the connector creation.
It is better for KMS driver that has the whole view of the display pipeline.

Yes, that's the eventual plan. We were thinking of creating an additional drm bridge api (drm_bridge_create_connector) that helps the KMS driver create a connector for the bridge.

Since there are certain connector related properties that the KMS driver may not be aware of, we were thinking of creating another drm_bridge op which fills up connector properties. Some properties (like whether we want POLLED HPD or not) are more platform specific, and would be parsed via the connector's DT node (that is, if DT is supported on that platform)

For now, this series creates the connector in the bridge's attach op, but relies on the KMS driver to call drm_connector_register. The other stuff I mentioned above can come later.

Quoted 13 lines

In this case, I mean creating bridge driver to support ADV7533. I think this is something look like panel driver. Maybe we need to add some callback to the bridge to avoid creating connector in bridge driver.
We can refer to panel entity to see what callbacks to be added. One callback I can see is the get_modes callback might be need.

Quoted 5 lines

This patch set enables ADV7533 support with the above two issues now resolved. It also incorporates ADV7533 specific features and fixes that we've discovered since the first version of this patch was posted.

Quoted 7 lines
Quoted 1 line

Tested on ADV7533 chips on DB410c. It should work on the Hikey board too.

I have tested the this tracking branch :
https://git.linaro.org/landing-teams/working/qualcomm/kernel.git/shortlog/refs/heads/tracking-qcomlt-adv7511
it works for HiKey.
But it seems this patch set is a little different from the above branch. I think I need to tested this patch set.

Yes, it would be great if you could test the posted patch set and provided a Tested-by. The patches "drm/i2c: adv7511: Init regulators" and above need to still be applied from this branch. I'll post these out in another patch set later.

Thanks,
Archit

Quoted 36 lines

Thanks,
-xinliang

Quoted 32 lines

I'd appreaciate if someone could test it on a ADV7511 platform since I don't have one.

[4]
https://lists.freedesktop.org/archives/dri-devel/2016-January/098287.html

[3]
https://lkml.org/lkml/2016/2/12/67

[2]
https://lists.freedesktop.org/archives/dri-devel/2015-September/089884.html

[1]:
https://lists.freedesktop.org/archives/dri-devel/2015-July/087088.html

Archit Taneja (7):
drm/i2c: adv7511: Convert to drm_bridge
drm/i2c: adv7511: Fix mutex deadlock when interrupts are disabled drm/i2c: adv7511: Initial support for ADV7533
drm/i2c: adv7511: Create a MIPI DSI device
drm/i2c: adv7511: Use internal timing generator drm/i2c: adv7511: Change number of DSI lanes dynamically
dt-bindings: drm/bridge: Update bindings for ADV7533

  .../bindings/display/bridge/adi,adv7511.txt        |  25 +-
  drivers/gpu/drm/i2c/adv7511.c                      | 539 +++++++++++++++++----
  2 files changed, 476 insertions(+), 88 deletions(-)

--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, hosted by The Linux Foundation

Signature · 1 line
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, hosted by The Linux Foundation
#61 lore raw
Quoted 53 lines · Archit Taneja

Hi,

Quoted 32 lines · Xinliang Liu

Hi Archit,
Thank you for the patches.

Quoted 15 lines · Archit Taneja

ADV7533 is a DSI to HDMI encoder chip. It's like ADV7511, but with an additional DSI RX block that takes in DSI video mode output.

Trying to get this driver merged has had some challenges:

- ADV7533 has an I2C control bus, but acts as a DSI peripheral too. After discussions, it was concluded that we'd want to provide an API to create MIPI DSI devices, rather than expose two different interfaces on DT. The first version [1] tried the former approach the second version [2] showed how the driver would look like if exposed 2 DT nodes. This lateset patchset relies on the MIPI DSI device creation API provided by [3], this has been accepted and should be merged for 4.6.

Quoted 10 lines

- The driver was designed as an I2C slave encoder. When ADV7533 patches were posted [1], it was modelled as a bridge, but ADV7511 and others were still left as I2C slave encoders. This wasn't accepted. After discussions, it was decided that ADV7511 too would be converted into a bridge driver, and all the users of ADV7511 should assume it is a bridge. This bridge conversion was done in [4]. There is still some debate over whether the bridge driver be involved in the connector creation, or the KMS driver that has the whole view of the display pipeline. This discussion shouldn't affect this patch set, though.

Quoted 4 lines

I also agree with Laurent Pinchart that bridge driver shoudn't get involved in in the connector creation.
It is better for KMS driver that has the whole view of the display pipeline.

Yes, that's the eventual plan. We were thinking of creating an additional drm bridge api (drm_bridge_create_connector) that helps the KMS driver create a connector for the bridge.

Since there are certain connector related properties that the KMS driver may not be aware of, we were thinking of creating another drm_bridge op which fills up connector properties. Some properties (like whether we want POLLED HPD or not) are more platform specific, and would be parsed via the connector's DT node (that is, if DT is supported on that platform)

Quoted 4 lines

For now, this series creates the connector in the bridge's attach op, but relies on the KMS driver to call drm_connector_register. The other stuff I mentioned above can come later.

This is great, if we have the plan.

Quoted 25 lines
Quoted 17 lines

In this case, I mean creating bridge driver to support ADV7533. I think this is something look like panel driver. Maybe we need to add some callback to the bridge to avoid creating connector in bridge driver.
We can refer to panel entity to see what callbacks to be added. One callback I can see is the get_modes callback might be need.

Quoted 6 lines

This patch set enables ADV7533 support with the above two issues now resolved. It also incorporates ADV7533 specific features and fixes that we've discovered since the first version of this patch was posted.

Tested on ADV7533 chips on DB410c. It should work on the Hikey board too.

Quoted 6 lines

I have tested the this tracking branch :

https://git.linaro.org/landing-teams/working/qualcomm/kernel.git/shortlog/refs/heads/tracking-qcomlt-adv7511
it works for HiKey.
But it seems this patch set is a little different from the above branch. I think I need to tested this patch set.

Quoted 4 lines

Yes, it would be great if you could test the posted patch set and provided a Tested-by. The patches "drm/i2c: adv7511: Init regulators" and above need to still be applied from this branch. I'll post these out in another patch set later.

Sure, I will test them all.

Thanks,
-xinliang

Quoted 45 lines

Thanks,
Archit

Quoted 39 lines

Thanks,
-xinliang

Quoted 35 lines

I'd appreaciate if someone could test it on a ADV7511 platform since I don't have one.

[4]
https://lists.freedesktop.org/archives/dri-devel/2016-January/098287.html

[3]
https://lkml.org/lkml/2016/2/12/67

[2]

https://lists.freedesktop.org/archives/dri-devel/2015-September/089884.html

[1]:
https://lists.freedesktop.org/archives/dri-devel/2015-July/087088.html

Archit Taneja (7):
drm/i2c: adv7511: Convert to drm_bridge
drm/i2c: adv7511: Fix mutex deadlock when interrupts are disabled drm/i2c: adv7511: Initial support for ADV7533
drm/i2c: adv7511: Create a MIPI DSI device
drm/i2c: adv7511: Use internal timing generator drm/i2c: adv7511: Change number of DSI lanes dynamically
dt-bindings: drm/bridge: Update bindings for ADV7533

  .../bindings/display/bridge/adi,adv7511.txt        |  25 +-
  drivers/gpu/drm/i2c/adv7511.c                      | 539
+++++++++++++++++----
  2 files changed, 476 insertions(+), 88 deletions(-)

--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

Quoted 3 lines

--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, hosted by The Linux Foundation

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel

#62 lore raw
In reply to Archit Taneja

Hi Archit,

Quoted 43 lines · On Monday 18 Apr 2016 15:18:30 Archit Taneja wrote:
Quoted 26 lines · Xinliang Liu
Quoted 14 lines · Archit Taneja

ADV7533 is a DSI to HDMI encoder chip. It's like ADV7511, but with an additional DSI RX block that takes in DSI video mode output.

Trying to get this driver merged has had some challenges:

- ADV7533 has an I2C control bus, but acts as a DSI peripheral too. After discussions, it was concluded that we'd want to provide an API to create MIPI DSI devices, rather than expose two different interfaces on DT. The first version [1] tried the former approach the second version [2] showed how the driver would look like if exposed 2 DT nodes. This lateset patchset relies on the MIPI DSI device creation API provided by [3], this has been accepted and should be merged for 4.6.

Quoted 10 lines

- The driver was designed as an I2C slave encoder. When ADV7533 patches were posted [1], it was modelled as a bridge, but ADV7511 and others were still left as I2C slave encoders. This wasn't accepted. After discussions, it was decided that ADV7511 too would be converted into a bridge driver, and all the users of ADV7511 should assume it is a bridge. This bridge conversion was done in [4]. There is still some debate over whether the bridge driver be involved in the connector creation, or the KMS driver that has the whole view of the display pipeline. This discussion shouldn't affect this patch set, though.

Quoted 4 lines

I also agree with Laurent Pinchart that bridge driver shoudn't get involved in in the connector creation.
It is better for KMS driver that has the whole view of the display pipeline.

Yes, that's the eventual plan. We were thinking of creating an additional drm bridge api (drm_bridge_create_connector) that helps the KMS driver create a connector for the bridge.

Since there are certain connector related properties that the KMS driver may not be aware of, we were thinking of creating another drm_bridge op which fills up connector properties. Some properties (like whether we want POLLED HPD or not) are more platform specific, and would be parsed via the connector's DT node (that is, if DT is supported on that platform)

Quoted 4 lines

For now, this series creates the connector in the bridge's attach op, but relies on the KMS driver to call drm_connector_register. The other stuff I mentioned above can come later.

Do you think you'd have time to lead that effort ?

Quoted 49 lines
Quoted 11 lines

In this case, I mean creating bridge driver to support ADV7533. I think this is something look like panel driver. Maybe we need to add some callback to the bridge to avoid creating connector in bridge driver.
We can refer to panel entity to see what callbacks to be added. One callback I can see is the get_modes callback might be need.

Quoted 4 lines

This patch set enables ADV7533 support with the above two issues now resolved. It also incorporates ADV7533 specific features and fixes that we've discovered since the first version of this patch was posted.

Quoted 7 lines
Quoted 1 line

Tested on ADV7533 chips on DB410c. It should work on the Hikey board too.

I have tested the this tracking branch :
https://git.linaro.org/landing-teams/working/qualcomm/kernel.git/shortlog/
refs/heads/tracking-qcomlt-adv7511 it works for HiKey. But it seems this patch set is a little different from the above branch. I think I need to tested this patch set.

Yes, it would be great if you could test the posted patch set and provided a Tested-by. The patches "drm/i2c: adv7511: Init regulators" and above need to still be applied from this branch. I'll post these out in another patch set later.

Quoted 25 lines
Quoted 25 lines

I'd appreaciate if someone could test it on a ADV7511 platform since I don't have one.

[4]
https://lists.freedesktop.org/archives/dri-devel/2016-January/098287.html
[3]
https://lkml.org/lkml/2016/2/12/67
[2]
https://lists.freedesktop.org/archives/dri-devel/2015-September/089884.ht
ml
[1]:
https://lists.freedesktop.org/archives/dri-devel/2015-July/087088.html

Archit Taneja (7):
drm/i2c: adv7511: Convert to drm_bridge
drm/i2c: adv7511: Fix mutex deadlock when interrupts are disabled drm/i2c: adv7511: Initial support for ADV7533
drm/i2c: adv7511: Create a MIPI DSI device
drm/i2c: adv7511: Use internal timing generator drm/i2c: adv7511: Change number of DSI lanes dynamically
dt-bindings: drm/bridge: Update bindings for ADV7533

  .../bindings/display/bridge/adi,adv7511.txt        |  25 +-
  drivers/gpu/drm/i2c/adv7511.c                      | 539 ++++++++++----
  2 files changed, 476 insertions(+), 88 deletions(-)
Signature · 3 lines
Regards,

Laurent Pinchart
#63 lore raw
Quoted 46 lines · Laurent Pinchart

Hi Archit,

Quoted 43 lines · On Monday 18 Apr 2016 15:18:30 Archit Taneja wrote:
Quoted 26 lines · Xinliang Liu
Quoted 14 lines · Archit Taneja

ADV7533 is a DSI to HDMI encoder chip. It's like ADV7511, but with an additional DSI RX block that takes in DSI video mode output.

Trying to get this driver merged has had some challenges:

- ADV7533 has an I2C control bus, but acts as a DSI peripheral too. After discussions, it was concluded that we'd want to provide an API to create MIPI DSI devices, rather than expose two different interfaces on DT. The first version [1] tried the former approach the second version [2] showed how the driver would look like if exposed 2 DT nodes. This lateset patchset relies on the MIPI DSI device creation API provided by [3], this has been accepted and should be merged for 4.6.

Quoted 10 lines

- The driver was designed as an I2C slave encoder. When ADV7533 patches were posted [1], it was modelled as a bridge, but ADV7511 and others were still left as I2C slave encoders. This wasn't accepted. After discussions, it was decided that ADV7511 too would be converted into a bridge driver, and all the users of ADV7511 should assume it is a bridge. This bridge conversion was done in [4]. There is still some debate over whether the bridge driver be involved in the connector creation, or the KMS driver that has the whole view of the display pipeline. This discussion shouldn't affect this patch set, though.

Quoted 4 lines

I also agree with Laurent Pinchart that bridge driver shoudn't get involved in in the connector creation.
It is better for KMS driver that has the whole view of the display pipeline.

Yes, that's the eventual plan. We were thinking of creating an additional drm bridge api (drm_bridge_create_connector) that helps the KMS driver create a connector for the bridge.

Since there are certain connector related properties that the KMS driver may not be aware of, we were thinking of creating another drm_bridge op which fills up connector properties. Some properties (like whether we want POLLED HPD or not) are more platform specific, and would be parsed via the connector's DT node (that is, if DT is supported on that platform)

Quoted 6 lines
Quoted 4 lines

For now, this series creates the connector in the bridge's attach op, but relies on the KMS driver to call drm_connector_register. The other stuff I mentioned above can come later.

Do you think you'd have time to lead that effort ?

Yeah, I think I should.

I'll prepare a RFC and we can see how that goes.

Thanks,
Archit

Signature · 5 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, hosted by The Linux Foundation
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
#64 lore raw
In reply to Archit Taneja
Quoted 54 lines · Archit Taneja

ADV7533 is a DSI to HDMI encoder chip. It's like ADV7511, but with an additional DSI RX block that takes in DSI video mode output.

Trying to get this driver merged has had some challenges:

- ADV7533 has an I2C control bus, but acts as a DSI peripheral too. After discussions, it was concluded that we'd want to provide an API to create MIPI DSI devices, rather than expose two different interfaces on DT. The first version [1] tried the former approach the second version [2] showed how the driver would look like if exposed 2 DT nodes. This lateset patchset relies on the MIPI DSI device creation API provided by [3], this has been accepted and should be merged for 4.6.

- The driver was designed as an I2C slave encoder. When ADV7533 patches were posted [1], it was modelled as a bridge, but ADV7511 and others were still left as I2C slave encoders. This wasn't accepted. After discussions, it was decided that ADV7511 too would be converted into a bridge driver, and all the users of ADV7511 should assume it is a bridge. This bridge conversion was done in [4]. There is still some debate over whether the bridge driver be involved in the connector creation, or the KMS driver that has the whole view of the display pipeline. This discussion shouldn't affect this patch set, though.

This patch set enables ADV7533 support with the above two issues now resolved. It also incorporates ADV7533 specific features and fixes that we've discovered since the first version of this patch was posted.

Tested on ADV7533 chips on DB410c. It should work on the Hikey board too. I'd appreaciate if someone could test it on a ADV7511 platform since I don't have one.

[4]
https://lists.freedesktop.org/archives/dri-devel/2016-January/098287.html

[3]
https://lkml.org/lkml/2016/2/12/67

[2]
https://lists.freedesktop.org/archives/dri-devel/2015-September/089884.html

[1]:
https://lists.freedesktop.org/archives/dri-devel/2015-July/087088.html

Archit Taneja (7):
drm/i2c: adv7511: Convert to drm_bridge
drm/i2c: adv7511: Fix mutex deadlock when interrupts are disabled drm/i2c: adv7511: Initial support for ADV7533
drm/i2c: adv7511: Create a MIPI DSI device
drm/i2c: adv7511: Use internal timing generator drm/i2c: adv7511: Change number of DSI lanes dynamically
dt-bindings: drm/bridge: Update bindings for ADV7533

Quoted 8 lines
 .../bindings/display/bridge/adi,adv7511.txt        |  25 +-
 drivers/gpu/drm/i2c/adv7511.c                      | 539 +++++++++++++++++----
 2 files changed, 476 insertions(+), 88 deletions(-)

--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, hosted by The Linux Foundation

This patch set is Tested-by: Xinliang Liu <[email protected]>

Thanks
-xinliang
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel

#65 lore raw
Quoted 59 lines · Xinliang Liu
Quoted 58 lines · Archit Taneja

ADV7533 is a DSI to HDMI encoder chip. It's like ADV7511, but with an additional DSI RX block that takes in DSI video mode output.

Trying to get this driver merged has had some challenges:

- ADV7533 has an I2C control bus, but acts as a DSI peripheral too. After discussions, it was concluded that we'd want to provide an API to create MIPI DSI devices, rather than expose two different interfaces on DT. The first version [1] tried the former approach the second version [2] showed how the driver would look like if exposed 2 DT nodes. This lateset patchset relies on the MIPI DSI device creation API provided by [3], this has been accepted and should be merged for 4.6.

- The driver was designed as an I2C slave encoder. When ADV7533 patches were posted [1], it was modelled as a bridge, but ADV7511 and others were still left as I2C slave encoders. This wasn't accepted. After discussions, it was decided that ADV7511 too would be converted into a bridge driver, and all the users of ADV7511 should assume it is a bridge. This bridge conversion was done in [4]. There is still some debate over whether the bridge driver be involved in the connector creation, or the KMS driver that has the whole view of the display pipeline. This discussion shouldn't affect this patch set, though.

This patch set enables ADV7533 support with the above two issues now resolved. It also incorporates ADV7533 specific features and fixes that we've discovered since the first version of this patch was posted.

Tested on ADV7533 chips on DB410c. It should work on the Hikey board too. I'd appreaciate if someone could test it on a ADV7511 platform since I don't have one.

[4]
https://lists.freedesktop.org/archives/dri-devel/2016-January/098287.html

[3]
https://lkml.org/lkml/2016/2/12/67

[2]
https://lists.freedesktop.org/archives/dri-devel/2015-September/089884.html

[1]:
https://lists.freedesktop.org/archives/dri-devel/2015-July/087088.html

Archit Taneja (7):
drm/i2c: adv7511: Convert to drm_bridge
drm/i2c: adv7511: Fix mutex deadlock when interrupts are disabled drm/i2c: adv7511: Initial support for ADV7533
drm/i2c: adv7511: Create a MIPI DSI device
drm/i2c: adv7511: Use internal timing generator drm/i2c: adv7511: Change number of DSI lanes dynamically
dt-bindings: drm/bridge: Update bindings for ADV7533

  .../bindings/display/bridge/adi,adv7511.txt        |  25 +-
  drivers/gpu/drm/i2c/adv7511.c                      | 539 +++++++++++++++++----
  2 files changed, 476 insertions(+), 88 deletions(-)
Quoted 6 lines
Quoted 4 lines

--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, hosted by The Linux Foundation

This patch set is Tested-by: Xinliang Liu <[email protected]>

Thanks for testing!

Archit

Quoted 8 lines

Thanks
-xinliang
--
To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

Signature · 1 line
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, hosted by The Linux Foundation
#66 lore raw

v4 cover drm/i2c: adv7511: ADV7533 support

In reply to Archit Taneja

ADV7533 is a DSI to HDMI encoder chip. It's like ADV7511, but with an additional DSI RX block that takes in DSI video mode output.

Trying to get this driver merged has had some challenges:

- ADV7533 has an I2C control bus, but acts as a DSI peripheral too. After discussions, it was concluded that we'd want to provide an API to create MIPI DSI devices, rather than expose two different interfaces on DT. The first version [1] tried the former approach the second version [2] showed how the driver would look like if exposed 2 DT nodes. This lateset patchset relies on the MIPI DSI device creation API provided by [3], this has been accepted and should be merged for 4.6.

- The driver was designed as an I2C slave encoder. When ADV7533 patches were posted [1], it was modelled as a bridge, but ADV7511 and others were still left as I2C slave encoders. This wasn't accepted. After discussions, it was decided that ADV7511 too would be converted into a bridge driver, and all the users of ADV7511 should assume it is a bridge. This bridge conversion was done in [4]. There is still some debate over whether the bridge driver be involved in the connector creation, or the KMS driver that has the whole view of the display pipeline. This discussion shouldn't affect this patch set, though.

This patch set enables ADV7533 support with the above two issues now resolved. It also incorporates ADV7533 specific features and fixes that we've discovered since the first version of this patch was posted.

Changes in v4:
- Separated out build for ADV7533. The original plan was to stub out the drm_mipi_dsi funcs, but that seemed like an overkill since it helped just this driver. It seems better to stub out the ADV7533 functionality altogether instead.
- Some minor DT binding corrections suggested by Laurent.

[4]
https://lists.freedesktop.org/archives/dri-devel/2016-January/098287.html

[3]
https://lkml.org/lkml/2016/2/12/67

[2]
https://lists.freedesktop.org/archives/dri-devel/2015-September/089884.html

[1]:
https://lists.freedesktop.org/archives/dri-devel/2015-July/087088.html

Archit Taneja (7):
drm/i2c: adv7511: Convert to drm_bridge
drm/i2c: adv7511: Fix mutex deadlock when interrupts are disabled drm/i2c: adv7511: Initial support for ADV7533
drm/i2c: adv7533: Create a MIPI DSI device
drm/i2c: adv7533: Use internal timing generator drm/i2c: adv7533: Change number of DSI lanes dynamically
dt-bindings: drm/bridge: Update bindings for ADV7533

 .../bindings/display/bridge/adi,adv7511.txt        |  26 +-
 drivers/gpu/drm/i2c/Kconfig                        |   8 +
 drivers/gpu/drm/i2c/Makefile                       |   4 +-
 drivers/gpu/drm/i2c/adv7511.c                      | 333 ++++++++++++++-------
 drivers/gpu/drm/i2c/adv7511.h                      |  95 ++++++
 drivers/gpu/drm/i2c/adv7533.c                      | 265 ++++++++++++++++
 6 files changed, 613 insertions(+), 118 deletions(-)
 create mode 100644 drivers/gpu/drm/i2c/adv7533.c
Signature · 7 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
#67 lore raw

PATCH v4 1/7 drm/i2c: adv7511: Convert to drm_bridge

We don't want to use the old i2c slave encoder interface anymore.

Remove that and make the i2c driver create a drm_bridge entity instead. Converting to bridges helps because the kms drivers don't need to exract encoder slave ops from this driver and use it within their own encoder/connector ops.

The driver now creates its own connector when a kms driver attaches itself to the bridge. Therefore, kms drivers don't need to create their own connectors anymore.

The old encoder slave ops are now used by the new bridge and connector entities.

---
 drivers/gpu/drm/i2c/adv7511.c | 222 ++++++++++++++++++++++++++++--------------
 1 file changed, 148 insertions(+), 74 deletions(-)
drivers/gpu/drm/i2c/adv7511.c +148 -74
index a02112b..fec5627 100644
@@ -14,9 +14,10 @@
 #include <linux/slab.h>
 
 #include <drm/drmP.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_edid.h>
-#include <drm/drm_encoder_slave.h>
 
 #include "adv7511.h"
 
@@ -36,7 +37,8 @@ struct adv7511 {
 	bool edid_read;
 
 	wait_queue_head_t wq;
-	struct drm_encoder *encoder;
+	struct drm_bridge bridge;
+	struct drm_connector connector;
 
 	bool embedded_sync;
 	enum adv7511_sync_polarity vsync_polarity;
@@ -48,11 +50,6 @@ struct adv7511 {
 	struct gpio_desc *gpio_pd;
 };
 
-static struct adv7511 *encoder_to_adv7511(struct drm_encoder *encoder)
-{
-	return to_encoder_slave(encoder)->slave_priv;
-}
-
 /* ADI recommended values for proper operation. */
 static const struct reg_sequence adv7511_fixed_registers[] = {
 	{ 0x98, 0x03 },
@@ -446,8 +443,8 @@ static int adv7511_irq_process(struct adv7511 *adv7511)
 	regmap_write(adv7511->regmap, ADV7511_REG_INT(0), irq0);
 	regmap_write(adv7511->regmap, ADV7511_REG_INT(1), irq1);
 
-	if (irq0 & ADV7511_INT0_HPD && adv7511->encoder)
-		drm_helper_hpd_irq_event(adv7511->encoder->dev);
+	if (irq0 & ADV7511_INT0_HPD && adv7511->bridge.encoder)
+		drm_helper_hpd_irq_event(adv7511->connector.dev);
 
 	if (irq0 & ADV7511_INT0_EDID_READY || irq1 & ADV7511_INT1_DDC_ERROR) {
 		adv7511->edid_read = true;
@@ -563,13 +560,12 @@ static int adv7511_get_edid_block(void *data, u8 *buf, unsigned int block,
 }
 
 /* -----------------------------------------------------------------------------
- * Encoder operations
+ * ADV75xx helpers
  */
 
-static int adv7511_get_modes(struct drm_encoder *encoder,
+static int adv7511_get_modes(struct adv7511 *adv7511,
 			     struct drm_connector *connector)
 {
-	struct adv7511 *adv7511 = encoder_to_adv7511(encoder);
 	struct edid *edid;
 	unsigned int count;
 
@@ -606,21 +602,9 @@ static int adv7511_get_modes(struct drm_encoder *encoder,
 	return count;
 }
 
-static void adv7511_encoder_dpms(struct drm_encoder *encoder, int mode)
-{
-	struct adv7511 *adv7511 = encoder_to_adv7511(encoder);
-
-	if (mode == DRM_MODE_DPMS_ON)
-		adv7511_power_on(adv7511);
-	else
-		adv7511_power_off(adv7511);
-}
-
 static enum drm_connector_status
-adv7511_encoder_detect(struct drm_encoder *encoder,
-		       struct drm_connector *connector)
+adv7511_detect(struct adv7511 *adv7511, struct drm_connector *connector)
 {
-	struct adv7511 *adv7511 = encoder_to_adv7511(encoder);
 	enum drm_connector_status status;
 	unsigned int val;
 	bool hpd;
@@ -644,7 +628,7 @@ adv7511_encoder_detect(struct drm_encoder *encoder,
 	if (status == connector_status_connected && hpd && adv7511->powered) {
 		regcache_mark_dirty(adv7511->regmap);
 		adv7511_power_on(adv7511);
-		adv7511_get_modes(encoder, connector);
+		adv7511_get_modes(adv7511, connector);
 		if (adv7511->status == connector_status_connected)
 			status = connector_status_disconnected;
 	} else {
@@ -658,8 +642,8 @@ adv7511_encoder_detect(struct drm_encoder *encoder,
 	return status;
 }
 
-static int adv7511_encoder_mode_valid(struct drm_encoder *encoder,
-				      struct drm_display_mode *mode)
+static int adv7511_mode_valid(struct adv7511 *adv7511,
+			      struct drm_display_mode *mode)
 {
 	if (mode->clock > 165000)
 		return MODE_CLOCK_HIGH;
@@ -667,11 +651,10 @@ static int adv7511_encoder_mode_valid(struct drm_encoder *encoder,
 	return MODE_OK;
 }
 
-static void adv7511_encoder_mode_set(struct drm_encoder *encoder,
-				     struct drm_display_mode *mode,
-				     struct drm_display_mode *adj_mode)
+static void adv7511_mode_set(struct adv7511 *adv7511,
+			     struct drm_display_mode *mode,
+			     struct drm_display_mode *adj_mode)
 {
-	struct adv7511 *adv7511 = encoder_to_adv7511(encoder);
 	unsigned int low_refresh_rate;
 	unsigned int hsync_polarity = 0;
 	unsigned int vsync_polarity = 0;
@@ -762,12 +745,120 @@ static void adv7511_encoder_mode_set(struct drm_encoder *encoder,
 	adv7511->f_tmds = mode->clock;
 }
 
-static const struct drm_encoder_slave_funcs adv7511_encoder_funcs = {
-	.dpms = adv7511_encoder_dpms,
-	.mode_valid = adv7511_encoder_mode_valid,
-	.mode_set = adv7511_encoder_mode_set,
-	.detect = adv7511_encoder_detect,
-	.get_modes = adv7511_get_modes,
+/* Connector funcs */
+static struct adv7511 *connector_to_adv7511(struct drm_connector *connector)
+{
+	return container_of(connector, struct adv7511, connector);
+}
+
+static int adv7511_connector_get_modes(struct drm_connector *connector)
+{
+	struct adv7511 *adv = connector_to_adv7511(connector);
+
+	return adv7511_get_modes(adv, connector);
+}
+
+static struct drm_encoder *
+adv7511_connector_best_encoder(struct drm_connector *connector)
+{
+	struct adv7511 *adv = connector_to_adv7511(connector);
+
+	return adv->bridge.encoder;
+}
+
+static enum drm_mode_status
+adv7511_connector_mode_valid(struct drm_connector *connector,
+			     struct drm_display_mode *mode)
+{
+	struct adv7511 *adv = connector_to_adv7511(connector);
+
+	return adv7511_mode_valid(adv, mode);
+}
+
+static struct drm_connector_helper_funcs adv7511_connector_helper_funcs = {
+	.get_modes = adv7511_connector_get_modes,
+	.best_encoder = adv7511_connector_best_encoder,
+	.mode_valid = adv7511_connector_mode_valid,
+};
+
+static enum drm_connector_status
+adv7511_connector_detect(struct drm_connector *connector, bool force)
+{
+	struct adv7511 *adv = connector_to_adv7511(connector);
+
+	return adv7511_detect(adv, connector);
+}
+
+static struct drm_connector_funcs adv7511_connector_funcs = {
+	.dpms = drm_atomic_helper_connector_dpms,
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.detect = adv7511_connector_detect,
+	.destroy = drm_connector_cleanup,
+	.reset = drm_atomic_helper_connector_reset,
+	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+/* Bridge funcs */
+static struct adv7511 *bridge_to_adv7511(struct drm_bridge *bridge)
+{
+	return container_of(bridge, struct adv7511, bridge);
+}
+
+static void adv7511_bridge_enable(struct drm_bridge *bridge)
+{
+	struct adv7511 *adv = bridge_to_adv7511(bridge);
+
+	adv7511_power_on(adv);
+}
+
+static void adv7511_bridge_disable(struct drm_bridge *bridge)
+{
+	struct adv7511 *adv = bridge_to_adv7511(bridge);
+
+	adv7511_power_off(adv);
+}
+
+static void adv7511_bridge_mode_set(struct drm_bridge *bridge,
+				    struct drm_display_mode *mode,
+				    struct drm_display_mode *adj_mode)
+{
+	struct adv7511 *adv = bridge_to_adv7511(bridge);
+
+	adv7511_mode_set(adv, mode, adj_mode);
+}
+
+static int adv7511_bridge_attach(struct drm_bridge *bridge)
+{
+	struct adv7511 *adv = bridge_to_adv7511(bridge);
+	int ret;
+
+	if (!bridge->encoder) {
+		DRM_ERROR("Parent encoder object not found");
+		return -ENODEV;
+	}
+
+	adv->connector.polled = DRM_CONNECTOR_POLL_HPD;
+
+	ret = drm_connector_init(bridge->dev, &adv->connector,
+				 &adv7511_connector_funcs,
+				 DRM_MODE_CONNECTOR_HDMIA);
+	if (ret) {
+		DRM_ERROR("Failed to initialize connector with drm\n");
+		return ret;
+	}
+	drm_connector_helper_add(&adv->connector,
+				 &adv7511_connector_helper_funcs);
+	drm_mode_connector_attach_encoder(&adv->connector, bridge->encoder);
+
+	return ret;
+}
+
+static struct drm_bridge_funcs adv7511_bridge_funcs = {
+	.enable = adv7511_bridge_enable,
+	.disable = adv7511_bridge_disable,
+	.mode_set = adv7511_bridge_mode_set,
+	.attach = adv7511_bridge_attach,
 };
 
 /* -----------------------------------------------------------------------------
@@ -944,6 +1035,15 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
 
 	adv7511_set_link_config(adv7511, &link_config);
 
+	adv7511->bridge.funcs = &adv7511_bridge_funcs;
+	adv7511->bridge.of_node = dev->of_node;
+
+	ret = drm_bridge_add(&adv7511->bridge);
+	if (ret) {
+		dev_err(dev, "failed to add adv7511 bridge\n");
+		goto err_i2c_unregister_device;
+	}
+
 	return 0;
 
 err_i2c_unregister_device:
@@ -956,6 +1056,8 @@ static int adv7511_remove(struct i2c_client *i2c)
 {
 	struct adv7511 *adv7511 = i2c_get_clientdata(i2c);
 
+	drm_bridge_remove(&adv7511->bridge);
+
 	i2c_unregister_device(adv7511->i2c_edid);
 
 	kfree(adv7511->edid);
@@ -963,20 +1065,6 @@ static int adv7511_remove(struct i2c_client *i2c)
 	return 0;
 }
 
-static int adv7511_encoder_init(struct i2c_client *i2c, struct drm_device *dev,
-				struct drm_encoder_slave *encoder)
-{
-
-	struct adv7511 *adv7511 = i2c_get_clientdata(i2c);
-
-	encoder->slave_priv = adv7511;
-	encoder->slave_funcs = &adv7511_encoder_funcs;
-
-	adv7511->encoder = &encoder->base;
-
-	return 0;
-}
-
 static const struct i2c_device_id adv7511_i2c_ids[] = {
 	{ "adv7511", 0 },
 	{ "adv7511w", 0 },
@@ -993,31 +1081,17 @@ static const struct of_device_id adv7511_of_ids[] = {
 };
 MODULE_DEVICE_TABLE(of, adv7511_of_ids);
 
-static struct drm_i2c_encoder_driver adv7511_driver = {
-	.i2c_driver = {
-		.driver = {
-			.name = "adv7511",
-			.of_match_table = adv7511_of_ids,
-		},
-		.id_table = adv7511_i2c_ids,
-		.probe = adv7511_probe,
-		.remove = adv7511_remove,
+static struct i2c_driver adv7511_driver = {
+	.driver = {
+		.name = "adv7511",
+		.of_match_table = adv7511_of_ids,
 	},
-
-	.encoder_init = adv7511_encoder_init,
+	.id_table = adv7511_i2c_ids,
+	.probe = adv7511_probe,
+	.remove = adv7511_remove,
 };
 
-static int __init adv7511_init(void)
-{
-	return drm_i2c_encoder_register(THIS_MODULE, &adv7511_driver);
-}
-module_init(adv7511_init);
-
-static void __exit adv7511_exit(void)
-{
-	drm_i2c_encoder_unregister(&adv7511_driver);
-}
-module_exit(adv7511_exit);
+module_i2c_driver(adv7511_driver);
 
 MODULE_AUTHOR("Lars-Peter Clausen <[email protected]>");
 MODULE_DESCRIPTION("ADV7511 HDMI transmitter driver");
Signature · 7 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
#68 lore raw

PATCH v4 2/7 drm/i2c: adv7511: Fix mutex deadlock when interrupts are disabled

In reply to Archit Taneja

When the adv7511 i2c client doesn't have an interrupt line, we observe a deadlock on caused by trying to lock drm device's mode_config.mutex twice in the same context.

Here is the sequence that causes it:

ioctl DRM_IOCTL_MODE_GETCONNECTOR from userspace
drm_mode_getconnector (acquires mode_config mutex)

    connector->fill_modes()
    drm_helper_probe_single_connector_modes
      connector_funcs->get_modes
	adv7511_encoder_get_modes
	  adv7511_get_edid_block
	    adv7511_irq_process
	      drm_helper_hpd_irq_event (acquires mode_config mutex again)

In adv7511_irq_process, don't call drm_helper_hpd_irq_event when not called from the interrupt handler. It doesn't serve any purpose there anyway.

---
 drivers/gpu/drm/i2c/adv7511.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/gpu/drm/i2c/adv7511.c +4 -4
index fec5627..c00d11d 100644
@@ -427,7 +427,7 @@ static bool adv7511_hpd(struct adv7511 *adv7511)
 	return false;
 }
 
-static int adv7511_irq_process(struct adv7511 *adv7511)
+static int adv7511_irq_process(struct adv7511 *adv7511, bool process_hpd)
 {
 	unsigned int irq0, irq1;
 	int ret;
@@ -443,7 +443,7 @@ static int adv7511_irq_process(struct adv7511 *adv7511)
 	regmap_write(adv7511->regmap, ADV7511_REG_INT(0), irq0);
 	regmap_write(adv7511->regmap, ADV7511_REG_INT(1), irq1);
 
-	if (irq0 & ADV7511_INT0_HPD && adv7511->bridge.encoder)
+	if (process_hpd && irq0 & ADV7511_INT0_HPD && adv7511->bridge.encoder)
 		drm_helper_hpd_irq_event(adv7511->connector.dev);
 
 	if (irq0 & ADV7511_INT0_EDID_READY || irq1 & ADV7511_INT1_DDC_ERROR) {
@@ -461,7 +461,7 @@ static irqreturn_t adv7511_irq_handler(int irq, void *devid)
 	struct adv7511 *adv7511 = devid;
 	int ret;
 
-	ret = adv7511_irq_process(adv7511);
+	ret = adv7511_irq_process(adv7511, true);
 	return ret < 0 ? IRQ_NONE : IRQ_HANDLED;
 }
 
@@ -478,7 +478,7 @@ static int adv7511_wait_for_edid(struct adv7511 *adv7511, int timeout)
 				adv7511->edid_read, msecs_to_jiffies(timeout));
 	} else {
 		for (; timeout > 0; timeout -= 25) {
-			ret = adv7511_irq_process(adv7511);
+			ret = adv7511_irq_process(adv7511, false);
 			if (ret < 0)
 				break;
 
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
#69 lore raw

PATCH v4 3/7 drm/i2c: adv7511: Initial support for ADV7533

In reply to Archit Taneja

ADV7533 is a DSI to HDMI encoder chip. It is a derivative of ADV7511, with additional blocks to translate input DSI data to parallel RGB data. Besides the ADV7511 I2C register map, it has additional registers that require to be configured to activate the DSI Rx block.

Create a new config that enables ADV7533 support. Use DT compatible strings to populate the ADV7533 type enum. Add minimal register configurations belonging to the DSI/CEC register map. Keep the ADV7533 code in a separate file.

Originally worked on by Lars-Peter Clausen <[email protected]>

---
 drivers/gpu/drm/i2c/Kconfig   |   7 +++
 drivers/gpu/drm/i2c/Makefile  |   4 +-
 drivers/gpu/drm/i2c/adv7511.c | 100 +++++++++++++++++++++---------------------
 drivers/gpu/drm/i2c/adv7511.h |  67 ++++++++++++++++++++++++++++
 drivers/gpu/drm/i2c/adv7533.c | 100 ++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 228 insertions(+), 50 deletions(-)
 create mode 100644 drivers/gpu/drm/i2c/adv7533.c
drivers/gpu/drm/i2c/Kconfig +7 -0
index 22c7ed6..03c5528 100644
@@ -7,6 +7,13 @@ config DRM_I2C_ADV7511
 	help
 	  Support for the Analog Device ADV7511(W) and ADV7513 HDMI encoders.
 
+config DRM_I2C_ADV7533
+	bool "ADV7533 encoder"
+	depends on DRM_I2C_ADV7511
+	default y
+	help
+	  Support for the Analog Devices ADV7533 DSI to HDMI encoder.
+
 config DRM_I2C_CH7006
 	tristate "Chrontel ch7006 TV encoder"
 	default m if DRM_NOUVEAU
drivers/gpu/drm/i2c/Makefile +3 -1
index 2c72eb5..cd2c22c 100644
@@ -1,6 +1,8 @@
 ccflags-y := -Iinclude/drm
 
-obj-$(CONFIG_DRM_I2C_ADV7511) += adv7511.o
+adv75xx-y := adv7511.o
+adv75xx-$(CONFIG_DRM_I2C_ADV7533) += adv7533.o
+obj-$(CONFIG_DRM_I2C_ADV7511) += adv75xx.o
 
 ch7006-y := ch7006_drv.o ch7006_mode.o
 obj-$(CONFIG_DRM_I2C_CH7006) += ch7006.o
drivers/gpu/drm/i2c/adv7511.c +51 -49

191 lines not on this page · raw message

drivers/gpu/drm/i2c/adv7511.h +67 -0

77 lines not on this page · raw message

drivers/gpu/drm/i2c/adv7533.c new file +100 -0

100 lines not on this page · raw message

Signature · 7 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
#70 lore raw

PATCH v4 4/7 drm/i2c: adv7533: Create a MIPI DSI device

In reply to Archit Taneja

In order to pass DSI specific parameters to the DSI host, we need the driver to create a mipi_dsi_device DSI device that attaches to the host.

Use of_graph helpers to get the DSI host DT node. Create a MIPI DSI device using this host. Finally, attach this device to the DSI host.

Populate DT parameters (number of data lanes for now) that are required for DSI RX to work correctly. Hardcode few other parameters (rgb, embedded_sync) for now.

Select DRM_MIPI_DSI config option only when ADV7533 support is enabled.

---
 drivers/gpu/drm/i2c/Kconfig   |  1 +
 drivers/gpu/drm/i2c/adv7511.c | 40 ++++++++++++++++---
 drivers/gpu/drm/i2c/adv7511.h | 20 ++++++++++
 drivers/gpu/drm/i2c/adv7533.c | 91 ++++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 144 insertions(+), 8 deletions(-)
drivers/gpu/drm/i2c/Kconfig +1 -0
index 03c5528..f7cd9e5 100644
@@ -10,6 +10,7 @@ config DRM_I2C_ADV7511
 config DRM_I2C_ADV7533
 	bool "ADV7533 encoder"
 	depends on DRM_I2C_ADV7511
+	select DRM_MIPI_DSI
 	default y
 	help
 	  Support for the Analog Devices ADV7533 DSI to HDMI encoder.
drivers/gpu/drm/i2c/adv7511.c +34 -6
index 9deb4fd..42bd674 100644
@@ -826,6 +826,9 @@ static int adv7511_bridge_attach(struct drm_bridge *bridge)
 				 &adv7511_connector_helper_funcs);
 	drm_mode_connector_attach_encoder(&adv->connector, bridge->encoder);
 
+	if (adv->type == ADV7533)
+		ret = adv7533_attach_dsi(adv);
+
 	return ret;
 }
 
@@ -952,11 +955,12 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
 
 	memset(&link_config, 0, sizeof(link_config));
 
-	if (adv7511->type == ADV7511) {
+	if (adv7511->type == ADV7511)
 		ret = adv7511_parse_dt(dev->of_node, &link_config);
-		if (ret)
-			return ret;
-	}
+	else
+		ret = adv7533_parse_dt(dev->of_node, adv7511);
+	if (ret)
+		return ret;
 
 	/*
 	 * The power down GPIO is optional. If present, toggle it from active to
@@ -1051,9 +1055,13 @@ static int adv7511_remove(struct i2c_client *i2c)
 {
 	struct adv7511 *adv7511 = i2c_get_clientdata(i2c);
 
+	if (adv7511->type == ADV7533) {
+		adv7533_detach_dsi(adv7511);
+		adv7533_uninit_cec(adv7511);
+	}
+
 	drm_bridge_remove(&adv7511->bridge);
 
-	adv7533_uninit_cec(adv7511);
 	i2c_unregister_device(adv7511->i2c_edid);
 
 	kfree(adv7511->edid);
@@ -1083,6 +1091,10 @@ static const struct of_device_id adv7511_of_ids[] = {
 };
 MODULE_DEVICE_TABLE(of, adv7511_of_ids);
 
+static struct mipi_dsi_driver adv7533_dsi_driver = {
+	.driver.name = "adv7533",
+};
+
 static struct i2c_driver adv7511_driver = {
 	.driver = {
 		.name = "adv7511",
@@ -1093,7 +1105,23 @@ static struct i2c_driver adv7511_driver = {
 	.remove = adv7511_remove,
 };
 
-module_i2c_driver(adv7511_driver);
+static int __init adv7511_init(void)
+{
+	if (IS_ENABLED(CONFIG_DRM_MIPI_DSI))
+		mipi_dsi_driver_register(&adv7533_dsi_driver);
+
+	return i2c_add_driver(&adv7511_driver);
+}
+module_init(adv7511_init);
+
+static void __exit adv7511_exit(void)
+{
+	i2c_del_driver(&adv7511_driver);
+
+	if (IS_ENABLED(CONFIG_DRM_MIPI_DSI))
+		mipi_dsi_driver_unregister(&adv7533_dsi_driver);
+}
+module_exit(adv7511_exit);
 
 MODULE_AUTHOR("Lars-Peter Clausen <[email protected]>");
 MODULE_DESCRIPTION("ADV7511 HDMI transmitter driver");
drivers/gpu/drm/i2c/adv7511.h +20 -0
index 541c5d7..056f747 100644
@@ -14,6 +14,7 @@
 #include <linux/regmap.h>
 
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_mipi_dsi.h>
 
 #define ADV7511_REG_CHIP_REVISION		0x00
 #define ADV7511_REG_N0				0x01
@@ -324,6 +325,11 @@ struct adv7511 {
 
 	struct gpio_desc *gpio_pd;
 
+	/* ADV7533 DSI RX related params */
+	struct device_node *host_node;
+	struct mipi_dsi_device *dsi;
+	u8 num_dsi_lanes;
+
 	enum adv7511_type type;
 };
 
@@ -333,6 +339,9 @@ void adv7533_dsi_power_off(struct adv7511 *adv);
 int adv7533_patch_registers(struct adv7511 *adv);
 void adv7533_uninit_cec(struct adv7511 *adv);
 int adv7533_init_cec(struct adv7511 *adv);
+int adv7533_attach_dsi(struct adv7511 *adv);
+void adv7533_detach_dsi(struct adv7511 *adv);
+int adv7533_parse_dt(struct device_node *np, struct adv7511 *adv);
 #else
 static inline void adv7533_dsi_power_on(struct adv7511 *adv)
 {
@@ -351,6 +360,17 @@ static inline int adv7533_init_cec(struct adv7511 *adv)
 {
 	return -ENODEV;
 }
+static inline int adv7533_attach_dsi(struct adv7511 *adv)
+{
+	return -ENODEV;
+}
+static inline void adv7533_detach_dsi(struct adv7511 *adv)
+{
+}
+static inline int adv7533_parse_dt(struct device_node *np, struct adv7511 *adv)
+{
+	return -ENODEV;
+}
 #endif
 
 #endif /* __DRM_I2C_ADV7511_H__ */
drivers/gpu/drm/i2c/adv7533.c +89 -2

106 lines not on this page · raw message

Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
#71 lore raw

PATCH v4 5/7 drm/i2c: adv7533: Use internal timing generator

In reply to Archit Taneja

ADV7533 provides an internal timing generator for certain modes that it can't use the DSI clock directly.

We've observed that HDMI is more stable with the internal timing generator, especially if there are instabilities in the DSI clock source. The data spec also seems to recommend the usage of the timing generator for all modes.

However, on some platforms, it's reported that enabling the timing generator causes instabilities with the HDMI output.

Create a DT parameter that lets a platform explicitly disable the timing generator. The timing generator is enabled by default.

---
 drivers/gpu/drm/i2c/adv7511.c |  2 ++
 drivers/gpu/drm/i2c/adv7511.h |  3 +++
 drivers/gpu/drm/i2c/adv7533.c | 60 +++++++++++++++++++++++++++++++++++++++++--
 3 files changed, 63 insertions(+), 2 deletions(-)
drivers/gpu/drm/i2c/adv7511.c +2 -0
index 42bd674..61c751f 100644
@@ -712,6 +712,8 @@ static void adv7511_mode_set(struct adv7511 *adv7511,
 	regmap_update_bits(adv7511->regmap, 0x17,
 		0x60, (vsync_polarity << 6) | (hsync_polarity << 5));
 
+	drm_mode_copy(&adv7511->curr_mode, adj_mode);
+
 	/*
 	 * TODO Test first order 4:2:2 to 4:4:4 up conversion method, which is
 	 * supposed to give better results.
drivers/gpu/drm/i2c/adv7511.h +3 -0
index 056f747..a9745ea 100644
@@ -306,6 +306,8 @@ struct adv7511 {
 	enum drm_connector_status status;
 	bool powered;
 
+	struct drm_display_mode curr_mode;
+
 	unsigned int f_tmds;
 
 	unsigned int current_edid_segment;
@@ -329,6 +331,7 @@ struct adv7511 {
 	struct device_node *host_node;
 	struct mipi_dsi_device *dsi;
 	u8 num_dsi_lanes;
+	bool use_timing_gen;
 
 	enum adv7511_type type;
 };
drivers/gpu/drm/i2c/adv7533.c +58 -2

84 lines not on this page · raw message

Signature · 7 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
#72 lore raw

PATCH v4 6/7 drm/i2c: adv7533: Change number of DSI lanes dynamically

In reply to Archit Taneja

Lower modes on ADV7533 require lower number of DSI lanes for correct operation. If ADV7533 is being used with 4 DSI lanes, then switch the lanes to 3 when the target mode's pixel clock is less than 80 Mhz.

Based on patch by Andy Green <[email protected]>

---
 drivers/gpu/drm/i2c/adv7511.c |  3 +++
 drivers/gpu/drm/i2c/adv7511.h |  5 +++++
 drivers/gpu/drm/i2c/adv7533.c | 22 ++++++++++++++++++++++
 3 files changed, 30 insertions(+)
drivers/gpu/drm/i2c/adv7511.c +3 -0
index 61c751f..5dfca1a 100644
@@ -712,6 +712,9 @@ static void adv7511_mode_set(struct adv7511 *adv7511,
 	regmap_update_bits(adv7511->regmap, 0x17,
 		0x60, (vsync_polarity << 6) | (hsync_polarity << 5));
 
+	if (adv7511->type == ADV7533)
+		adv7533_mode_set(adv7511, adj_mode);
+
 	drm_mode_copy(&adv7511->curr_mode, adj_mode);
 
 	/*
drivers/gpu/drm/i2c/adv7511.h +5 -0
index a9745ea..b113b77 100644
@@ -339,6 +339,7 @@ struct adv7511 {
 #ifdef CONFIG_DRM_I2C_ADV7533
 void adv7533_dsi_power_on(struct adv7511 *adv);
 void adv7533_dsi_power_off(struct adv7511 *adv);
+void adv7533_mode_set(struct adv7511 *adv, struct drm_display_mode *mode);
 int adv7533_patch_registers(struct adv7511 *adv);
 void adv7533_uninit_cec(struct adv7511 *adv);
 int adv7533_init_cec(struct adv7511 *adv);
@@ -352,6 +353,10 @@ static inline void adv7533_dsi_power_on(struct adv7511 *adv)
 static inline void adv7533_dsi_power_off(struct adv7511 *adv)
 {
 }
+static inline void adv7533_mode_set(struct adv7511 *adv,
+				    struct drm_display_mode *mode)
+{
+}
 static inline int adv7533_patch_registers(struct adv7511 *adv)
 {
 	return -ENODEV;
drivers/gpu/drm/i2c/adv7533.c +22 -0
index d002ac4..5eebd15 100644
@@ -115,6 +115,28 @@ void adv7533_dsi_power_off(struct adv7511 *adv)
 	regmap_write(adv->regmap_cec, 0x27, 0x0b);
 }
 
+void adv7533_mode_set(struct adv7511 *adv, struct drm_display_mode *mode)
+{
+	struct mipi_dsi_device *dsi = adv->dsi;
+	int lanes, ret;
+
+	if (adv->num_dsi_lanes != 4)
+		return;
+
+	if (mode->clock > 80000)
+		lanes = 4;
+	else
+		lanes = 3;
+
+	if (lanes != dsi->lanes) {
+		mipi_dsi_detach(dsi);
+		dsi->lanes = lanes;
+		ret = mipi_dsi_attach(dsi);
+		if (ret)
+			dev_err(&dsi->dev, "failed to change host lanes\n");
+	}
+}
+
 int adv7533_patch_registers(struct adv7511 *adv)
 {
 	return regmap_register_patch(adv->regmap,
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
#73 lore raw

PATCH v4 7/7 dt-bindings: drm/bridge: Update bindings for ADV7533

In reply to Archit Taneja

Add description of ADV7533. Add the required and optional properties that are specific to it.

---
 .../bindings/display/bridge/adi,adv7511.txt        | 26 +++++++++++++++++-----
 1 file changed, 21 insertions(+), 5 deletions(-)
Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt +21 -5
index 96c25ee..6532a59 100644
@@ -1,13 +1,19 @@
-Analog Device ADV7511(W)/13 HDMI Encoders
+Analog Device ADV7511(W)/13/33 HDMI Encoders
 -----------------------------------------
 
-The ADV7511, ADV7511W and ADV7513 are HDMI audio and video transmitters
+The ADV7511, ADV7511W, ADV7513 and ADV7533 are HDMI audio and video transmitters
 compatible with HDMI 1.4 and DVI 1.0. They support color space conversion,
-S/PDIF, CEC and HDCP.
+S/PDIF, CEC and HDCP. ADV7533 supports the DSI interface for input pixels, while
+the others support RGB interface.
 
 Required properties:
 
-- compatible: Should be one of "adi,adv7511", "adi,adv7511w" or "adi,adv7513"
+- compatible: Should be one of:
+		"adi,adv7511"
+		"adi,adv7511w"
+		"adi,adv7513"
+		"adi,adv7533"
+
 - reg: I2C slave address
 
 The ADV7511 supports a large number of input data formats that differ by their
@@ -32,6 +38,11 @@ The following input format properties are required except in "rgb 1x" and
 - adi,input-justification: The input bit justification ("left", "evenly",
   "right").
 
+The following properties are required for ADV7533:
+
+- adi,dsi-lanes: Number of DSI data lanes connected to the DSI host. It should
+  be one of 1, 2, 3 or 4.
+
 Optional properties:
 
 - interrupts: Specifier for the ADV7511 interrupt
@@ -42,13 +53,18 @@ Optional properties:
 - adi,embedded-sync: The input uses synchronization signals embedded in the
   data stream (similar to BT.656). Defaults to separate H/V synchronization
   signals.
+- adi,disable-timing-generator: Only for ADV7533. Disables the internal timing
+  generator. The chip will rely on the sync signals in the DSI data lanes,
+  rather than generate its own timings for HDMI output.
 
 Required nodes:
 
 The ADV7511 has two video ports. Their connections are modelled using the OF
 graph bindings specified in Documentation/devicetree/bindings/graph.txt.
 
-- Video port 0 for the RGB or YUV input
+- Video port 0 for the RGB, YUV or DSI input. In the case of ADV7533, the
+  remote endpoint phandle should be a reference to a valid mipi_dsi_host device
+  node.
 - Video port 1 for the HDMI output
 
 
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
#74 lore raw

v5 cover drm/i2c: adv7511: ADV7533 support

In reply to Archit Taneja

ADV7533 is a DSI to HDMI encoder chip. It's like ADV7511, but with an additional DSI RX block that takes in DSI video mode output.

Trying to get this driver merged has had some challenges:

- ADV7533 has an I2C control bus, but acts as a DSI peripheral too. After discussions, it was concluded that we'd want to provide an API to create MIPI DSI devices, rather than expose two different interfaces on DT. The first version [1] tried the former approach the second version [2] showed how the driver would look like if exposed 2 DT nodes. This lateset patchset relies on the MIPI DSI device creation API provided by [3], this has been accepted and should be merged for 4.6.

- The driver was designed as an I2C slave encoder. When ADV7533 patches were posted [1], it was modelled as a bridge, but ADV7511 and others were still left as I2C slave encoders. This wasn't accepted. After discussions, it was decided that ADV7511 too would be converted into a bridge driver, and all the users of ADV7511 should assume it is a bridge. This bridge conversion was done in [4]. There is still some debate over whether the bridge driver be involved in the connector creation, or the KMS driver that has the whole view of the display pipeline. This discussion shouldn't affect this patch set, though.

This patch set enables ADV7533 support with the above two issues now resolved. It also incorporates ADV7533 specific features and fixes that we've discovered since the first version of this patch was posted.

If this looks okay, I request that it gets pulled in 4.8. This patchset has been floating around since July last year.

Changes in v5:
- Fix break observed when built for x86.
- Based off current drm-misc.
- Removes best_encoder connector helper function since it isn't needed after this series:
https://lkml.org/lkml/2016/6/2/508

Changes in v4:
- Separated out build for ADV7533. The original plan was to stub out the drm_mipi_dsi funcs, but that seemed like an overkill since it helped just this driver. It seems better to stub out the ADV7533 functionality altogether instead.
- Some minor DT binding corrections suggested by Laurent.

[4]
https://lists.freedesktop.org/archives/dri-devel/2016-January/098287.html

[3]
https://lkml.org/lkml/2016/2/12/67

[2]
https://lists.freedesktop.org/archives/dri-devel/2015-September/089884.html

[1]:
https://lists.freedesktop.org/archives/dri-devel/2015-July/087088.html

Archit Taneja (7):
drm/i2c: adv7511: Convert to drm_bridge
drm/i2c: adv7511: Fix mutex deadlock when interrupts are disabled drm/i2c: adv7511: Initial support for ADV7533
drm/i2c: adv7533: Create a MIPI DSI device
drm/i2c: adv7533: Use internal timing generator drm/i2c: adv7533: Change number of DSI lanes dynamically
dt-bindings: drm/bridge: Update bindings for ADV7533

 .../bindings/display/bridge/adi,adv7511.txt        |  26 +-
 drivers/gpu/drm/i2c/Kconfig                        |   9 +
 drivers/gpu/drm/i2c/Makefile                       |   4 +-
 drivers/gpu/drm/i2c/adv7511.c                      | 324 ++++++++++++++-------
 drivers/gpu/drm/i2c/adv7511.h                      |  95 ++++++
 drivers/gpu/drm/i2c/adv7533.c                      | 265 +++++++++++++++++
 6 files changed, 605 insertions(+), 118 deletions(-)
 create mode 100644 drivers/gpu/drm/i2c/adv7533.c
Signature · 7 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
#75 lore raw

PATCH v5 1/7 drm/i2c: adv7511: Convert to drm_bridge

We don't want to use the old i2c slave encoder interface anymore.

Remove that and make the i2c driver create a drm_bridge entity instead. Converting to bridges helps because the kms drivers don't need to exract encoder slave ops from this driver and use it within their own encoder/connector ops.

The driver now creates its own connector when a kms driver attaches itself to the bridge. Therefore, kms drivers don't need to create their own connectors anymore.

The old encoder slave ops are now used by the new bridge and connector entities.

The of_node member in drm_bridge is accessible only when CONFIG_OF is enabled. The driver anyway only works only when OF is available. Make the driver depend on OF in its Kconfig.

---
Changes in v5:
- Make the driver depend on CONFIG_OF
- Remove best_encoder connector helper

 drivers/gpu/drm/i2c/Kconfig   |   1 +
 drivers/gpu/drm/i2c/adv7511.c | 213 +++++++++++++++++++++++++++---------------
 2 files changed, 140 insertions(+), 74 deletions(-)
drivers/gpu/drm/i2c/Kconfig +1 -0
index 22c7ed6..8bb0697 100644
@@ -3,6 +3,7 @@ menu "I2C encoder or helper chips"
 
 config DRM_I2C_ADV7511
 	tristate "AV7511 encoder"
+	depends on OF
 	select REGMAP_I2C
 	help
 	  Support for the Analog Device ADV7511(W) and ADV7513 HDMI encoders.
drivers/gpu/drm/i2c/adv7511.c +139 -74

309 lines not on this page · raw message

Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
#76 lore raw

PATCH v5 2/7 drm/i2c: adv7511: Fix mutex deadlock when interrupts are disabled

In reply to Archit Taneja

When the adv7511 i2c client doesn't have an interrupt line, we observe a deadlock on caused by trying to lock drm device's mode_config.mutex twice in the same context.

Here is the sequence that causes it:

ioctl DRM_IOCTL_MODE_GETCONNECTOR from userspace
drm_mode_getconnector (acquires mode_config mutex)

    connector->fill_modes()
    drm_helper_probe_single_connector_modes
      connector_funcs->get_modes
	adv7511_encoder_get_modes
	  adv7511_get_edid_block
	    adv7511_irq_process
	      drm_helper_hpd_irq_event (acquires mode_config mutex again)

In adv7511_irq_process, don't call drm_helper_hpd_irq_event when not called from the interrupt handler. It doesn't serve any purpose there anyway.

---
 drivers/gpu/drm/i2c/adv7511.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/gpu/drm/i2c/adv7511.c +4 -4
index c2642f9..1fff0ab 100644
@@ -427,7 +427,7 @@ static bool adv7511_hpd(struct adv7511 *adv7511)
 	return false;
 }
 
-static int adv7511_irq_process(struct adv7511 *adv7511)
+static int adv7511_irq_process(struct adv7511 *adv7511, bool process_hpd)
 {
 	unsigned int irq0, irq1;
 	int ret;
@@ -443,7 +443,7 @@ static int adv7511_irq_process(struct adv7511 *adv7511)
 	regmap_write(adv7511->regmap, ADV7511_REG_INT(0), irq0);
 	regmap_write(adv7511->regmap, ADV7511_REG_INT(1), irq1);
 
-	if (irq0 & ADV7511_INT0_HPD && adv7511->bridge.encoder)
+	if (process_hpd && irq0 & ADV7511_INT0_HPD && adv7511->bridge.encoder)
 		drm_helper_hpd_irq_event(adv7511->connector.dev);
 
 	if (irq0 & ADV7511_INT0_EDID_READY || irq1 & ADV7511_INT1_DDC_ERROR) {
@@ -461,7 +461,7 @@ static irqreturn_t adv7511_irq_handler(int irq, void *devid)
 	struct adv7511 *adv7511 = devid;
 	int ret;
 
-	ret = adv7511_irq_process(adv7511);
+	ret = adv7511_irq_process(adv7511, true);
 	return ret < 0 ? IRQ_NONE : IRQ_HANDLED;
 }
 
@@ -478,7 +478,7 @@ static int adv7511_wait_for_edid(struct adv7511 *adv7511, int timeout)
 				adv7511->edid_read, msecs_to_jiffies(timeout));
 	} else {
 		for (; timeout > 0; timeout -= 25) {
-			ret = adv7511_irq_process(adv7511);
+			ret = adv7511_irq_process(adv7511, false);
 			if (ret < 0)
 				break;
 
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
#77 lore raw

PATCH v5 3/7 drm/i2c: adv7511: Initial support for ADV7533

In reply to Archit Taneja

ADV7533 is a DSI to HDMI encoder chip. It is a derivative of ADV7511, with additional blocks to translate input DSI data to parallel RGB data. Besides the ADV7511 I2C register map, it has additional registers that require to be configured to activate the DSI Rx block.

Create a new config that enables ADV7533 support. Use DT compatible strings to populate the ADV7533 type enum. Add minimal register configurations belonging to the DSI/CEC register map. Keep the ADV7533 code in a separate file.

Originally worked on by Lars-Peter Clausen <[email protected]>

---
 drivers/gpu/drm/i2c/Kconfig   |   7 +++
 drivers/gpu/drm/i2c/Makefile  |   4 +-
 drivers/gpu/drm/i2c/adv7511.c | 100 +++++++++++++++++++++---------------------
 drivers/gpu/drm/i2c/adv7511.h |  67 ++++++++++++++++++++++++++++
 drivers/gpu/drm/i2c/adv7533.c | 100 ++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 228 insertions(+), 50 deletions(-)
 create mode 100644 drivers/gpu/drm/i2c/adv7533.c
drivers/gpu/drm/i2c/Kconfig +7 -0
index 8bb0697..4cbbfd8 100644
@@ -8,6 +8,13 @@ config DRM_I2C_ADV7511
 	help
 	  Support for the Analog Device ADV7511(W) and ADV7513 HDMI encoders.
 
+config DRM_I2C_ADV7533
+	bool "ADV7533 encoder"
+	depends on DRM_I2C_ADV7511
+	default y
+	help
+	  Support for the Analog Devices ADV7533 DSI to HDMI encoder.
+
 config DRM_I2C_CH7006
 	tristate "Chrontel ch7006 TV encoder"
 	default m if DRM_NOUVEAU
drivers/gpu/drm/i2c/Makefile +3 -1
index 2c72eb5..cd2c22c 100644
@@ -1,6 +1,8 @@
 ccflags-y := -Iinclude/drm
 
-obj-$(CONFIG_DRM_I2C_ADV7511) += adv7511.o
+adv75xx-y := adv7511.o
+adv75xx-$(CONFIG_DRM_I2C_ADV7533) += adv7533.o
+obj-$(CONFIG_DRM_I2C_ADV7511) += adv75xx.o
 
 ch7006-y := ch7006_drv.o ch7006_mode.o
 obj-$(CONFIG_DRM_I2C_CH7006) += ch7006.o
drivers/gpu/drm/i2c/adv7511.c +51 -49

191 lines not on this page · raw message

drivers/gpu/drm/i2c/adv7511.h +67 -0

77 lines not on this page · raw message

drivers/gpu/drm/i2c/adv7533.c new file +100 -0

100 lines not on this page · raw message

Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
#78 lore raw

PATCH v5 4/7 drm/i2c: adv7533: Create a MIPI DSI device

In reply to Archit Taneja

In order to pass DSI specific parameters to the DSI host, we need the driver to create a mipi_dsi_device DSI device that attaches to the host.

Use of_graph helpers to get the DSI host DT node. Create a MIPI DSI device using this host. Finally, attach this device to the DSI host.

Populate DT parameters (number of data lanes for now) that are required for DSI RX to work correctly. Hardcode few other parameters (rgb, embedded_sync) for now.

Select DRM_MIPI_DSI config option only when ADV7533 support is enabled.

---
 drivers/gpu/drm/i2c/Kconfig   |  1 +
 drivers/gpu/drm/i2c/adv7511.c | 40 ++++++++++++++++---
 drivers/gpu/drm/i2c/adv7511.h | 20 ++++++++++
 drivers/gpu/drm/i2c/adv7533.c | 91 ++++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 144 insertions(+), 8 deletions(-)
drivers/gpu/drm/i2c/Kconfig +1 -0
index 4cbbfd8..70ee29d 100644
@@ -11,6 +11,7 @@ config DRM_I2C_ADV7511
 config DRM_I2C_ADV7533
 	bool "ADV7533 encoder"
 	depends on DRM_I2C_ADV7511
+	select DRM_MIPI_DSI
 	default y
 	help
 	  Support for the Analog Devices ADV7533 DSI to HDMI encoder.
drivers/gpu/drm/i2c/adv7511.c +34 -6
index e33702b..6586c52 100644
@@ -817,6 +817,9 @@ static int adv7511_bridge_attach(struct drm_bridge *bridge)
 				 &adv7511_connector_helper_funcs);
 	drm_mode_connector_attach_encoder(&adv->connector, bridge->encoder);
 
+	if (adv->type == ADV7533)
+		ret = adv7533_attach_dsi(adv);
+
 	return ret;
 }
 
@@ -943,11 +946,12 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
 
 	memset(&link_config, 0, sizeof(link_config));
 
-	if (adv7511->type == ADV7511) {
+	if (adv7511->type == ADV7511)
 		ret = adv7511_parse_dt(dev->of_node, &link_config);
-		if (ret)
-			return ret;
-	}
+	else
+		ret = adv7533_parse_dt(dev->of_node, adv7511);
+	if (ret)
+		return ret;
 
 	/*
 	 * The power down GPIO is optional. If present, toggle it from active to
@@ -1042,9 +1046,13 @@ static int adv7511_remove(struct i2c_client *i2c)
 {
 	struct adv7511 *adv7511 = i2c_get_clientdata(i2c);
 
+	if (adv7511->type == ADV7533) {
+		adv7533_detach_dsi(adv7511);
+		adv7533_uninit_cec(adv7511);
+	}
+
 	drm_bridge_remove(&adv7511->bridge);
 
-	adv7533_uninit_cec(adv7511);
 	i2c_unregister_device(adv7511->i2c_edid);
 
 	kfree(adv7511->edid);
@@ -1074,6 +1082,10 @@ static const struct of_device_id adv7511_of_ids[] = {
 };
 MODULE_DEVICE_TABLE(of, adv7511_of_ids);
 
+static struct mipi_dsi_driver adv7533_dsi_driver = {
+	.driver.name = "adv7533",
+};
+
 static struct i2c_driver adv7511_driver = {
 	.driver = {
 		.name = "adv7511",
@@ -1084,7 +1096,23 @@ static struct i2c_driver adv7511_driver = {
 	.remove = adv7511_remove,
 };
 
-module_i2c_driver(adv7511_driver);
+static int __init adv7511_init(void)
+{
+	if (IS_ENABLED(CONFIG_DRM_MIPI_DSI))
+		mipi_dsi_driver_register(&adv7533_dsi_driver);
+
+	return i2c_add_driver(&adv7511_driver);
+}
+module_init(adv7511_init);
+
+static void __exit adv7511_exit(void)
+{
+	i2c_del_driver(&adv7511_driver);
+
+	if (IS_ENABLED(CONFIG_DRM_MIPI_DSI))
+		mipi_dsi_driver_unregister(&adv7533_dsi_driver);
+}
+module_exit(adv7511_exit);
 
 MODULE_AUTHOR("Lars-Peter Clausen <[email protected]>");
 MODULE_DESCRIPTION("ADV7511 HDMI transmitter driver");
drivers/gpu/drm/i2c/adv7511.h +20 -0
index 541c5d7..056f747 100644
@@ -14,6 +14,7 @@
 #include <linux/regmap.h>
 
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_mipi_dsi.h>
 
 #define ADV7511_REG_CHIP_REVISION		0x00
 #define ADV7511_REG_N0				0x01
@@ -324,6 +325,11 @@ struct adv7511 {
 
 	struct gpio_desc *gpio_pd;
 
+	/* ADV7533 DSI RX related params */
+	struct device_node *host_node;
+	struct mipi_dsi_device *dsi;
+	u8 num_dsi_lanes;
+
 	enum adv7511_type type;
 };
 
@@ -333,6 +339,9 @@ void adv7533_dsi_power_off(struct adv7511 *adv);
 int adv7533_patch_registers(struct adv7511 *adv);
 void adv7533_uninit_cec(struct adv7511 *adv);
 int adv7533_init_cec(struct adv7511 *adv);
+int adv7533_attach_dsi(struct adv7511 *adv);
+void adv7533_detach_dsi(struct adv7511 *adv);
+int adv7533_parse_dt(struct device_node *np, struct adv7511 *adv);
 #else
 static inline void adv7533_dsi_power_on(struct adv7511 *adv)
 {
@@ -351,6 +360,17 @@ static inline int adv7533_init_cec(struct adv7511 *adv)
 {
 	return -ENODEV;
 }
+static inline int adv7533_attach_dsi(struct adv7511 *adv)
+{
+	return -ENODEV;
+}
+static inline void adv7533_detach_dsi(struct adv7511 *adv)
+{
+}
+static inline int adv7533_parse_dt(struct device_node *np, struct adv7511 *adv)
+{
+	return -ENODEV;
+}
 #endif
 
 #endif /* __DRM_I2C_ADV7511_H__ */
drivers/gpu/drm/i2c/adv7533.c +89 -2

106 lines not on this page · raw message

Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
#79 lore raw

PATCH v5 5/7 drm/i2c: adv7533: Use internal timing generator

In reply to Archit Taneja

ADV7533 provides an internal timing generator for certain modes that it can't use the DSI clock directly.

We've observed that HDMI is more stable with the internal timing generator, especially if there are instabilities in the DSI clock source. The data spec also seems to recommend the usage of the timing generator for all modes.

However, on some platforms, it's reported that enabling the timing generator causes instabilities with the HDMI output.

Create a DT parameter that lets a platform explicitly disable the timing generator. The timing generator is enabled by default.

---
 drivers/gpu/drm/i2c/adv7511.c |  2 ++
 drivers/gpu/drm/i2c/adv7511.h |  3 +++
 drivers/gpu/drm/i2c/adv7533.c | 60 +++++++++++++++++++++++++++++++++++++++++--
 3 files changed, 63 insertions(+), 2 deletions(-)
drivers/gpu/drm/i2c/adv7511.c +2 -0
index 6586c52..e0c353e 100644
@@ -712,6 +712,8 @@ static void adv7511_mode_set(struct adv7511 *adv7511,
 	regmap_update_bits(adv7511->regmap, 0x17,
 		0x60, (vsync_polarity << 6) | (hsync_polarity << 5));
 
+	drm_mode_copy(&adv7511->curr_mode, adj_mode);
+
 	/*
 	 * TODO Test first order 4:2:2 to 4:4:4 up conversion method, which is
 	 * supposed to give better results.
drivers/gpu/drm/i2c/adv7511.h +3 -0
index 056f747..a9745ea 100644
@@ -306,6 +306,8 @@ struct adv7511 {
 	enum drm_connector_status status;
 	bool powered;
 
+	struct drm_display_mode curr_mode;
+
 	unsigned int f_tmds;
 
 	unsigned int current_edid_segment;
@@ -329,6 +331,7 @@ struct adv7511 {
 	struct device_node *host_node;
 	struct mipi_dsi_device *dsi;
 	u8 num_dsi_lanes;
+	bool use_timing_gen;
 
 	enum adv7511_type type;
 };
drivers/gpu/drm/i2c/adv7533.c +58 -2

84 lines not on this page · raw message

Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
#80 lore raw

PATCH v5 6/7 drm/i2c: adv7533: Change number of DSI lanes dynamically

In reply to Archit Taneja

Lower modes on ADV7533 require lower number of DSI lanes for correct operation. If ADV7533 is being used with 4 DSI lanes, then switch the lanes to 3 when the target mode's pixel clock is less than 80 Mhz.

Based on patch by Andy Green <[email protected]>

---
 drivers/gpu/drm/i2c/adv7511.c |  3 +++
 drivers/gpu/drm/i2c/adv7511.h |  5 +++++
 drivers/gpu/drm/i2c/adv7533.c | 22 ++++++++++++++++++++++
 3 files changed, 30 insertions(+)
drivers/gpu/drm/i2c/adv7511.c +3 -0
index e0c353e..ec8fb2e 100644
@@ -712,6 +712,9 @@ static void adv7511_mode_set(struct adv7511 *adv7511,
 	regmap_update_bits(adv7511->regmap, 0x17,
 		0x60, (vsync_polarity << 6) | (hsync_polarity << 5));
 
+	if (adv7511->type == ADV7533)
+		adv7533_mode_set(adv7511, adj_mode);
+
 	drm_mode_copy(&adv7511->curr_mode, adj_mode);
 
 	/*
drivers/gpu/drm/i2c/adv7511.h +5 -0
index a9745ea..b113b77 100644
@@ -339,6 +339,7 @@ struct adv7511 {
 #ifdef CONFIG_DRM_I2C_ADV7533
 void adv7533_dsi_power_on(struct adv7511 *adv);
 void adv7533_dsi_power_off(struct adv7511 *adv);
+void adv7533_mode_set(struct adv7511 *adv, struct drm_display_mode *mode);
 int adv7533_patch_registers(struct adv7511 *adv);
 void adv7533_uninit_cec(struct adv7511 *adv);
 int adv7533_init_cec(struct adv7511 *adv);
@@ -352,6 +353,10 @@ static inline void adv7533_dsi_power_on(struct adv7511 *adv)
 static inline void adv7533_dsi_power_off(struct adv7511 *adv)
 {
 }
+static inline void adv7533_mode_set(struct adv7511 *adv,
+				    struct drm_display_mode *mode)
+{
+}
 static inline int adv7533_patch_registers(struct adv7511 *adv)
 {
 	return -ENODEV;
drivers/gpu/drm/i2c/adv7533.c +22 -0
index d002ac4..5eebd15 100644
@@ -115,6 +115,28 @@ void adv7533_dsi_power_off(struct adv7511 *adv)
 	regmap_write(adv->regmap_cec, 0x27, 0x0b);
 }
 
+void adv7533_mode_set(struct adv7511 *adv, struct drm_display_mode *mode)
+{
+	struct mipi_dsi_device *dsi = adv->dsi;
+	int lanes, ret;
+
+	if (adv->num_dsi_lanes != 4)
+		return;
+
+	if (mode->clock > 80000)
+		lanes = 4;
+	else
+		lanes = 3;
+
+	if (lanes != dsi->lanes) {
+		mipi_dsi_detach(dsi);
+		dsi->lanes = lanes;
+		ret = mipi_dsi_attach(dsi);
+		if (ret)
+			dev_err(&dsi->dev, "failed to change host lanes\n");
+	}
+}
+
 int adv7533_patch_registers(struct adv7511 *adv)
 {
 	return regmap_register_patch(adv->regmap,
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
#81 lore raw

PATCH v5 7/7 dt-bindings: drm/bridge: Update bindings for ADV7533

In reply to Archit Taneja

Add description of ADV7533. Add the required and optional properties that are specific to it.

---
 .../bindings/display/bridge/adi,adv7511.txt        | 26 +++++++++++++++++-----
 1 file changed, 21 insertions(+), 5 deletions(-)
Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt +21 -5
index 96c25ee..6532a59 100644
@@ -1,13 +1,19 @@
-Analog Device ADV7511(W)/13 HDMI Encoders
+Analog Device ADV7511(W)/13/33 HDMI Encoders
 -----------------------------------------
 
-The ADV7511, ADV7511W and ADV7513 are HDMI audio and video transmitters
+The ADV7511, ADV7511W, ADV7513 and ADV7533 are HDMI audio and video transmitters
 compatible with HDMI 1.4 and DVI 1.0. They support color space conversion,
-S/PDIF, CEC and HDCP.
+S/PDIF, CEC and HDCP. ADV7533 supports the DSI interface for input pixels, while
+the others support RGB interface.
 
 Required properties:
 
-- compatible: Should be one of "adi,adv7511", "adi,adv7511w" or "adi,adv7513"
+- compatible: Should be one of:
+		"adi,adv7511"
+		"adi,adv7511w"
+		"adi,adv7513"
+		"adi,adv7533"
+
 - reg: I2C slave address
 
 The ADV7511 supports a large number of input data formats that differ by their
@@ -32,6 +38,11 @@ The following input format properties are required except in "rgb 1x" and
 - adi,input-justification: The input bit justification ("left", "evenly",
   "right").
 
+The following properties are required for ADV7533:
+
+- adi,dsi-lanes: Number of DSI data lanes connected to the DSI host. It should
+  be one of 1, 2, 3 or 4.
+
 Optional properties:
 
 - interrupts: Specifier for the ADV7511 interrupt
@@ -42,13 +53,18 @@ Optional properties:
 - adi,embedded-sync: The input uses synchronization signals embedded in the
   data stream (similar to BT.656). Defaults to separate H/V synchronization
   signals.
+- adi,disable-timing-generator: Only for ADV7533. Disables the internal timing
+  generator. The chip will rely on the sync signals in the DSI data lanes,
+  rather than generate its own timings for HDMI output.
 
 Required nodes:
 
 The ADV7511 has two video ports. Their connections are modelled using the OF
 graph bindings specified in Documentation/devicetree/bindings/graph.txt.
 
-- Video port 0 for the RGB or YUV input
+- Video port 0 for the RGB, YUV or DSI input. In the case of ADV7533, the
+  remote endpoint phandle should be a reference to a valid mipi_dsi_host device
+  node.
 - Video port 1 for the HDMI output
 
 
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
#82 lore raw

v6 cover drm/i2c: adv7511: ADV7533 support

In reply to Archit Taneja

ADV7533 is a DSI to HDMI encoder chip. It's like ADV7511, but with an additional DSI RX block that takes in DSI video mode output.

This revision is quite similar to the previous version with some issues fixed.

Changes in v6:
- v5 changed the adv7511 module name to adv75xx.ko, it was previously called adv7511.ko. This revision fixes the Makefile such that the module name doesn't change, and hence not break userspace.
- Move the driver to the drivers/gpu/drm/bridge folder. This was planned to be done later, but I thought it would be better if we did it in this patchset itself since the driver is already converted to a bridge.

Changes in v5:
- Fix break observed when built for x86.
- Based off current drm-misc.
- Removes best_encoder connector helper function since it isn't needed after this series:
https://lkml.org/lkml/2016/6/2/508

Changes in v4:
- Separated out build for ADV7533. The original plan was to stub out the drm_mipi_dsi funcs, but that seemed like an overkill since it helped just this driver. It seems better to stub out the ADV7533 functionality altogether instead.
- Some minor DT binding corrections suggested by Laurent.

Archit Taneja (8):
drm/i2c: adv7511: Convert to drm_bridge
drm/i2c: adv7511: Move to bridge folder
drm/bridge: adv7511: Fix mutex deadlock when interrupts are disabled drm/bridge: adv7533: Initial support for ADV7533 drm/bridge: adv7533: Create a MIPI DSI device
drm/bridge: adv7533: Use internal timing generator drm/bridge: adv7533: Change number of DSI lanes dynamically
dt-bindings: drm/bridge: Update bindings for ADV7533

 .../bindings/display/bridge/adi,adv7511.txt        |   26 +-
 drivers/gpu/drm/bridge/Kconfig                     |    2 +
 drivers/gpu/drm/bridge/Makefile                    |    1 +
 drivers/gpu/drm/bridge/adv7511/Kconfig             |   15 +
 drivers/gpu/drm/bridge/adv7511/Makefile            |    3 +
 drivers/gpu/drm/bridge/adv7511/adv7511.h           |  392 +++++++
 drivers/gpu/drm/bridge/adv7511/adv7511_drv.c       | 1124 ++++++++++++++++++++
 drivers/gpu/drm/bridge/adv7511/adv7533.c           |  265 +++++
 drivers/gpu/drm/i2c/Kconfig                        |    6 -
 drivers/gpu/drm/i2c/Makefile                       |    2 -
 drivers/gpu/drm/i2c/adv7511.c                      | 1024 ------------------
 drivers/gpu/drm/i2c/adv7511.h                      |  289 -----
 12 files changed, 1823 insertions(+), 1326 deletions(-)
 create mode 100644 drivers/gpu/drm/bridge/adv7511/Kconfig
 create mode 100644 drivers/gpu/drm/bridge/adv7511/Makefile
 create mode 100644 drivers/gpu/drm/bridge/adv7511/adv7511.h
 create mode 100644 drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
 create mode 100644 drivers/gpu/drm/bridge/adv7511/adv7533.c
 delete mode 100644 drivers/gpu/drm/i2c/adv7511.c
 delete mode 100644 drivers/gpu/drm/i2c/adv7511.h
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
#83 lore raw

PATCH v6 1/8 drm/i2c: adv7511: Convert to drm_bridge

We don't want to use the old i2c slave encoder interface anymore.

Remove that and make the i2c driver create a drm_bridge entity instead. Converting to bridges helps because the kms drivers don't need to exract encoder slave ops from this driver and use it within their own encoder/connector ops.

The driver now creates its own connector when a kms driver attaches itself to the bridge. Therefore, kms drivers don't need to create their own connectors anymore.

The old encoder slave ops are now used by the new bridge and connector entities.

The of_node member in drm_bridge is accessible only when CONFIG_OF is enabled. The driver anyway only works only when OF is available. Make the driver depend on OF in its Kconfig.

---
 drivers/gpu/drm/i2c/Kconfig   |   1 +
 drivers/gpu/drm/i2c/adv7511.c | 213 +++++++++++++++++++++++++++---------------
 2 files changed, 140 insertions(+), 74 deletions(-)
drivers/gpu/drm/i2c/Kconfig +1 -0
index 22c7ed6..8bb0697 100644
@@ -3,6 +3,7 @@ menu "I2C encoder or helper chips"
 
 config DRM_I2C_ADV7511
 	tristate "AV7511 encoder"
+	depends on OF
 	select REGMAP_I2C
 	help
 	  Support for the Analog Device ADV7511(W) and ADV7513 HDMI encoders.
drivers/gpu/drm/i2c/adv7511.c +139 -74

309 lines not on this page · raw message

Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
#84 lore raw

PATCH v6 2/8 drm/i2c: adv7511: Move to bridge folder

In reply to Archit Taneja

The driver has been converted to use drm_bridge instead of drm_i2c_slave_encoder. We can now move it to the bridge folder.

Create a separate folder since we already have a couple of files and expect more when we support audio and ADV7533.

Rename the driver to adv7511_drv.c. This will come in handy later when the driver module will need to be built from multiple object files.

---
v6:
- New patch

 drivers/gpu/drm/bridge/Kconfig               |    2 +
 drivers/gpu/drm/bridge/Makefile              |    1 +
 drivers/gpu/drm/bridge/adv7511/Kconfig       |    7 +
 drivers/gpu/drm/bridge/adv7511/Makefile      |    2 +
 drivers/gpu/drm/bridge/adv7511/adv7511.h     |  289 +++++++
 drivers/gpu/drm/bridge/adv7511/adv7511_drv.c | 1089 ++++++++++++++++++++++++++
 drivers/gpu/drm/i2c/Kconfig                  |    7 -
 drivers/gpu/drm/i2c/Makefile                 |    2 -
 drivers/gpu/drm/i2c/adv7511.c                | 1089 --------------------------
 drivers/gpu/drm/i2c/adv7511.h                |  289 -------
 10 files changed, 1390 insertions(+), 1387 deletions(-)
 create mode 100644 drivers/gpu/drm/bridge/adv7511/Kconfig
 create mode 100644 drivers/gpu/drm/bridge/adv7511/Makefile
 create mode 100644 drivers/gpu/drm/bridge/adv7511/adv7511.h
 create mode 100644 drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
 delete mode 100644 drivers/gpu/drm/i2c/adv7511.c
 delete mode 100644 drivers/gpu/drm/i2c/adv7511.h
drivers/gpu/drm/bridge/Kconfig +2 -0
index 8f7423f..9ac6427 100644
@@ -52,4 +52,6 @@ config DRM_PARADE_PS8622
 
 source "drivers/gpu/drm/bridge/analogix/Kconfig"
 
+source "drivers/gpu/drm/bridge/adv7511/Kconfig"
+
 endmenu
drivers/gpu/drm/bridge/Makefile +1 -0
index 96b13b3..94e7d2f 100644
@@ -6,3 +6,4 @@ obj-$(CONFIG_DRM_DW_HDMI_AHB_AUDIO) += dw-hdmi-ahb-audio.o
 obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o
 obj-$(CONFIG_DRM_PARADE_PS8622) += parade-ps8622.o
 obj-$(CONFIG_DRM_ANALOGIX_DP) += analogix/
+obj-$(CONFIG_DRM_I2C_ADV7511) += adv7511/
drivers/gpu/drm/bridge/adv7511/Kconfig new file +7 -0
new file mode 100644
index 0000000..222c6cc
@@ -0,0 +1,7 @@
+config DRM_I2C_ADV7511
+	tristate "AV7511 encoder"
+	depends on OF
+	select DRM_KMS_HELPER
+	select REGMAP_I2C
+	help
+	  Support for the Analog Device ADV7511(W) and ADV7513 HDMI encoders.
drivers/gpu/drm/bridge/adv7511/Makefile new file +2 -0
new file mode 100644
index 0000000..692f83a
@@ -0,0 +1,2 @@
+adv7511-y := adv7511_drv.o
+obj-$(CONFIG_DRM_I2C_ADV7511) += adv7511.o
drivers/gpu/drm/bridge/adv7511/adv7511.h new file +289 -0

289 lines not on this page · raw message

drivers/gpu/drm/bridge/adv7511/adv7511_drv.c new file +1089 -0

1,089 lines not on this page · raw message

drivers/gpu/drm/i2c/Kconfig +0 -7
index 8bb0697..4d341db 100644
@@ -1,13 +1,6 @@
 menu "I2C encoder or helper chips"
      depends on DRM && DRM_KMS_HELPER && I2C
 
-config DRM_I2C_ADV7511
-	tristate "AV7511 encoder"
-	depends on OF
-	select REGMAP_I2C
-	help
-	  Support for the Analog Device ADV7511(W) and ADV7513 HDMI encoders.
-
 config DRM_I2C_CH7006
 	tristate "Chrontel ch7006 TV encoder"
 	default m if DRM_NOUVEAU
drivers/gpu/drm/i2c/Makefile +0 -2
index 2c72eb5..43aa33b 100644
@@ -1,7 +1,5 @@
 ccflags-y := -Iinclude/drm
 
-obj-$(CONFIG_DRM_I2C_ADV7511) += adv7511.o
-
 ch7006-y := ch7006_drv.o ch7006_mode.o
 obj-$(CONFIG_DRM_I2C_CH7006) += ch7006.o
 
drivers/gpu/drm/i2c/adv7511.c deleted +0 -1089

1,089 lines not on this page · raw message

drivers/gpu/drm/i2c/adv7511.h deleted +0 -289

289 lines not on this page · raw message

Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
#85 lore raw

PATCH v6 3/8 drm/bridge: adv7511: Fix mutex deadlock when interrupts are disabled

In reply to Archit Taneja

When the adv7511 i2c client doesn't have an interrupt line, we observe a deadlock on caused by trying to lock drm device's mode_config.mutex twice in the same context.

Here is the sequence that causes it:

ioctl DRM_IOCTL_MODE_GETCONNECTOR from userspace
drm_mode_getconnector (acquires mode_config mutex)

    connector->fill_modes()
    drm_helper_probe_single_connector_modes
      connector_funcs->get_modes
	adv7511_encoder_get_modes
	  adv7511_get_edid_block
	    adv7511_irq_process
	      drm_helper_hpd_irq_event (acquires mode_config mutex again)

In adv7511_irq_process, don't call drm_helper_hpd_irq_event when not called from the interrupt handler. It doesn't serve any purpose there anyway.

---
 drivers/gpu/drm/bridge/adv7511/adv7511_drv.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/gpu/drm/bridge/adv7511/adv7511_drv.c +4 -4
index c2642f9..1fff0ab 100644
@@ -427,7 +427,7 @@ static bool adv7511_hpd(struct adv7511 *adv7511)
 	return false;
 }
 
-static int adv7511_irq_process(struct adv7511 *adv7511)
+static int adv7511_irq_process(struct adv7511 *adv7511, bool process_hpd)
 {
 	unsigned int irq0, irq1;
 	int ret;
@@ -443,7 +443,7 @@ static int adv7511_irq_process(struct adv7511 *adv7511)
 	regmap_write(adv7511->regmap, ADV7511_REG_INT(0), irq0);
 	regmap_write(adv7511->regmap, ADV7511_REG_INT(1), irq1);
 
-	if (irq0 & ADV7511_INT0_HPD && adv7511->bridge.encoder)
+	if (process_hpd && irq0 & ADV7511_INT0_HPD && adv7511->bridge.encoder)
 		drm_helper_hpd_irq_event(adv7511->connector.dev);
 
 	if (irq0 & ADV7511_INT0_EDID_READY || irq1 & ADV7511_INT1_DDC_ERROR) {
@@ -461,7 +461,7 @@ static irqreturn_t adv7511_irq_handler(int irq, void *devid)
 	struct adv7511 *adv7511 = devid;
 	int ret;
 
-	ret = adv7511_irq_process(adv7511);
+	ret = adv7511_irq_process(adv7511, true);
 	return ret < 0 ? IRQ_NONE : IRQ_HANDLED;
 }
 
@@ -478,7 +478,7 @@ static int adv7511_wait_for_edid(struct adv7511 *adv7511, int timeout)
 				adv7511->edid_read, msecs_to_jiffies(timeout));
 	} else {
 		for (; timeout > 0; timeout -= 25) {
-			ret = adv7511_irq_process(adv7511);
+			ret = adv7511_irq_process(adv7511, false);
 			if (ret < 0)
 				break;
 
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
#86 lore raw

PATCH v6 4/8 drm/bridge: adv7533: Initial support for ADV7533

In reply to Archit Taneja

ADV7533 is a DSI to HDMI encoder chip. It is a derivative of ADV7511, with additional blocks to translate input DSI data to parallel RGB data. Besides the ADV7511 I2C register map, it has additional registers that require to be configured to activate the DSI Rx block.

Create a new config that enables ADV7533 support. Use DT compatible strings to populate the ADV7533 type enum. Add minimal register configurations belonging to the DSI/CEC register map. Keep the ADV7533 code in a separate file.

Originally worked on by Lars-Peter Clausen <[email protected]>

---
 drivers/gpu/drm/bridge/adv7511/Kconfig       |   7 ++
 drivers/gpu/drm/bridge/adv7511/Makefile      |   1 +
 drivers/gpu/drm/bridge/adv7511/adv7511.h     |  71 +++++++++++++++++++
 drivers/gpu/drm/bridge/adv7511/adv7511_drv.c | 100 ++++++++++++++-------------
 drivers/gpu/drm/bridge/adv7511/adv7533.c     | 100 +++++++++++++++++++++++++++
 5 files changed, 230 insertions(+), 49 deletions(-)
 create mode 100644 drivers/gpu/drm/bridge/adv7511/adv7533.c
drivers/gpu/drm/bridge/adv7511/Kconfig +7 -0
index 222c6cc..eb84419 100644
@@ -5,3 +5,10 @@ config DRM_I2C_ADV7511
 	select REGMAP_I2C
 	help
 	  Support for the Analog Device ADV7511(W) and ADV7513 HDMI encoders.
+
+config DRM_I2C_ADV7533
+	bool "ADV7533 encoder"
+	depends on DRM_I2C_ADV7511
+	default y
+	help
+	  Support for the Analog Devices ADV7533 DSI to HDMI encoder.
drivers/gpu/drm/bridge/adv7511/Makefile +1 -0
index 692f83a..9019327 100644
@@ -1,2 +1,3 @@
 adv7511-y := adv7511_drv.o
+adv7511-$(CONFIG_DRM_I2C_ADV7533) += adv7533.o
 obj-$(CONFIG_DRM_I2C_ADV7511) += adv7511.o
drivers/gpu/drm/bridge/adv7511/adv7511.h +71 -0

81 lines not on this page · raw message

drivers/gpu/drm/bridge/adv7511/adv7511_drv.c +51 -49

191 lines not on this page · raw message

drivers/gpu/drm/bridge/adv7511/adv7533.c new file +100 -0

100 lines not on this page · raw message

Signature · 7 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
#87 lore raw

PATCH v6 5/8 drm/bridge: adv7533: Create a MIPI DSI device

In reply to Archit Taneja

In order to pass DSI specific parameters to the DSI host, we need the driver to create a mipi_dsi_device DSI device that attaches to the host.

Use of_graph helpers to get the DSI host DT node. Create a MIPI DSI device using this host. Finally, attach this device to the DSI host.

Populate DT parameters (number of data lanes for now) that are required for DSI RX to work correctly. Hardcode few other parameters (rgb, embedded_sync) for now.

Select DRM_MIPI_DSI config option only when ADV7533 support is enabled.

---
 drivers/gpu/drm/bridge/adv7511/Kconfig       |  1 +
 drivers/gpu/drm/bridge/adv7511/adv7511.h     | 23 +++++++
 drivers/gpu/drm/bridge/adv7511/adv7511_drv.c | 40 ++++++++++--
 drivers/gpu/drm/bridge/adv7511/adv7533.c     | 91 +++++++++++++++++++++++++++-
 4 files changed, 147 insertions(+), 8 deletions(-)
drivers/gpu/drm/bridge/adv7511/Kconfig +1 -0
index eb84419..d2b0499 100644
@@ -9,6 +9,7 @@ config DRM_I2C_ADV7511
 config DRM_I2C_ADV7533
 	bool "ADV7533 encoder"
 	depends on DRM_I2C_ADV7511
+	select DRM_MIPI_DSI
 	default y
 	help
 	  Support for the Analog Devices ADV7533 DSI to HDMI encoder.
drivers/gpu/drm/bridge/adv7511/adv7511.h +23 -0
index 5dea769..3e4d47a 100644
@@ -14,6 +14,7 @@
 #include <linux/regmap.h>
 
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_mipi_dsi.h>
 
 #define ADV7511_REG_CHIP_REVISION		0x00
 #define ADV7511_REG_N0				0x01
@@ -324,6 +325,11 @@ struct adv7511 {
 
 	struct gpio_desc *gpio_pd;
 
+	/* ADV7533 DSI RX related params */
+	struct device_node *host_node;
+	struct mipi_dsi_device *dsi;
+	u8 num_dsi_lanes;
+
 	enum adv7511_type type;
 };
 
@@ -333,6 +339,9 @@ void adv7533_dsi_power_off(struct adv7511 *adv);
 int adv7533_patch_registers(struct adv7511 *adv);
 void adv7533_uninit_cec(struct adv7511 *adv);
 int adv7533_init_cec(struct adv7511 *adv);
+int adv7533_attach_dsi(struct adv7511 *adv);
+void adv7533_detach_dsi(struct adv7511 *adv);
+int adv7533_parse_dt(struct device_node *np, struct adv7511 *adv);
 #else
 static inline void adv7533_dsi_power_on(struct adv7511 *adv)
 {
@@ -355,6 +364,20 @@ static inline int adv7533_init_cec(struct adv7511 *adv)
 {
 	return -ENODEV;
 }
+
+static inline int adv7533_attach_dsi(struct adv7511 *adv)
+{
+	return -ENODEV;
+}
+
+static inline void adv7533_detach_dsi(struct adv7511 *adv)
+{
+}
+
+static inline int adv7533_parse_dt(struct device_node *np, struct adv7511 *adv)
+{
+	return -ENODEV;
+}
 #endif
 
 #endif /* __DRM_I2C_ADV7511_H__ */
drivers/gpu/drm/bridge/adv7511/adv7511_drv.c +34 -6
index e33702b..6586c52 100644
@@ -817,6 +817,9 @@ static int adv7511_bridge_attach(struct drm_bridge *bridge)
 				 &adv7511_connector_helper_funcs);
 	drm_mode_connector_attach_encoder(&adv->connector, bridge->encoder);
 
+	if (adv->type == ADV7533)
+		ret = adv7533_attach_dsi(adv);
+
 	return ret;
 }
 
@@ -943,11 +946,12 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
 
 	memset(&link_config, 0, sizeof(link_config));
 
-	if (adv7511->type == ADV7511) {
+	if (adv7511->type == ADV7511)
 		ret = adv7511_parse_dt(dev->of_node, &link_config);
-		if (ret)
-			return ret;
-	}
+	else
+		ret = adv7533_parse_dt(dev->of_node, adv7511);
+	if (ret)
+		return ret;
 
 	/*
 	 * The power down GPIO is optional. If present, toggle it from active to
@@ -1042,9 +1046,13 @@ static int adv7511_remove(struct i2c_client *i2c)
 {
 	struct adv7511 *adv7511 = i2c_get_clientdata(i2c);
 
+	if (adv7511->type == ADV7533) {
+		adv7533_detach_dsi(adv7511);
+		adv7533_uninit_cec(adv7511);
+	}
+
 	drm_bridge_remove(&adv7511->bridge);
 
-	adv7533_uninit_cec(adv7511);
 	i2c_unregister_device(adv7511->i2c_edid);
 
 	kfree(adv7511->edid);
@@ -1074,6 +1082,10 @@ static const struct of_device_id adv7511_of_ids[] = {
 };
 MODULE_DEVICE_TABLE(of, adv7511_of_ids);
 
+static struct mipi_dsi_driver adv7533_dsi_driver = {
+	.driver.name = "adv7533",
+};
+
 static struct i2c_driver adv7511_driver = {
 	.driver = {
 		.name = "adv7511",
@@ -1084,7 +1096,23 @@ static struct i2c_driver adv7511_driver = {
 	.remove = adv7511_remove,
 };
 
-module_i2c_driver(adv7511_driver);
+static int __init adv7511_init(void)
+{
+	if (IS_ENABLED(CONFIG_DRM_MIPI_DSI))
+		mipi_dsi_driver_register(&adv7533_dsi_driver);
+
+	return i2c_add_driver(&adv7511_driver);
+}
+module_init(adv7511_init);
+
+static void __exit adv7511_exit(void)
+{
+	i2c_del_driver(&adv7511_driver);
+
+	if (IS_ENABLED(CONFIG_DRM_MIPI_DSI))
+		mipi_dsi_driver_unregister(&adv7533_dsi_driver);
+}
+module_exit(adv7511_exit);
 
 MODULE_AUTHOR("Lars-Peter Clausen <[email protected]>");
 MODULE_DESCRIPTION("ADV7511 HDMI transmitter driver");
drivers/gpu/drm/bridge/adv7511/adv7533.c +89 -2

106 lines not on this page · raw message

Signature · 7 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
#88 lore raw

PATCH v6 6/8 drm/bridge: adv7533: Use internal timing generator

In reply to Archit Taneja

ADV7533 provides an internal timing generator for certain modes that it can't use the DSI clock directly.

We've observed that HDMI is more stable with the internal timing generator, especially if there are instabilities in the DSI clock source. The data spec also seems to recommend the usage of the timing generator for all modes.

However, on some platforms, it's reported that enabling the timing generator causes instabilities with the HDMI output.

Create a DT parameter that lets a platform explicitly disable the timing generator. The timing generator is enabled by default.

---
 drivers/gpu/drm/bridge/adv7511/adv7511.h     |  3 ++
 drivers/gpu/drm/bridge/adv7511/adv7511_drv.c |  2 +
 drivers/gpu/drm/bridge/adv7511/adv7533.c     | 60 +++++++++++++++++++++++++++-
 3 files changed, 63 insertions(+), 2 deletions(-)
drivers/gpu/drm/bridge/adv7511/adv7511.h +3 -0
index 3e4d47a..90a8c09 100644
@@ -306,6 +306,8 @@ struct adv7511 {
 	enum drm_connector_status status;
 	bool powered;
 
+	struct drm_display_mode curr_mode;
+
 	unsigned int f_tmds;
 
 	unsigned int current_edid_segment;
@@ -329,6 +331,7 @@ struct adv7511 {
 	struct device_node *host_node;
 	struct mipi_dsi_device *dsi;
 	u8 num_dsi_lanes;
+	bool use_timing_gen;
 
 	enum adv7511_type type;
 };
drivers/gpu/drm/bridge/adv7511/adv7511_drv.c +2 -0
index 6586c52..e0c353e 100644
@@ -712,6 +712,8 @@ static void adv7511_mode_set(struct adv7511 *adv7511,
 	regmap_update_bits(adv7511->regmap, 0x17,
 		0x60, (vsync_polarity << 6) | (hsync_polarity << 5));
 
+	drm_mode_copy(&adv7511->curr_mode, adj_mode);
+
 	/*
 	 * TODO Test first order 4:2:2 to 4:4:4 up conversion method, which is
 	 * supposed to give better results.
drivers/gpu/drm/bridge/adv7511/adv7533.c +58 -2

84 lines not on this page · raw message

Signature · 7 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
#89 lore raw

PATCH v6 7/8 drm/bridge: adv7533: Change number of DSI lanes dynamically

In reply to Archit Taneja

Lower modes on ADV7533 require lower number of DSI lanes for correct operation. If ADV7533 is being used with 4 DSI lanes, then switch the lanes to 3 when the target mode's pixel clock is less than 80 Mhz.

Based on patch by Andy Green <[email protected]>

---
 drivers/gpu/drm/bridge/adv7511/adv7511.h     |  6 ++++++
 drivers/gpu/drm/bridge/adv7511/adv7511_drv.c |  3 +++
 drivers/gpu/drm/bridge/adv7511/adv7533.c     | 22 ++++++++++++++++++++++
 3 files changed, 31 insertions(+)
drivers/gpu/drm/bridge/adv7511/adv7511.h +6 -0
index 90a8c09..161c923 100644
@@ -339,6 +339,7 @@ struct adv7511 {
 #ifdef CONFIG_DRM_I2C_ADV7533
 void adv7533_dsi_power_on(struct adv7511 *adv);
 void adv7533_dsi_power_off(struct adv7511 *adv);
+void adv7533_mode_set(struct adv7511 *adv, struct drm_display_mode *mode);
 int adv7533_patch_registers(struct adv7511 *adv);
 void adv7533_uninit_cec(struct adv7511 *adv);
 int adv7533_init_cec(struct adv7511 *adv);
@@ -354,6 +355,11 @@ static inline void adv7533_dsi_power_off(struct adv7511 *adv)
 {
 }
 
+static inline void adv7533_mode_set(struct adv7511 *adv,
+				    struct drm_display_mode *mode)
+{
+}
+
 static inline int adv7533_patch_registers(struct adv7511 *adv)
 {
 	return -ENODEV;
drivers/gpu/drm/bridge/adv7511/adv7511_drv.c +3 -0
index e0c353e..ec8fb2e 100644
@@ -712,6 +712,9 @@ static void adv7511_mode_set(struct adv7511 *adv7511,
 	regmap_update_bits(adv7511->regmap, 0x17,
 		0x60, (vsync_polarity << 6) | (hsync_polarity << 5));
 
+	if (adv7511->type == ADV7533)
+		adv7533_mode_set(adv7511, adj_mode);
+
 	drm_mode_copy(&adv7511->curr_mode, adj_mode);
 
 	/*
drivers/gpu/drm/bridge/adv7511/adv7533.c +22 -0
index d002ac4..5eebd15 100644
@@ -115,6 +115,28 @@ void adv7533_dsi_power_off(struct adv7511 *adv)
 	regmap_write(adv->regmap_cec, 0x27, 0x0b);
 }
 
+void adv7533_mode_set(struct adv7511 *adv, struct drm_display_mode *mode)
+{
+	struct mipi_dsi_device *dsi = adv->dsi;
+	int lanes, ret;
+
+	if (adv->num_dsi_lanes != 4)
+		return;
+
+	if (mode->clock > 80000)
+		lanes = 4;
+	else
+		lanes = 3;
+
+	if (lanes != dsi->lanes) {
+		mipi_dsi_detach(dsi);
+		dsi->lanes = lanes;
+		ret = mipi_dsi_attach(dsi);
+		if (ret)
+			dev_err(&dsi->dev, "failed to change host lanes\n");
+	}
+}
+
 int adv7533_patch_registers(struct adv7511 *adv)
 {
 	return regmap_register_patch(adv->regmap,
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
#90 lore raw

PATCH v6 8/8 dt-bindings: drm/bridge: Update bindings for ADV7533

In reply to Archit Taneja

Add description of ADV7533. Add the required and optional properties that are specific to it.

---
 .../bindings/display/bridge/adi,adv7511.txt        | 26 +++++++++++++++++-----
 1 file changed, 21 insertions(+), 5 deletions(-)
Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt +21 -5
index 96c25ee..6532a59 100644
@@ -1,13 +1,19 @@
-Analog Device ADV7511(W)/13 HDMI Encoders
+Analog Device ADV7511(W)/13/33 HDMI Encoders
 -----------------------------------------
 
-The ADV7511, ADV7511W and ADV7513 are HDMI audio and video transmitters
+The ADV7511, ADV7511W, ADV7513 and ADV7533 are HDMI audio and video transmitters
 compatible with HDMI 1.4 and DVI 1.0. They support color space conversion,
-S/PDIF, CEC and HDCP.
+S/PDIF, CEC and HDCP. ADV7533 supports the DSI interface for input pixels, while
+the others support RGB interface.
 
 Required properties:
 
-- compatible: Should be one of "adi,adv7511", "adi,adv7511w" or "adi,adv7513"
+- compatible: Should be one of:
+		"adi,adv7511"
+		"adi,adv7511w"
+		"adi,adv7513"
+		"adi,adv7533"
+
 - reg: I2C slave address
 
 The ADV7511 supports a large number of input data formats that differ by their
@@ -32,6 +38,11 @@ The following input format properties are required except in "rgb 1x" and
 - adi,input-justification: The input bit justification ("left", "evenly",
   "right").
 
+The following properties are required for ADV7533:
+
+- adi,dsi-lanes: Number of DSI data lanes connected to the DSI host. It should
+  be one of 1, 2, 3 or 4.
+
 Optional properties:
 
 - interrupts: Specifier for the ADV7511 interrupt
@@ -42,13 +53,18 @@ Optional properties:
 - adi,embedded-sync: The input uses synchronization signals embedded in the
   data stream (similar to BT.656). Defaults to separate H/V synchronization
   signals.
+- adi,disable-timing-generator: Only for ADV7533. Disables the internal timing
+  generator. The chip will rely on the sync signals in the DSI data lanes,
+  rather than generate its own timings for HDMI output.
 
 Required nodes:
 
 The ADV7511 has two video ports. Their connections are modelled using the OF
 graph bindings specified in Documentation/devicetree/bindings/graph.txt.
 
-- Video port 0 for the RGB or YUV input
+- Video port 0 for the RGB, YUV or DSI input. In the case of ADV7533, the
+  remote endpoint phandle should be a reference to a valid mipi_dsi_host device
+  node.
 - Video port 1 for the HDMI output
 
 
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation