diff options
Diffstat (limited to 'drivers/base')
-rw-r--r-- | drivers/base/core.c | 7 | ||||
-rw-r--r-- | drivers/base/dma-contiguous.c | 5 | ||||
-rw-r--r-- | drivers/base/dma-mapping.c | 5 | ||||
-rw-r--r-- | drivers/base/platform-msi.c | 3 | ||||
-rw-r--r-- | drivers/base/platform.c | 2 | ||||
-rw-r--r-- | drivers/base/power/domain.c | 68 | ||||
-rw-r--r-- | drivers/base/property.c | 364 |
7 files changed, 343 insertions, 111 deletions
diff --git a/drivers/base/core.c b/drivers/base/core.c index 684bda4d14a1..bbecaf9293be 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -639,11 +639,6 @@ int lock_device_hotplug_sysfs(void) return restart_syscall(); } -void assert_held_device_hotplug(void) -{ - lockdep_assert_held(&device_hotplug_lock); -} - #ifdef CONFIG_BLOCK static inline int device_is_not_partition(struct device *dev) { @@ -1612,7 +1607,7 @@ int device_private_init(struct device *dev) */ int device_add(struct device *dev) { - struct device *parent = NULL; + struct device *parent; struct kobject *kobj; struct class_interface *class_intf; int error = -EINVAL; diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c index b55804cac4c4..ea9726e71468 100644 --- a/drivers/base/dma-contiguous.c +++ b/drivers/base/dma-contiguous.c @@ -165,7 +165,8 @@ int __init dma_contiguous_reserve_area(phys_addr_t size, phys_addr_t base, { int ret; - ret = cma_declare_contiguous(base, size, limit, 0, 0, fixed, res_cma); + ret = cma_declare_contiguous(base, size, limit, 0, 0, fixed, + "reserved", res_cma); if (ret) return ret; @@ -258,7 +259,7 @@ static int __init rmem_cma_setup(struct reserved_mem *rmem) return -EINVAL; } - err = cma_init_reserved_mem(rmem->base, rmem->size, 0, &cma); + err = cma_init_reserved_mem(rmem->base, rmem->size, 0, rmem->name, &cma); if (err) { pr_err("Reserved memory: unable to setup CMA region\n"); return err; diff --git a/drivers/base/dma-mapping.c b/drivers/base/dma-mapping.c index efd71cf4fdea..51b7061ff7c0 100644 --- a/drivers/base/dma-mapping.c +++ b/drivers/base/dma-mapping.c @@ -309,14 +309,13 @@ void *dma_common_contiguous_remap(struct page *page, size_t size, int i; struct page **pages; void *ptr; - unsigned long pfn; pages = kmalloc(sizeof(struct page *) << get_order(size), GFP_KERNEL); if (!pages) return NULL; - for (i = 0, pfn = page_to_pfn(page); i < (size >> PAGE_SHIFT); i++) - pages[i] = pfn_to_page(pfn + i); + for (i = 0; i < (size >> PAGE_SHIFT); i++) + pages[i] = nth_page(page, i); ptr = dma_common_pages_remap(pages, size, vm_flags, prot, caller); diff --git a/drivers/base/platform-msi.c b/drivers/base/platform-msi.c index 0fc7c4da7756..d35e9a20caf7 100644 --- a/drivers/base/platform-msi.c +++ b/drivers/base/platform-msi.c @@ -345,8 +345,7 @@ platform_msi_create_device_domain(struct device *dev, data->host_data = host_data; domain = irq_domain_create_hierarchy(dev->msi_domain, 0, nvec, - of_node_to_fwnode(dev->of_node), - ops, data); + dev->fwnode, ops, data); if (!domain) goto free_priv; diff --git a/drivers/base/platform.c b/drivers/base/platform.c index c2456839214a..a102152301c8 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -847,7 +847,7 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *a, struct platform_device *pdev = to_platform_device(dev); int len; - len = of_device_get_modalias(dev, buf, PAGE_SIZE -1); + len = of_device_modalias(dev, buf, PAGE_SIZE); if (len != -ENODEV) return len; diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 8e0550c27394..da49a8383dc3 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -121,7 +121,9 @@ static const struct genpd_lock_ops genpd_spin_ops = { #define genpd_lock_interruptible(p) p->lock_ops->lock_interruptible(p) #define genpd_unlock(p) p->lock_ops->unlock(p) +#define genpd_status_on(genpd) (genpd->status == GPD_STATE_ACTIVE) #define genpd_is_irq_safe(genpd) (genpd->flags & GENPD_FLAG_IRQ_SAFE) +#define genpd_is_always_on(genpd) (genpd->flags & GENPD_FLAG_ALWAYS_ON) static inline bool irq_safe_dev_in_no_sleep_domain(struct device *dev, struct generic_pm_domain *genpd) @@ -130,8 +132,12 @@ static inline bool irq_safe_dev_in_no_sleep_domain(struct device *dev, ret = pm_runtime_is_irq_safe(dev) && !genpd_is_irq_safe(genpd); - /* Warn once if IRQ safe dev in no sleep domain */ - if (ret) + /* + * Warn once if an IRQ safe device is attached to a no sleep domain, as + * to indicate a suboptimal configuration for PM. For an always on + * domain this isn't case, thus don't warn. + */ + if (ret && !genpd_is_always_on(genpd)) dev_warn_once(dev, "PM domain %s will not be powered off\n", genpd->name); @@ -296,11 +302,15 @@ static int genpd_power_off(struct generic_pm_domain *genpd, bool one_dev_on, * (1) The domain is already in the "power off" state. * (2) System suspend is in progress. */ - if (genpd->status == GPD_STATE_POWER_OFF - || genpd->prepared_count > 0) + if (!genpd_status_on(genpd) || genpd->prepared_count > 0) return 0; - if (atomic_read(&genpd->sd_count) > 0) + /* + * Abort power off for the PM domain in the following situations: + * (1) The domain is configured as always on. + * (2) When the domain has a subdomain being powered on. + */ + if (genpd_is_always_on(genpd) || atomic_read(&genpd->sd_count) > 0) return -EBUSY; list_for_each_entry(pdd, &genpd->dev_list, list_node) { @@ -373,7 +383,7 @@ static int genpd_power_on(struct generic_pm_domain *genpd, unsigned int depth) struct gpd_link *link; int ret = 0; - if (genpd->status == GPD_STATE_ACTIVE) + if (genpd_status_on(genpd)) return 0; /* @@ -752,7 +762,7 @@ static void genpd_sync_power_off(struct generic_pm_domain *genpd, bool use_lock, { struct gpd_link *link; - if (genpd->status == GPD_STATE_POWER_OFF) + if (!genpd_status_on(genpd) || genpd_is_always_on(genpd)) return; if (genpd->suspended_count != genpd->device_count @@ -761,7 +771,8 @@ static void genpd_sync_power_off(struct generic_pm_domain *genpd, bool use_lock, /* Choose the deepest state when suspending */ genpd->state_idx = genpd->state_count - 1; - _genpd_power_off(genpd, false); + if (_genpd_power_off(genpd, false)) + return; genpd->status = GPD_STATE_POWER_OFF; @@ -793,7 +804,7 @@ static void genpd_sync_power_on(struct generic_pm_domain *genpd, bool use_lock, { struct gpd_link *link; - if (genpd->status == GPD_STATE_ACTIVE) + if (genpd_status_on(genpd)) return; list_for_each_entry(link, &genpd->slave_links, slave_node) { @@ -1329,8 +1340,7 @@ static int genpd_add_subdomain(struct generic_pm_domain *genpd, genpd_lock(subdomain); genpd_lock_nested(genpd, SINGLE_DEPTH_NESTING); - if (genpd->status == GPD_STATE_POWER_OFF - && subdomain->status != GPD_STATE_POWER_OFF) { + if (!genpd_status_on(genpd) && genpd_status_on(subdomain)) { ret = -EINVAL; goto out; } @@ -1346,7 +1356,7 @@ static int genpd_add_subdomain(struct generic_pm_domain *genpd, list_add_tail(&link->master_node, &genpd->master_links); link->slave = subdomain; list_add_tail(&link->slave_node, &subdomain->slave_links); - if (subdomain->status != GPD_STATE_POWER_OFF) + if (genpd_status_on(subdomain)) genpd_sd_counter_inc(genpd); out: @@ -1406,7 +1416,7 @@ int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd, list_del(&link->master_node); list_del(&link->slave_node); kfree(link); - if (subdomain->status != GPD_STATE_POWER_OFF) + if (genpd_status_on(subdomain)) genpd_sd_counter_dec(genpd); ret = 0; @@ -1492,6 +1502,10 @@ int pm_genpd_init(struct generic_pm_domain *genpd, genpd->dev_ops.start = pm_clk_resume; } + /* Always-on domains must be powered on at initialization. */ + if (genpd_is_always_on(genpd) && !genpd_status_on(genpd)) + return -EINVAL; + /* Use only one "off" state if there were no states declared */ if (genpd->state_count == 0) { ret = genpd_set_default_power_state(genpd); @@ -1698,12 +1712,12 @@ int of_genpd_add_provider_simple(struct device_node *np, mutex_lock(&gpd_list_lock); - if (pm_genpd_present(genpd)) + if (pm_genpd_present(genpd)) { ret = genpd_add_provider(np, genpd_xlate_simple, genpd); - - if (!ret) { - genpd->provider = &np->fwnode; - genpd->has_provider = true; + if (!ret) { + genpd->provider = &np->fwnode; + genpd->has_provider = true; + } } mutex_unlock(&gpd_list_lock); @@ -2077,11 +2091,6 @@ static int genpd_parse_state(struct genpd_power_state *genpd_state, int err; u32 residency; u32 entry_latency, exit_latency; - const struct of_device_id *match_id; - - match_id = of_match_node(idle_state_match, state_node); - if (!match_id) - return -EINVAL; err = of_property_read_u32(state_node, "entry-latency-us", &entry_latency); @@ -2130,6 +2139,7 @@ int of_genpd_parse_idle_states(struct device_node *dn, int err, ret; int count; struct of_phandle_iterator it; + const struct of_device_id *match_id; count = of_count_phandle_with_args(dn, "domain-idle-states", NULL); if (count <= 0) @@ -2142,6 +2152,9 @@ int of_genpd_parse_idle_states(struct device_node *dn, /* Loop over the phandles until all the requested entry is found */ of_for_each_phandle(&it, err, dn, "domain-idle-states", NULL, 0) { np = it.node; + match_id = of_match_node(idle_state_match, np); + if (!match_id) + continue; ret = genpd_parse_state(&st[i++], np); if (ret) { pr_err @@ -2153,8 +2166,11 @@ int of_genpd_parse_idle_states(struct device_node *dn, } } - *n = count; - *states = st; + *n = i; + if (!i) + kfree(st); + else + *states = st; return 0; } @@ -2219,7 +2235,7 @@ static int pm_genpd_summary_one(struct seq_file *s, if (WARN_ON(genpd->status >= ARRAY_SIZE(status_lookup))) goto exit; - if (genpd->status == GPD_STATE_POWER_OFF) + if (!genpd_status_on(genpd)) snprintf(state, sizeof(state), "%s-%u", status_lookup[genpd->status], genpd->state_idx); else diff --git a/drivers/base/property.c b/drivers/base/property.c index c458c63e353f..149de311a10e 100644 --- a/drivers/base/property.c +++ b/drivers/base/property.c @@ -15,6 +15,7 @@ #include <linux/kernel.h> #include <linux/of.h> #include <linux/of_address.h> +#include <linux/of_graph.h> #include <linux/property.h> #include <linux/etherdevice.h> #include <linux/phy.h> @@ -146,47 +147,45 @@ static int pset_prop_read_string_array(struct property_set *pset, const char *propname, const char **strings, size_t nval) { + const struct property_entry *prop; const void *pointer; - size_t length = nval * sizeof(*strings); + size_t array_len, length; + + /* Find out the array length. */ + prop = pset_prop_get(pset, propname); + if (!prop) + return -EINVAL; + + if (!prop->is_array) + /* The array length for a non-array string property is 1. */ + array_len = 1; + else + /* Find the length of an array. */ + array_len = pset_prop_count_elems_of_size(pset, propname, + sizeof(const char *)); + + /* Return how many there are if strings is NULL. */ + if (!strings) + return array_len; + + array_len = min(nval, array_len); + length = array_len * sizeof(*strings); pointer = pset_prop_find(pset, propname, length); if (IS_ERR(pointer)) return PTR_ERR(pointer); memcpy(strings, pointer, length); - return 0; -} -static int pset_prop_read_string(struct property_set *pset, - const char *propname, const char **strings) -{ - const struct property_entry *prop; - const char * const *pointer; - - prop = pset_prop_get(pset, propname); - if (!prop) - return -EINVAL; - if (!prop->is_string) - return -EILSEQ; - if (prop->is_array) { - pointer = prop->pointer.str; - if (!pointer) - return -ENODATA; - } else { - pointer = &prop->value.str; - if (*pointer && strnlen(*pointer, prop->length) >= prop->length) - return -EILSEQ; - } - - *strings = *pointer; - return 0; + return array_len; } -static inline struct fwnode_handle *dev_fwnode(struct device *dev) +struct fwnode_handle *dev_fwnode(struct device *dev) { return IS_ENABLED(CONFIG_OF) && dev->of_node ? &dev->of_node->fwnode : dev->fwnode; } +EXPORT_SYMBOL_GPL(dev_fwnode); /** * device_property_present - check if a property of a device is present @@ -340,8 +339,8 @@ EXPORT_SYMBOL_GPL(device_property_read_u64_array); * Function reads an array of string properties with @propname from the device * firmware description and stores them to @val if found. * - * Return: number of values if @val was %NULL, - * %0 if the property was found (success), + * Return: number of values read on success if @val is non-NULL, + * number of values available on success if @val is NULL, * %-EINVAL if given arguments are not valid, * %-ENODATA if the property does not have a value, * %-EPROTO or %-EILSEQ if the property is not an array of strings, @@ -553,25 +552,8 @@ static int __fwnode_property_read_string_array(struct fwnode_handle *fwnode, return acpi_node_prop_read(fwnode, propname, DEV_PROP_STRING, val, nval); else if (is_pset_node(fwnode)) - return val ? - pset_prop_read_string_array(to_pset_node(fwnode), - propname, val, nval) : - pset_prop_count_elems_of_size(to_pset_node(fwnode), - propname, - sizeof(const char *)); - return -ENXIO; -} - -static int __fwnode_property_read_string(struct fwnode_handle *fwnode, - const char *propname, const char **val) -{ - if (is_of_node(fwnode)) - return of_property_read_string(to_of_node(fwnode), propname, val); - else if (is_acpi_node(fwnode)) - return acpi_node_prop_read(fwnode, propname, DEV_PROP_STRING, - val, 1); - else if (is_pset_node(fwnode)) - return pset_prop_read_string(to_pset_node(fwnode), propname, val); + return pset_prop_read_string_array(to_pset_node(fwnode), + propname, val, nval); return -ENXIO; } @@ -585,11 +567,11 @@ static int __fwnode_property_read_string(struct fwnode_handle *fwnode, * Read an string list property @propname from the given firmware node and store * them to @val if found. * - * Return: number of values if @val was %NULL, - * %0 if the property was found (success), + * Return: number of values read on success if @val is non-NULL, + * number of values available on success if @val is NULL, * %-EINVAL if given arguments are not valid, * %-ENODATA if the property does not have a value, - * %-EPROTO if the property is not an array of strings, + * %-EPROTO or %-EILSEQ if the property is not an array of strings, * %-EOVERFLOW if the size of the property is not as expected, * %-ENXIO if no suitable firmware interface is present. */ @@ -626,14 +608,9 @@ EXPORT_SYMBOL_GPL(fwnode_property_read_string_array); int fwnode_property_read_string(struct fwnode_handle *fwnode, const char *propname, const char **val) { - int ret; + int ret = fwnode_property_read_string_array(fwnode, propname, val, 1); - ret = __fwnode_property_read_string(fwnode, propname, val); - if (ret == -EINVAL && !IS_ERR_OR_NULL(fwnode) && - !IS_ERR_OR_NULL(fwnode->secondary)) - ret = __fwnode_property_read_string(fwnode->secondary, - propname, val); - return ret; + return ret < 0 ? ret : 0; } EXPORT_SYMBOL_GPL(fwnode_property_read_string); @@ -932,41 +909,109 @@ int device_add_properties(struct device *dev, EXPORT_SYMBOL_GPL(device_add_properties); /** - * device_get_next_child_node - Return the next child node handle for a device - * @dev: Device to find the next child node for. - * @child: Handle to one of the device's child nodes or a null handle. + * fwnode_get_next_parent - Iterate to the node's parent + * @fwnode: Firmware whose parent is retrieved + * + * This is like fwnode_get_parent() except that it drops the refcount + * on the passed node, making it suitable for iterating through a + * node's parents. + * + * Returns a node pointer with refcount incremented, use + * fwnode_handle_node() on it when done. */ -struct fwnode_handle *device_get_next_child_node(struct device *dev, +struct fwnode_handle *fwnode_get_next_parent(struct fwnode_handle *fwnode) +{ + struct fwnode_handle *parent = fwnode_get_parent(fwnode); + + fwnode_handle_put(fwnode); + + return parent; +} +EXPORT_SYMBOL_GPL(fwnode_get_next_parent); + +/** + * fwnode_get_parent - Return parent firwmare node + * @fwnode: Firmware whose parent is retrieved + * + * Return parent firmware node of the given node if possible or %NULL if no + * parent was available. + */ +struct fwnode_handle *fwnode_get_parent(struct fwnode_handle *fwnode) +{ + struct fwnode_handle *parent = NULL; + + if (is_of_node(fwnode)) { + struct device_node *node; + + node = of_get_parent(to_of_node(fwnode)); + if (node) + parent = &node->fwnode; + } else if (is_acpi_node(fwnode)) { + parent = acpi_node_get_parent(fwnode); + } + + return parent; +} +EXPORT_SYMBOL_GPL(fwnode_get_parent); + +/** + * fwnode_get_next_child_node - Return the next child node handle for a node + * @fwnode: Firmware node to find the next child node for. + * @child: Handle to one of the node's child nodes or a %NULL handle. + */ +struct fwnode_handle *fwnode_get_next_child_node(struct fwnode_handle *fwnode, struct fwnode_handle *child) { - if (IS_ENABLED(CONFIG_OF) && dev->of_node) { + if (is_of_node(fwnode)) { struct device_node *node; - node = of_get_next_available_child(dev->of_node, to_of_node(child)); + node = of_get_next_available_child(to_of_node(fwnode), + to_of_node(child)); if (node) return &node->fwnode; - } else if (IS_ENABLED(CONFIG_ACPI)) { - return acpi_get_next_subnode(dev, child); + } else if (is_acpi_node(fwnode)) { + return acpi_get_next_subnode(fwnode, child); } + return NULL; } +EXPORT_SYMBOL_GPL(fwnode_get_next_child_node); + +/** + * device_get_next_child_node - Return the next child node handle for a device + * @dev: Device to find the next child node for. + * @child: Handle to one of the device's child nodes or a null handle. + */ +struct fwnode_handle *device_get_next_child_node(struct device *dev, + struct fwnode_handle *child) +{ + struct acpi_device *adev = ACPI_COMPANION(dev); + struct fwnode_handle *fwnode = NULL; + + if (dev->of_node) + fwnode = &dev->of_node->fwnode; + else if (adev) + fwnode = acpi_fwnode_handle(adev); + + return fwnode_get_next_child_node(fwnode, child); +} EXPORT_SYMBOL_GPL(device_get_next_child_node); /** - * device_get_named_child_node - Return first matching named child node handle - * @dev: Device to find the named child node for. + * fwnode_get_named_child_node - Return first matching named child node handle + * @fwnode: Firmware node to find the named child node for. * @childname: String to match child node name against. */ -struct fwnode_handle *device_get_named_child_node(struct device *dev, +struct fwnode_handle *fwnode_get_named_child_node(struct fwnode_handle *fwnode, const char *childname) { struct fwnode_handle *child; /* - * Find first matching named child node of this device. + * Find first matching named child node of this fwnode. * For ACPI this will be a data only sub-node. */ - device_for_each_child_node(dev, child) { + fwnode_for_each_child_node(fwnode, child) { if (is_of_node(child)) { if (!of_node_cmp(to_of_node(child)->name, childname)) return child; @@ -978,9 +1023,32 @@ struct fwnode_handle *device_get_named_child_node(struct device *dev, return NULL; } +EXPORT_SYMBOL_GPL(fwnode_get_named_child_node); + +/** + * device_get_named_child_node - Return first matching named child node handle + * @dev: Device to find the named child node for. + * @childname: String to match child node name against. + */ +struct fwnode_handle *device_get_named_child_node(struct device *dev, + const char *childname) +{ + return fwnode_get_named_child_node(dev_fwnode(dev), childname); +} EXPORT_SYMBOL_GPL(device_get_named_child_node); /** + * fwnode_handle_get - Obtain a reference to a device node + * @fwnode: Pointer to the device node to obtain the reference to. + */ +void fwnode_handle_get(struct fwnode_handle *fwnode) +{ + if (is_of_node(fwnode)) + of_node_get(to_of_node(fwnode)); +} +EXPORT_SYMBOL_GPL(fwnode_handle_get); + +/** * fwnode_handle_put - Drop reference to a device node * @fwnode: Pointer to the device node to drop the reference to. * @@ -1117,3 +1185,157 @@ void *device_get_mac_address(struct device *dev, char *addr, int alen) return device_get_mac_addr(dev, "address", addr, alen); } EXPORT_SYMBOL(device_get_mac_address); + +/** + * device_graph_get_next_endpoint - Get next endpoint firmware node + * @fwnode: Pointer to the parent firmware node + * @prev: Previous endpoint node or %NULL to get the first + * + * Returns an endpoint firmware node pointer or %NULL if no more endpoints + * are available. + */ +struct fwnode_handle * +fwnode_graph_get_next_endpoint(struct fwnode_handle *fwnode, + struct fwnode_handle *prev) +{ + struct fwnode_handle *endpoint = NULL; + + if (is_of_node(fwnode)) { + struct device_node *node; + + node = of_graph_get_next_endpoint(to_of_node(fwnode), + to_of_node(prev)); + + if (node) + endpoint = &node->fwnode; + } else if (is_acpi_node(fwnode)) { + endpoint = acpi_graph_get_next_endpoint(fwnode, prev); + if (IS_ERR(endpoint)) + endpoint = NULL; + } + + return endpoint; + +} +EXPORT_SYMBOL_GPL(fwnode_graph_get_next_endpoint); + +/** + * fwnode_graph_get_remote_port_parent - Return fwnode of a remote device + * @fwnode: Endpoint firmware node pointing to the remote endpoint + * + * Extracts firmware node of a remote device the @fwnode points to. + */ +struct fwnode_handle * +fwnode_graph_get_remote_port_parent(struct fwnode_handle *fwnode) +{ + struct fwnode_handle *parent = NULL; + + if (is_of_node(fwnode)) { + struct device_node *node; + + node = of_graph_get_remote_port_parent(to_of_node(fwnode)); + if (node) + parent = &node->fwnode; + } else if (is_acpi_node(fwnode)) { + int ret; + + ret = acpi_graph_get_remote_endpoint(fwnode, &parent, NULL, + NULL); + if (ret) + return NULL; + } + + return parent; +} +EXPORT_SYMBOL_GPL(fwnode_graph_get_remote_port_parent); + +/** + * fwnode_graph_get_remote_port - Return fwnode of a remote port + * @fwnode: Endpoint firmware node pointing to the remote endpoint + * + * Extracts firmware node of a remote port the @fwnode points to. + */ +struct fwnode_handle *fwnode_graph_get_remote_port(struct fwnode_handle *fwnode) +{ + struct fwnode_handle *port = NULL; + + if (is_of_node(fwnode)) { + struct device_node *node; + + node = of_graph_get_remote_port(to_of_node(fwnode)); + if (node) + port = &node->fwnode; + } else if (is_acpi_node(fwnode)) { + int ret; + + ret = acpi_graph_get_remote_endpoint(fwnode, NULL, &port, NULL); + if (ret) + return NULL; + } + + return port; +} +EXPORT_SYMBOL_GPL(fwnode_graph_get_remote_port); + +/** + * fwnode_graph_get_remote_endpoint - Return fwnode of a remote endpoint + * @fwnode: Endpoint firmware node pointing to the remote endpoint + * + * Extracts firmware node of a remote endpoint the @fwnode points to. + */ +struct fwnode_handle * +fwnode_graph_get_remote_endpoint(struct fwnode_handle *fwnode) +{ + struct fwnode_handle *endpoint = NULL; + + if (is_of_node(fwnode)) { + struct device_node *node; + + node = of_parse_phandle(to_of_node(fwnode), "remote-endpoint", + 0); + if (node) + endpoint = &node->fwnode; + } else if (is_acpi_node(fwnode)) { + int ret; + + ret = acpi_graph_get_remote_endpoint(fwnode, NULL, NULL, + &endpoint); + if (ret) + return NULL; + } + + return endpoint; +} +EXPORT_SYMBOL_GPL(fwnode_graph_get_remote_endpoint); + +/** + * fwnode_graph_parse_endpoint - parse common endpoint node properties + * @fwnode: pointer to endpoint fwnode_handle + * @endpoint: pointer to the fwnode endpoint data structure + * + * Parse @fwnode representing a graph endpoint node and store the + * information in @endpoint. The caller must hold a reference to + * @fwnode. + */ +int fwnode_graph_parse_endpoint(struct fwnode_handle *fwnode, + struct fwnode_endpoint *endpoint) +{ + struct fwnode_handle *port_fwnode = fwnode_get_parent(fwnode); + + memset(endpoint, 0, sizeof(*endpoint)); + + endpoint->local_fwnode = fwnode; + + if (is_acpi_node(port_fwnode)) { + fwnode_property_read_u32(port_fwnode, "port", &endpoint->port); + fwnode_property_read_u32(fwnode, "endpoint", &endpoint->id); + } else { + fwnode_property_read_u32(port_fwnode, "reg", &endpoint->port); + fwnode_property_read_u32(fwnode, "reg", &endpoint->id); + } + + fwnode_handle_put(port_fwnode); + + return 0; +} +EXPORT_SYMBOL(fwnode_graph_parse_endpoint); |