All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/5] drm/i2c: adv7511: ADV7533 support
@ 2015-07-27  6:16 Archit Taneja
  2015-07-27  6:16 ` [PATCH 1/5] drm/i2c: adv7511: Fix mutex deadlock when interrupts are disabled Archit Taneja
                   ` (5 more replies)
  0 siblings, 6 replies; 89+ messages in thread
From: Archit Taneja @ 2015-07-27  6:16 UTC (permalink / raw)
  To: dri-devel, lars
  Cc: linux-arm-msm, laurent.pinchart, andy.green, srinivas.kandagatla,
	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.

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(-)

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

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

* [PATCH 1/5] drm/i2c: adv7511: Fix mutex deadlock when interrupts are disabled
  2015-07-27  6:16 [PATCH 0/5] drm/i2c: adv7511: ADV7533 support Archit Taneja
@ 2015-07-27  6:16 ` Archit Taneja
  2015-07-27  6:16 ` [PATCH 2/5] drm/i2c: adv7511: Initial support for adv7533 Archit Taneja
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 89+ messages in thread
From: Archit Taneja @ 2015-07-27  6:16 UTC (permalink / raw)
  To: dri-devel, lars
  Cc: linux-arm-msm, andy.green, srinivas.kandagatla, laurent.pinchart

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.

Signed-off-by: Archit Taneja <architt@codeaurora.org>
---
 drivers/gpu/drm/i2c/adv7511.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/i2c/adv7511.c b/drivers/gpu/drm/i2c/adv7511.c
index 2aaa3c8..cf5bb29 100644
--- a/drivers/gpu/drm/i2c/adv7511.c
+++ b/drivers/gpu/drm/i2c/adv7511.c
@@ -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;
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [PATCH 2/5] drm/i2c: adv7511: Initial support for adv7533
  2015-07-27  6:16 [PATCH 0/5] drm/i2c: adv7511: ADV7533 support Archit Taneja
  2015-07-27  6:16 ` [PATCH 1/5] drm/i2c: adv7511: Fix mutex deadlock when interrupts are disabled Archit Taneja
@ 2015-07-27  6:16 ` Archit Taneja
  2015-07-28  3:27   ` Bjorn Andersson
  2015-07-27  6:16 ` [PATCH 3/5] drm/i2c: adv7511: Refactor encoder slave functions Archit Taneja
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 89+ messages in thread
From: Archit Taneja @ 2015-07-27  6:16 UTC (permalink / raw)
  To: dri-devel, lars
  Cc: linux-arm-msm, laurent.pinchart, andy.green, srinivas.kandagatla,
	Archit Taneja

From: Lars-Peter Clausen <lars@metafoo.de>

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.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Signed-off-by: Archit Taneja <architt@codeaurora.org>
---
 drivers/gpu/drm/i2c/adv7511.c | 155 +++++++++++++++++++++++++++++++++++-------
 1 file changed, 131 insertions(+), 24 deletions(-)

