diff mbox

drm/msm: convert to drm_bridge

Message ID 1377882135-10626-1-git-send-email-robdclark@gmail.com (mailing list archive)
State Accepted
Headers show

Commit Message

Rob Clark Aug. 30, 2013, 5:02 p.m. UTC
Drop the msm_connector base class, and special calls to base class
methods from the encoder, and use instead drm_bridge.  This allows for a
cleaner division between the hdmi (and in future dsi) blocks, from the
mdp block.

Signed-off-by: Rob Clark <robdclark@gmail.com>
---
 drivers/gpu/drm/msm/Makefile                |   2 +-
 drivers/gpu/drm/msm/hdmi/hdmi.c             |  49 +++++++-
 drivers/gpu/drm/msm/hdmi/hdmi.h             |  31 +++++-
 drivers/gpu/drm/msm/hdmi/hdmi_bridge.c      | 167 ++++++++++++++++++++++++++++
 drivers/gpu/drm/msm/hdmi/hdmi_connector.c   | 156 ++++++--------------------
 drivers/gpu/drm/msm/mdp4/mdp4_dtv_encoder.c |  12 --
 drivers/gpu/drm/msm/mdp4/mdp4_kms.c         |   9 +-
 drivers/gpu/drm/msm/msm_connector.c         |  34 ------
 drivers/gpu/drm/msm/msm_connector.h         |  68 -----------
 drivers/gpu/drm/msm/msm_drv.h               |   6 +-
 10 files changed, 274 insertions(+), 260 deletions(-)
 create mode 100644 drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
 delete mode 100644 drivers/gpu/drm/msm/msm_connector.c
 delete mode 100644 drivers/gpu/drm/msm/msm_connector.h
diff mbox

Patch

diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index 439dfb5..e179148 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -7,6 +7,7 @@  msm-y := \
 	adreno/adreno_gpu.o \
 	adreno/a3xx_gpu.o \
 	hdmi/hdmi.o \
+	hdmi/hdmi_bridge.o \
 	hdmi/hdmi_connector.o \
 	hdmi/hdmi_i2c.o \
 	hdmi/hdmi_phy_8960.o \
@@ -17,7 +18,6 @@  msm-y := \
 	mdp4/mdp4_irq.o \
 	mdp4/mdp4_kms.o \
 	mdp4/mdp4_plane.o \
