diff options
Diffstat (limited to 'drivers/gpu/drm/imx')
| -rw-r--r-- | drivers/gpu/drm/imx/Kconfig | 1 | ||||
| -rw-r--r-- | drivers/gpu/drm/imx/dw_hdmi-imx.c | 14 | ||||
| -rw-r--r-- | drivers/gpu/drm/imx/imx-drm-core.c | 34 | ||||
| -rw-r--r-- | drivers/gpu/drm/imx/imx-drm.h | 10 | ||||
| -rw-r--r-- | drivers/gpu/drm/imx/imx-ldb.c | 196 | ||||
| -rw-r--r-- | drivers/gpu/drm/imx/imx-tve.c | 6 | ||||
| -rw-r--r-- | drivers/gpu/drm/imx/ipuv3-crtc.c | 24 | ||||
| -rw-r--r-- | drivers/gpu/drm/imx/ipuv3-plane.c | 7 | ||||
| -rw-r--r-- | drivers/gpu/drm/imx/ipuv3-plane.h | 2 | ||||
| -rw-r--r-- | drivers/gpu/drm/imx/parallel-display.c | 13 | 
10 files changed, 189 insertions, 118 deletions
| diff --git a/drivers/gpu/drm/imx/Kconfig b/drivers/gpu/drm/imx/Kconfig index 33cdddf26684..2b81a417cf29 100644 --- a/drivers/gpu/drm/imx/Kconfig +++ b/drivers/gpu/drm/imx/Kconfig @@ -36,6 +36,7 @@ config DRM_IMX_TVE  config DRM_IMX_LDB  	tristate "Support for LVDS displays"  	depends on DRM_IMX && MFD_SYSCON +	select DRM_PANEL  	help  	  Choose this to enable the internal LVDS Display Bridge (LDB)  	  found on i.MX53 and i.MX6 processors. diff --git a/drivers/gpu/drm/imx/dw_hdmi-imx.c b/drivers/gpu/drm/imx/dw_hdmi-imx.c index 87fe8ed92ebe..a3ecf1069b76 100644 --- a/drivers/gpu/drm/imx/dw_hdmi-imx.c +++ b/drivers/gpu/drm/imx/dw_hdmi-imx.c @@ -75,10 +75,10 @@ static const struct dw_hdmi_curr_ctrl imx_cur_ctr[] = {  	},  }; -static const struct dw_hdmi_sym_term imx_sym_term[] = { -	/*pixelclk   symbol   term*/ -	{ 148500000, 0x800d, 0x0005 }, -	{ ~0UL,      0x0000, 0x0000 } +static const struct dw_hdmi_phy_config imx_phy_config[] = { +	/*pixelclk   symbol   term   vlev */ +	{ 148500000, 0x800d, 0x0005, 0x01ad}, +	{ ~0UL,      0x0000, 0x0000, 0x0000}  };  static int dw_hdmi_imx_parse_dt(struct imx_hdmi *hdmi) @@ -123,7 +123,7 @@ static void dw_hdmi_imx_encoder_commit(struct drm_encoder *encoder)  static void dw_hdmi_imx_encoder_prepare(struct drm_encoder *encoder)  { -	imx_drm_panel_format(encoder, V4L2_PIX_FMT_RGB24); +	imx_drm_set_bus_format(encoder, MEDIA_BUS_FMT_RGB888_1X24);  }  static struct drm_encoder_helper_funcs dw_hdmi_imx_encoder_helper_funcs = { @@ -163,7 +163,7 @@ static enum drm_mode_status imx6dl_hdmi_mode_valid(struct drm_connector *con,  static struct dw_hdmi_plat_data imx6q_hdmi_drv_data = {  	.mpll_cfg   = imx_mpll_cfg,  	.cur_ctr    = imx_cur_ctr, -	.sym_term   = imx_sym_term, +	.phy_config = imx_phy_config,  	.dev_type   = IMX6Q_HDMI,  	.mode_valid = imx6q_hdmi_mode_valid,  }; @@ -171,7 +171,7 @@ static struct dw_hdmi_plat_data imx6q_hdmi_drv_data = {  static struct dw_hdmi_plat_data imx6dl_hdmi_drv_data = {  	.mpll_cfg = imx_mpll_cfg,  	.cur_ctr  = imx_cur_ctr, -	.sym_term = imx_sym_term, +	.phy_config = imx_phy_config,  	.dev_type = IMX6DL_HDMI,  	.mode_valid = imx6dl_hdmi_mode_valid,  }; diff --git a/drivers/gpu/drm/imx/imx-drm-core.c b/drivers/gpu/drm/imx/imx-drm-core.c index a002f53aab0e..74f505b0dd02 100644 --- a/drivers/gpu/drm/imx/imx-drm-core.c +++ b/drivers/gpu/drm/imx/imx-drm-core.c @@ -103,8 +103,8 @@ static struct imx_drm_crtc *imx_drm_find_crtc(struct drm_crtc *crtc)  	return NULL;  } -int imx_drm_panel_format_pins(struct drm_encoder *encoder, -		u32 interface_pix_fmt, int hsync_pin, int vsync_pin) +int imx_drm_set_bus_format_pins(struct drm_encoder *encoder, u32 bus_format, +		int hsync_pin, int vsync_pin)  {  	struct imx_drm_crtc_helper_funcs *helper;  	struct imx_drm_crtc *imx_crtc; @@ -116,16 +116,16 @@ int imx_drm_panel_format_pins(struct drm_encoder *encoder,  	helper = &imx_crtc->imx_drm_helper_funcs;  	if (helper->set_interface_pix_fmt)  		return helper->set_interface_pix_fmt(encoder->crtc, -				interface_pix_fmt, hsync_pin, vsync_pin); +					bus_format, hsync_pin, vsync_pin);  	return 0;  } -EXPORT_SYMBOL_GPL(imx_drm_panel_format_pins); +EXPORT_SYMBOL_GPL(imx_drm_set_bus_format_pins); -int imx_drm_panel_format(struct drm_encoder *encoder, u32 interface_pix_fmt) +int imx_drm_set_bus_format(struct drm_encoder *encoder, u32 bus_format)  { -	return imx_drm_panel_format_pins(encoder, interface_pix_fmt, 2, 3); +	return imx_drm_set_bus_format_pins(encoder, bus_format, 2, 3);  } -EXPORT_SYMBOL_GPL(imx_drm_panel_format); +EXPORT_SYMBOL_GPL(imx_drm_set_bus_format);  int imx_drm_crtc_vblank_get(struct imx_drm_crtc *imx_drm_crtc)  { @@ -431,15 +431,6 @@ int imx_drm_encoder_parse_of(struct drm_device *drm,  }  EXPORT_SYMBOL_GPL(imx_drm_encoder_parse_of); -static struct device_node *imx_drm_of_get_next_endpoint( -		const struct device_node *parent, struct device_node *prev) -{ -	struct device_node *node = of_graph_get_next_endpoint(parent, prev); - -	of_node_put(prev); -	return node; -} -  /*   * @node: device tree node containing encoder input ports   * @encoder: drm_encoder @@ -448,7 +439,7 @@ int imx_drm_encoder_get_mux_id(struct device_node *node,  			       struct drm_encoder *encoder)  {  	struct imx_drm_crtc *imx_crtc = imx_drm_find_crtc(encoder->crtc); -	struct device_node *ep = NULL; +	struct device_node *ep;  	struct of_endpoint endpoint;  	struct device_node *port;  	int ret; @@ -456,18 +447,15 @@ int imx_drm_encoder_get_mux_id(struct device_node *node,  	if (!node || !imx_crtc)  		return -EINVAL; -	do { -		ep = imx_drm_of_get_next_endpoint(node, ep); -		if (!ep) -			break; - +	for_each_endpoint_of_node(node, ep) {  		port = of_graph_get_remote_port(ep);  		of_node_put(port);  		if (port == imx_crtc->crtc->port) {  			ret = of_graph_parse_endpoint(ep, &endpoint); +			of_node_put(ep);  			return ret ? ret : endpoint.port;  		} -	} while (ep); +	}  	return -EINVAL;  } diff --git a/drivers/gpu/drm/imx/imx-drm.h b/drivers/gpu/drm/imx/imx-drm.h index 3c559ccd6af0..28e776d8d9d2 100644 --- a/drivers/gpu/drm/imx/imx-drm.h +++ b/drivers/gpu/drm/imx/imx-drm.h @@ -18,7 +18,7 @@ struct imx_drm_crtc_helper_funcs {  	int (*enable_vblank)(struct drm_crtc *crtc);  	void (*disable_vblank)(struct drm_crtc *crtc);  	int (*set_interface_pix_fmt)(struct drm_crtc *crtc, -			u32 pix_fmt, int hsync_pin, int vsync_pin); +			u32 bus_format, int hsync_pin, int vsync_pin);  	const struct drm_crtc_helper_funcs *crtc_helper_funcs;  	const struct drm_crtc_funcs *crtc_funcs;  }; @@ -40,10 +40,10 @@ void imx_drm_mode_config_init(struct drm_device *drm);  struct drm_gem_cma_object *imx_drm_fb_get_obj(struct drm_framebuffer *fb); -int imx_drm_panel_format_pins(struct drm_encoder *encoder, -		u32 interface_pix_fmt, int hsync_pin, int vsync_pin); -int imx_drm_panel_format(struct drm_encoder *encoder, -		u32 interface_pix_fmt); +int imx_drm_set_bus_format_pins(struct drm_encoder *encoder, +		u32 bus_format, int hsync_pin, int vsync_pin); +int imx_drm_set_bus_format(struct drm_encoder *encoder, +		u32 bus_format);  int imx_drm_encoder_get_mux_id(struct device_node *node,  		struct drm_encoder *encoder); diff --git a/drivers/gpu/drm/imx/imx-ldb.c b/drivers/gpu/drm/imx/imx-ldb.c index 2d6dc94e1e64..abacc8f67469 100644 --- a/drivers/gpu/drm/imx/imx-ldb.c +++ b/drivers/gpu/drm/imx/imx-ldb.c @@ -19,10 +19,11 @@  #include <drm/drmP.h>  #include <drm/drm_fb_helper.h>  #include <drm/drm_crtc_helper.h> +#include <drm/drm_panel.h>  #include <linux/mfd/syscon.h>  #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h> -#include <linux/of_address.h>  #include <linux/of_device.h> +#include <linux/of_graph.h>  #include <video/of_videomode.h>  #include <linux/regmap.h>  #include <linux/videodev2.h> @@ -55,12 +56,14 @@ struct imx_ldb_channel {  	struct imx_ldb *ldb;  	struct drm_connector connector;  	struct drm_encoder encoder; +	struct drm_panel *panel;  	struct device_node *child;  	int chno;  	void *edid;  	int edid_len;  	struct drm_display_mode mode;  	int mode_valid; +	int bus_format;  };  struct bus_mux { @@ -75,6 +78,7 @@ struct imx_ldb {  	struct imx_ldb_channel channel[2];  	struct clk *clk[2]; /* our own clock */  	struct clk *clk_sel[4]; /* parent of display clock */ +	struct clk *clk_parent[4]; /* original parent of clk_sel */  	struct clk *clk_pll[2]; /* upstream clock we can adjust */  	u32 ldb_ctrl;  	const struct bus_mux *lvds_mux; @@ -91,6 +95,17 @@ static int imx_ldb_connector_get_modes(struct drm_connector *connector)  	struct imx_ldb_channel *imx_ldb_ch = con_to_imx_ldb_ch(connector);  	int num_modes = 0; +	if (imx_ldb_ch->panel && imx_ldb_ch->panel->funcs && +	    imx_ldb_ch->panel->funcs->get_modes) { +		struct drm_display_info *di = &connector->display_info; + +		num_modes = imx_ldb_ch->panel->funcs->get_modes(imx_ldb_ch->panel); +		if (!imx_ldb_ch->bus_format && di->num_bus_formats) +			imx_ldb_ch->bus_format = di->bus_formats[0]; +		if (num_modes > 0) +			return num_modes; +	} +  	if (imx_ldb_ch->edid) {  		drm_mode_connector_update_edid_property(connector,  							imx_ldb_ch->edid); @@ -163,24 +178,36 @@ static void imx_ldb_encoder_prepare(struct drm_encoder *encoder)  {  	struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder);  	struct imx_ldb *ldb = imx_ldb_ch->ldb; -	u32 pixel_fmt; +	int dual = ldb->ldb_ctrl & LDB_SPLIT_MODE_EN; +	u32 bus_format; -	switch (imx_ldb_ch->chno) { -	case 0: -		pixel_fmt = (ldb->ldb_ctrl & LDB_DATA_WIDTH_CH0_24) ? -			V4L2_PIX_FMT_RGB24 : V4L2_PIX_FMT_BGR666; +	switch (imx_ldb_ch->bus_format) { +	default: +		dev_warn(ldb->dev, +			 "could not determine data mapping, default to 18-bit \"spwg\"\n"); +		/* fallthrough */ +	case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG: +		bus_format = MEDIA_BUS_FMT_RGB666_1X18;  		break; -	case 1: -		pixel_fmt = (ldb->ldb_ctrl & LDB_DATA_WIDTH_CH1_24) ? -			V4L2_PIX_FMT_RGB24 : V4L2_PIX_FMT_BGR666; +	case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG: +		bus_format = MEDIA_BUS_FMT_RGB888_1X24; +		if (imx_ldb_ch->chno == 0 || dual) +			ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH0_24; +		if (imx_ldb_ch->chno == 1 || dual) +			ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH1_24; +		break; +	case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA: +		bus_format = MEDIA_BUS_FMT_RGB888_1X24; +		if (imx_ldb_ch->chno == 0 || dual) +			ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH0_24 | +					 LDB_BIT_MAP_CH0_JEIDA; +		if (imx_ldb_ch->chno == 1 || dual) +			ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH1_24 | +					 LDB_BIT_MAP_CH1_JEIDA;  		break; -	default: -		dev_err(ldb->dev, "unable to config di%d panel format\n", -			imx_ldb_ch->chno); -		pixel_fmt = V4L2_PIX_FMT_RGB24;  	} -	imx_drm_panel_format(encoder, pixel_fmt); +	imx_drm_set_bus_format(encoder, bus_format);  }  static void imx_ldb_encoder_commit(struct drm_encoder *encoder) @@ -190,6 +217,8 @@ static void imx_ldb_encoder_commit(struct drm_encoder *encoder)  	int dual = ldb->ldb_ctrl & LDB_SPLIT_MODE_EN;  	int mux = imx_drm_encoder_get_mux_id(imx_ldb_ch->child, encoder); +	drm_panel_prepare(imx_ldb_ch->panel); +  	if (dual) {  		clk_prepare_enable(ldb->clk[0]);  		clk_prepare_enable(ldb->clk[1]); @@ -223,6 +252,8 @@ static void imx_ldb_encoder_commit(struct drm_encoder *encoder)  	}  	regmap_write(ldb->regmap, IOMUXC_GPR2, ldb->ldb_ctrl); + +	drm_panel_enable(imx_ldb_ch->panel);  }  static void imx_ldb_encoder_mode_set(struct drm_encoder *encoder, @@ -274,6 +305,7 @@ static void imx_ldb_encoder_disable(struct drm_encoder *encoder)  {  	struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder);  	struct imx_ldb *ldb = imx_ldb_ch->ldb; +	int mux, ret;  	/*  	 * imx_ldb_encoder_disable is called by @@ -287,6 +319,8 @@ static void imx_ldb_encoder_disable(struct drm_encoder *encoder)  		 (ldb->ldb_ctrl & LDB_CH1_MODE_EN_MASK) == 0)  		return; +	drm_panel_disable(imx_ldb_ch->panel); +  	if (imx_ldb_ch == &ldb->channel[0])  		ldb->ldb_ctrl &= ~LDB_CH0_MODE_EN_MASK;  	else if (imx_ldb_ch == &ldb->channel[1]) @@ -298,6 +332,30 @@ static void imx_ldb_encoder_disable(struct drm_encoder *encoder)  		clk_disable_unprepare(ldb->clk[0]);  		clk_disable_unprepare(ldb->clk[1]);  	} + +	if (ldb->lvds_mux) { +		const struct bus_mux *lvds_mux = NULL; + +		if (imx_ldb_ch == &ldb->channel[0]) +			lvds_mux = &ldb->lvds_mux[0]; +		else if (imx_ldb_ch == &ldb->channel[1]) +			lvds_mux = &ldb->lvds_mux[1]; + +		regmap_read(ldb->regmap, lvds_mux->reg, &mux); +		mux &= lvds_mux->mask; +		mux >>= lvds_mux->shift; +	} else { +		mux = (imx_ldb_ch == &ldb->channel[0]) ? 0 : 1; +	} + +	/* set display clock mux back to original input clock */ +	ret = clk_set_parent(ldb->clk_sel[mux], ldb->clk_parent[mux]); +	if (ret) +		dev_err(ldb->dev, +			"unable to set di%d parent clock to original parent\n", +			mux); + +	drm_panel_unprepare(imx_ldb_ch->panel);  }  static struct drm_connector_funcs imx_ldb_connector_funcs = { @@ -371,6 +429,9 @@ static int imx_ldb_register(struct drm_device *drm,  	drm_connector_init(drm, &imx_ldb_ch->connector,  			   &imx_ldb_connector_funcs, DRM_MODE_CONNECTOR_LVDS); +	if (imx_ldb_ch->panel) +		drm_panel_attach(imx_ldb_ch->panel, &imx_ldb_ch->connector); +  	drm_mode_connector_attach_encoder(&imx_ldb_ch->connector,  			&imx_ldb_ch->encoder); @@ -382,25 +443,39 @@ enum {  	LVDS_BIT_MAP_JEIDA  }; -static const char * const imx_ldb_bit_mappings[] = { -	[LVDS_BIT_MAP_SPWG]  = "spwg", -	[LVDS_BIT_MAP_JEIDA] = "jeida", +struct imx_ldb_bit_mapping { +	u32 bus_format; +	u32 datawidth; +	const char * const mapping; +}; + +static const struct imx_ldb_bit_mapping imx_ldb_bit_mappings[] = { +	{ MEDIA_BUS_FMT_RGB666_1X7X3_SPWG,  18, "spwg" }, +	{ MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,  24, "spwg" }, +	{ MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA, 24, "jeida" },  }; -static const int of_get_data_mapping(struct device_node *np) +static u32 of_get_bus_format(struct device *dev, struct device_node *np)  {  	const char *bm; +	u32 datawidth = 0;  	int ret, i;  	ret = of_property_read_string(np, "fsl,data-mapping", &bm);  	if (ret < 0)  		return ret; -	for (i = 0; i < ARRAY_SIZE(imx_ldb_bit_mappings); i++) -		if (!strcasecmp(bm, imx_ldb_bit_mappings[i])) -			return i; +	of_property_read_u32(np, "fsl,data-width", &datawidth); -	return -EINVAL; +	for (i = 0; i < ARRAY_SIZE(imx_ldb_bit_mappings); i++) { +		if (!strcasecmp(bm, imx_ldb_bit_mappings[i].mapping) && +		    datawidth == imx_ldb_bit_mappings[i].datawidth) +			return imx_ldb_bit_mappings[i].bus_format; +	} + +	dev_err(dev, "invalid data mapping: %d-bit \"%s\"\n", datawidth, bm); + +	return -ENOENT;  }  static struct bus_mux imx6q_lvds_mux[2] = { @@ -437,8 +512,6 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data)  	struct device_node *child;  	const u8 *edidp;  	struct imx_ldb *imx_ldb; -	int datawidth; -	int mapping;  	int dual;  	int ret;  	int i; @@ -479,12 +552,15 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data)  			imx_ldb->clk_sel[i] = NULL;  			break;  		} + +		imx_ldb->clk_parent[i] = clk_get_parent(imx_ldb->clk_sel[i]);  	}  	if (i == 0)  		return ret;  	for_each_child_of_node(np, child) {  		struct imx_ldb_channel *channel; +		struct device_node *port;  		ret = of_property_read_u32(child, "reg", &i);  		if (ret || i < 0 || i > 1) @@ -503,49 +579,53 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data)  		channel->chno = i;  		channel->child = child; +		/* +		 * The output port is port@4 with an external 4-port mux or +		 * port@2 with the internal 2-port mux. +		 */ +		port = of_graph_get_port_by_id(child, imx_ldb->lvds_mux ? 4 : 2); +		if (port) { +			struct device_node *endpoint, *remote; + +			endpoint = of_get_child_by_name(port, "endpoint"); +			if (endpoint) { +				remote = of_graph_get_remote_port_parent(endpoint); +				if (remote) +					channel->panel = of_drm_find_panel(remote); +				else +					return -EPROBE_DEFER; +				if (!channel->panel) { +					dev_err(dev, "panel not found: %s\n", +						remote->full_name); +					return -EPROBE_DEFER; +				} +			} +		} +  		edidp = of_get_property(child, "edid", &channel->edid_len);  		if (edidp) {  			channel->edid = kmemdup(edidp, channel->edid_len,  						GFP_KERNEL); -		} else { +		} else if (!channel->panel) {  			ret = of_get_drm_display_mode(child, &channel->mode, 0);  			if (!ret)  				channel->mode_valid = 1;  		} -		ret = of_property_read_u32(child, "fsl,data-width", &datawidth); -		if (ret) -			datawidth = 0; -		else if (datawidth != 18 && datawidth != 24) -			return -EINVAL; - -		mapping = of_get_data_mapping(child); -		switch (mapping) { -		case LVDS_BIT_MAP_SPWG: -			if (datawidth == 24) { -				if (i == 0 || dual) -					imx_ldb->ldb_ctrl |= -						LDB_DATA_WIDTH_CH0_24; -				if (i == 1 || dual) -					imx_ldb->ldb_ctrl |= -						LDB_DATA_WIDTH_CH1_24; -			} -			break; -		case LVDS_BIT_MAP_JEIDA: -			if (datawidth == 18) { -				dev_err(dev, "JEIDA standard only supported in 24 bit\n"); -				return -EINVAL; -			} -			if (i == 0 || dual) -				imx_ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH0_24 | -					LDB_BIT_MAP_CH0_JEIDA; -			if (i == 1 || dual) -				imx_ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH1_24 | -					LDB_BIT_MAP_CH1_JEIDA; -			break; -		default: -			dev_err(dev, "data mapping not specified or invalid\n"); -			return -EINVAL; +		channel->bus_format = of_get_bus_format(dev, child); +		if (channel->bus_format == -EINVAL) { +			/* +			 * If no bus format was specified in the device tree, +			 * we can still get it from the connected panel later. +			 */ +			if (channel->panel && channel->panel->funcs && +			    channel->panel->funcs->get_modes) +				channel->bus_format = 0; +		} +		if (channel->bus_format < 0) { +			dev_err(dev, "could not determine data mapping: %d\n", +				channel->bus_format); +			return channel->bus_format;  		}  		ret = imx_ldb_register(drm, channel); diff --git a/drivers/gpu/drm/imx/imx-tve.c b/drivers/gpu/drm/imx/imx-tve.c index 4216e479a9be..214eceefc981 100644 --- a/drivers/gpu/drm/imx/imx-tve.c +++ b/drivers/gpu/drm/imx/imx-tve.c @@ -301,11 +301,11 @@ static void imx_tve_encoder_prepare(struct drm_encoder *encoder)  	switch (tve->mode) {  	case TVE_MODE_VGA: -		imx_drm_panel_format_pins(encoder, IPU_PIX_FMT_GBR24, -				tve->hsync_pin, tve->vsync_pin); +		imx_drm_set_bus_format_pins(encoder, MEDIA_BUS_FMT_YUV8_1X24, +					    tve->hsync_pin, tve->vsync_pin);  		break;  	case TVE_MODE_TVOUT: -		imx_drm_panel_format(encoder, V4L2_PIX_FMT_YUV444); +		imx_drm_set_bus_format(encoder, MEDIA_BUS_FMT_YUV8_1X24);  		break;  	}  } diff --git a/drivers/gpu/drm/imx/ipuv3-crtc.c b/drivers/gpu/drm/imx/ipuv3-crtc.c index 98551e356e12..7bc8301fafff 100644 --- a/drivers/gpu/drm/imx/ipuv3-crtc.c +++ b/drivers/gpu/drm/imx/ipuv3-crtc.c @@ -45,7 +45,7 @@ struct ipu_crtc {  	struct drm_pending_vblank_event *page_flip_event;  	struct drm_framebuffer	*newfb;  	int			irq; -	u32			interface_pix_fmt; +	u32			bus_format;  	int			di_hsync_pin;  	int			di_vsync_pin;  }; @@ -145,7 +145,6 @@ static int ipu_crtc_mode_set(struct drm_crtc *crtc,  	struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);  	struct ipu_di_signal_cfg sig_cfg = {};  	unsigned long encoder_types = 0; -	u32 out_pixel_fmt;  	int ret;  	dev_dbg(ipu_crtc->dev, "%s: mode->hdisplay: %d\n", __func__, @@ -161,21 +160,21 @@ static int ipu_crtc_mode_set(struct drm_crtc *crtc,  		__func__, encoder_types);  	/* -	 * If we have DAC, TVDAC or LDB, then we need the IPU DI clock -	 * to be the same as the LDB DI clock. +	 * If we have DAC or LDB, then we need the IPU DI clock to be +	 * the same as the LDB DI clock. For TVDAC, derive the IPU DI +	 * clock from 27 MHz TVE_DI clock, but allow to divide it.  	 */  	if (encoder_types & (BIT(DRM_MODE_ENCODER_DAC) | -			     BIT(DRM_MODE_ENCODER_TVDAC) |  			     BIT(DRM_MODE_ENCODER_LVDS)))  		sig_cfg.clkflags = IPU_DI_CLKMODE_SYNC | IPU_DI_CLKMODE_EXT; +	else if (encoder_types & BIT(DRM_MODE_ENCODER_TVDAC)) +		sig_cfg.clkflags = IPU_DI_CLKMODE_EXT;  	else  		sig_cfg.clkflags = 0; -	out_pixel_fmt = ipu_crtc->interface_pix_fmt; -  	sig_cfg.enable_pol = 1;  	sig_cfg.clk_pol = 0; -	sig_cfg.pixel_fmt = out_pixel_fmt; +	sig_cfg.bus_format = ipu_crtc->bus_format;  	sig_cfg.v_to_h_sync = 0;  	sig_cfg.hsync_pin = ipu_crtc->di_hsync_pin;  	sig_cfg.vsync_pin = ipu_crtc->di_vsync_pin; @@ -184,7 +183,7 @@ static int ipu_crtc_mode_set(struct drm_crtc *crtc,  	ret = ipu_dc_init_sync(ipu_crtc->dc, ipu_crtc->di,  			       mode->flags & DRM_MODE_FLAG_INTERLACE, -			       out_pixel_fmt, mode->hdisplay); +			       ipu_crtc->bus_format, mode->hdisplay);  	if (ret) {  		dev_err(ipu_crtc->dev,  				"initializing display controller failed with %d\n", @@ -202,7 +201,8 @@ static int ipu_crtc_mode_set(struct drm_crtc *crtc,  	return ipu_plane_mode_set(ipu_crtc->plane[0], crtc, mode,  				  crtc->primary->fb,  				  0, 0, mode->hdisplay, mode->vdisplay, -				  x, y, mode->hdisplay, mode->vdisplay); +				  x, y, mode->hdisplay, mode->vdisplay, +				  mode->flags & DRM_MODE_FLAG_INTERLACE);  }  static void ipu_crtc_handle_pageflip(struct ipu_crtc *ipu_crtc) @@ -291,11 +291,11 @@ static void ipu_disable_vblank(struct drm_crtc *crtc)  }  static int ipu_set_interface_pix_fmt(struct drm_crtc *crtc, -		u32 pixfmt, int hsync_pin, int vsync_pin) +		u32 bus_format, int hsync_pin, int vsync_pin)  {  	struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc); -	ipu_crtc->interface_pix_fmt = pixfmt; +	ipu_crtc->bus_format = bus_format;  	ipu_crtc->di_hsync_pin = hsync_pin;  	ipu_crtc->di_vsync_pin = vsync_pin; diff --git a/drivers/gpu/drm/imx/ipuv3-plane.c b/drivers/gpu/drm/imx/ipuv3-plane.c index 6987e16fe99b..878a643d72e4 100644 --- a/drivers/gpu/drm/imx/ipuv3-plane.c +++ b/drivers/gpu/drm/imx/ipuv3-plane.c @@ -99,7 +99,7 @@ int ipu_plane_mode_set(struct ipu_plane *ipu_plane, struct drm_crtc *crtc,  		       struct drm_framebuffer *fb, int crtc_x, int crtc_y,  		       unsigned int crtc_w, unsigned int crtc_h,  		       uint32_t src_x, uint32_t src_y, -		       uint32_t src_w, uint32_t src_h) +		       uint32_t src_w, uint32_t src_h, bool interlaced)  {  	struct device *dev = ipu_plane->base.dev->dev;  	int ret; @@ -213,6 +213,8 @@ int ipu_plane_mode_set(struct ipu_plane *ipu_plane, struct drm_crtc *crtc,  	ret = ipu_plane_set_base(ipu_plane, fb, src_x, src_y);  	if (ret < 0)  		return ret; +	if (interlaced) +		ipu_cpmem_interlaced_scan(ipu_plane->ipu_ch, fb->pitches[0]);  	ipu_plane->w = src_w;  	ipu_plane->h = src_h; @@ -312,7 +314,8 @@ static int ipu_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,  	ret = ipu_plane_mode_set(ipu_plane, crtc, &crtc->hwmode, fb,  			crtc_x, crtc_y, crtc_w, crtc_h, -			src_x >> 16, src_y >> 16, src_w >> 16, src_h >> 16); +			src_x >> 16, src_y >> 16, src_w >> 16, src_h >> 16, +			false);  	if (ret < 0) {  		ipu_plane_put_resources(ipu_plane);  		return ret; diff --git a/drivers/gpu/drm/imx/ipuv3-plane.h b/drivers/gpu/drm/imx/ipuv3-plane.h index af125fb40ef5..9b5eff18f5b8 100644 --- a/drivers/gpu/drm/imx/ipuv3-plane.h +++ b/drivers/gpu/drm/imx/ipuv3-plane.h @@ -42,7 +42,7 @@ int ipu_plane_mode_set(struct ipu_plane *plane, struct drm_crtc *crtc,  		       struct drm_framebuffer *fb, int crtc_x, int crtc_y,  		       unsigned int crtc_w, unsigned int crtc_h,  		       uint32_t src_x, uint32_t src_y, uint32_t src_w, -		       uint32_t src_h); +		       uint32_t src_h, bool interlaced);  void ipu_plane_enable(struct ipu_plane *plane);  void ipu_plane_disable(struct ipu_plane *plane); diff --git a/drivers/gpu/drm/imx/parallel-display.c b/drivers/gpu/drm/imx/parallel-display.c index 900dda6a8e71..74a9ce40ddc4 100644 --- a/drivers/gpu/drm/imx/parallel-display.c +++ b/drivers/gpu/drm/imx/parallel-display.c @@ -33,7 +33,7 @@ struct imx_parallel_display {  	struct device *dev;  	void *edid;  	int edid_len; -	u32 interface_pix_fmt; +	u32 bus_format;  	int mode_valid;  	struct drm_display_mode mode;  	struct drm_panel *panel; @@ -118,7 +118,7 @@ static void imx_pd_encoder_prepare(struct drm_encoder *encoder)  {  	struct imx_parallel_display *imxpd = enc_to_imxpd(encoder); -	imx_drm_panel_format(encoder, imxpd->interface_pix_fmt); +	imx_drm_set_bus_format(encoder, imxpd->bus_format);  }  static void imx_pd_encoder_commit(struct drm_encoder *encoder) @@ -225,14 +225,13 @@ static int imx_pd_bind(struct device *dev, struct device *master, void *data)  	ret = of_property_read_string(np, "interface-pix-fmt", &fmt);  	if (!ret) {  		if (!strcmp(fmt, "rgb24")) -			imxpd->interface_pix_fmt = V4L2_PIX_FMT_RGB24; +			imxpd->bus_format = MEDIA_BUS_FMT_RGB888_1X24;  		else if (!strcmp(fmt, "rgb565")) -			imxpd->interface_pix_fmt = V4L2_PIX_FMT_RGB565; +			imxpd->bus_format = MEDIA_BUS_FMT_RGB565_1X16;  		else if (!strcmp(fmt, "bgr666")) -			imxpd->interface_pix_fmt = V4L2_PIX_FMT_BGR666; +			imxpd->bus_format = MEDIA_BUS_FMT_RGB666_1X18;  		else if (!strcmp(fmt, "lvds666")) -			imxpd->interface_pix_fmt = -					v4l2_fourcc('L', 'V', 'D', '6'); +			imxpd->bus_format = MEDIA_BUS_FMT_RGB666_1X24_CPADHI;  	}  	panel_node = of_parse_phandle(np, "fsl,panel", 0); | 