diff --git a/drivers/gpu/drm/i2c/adv7511.c b/drivers/gpu/drm/i2c/adv7511.c
index cf5bb29..63a3d20 100644
--- a/drivers/gpu/drm/i2c/adv7511.c
+++ b/drivers/gpu/drm/i2c/adv7511.c
@@ -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 = {
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

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

* [PATCH 3/5] drm/i2c: adv7511: Refactor encoder slave functions
  2015-07-27  6:16 [PATCH 0/5] drm/i2c: adv7511: ADV7533 support Archit Taneja
  2015-07-27  6:16 ` [PATCH 1/5] drm/i2c: adv7511: Fix mutex deadlock when interrupts are disabled Archit Taneja
  2015-07-27  6:16 ` [PATCH 2/5] drm/i2c: adv7511: Initial support for adv7533 Archit Taneja
@ 2015-07-27  6:16 ` Archit Taneja
  2015-07-27  8:59   ` Laurent Pinchart
  2015-07-27  6:16 ` [PATCH 4/5] drm/i2c: adv7511: Add drm_bridge/connector for ADV7533 Archit Taneja
                   ` (2 subsequent siblings)
  5 siblings, 1 reply; 89+ messages in thread
From: Archit Taneja @ 2015-07-27  6:16 UTC (permalink / raw)
  To: dri-devel, lars
  Cc: linux-arm-msm, laurent.pinchart, andy.green, srinivas.kandagatla,
	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.

Signed-off-by: Archit Taneja <architt@codeaurora.org>
---
 drivers/gpu/drm/i2c/adv7511.c | 80 ++++++++++++++++++++++++++++++-------------
 1 file changed, 57 insertions(+), 23 deletions(-)

diff --git a/drivers/gpu/drm/i2c/adv7511.c b/drivers/gpu/drm/i2c/adv7511.c
index 63a3d20..46fb24d 100644
--- a/drivers/gpu/drm/i2c/adv7511.c
+++ b/drivers/gpu/drm/i2c/adv7511.c
@@ -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,
 };
 
 /* -----------------------------------------------------------------------------
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

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

* [PATCH 4/5] drm/i2c: adv7511: Add drm_bridge/connector for ADV7533
  2015-07-27  6:16 [PATCH 0/5] drm/i2c: adv7511: ADV7533 support Archit Taneja
                   ` (2 preceding siblings ...)
  2015-07-27  6:16 ` [PATCH 3/5] drm/i2c: adv7511: Refactor encoder slave functions Archit Taneja
@ 2015-07-27  6:16 ` Archit Taneja
  2015-07-27  6:16 ` [PATCH 5/5] drm/i2c: adv7511: Create mipi_dsi_device " Archit Taneja
  2015-09-07 11:36 ` [PATCH v2 0/5] drm/i2c: adv7511: ADV7533 support Archit Taneja
  5 siblings, 0 replies; 89+ messages in thread
From: Archit Taneja @ 2015-07-27  6:16 UTC (permalink / raw)
  To: dri-devel, lars
  Cc: linux-arm-msm, laurent.pinchart, andy.green, srinivas.kandagatla,
	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.

Signed-off-by: Archit Taneja <architt@codeaurora.org>
---
 drivers/gpu/drm/i2c/adv7511.c | 155 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 155 insertions(+)

diff --git a/drivers/gpu/drm/i2c/adv7511.c b/drivers/gpu/drm/i2c/adv7511.c
index 46fb24d..10642e1 100644
--- a/drivers/gpu/drm/i2c/adv7511.c
+++ b/drivers/gpu/drm/i2c/adv7511.c
@@ -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;
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

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

* [PATCH 5/5] drm/i2c: adv7511: Create mipi_dsi_device for ADV7533
  2015-07-27  6:16 [PATCH 0/5] drm/i2c: adv7511: ADV7533 support Archit Taneja
                   ` (3 preceding siblings ...)
  2015-07-27  6:16 ` [PATCH 4/5] drm/i2c: adv7511: Add drm_bridge/connector for ADV7533 Archit Taneja
@ 2015-07-27  6:16 ` Archit Taneja
  2015-09-07 11:36 ` [PATCH v2 0/5] drm/i2c: adv7511: ADV7533 support Archit Taneja
  5 siblings, 0 replies; 89+ messages in thread
From: Archit Taneja @ 2015-07-27  6:16 UTC (permalink / raw)
  To: dri-devel, lars
  Cc: linux-arm-msm, laurent.pinchart, andy.green, srinivas.kandagatla,
	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.

Signed-off-by: Archit Taneja <architt@codeaurora.org>
---
 drivers/gpu/drm/i2c/adv7511.c | 106 +++++++++++++++++++++++++++++++++++++++---
 1 file changed, 99 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/i2c/adv7511.c b/drivers/gpu/drm/i2c/adv7511.c
index 10642e1..ccb57a9 100644
--- a/drivers/gpu/drm/i2c/adv7511.c
+++ b/drivers/gpu/drm/i2c/adv7511.c
@@ -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;
 }
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

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

* Re: [PATCH 3/5] drm/i2c: adv7511: Refactor encoder slave functions
  2015-07-27  6:16 ` [PATCH 3/5] drm/i2c: adv7511: Refactor encoder slave functions Archit Taneja
@ 2015-07-27  8:59   ` Laurent Pinchart
  2015-07-28  8:17     ` Archit Taneja
  2015-12-03 15:02     ` Rob Clark
  0 siblings, 2 replies; 89+ messages in thread
From: Laurent Pinchart @ 2015-07-27  8:59 UTC (permalink / raw)
  To: Archit Taneja
  Cc: dri-devel, lars, linux-arm-msm, andy.green, srinivas.kandagatla,
	Boris BREZILLON

Hi Archit,

(CC'ing Boris Brezillon)

Thank you for the patch.

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 
?

> 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.
> 
> Signed-off-by: Archit Taneja <architt@codeaurora.org>
> ---
>  drivers/gpu/drm/i2c/adv7511.c | 80 +++++++++++++++++++++++++++------------
>  1 file changed, 57 insertions(+), 23 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i2c/adv7511.c b/drivers/gpu/drm/i2c/adv7511.c
> index 63a3d20..46fb24d 100644
> --- a/drivers/gpu/drm/i2c/adv7511.c
> +++ b/drivers/gpu/drm/i2c/adv7511.c
> @@ -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,
>  };
> 
>  /*
> ---------------------------------------------------------------------------
> --

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH 2/5] drm/i2c: adv7511: Initial support for adv7533
  2015-07-27  6:16 ` [PATCH 2/5] drm/i2c: adv7511: Initial support for adv7533 Archit Taneja
@ 2015-07-28  3:27   ` Bjorn Andersson
  2015-08-03  5:39     ` Archit Taneja
  0 siblings, 1 reply; 89+ messages in thread
From: Bjorn Andersson @ 2015-07-28  3:27 UTC (permalink / raw)
  To: Archit Taneja
  Cc: dri-devel, lars, linux-arm-msm, andy.green, srinivas.kandagatla,
	laurent.pinchart

On Sun 26 Jul 23:16 PDT 2015, Archit Taneja wrote:

> From: Lars-Peter Clausen <lars@metafoo.de>
> 
[..]
> diff --git a/drivers/gpu/drm/i2c/adv7511.c b/drivers/gpu/drm/i2c/adv7511.c

[..]

>  
> +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.

> +
>  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);

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

> +		adv7511->type = (enum adv7511_type) of_id->data;
> +	} else {
> +		adv7511->type = id->driver_data;
> +	}
> +
[..]

>  
>  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);
> -

Regards,
Bjorn

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

* Re: [PATCH 3/5] drm/i2c: adv7511: Refactor encoder slave functions
  2015-07-27  8:59   ` Laurent Pinchart
@ 2015-07-28  8:17     ` Archit Taneja
  2015-07-28 14:38       ` Boris Brezillon
  2015-12-03 15:02     ` Rob Clark
  1 sibling, 1 reply; 89+ messages in thread
From: Archit Taneja @ 2015-07-28  8:17 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: linux-arm-msm, dri-devel, andy.green, srinivas.kandagatla

Hi,

On 07/27/2015 02:29 PM, Laurent Pinchart wrote:
> Hi Archit,
>
> (CC'ing Boris Brezillon)
>
> Thank you for the patch.
>
> 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.

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

>
> Boris, I know you were experimenting with that, do you have anything to report
> ?
>
>> 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.
>>
>> Signed-off-by: Archit Taneja <architt@codeaurora.org>
>> ---
>>   drivers/gpu/drm/i2c/adv7511.c | 80 +++++++++++++++++++++++++++------------
>>   1 file changed, 57 insertions(+), 23 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/i2c/adv7511.c b/drivers/gpu/drm/i2c/adv7511.c
>> index 63a3d20..46fb24d 100644
>> --- a/drivers/gpu/drm/i2c/adv7511.c
>> +++ b/drivers/gpu/drm/i2c/adv7511.c
>> @@ -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,
>>   };
>>
>>   /*
>> ---------------------------------------------------------------------------
>> --
>

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH 3/5] drm/i2c: adv7511: Refactor encoder slave functions
  2015-07-28  8:17     ` Archit Taneja
@ 2015-07-28 14:38       ` Boris Brezillon
  2015-07-31  5:26         ` Archit Taneja
  0 siblings, 1 reply; 89+ messages in thread
From: Boris Brezillon @ 2015-07-28 14:38 UTC (permalink / raw)
  To: Archit Taneja
  Cc: linux-arm-msm, dri-devel, andy.green, srinivas.kandagatla,
	Laurent Pinchart

Archit, Laurent,

On Tue, 28 Jul 2015 13:47:37 +0530
Archit Taneja <architt@codeaurora.org> wrote:

> Hi,
> 
> On 07/27/2015 02:29 PM, Laurent Pinchart wrote:
> > Hi Archit,
> >
> > (CC'ing Boris Brezillon)
> >
> > Thank you for the patch.
> >
> > 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.
> 
> 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.

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.

> 
> Archit
> 
> >
> > 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



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

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

* Re: [PATCH 3/5] drm/i2c: adv7511: Refactor encoder slave functions
  2015-07-28 14:38       ` Boris Brezillon
@ 2015-07-31  5:26         ` Archit Taneja
  2015-07-31  9:12           ` Boris Brezillon
  0 siblings, 1 reply; 89+ messages in thread
From: Archit Taneja @ 2015-07-31  5:26 UTC (permalink / raw)
  To: Boris Brezillon, Laurent Pinchart
  Cc: linux-arm-msm, dri-devel, andy.green, srinivas.kandagatla

Hi Boris, Laurent,

On 07/28/2015 08:08 PM, Boris Brezillon wrote:
> Archit, Laurent,
>
> On Tue, 28 Jul 2015 13:47:37 +0530
> Archit Taneja <architt@codeaurora.org> wrote:
>
>> Hi,
>>
>> On 07/27/2015 02:29 PM, Laurent Pinchart wrote:
>>> Hi Archit,
>>>
>>> (CC'ing Boris Brezillon)
>>>
>>> Thank you for the patch.
>>>
>>> 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.
>>
>> 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.
>
> 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.
>
>>
>> Archit
>>
>>>
>>> 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

>
> Best Regards,
>
> Boris
>
> [1]https://github.com/bbrezillon/linux-at91/tree/drm-encoder-chain-WIP
>
>
>

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH 3/5] drm/i2c: adv7511: Refactor encoder slave functions
  2015-07-31  5:26         ` Archit Taneja
@ 2015-07-31  9:12           ` Boris Brezillon
  2015-07-31 10:38             ` Archit Taneja
  2015-07-31 12:13             ` Rob Clark
  0 siblings, 2 replies; 89+ messages in thread
From: Boris Brezillon @ 2015-07-31  9:12 UTC (permalink / raw)
  To: Archit Taneja
  Cc: linux-arm-msm, dri-devel, andy.green, srinivas.kandagatla,
	Laurent Pinchart

Hi Archit,

On Fri, 31 Jul 2015 10:56:20 +0530
Archit Taneja <architt@codeaurora.org> wrote:

> Hi Boris, Laurent,
> 
> On 07/28/2015 08:08 PM, Boris Brezillon wrote:
> > Archit, Laurent,
> >
> > On Tue, 28 Jul 2015 13:47:37 +0530
> > Archit Taneja <architt@codeaurora.org> wrote:
> >
> >> Hi,
> >>
> >> On 07/27/2015 02:29 PM, Laurent Pinchart wrote:
> >>> Hi Archit,
> >>>
> >>> (CC'ing Boris Brezillon)
> >>>
> >>> Thank you for the patch.
> >>>
> >>> 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.
> >>
> >> 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.
> >
> > 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.
> >
> >>
> >> Archit
> >>
> >>>
> >>> 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.

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.

> 
> 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.

> 
> 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.

> 
> 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.

> 
> 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

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

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

* Re: [PATCH 3/5] drm/i2c: adv7511: Refactor encoder slave functions
  2015-07-31  9:12           ` Boris Brezillon
@ 2015-07-31 10:38             ` Archit Taneja
  2015-07-31 12:13             ` Rob Clark
  1 sibling, 0 replies; 89+ messages in thread
From: Archit Taneja @ 2015-07-31 10:38 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Laurent Pinchart, dri-devel, lars, linux-arm-msm, andy.green,
	srinivas.kandagatla, Daniel Vetter



On 07/31/2015 02:42 PM, Boris Brezillon wrote:
> Hi Archit,
>
> On Fri, 31 Jul 2015 10:56:20 +0530
> Archit Taneja <architt@codeaurora.org> wrote:
>
>> Hi Boris, Laurent,
>>
>> On 07/28/2015 08:08 PM, Boris Brezillon wrote:
>>> Archit, Laurent,
>>>
>>> On Tue, 28 Jul 2015 13:47:37 +0530
>>> Archit Taneja <architt@codeaurora.org> wrote:
>>>
>>>> Hi,
>>>>
>>>> On 07/27/2015 02:29 PM, Laurent Pinchart wrote:
>>>>> Hi Archit,
>>>>>
>>>>> (CC'ing Boris Brezillon)
>>>>>
>>>>> Thank you for the patch.
>>>>>
>>>>> 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.
>>>>
>>>> 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.
>>>
>>> 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.
>>>
>>>>
>>>> Archit
>>>>
>>>>>
>>>>> 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.
>
> 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.

>
>>
>> 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.
>
>>
>> 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.
>
>>
>> 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.

>
> 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.

>
>>
>> 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.

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

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

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

* Re: [PATCH 3/5] drm/i2c: adv7511: Refactor encoder slave functions
  2015-07-31  9:12           ` Boris Brezillon
  2015-07-31 10:38             ` Archit Taneja
@ 2015-07-31 12:13             ` Rob Clark
  2015-07-31 12:58               ` Boris Brezillon
  1 sibling, 1 reply; 89+ messages in thread
From: Rob Clark @ 2015-07-31 12:13 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Andy Green, linux-arm-msm, dri-devel, Srinivas Kandagatla,
	Laurent Pinchart

On Fri, Jul 31, 2015 at 5:12 AM, Boris Brezillon
<boris.brezillon@free-electrons.com> wrote:
> Hi Archit,
>
> On Fri, 31 Jul 2015 10:56:20 +0530
> Archit Taneja <architt@codeaurora.org> wrote:
>
>> Hi Boris, Laurent,
>>
>> On 07/28/2015 08:08 PM, Boris Brezillon wrote:
>> > Archit, Laurent,
>> >
>> > On Tue, 28 Jul 2015 13:47:37 +0530
>> > Archit Taneja <architt@codeaurora.org> wrote:
>> >
>> >> Hi,
>> >>
>> >> On 07/27/2015 02:29 PM, Laurent Pinchart wrote:
>> >>> Hi Archit,
>> >>>
>> >>> (CC'ing Boris Brezillon)
>> >>>
>> >>> Thank you for the patch.
>> >>>
>> >>> 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.
>> >>
>> >> 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.
>> >
>> > 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.
>> >
>> >>
>> >> Archit
>> >>
>> >>>
>> >>> 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.
>
> 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


>>
>> 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.
>
>>
>> 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.
>
>>
>> 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.
>
>>
>> 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
>
> --
> Boris Brezillon, Free Electrons
> Embedded Linux and Kernel engineering
> http://free-electrons.com
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH 3/5] drm/i2c: adv7511: Refactor encoder slave functions
  2015-07-31 12:13             ` Rob Clark
@ 2015-07-31 12:58               ` Boris Brezillon
  2015-07-31 14:48                 ` Rob Clark
  0 siblings, 1 reply; 89+ messages in thread
From: Boris Brezillon @ 2015-07-31 12:58 UTC (permalink / raw)
  To: Rob Clark
  Cc: Archit Taneja, linux-arm-msm, dri-devel, Andy Green,
	Srinivas Kandagatla, Laurent Pinchart

Hi Rob,

On Fri, 31 Jul 2015 08:13:59 -0400
Rob Clark <robdclark@gmail.com> wrote:

> >>
> >> 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.
> >
> > 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.

> 
> 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.

> 
> 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.

> 
> 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

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

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

* Re: [PATCH 3/5] drm/i2c: adv7511: Refactor encoder slave functions
  2015-07-31 12:58               ` Boris Brezillon
@ 2015-07-31 14:48                 ` Rob Clark
  2015-08-03 12:03                   ` Andrzej Hajda
  0 siblings, 1 reply; 89+ messages in thread
From: Rob Clark @ 2015-07-31 14:48 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Archit Taneja, linux-arm-msm, dri-devel, Andy Green,
	Srinivas Kandagatla, Laurent Pinchart

On Fri, Jul 31, 2015 at 8:58 AM, Boris Brezillon
<boris.brezillon@free-electrons.com> wrote:
> Hi Rob,
>
> On Fri, 31 Jul 2015 08:13:59 -0400
> Rob Clark <robdclark@gmail.com> wrote:
>
>> >>
>> >> 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.
>> >
>> > 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.
>
>>
>> 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.

chaining bridges is very recent addition, fwiw

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

>>
>> 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..

> 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.
>
>>
>> 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

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)

> 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

> 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

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

* Re: [PATCH 2/5] drm/i2c: adv7511: Initial support for adv7533
  2015-07-28  3:27   ` Bjorn Andersson
@ 2015-08-03  5:39     ` Archit Taneja
  0 siblings, 0 replies; 89+ messages in thread
From: Archit Taneja @ 2015-08-03  5:39 UTC (permalink / raw)
  To: Bjorn Andersson
  Cc: dri-devel, lars, linux-arm-msm, andy.green, srinivas.kandagatla,
	laurent.pinchart



On 07/28/2015 08:57 AM, Bjorn Andersson wrote:
> On Sun 26 Jul 23:16 PDT 2015, Archit Taneja wrote:
>
>> From: Lars-Peter Clausen <lars@metafoo.de>
>>
> [..]
>> diff --git a/drivers/gpu/drm/i2c/adv7511.c b/drivers/gpu/drm/i2c/adv7511.c
>
> [..]
>
>>
>> +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.
>
>> +
>>   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);
>
> 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

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

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

* Re: [PATCH 3/5] drm/i2c: adv7511: Refactor encoder slave functions
  2015-07-31 14:48                 ` Rob Clark
@ 2015-08-03 12:03                   ` Andrzej Hajda
  2015-08-03 14:04                     ` Rob Clark
  0 siblings, 1 reply; 89+ messages in thread
From: Andrzej Hajda @ 2015-08-03 12:03 UTC (permalink / raw)
  To: Rob Clark, Boris Brezillon
  Cc: Andy Green, linux-arm-msm, dri-devel, Srinivas Kandagatla,
	Laurent Pinchart

Hi,

On 07/31/2015 04:48 PM, Rob Clark wrote:
> On Fri, Jul 31, 2015 at 8:58 AM, Boris Brezillon
> <boris.brezillon@free-electrons.com> wrote:
>> Hi Rob,
>>
>> On Fri, 31 Jul 2015 08:13:59 -0400
>> Rob Clark <robdclark@gmail.com> wrote:
>>

(...)

>>
>> 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

> 
>> 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
> 
>> 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
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH 3/5] drm/i2c: adv7511: Refactor encoder slave functions
  2015-08-03 12:03                   ` Andrzej Hajda
@ 2015-08-03 14:04                     ` Rob Clark
  2015-08-04  5:16                       ` Andrzej Hajda
  0 siblings, 1 reply; 89+ messages in thread
From: Rob Clark @ 2015-08-03 14:04 UTC (permalink / raw)
  To: Andrzej Hajda
  Cc: Boris Brezillon, Archit Taneja, linux-arm-msm, dri-devel,
	Andy Green, Srinivas Kandagatla, Laurent Pinchart

On Mon, Aug 3, 2015 at 8:03 AM, Andrzej Hajda <a.hajda@samsung.com> wrote:
> Hi,
>
> On 07/31/2015 04:48 PM, Rob Clark wrote:
>> On Fri, Jul 31, 2015 at 8:58 AM, Boris Brezillon
>> <boris.brezillon@free-electrons.com> wrote:
>>> Hi Rob,
>>>
>>> On Fri, 31 Jul 2015 08:13:59 -0400
>>> Rob Clark <robdclark@gmail.com> wrote:
>>>
>
> (...)
>
>>>
>>> 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.

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

>
> Regards
> Andrzej
>
>>
>>> 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
>>
>>> 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
>

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

* Re: [PATCH 3/5] drm/i2c: adv7511: Refactor encoder slave functions
  2015-08-03 14:04                     ` Rob Clark
@ 2015-08-04  5:16                       ` Andrzej Hajda
  2015-08-04 12:24                         ` Rob Clark
  0 siblings, 1 reply; 89+ messages in thread
From: Andrzej Hajda @ 2015-08-04  5:16 UTC (permalink / raw)
  To: Rob Clark
  Cc: Boris Brezillon, Archit Taneja, linux-arm-msm, dri-devel,
	Andy Green, Srinivas Kandagatla, Laurent Pinchart

On 08/03/2015 04:04 PM, Rob Clark wrote:
> On Mon, Aug 3, 2015 at 8:03 AM, Andrzej Hajda <a.hajda@samsung.com> wrote:
>> Hi,
>>
>> On 07/31/2015 04:48 PM, Rob Clark wrote:
>>> On Fri, Jul 31, 2015 at 8:58 AM, Boris Brezillon
>>> <boris.brezillon@free-electrons.com> wrote:
>>>> Hi Rob,
>>>>
>>>> On Fri, 31 Jul 2015 08:13:59 -0400
>>>> Rob Clark <robdclark@gmail.com> wrote:
>>>>
>> (...)
>>
>>>> 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.
> 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

>
> BR,
> -R
>
>> Regards
>> Andrzej
>>
>>>> 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
>>>
>>>> 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

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

* Re: [PATCH 3/5] drm/i2c: adv7511: Refactor encoder slave functions
  2015-08-04  5:16                       ` Andrzej Hajda
@ 2015-08-04 12:24                         ` Rob Clark
  2015-09-02  6:30                           ` Archit Taneja
  0 siblings, 1 reply; 89+ messages in thread
From: Rob Clark @ 2015-08-04 12:24 UTC (permalink / raw)
  To: Andrzej Hajda
  Cc: Boris Brezillon, Archit Taneja, linux-arm-msm, dri-devel,
	Andy Green, Srinivas Kandagatla, Laurent Pinchart

On Tue, Aug 4, 2015 at 1:16 AM, Andrzej Hajda <a.hajda@samsung.com> wrote:
> On 08/03/2015 04:04 PM, Rob Clark wrote:
>> On Mon, Aug 3, 2015 at 8:03 AM, Andrzej Hajda <a.hajda@samsung.com> wrote:
>>> Hi,
>>>
>>> On 07/31/2015 04:48 PM, Rob Clark wrote:
>>>> On Fri, Jul 31, 2015 at 8:58 AM, Boris Brezillon
>>>> <boris.brezillon@free-electrons.com> wrote:
>>>>> Hi Rob,
>>>>>
>>>>> On Fri, 31 Jul 2015 08:13:59 -0400
>>>>> Rob Clark <robdclark@gmail.com> wrote:
>>>>>
>>> (...)
>>>
>>>>> 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.
>> 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

> Regards
> Andrzej
>
>>
>> BR,
>> -R
>>
>>> Regards
>>> Andrzej
>>>
>>>>> 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
>>>>
>>>>> 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
>

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

* Re: [PATCH 3/5] drm/i2c: adv7511: Refactor encoder slave functions
  2015-08-04 12:24                         ` Rob Clark
@ 2015-09-02  6:30                           ` Archit Taneja
  0 siblings, 0 replies; 89+ messages in thread
From: Archit Taneja @ 2015-09-02  6:30 UTC (permalink / raw)
  To: Rob Clark, Andrzej Hajda
  Cc: Boris Brezillon, linux-arm-msm, dri-devel, Andy Green,
	Srinivas Kandagatla, Laurent Pinchart



On 08/04/2015 05:54 PM, Rob Clark wrote:
> On Tue, Aug 4, 2015 at 1:16 AM, Andrzej Hajda <a.hajda@samsung.com> wrote:
>> On 08/03/2015 04:04 PM, Rob Clark wrote:
>>> On Mon, Aug 3, 2015 at 8:03 AM, Andrzej Hajda <a.hajda@samsung.com> wrote:
>>>> Hi,
>>>>
>>>> On 07/31/2015 04:48 PM, Rob Clark wrote:
>>>>> On Fri, Jul 31, 2015 at 8:58 AM, Boris Brezillon
>>>>> <boris.brezillon@free-electrons.com> wrote:
>>>>>> Hi Rob,
>>>>>>
>>>>>> On Fri, 31 Jul 2015 08:13:59 -0400
>>>>>> Rob Clark <robdclark@gmail.com> wrote:
>>>>>>
>>>> (...)
>>>>
>>>>>> 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.
>>> 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.

Could we get to a consensus for this?

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

Thanks,
Archit

>
> BR,
> -R
>
>> Regards
>> Andrzej
>>
>>>
>>> BR,
>>> -R
>>>
>>>> Regards
>>>> Andrzej
>>>>
>>>>>> 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
>>>>>
>>>>>> 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
>>

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

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

* [PATCH v2 0/5] drm/i2c: adv7511: ADV7533 support
  2015-07-27  6:16 [PATCH 0/5] drm/i2c: adv7511: ADV7533 support Archit Taneja
                   ` (4 preceding siblings ...)
  2015-07-27  6:16 ` [PATCH 5/5] drm/i2c: adv7511: Create mipi_dsi_device " Archit Taneja
@ 2015-09-07 11:36 ` Archit Taneja
  2015-09-07 11:36   ` [PATCH v2 1/5] drm/i2c: adv7511: Fix mutex deadlock when interrupts are disabled Archit Taneja
                     ` (5 more replies)
  5 siblings, 6 replies; 89+ messages in thread
From: Archit Taneja @ 2015-09-07 11:36 UTC (permalink / raw)
  To: dri-devel, lars, treding
  Cc: linux-arm-msm, laurent.pinchart, andy.green, srinivas.kandagatla,
	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(-)

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

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

* [PATCH v2 1/5] drm/i2c: adv7511: Fix mutex deadlock when interrupts are disabled
  2015-09-07 11:36 ` [PATCH v2 0/5] drm/i2c: adv7511: ADV7533 support Archit Taneja
@ 2015-09-07 11:36   ` Archit Taneja
  2015-09-07 11:36   ` [PATCH v2 2/5] drm/i2c: adv7511: Initial support for adv7533 Archit Taneja
                     ` (4 subsequent siblings)
  5 siblings, 0 replies; 89+ messages in thread
From: Archit Taneja @ 2015-09-07 11:36 UTC (permalink / raw)
  To: dri-devel, lars, treding
  Cc: linux-arm-msm, laurent.pinchart, andy.green, srinivas.kandagatla,
	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 interrupt context. It doesn't serve any purpose there anyway.

Signed-off-by: Archit Taneja <architt@codeaurora.org>
---
 drivers/gpu/drm/i2c/adv7511.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/i2c/adv7511.c b/drivers/gpu/drm/i2c/adv7511.c
index 2aaa3c8..cf5bb29 100644
--- a/drivers/gpu/drm/i2c/adv7511.c
+++ b/drivers/gpu/drm/i2c/adv7511.c
@@ -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;
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

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

* [PATCH v2 2/5] drm/i2c: adv7511: Initial support for adv7533
  2015-09-07 11:36 ` [PATCH v2 0/5] drm/i2c: adv7511: ADV7533 support Archit Taneja
  2015-09-07 11:36   ` [PATCH v2 1/5] drm/i2c: adv7511: Fix mutex deadlock when interrupts are disabled Archit Taneja
@ 2015-09-07 11:36   ` Archit Taneja
  2015-09-07 11:36   ` [PATCH v2 3/5] drm/i2c: adv7511: Refactor encoder slave functions Archit Taneja
                     ` (3 subsequent siblings)
  5 siblings, 0 replies; 89+ messages in thread
From: Archit Taneja @ 2015-09-07 11:36 UTC (permalink / raw)
  To: dri-devel, lars, treding
  Cc: linux-arm-msm, andy.green, srinivas.kandagatla, laurent.pinchart

From: Lars-Peter Clausen <lars@metafoo.de>

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.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
---
 drivers/gpu/drm/i2c/adv7511.c | 141 ++++++++++++++++++++++++++++++++++++------
 1 file changed, 122 insertions(+), 19 deletions(-)

diff --git a/drivers/gpu/drm/i2c/adv7511.c b/drivers/gpu/drm/i2c/adv7511.c
index cf5bb29..cf5961d5 100644
--- a/drivers/gpu/drm/i2c/adv7511.c
+++ b/drivers/gpu/drm/i2c/adv7511.c
@@ -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);
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [PATCH v2 3/5] drm/i2c: adv7511: Refactor encoder slave functions
  2015-09-07 11:36 ` [PATCH v2 0/5] drm/i2c: adv7511: ADV7533 support Archit Taneja
  2015-09-07 11:36   ` [PATCH v2 1/5] drm/i2c: adv7511: Fix mutex deadlock when interrupts are disabled Archit Taneja
  2015-09-07 11:36   ` [PATCH v2 2/5] drm/i2c: adv7511: Initial support for adv7533 Archit Taneja
@ 2015-09-07 11:36   ` Archit Taneja
  2015-09-07 11:36   ` [PATCH v2 4/5] drm/i2c: adv7511: Add drm_bridge/connector for ADV7533 Archit Taneja
                     ` (2 subsequent siblings)
  5 siblings, 0 replies; 89+ messages in thread
From: Archit Taneja @ 2015-09-07 11:36 UTC (permalink / raw)
  To: dri-devel, lars, treding
  Cc: linux-arm-msm, andy.green, srinivas.kandagatla, laurent.pinchart

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.

Signed-off-by: Archit Taneja <architt@codeaurora.org>
---
 drivers/gpu/drm/i2c/adv7511.c | 80 ++++++++++++++++++++++++++++++-------------
 1 file changed, 57 insertions(+), 23 deletions(-)

diff --git a/drivers/gpu/drm/i2c/adv7511.c b/drivers/gpu/drm/i2c/adv7511.c
index cf5961d5..e35ad37 100644
--- a/drivers/gpu/drm/i2c/adv7511.c
+++ b/drivers/gpu/drm/i2c/adv7511.c
@@ -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,
 };
 
 /* -----------------------------------------------------------------------------
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [PATCH v2 4/5] drm/i2c: adv7511: Add drm_bridge/connector for ADV7533
  2015-09-07 11:36 ` [PATCH v2 0/5] drm/i2c: adv7511: ADV7533 support Archit Taneja
                     ` (2 preceding siblings ...)
  2015-09-07 11:36   ` [PATCH v2 3/5] drm/i2c: adv7511: Refactor encoder slave functions Archit Taneja
@ 2015-09-07 11:36   ` Archit Taneja
  2015-09-07 11:36   ` [PATCH v2 5/5] drm/i2c: adv7511: Add dsi driver for adv7533 Archit Taneja
  2016-03-09 10:57   ` [PATCH v3 0/7] drm/i2c: adv7511: ADV7533 support Archit Taneja
  5 siblings, 0 replies; 89+ messages in thread
From: Archit Taneja @ 2015-09-07 11:36 UTC (permalink / raw)
  To: dri-devel, lars, treding
  Cc: linux-arm-msm, andy.green, srinivas.kandagatla, laurent.pinchart

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.

Signed-off-by: Archit Taneja <architt@codeaurora.org>
---
 drivers/gpu/drm/i2c/adv7511.c | 155 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 155 insertions(+)

diff --git a/drivers/gpu/drm/i2c/adv7511.c b/drivers/gpu/drm/i2c/adv7511.c
index e35ad37..b6c80e3 100644
--- a/drivers/gpu/drm/i2c/adv7511.c
+++ b/drivers/gpu/drm/i2c/adv7511.c
@@ -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;
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [PATCH v2 5/5] drm/i2c: adv7511: Add dsi driver for adv7533
  2015-09-07 11:36 ` [PATCH v2 0/5] drm/i2c: adv7511: ADV7533 support Archit Taneja
                     ` (3 preceding siblings ...)
  2015-09-07 11:36   ` [PATCH v2 4/5] drm/i2c: adv7511: Add drm_bridge/connector for ADV7533 Archit Taneja
@ 2015-09-07 11:36   ` Archit Taneja
  2016-03-09 10:57   ` [PATCH v3 0/7] drm/i2c: adv7511: ADV7533 support Archit Taneja
  5 siblings, 0 replies; 89+ messages in thread
From: Archit Taneja @ 2015-09-07 11:36 UTC (permalink / raw)
  To: dri-devel, lars, treding
  Cc: linux-arm-msm, laurent.pinchart, andy.green, srinivas.kandagatla,
	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.

Signed-off-by: Archit Taneja <architt@codeaurora.org>
---
 drivers/gpu/drm/i2c/adv7511.c | 98 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 97 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i2c/adv7511.c b/drivers/gpu/drm/i2c/adv7511.c
index b6c80e3..8325913 100644
--- a/drivers/gpu/drm/i2c/adv7511.c
+++ b/drivers/gpu/drm/i2c/adv7511.c
@@ -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);
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

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

* Re: [PATCH 3/5] drm/i2c: adv7511: Refactor encoder slave functions
  2015-07-27  8:59   ` Laurent Pinchart
  2015-07-28  8:17     ` Archit Taneja
@ 2015-12-03 15:02     ` Rob Clark
  2015-12-03 15:28       ` Laurent Pinchart
  1 sibling, 1 reply; 89+ messages in thread
From: Rob Clark @ 2015-12-03 15:02 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: linux-arm-msm, Andy Green, Srinivas Kandagatla, dri-devel

On Mon, Jul 27, 2015 at 4:59 AM, Laurent Pinchart
<laurent.pinchart@ideasonboard.com> wrote:
> Hi Archit,
>
> (CC'ing Boris Brezillon)
>
> Thank you for the patch.
>
> 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..)

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

> Boris, I know you were experimenting with that, do you have anything to report
> ?
>
>> 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.
>>
>> Signed-off-by: Archit Taneja <architt@codeaurora.org>
>> ---
>>  drivers/gpu/drm/i2c/adv7511.c | 80 +++++++++++++++++++++++++++------------
>>  1 file changed, 57 insertions(+), 23 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/i2c/adv7511.c b/drivers/gpu/drm/i2c/adv7511.c
>> index 63a3d20..46fb24d 100644
>> --- a/drivers/gpu/drm/i2c/adv7511.c
>> +++ b/drivers/gpu/drm/i2c/adv7511.c
>> @@ -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,
>>  };
>>
>>  /*
>> ---------------------------------------------------------------------------
>> --
>
> --
> Regards,
>
> Laurent Pinchart
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH 3/5] drm/i2c: adv7511: Refactor encoder slave functions
  2015-12-03 15:02     ` Rob Clark
@ 2015-12-03 15:28       ` Laurent Pinchart
  2015-12-03 15:55         ` Rob Clark
  0 siblings, 1 reply; 89+ messages in thread
From: Laurent Pinchart @ 2015-12-03 15:28 UTC (permalink / raw)
  To: Rob Clark
  Cc: Archit Taneja, linux-arm-msm, dri-devel, Andy Green, Srinivas Kandagatla

On Thursday 03 December 2015 10:02:02 Rob Clark wrote:
> On Mon, Jul 27, 2015 at 4:59 AM, Laurent Pinchart wrote:
> > 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..)

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).

> 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.

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH 3/5] drm/i2c: adv7511: Refactor encoder slave functions
  2015-12-03 15:28       ` Laurent Pinchart
@ 2015-12-03 15:55         ` Rob Clark
  2015-12-03 16:06           ` Laurent Pinchart
  2015-12-03 16:11           ` Archit Taneja
  0 siblings, 2 replies; 89+ messages in thread
From: Rob Clark @ 2015-12-03 15:55 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Archit Taneja, linux-arm-msm, dri-devel, Andy Green, Srinivas Kandagatla

On Thu, Dec 3, 2015 at 10:28 AM, Laurent Pinchart
<laurent.pinchart@ideasonboard.com> wrote:
> On Thursday 03 December 2015 10:02:02 Rob Clark wrote:
>> On Mon, Jul 27, 2015 at 4:59 AM, Laurent Pinchart wrote:
>> > 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..)
>
> 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.

>> 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.

> 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

> --
> Regards,
>
> Laurent Pinchart
>

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

* Re: [PATCH 3/5] drm/i2c: adv7511: Refactor encoder slave functions
  2015-12-03 15:55         ` Rob Clark
@ 2015-12-03 16:06           ` Laurent Pinchart
  2015-12-03 16:11           ` Archit Taneja
  1 sibling, 0 replies; 89+ messages in thread
From: Laurent Pinchart @ 2015-12-03 16:06 UTC (permalink / raw)
  To: Rob Clark; +Cc: linux-arm-msm, Andy Green, Srinivas Kandagatla, dri-devel

Hi Rob,

On Thursday 03 December 2015 10:55:12 Rob Clark wrote:
> On Thu, Dec 3, 2015 at 10:28 AM, Laurent Pinchart wrote:
> > On Thursday 03 December 2015 10:02:02 Rob Clark wrote:
> >> On Mon, Jul 27, 2015 at 4:59 AM, Laurent Pinchart wrote:
> >>> 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..)
> > 
> > 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 ;-)

> 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.
> 
> >> 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>

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.

> 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.
> 
> > 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.

-- 
Regards,

Laurent Pinchart

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH 3/5] drm/i2c: adv7511: Refactor encoder slave functions
  2015-12-03 15:55         ` Rob Clark
  2015-12-03 16:06           ` Laurent Pinchart
@ 2015-12-03 16:11           ` Archit Taneja
  2016-01-09 17:03             ` Archit Taneja
  1 sibling, 1 reply; 89+ messages in thread
From: Archit Taneja @ 2015-12-03 16:11 UTC (permalink / raw)
  To: Rob Clark, Laurent Pinchart
  Cc: linux-arm-msm, dri-devel, Andy Green, Srinivas Kandagatla



On 12/3/2015 9:25 PM, Rob Clark wrote:
> On Thu, Dec 3, 2015 at 10:28 AM, Laurent Pinchart
> <laurent.pinchart@ideasonboard.com> wrote:
>> On Thursday 03 December 2015 10:02:02 Rob Clark wrote:
>>> On Mon, Jul 27, 2015 at 4:59 AM, Laurent Pinchart wrote:
>>>> 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..)
>>
>> 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.
>
>>> 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.
>
>> 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.

>
> 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

>
> BR,
> -R
>
>> --
>> Regards,
>>
>> Laurent Pinchart
>>

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

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

* Re: [PATCH 3/5] drm/i2c: adv7511: Refactor encoder slave functions
  2015-12-03 16:11           ` Archit Taneja
@ 2016-01-09 17:03             ` Archit Taneja
  0 siblings, 0 replies; 89+ messages in thread
From: Archit Taneja @ 2016-01-09 17:03 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Rob Clark, linux-arm-msm, dri-devel, Andy Green, Srinivas Kandagatla

Hi Laurent,

On 12/3/2015 9:41 PM, Archit Taneja wrote:
>
>
> On 12/3/2015 9:25 PM, Rob Clark wrote:
>> On Thu, Dec 3, 2015 at 10:28 AM, Laurent Pinchart
>> <laurent.pinchart@ideasonboard.com> wrote:
>>> On Thursday 03 December 2015 10:02:02 Rob Clark wrote:
>>>> On Mon, Jul 27, 2015 at 4:59 AM, Laurent Pinchart wrote:
>>>>> 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>

>
> 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.
>

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

>
>>
>> BR,
>> -R
>>
>>> --
>>> Regards,
>>>
>>> Laurent Pinchart
>>>
>

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

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

* [PATCH v3 0/7] drm/i2c: adv7511: ADV7533 support
  2015-09-07 11:36 ` [PATCH v2 0/5] drm/i2c: adv7511: ADV7533 support Archit Taneja
                     ` (4 preceding siblings ...)
  2015-09-07 11:36   ` [PATCH v2 5/5] drm/i2c: adv7511: Add dsi driver for adv7533 Archit Taneja
@ 2016-03-09 10:57   ` Archit Taneja
  2016-03-09 10:57     ` [PATCH v3 1/7] drm/i2c: adv7511: Convert to drm_bridge Archit Taneja
                       ` (10 more replies)
  5 siblings, 11 replies; 89+ messages in thread
From: Archit Taneja @ 2016-03-09 10:57 UTC (permalink / raw)
  To: dri-devel
  Cc: andy.green, linux-arm-msm, amit.kucheria, srinivas.kandagatla,
	laurent.pinchart, treding

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(-)

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

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [PATCH v3 1/7] drm/i2c: adv7511: Convert to drm_bridge
  2016-03-09 10:57   ` [PATCH v3 0/7] drm/i2c: adv7511: ADV7533 support Archit Taneja
@ 2016-03-09 10:57     ` Archit Taneja
  2016-03-09 10:57     ` [PATCH v3 2/7] drm/i2c: adv7511: Fix mutex deadlock when interrupts are disabled Archit Taneja
                       ` (9 subsequent siblings)
  10 siblings, 0 replies; 89+ messages in thread
From: Archit Taneja @ 2016-03-09 10:57 UTC (permalink / raw)
  To: dri-devel
  Cc: andy.green, linux-arm-msm, amit.kucheria, srinivas.kandagatla,
	laurent.pinchart, treding

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.

Signed-off-by: Archit Taneja <architt@codeaurora.org>
---
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(-)

diff --git a/drivers/gpu/drm/i2c/adv7511.c b/drivers/gpu/drm/i2c/adv7511.c
index a02112b..fec5627 100644
--- a/drivers/gpu/drm/i2c/adv7511.c
+++ b/drivers/gpu/drm/i2c/adv7511.c
@@ -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 <lars@metafoo.de>");
 MODULE_DESCRIPTION("ADV7511 HDMI transmitter driver");
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [PATCH v3 2/7] drm/i2c: adv7511: Fix mutex deadlock when interrupts are disabled
  2016-03-09 10:57   ` [PATCH v3 0/7] drm/i2c: adv7511: ADV7533 support Archit Taneja
  2016-03-09 10:57     ` [PATCH v3 1/7] drm/i2c: adv7511: Convert to drm_bridge Archit Taneja
@ 2016-03-09 10:57     ` Archit Taneja
  2016-03-09 10:57     ` [PATCH v3 3/7] drm/i2c: adv7511: Initial support for ADV7533 Archit Taneja
                       ` (8 subsequent siblings)
  10 siblings, 0 replies; 89+ messages in thread
From: Archit Taneja @ 2016-03-09 10:57 UTC (permalink / raw)
  To: dri-devel
  Cc: airlied, daniel, treding, linux-arm-msm, srinivas.kandagatla,
	andy.green, laurent.pinchart, lars, xinliang.liu, amit.kucheria,
	robdclark, 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.

Signed-off-by: Archit Taneja <architt@codeaurora.org>
---
 drivers/gpu/drm/i2c/adv7511.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/i2c/adv7511.c b/drivers/gpu/drm/i2c/adv7511.c
index fec5627..c00d11d 100644
--- a/drivers/gpu/drm/i2c/adv7511.c
+++ b/drivers/gpu/drm/i2c/adv7511.c
@@ -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;
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

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

* [PATCH v3 3/7] drm/i2c: adv7511: Initial support for ADV7533
  2016-03-09 10:57   ` [PATCH v3 0/7] drm/i2c: adv7511: ADV7533 support Archit Taneja
  2016-03-09 10:57     ` [PATCH v3 1/7] drm/i2c: adv7511: Convert to drm_bridge Archit Taneja
  2016-03-09 10:57     ` [PATCH v3 2/7] drm/i2c: adv7511: Fix mutex deadlock when interrupts are disabled Archit Taneja
@ 2016-03-09 10:57     ` Archit Taneja
  2016-03-09 10:57     ` [PATCH v3 4/7] drm/i2c: adv7511: Create a MIPI DSI device Archit Taneja
                       ` (7 subsequent siblings)
  10 siblings, 0 replies; 89+ messages in thread
From: Archit Taneja @ 2016-03-09 10:57 UTC (permalink / raw)
  To: dri-devel
  Cc: andy.green, linux-arm-msm, amit.kucheria, srinivas.kandagatla,
	laurent.pinchart, treding

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 <lars@metafoo.de>

Signed-off-by: Archit Taneja <architt@codeaurora.org>
---
 drivers/gpu/drm/i2c/adv7511.c | 138 ++++++++++++++++++++++++++++++++++++------
 1 file changed, 120 insertions(+), 18 deletions(-)

diff --git a/drivers/gpu/drm/i2c/adv7511.c b/drivers/gpu/drm/i2c/adv7511.c
index c00d11d..75be17c 100644
--- a/drivers/gpu/drm/i2c/adv7511.c
+++ b/drivers/gpu/drm/i2c/adv7511.c
@@ -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);
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [PATCH v3 4/7] drm/i2c: adv7511: Create a MIPI DSI device
  2016-03-09 10:57   ` [PATCH v3 0/7] drm/i2c: adv7511: ADV7533 support Archit Taneja
                       ` (2 preceding siblings ...)
  2016-03-09 10:57     ` [PATCH v3 3/7] drm/i2c: adv7511: Initial support for ADV7533 Archit Taneja
@ 2016-03-09 10:57     ` Archit Taneja
  2016-04-21 22:29       ` Laurent Pinchart
  2016-03-09 10:57     ` [PATCH v3 5/7] drm/i2c: adv7511: Use internal timing generator Archit Taneja
                       ` (6 subsequent siblings)
  10 siblings, 1 reply; 89+ messages in thread
From: Archit Taneja @ 2016-03-09 10:57 UTC (permalink / raw)
  To: dri-devel
  Cc: andy.green, linux-arm-msm, amit.kucheria, srinivas.kandagatla,
	laurent.pinchart, treding

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.

Signed-off-by: Archit Taneja <architt@codeaurora.org>
---
 drivers/gpu/drm/i2c/adv7511.c | 130 +++++++++++++++++++++++++++++++++++++++---
 1 file changed, 123 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/i2c/adv7511.c b/drivers/gpu/drm/i2c/adv7511.c
index 75be17c..6c2a89a 100644
--- a/drivers/gpu/drm/i2c/adv7511.c
+++ b/drivers/gpu/drm/i2c/adv7511.c
@@ -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 <lars@metafoo.de>");
 MODULE_DESCRIPTION("ADV7511 HDMI transmitter driver");
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [PATCH v3 5/7] drm/i2c: adv7511: Use internal timing generator
  2016-03-09 10:57   ` [PATCH v3 0/7] drm/i2c: adv7511: ADV7533 support Archit Taneja
                       ` (3 preceding siblings ...)
  2016-03-09 10:57     ` [PATCH v3 4/7] drm/i2c: adv7511: Create a MIPI DSI device Archit Taneja
@ 2016-03-09 10:57     ` Archit Taneja
  2016-03-09 10:57     ` [PATCH v3 6/7] drm/i2c: adv7511: Change number of DSI lanes dynamically Archit Taneja
                       ` (5 subsequent siblings)
  10 siblings, 0 replies; 89+ messages in thread
From: Archit Taneja @ 2016-03-09 10:57 UTC (permalink / raw)
  To: dri-devel
  Cc: andy.green, linux-arm-msm, amit.kucheria, srinivas.kandagatla,
	laurent.pinchart, treding

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.

Signed-off-by: Archit Taneja <architt@codeaurora.org>
---
 drivers/gpu/drm/i2c/adv7511.c | 65 +++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 63 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/i2c/adv7511.c b/drivers/gpu/drm/i2c/adv7511.c
index 6c2a89a..88918ae 100644
--- a/drivers/gpu/drm/i2c/adv7511.c
+++ b/drivers/gpu/drm/i2c/adv7511.c
@@ -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;
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [PATCH v3 6/7] drm/i2c: adv7511: Change number of DSI lanes dynamically
  2016-03-09 10:57   ` [PATCH v3 0/7] drm/i2c: adv7511: ADV7533 support Archit Taneja
                       ` (4 preceding siblings ...)
  2016-03-09 10:57     ` [PATCH v3 5/7] drm/i2c: adv7511: Use internal timing generator Archit Taneja
@ 2016-03-09 10:57     ` Archit Taneja
       [not found]     ` <1457521038-5906-1-git-send-email-architt-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
                       ` (4 subsequent siblings)
  10 siblings, 0 replies; 89+ messages in thread
From: Archit Taneja @ 2016-03-09 10:57 UTC (permalink / raw)
  To: dri-devel
  Cc: airlied, daniel, treding, linux-arm-msm, srinivas.kandagatla,
	andy.green, laurent.pinchart, lars, xinliang.liu, amit.kucheria,
	robdclark, 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 <andy.green@linaro.org>

Signed-off-by: Archit Taneja <architt@codeaurora.org>
---
 drivers/gpu/drm/i2c/adv7511.c | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/drivers/gpu/drm/i2c/adv7511.c b/drivers/gpu/drm/i2c/adv7511.c
index 88918ae..ca9e862 100644
--- a/drivers/gpu/drm/i2c/adv7511.c
+++ b/drivers/gpu/drm/i2c/adv7511.c
@@ -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);
 
 	/*
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

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

* [PATCH v3 7/7] dt-bindings: drm/bridge: Update bindings for ADV7533
       [not found]     ` <1457521038-5906-1-git-send-email-architt-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
@ 2016-03-09 10:57       ` Archit Taneja
  2016-03-17 19:12         ` Rob Herring
  2016-04-21 22:32         ` Laurent Pinchart
  0 siblings, 2 replies; 89+ messages in thread
From: Archit Taneja @ 2016-03-09 10:57 UTC (permalink / raw)
  To: dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW
  Cc: airlied-cv59FeDIM0c, daniel-/w4YWyX8dFk,
	treding-DDmLM1+adcrQT0dZR+AlfA,
	linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
	srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A,
	andy.green-QSEj5FYQhm4dnm+yROfE0A,
	laurent.pinchart-ryLnwIuWjnjg/C1BVhZhaw,
	lars-Qo5EllUWu/uELgA04lAiVw, xinliang.liu-QSEj5FYQhm4dnm+yROfE0A,
	amit.kucheria-QSEj5FYQhm4dnm+yROfE0A,
	robdclark-Re5JQEeQqe8AvxtiuMwx3w, Archit Taneja,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Rob Herring

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

Cc: devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Cc: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>

Signed-off-by: Archit Taneja <architt-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
---
 .../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
--- a/Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt
+++ b/Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt
@@ -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
 
 
-- 
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 majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH v3 7/7] dt-bindings: drm/bridge: Update bindings for ADV7533
  2016-03-09 10:57       ` [PATCH v3 7/7] dt-bindings: drm/bridge: Update bindings for ADV7533 Archit Taneja
@ 2016-03-17 19:12         ` Rob Herring
  2016-04-21 22:32         ` Laurent Pinchart
  1 sibling, 0 replies; 89+ messages in thread
From: Rob Herring @ 2016-03-17 19:12 UTC (permalink / raw)
  To: Archit Taneja
  Cc: devicetree, andy.green, linux-arm-msm, dri-devel,
	srinivas.kandagatla, laurent.pinchart, treding, amit.kucheria

On Wed, Mar 09, 2016 at 04:27:18PM +0530, Archit Taneja wrote:
> Add description of ADV7533. Add the required and optional properties that
> are specific to it.
> 
> Cc: devicetree@vger.kernel.org
> Cc: Rob Herring <robh@kernel.org>
> 
> Signed-off-by: Archit Taneja <architt@codeaurora.org>
> ---
>  .../bindings/display/bridge/adi,adv7511.txt        | 25 +++++++++++++++++-----
>  1 file changed, 20 insertions(+), 5 deletions(-)

Acked-by: Rob Herring <robh@kernel.org>
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v3 0/7] drm/i2c: adv7511: ADV7533 support
  2016-03-09 10:57   ` [PATCH v3 0/7] drm/i2c: adv7511: ADV7533 support Archit Taneja
                       ` (6 preceding siblings ...)
       [not found]     ` <1457521038-5906-1-git-send-email-architt-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
@ 2016-04-14 14:56     ` Archit Taneja
  2016-04-21 22:33       ` Laurent Pinchart
  2016-04-17 11:31     ` Xinliang Liu
                       ` (2 subsequent siblings)
  10 siblings, 1 reply; 89+ messages in thread
From: Archit Taneja @ 2016-04-14 14:56 UTC (permalink / raw)
  To: dri-devel, laurent.pinchart
  Cc: andy.green, linux-arm-msm, amit.kucheria, srinivas.kandagatla, treding

Hi Laurent,

On 3/9/2016 4:27 PM, Archit Taneja wrote:
> 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.

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

Thanks,
Archit

>
> [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(-)
>

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v3 0/7] drm/i2c: adv7511: ADV7533 support
  2016-03-09 10:57   ` [PATCH v3 0/7] drm/i2c: adv7511: ADV7533 support Archit Taneja
                       ` (7 preceding siblings ...)
  2016-04-14 14:56     ` [PATCH v3 0/7] drm/i2c: adv7511: ADV7533 support Archit Taneja
@ 2016-04-17 11:31     ` Xinliang Liu
  2016-04-18  9:48       ` Archit Taneja
  2016-05-03  1:52     ` Xinliang Liu
  2016-05-16 10:41     ` [PATCH v4 " Archit Taneja
  10 siblings, 1 reply; 89+ messages in thread
From: Xinliang Liu @ 2016-04-17 11:31 UTC (permalink / raw)
  To: Archit Taneja
  Cc: Andy Green, linux-arm-msm, dri-devel, Srinivas Kandagatla,
	laurent.pinchart, treding, Amit Kucheria

Hi Archit,
Thank you for the patches.

On 9 March 2016 at 18:57, Archit Taneja <architt@codeaurora.org> wrote:
> 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.

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.

>
> 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

> 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
>
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v3 0/7] drm/i2c: adv7511: ADV7533 support
  2016-04-17 11:31     ` Xinliang Liu
@ 2016-04-18  9:48       ` Archit Taneja
  2016-04-19  8:44         ` Xinliang Liu
  2016-04-21 22:36         ` Laurent Pinchart
  0 siblings, 2 replies; 89+ messages in thread
From: Archit Taneja @ 2016-04-18  9:48 UTC (permalink / raw)
  To: Xinliang Liu, laurent.pinchart
  Cc: dri-devel, David Airlie, Daniel Vetter, treding, linux-arm-msm,
	Srinivas Kandagatla, lars, Amit Kucheria, Rob Clark

Hi,

On 04/17/2016 05:01 PM, Xinliang Liu wrote:
> Hi Archit,
> Thank you for the patches.
>
> On 9 March 2016 at 18:57, Archit Taneja <architt@codeaurora.org> wrote:
>> 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.
>
> 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.

>
> 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.
>
>>
>> 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.

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

>
> Thanks,
> -xinliang
>
>> 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
>>

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

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

* Re: [PATCH v3 0/7] drm/i2c: adv7511: ADV7533 support
  2016-04-18  9:48       ` Archit Taneja
@ 2016-04-19  8:44         ` Xinliang Liu
  2016-04-21 22:36         ` Laurent Pinchart
  1 sibling, 0 replies; 89+ messages in thread
From: Xinliang Liu @ 2016-04-19  8:44 UTC (permalink / raw)
  To: Archit Taneja
  Cc: linux-arm-msm, dri-devel, Srinivas Kandagatla, laurent.pinchart,
	treding, Amit Kucheria

On 18 April 2016 at 17:48, Archit Taneja <architt@codeaurora.org> wrote:
> Hi,
>
>
> On 04/17/2016 05:01 PM, Xinliang Liu wrote:
>>
>> Hi Archit,
>> Thank you for the patches.
>>
>> On 9 March 2016 at 18:57, Archit Taneja <architt@codeaurora.org> wrote:
>>>
>>> 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.
>>
>>
>> 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.

This is great, if we have the plan.

>
>>
>> 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.
>>
>>>
>>> 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.
>
>
> 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

>
> Thanks,
> Archit
>
>
>>
>> Thanks,
>> -xinliang
>>
>>> 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
>>>
>
> --
> The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
> hosted by The Linux Foundation
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v3 4/7] drm/i2c: adv7511: Create a MIPI DSI device
  2016-03-09 10:57     ` [PATCH v3 4/7] drm/i2c: adv7511: Create a MIPI DSI device Archit Taneja
@ 2016-04-21 22:29       ` Laurent Pinchart
  2016-04-22  5:10         ` Archit Taneja
  0 siblings, 1 reply; 89+ messages in thread
From: Laurent Pinchart @ 2016-04-21 22:29 UTC (permalink / raw)
  To: Archit Taneja
  Cc: andy.green, linux-arm-msm, dri-devel, srinivas.kandagatla,
	amit.kucheria, treding

Hi Archit,

Thank you for the patch.

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.
> 
> Signed-off-by: Archit Taneja <architt@codeaurora.org>

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 ?

> ---
>  drivers/gpu/drm/i2c/adv7511.c | 130 ++++++++++++++++++++++++++++++++++++---
>  1 file changed, 123 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i2c/adv7511.c b/drivers/gpu/drm/i2c/adv7511.c
> index 75be17c..6c2a89a 100644
> --- a/drivers/gpu/drm/i2c/adv7511.c
> +++ b/drivers/gpu/drm/i2c/adv7511.c
> @@ -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 <lars@metafoo.de>");
>  MODULE_DESCRIPTION("ADV7511 HDMI transmitter driver");

-- 
Regards,

Laurent Pinchart

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v3 7/7] dt-bindings: drm/bridge: Update bindings for ADV7533
  2016-03-09 10:57       ` [PATCH v3 7/7] dt-bindings: drm/bridge: Update bindings for ADV7533 Archit Taneja
  2016-03-17 19:12         ` Rob Herring
@ 2016-04-21 22:32         ` Laurent Pinchart
  2016-04-22  5:40           ` Archit Taneja
  1 sibling, 1 reply; 89+ messages in thread
From: Laurent Pinchart @ 2016-04-21 22:32 UTC (permalink / raw)
  To: Archit Taneja
  Cc: devicetree, andy.green, linux-arm-msm, dri-devel,
	srinivas.kandagatla, amit.kucheria, treding

Hi Archit,

Thank you for the patch.

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.
> 
> Cc: devicetree@vger.kernel.org
> Cc: Rob Herring <robh@kernel.org>
> 
> Signed-off-by: Archit Taneja <architt@codeaurora.org>
> ---
>  .../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
> --- a/Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt
> +++ b/Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt
> @@ -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.

Does the ADV7533 support data lanes remapping ?

>  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.

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

>  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".

> node. - Video port 1 for the HDMI output

-- 
Regards,

Laurent Pinchart

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v3 0/7] drm/i2c: adv7511: ADV7533 support
  2016-04-14 14:56     ` [PATCH v3 0/7] drm/i2c: adv7511: ADV7533 support Archit Taneja
@ 2016-04-21 22:33       ` Laurent Pinchart
  2016-04-22  5:45         ` Archit Taneja
  0 siblings, 1 reply; 89+ messages in thread
From: Laurent Pinchart @ 2016-04-21 22:33 UTC (permalink / raw)
  To: Archit Taneja
  Cc: andy.green, linux-arm-msm, dri-devel, srinivas.kandagatla,
	amit.kucheria, treding

Hi Archit,

On Thursday 14 Apr 2016 20:26:11 Archit Taneja wrote:
> On 3/9/2016 4:27 PM, Archit Taneja wrote:
> > 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.
> 
> 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,

Tested-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

> > [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(-)

-- 
Regards,

Laurent Pinchart

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v3 0/7] drm/i2c: adv7511: ADV7533 support
  2016-04-18  9:48       ` Archit Taneja
  2016-04-19  8:44         ` Xinliang Liu
@ 2016-04-21 22:36         ` Laurent Pinchart
  2016-04-22  5:44           ` Archit Taneja
  1 sibling, 1 reply; 89+ messages in thread
From: Laurent Pinchart @ 2016-04-21 22:36 UTC (permalink / raw)
  To: Archit Taneja
  Cc: Xinliang Liu, dri-devel, David Airlie, Daniel Vetter, treding,
	linux-arm-msm, Srinivas Kandagatla, lars, Amit Kucheria,
	Rob Clark

Hi Archit,

On Monday 18 Apr 2016 15:18:30 Archit Taneja wrote:
> On 04/17/2016 05:01 PM, Xinliang Liu wrote:
> > On 9 March 2016 at 18:57, Archit Taneja <architt@codeaurora.org> wrote:
> >> 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.
> > 
> > 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.

Do you think you'd have time to lead that effort ?

> > 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.
> > 
> >> 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.
> 
> 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.
> 
> >> 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(-)

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v3 4/7] drm/i2c: adv7511: Create a MIPI DSI device
  2016-04-21 22:29       ` Laurent Pinchart
@ 2016-04-22  5:10         ` Archit Taneja
  2016-05-03  6:57           ` Archit Taneja
  0 siblings, 1 reply; 89+ messages in thread
From: Archit Taneja @ 2016-04-22  5:10 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: dri-devel, airlied, daniel, treding, linux-arm-msm,
	srinivas.kandagatla, andy.green, lars, xinliang.liu,
	amit.kucheria, robdclark

Hi Laurent,


On 04/22/2016 03:59 AM, Laurent Pinchart wrote:
> Hi Archit,
>
> Thank you for the patch.
>
> 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.
>>
>> Signed-off-by: Archit Taneja <architt@codeaurora.org>
>
> 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

>
>> ---
>>   drivers/gpu/drm/i2c/adv7511.c | 130 ++++++++++++++++++++++++++++++++++++---
>>   1 file changed, 123 insertions(+), 7 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/i2c/adv7511.c b/drivers/gpu/drm/i2c/adv7511.c
>> index 75be17c..6c2a89a 100644
>> --- a/drivers/gpu/drm/i2c/adv7511.c
>> +++ b/drivers/gpu/drm/i2c/adv7511.c
>> @@ -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 <lars@metafoo.de>");
>>   MODULE_DESCRIPTION("ADV7511 HDMI transmitter driver");
>

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

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

* Re: [PATCH v3 7/7] dt-bindings: drm/bridge: Update bindings for ADV7533
  2016-04-21 22:32         ` Laurent Pinchart
@ 2016-04-22  5:40           ` Archit Taneja
       [not found]             ` <5719B942.8070907-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
  0 siblings, 1 reply; 89+ messages in thread
From: Archit Taneja @ 2016-04-22  5:40 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: dri-devel, airlied, daniel, treding, linux-arm-msm,
	srinivas.kandagatla, andy.green, lars, xinliang.liu,
	amit.kucheria, robdclark, devicetree, Rob Herring



On 04/22/2016 04:02 AM, Laurent Pinchart wrote:
> Hi Archit,
>
> Thank you for the patch.
>
> 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.
>>
>> Cc: devicetree@vger.kernel.org
>> Cc: Rob Herring <robh@kernel.org>
>>
>> Signed-off-by: Archit Taneja <architt@codeaurora.org>
>> ---
>>   .../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
>> --- a/Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt
>> +++ b/Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt
>> @@ -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.
>
> 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.

>
>>   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.
>
> 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.

>
>>   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

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

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

* Re: [PATCH v3 0/7] drm/i2c: adv7511: ADV7533 support
  2016-04-21 22:36         ` Laurent Pinchart
@ 2016-04-22  5:44           ` Archit Taneja
  0 siblings, 0 replies; 89+ messages in thread
From: Archit Taneja @ 2016-04-22  5:44 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: linux-arm-msm, dri-devel, Srinivas Kandagatla, Amit Kucheria, treding



On 04/22/2016 04:06 AM, Laurent Pinchart wrote:
> Hi Archit,
>
> On Monday 18 Apr 2016 15:18:30 Archit Taneja wrote:
>> On 04/17/2016 05:01 PM, Xinliang Liu wrote:
>>> On 9 March 2016 at 18:57, Archit Taneja <architt@codeaurora.org> wrote:
>>>> 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.
>>>
>>> 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.
>
> 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

-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora 
Forum, hosted by The Linux Foundation
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v3 0/7] drm/i2c: adv7511: ADV7533 support
  2016-04-21 22:33       ` Laurent Pinchart
@ 2016-04-22  5:45         ` Archit Taneja
  0 siblings, 0 replies; 89+ messages in thread
From: Archit Taneja @ 2016-04-22  5:45 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: linux-arm-msm, dri-devel, srinivas.kandagatla, amit.kucheria, treding



On 04/22/2016 04:03 AM, Laurent Pinchart wrote:
> Hi Archit,
>
> On Thursday 14 Apr 2016 20:26:11 Archit Taneja wrote:
>> On 3/9/2016 4:27 PM, Archit Taneja wrote:
>>> 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.
>>
>> 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,
>
> Tested-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

Thanks!

Archit

-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora 
Forum, hosted by The Linux Foundation
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v3 0/7] drm/i2c: adv7511: ADV7533 support
  2016-03-09 10:57   ` [PATCH v3 0/7] drm/i2c: adv7511: ADV7533 support Archit Taneja
                       ` (8 preceding siblings ...)
  2016-04-17 11:31     ` Xinliang Liu
@ 2016-05-03  1:52     ` Xinliang Liu
  2016-05-03  6:53       ` Archit Taneja
  2016-05-16 10:41     ` [PATCH v4 " Archit Taneja
  10 siblings, 1 reply; 89+ messages in thread
From: Xinliang Liu @ 2016-05-03  1:52 UTC (permalink / raw)
  To: Archit Taneja
  Cc: Andy Green, linux-arm-msm, dri-devel, Srinivas Kandagatla,
	laurent.pinchart, treding, Amit Kucheria

On 9 March 2016 at 18:57, Archit Taneja <architt@codeaurora.org> wrote:
> 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(-)
>
> --
> 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 <xinliang.liu@linaro.org>

Thanks
-xinliang
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v3 0/7] drm/i2c: adv7511: ADV7533 support
  2016-05-03  1:52     ` Xinliang Liu
@ 2016-05-03  6:53       ` Archit Taneja
  0 siblings, 0 replies; 89+ messages in thread
From: Archit Taneja @ 2016-05-03  6:53 UTC (permalink / raw)
  To: Xinliang Liu
  Cc: dri-devel, David Airlie, Daniel Vetter, treding, linux-arm-msm,
	Srinivas Kandagatla, Andy Green, laurent.pinchart, lars,
	Amit Kucheria, Rob Clark



On 05/03/2016 07:22 AM, Xinliang Liu wrote:
> On 9 March 2016 at 18:57, Archit Taneja <architt@codeaurora.org> wrote:
>> 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(-)
>>
>> --
>> 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 <xinliang.liu@linaro.org>

Thanks for testing!

Archit

>
> Thanks
> -xinliang
> --
> To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>

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

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

* Re: [PATCH v3 4/7] drm/i2c: adv7511: Create a MIPI DSI device
  2016-04-22  5:10         ` Archit Taneja
@ 2016-05-03  6:57           ` Archit Taneja
  2016-05-09 20:38             ` Laurent Pinchart
  0 siblings, 1 reply; 89+ messages in thread
From: Archit Taneja @ 2016-05-03  6:57 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: dri-devel, airlied, daniel, treding, linux-arm-msm,
	srinivas.kandagatla, andy.green, lars, xinliang.liu,
	amit.kucheria, robdclark

Hi Laurent,

On 04/22/2016 10:40 AM, Archit Taneja wrote:
> Hi Laurent,
>
>
> On 04/22/2016 03:59 AM, Laurent Pinchart wrote:
>> Hi Archit,
>>
>> Thank you for the patch.
>>
>> 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.
>>>
>>> Signed-off-by: Archit Taneja <architt@codeaurora.org>
>>
>> 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?

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

>
>>
>>> ---
>>>   drivers/gpu/drm/i2c/adv7511.c | 130
>>> ++++++++++++++++++++++++++++++++++++---
>>>   1 file changed, 123 insertions(+), 7 deletions(-)
>>>
>>> diff --git a/drivers/gpu/drm/i2c/adv7511.c
>>> b/drivers/gpu/drm/i2c/adv7511.c
>>> index 75be17c..6c2a89a 100644
>>> --- a/drivers/gpu/drm/i2c/adv7511.c
>>> +++ b/drivers/gpu/drm/i2c/adv7511.c
>>> @@ -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 <lars@metafoo.de>");
>>>   MODULE_DESCRIPTION("ADV7511 HDMI transmitter driver");
>>
>

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

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

* Re: [PATCH v3 4/7] drm/i2c: adv7511: Create a MIPI DSI device
  2016-05-03  6:57           ` Archit Taneja
@ 2016-05-09 20:38             ` Laurent Pinchart
  2016-05-11 10:19               ` Archit Taneja
  0 siblings, 1 reply; 89+ messages in thread
From: Laurent Pinchart @ 2016-05-09 20:38 UTC (permalink / raw)
  To: Archit Taneja
  Cc: dri-devel, airlied, daniel, treding, linux-arm-msm,
	srinivas.kandagatla, andy.green, lars, xinliang.liu,
	amit.kucheria, robdclark

Hi Archit,

On Tuesday 03 May 2016 12:27:38 Archit Taneja wrote:
> On 04/22/2016 10:40 AM, Archit Taneja wrote:
> > On 04/22/2016 03:59 AM, Laurent Pinchart wrote:
> >> 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.
> >>> 
> >>> Signed-off-by: Archit Taneja <architt@codeaurora.org>
> >> 
> >> 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?
> 
> 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.

> >>> ---
> >>> 
> >>> drivers/gpu/drm/i2c/adv7511.c | 130 +++++++++++++++++++++++++++++++++---
> >>>  1 file changed, 123 insertions(+), 7 deletions(-)

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v3 4/7] drm/i2c: adv7511: Create a MIPI DSI device
  2016-05-09 20:38             ` Laurent Pinchart
@ 2016-05-11 10:19               ` Archit Taneja
  0 siblings, 0 replies; 89+ messages in thread
From: Archit Taneja @ 2016-05-11 10:19 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: andy.green, linux-arm-msm, dri-devel, srinivas.kandagatla,
	amit.kucheria, treding



On 05/10/2016 02:08 AM, Laurent Pinchart wrote:
> Hi Archit,
>
> On Tuesday 03 May 2016 12:27:38 Archit Taneja wrote:
>> On 04/22/2016 10:40 AM, Archit Taneja wrote:
>>> On 04/22/2016 03:59 AM, Laurent Pinchart wrote:
>>>> 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.
>>>>>
>>>>> Signed-off-by: Archit Taneja <architt@codeaurora.org>
>>>>
>>>> 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?
>>
>> 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.

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

>
>>>>> ---
>>>>>
>>>>> drivers/gpu/drm/i2c/adv7511.c | 130 +++++++++++++++++++++++++++++++++---
>>>>>   1 file changed, 123 insertions(+), 7 deletions(-)
>

-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora 
Forum, hosted by The Linux Foundation
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [PATCH v4 0/7] drm/i2c: adv7511: ADV7533 support
  2016-03-09 10:57   ` [PATCH v3 0/7] drm/i2c: adv7511: ADV7533 support Archit Taneja
                       ` (9 preceding siblings ...)
  2016-05-03  1:52     ` Xinliang Liu
@ 2016-05-16 10:41     ` Archit Taneja
  2016-05-16 10:41       ` [PATCH v4 1/7] drm/i2c: adv7511: Convert to drm_bridge Archit Taneja
                         ` (7 more replies)
  10 siblings, 8 replies; 89+ messages in thread
From: Archit Taneja @ 2016-05-16 10:41 UTC (permalink / raw)
  To: dri-devel, laurent.pinchart, xinliang.liu
  Cc: linux-arm-msm, amit.kucheria, srinivas.kandagatla, treding

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

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

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [PATCH v4 1/7] drm/i2c: adv7511: Convert to drm_bridge
  2016-05-16 10:41     ` [PATCH v4 " Archit Taneja
@ 2016-05-16 10:41       ` Archit Taneja
  2016-05-16 10:41       ` [PATCH v4 2/7] drm/i2c: adv7511: Fix mutex deadlock when interrupts are disabled Archit Taneja
                         ` (6 subsequent siblings)
  7 siblings, 0 replies; 89+ messages in thread
From: Archit Taneja @ 2016-05-16 10:41 UTC (permalink / raw)
  To: dri-devel, laurent.pinchart, xinliang.liu
  Cc: linux-arm-msm, amit.kucheria, srinivas.kandagatla, treding

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.

Signed-off-by: Archit Taneja <architt@codeaurora.org>
---
 drivers/gpu/drm/i2c/adv7511.c | 222 ++++++++++++++++++++++++++++--------------
 1 file changed, 148 insertions(+), 74 deletions(-)

diff --git a/drivers/gpu/drm/i2c/adv7511.c b/drivers/gpu/drm/i2c/adv7511.c
index a02112b..fec5627 100644
--- a/drivers/gpu/drm/i2c/adv7511.c
+++ b/drivers/gpu/drm/i2c/adv7511.c
@@ -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 <lars@metafoo.de>");
 MODULE_DESCRIPTION("ADV7511 HDMI transmitter driver");
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [PATCH v4 2/7] drm/i2c: adv7511: Fix mutex deadlock when interrupts are disabled
  2016-05-16 10:41     ` [PATCH v4 " Archit Taneja
  2016-05-16 10:41       ` [PATCH v4 1/7] drm/i2c: adv7511: Convert to drm_bridge Archit Taneja
@ 2016-05-16 10:41       ` Archit Taneja
  2016-05-16 10:41       ` [PATCH v4 3/7] drm/i2c: adv7511: Initial support for ADV7533 Archit Taneja
                         ` (5 subsequent siblings)
  7 siblings, 0 replies; 89+ messages in thread
From: Archit Taneja @ 2016-05-16 10:41 UTC (permalink / raw)
  To: dri-devel, laurent.pinchart, xinliang.liu
  Cc: treding, linux-arm-msm, srinivas.kandagatla, lars, amit.kucheria,
	robdclark, 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.

Signed-off-by: Archit Taneja <architt@codeaurora.org>
---
 drivers/gpu/drm/i2c/adv7511.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/i2c/adv7511.c b/drivers/gpu/drm/i2c/adv7511.c
index fec5627..c00d11d 100644
--- a/drivers/gpu/drm/i2c/adv7511.c
+++ b/drivers/gpu/drm/i2c/adv7511.c
@@ -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;
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

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

* [PATCH v4 3/7] drm/i2c: adv7511: Initial support for ADV7533
  2016-05-16 10:41     ` [PATCH v4 " Archit Taneja
  2016-05-16 10:41       ` [PATCH v4 1/7] drm/i2c: adv7511: Convert to drm_bridge Archit Taneja
  2016-05-16 10:41       ` [PATCH v4 2/7] drm/i2c: adv7511: Fix mutex deadlock when interrupts are disabled Archit Taneja
@ 2016-05-16 10:41       ` Archit Taneja
  2016-05-16 10:41       ` [PATCH v4 4/7] drm/i2c: adv7533: Create a MIPI DSI device Archit Taneja
                         ` (4 subsequent siblings)
  7 siblings, 0 replies; 89+ messages in thread
From: Archit Taneja @ 2016-05-16 10:41 UTC (permalink / raw)
  To: dri-devel, laurent.pinchart, xinliang.liu
  Cc: linux-arm-msm, amit.kucheria, srinivas.kandagatla, treding

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 <lars@metafoo.de>

Signed-off-by: Archit Taneja <architt@codeaurora.org>
---
 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

diff --git a/drivers/gpu/drm/i2c/Kconfig b/drivers/gpu/drm/i2c/Kconfig
index 22c7ed6..03c5528 100644
--- a/drivers/gpu/drm/i2c/Kconfig
+++ b/drivers/gpu/drm/i2c/Kconfig
@@ -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
diff --git a/drivers/gpu/drm/i2c/Makefile b/drivers/gpu/drm/i2c/Makefile
index 2c72eb5..cd2c22c 100644
--- a/drivers/gpu/drm/i2c/Makefile
+++ b/drivers/gpu/drm/i2c/Makefile
@@ -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
diff --git a/drivers/gpu/drm/i2c/adv7511.c b/drivers/gpu/drm/i2c/adv7511.c
index c00d11d..9deb4fd 100644
--- a/drivers/gpu/drm/i2c/adv7511.c
+++ b/drivers/gpu/drm/i2c/adv7511.c
@@ -8,48 +8,17 @@
 
 #include <linux/device.h>
 #include <linux/gpio/consumer.h>
-#include <linux/i2c.h>
 #include <linux/module.h>
-#include <linux/regmap.h>
+#include <linux/of_device.h>
 #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 "adv7511.h"
 
-struct adv7511 {
-	struct i2c_client *i2c_main;
-	struct i2c_client *i2c_edid;
-
-	struct regmap *regmap;
-	struct regmap *packet_memory_regmap;
-	enum drm_connector_status status;
-	bool powered;
-
-	unsigned int f_tmds;
-
-	unsigned int current_edid_segment;
-	uint8_t edid_buf[256];
-	bool edid_read;
-
-	wait_queue_head_t wq;
-	struct drm_bridge bridge;
-	struct drm_connector connector;
-
-	bool embedded_sync;
-	enum adv7511_sync_polarity vsync_polarity;
-	enum adv7511_sync_polarity hsync_polarity;
-	bool rgb;
-
-	struct edid *edid;
-
-	struct gpio_desc *gpio_pd;
-};
-
 /* ADI recommended values for proper operation. */
 static const struct reg_sequence adv7511_fixed_registers[] = {
 	{ 0x98, 0x03 },
@@ -391,6 +360,9 @@ static void adv7511_power_on(struct adv7511 *adv7511)
 	 */
 	regcache_sync(adv7511->regmap);
 
+	if (adv7511->type == ADV7533)
+		adv7533_dsi_power_on(adv7511);
+
 	adv7511->powered = true;
 }
 
@@ -402,6 +374,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 +846,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 +945,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 +980,12 @@ 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 = adv7533_patch_registers(adv7511);
 	if (ret)
 		return ret;
 
@@ -1014,6 +1000,12 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
 	if (!adv7511->i2c_edid)
 		return -ENOMEM;
 
+	if (adv7511->type == ADV7533) {
+		ret = adv7533_init_cec(adv7511);
+		if (ret)
+			goto err_i2c_unregister_edid;
+	}
+
 	if (i2c->irq) {
 		init_waitqueue_head(&adv7511->wq);
 
@@ -1022,7 +1014,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_unregister_cec;
 	}
 
 	/* CEC is unused for now */
@@ -1033,7 +1025,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 +1034,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_unregister_cec;
 	}
 
 	return 0;
 
-err_i2c_unregister_device:
+err_unregister_cec:
+	adv7533_uninit_cec(adv7511);
+err_i2c_unregister_edid:
 	i2c_unregister_device(adv7511->i2c_edid);
 
 	return ret;
@@ -1058,6 +1053,7 @@ static int adv7511_remove(struct i2c_client *i2c)
 
 	drm_bridge_remove(&adv7511->bridge);
 
+	adv7533_uninit_cec(adv7511);
 	i2c_unregister_device(adv7511->i2c_edid);
 
 	kfree(adv7511->edid);
@@ -1066,17 +1062,23 @@ 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 },
+#ifdef CONFIG_DRM_I2C_ADV7533
+	{ "adv7533", ADV7533 },
+#endif
 	{ }
 };
 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 },
+#ifdef CONFIG_DRM_I2C_ADV7533
+	{ .compatible = "adi,adv7533", .data = (void *)ADV7533 },
+#endif
 	{ }
 };
 MODULE_DEVICE_TABLE(of, adv7511_of_ids);
diff --git a/drivers/gpu/drm/i2c/adv7511.h b/drivers/gpu/drm/i2c/adv7511.h
index 38515b3..541c5d7 100644
--- a/drivers/gpu/drm/i2c/adv7511.h
+++ b/drivers/gpu/drm/i2c/adv7511.h
@@ -10,6 +10,10 @@
 #define __DRM_I2C_ADV7511_H__
 
 #include <linux/hdmi.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+
+#include <drm/drm_crtc_helper.h>
 
 #define ADV7511_REG_CHIP_REVISION		0x00
 #define ADV7511_REG_N0				0x01
@@ -286,4 +290,67 @@ struct adv7511_video_config {
 	struct hdmi_avi_infoframe avi_infoframe;
 };
 
+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 *regmap_cec;
+	enum drm_connector_status status;
+	bool powered;
+
+	unsigned int f_tmds;
+
+	unsigned int current_edid_segment;
+	uint8_t edid_buf[256];
+	bool edid_read;
+
+	wait_queue_head_t wq;
+	struct drm_bridge bridge;
+	struct drm_connector connector;
+
+	bool embedded_sync;
+	enum adv7511_sync_polarity vsync_polarity;
+	enum adv7511_sync_polarity hsync_polarity;
+	bool rgb;
+
+	struct edid *edid;
+
+	struct gpio_desc *gpio_pd;
+
+	enum adv7511_type type;
+};
+
+#ifdef CONFIG_DRM_I2C_ADV7533
+void adv7533_dsi_power_on(struct adv7511 *adv);
+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);
+#else
+static inline void adv7533_dsi_power_on(struct adv7511 *adv)
+{
+}
+static inline void adv7533_dsi_power_off(struct adv7511 *adv)
+{
+}
+static inline int adv7533_patch_registers(struct adv7511 *adv)
+{
+	return -ENODEV;
+}
+static inline void adv7533_uninit_cec(struct adv7511 *adv)
+{
+}
+static inline int adv7533_init_cec(struct adv7511 *adv)
+{
+	return -ENODEV;
+}
+#endif
+
 #endif /* __DRM_I2C_ADV7511_H__ */
diff --git a/drivers/gpu/drm/i2c/adv7533.c b/drivers/gpu/drm/i2c/adv7533.c
new file mode 100644
index 0000000..cb4ca64
--- /dev/null
+++ b/drivers/gpu/drm/i2c/adv7533.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "adv7511.h"
+
+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 },
+};
+
+static const struct regmap_config adv7533_cec_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.max_register = 0xff,
+	.cache_type = REGCACHE_RBTREE,
+};
+
+void adv7533_dsi_power_on(struct adv7511 *adv)
+{
+	/* set number of dsi lanes (hardcoded to 4 for now) */
+	regmap_write(adv->regmap_cec, 0x1c, 4 << 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));
+}
+
+void adv7533_dsi_power_off(struct adv7511 *adv)
+{
+	/* disable hdmi */
+	regmap_write(adv->regmap_cec, 0x03, 0x0b);
+}
+
+int adv7533_patch_registers(struct adv7511 *adv)
+{
+	return regmap_register_patch(adv->regmap,
+				     adv7533_fixed_registers,
+				     ARRAY_SIZE(adv7533_fixed_registers));
+}
+
+void adv7533_uninit_cec(struct adv7511 *adv)
+{
+	i2c_unregister_device(adv->i2c_cec);
+}
+
+static const int cec_i2c_addr = 0x78;
+
+int adv7533_init_cec(struct adv7511 *adv)
+{
+	int ret;
+
+	adv->i2c_cec = i2c_new_dummy(adv->i2c_main->adapter, cec_i2c_addr >> 1);
+	if (!adv->i2c_cec)
+		return -ENOMEM;
+
+	adv->regmap_cec = devm_regmap_init_i2c(adv->i2c_cec,
+					&adv7533_cec_regmap_config);
+	if (IS_ERR(adv->regmap_cec)) {
+		ret = PTR_ERR(adv->regmap_cec);
+		goto err;
+	}
+
+	ret = regmap_register_patch(adv->regmap_cec,
+				    adv7533_cec_fixed_registers,
+				    ARRAY_SIZE(adv7533_cec_fixed_registers));
+	if (ret)
+		goto err;
+
+	return 0;
+err:
+	adv7533_uninit_cec(adv);
+	return ret;
+}
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [PATCH v4 4/7] drm/i2c: adv7533: Create a MIPI DSI device
  2016-05-16 10:41     ` [PATCH v4 " Archit Taneja
                         ` (2 preceding siblings ...)
  2016-05-16 10:41       ` [PATCH v4 3/7] drm/i2c: adv7511: Initial support for ADV7533 Archit Taneja
@ 2016-05-16 10:41       ` Archit Taneja
  2016-05-16 10:41       ` [PATCH v4 5/7] drm/i2c: adv7533: Use internal timing generator Archit Taneja
                         ` (3 subsequent siblings)
  7 siblings, 0 replies; 89+ messages in thread
From: Archit Taneja @ 2016-05-16 10:41 UTC (permalink / raw)
  To: dri-devel, laurent.pinchart, xinliang.liu
  Cc: treding, linux-arm-msm, srinivas.kandagatla, lars, amit.kucheria,
	robdclark, 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.

Signed-off-by: Archit Taneja <architt@codeaurora.org>
---
 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(-)

diff --git a/drivers/gpu/drm/i2c/Kconfig b/drivers/gpu/drm/i2c/Kconfig
index 03c5528..f7cd9e5 100644
--- a/drivers/gpu/drm/i2c/Kconfig
+++ b/drivers/gpu/drm/i2c/Kconfig
@@ -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.
diff --git a/drivers/gpu/drm/i2c/adv7511.c b/drivers/gpu/drm/i2c/adv7511.c
index 9deb4fd..42bd674 100644
--- a/drivers/gpu/drm/i2c/adv7511.c
+++ b/drivers/gpu/drm/i2c/adv7511.c
@@ -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 <lars@metafoo.de>");
 MODULE_DESCRIPTION("ADV7511 HDMI transmitter driver");
diff --git a/drivers/gpu/drm/i2c/adv7511.h b/drivers/gpu/drm/i2c/adv7511.h
index 541c5d7..056f747 100644
--- a/drivers/gpu/drm/i2c/adv7511.h
+++ b/drivers/gpu/drm/i2c/adv7511.h
@@ -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__ */
diff --git a/drivers/gpu/drm/i2c/adv7533.c b/drivers/gpu/drm/i2c/adv7533.c
index cb4ca64..ecbcaa0 100644
--- a/drivers/gpu/drm/i2c/adv7533.c
+++ b/drivers/gpu/drm/i2c/adv7533.c
@@ -11,6 +11,8 @@
  * GNU General Public License for more details.
  */
 
+#include <linux/of_graph.h>
+
 #include "adv7511.h"
 
 static const struct reg_sequence adv7533_fixed_registers[] = {
@@ -39,8 +41,10 @@ static const struct regmap_config adv7533_cec_regmap_config = {
 
 void adv7533_dsi_power_on(struct adv7511 *adv)
 {
-	/* set number of dsi lanes (hardcoded to 4 for now) */
-	regmap_write(adv->regmap_cec, 0x1c, 4 << 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 */
@@ -98,3 +102,86 @@ err:
 	adv7533_uninit_cec(adv);
 	return ret;
 }
+
+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;
+}
+
+void adv7533_detach_dsi(struct adv7511 *adv)
+{
+	mipi_dsi_detach(adv->dsi);
+	mipi_dsi_device_unregister(adv->dsi);
+}
+
+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)
+		return -ENODEV;
+
+	adv->host_node = of_graph_get_remote_port_parent(endpoint);
+	if (!adv->host_node) {
+		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;
+}
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

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

* [PATCH v4 5/7] drm/i2c: adv7533: Use internal timing generator
  2016-05-16 10:41     ` [PATCH v4 " Archit Taneja
                         ` (3 preceding siblings ...)
  2016-05-16 10:41       ` [PATCH v4 4/7] drm/i2c: adv7533: Create a MIPI DSI device Archit Taneja
@ 2016-05-16 10:41       ` Archit Taneja
  2016-05-16 10:41       ` [PATCH v4 6/7] drm/i2c: adv7533: Change number of DSI lanes dynamically Archit Taneja
                         ` (2 subsequent siblings)
  7 siblings, 0 replies; 89+ messages in thread
From: Archit Taneja @ 2016-05-16 10:41 UTC (permalink / raw)
  To: dri-devel, laurent.pinchart, xinliang.liu
  Cc: linux-arm-msm, amit.kucheria, srinivas.kandagatla, treding

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.

Signed-off-by: Archit Taneja <architt@codeaurora.org>
---
 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(-)

diff --git a/drivers/gpu/drm/i2c/adv7511.c b/drivers/gpu/drm/i2c/adv7511.c
index 42bd674..61c751f 100644
--- a/drivers/gpu/drm/i2c/adv7511.c
+++ b/drivers/gpu/drm/i2c/adv7511.c
@@ -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.
diff --git a/drivers/gpu/drm/i2c/adv7511.h b/drivers/gpu/drm/i2c/adv7511.h
index 056f747..a9745ea 100644
--- a/drivers/gpu/drm/i2c/adv7511.h
+++ b/drivers/gpu/drm/i2c/adv7511.h
@@ -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;
 };
diff --git a/drivers/gpu/drm/i2c/adv7533.c b/drivers/gpu/drm/i2c/adv7533.c
index ecbcaa0..d002ac4 100644
--- a/drivers/gpu/drm/i2c/adv7533.c
+++ b/drivers/gpu/drm/i2c/adv7533.c
@@ -39,14 +39,65 @@ static const struct regmap_config adv7533_cec_regmap_config = {
 	.cache_type = REGCACHE_RBTREE,
 };
 
+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);
+}
+
 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 */
@@ -60,6 +111,8 @@ 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);
 }
 
 int adv7533_patch_registers(struct adv7511 *adv)
@@ -179,6 +232,9 @@ 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;
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [PATCH v4 6/7] drm/i2c: adv7533: Change number of DSI lanes dynamically
  2016-05-16 10:41     ` [PATCH v4 " Archit Taneja
                         ` (4 preceding siblings ...)
  2016-05-16 10:41       ` [PATCH v4 5/7] drm/i2c: adv7533: Use internal timing generator Archit Taneja
@ 2016-05-16 10:41       ` Archit Taneja
  2016-05-16 10:41       ` [PATCH v4 7/7] dt-bindings: drm/bridge: Update bindings for ADV7533 Archit Taneja
  2016-06-08 10:27       ` [PATCH v5 0/7] drm/i2c: adv7511: ADV7533 support Archit Taneja
  7 siblings, 0 replies; 89+ messages in thread
From: Archit Taneja @ 2016-05-16 10:41 UTC (permalink / raw)
  To: dri-devel, laurent.pinchart, xinliang.liu
  Cc: treding, linux-arm-msm, srinivas.kandagatla, lars, amit.kucheria,
	robdclark, 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 <andy.green@linaro.org>

Signed-off-by: Archit Taneja <architt@codeaurora.org>
---
 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(+)