-	msm_connector.o \
 	msm_drv.o \
 	msm_fb.o \
 	msm_gem.o \
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c
index 12ecfb9..50d11df 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi.c
@@ -56,8 +56,9 @@  static irqreturn_t hdmi_irq(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
-void hdmi_destroy(struct hdmi *hdmi)
+void hdmi_destroy(struct kref *kref)
 {
+	struct hdmi *hdmi = container_of(kref, struct hdmi, refcount);
 	struct hdmi_phy *phy = hdmi->phy;
 
 	if (phy)
@@ -70,9 +71,10 @@  void hdmi_destroy(struct hdmi *hdmi)
 }
 
 /* initialize connector */
-int hdmi_init(struct hdmi *hdmi, struct drm_device *dev,
-		struct drm_connector *connector)
+int hdmi_init(struct drm_device *dev, struct drm_encoder *encoder)
 {
+	struct hdmi *hdmi = NULL;
+	struct msm_drm_private *priv = dev->dev_private;
 	struct platform_device *pdev = hdmi_pdev;
 	struct hdmi_platform_config *config;
 	int ret;
@@ -85,11 +87,19 @@  int hdmi_init(struct hdmi *hdmi, struct drm_device *dev,
 
 	config = pdev->dev.platform_data;
 
+	hdmi = kzalloc(sizeof(*hdmi), GFP_KERNEL);
+	if (!hdmi) {
+		ret = -ENOMEM;
+		goto fail;
+	}
+
+	kref_init(&hdmi->refcount);
+
 	get_device(&pdev->dev);
 
 	hdmi->dev = dev;
 	hdmi->pdev = pdev;
-	hdmi->connector = connector;
+	hdmi->encoder = encoder;
 
 	/* not sure about which phy maps to which msm.. probably I miss some */
 	if (config->phy_init)
@@ -152,6 +162,22 @@  int hdmi_init(struct hdmi *hdmi, struct drm_device *dev,
 		goto fail;
 	}
 
+	hdmi->bridge = hdmi_bridge_init(hdmi);
+	if (IS_ERR(hdmi->bridge)) {
+		ret = PTR_ERR(hdmi->bridge);
+		dev_err(dev->dev, "failed to create HDMI bridge: %d\n", ret);
+		hdmi->bridge = NULL;
+		goto fail;
+	}
+
+	hdmi->connector = hdmi_connector_init(hdmi);
+	if (IS_ERR(hdmi->connector)) {
+		ret = PTR_ERR(hdmi->connector);
+		dev_err(dev->dev, "failed to create HDMI connector: %d\n", ret);
+		hdmi->connector = NULL;
+		goto fail;
+	}
+
 	hdmi->irq = platform_get_irq(pdev, 0);
 	if (hdmi->irq < 0) {
 		ret = hdmi->irq;
@@ -168,11 +194,22 @@  int hdmi_init(struct hdmi *hdmi, struct drm_device *dev,
 		goto fail;
 	}
 
+	encoder->bridge = hdmi->bridge;
+
+	priv->bridges[priv->num_bridges++]       = hdmi->bridge;
+	priv->connectors[priv->num_connectors++] = hdmi->connector;
+
 	return 0;
 
 fail:
-	if (hdmi)
-		hdmi_destroy(hdmi);
+	if (hdmi) {
+		/* bridge/connector are normally destroyed by drm: */
+		if (hdmi->bridge)
+			hdmi->bridge->funcs->destroy(hdmi->bridge);
+		if (hdmi->connector)
+			hdmi->connector->funcs->destroy(hdmi->connector);
+		hdmi_destroy(&hdmi->refcount);
+	}
 
 	return ret;
 }
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.h b/drivers/gpu/drm/msm/hdmi/hdmi.h
index 34703fe..2c2ec56 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi.h
+++ b/drivers/gpu/drm/msm/hdmi/hdmi.h
@@ -30,6 +30,8 @@ 
 struct hdmi_phy;
 
 struct hdmi {
+	struct kref refcount;
+
 	struct drm_device *dev;
 	struct platform_device *pdev;
 
@@ -45,6 +47,10 @@  struct hdmi {
 	struct hdmi_phy *phy;
 	struct i2c_adapter *i2c;
 	struct drm_connector *connector;
+	struct drm_bridge *bridge;
+
+	/* the encoder we are hooked to (outside of hdmi block) */
+	struct drm_encoder *encoder;
 
 	bool hdmi_mode;               /* are we in hdmi mode? */
 
@@ -58,9 +64,7 @@  struct hdmi_platform_config {
 };
 
 void hdmi_set_mode(struct hdmi *hdmi, bool power_on);
-void hdmi_destroy(struct hdmi *hdmi);
-int hdmi_init(struct hdmi *hdmi, struct drm_device *dev,
-		struct drm_connector *connector);
+void hdmi_destroy(struct kref *kref);
 
 static inline void hdmi_write(struct hdmi *hdmi, u32 reg, u32 data)
 {
@@ -72,6 +76,17 @@  static inline u32 hdmi_read(struct hdmi *hdmi, u32 reg)
 	return msm_readl(hdmi->mmio + reg);
 }
 
+static inline struct hdmi * hdmi_reference(struct hdmi *hdmi)
+{
+	kref_get(&hdmi->refcount);
+	return hdmi;
+}
+
+static inline void hdmi_unreference(struct hdmi *hdmi)
+{
+	kref_put(&hdmi->refcount, hdmi_destroy);
+}
+
 /*
  * The phy appears to be different, for example between 8960 and 8x60,
  * so split the phy related functions out and load the correct one at
@@ -89,17 +104,21 @@  struct hdmi_phy {
 	const struct hdmi_phy_funcs *funcs;
 };
 
-/*
- * phy can be different on different generations:
- */
 struct hdmi_phy *hdmi_phy_8960_init(struct hdmi *hdmi);
 struct hdmi_phy *hdmi_phy_8x60_init(struct hdmi *hdmi);
 
 /*
+ * hdmi bridge:
+ */
+
+struct drm_bridge *hdmi_bridge_init(struct hdmi *hdmi);
+
+/*
  * hdmi connector:
  */
 
 void hdmi_connector_irq(struct drm_connector *connector);
+struct drm_connector *hdmi_connector_init(struct hdmi *hdmi);
 
 /*
  * i2c adapter for ddc:
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
new file mode 100644
index 0000000..5a8ee34
--- /dev/null
+++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
@@ -0,0 +1,167 @@ 
+/*
+ * Copyright (C) 2013 Red Hat
+ * Author: Rob Clark <robdclark@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hdmi.h"
+
+struct hdmi_bridge {
+	struct drm_bridge base;
+
+	struct hdmi *hdmi;
+
+	unsigned long int pixclock;
+};
+#define to_hdmi_bridge(x) container_of(x, struct hdmi_bridge, base)
+
+static void hdmi_bridge_destroy(struct drm_bridge *bridge)
+{
+	struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
+	hdmi_unreference(hdmi_bridge->hdmi);
+	drm_bridge_cleanup(bridge);
+	kfree(hdmi_bridge);
+}
+
+static void hdmi_bridge_pre_enable(struct drm_bridge *bridge)
+{
+	struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
+	struct hdmi *hdmi = hdmi_bridge->hdmi;
+	struct hdmi_phy *phy = hdmi->phy;
+
+	DBG("power up");
+	phy->funcs->powerup(phy, hdmi_bridge->pixclock);
+	hdmi_set_mode(hdmi, true);
+}
+
+static void hdmi_bridge_enable(struct drm_bridge *bridge)
+{
+}
+
+static void hdmi_bridge_disable(struct drm_bridge *bridge)
+{
+}
+
+static void hdmi_bridge_post_disable(struct drm_bridge *bridge)
+{
+	struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
+	struct hdmi *hdmi = hdmi_bridge->hdmi;
+	struct hdmi_phy *phy = hdmi->phy;
+
+	DBG("power down");
+	hdmi_set_mode(hdmi, false);
+	phy->funcs->powerdown(phy);
+}
+
+static void hdmi_bridge_mode_set(struct drm_bridge *bridge,
+		 struct drm_display_mode *mode,
+		 struct drm_display_mode *adjusted_mode)
+{
+	struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
+	struct hdmi *hdmi = hdmi_bridge->hdmi;
+	int hstart, hend, vstart, vend;
+	uint32_t frame_ctrl;
+
+	mode = adjusted_mode;
+
+	hdmi_bridge->pixclock = mode->clock * 1000;
+
+	hdmi->hdmi_mode = drm_match_cea_mode(mode) > 1;
+
+	hstart = mode->htotal - mode->hsync_start;
+	hend   = mode->htotal - mode->hsync_start + mode->hdisplay;
+
+	vstart = mode->vtotal - mode->vsync_start - 1;
+	vend   = mode->vtotal - mode->vsync_start + mode->vdisplay - 1;
+
+	DBG("htotal=%d, vtotal=%d, hstart=%d, hend=%d, vstart=%d, vend=%d",
+			mode->htotal, mode->vtotal, hstart, hend, vstart, vend);
+
+	hdmi_write(hdmi, REG_HDMI_TOTAL,
+			HDMI_TOTAL_H_TOTAL(mode->htotal - 1) |
+			HDMI_TOTAL_V_TOTAL(mode->vtotal - 1));
+
+	hdmi_write(hdmi, REG_HDMI_ACTIVE_HSYNC,
+			HDMI_ACTIVE_HSYNC_START(hstart) |
+			HDMI_ACTIVE_HSYNC_END(hend));
+	hdmi_write(hdmi, REG_HDMI_ACTIVE_VSYNC,
+			HDMI_ACTIVE_VSYNC_START(vstart) |
+			HDMI_ACTIVE_VSYNC_END(vend));
+
+	if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
+		hdmi_write(hdmi, REG_HDMI_VSYNC_TOTAL_F2,
+				HDMI_VSYNC_TOTAL_F2_V_TOTAL(mode->vtotal));
+		hdmi_write(hdmi, REG_HDMI_VSYNC_ACTIVE_F2,
+				HDMI_VSYNC_ACTIVE_F2_START(vstart + 1) |
+				HDMI_VSYNC_ACTIVE_F2_END(vend + 1));
+	} else {
+		hdmi_write(hdmi, REG_HDMI_VSYNC_TOTAL_F2,
+				HDMI_VSYNC_TOTAL_F2_V_TOTAL(0));
+		hdmi_write(hdmi, REG_HDMI_VSYNC_ACTIVE_F2,
+				HDMI_VSYNC_ACTIVE_F2_START(0) |
+				HDMI_VSYNC_ACTIVE_F2_END(0));
+	}
+
+	frame_ctrl = 0;
+	if (mode->flags & DRM_MODE_FLAG_NHSYNC)
+		frame_ctrl |= HDMI_FRAME_CTRL_HSYNC_LOW;
+	if (mode->flags & DRM_MODE_FLAG_NVSYNC)
+		frame_ctrl |= HDMI_FRAME_CTRL_VSYNC_LOW;
+	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+		frame_ctrl |= HDMI_FRAME_CTRL_INTERLACED_EN;
+	DBG("frame_ctrl=%08x", frame_ctrl);
+	hdmi_write(hdmi, REG_HDMI_FRAME_CTRL, frame_ctrl);
+
+	// TODO until we have audio, this might be safest:
+	if (hdmi->hdmi_mode)
+		hdmi_write(hdmi, REG_HDMI_GC, HDMI_GC_MUTE);
+}
+
+static const struct drm_bridge_funcs hdmi_bridge_funcs = {
+		.pre_enable = hdmi_bridge_pre_enable,
+		.enable = hdmi_bridge_enable,
+		.disable = hdmi_bridge_disable,
+		.post_disable = hdmi_bridge_post_disable,
+		.mode_set = hdmi_bridge_mode_set,
+		.destroy = hdmi_bridge_destroy,
+};
+
+
+/* initialize bridge */
+struct drm_bridge *hdmi_bridge_init(struct hdmi *hdmi)
+{
+	struct drm_bridge *bridge = NULL;
+	struct hdmi_bridge *hdmi_bridge;
+	int ret;
+
+	hdmi_bridge = kzalloc(sizeof(*hdmi_bridge), GFP_KERNEL);
+	if (!hdmi_bridge) {
+		ret = -ENOMEM;
+		goto fail;
+	}
+
+	hdmi_bridge->hdmi = hdmi_reference(hdmi);
+
+	bridge = &hdmi_bridge->base;
+
+	drm_bridge_init(hdmi->dev, bridge, &hdmi_bridge_funcs);
+
+	return bridge;
+
+fail:
+	if (bridge)
+		hdmi_bridge_destroy(bridge);
+
+	return ERR_PTR(ret);
+}
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_connector.c b/drivers/gpu/drm/msm/hdmi/hdmi_connector.c
index 7d63f5f..823eee5 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi_connector.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi_connector.c
@@ -17,14 +17,11 @@ 
 
 #include <linux/gpio.h>
 
-#include "msm_connector.h"
 #include "hdmi.h"
 
 struct hdmi_connector {
-	struct msm_connector base;
-	struct hdmi hdmi;
-	unsigned long int pixclock;
-	bool enabled;
+	struct drm_connector base;
+	struct hdmi *hdmi;
 };
 #define to_hdmi_connector(x) container_of(x, struct hdmi_connector, base)
 
@@ -90,8 +87,8 @@  error1:
 
 static int hpd_enable(struct hdmi_connector *hdmi_connector)
 {
-	struct hdmi *hdmi = &hdmi_connector->hdmi;
-	struct drm_device *dev = hdmi_connector->base.base.dev;
+	struct hdmi *hdmi = hdmi_connector->hdmi;
+	struct drm_device *dev = hdmi_connector->base.dev;
 	struct hdmi_phy *phy = hdmi->phy;
 	uint32_t hpd_ctrl;
 	int ret;
@@ -158,8 +155,8 @@  fail:
 
 static int hdp_disable(struct hdmi_connector *hdmi_connector)
 {
-	struct hdmi *hdmi = &hdmi_connector->hdmi;
-	struct drm_device *dev = hdmi_connector->base.base.dev;
+	struct hdmi *hdmi = hdmi_connector->hdmi;
+	struct drm_device *dev = hdmi_connector->base.dev;
 	int ret = 0;
 
 	/* Disable HPD interrupt */
@@ -194,9 +191,8 @@  fail:
 
 void hdmi_connector_irq(struct drm_connector *connector)
 {
-	struct msm_connector *msm_connector = to_msm_connector(connector);
-	struct hdmi_connector *hdmi_connector = to_hdmi_connector(msm_connector);
-	struct hdmi *hdmi = &hdmi_connector->hdmi;
+	struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector);
+	struct hdmi *hdmi = hdmi_connector->hdmi;
 	uint32_t hpd_int_status, hpd_int_ctrl;
 
 	/* Process HPD: */
@@ -226,9 +222,8 @@  void hdmi_connector_irq(struct drm_connector *connector)
 static enum drm_connector_status hdmi_connector_detect(
 		struct drm_connector *connector, bool force)
 {
-	struct msm_connector *msm_connector = to_msm_connector(connector);
-	struct hdmi_connector *hdmi_connector = to_hdmi_connector(msm_connector);
-	struct hdmi *hdmi = &hdmi_connector->hdmi;
+	struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector);
+	struct hdmi *hdmi = hdmi_connector->hdmi;
 	uint32_t hpd_int_status;
 	int retry = 20;
 
@@ -249,24 +244,22 @@  static enum drm_connector_status hdmi_connector_detect(
 
 static void hdmi_connector_destroy(struct drm_connector *connector)
 {
-	struct msm_connector *msm_connector = to_msm_connector(connector);
-	struct hdmi_connector *hdmi_connector = to_hdmi_connector(msm_connector);
+	struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector);
 
 	hdp_disable(hdmi_connector);
 
 	drm_sysfs_connector_remove(connector);
 	drm_connector_cleanup(connector);
 
-	hdmi_destroy(&hdmi_connector->hdmi);
+	hdmi_unreference(hdmi_connector->hdmi);
 
 	kfree(hdmi_connector);
 }
 
 static int hdmi_connector_get_modes(struct drm_connector *connector)
 {
-	struct msm_connector *msm_connector = to_msm_connector(connector);
-	struct hdmi_connector *hdmi_connector = to_hdmi_connector(msm_connector);
-	struct hdmi *hdmi = &hdmi_connector->hdmi;
+	struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector);
+	struct hdmi *hdmi = hdmi_connector->hdmi;
 	struct edid *edid;
 	uint32_t hdmi_ctrl;
 	int ret = 0;
@@ -291,14 +284,14 @@  static int hdmi_connector_get_modes(struct drm_connector *connector)
 static int hdmi_connector_mode_valid(struct drm_connector *connector,
 				 struct drm_display_mode *mode)
 {
-	struct msm_connector *msm_connector = to_msm_connector(connector);
+	struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector);
 	struct msm_drm_private *priv = connector->dev->dev_private;
 	struct msm_kms *kms = priv->kms;
 	long actual, requested;
 
 	requested = 1000 * mode->clock;
 	actual = kms->funcs->round_pixclk(kms,
-			requested, msm_connector->encoder);
+			requested, hdmi_connector->hdmi->encoder);
 
 	DBG("requested=%ld, actual=%ld", requested, actual);
 
@@ -308,6 +301,13 @@  static int hdmi_connector_mode_valid(struct drm_connector *connector,
 	return 0;
 }
 
+static struct drm_encoder *
+hdmi_connector_best_encoder(struct drm_connector *connector)
+{
+	struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector);
+	return hdmi_connector->hdmi->encoder;
+}
+
 static const struct drm_connector_funcs hdmi_connector_funcs = {
 	.dpms = drm_helper_connector_dpms,
 	.detect = hdmi_connector_detect,
@@ -318,101 +318,11 @@  static const struct drm_connector_funcs hdmi_connector_funcs = {
 static const struct drm_connector_helper_funcs hdmi_connector_helper_funcs = {
 	.get_modes = hdmi_connector_get_modes,
 	.mode_valid = hdmi_connector_mode_valid,
-	.best_encoder = msm_connector_attached_encoder,
-};
-
-static void hdmi_connector_dpms(struct msm_connector *msm_connector, int mode)
-{
-	struct hdmi_connector *hdmi_connector = to_hdmi_connector(msm_connector);
-	struct hdmi *hdmi = &hdmi_connector->hdmi;
-	struct hdmi_phy *phy = hdmi->phy;
-	bool enabled = (mode == DRM_MODE_DPMS_ON);
-
-	DBG("mode=%d", mode);
-
-	if (enabled == hdmi_connector->enabled)
-		return;
-
-	if (enabled) {
-		phy->funcs->powerup(phy, hdmi_connector->pixclock);
-		hdmi_set_mode(hdmi, true);
-	} else {
-		hdmi_set_mode(hdmi, false);
-		phy->funcs->powerdown(phy);
-	}
-
-	hdmi_connector->enabled = enabled;
-}
-
-static void hdmi_connector_mode_set(struct msm_connector *msm_connector,
-		struct drm_display_mode *mode)
-{
-	struct hdmi_connector *hdmi_connector = to_hdmi_connector(msm_connector);
-	struct hdmi *hdmi = &hdmi_connector->hdmi;
-	int hstart, hend, vstart, vend;
-	uint32_t frame_ctrl;
-
-	hdmi_connector->pixclock = mode->clock * 1000;
-
-	hdmi->hdmi_mode = drm_match_cea_mode(mode) > 1;
-
-	hstart = mode->htotal - mode->hsync_start;
-	hend   = mode->htotal - mode->hsync_start + mode->hdisplay;
-
-	vstart = mode->vtotal - mode->vsync_start - 1;
-	vend   = mode->vtotal - mode->vsync_start + mode->vdisplay - 1;
-
-	DBG("htotal=%d, vtotal=%d, hstart=%d, hend=%d, vstart=%d, vend=%d",
-			mode->htotal, mode->vtotal, hstart, hend, vstart, vend);
-
-	hdmi_write(hdmi, REG_HDMI_TOTAL,
-			HDMI_TOTAL_H_TOTAL(mode->htotal - 1) |
-			HDMI_TOTAL_V_TOTAL(mode->vtotal - 1));
-
-	hdmi_write(hdmi, REG_HDMI_ACTIVE_HSYNC,
-			HDMI_ACTIVE_HSYNC_START(hstart) |
-			HDMI_ACTIVE_HSYNC_END(hend));
-	hdmi_write(hdmi, REG_HDMI_ACTIVE_VSYNC,
-			HDMI_ACTIVE_VSYNC_START(vstart) |
-			HDMI_ACTIVE_VSYNC_END(vend));
-
-	if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
-		hdmi_write(hdmi, REG_HDMI_VSYNC_TOTAL_F2,
-				HDMI_VSYNC_TOTAL_F2_V_TOTAL(mode->vtotal));
-		hdmi_write(hdmi, REG_HDMI_VSYNC_ACTIVE_F2,
-				HDMI_VSYNC_ACTIVE_F2_START(vstart + 1) |
-				HDMI_VSYNC_ACTIVE_F2_END(vend + 1));
-	} else {
-		hdmi_write(hdmi, REG_HDMI_VSYNC_TOTAL_F2,
-				HDMI_VSYNC_TOTAL_F2_V_TOTAL(0));
-		hdmi_write(hdmi, REG_HDMI_VSYNC_ACTIVE_F2,
-				HDMI_VSYNC_ACTIVE_F2_START(0) |
-				HDMI_VSYNC_ACTIVE_F2_END(0));
-	}
-
-	frame_ctrl = 0;
-	if (mode->flags & DRM_MODE_FLAG_NHSYNC)
-		frame_ctrl |= HDMI_FRAME_CTRL_HSYNC_LOW;
-	if (mode->flags & DRM_MODE_FLAG_NVSYNC)
-		frame_ctrl |= HDMI_FRAME_CTRL_VSYNC_LOW;
-	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
-		frame_ctrl |= HDMI_FRAME_CTRL_INTERLACED_EN;
-	DBG("frame_ctrl=%08x", frame_ctrl);
-	hdmi_write(hdmi, REG_HDMI_FRAME_CTRL, frame_ctrl);
-
-	// TODO until we have audio, this might be safest:
-	if (hdmi->hdmi_mode)
-		hdmi_write(hdmi, REG_HDMI_GC, HDMI_GC_MUTE);
-}
-
-static const struct msm_connector_funcs msm_connector_funcs = {
-		.dpms = hdmi_connector_dpms,
-		.mode_set = hdmi_connector_mode_set,
+	.best_encoder = hdmi_connector_best_encoder,
 };
 
 /* initialize connector */
-struct drm_connector *hdmi_connector_init(struct drm_device *dev,
-		struct drm_encoder *encoder)
+struct drm_connector *hdmi_connector_init(struct hdmi *hdmi)
 {
 	struct drm_connector *connector = NULL;
 	struct hdmi_connector *hdmi_connector;
@@ -424,11 +334,11 @@  struct drm_connector *hdmi_connector_init(struct drm_device *dev,
 		goto fail;
 	}
 
-	connector = &hdmi_connector->base.base;
+	hdmi_connector->hdmi = hdmi_reference(hdmi);
+
+	connector = &hdmi_connector->base;
 
-	msm_connector_init(&hdmi_connector->base,
-			&msm_connector_funcs, encoder);
-	drm_connector_init(dev, connector, &hdmi_connector_funcs,
+	drm_connector_init(hdmi->dev, connector, &hdmi_connector_funcs,
 			DRM_MODE_CONNECTOR_HDMIA);
 	drm_connector_helper_add(connector, &hdmi_connector_helper_funcs);
 
@@ -439,17 +349,13 @@  struct drm_connector *hdmi_connector_init(struct drm_device *dev,
 
 	drm_sysfs_connector_add(connector);
 
-	ret = hdmi_init(&hdmi_connector->hdmi, dev, connector);
-	if (ret)
-		goto fail;
-
 	ret = hpd_enable(hdmi_connector);
 	if (ret) {
-		dev_err(dev->dev, "failed to enable HPD: %d\n", ret);
+		dev_err(hdmi->dev->dev, "failed to enable HPD: %d\n", ret);
 		goto fail;
 	}
 
-	drm_mode_connector_attach_encoder(connector, encoder);
+	drm_mode_connector_attach_encoder(connector, hdmi->encoder);
 
 	return connector;
 
diff --git a/drivers/gpu/drm/msm/mdp4/mdp4_dtv_encoder.c b/drivers/gpu/drm/msm/mdp4/mdp4_dtv_encoder.c
index 06d49e3..5e0dcae 100644
--- a/drivers/gpu/drm/msm/mdp4/mdp4_dtv_encoder.c
+++ b/drivers/gpu/drm/msm/mdp4/mdp4_dtv_encoder.c
@@ -18,7 +18,6 @@ 
 #include <mach/clk.h>
 
 #include "mdp4_kms.h"
-#include "msm_connector.h"
 
 #include "drm_crtc.h"
 #include "drm_crtc_helper.h"
@@ -101,7 +100,6 @@  static void mdp4_dtv_encoder_dpms(struct drm_encoder *encoder, int mode)
 {
 	struct drm_device *dev = encoder->dev;
 	struct mdp4_dtv_encoder *mdp4_dtv_encoder = to_mdp4_dtv_encoder(encoder);
-	struct msm_connector *msm_connector = get_connector(encoder);
 	struct mdp4_kms *mdp4_kms = get_kms(encoder);
 	bool enabled = (mode == DRM_MODE_DPMS_ON);
 
@@ -116,9 +114,6 @@  static void mdp4_dtv_encoder_dpms(struct drm_encoder *encoder, int mode)
 
 		bs_set(mdp4_dtv_encoder, 1);
 
-		if (msm_connector)
-			msm_connector->funcs->dpms(msm_connector, mode);
-
 		DBG("setting src_clk=%lu", pc);
 
 		ret = clk_set_rate(mdp4_dtv_encoder->src_clk, pc);
@@ -150,9 +145,6 @@  static void mdp4_dtv_encoder_dpms(struct drm_encoder *encoder, int mode)
 		clk_disable_unprepare(mdp4_dtv_encoder->hdmi_clk);
 		clk_disable_unprepare(mdp4_dtv_encoder->mdp_clk);
 
-		if (msm_connector)
-			msm_connector->funcs->dpms(msm_connector, mode);
-
 		bs_set(mdp4_dtv_encoder, 0);
 	}
 
@@ -171,7 +163,6 @@  static void mdp4_dtv_encoder_mode_set(struct drm_encoder *encoder,
 		struct drm_display_mode *adjusted_mode)
 {
 	struct mdp4_dtv_encoder *mdp4_dtv_encoder = to_mdp4_dtv_encoder(encoder);
-	struct msm_connector *msm_connector = get_connector(encoder);
 	struct mdp4_kms *mdp4_kms = get_kms(encoder);
 	uint32_t dtv_hsync_skew, vsync_period, vsync_len, ctrl_pol;
 	uint32_t display_v_start, display_v_end;
@@ -230,9 +221,6 @@  static void mdp4_dtv_encoder_mode_set(struct drm_encoder *encoder,
 			MDP4_DTV_ACTIVE_HCTL_END(0));
 	mdp4_write(mdp4_kms, REG_MDP4_DTV_ACTIVE_VSTART, 0);
 	mdp4_write(mdp4_kms, REG_MDP4_DTV_ACTIVE_VEND, 0);
-
-	if (msm_connector)
-		msm_connector->funcs->mode_set(msm_connector, mode);
 }
 
 static void mdp4_dtv_encoder_prepare(struct drm_encoder *encoder)
diff --git a/drivers/gpu/drm/msm/mdp4/mdp4_kms.c b/drivers/gpu/drm/msm/mdp4/mdp4_kms.c
index 960cd89..5db5bba 100644
--- a/drivers/gpu/drm/msm/mdp4/mdp4_kms.c
+++ b/drivers/gpu/drm/msm/mdp4/mdp4_kms.c
@@ -191,7 +191,6 @@  static int modeset_init(struct mdp4_kms *mdp4_kms)
 	struct drm_plane *plane;
 	struct drm_crtc *crtc;
 	struct drm_encoder *encoder;
-	struct drm_connector *connector;
 	int ret;
 
 	/*
@@ -224,13 +223,11 @@  static int modeset_init(struct mdp4_kms *mdp4_kms)
 	encoder->possible_crtcs = 0x1;     /* DTV can be hooked to DMA_E */
 	priv->encoders[priv->num_encoders++] = encoder;
 
-	connector = hdmi_connector_init(dev, encoder);
-	if (IS_ERR(connector)) {
-		dev_err(dev->dev, "failed to construct HDMI connector\n");
-		ret = PTR_ERR(connector);
+	ret = hdmi_init(dev, encoder);
+	if (ret) {
+		dev_err(dev->dev, "failed to initialize HDMI\n");
 		goto fail;
 	}
-	priv->connectors[priv->num_connectors++] = connector;
 
 	return 0;
 
diff --git a/drivers/gpu/drm/msm/msm_connector.c b/drivers/gpu/drm/msm/msm_connector.c
deleted file mode 100644
index aeea887..0000000
--- a/drivers/gpu/drm/msm/msm_connector.c
+++ /dev/null
@@ -1,34 +0,0 @@ 
-/*
- * Copyright (C) 2013 Red Hat
- * Author: Rob Clark <robdclark@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "msm_drv.h"
-#include "msm_connector.h"
-
-void msm_connector_init(struct msm_connector *connector,
-		const struct msm_connector_funcs *funcs,
-		struct drm_encoder *encoder)
-{
-	connector->funcs = funcs;
-	connector->encoder = encoder;
-}
-
-struct drm_encoder *msm_connector_attached_encoder(
-		struct drm_connector *connector)
-{
-	struct msm_connector *msm_connector = to_msm_connector(connector);
-	return msm_connector->encoder;
-}
diff --git a/drivers/gpu/drm/msm/msm_connector.h b/drivers/gpu/drm/msm/msm_connector.h
deleted file mode 100644
index 0b41866..0000000
--- a/drivers/gpu/drm/msm/msm_connector.h
+++ /dev/null
@@ -1,68 +0,0 @@ 
-/*
- * Copyright (C) 2013 Red Hat
- * Author: Rob Clark <robdclark@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __MSM_CONNECTOR_H__
-#define __MSM_CONNECTOR_H__
-
-#include "msm_drv.h"
-
-/*
- * Base class for MSM connectors.  Typically a connector is a bit more
- * passive.  But with the split between (for example) DTV within MDP4,
- * and HDMI encoder, we really need two parts to an encoder.  Instead
- * what we do is have the part external to the display controller block
- * in the connector, which is called from the encoder to delegate the
- * appropriate parts of modeset.
- */
-
-struct msm_connector;
-
-struct msm_connector_funcs {
-	void (*dpms)(struct msm_connector *connector, int mode);
-	void (*mode_set)(struct msm_connector *connector,
-			struct drm_display_mode *mode);
-};
-
-struct msm_connector {
-	struct drm_connector base;
-	struct drm_encoder *encoder;
-	const struct msm_connector_funcs *funcs;
-};
-#define to_msm_connector(x) container_of(x, struct msm_connector, base)
-
-void msm_connector_init(struct msm_connector *connector,
-		const struct msm_connector_funcs *funcs,
-		struct drm_encoder *encoder);
-
-struct drm_encoder *msm_connector_attached_encoder(
-		struct drm_connector *connector);
-
-static inline struct msm_connector *get_connector(struct drm_encoder *encoder)
-{
-	struct msm_drm_private *priv = encoder->dev->dev_private;
-	int i;
-
-	for (i = 0; i < priv->num_connectors; i++) {
-		struct drm_connector *connector = priv->connectors[i];
-		if (msm_connector_attached_encoder(connector) == encoder)
-			return to_msm_connector(connector);
-	}
-
-	return NULL;
-}
-
-#endif /* __MSM_CONNECTOR_H__ */
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index 34c36b2..80d7509 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -83,6 +83,9 @@  struct msm_drm_private {
 	unsigned int num_encoders;
 	struct drm_encoder *encoders[8];
 
+	unsigned int num_bridges;
+	struct drm_bridge *bridges[8];
+
 	unsigned int num_connectors;
 	struct drm_connector *connectors[8];
 };
@@ -170,8 +173,7 @@  struct drm_framebuffer *msm_framebuffer_create(struct drm_device *dev,
 
 struct drm_fb_helper *msm_fbdev_init(struct drm_device *dev);
 
-struct drm_connector *hdmi_connector_init(struct drm_device *dev,
-		struct drm_encoder *encoder);
+int hdmi_init(struct drm_device *dev, struct drm_encoder *encoder);
 void __init hdmi_register(void);
 void __exit hdmi_unregister(void);