fbtft: experimental DMA support

A DMA capable SPI master driver is needed to use DMA.

Tested-by: Derek Campbell
This commit is contained in:
notro 2013-09-10 16:07:16 +00:00
parent 49d03f9634
commit 2c721932aa
3 changed files with 34 additions and 7 deletions

View file

@ -36,6 +36,7 @@
#include <linux/backlight.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>
#include <linux/dma-mapping.h>
#include "fbtft.h"
@ -49,6 +50,10 @@ static unsigned long debug;
module_param(debug, ulong , 0);
MODULE_PARM_DESC(debug, "override device debug level");
static bool dma;
module_param(dma, bool, 0);
MODULE_PARM_DESC(dma, "Use DMA buffer");
void fbtft_dbg_hex(const struct device *dev, int groupsize,
void *buf, size_t len, const char *fmt, ...)
@ -788,7 +793,12 @@ struct fb_info *fbtft_framebuffer_alloc(struct fbtft_display *display,
#endif
if (txbuflen > 0) {
if (dma) {
dev->coherent_dma_mask = ~0;
txbuf = dma_alloc_coherent(dev, txbuflen, &par->txbuf.dma, GFP_DMA);
} else {
txbuf = vzalloc(txbuflen);
}
if (!txbuf)
goto alloc_fail;
par->txbuf.buf = txbuf;
@ -817,8 +827,6 @@ struct fb_info *fbtft_framebuffer_alloc(struct fbtft_display *display,
alloc_fail:
if (vmem)
vfree(vmem);
if (txbuf)
vfree(txbuf);
if (buf)
vfree(buf);
kfree(fbops);
@ -841,8 +849,12 @@ void fbtft_framebuffer_release(struct fb_info *info)
fb_deferred_io_cleanup(info);
vfree(info->screen_base);
if (par->txbuf.buf)
if (par->txbuf.buf) {
if (par->txbuf.dma)
dma_free_coherent(info->device, par->txbuf.len, par->txbuf.buf, par->txbuf.dma);
else
vfree(par->txbuf.buf);
}
vfree(par->buf);
kfree(info->fbops);
kfree(info->fbdefio);
@ -921,7 +933,8 @@ int fbtft_register_framebuffer(struct fb_info *fb_info)
fbtft_sysfs_init(par);
if (par->txbuf.buf)
sprintf(text1, ", %d KiB buffer memory", par->txbuf.len >> 10);
sprintf(text1, ", %d KiB %sbuffer memory",
par->txbuf.len >> 10, par->txbuf.dma ? "DMA " : "");
if (spi)
sprintf(text2, ", spi%d.%d at %d MHz", spi->master->bus_num,
spi->chip_select, spi->max_speed_hz/1000000);

View file

@ -9,6 +9,12 @@
int fbtft_write_spi(struct fbtft_par *par, void *buf, size_t len)
{
struct spi_transfer t = {
.tx_buf = buf,
.len = len,
};
struct spi_message m;
fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len,
"%s(len=%d): ", __func__, len);
@ -17,7 +23,14 @@ int fbtft_write_spi(struct fbtft_par *par, void *buf, size_t len)
"%s: par->spi is unexpectedly NULL\n", __func__);
return -1;
}
return spi_write(par->spi, buf, len);
spi_message_init(&m);
if (par->txbuf.dma && buf == par->txbuf.buf) {
t.tx_dma = par->txbuf.dma;
m.is_dma_mapped = 1;
}
spi_message_add_tail(&t, &m);
return spi_sync(par->spi, &m);
}
EXPORT_SYMBOL(fbtft_write_spi);

View file

@ -219,6 +219,7 @@ struct fbtft_par {
u32 pseudo_palette[16];
struct {
void *buf;
dma_addr_t dma;
size_t len;
} txbuf;
u8 *buf;