diff options
author | Shawn Guo <shawn.guo@linaro.org> | 2013-03-13 22:57:34 -0400 |
---|---|---|
committer | Shawn Guo <shawn.guo@linaro.org> | 2013-04-04 09:22:41 -0400 |
commit | 669406534b4abb827d1bdc39bb5e2d5255818ae2 (patch) | |
tree | 0999716da16a54cb37f66c1f7ebf75b025a1852b /drivers/video/mxsfb.c | |
parent | 36f3e99649baa77b2d22e385b2ea09e8f308c905 (diff) |
video: mxsfb: get display timings from device tree
Use videomode helpers to get display timings and configurations from
device tree when platform_data is absent.
Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
Diffstat (limited to 'drivers/video/mxsfb.c')
-rw-r--r-- | drivers/video/mxsfb.c | 122 |
1 files changed, 110 insertions, 12 deletions
diff --git a/drivers/video/mxsfb.c b/drivers/video/mxsfb.c index a89901c7f5e9..e5ceba54d22f 100644 --- a/drivers/video/mxsfb.c +++ b/drivers/video/mxsfb.c | |||
@@ -43,12 +43,14 @@ | |||
43 | #include <linux/kernel.h> | 43 | #include <linux/kernel.h> |
44 | #include <linux/of_device.h> | 44 | #include <linux/of_device.h> |
45 | #include <linux/of_gpio.h> | 45 | #include <linux/of_gpio.h> |
46 | #include <video/of_display_timing.h> | ||
46 | #include <linux/platform_device.h> | 47 | #include <linux/platform_device.h> |
47 | #include <linux/clk.h> | 48 | #include <linux/clk.h> |
48 | #include <linux/dma-mapping.h> | 49 | #include <linux/dma-mapping.h> |
49 | #include <linux/io.h> | 50 | #include <linux/io.h> |
50 | #include <linux/pinctrl/consumer.h> | 51 | #include <linux/pinctrl/consumer.h> |
51 | #include <linux/mxsfb.h> | 52 | #include <linux/mxsfb.h> |
53 | #include <video/videomode.h> | ||
52 | 54 | ||
53 | #define REG_SET 4 | 55 | #define REG_SET 4 |
54 | #define REG_CLR 8 | 56 | #define REG_CLR 8 |
@@ -678,6 +680,97 @@ static int mxsfb_restore_mode(struct mxsfb_info *host) | |||
678 | return 0; | 680 | return 0; |
679 | } | 681 | } |
680 | 682 | ||
683 | static int mxsfb_init_fbinfo_dt(struct mxsfb_info *host) | ||
684 | { | ||
685 | struct fb_info *fb_info = &host->fb_info; | ||
686 | struct fb_var_screeninfo *var = &fb_info->var; | ||
687 | struct device *dev = &host->pdev->dev; | ||
688 | struct device_node *np = host->pdev->dev.of_node; | ||
689 | struct device_node *display_np; | ||
690 | struct device_node *timings_np; | ||
691 | struct display_timings *timings; | ||
692 | u32 width; | ||
693 | int i; | ||
694 | int ret = 0; | ||
695 | |||
696 | display_np = of_parse_phandle(np, "display", 0); | ||
697 | if (!display_np) { | ||
698 | dev_err(dev, "failed to find display phandle\n"); | ||
699 | return -ENOENT; | ||
700 | } | ||
701 | |||
702 | ret = of_property_read_u32(display_np, "bus-width", &width); | ||
703 | if (ret < 0) { | ||
704 | dev_err(dev, "failed to get property bus-width\n"); | ||
705 | goto put_display_node; | ||
706 | } | ||
707 | |||
708 | switch (width) { | ||
709 | case 8: | ||
710 | host->ld_intf_width = STMLCDIF_8BIT; | ||
711 | break; | ||
712 | case 16: | ||
713 | host->ld_intf_width = STMLCDIF_16BIT; | ||
714 | break; | ||
715 | case 18: | ||
716 | host->ld_intf_width = STMLCDIF_18BIT; | ||
717 | break; | ||
718 | case 24: | ||
719 | host->ld_intf_width = STMLCDIF_24BIT; | ||
720 | break; | ||
721 | default: | ||
722 | dev_err(dev, "invalid bus-width value\n"); | ||
723 | ret = -EINVAL; | ||
724 | goto put_display_node; | ||
725 | } | ||
726 | |||
727 | ret = of_property_read_u32(display_np, "bits-per-pixel", | ||
728 | &var->bits_per_pixel); | ||
729 | if (ret < 0) { | ||
730 | dev_err(dev, "failed to get property bits-per-pixel\n"); | ||
731 | goto put_display_node; | ||
732 | } | ||
733 | |||
734 | timings = of_get_display_timings(display_np); | ||
735 | if (!timings) { | ||
736 | dev_err(dev, "failed to get display timings\n"); | ||
737 | ret = -ENOENT; | ||
738 | goto put_display_node; | ||
739 | } | ||
740 | |||
741 | timings_np = of_find_node_by_name(display_np, | ||
742 | "display-timings"); | ||
743 | if (!timings_np) { | ||
744 | dev_err(dev, "failed to find display-timings node\n"); | ||
745 | ret = -ENOENT; | ||
746 | goto put_display_node; | ||
747 | } | ||
748 | |||
749 | for (i = 0; i < of_get_child_count(timings_np); i++) { | ||
750 | struct videomode vm; | ||
751 | struct fb_videomode fb_vm; | ||
752 | |||
753 | ret = videomode_from_timing(timings, &vm, i); | ||
754 | if (ret < 0) | ||
755 | goto put_timings_node; | ||
756 | ret = fb_videomode_from_videomode(&vm, &fb_vm); | ||
757 | if (ret < 0) | ||
758 | goto put_timings_node; | ||
759 | |||
760 | if (vm.data_flags & DISPLAY_FLAGS_DE_HIGH) | ||
761 | host->sync |= MXSFB_SYNC_DATA_ENABLE_HIGH_ACT; | ||
762 | if (vm.data_flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE) | ||
763 | host->sync |= MXSFB_SYNC_DOTCLK_FAILING_ACT; | ||
764 | fb_add_videomode(&fb_vm, &fb_info->modelist); | ||
765 | } | ||
766 | |||
767 | put_timings_node: | ||
768 | of_node_put(timings_np); | ||
769 | put_display_node: | ||
770 | of_node_put(display_np); | ||
771 | return ret; | ||
772 | } | ||
773 | |||
681 | static int mxsfb_init_fbinfo(struct mxsfb_info *host) | 774 | static int mxsfb_init_fbinfo(struct mxsfb_info *host) |
682 | { | 775 | { |
683 | struct fb_info *fb_info = &host->fb_info; | 776 | struct fb_info *fb_info = &host->fb_info; |
@@ -686,6 +779,7 @@ static int mxsfb_init_fbinfo(struct mxsfb_info *host) | |||
686 | dma_addr_t fb_phys; | 779 | dma_addr_t fb_phys; |
687 | void *fb_virt; | 780 | void *fb_virt; |
688 | unsigned fb_size; | 781 | unsigned fb_size; |
782 | int ret; | ||
689 | 783 | ||
690 | fb_info->fbops = &mxsfb_ops; | 784 | fb_info->fbops = &mxsfb_ops; |
691 | fb_info->flags = FBINFO_FLAG_DEFAULT | FBINFO_READS_FAST; | 785 | fb_info->flags = FBINFO_FLAG_DEFAULT | FBINFO_READS_FAST; |
@@ -695,14 +789,21 @@ static int mxsfb_init_fbinfo(struct mxsfb_info *host) | |||
695 | fb_info->fix.visual = FB_VISUAL_TRUECOLOR, | 789 | fb_info->fix.visual = FB_VISUAL_TRUECOLOR, |
696 | fb_info->fix.accel = FB_ACCEL_NONE; | 790 | fb_info->fix.accel = FB_ACCEL_NONE; |
697 | 791 | ||
698 | var->bits_per_pixel = pdata->default_bpp ? pdata->default_bpp : 16; | 792 | if (pdata) { |
793 | host->ld_intf_width = pdata->ld_intf_width; | ||
794 | var->bits_per_pixel = | ||
795 | pdata->default_bpp ? pdata->default_bpp : 16; | ||
796 | } else { | ||
797 | ret = mxsfb_init_fbinfo_dt(host); | ||
798 | if (ret) | ||
799 | return ret; | ||
800 | } | ||
801 | |||
699 | var->nonstd = 0; | 802 | var->nonstd = 0; |
700 | var->activate = FB_ACTIVATE_NOW; | 803 | var->activate = FB_ACTIVATE_NOW; |
701 | var->accel_flags = 0; | 804 | var->accel_flags = 0; |
702 | var->vmode = FB_VMODE_NONINTERLACED; | 805 | var->vmode = FB_VMODE_NONINTERLACED; |
703 | 806 | ||
704 | host->ld_intf_width = pdata->ld_intf_width; | ||
705 | |||
706 | /* Memory allocation for framebuffer */ | 807 | /* Memory allocation for framebuffer */ |
707 | fb_size = SZ_2M; | 808 | fb_size = SZ_2M; |
708 | fb_virt = alloc_pages_exact(fb_size, GFP_DMA); | 809 | fb_virt = alloc_pages_exact(fb_size, GFP_DMA); |
@@ -765,11 +866,6 @@ static int mxsfb_probe(struct platform_device *pdev) | |||
765 | if (of_id) | 866 | if (of_id) |
766 | pdev->id_entry = of_id->data; | 867 | pdev->id_entry = of_id->data; |
767 | 868 | ||
768 | if (!pdata) { | ||
769 | dev_err(&pdev->dev, "No platformdata. Giving up\n"); | ||
770 | return -ENODEV; | ||
771 | } | ||
772 | |||
773 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 869 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
774 | if (!res) { | 870 | if (!res) { |
775 | dev_err(&pdev->dev, "Cannot get memory IO resource\n"); | 871 | dev_err(&pdev->dev, "Cannot get memory IO resource\n"); |
@@ -833,14 +929,16 @@ static int mxsfb_probe(struct platform_device *pdev) | |||
833 | 929 | ||
834 | INIT_LIST_HEAD(&fb_info->modelist); | 930 | INIT_LIST_HEAD(&fb_info->modelist); |
835 | 931 | ||
836 | host->sync = pdata->sync; | ||
837 | |||
838 | ret = mxsfb_init_fbinfo(host); | 932 | ret = mxsfb_init_fbinfo(host); |
839 | if (ret != 0) | 933 | if (ret != 0) |
840 | goto fb_release; | 934 | goto fb_release; |
841 | 935 | ||
842 | for (i = 0; i < pdata->mode_count; i++) | 936 | if (pdata) { |
843 | fb_add_videomode(&pdata->mode_list[i], &fb_info->modelist); | 937 | host->sync = pdata->sync; |
938 | for (i = 0; i < pdata->mode_count; i++) | ||
939 | fb_add_videomode(&pdata->mode_list[i], | ||
940 | &fb_info->modelist); | ||
941 | } | ||
844 | 942 | ||
845 | modelist = list_first_entry(&fb_info->modelist, | 943 | modelist = list_first_entry(&fb_info->modelist, |
846 | struct fb_modelist, list); | 944 | struct fb_modelist, list); |