video: mxsfb: get display timings from device tree
authorShawn Guo <shawn.guo@linaro.org>
Thu, 14 Mar 2013 02:57:34 +0000 (10:57 +0800)
committerShawn Guo <shawn.guo@linaro.org>
Thu, 4 Apr 2013 13:22:41 +0000 (21:22 +0800)
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>
Documentation/devicetree/bindings/fb/mxsfb.txt
drivers/video/Kconfig
drivers/video/mxsfb.c

index b41e5e52a676c4cf28f7c0529e9cb64d46a3b0a6..7ba3b76635138b812d0ce134fce41238712a8787 100644 (file)
@@ -5,10 +5,20 @@ Required properties:
   imx23 and imx28.
 - reg: Address and length of the register set for lcdif
 - interrupts: Should contain lcdif interrupts
+- display : phandle to display node (see below for details)
 
 Optional properties:
 - panel-enable-gpios : Should specify the gpio for panel enable
 
+* display node
+
+Required properties:
+- bits-per-pixel : <16> for RGB565, <32> for RGB888/666.
+- bus-width : number of data lines.  Could be <8>, <16>, <18> or <24>.
+
+Required sub-node:
+- display-timings : Refer to binding doc display-timing.txt for details.
+
 Examples:
 
 lcdif@80030000 {
@@ -16,4 +26,28 @@ lcdif@80030000 {
        reg = <0x80030000 2000>;
        interrupts = <38 86>;
        panel-enable-gpios = <&gpio3 30 0>;
+
+       display: display {
+               bits-per-pixel = <32>;
+               bus-width = <24>;
+
+               display-timings {
+                       native-mode = <&timing0>;
+                       timing0: timing0 {
+                               clock-frequency = <33500000>;
+                               hactive = <800>;
+                               vactive = <480>;
+                               hfront-porch = <164>;
+                               hback-porch = <89>;
+                               hsync-len = <10>;
+                               vback-porch = <23>;
+                               vfront-porch = <10>;
+                               vsync-len = <10>;
+                               hsync-active = <0>;
+                               vsync-active = <0>;
+                               de-active = <1>;
+                               pixelclk-active = <0>;
+                       };
+               };
+       };
 };
index 4c1546f71d56a2be51785f3bf02ab50437ac94d6..e7718fdad1e162ad10c3e613008645db486be3a1 100644 (file)
@@ -2437,6 +2437,8 @@ config FB_MXS
        select FB_CFB_FILLRECT
        select FB_CFB_COPYAREA
        select FB_CFB_IMAGEBLIT
+       select FB_MODE_HELPERS
+       select OF_VIDEOMODE
        help
          Framebuffer support for the MXS SoC.
 
index a89901c7f5e9df36529a514730d6db4d0222d11e..e5ceba54d22ff7af553782c33891bc2a33d38873 100644 (file)
 #include <linux/kernel.h>
 #include <linux/of_device.h>
 #include <linux/of_gpio.h>
+#include <video/of_display_timing.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
 #include <linux/dma-mapping.h>
 #include <linux/io.h>
 #include <linux/pinctrl/consumer.h>
 #include <linux/mxsfb.h>
+#include <video/videomode.h>
 
 #define REG_SET        4
 #define REG_CLR        8
@@ -678,6 +680,97 @@ static int mxsfb_restore_mode(struct mxsfb_info *host)
        return 0;
 }
 
