Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit dc80d703 authored by Peter Senna Tschudin's avatar Peter Senna Tschudin Committed by Philipp Zabel
Browse files

drm/imx-ldb: Add support to drm-bridge



Add support to attach a drm_bridge to imx-ldb in addition to
existing support to attach a LVDS panel.

This patch does a simple code refactoring by moving code
from for_each_child_of_node iterator to a new function named
imx_ldb_panel_ddc(). This was necessary to allow the panel ddc
code to run only when the imx_ldb is not attached to a bridge.

Cc: Enric Balletbo i Serra <enric.balletbo@collabora.com>
Cc: Philipp Zabel <p.zabel@pengutronix.de>
Cc: Rob Herring <robh@kernel.org>
Cc: Fabio Estevam <fabio.estevam@nxp.com>
Cc: David Airlie <airlied@linux.ie>
Cc: Thierry Reding <treding@nvidia.com>
Cc: Thierry Reding <thierry.reding@gmail.com>
Signed-off-by: default avatarPeter Senna Tschudin <peter.senna@collabora.com>
Signed-off-by: default avatarPhilipp Zabel <p.zabel@pengutronix.de>
parent 3a2ad502
Loading
Loading
Loading
Loading
+79 −41
Original line number Original line Diff line number Diff line
@@ -57,7 +57,11 @@ struct imx_ldb_channel {
	struct imx_ldb *ldb;
	struct imx_ldb *ldb;
	struct drm_connector connector;
	struct drm_connector connector;
	struct drm_encoder encoder;
	struct drm_encoder encoder;

	/* Defines what is connected to the ldb, only one at a time */
	struct drm_panel *panel;
	struct drm_panel *panel;
	struct drm_bridge *bridge;

	struct device_node *child;
	struct device_node *child;
	struct i2c_adapter *ddc;
	struct i2c_adapter *ddc;
	int chno;
	int chno;
@@ -468,10 +472,30 @@ static int imx_ldb_register(struct drm_device *drm,
	drm_encoder_init(drm, encoder, &imx_ldb_encoder_funcs,
	drm_encoder_init(drm, encoder, &imx_ldb_encoder_funcs,
			 DRM_MODE_ENCODER_LVDS, NULL);
			 DRM_MODE_ENCODER_LVDS, NULL);


	if (imx_ldb_ch->bridge) {
		imx_ldb_ch->bridge->encoder = encoder;

		imx_ldb_ch->encoder.bridge = imx_ldb_ch->bridge;
		ret = drm_bridge_attach(drm, imx_ldb_ch->bridge);
		if (ret) {
			DRM_ERROR("Failed to initialize bridge with drm\n");
			return ret;
		}
	} else {
		/*
		 * We want to add the connector whenever there is no bridge
		 * that brings its own, not only when there is a panel. For
		 * historical reasons, the ldb driver can also work without
		 * a panel.
		 */
		drm_connector_helper_add(&imx_ldb_ch->connector,
		drm_connector_helper_add(&imx_ldb_ch->connector,
				&imx_ldb_connector_helper_funcs);
				&imx_ldb_connector_helper_funcs);
		drm_connector_init(drm, &imx_ldb_ch->connector,
		drm_connector_init(drm, &imx_ldb_ch->connector,
			   &imx_ldb_connector_funcs, DRM_MODE_CONNECTOR_LVDS);
				&imx_ldb_connector_funcs,
				DRM_MODE_CONNECTOR_LVDS);
		drm_mode_connector_attach_encoder(&imx_ldb_ch->connector,
				encoder);
	}


	if (imx_ldb_ch->panel) {
	if (imx_ldb_ch->panel) {
		ret = drm_panel_attach(imx_ldb_ch->panel,
		ret = drm_panel_attach(imx_ldb_ch->panel,
@@ -480,8 +504,6 @@ static int imx_ldb_register(struct drm_device *drm,
			return ret;
			return ret;
	}
	}


	drm_mode_connector_attach_encoder(&imx_ldb_ch->connector, encoder);

	return 0;
	return 0;
}
}


@@ -550,6 +572,46 @@ static const struct of_device_id imx_ldb_dt_ids[] = {
};
};
MODULE_DEVICE_TABLE(of, imx_ldb_dt_ids);
MODULE_DEVICE_TABLE(of, imx_ldb_dt_ids);


static int imx_ldb_panel_ddc(struct device *dev,
		struct imx_ldb_channel *channel, struct device_node *child)
{
	struct device_node *ddc_node;
	const u8 *edidp;
	int ret;

	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,
						      &channel->bus_flags,
						      OF_USE_NATIVE_MODE);
			if (!ret)
				channel->mode_valid = 1;
		}
	}
	return 0;
}

static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
{
{
	struct drm_device *drm = data;
	struct drm_device *drm = data;
@@ -557,7 +619,6 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
	const struct of_device_id *of_id =
	const struct of_device_id *of_id =
			of_match_device(imx_ldb_dt_ids, dev);
			of_match_device(imx_ldb_dt_ids, dev);
	struct device_node *child;
	struct device_node *child;
	const u8 *edidp;
	struct imx_ldb *imx_ldb;
	struct imx_ldb *imx_ldb;
	int dual;
	int dual;
	int ret;
	int ret;
@@ -607,7 +668,6 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data)


	for_each_child_of_node(np, child) {
	for_each_child_of_node(np, child) {
		struct imx_ldb_channel *channel;
		struct imx_ldb_channel *channel;
		struct device_node *ddc_node;
		struct device_node *ep;
		struct device_node *ep;
		int bus_format;
		int bus_format;


@@ -640,47 +700,25 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data)


			remote = of_graph_get_remote_port_parent(ep);
			remote = of_graph_get_remote_port_parent(ep);
			of_node_put(ep);
			of_node_put(ep);
			if (remote)
			if (remote) {
				channel->panel = of_drm_find_panel(remote);
				channel->panel = of_drm_find_panel(remote);
			else
				channel->bridge = of_drm_find_bridge(remote);
			} else
				return -EPROBE_DEFER;
				return -EPROBE_DEFER;
			of_node_put(remote);
			of_node_put(remote);
			if (!channel->panel) {
				dev_err(dev, "panel not found: %s\n",
					remote->full_name);
				return -EPROBE_DEFER;
			}
		}


		ddc_node = of_parse_phandle(child, "ddc-i2c-bus", 0);
			if (!channel->panel && !channel->bridge) {
		if (ddc_node) {
				dev_err(dev, "panel/bridge not found: %s\n",
			channel->ddc = of_find_i2c_adapter_by_node(ddc_node);
					remote->full_name);
			of_node_put(ddc_node);
			if (!channel->ddc) {
				dev_warn(dev, "failed to get ddc i2c adapter\n");
				return -EPROBE_DEFER;
				return -EPROBE_DEFER;
			}
			}
		}
		}


		if (!channel->ddc) {
		/* panel ddc only if there is no bridge */
			/* if no DDC available, fallback to hardcoded EDID */
		if (!channel->bridge) {
			dev_dbg(dev, "no ddc available\n");
			ret = imx_ldb_panel_ddc(dev, channel, child);

			if (ret)
			edidp = of_get_property(child, "edid",
				return ret;
						&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,
							      &channel->bus_flags,
							      OF_USE_NATIVE_MODE);
				if (!ret)
					channel->mode_valid = 1;
			}
		}
		}


		bus_format = of_get_bus_format(dev, child);
		bus_format = of_get_bus_format(dev, child);