All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/4] drm: bridge: dw-hdmi: Add support for Custom PHYs
@ 2017-01-30 11:05 ` Neil Armstrong
  0 siblings, 0 replies; 15+ messages in thread
From: Neil Armstrong @ 2017-01-30 11:05 UTC (permalink / raw)
  To: dri-devel, laurent.pinchart+renesas
  Cc: Neil Armstrong, Jose.Abreu, kieran.bingham, linux-amlogic, linux-kernel

The Amlogic GX SoCs implements a Synopsys DesignWare HDMI TX Controller
in combination with a very custom PHY.

Thanks to Laurent Pinchart's changes, the HW report the following :
 Detected HDMI TX controller v2.01a with HDCP (Vendor PHY)

The following differs from common PHY integration as managed in the current
driver :
 - Amlogic PHY is not configured through the internal I2C link
 - Amlogic PHY do not use the ENTMDS, SVSRET, PDDQ, ... signals from the controller
 - Amlogic PHY do not export HPD ands RxSense signals to the controller

And finally, concerning the controller integration :
 - the Controller registers are not flat memory-mapped, and uses an
    addr+read/write register pair to write all registers.
 - Inputs only YUV444 pixel data

This is why the following patchset implements :
 - Conversion to regmap for register access
 - Add more callbacks ops to handle Custom PHYs
 - Configure the Input format from the plat_data
 - Fixes a bug that considers the input to be always RBG and sends bad pixel
   format to a DVI sink by disabling CSC

This patchset makes the Amlogix GX SoCs HDMI output successfully work, but I
do not have access to Renesas, i.MX or RockChip SoCs to test against
potentiel regressions, like the regmap conversion.

This patchset is based on the latest Laurent Pinchart dw-hdmi serie at [1] that was recently
merged into drm-misc.

Changes since RFC at [2] :
 - Regmap fixup for 4bytes register access, tested on RK3288 SoC
 - Move phy callbacks to phy_ops and move Synopsys PHY calls into default ops
 - Move HDMI link data into shared header
 - Move Pixel Encoding enum to shared header

[1] http://lkml.kernel.org/r/20170117082910.27023-1-laurent.pinchart+renesas@ideasonboard.com
[2] http://lkml.kernel.org/r/1484656294-6140-1-git-send-email-narmstrong@baylibre.com

Neil Armstrong (4):
  drm: bridge: dw-hdmi: Switch to regmap for register access
  drm: bridge: dw-hdmi: Add support for custom PHY handling
  drm: bridge: dw-hdmi: Enable CSC even for DVI
  drm: bridge: dw-hdmi: Take input format from plat_data

 drivers/gpu/drm/bridge/dw-hdmi.c | 313 ++++++++++++++++++++++-----------------
 include/drm/bridge/dw_hdmi.h     |  46 ++++++
 2 files changed, 226 insertions(+), 133 deletions(-)

-- 
1.9.1

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

* [PATCH 0/4] drm: bridge: dw-hdmi: Add support for Custom PHYs
@ 2017-01-30 11:05 ` Neil Armstrong
  0 siblings, 0 replies; 15+ messages in thread
From: Neil Armstrong @ 2017-01-30 11:05 UTC (permalink / raw)
  To: dri-devel, laurent.pinchart+renesas
  Cc: Jose.Abreu, linux-amlogic, kieran.bingham, linux-kernel, Neil Armstrong

The Amlogic GX SoCs implements a Synopsys DesignWare HDMI TX Controller
in combination with a very custom PHY.

Thanks to Laurent Pinchart's changes, the HW report the following :
 Detected HDMI TX controller v2.01a with HDCP (Vendor PHY)

The following differs from common PHY integration as managed in the current
driver :
 - Amlogic PHY is not configured through the internal I2C link
 - Amlogic PHY do not use the ENTMDS, SVSRET, PDDQ, ... signals from the controller
 - Amlogic PHY do not export HPD ands RxSense signals to the controller

And finally, concerning the controller integration :
 - the Controller registers are not flat memory-mapped, and uses an
    addr+read/write register pair to write all registers.
 - Inputs only YUV444 pixel data

This is why the following patchset implements :
 - Conversion to regmap for register access
 - Add more callbacks ops to handle Custom PHYs
 - Configure the Input format from the plat_data
 - Fixes a bug that considers the input to be always RBG and sends bad pixel
   format to a DVI sink by disabling CSC

This patchset makes the Amlogix GX SoCs HDMI output successfully work, but I
do not have access to Renesas, i.MX or RockChip SoCs to test against
potentiel regressions, like the regmap conversion.

This patchset is based on the latest Laurent Pinchart dw-hdmi serie at [1] that was recently
merged into drm-misc.

Changes since RFC at [2] :
 - Regmap fixup for 4bytes register access, tested on RK3288 SoC
 - Move phy callbacks to phy_ops and move Synopsys PHY calls into default ops
 - Move HDMI link data into shared header
 - Move Pixel Encoding enum to shared header

[1] http://lkml.kernel.org/r/20170117082910.27023-1-laurent.pinchart+renesas@ideasonboard.com
[2] http://lkml.kernel.org/r/1484656294-6140-1-git-send-email-narmstrong@baylibre.com

Neil Armstrong (4):
  drm: bridge: dw-hdmi: Switch to regmap for register access
  drm: bridge: dw-hdmi: Add support for custom PHY handling
  drm: bridge: dw-hdmi: Enable CSC even for DVI
  drm: bridge: dw-hdmi: Take input format from plat_data

 drivers/gpu/drm/bridge/dw-hdmi.c | 313 ++++++++++++++++++++++-----------------
 include/drm/bridge/dw_hdmi.h     |  46 ++++++
 2 files changed, 226 insertions(+), 133 deletions(-)

-- 
1.9.1

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

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

* [PATCH 0/4] drm: bridge: dw-hdmi: Add support for Custom PHYs
@ 2017-01-30 11:05 ` Neil Armstrong
  0 siblings, 0 replies; 15+ messages in thread
From: Neil Armstrong @ 2017-01-30 11:05 UTC (permalink / raw)
  To: linus-amlogic

The Amlogic GX SoCs implements a Synopsys DesignWare HDMI TX Controller
in combination with a very custom PHY.

Thanks to Laurent Pinchart's changes, the HW report the following :
 Detected HDMI TX controller v2.01a with HDCP (Vendor PHY)

The following differs from common PHY integration as managed in the current
driver :
 - Amlogic PHY is not configured through the internal I2C link
 - Amlogic PHY do not use the ENTMDS, SVSRET, PDDQ, ... signals from the controller
 - Amlogic PHY do not export HPD ands RxSense signals to the controller

And finally, concerning the controller integration :
 - the Controller registers are not flat memory-mapped, and uses an
    addr+read/write register pair to write all registers.
 - Inputs only YUV444 pixel data

This is why the following patchset implements :
 - Conversion to regmap for register access
 - Add more callbacks ops to handle Custom PHYs
 - Configure the Input format from the plat_data
 - Fixes a bug that considers the input to be always RBG and sends bad pixel
   format to a DVI sink by disabling CSC

This patchset makes the Amlogix GX SoCs HDMI output successfully work, but I
do not have access to Renesas, i.MX or RockChip SoCs to test against
potentiel regressions, like the regmap conversion.

This patchset is based on the latest Laurent Pinchart dw-hdmi serie at [1] that was recently
merged into drm-misc.

Changes since RFC at [2] :
 - Regmap fixup for 4bytes register access, tested on RK3288 SoC
 - Move phy callbacks to phy_ops and move Synopsys PHY calls into default ops
 - Move HDMI link data into shared header
 - Move Pixel Encoding enum to shared header

[1] http://lkml.kernel.org/r/20170117082910.27023-1-laurent.pinchart+renesas at ideasonboard.com
[2] http://lkml.kernel.org/r/1484656294-6140-1-git-send-email-narmstrong at baylibre.com

Neil Armstrong (4):
  drm: bridge: dw-hdmi: Switch to regmap for register access
  drm: bridge: dw-hdmi: Add support for custom PHY handling
  drm: bridge: dw-hdmi: Enable CSC even for DVI
  drm: bridge: dw-hdmi: Take input format from plat_data

 drivers/gpu/drm/bridge/dw-hdmi.c | 313 ++++++++++++++++++++++-----------------
 include/drm/bridge/dw_hdmi.h     |  46 ++++++
 2 files changed, 226 insertions(+), 133 deletions(-)

-- 
1.9.1

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

* [PATCH 1/4] drm: bridge: dw-hdmi: Switch to regmap for register access
  2017-01-30 11:05 ` Neil Armstrong
  (?)
@ 2017-01-30 11:05   ` Neil Armstrong
  -1 siblings, 0 replies; 15+ messages in thread
From: Neil Armstrong @ 2017-01-30 11:05 UTC (permalink / raw)
  To: dri-devel, laurent.pinchart+renesas
  Cc: Neil Armstrong, Jose.Abreu, kieran.bingham, linux-amlogic, linux-kernel

The Synopsys Designware HDMI TX Controller does not enforce register
access on platforms instanciating it. The current driver supports two
different types of memory-mapped flat register access, but in order to
support the Amlogic Meson SoCs integration, and provide a more generic
way to handle all sorts of register mapping, switch the register access
to use the regmap infrastructure.

In the case of registers that are not flat memory-mapped or do not
conform to the current driver implementation, a regmap struct can be
given in the plat_data and be used at probe or bind.

Since the AHB audio driver is only available with direct memory access,
only allow the I2S audio driver to be registered is directly
memory-mapped.

Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Tested-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/gpu/drm/bridge/dw-hdmi.c | 109 +++++++++++++++++++++------------------
 include/drm/bridge/dw_hdmi.h     |   1 +
 2 files changed, 59 insertions(+), 51 deletions(-)

diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
index ca9d0ce..674ab05 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/dw-hdmi.c
@@ -19,6 +19,7 @@
 #include <linux/hdmi.h>
 #include <linux/mutex.h>
 #include <linux/of_device.h>
+#include <linux/regmap.h>
 #include <linux/spinlock.h>
 
 #include <drm/drm_of.h>
@@ -167,8 +168,8 @@ struct dw_hdmi {
 	unsigned int audio_n;
 	bool audio_enable;
 
-	void (*write)(struct dw_hdmi *hdmi, u8 val, int offset);
-	u8 (*read)(struct dw_hdmi *hdmi, int offset);
+	unsigned int reg_shift;
+	struct regmap *regm;
 };
 
 #define HDMI_IH_PHY_STAT0_RX_SENSE \
@@ -179,42 +180,23 @@ struct dw_hdmi {
 	(HDMI_PHY_RX_SENSE0 | HDMI_PHY_RX_SENSE1 | \
 	 HDMI_PHY_RX_SENSE2 | HDMI_PHY_RX_SENSE3)
 
-static void dw_hdmi_writel(struct dw_hdmi *hdmi, u8 val, int offset)
-{
-	writel(val, hdmi->regs + (offset << 2));
-}
-
-static u8 dw_hdmi_readl(struct dw_hdmi *hdmi, int offset)
-{
-	return readl(hdmi->regs + (offset << 2));
-}
-
-static void dw_hdmi_writeb(struct dw_hdmi *hdmi, u8 val, int offset)
-{
-	writeb(val, hdmi->regs + offset);
-}
-
-static u8 dw_hdmi_readb(struct dw_hdmi *hdmi, int offset)
-{
-	return readb(hdmi->regs + offset);
-}
-
 static inline void hdmi_writeb(struct dw_hdmi *hdmi, u8 val, int offset)
 {
-	hdmi->write(hdmi, val, offset);
+	regmap_write(hdmi->regm, offset << hdmi->reg_shift, val);
 }
 
 static inline u8 hdmi_readb(struct dw_hdmi *hdmi, int offset)
 {
-	return hdmi->read(hdmi, offset);
+	unsigned int val = 0;
+
+	regmap_read(hdmi->regm, offset << hdmi->reg_shift, &val);
+
+	return val;
 }
 
 static void hdmi_modb(struct dw_hdmi *hdmi, u8 data, u8 mask, unsigned reg)
 {
-	u8 val = hdmi_readb(hdmi, reg) & ~mask;
-
-	val |= data & mask;
-	hdmi_writeb(hdmi, val, reg);
+	regmap_update_bits(hdmi->regm, reg << hdmi->reg_shift, mask, data);
 }
 
 static void hdmi_mask_writeb(struct dw_hdmi *hdmi, u8 data, unsigned int reg,
@@ -1949,6 +1931,20 @@ static int dw_hdmi_detect_phy(struct dw_hdmi *hdmi)
 	return 0;
 }
 
+static const struct regmap_config hdmi_regmap_8bit_config = {
+	.reg_bits	= 32,
+	.val_bits	= 8,
+	.reg_stride	= 1,
+	.max_register	= HDMI_I2CM_FS_SCL_LCNT_0_ADDR,
+};
+
+static const struct regmap_config hdmi_regmap_32bit_config = {
+	.reg_bits	= 32,
+	.val_bits	= 32,
+	.reg_stride	= 4,
+	.max_register	= HDMI_I2CM_FS_SCL_LCNT_0_ADDR << 2,
+};
+
 static struct dw_hdmi *
 __dw_hdmi_probe(struct platform_device *pdev,
 		const struct dw_hdmi_plat_data *plat_data)
@@ -1958,7 +1954,7 @@ static int dw_hdmi_detect_phy(struct dw_hdmi *hdmi)
 	struct platform_device_info pdevinfo;
 	struct device_node *ddc_node;
 	struct dw_hdmi *hdmi;
-	struct resource *iores;
+	struct resource *iores = NULL;
 	int irq;
 	int ret;
 	u32 val = 1;
@@ -1982,22 +1978,6 @@ static int dw_hdmi_detect_phy(struct dw_hdmi *hdmi)
 	mutex_init(&hdmi->audio_mutex);
 	spin_lock_init(&hdmi->audio_lock);
 
-	of_property_read_u32(np, "reg-io-width", &val);
-
-	switch (val) {
-	case 4:
-		hdmi->write = dw_hdmi_writel;
-		hdmi->read = dw_hdmi_readl;
-		break;
-	case 1:
-		hdmi->write = dw_hdmi_writeb;
-		hdmi->read = dw_hdmi_readb;
-		break;
-	default:
-		dev_err(dev, "reg-io-width must be 1 or 4\n");
-		return ERR_PTR(-EINVAL);
-	}
-
 	ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0);
 	if (ddc_node) {
 		hdmi->ddc = of_get_i2c_adapter_by_node(ddc_node);
@@ -2011,11 +1991,38 @@ static int dw_hdmi_detect_phy(struct dw_hdmi *hdmi)
 		dev_dbg(hdmi->dev, "no ddc property found\n");
 	}
 
-	iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	hdmi->regs = devm_ioremap_resource(dev, iores);
-	if (IS_ERR(hdmi->regs)) {
-		ret = PTR_ERR(hdmi->regs);
-		goto err_res;
+	if (!plat_data->regm) {
+		const struct regmap_config *reg_config;
+
+		of_property_read_u32(np, "reg-io-width", &val);
+		switch (val) {
+		case 4:
+			reg_config = &hdmi_regmap_32bit_config;
+			hdmi->reg_shift = 2;
+			break;
+		case 1:
+			reg_config = &hdmi_regmap_8bit_config;
+			break;
+		default:
+			dev_err(dev, "reg-io-width must be 1 or 4\n");
+			return ERR_PTR(-EINVAL);
+		}
+
+		iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+		hdmi->regs = devm_ioremap_resource(dev, iores);
+		if (IS_ERR(hdmi->regs)) {
+			ret = PTR_ERR(hdmi->regs);
+			goto err_res;
+		}
+
+		hdmi->regm = devm_regmap_init_mmio(dev, hdmi->regs, reg_config);
+		if (IS_ERR(hdmi->regm)) {
+			dev_err(dev, "Failed to configure regmap\n");
+			ret = PTR_ERR(hdmi->regm);
+			goto err_res;
+		}
+	} else {
+		hdmi->regm = plat_data->regm;
 	}
 
 	hdmi->isfr_clk = devm_clk_get(hdmi->dev, "isfr");
@@ -2123,7 +2130,7 @@ static int dw_hdmi_detect_phy(struct dw_hdmi *hdmi)
 	config0 = hdmi_readb(hdmi, HDMI_CONFIG0_ID);
 	config3 = hdmi_readb(hdmi, HDMI_CONFIG3_ID);
 
-	if (config3 & HDMI_CONFIG3_AHBAUDDMA) {
+	if (iores && config3 & HDMI_CONFIG3_AHBAUDDMA) {
 		struct dw_hdmi_audio_data audio;
 
 		audio.phys = iores->start;
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
index 735a8ab..163842d 100644
--- a/include/drm/bridge/dw_hdmi.h
+++ b/include/drm/bridge/dw_hdmi.h
@@ -60,6 +60,7 @@ struct dw_hdmi_plat_data {
 			     unsigned long mpixelclock);
 	enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
 					   struct drm_display_mode *mode);
+	struct regmap *regm;
 };
 
 int dw_hdmi_probe(struct platform_device *pdev,
-- 
1.9.1

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

* [PATCH 1/4] drm: bridge: dw-hdmi: Switch to regmap for register access
@ 2017-01-30 11:05   ` Neil Armstrong
  0 siblings, 0 replies; 15+ messages in thread
