aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/fbdev
diff options
context:
space:
mode:
authorLinus Walleij <linus.walleij@linaro.org>2016-06-16 05:36:16 -0400
committerTomi Valkeinen <tomi.valkeinen@ti.com>2016-08-11 10:54:53 -0400
commit046ad6cdeb3f83abcbfa2af88ce471afb2e7fc30 (patch)
tree6b668c3b7b7540c22105bc5fc22d0ef5e13af9fb /drivers/video/fbdev
parent03d14c36af98dd2191c2e35b5ed55ff93b59d345 (diff)
video: ARM CLCD: support Nomadik variant
The Nomadik variant has a few special quirks that need to be respected to make the driver work: - The block need to be clocked during writing of the TIMn registers or the bus will stall. - Special bits in the control register select how many of the output display lines get activated. - Special bits in the control register select how to manage the different 565 and 5551 modes. - There is a packed 24bit graphics mode, i.e 888 pixels can be stored in memory is three consecutive bytes, not evenly aligned to a 32bit word. This patch uses the vendor data pointer from the AMBA matching mechanism to track the quirks for this variant, and adds two hooks that variants can use to initialize boards and panels during start-up. These will later be used to adopt a Nomadik board profile. Cc: Pawel Moll <pawel.moll@arm.com> Cc: Rob Herring <robh@kernel.org> Cc: Russell King <linux@arm.linux.org.uk> Signed-off-by: Linus Walleij <linus.walleij@linaro.org> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
Diffstat (limited to 'drivers/video/fbdev')
-rw-r--r--drivers/video/fbdev/amba-clcd.c106
1 files changed, 97 insertions, 9 deletions
diff --git a/drivers/video/fbdev/amba-clcd.c b/drivers/video/fbdev/amba-clcd.c
index 080e8a246faf..371f4e2aea6c 100644
--- a/drivers/video/fbdev/amba-clcd.c
+++ b/drivers/video/fbdev/amba-clcd.c
@@ -225,6 +225,15 @@ clcdfb_set_bitfields(struct clcd_fb *fb, struct fb_var_screeninfo *var)
225 var->blue.length = 4; 225 var->blue.length = 4;
226 } 226 }
227 break; 227 break;
228 case 24:
229 if (fb->vendor->packed_24_bit_pixels) {
230 var->red.length = 8;
231 var->green.length = 8;
232 var->blue.length = 8;
233 } else {
234 ret = -EINVAL;
235 }
236 break;
228 case 32: 237 case 32:
229 /* If we can't do 888, reject */ 238 /* If we can't do 888, reject */
230 caps &= CLCD_CAP_888; 239 caps &= CLCD_CAP_888;
@@ -311,6 +320,12 @@ static int clcdfb_set_par(struct fb_info *info)
311 320
312 clcdfb_disable(fb); 321 clcdfb_disable(fb);
313 322
323 /* Some variants must be clocked here */
324 if (fb->vendor->clock_timregs && !fb->clk_enabled) {
325 fb->clk_enabled = true;
326 clk_enable(fb->clk);
327 }
328
314 writel(regs.tim0, fb->regs + CLCD_TIM0); 329 writel(regs.tim0, fb->regs + CLCD_TIM0);
315 writel(regs.tim1, fb->regs + CLCD_TIM1); 330 writel(regs.tim1, fb->regs + CLCD_TIM1);
316 writel(regs.tim2, fb->regs + CLCD_TIM2); 331 writel(regs.tim2, fb->regs + CLCD_TIM2);
@@ -710,6 +725,42 @@ static int clcdfb_of_init_tft_panel(struct clcd_fb *fb, u32 r0, u32 g0, u32 b0)
710 if (r0 != 0 && b0 == 0) 725 if (r0 != 0 && b0 == 0)
711 fb->panel->bgr_connection = true; 726 fb->panel->bgr_connection = true;
712 727
728 if (fb->panel->caps && fb->vendor->st_bitmux_control) {
729 /*
730 * Set up the special bits for the Nomadik control register
731 * (other platforms tend to do this through an external
732 * register).
733 */
734
735 /* Offset of the highest used color */
736 int maxoff = max3(r0, g0, b0);
737 /* Most significant bit out, highest used bit */
738 int msb = 0;
739
740 if (fb->panel->caps & CLCD_CAP_888) {
741 msb = maxoff + 8 - 1;
742 } else if (fb->panel->caps & CLCD_CAP_565) {
743 msb = maxoff + 5 - 1;
744 fb->panel->cntl |= CNTL_ST_1XBPP_565;
745 } else if (fb->panel->caps & CLCD_CAP_5551) {
746 msb = maxoff + 5 - 1;
747 fb->panel->cntl |= CNTL_ST_1XBPP_5551;
748 } else if (fb->panel->caps & CLCD_CAP_444) {
749 msb = maxoff + 4 - 1;
750 fb->panel->cntl |= CNTL_ST_1XBPP_444;
751 }
752
753 /* Send out as many bits as we need */
754 if (msb > 17)
755 fb->panel->cntl |= CNTL_ST_CDWID_24;
756 else if (msb > 15)
757 fb->panel->cntl |= CNTL_ST_CDWID_18;
758 else if (msb > 11)
759 fb->panel->cntl |= CNTL_ST_CDWID_16;
760 else
761 fb->panel->cntl |= CNTL_ST_CDWID_12;
762 }
763
713 return fb->panel->caps ? 0 : -EINVAL; 764 return fb->panel->caps ? 0 : -EINVAL;
714} 765}
715 766
@@ -725,9 +776,21 @@ static int clcdfb_of_init_display(struct clcd_fb *fb)
725 if (!fb->panel) 776 if (!fb->panel)
726 return -ENOMEM; 777 return -ENOMEM;
727 778
728 endpoint = of_graph_get_next_endpoint(fb->dev->dev.of_node, NULL); 779 /*
729 if (!endpoint) 780 * Fetch the panel endpoint.
730 return -ENODEV; 781 */
782 if (!endpoint) {
783 endpoint = of_graph_get_next_endpoint(fb->dev->dev.of_node,
784 NULL);
785 if (!endpoint)
786 return -ENODEV;
787 }
788
789 if (fb->vendor->init_panel) {
790 err = fb->vendor->init_panel(fb, endpoint);
791 if (err)
792 return err;
793 }
731 794
732 err = clcdfb_of_get_backlight(endpoint, fb->panel); 795 err = clcdfb_of_get_backlight(endpoint, fb->panel);
733 if (err) 796 if (err)
@@ -764,11 +827,11 @@ static int clcdfb_of_init_display(struct clcd_fb *fb)
764 827
765 if (of_property_read_u32_array(endpoint, 828 if (of_property_read_u32_array(endpoint,
766 "arm,pl11x,tft-r0g0b0-pads", 829 "arm,pl11x,tft-r0g0b0-pads",
767 tft_r0b0g0, ARRAY_SIZE(tft_r0b0g0)) == 0) 830 tft_r0b0g0, ARRAY_SIZE(tft_r0b0g0)) != 0)
768 return clcdfb_of_init_tft_panel(fb, tft_r0b0g0[0], 831 return -ENOENT;
769 tft_r0b0g0[1], tft_r0b0g0[2]);
770 832
771 return -ENOENT; 833 return clcdfb_of_init_tft_panel(fb, tft_r0b0g0[0],
834 tft_r0b0g0[1], tft_r0b0g0[2]);
772} 835}
773 836
774static int clcdfb_of_vram_setup(struct clcd_fb *fb) 837static int clcdfb_of_vram_setup(struct clcd_fb *fb)
@@ -889,6 +952,7 @@ static struct clcd_board *clcdfb_of_get_board(struct amba_device *dev)
889static int clcdfb_probe(struct amba_device *dev, const struct amba_id *id) 952static int clcdfb_probe(struct amba_device *dev, const struct amba_id *id)
890{ 953{
891 struct clcd_board *board = dev_get_platdata(&dev->dev); 954 struct clcd_board *board = dev_get_platdata(&dev->dev);
955 struct clcd_vendor_data *vendor = id->data;
892 struct clcd_fb *fb; 956 struct clcd_fb *fb;
893 int ret; 957 int ret;
894 958
@@ -898,6 +962,12 @@ static int clcdfb_probe(struct amba_device *dev, const struct amba_id *id)
898 if (!board) 962 if (!board)
899 return -EINVAL; 963 return -EINVAL;
900 964
965 if (vendor->init_board) {
966 ret = vendor->init_board(dev, board);
967 if (ret)
968 return ret;
969 }
970
901 ret = dma_set_mask_and_coherent(&dev->dev, DMA_BIT_MASK(32)); 971 ret = dma_set_mask_and_coherent(&dev->dev, DMA_BIT_MASK(32));
902 if (ret) 972 if (ret)
903 goto out; 973 goto out;
@@ -916,10 +986,11 @@ static int clcdfb_probe(struct amba_device *dev, const struct amba_id *id)
916 } 986 }
917 987
918 fb->dev = dev; 988 fb->dev = dev;
989 fb->vendor = vendor;
919 fb->board = board; 990 fb->board = board;
920 991
921 dev_info(&fb->dev->dev, "PL%03x rev%u at 0x%08llx\n", 992 dev_info(&fb->dev->dev, "PL%03x designer %02x rev%u at 0x%08llx\n",
922 amba_part(dev), amba_rev(dev), 993 amba_part(dev), amba_manf(dev), amba_rev(dev),
923 (unsigned long long)dev->res.start); 994 (unsigned long long)dev->res.start);
924 995
925 ret = fb->board->setup(fb); 996 ret = fb->board->setup(fb);
@@ -962,10 +1033,27 @@ static int clcdfb_remove(struct amba_device *dev)
962 return 0; 1033 return 0;
963} 1034}
964 1035
1036static struct clcd_vendor_data vendor_arm = {
1037 /* No special business */
1038};
1039
1040static struct clcd_vendor_data vendor_nomadik = {
1041 .clock_timregs = true,
1042 .packed_24_bit_pixels = true,
1043 .st_bitmux_control = true,
1044};
1045
965static struct amba_id clcdfb_id_table[] = { 1046static struct amba_id clcdfb_id_table[] = {
966 { 1047 {
967 .id = 0x00041110, 1048 .id = 0x00041110,
968 .mask = 0x000ffffe, 1049 .mask = 0x000ffffe,
1050 .data = &vendor_arm,
1051 },
1052 /* ST Electronics Nomadik variant */
1053 {
1054 .id = 0x00180110,
1055 .mask = 0x00fffffe,
1056 .data = &vendor_nomadik,
969 }, 1057 },
970 { 0, 0 }, 1058 { 0, 0 },
971}; 1059};