diff options
Diffstat (limited to 'drivers/amba/bus.c')
| -rw-r--r-- | drivers/amba/bus.c | 819 |
1 files changed, 363 insertions, 456 deletions
diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c index c6707278a6bb..952c45ca6e48 100644 --- a/drivers/amba/bus.c +++ b/drivers/amba/bus.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/arch/arm/common/amba.c * * Copyright (C) 2003 Deep Blue Solutions Ltd, All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> #include <linux/init.h> @@ -15,48 +12,102 @@ #include <linux/io.h> #include <linux/pm.h> #include <linux/pm_runtime.h> +#include <linux/pm_domain.h> #include <linux/amba/bus.h> #include <linux/sizes.h> +#include <linux/limits.h> +#include <linux/clk/clk-conf.h> +#include <linux/platform_device.h> +#include <linux/property.h> +#include <linux/reset.h> +#include <linux/of_irq.h> +#include <linux/of_device.h> +#include <linux/acpi.h> +#include <linux/iommu.h> +#include <linux/dma-map-ops.h> + +#define to_amba_driver(d) container_of_const(d, struct amba_driver, drv) + +/* called on periphid match and class 0x9 coresight device. */ +static int +amba_cs_uci_id_match(const struct amba_id *table, struct amba_device *dev) +{ + int ret = 0; + struct amba_cs_uci_id *uci; -#include <asm/irq.h> + uci = table->data; -#define to_amba_driver(d) container_of(d, struct amba_driver, drv) + /* no table data or zero mask - return match on periphid */ + if (!uci || (uci->devarch_mask == 0)) + return 1; + + /* test against read devtype and masked devarch value */ + ret = (dev->uci.devtype == uci->devtype) && + ((dev->uci.devarch & uci->devarch_mask) == uci->devarch); + return ret; +} static const struct amba_id * amba_lookup(const struct amba_id *table, struct amba_device *dev) { - int ret = 0; - while (table->mask) { - ret = (dev->periphid & table->mask) == table->id; - if (ret) - break; + if (((dev->periphid & table->mask) == table->id) && + ((dev->cid != CORESIGHT_CID) || + (amba_cs_uci_id_match(table, dev)))) + return table; table++; } + return NULL; +} - return ret ? table : NULL; +static int amba_get_enable_pclk(struct amba_device *pcdev) +{ + int ret; + + pcdev->pclk = clk_get(&pcdev->dev, "apb_pclk"); + if (IS_ERR(pcdev->pclk)) + return PTR_ERR(pcdev->pclk); + + ret = clk_prepare_enable(pcdev->pclk); + if (ret) + clk_put(pcdev->pclk); + + return ret; } -static int amba_match(struct device *dev, struct device_driver *drv) +static void amba_put_disable_pclk(struct amba_device *pcdev) { - struct amba_device *pcdev = to_amba_device(dev); - struct amba_driver *pcdrv = to_amba_driver(drv); + clk_disable_unprepare(pcdev->pclk); + clk_put(pcdev->pclk); +} - return amba_lookup(pcdrv->id_table, pcdev) != NULL; + +static ssize_t driver_override_show(struct device *_dev, + struct device_attribute *attr, char *buf) +{ + struct amba_device *dev = to_amba_device(_dev); + ssize_t len; + + device_lock(_dev); + len = sprintf(buf, "%s\n", dev->driver_override); + device_unlock(_dev); + return len; } -static int amba_uevent(struct device *dev, struct kobj_uevent_env *env) +static ssize_t driver_override_store(struct device *_dev, + struct device_attribute *attr, + const char *buf, size_t count) { - struct amba_device *pcdev = to_amba_device(dev); - int retval = 0; + struct amba_device *dev = to_amba_device(_dev); + int ret; - retval = add_uevent_var(env, "AMBA_ID=%08x", pcdev->periphid); - if (retval) - return retval; + ret = driver_set_override(_dev, &dev->driver_override, buf, count); + if (ret) + return ret; - retval = add_uevent_var(env, "MODALIAS=amba:d%08X", pcdev->periphid); - return retval; + return count; } +static DEVICE_ATTR_RW(driver_override); #define amba_attr_func(name,fmt,arg...) \ static ssize_t name##_show(struct device *_dev, \ @@ -64,182 +115,271 @@ static ssize_t name##_show(struct device *_dev, \ { \ struct amba_device *dev = to_amba_device(_dev); \ return sprintf(buf, fmt, arg); \ -} - -#define amba_attr(name,fmt,arg...) \ -amba_attr_func(name,fmt,arg) \ -static DEVICE_ATTR(name, S_IRUGO, name##_show, NULL) +} \ +static DEVICE_ATTR_RO(name) amba_attr_func(id, "%08x\n", dev->periphid); -amba_attr(irq0, "%u\n", dev->irq[0]); -amba_attr(irq1, "%u\n", dev->irq[1]); amba_attr_func(resource, "\t%016llx\t%016llx\t%016lx\n", (unsigned long long)dev->res.start, (unsigned long long)dev->res.end, dev->res.flags); -static struct device_attribute amba_dev_attrs[] = { - __ATTR_RO(id), - __ATTR_RO(resource), - __ATTR_NULL, +static struct attribute *amba_dev_attrs[] = { + &dev_attr_id.attr, + &dev_attr_resource.attr, + &dev_attr_driver_override.attr, + NULL, }; +ATTRIBUTE_GROUPS(amba_dev); -#ifdef CONFIG_PM_SLEEP - -static int amba_legacy_suspend(struct device *dev, pm_message_t mesg) +static int amba_read_periphid(struct amba_device *dev) { - struct amba_driver *adrv = to_amba_driver(dev->driver); - struct amba_device *adev = to_amba_device(dev); - int ret = 0; + struct reset_control *rstc; + u32 size, pid, cid; + void __iomem *tmp; + int i, ret; - if (dev->driver && adrv->suspend) - ret = adrv->suspend(adev, mesg); + ret = dev_pm_domain_attach(&dev->dev, PD_FLAG_ATTACH_POWER_ON); + if (ret) { + dev_dbg(&dev->dev, "can't get PM domain: %d\n", ret); + goto err_out; + } - return ret; -} + ret = amba_get_enable_pclk(dev); + if (ret) { + dev_dbg(&dev->dev, "can't get pclk: %d\n", ret); + goto err_pm; + } -static int amba_legacy_resume(struct device *dev) -{ - struct amba_driver *adrv = to_amba_driver(dev->driver); - struct amba_device *adev = to_amba_device(dev); - int ret = 0; + /* + * Find reset control(s) of the amba bus and de-assert them. + */ + rstc = of_reset_control_array_get_optional_shared(dev->dev.of_node); + if (IS_ERR(rstc)) { + ret = PTR_ERR(rstc); + if (ret != -EPROBE_DEFER) + dev_err(&dev->dev, "can't get reset: %d\n", ret); + goto err_clk; + } + reset_control_deassert(rstc); + reset_control_put(rstc); - if (dev->driver && adrv->resume) - ret = adrv->resume(adev); + size = resource_size(&dev->res); + tmp = ioremap(dev->res.start, size); + if (!tmp) { + ret = -ENOMEM; + goto err_clk; + } - return ret; -} + /* + * Read pid and cid based on size of resource + * they are located at end of region + */ + for (pid = 0, i = 0; i < 4; i++) + pid |= (readl(tmp + size - 0x20 + 4 * i) & 255) << (i * 8); + for (cid = 0, i = 0; i < 4; i++) + cid |= (readl(tmp + size - 0x10 + 4 * i) & 255) << (i * 8); -#endif /* CONFIG_PM_SLEEP */ + if (cid == CORESIGHT_CID) { + /* set the base to the start of the last 4k block */ + void __iomem *csbase = tmp + size - 4096; -#ifdef CONFIG_SUSPEND + dev->uci.devarch = readl(csbase + UCI_REG_DEVARCH_OFFSET); + dev->uci.devtype = readl(csbase + UCI_REG_DEVTYPE_OFFSET) & 0xff; + } -static int amba_pm_suspend(struct device *dev) -{ - struct device_driver *drv = dev->driver; - int ret = 0; + if (cid == AMBA_CID || cid == CORESIGHT_CID) { + dev->periphid = pid; + dev->cid = cid; + } - if (!drv) - return 0; + if (!dev->periphid) + ret = -ENODEV; - if (drv->pm) { - if (drv->pm->suspend) - ret = drv->pm->suspend(dev); - } else { - ret = amba_legacy_suspend(dev, PMSG_SUSPEND); - } + iounmap(tmp); +err_clk: + amba_put_disable_pclk(dev); +err_pm: + dev_pm_domain_detach(&dev->dev, true); +err_out: return ret; } -static int amba_pm_resume(struct device *dev) +static int amba_match(struct device *dev, const struct device_driver *drv) { - struct device_driver *drv = dev->driver; - int ret = 0; + struct amba_device *pcdev = to_amba_device(dev); + const struct amba_driver *pcdrv = to_amba_driver(drv); - if (!drv) - return 0; + mutex_lock(&pcdev->periphid_lock); + if (!pcdev->periphid) { + int ret = amba_read_periphid(pcdev); - if (drv->pm) { - if (drv->pm->resume) - ret = drv->pm->resume(dev); - } else { - ret = amba_legacy_resume(dev); + /* + * Returning any error other than -EPROBE_DEFER from bus match + * can cause driver registration failure. So, if there's a + * permanent failure in reading pid and cid, simply map it to + * -EPROBE_DEFER. + */ + if (ret) { + mutex_unlock(&pcdev->periphid_lock); + return -EPROBE_DEFER; + } + dev_set_uevent_suppress(dev, false); + kobject_uevent(&dev->kobj, KOBJ_ADD); } + mutex_unlock(&pcdev->periphid_lock); - return ret; -} + /* When driver_override is set, only bind to the matching driver */ + if (pcdev->driver_override) + return !strcmp(pcdev->driver_override, drv->name); -#else /* !CONFIG_SUSPEND */ + return amba_lookup(pcdrv->id_table, pcdev) != NULL; +} -#define amba_pm_suspend NULL -#define amba_pm_resume NULL +static int amba_uevent(const struct device *dev, struct kobj_uevent_env *env) +{ + const struct amba_device *pcdev = to_amba_device(dev); + int retval = 0; -#endif /* !CONFIG_SUSPEND */ + retval = add_uevent_var(env, "AMBA_ID=%08x", pcdev->periphid); + if (retval) + return retval; -#ifdef CONFIG_HIBERNATE_CALLBACKS + retval = add_uevent_var(env, "MODALIAS=amba:d%08X", pcdev->periphid); + return retval; +} -static int amba_pm_freeze(struct device *dev) +static int of_amba_device_decode_irq(struct amba_device *dev) { - struct device_driver *drv = dev->driver; - int ret = 0; + struct device_node *node = dev->dev.of_node; + int i, irq = 0; - if (!drv) - return 0; + if (IS_ENABLED(CONFIG_OF_IRQ) && node) { + /* Decode the IRQs and address ranges */ + for (i = 0; i < AMBA_NR_IRQS; i++) { + irq = of_irq_get(node, i); + if (irq < 0) { + if (irq == -EPROBE_DEFER) + return irq; + irq = 0; + } - if (drv->pm) { - if (drv->pm->freeze) - ret = drv->pm->freeze(dev); - } else { - ret = amba_legacy_suspend(dev, PMSG_FREEZE); + dev->irq[i] = irq; + } } - return ret; + return 0; } -static int amba_pm_thaw(struct device *dev) +/* + * These are the device model conversion veneers; they convert the + * device model structures to our more specific structures. + */ +static int amba_probe(struct device *dev) { - struct device_driver *drv = dev->driver; - int ret = 0; + struct amba_device *pcdev = to_amba_device(dev); + struct amba_driver *pcdrv = to_amba_driver(dev->driver); + const struct amba_id *id = amba_lookup(pcdrv->id_table, pcdev); + int ret; - if (!drv) - return 0; + do { + ret = of_amba_device_decode_irq(pcdev); + if (ret) + break; - if (drv->pm) { - if (drv->pm->thaw) - ret = drv->pm->thaw(dev); - } else { - ret = amba_legacy_resume(dev); - } + ret = of_clk_set_defaults(dev->of_node, false); + if (ret < 0) + break; + + ret = dev_pm_domain_attach(dev, PD_FLAG_ATTACH_POWER_ON | + PD_FLAG_DETACH_POWER_OFF); + if (ret) + break; + + ret = amba_get_enable_pclk(pcdev); + if (ret) + break; + + pm_runtime_get_noresume(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + + ret = pcdrv->probe(pcdev, id); + if (ret == 0) + break; + + pm_runtime_disable(dev); + pm_runtime_set_suspended(dev); + pm_runtime_put_noidle(dev); + + amba_put_disable_pclk(pcdev); + } while (0); return ret; } -static int amba_pm_poweroff(struct device *dev) +static void amba_remove(struct device *dev) { - struct device_driver *drv = dev->driver; - int ret = 0; + struct amba_device *pcdev = to_amba_device(dev); + struct amba_driver *drv = to_amba_driver(dev->driver); - if (!drv) - return 0; + pm_runtime_get_sync(dev); + if (drv->remove) + drv->remove(pcdev); + pm_runtime_put_noidle(dev); - if (drv->pm) { - if (drv->pm->poweroff) - ret = drv->pm->poweroff(dev); - } else { - ret = amba_legacy_suspend(dev, PMSG_HIBERNATE); - } + /* Undo the runtime PM settings in amba_probe() */ + pm_runtime_disable(dev); + pm_runtime_set_suspended(dev); + pm_runtime_put_noidle(dev); - return ret; + amba_put_disable_pclk(pcdev); } -static int amba_pm_restore(struct device *dev) +static void amba_shutdown(struct device *dev) { - struct device_driver *drv = dev->driver; + struct amba_driver *drv; + + if (!dev->driver) + return; + + drv = to_amba_driver(dev->driver); + if (drv->shutdown) + drv->shutdown(to_amba_device(dev)); +} + +static int amba_dma_configure(struct device *dev) +{ + struct amba_driver *drv = to_amba_driver(dev->driver); + enum dev_dma_attr attr; int ret = 0; - if (!drv) - return 0; + if (dev->of_node) { + ret = of_dma_configure(dev, dev->of_node, true); + } else if (has_acpi_companion(dev)) { + attr = acpi_get_dma_attr(to_acpi_device_node(dev->fwnode)); + ret = acpi_dma_configure(dev, attr); + } - if (drv->pm) { - if (drv->pm->restore) - ret = drv->pm->restore(dev); - } else { - ret = amba_legacy_resume(dev); + /* @drv may not be valid when we're called from the IOMMU layer */ + if (!ret && dev->driver && !drv->driver_managed_dma) { + ret = iommu_device_use_default_domain(dev); + if (ret) + arch_teardown_dma_ops(dev); } return ret; } -#else /* !CONFIG_HIBERNATE_CALLBACKS */ - -#define amba_pm_freeze NULL -#define amba_pm_thaw NULL -#define amba_pm_poweroff NULL -#define amba_pm_restore NULL +static void amba_dma_cleanup(struct device *dev) +{ + struct amba_driver *drv = to_amba_driver(dev->driver); -#endif /* !CONFIG_HIBERNATE_CALLBACKS */ + if (!drv->driver_managed_dma) + iommu_device_unuse_default_domain(dev); +} -#ifdef CONFIG_PM_RUNTIME +#ifdef CONFIG_PM /* * Hooks to provide runtime PM of the pclk (bus clock). It is safe to * enable/disable the bus clock at runtime PM suspend/resume as this @@ -250,8 +390,12 @@ static int amba_pm_runtime_suspend(struct device *dev) struct amba_device *pcdev = to_amba_device(dev); int ret = pm_generic_runtime_suspend(dev); - if (ret == 0 && dev->driver) - clk_disable(pcdev->pclk); + if (ret == 0 && dev->driver) { + if (pm_runtime_is_irq_safe(dev)) + clk_disable(pcdev->pclk); + else + clk_disable_unprepare(pcdev->pclk); + } return ret; } @@ -262,7 +406,10 @@ static int amba_pm_runtime_resume(struct device *dev) int ret; if (dev->driver) { - ret = clk_enable(pcdev->pclk); + if (pm_runtime_is_irq_safe(dev)) + ret = clk_enable(pcdev->pclk); + else + ret = clk_prepare_enable(pcdev->pclk); /* Failure is probably fatal to the system, but... */ if (ret) return ret; @@ -270,17 +417,9 @@ static int amba_pm_runtime_resume(struct device *dev) return pm_generic_runtime_resume(dev); } -#endif - -#ifdef CONFIG_PM +#endif /* CONFIG_PM */ static const struct dev_pm_ops amba_pm = { - .suspend = amba_pm_suspend, - .resume = amba_pm_resume, - .freeze = amba_pm_freeze, - .thaw = amba_pm_thaw, - .poweroff = amba_pm_poweroff, - .restore = amba_pm_restore, SET_RUNTIME_PM_OPS( amba_pm_runtime_suspend, amba_pm_runtime_resume, @@ -288,25 +427,31 @@ static const struct dev_pm_ops amba_pm = { ) }; -#define AMBA_PM (&amba_pm) - -#else /* !CONFIG_PM */ - -#define AMBA_PM NULL - -#endif /* !CONFIG_PM */ - /* * Primecells are part of the Advanced Microcontroller Bus Architecture, * so we call the bus "amba". + * DMA configuration for platform and AMBA bus is same. So here we reuse + * platform's DMA config routine. */ -struct bus_type amba_bustype = { +const struct bus_type amba_bustype = { .name = "amba", - .dev_attrs = amba_dev_attrs, + .dev_groups = amba_dev_groups, .match = amba_match, .uevent = amba_uevent, - .pm = AMBA_PM, + .probe = amba_probe, + .remove = amba_remove, + .shutdown = amba_shutdown, + .dma_configure = amba_dma_configure, + .dma_cleanup = amba_dma_cleanup, + .pm = &amba_pm, }; +EXPORT_SYMBOL_GPL(amba_bustype); + +bool dev_is_amba(const struct device *dev) +{ + return dev->bus == &amba_bustype; +} +EXPORT_SYMBOL_GPL(dev_is_amba); static int __init amba_init(void) { @@ -315,119 +460,63 @@ static int __init amba_init(void) postcore_initcall(amba_init); -static int amba_get_enable_pclk(struct amba_device *pcdev) +static int amba_proxy_probe(struct amba_device *adev, + const struct amba_id *id) { - struct clk *pclk = clk_get(&pcdev->dev, "apb_pclk"); - int ret; - - pcdev->pclk = pclk; - - if (IS_ERR(pclk)) - return PTR_ERR(pclk); - - ret = clk_prepare(pclk); - if (ret) { - clk_put(pclk); - return ret; - } - - ret = clk_enable(pclk); - if (ret) { - clk_unprepare(pclk); - clk_put(pclk); - } - - return ret; -} - -static void amba_put_disable_pclk(struct amba_device *pcdev) -{ - struct clk *pclk = pcdev->pclk; - - clk_disable(pclk); - clk_unprepare(pclk); - clk_put(pclk); + WARN(1, "Stub driver should never match any device.\n"); + return -ENODEV; } -/* - * These are the device model conversion veneers; they convert the - * device model structures to our more specific structures. - */ -static int amba_probe(struct device *dev) -{ - struct amba_device *pcdev = to_amba_device(dev); - struct amba_driver *pcdrv = to_amba_driver(dev->driver); - const struct amba_id *id = amba_lookup(pcdrv->id_table, pcdev); - int ret; - - do { - ret = amba_get_enable_pclk(pcdev); - if (ret) - break; - - pm_runtime_get_noresume(dev); - pm_runtime_set_active(dev); - pm_runtime_enable(dev); - - ret = pcdrv->probe(pcdev, id); - if (ret == 0) - break; - - pm_runtime_disable(dev); - pm_runtime_set_suspended(dev); - pm_runtime_put_noidle(dev); - - amba_put_disable_pclk(pcdev); - } while (0); +static const struct amba_id amba_stub_drv_ids[] = { + { 0, 0 }, +}; - return ret; -} +static struct amba_driver amba_proxy_drv = { + .drv = { + .name = "amba-proxy", + }, + .probe = amba_proxy_probe, + .id_table = amba_stub_drv_ids, +}; -static int amba_remove(struct device *dev) +static int __init amba_stub_drv_init(void) { - struct amba_device *pcdev = to_amba_device(dev); - struct amba_driver *drv = to_amba_driver(dev->driver); - int ret; - - pm_runtime_get_sync(dev); - ret = drv->remove(pcdev); - pm_runtime_put_noidle(dev); - - /* Undo the runtime PM settings in amba_probe() */ - pm_runtime_disable(dev); - pm_runtime_set_suspended(dev); - pm_runtime_put_noidle(dev); - - amba_put_disable_pclk(pcdev); - - return ret; -} + if (!IS_ENABLED(CONFIG_MODULES)) + return 0; -static void amba_shutdown(struct device *dev) -{ - struct amba_driver *drv = to_amba_driver(dev->driver); - drv->shutdown(to_amba_device(dev)); + /* + * The amba_match() function will get called only if there is at least + * one amba driver registered. If all amba drivers are modules and are + * only loaded based on uevents, then we'll hit a chicken-and-egg + * situation where amba_match() is waiting on drivers and drivers are + * waiting on amba_match(). So, register a stub driver to make sure + * amba_match() is called even if no amba driver has been registered. + */ + return __amba_driver_register(&amba_proxy_drv, NULL); } +late_initcall_sync(amba_stub_drv_init); /** - * amba_driver_register - register an AMBA device driver + * __amba_driver_register - register an AMBA device driver * @drv: amba device driver structure + * @owner: owning module/driver * * Register an AMBA device driver with the Linux device model * core. If devices pre-exist, the drivers probe function will * be called. */ -int amba_driver_register(struct amba_driver *drv) +int __amba_driver_register(struct amba_driver *drv, + struct module *owner) { - drv->drv.bus = &amba_bustype; + if (!drv->probe) + return -EINVAL; -#define SETFN(fn) if (drv->fn) drv->drv.fn = amba_##fn - SETFN(probe); - SETFN(remove); - SETFN(shutdown); + drv->drv.owner = owner; + drv->drv.bus = &amba_bustype; return driver_register(&drv->drv); } +EXPORT_SYMBOL(__amba_driver_register); /** * amba_driver_unregister - remove an AMBA device driver @@ -441,14 +530,16 @@ void amba_driver_unregister(struct amba_driver *drv) { driver_unregister(&drv->drv); } - +EXPORT_SYMBOL(amba_driver_unregister); static void amba_device_release(struct device *dev) { struct amba_device *d = to_amba_device(dev); + fwnode_handle_put(dev_fwnode(&d->dev)); if (d->res.parent) release_resource(&d->res); + mutex_destroy(&d->periphid_lock); kfree(d); } @@ -463,155 +554,36 @@ static void amba_device_release(struct device *dev) */ int amba_device_add(struct amba_device *dev, struct resource *parent) { - u32 size; - void __iomem *tmp; - int i, ret; + int ret; - WARN_ON(dev->irq[0] == (unsigned int)-1); - WARN_ON(dev->irq[1] == (unsigned int)-1); + fwnode_handle_get(dev_fwnode(&dev->dev)); ret = request_resource(parent, &dev->res); if (ret) - goto err_out; - - /* Hard-coded primecell ID instead of plug-n-play */ - if (dev->periphid != 0) - goto skip_probe; - - /* - * Dynamically calculate the size of the resource - * and use this for iomap - */ - size = resource_size(&dev->res); - tmp = ioremap(dev->res.start, size); - if (!tmp) { - ret = -ENOMEM; - goto err_release; - } - - ret = amba_get_enable_pclk(dev); - if (ret == 0) { - u32 pid, cid; + return ret; + /* If primecell ID isn't hard-coded, figure it out */ + if (!dev->periphid) { /* - * Read pid and cid based on size of resource - * they are located at end of region + * AMBA device uevents require reading its pid and cid + * registers. To do this, the device must be on, clocked and + * out of reset. However in some cases those resources might + * not yet be available. If that's the case, we suppress the + * generation of uevents until we can read the pid and cid + * registers. See also amba_match(). */ - for (pid = 0, i = 0; i < 4; i++) - pid |= (readl(tmp + size - 0x20 + 4 * i) & 255) << - (i * 8); - for (cid = 0, i = 0; i < 4; i++) - cid |= (readl(tmp + size - 0x10 + 4 * i) & 255) << - (i * 8); - - amba_put_disable_pclk(dev); - - if (cid == AMBA_CID) - dev->periphid = pid; - - if (!dev->periphid) - ret = -ENODEV; + if (amba_read_periphid(dev)) + dev_set_uevent_suppress(&dev->dev, true); } - iounmap(tmp); - - if (ret) - goto err_release; - - skip_probe: ret = device_add(&dev->dev); if (ret) - goto err_release; - - if (dev->irq[0]) - ret = device_create_file(&dev->dev, &dev_attr_irq0); - if (ret == 0 && dev->irq[1]) - ret = device_create_file(&dev->dev, &dev_attr_irq1); - if (ret == 0) - return ret; - - device_unregister(&dev->dev); + release_resource(&dev->res); - err_release: - release_resource(&dev->res); - err_out: return ret; } EXPORT_SYMBOL_GPL(amba_device_add); -static struct amba_device * -amba_aphb_device_add(struct device *parent, const char *name, - resource_size_t base, size_t size, int irq1, int irq2, - void *pdata, unsigned int periphid, u64 dma_mask, - struct resource *resbase) -{ - struct amba_device *dev; - int ret; - - dev = amba_device_alloc(name, base, size); - if (!dev) - return ERR_PTR(-ENOMEM); - - dev->dma_mask = dma_mask; - dev->dev.coherent_dma_mask = dma_mask; - dev->irq[0] = irq1; - dev->irq[1] = irq2; - dev->periphid = periphid; - dev->dev.platform_data = pdata; - dev->dev.parent = parent; - - ret = amba_device_add(dev, resbase); - if (ret) { - amba_device_put(dev); - return ERR_PTR(ret); - } - - return dev; -} - -struct amba_device * -amba_apb_device_add(struct device *parent, const char *name, - resource_size_t base, size_t size, int irq1, int irq2, - void *pdata, unsigned int periphid) -{ - return amba_aphb_device_add(parent, name, base, size, irq1, irq2, pdata, - periphid, 0, &iomem_resource); -} -EXPORT_SYMBOL_GPL(amba_apb_device_add); - -struct amba_device * -amba_ahb_device_add(struct device *parent, const char *name, - resource_size_t base, size_t size, int irq1, int irq2, - void *pdata, unsigned int periphid) -{ - return amba_aphb_device_add(parent, name, base, size, irq1, irq2, pdata, - periphid, ~0ULL, &iomem_resource); -} -EXPORT_SYMBOL_GPL(amba_ahb_device_add); - -struct amba_device * -amba_apb_device_add_res(struct device *parent, const char *name, - resource_size_t base, size_t size, int irq1, - int irq2, void *pdata, unsigned int periphid, - struct resource *resbase) -{ - return amba_aphb_device_add(parent, name, base, size, irq1, irq2, pdata, - periphid, 0, resbase); -} -EXPORT_SYMBOL_GPL(amba_apb_device_add_res); - -struct amba_device * -amba_ahb_device_add_res(struct device *parent, const char *name, - resource_size_t base, size_t size, int irq1, - int irq2, void *pdata, unsigned int periphid, - struct resource *resbase) -{ - return amba_aphb_device_add(parent, name, base, size, irq1, irq2, pdata, - periphid, ~0ULL, resbase); -} -EXPORT_SYMBOL_GPL(amba_ahb_device_add_res); - - static void amba_device_initialize(struct amba_device *dev, const char *name) { device_initialize(&dev->dev); @@ -619,8 +591,10 @@ static void amba_device_initialize(struct amba_device *dev, const char *name) dev_set_name(&dev->dev, "%s", name); dev->dev.release = amba_device_release; dev->dev.bus = &amba_bustype; - dev->dev.dma_mask = &dev->dma_mask; + dev->dev.dma_mask = &dev->dev.coherent_dma_mask; + dev->dev.dma_parms = &dev->dma_parms; dev->res.name = dev_name(&dev->dev); + mutex_init(&dev->periphid_lock); } /** @@ -663,11 +637,9 @@ int amba_device_register(struct amba_device *dev, struct resource *parent) amba_device_initialize(dev, dev->dev.init_name); dev->dev.init_name = NULL; - if (!dev->dev.coherent_dma_mask && dev->dma_mask) - dev_warn(&dev->dev, "coherent dma mask is unset\n"); - return amba_device_add(dev, parent); } +EXPORT_SYMBOL(amba_device_register); /** * amba_device_put - put an AMBA device @@ -694,66 +666,7 @@ void amba_device_unregister(struct amba_device *dev) { device_unregister(&dev->dev); } - - -struct find_data { - struct amba_device *dev; - struct device *parent; - const char *busid; - unsigned int id; - unsigned int mask; -}; - -static int amba_find_match(struct device *dev, void *data) -{ - struct find_data *d = data; - struct amba_device *pcdev = to_amba_device(dev); - int r; - - r = (pcdev->periphid & d->mask) == d->id; - if (d->parent) - r &= d->parent == dev->parent; - if (d->busid) - r &= strcmp(dev_name(dev), d->busid) == 0; - - if (r) { - get_device(dev); - d->dev = pcdev; - } - - return r; -} - -/** - * amba_find_device - locate an AMBA device given a bus id - * @busid: bus id for device (or NULL) - * @parent: parent device (or NULL) - * @id: peripheral ID (or 0) - * @mask: peripheral ID mask (or 0) - * - * Return the AMBA device corresponding to the supplied parameters. - * If no device matches, returns NULL. - * - * NOTE: When a valid device is found, its refcount is - * incremented, and must be decremented before the returned - * reference. - */ -struct amba_device * -amba_find_device(const char *busid, struct device *parent, unsigned int id, - unsigned int mask) -{ - struct find_data data; - - data.dev = NULL; - data.parent = parent; - data.busid = busid; - data.id = id; - data.mask = mask; - - bus_for_each_dev(&amba_bustype, NULL, &data, amba_find_match); - - return data.dev; -} +EXPORT_SYMBOL(amba_device_unregister); /** * amba_request_regions - request all mem regions associated with device @@ -775,6 +688,7 @@ int amba_request_regions(struct amba_device *dev, const char *name) return ret; } +EXPORT_SYMBOL(amba_request_regions); /** * amba_release_regions - release mem regions associated with device @@ -789,11 +703,4 @@ void amba_release_regions(struct amba_device *dev) size = resource_size(&dev->res); release_mem_region(dev->res.start, size); } - -EXPORT_SYMBOL(amba_driver_register); -EXPORT_SYMBOL(amba_driver_unregister); -EXPORT_SYMBOL(amba_device_register); -EXPORT_SYMBOL(amba_device_unregister); -EXPORT_SYMBOL(amba_find_device); -EXPORT_SYMBOL(amba_request_regions); EXPORT_SYMBOL(amba_release_regions); |
