You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
openwrt/target/linux/brcm2708/patches-4.4/0533-brcmvirt_gpio-Create-c...

170 lines
4.7 KiB
Diff

From 07afae52a73991a3ea948aab5d0303a5a9805b41 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Wed, 9 Nov 2016 22:42:39 +0000
Subject: [PATCH] brcmvirt_gpio: Create coherent buffer and push to firmware
---
drivers/gpio/gpio-bcm-virt.c | 88 +++++++++++++++++++++---------
include/soc/bcm2835/raspberrypi-firmware.h | 1 +
2 files changed, 62 insertions(+), 27 deletions(-)
--- a/drivers/gpio/gpio-bcm-virt.c
+++ b/drivers/gpio/gpio-bcm-virt.c
@@ -15,6 +15,7 @@
#include <linux/module.h>
#include <linux/basic_mmio_gpio.h>
#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
#include <soc/bcm2835/raspberrypi-firmware.h>
#define MODULE_NAME "brcmvirt-gpio"
@@ -26,6 +27,7 @@ struct brcmvirt_gpio {
/* two packed 16-bit counts of enabled and disables
Allows host to detect a brief enable that was missed */
u32 enables_disables[NUM_GPIO];
+ dma_addr_t bus_addr;
};
static int brcmvirt_gpio_dir_in(struct gpio_chip *gc, unsigned off)
@@ -76,13 +78,13 @@ static void brcmvirt_gpio_set(struct gpi
static int brcmvirt_gpio_probe(struct platform_device *pdev)
{
+ int err = 0;
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct device_node *fw_node;
struct rpi_firmware *fw;
struct brcmvirt_gpio *ucb;
u32 gpiovirtbuf;
- int err = 0;
fw_node = of_parse_phandle(np, "firmware", 0);
if (!fw_node) {
@@ -94,35 +96,56 @@ static int brcmvirt_gpio_probe(struct pl
if (!fw)
return -EPROBE_DEFER;
- err = rpi_firmware_property(fw, RPI_FIRMWARE_FRAMEBUFFER_GET_GPIOVIRTBUF,
- &gpiovirtbuf, sizeof(gpiovirtbuf));
-
- if (err) {
- dev_err(dev, "Failed to get gpiovirtbuf\n");
- goto err;
- }
-
- if (!gpiovirtbuf) {
- dev_err(dev, "No virtgpio buffer\n");
- err = -ENOENT;
- goto err;
- }
-
ucb = devm_kzalloc(dev, sizeof *ucb, GFP_KERNEL);
if (!ucb) {
err = -EINVAL;
- goto err;
+ goto out;
}
- // mmap the physical memory
- gpiovirtbuf &= ~0xc0000000;
- ucb->ts_base = ioremap(gpiovirtbuf, 4096);
- if (ucb->ts_base == NULL) {
- dev_err(dev, "Failed to map physical address\n");
- err = -ENOENT;
- goto err;
+ ucb->ts_base = dma_zalloc_coherent(NULL, PAGE_SIZE, &ucb->bus_addr, GFP_KERNEL);
+ if (!ucb->ts_base) {
+ pr_err("[%s]: failed to dma_alloc_coherent(%ld)\n",
+ __func__, PAGE_SIZE);
+ err = -ENOMEM;
+ goto out;
}
+ gpiovirtbuf = (u32)ucb->bus_addr;
+ err = rpi_firmware_property(fw, RPI_FIRMWARE_FRAMEBUFFER_SET_GPIOVIRTBUF,
+ &gpiovirtbuf, sizeof(gpiovirtbuf));
+
+ if (err || gpiovirtbuf != 0) {
+ dev_warn(dev, "Failed to set gpiovirtbuf, trying to get err:%x\n", err);
+ dma_free_coherent(NULL, PAGE_SIZE, ucb->ts_base, ucb->bus_addr);
+ ucb->ts_base = 0;
+ ucb->bus_addr = 0;
+ }
+
+ if (!ucb->ts_base) {
+ err = rpi_firmware_property(fw, RPI_FIRMWARE_FRAMEBUFFER_GET_GPIOVIRTBUF,
+ &gpiovirtbuf, sizeof(gpiovirtbuf));
+
+ if (err) {
+ dev_err(dev, "Failed to get gpiovirtbuf\n");
+ goto out;
+ }
+
+ if (!gpiovirtbuf) {
+ dev_err(dev, "No virtgpio buffer\n");
+ err = -ENOENT;
+ goto out;
+ }
+
+ // mmap the physical memory
+ gpiovirtbuf &= ~0xc0000000;
+ ucb->ts_base = ioremap(gpiovirtbuf, 4096);
+ if (ucb->ts_base == NULL) {
+ dev_err(dev, "Failed to map physical address\n");
+ err = -ENOENT;
+ goto out;
+ }
+ ucb->bus_addr = 0;
+ }
ucb->gc.label = MODULE_NAME;
ucb->gc.owner = THIS_MODULE;
ucb->gc.dev = dev;
@@ -138,13 +161,21 @@ static int brcmvirt_gpio_probe(struct pl
err = gpiochip_add(&ucb->gc);
if (err)
- goto err;
+ goto out;
platform_set_drvdata(pdev, ucb);
-err:
+ return 0;
+out:
+ if (ucb->bus_addr) {
+ dma_free_coherent(NULL, PAGE_SIZE, ucb->ts_base, ucb->bus_addr);
+ ucb->bus_addr = 0;
+ ucb->ts_base = NULL;
+ } else if (ucb->ts_base) {
+ iounmap(ucb->ts_base);
+ ucb->ts_base = NULL;
+ }
return err;
-
}
static int brcmvirt_gpio_remove(struct platform_device *pdev)
@@ -153,7 +184,10 @@ static int brcmvirt_gpio_remove(struct p
struct brcmvirt_gpio *ucb = platform_get_drvdata(pdev);
gpiochip_remove(&ucb->gc);
- iounmap(ucb->ts_base);
+ if (ucb->bus_addr)
+ dma_free_coherent(NULL, PAGE_SIZE, ucb->ts_base, ucb->bus_addr);
+ else if (ucb->ts_base)
+ iounmap(ucb->ts_base);
return err;
}
--- a/include/soc/bcm2835/raspberrypi-firmware.h
+++ b/include/soc/bcm2835/raspberrypi-firmware.h
@@ -118,6 +118,7 @@ enum rpi_firmware_property_tag {
RPI_FIRMWARE_FRAMEBUFFER_SET_OVERSCAN = 0x0004800a,
RPI_FIRMWARE_FRAMEBUFFER_SET_PALETTE = 0x0004800b,
RPI_FIRMWARE_FRAMEBUFFER_SET_TOUCHBUF = 0x0004801f,
+ RPI_FIRMWARE_FRAMEBUFFER_SET_GPIOVIRTBUF = 0x00048020,
RPI_FIRMWARE_FRAMEBUFFER_SET_VSYNC = 0x0004800e,
RPI_FIRMWARE_FRAMEBUFFER_SET_BACKLIGHT = 0x0004800f,