Commit 5fab1004 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'devprop-4.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm

Pull generic device properties framework updates from Rafael Wysocki:
 "These add support for the ports and endpoints concepts, based on the
  existing DT support for them, to the generic device properties
  framework and update the ACPI _DSD properties code to recognize ports
  and endpoints accordingly.

  Specifics:

   - Extend the ACPI _DSD properties code and the generic device
     properties framework to support the concept of remote endponts
     (Mika Westerberg, Sakari Ailus).

   - Document the support for ports and endpoints in _DSD properties and
     extend the generic device properties framework to make it more
     suitable for the handling of ports and endpoints (Sakari Ailus)"

* tag 'devprop-4.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm:
  device property: Read strings using string array reading functions
  device property: fwnode_property_read_string_array() returns nr of strings
  device property: Fix reading pset strings using array access functions
  device property: fwnode_property_read_string_array() may return -EILSEQ
  ACPI / DSD: Document references, ports and endpoints
  device property: Add fwnode_get_next_parent()
  device property: Add support for fwnode endpoints
  device property: Make dev_fwnode() public
  of: Add of_fwnode_handle() to convert device nodes to fwnode_handle
  device property: Add fwnode_handle_get()
  device property: Add support for remote endpoints
  ACPI / property: Add support for remote endpoints
  device property: Add fwnode_get_named_child_node()
  ACPI / property: Add fwnode_get_next_child_node()
  device property: Add fwnode_get_parent()
  ACPI / property: Add possiblity to retrieve parent firmware node