From: Neil Armstrong @ 2017-01-30 11:05 UTC (permalink / raw)
  To: dri-devel, laurent.pinchart+renesas
  Cc: Jose.Abreu, linux-amlogic, kieran.bingham, linux-kernel, Neil Armstrong

The Synopsys Designware HDMI TX Controller does not enforce register
access on platforms instanciating it. The current driver supports two
different types of memory-mapped flat register access, but in order to
support the Amlogic Meson SoCs integration, and provide a more generic
way to handle all sorts of register mapping, switch the register access
to use the regmap infrastructure.

In the case of registers that are not flat memory-mapped or do not
conform to the current driver implementation, a regmap struct can be
given in the plat_data and be used at probe or bind.

Since the AHB audio driver is only available with direct memory access,
only allow the I2S audio driver to be registered is directly
memory-mapped.

Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Tested-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/gpu/drm/bridge/dw-hdmi.c | 109 +++++++++++++++++++++------------------
 include/drm/bridge/dw_hdmi.h     |   1 +
 2 files changed, 59 insertions(+), 51 deletions(-)

diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
index ca9d0ce..674ab05 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/dw-hdmi.c
@@ -19,6 +19,7 @@
 #include <linux/hdmi.h>
 #include <linux/mutex.h>
 #include <linux/of_device.h>
+#include <linux/regmap.h>
 #include <linux/spinlock.h>
 
 #include <drm/drm_of.h>
@@ -167,8 +168,8 @@ struct dw_hdmi {
 	unsigned int audio_n;
 	bool audio_enable;
 
-	void (*write)(struct dw_hdmi *hdmi, u8 val, int offset);
-	u8 (*read)(struct dw_hdmi *hdmi, int offset);
+	unsigned int reg_shift;
+	struct regmap *regm;
 };
 
 #define HDMI_IH_PHY_STAT0_RX_SENSE \
@@ -179,42 +180,23 @@ struct dw_hdmi {
 	(HDMI_PHY_RX_SENSE0 | HDMI_PHY_RX_SENSE1 | \
 	 HDMI_PHY_RX_SENSE2 | HDMI_PHY_RX_SENSE3)
 
-static void dw_hdmi_writel(struct dw_hdmi *hdmi, u8 val, int offset)
-{
-	writel(val, hdmi->regs + (offset << 2));
-}
-
-static u8 dw_hdmi_readl(struct dw_hdmi *hdmi, int offset)
-{
-	return readl(hdmi->regs + (offset << 2));
-}
-
-static void dw_hdmi_writeb(struct dw_hdmi *hdmi, u8 val, int offset)
-{
-	writeb(val, hdmi->regs + offset);
-}
-
-static u8 dw_hdmi_readb(struct dw_hdmi *hdmi, int offset)
-{
-	return readb(hdmi->regs + offset);
-}
-
 static inline void hdmi_writeb(struct dw_hdmi *hdmi, u8 val, int offset)
 {
-	hdmi->write(hdmi, val, offset);
+	regmap_write(hdmi->regm, offset << hdmi->reg_shift, val);
 }
 
 static inline u8 hdmi_readb(struct dw_hdmi *hdmi, int offset)
 {
-	return hdmi->read(hdmi, offset);
+	unsigned int val = 0;
+
+	regmap_read(hdmi->regm, offset << hdmi->reg_shift, &val);
+
+	return val;
 }
 
 static void hdmi_modb(struct dw_hdmi *hdmi, u8 data, u8 mask, unsigned reg)
 {
-	u8 val = hdmi_readb(hdmi, reg) & ~mask;
-
-	val |= data & mask;
-	hdmi_writeb(hdmi, val, reg);
+	regmap_update_bits(hdmi->regm, reg << hdmi->reg_shift, mask, data);
 }
 
 static void hdmi_mask_writeb(struct dw_hdmi *hdmi, u8 data, unsigned int reg,
@@ -1949,6 +1931,20 @@ static int dw_hdmi_detect_phy(struct dw_hdmi *hdmi)
 	return 0;
 }
 
+static const struct regmap_config hdmi_regmap_8bit_config = {
+	.reg_bits	= 32,
+	.val_bits	= 8,
+	.reg_stride	= 1,
+	.max_register	= HDMI_I2CM_FS_SCL_LCNT_0_ADDR,
+};
+
+static const struct regmap_config hdmi_regmap_32bit_config = {
+	.reg_bits	= 32,
+	.val_bits	= 32,
+	.reg_stride	= 4,
+	.max_register	= HDMI_I2CM_FS_SCL_LCNT_0_ADDR << 2,
+};
+
 static struct dw_hdmi *
 __dw_hdmi_probe(struct platform_device *pdev,
 		const struct dw_hdmi_plat_data *plat_data)
@@ -1958,7 +1954,7 @@ static int dw_hdmi_detect_phy(struct dw_hdmi *hdmi)
 	struct platform_device_info pdevinfo;
 	struct device_node *ddc_node;
 	struct dw_hdmi *hdmi;
-	struct resource *iores;
+	struct resource *iores = NULL;
 	int irq;
 	int ret;
 	u32 val = 1;
@@ -1982,22 +1978,6 @@ static int dw_hdmi_detect_phy(struct dw_hdmi *hdmi)
 	mutex_init(&hdmi->audio_mutex);
 	spin_lock_init(&hdmi->audio_lock);
 
-	of_property_read_u32(np, "reg-io-width", &val);
-
-	switch (val) {
-	case 4:
-		hdmi->write = dw_hdmi_writel;
-		hdmi->read = dw_hdmi_readl;
-		break;
-	case 1:
-		hdmi->write = dw_hdmi_writeb;
-		hdmi->read = dw_hdmi_readb;
-		break;
-	default:
-		dev_err(dev, "reg-io-width must be 1 or 4\n");
-		return ERR_PTR(-EINVAL);
-	}
-
 	ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0);
 	if (ddc_node) {
 		hdmi->ddc = of_get_i2c_adapter_by_node(ddc_node);
@@ -2011,11 +1991,38 @@ static int dw_hdmi_detect_phy(struct dw_hdmi *hdmi)
 		dev_dbg(hdmi->dev, "no ddc property found\n");
 	}
 
