170 lines
4.7 KiB
Diff
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,
|
||
|
|