/** * of_platform_device_create_pdata - Alloc, initialize and register an of_device * @np: pointer to node to create device for * @bus_id: name to assign device * @platform_data: pointer to populate platform_data pointer with * @parent: Linux device model parent device. * * Returns pointer to created platform device, or NULL if a device was not * registered. Unavailable devices will not get registered. */ static struct platform_device *of_platform_device_create_pdata( struct device_node *np, const char *bus_id, void *platform_data, struct device *parent) { struct platform_device *dev; if (!of_device_is_available(np) || of_node_test_and_set_flag(np, OF_POPULATED)) return NULL; dev = of_device_alloc(np, bus_id, parent); if (!dev) goto err_clear_flag; dev->dev.bus = &platform_bus_type; dev->dev.platform_data = platform_data; of_dma_configure(&dev->dev, dev->dev.of_node); of_msi_configure(&dev->dev, dev->dev.of_node); if (of_device_add(dev) != 0) { of_dma_deconfigure(&dev->dev); platform_device_put(dev); goto err_clear_flag; } return dev; err_clear_flag: of_node_clear_flag(np, OF_POPULATED); return NULL; }
int platform_dma_configure(struct device *dev) { enum dev_dma_attr attr; int ret = 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); } return ret; }
static struct amba_device *of_amba_device_create(struct device_node *node, const char *bus_id, void *platform_data, struct device *parent) { struct amba_device *dev; const void *prop; int i, ret; pr_debug("Creating amba device %s\n", node->full_name); if (!of_device_is_available(node) || of_node_test_and_set_flag(node, OF_POPULATED)) return NULL; dev = amba_device_alloc(NULL, 0, 0); if (!dev) goto err_clear_flag; /* setup generic device info */ dev->dev.of_node = of_node_get(node); dev->dev.fwnode = &node->fwnode; dev->dev.parent = parent ? : &platform_bus; dev->dev.platform_data = platform_data; if (bus_id) dev_set_name(&dev->dev, "%s", bus_id); else of_device_make_bus_id(&dev->dev); of_dma_configure(&dev->dev, dev->dev.of_node); /* Allow the HW Peripheral ID to be overridden */ prop = of_get_property(node, "arm,primecell-periphid", NULL); if (prop) dev->periphid = of_read_ulong(prop, 1); /* Decode the IRQs and address ranges */ for (i = 0; i < AMBA_NR_IRQS; i++) dev->irq[i] = irq_of_parse_and_map(node, i); ret = of_address_to_resource(node, 0, &dev->res); if (ret) { pr_err("amba: of_address_to_resource() failed (%d) for %s\n", ret, node->full_name); goto err_free; } ret = amba_device_add(dev, &iomem_resource); if (ret) { pr_err("amba_device_add() failed (%d) for %s\n", ret, node->full_name); goto err_free; } return dev; err_free: amba_device_put(dev); err_clear_flag: of_node_clear_flag(node, OF_POPULATED); return NULL; }
int a6xx_gmu_init(struct a6xx_gpu *a6xx_gpu, struct device_node *node) { struct a6xx_gmu *gmu = &a6xx_gpu->gmu; struct platform_device *pdev = of_find_device_by_node(node); int ret; if (!pdev) return -ENODEV; gmu->dev = &pdev->dev; of_dma_configure(gmu->dev, node, true); /* Fow now, don't do anything fancy until we get our feet under us */ gmu->idle_level = GMU_IDLE_STATE_ACTIVE; pm_runtime_enable(gmu->dev); /* Get the list of clocks */ ret = a6xx_gmu_clocks_probe(gmu); if (ret) goto err_put_device; /* Set up the IOMMU context bank */ ret = a6xx_gmu_memory_probe(gmu); if (ret) goto err_put_device; /* Allocate memory for for the HFI queues */ gmu->hfi = a6xx_gmu_memory_alloc(gmu, SZ_16K); if (IS_ERR(gmu->hfi)) goto err_memory; /* Allocate memory for the GMU debug region */ gmu->debug = a6xx_gmu_memory_alloc(gmu, SZ_16K); if (IS_ERR(gmu->debug)) goto err_memory; /* Map the GMU registers */ gmu->mmio = a6xx_gmu_get_mmio(pdev, "gmu"); if (IS_ERR(gmu->mmio)) goto err_memory; /* Get the HFI and GMU interrupts */ gmu->hfi_irq = a6xx_gmu_get_irq(gmu, pdev, "hfi", a6xx_hfi_irq); gmu->gmu_irq = a6xx_gmu_get_irq(gmu, pdev, "gmu", a6xx_gmu_irq); if (gmu->hfi_irq < 0 || gmu->gmu_irq < 0) goto err_mmio; /* * Get a link to the GX power domain to reset the GPU in case of GMU * crash */ gmu->gxpd = dev_pm_domain_attach_by_name(gmu->dev, "gx"); /* Get the power levels for the GMU and GPU */ a6xx_gmu_pwrlevels_probe(gmu); /* Set up the HFI queues */ a6xx_hfi_init(gmu); gmu->initialized = true; return 0; err_mmio: iounmap(gmu->mmio); free_irq(gmu->gmu_irq, gmu); free_irq(gmu->hfi_irq, gmu); err_memory: a6xx_gmu_memory_free(gmu, gmu->hfi); if (gmu->domain) { iommu_detach_device(gmu->domain, gmu->dev); iommu_domain_free(gmu->domain); } ret = -ENODEV; err_put_device: /* Drop reference taken in of_find_device_by_node */ put_device(gmu->dev); return ret; }
int a6xx_gmu_probe(struct a6xx_gpu *a6xx_gpu, struct device_node *node) { struct a6xx_gmu *gmu = &a6xx_gpu->gmu; struct platform_device *pdev = of_find_device_by_node(node); int ret; if (!pdev) return -ENODEV; gmu->dev = &pdev->dev; of_dma_configure(gmu->dev, node, false); /* Fow now, don't do anything fancy until we get our feet under us */ gmu->idle_level = GMU_IDLE_STATE_ACTIVE; pm_runtime_enable(gmu->dev); gmu->gx = devm_regulator_get(gmu->dev, "vdd"); /* Get the list of clocks */ ret = a6xx_gmu_clocks_probe(gmu); if (ret) return ret; /* Set up the IOMMU context bank */ ret = a6xx_gmu_memory_probe(gmu); if (ret) return ret; /* Allocate memory for for the HFI queues */ gmu->hfi = a6xx_gmu_memory_alloc(gmu, SZ_16K); if (IS_ERR(gmu->hfi)) goto err; /* Allocate memory for the GMU debug region */ gmu->debug = a6xx_gmu_memory_alloc(gmu, SZ_16K); if (IS_ERR(gmu->debug)) goto err; /* Map the GMU registers */ gmu->mmio = a6xx_gmu_get_mmio(pdev, "gmu"); /* Map the GPU power domain controller registers */ gmu->pdc_mmio = a6xx_gmu_get_mmio(pdev, "gmu_pdc"); if (IS_ERR(gmu->mmio) || IS_ERR(gmu->pdc_mmio)) goto err; /* Get the HFI and GMU interrupts */ gmu->hfi_irq = a6xx_gmu_get_irq(gmu, pdev, "hfi", a6xx_hfi_irq); gmu->gmu_irq = a6xx_gmu_get_irq(gmu, pdev, "gmu", a6xx_gmu_irq); if (gmu->hfi_irq < 0 || gmu->gmu_irq < 0) goto err; /* Set up a tasklet to handle GMU HFI responses */ tasklet_init(&gmu->hfi_tasklet, a6xx_hfi_task, (unsigned long) gmu); /* Get the power levels for the GMU and GPU */ a6xx_gmu_pwrlevels_probe(gmu); /* Set up the HFI queues */ a6xx_hfi_init(gmu); return 0; err: a6xx_gmu_memory_free(gmu, gmu->hfi); if (gmu->domain) { iommu_detach_device(gmu->domain, gmu->dev); iommu_domain_free(gmu->domain); } return -ENODEV; }
static int __init hidma_mgmt_of_populate_channels(struct device_node *np) { struct platform_device *pdev_parent = of_find_device_by_node(np); struct platform_device_info pdevinfo; struct of_phandle_args out_irq; struct device_node *child; struct resource *res; const __be32 *cell; int ret = 0, size, i, num; u64 addr, addr_size; for_each_available_child_of_node(np, child) { struct resource *res_iter; struct platform_device *new_pdev; cell = of_get_property(child, "reg", &size); if (!cell) { ret = -EINVAL; goto out; } size /= sizeof(*cell); num = size / (of_n_addr_cells(child) + of_n_size_cells(child)) + 1; /* allocate a resource array */ res = kcalloc(num, sizeof(*res), GFP_KERNEL); if (!res) { ret = -ENOMEM; goto out; } /* read each reg value */ i = 0; res_iter = res; while (i < size) { addr = of_read_number(&cell[i], of_n_addr_cells(child)); i += of_n_addr_cells(child); addr_size = of_read_number(&cell[i], of_n_size_cells(child)); i += of_n_size_cells(child); res_iter->start = addr; res_iter->end = res_iter->start + addr_size - 1; res_iter->flags = IORESOURCE_MEM; res_iter++; } ret = of_irq_parse_one(child, 0, &out_irq); if (ret) goto out; res_iter->start = irq_create_of_mapping(&out_irq); res_iter->name = "hidma event irq"; res_iter->flags = IORESOURCE_IRQ; memset(&pdevinfo, 0, sizeof(pdevinfo)); pdevinfo.fwnode = &child->fwnode; pdevinfo.parent = pdev_parent ? &pdev_parent->dev : NULL; pdevinfo.name = child->name; pdevinfo.id = object_counter++; pdevinfo.res = res; pdevinfo.num_res = num; pdevinfo.data = NULL; pdevinfo.size_data = 0; pdevinfo.dma_mask = DMA_BIT_MASK(64); new_pdev = platform_device_register_full(&pdevinfo); if (IS_ERR(new_pdev)) { ret = PTR_ERR(new_pdev); goto out; } of_node_get(child); new_pdev->dev.of_node = child; of_dma_configure(&new_pdev->dev, child); /* * It is assumed that calling of_msi_configure is safe on * platforms with or without MSI support. */ of_msi_configure(&new_pdev->dev, child); of_node_put(child); kfree(res); res = NULL; } out: kfree(res); return ret; }