-	iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	hdmi->regs = devm_ioremap_resource(dev, iores);
-	if (IS_ERR(hdmi->regs)) {
-		ret = PTR_ERR(hdmi->regs);
-		goto err_res;
+	if (!plat_data->regm) {
+		const struct regmap_config *reg_config;
+
+		of_property_read_u32(np, "reg-io-width", &val);
+		switch (val) {
+		case 4:
+			reg_config = &hdmi_regmap_32bit_config;
+			hdmi->reg_shift = 2;
+			break;
+		case 1:
+			reg_config = &hdmi_regmap_8bit_config;
+			break;
+		default:
+			dev_err(dev, "reg-io-width must be 1 or 4\n");
+			return ERR_PTR(-EINVAL);
+		}
+
+		iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+		hdmi->regs = devm_ioremap_resource(dev, iores);
+		if (IS_ERR(hdmi->regs)) {
+			ret = PTR_ERR(hdmi->regs);
+			goto err_res;
+		}
+
+		hdmi->regm = devm_regmap_init_mmio(dev, hdmi->regs, reg_config);
+		if (IS_ERR(hdmi->regm)) {
+			dev_err(dev, "Failed to configure regmap\n");
+			ret = PTR_ERR(hdmi->regm);
+			goto err_res;
+		}
+	} else {
+		hdmi->regm = plat_data->regm;
 	}
 
 	hdmi->isfr_clk = devm_clk_get(hdmi->dev, "isfr");
@@ -2123,7 +2130,7 @@ static int dw_hdmi_detect_phy(struct dw_hdmi *hdmi)
 	config0 = hdmi_readb(hdmi, HDMI_CONFIG0_ID);
 	config3 = hdmi_readb(hdmi, HDMI_CONFIG3_ID);
 
-	if (config3 & HDMI_CONFIG3_AHBAUDDMA) {
+	if (iores && config3 & HDMI_CONFIG3_AHBAUDDMA) {
 		struct dw_hdmi_audio_data audio;
 
 		audio.phys = iores->start;
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
index 735a8ab..163842d 100644
--- a/include/drm/bridge/dw_hdmi.h
+++ b/include/drm/bridge/dw_hdmi.h
@@ -60,6 +60,7 @@ struct dw_hdmi_plat_data {
 			     unsigned long mpixelclock);
 	enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
 					   struct drm_display_mode *mode);
+	struct regmap *regm;
 };
 
 int dw_hdmi_probe(struct platform_device *pdev,
-- 
1.9.1

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

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

* [PATCH 1/4] drm: bridge: dw-hdmi: Switch to regmap for register access
@ 2017-01-30 11:05   ` Neil Armstrong
  0 siblings, 0 replies; 15+ messages in thread
From: Neil Armstrong @ 2017-01-30 11:05 UTC (permalink / raw)
  To: linus-amlogic

The Synopsys Designware HDMI TX Controller does not enforce register
access on platforms instanciating it. The current driver supports two
different types of memory-mapped flat register access, but in order to
support the Amlogic Meson SoCs integration, and provide a more generic
way to handle all sorts of register mapping, switch the register access
to use the regmap infrastructure.

In the case of registers that are not flat memory-mapped or do not
conform to the current driver implementation, a regmap struct can be
given in the plat_data and be used at probe or bind.

Since the AHB audio driver is only available with direct memory access,
only allow the I2S audio driver to be registered is directly
memory-mapped.

Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Tested-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/gpu/drm/bridge/dw-hdmi.c | 109 +++++++++++++++++++++------------------
 include/drm/bridge/dw_hdmi.h     |   1 +
 2 files changed, 59 insertions(+), 51 deletions(-)

diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
index ca9d0ce..674ab05 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/dw-hdmi.c
@@ -19,6 +19,7 @@
 #include <linux/hdmi.h>
 #include <linux/mutex.h>
 #include <linux/of_device.h>
+#include <linux/regmap.h>
 #include <linux/spinlock.h>
 
 #include <drm/drm_of.h>
@@ -167,8 +168,8 @@ struct dw_hdmi {
 	unsigned int audio_n;
 	bool audio_enable;
 
-	void (*write)(struct dw_hdmi *hdmi, u8 val, int offset);
-	u8 (*read)(struct dw_hdmi *hdmi, int offset);
+	unsigned int reg_shift;
+	struct regmap *regm;
 };
 
 #define HDMI_IH_PHY_STAT0_RX_SENSE \
@@ -179,42 +180,23 @@ struct dw_hdmi {
 	(HDMI_PHY_RX_SENSE0 | HDMI_PHY_RX_SENSE1 | \
 	 HDMI_PHY_RX_SENSE2 | HDMI_PHY_RX_SENSE3)
 
-static void dw_hdmi_writel(struct dw_hdmi *hdmi, u8 val, int offset)
-{
-	writel(val, hdmi->regs + (offset << 2));
-}
-
-static u8 dw_hdmi_readl(struct dw_hdmi *hdmi, int offset)
-{
-	return readl(hdmi->regs + (offset << 2));
-}
-
-static void dw_hdmi_writeb(struct dw_hdmi *hdmi, u8 val, int offset)
-{
-	writeb(val, hdmi->regs + offset);
-}
-
-static u8 dw_hdmi_readb(struct dw_hdmi *hdmi, int offset)
-{
-	return readb(hdmi->regs + offset);
-}
-
 static inline void hdmi_writeb(struct dw_hdmi *hdmi, u8 val, int offset)
 {
-	hdmi->write(hdmi, val, offset);
+	regmap_write(hdmi->regm, offset << hdmi->reg_shift, val);
 }
 
 static inline u8 hdmi_readb(struct dw_hdmi *hdmi, int offset)
 {
-	return hdmi->read(hdmi, offset);
+	unsigned int val = 0;
+
+	regmap_read(hdmi->regm, offset << hdmi->reg_shift, &val);
+
+	return val;
 }
 
 static void hdmi_modb(struct dw_hdmi *hdmi, u8 data, u8 mask, unsigned reg)
 {
-	u8 val = hdmi_readb(hdmi, reg) & ~mask;
-
-	val |= data & mask;
-	hdmi_writeb(hdmi, val, reg);
+	regmap_update_bits(hdmi->regm, reg << hdmi->reg_shift, mask, data);
 }
 
 static void hdmi_mask_writeb(struct dw_hdmi *hdmi, u8 data, unsigned int reg,
@@ -1949,6 +1931,20 @@ static int dw_hdmi_detect_phy(struct dw_hdmi *hdmi)
 	return 0;
 }
 
+static const struct regmap_config hdmi_regmap_8bit_config = {
+	.reg_bits	= 32,
+	.val_bits	= 8,
+	.reg_stride	= 1,
+	.max_register	= HDMI_I2CM_FS_SCL_LCNT_0_ADDR,
+};
+
+static const struct regmap_config hdmi_regmap_32bit_config = {
+	.reg_bits	= 32,
+	.val_bits	= 32,
+	.reg_stride	= 4,
+	.max_register	= HDMI_I2CM_FS_SCL_LCNT_0_ADDR << 2,
+};
+
 static struct dw_hdmi *
 __dw_hdmi_probe(struct platform_device *pdev,
 		const struct dw_hdmi_plat_data *plat_data)
@@ -1958,7 +1954,7 @@ static int dw_hdmi_detect_phy(struct dw_hdmi *hdmi)
 	struct platform_device_info pdevinfo;
 	struct device_node *ddc_node;
 	struct dw_hdmi *hdmi;
-	struct resource *iores;
+	struct resource *iores = NULL;
 	int irq;
 	int ret;
 	u32 val = 1;
@@ -1982,22 +1978,6 @@ static int dw_hdmi_detect_phy(struct dw_hdmi *hdmi)
 	mutex_init(&hdmi->audio_mutex);
 	spin_lock_init(&hdmi->audio_lock);
 
-	of_property_read_u32(np, "reg-io-width", &val);
-
-	switch (val) {
-	case 4:
-		hdmi->write = dw_hdmi_writel;
-		hdmi->read = dw_hdmi_readl;
-		break;
-	case 1:
-		hdmi->write = dw_hdmi_writeb;
-		hdmi->read = dw_hdmi_readb;
-		break;
-	default:
-		dev_err(dev, "reg-io-width must be 1 or 4\n");
-		return ERR_PTR(-EINVAL);
-	}
-
 	ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0);
 	if (ddc_node) {
 		hdmi->ddc = of_get_i2c_adapter_by_node(ddc_node);
@@ -2011,11 +1991,38 @@ static int dw_hdmi_detect_phy(struct dw_hdmi *hdmi)
 		dev_dbg(hdmi->dev, "no ddc property found\n");
 	}
 
-	iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	hdmi->regs = devm_ioremap_resource(dev, iores);
-	if (IS_ERR(hdmi->regs)) {
-		ret = PTR_ERR(hdmi->regs);
-		goto err_res;
+	if (!plat_data->regm) {
+		const struct regmap_config *reg_config;
+
+		of_property_read_u32(np, "reg-io-width", &val);
+		switch (val) {
+		case 4:
+			reg_config = &hdmi_regmap_32bit_config;
+			hdmi->reg_shift = 2;
+			break;
+		case 1:
+			reg_config = &hdmi_regmap_8bit_config;
+			break;
+		default:
+			dev_err(dev, "reg-io-width must be 1 or 4\n");
+			return ERR_PTR(-EINVAL);
+		}
+
+		iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+		hdmi->regs = devm_ioremap_resource(dev, iores);
+		if (IS_ERR(hdmi->regs)) {
+			ret = PTR_ERR(hdmi->regs);
+			goto err_res;
+		}
+
+		hdmi->regm = devm_regmap_init_mmio(dev, hdmi->regs, reg_config);
+		if (IS_ERR(hdmi->regm)) {
+			dev_err(dev, "Failed to configure regmap\n");
+			ret = PTR_ERR(hdmi->regm);
+			goto err_res;
+		}
+	} else {
+		hdmi->regm = plat_data->regm;
 	}
 
 	hdmi->isfr_clk = devm_clk_get(hdmi->dev, "isfr");
@@ -2123,7 +2130,7 @@ static int dw_hdmi_detect_phy(struct dw_hdmi *hdmi)
 	config0 = hdmi_readb(hdmi, HDMI_CONFIG0_ID);
 	config3 = hdmi_readb(hdmi, HDMI_CONFIG3_ID);
 
-	if (config3 & HDMI_CONFIG3_AHBAUDDMA) {
+	if (iores && config3 & HDMI_CONFIG3_AHBAUDDMA) {
 		struct dw_hdmi_audio_data audio;
 
 		audio.phys = iores->start;
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
index 735a8ab..163842d 100644
--- a/include/drm/bridge/dw_hdmi.h
+++ b/include/drm/bridge/dw_hdmi.h
@@ -60,6 +60,7 @@ struct dw_hdmi_plat_data {
 			     unsigned long mpixelclock);
 	enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
 					   struct drm_display_mode *mode);
+	struct regmap *regm;
 };
 
 int dw_hdmi_probe(struct platform_device *pdev,
-- 
1.9.1

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

* [PATCH 2/4] drm: bridge: dw-hdmi: Add support for custom PHY handling
  2017-01-30 11:05 ` Neil Armstrong
  (?)
@ 2017-01-30 11:05   ` Neil Armstrong
  -1 siblings, 0 replies; 15+ messages in thread
From: Neil Armstrong @ 2017-01-30 11:05 UTC (permalink / raw)
  To: dri-devel, laurent.pinchart+renesas
  Cc: Neil Armstrong, Jose.Abreu, kieran.bingham, linux-amlogic, linux-kernel

The Synopsys DesignWare HDMI TX Controller support various Transceivers (PHY)
attached to the controller, but also allows fully custom PHYs to be connected.

Add PHY init and disable functions in phy_ops structure passed in plat_data
to handle fully custom PHY init or provide the default one.

Some custom PHYs also handles the HPD and RxSense separately and do not use
the internal signals exported in the Controller's IRQ stat, so a read_hpd
is provided to switch to HPD status polling.
To complete the implementation, add a function to mimic the Controllers
interrupt HPD and RxSense handling from the vendor PHY wrapper code.

Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
 drivers/gpu/drm/bridge/dw-hdmi.c | 145 +++++++++++++++++++++++++--------------
 include/drm/bridge/dw_hdmi.h     |  35 ++++++++++
 2 files changed, 127 insertions(+), 53 deletions(-)

diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
index 674ab05..a8083f4 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/dw-hdmi.c
@@ -85,24 +85,6 @@ enum hdmi_datamap {
 	{ 0x6756, 0x78ab, 0x2000, 0x0200 }
 };
 
-struct hdmi_vmode {
-	bool mdataenablepolarity;
-
-	unsigned int mpixelclock;
-	unsigned int mpixelrepetitioninput;
-	unsigned int mpixelrepetitionoutput;
-};
-
-struct hdmi_data_info {
-	unsigned int enc_in_format;
-	unsigned int enc_out_format;
-	unsigned int enc_color_depth;
-	unsigned int colorimetry;
-	unsigned int pix_repet_factor;
-	unsigned int hdcp_enable;
-	struct hdmi_vmode video_mode;
-};
-
 struct dw_hdmi_i2c {
 	struct i2c_adapter	adap;
 
@@ -144,6 +126,7 @@ struct dw_hdmi {
 	u8 edid[HDMI_EDID_LEN];
 	bool cable_plugin;
 
+	const struct dw_hdmi_phy_ops *phy_ops;
 	const struct dw_hdmi_phy_data *phy;
 	bool phy_enabled;
 
@@ -926,7 +909,8 @@ static void dw_hdmi_phy_sel_interface_control(struct dw_hdmi *hdmi, u8 enable)
 			 HDMI_PHY_CONF0_SELDIPIF_MASK);
 }
 
-static void dw_hdmi_phy_power_off(struct dw_hdmi *hdmi)
+static void dw_hdmi_phy_power_off(struct dw_hdmi *hdmi,
+				  const struct dw_hdmi_plat_data *pdata)
 {
 	if (hdmi->phy->gen == 1) {
 		dw_hdmi_phy_enable_tmds(hdmi, 0);
@@ -1006,14 +990,15 @@ static int hdmi_phy_configure_dwc_hdmi_3d_tx(struct dw_hdmi *hdmi,
 	return 0;
 }
 
-static int hdmi_phy_configure(struct dw_hdmi *hdmi)
+static int hdmi_phy_configure(struct dw_hdmi *hdmi,
+			      const struct dw_hdmi_plat_data *pdata,
+			      struct hdmi_data_info *hdmi_data)
 {
-	const struct dw_hdmi_plat_data *pdata = hdmi->plat_data;
-	unsigned long mpixelclock = hdmi->hdmi_data.video_mode.mpixelclock;
+	unsigned long mpixelclock = hdmi_data->video_mode.mpixelclock;
 	u8 val, msec;
 	int ret;
 
-	dw_hdmi_phy_power_off(hdmi);
+	dw_hdmi_phy_power_off(hdmi, pdata);
 
 	/* Leave low power consumption mode by asserting SVSRET. */
 	if (hdmi->phy->has_svsret)
@@ -1062,7 +1047,10 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi)
 	return 0;
 }
 
-static int dw_hdmi_phy_init(struct dw_hdmi *hdmi)
+static int dw_hdmi_phy_init(struct dw_hdmi *hdmi,
+			    const struct dw_hdmi_plat_data *pdata,
+			    struct drm_display_mode *mode,
+			    struct hdmi_data_info *hdmi_data)
 {
 	int i, ret;
 
@@ -1071,15 +1059,21 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi)
 		dw_hdmi_phy_sel_data_en_pol(hdmi, 1);
 		dw_hdmi_phy_sel_interface_control(hdmi, 0);
 
-		ret = hdmi_phy_configure(hdmi);
+		ret = hdmi_phy_configure(hdmi, pdata, hdmi_data);
 		if (ret)
 			return ret;
 	}
 
-	hdmi->phy_enabled = true;
 	return 0;
 }
 
+/* Synopsys DW-HDMI PHY Control Ops */
+const struct dw_hdmi_phy_ops dw_hdmi_phy_ops = {
+	.phy_init = dw_hdmi_phy_init,
+	.phy_disable = dw_hdmi_phy_power_off,
+};
+EXPORT_SYMBOL_GPL(dw_hdmi_phy_ops);
+
 static void hdmi_tx_hdcp_config(struct dw_hdmi *hdmi)
 {
 	u8 de;
@@ -1294,15 +1288,6 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi,
 	hdmi_writeb(hdmi, vsync_len, HDMI_FC_VSYNCINWIDTH);
 }
 
-static void dw_hdmi_phy_disable(struct dw_hdmi *hdmi)
-{
-	if (!hdmi->phy_enabled)
-		return;
-
-	dw_hdmi_phy_power_off(hdmi);
-	hdmi->phy_enabled = false;
-}
-
 /* HDMI Initialization Step B.4 */
 static void dw_hdmi_enable_video_path(struct dw_hdmi *hdmi)
 {
@@ -1434,10 +1419,15 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
 	/* HDMI Initialization Step B.1 */
 	hdmi_av_composer(hdmi, mode);
 
-	/* HDMI Initializateion Step B.2 */
-	ret = dw_hdmi_phy_init(hdmi);
-	if (ret)
-		return ret;
+	/* HDMI Initialization Step B.2 */
+	if (hdmi->phy_ops->phy_init) {
+		ret = hdmi->phy_ops->phy_init(hdmi, hdmi->plat_data,
+					      &hdmi->previous_mode,
+					      &hdmi->hdmi_data);
+		if (ret)
+			return ret;
+	}
+	hdmi->phy_enabled = true;
 
 	/* HDMI Initialization Step B.3 */
 	dw_hdmi_enable_video_path(hdmi);
@@ -1552,7 +1542,13 @@ static void dw_hdmi_poweron(struct dw_hdmi *hdmi)
 
 static void dw_hdmi_poweroff(struct dw_hdmi *hdmi)
 {
-	dw_hdmi_phy_disable(hdmi);
+	if (!hdmi->phy_enabled)
+		return;
+
+	if (hdmi->phy_ops->phy_disable)
+		hdmi->phy_ops->phy_disable(hdmi, hdmi->plat_data);
+
+	hdmi->phy_enabled = false;
 	hdmi->bridge_is_on = false;
 }
 
@@ -1594,6 +1590,10 @@ static void dw_hdmi_update_phy_mask(struct dw_hdmi *hdmi)
 {
 	u8 old_mask = hdmi->phy_mask;
 
+	/* Ignore if HPD/RxSense handling is done outside the controller */
+	if (hdmi->plat_data && hdmi->plat_data->read_hpd)
+		return;
+
 	if (hdmi->force || hdmi->disabled || !hdmi->rxsense)
 		hdmi->phy_mask |= HDMI_PHY_RX_SENSE;
 	else
@@ -1615,6 +1615,12 @@ static void dw_hdmi_update_phy_mask(struct dw_hdmi *hdmi)
 	dw_hdmi_update_phy_mask(hdmi);
 	mutex_unlock(&hdmi->mutex);
 
+	/* Use specialized callback if handled outside the controller */
+	if (hdmi->plat_data && hdmi->plat_data->read_hpd)
+		return hdmi->plat_data->read_hpd(hdmi, hdmi->plat_data) ?
+			connector_status_connected :
+			connector_status_disconnected;
+
 	return hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_HPD ?
 		connector_status_connected : connector_status_disconnected;
 }
@@ -1902,6 +1908,26 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id)
 	}
 };
 
+void dw_hdmi_setup_rx_sense(struct device *dev, bool hpd, bool rx_sense)
+{
+	struct dw_hdmi *hdmi = dev_get_drvdata(dev);
+
+	mutex_lock(&hdmi->mutex);
+
+	if (!hdmi->disabled && !hdmi->force) {
+		if (!rx_sense)
+			hdmi->rxsense = false;
+
+		if (hpd)
+			hdmi->rxsense = true;
+
+		dw_hdmi_update_power(hdmi);
+		dw_hdmi_update_phy_mask(hdmi);
+	}
+	mutex_unlock(&hdmi->mutex);
+}
+EXPORT_SYMBOL_GPL(dw_hdmi_setup_rx_sense);
+
 static int dw_hdmi_detect_phy(struct dw_hdmi *hdmi)
 {
 	unsigned int i;
@@ -1922,7 +1948,10 @@ static int dw_hdmi_detect_phy(struct dw_hdmi *hdmi)
 		return -ENODEV;
 	}
 
-	if (!hdmi->phy->configure && !hdmi->plat_data->configure_phy) {
+	/* Consider Vendor PHY using phy_ops to control the PHY init/disable */
+	if (hdmi->phy->type != DW_HDMI_PHY_VENDOR_PHY &&
+	    !hdmi->phy->configure &&
+	    !hdmi->plat_data->configure_phy) {
 		dev_err(hdmi->dev, "%s requires platform support\n",
 			hdmi->phy->name);
 		return -ENODEV;
@@ -2051,6 +2080,11 @@ static int dw_hdmi_detect_phy(struct dw_hdmi *hdmi)
 		goto err_isfr;
 	}
 
+	/* Fallback to default PHY ops */
+	hdmi->phy_ops = plat_data->phy_ops;
+	if (!hdmi->phy_ops)
+		hdmi->phy_ops = &dw_hdmi_phy_ops;
+
 	/* Product and revision IDs */
 	hdmi->version = (hdmi_readb(hdmi, HDMI_DESIGN_ID) << 8)
 		      | (hdmi_readb(hdmi, HDMI_REVISION_ID) << 0);
@@ -2101,15 +2135,18 @@ static int dw_hdmi_detect_phy(struct dw_hdmi *hdmi)
 			hdmi->ddc = NULL;
 	}
 
-	/*
-	 * Configure registers related to HDMI interrupt
-	 * generation before registering IRQ.
-	 */
-	hdmi_writeb(hdmi, HDMI_PHY_HPD | HDMI_PHY_RX_SENSE, HDMI_PHY_POL0);
-
-	/* Clear Hotplug interrupts */
-	hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE,
-		    HDMI_IH_PHY_STAT0);
+	/* Ignore if HPD/RxSense handling is done outside the controller */
+	if (!hdmi->plat_data || !hdmi->plat_data->read_hpd) {
+		/*
+		 * Configure registers related to HDMI interrupt
+		 * generation before registering IRQ.
+		 */
+		hdmi_writeb(hdmi, HDMI_PHY_HPD | HDMI_PHY_RX_SENSE, HDMI_PHY_POL0);
+
+		/* Clear Hotplug interrupts */
+		hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE,
+			    HDMI_IH_PHY_STAT0);
+	}
 
 	hdmi->bridge.driver_private = hdmi;
 	hdmi->bridge.funcs = &dw_hdmi_bridge_funcs;
@@ -2119,9 +2156,11 @@ static int dw_hdmi_detect_phy(struct dw_hdmi *hdmi)
 	if (ret)
 		goto err_iahb;
 
-	/* Unmute interrupts */
-	hdmi_writeb(hdmi, ~(HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE),
-		    HDMI_IH_MUTE_PHY_STAT0);
+	/* Ignore if HPD/RxSense handling is done outside the controller */
+	if (!hdmi->plat_data || !hdmi->plat_data->read_hpd)
+		/* Unmute interrupts */
+		hdmi_writeb(hdmi, ~(HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE),
+			    HDMI_IH_MUTE_PHY_STAT0);
 
 	memset(&pdevinfo, 0, sizeof(pdevinfo));
 	pdevinfo.parent = dev;
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
index 163842d..5b5dfb6 100644
--- a/include/drm/bridge/dw_hdmi.h
+++ b/include/drm/bridge/dw_hdmi.h
@@ -13,6 +13,7 @@
 #include <drm/drmP.h>
 
 struct dw_hdmi;
+struct dw_hdmi_plat_data;
 
 enum {
 	DW_HDMI_RES_8,
@@ -51,13 +52,46 @@ struct dw_hdmi_phy_config {
 	u16 vlev_ctr;   /* voltage level control */
 };
 
+struct hdmi_vmode {
+	bool mdataenablepolarity;
+
+	unsigned int mpixelclock;
+	unsigned int mpixelrepetitioninput;
+	unsigned int mpixelrepetitionoutput;
+};
+
+struct hdmi_data_info {
+	unsigned int enc_in_format;
+	unsigned int enc_out_format;
+	unsigned int enc_color_depth;
+	unsigned int colorimetry;
+	unsigned int pix_repet_factor;
+	unsigned int hdcp_enable;
+	struct hdmi_vmode video_mode;
+};
+
+struct dw_hdmi_phy_ops {
+	int (*phy_init)(struct dw_hdmi *hdmi,
+			const struct dw_hdmi_plat_data *pdata,
+			struct drm_display_mode *mode,
+			struct hdmi_data_info *hdmi_data);
+	void (*phy_disable)(struct dw_hdmi *hdmi,
+			    const struct dw_hdmi_plat_data *pdata);
+};
+
+/* Synopsys DW-HDMI PHY Control Ops */
+extern const struct dw_hdmi_phy_ops dw_hdmi_phy_ops;
+
 struct dw_hdmi_plat_data {
 	const struct dw_hdmi_mpll_config *mpll_cfg;
 	const struct dw_hdmi_curr_ctrl *cur_ctr;
 	const struct dw_hdmi_phy_config *phy_config;
+	const struct dw_hdmi_phy_ops *phy_ops;
 	int (*configure_phy)(struct dw_hdmi *hdmi,
 			     const struct dw_hdmi_plat_data *pdata,
 			     unsigned long mpixelclock);
+	bool (*read_hpd)(struct dw_hdmi *hdmi,
+			 const struct dw_hdmi_plat_data *pdata);
 	enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
 					   struct drm_display_mode *mode);
 	struct regmap *regm;
@@ -70,6 +104,7 @@ int dw_hdmi_probe(struct platform_device *pdev,
 int dw_hdmi_bind(struct platform_device *pdev, struct drm_encoder *encoder,
 		 const struct dw_hdmi_plat_data *plat_data);
 
+void dw_hdmi_setup_rx_sense(struct device *dev, bool hpd, bool rx_sense);
 void dw_hdmi_set_sample_rate(struct dw_hdmi *hdmi, unsigned int rate);
 void dw_hdmi_audio_enable(struct dw_hdmi *hdmi);
 void dw_hdmi_audio_disable(struct dw_hdmi *hdmi);
-- 
1.9.1

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

* [PATCH 2/4] drm: bridge: dw-hdmi: Add support for custom PHY handling
@ 2017-01-30 11:05   ` Neil Armstrong
  0 siblings, 0 replies; 15+ messages in thread
From: Neil Armstrong @ 2017-01-30 11:05 UTC (permalink / raw)
  To: dri-devel, laurent.pinchart+renesas
  Cc: Jose.Abreu, linux-amlogic, kieran.bingham, linux-kernel, Neil Armstrong

The Synopsys DesignWare HDMI TX Controller support various Transceivers (PHY)
attached to the controller, but also allows fully custom PHYs to be connected.

Add PHY init and disable functions in phy_ops structure passed in plat_data
to handle fully custom PHY init or provide the default one.

Some custom PHYs also handles the HPD and RxSense separately and do not use
the internal signals exported in the Controller's IRQ stat, so a read_hpd
is provided to switch to HPD status polling.
To complete the implementation, add a function to mimic the Controllers
interrupt HPD and RxSense handling from the vendor PHY wrapper code.

Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
 drivers/gpu/drm/bridge/dw-hdmi.c | 145 +++++++++++++++++++++++++--------------
 include/drm/bridge/dw_hdmi.h     |  35 ++++++++++
 2 files changed, 127 insertions(+), 53 deletions(-)

diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
index 674ab05..a8083f4 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/dw-hdmi.c
@@ -85,24 +85,6 @@ enum hdmi_datamap {
 	{ 0x6756, 0x78ab, 0x2000, 0x0200 }
 };
 
-struct hdmi_vmode {
-	bool mdataenablepolarity;
-
-	unsigned int mpixelclock;
-	unsigned int mpixelrepetitioninput;
-	unsigned int mpixelrepetitionoutput;
-};
-
-struct hdmi_data_info {
-	unsigned int enc_in_format;
-	unsigned int enc_out_format;
-	unsigned int enc_color_depth;
-	unsigned int colorimetry;
-	unsigned int pix_repet_factor;
-	unsigned int hdcp_enable;
-	struct hdmi_vmode video_mode;
-};
-
 struct dw_hdmi_i2c {
 	struct i2c_adapter	adap;
 
@@ -144,6 +126,7 @@ struct dw_hdmi {
 	u8 edid[HDMI_EDID_LEN];
 	bool cable_plugin;
 
+	const struct dw_hdmi_phy_ops *phy_ops;
 	const struct dw_hdmi_phy_data *phy;
 	bool phy_enabled;
 
@@ -926,7 +909,8 @@ static void dw_hdmi_phy_sel_interface_control(struct dw_hdmi *hdmi, u8 enable)
 			 HDMI_PHY_CONF0_SELDIPIF_MASK);
 }
 
-static void dw_hdmi_phy_power_off(struct dw_hdmi *hdmi)
+static void dw_hdmi_phy_power_off(struct dw_hdmi *hdmi,
+				  const struct dw_hdmi_plat_data *pdata)
 {
 	if (hdmi->phy->gen == 1) {
 		dw_hdmi_phy_enable_tmds(hdmi, 0);
@@ -1006,14 +990,15 @@ static int hdmi_phy_configure_dwc_hdmi_3d_tx(struct dw_hdmi *hdmi,
 	return 0;
 }
 
-static int hdmi_phy_configure(struct dw_hdmi *hdmi)
+static int hdmi_phy_configure(struct dw_hdmi *hdmi,
+			      const struct dw_hdmi_plat_data *pdata,
+			      struct hdmi_data_info *hdmi_data)
 {
-	const struct dw_hdmi_plat_data *pdata = hdmi->plat_data;
-	unsigned long mpixelclock = hdmi->hdmi_data.video_mode.mpixelclock;
+	unsigned long mpixelclock = hdmi_data->video_mode.mpixelclock;
 	u8 val, msec;
 	int ret;
 
-	dw_hdmi_phy_power_off(hdmi);
+	dw_hdmi_phy_power_off(hdmi, pdata);
 
 	/* Leave low power consumption mode by asserting SVSRET. */
 	if (hdmi->phy->has_svsret)
@@ -1062,7 +1047,10 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi)
 	return 0;
 }
 
-static int dw_hdmi_phy_init(struct dw_hdmi *hdmi)
+static int dw_hdmi_phy_init(struct dw_hdmi *hdmi,
+			    const struct dw_hdmi_plat_data *pdata,
+			    struct drm_display_mode *mode,
+			    struct hdmi_data_info *hdmi_data)
 {
 	int i, ret;
 
@@ -1071,15 +1059,21 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi)
 		dw_hdmi_phy_sel_data_en_pol(hdmi, 1);
 		dw_hdmi_phy_sel_interface_control(hdmi, 0);
 
-		ret = hdmi_phy_configure(hdmi);
+		ret = hdmi_phy_configure(hdmi, pdata, hdmi_data);
 		if (ret)
 			return ret;
 	}
 
-	hdmi->phy_enabled = true;
 	return 0;
 }
 
+/* Synopsys DW-HDMI PHY Control Ops */
+const struct dw_hdmi_phy_ops dw_hdmi_phy_ops = {
+	.phy_init = dw_hdmi_phy_init,
+	.phy_disable = dw_hdmi_phy_power_off,
+};
+EXPORT_SYMBOL_GPL(dw_hdmi_phy_ops);
+
 static void hdmi_tx_hdcp_config(struct dw_hdmi *hdmi)
 {
 	u8 de;
@@ -1294,15 +1288,6 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi,
 	hdmi_writeb(hdmi, vsync_len, HDMI_FC_VSYNCINWIDTH);
 }
 
-static void dw_hdmi_phy_disable(struct dw_hdmi *hdmi)
-{
-	if (!hdmi->phy_enabled)
-		return;
-
-	dw_hdmi_phy_power_off(hdmi);
-	hdmi->phy_enabled = false;
-}
-
 /* HDMI Initialization Step B.4 */
 static void dw_hdmi_enable_video_path(struct dw_hdmi *hdmi)
 {
@@ -1434,10 +1419,15 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
 	/* HDMI Initialization Step B.1 */
 	hdmi_av_composer(hdmi, mode);
 
-	/* HDMI Initializateion Step B.2 */
-	ret = dw_hdmi_phy_init(hdmi);
-	if (ret)
-		return ret;
+	/* HDMI Initialization Step B.2 */
+	if (hdmi->phy_ops->phy_init) {
+		ret = hdmi->phy_ops->phy_init(hdmi, hdmi->plat_data,
+					      &hdmi->previous_mode,
+					      &hdmi->hdmi_data);
+		if (ret)
+			return ret;
+	}
+	hdmi->phy_enabled = true;
 
 	/* HDMI Initialization Step B.3 */
 	dw_hdmi_enable_video_path(hdmi);
@@ -1552,7 +1542,13 @@ static void dw_hdmi_poweron(struct dw_hdmi *hdmi)
 
 static void dw_hdmi_poweroff(struct dw_hdmi *hdmi)
 {
-	dw_hdmi_phy_disable(hdmi);
+	if (!hdmi->phy_enabled)
+		return;
+
+	if (hdmi->phy_ops->phy_disable)
+		hdmi->phy_ops->phy_disable(hdmi, hdmi->plat_data);
+
+	hdmi->phy_enabled = false;
 	hdmi->bridge_is_on = false;
 }
 
@@ -1594,6 +1590,10 @@ static void dw_hdmi_update_phy_mask(struct dw_hdmi *hdmi)
 {
 	u8 old_mask = hdmi->phy_mask;
 
+	/* Ignore if HPD/RxSense handling is done outside the controller */
+	if (hdmi->plat_data && hdmi->plat_data->read_hpd)
+		return;
+
 	if (hdmi->force || hdmi->disabled || !hdmi->rxsense)
 		hdmi->phy_mask |= HDMI_PHY_RX_SENSE;
 	else
@@ -1615,6 +1615,12 @@ static void dw_hdmi_update_phy_mask(struct dw_hdmi *hdmi)
 	dw_hdmi_update_phy_mask(hdmi);
 	mutex_unlock(&hdmi->mutex);
 
+	/* Use specialized callback if handled outside the controller */
+	if (hdmi->plat_data && hdmi->plat_data->read_hpd)
+		return hdmi->plat_data->read_hpd(hdmi, hdmi->plat_data) ?
+			connector_status_connected :
+			connector_status_disconnected;
+
 	return hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_HPD ?
 		connector_status_connected : connector_status_disconnected;
 }
@@ -1902,6 +1908,26 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id)
 	}
 };
 
