diff options
Diffstat (limited to 'drivers/video/pxa3xx-gcu.c')
-rw-r--r-- | drivers/video/pxa3xx-gcu.c | 191 |
1 files changed, 81 insertions, 110 deletions
diff --git a/drivers/video/pxa3xx-gcu.c b/drivers/video/pxa3xx-gcu.c index ad382b3396cd..417f9a27eb7d 100644 --- a/drivers/video/pxa3xx-gcu.c +++ b/drivers/video/pxa3xx-gcu.c | |||
@@ -107,7 +107,6 @@ struct pxa3xx_gcu_priv { | |||
107 | struct timeval base_time; | 107 | struct timeval base_time; |
108 | 108 | ||
109 | struct pxa3xx_gcu_batch *free; | 109 | struct pxa3xx_gcu_batch *free; |
110 | |||
111 | struct pxa3xx_gcu_batch *ready; | 110 | struct pxa3xx_gcu_batch *ready; |
112 | struct pxa3xx_gcu_batch *ready_last; | 111 | struct pxa3xx_gcu_batch *ready_last; |
113 | struct pxa3xx_gcu_batch *running; | 112 | struct pxa3xx_gcu_batch *running; |
@@ -368,27 +367,35 @@ pxa3xx_gcu_wait_free(struct pxa3xx_gcu_priv *priv) | |||
368 | 367 | ||
369 | /* Misc device layer */ | 368 | /* Misc device layer */ |
370 | 369 | ||
371 | static inline struct pxa3xx_gcu_priv *file_dev(struct file *file) | 370 | static inline struct pxa3xx_gcu_priv *to_pxa3xx_gcu_priv(struct file *file) |
372 | { | 371 | { |
373 | struct miscdevice *dev = file->private_data; | 372 | struct miscdevice *dev = file->private_data; |
374 | return container_of(dev, struct pxa3xx_gcu_priv, misc_dev); | 373 | return container_of(dev, struct pxa3xx_gcu_priv, misc_dev); |
375 | } | 374 | } |
376 | 375 | ||
376 | /* | ||
377 | * provide an empty .open callback, so the core sets file->private_data | ||
378 | * for us. | ||
379 | */ | ||
380 | static int pxa3xx_gcu_open(struct inode *inode, struct file *file) | ||
381 | { | ||
382 | return 0; | ||
383 | } | ||
384 | |||
377 | static ssize_t | 385 | static ssize_t |
378 | pxa3xx_gcu_misc_write(struct file *file, const char *buff, | 386 | pxa3xx_gcu_write(struct file *file, const char *buff, |
379 | size_t count, loff_t *offp) | 387 | size_t count, loff_t *offp) |
380 | { | 388 | { |
381 | int ret; | 389 | int ret; |
382 | unsigned long flags; | 390 | unsigned long flags; |
383 | struct pxa3xx_gcu_batch *buffer; | 391 | struct pxa3xx_gcu_batch *buffer; |
384 | struct pxa3xx_gcu_priv *priv = file_dev(file); | 392 | struct pxa3xx_gcu_priv *priv = to_pxa3xx_gcu_priv(file); |
385 | 393 | ||
386 | int words = count / 4; | 394 | int words = count / 4; |
387 | 395 | ||
388 | /* Does not need to be atomic. There's a lock in user space, | 396 | /* Does not need to be atomic. There's a lock in user space, |
389 | * but anyhow, this is just for statistics. */ | 397 | * but anyhow, this is just for statistics. */ |
390 | priv->shared->num_writes++; | 398 | priv->shared->num_writes++; |
391 | |||
392 | priv->shared->num_words += words; | 399 | priv->shared->num_words += words; |
393 | 400 | ||
394 | /* Last word reserved for batch buffer end command */ | 401 | /* Last word reserved for batch buffer end command */ |
@@ -406,10 +413,8 @@ pxa3xx_gcu_misc_write(struct file *file, const char *buff, | |||
406 | * Get buffer from free list | 413 | * Get buffer from free list |
407 | */ | 414 | */ |
408 | spin_lock_irqsave(&priv->spinlock, flags); | 415 | spin_lock_irqsave(&priv->spinlock, flags); |
409 | |||
410 | buffer = priv->free; | 416 | buffer = priv->free; |
411 | priv->free = buffer->next; | 417 | priv->free = buffer->next; |
412 | |||
413 | spin_unlock_irqrestore(&priv->spinlock, flags); | 418 | spin_unlock_irqrestore(&priv->spinlock, flags); |
414 | 419 | ||
415 | 420 | ||
@@ -454,10 +459,10 @@ pxa3xx_gcu_misc_write(struct file *file, const char *buff, | |||
454 | 459 | ||
455 | 460 | ||
456 | static long | 461 | static long |
457 | pxa3xx_gcu_misc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | 462 | pxa3xx_gcu_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
458 | { | 463 | { |
459 | unsigned long flags; | 464 | unsigned long flags; |
460 | struct pxa3xx_gcu_priv *priv = file_dev(file); | 465 | struct pxa3xx_gcu_priv *priv = to_pxa3xx_gcu_priv(file); |
461 | 466 | ||
462 | switch (cmd) { | 467 | switch (cmd) { |
463 | case PXA3XX_GCU_IOCTL_RESET: | 468 | case PXA3XX_GCU_IOCTL_RESET: |
@@ -474,10 +479,10 @@ pxa3xx_gcu_misc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
474 | } | 479 | } |
475 | 480 | ||
476 | static int | 481 | static int |
477 | pxa3xx_gcu_misc_mmap(struct file *file, struct vm_area_struct *vma) | 482 | pxa3xx_gcu_mmap(struct file *file, struct vm_area_struct *vma) |
478 | { | 483 | { |
479 | unsigned int size = vma->vm_end - vma->vm_start; | 484 | unsigned int size = vma->vm_end - vma->vm_start; |
480 | struct pxa3xx_gcu_priv *priv = file_dev(file); | 485 | struct pxa3xx_gcu_priv *priv = to_pxa3xx_gcu_priv(file); |
481 | 486 | ||
482 | switch (vma->vm_pgoff) { | 487 | switch (vma->vm_pgoff) { |
483 | case 0: | 488 | case 0: |
@@ -532,8 +537,8 @@ static inline void pxa3xx_gcu_init_debug_timer(void) {} | |||
532 | #endif | 537 | #endif |
533 | 538 | ||
534 | static int | 539 | static int |
535 | add_buffer(struct platform_device *dev, | 540 | pxa3xx_gcu_add_buffer(struct device *dev, |
536 | struct pxa3xx_gcu_priv *priv) | 541 | struct pxa3xx_gcu_priv *priv) |
537 | { | 542 | { |
538 | struct pxa3xx_gcu_batch *buffer; | 543 | struct pxa3xx_gcu_batch *buffer; |
539 | 544 | ||
@@ -541,7 +546,7 @@ add_buffer(struct platform_device *dev, | |||
541 | if (!buffer) | 546 | if (!buffer) |
542 | return -ENOMEM; | 547 | return -ENOMEM; |
543 | 548 | ||
544 | buffer->ptr = dma_alloc_coherent(&dev->dev, PXA3XX_GCU_BATCH_WORDS * 4, | 549 | buffer->ptr = dma_alloc_coherent(dev, PXA3XX_GCU_BATCH_WORDS * 4, |
545 | &buffer->phys, GFP_KERNEL); | 550 | &buffer->phys, GFP_KERNEL); |
546 | if (!buffer->ptr) { | 551 | if (!buffer->ptr) { |
547 | kfree(buffer); | 552 | kfree(buffer); |
@@ -549,57 +554,49 @@ add_buffer(struct platform_device *dev, | |||
549 | } | 554 | } |
550 | 555 | ||
551 | buffer->next = priv->free; | 556 | buffer->next = priv->free; |
552 | |||
553 | priv->free = buffer; | 557 | priv->free = buffer; |
554 | 558 | ||
555 | return 0; | 559 | return 0; |
556 | } | 560 | } |
557 | 561 | ||
558 | static void | 562 | static void |
559 | free_buffers(struct platform_device *dev, | 563 | pxa3xx_gcu_free_buffers(struct device *dev, |
560 | struct pxa3xx_gcu_priv *priv) | 564 | struct pxa3xx_gcu_priv *priv) |
561 | { | 565 | { |
562 | struct pxa3xx_gcu_batch *next, *buffer = priv->free; | 566 | struct pxa3xx_gcu_batch *next, *buffer = priv->free; |
563 | 567 | ||
564 | while (buffer) { | 568 | while (buffer) { |
565 | next = buffer->next; | 569 | next = buffer->next; |
566 | 570 | ||
567 | dma_free_coherent(&dev->dev, PXA3XX_GCU_BATCH_WORDS * 4, | 571 | dma_free_coherent(dev, PXA3XX_GCU_BATCH_WORDS * 4, |
568 | buffer->ptr, buffer->phys); | 572 | buffer->ptr, buffer->phys); |
569 | 573 | ||
570 | kfree(buffer); | 574 | kfree(buffer); |
571 | |||
572 | buffer = next; | 575 | buffer = next; |
573 | } | 576 | } |
574 | 577 | ||
575 | priv->free = NULL; | 578 | priv->free = NULL; |
576 | } | 579 | } |
577 | 580 | ||
578 | static const struct file_operations misc_fops = { | 581 | static const struct file_operations pxa3xx_gcu_miscdev_fops = { |
579 | .owner = THIS_MODULE, | 582 | .owner = THIS_MODULE, |
580 | .write = pxa3xx_gcu_misc_write, | 583 | .open = pxa3xx_gcu_open, |
581 | .unlocked_ioctl = pxa3xx_gcu_misc_ioctl, | 584 | .write = pxa3xx_gcu_write, |
582 | .mmap = pxa3xx_gcu_misc_mmap | 585 | .unlocked_ioctl = pxa3xx_gcu_ioctl, |
586 | .mmap = pxa3xx_gcu_mmap, | ||
583 | }; | 587 | }; |
584 | 588 | ||
585 | static int pxa3xx_gcu_probe(struct platform_device *dev) | 589 | static int pxa3xx_gcu_probe(struct platform_device *pdev) |
586 | { | 590 | { |
587 | int i, ret, irq; | 591 | int i, ret, irq; |
588 | struct resource *r; | 592 | struct resource *r; |
589 | struct pxa3xx_gcu_priv *priv; | 593 | struct pxa3xx_gcu_priv *priv; |
594 | struct device *dev = &pdev->dev; | ||
590 | 595 | ||
591 | priv = kzalloc(sizeof(struct pxa3xx_gcu_priv), GFP_KERNEL); | 596 | priv = devm_kzalloc(dev, sizeof(struct pxa3xx_gcu_priv), GFP_KERNEL); |
592 | if (!priv) | 597 | if (!priv) |
593 | return -ENOMEM; | 598 | return -ENOMEM; |
594 | 599 | ||
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); | 600 | init_waitqueue_head(&priv->wait_idle); |
604 | init_waitqueue_head(&priv->wait_free); | 601 | init_waitqueue_head(&priv->wait_free); |
605 | spin_lock_init(&priv->spinlock); | 602 | spin_lock_init(&priv->spinlock); |
@@ -611,125 +608,99 @@ static int pxa3xx_gcu_probe(struct platform_device *dev) | |||
611 | 608 | ||
612 | priv->misc_dev.minor = MISCDEV_MINOR, | 609 | priv->misc_dev.minor = MISCDEV_MINOR, |
613 | priv->misc_dev.name = DRV_NAME, | 610 | priv->misc_dev.name = DRV_NAME, |
614 | priv->misc_dev.fops = &misc_fops, | 611 | priv->misc_dev.fops = &pxa3xx_gcu_miscdev_fops; |
615 | 612 | ||
616 | /* register misc device */ | 613 | /* handle IO resources */ |
617 | ret = misc_register(&priv->misc_dev); | 614 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
618 | if (ret < 0) { | 615 | priv->mmio_base = devm_request_and_ioremap(dev, r); |
619 | dev_err(&dev->dev, "misc_register() for minor %d failed\n", | 616 | if (IS_ERR(priv->mmio_base)) { |
620 | MISCDEV_MINOR); | 617 | dev_err(dev, "failed to map I/O memory\n"); |
621 | goto err_free_priv; | 618 | return PTR_ERR(priv->mmio_base); |
622 | } | 619 | } |
623 | 620 | ||
624 | /* handle IO resources */ | 621 | /* enable the clock */ |
625 | r = platform_get_resource(dev, IORESOURCE_MEM, 0); | 622 | priv->clk = devm_clk_get(dev, NULL); |
626 | if (r == NULL) { | 623 | if (IS_ERR(priv->clk)) { |
627 | dev_err(&dev->dev, "no I/O memory resource defined\n"); | 624 | dev_err(dev, "failed to get clock\n"); |
628 | ret = -ENODEV; | 625 | return PTR_ERR(priv->clk); |
629 | goto err_misc_deregister; | ||
630 | } | 626 | } |
631 | 627 | ||
632 | if (!request_mem_region(r->start, resource_size(r), dev->name)) { | 628 | /* request the IRQ */ |
633 | dev_err(&dev->dev, "failed to request I/O memory\n"); | 629 | irq = platform_get_irq(pdev, 0); |
634 | ret = -EBUSY; | 630 | if (irq < 0) { |
635 | goto err_misc_deregister; | 631 | dev_err(dev, "no IRQ defined\n"); |
632 | return -ENODEV; | ||
636 | } | 633 | } |
637 | 634 | ||
638 | priv->mmio_base = ioremap_nocache(r->start, resource_size(r)); | 635 | ret = devm_request_irq(dev, irq, pxa3xx_gcu_handle_irq, |
639 | if (!priv->mmio_base) { | 636 | 0, DRV_NAME, priv); |
640 | dev_err(&dev->dev, "failed to map I/O memory\n"); | 637 | if (ret < 0) { |
641 | ret = -EBUSY; | 638 | dev_err(dev, "request_irq failed\n"); |
642 | goto err_free_mem_region; | 639 | return ret; |
643 | } | 640 | } |
644 | 641 | ||
645 | /* allocate dma memory */ | 642 | /* allocate dma memory */ |
646 | priv->shared = dma_alloc_coherent(&dev->dev, SHARED_SIZE, | 643 | priv->shared = dma_alloc_coherent(dev, SHARED_SIZE, |
647 | &priv->shared_phys, GFP_KERNEL); | 644 | &priv->shared_phys, GFP_KERNEL); |
648 | |||
649 | if (!priv->shared) { | 645 | if (!priv->shared) { |
650 | dev_err(&dev->dev, "failed to allocate DMA memory\n"); | 646 | dev_err(dev, "failed to allocate DMA memory\n"); |
651 | ret = -ENOMEM; | 647 | return -ENOMEM; |
652 | goto err_free_io; | ||
653 | } | 648 | } |
654 | 649 | ||
655 | /* enable the clock */ | 650 | /* register misc device */ |
656 | priv->clk = clk_get(&dev->dev, NULL); | 651 | ret = misc_register(&priv->misc_dev); |
657 | if (IS_ERR(priv->clk)) { | 652 | if (ret < 0) { |
658 | dev_err(&dev->dev, "failed to get clock\n"); | 653 | dev_err(dev, "misc_register() for minor %d failed\n", |
659 | ret = -ENODEV; | 654 | MISCDEV_MINOR); |
660 | goto err_free_dma; | 655 | goto err_free_dma; |
661 | } | 656 | } |
662 | 657 | ||
663 | ret = clk_enable(priv->clk); | 658 | ret = clk_enable(priv->clk); |
664 | if (ret < 0) { | 659 | if (ret < 0) { |
665 | dev_err(&dev->dev, "failed to enable clock\n"); | 660 | dev_err(dev, "failed to enable clock\n"); |
666 | goto err_put_clk; | 661 | goto err_misc_deregister; |
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 | } | 662 | } |
676 | 663 | ||
677 | ret = request_irq(irq, pxa3xx_gcu_handle_irq, | 664 | for (i = 0; i < 8; i++) { |
678 | 0, DRV_NAME, priv); | 665 | ret = pxa3xx_gcu_add_buffer(dev, priv); |
679 | if (ret) { | 666 | if (ret) { |
680 | dev_err(&dev->dev, "request_irq failed\n"); | 667 | dev_err(dev, "failed to allocate DMA memory\n"); |
681 | ret = -EBUSY; | 668 | goto err_disable_clk; |
682 | goto err_put_clk; | 669 | } |
683 | } | 670 | } |
684 | 671 | ||
685 | platform_set_drvdata(dev, priv); | 672 | platform_set_drvdata(pdev, priv); |
686 | priv->resource_mem = r; | 673 | priv->resource_mem = r; |
687 | pxa3xx_gcu_reset(priv); | 674 | pxa3xx_gcu_reset(priv); |
688 | pxa3xx_gcu_init_debug_timer(); | 675 | pxa3xx_gcu_init_debug_timer(); |
689 | 676 | ||
690 | dev_info(&dev->dev, "registered @0x%p, DMA 0x%p (%d bytes), IRQ %d\n", | 677 | dev_info(dev, "registered @0x%p, DMA 0x%p (%d bytes), IRQ %d\n", |
691 | (void *) r->start, (void *) priv->shared_phys, | 678 | (void *) r->start, (void *) priv->shared_phys, |
692 | SHARED_SIZE, irq); | 679 | SHARED_SIZE, irq); |
693 | return 0; | 680 | return 0; |
694 | 681 | ||
695 | err_put_clk: | ||
696 | clk_disable(priv->clk); | ||
697 | clk_put(priv->clk); | ||
698 | |||
699 | err_free_dma: | 682 | err_free_dma: |
700 | dma_free_coherent(&dev->dev, SHARED_SIZE, | 683 | dma_free_coherent(dev, SHARED_SIZE, |
701 | priv->shared, priv->shared_phys); | 684 | priv->shared, priv->shared_phys); |
702 | 685 | ||
703 | err_free_io: | ||
704 | iounmap(priv->mmio_base); | ||
705 | |||
706 | err_free_mem_region: | ||
707 | release_mem_region(r->start, resource_size(r)); | ||
708 | |||
709 | err_misc_deregister: | 686 | err_misc_deregister: |
710 | misc_deregister(&priv->misc_dev); | 687 | misc_deregister(&priv->misc_dev); |
711 | 688 | ||
712 | err_free_priv: | 689 | err_disable_clk: |
713 | free_buffers(dev, priv); | 690 | clk_disable(priv->clk); |
714 | kfree(priv); | 691 | |
715 | return ret; | 692 | return ret; |
716 | } | 693 | } |
717 | 694 | ||
718 | static int pxa3xx_gcu_remove(struct platform_device *dev) | 695 | static int pxa3xx_gcu_remove(struct platform_device *pdev) |
719 | { | 696 | { |
720 | struct pxa3xx_gcu_priv *priv = platform_get_drvdata(dev); | 697 | struct pxa3xx_gcu_priv *priv = platform_get_drvdata(pdev); |
721 | struct resource *r = priv->resource_mem; | 698 | struct device *dev = &pdev->dev; |
722 | 699 | ||
723 | pxa3xx_gcu_wait_idle(priv); | 700 | pxa3xx_gcu_wait_idle(priv); |
724 | |||
725 | misc_deregister(&priv->misc_dev); | 701 | misc_deregister(&priv->misc_dev); |
726 | dma_free_coherent(&dev->dev, SHARED_SIZE, | 702 | dma_free_coherent(dev, SHARED_SIZE, priv->shared, priv->shared_phys); |
727 | priv->shared, priv->shared_phys); | 703 | pxa3xx_gcu_free_buffers(dev, priv); |
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 | 704 | ||
734 | return 0; | 705 | return 0; |
735 | } | 706 | } |