diff --git a/drivers/gpu/drm/i2c/adv7511.c b/drivers/gpu/drm/i2c/adv7511.c
index 61c751f..5dfca1a 100644
--- a/drivers/gpu/drm/i2c/adv7511.c
+++ b/drivers/gpu/drm/i2c/adv7511.c
@@ -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);
 
 	/*
diff --git a/drivers/gpu/drm/i2c/adv7511.h b/drivers/gpu/drm/i2c/adv7511.h
index a9745ea..b113b77 100644
--- a/drivers/gpu/drm/i2c/adv7511.h
+++ b/drivers/gpu/drm/i2c/adv7511.h
@@ -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;
diff --git a/drivers/gpu/drm/i2c/adv7533.c b/drivers/gpu/drm/i2c/adv7533.c
index d002ac4..5eebd15 100644
--- a/drivers/gpu/drm/i2c/adv7533.c
+++ b/drivers/gpu/drm/i2c/adv7533.c
@@ -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,
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

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

* [PATCH v4 7/7] dt-bindings: drm/bridge: Update bindings for ADV7533
  2016-05-16 10:41     ` [PATCH v4 " Archit Taneja
                         ` (5 preceding siblings ...)
  2016-05-16 10:41       ` [PATCH v4 6/7] drm/i2c: adv7533: Change number of DSI lanes dynamically Archit Taneja
@ 2016-05-16 10:41       ` Archit Taneja
  2016-06-08 10:27       ` [PATCH v5 0/7] drm/i2c: adv7511: ADV7533 support Archit Taneja
  7 siblings, 0 replies; 89+ messages in thread
From: Archit Taneja @ 2016-05-16 10:41 UTC (permalink / raw)
  To: dri-devel, laurent.pinchart, xinliang.liu
  Cc: treding, linux-arm-msm, srinivas.kandagatla, lars, amit.kucheria,
	robdclark, Archit Taneja, devicetree

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

Cc: devicetree@vger.kernel.org

Acked-by: Rob Herring <robh@kernel.org>

Signed-off-by: Archit Taneja <architt@codeaurora.org>
---
 .../bindings/display/bridge/adi,adv7511.txt        | 26 +++++++++++++++++-----
 1 file changed, 21 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..6532a59 100644
--- a/Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt
+++ b/Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt
@@ -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
 
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

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

* Re: [PATCH v3 7/7] dt-bindings: drm/bridge: Update bindings for ADV7533
       [not found]             ` <5719B942.8070907-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
@ 2016-05-16 12:01               ` Laurent Pinchart
  2016-05-17  3:43                 ` Archit Taneja
  0 siblings, 1 reply; 89+ messages in thread
From: Laurent Pinchart @ 2016-05-16 12:01 UTC (permalink / raw)
  To: Archit Taneja
  Cc: dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW, airlied-cv59FeDIM0c,
	daniel-/w4YWyX8dFk, treding-DDmLM1+adcrQT0dZR+AlfA,
	linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
	srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A,
	andy.green-QSEj5FYQhm4dnm+yROfE0A, lars-Qo5EllUWu/uELgA04lAiVw,
	xinliang.liu-QSEj5FYQhm4dnm+yROfE0A,
	amit.kucheria-QSEj5FYQhm4dnm+yROfE0A,
	robdclark-Re5JQEeQqe8AvxtiuMwx3w,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Rob Herring

Hi Archit,

On Friday 22 Apr 2016 11:10:18 Archit Taneja wrote:
> On 04/22/2016 04:02 AM, Laurent Pinchart wrote:
> > 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.
> >> 
> >> Cc: devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> >> Cc: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> >> 
> >> Signed-off-by: Archit Taneja <architt-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
> >> ---
> >> 
> >> .../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
> >> --- a/Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt
> >> +++ b/Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt

[snip]

> >> +- 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.

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 ?

-- 
Regards,

Laurent Pinchart

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH v3 7/7] dt-bindings: drm/bridge: Update bindings for ADV7533
  2016-05-16 12:01               ` Laurent Pinchart
@ 2016-05-17  3:43                 ` Archit Taneja
  2016-05-17  4:18                   ` Xinliang Liu
  0 siblings, 1 reply; 89+ messages in thread
From: Archit Taneja @ 2016-05-17  3:43 UTC (permalink / raw)
  To: Laurent Pinchart, xinliang.liu
  Cc: dri-devel, airlied, daniel, treding, linux-arm-msm,
	srinivas.kandagatla, lars, amit.kucheria, robdclark, devicetree,
	Rob Herring



On 05/16/2016 05:31 PM, Laurent Pinchart wrote:
> Hi Archit,
>
> On Friday 22 Apr 2016 11:10:18 Archit Taneja wrote:
>> On 04/22/2016 04:02 AM, Laurent Pinchart wrote:
>>> 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.
>>>>
>>>> Cc: devicetree@vger.kernel.org
>>>> Cc: Rob Herring <robh@kernel.org>
>>>>
>>>> Signed-off-by: Archit Taneja <architt@codeaurora.org>
>>>> ---
>>>>
>>>> .../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
>>>> --- a/Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt
>>>> +++ b/Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt
>
> [snip]
>
>>>> +- 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.
>
> 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

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

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

* Re: [PATCH v3 7/7] dt-bindings: drm/bridge: Update bindings for ADV7533
  2016-05-17  3:43                 ` Archit Taneja
@ 2016-05-17  4:18                   ` Xinliang Liu
  2016-05-24  5:15                     ` Archit Taneja
  0 siblings, 1 reply; 89+ messages in thread
From: Xinliang Liu @ 2016-05-17  4:18 UTC (permalink / raw)
  To: Archit Taneja
  Cc: devicetree, linux-arm-msm, dri-devel, Srinivas Kandagatla,
	Laurent Pinchart, treding, Amit Kucheria

On 17 May 2016 at 11:43, Archit Taneja <architt@codeaurora.org> wrote:
>
>
> On 05/16/2016 05:31 PM, Laurent Pinchart wrote:
>>
>> Hi Archit,
>>
>> On Friday 22 Apr 2016 11:10:18 Archit Taneja wrote:
>>>
>>> On 04/22/2016 04:02 AM, Laurent Pinchart wrote:
>>>>
>>>> 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.
>>>>>
>>>>> Cc: devicetree@vger.kernel.org
>>>>> Cc: Rob Herring <robh@kernel.org>
>>>>>
>>>>> Signed-off-by: Archit Taneja <architt@codeaurora.org>
>>>>> ---
>>>>>
>>>>> .../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
>>>>> --- a/Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt
>>>>> +++ b/Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt
>>
>>
>> [snip]
>>
>>>>> +- 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.
>>
>>
>> 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?

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

>
>
> Thanks,
> Archit
>
> --
> The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
> hosted by The Linux Foundation
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v3 7/7] dt-bindings: drm/bridge: Update bindings for ADV7533
  2016-05-17  4:18                   ` Xinliang Liu
@ 2016-05-24  5:15                     ` Archit Taneja
  0 siblings, 0 replies; 89+ messages in thread
From: Archit Taneja @ 2016-05-24  5:15 UTC (permalink / raw)
  To: Xinliang Liu, Laurent Pinchart
  Cc: devicetree, linux-arm-msm, dri-devel, Srinivas Kandagatla,
	Amit Kucheria, treding



On 05/17/2016 09:48 AM, Xinliang Liu wrote:
> On 17 May 2016 at 11:43, Archit Taneja <architt@codeaurora.org> wrote:
>>
>>
>> On 05/16/2016 05:31 PM, Laurent Pinchart wrote:
>>>
>>> Hi Archit,
>>>
>>> On Friday 22 Apr 2016 11:10:18 Archit Taneja wrote:
>>>>
>>>> On 04/22/2016 04:02 AM, Laurent Pinchart wrote:
>>>>>
>>>>> 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.
>>>>>>
>>>>>> Cc: devicetree@vger.kernel.org
>>>>>> Cc: Rob Herring <robh@kernel.org>
>>>>>>
>>>>>> Signed-off-by: Archit Taneja <architt@codeaurora.org>
>>>>>> ---
>>>>>>
>>>>>> .../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
>>>>>> --- a/Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt
>>>>>> +++ b/Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt
>>>
>>>
>>> [snip]
>>>
>>>>>> +- 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.
>>>
>>>
>>> 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?
>
> 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

-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora 
Forum, hosted by The Linux Foundation
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [PATCH v5 0/7] drm/i2c: adv7511: ADV7533 support
  2016-05-16 10:41     ` [PATCH v4 " Archit Taneja
                         ` (6 preceding siblings ...)
  2016-05-16 10:41       ` [PATCH v4 7/7] dt-bindings: drm/bridge: Update bindings for ADV7533 Archit Taneja
@ 2016-06-08 10:27       ` Archit Taneja
  2016-06-08 10:27         ` [PATCH v5 1/7] drm/i2c: adv7511: Convert to drm_bridge Archit Taneja
                           ` (7 more replies)
  7 siblings, 8 replies; 89+ messages in thread
From: Archit Taneja @ 2016-06-08 10:27 UTC (permalink / raw)
  To: dri-devel, treding, laurent.pinchart, xinliang.liu
  Cc: linux-arm-msm, amit.kucheria, srinivas.kandagatla

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

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

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [PATCH v5 1/7] drm/i2c: adv7511: Convert to drm_bridge
  2016-06-08 10:27       ` [PATCH v5 0/7] drm/i2c: adv7511: ADV7533 support Archit Taneja
@ 2016-06-08 10:27         ` Archit Taneja
  2016-06-08 10:27         ` [PATCH v5 2/7] drm/i2c: adv7511: Fix mutex deadlock when interrupts are disabled Archit Taneja
                           ` (6 subsequent siblings)
  7 siblings, 0 replies; 89+ messages in thread
From: Archit Taneja @ 2016-06-08 10:27 UTC (permalink / raw)
  To: dri-devel, treding, laurent.pinchart, xinliang.liu
  Cc: linux-arm-msm, srinivas.kandagatla, lars, amit.kucheria,
	robdclark, Archit Taneja

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.

Signed-off-by: Archit Taneja <architt@codeaurora.org>
---
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(-)

diff --git a/drivers/gpu/drm/i2c/Kconfig b/drivers/gpu/drm/i2c/Kconfig
index 22c7ed6..8bb0697 100644
--- a/drivers/gpu/drm/i2c/Kconfig
+++ b/drivers/gpu/drm/i2c/Kconfig
@@ -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.
diff --git a/drivers/gpu/drm/i2c/adv7511.c b/drivers/gpu/drm/i2c/adv7511.c
index a02112b..c2642f9 100644
--- a/drivers/gpu/drm/i2c/adv7511.c
+++ b/drivers/gpu/drm/i2c/adv7511.c
@@ -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,111 @@ 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 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,
+	.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 +1026,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 +1047,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 +1056,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 +1072,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 <lars@metafoo.de>");
 MODULE_DESCRIPTION("ADV7511 HDMI transmitter driver");
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

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

* [PATCH v5 2/7] drm/i2c: adv7511: Fix mutex deadlock when interrupts are disabled
  2016-06-08 10:27       ` [PATCH v5 0/7] drm/i2c: adv7511: ADV7533 support Archit Taneja
  2016-06-08 10:27         ` [PATCH v5 1/7] drm/i2c: adv7511: Convert to drm_bridge Archit Taneja
@ 2016-06-08 10:27         ` Archit Taneja
  2016-06-08 10:27         ` [PATCH v5 3/7] drm/i2c: adv7511: Initial support for ADV7533 Archit Taneja
                           ` (5 subsequent siblings)
  7 siblings, 0 replies; 89+ messages in thread
From: Archit Taneja @ 2016-06-08 10:27 UTC (permalink / raw)
  To: dri-devel, treding, laurent.pinchart, xinliang.liu
  Cc: linux-arm-msm, srinivas.kandagatla, lars, amit.kucheria,
	robdclark, 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.

Signed-off-by: Archit Taneja <architt@codeaurora.org>
---
 drivers/gpu/drm/i2c/adv7511.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/i2c/adv7511.c b/drivers/gpu/drm/i2c/adv7511.c
index c2642f9..1fff0ab 100644
--- a/drivers/gpu/drm/i2c/adv7511.c
+++ b/drivers/gpu/drm/i2c/adv7511.c
@@ -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;
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

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

* [PATCH v5 3/7] drm/i2c: adv7511: Initial support for ADV7533
  2016-06-08 10:27       ` [PATCH v5 0/7] drm/i2c: adv7511: ADV7533 support Archit Taneja
  2016-06-08 10:27         ` [PATCH v5 1/7] drm/i2c: adv7511: Convert to drm_bridge Archit Taneja
  2016-06-08 10:27         ` [PATCH v5 2/7] drm/i2c: adv7511: Fix mutex deadlock when interrupts are disabled Archit Taneja
@ 2016-06-08 10:27         ` Archit Taneja
  2016-06-08 10:27         ` [PATCH v5 4/7] drm/i2c: adv7533: Create a MIPI DSI device Archit Taneja
                           ` (4 subsequent siblings)
  7 siblings, 0 replies; 89+ messages in thread
From: Archit Taneja @ 2016-06-08 10:27 UTC (permalink / raw)
  To: dri-devel, treding, laurent.pinchart, xinliang.liu
  Cc: linux-arm-msm, srinivas.kandagatla, lars, amit.kucheria,
	robdclark, 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 <lars@metafoo.de>

Signed-off-by: Archit Taneja <architt@codeaurora.org>
---
 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

diff --git a/drivers/gpu/drm/i2c/Kconfig b/drivers/gpu/drm/i2c/Kconfig
index 8bb0697..4cbbfd8 100644
--- a/drivers/gpu/drm/i2c/Kconfig
+++ b/drivers/gpu/drm/i2c/Kconfig
@@ -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
diff --git a/drivers/gpu/drm/i2c/Makefile b/drivers/gpu/drm/i2c/Makefile
index 2c72eb5..cd2c22c 100644
--- a/drivers/gpu/drm/i2c/Makefile
+++ b/drivers/gpu/drm/i2c/Makefile
@@ -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
diff --git a/drivers/gpu/drm/i2c/adv7511.c b/drivers/gpu/drm/i2c/adv7511.c
index 1fff0ab..e33702b 100644
--- a/drivers/gpu/drm/i2c/adv7511.c
+++ b/drivers/gpu/drm/i2c/adv7511.c
@@ -8,48 +8,17 @@
 
 #include <linux/device.h>
 #include <linux/gpio/consumer.h>
-#include <linux/i2c.h>
 #include <linux/module.h>
-#include <linux/regmap.h>
+#include <linux/of_device.h>
 #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 "adv7511.h"
 
-struct adv7511 {
-	struct i2c_client *i2c_main;
-	struct i2c_client *i2c_edid;
-
-	struct regmap *regmap;
-	struct regmap *packet_memory_regmap;
-	enum drm_connector_status status;
-	bool powered;
-
-	unsigned int f_tmds;
-
-	unsigned int current_edid_segment;
-	uint8_t edid_buf[256];
-	bool edid_read;
-
-	wait_queue_head_t wq;
-	struct drm_bridge bridge;
-	struct drm_connector connector;
-
-	bool embedded_sync;
-	enum adv7511_sync_polarity vsync_polarity;
-	enum adv7511_sync_polarity hsync_polarity;
-	bool rgb;
-
-	struct edid *edid;
-
-	struct gpio_desc *gpio_pd;
-};
-
 /* ADI recommended values for proper operation. */
 static const struct reg_sequence adv7511_fixed_registers[] = {
 	{ 0x98, 0x03 },
@@ -391,6 +360,9 @@ static void adv7511_power_on(struct adv7511 *adv7511)
 	 */
 	regcache_sync(adv7511->regmap);
 
+	if (adv7511->type == ADV7533)
+		adv7533_dsi_power_on(adv7511);
+
 	adv7511->powered = true;
 }
 
@@ -402,6 +374,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;
 }
 
@@ -862,8 +837,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)
@@ -963,9 +936,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
@@ -989,8 +971,12 @@ 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 = adv7533_patch_registers(adv7511);
 	if (ret)
 		return ret;
 
@@ -1005,6 +991,12 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
 	if (!adv7511->i2c_edid)
 		return -ENOMEM;
 
+	if (adv7511->type == ADV7533) {
+		ret = adv7533_init_cec(adv7511);
+		if (ret)
+			goto err_i2c_unregister_edid;
+	}
+
 	if (i2c->irq) {
 		init_waitqueue_head(&adv7511->wq);
 
@@ -1013,7 +1005,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_unregister_cec;
 	}
 
 	/* CEC is unused for now */
@@ -1024,7 +1016,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;
@@ -1032,12 +1025,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_unregister_cec;
 	}
 
 	return 0;
 
-err_i2c_unregister_device:
+err_unregister_cec:
+	adv7533_uninit_cec(adv7511);
+err_i2c_unregister_edid:
 	i2c_unregister_device(adv7511->i2c_edid);
 
 	return ret;
@@ -1049,6 +1044,7 @@ static int adv7511_remove(struct i2c_client *i2c)
 
 	drm_bridge_remove(&adv7511->bridge);
 
+	adv7533_uninit_cec(adv7511);
 	i2c_unregister_device(adv7511->i2c_edid);
 
 	kfree(adv7511->edid);
@@ -1057,17 +1053,23 @@ 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 },
+#ifdef CONFIG_DRM_I2C_ADV7533
+	{ "adv7533", ADV7533 },
+#endif
 	{ }
 };
 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 },
+#ifdef CONFIG_DRM_I2C_ADV7533
+	{ .compatible = "adi,adv7533", .data = (void *)ADV7533 },
+#endif
 	{ }
 };
 MODULE_DEVICE_TABLE(of, adv7511_of_ids);
diff --git a/drivers/gpu/drm/i2c/adv7511.h b/drivers/gpu/drm/i2c/adv7511.h
index 38515b3..541c5d7 100644
--- a/drivers/gpu/drm/i2c/adv7511.h
+++ b/drivers/gpu/drm/i2c/adv7511.h
@@ -10,6 +10,10 @@
 #define __DRM_I2C_ADV7511_H__
 
 #include <linux/hdmi.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+
+#include <drm/drm_crtc_helper.h>
 
 #define ADV7511_REG_CHIP_REVISION		0x00
 #define ADV7511_REG_N0				0x01
@@ -286,4 +290,67 @@ struct adv7511_video_config {
 	struct hdmi_avi_infoframe avi_infoframe;
 };
 
+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 *regmap_cec;
+	enum drm_connector_status status;
+	bool powered;
+
+	unsigned int f_tmds;
+
+	unsigned int current_edid_segment;
+	uint8_t edid_buf[256];
+	bool edid_read;
+
+	wait_queue_head_t wq;
+	struct drm_bridge bridge;
+	struct drm_connector connector;
+
+	bool embedded_sync;
+	enum adv7511_sync_polarity vsync_polarity;
+	enum adv7511_sync_polarity hsync_polarity;
+	bool rgb;
+
+	struct edid *edid;
+
+	struct gpio_desc *gpio_pd;
+
+	enum adv7511_type type;
+};
+
+#ifdef CONFIG_DRM_I2C_ADV7533
+void adv7533_dsi_power_on(struct adv7511 *adv);
+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);
+#else
+static inline void adv7533_dsi_power_on(struct adv7511 *adv)
+{
+}
+static inline void adv7533_dsi_power_off(struct adv7511 *adv)
+{
+}
+static inline int adv7533_patch_registers(struct adv7511 *adv)
+{
+	return -ENODEV;
+}
+static inline void adv7533_uninit_cec(struct adv7511 *adv)
+{
+}
+static inline int adv7533_init_cec(struct adv7511 *adv)
+{
+	return -ENODEV;
+}
+#endif
+
 #endif /* __DRM_I2C_ADV7511_H__ */
diff --git a/drivers/gpu/drm/i2c/adv7533.c b/drivers/gpu/drm/i2c/adv7533.c
new file mode 100644
index 0000000..cb4ca64
--- /dev/null
+++ b/drivers/gpu/drm/i2c/adv7533.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "adv7511.h"
+
+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 },
+};
+
+static const struct regmap_config adv7533_cec_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.max_register = 0xff,
+	.cache_type = REGCACHE_RBTREE,
+};
+
+void adv7533_dsi_power_on(struct adv7511 *adv)
+{
+	/* set number of dsi lanes (hardcoded to 4 for now) */
+	regmap_write(adv->regmap_cec, 0x1c, 4 << 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));
+}
+
+void adv7533_dsi_power_off(struct adv7511 *adv)
+{
+	/* disable hdmi */
+	regmap_write(adv->regmap_cec, 0x03, 0x0b);
+}
+
+int adv7533_patch_registers(struct adv7511 *adv)
+{
+	return regmap_register_patch(adv->regmap,
+				     adv7533_fixed_registers,
+				     ARRAY_SIZE(adv7533_fixed_registers));
+}
+
+void adv7533_uninit_cec(struct adv7511 *adv)
+{
+	i2c_unregister_device(adv->i2c_cec);
+}
+
+static const int cec_i2c_addr = 0x78;
+
+int adv7533_init_cec(struct adv7511 *adv)
+{
+	int ret;
+
+	adv->i2c_cec = i2c_new_dummy(adv->i2c_main->adapter, cec_i2c_addr >> 1);
+	if (!adv->i2c_cec)
+		return -ENOMEM;
+
+	adv->regmap_cec = devm_regmap_init_i2c(adv->i2c_cec,
+					&adv7533_cec_regmap_config);
+	if (IS_ERR(adv->regmap_cec)) {
+		ret = PTR_ERR(adv->regmap_cec);
+		goto err;
+	}
+
+	ret = regmap_register_patch(adv->regmap_cec,
+				    adv7533_cec_fixed_registers,
+				    ARRAY_SIZE(adv7533_cec_fixed_registers));
+	if (ret)
+		goto err;
+
+	return 0;
+err:
+	adv7533_uninit_cec(adv);
+	return ret;
+}
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

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

* [PATCH v5 4/7] drm/i2c: adv7533: Create a MIPI DSI device
  2016-06-08 10:27       ` [PATCH v5 0/7] drm/i2c: adv7511: ADV7533 support Archit Taneja
                           ` (2 preceding siblings ...)
  2016-06-08 10:27         ` [PATCH v5 3/7] drm/i2c: adv7511: Initial support for ADV7533 Archit Taneja
@ 2016-06-08 10:27         ` Archit Taneja
  2016-06-08 10:27         ` [PATCH v5 5/7] drm/i2c: adv7533: Use internal timing generator Archit Taneja
                           ` (3 subsequent siblings)
  7 siblings, 0 replies; 89+ messages in thread
From: Archit Taneja @ 2016-06-08 10:27 UTC (permalink / raw)
  To: dri-devel, treding, laurent.pinchart, xinliang.liu
  Cc: linux-arm-msm, srinivas.kandagatla, lars, amit.kucheria,
	robdclark, 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.

Signed-off-by: Archit Taneja <architt@codeaurora.org>
---
 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(-)

diff --git a/drivers/gpu/drm/i2c/Kconfig b/drivers/gpu/drm/i2c/Kconfig
index 4cbbfd8..70ee29d 100644
--- a/drivers/gpu/drm/i2c/Kconfig
+++ b/drivers/gpu/drm/i2c/Kconfig
@@ -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.
diff --git a/drivers/gpu/drm/i2c/adv7511.c b/drivers/gpu/drm/i2c/adv7511.c
index e33702b..6586c52 100644
--- a/drivers/gpu/drm/i2c/adv7511.c
+++ b/drivers/gpu/drm/i2c/adv7511.c
@@ -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 <lars@metafoo.de>");
 MODULE_DESCRIPTION("ADV7511 HDMI transmitter driver");
diff --git a/drivers/gpu/drm/i2c/adv7511.h b/drivers/gpu/drm/i2c/adv7511.h
index 541c5d7..056f747 100644
--- a/drivers/gpu/drm/i2c/adv7511.h
+++ b/drivers/gpu/drm/i2c/adv7511.h
@@ -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__ */
diff --git a/drivers/gpu/drm/i2c/adv7533.c b/drivers/gpu/drm/i2c/adv7533.c
index cb4ca64..ecbcaa0 100644
--- a/drivers/gpu/drm/i2c/adv7533.c
+++ b/drivers/gpu/drm/i2c/adv7533.c
@@ -11,6 +11,8 @@
  * GNU General Public License for more details.
  */
 
+#include <linux/of_graph.h>
+
 #include "adv7511.h"
 
 static const struct reg_sequence adv7533_fixed_registers[] = {
@@ -39,8 +41,10 @@ static const struct regmap_config adv7533_cec_regmap_config = {
 
 void adv7533_dsi_power_on(struct adv7511 *adv)
 {
-	/* set number of dsi lanes (hardcoded to 4 for now) */
-	regmap_write(adv->regmap_cec, 0x1c, 4 << 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 */
@@ -98,3 +102,86 @@ err:
 	adv7533_uninit_cec(adv);
 	return ret;
 }
+
+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;
+}
+
+void adv7533_detach_dsi(struct adv7511 *adv)
+{
+	mipi_dsi_detach(adv->dsi);
+	mipi_dsi_device_unregister(adv->dsi);
+}
+
+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)
+		return -ENODEV;
+
+	adv->host_node = of_graph_get_remote_port_parent(endpoint);
+	if (!adv->host_node) {
+		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;
+}
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

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

* [PATCH v5 5/7] drm/i2c: adv7533: Use internal timing generator
  2016-06-08 10:27       ` [PATCH v5 0/7] drm/i2c: adv7511: ADV7533 support Archit Taneja
                           ` (3 preceding siblings ...)
  2016-06-08 10:27         ` [PATCH v5 4/7] drm/i2c: adv7533: Create a MIPI DSI device Archit Taneja
@ 2016-06-08 10:27         ` Archit Taneja
  2016-06-08 10:27         ` [PATCH v5 6/7] drm/i2c: adv7533: Change number of DSI lanes dynamically Archit Taneja
                           ` (2 subsequent siblings)
  7 siblings, 0 replies; 89+ messages in thread
From: Archit Taneja @ 2016-06-08 10:27 UTC (permalink / raw)
  To: dri-devel, treding, laurent.pinchart, xinliang.liu
  Cc: linux-arm-msm, srinivas.kandagatla, lars, amit.kucheria,
	robdclark, 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.

Signed-off-by: Archit Taneja <architt@codeaurora.org>
---
 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(-)

diff --git a/drivers/gpu/drm/i2c/adv7511.c b/drivers/gpu/drm/i2c/adv7511.c
index 6586c52..e0c353e 100644
--- a/drivers/gpu/drm/i2c/adv7511.c
+++ b/drivers/gpu/drm/i2c/adv7511.c
@@ -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.
diff --git a/drivers/gpu/drm/i2c/adv7511.h b/drivers/gpu/drm/i2c/adv7511.h
index 056f747..a9745ea 100644
--- a/drivers/gpu/drm/i2c/adv7511.h
+++ b/drivers/gpu/drm/i2c/adv7511.h
@@ -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;
 };
diff --git a/drivers/gpu/drm/i2c/adv7533.c b/drivers/gpu/drm/i2c/adv7533.c
index ecbcaa0..d002ac4 100644
--- a/drivers/gpu/drm/i2c/adv7533.c
+++ b/drivers/gpu/drm/i2c/adv7533.c
@@ -39,14 +39,65 @@ static const struct regmap_config adv7533_cec_regmap_config = {
 	.cache_type = REGCACHE_RBTREE,
 };
 
+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);
+}
+
 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 */
@@ -60,6 +111,8 @@ 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);
 }
 
 int adv7533_patch_registers(struct adv7511 *adv)
@@ -179,6 +232,9 @@ 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;
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

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

* [PATCH v5 6/7] drm/i2c: adv7533: Change number of DSI lanes dynamically
  2016-06-08 10:27       ` [PATCH v5 0/7] drm/i2c: adv7511: ADV7533 support Archit Taneja
                           ` (4 preceding siblings ...)
  2016-06-08 10:27         ` [PATCH v5 5/7] drm/i2c: adv7533: Use internal timing generator Archit Taneja
@ 2016-06-08 10:27         ` Archit Taneja
  2016-06-08 10:27         ` [PATCH v5 7/7] dt-bindings: drm/bridge: Update bindings for ADV7533 Archit Taneja
  2016-06-17  7:53         ` [PATCH v6 0/8] drm/i2c: adv7511: ADV7533 support Archit Taneja
  7 siblings, 0 replies; 89+ messages in thread
From: Archit Taneja @ 2016-06-08 10:27 UTC (permalink / raw)
  To: dri-devel, treding, laurent.pinchart, xinliang.liu
  Cc: linux-arm-msm, srinivas.kandagatla, lars, amit.kucheria,
	robdclark, 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 <andy.green@linaro.org>

Signed-off-by: Archit Taneja <architt@codeaurora.org>
---
 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(+)

diff --git a/drivers/gpu/drm/i2c/adv7511.c b/drivers/gpu/drm/i2c/adv7511.c
index e0c353e..ec8fb2e 100644
--- a/drivers/gpu/drm/i2c/adv7511.c
+++ b/drivers/gpu/drm/i2c/adv7511.c
@@ -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);
 
 	/*
diff --git a/drivers/gpu/drm/i2c/adv7511.h b/drivers/gpu/drm/i2c/adv7511.h
index a9745ea..b113b77 100644
--- a/drivers/gpu/drm/i2c/adv7511.h
+++ b/drivers/gpu/drm/i2c/adv7511.h
@@ -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;
diff --git a/drivers/gpu/drm/i2c/adv7533.c b/drivers/gpu/drm/i2c/adv7533.c
index d002ac4..5eebd15 100644
--- a/drivers/gpu/drm/i2c/adv7533.c
+++ b/drivers/gpu/drm/i2c/adv7533.c
@@ -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,
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

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

* [PATCH v5 7/7] dt-bindings: drm/bridge: Update bindings for ADV7533
  2016-06-08 10:27       ` [PATCH v5 0/7] drm/i2c: adv7511: ADV7533 support Archit Taneja
                           ` (5 preceding siblings ...)
  2016-06-08 10:27         ` [PATCH v5 6/7] drm/i2c: adv7533: Change number of DSI lanes dynamically Archit Taneja
@ 2016-06-08 10:27         ` Archit Taneja
  2016-06-17  7:53         ` [PATCH v6 0/8] drm/i2c: adv7511: ADV7533 support Archit Taneja
  7 siblings, 0 replies; 89+ messages in thread
From: Archit Taneja @ 2016-06-08 10:27 UTC (permalink / raw)
  To: dri-devel, treding, laurent.pinchart, xinliang.liu
  Cc: linux-arm-msm, srinivas.kandagatla, lars, amit.kucheria,
	robdclark, Archit Taneja, devicetree

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

Cc: devicetree@vger.kernel.org

Acked-by: Rob Herring <robh@kernel.org>

Signed-off-by: Archit Taneja <architt@codeaurora.org>
---
 .../bindings/display/bridge/adi,adv7511.txt        | 26 +++++++++++++++++-----
 1 file changed, 21 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..6532a59 100644
--- a/Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt
+++ b/Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt
@@ -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
 
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

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

* [PATCH v6 0/8] drm/i2c: adv7511: ADV7533 support
  2016-06-08 10:27       ` [PATCH v5 0/7] drm/i2c: adv7511: ADV7533 support Archit Taneja
                           ` (6 preceding siblings ...)
  2016-06-08 10:27         ` [PATCH v5 7/7] dt-bindings: drm/bridge: Update bindings for ADV7533 Archit Taneja
@ 2016-06-17  7:53         ` Archit Taneja
  2016-06-17  7:53           ` [PATCH v6 1/8] drm/i2c: adv7511: Convert to drm_bridge Archit Taneja
                             ` (7 more replies)
  7 siblings, 8 replies; 89+ messages in thread
From: Archit Taneja @ 2016-06-17  7:53 UTC (permalink / raw)
  To: dri-devel, treding, laurent.pinchart, xinliang.liu
  Cc: linux-arm-msm, srinivas.kandagatla, lars, amit.kucheria,
	robdclark, 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

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

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

* [PATCH v6 1/8] drm/i2c: adv7511: Convert to drm_bridge
  2016-06-17  7:53         ` [PATCH v6 0/8] drm/i2c: adv7511: ADV7533 support Archit Taneja
@ 2016-06-17  7:53           ` Archit Taneja
  2016-06-17  7:53           ` [PATCH v6 2/8] drm/i2c: adv7511: Move to bridge folder Archit Taneja
                             ` (6 subsequent siblings)
  7 siblings, 0 replies; 89+ messages in thread
From: Archit Taneja @ 2016-06-17  7:53 UTC (permalink / raw)
  To: dri-devel, treding, laurent.pinchart, xinliang.liu
  Cc: linux-arm-msm, srinivas.kandagatla, lars, amit.kucheria,
	robdclark, Archit Taneja

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.

Signed-off-by: Archit Taneja <architt@codeaurora.org>
---
 drivers/gpu/drm/i2c/Kconfig   |   1 +
 drivers/gpu/drm/i2c/adv7511.c | 213 +++++++++++++++++++++++++++---------------
 2 files changed, 140 insertions(+), 74 deletions(-)

diff --git a/drivers/gpu/drm/i2c/Kconfig b/drivers/gpu/drm/i2c/Kconfig
index 22c7ed6..8bb0697 100644
--- a/drivers/gpu/drm/i2c/Kconfig
+++ b/drivers/gpu/drm/i2c/Kconfig
@@ -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.
diff --git a/drivers/gpu/drm/i2c/adv7511.c b/drivers/gpu/drm/i2c/adv7511.c
index a02112b..c2642f9 100644
--- a/drivers/gpu/drm/i2c/adv7511.c
+++ b/drivers/gpu/drm/i2c/adv7511.c
@@ -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,111 @@ 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 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,
+	.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 +1026,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 +1047,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 +1056,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 +1072,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 <lars@metafoo.de>");
 MODULE_DESCRIPTION("ADV7511 HDMI transmitter driver");
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

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

* [PATCH v6 2/8] drm/i2c: adv7511: Move to bridge folder
  2016-06-17  7:53         ` [PATCH v6 0/8] drm/i2c: adv7511: ADV7533 support Archit Taneja
  2016-06-17  7:53           ` [PATCH v6 1/8] drm/i2c: adv7511: Convert to drm_bridge Archit Taneja
@ 2016-06-17  7:53           ` Archit Taneja
  2016-06-17  7:53           ` [PATCH v6 3/8] drm/bridge: adv7511: Fix mutex deadlock when interrupts are disabled Archit Taneja
                             ` (5 subsequent siblings)
  7 siblings, 0 replies; 89+ messages in thread
From: Archit Taneja @ 2016-06-17  7:53 UTC (permalink / raw)
  To: dri-devel, treding, laurent.pinchart, xinliang.liu
  Cc: linux-arm-msm, srinivas.kandagatla, lars, amit.kucheria,
	robdclark, 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.

Signed-off-by: Archit Taneja <architt@codeaurora.org>
---
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

diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index 8f7423f..9ac6427 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -52,4 +52,6 @@ config DRM_PARADE_PS8622
 
 source "drivers/gpu/drm/bridge/analogix/Kconfig"
 
+source "drivers/gpu/drm/bridge/adv7511/Kconfig"
+
 endmenu
diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
index 96b13b3..94e7d2f 100644
--- a/drivers/gpu/drm/bridge/Makefile
+++ b/drivers/gpu/drm/bridge/Makefile
@@ -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/
diff --git a/drivers/gpu/drm/bridge/adv7511/Kconfig b/drivers/gpu/drm/bridge/adv7511/Kconfig
new file mode 100644
index 0000000..222c6cc
--- /dev/null
+++ b/drivers/gpu/drm/bridge/adv7511/Kconfig
@@ -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.
diff --git a/drivers/gpu/drm/bridge/adv7511/Makefile b/drivers/gpu/drm/bridge/adv7511/Makefile
new file mode 100644
index 0000000..692f83a
--- /dev/null
+++ b/drivers/gpu/drm/bridge/adv7511/Makefile
@@ -0,0 +1,2 @@
+adv7511-y := adv7511_drv.o
+obj-$(CONFIG_DRM_I2C_ADV7511) += adv7511.o
diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511.h b/drivers/gpu/drm/bridge/adv7511/adv7511.h
new file mode 100644
index 0000000..38515b3
--- /dev/null
+++ b/drivers/gpu/drm/bridge/adv7511/adv7511.h
@@ -0,0 +1,289 @@
+/*
+ * Analog Devices ADV7511 HDMI transmitter driver
+ *
+ * Copyright 2012 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#ifndef __DRM_I2C_ADV7511_H__
+#define __DRM_I2C_ADV7511_H__
+
+#include <linux/hdmi.h>
+
+#define ADV7511_REG_CHIP_REVISION		0x00
+#define ADV7511_REG_N0				0x01
+#define ADV7511_REG_N1				0x02
+#define ADV7511_REG_N2				0x03
+#define ADV7511_REG_SPDIF_FREQ			0x04
+#define ADV7511_REG_CTS_AUTOMATIC1		0x05
+#define ADV7511_REG_CTS_AUTOMATIC2		0x06
+#define ADV7511_REG_CTS_MANUAL0			0x07
+#define ADV7511_REG_CTS_MANUAL1			0x08
+#define ADV7511_REG_CTS_MANUAL2			0x09
+#define ADV7511_REG_AUDIO_SOURCE		0x0a
+#define ADV7511_REG_AUDIO_CONFIG		0x0b
+#define ADV7511_REG_I2S_CONFIG			0x0c
+#define ADV7511_REG_I2S_WIDTH			0x0d
+#define ADV7511_REG_AUDIO_SUB_SRC0		0x0e
+#define ADV7511_REG_AUDIO_SUB_SRC1		0x0f
+#define ADV7511_REG_AUDIO_SUB_SRC2		0x10
+#define ADV7511_REG_AUDIO_SUB_SRC3		0x11
+#define ADV7511_REG_AUDIO_CFG1			0x12
+#define ADV7511_REG_AUDIO_CFG2			0x13
+#define ADV7511_REG_AUDIO_CFG3			0x14
+#define ADV7511_REG_I2C_FREQ_ID_CFG		0x15
+#define ADV7511_REG_VIDEO_INPUT_CFG1		0x16
+#define ADV7511_REG_CSC_UPPER(x)		(0x18 + (x) * 2)
+#define ADV7511_REG_CSC_LOWER(x)		(0x19 + (x) * 2)
+#define ADV7511_REG_SYNC_DECODER(x)		(0x30 + (x))
+#define ADV7511_REG_DE_GENERATOR		(0x35 + (x))
+#define ADV7511_REG_PIXEL_REPETITION		0x3b
+#define ADV7511_REG_VIC_MANUAL			0x3c
+#define ADV7511_REG_VIC_SEND			0x3d
+#define ADV7511_REG_VIC_DETECTED		0x3e
+#define ADV7511_REG_AUX_VIC_DETECTED		0x3f
+#define ADV7511_REG_PACKET_ENABLE0		0x40
+#define ADV7511_REG_POWER			0x41
+#define ADV7511_REG_STATUS			0x42
+#define ADV7511_REG_EDID_I2C_ADDR		0x43
+#define ADV7511_REG_PACKET_ENABLE1		0x44
+#define ADV7511_REG_PACKET_I2C_ADDR		0x45
+#define ADV7511_REG_DSD_ENABLE			0x46
+#define ADV7511_REG_VIDEO_INPUT_CFG2		0x48
+#define ADV7511_REG_INFOFRAME_UPDATE		0x4a
+#define ADV7511_REG_GC(x)			(0x4b + (x)) /* 0x4b - 0x51 */
+#define ADV7511_REG_AVI_INFOFRAME_VERSION	0x52
+#define ADV7511_REG_AVI_INFOFRAME_LENGTH	0x53
+#define ADV7511_REG_AVI_INFOFRAME_CHECKSUM	0x54
+#define ADV7511_REG_AVI_INFOFRAME(x)		(0x55 + (x)) /* 0x55 - 0x6f */
+#define ADV7511_REG_AUDIO_INFOFRAME_VERSION	0x70
+#define ADV7511_REG_AUDIO_INFOFRAME_LENGTH	0x71
+#define ADV7511_REG_AUDIO_INFOFRAME_CHECKSUM	0x72
+#define ADV7511_REG_AUDIO_INFOFRAME(x)		(0x73 + (x)) /* 0x73 - 0x7c */
+#define ADV7511_REG_INT_ENABLE(x)		(0x94 + (x))
+#define ADV7511_REG_INT(x)			(0x96 + (x))
+#define ADV7511_REG_INPUT_CLK_DIV		0x9d
+#define ADV7511_REG_PLL_STATUS			0x9e
+#define ADV7511_REG_HDMI_POWER			0xa1
+#define ADV7511_REG_HDCP_HDMI_CFG		0xaf
+#define ADV7511_REG_AN(x)			(0xb0 + (x)) /* 0xb0 - 0xb7 */
+#define ADV7511_REG_HDCP_STATUS			0xb8
+#define ADV7511_REG_BCAPS			0xbe
+#define ADV7511_REG_BKSV(x)			(0xc0 + (x)) /* 0xc0 - 0xc3 */
+#define ADV7511_REG_EDID_SEGMENT		0xc4
+#define ADV7511_REG_DDC_STATUS			0xc8
+#define ADV7511_REG_EDID_READ_CTRL		0xc9
+#define ADV7511_REG_BSTATUS(x)			(0xca + (x)) /* 0xca - 0xcb */
+#define ADV7511_REG_TIMING_GEN_SEQ		0xd0
+#define ADV7511_REG_POWER2			0xd6
+#define ADV7511_REG_HSYNC_PLACEMENT_MSB		0xfa
+
+#define ADV7511_REG_SYNC_ADJUSTMENT(x)		(0xd7 + (x)) /* 0xd7 - 0xdc */
+#define ADV7511_REG_TMDS_CLOCK_INV		0xde
+#define ADV7511_REG_ARC_CTRL			0xdf
+#define ADV7511_REG_CEC_I2C_ADDR		0xe1
+#define ADV7511_REG_CEC_CTRL			0xe2
+#define ADV7511_REG_CHIP_ID_HIGH		0xf5
+#define ADV7511_REG_CHIP_ID_LOW			0xf6
+
+#define ADV7511_CSC_ENABLE			BIT(7)
+#define ADV7511_CSC_UPDATE_MODE			BIT(5)
+
+#define ADV7511_INT0_HPD			BIT(7)
+#define ADV7511_INT0_VSYNC			BIT(5)
+#define ADV7511_INT0_AUDIO_FIFO_FULL		BIT(4)
+#define ADV7511_INT0_EDID_READY			BIT(2)
+#define ADV7511_INT0_HDCP_AUTHENTICATED		BIT(1)
+
+#define ADV7511_INT1_DDC_ERROR			BIT(7)
+#define ADV7511_INT1_BKSV			BIT(6)
+#define ADV7511_INT1_CEC_TX_READY		BIT(5)
+#define ADV7511_INT1_CEC_TX_ARBIT_LOST		BIT(4)
+#define ADV7511_INT1_CEC_TX_RETRY_TIMEOUT	BIT(3)
+#define ADV7511_INT1_CEC_RX_READY3		BIT(2)
+#define ADV7511_INT1_CEC_RX_READY2		BIT(1)
+#define ADV7511_INT1_CEC_RX_READY1		BIT(0)
+
+#define ADV7511_ARC_CTRL_POWER_DOWN		BIT(0)
+
+#define ADV7511_CEC_CTRL_POWER_DOWN		BIT(0)
+
+#define ADV7511_POWER_POWER_DOWN		BIT(6)
+
+#define ADV7511_HDMI_CFG_MODE_MASK		0x2
+#define ADV7511_HDMI_CFG_MODE_DVI		0x0
+#define ADV7511_HDMI_CFG_MODE_HDMI		0x2
+
+#define ADV7511_AUDIO_SELECT_I2C		0x0
+#define ADV7511_AUDIO_SELECT_SPDIF		0x1
+#define ADV7511_AUDIO_SELECT_DSD		0x2
+#define ADV7511_AUDIO_SELECT_HBR		0x3
+#define ADV7511_AUDIO_SELECT_DST		0x4
+
+#define ADV7511_I2S_SAMPLE_LEN_16		0x2
+#define ADV7511_I2S_SAMPLE_LEN_20		0x3
+#define ADV7511_I2S_SAMPLE_LEN_18		0x4
+#define ADV7511_I2S_SAMPLE_LEN_22		0x5
+#define ADV7511_I2S_SAMPLE_LEN_19		0x8
+#define ADV7511_I2S_SAMPLE_LEN_23		0x9
+#define ADV7511_I2S_SAMPLE_LEN_24		0xb
+#define ADV7511_I2S_SAMPLE_LEN_17		0xc
+#define ADV7511_I2S_SAMPLE_LEN_21		0xd
+
+#define ADV7511_SAMPLE_FREQ_44100		0x0
+#define ADV7511_SAMPLE_FREQ_48000		0x2
+#define ADV7511_SAMPLE_FREQ_32000		0x3
+#define ADV7511_SAMPLE_FREQ_88200		0x8
+#define ADV7511_SAMPLE_FREQ_96000		0xa
+#define ADV7511_SAMPLE_FREQ_176400		0xc
+#define ADV7511_SAMPLE_FREQ_192000		0xe
+
+#define ADV7511_STATUS_POWER_DOWN_POLARITY	BIT(7)
+#define ADV7511_STATUS_HPD			BIT(6)
+#define ADV7511_STATUS_MONITOR_SENSE		BIT(5)
+#define ADV7511_STATUS_I2S_32BIT_MODE		BIT(3)
+
+#define ADV7511_PACKET_ENABLE_N_CTS		BIT(8+6)
+#define ADV7511_PACKET_ENABLE_AUDIO_SAMPLE	BIT(8+5)
+#define ADV7511_PACKET_ENABLE_AVI_INFOFRAME	BIT(8+4)
+#define ADV7511_PACKET_ENABLE_AUDIO_INFOFRAME	BIT(8+3)
+#define ADV7511_PACKET_ENABLE_GC		BIT(7)
+#define ADV7511_PACKET_ENABLE_SPD		BIT(6)
+#define ADV7511_PACKET_ENABLE_MPEG		BIT(5)
+#define ADV7511_PACKET_ENABLE_ACP		BIT(4)
+#define ADV7511_PACKET_ENABLE_ISRC		BIT(3)
+#define ADV7511_PACKET_ENABLE_GM		BIT(2)
+#define ADV7511_PACKET_ENABLE_SPARE2		BIT(1)
+#define ADV7511_PACKET_ENABLE_SPARE1		BIT(0)
+
+#define ADV7511_REG_POWER2_HPD_SRC_MASK		0xc0
+#define ADV7511_REG_POWER2_HPD_SRC_BOTH		0x00
+#define ADV7511_REG_POWER2_HPD_SRC_HPD		0x40
+#define ADV7511_REG_POWER2_HPD_SRC_CEC		0x80
+#define ADV7511_REG_POWER2_HPD_SRC_NONE		0xc0
+#define ADV7511_REG_POWER2_TDMS_ENABLE		BIT(4)
+#define ADV7511_REG_POWER2_GATE_INPUT_CLK	BIT(0)
+
+#define ADV7511_LOW_REFRESH_RATE_NONE		0x0
+#define ADV7511_LOW_REFRESH_RATE_24HZ		0x1
+#define ADV7511_LOW_REFRESH_RATE_25HZ		0x2
+#define ADV7511_LOW_REFRESH_RATE_30HZ		0x3
+
+#define ADV7511_AUDIO_CFG3_LEN_MASK		0x0f
+#define ADV7511_I2C_FREQ_ID_CFG_RATE_MASK	0xf0
+
+#define ADV7511_AUDIO_SOURCE_I2S		0
+#define ADV7511_AUDIO_SOURCE_SPDIF		1
+
+#define ADV7511_I2S_FORMAT_I2S			0
+#define ADV7511_I2S_FORMAT_RIGHT_J		1
+#define ADV7511_I2S_FORMAT_LEFT_J		2
+
+#define ADV7511_PACKET(p, x)	    ((p) * 0x20 + (x))
+#define ADV7511_PACKET_SDP(x)	    ADV7511_PACKET(0, x)
+#define ADV7511_PACKET_MPEG(x)	    ADV7511_PACKET(1, x)
+#define ADV7511_PACKET_ACP(x)	    ADV7511_PACKET(2, x)
+#define ADV7511_PACKET_ISRC1(x)	    ADV7511_PACKET(3, x)
+#define ADV7511_PACKET_ISRC2(x)	    ADV7511_PACKET(4, x)
+#define ADV7511_PACKET_GM(x)	    ADV7511_PACKET(5, x)
+#define ADV7511_PACKET_SPARE(x)	    ADV7511_PACKET(6, x)
+
+enum adv7511_input_clock {
+	ADV7511_INPUT_CLOCK_1X,
+	ADV7511_INPUT_CLOCK_2X,
+	ADV7511_INPUT_CLOCK_DDR,
+};
+
+enum adv7511_input_justification {
+	ADV7511_INPUT_JUSTIFICATION_EVENLY = 0,
+	ADV7511_INPUT_JUSTIFICATION_RIGHT = 1,
+	ADV7511_INPUT_JUSTIFICATION_LEFT = 2,
+};
+
+enum adv7511_input_sync_pulse {
+	ADV7511_INPUT_SYNC_PULSE_DE = 0,
+	ADV7511_INPUT_SYNC_PULSE_HSYNC = 1,
+	ADV7511_INPUT_SYNC_PULSE_VSYNC = 2,
+	ADV7511_INPUT_SYNC_PULSE_NONE = 3,
+};
+
+/**
+ * enum adv7511_sync_polarity - Polarity for the input sync signals
+ * @ADV7511_SYNC_POLARITY_PASSTHROUGH:  Sync polarity matches that of
+ *				       the currently configured mode.
+ * @ADV7511_SYNC_POLARITY_LOW:	    Sync polarity is low
+ * @ADV7511_SYNC_POLARITY_HIGH:	    Sync polarity is high
+ *
+ * If the polarity is set to either LOW or HIGH the driver will configure the
+ * ADV7511 to internally invert the sync signal if required to match the sync
+ * polarity setting for the currently selected output mode.
+ *
+ * If the polarity is set to PASSTHROUGH, the ADV7511 will route the signal
+ * unchanged. This is used when the upstream graphics core already generates
+ * the sync signals with the correct polarity.
+ */
+enum adv7511_sync_polarity {
+	ADV7511_SYNC_POLARITY_PASSTHROUGH,
+	ADV7511_SYNC_POLARITY_LOW,
+	ADV7511_SYNC_POLARITY_HIGH,
+};
+
+/**
+ * struct adv7511_link_config - Describes adv7511 hardware configuration
+ * @input_color_depth:		Number of bits per color component (8, 10 or 12)
+ * @input_colorspace:		The input colorspace (RGB, YUV444, YUV422)
+ * @input_clock:		The input video clock style (1x, 2x, DDR)
+ * @input_style:		The input component arrangement variant
+ * @input_justification:	Video input format bit justification
+ * @clock_delay:		Clock delay for the input clock (in ps)
+ * @embedded_sync:		Video input uses BT.656-style embedded sync
+ * @sync_pulse:			Select the sync pulse
+ * @vsync_polarity:		vsync input signal configuration
+ * @hsync_polarity:		hsync input signal configuration
+ */
+struct adv7511_link_config {
+	unsigned int input_color_depth;
+	enum hdmi_colorspace input_colorspace;
+	enum adv7511_input_clock input_clock;
+	unsigned int input_style;
+	enum adv7511_input_justification input_justification;
+
+	int clock_delay;
+
+	bool embedded_sync;
+	enum adv7511_input_sync_pulse sync_pulse;
+	enum adv7511_sync_polarity vsync_polarity;
+	enum adv7511_sync_polarity hsync_polarity;
+};
+
+/**
+ * enum adv7511_csc_scaling - Scaling factor for the ADV7511 CSC
+ * @ADV7511_CSC_SCALING_1: CSC results are not scaled
+ * @ADV7511_CSC_SCALING_2: CSC results are scaled by a factor of two
+ * @ADV7511_CSC_SCALING_4: CSC results are scalled by a factor of four
+ */
+enum adv7511_csc_scaling {
+	ADV7511_CSC_SCALING_1 = 0,
+	ADV7511_CSC_SCALING_2 = 1,
+	ADV7511_CSC_SCALING_4 = 2,
+};
+
+/**
+ * struct adv7511_video_config - Describes adv7511 hardware configuration
+ * @csc_enable:			Whether to enable color space conversion
+ * @csc_scaling_factor:		Color space conversion scaling factor
+ * @csc_coefficents:		Color space conversion coefficents
+ * @hdmi_mode:			Whether to use HDMI or DVI output mode
+ * @avi_infoframe:		HDMI infoframe
+ */
+struct adv7511_video_config {
+	bool csc_enable;
+	enum adv7511_csc_scaling csc_scaling_factor;
+	const uint16_t *csc_coefficents;
+
+	bool hdmi_mode;
+	struct hdmi_avi_infoframe avi_infoframe;
+};
+
+#endif /* __DRM_I2C_ADV7511_H__ */
diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
new file mode 100644
index 0000000..c2642f9
--- /dev/null
+++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
@@ -0,0 +1,1089 @@
+/*
+ * Analog Devices ADV7511 HDMI transmitter driver
+ *
+ * Copyright 2012 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#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 "adv7511.h"
+
+struct adv7511 {
+	struct i2c_client *i2c_main;
+	struct i2c_client *i2c_edid;
+
+	struct regmap *regmap;
+	struct regmap *packet_memory_regmap;
+	enum drm_connector_status status;
+	bool powered;
+
+	unsigned int f_tmds;
+
+	unsigned int current_edid_segment;
+	uint8_t edid_buf[256];
+	bool edid_read;
+
+	wait_queue_head_t wq;
+	struct drm_bridge bridge;
+	struct drm_connector connector;
+
+	bool embedded_sync;
+	enum adv7511_sync_polarity vsync_polarity;
+	enum adv7511_sync_polarity hsync_polarity;
+	bool rgb;
+
+	struct edid *edid;
+
+	struct gpio_desc *gpio_pd;
+};
+
+/* ADI recommended values for proper operation. */
+static const struct reg_sequence adv7511_fixed_registers[] = {
+	{ 0x98, 0x03 },
+	{ 0x9a, 0xe0 },
+	{ 0x9c, 0x30 },
+	{ 0x9d, 0x61 },
+	{ 0xa2, 0xa4 },
+	{ 0xa3, 0xa4 },
+	{ 0xe0, 0xd0 },
+	{ 0xf9, 0x00 },
+	{ 0x55, 0x02 },
+};
+
+/* -----------------------------------------------------------------------------
+ * Register access
+ */
+
+static const uint8_t adv7511_register_defaults[] = {
+	0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 00 */
+	0x00, 0x00, 0x01, 0x0e, 0xbc, 0x18, 0x01, 0x13,
+	0x25, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 10 */
+	0x46, 0x62, 0x04, 0xa8, 0x00, 0x00, 0x1c, 0x84,
+	0x1c, 0xbf, 0x04, 0xa8, 0x1e, 0x70, 0x02, 0x1e, /* 20 */
+	0x00, 0x00, 0x04, 0xa8, 0x08, 0x12, 0x1b, 0xac,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 30 */
+	0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xb0,
+	0x00, 0x50, 0x90, 0x7e, 0x79, 0x70, 0x00, 0x00, /* 40 */
+	0x00, 0xa8, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x02, 0x0d, 0x00, 0x00, 0x00, 0x00, /* 50 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 60 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x01, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 70 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 80 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 90 */
+	0x0b, 0x02, 0x00, 0x18, 0x5a, 0x60, 0x00, 0x00,
+	0x00, 0x00, 0x80, 0x80, 0x08, 0x04, 0x00, 0x00, /* a0 */
+	0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x14,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* b0 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* c0 */
+	0x00, 0x03, 0x00, 0x00, 0x02, 0x00, 0x01, 0x04,
+	0x30, 0xff, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, /* d0 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01,
+	0x80, 0x75, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, /* e0 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0x11, 0x00, /* f0 */
+	0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+static bool adv7511_register_volatile(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case ADV7511_REG_CHIP_REVISION:
+	case ADV7511_REG_SPDIF_FREQ:
+	case ADV7511_REG_CTS_AUTOMATIC1:
+	case ADV7511_REG_CTS_AUTOMATIC2:
+	case ADV7511_REG_VIC_DETECTED:
+	case ADV7511_REG_VIC_SEND:
+	case ADV7511_REG_AUX_VIC_DETECTED:
+	case ADV7511_REG_STATUS:
+	case ADV7511_REG_GC(1):
+	case ADV7511_REG_INT(0):
+	case ADV7511_REG_INT(1):
+	case ADV7511_REG_PLL_STATUS:
+	case ADV7511_REG_AN(0):
+	case ADV7511_REG_AN(1):
+	case ADV7511_REG_AN(2):
+	case ADV7511_REG_AN(3):
+	case ADV7511_REG_AN(4):
+	case ADV7511_REG_AN(5):
+	case ADV7511_REG_AN(6):
+	case ADV7511_REG_AN(7):
+	case ADV7511_REG_HDCP_STATUS:
+	case ADV7511_REG_BCAPS:
+	case ADV7511_REG_BKSV(0):
+	case ADV7511_REG_BKSV(1):
+	case ADV7511_REG_BKSV(2):
+	case ADV7511_REG_BKSV(3):
+	case ADV7511_REG_BKSV(4):
+	case ADV7511_REG_DDC_STATUS:
+	case ADV7511_REG_EDID_READ_CTRL:
+	case ADV7511_REG_BSTATUS(0):
+	case ADV7511_REG_BSTATUS(1):
+	case ADV7511_REG_CHIP_ID_HIGH:
+	case ADV7511_REG_CHIP_ID_LOW:
+		return true;
+	}
+
+	return false;
+}
+
+static const struct regmap_config adv7511_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.max_register = 0xff,
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults_raw = adv7511_register_defaults,
+	.num_reg_defaults_raw = ARRAY_SIZE(adv7511_register_defaults),
+
+	.volatile_reg = adv7511_register_volatile,
+};
+
+/* -----------------------------------------------------------------------------
+ * Hardware configuration
+ */
+
+static void adv7511_set_colormap(struct adv7511 *adv7511, bool enable,
+				 const uint16_t *coeff,
+				 unsigned int scaling_factor)
+{
+	unsigned int i;
+
+	regmap_update_bits(adv7511->regmap, ADV7511_REG_CSC_UPPER(1),
+			   ADV7511_CSC_UPDATE_MODE, ADV7511_CSC_UPDATE_MODE);
+
+	if (enable) {
+		for (i = 0; i < 12; ++i) {
+			regmap_update_bits(adv7511->regmap,
+					   ADV7511_REG_CSC_UPPER(i),
+					   0x1f, coeff[i] >> 8);
+			regmap_write(adv7511->regmap,
+				     ADV7511_REG_CSC_LOWER(i),
+				     coeff[i] & 0xff);
+		}
+	}
+
+	if (enable)
+		regmap_update_bits(adv7511->regmap, ADV7511_REG_CSC_UPPER(0),
+				   0xe0, 0x80 | (scaling_factor << 5));
+	else
+		regmap_update_bits(adv7511->regmap, ADV7511_REG_CSC_UPPER(0),
+				   0x80, 0x00);
+
+	regmap_update_bits(adv7511->regmap, ADV7511_REG_CSC_UPPER(1),
+			   ADV7511_CSC_UPDATE_MODE, 0);
+}
+
+static int adv7511_packet_enable(struct adv7511 *adv7511, unsigned int packet)
+{
+	if (packet & 0xff)
+		regmap_update_bits(adv7511->regmap, ADV7511_REG_PACKET_ENABLE0,
+				   packet, 0xff);
+
+	if (packet & 0xff00) {
+		packet >>= 8;
+		regmap_update_bits(adv7511->regmap, ADV7511_REG_PACKET_ENABLE1,
+				   packet, 0xff);
+	}
+
+	return 0;
+}
+
+static int adv7511_packet_disable(struct adv7511 *adv7511, unsigned int packet)
+{
+	if (packet & 0xff)
+		regmap_update_bits(adv7511->regmap, ADV7511_REG_PACKET_ENABLE0,
+				   packet, 0x00);
+
+	if (packet & 0xff00) {
+		packet >>= 8;
+		regmap_update_bits(adv7511->regmap, ADV7511_REG_PACKET_ENABLE1,
+				   packet, 0x00);
+	}
+
+	return 0;
+}
+
+/* Coefficients for adv7511 color space conversion */
+static const uint16_t adv7511_csc_ycbcr_to_rgb[] = {
+	0x0734, 0x04ad, 0x0000, 0x1c1b,
+	0x1ddc, 0x04ad, 0x1f24, 0x0135,
+	0x0000, 0x04ad, 0x087c, 0x1b77,
+};
+
+static void adv7511_set_config_csc(struct adv7511 *adv7511,
+				   struct drm_connector *connector,
+				   bool rgb)
+{
+	struct adv7511_video_config config;
+	bool output_format_422, output_format_ycbcr;
+	unsigned int mode;
+	uint8_t infoframe[17];
+
+	if (adv7511->edid)
+		config.hdmi_mode = drm_detect_hdmi_monitor(adv7511->edid);
+	else
+		config.hdmi_mode = false;
+
+	hdmi_avi_infoframe_init(&config.avi_infoframe);
+
+	config.avi_infoframe.scan_mode = HDMI_SCAN_MODE_UNDERSCAN;
+
+	if (rgb) {
+		config.csc_enable = false;
+		config.avi_infoframe.colorspace = HDMI_COLORSPACE_RGB;
+	} else {
+		config.csc_scaling_factor = ADV7511_CSC_SCALING_4;
+		config.csc_coefficents = adv7511_csc_ycbcr_to_rgb;
+
+		if ((connector->display_info.color_formats &
+		     DRM_COLOR_FORMAT_YCRCB422) &&
+		    config.hdmi_mode) {
+			config.csc_enable = false;
+			config.avi_infoframe.colorspace =
+				HDMI_COLORSPACE_YUV422;
+		} else {
+			config.csc_enable = true;
+			config.avi_infoframe.colorspace = HDMI_COLORSPACE_RGB;
+		}
+	}
+
+	if (config.hdmi_mode) {
+		mode = ADV7511_HDMI_CFG_MODE_HDMI;
+
+		switch (config.avi_infoframe.colorspace) {
+		case HDMI_COLORSPACE_YUV444:
+			output_format_422 = false;
+			output_format_ycbcr = true;
+			break;
+		case HDMI_COLORSPACE_YUV422:
+			output_format_422 = true;
+			output_format_ycbcr = true;
+			break;
+		default:
+			output_format_422 = false;
+			output_format_ycbcr = false;
+			break;
+		}
+	} else {
+		mode = ADV7511_HDMI_CFG_MODE_DVI;
+		output_format_422 = false;
+		output_format_ycbcr = false;
+	}
+
+	adv7511_packet_disable(adv7511, ADV7511_PACKET_ENABLE_AVI_INFOFRAME);
+
+	adv7511_set_colormap(adv7511, config.csc_enable,
+			     config.csc_coefficents,
+			     config.csc_scaling_factor);
+
+	regmap_update_bits(adv7511->regmap, ADV7511_REG_VIDEO_INPUT_CFG1, 0x81,
+			   (output_format_422 << 7) | output_format_ycbcr);
+
+	regmap_update_bits(adv7511->regmap, ADV7511_REG_HDCP_HDMI_CFG,
+			   ADV7511_HDMI_CFG_MODE_MASK, mode);
+
+	hdmi_avi_infoframe_pack(&config.avi_infoframe, infoframe,
+				sizeof(infoframe));
+
+	/* The AVI infoframe id is not configurable */
+	regmap_bulk_write(adv7511->regmap, ADV7511_REG_AVI_INFOFRAME_VERSION,
+			  infoframe + 1, sizeof(infoframe) - 1);
+
+	adv7511_packet_enable(adv7511, ADV7511_PACKET_ENABLE_AVI_INFOFRAME);
+}
+
+static void adv7511_set_link_config(struct adv7511 *adv7511,
+				    const struct adv7511_link_config *config)
+{
+	/*
+	 * The input style values documented in the datasheet don't match the
+	 * hardware register field values :-(
+	 */
+	static const unsigned int input_styles[4] = { 0, 2, 1, 3 };
+
+	unsigned int clock_delay;
+	unsigned int color_depth;
+	unsigned int input_id;
+
+	clock_delay = (config->clock_delay + 1200) / 400;
+	color_depth = config->input_color_depth == 8 ? 3
+		    : (config->input_color_depth == 10 ? 1 : 2);
+
+	/* TODO Support input ID 6 */
+	if (config->input_colorspace != HDMI_COLORSPACE_YUV422)
+		input_id = config->input_clock == ADV7511_INPUT_CLOCK_DDR
+			 ? 5 : 0;
+	else if (config->input_clock == ADV7511_INPUT_CLOCK_DDR)
+		input_id = config->embedded_sync ? 8 : 7;
+	else if (config->input_clock == ADV7511_INPUT_CLOCK_2X)
+		input_id = config->embedded_sync ? 4 : 3;
+	else
+		input_id = config->embedded_sync ? 2 : 1;
+
+	regmap_update_bits(adv7511->regmap, ADV7511_REG_I2C_FREQ_ID_CFG, 0xf,
+			   input_id);
+	regmap_update_bits(adv7511->regmap, ADV7511_REG_VIDEO_INPUT_CFG1, 0x7e,
+			   (color_depth << 4) |
+			   (input_styles[config->input_style] << 2));
+	regmap_write(adv7511->regmap, ADV7511_REG_VIDEO_INPUT_CFG2,
+		     config->input_justification << 3);
+	regmap_write(adv7511->regmap, ADV7511_REG_TIMING_GEN_SEQ,
+		     config->sync_pulse << 2);
+
+	regmap_write(adv7511->regmap, 0xba, clock_delay << 5);
+
+	adv7511->embedded_sync = config->embedded_sync;
+	adv7511->hsync_polarity = config->hsync_polarity;
+	adv7511->vsync_polarity = config->vsync_polarity;
+	adv7511->rgb = config->input_colorspace == HDMI_COLORSPACE_RGB;
+}
+
+static void adv7511_power_on(struct adv7511 *adv7511)
+{
+	adv7511->current_edid_segment = -1;
+
+	regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER,
+			   ADV7511_POWER_POWER_DOWN, 0);
+	if (adv7511->i2c_main->irq) {
+		/*
+		 * Documentation says the INT_ENABLE registers are reset in
+		 * POWER_DOWN mode. My 7511w preserved the bits, however.
+		 * Still, let's be safe and stick to the documentation.
+		 */
+		regmap_write(adv7511->regmap, ADV7511_REG_INT_ENABLE(0),
+			     ADV7511_INT0_EDID_READY);
+		regmap_write(adv7511->regmap, ADV7511_REG_INT_ENABLE(1),
+			     ADV7511_INT1_DDC_ERROR);
+	}
+
+	/*
+	 * Per spec it is allowed to pulse the HPD signal to indicate that the
+	 * EDID information has changed. Some monitors do this when they wakeup
+	 * from standby or are enabled. When the HPD goes low the adv7511 is
+	 * reset and the outputs are disabled which might cause the monitor to
+	 * go to standby again. To avoid this we ignore the HPD pin for the
+	 * first few seconds after enabling the output.
+	 */
+	regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2,
+			   ADV7511_REG_POWER2_HPD_SRC_MASK,
+			   ADV7511_REG_POWER2_HPD_SRC_NONE);
+
+	/*
+	 * Most of the registers are reset during power down or when HPD is low.
+	 */
+	regcache_sync(adv7511->regmap);
+
+	adv7511->powered = true;
+}
+
+static void adv7511_power_off(struct adv7511 *adv7511)
+{
+	/* TODO: setup additional power down modes */
+	regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER,
+			   ADV7511_POWER_POWER_DOWN,
+			   ADV7511_POWER_POWER_DOWN);
+	regcache_mark_dirty(adv7511->regmap);
+
+	adv7511->powered = false;
+}
+
+/* -----------------------------------------------------------------------------
+ * Interrupt and hotplug detection
+ */
+
+static bool adv7511_hpd(struct adv7511 *adv7511)
+{
+	unsigned int irq0;
+	int ret;
+
+	ret = regmap_read(adv7511->regmap, ADV7511_REG_INT(0), &irq0);
+	if (ret < 0)
+		return false;
+
+	if (irq0 & ADV7511_INT0_HPD) {
+		regmap_write(adv7511->regmap, ADV7511_REG_INT(0),
+			     ADV7511_INT0_HPD);
+		return true;
+	}
+
+	return false;
+}
+
+static int adv7511_irq_process(struct adv7511 *adv7511)
+{
+	unsigned int irq0, irq1;
+	int ret;
+
+	ret = regmap_read(adv7511->regmap, ADV7511_REG_INT(0), &irq0);
+	if (ret < 0)
+		return ret;
+
+	ret = regmap_read(adv7511->regmap, ADV7511_REG_INT(1), &irq1);
+	if (ret < 0)
+		return ret;
+
+	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)
+		drm_helper_hpd_irq_event(adv7511->connector.dev);
+
+	if (irq0 & ADV7511_INT0_EDID_READY || irq1 & ADV7511_INT1_DDC_ERROR) {
+		adv7511->edid_read = true;
+
+		if (adv7511->i2c_main->irq)
+			wake_up_all(&adv7511->wq);
+	}
+
+	return 0;
+}
+
+static irqreturn_t adv7511_irq_handler(int irq, void *devid)
+{
+	struct adv7511 *adv7511 = devid;
+	int ret;
+
+	ret = adv7511_irq_process(adv7511);
+	return ret < 0 ? IRQ_NONE : IRQ_HANDLED;
+}
+
+/* -----------------------------------------------------------------------------
+ * EDID retrieval
+ */
+
+static int adv7511_wait_for_edid(struct adv7511 *adv7511, int timeout)
+{
+	int ret;
+
+	if (adv7511->i2c_main->irq) {
+		ret = wait_event_interruptible_timeout(adv7511->wq,
+				adv7511->edid_read, msecs_to_jiffies(timeout));
+	} else {
+		for (; timeout > 0; timeout -= 25) {
+			ret = adv7511_irq_process(adv7511);
+			if (ret < 0)
+				break;
+
+			if (adv7511->edid_read)
+				break;
+
+			msleep(25);
+		}
+	}
+
+	return adv7511->edid_read ? 0 : -EIO;
+}
+
+static int adv7511_get_edid_block(void *data, u8 *buf, unsigned int block,
+				  size_t len)
+{
+	struct adv7511 *adv7511 = data;
+	struct i2c_msg xfer[2];
+	uint8_t offset;
+	unsigned int i;
+	int ret;
+
+	if (len > 128)
+		return -EINVAL;
+
+	if (adv7511->current_edid_segment != block / 2) {
+		unsigned int status;
+
+		ret = regmap_read(adv7511->regmap, ADV7511_REG_DDC_STATUS,
+				  &status);
+		if (ret < 0)
+			return ret;
+
+		if (status != 2) {
+			adv7511->edid_read = false;
+			regmap_write(adv7511->regmap, ADV7511_REG_EDID_SEGMENT,
+				     block);
+			ret = adv7511_wait_for_edid(adv7511, 200);
+			if (ret < 0)
+				return ret;
+		}
+
+		/* Break this apart, hopefully more I2C controllers will
+		 * support 64 byte transfers than 256 byte transfers
+		 */
+
+		xfer[0].addr = adv7511->i2c_edid->addr;
+		xfer[0].flags = 0;
+		xfer[0].len = 1;
+		xfer[0].buf = &offset;
+		xfer[1].addr = adv7511->i2c_edid->addr;
+		xfer[1].flags = I2C_M_RD;
+		xfer[1].len = 64;
+		xfer[1].buf = adv7511->edid_buf;
+
+		offset = 0;
+
+		for (i = 0; i < 4; ++i) {
+			ret = i2c_transfer(adv7511->i2c_edid->adapter, xfer,
+					   ARRAY_SIZE(xfer));
+			if (ret < 0)
+				return ret;
+			else if (ret != 2)
+				return -EIO;
+
+			xfer[1].buf += 64;
+			offset += 64;
+		}
+
+		adv7511->current_edid_segment = block / 2;
+	}
+
+	if (block % 2 == 0)
+		memcpy(buf, adv7511->edid_buf, len);
+	else
+		memcpy(buf, adv7511->edid_buf + 128, len);
+
+	return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * ADV75xx helpers
+ */
+
+static int adv7511_get_modes(struct adv7511 *adv7511,
+			     struct drm_connector *connector)
+{
+	struct edid *edid;
+	unsigned int count;
+
+	/* Reading the EDID only works if the device is powered */
+	if (!adv7511->powered) {
+		regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER,
+				   ADV7511_POWER_POWER_DOWN, 0);
+		if (adv7511->i2c_main->irq) {
+			regmap_write(adv7511->regmap, ADV7511_REG_INT_ENABLE(0),
+				     ADV7511_INT0_EDID_READY);
+			regmap_write(adv7511->regmap, ADV7511_REG_INT_ENABLE(1),
+				     ADV7511_INT1_DDC_ERROR);
+		}
+		adv7511->current_edid_segment = -1;
+	}
+
+	edid = drm_do_get_edid(connector, adv7511_get_edid_block, adv7511);
+
+	if (!adv7511->powered)
+		regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER,
+				   ADV7511_POWER_POWER_DOWN,
+				   ADV7511_POWER_POWER_DOWN);
+
+	kfree(adv7511->edid);
+	adv7511->edid = edid;
+	if (!edid)
+		return 0;
+
+	drm_mode_connector_update_edid_property(connector, edid);
+	count = drm_add_edid_modes(connector, edid);
+
+	adv7511_set_config_csc(adv7511, connector, adv7511->rgb);
+
+	return count;
+}
+
+static enum drm_connector_status
+adv7511_detect(struct adv7511 *adv7511, struct drm_connector *connector)
+{
+	enum drm_connector_status status;
+	unsigned int val;
+	bool hpd;
+	int ret;
+
+	ret = regmap_read(adv7511->regmap, ADV7511_REG_STATUS, &val);
+	if (ret < 0)
+		return connector_status_disconnected;
+
+	if (val & ADV7511_STATUS_HPD)
+		status = connector_status_connected;
+	else
+		status = connector_status_disconnected;
+
+	hpd = adv7511_hpd(adv7511);
+
+	/* The chip resets itself when the cable is disconnected, so in case
+	 * there is a pending HPD interrupt and the cable is connected there was
+	 * at least one transition from disconnected to connected and the chip
+	 * has to be reinitialized. */
+	if (status == connector_status_connected && hpd && adv7511->powered) {
+		regcache_mark_dirty(adv7511->regmap);
+		adv7511_power_on(adv7511);
+		adv7511_get_modes(adv7511, connector);
+		if (adv7511->status == connector_status_connected)
+			status = connector_status_disconnected;
+	} else {
+		/* Renable HPD sensing */
+		regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2,
+				   ADV7511_REG_POWER2_HPD_SRC_MASK,
+				   ADV7511_REG_POWER2_HPD_SRC_BOTH);
+	}
+
+	adv7511->status = status;
+	return status;
+}
+
+static int adv7511_mode_valid(struct adv7511 *adv7511,
+			      struct drm_display_mode *mode)
+{
+	if (mode->clock > 165000)
+		return MODE_CLOCK_HIGH;
+
+	return MODE_OK;
+}
+
+static void adv7511_mode_set(struct adv7511 *adv7511,
+			     struct drm_display_mode *mode,
+			     struct drm_display_mode *adj_mode)
+{
+	unsigned int low_refresh_rate;
+	unsigned int hsync_polarity = 0;
+	unsigned int vsync_polarity = 0;
+
+	if (adv7511->embedded_sync) {
+		unsigned int hsync_offset, hsync_len;
+		unsigned int vsync_offset, vsync_len;
+
+		hsync_offset = adj_mode->crtc_hsync_start -
+			       adj_mode->crtc_hdisplay;
+		vsync_offset = adj_mode->crtc_vsync_start -
+			       adj_mode->crtc_vdisplay;
+		hsync_len = adj_mode->crtc_hsync_end -
+			    adj_mode->crtc_hsync_start;
+		vsync_len = adj_mode->crtc_vsync_end -
+			    adj_mode->crtc_vsync_start;
+
+		/* The hardware vsync generator has a off-by-one bug */
+		vsync_offset += 1;
+
+		regmap_write(adv7511->regmap, ADV7511_REG_HSYNC_PLACEMENT_MSB,
+			     ((hsync_offset >> 10) & 0x7) << 5);
+		regmap_write(adv7511->regmap, ADV7511_REG_SYNC_DECODER(0),
+			     (hsync_offset >> 2) & 0xff);
+		regmap_write(adv7511->regmap, ADV7511_REG_SYNC_DECODER(1),
+			     ((hsync_offset & 0x3) << 6) |
+			     ((hsync_len >> 4) & 0x3f));
+		regmap_write(adv7511->regmap, ADV7511_REG_SYNC_DECODER(2),
+			     ((hsync_len & 0xf) << 4) |
+			     ((vsync_offset >> 6) & 0xf));
+		regmap_write(adv7511->regmap, ADV7511_REG_SYNC_DECODER(3),
+			     ((vsync_offset & 0x3f) << 2) |
+			     ((vsync_len >> 8) & 0x3));
+		regmap_write(adv7511->regmap, ADV7511_REG_SYNC_DECODER(4),
+			     vsync_len & 0xff);
+
+		hsync_polarity = !(adj_mode->flags & DRM_MODE_FLAG_PHSYNC);
+		vsync_polarity = !(adj_mode->flags & DRM_MODE_FLAG_PVSYNC);
+	} else {
+		enum adv7511_sync_polarity mode_hsync_polarity;
+		enum adv7511_sync_polarity mode_vsync_polarity;
+
+		/**
+		 * If the input signal is always low or always high we want to
+		 * invert or let it passthrough depending on the polarity of the
+		 * current mode.
+		 **/
+		if (adj_mode->flags & DRM_MODE_FLAG_NHSYNC)
+			mode_hsync_polarity = ADV7511_SYNC_POLARITY_LOW;
+		else
+			mode_hsync_polarity = ADV7511_SYNC_POLARITY_HIGH;
+
+		if (adj_mode->flags & DRM_MODE_FLAG_NVSYNC)
+			mode_vsync_polarity = ADV7511_SYNC_POLARITY_LOW;
+		else
+			mode_vsync_polarity = ADV7511_SYNC_POLARITY_HIGH;
+
+		if (adv7511->hsync_polarity != mode_hsync_polarity &&
+		    adv7511->hsync_polarity !=
+		    ADV7511_SYNC_POLARITY_PASSTHROUGH)
+			hsync_polarity = 1;
+
+		if (adv7511->vsync_polarity != mode_vsync_polarity &&
+		    adv7511->vsync_polarity !=
+		    ADV7511_SYNC_POLARITY_PASSTHROUGH)
+			vsync_polarity = 1;
+	}
+
+	if (mode->vrefresh <= 24000)
+		low_refresh_rate = ADV7511_LOW_REFRESH_RATE_24HZ;
+	else if (mode->vrefresh <= 25000)
+		low_refresh_rate = ADV7511_LOW_REFRESH_RATE_25HZ;
+	else if (mode->vrefresh <= 30000)
+		low_refresh_rate = ADV7511_LOW_REFRESH_RATE_30HZ;
+	else
+		low_refresh_rate = ADV7511_LOW_REFRESH_RATE_NONE;
+
+	regmap_update_bits(adv7511->regmap, 0xfb,
+		0x6, low_refresh_rate << 1);
+	regmap_update_bits(adv7511->regmap, 0x17,
+		0x60, (vsync_polarity << 6) | (hsync_polarity << 5));
+
+	/*
+	 * TODO Test first order 4:2:2 to 4:4:4 up conversion method, which is
+	 * supposed to give better results.
+	 */
+
+	adv7511->f_tmds = mode->clock;
+}
+
+/* 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 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,
+	.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,
+};
+
+/* -----------------------------------------------------------------------------
+ * Probe & remove
+ */
+
+static int adv7511_parse_dt(struct device_node *np,
+			    struct adv7511_link_config *config)
+{
+	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)
+		return -EINVAL;
+
+	ret = of_property_read_string(np, "adi,input-colorspace", &str);
+	if (ret < 0)
+		return ret;
+
+	if (!strcmp(str, "rgb"))
+		config->input_colorspace = HDMI_COLORSPACE_RGB;
+	else if (!strcmp(str, "yuv422"))
+		config->input_colorspace = HDMI_COLORSPACE_YUV422;
+	else if (!strcmp(str, "yuv444"))
+		config->input_colorspace = HDMI_COLORSPACE_YUV444;
+	else
+		return -EINVAL;
+
+	ret = of_property_read_string(np, "adi,input-clock", &str);
+	if (ret < 0)
+		return ret;
+
+	if (!strcmp(str, "1x"))
+		config->input_clock = ADV7511_INPUT_CLOCK_1X;
+	else if (!strcmp(str, "2x"))
+		config->input_clock = ADV7511_INPUT_CLOCK_2X;
+	else if (!strcmp(str, "ddr"))
+		config->input_clock = ADV7511_INPUT_CLOCK_DDR;
+	else
+		return -EINVAL;
+
+	if (config->input_colorspace == HDMI_COLORSPACE_YUV422 ||
+	    config->input_clock != ADV7511_INPUT_CLOCK_1X) {
+		ret = of_property_read_u32(np, "adi,input-style",
+					   &config->input_style);
+		if (ret)
+			return ret;
+
+		if (config->input_style < 1 || config->input_style > 3)
+			return -EINVAL;
+
+		ret = of_property_read_string(np, "adi,input-justification",
+					      &str);
+		if (ret < 0)
+			return ret;
+
+		if (!strcmp(str, "left"))
+			config->input_justification =
+				ADV7511_INPUT_JUSTIFICATION_LEFT;
+		else if (!strcmp(str, "evenly"))
+			config->input_justification =
+				ADV7511_INPUT_JUSTIFICATION_EVENLY;
+		else if (!strcmp(str, "right"))
+			config->input_justification =
+				ADV7511_INPUT_JUSTIFICATION_RIGHT;
+		else
+			return -EINVAL;
+
+	} else {
+		config->input_style = 1;
+		config->input_justification = ADV7511_INPUT_JUSTIFICATION_LEFT;
+	}
+
+	of_property_read_u32(np, "adi,clock-delay", &config->clock_delay);
+	if (config->clock_delay < -1200 || config->clock_delay > 1600)
+		return -EINVAL;
+
+	config->embedded_sync = of_property_read_bool(np, "adi,embedded-sync");
+
+	/* Hardcode the sync pulse configurations for now. */
+	config->sync_pulse = ADV7511_INPUT_SYNC_PULSE_NONE;
+	config->vsync_polarity = ADV7511_SYNC_POLARITY_PASSTHROUGH;
+	config->hsync_polarity = ADV7511_SYNC_POLARITY_PASSTHROUGH;
+
+	return 0;
+}
+
+static const int edid_i2c_addr = 0x7e;
+static const int packet_i2c_addr = 0x70;
+static const int cec_i2c_addr = 0x78;
+
+static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
+{
+	struct adv7511_link_config link_config;
+	struct adv7511 *adv7511;
+	struct device *dev = &i2c->dev;
+	unsigned int val;
+	int ret;
+
+	if (!dev->of_node)
+		return -EINVAL;
+
+	adv7511 = devm_kzalloc(dev, sizeof(*adv7511), GFP_KERNEL);
+	if (!adv7511)
+		return -ENOMEM;
+
+	adv7511->powered = false;
+	adv7511->status = connector_status_disconnected;
+
+	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
+	 * inactive to wake up the encoder.
+	 */
+	adv7511->gpio_pd = devm_gpiod_get_optional(dev, "pd", GPIOD_OUT_HIGH);
+	if (IS_ERR(adv7511->gpio_pd))
+		return PTR_ERR(adv7511->gpio_pd);
+
+	if (adv7511->gpio_pd) {
+		mdelay(5);
+		gpiod_set_value_cansleep(adv7511->gpio_pd, 0);
+	}
+
+	adv7511->regmap = devm_regmap_init_i2c(i2c, &adv7511_regmap_config);
+	if (IS_ERR(adv7511->regmap))
+		return PTR_ERR(adv7511->regmap);
+
+	ret = regmap_read(adv7511->regmap, ADV7511_REG_CHIP_REVISION, &val);
+	if (ret)
+		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;
+
+	regmap_write(adv7511->regmap, ADV7511_REG_EDID_I2C_ADDR, edid_i2c_addr);
+	regmap_write(adv7511->regmap, ADV7511_REG_PACKET_I2C_ADDR,
+		     packet_i2c_addr);
+	regmap_write(adv7511->regmap, ADV7511_REG_CEC_I2C_ADDR, cec_i2c_addr);
+	adv7511_packet_disable(adv7511, 0xffff);
+
+	adv7511->i2c_main = i2c;
+	adv7511->i2c_edid = i2c_new_dummy(i2c->adapter, edid_i2c_addr >> 1);
+	if (!adv7511->i2c_edid)
+		return -ENOMEM;
+
+	if (i2c->irq) {
+		init_waitqueue_head(&adv7511->wq);
+
+		ret = devm_request_threaded_irq(dev, i2c->irq, NULL,
+						adv7511_irq_handler,
+						IRQF_ONESHOT, dev_name(dev),
+						adv7511);
+		if (ret)
+			goto err_i2c_unregister_device;
+	}
+
+	/* CEC is unused for now */
+	regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL,
+		     ADV7511_CEC_CTRL_POWER_DOWN);
+
+	adv7511_power_off(adv7511);
+
+	i2c_set_clientdata(i2c, adv7511);
+
+	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:
+	i2c_unregister_device(adv7511->i2c_edid);
+
+	return ret;
+}
+
+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);
+
+	return 0;
+}
+
+static const struct i2c_device_id adv7511_i2c_ids[] = {
+	{ "adv7511", 0 },
+	{ "adv7511w", 0 },
+	{ "adv7513", 0 },
+	{ }
+};
+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 i2c_driver adv7511_driver = {
+	.driver = {
+		.name = "adv7511",
+		.of_match_table = adv7511_of_ids,
+	},
+	.id_table = adv7511_i2c_ids,
+	.probe = adv7511_probe,
+	.remove = adv7511_remove,
+};
+
+module_i2c_driver(adv7511_driver);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("ADV7511 HDMI transmitter driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/i2c/Kconfig b/drivers/gpu/drm/i2c/Kconfig
index 8bb0697..4d341db 100644
--- a/drivers/gpu/drm/i2c/Kconfig
+++ b/drivers/gpu/drm/i2c/Kconfig
@@ -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
diff --git a/drivers/gpu/drm/i2c/Makefile b/drivers/gpu/drm/i2c/Makefile
index 2c72eb5..43aa33b 100644
--- a/drivers/gpu/drm/i2c/Makefile
+++ b/drivers/gpu/drm/i2c/Makefile
@@ -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
 
diff --git a/drivers/gpu/drm/i2c/adv7511.c b/drivers/gpu/drm/i2c/adv7511.c
deleted file mode 100644
index c2642f9..0000000
--- a/drivers/gpu/drm/i2c/adv7511.c
+++ /dev/null
@@ -1,1089 +0,0 @@
-/*
- * Analog Devices ADV7511 HDMI transmitter driver
- *
- * Copyright 2012 Analog Devices Inc.
- *
- * Licensed under the GPL-2.
- */
-
-#include <linux/device.h>
-#include <linux/gpio/consumer.h>
-#include <linux/i2c.h>
-#include <linux/module.h>
-#include <linux/regmap.h>
-#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 "adv7511.h"
-
-struct adv7511 {
-	struct i2c_client *i2c_main;
-	struct i2c_client *i2c_edid;
-
-	struct regmap *regmap;
-	struct regmap *packet_memory_regmap;
-	enum drm_connector_status status;
-	bool powered;
-
-	unsigned int f_tmds;
-
-	unsigned int current_edid_segment;
-	uint8_t edid_buf[256];
-	bool edid_read;
-
-	wait_queue_head_t wq;
-	struct drm_bridge bridge;
-	struct drm_connector connector;
-
-	bool embedded_sync;
-	enum adv7511_sync_polarity vsync_polarity;
-	enum adv7511_sync_polarity hsync_polarity;
-	bool rgb;
-
-	struct edid *edid;
-
-	struct gpio_desc *gpio_pd;
-};
-
-/* ADI recommended values for proper operation. */
-static const struct reg_sequence adv7511_fixed_registers[] = {
-	{ 0x98, 0x03 },
-	{ 0x9a, 0xe0 },
-	{ 0x9c, 0x30 },
-	{ 0x9d, 0x61 },
-	{ 0xa2, 0xa4 },
-	{ 0xa3, 0xa4 },
-	{ 0xe0, 0xd0 },
-	{ 0xf9, 0x00 },
-	{ 0x55, 0x02 },
-};
-
-/* -----------------------------------------------------------------------------
- * Register access
- */
-
-static const uint8_t adv7511_register_defaults[] = {
-	0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 00 */
-	0x00, 0x00, 0x01, 0x0e, 0xbc, 0x18, 0x01, 0x13,
-	0x25, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 10 */
-	0x46, 0x62, 0x04, 0xa8, 0x00, 0x00, 0x1c, 0x84,
-	0x1c, 0xbf, 0x04, 0xa8, 0x1e, 0x70, 0x02, 0x1e, /* 20 */
-	0x00, 0x00, 0x04, 0xa8, 0x08, 0x12, 0x1b, 0xac,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 30 */
-	0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xb0,
-	0x00, 0x50, 0x90, 0x7e, 0x79, 0x70, 0x00, 0x00, /* 40 */
-	0x00, 0xa8, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x02, 0x0d, 0x00, 0x00, 0x00, 0x00, /* 50 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 60 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x01, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 70 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 80 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 90 */
-	0x0b, 0x02, 0x00, 0x18, 0x5a, 0x60, 0x00, 0x00,
-	0x00, 0x00, 0x80, 0x80, 0x08, 0x04, 0x00, 0x00, /* a0 */
-	0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x14,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* b0 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* c0 */
-	0x00, 0x03, 0x00, 0x00, 0x02, 0x00, 0x01, 0x04,
-	0x30, 0xff, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, /* d0 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01,
-	0x80, 0x75, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, /* e0 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0x11, 0x00, /* f0 */
-	0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-};
-
-static bool adv7511_register_volatile(struct device *dev, unsigned int reg)
-{
-	switch (reg) {
-	case ADV7511_REG_CHIP_REVISION:
-	case ADV7511_REG_SPDIF_FREQ:
-	case ADV7511_REG_CTS_AUTOMATIC1:
-	case ADV7511_REG_CTS_AUTOMATIC2:
-	case ADV7511_REG_VIC_DETECTED:
-	case ADV7511_REG_VIC_SEND:
-	case ADV7511_REG_AUX_VIC_DETECTED:
-	case ADV7511_REG_STATUS:
-	case ADV7511_REG_GC(1):
-	case ADV7511_REG_INT(0):
-	case ADV7511_REG_INT(1):
-	case ADV7511_REG_PLL_STATUS:
-	case ADV7511_REG_AN(0):
-	case ADV7511_REG_AN(1):
-	case ADV7511_REG_AN(2):
-	case ADV7511_REG_AN(3):
-	case ADV7511_REG_AN(4):
-	case ADV7511_REG_AN(5):
-	case ADV7511_REG_AN(6):
-	case ADV7511_REG_AN(7):
-	case ADV7511_REG_HDCP_STATUS:
-	case ADV7511_REG_BCAPS:
-	case ADV7511_REG_BKSV(0):
-	case ADV7511_REG_BKSV(1):
-	case ADV7511_REG_BKSV(2):
-	case ADV7511_REG_BKSV(3):
-	case ADV7511_REG_BKSV(4):
-	case ADV7511_REG_DDC_STATUS:
-	case ADV7511_REG_EDID_READ_CTRL:
-	case ADV7511_REG_BSTATUS(0):
-	case ADV7511_REG_BSTATUS(1):
-	case ADV7511_REG_CHIP_ID_HIGH:
-	case ADV7511_REG_CHIP_ID_LOW:
-		return true;
-	}
-
-	return false;
-}
-
-static const struct regmap_config adv7511_regmap_config = {
-	.reg_bits = 8,
-	.val_bits = 8,
-
-	.max_register = 0xff,
-	.cache_type = REGCACHE_RBTREE,
-	.reg_defaults_raw = adv7511_register_defaults,
-	.num_reg_defaults_raw = ARRAY_SIZE(adv7511_register_defaults),
-
-	.volatile_reg = adv7511_register_volatile,
-};
-
-/* -----------------------------------------------------------------------------
- * Hardware configuration
- */
-
-static void adv7511_set_colormap(struct adv7511 *adv7511, bool enable,
-				 const uint16_t *coeff,
-				 unsigned int scaling_factor)
-{
-	unsigned int i;
-
-	regmap_update_bits(adv7511->regmap, ADV7511_REG_CSC_UPPER(1),
-			   ADV7511_CSC_UPDATE_MODE, ADV7511_CSC_UPDATE_MODE);
-
-	if (enable) {
-		for (i = 0; i < 12; ++i) {
-			regmap_update_bits(adv7511->regmap,
-					   ADV7511_REG_CSC_UPPER(i),
-					   0x1f, coeff[i] >> 8);
-			regmap_write(adv7511->regmap,
-				     ADV7511_REG_CSC_LOWER(i),
-				     coeff[i] & 0xff);
-		}
-	}
-
-	if (enable)
-		regmap_update_bits(adv7511->regmap, ADV7511_REG_CSC_UPPER(0),
-				   0xe0, 0x80 | (scaling_factor << 5));
-	else
-		regmap_update_bits(adv7511->regmap, ADV7511_REG_CSC_UPPER(0),
-				   0x80, 0x00);
-
-	regmap_update_bits(adv7511->regmap, ADV7511_REG_CSC_UPPER(1),
-			   ADV7511_CSC_UPDATE_MODE, 0);
-}
-
-static int adv7511_packet_enable(struct adv7511 *adv7511, unsigned int packet)
-{
-	if (packet & 0xff)
-		regmap_update_bits(adv7511->regmap, ADV7511_REG_PACKET_ENABLE0,
-				   packet, 0xff);
-
-	if (packet & 0xff00) {
-		packet >>= 8;
-		regmap_update_bits(adv7511->regmap, ADV7511_REG_PACKET_ENABLE1,
-				   packet, 0xff);
-	}
-
-	return 0;
-}
-
-static int adv7511_packet_disable(struct adv7511 *adv7511, unsigned int packet)
-{
-	if (packet & 0xff)
-		regmap_update_bits(adv7511->regmap, ADV7511_REG_PACKET_ENABLE0,
-				   packet, 0x00);
-
-	if (packet & 0xff00) {
-		packet >>= 8;
-		regmap_update_bits(adv7511->regmap, ADV7511_REG_PACKET_ENABLE1,
-				   packet, 0x00);
-	}
-
-	return 0;
-}
-
-/* Coefficients for adv7511 color space conversion */
-static const uint16_t adv7511_csc_ycbcr_to_rgb[] = {
-	0x0734, 0x04ad, 0x0000, 0x1c1b,
-	0x1ddc, 0x04ad, 0x1f24, 0x0135,
-	0x0000, 0x04ad, 0x087c, 0x1b77,
-};
-
-static void adv7511_set_config_csc(struct adv7511 *adv7511,
-				   struct drm_connector *connector,
-				   bool rgb)
-{
-	struct adv7511_video_config config;
-	bool output_format_422, output_format_ycbcr;
-	unsigned int mode;
-	uint8_t infoframe[17];
-
-	if (adv7511->edid)
-		config.hdmi_mode = drm_detect_hdmi_monitor(adv7511->edid);
-	else
-		config.hdmi_mode = false;
-
-	hdmi_avi_infoframe_init(&config.avi_infoframe);
-
-	config.avi_infoframe.scan_mode = HDMI_SCAN_MODE_UNDERSCAN;
-
-	if (rgb) {
-		config.csc_enable = false;
-		config.avi_infoframe.colorspace = HDMI_COLORSPACE_RGB;
-	} else {
-		config.csc_scaling_factor = ADV7511_CSC_SCALING_4;
-		config.csc_coefficents = adv7511_csc_ycbcr_to_rgb;
-
-		if ((connector->display_info.color_formats &
-		     DRM_COLOR_FORMAT_YCRCB422) &&
-		    config.hdmi_mode) {
-			config.csc_enable = false;
-			config.avi_infoframe.colorspace =
-				HDMI_COLORSPACE_YUV422;
-		} else {
-			config.csc_enable = true;
-			config.avi_infoframe.colorspace = HDMI_COLORSPACE_RGB;
-		}
-	}
-
-	if (config.hdmi_mode) {
-		mode = ADV7511_HDMI_CFG_MODE_HDMI;
-
-		switch (config.avi_infoframe.colorspace) {
-		case HDMI_COLORSPACE_YUV444:
-			output_format_422 = false;
-			output_format_ycbcr = true;
-			break;
-		case HDMI_COLORSPACE_YUV422:
-			output_format_422 = true;
-			output_format_ycbcr = true;
-			break;
-		default:
-			output_format_422 = false;
-			output_format_ycbcr = false;
-			break;
-		}
-	} else {
-		mode = ADV7511_HDMI_CFG_MODE_DVI;
-		output_format_422 = false;
-		output_format_ycbcr = false;
-	}
-
-	adv7511_packet_disable(adv7511, ADV7511_PACKET_ENABLE_AVI_INFOFRAME);
-
-	adv7511_set_colormap(adv7511, config.csc_enable,
-			     config.csc_coefficents,
-			     config.csc_scaling_factor);
-
-	regmap_update_bits(adv7511->regmap, ADV7511_REG_VIDEO_INPUT_CFG1, 0x81,
-			   (output_format_422 << 7) | output_format_ycbcr);
-
-	regmap_update_bits(adv7511->regmap, ADV7511_REG_HDCP_HDMI_CFG,
-			   ADV7511_HDMI_CFG_MODE_MASK, mode);
-
-	hdmi_avi_infoframe_pack(&config.avi_infoframe, infoframe,
-				sizeof(infoframe));
-
-	/* The AVI infoframe id is not configurable */
-	regmap_bulk_write(adv7511->regmap, ADV7511_REG_AVI_INFOFRAME_VERSION,
-			  infoframe + 1, sizeof(infoframe) - 1);
-
-	adv7511_packet_enable(adv7511, ADV7511_PACKET_ENABLE_AVI_INFOFRAME);
-}
-
-static void adv7511_set_link_config(struct adv7511 *adv7511,
-				    const struct adv7511_link_config *config)
-{
-	/*
-	 * The input style values documented in the datasheet don't match the
-	 * hardware register field values :-(
-	 */
-	static const unsigned int input_styles[4] = { 0, 2, 1, 3 };
-
-	unsigned int clock_delay;
-	unsigned int color_depth;
-	unsigned int input_id;
-
-	clock_delay = (config->clock_delay + 1200) / 400;
-	color_depth = config->input_color_depth == 8 ? 3
-		    : (config->input_color_depth == 10 ? 1 : 2);
-
-	/* TODO Support input ID 6 */
-	if (config->input_colorspace != HDMI_COLORSPACE_YUV422)
-		input_id = config->input_clock == ADV7511_INPUT_CLOCK_DDR
-			 ? 5 : 0;
-	else if (config->input_clock == ADV7511_INPUT_CLOCK_DDR)
-		input_id = config->embedded_sync ? 8 : 7;
-	else if (config->input_clock == ADV7511_INPUT_CLOCK_2X)
-		input_id = config->embedded_sync ? 4 : 3;
-	else
-		input_id = config->embedded_sync ? 2 : 1;
-
-	regmap_update_bits(adv7511->regmap, ADV7511_REG_I2C_FREQ_ID_CFG, 0xf,
-			   input_id);
-	regmap_update_bits(adv7511->regmap, ADV7511_REG_VIDEO_INPUT_CFG1, 0x7e,
-			   (color_depth << 4) |
-			   (input_styles[config->input_style] << 2));
-	regmap_write(adv7511->regmap, ADV7511_REG_VIDEO_INPUT_CFG2,
-		     config->input_justification << 3);
-	regmap_write(adv7511->regmap, ADV7511_REG_TIMING_GEN_SEQ,
-		     config->sync_pulse << 2);
-
-	regmap_write(adv7511->regmap, 0xba, clock_delay << 5);
-
-	adv7511->embedded_sync = config->embedded_sync;
-	adv7511->hsync_polarity = config->hsync_polarity;
-	adv7511->vsync_polarity = config->vsync_polarity;
-	adv7511->rgb = config->input_colorspace == HDMI_COLORSPACE_RGB;
-}
-
-static void adv7511_power_on(struct adv7511 *adv7511)
-{
-	adv7511->current_edid_segment = -1;
-
-	regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER,
-			   ADV7511_POWER_POWER_DOWN, 0);
-	if (adv7511->i2c_main->irq) {
-		/*
-		 * Documentation says the INT_ENABLE registers are reset in
-		 * POWER_DOWN mode. My 7511w preserved the bits, however.
-		 * Still, let's be safe and stick to the documentation.
-		 */
-		regmap_write(adv7511->regmap, ADV7511_REG_INT_ENABLE(0),
-			     ADV7511_INT0_EDID_READY);
-		regmap_write(adv7511->regmap, ADV7511_REG_INT_ENABLE(1),
-			     ADV7511_INT1_DDC_ERROR);
-	}
-
-	/*
-	 * Per spec it is allowed to pulse the HPD signal to indicate that the
-	 * EDID information has changed. Some monitors do this when they wakeup
-	 * from standby or are enabled. When the HPD goes low the adv7511 is
-	 * reset and the outputs are disabled which might cause the monitor to
-	 * go to standby again. To avoid this we ignore the HPD pin for the
-	 * first few seconds after enabling the output.
-	 */
-	regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2,
-			   ADV7511_REG_POWER2_HPD_SRC_MASK,
-			   ADV7511_REG_POWER2_HPD_SRC_NONE);
-
-	/*
-	 * Most of the registers are reset during power down or when HPD is low.
-	 */
-	regcache_sync(adv7511->regmap);
-
-	adv7511->powered = true;
-}
-
-static void adv7511_power_off(struct adv7511 *adv7511)
-{
-	/* TODO: setup additional power down modes */
-	regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER,
-			   ADV7511_POWER_POWER_DOWN,
-			   ADV7511_POWER_POWER_DOWN);
-	regcache_mark_dirty(adv7511->regmap);
-
-	adv7511->powered = false;
-}
-
-/* -----------------------------------------------------------------------------
- * Interrupt and hotplug detection
- */
-
-static bool adv7511_hpd(struct adv7511 *adv7511)
-{
-	unsigned int irq0;
-	int ret;
-
-	ret = regmap_read(adv7511->regmap, ADV7511_REG_INT(0), &irq0);
-	if (ret < 0)
-		return false;
-
-	if (irq0 & ADV7511_INT0_HPD) {
-		regmap_write(adv7511->regmap, ADV7511_REG_INT(0),
-			     ADV7511_INT0_HPD);
-		return true;
-	}
-
-	return false;
-}
-
-static int adv7511_irq_process(struct adv7511 *adv7511)
-{
-	unsigned int irq0, irq1;
-	int ret;
-
-	ret = regmap_read(adv7511->regmap, ADV7511_REG_INT(0), &irq0);
-	if (ret < 0)
-		return ret;
-
-	ret = regmap_read(adv7511->regmap, ADV7511_REG_INT(1), &irq1);
-	if (ret < 0)
-		return ret;
-
-	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)
-		drm_helper_hpd_irq_event(adv7511->connector.dev);
-
-	if (irq0 & ADV7511_INT0_EDID_READY || irq1 & ADV7511_INT1_DDC_ERROR) {
-		adv7511->edid_read = true;
-
-		if (adv7511->i2c_main->irq)
-			wake_up_all(&adv7511->wq);
-	}
-
-	return 0;
-}
-
-static irqreturn_t adv7511_irq_handler(int irq, void *devid)
-{
-	struct adv7511 *adv7511 = devid;
-	int ret;
-
-	ret = adv7511_irq_process(adv7511);
-	return ret < 0 ? IRQ_NONE : IRQ_HANDLED;
-}
-
-/* -----------------------------------------------------------------------------
- * EDID retrieval
- */
-
-static int adv7511_wait_for_edid(struct adv7511 *adv7511, int timeout)
-{
-	int ret;
-
-	if (adv7511->i2c_main->irq) {
-		ret = wait_event_interruptible_timeout(adv7511->wq,
-				adv7511->edid_read, msecs_to_jiffies(timeout));
-	} else {
-		for (; timeout > 0; timeout -= 25) {
-			ret = adv7511_irq_process(adv7511);
-			if (ret < 0)
-				break;
-
-			if (adv7511->edid_read)
-				break;
-
-			msleep(25);
-		}
-	}
-
-	return adv7511->edid_read ? 0 : -EIO;
-}
-
-static int adv7511_get_edid_block(void *data, u8 *buf, unsigned int block,
-				  size_t len)
-{
-	struct adv7511 *adv7511 = data;
-	struct i2c_msg xfer[2];
-	uint8_t offset;
-	unsigned int i;
-	int ret;
-
-	if (len > 128)
-		return -EINVAL;
-
-	if (adv7511->current_edid_segment != block / 2) {
-		unsigned int status;
-
-		ret = regmap_read(adv7511->regmap, ADV7511_REG_DDC_STATUS,
-				  &status);
-		if (ret < 0)
-			return ret;
-
-		if (status != 2) {
-			adv7511->edid_read = false;
-			regmap_write(adv7511->regmap, ADV7511_REG_EDID_SEGMENT,
-				     block);
-			ret = adv7511_wait_for_edid(adv7511, 200);
-			if (ret < 0)
-				return ret;
-		}
-
-		/* Break this apart, hopefully more I2C controllers will
-		 * support 64 byte transfers than 256 byte transfers
-		 */
-
-		xfer[0].addr = adv7511->i2c_edid->addr;
-		xfer[0].flags = 0;
-		xfer[0].len = 1;
-		xfer[0].buf = &offset;
-		xfer[1].addr = adv7511->i2c_edid->addr;
-		xfer[1].flags = I2C_M_RD;
-		xfer[1].len = 64;
-		xfer[1].buf = adv7511->edid_buf;
-
-		offset = 0;
-
-		for (i = 0; i < 4; ++i) {
-			ret = i2c_transfer(adv7511->i2c_edid->adapter, xfer,
-					   ARRAY_SIZE(xfer));
-			if (ret < 0)
-				return ret;
-			else if (ret != 2)
-				return -EIO;
-
-			xfer[1].buf += 64;
-			offset += 64;
-		}
-
-		adv7511->current_edid_segment = block / 2;
-	}
-
-	if (block % 2 == 0)
-		memcpy(buf, adv7511->edid_buf, len);
-	else
-		memcpy(buf, adv7511->edid_buf + 128, len);
-
-	return 0;
-}
-
-/* -----------------------------------------------------------------------------
- * ADV75xx helpers
- */
-
-static int adv7511_get_modes(struct adv7511 *adv7511,
-			     struct drm_connector *connector)
-{
-	struct edid *edid;
-	unsigned int count;
-
-	/* Reading the EDID only works if the device is powered */
-	if (!adv7511->powered) {
-		regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER,
-				   ADV7511_POWER_POWER_DOWN, 0);
-		if (adv7511->i2c_main->irq) {
-			regmap_write(adv7511->regmap, ADV7511_REG_INT_ENABLE(0),
-				     ADV7511_INT0_EDID_READY);
-			regmap_write(adv7511->regmap, ADV7511_REG_INT_ENABLE(1),
-				     ADV7511_INT1_DDC_ERROR);
-		}
-		adv7511->current_edid_segment = -1;
-	}
-
-	edid = drm_do_get_edid(connector, adv7511_get_edid_block, adv7511);
-
-	if (!adv7511->powered)
-		regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER,
-				   ADV7511_POWER_POWER_DOWN,
-				   ADV7511_POWER_POWER_DOWN);
-
-	kfree(adv7511->edid);
-	adv7511->edid = edid;
-	if (!edid)
-		return 0;
-
-	drm_mode_connector_update_edid_property(connector, edid);
-	count = drm_add_edid_modes(connector, edid);
-
-	adv7511_set_config_csc(adv7511, connector, adv7511->rgb);
-
-	return count;
-}
-
-static enum drm_connector_status
-adv7511_detect(struct adv7511 *adv7511, struct drm_connector *connector)
-{
-	enum drm_connector_status status;
-	unsigned int val;
-	bool hpd;
-	int ret;
-
-	ret = regmap_read(adv7511->regmap, ADV7511_REG_STATUS, &val);
-	if (ret < 0)
-		return connector_status_disconnected;
-
-	if (val & ADV7511_STATUS_HPD)
-		status = connector_status_connected;
-	else
-		status = connector_status_disconnected;
-
-	hpd = adv7511_hpd(adv7511);
-
-	/* The chip resets itself when the cable is disconnected, so in case
-	 * there is a pending HPD interrupt and the cable is connected there was
-	 * at least one transition from disconnected to connected and the chip
-	 * has to be reinitialized. */
-	if (status == connector_status_connected && hpd && adv7511->powered) {
-		regcache_mark_dirty(adv7511->regmap);
-		adv7511_power_on(adv7511);
-		adv7511_get_modes(adv7511, connector);
-		if (adv7511->status == connector_status_connected)
-			status = connector_status_disconnected;
-	} else {
-		/* Renable HPD sensing */
-		regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2,
-				   ADV7511_REG_POWER2_HPD_SRC_MASK,
-				   ADV7511_REG_POWER2_HPD_SRC_BOTH);
-	}
-
-	adv7511->status = status;
-	return status;
-}
-
-static int adv7511_mode_valid(struct adv7511 *adv7511,
-			      struct drm_display_mode *mode)
-{
-	if (mode->clock > 165000)
-		return MODE_CLOCK_HIGH;
-
-	return MODE_OK;
-}
-
-static void adv7511_mode_set(struct adv7511 *adv7511,
-			     struct drm_display_mode *mode,
-			     struct drm_display_mode *adj_mode)
-{
-	unsigned int low_refresh_rate;
-	unsigned int hsync_polarity = 0;
-	unsigned int vsync_polarity = 0;
-
-	if (adv7511->embedded_sync) {
-		unsigned int hsync_offset, hsync_len;
-		unsigned int vsync_offset, vsync_len;
-
-		hsync_offset = adj_mode->crtc_hsync_start -
-			       adj_mode->crtc_hdisplay;
-		vsync_offset = adj_mode->crtc_vsync_start -
-			       adj_mode->crtc_vdisplay;
-		hsync_len = adj_mode->crtc_hsync_end -
-			    adj_mode->crtc_hsync_start;
-		vsync_len = adj_mode->crtc_vsync_end -
-			    adj_mode->crtc_vsync_start;
-
-		/* The hardware vsync generator has a off-by-one bug */
-		vsync_offset += 1;
-
-		regmap_write(adv7511->regmap, ADV7511_REG_HSYNC_PLACEMENT_MSB,
-			     ((hsync_offset >> 10) & 0x7) << 5);
-		regmap_write(adv7511->regmap, ADV7511_REG_SYNC_DECODER(0),
-			     (hsync_offset >> 2) & 0xff);
-		regmap_write(adv7511->regmap, ADV7511_REG_SYNC_DECODER(1),
-			     ((hsync_offset & 0x3) << 6) |
-			     ((hsync_len >> 4) & 0x3f));
-		regmap_write(adv7511->regmap, ADV7511_REG_SYNC_DECODER(2),
-			     ((hsync_len & 0xf) << 4) |
-			     ((vsync_offset >> 6) & 0xf));
-		regmap_write(adv7511->regmap, ADV7511_REG_SYNC_DECODER(3),
-			     ((vsync_offset & 0x3f) << 2) |
-			     ((vsync_len >> 8) & 0x3));
-		regmap_write(adv7511->regmap, ADV7511_REG_SYNC_DECODER(4),
-			     vsync_len & 0xff);
-
-		hsync_polarity = !(adj_mode->flags & DRM_MODE_FLAG_PHSYNC);
-		vsync_polarity = !(adj_mode->flags & DRM_MODE_FLAG_PVSYNC);
-	} else {
-		enum adv7511_sync_polarity mode_hsync_polarity;
-		enum adv7511_sync_polarity mode_vsync_polarity;
-
-		/**
-		 * If the input signal is always low or always high we want to
-		 * invert or let it passthrough depending on the polarity of the
-		 * current mode.
-		 **/
-		if (adj_mode->flags & DRM_MODE_FLAG_NHSYNC)
-			mode_hsync_polarity = ADV7511_SYNC_POLARITY_LOW;
-		else
-			mode_hsync_polarity = ADV7511_SYNC_POLARITY_HIGH;
-
-		if (adj_mode->flags & DRM_MODE_FLAG_NVSYNC)
-			mode_vsync_polarity = ADV7511_SYNC_POLARITY_LOW;
-		else
-			mode_vsync_polarity = ADV7511_SYNC_POLARITY_HIGH;
-
-		if (adv7511->hsync_polarity != mode_hsync_polarity &&
-		    adv7511->hsync_polarity !=
-		    ADV7511_SYNC_POLARITY_PASSTHROUGH)
-			hsync_polarity = 1;
-
-		if (adv7511->vsync_polarity != mode_vsync_polarity &&
-		    adv7511->vsync_polarity !=
-		    ADV7511_SYNC_POLARITY_PASSTHROUGH)
-			vsync_polarity = 1;
-	}
-
-	if (mode->vrefresh <= 24000)
-		low_refresh_rate = ADV7511_LOW_REFRESH_RATE_24HZ;
-	else if (mode->vrefresh <= 25000)
-		low_refresh_rate = ADV7511_LOW_REFRESH_RATE_25HZ;
-	else if (mode->vrefresh <= 30000)
-		low_refresh_rate = ADV7511_LOW_REFRESH_RATE_30HZ;
-	else
-		low_refresh_rate = ADV7511_LOW_REFRESH_RATE_NONE;
-
-	regmap_update_bits(adv7511->regmap, 0xfb,
-		0x6, low_refresh_rate << 1);
-	regmap_update_bits(adv7511->regmap, 0x17,
-		0x60, (vsync_polarity << 6) | (hsync_polarity << 5));
-
-	/*
-	 * TODO Test first order 4:2:2 to 4:4:4 up conversion method, which is
-	 * supposed to give better results.
-	 */
-
-	adv7511->f_tmds = mode->clock;
-}
-
-/* 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 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,
-	.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,
-};
-
-/* -----------------------------------------------------------------------------
- * Probe & remove
- */
-
-static int adv7511_parse_dt(struct device_node *np,
-			    struct adv7511_link_config *config)
-{
-	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)
-		return -EINVAL;
-
-	ret = of_property_read_string(np, "adi,input-colorspace", &str);
-	if (ret < 0)
-		return ret;
-
-	if (!strcmp(str, "rgb"))
-		config->input_colorspace = HDMI_COLORSPACE_RGB;
-	else if (!strcmp(str, "yuv422"))
-		config->input_colorspace = HDMI_COLORSPACE_YUV422;
-	else if (!strcmp(str, "yuv444"))
-		config->input_colorspace = HDMI_COLORSPACE_YUV444;
-	else
-		return -EINVAL;
-
-	ret = of_property_read_string(np, "adi,input-clock", &str);
-	if (ret < 0)
-		return ret;
-
-	if (!strcmp(str, "1x"))
-		config->input_clock = ADV7511_INPUT_CLOCK_1X;
-	else if (!strcmp(str, "2x"))
-		config->input_clock = ADV7511_INPUT_CLOCK_2X;
-	else if (!strcmp(str, "ddr"))
-		config->input_clock = ADV7511_INPUT_CLOCK_DDR;
-	else
-		return -EINVAL;
-
-	if (config->input_colorspace == HDMI_COLORSPACE_YUV422 ||
-	    config->input_clock != ADV7511_INPUT_CLOCK_1X) {
-		ret = of_property_read_u32(np, "adi,input-style",
-					   &config->input_style);
-		if (ret)
-			return ret;
-
-		if (config->input_style < 1 || config->input_style > 3)
-			return -EINVAL;
-
-		ret = of_property_read_string(np, "adi,input-justification",
-					      &str);
-		if (ret < 0)
-			return ret;
-
-		if (!strcmp(str, "left"))
-			config->input_justification =
-				ADV7511_INPUT_JUSTIFICATION_LEFT;
-		else if (!strcmp(str, "evenly"))
-			config->input_justification =
-				ADV7511_INPUT_JUSTIFICATION_EVENLY;
-		else if (!strcmp(str, "right"))
-			config->input_justification =
-				ADV7511_INPUT_JUSTIFICATION_RIGHT;
-		else
-			return -EINVAL;
-
-	} else {
-		config->input_style = 1;
-		config->input_justification = ADV7511_INPUT_JUSTIFICATION_LEFT;
-	}
-
-	of_property_read_u32(np, "adi,clock-delay", &config->clock_delay);
-	if (config->clock_delay < -1200 || config->clock_delay > 1600)
-		return -EINVAL;
-
-	config->embedded_sync = of_property_read_bool(np, "adi,embedded-sync");
-
-	/* Hardcode the sync pulse configurations for now. */
-	config->sync_pulse = ADV7511_INPUT_SYNC_PULSE_NONE;
-	config->vsync_polarity = ADV7511_SYNC_POLARITY_PASSTHROUGH;
-	config->hsync_polarity = ADV7511_SYNC_POLARITY_PASSTHROUGH;
-
-	return 0;
-}
-
-static const int edid_i2c_addr = 0x7e;
-static const int packet_i2c_addr = 0x70;
-static const int cec_i2c_addr = 0x78;
-
-static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
-{
-	struct adv7511_link_config link_config;
-	struct adv7511 *adv7511;
-	struct device *dev = &i2c->dev;
-	unsigned int val;
-	int ret;
-
-	if (!dev->of_node)
-		return -EINVAL;
-
-	adv7511 = devm_kzalloc(dev, sizeof(*adv7511), GFP_KERNEL);
-	if (!adv7511)
-		return -ENOMEM;
-
-	adv7511->powered = false;
-	adv7511->status = connector_status_disconnected;
-
-	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
-	 * inactive to wake up the encoder.
-	 */
-	adv7511->gpio_pd = devm_gpiod_get_optional(dev, "pd", GPIOD_OUT_HIGH);
-	if (IS_ERR(adv7511->gpio_pd))
-		return PTR_ERR(adv7511->gpio_pd);
-
-	if (adv7511->gpio_pd) {
-		mdelay(5);
-		gpiod_set_value_cansleep(adv7511->gpio_pd, 0);
-	}
-
-	adv7511->regmap = devm_regmap_init_i2c(i2c, &adv7511_regmap_config);
-	if (IS_ERR(adv7511->regmap))
-		return PTR_ERR(adv7511->regmap);
-
-	ret = regmap_read(adv7511->regmap, ADV7511_REG_CHIP_REVISION, &val);
-	if (ret)
-		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;
-
-	regmap_write(adv7511->regmap, ADV7511_REG_EDID_I2C_ADDR, edid_i2c_addr);
-	regmap_write(adv7511->regmap, ADV7511_REG_PACKET_I2C_ADDR,
-		     packet_i2c_addr);
-	regmap_write(adv7511->regmap, ADV7511_REG_CEC_I2C_ADDR, cec_i2c_addr);
-	adv7511_packet_disable(adv7511, 0xffff);
-
-	adv7511->i2c_main = i2c;
-	adv7511->i2c_edid = i2c_new_dummy(i2c->adapter, edid_i2c_addr >> 1);
-	if (!adv7511->i2c_edid)
-		return -ENOMEM;
-
-	if (i2c->irq) {
-		init_waitqueue_head(&adv7511->wq);
-
-		ret = devm_request_threaded_irq(dev, i2c->irq, NULL,
-						adv7511_irq_handler,
-						IRQF_ONESHOT, dev_name(dev),
-						adv7511);
-		if (ret)
-			goto err_i2c_unregister_device;
-	}
-
-	/* CEC is unused for now */
-	regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL,
-		     ADV7511_CEC_CTRL_POWER_DOWN);
-
-	adv7511_power_off(adv7511);
-
-	i2c_set_clientdata(i2c, adv7511);
-
-	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:
-	i2c_unregister_device(adv7511->i2c_edid);
-
-	return ret;
-}
-
-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);
-
-	return 0;
-}
-
-static const struct i2c_device_id adv7511_i2c_ids[] = {
-	{ "adv7511", 0 },
-	{ "adv7511w", 0 },
-	{ "adv7513", 0 },
-	{ }
-};
-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 i2c_driver adv7511_driver = {
-	.driver = {
-		.name = "adv7511",
-		.of_match_table = adv7511_of_ids,
-	},
-	.id_table = adv7511_i2c_ids,
-	.probe = adv7511_probe,
-	.remove = adv7511_remove,
-};
-
-module_i2c_driver(adv7511_driver);
-
-MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
-MODULE_DESCRIPTION("ADV7511 HDMI transmitter driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/i2c/adv7511.h b/drivers/gpu/drm/i2c/adv7511.h
deleted file mode 100644
index 38515b3..0000000
--- a/drivers/gpu/drm/i2c/adv7511.h
+++ /dev/null
@@ -1,289 +0,0 @@
-/*
- * Analog Devices ADV7511 HDMI transmitter driver
- *
- * Copyright 2012 Analog Devices Inc.
- *
- * Licensed under the GPL-2.
- */
-
-#ifndef __DRM_I2C_ADV7511_H__
-#define __DRM_I2C_ADV7511_H__
-
-#include <linux/hdmi.h>
-
-#define ADV7511_REG_CHIP_REVISION		0x00
-#define ADV7511_REG_N0				0x01
-#define ADV7511_REG_N1				0x02
-#define ADV7511_REG_N2				0x03
-#define ADV7511_REG_SPDIF_FREQ			0x04
-#define ADV7511_REG_CTS_AUTOMATIC1		0x05
-#define ADV7511_REG_CTS_AUTOMATIC2		0x06
-#define ADV7511_REG_CTS_MANUAL0			0x07
-#define ADV7511_REG_CTS_MANUAL1			0x08
-#define ADV7511_REG_CTS_MANUAL2			0x09
-#define ADV7511_REG_AUDIO_SOURCE		0x0a
-#define ADV7511_REG_AUDIO_CONFIG		0x0b
-#define ADV7511_REG_I2S_CONFIG			0x0c
-#define ADV7511_REG_I2S_WIDTH			0x0d
-#define ADV7511_REG_AUDIO_SUB_SRC0		0x0e
-#define ADV7511_REG_AUDIO_SUB_SRC1		0x0f
-#define ADV7511_REG_AUDIO_SUB_SRC2		0x10
-#define ADV7511_REG_AUDIO_SUB_SRC3		0x11
-#define ADV7511_REG_AUDIO_CFG1			0x12
-#define ADV7511_REG_AUDIO_CFG2			0x13
-#define ADV7511_REG_AUDIO_CFG3			0x14
-#define ADV7511_REG_I2C_FREQ_ID_CFG		0x15
-#define ADV7511_REG_VIDEO_INPUT_CFG1		0x16
-#define ADV7511_REG_CSC_UPPER(x)		(0x18 + (x) * 2)
-#define ADV7511_REG_CSC_LOWER(x)		(0x19 + (x) * 2)
-#define ADV7511_REG_SYNC_DECODER(x)		(0x30 + (x))
-#define ADV7511_REG_DE_GENERATOR		(0x35 + (x))
-#define ADV7511_REG_PIXEL_REPETITION		0x3b
-#define ADV7511_REG_VIC_MANUAL			0x3c
-#define ADV7511_REG_VIC_SEND			0x3d
-#define ADV7511_REG_VIC_DETECTED		0x3e
-#define ADV7511_REG_AUX_VIC_DETECTED		0x3f
-#define ADV7511_REG_PACKET_ENABLE0		0x40
-#define ADV7511_REG_POWER			0x41
-#define ADV7511_REG_STATUS			0x42
-#define ADV7511_REG_EDID_I2C_ADDR		0x43
-#define ADV7511_REG_PACKET_ENABLE1		0x44
-#define ADV7511_REG_PACKET_I2C_ADDR		0x45
-#define ADV7511_REG_DSD_ENABLE			0x46
-#define ADV7511_REG_VIDEO_INPUT_CFG2		0x48
-#define ADV7511_REG_INFOFRAME_UPDATE		0x4a
-#define ADV7511_REG_GC(x)			(0x4b + (x)) /* 0x4b - 0x51 */
-#define ADV7511_REG_AVI_INFOFRAME_VERSION	0x52
-#define ADV7511_REG_AVI_INFOFRAME_LENGTH	0x53
-#define ADV7511_REG_AVI_INFOFRAME_CHECKSUM	0x54
-#define ADV7511_REG_AVI_INFOFRAME(x)		(0x55 + (x)) /* 0x55 - 0x6f */
-#define ADV7511_REG_AUDIO_INFOFRAME_VERSION	0x70
-#define ADV7511_REG_AUDIO_INFOFRAME_LENGTH	0x71
-#define ADV7511_REG_AUDIO_INFOFRAME_CHECKSUM	0x72
-#define ADV7511_REG_AUDIO_INFOFRAME(x)		(0x73 + (x)) /* 0x73 - 0x7c */
-#define ADV7511_REG_INT_ENABLE(x)		(0x94 + (x))
-#define ADV7511_REG_INT(x)			(0x96 + (x))
-#define ADV7511_REG_INPUT_CLK_DIV		0x9d
-#define ADV7511_REG_PLL_STATUS			0x9e
-#define ADV7511_REG_HDMI_POWER			0xa1
-#define ADV7511_REG_HDCP_HDMI_CFG		0xaf
-#define ADV7511_REG_AN(x)			(0xb0 + (x)) /* 0xb0 - 0xb7 */
-#define ADV7511_REG_HDCP_STATUS			0xb8
-#define ADV7511_REG_BCAPS			0xbe
-#define ADV7511_REG_BKSV(x)			(0xc0 + (x)) /* 0xc0 - 0xc3 */
-#define ADV7511_REG_EDID_SEGMENT		0xc4
-#define ADV7511_REG_DDC_STATUS			0xc8
-#define ADV7511_REG_EDID_READ_CTRL		0xc9
-#define ADV7511_REG_BSTATUS(x)			(0xca + (x)) /* 0xca - 0xcb */
-#define ADV7511_REG_TIMING_GEN_SEQ		0xd0
-#define ADV7511_REG_POWER2			0xd6
-#define ADV7511_REG_HSYNC_PLACEMENT_MSB		0xfa
-
-#define ADV7511_REG_SYNC_ADJUSTMENT(x)		(0xd7 + (x)) /* 0xd7 - 0xdc */
-#define ADV7511_REG_TMDS_CLOCK_INV		0xde
-#define ADV7511_REG_ARC_CTRL			0xdf
-#define ADV7511_REG_CEC_I2C_ADDR		0xe1
-#define ADV7511_REG_CEC_CTRL			0xe2
-#define ADV7511_REG_CHIP_ID_HIGH		0xf5
-#define ADV7511_REG_CHIP_ID_LOW			0xf6
-
-#define ADV7511_CSC_ENABLE			BIT(7)
-#define ADV7511_CSC_UPDATE_MODE			BIT(5)
-
-#define ADV7511_INT0_HPD			BIT(7)
-#define ADV7511_INT0_VSYNC			BIT(5)
-#define ADV7511_INT0_AUDIO_FIFO_FULL		BIT(4)
-#define ADV7511_INT0_EDID_READY			BIT(2)
-#define ADV7511_INT0_HDCP_AUTHENTICATED		BIT(1)
-
-#define ADV7511_INT1_DDC_ERROR			BIT(7)
-#define ADV7511_INT1_BKSV			BIT(6)
-#define ADV7511_INT1_CEC_TX_READY		BIT(5)
-#define ADV7511_INT1_CEC_TX_ARBIT_LOST		BIT(4)
-#define ADV7511_INT1_CEC_TX_RETRY_TIMEOUT	BIT(3)
-#define ADV7511_INT1_CEC_RX_READY3		BIT(2)
-#define ADV7511_INT1_CEC_RX_READY2		BIT(1)
-#define ADV7511_INT1_CEC_RX_READY1		BIT(0)
-
-#define ADV7511_ARC_CTRL_POWER_DOWN		BIT(0)
-
-#define ADV7511_CEC_CTRL_POWER_DOWN		BIT(0)
-
-#define ADV7511_POWER_POWER_DOWN		BIT(6)
-
-#define ADV7511_HDMI_CFG_MODE_MASK		0x2
-#define ADV7511_HDMI_CFG_MODE_DVI		0x0
-#define ADV7511_HDMI_CFG_MODE_HDMI		0x2
-
-#define ADV7511_AUDIO_SELECT_I2C		0x0
-#define ADV7511_AUDIO_SELECT_SPDIF		0x1
-#define ADV7511_AUDIO_SELECT_DSD		0x2
-#define ADV7511_AUDIO_SELECT_HBR		0x3
-#define ADV7511_AUDIO_SELECT_DST		0x4
-
-#define ADV7511_I2S_SAMPLE_LEN_16		0x2
-#define ADV7511_I2S_SAMPLE_LEN_20		0x3
-#define ADV7511_I2S_SAMPLE_LEN_18		0x4
-#define ADV7511_I2S_SAMPLE_LEN_22		0x5
-#define ADV7511_I2S_SAMPLE_LEN_19		0x8
-#define ADV7511_I2S_SAMPLE_LEN_23		0x9
-#define ADV7511_I2S_SAMPLE_LEN_24		0xb
-#define ADV7511_I2S_SAMPLE_LEN_17		0xc
-#define ADV7511_I2S_SAMPLE_LEN_21		0xd
-
-#define ADV7511_SAMPLE_FREQ_44100		0x0
-#define ADV7511_SAMPLE_FREQ_48000		0x2
-#define ADV7511_SAMPLE_FREQ_32000		0x3
-#define ADV7511_SAMPLE_FREQ_88200		0x8
-#define ADV7511_SAMPLE_FREQ_96000		0xa
-#define ADV7511_SAMPLE_FREQ_176400		0xc
-#define ADV7511_SAMPLE_FREQ_192000		0xe
-
-#define ADV7511_STATUS_POWER_DOWN_POLARITY	BIT(7)
-#define ADV7511_STATUS_HPD			BIT(6)
-#define ADV7511_STATUS_MONITOR_SENSE		BIT(5)
-#define ADV7511_STATUS_I2S_32BIT_MODE		BIT(3)
-
-#define ADV7511_PACKET_ENABLE_N_CTS		BIT(8+6)
-#define ADV7511_PACKET_ENABLE_AUDIO_SAMPLE	BIT(8+5)
-#define ADV7511_PACKET_ENABLE_AVI_INFOFRAME	BIT(8+4)
-#define ADV7511_PACKET_ENABLE_AUDIO_INFOFRAME	BIT(8+3)
-#define ADV7511_PACKET_ENABLE_GC		BIT(7)
-#define ADV7511_PACKET_ENABLE_SPD		BIT(6)
-#define ADV7511_PACKET_ENABLE_MPEG		BIT(5)
-#define ADV7511_PACKET_ENABLE_ACP		BIT(4)
-#define ADV7511_PACKET_ENABLE_ISRC		BIT(3)
-#define ADV7511_PACKET_ENABLE_GM		BIT(2)
-#define ADV7511_PACKET_ENABLE_SPARE2		BIT(1)
-#define ADV7511_PACKET_ENABLE_SPARE1		BIT(0)
-
-#define ADV7511_REG_POWER2_HPD_SRC_MASK		0xc0
-#define ADV7511_REG_POWER2_HPD_SRC_BOTH		0x00
-#define ADV7511_REG_POWER2_HPD_SRC_HPD		0x40
-#define ADV7511_REG_POWER2_HPD_SRC_CEC		0x80
-#define ADV7511_REG_POWER2_HPD_SRC_NONE		0xc0
-#define ADV7511_REG_POWER2_TDMS_ENABLE		BIT(4)
-#define ADV7511_REG_POWER2_GATE_INPUT_CLK	BIT(0)
-
-#define ADV7511_LOW_REFRESH_RATE_NONE		0x0
-#define ADV7511_LOW_REFRESH_RATE_24HZ		0x1
-#define ADV7511_LOW_REFRESH_RATE_25HZ		0x2
-#define ADV7511_LOW_REFRESH_RATE_30HZ		0x3
-
-#define ADV7511_AUDIO_CFG3_LEN_MASK		0x0f
-#define ADV7511_I2C_FREQ_ID_CFG_RATE_MASK	0xf0
-
-#define ADV7511_AUDIO_SOURCE_I2S		0
-#define ADV7511_AUDIO_SOURCE_SPDIF		1
-
-#define ADV7511_I2S_FORMAT_I2S			0
-#define ADV7511_I2S_FORMAT_RIGHT_J		1
-#define ADV7511_I2S_FORMAT_LEFT_J		2
-
-#define ADV7511_PACKET(p, x)	    ((p) * 0x20 + (x))
-#define ADV7511_PACKET_SDP(x)	    ADV7511_PACKET(0, x)
-#define ADV7511_PACKET_MPEG(x)	    ADV7511_PACKET(1, x)
-#define ADV7511_PACKET_ACP(x)	    ADV7511_PACKET(2, x)
-#define ADV7511_PACKET_ISRC1(x)	    ADV7511_PACKET(3, x)
-#define ADV7511_PACKET_ISRC2(x)	    ADV7511_PACKET(4, x)
-#define ADV7511_PACKET_GM(x)	    ADV7511_PACKET(5, x)
-#define ADV7511_PACKET_SPARE(x)	    ADV7511_PACKET(6, x)
-
-enum adv7511_input_clock {
-	ADV7511_INPUT_CLOCK_1X,
-	ADV7511_INPUT_CLOCK_2X,
-	ADV7511_INPUT_CLOCK_DDR,
-};
-
-enum adv7511_input_justification {
-	ADV7511_INPUT_JUSTIFICATION_EVENLY = 0,
-	ADV7511_INPUT_JUSTIFICATION_RIGHT = 1,
-	ADV7511_INPUT_JUSTIFICATION_LEFT = 2,
-};
-
-enum adv7511_input_sync_pulse {
-	ADV7511_INPUT_SYNC_PULSE_DE = 0,
-	ADV7511_INPUT_SYNC_PULSE_HSYNC = 1,
-	ADV7511_INPUT_SYNC_PULSE_VSYNC = 2,
-	ADV7511_INPUT_SYNC_PULSE_NONE = 3,
-};
-
-/**
- * enum adv7511_sync_polarity - Polarity for the input sync signals
- * @ADV7511_SYNC_POLARITY_PASSTHROUGH:  Sync polarity matches that of
- *				       the currently configured mode.
- * @ADV7511_SYNC_POLARITY_LOW:	    Sync polarity is low
- * @ADV7511_SYNC_POLARITY_HIGH:	    Sync polarity is high
- *
- * If the polarity is set to either LOW or HIGH the driver will configure the
- * ADV7511 to internally invert the sync signal if required to match the sync
- * polarity setting for the currently selected output mode.
- *
- * If the polarity is set to PASSTHROUGH, the ADV7511 will route the signal
- * unchanged. This is used when the upstream graphics core already generates
- * the sync signals with the correct polarity.
- */
-enum adv7511_sync_polarity {
-	ADV7511_SYNC_POLARITY_PASSTHROUGH,
-	ADV7511_SYNC_POLARITY_LOW,
-	ADV7511_SYNC_POLARITY_HIGH,
-};
-
-/**
- * struct adv7511_link_config - Describes adv7511 hardware configuration
- * @input_color_depth:		Number of bits per color component (8, 10 or 12)
- * @input_colorspace:		The input colorspace (RGB, YUV444, YUV422)
- * @input_clock:		The input video clock style (1x, 2x, DDR)
- * @input_style:		The input component arrangement variant
- * @input_justification:	Video input format bit justification
- * @clock_delay:		Clock delay for the input clock (in ps)
- * @embedded_sync:		Video input uses BT.656-style embedded sync
- * @sync_pulse:			Select the sync pulse
- * @vsync_polarity:		vsync input signal configuration
- * @hsync_polarity:		hsync input signal configuration
- */
-struct adv7511_link_config {
-	unsigned int input_color_depth;
-	enum hdmi_colorspace input_colorspace;
-	enum adv7511_input_clock input_clock;
-	unsigned int input_style;
-	enum adv7511_input_justification input_justification;
-
-	int clock_delay;
-
-	bool embedded_sync;
-	enum adv7511_input_sync_pulse sync_pulse;
-	enum adv7511_sync_polarity vsync_polarity;
-	enum adv7511_sync_polarity hsync_polarity;
-};
-
-/**
- * enum adv7511_csc_scaling - Scaling factor for the ADV7511 CSC
- * @ADV7511_CSC_SCALING_1: CSC results are not scaled
- * @ADV7511_CSC_SCALING_2: CSC results are scaled by a factor of two
- * @ADV7511_CSC_SCALING_4: CSC results are scalled by a factor of four
- */
-enum adv7511_csc_scaling {
-	ADV7511_CSC_SCALING_1 = 0,
-	ADV7511_CSC_SCALING_2 = 1,
-	ADV7511_CSC_SCALING_4 = 2,
-};
-
-/**
- * struct adv7511_video_config - Describes adv7511 hardware configuration
- * @csc_enable:			Whether to enable color space conversion
- * @csc_scaling_factor:		Color space conversion scaling factor
- * @csc_coefficents:		Color space conversion coefficents
- * @hdmi_mode:			Whether to use HDMI or DVI output mode
- * @avi_infoframe:		HDMI infoframe
- */
-struct adv7511_video_config {
-	bool csc_enable;
-	enum adv7511_csc_scaling csc_scaling_factor;
-	const uint16_t *csc_coefficents;
-
-	bool hdmi_mode;
-	struct hdmi_avi_infoframe avi_infoframe;
-};
-
-#endif /* __DRM_I2C_ADV7511_H__ */
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

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

* [PATCH v6 3/8] drm/bridge: adv7511: Fix mutex deadlock when interrupts are disabled
  2016-06-17  7:53         ` [PATCH v6 0/8] drm/i2c: adv7511: ADV7533 support Archit Taneja
  2016-06-17  7:53           ` [PATCH v6 1/8] drm/i2c: adv7511: Convert to drm_bridge Archit Taneja
  2016-06-17  7:53           ` [PATCH v6 2/8] drm/i2c: adv7511: Move to bridge folder Archit Taneja
@ 2016-06-17  7:53           ` Archit Taneja
  2016-06-17  7:53           ` [PATCH v6 4/8] drm/bridge: adv7533: Initial support for ADV7533 Archit Taneja
                             ` (4 subsequent siblings)
  7 siblings, 0 replies; 89+ messages in thread
From: Archit Taneja @ 2016-06-17  7:53 UTC (permalink / raw)
  To: dri-devel, treding, laurent.pinchart, xinliang.liu
  Cc: linux-arm-msm, srinivas.kandagatla, lars, amit.kucheria,
	robdclark, 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.

Signed-off-by: Archit Taneja <architt@codeaurora.org>
---
 drivers/gpu/drm/bridge/adv7511/adv7511_drv.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
index c2642f9..1fff0ab 100644
--- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
+++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
@@ -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;
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

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

* [PATCH v6 4/8] drm/bridge: adv7533: Initial support for ADV7533
  2016-06-17  7:53         ` [PATCH v6 0/8] drm/i2c: adv7511: ADV7533 support Archit Taneja
                             ` (2 preceding siblings ...)
  2016-06-17  7:53           ` [PATCH v6 3/8] drm/bridge: adv7511: Fix mutex deadlock when interrupts are disabled Archit Taneja
@ 2016-06-17  7:53           ` Archit Taneja
  2016-06-17  7:53           ` [PATCH v6 5/8] drm/bridge: adv7533: Create a MIPI DSI device Archit Taneja
                             ` (3 subsequent siblings)
  7 siblings, 0 replies; 89+ messages in thread
From: Archit Taneja @ 2016-06-17  7:53 UTC (permalink / raw)
  To: dri-devel, treding, laurent.pinchart, xinliang.liu
  Cc: linux-arm-msm, amit.kucheria, srinivas.kandagatla

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 <lars@metafoo.de>

Signed-off-by: Archit Taneja <architt@codeaurora.org>
---
 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

diff --git a/drivers/gpu/drm/bridge/adv7511/Kconfig b/drivers/gpu/drm/bridge/adv7511/Kconfig
index 222c6cc..eb84419 100644
--- a/drivers/gpu/drm/bridge/adv7511/Kconfig
+++ b/drivers/gpu/drm/bridge/adv7511/Kconfig
@@ -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.
diff --git a/drivers/gpu/drm/bridge/adv7511/Makefile b/drivers/gpu/drm/bridge/adv7511/Makefile
index 692f83a..9019327 100644
--- a/drivers/gpu/drm/bridge/adv7511/Makefile
+++ b/drivers/gpu/drm/bridge/adv7511/Makefile
@@ -1,2 +1,3 @@
 adv7511-y := adv7511_drv.o
+adv7511-$(CONFIG_DRM_I2C_ADV7533) += adv7533.o
 obj-$(CONFIG_DRM_I2C_ADV7511) += adv7511.o
diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511.h b/drivers/gpu/drm/bridge/adv7511/adv7511.h
index 38515b3..5dea769 100644
--- a/drivers/gpu/drm/bridge/adv7511/adv7511.h
+++ b/drivers/gpu/drm/bridge/adv7511/adv7511.h
@@ -10,6 +10,10 @@
 #define __DRM_I2C_ADV7511_H__
 
 #include <linux/hdmi.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+
+#include <drm/drm_crtc_helper.h>
 
 #define ADV7511_REG_CHIP_REVISION		0x00
 #define ADV7511_REG_N0				0x01
@@ -286,4 +290,71 @@ struct adv7511_video_config {
 	struct hdmi_avi_infoframe avi_infoframe;
 };
 
+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 *regmap_cec;
+	enum drm_connector_status status;
+	bool powered;
+
+	unsigned int f_tmds;
+
+	unsigned int current_edid_segment;
+	uint8_t edid_buf[256];
+	bool edid_read;
+
+	wait_queue_head_t wq;
+	struct drm_bridge bridge;
+	struct drm_connector connector;
+
+	bool embedded_sync;
+	enum adv7511_sync_polarity vsync_polarity;
+	enum adv7511_sync_polarity hsync_polarity;
+	bool rgb;
+
+	struct edid *edid;
+
+	struct gpio_desc *gpio_pd;
+
+	enum adv7511_type type;
+};
+
+#ifdef CONFIG_DRM_I2C_ADV7533
+void adv7533_dsi_power_on(struct adv7511 *adv);
+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);
+#else
+static inline void adv7533_dsi_power_on(struct adv7511 *adv)
+{
+}
+
+static inline void adv7533_dsi_power_off(struct adv7511 *adv)
+{
+}
+
+static inline int adv7533_patch_registers(struct adv7511 *adv)
+{
+	return -ENODEV;
+}
+
+static inline void adv7533_uninit_cec(struct adv7511 *adv)
+{
+}
+
+static inline int adv7533_init_cec(struct adv7511 *adv)
+{
+	return -ENODEV;
+}
+#endif
+
 #endif /* __DRM_I2C_ADV7511_H__ */
diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
index 1fff0ab..e33702b 100644
--- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
+++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
@@ -8,48 +8,17 @@
 
 #include <linux/device.h>
 #include <linux/gpio/consumer.h>
-#include <linux/i2c.h>
 #include <linux/module.h>
-#include <linux/regmap.h>
+#include <linux/of_device.h>
 #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 "adv7511.h"
 
-struct adv7511 {
-	struct i2c_client *i2c_main;
-	struct i2c_client *i2c_edid;
-
-	struct regmap *regmap;
-	struct regmap *packet_memory_regmap;
-	enum drm_connector_status status;
-	bool powered;
-
-	unsigned int f_tmds;
-
-	unsigned int current_edid_segment;
-	uint8_t edid_buf[256];
-	bool edid_read;
-
-	wait_queue_head_t wq;
-	struct drm_bridge bridge;
-	struct drm_connector connector;
-
-	bool embedded_sync;
-	enum adv7511_sync_polarity vsync_polarity;
-	enum adv7511_sync_polarity hsync_polarity;
-	bool rgb;
-
-	struct edid *edid;
-
-	struct gpio_desc *gpio_pd;
-};
-
 /* ADI recommended values for proper operation. */
 static const struct reg_sequence adv7511_fixed_registers[] = {
 	{ 0x98, 0x03 },
@@ -391,6 +360,9 @@ static void adv7511_power_on(struct adv7511 *adv7511)
 	 */
 	regcache_sync(adv7511->regmap);
 
+	if (adv7511->type == ADV7533)
+		adv7533_dsi_power_on(adv7511);
+
 	adv7511->powered = true;
 }
 
