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: 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>
This commit is contained in:
parent
21ea73f54c
commit
79389a83bc
2 changed files with 161 additions and 0 deletions
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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)) \
|
||||||
|
|
Loading…
Add table
Reference in a new issue