Browse Source

Merge branch 'audio_display-ti-linux-4.19.y' of git.ti.com:~jyrisarha/ti-linux-kernel/jyrisarhas-audio-video-linux-feature-tree into ti-linux-4.19.y

TI-Feature: audio-display
TI-Tree: git@git.ti.com:~jyrisarha/ti-linux-kernel/jyrisarhas-audio-video-linux-feature-tree.git
TI-Branch: audio_display-ti-linux-4.19.y

* 'audio_display-ti-linux-4.19.y' of git.ti.com:~jyrisarha/ti-linux-kernel/jyrisarhas-audio-video-linux-feature-tree: (124 commits)
  drm/omap: fix incorrect union usage
  drm/omap: populate DSI platform bus earlier
  drm/omap: fix bus_flags for panel-dpi
  drm/omap: dsi: Fix missing of_platform_depopulate()
  drm/omap: Move DISPC runtime PM handling to omapdrm
  drm/omap: dsi: Ensure the device is active during probe
  drm/omap: hdmi4: Ensure the device is active during bind
  drm/omap: Populate DSS children in omapdss driver
  drm/omap: fix use of freed memory
  drm/omap: Replace drm_dev_unref with drm_dev_put
  drm/omap: Replace drm_gem_object_unreference_unlocked with put function
  drm/omap: Replace drm_gem_object_{un/reference} with put,get functions
  drm/omap: Substitute format_is_yuv() with format->is_yuv
  drm/omap: partial workaround for DRA7xx DMM errata i878
  drm/omap: dmm_tiler: Fix interrupt request/free sequence during probe/remove
  drm/omap: dmm_tiler: No need to check if irq is valid in omap_dmm_remove
  drm/omap: remove set but not used variable 'frame_height'
  drm/omap: Use ERR_CAST directly instead of ERR_PTR(PTR_ERR())
  drm/omap: remove unused header tcm-sita.h
  drm/omap: Don't call .set_timings() operation recursively
  ...

Signed-off-by: LCPD Auto Merger <lcpd_integration@list.ti.com>
LCPD Auto Merger 7 years ago
parent
commit
bb18216001
49 changed files with 2583 additions and 4143 deletions
  1. 53 58
      arch/arm/mach-omap2/display.c
  2. 14 125
      drivers/gpu/drm/omapdrm/displays/connector-analog-tv.c
  3. 22 153
      drivers/gpu/drm/omapdrm/displays/connector-dvi.c
  4. 45 232
      drivers/gpu/drm/omapdrm/displays/connector-hdmi.c
  5. 24 108
      drivers/gpu/drm/omapdrm/displays/encoder-opa362.c
  6. 40 147
      drivers/gpu/drm/omapdrm/displays/encoder-tfp410.c
  7. 36 161
      drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c
  8. 16 73
      drivers/gpu/drm/omapdrm/displays/panel-dpi.c
  9. 108 139
      drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c
  10. 24 79
      drivers/gpu/drm/omapdrm/displays/panel-lgphilips-lb035q02.c
  11. 28 118
      drivers/gpu/drm/omapdrm/displays/panel-nec-nl8048hl11.c
  12. 22 79
      drivers/gpu/drm/omapdrm/displays/panel-sharp-ls037v7dw01.c
  13. 43 122
      drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c
  14. 22 80
      drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c
  15. 41 151
      drivers/gpu/drm/omapdrm/displays/panel-tpo-td043mtea1.c
  16. 205 12
      drivers/gpu/drm/omapdrm/dss/base.c
  17. 2 24
      drivers/gpu/drm/omapdrm/dss/core.c
  18. 23 38
      drivers/gpu/drm/omapdrm/dss/dispc.c
  19. 10 124
      drivers/gpu/drm/omapdrm/dss/display.c
  20. 78 114
      drivers/gpu/drm/omapdrm/dss/dpi.c
  21. 268 323
      drivers/gpu/drm/omapdrm/dss/dsi.c
  22. 22 25
      drivers/gpu/drm/omapdrm/dss/dss-of.c
  23. 38 20
      drivers/gpu/drm/omapdrm/dss/dss.c
  24. 4 7
      drivers/gpu/drm/omapdrm/dss/dss.h
  25. 4 4
      drivers/gpu/drm/omapdrm/dss/hdmi.h
  26. 176 206
      drivers/gpu/drm/omapdrm/dss/hdmi4.c
  27. 162 199
      drivers/gpu/drm/omapdrm/dss/hdmi5.c
  28. 3 3
      drivers/gpu/drm/omapdrm/dss/hdmi5_core.c
  29. 4 4
      drivers/gpu/drm/omapdrm/dss/hdmi_wp.c
  30. 96 210
      drivers/gpu/drm/omapdrm/dss/omapdss.h
  31. 33 175
      drivers/gpu/drm/omapdrm/dss/output.c
  32. 63 86
      drivers/gpu/drm/omapdrm/dss/sdi.c
  33. 124 174
      drivers/gpu/drm/omapdrm/dss/venc.c
  34. 241 133
      drivers/gpu/drm/omapdrm/omap_connector.c
  35. 5 2
      drivers/gpu/drm/omapdrm/omap_connector.h
  36. 25 92
      drivers/gpu/drm/omapdrm/omap_crtc.c
  37. 4 2
      drivers/gpu/drm/omapdrm/omap_crtc.h
  38. 7 0
      drivers/gpu/drm/omapdrm/omap_dmm_priv.h
  39. 168 22
      drivers/gpu/drm/omapdrm/omap_dmm_tiler.c
  40. 156 148
      drivers/gpu/drm/omapdrm/omap_drv.c
  41. 11 8
      drivers/gpu/drm/omapdrm/omap_drv.h
  42. 102 57
      drivers/gpu/drm/omapdrm/omap_encoder.c
  43. 2 4
      drivers/gpu/drm/omapdrm/omap_encoder.h
  44. 1 1
      drivers/gpu/drm/omapdrm/omap_fb.c
  45. 3 3
      drivers/gpu/drm/omapdrm/omap_fbdev.c
  46. 2 2
      drivers/gpu/drm/omapdrm/omap_gem.c
  47. 1 1
      drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c
  48. 2 2
      drivers/gpu/drm/omapdrm/omap_irq.c
  49. 0 93
      drivers/gpu/drm/omapdrm/tcm-sita.h

+ 53 - 58
arch/arm/mach-omap2/display.c

@@ -209,11 +209,61 @@ static int __init omapdss_init_fbdev(void)
 
 	return 0;
 }
-#else
-static inline int omapdss_init_fbdev(void)
+
+static const char * const omapdss_compat_names[] __initconst = {
+	"ti,omap2-dss",
+	"ti,omap3-dss",
+	"ti,omap4-dss",
+	"ti,omap5-dss",
+	"ti,dra7-dss",
+};
+
+static struct device_node * __init omapdss_find_dss_of_node(void)
 {
-	return 0;
+	struct device_node *node;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(omapdss_compat_names); ++i) {
+		node = of_find_compatible_node(NULL, NULL,
+			omapdss_compat_names[i]);
+		if (node)
+			return node;
+	}
+
+	return NULL;
 }
+
+static int __init omapdss_init_of(void)
+{
+	int r;
+	struct device_node *node;
+	struct platform_device *pdev;
+
+	/* only create dss helper devices if dss is enabled in the .dts */
+
+	node = omapdss_find_dss_of_node();
+	if (!node)
+		return 0;
+
+	if (!of_device_is_available(node))
+		return 0;
+
+	pdev = of_find_device_by_node(node);
+
+	if (!pdev) {
+		pr_err("Unable to find DSS platform device\n");
+		return -ENODEV;
+	}
+
+	r = of_platform_populate(node, NULL, NULL, &pdev->dev);
+	if (r) {
+		pr_err("Unable to populate DSS submodule devices\n");
+		return r;
+	}
+
+	return omapdss_init_fbdev();
+}
+omap_device_initcall(omapdss_init_of);
 #endif /* CONFIG_FB_OMAP2 */
 
 static void dispc_disable_outputs(void)
@@ -361,58 +411,3 @@ int omap_dss_reset(struct omap_hwmod *oh)
 
 	return r;
 }
-
-static const char * const omapdss_compat_names[] __initconst = {
-	"ti,omap2-dss",
-	"ti,omap3-dss",
-	"ti,omap4-dss",
-	"ti,omap5-dss",
-	"ti,dra7-dss",
-};
-
-static struct device_node * __init omapdss_find_dss_of_node(void)
-{
-	struct device_node *node;
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(omapdss_compat_names); ++i) {
-		node = of_find_compatible_node(NULL, NULL,
-			omapdss_compat_names[i]);
-		if (node)
-			return node;
-	}
-
-	return NULL;
-}
-
-static int __init omapdss_init_of(void)
-{
-	int r;
-	struct device_node *node;
-	struct platform_device *pdev;
-
-	/* only create dss helper devices if dss is enabled in the .dts */
-
-	node = omapdss_find_dss_of_node();
-	if (!node)
-		return 0;
-
-	if (!of_device_is_available(node))
-		return 0;
-
-	pdev = of_find_device_by_node(node);
-
-	if (!pdev) {
-		pr_err("Unable to find DSS platform device\n");
-		return -ENODEV;
-	}
-
-	r = of_platform_populate(node, NULL, NULL, &pdev->dev);
-	if (r) {
-		pr_err("Unable to populate DSS submodule devices\n");
-		return r;
-	}
-
-	return omapdss_init_fbdev();
-}
-omap_device_initcall(omapdss_init_of);

+ 14 - 125
drivers/gpu/drm/omapdrm/displays/connector-analog-tv.c

@@ -18,77 +18,27 @@
 
 struct panel_drv_data {
 	struct omap_dss_device dssdev;
-	struct omap_dss_device *in;
 
 	struct device *dev;
-
-	struct videomode vm;
-};
-
-static const struct videomode tvc_pal_vm = {
-	.hactive	= 720,
-	.vactive	= 574,
-	.pixelclock	= 13500000,
-	.hsync_len	= 64,
-	.hfront_porch	= 12,
-	.hback_porch	= 68,
-	.vsync_len	= 5,
-	.vfront_porch	= 5,
-	.vback_porch	= 41,
-
-	.flags		= DISPLAY_FLAGS_INTERLACED | DISPLAY_FLAGS_HSYNC_LOW |
-			  DISPLAY_FLAGS_VSYNC_LOW,
 };
 
 #define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev)
 
-static int tvc_connect(struct omap_dss_device *dssdev)
+static int tvc_connect(struct omap_dss_device *src,
+		       struct omap_dss_device *dst)
 {
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in;
-	int r;
-
-	dev_dbg(ddata->dev, "connect\n");
-
-	if (omapdss_device_is_connected(dssdev))
-		return 0;
-
-	in = omapdss_of_find_source_for_first_ep(ddata->dev->of_node);
-	if (IS_ERR(in)) {
-		dev_err(ddata->dev, "failed to find video source\n");
-		return PTR_ERR(in);
-	}
-
-	r = in->ops.atv->connect(in, dssdev);
-	if (r) {
-		omap_dss_put_device(in);
-		return r;
-	}
-
-	ddata->in = in;
 	return 0;
 }
 
-static void tvc_disconnect(struct omap_dss_device *dssdev)
+static void tvc_disconnect(struct omap_dss_device *src,
+			   struct omap_dss_device *dst)
 {
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
-
-	dev_dbg(ddata->dev, "disconnect\n");
-
-	if (!omapdss_device_is_connected(dssdev))
-		return;
-
-	in->ops.atv->disconnect(in, dssdev);
-
-	omap_dss_put_device(in);
-	ddata->in = NULL;
 }
 
 static int tvc_enable(struct omap_dss_device *dssdev)
 {
 	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
+	struct omap_dss_device *src = dssdev->src;
 	int r;
 
 	dev_dbg(ddata->dev, "enable\n");
@@ -99,9 +49,7 @@ static int tvc_enable(struct omap_dss_device *dssdev)
 	if (omapdss_device_is_enabled(dssdev))
 		return 0;
 
-	in->ops.atv->set_timings(in, &ddata->vm);
-
-	r = in->ops.atv->enable(in);
+	r = src->ops->enable(src);
 	if (r)
 		return r;
 
@@ -113,83 +61,30 @@ static int tvc_enable(struct omap_dss_device *dssdev)
 static void tvc_disable(struct omap_dss_device *dssdev)
 {
 	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
+	struct omap_dss_device *src = dssdev->src;
 
 	dev_dbg(ddata->dev, "disable\n");
 
 	if (!omapdss_device_is_enabled(dssdev))
 		return;
 
-	in->ops.atv->disable(in);
+	src->ops->disable(src);
 
 	dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
 }
 
-static void tvc_set_timings(struct omap_dss_device *dssdev,
-			    struct videomode *vm)
-{
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
-
-	ddata->vm = *vm;
-	dssdev->panel.vm = *vm;
-
-	in->ops.atv->set_timings(in, vm);
-}
-
-static void tvc_get_timings(struct omap_dss_device *dssdev,
-			    struct videomode *vm)
-{
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-
-	*vm = ddata->vm;
-}
-
-static int tvc_check_timings(struct omap_dss_device *dssdev,
-			     struct videomode *vm)
-{
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
-
-	return in->ops.atv->check_timings(in, vm);
-}
-
-static u32 tvc_get_wss(struct omap_dss_device *dssdev)
-{
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
-
-	return in->ops.atv->get_wss(in);
-}
-
-static int tvc_set_wss(struct omap_dss_device *dssdev, u32 wss)
-{
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
-
-	return in->ops.atv->set_wss(in, wss);
-}
-
-static struct omap_dss_driver tvc_driver = {
+static const struct omap_dss_device_ops tvc_ops = {
 	.connect		= tvc_connect,
 	.disconnect		= tvc_disconnect,
 
 	.enable			= tvc_enable,
 	.disable		= tvc_disable,
-
-	.set_timings		= tvc_set_timings,
-	.get_timings		= tvc_get_timings,
-	.check_timings		= tvc_check_timings,
-
-	.get_wss		= tvc_get_wss,
-	.set_wss		= tvc_set_wss,
 };
 
 static int tvc_probe(struct platform_device *pdev)
 {
 	struct panel_drv_data *ddata;
 	struct omap_dss_device *dssdev;
-	int r;
 
 	ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
 	if (!ddata)
@@ -198,20 +93,15 @@ static int tvc_probe(struct platform_device *pdev)
 	platform_set_drvdata(pdev, ddata);
 	ddata->dev = &pdev->dev;
 
-	ddata->vm = tvc_pal_vm;
-
 	dssdev = &ddata->dssdev;
-	dssdev->driver = &tvc_driver;
+	dssdev->ops = &tvc_ops;
 	dssdev->dev = &pdev->dev;
 	dssdev->type = OMAP_DISPLAY_TYPE_VENC;
 	dssdev->owner = THIS_MODULE;
-	dssdev->panel.vm = tvc_pal_vm;
+	dssdev->of_ports = BIT(0);
 
-	r = omapdss_register_display(dssdev);
-	if (r) {
-		dev_err(&pdev->dev, "Failed to register panel\n");
-		return r;
-	}
+	omapdss_display_init(dssdev);
+	omapdss_device_register(dssdev);
 
 	return 0;
 }
@@ -221,10 +111,9 @@ static int __exit tvc_remove(struct platform_device *pdev)
 	struct panel_drv_data *ddata = platform_get_drvdata(pdev);
 	struct omap_dss_device *dssdev = &ddata->dssdev;
 
-	omapdss_unregister_display(&ddata->dssdev);
+	omapdss_device_unregister(&ddata->dssdev);
 
 	tvc_disable(dssdev);
-	tvc_disconnect(dssdev);
 
 	return 0;
 }

+ 22 - 153
drivers/gpu/drm/omapdrm/displays/connector-dvi.c

@@ -19,30 +19,8 @@
 
 #include "../dss/omapdss.h"
 
-static const struct videomode dvic_default_vm = {
-	.hactive	= 640,
-	.vactive	= 480,
-
-	.pixelclock	= 23500000,
-
-	.hfront_porch	= 48,
-	.hsync_len	= 32,
-	.hback_porch	= 80,
-
-	.vfront_porch	= 3,
-	.vsync_len	= 4,
-	.vback_porch	= 7,
-
-	.flags		= DISPLAY_FLAGS_HSYNC_HIGH | DISPLAY_FLAGS_VSYNC_HIGH |
-			  DISPLAY_FLAGS_SYNC_NEGEDGE | DISPLAY_FLAGS_DE_HIGH |
-			  DISPLAY_FLAGS_PIXDATA_POSEDGE,
-};
-
 struct panel_drv_data {
 	struct omap_dss_device dssdev;
-	struct omap_dss_device *in;
-
-	struct videomode vm;
 
 	struct i2c_adapter *i2c_adapter;
 
@@ -57,49 +35,20 @@ struct panel_drv_data {
 
 #define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev)
 
-static int dvic_connect(struct omap_dss_device *dssdev)
+static int dvic_connect(struct omap_dss_device *src,
+			struct omap_dss_device *dst)
 {
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in;
-	int r;
-
-	if (omapdss_device_is_connected(dssdev))
-		return 0;
-
-	in = omapdss_of_find_source_for_first_ep(dssdev->dev->of_node);
-	if (IS_ERR(in)) {
-		dev_err(dssdev->dev, "failed to find video source\n");
-		return PTR_ERR(in);
-	}
-
-	r = in->ops.dvi->connect(in, dssdev);
-	if (r) {
-		omap_dss_put_device(in);
-		return r;
-	}
-
-	ddata->in = in;
 	return 0;
 }
 
-static void dvic_disconnect(struct omap_dss_device *dssdev)
+static void dvic_disconnect(struct omap_dss_device *src,
+			    struct omap_dss_device *dst)
 {
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
-
-	if (!omapdss_device_is_connected(dssdev))
-		return;
-
-	in->ops.dvi->disconnect(in, dssdev);
-
-	omap_dss_put_device(in);
-	ddata->in = NULL;
 }
 
 static int dvic_enable(struct omap_dss_device *dssdev)
 {
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
+	struct omap_dss_device *src = dssdev->src;
 	int r;
 
 	if (!omapdss_device_is_connected(dssdev))
@@ -108,9 +57,7 @@ static int dvic_enable(struct omap_dss_device *dssdev)
 	if (omapdss_device_is_enabled(dssdev))
 		return 0;
 
-	in->ops.dvi->set_timings(in, &ddata->vm);
-
-	r = in->ops.dvi->enable(in);
+	r = src->ops->enable(src);
 	if (r)
 		return r;
 
@@ -121,46 +68,16 @@ static int dvic_enable(struct omap_dss_device *dssdev)
 
 static void dvic_disable(struct omap_dss_device *dssdev)
 {
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
+	struct omap_dss_device *src = dssdev->src;
 
 	if (!omapdss_device_is_enabled(dssdev))
 		return;
 
-	in->ops.dvi->disable(in);
+	src->ops->disable(src);
 
 	dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
 }
 
-static void dvic_set_timings(struct omap_dss_device *dssdev,
-			     struct videomode *vm)
-{
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
-
-	ddata->vm = *vm;
-	dssdev->panel.vm = *vm;
-
-	in->ops.dvi->set_timings(in, vm);
-}
-
-static void dvic_get_timings(struct omap_dss_device *dssdev,
-			     struct videomode *vm)
-{
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-
-	*vm = ddata->vm;
-}
-
-static int dvic_check_timings(struct omap_dss_device *dssdev,
-			      struct videomode *vm)
-{
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
-
-	return in->ops.dvi->check_timings(in, vm);
-}
-
 static int dvic_ddc_read(struct i2c_adapter *adapter,
 		unsigned char *buf, u16 count, u8 offset)
 {
@@ -198,12 +115,6 @@ static int dvic_read_edid(struct omap_dss_device *dssdev,
 	struct panel_drv_data *ddata = to_panel_data(dssdev);
 	int r, l, bytes_read;
 
-	if (ddata->hpd_gpio && !gpiod_get_value_cansleep(ddata->hpd_gpio))
-		return -ENODEV;
-
-	if (!ddata->i2c_adapter)
-		return -ENODEV;
-
 	l = min(EDID_LENGTH, len);
 	r = dvic_ddc_read(ddata->i2c_adapter, edid, l, 0);
 	if (r)
@@ -243,78 +154,41 @@ static bool dvic_detect(struct omap_dss_device *dssdev)
 	return r == 0;
 }
 
-static int dvic_register_hpd_cb(struct omap_dss_device *dssdev,
+static void dvic_register_hpd_cb(struct omap_dss_device *dssdev,
 				 void (*cb)(void *cb_data,
 					    enum drm_connector_status status),
 				 void *cb_data)
 {
 	struct panel_drv_data *ddata = to_panel_data(dssdev);
 
-	if (!ddata->hpd_gpio)
-		return -ENOTSUPP;
-
 	mutex_lock(&ddata->hpd_lock);
 	ddata->hpd_cb = cb;
 	ddata->hpd_cb_data = cb_data;
 	mutex_unlock(&ddata->hpd_lock);
-	return 0;
 }
 
 static void dvic_unregister_hpd_cb(struct omap_dss_device *dssdev)
 {
 	struct panel_drv_data *ddata = to_panel_data(dssdev);
 
-	if (!ddata->hpd_gpio)
-		return;
-
 	mutex_lock(&ddata->hpd_lock);
 	ddata->hpd_cb = NULL;
 	ddata->hpd_cb_data = NULL;
 	mutex_unlock(&ddata->hpd_lock);
 }
 
-static void dvic_enable_hpd(struct omap_dss_device *dssdev)
-{
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-
-	if (!ddata->hpd_gpio)
-		return;
-
-	mutex_lock(&ddata->hpd_lock);
-	ddata->hpd_enabled = true;
-	mutex_unlock(&ddata->hpd_lock);
-}
-
-static void dvic_disable_hpd(struct omap_dss_device *dssdev)
-{
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-
-	if (!ddata->hpd_gpio)
-		return;
-
-	mutex_lock(&ddata->hpd_lock);
-	ddata->hpd_enabled = false;
-	mutex_unlock(&ddata->hpd_lock);
-}
-
-static struct omap_dss_driver dvic_driver = {
+static const struct omap_dss_device_ops dvic_ops = {
 	.connect	= dvic_connect,
 	.disconnect	= dvic_disconnect,
 
 	.enable		= dvic_enable,
 	.disable	= dvic_disable,
 
-	.set_timings	= dvic_set_timings,
-	.get_timings	= dvic_get_timings,
-	.check_timings	= dvic_check_timings,
-
 	.read_edid	= dvic_read_edid,
 	.detect		= dvic_detect,
 
 	.register_hpd_cb	= dvic_register_hpd_cb,
 	.unregister_hpd_cb	= dvic_unregister_hpd_cb,
-	.enable_hpd		= dvic_enable_hpd,
-	.disable_hpd		= dvic_disable_hpd,
 };
 
 static irqreturn_t dvic_hpd_isr(int irq, void *data)
@@ -396,28 +270,24 @@ static int dvic_probe(struct platform_device *pdev)
 	if (r)
 		return r;
 
-	ddata->vm = dvic_default_vm;
-
 	dssdev = &ddata->dssdev;
-	dssdev->driver = &dvic_driver;
+	dssdev->ops = &dvic_ops;
 	dssdev->dev = &pdev->dev;
 	dssdev->type = OMAP_DISPLAY_TYPE_DVI;
 	dssdev->owner = THIS_MODULE;
-	dssdev->panel.vm = dvic_default_vm;
+	dssdev->of_ports = BIT(0);
 
-	r = omapdss_register_display(dssdev);
-	if (r) {
-		dev_err(&pdev->dev, "Failed to register panel\n");
-		goto err_reg;
-	}
-
-	return 0;
+	if (ddata->hpd_gpio)
+		dssdev->ops_flags |= OMAP_DSS_DEVICE_OP_DETECT
+				  |  OMAP_DSS_DEVICE_OP_HPD;
+	if (ddata->i2c_adapter)
+		dssdev->ops_flags |= OMAP_DSS_DEVICE_OP_DETECT
+				  |  OMAP_DSS_DEVICE_OP_EDID;
 
-err_reg:
-	i2c_put_adapter(ddata->i2c_adapter);
-	mutex_destroy(&ddata->hpd_lock);
+	omapdss_display_init(dssdev);
+	omapdss_device_register(dssdev);
 
-	return r;
+	return 0;
 }
 
 static int __exit dvic_remove(struct platform_device *pdev)
@@ -425,10 +295,9 @@ static int __exit dvic_remove(struct platform_device *pdev)
 	struct panel_drv_data *ddata = platform_get_drvdata(pdev);
 	struct omap_dss_device *dssdev = &ddata->dssdev;
 
-	omapdss_unregister_display(&ddata->dssdev);
+	omapdss_device_unregister(&ddata->dssdev);
 
 	dvic_disable(dssdev);
-	dvic_disconnect(dssdev);
 
 	i2c_put_adapter(ddata->i2c_adapter);
 

+ 45 - 232
drivers/gpu/drm/omapdrm/displays/connector-hdmi.c

@@ -10,95 +10,41 @@
  */
 
 #include <linux/gpio/consumer.h>
-#include <linux/slab.h>
 #include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/of.h>
-#include <linux/of_gpio.h>
 #include <linux/mutex.h>
-
-#include <drm/drm_edid.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
 
 #include "../dss/omapdss.h"
 
-static const struct videomode hdmic_default_vm = {
-	.hactive	= 640,
-	.vactive	= 480,
-	.pixelclock	= 25175000,
-	.hsync_len	= 96,
-	.hfront_porch	= 16,
-	.hback_porch	= 48,
-	.vsync_len	= 2,
-	.vfront_porch	= 11,
-	.vback_porch	= 31,
-
-	.flags		= DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW,
-};
-
 struct panel_drv_data {
 	struct omap_dss_device dssdev;
-	struct omap_dss_device *in;
 	void (*hpd_cb)(void *cb_data, enum drm_connector_status status);
 	void *hpd_cb_data;
-	bool hpd_enabled;
 	struct mutex hpd_lock;
 
 	struct device *dev;
 
-	struct videomode vm;
-
-	int hpd_gpio;
+	struct gpio_desc *hpd_gpio;
 };
 
 #define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev)
 
-static int hdmic_connect(struct omap_dss_device *dssdev)
+static int hdmic_connect(struct omap_dss_device *src,
+			 struct omap_dss_device *dst)
 {
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in;
-	int r;
-
-	dev_dbg(ddata->dev, "connect\n");
-
-	if (omapdss_device_is_connected(dssdev))
-		return 0;
-
-	in = omapdss_of_find_source_for_first_ep(ddata->dev->of_node);
-	if (IS_ERR(in)) {
-		dev_err(ddata->dev, "failed to find video source\n");
-		return PTR_ERR(in);
-	}
-
-	r = in->ops.hdmi->connect(in, dssdev);
-	if (r) {
-		omap_dss_put_device(in);
-		return r;
-	}
-
-	ddata->in = in;
 	return 0;
 }
 
-static void hdmic_disconnect(struct omap_dss_device *dssdev)
+static void hdmic_disconnect(struct omap_dss_device *src,
+			     struct omap_dss_device *dst)
 {
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
-
-	dev_dbg(ddata->dev, "disconnect\n");
-
-	if (!omapdss_device_is_connected(dssdev))
-		return;
-
-	in->ops.hdmi->disconnect(in, dssdev);
-
-	omap_dss_put_device(in);
-	ddata->in = NULL;
 }
 
 static int hdmic_enable(struct omap_dss_device *dssdev)
 {
 	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
+	struct omap_dss_device *src = dssdev->src;
 	int r;
 
 	dev_dbg(ddata->dev, "enable\n");
@@ -109,9 +55,7 @@ static int hdmic_enable(struct omap_dss_device *dssdev)
 	if (omapdss_device_is_enabled(dssdev))
 		return 0;
 
-	in->ops.hdmi->set_timings(in, &ddata->vm);
-
-	r = in->ops.hdmi->enable(in);
+	r = src->ops->enable(src);
 	if (r)
 		return r;
 
@@ -123,171 +67,58 @@ static int hdmic_enable(struct omap_dss_device *dssdev)
 static void hdmic_disable(struct omap_dss_device *dssdev)
 {
 	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
+	struct omap_dss_device *src = dssdev->src;
 
 	dev_dbg(ddata->dev, "disable\n");
 
 	if (!omapdss_device_is_enabled(dssdev))
 		return;
 
-	in->ops.hdmi->disable(in);
+	src->ops->disable(src);
 
 	dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
 }
 
-static void hdmic_set_timings(struct omap_dss_device *dssdev,
-			      struct videomode *vm)
-{
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
-
-	ddata->vm = *vm;
-	dssdev->panel.vm = *vm;
-
-	in->ops.hdmi->set_timings(in, vm);
-}
-
-static void hdmic_get_timings(struct omap_dss_device *dssdev,
-			      struct videomode *vm)
-{
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-
-	*vm = ddata->vm;
-}
-
-static int hdmic_check_timings(struct omap_dss_device *dssdev,
-			       struct videomode *vm)
-{
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
-
-	return in->ops.hdmi->check_timings(in, vm);
-}
-
-static int hdmic_read_edid(struct omap_dss_device *dssdev,
-		u8 *edid, int len)
-{
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
-
-	return in->ops.hdmi->read_edid(in, edid, len);
-}
-
 static bool hdmic_detect(struct omap_dss_device *dssdev)
 {
 	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
-	bool connected;
-
-	if (gpio_is_valid(ddata->hpd_gpio))
-		connected = gpio_get_value_cansleep(ddata->hpd_gpio);
-	else
-		connected = in->ops.hdmi->detect(in);
-	if (!connected && in->ops.hdmi->lost_hotplug)
-		in->ops.hdmi->lost_hotplug(in);
-	return connected;
+
+	return gpiod_get_value_cansleep(ddata->hpd_gpio);
 }
 
-static int hdmic_register_hpd_cb(struct omap_dss_device *dssdev,
-				 void (*cb)(void *cb_data,
+static void hdmic_register_hpd_cb(struct omap_dss_device *dssdev,
+				  void (*cb)(void *cb_data,
 					    enum drm_connector_status status),
-				 void *cb_data)
+				  void *cb_data)
 {
 	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
-
-	if (gpio_is_valid(ddata->hpd_gpio)) {
-		mutex_lock(&ddata->hpd_lock);
-		ddata->hpd_cb = cb;
-		ddata->hpd_cb_data = cb_data;
-		mutex_unlock(&ddata->hpd_lock);
-		return 0;
-	} else if (in->ops.hdmi->register_hpd_cb) {
-		return in->ops.hdmi->register_hpd_cb(in, cb, cb_data);
-	}
 
-	return -ENOTSUPP;
+	mutex_lock(&ddata->hpd_lock);
+	ddata->hpd_cb = cb;
+	ddata->hpd_cb_data = cb_data;
+	mutex_unlock(&ddata->hpd_lock);
 }
 
 static void hdmic_unregister_hpd_cb(struct omap_dss_device *dssdev)
 {
 	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
-
-	if (gpio_is_valid(ddata->hpd_gpio)) {
-		mutex_lock(&ddata->hpd_lock);
-		ddata->hpd_cb = NULL;
-		ddata->hpd_cb_data = NULL;
-		mutex_unlock(&ddata->hpd_lock);
-	} else if (in->ops.hdmi->unregister_hpd_cb) {
-		in->ops.hdmi->unregister_hpd_cb(in);
-	}
-}
-
-static void hdmic_enable_hpd(struct omap_dss_device *dssdev)
-{
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
-
-	if (gpio_is_valid(ddata->hpd_gpio)) {
-		mutex_lock(&ddata->hpd_lock);
-		ddata->hpd_enabled = true;
-		mutex_unlock(&ddata->hpd_lock);
-	} else if (in->ops.hdmi->enable_hpd) {
-		in->ops.hdmi->enable_hpd(in);
-	}
-}
-
-static void hdmic_disable_hpd(struct omap_dss_device *dssdev)
-{
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
-
-	if (gpio_is_valid(ddata->hpd_gpio)) {
-		mutex_lock(&ddata->hpd_lock);
-		ddata->hpd_enabled = false;
-		mutex_unlock(&ddata->hpd_lock);
-	} else if (in->ops.hdmi->disable_hpd) {
-		in->ops.hdmi->disable_hpd(in);
-	}
-}
-
-static int hdmic_set_hdmi_mode(struct omap_dss_device *dssdev, bool hdmi_mode)
-{
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
-
-	return in->ops.hdmi->set_hdmi_mode(in, hdmi_mode);
-}
-
-static int hdmic_set_infoframe(struct omap_dss_device *dssdev,
-		const struct hdmi_avi_infoframe *avi)
-{
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
 
-	return in->ops.hdmi->set_infoframe(in, avi);
+	mutex_lock(&ddata->hpd_lock);
+	ddata->hpd_cb = NULL;
+	ddata->hpd_cb_data = NULL;
+	mutex_unlock(&ddata->hpd_lock);
 }
 
-static struct omap_dss_driver hdmic_driver = {
+static const struct omap_dss_device_ops hdmic_ops = {
 	.connect		= hdmic_connect,
 	.disconnect		= hdmic_disconnect,
 
 	.enable			= hdmic_enable,
 	.disable		= hdmic_disable,
 
-	.set_timings		= hdmic_set_timings,
-	.get_timings		= hdmic_get_timings,
-	.check_timings		= hdmic_check_timings,
-
-	.read_edid		= hdmic_read_edid,
 	.detect			= hdmic_detect,
 	.register_hpd_cb	= hdmic_register_hpd_cb,
 	.unregister_hpd_cb	= hdmic_unregister_hpd_cb,
-	.enable_hpd		= hdmic_enable_hpd,
-	.disable_hpd		= hdmic_disable_hpd,
-	.set_hdmi_mode		= hdmic_set_hdmi_mode,
-	.set_hdmi_infoframe	= hdmic_set_infoframe,
 };
 
 static irqreturn_t hdmic_hpd_isr(int irq, void *data)
@@ -295,7 +126,7 @@ static irqreturn_t hdmic_hpd_isr(int irq, void *data)
 	struct panel_drv_data *ddata = data;
 
 	mutex_lock(&ddata->hpd_lock);
-	if (ddata->hpd_enabled && ddata->hpd_cb) {
+	if (ddata->hpd_cb) {
 		enum drm_connector_status status;
 
 		if (hdmic_detect(&ddata->dssdev))
@@ -310,26 +141,11 @@ static irqreturn_t hdmic_hpd_isr(int irq, void *data)
 	return IRQ_HANDLED;
 }
 
-static int hdmic_probe_of(struct platform_device *pdev)
-{
-	struct panel_drv_data *ddata = platform_get_drvdata(pdev);
-	struct device_node *node = pdev->dev.of_node;
-	int gpio;
-
-	/* HPD GPIO */
-	gpio = of_get_named_gpio(node, "hpd-gpios", 0);
-	if (gpio_is_valid(gpio))
-		ddata->hpd_gpio = gpio;
-	else
-		ddata->hpd_gpio = -ENODEV;
-
-	return 0;
-}
-
 static int hdmic_probe(struct platform_device *pdev)
 {
 	struct panel_drv_data *ddata;
 	struct omap_dss_device *dssdev;
+	struct gpio_desc *gpio;
 	int r;
 
 	ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
@@ -339,20 +155,20 @@ static int hdmic_probe(struct platform_device *pdev)
 	platform_set_drvdata(pdev, ddata);
 	ddata->dev = &pdev->dev;
 
-	r = hdmic_probe_of(pdev);
-	if (r)
-		return r;
-
 	mutex_init(&ddata->hpd_lock);
 
-	if (gpio_is_valid(ddata->hpd_gpio)) {
-		r = devm_gpio_request_one(&pdev->dev, ddata->hpd_gpio,
-				GPIOF_DIR_IN, "hdmi_hpd");
-		if (r)
-			return r;
+	/* HPD GPIO */
+	gpio = devm_gpiod_get_optional(&pdev->dev, "hpd", GPIOD_IN);
+	if (IS_ERR(gpio)) {
+		dev_err(&pdev->dev, "failed to parse HPD gpio\n");
+		return PTR_ERR(gpio);
+	}
+
+	ddata->hpd_gpio = gpio;
 
+	if (ddata->hpd_gpio) {
 		r = devm_request_threaded_irq(&pdev->dev,
-				gpio_to_irq(ddata->hpd_gpio),
+				gpiod_to_irq(ddata->hpd_gpio),
 				NULL, hdmic_hpd_isr,
 				IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
 				IRQF_ONESHOT,
@@ -361,20 +177,18 @@ static int hdmic_probe(struct platform_device *pdev)
 			return r;
 	}
 
-	ddata->vm = hdmic_default_vm;
-
 	dssdev = &ddata->dssdev;
-	dssdev->driver = &hdmic_driver;
+	dssdev->ops = &hdmic_ops;
 	dssdev->dev = &pdev->dev;
 	dssdev->type = OMAP_DISPLAY_TYPE_HDMI;
 	dssdev->owner = THIS_MODULE;
-	dssdev->panel.vm = hdmic_default_vm;
+	dssdev->of_ports = BIT(0);
+	dssdev->ops_flags = ddata->hpd_gpio
+			  ? OMAP_DSS_DEVICE_OP_DETECT | OMAP_DSS_DEVICE_OP_HPD
+			  : 0;
 
-	r = omapdss_register_display(dssdev);
-	if (r) {
-		dev_err(&pdev->dev, "Failed to register panel\n");
-		return r;
-	}
+	omapdss_display_init(dssdev);
+	omapdss_device_register(dssdev);
 
 	return 0;
 }
@@ -384,10 +198,9 @@ static int __exit hdmic_remove(struct platform_device *pdev)
 	struct panel_drv_data *ddata = platform_get_drvdata(pdev);
 	struct omap_dss_device *dssdev = &ddata->dssdev;
 
-	omapdss_unregister_display(&ddata->dssdev);
+	omapdss_device_unregister(&ddata->dssdev);
 
 	hdmic_disable(dssdev);
-	hdmic_disconnect(dssdev);
 
 	return 0;
 }

+ 24 - 108
drivers/gpu/drm/omapdrm/displays/encoder-opa362.c

@@ -23,75 +23,28 @@
 
 struct panel_drv_data {
 	struct omap_dss_device dssdev;
-	struct omap_dss_device *in;
 
 	struct gpio_desc *enable_gpio;
-
-	struct videomode vm;
 };
 
 #define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev)
 
-static int opa362_connect(struct omap_dss_device *dssdev,
-		struct omap_dss_device *dst)
+static int opa362_connect(struct omap_dss_device *src,
+			  struct omap_dss_device *dst)
 {
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in;
-	int r;
-
-	dev_dbg(dssdev->dev, "connect\n");
-
-	if (omapdss_device_is_connected(dssdev))
-		return -EBUSY;
-
-	in = omapdss_of_find_source_for_first_ep(dssdev->dev->of_node);
-	if (IS_ERR(in)) {
-		dev_err(dssdev->dev, "failed to find video source\n");
-		return PTR_ERR(in);
-	}
-
-	r = in->ops.atv->connect(in, dssdev);
-	if (r) {
-		omap_dss_put_device(in);
-		return r;
-	}
-
-	dst->src = dssdev;
-	dssdev->dst = dst;
-
-	ddata->in = in;
-	return 0;
+	return omapdss_device_connect(dst->dss, dst, dst->next);
 }
 
-static void opa362_disconnect(struct omap_dss_device *dssdev,
-		struct omap_dss_device *dst)
+static void opa362_disconnect(struct omap_dss_device *src,
+			      struct omap_dss_device *dst)
 {
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
-
-	dev_dbg(dssdev->dev, "disconnect\n");
-
-	WARN_ON(!omapdss_device_is_connected(dssdev));
-	if (!omapdss_device_is_connected(dssdev))
-		return;
-
-	WARN_ON(dst != dssdev->dst);
-	if (dst != dssdev->dst)
-		return;
-
-	dst->src = NULL;
-	dssdev->dst = NULL;
-
-	in->ops.atv->disconnect(in, &ddata->dssdev);
-
-	omap_dss_put_device(in);
-	ddata->in = NULL;
+	omapdss_device_disconnect(dst, dst->next);
 }
 
 static int opa362_enable(struct omap_dss_device *dssdev)
 {
 	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
+	struct omap_dss_device *src = dssdev->src;
 	int r;
 
 	dev_dbg(dssdev->dev, "enable\n");
@@ -102,9 +55,7 @@ static int opa362_enable(struct omap_dss_device *dssdev)
 	if (omapdss_device_is_enabled(dssdev))
 		return 0;
 
-	in->ops.atv->set_timings(in, &ddata->vm);
-
-	r = in->ops.atv->enable(in);
+	r = src->ops->enable(src);
 	if (r)
 		return r;
 
@@ -119,7 +70,7 @@ static int opa362_enable(struct omap_dss_device *dssdev)
 static void opa362_disable(struct omap_dss_device *dssdev)
 {
 	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
+	struct omap_dss_device *src = dssdev->src;
 
 	dev_dbg(dssdev->dev, "disable\n");
 
@@ -129,56 +80,16 @@ static void opa362_disable(struct omap_dss_device *dssdev)
 	if (ddata->enable_gpio)
 		gpiod_set_value_cansleep(ddata->enable_gpio, 0);
 
-	in->ops.atv->disable(in);
+	src->ops->disable(src);
 
 	dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
 }
 
-static void opa362_set_timings(struct omap_dss_device *dssdev,
-			       struct videomode *vm)
-{
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
-
-	dev_dbg(dssdev->dev, "set_timings\n");
-
-	ddata->vm = *vm;
-	dssdev->panel.vm = *vm;
-
-	in->ops.atv->set_timings(in, vm);
-}
-
-static void opa362_get_timings(struct omap_dss_device *dssdev,
-			       struct videomode *vm)
-{
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-
-	dev_dbg(dssdev->dev, "get_timings\n");
-
-	*vm = ddata->vm;
-}
-
-static int opa362_check_timings(struct omap_dss_device *dssdev,
-				struct videomode *vm)
-{
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
-
-	dev_dbg(dssdev->dev, "check_timings\n");
-
-	return in->ops.atv->check_timings(in, vm);
-}
-
-static const struct omapdss_atv_ops opa362_atv_ops = {
+static const struct omap_dss_device_ops opa362_ops = {
 	.connect	= opa362_connect,
 	.disconnect	= opa362_disconnect,
-
 	.enable		= opa362_enable,
 	.disable	= opa362_disable,
-
-	.check_timings	= opa362_check_timings,
-	.set_timings	= opa362_set_timings,
-	.get_timings	= opa362_get_timings,
 };
 
 static int opa362_probe(struct platform_device *pdev)
@@ -186,7 +97,6 @@ static int opa362_probe(struct platform_device *pdev)
 	struct panel_drv_data *ddata;
 	struct omap_dss_device *dssdev;
 	struct gpio_desc *gpio;
-	int r;
 
 	dev_dbg(&pdev->dev, "probe\n");
 
@@ -203,18 +113,22 @@ static int opa362_probe(struct platform_device *pdev)
 	ddata->enable_gpio = gpio;
 
 	dssdev = &ddata->dssdev;
-	dssdev->ops.atv = &opa362_atv_ops;
+	dssdev->ops = &opa362_ops;
 	dssdev->dev = &pdev->dev;
 	dssdev->type = OMAP_DISPLAY_TYPE_VENC;
 	dssdev->output_type = OMAP_DISPLAY_TYPE_VENC;
 	dssdev->owner = THIS_MODULE;
+	dssdev->of_ports = BIT(1) | BIT(0);
 
-	r = omapdss_register_output(dssdev);
-	if (r) {
-		dev_err(&pdev->dev, "Failed to register output\n");
-		return r;
+	dssdev->next = omapdss_of_find_connected_device(pdev->dev.of_node, 1);
+	if (IS_ERR(dssdev->next)) {
+		if (PTR_ERR(dssdev->next) != -EPROBE_DEFER)
+			dev_err(&pdev->dev, "failed to find video sink\n");
+		return PTR_ERR(dssdev->next);
 	}
 
+	omapdss_device_register(dssdev);
+
 	return 0;
 }
 
@@ -223,7 +137,9 @@ static int __exit opa362_remove(struct platform_device *pdev)
 	struct panel_drv_data *ddata = platform_get_drvdata(pdev);
 	struct omap_dss_device *dssdev = &ddata->dssdev;
 
-	omapdss_unregister_output(&ddata->dssdev);
+	if (dssdev->next)
+		omapdss_device_put(dssdev->next);
+	omapdss_device_unregister(&ddata->dssdev);
 
 	WARN_ON(omapdss_device_is_enabled(dssdev));
 	if (omapdss_device_is_enabled(dssdev))
@@ -231,7 +147,7 @@ static int __exit opa362_remove(struct platform_device *pdev)
 
 	WARN_ON(omapdss_device_is_connected(dssdev));
 	if (omapdss_device_is_connected(dssdev))
-		opa362_disconnect(dssdev, dssdev->dst);
+		omapdss_device_disconnect(NULL, dssdev);
 
 	return 0;
 }

+ 40 - 147
drivers/gpu/drm/omapdrm/displays/encoder-tfp410.c

@@ -13,77 +13,33 @@
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
-#include <linux/of_gpio.h>
 
 #include "../dss/omapdss.h"
 
 struct panel_drv_data {
 	struct omap_dss_device dssdev;
-	struct omap_dss_device *in;
 
-	int pd_gpio;
-
-	struct videomode vm;
+	struct gpio_desc *pd_gpio;
 };
 
 #define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev)
 
-static int tfp410_connect(struct omap_dss_device *dssdev,
-		struct omap_dss_device *dst)
+static int tfp410_connect(struct omap_dss_device *src,
+			  struct omap_dss_device *dst)
 {
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in;
-	int r;
-
-	if (omapdss_device_is_connected(dssdev))
-		return -EBUSY;
-
-	in = omapdss_of_find_source_for_first_ep(dssdev->dev->of_node);
-	if (IS_ERR(in)) {
-		dev_err(dssdev->dev, "failed to find video source\n");
-		return PTR_ERR(in);
-	}
-
-	r = in->ops.dpi->connect(in, dssdev);
-	if (r) {
-		omap_dss_put_device(in);
-		return r;
-	}
-
-	dst->src = dssdev;
-	dssdev->dst = dst;
-
-	ddata->in = in;
-	return 0;
+	return omapdss_device_connect(dst->dss, dst, dst->next);
 }
 
-static void tfp410_disconnect(struct omap_dss_device *dssdev,
-		struct omap_dss_device *dst)
+static void tfp410_disconnect(struct omap_dss_device *src,
+			      struct omap_dss_device *dst)
 {
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
-
-	WARN_ON(!omapdss_device_is_connected(dssdev));
-	if (!omapdss_device_is_connected(dssdev))
-		return;
-
-	WARN_ON(dst != dssdev->dst);
-	if (dst != dssdev->dst)
-		return;
-
-	dst->src = NULL;
-	dssdev->dst = NULL;
-
-	in->ops.dpi->disconnect(in, &ddata->dssdev);
-
-	omap_dss_put_device(in);
-	ddata->in = NULL;
+	omapdss_device_disconnect(dst, dst->next);
 }
 
 static int tfp410_enable(struct omap_dss_device *dssdev)
 {
 	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
+	struct omap_dss_device *src = dssdev->src;
 	int r;
 
 	if (!omapdss_device_is_connected(dssdev))
@@ -92,14 +48,12 @@ static int tfp410_enable(struct omap_dss_device *dssdev)
 	if (omapdss_device_is_enabled(dssdev))
 		return 0;
 
-	in->ops.dpi->set_timings(in, &ddata->vm);
-
-	r = in->ops.dpi->enable(in);
+	r = src->ops->enable(src);
 	if (r)
 		return r;
 
-	if (gpio_is_valid(ddata->pd_gpio))
-		gpio_set_value_cansleep(ddata->pd_gpio, 1);
+	if (ddata->pd_gpio)
+		gpiod_set_value_cansleep(ddata->pd_gpio, 0);
 
 	dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
 
@@ -109,94 +63,31 @@ static int tfp410_enable(struct omap_dss_device *dssdev)
 static void tfp410_disable(struct omap_dss_device *dssdev)
 {
 	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
+	struct omap_dss_device *src = dssdev->src;
 
 	if (!omapdss_device_is_enabled(dssdev))
 		return;
 
-	if (gpio_is_valid(ddata->pd_gpio))
-		gpio_set_value_cansleep(ddata->pd_gpio, 0);
+	if (ddata->pd_gpio)
+		gpiod_set_value_cansleep(ddata->pd_gpio, 0);
 
-	in->ops.dpi->disable(in);
+	src->ops->disable(src);
 
 	dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
 }
 
-static void tfp410_fix_timings(struct videomode *vm)
-{
-	vm->flags |= DISPLAY_FLAGS_DE_HIGH | DISPLAY_FLAGS_PIXDATA_POSEDGE |
-		     DISPLAY_FLAGS_SYNC_POSEDGE;
-}
-
-static void tfp410_set_timings(struct omap_dss_device *dssdev,
-			       struct videomode *vm)
-{
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
-
-	tfp410_fix_timings(vm);
-
-	ddata->vm = *vm;
-	dssdev->panel.vm = *vm;
-
-	in->ops.dpi->set_timings(in, vm);
-}
-
-static void tfp410_get_timings(struct omap_dss_device *dssdev,
-			       struct videomode *vm)
-{
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-
-	*vm = ddata->vm;
-}
-
-static int tfp410_check_timings(struct omap_dss_device *dssdev,
-				struct videomode *vm)
-{
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
-
-	tfp410_fix_timings(vm);
-
-	return in->ops.dpi->check_timings(in, vm);
-}
-
-static const struct omapdss_dvi_ops tfp410_dvi_ops = {
+static const struct omap_dss_device_ops tfp410_ops = {
 	.connect	= tfp410_connect,
 	.disconnect	= tfp410_disconnect,
-
 	.enable		= tfp410_enable,
 	.disable	= tfp410_disable,
-
-	.check_timings	= tfp410_check_timings,
-	.set_timings	= tfp410_set_timings,
-	.get_timings	= tfp410_get_timings,
 };
 
-static int tfp410_probe_of(struct platform_device *pdev)
-{
-	struct panel_drv_data *ddata = platform_get_drvdata(pdev);
-	struct device_node *node = pdev->dev.of_node;
-	int gpio;
-
-	gpio = of_get_named_gpio(node, "powerdown-gpios", 0);
-
-	if (gpio_is_valid(gpio) || gpio == -ENOENT) {
-		ddata->pd_gpio = gpio;
-	} else {
-		if (gpio != -EPROBE_DEFER)
-			dev_err(&pdev->dev, "failed to parse PD gpio\n");
-		return gpio;
-	}
-
-	return 0;
-}
-
 static int tfp410_probe(struct platform_device *pdev)
 {
 	struct panel_drv_data *ddata;
 	struct omap_dss_device *dssdev;
-	int r;
+	struct gpio_desc *gpio;
 
 	ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
 	if (!ddata)
@@ -204,34 +95,34 @@ static int tfp410_probe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, ddata);
 
-	r = tfp410_probe_of(pdev);
-	if (r)
-		return r;
-
-	if (gpio_is_valid(ddata->pd_gpio)) {
-		r = devm_gpio_request_one(&pdev->dev, ddata->pd_gpio,
-				GPIOF_OUT_INIT_LOW, "tfp410 PD");
-		if (r) {
-			dev_err(&pdev->dev, "Failed to request PD GPIO %d\n",
-					ddata->pd_gpio);
-			return r;
-		}
+	/* Powerdown GPIO */
+	gpio = devm_gpiod_get_optional(&pdev->dev, "powerdown", GPIOD_OUT_HIGH);
+	if (IS_ERR(gpio)) {
+		dev_err(&pdev->dev, "failed to parse powerdown gpio\n");
+		return PTR_ERR(gpio);
 	}
 
+	ddata->pd_gpio = gpio;
+
 	dssdev = &ddata->dssdev;
-	dssdev->ops.dvi = &tfp410_dvi_ops;
+	dssdev->ops = &tfp410_ops;
 	dssdev->dev = &pdev->dev;
 	dssdev->type = OMAP_DISPLAY_TYPE_DPI;
 	dssdev->output_type = OMAP_DISPLAY_TYPE_DVI;
 	dssdev->owner = THIS_MODULE;
-	dssdev->port_num = 1;
-
-	r = omapdss_register_output(dssdev);
-	if (r) {
-		dev_err(&pdev->dev, "Failed to register output\n");
-		return r;
+	dssdev->of_ports = BIT(1) | BIT(0);
+	dssdev->bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_SYNC_POSEDGE
+			  | DRM_BUS_FLAG_PIXDATA_POSEDGE;
+
+	dssdev->next = omapdss_of_find_connected_device(pdev->dev.of_node, 1);
+	if (IS_ERR(dssdev->next)) {
+		if (PTR_ERR(dssdev->next) != -EPROBE_DEFER)
+			dev_err(&pdev->dev, "failed to find video sink\n");
+		return PTR_ERR(dssdev->next);
 	}
 
+	omapdss_device_register(dssdev);
+
 	return 0;
 }
 
@@ -240,7 +131,9 @@ static int __exit tfp410_remove(struct platform_device *pdev)
 	struct panel_drv_data *ddata = platform_get_drvdata(pdev);
 	struct omap_dss_device *dssdev = &ddata->dssdev;
 
-	omapdss_unregister_output(&ddata->dssdev);
+	if (dssdev->next)
+		omapdss_device_put(dssdev->next);
+	omapdss_device_unregister(&ddata->dssdev);
 
 	WARN_ON(omapdss_device_is_enabled(dssdev));
 	if (omapdss_device_is_enabled(dssdev))
@@ -248,7 +141,7 @@ static int __exit tfp410_remove(struct platform_device *pdev)
 
 	WARN_ON(omapdss_device_is_connected(dssdev));
 	if (omapdss_device_is_connected(dssdev))
-		tfp410_disconnect(dssdev, dssdev->dst);
+		omapdss_device_disconnect(NULL, dssdev);
 
 	return 0;
 }

+ 36 - 161
drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c

@@ -21,42 +21,26 @@
 
 struct panel_drv_data {
 	struct omap_dss_device dssdev;
-	struct omap_dss_device *in;
 	void (*hpd_cb)(void *cb_data, enum drm_connector_status status);
 	void *hpd_cb_data;
-	bool hpd_enabled;
 	struct mutex hpd_lock;
 
 	struct gpio_desc *ct_cp_hpd_gpio;
 	struct gpio_desc *ls_oe_gpio;
 	struct gpio_desc *hpd_gpio;
-
-	struct videomode vm;
 };
 
 #define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev)
 
-static int tpd_connect(struct omap_dss_device *dssdev,
-		struct omap_dss_device *dst)
+static int tpd_connect(struct omap_dss_device *src,
+		       struct omap_dss_device *dst)
 {
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in;
+	struct panel_drv_data *ddata = to_panel_data(dst);
 	int r;
 
-	in = omapdss_of_find_source_for_first_ep(dssdev->dev->of_node);
-	if (IS_ERR(in)) {
-		dev_err(dssdev->dev, "failed to find video source\n");
-		return PTR_ERR(in);
-	}
-
-	r = in->ops.hdmi->connect(in, dssdev);
-	if (r) {
-		omap_dss_put_device(in);
+	r = omapdss_device_connect(dst->dss, dst, dst->next);
+	if (r)
 		return r;
-	}
-
-	dst->src = dssdev;
-	dssdev->dst = dst;
 
 	gpiod_set_value_cansleep(ddata->ct_cp_hpd_gpio, 1);
 	gpiod_set_value_cansleep(ddata->ls_oe_gpio, 1);
@@ -64,45 +48,29 @@ static int tpd_connect(struct omap_dss_device *dssdev,
 	/* DC-DC converter needs at max 300us to get to 90% of 5V */
 	udelay(300);
 
-	ddata->in = in;
 	return 0;
 }
 
-static void tpd_disconnect(struct omap_dss_device *dssdev,
-		struct omap_dss_device *dst)
+static void tpd_disconnect(struct omap_dss_device *src,
+			   struct omap_dss_device *dst)
 {
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
-
-	WARN_ON(dst != dssdev->dst);
-
-	if (dst != dssdev->dst)
-		return;
+	struct panel_drv_data *ddata = to_panel_data(dst);
 
 	gpiod_set_value_cansleep(ddata->ct_cp_hpd_gpio, 0);
 	gpiod_set_value_cansleep(ddata->ls_oe_gpio, 0);
 
-	dst->src = NULL;
-	dssdev->dst = NULL;
-
-	in->ops.hdmi->disconnect(in, &ddata->dssdev);
-
-	omap_dss_put_device(in);
-	ddata->in = NULL;
+	omapdss_device_disconnect(dst, dst->next);
 }
 
 static int tpd_enable(struct omap_dss_device *dssdev)
 {
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
+	struct omap_dss_device *src = dssdev->src;
 	int r;
 
 	if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
 		return 0;
 
-	in->ops.hdmi->set_timings(in, &ddata->vm);
-
-	r = in->ops.hdmi->enable(in);
+	r = src->ops->enable(src);
 	if (r)
 		return r;
 
@@ -113,76 +81,27 @@ static int tpd_enable(struct omap_dss_device *dssdev)
 
 static void tpd_disable(struct omap_dss_device *dssdev)
 {
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
+	struct omap_dss_device *src = dssdev->src;
 
 	if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
 		return;
 
-	in->ops.hdmi->disable(in);
+	src->ops->disable(src);
 
 	dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
 }
 
-static void tpd_set_timings(struct omap_dss_device *dssdev,
-			    struct videomode *vm)
-{
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
-
-	ddata->vm = *vm;
-	dssdev->panel.vm = *vm;
-
-	in->ops.hdmi->set_timings(in, vm);
-}
-
-static void tpd_get_timings(struct omap_dss_device *dssdev,
-			    struct videomode *vm)
-{
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-
-	*vm = ddata->vm;
-}
-
-static int tpd_check_timings(struct omap_dss_device *dssdev,
-			     struct videomode *vm)
-{
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
-	int r;
-
-	r = in->ops.hdmi->check_timings(in, vm);
-
-	return r;
-}
-
-static int tpd_read_edid(struct omap_dss_device *dssdev,
-		u8 *edid, int len)
-{
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
-
-	if (!gpiod_get_value_cansleep(ddata->hpd_gpio))
-		return -ENODEV;
-
-	return in->ops.hdmi->read_edid(in, edid, len);
-}
-
 static bool tpd_detect(struct omap_dss_device *dssdev)
 {
 	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
-	bool connected = gpiod_get_value_cansleep(ddata->hpd_gpio);
 
-	if (!connected && in->ops.hdmi->lost_hotplug)
-		in->ops.hdmi->lost_hotplug(in);
-	return connected;
+	return gpiod_get_value_cansleep(ddata->hpd_gpio);
 }
 
-static int tpd_register_hpd_cb(struct omap_dss_device *dssdev,
-			       void (*cb)(void *cb_data,
+static void tpd_register_hpd_cb(struct omap_dss_device *dssdev,
+				void (*cb)(void *cb_data,
 					  enum drm_connector_status status),
-			       void *cb_data)
+				void *cb_data)
 {
 	struct panel_drv_data *ddata = to_panel_data(dssdev);
 
@@ -190,8 +109,6 @@ static int tpd_register_hpd_cb(struct omap_dss_device *dssdev,
 	ddata->hpd_cb = cb;
 	ddata->hpd_cb_data = cb_data;
 	mutex_unlock(&ddata->hpd_lock);
-
-	return 0;
 }
 
 static void tpd_unregister_hpd_cb(struct omap_dss_device *dssdev)
@@ -204,61 +121,14 @@ static void tpd_unregister_hpd_cb(struct omap_dss_device *dssdev)
 	mutex_unlock(&ddata->hpd_lock);
 }
 
-static void tpd_enable_hpd(struct omap_dss_device *dssdev)
-{
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-
-	mutex_lock(&ddata->hpd_lock);
-	ddata->hpd_enabled = true;
-	mutex_unlock(&ddata->hpd_lock);
-}
-
-static void tpd_disable_hpd(struct omap_dss_device *dssdev)
-{
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-
-	mutex_lock(&ddata->hpd_lock);
-	ddata->hpd_enabled = false;
-	mutex_unlock(&ddata->hpd_lock);
-}
-
-static int tpd_set_infoframe(struct omap_dss_device *dssdev,
-		const struct hdmi_avi_infoframe *avi)
-{
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
-
-	return in->ops.hdmi->set_infoframe(in, avi);
-}
-
-static int tpd_set_hdmi_mode(struct omap_dss_device *dssdev,
-		bool hdmi_mode)
-{
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
-
-	return in->ops.hdmi->set_hdmi_mode(in, hdmi_mode);
-}
-
-static const struct omapdss_hdmi_ops tpd_hdmi_ops = {
+static const struct omap_dss_device_ops tpd_ops = {
 	.connect		= tpd_connect,
 	.disconnect		= tpd_disconnect,
-
 	.enable			= tpd_enable,
 	.disable		= tpd_disable,
-
-	.check_timings		= tpd_check_timings,
-	.set_timings		= tpd_set_timings,
-	.get_timings		= tpd_get_timings,
-
-	.read_edid		= tpd_read_edid,
 	.detect			= tpd_detect,
 	.register_hpd_cb	= tpd_register_hpd_cb,
 	.unregister_hpd_cb	= tpd_unregister_hpd_cb,
-	.enable_hpd		= tpd_enable_hpd,
-	.disable_hpd		= tpd_disable_hpd,
-	.set_infoframe		= tpd_set_infoframe,
-	.set_hdmi_mode		= tpd_set_hdmi_mode,
 };
 
 static irqreturn_t tpd_hpd_isr(int irq, void *data)
@@ -266,7 +136,7 @@ static irqreturn_t tpd_hpd_isr(int irq, void *data)
 	struct panel_drv_data *ddata = data;
 
 	mutex_lock(&ddata->hpd_lock);
-	if (ddata->hpd_enabled && ddata->hpd_cb) {
+	if (ddata->hpd_cb) {
 		enum drm_connector_status status;
 
 		if (tpd_detect(&ddata->dssdev))
@@ -283,7 +153,7 @@ static irqreturn_t tpd_hpd_isr(int irq, void *data)
 
 static int tpd_probe(struct platform_device *pdev)
 {
-	struct omap_dss_device *in, *dssdev;
+	struct omap_dss_device *dssdev;
 	struct panel_drv_data *ddata;
 	int r;
 	struct gpio_desc *gpio;
@@ -325,21 +195,24 @@ static int tpd_probe(struct platform_device *pdev)
 		return r;
 
 	dssdev = &ddata->dssdev;
-	dssdev->ops.hdmi = &tpd_hdmi_ops;
+	dssdev->ops = &tpd_ops;
 	dssdev->dev = &pdev->dev;
 	dssdev->type = OMAP_DISPLAY_TYPE_HDMI;
 	dssdev->output_type = OMAP_DISPLAY_TYPE_HDMI;
 	dssdev->owner = THIS_MODULE;
-	dssdev->port_num = 1;
-
-	in = ddata->in;
-
-	r = omapdss_register_output(dssdev);
-	if (r) {
-		dev_err(&pdev->dev, "Failed to register output\n");
-		return r;
+	dssdev->of_ports = BIT(1) | BIT(0);
+	dssdev->ops_flags = OMAP_DSS_DEVICE_OP_DETECT
+			  | OMAP_DSS_DEVICE_OP_HPD;
+
+	dssdev->next = omapdss_of_find_connected_device(pdev->dev.of_node, 1);
+	if (IS_ERR(dssdev->next)) {
+		if (PTR_ERR(dssdev->next) != -EPROBE_DEFER)
+			dev_err(&pdev->dev, "failed to find video sink\n");
+		return PTR_ERR(dssdev->next);
 	}
 
+	omapdss_device_register(dssdev);
+
 	return 0;
 }
 
@@ -348,7 +221,9 @@ static int __exit tpd_remove(struct platform_device *pdev)
 	struct panel_drv_data *ddata = platform_get_drvdata(pdev);
 	struct omap_dss_device *dssdev = &ddata->dssdev;
 
-	omapdss_unregister_output(&ddata->dssdev);
+	if (dssdev->next)
+		omapdss_device_put(dssdev->next);
+	omapdss_device_unregister(&ddata->dssdev);
 
 	WARN_ON(omapdss_device_is_enabled(dssdev));
 	if (omapdss_device_is_enabled(dssdev))
@@ -356,7 +231,7 @@ static int __exit tpd_remove(struct platform_device *pdev)
 
 	WARN_ON(omapdss_device_is_connected(dssdev));
 	if (omapdss_device_is_connected(dssdev))
-		tpd_disconnect(dssdev, dssdev->dst);
+		omapdss_device_disconnect(NULL, dssdev);
 
 	return 0;
 }

+ 16 - 73
drivers/gpu/drm/omapdrm/displays/panel-dpi.c

@@ -23,7 +23,6 @@
 
 struct panel_drv_data {
 	struct omap_dss_device dssdev;
-	struct omap_dss_device *in;
 
 	struct videomode vm;
 
@@ -35,49 +34,21 @@ struct panel_drv_data {
 
 #define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev)
 
-static int panel_dpi_connect(struct omap_dss_device *dssdev)
+static int panel_dpi_connect(struct omap_dss_device *src,
+			     struct omap_dss_device *dst)
 {
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in;
-	int r;
-
-	if (omapdss_device_is_connected(dssdev))
-		return 0;
-
-	in = omapdss_of_find_source_for_first_ep(dssdev->dev->of_node);
-	if (IS_ERR(in)) {
-		dev_err(dssdev->dev, "failed to find video source\n");
-		return PTR_ERR(in);
-	}
-
-	r = in->ops.dpi->connect(in, dssdev);
-	if (r) {
-		omap_dss_put_device(in);
-		return r;
-	}
-
-	ddata->in = in;
 	return 0;
 }
 
-static void panel_dpi_disconnect(struct omap_dss_device *dssdev)
+static void panel_dpi_disconnect(struct omap_dss_device *src,
+				 struct omap_dss_device *dst)
 {
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
-
-	if (!omapdss_device_is_connected(dssdev))
-		return;
-
-	in->ops.dpi->disconnect(in, dssdev);
-
-	omap_dss_put_device(in);
-	ddata->in = NULL;
 }
 
 static int panel_dpi_enable(struct omap_dss_device *dssdev)
 {
 	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
+	struct omap_dss_device *src = dssdev->src;
 	int r;
 
 	if (!omapdss_device_is_connected(dssdev))
@@ -86,15 +57,13 @@ static int panel_dpi_enable(struct omap_dss_device *dssdev)
 	if (omapdss_device_is_enabled(dssdev))
 		return 0;
 
-	in->ops.dpi->set_timings(in, &ddata->vm);
-
-	r = in->ops.dpi->enable(in);
+	r = src->ops->enable(src);
 	if (r)
 		return r;
 
 	r = regulator_enable(ddata->vcc_supply);
 	if (r) {
-		in->ops.dpi->disable(in);
+		src->ops->disable(src);
 		return r;
 	}
 
@@ -109,7 +78,7 @@ static int panel_dpi_enable(struct omap_dss_device *dssdev)
 static void panel_dpi_disable(struct omap_dss_device *dssdev)
 {
 	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
+	struct omap_dss_device *src = dssdev->src;
 
 	if (!omapdss_device_is_enabled(dssdev))
 		return;
@@ -119,23 +88,11 @@ static void panel_dpi_disable(struct omap_dss_device *dssdev)
 	gpiod_set_value_cansleep(ddata->enable_gpio, 0);
 	regulator_disable(ddata->vcc_supply);
 
-	in->ops.dpi->disable(in);
+	src->ops->disable(src);
 
 	dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
 }
 
-static void panel_dpi_set_timings(struct omap_dss_device *dssdev,
-				  struct videomode *vm)
-{
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
-
-	ddata->vm = *vm;
-	dssdev->panel.vm = *vm;
-
-	in->ops.dpi->set_timings(in, vm);
-}
-
 static void panel_dpi_get_timings(struct omap_dss_device *dssdev,
 				  struct videomode *vm)
 {
@@ -144,25 +101,14 @@ static void panel_dpi_get_timings(struct omap_dss_device *dssdev,
 	*vm = ddata->vm;
 }
 
-static int panel_dpi_check_timings(struct omap_dss_device *dssdev,
-				   struct videomode *vm)
-{
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
-
-	return in->ops.dpi->check_timings(in, vm);
-}
-
-static struct omap_dss_driver panel_dpi_ops = {
+static const struct omap_dss_device_ops panel_dpi_ops = {
 	.connect	= panel_dpi_connect,
 	.disconnect	= panel_dpi_disconnect,
 
 	.enable		= panel_dpi_enable,
 	.disable	= panel_dpi_disable,
 
-	.set_timings	= panel_dpi_set_timings,
 	.get_timings	= panel_dpi_get_timings,
-	.check_timings	= panel_dpi_check_timings,
 };
 
 static int panel_dpi_probe_of(struct platform_device *pdev)
@@ -227,16 +173,14 @@ static int panel_dpi_probe(struct platform_device *pdev)
 
 	dssdev = &ddata->dssdev;
 	dssdev->dev = &pdev->dev;
-	dssdev->driver = &panel_dpi_ops;
+	dssdev->ops = &panel_dpi_ops;
 	dssdev->type = OMAP_DISPLAY_TYPE_DPI;
 	dssdev->owner = THIS_MODULE;
-	dssdev->panel.vm = ddata->vm;
+	dssdev->of_ports = BIT(0);
+	drm_bus_flags_from_videomode(&ddata->vm, &dssdev->bus_flags);
 
-	r = omapdss_register_display(dssdev);
-	if (r) {
-		dev_err(&pdev->dev, "Failed to register panel\n");
-		return r;
-	}
+	omapdss_display_init(dssdev);
+	omapdss_device_register(dssdev);
 
 	return 0;
 }
@@ -246,10 +190,9 @@ static int __exit panel_dpi_remove(struct platform_device *pdev)
 	struct panel_drv_data *ddata = platform_get_drvdata(pdev);
 	struct omap_dss_device *dssdev = &ddata->dssdev;
 
-	omapdss_unregister_display(dssdev);
+	omapdss_device_unregister(dssdev);
 
 	panel_dpi_disable(dssdev);
-	panel_dpi_disconnect(dssdev);
 
 	return 0;
 }

+ 108 - 139
drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c

@@ -41,7 +41,6 @@
 
 struct panel_drv_data {
 	struct omap_dss_device dssdev;
-	struct omap_dss_device *in;
 
 	struct videomode vm;
 
@@ -142,11 +141,11 @@ static void hw_guard_wait(struct panel_drv_data *ddata)
 
 static int dsicm_dcs_read_1(struct panel_drv_data *ddata, u8 dcs_cmd, u8 *data)
 {
-	struct omap_dss_device *in = ddata->in;
+	struct omap_dss_device *src = ddata->dssdev.src;
 	int r;
 	u8 buf[1];
 
-	r = in->ops.dsi->dcs_read(in, ddata->channel, dcs_cmd, buf, 1);
+	r = src->ops->dsi.dcs_read(src, ddata->channel, dcs_cmd, buf, 1);
 
 	if (r < 0)
 		return r;
@@ -158,29 +157,30 @@ static int dsicm_dcs_read_1(struct panel_drv_data *ddata, u8 dcs_cmd, u8 *data)
 
 static int dsicm_dcs_write_0(struct panel_drv_data *ddata, u8 dcs_cmd)
 {
-	struct omap_dss_device *in = ddata->in;
-	return in->ops.dsi->dcs_write(in, ddata->channel, &dcs_cmd, 1);
+	struct omap_dss_device *src = ddata->dssdev.src;
+
+	return src->ops->dsi.dcs_write(src, ddata->channel, &dcs_cmd, 1);
 }
 
 static int dsicm_dcs_write_1(struct panel_drv_data *ddata, u8 dcs_cmd, u8 param)
 {
-	struct omap_dss_device *in = ddata->in;
+	struct omap_dss_device *src = ddata->dssdev.src;
 	u8 buf[2] = { dcs_cmd, param };
 
-	return in->ops.dsi->dcs_write(in, ddata->channel, buf, 2);
+	return src->ops->dsi.dcs_write(src, ddata->channel, buf, 2);
 }
 
 static int dsicm_sleep_in(struct panel_drv_data *ddata)
 
 {
-	struct omap_dss_device *in = ddata->in;
+	struct omap_dss_device *src = ddata->dssdev.src;
 	u8 cmd;
 	int r;
 
 	hw_guard_wait(ddata);
 
 	cmd = MIPI_DCS_ENTER_SLEEP_MODE;
-	r = in->ops.dsi->dcs_write_nosync(in, ddata->channel, &cmd, 1);
+	r = src->ops->dsi.dcs_write_nosync(src, ddata->channel, &cmd, 1);
 	if (r)
 		return r;
 
@@ -228,7 +228,7 @@ static int dsicm_get_id(struct panel_drv_data *ddata, u8 *id1, u8 *id2, u8 *id3)
 static int dsicm_set_update_window(struct panel_drv_data *ddata,
 		u16 x, u16 y, u16 w, u16 h)
 {
-	struct omap_dss_device *in = ddata->in;
+	struct omap_dss_device *src = ddata->dssdev.src;
 	int r;
 	u16 x1 = x;
 	u16 x2 = x + w - 1;
@@ -242,7 +242,7 @@ static int dsicm_set_update_window(struct panel_drv_data *ddata,
 	buf[3] = (x2 >> 8) & 0xff;
 	buf[4] = (x2 >> 0) & 0xff;
 
-	r = in->ops.dsi->dcs_write_nosync(in, ddata->channel, buf, sizeof(buf));
+	r = src->ops->dsi.dcs_write_nosync(src, ddata->channel, buf, sizeof(buf));
 	if (r)
 		return r;
 
@@ -252,11 +252,11 @@ static int dsicm_set_update_window(struct panel_drv_data *ddata,
 	buf[3] = (y2 >> 8) & 0xff;
 	buf[4] = (y2 >> 0) & 0xff;
 
-	r = in->ops.dsi->dcs_write_nosync(in, ddata->channel, buf, sizeof(buf));
+	r = src->ops->dsi.dcs_write_nosync(src, ddata->channel, buf, sizeof(buf));
 	if (r)
 		return r;
 
-	in->ops.dsi->bta_sync(in, ddata->channel);
+	src->ops->dsi.bta_sync(src, ddata->channel);
 
 	return r;
 }
@@ -275,7 +275,7 @@ static void dsicm_cancel_ulps_work(struct panel_drv_data *ddata)
 
 static int dsicm_enter_ulps(struct panel_drv_data *ddata)
 {
-	struct omap_dss_device *in = ddata->in;
+	struct omap_dss_device *src = ddata->dssdev.src;
 	int r;
 
 	if (ddata->ulps_enabled)
@@ -290,7 +290,7 @@ static int dsicm_enter_ulps(struct panel_drv_data *ddata)
 	if (ddata->ext_te_gpio)
 		disable_irq(gpiod_to_irq(ddata->ext_te_gpio));
 
-	in->ops.dsi->disable(in, false, true);
+	src->ops->dsi.disable(src, false, true);
 
 	ddata->ulps_enabled = true;
 
@@ -309,19 +309,19 @@ err:
 
 static int dsicm_exit_ulps(struct panel_drv_data *ddata)
 {
-	struct omap_dss_device *in = ddata->in;
+	struct omap_dss_device *src = ddata->dssdev.src;
 	int r;
 
 	if (!ddata->ulps_enabled)
 		return 0;
 
-	r = in->ops.dsi->enable(in);
+	r = src->ops->enable(src);
 	if (r) {
 		dev_err(&ddata->pdev->dev, "failed to enable DSI\n");
 		goto err1;
 	}
 
-	in->ops.dsi->enable_hs(in, ddata->channel, true);
+	src->ops->dsi.enable_hs(src, ddata->channel, true);
 
 	r = _dsicm_enable_te(ddata, true);
 	if (r) {
@@ -366,7 +366,7 @@ static int dsicm_wake_up(struct panel_drv_data *ddata)
 static int dsicm_bl_update_status(struct backlight_device *dev)
 {
 	struct panel_drv_data *ddata = dev_get_drvdata(&dev->dev);
-	struct omap_dss_device *in = ddata->in;
+	struct omap_dss_device *src = ddata->dssdev.src;
 	int r = 0;
 	int level;
 
@@ -381,13 +381,13 @@ static int dsicm_bl_update_status(struct backlight_device *dev)
 	mutex_lock(&ddata->lock);
 
 	if (ddata->enabled) {
-		in->ops.dsi->bus_lock(in);
+		src->ops->dsi.bus_lock(src);
 
 		r = dsicm_wake_up(ddata);
 		if (!r)
 			r = dsicm_dcs_write_1(ddata, DCS_BRIGHTNESS, level);
 
-		in->ops.dsi->bus_unlock(in);
+		src->ops->dsi.bus_unlock(src);
 	}
 
 	mutex_unlock(&ddata->lock);
@@ -414,21 +414,21 @@ static ssize_t dsicm_num_errors_show(struct device *dev,
 {
 	struct platform_device *pdev = to_platform_device(dev);
 	struct panel_drv_data *ddata = platform_get_drvdata(pdev);
-	struct omap_dss_device *in = ddata->in;
+	struct omap_dss_device *src = ddata->dssdev.src;
 	u8 errors = 0;
 	int r;
 
 	mutex_lock(&ddata->lock);
 
 	if (ddata->enabled) {
-		in->ops.dsi->bus_lock(in);
+		src->ops->dsi.bus_lock(src);
 
 		r = dsicm_wake_up(ddata);
 		if (!r)
 			r = dsicm_dcs_read_1(ddata, DCS_READ_NUM_ERRORS,
 					&errors);
 
-		in->ops.dsi->bus_unlock(in);
+		src->ops->dsi.bus_unlock(src);
 	} else {
 		r = -ENODEV;
 	}
@@ -446,20 +446,20 @@ static ssize_t dsicm_hw_revision_show(struct device *dev,
 {
 	struct platform_device *pdev = to_platform_device(dev);
 	struct panel_drv_data *ddata = platform_get_drvdata(pdev);
-	struct omap_dss_device *in = ddata->in;
+	struct omap_dss_device *src = ddata->dssdev.src;
 	u8 id1, id2, id3;
 	int r;
 
 	mutex_lock(&ddata->lock);
 
 	if (ddata->enabled) {
-		in->ops.dsi->bus_lock(in);
+		src->ops->dsi.bus_lock(src);
 
 		r = dsicm_wake_up(ddata);
 		if (!r)
 			r = dsicm_get_id(ddata, &id1, &id2, &id3);
 
-		in->ops.dsi->bus_unlock(in);
+		src->ops->dsi.bus_unlock(src);
 	} else {
 		r = -ENODEV;
 	}
@@ -478,7 +478,7 @@ static ssize_t dsicm_store_ulps(struct device *dev,
 {
 	struct platform_device *pdev = to_platform_device(dev);
 	struct panel_drv_data *ddata = platform_get_drvdata(pdev);
-	struct omap_dss_device *in = ddata->in;
+	struct omap_dss_device *src = ddata->dssdev.src;
 	unsigned long t;
 	int r;
 
@@ -489,14 +489,14 @@ static ssize_t dsicm_store_ulps(struct device *dev,
 	mutex_lock(&ddata->lock);
 
 	if (ddata->enabled) {
-		in->ops.dsi->bus_lock(in);
+		src->ops->dsi.bus_lock(src);
 
 		if (t)
 			r = dsicm_enter_ulps(ddata);
 		else
 			r = dsicm_wake_up(ddata);
 
-		in->ops.dsi->bus_unlock(in);
+		src->ops->dsi.bus_unlock(src);
 	}
 
 	mutex_unlock(&ddata->lock);
@@ -528,7 +528,7 @@ static ssize_t dsicm_store_ulps_timeout(struct device *dev,
 {
 	struct platform_device *pdev = to_platform_device(dev);
 	struct panel_drv_data *ddata = platform_get_drvdata(pdev);
-	struct omap_dss_device *in = ddata->in;
+	struct omap_dss_device *src = ddata->dssdev.src;
 	unsigned long t;
 	int r;
 
@@ -541,9 +541,9 @@ static ssize_t dsicm_store_ulps_timeout(struct device *dev,
 
 	if (ddata->enabled) {
 		/* dsicm_wake_up will restart the timer */
-		in->ops.dsi->bus_lock(in);
+		src->ops->dsi.bus_lock(src);
 		r = dsicm_wake_up(ddata);
-		in->ops.dsi->bus_unlock(in);
+		src->ops->dsi.bus_unlock(src);
 	}
 
 	mutex_unlock(&ddata->lock);
@@ -603,7 +603,7 @@ static void dsicm_hw_reset(struct panel_drv_data *ddata)
 
 static int dsicm_power_on(struct panel_drv_data *ddata)
 {
-	struct omap_dss_device *in = ddata->in;
+	struct omap_dss_device *src = ddata->dssdev.src;
 	u8 id1, id2, id3;
 	int r;
 	struct omap_dss_dsi_config dsi_config = {
@@ -635,7 +635,7 @@ static int dsicm_power_on(struct panel_drv_data *ddata)
 	}
 
 	if (ddata->pin_config.num_pins > 0) {
-		r = in->ops.dsi->configure_pins(in, &ddata->pin_config);
+		r = src->ops->dsi.configure_pins(src, &ddata->pin_config);
 		if (r) {
 			dev_err(&ddata->pdev->dev,
 				"failed to configure DSI pins\n");
@@ -643,13 +643,13 @@ static int dsicm_power_on(struct panel_drv_data *ddata)
 		}
 	}
 
-	r = in->ops.dsi->set_config(in, &dsi_config);
+	r = src->ops->dsi.set_config(src, &dsi_config);
 	if (r) {
 		dev_err(&ddata->pdev->dev, "failed to configure DSI\n");
 		goto err_vddi;
 	}
 
-	r = in->ops.dsi->enable(in);
+	r = src->ops->enable(src);
 	if (r) {
 		dev_err(&ddata->pdev->dev, "failed to enable DSI\n");
 		goto err_vddi;
@@ -657,7 +657,7 @@ static int dsicm_power_on(struct panel_drv_data *ddata)
 
 	dsicm_hw_reset(ddata);
 
-	in->ops.dsi->enable_hs(in, ddata->channel, false);
+	src->ops->dsi.enable_hs(src, ddata->channel, false);
 
 	r = dsicm_sleep_out(ddata);
 	if (r)
@@ -689,7 +689,7 @@ static int dsicm_power_on(struct panel_drv_data *ddata)
 	if (r)
 		goto err;
 
-	r = in->ops.dsi->enable_video_output(in, ddata->channel);
+	r = src->ops->dsi.enable_video_output(src, ddata->channel);
 	if (r)
 		goto err;
 
@@ -701,7 +701,7 @@ static int dsicm_power_on(struct panel_drv_data *ddata)
 		ddata->intro_printed = true;
 	}
 
-	in->ops.dsi->enable_hs(in, ddata->channel, true);
+	src->ops->dsi.enable_hs(src, ddata->channel, true);
 
 	return 0;
 err:
@@ -709,7 +709,7 @@ err:
 
 	dsicm_hw_reset(ddata);
 
-	in->ops.dsi->disable(in, true, false);
+	src->ops->dsi.disable(src, true, false);
 err_vddi:
 	if (ddata->vddi)
 		regulator_disable(ddata->vddi);
@@ -722,10 +722,10 @@ err_vpnl:
 
 static void dsicm_power_off(struct panel_drv_data *ddata)
 {
-	struct omap_dss_device *in = ddata->in;
+	struct omap_dss_device *src = ddata->dssdev.src;
 	int r;
 
-	in->ops.dsi->disable_video_output(in, ddata->channel);
+	src->ops->dsi.disable_video_output(src, ddata->channel);
 
 	r = dsicm_dcs_write_0(ddata, MIPI_DCS_SET_DISPLAY_OFF);
 	if (!r)
@@ -737,7 +737,7 @@ static void dsicm_power_off(struct panel_drv_data *ddata)
 		dsicm_hw_reset(ddata);
 	}
 
-	in->ops.dsi->disable(in, true, false);
+	src->ops->dsi.disable(src, true, false);
 
 	if (ddata->vddi)
 		regulator_disable(ddata->vddi);
@@ -756,71 +756,41 @@ static int dsicm_panel_reset(struct panel_drv_data *ddata)
 	return dsicm_power_on(ddata);
 }
 
-static int dsicm_connect(struct omap_dss_device *dssdev)
+static int dsicm_connect(struct omap_dss_device *src,
+			 struct omap_dss_device *dst)
 {
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
+	struct panel_drv_data *ddata = to_panel_data(dst);
 	struct device *dev = &ddata->pdev->dev;
-	struct omap_dss_device *in;
 	int r;
 
-	if (omapdss_device_is_connected(dssdev))
-		return 0;
-
-	in = omapdss_of_find_source_for_first_ep(dssdev->dev->of_node);
-	if (IS_ERR(in)) {
-		dev_err(dssdev->dev, "failed to find video source\n");
-		return PTR_ERR(in);
-	}
-
-	r = in->ops.dsi->connect(in, dssdev);
-	if (r) {
-		dev_err(dev, "Failed to connect to video source\n");
-		goto err_connect;
-	}
-
-	r = in->ops.dsi->request_vc(in, &ddata->channel);
+	r = src->ops->dsi.request_vc(src, &ddata->channel);
 	if (r) {
 		dev_err(dev, "failed to get virtual channel\n");
-		goto err_req_vc;
+		return r;
 	}
 
-	r = in->ops.dsi->set_vc_id(in, ddata->channel, TCH);
+	r = src->ops->dsi.set_vc_id(src, ddata->channel, TCH);
 	if (r) {
 		dev_err(dev, "failed to set VC_ID\n");
-		goto err_vc_id;
+		src->ops->dsi.release_vc(src, ddata->channel);
+		return r;
 	}
 
-	ddata->in = in;
 	return 0;
-
-err_vc_id:
-	in->ops.dsi->release_vc(in, ddata->channel);
-err_req_vc:
-	in->ops.dsi->disconnect(in, dssdev);
-err_connect:
-	omap_dss_put_device(in);
-	return r;
 }
 
-static void dsicm_disconnect(struct omap_dss_device *dssdev)
+static void dsicm_disconnect(struct omap_dss_device *src,
+			     struct omap_dss_device *dst)
 {
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
-
-	if (!omapdss_device_is_connected(dssdev))
-		return;
-
-	in->ops.dsi->release_vc(in, ddata->channel);
-	in->ops.dsi->disconnect(in, dssdev);
+	struct panel_drv_data *ddata = to_panel_data(dst);
 
-	omap_dss_put_device(in);
-	ddata->in = NULL;
+	src->ops->dsi.release_vc(src, ddata->channel);
 }
 
 static int dsicm_enable(struct omap_dss_device *dssdev)
 {
 	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
+	struct omap_dss_device *src = dssdev->src;
 	int r;
 
 	dev_dbg(&ddata->pdev->dev, "enable\n");
@@ -837,11 +807,11 @@ static int dsicm_enable(struct omap_dss_device *dssdev)
 		goto err;
 	}
 
-	in->ops.dsi->bus_lock(in);
+	src->ops->dsi.bus_lock(src);
 
 	r = dsicm_power_on(ddata);
 
-	in->ops.dsi->bus_unlock(in);
+	src->ops->dsi.bus_unlock(src);
 
 	if (r)
 		goto err;
@@ -862,7 +832,7 @@ err:
 static void dsicm_disable(struct omap_dss_device *dssdev)
 {
 	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
+	struct omap_dss_device *src = dssdev->src;
 	int r;
 
 	dev_dbg(&ddata->pdev->dev, "disable\n");
@@ -873,7 +843,7 @@ static void dsicm_disable(struct omap_dss_device *dssdev)
 
 	dsicm_cancel_ulps_work(ddata);
 
-	in->ops.dsi->bus_lock(in);
+	src->ops->dsi.bus_lock(src);
 
 	if (omapdss_device_is_enabled(dssdev)) {
 		r = dsicm_wake_up(ddata);
@@ -881,7 +851,7 @@ static void dsicm_disable(struct omap_dss_device *dssdev)
 			dsicm_power_off(ddata);
 	}
 
-	in->ops.dsi->bus_unlock(in);
+	src->ops->dsi.bus_unlock(src);
 
 	dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
 
@@ -891,16 +861,16 @@ static void dsicm_disable(struct omap_dss_device *dssdev)
 static void dsicm_framedone_cb(int err, void *data)
 {
 	struct panel_drv_data *ddata = data;
-	struct omap_dss_device *in = ddata->in;
+	struct omap_dss_device *src = ddata->dssdev.src;
 
 	dev_dbg(&ddata->pdev->dev, "framedone, err %d\n", err);
-	in->ops.dsi->bus_unlock(ddata->in);
+	src->ops->dsi.bus_unlock(src);
 }
 
 static irqreturn_t dsicm_te_isr(int irq, void *data)
 {
 	struct panel_drv_data *ddata = data;
-	struct omap_dss_device *in = ddata->in;
+	struct omap_dss_device *src = ddata->dssdev.src;
 	int old;
 	int r;
 
@@ -909,7 +879,7 @@ static irqreturn_t dsicm_te_isr(int irq, void *data)
 	if (old) {
 		cancel_delayed_work(&ddata->te_timeout_work);
 
-		r = in->ops.dsi->update(in, ddata->channel, dsicm_framedone_cb,
+		r = src->ops->dsi.update(src, ddata->channel, dsicm_framedone_cb,
 				ddata);
 		if (r)
 			goto err;
@@ -918,7 +888,7 @@ static irqreturn_t dsicm_te_isr(int irq, void *data)
 	return IRQ_HANDLED;
 err:
 	dev_err(&ddata->pdev->dev, "start update failed\n");
-	in->ops.dsi->bus_unlock(in);
+	src->ops->dsi.bus_unlock(src);
 	return IRQ_HANDLED;
 }
 
@@ -926,25 +896,25 @@ static void dsicm_te_timeout_work_callback(struct work_struct *work)
 {
 	struct panel_drv_data *ddata = container_of(work, struct panel_drv_data,
 					te_timeout_work.work);
-	struct omap_dss_device *in = ddata->in;
+	struct omap_dss_device *src = ddata->dssdev.src;
 
 	dev_err(&ddata->pdev->dev, "TE not received for 250ms!\n");
 
 	atomic_set(&ddata->do_update, 0);
-	in->ops.dsi->bus_unlock(in);
+	src->ops->dsi.bus_unlock(src);
 }
 
 static int dsicm_update(struct omap_dss_device *dssdev,
 				    u16 x, u16 y, u16 w, u16 h)
 {
 	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
+	struct omap_dss_device *src = dssdev->src;
 	int r;
 
 	dev_dbg(&ddata->pdev->dev, "update %d, %d, %d x %d\n", x, y, w, h);
 
 	mutex_lock(&ddata->lock);
-	in->ops.dsi->bus_lock(in);
+	src->ops->dsi.bus_lock(src);
 
 	r = dsicm_wake_up(ddata);
 	if (r)
@@ -956,9 +926,8 @@ static int dsicm_update(struct omap_dss_device *dssdev,
 	}
 
 	/* XXX no need to send this every frame, but dsi break if not done */
-	r = dsicm_set_update_window(ddata, 0, 0,
-			dssdev->panel.vm.hactive,
-			dssdev->panel.vm.vactive);
+	r = dsicm_set_update_window(ddata, 0, 0, ddata->vm.hactive,
+				    ddata->vm.vactive);
 	if (r)
 		goto err;
 
@@ -967,17 +936,17 @@ static int dsicm_update(struct omap_dss_device *dssdev,
 				msecs_to_jiffies(250));
 		atomic_set(&ddata->do_update, 1);
 	} else {
-		r = in->ops.dsi->update(in, ddata->channel, dsicm_framedone_cb,
+		r = src->ops->dsi.update(src, ddata->channel, dsicm_framedone_cb,
 				ddata);
 		if (r)
 			goto err;
 	}
 
-	/* note: no bus_unlock here. unlock is in framedone_cb */
+	/* note: no bus_unlock here. unlock is src framedone_cb */
 	mutex_unlock(&ddata->lock);
 	return 0;
 err:
-	in->ops.dsi->bus_unlock(in);
+	src->ops->dsi.bus_unlock(src);
 	mutex_unlock(&ddata->lock);
 	return r;
 }
@@ -985,13 +954,13 @@ err:
 static int dsicm_sync(struct omap_dss_device *dssdev)
 {
 	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
+	struct omap_dss_device *src = dssdev->src;
 
 	dev_dbg(&ddata->pdev->dev, "sync\n");
 
 	mutex_lock(&ddata->lock);
-	in->ops.dsi->bus_lock(in);
-	in->ops.dsi->bus_unlock(in);
+	src->ops->dsi.bus_lock(src);
+	src->ops->dsi.bus_unlock(src);
 	mutex_unlock(&ddata->lock);
 
 	dev_dbg(&ddata->pdev->dev, "sync done\n");
@@ -1001,7 +970,7 @@ static int dsicm_sync(struct omap_dss_device *dssdev)
 
 static int _dsicm_enable_te(struct panel_drv_data *ddata, bool enable)
 {
-	struct omap_dss_device *in = ddata->in;
+	struct omap_dss_device *src = ddata->dssdev.src;
 	int r;
 
 	if (enable)
@@ -1010,7 +979,7 @@ static int _dsicm_enable_te(struct panel_drv_data *ddata, bool enable)
 		r = dsicm_dcs_write_0(ddata, MIPI_DCS_SET_TEAR_OFF);
 
 	if (!ddata->ext_te_gpio)
-		in->ops.dsi->enable_te(in, enable);
+		src->ops->dsi.enable_te(src, enable);
 
 	/* possible panel bug */
 	msleep(100);
@@ -1021,7 +990,7 @@ static int _dsicm_enable_te(struct panel_drv_data *ddata, bool enable)
 static int dsicm_enable_te(struct omap_dss_device *dssdev, bool enable)
 {
 	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
+	struct omap_dss_device *src = dssdev->src;
 	int r;
 
 	mutex_lock(&ddata->lock);
@@ -1029,7 +998,7 @@ static int dsicm_enable_te(struct omap_dss_device *dssdev, bool enable)
 	if (ddata->te_enabled == enable)
 		goto end;
 
-	in->ops.dsi->bus_lock(in);
+	src->ops->dsi.bus_lock(src);
 
 	if (ddata->enabled) {
 		r = dsicm_wake_up(ddata);
@@ -1043,13 +1012,13 @@ static int dsicm_enable_te(struct omap_dss_device *dssdev, bool enable)
 
 	ddata->te_enabled = enable;
 
-	in->ops.dsi->bus_unlock(in);
+	src->ops->dsi.bus_unlock(src);
 end:
 	mutex_unlock(&ddata->lock);
 
 	return 0;
 err:
-	in->ops.dsi->bus_unlock(in);
+	src->ops->dsi.bus_unlock(src);
 	mutex_unlock(&ddata->lock);
 
 	return r;
@@ -1072,7 +1041,7 @@ static int dsicm_memory_read(struct omap_dss_device *dssdev,
 		u16 x, u16 y, u16 w, u16 h)
 {
 	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
+	struct omap_dss_device *src = dssdev->src;
 	int r;
 	int first = 1;
 	int plen;
@@ -1089,9 +1058,9 @@ static int dsicm_memory_read(struct omap_dss_device *dssdev,
 	}
 
 	size = min((u32)w * h * 3,
-		   dssdev->panel.vm.hactive * dssdev->panel.vm.vactive * 3);
+		   ddata->vm.hactive * ddata->vm.vactive * 3);
 
-	in->ops.dsi->bus_lock(in);
+	src->ops->dsi.bus_lock(src);
 
 	r = dsicm_wake_up(ddata);
 	if (r)
@@ -1107,7 +1076,7 @@ static int dsicm_memory_read(struct omap_dss_device *dssdev,
 
 	dsicm_set_update_window(ddata, x, y, w, h);
 
-	r = in->ops.dsi->set_max_rx_packet_size(in, ddata->channel, plen);
+	r = src->ops->dsi.set_max_rx_packet_size(src, ddata->channel, plen);
 	if (r)
 		goto err2;
 
@@ -1115,7 +1084,7 @@ static int dsicm_memory_read(struct omap_dss_device *dssdev,
 		u8 dcs_cmd = first ? 0x2e : 0x3e;
 		first = 0;
 
-		r = in->ops.dsi->dcs_read(in, ddata->channel, dcs_cmd,
+		r = src->ops->dsi.dcs_read(src, ddata->channel, dcs_cmd,
 				buf + buf_used, size - buf_used);
 
 		if (r < 0) {
@@ -1141,9 +1110,9 @@ static int dsicm_memory_read(struct omap_dss_device *dssdev,
 	r = buf_used;
 
 err3:
-	in->ops.dsi->set_max_rx_packet_size(in, ddata->channel, 1);
+	src->ops->dsi.set_max_rx_packet_size(src, ddata->channel, 1);
 err2:
-	in->ops.dsi->bus_unlock(in);
+	src->ops->dsi.bus_unlock(src);
 err1:
 	mutex_unlock(&ddata->lock);
 	return r;
@@ -1154,7 +1123,7 @@ static void dsicm_ulps_work(struct work_struct *work)
 	struct panel_drv_data *ddata = container_of(work, struct panel_drv_data,
 			ulps_work.work);
 	struct omap_dss_device *dssdev = &ddata->dssdev;
-	struct omap_dss_device *in = ddata->in;
+	struct omap_dss_device *src = dssdev->src;
 
 	mutex_lock(&ddata->lock);
 
@@ -1163,11 +1132,11 @@ static void dsicm_ulps_work(struct work_struct *work)
 		return;
 	}
 
-	in->ops.dsi->bus_lock(in);
+	src->ops->dsi.bus_lock(src);
 
 	dsicm_enter_ulps(ddata);
 
-	in->ops.dsi->bus_unlock(in);
+	src->ops->dsi.bus_unlock(src);
 	mutex_unlock(&ddata->lock);
 }
 
@@ -1210,18 +1179,21 @@ static void dsicm_get_size(struct omap_dss_device *dssdev,
 	*height = ddata->height_mm;
 }
 
-static struct omap_dss_driver dsicm_ops = {
+static const struct omap_dss_device_ops dsicm_ops = {
 	.connect	= dsicm_connect,
 	.disconnect	= dsicm_disconnect,
 
 	.enable		= dsicm_enable,
 	.disable	= dsicm_disable,
 
+	.get_timings	= dsicm_get_timings,
+	.check_timings	= dsicm_check_timings,
+};
+
+static const struct omap_dss_driver dsicm_dss_driver = {
 	.update		= dsicm_update,
 	.sync		= dsicm_sync,
 
-	.get_timings	= dsicm_get_timings,
-	.check_timings	= dsicm_check_timings,
 	.get_size	= dsicm_get_size,
 
 	.enable_te	= dsicm_enable_te,
@@ -1330,20 +1302,17 @@ static int dsicm_probe(struct platform_device *pdev)
 
 	dssdev = &ddata->dssdev;
 	dssdev->dev = dev;
-	dssdev->driver = &dsicm_ops;
-	dssdev->panel.vm = ddata->vm;
+	dssdev->ops = &dsicm_ops;
+	dssdev->driver = &dsicm_dss_driver;
 	dssdev->type = OMAP_DISPLAY_TYPE_DSI;
 	dssdev->owner = THIS_MODULE;
+	dssdev->of_ports = BIT(0);
 
-	dssdev->panel.dsi_pix_fmt = OMAP_DSS_DSI_FMT_RGB888;
 	dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE |
 		OMAP_DSS_DISPLAY_CAP_TEAR_ELIM;
 
-	r = omapdss_register_display(dssdev);
-	if (r) {
-		dev_err(dev, "Failed to register panel\n");
-		goto err_reg;
-	}
+	omapdss_display_init(dssdev);
+	omapdss_device_register(dssdev);
 
 	mutex_init(&ddata->lock);
 
@@ -1414,10 +1383,10 @@ static int __exit dsicm_remove(struct platform_device *pdev)
 
 	dev_dbg(&pdev->dev, "remove\n");
 
-	omapdss_unregister_display(dssdev);
+	omapdss_device_unregister(dssdev);
 
 	dsicm_disable(dssdev);
-	dsicm_disconnect(dssdev);
+	omapdss_device_disconnect(dssdev->src, dssdev);
 
 	sysfs_remove_group(&pdev->dev.kobj, &dsicm_attr_group);
 

+ 24 - 79
drivers/gpu/drm/omapdrm/displays/panel-lgphilips-lb035q02.c

@@ -33,19 +33,11 @@ static const struct videomode lb035q02_vm = {
 	.vfront_porch	= 4,
 	.vback_porch	= 18,
 
-	.flags		= DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW |
-			  DISPLAY_FLAGS_DE_HIGH | DISPLAY_FLAGS_SYNC_NEGEDGE |
-			  DISPLAY_FLAGS_PIXDATA_POSEDGE,
-	/*
-	 * Note: According to the panel documentation:
-	 * DE is active LOW
-	 * DATA needs to be driven on the FALLING edge
-	 */
+	.flags		= DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW,
 };
 
 struct panel_drv_data {
 	struct omap_dss_device dssdev;
-	struct omap_dss_device *in;
 
 	struct spi_device *spi;
 
@@ -116,51 +108,25 @@ static void init_lb035q02_panel(struct spi_device *spi)
 	lb035q02_write_reg(spi, 0x3b, 0x0806);
 }
 
-static int lb035q02_connect(struct omap_dss_device *dssdev)
+static int lb035q02_connect(struct omap_dss_device *src,
+			    struct omap_dss_device *dst)
 {
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in;
-	int r;
-
-	if (omapdss_device_is_connected(dssdev))
-		return 0;
-
-	in = omapdss_of_find_source_for_first_ep(dssdev->dev->of_node);
-	if (IS_ERR(in)) {
-		dev_err(dssdev->dev, "failed to find video source\n");
-		return PTR_ERR(in);
-	}
-
-	r = in->ops.dpi->connect(in, dssdev);
-	if (r) {
-		omap_dss_put_device(in);
-		return r;
-	}
+	struct panel_drv_data *ddata = to_panel_data(dst);
 
 	init_lb035q02_panel(ddata->spi);
 
-	ddata->in = in;
 	return 0;
 }
 
-static void lb035q02_disconnect(struct omap_dss_device *dssdev)
+static void lb035q02_disconnect(struct omap_dss_device *src,
+				struct omap_dss_device *dst)
 {
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
-
-	if (!omapdss_device_is_connected(dssdev))
-		return;
-
-	in->ops.dpi->disconnect(in, dssdev);
-
-	omap_dss_put_device(in);
-	ddata->in = NULL;
 }
 
 static int lb035q02_enable(struct omap_dss_device *dssdev)
 {
 	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
+	struct omap_dss_device *src = dssdev->src;
 	int r;
 
 	if (!omapdss_device_is_connected(dssdev))
@@ -169,9 +135,7 @@ static int lb035q02_enable(struct omap_dss_device *dssdev)
 	if (omapdss_device_is_enabled(dssdev))
 		return 0;
 
-	in->ops.dpi->set_timings(in, &ddata->vm);
-
-	r = in->ops.dpi->enable(in);
+	r = src->ops->enable(src);
 	if (r)
 		return r;
 
@@ -186,7 +150,7 @@ static int lb035q02_enable(struct omap_dss_device *dssdev)
 static void lb035q02_disable(struct omap_dss_device *dssdev)
 {
 	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
+	struct omap_dss_device *src = dssdev->src;
 
 	if (!omapdss_device_is_enabled(dssdev))
 		return;
@@ -194,23 +158,11 @@ static void lb035q02_disable(struct omap_dss_device *dssdev)
 	if (ddata->enable_gpio)
 		gpiod_set_value_cansleep(ddata->enable_gpio, 0);
 
-	in->ops.dpi->disable(in);
+	src->ops->disable(src);
 
 	dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
 }
 
-static void lb035q02_set_timings(struct omap_dss_device *dssdev,
-				 struct videomode *vm)
-{
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
-
-	ddata->vm = *vm;
-	dssdev->panel.vm = *vm;
-
-	in->ops.dpi->set_timings(in, vm);
-}
-
 static void lb035q02_get_timings(struct omap_dss_device *dssdev,
 				 struct videomode *vm)
 {
@@ -219,25 +171,14 @@ static void lb035q02_get_timings(struct omap_dss_device *dssdev,
 	*vm = ddata->vm;
 }
 
-static int lb035q02_check_timings(struct omap_dss_device *dssdev,
-				  struct videomode *vm)
-{
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
-
-	return in->ops.dpi->check_timings(in, vm);
-}
-
-static struct omap_dss_driver lb035q02_ops = {
+static const struct omap_dss_device_ops lb035q02_ops = {
 	.connect	= lb035q02_connect,
 	.disconnect	= lb035q02_disconnect,
 
 	.enable		= lb035q02_enable,
 	.disable	= lb035q02_disable,
 
-	.set_timings	= lb035q02_set_timings,
 	.get_timings	= lb035q02_get_timings,
-	.check_timings	= lb035q02_check_timings,
 };
 
 static int lb035q02_probe_of(struct spi_device *spi)
@@ -278,16 +219,21 @@ static int lb035q02_panel_spi_probe(struct spi_device *spi)
 
 	dssdev = &ddata->dssdev;
 	dssdev->dev = &spi->dev;
-	dssdev->driver = &lb035q02_ops;
+	dssdev->ops = &lb035q02_ops;
 	dssdev->type = OMAP_DISPLAY_TYPE_DPI;
 	dssdev->owner = THIS_MODULE;
-	dssdev->panel.vm = ddata->vm;
+	dssdev->of_ports = BIT(0);
 
-	r = omapdss_register_display(dssdev);
-	if (r) {
-		dev_err(&spi->dev, "Failed to register panel\n");
-		return r;
-	}
+	/*
+	 * Note: According to the panel documentation:
+	 * DE is active LOW
+	 * DATA needs to be driven on the FALLING edge
+	 */
+	dssdev->bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_SYNC_NEGEDGE
+			  | DRM_BUS_FLAG_PIXDATA_POSEDGE;
+
+	omapdss_display_init(dssdev);
+	omapdss_device_register(dssdev);
 
 	return 0;
 }
@@ -297,10 +243,9 @@ static int lb035q02_panel_spi_remove(struct spi_device *spi)
 	struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
 	struct omap_dss_device *dssdev = &ddata->dssdev;
 
-	omapdss_unregister_display(dssdev);
+	omapdss_device_unregister(dssdev);
 
 	lb035q02_disable(dssdev);
-	lb035q02_disconnect(dssdev);
 
 	return 0;
 }

+ 28 - 118
drivers/gpu/drm/omapdrm/displays/panel-nec-nl8048hl11.c

@@ -11,22 +11,19 @@
  * (at your option) any later version.
  */
 
-#include <linux/module.h>
 #include <linux/delay.h>
-#include <linux/spi/spi.h>
 #include <linux/gpio/consumer.h>
-#include <linux/of_gpio.h>
+#include <linux/module.h>
+#include <linux/spi/spi.h>
 
 #include "../dss/omapdss.h"
 
 struct panel_drv_data {
 	struct omap_dss_device	dssdev;
-	struct omap_dss_device *in;
 
 	struct videomode vm;
 
-	int res_gpio;
-	int qvga_gpio;
+	struct gpio_desc *res_gpio;
 
 	struct spi_device *spi;
 };
@@ -74,9 +71,7 @@ static const struct videomode nec_8048_panel_vm = {
 	.vsync_len	= 1,
 	.vback_porch	= 4,
 
-	.flags		= DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW |
-			  DISPLAY_FLAGS_DE_HIGH | DISPLAY_FLAGS_SYNC_POSEDGE |
-			  DISPLAY_FLAGS_PIXDATA_POSEDGE,
+	.flags		= DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW,
 };
 
 #define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev)
@@ -112,49 +107,21 @@ static int init_nec_8048_wvga_lcd(struct spi_device *spi)
 	return 0;
 }
 
-static int nec_8048_connect(struct omap_dss_device *dssdev)
+static int nec_8048_connect(struct omap_dss_device *src,
+			    struct omap_dss_device *dst)
 {
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in;
-	int r;
-
-	if (omapdss_device_is_connected(dssdev))
-		return 0;
-
-	in = omapdss_of_find_source_for_first_ep(dssdev->dev->of_node);
-	if (IS_ERR(in)) {
-		dev_err(dssdev->dev, "failed to find video source\n");
-		return PTR_ERR(in);
-	}
-
-	r = in->ops.dpi->connect(in, dssdev);
-	if (r) {
-		omap_dss_put_device(in);
-		return r;
-	}
-
-	ddata->in = in;
 	return 0;
 }
 
-static void nec_8048_disconnect(struct omap_dss_device *dssdev)
+static void nec_8048_disconnect(struct omap_dss_device *src,
+				struct omap_dss_device *dst)
 {
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
-
-	if (!omapdss_device_is_connected(dssdev))
-		return;
-
-	in->ops.dpi->disconnect(in, dssdev);
-
-	omap_dss_put_device(in);
-	ddata->in = NULL;
 }
 
 static int nec_8048_enable(struct omap_dss_device *dssdev)
 {
 	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
+	struct omap_dss_device *src = dssdev->src;
 	int r;
 
 	if (!omapdss_device_is_connected(dssdev))
@@ -163,14 +130,11 @@ static int nec_8048_enable(struct omap_dss_device *dssdev)
 	if (omapdss_device_is_enabled(dssdev))
 		return 0;
 
-	in->ops.dpi->set_timings(in, &ddata->vm);
-
-	r = in->ops.dpi->enable(in);
+	r = src->ops->enable(src);
 	if (r)
 		return r;
 
-	if (gpio_is_valid(ddata->res_gpio))
-		gpio_set_value_cansleep(ddata->res_gpio, 1);
+	gpiod_set_value_cansleep(ddata->res_gpio, 1);
 
 	dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
 
@@ -180,31 +144,18 @@ static int nec_8048_enable(struct omap_dss_device *dssdev)
 static void nec_8048_disable(struct omap_dss_device *dssdev)
 {
 	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
+	struct omap_dss_device *src = dssdev->src;
 
 	if (!omapdss_device_is_enabled(dssdev))
 		return;
 
-	if (gpio_is_valid(ddata->res_gpio))
-		gpio_set_value_cansleep(ddata->res_gpio, 0);
+	gpiod_set_value_cansleep(ddata->res_gpio, 0);
 
-	in->ops.dpi->disable(in);
+	src->ops->disable(src);
 
 	dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
 }
 
-static void nec_8048_set_timings(struct omap_dss_device *dssdev,
-				 struct videomode *vm)
-{
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
-
-	ddata->vm = *vm;
-	dssdev->panel.vm = *vm;
-
-	in->ops.dpi->set_timings(in, vm);
-}
-
 static void nec_8048_get_timings(struct omap_dss_device *dssdev,
 				 struct videomode *vm)
 {
@@ -213,50 +164,21 @@ static void nec_8048_get_timings(struct omap_dss_device *dssdev,
 	*vm = ddata->vm;
 }
 
-static int nec_8048_check_timings(struct omap_dss_device *dssdev,
-				  struct videomode *vm)
-{
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
-
-	return in->ops.dpi->check_timings(in, vm);
-}
-
-static struct omap_dss_driver nec_8048_ops = {
+static const struct omap_dss_device_ops nec_8048_ops = {
 	.connect	= nec_8048_connect,
 	.disconnect	= nec_8048_disconnect,
 
 	.enable		= nec_8048_enable,
 	.disable	= nec_8048_disable,
 
-	.set_timings	= nec_8048_set_timings,
 	.get_timings	= nec_8048_get_timings,
-	.check_timings	= nec_8048_check_timings,
 };
 
-static int nec_8048_probe_of(struct spi_device *spi)
-{
-	struct device_node *node = spi->dev.of_node;
-	struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
-	int gpio;
-
-	gpio = of_get_named_gpio(node, "reset-gpios", 0);
-	if (!gpio_is_valid(gpio)) {
-		dev_err(&spi->dev, "failed to parse enable gpio\n");
-		return gpio;
-	}
-	ddata->res_gpio = gpio;
-
-	/* XXX the panel spec doesn't mention any QVGA pin?? */
-	ddata->qvga_gpio = -ENOENT;
-
-	return 0;
-}
-
 static int nec_8048_probe(struct spi_device *spi)
 {
 	struct panel_drv_data *ddata;
 	struct omap_dss_device *dssdev;
+	struct gpio_desc *gpio;
 	int r;
 
 	dev_dbg(&spi->dev, "%s\n", __func__);
@@ -280,38 +202,27 @@ static int nec_8048_probe(struct spi_device *spi)
 
 	ddata->spi = spi;
 
-	r = nec_8048_probe_of(spi);
-	if (r)
-		return r;
-
-	if (gpio_is_valid(ddata->qvga_gpio)) {
-		r = devm_gpio_request_one(&spi->dev, ddata->qvga_gpio,
-				GPIOF_OUT_INIT_HIGH, "lcd QVGA");
-		if (r)
-			return r;
+	gpio = devm_gpiod_get(&spi->dev, "reset", GPIOD_OUT_LOW);
+	if (IS_ERR(gpio)) {
+		dev_err(&spi->dev, "failed to get reset gpio\n");
+		return PTR_ERR(gpio);
 	}
 
-	if (gpio_is_valid(ddata->res_gpio)) {
-		r = devm_gpio_request_one(&spi->dev, ddata->res_gpio,
-				GPIOF_OUT_INIT_LOW, "lcd RES");
-		if (r)
-			return r;
-	}
+	ddata->res_gpio = gpio;
 
 	ddata->vm = nec_8048_panel_vm;
 
 	dssdev = &ddata->dssdev;
 	dssdev->dev = &spi->dev;
-	dssdev->driver = &nec_8048_ops;
+	dssdev->ops = &nec_8048_ops;
 	dssdev->type = OMAP_DISPLAY_TYPE_DPI;
 	dssdev->owner = THIS_MODULE;
-	dssdev->panel.vm = ddata->vm;
+	dssdev->of_ports = BIT(0);
+	dssdev->bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_SYNC_POSEDGE
+			  | DRM_BUS_FLAG_PIXDATA_POSEDGE;
 
-	r = omapdss_register_display(dssdev);
-	if (r) {
-		dev_err(&spi->dev, "Failed to register panel\n");
-		return r;
-	}
+	omapdss_display_init(dssdev);
+	omapdss_device_register(dssdev);
 
 	return 0;
 }
@@ -323,10 +234,9 @@ static int nec_8048_remove(struct spi_device *spi)
 
 	dev_dbg(&ddata->spi->dev, "%s\n", __func__);
 
-	omapdss_unregister_display(dssdev);
+	omapdss_device_unregister(dssdev);
 
 	nec_8048_disable(dssdev);
-	nec_8048_disconnect(dssdev);
 
 	return 0;
 }

+ 22 - 79
drivers/gpu/drm/omapdrm/displays/panel-sharp-ls037v7dw01.c

@@ -21,7 +21,6 @@
 
 struct panel_drv_data {
 	struct omap_dss_device dssdev;
-	struct omap_dss_device *in;
 	struct regulator *vcc;
 
 	struct videomode vm;
@@ -47,60 +46,26 @@ static const struct videomode sharp_ls_vm = {
 	.vfront_porch	= 1,
 	.vback_porch	= 1,
 
-	.flags		= DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW |
-			  DISPLAY_FLAGS_DE_HIGH | DISPLAY_FLAGS_SYNC_NEGEDGE |
-			  DISPLAY_FLAGS_PIXDATA_POSEDGE,
-	/*
-	 * Note: According to the panel documentation:
-	 * DATA needs to be driven on the FALLING edge
-	 */
+	.flags		= DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW,
 };
 
 #define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev)
 
-static int sharp_ls_connect(struct omap_dss_device *dssdev)
+static int sharp_ls_connect(struct omap_dss_device *src,
+			    struct omap_dss_device *dst)
 {
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in;
-	int r;
-
-	if (omapdss_device_is_connected(dssdev))
-		return 0;
-
-	in = omapdss_of_find_source_for_first_ep(dssdev->dev->of_node);
-	if (IS_ERR(in)) {
-		dev_err(dssdev->dev, "failed to find video source\n");
-		return PTR_ERR(in);
-	}
-
-	r = in->ops.dpi->connect(in, dssdev);
-	if (r) {
-		omap_dss_put_device(in);
-		return r;
-	}
-
-	ddata->in = in;
 	return 0;
 }
 
-static void sharp_ls_disconnect(struct omap_dss_device *dssdev)
+static void sharp_ls_disconnect(struct omap_dss_device *src,
+				struct omap_dss_device *dst)
 {
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
-
-	if (!omapdss_device_is_connected(dssdev))
-		return;
-
-	in->ops.dpi->disconnect(in, dssdev);
-
-	omap_dss_put_device(in);
-	ddata->in = NULL;
 }
 
 static int sharp_ls_enable(struct omap_dss_device *dssdev)
 {
 	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
+	struct omap_dss_device *src = dssdev->src;
 	int r;
 
 	if (!omapdss_device_is_connected(dssdev))
@@ -109,15 +74,13 @@ static int sharp_ls_enable(struct omap_dss_device *dssdev)
 	if (omapdss_device_is_enabled(dssdev))
 		return 0;
 
-	in->ops.dpi->set_timings(in, &ddata->vm);
-
 	if (ddata->vcc) {
 		r = regulator_enable(ddata->vcc);
 		if (r != 0)
 			return r;
 	}
 
-	r = in->ops.dpi->enable(in);
+	r = src->ops->enable(src);
 	if (r) {
 		regulator_disable(ddata->vcc);
 		return r;
@@ -140,7 +103,7 @@ static int sharp_ls_enable(struct omap_dss_device *dssdev)
 static void sharp_ls_disable(struct omap_dss_device *dssdev)
 {
 	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
+	struct omap_dss_device *src = dssdev->src;
 
 	if (!omapdss_device_is_enabled(dssdev))
 		return;
@@ -155,7 +118,7 @@ static void sharp_ls_disable(struct omap_dss_device *dssdev)
 
 	msleep(100);
 
-	in->ops.dpi->disable(in);
+	src->ops->disable(src);
 
 	if (ddata->vcc)
 		regulator_disable(ddata->vcc);
@@ -163,18 +126,6 @@ static void sharp_ls_disable(struct omap_dss_device *dssdev)
 	dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
 }
 
-static void sharp_ls_set_timings(struct omap_dss_device *dssdev,
-				 struct videomode *vm)
-{
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
-
-	ddata->vm = *vm;
-	dssdev->panel.vm = *vm;
-
-	in->ops.dpi->set_timings(in, vm);
-}
-
 static void sharp_ls_get_timings(struct omap_dss_device *dssdev,
 				 struct videomode *vm)
 {
@@ -183,25 +134,14 @@ static void sharp_ls_get_timings(struct omap_dss_device *dssdev,
 	*vm = ddata->vm;
 }
 
-static int sharp_ls_check_timings(struct omap_dss_device *dssdev,
-				  struct videomode *vm)
-{
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
-
-	return in->ops.dpi->check_timings(in, vm);
-}
-
-static struct omap_dss_driver sharp_ls_ops = {
+static const struct omap_dss_device_ops sharp_ls_ops = {
 	.connect	= sharp_ls_connect,
 	.disconnect	= sharp_ls_disconnect,
 
 	.enable		= sharp_ls_enable,
 	.disable	= sharp_ls_disable,
 
-	.set_timings	= sharp_ls_set_timings,
 	.get_timings	= sharp_ls_get_timings,
-	.check_timings	= sharp_ls_check_timings,
 };
 
 static  int sharp_ls_get_gpio_of(struct device *dev, int index, int val,
@@ -278,16 +218,20 @@ static int sharp_ls_probe(struct platform_device *pdev)
 
 	dssdev = &ddata->dssdev;
 	dssdev->dev = &pdev->dev;
-	dssdev->driver = &sharp_ls_ops;
+	dssdev->ops = &sharp_ls_ops;
 	dssdev->type = OMAP_DISPLAY_TYPE_DPI;
 	dssdev->owner = THIS_MODULE;
-	dssdev->panel.vm = ddata->vm;
+	dssdev->of_ports = BIT(0);
 
-	r = omapdss_register_display(dssdev);
-	if (r) {
-		dev_err(&pdev->dev, "Failed to register panel\n");
-		return r;
-	}
+	/*
+	 * Note: According to the panel documentation:
+	 * DATA needs to be driven on the FALLING edge
+	 */
+	dssdev->bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_SYNC_NEGEDGE
+			  | DRM_BUS_FLAG_PIXDATA_POSEDGE;
+
+	omapdss_display_init(dssdev);
+	omapdss_device_register(dssdev);
 
 	return 0;
 }
@@ -297,10 +241,9 @@ static int __exit sharp_ls_remove(struct platform_device *pdev)
 	struct panel_drv_data *ddata = platform_get_drvdata(pdev);
 	struct omap_dss_device *dssdev = &ddata->dssdev;
 
-	omapdss_unregister_display(dssdev);
+	omapdss_device_unregister(dssdev);
 
 	sharp_ls_disable(dssdev);
-	sharp_ls_disconnect(dssdev);
 
 	return 0;
 }

+ 43 - 122
drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c

@@ -20,17 +20,15 @@
  * this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <linux/backlight.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/jiffies.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
-#include <linux/delay.h>
-#include <linux/spi/spi.h>
-#include <linux/jiffies.h>
 #include <linux/sched.h>
-#include <linux/backlight.h>
-#include <linux/gpio/consumer.h>
-#include <linux/of.h>
-#include <linux/of_gpio.h>
+#include <linux/spi/spi.h>
 
 #include "../dss/omapdss.h"
 
@@ -64,9 +62,8 @@
 
 struct panel_drv_data {
 	struct omap_dss_device	dssdev;
-	struct omap_dss_device *in;
 
-	int reset_gpio;
+	struct gpio_desc *reset_gpio;
 
 	struct videomode vm;
 
@@ -100,9 +97,7 @@ static const struct videomode acx565akm_panel_vm = {
 	.vsync_len	= 3,
 	.vback_porch	= 4,
 
-	.flags		= DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW |
-			  DISPLAY_FLAGS_DE_HIGH | DISPLAY_FLAGS_SYNC_NEGEDGE |
-			  DISPLAY_FLAGS_PIXDATA_POSEDGE,
+	.flags		= DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW,
 };
 
 #define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev)
@@ -507,56 +502,26 @@ static const struct attribute_group bldev_attr_group = {
 	.attrs = bldev_attrs,
 };
 
-static int acx565akm_connect(struct omap_dss_device *dssdev)
+static int acx565akm_connect(struct omap_dss_device *src,
+			     struct omap_dss_device *dst)
 {
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in;
-	int r;
-
-	if (omapdss_device_is_connected(dssdev))
-		return 0;
-
-	in = omapdss_of_find_source_for_first_ep(dssdev->dev->of_node);
-	if (IS_ERR(in)) {
-		dev_err(dssdev->dev, "failed to find video source\n");
-		return PTR_ERR(in);
-	}
-
-	r = in->ops.sdi->connect(in, dssdev);
-	if (r) {
-		omap_dss_put_device(in);
-		return r;
-	}
-
-	ddata->in = in;
 	return 0;
 }
 
-static void acx565akm_disconnect(struct omap_dss_device *dssdev)
+static void acx565akm_disconnect(struct omap_dss_device *src,
+				 struct omap_dss_device *dst)
 {
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
-
-	if (!omapdss_device_is_connected(dssdev))
-		return;
-
-	in->ops.sdi->disconnect(in, dssdev);
-
-	omap_dss_put_device(in);
-	ddata->in = NULL;
 }
 
 static int acx565akm_panel_power_on(struct omap_dss_device *dssdev)
 {
 	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
+	struct omap_dss_device *src = dssdev->src;
 	int r;
 
 	dev_dbg(&ddata->spi->dev, "%s\n", __func__);
 
-	in->ops.sdi->set_timings(in, &ddata->vm);
-
-	r = in->ops.sdi->enable(in);
+	r = src->ops->enable(src);
 	if (r) {
 		pr_err("%s sdi enable failed\n", __func__);
 		return r;
@@ -565,8 +530,8 @@ static int acx565akm_panel_power_on(struct omap_dss_device *dssdev)
 	/*FIXME tweak me */
 	msleep(50);
 
-	if (gpio_is_valid(ddata->reset_gpio))
-		gpio_set_value(ddata->reset_gpio, 1);
+	if (ddata->reset_gpio)
+		gpiod_set_value(ddata->reset_gpio, 1);
 
 	if (ddata->enabled) {
 		dev_dbg(&ddata->spi->dev, "panel already enabled\n");
@@ -597,7 +562,7 @@ static int acx565akm_panel_power_on(struct omap_dss_device *dssdev)
 static void acx565akm_panel_power_off(struct omap_dss_device *dssdev)
 {
 	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
+	struct omap_dss_device *src = dssdev->src;
 
 	dev_dbg(dssdev->dev, "%s\n", __func__);
 
@@ -615,13 +580,13 @@ static void acx565akm_panel_power_off(struct omap_dss_device *dssdev)
 	 */
 	msleep(50);
 
-	if (gpio_is_valid(ddata->reset_gpio))
-		gpio_set_value(ddata->reset_gpio, 0);
+	if (ddata->reset_gpio)
+		gpiod_set_value(ddata->reset_gpio, 0);
 
 	/* FIXME need to tweak this delay */
 	msleep(100);
 
-	in->ops.sdi->disable(in);
+	src->ops->disable(src);
 }
 
 static int acx565akm_enable(struct omap_dss_device *dssdev)
@@ -664,18 +629,6 @@ static void acx565akm_disable(struct omap_dss_device *dssdev)
 	dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
 }
 
-static void acx565akm_set_timings(struct omap_dss_device *dssdev,
-				  struct videomode *vm)
-{
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
-
-	ddata->vm = *vm;
-	dssdev->panel.vm = *vm;
-
-	in->ops.sdi->set_timings(in, vm);
-}
-
 static void acx565akm_get_timings(struct omap_dss_device *dssdev,
 				  struct videomode *vm)
 {
@@ -684,37 +637,16 @@ static void acx565akm_get_timings(struct omap_dss_device *dssdev,
 	*vm = ddata->vm;
 }
 
-static int acx565akm_check_timings(struct omap_dss_device *dssdev,
-				   struct videomode *vm)
-{
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
-
-	return in->ops.sdi->check_timings(in, vm);
-}
-
-static struct omap_dss_driver acx565akm_ops = {
+static const struct omap_dss_device_ops acx565akm_ops = {
 	.connect	= acx565akm_connect,
 	.disconnect	= acx565akm_disconnect,
 
 	.enable		= acx565akm_enable,
 	.disable	= acx565akm_disable,
 
-	.set_timings	= acx565akm_set_timings,
 	.get_timings	= acx565akm_get_timings,
-	.check_timings	= acx565akm_check_timings,
 };
 
-static int acx565akm_probe_of(struct spi_device *spi)
-{
-	struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
-	struct device_node *np = spi->dev.of_node;
-
-	ddata->reset_gpio = of_get_named_gpio(np, "reset-gpios", 0);
-
-	return 0;
-}
-
 static int acx565akm_probe(struct spi_device *spi)
 {
 	struct panel_drv_data *ddata;
@@ -722,6 +654,7 @@ static int acx565akm_probe(struct spi_device *spi)
 	struct backlight_device *bldev;
 	int max_brightness, brightness;
 	struct backlight_properties props;
+	struct gpio_desc *gpio;
 	int r;
 
 	dev_dbg(&spi->dev, "%s\n", __func__);
@@ -738,19 +671,16 @@ static int acx565akm_probe(struct spi_device *spi)
 
 	mutex_init(&ddata->mutex);
 
-	r = acx565akm_probe_of(spi);
-	if (r)
-		return r;
-
-	if (gpio_is_valid(ddata->reset_gpio)) {
-		r = devm_gpio_request_one(&spi->dev, ddata->reset_gpio,
-				GPIOF_OUT_INIT_LOW, "lcd reset");
-		if (r)
-			goto err_gpio;
+	gpio = devm_gpiod_get_optional(&spi->dev, "reset", GPIOD_OUT_LOW);
+	if (IS_ERR(gpio)) {
+		dev_err(&spi->dev, "failed to parse reset gpio\n");
+		return PTR_ERR(gpio);
 	}
 
-	if (gpio_is_valid(ddata->reset_gpio))
-		gpio_set_value(ddata->reset_gpio, 1);
+	ddata->reset_gpio = gpio;
+
+	if (ddata->reset_gpio)
+		gpiod_set_value(ddata->reset_gpio, 1);
 
 	/*
 	 * After reset we have to wait 5 msec before the first
@@ -762,12 +692,12 @@ static int acx565akm_probe(struct spi_device *spi)
 
 	r = panel_detect(ddata);
 
-	if (!ddata->enabled && gpio_is_valid(ddata->reset_gpio))
-		gpio_set_value(ddata->reset_gpio, 0);
+	if (!ddata->enabled && ddata->reset_gpio)
+		gpiod_set_value(ddata->reset_gpio, 0);
 
 	if (r) {
 		dev_err(&spi->dev, "%s panel detect error\n", __func__);
-		goto err_detect;
+		return r;
 	}
 
 	memset(&props, 0, sizeof(props));
@@ -777,17 +707,15 @@ static int acx565akm_probe(struct spi_device *spi)
 
 	bldev = backlight_device_register("acx565akm", &ddata->spi->dev,
 			ddata, &acx565akm_bl_ops, &props);
-	if (IS_ERR(bldev)) {
-		r = PTR_ERR(bldev);
-		goto err_reg_bl;
-	}
+	if (IS_ERR(bldev))
+		return PTR_ERR(bldev);
 	ddata->bl_dev = bldev;
 	if (ddata->has_cabc) {
 		r = sysfs_create_group(&bldev->dev.kobj, &bldev_attr_group);
 		if (r) {
 			dev_err(&bldev->dev,
 				"%s failed to create sysfs files\n", __func__);
-			goto err_sysfs;
+			goto err_backlight_unregister;
 		}
 		ddata->cabc_mode = get_hw_cabc_mode(ddata);
 	}
@@ -809,26 +737,20 @@ static int acx565akm_probe(struct spi_device *spi)
 
 	dssdev = &ddata->dssdev;
 	dssdev->dev = &spi->dev;
-	dssdev->driver = &acx565akm_ops;
+	dssdev->ops = &acx565akm_ops;
 	dssdev->type = OMAP_DISPLAY_TYPE_SDI;
 	dssdev->owner = THIS_MODULE;
-	dssdev->panel.vm = ddata->vm;
+	dssdev->of_ports = BIT(0);
+	dssdev->bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_SYNC_NEGEDGE
+			  | DRM_BUS_FLAG_PIXDATA_POSEDGE;
 
-	r = omapdss_register_display(dssdev);
-	if (r) {
-		dev_err(&spi->dev, "Failed to register panel\n");
-		goto err_reg;
-	}
+	omapdss_display_init(dssdev);
+	omapdss_device_register(dssdev);
 
 	return 0;
 
-err_reg:
-	sysfs_remove_group(&bldev->dev.kobj, &bldev_attr_group);
-err_sysfs:
+err_backlight_unregister:
 	backlight_device_unregister(bldev);
-err_reg_bl:
-err_detect:
-err_gpio:
 	return r;
 }
 
@@ -842,10 +764,9 @@ static int acx565akm_remove(struct spi_device *spi)
 	sysfs_remove_group(&ddata->bl_dev->dev.kobj, &bldev_attr_group);
 	backlight_device_unregister(ddata->bl_dev);
 
-	omapdss_unregister_display(dssdev);
+	omapdss_device_unregister(dssdev);
 
 	acx565akm_disable(dssdev);
-	acx565akm_disconnect(dssdev);
 
 	return 0;
 }

+ 22 - 80
drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c

@@ -27,13 +27,11 @@
 #include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/spi/spi.h>
-#include <linux/gpio.h>
 
 #include "../dss/omapdss.h"
 
 struct panel_drv_data {
 	struct omap_dss_device dssdev;
-	struct omap_dss_device *in;
 
 	struct videomode vm;
 
@@ -51,13 +49,7 @@ static const struct videomode td028ttec1_panel_vm = {
 	.vsync_len	= 2,
 	.vback_porch	= 2,
 
-	.flags		= DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW |
-			  DISPLAY_FLAGS_DE_HIGH | DISPLAY_FLAGS_SYNC_POSEDGE |
-			  DISPLAY_FLAGS_PIXDATA_NEGEDGE,
-	/*
-	 * Note: According to the panel documentation:
-	 * SYNC needs to be driven on the FALLING edge
-	 */
+	.flags		= DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW,
 };
 
 #define JBT_COMMAND	0x000
@@ -166,49 +158,21 @@ enum jbt_register {
 
 #define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev)
 
-static int td028ttec1_panel_connect(struct omap_dss_device *dssdev)
+static int td028ttec1_panel_connect(struct omap_dss_device *src,
+				    struct omap_dss_device *dst)
 {
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in;
-	int r;
-
-	if (omapdss_device_is_connected(dssdev))
-		return 0;
-
-	in = omapdss_of_find_source_for_first_ep(dssdev->dev->of_node);
-	if (IS_ERR(in)) {
-		dev_err(dssdev->dev, "failed to find video source\n");
-		return PTR_ERR(in);
-	}
-
-	r = in->ops.dpi->connect(in, dssdev);
-	if (r) {
-		omap_dss_put_device(in);
-		return r;
-	}
-
-	ddata->in = in;
 	return 0;
 }
 
-static void td028ttec1_panel_disconnect(struct omap_dss_device *dssdev)
+static void td028ttec1_panel_disconnect(struct omap_dss_device *src,
+					struct omap_dss_device *dst)
 {
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
-
-	if (!omapdss_device_is_connected(dssdev))
-		return;
-
-	in->ops.dpi->disconnect(in, dssdev);
-
-	omap_dss_put_device(in);
-	ddata->in = NULL;
 }
 
 static int td028ttec1_panel_enable(struct omap_dss_device *dssdev)
 {
 	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
+	struct omap_dss_device *src = dssdev->src;
 	int r;
 
 	if (!omapdss_device_is_connected(dssdev))
@@ -217,9 +181,7 @@ static int td028ttec1_panel_enable(struct omap_dss_device *dssdev)
 	if (omapdss_device_is_enabled(dssdev))
 		return 0;
 
-	in->ops.dpi->set_timings(in, &ddata->vm);
-
-	r = in->ops.dpi->enable(in);
+	r = src->ops->enable(src);
 	if (r)
 		return r;
 
@@ -316,7 +278,7 @@ transfer_err:
 static void td028ttec1_panel_disable(struct omap_dss_device *dssdev)
 {
 	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
+	struct omap_dss_device *src = dssdev->src;
 
 	if (!omapdss_device_is_enabled(dssdev))
 		return;
@@ -328,23 +290,11 @@ static void td028ttec1_panel_disable(struct omap_dss_device *dssdev)
 	jbt_ret_write_0(ddata, JBT_REG_SLEEP_IN);
 	jbt_reg_write_1(ddata, JBT_REG_POWER_ON_OFF, 0x00);
 
-	in->ops.dpi->disable(in);
+	src->ops->disable(src);
 
 	dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
 }
 
-static void td028ttec1_panel_set_timings(struct omap_dss_device *dssdev,
-					 struct videomode *vm)
-{
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
-
-	ddata->vm = *vm;
-	dssdev->panel.vm = *vm;
-
-	in->ops.dpi->set_timings(in, vm);
-}
-
 static void td028ttec1_panel_get_timings(struct omap_dss_device *dssdev,
 					 struct videomode *vm)
 {
@@ -353,25 +303,14 @@ static void td028ttec1_panel_get_timings(struct omap_dss_device *dssdev,
 	*vm = ddata->vm;
 }
 
-static int td028ttec1_panel_check_timings(struct omap_dss_device *dssdev,
-					  struct videomode *vm)
-{
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
-
-	return in->ops.dpi->check_timings(in, vm);
-}
-
-static struct omap_dss_driver td028ttec1_ops = {
+static const struct omap_dss_device_ops td028ttec1_ops = {
 	.connect	= td028ttec1_panel_connect,
 	.disconnect	= td028ttec1_panel_disconnect,
 
 	.enable		= td028ttec1_panel_enable,
 	.disable	= td028ttec1_panel_disable,
 
-	.set_timings	= td028ttec1_panel_set_timings,
 	.get_timings	= td028ttec1_panel_get_timings,
-	.check_timings	= td028ttec1_panel_check_timings,
 };
 
 static int td028ttec1_panel_probe(struct spi_device *spi)
@@ -403,16 +342,20 @@ static int td028ttec1_panel_probe(struct spi_device *spi)
 
 	dssdev = &ddata->dssdev;
 	dssdev->dev = &spi->dev;
-	dssdev->driver = &td028ttec1_ops;
+	dssdev->ops = &td028ttec1_ops;
 	dssdev->type = OMAP_DISPLAY_TYPE_DPI;
 	dssdev->owner = THIS_MODULE;
-	dssdev->panel.vm = ddata->vm;
+	dssdev->of_ports = BIT(0);
 
-	r = omapdss_register_display(dssdev);
-	if (r) {
-		dev_err(&spi->dev, "Failed to register panel\n");
-		return r;
-	}
+	/*
+	 * Note: According to the panel documentation:
+	 * SYNC needs to be driven on the FALLING edge
+	 */
+	dssdev->bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_SYNC_POSEDGE
+			  | DRM_BUS_FLAG_PIXDATA_NEGEDGE;
+
+	omapdss_display_init(dssdev);
+	omapdss_device_register(dssdev);
 
 	return 0;
 }
@@ -424,10 +367,9 @@ static int td028ttec1_panel_remove(struct spi_device *spi)
 
 	dev_dbg(&ddata->spi_dev->dev, "%s\n", __func__);
 
-	omapdss_unregister_display(dssdev);
+	omapdss_device_unregister(dssdev);
 
 	td028ttec1_panel_disable(dssdev);
-	td028ttec1_panel_disconnect(dssdev);
 
 	return 0;
 }

+ 41 - 151
drivers/gpu/drm/omapdrm/displays/panel-tpo-td043mtea1.c

@@ -10,14 +10,13 @@
  * (at your option) any later version.
  */
 
-#include <linux/module.h>
 #include <linux/delay.h>
-#include <linux/spi/spi.h>
-#include <linux/regulator/consumer.h>
-#include <linux/gpio/consumer.h>
 #include <linux/err.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/regulator/consumer.h>
 #include <linux/slab.h>
-#include <linux/of_gpio.h>
+#include <linux/spi/spi.h>
 
 #include "../dss/omapdss.h"
 
@@ -54,16 +53,14 @@ static const u16 tpo_td043_def_gamma[12] = {
 
 struct panel_drv_data {
 	struct omap_dss_device	dssdev;
-	struct omap_dss_device *in;
 
 	struct videomode vm;
 
 	struct spi_device *spi;
 	struct regulator *vcc_reg;
-	int nreset_gpio;
+	struct gpio_desc *reset_gpio;
 	u16 gamma[12];
 	u32 mode;
-	u32 hmirror:1;
 	u32 vmirror:1;
 	u32 powered_on:1;
 	u32 spi_suspended:1;
@@ -84,13 +81,7 @@ static const struct videomode tpo_td043_vm = {
 	.vfront_porch	= 39,
 	.vback_porch	= 34,
 
-	.flags		= DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW |
-			  DISPLAY_FLAGS_DE_HIGH | DISPLAY_FLAGS_SYNC_POSEDGE |
-			  DISPLAY_FLAGS_PIXDATA_NEGEDGE,
-	/*
-	 * Note: According to the panel documentation:
-	 * SYNC needs to be driven on the FALLING edge
-	 */
+	.flags		= DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW,
 };
 
 #define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev)
@@ -152,22 +143,6 @@ static int tpo_td043_write_mirror(struct spi_device *spi, bool h, bool v)
 	return tpo_td043_write(spi, 4, reg4);
 }
 
-static int tpo_td043_set_hmirror(struct omap_dss_device *dssdev, bool enable)
-{
-	struct panel_drv_data *ddata = dev_get_drvdata(dssdev->dev);
-
-	ddata->hmirror = enable;
-	return tpo_td043_write_mirror(ddata->spi, ddata->hmirror,
-			ddata->vmirror);
-}
-
-static bool tpo_td043_get_hmirror(struct omap_dss_device *dssdev)
-{
-	struct panel_drv_data *ddata = dev_get_drvdata(dssdev->dev);
-
-	return ddata->hmirror;
-}
-
 static ssize_t tpo_td043_vmirror_show(struct device *dev,
 	struct device_attribute *attr, char *buf)
 {
@@ -189,7 +164,7 @@ static ssize_t tpo_td043_vmirror_store(struct device *dev,
 
 	val = !!val;
 
-	ret = tpo_td043_write_mirror(ddata->spi, ddata->hmirror, val);
+	ret = tpo_td043_write_mirror(ddata->spi, false, val);
 	if (ret < 0)
 		return ret;
 
@@ -300,16 +275,14 @@ static int tpo_td043_power_on(struct panel_drv_data *ddata)
 	/* wait for panel to stabilize */
 	msleep(160);
 
-	if (gpio_is_valid(ddata->nreset_gpio))
-		gpio_set_value(ddata->nreset_gpio, 1);
+	gpiod_set_value(ddata->reset_gpio, 0);
 
 	tpo_td043_write(ddata->spi, 2,
 			TPO_R02_MODE(ddata->mode) | TPO_R02_NCLK_RISING);
 	tpo_td043_write(ddata->spi, 3, TPO_R03_VAL_NORMAL);
 	tpo_td043_write(ddata->spi, 0x20, 0xf0);
 	tpo_td043_write(ddata->spi, 0x21, 0xf0);
-	tpo_td043_write_mirror(ddata->spi, ddata->hmirror,
-			ddata->vmirror);
+	tpo_td043_write_mirror(ddata->spi, false, ddata->vmirror);
 	tpo_td043_write_gamma(ddata->spi, ddata->gamma);
 
 	ddata->powered_on = 1;
@@ -324,8 +297,7 @@ static void tpo_td043_power_off(struct panel_drv_data *ddata)
 	tpo_td043_write(ddata->spi, 3,
 			TPO_R03_VAL_STANDBY | TPO_R03_EN_PWM);
 
-	if (gpio_is_valid(ddata->nreset_gpio))
-		gpio_set_value(ddata->nreset_gpio, 0);
+	gpiod_set_value(ddata->reset_gpio, 1);
 
 	/* wait for at least 2 vsyncs before cutting off power */
 	msleep(50);
@@ -337,49 +309,21 @@ static void tpo_td043_power_off(struct panel_drv_data *ddata)
 	ddata->powered_on = 0;
 }
 
-static int tpo_td043_connect(struct omap_dss_device *dssdev)
+static int tpo_td043_connect(struct omap_dss_device *src,
+			     struct omap_dss_device *dst)
 {
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in;
-	int r;
-
-	if (omapdss_device_is_connected(dssdev))
-		return 0;
-
-	in = omapdss_of_find_source_for_first_ep(dssdev->dev->of_node);
-	if (IS_ERR(in)) {
-		dev_err(dssdev->dev, "failed to find video source\n");
-		return PTR_ERR(in);
-	}
-
-	r = in->ops.dpi->connect(in, dssdev);
-	if (r) {
-		omap_dss_put_device(in);
-		return r;
-	}
-
-	ddata->in = in;
 	return 0;
 }
 
-static void tpo_td043_disconnect(struct omap_dss_device *dssdev)
+static void tpo_td043_disconnect(struct omap_dss_device *src,
+				 struct omap_dss_device *dst)
 {
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
-
-	if (!omapdss_device_is_connected(dssdev))
-		return;
-
-	in->ops.dpi->disconnect(in, dssdev);
-
-	omap_dss_put_device(in);
-	ddata->in = NULL;
 }
 
 static int tpo_td043_enable(struct omap_dss_device *dssdev)
 {
 	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
+	struct omap_dss_device *src = dssdev->src;
 	int r;
 
 	if (!omapdss_device_is_connected(dssdev))
@@ -388,9 +332,7 @@ static int tpo_td043_enable(struct omap_dss_device *dssdev)
 	if (omapdss_device_is_enabled(dssdev))
 		return 0;
 
-	in->ops.dpi->set_timings(in, &ddata->vm);
-
-	r = in->ops.dpi->enable(in);
+	r = src->ops->enable(src);
 	if (r)
 		return r;
 
@@ -401,7 +343,7 @@ static int tpo_td043_enable(struct omap_dss_device *dssdev)
 	if (!ddata->spi_suspended) {
 		r = tpo_td043_power_on(ddata);
 		if (r) {
-			in->ops.dpi->disable(in);
+			src->ops->disable(src);
 			return r;
 		}
 	}
@@ -414,12 +356,12 @@ static int tpo_td043_enable(struct omap_dss_device *dssdev)
 static void tpo_td043_disable(struct omap_dss_device *dssdev)
 {
 	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
+	struct omap_dss_device *src = dssdev->src;
 
 	if (!omapdss_device_is_enabled(dssdev))
 		return;
 
-	in->ops.dpi->disable(in);
+	src->ops->disable(src);
 
 	if (!ddata->spi_suspended)
 		tpo_td043_power_off(ddata);
@@ -427,18 +369,6 @@ static void tpo_td043_disable(struct omap_dss_device *dssdev)
 	dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
 }
 
-static void tpo_td043_set_timings(struct omap_dss_device *dssdev,
-				  struct videomode *vm)
-{
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
-
-	ddata->vm = *vm;
-	dssdev->panel.vm = *vm;
-
-	in->ops.dpi->set_timings(in, vm);
-}
-
 static void tpo_td043_get_timings(struct omap_dss_device *dssdev,
 				  struct videomode *vm)
 {
@@ -447,50 +377,21 @@ static void tpo_td043_get_timings(struct omap_dss_device *dssdev,
 	*vm = ddata->vm;
 }
 
-static int tpo_td043_check_timings(struct omap_dss_device *dssdev,
-				   struct videomode *vm)
-{
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
-
-	return in->ops.dpi->check_timings(in, vm);
-}
-
-static struct omap_dss_driver tpo_td043_ops = {
+static const struct omap_dss_device_ops tpo_td043_ops = {
 	.connect	= tpo_td043_connect,
 	.disconnect	= tpo_td043_disconnect,
 
 	.enable		= tpo_td043_enable,
 	.disable	= tpo_td043_disable,
 
-	.set_timings	= tpo_td043_set_timings,
 	.get_timings	= tpo_td043_get_timings,
-	.check_timings	= tpo_td043_check_timings,
-
-	.set_mirror	= tpo_td043_set_hmirror,
-	.get_mirror	= tpo_td043_get_hmirror,
 };
 
-static int tpo_td043_probe_of(struct spi_device *spi)
-{
-	struct device_node *node = spi->dev.of_node;
-	struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
-	int gpio;
-
-	gpio = of_get_named_gpio(node, "reset-gpios", 0);
-	if (!gpio_is_valid(gpio)) {
-		dev_err(&spi->dev, "failed to parse enable gpio\n");
-		return gpio;
-	}
-	ddata->nreset_gpio = gpio;
-
-	return 0;
-}
-
 static int tpo_td043_probe(struct spi_device *spi)
 {
 	struct panel_drv_data *ddata;
 	struct omap_dss_device *dssdev;
+	struct gpio_desc *gpio;
 	int r;
 
 	dev_dbg(&spi->dev, "%s\n", __func__);
@@ -512,59 +413,49 @@ static int tpo_td043_probe(struct spi_device *spi)
 
 	ddata->spi = spi;
 
-	r = tpo_td043_probe_of(spi);
-	if (r)
-		return r;
-
 	ddata->mode = TPO_R02_MODE_800x480;
 	memcpy(ddata->gamma, tpo_td043_def_gamma, sizeof(ddata->gamma));
 
 	ddata->vcc_reg = devm_regulator_get(&spi->dev, "vcc");
 	if (IS_ERR(ddata->vcc_reg)) {
 		dev_err(&spi->dev, "failed to get LCD VCC regulator\n");
-		r = PTR_ERR(ddata->vcc_reg);
-		goto err_regulator;
+		return PTR_ERR(ddata->vcc_reg);
 	}
 
-	if (gpio_is_valid(ddata->nreset_gpio)) {
-		r = devm_gpio_request_one(&spi->dev,
-				ddata->nreset_gpio, GPIOF_OUT_INIT_LOW,
-				"lcd reset");
-		if (r < 0) {
-			dev_err(&spi->dev, "couldn't request reset GPIO\n");
-			goto err_gpio_req;
-		}
+	gpio = devm_gpiod_get(&spi->dev, "reset", GPIOD_OUT_HIGH);
+	if (IS_ERR(gpio)) {
+		dev_err(&spi->dev, "failed to get reset gpio\n");
+		return PTR_ERR(gpio);
 	}
 
+	ddata->reset_gpio = gpio;
+
 	r = sysfs_create_group(&spi->dev.kobj, &tpo_td043_attr_group);
 	if (r) {
 		dev_err(&spi->dev, "failed to create sysfs files\n");
-		goto err_sysfs;
+		return r;
 	}
 
 	ddata->vm = tpo_td043_vm;
 
 	dssdev = &ddata->dssdev;
 	dssdev->dev = &spi->dev;
-	dssdev->driver = &tpo_td043_ops;
+	dssdev->ops = &tpo_td043_ops;
 	dssdev->type = OMAP_DISPLAY_TYPE_DPI;
 	dssdev->owner = THIS_MODULE;
-	dssdev->panel.vm = ddata->vm;
+	dssdev->of_ports = BIT(0);
 
-	r = omapdss_register_display(dssdev);
-	if (r) {
-		dev_err(&spi->dev, "Failed to register panel\n");
-		goto err_reg;
-	}
+	/*
+	 * Note: According to the panel documentation:
+	 * SYNC needs to be driven on the FALLING edge
+	 */
+	dssdev->bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_SYNC_POSEDGE
+			  | DRM_BUS_FLAG_PIXDATA_NEGEDGE;
 
-	return 0;
+	omapdss_display_init(dssdev);
+	omapdss_device_register(dssdev);
 
-err_reg:
-	sysfs_remove_group(&spi->dev.kobj, &tpo_td043_attr_group);
-err_sysfs:
-err_gpio_req:
-err_regulator:
-	return r;
+	return 0;
 }
 
 static int tpo_td043_remove(struct spi_device *spi)
@@ -574,10 +465,9 @@ static int tpo_td043_remove(struct spi_device *spi)
 
 	dev_dbg(&ddata->spi->dev, "%s\n", __func__);
 
-	omapdss_unregister_display(dssdev);
+	omapdss_device_unregister(dssdev);
 
 	tpo_td043_disable(dssdev);
-	tpo_td043_disconnect(dssdev);
 
 	sysfs_remove_group(&spi->dev.kobj, &tpo_td043_attr_group);
 

+ 205 - 12
drivers/gpu/drm/omapdrm/dss/base.c

@@ -14,24 +14,17 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/list.h>
 #include <linux/module.h>
+#include <linux/mutex.h>
 #include <linux/of.h>
 #include <linux/of_graph.h>
-#include <linux/list.h>
 
 #include "dss.h"
 #include "omapdss.h"
 
 static struct dss_device *dss_device;
 
-static struct list_head omapdss_comp_list;
-
-struct omapdss_comp_node {
-	struct list_head list;
-	struct device_node *node;
-	bool dss_core_component;
-};
-
 struct dss_device *omapdss_get_dss(void)
 {
 	return dss_device;
@@ -56,6 +49,208 @@ const struct dispc_ops *dispc_get_ops(struct dss_device *dss)
 }
 EXPORT_SYMBOL(dispc_get_ops);
 
+
+/* -----------------------------------------------------------------------------
+ * OMAP DSS Devices Handling
+ */
+
+static LIST_HEAD(omapdss_devices_list);
+static DEFINE_MUTEX(omapdss_devices_lock);
+
+void omapdss_device_register(struct omap_dss_device *dssdev)
+{
+	mutex_lock(&omapdss_devices_lock);
+	list_add_tail(&dssdev->list, &omapdss_devices_list);
+	mutex_unlock(&omapdss_devices_lock);
+}
+EXPORT_SYMBOL_GPL(omapdss_device_register);
+
+void omapdss_device_unregister(struct omap_dss_device *dssdev)
+{
+	mutex_lock(&omapdss_devices_lock);
+	list_del(&dssdev->list);
+	mutex_unlock(&omapdss_devices_lock);
+}
+EXPORT_SYMBOL_GPL(omapdss_device_unregister);
+
+static bool omapdss_device_is_registered(struct device_node *node)
+{
+	struct omap_dss_device *dssdev;
+	bool found = false;
+
+	mutex_lock(&omapdss_devices_lock);
+
+	list_for_each_entry(dssdev, &omapdss_devices_list, list) {
+		if (dssdev->dev->of_node == node) {
+			found = true;
+			break;
+		}
+	}
+
+	mutex_unlock(&omapdss_devices_lock);
+	return found;
+}
+
+struct omap_dss_device *omapdss_device_get(struct omap_dss_device *dssdev)
+{
+	if (!try_module_get(dssdev->owner))
+		return NULL;
+
+	if (get_device(dssdev->dev) == NULL) {
+		module_put(dssdev->owner);
+		return NULL;
+	}
+
+	return dssdev;
+}
+EXPORT_SYMBOL(omapdss_device_get);
+
+void omapdss_device_put(struct omap_dss_device *dssdev)
+{
+	put_device(dssdev->dev);
+	module_put(dssdev->owner);
+}
+EXPORT_SYMBOL(omapdss_device_put);
+
+struct omap_dss_device *omapdss_find_device_by_port(struct device_node *src,
+						    unsigned int port)
+{
+	struct omap_dss_device *dssdev;
+
+	list_for_each_entry(dssdev, &omapdss_devices_list, list) {
+		if (dssdev->dev->of_node == src && dssdev->of_ports & BIT(port))
+			return omapdss_device_get(dssdev);
+	}
+
+	return NULL;
+}
+
+/*
+ * Search for the next device starting at @from. The type argument specfies
+ * which device types to consider when searching. Searching for multiple types
+ * is supported by and'ing their type flags. Release the reference to the @from
+ * device, and acquire a reference to the returned device if found.
+ */
+struct omap_dss_device *omapdss_device_get_next(struct omap_dss_device *from,
+						enum omap_dss_device_type type)
+{
+	struct omap_dss_device *dssdev;
+	struct list_head *list;
+
+	mutex_lock(&omapdss_devices_lock);
+
+	if (list_empty(&omapdss_devices_list)) {
+		dssdev = NULL;
+		goto done;
+	}
+
+	/*
+	 * Start from the from entry if given or from omapdss_devices_list
+	 * otherwise.
+	 */
+	list = from ? &from->list : &omapdss_devices_list;
+
+	list_for_each_entry(dssdev, list, list) {
+		/*
+		 * Stop if we reach the omapdss_devices_list, that's the end of
+		 * the list.
+		 */
+		if (&dssdev->list == &omapdss_devices_list) {
+			dssdev = NULL;
+			goto done;
+		}
+
+		/*
+		 * Accept display entities if the display type is requested,
+		 * and output entities if the output type is requested.
+		 */
+		if ((type & OMAP_DSS_DEVICE_TYPE_DISPLAY) &&
+		    !dssdev->output_type)
+			goto done;
+		if ((type & OMAP_DSS_DEVICE_TYPE_OUTPUT) && dssdev->id &&
+		    dssdev->next)
+			goto done;
+	}
+
+	dssdev = NULL;
+
+done:
+	if (from)
+		omapdss_device_put(from);
+	if (dssdev)
+		omapdss_device_get(dssdev);
+
+	mutex_unlock(&omapdss_devices_lock);
+	return dssdev;
+}
+EXPORT_SYMBOL(omapdss_device_get_next);
+
+int omapdss_device_connect(struct dss_device *dss,
+			   struct omap_dss_device *src,
+			   struct omap_dss_device *dst)
+{
+	int ret;
+
+	dev_dbg(dst->dev, "connect\n");
+
+	if (omapdss_device_is_connected(dst))
+		return -EBUSY;
+
+	dst->dss = dss;
+
+	ret = dst->ops->connect(src, dst);
+	if (ret < 0) {
+		dst->dss = NULL;
+		return ret;
+	}
+
+	if (src) {
+		WARN_ON(src->dst);
+		dst->src = src;
+		src->dst = dst;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(omapdss_device_connect);
+
+void omapdss_device_disconnect(struct omap_dss_device *src,
+			       struct omap_dss_device *dst)
+{
+	dev_dbg(dst->dev, "disconnect\n");
+
+	if (!dst->id && !omapdss_device_is_connected(dst)) {
+		WARN_ON(dst->output_type);
+		return;
+	}
+
+	if (src) {
+		if (WARN_ON(dst != src->dst))
+			return;
+
+		dst->src = NULL;
+		src->dst = NULL;
+	}
+
+	WARN_ON(dst->state != OMAP_DSS_DISPLAY_DISABLED);
+
+	dst->ops->disconnect(src, dst);
+	dst->dss = NULL;
+}
+EXPORT_SYMBOL_GPL(omapdss_device_disconnect);
+
+/* -----------------------------------------------------------------------------
+ * Components Handling
+ */
+
+static struct list_head omapdss_comp_list;
+
+struct omapdss_comp_node {
+	struct list_head list;
+	struct device_node *node;
+	bool dss_core_component;
+};
+
 static bool omapdss_list_contains(const struct device_node *node)
 {
 	struct omapdss_comp_node *comp;
@@ -130,9 +325,7 @@ static bool omapdss_component_is_loaded(struct omapdss_comp_node *comp)
 {
 	if (comp->dss_core_component)
 		return true;
-	if (omapdss_component_is_display(comp->node))
-		return true;
-	if (omapdss_component_is_output(comp->node))
+	if (omapdss_device_is_registered(comp->node))
 		return true;
 
 	return false;

+ 2 - 24
drivers/gpu/drm/omapdrm/dss/core.c

@@ -45,36 +45,14 @@ static struct platform_driver * const omap_dss_drivers[] = {
 #endif
 };
 
-static struct platform_device *omap_drm_device;
-
 static int __init omap_dss_init(void)
 {
-	int r;
-
-	r = platform_register_drivers(omap_dss_drivers,
-				      ARRAY_SIZE(omap_dss_drivers));
-	if (r)
-		goto err_reg;
-
-	omap_drm_device = platform_device_register_simple("omapdrm", 0, NULL, 0);
-	if (IS_ERR(omap_drm_device)) {
-		r = PTR_ERR(omap_drm_device);
-		goto err_reg;
-	}
-
-	return 0;
-
-err_reg:
-	platform_unregister_drivers(omap_dss_drivers,
-				    ARRAY_SIZE(omap_dss_drivers));
-
-	return r;
+	return platform_register_drivers(omap_dss_drivers,
+					 ARRAY_SIZE(omap_dss_drivers));
 }
 
 static void __exit omap_dss_exit(void)
 {
-	platform_device_unregister(omap_drm_device);
-
 	platform_unregister_drivers(omap_dss_drivers,
 				    ARRAY_SIZE(omap_dss_drivers));
 }

+ 23 - 38
drivers/gpu/drm/omapdrm/dss/dispc.c

@@ -1140,18 +1140,6 @@ static void dispc_ovl_set_color_mode(struct dispc_device *dispc,
 	REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), m, 4, 1);
 }
 
-static bool format_is_yuv(u32 fourcc)
-{
-	switch (fourcc) {
-	case DRM_FORMAT_YUYV:
-	case DRM_FORMAT_UYVY:
-	case DRM_FORMAT_NV12:
-		return true;
-	default:
-		return false;
-	}
-}
-
 static void dispc_ovl_configure_burst_type(struct dispc_device *dispc,
 					   enum omap_plane_id plane,
 					   enum omap_dss_rotation_type rotation)
@@ -1910,11 +1898,14 @@ static void dispc_ovl_set_scaling_uv(struct dispc_device *dispc,
 	int scale_x = out_width != orig_width;
 	int scale_y = out_height != orig_height;
 	bool chroma_upscale = plane != OMAP_DSS_WB;
+	const struct drm_format_info *info;
+
+	info = drm_format_info(fourcc);
 
 	if (!dispc_has_feature(dispc, FEAT_HANDLE_UV_SEPARATE))
 		return;
 
-	if (!format_is_yuv(fourcc)) {
+	if (!info->is_yuv) {
 		/* reset chroma resampling for RGB formats  */
 		if (plane != OMAP_DSS_WB)
 			REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES2(plane),
@@ -2624,7 +2615,7 @@ static int dispc_ovl_setup_common(struct dispc_device *dispc,
 	unsigned int offset0, offset1;
 	s32 row_inc;
 	s32 pix_inc;
-	u16 frame_width, frame_height;
+	u16 frame_width;
 	unsigned int field_offset = 0;
 	u16 in_height = height;
 	u16 in_width = width;
@@ -2632,6 +2623,9 @@ static int dispc_ovl_setup_common(struct dispc_device *dispc,
 	bool ilace = !!(vm->flags & DISPLAY_FLAGS_INTERLACED);
 	unsigned long pclk = dispc_plane_pclk_rate(dispc, plane);
 	unsigned long lclk = dispc_plane_lclk_rate(dispc, plane);
+	const struct drm_format_info *info;
+
+	info = drm_format_info(fourcc);
 
 	/* when setting up WB, dispc_plane_pclk_rate() returns 0 */
 	if (plane == OMAP_DSS_WB)
@@ -2640,7 +2634,7 @@ static int dispc_ovl_setup_common(struct dispc_device *dispc,
 	if (paddr == 0 && rotation_type != OMAP_DSS_ROT_TILER)
 		return -EINVAL;
 
-	if (format_is_yuv(fourcc) && (in_width & 1)) {
+	if (info->is_yuv && (in_width & 1)) {
 		DSSERR("input width %d is not even for YUV format\n", in_width);
 		return -EINVAL;
 	}
@@ -2680,7 +2674,7 @@ static int dispc_ovl_setup_common(struct dispc_device *dispc,
 		DSSDBG("predecimation %d x %x, new input size %d x %d\n",
 			x_predecim, y_predecim, in_width, in_height);
 
-	if (format_is_yuv(fourcc) && (in_width & 1)) {
+	if (info->is_yuv && (in_width & 1)) {
 		DSSDBG("predecimated input width is not even for YUV format\n");
 		DSSDBG("adjusting input width %d -> %d\n",
 			in_width, in_width & ~1);
@@ -2688,7 +2682,7 @@ static int dispc_ovl_setup_common(struct dispc_device *dispc,
 		in_width &= ~1;
 	}
 
-	if (format_is_yuv(fourcc))
+	if (info->is_yuv)
 		cconv = 1;
 
 	if (ilace && !fieldmode) {
@@ -2714,13 +2708,10 @@ static int dispc_ovl_setup_common(struct dispc_device *dispc,
 	row_inc = 0;
 	pix_inc = 0;
 
-	if (plane == OMAP_DSS_WB) {
+	if (plane == OMAP_DSS_WB)
 		frame_width = out_width;
-		frame_height = out_height;
-	} else {
+	else
 		frame_width = in_width;
-		frame_height = height;
-	}
 
 	calc_offset(screen_width, frame_width,
 			fourcc, fieldmode, field_offset,
@@ -2904,13 +2895,6 @@ static int dispc_ovl_enable(struct dispc_device *dispc,
 	return 0;
 }
 
-static enum omap_dss_output_id
-dispc_mgr_get_supported_outputs(struct dispc_device *dispc,
-				enum omap_channel channel)
-{
-	return dss_get_supported_outputs(dispc->dss, channel);
-}
-
 static void dispc_lcd_enable_signal_polarity(struct dispc_device *dispc,
 					     bool act_high)
 {
@@ -3120,28 +3104,29 @@ static bool _dispc_mgr_pclk_ok(struct dispc_device *dispc,
 		return pclk <= dispc->feat->max_tv_pclk;
 }
 
-bool dispc_mgr_timings_ok(struct dispc_device *dispc, enum omap_channel channel,
-			  const struct videomode *vm)
+static int dispc_mgr_check_timings(struct dispc_device *dispc,
+				   enum omap_channel channel,
+				   const struct videomode *vm)
 {
 	if (!_dispc_mgr_size_ok(dispc, vm->hactive, vm->vactive))
-		return false;
+		return MODE_BAD;
 
 	if (!_dispc_mgr_pclk_ok(dispc, channel, vm->pixelclock))
-		return false;
+		return MODE_BAD;
 
 	if (dss_mgr_is_lcd(channel)) {
 		/* TODO: OMAP4+ supports interlace for LCD outputs */
 		if (vm->flags & DISPLAY_FLAGS_INTERLACED)
-			return false;
+			return MODE_BAD;
 
 		if (!_dispc_lcd_timings_ok(dispc, vm->hsync_len,
 				vm->hfront_porch, vm->hback_porch,
 				vm->vsync_len, vm->vfront_porch,
 				vm->vback_porch))
-			return false;
+			return MODE_BAD;
 	}
 
-	return true;
+	return MODE_OK;
 }
 
 static void _dispc_mgr_set_lcd_timings(struct dispc_device *dispc,
@@ -3243,7 +3228,7 @@ static void dispc_mgr_set_timings(struct dispc_device *dispc,
 
 	DSSDBG("channel %d xres %u yres %u\n", channel, t.hactive, t.vactive);
 
-	if (!dispc_mgr_timings_ok(dispc, channel, &t)) {
+	if (dispc_mgr_check_timings(dispc, channel, &t)) {
 		BUG();
 		return;
 	}
@@ -4740,9 +4725,9 @@ static const struct dispc_ops dispc_ops = {
 	.mgr_go_busy = dispc_mgr_go_busy,
 	.mgr_go = dispc_mgr_go,
 	.mgr_set_lcd_config = dispc_mgr_set_lcd_config,
+	.mgr_check_timings = dispc_mgr_check_timings,
 	.mgr_set_timings = dispc_mgr_set_timings,
 	.mgr_setup = dispc_mgr_setup,
-	.mgr_get_supported_outputs = dispc_mgr_get_supported_outputs,
 	.mgr_gamma_size = dispc_mgr_gamma_size,
 	.mgr_set_gamma = dispc_mgr_set_gamma,
 

+ 10 - 124
drivers/gpu/drm/omapdrm/dss/display.c

@@ -21,27 +21,14 @@
 #define DSS_SUBSYS_NAME "DISPLAY"
 
 #include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/jiffies.h>
-#include <linux/platform_device.h>
 #include <linux/of.h>
 
 #include "omapdss.h"
 
-static void omapdss_default_get_timings(struct omap_dss_device *dssdev,
-					struct videomode *vm)
-{
-	*vm = dssdev->panel.vm;
-}
-
-static LIST_HEAD(panel_list);
-static DEFINE_MUTEX(panel_list_mutex);
 static int disp_num_counter;
 
-int omapdss_register_display(struct omap_dss_device *dssdev)
+void omapdss_display_init(struct omap_dss_device *dssdev)
 {
-	struct omap_dss_driver *drv = dssdev->driver;
-	struct list_head *cur;
 	int id;
 
 	/*
@@ -52,123 +39,22 @@ int omapdss_register_display(struct omap_dss_device *dssdev)
 	if (id < 0)
 		id = disp_num_counter++;
 
-	snprintf(dssdev->alias, sizeof(dssdev->alias), "display%d", id);
+	dssdev->alias_id = id;
 
 	/* Use 'label' property for name, if it exists */
 	of_property_read_string(dssdev->dev->of_node, "label", &dssdev->name);
 
 	if (dssdev->name == NULL)
-		dssdev->name = dssdev->alias;
-
-	if (drv && drv->get_timings == NULL)
-		drv->get_timings = omapdss_default_get_timings;
-
-	mutex_lock(&panel_list_mutex);
-	list_for_each(cur, &panel_list) {
-		struct omap_dss_device *ldev = list_entry(cur,
-							 struct omap_dss_device,
-							 panel_list);
-		if (strcmp(ldev->alias, dssdev->alias) > 0)
-			break;
-	}
-	list_add_tail(&dssdev->panel_list, cur);
-	mutex_unlock(&panel_list_mutex);
-	return 0;
-}
-EXPORT_SYMBOL(omapdss_register_display);
-
-void omapdss_unregister_display(struct omap_dss_device *dssdev)
-{
-	mutex_lock(&panel_list_mutex);
-	list_del(&dssdev->panel_list);
-	mutex_unlock(&panel_list_mutex);
+		dssdev->name = devm_kasprintf(dssdev->dev, GFP_KERNEL,
+					      "display%u", id);
 }
-EXPORT_SYMBOL(omapdss_unregister_display);
+EXPORT_SYMBOL_GPL(omapdss_display_init);
 
-bool omapdss_component_is_display(struct device_node *node)
+struct omap_dss_device *omapdss_display_get(struct omap_dss_device *output)
 {
-	struct omap_dss_device *dssdev;
-	bool found = false;
-
-	mutex_lock(&panel_list_mutex);
-	list_for_each_entry(dssdev, &panel_list, panel_list) {
-		if (dssdev->dev->of_node == node) {
-			found = true;
-			goto out;
-		}
-	}
-out:
-	mutex_unlock(&panel_list_mutex);
-	return found;
-}
-EXPORT_SYMBOL(omapdss_component_is_display);
-
-struct omap_dss_device *omap_dss_get_device(struct omap_dss_device *dssdev)
-{
-	if (!try_module_get(dssdev->owner))
-		return NULL;
-
-	if (get_device(dssdev->dev) == NULL) {
-		module_put(dssdev->owner);
-		return NULL;
-	}
-
-	return dssdev;
-}
-EXPORT_SYMBOL(omap_dss_get_device);
-
-void omap_dss_put_device(struct omap_dss_device *dssdev)
-{
-	put_device(dssdev->dev);
-	module_put(dssdev->owner);
-}
-EXPORT_SYMBOL(omap_dss_put_device);
-
-/*
- * ref count of the found device is incremented.
- * ref count of from-device is decremented.
- */
-struct omap_dss_device *omap_dss_get_next_device(struct omap_dss_device *from)
-{
-	struct list_head *l;
-	struct omap_dss_device *dssdev;
-
-	mutex_lock(&panel_list_mutex);
-
-	if (list_empty(&panel_list)) {
-		dssdev = NULL;
-		goto out;
-	}
-
-	if (from == NULL) {
-		dssdev = list_first_entry(&panel_list, struct omap_dss_device,
-				panel_list);
-		omap_dss_get_device(dssdev);
-		goto out;
-	}
-
-	omap_dss_put_device(from);
-
-	list_for_each(l, &panel_list) {
-		dssdev = list_entry(l, struct omap_dss_device, panel_list);
-		if (dssdev == from) {
-			if (list_is_last(l, &panel_list)) {
-				dssdev = NULL;
-				goto out;
-			}
-
-			dssdev = list_entry(l->next, struct omap_dss_device,
-					panel_list);
-			omap_dss_get_device(dssdev);
-			goto out;
-		}
-	}
-
-	WARN(1, "'from' dssdev not found\n");
+	while (output->next)
+		output = output->next;
 
-	dssdev = NULL;
-out:
-	mutex_unlock(&panel_list_mutex);
-	return dssdev;
+	return omapdss_device_get(output);
 }
-EXPORT_SYMBOL(omap_dss_get_next_device);
+EXPORT_SYMBOL_GPL(omapdss_display_get);

+ 78 - 114
drivers/gpu/drm/omapdrm/dss/dpi.c

@@ -39,6 +39,7 @@ struct dpi_data {
 	struct platform_device *pdev;
 	enum dss_model dss_model;
 	struct dss_device *dss;
+	unsigned int id;
 
 	struct regulator *vdds_dsi_reg;
 	enum dss_clk_source clk_src;
@@ -346,10 +347,9 @@ static int dpi_set_dispc_clk(struct dpi_data *dpi, unsigned long pck_req,
 
 static int dpi_set_mode(struct dpi_data *dpi)
 {
-	struct videomode *vm = &dpi->vm;
+	const struct videomode *vm = &dpi->vm;
 	int lck_div = 0, pck_div = 0;
 	unsigned long fck = 0;
-	unsigned long pck;
 	int r = 0;
 
 	if (dpi->pll)
@@ -361,17 +361,6 @@ static int dpi_set_mode(struct dpi_data *dpi)
 	if (r)
 		return r;
 
-	pck = fck / lck_div / pck_div;
-
-	if (pck != vm->pixelclock) {
-		DSSWARN("Could not find exact pixel clock. Requested %lu Hz, got %lu Hz\n",
-			vm->pixelclock, pck);
-
-		vm->pixelclock = pck;
-	}
-
-	dss_mgr_set_timings(&dpi->output, vm);
-
 	return 0;
 }
 
@@ -413,7 +402,7 @@ static int dpi_display_enable(struct omap_dss_device *dssdev)
 	if (r)
 		goto err_get_dispc;
 
-	r = dss_dpi_select_source(dpi->dss, out->port_num, out->dispc_channel);
+	r = dss_dpi_select_source(dpi->dss, dpi->id, out->dispc_channel);
 	if (r)
 		goto err_src_sel;
 
@@ -478,7 +467,7 @@ static void dpi_display_disable(struct omap_dss_device *dssdev)
 }
 
 static void dpi_set_timings(struct omap_dss_device *dssdev,
-			    struct videomode *vm)
+			    const struct videomode *vm)
 {
 	struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
 
@@ -491,23 +480,10 @@ static void dpi_set_timings(struct omap_dss_device *dssdev,
 	mutex_unlock(&dpi->lock);
 }
 
-static void dpi_get_timings(struct omap_dss_device *dssdev,
-			    struct videomode *vm)
-{
-	struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
-
-	mutex_lock(&dpi->lock);
-
-	*vm = dpi->vm;
-
-	mutex_unlock(&dpi->lock);
-}
-
 static int dpi_check_timings(struct omap_dss_device *dssdev,
 			     struct videomode *vm)
 {
 	struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
-	enum omap_channel channel = dpi->output.dispc_channel;
 	int lck_div, pck_div;
 	unsigned long fck;
 	unsigned long pck;
@@ -517,9 +493,6 @@ static int dpi_check_timings(struct omap_dss_device *dssdev,
 	if (vm->hactive % 8 != 0)
 		return -EINVAL;
 
-	if (!dispc_mgr_timings_ok(dpi->dss->dispc, channel, vm))
-		return -EINVAL;
-
 	if (vm->pixelclock == 0)
 		return -EINVAL;
 
@@ -562,38 +535,6 @@ static int dpi_verify_pll(struct dss_pll *pll)
 	return 0;
 }
 
-static const struct soc_device_attribute dpi_soc_devices[] = {
-	{ .machine = "OMAP3[456]*" },
-	{ .machine = "[AD]M37*" },
-	{ /* sentinel */ }
-};
-
-static int dpi_init_regulator(struct dpi_data *dpi)
-{
-	struct regulator *vdds_dsi;
-
-	/*
-	 * The DPI uses the DSI VDDS on OMAP34xx, OMAP35xx, OMAP36xx, AM37xx and
-	 * DM37xx only.
-	 */
-	if (!soc_device_match(dpi_soc_devices))
-		return 0;
-
-	if (dpi->vdds_dsi_reg)
-		return 0;
-
-	vdds_dsi = devm_regulator_get(&dpi->pdev->dev, "vdds_dsi");
-	if (IS_ERR(vdds_dsi)) {
-		if (PTR_ERR(vdds_dsi) != -EPROBE_DEFER)
-			DSSERR("can't get VDDS_DSI regulator\n");
-		return PTR_ERR(vdds_dsi);
-	}
-
-	dpi->vdds_dsi_reg = vdds_dsi;
-
-	return 0;
-}
-
 static void dpi_init_pll(struct dpi_data *dpi)
 {
 	struct dss_pll *pll;
@@ -621,7 +562,7 @@ static void dpi_init_pll(struct dpi_data *dpi)
  * the channel in some more dynamic manner, or get the channel as a user
  * parameter.
  */
-static enum omap_channel dpi_get_channel(struct dpi_data *dpi, int port_num)
+static enum omap_channel dpi_get_channel(struct dpi_data *dpi)
 {
 	switch (dpi->dss_model) {
 	case DSS_MODEL_OMAP2:
@@ -629,7 +570,7 @@ static enum omap_channel dpi_get_channel(struct dpi_data *dpi, int port_num)
 		return OMAP_DSS_CHANNEL_LCD;
 
 	case DSS_MODEL_DRA7:
-		switch (port_num) {
+		switch (dpi->id) {
 		case 2:
 			return OMAP_DSS_CHANNEL_LCD3;
 		case 1:
@@ -651,49 +592,31 @@ static enum omap_channel dpi_get_channel(struct dpi_data *dpi, int port_num)
 	}
 }
 
-static int dpi_connect(struct omap_dss_device *dssdev,
-		struct omap_dss_device *dst)
+static int dpi_connect(struct omap_dss_device *src,
+		       struct omap_dss_device *dst)
 {
-	struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
+	struct dpi_data *dpi = dpi_get_data_from_dssdev(dst);
 	int r;
 
-	r = dpi_init_regulator(dpi);
-	if (r)
-		return r;
-
 	dpi_init_pll(dpi);
 
-	r = dss_mgr_connect(&dpi->output, dssdev);
+	r = omapdss_device_connect(dst->dss, dst, dst->next);
 	if (r)
 		return r;
 
-	r = omapdss_output_set_device(dssdev, dst);
-	if (r) {
-		DSSERR("failed to connect output to new device: %s\n",
-				dst->name);
-		dss_mgr_disconnect(&dpi->output, dssdev);
-		return r;
-	}
-
+	dst->dispc_channel_connected = true;
 	return 0;
 }
 
-static void dpi_disconnect(struct omap_dss_device *dssdev,
-		struct omap_dss_device *dst)
+static void dpi_disconnect(struct omap_dss_device *src,
+			   struct omap_dss_device *dst)
 {
-	struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
-
-	WARN_ON(dst != dssdev->dst);
+	dst->dispc_channel_connected = false;
 
-	if (dst != dssdev->dst)
-		return;
-
-	omapdss_output_unset_device(dssdev);
-
-	dss_mgr_disconnect(&dpi->output, dssdev);
+	omapdss_device_disconnect(dst, dst->next);
 }
 
-static const struct omapdss_dpi_ops dpi_ops = {
+static const struct omap_dss_device_ops dpi_ops = {
 	.connect = dpi_connect,
 	.disconnect = dpi_disconnect,
 
@@ -702,18 +625,16 @@ static const struct omapdss_dpi_ops dpi_ops = {
 
 	.check_timings = dpi_check_timings,
 	.set_timings = dpi_set_timings,
-	.get_timings = dpi_get_timings,
 };
 
-static void dpi_init_output_port(struct dpi_data *dpi, struct device_node *port)
+static int dpi_init_output_port(struct dpi_data *dpi, struct device_node *port)
 {
 	struct omap_dss_device *out = &dpi->output;
+	u32 port_num = 0;
 	int r;
-	u32 port_num;
 
-	r = of_property_read_u32(port, "reg", &port_num);
-	if (r)
-		port_num = 0;
+	of_property_read_u32(port, "reg", &port_num);
+	dpi->id = port_num <= 2 ? port_num : 0;
 
 	switch (port_num) {
 	case 2:
@@ -731,12 +652,28 @@ static void dpi_init_output_port(struct dpi_data *dpi, struct device_node *port)
 	out->dev = &dpi->pdev->dev;
 	out->id = OMAP_DSS_OUTPUT_DPI;
 	out->output_type = OMAP_DISPLAY_TYPE_DPI;
-	out->dispc_channel = dpi_get_channel(dpi, port_num);
-	out->port_num = port_num;
-	out->ops.dpi = &dpi_ops;
+	out->dispc_channel = dpi_get_channel(dpi);
+	out->of_ports = BIT(port_num);
+	out->ops = &dpi_ops;
 	out->owner = THIS_MODULE;
 
-	omapdss_register_output(out);
+	out->next = omapdss_of_find_connected_device(out->dev->of_node, 0);
+	if (IS_ERR(out->next)) {
+		if (PTR_ERR(out->next) != -EPROBE_DEFER)
+			dev_err(out->dev, "failed to find video sink\n");
+		return PTR_ERR(out->next);
+	}
+
+	r = omapdss_output_validate(out);
+	if (r) {
+		omapdss_device_put(out->next);
+		out->next = NULL;
+		return r;
+	}
+
+	omapdss_device_register(out);
+
+	return 0;
 }
 
 static void dpi_uninit_output_port(struct device_node *port)
@@ -744,7 +681,38 @@ static void dpi_uninit_output_port(struct device_node *port)
 	struct dpi_data *dpi = port->data;
 	struct omap_dss_device *out = &dpi->output;
 
-	omapdss_unregister_output(out);
+	if (out->next)
+		omapdss_device_put(out->next);
+	omapdss_device_unregister(out);
+}
+
+static const struct soc_device_attribute dpi_soc_devices[] = {
+	{ .machine = "OMAP3[456]*" },
+	{ .machine = "[AD]M37*" },
+	{ /* sentinel */ }
+};
+
+static int dpi_init_regulator(struct dpi_data *dpi)
+{
+	struct regulator *vdds_dsi;
+
+	/*
+	 * The DPI uses the DSI VDDS on OMAP34xx, OMAP35xx, OMAP36xx, AM37xx and
+	 * DM37xx only.
+	 */
+	if (!soc_device_match(dpi_soc_devices))
+		return 0;
+
+	vdds_dsi = devm_regulator_get(&dpi->pdev->dev, "vdds_dsi");
+	if (IS_ERR(vdds_dsi)) {
+		if (PTR_ERR(vdds_dsi) != -EPROBE_DEFER)
+			DSSERR("can't get VDDS_DSI regulator\n");
+		return PTR_ERR(vdds_dsi);
+	}
+
+	dpi->vdds_dsi_reg = vdds_dsi;
+
+	return 0;
 }
 
 int dpi_init_port(struct dss_device *dss, struct platform_device *pdev,
@@ -764,15 +732,14 @@ int dpi_init_port(struct dss_device *dss, struct platform_device *pdev,
 		return 0;
 
 	r = of_property_read_u32(ep, "data-lines", &datalines);
+	of_node_put(ep);
 	if (r) {
 		DSSERR("failed to parse datalines\n");
-		goto err_datalines;
+		return r;
 	}
 
 	dpi->data_lines = datalines;
 
-	of_node_put(ep);
-
 	dpi->pdev = pdev;
 	dpi->dss_model = dss_model;
 	dpi->dss = dss;
@@ -780,14 +747,11 @@ int dpi_init_port(struct dss_device *dss, struct platform_device *pdev,
 
 	mutex_init(&dpi->lock);
 
-	dpi_init_output_port(dpi, port);
-
-	return 0;
-
-err_datalines:
-	of_node_put(ep);
+	r = dpi_init_regulator(dpi);
+	if (r)
+		return r;
 
-	return r;
+	return dpi_init_output_port(dpi, port);
 }
 
 void dpi_uninit_port(struct device_node *port)

+ 268 - 323
drivers/gpu/drm/omapdrm/dss/dsi.c

@@ -403,6 +403,7 @@ struct dsi_data {
 	struct {
 		struct dss_debugfs_entry *irqs;
 		struct dss_debugfs_entry *regs;
+		struct dss_debugfs_entry *clks;
 	} debugfs;
 
 #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
@@ -442,27 +443,6 @@ static inline struct dsi_data *to_dsi_data(struct omap_dss_device *dssdev)
 	return dev_get_drvdata(dssdev->dev);
 }
 
-static struct dsi_data *dsi_get_dsi_from_id(int module)
-{
-	struct omap_dss_device *out;
-	enum omap_dss_output_id	id;
-
-	switch (module) {
-	case 0:
-		id = OMAP_DSS_OUTPUT_DSI1;
-		break;
-	case 1:
-		id = OMAP_DSS_OUTPUT_DSI2;
-		break;
-	default:
-		return NULL;
-	}
-
-	out = omap_dss_get_output(id);
-
-	return out ? to_dsi_data(out) : NULL;
-}
-
 static inline void dsi_write_reg(struct dsi_data *dsi,
 				 const struct dsi_reg idx, u32 val)
 {
@@ -1157,26 +1137,6 @@ static void dsi_runtime_put(struct dsi_data *dsi)
 	WARN_ON(r < 0 && r != -ENOSYS);
 }
 
-static int dsi_regulator_init(struct dsi_data *dsi)
-{
-	struct regulator *vdds_dsi;
-
-	if (dsi->vdds_dsi_reg != NULL)
-		return 0;
-
-	vdds_dsi = devm_regulator_get(dsi->dev, "vdd");
-
-	if (IS_ERR(vdds_dsi)) {
-		if (PTR_ERR(vdds_dsi) != -EPROBE_DEFER)
-			DSSERR("can't get DSI VDD regulator\n");
-		return PTR_ERR(vdds_dsi);
-	}
-
-	dsi->vdds_dsi_reg = vdds_dsi;
-
-	return 0;
-}
-
 static void _dsi_print_reset_status(struct dsi_data *dsi)
 {
 	u32 l;
@@ -1373,10 +1333,6 @@ static int dsi_pll_enable(struct dss_pll *pll)
 
 	DSSDBG("PLL init\n");
 
-	r = dsi_regulator_init(dsi);
-	if (r)
-		return r;
-
 	r = dsi_runtime_get(dsi);
 	if (r)
 		return r;
@@ -1448,8 +1404,9 @@ static void dsi_pll_disable(struct dss_pll *pll)
 	dsi_pll_uninit(dsi, true);
 }
 
-static void dsi_dump_dsi_clocks(struct dsi_data *dsi, struct seq_file *s)
+static int dsi_dump_dsi_clocks(struct seq_file *s, void *p)
 {
+	struct dsi_data *dsi = p;
 	struct dss_pll_clock_info *cinfo = &dsi->pll.cinfo;
 	enum dss_clk_source dispc_clk_src, dsi_clk_src;
 	int dsi_module = dsi->module_id;
@@ -1459,7 +1416,7 @@ static void dsi_dump_dsi_clocks(struct dsi_data *dsi, struct seq_file *s)
 	dsi_clk_src = dss_get_dsi_clk_source(dsi->dss, dsi_module);
 
 	if (dsi_runtime_get(dsi))
-		return;
+		return 0;
 
 	seq_printf(s,	"- DSI%d PLL -\n", dsi_module + 1);
 
@@ -1503,23 +1460,14 @@ static void dsi_dump_dsi_clocks(struct dsi_data *dsi, struct seq_file *s)
 	seq_printf(s,	"LP_CLK\t\t%lu\n", dsi->current_lp_cinfo.lp_clk);
 
 	dsi_runtime_put(dsi);
-}
-
-void dsi_dump_clocks(struct seq_file *s)
-{
-	struct dsi_data *dsi;
-	int i;
 
-	for  (i = 0; i < MAX_NUM_DSI; i++) {
-		dsi = dsi_get_dsi_from_id(i);
-		if (dsi)
-			dsi_dump_dsi_clocks(dsi, s);
-	}
+	return 0;
 }
 
 #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
-static void dsi_dump_dsi_irqs(struct dsi_data *dsi, struct seq_file *s)
+static int dsi_dump_dsi_irqs(struct seq_file *s, void *p)
 {
+	struct dsi_data *dsi = p;
 	unsigned long flags;
 	struct dsi_irq_stats stats;
 
@@ -1603,33 +1551,20 @@ static void dsi_dump_dsi_irqs(struct dsi_data *dsi, struct seq_file *s)
 	PIS(ULPSACTIVENOT_ALL0);
 	PIS(ULPSACTIVENOT_ALL1);
 #undef PIS
-}
 
-static int dsi1_dump_irqs(struct seq_file *s, void *p)
-{
-	struct dsi_data *dsi = dsi_get_dsi_from_id(0);
-
-	dsi_dump_dsi_irqs(dsi, s);
-	return 0;
-}
-
-static int dsi2_dump_irqs(struct seq_file *s, void *p)
-{
-	struct dsi_data *dsi = dsi_get_dsi_from_id(1);
-
-	dsi_dump_dsi_irqs(dsi, s);
 	return 0;
 }
 #endif
 
-static void dsi_dump_dsi_regs(struct dsi_data *dsi, struct seq_file *s)
+static int dsi_dump_dsi_regs(struct seq_file *s, void *p)
 {
-#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dsi_read_reg(dsi, r))
+	struct dsi_data *dsi = p;
 
 	if (dsi_runtime_get(dsi))
-		return;
+		return 0;
 	dsi_enable_scp_clk(dsi);
 
+#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dsi_read_reg(dsi, r))
 	DUMPREG(DSI_REVISION);
 	DUMPREG(DSI_SYSCONFIG);
 	DUMPREG(DSI_SYSSTATUS);
@@ -1699,25 +1634,11 @@ static void dsi_dump_dsi_regs(struct dsi_data *dsi, struct seq_file *s)
 	DUMPREG(DSI_PLL_GO);
 	DUMPREG(DSI_PLL_CONFIGURATION1);
 	DUMPREG(DSI_PLL_CONFIGURATION2);
+#undef DUMPREG
 
 	dsi_disable_scp_clk(dsi);
 	dsi_runtime_put(dsi);
-#undef DUMPREG
-}
-
-static int dsi1_dump_regs(struct seq_file *s, void *p)
-{
-	struct dsi_data *dsi = dsi_get_dsi_from_id(0);
-
-	dsi_dump_dsi_regs(dsi, s);
-	return 0;
-}
-
-static int dsi2_dump_regs(struct seq_file *s, void *p)
-{
-	struct dsi_data *dsi = dsi_get_dsi_from_id(1);
 
-	dsi_dump_dsi_regs(dsi, s);
 	return 0;
 }
 
@@ -3344,7 +3265,7 @@ static void dsi_config_vp_num_line_buffers(struct dsi_data *dsi)
 
 	if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
 		int bpp = dsi_get_pixel_size(dsi->pix_fmt);
-		struct videomode *vm = &dsi->vm;
+		const struct videomode *vm = &dsi->vm;
 		/*
 		 * Don't use line buffers if width is greater than the video
 		 * port's line buffer size
@@ -3473,7 +3394,7 @@ static void dsi_config_cmd_mode_interleaving(struct dsi_data *dsi)
 	int ddr_clk_pre, ddr_clk_post, enter_hs_mode_lat, exit_hs_mode_lat;
 	int tclk_trail, ths_exit, exiths_clk;
 	bool ddr_alwon;
-	struct videomode *vm = &dsi->vm;
+	const struct videomode *vm = &dsi->vm;
 	int bpp = dsi_get_pixel_size(dsi->pix_fmt);
 	int ndl = dsi->num_lanes_used - 1;
 	int dsi_fclk_hsdiv = dsi->user_dsi_cinfo.mX[HSDIV_DSI] + 1;
@@ -3723,7 +3644,7 @@ static void dsi_proto_timings(struct dsi_data *dsi)
 		int vbp = dsi->vm_timings.vbp;
 		int window_sync = dsi->vm_timings.window_sync;
 		bool hsync_end;
-		struct videomode *vm = &dsi->vm;
+		const struct videomode *vm = &dsi->vm;
 		int bpp = dsi_get_pixel_size(dsi->pix_fmt);
 		int tl, t_he, width_bytes;
 
@@ -3980,8 +3901,6 @@ static void dsi_update_screen_dispc(struct dsi_data *dsi)
 		msecs_to_jiffies(250));
 	BUG_ON(r == 0);
 
-	dss_mgr_set_timings(&dsi->output, &dsi->vm);
-
 	dss_mgr_start_update(&dsi->output);
 
 	if (dsi->te_enabled) {
@@ -4123,24 +4042,6 @@ static int dsi_display_init_dispc(struct dsi_data *dsi)
 		dsi->mgr_config.fifohandcheck = false;
 	}
 
-	/*
-	 * override interlace, logic level and edge related parameters in
-	 * videomode with default values
-	 */
-	dsi->vm.flags &= ~DISPLAY_FLAGS_INTERLACED;
-	dsi->vm.flags &= ~DISPLAY_FLAGS_HSYNC_LOW;
-	dsi->vm.flags |= DISPLAY_FLAGS_HSYNC_HIGH;
-	dsi->vm.flags &= ~DISPLAY_FLAGS_VSYNC_LOW;
-	dsi->vm.flags |= DISPLAY_FLAGS_VSYNC_HIGH;
-	dsi->vm.flags &= ~DISPLAY_FLAGS_PIXDATA_NEGEDGE;
-	dsi->vm.flags |= DISPLAY_FLAGS_PIXDATA_POSEDGE;
-	dsi->vm.flags &= ~DISPLAY_FLAGS_DE_LOW;
-	dsi->vm.flags |= DISPLAY_FLAGS_DE_HIGH;
-	dsi->vm.flags &= ~DISPLAY_FLAGS_SYNC_POSEDGE;
-	dsi->vm.flags |= DISPLAY_FLAGS_SYNC_NEGEDGE;
-
-	dss_mgr_set_timings(&dsi->output, &dsi->vm);
-
 	r = dsi_configure_dispc_clocks(dsi);
 	if (r)
 		goto err1;
@@ -4840,6 +4741,19 @@ static int dsi_set_config(struct omap_dss_device *dssdev,
 	dsi->user_dispc_cinfo = ctx.dispc_cinfo;
 
 	dsi->vm = ctx.vm;
+
+	/*
+	 * override interlace, logic level and edge related parameters in
+	 * videomode with default values
+	 */
+	dsi->vm.flags &= ~DISPLAY_FLAGS_INTERLACED;
+	dsi->vm.flags &= ~DISPLAY_FLAGS_HSYNC_LOW;
+	dsi->vm.flags |= DISPLAY_FLAGS_HSYNC_HIGH;
+	dsi->vm.flags &= ~DISPLAY_FLAGS_VSYNC_LOW;
+	dsi->vm.flags |= DISPLAY_FLAGS_VSYNC_HIGH;
+
+	dss_mgr_set_timings(&dsi->output, &dsi->vm);
+
 	dsi->vm_timings = ctx.dsi_vm;
 
 	mutex_unlock(&dsi->lock);
@@ -4960,163 +4874,71 @@ static int dsi_get_clocks(struct dsi_data *dsi)
 	return 0;
 }
 
-static int dsi_connect(struct omap_dss_device *dssdev,
-		struct omap_dss_device *dst)
+static int dsi_connect(struct omap_dss_device *src,
+		       struct omap_dss_device *dst)
 {
-	struct dsi_data *dsi = to_dsi_data(dssdev);
 	int r;
 
-	r = dsi_regulator_init(dsi);
-	if (r)
-		return r;
-
-	r = dss_mgr_connect(&dsi->output, dssdev);
+	r = omapdss_device_connect(dst->dss, dst, dst->next);
 	if (r)
 		return r;
 
-	r = omapdss_output_set_device(dssdev, dst);
-	if (r) {
-		DSSERR("failed to connect output to new device: %s\n",
-				dssdev->name);
-		dss_mgr_disconnect(&dsi->output, dssdev);
-		return r;
-	}
-
+	dst->dispc_channel_connected = true;
 	return 0;
 }
 
-static void dsi_disconnect(struct omap_dss_device *dssdev,
-		struct omap_dss_device *dst)
+static void dsi_disconnect(struct omap_dss_device *src,
+			   struct omap_dss_device *dst)
 {
-	struct dsi_data *dsi = to_dsi_data(dssdev);
-
-	WARN_ON(dst != dssdev->dst);
-
-	if (dst != dssdev->dst)
-		return;
+	dst->dispc_channel_connected = false;
 
-	omapdss_output_unset_device(dssdev);
-
-	dss_mgr_disconnect(&dsi->output, dssdev);
+	omapdss_device_disconnect(dst, dst->next);
 }
 
-static const struct omapdss_dsi_ops dsi_ops = {
+static const struct omap_dss_device_ops dsi_ops = {
 	.connect = dsi_connect,
 	.disconnect = dsi_disconnect,
-
-	.bus_lock = dsi_bus_lock,
-	.bus_unlock = dsi_bus_unlock,
-
 	.enable = dsi_display_enable,
-	.disable = dsi_display_disable,
-
-	.enable_hs = dsi_vc_enable_hs,
-
-	.configure_pins = dsi_configure_pins,
-	.set_config = dsi_set_config,
-
-	.enable_video_output = dsi_enable_video_output,
-	.disable_video_output = dsi_disable_video_output,
-
-	.update = dsi_update,
-
-	.enable_te = dsi_enable_te,
-
-	.request_vc = dsi_request_vc,
-	.set_vc_id = dsi_set_vc_id,
-	.release_vc = dsi_release_vc,
-
-	.dcs_write = dsi_vc_dcs_write,
-	.dcs_write_nosync = dsi_vc_dcs_write_nosync,
-	.dcs_read = dsi_vc_dcs_read,
-
-	.gen_write = dsi_vc_generic_write,
-	.gen_write_nosync = dsi_vc_generic_write_nosync,
-	.gen_read = dsi_vc_generic_read,
-
-	.bta_sync = dsi_vc_send_bta_sync,
-
-	.set_max_rx_packet_size = dsi_vc_set_max_rx_packet_size,
-};
-
-static void dsi_init_output(struct dsi_data *dsi)
-{
-	struct omap_dss_device *out = &dsi->output;
-
-	out->dev = dsi->dev;
-	out->id = dsi->module_id == 0 ?
-			OMAP_DSS_OUTPUT_DSI1 : OMAP_DSS_OUTPUT_DSI2;
-
-	out->output_type = OMAP_DISPLAY_TYPE_DSI;
-	out->name = dsi->module_id == 0 ? "dsi.0" : "dsi.1";
-	out->dispc_channel = dsi_get_channel(dsi);
-	out->ops.dsi = &dsi_ops;
-	out->owner = THIS_MODULE;
-
-	omapdss_register_output(out);
-}
 
-static void dsi_uninit_output(struct dsi_data *dsi)
-{
-	struct omap_dss_device *out = &dsi->output;
+	.dsi = {
+		.bus_lock = dsi_bus_lock,
+		.bus_unlock = dsi_bus_unlock,
 
-	omapdss_unregister_output(out);
-}
+		.disable = dsi_display_disable,
 
-static int dsi_probe_of(struct dsi_data *dsi)
-{
-	struct device_node *node = dsi->dev->of_node;
-	struct property *prop;
-	u32 lane_arr[10];
-	int len, num_pins;
-	int r, i;
-	struct device_node *ep;
-	struct omap_dsi_pin_config pin_cfg;
+		.enable_hs = dsi_vc_enable_hs,
 
-	ep = of_graph_get_endpoint_by_regs(node, 0, 0);
-	if (!ep)
-		return 0;
+		.configure_pins = dsi_configure_pins,
+		.set_config = dsi_set_config,
 
-	prop = of_find_property(ep, "lanes", &len);
-	if (prop == NULL) {
-		dev_err(dsi->dev, "failed to find lane data\n");
-		r = -EINVAL;
-		goto err;
-	}
+		.enable_video_output = dsi_enable_video_output,
+		.disable_video_output = dsi_disable_video_output,
 
-	num_pins = len / sizeof(u32);
+		.update = dsi_update,
 
-	if (num_pins < 4 || num_pins % 2 != 0 ||
-		num_pins > dsi->num_lanes_supported * 2) {
-		dev_err(dsi->dev, "bad number of lanes\n");
-		r = -EINVAL;
-		goto err;
-	}
+		.enable_te = dsi_enable_te,
 
-	r = of_property_read_u32_array(ep, "lanes", lane_arr, num_pins);
-	if (r) {
-		dev_err(dsi->dev, "failed to read lane data\n");
-		goto err;
-	}
+		.request_vc = dsi_request_vc,
+		.set_vc_id = dsi_set_vc_id,
+		.release_vc = dsi_release_vc,
 
-	pin_cfg.num_pins = num_pins;
-	for (i = 0; i < num_pins; ++i)
-		pin_cfg.pins[i] = (int)lane_arr[i];
+		.dcs_write = dsi_vc_dcs_write,
+		.dcs_write_nosync = dsi_vc_dcs_write_nosync,
+		.dcs_read = dsi_vc_dcs_read,
 
-	r = dsi_configure_pins(&dsi->output, &pin_cfg);
-	if (r) {
-		dev_err(dsi->dev, "failed to configure pins");
-		goto err;
-	}
+		.gen_write = dsi_vc_generic_write,
+		.gen_write_nosync = dsi_vc_generic_write_nosync,
+		.gen_read = dsi_vc_generic_read,
 
-	of_node_put(ep);
+		.bta_sync = dsi_vc_send_bta_sync,
 
-	return 0;
+		.set_max_rx_packet_size = dsi_vc_set_max_rx_packet_size,
+	},
+};
 
-err:
-	of_node_put(ep);
-	return r;
-}
+/* -----------------------------------------------------------------------------
+ * PLL
+ */
 
 static const struct dss_pll_ops dsi_pll_ops = {
 	.enable = dsi_pll_enable,
@@ -5231,7 +5053,175 @@ static int dsi_init_pll_data(struct dss_device *dss, struct dsi_data *dsi)
 	return 0;
 }
 
-/* DSI1 HW IP initialisation */
+/* -----------------------------------------------------------------------------
+ * Component Bind & Unbind
+ */
+
+static int dsi_bind(struct device *dev, struct device *master, void *data)
+{
+	struct dss_device *dss = dss_get_device(master);
+	struct dsi_data *dsi = dev_get_drvdata(dev);
+	char name[10];
+	u32 rev;
+	int r;
+
+	dsi->dss = dss;
+
+	dsi_init_pll_data(dss, dsi);
+
+	r = dsi_runtime_get(dsi);
+	if (r)
+		return r;
+
+	rev = dsi_read_reg(dsi, DSI_REVISION);
+	dev_dbg(dev, "OMAP DSI rev %d.%d\n",
+	       FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
+
+	dsi->line_buffer_size = dsi_get_line_buf_size(dsi);
+
+	dsi_runtime_put(dsi);
+
+	snprintf(name, sizeof(name), "dsi%u_regs", dsi->module_id + 1);
+	dsi->debugfs.regs = dss_debugfs_create_file(dss, name,
+						    dsi_dump_dsi_regs, &dsi);
+#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
+	snprintf(name, sizeof(name), "dsi%u_irqs", dsi->module_id + 1);
+	dsi->debugfs.irqs = dss_debugfs_create_file(dss, name,
+						    dsi_dump_dsi_irqs, &dsi);
+#endif
+	snprintf(name, sizeof(name), "dsi%u_clks", dsi->module_id + 1);
+	dsi->debugfs.clks = dss_debugfs_create_file(dss, name,
+						    dsi_dump_dsi_clocks, &dsi);
+
+	return 0;
+}
+
+static void dsi_unbind(struct device *dev, struct device *master, void *data)
+{
+	struct dsi_data *dsi = dev_get_drvdata(dev);
+
+	dss_debugfs_remove_file(dsi->debugfs.clks);
+	dss_debugfs_remove_file(dsi->debugfs.irqs);
+	dss_debugfs_remove_file(dsi->debugfs.regs);
+
+	of_platform_depopulate(dev);
+
+	WARN_ON(dsi->scp_clk_refcount > 0);
+
+	dss_pll_unregister(&dsi->pll);
+}
+
+static const struct component_ops dsi_component_ops = {
+	.bind	= dsi_bind,
+	.unbind	= dsi_unbind,
+};
+
+/* -----------------------------------------------------------------------------
+ * Probe & Remove, Suspend & Resume
+ */
+
+static int dsi_init_output(struct dsi_data *dsi)
+{
+	struct omap_dss_device *out = &dsi->output;
+	int r;
+
+	out->dev = dsi->dev;
+	out->id = dsi->module_id == 0 ?
+			OMAP_DSS_OUTPUT_DSI1 : OMAP_DSS_OUTPUT_DSI2;
+
+	out->output_type = OMAP_DISPLAY_TYPE_DSI;
+	out->name = dsi->module_id == 0 ? "dsi.0" : "dsi.1";
+	out->dispc_channel = dsi_get_channel(dsi);
+	out->ops = &dsi_ops;
+	out->owner = THIS_MODULE;
+	out->of_ports = BIT(0);
+	out->bus_flags = DRM_BUS_FLAG_PIXDATA_POSEDGE
+		       | DRM_BUS_FLAG_DE_HIGH
+		       | DRM_BUS_FLAG_SYNC_NEGEDGE;
+
+	out->next = omapdss_of_find_connected_device(out->dev->of_node, 0);
+	if (IS_ERR(out->next)) {
+		if (PTR_ERR(out->next) != -EPROBE_DEFER)
+			dev_err(out->dev, "failed to find video sink\n");
+		return PTR_ERR(out->next);
+	}
+
+	r = omapdss_output_validate(out);
+	if (r) {
+		omapdss_device_put(out->next);
+		out->next = NULL;
+		return r;
+	}
+
+	omapdss_device_register(out);
+
+	return 0;
+}
+
+static void dsi_uninit_output(struct dsi_data *dsi)
+{
+	struct omap_dss_device *out = &dsi->output;
+
+	if (out->next)
+		omapdss_device_put(out->next);
+	omapdss_device_unregister(out);
+}
+
+static int dsi_probe_of(struct dsi_data *dsi)
+{
+	struct device_node *node = dsi->dev->of_node;
+	struct property *prop;
+	u32 lane_arr[10];
+	int len, num_pins;
+	int r, i;
+	struct device_node *ep;
+	struct omap_dsi_pin_config pin_cfg;
+
+	ep = of_graph_get_endpoint_by_regs(node, 0, 0);
+	if (!ep)
+		return 0;
+
+	prop = of_find_property(ep, "lanes", &len);
+	if (prop == NULL) {
+		dev_err(dsi->dev, "failed to find lane data\n");
+		r = -EINVAL;
+		goto err;
+	}
+
+	num_pins = len / sizeof(u32);
+
+	if (num_pins < 4 || num_pins % 2 != 0 ||
+		num_pins > dsi->num_lanes_supported * 2) {
+		dev_err(dsi->dev, "bad number of lanes\n");
+		r = -EINVAL;
+		goto err;
+	}
+
+	r = of_property_read_u32_array(ep, "lanes", lane_arr, num_pins);
+	if (r) {
+		dev_err(dsi->dev, "failed to read lane data\n");
+		goto err;
+	}
+
+	pin_cfg.num_pins = num_pins;
+	for (i = 0; i < num_pins; ++i)
+		pin_cfg.pins[i] = (int)lane_arr[i];
+
+	r = dsi_configure_pins(&dsi->output, &pin_cfg);
+	if (r) {
+		dev_err(dsi->dev, "failed to configure pins");
+		goto err;
+	}
+
+	of_node_put(ep);
+
+	return 0;
+
+err:
+	of_node_put(ep);
+	return r;
+}
+
 static const struct dsi_of_data dsi_of_data_omap34xx = {
 	.model = DSI_MODEL_OMAP3,
 	.pll_hw = &dss_omap3_dsi_pll_hw,
@@ -5297,23 +5287,21 @@ static const struct soc_device_attribute dsi_soc_devices[] = {
 	{ /* sentinel */ }
 };
 
-static int dsi_bind(struct device *dev, struct device *master, void *data)
+static int dsi_probe(struct platform_device *pdev)
 {
-	struct platform_device *pdev = to_platform_device(dev);
-	struct dss_device *dss = dss_get_device(master);
 	const struct soc_device_attribute *soc;
 	const struct dsi_module_id_data *d;
-	u32 rev;
-	int r, i;
+	struct device *dev = &pdev->dev;
 	struct dsi_data *dsi;
 	struct resource *dsi_mem;
 	struct resource *res;
+	unsigned int i;
+	int r;
 
 	dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL);
 	if (!dsi)
 		return -ENOMEM;
 
-	dsi->dss = dss;
 	dsi->dev = dev;
 	dev_set_drvdata(dev, dsi);
 
@@ -5364,6 +5352,13 @@ static int dsi_bind(struct device *dev, struct device *master, void *data)
 		return r;
 	}
 
+	dsi->vdds_dsi_reg = devm_regulator_get(dev, "vdd");
+	if (IS_ERR(dsi->vdds_dsi_reg)) {
+		if (PTR_ERR(dsi->vdds_dsi_reg) != -EPROBE_DEFER)
+			DSSERR("can't get DSI VDD regulator\n");
+		return PTR_ERR(dsi->vdds_dsi_reg);
+	}
+
 	soc = soc_device_match(dsi_soc_devices);
 	if (soc)
 		dsi->data = soc->data;
@@ -5410,108 +5405,65 @@ static int dsi_bind(struct device *dev, struct device *master, void *data)
 	if (r)
 		return r;
 
-	dsi_init_pll_data(dss, dsi);
-
 	pm_runtime_enable(dev);
 
-	r = dsi_runtime_get(dsi);
-	if (r)
-		goto err_runtime_get;
-
-	rev = dsi_read_reg(dsi, DSI_REVISION);
-	dev_dbg(dev, "OMAP DSI rev %d.%d\n",
-	       FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
-
 	/* DSI on OMAP3 doesn't have register DSI_GNQ, set number
 	 * of data to 3 by default */
-	if (dsi->data->quirks & DSI_QUIRK_GNQ)
+	if (dsi->data->quirks & DSI_QUIRK_GNQ) {
+		dsi_runtime_get(dsi);
 		/* NB_DATA_LANES */
 		dsi->num_lanes_supported = 1 + REG_GET(dsi, DSI_GNQ, 11, 9);
-	else
+		dsi_runtime_put(dsi);
+	} else {
 		dsi->num_lanes_supported = 3;
+	}
 
-	dsi->line_buffer_size = dsi_get_line_buf_size(dsi);
+	r = of_platform_populate(dev->of_node, NULL, NULL, dev);
+	if (r) {
+		DSSERR("Failed to populate DSI child devices: %d\n", r);
+		goto err_pm_disable;
+	}
 
-	dsi_init_output(dsi);
+	r = dsi_init_output(dsi);
+	if (r)
+		goto err_of_depopulate;
 
 	r = dsi_probe_of(dsi);
 	if (r) {
 		DSSERR("Invalid DSI DT data\n");
-		goto err_probe_of;
+		goto err_uninit_output;
 	}
 
-	r = of_platform_populate(dev->of_node, NULL, NULL, dev);
+	r = component_add(&pdev->dev, &dsi_component_ops);
 	if (r)
-		DSSERR("Failed to populate DSI child devices: %d\n", r);
-
-	dsi_runtime_put(dsi);
-
-	if (dsi->module_id == 0)
-		dsi->debugfs.regs = dss_debugfs_create_file(dss, "dsi1_regs",
-							    dsi1_dump_regs,
-							    &dsi);
-	else
-		dsi->debugfs.regs = dss_debugfs_create_file(dss, "dsi2_regs",
-							    dsi2_dump_regs,
-							    &dsi);
-#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
-	if (dsi->module_id == 0)
-		dsi->debugfs.irqs = dss_debugfs_create_file(dss, "dsi1_irqs",
-							    dsi1_dump_irqs,
-							    &dsi);
-	else
-		dsi->debugfs.irqs = dss_debugfs_create_file(dss, "dsi2_irqs",
-							    dsi2_dump_irqs,
-							    &dsi);
-#endif
+		goto err_uninit_output;
 
 	return 0;
 
-err_probe_of:
+err_uninit_output:
 	dsi_uninit_output(dsi);
-	dsi_runtime_put(dsi);
-
-err_runtime_get:
+err_of_depopulate:
+	of_platform_depopulate(dev);
+err_pm_disable:
 	pm_runtime_disable(dev);
 	return r;
 }
 
-static void dsi_unbind(struct device *dev, struct device *master, void *data)
+static int dsi_remove(struct platform_device *pdev)
 {
-	struct dsi_data *dsi = dev_get_drvdata(dev);
-
-	dss_debugfs_remove_file(dsi->debugfs.irqs);
-	dss_debugfs_remove_file(dsi->debugfs.regs);
-
-	of_platform_depopulate(dev);
+	struct dsi_data *dsi = platform_get_drvdata(pdev);
 
-	WARN_ON(dsi->scp_clk_refcount > 0);
-
-	dss_pll_unregister(&dsi->pll);
+	component_del(&pdev->dev, &dsi_component_ops);
 
 	dsi_uninit_output(dsi);
 
-	pm_runtime_disable(dev);
+	pm_runtime_disable(&pdev->dev);
 
 	if (dsi->vdds_dsi_reg != NULL && dsi->vdds_dsi_enabled) {
 		regulator_disable(dsi->vdds_dsi_reg);
 		dsi->vdds_dsi_enabled = false;
 	}
-}
 
-static const struct component_ops dsi_component_ops = {
-	.bind	= dsi_bind,
-	.unbind	= dsi_unbind,
-};
-
-static int dsi_probe(struct platform_device *pdev)
-{
-	return component_add(&pdev->dev, &dsi_component_ops);
-}
-
-static int dsi_remove(struct platform_device *pdev)
-{
-	component_del(&pdev->dev, &dsi_component_ops);
 	return 0;
 }
 
@@ -5525,19 +5477,12 @@ static int dsi_runtime_suspend(struct device *dev)
 	/* wait for current handler to finish before turning the DSI off */
 	synchronize_irq(dsi->irq);
 
-	dispc_runtime_put(dsi->dss->dispc);
-
 	return 0;
 }
 
 static int dsi_runtime_resume(struct device *dev)
 {
 	struct dsi_data *dsi = dev_get_drvdata(dev);
-	int r;
-
-	r = dispc_runtime_get(dsi->dss->dispc);
-	if (r)
-		return r;
 
 	dsi->is_enabled = true;
 	/* ensure the irq handler sees the is_enabled value */

+ 22 - 25
drivers/gpu/drm/omapdrm/dss/dss-of.c

@@ -21,7 +21,8 @@
 
 #include "omapdss.h"
 
-struct device_node *dss_of_port_get_parent_device(struct device_node *port)
+static struct device_node *
+dss_of_port_get_parent_device(struct device_node *port)
 {
 	struct device_node *np;
 	int i;
@@ -45,41 +46,37 @@ struct device_node *dss_of_port_get_parent_device(struct device_node *port)
 	return NULL;
 }
 
-u32 dss_of_port_get_port_number(struct device_node *port)
-{
-	int r;
-	u32 reg;
-
-	r = of_property_read_u32(port, "reg", &reg);
-	if (r)
-		reg = 0;
-
-	return reg;
-}
-
 struct omap_dss_device *
-omapdss_of_find_source_for_first_ep(struct device_node *node)
+omapdss_of_find_connected_device(struct device_node *node, unsigned int port)
 {
-	struct device_node *ep;
+	struct device_node *src_node;
 	struct device_node *src_port;
+	struct device_node *ep;
 	struct omap_dss_device *src;
+	u32 port_number = 0;
 
-	ep = of_graph_get_endpoint_by_regs(node, 0, 0);
+	/* Get the endpoint... */
+	ep = of_graph_get_endpoint_by_regs(node, port, 0);
 	if (!ep)
-		return ERR_PTR(-EINVAL);
+		return NULL;
 
+	/* ... and its remote port... */
 	src_port = of_graph_get_remote_port(ep);
-	if (!src_port) {
-		of_node_put(ep);
-		return ERR_PTR(-EINVAL);
-	}
-
 	of_node_put(ep);
+	if (!src_port)
+		return NULL;
 
-	src = omap_dss_find_output_by_port_node(src_port);
-
+	/* ... and the remote port's number and parent... */
+	of_property_read_u32(src_port, "reg", &port_number);
+	src_node = dss_of_port_get_parent_device(src_port);
 	of_node_put(src_port);
+	if (!src_node)
+		return ERR_PTR(-EINVAL);
+
+	/* ... and finally the connected device. */
+	src = omapdss_find_device_by_port(src_node, port_number);
+	of_node_put(src_node);
 
 	return src ? src : ERR_PTR(-EPROBE_DEFER);
 }
-EXPORT_SYMBOL_GPL(omapdss_of_find_source_for_first_ep);
+EXPORT_SYMBOL_GPL(omapdss_of_find_connected_device);

+ 38 - 20
drivers/gpu/drm/omapdrm/dss/dss.c

@@ -394,9 +394,6 @@ static int dss_debug_dump_clocks(struct seq_file *s, void *p)
 
 	dss_dump_clocks(dss, s);
 	dispc_dump_clocks(dss->dispc, s);
-#ifdef CONFIG_OMAP2_DSS_DSI
-	dsi_dump_clocks(s);
-#endif
 	return 0;
 }
 
@@ -681,12 +678,6 @@ unsigned long dss_get_max_fck_rate(struct dss_device *dss)
 	return dss->feat->fck_freq_max;
 }
 
-enum omap_dss_output_id dss_get_supported_outputs(struct dss_device *dss,
-						  enum omap_channel channel)
-{
-	return dss->feat->outputs[channel];
-}
-
 static int dss_setup_default_clock(struct dss_device *dss)
 {
 	unsigned long max_dss_fck, prate;
@@ -956,7 +947,7 @@ dss_debugfs_create_file(struct dss_device *dss, const char *name,
 				&dss_debug_fops);
 	if (IS_ERR(d)) {
 		kfree(entry);
-		return ERR_PTR(PTR_ERR(d));
+		return ERR_CAST(d);
 	}
 
 	entry->dentry = d;
@@ -1183,7 +1174,8 @@ static int dss_init_ports(struct dss_device *dss)
 	struct platform_device *pdev = dss->pdev;
 	struct device_node *parent = pdev->dev.of_node;
 	struct device_node *port;
-	int i;
+	unsigned int i;
+	int r;
 
 	for (i = 0; i < dss->feat->num_ports; i++) {
 		port = of_graph_get_port_by_id(parent, i);
@@ -1192,11 +1184,17 @@ static int dss_init_ports(struct dss_device *dss)
 
 		switch (dss->feat->ports[i]) {
 		case OMAP_DISPLAY_TYPE_DPI:
-			dpi_init_port(dss, pdev, port, dss->feat->model);
+			r = dpi_init_port(dss, pdev, port, dss->feat->model);
+			if (r)
+				return r;
 			break;
+
 		case OMAP_DISPLAY_TYPE_SDI:
-			sdi_init_port(dss, pdev, port);
+			r = sdi_init_port(dss, pdev, port);
+			if (r)
+				return r;
 			break;
+
 		default:
 			break;
 		}
@@ -1315,6 +1313,7 @@ static const struct soc_device_attribute dss_soc_devices[] = {
 static int dss_bind(struct device *dev)
 {
 	struct dss_device *dss = dev_get_drvdata(dev);
+	struct platform_device *drm_pdev;
 	int r;
 
 	r = component_bind_all(dev, NULL);
@@ -1323,14 +1322,25 @@ static int dss_bind(struct device *dev)
 
 	pm_set_vt_switch(0);
 
-	omapdss_gather_components(dev);
 	omapdss_set_dss(dss);
 
+	drm_pdev = platform_device_register_simple("omapdrm", 0, NULL, 0);
+	if (IS_ERR(drm_pdev)) {
+		component_unbind_all(dev, NULL);
+		return PTR_ERR(drm_pdev);
+	}
+
+	dss->drm_pdev = drm_pdev;
+
 	return 0;
 }
 
 static void dss_unbind(struct device *dev)
 {
+	struct dss_device *dss = dev_get_drvdata(dev);
+
+	platform_device_unregister(dss->drm_pdev);
+
 	omapdss_set_dss(NULL);
 
 	component_unbind_all(dev, NULL);
@@ -1474,14 +1484,23 @@ static int dss_probe(struct platform_device *pdev)
 						   dss);
 
 	/* Add all the child devices as components. */
+	r = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
+	if (r)
+		goto err_uninit_debugfs;
+
+	omapdss_gather_components(&pdev->dev);
+
 	device_for_each_child(&pdev->dev, &match, dss_add_child_component);
 
 	r = component_master_add_with_match(&pdev->dev, &dss_component_ops, match);
 	if (r)
-		goto err_uninit_debugfs;
+		goto err_of_depopulate;
 
 	return 0;
 
+err_of_depopulate:
+	of_platform_depopulate(&pdev->dev);
+
 err_uninit_debugfs:
 	dss_debugfs_remove_file(dss->debugfs.clk);
 	dss_debugfs_remove_file(dss->debugfs.dss);
@@ -1510,6 +1529,8 @@ static int dss_remove(struct platform_device *pdev)
 {
 	struct dss_device *dss = platform_get_drvdata(pdev);
 
+	of_platform_depopulate(&pdev->dev);
+
 	component_master_del(&pdev->dev, &dss_component_ops);
 
 	dss_debugfs_remove_file(dss->debugfs.clk);
@@ -1539,12 +1560,9 @@ static void dss_shutdown(struct platform_device *pdev)
 
 	DSSDBG("shutdown\n");
 
-	for_each_dss_dev(dssdev) {
-		if (!dssdev->driver)
-			continue;
-
+	for_each_dss_display(dssdev) {
 		if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
-			dssdev->driver->disable(dssdev);
+			dssdev->ops->disable(dssdev);
 	}
 }
 

+ 4 - 7
drivers/gpu/drm/omapdrm/dss/dss.h

@@ -238,6 +238,8 @@ struct dss_device {
 	struct regmap	*syscon_pll_ctrl;
 	u32		syscon_pll_ctrl_offset;
 
+	struct platform_device *drm_pdev;
+
 	struct clk	*parent_clk;
 	struct clk	*dss_clk;
 	unsigned long	dss_clk_rate;
@@ -267,6 +269,8 @@ struct dss_device {
 
 	struct dispc_device *dispc;
 	const struct dispc_ops *dispc_ops;
+	const struct dss_mgr_ops *mgr_ops;
+	struct omap_drm_private *mgr_ops_priv;
 };
 
 /* core */
@@ -313,8 +317,6 @@ void dss_runtime_put(struct dss_device *dss);
 
 unsigned long dss_get_dispc_clk_rate(struct dss_device *dss);
 unsigned long dss_get_max_fck_rate(struct dss_device *dss);
-enum omap_dss_output_id dss_get_supported_outputs(struct dss_device *dss,
-						  enum omap_channel channel);
 int dss_dpi_select_source(struct dss_device *dss, int port,
 			  enum omap_channel channel);
 void dss_select_hdmi_venc_clk_source(struct dss_device *dss,
@@ -374,8 +376,6 @@ static inline void sdi_uninit_port(struct device_node *port)
 
 #ifdef CONFIG_OMAP2_DSS_DSI
 
-void dsi_dump_clocks(struct seq_file *s);
-
 void dsi_irq_handler(void);
 
 #endif
@@ -417,9 +417,6 @@ bool dispc_div_calc(struct dispc_device *dispc, unsigned long dispc_freq,
 		    unsigned long pck_min, unsigned long pck_max,
 		    dispc_div_calc_func func, void *data);
 
-bool dispc_mgr_timings_ok(struct dispc_device *dispc,
-			  enum omap_channel channel,
-			  const struct videomode *vm);
 int dispc_calc_clock_rates(struct dispc_device *dispc,
 			   unsigned long dispc_fclk_rate,
 			   struct dispc_clock_info *cinfo);

+ 4 - 4
drivers/gpu/drm/omapdrm/dss/hdmi.h

@@ -313,13 +313,13 @@ void hdmi_wp_clear_irqenable(struct hdmi_wp_data *wp, u32 mask);
 int hdmi_wp_set_phy_pwr(struct hdmi_wp_data *wp, enum hdmi_phy_pwr val);
 int hdmi_wp_set_pll_pwr(struct hdmi_wp_data *wp, enum hdmi_pll_pwr val);
 void hdmi_wp_video_config_format(struct hdmi_wp_data *wp,
-		struct hdmi_video_format *video_fmt);
+		const struct hdmi_video_format *video_fmt);
 void hdmi_wp_video_config_interface(struct hdmi_wp_data *wp,
-		struct videomode *vm);
+		const struct videomode *vm);
 void hdmi_wp_video_config_timing(struct hdmi_wp_data *wp,
-		struct videomode *vm);
+		const struct videomode *vm);
 void hdmi_wp_init_vid_fmt_timings(struct hdmi_video_format *video_fmt,
-		struct videomode *vm, struct hdmi_config *param);
+		struct videomode *vm, const struct hdmi_config *param);
 int hdmi_wp_init(struct platform_device *pdev, struct hdmi_wp_data *wp,
 		 unsigned int version);
 phys_addr_t hdmi_wp_get_audio_dma_addr(struct hdmi_wp_data *wp);

+ 176 - 206
drivers/gpu/drm/omapdrm/dss/hdmi4.c

@@ -108,26 +108,6 @@ static irqreturn_t hdmi_irq_handler(int irq, void *data)
 	return IRQ_HANDLED;
 }
 
-static int hdmi_init_regulator(struct omap_hdmi *hdmi)
-{
-	struct regulator *reg;
-
-	if (hdmi->vdda_reg != NULL)
-		return 0;
-
-	reg = devm_regulator_get(&hdmi->pdev->dev, "vdda");
-
-	if (IS_ERR(reg)) {
-		if (PTR_ERR(reg) != -EPROBE_DEFER)
-			DSSERR("can't get VDDA regulator\n");
-		return PTR_ERR(reg);
-	}
-
-	hdmi->vdda_reg = reg;
-
-	return 0;
-}
-
 static int hdmi_power_on_core(struct omap_hdmi *hdmi)
 {
 	int r;
@@ -174,7 +154,7 @@ static void hdmi_power_off_core(struct omap_hdmi *hdmi)
 static int hdmi_power_on_full(struct omap_hdmi *hdmi)
 {
 	int r;
-	struct videomode *vm;
+	const struct videomode *vm;
 	struct hdmi_wp_data *wp = &hdmi->wp;
 	struct dss_pll_clock_info hdmi_cinfo = { 0 };
 	unsigned int pc;
@@ -227,9 +207,6 @@ static int hdmi_power_on_full(struct omap_hdmi *hdmi)
 
 	hdmi4_configure(&hdmi->core, &hdmi->wp, &hdmi->cfg);
 
-	/* tv size */
-	dss_mgr_set_timings(&hdmi->output, vm);
-
 	r = dss_mgr_enable(&hdmi->output);
 	if (r)
 		goto err_mgr_enable;
@@ -271,19 +248,8 @@ static void hdmi_power_off_full(struct omap_hdmi *hdmi)
 	hdmi_power_off_core(hdmi);
 }
 
-static int hdmi_display_check_timing(struct omap_dss_device *dssdev,
-				     struct videomode *vm)
-{
-	struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
-
-	if (!dispc_mgr_timings_ok(hdmi->dss->dispc, dssdev->dispc_channel, vm))
-		return -EINVAL;
-
-	return 0;
-}
-
-static void hdmi_display_set_timing(struct omap_dss_device *dssdev,
-				    struct videomode *vm)
+static void hdmi_display_set_timings(struct omap_dss_device *dssdev,
+				     const struct videomode *vm)
 {
 	struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
 
@@ -296,14 +262,6 @@ static void hdmi_display_set_timing(struct omap_dss_device *dssdev,
 	mutex_unlock(&hdmi->lock);
 }
 
-static void hdmi_display_get_timings(struct omap_dss_device *dssdev,
-				     struct videomode *vm)
-{
-	struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
-
-	*vm = hdmi->cfg.vm;
-}
-
 static int hdmi_dump_regs(struct seq_file *s, void *p)
 {
 	struct omap_hdmi *hdmi = s->private;
@@ -456,44 +414,25 @@ void hdmi4_core_disable(struct hdmi_core_data *core)
 	mutex_unlock(&hdmi->lock);
 }
 
-static int hdmi_connect(struct omap_dss_device *dssdev,
-		struct omap_dss_device *dst)
+static int hdmi_connect(struct omap_dss_device *src,
+			struct omap_dss_device *dst)
 {
-	struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
 	int r;
 
-	r = hdmi_init_regulator(hdmi);
+	r = omapdss_device_connect(dst->dss, dst, dst->next);
 	if (r)
 		return r;
 
-	r = dss_mgr_connect(&hdmi->output, dssdev);
-	if (r)
-		return r;
-
-	r = omapdss_output_set_device(dssdev, dst);
-	if (r) {
-		DSSERR("failed to connect output to new device: %s\n",
-				dst->name);
-		dss_mgr_disconnect(&hdmi->output, dssdev);
-		return r;
-	}
-
+	dst->dispc_channel_connected = true;
 	return 0;
 }
 
-static void hdmi_disconnect(struct omap_dss_device *dssdev,
-		struct omap_dss_device *dst)
+static void hdmi_disconnect(struct omap_dss_device *src,
+			    struct omap_dss_device *dst)
 {
-	struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
-
-	WARN_ON(dst != dssdev->dst);
+	dst->dispc_channel_connected = false;
 
-	if (dst != dssdev->dst)
-		return;
-
-	omapdss_output_unset_device(dssdev);
-
-	dss_mgr_disconnect(&hdmi->output, dssdev);
+	omapdss_device_disconnect(dst, dst->next);
 }
 
 static int hdmi_read_edid(struct omap_dss_device *dssdev,
@@ -548,69 +487,28 @@ static int hdmi_set_hdmi_mode(struct omap_dss_device *dssdev,
 	return 0;
 }
 
-static const struct omapdss_hdmi_ops hdmi_ops = {
+static const struct omap_dss_device_ops hdmi_ops = {
 	.connect		= hdmi_connect,
 	.disconnect		= hdmi_disconnect,
 
 	.enable			= hdmi_display_enable,
 	.disable		= hdmi_display_disable,
 
-	.check_timings		= hdmi_display_check_timing,
-	.set_timings		= hdmi_display_set_timing,
-	.get_timings		= hdmi_display_get_timings,
+	.set_timings		= hdmi_display_set_timings,
 
 	.read_edid		= hdmi_read_edid,
-	.lost_hotplug		= hdmi_lost_hotplug,
-	.set_infoframe		= hdmi_set_infoframe,
-	.set_hdmi_mode		= hdmi_set_hdmi_mode,
-};
-
-static void hdmi_init_output(struct omap_hdmi *hdmi)
-{
-	struct omap_dss_device *out = &hdmi->output;
-
-	out->dev = &hdmi->pdev->dev;
-	out->id = OMAP_DSS_OUTPUT_HDMI;
-	out->output_type = OMAP_DISPLAY_TYPE_HDMI;
-	out->name = "hdmi.0";
-	out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT;
-	out->ops.hdmi = &hdmi_ops;
-	out->owner = THIS_MODULE;
-
-	omapdss_register_output(out);
-}
-
-static void hdmi_uninit_output(struct omap_hdmi *hdmi)
-{
-	struct omap_dss_device *out = &hdmi->output;
 
-	omapdss_unregister_output(out);
-}
-
-static int hdmi_probe_of(struct omap_hdmi *hdmi)
-{
-	struct platform_device *pdev = hdmi->pdev;
-	struct device_node *node = pdev->dev.of_node;
-	struct device_node *ep;
-	int r;
-
-	ep = of_graph_get_endpoint_by_regs(node, 0, 0);
-	if (!ep)
-		return 0;
-
-	r = hdmi_parse_lanes_of(pdev, ep, &hdmi->phy);
-	if (r)
-		goto err;
-
-	of_node_put(ep);
-	return 0;
+	.hdmi = {
+		.lost_hotplug		= hdmi_lost_hotplug,
+		.set_infoframe		= hdmi_set_infoframe,
+		.set_hdmi_mode		= hdmi_set_hdmi_mode,
+	},
+};
 
-err:
-	of_node_put(ep);
-	return r;
-}
+/* -----------------------------------------------------------------------------
+ * Audio Callbacks
+ */
 
-/* Audio callbacks */
 static int hdmi_audio_startup(struct device *dev,
 			      void (*abort_cb)(struct device *dev))
 {
@@ -725,86 +623,49 @@ static int hdmi_audio_register(struct omap_hdmi *hdmi)
 	return 0;
 }
 
-/* HDMI HW IP initialisation */
+/* -----------------------------------------------------------------------------
+ * Component Bind & Unbind
+ */
+
 static int hdmi4_bind(struct device *dev, struct device *master, void *data)
 {
-	struct platform_device *pdev = to_platform_device(dev);
 	struct dss_device *dss = dss_get_device(master);
-	struct omap_hdmi *hdmi;
+	struct omap_hdmi *hdmi = dev_get_drvdata(dev);
 	int r;
-	int irq;
 
-	hdmi = kzalloc(sizeof(*hdmi), GFP_KERNEL);
-	if (!hdmi)
-		return -ENOMEM;
-
-	hdmi->pdev = pdev;
 	hdmi->dss = dss;
-	dev_set_drvdata(&pdev->dev, hdmi);
-
-	mutex_init(&hdmi->lock);
-	spin_lock_init(&hdmi->audio_playing_lock);
 
-	r = hdmi_probe_of(hdmi);
-	if (r)
-		goto err_free;
-
-	r = hdmi_wp_init(pdev, &hdmi->wp, 4);
-	if (r)
-		goto err_free;
-
-	r = hdmi_pll_init(dss, pdev, &hdmi->pll, &hdmi->wp);
-	if (r)
-		goto err_free;
-
-	r = hdmi_phy_init(pdev, &hdmi->phy, 4);
+	r = hdmi_runtime_get(hdmi);
 	if (r)
-		goto err_pll;
+		return r;
 
-	r = hdmi4_core_init(pdev, &hdmi->core);
+	r = hdmi_pll_init(dss, hdmi->pdev, &hdmi->pll, &hdmi->wp);
 	if (r)
-		goto err_pll;
+		goto err_runtime_put;
 
-	r = hdmi4_cec_init(pdev, &hdmi->core, &hdmi->wp);
+	r = hdmi4_cec_init(hdmi->pdev, &hdmi->core, &hdmi->wp);
 	if (r)
-		goto err_pll;
-
-	irq = platform_get_irq(pdev, 0);
-	if (irq < 0) {
-		DSSERR("platform_get_irq failed\n");
-		r = -ENODEV;
-		goto err_pll;
-	}
-
-	r = devm_request_threaded_irq(&pdev->dev, irq,
-			NULL, hdmi_irq_handler,
-			IRQF_ONESHOT, "OMAP HDMI", hdmi);
-	if (r) {
-		DSSERR("HDMI IRQ request failed\n");
-		goto err_pll;
-	}
-
-	pm_runtime_enable(&pdev->dev);
-
-	hdmi_init_output(hdmi);
+		goto err_pll_uninit;
 
 	r = hdmi_audio_register(hdmi);
 	if (r) {
 		DSSERR("Registering HDMI audio failed\n");
-		hdmi_uninit_output(hdmi);
-		pm_runtime_disable(&pdev->dev);
-		return r;
+		goto err_cec_uninit;
 	}
 
 	hdmi->debugfs = dss_debugfs_create_file(dss, "hdmi", hdmi_dump_regs,
 					       hdmi);
 
+	hdmi_runtime_put(hdmi);
+
 	return 0;
 
-err_pll:
+err_cec_uninit:
+	hdmi4_cec_uninit(&hdmi->core);
+err_pll_uninit:
 	hdmi_pll_uninit(&hdmi->pll);
-err_free:
-	kfree(hdmi);
+err_runtime_put:
+	hdmi_runtime_put(hdmi);
 	return r;
 }
 
@@ -817,15 +678,8 @@ static void hdmi4_unbind(struct device *dev, struct device *master, void *data)
 	if (hdmi->audio_pdev)
 		platform_device_unregister(hdmi->audio_pdev);
 
-	hdmi_uninit_output(hdmi);
-
 	hdmi4_cec_uninit(&hdmi->core);
-
 	hdmi_pll_uninit(&hdmi->pll);
-
-	pm_runtime_disable(dev);
-
-	kfree(hdmi);
 }
 
 static const struct component_ops hdmi4_component_ops = {
@@ -833,42 +687,159 @@ static const struct component_ops hdmi4_component_ops = {
 	.unbind	= hdmi4_unbind,
 };
 
-static int hdmi4_probe(struct platform_device *pdev)
+/* -----------------------------------------------------------------------------
+ * Probe & Remove, Suspend & Resume
+ */
+
+static int hdmi4_init_output(struct omap_hdmi *hdmi)
 {
-	return component_add(&pdev->dev, &hdmi4_component_ops);
+	struct omap_dss_device *out = &hdmi->output;
+	int r;
+
+	out->dev = &hdmi->pdev->dev;
+	out->id = OMAP_DSS_OUTPUT_HDMI;
+	out->output_type = OMAP_DISPLAY_TYPE_HDMI;
+	out->name = "hdmi.0";
+	out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT;
+	out->ops = &hdmi_ops;
+	out->owner = THIS_MODULE;
+	out->of_ports = BIT(0);
+	out->ops_flags = OMAP_DSS_DEVICE_OP_EDID;
+
+	out->next = omapdss_of_find_connected_device(out->dev->of_node, 0);
+	if (IS_ERR(out->next)) {
+		if (PTR_ERR(out->next) != -EPROBE_DEFER)
+			dev_err(out->dev, "failed to find video sink\n");
+		return PTR_ERR(out->next);
+	}
+
+	r = omapdss_output_validate(out);
+	if (r) {
+		omapdss_device_put(out->next);
+		out->next = NULL;
+		return r;
+	}
+
+	omapdss_device_register(out);
+
+	return 0;
 }
 
-static int hdmi4_remove(struct platform_device *pdev)
+static void hdmi4_uninit_output(struct omap_hdmi *hdmi)
 {
-	component_del(&pdev->dev, &hdmi4_component_ops);
-	return 0;
+	struct omap_dss_device *out = &hdmi->output;
+
+	if (out->next)
+		omapdss_device_put(out->next);
+	omapdss_device_unregister(out);
 }
 
-static int hdmi_runtime_suspend(struct device *dev)
+static int hdmi4_probe_of(struct omap_hdmi *hdmi)
 {
-	struct omap_hdmi *hdmi = dev_get_drvdata(dev);
+	struct platform_device *pdev = hdmi->pdev;
+	struct device_node *node = pdev->dev.of_node;
+	struct device_node *ep;
+	int r;
 
-	dispc_runtime_put(hdmi->dss->dispc);
+	ep = of_graph_get_endpoint_by_regs(node, 0, 0);
+	if (!ep)
+		return 0;
 
-	return 0;
+	r = hdmi_parse_lanes_of(pdev, ep, &hdmi->phy);
+	of_node_put(ep);
+	return r;
 }
 
-static int hdmi_runtime_resume(struct device *dev)
+static int hdmi4_probe(struct platform_device *pdev)
 {
-	struct omap_hdmi *hdmi = dev_get_drvdata(dev);
+	struct omap_hdmi *hdmi;
+	int irq;
 	int r;
 
-	r = dispc_runtime_get(hdmi->dss->dispc);
-	if (r < 0)
-		return r;
+	hdmi = kzalloc(sizeof(*hdmi), GFP_KERNEL);
+	if (!hdmi)
+		return -ENOMEM;
+
+	hdmi->pdev = pdev;
+
+	dev_set_drvdata(&pdev->dev, hdmi);
+
+	mutex_init(&hdmi->lock);
+	spin_lock_init(&hdmi->audio_playing_lock);
+
+	r = hdmi4_probe_of(hdmi);
+	if (r)
+		goto err_free;
+
+	r = hdmi_wp_init(pdev, &hdmi->wp, 4);
+	if (r)
+		goto err_free;
+
+	r = hdmi_phy_init(pdev, &hdmi->phy, 4);
+	if (r)
+		goto err_free;
+
+	r = hdmi4_core_init(pdev, &hdmi->core);
+	if (r)
+		goto err_free;
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		DSSERR("platform_get_irq failed\n");
+		r = -ENODEV;
+		goto err_free;
+	}
+
+	r = devm_request_threaded_irq(&pdev->dev, irq,
+			NULL, hdmi_irq_handler,
+			IRQF_ONESHOT, "OMAP HDMI", hdmi);
+	if (r) {
+		DSSERR("HDMI IRQ request failed\n");
+		goto err_free;
+	}
+
+	hdmi->vdda_reg = devm_regulator_get(&pdev->dev, "vdda");
+	if (IS_ERR(hdmi->vdda_reg)) {
+		r = PTR_ERR(hdmi->vdda_reg);
+		if (r != -EPROBE_DEFER)
+			DSSERR("can't get VDDA regulator\n");
+		goto err_free;
+	}
+
+	pm_runtime_enable(&pdev->dev);
+
+	r = hdmi4_init_output(hdmi);
+	if (r)
+		goto err_pm_disable;
+
+	r = component_add(&pdev->dev, &hdmi4_component_ops);
+	if (r)
+		goto err_uninit_output;
 
 	return 0;
+
+err_uninit_output:
+	hdmi4_uninit_output(hdmi);
+err_pm_disable:
+	pm_runtime_disable(&pdev->dev);
+err_free:
+	kfree(hdmi);
+	return r;
 }
 
-static const struct dev_pm_ops hdmi_pm_ops = {
-	.runtime_suspend = hdmi_runtime_suspend,
-	.runtime_resume = hdmi_runtime_resume,
-};
+static int hdmi4_remove(struct platform_device *pdev)
+{
+	struct omap_hdmi *hdmi = platform_get_drvdata(pdev);
+
+	component_del(&pdev->dev, &hdmi4_component_ops);
+
+	hdmi4_uninit_output(hdmi);
+
+	pm_runtime_disable(&pdev->dev);
+
+	kfree(hdmi);
+	return 0;
+}
 
 static const struct of_device_id hdmi_of_match[] = {
 	{ .compatible = "ti,omap4-hdmi", },
@@ -880,7 +851,6 @@ struct platform_driver omapdss_hdmi4hw_driver = {
 	.remove		= hdmi4_remove,
 	.driver         = {
 		.name   = "omapdss_hdmi",
-		.pm	= &hdmi_pm_ops,
 		.of_match_table = hdmi_of_match,
 		.suppress_bind_attrs = true,
 	},

+ 162 - 199
drivers/gpu/drm/omapdrm/dss/hdmi5.c

@@ -117,24 +117,6 @@ static irqreturn_t hdmi_irq_handler(int irq, void *data)
 	return IRQ_HANDLED;
 }
 
-static int hdmi_init_regulator(struct omap_hdmi *hdmi)
-{
-	struct regulator *reg;
-
-	if (hdmi->vdda_reg != NULL)
-		return 0;
-
-	reg = devm_regulator_get(&hdmi->pdev->dev, "vdda");
-	if (IS_ERR(reg)) {
-		DSSERR("can't get VDDA regulator\n");
-		return PTR_ERR(reg);
-	}
-
-	hdmi->vdda_reg = reg;
-
-	return 0;
-}
-
 static int hdmi_power_on_core(struct omap_hdmi *hdmi)
 {
 	int r;
@@ -171,7 +153,7 @@ static void hdmi_power_off_core(struct omap_hdmi *hdmi)
 static int hdmi_power_on_full(struct omap_hdmi *hdmi)
 {
 	int r;
-	struct videomode *vm;
+	const struct videomode *vm;
 	struct dss_pll_clock_info hdmi_cinfo = { 0 };
 	unsigned int pc;
 
@@ -224,9 +206,6 @@ static int hdmi_power_on_full(struct omap_hdmi *hdmi)
 
 	hdmi5_configure(&hdmi->core, &hdmi->wp, &hdmi->cfg);
 
-	/* tv size */
-	dss_mgr_set_timings(&hdmi->output, vm);
-
 	r = dss_mgr_enable(&hdmi->output);
 	if (r)
 		goto err_mgr_enable;
@@ -268,19 +247,8 @@ static void hdmi_power_off_full(struct omap_hdmi *hdmi)
 	hdmi_power_off_core(hdmi);
 }
 
-static int hdmi_display_check_timing(struct omap_dss_device *dssdev,
-				     struct videomode *vm)
-{
-	struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
-
-	if (!dispc_mgr_timings_ok(hdmi->dss->dispc, dssdev->dispc_channel, vm))
-		return -EINVAL;
-
-	return 0;
-}
-
-static void hdmi_display_set_timing(struct omap_dss_device *dssdev,
-				    struct videomode *vm)
+static void hdmi_display_set_timings(struct omap_dss_device *dssdev,
+				     const struct videomode *vm)
 {
 	struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
 
@@ -293,14 +261,6 @@ static void hdmi_display_set_timing(struct omap_dss_device *dssdev,
 	mutex_unlock(&hdmi->lock);
 }
 
-static void hdmi_display_get_timings(struct omap_dss_device *dssdev,
-				     struct videomode *vm)
-{
-	struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
-
-	*vm = hdmi->cfg.vm;
-}
-
 static int hdmi_dump_regs(struct seq_file *s, void *p)
 {
 	struct omap_hdmi *hdmi = s->private;
@@ -459,44 +419,25 @@ static void hdmi_core_disable(struct omap_hdmi *hdmi)
 	mutex_unlock(&hdmi->lock);
 }
 
-static int hdmi_connect(struct omap_dss_device *dssdev,
-		struct omap_dss_device *dst)
+static int hdmi_connect(struct omap_dss_device *src,
+			struct omap_dss_device *dst)
 {
-	struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
 	int r;
 
-	r = hdmi_init_regulator(hdmi);
+	r = omapdss_device_connect(dst->dss, dst, dst->next);
 	if (r)
 		return r;
 
-	r = dss_mgr_connect(&hdmi->output, dssdev);
-	if (r)
-		return r;
-
-	r = omapdss_output_set_device(dssdev, dst);
-	if (r) {
-		DSSERR("failed to connect output to new device: %s\n",
-				dst->name);
-		dss_mgr_disconnect(&hdmi->output, dssdev);
-		return r;
-	}
-
+	dst->dispc_channel_connected = true;
 	return 0;
 }
 
-static void hdmi_disconnect(struct omap_dss_device *dssdev,
-		struct omap_dss_device *dst)
+static void hdmi_disconnect(struct omap_dss_device *src,
+			    struct omap_dss_device *dst)
 {
-	struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
-
-	WARN_ON(dst != dssdev->dst);
+	dst->dispc_channel_connected = false;
 
-	if (dst != dssdev->dst)
-		return;
-
-	omapdss_output_unset_device(dssdev);
-
-	dss_mgr_disconnect(&hdmi->output, dssdev);
+	omapdss_device_disconnect(dst, dst->next);
 }
 
 static int hdmi_read_edid(struct omap_dss_device *dssdev,
@@ -540,68 +481,27 @@ static int hdmi_set_hdmi_mode(struct omap_dss_device *dssdev,
 	return 0;
 }
 
-static const struct omapdss_hdmi_ops hdmi_ops = {
+static const struct omap_dss_device_ops hdmi_ops = {
 	.connect		= hdmi_connect,
 	.disconnect		= hdmi_disconnect,
 
 	.enable			= hdmi_display_enable,
 	.disable		= hdmi_display_disable,
 
-	.check_timings		= hdmi_display_check_timing,
-	.set_timings		= hdmi_display_set_timing,
-	.get_timings		= hdmi_display_get_timings,
+	.set_timings		= hdmi_display_set_timings,
 
 	.read_edid		= hdmi_read_edid,
-	.set_infoframe		= hdmi_set_infoframe,
-	.set_hdmi_mode		= hdmi_set_hdmi_mode,
-};
-
-static void hdmi_init_output(struct omap_hdmi *hdmi)
-{
-	struct omap_dss_device *out = &hdmi->output;
-
-	out->dev = &hdmi->pdev->dev;
-	out->id = OMAP_DSS_OUTPUT_HDMI;
-	out->output_type = OMAP_DISPLAY_TYPE_HDMI;
-	out->name = "hdmi.0";
-	out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT;
-	out->ops.hdmi = &hdmi_ops;
-	out->owner = THIS_MODULE;
-
-	omapdss_register_output(out);
-}
-
-static void hdmi_uninit_output(struct omap_hdmi *hdmi)
-{
-	struct omap_dss_device *out = &hdmi->output;
-
-	omapdss_unregister_output(out);
-}
-
-static int hdmi_probe_of(struct omap_hdmi *hdmi)
-{
-	struct platform_device *pdev = hdmi->pdev;
-	struct device_node *node = pdev->dev.of_node;
-	struct device_node *ep;
-	int r;
-
-	ep = of_graph_get_endpoint_by_regs(node, 0, 0);
-	if (!ep)
-		return 0;
 
-	r = hdmi_parse_lanes_of(pdev, ep, &hdmi->phy);
-	if (r)
-		goto err;
-
-	of_node_put(ep);
-	return 0;
+	.hdmi = {
+		.set_infoframe		= hdmi_set_infoframe,
+		.set_hdmi_mode		= hdmi_set_hdmi_mode,
+	},
+};
 
-err:
-	of_node_put(ep);
-	return r;
-}
+/* -----------------------------------------------------------------------------
+ * Audio Callbacks
+ */
 
-/* Audio callbacks */
 static int hdmi_audio_startup(struct device *dev,
 			      void (*abort_cb)(struct device *dev))
 {
@@ -722,27 +622,136 @@ static int hdmi_audio_register(struct omap_hdmi *hdmi)
 	return 0;
 }
 
-/* HDMI HW IP initialisation */
+/* -----------------------------------------------------------------------------
+ * Component Bind & Unbind
+ */
+
 static int hdmi5_bind(struct device *dev, struct device *master, void *data)
 {
-	struct platform_device *pdev = to_platform_device(dev);
 	struct dss_device *dss = dss_get_device(master);
-	struct omap_hdmi *hdmi;
+	struct omap_hdmi *hdmi = dev_get_drvdata(dev);
 	int r;
+
+	hdmi->dss = dss;
+
+	r = hdmi_pll_init(dss, hdmi->pdev, &hdmi->pll, &hdmi->wp);
+	if (r)
+		return r;
+
+	r = hdmi_audio_register(hdmi);
+	if (r) {
+		DSSERR("Registering HDMI audio failed %d\n", r);
+		goto err_pll_uninit;
+	}
+
+	hdmi->debugfs = dss_debugfs_create_file(dss, "hdmi", hdmi_dump_regs,
+						hdmi);
+
+	return 0;
+
+err_pll_uninit:
+	hdmi_pll_uninit(&hdmi->pll);
+	return r;
+}
+
+static void hdmi5_unbind(struct device *dev, struct device *master, void *data)
+{
+	struct omap_hdmi *hdmi = dev_get_drvdata(dev);
+
+	dss_debugfs_remove_file(hdmi->debugfs);
+
+	if (hdmi->audio_pdev)
+		platform_device_unregister(hdmi->audio_pdev);
+
+	hdmi_pll_uninit(&hdmi->pll);
+}
+
+static const struct component_ops hdmi5_component_ops = {
+	.bind	= hdmi5_bind,
+	.unbind	= hdmi5_unbind,
+};
+
+/* -----------------------------------------------------------------------------
+ * Probe & Remove, Suspend & Resume
+ */
+
+static int hdmi5_init_output(struct omap_hdmi *hdmi)
+{
+	struct omap_dss_device *out = &hdmi->output;
+	int r;
+
+	out->dev = &hdmi->pdev->dev;
+	out->id = OMAP_DSS_OUTPUT_HDMI;
+	out->output_type = OMAP_DISPLAY_TYPE_HDMI;
+	out->name = "hdmi.0";
+	out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT;
+	out->ops = &hdmi_ops;
+	out->owner = THIS_MODULE;
+	out->of_ports = BIT(0);
+	out->ops_flags = OMAP_DSS_DEVICE_OP_EDID;
+
+	out->next = omapdss_of_find_connected_device(out->dev->of_node, 0);
+	if (IS_ERR(out->next)) {
+		if (PTR_ERR(out->next) != -EPROBE_DEFER)
+			dev_err(out->dev, "failed to find video sink\n");
+		return PTR_ERR(out->next);
+	}
+
+	r = omapdss_output_validate(out);
+	if (r) {
+		omapdss_device_put(out->next);
+		out->next = NULL;
+		return r;
+	}
+
+	omapdss_device_register(out);
+
+	return 0;
+}
+
+static void hdmi5_uninit_output(struct omap_hdmi *hdmi)
+{
+	struct omap_dss_device *out = &hdmi->output;
+
+	if (out->next)
+		omapdss_device_put(out->next);
+	omapdss_device_unregister(out);
+}
+
+static int hdmi5_probe_of(struct omap_hdmi *hdmi)
+{
+	struct platform_device *pdev = hdmi->pdev;
+	struct device_node *node = pdev->dev.of_node;
+	struct device_node *ep;
+	int r;
+
+	ep = of_graph_get_endpoint_by_regs(node, 0, 0);
+	if (!ep)
+		return 0;
+
+	r = hdmi_parse_lanes_of(pdev, ep, &hdmi->phy);
+	of_node_put(ep);
+	return r;
+}
+
+static int hdmi5_probe(struct platform_device *pdev)
+{
+	struct omap_hdmi *hdmi;
 	int irq;
+	int r;
 
 	hdmi = kzalloc(sizeof(*hdmi), GFP_KERNEL);
 	if (!hdmi)
 		return -ENOMEM;
 
 	hdmi->pdev = pdev;
-	hdmi->dss = dss;
+
 	dev_set_drvdata(&pdev->dev, hdmi);
 
 	mutex_init(&hdmi->lock);
 	spin_lock_init(&hdmi->audio_playing_lock);
 
-	r = hdmi_probe_of(hdmi);
+	r = hdmi5_probe_of(hdmi);
 	if (r)
 		goto err_free;
 
@@ -750,23 +759,19 @@ static int hdmi5_bind(struct device *dev, struct device *master, void *data)
 	if (r)
 		goto err_free;
 
-	r = hdmi_pll_init(dss, pdev, &hdmi->pll, &hdmi->wp);
-	if (r)
-		goto err_free;
-
 	r = hdmi_phy_init(pdev, &hdmi->phy, 5);
 	if (r)
-		goto err_pll;
+		goto err_free;
 
 	r = hdmi5_core_init(pdev, &hdmi->core);
 	if (r)
-		goto err_pll;
+		goto err_free;
 
 	irq = platform_get_irq(pdev, 0);
 	if (irq < 0) {
 		DSSERR("platform_get_irq failed\n");
 		r = -ENODEV;
-		goto err_pll;
+		goto err_free;
 	}
 
 	r = devm_request_threaded_irq(&pdev->dev, irq,
@@ -774,93 +779,52 @@ static int hdmi5_bind(struct device *dev, struct device *master, void *data)
 			IRQF_ONESHOT, "OMAP HDMI", hdmi);
 	if (r) {
 		DSSERR("HDMI IRQ request failed\n");
-		goto err_pll;
+		goto err_free;
 	}
 
-	pm_runtime_enable(&pdev->dev);
+	hdmi->vdda_reg = devm_regulator_get(&pdev->dev, "vdda");
+	if (IS_ERR(hdmi->vdda_reg)) {
+		r = PTR_ERR(hdmi->vdda_reg);
+		if (r != -EPROBE_DEFER)
+			DSSERR("can't get VDDA regulator\n");
+		goto err_free;
+	}
 
-	hdmi_init_output(hdmi);
+	pm_runtime_enable(&pdev->dev);
 
-	r = hdmi_audio_register(hdmi);
-	if (r) {
-		DSSERR("Registering HDMI audio failed %d\n", r);
-		hdmi_uninit_output(hdmi);
-		pm_runtime_disable(&pdev->dev);
-		return r;
-	}
+	r = hdmi5_init_output(hdmi);
+	if (r)
+		goto err_pm_disable;
 
-	hdmi->debugfs = dss_debugfs_create_file(dss, "hdmi", hdmi_dump_regs,
-						hdmi);
+	r = component_add(&pdev->dev, &hdmi5_component_ops);
+	if (r)
+		goto err_uninit_output;
 
 	return 0;
 
-err_pll:
-	hdmi_pll_uninit(&hdmi->pll);
+err_uninit_output:
+	hdmi5_uninit_output(hdmi);
+err_pm_disable:
+	pm_runtime_disable(&pdev->dev);
 err_free:
 	kfree(hdmi);
 	return r;
 }
 
-static void hdmi5_unbind(struct device *dev, struct device *master, void *data)
-{
-	struct omap_hdmi *hdmi = dev_get_drvdata(dev);
-
-	dss_debugfs_remove_file(hdmi->debugfs);
-
-	if (hdmi->audio_pdev)
-		platform_device_unregister(hdmi->audio_pdev);
-
-	hdmi_uninit_output(hdmi);
-
-	hdmi_pll_uninit(&hdmi->pll);
-
-	pm_runtime_disable(dev);
-
-	kfree(hdmi);
-}
-
-static const struct component_ops hdmi5_component_ops = {
-	.bind	= hdmi5_bind,
-	.unbind	= hdmi5_unbind,
-};
-
-static int hdmi5_probe(struct platform_device *pdev)
-{
-	return component_add(&pdev->dev, &hdmi5_component_ops);
-}
-
 static int hdmi5_remove(struct platform_device *pdev)
 {
-	component_del(&pdev->dev, &hdmi5_component_ops);
-	return 0;
-}
-
-static int hdmi_runtime_suspend(struct device *dev)
-{
-	struct omap_hdmi *hdmi = dev_get_drvdata(dev);
+	struct omap_hdmi *hdmi = platform_get_drvdata(pdev);
 
-	dispc_runtime_put(hdmi->dss->dispc);
-
-	return 0;
-}
+	component_del(&pdev->dev, &hdmi5_component_ops);
 
-static int hdmi_runtime_resume(struct device *dev)
-{
-	struct omap_hdmi *hdmi = dev_get_drvdata(dev);
-	int r;
+	hdmi5_uninit_output(hdmi);
 
-	r = dispc_runtime_get(hdmi->dss->dispc);
-	if (r < 0)
-		return r;
+	pm_runtime_disable(&pdev->dev);
 
+	kfree(hdmi);
 	return 0;
 }
 
-static const struct dev_pm_ops hdmi_pm_ops = {
-	.runtime_suspend = hdmi_runtime_suspend,
-	.runtime_resume = hdmi_runtime_resume,
-};
-
 static const struct of_device_id hdmi_of_match[] = {
 	{ .compatible = "ti,omap5-hdmi", },
 	{ .compatible = "ti,dra7-hdmi", },
@@ -872,7 +836,6 @@ struct platform_driver omapdss_hdmi5hw_driver = {
 	.remove		= hdmi5_remove,
 	.driver         = {
 		.name   = "omapdss_hdmi5",
-		.pm	= &hdmi_pm_ops,
 		.of_match_table = hdmi_of_match,
 		.suppress_bind_attrs = true,
 	},

+ 3 - 3
drivers/gpu/drm/omapdrm/dss/hdmi5_core.c

@@ -287,7 +287,7 @@ void hdmi5_core_dump(struct hdmi_core_data *core, struct seq_file *s)
 }
 
 static void hdmi_core_init(struct hdmi_core_vid_config *video_cfg,
-			struct hdmi_config *cfg)
+			   const struct hdmi_config *cfg)
 {
 	DSSDBG("hdmi_core_init\n");
 
@@ -325,10 +325,10 @@ static void hdmi_core_init(struct hdmi_core_vid_config *video_cfg,
 
 /* DSS_HDMI_CORE_VIDEO_CONFIG */
 static void hdmi_core_video_config(struct hdmi_core_data *core,
-			struct hdmi_core_vid_config *cfg)
+			const struct hdmi_core_vid_config *cfg)
 {
 	void __iomem *base = core->base;
-	struct videomode *vm = &cfg->v_fc_config.vm;
+	const struct videomode *vm = &cfg->v_fc_config.vm;
 	unsigned char r = 0;
 	bool vsync_pol, hsync_pol;
 

+ 4 - 4
drivers/gpu/drm/omapdrm/dss/hdmi_wp.c

@@ -131,7 +131,7 @@ void hdmi_wp_video_stop(struct hdmi_wp_data *wp)
 }
 
 void hdmi_wp_video_config_format(struct hdmi_wp_data *wp,
-		struct hdmi_video_format *video_fmt)
+		const struct hdmi_video_format *video_fmt)
 {
 	u32 l = 0;
 
@@ -144,7 +144,7 @@ void hdmi_wp_video_config_format(struct hdmi_wp_data *wp,
 }
 
 void hdmi_wp_video_config_interface(struct hdmi_wp_data *wp,
-				    struct videomode *vm)
+				    const struct videomode *vm)
 {
 	u32 r;
 	bool vsync_inv, hsync_inv;
@@ -164,7 +164,7 @@ void hdmi_wp_video_config_interface(struct hdmi_wp_data *wp,
 }
 
 void hdmi_wp_video_config_timing(struct hdmi_wp_data *wp,
-				 struct videomode *vm)
+				 const struct videomode *vm)
 {
 	u32 timing_h = 0;
 	u32 timing_v = 0;
@@ -193,7 +193,7 @@ void hdmi_wp_video_config_timing(struct hdmi_wp_data *wp,
 }
 
 void hdmi_wp_init_vid_fmt_timings(struct hdmi_video_format *video_fmt,
-		struct videomode *vm, struct hdmi_config *param)
+		struct videomode *vm, const struct hdmi_config *param)
 {
 	DSSDBG("Enter hdmi_wp_video_init_format\n");
 

+ 96 - 210
drivers/gpu/drm/omapdrm/dss/omapdss.h

@@ -296,117 +296,14 @@ struct omap_dss_writeback_info {
 	u8 pre_mult_alpha;
 };
 
-struct omapdss_dpi_ops {
-	int (*connect)(struct omap_dss_device *dssdev,
-			struct omap_dss_device *dst);
-	void (*disconnect)(struct omap_dss_device *dssdev,
-			struct omap_dss_device *dst);
-
-	int (*enable)(struct omap_dss_device *dssdev);
-	void (*disable)(struct omap_dss_device *dssdev);
-
-	int (*check_timings)(struct omap_dss_device *dssdev,
-			     struct videomode *vm);
-	void (*set_timings)(struct omap_dss_device *dssdev,
-			    struct videomode *vm);
-	void (*get_timings)(struct omap_dss_device *dssdev,
-			    struct videomode *vm);
-};
-
-struct omapdss_sdi_ops {
-	int (*connect)(struct omap_dss_device *dssdev,
-			struct omap_dss_device *dst);
-	void (*disconnect)(struct omap_dss_device *dssdev,
-			struct omap_dss_device *dst);
-
-	int (*enable)(struct omap_dss_device *dssdev);
-	void (*disable)(struct omap_dss_device *dssdev);
-
-	int (*check_timings)(struct omap_dss_device *dssdev,
-			     struct videomode *vm);
-	void (*set_timings)(struct omap_dss_device *dssdev,
-			    struct videomode *vm);
-	void (*get_timings)(struct omap_dss_device *dssdev,
-			    struct videomode *vm);
-};
-
-struct omapdss_dvi_ops {
-	int (*connect)(struct omap_dss_device *dssdev,
-			struct omap_dss_device *dst);
-	void (*disconnect)(struct omap_dss_device *dssdev,
-			struct omap_dss_device *dst);
-
-	int (*enable)(struct omap_dss_device *dssdev);
-	void (*disable)(struct omap_dss_device *dssdev);
-
-	int (*check_timings)(struct omap_dss_device *dssdev,
-			     struct videomode *vm);
-	void (*set_timings)(struct omap_dss_device *dssdev,
-			    struct videomode *vm);
-	void (*get_timings)(struct omap_dss_device *dssdev,
-			    struct videomode *vm);
-};
-
-struct omapdss_atv_ops {
-	int (*connect)(struct omap_dss_device *dssdev,
-			struct omap_dss_device *dst);
-	void (*disconnect)(struct omap_dss_device *dssdev,
-			struct omap_dss_device *dst);
-
-	int (*enable)(struct omap_dss_device *dssdev);
-	void (*disable)(struct omap_dss_device *dssdev);
-
-	int (*check_timings)(struct omap_dss_device *dssdev,
-			     struct videomode *vm);
-	void (*set_timings)(struct omap_dss_device *dssdev,
-			    struct videomode *vm);
-	void (*get_timings)(struct omap_dss_device *dssdev,
-			    struct videomode *vm);
-
-	int (*set_wss)(struct omap_dss_device *dssdev, u32 wss);
-	u32 (*get_wss)(struct omap_dss_device *dssdev);
-};
-
 struct omapdss_hdmi_ops {
-	int (*connect)(struct omap_dss_device *dssdev,
-			struct omap_dss_device *dst);
-	void (*disconnect)(struct omap_dss_device *dssdev,
-			struct omap_dss_device *dst);
-
-	int (*enable)(struct omap_dss_device *dssdev);
-	void (*disable)(struct omap_dss_device *dssdev);
-
-	int (*check_timings)(struct omap_dss_device *dssdev,
-			     struct videomode *vm);
-	void (*set_timings)(struct omap_dss_device *dssdev,
-			    struct videomode *vm);
-	void (*get_timings)(struct omap_dss_device *dssdev,
-			    struct videomode *vm);
-
-	int (*read_edid)(struct omap_dss_device *dssdev, u8 *buf, int len);
 	void (*lost_hotplug)(struct omap_dss_device *dssdev);
-	bool (*detect)(struct omap_dss_device *dssdev);
-
-	int (*register_hpd_cb)(struct omap_dss_device *dssdev,
-			       void (*cb)(void *cb_data,
-					  enum drm_connector_status status),
-			       void *cb_data);
-	void (*unregister_hpd_cb)(struct omap_dss_device *dssdev);
-	void (*enable_hpd)(struct omap_dss_device *dssdev);
-	void (*disable_hpd)(struct omap_dss_device *dssdev);
-
 	int (*set_hdmi_mode)(struct omap_dss_device *dssdev, bool hdmi_mode);
 	int (*set_infoframe)(struct omap_dss_device *dssdev,
 		const struct hdmi_avi_infoframe *avi);
 };
 
 struct omapdss_dsi_ops {
-	int (*connect)(struct omap_dss_device *dssdev,
-			struct omap_dss_device *dst);
-	void (*disconnect)(struct omap_dss_device *dssdev,
-			struct omap_dss_device *dst);
-
-	int (*enable)(struct omap_dss_device *dssdev);
 	void (*disable)(struct omap_dss_device *dssdev, bool disconnect_lanes,
 			bool enter_ulps);
 
@@ -457,53 +354,95 @@ struct omapdss_dsi_ops {
 			int channel, u16 plen);
 };
 
+struct omap_dss_device_ops {
+	int (*connect)(struct omap_dss_device *dssdev,
+			struct omap_dss_device *dst);
+	void (*disconnect)(struct omap_dss_device *dssdev,
+			struct omap_dss_device *dst);
+
+	int (*enable)(struct omap_dss_device *dssdev);
+	void (*disable)(struct omap_dss_device *dssdev);
+
+	int (*check_timings)(struct omap_dss_device *dssdev,
+			     struct videomode *vm);
+	void (*get_timings)(struct omap_dss_device *dssdev,
+			    struct videomode *vm);
+	void (*set_timings)(struct omap_dss_device *dssdev,
+			    const struct videomode *vm);
+
+	bool (*detect)(struct omap_dss_device *dssdev);
+
+	void (*register_hpd_cb)(struct omap_dss_device *dssdev,
+				void (*cb)(void *cb_data,
+					  enum drm_connector_status status),
+				void *cb_data);
+	void (*unregister_hpd_cb)(struct omap_dss_device *dssdev);
+
+	int (*read_edid)(struct omap_dss_device *dssdev, u8 *buf, int len);
+
+	union {
+		const struct omapdss_hdmi_ops hdmi;
+		const struct omapdss_dsi_ops dsi;
+	};
+};
+
+/**
+ * enum omap_dss_device_ops_flag - Indicates which device ops are supported
+ * @OMAP_DSS_DEVICE_OP_DETECT: The device supports output connection detection
+ * @OMAP_DSS_DEVICE_OP_HPD: The device supports all hot-plug-related operations
+ * @OMAP_DSS_DEVICE_OP_EDID: The device supports readind EDID
+ */
+enum omap_dss_device_ops_flag {
+	OMAP_DSS_DEVICE_OP_DETECT = BIT(0),
+	OMAP_DSS_DEVICE_OP_HPD = BIT(1),
+	OMAP_DSS_DEVICE_OP_EDID = BIT(2),
+};
+
+enum omap_dss_device_type {
+	OMAP_DSS_DEVICE_TYPE_OUTPUT = (1 << 0),
+	OMAP_DSS_DEVICE_TYPE_DISPLAY = (1 << 1),
+};
+
 struct omap_dss_device {
 	struct kobject kobj;
 	struct device *dev;
 
 	struct module *owner;
 
-	struct list_head panel_list;
+	struct dss_device *dss;
+	struct omap_dss_device *src;
+	struct omap_dss_device *dst;
+	struct omap_dss_device *next;
+
+	struct list_head list;
 
-	/* alias in the form of "display%d" */
-	char alias[16];
+	unsigned int alias_id;
 
 	enum omap_display_type type;
+	/*
+	 * DSS output type that this device generates (for DSS internal devices)
+	 * or requires (for external encoders). Must be OMAP_DISPLAY_TYPE_NONE
+	 * for display devices (connectors and panels) and to non-zero value for
+	 * all other devices.
+	 */
 	enum omap_display_type output_type;
 
-	struct {
-		struct videomode vm;
-
-		enum omap_dss_dsi_pixel_format dsi_pix_fmt;
-		enum omap_dss_dsi_mode dsi_mode;
-	} panel;
-
 	const char *name;
 
-	struct omap_dss_driver *driver;
-
-	union {
-		const struct omapdss_dpi_ops *dpi;
-		const struct omapdss_sdi_ops *sdi;
-		const struct omapdss_dvi_ops *dvi;
-		const struct omapdss_hdmi_ops *hdmi;
-		const struct omapdss_atv_ops *atv;
-		const struct omapdss_dsi_ops *dsi;
-	} ops;
+	const struct omap_dss_driver *driver;
+	const struct omap_dss_device_ops *ops;
+	unsigned long ops_flags;
+	u32 bus_flags;
 
 	/* helper variable for driver suspend/resume */
 	bool activate_after_resume;
 
 	enum omap_display_caps caps;
 
-	struct omap_dss_device *src;
-
 	enum omap_dss_display_state state;
 
 	/* OMAP DSS output specific fields */
 
-	struct list_head list;
-
 	/* DISPC channel for this output */
 	enum omap_channel dispc_channel;
 	bool dispc_channel_connected;
@@ -511,24 +450,11 @@ struct omap_dss_device {
 	/* output instance */
 	enum omap_dss_output_id id;
 
-	/* the port number in the DT node */
-	int port_num;
-
-	/* dynamic fields */
-	struct omap_dss_device *dst;
+	/* bitmask of port numbers in DT */
+	unsigned int of_ports;
 };
 
 struct omap_dss_driver {
-	int (*probe)(struct omap_dss_device *);
-	void (*remove)(struct omap_dss_device *);
-
-	int (*connect)(struct omap_dss_device *dssdev);
-	void (*disconnect)(struct omap_dss_device *dssdev);
-
-	int (*enable)(struct omap_dss_device *display);
-	void (*disable)(struct omap_dss_device *display);
-	int (*run_test)(struct omap_dss_device *display, int test);
-
 	int (*update)(struct omap_dss_device *dssdev,
 			       u16 x, u16 y, u16 w, u16 h);
 	int (*sync)(struct omap_dss_device *dssdev);
@@ -536,42 +462,12 @@ struct omap_dss_driver {
 	int (*enable_te)(struct omap_dss_device *dssdev, bool enable);
 	int (*get_te)(struct omap_dss_device *dssdev);
 
-	u8 (*get_rotate)(struct omap_dss_device *dssdev);
-	int (*set_rotate)(struct omap_dss_device *dssdev, u8 rotate);
-
-	bool (*get_mirror)(struct omap_dss_device *dssdev);
-	int (*set_mirror)(struct omap_dss_device *dssdev, bool enable);
-
 	int (*memory_read)(struct omap_dss_device *dssdev,
 			void *buf, size_t size,
 			u16 x, u16 y, u16 w, u16 h);
 
-	int (*check_timings)(struct omap_dss_device *dssdev,
-			     struct videomode *vm);
-	void (*set_timings)(struct omap_dss_device *dssdev,
-			    struct videomode *vm);
-	void (*get_timings)(struct omap_dss_device *dssdev,
-			    struct videomode *vm);
 	void (*get_size)(struct omap_dss_device *dssdev,
 			 unsigned int *width, unsigned int *height);
-
-	int (*set_wss)(struct omap_dss_device *dssdev, u32 wss);
-	u32 (*get_wss)(struct omap_dss_device *dssdev);
-
-	int (*read_edid)(struct omap_dss_device *dssdev, u8 *buf, int len);
-	bool (*detect)(struct omap_dss_device *dssdev);
-
-	int (*register_hpd_cb)(struct omap_dss_device *dssdev,
-			       void (*cb)(void *cb_data,
-					  enum drm_connector_status status),
-			       void *cb_data);
-	void (*unregister_hpd_cb)(struct omap_dss_device *dssdev);
-	void (*enable_hpd)(struct omap_dss_device *dssdev);
-	void (*disable_hpd)(struct omap_dss_device *dssdev);
-
-	int (*set_hdmi_mode)(struct omap_dss_device *dssdev, bool hdmi_mode);
-	int (*set_hdmi_infoframe)(struct omap_dss_device *dssdev,
-		const struct hdmi_avi_infoframe *avi);
 };
 
 struct dss_device *omapdss_get_dss(void);
@@ -581,27 +477,32 @@ static inline bool omapdss_is_initialized(void)
 	return !!omapdss_get_dss();
 }
 
-int omapdss_register_display(struct omap_dss_device *dssdev);
-void omapdss_unregister_display(struct omap_dss_device *dssdev);
-
-struct omap_dss_device *omap_dss_get_device(struct omap_dss_device *dssdev);
-void omap_dss_put_device(struct omap_dss_device *dssdev);
-#define for_each_dss_dev(d) while ((d = omap_dss_get_next_device(d)) != NULL)
-struct omap_dss_device *omap_dss_get_next_device(struct omap_dss_device *from);
+#define for_each_dss_display(d) \
+	while ((d = omapdss_device_get_next(d, OMAP_DSS_DEVICE_TYPE_DISPLAY)) != NULL)
+void omapdss_display_init(struct omap_dss_device *dssdev);
+struct omap_dss_device *omapdss_display_get(struct omap_dss_device *output);
+
+void omapdss_device_register(struct omap_dss_device *dssdev);
+void omapdss_device_unregister(struct omap_dss_device *dssdev);
+struct omap_dss_device *omapdss_device_get(struct omap_dss_device *dssdev);
+void omapdss_device_put(struct omap_dss_device *dssdev);
+struct omap_dss_device *omapdss_find_device_by_port(struct device_node *src,
+						    unsigned int port);
+struct omap_dss_device *omapdss_device_get_next(struct omap_dss_device *from,
+						enum omap_dss_device_type type);
+int omapdss_device_connect(struct dss_device *dss,
+			   struct omap_dss_device *src,
+			   struct omap_dss_device *dst);
+void omapdss_device_disconnect(struct omap_dss_device *src,
+			       struct omap_dss_device *dst);
 
 int omap_dss_get_num_overlay_managers(void);
 
 int omap_dss_get_num_overlays(void);
 
-int omapdss_register_output(struct omap_dss_device *output);
-void omapdss_unregister_output(struct omap_dss_device *output);
-struct omap_dss_device *omap_dss_get_output(enum omap_dss_output_id id);
-struct omap_dss_device *omap_dss_find_output_by_port_node(struct device_node *port);
-int omapdss_output_set_device(struct omap_dss_device *out,
-		struct omap_dss_device *dssdev);
-int omapdss_output_unset_device(struct omap_dss_device *out);
-
-struct omap_dss_device *omapdss_find_output_from_display(struct omap_dss_device *dssdev);
+#define for_each_dss_output(d) \
+	while ((d = omapdss_device_get_next(d, OMAP_DSS_DEVICE_TYPE_OUTPUT)) != NULL)
+int omapdss_output_validate(struct omap_dss_device *out);
 
 typedef void (*omap_dispc_isr_t) (void *arg, u32 mask);
 int omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask);
@@ -621,10 +522,7 @@ static inline bool omapdss_device_is_enabled(struct omap_dss_device *dssdev)
 }
 
 struct omap_dss_device *
-omapdss_of_find_source_for_first_ep(struct device_node *node);
-
-struct device_node *dss_of_port_get_parent_device(struct device_node *port);
-u32 dss_of_port_get_port_number(struct device_node *port);
+omapdss_of_find_connected_device(struct device_node *node, unsigned int port);
 
 enum dss_writeback_channel {
 	DSS_WB_LCD1_MGR =	0,
@@ -638,13 +536,6 @@ enum dss_writeback_channel {
 };
 
 struct dss_mgr_ops {
-	int (*connect)(struct omap_drm_private *priv,
-		       enum omap_channel channel,
-		       struct omap_dss_device *dst);
-	void (*disconnect)(struct omap_drm_private *priv,
-			   enum omap_channel channel,
-			   struct omap_dss_device *dst);
-
 	void (*start_update)(struct omap_drm_private *priv,
 			     enum omap_channel channel);
 	int (*enable)(struct omap_drm_private *priv,
@@ -665,14 +556,11 @@ struct dss_mgr_ops {
 			void (*handler)(void *), void *data);
 };
 
-int dss_install_mgr_ops(const struct dss_mgr_ops *mgr_ops,
+int dss_install_mgr_ops(struct dss_device *dss,
+			const struct dss_mgr_ops *mgr_ops,
 			struct omap_drm_private *priv);
-void dss_uninstall_mgr_ops(void);
+void dss_uninstall_mgr_ops(struct dss_device *dss);
 
-int dss_mgr_connect(struct omap_dss_device *dssdev,
-		    struct omap_dss_device *dst);
-void dss_mgr_disconnect(struct omap_dss_device *dssdev,
-			struct omap_dss_device *dst);
 void dss_mgr_set_timings(struct omap_dss_device *dssdev,
 		const struct videomode *vm);
 void dss_mgr_set_lcd_config(struct omap_dss_device *dssdev,
@@ -720,13 +608,14 @@ struct dispc_ops {
 	void (*mgr_set_lcd_config)(struct dispc_device *dispc,
 				   enum omap_channel channel,
 				   const struct dss_lcd_mgr_config *config);
+	int (*mgr_check_timings)(struct dispc_device *dispc,
+				 enum omap_channel channel,
+				 const struct videomode *vm);
 	void (*mgr_set_timings)(struct dispc_device *dispc,
 				enum omap_channel channel,
 				const struct videomode *vm);
 	void (*mgr_setup)(struct dispc_device *dispc, enum omap_channel channel,
 			  const struct omap_overlay_manager_info *info);
-	enum omap_dss_output_id (*mgr_get_supported_outputs)(
-			struct dispc_device *dispc, enum omap_channel channel);
 	u32 (*mgr_gamma_size)(struct dispc_device *dispc,
 			      enum omap_channel channel);
 	void (*mgr_set_gamma)(struct dispc_device *dispc,
@@ -757,9 +646,6 @@ struct dispc_ops {
 struct dispc_device *dispc_get_dispc(struct dss_device *dss);
 const struct dispc_ops *dispc_get_ops(struct dss_device *dss);
 
-bool omapdss_component_is_display(struct device_node *node);
-bool omapdss_component_is_output(struct device_node *node);
-
 bool omapdss_stack_is_ready(void);
 void omapdss_gather_components(struct device *dev);
 

+ 33 - 175
drivers/gpu/drm/omapdrm/dss/output.c

@@ -21,238 +21,96 @@
 #include <linux/slab.h>
 #include <linux/of.h>
 
+#include "dss.h"
 #include "omapdss.h"
 
-static LIST_HEAD(output_list);
-static DEFINE_MUTEX(output_lock);
-
-int omapdss_output_set_device(struct omap_dss_device *out,
-		struct omap_dss_device *dssdev)
+int omapdss_output_validate(struct omap_dss_device *out)
 {
-	int r;
-
-	mutex_lock(&output_lock);
-
-	if (out->dst) {
-		dev_err(out->dev,
-			"output already has device %s connected to it\n",
-			out->dst->name);
-		r = -EINVAL;
-		goto err;
-	}
-
-	if (out->output_type != dssdev->type) {
+	if (out->next && out->output_type != out->next->type) {
 		dev_err(out->dev, "output type and display type don't match\n");
-		r = -EINVAL;
-		goto err;
-	}
-
-	out->dst = dssdev;
-	dssdev->src = out;
-
-	mutex_unlock(&output_lock);
-
-	return 0;
-err:
-	mutex_unlock(&output_lock);
-
-	return r;
-}
-EXPORT_SYMBOL(omapdss_output_set_device);
-
-int omapdss_output_unset_device(struct omap_dss_device *out)
-{
-	int r;
-
-	mutex_lock(&output_lock);
-
-	if (!out->dst) {
-		dev_err(out->dev,
-			"output doesn't have a device connected to it\n");
-		r = -EINVAL;
-		goto err;
+		return -EINVAL;
 	}
 
-	if (out->dst->state != OMAP_DSS_DISPLAY_DISABLED) {
-		dev_err(out->dev,
-			"device %s is not disabled, cannot unset device\n",
-			out->dst->name);
-		r = -EINVAL;
-		goto err;
-	}
-
-	out->dst->src = NULL;
-	out->dst = NULL;
-
-	mutex_unlock(&output_lock);
-
-	return 0;
-err:
-	mutex_unlock(&output_lock);
-
-	return r;
-}
-EXPORT_SYMBOL(omapdss_output_unset_device);
-
-int omapdss_register_output(struct omap_dss_device *out)
-{
-	list_add_tail(&out->list, &output_list);
 	return 0;
 }
-EXPORT_SYMBOL(omapdss_register_output);
-
-void omapdss_unregister_output(struct omap_dss_device *out)
-{
-	list_del(&out->list);
-}
-EXPORT_SYMBOL(omapdss_unregister_output);
-
-bool omapdss_component_is_output(struct device_node *node)
-{
-	struct omap_dss_device *out;
-
-	list_for_each_entry(out, &output_list, list) {
-		if (out->dev->of_node == node)
-			return true;
-	}
+EXPORT_SYMBOL(omapdss_output_validate);
 
-	return false;
-}
-EXPORT_SYMBOL(omapdss_component_is_output);
-
-struct omap_dss_device *omap_dss_get_output(enum omap_dss_output_id id)
-{
-	struct omap_dss_device *out;
-
-	list_for_each_entry(out, &output_list, list) {
-		if (out->id == id)
-			return out;
-	}
-
-	return NULL;
-}
-EXPORT_SYMBOL(omap_dss_get_output);
-
-struct omap_dss_device *omap_dss_find_output_by_port_node(struct device_node *port)
-{
-	struct device_node *src_node;
-	struct omap_dss_device *out;
-	u32 reg;
-
-	src_node = dss_of_port_get_parent_device(port);
-	if (!src_node)
-		return NULL;
-
-	reg = dss_of_port_get_port_number(port);
-
-	list_for_each_entry(out, &output_list, list) {
-		if (out->dev->of_node == src_node && out->port_num == reg) {
-			of_node_put(src_node);
-			return omap_dss_get_device(out);
-		}
-	}
-
-	of_node_put(src_node);
-
-	return NULL;
-}
-
-struct omap_dss_device *omapdss_find_output_from_display(struct omap_dss_device *dssdev)
-{
-	while (dssdev->src)
-		dssdev = dssdev->src;
-
-	if (dssdev->id != 0)
-		return omap_dss_get_device(dssdev);
-
-	return NULL;
-}
-EXPORT_SYMBOL(omapdss_find_output_from_display);
-
-static const struct dss_mgr_ops *dss_mgr_ops;
-static struct omap_drm_private *dss_mgr_ops_priv;
-
-int dss_install_mgr_ops(const struct dss_mgr_ops *mgr_ops,
+int dss_install_mgr_ops(struct dss_device *dss,
+			const struct dss_mgr_ops *mgr_ops,
 			struct omap_drm_private *priv)
 {
-	if (dss_mgr_ops)
+	if (dss->mgr_ops)
 		return -EBUSY;
 
-	dss_mgr_ops = mgr_ops;
-	dss_mgr_ops_priv = priv;
+	dss->mgr_ops = mgr_ops;
+	dss->mgr_ops_priv = priv;
 
 	return 0;
 }
 EXPORT_SYMBOL(dss_install_mgr_ops);
 
-void dss_uninstall_mgr_ops(void)
+void dss_uninstall_mgr_ops(struct dss_device *dss)
 {
-	dss_mgr_ops = NULL;
-	dss_mgr_ops_priv = NULL;
+	dss->mgr_ops = NULL;
+	dss->mgr_ops_priv = NULL;
 }
 EXPORT_SYMBOL(dss_uninstall_mgr_ops);
 
-int dss_mgr_connect(struct omap_dss_device *dssdev, struct omap_dss_device *dst)
-{
-	return dss_mgr_ops->connect(dss_mgr_ops_priv,
-				    dssdev->dispc_channel, dst);
-}
-EXPORT_SYMBOL(dss_mgr_connect);
-
-void dss_mgr_disconnect(struct omap_dss_device *dssdev,
-			struct omap_dss_device *dst)
-{
-	dss_mgr_ops->disconnect(dss_mgr_ops_priv, dssdev->dispc_channel, dst);
-}
-EXPORT_SYMBOL(dss_mgr_disconnect);
-
 void dss_mgr_set_timings(struct omap_dss_device *dssdev,
 			 const struct videomode *vm)
 {
-	dss_mgr_ops->set_timings(dss_mgr_ops_priv, dssdev->dispc_channel, vm);
+	dssdev->dss->mgr_ops->set_timings(dssdev->dss->mgr_ops_priv,
+					  dssdev->dispc_channel, vm);
 }
 EXPORT_SYMBOL(dss_mgr_set_timings);
 
 void dss_mgr_set_lcd_config(struct omap_dss_device *dssdev,
 		const struct dss_lcd_mgr_config *config)
 {
-	dss_mgr_ops->set_lcd_config(dss_mgr_ops_priv,
-				    dssdev->dispc_channel, config);
+	dssdev->dss->mgr_ops->set_lcd_config(dssdev->dss->mgr_ops_priv,
+					     dssdev->dispc_channel, config);
 }
 EXPORT_SYMBOL(dss_mgr_set_lcd_config);
 
 int dss_mgr_enable(struct omap_dss_device *dssdev)
 {
-	return dss_mgr_ops->enable(dss_mgr_ops_priv, dssdev->dispc_channel);
+	return dssdev->dss->mgr_ops->enable(dssdev->dss->mgr_ops_priv,
+					    dssdev->dispc_channel);
 }
 EXPORT_SYMBOL(dss_mgr_enable);
 
 void dss_mgr_disable(struct omap_dss_device *dssdev)
 {
-	dss_mgr_ops->disable(dss_mgr_ops_priv, dssdev->dispc_channel);
+	dssdev->dss->mgr_ops->disable(dssdev->dss->mgr_ops_priv,
+				      dssdev->dispc_channel);
 }
 EXPORT_SYMBOL(dss_mgr_disable);
 
 void dss_mgr_start_update(struct omap_dss_device *dssdev)
 {
-	dss_mgr_ops->start_update(dss_mgr_ops_priv, dssdev->dispc_channel);
+	dssdev->dss->mgr_ops->start_update(dssdev->dss->mgr_ops_priv,
+					   dssdev->dispc_channel);
 }
 EXPORT_SYMBOL(dss_mgr_start_update);
 
 int dss_mgr_register_framedone_handler(struct omap_dss_device *dssdev,
 		void (*handler)(void *), void *data)
 {
-	return dss_mgr_ops->register_framedone_handler(dss_mgr_ops_priv,
-						       dssdev->dispc_channel,
-						       handler, data);
+	struct dss_device *dss = dssdev->dss;
+
+	return dss->mgr_ops->register_framedone_handler(dss->mgr_ops_priv,
+							dssdev->dispc_channel,
+							handler, data);
 }
 EXPORT_SYMBOL(dss_mgr_register_framedone_handler);
 
 void dss_mgr_unregister_framedone_handler(struct omap_dss_device *dssdev,
 		void (*handler)(void *), void *data)
 {
-	dss_mgr_ops->unregister_framedone_handler(dss_mgr_ops_priv,
-						  dssdev->dispc_channel,
-						  handler, data);
+	struct dss_device *dss = dssdev->dss;
+
+	dss->mgr_ops->unregister_framedone_handler(dss->mgr_ops_priv,
+						   dssdev->dispc_channel,
+						   handler, data);
 }
 EXPORT_SYMBOL(dss_mgr_unregister_framedone_handler);

+ 63 - 86
drivers/gpu/drm/omapdrm/dss/sdi.c

@@ -132,10 +132,8 @@ static void sdi_config_lcd_manager(struct sdi_device *sdi)
 static int sdi_display_enable(struct omap_dss_device *dssdev)
 {
 	struct sdi_device *sdi = dssdev_to_sdi(dssdev);
-	struct videomode *vm = &sdi->vm;
-	unsigned long fck;
 	struct dispc_clock_info dispc_cinfo;
-	unsigned long pck;
+	unsigned long fck;
 	int r;
 
 	if (!sdi->output.dispc_channel_connected) {
@@ -151,27 +149,12 @@ static int sdi_display_enable(struct omap_dss_device *dssdev)
 	if (r)
 		goto err_get_dispc;
 
-	/* 15.5.9.1.2 */
-	vm->flags |= DISPLAY_FLAGS_PIXDATA_POSEDGE | DISPLAY_FLAGS_SYNC_POSEDGE;
-
-	r = sdi_calc_clock_div(sdi, vm->pixelclock, &fck, &dispc_cinfo);
+	r = sdi_calc_clock_div(sdi, sdi->vm.pixelclock, &fck, &dispc_cinfo);
 	if (r)
 		goto err_calc_clock_div;
 
 	sdi->mgr_config.clock_info = dispc_cinfo;
 
-	pck = fck / dispc_cinfo.lck_div / dispc_cinfo.pck_div;
-
-	if (pck != vm->pixelclock) {
-		DSSWARN("Could not find exact pixel clock. Requested %lu Hz, got %lu Hz\n",
-			vm->pixelclock, pck);
-
-		vm->pixelclock = pck;
-	}
-
-
-	dss_mgr_set_timings(&sdi->output, vm);
-
 	r = dss_set_fck_rate(sdi->dss, fck);
 	if (r)
 		goto err_set_dss_clock_div;
@@ -230,96 +213,63 @@ static void sdi_display_disable(struct omap_dss_device *dssdev)
 }
 
 static void sdi_set_timings(struct omap_dss_device *dssdev,
-			    struct videomode *vm)
+			    const struct videomode *vm)
 {
 	struct sdi_device *sdi = dssdev_to_sdi(dssdev);
 
 	sdi->vm = *vm;
 }
 
-static void sdi_get_timings(struct omap_dss_device *dssdev,
-			    struct videomode *vm)
-{
-	struct sdi_device *sdi = dssdev_to_sdi(dssdev);
-
-	*vm = sdi->vm;
-}
-
 static int sdi_check_timings(struct omap_dss_device *dssdev,
 			     struct videomode *vm)
 {
 	struct sdi_device *sdi = dssdev_to_sdi(dssdev);
-	enum omap_channel channel = dssdev->dispc_channel;
-
-	if (!dispc_mgr_timings_ok(sdi->dss->dispc, channel, vm))
-		return -EINVAL;
+	struct dispc_clock_info dispc_cinfo;
+	unsigned long fck;
+	unsigned long pck;
+	int r;
 
 	if (vm->pixelclock == 0)
 		return -EINVAL;
 
-	return 0;
-}
+	r = sdi_calc_clock_div(sdi, vm->pixelclock, &fck, &dispc_cinfo);
+	if (r)
+		return r;
 
-static int sdi_init_regulator(struct sdi_device *sdi)
-{
-	struct regulator *vdds_sdi;
+	pck = fck / dispc_cinfo.lck_div / dispc_cinfo.pck_div;
 
-	if (sdi->vdds_sdi_reg)
-		return 0;
+	if (pck != vm->pixelclock) {
+		DSSWARN("Pixel clock adjusted from %lu Hz to %lu Hz\n",
+			vm->pixelclock, pck);
 
-	vdds_sdi = devm_regulator_get(&sdi->pdev->dev, "vdds_sdi");
-	if (IS_ERR(vdds_sdi)) {
-		if (PTR_ERR(vdds_sdi) != -EPROBE_DEFER)
-			DSSERR("can't get VDDS_SDI regulator\n");
-		return PTR_ERR(vdds_sdi);
+		vm->pixelclock = pck;
 	}
 
-	sdi->vdds_sdi_reg = vdds_sdi;
-
 	return 0;
 }
 
-static int sdi_connect(struct omap_dss_device *dssdev,
-		struct omap_dss_device *dst)
+static int sdi_connect(struct omap_dss_device *src,
+		       struct omap_dss_device *dst)
 {
-	struct sdi_device *sdi = dssdev_to_sdi(dssdev);
 	int r;
 
-	r = sdi_init_regulator(sdi);
+	r = omapdss_device_connect(dst->dss, dst, dst->next);
 	if (r)
 		return r;
 
-	r = dss_mgr_connect(&sdi->output, dssdev);
-	if (r)
-		return r;
-
-	r = omapdss_output_set_device(dssdev, dst);
-	if (r) {
-		DSSERR("failed to connect output to new device: %s\n",
-				dst->name);
-		dss_mgr_disconnect(&sdi->output, dssdev);
-		return r;
-	}
-
+	dst->dispc_channel_connected = true;
 	return 0;
 }
 
-static void sdi_disconnect(struct omap_dss_device *dssdev,
-		struct omap_dss_device *dst)
+static void sdi_disconnect(struct omap_dss_device *src,
+			   struct omap_dss_device *dst)
 {
-	struct sdi_device *sdi = dssdev_to_sdi(dssdev);
+	dst->dispc_channel_connected = false;
 
-	WARN_ON(dst != dssdev->dst);
-
-	if (dst != dssdev->dst)
-		return;
-
-	omapdss_output_unset_device(dssdev);
-
-	dss_mgr_disconnect(&sdi->output, dssdev);
+	omapdss_device_disconnect(dst, dst->next);
 }
 
-static const struct omapdss_sdi_ops sdi_ops = {
+static const struct omap_dss_device_ops sdi_ops = {
 	.connect = sdi_connect,
 	.disconnect = sdi_disconnect,
 
@@ -328,12 +278,12 @@ static const struct omapdss_sdi_ops sdi_ops = {
 
 	.check_timings = sdi_check_timings,
 	.set_timings = sdi_set_timings,
-	.get_timings = sdi_get_timings,
 };
 
-static void sdi_init_output(struct sdi_device *sdi)
+static int sdi_init_output(struct sdi_device *sdi)
 {
 	struct omap_dss_device *out = &sdi->output;
+	int r;
 
 	out->dev = &sdi->pdev->dev;
 	out->id = OMAP_DSS_OUTPUT_SDI;
@@ -341,16 +291,36 @@ static void sdi_init_output(struct sdi_device *sdi)
 	out->name = "sdi.0";
 	out->dispc_channel = OMAP_DSS_CHANNEL_LCD;
 	/* We have SDI only on OMAP3, where it's on port 1 */
-	out->port_num = 1;
-	out->ops.sdi = &sdi_ops;
+	out->of_ports = BIT(1);
+	out->ops = &sdi_ops;
 	out->owner = THIS_MODULE;
+	out->bus_flags = DRM_BUS_FLAG_PIXDATA_POSEDGE	/* 15.5.9.1.2 */
+		       | DRM_BUS_FLAG_SYNC_POSEDGE;
+
+	out->next = omapdss_of_find_connected_device(out->dev->of_node, 1);
+	if (IS_ERR(out->next)) {
+		if (PTR_ERR(out->next) != -EPROBE_DEFER)
+			dev_err(out->dev, "failed to find video sink\n");
+		return PTR_ERR(out->next);
+	}
 
-	omapdss_register_output(out);
+	r = omapdss_output_validate(out);
+	if (r) {
+		omapdss_device_put(out->next);
+		out->next = NULL;
+		return r;
+	}
+
+	omapdss_device_register(out);
+
+	return 0;
 }
 
 static void sdi_uninit_output(struct sdi_device *sdi)
 {
-	omapdss_unregister_output(&sdi->output);
+	if (sdi->output.next)
+		omapdss_device_put(sdi->output.next);
+	omapdss_device_unregister(&sdi->output);
 }
 
 int sdi_init_port(struct dss_device *dss, struct platform_device *pdev,
@@ -372,25 +342,32 @@ int sdi_init_port(struct dss_device *dss, struct platform_device *pdev,
 	}
 
 	r = of_property_read_u32(ep, "datapairs", &datapairs);
+	of_node_put(ep);
 	if (r) {
 		DSSERR("failed to parse datapairs\n");
-		goto err_datapairs;
+		goto err_free;
 	}
 
 	sdi->datapairs = datapairs;
 	sdi->dss = dss;
 
-	of_node_put(ep);
-
 	sdi->pdev = pdev;
 	port->data = sdi;
 
-	sdi_init_output(sdi);
+	sdi->vdds_sdi_reg = devm_regulator_get(&pdev->dev, "vdds_sdi");
+	if (IS_ERR(sdi->vdds_sdi_reg)) {
+		r = PTR_ERR(sdi->vdds_sdi_reg);
+		if (r != -EPROBE_DEFER)
+			DSSERR("can't get VDDS_SDI regulator\n");
+		goto err_free;
+	}
+
+	r = sdi_init_output(sdi);
+	if (r)
+		goto err_free;
 
 	return 0;
 
-err_datapairs:
-	of_node_put(ep);
 err_free:
 	kfree(sdi);
 

+ 124 - 174
drivers/gpu/drm/omapdrm/dss/venc.c

@@ -452,7 +452,7 @@ static void venc_runtime_put(struct venc_device *venc)
 	WARN_ON(r < 0 && r != -ENOSYS);
 }
 
-static const struct venc_config *venc_timings_to_config(struct videomode *vm)
+static const struct venc_config *venc_timings_to_config(const struct videomode *vm)
 {
 	switch (venc_get_videomode(vm)) {
 	default:
@@ -491,8 +491,6 @@ static int venc_power_on(struct venc_device *venc)
 
 	venc_write_reg(venc, VENC_OUTPUT_CONTROL, l);
 
-	dss_mgr_set_timings(&venc->output, &venc->vm);
-
 	r = regulator_enable(venc->vdda_dac_reg);
 	if (r)
 		goto err1;
@@ -568,32 +566,30 @@ static void venc_display_disable(struct omap_dss_device *dssdev)
 	mutex_unlock(&venc->venc_lock);
 }
 
-static void venc_set_timings(struct omap_dss_device *dssdev,
+static void venc_get_timings(struct omap_dss_device *dssdev,
 			     struct videomode *vm)
 {
 	struct venc_device *venc = dssdev_to_venc(dssdev);
-	struct videomode actual_vm;
+
+	mutex_lock(&venc->venc_lock);
+	*vm = venc->vm;
+	mutex_unlock(&venc->venc_lock);
+}
+
+static void venc_set_timings(struct omap_dss_device *dssdev,
+			     const struct videomode *vm)
+{
+	struct venc_device *venc = dssdev_to_venc(dssdev);
 
 	DSSDBG("venc_set_timings\n");
 
 	mutex_lock(&venc->venc_lock);
 
-	switch (venc_get_videomode(vm)) {
-	default:
-		WARN_ON_ONCE(1);
-	case VENC_MODE_PAL:
-		actual_vm = omap_dss_pal_vm;
-		break;
-	case VENC_MODE_NTSC:
-		actual_vm = omap_dss_ntsc_vm;
-		break;
-	}
-
 	/* Reset WSS data when the TV standard changes. */
-	if (memcmp(&venc->vm, &actual_vm, sizeof(actual_vm)))
+	if (memcmp(&venc->vm, vm, sizeof(*vm)))
 		venc->wss_data = 0;
 
-	venc->vm = actual_vm;
+	venc->vm = *vm;
 
 	dispc_set_tv_pclk(venc->dss->dispc, 13500000);
 
@@ -607,80 +603,16 @@ static int venc_check_timings(struct omap_dss_device *dssdev,
 
 	switch (venc_get_videomode(vm)) {
 	case VENC_MODE_PAL:
-	case VENC_MODE_NTSC:
+		*vm = omap_dss_pal_vm;
 		return 0;
-	default:
-		return -EINVAL;
-	}
-}
-
-static void venc_get_timings(struct omap_dss_device *dssdev,
-			     struct videomode *vm)
-{
-	struct venc_device *venc = dssdev_to_venc(dssdev);
-
-	mutex_lock(&venc->venc_lock);
-
-	*vm = venc->vm;
-
-	mutex_unlock(&venc->venc_lock);
-}
-
-static u32 venc_get_wss(struct omap_dss_device *dssdev)
-{
-	struct venc_device *venc = dssdev_to_venc(dssdev);
-
-	/* Invert due to VENC_L21_WC_CTL:INV=1 */
-	return (venc->wss_data >> 8) ^ 0xfffff;
-}
-
-static int venc_set_wss(struct omap_dss_device *dssdev, u32 wss)
-{
-	struct venc_device *venc = dssdev_to_venc(dssdev);
-	const struct venc_config *config;
-	int r;
-
-	DSSDBG("venc_set_wss\n");
 
-	mutex_lock(&venc->venc_lock);
-
-	config = venc_timings_to_config(&venc->vm);
-
-	/* Invert due to VENC_L21_WC_CTL:INV=1 */
-	venc->wss_data = (wss ^ 0xfffff) << 8;
-
-	r = venc_runtime_get(venc);
-	if (r)
-		goto err;
-
-	venc_write_reg(venc, VENC_BSTAMP_WSS_DATA, config->bstamp_wss_data |
-		       venc->wss_data);
-
-	venc_runtime_put(venc);
-
-err:
-	mutex_unlock(&venc->venc_lock);
-
-	return r;
-}
-
-static int venc_init_regulator(struct venc_device *venc)
-{
-	struct regulator *vdda_dac;
-
-	if (venc->vdda_dac_reg != NULL)
+	case VENC_MODE_NTSC:
+		*vm = omap_dss_ntsc_vm;
 		return 0;
 
-	vdda_dac = devm_regulator_get(&venc->pdev->dev, "vdda");
-	if (IS_ERR(vdda_dac)) {
-		if (PTR_ERR(vdda_dac) != -EPROBE_DEFER)
-			DSSERR("can't get VDDA_DAC regulator\n");
-		return PTR_ERR(vdda_dac);
+	default:
+		return -EINVAL;
 	}
-
-	venc->vdda_dac_reg = vdda_dac;
-
-	return 0;
 }
 
 static int venc_dump_regs(struct seq_file *s, void *p)
@@ -760,47 +692,28 @@ static int venc_get_clocks(struct venc_device *venc)
 	return 0;
 }
 
-static int venc_connect(struct omap_dss_device *dssdev,
-		struct omap_dss_device *dst)
+static int venc_connect(struct omap_dss_device *src,
+			struct omap_dss_device *dst)
 {
-	struct venc_device *venc = dssdev_to_venc(dssdev);
 	int r;
 
-	r = venc_init_regulator(venc);
-	if (r)
-		return r;
-
-	r = dss_mgr_connect(&venc->output, dssdev);
+	r = omapdss_device_connect(dst->dss, dst, dst->next);
 	if (r)
 		return r;
 
-	r = omapdss_output_set_device(dssdev, dst);
-	if (r) {
-		DSSERR("failed to connect output to new device: %s\n",
-				dst->name);
-		dss_mgr_disconnect(&venc->output, dssdev);
-		return r;
-	}
-
+	dst->dispc_channel_connected = true;
 	return 0;
 }
 
-static void venc_disconnect(struct omap_dss_device *dssdev,
-		struct omap_dss_device *dst)
+static void venc_disconnect(struct omap_dss_device *src,
+			    struct omap_dss_device *dst)
 {
-	struct venc_device *venc = dssdev_to_venc(dssdev);
-
-	WARN_ON(dst != dssdev->dst);
-
-	if (dst != dssdev->dst)
-		return;
+	dst->dispc_channel_connected = false;
 
-	omapdss_output_unset_device(dssdev);
-
-	dss_mgr_disconnect(&venc->output, dssdev);
+	omapdss_device_disconnect(dst, dst->next);
 }
 
-static const struct omapdss_atv_ops venc_ops = {
+static const struct omap_dss_device_ops venc_ops = {
 	.connect = venc_connect,
 	.disconnect = venc_disconnect,
 
@@ -808,31 +721,92 @@ static const struct omapdss_atv_ops venc_ops = {
 	.disable = venc_display_disable,
 
 	.check_timings = venc_check_timings,
-	.set_timings = venc_set_timings,
 	.get_timings = venc_get_timings,
+	.set_timings = venc_set_timings,
+};
+
+/* -----------------------------------------------------------------------------
+ * Component Bind & Unbind
+ */
 
-	.set_wss = venc_set_wss,
-	.get_wss = venc_get_wss,
+static int venc_bind(struct device *dev, struct device *master, void *data)
+{
+	struct dss_device *dss = dss_get_device(master);
+	struct venc_device *venc = dev_get_drvdata(dev);
+	u8 rev_id;
+	int r;
+
+	venc->dss = dss;
+
+	r = venc_runtime_get(venc);
+	if (r)
+		return r;
+
+	rev_id = (u8)(venc_read_reg(venc, VENC_REV_ID) & 0xff);
+	dev_dbg(dev, "OMAP VENC rev %d\n", rev_id);
+
+	venc_runtime_put(venc);
+
+	venc->debugfs = dss_debugfs_create_file(dss, "venc", venc_dump_regs,
+						venc);
+
+	return 0;
+}
+
+static void venc_unbind(struct device *dev, struct device *master, void *data)
+{
+	struct venc_device *venc = dev_get_drvdata(dev);
+
+	dss_debugfs_remove_file(venc->debugfs);
+}
+
+static const struct component_ops venc_component_ops = {
+	.bind	= venc_bind,
+	.unbind	= venc_unbind,
 };
 
-static void venc_init_output(struct venc_device *venc)
+/* -----------------------------------------------------------------------------
+ * Probe & Remove, Suspend & Resume
+ */
+
+static int venc_init_output(struct venc_device *venc)
 {
 	struct omap_dss_device *out = &venc->output;
+	int r;
 
 	out->dev = &venc->pdev->dev;
 	out->id = OMAP_DSS_OUTPUT_VENC;
 	out->output_type = OMAP_DISPLAY_TYPE_VENC;
 	out->name = "venc.0";
 	out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT;
-	out->ops.atv = &venc_ops;
+	out->ops = &venc_ops;
 	out->owner = THIS_MODULE;
+	out->of_ports = BIT(0);
+
+	out->next = omapdss_of_find_connected_device(out->dev->of_node, 0);
+	if (IS_ERR(out->next)) {
+		if (PTR_ERR(out->next) != -EPROBE_DEFER)
+			dev_err(out->dev, "failed to find video sink\n");
+		return PTR_ERR(out->next);
+	}
 
-	omapdss_register_output(out);
+	r = omapdss_output_validate(out);
+	if (r) {
+		omapdss_device_put(out->next);
+		out->next = NULL;
+		return r;
+	}
+
+	omapdss_device_register(out);
+
+	return 0;
 }
 
 static void venc_uninit_output(struct venc_device *venc)
 {
-	omapdss_unregister_output(&venc->output);
+	if (venc->output.next)
+		omapdss_device_put(venc->output.next);
+	omapdss_device_unregister(&venc->output);
 }
 
 static int venc_probe_of(struct venc_device *venc)
@@ -878,19 +852,15 @@ err:
 	return r;
 }
 
-/* VENC HW IP initialisation */
 static const struct soc_device_attribute venc_soc_devices[] = {
 	{ .machine = "OMAP3[45]*" },
 	{ .machine = "AM35*" },
 	{ /* sentinel */ }
 };
 
-static int venc_bind(struct device *dev, struct device *master, void *data)
+static int venc_probe(struct platform_device *pdev)
 {
-	struct platform_device *pdev = to_platform_device(dev);
-	struct dss_device *dss = dss_get_device(master);
 	struct venc_device *venc;
-	u8 rev_id;
 	struct resource *venc_mem;
 	int r;
 
@@ -899,8 +869,8 @@ static int venc_bind(struct device *dev, struct device *master, void *data)
 		return -ENOMEM;
 
 	venc->pdev = pdev;
-	venc->dss = dss;
-	dev_set_drvdata(dev, venc);
+
+	platform_set_drvdata(pdev, venc);
 
 	/* The OMAP34xx, OMAP35xx and AM35xx VENC require the TV DAC clock. */
 	if (soc_device_match(venc_soc_devices))
@@ -909,6 +879,7 @@ static int venc_bind(struct device *dev, struct device *master, void *data)
 	mutex_init(&venc->venc_lock);
 
 	venc->wss_data = 0;
+	venc->vm = omap_dss_pal_vm;
 
 	venc_mem = platform_get_resource(venc->pdev, IORESOURCE_MEM, 0);
 	venc->base = devm_ioremap_resource(&pdev->dev, venc_mem);
@@ -917,68 +888,54 @@ static int venc_bind(struct device *dev, struct device *master, void *data)
 		goto err_free;
 	}
 
+	venc->vdda_dac_reg = devm_regulator_get(&pdev->dev, "vdda");
+	if (IS_ERR(venc->vdda_dac_reg)) {
+		r = PTR_ERR(venc->vdda_dac_reg);
+		if (r != -EPROBE_DEFER)
+			DSSERR("can't get VDDA_DAC regulator\n");
+		goto err_free;
+	}
+
 	r = venc_get_clocks(venc);
 	if (r)
 		goto err_free;
 
-	pm_runtime_enable(&pdev->dev);
-
-	r = venc_runtime_get(venc);
+	r = venc_probe_of(venc);
 	if (r)
-		goto err_runtime_get;
-
-	rev_id = (u8)(venc_read_reg(venc, VENC_REV_ID) & 0xff);
-	dev_dbg(&pdev->dev, "OMAP VENC rev %d\n", rev_id);
-
-	venc_runtime_put(venc);
+		goto err_free;
 
-	r = venc_probe_of(venc);
-	if (r) {
-		DSSERR("Invalid DT data\n");
-		goto err_probe_of;
-	}
+	pm_runtime_enable(&pdev->dev);
 
-	venc->debugfs = dss_debugfs_create_file(dss, "venc", venc_dump_regs,
-						venc);
+	r = venc_init_output(venc);
+	if (r)
+		goto err_pm_disable;
 
-	venc_init_output(venc);
+	r = component_add(&pdev->dev, &venc_component_ops);
+	if (r)
+		goto err_uninit_output;
 
 	return 0;
 
-err_probe_of:
-err_runtime_get:
+err_uninit_output:
+	venc_uninit_output(venc);
+err_pm_disable:
 	pm_runtime_disable(&pdev->dev);
 err_free:
 	kfree(venc);
 	return r;
 }
 
-static void venc_unbind(struct device *dev, struct device *master, void *data)
+static int venc_remove(struct platform_device *pdev)
 {
-	struct venc_device *venc = dev_get_drvdata(dev);
+	struct venc_device *venc = platform_get_drvdata(pdev);
 
-	dss_debugfs_remove_file(venc->debugfs);
+	component_del(&pdev->dev, &venc_component_ops);
 
 	venc_uninit_output(venc);
 
-	pm_runtime_disable(dev);
+	pm_runtime_disable(&pdev->dev);
 
 	kfree(venc);
-}
-
-static const struct component_ops venc_component_ops = {
-	.bind	= venc_bind,
-	.unbind	= venc_unbind,
-};
-
-static int venc_probe(struct platform_device *pdev)
-{
-	return component_add(&pdev->dev, &venc_component_ops);
-}
-
-static int venc_remove(struct platform_device *pdev)
-{
-	component_del(&pdev->dev, &venc_component_ops);
 	return 0;
 }
 
@@ -989,19 +946,12 @@ static int venc_runtime_suspend(struct device *dev)
 	if (venc->tv_dac_clk)
 		clk_disable_unprepare(venc->tv_dac_clk);
 
-	dispc_runtime_put(venc->dss->dispc);
-
 	return 0;
 }
 
 static int venc_runtime_resume(struct device *dev)
 {
 	struct venc_device *venc = dev_get_drvdata(dev);
-	int r;
-
-	r = dispc_runtime_get(venc->dss->dispc);
-	if (r < 0)
-		return r;
 
 	if (venc->tv_dac_clk)
 		clk_prepare_enable(venc->tv_dac_clk);

+ 241 - 133
drivers/gpu/drm/omapdrm/omap_connector.c

@@ -29,10 +29,28 @@
 
 struct omap_connector {
 	struct drm_connector base;
-	struct omap_dss_device *dssdev;
+	struct omap_dss_device *output;
+	struct omap_dss_device *display;
+	struct omap_dss_device *hpd;
 	bool hdmi_mode;
 };
 
+static void omap_connector_hpd_notify(struct drm_connector *connector,
+				      struct omap_dss_device *src,
+				      enum drm_connector_status status)
+{
+	if (status == connector_status_disconnected) {
+		/*
+		 * If the source is an HDMI encoder, notify it of disconnection.
+		 * This is required to let the HDMI encoder reset any internal
+		 * state related to connection status, such as the CEC address.
+		 */
+		if (src && src->type == OMAP_DISPLAY_TYPE_HDMI &&
+		    src->ops->hdmi.lost_hotplug)
+			src->ops->hdmi.lost_hotplug(src);
+	}
+}
+
 static void omap_connector_hpd_cb(void *cb_data,
 				  enum drm_connector_status status)
 {
@@ -46,8 +64,31 @@ static void omap_connector_hpd_cb(void *cb_data,
 	connector->status = status;
 	mutex_unlock(&dev->mode_config.mutex);
 
-	if (old_status != status)
-		drm_kms_helper_hotplug_event(dev);
+	if (old_status == status)
+		return;
+
+	omap_connector_hpd_notify(connector, omap_connector->hpd, status);
+
+	drm_kms_helper_hotplug_event(dev);
+}
+
+void omap_connector_enable_hpd(struct drm_connector *connector)
+{
+	struct omap_connector *omap_connector = to_omap_connector(connector);
+	struct omap_dss_device *hpd = omap_connector->hpd;
+
+	if (hpd)
+		hpd->ops->register_hpd_cb(hpd, omap_connector_hpd_cb,
+					  omap_connector);
+}
+
+void omap_connector_disable_hpd(struct drm_connector *connector)
+{
+	struct omap_connector *omap_connector = to_omap_connector(connector);
+	struct omap_dss_device *hpd = omap_connector->hpd;
+
+	if (hpd)
+		hpd->ops->unregister_hpd_cb(hpd);
 }
 
 bool omap_connector_get_hdmi_mode(struct drm_connector *connector)
@@ -57,120 +98,180 @@ bool omap_connector_get_hdmi_mode(struct drm_connector *connector)
 	return omap_connector->hdmi_mode;
 }
 
+static struct omap_dss_device *
+omap_connector_find_device(struct drm_connector *connector,
+			   enum omap_dss_device_ops_flag op)
+{
+	struct omap_connector *omap_connector = to_omap_connector(connector);
+	struct omap_dss_device *dssdev;
+
+	for (dssdev = omap_connector->display; dssdev; dssdev = dssdev->src) {
+		if (dssdev->ops_flags & op)
+			return dssdev;
+	}
+
+	return NULL;
+}
+
 static enum drm_connector_status omap_connector_detect(
 		struct drm_connector *connector, bool force)
 {
 	struct omap_connector *omap_connector = to_omap_connector(connector);
-	struct omap_dss_device *dssdev = omap_connector->dssdev;
-	struct omap_dss_driver *dssdrv = dssdev->driver;
-	enum drm_connector_status ret;
-
-	if (dssdrv->detect) {
-		if (dssdrv->detect(dssdev))
-			ret = connector_status_connected;
-		else
-			ret = connector_status_disconnected;
-	} else if (dssdev->type == OMAP_DISPLAY_TYPE_DPI ||
-			dssdev->type == OMAP_DISPLAY_TYPE_DBI ||
-			dssdev->type == OMAP_DISPLAY_TYPE_SDI ||
-			dssdev->type == OMAP_DISPLAY_TYPE_DSI) {
-		ret = connector_status_connected;
+	struct omap_dss_device *dssdev;
+	enum drm_connector_status status;
+
+	dssdev = omap_connector_find_device(connector,
+					    OMAP_DSS_DEVICE_OP_DETECT);
+
+	if (dssdev) {
+		status = dssdev->ops->detect(dssdev)
+		       ? connector_status_connected
+		       : connector_status_disconnected;
+
+		omap_connector_hpd_notify(connector, dssdev->src, status);
 	} else {
-		ret = connector_status_unknown;
+		switch (omap_connector->display->type) {
+		case OMAP_DISPLAY_TYPE_DPI:
+		case OMAP_DISPLAY_TYPE_DBI:
+		case OMAP_DISPLAY_TYPE_SDI:
+		case OMAP_DISPLAY_TYPE_DSI:
+			status = connector_status_connected;
+			break;
+		default:
+			status = connector_status_unknown;
+			break;
+		}
 	}
 
-	VERB("%s: %d (force=%d)", omap_connector->dssdev->name, ret, force);
+	VERB("%s: %d (force=%d)", omap_connector->display->name, status, force);
 
-	return ret;
+	return status;
 }
 
 static void omap_connector_destroy(struct drm_connector *connector)
 {
 	struct omap_connector *omap_connector = to_omap_connector(connector);
-	struct omap_dss_device *dssdev = omap_connector->dssdev;
 
-	DBG("%s", omap_connector->dssdev->name);
-	if (connector->polled == DRM_CONNECTOR_POLL_HPD &&
-	    dssdev->driver->unregister_hpd_cb) {
-		dssdev->driver->unregister_hpd_cb(dssdev);
+	DBG("%s", omap_connector->display->name);
+
+	if (omap_connector->hpd) {
+		struct omap_dss_device *hpd = omap_connector->hpd;
+
+		hpd->ops->unregister_hpd_cb(hpd);
+		omapdss_device_put(hpd);
+		omap_connector->hpd = NULL;
 	}
+
 	drm_connector_unregister(connector);
 	drm_connector_cleanup(connector);
-	kfree(omap_connector);
 
-	omap_dss_put_device(dssdev);
+	omapdss_device_put(omap_connector->output);
+	omapdss_device_put(omap_connector->display);
+
+	kfree(omap_connector);
 }
 
 #define MAX_EDID  512
 
-static int omap_connector_get_modes(struct drm_connector *connector)
+static int omap_connector_get_modes_edid(struct drm_connector *connector,
+					 struct omap_dss_device *dssdev)
 {
 	struct omap_connector *omap_connector = to_omap_connector(connector);
-	struct omap_dss_device *dssdev = omap_connector->dssdev;
-	struct omap_dss_driver *dssdrv = dssdev->driver;
-	struct drm_device *dev = connector->dev;
-	int n = 0;
+	enum drm_connector_status status;
+	void *edid;
+	int n;
 
-	DBG("%s", omap_connector->dssdev->name);
+	status = omap_connector_detect(connector, false);
+	if (status != connector_status_connected)
+		goto no_edid;
 
-	/* if display exposes EDID, then we parse that in the normal way to
-	 * build table of supported modes.. otherwise (ie. fixed resolution
-	 * LCD panels) we just return a single mode corresponding to the
-	 * currently configured timings:
-	 */
-	if (dssdrv->read_edid) {
-		void *edid = kzalloc(MAX_EDID, GFP_KERNEL);
-
-		if (!edid)
-			return 0;
-
-		if ((dssdrv->read_edid(dssdev, edid, MAX_EDID) > 0) &&
-				drm_edid_is_valid(edid)) {
-			drm_connector_update_edid_property(
-					connector, edid);
-			n = drm_add_edid_modes(connector, edid);
-
-			omap_connector->hdmi_mode =
-				drm_detect_hdmi_monitor(edid);
-		} else {
-			drm_connector_update_edid_property(
-					connector, NULL);
-		}
+	edid = kzalloc(MAX_EDID, GFP_KERNEL);
+	if (!edid)
+		goto no_edid;
 
+	if (dssdev->ops->read_edid(dssdev, edid, MAX_EDID) <= 0 ||
+	    !drm_edid_is_valid(edid)) {
 		kfree(edid);
-	} else {
-		struct drm_display_mode *mode = drm_mode_create(dev);
-		struct videomode vm = {0};
+		goto no_edid;
+	}
+
+	drm_connector_update_edid_property(connector, edid);
+	n = drm_add_edid_modes(connector, edid);
 
-		if (!mode)
-			return 0;
+	omap_connector->hdmi_mode = drm_detect_hdmi_monitor(edid);
 
-		dssdrv->get_timings(dssdev, &vm);
+	kfree(edid);
+	return n;
+
+no_edid:
+	drm_connector_update_edid_property(connector, NULL);
+	return 0;
+}
+
+static int omap_connector_get_modes(struct drm_connector *connector)
+{
+	struct omap_connector *omap_connector = to_omap_connector(connector);
+	struct omap_dss_device *dssdev;
+	struct drm_display_mode *mode;
+	struct videomode vm = {0};
 
-		drm_display_mode_from_videomode(&vm, mode);
+	DBG("%s", omap_connector->display->name);
 
-		mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
-		drm_mode_set_name(mode);
-		drm_mode_probed_add(connector, mode);
+	/*
+	 * If display exposes EDID, then we parse that in the normal way to
+	 * build table of supported modes.
+	 */
+	dssdev = omap_connector_find_device(connector,
+					    OMAP_DSS_DEVICE_OP_EDID);
+	if (dssdev)
+		return omap_connector_get_modes_edid(connector, dssdev);
 
-		if (dssdrv->get_size) {
-			dssdrv->get_size(dssdev,
+	/*
+	 * Otherwise we have either a fixed resolution panel or an output that
+	 * doesn't support modes discovery (e.g. DVI or VGA with the DDC bus
+	 * unconnected, or analog TV). Start by querying the size.
+	 */
+	dssdev = omap_connector->display;
+	if (dssdev->driver && dssdev->driver->get_size)
+		dssdev->driver->get_size(dssdev,
 					 &connector->display_info.width_mm,
 					 &connector->display_info.height_mm);
-		}
 
-		n = 1;
+	/*
+	 * Iterate over the pipeline to find the first device that can provide
+	 * timing information. If we can't find any, we just let the KMS core
+	 * add the default modes.
+	 */
+	for (dssdev = omap_connector->display; dssdev; dssdev = dssdev->src) {
+		if (dssdev->ops->get_timings)
+			break;
 	}
+	if (!dssdev)
+		return 0;
 
-	return n;
+	/* Add a single mode corresponding to the fixed panel timings. */
+	mode = drm_mode_create(connector->dev);
+	if (!mode)
+		return 0;
+
+	dssdev->ops->get_timings(dssdev, &vm);
+
+	drm_display_mode_from_videomode(&vm, mode);
+
+	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
+	drm_mode_set_name(mode);
+	drm_mode_probed_add(connector, mode);
+
+	return 1;
 }
 
 static int omap_connector_mode_valid(struct drm_connector *connector,
 				 struct drm_display_mode *mode)
 {
 	struct omap_connector *omap_connector = to_omap_connector(connector);
-	struct omap_dss_device *dssdev = omap_connector->dssdev;
-	struct omap_dss_driver *dssdrv = dssdev->driver;
+	enum omap_channel channel = omap_connector->output->dispc_channel;
+	struct omap_drm_private *priv = connector->dev->dev_private;
+	struct omap_dss_device *dssdev;
 	struct videomode vm = {0};
 	struct drm_device *dev = connector->dev;
 	struct drm_display_mode *new_mode;
@@ -179,44 +280,31 @@ static int omap_connector_mode_valid(struct drm_connector *connector,
 	drm_display_mode_to_videomode(mode, &vm);
 	mode->vrefresh = drm_mode_vrefresh(mode);
 
-	/*
-	 * if the panel driver doesn't have a check_timings, it's most likely
-	 * a fixed resolution panel, check if the timings match with the
-	 * panel's timings
-	 */
-	if (dssdrv->check_timings) {
-		r = dssdrv->check_timings(dssdev, &vm);
-	} else {
-		struct videomode t = {0};
-
-		dssdrv->get_timings(dssdev, &t);
+	r = priv->dispc_ops->mgr_check_timings(priv->dispc, channel, &vm);
+	if (r)
+		goto done;
 
-		/*
-		 * Ignore the flags, as we don't get them from
-		 * drm_display_mode_to_videomode.
-		 */
-		t.flags = 0;
+	for (dssdev = omap_connector->output; dssdev; dssdev = dssdev->next) {
+		if (!dssdev->ops->check_timings)
+			continue;
 
-		if (memcmp(&vm, &t, sizeof(vm)))
-			r = -EINVAL;
-		else
-			r = 0;
+		r = dssdev->ops->check_timings(dssdev, &vm);
+		if (r)
+			goto done;
 	}
 
-	if (!r) {
-		/* check if vrefresh is still valid */
-		new_mode = drm_mode_duplicate(dev, mode);
-
-		if (!new_mode)
-			return MODE_BAD;
+	/* check if vrefresh is still valid */
+	new_mode = drm_mode_duplicate(dev, mode);
+	if (!new_mode)
+		return MODE_BAD;
 
-		new_mode->clock = vm.pixelclock / 1000;
-		new_mode->vrefresh = 0;
-		if (mode->vrefresh == drm_mode_vrefresh(new_mode))
-			ret = MODE_OK;
-		drm_mode_destroy(dev, new_mode);
-	}
+	new_mode->clock = vm.pixelclock / 1000;
+	new_mode->vrefresh = 0;
+	if (mode->vrefresh == drm_mode_vrefresh(new_mode))
+		ret = MODE_OK;
+	drm_mode_destroy(dev, new_mode);
 
+done:
 	DBG("connector: mode %s: "
 			"%d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
 			(ret == MODE_OK) ? "valid" : "invalid",
@@ -243,52 +331,72 @@ static const struct drm_connector_helper_funcs omap_connector_helper_funcs = {
 	.mode_valid = omap_connector_mode_valid,
 };
 
+static int omap_connector_get_type(struct omap_dss_device *display)
+{
+	switch (display->type) {
+	case OMAP_DISPLAY_TYPE_HDMI:
+		return DRM_MODE_CONNECTOR_HDMIA;
+	case OMAP_DISPLAY_TYPE_DVI:
+		return DRM_MODE_CONNECTOR_DVID;
+	case OMAP_DISPLAY_TYPE_DSI:
+		return DRM_MODE_CONNECTOR_DSI;
+	case OMAP_DISPLAY_TYPE_DPI:
+	case OMAP_DISPLAY_TYPE_DBI:
+		return DRM_MODE_CONNECTOR_DPI;
+	case OMAP_DISPLAY_TYPE_VENC:
+		/* TODO: This could also be composite */
+		return DRM_MODE_CONNECTOR_SVIDEO;
+	case OMAP_DISPLAY_TYPE_SDI:
+		return DRM_MODE_CONNECTOR_LVDS;
+	default:
+		return DRM_MODE_CONNECTOR_Unknown;
+	}
+}
+
 /* initialize connector */
 struct drm_connector *omap_connector_init(struct drm_device *dev,
-		int connector_type, struct omap_dss_device *dssdev,
-		struct drm_encoder *encoder)
+					  struct omap_dss_device *output,
+					  struct omap_dss_device *display,
+					  struct drm_encoder *encoder)
 {
 	struct drm_connector *connector = NULL;
 	struct omap_connector *omap_connector;
-	bool hpd_supported = false;
-
-	DBG("%s", dssdev->name);
+	struct omap_dss_device *dssdev;
 
-	omap_dss_get_device(dssdev);
+	DBG("%s", display->name);
 
 	omap_connector = kzalloc(sizeof(*omap_connector), GFP_KERNEL);
 	if (!omap_connector)
 		goto fail;
 
-	omap_connector->dssdev = dssdev;
+	omap_connector->output = omapdss_device_get(output);
+	omap_connector->display = omapdss_device_get(display);
 
 	connector = &omap_connector->base;
+	connector->interlace_allowed = 1;
+	connector->doublescan_allowed = 0;
 
 	drm_connector_init(dev, connector, &omap_connector_funcs,
-				connector_type);
+			   omap_connector_get_type(display));
 	drm_connector_helper_add(connector, &omap_connector_helper_funcs);
 
-	if (dssdev->driver->register_hpd_cb) {
-		int ret = dssdev->driver->register_hpd_cb(dssdev,
-							  omap_connector_hpd_cb,
-							  omap_connector);
-		if (!ret)
-			hpd_supported = true;
-		else if (ret != -ENOTSUPP)
-			DBG("%s: Failed to register HPD callback (%d).",
-			    dssdev->name, ret);
-	}
-
-	if (hpd_supported)
+	/*
+	 * Initialize connector status handling. First try to find a device that
+	 * supports hot-plug reporting. If it fails, fall back to a device that
+	 * support polling. If that fails too, we don't support hot-plug
+	 * detection at all.
+	 */
+	dssdev = omap_connector_find_device(connector, OMAP_DSS_DEVICE_OP_HPD);
+	if (dssdev) {
+		omap_connector->hpd = omapdss_device_get(dssdev);
 		connector->polled = DRM_CONNECTOR_POLL_HPD;
-	else if (dssdev->driver->detect)
-		connector->polled = DRM_CONNECTOR_POLL_CONNECT |
-				    DRM_CONNECTOR_POLL_DISCONNECT;
-	else
-		connector->polled = 0;
-
-	connector->interlace_allowed = 1;
-	connector->doublescan_allowed = 0;
+	} else {
+		dssdev = omap_connector_find_device(connector,
+						    OMAP_DSS_DEVICE_OP_DETECT);
+		if (dssdev)
+			connector->polled = DRM_CONNECTOR_POLL_CONNECT |
+					    DRM_CONNECTOR_POLL_DISCONNECT;
+	}
 
 	return connector;
 

+ 5 - 2
drivers/gpu/drm/omapdrm/omap_connector.h

@@ -28,10 +28,13 @@ struct drm_encoder;
 struct omap_dss_device;
 
 struct drm_connector *omap_connector_init(struct drm_device *dev,
-		int connector_type, struct omap_dss_device *dssdev,
-		struct drm_encoder *encoder);
+					  struct omap_dss_device *output,
+					  struct omap_dss_device *display,
+					  struct drm_encoder *encoder);
 struct drm_encoder *omap_connector_attached_encoder(
 		struct drm_connector *connector);
 bool omap_connector_get_hdmi_mode(struct drm_connector *connector);
+void omap_connector_enable_hpd(struct drm_connector *connector);
+void omap_connector_disable_hpd(struct drm_connector *connector);
 
 #endif /* __OMAPDRM_CONNECTOR_H__ */

+ 25 - 92
drivers/gpu/drm/omapdrm/omap_crtc.c

@@ -41,6 +41,7 @@ struct omap_crtc {
 	struct drm_crtc base;
 
 	const char *name;
+	struct omap_drm_pipeline *pipe;
 	enum omap_channel channel;
 
 	struct videomode vm;
@@ -108,38 +109,7 @@ int omap_crtc_wait_pending(struct drm_crtc *crtc)
  * job of sequencing the setup of the video pipe in the proper order
  */
 
-/* ovl-mgr-id -> crtc */
-static struct omap_crtc *omap_crtcs[8];
-static struct omap_dss_device *omap_crtc_output[8];
-
 /* we can probably ignore these until we support command-mode panels: */
-static int omap_crtc_dss_connect(struct omap_drm_private *priv,
-		enum omap_channel channel,
-		struct omap_dss_device *dst)
-{
-	const struct dispc_ops *dispc_ops = priv->dispc_ops;
-	struct dispc_device *dispc = priv->dispc;
-
-	if (omap_crtc_output[channel])
-		return -EINVAL;
-
-	if (!(dispc_ops->mgr_get_supported_outputs(dispc, channel) & dst->id))
-		return -EINVAL;
-
-	omap_crtc_output[channel] = dst;
-	dst->dispc_channel_connected = true;
-
-	return 0;
-}
-
-static void omap_crtc_dss_disconnect(struct omap_drm_private *priv,
-		enum omap_channel channel,
-		struct omap_dss_device *dst)
-{
-	omap_crtc_output[channel] = NULL;
-	dst->dispc_channel_connected = false;
-}
-
 static void omap_crtc_dss_start_update(struct omap_drm_private *priv,
 				       enum omap_channel channel)
 {
@@ -159,7 +129,7 @@ static void omap_crtc_set_enabled(struct drm_crtc *crtc, bool enable)
 	if (WARN_ON(omap_crtc->enabled == enable))
 		return;
 
-	if (omap_crtc_output[channel]->output_type == OMAP_DISPLAY_TYPE_HDMI) {
+	if (omap_crtc->pipe->output->output_type == OMAP_DISPLAY_TYPE_HDMI) {
 		priv->dispc_ops->mgr_enable(priv->dispc, channel, enable);
 		omap_crtc->enabled = enable;
 		return;
@@ -215,7 +185,8 @@ static void omap_crtc_set_enabled(struct drm_crtc *crtc, bool enable)
 static int omap_crtc_dss_enable(struct omap_drm_private *priv,
 				enum omap_channel channel)
 {
-	struct omap_crtc *omap_crtc = omap_crtcs[channel];
+	struct drm_crtc *crtc = priv->channels[channel]->crtc;
+	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
 
 	priv->dispc_ops->mgr_set_timings(priv->dispc, omap_crtc->channel,
 					 &omap_crtc->vm);
@@ -227,7 +198,8 @@ static int omap_crtc_dss_enable(struct omap_drm_private *priv,
 static void omap_crtc_dss_disable(struct omap_drm_private *priv,
 				  enum omap_channel channel)
 {
-	struct omap_crtc *omap_crtc = omap_crtcs[channel];
+	struct drm_crtc *crtc = priv->channels[channel]->crtc;
+	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
 
 	omap_crtc_set_enabled(&omap_crtc->base, false);
 }
@@ -236,7 +208,9 @@ static void omap_crtc_dss_set_timings(struct omap_drm_private *priv,
 		enum omap_channel channel,
 		const struct videomode *vm)
 {
-	struct omap_crtc *omap_crtc = omap_crtcs[channel];
+	struct drm_crtc *crtc = priv->channels[channel]->crtc;
+	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
+
 	DBG("%s", omap_crtc->name);
 	omap_crtc->vm = *vm;
 }
@@ -245,7 +219,8 @@ static void omap_crtc_dss_set_lcd_config(struct omap_drm_private *priv,
 		enum omap_channel channel,
 		const struct dss_lcd_mgr_config *config)
 {
-	struct omap_crtc *omap_crtc = omap_crtcs[channel];
+	struct drm_crtc *crtc = priv->channels[channel]->crtc;
+	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
 
 	DBG("%s", omap_crtc->name);
 	priv->dispc_ops->mgr_set_lcd_config(priv->dispc, omap_crtc->channel,
@@ -266,8 +241,6 @@ static void omap_crtc_dss_unregister_framedone(
 }
 
 static const struct dss_mgr_ops mgr_ops = {
-	.connect = omap_crtc_dss_connect,
-	.disconnect = omap_crtc_dss_disconnect,
 	.start_update = omap_crtc_dss_start_update,
 	.enable = omap_crtc_dss_enable,
 	.disable = omap_crtc_dss_disable,
@@ -377,11 +350,14 @@ static void omap_crtc_arm_event(struct drm_crtc *crtc)
 static void omap_crtc_atomic_enable(struct drm_crtc *crtc,
 				    struct drm_crtc_state *old_state)
 {
+	struct omap_drm_private *priv = crtc->dev->dev_private;
 	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
 	int ret;
 
 	DBG("%s", omap_crtc->name);
 
+	priv->dispc_ops->runtime_get(priv->dispc);
+
 	spin_lock_irq(&crtc->dev->event_lock);
 	drm_crtc_vblank_on(crtc);
 	ret = drm_crtc_vblank_get(crtc);
@@ -394,6 +370,7 @@ static void omap_crtc_atomic_enable(struct drm_crtc *crtc,
 static void omap_crtc_atomic_disable(struct drm_crtc *crtc,
 				     struct drm_crtc_state *old_state)
 {
+	struct omap_drm_private *priv = crtc->dev->dev_private;
 	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
 
 	DBG("%s", omap_crtc->name);
@@ -406,6 +383,8 @@ static void omap_crtc_atomic_disable(struct drm_crtc *crtc,
 	spin_unlock_irq(&crtc->dev->event_lock);
 
 	drm_crtc_vblank_off(crtc);
+
+	priv->dispc_ops->runtime_put(priv->dispc);
 }
 
 static enum drm_mode_status omap_crtc_mode_valid(struct drm_crtc *crtc,
@@ -447,11 +426,6 @@ static void omap_crtc_mode_set_nofb(struct drm_crtc *crtc)
 {
 	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
 	struct drm_display_mode *mode = &crtc->state->adjusted_mode;
-	struct omap_drm_private *priv = crtc->dev->dev_private;
-	const u32 flags_mask = DISPLAY_FLAGS_DE_HIGH | DISPLAY_FLAGS_DE_LOW |
-		DISPLAY_FLAGS_PIXDATA_POSEDGE | DISPLAY_FLAGS_PIXDATA_NEGEDGE |
-		DISPLAY_FLAGS_SYNC_POSEDGE | DISPLAY_FLAGS_SYNC_NEGEDGE;
-	unsigned int i;
 
 	DBG("%s: set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
 	    omap_crtc->name, mode->base.id, mode->name,
@@ -461,38 +435,6 @@ static void omap_crtc_mode_set_nofb(struct drm_crtc *crtc)
 	    mode->type, mode->flags);
 
 	drm_display_mode_to_videomode(mode, &omap_crtc->vm);
-
-	/*
-	 * HACK: This fixes the vm flags.
-	 * struct drm_display_mode does not contain the VSYNC/HSYNC/DE flags
-	 * and they get lost when converting back and forth between
-	 * struct drm_display_mode and struct videomode. The hack below
-	 * goes and fetches the missing flags from the panel drivers.
-	 *
-	 * Correct solution would be to use DRM's bus-flags, but that's not
-	 * easily possible before the omapdrm's panel/encoder driver model
-	 * has been changed to the DRM model.
-	 */
-
-	for (i = 0; i < priv->num_encoders; ++i) {
-		struct drm_encoder *encoder = priv->encoders[i];
-
-		if (encoder->crtc == crtc) {
-			struct omap_dss_device *dssdev;
-
-			dssdev = omap_encoder_get_dssdev(encoder);
-
-			if (dssdev) {
-				struct videomode vm = {0};
-
-				dssdev->driver->get_timings(dssdev, &vm);
-
-				omap_crtc->vm.flags |= vm.flags & flags_mask;
-			}
-
-			break;
-		}
-	}
 }
 
 static int omap_crtc_atomic_check(struct drm_crtc *crtc,
@@ -681,37 +623,29 @@ static const char *channel_names[] = {
 
 void omap_crtc_pre_init(struct omap_drm_private *priv)
 {
-	memset(omap_crtcs, 0, sizeof(omap_crtcs));
-
-	dss_install_mgr_ops(&mgr_ops, priv);
+	dss_install_mgr_ops(priv->dss, &mgr_ops, priv);
 }
 
-void omap_crtc_pre_uninit(void)
+void omap_crtc_pre_uninit(struct omap_drm_private *priv)
 {
-	dss_uninstall_mgr_ops();
+	dss_uninstall_mgr_ops(priv->dss);
 }
 
 /* initialize crtc */
 struct drm_crtc *omap_crtc_init(struct drm_device *dev,
-		struct drm_plane *plane, struct omap_dss_device *dssdev)
+				struct omap_drm_pipeline *pipe,
+				struct drm_plane *plane)
 {
 	struct omap_drm_private *priv = dev->dev_private;
 	struct drm_crtc *crtc = NULL;
 	struct omap_crtc *omap_crtc;
 	enum omap_channel channel;
-	struct omap_dss_device *out;
 	int ret;
 
-	out = omapdss_find_output_from_display(dssdev);
-	channel = out->dispc_channel;
-	omap_dss_put_device(out);
+	channel = pipe->output->dispc_channel;
 
 	DBG("%s", channel_names[channel]);
 
-	/* Multiple displays on same channel is not allowed */
-	if (WARN_ON(omap_crtcs[channel] != NULL))
-		return ERR_PTR(-EINVAL);
-
 	omap_crtc = kzalloc(sizeof(*omap_crtc), GFP_KERNEL);
 	if (!omap_crtc)
 		return ERR_PTR(-ENOMEM);
@@ -720,6 +654,7 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
 
 	init_waitqueue_head(&omap_crtc->pending_wait);
 
+	omap_crtc->pipe = pipe;
 	omap_crtc->channel = channel;
 	omap_crtc->name = channel_names[channel];
 
@@ -727,7 +662,7 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
 					&omap_crtc_funcs, NULL);
 	if (ret < 0) {
 		dev_err(dev->dev, "%s(): could not init crtc for: %s\n",
-			__func__, dssdev->name);
+			__func__, pipe->display->name);
 		kfree(omap_crtc);
 		return ERR_PTR(ret);
 	}
@@ -750,7 +685,5 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
 
 	omap_plane_install_properties(crtc->primary, &crtc->base);
 
-	omap_crtcs[channel] = omap_crtc;
-
 	return crtc;
 }

+ 4 - 2
drivers/gpu/drm/omapdrm/omap_crtc.h

@@ -27,15 +27,17 @@ enum omap_channel;
 struct drm_crtc;
 struct drm_device;
 struct drm_plane;
+struct omap_drm_pipeline;
 struct omap_dss_device;
 struct videomode;
 
 struct videomode *omap_crtc_timings(struct drm_crtc *crtc);
 enum omap_channel omap_crtc_channel(struct drm_crtc *crtc);
 void omap_crtc_pre_init(struct omap_drm_private *priv);
-void omap_crtc_pre_uninit(void);
+void omap_crtc_pre_uninit(struct omap_drm_private *priv);
 struct drm_crtc *omap_crtc_init(struct drm_device *dev,
-		struct drm_plane *plane, struct omap_dss_device *dssdev);
+				struct omap_drm_pipeline *pipe,
+				struct drm_plane *plane);
 int omap_crtc_wait_pending(struct drm_crtc *crtc);
 void omap_crtc_error_irq(struct drm_crtc *crtc, u32 irqstatus);
 void omap_crtc_vblank_irq(struct drm_crtc *crtc);

+ 7 - 0
drivers/gpu/drm/omapdrm/omap_dmm_priv.h

@@ -159,6 +159,7 @@ struct dmm_platform_data {
 
 struct dmm {
 	struct device *dev;
+	dma_addr_t phys_base;
 	void __iomem *base;
 	int irq;
 
@@ -189,6 +190,12 @@ struct dmm {
 	struct list_head alloc_head;
 
 	const struct dmm_platform_data *plat_data;
+
+	bool dmm_workaround;
+	spinlock_t wa_lock;
+	u32 *wa_dma_data;
+	dma_addr_t wa_dma_handle;
+	struct dma_chan *wa_dma_chan;
 };
 
 #endif

+ 168 - 22
drivers/gpu/drm/omapdrm/omap_dmm_tiler.c

@@ -18,6 +18,7 @@
 #include <linux/completion.h>
 #include <linux/delay.h>
 #include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
@@ -79,14 +80,138 @@ static const u32 reg[][4] = {
 			DMM_PAT_DESCR__2, DMM_PAT_DESCR__3},
 };
 
+static int dmm_dma_copy(struct dmm *dmm, dma_addr_t src, dma_addr_t dst)
+{
+	struct dma_device *dma_dev = dmm->wa_dma_chan->device;
+	struct dma_async_tx_descriptor *tx;
+	enum dma_status status;
+	dma_cookie_t cookie;
+
+	tx = dma_dev->device_prep_dma_memcpy(dmm->wa_dma_chan, dst, src, 4, 0);
+	if (!tx) {
+		dev_err(dmm->dev, "Failed to prepare DMA memcpy\n");
+		return -EIO;
+	}
+
+	cookie = tx->tx_submit(tx);
+	if (dma_submit_error(cookie)) {
+		dev_err(dmm->dev, "Failed to do DMA tx_submit\n");
+		return -EIO;
+	}
+
+	dma_async_issue_pending(dmm->wa_dma_chan);
+	status = dma_sync_wait(dmm->wa_dma_chan, cookie);
+	if (status != DMA_COMPLETE)
+		dev_err(dmm->dev, "i878 wa DMA copy failure\n");
+
+	dmaengine_terminate_all(dmm->wa_dma_chan);
+	return 0;
+}
+
+static u32 dmm_read_wa(struct dmm *dmm, u32 reg)
+{
+	dma_addr_t src, dst;
+	int r;
+
+	src = dmm->phys_base + reg;
+	dst = dmm->wa_dma_handle;
+
+	r = dmm_dma_copy(dmm, src, dst);
+	if (r) {
+		dev_err(dmm->dev, "sDMA read transfer timeout\n");
+		return readl(dmm->base + reg);
+	}
+
+	/*
+	 * As per i878 workaround, the DMA is used to access the DMM registers.
+	 * Make sure that the readl is not moved by the compiler or the CPU
+	 * earlier than the DMA finished writing the value to memory.
+	 */
+	rmb();
+	return readl(dmm->wa_dma_data);
+}
+
+static void dmm_write_wa(struct dmm *dmm, u32 val, u32 reg)
+{
+	dma_addr_t src, dst;
+	int r;
+
+	writel(val, dmm->wa_dma_data);
+	/*
+	 * As per i878 workaround, the DMA is used to access the DMM registers.
+	 * Make sure that the writel is not moved by the compiler or the CPU, so
+	 * the data will be in place before we start the DMA to do the actual
+	 * register write.
+	 */
+	wmb();
+
+	src = dmm->wa_dma_handle;
+	dst = dmm->phys_base + reg;
+
+	r = dmm_dma_copy(dmm, src, dst);
+	if (r) {
+		dev_err(dmm->dev, "sDMA write transfer timeout\n");
+		writel(val, dmm->base + reg);
+	}
+}
+
 static u32 dmm_read(struct dmm *dmm, u32 reg)
 {
-	return readl(dmm->base + reg);
+	if (dmm->dmm_workaround) {
+		u32 v;
+		unsigned long flags;
+
+		spin_lock_irqsave(&dmm->wa_lock, flags);
+		v = dmm_read_wa(dmm, reg);
+		spin_unlock_irqrestore(&dmm->wa_lock, flags);
+
+		return v;
+	} else {
+		return readl(dmm->base + reg);
+	}
 }
 
 static void dmm_write(struct dmm *dmm, u32 val, u32 reg)
 {
-	writel(val, dmm->base + reg);
+	if (dmm->dmm_workaround) {
+		unsigned long flags;
+
+		spin_lock_irqsave(&dmm->wa_lock, flags);
+		dmm_write_wa(dmm, val, reg);
+		spin_unlock_irqrestore(&dmm->wa_lock, flags);
+	} else {
+		writel(val, dmm->base + reg);
+	}
+}
+
+static int dmm_workaround_init(struct dmm *dmm)
+{
+	dma_cap_mask_t mask;
+
+	spin_lock_init(&dmm->wa_lock);
+
+	dmm->wa_dma_data = dma_alloc_coherent(dmm->dev,  sizeof(u32),
+					      &dmm->wa_dma_handle, GFP_KERNEL);
+	if (!dmm->wa_dma_data)
+		return -ENOMEM;
+
+	dma_cap_zero(mask);
+	dma_cap_set(DMA_MEMCPY, mask);
+
+	dmm->wa_dma_chan = dma_request_channel(mask, NULL, NULL);
+	if (!dmm->wa_dma_chan) {
+		dma_free_coherent(dmm->dev, 4, dmm->wa_dma_data, dmm->wa_dma_handle);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static void dmm_workaround_uninit(struct dmm *dmm)
+{
+	dma_release_channel(dmm->wa_dma_chan);
+
+	dma_free_coherent(dmm->dev, 4, dmm->wa_dma_data, dmm->wa_dma_handle);
 }
 
 /* simple allocator to grab next 16 byte aligned memory from txn */
@@ -614,6 +739,10 @@ static int omap_dmm_remove(struct platform_device *dev)
 	unsigned long flags;
 
 	if (omap_dmm) {
+		/* Disable all enabled interrupts */
+		dmm_write(omap_dmm, 0x7e7e7e7e, DMM_PAT_IRQENABLE_CLR);
+		free_irq(omap_dmm->irq, omap_dmm);
+
 		/* free all area regions */
 		spin_lock_irqsave(&list_lock, flags);
 		list_for_each_entry_safe(block, _block, &omap_dmm->alloc_head,
@@ -636,8 +765,8 @@ static int omap_dmm_remove(struct platform_device *dev)
 		if (omap_dmm->dummy_page)
 			__free_page(omap_dmm->dummy_page);
 
-		if (omap_dmm->irq > 0)
-			free_irq(omap_dmm->irq, omap_dmm);
+		if (omap_dmm->dmm_workaround)
+			dmm_workaround_uninit(omap_dmm);
 
 		iounmap(omap_dmm->base);
 		kfree(omap_dmm);
@@ -684,6 +813,7 @@ static int omap_dmm_probe(struct platform_device *dev)
 		goto fail;
 	}
 
+	omap_dmm->phys_base = mem->start;
 	omap_dmm->base = ioremap(mem->start, SZ_2K);
 
 	if (!omap_dmm->base) {
@@ -699,6 +829,22 @@ static int omap_dmm_probe(struct platform_device *dev)
 
 	omap_dmm->dev = &dev->dev;
 
+	if (of_machine_is_compatible("ti,dra7")) {
+		/*
+		 * DRA7 Errata i878 says that MPU should not be used to access
+		 * RAM and DMM at the same time. As it's not possible to prevent
+		 * MPU accessing RAM, we need to access DMM via a proxy.
+		 */
+		if (!dmm_workaround_init(omap_dmm)) {
+			omap_dmm->dmm_workaround = true;
+			dev_info(&dev->dev,
+				"workaround for errata i878 in use\n");
+		} else {
+			dev_warn(&dev->dev,
+				 "failed to initialize work-around for i878\n");
+		}
+	}
+
 	hwinfo = dmm_read(omap_dmm, DMM_PAT_HWINFO);
 	omap_dmm->num_engines = (hwinfo >> 24) & 0x1F;
 	omap_dmm->num_lut = (hwinfo >> 16) & 0x1F;
@@ -725,24 +871,6 @@ static int omap_dmm_probe(struct platform_device *dev)
 	dmm_write(omap_dmm, 0x88888888, DMM_TILER_OR__0);
 	dmm_write(omap_dmm, 0x88888888, DMM_TILER_OR__1);
 
-	ret = request_irq(omap_dmm->irq, omap_dmm_irq_handler, IRQF_SHARED,
-				"omap_dmm_irq_handler", omap_dmm);
-
-	if (ret) {
-		dev_err(&dev->dev, "couldn't register IRQ %d, error %d\n",
-			omap_dmm->irq, ret);
-		omap_dmm->irq = -1;
-		goto fail;
-	}
-
-	/* Enable all interrupts for each refill engine except
-	 * ERR_LUT_MISS<n> (which is just advisory, and we don't care
-	 * about because we want to be able to refill live scanout
-	 * buffers for accelerated pan/scroll) and FILL_DSC<n> which
-	 * we just generally don't care about.
-	 */
-	dmm_write(omap_dmm, 0x7e7e7e7e, DMM_PAT_IRQENABLE_SET);
-
 	omap_dmm->dummy_page = alloc_page(GFP_KERNEL | __GFP_DMA32);
 	if (!omap_dmm->dummy_page) {
 		dev_err(&dev->dev, "could not allocate dummy page\n");
@@ -834,6 +962,24 @@ static int omap_dmm_probe(struct platform_device *dev)
 		.p1.y = omap_dmm->container_height - 1,
 	};
 
+	ret = request_irq(omap_dmm->irq, omap_dmm_irq_handler, IRQF_SHARED,
+				"omap_dmm_irq_handler", omap_dmm);
+
+	if (ret) {
+		dev_err(&dev->dev, "couldn't register IRQ %d, error %d\n",
+			omap_dmm->irq, ret);
+		omap_dmm->irq = -1;
+		goto fail;
+	}
+
+	/* Enable all interrupts for each refill engine except
+	 * ERR_LUT_MISS<n> (which is just advisory, and we don't care
+	 * about because we want to be able to refill live scanout
+	 * buffers for accelerated pan/scroll) and FILL_DSC<n> which
+	 * we just generally don't care about.
+	 */
+	dmm_write(omap_dmm, 0x7e7e7e7e, DMM_PAT_IRQENABLE_SET);
+
 	/* initialize all LUTs to dummy page entries */
 	for (i = 0; i < omap_dmm->num_lut; i++) {
 		area.tcm = omap_dmm->tcm[i];

+ 156 - 148
drivers/gpu/drm/omapdrm/omap_drv.c

@@ -15,6 +15,8 @@
  * this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <linux/of.h>
+#include <linux/sort.h>
 #include <linux/sys_soc.h>
 
 #include <drm/drm_atomic.h>
@@ -127,55 +129,92 @@ static const struct drm_mode_config_funcs omap_mode_config_funcs = {
 	.atomic_commit = drm_atomic_helper_commit,
 };
 
-static int get_connector_type(struct omap_dss_device *dssdev)
+static void omap_disconnect_pipelines(struct drm_device *ddev)
 {
-	switch (dssdev->type) {
-	case OMAP_DISPLAY_TYPE_HDMI:
-		return DRM_MODE_CONNECTOR_HDMIA;
-	case OMAP_DISPLAY_TYPE_DVI:
-		return DRM_MODE_CONNECTOR_DVID;
-	case OMAP_DISPLAY_TYPE_DSI:
-		return DRM_MODE_CONNECTOR_DSI;
-	case OMAP_DISPLAY_TYPE_DPI:
-	case OMAP_DISPLAY_TYPE_DBI:
-		return DRM_MODE_CONNECTOR_DPI;
-	case OMAP_DISPLAY_TYPE_VENC:
-		/* TODO: This could also be composite */
-		return DRM_MODE_CONNECTOR_SVIDEO;
-	case OMAP_DISPLAY_TYPE_SDI:
-		return DRM_MODE_CONNECTOR_LVDS;
-	default:
-		return DRM_MODE_CONNECTOR_Unknown;
+	struct omap_drm_private *priv = ddev->dev_private;
+	unsigned int i;
+
+	for (i = 0; i < priv->num_pipes; i++) {
+		struct omap_drm_pipeline *pipe = &priv->pipes[i];
+
+		omapdss_device_disconnect(NULL, pipe->output);
+
+		omapdss_device_put(pipe->output);
+		omapdss_device_put(pipe->display);
+		pipe->output = NULL;
+		pipe->display = NULL;
 	}
+
+	memset(&priv->channels, 0, sizeof(priv->channels));
+
+	priv->num_pipes = 0;
 }
 
-static void omap_disconnect_dssdevs(void)
+static int omap_compare_pipes(const void *a, const void *b)
 {
-	struct omap_dss_device *dssdev = NULL;
+	const struct omap_drm_pipeline *pipe1 = a;
+	const struct omap_drm_pipeline *pipe2 = b;
 
-	for_each_dss_dev(dssdev)
-		dssdev->driver->disconnect(dssdev);
+	if (pipe1->display->alias_id > pipe2->display->alias_id)
+		return 1;
+	else if (pipe1->display->alias_id < pipe2->display->alias_id)
+		return -1;
+	return 0;
 }
 
-static int omap_connect_dssdevs(void)
+static int omap_connect_pipelines(struct drm_device *ddev)
 {
+	struct omap_drm_private *priv = ddev->dev_private;
+	struct omap_dss_device *output = NULL;
+	unsigned int i;
 	int r;
-	struct omap_dss_device *dssdev = NULL;
 
 	if (!omapdss_stack_is_ready())
 		return -EPROBE_DEFER;
 
-	for_each_dss_dev(dssdev) {
-		r = dssdev->driver->connect(dssdev);
+	for_each_dss_output(output) {
+		r = omapdss_device_connect(priv->dss, NULL, output);
 		if (r == -EPROBE_DEFER) {
-			omap_dss_put_device(dssdev);
+			omapdss_device_put(output);
 			goto cleanup;
 		} else if (r) {
-			dev_warn(dssdev->dev, "could not connect display: %s\n",
-				dssdev->name);
+			dev_warn(output->dev, "could not connect output %s\n",
+				 output->name);
+		} else {
+			struct omap_drm_pipeline *pipe;
+
+			pipe = &priv->pipes[priv->num_pipes++];
+			pipe->output = omapdss_device_get(output);
+			pipe->display = omapdss_display_get(output);
+
+			if (priv->num_pipes == ARRAY_SIZE(priv->pipes)) {
+				/* To balance the 'for_each_dss_output' loop */
+				omapdss_device_put(output);
+				break;
+			}
 		}
 	}
 
+	/* Sort the list by DT aliases */
+	sort(priv->pipes, priv->num_pipes, sizeof(priv->pipes[0]),
+	     omap_compare_pipes, NULL);
+
+	/*
+	 * Populate the pipeline lookup table by DISPC channel. Only one display
+	 * is allowed per channel.
+	 */
+	for (i = 0; i < priv->num_pipes; ++i) {
+		struct omap_drm_pipeline *pipe = &priv->pipes[i];
+		enum omap_channel channel = pipe->output->dispc_channel;
+
+		if (WARN_ON(priv->channels[channel] != NULL)) {
+			r = -EINVAL;
+			goto cleanup;
+		}
+
+		priv->channels[channel] = pipe;
+	}
+
 	return 0;
 
 cleanup:
@@ -183,7 +222,7 @@ cleanup:
 	 * if we are deferring probe, we disconnect the devices we previously
 	 * connected
 	 */
-	omap_disconnect_dssdevs();
+	omap_disconnect_pipelines(ddev);
 
 	return r;
 }
@@ -204,10 +243,9 @@ static int omap_modeset_init_properties(struct drm_device *dev)
 static int omap_modeset_init(struct drm_device *dev)
 {
 	struct omap_drm_private *priv = dev->dev_private;
-	struct omap_dss_device *dssdev = NULL;
 	int num_ovls = priv->dispc_ops->get_num_ovls(priv->dispc);
 	int num_mgrs = priv->dispc_ops->get_num_mgrs(priv->dispc);
-	int num_crtcs, crtc_idx, plane_idx;
+	unsigned int i;
 	int ret;
 	u32 plane_crtc_mask;
 
@@ -225,87 +263,62 @@ static int omap_modeset_init(struct drm_device *dev)
 	 * configuration does not match the expectations or exceeds
 	 * the available resources, the configuration is rejected.
 	 */
-	num_crtcs = 0;
-	for_each_dss_dev(dssdev)
-		if (omapdss_device_is_connected(dssdev))
-			num_crtcs++;
-
-	if (num_crtcs > num_mgrs || num_crtcs > num_ovls ||
-	    num_crtcs > ARRAY_SIZE(priv->crtcs) ||
-	    num_crtcs > ARRAY_SIZE(priv->planes) ||
-	    num_crtcs > ARRAY_SIZE(priv->encoders) ||
-	    num_crtcs > ARRAY_SIZE(priv->connectors)) {
+	if (priv->num_pipes > num_mgrs || priv->num_pipes > num_ovls) {
 		dev_err(dev->dev, "%s(): Too many connected displays\n",
 			__func__);
 		return -EINVAL;
 	}
 
-	/* All planes can be put to any CRTC */
-	plane_crtc_mask = (1 << num_crtcs) - 1;
+	/* Create all planes first. They can all be put to any CRTC. */
+	plane_crtc_mask = (1 << priv->num_pipes) - 1;
 
-	dssdev = NULL;
+	for (i = 0; i < num_ovls; i++) {
+		enum drm_plane_type type = i < priv->num_pipes
+					 ? DRM_PLANE_TYPE_PRIMARY
+					 : DRM_PLANE_TYPE_OVERLAY;
+		struct drm_plane *plane;
 
-	crtc_idx = 0;
-	plane_idx = 0;
-	for_each_dss_dev(dssdev) {
+		if (WARN_ON(priv->num_planes >= ARRAY_SIZE(priv->planes)))
+			return -EINVAL;
+
+		plane = omap_plane_init(dev, i, type, plane_crtc_mask);
+		if (IS_ERR(plane))
+			return PTR_ERR(plane);
+
+		priv->planes[priv->num_planes++] = plane;
+	}
+
+	/* Create the CRTCs, encoders and connectors. */
+	for (i = 0; i < priv->num_pipes; i++) {
+		struct omap_drm_pipeline *pipe = &priv->pipes[i];
+		struct omap_dss_device *display = pipe->display;
 		struct drm_connector *connector;
 		struct drm_encoder *encoder;
-		struct drm_plane *plane;
 		struct drm_crtc *crtc;
 
-		if (!omapdss_device_is_connected(dssdev))
-			continue;
-
-		encoder = omap_encoder_init(dev, dssdev);
+		encoder = omap_encoder_init(dev, pipe->output, display);
 		if (!encoder)
 			return -ENOMEM;
 
-		connector = omap_connector_init(dev,
-				get_connector_type(dssdev), dssdev, encoder);
+		connector = omap_connector_init(dev, pipe->output, display,
+						encoder);
 		if (!connector)
 			return -ENOMEM;
 
-		plane = omap_plane_init(dev, plane_idx, DRM_PLANE_TYPE_PRIMARY,
-					plane_crtc_mask);
-		if (IS_ERR(plane))
-			return PTR_ERR(plane);
-
-		crtc = omap_crtc_init(dev, plane, dssdev);
+		crtc = omap_crtc_init(dev, pipe, priv->planes[i]);
 		if (IS_ERR(crtc))
 			return PTR_ERR(crtc);
 
 		drm_connector_attach_encoder(connector, encoder);
-		encoder->possible_crtcs = (1 << crtc_idx);
-
-		priv->crtcs[priv->num_crtcs++] = crtc;
-		priv->planes[priv->num_planes++] = plane;
-		priv->encoders[priv->num_encoders++] = encoder;
-		priv->connectors[priv->num_connectors++] = connector;
-
-		plane_idx++;
-		crtc_idx++;
-	}
-
-	/*
-	 * Create normal planes for the remaining overlays:
-	 */
-	for (; plane_idx < num_ovls; plane_idx++) {
-		struct drm_plane *plane;
-
-		if (WARN_ON(priv->num_planes >= ARRAY_SIZE(priv->planes)))
-			return -EINVAL;
+		encoder->possible_crtcs = 1 << i;
 
-		plane = omap_plane_init(dev, plane_idx, DRM_PLANE_TYPE_OVERLAY,
-			plane_crtc_mask);
-		if (IS_ERR(plane))
-			return PTR_ERR(plane);
-
-		priv->planes[priv->num_planes++] = plane;
+		pipe->crtc = crtc;
+		pipe->encoder = encoder;
+		pipe->connector = connector;
 	}
 
-	DBG("registered %d planes, %d crtcs, %d encoders and %d connectors\n",
-		priv->num_planes, priv->num_crtcs, priv->num_encoders,
-		priv->num_connectors);
+	DBG("registered %u planes, %u crtcs/encoders/connectors\n",
+	    priv->num_planes, priv->num_pipes);
 
 	dev->mode_config.min_width = 8;
 	dev->mode_config.min_height = 2;
@@ -335,27 +348,25 @@ static int omap_modeset_init(struct drm_device *dev)
 /*
  * Enable the HPD in external components if supported
  */
-static void omap_modeset_enable_external_hpd(void)
+static void omap_modeset_enable_external_hpd(struct drm_device *ddev)
 {
-	struct omap_dss_device *dssdev = NULL;
+	struct omap_drm_private *priv = ddev->dev_private;
+	int i;
 
-	for_each_dss_dev(dssdev) {
-		if (dssdev->driver->enable_hpd)
-			dssdev->driver->enable_hpd(dssdev);
-	}
+	for (i = 0; i < priv->num_pipes; i++)
+		omap_connector_enable_hpd(priv->pipes[i].connector);
 }
 
 /*
  * Disable the HPD in external components if supported
  */
-static void omap_modeset_disable_external_hpd(void)
+static void omap_modeset_disable_external_hpd(struct drm_device *ddev)
 {
-	struct omap_dss_device *dssdev = NULL;
+	struct omap_drm_private *priv = ddev->dev_private;
+	int i;
 
-	for_each_dss_dev(dssdev) {
-		if (dssdev->driver->disable_hpd)
-			dssdev->driver->disable_hpd(dssdev);
-	}
+	for (i = 0; i < priv->num_pipes; i++)
+		omap_connector_disable_hpd(priv->pipes[i].connector);
 }
 
 /*
@@ -428,7 +439,7 @@ static int ioctl_gem_info(struct drm_device *dev, void *data,
 	args->size = omap_gem_mmap_size(obj);
 	args->offset = omap_gem_mmap_offset(obj);
 
-	drm_gem_object_unreference_unlocked(obj);
+	drm_gem_object_put_unlocked(obj);
 
 	return ret;
 }
@@ -525,6 +536,14 @@ static int omapdrm_init(struct omap_drm_private *priv, struct device *dev)
 
 	DBG("%s", dev_name(dev));
 
+	/* Allocate and initialize the DRM device. */
+	ddev = drm_dev_alloc(&omap_drm_driver, dev);
+	if (IS_ERR(ddev))
+		return PTR_ERR(ddev);
+
+	priv->ddev = ddev;
+	ddev->dev_private = priv;
+
 	priv->dev = dev;
 	priv->dss = omapdss_get_dss();
 	priv->dispc = dispc_get_dispc(priv->dss);
@@ -532,7 +551,7 @@ static int omapdrm_init(struct omap_drm_private *priv, struct device *dev)
 
 	omap_crtc_pre_init(priv);
 
-	ret = omap_connect_dssdevs();
+	ret = omap_connect_pipelines(ddev);
 	if (ret)
 		goto err_crtc_uninit;
 
@@ -543,16 +562,6 @@ static int omapdrm_init(struct omap_drm_private *priv, struct device *dev)
 	mutex_init(&priv->list_lock);
 	INIT_LIST_HEAD(&priv->obj_list);
 
-	/* Allocate and initialize the DRM device. */
-	ddev = drm_dev_alloc(&omap_drm_driver, priv->dev);
-	if (IS_ERR(ddev)) {
-		ret = PTR_ERR(ddev);
-		goto err_destroy_wq;
-	}
-
-	priv->ddev = ddev;
-	ddev->dev_private = priv;
-
 	/* Get memory bandwidth limits */
 	if (priv->dispc_ops->get_memory_bandwidth_limit)
 		priv->max_bandwidth =
@@ -563,23 +572,23 @@ static int omapdrm_init(struct omap_drm_private *priv, struct device *dev)
 	ret = omap_modeset_init(ddev);
 	if (ret) {
 		dev_err(priv->dev, "omap_modeset_init failed: ret=%d\n", ret);
-		goto err_free_drm_dev;
+		goto err_gem_deinit;
 	}
 
 	/* Initialize vblank handling, start with all CRTCs disabled. */
-	ret = drm_vblank_init(ddev, priv->num_crtcs);
+	ret = drm_vblank_init(ddev, priv->num_pipes);
 	if (ret) {
 		dev_err(priv->dev, "could not init vblank\n");
 		goto err_cleanup_modeset;
 	}
 
-	for (i = 0; i < priv->num_crtcs; i++)
-		drm_crtc_vblank_off(priv->crtcs[i]);
+	for (i = 0; i < priv->num_pipes; i++)
+		drm_crtc_vblank_off(priv->pipes[i].crtc);
 
 	omap_fbdev_init(ddev);
 
 	drm_kms_helper_poll_init(ddev);
-	omap_modeset_enable_external_hpd();
+	omap_modeset_enable_external_hpd(ddev);
 
 	/*
 	 * Register the DRM device with the core and the connectors with
@@ -592,21 +601,20 @@ static int omapdrm_init(struct omap_drm_private *priv, struct device *dev)
 	return 0;
 
 err_cleanup_helpers:
-	omap_modeset_disable_external_hpd();
+	omap_modeset_disable_external_hpd(ddev);
 	drm_kms_helper_poll_fini(ddev);
 
 	omap_fbdev_fini(ddev);
 err_cleanup_modeset:
 	drm_mode_config_cleanup(ddev);
 	omap_drm_irq_uninstall(ddev);
-err_free_drm_dev:
+err_gem_deinit:
 	omap_gem_deinit(ddev);
-	drm_dev_unref(ddev);
-err_destroy_wq:
 	destroy_workqueue(priv->wq);
-	omap_disconnect_dssdevs();
+	omap_disconnect_pipelines(ddev);
 err_crtc_uninit:
-	omap_crtc_pre_uninit();
+	omap_crtc_pre_uninit(priv);
+	drm_dev_put(ddev);
 	return ret;
 }
 
@@ -618,7 +626,7 @@ static void omapdrm_cleanup(struct omap_drm_private *priv)
 
 	drm_dev_unregister(ddev);
 
-	omap_modeset_disable_external_hpd();
+	omap_modeset_disable_external_hpd(ddev);
 	drm_kms_helper_poll_fini(ddev);
 
 	omap_fbdev_fini(ddev);
@@ -630,12 +638,12 @@ static void omapdrm_cleanup(struct omap_drm_private *priv)
 	omap_drm_irq_uninstall(ddev);
 	omap_gem_deinit(ddev);
 
-	drm_dev_unref(ddev);
-
 	destroy_workqueue(priv->wq);
 
-	omap_disconnect_dssdevs();
-	omap_crtc_pre_uninit();
+	omap_disconnect_pipelines(ddev);
+	omap_crtc_pre_uninit(priv);
+
+	drm_dev_put(ddev);
 }
 
 static int pdev_probe(struct platform_device *pdev)
@@ -677,36 +685,36 @@ static int pdev_remove(struct platform_device *pdev)
 }
 
 #ifdef CONFIG_PM_SLEEP
-static int omap_drm_suspend_all_displays(void)
+static int omap_drm_suspend_all_displays(struct drm_device *ddev)
 {
-	struct omap_dss_device *dssdev = NULL;
+	struct omap_drm_private *priv = ddev->dev_private;
+	int i;
 
-	for_each_dss_dev(dssdev) {
-		if (!dssdev->driver)
-			continue;
+	for (i = 0; i < priv->num_pipes; i++) {
+		struct omap_dss_device *display = priv->pipes[i].display;
 
-		if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
-			dssdev->driver->disable(dssdev);
-			dssdev->activate_after_resume = true;
+		if (display->state == OMAP_DSS_DISPLAY_ACTIVE) {
+			display->ops->disable(display);
+			display->activate_after_resume = true;
 		} else {
-			dssdev->activate_after_resume = false;
+			display->activate_after_resume = false;
 		}
 	}
 
 	return 0;
 }
 
-static int omap_drm_resume_all_displays(void)
+static int omap_drm_resume_all_displays(struct drm_device *ddev)
 {
-	struct omap_dss_device *dssdev = NULL;
+	struct omap_drm_private *priv = ddev->dev_private;
+	int i;
 
-	for_each_dss_dev(dssdev) {
-		if (!dssdev->driver)
-			continue;
+	for (i = 0; i < priv->num_pipes; i++) {
+		struct omap_dss_device *display = priv->pipes[i].display;
 
-		if (dssdev->activate_after_resume) {
-			dssdev->driver->enable(dssdev);
-			dssdev->activate_after_resume = false;
+		if (display->activate_after_resume) {
+			display->ops->enable(display);
+			display->activate_after_resume = false;
 		}
 	}
 
@@ -721,7 +729,7 @@ static int omap_drm_suspend(struct device *dev)
 	drm_kms_helper_poll_disable(drm_dev);
 
 	drm_modeset_lock_all(drm_dev);
-	omap_drm_suspend_all_displays();
+	omap_drm_suspend_all_displays(drm_dev);
 	drm_modeset_unlock_all(drm_dev);
 
 	return 0;
@@ -733,7 +741,7 @@ static int omap_drm_resume(struct device *dev)
 	struct drm_device *drm_dev = priv->ddev;
 
 	drm_modeset_lock_all(drm_dev);
-	omap_drm_resume_all_displays();
+	omap_drm_resume_all_displays(drm_dev);
 	drm_modeset_unlock_all(drm_dev);
 
 	drm_kms_helper_poll_enable(drm_dev);

+ 11 - 8
drivers/gpu/drm/omapdrm/omap_drv.h

@@ -45,6 +45,14 @@
 
 struct omap_drm_usergart;
 
+struct omap_drm_pipeline {
+	struct drm_crtc *crtc;
+	struct drm_encoder *encoder;
+	struct drm_connector *connector;
+	struct omap_dss_device *output;
+	struct omap_dss_device *display;
+};
+
 struct omap_drm_private {
 	struct drm_device *ddev;
 	struct device *dev;
@@ -54,18 +62,13 @@ struct omap_drm_private {
 	struct dispc_device *dispc;
 	const struct dispc_ops *dispc_ops;
 
-	unsigned int num_crtcs;
-	struct drm_crtc *crtcs[8];
+	unsigned int num_pipes;
+	struct omap_drm_pipeline pipes[8];
+	struct omap_drm_pipeline *channels[8];
 
 	unsigned int num_planes;
 	struct drm_plane *planes[8];
 
-	unsigned int num_encoders;
-	struct drm_encoder *encoders[8];
-
-	unsigned int num_connectors;
-	struct drm_connector *connectors[8];
-
 	struct drm_fb_helper *fbdev;
 
 	struct workqueue_struct *wq;

+ 102 - 57
drivers/gpu/drm/omapdrm/omap_encoder.c

@@ -36,16 +36,10 @@
  */
 struct omap_encoder {
 	struct drm_encoder base;
-	struct omap_dss_device *dssdev;
+	struct omap_dss_device *output;
+	struct omap_dss_device *display;
 };
 
-struct omap_dss_device *omap_encoder_get_dssdev(struct drm_encoder *encoder)
-{
-	struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
-
-	return omap_encoder->dssdev;
-}
-
 static void omap_encoder_destroy(struct drm_encoder *encoder)
 {
 	struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
@@ -58,16 +52,14 @@ static const struct drm_encoder_funcs omap_encoder_funcs = {
 	.destroy = omap_encoder_destroy,
 };
 
-static void omap_encoder_mode_set(struct drm_encoder *encoder,
-				struct drm_display_mode *mode,
-				struct drm_display_mode *adjusted_mode)
+static void omap_encoder_hdmi_mode_set(struct drm_encoder *encoder,
+				       struct drm_display_mode *adjusted_mode)
 {
 	struct drm_device *dev = encoder->dev;
 	struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
-	struct omap_dss_device *dssdev = omap_encoder->dssdev;
+	struct omap_dss_device *dssdev = omap_encoder->output;
 	struct drm_connector *connector;
 	bool hdmi_mode;
-	int r;
 
 	hdmi_mode = false;
 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
@@ -77,73 +69,95 @@ static void omap_encoder_mode_set(struct drm_encoder *encoder,
 		}
 	}
 
-	if (dssdev->driver->set_hdmi_mode)
-		dssdev->driver->set_hdmi_mode(dssdev, hdmi_mode);
+	if (dssdev->ops->hdmi.set_hdmi_mode)
+		dssdev->ops->hdmi.set_hdmi_mode(dssdev, hdmi_mode);
 
-	if (hdmi_mode && dssdev->driver->set_hdmi_infoframe) {
+	if (hdmi_mode && dssdev->ops->hdmi.set_infoframe) {
 		struct hdmi_avi_infoframe avi;
+		int r;
 
 		r = drm_hdmi_avi_infoframe_from_display_mode(&avi, adjusted_mode,
 							     false);
 		if (r == 0)
-			dssdev->driver->set_hdmi_infoframe(dssdev, &avi);
+			dssdev->ops->hdmi.set_infoframe(dssdev, &avi);
 	}
 }
 
-static void omap_encoder_disable(struct drm_encoder *encoder)
+static void omap_encoder_mode_set(struct drm_encoder *encoder,
+				  struct drm_display_mode *mode,
+				  struct drm_display_mode *adjusted_mode)
 {
 	struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
-	struct omap_dss_device *dssdev = omap_encoder->dssdev;
-	struct omap_dss_driver *dssdrv = dssdev->driver;
-
-	dssdrv->disable(dssdev);
-}
+	struct omap_dss_device *dssdev;
+	struct videomode vm = { 0 };
+
+	drm_display_mode_to_videomode(adjusted_mode, &vm);
+
+	/*
+	 * HACK: This fixes the vm flags.
+	 * struct drm_display_mode does not contain the VSYNC/HSYNC/DE flags and
+	 * they get lost when converting back and forth between struct
+	 * drm_display_mode and struct videomode. The hack below goes and
+	 * fetches the missing flags.
+	 *
+	 * A better solution is to use DRM's bus-flags through the whole driver.
+	 */
+	for (dssdev = omap_encoder->output; dssdev; dssdev = dssdev->next) {
+		unsigned long bus_flags = dssdev->bus_flags;
+
+		if (!(vm.flags & (DISPLAY_FLAGS_DE_LOW |
+				  DISPLAY_FLAGS_DE_HIGH))) {
+			if (bus_flags & DRM_BUS_FLAG_DE_LOW)
+				vm.flags |= DISPLAY_FLAGS_DE_LOW;
+			else if (bus_flags & DRM_BUS_FLAG_DE_HIGH)
+				vm.flags |= DISPLAY_FLAGS_DE_HIGH;
+		}
 
-static int omap_encoder_update(struct drm_encoder *encoder,
-			       enum omap_channel channel,
-			       struct videomode *vm)
-{
-	struct drm_device *dev = encoder->dev;
-	struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
-	struct omap_dss_device *dssdev = omap_encoder->dssdev;
-	struct omap_dss_driver *dssdrv = dssdev->driver;
-	int ret;
+		if (!(vm.flags & (DISPLAY_FLAGS_PIXDATA_POSEDGE |
+				  DISPLAY_FLAGS_PIXDATA_NEGEDGE))) {
+			if (bus_flags & DRM_BUS_FLAG_PIXDATA_POSEDGE)
+				vm.flags |= DISPLAY_FLAGS_PIXDATA_POSEDGE;
+			else if (bus_flags & DRM_BUS_FLAG_PIXDATA_NEGEDGE)
+				vm.flags |= DISPLAY_FLAGS_PIXDATA_NEGEDGE;
+		}
 
-	if (dssdrv->check_timings) {
-		ret = dssdrv->check_timings(dssdev, vm);
-	} else {
-		struct videomode t = {0};
+		if (!(vm.flags & (DISPLAY_FLAGS_SYNC_POSEDGE |
+				  DISPLAY_FLAGS_SYNC_NEGEDGE))) {
+			if (bus_flags & DRM_BUS_FLAG_SYNC_POSEDGE)
+				vm.flags |= DISPLAY_FLAGS_SYNC_POSEDGE;
+			else if (bus_flags & DRM_BUS_FLAG_SYNC_NEGEDGE)
+				vm.flags |= DISPLAY_FLAGS_SYNC_NEGEDGE;
+		}
+	}
 
-		dssdrv->get_timings(dssdev, &t);
+	/* Set timings for all devices in the display pipeline. */
+	dss_mgr_set_timings(omap_encoder->output, &vm);
 
-		if (memcmp(vm, &t, sizeof(*vm)))
-			ret = -EINVAL;
-		else
-			ret = 0;
+	for (dssdev = omap_encoder->output; dssdev; dssdev = dssdev->next) {
+		if (dssdev->ops->set_timings)
+			dssdev->ops->set_timings(dssdev, &vm);
 	}
 
-	if (ret) {
-		dev_err(dev->dev, "could not set timings: %d\n", ret);
-		return ret;
-	}
+	/* Set the HDMI mode and HDMI infoframe if applicable. */
+	if (omap_encoder->output->output_type == OMAP_DISPLAY_TYPE_HDMI)
+		omap_encoder_hdmi_mode_set(encoder, adjusted_mode);
+}
 
-	if (dssdrv->set_timings)
-		dssdrv->set_timings(dssdev, vm);
+static void omap_encoder_disable(struct drm_encoder *encoder)
+{
+	struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
+	struct omap_dss_device *dssdev = omap_encoder->display;
 
-	return 0;
+	dssdev->ops->disable(dssdev);
 }
 
 static void omap_encoder_enable(struct drm_encoder *encoder)
 {
 	struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
-	struct omap_dss_device *dssdev = omap_encoder->dssdev;
-	struct omap_dss_driver *dssdrv = dssdev->driver;
+	struct omap_dss_device *dssdev = omap_encoder->display;
 	int r;
 
-	omap_encoder_update(encoder, omap_crtc_channel(encoder->crtc),
-			    omap_crtc_timings(encoder->crtc));
-
-	r = dssdrv->enable(dssdev);
+	r = dssdev->ops->enable(dssdev);
 	if (r)
 		dev_err(encoder->dev->dev,
 			"Failed to enable display '%s': %d\n",
@@ -154,7 +168,36 @@ static int omap_encoder_atomic_check(struct drm_encoder *encoder,
 				     struct drm_crtc_state *crtc_state,
 				     struct drm_connector_state *conn_state)
 {
-	return 0;
+	struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
+	enum omap_channel channel = omap_encoder->output->dispc_channel;
+	struct drm_device *dev = encoder->dev;
+	struct omap_drm_private *priv = dev->dev_private;
+	struct omap_dss_device *dssdev;
+	struct videomode vm = { 0 };
+	int ret;
+
+	drm_display_mode_to_videomode(&crtc_state->mode, &vm);
+
+	ret = priv->dispc_ops->mgr_check_timings(priv->dispc, channel, &vm);
+	if (ret)
+		goto done;
+
+	for (dssdev = omap_encoder->output; dssdev; dssdev = dssdev->next) {
+		if (!dssdev->ops->check_timings)
+			continue;
+
+		ret = dssdev->ops->check_timings(dssdev, &vm);
+		if (ret)
+			goto done;
+	}
+
+	drm_display_mode_from_videomode(&vm, &crtc_state->adjusted_mode);
+
+done:
+	if (ret)
+		dev_err(dev->dev, "invalid timings: %d\n", ret);
+
+	return ret;
 }
 
 static const struct drm_encoder_helper_funcs omap_encoder_helper_funcs = {
@@ -166,7 +209,8 @@ static const struct drm_encoder_helper_funcs omap_encoder_helper_funcs = {
 
 /* initialize encoder */
 struct drm_encoder *omap_encoder_init(struct drm_device *dev,
-		struct omap_dss_device *dssdev)
+				      struct omap_dss_device *output,
+				      struct omap_dss_device *display)
 {
 	struct drm_encoder *encoder = NULL;
 	struct omap_encoder *omap_encoder;
@@ -175,7 +219,8 @@ struct drm_encoder *omap_encoder_init(struct drm_device *dev,
 	if (!omap_encoder)
 		goto fail;
 
-	omap_encoder->dssdev = dssdev;
+	omap_encoder->output = output;
+	omap_encoder->display = display;
 
 	encoder = &omap_encoder->base;
 

+ 2 - 4
drivers/gpu/drm/omapdrm/omap_encoder.h

@@ -25,9 +25,7 @@ struct drm_encoder;
 struct omap_dss_device;
 
 struct drm_encoder *omap_encoder_init(struct drm_device *dev,
-		struct omap_dss_device *dssdev);
-
-/* map crtc to vblank mask */
-struct omap_dss_device *omap_encoder_get_dssdev(struct drm_encoder *encoder);
+				      struct omap_dss_device *output,
+				      struct omap_dss_device *display);
 
 #endif /* __OMAPDRM_ENCODER_H__ */

+ 1 - 1
drivers/gpu/drm/omapdrm/omap_fb.c

@@ -319,7 +319,7 @@ struct drm_framebuffer *omap_framebuffer_create(struct drm_device *dev,
 
 error:
 	while (--i >= 0)
-		drm_gem_object_unreference_unlocked(bos[i]);
+		drm_gem_object_put_unlocked(bos[i]);
 
 	return fb;
 }

+ 3 - 3
drivers/gpu/drm/omapdrm/omap_fbdev.c

@@ -150,7 +150,7 @@ static int omap_fbdev_create(struct drm_fb_helper *helper,
 		/* note: if fb creation failed, we can't rely on fb destroy
 		 * to unref the bo:
 		 */
-		drm_gem_object_unreference_unlocked(fbdev->bo);
+		drm_gem_object_put_unlocked(fbdev->bo);
 		ret = PTR_ERR(fb);
 		goto fail;
 	}
@@ -243,7 +243,7 @@ void omap_fbdev_init(struct drm_device *dev)
 	struct drm_fb_helper *helper;
 	int ret = 0;
 
-	if (!priv->num_crtcs || !priv->num_connectors)
+	if (!priv->num_pipes)
 		return;
 
 	fbdev = kzalloc(sizeof(*fbdev), GFP_KERNEL);
@@ -256,7 +256,7 @@ void omap_fbdev_init(struct drm_device *dev)
 
 	drm_fb_helper_prepare(dev, helper, &omap_fb_helper_funcs);
 
-	ret = drm_fb_helper_init(dev, helper, priv->num_connectors);
+	ret = drm_fb_helper_init(dev, helper, priv->num_pipes);
 	if (ret)
 		goto fail;
 

+ 2 - 2
drivers/gpu/drm/omapdrm/omap_gem.c

@@ -638,7 +638,7 @@ int omap_gem_dumb_map_offset(struct drm_file *file, struct drm_device *dev,
 
 	*offset = omap_gem_mmap_offset(obj);
 
-	drm_gem_object_unreference_unlocked(obj);
+	drm_gem_object_put_unlocked(obj);
 
 fail:
 	return ret;
@@ -1312,7 +1312,7 @@ int omap_gem_new_handle(struct drm_device *dev, struct drm_file *file,
 	}
 
 	/* drop reference from allocate - handle holds it now */
-	drm_gem_object_unreference_unlocked(obj);
+	drm_gem_object_put_unlocked(obj);
 
 	return 0;
 }

+ 1 - 1
drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c

@@ -168,7 +168,7 @@ struct drm_gem_object *omap_gem_prime_import(struct drm_device *dev,
 			 * Importing dmabuf exported from out own gem increases
 			 * refcount on gem itself instead of f_count of dmabuf.
 			 */
-			drm_gem_object_reference(obj);
+			drm_gem_object_get(obj);
 			return obj;
 		}
 	}

+ 2 - 2
drivers/gpu/drm/omapdrm/omap_irq.c

@@ -206,8 +206,8 @@ static irqreturn_t omap_irq_handler(int irq, void *arg)
 
 	VERB("irqs: %08x", irqstatus);
 
-	for (id = 0; id < priv->num_crtcs; id++) {
-		struct drm_crtc *crtc = priv->crtcs[id];
+	for (id = 0; id < priv->num_pipes; id++) {
+		struct drm_crtc *crtc = priv->pipes[id].crtc;
 		enum omap_channel channel = omap_crtc_channel(crtc);
 
 		if (irqstatus & priv->dispc_ops->mgr_get_vsync_irq(priv->dispc, channel)) {

+ 0 - 93
drivers/gpu/drm/omapdrm/tcm-sita.h

@@ -1,93 +0,0 @@
-/*
- * SImple Tiler Allocator (SiTA) private structures.
- *
- * Copyright (C) 2009-2011 Texas Instruments Incorporated - http://www.ti.com/
- * Author: Ravi Ramachandra <r.ramachandra@ti.com>
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * * Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- *
- * * Neither the name of Texas Instruments Incorporated nor the names of
- *   its contributors may be used to endorse or promote products derived
- *   from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
- * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef _TCM_SITA_H
-#define _TCM_SITA_H
-
-#include "tcm.h"
-
-/* length between two coordinates */
-#define LEN(a, b) ((a) > (b) ? (a) - (b) + 1 : (b) - (a) + 1)
-
-enum criteria {
-	CR_MAX_NEIGHS		= 0x01,
-	CR_FIRST_FOUND		= 0x10,
-	CR_BIAS_HORIZONTAL	= 0x20,
-	CR_BIAS_VERTICAL	= 0x40,
-	CR_DIAGONAL_BALANCE	= 0x80
-};
-
-/* nearness to the beginning of the search field from 0 to 1000 */
-struct nearness_factor {
-	s32 x;
-	s32 y;
-};
-
-/*
- * Statistics on immediately neighboring slots.  Edge is the number of
- * border segments that are also border segments of the scan field.  Busy
- * refers to the number of neighbors that are occupied.
- */
-struct neighbor_stats {
-	u16 edge;
-	u16 busy;
-};
-
-/* structure to keep the score of a potential allocation */
-struct score {
-	struct nearness_factor	f;
-	struct neighbor_stats	n;
-	struct tcm_area		a;
-	u16    neighs;		/* number of busy neighbors */
-};
-
-struct sita_pvt {
-	spinlock_t lock;	/* spinlock to protect access */
-	struct tcm_pt div_pt;	/* divider point splitting container */
-	struct tcm_area ***map;	/* pointers to the parent area for each slot */
-};
-
-/* assign coordinates to area */
-static inline
-void assign(struct tcm_area *a, u16 x0, u16 y0, u16 x1, u16 y1)
-{
-	a->p0.x = x0;
-	a->p0.y = y0;
-	a->p1.x = x1;
-	a->p1.y = y1;
-}
-
-#endif