123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169 |
- 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,
-
|