diff options
Diffstat (limited to 'drivers/gpu/drm/omapdrm/dss')
| -rw-r--r-- | drivers/gpu/drm/omapdrm/dss/Makefile | 2 | ||||
| -rw-r--r-- | drivers/gpu/drm/omapdrm/dss/base.c | 55 | ||||
| -rw-r--r-- | drivers/gpu/drm/omapdrm/dss/display.c | 9 | ||||
| -rw-r--r-- | drivers/gpu/drm/omapdrm/dss/dpi.c | 349 | ||||
| -rw-r--r-- | drivers/gpu/drm/omapdrm/dss/dsi.c | 4 | ||||
| -rw-r--r-- | drivers/gpu/drm/omapdrm/dss/dss-of.c | 28 | ||||
| -rw-r--r-- | drivers/gpu/drm/omapdrm/dss/dss.c | 46 | ||||
| -rw-r--r-- | drivers/gpu/drm/omapdrm/dss/hdmi.h | 4 | ||||
| -rw-r--r-- | drivers/gpu/drm/omapdrm/dss/hdmi4.c | 313 | ||||
| -rw-r--r-- | drivers/gpu/drm/omapdrm/dss/hdmi4_core.c | 59 | ||||
| -rw-r--r-- | drivers/gpu/drm/omapdrm/dss/hdmi4_core.h | 4 | ||||
| -rw-r--r-- | drivers/gpu/drm/omapdrm/dss/hdmi5.c | 295 | ||||
| -rw-r--r-- | drivers/gpu/drm/omapdrm/dss/hdmi5_core.c | 48 | ||||
| -rw-r--r-- | drivers/gpu/drm/omapdrm/dss/hdmi5_core.h | 5 | ||||
| -rw-r--r-- | drivers/gpu/drm/omapdrm/dss/omapdss-boot-init.c | 9 | ||||
| -rw-r--r-- | drivers/gpu/drm/omapdrm/dss/omapdss.h | 46 | ||||
| -rw-r--r-- | drivers/gpu/drm/omapdrm/dss/output.c | 53 | ||||
| -rw-r--r-- | drivers/gpu/drm/omapdrm/dss/sdi.c | 178 | ||||
| -rw-r--r-- | drivers/gpu/drm/omapdrm/dss/venc.c | 269 | 
19 files changed, 909 insertions, 867 deletions
| diff --git a/drivers/gpu/drm/omapdrm/dss/Makefile b/drivers/gpu/drm/omapdrm/dss/Makefile index 5950c3f52c2e..f967e6948f2e 100644 --- a/drivers/gpu/drm/omapdrm/dss/Makefile +++ b/drivers/gpu/drm/omapdrm/dss/Makefile @@ -2,7 +2,7 @@  obj-$(CONFIG_OMAP2_DSS_INIT) += omapdss-boot-init.o  obj-$(CONFIG_OMAP_DSS_BASE) += omapdss-base.o -omapdss-base-y := base.o display.o dss-of.o output.o +omapdss-base-y := base.o display.o output.o  obj-$(CONFIG_OMAP2_DSS) += omapdss.o  # Core DSS files diff --git a/drivers/gpu/drm/omapdrm/dss/base.c b/drivers/gpu/drm/omapdrm/dss/base.c index a1970b9db6ab..c7650a7c155d 100644 --- a/drivers/gpu/drm/omapdrm/dss/base.c +++ b/drivers/gpu/drm/omapdrm/dss/base.c @@ -149,8 +149,7 @@ struct omap_dss_device *omapdss_device_next_output(struct omap_dss_device *from)  			goto done;  		} -		if (dssdev->id && -		    (dssdev->next || dssdev->bridge || dssdev->panel)) +		if (dssdev->id && (dssdev->next || dssdev->bridge))  			goto done;  	} @@ -185,11 +184,10 @@ int omapdss_device_connect(struct dss_device *dss,  	if (!dst) {  		/*  		 * The destination is NULL when the source is connected to a -		 * bridge or panel instead of a DSS device. Stop here, we will -		 * attach the bridge or panel later when we will have a DRM -		 * encoder. +		 * bridge instead of a DSS device. Stop here, we will attach +		 * the bridge later when we will have a DRM encoder.  		 */ -		return src && (src->bridge || src->panel) ? 0 : -EINVAL; +		return src && src->bridge ? 0 : -EINVAL;  	}  	if (omapdss_device_is_connected(dst)) @@ -197,10 +195,12 @@ int omapdss_device_connect(struct dss_device *dss,  	dst->dss = dss; -	ret = dst->ops->connect(src, dst); -	if (ret < 0) { -		dst->dss = NULL; -		return ret; +	if (dst->ops && dst->ops->connect) { +		ret = dst->ops->connect(src, dst); +		if (ret < 0) { +			dst->dss = NULL; +			return ret; +		}  	}  	return 0; @@ -217,7 +217,7 @@ void omapdss_device_disconnect(struct omap_dss_device *src,  		dst ? dev_name(dst->dev) : "NULL");  	if (!dst) { -		WARN_ON(!src->bridge && !src->panel); +		WARN_ON(!src->bridge);  		return;  	} @@ -228,29 +228,18 @@ void omapdss_device_disconnect(struct omap_dss_device *src,  	WARN_ON(dst->state != OMAP_DSS_DISPLAY_DISABLED); -	dst->ops->disconnect(src, dst); +	if (dst->ops && dst->ops->disconnect) +		dst->ops->disconnect(src, dst);  	dst->dss = NULL;  }  EXPORT_SYMBOL_GPL(omapdss_device_disconnect); -void omapdss_device_pre_enable(struct omap_dss_device *dssdev) -{ -	if (!dssdev) -		return; - -	omapdss_device_pre_enable(dssdev->next); - -	if (dssdev->ops->pre_enable) -		dssdev->ops->pre_enable(dssdev); -} -EXPORT_SYMBOL_GPL(omapdss_device_pre_enable); -  void omapdss_device_enable(struct omap_dss_device *dssdev)  {  	if (!dssdev)  		return; -	if (dssdev->ops->enable) +	if (dssdev->ops && dssdev->ops->enable)  		dssdev->ops->enable(dssdev);  	omapdss_device_enable(dssdev->next); @@ -266,25 +255,11 @@ void omapdss_device_disable(struct omap_dss_device *dssdev)  	omapdss_device_disable(dssdev->next); -	if (dssdev->ops->disable) +	if (dssdev->ops && dssdev->ops->disable)  		dssdev->ops->disable(dssdev);  }  EXPORT_SYMBOL_GPL(omapdss_device_disable); -void omapdss_device_post_disable(struct omap_dss_device *dssdev) -{ -	if (!dssdev) -		return; - -	if (dssdev->ops->post_disable) -		dssdev->ops->post_disable(dssdev); - -	omapdss_device_post_disable(dssdev->next); - -	dssdev->state = OMAP_DSS_DISPLAY_DISABLED; -} -EXPORT_SYMBOL_GPL(omapdss_device_post_disable); -  /* -----------------------------------------------------------------------------   * Components Handling   */ diff --git a/drivers/gpu/drm/omapdrm/dss/display.c b/drivers/gpu/drm/omapdrm/dss/display.c index 8a3f61f5825f..3b82158b1bfd 100644 --- a/drivers/gpu/drm/omapdrm/dss/display.c +++ b/drivers/gpu/drm/omapdrm/dss/display.c @@ -40,15 +40,6 @@ void omapdss_display_init(struct omap_dss_device *dssdev)  }  EXPORT_SYMBOL_GPL(omapdss_display_init); -struct omap_dss_device *omapdss_display_get(struct omap_dss_device *output) -{ -	while (output->next) -		output = output->next; - -	return omapdss_device_get(output); -} -EXPORT_SYMBOL_GPL(omapdss_display_get); -  int omapdss_display_get_modes(struct drm_connector *connector,  			      const struct videomode *vm)  { diff --git a/drivers/gpu/drm/omapdrm/dss/dpi.c b/drivers/gpu/drm/omapdrm/dss/dpi.c index 95147437b990..5110acb0c6c1 100644 --- a/drivers/gpu/drm/omapdrm/dss/dpi.c +++ b/drivers/gpu/drm/omapdrm/dss/dpi.c @@ -9,20 +9,22 @@  #define DSS_SUBSYS_NAME "DPI" -#include <linux/kernel.h> +#include <linux/clk.h>  #include <linux/delay.h> -#include <linux/export.h>  #include <linux/err.h>  #include <linux/errno.h> +#include <linux/export.h> +#include <linux/kernel.h> +#include <linux/of.h>  #include <linux/platform_device.h>  #include <linux/regulator/consumer.h>  #include <linux/string.h> -#include <linux/of.h> -#include <linux/clk.h>  #include <linux/sys_soc.h> -#include "omapdss.h" +#include <drm/drm_bridge.h> +  #include "dss.h" +#include "omapdss.h"  struct dpi_data {  	struct platform_device *pdev; @@ -34,19 +36,19 @@ struct dpi_data {  	enum dss_clk_source clk_src;  	struct dss_pll *pll; -	struct mutex lock; -  	struct dss_lcd_mgr_config mgr_config;  	unsigned long pixelclock;  	int data_lines;  	struct omap_dss_device output; +	struct drm_bridge bridge;  }; -static struct dpi_data *dpi_get_data_from_dssdev(struct omap_dss_device *dssdev) -{ -	return container_of(dssdev, struct dpi_data, output); -} +#define drm_bridge_to_dpi(bridge) container_of(bridge, struct dpi_data, bridge) + +/* ----------------------------------------------------------------------------- + * Clock Handling and PLL + */  static enum dss_clk_source dpi_get_clk_src_dra7xx(struct dpi_data *dpi,  						  enum omap_channel channel) @@ -283,9 +285,7 @@ static bool dpi_dss_clk_calc(struct dpi_data *dpi, unsigned long pck, -static int dpi_set_pll_clk(struct dpi_data *dpi, enum omap_channel channel, -		unsigned long pck_req, unsigned long *fck, int *lck_div, -		int *pck_div) +static int dpi_set_pll_clk(struct dpi_data *dpi, unsigned long pck_req)  {  	struct dpi_clk_calc_ctx ctx;  	int r; @@ -299,19 +299,15 @@ static int dpi_set_pll_clk(struct dpi_data *dpi, enum omap_channel channel,  	if (r)  		return r; -	dss_select_lcd_clk_source(dpi->dss, channel, dpi->clk_src); +	dss_select_lcd_clk_source(dpi->dss, dpi->output.dispc_channel, +				  dpi->clk_src);  	dpi->mgr_config.clock_info = ctx.dispc_cinfo; -	*fck = ctx.pll_cinfo.clkout[ctx.clkout_idx]; -	*lck_div = ctx.dispc_cinfo.lck_div; -	*pck_div = ctx.dispc_cinfo.pck_div; -  	return 0;  } -static int dpi_set_dispc_clk(struct dpi_data *dpi, unsigned long pck_req, -		unsigned long *fck, int *lck_div, int *pck_div) +static int dpi_set_dispc_clk(struct dpi_data *dpi, unsigned long pck_req)  {  	struct dpi_clk_calc_ctx ctx;  	int r; @@ -327,29 +323,19 @@ static int dpi_set_dispc_clk(struct dpi_data *dpi, unsigned long pck_req,  	dpi->mgr_config.clock_info = ctx.dispc_cinfo; -	*fck = ctx.fck; -	*lck_div = ctx.dispc_cinfo.lck_div; -	*pck_div = ctx.dispc_cinfo.pck_div; -  	return 0;  }  static int dpi_set_mode(struct dpi_data *dpi)  { -	int lck_div = 0, pck_div = 0; -	unsigned long fck = 0; -	int r = 0; +	int r;  	if (dpi->pll) -		r = dpi_set_pll_clk(dpi, dpi->output.dispc_channel, -				    dpi->pixelclock, &fck, &lck_div, &pck_div); +		r = dpi_set_pll_clk(dpi, dpi->pixelclock);  	else -		r = dpi_set_dispc_clk(dpi, dpi->pixelclock, &fck, -				&lck_div, &pck_div); -	if (r) -		return r; +		r = dpi_set_dispc_clk(dpi, dpi->pixelclock); -	return 0; +	return r;  }  static void dpi_config_lcd_manager(struct dpi_data *dpi) @@ -366,25 +352,149 @@ static void dpi_config_lcd_manager(struct dpi_data *dpi)  	dss_mgr_set_lcd_config(&dpi->output, &dpi->mgr_config);  } -static void dpi_display_enable(struct omap_dss_device *dssdev) +static int dpi_clock_update(struct dpi_data *dpi, unsigned long *clock) +{ +	int lck_div, pck_div; +	unsigned long fck; +	struct dpi_clk_calc_ctx ctx; + +	if (dpi->pll) { +		if (!dpi_pll_clk_calc(dpi, *clock, &ctx)) +			return -EINVAL; + +		fck = ctx.pll_cinfo.clkout[ctx.clkout_idx]; +	} else { +		if (!dpi_dss_clk_calc(dpi, *clock, &ctx)) +			return -EINVAL; + +		fck = ctx.fck; +	} + +	lck_div = ctx.dispc_cinfo.lck_div; +	pck_div = ctx.dispc_cinfo.pck_div; + +	*clock = fck / lck_div / pck_div; + +	return 0; +} + +static int dpi_verify_pll(struct dss_pll *pll)  { -	struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev); -	struct omap_dss_device *out = &dpi->output;  	int r; -	mutex_lock(&dpi->lock); +	/* do initial setup with the PLL to see if it is operational */ + +	r = dss_pll_enable(pll); +	if (r) +		return r; + +	dss_pll_disable(pll); + +	return 0; +} + +static void dpi_init_pll(struct dpi_data *dpi) +{ +	struct dss_pll *pll; + +	if (dpi->pll) +		return; + +	dpi->clk_src = dpi_get_clk_src(dpi); + +	pll = dss_pll_find_by_src(dpi->dss, dpi->clk_src); +	if (!pll) +		return; + +	if (dpi_verify_pll(pll)) { +		DSSWARN("PLL not operational\n"); +		return; +	} + +	dpi->pll = pll; +} + +/* ----------------------------------------------------------------------------- + * DRM Bridge Operations + */ + +static int dpi_bridge_attach(struct drm_bridge *bridge, +			     enum drm_bridge_attach_flags flags) +{ +	struct dpi_data *dpi = drm_bridge_to_dpi(bridge); + +	if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) +		return -EINVAL; + +	dpi_init_pll(dpi); + +	return drm_bridge_attach(bridge->encoder, dpi->output.next_bridge, +				 bridge, flags); +} + +static enum drm_mode_status +dpi_bridge_mode_valid(struct drm_bridge *bridge, +		       const struct drm_display_mode *mode) +{ +	struct dpi_data *dpi = drm_bridge_to_dpi(bridge); +	unsigned long clock = mode->clock * 1000; +	int ret; + +	if (mode->hdisplay % 8 != 0) +		return MODE_BAD_WIDTH; + +	if (mode->clock == 0) +		return MODE_NOCLOCK; + +	ret = dpi_clock_update(dpi, &clock); +	if (ret < 0) +		return MODE_CLOCK_RANGE; + +	return MODE_OK; +} + +static bool dpi_bridge_mode_fixup(struct drm_bridge *bridge, +				   const struct drm_display_mode *mode, +				   struct drm_display_mode *adjusted_mode) +{ +	struct dpi_data *dpi = drm_bridge_to_dpi(bridge); +	unsigned long clock = mode->clock * 1000; +	int ret; + +	ret = dpi_clock_update(dpi, &clock); +	if (ret < 0) +		return false; + +	adjusted_mode->clock = clock / 1000; + +	return true; +} + +static void dpi_bridge_mode_set(struct drm_bridge *bridge, +				 const struct drm_display_mode *mode, +				 const struct drm_display_mode *adjusted_mode) +{ +	struct dpi_data *dpi = drm_bridge_to_dpi(bridge); + +	dpi->pixelclock = adjusted_mode->clock * 1000; +} + +static void dpi_bridge_enable(struct drm_bridge *bridge) +{ +	struct dpi_data *dpi = drm_bridge_to_dpi(bridge); +	int r;  	if (dpi->vdds_dsi_reg) {  		r = regulator_enable(dpi->vdds_dsi_reg);  		if (r) -			goto err_reg_enable; +			return;  	}  	r = dispc_runtime_get(dpi->dss->dispc);  	if (r)  		goto err_get_dispc; -	r = dss_dpi_select_source(dpi->dss, dpi->id, out->dispc_channel); +	r = dss_dpi_select_source(dpi->dss, dpi->id, dpi->output.dispc_channel);  	if (r)  		goto err_src_sel; @@ -406,8 +516,6 @@ static void dpi_display_enable(struct omap_dss_device *dssdev)  	if (r)  		goto err_mgr_enable; -	mutex_unlock(&dpi->lock); -  	return;  err_mgr_enable: @@ -420,15 +528,11 @@ err_src_sel:  err_get_dispc:  	if (dpi->vdds_dsi_reg)  		regulator_disable(dpi->vdds_dsi_reg); -err_reg_enable: -	mutex_unlock(&dpi->lock);  } -static void dpi_display_disable(struct omap_dss_device *dssdev) +static void dpi_bridge_disable(struct drm_bridge *bridge)  { -	struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev); - -	mutex_lock(&dpi->lock); +	struct dpi_data *dpi = drm_bridge_to_dpi(bridge);  	dss_mgr_disable(&dpi->output); @@ -442,99 +546,34 @@ static void dpi_display_disable(struct omap_dss_device *dssdev)  	if (dpi->vdds_dsi_reg)  		regulator_disable(dpi->vdds_dsi_reg); - -	mutex_unlock(&dpi->lock);  } -static void dpi_set_timings(struct omap_dss_device *dssdev, -			    const struct drm_display_mode *mode) -{ -	struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev); - -	DSSDBG("dpi_set_timings\n"); - -	mutex_lock(&dpi->lock); - -	dpi->pixelclock = mode->clock * 1000; - -	mutex_unlock(&dpi->lock); -} +static const struct drm_bridge_funcs dpi_bridge_funcs = { +	.attach = dpi_bridge_attach, +	.mode_valid = dpi_bridge_mode_valid, +	.mode_fixup = dpi_bridge_mode_fixup, +	.mode_set = dpi_bridge_mode_set, +	.enable = dpi_bridge_enable, +	.disable = dpi_bridge_disable, +}; -static int dpi_check_timings(struct omap_dss_device *dssdev, -			     struct drm_display_mode *mode) +static void dpi_bridge_init(struct dpi_data *dpi)  { -	struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev); -	int lck_div, pck_div; -	unsigned long fck; -	unsigned long pck; -	struct dpi_clk_calc_ctx ctx; -	bool ok; +	dpi->bridge.funcs = &dpi_bridge_funcs; +	dpi->bridge.of_node = dpi->pdev->dev.of_node; +	dpi->bridge.type = DRM_MODE_CONNECTOR_DPI; -	if (mode->hdisplay % 8 != 0) -		return -EINVAL; - -	if (mode->clock == 0) -		return -EINVAL; - -	if (dpi->pll) { -		ok = dpi_pll_clk_calc(dpi, mode->clock * 1000, &ctx); -		if (!ok) -			return -EINVAL; - -		fck = ctx.pll_cinfo.clkout[ctx.clkout_idx]; -	} else { -		ok = dpi_dss_clk_calc(dpi, mode->clock * 1000, &ctx); -		if (!ok) -			return -EINVAL; - -		fck = ctx.fck; -	} - -	lck_div = ctx.dispc_cinfo.lck_div; -	pck_div = ctx.dispc_cinfo.pck_div; - -	pck = fck / lck_div / pck_div; - -	mode->clock = pck / 1000; - -	return 0; +	drm_bridge_add(&dpi->bridge);  } -static int dpi_verify_pll(struct dss_pll *pll) +static void dpi_bridge_cleanup(struct dpi_data *dpi)  { -	int r; - -	/* do initial setup with the PLL to see if it is operational */ - -	r = dss_pll_enable(pll); -	if (r) -		return r; - -	dss_pll_disable(pll); - -	return 0; +	drm_bridge_remove(&dpi->bridge);  } -static void dpi_init_pll(struct dpi_data *dpi) -{ -	struct dss_pll *pll; - -	if (dpi->pll) -		return; - -	dpi->clk_src = dpi_get_clk_src(dpi); - -	pll = dss_pll_find_by_src(dpi->dss, dpi->clk_src); -	if (!pll) -		return; - -	if (dpi_verify_pll(pll)) { -		DSSWARN("PLL not operational\n"); -		return; -	} - -	dpi->pll = pll; -} +/* ----------------------------------------------------------------------------- + * Initialisation and Cleanup + */  /*   * Return a hardcoded channel for the DPI output. This should work for @@ -572,39 +611,14 @@ static enum omap_channel dpi_get_channel(struct dpi_data *dpi)  	}  } -static int dpi_connect(struct omap_dss_device *src, -		       struct omap_dss_device *dst) -{ -	struct dpi_data *dpi = dpi_get_data_from_dssdev(dst); - -	dpi_init_pll(dpi); - -	return omapdss_device_connect(dst->dss, dst, dst->next); -} - -static void dpi_disconnect(struct omap_dss_device *src, -			   struct omap_dss_device *dst) -{ -	omapdss_device_disconnect(dst, dst->next); -} - -static const struct omap_dss_device_ops dpi_ops = { -	.connect = dpi_connect, -	.disconnect = dpi_disconnect, - -	.enable = dpi_display_enable, -	.disable = dpi_display_disable, - -	.check_timings = dpi_check_timings, -	.set_timings = dpi_set_timings, -}; -  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; +	dpi_bridge_init(dpi); +  	of_property_read_u32(port, "reg", &port_num);  	dpi->id = port_num <= 2 ? port_num : 0; @@ -625,13 +639,14 @@ static int dpi_init_output_port(struct dpi_data *dpi, struct device_node *port)  	out->id = OMAP_DSS_OUTPUT_DPI;  	out->type = OMAP_DISPLAY_TYPE_DPI;  	out->dispc_channel = dpi_get_channel(dpi); -	out->of_ports = BIT(port_num); -	out->ops = &dpi_ops; +	out->of_port = port_num;  	out->owner = THIS_MODULE; -	r = omapdss_device_init_output(out); -	if (r < 0) +	r = omapdss_device_init_output(out, &dpi->bridge); +	if (r < 0) { +		dpi_bridge_cleanup(dpi);  		return r; +	}  	omapdss_device_register(out); @@ -645,8 +660,14 @@ static void dpi_uninit_output_port(struct device_node *port)  	omapdss_device_unregister(out);  	omapdss_device_cleanup_output(out); + +	dpi_bridge_cleanup(dpi);  } +/* ----------------------------------------------------------------------------- + * Initialisation and Cleanup + */ +  static const struct soc_device_attribute dpi_soc_devices[] = {  	{ .machine = "OMAP3[456]*" },  	{ .machine = "[AD]M37*" }, @@ -706,8 +727,6 @@ int dpi_init_port(struct dss_device *dss, struct platform_device *pdev,  	dpi->dss = dss;  	port->data = dpi; -	mutex_init(&dpi->lock); -  	r = dpi_init_regulator(dpi);  	if (r)  		return r; diff --git a/drivers/gpu/drm/omapdrm/dss/dsi.c b/drivers/gpu/drm/omapdrm/dss/dsi.c index da16ea095f13..79ddfbfd1b58 100644 --- a/drivers/gpu/drm/omapdrm/dss/dsi.c +++ b/drivers/gpu/drm/omapdrm/dss/dsi.c @@ -5116,12 +5116,12 @@ static int dsi_init_output(struct dsi_data *dsi)  	out->dispc_channel = dsi_get_channel(dsi);  	out->ops = &dsi_ops;  	out->owner = THIS_MODULE; -	out->of_ports = BIT(0); +	out->of_port = 0;  	out->bus_flags = DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE  		       | DRM_BUS_FLAG_DE_HIGH  		       | DRM_BUS_FLAG_SYNC_DRIVE_NEGEDGE; -	r = omapdss_device_init_output(out); +	r = omapdss_device_init_output(out, NULL);  	if (r < 0)  		return r; diff --git a/drivers/gpu/drm/omapdrm/dss/dss-of.c b/drivers/gpu/drm/omapdrm/dss/dss-of.c deleted file mode 100644 index b7981f3b80ad..000000000000 --- a/drivers/gpu/drm/omapdrm/dss/dss-of.c +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/ - * Author: Tomi Valkeinen <[email protected]> - */ - -#include <linux/err.h> -#include <linux/of.h> -#include <linux/of_graph.h> - -#include "omapdss.h" - -struct omap_dss_device * -omapdss_of_find_connected_device(struct device_node *node, unsigned int port) -{ -	struct device_node *remote_node; -	struct omap_dss_device *dssdev; - -	remote_node = of_graph_get_remote_node(node, port, 0); -	if (!remote_node) -		return NULL; - -	dssdev = omapdss_find_device_by_node(remote_node); -	of_node_put(remote_node); - -	return dssdev ? dssdev : ERR_PTR(-EPROBE_DEFER); -} -EXPORT_SYMBOL_GPL(omapdss_of_find_connected_device); diff --git a/drivers/gpu/drm/omapdrm/dss/dss.c b/drivers/gpu/drm/omapdrm/dss/dss.c index 225ec808b01a..b76fc2b56227 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss.c +++ b/drivers/gpu/drm/omapdrm/dss/dss.c @@ -1151,46 +1151,38 @@ static const struct dss_features dra7xx_dss_feats = {  	.has_lcd_clk_src	=	true,  }; -static int dss_init_ports(struct dss_device *dss) +static void __dss_uninit_ports(struct dss_device *dss, unsigned int num_ports)  {  	struct platform_device *pdev = dss->pdev;  	struct device_node *parent = pdev->dev.of_node;  	struct device_node *port;  	unsigned int i; -	int r; -	for (i = 0; i < dss->feat->num_ports; i++) { +	for (i = 0; i < num_ports; i++) {  		port = of_graph_get_port_by_id(parent, i);  		if (!port)  			continue;  		switch (dss->feat->ports[i]) {  		case OMAP_DISPLAY_TYPE_DPI: -			r = dpi_init_port(dss, pdev, port, dss->feat->model); -			if (r) -				return r; +			dpi_uninit_port(port);  			break; -  		case OMAP_DISPLAY_TYPE_SDI: -			r = sdi_init_port(dss, pdev, port); -			if (r) -				return r; +			sdi_uninit_port(port);  			break; -  		default:  			break;  		}  	} - -	return 0;  } -static void dss_uninit_ports(struct dss_device *dss) +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); @@ -1199,15 +1191,32 @@ static void dss_uninit_ports(struct dss_device *dss)  		switch (dss->feat->ports[i]) {  		case OMAP_DISPLAY_TYPE_DPI: -			dpi_uninit_port(port); +			r = dpi_init_port(dss, pdev, port, dss->feat->model); +			if (r) +				goto error;  			break; +  		case OMAP_DISPLAY_TYPE_SDI: -			sdi_uninit_port(port); +			r = sdi_init_port(dss, pdev, port); +			if (r) +				goto error;  			break; +  		default:  			break;  		}  	} + +	return 0; + +error: +	__dss_uninit_ports(dss, i); +	return r; +} + +static void dss_uninit_ports(struct dss_device *dss) +{ +	__dss_uninit_ports(dss, dss->feat->num_ports);  }  static int dss_video_pll_probe(struct dss_device *dss) @@ -1543,7 +1552,8 @@ static void dss_shutdown(struct platform_device *pdev)  	DSSDBG("shutdown\n");  	for_each_dss_output(dssdev) { -		if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) +		if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE && +		    dssdev->ops && dssdev->ops->disable)  			dssdev->ops->disable(dssdev);  	}  } diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi.h b/drivers/gpu/drm/omapdrm/dss/hdmi.h index c867552c925c..3a40833d3368 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi.h +++ b/drivers/gpu/drm/omapdrm/dss/hdmi.h @@ -14,6 +14,7 @@  #include <linux/hdmi.h>  #include <sound/omap-hdmi-audio.h>  #include <media/cec.h> +#include <drm/drm_bridge.h>  #include "omapdss.h"  #include "dss.h" @@ -364,6 +365,7 @@ struct omap_hdmi {  	bool core_enabled;  	struct omap_dss_device output; +	struct drm_bridge bridge;  	struct platform_device *audio_pdev;  	void (*audio_abort_cb)(struct device *dev); @@ -378,6 +380,6 @@ struct omap_hdmi {  	bool display_enabled;  }; -#define dssdev_to_hdmi(dssdev) container_of(dssdev, struct omap_hdmi, output) +#define drm_bridge_to_hdmi(b) container_of(b, struct omap_hdmi, bridge)  #endif diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4.c b/drivers/gpu/drm/omapdrm/dss/hdmi4.c index 0f557fad4513..2578c95570f6 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi4.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi4.c @@ -28,6 +28,9 @@  #include <sound/omap-hdmi-audio.h>  #include <media/cec.h> +#include <drm/drm_atomic.h> +#include <drm/drm_atomic_state_helper.h> +  #include "omapdss.h"  #include "hdmi4_core.h"  #include "hdmi4_cec.h" @@ -237,20 +240,6 @@ static void hdmi_power_off_full(struct omap_hdmi *hdmi)  	hdmi_power_off_core(hdmi);  } -static void hdmi_display_set_timings(struct omap_dss_device *dssdev, -				     const struct drm_display_mode *mode) -{ -	struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); - -	mutex_lock(&hdmi->lock); - -	drm_display_mode_to_videomode(mode, &hdmi->cfg.vm); - -	dispc_set_tv_pclk(hdmi->dss->dispc, mode->clock * 1000); - -	mutex_unlock(&hdmi->lock); -} -  static int hdmi_dump_regs(struct seq_file *s, void *p)  {  	struct omap_hdmi *hdmi = s->private; @@ -272,57 +261,139 @@ static int hdmi_dump_regs(struct seq_file *s, void *p)  	return 0;  } -static int read_edid(struct omap_hdmi *hdmi, u8 *buf, int len) +static void hdmi_start_audio_stream(struct omap_hdmi *hd)  { -	int r; +	hdmi_wp_audio_enable(&hd->wp, true); +	hdmi4_audio_start(&hd->core, &hd->wp); +} -	mutex_lock(&hdmi->lock); +static void hdmi_stop_audio_stream(struct omap_hdmi *hd) +{ +	hdmi4_audio_stop(&hd->core, &hd->wp); +	hdmi_wp_audio_enable(&hd->wp, false); +} -	r = hdmi_runtime_get(hdmi); -	BUG_ON(r); +int hdmi4_core_enable(struct hdmi_core_data *core) +{ +	struct omap_hdmi *hdmi = container_of(core, struct omap_hdmi, core); +	int r = 0; -	r = hdmi4_read_edid(&hdmi->core,  buf, len); +	DSSDBG("ENTER omapdss_hdmi4_core_enable\n"); + +	mutex_lock(&hdmi->lock); + +	r = hdmi_power_on_core(hdmi); +	if (r) { +		DSSERR("failed to power on device\n"); +		goto err0; +	} -	hdmi_runtime_put(hdmi);  	mutex_unlock(&hdmi->lock); +	return 0; +err0: +	mutex_unlock(&hdmi->lock);  	return r;  } -static void hdmi_start_audio_stream(struct omap_hdmi *hd) +void hdmi4_core_disable(struct hdmi_core_data *core)  { -	hdmi_wp_audio_enable(&hd->wp, true); -	hdmi4_audio_start(&hd->core, &hd->wp); +	struct omap_hdmi *hdmi = container_of(core, struct omap_hdmi, core); + +	DSSDBG("Enter omapdss_hdmi4_core_disable\n"); + +	mutex_lock(&hdmi->lock); + +	hdmi_power_off_core(hdmi); + +	mutex_unlock(&hdmi->lock);  } -static void hdmi_stop_audio_stream(struct omap_hdmi *hd) +/* ----------------------------------------------------------------------------- + * DRM Bridge Operations + */ + +static int hdmi4_bridge_attach(struct drm_bridge *bridge, +			       enum drm_bridge_attach_flags flags)  { -	hdmi4_audio_stop(&hd->core, &hd->wp); -	hdmi_wp_audio_enable(&hd->wp, false); +	struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge); + +	if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) +		return -EINVAL; + +	return drm_bridge_attach(bridge->encoder, hdmi->output.next_bridge, +				 bridge, flags);  } -static void hdmi_display_enable(struct omap_dss_device *dssdev) +static void hdmi4_bridge_mode_set(struct drm_bridge *bridge, +				  const struct drm_display_mode *mode, +				  const struct drm_display_mode *adjusted_mode)  { -	struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); +	struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge); + +	mutex_lock(&hdmi->lock); + +	drm_display_mode_to_videomode(adjusted_mode, &hdmi->cfg.vm); + +	dispc_set_tv_pclk(hdmi->dss->dispc, adjusted_mode->clock * 1000); + +	mutex_unlock(&hdmi->lock); +} + +static void hdmi4_bridge_enable(struct drm_bridge *bridge, +				struct drm_bridge_state *bridge_state) +{ +	struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge); +	struct drm_atomic_state *state = bridge_state->base.state; +	struct drm_connector_state *conn_state; +	struct drm_connector *connector; +	struct drm_crtc_state *crtc_state;  	unsigned long flags; -	int r; +	int ret; + +	/* +	 * None of these should fail, as the bridge can't be enabled without a +	 * valid CRTC to connector path with fully populated new states. +	 */ +	connector = drm_atomic_get_new_connector_for_encoder(state, +							     bridge->encoder); +	if (WARN_ON(!connector)) +		return; +	conn_state = drm_atomic_get_new_connector_state(state, connector); +	if (WARN_ON(!conn_state)) +		return; +	crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc); +	if (WARN_ON(!crtc_state)) +		return; + +	hdmi->cfg.hdmi_dvi_mode = connector->display_info.is_hdmi +				? HDMI_HDMI : HDMI_DVI; -	DSSDBG("ENTER hdmi_display_enable\n"); +	if (connector->display_info.is_hdmi) { +		const struct drm_display_mode *mode; +		struct hdmi_avi_infoframe avi; + +		mode = &crtc_state->adjusted_mode; +		ret = drm_hdmi_avi_infoframe_from_display_mode(&avi, connector, +							       mode); +		if (ret == 0) +			hdmi->cfg.infoframe = avi; +	}  	mutex_lock(&hdmi->lock); -	r = hdmi_power_on_full(hdmi); -	if (r) { +	ret = hdmi_power_on_full(hdmi); +	if (ret) {  		DSSERR("failed to power on device\n");  		goto done;  	}  	if (hdmi->audio_configured) { -		r = hdmi4_audio_config(&hdmi->core, &hdmi->wp, -				       &hdmi->audio_config, -				       hdmi->cfg.vm.pixelclock); -		if (r) { -			DSSERR("Error restoring audio configuration: %d", r); +		ret = hdmi4_audio_config(&hdmi->core, &hdmi->wp, +					 &hdmi->audio_config, +					 hdmi->cfg.vm.pixelclock); +		if (ret) { +			DSSERR("Error restoring audio configuration: %d", ret);  			hdmi->audio_abort_cb(&hdmi->pdev->dev);  			hdmi->audio_configured = false;  		} @@ -338,13 +409,12 @@ done:  	mutex_unlock(&hdmi->lock);  } -static void hdmi_display_disable(struct omap_dss_device *dssdev) +static void hdmi4_bridge_disable(struct drm_bridge *bridge, +				 struct drm_bridge_state *bridge_state)  { -	struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); +	struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge);  	unsigned long flags; -	DSSDBG("Enter hdmi_display_disable\n"); -  	mutex_lock(&hdmi->lock);  	spin_lock_irqsave(&hdmi->audio_playing_lock, flags); @@ -357,58 +427,21 @@ static void hdmi_display_disable(struct omap_dss_device *dssdev)  	mutex_unlock(&hdmi->lock);  } -int hdmi4_core_enable(struct hdmi_core_data *core) +static void hdmi4_bridge_hpd_notify(struct drm_bridge *bridge, +				    enum drm_connector_status status)  { -	struct omap_hdmi *hdmi = container_of(core, struct omap_hdmi, core); -	int r = 0; - -	DSSDBG("ENTER omapdss_hdmi4_core_enable\n"); - -	mutex_lock(&hdmi->lock); - -	r = hdmi_power_on_core(hdmi); -	if (r) { -		DSSERR("failed to power on device\n"); -		goto err0; -	} - -	mutex_unlock(&hdmi->lock); -	return 0; - -err0: -	mutex_unlock(&hdmi->lock); -	return r; -} - -void hdmi4_core_disable(struct hdmi_core_data *core) -{ -	struct omap_hdmi *hdmi = container_of(core, struct omap_hdmi, core); - -	DSSDBG("Enter omapdss_hdmi4_core_disable\n"); - -	mutex_lock(&hdmi->lock); - -	hdmi_power_off_core(hdmi); - -	mutex_unlock(&hdmi->lock); -} - -static int hdmi_connect(struct omap_dss_device *src, -			struct omap_dss_device *dst) -{ -	return omapdss_device_connect(dst->dss, dst, dst->next); -} +	struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge); -static void hdmi_disconnect(struct omap_dss_device *src, -			    struct omap_dss_device *dst) -{ -	omapdss_device_disconnect(dst, dst->next); +	if (status == connector_status_disconnected) +		hdmi4_cec_set_phys_addr(&hdmi->core, CEC_PHYS_ADDR_INVALID);  } -static int hdmi_read_edid(struct omap_dss_device *dssdev, -		u8 *edid, int len) +static struct edid *hdmi4_bridge_get_edid(struct drm_bridge *bridge, +					  struct drm_connector *connector)  { -	struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); +	struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge); +	struct edid *edid = NULL; +	unsigned int cec_addr;  	bool need_enable;  	int r; @@ -417,63 +450,65 @@ static int hdmi_read_edid(struct omap_dss_device *dssdev,  	if (need_enable) {  		r = hdmi4_core_enable(&hdmi->core);  		if (r) -			return r; +			return NULL;  	} -	r = read_edid(hdmi, edid, len); -	if (r >= 256) -		hdmi4_cec_set_phys_addr(&hdmi->core, -					cec_get_edid_phys_addr(edid, r, NULL)); -	else -		hdmi4_cec_set_phys_addr(&hdmi->core, CEC_PHYS_ADDR_INVALID); -	if (need_enable) -		hdmi4_core_disable(&hdmi->core); +	mutex_lock(&hdmi->lock); +	r = hdmi_runtime_get(hdmi); +	BUG_ON(r); -	return r; -} +	r = hdmi4_core_ddc_init(&hdmi->core); +	if (r) +		goto done; -static void hdmi_lost_hotplug(struct omap_dss_device *dssdev) -{ -	struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); +	edid = drm_do_get_edid(connector, hdmi4_core_ddc_read, &hdmi->core); -	hdmi4_cec_set_phys_addr(&hdmi->core, CEC_PHYS_ADDR_INVALID); -} +done: +	hdmi_runtime_put(hdmi); +	mutex_unlock(&hdmi->lock); -static int hdmi_set_infoframe(struct omap_dss_device *dssdev, -		const struct hdmi_avi_infoframe *avi) -{ -	struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); +	if (edid && edid->extensions) { +		unsigned int len = (edid->extensions + 1) * EDID_LENGTH; -	hdmi->cfg.infoframe = *avi; -	return 0; -} +		cec_addr = cec_get_edid_phys_addr((u8 *)edid, len, NULL); +	} else { +		cec_addr = CEC_PHYS_ADDR_INVALID; +	} -static int hdmi_set_hdmi_mode(struct omap_dss_device *dssdev, -		bool hdmi_mode) -{ -	struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); +	hdmi4_cec_set_phys_addr(&hdmi->core, cec_addr); -	hdmi->cfg.hdmi_dvi_mode = hdmi_mode ? HDMI_HDMI : HDMI_DVI; -	return 0; -} +	if (need_enable) +		hdmi4_core_disable(&hdmi->core); -static const struct omap_dss_device_ops hdmi_ops = { -	.connect		= hdmi_connect, -	.disconnect		= hdmi_disconnect, +	return edid; +} -	.enable			= hdmi_display_enable, -	.disable		= hdmi_display_disable, +static const struct drm_bridge_funcs hdmi4_bridge_funcs = { +	.attach = hdmi4_bridge_attach, +	.mode_set = hdmi4_bridge_mode_set, +	.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, +	.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, +	.atomic_reset = drm_atomic_helper_bridge_reset, +	.atomic_enable = hdmi4_bridge_enable, +	.atomic_disable = hdmi4_bridge_disable, +	.hpd_notify = hdmi4_bridge_hpd_notify, +	.get_edid = hdmi4_bridge_get_edid, +}; -	.set_timings		= hdmi_display_set_timings, +static void hdmi4_bridge_init(struct omap_hdmi *hdmi) +{ +	hdmi->bridge.funcs = &hdmi4_bridge_funcs; +	hdmi->bridge.of_node = hdmi->pdev->dev.of_node; +	hdmi->bridge.ops = DRM_BRIDGE_OP_EDID; +	hdmi->bridge.type = DRM_MODE_CONNECTOR_HDMIA; -	.read_edid		= hdmi_read_edid, +	drm_bridge_add(&hdmi->bridge); +} -	.hdmi = { -		.lost_hotplug		= hdmi_lost_hotplug, -		.set_infoframe		= hdmi_set_infoframe, -		.set_hdmi_mode		= hdmi_set_hdmi_mode, -	}, -}; +static void hdmi4_bridge_cleanup(struct omap_hdmi *hdmi) +{ +	drm_bridge_remove(&hdmi->bridge); +}  /* -----------------------------------------------------------------------------   * Audio Callbacks @@ -666,19 +701,21 @@ static int hdmi4_init_output(struct omap_hdmi *hdmi)  	struct omap_dss_device *out = &hdmi->output;  	int r; +	hdmi4_bridge_init(hdmi); +  	out->dev = &hdmi->pdev->dev;  	out->id = OMAP_DSS_OUTPUT_HDMI;  	out->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->of_port = 0; -	r = omapdss_device_init_output(out); -	if (r < 0) +	r = omapdss_device_init_output(out, &hdmi->bridge); +	if (r < 0) { +		hdmi4_bridge_cleanup(hdmi);  		return r; +	}  	omapdss_device_register(out); @@ -691,6 +728,8 @@ static void hdmi4_uninit_output(struct omap_hdmi *hdmi)  	omapdss_device_unregister(out);  	omapdss_device_cleanup_output(out); + +	hdmi4_bridge_cleanup(hdmi);  }  static int hdmi4_probe_of(struct omap_hdmi *hdmi) diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4_core.c b/drivers/gpu/drm/omapdrm/dss/hdmi4_core.c index ea5d5c228534..751985a2679a 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi4_core.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi4_core.c @@ -32,7 +32,7 @@ static inline void __iomem *hdmi_av_base(struct hdmi_core_data *core)  	return core->base + HDMI_CORE_AV;  } -static int hdmi_core_ddc_init(struct hdmi_core_data *core) +int hdmi4_core_ddc_init(struct hdmi_core_data *core)  {  	void __iomem *base = core->base; @@ -74,13 +74,11 @@ static int hdmi_core_ddc_init(struct hdmi_core_data *core)  	return 0;  } -static int hdmi_core_ddc_edid(struct hdmi_core_data *core, -		u8 *pedid, int ext) +int hdmi4_core_ddc_read(void *data, u8 *buf, unsigned int block, size_t len)  { +	struct hdmi_core_data *core = data;  	void __iomem *base = core->base;  	u32 i; -	char checksum; -	u32 offset = 0;  	/* HDMI_CORE_DDC_STATUS_IN_PROG */  	if (hdmi_wait_for_bit_change(base, HDMI_CORE_DDC_STATUS, @@ -89,24 +87,21 @@ static int hdmi_core_ddc_edid(struct hdmi_core_data *core,  		return -ETIMEDOUT;  	} -	if (ext % 2 != 0) -		offset = 0x80; -  	/* Load Segment Address Register */ -	REG_FLD_MOD(base, HDMI_CORE_DDC_SEGM, ext / 2, 7, 0); +	REG_FLD_MOD(base, HDMI_CORE_DDC_SEGM, block / 2, 7, 0);  	/* Load Slave Address Register */  	REG_FLD_MOD(base, HDMI_CORE_DDC_ADDR, 0xA0 >> 1, 7, 1);  	/* Load Offset Address Register */ -	REG_FLD_MOD(base, HDMI_CORE_DDC_OFFSET, offset, 7, 0); +	REG_FLD_MOD(base, HDMI_CORE_DDC_OFFSET, block % 2 ? 0x80 : 0, 7, 0);  	/* Load Byte Count */ -	REG_FLD_MOD(base, HDMI_CORE_DDC_COUNT1, 0x80, 7, 0); +	REG_FLD_MOD(base, HDMI_CORE_DDC_COUNT1, len, 7, 0);  	REG_FLD_MOD(base, HDMI_CORE_DDC_COUNT2, 0x0, 1, 0);  	/* Set DDC_CMD */ -	if (ext) +	if (block)  		REG_FLD_MOD(base, HDMI_CORE_DDC_CMD, 0x4, 3, 0);  	else  		REG_FLD_MOD(base, HDMI_CORE_DDC_CMD, 0x2, 3, 0); @@ -122,7 +117,7 @@ static int hdmi_core_ddc_edid(struct hdmi_core_data *core,  		return -EIO;  	} -	for (i = 0; i < 0x80; ++i) { +	for (i = 0; i < len; ++i) {  		int t;  		/* IN_PROG */ @@ -141,48 +136,12 @@ static int hdmi_core_ddc_edid(struct hdmi_core_data *core,  			udelay(1);  		} -		pedid[i] = REG_GET(base, HDMI_CORE_DDC_DATA, 7, 0); -	} - -	checksum = 0; -	for (i = 0; i < 0x80; ++i) -		checksum += pedid[i]; - -	if (checksum != 0) { -		DSSERR("E-EDID checksum failed!!\n"); -		return -EIO; +		buf[i] = REG_GET(base, HDMI_CORE_DDC_DATA, 7, 0);  	}  	return 0;  } -int hdmi4_read_edid(struct hdmi_core_data *core, u8 *edid, int len) -{ -	int r, l; - -	if (len < 128) -		return -EINVAL; - -	r = hdmi_core_ddc_init(core); -	if (r) -		return r; - -	r = hdmi_core_ddc_edid(core, edid, 0); -	if (r) -		return r; - -	l = 128; - -	if (len >= 128 * 2 && edid[0x7e] > 0) { -		r = hdmi_core_ddc_edid(core, edid + 0x80, 1); -		if (r) -			return r; -		l += 128; -	} - -	return l; -} -  static void hdmi_core_init(struct hdmi_core_video_config *video_cfg)  {  	DSSDBG("Enter hdmi_core_init\n"); diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4_core.h b/drivers/gpu/drm/omapdrm/dss/hdmi4_core.h index 11c4b7ba1eee..dc64ae2aa300 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi4_core.h +++ b/drivers/gpu/drm/omapdrm/dss/hdmi4_core.h @@ -249,7 +249,9 @@ struct hdmi_core_packet_enable_repeat {  	u32	generic_pkt_repeat;  }; -int hdmi4_read_edid(struct hdmi_core_data *core, u8 *edid, int len); +int hdmi4_core_ddc_init(struct hdmi_core_data *core); +int hdmi4_core_ddc_read(void *data, u8 *buf, unsigned int block, size_t len); +  void hdmi4_configure(struct hdmi_core_data *core, struct hdmi_wp_data *wp,  		struct hdmi_config *cfg);  void hdmi4_core_dump(struct hdmi_core_data *core, struct seq_file *s); diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi5.c b/drivers/gpu/drm/omapdrm/dss/hdmi5.c index d9463b332554..4d4c1fabd0a1 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi5.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi5.c @@ -31,6 +31,9 @@  #include <linux/of_graph.h>  #include <sound/omap-hdmi-audio.h> +#include <drm/drm_atomic.h> +#include <drm/drm_atomic_state_helper.h> +  #include "omapdss.h"  #include "hdmi5_core.h"  #include "dss.h" @@ -236,20 +239,6 @@ static void hdmi_power_off_full(struct omap_hdmi *hdmi)  	hdmi_power_off_core(hdmi);  } -static void hdmi_display_set_timings(struct omap_dss_device *dssdev, -				     const struct drm_display_mode *mode) -{ -	struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); - -	mutex_lock(&hdmi->lock); - -	drm_display_mode_to_videomode(mode, &hdmi->cfg.vm); - -	dispc_set_tv_pclk(hdmi->dss->dispc, mode->clock * 1000); - -	mutex_unlock(&hdmi->lock); -} -  static int hdmi_dump_regs(struct seq_file *s, void *p)  {  	struct omap_hdmi *hdmi = s->private; @@ -271,66 +260,138 @@ static int hdmi_dump_regs(struct seq_file *s, void *p)  	return 0;  } -static int read_edid(struct omap_hdmi *hdmi, u8 *buf, int len) +static void hdmi_start_audio_stream(struct omap_hdmi *hd)  { -	int r; -	int idlemode; +	REG_FLD_MOD(hd->wp.base, HDMI_WP_SYSCONFIG, 1, 3, 2); +	hdmi_wp_audio_enable(&hd->wp, true); +	hdmi_wp_audio_core_req_enable(&hd->wp, true); +} -	mutex_lock(&hdmi->lock); +static void hdmi_stop_audio_stream(struct omap_hdmi *hd) +{ +	hdmi_wp_audio_core_req_enable(&hd->wp, false); +	hdmi_wp_audio_enable(&hd->wp, false); +	REG_FLD_MOD(hd->wp.base, HDMI_WP_SYSCONFIG, hd->wp_idlemode, 3, 2); +} -	r = hdmi_runtime_get(hdmi); -	BUG_ON(r); +static int hdmi_core_enable(struct omap_hdmi *hdmi) +{ +	int r = 0; -	idlemode = REG_GET(hdmi->wp.base, HDMI_WP_SYSCONFIG, 3, 2); -	/* No-idle mode */ -	REG_FLD_MOD(hdmi->wp.base, HDMI_WP_SYSCONFIG, 1, 3, 2); +	DSSDBG("ENTER omapdss_hdmi_core_enable\n"); -	r = hdmi5_read_edid(&hdmi->core,  buf, len); +	mutex_lock(&hdmi->lock); -	REG_FLD_MOD(hdmi->wp.base, HDMI_WP_SYSCONFIG, idlemode, 3, 2); +	r = hdmi_power_on_core(hdmi); +	if (r) { +		DSSERR("failed to power on device\n"); +		goto err0; +	} -	hdmi_runtime_put(hdmi);  	mutex_unlock(&hdmi->lock); +	return 0; +err0: +	mutex_unlock(&hdmi->lock);  	return r;  } -static void hdmi_start_audio_stream(struct omap_hdmi *hd) +static void hdmi_core_disable(struct omap_hdmi *hdmi)  { -	REG_FLD_MOD(hd->wp.base, HDMI_WP_SYSCONFIG, 1, 3, 2); -	hdmi_wp_audio_enable(&hd->wp, true); -	hdmi_wp_audio_core_req_enable(&hd->wp, true); +	DSSDBG("Enter omapdss_hdmi_core_disable\n"); + +	mutex_lock(&hdmi->lock); + +	hdmi_power_off_core(hdmi); + +	mutex_unlock(&hdmi->lock);  } -static void hdmi_stop_audio_stream(struct omap_hdmi *hd) +/* ----------------------------------------------------------------------------- + * DRM Bridge Operations + */ + +static int hdmi5_bridge_attach(struct drm_bridge *bridge, +			       enum drm_bridge_attach_flags flags)  { -	hdmi_wp_audio_core_req_enable(&hd->wp, false); -	hdmi_wp_audio_enable(&hd->wp, false); -	REG_FLD_MOD(hd->wp.base, HDMI_WP_SYSCONFIG, hd->wp_idlemode, 3, 2); +	struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge); + +	if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) +		return -EINVAL; + +	return drm_bridge_attach(bridge->encoder, hdmi->output.next_bridge, +				 bridge, flags);  } -static void hdmi_display_enable(struct omap_dss_device *dssdev) +static void hdmi5_bridge_mode_set(struct drm_bridge *bridge, +				  const struct drm_display_mode *mode, +				  const struct drm_display_mode *adjusted_mode)  { -	struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); -	unsigned long flags; -	int r; +	struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge); + +	mutex_lock(&hdmi->lock); -	DSSDBG("ENTER hdmi_display_enable\n"); +	drm_display_mode_to_videomode(adjusted_mode, &hdmi->cfg.vm); + +	dispc_set_tv_pclk(hdmi->dss->dispc, adjusted_mode->clock * 1000); + +	mutex_unlock(&hdmi->lock); +} + +static void hdmi5_bridge_enable(struct drm_bridge *bridge, +				struct drm_bridge_state *bridge_state) +{ +	struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge); +	struct drm_atomic_state *state = bridge_state->base.state; +	struct drm_connector_state *conn_state; +	struct drm_connector *connector; +	struct drm_crtc_state *crtc_state; +	unsigned long flags; +	int ret; + +	/* +	 * None of these should fail, as the bridge can't be enabled without a +	 * valid CRTC to connector path with fully populated new states. +	 */ +	connector = drm_atomic_get_new_connector_for_encoder(state, +							     bridge->encoder); +	if (WARN_ON(!connector)) +		return; +	conn_state = drm_atomic_get_new_connector_state(state, connector); +	if (WARN_ON(!conn_state)) +		return; +	crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc); +	if (WARN_ON(!crtc_state)) +		return; + +	hdmi->cfg.hdmi_dvi_mode = connector->display_info.is_hdmi +				? HDMI_HDMI : HDMI_DVI; + +	if (connector->display_info.is_hdmi) { +		const struct drm_display_mode *mode; +		struct hdmi_avi_infoframe avi; + +		mode = &crtc_state->adjusted_mode; +		ret = drm_hdmi_avi_infoframe_from_display_mode(&avi, connector, +							       mode); +		if (ret == 0) +			hdmi->cfg.infoframe = avi; +	}  	mutex_lock(&hdmi->lock); -	r = hdmi_power_on_full(hdmi); -	if (r) { +	ret = hdmi_power_on_full(hdmi); +	if (ret) {  		DSSERR("failed to power on device\n");  		goto done;  	}  	if (hdmi->audio_configured) { -		r = hdmi5_audio_config(&hdmi->core, &hdmi->wp, -				       &hdmi->audio_config, -				       hdmi->cfg.vm.pixelclock); -		if (r) { -			DSSERR("Error restoring audio configuration: %d", r); +		ret = hdmi5_audio_config(&hdmi->core, &hdmi->wp, +					 &hdmi->audio_config, +					 hdmi->cfg.vm.pixelclock); +		if (ret) { +			DSSERR("Error restoring audio configuration: %d", ret);  			hdmi->audio_abort_cb(&hdmi->pdev->dev);  			hdmi->audio_configured = false;  		} @@ -346,13 +407,12 @@ done:  	mutex_unlock(&hdmi->lock);  } -static void hdmi_display_disable(struct omap_dss_device *dssdev) +static void hdmi5_bridge_disable(struct drm_bridge *bridge, +				 struct drm_bridge_state *bridge_state)  { -	struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); +	struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge);  	unsigned long flags; -	DSSDBG("Enter hdmi_display_disable\n"); -  	mutex_lock(&hdmi->lock);  	spin_lock_irqsave(&hdmi->audio_playing_lock, flags); @@ -365,109 +425,74 @@ static void hdmi_display_disable(struct omap_dss_device *dssdev)  	mutex_unlock(&hdmi->lock);  } -static int hdmi_core_enable(struct omap_hdmi *hdmi) +static struct edid *hdmi5_bridge_get_edid(struct drm_bridge *bridge, +					  struct drm_connector *connector)  { -	int r = 0; - -	DSSDBG("ENTER omapdss_hdmi_core_enable\n"); +	struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge); +	struct edid *edid; +	bool need_enable; +	int idlemode; +	int r; -	mutex_lock(&hdmi->lock); +	need_enable = hdmi->core_enabled == false; -	r = hdmi_power_on_core(hdmi); -	if (r) { -		DSSERR("failed to power on device\n"); -		goto err0; +	if (need_enable) { +		r = hdmi_core_enable(hdmi); +		if (r) +			return NULL;  	} -	mutex_unlock(&hdmi->lock); -	return 0; - -err0: -	mutex_unlock(&hdmi->lock); -	return r; -} - -static void hdmi_core_disable(struct omap_hdmi *hdmi) -{ -	DSSDBG("Enter omapdss_hdmi_core_disable\n"); -  	mutex_lock(&hdmi->lock); +	r = hdmi_runtime_get(hdmi); +	BUG_ON(r); -	hdmi_power_off_core(hdmi); - -	mutex_unlock(&hdmi->lock); -} - -static int hdmi_connect(struct omap_dss_device *src, -			struct omap_dss_device *dst) -{ -	return omapdss_device_connect(dst->dss, dst, dst->next); -} +	idlemode = REG_GET(hdmi->wp.base, HDMI_WP_SYSCONFIG, 3, 2); +	/* No-idle mode */ +	REG_FLD_MOD(hdmi->wp.base, HDMI_WP_SYSCONFIG, 1, 3, 2); -static void hdmi_disconnect(struct omap_dss_device *src, -			    struct omap_dss_device *dst) -{ -	omapdss_device_disconnect(dst, dst->next); -} +	hdmi5_core_ddc_init(&hdmi->core); -static int hdmi_read_edid(struct omap_dss_device *dssdev, -		u8 *edid, int len) -{ -	struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); -	bool need_enable; -	int r; +	edid = drm_do_get_edid(connector, hdmi5_core_ddc_read, &hdmi->core); -	need_enable = hdmi->core_enabled == false; +	hdmi5_core_ddc_uninit(&hdmi->core); -	if (need_enable) { -		r = hdmi_core_enable(hdmi); -		if (r) -			return r; -	} +	REG_FLD_MOD(hdmi->wp.base, HDMI_WP_SYSCONFIG, idlemode, 3, 2); -	r = read_edid(hdmi, edid, len); +	hdmi_runtime_put(hdmi); +	mutex_unlock(&hdmi->lock);  	if (need_enable)  		hdmi_core_disable(hdmi); -	return r; +	return (struct edid *)edid;  } -static int hdmi_set_infoframe(struct omap_dss_device *dssdev, -		const struct hdmi_avi_infoframe *avi) +static const struct drm_bridge_funcs hdmi5_bridge_funcs = { +	.attach = hdmi5_bridge_attach, +	.mode_set = hdmi5_bridge_mode_set, +	.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, +	.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, +	.atomic_reset = drm_atomic_helper_bridge_reset, +	.atomic_enable = hdmi5_bridge_enable, +	.atomic_disable = hdmi5_bridge_disable, +	.get_edid = hdmi5_bridge_get_edid, +}; + +static void hdmi5_bridge_init(struct omap_hdmi *hdmi)  { -	struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); +	hdmi->bridge.funcs = &hdmi5_bridge_funcs; +	hdmi->bridge.of_node = hdmi->pdev->dev.of_node; +	hdmi->bridge.ops = DRM_BRIDGE_OP_EDID; +	hdmi->bridge.type = DRM_MODE_CONNECTOR_HDMIA; -	hdmi->cfg.infoframe = *avi; -	return 0; +	drm_bridge_add(&hdmi->bridge);  } -static int hdmi_set_hdmi_mode(struct omap_dss_device *dssdev, -		bool hdmi_mode) +static void hdmi5_bridge_cleanup(struct omap_hdmi *hdmi)  { -	struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); - -	hdmi->cfg.hdmi_dvi_mode = hdmi_mode ? HDMI_HDMI : HDMI_DVI; -	return 0; +	drm_bridge_remove(&hdmi->bridge);  } -static const struct omap_dss_device_ops hdmi_ops = { -	.connect		= hdmi_connect, -	.disconnect		= hdmi_disconnect, - -	.enable			= hdmi_display_enable, -	.disable		= hdmi_display_disable, - -	.set_timings		= hdmi_display_set_timings, - -	.read_edid		= hdmi_read_edid, - -	.hdmi = { -		.set_infoframe		= hdmi_set_infoframe, -		.set_hdmi_mode		= hdmi_set_hdmi_mode, -	}, -}; -  /* -----------------------------------------------------------------------------   * Audio Callbacks   */ @@ -650,19 +675,21 @@ static int hdmi5_init_output(struct omap_hdmi *hdmi)  	struct omap_dss_device *out = &hdmi->output;  	int r; +	hdmi5_bridge_init(hdmi); +  	out->dev = &hdmi->pdev->dev;  	out->id = OMAP_DSS_OUTPUT_HDMI;  	out->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->of_port = 0; -	r = omapdss_device_init_output(out); -	if (r < 0) +	r = omapdss_device_init_output(out, &hdmi->bridge); +	if (r < 0) { +		hdmi5_bridge_cleanup(hdmi);  		return r; +	}  	omapdss_device_register(out); @@ -675,6 +702,8 @@ static void hdmi5_uninit_output(struct omap_hdmi *hdmi)  	omapdss_device_unregister(out);  	omapdss_device_cleanup_output(out); + +	hdmi5_bridge_cleanup(hdmi);  }  static int hdmi5_probe_of(struct omap_hdmi *hdmi) diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi5_core.c b/drivers/gpu/drm/omapdrm/dss/hdmi5_core.c index ff4d35c8771f..7dd587035160 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi5_core.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi5_core.c @@ -23,7 +23,7 @@  #include "hdmi5_core.h" -static void hdmi_core_ddc_init(struct hdmi_core_data *core) +void hdmi5_core_ddc_init(struct hdmi_core_data *core)  {  	void __iomem *base = core->base;  	const unsigned long long iclk = 266000000;	/* DSS L3 ICLK */ @@ -102,7 +102,7 @@ static void hdmi_core_ddc_init(struct hdmi_core_data *core)  	REG_FLD_MOD(base, HDMI_CORE_I2CM_INT, 0x0, 2, 2);  } -static void hdmi_core_ddc_uninit(struct hdmi_core_data *core) +void hdmi5_core_ddc_uninit(struct hdmi_core_data *core)  {  	void __iomem *base = core->base; @@ -112,14 +112,14 @@ static void hdmi_core_ddc_uninit(struct hdmi_core_data *core)  	REG_FLD_MOD(base, HDMI_CORE_I2CM_INT, 0x1, 2, 2);  } -static int hdmi_core_ddc_edid(struct hdmi_core_data *core, u8 *pedid, u8 ext) +int hdmi5_core_ddc_read(void *data, u8 *buf, unsigned int block, size_t len)  { +	struct hdmi_core_data *core = data;  	void __iomem *base = core->base;  	u8 cur_addr; -	char checksum = 0;  	const int retries = 1000; -	u8 seg_ptr = ext / 2; -	u8 edidbase = ((ext % 2) * 0x80); +	u8 seg_ptr = block / 2; +	u8 edidbase = ((block % 2) * EDID_LENGTH);  	REG_FLD_MOD(base, HDMI_CORE_I2CM_SEGPTR, seg_ptr, 7, 0); @@ -127,7 +127,7 @@ static int hdmi_core_ddc_edid(struct hdmi_core_data *core, u8 *pedid, u8 ext)  	 * TODO: We use polling here, although we probably should use proper  	 * interrupts.  	 */ -	for (cur_addr = 0; cur_addr < 128; ++cur_addr) { +	for (cur_addr = 0; cur_addr < len; ++cur_addr) {  		int i;  		/* clear ERROR and DONE */ @@ -164,45 +164,13 @@ static int hdmi_core_ddc_edid(struct hdmi_core_data *core, u8 *pedid, u8 ext)  			return -EIO;  		} -		pedid[cur_addr] = REG_GET(base, HDMI_CORE_I2CM_DATAI, 7, 0); -		checksum += pedid[cur_addr]; +		buf[cur_addr] = REG_GET(base, HDMI_CORE_I2CM_DATAI, 7, 0);  	}  	return 0;  } -int hdmi5_read_edid(struct hdmi_core_data *core, u8 *edid, int len) -{ -	int r, n, i; -	int max_ext_blocks = (len / 128) - 1; - -	if (len < 128) -		return -EINVAL; - -	hdmi_core_ddc_init(core); - -	r = hdmi_core_ddc_edid(core, edid, 0); -	if (r) -		goto out; - -	n = edid[0x7e]; - -	if (n > max_ext_blocks) -		n = max_ext_blocks; - -	for (i = 1; i <= n; i++) { -		r = hdmi_core_ddc_edid(core, edid + i * EDID_LENGTH, i); -		if (r) -			goto out; -	} - -out: -	hdmi_core_ddc_uninit(core); - -	return r ? r : len; -} -  void hdmi5_core_dump(struct hdmi_core_data *core, struct seq_file *s)  { diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi5_core.h b/drivers/gpu/drm/omapdrm/dss/hdmi5_core.h index f10b8a283011..65eadefdb3f9 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi5_core.h +++ b/drivers/gpu/drm/omapdrm/dss/hdmi5_core.h @@ -281,7 +281,10 @@ struct csc_table {  	u16 c1, c2, c3, c4;  }; -int hdmi5_read_edid(struct hdmi_core_data *core, u8 *edid, int len); +void hdmi5_core_ddc_init(struct hdmi_core_data *core); +int hdmi5_core_ddc_read(void *data, u8 *buf, unsigned int block, size_t len); +void hdmi5_core_ddc_uninit(struct hdmi_core_data *core); +  void hdmi5_core_dump(struct hdmi_core_data *core, struct seq_file *s);  int hdmi5_core_handle_irqs(struct hdmi_core_data *core);  void hdmi5_configure(struct hdmi_core_data *core, struct hdmi_wp_data *wp, diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss-boot-init.c b/drivers/gpu/drm/omapdrm/dss/omapdss-boot-init.c index 31502857f013..00372f4ce711 100644 --- a/drivers/gpu/drm/omapdrm/dss/omapdss-boot-init.c +++ b/drivers/gpu/drm/omapdrm/dss/omapdss-boot-init.c @@ -174,12 +174,7 @@ static const struct of_device_id omapdss_of_match[] __initconst = {  };  static const struct of_device_id omapdss_of_fixups_whitelist[] __initconst = { -	{ .compatible = "composite-video-connector" }, -	{ .compatible = "hdmi-connector" },  	{ .compatible = "panel-dsi-cm" }, -	{ .compatible = "svideo-connector" }, -	{ .compatible = "ti,opa362" }, -	{ .compatible = "ti,tpd12s015" },  	{},  }; @@ -192,7 +187,7 @@ static int __init omapdss_boot_init(void)  	dss = of_find_matching_node(NULL, omapdss_of_match);  	if (dss == NULL || !of_device_is_available(dss)) -		return 0; +		goto put_node;  	omapdss_walk_device(dss, true); @@ -217,6 +212,8 @@ static int __init omapdss_boot_init(void)  		kfree(n);  	} +put_node: +	of_node_put(dss);  	return 0;  } diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss.h b/drivers/gpu/drm/omapdrm/dss/omapdss.h index 79f6b195c7cf..ab19d4af8de7 100644 --- a/drivers/gpu/drm/omapdrm/dss/omapdss.h +++ b/drivers/gpu/drm/omapdrm/dss/omapdss.h @@ -285,13 +285,6 @@ struct omap_dss_writeback_info {  	u8 pre_mult_alpha;  }; -struct omapdss_hdmi_ops { -	void (*lost_hotplug)(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 {  	void (*disable)(struct omap_dss_device *dssdev, bool disconnect_lanes,  			bool enter_ulps); @@ -349,46 +342,23 @@ struct omap_dss_device_ops {  	void (*disconnect)(struct omap_dss_device *dssdev,  			struct omap_dss_device *dst); -	void (*pre_enable)(struct omap_dss_device *dssdev);  	void (*enable)(struct omap_dss_device *dssdev);  	void (*disable)(struct omap_dss_device *dssdev); -	void (*post_disable)(struct omap_dss_device *dssdev);  	int (*check_timings)(struct omap_dss_device *dssdev,  			     struct drm_display_mode *mode); -	void (*set_timings)(struct omap_dss_device *dssdev, -			    const struct drm_display_mode *mode); - -	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);  	int (*get_modes)(struct omap_dss_device *dssdev,  			 struct drm_connector *connector); -	union { -		const struct omapdss_hdmi_ops hdmi; -		const struct omapdss_dsi_ops dsi; -	}; +	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 reading EDID   * @OMAP_DSS_DEVICE_OP_MODES: The device supports reading modes   */  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),  	OMAP_DSS_DEVICE_OP_MODES = BIT(3),  }; @@ -400,6 +370,7 @@ struct omap_dss_device {  	struct dss_device *dss;  	struct omap_dss_device *next;  	struct drm_bridge *bridge; +	struct drm_bridge *next_bridge;  	struct drm_panel *panel;  	struct list_head list; @@ -436,8 +407,8 @@ struct omap_dss_device {  	/* output instance */  	enum omap_dss_output_id id; -	/* bitmask of port numbers in DT */ -	unsigned int of_ports; +	/* port number in DT */ +	unsigned int of_port;  };  struct omap_dss_driver { @@ -461,7 +432,6 @@ static inline bool omapdss_is_initialized(void)  }  void omapdss_display_init(struct omap_dss_device *dssdev); -struct omap_dss_device *omapdss_display_get(struct omap_dss_device *output);  int omapdss_display_get_modes(struct drm_connector *connector,  			      const struct videomode *vm); @@ -475,10 +445,8 @@ int omapdss_device_connect(struct dss_device *dss,  			   struct omap_dss_device *dst);  void omapdss_device_disconnect(struct omap_dss_device *src,  			       struct omap_dss_device *dst); -void omapdss_device_pre_enable(struct omap_dss_device *dssdev);  void omapdss_device_enable(struct omap_dss_device *dssdev);  void omapdss_device_disable(struct omap_dss_device *dssdev); -void omapdss_device_post_disable(struct omap_dss_device *dssdev);  int omap_dss_get_num_overlay_managers(void); @@ -487,7 +455,8 @@ int omap_dss_get_num_overlays(void);  #define for_each_dss_output(d) \  	while ((d = omapdss_device_next_output(d)) != NULL)  struct omap_dss_device *omapdss_device_next_output(struct omap_dss_device *from); -int omapdss_device_init_output(struct omap_dss_device *out); +int omapdss_device_init_output(struct omap_dss_device *out, +			       struct drm_bridge *local_bridge);  void omapdss_device_cleanup_output(struct omap_dss_device *out);  typedef void (*omap_dispc_isr_t) (void *arg, u32 mask); @@ -502,9 +471,6 @@ static inline bool omapdss_device_is_enabled(struct omap_dss_device *dssdev)  	return dssdev->state == OMAP_DSS_DISPLAY_ACTIVE;  } -struct omap_dss_device * -omapdss_of_find_connected_device(struct device_node *node, unsigned int port); -  enum dss_writeback_channel {  	DSS_WB_LCD1_MGR =	0,  	DSS_WB_LCD2_MGR =	1, diff --git a/drivers/gpu/drm/omapdrm/dss/output.c b/drivers/gpu/drm/omapdrm/dss/output.c index 0693d34fca1b..ce21c798cca6 100644 --- a/drivers/gpu/drm/omapdrm/dss/output.c +++ b/drivers/gpu/drm/omapdrm/dss/output.c @@ -4,7 +4,6 @@   * Author: Archit Taneja <[email protected]>   */ -#include <linux/bitops.h>  #include <linux/kernel.h>  #include <linux/module.h>  #include <linux/platform_device.h> @@ -18,12 +17,14 @@  #include "dss.h"  #include "omapdss.h" -int omapdss_device_init_output(struct omap_dss_device *out) +int omapdss_device_init_output(struct omap_dss_device *out, +			       struct drm_bridge *local_bridge)  {  	struct device_node *remote_node; +	int ret;  	remote_node = of_graph_get_remote_node(out->dev->of_node, -					       ffs(out->of_ports) - 1, 0); +					       out->of_port, 0);  	if (!remote_node) {  		dev_dbg(out->dev, "failed to find video sink\n");  		return 0; @@ -39,17 +40,55 @@ int omapdss_device_init_output(struct omap_dss_device *out)  	if (out->next && out->type != out->next->type) {  		dev_err(out->dev, "output type and display type don't match\n"); -		omapdss_device_put(out->next); -		out->next = NULL; -		return -EINVAL; +		ret = -EINVAL; +		goto error;  	} -	return out->next || out->bridge || out->panel ? 0 : -EPROBE_DEFER; +	if (out->panel) { +		struct drm_bridge *bridge; + +		bridge = drm_panel_bridge_add(out->panel); +		if (IS_ERR(bridge)) { +			dev_err(out->dev, +				"unable to create panel bridge (%ld)\n", +				PTR_ERR(bridge)); +			ret = PTR_ERR(bridge); +			goto error; +		} + +		out->bridge = bridge; +	} + +	if (local_bridge) { +		if (!out->bridge) { +			ret = -EPROBE_DEFER; +			goto error; +		} + +		out->next_bridge = out->bridge; +		out->bridge = local_bridge; +	} + +	if (!out->next && !out->bridge) { +		ret = -EPROBE_DEFER; +		goto error; +	} + +	return 0; + +error: +	omapdss_device_cleanup_output(out); +	out->next = NULL; +	return ret;  }  EXPORT_SYMBOL(omapdss_device_init_output);  void omapdss_device_cleanup_output(struct omap_dss_device *out)  { +	if (out->bridge && out->panel) +		drm_panel_bridge_remove(out->next_bridge ? +					out->next_bridge : out->bridge); +  	if (out->next)  		omapdss_device_put(out->next);  } diff --git a/drivers/gpu/drm/omapdrm/dss/sdi.c b/drivers/gpu/drm/omapdrm/dss/sdi.c index 3b447c01fa2a..417a8740ad0a 100644 --- a/drivers/gpu/drm/omapdrm/dss/sdi.c +++ b/drivers/gpu/drm/omapdrm/dss/sdi.c @@ -6,17 +6,19 @@  #define DSS_SUBSYS_NAME "SDI" -#include <linux/kernel.h>  #include <linux/delay.h>  #include <linux/err.h> -#include <linux/regulator/consumer.h>  #include <linux/export.h> +#include <linux/kernel.h> +#include <linux/of.h>  #include <linux/platform_device.h> +#include <linux/regulator/consumer.h>  #include <linux/string.h> -#include <linux/of.h> -#include "omapdss.h" +#include <drm/drm_bridge.h> +  #include "dss.h" +#include "omapdss.h"  struct sdi_device {  	struct platform_device *pdev; @@ -30,9 +32,11 @@ struct sdi_device {  	int datapairs;  	struct omap_dss_device output; +	struct drm_bridge bridge;  }; -#define dssdev_to_sdi(dssdev) container_of(dssdev, struct sdi_device, output) +#define drm_bridge_to_sdi(bridge) \ +	container_of(bridge, struct sdi_device, bridge)  struct sdi_clk_calc_ctx {  	struct sdi_device *sdi; @@ -118,9 +122,82 @@ static void sdi_config_lcd_manager(struct sdi_device *sdi)  	dss_mgr_set_lcd_config(&sdi->output, &sdi->mgr_config);  } -static void sdi_display_enable(struct omap_dss_device *dssdev) +/* ----------------------------------------------------------------------------- + * DRM Bridge Operations + */ + +static int sdi_bridge_attach(struct drm_bridge *bridge, +			     enum drm_bridge_attach_flags flags) +{ +	struct sdi_device *sdi = drm_bridge_to_sdi(bridge); + +	if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) +		return -EINVAL; + +	return drm_bridge_attach(bridge->encoder, sdi->output.next_bridge, +				 bridge, flags); +} + +static enum drm_mode_status +sdi_bridge_mode_valid(struct drm_bridge *bridge, +		      const struct drm_display_mode *mode) +{ +	struct sdi_device *sdi = drm_bridge_to_sdi(bridge); +	unsigned long pixelclock = mode->clock * 1000; +	struct dispc_clock_info dispc_cinfo; +	unsigned long fck; +	int ret; + +	if (pixelclock == 0) +		return MODE_NOCLOCK; + +	ret = sdi_calc_clock_div(sdi, pixelclock, &fck, &dispc_cinfo); +	if (ret < 0) +		return MODE_CLOCK_RANGE; + +	return MODE_OK; +} + +static bool sdi_bridge_mode_fixup(struct drm_bridge *bridge, +				  const struct drm_display_mode *mode, +				  struct drm_display_mode *adjusted_mode) +{ +	struct sdi_device *sdi = drm_bridge_to_sdi(bridge); +	unsigned long pixelclock = mode->clock * 1000; +	struct dispc_clock_info dispc_cinfo; +	unsigned long fck; +	unsigned long pck; +	int ret; + +	ret = sdi_calc_clock_div(sdi, pixelclock, &fck, &dispc_cinfo); +	if (ret < 0) +		return false; + +	pck = fck / dispc_cinfo.lck_div / dispc_cinfo.pck_div; + +	if (pck != pixelclock) +		dev_dbg(&sdi->pdev->dev, +			"pixel clock adjusted from %lu Hz to %lu Hz\n", +			pixelclock, pck); + +	adjusted_mode->clock = pck / 1000; + +	return true; +} + +static void sdi_bridge_mode_set(struct drm_bridge *bridge, +				const struct drm_display_mode *mode, +				const struct drm_display_mode *adjusted_mode) +{ +	struct sdi_device *sdi = drm_bridge_to_sdi(bridge); + +	sdi->pixelclock = adjusted_mode->clock * 1000; +} + +static void sdi_bridge_enable(struct drm_bridge *bridge, +			      struct drm_bridge_state *bridge_state)  { -	struct sdi_device *sdi = dssdev_to_sdi(dssdev); +	struct sdi_device *sdi = drm_bridge_to_sdi(bridge);  	struct dispc_clock_info dispc_cinfo;  	unsigned long fck;  	int r; @@ -181,9 +258,10 @@ err_get_dispc:  	regulator_disable(sdi->vdds_sdi_reg);  } -static void sdi_display_disable(struct omap_dss_device *dssdev) +static void sdi_bridge_disable(struct drm_bridge *bridge, +			       struct drm_bridge_state *bridge_state)  { -	struct sdi_device *sdi = dssdev_to_sdi(dssdev); +	struct sdi_device *sdi = drm_bridge_to_sdi(bridge);  	dss_mgr_disable(&sdi->output); @@ -194,86 +272,56 @@ static void sdi_display_disable(struct omap_dss_device *dssdev)  	regulator_disable(sdi->vdds_sdi_reg);  } -static void sdi_set_timings(struct omap_dss_device *dssdev, -			    const struct drm_display_mode *mode) -{ -	struct sdi_device *sdi = dssdev_to_sdi(dssdev); - -	sdi->pixelclock = mode->clock * 1000; -} +static const struct drm_bridge_funcs sdi_bridge_funcs = { +	.attach = sdi_bridge_attach, +	.mode_valid = sdi_bridge_mode_valid, +	.mode_fixup = sdi_bridge_mode_fixup, +	.mode_set = sdi_bridge_mode_set, +	.atomic_enable = sdi_bridge_enable, +	.atomic_disable = sdi_bridge_disable, +}; -static int sdi_check_timings(struct omap_dss_device *dssdev, -			     struct drm_display_mode *mode) +static void sdi_bridge_init(struct sdi_device *sdi)  { -	struct sdi_device *sdi = dssdev_to_sdi(dssdev); -	struct dispc_clock_info dispc_cinfo; -	unsigned long pixelclock = mode->clock * 1000; -	unsigned long fck; -	unsigned long pck; -	int r; +	sdi->bridge.funcs = &sdi_bridge_funcs; +	sdi->bridge.of_node = sdi->pdev->dev.of_node; +	sdi->bridge.type = DRM_MODE_CONNECTOR_LVDS; -	if (pixelclock == 0) -		return -EINVAL; - -	r = sdi_calc_clock_div(sdi, pixelclock, &fck, &dispc_cinfo); -	if (r) -		return r; - -	pck = fck / dispc_cinfo.lck_div / dispc_cinfo.pck_div; - -	if (pck != pixelclock) { -		DSSWARN("Pixel clock adjusted from %lu Hz to %lu Hz\n", -			pixelclock, pck); - -		mode->clock = pck / 1000; -	} - -	return 0; +	drm_bridge_add(&sdi->bridge);  } -static int sdi_connect(struct omap_dss_device *src, -		       struct omap_dss_device *dst) +static void sdi_bridge_cleanup(struct sdi_device *sdi)  { -	return omapdss_device_connect(dst->dss, dst, dst->next); +	drm_bridge_remove(&sdi->bridge);  } -static void sdi_disconnect(struct omap_dss_device *src, -			   struct omap_dss_device *dst) -{ -	omapdss_device_disconnect(dst, dst->next); -} - -static const struct omap_dss_device_ops sdi_ops = { -	.connect = sdi_connect, -	.disconnect = sdi_disconnect, - -	.enable = sdi_display_enable, -	.disable = sdi_display_disable, - -	.check_timings = sdi_check_timings, -	.set_timings = sdi_set_timings, -}; +/* ----------------------------------------------------------------------------- + * Initialisation and Cleanup + */  static int sdi_init_output(struct sdi_device *sdi)  {  	struct omap_dss_device *out = &sdi->output;  	int r; +	sdi_bridge_init(sdi); +  	out->dev = &sdi->pdev->dev;  	out->id = OMAP_DSS_OUTPUT_SDI;  	out->type = OMAP_DISPLAY_TYPE_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->of_ports = BIT(1); -	out->ops = &sdi_ops; +	out->of_port = 1;  	out->owner = THIS_MODULE;  	out->bus_flags = DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE	/* 15.5.9.1.2 */  		       | DRM_BUS_FLAG_SYNC_DRIVE_POSEDGE; -	r = omapdss_device_init_output(out); -	if (r < 0) +	r = omapdss_device_init_output(out, &sdi->bridge); +	if (r < 0) { +		sdi_bridge_cleanup(sdi);  		return r; +	}  	omapdss_device_register(out); @@ -284,6 +332,8 @@ static void sdi_uninit_output(struct sdi_device *sdi)  {  	omapdss_device_unregister(&sdi->output);  	omapdss_device_cleanup_output(&sdi->output); + +	sdi_bridge_cleanup(sdi);  }  int sdi_init_port(struct dss_device *dss, struct platform_device *pdev, diff --git a/drivers/gpu/drm/omapdrm/dss/venc.c b/drivers/gpu/drm/omapdrm/dss/venc.c index 596a297d5813..766553bb2f87 100644 --- a/drivers/gpu/drm/omapdrm/dss/venc.c +++ b/drivers/gpu/drm/omapdrm/dss/venc.c @@ -13,7 +13,6 @@  #include <linux/clk.h>  #include <linux/err.h>  #include <linux/io.h> -#include <linux/mutex.h>  #include <linux/completion.h>  #include <linux/delay.h>  #include <linux/string.h> @@ -26,6 +25,8 @@  #include <linux/component.h>  #include <linux/sys_soc.h> +#include <drm/drm_bridge.h> +  #include "omapdss.h"  #include "dss.h" @@ -289,7 +290,6 @@ static const struct drm_display_mode omap_dss_ntsc_mode = {  struct venc_device {  	struct platform_device *pdev;  	void __iomem *base; -	struct mutex venc_lock;  	struct regulator *vdda_dac_reg;  	struct dss_device *dss; @@ -303,9 +303,10 @@ struct venc_device {  	bool requires_tv_dac_clk;  	struct omap_dss_device output; +	struct drm_bridge bridge;  }; -#define dssdev_to_venc(dssdev) container_of(dssdev, struct venc_device, output) +#define drm_bridge_to_venc(b) container_of(b, struct venc_device, bridge)  static inline void venc_write_reg(struct venc_device *venc, int idx, u32 val)  { @@ -477,56 +478,6 @@ static void venc_power_off(struct venc_device *venc)  	venc_runtime_put(venc);  } -static void venc_display_enable(struct omap_dss_device *dssdev) -{ -	struct venc_device *venc = dssdev_to_venc(dssdev); - -	DSSDBG("venc_display_enable\n"); - -	mutex_lock(&venc->venc_lock); - -	venc_power_on(venc); - -	mutex_unlock(&venc->venc_lock); -} - -static void venc_display_disable(struct omap_dss_device *dssdev) -{ -	struct venc_device *venc = dssdev_to_venc(dssdev); - -	DSSDBG("venc_display_disable\n"); - -	mutex_lock(&venc->venc_lock); - -	venc_power_off(venc); - -	mutex_unlock(&venc->venc_lock); -} - -static int venc_get_modes(struct omap_dss_device *dssdev, -			  struct drm_connector *connector) -{ -	static const struct drm_display_mode *modes[] = { -		&omap_dss_pal_mode, -		&omap_dss_ntsc_mode, -	}; -	unsigned int i; - -	for (i = 0; i < ARRAY_SIZE(modes); ++i) { -		struct drm_display_mode *mode; - -		mode = drm_mode_duplicate(connector->dev, modes[i]); -		if (!mode) -			return i; - -		mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; -		drm_mode_set_name(mode); -		drm_mode_probed_add(connector, mode); -	} - -	return ARRAY_SIZE(modes); -} -  static enum venc_videomode venc_get_videomode(const struct drm_display_mode *mode)  {  	if (!(mode->flags & DRM_MODE_FLAG_INTERLACE)) @@ -545,57 +496,6 @@ static enum venc_videomode venc_get_videomode(const struct drm_display_mode *mod  	return VENC_MODE_UNKNOWN;  } -static void venc_set_timings(struct omap_dss_device *dssdev, -			     const struct drm_display_mode *mode) -{ -	struct venc_device *venc = dssdev_to_venc(dssdev); -	enum venc_videomode venc_mode = venc_get_videomode(mode); - -	DSSDBG("venc_set_timings\n"); - -	mutex_lock(&venc->venc_lock); - -	switch (venc_mode) { -	default: -		WARN_ON_ONCE(1); -		/* Fall-through */ -	case VENC_MODE_PAL: -		venc->config = &venc_config_pal_trm; -		break; - -	case VENC_MODE_NTSC: -		venc->config = &venc_config_ntsc_trm; -		break; -	} - -	dispc_set_tv_pclk(venc->dss->dispc, 13500000); - -	mutex_unlock(&venc->venc_lock); -} - -static int venc_check_timings(struct omap_dss_device *dssdev, -			      struct drm_display_mode *mode) -{ -	DSSDBG("venc_check_timings\n"); - -	switch (venc_get_videomode(mode)) { -	case VENC_MODE_PAL: -		drm_mode_copy(mode, &omap_dss_pal_mode); -		break; - -	case VENC_MODE_NTSC: -		drm_mode_copy(mode, &omap_dss_ntsc_mode); -		break; - -	default: -		return -EINVAL; -	} - -	drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); -	drm_mode_set_name(mode); -	return 0; -} -  static int venc_dump_regs(struct seq_file *s, void *p)  {  	struct venc_device *venc = s->private; @@ -673,31 +573,149 @@ static int venc_get_clocks(struct venc_device *venc)  	return 0;  } -static int venc_connect(struct omap_dss_device *src, -			struct omap_dss_device *dst) +/* ----------------------------------------------------------------------------- + * DRM Bridge Operations + */ + +static int venc_bridge_attach(struct drm_bridge *bridge, +			      enum drm_bridge_attach_flags flags) +{ +	struct venc_device *venc = drm_bridge_to_venc(bridge); + +	if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) +		return -EINVAL; + +	return drm_bridge_attach(bridge->encoder, venc->output.next_bridge, +				 bridge, flags); +} + +static enum drm_mode_status +venc_bridge_mode_valid(struct drm_bridge *bridge, +		       const struct drm_display_mode *mode) +{ +	switch (venc_get_videomode(mode)) { +	case VENC_MODE_PAL: +	case VENC_MODE_NTSC: +		return MODE_OK; + +	default: +		return MODE_BAD; +	} +} + +static bool venc_bridge_mode_fixup(struct drm_bridge *bridge, +				   const struct drm_display_mode *mode, +				   struct drm_display_mode *adjusted_mode) +{ +	const struct drm_display_mode *venc_mode; + +	switch (venc_get_videomode(adjusted_mode)) { +	case VENC_MODE_PAL: +		venc_mode = &omap_dss_pal_mode; +		break; + +	case VENC_MODE_NTSC: +		venc_mode = &omap_dss_ntsc_mode; +		break; + +	default: +		return false; +	} + +	drm_mode_copy(adjusted_mode, venc_mode); +	drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V); +	drm_mode_set_name(adjusted_mode); + +	return true; +} + +static void venc_bridge_mode_set(struct drm_bridge *bridge, +				 const struct drm_display_mode *mode, +				 const struct drm_display_mode *adjusted_mode) +{ +	struct venc_device *venc = drm_bridge_to_venc(bridge); +	enum venc_videomode venc_mode = venc_get_videomode(adjusted_mode); + +	switch (venc_mode) { +	default: +		WARN_ON_ONCE(1); +		/* Fall-through */ +	case VENC_MODE_PAL: +		venc->config = &venc_config_pal_trm; +		break; + +	case VENC_MODE_NTSC: +		venc->config = &venc_config_ntsc_trm; +		break; +	} + +	dispc_set_tv_pclk(venc->dss->dispc, 13500000); +} + +static void venc_bridge_enable(struct drm_bridge *bridge)  { -	return omapdss_device_connect(dst->dss, dst, dst->next); +	struct venc_device *venc = drm_bridge_to_venc(bridge); + +	venc_power_on(venc);  } -static void venc_disconnect(struct omap_dss_device *src, -			    struct omap_dss_device *dst) +static void venc_bridge_disable(struct drm_bridge *bridge)  { -	omapdss_device_disconnect(dst, dst->next); +	struct venc_device *venc = drm_bridge_to_venc(bridge); + +	venc_power_off(venc);  } -static const struct omap_dss_device_ops venc_ops = { -	.connect = venc_connect, -	.disconnect = venc_disconnect, +static int venc_bridge_get_modes(struct drm_bridge *bridge, +				 struct drm_connector *connector) +{ +	static const struct drm_display_mode *modes[] = { +		&omap_dss_pal_mode, +		&omap_dss_ntsc_mode, +	}; +	unsigned int i; + +	for (i = 0; i < ARRAY_SIZE(modes); ++i) { +		struct drm_display_mode *mode; + +		mode = drm_mode_duplicate(connector->dev, modes[i]); +		if (!mode) +			return i; -	.enable = venc_display_enable, -	.disable = venc_display_disable, +		mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; +		drm_mode_set_name(mode); +		drm_mode_probed_add(connector, mode); +	} -	.check_timings = venc_check_timings, -	.set_timings = venc_set_timings, +	return ARRAY_SIZE(modes); +} -	.get_modes = venc_get_modes, +static const struct drm_bridge_funcs venc_bridge_funcs = { +	.attach = venc_bridge_attach, +	.mode_valid = venc_bridge_mode_valid, +	.mode_fixup = venc_bridge_mode_fixup, +	.mode_set = venc_bridge_mode_set, +	.enable = venc_bridge_enable, +	.disable = venc_bridge_disable, +	.get_modes = venc_bridge_get_modes,  }; +static void venc_bridge_init(struct venc_device *venc) +{ +	venc->bridge.funcs = &venc_bridge_funcs; +	venc->bridge.of_node = venc->pdev->dev.of_node; +	venc->bridge.ops = DRM_BRIDGE_OP_MODES; +	venc->bridge.type = DRM_MODE_CONNECTOR_SVIDEO; +	venc->bridge.interlace_allowed = true; + +	drm_bridge_add(&venc->bridge); +} + +static void venc_bridge_cleanup(struct venc_device *venc) +{ +	drm_bridge_remove(&venc->bridge); +} +  /* -----------------------------------------------------------------------------   * Component Bind & Unbind   */ @@ -747,19 +765,22 @@ static int venc_init_output(struct venc_device *venc)  	struct omap_dss_device *out = &venc->output;  	int r; +	venc_bridge_init(venc); +  	out->dev = &venc->pdev->dev;  	out->id = OMAP_DSS_OUTPUT_VENC;  	out->type = OMAP_DISPLAY_TYPE_VENC;  	out->name = "venc.0";  	out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT; -	out->ops = &venc_ops;  	out->owner = THIS_MODULE; -	out->of_ports = BIT(0); +	out->of_port = 0;  	out->ops_flags = OMAP_DSS_DEVICE_OP_MODES; -	r = omapdss_device_init_output(out); -	if (r < 0) +	r = omapdss_device_init_output(out, &venc->bridge); +	if (r < 0) { +		venc_bridge_cleanup(venc);  		return r; +	}  	omapdss_device_register(out); @@ -770,6 +791,8 @@ static void venc_uninit_output(struct venc_device *venc)  {  	omapdss_device_unregister(&venc->output);  	omapdss_device_cleanup_output(&venc->output); + +	venc_bridge_cleanup(venc);  }  static int venc_probe_of(struct venc_device *venc) @@ -839,8 +862,6 @@ static int venc_probe(struct platform_device *pdev)  	if (soc_device_match(venc_soc_devices))  		venc->requires_tv_dac_clk = true; -	mutex_init(&venc->venc_lock); -  	venc->config = &venc_config_pal_trm;  	venc_mem = platform_get_resource(venc->pdev, IORESOURCE_MEM, 0); |