diff options
Diffstat (limited to 'drivers/of/platform.c')
-rw-r--r-- | drivers/of/platform.c | 194 |
1 files changed, 141 insertions, 53 deletions
diff --git a/drivers/of/platform.c b/drivers/of/platform.c index 7f377b8b37..918607a518 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -12,6 +12,7 @@ #include <of.h> #include <of_address.h> #include <linux/amba/bus.h> +#include <mmu.h> /** * of_find_device_by_node - Find the platform_device associated with a node @@ -19,17 +20,18 @@ * * Returns platform_device pointer, or NULL if not found */ -struct device_d *of_find_device_by_node(struct device_node *np) +struct device *of_find_device_by_node(struct device_node *np) { - struct device_d *dev; - int ret; + struct device *dev; - ret = of_device_ensure_probed(np); - if (ret) - return NULL; + /* Not having a driver is not an error here */ + (void)of_device_ensure_probed(np); + + if (deep_probe_is_supported()) + return np->dev; for_each_device(dev) - if (dev->device_node == np) + if (dev->of_node == np) return dev; return NULL; } @@ -43,9 +45,9 @@ EXPORT_SYMBOL(of_find_device_by_node); * derive a unique name. If it cannot, then it will prepend names from * parent nodes until a unique name can be derived. */ -static void of_device_make_bus_id(struct device_d *dev) +static void of_device_make_bus_id(struct device *dev) { - struct device_node *node = dev->device_node; + struct device_node *node = dev->of_node; const __be32 *reg; u64 addr; @@ -70,7 +72,64 @@ static void of_device_make_bus_id(struct device_d *dev) } } -static void of_dma_configure(struct device_d *dev, struct device_node *np) +static struct device_node *of_get_next_dma_parent(const struct device_node *np) +{ + struct of_phandle_args args; + int ret, index; + + index = of_property_match_string(np, "interconnect-names", "dma-mem"); + if (index < 0) + return of_get_parent(np); + + ret = of_parse_phandle_with_args(np, "interconnects", + "#interconnect-cells", + index, &args); + if (ret < 0) + return of_get_parent(np); + + return args.np; +} + +static enum dev_dma_coherence of_dma_get_coherence(struct device_node *node) +{ + if (IS_ENABLED(CONFIG_OF_DMA_COHERENCY)) { + while (node) { + if (of_property_read_bool(node, "dma-coherent")) + return DEV_DMA_COHERENT; + if (of_property_read_bool(node, "dma-noncoherent")) + return DEV_DMA_NON_COHERENT; + node = of_get_next_dma_parent(node); + } + } + + return DEV_DMA_COHERENCE_DEFAULT; +} + +/** + * of_dma_is_coherent - Check if device is coherent + * @np: device node + * + * It returns true if "dma-coherent" property was found + * for this device in the DT, or if DMA is coherent by + * default for OF devices on the current platform and no + * "dma-noncoherent" property was found for this device. + */ +bool of_dma_is_coherent(struct device_node *node) +{ + switch (of_dma_get_coherence(node)) { + case DEV_DMA_COHERENT: + return true; + case DEV_DMA_NON_COHERENT: + return false; + case DEV_DMA_COHERENCE_DEFAULT: + return IS_ENABLED(CONFIG_ARCH_DMA_DEFAULT_COHERENT); + } + + BUG(); +} +EXPORT_SYMBOL_GPL(of_dma_is_coherent); + +static void of_dma_configure(struct device *dev, struct device_node *np) { u64 dma_addr, paddr, size = 0; unsigned long offset; @@ -84,6 +143,7 @@ static void of_dma_configure(struct device_d *dev, struct device_node *np) } dev->dma_offset = offset; + dev->dma_coherent = of_dma_get_coherence(np); } /** @@ -94,13 +154,14 @@ static void of_dma_configure(struct device_d *dev, struct device_node *np) * Returns pointer to created platform device, or NULL if a device was not * registered. Unavailable devices will not get registered. */ -struct device_d *of_platform_device_create(struct device_node *np, - struct device_d *parent) +struct device *of_platform_device_create(struct device_node *np, + struct device *parent) { - struct device_d *dev; + struct device *dev; struct resource *res = NULL, temp_res; resource_size_t resinval; int i, ret, num_reg = 0; + u32 virt; if (!of_device_is_available(np)) return NULL; @@ -109,8 +170,10 @@ struct device_d *of_platform_device_create(struct device_node *np, * Linux uses the OF_POPULATED flag to skip already populated/created * devices. */ - if (np->dev) + if (np->dev) { + device_rescan(np->dev); return np->dev; + } /* count the io resources */ if (of_can_translate_address(np)) @@ -132,7 +195,7 @@ struct device_d *of_platform_device_create(struct device_node *np, /* setup generic device info */ dev = xzalloc(sizeof(*dev)); dev->id = DEVICE_ID_SINGLE; - dev->device_node = np; + dev->of_node = np; dev->parent = parent; dev->resource = res; dev->num_resources = num_reg; @@ -140,6 +203,24 @@ struct device_d *of_platform_device_create(struct device_node *np, of_dma_configure(dev, np); + if (num_reg && !of_property_read_u32(np, "virtual-reg", &virt)) { + resource_size_t remap_offset = virt - res[0].start; + + for (i = 0; i < num_reg; i++) { + void *new_virt = (void *)res[i].start + remap_offset; + resource_size_t size = resource_size(&res[i]); + + ret = arch_remap_range(new_virt, res[i].start, size, MAP_UNCACHED); + if (!ret) { + debug("%s: remap device %s resource %d: %pa -> 0x%p\n", + __func__, dev_name(dev), i, &res[i].start, new_virt); + + res[i].start = (resource_size_t)new_virt; + res[i].end = res[i].start + size - 1; + } + } + } + resinval = (-1); debug("%s: register device %s, io=%pa\n", @@ -161,11 +242,11 @@ struct device_d *of_platform_device_create(struct device_node *np, return NULL; } -struct driver_d dummy_driver = { +struct driver dummy_driver = { .name = "dummy-driver", }; -void of_platform_device_dummy_drv(struct device_d *dev) +void of_platform_device_dummy_drv(struct device *dev) { dev->driver = &dummy_driver; } @@ -177,9 +258,9 @@ void of_platform_device_dummy_drv(struct device_d *dev) * Returns pointer to created platform device, or NULL if a device was not * registered. Unavailable devices will not get registered. */ -struct device_d *of_device_enable_and_register(struct device_node *np) +struct device *of_device_enable_and_register(struct device_node *np) { - struct device_d *dev; + struct device *dev; of_device_enable(np); @@ -198,7 +279,7 @@ EXPORT_SYMBOL(of_device_enable_and_register); * Returns pointer to created platform device, or NULL if a device was not * registered. Unavailable devices will not get registered. */ -struct device_d *of_device_enable_and_register_by_name(const char *name) +struct device *of_device_enable_and_register_by_name(const char *name) { struct device_node *node; @@ -220,7 +301,7 @@ EXPORT_SYMBOL(of_device_enable_and_register_by_name); * Returns pointer to created platform device, or NULL if a device was not * registered. Unavailable devices will not get registered. */ -struct device_d *of_device_enable_and_register_by_alias(const char *alias) +struct device *of_device_enable_and_register_by_alias(const char *alias) { struct device_node *node; @@ -233,12 +314,12 @@ struct device_d *of_device_enable_and_register_by_alias(const char *alias) EXPORT_SYMBOL(of_device_enable_and_register_by_alias); #ifdef CONFIG_ARM_AMBA -static struct device_d *of_amba_device_create(struct device_node *np) +static struct device *of_amba_device_create(struct device_node *np) { struct amba_device *dev; int ret; - debug("Creating amba device %s\n", np->full_name); + debug("Creating amba device %pOF\n", np); if (!of_device_is_available(np)) return NULL; @@ -254,7 +335,7 @@ static struct device_d *of_amba_device_create(struct device_node *np) /* setup generic device info */ dev->dev.id = DEVICE_ID_SINGLE; - dev->dev.device_node = np; + dev->dev.of_node = np; of_device_make_bus_id(&dev->dev); ret = of_address_to_resource(np, 0, &dev->res); @@ -283,7 +364,7 @@ amba_err_free: return NULL; } #else /* CONFIG_ARM_AMBA */ -static inline struct device_d *of_amba_device_create(struct device_node *np) +static inline struct device *of_amba_device_create(struct device_node *np) { return NULL; } @@ -300,16 +381,16 @@ static inline struct device_d *of_amba_device_create(struct device_node *np) */ static int of_platform_bus_create(struct device_node *bus, const struct of_device_id *matches, - struct device_d *parent) + struct device *parent) { struct device_node *child; - struct device_d *dev; + struct device *dev; int rc = 0; /* Make sure it has a compatible property */ if (!of_get_property(bus, "compatible", NULL)) { - pr_debug("%s() - skipping %s, no compatible prop\n", - __func__, bus->full_name); + pr_debug("%s() - skipping %pOF, no compatible prop\n", + __func__, bus); return 0; } @@ -323,7 +404,7 @@ static int of_platform_bus_create(struct device_node *bus, return 0; for_each_child_of_node(bus, child) { - pr_debug(" create child: %s\n", child->full_name); + pr_debug(" create child: %pOF\n", child); rc = of_platform_bus_create(child, matches, dev); if (rc) break; @@ -346,7 +427,7 @@ static int of_platform_bus_create(struct device_node *bus, */ int of_platform_populate(struct device_node *root, const struct of_device_id *matches, - struct device_d *parent) + struct device *parent) { struct device_node *child; int rc = 0; @@ -366,17 +447,17 @@ int of_platform_populate(struct device_node *root, } EXPORT_SYMBOL_GPL(of_platform_populate); -static struct device_d *of_device_create_on_demand(struct device_node *np) +static struct device *of_device_create_on_demand(struct device_node *np) { struct device_node *parent; - struct device_d *parent_dev, *dev; + struct device *parent_dev, *dev; parent = of_get_parent(np); if (!parent) return NULL; - if (!np->dev) - pr_debug("Creating device for %s\n", np->full_name); + if (!np->dev && parent->dev) + device_rescan(parent->dev); /* Create all parent devices needed for the requested device */ parent_dev = parent->dev ? : of_device_create_on_demand(parent); @@ -391,12 +472,17 @@ static struct device_d *of_device_create_on_demand(struct device_node *np) if (np->dev) return np->dev; + if (!of_property_present(np, "compatible")) + return NULL; + + pr_debug("Creating device for %pOF\n", np); + if (of_device_is_compatible(np, "arm,primecell")) dev = of_amba_device_create(np); else dev = of_platform_device_create(np, parent_dev); - return dev ? : ERR_PTR(-ENODEV); + return dev ? : ERR_PTR(-EPROBE_DEFER); } /** @@ -408,23 +494,19 @@ static struct device_d *of_device_create_on_demand(struct device_node *np) * it. * * Return: %0 on success - * %-ENODEV if either the device can't be populated, the driver is + * %-EPROBE_DEFER if either the device can't be populated, the driver is * missing or the driver probe returns an error. */ int of_device_ensure_probed(struct device_node *np) { - struct device_d *dev; + struct device *dev; - if (!deep_probe_is_supported()) + if (!np || !deep_probe_is_supported()) return 0; dev = of_device_create_on_demand(np); - if (IS_ERR(dev)) - return PTR_ERR(dev); - - if (!dev) - panic("deep-probe: device for '%s' couldn't be created\n", - np->full_name); + if (IS_ERR_OR_NULL(dev)) + return -EPROBE_DEFER; /* * The deep-probe mechanism relies on the fact that all necessary @@ -434,7 +516,7 @@ int of_device_ensure_probed(struct device_node *np) * requirements are fulfilled if 'dev->driver' is not NULL. */ if (!dev->driver) - return -ENODEV; + return -EPROBE_DEFER; return 0; } @@ -449,7 +531,7 @@ EXPORT_SYMBOL_GPL(of_device_ensure_probed); * populated and probed if found. * * Return: %0 on success - * %-ENODEV if either the device can't be populated, the driver is + * %-EPROBE_DEFER if either the device can't be populated, the driver is * missing or the driver probe returns an error * %-EINVAL if alias can't be found */ @@ -477,7 +559,7 @@ EXPORT_SYMBOL_GPL(of_device_ensure_probed_by_alias); * probes devices which match @ids. * * Return: %0 on success - * %-ENODEV if either the device wasn't found, can't be populated, + * %-EPROBE_DEFER if either the device wasn't found, can't be populated, * the driver is missing or the driver probe returns an error */ int of_devices_ensure_probed_by_dev_id(const struct of_device_id *ids) @@ -510,7 +592,7 @@ EXPORT_SYMBOL_GPL(of_devices_ensure_probed_by_dev_id); * devices which matches @property_name. * * Return: %0 on success - * %-ENODEV if either the device wasn't found, can't be populated, + * %-EPROBE_DEFER if either the device wasn't found, can't be populated, * the driver is missing or the driver probe returns an error */ int of_devices_ensure_probed_by_property(const char *property_name) @@ -522,12 +604,15 @@ int of_devices_ensure_probed_by_property(const char *property_name) return 0; for_each_node_with_property(node, property_name) { - ret = of_device_ensure_probed(node); + if (!of_device_is_available(node)) + continue; + + err = of_device_ensure_probed(node); if (err) ret = err; } - return 0; + return ret; } EXPORT_SYMBOL_GPL(of_devices_ensure_probed_by_property); @@ -540,12 +625,15 @@ int of_devices_ensure_probed_by_name(const char *name) return 0; for_each_node_by_name(node, name) { - ret = of_device_ensure_probed(node); + if (!of_device_is_available(node)) + continue; + + err = of_device_ensure_probed(node); if (err) ret = err; } - return 0; + return ret; } EXPORT_SYMBOL_GPL(of_devices_ensure_probed_by_name); |