+void dw_hdmi_setup_rx_sense(struct device *dev, bool hpd, bool rx_sense)
+{
+	struct dw_hdmi *hdmi = dev_get_drvdata(dev);
+
+	mutex_lock(&hdmi->mutex);
+
+	if (!hdmi->disabled && !hdmi->force) {
+		if (!rx_sense)
+			hdmi->rxsense = false;
+
+		if (hpd)
+			hdmi->rxsense = true;
+
+		dw_hdmi_update_power(hdmi);
+		dw_hdmi_update_phy_mask(hdmi);
+	}
+	mutex_unlock(&hdmi->mutex);
+}
+EXPORT_SYMBOL_GPL(dw_hdmi_setup_rx_sense);
+
 static int dw_hdmi_detect_phy(struct dw_hdmi *hdmi)
 {
 	unsigned int i;
@@ -1922,7 +1948,10 @@ static int dw_hdmi_detect_phy(struct dw_hdmi *hdmi)
 		return -ENODEV;
 	}
 
-	if (!hdmi->phy->configure && !hdmi->plat_data->configure_phy) {
+	/* Consider Vendor PHY using phy_ops to control the PHY init/disable */
+	if (hdmi->phy->type != DW_HDMI_PHY_VENDOR_PHY &&
+	    !hdmi->phy->configure &&
+	    !hdmi->plat_data->configure_phy) {
 		dev_err(hdmi->dev, "%s requires platform support\n",
 			hdmi->phy->name);
 		return -ENODEV;
@@ -2051,6 +2080,11 @@ static int dw_hdmi_detect_phy(struct dw_hdmi *hdmi)
 		goto err_isfr;
 	}
 
+	/* Fallback to default PHY ops */
+	hdmi->phy_ops = plat_data->phy_ops;
+	if (!hdmi->phy_ops)
+		hdmi->phy_ops = &dw_hdmi_phy_ops;
+
 	/* Product and revision IDs */
 	hdmi->version = (hdmi_readb(hdmi, HDMI_DESIGN_ID) << 8)
 		      | (hdmi_readb(hdmi, HDMI_REVISION_ID) << 0);
@@ -2101,15 +2135,18 @@ static int dw_hdmi_detect_phy(struct dw_hdmi *hdmi)
 			hdmi->ddc = NULL;
 	}
 
