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

Commit 2f2d2702 authored by Russell King's avatar Russell King
Browse files

Merge branches 'drm-devel' and 'component-for-driver' into armada-drm

Loading
Loading
Loading
Loading
+157 −35
Original line number Diff line number Diff line
@@ -18,6 +18,15 @@
#include <linux/mutex.h>
#include <linux/slab.h>

struct component_match {
	size_t alloc;
	size_t num;
	struct {
		void *data;
		int (*fn)(struct device *, void *);
	} compare[0];
};

struct master {
	struct list_head node;
	struct list_head components;
@@ -25,6 +34,7 @@ struct master {

	const struct component_master_ops *ops;
	struct device *dev;
	struct component_match *match;
};

struct component {
@@ -69,6 +79,11 @@ static void component_detach_master(struct master *master, struct component *c)
	c->master = NULL;
}

/*
 * Add a component to a master, finding the component via the compare
 * function and compare data.  This is safe to call for duplicate matches
 * and will not result in the same component being added multiple times.
 */
int component_master_add_child(struct master *master,
	int (*compare)(struct device *, void *), void *compare_data)
{
@@ -76,10 +91,11 @@ int component_master_add_child(struct master *master,
	int ret = -ENXIO;

	list_for_each_entry(c, &component_list, node) {
		if (c->master)
		if (c->master && c->master != master)
			continue;

		if (compare(c->dev, compare_data)) {
			if (!c->master)
				component_attach_master(master, c);
			ret = 0;
			break;
@@ -90,6 +106,34 @@ int component_master_add_child(struct master *master,
}
EXPORT_SYMBOL_GPL(component_master_add_child);

static int find_components(struct master *master)
{
	struct component_match *match = master->match;
	size_t i;
	int ret = 0;

	if (!match) {
		/*
		 * Search the list of components, looking for components that
		 * belong to this master, and attach them to the master.
		 */
		return master->ops->add_components(master->dev, master);
	}

	/*
	 * Scan the array of match functions and attach
	 * any components which are found to this master.
	 */
	for (i = 0; i < match->num; i++) {
		ret = component_master_add_child(master,
						 match->compare[i].fn,
						 match->compare[i].data);
		if (ret)
			break;
	}
	return ret;
}

/* Detach all attached components from this master */
static void master_remove_components(struct master *master)
{
@@ -113,22 +157,22 @@ static void master_remove_components(struct master *master)
static int try_to_bring_up_master(struct master *master,
	struct component *component)
{
	int ret = 0;
	int ret;

	if (master->bound)
		return 0;

	if (!master->bound) {
	/*
	 * Search the list of components, looking for components that
	 * belong to this master, and attach them to the master.
	 */
		if (master->ops->add_components(master->dev, master)) {
	if (find_components(master)) {
		/* Failed to find all components */
			master_remove_components(master);
		ret = 0;
		goto out;
	}

	if (component && component->master != master) {
			master_remove_components(master);
		ret = 0;
		goto out;
	}
@@ -143,14 +187,14 @@ static int try_to_bring_up_master(struct master *master,
	if (ret < 0) {
		devres_release_group(master->dev, NULL);
		dev_info(master->dev, "master bind failed: %d\n", ret);
			master_remove_components(master);
		goto out;
	}

	master->bound = true;
		ret = 1;
	}
	return 1;

out:
	master_remove_components(master);

	return ret;
}
@@ -180,18 +224,89 @@ static void take_down_master(struct master *master)
	master_remove_components(master);
}

int component_master_add(struct device *dev,
	const struct component_master_ops *ops)
static size_t component_match_size(size_t num)
{
	return offsetof(struct component_match, compare[num]);
}

static struct component_match *component_match_realloc(struct device *dev,
	struct component_match *match, size_t num)
{
	struct component_match *new;

	if (match && match->alloc == num)
		return match;

	new = devm_kmalloc(dev, component_match_size(num), GFP_KERNEL);
	if (!new)
		return ERR_PTR(-ENOMEM);

	if (match) {
		memcpy(new, match, component_match_size(min(match->num, num)));
		devm_kfree(dev, match);
	} else {
		new->num = 0;
	}

	new->alloc = num;

	return new;
}

/*
 * Add a component to be matched.
 *
 * The match array is first created or extended if necessary.
 */
void component_match_add(struct device *dev, struct component_match **matchptr,
	int (*compare)(struct device *, void *), void *compare_data)
{
	struct component_match *match = *matchptr;

	if (IS_ERR(match))
		return;

	if (!match || match->num == match->alloc) {
		size_t new_size = match ? match->alloc + 16 : 15;

		match = component_match_realloc(dev, match, new_size);

		*matchptr = match;

		if (IS_ERR(match))
			return;
	}

	match->compare[match->num].fn = compare;
	match->compare[match->num].data = compare_data;
	match->num++;
}
EXPORT_SYMBOL(component_match_add);

int component_master_add_with_match(struct device *dev,
	const struct component_master_ops *ops,
	struct component_match *match)
{
	struct master *master;
	int ret;

	if (ops->add_components && match)
		return -EINVAL;

	if (match) {
		/* Reallocate the match array for its true size */
		match = component_match_realloc(dev, match, match->num);
		if (IS_ERR(match))
			return PTR_ERR(match);
	}

	master = kzalloc(sizeof(*master), GFP_KERNEL);
	if (!master)
		return -ENOMEM;

	master->dev = dev;
	master->ops = ops;
	master->match = match;
	INIT_LIST_HEAD(&master->components);

	/* Add to the list of available masters. */
@@ -209,6 +324,13 @@ int component_master_add(struct device *dev,

	return ret < 0 ? ret : 0;
}
EXPORT_SYMBOL_GPL(component_master_add_with_match);

int component_master_add(struct device *dev,
	const struct component_master_ops *ops)
{
	return component_master_add_with_match(dev, ops, NULL);
}
EXPORT_SYMBOL_GPL(component_master_add);

void component_master_del(struct device *dev,
+1 −0
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ drm-$(CONFIG_COMPAT) += drm_ioc32.o
drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o
drm-$(CONFIG_PCI) += ati_pcigart.o
drm-$(CONFIG_DRM_PANEL) += drm_panel.o
drm-$(CONFIG_OF) += drm_of.o

drm-usb-y   := drm_usb.o

+67 −0
Original line number Diff line number Diff line
#include <linux/export.h>
#include <linux/list.h>
#include <linux/of_graph.h>
#include <drm/drmP.h>
#include <drm/drm_crtc.h>
#include <drm/drm_of.h>

/**
 * drm_crtc_port_mask - find the mask of a registered CRTC by port OF node
 * @dev: DRM device
 * @port: port OF node
 *
 * Given a port OF node, return the possible mask of the corresponding
 * CRTC within a device's list of CRTCs.  Returns zero if not found.
 */
static uint32_t drm_crtc_port_mask(struct drm_device *dev,
				   struct device_node *port)
{
	unsigned int index = 0;
	struct drm_crtc *tmp;

	list_for_each_entry(tmp, &dev->mode_config.crtc_list, head) {
		if (tmp->port == port)
			return 1 << index;

		index++;
	}

	return 0;
}

/**
 * drm_of_find_possible_crtcs - find the possible CRTCs for an encoder port
 * @dev: DRM device
 * @port: encoder port to scan for endpoints
 *
 * Scan all endpoints attached to a port, locate their attached CRTCs,
 * and generate the DRM mask of CRTCs which may be attached to this
 * encoder.
 *
 * See Documentation/devicetree/bindings/graph.txt for the bindings.
 */
uint32_t drm_of_find_possible_crtcs(struct drm_device *dev,
				    struct device_node *port)
{
	struct device_node *remote_port, *ep = NULL;
	uint32_t possible_crtcs = 0;

	do {
		ep = of_graph_get_next_endpoint(port, ep);
		if (!ep)
			break;

		remote_port = of_graph_get_remote_port(ep);
		if (!remote_port) {
			of_node_put(ep);
			return 0;
		}

		possible_crtcs |= drm_crtc_port_mask(dev, remote_port);

		of_node_put(remote_port);
	} while (1);

	return possible_crtcs;
}
EXPORT_SYMBOL(drm_of_find_possible_crtcs);
+2 −0
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@ struct drm_framebuffer;
struct drm_object_properties;
struct drm_file;
struct drm_clip_rect;
struct device_node;

#define DRM_MODE_OBJECT_CRTC 0xcccccccc
#define DRM_MODE_OBJECT_CONNECTOR 0xc0c0c0c0
@@ -314,6 +315,7 @@ struct drm_crtc_funcs {
 */
struct drm_crtc {
	struct drm_device *dev;
	struct device_node *port;
	struct list_head head;

	/**

include/drm/drm_of.h

0 → 100644
+18 −0
Original line number Diff line number Diff line
#ifndef __DRM_OF_H__
#define __DRM_OF_H__

struct drm_device;
struct device_node;

#ifdef CONFIG_OF
extern uint32_t drm_of_find_possible_crtcs(struct drm_device *dev,
					   struct device_node *port);
#else
static inline uint32_t drm_of_find_possible_crtcs(struct drm_device *dev,
						  struct device_node *port)
{
	return 0;
}
#endif

#endif /* __DRM_OF_H__ */
Loading