1 // SPDX-License-Identifier: GPL-2.0
3 * Xilinx UIO driver for AI Engine
5 * Copyright (C) 2018 Xilinx, Inc.
7 * Author: Hyun Woo Kwon <hyun.kwon@xilinx.com>
11 #include <linux/module.h>
13 #include <linux/of_device.h>
14 #include <linux/platform_data/uio_dmem_genirq.h>
15 #include <linux/platform_device.h>
16 #include <linux/uio_driver.h>
18 #define DRIVER_NAME "xilinx-aiengine"
20 static uint xilinx_ai_engine_mem_cnt = 1;
21 module_param_named(mem_cnt, xilinx_ai_engine_mem_cnt, uint, 0444);
22 MODULE_PARM_DESC(mem_cnt, "Dynamic memory allocation count (default: 1)");
24 static uint xilinx_ai_engine_mem_size = 32 * 1024 * 1024;
25 module_param_named(mem_size, xilinx_ai_engine_mem_size, uint, 0444);
26 MODULE_PARM_DESC(mem_size,
27 "Dynamic memory allocation size in bytes (default: 32 MB)");
29 static int xilinx_ai_engine_mem_index(struct uio_info *info,
30 struct vm_area_struct *vma)
32 if (vma->vm_pgoff < MAX_UIO_MAPS) {
33 if (info->mem[vma->vm_pgoff].size == 0)
35 return (int)vma->vm_pgoff;
40 static const struct vm_operations_struct xilinx_ai_engine_vm_ops = {
41 #ifdef CONFIG_HAVE_IOREMAP_PROT
42 .access = generic_access_phys,
46 static int xilinx_ai_engine_mmap(struct uio_info *info,
47 struct vm_area_struct *vma)
49 int mi = xilinx_ai_engine_mem_index(info, vma);
56 if (mem->addr & ~PAGE_MASK)
58 if (vma->vm_end - vma->vm_start > mem->size)
61 vma->vm_ops = &xilinx_ai_engine_vm_ops;
63 * Make the dynamic memory mapping as write-combined. Only first one
64 * will be the mmio region, which will be mapped as noncached.
67 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
69 vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
72 * We cannot use the vm_iomap_memory() helper here,
73 * because vma->vm_pgoff is the map index we looked
74 * up above in uio_find_mem_index(), rather than an
75 * actual page offset into the mmap.
77 * So we just do the physical mmap without a page
80 return remap_pfn_range(vma,
82 mem->addr >> PAGE_SHIFT,
83 vma->vm_end - vma->vm_start,
87 static int xilinx_ai_engine_probe(struct platform_device *pdev)
89 struct platform_device *uio;
90 struct uio_dmem_genirq_pdata *pdata;
94 uio = platform_device_alloc(DRIVER_NAME, PLATFORM_DEVID_NONE);
97 uio->driver_override = "uio_dmem_genirq";
98 uio->dev.parent = &pdev->dev;
100 pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
106 pdata->num_dynamic_regions = xilinx_ai_engine_mem_cnt;
107 pdata->dynamic_region_sizes = &xilinx_ai_engine_mem_size;
108 pdata->uioinfo.name = DRIVER_NAME;
109 pdata->uioinfo.version = "devicetree";
110 pdata->uioinfo.irq = UIO_IRQ_CUSTOM;
111 pdata->uioinfo.mmap = xilinx_ai_engine_mmap;
112 /* Set the offset value as it's map index for each memory */
113 for (i = 0; i < MAX_UIO_MAPS; i++)
114 pdata->uioinfo.mem[i].offs = i << PAGE_SHIFT;
115 ret = platform_device_add_data(uio, pdata, sizeof(*pdata));
119 /* Mirror the parent device resource to uio device */
120 ret = platform_device_add_resources(uio, pdev->resource,
121 pdev->num_resources);
125 /* Configure the dma for uio device using the parent of_node */
126 uio->dev.bus = &platform_bus_type;
127 ret = of_dma_configure(&uio->dev, of_node_get(pdev->dev.of_node), true);
128 of_node_put(pdev->dev.of_node);
132 ret = platform_device_add(uio);
135 platform_set_drvdata(uio, pdata);
136 platform_set_drvdata(pdev, uio);
138 dev_info(&pdev->dev, "Xilinx AI Engine UIO driver probed");
142 platform_device_put(pdev);
144 "failed to probe Xilinx AI Engine UIO driver");
148 static int xilinx_ai_engine_remove(struct platform_device *pdev)
150 struct platform_device *uio = platform_get_drvdata(pdev);
152 platform_device_unregister(uio);
153 of_node_put(pdev->dev.of_node);
158 static const struct of_device_id xilinx_ai_engine_of_match[] = {
159 { .compatible = "xlnx,ai_engine", },
160 { /* end of table */ },
162 MODULE_DEVICE_TABLE(of, xilinx_ai_engine_of_match);
164 static struct platform_driver xilinx_ai_engine_driver = {
165 .probe = xilinx_ai_engine_probe,
166 .remove = xilinx_ai_engine_remove,
169 .of_match_table = xilinx_ai_engine_of_match,
173 module_platform_driver(xilinx_ai_engine_driver);
175 MODULE_AUTHOR("Xilinx, Inc.");
176 MODULE_LICENSE("GPL v2");