Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  pxa3xx-gcu.c - Linux kernel module for PXA3xx graphics controllers
0004  *
0005  *  This driver needs a DirectFB counterpart in user space, communication
0006  *  is handled via mmap()ed memory areas and an ioctl.
0007  *
0008  *  Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
0009  *  Copyright (c) 2009 Janine Kropp <nin@directfb.org>
0010  *  Copyright (c) 2009 Denis Oliver Kropp <dok@directfb.org>
0011  */
0012 
0013 /*
0014  * WARNING: This controller is attached to System Bus 2 of the PXA which
0015  * needs its arbiter to be enabled explicitly (CKENB & 1<<9).
0016  * There is currently no way to do this from Linux, so you need to teach
0017  * your bootloader for now.
0018  */
0019 
0020 #include <linux/module.h>
0021 #include <linux/platform_device.h>
0022 #include <linux/dma-mapping.h>
0023 #include <linux/miscdevice.h>
0024 #include <linux/interrupt.h>
0025 #include <linux/spinlock.h>
0026 #include <linux/uaccess.h>
0027 #include <linux/ioctl.h>
0028 #include <linux/delay.h>
0029 #include <linux/sched.h>
0030 #include <linux/slab.h>
0031 #include <linux/clk.h>
0032 #include <linux/fs.h>
0033 #include <linux/io.h>
0034 #include <linux/of.h>
0035 
0036 #include "pxa3xx-gcu.h"
0037 
0038 #define DRV_NAME    "pxa3xx-gcu"
0039 
0040 #define REG_GCCR    0x00
0041 #define GCCR_SYNC_CLR   (1 << 9)
0042 #define GCCR_BP_RST (1 << 8)
0043 #define GCCR_ABORT  (1 << 6)
0044 #define GCCR_STOP   (1 << 4)
0045 
0046 #define REG_GCISCR  0x04
0047 #define REG_GCIECR  0x08
0048 #define REG_GCRBBR  0x20
0049 #define REG_GCRBLR  0x24
0050 #define REG_GCRBHR  0x28
0051 #define REG_GCRBTR  0x2C
0052 #define REG_GCRBEXHR    0x30
0053 
0054 #define IE_EOB      (1 << 0)
0055 #define IE_EEOB     (1 << 5)
0056 #define IE_ALL      0xff
0057 
0058 #define SHARED_SIZE PAGE_ALIGN(sizeof(struct pxa3xx_gcu_shared))
0059 
0060 /* #define PXA3XX_GCU_DEBUG */
0061 /* #define PXA3XX_GCU_DEBUG_TIMER */
0062 
0063 #ifdef PXA3XX_GCU_DEBUG
0064 #define QDUMP(msg)                  \
0065     do {                        \
0066         QPRINT(priv, KERN_DEBUG, msg);      \
0067     } while (0)
0068 #else
0069 #define QDUMP(msg)  do {} while (0)
0070 #endif
0071 
0072 #define QERROR(msg)                 \
0073     do {                        \
0074         QPRINT(priv, KERN_ERR, msg);        \
0075     } while (0)
0076 
0077 struct pxa3xx_gcu_batch {
0078     struct pxa3xx_gcu_batch *next;
0079     u32         *ptr;
0080     dma_addr_t       phys;
0081     unsigned long        length;
0082 };
0083 
0084 struct pxa3xx_gcu_priv {
0085     struct device        *dev;
0086     void __iomem         *mmio_base;
0087     struct clk       *clk;
0088     struct pxa3xx_gcu_shared *shared;
0089     dma_addr_t        shared_phys;
0090     struct resource      *resource_mem;
0091     struct miscdevice     misc_dev;
0092     wait_queue_head_t     wait_idle;
0093     wait_queue_head_t     wait_free;
0094     spinlock_t        spinlock;
0095     struct timespec64     base_time;
0096 
0097     struct pxa3xx_gcu_batch *free;
0098     struct pxa3xx_gcu_batch *ready;
0099     struct pxa3xx_gcu_batch *ready_last;
0100     struct pxa3xx_gcu_batch *running;
0101 };
0102 
0103 static inline unsigned long
0104 gc_readl(struct pxa3xx_gcu_priv *priv, unsigned int off)
0105 {
0106     return __raw_readl(priv->mmio_base + off);
0107 }
0108 
0109 static inline void
0110 gc_writel(struct pxa3xx_gcu_priv *priv, unsigned int off, unsigned long val)
0111 {
0112     __raw_writel(val, priv->mmio_base + off);
0113 }
0114 
0115 #define QPRINT(priv, level, msg)                    \
0116     do {                                \
0117         struct timespec64 ts;                   \
0118         struct pxa3xx_gcu_shared *shared = priv->shared;    \
0119         u32 base = gc_readl(priv, REG_GCRBBR);          \
0120                                     \
0121         ktime_get_ts64(&ts);                    \
0122         ts = timespec64_sub(ts, priv->base_time);       \
0123                                     \
0124         printk(level "%lld.%03ld.%03ld - %-17s: %-21s (%s, "    \
0125             "STATUS "                   \
0126             "0x%02lx, B 0x%08lx [%ld], E %5ld, H %5ld, "    \
0127             "T %5ld)\n",                    \
0128             (s64)(ts.tv_sec),               \
0129             ts.tv_nsec / NSEC_PER_MSEC,         \
0130             (ts.tv_nsec % NSEC_PER_MSEC) / USEC_PER_MSEC,   \
0131             __func__, msg,                  \
0132             shared->hw_running ? "running" : "   idle", \
0133             gc_readl(priv, REG_GCISCR),         \
0134             gc_readl(priv, REG_GCRBBR),         \
0135             gc_readl(priv, REG_GCRBLR),         \
0136             (gc_readl(priv, REG_GCRBEXHR) - base) / 4,  \
0137             (gc_readl(priv, REG_GCRBHR) - base) / 4,    \
0138             (gc_readl(priv, REG_GCRBTR) - base) / 4);   \
0139     } while (0)
0140 
0141 static void
0142 pxa3xx_gcu_reset(struct pxa3xx_gcu_priv *priv)
0143 {
0144     QDUMP("RESET");
0145 
0146     /* disable interrupts */
0147     gc_writel(priv, REG_GCIECR, 0);
0148 
0149     /* reset hardware */
0150     gc_writel(priv, REG_GCCR, GCCR_ABORT);
0151     gc_writel(priv, REG_GCCR, 0);
0152 
0153     memset(priv->shared, 0, SHARED_SIZE);
0154     priv->shared->buffer_phys = priv->shared_phys;
0155     priv->shared->magic = PXA3XX_GCU_SHARED_MAGIC;
0156 
0157     ktime_get_ts64(&priv->base_time);
0158 
0159     /* set up the ring buffer pointers */
0160     gc_writel(priv, REG_GCRBLR, 0);
0161     gc_writel(priv, REG_GCRBBR, priv->shared_phys);
0162     gc_writel(priv, REG_GCRBTR, priv->shared_phys);
0163 
0164     /* enable all IRQs except EOB */
0165     gc_writel(priv, REG_GCIECR, IE_ALL & ~IE_EOB);
0166 }
0167 
0168 static void
0169 dump_whole_state(struct pxa3xx_gcu_priv *priv)
0170 {
0171     struct pxa3xx_gcu_shared *sh = priv->shared;
0172     u32 base = gc_readl(priv, REG_GCRBBR);
0173 
0174     QDUMP("DUMP");
0175 
0176     printk(KERN_DEBUG "== PXA3XX-GCU DUMP ==\n"
0177         "%s, STATUS 0x%02lx, B 0x%08lx [%ld], E %5ld, H %5ld, T %5ld\n",
0178         sh->hw_running ? "running" : "idle   ",
0179         gc_readl(priv, REG_GCISCR),
0180         gc_readl(priv, REG_GCRBBR),
0181         gc_readl(priv, REG_GCRBLR),
0182         (gc_readl(priv, REG_GCRBEXHR) - base) / 4,
0183         (gc_readl(priv, REG_GCRBHR) - base) / 4,
0184         (gc_readl(priv, REG_GCRBTR) - base) / 4);
0185 }
0186 
0187 static void
0188 flush_running(struct pxa3xx_gcu_priv *priv)
0189 {
0190     struct pxa3xx_gcu_batch *running = priv->running;
0191     struct pxa3xx_gcu_batch *next;
0192 
0193     while (running) {
0194         next = running->next;
0195         running->next = priv->free;
0196         priv->free = running;
0197         running = next;
0198     }
0199 
0200     priv->running = NULL;
0201 }
0202 
0203 static void
0204 run_ready(struct pxa3xx_gcu_priv *priv)
0205 {
0206     unsigned int num = 0;
0207     struct pxa3xx_gcu_shared *shared = priv->shared;
0208     struct pxa3xx_gcu_batch *ready = priv->ready;
0209 
0210     QDUMP("Start");
0211 
0212     BUG_ON(!ready);
0213 
0214     shared->buffer[num++] = 0x05000000;
0215 
0216     while (ready) {
0217         shared->buffer[num++] = 0x00000001;
0218         shared->buffer[num++] = ready->phys;
0219         ready = ready->next;
0220     }
0221 
0222     shared->buffer[num++] = 0x05000000;
0223     priv->running = priv->ready;
0224     priv->ready = priv->ready_last = NULL;
0225     gc_writel(priv, REG_GCRBLR, 0);
0226     shared->hw_running = 1;
0227 
0228     /* ring base address */
0229     gc_writel(priv, REG_GCRBBR, shared->buffer_phys);
0230 
0231     /* ring tail address */
0232     gc_writel(priv, REG_GCRBTR, shared->buffer_phys + num * 4);
0233 
0234     /* ring length */
0235     gc_writel(priv, REG_GCRBLR, ((num + 63) & ~63) * 4);
0236 }
0237 
0238 static irqreturn_t
0239 pxa3xx_gcu_handle_irq(int irq, void *ctx)
0240 {
0241     struct pxa3xx_gcu_priv *priv = ctx;
0242     struct pxa3xx_gcu_shared *shared = priv->shared;
0243     u32 status = gc_readl(priv, REG_GCISCR) & IE_ALL;
0244 
0245     QDUMP("-Interrupt");
0246 
0247     if (!status)
0248         return IRQ_NONE;
0249 
0250     spin_lock(&priv->spinlock);
0251     shared->num_interrupts++;
0252 
0253     if (status & IE_EEOB) {
0254         QDUMP(" [EEOB]");
0255 
0256         flush_running(priv);
0257         wake_up_all(&priv->wait_free);
0258 
0259         if (priv->ready) {
0260             run_ready(priv);
0261         } else {
0262             /* There is no more data prepared by the userspace.
0263              * Set hw_running = 0 and wait for the next userspace
0264              * kick-off */
0265             shared->num_idle++;
0266             shared->hw_running = 0;
0267 
0268             QDUMP(" '-> Idle.");
0269 
0270             /* set ring buffer length to zero */
0271             gc_writel(priv, REG_GCRBLR, 0);
0272 
0273             wake_up_all(&priv->wait_idle);
0274         }
0275 
0276         shared->num_done++;
0277     } else {
0278         QERROR(" [???]");
0279         dump_whole_state(priv);
0280     }
0281 
0282     /* Clear the interrupt */
0283     gc_writel(priv, REG_GCISCR, status);
0284     spin_unlock(&priv->spinlock);
0285 
0286     return IRQ_HANDLED;
0287 }
0288 
0289 static int
0290 pxa3xx_gcu_wait_idle(struct pxa3xx_gcu_priv *priv)
0291 {
0292     int ret = 0;
0293 
0294     QDUMP("Waiting for idle...");
0295 
0296     /* Does not need to be atomic. There's a lock in user space,
0297      * but anyhow, this is just for statistics. */
0298     priv->shared->num_wait_idle++;
0299 
0300     while (priv->shared->hw_running) {
0301         int num = priv->shared->num_interrupts;
0302         u32 rbexhr = gc_readl(priv, REG_GCRBEXHR);
0303 
0304         ret = wait_event_interruptible_timeout(priv->wait_idle,
0305                     !priv->shared->hw_running, HZ*4);
0306 
0307         if (ret != 0)
0308             break;
0309 
0310         if (gc_readl(priv, REG_GCRBEXHR) == rbexhr &&
0311             priv->shared->num_interrupts == num) {
0312             QERROR("TIMEOUT");
0313             ret = -ETIMEDOUT;
0314             break;
0315         }
0316     }
0317 
0318     QDUMP("done");
0319 
0320     return ret;
0321 }
0322 
0323 static int
0324 pxa3xx_gcu_wait_free(struct pxa3xx_gcu_priv *priv)
0325 {
0326     int ret = 0;
0327 
0328     QDUMP("Waiting for free...");
0329 
0330     /* Does not need to be atomic. There's a lock in user space,
0331      * but anyhow, this is just for statistics. */
0332     priv->shared->num_wait_free++;
0333 
0334     while (!priv->free) {
0335         u32 rbexhr = gc_readl(priv, REG_GCRBEXHR);
0336 
0337         ret = wait_event_interruptible_timeout(priv->wait_free,
0338                                priv->free, HZ*4);
0339 
0340         if (ret < 0)
0341             break;
0342 
0343         if (ret > 0)
0344             continue;
0345 
0346         if (gc_readl(priv, REG_GCRBEXHR) == rbexhr) {
0347             QERROR("TIMEOUT");
0348             ret = -ETIMEDOUT;
0349             break;
0350         }
0351     }
0352 
0353     QDUMP("done");
0354 
0355     return ret;
0356 }
0357 
0358 /* Misc device layer */
0359 
0360 static inline struct pxa3xx_gcu_priv *to_pxa3xx_gcu_priv(struct file *file)
0361 {
0362     struct miscdevice *dev = file->private_data;
0363     return container_of(dev, struct pxa3xx_gcu_priv, misc_dev);
0364 }
0365 
0366 /*
0367  * provide an empty .open callback, so the core sets file->private_data
0368  * for us.
0369  */
0370 static int pxa3xx_gcu_open(struct inode *inode, struct file *file)
0371 {
0372     return 0;
0373 }
0374 
0375 static ssize_t
0376 pxa3xx_gcu_write(struct file *file, const char *buff,
0377          size_t count, loff_t *offp)
0378 {
0379     int ret;
0380     unsigned long flags;
0381     struct pxa3xx_gcu_batch *buffer;
0382     struct pxa3xx_gcu_priv *priv = to_pxa3xx_gcu_priv(file);
0383 
0384     size_t words = count / 4;
0385 
0386     /* Does not need to be atomic. There's a lock in user space,
0387      * but anyhow, this is just for statistics. */
0388     priv->shared->num_writes++;
0389     priv->shared->num_words += words;
0390 
0391     /* Last word reserved for batch buffer end command */
0392     if (words >= PXA3XX_GCU_BATCH_WORDS)
0393         return -E2BIG;
0394 
0395     /* Wait for a free buffer */
0396     if (!priv->free) {
0397         ret = pxa3xx_gcu_wait_free(priv);
0398         if (ret < 0)
0399             return ret;
0400     }
0401 
0402     /*
0403      * Get buffer from free list
0404      */
0405     spin_lock_irqsave(&priv->spinlock, flags);
0406     buffer = priv->free;
0407     priv->free = buffer->next;
0408     spin_unlock_irqrestore(&priv->spinlock, flags);
0409 
0410 
0411     /* Copy data from user into buffer */
0412     ret = copy_from_user(buffer->ptr, buff, words * 4);
0413     if (ret) {
0414         spin_lock_irqsave(&priv->spinlock, flags);
0415         buffer->next = priv->free;
0416         priv->free = buffer;
0417         spin_unlock_irqrestore(&priv->spinlock, flags);
0418         return -EFAULT;
0419     }
0420 
0421     buffer->length = words;
0422 
0423     /* Append batch buffer end command */
0424     buffer->ptr[words] = 0x01000000;
0425 
0426     /*
0427      * Add buffer to ready list
0428      */
0429     spin_lock_irqsave(&priv->spinlock, flags);
0430 
0431     buffer->next = NULL;
0432 
0433     if (priv->ready) {
0434         BUG_ON(priv->ready_last == NULL);
0435 
0436         priv->ready_last->next = buffer;
0437     } else
0438         priv->ready = buffer;
0439 
0440     priv->ready_last = buffer;
0441 
0442     if (!priv->shared->hw_running)
0443         run_ready(priv);
0444 
0445     spin_unlock_irqrestore(&priv->spinlock, flags);
0446 
0447     return words * 4;
0448 }
0449 
0450 
0451 static long
0452 pxa3xx_gcu_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
0453 {
0454     unsigned long flags;
0455     struct pxa3xx_gcu_priv *priv = to_pxa3xx_gcu_priv(file);
0456 
0457     switch (cmd) {
0458     case PXA3XX_GCU_IOCTL_RESET:
0459         spin_lock_irqsave(&priv->spinlock, flags);
0460         pxa3xx_gcu_reset(priv);
0461         spin_unlock_irqrestore(&priv->spinlock, flags);
0462         return 0;
0463 
0464     case PXA3XX_GCU_IOCTL_WAIT_IDLE:
0465         return pxa3xx_gcu_wait_idle(priv);
0466     }
0467 
0468     return -ENOSYS;
0469 }
0470 
0471 static int
0472 pxa3xx_gcu_mmap(struct file *file, struct vm_area_struct *vma)
0473 {
0474     unsigned int size = vma->vm_end - vma->vm_start;
0475     struct pxa3xx_gcu_priv *priv = to_pxa3xx_gcu_priv(file);
0476 
0477     switch (vma->vm_pgoff) {
0478     case 0:
0479         /* hand out the shared data area */
0480         if (size != SHARED_SIZE)
0481             return -EINVAL;
0482 
0483         return dma_mmap_coherent(priv->dev, vma,
0484             priv->shared, priv->shared_phys, size);
0485 
0486     case SHARED_SIZE >> PAGE_SHIFT:
0487         /* hand out the MMIO base for direct register access
0488          * from userspace */
0489         if (size != resource_size(priv->resource_mem))
0490             return -EINVAL;
0491 
0492         vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
0493 
0494         return io_remap_pfn_range(vma, vma->vm_start,
0495                 priv->resource_mem->start >> PAGE_SHIFT,
0496                 size, vma->vm_page_prot);
0497     }
0498 
0499     return -EINVAL;
0500 }
0501 
0502 
0503 #ifdef PXA3XX_GCU_DEBUG_TIMER
0504 static struct timer_list pxa3xx_gcu_debug_timer;
0505 static struct pxa3xx_gcu_priv *debug_timer_priv;
0506 
0507 static void pxa3xx_gcu_debug_timedout(struct timer_list *unused)
0508 {
0509     struct pxa3xx_gcu_priv *priv = debug_timer_priv;
0510 
0511     QERROR("Timer DUMP");
0512 
0513     mod_timer(&pxa3xx_gcu_debug_timer, jiffies + 5 * HZ);
0514 }
0515 
0516 static void pxa3xx_gcu_init_debug_timer(struct pxa3xx_gcu_priv *priv)
0517 {
0518     /* init the timer structure */
0519     debug_timer_priv = priv;
0520     timer_setup(&pxa3xx_gcu_debug_timer, pxa3xx_gcu_debug_timedout, 0);
0521     pxa3xx_gcu_debug_timedout(NULL);
0522 }
0523 #else
0524 static inline void pxa3xx_gcu_init_debug_timer(struct pxa3xx_gcu_priv *priv) {}
0525 #endif
0526 
0527 static int
0528 pxa3xx_gcu_add_buffer(struct device *dev,
0529               struct pxa3xx_gcu_priv *priv)
0530 {
0531     struct pxa3xx_gcu_batch *buffer;
0532 
0533     buffer = kzalloc(sizeof(struct pxa3xx_gcu_batch), GFP_KERNEL);
0534     if (!buffer)
0535         return -ENOMEM;
0536 
0537     buffer->ptr = dma_alloc_coherent(dev, PXA3XX_GCU_BATCH_WORDS * 4,
0538                      &buffer->phys, GFP_KERNEL);
0539     if (!buffer->ptr) {
0540         kfree(buffer);
0541         return -ENOMEM;
0542     }
0543 
0544     buffer->next = priv->free;
0545     priv->free = buffer;
0546 
0547     return 0;
0548 }
0549 
0550 static void
0551 pxa3xx_gcu_free_buffers(struct device *dev,
0552             struct pxa3xx_gcu_priv *priv)
0553 {
0554     struct pxa3xx_gcu_batch *next, *buffer = priv->free;
0555 
0556     while (buffer) {
0557         next = buffer->next;
0558 
0559         dma_free_coherent(dev, PXA3XX_GCU_BATCH_WORDS * 4,
0560                   buffer->ptr, buffer->phys);
0561 
0562         kfree(buffer);
0563         buffer = next;
0564     }
0565 
0566     priv->free = NULL;
0567 }
0568 
0569 static const struct file_operations pxa3xx_gcu_miscdev_fops = {
0570     .owner =        THIS_MODULE,
0571     .open =         pxa3xx_gcu_open,
0572     .write =        pxa3xx_gcu_write,
0573     .unlocked_ioctl =   pxa3xx_gcu_ioctl,
0574     .mmap =         pxa3xx_gcu_mmap,
0575 };
0576 
0577 static int pxa3xx_gcu_probe(struct platform_device *pdev)
0578 {
0579     int i, ret, irq;
0580     struct resource *r;
0581     struct pxa3xx_gcu_priv *priv;
0582     struct device *dev = &pdev->dev;
0583 
0584     priv = devm_kzalloc(dev, sizeof(struct pxa3xx_gcu_priv), GFP_KERNEL);
0585     if (!priv)
0586         return -ENOMEM;
0587 
0588     init_waitqueue_head(&priv->wait_idle);
0589     init_waitqueue_head(&priv->wait_free);
0590     spin_lock_init(&priv->spinlock);
0591 
0592     /* we allocate the misc device structure as part of our own allocation,
0593      * so we can get a pointer to our priv structure later on with
0594      * container_of(). This isn't really necessary as we have a fixed minor
0595      * number anyway, but this is to avoid statics. */
0596 
0597     priv->misc_dev.minor    = PXA3XX_GCU_MINOR,
0598     priv->misc_dev.name = DRV_NAME,
0599     priv->misc_dev.fops = &pxa3xx_gcu_miscdev_fops;
0600 
0601     /* handle IO resources */
0602     r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0603     priv->mmio_base = devm_ioremap_resource(dev, r);
0604     if (IS_ERR(priv->mmio_base))
0605         return PTR_ERR(priv->mmio_base);
0606 
0607     /* enable the clock */
0608     priv->clk = devm_clk_get(dev, NULL);
0609     if (IS_ERR(priv->clk))
0610         return dev_err_probe(dev, PTR_ERR(priv->clk), "failed to get clock\n");
0611 
0612     /* request the IRQ */
0613     irq = platform_get_irq(pdev, 0);
0614     if (irq < 0)
0615         return irq;
0616 
0617     ret = devm_request_irq(dev, irq, pxa3xx_gcu_handle_irq,
0618                    0, DRV_NAME, priv);
0619     if (ret < 0) {
0620         dev_err(dev, "request_irq failed\n");
0621         return ret;
0622     }
0623 
0624     /* allocate dma memory */
0625     priv->shared = dma_alloc_coherent(dev, SHARED_SIZE,
0626                       &priv->shared_phys, GFP_KERNEL);
0627     if (!priv->shared) {
0628         dev_err(dev, "failed to allocate DMA memory\n");
0629         return -ENOMEM;
0630     }
0631 
0632     /* register misc device */
0633     ret = misc_register(&priv->misc_dev);
0634     if (ret < 0) {
0635         dev_err(dev, "misc_register() for minor %d failed\n",
0636             PXA3XX_GCU_MINOR);
0637         goto err_free_dma;
0638     }
0639 
0640     ret = clk_prepare_enable(priv->clk);
0641     if (ret < 0) {
0642         dev_err(dev, "failed to enable clock\n");
0643         goto err_misc_deregister;
0644     }
0645 
0646     for (i = 0; i < 8; i++) {
0647         ret = pxa3xx_gcu_add_buffer(dev, priv);
0648         if (ret) {
0649             pxa3xx_gcu_free_buffers(dev, priv);
0650             dev_err(dev, "failed to allocate DMA memory\n");
0651             goto err_disable_clk;
0652         }
0653     }
0654 
0655     platform_set_drvdata(pdev, priv);
0656     priv->resource_mem = r;
0657     priv->dev = dev;
0658     pxa3xx_gcu_reset(priv);
0659     pxa3xx_gcu_init_debug_timer(priv);
0660 
0661     dev_info(dev, "registered @0x%p, DMA 0x%p (%d bytes), IRQ %d\n",
0662             (void *) r->start, (void *) priv->shared_phys,
0663             SHARED_SIZE, irq);
0664     return 0;
0665 
0666 err_disable_clk:
0667     clk_disable_unprepare(priv->clk);
0668 
0669 err_misc_deregister:
0670     misc_deregister(&priv->misc_dev);
0671 
0672 err_free_dma:
0673     dma_free_coherent(dev, SHARED_SIZE,
0674               priv->shared, priv->shared_phys);
0675 
0676     return ret;
0677 }
0678 
0679 static int pxa3xx_gcu_remove(struct platform_device *pdev)
0680 {
0681     struct pxa3xx_gcu_priv *priv = platform_get_drvdata(pdev);
0682     struct device *dev = &pdev->dev;
0683 
0684     pxa3xx_gcu_wait_idle(priv);
0685     misc_deregister(&priv->misc_dev);
0686     dma_free_coherent(dev, SHARED_SIZE, priv->shared, priv->shared_phys);
0687     clk_disable_unprepare(priv->clk);
0688     pxa3xx_gcu_free_buffers(dev, priv);
0689 
0690     return 0;
0691 }
0692 
0693 #ifdef CONFIG_OF
0694 static const struct of_device_id pxa3xx_gcu_of_match[] = {
0695     { .compatible = "marvell,pxa300-gcu", },
0696     { }
0697 };
0698 MODULE_DEVICE_TABLE(of, pxa3xx_gcu_of_match);
0699 #endif
0700 
0701 static struct platform_driver pxa3xx_gcu_driver = {
0702     .probe    = pxa3xx_gcu_probe,
0703     .remove  = pxa3xx_gcu_remove,
0704     .driver  = {
0705         .name   = DRV_NAME,
0706         .of_match_table = of_match_ptr(pxa3xx_gcu_of_match),
0707     },
0708 };
0709 
0710 module_platform_driver(pxa3xx_gcu_driver);
0711 
0712 MODULE_DESCRIPTION("PXA3xx graphics controller unit driver");
0713 MODULE_LICENSE("GPL");
0714 MODULE_ALIAS_MISCDEV(PXA3XX_GCU_MINOR);
0715 MODULE_AUTHOR("Janine Kropp <nin@directfb.org>, "
0716         "Denis Oliver Kropp <dok@directfb.org>, "
0717         "Daniel Mack <daniel@caiaq.de>");