1 /*
2 * File name: hplibmod.c
3 *
4 * Description: HPLIB utility module.
5 *
6 * Copyright (C) 2013 Texas Instruments, Incorporated
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation version 2.
11 *
12 * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
13 * whether express or implied; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 */
19 #include <linux/init.h>
20 #include <linux/module.h>
21 #include <linux/kernel.h>
22 #include <linux/fs.h>
23 #include <linux/sysfs.h>
24 #include <linux/version.h>
25 #include <linux/unistd.h>
26 #include <asm/unistd.h>
27 #include <linux/wait.h>
28 #include <linux/sched.h>
29 #include <linux/timer.h>
30 #include <linux/string.h>
31 #include <linux/if.h>
33 #include <asm/uaccess.h>
34 #include <linux/dma-mapping.h>
36 #include <asm/irq.h>
37 #include <linux/clk.h>
39 #include <asm/mach/map.h>
41 #include <linux/hrtimer.h>
43 #include "../hplibmod.h"
45 #include <asm/pgtable.h>
47 #define HPLIBMOD_DEBUG
49 #define HPLIBMOD_DEVNAME "hplib"
51 #ifdef HPLIBMOD_DEBUG
52 # define __D(fmt, args...) printk(KERN_DEBUG "HPLIBMOD Debug: " fmt, ## args)
53 #else
54 # define __D(fmt, args...)
55 #endif
57 #define __E(fmt, args...) printk(KERN_ERR "HPLIBMOD Error: " fmt, ## args)
59 #define LINE_LEN 50
60 static struct class *hplibmod_class;
61 static int hplibmod_major;
63 static dma_addr_t dmaAddr; /*physical address of CMA region */
64 static void * cpuAddr=NULL; /* virtual address for above */
65 static void * userVmaStart = NULL;
67 static unsigned int memSize = HPLIBMOD_MEMSZ;
68 module_param(memSize, uint, 0);
69 MODULE_PARM_DESC(memSize, "Size of DMA coherent memory to be allocated");
71 #ifdef CORTEX_A8
72 static void MPU_Enable_userModeAccess(void)
73 {
74 unsigned int reg_addr,i,count,defRegVal;
75 void __iomem * temp_reg;
76 defRegVal = 0x3FFFFFF;
77 reg_addr = 0x2368208;
78 count = 5;
80 for(i=1;i<=count;i++) {
81 temp_reg= ioremap(reg_addr, 4);
82 __raw_writel(defRegVal, temp_reg) ;
83 iounmap(temp_reg);
84 reg_addr = reg_addr + 0x10;
85 }
87 reg_addr = 0x2370208;
88 count = 16;
90 for(i=1;i<=count;i++) {
91 temp_reg= ioremap(reg_addr, 4);
92 __raw_writel(defRegVal,temp_reg) ;
93 iounmap(temp_reg);
94 reg_addr = reg_addr + 0x10;
95 }
97 reg_addr = 0x2378208;
98 count = 1;
100 for(i=1;i<=count;i++) {
101 temp_reg= ioremap(reg_addr, 4);
102 __raw_writel(defRegVal, temp_reg) ;
103 iounmap(temp_reg);
105 reg_addr = reg_addr + 0x10;
106 }
107 }
108 #endif
110 static ssize_t hplib_show(struct device *dev,
111 struct device_attribute *attr,
112 char *buf)
113 {
114 int len = 0;
116 len += snprintf(buf + len, LINE_LEN, "HPLIBMOD Info\n");
117 len += snprintf(buf + len, LINE_LEN, "======================\n");
118 len += snprintf(buf + len, LINE_LEN, "CMA memory properties :\n");
119 len += snprintf(buf + len, LINE_LEN, "Device viewed CMA physical address 0x%x\n", (unsigned int) dmaAddr);
120 len += snprintf(buf + len, LINE_LEN, "CPU viewed CMA virtual address 0x%x\n", (unsigned int) cpuAddr);
121 len += snprintf(buf + len, LINE_LEN, "Size of CMA allocated 0x%x\n", memSize);
123 return len;
125 }
127 static DEVICE_ATTR(hplib, S_IRUGO, hplib_show, NULL);
129 static int hplibmod_core_setup(void)
130 {
131 unsigned long val;
134 //enable user access to qmss h/w
135 #ifdef CORTEX_A8
136 MPU_Enable_userModeAccess();
137 #endif
138 //pmcr <- single clock, reset, enable
139 val = 0x4|0x1;
140 asm volatile("mcr p15, 0, %0, c9, c12, 0" : : "r"(val));
142 /*userenr <- enable user space access */
143 val = 1;
144 asm volatile("mcr p15, 0, %0, c9, c14, 0" : : "r"(val));
146 val = 0x80000000;
147 asm volatile("mcr p15, 0, %0, c9, c12, 1" :: "r"(val));
149 asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r"(val));
150 #ifndef CORTEX_A8
151 /* enabling of arm timer for user space */
152 asm volatile("mrc p15, 0, %0, c14, c1, 0" : "=r"(val));
153 val |= 0x3;
154 asm volatile("mcr p15, 0, %0, c14, c1, 0" : : "r"(val));
155 #endif
157 return 0;
158 }
159 static long hplibmod_ioctl(struct file *filp, unsigned int cmd, unsigned long args)
160 {
161 unsigned int __user *argp = (unsigned int __user *) args;
162 struct hplibmod_block block;
163 unsigned long physp;
165 if (_IOC_TYPE(cmd) != _IOC_TYPE(HPLIBMOD_IOCMAGIC)) {
166 __E("ioctl(): bad command type 0x%x (should be 0x%x)\n",
167 _IOC_TYPE(cmd), _IOC_TYPE(HPLIBMOD_IOCMAGIC));
168 }
170 switch (cmd & HPLIBMOD_IOCCMDMASK) {
171 case HPLIBMOD_IOINIT:
172 __D("INIT ioctl received.\n");
173 hplibmod_core_setup();
174 break;
176 case HPLIBMOD_IOCGETPHYS:
177 __D("GETPHYS ioctl received.\n");
179 if (put_user((unsigned long)dmaAddr, argp)) {
180 return -EFAULT;
181 }
183 __D("GETPHYS returning %#llx\n", (long long)dmaAddr);
184 break;
186 case HPLIBMOD_IOCCACHE:
187 __D("CACHE%s%s ioctl received.\n",
188 cmd & HPLIBMOD_WB ? "WB" : "", cmd & HPLIBMOD_INV ? "INV" : "");
190 if (copy_from_user(&block, argp, sizeof(block))) {
191 return -EFAULT;
192 }
193 physp = (unsigned long)dmaAddr +
194 (block.addr - (unsigned long)userVmaStart);
196 switch (cmd & ~HPLIBMOD_IOCMAGIC) {
197 case HPLIBMOD_IOCCACHEWB:
198 dma_sync_single_for_device(NULL, (dma_addr_t)physp,
199 block.size, DMA_TO_DEVICE);
200 break;
202 case HPLIBMOD_IOCCACHEINV:
203 dma_sync_single_for_cpu(NULL, (dma_addr_t)physp,
204 block.size, DMA_FROM_DEVICE);
205 break;
207 case HPLIBMOD_IOCCACHEWBINV:
208 dma_sync_single_for_device(NULL, (dma_addr_t)physp,
209 block.size, DMA_TO_DEVICE);
210 dma_sync_single_for_cpu(NULL, (dma_addr_t)physp,
211 block.size, DMA_FROM_DEVICE);
212 break;
214 } /* switch cmd */
216 __D("CACHE%s%s ioctl returned vaddr=0x%p size=0x%x paddr=0x%p.\n",
217 cmd & HPLIBMOD_WB ? "WB" : "",
218 cmd & HPLIBMOD_INV ? "INV" : "",
219 (void *)block.addr, block.size, (void *)physp);
220 break;
222 case HPLIBMOD_IOCGETSIZE:
223 __D("GETSIZE ioctl received.\n");
225 if (put_user((unsigned long)memSize, argp)) {
226 return -EFAULT;
227 }
229 __D("GETSIZE returning %#1x\n", (unsigned int)memSize);
230 break;
232 default:
233 __E("Unknown ioctl received.\n");
234 return -EINVAL;
236 } /* switch base cmd */
238 return 0;
239 }
241 #define PROT_PTE_DEVICE (L_PTE_PRESENT|L_PTE_YOUNG|L_PTE_DIRTY|L_PTE_XN)
243 #define hplibmod_pgprot_dev_buffer(prot) \
244 __pgprot_modify(prot, L_PTE_MT_MASK, PROT_PTE_DEVICE | \
245 L_PTE_MT_DEV_SHARED | L_PTE_SHARED)
247 static int hplibmod_mmap(struct file *filp, struct vm_area_struct *vma)
248 {
249 size_t size = vma->vm_end - vma->vm_start;
251 __D("mmap: vma->vm_start = %#lx\n", vma->vm_start);
252 __D("mmap: vma->vm_pgoff = %#lx\n", vma->vm_pgoff);
253 __D("mmap: vma->vm_end = %#lx\n", vma->vm_end);
254 __D("mmap: size = 0x%x\n", size);
256 switch ((vma->vm_pgoff << PAGE_SHIFT))
257 {
258 case HPLIBMOD_MMAP_DMA_MEM_OFFSET:
259 userVmaStart = (void *)vma->vm_start;
260 __D("mmap: calling dma_mmap_coherent\n");
261 return dma_mmap_coherent(NULL, vma, cpuAddr, dmaAddr, size);
262 break;
264 case HPLIBMOD_MMAP_QM_DATA_REG_MEM_OFFSET:
265 vma->vm_page_prot = hplibmod_pgprot_dev_buffer(vma->vm_page_prot);
266 if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, size,
267 vma->vm_page_prot)) {
268 return -EAGAIN;
269 }
270 __D("mmap: page_prot=%#lx\n", (long unsigned int) vma->vm_page_prot);
271 return 0;
272 break;
274 default:
275 return -EINVAL;
276 }
277 }
279 static int hplibmod_open(struct inode *inode, struct file *filp)
280 {
281 __D("open: called.\n");
282 return 0;
283 }
285 static int hplibmod_release(struct inode *inode, struct file *filp)
286 {
287 __D("close: called.\n");
288 return 0;
289 }
291 static struct file_operations hplibmod_fxns = {
292 owner: THIS_MODULE,
293 unlocked_ioctl: hplibmod_ioctl,
294 mmap: hplibmod_mmap,
295 open: hplibmod_open,
296 release: hplibmod_release
297 };
298 static struct device *hplib_dev;
300 /*********************************************************************************
301 * FUNCTION: hplibmod_init_module
302 *
303 * DESCRIPTION:Initialization routine for hplib kernel device
304 *********************************************************************************/
305 static int __init hplibmod_init_module(void)
306 {
307 int ret;
309 __D("init\n");
311 /* allocate space from CMA */
312 cpuAddr = dma_alloc_coherent(NULL,
313 memSize,
314 &dmaAddr,
315 GFP_KERNEL | GFP_DMA);
317 if (!cpuAddr) {
318 __E("Error allocating from CMA for size 0x%x\n", memSize);
319 return -ENOMEM;
320 } else {
321 __D("hplibmod_init_module: Allocated 0x%x size memory from CMA.\n",memSize);
322 __D("hplibmod_init_module: dmaAddr %#llx\n", (long long)dmaAddr);
323 }
324 hplibmod_major = register_chrdev(0, HPLIBMOD_DEVNAME, &hplibmod_fxns);
326 if (hplibmod_major < 0) {
327 __E("Failed to allocate major number.\n");
328 ret = -ENODEV;
329 goto cleanup_mem;
330 }
332 __D("Allocated major number: %d\n", hplibmod_major);
334 hplibmod_class = class_create(THIS_MODULE, HPLIBMOD_DEVNAME);
335 if (IS_ERR(hplibmod_class)) {
336 __E("Error creating hplib device class.\n");
337 ret = PTR_ERR(hplibmod_class);
338 goto cleanup_dev;
339 }
341 hplib_dev = device_create(hplibmod_class, NULL, MKDEV(hplibmod_major, 0), NULL,
342 HPLIBMOD_DEVNAME);
344 if (IS_ERR(hplib_dev)) {
345 __E("Error creating hplib device .\n");
346 ret = PTR_ERR(hplib_dev);
347 goto cleanup_dev;
348 }
349 device_create_file(hplib_dev,&dev_attr_hplib);
351 __D("module loaded\n");
353 return 0;
355 cleanup_dev:
356 unregister_chrdev(hplibmod_major, HPLIBMOD_DEVNAME);
357 cleanup_mem:
358 dma_free_coherent(NULL, memSize, cpuAddr, dmaAddr);
360 return ret;
361 }
363 /*********************************************************************************
364 * FUNCTION: hplibmod_cleanup_module
365 *
366 * DESCRIPTION:
367 *********************************************************************************/
368 static void __exit hplibmod_cleanup_module(void)
369 {
370 /* Remove netapi device */
371 device_destroy(hplibmod_class, MKDEV(hplibmod_major, 0));
372 unregister_chrdev(hplibmod_major, HPLIBMOD_DEVNAME);
373 class_destroy(hplibmod_class);
375 /* Free CMA buffer */
376 dma_free_coherent(NULL, memSize, cpuAddr, dmaAddr);
378 __D("module unloaded\n");
379 return;
380 }
382 module_init(hplibmod_init_module);
383 module_exit(hplibmod_cleanup_module);
386 MODULE_AUTHOR("Texas Instruments Incorporated");
387 MODULE_DESCRIPTION("TI HPLIB kernel module.");
388 MODULE_SUPPORTED_DEVICE("Texas Instruments hplib");
389 MODULE_LICENSE("GPL v2");