-	/*
-	 * Configure registers related to HDMI interrupt
-	 * generation before registering IRQ.
-	 */
-	hdmi_writeb(hdmi, HDMI_PHY_HPD | HDMI_PHY_RX_SENSE, HDMI_PHY_POL0);
-
-	/* Clear Hotplug interrupts */
-	hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE,
-		    HDMI_IH_PHY_STAT0);
+	/* Ignore if HPD/RxSense handling is done outside the controller */
+	if (!hdmi->plat_data || !hdmi->plat_data->read_hpd) {
+		/*
+		 * Configure registers related to HDMI interrupt
+		 * generation before registering IRQ.
+		 */
+		hdmi_writeb(hdmi, HDMI_PHY_HPD | HDMI_PHY_RX_SENSE, HDMI_PHY_POL0);
+
+		/* Clear Hotplug interrupts */
+		hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE,
+			    HDMI_IH_PHY_STAT0);
+	}
 
 	hdmi->bridge.driver_private = hdmi;
 	hdmi->bridge.funcs = &dw_hdmi_bridge_funcs;
@@ -2119,9 +2156,11 @@ static int dw_hdmi_detect_phy(struct dw_hdmi *hdmi)
 	if (ret)
 		goto err_iahb;
 
-	/* Unmute interrupts */
-	hdmi_writeb(hdmi, ~(HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE),
-		    HDMI_IH_MUTE_PHY_STAT0);
+	/* Ignore if HPD/RxSense handling is done outside the controller */
+	if (!hdmi->plat_data || !hdmi->plat_data->read_hpd)
+		/* Unmute interrupts */
+		hdmi_writeb(hdmi, ~(HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE),
+			    HDMI_IH_MUTE_PHY_STAT0);
 
 	memset(&pdevinfo, 0, sizeof(pdevinfo));
 	pdevinfo.parent = dev;
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
index 163842d..5b5dfb6 100644
--- a/include/drm/bridge/dw_hdmi.h
+++ b/include/drm/bridge/dw_hdmi.h
@@ -13,6 +13,7 @@
 #include <drm/drmP.h>
 
 struct dw_hdmi;
+struct dw_hdmi_plat_data;
 
 enum {
 	DW_HDMI_RES_8,
@@ -51,13 +52,46 @@ struct dw_hdmi_phy_config {
 	u16 vlev_ctr;   /* voltage level control */
 };
 
+struct hdmi_vmode {
+	bool mdataenablepolarity;
+
+	unsigned int mpixelclock;
+	unsigned int mpixelrepetitioninput;
+	unsigned int mpixelrepetitionoutput;
+};
+
+struct hdmi_data_info {
+	unsigned int enc_in_format;
+	unsigned int enc_out_format;
+	unsigned int enc_color_depth;
+	unsigned int colorimetry;
+	unsigned int pix_repet_factor;
+	unsigned int hdcp_enable;
+	struct hdmi_vmode video_mode;
+};
+
+struct dw_hdmi_phy_ops {
+	int (*phy_init)(struct dw_hdmi *hdmi,
+			const struct dw_hdmi_plat_data *pdata,
+			struct drm_display_mode *mode,
+			struct hdmi_data_info *hdmi_data);
+	void (*phy_disable)(struct dw_hdmi *hdmi,
+			    const struct dw_hdmi_plat_data *pdata);
+};
+
+/* Synopsys DW-HDMI PHY Control Ops */
+extern const struct dw_hdmi_phy_ops dw_hdmi_phy_ops;
+
 struct dw_hdmi_plat_data {
 	const struct dw_hdmi_mpll_config *mpll_cfg;
 	const struct dw_hdmi_curr_ctrl *cur_ctr;
 	const struct dw_hdmi_phy_config *phy_config;
+	const struct dw_hdmi_phy_ops *phy_ops;
 	int (*configure_phy)(struct dw_hdmi *hdmi,
 			     const struct dw_hdmi_plat_data *pdata,
 			     unsigned long mpixelclock);
+	bool (*read_hpd)(struct dw_hdmi *hdmi,
+			 const struct dw_hdmi_plat_data *pdata);
 	enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
 					   struct drm_display_mode *mode);
 	struct regmap *regm;
@@ -70,6 +104,7 @@ int dw_hdmi_probe(struct platform_device *pdev,
 int dw_hdmi_bind(struct platform_device *pdev, struct drm_encoder *encoder,
 		 const struct dw_hdmi_plat_data *plat_data);
 
+void dw_hdmi_setup_rx_sense(struct device *dev, bool hpd, bool rx_sense);
 void dw_hdmi_set_sample_rate(struct dw_hdmi *hdmi, unsigned int rate);
 void dw_hdmi_audio_enable(struct dw_hdmi *hdmi);
 void dw_hdmi_audio_disable(struct dw_hdmi *hdmi);
-- 
1.9.1

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

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

* [PATCH 2/4] drm: bridge: dw-hdmi: Add support for custom PHY handling
@ 2017-01-30 11:05   ` Neil Armstrong
  0 siblings, 0 replies; 15+ messages in thread
From: Neil Armstrong @ 2017-01-30 11:05 UTC (permalink / raw)
  To: linus-amlogic

The Synopsys DesignWare HDMI TX Controller support various Transceivers (PHY)
attached to the controller, but also allows fully custom PHYs to be connected.

Add PHY init and disable functions in phy_ops structure passed in plat_data
to handle fully custom PHY init or provide the default one.

Some custom PHYs also handles the HPD and RxSense separately and do not use
the internal signals exported in the Controller's IRQ stat, so a read_hpd
is provided to switch to HPD status polling.
To complete the implementation, add a function to mimic the Controllers
interrupt HPD and RxSense handling from the vendor PHY wrapper code.

Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
 drivers/gpu/drm/bridge/dw-hdmi.c | 145 +++++++++++++++++++++++++--------------
 include/drm/bridge/dw_hdmi.h     |  35 ++++++++++
 2 files changed, 127 insertions(+), 53 deletions(-)

diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
index 674ab05..a8083f4 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/dw-hdmi.c
@@ -85,24 +85,6 @@ enum hdmi_datamap {
 	{ 0x6756, 0x78ab, 0x2000, 0x0200 }
 };
 
-struct hdmi_vmode {
-	bool mdataenablepolarity;
-
-	unsigned int mpixelclock;
-	unsigned int mpixelrepetitioninput;
-	unsigned int mpixelrepetitionoutput;
-};
-
-struct hdmi_data_info {
-	unsigned int enc_in_format;
-	unsigned int enc_out_format;
-	unsigned int enc_color_depth;
-	unsigned int colorimetry;
-	unsigned int pix_repet_factor;
-	unsigned int hdcp_enable;
-	struct hdmi_vmode video_mode;
-};
-
 struct dw_hdmi_i2c {
 	struct i2c_adapter	adap;
 
@@ -144,6 +126,7 @@ struct dw_hdmi {
 	u8 edid[HDMI_EDID_LEN];
 	bool cable_plugin;
 
+	const struct dw_hdmi_phy_ops *phy_ops;
 	const struct dw_hdmi_phy_data *phy;
 	bool phy_enabled;
 
@@ -926,7 +909,8 @@ static void dw_hdmi_phy_sel_interface_control(struct dw_hdmi *hdmi, u8 enable)
 			 HDMI_PHY_CONF0_SELDIPIF_MASK);
 }
 
-static void dw_hdmi_phy_power_off(struct dw_hdmi *hdmi)
+static void dw_hdmi_phy_power_off(struct dw_hdmi *hdmi,
+				  const struct dw_hdmi_plat_data *pdata)
 {
 	if (hdmi->phy->gen == 1) {
 		dw_hdmi_phy_enable_tmds(hdmi, 0);
@@ -1006,14 +990,15 @@ static int hdmi_phy_configure_dwc_hdmi_3d_tx(struct dw_hdmi *hdmi,
 	return 0;
 }
 
-static int hdmi_phy_configure(struct dw_hdmi *hdmi)
+static int hdmi_phy_configure(struct dw_hdmi *hdmi,
+			      const struct dw_hdmi_plat_data *pdata,
+			      struct hdmi_data_info *hdmi_data)
 {
-	const struct dw_hdmi_plat_data *pdata = hdmi->plat_data;
-	unsigned long mpixelclock = hdmi->hdmi_data.video_mode.mpixelclock;
+	unsigned long mpixelclock = hdmi_data->video_mode.mpixelclock;
 	u8 val, msec;
 	int ret;
 
-	dw_hdmi_phy_power_off(hdmi);
+	dw_hdmi_phy_power_off(hdmi, pdata);
 
 	/* Leave low power consumption mode by asserting SVSRET. */
 	if (hdmi->phy->has_svsret)
@@ -1062,7 +1047,10 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi)
 	return 0;
 }
 
-static int dw_hdmi_phy_init(struct dw_hdmi *hdmi)
+static int dw_hdmi_phy_init(struct dw_hdmi *hdmi,
+			    const struct dw_hdmi_plat_data *pdata,
+			    struct drm_display_mode *mode,
+			    struct hdmi_data_info *hdmi_data)
 {
 	int i, ret;
 
@@ -1071,15 +1059,21 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi)
 		dw_hdmi_phy_sel_data_en_pol(hdmi, 1);
 		dw_hdmi_phy_sel_interface_control(hdmi, 0);
 
-		ret = hdmi_phy_configure(hdmi);
+		ret = hdmi_phy_configure(hdmi, pdata, hdmi_data);
 		if (ret)
 			return ret;
 	}
 
-	hdmi->phy_enabled = true;
 	return 0;
 }
 
+/* Synopsys DW-HDMI PHY Control Ops */
+const struct dw_hdmi_phy_ops dw_hdmi_phy_ops = {
+	.phy_init = dw_hdmi_phy_init,
+	.phy_disable = dw_hdmi_phy_power_off,
+};
+EXPORT_SYMBOL_GPL(dw_hdmi_phy_ops);
+
 static void hdmi_tx_hdcp_config(struct dw_hdmi *hdmi)
 {
 	u8 de;
@@ -1294,15 +1288,6 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi,
 	hdmi_writeb(hdmi, vsync_len, HDMI_FC_VSYNCINWIDTH);
 }
 
-static void dw_hdmi_phy_disable(struct dw_hdmi *hdmi)
-{
-	if (!hdmi->phy_enabled)
-		return;
-
-	dw_hdmi_phy_power_off(hdmi);
-	hdmi->phy_enabled = false;
-}
-
 /* HDMI Initialization Step B.4 */
 static void dw_hdmi_enable_video_path(struct dw_hdmi *hdmi)
 {
@@ -1434,10 +1419,15 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
 	/* HDMI Initialization Step B.1 */
 	hdmi_av_composer(hdmi, mode);
 
-	/* HDMI Initializateion Step B.2 */
-	ret = dw_hdmi_phy_init(hdmi);
-	if (ret)
-		return ret;
+	/* HDMI Initialization Step B.2 */
+	if (hdmi->phy_ops->phy_init) {
+		ret = hdmi->phy_ops->phy_init(hdmi, hdmi->plat_data,
+					      &hdmi->previous_mode,
+					      &hdmi->hdmi_data);
+		if (ret)
+			return ret;
+	}
+	hdmi->phy_enabled = true;
 
 	/* HDMI Initialization Step B.3 */
 	dw_hdmi_enable_video_path(hdmi);
@@ -1552,7 +1542,13 @@ static void dw_hdmi_poweron(struct dw_hdmi *hdmi)
 
 static void dw_hdmi_poweroff(struct dw_hdmi *hdmi)
 {
-	dw_hdmi_phy_disable(hdmi);
+	if (!hdmi->phy_enabled)
+		return;
+
+	if (hdmi->phy_ops->phy_disable)
+		hdmi->phy_ops->phy_disable(hdmi, hdmi->plat_data);
+
+	hdmi->phy_enabled = false;
 	hdmi->bridge_is_on = false;
 }
 
@@ -1594,6 +1590,10 @@ static void dw_hdmi_update_phy_mask(struct dw_hdmi *hdmi)
 {
 	u8 old_mask = hdmi->phy_mask;
 
+	/* Ignore if HPD/RxSense handling is done outside the controller */
+	if (hdmi->plat_data && hdmi->plat_data->read_hpd)
+		return;
+
 	if (hdmi->force || hdmi->disabled || !hdmi->rxsense)
 		hdmi->phy_mask |= HDMI_PHY_RX_SENSE;
 	else
@@ -1615,6 +1615,12 @@ static void dw_hdmi_update_phy_mask(struct dw_hdmi *hdmi)
 	dw_hdmi_update_phy_mask(hdmi);
 	mutex_unlock(&hdmi->mutex);
 
+	/* Use specialized callback if handled outside the controller */
+	if (hdmi->plat_data && hdmi->plat_data->read_hpd)
+		return hdmi->plat_data->read_hpd(hdmi, hdmi->plat_data) ?
+			connector_status_connected :
+			connector_status_disconnected;
+
 	return hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_HPD ?
 		connector_status_connected : connector_status_disconnected;
 }
@@ -1902,6 +1908,26 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id)
 	}
 };
 
+void dw_hdmi_setup_rx_sense(struct device *dev, bool hpd, bool rx_sense)
+{
+	struct dw_hdmi *hdmi = dev_get_drvdata(dev);
+
+	mutex_lock(&hdmi->mutex);
+
+	if (!hdmi->disabled && !hdmi->force) {
+		if (!rx_sense)
+			hdmi->rxsense = false;
+
+		if (hpd)
+			hdmi->rxsense = true;
+
+		dw_hdmi_update_power(hdmi);
+		dw_hdmi_update_phy_mask(hdmi);
+	}
+	mutex_unlock(&hdmi->mutex);
+}
+EXPORT_SYMBOL_GPL(dw_hdmi_setup_rx_sense);
+
 static int dw_hdmi_detect_phy(struct dw_hdmi *hdmi)
 {
 	unsigned int i;
@@ -1922,7 +1948,10 @@ static int dw_hdmi_detect_phy(struct dw_hdmi *hdmi)
 		return -ENODEV;
 	}
 
-	if (!hdmi->phy->configure && !hdmi->plat_data->configure_phy) {
+	/* Consider Vendor PHY using phy_ops to control the PHY init/disable */
+	if (hdmi->phy->type != DW_HDMI_PHY_VENDOR_PHY &&
+	    !hdmi->phy->configure &&
+	    !hdmi->plat_data->configure_phy) {
 		dev_err(hdmi->dev, "%s requires platform support\n",
 			hdmi->phy->name);
 		return -ENODEV;
@@ -2051,6 +2080,11 @@ static int dw_hdmi_detect_phy(struct dw_hdmi *hdmi)
 		goto err_isfr;
 	}
 
+	/* Fallback to default PHY ops */
+	hdmi->phy_ops = plat_data->phy_ops;
+	if (!hdmi->phy_ops)
+		hdmi->phy_ops = &dw_hdmi_phy_ops;
+
 	/* Product and revision IDs */
 	hdmi->version = (hdmi_readb(hdmi, HDMI_DESIGN_ID) << 8)
 		      | (hdmi_readb(hdmi, HDMI_REVISION_ID) << 0);
@@ -2101,15 +2135,18 @@ static int dw_hdmi_detect_phy(struct dw_hdmi *hdmi)
 			hdmi->ddc = NULL;
 	}
 
-	/*
-	 * Configure registers related to HDMI interrupt
-	 * generation before registering IRQ.
-	 */
-	hdmi_writeb(hdmi, HDMI_PHY_HPD | HDMI_PHY_RX_SENSE, HDMI_PHY_POL0);
-
-	/* Clear Hotplug interrupts */
-	hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE,
-		    HDMI_IH_PHY_STAT0);
+	/* Ignore if HPD/RxSense handling is done outside the controller */
+	if (!hdmi->plat_data || !hdmi->plat_data->read_hpd) {
+		/*
+		 * Configure registers related to HDMI interrupt
+		 * generation before registering IRQ.
+		 */
+		hdmi_writeb(hdmi, HDMI_PHY_HPD | HDMI_PHY_RX_SENSE, HDMI_PHY_POL0);
+
+		/* Clear Hotplug interrupts */
+		hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE,
+			    HDMI_IH_PHY_STAT0);
+	}
 
 	hdmi->bridge.driver_private = hdmi;
 	hdmi->bridge.funcs = &dw_hdmi_bridge_funcs;
@@ -2119,9 +2156,11 @@ static int dw_hdmi_detect_phy(struct dw_hdmi *hdmi)
 	if (ret)
 		goto err_iahb;
 
-	/* Unmute interrupts */
-	hdmi_writeb(hdmi, ~(HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE),
-		    HDMI_IH_MUTE_PHY_STAT0);
+	/* Ignore if HPD/RxSense handling is done outside the controller */
+	if (!hdmi->plat_data || !hdmi->plat_data->read_hpd)
+		/* Unmute interrupts */
+		hdmi_writeb(hdmi, ~(HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE),
+			    HDMI_IH_MUTE_PHY_STAT0);
 
 	memset(&pdevinfo, 0, sizeof(pdevinfo));
 	pdevinfo.parent = dev;
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
index 163842d..5b5dfb6 100644
--- a/include/drm/bridge/dw_hdmi.h
+++ b/include/drm/bridge/dw_hdmi.h
@@ -13,6 +13,7 @@
 #include <drm/drmP.h>
 
 struct dw_hdmi;
+struct dw_hdmi_plat_data;
 
 enum {
 	DW_HDMI_RES_8,
@@ -51,13 +52,46 @@ struct dw_hdmi_phy_config {
 	u16 vlev_ctr;   /* voltage level control */
 };
 
+struct hdmi_vmode {
+	bool mdataenablepolarity;
+
+	unsigned int mpixelclock;
+	unsigned int mpixelrepetitioninput;
+	unsigned int mpixelrepetitionoutput;
+};
+
+struct hdmi_data_info {
+	unsigned int enc_in_format;
+	unsigned int enc_out_format;
+	unsigned int enc_color_depth;
+	unsigned int colorimetry;
+	unsigned int pix_repet_factor;
+	unsigned int hdcp_enable;
+	struct hdmi_vmode video_mode;
+};
+
+struct dw_hdmi_phy_ops {
+	int (*phy_init)(struct dw_hdmi *hdmi,
+			const struct dw_hdmi_plat_data *pdata,
+			struct drm_display_mode *mode,
+			struct hdmi_data_info *hdmi_data);
+	void (*phy_disable)(struct dw_hdmi *hdmi,
+			    const struct dw_hdmi_plat_data *pdata);
+};
+
+/* Synopsys DW-HDMI PHY Control Ops */
+extern const struct dw_hdmi_phy_ops dw_hdmi_phy_ops;
+
 struct dw_hdmi_plat_data {
 	const struct dw_hdmi_mpll_config *mpll_cfg;
 	const struct dw_hdmi_curr_ctrl *cur_ctr;
 	const struct dw_hdmi_phy_config *phy_config;
+	const struct dw_hdmi_phy_ops *phy_ops;
 	int (*configure_phy)(struct dw_hdmi *hdmi,
 			     const struct dw_hdmi_plat_data *pdata,
 			     unsigned long mpixelclock);
+	bool (*read_hpd)(struct dw_hdmi *hdmi,
+			 const struct dw_hdmi_plat_data *pdata);
 	enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
 					   struct drm_display_mode *mode);
 	struct regmap *regm;
@@ -70,6 +104,7 @@ int dw_hdmi_probe(struct platform_device *pdev,
 int dw_hdmi_bind(struct platform_device *pdev, struct drm_encoder *encoder,
 		 const struct dw_hdmi_plat_data *plat_data);
 
+void dw_hdmi_setup_rx_sense(struct device *dev, bool hpd, bool rx_sense);
 void dw_hdmi_set_sample_rate(struct dw_hdmi *hdmi, unsigned int rate);
 void dw_hdmi_audio_enable(struct dw_hdmi *hdmi);
 void dw_hdmi_audio_disable(struct dw_hdmi *hdmi);
-- 
1.9.1

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

* [PATCH 3/4] drm: bridge: dw-hdmi: Enable CSC even for DVI
  2017-01-30 11:05 ` Neil Armstrong
  (?)
@ 2017-01-30 11:05   ` Neil Armstrong
  -1 siblings, 0 replies; 15+ messages in thread
From: Neil Armstrong @ 2017-01-30 11:05 UTC (permalink / raw)
  To: dri-devel, laurent.pinchart+renesas
  Cc: Neil Armstrong, Jose.Abreu, kieran.bingham, linux-amlogic, linux-kernel

If the input pixel format is not RGB, the CSC must be enabled in order to
provide valid pixel to DVI sinks.
This patch removes the hdmi only dependency on the CSC enabling.

Reviewed-by: Jose Abreu <joabreu@synopsys.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
 drivers/gpu/drm/bridge/dw-hdmi.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
index a8083f4..f75e5f9 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/dw-hdmi.c
@@ -1317,8 +1317,8 @@ static void dw_hdmi_enable_video_path(struct dw_hdmi *hdmi)
 		hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS);
 	}
 
-	/* Enable color space conversion if needed (for HDMI sinks only). */
-	if (hdmi->sink_is_hdmi && is_color_space_conversion(hdmi))
+	/* Enable color space conversion if needed */
+	if (is_color_space_conversion(hdmi))
 		hdmi_writeb(hdmi, HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_IN_PATH,
 			    HDMI_MC_FLOWCTRL);
 	else
-- 
1.9.1

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

* [PATCH 3/4] drm: bridge: dw-hdmi: Enable CSC even for DVI
@ 2017-01-30 11:05   ` Neil Armstrong
  0 siblings, 0 replies; 15+ messages in thread
From: Neil Armstrong @ 2017-01-30 11:05 UTC (permalink / raw)
  To: dri-devel, laurent.pinchart+renesas
  Cc: Jose.Abreu, linux-amlogic, kieran.bingham, linux-kernel, Neil Armstrong

If the input pixel format is not RGB, the CSC must be enabled in order to
provide valid pixel to DVI sinks.
This patch removes the hdmi only dependency on the CSC enabling.

Reviewed-by: Jose Abreu <joabreu@synopsys.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
 drivers/gpu/drm/bridge/dw-hdmi.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
index a8083f4..f75e5f9 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/dw-hdmi.c
@@ -1317,8 +1317,8 @@ static void dw_hdmi_enable_video_path(struct dw_hdmi *hdmi)
 		hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS);
 	}
 
