diff mbox

[PATCH/RFC,v3,05/19] video: display: Graph helpers

Message ID 1376068510-30363-6-git-send-email-laurent.pinchart+renesas@ideasonboard.com (mailing list archive)
State New, archived
Headers show

Commit Message

Laurent Pinchart Aug. 9, 2013, 5:14 p.m. UTC
Add two graph helper functions. display_entity_build_notifier() builds
an entity notifier from an entities graph represented as a flat array,
typically passed from platform data. display_entity_link_graph() can
then be used to create media controller links between all entities in
the graph.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/video/display/display-core.c     | 107 +++++++++++++++++++++++++++++++
 drivers/video/display/display-notifier.c |  51 +++++++++++++++
 include/video/display.h                  |  20 ++++++
 3 files changed, 178 insertions(+)
diff mbox

Patch

diff --git a/drivers/video/display/display-core.c b/drivers/video/display/display-core.c
index bb18723..c3b47d3 100644
--- a/drivers/video/display/display-core.c
+++ b/drivers/video/display/display-core.c
@@ -10,6 +10,7 @@ 
  * published by the Free Software Foundation.
  */
 
+#include <linux/device.h>
 #include <linux/export.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
@@ -313,6 +314,112 @@  void display_entity_unregister(struct display_entity *entity)
 }
 EXPORT_SYMBOL_GPL(display_entity_unregister);
 