parents 08be8810 e4817477
Graphs
_DSD
----
_DSD (Device Specific Data) [7] is a predefined ACPI device
configuration object that can be used to convey information on
hardware features which are not specifically covered by the ACPI
specification [1][6]. There are two _DSD extensions that are relevant
for graphs: property [4] and hierarchical data extensions [5]. The
property extension provides generic key-value pairs whereas the
hierarchical data extension supports nodes with references to other
nodes, forming a tree. The nodes in the tree may contain properties as
defined by the property extension. The two extensions together provide
a tree-like structure with zero or more properties (key-value pairs)
in each node of the tree.
The data structure may be accessed at runtime by using the device_*
and fwnode_* functions defined in include/linux/fwnode.h .
Fwnode represents a generic firmware node object. It is independent on
the firmware type. In ACPI, fwnodes are _DSD hierarchical data
extensions objects. A device's _DSD object is represented by an
fwnode.
The data structure may be referenced to elsewhere in the ACPI tables
by using a hard reference to the device itself and an index to the
hierarchical data extension array on each depth.
Ports and endpoints
-------------------
The port and endpoint concepts are very similar to those in Devicetree
[3]. A port represents an interface in a device, and an endpoint
represents a connection to that interface.
All port nodes are located under the device's "_DSD" node in the
hierarchical data extension tree. The property extension related to
each port node must contain the key "port" and an integer value which
is the number of the port. The object it refers to should be called "PRTX",
where "X" is the number of the port.
Further on, endpoints are located under the individual port nodes. The
first hierarchical data extension package list entry of the endpoint
nodes must begin with "endpoint" and must be followed by the number
of the endpoint. The object it refers to should be called "EPXY", where
"X" is the number of the port and "Y" is the number of the endpoint.
Each port node contains a property extension key "port", the value of
which is the number of the port node. The each endpoint is similarly numbered
with a property extension key "endpoint". Port numbers must be unique within a
device and endpoint numbers must be unique within a port.
The endpoint reference uses property extension with "remote-endpoint" property
name followed by a reference in the same package. Such references consist of the
the remote device reference, number of the port in the device and finally the
number of the endpoint in that port. Individual references thus appear as:
Package() { device, port_number, endpoint_number }
The references to endpoints must be always done both ways, to the
remote endpoint and back from the referred remote endpoint node.
A simple example of this is show below:
Scope (\_SB.PCI0.I2C2)
{
Device (CAM0)
{
Name (_DSD, Package () {
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package () {
Package () { "compatible", Package () { "nokia,smia" } },
},
ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
Package () {
Package () { "port0", "PRT0" },
}
})
Name (PRT0, Package() {
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package () {
Package () { "port", 0 },
},
ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
Package () {
Package () { "endpoint0", "EP00" },
}
})
Name (EP00, Package() {
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package () {
Package () { "endpoint", 0 },
Package () { "remote-endpoint", Package() { \_SB.PCI0.ISP, 4, 0 } },
}
})
}
}
Scope (\_SB.PCI0)
{
Device (ISP)
{
Name (_DSD, Package () {
ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
Package () {
Package () { "port4", "PRT4" },
}
})
Name (PRT4, Package() {
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package () {
Package () { "port", 4 }, /* CSI-2 port number */
},
ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
Package () {
Package () { "endpoint0", "EP40" },
}
})
Name (EP40, Package() {
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package () {
Package () { "endpoint", 0 },
Package () { "remote-endpoint", Package () { \_SB.PCI0.I2C2.CAM0, 0, 0 } },
}
})
}
}
Here, the port 0 of the "CAM0" device is connected to the port 4 of
the "ISP" device and vice versa.
References
----------
[1] _DSD (Device Specific Data) Implementation Guide.
<URL:http://www.uefi.org/sites/default/files/resources/_DSD-implementation-guide-toplevel-1_1.htm>,
referenced 2016-10-03.
[2] Devicetree. <URL:http://www.devicetree.org>, referenced 2016-10-03.
[3] Documentation/devicetree/bindings/graph.txt
[4] Device Properties UUID For _DSD.
<URL:http://www.uefi.org/sites/default/files/resources/_DSD-device-properties-UUID.pdf>,
referenced 2016-10-04.
[5] Hierarchical Data Extension UUID For _DSD.
<URL:http://www.uefi.org/sites/default/files/resources/_DSD-hierarchical-data-extension-UUID-v1.pdf>,
referenced 2016-10-04.
[6] Advanced Configuration and Power Interface Specification.
<URL:http://www.uefi.org/sites/default/files/resources/ACPI_6_1.pdf>,
referenced 2016-10-04.
[7] _DSD Device Properties Usage Rules.
Documentation/acpi/DSD-properties-rules.txt
This diff is collapsed.
This diff is collapsed.
...@@ -387,6 +387,7 @@ struct acpi_data_node { ...@@ -387,6 +387,7 @@ struct acpi_data_node {
const char *name; const char *name;
acpi_handle handle; acpi_handle handle;
struct fwnode_handle fwnode; struct fwnode_handle fwnode;
struct fwnode_handle *parent;
struct acpi_device_data data; struct acpi_device_data data;
struct list_head sibling; struct list_head sibling;
struct kobject kobj; struct kobject kobj;
......
...@@ -998,8 +998,16 @@ int acpi_node_prop_read(struct fwnode_handle *fwnode, const char *propname, ...@@ -998,8 +998,16 @@ int acpi_node_prop_read(struct fwnode_handle *fwnode, const char *propname,
int acpi_dev_prop_read(struct acpi_device *adev, const char *propname, int acpi_dev_prop_read(struct acpi_device *adev, const char *propname,
enum dev_prop_type proptype, void *val, size_t nval); enum dev_prop_type proptype, void *val, size_t nval);
struct fwnode_handle *acpi_get_next_subnode(struct device *dev, struct fwnode_handle *acpi_get_next_subnode(struct fwnode_handle *fwnode,
struct fwnode_handle *subnode); 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; 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 *,
...@@ -1116,12 +1124,34 @@ static inline int acpi_dev_prop_read(struct acpi_device *adev, ...@@ -1116,12 +1124,34 @@ static inline int acpi_dev_prop_read(struct acpi_device *adev,
return -ENXIO; return -ENXIO;
} }
static inline struct fwnode_handle *acpi_get_next_subnode(struct device *dev, static inline struct fwnode_handle *
struct fwnode_handle *subnode) acpi_get_next_subnode(struct fwnode_handle *fwnode, struct fwnode_handle *child)
{ {
return NULL; return NULL;
} }
static inline struct fwnode_handle *
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) \ #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)) \
......
...@@ -27,4 +27,16 @@ struct fwnode_handle { ...@@ -27,4 +27,16 @@ struct fwnode_handle {
struct fwnode_handle *secondary; struct fwnode_handle *secondary;
}; };
/**
* struct fwnode_endpoint - Fwnode graph endpoint
* @port: Port number
* @id: Endpoint id
* @local_fwnode: reference to the related fwnode
*/
struct fwnode_endpoint {
unsigned int port;
unsigned int id;
const struct fwnode_handle *local_fwnode;
};
#endif #endif
...@@ -159,6 +159,8 @@ static inline struct device_node *to_of_node(struct fwnode_handle *fwnode) ...@@ -159,6 +159,8 @@ static inline struct device_node *to_of_node(struct fwnode_handle *fwnode)
container_of(fwnode, struct device_node, fwnode) : NULL; container_of(fwnode, struct device_node, fwnode) : NULL;
} }
#define of_fwnode_handle(node) (&(node)->fwnode)
static inline bool of_have_populated_dt(void) static inline bool of_have_populated_dt(void)
{ {
return of_root != NULL; return of_root != NULL;
...@@ -602,6 +604,8 @@ static inline struct device_node *of_find_node_with_property( ...@@ -602,6 +604,8 @@ static inline struct device_node *of_find_node_with_property(
return NULL; return NULL;
} }
#define of_fwnode_handle(node) NULL
static inline bool of_have_populated_dt(void) static inline bool of_have_populated_dt(void)
{ {
return false; return false;
......
...@@ -33,6 +33,8 @@ enum dev_dma_attr { ...@@ -33,6 +33,8 @@ enum dev_dma_attr {
DEV_DMA_COHERENT, DEV_DMA_COHERENT,
}; };
struct fwnode_handle *dev_fwnode(struct device *dev);
bool device_property_present(struct device *dev, const char *propname); bool device_property_present(struct device *dev, const char *propname);
int device_property_read_u8_array(struct device *dev, const char *propname, int device_property_read_u8_array(struct device *dev, const char *propname,
u8 *val, size_t nval); u8 *val, size_t nval);
...@@ -70,6 +72,15 @@ int fwnode_property_read_string(struct fwnode_handle *fwnode, ...@@ -70,6 +72,15 @@ int fwnode_property_read_string(struct fwnode_handle *fwnode,
int fwnode_property_match_string(struct fwnode_handle *fwnode, int fwnode_property_match_string(struct fwnode_handle *fwnode,
const char *propname, const char *string); const char *propname, const char *string);
struct fwnode_handle *fwnode_get_parent(struct fwnode_handle *fwnode);
struct fwnode_handle *fwnode_get_next_parent(struct fwnode_handle *fwnode);
struct fwnode_handle *fwnode_get_next_child_node(struct fwnode_handle *fwnode,
struct fwnode_handle *child);
#define fwnode_for_each_child_node(fwnode, child) \
for (child = fwnode_get_next_child_node(fwnode, NULL); child; \
child = fwnode_get_next_child_node(fwnode, child))
struct fwnode_handle *device_get_next_child_node(struct device *dev, struct fwnode_handle *device_get_next_child_node(struct device *dev,
struct fwnode_handle *child); struct fwnode_handle *child);
...@@ -77,9 +88,12 @@ struct fwnode_handle *device_get_next_child_node(struct device *dev, ...@@ -77,9 +88,12 @@ struct fwnode_handle *device_get_next_child_node(struct device *dev,
for (child = device_get_next_child_node(dev, NULL); child; \ for (child = device_get_next_child_node(dev, NULL); child; \
child = device_get_next_child_node(dev, child)) child = device_get_next_child_node(dev, child))
struct fwnode_handle *fwnode_get_named_child_node(struct fwnode_handle *fwnode,
const char *childname);
struct fwnode_handle *device_get_named_child_node(struct device *dev, struct fwnode_handle *device_get_named_child_node(struct device *dev,
const char *childname); const char *childname);
void fwnode_handle_get(struct fwnode_handle *fwnode);
void fwnode_handle_put(struct fwnode_handle *fwnode); void fwnode_handle_put(struct fwnode_handle *fwnode);
unsigned int device_get_child_node_count(struct device *dev); unsigned int device_get_child_node_count(struct device *dev);
...@@ -258,4 +272,16 @@ int device_get_phy_mode(struct device *dev); ...@@ -258,4 +272,16 @@ int device_get_phy_mode(struct device *dev);
void *device_get_mac_address(struct device *dev, char *addr, int alen); void *device_get_mac_address(struct device *dev, char *addr, int alen);
struct fwnode_handle *fwnode_graph_get_next_endpoint(
struct fwnode_handle *fwnode, struct fwnode_handle *prev);
struct fwnode_handle *fwnode_graph_get_remote_port_parent(
struct fwnode_handle *fwnode);
struct fwnode_handle *fwnode_graph_get_remote_port(
struct fwnode_handle *fwnode);
struct fwnode_handle *fwnode_graph_get_remote_endpoint(
struct fwnode_handle *fwnode);
int fwnode_graph_parse_endpoint(struct fwnode_handle *fwnode,
struct fwnode_endpoint *endpoint);
#endif /* _LINUX_PROPERTY_H_ */ #endif /* _LINUX_PROPERTY_H_ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment