diff options
author | Markus Pargmann <mpa@pengutronix.de> | 2013-05-26 06:35:38 -0400 |
---|---|---|
committer | Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> | 2013-07-08 04:36:49 -0400 |
commit | 1b6c79361ba5ce30b40f0f7d6fc2421dc5fcbe0c (patch) | |
tree | 835b5dce4d4a29f1c1dc67c17f9d9658e648837c /drivers/video | |
parent | 19fd7441e9cc29b6c6d73c5469b3c93aa245fbb5 (diff) |
video: imxfb: Add DT support
Add devicetree support for imx framebuffer driver. It uses the generic
display bindings and helper functions.
Signed-off-by: Markus Pargmann <mpa@pengutronix.de>
Cc: Fabio Estevam <festevam@gmail.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Acked-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Acked-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'drivers/video')
-rw-r--r-- | drivers/video/Kconfig | 2 | ||||
-rw-r--r-- | drivers/video/imxfb.c | 194 |
2 files changed, 161 insertions, 35 deletions
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 2c301f8441e9..4cf1e1dd5621 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig | |||
@@ -367,6 +367,8 @@ config FB_IMX | |||
367 | select FB_CFB_FILLRECT | 367 | select FB_CFB_FILLRECT |
368 | select FB_CFB_COPYAREA | 368 | select FB_CFB_COPYAREA |
369 | select FB_CFB_IMAGEBLIT | 369 | select FB_CFB_IMAGEBLIT |
370 | select FB_MODE_HELPERS | ||
371 | select VIDEOMODE_HELPERS | ||
370 | 372 | ||
371 | config FB_CYBER2000 | 373 | config FB_CYBER2000 |
372 | tristate "CyberPro 2000/2010/5000 support" | 374 | tristate "CyberPro 2000/2010/5000 support" |
diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c index 12af22ba4d92..38733ac2b698 100644 --- a/drivers/video/imxfb.c +++ b/drivers/video/imxfb.c | |||
@@ -31,6 +31,12 @@ | |||
31 | #include <linux/dma-mapping.h> | 31 | #include <linux/dma-mapping.h> |
32 | #include <linux/io.h> | 32 | #include <linux/io.h> |
33 | #include <linux/math64.h> | 33 | #include <linux/math64.h> |
34 | #include <linux/of.h> | ||
35 | #include <linux/of_device.h> | ||
36 | |||
37 | #include <video/of_display_timing.h> | ||
38 | #include <video/of_videomode.h> | ||
39 | #include <video/videomode.h> | ||
34 | 40 | ||
35 | #include <linux/platform_data/video-imxfb.h> | 41 | #include <linux/platform_data/video-imxfb.h> |
36 | 42 | ||
@@ -112,10 +118,11 @@ | |||
112 | #define LCDISR_EOF (1<<1) | 118 | #define LCDISR_EOF (1<<1) |
113 | #define LCDISR_BOF (1<<0) | 119 | #define LCDISR_BOF (1<<0) |
114 | 120 | ||
121 | #define IMXFB_LSCR1_DEFAULT 0x00120300 | ||
122 | |||
115 | /* Used fb-mode. Can be set on kernel command line, therefore file-static. */ | 123 | /* Used fb-mode. Can be set on kernel command line, therefore file-static. */ |
116 | static const char *fb_mode; | 124 | static const char *fb_mode; |
117 | 125 | ||
118 | |||
119 | /* | 126 | /* |
120 | * These are the bitfields for each | 127 | * These are the bitfields for each |
121 | * display depth that we support. | 128 | * display depth that we support. |
@@ -187,6 +194,19 @@ static struct platform_device_id imxfb_devtype[] = { | |||
187 | }; | 194 | }; |
188 | MODULE_DEVICE_TABLE(platform, imxfb_devtype); | 195 | MODULE_DEVICE_TABLE(platform, imxfb_devtype); |
189 | 196 | ||
197 | static struct of_device_id imxfb_of_dev_id[] = { | ||
198 | { | ||
199 | .compatible = "fsl,imx1-fb", | ||
200 | .data = &imxfb_devtype[IMX1_FB], | ||
201 | }, { | ||
202 | .compatible = "fsl,imx21-fb", | ||
203 | .data = &imxfb_devtype[IMX21_FB], | ||
204 | }, { | ||
205 | /* sentinel */ | ||
206 | } | ||
207 | }; | ||
208 | MODULE_DEVICE_TABLE(of, imxfb_of_dev_id); | ||
209 | |||
190 | static inline int is_imx1_fb(struct imxfb_info *fbi) | 210 | static inline int is_imx1_fb(struct imxfb_info *fbi) |
191 | { | 211 | { |
192 | return fbi->devtype == IMX1_FB; | 212 | return fbi->devtype == IMX1_FB; |
@@ -319,6 +339,9 @@ static const struct imx_fb_videomode *imxfb_find_mode(struct imxfb_info *fbi) | |||
319 | struct imx_fb_videomode *m; | 339 | struct imx_fb_videomode *m; |
320 | int i; | 340 | int i; |
321 | 341 | ||
342 | if (!fb_mode) | ||
343 | return &fbi->mode[0]; | ||
344 | |||
322 | for (i = 0, m = &fbi->mode[0]; i < fbi->num_modes; i++, m++) { | 345 | for (i = 0, m = &fbi->mode[0]; i < fbi->num_modes; i++, m++) { |
323 | if (!strcmp(m->mode.name, fb_mode)) | 346 | if (!strcmp(m->mode.name, fb_mode)) |
324 | return m; | 347 | return m; |
@@ -474,6 +497,9 @@ static int imxfb_bl_update_status(struct backlight_device *bl) | |||
474 | struct imxfb_info *fbi = bl_get_data(bl); | 497 | struct imxfb_info *fbi = bl_get_data(bl); |
475 | int brightness = bl->props.brightness; | 498 | int brightness = bl->props.brightness; |
476 | 499 | ||
500 | if (!fbi->pwmr) | ||
501 | return 0; | ||
502 | |||
477 | if (bl->props.power != FB_BLANK_UNBLANK) | 503 | if (bl->props.power != FB_BLANK_UNBLANK) |
478 | brightness = 0; | 504 | brightness = 0; |
479 | if (bl->props.fb_blank != FB_BLANK_UNBLANK) | 505 | if (bl->props.fb_blank != FB_BLANK_UNBLANK) |
@@ -684,10 +710,14 @@ static int imxfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *inf | |||
684 | 710 | ||
685 | writel(fbi->pcr, fbi->regs + LCDC_PCR); | 711 | writel(fbi->pcr, fbi->regs + LCDC_PCR); |
686 | #ifndef PWMR_BACKLIGHT_AVAILABLE | 712 | #ifndef PWMR_BACKLIGHT_AVAILABLE |
687 | writel(fbi->pwmr, fbi->regs + LCDC_PWMR); | 713 | if (fbi->pwmr) |
714 | writel(fbi->pwmr, fbi->regs + LCDC_PWMR); | ||
688 | #endif | 715 | #endif |
689 | writel(fbi->lscr1, fbi->regs + LCDC_LSCR1); | 716 | writel(fbi->lscr1, fbi->regs + LCDC_LSCR1); |
690 | writel(fbi->dmacr, fbi->regs + LCDC_DMACR); | 717 | |
718 | /* dmacr = 0 is no valid value, as we need DMA control marks. */ | ||
719 | if (fbi->dmacr) | ||
720 | writel(fbi->dmacr, fbi->regs + LCDC_DMACR); | ||
691 | 721 | ||
692 | return 0; | 722 | return 0; |
693 | } | 723 | } |
@@ -723,13 +753,12 @@ static int imxfb_resume(struct platform_device *dev) | |||
723 | #define imxfb_resume NULL | 753 | #define imxfb_resume NULL |
724 | #endif | 754 | #endif |
725 | 755 | ||
726 | static int __init imxfb_init_fbinfo(struct platform_device *pdev) | 756 | static int imxfb_init_fbinfo(struct platform_device *pdev) |
727 | { | 757 | { |
728 | struct imx_fb_platform_data *pdata = pdev->dev.platform_data; | 758 | struct imx_fb_platform_data *pdata = pdev->dev.platform_data; |
729 | struct fb_info *info = dev_get_drvdata(&pdev->dev); | 759 | struct fb_info *info = dev_get_drvdata(&pdev->dev); |
730 | struct imxfb_info *fbi = info->par; | 760 | struct imxfb_info *fbi = info->par; |
731 | struct imx_fb_videomode *m; | 761 | struct device_node *np; |
732 | int i; | ||
733 | 762 | ||
734 | pr_debug("%s\n",__func__); | 763 | pr_debug("%s\n",__func__); |
735 | 764 | ||
@@ -760,41 +789,95 @@ static int __init imxfb_init_fbinfo(struct platform_device *pdev) | |||
760 | info->fbops = &imxfb_ops; | 789 | info->fbops = &imxfb_ops; |
761 | info->flags = FBINFO_FLAG_DEFAULT | | 790 | info->flags = FBINFO_FLAG_DEFAULT | |
762 | FBINFO_READS_FAST; | 791 | FBINFO_READS_FAST; |
763 | info->var.grayscale = pdata->cmap_greyscale; | 792 | if (pdata) { |
764 | fbi->cmap_inverse = pdata->cmap_inverse; | 793 | info->var.grayscale = pdata->cmap_greyscale; |
765 | fbi->cmap_static = pdata->cmap_static; | 794 | fbi->cmap_inverse = pdata->cmap_inverse; |
766 | fbi->lscr1 = pdata->lscr1; | 795 | fbi->cmap_static = pdata->cmap_static; |
767 | fbi->dmacr = pdata->dmacr; | 796 | fbi->lscr1 = pdata->lscr1; |
768 | fbi->pwmr = pdata->pwmr; | 797 | fbi->dmacr = pdata->dmacr; |
769 | fbi->lcd_power = pdata->lcd_power; | 798 | fbi->pwmr = pdata->pwmr; |
770 | fbi->backlight_power = pdata->backlight_power; | 799 | fbi->lcd_power = pdata->lcd_power; |
771 | 800 | fbi->backlight_power = pdata->backlight_power; | |
772 | for (i = 0, m = &pdata->mode[0]; i < pdata->num_modes; i++, m++) | 801 | } else { |
773 | info->fix.smem_len = max_t(size_t, info->fix.smem_len, | 802 | np = pdev->dev.of_node; |
774 | m->mode.xres * m->mode.yres * m->bpp / 8); | 803 | info->var.grayscale = of_property_read_bool(np, |
804 | "cmap-greyscale"); | ||
805 | fbi->cmap_inverse = of_property_read_bool(np, "cmap-inverse"); | ||
806 | fbi->cmap_static = of_property_read_bool(np, "cmap-static"); | ||
807 | |||
808 | fbi->lscr1 = IMXFB_LSCR1_DEFAULT; | ||
809 | of_property_read_u32(np, "fsl,lscr1", &fbi->lscr1); | ||
810 | |||
811 | of_property_read_u32(np, "fsl,dmacr", &fbi->dmacr); | ||
812 | |||
813 | /* These two function pointers could be used by some specific | ||
814 | * platforms. */ | ||
815 | fbi->lcd_power = NULL; | ||
816 | fbi->backlight_power = NULL; | ||
817 | } | ||
818 | |||
819 | return 0; | ||
820 | } | ||
821 | |||
822 | static int imxfb_of_read_mode(struct device *dev, struct device_node *np, | ||
823 | struct imx_fb_videomode *imxfb_mode) | ||
824 | { | ||
825 | int ret; | ||
826 | struct fb_videomode *of_mode = &imxfb_mode->mode; | ||
827 | u32 bpp; | ||
828 | u32 pcr; | ||
829 | |||
830 | ret = of_property_read_string(np, "model", &of_mode->name); | ||
831 | if (ret) | ||
832 | of_mode->name = NULL; | ||
833 | |||
834 | ret = of_get_fb_videomode(np, of_mode, OF_USE_NATIVE_MODE); | ||
835 | if (ret) { | ||
836 | dev_err(dev, "Failed to get videomode from DT\n"); | ||
837 | return ret; | ||
838 | } | ||
839 | |||
840 | ret = of_property_read_u32(np, "bits-per-pixel", &bpp); | ||
841 | ret |= of_property_read_u32(np, "fsl,pcr", &pcr); | ||
842 | |||
843 | if (ret) { | ||
844 | dev_err(dev, "Failed to read bpp and pcr from DT\n"); | ||
845 | return -EINVAL; | ||
846 | } | ||
847 | |||
848 | if (bpp < 1 || bpp > 255) { | ||
849 | dev_err(dev, "Bits per pixel have to be between 1 and 255\n"); | ||
850 | return -EINVAL; | ||
851 | } | ||
852 | |||
853 | imxfb_mode->bpp = bpp; | ||
854 | imxfb_mode->pcr = pcr; | ||
775 | 855 | ||
776 | return 0; | 856 | return 0; |
777 | } | 857 | } |
778 | 858 | ||
779 | static int __init imxfb_probe(struct platform_device *pdev) | 859 | static int imxfb_probe(struct platform_device *pdev) |
780 | { | 860 | { |
781 | struct imxfb_info *fbi; | 861 | struct imxfb_info *fbi; |
782 | struct fb_info *info; | 862 | struct fb_info *info; |
783 | struct imx_fb_platform_data *pdata; | 863 | struct imx_fb_platform_data *pdata; |
784 | struct resource *res; | 864 | struct resource *res; |
865 | struct imx_fb_videomode *m; | ||
866 | const struct of_device_id *of_id; | ||
785 | int ret, i; | 867 | int ret, i; |
868 | int bytes_per_pixel; | ||
786 | 869 | ||
787 | dev_info(&pdev->dev, "i.MX Framebuffer driver\n"); | 870 | dev_info(&pdev->dev, "i.MX Framebuffer driver\n"); |
788 | 871 | ||
872 | of_id = of_match_device(imxfb_of_dev_id, &pdev->dev); | ||
873 | if (of_id) | ||
874 | pdev->id_entry = of_id->data; | ||
875 | |||
789 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 876 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
790 | if (!res) | 877 | if (!res) |
791 | return -ENODEV; | 878 | return -ENODEV; |
792 | 879 | ||
793 | pdata = pdev->dev.platform_data; | 880 | pdata = pdev->dev.platform_data; |
794 | if (!pdata) { | ||
795 | dev_err(&pdev->dev,"No platform_data available\n"); | ||
796 | return -ENOMEM; | ||
797 | } | ||
798 | 881 | ||
799 | info = framebuffer_alloc(sizeof(struct imxfb_info), &pdev->dev); | 882 | info = framebuffer_alloc(sizeof(struct imxfb_info), &pdev->dev); |
800 | if (!info) | 883 | if (!info) |
@@ -802,15 +885,55 @@ static int __init imxfb_probe(struct platform_device *pdev) | |||
802 | 885 | ||
803 | fbi = info->par; | 886 | fbi = info->par; |
804 | 887 | ||
805 | if (!fb_mode) | ||
806 | fb_mode = pdata->mode[0].mode.name; | ||
807 | |||
808 | platform_set_drvdata(pdev, info); | 888 | platform_set_drvdata(pdev, info); |
809 | 889 | ||
810 | ret = imxfb_init_fbinfo(pdev); | 890 | ret = imxfb_init_fbinfo(pdev); |
811 | if (ret < 0) | 891 | if (ret < 0) |
812 | goto failed_init; | 892 | goto failed_init; |
813 | 893 | ||
894 | if (pdata) { | ||
895 | if (!fb_mode) | ||
896 | fb_mode = pdata->mode[0].mode.name; | ||
897 | |||
898 | fbi->mode = pdata->mode; | ||
899 | fbi->num_modes = pdata->num_modes; | ||
900 | } else { | ||
901 | struct device_node *display_np; | ||
902 | fb_mode = NULL; | ||
903 | |||
904 | display_np = of_parse_phandle(pdev->dev.of_node, "display", 0); | ||
905 | if (!display_np) { | ||
906 | dev_err(&pdev->dev, "No display defined in devicetree\n"); | ||
907 | ret = -EINVAL; | ||
908 | goto failed_of_parse; | ||
909 | } | ||
910 | |||
911 | /* | ||
912 | * imxfb does not support more modes, we choose only the native | ||
913 | * mode. | ||
914 | */ | ||
915 | fbi->num_modes = 1; | ||
916 | |||
917 | fbi->mode = devm_kzalloc(&pdev->dev, | ||
918 | sizeof(struct imx_fb_videomode), GFP_KERNEL); | ||
919 | if (!fbi->mode) { | ||
920 | ret = -ENOMEM; | ||
921 | goto failed_of_parse; | ||
922 | } | ||
923 | |||
924 | ret = imxfb_of_read_mode(&pdev->dev, display_np, fbi->mode); | ||
925 | if (ret) | ||
926 | goto failed_of_parse; | ||
927 | } | ||
928 | |||
929 | /* Calculate maximum bytes used per pixel. In most cases this should | ||
930 | * be the same as m->bpp/8 */ | ||
931 | m = &fbi->mode[0]; | ||
932 | bytes_per_pixel = (m->bpp + 7) / 8; | ||
933 | for (i = 0; i < fbi->num_modes; i++, m++) | ||
934 | info->fix.smem_len = max_t(size_t, info->fix.smem_len, | ||
935 | m->mode.xres * m->mode.yres * bytes_per_pixel); | ||
936 | |||
814 | res = request_mem_region(res->start, resource_size(res), | 937 | res = request_mem_region(res->start, resource_size(res), |
815 | DRIVER_NAME); | 938 | DRIVER_NAME); |
816 | if (!res) { | 939 | if (!res) { |
@@ -843,7 +966,8 @@ static int __init imxfb_probe(struct platform_device *pdev) | |||
843 | goto failed_ioremap; | 966 | goto failed_ioremap; |
844 | } | 967 | } |
845 | 968 | ||
846 | if (!pdata->fixed_screen_cpu) { | 969 | /* Seems not being used by anyone, so no support for oftree */ |
970 | if (!pdata || !pdata->fixed_screen_cpu) { | ||
847 | fbi->map_size = PAGE_ALIGN(info->fix.smem_len); | 971 | fbi->map_size = PAGE_ALIGN(info->fix.smem_len); |
848 | fbi->map_cpu = dma_alloc_writecombine(&pdev->dev, | 972 | fbi->map_cpu = dma_alloc_writecombine(&pdev->dev, |
849 | fbi->map_size, &fbi->map_dma, GFP_KERNEL); | 973 | fbi->map_size, &fbi->map_dma, GFP_KERNEL); |
@@ -868,18 +992,16 @@ static int __init imxfb_probe(struct platform_device *pdev) | |||
868 | info->fix.smem_start = fbi->screen_dma; | 992 | info->fix.smem_start = fbi->screen_dma; |
869 | } | 993 | } |
870 | 994 | ||
871 | if (pdata->init) { | 995 | if (pdata && pdata->init) { |
872 | ret = pdata->init(fbi->pdev); | 996 | ret = pdata->init(fbi->pdev); |
873 | if (ret) | 997 | if (ret) |
874 | goto failed_platform_init; | 998 | goto failed_platform_init; |
875 | } | 999 | } |
876 | 1000 | ||
877 | fbi->mode = pdata->mode; | ||
878 | fbi->num_modes = pdata->num_modes; | ||
879 | 1001 | ||
880 | INIT_LIST_HEAD(&info->modelist); | 1002 | INIT_LIST_HEAD(&info->modelist); |
881 | for (i = 0; i < pdata->num_modes; i++) | 1003 | for (i = 0; i < fbi->num_modes; i++) |
882 | fb_add_videomode(&pdata->mode[i].mode, &info->modelist); | 1004 | fb_add_videomode(&fbi->mode[i].mode, &info->modelist); |
883 | 1005 | ||
884 | /* | 1006 | /* |
885 | * This makes sure that our colour bitfield | 1007 | * This makes sure that our colour bitfield |
@@ -909,10 +1031,10 @@ static int __init imxfb_probe(struct platform_device *pdev) | |||
909 | failed_register: | 1031 | failed_register: |
910 | fb_dealloc_cmap(&info->cmap); | 1032 | fb_dealloc_cmap(&info->cmap); |
911 | failed_cmap: | 1033 | failed_cmap: |
912 | if (pdata->exit) | 1034 | if (pdata && pdata->exit) |
913 | pdata->exit(fbi->pdev); | 1035 | pdata->exit(fbi->pdev); |
914 | failed_platform_init: | 1036 | failed_platform_init: |
915 | if (!pdata->fixed_screen_cpu) | 1037 | if (pdata && !pdata->fixed_screen_cpu) |
916 | dma_free_writecombine(&pdev->dev,fbi->map_size,fbi->map_cpu, | 1038 | dma_free_writecombine(&pdev->dev,fbi->map_size,fbi->map_cpu, |
917 | fbi->map_dma); | 1039 | fbi->map_dma); |
918 | failed_map: | 1040 | failed_map: |
@@ -921,6 +1043,7 @@ failed_ioremap: | |||
921 | failed_getclock: | 1043 | failed_getclock: |
922 | release_mem_region(res->start, resource_size(res)); | 1044 | release_mem_region(res->start, resource_size(res)); |
923 | failed_req: | 1045 | failed_req: |
1046 | failed_of_parse: | ||
924 | kfree(info->pseudo_palette); | 1047 | kfree(info->pseudo_palette); |
925 | failed_init: | 1048 | failed_init: |
926 | framebuffer_release(info); | 1049 | framebuffer_release(info); |
@@ -944,7 +1067,7 @@ static int imxfb_remove(struct platform_device *pdev) | |||
944 | unregister_framebuffer(info); | 1067 | unregister_framebuffer(info); |
945 | 1068 | ||
946 | pdata = pdev->dev.platform_data; | 1069 | pdata = pdev->dev.platform_data; |
947 | if (pdata->exit) | 1070 | if (pdata && pdata->exit) |
948 | pdata->exit(fbi->pdev); | 1071 | pdata->exit(fbi->pdev); |
949 | 1072 | ||
950 | fb_dealloc_cmap(&info->cmap); | 1073 | fb_dealloc_cmap(&info->cmap); |
@@ -971,6 +1094,7 @@ static struct platform_driver imxfb_driver = { | |||
971 | .shutdown = imxfb_shutdown, | 1094 | .shutdown = imxfb_shutdown, |
972 | .driver = { | 1095 | .driver = { |
973 | .name = DRIVER_NAME, | 1096 | .name = DRIVER_NAME, |
1097 | .of_match_table = imxfb_of_dev_id, | ||
974 | }, | 1098 | }, |
975 | .id_table = imxfb_devtype, | 1099 | .id_table = imxfb_devtype, |
976 | }; | 1100 | }; |