+/* -----------------------------------------------------------------------------
+ * Graph Helpers
+ */
+
+static int display_entity_link_entity(struct device *dev,
+				      struct display_entity *entity,
+				      struct list_head *entities)
+{
+	const struct display_entity_graph_data *graph = entity->match->data;
+	u32 link_flags = MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED;
+	struct media_entity *local = &entity->entity;
+	unsigned int i;
+	int ret = 0;
+
+	dev_dbg(dev, "creating links for entity %s\n", local->name);
+
+	for (i = 0; i < entity->entity.num_pads; ++i) {
+		const struct display_entity_source_data *source;
+		struct media_pad *local_pad = &local->pads[i];
+		struct media_entity *remote = NULL;
+		struct media_pad *remote_pad;
+		struct display_entity *ent;
+
+		dev_dbg(dev, "processing pad %u\n", i);
+
+		/* Skip source pads, they will be processed from the other end
+		 * of the link.
+		 */
+		if (local_pad->flags & MEDIA_PAD_FL_SOURCE) {
+			dev_dbg(dev, "skipping source pad %s:%u\n",
+				local->name, i);
+			continue;
+		}
+
+		/* Find the remote entity. If not found, just skip the link as
+		 * it goes out of scope of the entities handled by the notifier.
+		 */
+		source = &graph->sources[i];
+		list_for_each_entry(ent, entities, list) {
+			if (strcmp(source->name, dev_name(ent->dev)) == 0) {
+				remote = &ent->entity;
+				break;
+			}
+		}
+
+		if (remote == NULL) {
+			dev_dbg(dev, "no entity found for %s\n", source->name);
+			continue;
+		}
+
+		if (source->port >= remote->num_pads) {
+			dev_err(dev, "invalid port number %u on %s\n",
+				source->port, source->name);
+			ret = -EINVAL;
+			break;
+		}
+
+		remote_pad = &remote->pads[source->port];
+
+		/* Create the media link. */
+		dev_dbg(dev, "creating %s:%u -> %s:%u link\n",
+			remote->name, remote_pad->index,
+			local->name, local_pad->index);
+
+		ret = media_entity_create_link(remote, remote_pad->index,
+					       local, local_pad->index,
+					       link_flags);
+		if (ret < 0) {
+			dev_err(dev, "failed to create %s:%u -> %s:%u link\n",
+				remote->name, remote_pad->index,
+				local->name, local_pad->index);
+			break;
+		}
+	}
+
+	return ret;
+}
+
+/**
+ * display_entity_link_graph - Link all entities in a graph
+ * @dev: device used to print debugging and error messages
+ * @entities: list of display entities in the graph
+ *
+ * This function creates media controller links for all entities in a graph
+ * based on graph link data. It relies on the entities match data pointers
+ * having been initialized by the display_entity_build_notifier() function when
+ * building the notifier and thus can't be used when the notifier is built in a
+ * different way.
+ *
+ * Return 0 on success or a negative error code otherwise.
+ */
+int display_entity_link_graph(struct device *dev, struct list_head *entities)
+{
+	struct display_entity *entity;
+	int ret;
+
+	list_for_each_entry(entity, entities, list) {
+		ret = display_entity_link_entity(dev, entity, entities);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(display_entity_link_graph);
+
 MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
 MODULE_DESCRIPTION("Display Core");
 MODULE_LICENSE("GPL");
diff --git a/drivers/video/display/display-notifier.c b/drivers/video/display/display-notifier.c
index c9210ec..2d752b3 100644
--- a/drivers/video/display/display-notifier.c
+++ b/drivers/video/display/display-notifier.c
@@ -220,6 +220,57 @@  void display_entity_unregister_notifier(struct display_entity_notifier *notifier
 }
 EXPORT_SYMBOL_GPL(display_entity_unregister_notifier);
 
+/**
+ * display_entity_build_notifier - build a notifier from graph data
+ * @notifier: display entity notifier to be built
+ * @graph: graph data
+ *
+ * Before registering a notifier drivers must initialize the notifier's list of
+ * entities. This helper function simplifies building the list of entities for
+ * drivers that use an array of struct display_entity_graph_data to describe the
+ * entities graph.
+ *
+ * The function allocates an array of struct display_entity_match, initialize it
+ * from graph data, and sets the notifier entities and num_entities fields.
+ *
+ * The entities array is allocated using the managed memory allocation API on
+ * the notifier device, which must be initialized before calling this function.
+ *
+ * Return 0 on success or a negative error code on error.
+ */
+int display_entity_build_notifier(struct display_entity_notifier *notifier,
+				  const struct display_entity_graph_data *graph)
+{
+	struct display_entity_match *entities;
+	unsigned int num_entities;
+	unsigned int i;
+
+	for (num_entities = 0; graph[num_entities].name; ++num_entities) {
+	}
+
+	if (num_entities == 0)
+		return -EINVAL;
+
+	entities = devm_kzalloc(notifier->dev, sizeof(*notifier->entities) *
+				num_entities, GFP_KERNEL);
+	if (entities == NULL)
+		return -ENOMEM;
+
+	for (i = 0; i < num_entities; ++i) {
+		struct display_entity_match *match = &entities[i];
+
+		match->type = DISPLAY_ENTITY_BUS_PLATFORM;
+		match->match.platform.name = graph[i].name;
+		match->data = &graph[i];
+	}
+
+	notifier->num_entities = num_entities;
+	notifier->entities = entities;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(display_entity_build_notifier);
+
 /* -----------------------------------------------------------------------------
  * Entity Registration
  */
diff --git a/include/video/display.h b/include/video/display.h
index 2063694..58ff0d1 100644
--- a/include/video/display.h
+++ b/include/video/display.h
@@ -159,6 +159,7 @@  enum display_entity_bus_type {
  * @match.platform.name: platform device name
  * @match.dt.node: DT node
  * @list: link match objects waiting to be matched
+ * @data: driver private data, not touched by the core
  */
 struct display_entity_match {
 	enum display_entity_bus_type type;
@@ -169,6 +170,7 @@  struct display_entity_match {
 	} match;
 
 	struct list_head list;
+	const void *data;
 };
 
 /**
@@ -206,4 +208,22 @@  void display_entity_unregister_notifier(struct display_entity_notifier *notifier
 int display_entity_add(struct display_entity *entity);
 void display_entity_remove(struct display_entity *entity);
 
+/* -----------------------------------------------------------------------------
+ * Graph Helpers
+ */
+
+struct display_entity_source_data {
+	const char *name;
+	unsigned int port;
+};
+
+struct display_entity_graph_data {
+	const char *name;
+	const struct display_entity_source_data *sources;
+};
+
+int display_entity_build_notifier(struct display_entity_notifier *notifier,
+				  const struct display_entity_graph_data *graph);
+int display_entity_link_graph(struct device *dev, struct list_head *entities);
+
 #endif /* __DISPLAY_H__ */