aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video
diff options
context:
space:
mode:
authorPawel Moll <pawel.moll@arm.com>2014-06-24 07:55:11 -0400
committerTomi Valkeinen <tomi.valkeinen@ti.com>2014-07-29 07:12:12 -0400
commitd10715be03bd8bad59ddc50236cb140c3bd73c7b (patch)
tree587203bb2ae8ae20a755b9eeda5cac8181aa4c95 /drivers/video
parentb1f46dd1079d78aa46b8bc740d3e24117335f150 (diff)
video: ARM CLCD: Add DT support
This patch adds basic DT bindings for the PL11x CLCD cells and make their fbdev driver use them. Signed-off-by: Pawel Moll <pawel.moll@arm.com> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
Diffstat (limited to 'drivers/video')
-rw-r--r--drivers/video/fbdev/Kconfig1
-rw-r--r--drivers/video/fbdev/amba-clcd.c263
2 files changed, 264 insertions, 0 deletions
diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig
index 4a7098fb32c3..6f451ad34afc 100644
--- a/drivers/video/fbdev/Kconfig
+++ b/drivers/video/fbdev/Kconfig
@@ -280,6 +280,7 @@ config FB_ARMCLCD
280 select FB_CFB_FILLRECT 280 select FB_CFB_FILLRECT
281 select FB_CFB_COPYAREA 281 select FB_CFB_COPYAREA
282 select FB_CFB_IMAGEBLIT 282 select FB_CFB_IMAGEBLIT
283 select VIDEOMODE_HELPERS if OF
283 help 284 help
284 This framebuffer device driver is for the ARM PrimeCell PL110 285 This framebuffer device driver is for the ARM PrimeCell PL110
285 Colour LCD controller. ARM PrimeCells provide the building 286 Colour LCD controller. ARM PrimeCells provide the building
diff --git a/drivers/video/fbdev/amba-clcd.c b/drivers/video/fbdev/amba-clcd.c
index 14d6b3793e0a..23b35194dee3 100644
--- a/drivers/video/fbdev/amba-clcd.c
+++ b/drivers/video/fbdev/amba-clcd.c
@@ -26,6 +26,13 @@
26#include <linux/amba/clcd.h> 26#include <linux/amba/clcd.h>
27#include <linux/clk.h> 27#include <linux/clk.h>
28#include <linux/hardirq.h> 28#include <linux/hardirq.h>
29#include <linux/dma-mapping.h>
30#include <linux/of.h>
31#include <linux/of_address.h>
32#include <linux/of_graph.h>
33#include <video/display_timing.h>
34#include <video/of_display_timing.h>
35#include <video/videomode.h>
29 36
30#include <asm/sizes.h> 37#include <asm/sizes.h>
31 38
@@ -543,6 +550,259 @@ static int clcdfb_register(struct clcd_fb *fb)
543 return ret; 550 return ret;
544} 551}
545 552
553#ifdef CONFIG_OF
554static int clcdfb_of_get_dpi_panel_mode(struct device_node *node,
555 struct fb_videomode *mode)
556{
557 int err;
558 struct display_timing timing;
559 struct videomode video;
560
561 err = of_get_display_timing(node, "panel-timing", &timing);
562 if (err)
563 return err;
564
565 videomode_from_timing(&timing, &video);
566
567 err = fb_videomode_from_videomode(&video, mode);
568 if (err)
569 return err;
570
571 return 0;
572}
573
574static int clcdfb_snprintf_mode(char *buf, int size, struct fb_videomode *mode)
575{
576 return snprintf(buf, size, "%ux%u@%u", mode->xres, mode->yres,
577 mode->refresh);
578}
579
580static int clcdfb_of_get_mode(struct device *dev, struct device_node *endpoint,
581 struct fb_videomode *mode)
582{
583 int err;
584 struct device_node *panel;
585 char *name;
586 int len;
587
588 panel = of_graph_get_remote_port_parent(endpoint);
589 if (!panel)
590 return -ENODEV;
591
592 /* Only directly connected DPI panels supported for now */
593 if (of_device_is_compatible(panel, "panel-dpi"))
594 err = clcdfb_of_get_dpi_panel_mode(panel, mode);
595 else
596 err = -ENOENT;
597 if (err)
598 return err;
599
600 len = clcdfb_snprintf_mode(NULL, 0, mode);
601 name = devm_kzalloc(dev, len + 1, GFP_KERNEL);
602 clcdfb_snprintf_mode(name, len + 1, mode);
603 mode->name = name;
604
605 return 0;
606}
607
608static int clcdfb_of_init_tft_panel(struct clcd_fb *fb, u32 r0, u32 g0, u32 b0)
609{
610 static struct {
611 unsigned int part;
612 u32 r0, g0, b0;
613 u32 caps;
614 } panels[] = {
615 { 0x110, 1, 7, 13, CLCD_CAP_5551 },
616 { 0x110, 0, 8, 16, CLCD_CAP_888 },
617 { 0x111, 4, 14, 20, CLCD_CAP_444 },
618 { 0x111, 3, 11, 19, CLCD_CAP_444 | CLCD_CAP_5551 },
619 { 0x111, 3, 10, 19, CLCD_CAP_444 | CLCD_CAP_5551 |
620 CLCD_CAP_565 },
621 { 0x111, 0, 8, 16, CLCD_CAP_444 | CLCD_CAP_5551 |
622 CLCD_CAP_565 | CLCD_CAP_888 },
623 };
624 int i;
625
626 /* Bypass pixel clock divider, data output on the falling edge */
627 fb->panel->tim2 = TIM2_BCD | TIM2_IPC;
628
629 /* TFT display, vert. comp. interrupt at the start of the back porch */
630 fb->panel->cntl |= CNTL_LCDTFT | CNTL_LCDVCOMP(1);
631
632 fb->panel->caps = 0;
633
634 /* Match the setup with known variants */
635 for (i = 0; i < ARRAY_SIZE(panels) && !fb->panel->caps; i++) {
636 if (amba_part(fb->dev) != panels[i].part)
637 continue;
638 if (g0 != panels[i].g0)
639 continue;
640 if (r0 == panels[i].r0 && b0 == panels[i].b0)
641 fb->panel->caps = panels[i].caps & CLCD_CAP_RGB;
642 if (r0 == panels[i].b0 && b0 == panels[i].r0)
643 fb->panel->caps = panels[i].caps & CLCD_CAP_BGR;
644 }
645
646 return fb->panel->caps ? 0 : -EINVAL;
647}
648
649static int clcdfb_of_init_display(struct clcd_fb *fb)
650{
651 struct device_node *endpoint;
652 int err;
653 u32 max_bandwidth;
654 u32 tft_r0b0g0[3];
655
656 fb->panel = devm_kzalloc(&fb->dev->dev, sizeof(*fb->panel), GFP_KERNEL);
657 if (!fb->panel)
658 return -ENOMEM;
659
660 endpoint = of_graph_get_next_endpoint(fb->dev->dev.of_node, NULL);
661 if (!endpoint)
662 return -ENODEV;
663
664 err = clcdfb_of_get_mode(&fb->dev->dev, endpoint, &fb->panel->mode);
665 if (err)
666 return err;
667
668 err = of_property_read_u32(fb->dev->dev.of_node, "max-memory-bandwidth",
669 &max_bandwidth);
670 if (!err)
671 fb->panel->bpp = 8 * max_bandwidth / (fb->panel->mode.xres *
672 fb->panel->mode.yres * fb->panel->mode.refresh);
673 else
674 fb->panel->bpp = 32;
675
676#ifdef CONFIG_CPU_BIG_ENDIAN
677 fb->panel->cntl |= CNTL_BEBO;
678#endif
679 fb->panel->width = -1;
680 fb->panel->height = -1;
681
682 if (of_property_read_u32_array(endpoint,
683 "arm,pl11x,tft-r0g0b0-pads",
684 tft_r0b0g0, ARRAY_SIZE(tft_r0b0g0)) == 0)
685 return clcdfb_of_init_tft_panel(fb, tft_r0b0g0[0],
686 tft_r0b0g0[1], tft_r0b0g0[2]);
687
688 return -ENOENT;
689}
690
691static int clcdfb_of_vram_setup(struct clcd_fb *fb)
692{
693 int err;
694 struct device_node *memory;
695 u64 size;
696
697 err = clcdfb_of_init_display(fb);
698 if (err)
699 return err;
700
701 memory = of_parse_phandle(fb->dev->dev.of_node, "memory-region", 0);
702 if (!memory)
703 return -ENODEV;
704
705 fb->fb.screen_base = of_iomap(memory, 0);
706 if (!fb->fb.screen_base)
707 return -ENOMEM;
708
709 fb->fb.fix.smem_start = of_translate_address(memory,
710 of_get_address(memory, 0, &size, NULL));
711 fb->fb.fix.smem_len = size;
712
713 return 0;
714}
715
716static int clcdfb_of_vram_mmap(struct clcd_fb *fb, struct vm_area_struct *vma)
717{
718 unsigned long off, user_size, kernel_size;
719
720
721 off = vma->vm_pgoff << PAGE_SHIFT;
722 user_size = vma->vm_end - vma->vm_start;
723 kernel_size = fb->fb.fix.smem_len;
724
725 if (off >= kernel_size || user_size > (kernel_size - off))
726 return -ENXIO;
727
728 return remap_pfn_range(vma, vma->vm_start,
729 __phys_to_pfn(fb->fb.fix.smem_start) + vma->vm_pgoff,
730 user_size,
731 pgprot_writecombine(vma->vm_page_prot));
732}
733
734static void clcdfb_of_vram_remove(struct clcd_fb *fb)
735{
736 iounmap(fb->fb.screen_base);
737}
738
739static int clcdfb_of_dma_setup(struct clcd_fb *fb)
740{
741 unsigned long framesize;
742 dma_addr_t dma;
743 int err;
744
745 err = clcdfb_of_init_display(fb);
746 if (err)
747 return err;
748
749 framesize = fb->panel->mode.xres * fb->panel->mode.yres *
750 fb->panel->bpp / 8;
751 fb->fb.screen_base = dma_alloc_coherent(&fb->dev->dev, framesize,
752 &dma, GFP_KERNEL);
753 if (!fb->fb.screen_base)
754 return -ENOMEM;
755
756 fb->fb.fix.smem_start = dma;
757 fb->fb.fix.smem_len = framesize;
758
759 return 0;
760}
761
762static int clcdfb_of_dma_mmap(struct clcd_fb *fb, struct vm_area_struct *vma)
763{
764 return dma_mmap_writecombine(&fb->dev->dev, vma, fb->fb.screen_base,
765 fb->fb.fix.smem_start, fb->fb.fix.smem_len);
766}
767
768static void clcdfb_of_dma_remove(struct clcd_fb *fb)
769{
770 dma_free_coherent(&fb->dev->dev, fb->fb.fix.smem_len,
771 fb->fb.screen_base, fb->fb.fix.smem_start);
772}
773
774static struct clcd_board *clcdfb_of_get_board(struct amba_device *dev)
775{
776 struct clcd_board *board = devm_kzalloc(&dev->dev, sizeof(*board),
777 GFP_KERNEL);
778 struct device_node *node = dev->dev.of_node;
779
780 if (!board)
781 return NULL;
782
783 board->name = of_node_full_name(node);
784 board->caps = CLCD_CAP_ALL;
785 board->check = clcdfb_check;
786 board->decode = clcdfb_decode;
787 if (of_find_property(node, "memory-region", NULL)) {
788 board->setup = clcdfb_of_vram_setup;
789 board->mmap = clcdfb_of_vram_mmap;
790 board->remove = clcdfb_of_vram_remove;
791 } else {
792 board->setup = clcdfb_of_dma_setup;
793 board->mmap = clcdfb_of_dma_mmap;
794 board->remove = clcdfb_of_dma_remove;
795 }
796
797 return board;
798}
799#else
800static struct clcd_board *clcdfb_of_get_board(struct amba_dev *dev)
801{
802 return NULL;
803}
804#endif
805
546static int clcdfb_probe(struct amba_device *dev, const struct amba_id *id) 806static int clcdfb_probe(struct amba_device *dev, const struct amba_id *id)
547{ 807{
548 struct clcd_board *board = dev_get_platdata(&dev->dev); 808 struct clcd_board *board = dev_get_platdata(&dev->dev);
@@ -550,6 +810,9 @@ static int clcdfb_probe(struct amba_device *dev, const struct amba_id *id)
550 int ret; 810 int ret;
551 811
552 if (!board) 812 if (!board)
813 board = clcdfb_of_get_board(dev);
814
815 if (!board)
553 return -EINVAL; 816 return -EINVAL;
554 817
555 ret = dma_set_mask_and_coherent(&dev->dev, DMA_BIT_MASK(32)); 818 ret = dma_set_mask_and_coherent(&dev->dev, DMA_BIT_MASK(32));