17663b294f7c803322cbdac7e0f3657af136ca85
[oweals/openwrt.git] /
1 From cfdf39199781b73840dfdfb7d1281b398c1334cf Mon Sep 17 00:00:00 2001
2 From: popcornmix <popcornmix@gmail.com>
3 Date: Fri, 28 Oct 2016 15:36:43 +0100
4 Subject: [PATCH] vc_mem: Add vc_mem driver for querying firmware
5  memory addresses
6 MIME-Version: 1.0
7 Content-Type: text/plain; charset=UTF-8
8 Content-Transfer-Encoding: 8bit
9
10 Signed-off-by: popcornmix <popcornmix@gmail.com>
11
12 BCM270x: Move vc_mem
13
14 Make the vc_mem module available for ARCH_BCM2835 by moving it.
15
16 Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
17 ---
18  drivers/char/broadcom/Kconfig   |  18 ++
19  drivers/char/broadcom/Makefile  |   1 +
20  drivers/char/broadcom/vc_mem.c  | 422 ++++++++++++++++++++++++++++++++
21  include/linux/broadcom/vc_mem.h |  35 +++
22  4 files changed, 476 insertions(+)
23  create mode 100644 drivers/char/broadcom/Kconfig
24  create mode 100644 drivers/char/broadcom/Makefile
25  create mode 100644 drivers/char/broadcom/vc_mem.c
26  create mode 100644 include/linux/broadcom/vc_mem.h
27
28 --- /dev/null
29 +++ b/drivers/char/broadcom/Kconfig
30 @@ -0,0 +1,18 @@
31 +#
32 +# Broadcom char driver config
33 +#
34 +
35 +menuconfig BRCM_CHAR_DRIVERS
36 +       bool "Broadcom Char Drivers"
37 +       help
38 +         Broadcom's char drivers
39 +
40 +if BRCM_CHAR_DRIVERS
41 +
42 +config BCM2708_VCMEM
43 +       bool "Videocore Memory"
44 +        default y
45 +        help
46 +          Helper for videocore memory access and total size allocation.
47 +
48 +endif
49 --- /dev/null
50 +++ b/drivers/char/broadcom/Makefile
51 @@ -0,0 +1 @@
52 +obj-$(CONFIG_BCM2708_VCMEM)    += vc_mem.o
53 --- /dev/null
54 +++ b/drivers/char/broadcom/vc_mem.c
55 @@ -0,0 +1,422 @@
56 +/*****************************************************************************
57 +* Copyright 2010 - 2011 Broadcom Corporation.  All rights reserved.
58 +*
59 +* Unless you and Broadcom execute a separate written software license
60 +* agreement governing use of this software, this software is licensed to you
61 +* under the terms of the GNU General Public License version 2, available at
62 +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
63 +*
64 +* Notwithstanding the above, under no circumstances may you combine this
65 +* software in any way with any other Broadcom software provided under a
66 +* license other than the GPL, without Broadcom's express prior written
67 +* consent.
68 +*****************************************************************************/
69 +
70 +#include <linux/kernel.h>
71 +#include <linux/module.h>
72 +#include <linux/fs.h>
73 +#include <linux/device.h>
74 +#include <linux/cdev.h>
75 +#include <linux/mm.h>
76 +#include <linux/slab.h>
77 +#include <linux/debugfs.h>
78 +#include <linux/uaccess.h>
79 +#include <linux/dma-mapping.h>
80 +#include <linux/broadcom/vc_mem.h>
81 +
82 +#define DRIVER_NAME  "vc-mem"
83 +
84 +// Device (/dev) related variables
85 +static dev_t vc_mem_devnum = 0;
86 +static struct class *vc_mem_class = NULL;
87 +static struct cdev vc_mem_cdev;
88 +static int vc_mem_inited = 0;
89 +
90 +#ifdef CONFIG_DEBUG_FS
91 +static struct dentry *vc_mem_debugfs_entry;
92 +#endif
93 +
94 +/*
95 + * Videocore memory addresses and size
96 + *
97 + * Drivers that wish to know the videocore memory addresses and sizes should
98 + * use these variables instead of the MM_IO_BASE and MM_ADDR_IO defines in
99 + * headers. This allows the other drivers to not be tied down to a a certain
100 + * address/size at compile time.
101 + *
102 + * In the future, the goal is to have the videocore memory virtual address and
103 + * size be calculated at boot time rather than at compile time. The decision of
104 + * where the videocore memory resides and its size would be in the hands of the
105 + * bootloader (and/or kernel). When that happens, the values of these variables
106 + * would be calculated and assigned in the init function.
107 + */
108 +// in the 2835 VC in mapped above ARM, but ARM has full access to VC space
109 +unsigned long mm_vc_mem_phys_addr = 0x00000000;
110 +unsigned int mm_vc_mem_size = 0;
111 +unsigned int mm_vc_mem_base = 0;
112 +
113 +EXPORT_SYMBOL(mm_vc_mem_phys_addr);
114 +EXPORT_SYMBOL(mm_vc_mem_size);
115 +EXPORT_SYMBOL(mm_vc_mem_base);
116 +
117 +static uint phys_addr = 0;
118 +static uint mem_size = 0;
119 +static uint mem_base = 0;
120 +
121 +
122 +/****************************************************************************
123 +*
124 +*   vc_mem_open
125 +*
126 +***************************************************************************/
127 +
128 +static int
129 +vc_mem_open(struct inode *inode, struct file *file)
130 +{
131 +       (void) inode;
132 +       (void) file;
133 +
134 +       pr_debug("%s: called file = 0x%p\n", __func__, file);
135 +
136 +       return 0;
137 +}
138 +
139 +/****************************************************************************
140 +*
141 +*   vc_mem_release
142 +*
143 +***************************************************************************/
144 +
145 +static int
146 +vc_mem_release(struct inode *inode, struct file *file)
147 +{
148 +       (void) inode;
149 +       (void) file;
150 +
151 +       pr_debug("%s: called file = 0x%p\n", __func__, file);
152 +
153 +       return 0;
154 +}
155 +
156 +/****************************************************************************
157 +*
158 +*   vc_mem_get_size
159 +*
160 +***************************************************************************/
161 +
162 +static void
163 +vc_mem_get_size(void)
164 +{
165 +}
166 +
167 +/****************************************************************************
168 +*
169 +*   vc_mem_get_base
170 +*
171 +***************************************************************************/
172 +
173 +static void
174 +vc_mem_get_base(void)
175 +{
176 +}
177 +
178 +/****************************************************************************
179 +*
180 +*   vc_mem_get_current_size
181 +*
182 +***************************************************************************/
183 +
184 +int
185 +vc_mem_get_current_size(void)
186 +{
187 +       return mm_vc_mem_size;
188 +}
189 +
190 +EXPORT_SYMBOL_GPL(vc_mem_get_current_size);
191 +
192 +/****************************************************************************
193 +*
194 +*   vc_mem_ioctl
195 +*
196 +***************************************************************************/
197 +
198 +static long
199 +vc_mem_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
200 +{
201 +       int rc = 0;
202 +
203 +       (void) cmd;
204 +       (void) arg;
205 +
206 +       pr_debug("%s: called file = 0x%p\n", __func__, file);
207 +
208 +       switch (cmd) {
209 +       case VC_MEM_IOC_MEM_PHYS_ADDR:
210 +               {
211 +                       pr_debug("%s: VC_MEM_IOC_MEM_PHYS_ADDR=0x%p\n",
212 +                               __func__, (void *) mm_vc_mem_phys_addr);
213 +
214 +                       if (copy_to_user((void *) arg, &mm_vc_mem_phys_addr,
215 +                                        sizeof (mm_vc_mem_phys_addr)) != 0) {
216 +                               rc = -EFAULT;
217 +                       }
218 +                       break;
219 +               }
220 +       case VC_MEM_IOC_MEM_SIZE:
221 +               {
222 +                       // Get the videocore memory size first
223 +                       vc_mem_get_size();
224 +
225 +                       pr_debug("%s: VC_MEM_IOC_MEM_SIZE=%u\n", __func__,
226 +                               mm_vc_mem_size);
227 +
228 +                       if (copy_to_user((void *) arg, &mm_vc_mem_size,
229 +                                        sizeof (mm_vc_mem_size)) != 0) {
230 +                               rc = -EFAULT;
231 +                       }
232 +                       break;
233 +               }
234 +       case VC_MEM_IOC_MEM_BASE:
235 +               {
236 +                       // Get the videocore memory base
237 +                       vc_mem_get_base();
238 +
239 +                       pr_debug("%s: VC_MEM_IOC_MEM_BASE=%u\n", __func__,
240 +                               mm_vc_mem_base);
241 +
242 +                       if (copy_to_user((void *) arg, &mm_vc_mem_base,
243 +                                        sizeof (mm_vc_mem_base)) != 0) {
244 +                               rc = -EFAULT;
245 +                       }
246 +                       break;
247 +               }
248 +       case VC_MEM_IOC_MEM_LOAD:
249 +               {
250 +                       // Get the videocore memory base
251 +                       vc_mem_get_base();
252 +
253 +                       pr_debug("%s: VC_MEM_IOC_MEM_LOAD=%u\n", __func__,
254 +                               mm_vc_mem_base);
255 +
256 +                       if (copy_to_user((void *) arg, &mm_vc_mem_base,
257 +                                        sizeof (mm_vc_mem_base)) != 0) {
258 +                               rc = -EFAULT;
259 +                       }
260 +                       break;
261 +               }
262 +       default:
263 +               {
264 +                       return -ENOTTY;
265 +               }
266 +       }
267 +       pr_debug("%s: file = 0x%p returning %d\n", __func__, file, rc);
268 +
269 +       return rc;
270 +}
271 +
272 +/****************************************************************************
273 +*
274 +*   vc_mem_mmap
275 +*
276 +***************************************************************************/
277 +
278 +static int
279 +vc_mem_mmap(struct file *filp, struct vm_area_struct *vma)
280 +{
281 +       int rc = 0;
282 +       unsigned long length = vma->vm_end - vma->vm_start;
283 +       unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
284 +
285 +       pr_debug("%s: vm_start = 0x%08lx vm_end = 0x%08lx vm_pgoff = 0x%08lx\n",
286 +               __func__, (long) vma->vm_start, (long) vma->vm_end,
287 +               (long) vma->vm_pgoff);
288 +
289 +       if (offset + length > mm_vc_mem_size) {
290 +               pr_err("%s: length %ld is too big\n", __func__, length);
291 +               return -EINVAL;
292 +       }
293 +       // Do not cache the memory map
294 +       vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
295 +
296 +       rc = remap_pfn_range(vma, vma->vm_start,
297 +                            (mm_vc_mem_phys_addr >> PAGE_SHIFT) +
298 +                            vma->vm_pgoff, length, vma->vm_page_prot);
299 +       if (rc != 0) {
300 +               pr_err("%s: remap_pfn_range failed (rc=%d)\n", __func__, rc);
301 +       }
302 +
303 +       return rc;
304 +}
305 +
306 +/****************************************************************************
307 +*
308 +*   File Operations for the driver.
309 +*
310 +***************************************************************************/
311 +
312 +static const struct file_operations vc_mem_fops = {
313 +       .owner = THIS_MODULE,
314 +       .open = vc_mem_open,
315 +       .release = vc_mem_release,
316 +       .unlocked_ioctl = vc_mem_ioctl,
317 +       .mmap = vc_mem_mmap,
318 +};
319 +
320 +#ifdef CONFIG_DEBUG_FS
321 +static void vc_mem_debugfs_deinit(void)
322 +{
323 +       debugfs_remove_recursive(vc_mem_debugfs_entry);
324 +       vc_mem_debugfs_entry = NULL;
325 +}
326 +
327 +
328 +static int vc_mem_debugfs_init(
329 +       struct device *dev)
330 +{
331 +       vc_mem_debugfs_entry = debugfs_create_dir(DRIVER_NAME, NULL);
332 +       if (!vc_mem_debugfs_entry) {
333 +               dev_warn(dev, "could not create debugfs entry\n");
334 +               return -EFAULT;
335 +       }
336 +
337 +       if (!debugfs_create_x32("vc_mem_phys_addr",
338 +                               0444,
339 +                               vc_mem_debugfs_entry,
340 +                               (u32 *)&mm_vc_mem_phys_addr)) {
341 +               dev_warn(dev, "%s:could not create vc_mem_phys entry\n",
342 +                       __func__);
343 +               goto fail;
344 +       }
345 +
346 +       if (!debugfs_create_x32("vc_mem_size",
347 +                               0444,
348 +                               vc_mem_debugfs_entry,
349 +                               (u32 *)&mm_vc_mem_size)) {
350 +               dev_warn(dev, "%s:could not create vc_mem_size entry\n",
351 +                       __func__);
352 +               goto fail;
353 +       }
354 +
355 +       if (!debugfs_create_x32("vc_mem_base",
356 +                               0444,
357 +                               vc_mem_debugfs_entry,
358 +                               (u32 *)&mm_vc_mem_base)) {
359 +               dev_warn(dev, "%s:could not create vc_mem_base entry\n",
360 +                        __func__);
361 +               goto fail;
362 +       }
363 +
364 +       return 0;
365 +
366 +fail:
367 +       vc_mem_debugfs_deinit();
368 +       return -EFAULT;
369 +}
370 +
371 +#endif /* CONFIG_DEBUG_FS */
372 +
373 +
374 +/****************************************************************************
375 +*
376 +*   vc_mem_init
377 +*
378 +***************************************************************************/
379 +
380 +static int __init
381 +vc_mem_init(void)
382 +{
383 +       int rc = -EFAULT;
384 +       struct device *dev;
385 +
386 +       pr_debug("%s: called\n", __func__);
387 +
388 +       mm_vc_mem_phys_addr = phys_addr;
389 +       mm_vc_mem_size = mem_size;
390 +       mm_vc_mem_base = mem_base;
391 +
392 +       vc_mem_get_size();
393 +
394 +       pr_info("vc-mem: phys_addr:0x%08lx mem_base=0x%08x mem_size:0x%08x(%u MiB)\n",
395 +               mm_vc_mem_phys_addr, mm_vc_mem_base, mm_vc_mem_size, mm_vc_mem_size / (1024 * 1024));
396 +
397 +       if ((rc = alloc_chrdev_region(&vc_mem_devnum, 0, 1, DRIVER_NAME)) < 0) {
398 +               pr_err("%s: alloc_chrdev_region failed (rc=%d)\n",
399 +                      __func__, rc);
400 +               goto out_err;
401 +       }
402 +
403 +       cdev_init(&vc_mem_cdev, &vc_mem_fops);
404 +       if ((rc = cdev_add(&vc_mem_cdev, vc_mem_devnum, 1)) != 0) {
405 +               pr_err("%s: cdev_add failed (rc=%d)\n", __func__, rc);
406 +               goto out_unregister;
407 +       }
408 +
409 +       vc_mem_class = class_create(THIS_MODULE, DRIVER_NAME);
410 +       if (IS_ERR(vc_mem_class)) {
411 +               rc = PTR_ERR(vc_mem_class);
412 +               pr_err("%s: class_create failed (rc=%d)\n", __func__, rc);
413 +               goto out_cdev_del;
414 +       }
415 +
416 +       dev = device_create(vc_mem_class, NULL, vc_mem_devnum, NULL,
417 +                           DRIVER_NAME);
418 +       if (IS_ERR(dev)) {
419 +               rc = PTR_ERR(dev);
420 +               pr_err("%s: device_create failed (rc=%d)\n", __func__, rc);
421 +               goto out_class_destroy;
422 +       }
423 +
424 +#ifdef CONFIG_DEBUG_FS
425 +       /* don't fail if the debug entries cannot be created */
426 +       vc_mem_debugfs_init(dev);
427 +#endif
428 +
429 +       vc_mem_inited = 1;
430 +       return 0;
431 +
432 +       device_destroy(vc_mem_class, vc_mem_devnum);
433 +
434 +      out_class_destroy:
435 +       class_destroy(vc_mem_class);
436 +       vc_mem_class = NULL;
437 +
438 +      out_cdev_del:
439 +       cdev_del(&vc_mem_cdev);
440 +
441 +      out_unregister:
442 +       unregister_chrdev_region(vc_mem_devnum, 1);
443 +
444 +      out_err:
445 +       return -1;
446 +}
447 +
448 +/****************************************************************************
449 +*
450 +*   vc_mem_exit
451 +*
452 +***************************************************************************/
453 +
454 +static void __exit
455 +vc_mem_exit(void)
456 +{
457 +       pr_debug("%s: called\n", __func__);
458 +
459 +       if (vc_mem_inited) {
460 +#if CONFIG_DEBUG_FS
461 +               vc_mem_debugfs_deinit();
462 +#endif
463 +               device_destroy(vc_mem_class, vc_mem_devnum);
464 +               class_destroy(vc_mem_class);
465 +               cdev_del(&vc_mem_cdev);
466 +               unregister_chrdev_region(vc_mem_devnum, 1);
467 +       }
468 +}
469 +
470 +module_init(vc_mem_init);
471 +module_exit(vc_mem_exit);
472 +MODULE_LICENSE("GPL");
473 +MODULE_AUTHOR("Broadcom Corporation");
474 +
475 +module_param(phys_addr, uint, 0644);
476 +module_param(mem_size, uint, 0644);
477 +module_param(mem_base, uint, 0644);
478 --- /dev/null
479 +++ b/include/linux/broadcom/vc_mem.h
480 @@ -0,0 +1,35 @@
481 +/*****************************************************************************
482 +* Copyright 2010 - 2011 Broadcom Corporation.  All rights reserved.
483 +*
484 +* Unless you and Broadcom execute a separate written software license
485 +* agreement governing use of this software, this software is licensed to you
486 +* under the terms of the GNU General Public License version 2, available at
487 +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
488 +*
489 +* Notwithstanding the above, under no circumstances may you combine this
490 +* software in any way with any other Broadcom software provided under a
491 +* license other than the GPL, without Broadcom's express prior written
492 +* consent.
493 +*****************************************************************************/
494 +
495 +#ifndef _VC_MEM_H
496 +#define _VC_MEM_H
497 +
498 +#include <linux/ioctl.h>
499 +
500 +#define VC_MEM_IOC_MAGIC  'v'
501 +
502 +#define VC_MEM_IOC_MEM_PHYS_ADDR    _IOR( VC_MEM_IOC_MAGIC, 0, unsigned long )
503 +#define VC_MEM_IOC_MEM_SIZE         _IOR( VC_MEM_IOC_MAGIC, 1, unsigned int )
504 +#define VC_MEM_IOC_MEM_BASE         _IOR( VC_MEM_IOC_MAGIC, 2, unsigned int )
505 +#define VC_MEM_IOC_MEM_LOAD         _IOR( VC_MEM_IOC_MAGIC, 3, unsigned int )
506 +
507 +#if defined( __KERNEL__ )
508 +#define VC_MEM_TO_ARM_ADDR_MASK 0x3FFFFFFF
509 +
510 +extern unsigned long mm_vc_mem_phys_addr;
511 +extern unsigned int  mm_vc_mem_size;
512 +extern int vc_mem_get_current_size( void );
513 +#endif
514 +
515 +#endif  /* _VC_MEM_H */