aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/brcm2708/patches-4.1/0013-vc_mem-Add-vc_mem-driver.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/brcm2708/patches-4.1/0013-vc_mem-Add-vc_mem-driver.patch')
-rw-r--r--target/linux/brcm2708/patches-4.1/0013-vc_mem-Add-vc_mem-driver.patch992
1 files changed, 992 insertions, 0 deletions
diff --git a/target/linux/brcm2708/patches-4.1/0013-vc_mem-Add-vc_mem-driver.patch b/target/linux/brcm2708/patches-4.1/0013-vc_mem-Add-vc_mem-driver.patch
new file mode 100644
index 0000000..7c19cf9
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.1/0013-vc_mem-Add-vc_mem-driver.patch
@@ -0,0 +1,992 @@
+From c281e92ad16639d2b5bcce1302f78372f29b8cc0 Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Wed, 17 Jun 2015 16:07:06 +0100
+Subject: [PATCH 013/203] vc_mem: Add vc_mem driver
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: popcornmix <popcornmix@gmail.com>
+
+BCM270x: Move vc_mem
+
+Make the vc_mem module available for ARCH_BCM2835 by moving it.
+
+Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
+---
+ arch/arm/mach-bcm2709/include/mach/vc_mem.h | 35 ---
+ arch/arm/mach-bcm2709/vc_mem.c | 431 ----------------------------
+ drivers/char/broadcom/Kconfig | 12 +-
+ drivers/char/broadcom/Makefile | 1 +
+ drivers/char/broadcom/vc_mem.c | 423 +++++++++++++++++++++++++++
+ include/linux/broadcom/vc_mem.h | 35 +++
+ 6 files changed, 470 insertions(+), 467 deletions(-)
+ delete mode 100644 arch/arm/mach-bcm2709/include/mach/vc_mem.h
+ delete mode 100644 arch/arm/mach-bcm2709/vc_mem.c
+ create mode 100644 drivers/char/broadcom/vc_mem.c
+ create mode 100644 include/linux/broadcom/vc_mem.h
+
+--- a/arch/arm/mach-bcm2709/include/mach/vc_mem.h
++++ /dev/null
+@@ -1,35 +0,0 @@
+-/*****************************************************************************
+-* Copyright 2010 - 2011 Broadcom Corporation. All rights reserved.
+-*
+-* Unless you and Broadcom execute a separate written software license
+-* agreement governing use of this software, this software is licensed to you
+-* under the terms of the GNU General Public License version 2, available at
+-* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
+-*
+-* Notwithstanding the above, under no circumstances may you combine this
+-* software in any way with any other Broadcom software provided under a
+-* license other than the GPL, without Broadcom's express prior written
+-* consent.
+-*****************************************************************************/
+-
+-#if !defined( VC_MEM_H )
+-#define VC_MEM_H
+-
+-#include <linux/ioctl.h>
+-
+-#define VC_MEM_IOC_MAGIC 'v'
+-
+-#define VC_MEM_IOC_MEM_PHYS_ADDR _IOR( VC_MEM_IOC_MAGIC, 0, unsigned long )
+-#define VC_MEM_IOC_MEM_SIZE _IOR( VC_MEM_IOC_MAGIC, 1, unsigned int )
+-#define VC_MEM_IOC_MEM_BASE _IOR( VC_MEM_IOC_MAGIC, 2, unsigned int )
+-#define VC_MEM_IOC_MEM_LOAD _IOR( VC_MEM_IOC_MAGIC, 3, unsigned int )
+-
+-#if defined( __KERNEL__ )
+-#define VC_MEM_TO_ARM_ADDR_MASK 0x3FFFFFFF
+-
+-extern unsigned long mm_vc_mem_phys_addr;
+-extern unsigned int mm_vc_mem_size;
+-extern int vc_mem_get_current_size( void );
+-#endif
+-
+-#endif /* VC_MEM_H */
+--- a/arch/arm/mach-bcm2709/vc_mem.c
++++ /dev/null
+@@ -1,431 +0,0 @@
+-/*****************************************************************************
+-* Copyright 2010 - 2011 Broadcom Corporation. All rights reserved.
+-*
+-* Unless you and Broadcom execute a separate written software license
+-* agreement governing use of this software, this software is licensed to you
+-* under the terms of the GNU General Public License version 2, available at
+-* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
+-*
+-* Notwithstanding the above, under no circumstances may you combine this
+-* software in any way with any other Broadcom software provided under a
+-* license other than the GPL, without Broadcom's express prior written
+-* consent.
+-*****************************************************************************/
+-
+-#include <linux/kernel.h>
+-#include <linux/module.h>
+-#include <linux/fs.h>
+-#include <linux/device.h>
+-#include <linux/cdev.h>
+-#include <linux/mm.h>
+-#include <linux/slab.h>
+-#include <linux/debugfs.h>
+-#include <asm/uaccess.h>
+-#include <linux/dma-mapping.h>
+-#include <linux/platform_data/mailbox-bcm2708.h>
+-
+-#ifdef CONFIG_ARCH_KONA
+-#include <chal/chal_ipc.h>
+-#elif defined(CONFIG_ARCH_BCM2708) || defined(CONFIG_ARCH_BCM2709)
+-#else
+-#include <csp/chal_ipc.h>
+-#endif
+-
+-#include "mach/vc_mem.h"
+-
+-#define DRIVER_NAME "vc-mem"
+-
+-// Device (/dev) related variables
+-static dev_t vc_mem_devnum = 0;
+-static struct class *vc_mem_class = NULL;
+-static struct cdev vc_mem_cdev;
+-static int vc_mem_inited = 0;
+-
+-#ifdef CONFIG_DEBUG_FS
+-static struct dentry *vc_mem_debugfs_entry;
+-#endif
+-
+-/*
+- * Videocore memory addresses and size
+- *
+- * Drivers that wish to know the videocore memory addresses and sizes should
+- * use these variables instead of the MM_IO_BASE and MM_ADDR_IO defines in
+- * headers. This allows the other drivers to not be tied down to a a certain
+- * address/size at compile time.
+- *
+- * In the future, the goal is to have the videocore memory virtual address and
+- * size be calculated at boot time rather than at compile time. The decision of
+- * where the videocore memory resides and its size would be in the hands of the
+- * bootloader (and/or kernel). When that happens, the values of these variables
+- * would be calculated and assigned in the init function.
+- */
+-// in the 2835 VC in mapped above ARM, but ARM has full access to VC space
+-unsigned long mm_vc_mem_phys_addr = 0x00000000;
+-unsigned int mm_vc_mem_size = 0;
+-unsigned int mm_vc_mem_base = 0;
+-
+-EXPORT_SYMBOL(mm_vc_mem_phys_addr);
+-EXPORT_SYMBOL(mm_vc_mem_size);
+-EXPORT_SYMBOL(mm_vc_mem_base);
+-
+-static uint phys_addr = 0;
+-static uint mem_size = 0;
+-static uint mem_base = 0;
+-
+-
+-/****************************************************************************
+-*
+-* vc_mem_open
+-*
+-***************************************************************************/
+-
+-static int
+-vc_mem_open(struct inode *inode, struct file *file)
+-{
+- (void) inode;
+- (void) file;
+-
+- pr_debug("%s: called file = 0x%p\n", __func__, file);
+-
+- return 0;
+-}
+-
+-/****************************************************************************
+-*
+-* vc_mem_release
+-*
+-***************************************************************************/
+-
+-static int
+-vc_mem_release(struct inode *inode, struct file *file)
+-{
+- (void) inode;
+- (void) file;
+-
+- pr_debug("%s: called file = 0x%p\n", __func__, file);
+-
+- return 0;
+-}
+-
+-/****************************************************************************
+-*
+-* vc_mem_get_size
+-*
+-***************************************************************************/
+-
+-static void
+-vc_mem_get_size(void)
+-{
+-}
+-
+-/****************************************************************************
+-*
+-* vc_mem_get_base
+-*
+-***************************************************************************/
+-
+-static void
+-vc_mem_get_base(void)
+-{
+-}
+-
+-/****************************************************************************
+-*
+-* vc_mem_get_current_size
+-*
+-***************************************************************************/
+-
+-int
+-vc_mem_get_current_size(void)
+-{
+- return mm_vc_mem_size;
+-}
+-
+-EXPORT_SYMBOL_GPL(vc_mem_get_current_size);
+-
+-/****************************************************************************
+-*
+-* vc_mem_ioctl
+-*
+-***************************************************************************/
+-
+-static long
+-vc_mem_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+-{
+- int rc = 0;
+-
+- (void) cmd;
+- (void) arg;
+-
+- pr_debug("%s: called file = 0x%p\n", __func__, file);
+-
+- switch (cmd) {
+- case VC_MEM_IOC_MEM_PHYS_ADDR:
+- {
+- pr_debug("%s: VC_MEM_IOC_MEM_PHYS_ADDR=0x%p\n",
+- __func__, (void *) mm_vc_mem_phys_addr);
+-
+- if (copy_to_user((void *) arg, &mm_vc_mem_phys_addr,
+- sizeof (mm_vc_mem_phys_addr)) != 0) {
+- rc = -EFAULT;
+- }
+- break;
+- }
+- case VC_MEM_IOC_MEM_SIZE:
+- {
+- // Get the videocore memory size first
+- vc_mem_get_size();
+-
+- pr_debug("%s: VC_MEM_IOC_MEM_SIZE=%u\n", __func__,
+- mm_vc_mem_size);
+-
+- if (copy_to_user((void *) arg, &mm_vc_mem_size,
+- sizeof (mm_vc_mem_size)) != 0) {
+- rc = -EFAULT;
+- }
+- break;
+- }
+- case VC_MEM_IOC_MEM_BASE:
+- {
+- // Get the videocore memory base
+- vc_mem_get_base();
+-
+- pr_debug("%s: VC_MEM_IOC_MEM_BASE=%u\n", __func__,
+- mm_vc_mem_base);
+-
+- if (copy_to_user((void *) arg, &mm_vc_mem_base,
+- sizeof (mm_vc_mem_base)) != 0) {
+- rc = -EFAULT;
+- }
+- break;
+- }
+- case VC_MEM_IOC_MEM_LOAD:
+- {
+- // Get the videocore memory base
+- vc_mem_get_base();
+-
+- pr_debug("%s: VC_MEM_IOC_MEM_LOAD=%u\n", __func__,
+- mm_vc_mem_base);
+-
+- if (copy_to_user((void *) arg, &mm_vc_mem_base,
+- sizeof (mm_vc_mem_base)) != 0) {
+- rc = -EFAULT;
+- }
+- break;
+- }
+- default:
+- {
+- return -ENOTTY;
+- }
+- }
+- pr_debug("%s: file = 0x%p returning %d\n", __func__, file, rc);
+-
+- return rc;
+-}
+-
+-/****************************************************************************
+-*
+-* vc_mem_mmap
+-*
+-***************************************************************************/
+-
+-static int
+-vc_mem_mmap(struct file *filp, struct vm_area_struct *vma)
+-{
+- int rc = 0;
+- unsigned long length = vma->vm_end - vma->vm_start;
+- unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+-
+- pr_debug("%s: vm_start = 0x%08lx vm_end = 0x%08lx vm_pgoff = 0x%08lx\n",
+- __func__, (long) vma->vm_start, (long) vma->vm_end,
+- (long) vma->vm_pgoff);
+-
+- if (offset + length > mm_vc_mem_size) {
+- pr_err("%s: length %ld is too big\n", __func__, length);
+- return -EINVAL;
+- }
+- // Do not cache the memory map
+- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+-
+- rc = remap_pfn_range(vma, vma->vm_start,
+- (mm_vc_mem_phys_addr >> PAGE_SHIFT) +
+- vma->vm_pgoff, length, vma->vm_page_prot);
+- if (rc != 0) {
+- pr_err("%s: remap_pfn_range failed (rc=%d)\n", __func__, rc);
+- }
+-
+- return rc;
+-}
+-
+-/****************************************************************************
+-*
+-* File Operations for the driver.
+-*
+-***************************************************************************/
+-
+-static const struct file_operations vc_mem_fops = {
+- .owner = THIS_MODULE,
+- .open = vc_mem_open,
+- .release = vc_mem_release,
+- .unlocked_ioctl = vc_mem_ioctl,
+- .mmap = vc_mem_mmap,
+-};
+-
+-#ifdef CONFIG_DEBUG_FS
+-static void vc_mem_debugfs_deinit(void)
+-{
+- debugfs_remove_recursive(vc_mem_debugfs_entry);
+- vc_mem_debugfs_entry = NULL;
+-}
+-
+-
+-static int vc_mem_debugfs_init(
+- struct device *dev)
+-{
+- vc_mem_debugfs_entry = debugfs_create_dir(DRIVER_NAME, NULL);
+- if (!vc_mem_debugfs_entry) {
+- dev_warn(dev, "could not create debugfs entry\n");
+- return -EFAULT;
+- }
+-
+- if (!debugfs_create_x32("vc_mem_phys_addr",
+- 0444,
+- vc_mem_debugfs_entry,
+- (u32 *)&mm_vc_mem_phys_addr)) {
+- dev_warn(dev, "%s:could not create vc_mem_phys entry\n",
+- __func__);
+- goto fail;
+- }
+-
+- if (!debugfs_create_x32("vc_mem_size",
+- 0444,
+- vc_mem_debugfs_entry,
+- (u32 *)&mm_vc_mem_size)) {
+- dev_warn(dev, "%s:could not create vc_mem_size entry\n",
+- __func__);
+- goto fail;
+- }
+-
+- if (!debugfs_create_x32("vc_mem_base",
+- 0444,
+- vc_mem_debugfs_entry,
+- (u32 *)&mm_vc_mem_base)) {
+- dev_warn(dev, "%s:could not create vc_mem_base entry\n",
+- __func__);
+- goto fail;
+- }
+-
+- return 0;
+-
+-fail:
+- vc_mem_debugfs_deinit();
+- return -EFAULT;
+-}
+-
+-#endif /* CONFIG_DEBUG_FS */
+-
+-
+-/****************************************************************************
+-*
+-* vc_mem_init
+-*
+-***************************************************************************/
+-
+-static int __init
+-vc_mem_init(void)
+-{
+- int rc = -EFAULT;
+- struct device *dev;
+-
+- pr_debug("%s: called\n", __func__);
+-
+- mm_vc_mem_phys_addr = phys_addr;
+- mm_vc_mem_size = mem_size;
+- mm_vc_mem_base = mem_base;
+-
+- vc_mem_get_size();
+-
+- pr_info("vc-mem: phys_addr:0x%08lx mem_base=0x%08x mem_size:0x%08x(%u MiB)\n",
+- mm_vc_mem_phys_addr, mm_vc_mem_base, mm_vc_mem_size, mm_vc_mem_size / (1024 * 1024));
+-
+- if ((rc = alloc_chrdev_region(&vc_mem_devnum, 0, 1, DRIVER_NAME)) < 0) {
+- pr_err("%s: alloc_chrdev_region failed (rc=%d)\n",
+- __func__, rc);
+- goto out_err;
+- }
+-
+- cdev_init(&vc_mem_cdev, &vc_mem_fops);
+- if ((rc = cdev_add(&vc_mem_cdev, vc_mem_devnum, 1)) != 0) {
+- pr_err("%s: cdev_add failed (rc=%d)\n", __func__, rc);
+- goto out_unregister;
+- }
+-
+- vc_mem_class = class_create(THIS_MODULE, DRIVER_NAME);
+- if (IS_ERR(vc_mem_class)) {
+- rc = PTR_ERR(vc_mem_class);
+- pr_err("%s: class_create failed (rc=%d)\n", __func__, rc);
+- goto out_cdev_del;
+- }
+-
+- dev = device_create(vc_mem_class, NULL, vc_mem_devnum, NULL,
+- DRIVER_NAME);
+- if (IS_ERR(dev)) {
+- rc = PTR_ERR(dev);
+- pr_err("%s: device_create failed (rc=%d)\n", __func__, rc);
+- goto out_class_destroy;
+- }
+-
+-#ifdef CONFIG_DEBUG_FS
+- /* don't fail if the debug entries cannot be created */
+- vc_mem_debugfs_init(dev);
+-#endif
+-
+- vc_mem_inited = 1;
+- return 0;
+-
+- device_destroy(vc_mem_class, vc_mem_devnum);
+-
+- out_class_destroy:
+- class_destroy(vc_mem_class);
+- vc_mem_class = NULL;
+-
+- out_cdev_del:
+- cdev_del(&vc_mem_cdev);
+-
+- out_unregister:
+- unregister_chrdev_region(vc_mem_devnum, 1);
+-
+- out_err:
+- return -1;
+-}
+-
+-/****************************************************************************
+-*
+-* vc_mem_exit
+-*
+-***************************************************************************/
+-
+-static void __exit
+-vc_mem_exit(void)
+-{
+- pr_debug("%s: called\n", __func__);
+-
+- if (vc_mem_inited) {
+-#if CONFIG_DEBUG_FS
+- vc_mem_debugfs_deinit();
+-#endif
+- device_destroy(vc_mem_class, vc_mem_devnum);
+- class_destroy(vc_mem_class);
+- cdev_del(&vc_mem_cdev);
+- unregister_chrdev_region(vc_mem_devnum, 1);
+- }
+-}
+-
+-module_init(vc_mem_init);
+-module_exit(vc_mem_exit);
+-MODULE_LICENSE("GPL");
+-MODULE_AUTHOR("Broadcom Corporation");
+-
+-module_param(phys_addr, uint, 0644);
+-module_param(mem_size, uint, 0644);
+-module_param(mem_base, uint, 0644);
+--- a/drivers/char/broadcom/Kconfig
++++ b/drivers/char/broadcom/Kconfig
+@@ -7,9 +7,19 @@ menuconfig BRCM_CHAR_DRIVERS
+ help
+ Broadcom's char drivers
+
++if BRCM_CHAR_DRIVERS
++
+ config BCM_VC_CMA
+ bool "Videocore CMA"
+- depends on CMA && BRCM_CHAR_DRIVERS && BCM2708_VCHIQ
++ depends on CMA && BCM2708_VCHIQ
+ default n
+ help
+ Helper for videocore CMA access.
++
++config BCM2708_VCMEM
++ bool "Videocore Memory"
++ default y
++ help
++ Helper for videocore memory access and total size allocation.
++
++endif
+--- a/drivers/char/broadcom/Makefile
++++ b/drivers/char/broadcom/Makefile
+@@ -1 +1,2 @@
+ obj-$(CONFIG_BCM_VC_CMA) += vc_cma/
++obj-$(CONFIG_BCM2708_VCMEM) += vc_mem.o
+--- /dev/null
++++ b/drivers/char/broadcom/vc_mem.c
+@@ -0,0 +1,423 @@
++/*****************************************************************************
++* Copyright 2010 - 2011 Broadcom Corporation. All rights reserved.
++*
++* Unless you and Broadcom execute a separate written software license
++* agreement governing use of this software, this software is licensed to you
++* under the terms of the GNU General Public License version 2, available at
++* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
++*
++* Notwithstanding the above, under no circumstances may you combine this
++* software in any way with any other Broadcom software provided under a
++* license other than the GPL, without Broadcom's express prior written
++* consent.
++*****************************************************************************/
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/fs.h>
++#include <linux/device.h>
++#include <linux/cdev.h>
++#include <linux/mm.h>
++#include <linux/slab.h>
++#include <linux/debugfs.h>
++#include <asm/uaccess.h>
++#include <linux/dma-mapping.h>
++#include <linux/platform_data/mailbox-bcm2708.h>
++#include <linux/broadcom/vc_mem.h>
++
++#define DRIVER_NAME "vc-mem"
++
++// Device (/dev) related variables
++static dev_t vc_mem_devnum = 0;
++static struct class *vc_mem_class = NULL;
++static struct cdev vc_mem_cdev;
++static int vc_mem_inited = 0;
++
++#ifdef CONFIG_DEBUG_FS
++static struct dentry *vc_mem_debugfs_entry;
++#endif
++
++/*
++ * Videocore memory addresses and size
++ *
++ * Drivers that wish to know the videocore memory addresses and sizes should
++ * use these variables instead of the MM_IO_BASE and MM_ADDR_IO defines in
++ * headers. This allows the other drivers to not be tied down to a a certain
++ * address/size at compile time.
++ *
++ * In the future, the goal is to have the videocore memory virtual address and
++ * size be calculated at boot time rather than at compile time. The decision of
++ * where the videocore memory resides and its size would be in the hands of the
++ * bootloader (and/or kernel). When that happens, the values of these variables
++ * would be calculated and assigned in the init function.
++ */
++// in the 2835 VC in mapped above ARM, but ARM has full access to VC space
++unsigned long mm_vc_mem_phys_addr = 0x00000000;
++unsigned int mm_vc_mem_size = 0;
++unsigned int mm_vc_mem_base = 0;
++
++EXPORT_SYMBOL(mm_vc_mem_phys_addr);
++EXPORT_SYMBOL(mm_vc_mem_size);
++EXPORT_SYMBOL(mm_vc_mem_base);
++
++static uint phys_addr = 0;
++static uint mem_size = 0;
++static uint mem_base = 0;
++
++
++/****************************************************************************
++*
++* vc_mem_open
++*
++***************************************************************************/
++
++static int
++vc_mem_open(struct inode *inode, struct file *file)
++{
++ (void) inode;
++ (void) file;
++
++ pr_debug("%s: called file = 0x%p\n", __func__, file);
++
++ return 0;
++}
++
++/****************************************************************************
++*
++* vc_mem_release
++*
++***************************************************************************/
++
++static int
++vc_mem_release(struct inode *inode, struct file *file)
++{
++ (void) inode;
++ (void) file;
++
++ pr_debug("%s: called file = 0x%p\n", __func__, file);
++
++ return 0;
++}
++
++/****************************************************************************
++*
++* vc_mem_get_size
++*
++***************************************************************************/
++
++static void
++vc_mem_get_size(void)
++{
++}
++
++/****************************************************************************
++*
++* vc_mem_get_base
++*
++***************************************************************************/
++
++static void
++vc_mem_get_base(void)
++{
++}
++
++/****************************************************************************
++*
++* vc_mem_get_current_size
++*
++***************************************************************************/
++
++int
++vc_mem_get_current_size(void)
++{
++ return mm_vc_mem_size;
++}
++
++EXPORT_SYMBOL_GPL(vc_mem_get_current_size);
++
++/****************************************************************************
++*
++* vc_mem_ioctl
++*
++***************************************************************************/
++
++static long
++vc_mem_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
++{
++ int rc = 0;
++
++ (void) cmd;
++ (void) arg;
++
++ pr_debug("%s: called file = 0x%p\n", __func__, file);
++
++ switch (cmd) {
++ case VC_MEM_IOC_MEM_PHYS_ADDR:
++ {
++ pr_debug("%s: VC_MEM_IOC_MEM_PHYS_ADDR=0x%p\n",
++ __func__, (void *) mm_vc_mem_phys_addr);
++
++ if (copy_to_user((void *) arg, &mm_vc_mem_phys_addr,
++ sizeof (mm_vc_mem_phys_addr)) != 0) {
++ rc = -EFAULT;
++ }
++ break;
++ }
++ case VC_MEM_IOC_MEM_SIZE:
++ {
++ // Get the videocore memory size first
++ vc_mem_get_size();
++
++ pr_debug("%s: VC_MEM_IOC_MEM_SIZE=%u\n", __func__,
++ mm_vc_mem_size);
++
++ if (copy_to_user((void *) arg, &mm_vc_mem_size,
++ sizeof (mm_vc_mem_size)) != 0) {
++ rc = -EFAULT;
++ }
++ break;
++ }
++ case VC_MEM_IOC_MEM_BASE:
++ {
++ // Get the videocore memory base
++ vc_mem_get_base();
++
++ pr_debug("%s: VC_MEM_IOC_MEM_BASE=%u\n", __func__,
++ mm_vc_mem_base);
++
++ if (copy_to_user((void *) arg, &mm_vc_mem_base,
++ sizeof (mm_vc_mem_base)) != 0) {
++ rc = -EFAULT;
++ }
++ break;
++ }
++ case VC_MEM_IOC_MEM_LOAD:
++ {
++ // Get the videocore memory base
++ vc_mem_get_base();
++
++ pr_debug("%s: VC_MEM_IOC_MEM_LOAD=%u\n", __func__,
++ mm_vc_mem_base);
++
++ if (copy_to_user((void *) arg, &mm_vc_mem_base,
++ sizeof (mm_vc_mem_base)) != 0) {
++ rc = -EFAULT;
++ }
++ break;
++ }
++ default:
++ {
++ return -ENOTTY;
++ }
++ }
++ pr_debug("%s: file = 0x%p returning %d\n", __func__, file, rc);
++
++ return rc;
++}
++
++/****************************************************************************
++*
++* vc_mem_mmap
++*
++***************************************************************************/
++
++static int
++vc_mem_mmap(struct file *filp, struct vm_area_struct *vma)
++{
++ int rc = 0;
++ unsigned long length = vma->vm_end - vma->vm_start;
++ unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
++
++ pr_debug("%s: vm_start = 0x%08lx vm_end = 0x%08lx vm_pgoff = 0x%08lx\n",
++ __func__, (long) vma->vm_start, (long) vma->vm_end,
++ (long) vma->vm_pgoff);
++
++ if (offset + length > mm_vc_mem_size) {
++ pr_err("%s: length %ld is too big\n", __func__, length);
++ return -EINVAL;
++ }
++ // Do not cache the memory map
++ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
++
++ rc = remap_pfn_range(vma, vma->vm_start,
++ (mm_vc_mem_phys_addr >> PAGE_SHIFT) +
++ vma->vm_pgoff, length, vma->vm_page_prot);
++ if (rc != 0) {
++ pr_err("%s: remap_pfn_range failed (rc=%d)\n", __func__, rc);
++ }
++
++ return rc;
++}
++
++/****************************************************************************
++*
++* File Operations for the driver.
++*
++***************************************************************************/
++
++static const struct file_operations vc_mem_fops = {
++ .owner = THIS_MODULE,
++ .open = vc_mem_open,
++ .release = vc_mem_release,
++ .unlocked_ioctl = vc_mem_ioctl,
++ .mmap = vc_mem_mmap,
++};
++
++#ifdef CONFIG_DEBUG_FS
++static void vc_mem_debugfs_deinit(void)
++{
++ debugfs_remove_recursive(vc_mem_debugfs_entry);
++ vc_mem_debugfs_entry = NULL;
++}
++
++
++static int vc_mem_debugfs_init(
++ struct device *dev)
++{
++ vc_mem_debugfs_entry = debugfs_create_dir(DRIVER_NAME, NULL);
++ if (!vc_mem_debugfs_entry) {
++ dev_warn(dev, "could not create debugfs entry\n");
++ return -EFAULT;
++ }
++
++ if (!debugfs_create_x32("vc_mem_phys_addr",
++ 0444,
++ vc_mem_debugfs_entry,
++ (u32 *)&mm_vc_mem_phys_addr)) {
++ dev_warn(dev, "%s:could not create vc_mem_phys entry\n",
++ __func__);
++ goto fail;
++ }
++
++ if (!debugfs_create_x32("vc_mem_size",
++ 0444,
++ vc_mem_debugfs_entry,
++ (u32 *)&mm_vc_mem_size)) {
++ dev_warn(dev, "%s:could not create vc_mem_size entry\n",
++ __func__);
++ goto fail;
++ }
++
++ if (!debugfs_create_x32("vc_mem_base",
++ 0444,
++ vc_mem_debugfs_entry,
++ (u32 *)&mm_vc_mem_base)) {
++ dev_warn(dev, "%s:could not create vc_mem_base entry\n",
++ __func__);
++ goto fail;
++ }
++
++ return 0;
++
++fail:
++ vc_mem_debugfs_deinit();
++ return -EFAULT;
++}
++
++#endif /* CONFIG_DEBUG_FS */
++
++
++/****************************************************************************
++*
++* vc_mem_init
++*
++***************************************************************************/
++
++static int __init
++vc_mem_init(void)
++{
++ int rc = -EFAULT;
++ struct device *dev;
++
++ pr_debug("%s: called\n", __func__);
++
++ mm_vc_mem_phys_addr = phys_addr;
++ mm_vc_mem_size = mem_size;
++ mm_vc_mem_base = mem_base;
++
++ vc_mem_get_size();
++
++ pr_info("vc-mem: phys_addr:0x%08lx mem_base=0x%08x mem_size:0x%08x(%u MiB)\n",
++ mm_vc_mem_phys_addr, mm_vc_mem_base, mm_vc_mem_size, mm_vc_mem_size / (1024 * 1024));
++
++ if ((rc = alloc_chrdev_region(&vc_mem_devnum, 0, 1, DRIVER_NAME)) < 0) {
++ pr_err("%s: alloc_chrdev_region failed (rc=%d)\n",
++ __func__, rc);
++ goto out_err;
++ }
++
++ cdev_init(&vc_mem_cdev, &vc_mem_fops);
++ if ((rc = cdev_add(&vc_mem_cdev, vc_mem_devnum, 1)) != 0) {
++ pr_err("%s: cdev_add failed (rc=%d)\n", __func__, rc);
++ goto out_unregister;
++ }
++
++ vc_mem_class = class_create(THIS_MODULE, DRIVER_NAME);
++ if (IS_ERR(vc_mem_class)) {
++ rc = PTR_ERR(vc_mem_class);
++ pr_err("%s: class_create failed (rc=%d)\n", __func__, rc);
++ goto out_cdev_del;
++ }
++
++ dev = device_create(vc_mem_class, NULL, vc_mem_devnum, NULL,
++ DRIVER_NAME);
++ if (IS_ERR(dev)) {
++ rc = PTR_ERR(dev);
++ pr_err("%s: device_create failed (rc=%d)\n", __func__, rc);
++ goto out_class_destroy;
++ }
++
++#ifdef CONFIG_DEBUG_FS
++ /* don't fail if the debug entries cannot be created */
++ vc_mem_debugfs_init(dev);
++#endif
++
++ vc_mem_inited = 1;
++ return 0;
++
++ device_destroy(vc_mem_class, vc_mem_devnum);
++
++ out_class_destroy:
++ class_destroy(vc_mem_class);
++ vc_mem_class = NULL;
++
++ out_cdev_del:
++ cdev_del(&vc_mem_cdev);
++
++ out_unregister:
++ unregister_chrdev_region(vc_mem_devnum, 1);
++
++ out_err:
++ return -1;
++}
++
++/****************************************************************************
++*
++* vc_mem_exit
++*
++***************************************************************************/
++
++static void __exit
++vc_mem_exit(void)
++{
++ pr_debug("%s: called\n", __func__);
++
++ if (vc_mem_inited) {
++#if CONFIG_DEBUG_FS
++ vc_mem_debugfs_deinit();
++#endif
++ device_destroy(vc_mem_class, vc_mem_devnum);
++ class_destroy(vc_mem_class);
++ cdev_del(&vc_mem_cdev);
++ unregister_chrdev_region(vc_mem_devnum, 1);
++ }
++}
++
++module_init(vc_mem_init);
++module_exit(vc_mem_exit);
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Broadcom Corporation");
++
++module_param(phys_addr, uint, 0644);
++module_param(mem_size, uint, 0644);
++module_param(mem_base, uint, 0644);
+--- /dev/null
++++ b/include/linux/broadcom/vc_mem.h
+@@ -0,0 +1,35 @@
++/*****************************************************************************
++* Copyright 2010 - 2011 Broadcom Corporation. All rights reserved.
++*
++* Unless you and Broadcom execute a separate written software license
++* agreement governing use of this software, this software is licensed to you
++* under the terms of the GNU General Public License version 2, available at
++* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
++*
++* Notwithstanding the above, under no circumstances may you combine this
++* software in any way with any other Broadcom software provided under a
++* license other than the GPL, without Broadcom's express prior written
++* consent.
++*****************************************************************************/
++
++#ifndef _VC_MEM_H
++#define _VC_MEM_H
++
++#include <linux/ioctl.h>
++
++#define VC_MEM_IOC_MAGIC 'v'
++
++#define VC_MEM_IOC_MEM_PHYS_ADDR _IOR( VC_MEM_IOC_MAGIC, 0, unsigned long )
++#define VC_MEM_IOC_MEM_SIZE _IOR( VC_MEM_IOC_MAGIC, 1, unsigned int )
++#define VC_MEM_IOC_MEM_BASE _IOR( VC_MEM_IOC_MAGIC, 2, unsigned int )
++#define VC_MEM_IOC_MEM_LOAD _IOR( VC_MEM_IOC_MAGIC, 3, unsigned int )
++
++#if defined( __KERNEL__ )
++#define VC_MEM_TO_ARM_ADDR_MASK 0x3FFFFFFF
++
++extern unsigned long mm_vc_mem_phys_addr;
++extern unsigned int mm_vc_mem_size;
++extern int vc_mem_get_current_size( void );
++#endif
++
++#endif /* _VC_MEM_H */