From b40aeaad64f51e1cd24c07257eea69a1cd0accea Mon Sep 17 00:00:00 2001 From: Rabit Date: Wed, 4 Jul 2018 23:16:28 -0700 Subject: [PATCH] ASUS Tinkerboard: Ported /dev/gpiomem from default to next kernel --- config/kernel/linux-rockchip-next.config | 5 +- .../rockchip-next/260_DTS_gpiomem_node.patch | 17 + .../rockchip-next/261_gpiomem_driver.patch | 360 ++++++++++++++++++ 3 files changed, 381 insertions(+), 1 deletion(-) create mode 100644 patch/kernel/rockchip-next/260_DTS_gpiomem_node.patch create mode 100644 patch/kernel/rockchip-next/261_gpiomem_driver.patch diff --git a/config/kernel/linux-rockchip-next.config b/config/kernel/linux-rockchip-next.config index fb5dbae9c47a..00e3608fc5a2 100644 --- a/config/kernel/linux-rockchip-next.config +++ b/config/kernel/linux-rockchip-next.config @@ -1,6 +1,6 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/arm 4.14.52 Kernel Configuration +# Linux/arm 4.14.53 Kernel Configuration # CONFIG_ARM=y CONFIG_ARM_HAS_SG_CHAIN=y @@ -842,6 +842,7 @@ CONFIG_NF_LOG_COMMON=m CONFIG_NF_LOG_NETDEV=m CONFIG_NF_CONNTRACK_MARK=y CONFIG_NF_CONNTRACK_SECMARK=y +# CONFIG_NF_CONNTRACK_ZONES is not set CONFIG_NF_CONNTRACK_PROCFS=y CONFIG_NF_CONNTRACK_EVENTS=y CONFIG_NF_CONNTRACK_TIMEOUT=y @@ -2223,6 +2224,8 @@ CONFIG_UNIX98_PTYS=y # CONFIG_SERIAL_NONSTANDARD is not set # CONFIG_N_GSM is not set # CONFIG_TRACE_SINK is not set +CONFIG_RK_CHAR_DRIVERS=y +CONFIG_RK3288_DEVGPIOMEM=y CONFIG_DEVMEM=y # CONFIG_DEVKMEM is not set diff --git a/patch/kernel/rockchip-next/260_DTS_gpiomem_node.patch b/patch/kernel/rockchip-next/260_DTS_gpiomem_node.patch new file mode 100644 index 000000000000..fdaa60b3d44b --- /dev/null +++ b/patch/kernel/rockchip-next/260_DTS_gpiomem_node.patch @@ -0,0 +1,17 @@ +diff --git a/arch/arm/boot/dts/rk3288-tinker.dts b/arch/arm/boot/dts/rk3288-tinker.dts +index 925b277..33b198e 100644 +--- a/arch/arm/boot/dts/rk3288-tinker.dts ++++ b/arch/arm/boot/dts/rk3288-tinker.dts +@@ -100,6 +100,12 @@ + }; + }; + ++ rk3288-gpiomem { ++ compatible = "rockchip,rk3288-gpiomem"; ++ reg = <0x0 0xff750000 0x0 0x1000>; ++ status = "okay"; ++ }; ++ + sound { + compatible = "simple-audio-card"; + simple-audio-card,format = "i2s"; diff --git a/patch/kernel/rockchip-next/261_gpiomem_driver.patch b/patch/kernel/rockchip-next/261_gpiomem_driver.patch new file mode 100644 index 000000000000..a132834ed994 --- /dev/null +++ b/patch/kernel/rockchip-next/261_gpiomem_driver.patch @@ -0,0 +1,360 @@ +diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig +index c28dca0..d9df49d 100644 +--- a/drivers/char/Kconfig ++++ b/drivers/char/Kconfig +@@ -6,6 +6,7 @@ + menu "Character devices" + + source "drivers/tty/Kconfig" ++source "drivers/char/rockchip/Kconfig" + + config DEVMEM + bool "/dev/mem virtual device support" +diff --git a/drivers/char/Makefile b/drivers/char/Makefile +index 7dc3abe..5d43b1d 100644 +--- a/drivers/char/Makefile ++++ b/drivers/char/Makefile +@@ -60,3 +60,5 @@ js-rtc-y = rtc.o + obj-$(CONFIG_TILE_SROM) += tile-srom.o + obj-$(CONFIG_XILLYBUS) += xillybus/ + obj-$(CONFIG_POWERNV_OP_PANEL) += powernv-op-panel.o ++ ++obj-$(CONFIG_RK_CHAR_DRIVERS) += rockchip/ +diff --git a/drivers/char/rockchip/Kconfig b/drivers/char/rockchip/Kconfig +new file mode 100644 +index 0000000..867d51e +--- /dev/null ++++ b/drivers/char/rockchip/Kconfig +@@ -0,0 +1,16 @@ ++# ++# Broadcom char driver config ++# ++ ++menuconfig RK_CHAR_DRIVERS ++ bool "Rockchip Char Drivers" ++ help ++ Rockchip's char drivers ++ ++config RK3288_DEVGPIOMEM ++ tristate "/dev/gpiomem rootless GPIO access via mmap() on the RK3288" ++ default y ++ help ++ Provides users with root-free access to the GPIO registers ++ on the 3288. Calling mmap(/dev/gpiomem) will map the GPIO ++ register page to the user's pointer. +diff --git a/drivers/char/rockchip/Makefile b/drivers/char/rockchip/Makefile +new file mode 100644 +index 0000000..e7df7f2 +--- /dev/null ++++ b/drivers/char/rockchip/Makefile +@@ -0,0 +1 @@ ++obj-$(CONFIG_RK3288_DEVGPIOMEM)+= rk3288-gpiomem.o +diff --git a/drivers/char/rockchip/rk3288-gpiomem.c b/drivers/char/rockchip/rk3288-gpiomem.c +new file mode 100644 +index 0000000..c289041 +--- /dev/null ++++ b/drivers/char/rockchip/rk3288-gpiomem.c +@@ -0,0 +1,303 @@ ++/** ++ * GPIO memory device driver ++ * ++ * Creates a chardev /dev/gpiomem which will provide user access to ++ * the rk3288's GPIO registers when it is mmap()'d. ++ * No longer need root for user GPIO access, but without relaxing permissions ++ * on /dev/mem. ++ * ++ * Written by Luke Wren ++ * Copyright (c) 2015, Raspberry Pi (Trading) Ltd. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions, and the following disclaimer, ++ * without modification. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. The names of the above-listed copyright holders may not be used ++ * to endorse or promote products derived from this software without ++ * specific prior written permission. ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") version 2, as published by the Free ++ * Software Foundation. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS ++ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, ++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR ++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR ++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, ++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, ++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR ++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define DEVICE_NAME "rk3288-gpiomem" ++#define DRIVER_NAME "gpiomem-rk3288" ++#define DEVICE_MINOR 0 ++ ++struct rk3288_gpiomem_instance { ++ unsigned long gpio_regs_phys; ++ struct device *dev; ++}; ++ ++static struct cdev rk3288_gpiomem_cdev; ++static dev_t rk3288_gpiomem_devid; ++static struct class *rk3288_gpiomem_class; ++static struct device *rk3288_gpiomem_dev; ++static struct rk3288_gpiomem_instance *inst; ++ ++ ++/**************************************************************************** ++* ++* GPIO mem chardev file ops ++* ++***************************************************************************/ ++ ++static int rk3288_gpiomem_open(struct inode *inode, struct file *file) ++{ ++ int dev = iminor(inode); ++ int ret = 0; ++ ++ if (dev != DEVICE_MINOR) { ++ dev_err(inst->dev, "Unknown minor device: %d", dev); ++ ret = -ENXIO; ++ } ++ return ret; ++} ++ ++static int rk3288_gpiomem_release(struct inode *inode, struct file *file) ++{ ++ int dev = iminor(inode); ++ int ret = 0; ++ ++ if (dev != DEVICE_MINOR) { ++ dev_err(inst->dev, "Unknown minor device %d", dev); ++ ret = -ENXIO; ++ } ++ return ret; ++} ++ ++static const struct vm_operations_struct rk3288_gpiomem_vm_ops = { ++#ifdef CONFIG_HAVE_IOREMAP_PROT ++ .access = generic_access_phys ++#endif ++}; ++static int address_is_allowed(unsigned long pfn, unsigned long size) ++{ ++ unsigned long address = pfn << PAGE_SHIFT; ++ ++ dev_info(inst->dev, "address_is_allowed.pfn: 0x%08lx", address); ++ ++ switch(address) { ++ ++ case 0xff750000: ++ case 0xff760000: ++ case 0xff780000: ++ case 0xff790000: ++ case 0xff7a0000: ++ case 0xff7b0000: ++ case 0xff7c0000: ++ case 0xff7d0000: ++ case 0xff7e0000: ++ case 0xff7f0000: ++ case 0xff7f2000: ++ case 0xff770000: ++ case 0xff730000: ++ case 0xff680000: ++ dev_info(inst->dev, "address_is_allowed.return 1"); ++ return 1; ++ break; ++ default : ++ dev_info(inst->dev, "address_is_allowed.return 0"); ++ return 0; ++ } ++} ++ ++static int rk3288_gpiomem_mmap(struct file *file, struct vm_area_struct *vma) ++{ ++ ++ size_t size; ++ ++ size = vma->vm_end - vma->vm_start; ++ ++ ++ if (!address_is_allowed(vma->vm_pgoff, size)) ++ return -EPERM; ++ ++ vma->vm_page_prot = phys_mem_access_prot(file, vma->vm_pgoff, ++ size, ++ vma->vm_page_prot); ++ ++ vma->vm_ops = &rk3288_gpiomem_vm_ops; ++ ++ /* Remap-pfn-range will mark the range VM_IO */ ++ if (remap_pfn_range(vma, ++ vma->vm_start, ++ vma->vm_pgoff, ++ size, ++ vma->vm_page_prot)) { ++ return -EAGAIN; ++ } ++ ++ return 0; ++} ++ ++static const struct file_operations ++rk3288_gpiomem_fops = { ++ .owner = THIS_MODULE, ++ .open = rk3288_gpiomem_open, ++ .release = rk3288_gpiomem_release, ++ .mmap = rk3288_gpiomem_mmap, ++}; ++ ++static int rk3288_gpiomem_dev_uevent(struct device *dev, struct kobj_uevent_env *env) ++{ ++ add_uevent_var(env, "DEVMODE=%#o", 0666); ++ return 0; ++} ++ ++ /**************************************************************************** ++* ++* Probe and remove functions ++* ++***************************************************************************/ ++ ++ ++static int rk3288_gpiomem_probe(struct platform_device *pdev) ++{ ++ int err; ++ void *ptr_err; ++ struct device *dev = &pdev->dev; ++ struct resource *ioresource; ++ ++ /* Allocate buffers and instance data */ ++ ++ inst = kzalloc(sizeof(struct rk3288_gpiomem_instance), GFP_KERNEL); ++ ++ if (!inst) { ++ err = -ENOMEM; ++ goto failed_inst_alloc; ++ } ++ ++ inst->dev = dev; ++ ++ ioresource = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (ioresource) { ++ inst->gpio_regs_phys = ioresource->start; ++ } else { ++ dev_err(inst->dev, "failed to get IO resource"); ++ err = -ENOENT; ++ goto failed_get_resource; ++ } ++ ++ /* Create character device entries */ ++ ++ err = alloc_chrdev_region(&rk3288_gpiomem_devid, ++ DEVICE_MINOR, 1, DEVICE_NAME); ++ if (err != 0) { ++ dev_err(inst->dev, "unable to allocate device number"); ++ goto failed_alloc_chrdev; ++ } ++ cdev_init(&rk3288_gpiomem_cdev, &rk3288_gpiomem_fops); ++ rk3288_gpiomem_cdev.owner = THIS_MODULE; ++ err = cdev_add(&rk3288_gpiomem_cdev, rk3288_gpiomem_devid, 1); ++ if (err != 0) { ++ dev_err(inst->dev, "unable to register device"); ++ goto failed_cdev_add; ++ } ++ ++ /* Create sysfs entries */ ++ ++ rk3288_gpiomem_class = class_create(THIS_MODULE, DEVICE_NAME); ++ ptr_err = rk3288_gpiomem_class; ++ if (IS_ERR(ptr_err)) ++ goto failed_class_create; ++ rk3288_gpiomem_class->dev_uevent = rk3288_gpiomem_dev_uevent; ++ rk3288_gpiomem_dev = device_create(rk3288_gpiomem_class, NULL, ++ rk3288_gpiomem_devid, NULL, ++ "gpiomem"); ++ ptr_err = rk3288_gpiomem_dev; ++ if (IS_ERR(ptr_err)) ++ goto failed_device_create; ++ ++ dev_info(inst->dev, "Initialised: Registers at 0x%08lx", ++ inst->gpio_regs_phys); ++ ++ return 0; ++ ++failed_device_create: ++ class_destroy(rk3288_gpiomem_class); ++failed_class_create: ++ cdev_del(&rk3288_gpiomem_cdev); ++ err = PTR_ERR(ptr_err); ++failed_cdev_add: ++ unregister_chrdev_region(rk3288_gpiomem_devid, 1); ++failed_alloc_chrdev: ++failed_get_resource: ++ kfree(inst); ++failed_inst_alloc: ++ dev_err(inst->dev, "could not load rk3288_gpiomem"); ++ return err; ++} ++ ++static int rk3288_gpiomem_remove(struct platform_device *pdev) ++{ ++ struct device *dev = inst->dev; ++ ++ kfree(inst); ++ device_destroy(rk3288_gpiomem_class, rk3288_gpiomem_devid); ++ class_destroy(rk3288_gpiomem_class); ++ cdev_del(&rk3288_gpiomem_cdev); ++ unregister_chrdev_region(rk3288_gpiomem_devid, 1); ++ ++ dev_info(dev, "GPIO mem driver removed - OK"); ++ return 0; ++} ++ ++ /**************************************************************************** ++* ++* Register the driver with device tree ++* ++***************************************************************************/ ++ ++static const struct of_device_id rk3288_gpiomem_of_match[] = { ++ {.compatible = "rockchip,rk3288-gpiomem",}, ++ { /* sentinel */ }, ++}; ++ ++MODULE_DEVICE_TABLE(of, rk3288_gpiomem_of_match); ++ ++static struct platform_driver rk3288_gpiomem_driver = { ++ .probe = rk3288_gpiomem_probe, ++ .remove = rk3288_gpiomem_remove, ++ .driver = { ++ .name = DRIVER_NAME, ++ .owner = THIS_MODULE, ++ .of_match_table = rk3288_gpiomem_of_match, ++ }, ++}; ++ ++module_platform_driver(rk3288_gpiomem_driver); ++ ++MODULE_ALIAS("platform:gpiomem-rk3288"); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("gpiomem driver for accessing GPIO from userspace"); ++MODULE_AUTHOR("Luke Wren ");