All of lore.kernel.org
 help / color / mirror / Atom feed
  • * [PATCH 4/4] video: add driver for PXA3xx 2D graphics accelerator
           [not found]       ` <1247159091-28697-5-git-send-email-daniel@caiaq.de>
           [not found]         ` <4A56F02D.1000007@gmail.com>
    @ 2010-02-25 16:05         ` Daniel Mack
      2010-04-18  7:46           ` Daniel Mack
      1 sibling, 1 reply; 5+ messages in thread
    From: Daniel Mack @ 2010-02-25 16:05 UTC (permalink / raw)
      To: linux-arm-kernel
    
    (now used the new AKML address)
    
    Hi,
    
    Was anyone able to give that driver a try?
    Haojian, you wanted to have a look IIRC?
    
    I would appreciate seeing this in .35 if possible.
    
    Daniel
    
    
    On Thu, Jul 09, 2009 at 07:04:51PM +0200, Daniel Mack wrote:
    > This adds a driver for the the 2D graphics accelerator found on PXA3xx
    > processors. Only resource mapping, interrupt handling and a simple ioctl
    > handler is done by the kernel part, the rest of the logic is implemented
    > in DirectFB userspace.
    > 
    > Graphic applications benefit for line drawing, blend, and rectangle and
    > triangle filling operations.
    > 
    > Measurements on a PXA303 using the df_dok benchmarking tool follow,
    > where the value in square brackets show the CPU usage during that test.
    > 
    > Without accelerator:
    > 
    >   Fill Rectangle                                 3.007 secs (  175.922 MPixel/sec) [100.3%]
    >   Fill Rectangles [10]                           3.178 secs (  182.696 MPixel/sec) [100.0%]
    >   Fill Triangles                                 3.023 secs (   99.232 MPixel/sec) [100.3%]
    >   Blit                                           3.082 secs (   39.770 MPixel/sec) [100.0%]
    >   Blit 180                                       3.115 secs (   28.994 MPixel/sec) [100.3%]
    >   Blit with format conversion                    3.078 secs (   18.863 MPixel/sec) [100.0%]
    > 
    > With accelerator:
    > 
    >   Fill Rectangle                                 4.377 secs (*  88.433 MPixel/sec) [  5.9%]
    >   Fill Rectangles [10]                           5.176 secs (*  87.245 MPixel/sec) [  0.5%]
    >   Fill Triangles                                 3.025 secs (   87.437 MPixel/sec) [ 46.6%]
    >   Blit                                          12.177 secs (*  22.250 MPixel/sec) [  1.3%]
    >   Blit 180                                       8.421 secs (*  32.175 MPixel/sec) [  4.9%]
    >   Blit with format conversion                    8.216 secs (*  40.045 MPixel/sec) [  2.5%]
    > 
    > Signed-off-by: Daniel Mack <daniel@caiaq.de>
    > Cc: Denis Oliver Kropp <dok@directfb.org>
    > ---
    >  drivers/video/Kconfig      |   10 +
    >  drivers/video/Makefile     |    1 +
    >  drivers/video/pxa3xx-gcu.c |  591 ++++++++++++++++++++++++++++++++++++++++++++
    >  drivers/video/pxa3xx-gcu.h |   49 ++++
    >  4 files changed, 651 insertions(+), 0 deletions(-)
    >  create mode 100644 drivers/video/pxa3xx-gcu.c
    >  create mode 100644 drivers/video/pxa3xx-gcu.h
    > 
    > diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
    > index 8afcf08..6ad0a1c 100644
    > --- a/drivers/video/Kconfig
    > +++ b/drivers/video/Kconfig
    > @@ -1817,6 +1817,16 @@ config FB_PXA_PARAMETERS
    >  
    >  	  <file:Documentation/fb/pxafb.txt> describes the available parameters.
    >  
    > +config PXA3XX_GCU
    > +	tristate "PXA3xx 2D graphics accelerator driver"
    > +	depends on FB_PXA
    > +	help
    > +	  Kernelspace driver for the 2D graphics controller unit (GCU)
    > +	  found on PXA3xx processors. There is a counterpart driver in the
    > +	  DirectFB suite, see http://www.directfb.org/
    > +
    > +	  If you compile this as a module, it will be called pxa3xx_gcu.
    > +
    >  config FB_MBX
    >  	tristate "2700G LCD framebuffer support"
    >  	depends on FB && ARCH_PXA
    > diff --git a/drivers/video/Makefile b/drivers/video/Makefile
    > index 01a819f..ffe382c 100644
    > --- a/drivers/video/Makefile
    > +++ b/drivers/video/Makefile
    > @@ -98,6 +98,7 @@ obj-$(CONFIG_FB_CIRRUS)		  += cirrusfb.o
    >  obj-$(CONFIG_FB_ASILIANT)	  += asiliantfb.o
    >  obj-$(CONFIG_FB_PXA)		  += pxafb.o
    >  obj-$(CONFIG_FB_PXA168)		  += pxa168fb.o
    > +obj-$(CONFIG_PXA3XX_GCU)	  += pxa3xx-gcu.o
    >  obj-$(CONFIG_FB_W100)		  += w100fb.o
    >  obj-$(CONFIG_FB_TMIO)		  += tmiofb.o
    >  obj-$(CONFIG_FB_AU1100)		  += au1100fb.o
    > diff --git a/drivers/video/pxa3xx-gcu.c b/drivers/video/pxa3xx-gcu.c
    > new file mode 100644
    > index 0000000..224faf7
    > --- /dev/null
    > +++ b/drivers/video/pxa3xx-gcu.c
    > @@ -0,0 +1,591 @@
    > +/*
    > + *  pxa3xx-gc.c - Linux kernel module for PXA3xx graphics controllers
    > + *
    > + *  This driver needs a DirectFB counterpart in user space, communication
    > + *  is handled via mmap()ed memory areas and an ioctl.
    > + *
    > + *  Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
    > + *  Copyright (c) 2009 Janine Kropp <nin@directfb.org>
    > + *  Copyright (c) 2009 Denis Oliver Kropp <dok@directfb.org>
    > + *
    > + *  This program is free software; you can redistribute it and/or modify
    > + *  it under the terms of the GNU General Public License as published by
    > + *  the Free Software Foundation; either version 2 of the License, or
    > + *  (at your option) any later version.
    > + *
    > + *  This program is distributed in the hope that it will be useful,
    > + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
    > + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    > + *  GNU General Public License for more details.
    > + *
    > + *  You should have received a copy of the GNU General Public License
    > + *  along with this program; if not, write to the Free Software
    > + *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
    > + */
    > +
    > +/*
    > + * WARNING: This controller is attached to System Bus 2 of the PXA which
    > + * needs its arbiter to be enabled explictly (CKENB & 1<<9).
    > + * There is currently no way to do this from Linux, so you need to teach
    > + * your bootloader for now.
    > + */
    > +
    > +#include <linux/module.h>
    > +#include <linux/version.h>
    > +
    > +#include <linux/platform_device.h>
    > +#include <linux/dma-mapping.h>
    > +#include <linux/miscdevice.h>
    > +#include <linux/interrupt.h>
    > +#include <linux/spinlock.h>
    > +#include <linux/uaccess.h>
    > +#include <linux/ioctl.h>
    > +#include <linux/delay.h>
    > +#include <linux/sched.h>
    > +#include <linux/clk.h>
    > +#include <linux/fs.h>
    > +#include <linux/io.h>
    > +
    > +#include "pxa3xx-gcu.h"
    > +
    > +#define DRV_NAME	"pxa3xx-gcu"
    > +#define MISCDEV_MINOR	197
    > +
    > +#define REG_GCCR	0x00
    > +#define GCCR_SYNC_CLR	(1 << 9)
    > +#define GCCR_BP_RST	(1 << 8)
    > +#define GCCR_ABORT	(1 << 6)
    > +#define GCCR_STOP	(1 << 4)
    > +
    > +#define REG_GCISCR	0x04
    > +#define REG_GCIECR	0x08
    > +#define REG_GCRBBR	0x20
    > +#define REG_GCRBLR	0x24
    > +#define REG_GCRBHR	0x28
    > +#define REG_GCRBTR	0x2C
    > +#define REG_GCRBEXHR	0x30
    > +
    > +#define IE_EOB		(1 << 0)
    > +#define IE_EEOB		(1 << 5)
    > +#define IE_ALL		0xff
    > +
    > +#define SHARED_SIZE	PAGE_ALIGN(sizeof(struct pxa3xx_gcu_shared))
    > +
    > +/* #define PXA3XX_GCU_DEBUG */
    > +/* #define PXA3XX_GCU_DEBUG_TIMER */
    > +
    > +#ifdef PXA3XX_GCU_DEBUG
    > +#define QDUMP(msg)	\
    > +	do {						\
    > +		QPRINT(priv, KERN_DEBUG, msg);		\
    > +	} while (0)
    > +#else
    > +#define QDUMP(msg)	do {} while (0)
    > +#endif
    > +
    > +#define QERROR(msg)	\
    > +	do {						\
    > +		QPRINT(priv, KERN_ERR, msg);		\
    > +	} while (0)
    > +
    > +struct pxa3xx_gcu_priv {
    > +	void __iomem		*mmio_base;
    > +	struct clk		*clk;
    > +	struct pxa3xx_gcu_shared	*shared;
    > +	dma_addr_t		 shared_phys;
    > +	struct resource		*resource_mem;
    > +	struct miscdevice	 misc_dev;
    > +	struct file_operations	 misc_fops;
    > +	wait_queue_head_t	 wait_idle;
    > +	wait_queue_head_t	 wait_next;
    > +	spinlock_t		 spinlock;
    > +	struct timeval 		 base_time;
    > +};
    > +
    > +static inline unsigned long
    > +gc_readl(struct pxa3xx_gcu_priv *priv, unsigned int off)
    > +{
    > +	return __raw_readl(priv->mmio_base + off);
    > +}
    > +
    > +static inline void
    > +gc_writel(struct pxa3xx_gcu_priv *priv, unsigned int off, unsigned long val)
    > +{
    > +	__raw_writel(val, priv->mmio_base + off);
    > +}
    > +
    > +#define QPRINT(priv, level, msg)					\
    > +	do {								\
    > +		struct timeval tv;					\
    > +		struct pxa3xx_gcu_shared *shared = priv->shared;	\
    > +		u32 base = gc_readl(priv, REG_GCRBBR);			\
    > +									\
    > +		do_gettimeofday(&tv);					\
    > +									\
    > +		printk(level "%ld.%03ld.%03ld - %-17s: %-21s (%s, "	\
    > +			"hw %5d-%5d, next %5d-%5d, %svalid, STATUS "	\
    > +			"0x%02lx, B 0x%08lx [%ld], E %5ld, H %5ld, "	\
    > +			"T %5ld)\n",					\
    > +			tv.tv_sec - priv->base_time.tv_sec,		\
    > +			tv.tv_usec / 1000, tv.tv_usec % 1000,		\
    > +			__func__, msg,					\
    > +			shared->hw_running ? "running" : "   idle",	\
    > +			shared->hw_start,				\
    > +			shared->hw_end,					\
    > +			shared->next_start,				\
    > +			shared->next_end,				\
    > +			shared->next_valid ? "  " : "in",		\
    > +			gc_readl(priv, REG_GCISCR),			\
    > +			gc_readl(priv, REG_GCRBBR),			\
    > +			gc_readl(priv, REG_GCRBLR),			\
    > +			(gc_readl(priv, REG_GCRBEXHR) - base) / 4,	\
    > +			(gc_readl(priv, REG_GCRBHR) - base) / 4,	\
    > +			(gc_readl(priv, REG_GCRBTR) - base) / 4);	\
    > +	} while (0)
    > +
    > +static void pxa3xx_gcu_reset(struct pxa3xx_gcu_priv *priv)
    > +{
    > +	QDUMP("RESET");
    > +
    > +	/* disable interrupts */
    > +	gc_writel(priv, REG_GCIECR, 0);
    > +
    > +	/* reset hardware */
    > +	gc_writel(priv, REG_GCCR, GCCR_ABORT);
    > +	gc_writel(priv, REG_GCCR, 0);
    > +
    > +	memset(priv->shared, 0, SHARED_SIZE);
    > +	priv->shared->buffer_phys = priv->shared_phys;
    > +	priv->shared->magic = PXA3XX_GCU_SHARED_MAGIC;
    > +
    > +	do_gettimeofday(&priv->base_time);
    > +
    > +	/* set up the ring buffer pointers */
    > +	gc_writel(priv, REG_GCRBLR, 0);
    > +	gc_writel(priv, REG_GCRBBR, priv->shared_phys);
    > +	gc_writel(priv, REG_GCRBTR, priv->shared_phys);
    > +
    > +	/* enable all IRQs except EOB */
    > +	gc_writel(priv, REG_GCIECR, IE_ALL & ~IE_EOB);
    > +}
    > +
    > +static void pxa3xx_gcu_start(struct pxa3xx_gcu_priv *priv)
    > +{
    > +	struct pxa3xx_gcu_shared	*sh = priv->shared;
    > +
    > +	QDUMP("Start");
    > +
    > +	gc_writel(priv, REG_GCRBLR, 0);
    > +
    > +	/* ring base address */
    > +	gc_writel(priv, REG_GCRBBR, sh->buffer_phys + sh->hw_start * 4);
    > +
    > +	/* ring tail address */
    > +	gc_writel(priv, REG_GCRBTR, sh->buffer_phys + sh->hw_end * 4);
    > +
    > +	/* ring length */
    > +	gc_writel(priv, REG_GCRBLR,
    > +		((sh->hw_end - sh->hw_start + 63) & ~63) * 4);
    > +}
    > +
    > +static irqreturn_t pxa3xx_gcu_handle_irq(int irq, void *ctx)
    > +{
    > +	struct pxa3xx_gcu_priv *priv = ctx;
    > +	struct pxa3xx_gcu_shared *shared = priv->shared;
    > +	u32 status = gc_readl(priv, REG_GCISCR) & IE_ALL;
    > +
    > +	if (!status)
    > +		return IRQ_NONE;
    > +
    > +	QDUMP("-Interrupt");
    > +
    > +	spin_lock(&priv->spinlock);
    > +
    > +	shared->num_interrupts++;
    > +
    > +	if (status & IE_EEOB) {
    > +		QDUMP(" [EEOB]");
    > +
    > +		/* next_valid means user space is not in the process of
    > +		 * extending the buffer, so we can safely access the
    > +		 * contents. */
    > +		if (shared->next_valid &&
    > +		    shared->next_start != shared->next_end) {
    > +			shared->hw_start = shared->next_start;
    > +			shared->hw_end = shared->next_end;
    > +			shared->next_start = (shared->hw_end + 63) & ~63;
    > +			shared->next_end = shared->next_start;
    > +			shared->num_words += shared->hw_end - shared->hw_start;
    > +			shared->num_starts++;
    > +
    > +			pxa3xx_gcu_start(priv);
    > +
    > +			wake_up_all(&priv->wait_next);
    > +		} else {
    > +			/* There is no more data prepared by the userspace.
    > +			 * Set hw_running = 0 and wait for the next userspace
    > +			 * kick-off */
    > +			shared->num_idle++;
    > +			shared->hw_running = 0;
    > +
    > +			QDUMP(" '-> Idle.");
    > +
    > +			/* set ring buffer length to zero */
    > +			gc_writel(priv, REG_GCRBLR, 0);
    > +
    > +			wake_up_all(&priv->wait_next);
    > +			wake_up_all(&priv->wait_idle);
    > +		}
    > +
    > +		shared->num_done++;
    > +	} else
    > +		QERROR(" [???]");
    > +
    > +	/* Clear the interrupt */
    > +	gc_writel(priv, REG_GCISCR, status);
    > +	spin_unlock(&priv->spinlock);
    > +
    > +	return IRQ_HANDLED;
    > +}
    > +
    > +static int
    > +pxa3xx_gcu_wait_idle(struct pxa3xx_gcu_priv *priv)
    > +{
    > +	int ret = 0;
    > +
    > +	QDUMP("Waiting for idle...");
    > +
    > +	while (priv->shared->hw_running) {
    > +		int num = priv->shared->num_interrupts;
    > +		u32 rbexhr = gc_readl(priv, REG_GCRBEXHR);
    > +
    > +		ret = wait_event_interruptible_timeout(priv->wait_idle,
    > +					!priv->shared->hw_running, HZ/4);
    > +
    > +		if (ret < 0)
    > +			break;
    > +
    > +		if (ret > 0)
    > +			continue;
    > +
    > +		if (gc_readl(priv, REG_GCRBEXHR) == rbexhr &&
    > +		    priv->shared->num_interrupts == num) {
    > +			QERROR("TIMEOUT");
    > +			ret = -ETIMEDOUT;
    > +			break;
    > +		}
    > +	}
    > +
    > +	QDUMP("done");
    > +
    > +	return ret;
    > +}
    > +
    > +static int
    > +pxa3xx_gcu_wait_next(struct pxa3xx_gcu_priv *priv)
    > +{
    > +	int ret = 0;
    > +	int num = priv->shared->num_interrupts;
    > +
    > +	QDUMP("Waiting for next...");
    > +
    > +	while (priv->shared->hw_running &&
    > +	       num == priv->shared->num_interrupts) {
    > +		u32 rbexhr = gc_readl(priv, REG_GCRBEXHR);
    > +
    > +		ret = wait_event_interruptible_timeout(priv->wait_next,
    > +			(!priv->shared->hw_running ||
    > +			 num != priv->shared->num_interrupts), HZ/4);
    > +
    > +		if (ret < 0)
    > +			break;
    > +
    > +		if (ret > 0)
    > +			continue;
    > +
    > +		if (gc_readl(priv, REG_GCRBEXHR) == rbexhr) {
    > +			QERROR("TIMEOUT");
    > +			ret = -ETIMEDOUT;
    > +			break;
    > +		}
    > +	}
    > +
    > +	QDUMP("done");
    > +
    > +	return ret;
    > +}
    > +
    > +/* Misc device layer */
    > +
    > +static int
    > +pxa3xx_gcu_misc_ioctl(struct inode *inode, struct file *filp,
    > +		 unsigned int cmd, unsigned long arg)
    > +{
    > +	unsigned long flags;
    > +	struct pxa3xx_gcu_priv *priv =
    > +		container_of(filp->f_op, struct pxa3xx_gcu_priv, misc_fops);
    > +
    > +	switch (cmd) {
    > +	case PXA3XX_GCU_IOCTL_RESET:
    > +		spin_lock_irqsave(&priv->spinlock, flags);
    > +		pxa3xx_gcu_reset(priv);
    > +		spin_unlock_irqrestore(&priv->spinlock, flags);
    > +		return 0;
    > +
    > +	case PXA3XX_GCU_IOCTL_START:
    > +		spin_lock_irqsave(&priv->spinlock, flags);
    > +		pxa3xx_gcu_start(priv);
    > +		spin_unlock_irqrestore(&priv->spinlock, flags);
    > +		return 0;
    > +
    > +	case PXA3XX_GCU_IOCTL_WAIT_IDLE:
    > +		/* Does not need to be atomic. There's a lock in user space,
    > +		 * but anyhow, this is just for statistics. */
    > +		priv->shared->num_wait_idle++;
    > +		return pxa3xx_gcu_wait_idle(priv);
    > +
    > +	case PXA3XX_GCU_IOCTL_WAIT_NEXT:
    > +		/* Does not need to be atomic. There's a lock in user space,
    > +		 * but anyhow, this is just for statistics. */
    > +		priv->shared->num_wait_next++;
    > +		return pxa3xx_gcu_wait_next(priv);
    > +	}
    > +
    > +	return -ENOSYS;
    > +}
    > +
    > +static int
    > +pxa3xx_gcu_misc_mmap(struct file *filp, struct vm_area_struct *vma)
    > +{
    > +	unsigned int size = vma->vm_end - vma->vm_start;
    > +	struct pxa3xx_gcu_priv *priv =
    > +		container_of(filp->f_op, struct pxa3xx_gcu_priv, misc_fops);
    > +
    > +	switch (vma->vm_pgoff) {
    > +	case 0:
    > +		/* hand out the shared data area */
    > +		if (size != SHARED_SIZE)
    > +			return -EINVAL;
    > +
    > +		return dma_mmap_coherent(NULL, vma,
    > +			priv->shared, priv->shared_phys, size);
    > +
    > +	case SHARED_SIZE >> PAGE_SHIFT:
    > +		/* hand out the MMIO base for direct register access
    > +		 * from userspace */
    > +		if (size != resource_size(priv->resource_mem))
    > +			return -EINVAL;
    > +
    > +		vma->vm_flags |= VM_IO;
    > +		vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
    > +
    > +		return io_remap_pfn_range(vma, vma->vm_start,
    > +				priv->resource_mem->start >> PAGE_SHIFT,
    > +				size, vma->vm_page_prot);
    > +	}
    > +
    > +	return -EINVAL;
    > +}
    > +
    > +
    > +#ifdef PXA3XX_GCU_DEBUG_TIMER
    > +static struct timer_list pxa3xx_gcu_debug_timer;
    > +
    > +static void pxa3xx_gcu_debug_timedout(unsigned long ptr)
    > +{
    > +	struct pxa3xx_gcu_priv *priv = (struct pxa3xx_gcu_priv *) ptr;
    > +
    > +	QERROR("Timer DUMP");
    > +
    > +	/* init the timer structure */
    > +	init_timer(&pxa3xx_gcu_debug_timer);
    > +	pxa3xx_gcu_debug_timer.function = pxa3xx_gcu_debug_timedout;
    > +	pxa3xx_gcu_debug_timer.data = ptr;
    > +	pxa3xx_gcu_debug_timer.expires = jiffies + 5*HZ; /* one second */
    > +
    > +	add_timer(&pxa3xx_gcu_debug_timer);
    > +}
    > +
    > +static void pxa3xx_gcu_init_debug_timer(void)
    > +{
    > +	pxa3xx_gcu_debug_timedout((unsigned long) &pxa3xx_gcu_debug_timer);
    > +}
    > +#else
    > +static inline void pxa3xx_gcu_init_debug_timer(void) {}
    > +#endif
    > +
    > +static int __devinit pxa3xx_gcu_probe(struct platform_device *dev)
    > +{
    > +	int ret, irq;
    > +	struct resource *r;
    > +	struct pxa3xx_gcu_priv *priv;
    > +
    > +	priv = kzalloc(sizeof(struct pxa3xx_gcu_priv), GFP_KERNEL);
    > +	if (!priv)
    > +		return -ENOMEM;
    > +
    > +	init_waitqueue_head(&priv->wait_idle);
    > +	init_waitqueue_head(&priv->wait_next);
    > +	spin_lock_init(&priv->spinlock);
    > +
    > +	/* we allocate the misc device structure as part of our own allocation,
    > +	 * so we can get a pointer to our priv structure later on with
    > +	 * container_of(). This isn't really necessary as we have a fixed minor
    > +	 * number anyway, but this is to avoid statics. */
    > +
    > +	priv->misc_fops.owner	= THIS_MODULE;
    > +	priv->misc_fops.ioctl	= pxa3xx_gcu_misc_ioctl;
    > +	priv->misc_fops.mmap	= pxa3xx_gcu_misc_mmap;
    > +
    > +	priv->misc_dev.minor	= MISCDEV_MINOR,
    > +	priv->misc_dev.name	= DRV_NAME,
    > +	priv->misc_dev.fops	= &priv->misc_fops,
    > +
    > +	/* register misc device */
    > +	ret = misc_register(&priv->misc_dev);
    > +	if (ret < 0) {
    > +		dev_err(&dev->dev, "misc_register() for minor %d failed\n",
    > +			MISCDEV_MINOR);
    > +		goto err_free_priv;
    > +	}
    > +
    > +	/* handle IO resources */
    > +	r = platform_get_resource(dev, IORESOURCE_MEM, 0);
    > +	if (r == NULL) {
    > +		dev_err(&dev->dev, "no I/O memory resource defined\n");
    > +		ret = -ENODEV;
    > +		goto err_misc_deregister;
    > +	}
    > +
    > +	if (!request_mem_region(r->start, resource_size(r), dev->name)) {
    > +		dev_err(&dev->dev, "failed to request I/O memory\n");
    > +		ret = -EBUSY;
    > +		goto err_misc_deregister;
    > +	}
    > +
    > +	priv->mmio_base = ioremap_nocache(r->start, resource_size(r));
    > +	if (!priv->mmio_base) {
    > +		dev_err(&dev->dev, "failed to map I/O memory\n");
    > +		ret = -EBUSY;
    > +		goto err_free_mem_region;
    > +	}
    > +
    > +	/* allocate dma memory */
    > +	priv->shared = dma_alloc_coherent(&dev->dev, SHARED_SIZE,
    > +					  &priv->shared_phys, GFP_KERNEL);
    > +
    > +	if (!priv->shared) {
    > +		dev_err(&dev->dev, "failed to allocate DMA memory\n");
    > +		ret = -ENOMEM;
    > +		goto err_free_io;
    > +	}
    > +
    > +	/* enable the clock */
    > +	priv->clk = clk_get(&dev->dev, NULL);
    > +	if (IS_ERR(priv->clk)) {
    > +		dev_err(&dev->dev, "failed to get clock\n");
    > +		ret = -ENODEV;
    > +		goto err_free_dma;
    > +	}
    > +
    > +	ret = clk_enable(priv->clk);
    > +	if (ret < 0) {
    > +		dev_err(&dev->dev, "failed to enable clock\n");
    > +		goto err_put_clk;
    > +	}
    > +
    > +	/* request the IRQ */
    > +	irq = platform_get_irq(dev, 0);
    > +	if (irq < 0) {
    > +		dev_err(&dev->dev, "no IRQ defined\n");
    > +		ret = -ENODEV;
    > +		goto err_put_clk;
    > +	}
    > +
    > +	ret = request_irq(irq, pxa3xx_gcu_handle_irq,
    > +			  IRQF_DISABLED, DRV_NAME, priv);
    > +	if (ret) {
    > +		dev_err(&dev->dev, "request_irq failed\n");
    > +		ret = -EBUSY;
    > +		goto err_put_clk;
    > +	}
    > +
    > +	platform_set_drvdata(dev, priv);
    > +	priv->resource_mem = r;
    > +	pxa3xx_gcu_reset(priv);
    > +	pxa3xx_gcu_init_debug_timer();
    > +
    > +	dev_info(&dev->dev, "registered @0x%p, DMA 0x%p (%d bytes), IRQ %d\n",
    > +			(void *) r->start, (void *) priv->shared_phys,
    > +			SHARED_SIZE, irq);
    > +	return 0;
    > +
    > +err_put_clk:
    > +	clk_put(priv->clk);
    > +
    > +err_free_dma:
    > +	dma_free_coherent(&dev->dev, SHARED_SIZE,
    > +			priv->shared, priv->shared_phys);
    > +
    > +err_free_io:
    > +	iounmap(priv->mmio_base);
    > +	clk_disable(priv->clk);
    > +
    > +err_free_mem_region:
    > +	release_mem_region(r->start, resource_size(r));
    > +
    > +err_misc_deregister:
    > +	misc_deregister(&priv->misc_dev);
    > +
    > +err_free_priv:
    > +	platform_set_drvdata(dev, NULL);
    > +	kfree(priv);
    > +	return ret;
    > +}
    > +
    > +static int __devexit pxa3xx_gcu_remove(struct platform_device *dev)
    > +{
    > +	struct pxa3xx_gcu_priv *priv = platform_get_drvdata(dev);
    > +	struct resource *r = priv->resource_mem;
    > +
    > +	misc_deregister(&priv->misc_dev);
    > +	dma_free_coherent(&dev->dev, SHARED_SIZE,
    > +			priv->shared, priv->shared_phys);
    > +	iounmap(priv->mmio_base);
    > +	release_mem_region(r->start, resource_size(r));
    > +	platform_set_drvdata(dev, NULL);
    > +	clk_disable(priv->clk);
    > +	kfree(priv);
    > +
    > +	return 0;
    > +}
    > +
    > +static struct platform_driver pxa3xx_gcu_driver = {
    > +	.probe	  = pxa3xx_gcu_probe,
    > +	.remove	 = __devexit_p(pxa3xx_gcu_remove),
    > +	.driver	 = {
    > +		.owner  = THIS_MODULE,
    > +		.name   = DRV_NAME,
    > +	},
    > +};
    > +
    > +static int __init pxa3xx_gcu_init(void)
    > +{
    > +	return platform_driver_register(&pxa3xx_gcu_driver);
    > +}
    > +
    > +static void __exit pxa3xx_gcu_exit(void)
    > +{
    > +	platform_driver_unregister(&pxa3xx_gcu_driver);
    > +}
    > +
    > +module_init(pxa3xx_gcu_init);
    > +module_exit(pxa3xx_gcu_exit);
    > +
    > +MODULE_DESCRIPTION("PXA3xx graphics controller unit driver");
    > +MODULE_LICENSE("GPL");
    > +MODULE_ALIAS_MISCDEV(MISCDEV_MINOR);
    > +MODULE_AUTHOR("Janine Kropp <nin@directfb.org>, "
    > +		"Denis Oliver Kropp <dok@directfb.org>, "
    > +		"Daniel Mack <daniel@caiaq.de>");
    > +
    > diff --git a/drivers/video/pxa3xx-gcu.h b/drivers/video/pxa3xx-gcu.h
    > new file mode 100644
    > index 0000000..18d8e43
    > --- /dev/null
    > +++ b/drivers/video/pxa3xx-gcu.h
    > @@ -0,0 +1,49 @@
    > +#ifndef __PXA3XX_GCU_H__
    > +#define __PXA3XX_GCU_H__
    > +
    > +#include <linux/types.h>
    > +
    > +/* Number of 32bit words in display list (ring buffer). */
    > +#define PXA3XX_GCU_BUFFER_WORDS  ((256 * 1024 - 256) / 4)
    > +
    > +/* To be increased when breaking the ABI */
    > +#define PXA3XX_GCU_SHARED_MAGIC  0x30000001
    > +
    > +struct pxa3xx_gcu_shared {
    > +	u32            buffer[PXA3XX_GCU_BUFFER_WORDS];
    > +
    > +	bool           hw_running;
    > +	int            hw_start;
    > +	int            hw_end;
    > +
    > +	int            next_start;
    > +	int            next_end;
    > +	int            next_valid;
    > +
    > +	unsigned long  buffer_phys;
    > +
    > +	unsigned int   num_words;
    > +	unsigned int   num_starts;
    > +	unsigned int   num_done;
    > +	unsigned int   num_interrupts;
    > +	unsigned int   num_wait_idle;
    > +	unsigned int   num_wait_next;
    > +	unsigned int   num_idle;
    > +
    > +	u32            magic;
    > +};
    > +
    > +struct pxa3xx_gcu_register {
    > +	u32		address;	/* in */
    > +	u32		value;		/* in/out */
    > +};
    > +
    > +/* Initialization and synchronization.
    > + * Hardware is started from user space via MMIO or via ioctl. */
    > +#define PXA3XX_GCU_IOCTL_RESET		_IO('G', 0)
    > +#define PXA3XX_GCU_IOCTL_START		_IO('G', 1)
    > +#define PXA3XX_GCU_IOCTL_WAIT_IDLE	_IO('G', 2)
    > +#define PXA3XX_GCU_IOCTL_WAIT_NEXT	_IO('G', 3)
    > +
    > +#endif /* __PXA3XX_GCU_H__ */
    > +
    > -- 
    > 1.6.3.1
    > 
    
    ^ permalink raw reply	[flat|nested] 5+ messages in thread

  • end of thread, other threads:[~2010-04-18  7:46 UTC | newest]
    
    Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
    -- links below jump to the message on this page --
         [not found] <1247159091-28697-1-git-send-email-daniel@caiaq.de>
         [not found] ` <1247159091-28697-2-git-send-email-daniel@caiaq.de>
         [not found]   ` <1247159091-28697-3-git-send-email-daniel@caiaq.de>
         [not found]     ` <1247159091-28697-4-git-send-email-daniel@caiaq.de>
         [not found]       ` <1247159091-28697-5-git-send-email-daniel@caiaq.de>
         [not found]         ` <4A56F02D.1000007@gmail.com>
         [not found]           ` <20090718080736.GL13236@buzzloop.caiaq.de>
         [not found]             ` <4A63E08F.4090409@gmail.com>
    2009-07-20 10:14               ` [PATCH] video: add PXA3xx accelerator ID Daniel Mack
         [not found]               ` <20090720102239.GA3809@buzzloop.caiaq.de>
         [not found]                 ` <4A645A38.1080008@gmail.com>
         [not found]                   ` <20090720134703.GE19257@buzzloop.caiaq.de>
         [not found]                     ` <4A64830F.2020701@gmail.com>
         [not found]                       ` <20090722120433.GA9464@buzzloop.caiaq.de>
    2009-09-02 21:24                         ` [PATCH 4/4] video: add driver for PXA3xx 2D graphics accelerator Daniel Mack
    2009-09-02 21:24                           ` Daniel Mack
    2010-02-25 16:05         ` Daniel Mack
    2010-04-18  7:46           ` Daniel Mack
    

    This is an external index of several public inboxes,
    see mirroring instructions on how to clone and mirror
    all data and code used by this external index.