diff options
Diffstat (limited to 'drivers/gpu/drm/imx/imx-ldb.c')
| -rw-r--r-- | drivers/gpu/drm/imx/imx-ldb.c | 78 | 
1 files changed, 53 insertions, 25 deletions
diff --git a/drivers/gpu/drm/imx/imx-ldb.c b/drivers/gpu/drm/imx/imx-ldb.c index a58eee59550a..beff793bb717 100644 --- a/drivers/gpu/drm/imx/imx-ldb.c +++ b/drivers/gpu/drm/imx/imx-ldb.c @@ -25,6 +25,7 @@  #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>  #include <linux/of_device.h>  #include <linux/of_graph.h> +#include <video/of_display_timing.h>  #include <video/of_videomode.h>  #include <linux/regmap.h>  #include <linux/videodev2.h> @@ -59,6 +60,7 @@ struct imx_ldb_channel {  	struct drm_encoder encoder;  	struct drm_panel *panel;  	struct device_node *child; +	struct i2c_adapter *ddc;  	int chno;  	void *edid;  	int edid_len; @@ -107,6 +109,9 @@ static int imx_ldb_connector_get_modes(struct drm_connector *connector)  			return num_modes;  	} +	if (!imx_ldb_ch->edid && imx_ldb_ch->ddc) +		imx_ldb_ch->edid = drm_get_edid(connector, imx_ldb_ch->ddc); +  	if (imx_ldb_ch->edid) {  		drm_mode_connector_update_edid_property(connector,  							imx_ldb_ch->edid); @@ -553,7 +558,8 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data)  	for_each_child_of_node(np, child) {  		struct imx_ldb_channel *channel; -		struct device_node *port; +		struct device_node *ddc_node; +		struct device_node *ep;  		ret = of_property_read_u32(child, "reg", &i);  		if (ret || i < 0 || i > 1) @@ -576,33 +582,54 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data)  		 * 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; -				} +		ep = of_graph_get_endpoint_by_regs(child, +						   imx_ldb->lvds_mux ? 4 : 2, +						   -1); +		if (ep) { +			struct device_node *remote; + +			remote = of_graph_get_remote_port_parent(ep); +			of_node_put(ep); +			if (remote) +				channel->panel = of_drm_find_panel(remote); +			else +				return -EPROBE_DEFER; +			of_node_put(remote); +			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 if (!channel->panel) { -			ret = of_get_drm_display_mode(child, &channel->mode, 0); -			if (!ret) -				channel->mode_valid = 1; +		ddc_node = of_parse_phandle(child, "ddc-i2c-bus", 0); +		if (ddc_node) { +			channel->ddc = of_find_i2c_adapter_by_node(ddc_node); +			of_node_put(ddc_node); +			if (!channel->ddc) { +				dev_warn(dev, "failed to get ddc i2c adapter\n"); +				return -EPROBE_DEFER; +			} +		} + +		if (!channel->ddc) { +			/* if no DDC available, fallback to hardcoded EDID */ +			dev_dbg(dev, "no ddc available\n"); + +			edidp = of_get_property(child, "edid", +						&channel->edid_len); +			if (edidp) { +				channel->edid = kmemdup(edidp, +							channel->edid_len, +							GFP_KERNEL); +			} else if (!channel->panel) { +				/* fallback to display-timings node */ +				ret = of_get_drm_display_mode(child, +							      &channel->mode, +							      OF_USE_NATIVE_MODE); +				if (!ret) +					channel->mode_valid = 1; +			}  		}  		channel->bus_format = of_get_bus_format(dev, child); @@ -647,6 +674,7 @@ static void imx_ldb_unbind(struct device *dev, struct device *master,  		channel->encoder.funcs->destroy(&channel->encoder);  		kfree(channel->edid); +		i2c_put_adapter(channel->ddc);  	}  }  |