@@ -402,6 +374,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;
 }
 
@@ -862,8 +837,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)
@@ -963,9 +936,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
@@ -989,8 +971,12 @@ 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 = adv7533_patch_registers(adv7511);
 	if (ret)
 		return ret;
 
@@ -1005,6 +991,12 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
 	if (!adv7511->i2c_edid)
 		return -ENOMEM;
 
+	if (adv7511->type == ADV7533) {
+		ret = adv7533_init_cec(adv7511);
+		if (ret)
+			goto err_i2c_unregister_edid;
+	}
+
 	if (i2c->irq) {
 		init_waitqueue_head(&adv7511->wq);
 
@@ -1013,7 +1005,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_unregister_cec;
 	}
 
 	/* CEC is unused for now */
@@ -1024,7 +1016,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;
@@ -1032,12 +1025,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_unregister_cec;
 	}
 
 	return 0;
 
-err_i2c_unregister_device:
+err_unregister_cec:
+	adv7533_uninit_cec(adv7511);
+err_i2c_unregister_edid:
 	i2c_unregister_device(adv7511->i2c_edid);
 
 	return ret;
@@ -1049,6 +1044,7 @@ static int adv7511_remove(struct i2c_client *i2c)
 
 	drm_bridge_remove(&adv7511->bridge);
 
