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

Commit 79389a83 authored by Mika Westerberg's avatar Mika Westerberg Committed by Rafael J. Wysocki
Browse files

ACPI / property: Add support for remote endpoints



DT has had concept of remote endpoints for some time already. It makes
possible to reference another firmware node through a property called
remote-endpoint. This is already used by some subsystems like v4l2 for
parsing hardware properties related to camera.

This patch adds ACPI support for remote endpoints utilizing _DSD
hierarchical data extensions.

Signed-off-by: default avatarMika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: default avatarSakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
parent 21ea73f5
Loading
Loading
Loading
Loading
+138 −0
Original line number Original line Diff line number Diff line
@@ -969,3 +969,141 @@ struct fwnode_handle *acpi_node_get_parent(struct fwnode_handle *fwnode)


	return NULL;
	return NULL;
}
}

/**
 * acpi_graph_get_next_endpoint - Get next endpoint ACPI firmware node
 * @fwnode: Pointer to the parent firmware node
 * @prev: Previous endpoint node or %NULL to get the first
 *
 * Looks up next endpoint ACPI firmware node below a given @fwnode. Returns
 * %NULL if there is no next endpoint, ERR_PTR() in case of error. In case
 * of success the next endpoint is returned.
 */
struct fwnode_handle *acpi_graph_get_next_endpoint(struct fwnode_handle *fwnode,
						   struct fwnode_handle *prev)
{
	struct fwnode_handle *port = NULL;
	struct fwnode_handle *endpoint;

	if (!prev) {
		do {
			port = fwnode_get_next_child_node(fwnode, port);
			/* Ports must have port property */
			if (fwnode_property_present(port, "port"))
				break;
		} while (port);
	} else {
		port = fwnode_get_parent(prev);
	}

	if (!port)
		return NULL;

	endpoint = fwnode_get_next_child_node(port, prev);
	while (!endpoint) {
		port = fwnode_get_next_child_node(fwnode, port);
		if (!port)
			break;
		if (fwnode_property_present(port, "port"))
			endpoint = fwnode_get_next_child_node(port, NULL);
	}

	if (endpoint) {
		/* Endpoints must have "endpoint" property */
		if (!fwnode_property_present(endpoint, "endpoint"))
			return ERR_PTR(-EPROTO);
	}

	return endpoint;
}

/**
 * acpi_graph_get_child_prop_value - Return a child with a given property value
 * @fwnode: device fwnode
 * @prop_name: The name of the property to look for
 * @val: the desired property value
 *
 * Return the port node corresponding to a given port number. Returns
 * the child node on success, NULL otherwise.
 */
static struct fwnode_handle *acpi_graph_get_child_prop_value(
	struct fwnode_handle *fwnode, const char *prop_name, unsigned int val)
{
	struct fwnode_handle *child;

	fwnode_for_each_child_node(fwnode, child) {
		u32 nr;

		if (!fwnode_property_read_u32(fwnode, prop_name, &nr))
			continue;

		if (val == nr)
			return child;
	}

	return NULL;
}


/**
 * acpi_graph_get_remote_enpoint - Parses and returns remote end of an endpoint
 * @fwnode: Endpoint firmware node pointing to a remote device
 * @parent: Firmware node of remote port parent is filled here if not %NULL
 * @port: Firmware node of remote port is filled here if not %NULL
 * @endpoint: Firmware node of remote endpoint is filled here if not %NULL
 *
 * Function parses remote end of ACPI firmware remote endpoint and fills in
 * fields requested by the caller. Returns %0 in case of success and
 * negative errno otherwise.
 */
int acpi_graph_get_remote_endpoint(struct fwnode_handle *fwnode,
				   struct fwnode_handle **parent,
				   struct fwnode_handle **port,
				   struct fwnode_handle **endpoint)
{
	unsigned int port_nr, endpoint_nr;
	struct acpi_reference_args args;
	int ret;

	memset(&args, 0, sizeof(args));
	ret = acpi_node_get_property_reference(fwnode, "remote-endpoint", 0,
					       &args);
	if (ret)
		return ret;

	/*
	 * Always require two arguments with the reference: port and
	 * endpoint indices.
	 */
	if (args.nargs != 2)
		return -EPROTO;

	fwnode = acpi_fwnode_handle(args.adev);
	port_nr = args.args[0];
	endpoint_nr = args.args[1];

	if (parent)
		*parent = fwnode;

	if (!port && !endpoint)
		return 0;

	fwnode = acpi_graph_get_child_prop_value(fwnode, "port", port_nr);
	if (!fwnode)
		return -EPROTO;

	if (port)
		*port = fwnode;

	if (!endpoint)
		return 0;

	fwnode = acpi_graph_get_child_prop_value(fwnode, "endpoint",
						 endpoint_nr);
	if (!fwnode)
		return -EPROTO;

	*endpoint = fwnode;

	return 0;
}
+23 −0
Original line number Original line Diff line number Diff line
@@ -1001,6 +1001,13 @@ struct fwnode_handle *acpi_get_next_subnode(struct fwnode_handle *fwnode,
					    struct fwnode_handle *child);
					    struct fwnode_handle *child);
struct fwnode_handle *acpi_node_get_parent(struct fwnode_handle *fwnode);
struct fwnode_handle *acpi_node_get_parent(struct fwnode_handle *fwnode);


struct fwnode_handle *acpi_graph_get_next_endpoint(struct fwnode_handle *fwnode,
						   struct fwnode_handle *prev);
int acpi_graph_get_remote_endpoint(struct fwnode_handle *fwnode,
				   struct fwnode_handle **remote,
				   struct fwnode_handle **port,
				   struct fwnode_handle **endpoint);

struct acpi_probe_entry;
struct acpi_probe_entry;
typedef bool (*acpi_probe_entry_validate_subtbl)(struct acpi_subtable_header *,
typedef bool (*acpi_probe_entry_validate_subtbl)(struct acpi_subtable_header *,
						 struct acpi_probe_entry *);
						 struct acpi_probe_entry *);
@@ -1128,6 +1135,22 @@ acpi_node_get_parent(struct fwnode_handle *fwnode)
	return NULL;
	return NULL;
}
}


static inline struct fwnode_handle *
acpi_graph_get_next_endpoint(struct fwnode_handle *fwnode,
			     struct fwnode_handle *prev)
{
	return ERR_PTR(-ENXIO);
}

static inline int
acpi_graph_get_remote_endpoint(struct fwnode_handle *fwnode,
			       struct fwnode_handle **remote,
			       struct fwnode_handle **port,
			       struct fwnode_handle **endpoint)
{
	return -ENXIO;
}

#define ACPI_DECLARE_PROBE_ENTRY(table, name, table_id, subtable, valid, data, fn) \
#define ACPI_DECLARE_PROBE_ENTRY(table, name, table_id, subtable, valid, data, fn) \
	static const void * __acpi_table_##name[]			\
	static const void * __acpi_table_##name[]			\
		__attribute__((unused))					\
		__attribute__((unused))					\