+static int mxsfb_init_fbinfo_dt(struct mxsfb_info *host)
+{
+       struct fb_info *fb_info = &host->fb_info;
+       struct fb_var_screeninfo *var = &fb_info->var;
+       struct device *dev = &host->pdev->dev;
+       struct device_node *np = host->pdev->dev.of_node;
+       struct device_node *display_np;
+       struct device_node *timings_np;
+       struct display_timings *timings;
+       u32 width;
+       int i;
+       int ret = 0;
+
+       display_np = of_parse_phandle(np, "display", 0);
+       if (!display_np) {
+               dev_err(dev, "failed to find display phandle\n");
+               return -ENOENT;
+       }
+
+       ret = of_property_read_u32(display_np, "bus-width", &width);
+       if (ret < 0) {
+               dev_err(dev, "failed to get property bus-width\n");
+               goto put_display_node;
+       }
+
+       switch (width) {
+       case 8:
+               host->ld_intf_width = STMLCDIF_8BIT;
+               break;
+       case 16:
+               host->ld_intf_width = STMLCDIF_16BIT;
+               break;
+       case 18:
+               host->ld_intf_width = STMLCDIF_18BIT;
+               break;
+       case 24:
+               host->ld_intf_width = STMLCDIF_24BIT;
+               break;
+       default:
+               dev_err(dev, "invalid bus-width value\n");
+               ret = -EINVAL;
+               goto put_display_node;
+       }
+
+       ret = of_property_read_u32(display_np, "bits-per-pixel",
+                                  &var->bits_per_pixel);
+       if (ret < 0) {
+               dev_err(dev, "failed to get property bits-per-pixel\n");
+               goto put_display_node;
+       }
+
+       timings = of_get_display_timings(display_np);
+       if (!timings) {
+               dev_err(dev, "failed to get display timings\n");
+               ret = -ENOENT;
+               goto put_display_node;
+       }
+
+       timings_np = of_find_node_by_name(display_np,
+                                         "display-timings");
+       if (!timings_np) {
+               dev_err(dev, "failed to find display-timings node\n");
+               ret = -ENOENT;
+               goto put_display_node;
+       }
+
+       for (i = 0; i < of_get_child_count(timings_np); i++) {
+               struct videomode vm;
+               struct fb_videomode fb_vm;
+
+               ret = videomode_from_timing(timings, &vm, i);
+               if (ret < 0)
+                       goto put_timings_node;
+               ret = fb_videomode_from_videomode(&vm, &fb_vm);
+               if (ret < 0)
+                       goto put_timings_node;
+
+               if (vm.data_flags & DISPLAY_FLAGS_DE_HIGH)
+                       host->sync |= MXSFB_SYNC_DATA_ENABLE_HIGH_ACT;
+               if (vm.data_flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE)
+                       host->sync |= MXSFB_SYNC_DOTCLK_FAILING_ACT;
+               fb_add_videomode(&fb_vm, &fb_info->modelist);
+       }
+
+put_timings_node:
+       of_node_put(timings_np);
+put_display_node:
+       of_node_put(display_np);
+       return ret;
+}
+
 static int mxsfb_init_fbinfo(struct mxsfb_info *host)
 {
        struct fb_info *fb_info = &host->fb_info;
@@ -686,6 +779,7 @@ static int mxsfb_init_fbinfo(struct mxsfb_info *host)
        dma_addr_t fb_phys;
        void *fb_virt;
        unsigned fb_size;
+       int ret;
 
        fb_info->fbops = &mxsfb_ops;
        fb_info->flags = FBINFO_FLAG_DEFAULT | FBINFO_READS_FAST;
@@ -695,14 +789,21 @@ static int mxsfb_init_fbinfo(struct mxsfb_info *host)
        fb_info->fix.visual = FB_VISUAL_TRUECOLOR,
        fb_info->fix.accel = FB_ACCEL_NONE;
 
-       var->bits_per_pixel = pdata->default_bpp ? pdata->default_bpp : 16;
+       if (pdata) {
+               host->ld_intf_width = pdata->ld_intf_width;
+               var->bits_per_pixel =
+                       pdata->default_bpp ? pdata->default_bpp : 16;
+       } else {
+               ret = mxsfb_init_fbinfo_dt(host);
+               if (ret)
+                       return ret;
+       }
+
        var->nonstd = 0;
        var->activate = FB_ACTIVATE_NOW;
        var->accel_flags = 0;
        var->vmode = FB_VMODE_NONINTERLACED;
 
-       host->ld_intf_width = pdata->ld_intf_width;
-
        /* Memory allocation for framebuffer */
        fb_size = SZ_2M;
        fb_virt = alloc_pages_exact(fb_size, GFP_DMA);
@@ -765,11 +866,6 @@ static int mxsfb_probe(struct platform_device *pdev)
        if (of_id)
                pdev->id_entry = of_id->data;
 
-       if (!pdata) {
-               dev_err(&pdev->dev, "No platformdata. Giving up\n");
-               return -ENODEV;
-       }
-
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!res) {
                dev_err(&pdev->dev, "Cannot get memory IO resource\n");
@@ -833,14 +929,16 @@ static int mxsfb_probe(struct platform_device *pdev)
 
        INIT_LIST_HEAD(&fb_info->modelist);
 
-       host->sync = pdata->sync;
-
        ret = mxsfb_init_fbinfo(host);
        if (ret != 0)
                goto fb_release;
 
-       for (i = 0; i < pdata->mode_count; i++)
-               fb_add_videomode(&pdata->mode_list[i], &fb_info->modelist);
+       if (pdata) {
+               host->sync = pdata->sync;
+               for (i = 0; i < pdata->mode_count; i++)
+                       fb_add_videomode(&pdata->mode_list[i],
+                                        &fb_info->modelist);
+       }
 
        modelist = list_first_entry(&fb_info->modelist,
                        struct fb_modelist, list);