-	/* Enable color space conversion if needed (for HDMI sinks only). */
-	if (hdmi->sink_is_hdmi && is_color_space_conversion(hdmi))
+	/* Enable color space conversion if needed */
+	if (is_color_space_conversion(hdmi))
 		hdmi_writeb(hdmi, HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_IN_PATH,
 			    HDMI_MC_FLOWCTRL);
 	else
-- 
1.9.1

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

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

* [PATCH 3/4] drm: bridge: dw-hdmi: Enable CSC even for DVI
@ 2017-01-30 11:05   ` Neil Armstrong
  0 siblings, 0 replies; 15+ messages in thread
From: Neil Armstrong @ 2017-01-30 11:05 UTC (permalink / raw)
  To: linus-amlogic

If the input pixel format is not RGB, the CSC must be enabled in order to
provide valid pixel to DVI sinks.
This patch removes the hdmi only dependency on the CSC enabling.

Reviewed-by: Jose Abreu <joabreu@synopsys.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
 drivers/gpu/drm/bridge/dw-hdmi.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
index a8083f4..f75e5f9 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/dw-hdmi.c
@@ -1317,8 +1317,8 @@ static void dw_hdmi_enable_video_path(struct dw_hdmi *hdmi)
 		hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS);
 	}
 
-	/* Enable color space conversion if needed (for HDMI sinks only). */
-	if (hdmi->sink_is_hdmi && is_color_space_conversion(hdmi))
+	/* Enable color space conversion if needed */
+	if (is_color_space_conversion(hdmi))
 		hdmi_writeb(hdmi, HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_IN_PATH,
 			    HDMI_MC_FLOWCTRL);
 	else
-- 
1.9.1

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

* [PATCH 4/4] drm: bridge: dw-hdmi: Take input format from plat_data
  2017-01-30 11:05 ` Neil Armstrong
  (?)
