/* called on periphid match and class 0x9 coresight device. */ staticint
amba_cs_uci_id_match(conststruct amba_id *table, struct amba_device *dev)
{ int ret = 0; struct amba_cs_uci_id *uci;
uci = table->data;
/* 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;
}
staticint amba_read_periphid(struct amba_device *dev)
{ struct reset_control *rstc;
u32 size, pid, cid; void __iomem *tmp; int i, ret;
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;
}
ret = amba_get_enable_pclk(dev); if (ret) {
dev_dbg(&dev->dev, "can't get pclk: %d\n", ret); goto err_pm;
}
/* * 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);
size = resource_size(&dev->res);
tmp = ioremap(dev->res.start, size); if (!tmp) {
ret = -ENOMEM; goto err_clk;
}
/* * 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);
if (cid == CORESIGHT_CID) { /* set the base to the start of the last 4k block */ void __iomem *csbase = tmp + size - 4096;
mutex_lock(&pcdev->periphid_lock); if (!pcdev->periphid) { int ret = amba_read_periphid(pcdev);
/* * 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);
/* When driver_override is set, only bind to the matching driver */ if (pcdev->driver_override) return !strcmp(pcdev->driver_override, drv->name);
staticint of_amba_device_decode_irq(struct amba_device *dev)
{ struct device_node *node = dev->dev.of_node; int i, irq = 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;
}
dev->irq[i] = irq;
}
}
return 0;
}
/* * These are the device model conversion veneers; they convert the * device model structures to our more specific structures.
*/ staticint amba_probe(struct device *dev)
{ struct amba_device *pcdev = to_amba_device(dev); struct amba_driver *pcdrv = to_amba_driver(dev->driver); conststruct amba_id *id = amba_lookup(pcdrv->id_table, pcdev); int ret;
do {
ret = of_amba_device_decode_irq(pcdev); if (ret) break;
ret = of_clk_set_defaults(dev->of_node, false); if (ret < 0) break;
ret = dev_pm_domain_attach(dev, PD_FLAG_ATTACH_POWER_ON); if (ret) break;
ret = amba_get_enable_pclk(pcdev); if (ret) {
dev_pm_domain_detach(dev, true); break;
}
drv = to_amba_driver(dev->driver); if (drv->shutdown)
drv->shutdown(to_amba_device(dev));
}
staticint amba_dma_configure(struct device *dev)
{ struct amba_driver *drv = to_amba_driver(dev->driver); enum dev_dma_attr attr; int ret = 0;
if (dev->of_node) {
ret = of_dma_configure(dev, dev->of_node, true);
} elseif (has_acpi_companion(dev)) {
attr = acpi_get_dma_attr(to_acpi_device_node(dev->fwnode));
ret = acpi_dma_configure(dev, attr);
}
/* @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);
}
if (!drv->driver_managed_dma)
iommu_device_unuse_default_domain(dev);
}
#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 * does not result in loss of context.
*/ staticint 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) { if (pm_runtime_is_irq_safe(dev))
clk_disable(pcdev->pclk); else
clk_disable_unprepare(pcdev->pclk);
}
if (dev->driver) { 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;
}
/* * 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.
*/ conststruct bus_type amba_bustype = {
.name = "amba",
.dev_groups = amba_dev_groups,
.match = amba_match,
.uevent = amba_uevent,
.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);
staticint amba_proxy_probe(struct amba_device *adev, conststruct amba_id *id)
{
WARN(1, "Stub driver should never match any device.\n"); return -ENODEV;
}
staticint __init amba_stub_drv_init(void)
{ if (!IS_ENABLED(CONFIG_MODULES)) return 0;
/* * 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 * @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, struct module *owner)
{ if (!drv->probe) return -EINVAL;
/** * amba_driver_unregister - remove an AMBA device driver * @drv: AMBA device driver structure to remove * * Unregister an AMBA device driver from the Linux device * model. The device model will call the drivers remove function * for each device the device driver is currently handling.
*/ void amba_driver_unregister(struct amba_driver *drv)
{
driver_unregister(&drv->drv);
}
EXPORT_SYMBOL(amba_driver_unregister);
fwnode_handle_put(dev_fwnode(&d->dev)); if (d->res.parent)
release_resource(&d->res);
mutex_destroy(&d->periphid_lock);
kfree(d);
}
/** * amba_device_add - add a previously allocated AMBA device structure * @dev: AMBA device allocated by amba_device_alloc * @parent: resource parent for this devices resources * * Claim the resource, and read the device cell ID if not already * initialized. Register the AMBA device with the Linux device * manager.
*/ int amba_device_add(struct amba_device *dev, struct resource *parent)
{ int ret;
fwnode_handle_get(dev_fwnode(&dev->dev));
ret = request_resource(parent, &dev->res); if (ret) return ret;
/* If primecell ID isn't hard-coded, figure it out */ if (!dev->periphid) { /* * 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().
*/ if (amba_read_periphid(dev))
dev_set_uevent_suppress(&dev->dev, true);
}
ret = device_add(&dev->dev); if (ret)
release_resource(&dev->res);
/** * amba_device_register - register an AMBA device * @dev: AMBA device to register * @parent: parent memory resource * * Setup the AMBA device, reading the cell ID if present. * Claim the resource, and register the AMBA device with * the Linux device manager.
*/ int amba_device_register(struct amba_device *dev, struct resource *parent)
{
amba_device_initialize(dev, dev->dev.init_name);
dev->dev.init_name = NULL;
/** * amba_device_put - put an AMBA device * @dev: AMBA device to put
*/ void amba_device_put(struct amba_device *dev)
{
put_device(&dev->dev);
}
EXPORT_SYMBOL_GPL(amba_device_put);
/** * amba_device_unregister - unregister an AMBA device * @dev: AMBA device to remove * * Remove the specified AMBA device from the Linux device * manager. All files associated with this object will be * destroyed, and device drivers notified that the device has * been removed. The AMBA device's resources including * the amba_device structure will be freed once all * references to it have been dropped.
*/ void amba_device_unregister(struct amba_device *dev)
{
device_unregister(&dev->dev);
}
EXPORT_SYMBOL(amba_device_unregister);
/** * amba_request_regions - request all mem regions associated with device * @dev: amba_device structure for device * @name: name, or NULL to use driver name
*/ int amba_request_regions(struct amba_device *dev, constchar *name)
{ int ret = 0;
u32 size;
if (!name)
name = dev->dev.driver->name;
size = resource_size(&dev->res);
if (!request_mem_region(dev->res.start, size, name))
ret = -EBUSY;
/** * amba_release_regions - release mem regions associated with device * @dev: amba_device structure for device * * Release regions claimed by a successful call to amba_request_regions.
*/ void amba_release_regions(struct amba_device *dev)
{
u32 size;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.