linux/drivers/video/pxa3xx-gcu.c
<<
>>
Prefs
   1/*
   2 *  pxa3xx-gcu.c - Linux kernel module for PXA3xx graphics controllers
   3 *
   4 *  This driver needs a DirectFB counterpart in user space, communication
   5 *  is handled via mmap()ed memory areas and an ioctl.
   6 *
   7 *  Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
   8 *  Copyright (c) 2009 Janine Kropp <nin@directfb.org>
   9 *  Copyright (c) 2009 Denis Oliver Kropp <dok@directfb.org>
  10 *
  11 *  This program is free software; you can redistribute it and/or modify
  12 *  it under the terms of the GNU General Public License as published by
  13 *  the Free Software Foundation; either version 2 of the License, or
  14 *  (at your option) any later version.
  15 *
  16 *  This program is distributed in the hope that it will be useful,
  17 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  18 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19 *  GNU General Public License for more details.
  20 *
  21 *  You should have received a copy of the GNU General Public License
  22 *  along with this program; if not, write to the Free Software
  23 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  24 */
  25
  26/*
  27 * WARNING: This controller is attached to System Bus 2 of the PXA which
  28 * needs its arbiter to be enabled explicitly (CKENB & 1<<9).
  29 * There is currently no way to do this from Linux, so you need to teach
  30 * your bootloader for now.
  31 */
  32
  33#include <linux/module.h>
  34#include <linux/platform_device.h>
  35#include <linux/dma-mapping.h>
  36#include <linux/miscdevice.h>
  37#include <linux/interrupt.h>
  38#include <linux/spinlock.h>
  39#include <linux/uaccess.h>
  40#include <linux/ioctl.h>
  41#include <linux/delay.h>
  42#include <linux/sched.h>
  43#include <linux/slab.h>
  44#include <linux/clk.h>
  45#include <linux/fs.h>
  46#include <linux/io.h>
  47
  48#include "pxa3xx-gcu.h"
  49
  50#define DRV_NAME        "pxa3xx-gcu"
  51#define MISCDEV_MINOR   197
  52
  53#define REG_GCCR        0x00
  54#define GCCR_SYNC_CLR   (1 << 9)
  55#define GCCR_BP_RST     (1 << 8)
  56#define GCCR_ABORT      (1 << 6)
  57#define GCCR_STOP       (1 << 4)
  58
  59#define REG_GCISCR      0x04
  60#define REG_GCIECR      0x08
  61#define REG_GCRBBR      0x20
  62#define REG_GCRBLR      0x24
  63#define REG_GCRBHR      0x28
  64#define REG_GCRBTR      0x2C
  65#define REG_GCRBEXHR    0x30
  66
  67#define IE_EOB          (1 << 0)
  68#define IE_EEOB         (1 << 5)
  69#define IE_ALL          0xff
  70
  71#define SHARED_SIZE     PAGE_ALIGN(sizeof(struct pxa3xx_gcu_shared))
  72
  73/* #define PXA3XX_GCU_DEBUG */
  74/* #define PXA3XX_GCU_DEBUG_TIMER */
  75
  76#ifdef PXA3XX_GCU_DEBUG
  77#define QDUMP(msg)                                      \
  78        do {                                            \
  79                QPRINT(priv, KERN_DEBUG, msg);          \
  80        } while (0)
  81#else
  82#define QDUMP(msg)      do {} while (0)
  83#endif
  84
  85#define QERROR(msg)                                     \
  86        do {                                            \
  87                QPRINT(priv, KERN_ERR, msg);            \
  88        } while (0)
  89
  90struct pxa3xx_gcu_batch {
  91        struct pxa3xx_gcu_batch *next;
  92        u32                     *ptr;
  93        dma_addr_t               phys;
  94        unsigned long            length;
  95};
  96
  97struct pxa3xx_gcu_priv {
  98        void __iomem             *mmio_base;
  99        struct clk               *clk;
 100        struct pxa3xx_gcu_shared *shared;
 101        dma_addr_t                shared_phys;
 102        struct resource          *resource_mem;
 103        struct miscdevice         misc_dev;
 104        wait_queue_head_t         wait_idle;
 105        wait_queue_head_t         wait_free;
 106        spinlock_t                spinlock;
 107        struct timeval            base_time;
 108
 109        struct pxa3xx_gcu_batch *free;
 110
 111        struct pxa3xx_gcu_batch *ready;
 112        struct pxa3xx_gcu_batch *ready_last;
 113        struct pxa3xx_gcu_batch *running;
 114};
 115
 116static inline unsigned long
 117gc_readl(struct pxa3xx_gcu_priv *priv, unsigned int off)
 118{
 119        return __raw_readl(priv->mmio_base + off);
 120}
 121
 122static inline void
 123gc_writel(struct pxa3xx_gcu_priv *priv, unsigned int off, unsigned long val)
 124{
 125        __raw_writel(val, priv->mmio_base + off);
 126}
 127
 128#define QPRINT(priv, level, msg)                                        \
 129        do {                                                            \
 130                struct timeval tv;                                      \
 131                struct pxa3xx_gcu_shared *shared = priv->shared;        \
 132                u32 base = gc_readl(priv, REG_GCRBBR);                  \
 133                                                                        \
 134                do_gettimeofday(&tv);                                   \
 135                                                                        \
 136                printk(level "%ld.%03ld.%03ld - %-17s: %-21s (%s, "     \
 137                        "STATUS "                                       \
 138                        "0x%02lx, B 0x%08lx [%ld], E %5ld, H %5ld, "    \
 139                        "T %5ld)\n",                                    \
 140                        tv.tv_sec - priv->base_time.tv_sec,             \
 141                        tv.tv_usec / 1000, tv.tv_usec % 1000,           \
 142                        __func__, msg,                                  \
 143                        shared->hw_running ? "running" : "   idle",     \
 144                        gc_readl(priv, REG_GCISCR),                     \
 145                        gc_readl(priv, REG_GCRBBR),                     \
 146                        gc_readl(priv, REG_GCRBLR),                     \
 147                        (gc_readl(priv, REG_GCRBEXHR) - base) / 4,      \
 148                        (gc_readl(priv, REG_GCRBHR) - base) / 4,        \
 149                        (gc_readl(priv, REG_GCRBTR) - base) / 4);       \
 150        } while (0)
 151
 152static void
 153pxa3xx_gcu_reset(struct pxa3xx_gcu_priv *priv)
 154{
 155        QDUMP("RESET");
 156
 157        /* disable interrupts */
 158        gc_writel(priv, REG_GCIECR, 0);
 159
 160        /* reset hardware */
 161        gc_writel(priv, REG_GCCR, GCCR_ABORT);
 162        gc_writel(priv, REG_GCCR, 0);
 163
 164        memset(priv->shared, 0, SHARED_SIZE);
 165        priv->shared->buffer_phys = priv->shared_phys;
 166        priv->shared->magic = PXA3XX_GCU_SHARED_MAGIC;
 167
 168        do_gettimeofday(&priv->base_time);
 169
 170        /* set up the ring buffer pointers */
 171        gc_writel(priv, REG_GCRBLR, 0);
 172        gc_writel(priv, REG_GCRBBR, priv->shared_phys);
 173        gc_writel(priv, REG_GCRBTR, priv->shared_phys);
 174
 175        /* enable all IRQs except EOB */
 176        gc_writel(priv, REG_GCIECR, IE_ALL & ~IE_EOB);
 177}
 178
 179static void
 180dump_whole_state(struct pxa3xx_gcu_priv *priv)
 181{
 182        struct pxa3xx_gcu_shared *sh = priv->shared;
 183        u32 base = gc_readl(priv, REG_GCRBBR);
 184
 185        QDUMP("DUMP");
 186
 187        printk(KERN_DEBUG "== PXA3XX-GCU DUMP ==\n"
 188                "%s, STATUS 0x%02lx, B 0x%08lx [%ld], E %5ld, H %5ld, T %5ld\n",
 189                sh->hw_running ? "running" : "idle   ",
 190                gc_readl(priv, REG_GCISCR),
 191                gc_readl(priv, REG_GCRBBR),
 192                gc_readl(priv, REG_GCRBLR),
 193                (gc_readl(priv, REG_GCRBEXHR) - base) / 4,
 194                (gc_readl(priv, REG_GCRBHR) - base) / 4,
 195                (gc_readl(priv, REG_GCRBTR) - base) / 4);
 196}
 197
 198static void
 199flush_running(struct pxa3xx_gcu_priv *priv)
 200{
 201        struct pxa3xx_gcu_batch *running = priv->running;
 202        struct pxa3xx_gcu_batch *next;
 203
 204        while (running) {
 205                next = running->next;
 206                running->next = priv->free;
 207                priv->free = running;
 208                running = next;
 209        }
 210
 211        priv->running = NULL;
 212}
 213
 214static void
 215run_ready(struct pxa3xx_gcu_priv *priv)
 216{
 217        unsigned int num = 0;
 218        struct pxa3xx_gcu_shared *shared = priv->shared;
 219        struct pxa3xx_gcu_batch *ready = priv->ready;
 220
 221        QDUMP("Start");
 222
 223        BUG_ON(!ready);
 224
 225        shared->buffer[num++] = 0x05000000;
 226
 227        while (ready) {
 228                shared->buffer[num++] = 0x00000001;
 229                shared->buffer[num++] = ready->phys;
 230                ready = ready->next;
 231        }
 232
 233        shared->buffer[num++] = 0x05000000;
 234        priv->running = priv->ready;
 235        priv->ready = priv->ready_last = NULL;
 236        gc_writel(priv, REG_GCRBLR, 0);
 237        shared->hw_running = 1;
 238
 239        /* ring base address */
 240        gc_writel(priv, REG_GCRBBR, shared->buffer_phys);
 241
 242        /* ring tail address */
 243        gc_writel(priv, REG_GCRBTR, shared->buffer_phys + num * 4);
 244
 245        /* ring length */
 246        gc_writel(priv, REG_GCRBLR, ((num + 63) & ~63) * 4);
 247}
 248
 249static irqreturn_t
 250pxa3xx_gcu_handle_irq(int irq, void *ctx)
 251{
 252        struct pxa3xx_gcu_priv *priv = ctx;
 253        struct pxa3xx_gcu_shared *shared = priv->shared;
 254        u32 status = gc_readl(priv, REG_GCISCR) & IE_ALL;
 255
 256        QDUMP("-Interrupt");
 257
 258        if (!status)
 259                return IRQ_NONE;
 260
 261        spin_lock(&priv->spinlock);
 262        shared->num_interrupts++;
 263
 264        if (status & IE_EEOB) {
 265                QDUMP(" [EEOB]");
 266
 267                flush_running(priv);
 268                wake_up_all(&priv->wait_free);
 269
 270                if (priv->ready) {
 271                        run_ready(priv);
 272                } else {
 273                        /* There is no more data prepared by the userspace.
 274                         * Set hw_running = 0 and wait for the next userspace
 275                         * kick-off */
 276                        shared->num_idle++;
 277                        shared->hw_running = 0;
 278
 279                        QDUMP(" '-> Idle.");
 280
 281                        /* set ring buffer length to zero */
 282                        gc_writel(priv, REG_GCRBLR, 0);
 283
 284                        wake_up_all(&priv->wait_idle);
 285                }
 286
 287                shared->num_done++;
 288        } else {
 289                QERROR(" [???]");
 290                dump_whole_state(priv);
 291        }
 292
 293        /* Clear the interrupt */
 294        gc_writel(priv, REG_GCISCR, status);
 295        spin_unlock(&priv->spinlock);
 296
 297        return IRQ_HANDLED;
 298}
 299
 300static int
 301pxa3xx_gcu_wait_idle(struct pxa3xx_gcu_priv *priv)
 302{
 303        int ret = 0;
 304
 305        QDUMP("Waiting for idle...");
 306
 307        /* Does not need to be atomic. There's a lock in user space,
 308         * but anyhow, this is just for statistics. */
 309        priv->shared->num_wait_idle++;
 310
 311        while (priv->shared->hw_running) {
 312                int num = priv->shared->num_interrupts;
 313                u32 rbexhr = gc_readl(priv, REG_GCRBEXHR);
 314
 315                ret = wait_event_interruptible_timeout(priv->wait_idle,
 316                                        !priv->shared->hw_running, HZ*4);
 317
 318                if (ret != 0)
 319                        break;
 320
 321                if (gc_readl(priv, REG_GCRBEXHR) == rbexhr &&
 322                    priv->shared->num_interrupts == num) {
 323                        QERROR("TIMEOUT");
 324                        ret = -ETIMEDOUT;
 325                        break;
 326                }
 327        }
 328
 329        QDUMP("done");
 330
 331        return ret;
 332}
 333
 334static int
 335pxa3xx_gcu_wait_free(struct pxa3xx_gcu_priv *priv)
 336{
 337        int ret = 0;
 338
 339        QDUMP("Waiting for free...");
 340
 341        /* Does not need to be atomic. There's a lock in user space,
 342         * but anyhow, this is just for statistics. */
 343        priv->shared->num_wait_free++;
 344
 345        while (!priv->free) {
 346                u32 rbexhr = gc_readl(priv, REG_GCRBEXHR);
 347
 348                ret = wait_event_interruptible_timeout(priv->wait_free,
 349                                                       priv->free, HZ*4);
 350
 351                if (ret < 0)
 352                        break;
 353
 354                if (ret > 0)
 355                        continue;
 356
 357                if (gc_readl(priv, REG_GCRBEXHR) == rbexhr) {
 358                        QERROR("TIMEOUT");
 359                        ret = -ETIMEDOUT;
 360                        break;
 361                }
 362        }
 363
 364        QDUMP("done");
 365
 366        return ret;
 367}
 368
 369/* Misc device layer */
 370
 371static inline struct pxa3xx_gcu_priv *file_dev(struct file *file)
 372{
 373        struct miscdevice *dev = file->private_data;
 374        return container_of(dev, struct pxa3xx_gcu_priv, misc_dev);
 375}
 376
 377static ssize_t
 378pxa3xx_gcu_misc_write(struct file *file, const char *buff,
 379                      size_t count, loff_t *offp)
 380{
 381        int ret;
 382        unsigned long flags;
 383        struct pxa3xx_gcu_batch *buffer;
 384        struct pxa3xx_gcu_priv *priv = file_dev(file);
 385
 386        int words = count / 4;
 387
 388        /* Does not need to be atomic. There's a lock in user space,
 389         * but anyhow, this is just for statistics. */
 390        priv->shared->num_writes++;
 391
 392        priv->shared->num_words += words;
 393
 394        /* Last word reserved for batch buffer end command */
 395        if (words >= PXA3XX_GCU_BATCH_WORDS)
 396                return -E2BIG;
 397
 398        /* Wait for a free buffer */
 399        if (!priv->free) {
 400                ret = pxa3xx_gcu_wait_free(priv);
 401                if (ret < 0)
 402                        return ret;
 403        }
 404
 405        /*
 406         * Get buffer from free list
 407         */
 408        spin_lock_irqsave(&priv->spinlock, flags);
 409
 410        buffer = priv->free;
 411        priv->free = buffer->next;
 412
 413        spin_unlock_irqrestore(&priv->spinlock, flags);
 414
 415
 416        /* Copy data from user into buffer */
 417        ret = copy_from_user(buffer->ptr, buff, words * 4);
 418        if (ret) {
 419                spin_lock_irqsave(&priv->spinlock, flags);
 420                buffer->next = priv->free;
 421                priv->free = buffer;
 422                spin_unlock_irqrestore(&priv->spinlock, flags);
 423                return -EFAULT;
 424        }
 425
 426        buffer->length = words;
 427
 428        /* Append batch buffer end command */
 429        buffer->ptr[words] = 0x01000000;
 430
 431        /*
 432         * Add buffer to ready list
 433         */
 434        spin_lock_irqsave(&priv->spinlock, flags);
 435
 436        buffer->next = NULL;
 437
 438        if (priv->ready) {
 439                BUG_ON(priv->ready_last == NULL);
 440
 441                priv->ready_last->next = buffer;
 442        } else
 443                priv->ready = buffer;
 444
 445        priv->ready_last = buffer;
 446
 447        if (!priv->shared->hw_running)
 448                run_ready(priv);
 449
 450        spin_unlock_irqrestore(&priv->spinlock, flags);
 451
 452        return words * 4;
 453}
 454
 455
 456static long
 457pxa3xx_gcu_misc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 458{
 459        unsigned long flags;
 460        struct pxa3xx_gcu_priv *priv = file_dev(file);
 461
 462        switch (cmd) {
 463        case PXA3XX_GCU_IOCTL_RESET:
 464                spin_lock_irqsave(&priv->spinlock, flags);
 465                pxa3xx_gcu_reset(priv);
 466                spin_unlock_irqrestore(&priv->spinlock, flags);
 467                return 0;
 468
 469        case PXA3XX_GCU_IOCTL_WAIT_IDLE:
 470                return pxa3xx_gcu_wait_idle(priv);
 471        }
 472
 473        return -ENOSYS;
 474}
 475
 476static int
 477pxa3xx_gcu_misc_mmap(struct file *file, struct vm_area_struct *vma)
 478{
 479        unsigned int size = vma->vm_end - vma->vm_start;
 480        struct pxa3xx_gcu_priv *priv = file_dev(file);
 481
 482        switch (vma->vm_pgoff) {
 483        case 0:
 484                /* hand out the shared data area */
 485                if (size != SHARED_SIZE)
 486                        return -EINVAL;
 487
 488                return dma_mmap_coherent(NULL, vma,
 489                        priv->shared, priv->shared_phys, size);
 490
 491        case SHARED_SIZE >> PAGE_SHIFT:
 492                /* hand out the MMIO base for direct register access
 493                 * from userspace */
 494                if (size != resource_size(priv->resource_mem))
 495                        return -EINVAL;
 496
 497                vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 498
 499                return io_remap_pfn_range(vma, vma->vm_start,
 500                                priv->resource_mem->start >> PAGE_SHIFT,
 501                                size, vma->vm_page_prot);
 502        }
 503
 504        return -EINVAL;
 505}
 506
 507
 508#ifdef PXA3XX_GCU_DEBUG_TIMER
 509static struct timer_list pxa3xx_gcu_debug_timer;
 510
 511static void pxa3xx_gcu_debug_timedout(unsigned long ptr)
 512{
 513        struct pxa3xx_gcu_priv *priv = (struct pxa3xx_gcu_priv *) ptr;
 514
 515        QERROR("Timer DUMP");
 516
 517        /* init the timer structure */
 518        init_timer(&pxa3xx_gcu_debug_timer);
 519        pxa3xx_gcu_debug_timer.function = pxa3xx_gcu_debug_timedout;
 520        pxa3xx_gcu_debug_timer.data = ptr;
 521        pxa3xx_gcu_debug_timer.expires = jiffies + 5*HZ; /* one second */
 522
 523        add_timer(&pxa3xx_gcu_debug_timer);
 524}
 525
 526static void pxa3xx_gcu_init_debug_timer(void)
 527{
 528        pxa3xx_gcu_debug_timedout((unsigned long) &pxa3xx_gcu_debug_timer);
 529}
 530#else
 531static inline void pxa3xx_gcu_init_debug_timer(void) {}
 532#endif
 533
 534static int
 535add_buffer(struct platform_device *dev,
 536           struct pxa3xx_gcu_priv *priv)
 537{
 538        struct pxa3xx_gcu_batch *buffer;
 539
 540        buffer = kzalloc(sizeof(struct pxa3xx_gcu_batch), GFP_KERNEL);
 541        if (!buffer)
 542                return -ENOMEM;
 543
 544        buffer->ptr = dma_alloc_coherent(&dev->dev, PXA3XX_GCU_BATCH_WORDS * 4,
 545                                         &buffer->phys, GFP_KERNEL);
 546        if (!buffer->ptr) {
 547                kfree(buffer);
 548                return -ENOMEM;
 549        }
 550
 551        buffer->next = priv->free;
 552
 553        priv->free = buffer;
 554
 555        return 0;
 556}
 557
 558static void
 559free_buffers(struct platform_device *dev,
 560             struct pxa3xx_gcu_priv *priv)
 561{
 562        struct pxa3xx_gcu_batch *next, *buffer = priv->free;
 563
 564        while (buffer) {
 565                next = buffer->next;
 566
 567                dma_free_coherent(&dev->dev, PXA3XX_GCU_BATCH_WORDS * 4,
 568                                  buffer->ptr, buffer->phys);
 569
 570                kfree(buffer);
 571
 572                buffer = next;
 573        }
 574
 575        priv->free = NULL;
 576}
 577
 578static const struct file_operations misc_fops = {
 579        .owner  = THIS_MODULE,
 580        .write  = pxa3xx_gcu_misc_write,
 581        .unlocked_ioctl = pxa3xx_gcu_misc_ioctl,
 582        .mmap   = pxa3xx_gcu_misc_mmap
 583};
 584
 585static int pxa3xx_gcu_probe(struct platform_device *dev)
 586{
 587        int i, ret, irq;
 588        struct resource *r;
 589        struct pxa3xx_gcu_priv *priv;
 590
 591        priv = kzalloc(sizeof(struct pxa3xx_gcu_priv), GFP_KERNEL);
 592        if (!priv)
 593                return -ENOMEM;
 594
 595        for (i = 0; i < 8; i++) {
 596                ret = add_buffer(dev, priv);
 597                if (ret) {
 598                        dev_err(&dev->dev, "failed to allocate DMA memory\n");
 599                        goto err_free_priv;
 600                }
 601        }
 602
 603        init_waitqueue_head(&priv->wait_idle);
 604        init_waitqueue_head(&priv->wait_free);
 605        spin_lock_init(&priv->spinlock);
 606
 607        /* we allocate the misc device structure as part of our own allocation,
 608         * so we can get a pointer to our priv structure later on with
 609         * container_of(). This isn't really necessary as we have a fixed minor
 610         * number anyway, but this is to avoid statics. */
 611
 612        priv->misc_dev.minor    = MISCDEV_MINOR,
 613        priv->misc_dev.name     = DRV_NAME,
 614        priv->misc_dev.fops     = &misc_fops,
 615
 616        /* register misc device */
 617        ret = misc_register(&priv->misc_dev);
 618        if (ret < 0) {
 619                dev_err(&dev->dev, "misc_register() for minor %d failed\n",
 620                        MISCDEV_MINOR);
 621                goto err_free_priv;
 622        }
 623
 624        /* handle IO resources */
 625        r = platform_get_resource(dev, IORESOURCE_MEM, 0);
 626        if (r == NULL) {
 627                dev_err(&dev->dev, "no I/O memory resource defined\n");
 628                ret = -ENODEV;
 629                goto err_misc_deregister;
 630        }
 631
 632        if (!request_mem_region(r->start, resource_size(r), dev->name)) {
 633                dev_err(&dev->dev, "failed to request I/O memory\n");
 634                ret = -EBUSY;
 635                goto err_misc_deregister;
 636        }
 637
 638        priv->mmio_base = ioremap_nocache(r->start, resource_size(r));
 639        if (!priv->mmio_base) {
 640                dev_err(&dev->dev, "failed to map I/O memory\n");
 641                ret = -EBUSY;
 642                goto err_free_mem_region;
 643        }
 644
 645        /* allocate dma memory */
 646        priv->shared = dma_alloc_coherent(&dev->dev, SHARED_SIZE,
 647                                          &priv->shared_phys, GFP_KERNEL);
 648
 649        if (!priv->shared) {
 650                dev_err(&dev->dev, "failed to allocate DMA memory\n");
 651                ret = -ENOMEM;
 652                goto err_free_io;
 653        }
 654
 655        /* enable the clock */
 656        priv->clk = clk_get(&dev->dev, NULL);
 657        if (IS_ERR(priv->clk)) {
 658                dev_err(&dev->dev, "failed to get clock\n");
 659                ret = -ENODEV;
 660                goto err_free_dma;
 661        }
 662
 663        ret = clk_enable(priv->clk);
 664        if (ret < 0) {
 665                dev_err(&dev->dev, "failed to enable clock\n");
 666                goto err_put_clk;
 667        }
 668
 669        /* request the IRQ */
 670        irq = platform_get_irq(dev, 0);
 671        if (irq < 0) {
 672                dev_err(&dev->dev, "no IRQ defined\n");
 673                ret = -ENODEV;
 674                goto err_put_clk;
 675        }
 676
 677        ret = request_irq(irq, pxa3xx_gcu_handle_irq,
 678                          0, DRV_NAME, priv);
 679        if (ret) {
 680                dev_err(&dev->dev, "request_irq failed\n");
 681                ret = -EBUSY;
 682                goto err_put_clk;
 683        }
 684
 685        platform_set_drvdata(dev, priv);
 686        priv->resource_mem = r;
 687        pxa3xx_gcu_reset(priv);
 688        pxa3xx_gcu_init_debug_timer();
 689
 690        dev_info(&dev->dev, "registered @0x%p, DMA 0x%p (%d bytes), IRQ %d\n",
 691                        (void *) r->start, (void *) priv->shared_phys,
 692                        SHARED_SIZE, irq);
 693        return 0;
 694
 695err_put_clk:
 696        clk_disable(priv->clk);
 697        clk_put(priv->clk);
 698
 699err_free_dma:
 700        dma_free_coherent(&dev->dev, SHARED_SIZE,
 701                        priv->shared, priv->shared_phys);
 702
 703err_free_io:
 704        iounmap(priv->mmio_base);
 705
 706err_free_mem_region:
 707        release_mem_region(r->start, resource_size(r));
 708
 709err_misc_deregister:
 710        misc_deregister(&priv->misc_dev);
 711
 712err_free_priv:
 713        free_buffers(dev, priv);
 714        kfree(priv);
 715        return ret;
 716}
 717
 718static int pxa3xx_gcu_remove(struct platform_device *dev)
 719{
 720        struct pxa3xx_gcu_priv *priv = platform_get_drvdata(dev);
 721        struct resource *r = priv->resource_mem;
 722
 723        pxa3xx_gcu_wait_idle(priv);
 724
 725        misc_deregister(&priv->misc_dev);
 726        dma_free_coherent(&dev->dev, SHARED_SIZE,
 727                        priv->shared, priv->shared_phys);
 728        iounmap(priv->mmio_base);
 729        release_mem_region(r->start, resource_size(r));
 730        clk_disable(priv->clk);
 731        free_buffers(dev, priv);
 732        kfree(priv);
 733
 734        return 0;
 735}
 736
 737static struct platform_driver pxa3xx_gcu_driver = {
 738        .probe    = pxa3xx_gcu_probe,
 739        .remove  = pxa3xx_gcu_remove,
 740        .driver  = {
 741                .owner  = THIS_MODULE,
 742                .name   = DRV_NAME,
 743        },
 744};
 745
 746module_platform_driver(pxa3xx_gcu_driver);
 747
 748MODULE_DESCRIPTION("PXA3xx graphics controller unit driver");
 749MODULE_LICENSE("GPL");
 750MODULE_ALIAS_MISCDEV(MISCDEV_MINOR);
 751MODULE_AUTHOR("Janine Kropp <nin@directfb.org>, "
 752                "Denis Oliver Kropp <dok@directfb.org>, "
 753                "Daniel Mack <daniel@caiaq.de>");
 754
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.