@ 2017-01-30 11:05   ` Neil Armstrong
  -1 siblings, 0 replies; 15+ messages in thread
From: Neil Armstrong @ 2017-01-30 11:05 UTC (permalink / raw)
  To: dri-devel, laurent.pinchart+renesas
  Cc: Neil Armstrong, Jose.Abreu, kieran.bingham, linux-amlogic, linux-kernel

Some display pipelines can only provide non-RBG input pixels to the HDMI TX
Controller, this patch takes the pixel format from the plat_data if provided.

Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
 drivers/gpu/drm/bridge/dw-hdmi.c | 55 ++++++++++++++++++++--------------------
 include/drm/bridge/dw_hdmi.h     | 14 ++++++++--
 2 files changed, 40 insertions(+), 29 deletions(-)

diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
index f75e5f9..f4ba019 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/dw-hdmi.c
@@ -35,12 +35,6 @@
 
 #define HDMI_EDID_LEN		512
 
-#define RGB			0
-#define YCBCR444		1
-#define YCBCR422_16BITS		2
-#define YCBCR422_8BITS		3
-#define XVYCC444		4
-
 enum hdmi_datamap {
 	RGB444_8B = 0x01,
 	RGB444_10B = 0x03,
@@ -548,7 +542,7 @@ static void hdmi_video_sample(struct dw_hdmi *hdmi)
 	int color_format = 0;
 	u8 val;
 
-	if (hdmi->hdmi_data.enc_in_format == RGB) {
+	if (hdmi->hdmi_data.enc_in_format == DW_HDMI_ENC_FMT_RGB) {
 		if (hdmi->hdmi_data.enc_color_depth == 8)
 			color_format = 0x01;
 		else if (hdmi->hdmi_data.enc_color_depth == 10)
@@ -559,7 +553,7 @@ static void hdmi_video_sample(struct dw_hdmi *hdmi)
 			color_format = 0x07;
 		else
 			return;
-	} else if (hdmi->hdmi_data.enc_in_format == YCBCR444) {
+	} else if (hdmi->hdmi_data.enc_in_format == DW_HDMI_ENC_FMT_YCBCR444) {
 		if (hdmi->hdmi_data.enc_color_depth == 8)
 			color_format = 0x09;
 		else if (hdmi->hdmi_data.enc_color_depth == 10)
@@ -570,7 +564,8 @@ static void hdmi_video_sample(struct dw_hdmi *hdmi)
 			color_format = 0x0F;
 		else
 			return;
-	} else if (hdmi->hdmi_data.enc_in_format == YCBCR422_8BITS) {
+	} else if (hdmi->hdmi_data.enc_in_format ==
+					DW_HDMI_ENC_FMT_YCBCR422_8BITS) {
 		if (hdmi->hdmi_data.enc_color_depth == 8)
 			color_format = 0x16;
 		else if (hdmi->hdmi_data.enc_color_depth == 10)
@@ -606,20 +601,20 @@ static int is_color_space_conversion(struct dw_hdmi *hdmi)
 
 static int is_color_space_decimation(struct dw_hdmi *hdmi)
 {
-	if (hdmi->hdmi_data.enc_out_format != YCBCR422_8BITS)
+	if (hdmi->hdmi_data.enc_out_format != DW_HDMI_ENC_FMT_YCBCR422_8BITS)
 		return 0;
-	if (hdmi->hdmi_data.enc_in_format == RGB ||
-	    hdmi->hdmi_data.enc_in_format == YCBCR444)
+	if (hdmi->hdmi_data.enc_in_format == DW_HDMI_ENC_FMT_RGB ||
+	    hdmi->hdmi_data.enc_in_format == DW_HDMI_ENC_FMT_YCBCR444)
 		return 1;
 	return 0;
 }
 
 static int is_color_space_interpolation(struct dw_hdmi *hdmi)
 {
-	if (hdmi->hdmi_data.enc_in_format != YCBCR422_8BITS)
+	if (hdmi->hdmi_data.enc_in_format != DW_HDMI_ENC_FMT_YCBCR422_8BITS)
 		return 0;
-	if (hdmi->hdmi_data.enc_out_format == RGB ||
-	    hdmi->hdmi_data.enc_out_format == YCBCR444)
+	if (hdmi->hdmi_data.enc_out_format == DW_HDMI_ENC_FMT_RGB ||
+	    hdmi->hdmi_data.enc_out_format == DW_HDMI_ENC_FMT_YCBCR444)
 		return 1;
 	return 0;
 }
@@ -631,13 +626,14 @@ static void dw_hdmi_update_csc_coeffs(struct dw_hdmi *hdmi)
 	u32 csc_scale = 1;
 
 	if (is_color_space_conversion(hdmi)) {
-		if (hdmi->hdmi_data.enc_out_format == RGB) {
+		if (hdmi->hdmi_data.enc_out_format == DW_HDMI_ENC_FMT_RGB) {
 			if (hdmi->hdmi_data.colorimetry ==
 					HDMI_COLORIMETRY_ITU_601)
 				csc_coeff = &csc_coeff_rgb_out_eitu601;
 			else
 				csc_coeff = &csc_coeff_rgb_out_eitu709;
-		} else if (hdmi->hdmi_data.enc_in_format == RGB) {
+		} else if (hdmi->hdmi_data.enc_in_format ==
+					DW_HDMI_ENC_FMT_RGB) {
 			if (hdmi->hdmi_data.colorimetry ==
 					HDMI_COLORIMETRY_ITU_601)
 				csc_coeff = &csc_coeff_rgb_in_eitu601;
@@ -709,8 +705,8 @@ static void hdmi_video_packetize(struct dw_hdmi *hdmi)
 	struct hdmi_data_info *hdmi_data = &hdmi->hdmi_data;
 	u8 val, vp_conf;
 
-	if (hdmi_data->enc_out_format == RGB ||
-	    hdmi_data->enc_out_format == YCBCR444) {
+	if (hdmi_data->enc_out_format == DW_HDMI_ENC_FMT_RGB ||
+	    hdmi_data->enc_out_format == DW_HDMI_ENC_FMT_YCBCR444) {
 		if (!hdmi_data->enc_color_depth) {
 			output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS;
 		} else if (hdmi_data->enc_color_depth == 8) {
@@ -725,7 +721,8 @@ static void hdmi_video_packetize(struct dw_hdmi *hdmi)
 		} else {
 			return;
 		}
-	} else if (hdmi_data->enc_out_format == YCBCR422_8BITS) {
+	} else if (hdmi_data->enc_out_format ==
+					DW_HDMI_ENC_FMT_YCBCR422_8BITS) {
 		if (!hdmi_data->enc_color_depth ||
 		    hdmi_data->enc_color_depth == 8)
 			remap_size = HDMI_VP_REMAP_YCC422_16bit;
@@ -1101,15 +1098,16 @@ static void hdmi_config_AVI(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
 	/* Initialise info frame from DRM mode */
 	drm_hdmi_avi_infoframe_from_display_mode(&frame, mode);
 
-	if (hdmi->hdmi_data.enc_out_format == YCBCR444)
+	if (hdmi->hdmi_data.enc_out_format == DW_HDMI_ENC_FMT_YCBCR444)
 		frame.colorspace = HDMI_COLORSPACE_YUV444;
-	else if (hdmi->hdmi_data.enc_out_format == YCBCR422_8BITS)
+	else if (hdmi->hdmi_data.enc_out_format ==
+					DW_HDMI_ENC_FMT_YCBCR422_8BITS)
 		frame.colorspace = HDMI_COLORSPACE_YUV422;
 	else
 		frame.colorspace = HDMI_COLORSPACE_RGB;
 
 	/* Set up colorimetry */
-	if (hdmi->hdmi_data.enc_out_format == XVYCC444) {
+	if (hdmi->hdmi_data.enc_out_format == DW_HDMI_ENC_FMT_XVYCC444) {
 		frame.colorimetry = HDMI_COLORIMETRY_EXTENDED;
 		if (hdmi->hdmi_data.colorimetry == HDMI_COLORIMETRY_ITU_601)
 			frame.extended_colorimetry =
@@ -1117,7 +1115,7 @@ static void hdmi_config_AVI(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
 		else /*hdmi->hdmi_data.colorimetry == HDMI_COLORIMETRY_ITU_709*/
 			frame.extended_colorimetry =
 				HDMI_EXTENDED_COLORIMETRY_XV_YCC_709;
-	} else if (hdmi->hdmi_data.enc_out_format != RGB) {
+	} else if (hdmi->hdmi_data.enc_out_format != DW_HDMI_ENC_FMT_RGB) {
 		frame.colorimetry = hdmi->hdmi_data.colorimetry;
 		frame.extended_colorimetry = HDMI_EXTENDED_COLORIMETRY_XV_YCC_601;
 	} else { /* Carries no data */
@@ -1406,10 +1404,13 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
 	hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 0;
 	hdmi->hdmi_data.video_mode.mpixelrepetitioninput = 0;
 
-	/* TODO: Get input format from IPU (via FB driver interface) */
-	hdmi->hdmi_data.enc_in_format = RGB;
+	/* Get input format from plat data or fallback to RGB */
+	if (hdmi->plat_data->input_fmt >= 0)
+		hdmi->hdmi_data.enc_in_format = hdmi->plat_data->input_fmt;
+	else
+		hdmi->hdmi_data.enc_in_format = DW_HDMI_ENC_FMT_RGB;
 
-	hdmi->hdmi_data.enc_out_format = RGB;
+	hdmi->hdmi_data.enc_out_format = DW_HDMI_ENC_FMT_RGB;
 
 	hdmi->hdmi_data.enc_color_depth = 8;
 	hdmi->hdmi_data.pix_repet_factor = 0;
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
index 5b5dfb6..a4caf8b 100644
--- a/include/drm/bridge/dw_hdmi.h
+++ b/include/drm/bridge/dw_hdmi.h
@@ -22,6 +22,14 @@ enum {
 	DW_HDMI_RES_MAX,
 };
 
+enum dw_hdmi_color_enc_format {
+	DW_HDMI_ENC_FMT_RGB = 0,
+	DW_HDMI_ENC_FMT_YCBCR444,
+	DW_HDMI_ENC_FMT_YCBCR422_16BITS,
+	DW_HDMI_ENC_FMT_YCBCR422_8BITS,
+	DW_HDMI_ENC_FMT_XVYCC444,
+};
+
 enum dw_hdmi_phy_type {
 	DW_HDMI_PHY_DWC_HDMI_TX_PHY = 0x00,
 	DW_HDMI_PHY_DWC_MHL_PHY_HEAC = 0xb2,
@@ -61,8 +69,8 @@ struct hdmi_vmode {
 };
 
 struct hdmi_data_info {
-	unsigned int enc_in_format;
-	unsigned int enc_out_format;
+	enum dw_hdmi_color_enc_format enc_in_format;
+	enum dw_hdmi_color_enc_format enc_out_format;
 	unsigned int enc_color_depth;
 	unsigned int colorimetry;
 	unsigned int pix_repet_factor;
@@ -95,6 +103,8 @@ struct dw_hdmi_plat_data {
 	enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
 					   struct drm_display_mode *mode);
 	struct regmap *regm;
+
+	int input_fmt;
 };
 
 int dw_hdmi_probe(struct platform_device *pdev,
-- 
1.9.1

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

* [PATCH 4/4] drm: bridge: dw-hdmi: Take input format from plat_data
@ 2017-01-30 11:05   ` Neil Armstrong
  0 siblings, 0 replies; 15+ messages in thread
From: Neil Armstrong @ 2017-01-30 11:05 UTC (permalink / raw)
  To: dri-devel, laurent.pinchart+renesas
  Cc: Jose.Abreu, linux-amlogic, kieran.bingham, linux-kernel, Neil Armstrong

Some display pipelines can only provide non-RBG input pixels to the HDMI TX
Controller, this patch takes the pixel format from the plat_data if provided.

Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
 drivers/gpu/drm/bridge/dw-hdmi.c | 55 ++++++++++++++++++++--------------------
 include/drm/bridge/dw_hdmi.h     | 14 ++++++++--
 2 files changed, 40 insertions(+), 29 deletions(-)

diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
index f75e5f9..f4ba019 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/dw-hdmi.c
@@ -35,12 +35,6 @@
 
 #define HDMI_EDID_LEN		512
 
