Skip to content

Commit c23db27

Browse files
committed
brcmvirt_gpio: Create coherent buffer and push to firmware
1 parent 5a511f3 commit c23db27

File tree

2 files changed

+63
-27
lines changed

2 files changed

+63
-27
lines changed

drivers/gpio/gpio-bcm-virt.c

Lines changed: 62 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <linux/gpio.h>
1515
#include <linux/module.h>
1616
#include <linux/platform_device.h>
17+
#include <linux/dma-mapping.h>
1718
#include <soc/bcm2835/raspberrypi-firmware.h>
1819

1920
#define MODULE_NAME "brcmvirt-gpio"
@@ -25,6 +26,7 @@ struct brcmvirt_gpio {
2526
/* two packed 16-bit counts of enabled and disables
2627
Allows host to detect a brief enable that was missed */
2728
u32 enables_disables[NUM_GPIO];
29+
dma_addr_t bus_addr;
2830
};
2931

3032
static int brcmvirt_gpio_dir_in(struct gpio_chip *gc, unsigned off)
@@ -75,13 +77,13 @@ static void brcmvirt_gpio_set(struct gpio_chip *gc, unsigned off, int val)
7577

7678
static int brcmvirt_gpio_probe(struct platform_device *pdev)
7779
{
80+
int err = 0;
7881
struct device *dev = &pdev->dev;
7982
struct device_node *np = dev->of_node;
8083
struct device_node *fw_node;
8184
struct rpi_firmware *fw;
8285
struct brcmvirt_gpio *ucb;
8386
u32 gpiovirtbuf;
84-
int err = 0;
8587

8688
fw_node = of_parse_phandle(np, "firmware", 0);
8789
if (!fw_node) {
@@ -93,35 +95,56 @@ static int brcmvirt_gpio_probe(struct platform_device *pdev)
9395
if (!fw)
9496
return -EPROBE_DEFER;
9597

96-
err = rpi_firmware_property(fw, RPI_FIRMWARE_FRAMEBUFFER_GET_GPIOVIRTBUF,
97-
&gpiovirtbuf, sizeof(gpiovirtbuf));
98-
99-
if (err) {
100-
dev_err(dev, "Failed to get gpiovirtbuf\n");
101-
goto err;
102-
}
103-
104-
if (!gpiovirtbuf) {
105-
dev_err(dev, "No virtgpio buffer\n");
106-
err = -ENOENT;
107-
goto err;
108-
}
109-
11098
ucb = devm_kzalloc(dev, sizeof *ucb, GFP_KERNEL);
11199
if (!ucb) {
112100
err = -EINVAL;
113-
goto err;
101+
goto out;
114102
}
115103

116-
// mmap the physical memory
117-
gpiovirtbuf &= ~0xc0000000;
118-
ucb->ts_base = ioremap(gpiovirtbuf, 4096);
119-
if (ucb->ts_base == NULL) {
120-
dev_err(dev, "Failed to map physical address\n");
121-
err = -ENOENT;
122-
goto err;
104+
ucb->ts_base = dma_zalloc_coherent(dev, PAGE_SIZE, &ucb->bus_addr, GFP_KERNEL);
105+
if (!ucb->ts_base) {
106+
pr_err("[%s]: failed to dma_alloc_coherent(%ld)\n",
107+
__func__, PAGE_SIZE);
108+
err = -ENOMEM;
109+
goto out;
123110
}
124111

112+
gpiovirtbuf = (u32)ucb->bus_addr;
113+
err = rpi_firmware_property(fw, RPI_FIRMWARE_FRAMEBUFFER_SET_GPIOVIRTBUF,
114+
&gpiovirtbuf, sizeof(gpiovirtbuf));
115+
116+
if (err || gpiovirtbuf != 0) {
117+
dev_warn(dev, "Failed to set gpiovirtbuf, trying to get err:%x\n", err);
118+
dma_free_coherent(dev, PAGE_SIZE, ucb->ts_base, ucb->bus_addr);
119+
ucb->ts_base = 0;
120+
ucb->bus_addr = 0;
121+
}
122+
123+
if (!ucb->ts_base) {
124+
err = rpi_firmware_property(fw, RPI_FIRMWARE_FRAMEBUFFER_GET_GPIOVIRTBUF,
125+
&gpiovirtbuf, sizeof(gpiovirtbuf));
126+
127+
if (err) {
128+
dev_err(dev, "Failed to get gpiovirtbuf\n");
129+
goto out;
130+
}
131+
132+
if (!gpiovirtbuf) {
133+
dev_err(dev, "No virtgpio buffer\n");
134+
err = -ENOENT;
135+
goto out;
136+
}
137+
138+
// mmap the physical memory
139+
gpiovirtbuf &= ~0xc0000000;
140+
ucb->ts_base = ioremap(gpiovirtbuf, 4096);
141+
if (ucb->ts_base == NULL) {
142+
dev_err(dev, "Failed to map physical address\n");
143+
err = -ENOENT;
144+
goto out;
145+
}
146+
ucb->bus_addr = 0;
147+
}
125148
ucb->gc.label = MODULE_NAME;
126149
ucb->gc.owner = THIS_MODULE;
127150
//ucb->gc.dev = dev;
@@ -137,22 +160,34 @@ static int brcmvirt_gpio_probe(struct platform_device *pdev)
137160

138161
err = gpiochip_add(&ucb->gc);
139162
if (err)
140-
goto err;
163+
goto out;
141164

142165
platform_set_drvdata(pdev, ucb);
143166

144-
err:
167+
return 0;
168+
out:
169+
if (ucb->bus_addr) {
170+
dma_free_coherent(dev, PAGE_SIZE, ucb->ts_base, ucb->bus_addr);
171+
ucb->bus_addr = 0;
172+
ucb->ts_base = NULL;
173+
} else if (ucb->ts_base) {
174+
iounmap(ucb->ts_base);
175+
ucb->ts_base = NULL;
176+
}
145177
return err;
146-
147178
}
148179

149180
static int brcmvirt_gpio_remove(struct platform_device *pdev)
150181
{
182+
struct device *dev = &pdev->dev;
151183
int err = 0;
152184
struct brcmvirt_gpio *ucb = platform_get_drvdata(pdev);
153185

154186
gpiochip_remove(&ucb->gc);
155-
iounmap(ucb->ts_base);
187+
if (ucb->bus_addr)
188+
dma_free_coherent(dev, PAGE_SIZE, ucb->ts_base, ucb->bus_addr);
189+
else if (ucb->ts_base)
190+
iounmap(ucb->ts_base);
156191
return err;
157192
}
158193

include/soc/bcm2835/raspberrypi-firmware.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ enum rpi_firmware_property_tag {
116116
RPI_FIRMWARE_FRAMEBUFFER_SET_OVERSCAN = 0x0004800a,
117117
RPI_FIRMWARE_FRAMEBUFFER_SET_PALETTE = 0x0004800b,
118118
RPI_FIRMWARE_FRAMEBUFFER_SET_TOUCHBUF = 0x0004801f,
119+
RPI_FIRMWARE_FRAMEBUFFER_SET_GPIOVIRTBUF = 0x00048020,
119120
RPI_FIRMWARE_FRAMEBUFFER_SET_VSYNC = 0x0004800e,
120121
RPI_FIRMWARE_FRAMEBUFFER_SET_BACKLIGHT = 0x0004800f,
121122

0 commit comments

Comments
 (0)