+	adv7533_uninit_cec(adv7511);
 	i2c_unregister_device(adv7511->i2c_edid);
 
 	kfree(adv7511->edid);
@@ -1057,17 +1053,23 @@ 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 },
+#ifdef CONFIG_DRM_I2C_ADV7533
+	{ "adv7533", ADV7533 },
+#endif
 	{ }
 };
 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 },
+#ifdef CONFIG_DRM_I2C_ADV7533
+	{ .compatible = "adi,adv7533", .data = (void *)ADV7533 },
+#endif
 	{ }
 };
 MODULE_DEVICE_TABLE(of, adv7511_of_ids);
diff --git a/drivers/gpu/drm/bridge/adv7511/adv7533.c b/drivers/gpu/drm/bridge/adv7511/adv7533.c
new file mode 100644
index 0000000..cb4ca64
--- /dev/null
+++ b/drivers/gpu/drm/bridge/adv7511/adv7533.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "adv7511.h"
+
+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 },
+};
+
+static const struct regmap_config adv7533_cec_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.max_register = 0xff,
+	.cache_type = REGCACHE_RBTREE,
+};
+
+void adv7533_dsi_power_on(struct adv7511 *adv)
+{
+	/* set number of dsi lanes (hardcoded to 4 for now) */
+	regmap_write(adv->regmap_cec, 0x1c, 4 << 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));
+}
+
+void adv7533_dsi_power_off(struct adv7511 *adv)
+{
+	/* disable hdmi */
+	regmap_write(adv->regmap_cec, 0x03, 0x0b);
+}
+
+int adv7533_patch_registers(struct adv7511 *adv)
+{
+	return regmap_register_patch(adv->regmap,
+				     adv7533_fixed_registers,
+				     ARRAY_SIZE(adv7533_fixed_registers));
+}
+
+void adv7533_uninit_cec(struct adv7511 *adv)
+{
+	i2c_unregister_device(adv->i2c_cec);
+}
+
+static const int cec_i2c_addr = 0x78;
+
+int adv7533_init_cec(struct adv7511 *adv)
+{
+	int ret;
+
+	adv->i2c_cec = i2c_new_dummy(adv->i2c_main->adapter, cec_i2c_addr >> 1);
+	if (!adv->i2c_cec)
+		return -ENOMEM;
+
+	adv->regmap_cec = devm_regmap_init_i2c(adv->i2c_cec,
+					&adv7533_cec_regmap_config);
+	if (IS_ERR(adv->regmap_cec)) {
+		ret = PTR_ERR(adv->regmap_cec);
+		goto err;
+	}
+
+	ret = regmap_register_patch(adv->regmap_cec,
+				    adv7533_cec_fixed_registers,
+				    ARRAY_SIZE(adv7533_cec_fixed_registers));
+	if (ret)
+		goto err;
+
+	return 0;
+err:
+	adv7533_uninit_cec(adv);
+	return ret;
+}
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [PATCH v6 5/8] drm/bridge: adv7533: Create a MIPI DSI device
  2016-06-17  7:53         ` [PATCH v6 0/8] drm/i2c: adv7511: ADV7533 support Archit Taneja
                             ` (3 preceding siblings ...)
  2016-06-17  7:53           ` [PATCH v6 4/8] drm/bridge: adv7533: Initial support for ADV7533 Archit Taneja
@ 2016-06-17  7:53           ` Archit Taneja
  2016-06-17  7:53           ` [PATCH v6 6/8] drm/bridge: adv7533: Use internal timing generator Archit Taneja
                             ` (2 subsequent siblings)
  7 siblings, 0 replies; 89+ messages in thread
From: Archit Taneja @ 2016-06-17  7:53 UTC (permalink / raw)
  To: dri-devel, treding, laurent.pinchart, xinliang.liu
  Cc: linux-arm-msm, amit.kucheria, srinivas.kandagatla

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.

Signed-off-by: Archit Taneja <architt@codeaurora.org>
---
 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(-)

diff --git a/drivers/gpu/drm/bridge/adv7511/Kconfig b/drivers/gpu/drm/bridge/adv7511/Kconfig
index eb84419..d2b0499 100644
--- a/drivers/gpu/drm/bridge/adv7511/Kconfig
+++ b/drivers/gpu/drm/bridge/adv7511/Kconfig
@@ -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.
diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511.h b/drivers/gpu/drm/bridge/adv7511/adv7511.h
index 5dea769..3e4d47a 100644
--- a/drivers/gpu/drm/bridge/adv7511/adv7511.h
+++ b/drivers/gpu/drm/bridge/adv7511/adv7511.h
@@ -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__ */
diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
index e33702b..6586c52 100644
--- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
+++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
@@ -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 <lars@metafoo.de>");
 MODULE_DESCRIPTION("ADV7511 HDMI transmitter driver");
diff --git a/drivers/gpu/drm/bridge/adv7511/adv7533.c b/drivers/gpu/drm/bridge/adv7511/adv7533.c
index cb4ca64..ecbcaa0 100644
--- a/drivers/gpu/drm/bridge/adv7511/adv7533.c
+++ b/drivers/gpu/drm/bridge/adv7511/adv7533.c
@@ -11,6 +11,8 @@
  * GNU General Public License for more details.
  */
 
+#include <linux/of_graph.h>
+
 #include "adv7511.h"
 
 static const struct reg_sequence adv7533_fixed_registers[] = {
@@ -39,8 +41,10 @@ static const struct regmap_config adv7533_cec_regmap_config = {
 
 void adv7533_dsi_power_on(struct adv7511 *adv)
 {
-	/* set number of dsi lanes (hardcoded to 4 for now) */
-	regmap_write(adv->regmap_cec, 0x1c, 4 << 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 */
@@ -98,3 +102,86 @@ err:
 	adv7533_uninit_cec(adv);
 	return ret;
 }
+
+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;
+}
+
+void adv7533_detach_dsi(struct adv7511 *adv)
+{
+	mipi_dsi_detach(adv->dsi);
+	mipi_dsi_device_unregister(adv->dsi);
+}
+
+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)
+		return -ENODEV;
+
+	adv->host_node = of_graph_get_remote_port_parent(endpoint);
+	if (!adv->host_node) {
+		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;
+}
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [PATCH v6 6/8] drm/bridge: adv7533: Use internal timing generator
  2016-06-17  7:53         ` [PATCH v6 0/8] drm/i2c: adv7511: ADV7533 support Archit Taneja
                             ` (4 preceding siblings ...)
  2016-06-17  7:53           ` [PATCH v6 5/8] drm/bridge: adv7533: Create a MIPI DSI device Archit Taneja
@ 2016-06-17  7:53           ` Archit Taneja
  2016-06-17  7:53           ` [PATCH v6 7/8] drm/bridge: adv7533: Change number of DSI lanes dynamically Archit Taneja
  2016-06-17  7:53           ` [PATCH v6 8/8] dt-bindings: drm/bridge: Update bindings for ADV7533 Archit Taneja
  7 siblings, 0 replies; 89+ messages in thread
From: Archit Taneja @ 2016-06-17  7:53 UTC (permalink / raw)
  To: dri-devel, treding, laurent.pinchart, xinliang.liu
  Cc: linux-arm-msm, amit.kucheria, srinivas.kandagatla

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.

Signed-off-by: Archit Taneja <architt@codeaurora.org>
---
 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(-)

diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511.h b/drivers/gpu/drm/bridge/adv7511/adv7511.h
index 3e4d47a..90a8c09 100644
--- a/drivers/gpu/drm/bridge/adv7511/adv7511.h
+++ b/drivers/gpu/drm/bridge/adv7511/adv7511.h
@@ -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;
 };
diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
index 6586c52..e0c353e 100644
--- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
+++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
@@ -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.
diff --git a/drivers/gpu/drm/bridge/adv7511/adv7533.c b/drivers/gpu/drm/bridge/adv7511/adv7533.c
index ecbcaa0..d002ac4 100644
--- a/drivers/gpu/drm/bridge/adv7511/adv7533.c
+++ b/drivers/gpu/drm/bridge/adv7511/adv7533.c
@@ -39,14 +39,65 @@ static const struct regmap_config adv7533_cec_regmap_config = {
 	.cache_type = REGCACHE_RBTREE,
 };
 
+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);
+}
+
 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 */
@@ -60,6 +111,8 @@ 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);
 }
 
 int adv7533_patch_registers(struct adv7511 *adv)
@@ -179,6 +232,9 @@ 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;
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [PATCH v6 7/8] drm/bridge: adv7533: Change number of DSI lanes dynamically
  2016-06-17  7:53         ` [PATCH v6 0/8] drm/i2c: adv7511: ADV7533 support Archit Taneja
                             ` (5 preceding siblings ...)
  2016-06-17  7:53           ` [PATCH v6 6/8] drm/bridge: adv7533: Use internal timing generator Archit Taneja
@ 2016-06-17  7:53           ` Archit Taneja
  2016-06-17  7:53           ` [PATCH v6 8/8] dt-bindings: drm/bridge: Update bindings for ADV7533 Archit Taneja
  7 siblings, 0 replies; 89+ messages in thread
From: Archit Taneja @ 2016-06-17  7:53 UTC (permalink / raw)
  To: dri-devel, treding, laurent.pinchart, xinliang.liu
  Cc: linux-arm-msm, srinivas.kandagatla, lars, amit.kucheria,
	robdclark, 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 <andy.green@linaro.org>

Signed-off-by: Archit Taneja <architt@codeaurora.org>
---
 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(+)

diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511.h b/drivers/gpu/drm/bridge/adv7511/adv7511.h
index 90a8c09..161c923 100644
--- a/drivers/gpu/drm/bridge/adv7511/adv7511.h
+++ b/drivers/gpu/drm/bridge/adv7511/adv7511.h
@@ -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;
diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
index e0c353e..ec8fb2e 100644
--- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
+++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
@@ -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);
 
 	/*
diff --git a/drivers/gpu/drm/bridge/adv7511/adv7533.c b/drivers/gpu/drm/bridge/adv7511/adv7533.c
index d002ac4..5eebd15 100644
--- a/drivers/gpu/drm/bridge/adv7511/adv7533.c
+++ b/drivers/gpu/drm/bridge/adv7511/adv7533.c
@@ -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,
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

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

* [PATCH v6 8/8] dt-bindings: drm/bridge: Update bindings for ADV7533
  2016-06-17  7:53         ` [PATCH v6 0/8] drm/i2c: adv7511: ADV7533 support Archit Taneja
                             ` (6 preceding siblings ...)
  2016-06-17  7:53           ` [PATCH v6 7/8] drm/bridge: adv7533: Change number of DSI lanes dynamically Archit Taneja
@ 2016-06-17  7:53           ` Archit Taneja
  7 siblings, 0 replies; 89+ messages in thread
From: Archit Taneja @ 2016-06-17  7:53 UTC (permalink / raw)
  To: dri-devel, treding, laurent.pinchart, xinliang.liu
  Cc: linux-arm-msm, srinivas.kandagatla, lars, amit.kucheria,
	robdclark, Archit Taneja, devicetree

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

Cc: devicetree@vger.kernel.org

Acked-by: Rob Herring <robh@kernel.org>

Signed-off-by: Archit Taneja <architt@codeaurora.org>
---
 .../bindings/display/bridge/adi,adv7511.txt        | 26 +++++++++++++++++-----
 1 file changed, 21 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..6532a59 100644
--- a/Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt
+++ b/Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt
@@ -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
 
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

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

end of thread, other threads:[~2016-06-17  7:54 UTC | newest]

Thread overview: 89+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-07-27  6:16 [PATCH 0/5] drm/i2c: adv7511: ADV7533 support Archit Taneja
2015-07-27  6:16 ` [PATCH 1/5] drm/i2c: adv7511: Fix mutex deadlock when interrupts are disabled Archit Taneja
2015-07-27  6:16 ` [PATCH 2/5] drm/i2c: adv7511: Initial support for adv7533 Archit Taneja
2015-07-28  3:27   ` Bjorn Andersson
2015-08-03  5:39     ` Archit Taneja
2015-07-27  6:16 ` [PATCH 3/5] drm/i2c: adv7511: Refactor encoder slave functions Archit Taneja
2015-07-27  8:59   ` Laurent Pinchart
2015-07-28  8:17     ` Archit Taneja
2015-07-28 14:38       ` Boris Brezillon
2015-07-31  5:26         ` Archit Taneja
2015-07-31  9:12           ` Boris Brezillon
2015-07-31 10:38             ` Archit Taneja
2015-07-31 12:13             ` Rob Clark
2015-07-31 12:58               ` Boris Brezillon
2015-07-31 14:48                 ` Rob Clark
2015-08-03 12:03                   ` Andrzej Hajda
2015-08-03 14:04                     ` Rob Clark
2015-08-04  5:16                       ` Andrzej Hajda
2015-08-04 12:24                         ` Rob Clark
2015-09-02  6:30                           ` Archit Taneja
2015-12-03 15:02     ` Rob Clark
2015-12-03 15:28       ` Laurent Pinchart
2015-12-03 15:55         ` Rob Clark
2015-12-03 16:06           ` Laurent Pinchart
2015-12-03 16:11           ` Archit Taneja
2016-01-09 17:03             ` Archit Taneja
2015-07-27  6:16 ` [PATCH 4/5] drm/i2c: adv7511: Add drm_bridge/connector for ADV7533 Archit Taneja
2015-07-27  6:16 ` [PATCH 5/5] drm/i2c: adv7511: Create mipi_dsi_device " Archit Taneja
2015-09-07 11:36 ` [PATCH v2 0/5] drm/i2c: adv7511: ADV7533 support Archit Taneja
2015-09-07 11:36   ` [PATCH v2 1/5] drm/i2c: adv7511: Fix mutex deadlock when interrupts are disabled Archit Taneja
2015-09-07 11:36   ` [PATCH v2 2/5] drm/i2c: adv7511: Initial support for adv7533 Archit Taneja
2015-09-07 11:36   ` [PATCH v2 3/5] drm/i2c: adv7511: Refactor encoder slave functions Archit Taneja
2015-09-07 11:36   ` [PATCH v2 4/5] drm/i2c: adv7511: Add drm_bridge/connector for ADV7533 Archit Taneja
2015-09-07 11:36   ` [PATCH v2 5/5] drm/i2c: adv7511: Add dsi driver for adv7533 Archit Taneja
2016-03-09 10:57   ` [PATCH v3 0/7] drm/i2c: adv7511: ADV7533 support Archit Taneja
2016-03-09 10:57     ` [PATCH v3 1/7] drm/i2c: adv7511: Convert to drm_bridge Archit Taneja
2016-03-09 10:57     ` [PATCH v3 2/7] drm/i2c: adv7511: Fix mutex deadlock when interrupts are disabled Archit Taneja
2016-03-09 10:57     ` [PATCH v3 3/7] drm/i2c: adv7511: Initial support for ADV7533 Archit Taneja
2016-03-09 10:57     ` [PATCH v3 4/7] drm/i2c: adv7511: Create a MIPI DSI device Archit Taneja
2016-04-21 22:29       ` Laurent Pinchart
2016-04-22  5:10         ` Archit Taneja
2016-05-03  6:57           ` Archit Taneja
2016-05-09 20:38             ` Laurent Pinchart
2016-05-11 10:19               ` Archit Taneja
2016-03-09 10:57     ` [PATCH v3 5/7] drm/i2c: adv7511: Use internal timing generator Archit Taneja
2016-03-09 10:57     ` [PATCH v3 6/7] drm/i2c: adv7511: Change number of DSI lanes dynamically Archit Taneja
     [not found]     ` <1457521038-5906-1-git-send-email-architt-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
2016-03-09 10:57       ` [PATCH v3 7/7] dt-bindings: drm/bridge: Update bindings for ADV7533 Archit Taneja
2016-03-17 19:12         ` Rob Herring
2016-04-21 22:32         ` Laurent Pinchart
2016-04-22  5:40           ` Archit Taneja
     [not found]             ` <5719B942.8070907-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
2016-05-16 12:01               ` Laurent Pinchart
2016-05-17  3:43                 ` Archit Taneja
2016-05-17  4:18                   ` Xinliang Liu
2016-05-24  5:15                     ` Archit Taneja
2016-04-14 14:56     ` [PATCH v3 0/7] drm/i2c: adv7511: ADV7533 support Archit Taneja
2016-04-21 22:33       ` Laurent Pinchart
2016-04-22  5:45         ` Archit Taneja
2016-04-17 11:31     ` Xinliang Liu
2016-04-18  9:48       ` Archit Taneja
2016-04-19  8:44         ` Xinliang Liu
2016-04-21 22:36         ` Laurent Pinchart
2016-04-22  5:44           ` Archit Taneja
2016-05-03  1:52     ` Xinliang Liu
2016-05-03  6:53       ` Archit Taneja
2016-05-16 10:41     ` [PATCH v4 " Archit Taneja
2016-05-16 10:41       ` [PATCH v4 1/7] drm/i2c: adv7511: Convert to drm_bridge Archit Taneja
2016-05-16 10:41       ` [PATCH v4 2/7] drm/i2c: adv7511: Fix mutex deadlock when interrupts are disabled Archit Taneja
2016-05-16 10:41       ` [PATCH v4 3/7] drm/i2c: adv7511: Initial support for ADV7533 Archit Taneja
2016-05-16 10:41       ` [PATCH v4 4/7] drm/i2c: adv7533: Create a MIPI DSI device Archit Taneja
2016-05-16 10:41       ` [PATCH v4 5/7] drm/i2c: adv7533: Use internal timing generator Archit Taneja
2016-05-16 10:41       ` [PATCH v4 6/7] drm/i2c: adv7533: Change number of DSI lanes dynamically Archit Taneja
2016-05-16 10:41       ` [PATCH v4 7/7] dt-bindings: drm/bridge: Update bindings for ADV7533 Archit Taneja
2016-06-08 10:27       ` [PATCH v5 0/7] drm/i2c: adv7511: ADV7533 support Archit Taneja
2016-06-08 10:27         ` [PATCH v5 1/7] drm/i2c: adv7511: Convert to drm_bridge Archit Taneja
2016-06-08 10:27         ` [PATCH v5 2/7] drm/i2c: adv7511: Fix mutex deadlock when interrupts are disabled Archit Taneja
2016-06-08 10:27         ` [PATCH v5 3/7] drm/i2c: adv7511: Initial support for ADV7533 Archit Taneja
2016-06-08 10:27         ` [PATCH v5 4/7] drm/i2c: adv7533: Create a MIPI DSI device Archit Taneja
2016-06-08 10:27         ` [PATCH v5 5/7] drm/i2c: adv7533: Use internal timing generator Archit Taneja
2016-06-08 10:27         ` [PATCH v5 6/7] drm/i2c: adv7533: Change number of DSI lanes dynamically Archit Taneja
2016-06-08 10:27         ` [PATCH v5 7/7] dt-bindings: drm/bridge: Update bindings for ADV7533 Archit Taneja
2016-06-17  7:53         ` [PATCH v6 0/8] drm/i2c: adv7511: ADV7533 support Archit Taneja
2016-06-17  7:53           ` [PATCH v6 1/8] drm/i2c: adv7511: Convert to drm_bridge Archit Taneja
2016-06-17  7:53           ` [PATCH v6 2/8] drm/i2c: adv7511: Move to bridge folder Archit Taneja
2016-06-17  7:53           ` [PATCH v6 3/8] drm/bridge: adv7511: Fix mutex deadlock when interrupts are disabled Archit Taneja
2016-06-17  7:53           ` [PATCH v6 4/8] drm/bridge: adv7533: Initial support for ADV7533 Archit Taneja
2016-06-17  7:53           ` [PATCH v6 5/8] drm/bridge: adv7533: Create a MIPI DSI device Archit Taneja
2016-06-17  7:53           ` [PATCH v6 6/8] drm/bridge: adv7533: Use internal timing generator Archit Taneja
2016-06-17  7:53           ` [PATCH v6 7/8] drm/bridge: adv7533: Change number of DSI lanes dynamically Archit Taneja
2016-06-17  7:53           ` [PATCH v6 8/8] dt-bindings: drm/bridge: Update bindings for ADV7533 Archit Taneja

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