Skip to content

Commit

Permalink
ACPI / property: Add support for remote endpoints
Browse files Browse the repository at this point in the history
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: Mika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
  • Loading branch information
Mika Westerberg authored and Rafael J. Wysocki committed Mar 28, 2017
1 parent 21ea73f commit 79389a8
Show file tree
Hide file tree
Showing 2 changed files with 161 additions and 0 deletions.
138 changes: 138 additions & 0 deletions drivers/acpi/property.c
Original file line number Diff line number Diff line change
Expand Up @@ -969,3 +969,141 @@ struct fwnode_handle *acpi_node_get_parent(struct fwnode_handle *fwnode)

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 changes: 23 additions & 0 deletions include/linux/acpi.h
Original file line number Diff line number Diff line change
Expand Up @@ -1001,6 +1001,13 @@ struct fwnode_handle *acpi_get_next_subnode(struct fwnode_handle *fwnode,
struct fwnode_handle *child);
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;
typedef bool (*acpi_probe_entry_validate_subtbl)(struct acpi_subtable_header *,
struct acpi_probe_entry *);
Expand Down Expand Up @@ -1128,6 +1135,22 @@ acpi_node_get_parent(struct fwnode_handle *fwnode)
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) \
static const void * __acpi_table_##name[] \
__attribute__((unused)) \
Expand Down

0 comments on commit 79389a8

Please sign in to comment.