-#define RGB			0
-#define YCBCR444		1
-#define YCBCR422_16BITS		2
-#define YCBCR422_8BITS		3
-#define XVYCC444		4
-
 enum hdmi_datamap {
 	RGB444_8B = 0x01,
 	RGB444_10B = 0x03,
@@ -548,7 +542,7 @@ static void hdmi_video_sample(struct dw_hdmi *hdmi)
 	int color_format = 0;
 	u8 val;
 
-	if (hdmi->hdmi_data.enc_in_format == RGB) {
+	if (hdmi->hdmi_data.enc_in_format == DW_HDMI_ENC_FMT_RGB) {
 		if (hdmi->hdmi_data.enc_color_depth == 8)
 			color_format = 0x01;
 		else if (hdmi->hdmi_data.enc_color_depth == 10)
@@ -559,7 +553,7 @@ static void hdmi_video_sample(struct dw_hdmi *hdmi)
 			color_format = 0x07;
 		else
 			return;
-	} else if (hdmi->hdmi_data.enc_in_format == YCBCR444) {
+	} else if (hdmi->hdmi_data.enc_in_format == DW_HDMI_ENC_FMT_YCBCR444) {
 		if (hdmi->hdmi_data.enc_color_depth == 8)
 			color_format = 0x09;
 		else if (hdmi->hdmi_data.enc_color_depth == 10)
@@ -570,7 +564,8 @@ static void hdmi_video_sample(struct dw_hdmi *hdmi)
 			color_format = 0x0F;
 		else
 			return;
-	} else if (hdmi->hdmi_data.enc_in_format == YCBCR422_8BITS) {
+	} else if (hdmi->hdmi_data.enc_in_format ==
+					DW_HDMI_ENC_FMT_YCBCR422_8BITS) {
 		if (hdmi->hdmi_data.enc_color_depth == 8)
 			color_format = 0x16;
 		else if (hdmi->hdmi_data.enc_color_depth == 10)
@@ -606,20 +601,20 @@ static int is_color_space_conversion(struct dw_hdmi *hdmi)
 
 static int is_color_space_decimation(struct dw_hdmi *hdmi)
 {
-	if (hdmi->hdmi_data.enc_out_format != YCBCR422_8BITS)
+	if (hdmi->hdmi_data.enc_out_format != DW_HDMI_ENC_FMT_YCBCR422_8BITS)
 		return 0;
-	if (hdmi->hdmi_data.enc_in_format == RGB ||
-	    hdmi->hdmi_data.enc_in_format == YCBCR444)
+	if (hdmi->hdmi_data.enc_in_format == DW_HDMI_ENC_FMT_RGB ||
+	    hdmi->hdmi_data.enc_in_format == DW_HDMI_ENC_FMT_YCBCR444)
 		return 1;
 	return 0;
 }
 
 static int is_color_space_interpolation(struct dw_hdmi *hdmi)
 {
-	if (hdmi->hdmi_data.enc_in_format != YCBCR422_8BITS)
+	if (hdmi->hdmi_data.enc_in_format != DW_HDMI_ENC_FMT_YCBCR422_8BITS)
 		return 0;
-	if (hdmi->hdmi_data.enc_out_format == RGB ||
-	    hdmi->hdmi_data.enc_out_format == YCBCR444)
+	if (hdmi->hdmi_data.enc_out_format == DW_HDMI_ENC_FMT_RGB ||
+	    hdmi->hdmi_data.enc_out_format == DW_HDMI_ENC_FMT_YCBCR444)
 		return 1;
 	return 0;
 }
@@ -631,13 +626,14 @@ static void dw_hdmi_update_csc_coeffs(struct dw_hdmi *hdmi)
 	u32 csc_scale = 1;
 
 	if (is_color_space_conversion(hdmi)) {
-		if (hdmi->hdmi_data.enc_out_format == RGB) {
+		if (hdmi->hdmi_data.enc_out_format == DW_HDMI_ENC_FMT_RGB) {
 			if (hdmi->hdmi_data.colorimetry ==
 					HDMI_COLORIMETRY_ITU_601)
 				csc_coeff = &csc_coeff_rgb_out_eitu601;
 			else
 				csc_coeff = &csc_coeff_rgb_out_eitu709;
-		} else if (hdmi->hdmi_data.enc_in_format == RGB) {
+		} else if (hdmi->hdmi_data.enc_in_format ==
+					DW_HDMI_ENC_FMT_RGB) {
 			if (hdmi->hdmi_data.colorimetry ==
 					HDMI_COLORIMETRY_ITU_601)
 				csc_coeff = &csc_coeff_rgb_in_eitu601;
@@ -709,8 +705,8 @@ static void hdmi_video_packetize(struct dw_hdmi *hdmi)
 	struct hdmi_data_info *hdmi_data = &hdmi->hdmi_data;
 	u8 val, vp_conf;
 
-	if (hdmi_data->enc_out_format == RGB ||
-	    hdmi_data->enc_out_format == YCBCR444) {
+	if (hdmi_data->enc_out_format == DW_HDMI_ENC_FMT_RGB ||
+	    hdmi_data->enc_out_format == DW_HDMI_ENC_FMT_YCBCR444) {
 		if (!hdmi_data->enc_color_depth) {
 			output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS;
 		} else if (hdmi_data->enc_color_depth == 8) {
@@ -725,7 +721,8 @@ static void hdmi_video_packetize(struct dw_hdmi *hdmi)
 		} else {
 			return;
 		}
-	} else if (hdmi_data->enc_out_format == YCBCR422_8BITS) {
+	} else if (hdmi_data->enc_out_format ==
+					DW_HDMI_ENC_FMT_YCBCR422_8BITS) {
 		if (!hdmi_data->enc_color_depth ||
 		    hdmi_data->enc_color_depth == 8)
 			remap_size = HDMI_VP_REMAP_YCC422_16bit;
@@ -1101,15 +1098,16 @@ static void hdmi_config_AVI(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
 	/* Initialise info frame from DRM mode */
 	drm_hdmi_avi_infoframe_from_display_mode(&frame, mode);
 
-	if (hdmi->hdmi_data.enc_out_format == YCBCR444)
+	if (hdmi->hdmi_data.enc_out_format == DW_HDMI_ENC_FMT_YCBCR444)
 		frame.colorspace = HDMI_COLORSPACE_YUV444;
-	else if (hdmi->hdmi_data.enc_out_format == YCBCR422_8BITS)
+	else if (hdmi->hdmi_data.enc_out_format ==
+					DW_HDMI_ENC_FMT_YCBCR422_8BITS)
 		frame.colorspace = HDMI_COLORSPACE_YUV422;
 	else
 		frame.colorspace = HDMI_COLORSPACE_RGB;
 
 	/* Set up colorimetry */
-	if (hdmi->hdmi_data.enc_out_format == XVYCC444) {
+	if (hdmi->hdmi_data.enc_out_format == DW_HDMI_ENC_FMT_XVYCC444) {
 		frame.colorimetry = HDMI_COLORIMETRY_EXTENDED;
 		if (hdmi->hdmi_data.colorimetry == HDMI_COLORIMETRY_ITU_601)
 			frame.extended_colorimetry =
@@ -1117,7 +1115,7 @@ static void hdmi_config_AVI(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
 		else /*hdmi->hdmi_data.colorimetry == HDMI_COLORIMETRY_ITU_709*/
 			frame.extended_colorimetry =
 				HDMI_EXTENDED_COLORIMETRY_XV_YCC_709;
-	} else if (hdmi->hdmi_data.enc_out_format != RGB) {
+	} else if (hdmi->hdmi_data.enc_out_format != DW_HDMI_ENC_FMT_RGB) {
 		frame.colorimetry = hdmi->hdmi_data.colorimetry;
 		frame.extended_colorimetry = HDMI_EXTENDED_COLORIMETRY_XV_YCC_601;
 	} else { /* Carries no data */
@@ -1406,10 +1404,13 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
 	hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 0;
 	hdmi->hdmi_data.video_mode.mpixelrepetitioninput = 0;
 
-	/* TODO: Get input format from IPU (via FB driver interface) */
-	hdmi->hdmi_data.enc_in_format = RGB;
+	/* Get input format from plat data or fallback to RGB */
+	if (hdmi->plat_data->input_fmt >= 0)
+		hdmi->hdmi_data.enc_in_format = hdmi->plat_data->input_fmt;
+	else
+		hdmi->hdmi_data.enc_in_format = DW_HDMI_ENC_FMT_RGB;
 
-	hdmi->hdmi_data.enc_out_format = RGB;
+	hdmi->hdmi_data.enc_out_format = DW_HDMI_ENC_FMT_RGB;
 
 	hdmi->hdmi_data.enc_color_depth = 8;
 	hdmi->hdmi_data.pix_repet_factor = 0;
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
index 5b5dfb6..a4caf8b 100644
--- a/include/drm/bridge/dw_hdmi.h
+++ b/include/drm/bridge/dw_hdmi.h
@@ -22,6 +22,14 @@ enum {
 	DW_HDMI_RES_MAX,
 };
 
+enum dw_hdmi_color_enc_format {
+	DW_HDMI_ENC_FMT_RGB = 0,
+	DW_HDMI_ENC_FMT_YCBCR444,
+	DW_HDMI_ENC_FMT_YCBCR422_16BITS,
+	DW_HDMI_ENC_FMT_YCBCR422_8BITS,
+	DW_HDMI_ENC_FMT_XVYCC444,
+};
+
 enum dw_hdmi_phy_type {
 	DW_HDMI_PHY_DWC_HDMI_TX_PHY = 0x00,
 	DW_HDMI_PHY_DWC_MHL_PHY_HEAC = 0xb2,
@@ -61,8 +69,8 @@ struct hdmi_vmode {
 };
 
 struct hdmi_data_info {
-	unsigned int enc_in_format;
-	unsigned int enc_out_format;
+	enum dw_hdmi_color_enc_format enc_in_format;
+	enum dw_hdmi_color_enc_format enc_out_format;
 	unsigned int enc_color_depth;
 	unsigned int colorimetry;
 	unsigned int pix_repet_factor;
@@ -95,6 +103,8 @@ struct dw_hdmi_plat_data {
 	enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
 					   struct drm_display_mode *mode);
 	struct regmap *regm;
+
+	int input_fmt;
 };
 
 int dw_hdmi_probe(struct platform_device *pdev,
-- 
1.9.1

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

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

* [PATCH 4/4] drm: bridge: dw-hdmi: Take input format from plat_data
@ 2017-01-30 11:05   ` Neil Armstrong
  0 siblings, 0 replies; 15+ messages in thread
From: Neil Armstrong @ 2017-01-30 11:05 UTC (permalink / raw)
  To: linus-amlogic

Some display pipelines can only provide non-RBG input pixels to the HDMI TX
Controller, this patch takes the pixel format from the plat_data if provided.

Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
 drivers/gpu/drm/bridge/dw-hdmi.c | 55 ++++++++++++++++++++--------------------
 include/drm/bridge/dw_hdmi.h     | 14 ++++++++--
 2 files changed, 40 insertions(+), 29 deletions(-)

diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
index f75e5f9..f4ba019 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/dw-hdmi.c
@@ -35,12 +35,6 @@
 
 #define HDMI_EDID_LEN		512
 
-#define RGB			0
-#define YCBCR444		1
-#define YCBCR422_16BITS		2
-#define YCBCR422_8BITS		3
-#define XVYCC444		4
-
 enum hdmi_datamap {
 	RGB444_8B = 0x01,
 	RGB444_10B = 0x03,
@@ -548,7 +542,7 @@ static void hdmi_video_sample(struct dw_hdmi *hdmi)
 	int color_format = 0;
 	u8 val;
 
-	if (hdmi->hdmi_data.enc_in_format == RGB) {
+	if (hdmi->hdmi_data.enc_in_format == DW_HDMI_ENC_FMT_RGB) {
 		if (hdmi->hdmi_data.enc_color_depth == 8)
 			color_format = 0x01;
 		else if (hdmi->hdmi_data.enc_color_depth == 10)
@@ -559,7 +553,7 @@ static void hdmi_video_sample(struct dw_hdmi *hdmi)
 			color_format = 0x07;
 		else
 			return;
-	} else if (hdmi->hdmi_data.enc_in_format == YCBCR444) {
+	} else if (hdmi->hdmi_data.enc_in_format == DW_HDMI_ENC_FMT_YCBCR444) {
 		if (hdmi->hdmi_data.enc_color_depth == 8)
 			color_format = 0x09;
 		else if (hdmi->hdmi_data.enc_color_depth == 10)
@@ -570,7 +564,8 @@ static void hdmi_video_sample(struct dw_hdmi *hdmi)
 			color_format = 0x0F;
 		else
 			return;
-	} else if (hdmi->hdmi_data.enc_in_format == YCBCR422_8BITS) {
+	} else if (hdmi->hdmi_data.enc_in_format ==
+					DW_HDMI_ENC_FMT_YCBCR422_8BITS) {
 		if (hdmi->hdmi_data.enc_color_depth == 8)
 			color_format = 0x16;
 		else if (hdmi->hdmi_data.enc_color_depth == 10)
@@ -606,20 +601,20 @@ static int is_color_space_conversion(struct dw_hdmi *hdmi)
 
 static int is_color_space_decimation(struct dw_hdmi *hdmi)
 {
-	if (hdmi->hdmi_data.enc_out_format != YCBCR422_8BITS)
+	if (hdmi->hdmi_data.enc_out_format != DW_HDMI_ENC_FMT_YCBCR422_8BITS)
 		return 0;
-	if (hdmi->hdmi_data.enc_in_format == RGB ||
-	    hdmi->hdmi_data.enc_in_format == YCBCR444)
+	if (hdmi->hdmi_data.enc_in_format == DW_HDMI_ENC_FMT_RGB ||
+	    hdmi->hdmi_data.enc_in_format == DW_HDMI_ENC_FMT_YCBCR444)
 		return 1;
 	return 0;
 }
 
 static int is_color_space_interpolation(struct dw_hdmi *hdmi)
 {
-	if (hdmi->hdmi_data.enc_in_format != YCBCR422_8BITS)
+	if (hdmi->hdmi_data.enc_in_format != DW_HDMI_ENC_FMT_YCBCR422_8BITS)
 		return 0;
-	if (hdmi->hdmi_data.enc_out_format == RGB ||
-	    hdmi->hdmi_data.enc_out_format == YCBCR444)
+	if (hdmi->hdmi_data.enc_out_format == DW_HDMI_ENC_FMT_RGB ||
+	    hdmi->hdmi_data.enc_out_format == DW_HDMI_ENC_FMT_YCBCR444)
 		return 1;
 	return 0;
 }
@@ -631,13 +626,14 @@ static void dw_hdmi_update_csc_coeffs(struct dw_hdmi *hdmi)
 	u32 csc_scale = 1;
 
 	if (is_color_space_conversion(hdmi)) {
-		if (hdmi->hdmi_data.enc_out_format == RGB) {
+		if (hdmi->hdmi_data.enc_out_format == DW_HDMI_ENC_FMT_RGB) {
 			if (hdmi->hdmi_data.colorimetry ==
 					HDMI_COLORIMETRY_ITU_601)
 				csc_coeff = &csc_coeff_rgb_out_eitu601;
 			else
 				csc_coeff = &csc_coeff_rgb_out_eitu709;
-		} else if (hdmi->hdmi_data.enc_in_format == RGB) {
+		} else if (hdmi->hdmi_data.enc_in_format ==
+					DW_HDMI_ENC_FMT_RGB) {
 			if (hdmi->hdmi_data.colorimetry ==
 					HDMI_COLORIMETRY_ITU_601)
 				csc_coeff = &csc_coeff_rgb_in_eitu601;
@@ -709,8 +705,8 @@ static void hdmi_video_packetize(struct dw_hdmi *hdmi)
 	struct hdmi_data_info *hdmi_data = &hdmi->hdmi_data;
 	u8 val, vp_conf;
 
-	if (hdmi_data->enc_out_format == RGB ||
-	    hdmi_data->enc_out_format == YCBCR444) {
+	if (hdmi_data->enc_out_format == DW_HDMI_ENC_FMT_RGB ||
+	    hdmi_data->enc_out_format == DW_HDMI_ENC_FMT_YCBCR444) {
 		if (!hdmi_data->enc_color_depth) {
 			output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS;
 		} else if (hdmi_data->enc_color_depth == 8) {
@@ -725,7 +721,8 @@ static void hdmi_video_packetize(struct dw_hdmi *hdmi)
 		} else {
 			return;
 		}
-	} else if (hdmi_data->enc_out_format == YCBCR422_8BITS) {
+	} else if (hdmi_data->enc_out_format ==
+					DW_HDMI_ENC_FMT_YCBCR422_8BITS) {
 		if (!hdmi_data->enc_color_depth ||
 		    hdmi_data->enc_color_depth == 8)
 			remap_size = HDMI_VP_REMAP_YCC422_16bit;
@@ -1101,15 +1098,16 @@ static void hdmi_config_AVI(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
 	/* Initialise info frame from DRM mode */
 	drm_hdmi_avi_infoframe_from_display_mode(&frame, mode);
 
-	if (hdmi->hdmi_data.enc_out_format == YCBCR444)
+	if (hdmi->hdmi_data.enc_out_format == DW_HDMI_ENC_FMT_YCBCR444)
 		frame.colorspace = HDMI_COLORSPACE_YUV444;
-	else if (hdmi->hdmi_data.enc_out_format == YCBCR422_8BITS)
+	else if (hdmi->hdmi_data.enc_out_format ==
+					DW_HDMI_ENC_FMT_YCBCR422_8BITS)
 		frame.colorspace = HDMI_COLORSPACE_YUV422;
 	else
 		frame.colorspace = HDMI_COLORSPACE_RGB;
 
 	/* Set up colorimetry */
-	if (hdmi->hdmi_data.enc_out_format == XVYCC444) {
+	if (hdmi->hdmi_data.enc_out_format == DW_HDMI_ENC_FMT_XVYCC444) {
 		frame.colorimetry = HDMI_COLORIMETRY_EXTENDED;
 		if (hdmi->hdmi_data.colorimetry == HDMI_COLORIMETRY_ITU_601)
 			frame.extended_colorimetry =
@@ -1117,7 +1115,7 @@ static void hdmi_config_AVI(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
 		else /*hdmi->hdmi_data.colorimetry == HDMI_COLORIMETRY_ITU_709*/
 			frame.extended_colorimetry =
 				HDMI_EXTENDED_COLORIMETRY_XV_YCC_709;
-	} else if (hdmi->hdmi_data.enc_out_format != RGB) {
+	} else if (hdmi->hdmi_data.enc_out_format != DW_HDMI_ENC_FMT_RGB) {
 		frame.colorimetry = hdmi->hdmi_data.colorimetry;
 		frame.extended_colorimetry = HDMI_EXTENDED_COLORIMETRY_XV_YCC_601;
 	} else { /* Carries no data */
@@ -1406,10 +1404,13 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
 	hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 0;
 	hdmi->hdmi_data.video_mode.mpixelrepetitioninput = 0;
 
-	/* TODO: Get input format from IPU (via FB driver interface) */
-	hdmi->hdmi_data.enc_in_format = RGB;
+	/* Get input format from plat data or fallback to RGB */
+	if (hdmi->plat_data->input_fmt >= 0)
+		hdmi->hdmi_data.enc_in_format = hdmi->plat_data->input_fmt;
+	else
+		hdmi->hdmi_data.enc_in_format = DW_HDMI_ENC_FMT_RGB;
 
-	hdmi->hdmi_data.enc_out_format = RGB;
+	hdmi->hdmi_data.enc_out_format = DW_HDMI_ENC_FMT_RGB;
 
 	hdmi->hdmi_data.enc_color_depth = 8;
 	hdmi->hdmi_data.pix_repet_factor = 0;
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
index 5b5dfb6..a4caf8b 100644
--- a/include/drm/bridge/dw_hdmi.h
+++ b/include/drm/bridge/dw_hdmi.h
@@ -22,6 +22,14 @@ enum {
 	DW_HDMI_RES_MAX,
 };
 
+enum dw_hdmi_color_enc_format {
+	DW_HDMI_ENC_FMT_RGB = 0,
+	DW_HDMI_ENC_FMT_YCBCR444,
+	DW_HDMI_ENC_FMT_YCBCR422_16BITS,
+	DW_HDMI_ENC_FMT_YCBCR422_8BITS,
+	DW_HDMI_ENC_FMT_XVYCC444,
+};
+
 enum dw_hdmi_phy_type {
 	DW_HDMI_PHY_DWC_HDMI_TX_PHY = 0x00,
 	DW_HDMI_PHY_DWC_MHL_PHY_HEAC = 0xb2,
@@ -61,8 +69,8 @@ struct hdmi_vmode {
 };
 
 struct hdmi_data_info {
-	unsigned int enc_in_format;
-	unsigned int enc_out_format;
+	enum dw_hdmi_color_enc_format enc_in_format;
+	enum dw_hdmi_color_enc_format enc_out_format;
 	unsigned int enc_color_depth;
 	unsigned int colorimetry;
 	unsigned int pix_repet_factor;
@@ -95,6 +103,8 @@ struct dw_hdmi_plat_data {
 	enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
 					   struct drm_display_mode *mode);
 	struct regmap *regm;
+
+	int input_fmt;
 };
 
 int dw_hdmi_probe(struct platform_device *pdev,
-- 
1.9.1

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

end of thread, other threads:[~2017-01-30 11:07 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-01-30 11:05 [PATCH 0/4] drm: bridge: dw-hdmi: Add support for Custom PHYs Neil Armstrong
2017-01-30 11:05 ` Neil Armstrong
2017-01-30 11:05 ` Neil Armstrong
2017-01-30 11:05 ` [PATCH 1/4] drm: bridge: dw-hdmi: Switch to regmap for register access Neil Armstrong
2017-01-30 11:05   ` Neil Armstrong
2017-01-30 11:05   ` Neil Armstrong
2017-01-30 11:05 ` [PATCH 2/4] drm: bridge: dw-hdmi: Add support for custom PHY handling Neil Armstrong
2017-01-30 11:05   ` Neil Armstrong
2017-01-30 11:05   ` Neil Armstrong
2017-01-30 11:05 ` [PATCH 3/4] drm: bridge: dw-hdmi: Enable CSC even for DVI Neil Armstrong
2017-01-30 11:05   ` Neil Armstrong
2017-01-30 11:05   ` Neil Armstrong
2017-01-30 11:05 ` [PATCH 4/4] drm: bridge: dw-hdmi: Take input format from plat_data Neil Armstrong
2017-01-30 11:05   ` Neil Armstrong
2017-01-30 11:05   ` Neil Armstrong

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.