rk3036 lcdc: commit driver code, just pass compiling.
[firefly-linux-kernel-4.4.55.git] / drivers / video / rockchip / rk_fb.c
index c48781212fe38c0ffa07d9377b6522107d1c4f2f..57d6a8631ac0415890c13184e9a9a77a20b2d67c 100755 (executable)
@@ -2,7 +2,7 @@
  * drivers/video/rockchip/rk_fb.c
  *
  * Copyright (C) ROCKCHIP, Inc.
- *Author:yxj<yxj@rock-chips.com>
+ * Author:yxj<yxj@rock-chips.com>
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
  * may be copied, distributed, and modified under those terms.
 #include <linux/linux_logo.h>
 #include <linux/dma-mapping.h>
 
-
 #if defined(CONFIG_RK_HDMI)
 #include "hdmi/rk_hdmi.h"
 #endif
 
+#if defined(CONFIG_ROCKCHIP_RGA) || defined(CONFIG_ROCKCHIP_RGA2)
+#include "rga/rga.h"
+#endif
+
 #ifdef CONFIG_OF
 #include <linux/of.h>
 #include <linux/of_gpio.h>
 
 #if defined(CONFIG_ION_ROCKCHIP)
 #include <linux/rockchip_ion.h>
+#include <linux/rockchip/iovmm.h>
+#include <linux/rockchip/sysmmu.h>
+#include <linux/dma-buf.h>
+#include <linux/highmem.h>
 #endif
 
-
+#define H_USE_FENCE 1
 static int hdmi_switch_complete;
 static struct platform_device *fb_pdev;
 struct list_head saved_list;
 
 #if defined(CONFIG_FB_MIRRORING)
-int (*video_data_to_mirroring)(struct fb_info *info, u32 yuv_phy[2]);
+int (*video_data_to_mirroring) (struct fb_info *info, u32 yuv_phy[2]);
 EXPORT_SYMBOL(video_data_to_mirroring);
 #endif
 
-
+struct rk_fb_reg_win_data g_reg_win_data[4];
+static int g_last_win_num;
+static int g_first_buf = 1;
 static struct rk_fb_trsm_ops *trsm_lvds_ops;
 static struct rk_fb_trsm_ops *trsm_edp_ops;
 static struct rk_fb_trsm_ops *trsm_mipi_ops;
+static int uboot_logo_on;
+int support_uboot_display(void)
+{
+       return uboot_logo_on;
+}
 
 int rk_fb_trsm_ops_register(struct rk_fb_trsm_ops *ops, int type)
 {
@@ -79,7 +93,7 @@ int rk_fb_trsm_ops_register(struct rk_fb_trsm_ops *ops, int type)
                break;
        default:
                printk(KERN_WARNING "%s:un supported transmitter:%d!\n",
-                       __func__, type);
+                      __func__, type);
                break;
        }
        return 0;
@@ -104,7 +118,7 @@ struct rk_fb_trsm_ops *rk_fb_trsm_ops_get(int type)
        default:
                ops = NULL;
                printk(KERN_WARNING "%s:un supported transmitter:%d!\n",
-                       __func__, type);
+                      __func__, type);
                break;
        }
        return ops;
@@ -113,41 +127,48 @@ struct rk_fb_trsm_ops *rk_fb_trsm_ops_get(int type)
 int rk_fb_pixel_width(int data_format)
 {
        int pixel_width;
-       switch(data_format){
+       switch (data_format) {
        case XBGR888:
        case ABGR888:
        case ARGB888:
-               pixel_width = 4*8;
+               pixel_width = 4 * 8;
                break;
        case RGB888:
-               pixel_width = 3*8;
+               pixel_width = 3 * 8;
                break;
        case RGB565:
-               pixel_width = 2*8;
+               pixel_width = 2 * 8;
                break;
        case YUV422:
        case YUV420:
        case YUV444:
-               pixel_width = 1*8;
+               pixel_width = 1 * 8;
+               break;
+       case YUV422_A:
+       case YUV420_A:
+       case YUV444_A:
+               pixel_width = 8;
                break;
        default:
+               printk(KERN_WARNING "%s:un supported format:0x%x\n",
+                      __func__, data_format);
                return -EINVAL;
        }
        return pixel_width;
 }
 
-static int rk_fb_data_fmt(int data_format,int bits_per_pixel)
+static int rk_fb_data_fmt(int data_format, int bits_per_pixel)
 {
        int fb_data_fmt;
-       if(data_format){
-               switch(data_format){
-               case HAL_PIXEL_FORMAT_RGBX_8888: 
+       if (data_format) {
+               switch (data_format) {
+               case HAL_PIXEL_FORMAT_RGBX_8888:
                        fb_data_fmt = XBGR888;
                        break;
                case HAL_PIXEL_FORMAT_RGBA_8888:
                        fb_data_fmt = ABGR888;
                        break;
-               case HAL_PIXEL_FORMAT_BGRA_8888: 
+               case HAL_PIXEL_FORMAT_BGRA_8888:
                        fb_data_fmt = ARGB888;
                        break;
                case HAL_PIXEL_FORMAT_RGB_888:
@@ -156,21 +177,31 @@ static int rk_fb_data_fmt(int data_format,int bits_per_pixel)
                case HAL_PIXEL_FORMAT_RGB_565:
                        fb_data_fmt = RGB565;
                        break;
-               case HAL_PIXEL_FORMAT_YCbCr_422_SP: // yuv422
+               case HAL_PIXEL_FORMAT_YCbCr_422_SP:     /* yuv422 */
                        fb_data_fmt = YUV422;
                        break;
-               case HAL_PIXEL_FORMAT_YCrCb_NV12: // YUV420---uvuvuv
+               case HAL_PIXEL_FORMAT_YCrCb_NV12:       /* YUV420---uvuvuv */
                        fb_data_fmt = YUV420;
                        break;
-               case HAL_PIXEL_FORMAT_YCrCb_444: // yuv444
+               case HAL_PIXEL_FORMAT_YCrCb_444:        /* yuv444 */
                        fb_data_fmt = YUV444;
                        break;
+               case HAL_PIXEL_FORMAT_YCrCb_NV12_10:    /* yuv444 */
+                       fb_data_fmt = YUV420_A;
+                       break;
+               case HAL_PIXEL_FORMAT_YCbCr_422_SP_10:  /* yuv444 */
+                       fb_data_fmt = YUV422_A;
+                       break;
+               case HAL_PIXEL_FORMAT_YCrCb_420_SP_10:  /* yuv444 */
+                       fb_data_fmt = YUV444_A;
+                       break;
                default:
-                       printk("%s:un supported format:0x%x\n",__func__,data_format);
-                   return -EINVAL;
+                       printk(KERN_WARNING "%s:un supported format:0x%x\n",
+                              __func__, data_format);
+                       return -EINVAL;
                }
-       }else{
-               switch(bits_per_pixel){
+       } else {
+               switch (bits_per_pixel) {
                case 32:
                        fb_data_fmt = ARGB888;
                        break;
@@ -178,19 +209,22 @@ static int rk_fb_data_fmt(int data_format,int bits_per_pixel)
                        fb_data_fmt = RGB565;
                        break;
                default:
+                       printk(KERN_WARNING
+                              "%s:un supported bits_per_pixel:%d\n", __func__,
+                              bits_per_pixel);
                        break;
                }
        }
        return fb_data_fmt;
 }
 
-/* rk display power control parse from dts
- *
-*/
+/*
+ * rk display power control parse from dts
+ */
 int rk_disp_pwr_ctr_parse_dt(struct rk_lcdc_driver *dev_drv)
 {
-       struct device_node *root  = of_get_child_by_name(dev_drv->dev->of_node,
-                               "power_ctr");
+       struct device_node *root = of_get_child_by_name(dev_drv->dev->of_node,
+                                                       "power_ctr");
        struct device_node *child;
        struct rk_disp_pwr_ctr_list *pwr_ctr;
        struct list_head *pos;
@@ -201,26 +235,31 @@ int rk_disp_pwr_ctr_parse_dt(struct rk_lcdc_driver *dev_drv)
 
        INIT_LIST_HEAD(&dev_drv->pwrlist_head);
        if (!root) {
-               dev_err(dev_drv->dev, "can't find power_ctr node for lcdc%d\n",dev_drv->id);
+               dev_err(dev_drv->dev, "can't find power_ctr node for lcdc%d\n",
+                       dev_drv->id);
                return -ENODEV;
        }
 
        for_each_child_of_node(root, child) {
-               pwr_ctr = kmalloc(sizeof(struct rk_disp_pwr_ctr_list), GFP_KERNEL);
+               pwr_ctr = kmalloc(sizeof(struct rk_disp_pwr_ctr_list),
+                                 GFP_KERNEL);
                strcpy(pwr_ctr->pwr_ctr.name, child->name);
                if (!of_property_read_u32(child, "rockchip,power_type", &val)) {
                        if (val == GPIO) {
                                pwr_ctr->pwr_ctr.type = GPIO;
                                pwr_ctr->pwr_ctr.gpio = of_get_gpio_flags(child, 0, &flags);
                                if (!gpio_is_valid(pwr_ctr->pwr_ctr.gpio)) {
-                                       dev_err(dev_drv->dev, "%s ivalid gpio\n", child->name);
+                                       dev_err(dev_drv->dev, "%s ivalid gpio\n",
+                                               child->name);
                                        return -EINVAL;
                                }
                                pwr_ctr->pwr_ctr.atv_val = !(flags & OF_GPIO_ACTIVE_LOW);
-                               ret = gpio_request(pwr_ctr->pwr_ctr.gpio,child->name);
+                               ret = gpio_request(pwr_ctr->pwr_ctr.gpio,
+                                                  child->name);
                                if (ret) {
-                                       dev_err(dev_drv->dev, "request %s gpio fail:%d\n",
-                                               child->name,ret);
+                                       dev_err(dev_drv->dev,
+                                               "request %s gpio fail:%d\n",
+                                               child->name, ret);
                                }
 
                        } else {
@@ -237,17 +276,18 @@ int rk_disp_pwr_ctr_parse_dt(struct rk_lcdc_driver *dev_drv)
 
        if (debug) {
                list_for_each(pos, &dev_drv->pwrlist_head) {
-                       pwr_ctr = list_entry(pos, struct rk_disp_pwr_ctr_list, list);
+                       pwr_ctr = list_entry(pos, struct rk_disp_pwr_ctr_list,
+                                            list);
                        printk(KERN_INFO "pwr_ctr_name:%s\n"
-                                        "pwr_type:%s\n"
-                                        "gpio:%d\n"
-                                        "atv_val:%d\n"
-                                        "delay:%d\n\n",
-                                        pwr_ctr->pwr_ctr.name,
-                                        (pwr_ctr->pwr_ctr.type == GPIO) ? "gpio" : "regulator",
-                                        pwr_ctr->pwr_ctr.gpio,
-                                        pwr_ctr->pwr_ctr.atv_val,
-                                        pwr_ctr->pwr_ctr.delay);
+                              "pwr_type:%s\n"
+                              "gpio:%d\n"
+                              "atv_val:%d\n"
+                              "delay:%d\n\n",
+                              pwr_ctr->pwr_ctr.name,
+                              (pwr_ctr->pwr_ctr.type == GPIO) ? "gpio" : "regulator",
+                              pwr_ctr->pwr_ctr.gpio,
+                              pwr_ctr->pwr_ctr.atv_val,
+                              pwr_ctr->pwr_ctr.delay);
                }
        }
 
@@ -263,10 +303,11 @@ int rk_disp_pwr_enable(struct rk_lcdc_driver *dev_drv)
        if (list_empty(&dev_drv->pwrlist_head))
                return 0;
        list_for_each(pos, &dev_drv->pwrlist_head) {
-               pwr_ctr_list = list_entry(pos, struct rk_disp_pwr_ctr_list, list);
+               pwr_ctr_list = list_entry(pos, struct rk_disp_pwr_ctr_list,
+                                         list);
                pwr_ctr = &pwr_ctr_list->pwr_ctr;
                if (pwr_ctr->type == GPIO) {
-                       gpio_direction_output(pwr_ctr->gpio,pwr_ctr->atv_val);
+                       gpio_direction_output(pwr_ctr->gpio, pwr_ctr->atv_val);
                        mdelay(pwr_ctr->delay);
                }
        }
@@ -282,18 +323,17 @@ int rk_disp_pwr_disable(struct rk_lcdc_driver *dev_drv)
        if (list_empty(&dev_drv->pwrlist_head))
                return 0;
        list_for_each(pos, &dev_drv->pwrlist_head) {
-               pwr_ctr_list = list_entry(pos, struct rk_disp_pwr_ctr_list, list);
+               pwr_ctr_list = list_entry(pos, struct rk_disp_pwr_ctr_list,
+                                         list);
                pwr_ctr = &pwr_ctr_list->pwr_ctr;
-               if (pwr_ctr->type == GPIO) {
-                       gpio_set_value(pwr_ctr->gpio,pwr_ctr->atv_val);
-               }
+               if (pwr_ctr->type == GPIO)
+                       gpio_set_value(pwr_ctr->gpio, !pwr_ctr->atv_val);
        }
-
        return 0;
 }
 
-int rk_fb_video_mode_from_timing(const struct display_timing *dt, 
-                               struct rk_screen *screen)
+int rk_fb_video_mode_from_timing(const struct display_timing *dt,
+                                struct rk_screen *screen)
 {
        screen->mode.pixclock = dt->pixelclock.typ;
        screen->mode.left_margin = dt->hback_porch.typ;
@@ -312,21 +352,21 @@ int rk_fb_video_mode_from_timing(const struct display_timing *dt,
                screen->pin_dclk = 1;
        else
                screen->pin_dclk = 0;
-       if(dt->flags & DISPLAY_FLAGS_HSYNC_HIGH)
+       if (dt->flags & DISPLAY_FLAGS_HSYNC_HIGH)
                screen->pin_hsync = 1;
        else
                screen->pin_hsync = 0;
-       if(dt->flags & DISPLAY_FLAGS_VSYNC_HIGH)
+       if (dt->flags & DISPLAY_FLAGS_VSYNC_HIGH)
                screen->pin_vsync = 1;
        else
                screen->pin_vsync = 0;
-       if(dt->flags & DISPLAY_FLAGS_DE_HIGH)
+       if (dt->flags & DISPLAY_FLAGS_DE_HIGH)
                screen->pin_den = 1;
        else
                screen->pin_den = 0;
-       
+
        return 0;
-       
+
 }
 
 int rk_fb_prase_timing_dt(struct device_node *np, struct rk_screen *screen)
@@ -340,35 +380,11 @@ int rk_fb_prase_timing_dt(struct device_node *np, struct rk_screen *screen)
        }
        dt = display_timings_get(disp_timing, 0);
        rk_fb_video_mode_from_timing(dt, screen);
-       printk(KERN_DEBUG "dclk:%d\n"
-                        "hactive:%d\n"
-                        "hback_porch:%d\n"
-                        "hfront_porch:%d\n"
-                        "hsync_len:%d\n"
-                        "vactive:%d\n"
-                        "vback_porch:%d\n"
-                        "vfront_porch:%d\n"
-                        "vsync_len:%d\n"
-                        "screen_type:%d\n"
-                        "lvds_format:%d\n"
-                        "face:%d\n",
-                       dt->pixelclock.typ,
-                       dt->hactive.typ,
-                       dt->hback_porch.typ,
-                       dt->hfront_porch.typ,
-                       dt->hsync_len.typ,
-                       dt->vactive.typ,
-                       dt->vback_porch.typ,
-                       dt->vfront_porch.typ,
-                       dt->vsync_len.typ,
-                       dt->screen_type,
-                       dt->lvds_format,
-                       dt->face);
        return 0;
 
 }
 
-int  rk_fb_calc_fps(struct rk_screen * screen, u32 pixclock)
+int rk_fb_calc_fps(struct rk_screen *screen, u32 pixclock)
 {
        int x, y;
        unsigned long long hz;
@@ -376,10 +392,10 @@ int  rk_fb_calc_fps(struct rk_screen * screen, u32 pixclock)
                printk(KERN_ERR "%s:null screen!\n", __func__);
                return 0;
        }
-       x = screen->mode.xres + screen->mode.left_margin + screen->mode.right_margin +
-           screen->mode.hsync_len;
-       y = screen->mode.yres + screen->mode.upper_margin + screen->mode.lower_margin +
-           screen->mode.vsync_len;
+       x = screen->mode.xres + screen->mode.left_margin +
+           screen->mode.right_margin + screen->mode.hsync_len;
+       y = screen->mode.yres + screen->mode.upper_margin +
+           screen->mode.lower_margin + screen->mode.vsync_len;
 
        hz = 1000000000000ULL;  /* 1e12 picoseconds per second */
 
@@ -415,6 +431,15 @@ char *get_format_string(enum data_format format, char *fmt)
        case YUV444:
                strcpy(fmt, "YUV444");
                break;
+       case YUV420_A:
+               strcpy(fmt, "YUV420_A");
+               break;
+       case YUV422_A:
+               strcpy(fmt, "YUV422_A");
+               break;
+       case YUV444_A:
+               strcpy(fmt, "YUV444_A");
+               break;
        case XRGB888:
                strcpy(fmt, "XRGB888");
                break;
@@ -433,15 +458,13 @@ char *get_format_string(enum data_format format, char *fmt)
 
 }
 
-
-
-/**********************************************************************
-this is for hdmi
-name: lcdc device name ,lcdc0 , lcdc1
-***********************************************************************/
+/*
+ * this is for hdmi
+ * name: lcdc device name ,lcdc0 , lcdc1
+ */
 struct rk_lcdc_driver *rk_get_lcdc_drv(char *name)
 {
-       struct rk_fb *inf =  platform_get_drvdata(fb_pdev);
+       struct rk_fb *inf = platform_get_drvdata(fb_pdev);
        int i = 0;
        for (i = 0; i < inf->num_lcdc; i++) {
                if (!strcmp(inf->lcdc_dev_drv[i]->name, name))
@@ -463,7 +486,7 @@ static struct rk_lcdc_driver *rk_get_prmry_lcdc_drv(void)
                return NULL;
 
        for (i = 0; i < inf->num_lcdc; i++) {
-               if (inf->lcdc_dev_drv[i]->prop ==  PRMRY) {
+               if (inf->lcdc_dev_drv[i]->prop == PRMRY) {
                        dev_drv = inf->lcdc_dev_drv[i];
                        break;
                }
@@ -472,28 +495,82 @@ static struct rk_lcdc_driver *rk_get_prmry_lcdc_drv(void)
        return dev_drv;
 }
 
+/*
+ * get one frame time of the prmry screen, unit: us
+ */
+u32 rk_fb_get_prmry_screen_ft(void)
+{
+       struct rk_lcdc_driver *dev_drv = rk_get_prmry_lcdc_drv();
+       uint32_t htotal, vtotal, pixclock_ps;
+       u64 pix_total, ft_us;
+
+       if (unlikely(!dev_drv))
+               return 0;
+
+       pixclock_ps = dev_drv->pixclock;
+
+       vtotal = (dev_drv->cur_screen->mode.upper_margin +
+                dev_drv->cur_screen->mode.lower_margin +
+                dev_drv->cur_screen->mode.yres +
+                dev_drv->cur_screen->mode.vsync_len);
+       htotal = (dev_drv->cur_screen->mode.left_margin +
+                dev_drv->cur_screen->mode.right_margin +
+                dev_drv->cur_screen->mode.xres +
+                dev_drv->cur_screen->mode.hsync_len);
+       pix_total = htotal * vtotal;
+       ft_us = pix_total * pixclock_ps;
+       do_div(ft_us, 1000000);
+       if (dev_drv->frame_time.ft == 0)
+               dev_drv->frame_time.ft = ft_us;
+
+       ft_us = dev_drv->frame_time.framedone_t - dev_drv->frame_time.last_framedone_t;
+       do_div(ft_us, 1000);
+       ft_us = min(dev_drv->frame_time.ft, (u32)ft_us);
+       if (ft_us != 0)
+               dev_drv->frame_time.ft = ft_us;
 
-int rk_fb_get_prmry_screen_ft(void)
+       return dev_drv->frame_time.ft;
+}
+
+/*
+ * get the vblanking time of the prmry screen, unit: us
+ */
+u32 rk_fb_get_prmry_screen_vbt(void)
 {
        struct rk_lcdc_driver *dev_drv = rk_get_prmry_lcdc_drv();
-       uint32_t htotal, vtotal, pix_total, ft_us, dclk_mhz;
+       uint32_t htotal, vblank, pixclock_ps;
+       u64 pix_blank, vbt_us;
 
        if (unlikely(!dev_drv))
                return 0;
 
-       dclk_mhz = dev_drv->pixclock/(1000*1000);
+       pixclock_ps = dev_drv->pixclock;
+
+       htotal = (dev_drv->cur_screen->mode.left_margin +
+                dev_drv->cur_screen->mode.right_margin +
+                dev_drv->cur_screen->mode.xres +
+                dev_drv->cur_screen->mode.hsync_len);
+       vblank = (dev_drv->cur_screen->mode.upper_margin +
+                dev_drv->cur_screen->mode.lower_margin +
+                dev_drv->cur_screen->mode.vsync_len);
+       pix_blank = htotal * vblank;
+       vbt_us = pix_blank * pixclock_ps;
+       do_div(vbt_us, 1000000);
+       return (u32)vbt_us;
+}
 
-       htotal = (dev_drv->cur_screen->mode.upper_margin + dev_drv->cur_screen->mode.lower_margin +
-               dev_drv->cur_screen->mode.yres + dev_drv->cur_screen->mode.vsync_len);
-       vtotal = (dev_drv->cur_screen->mode.left_margin + dev_drv->cur_screen->mode.right_margin +
-               dev_drv->cur_screen->mode.xres + dev_drv->cur_screen->mode.hsync_len);
-       pix_total = htotal*vtotal;
-       ft_us = pix_total / dclk_mhz;
+/*
+ * get the frame done time of the prmry screen, unit: us
+ */
+u64 rk_fb_get_prmry_screen_framedone_t(void)
+{
+       struct rk_lcdc_driver *dev_drv = rk_get_prmry_lcdc_drv();
 
-       return ft_us;
+       return dev_drv->frame_time.framedone_t;
 }
 
-static struct rk_lcdc_driver  *rk_get_extend_lcdc_drv(void)
+#if 0
+static struct rk_lcdc_driver *rk_get_extend_lcdc_drv(void)
 {
        struct rk_fb *inf = NULL;
        struct rk_lcdc_driver *dev_drv = NULL;
@@ -513,7 +590,7 @@ static struct rk_lcdc_driver  *rk_get_extend_lcdc_drv(void)
 
        return dev_drv;
 }
-
+#endif
 
 u32 rk_fb_get_prmry_screen_pixclock(void)
 {
@@ -536,28 +613,47 @@ int rk_fb_poll_prmry_screen_vblank(void)
 bool rk_fb_poll_wait_frame_complete(void)
 {
        uint32_t timeout = RK_LF_MAX_TIMEOUT;
-       if (rk_fb_poll_prmry_screen_vblank() == RK_LF_STATUS_NC)
-               return false;
+       struct rk_lcdc_driver *dev_drv = rk_get_prmry_lcdc_drv();
 
-       while (!(rk_fb_poll_prmry_screen_vblank() == RK_LF_STATUS_FR)  &&  --timeout);
-       while (!(rk_fb_poll_prmry_screen_vblank() == RK_LF_STATUS_FC)  &&  --timeout);
+       if (likely(dev_drv)) {
+               if (dev_drv->ops->set_irq_to_cpu)
+                       dev_drv->ops->set_irq_to_cpu(dev_drv, 0);
+       }
+
+       if (rk_fb_poll_prmry_screen_vblank() == RK_LF_STATUS_NC) {
+               if (likely(dev_drv)) {
+                       if (dev_drv->ops->set_irq_to_cpu)
+                               dev_drv->ops->set_irq_to_cpu(dev_drv, 1);
+               }
+               return false;
+       }
+       while (!(rk_fb_poll_prmry_screen_vblank() == RK_LF_STATUS_FR) && --timeout)
+               ;
+       while (!(rk_fb_poll_prmry_screen_vblank() == RK_LF_STATUS_FC) && --timeout)
+               ;
+       if (likely(dev_drv)) {
+               if (dev_drv->ops->set_irq_to_cpu)
+                       dev_drv->ops->set_irq_to_cpu(dev_drv, 1);
+       }
 
        return true;
 }
+
 static int rk_fb_open(struct fb_info *info, int user)
 {
        struct rk_lcdc_driver *dev_drv = (struct rk_lcdc_driver *)info->par;
        int win_id;
 
        win_id = dev_drv->ops->fb_get_win_id(dev_drv, info->fix.id);
+       /* if this win aready opened ,no need to reopen */
        if (dev_drv->win[win_id]->state)
-               return 0;    /* if this win aready opened ,no need to reopen*/
+               return 0;
        else
                dev_drv->ops->open(dev_drv, win_id, 1);
        return 0;
 }
 
-static int  get_extend_fb_id(struct fb_info *info)
+static int get_extend_fb_id(struct fb_info *info)
 {
        int fb_id = 0;
        char *id = info->fix.id;
@@ -582,16 +678,19 @@ static int rk_fb_close(struct fb_info *info, int user)
 
                info->var.xres = dev_drv->screen0->mode.xres;
                info->var.yres = dev_drv->screen0->mode.yres;
-               info->var.grayscale |= (info->var.xres<<8) + (info->var.yres<<20);
+               info->var.grayscale |=
+                   (info->var.xres << 8) + (info->var.yres << 20);
+               info->var.xres_virtual = info->var.xres;
+               info->var.yres_virtual = info->var.yres;
 #if defined(CONFIG_LOGO_LINUX_BMP)
                info->var.bits_per_pixel = 32;
 #else
                info->var.bits_per_pixel = 16;
 #endif
-               info->fix.line_length  = (info->var.xres)*(info->var.bits_per_pixel>>3);
-               info->var.xres_virtual = info->var.xres;
-               info->var.yres_virtual = info->var.yres;
-               info->var.width =  dev_drv->screen0->width;
+
+               info->fix.line_length =
+                   (info->var.xres_virtual) * (info->var.bits_per_pixel >> 3);
+               info->var.width = dev_drv->screen0->width;
                info->var.height = dev_drv->screen0->height;
                info->var.pixclock = dev_drv->pixclock;
                info->var.left_margin = dev_drv->screen0->mode.left_margin;
@@ -638,12 +737,11 @@ static int get_ipp_format(int fmt)
 }
 
 static void ipp_win_check(int *dst_w, int *dst_h, int *dst_vir_w,
-                               int rotation, int fmt)
+                         int rotation, int fmt)
 {
        int align16 = 2;
        int align64 = 8;
 
-
        if (fmt == IPP_XRGB_8888) {
                align16 = 1;
                align64 = 2;
@@ -654,24 +752,24 @@ static void ipp_win_check(int *dst_w, int *dst_h, int *dst_vir_w,
                align16 = 2;
                align64 = 8;
        }
-       align16 -= 1;  /*for YUV, 1*/
-       align64 -= 1;  /*for YUV, 7*/
+       align16 -= 1;           /*for YUV, 1 */
+       align64 -= 1;           /*for YUV, 7 */
 
        if (rotation == IPP_ROT_0) {
                if (fmt > IPP_RGB_565) {
                        if ((*dst_w & 1) != 0)
-                               *dst_w = *dst_w+1;
+                               *dst_w = *dst_w + 1;
                        if ((*dst_h & 1) != 0)
-                               *dst_h = *dst_h+1;
+                               *dst_h = *dst_h + 1;
                        if (*dst_vir_w < *dst_w)
                                *dst_vir_w = *dst_w;
                }
        } else {
 
                if ((*dst_w & align64) != 0)
-                       *dst_w = (*dst_w+align64)&(~align64);
+                       *dst_w = (*dst_w + align64) & (~align64);
                if ((fmt > IPP_RGB_565) && ((*dst_h & 1) == 1))
-                       *dst_h = *dst_h+1;
+                       *dst_h = *dst_h + 1;
                if (*dst_vir_w < *dst_w)
                        *dst_vir_w = *dst_w;
        }
@@ -679,28 +777,30 @@ static void ipp_win_check(int *dst_w, int *dst_h, int *dst_vir_w,
 }
 
 static void fb_copy_by_ipp(struct fb_info *dst_info,
-               struct fb_info *src_info, int offset)
+                          struct fb_info *src_info, int offset)
 {
        struct rk29_ipp_req ipp_req;
-       uint32_t  rotation = 0;
+       uint32_t rotation = 0;
        int dst_w, dst_h, dst_vir_w;
        int ipp_fmt;
-       u8 data_format = (dst_info->var.nonstd)&0xff;
+       u8 data_format = (dst_info->var.nonstd) & 0xff;
+       struct rk_lcdc_driver *ext_dev_drv =
+                       (struct rk_lcdc_driver *)dst_info->par;
+       u16 orientation = ext_dev_drv->rotate_mode;
 
        memset(&ipp_req, 0, sizeof(struct rk29_ipp_req));
-#if defined(CONFIG_FB_ROTATE)
-       int orientation = 270 - CONFIG_ROTATE_ORIENTATION;
+
        switch (orientation) {
        case 0:
                rotation = IPP_ROT_0;
                break;
-       case 90:
+       case ROTATE_90:
                rotation = IPP_ROT_90;
                break;
-       case 180:
+       case ROTATE_180:
                rotation = IPP_ROT_180;
                break;
-       case 270:
+       case ROTATE_270:
                rotation = IPP_ROT_270;
                break;
        default:
@@ -708,7 +808,6 @@ static void fb_copy_by_ipp(struct fb_info *dst_info,
                break;
 
        }
-#endif
 
        dst_w = dst_info->var.xres;
        dst_h = dst_info->var.yres;
@@ -727,7 +826,6 @@ static void fb_copy_by_ipp(struct fb_info *dst_info,
        ipp_req.dst_vir_w = dst_vir_w;
        ipp_req.dst0.fmt = ipp_fmt;
 
-
        ipp_req.timeout = 100;
        ipp_req.flag = rotation;
        ipp_blit_sync(&ipp_req);
@@ -736,170 +834,405 @@ static void fb_copy_by_ipp(struct fb_info *dst_info,
 
 #endif
 
+#if defined(CONFIG_ROCKCHIP_RGA) || defined(CONFIG_ROCKCHIP_RGA2)
+static int get_rga_format(int fmt)
+{
+       int rga_fmt = 0;
+
+       switch (fmt) {
+       case XBGR888:
+               rga_fmt = RK_FORMAT_RGBX_8888;
+               break;
+       case ABGR888:
+               rga_fmt = RK_FORMAT_RGBA_8888;
+               break;
+       case ARGB888:
+               rga_fmt = RK_FORMAT_BGRA_8888;
+               break;
+       case RGB888:
+               rga_fmt = RK_FORMAT_RGB_888;
+               break;
+       case RGB565:
+               rga_fmt = RK_FORMAT_RGB_565;
+               break;
+       case YUV422:
+               rga_fmt = RK_FORMAT_YCbCr_422_SP;
+               break;
+       case YUV420:
+               rga_fmt = RK_FORMAT_YCbCr_420_SP;
+               break;
+       default:
+               rga_fmt = RK_FORMAT_RGBA_8888;
+               break;
+       }
+
+       return rga_fmt;
+}
+
+static void rga_win_check(struct rk_lcdc_win *dst_win,
+                         struct rk_lcdc_win *src_win)
+{
+       int align32 = 4;
+
+       align32 -= 1;
+       /*width and height must be aligned by 32 bit */
+       if ((src_win->area[0].xact & align32) != 0)
+               src_win->area[0].xact =
+                   (src_win->area[0].xact + align32) & (~align32);
+       if ((src_win->area[0].yact & align32) != 0)
+               src_win->area[0].yact =
+                   (src_win->area[0].yact + align32) & (~align32);
+       if (src_win->area[0].xvir < src_win->area[0].xact)
+               src_win->area[0].xvir = src_win->area[0].xact;
+       if (src_win->area[0].yvir < src_win->area[0].yact)
+               src_win->area[0].yvir = src_win->area[0].yact;
+
+       if ((dst_win->area[0].xact & align32) != 0)
+               dst_win->area[0].xact =
+                   (dst_win->area[0].xact + align32) & (~align32);
+       if ((dst_win->area[0].yact & align32) != 0)
+               dst_win->area[0].yact =
+                   (dst_win->area[0].yact + align32) & (~align32);
+       if (dst_win->area[0].xvir < dst_win->area[0].xact)
+               dst_win->area[0].xvir = dst_win->area[0].xact;
+       if (dst_win->area[0].yvir < dst_win->area[0].yact)
+               dst_win->area[0].yvir = dst_win->area[0].yact;
+}
+
+static void win_copy_by_rga(struct rk_lcdc_win *dst_win,
+                           struct rk_lcdc_win *src_win, u16 orientation)
+{
+       struct rk_fb *rk_fb = platform_get_drvdata(fb_pdev);
+       struct rga_req Rga_Request;
+       long ret = 0;
+       /* int fd = 0; */
+
+       memset(&Rga_Request, 0, sizeof(Rga_Request));
+       rga_win_check(dst_win, src_win);
+
+       switch (orientation) {
+       case ROTATE_90:
+               Rga_Request.rotate_mode = 1;
+               Rga_Request.sina = 65536;
+               Rga_Request.cosa = 0;
+               Rga_Request.dst.act_w = dst_win->area[0].yact;
+               Rga_Request.dst.act_h = dst_win->area[0].xact;
+               Rga_Request.dst.x_offset = dst_win->area[0].xact - 1;
+               Rga_Request.dst.y_offset = 0;
+               break;
+       case ROTATE_180:
+               Rga_Request.rotate_mode = 1;
+               Rga_Request.sina = 0;
+               Rga_Request.cosa = -65536;
+               Rga_Request.dst.act_w = dst_win->area[0].xact;
+               Rga_Request.dst.act_h = dst_win->area[0].yact;
+               Rga_Request.dst.x_offset = dst_win->area[0].xact - 1;
+               Rga_Request.dst.y_offset = dst_win->area[0].yact - 1;
+               break;
+       case ROTATE_270:
+               Rga_Request.rotate_mode = 1;
+               Rga_Request.sina = -65536;
+               Rga_Request.cosa = 0;
+               Rga_Request.dst.act_w = dst_win->area[0].yact;
+               Rga_Request.dst.act_h = dst_win->area[0].xact;
+               Rga_Request.dst.x_offset = dst_win->area[0].xact - 1;
+               Rga_Request.dst.y_offset = dst_win->area[0].yact - 1;
+               break;
+       default:
+               Rga_Request.rotate_mode = 0;
+               Rga_Request.dst.act_w = dst_win->area[0].xact;
+               Rga_Request.dst.act_h = dst_win->area[0].yact;
+               Rga_Request.dst.x_offset = dst_win->area[0].xact - 1;
+               Rga_Request.dst.y_offset = dst_win->area[0].yact - 1;
+               break;
+       }
+
+#if defined(CONFIG_ROCKCHIP_RGA)
+       Rga_Request.src.yrgb_addr =
+           src_win->area[0].smem_start + src_win->area[0].y_offset;
+       Rga_Request.src.uv_addr = 0;
+       Rga_Request.src.v_addr = 0;
+
+       dst_win->area[0].smem_start =
+           rk_fb->fb[rk_fb->num_fb >> 1]->fix.smem_start;
+       Rga_Request.dst.yrgb_addr =
+           dst_win->area[0].smem_start + dst_win->area[0].y_offset;
+       Rga_Request.dst.uv_addr = 0;
+       Rga_Request.dst.v_addr = 0;
+#elif defined(CONFIG_ROCKCHIP_RGA2)
+/*
+       fd = ion_share_dma_buf_fd(rk_fb->ion_client, src_win->area[0].ion_hdl);
+       Rga_Request.src.yrgb_addr = fd;
+       fd = ion_share_dma_buf_fd(rk_fb->ion_client, dst_win->area[0].ion_hdl);
+       Rga_Request.dst.yrgb_addr = fd;
+*/
+       Rga_Request.src.yrgb_addr = 0;
+       Rga_Request.src.uv_addr =
+           src_win->area[0].smem_start + src_win->area[0].y_offset;
+       Rga_Request.src.v_addr = 0;
+
+       dst_win->area[0].smem_start =
+           rk_fb->fb[rk_fb->num_fb >> 1]->fix.smem_start;
+       Rga_Request.dst.yrgb_addr = 0;
+       Rga_Request.dst.uv_addr =
+           dst_win->area[0].smem_start + dst_win->area[0].y_offset;
+       Rga_Request.dst.v_addr = 0;
+#endif
+
+       Rga_Request.src.vir_w = src_win->area[0].xvir;
+       Rga_Request.src.vir_h = src_win->area[0].yvir;
+       Rga_Request.src.format = get_rga_format(src_win->format);
+       Rga_Request.src.act_w = src_win->area[0].xact;
+       Rga_Request.src.act_h = src_win->area[0].yact;
+       Rga_Request.src.x_offset = 0;
+       Rga_Request.src.y_offset = 0;
+
+       Rga_Request.dst.vir_w = dst_win->area[0].xvir;
+       Rga_Request.dst.vir_h = dst_win->area[0].yvir;
+       Rga_Request.dst.format = get_rga_format(dst_win->format);
+
+       Rga_Request.clip.xmin = 0;
+       Rga_Request.clip.xmax = dst_win->area[0].xact - 1;
+       Rga_Request.clip.ymin = 0;
+       Rga_Request.clip.ymax = dst_win->area[0].yact - 1;
+       Rga_Request.scale_mode = 0;
+#if defined(CONFIG_ROCKCHIP_IOMMU)
+       Rga_Request.mmu_info.mmu_en = 1;        /* TODO Modify for use mmu */
+       Rga_Request.mmu_info.mmu_flag = 1;
+#else
+       Rga_Request.mmu_info.mmu_en = 0;
+       Rga_Request.mmu_info.mmu_flag = 0;
+#endif
+
+       ret = rga_ioctl_kernel(&Rga_Request);
+}
+
+/*
+ * This function is used for copying fb by RGA Module
+ * RGA only support copy RGB to RGB
+ * RGA2 support copy RGB to RGB and YUV to YUV
+ */
+static void fb_copy_by_rga(struct fb_info *dst_info, struct fb_info *src_info,
+                          int yrgb_offset)
+{
+       struct rk_lcdc_driver *dev_drv = (struct rk_lcdc_driver *)src_info->par;
+       struct rk_lcdc_driver *ext_dev_drv =
+           (struct rk_lcdc_driver *)dst_info->par;
+       int win_id = 0, ext_win_id;
+       struct rk_lcdc_win *src_win, *dst_win;
+
+       win_id = dev_drv->ops->fb_get_win_id(dev_drv, src_info->fix.id);
+       src_win = dev_drv->win[win_id];
+
+       ext_win_id =
+           ext_dev_drv->ops->fb_get_win_id(ext_dev_drv, dst_info->fix.id);
+       dst_win = ext_dev_drv->win[ext_win_id];
+
+       win_copy_by_rga(dst_win, src_win, ext_dev_drv->rotate_mode);
+}
+
+#endif
 
 static int rk_fb_rotate(struct fb_info *dst_info,
-                               struct fb_info *src_info, int offset)
+                       struct fb_info *src_info, int offset)
 {
-       #if defined(CONFIG_RK29_IPP)
-               fb_copy_by_ipp(dst_info, src_info, offset);
-       #else
-               return -1;
-       #endif
-               return 0;
+#if defined(CONFIG_RK29_IPP)
+       fb_copy_by_ipp(dst_info, src_info, offset);
+#elif defined(CONFIG_ROCKCHIP_RGA) || defined(CONFIG_ROCKCHIP_RGA2)
+       fb_copy_by_rga(dst_info, src_info, offset);
+#else
+       return -1;
+#endif
+       return 0;
 }
-static int rk_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
+
+static int rk_fb_win_rotate(struct rk_lcdc_win *dst_win,
+                           struct rk_lcdc_win *src_win, u16 rotate)
+{
+#if defined(CONFIG_ROCKCHIP_RGA) || defined(CONFIG_ROCKCHIP_RGA2)
+       win_copy_by_rga(dst_win, src_win, rotate);
+#else
+       return -1;
+#endif
+       return 0;
+}
+
+
+static int rk_fb_pan_display(struct fb_var_screeninfo *var,
+                            struct fb_info *info)
 {
        struct rk_fb *rk_fb = dev_get_drvdata(info->device);
-       struct rk_lcdc_driver *dev_drv  = (struct rk_lcdc_driver *)info->par;
+       struct rk_lcdc_driver *dev_drv = (struct rk_lcdc_driver *)info->par;
        struct fb_fix_screeninfo *fix = &info->fix;
        struct fb_info *extend_info = NULL;
        struct rk_lcdc_driver *extend_dev_drv = NULL;
        int win_id = 0, extend_win_id = 0;
        struct rk_lcdc_win *extend_win = NULL;
        struct rk_lcdc_win *win = NULL;
+       struct rk_screen *screen = dev_drv->cur_screen;
        int fb_id = 0;
 
-
        u32 xoffset = var->xoffset;
        u32 yoffset = var->yoffset;
        u32 xvir = var->xres_virtual;
-       u32 yvir = var->yres_virtual;
-       /*u8 data_format = var->nonstd&0xff;*/
+       /* u32 yvir = var->yres_virtual; */
+       /* u8 data_format = var->nonstd&0xff; */
 
-       u8  pixel_width;
+       u8 pixel_width;
        u32 vir_width_bit;
-       u32 stride,uv_stride;
-       u32 stride_32bit_1;
-       u32 stride_32bit_2;
-       u32 stride_128bit_1;
-       u32 stride_128bit_2;
-       u16 uv_x_off,uv_y_off;
-       u8  is_pic_yuv=0;
+       u32 stride, uv_stride;
+       u32 stride_32bit_1;
+       u32 stride_32bit_2;
+       u16 uv_x_off, uv_y_off, uv_y_act;
+       u8 is_pic_yuv = 0;
 
        win_id = dev_drv->ops->fb_get_win_id(dev_drv, info->fix.id);
        if (win_id < 0)
-               return  -ENODEV;
+               return -ENODEV;
        else
                win = dev_drv->win[win_id];
 
        if (rk_fb->disp_mode == DUAL) {
                fb_id = get_extend_fb_id(info);
-               extend_info = rk_fb->fb[(rk_fb->num_fb>>1) + fb_id];
-               extend_dev_drv  = (struct rk_lcdc_driver *)extend_info->par;
+               extend_info = rk_fb->fb[(rk_fb->num_fb >> 1) + fb_id];
+               extend_dev_drv = (struct rk_lcdc_driver *)extend_info->par;
                extend_win_id = dev_drv->ops->fb_get_win_id(extend_dev_drv,
-                                               extend_info->fix.id);
+                                                          extend_info->fix.id);
                extend_win = extend_dev_drv->win[extend_win_id];
        }
+
        pixel_width = rk_fb_pixel_width(win->format);
        vir_width_bit = pixel_width * xvir;
-       stride_128bit_1 = ((vir_width_bit   + 127) & (~127))/8; //pixel_width = byte_num *8
-       stride_128bit_2 = ((vir_width_bit*2 + 127) & (~127))/8; //pixel_width = byte_num *8
-       stride_32bit_1  = ((vir_width_bit   + 31 ) & (~31 ))/8; //pixel_width = byte_num *8
-       stride_32bit_2  = ((vir_width_bit*2 + 31 ) & (~31 ))/8; //pixel_width = byte_num *8
+       /* pixel_width = byte_num * 8 */
+       stride_32bit_1 = ALIGN_N_TIMES(vir_width_bit, 32) / 8;
+       stride_32bit_2 = ALIGN_N_TIMES(vir_width_bit * 2, 32) / 8;
 
-       stride    = stride_32bit_1;//default rgb
-       fix->line_length = stride;
-
-       switch (win->format){
+       switch (win->format) {
        case YUV422:
+       case YUV422_A:
                is_pic_yuv = 1;
-               stride     = stride_32bit_1;
-               uv_stride  = stride_32bit_1>> 1 ;//
-               uv_x_off   = xoffset >> 1 ;//
-               uv_y_off   = yoffset;//0
+               stride = stride_32bit_1;
+               uv_stride = stride_32bit_1 >> 1;
+               uv_x_off = xoffset >> 1;
+               uv_y_off = yoffset;
                fix->line_length = stride;
+               uv_y_act = win->area[0].yact >> 1;
                break;
-       case YUV420://420sp
+       case YUV420:            /* 420sp */
+       case YUV420_A:
                is_pic_yuv = 1;
-               stride     = stride_32bit_1;
-               uv_stride  = stride_32bit_1;
-               uv_x_off   = xoffset;
-               uv_y_off   = yoffset >> 1;
+               stride = stride_32bit_1;
+               uv_stride = stride_32bit_1;
+               uv_x_off = xoffset;
+               uv_y_off = yoffset >> 1;
                fix->line_length = stride;
+               uv_y_act = win->area[0].yact >> 1;
                break;
        case YUV444:
+       case YUV444_A:
                is_pic_yuv = 1;
-               stride     = stride_32bit_1;
-               uv_stride  = stride_32bit_2;
-               uv_x_off   = xoffset*2;
-               uv_y_off   = yoffset;
-               fix->line_length = stride<<2;
+               stride = stride_32bit_1;
+               uv_stride = stride_32bit_2;
+               uv_x_off = xoffset * 2;
+               uv_y_off = yoffset;
+               fix->line_length = stride << 2;
+               uv_y_act = win->area[0].yact;
                break;
        default:
+               stride = stride_32bit_1;        /* default rgb */
+               fix->line_length = stride;
                break;
        }
 
-       // x y mirror ,jump line
-       win->area[0].y_offset = yoffset*stride+xoffset*pixel_width/8;
-       if(is_pic_yuv == 1){
-               win->area[0].c_offset = uv_y_off*uv_stride+uv_x_off*pixel_width/8;
+       /* x y mirror ,jump line */
+       if (screen->y_mirror == 1) {
+               if (screen->interlace == 1) {
+                       win->area[0].y_offset = yoffset * stride * 2 +
+                           ((win->area[0].yact - 1) * 2 + 1) * stride +
+                           xoffset * pixel_width / 8;
+               } else {
+                       win->area[0].y_offset = yoffset * stride +
+                           (win->area[0].yact - 1) * stride +
+                           xoffset * pixel_width / 8;
+               }
+       } else {
+               if (screen->interlace == 1) {
+                       win->area[0].y_offset =
+                           yoffset * stride * 2 + xoffset * pixel_width / 8;
+               } else {
+                       win->area[0].y_offset =
+                           yoffset * stride + xoffset * pixel_width / 8;
+               }
        }
-
-       switch (win->format) {
-       case XBGR888:
-       case ARGB888:
-       case ABGR888:
-               win->area[0].y_offset=(yoffset*xvir + xoffset)*4;//win->y_offset = (yoffset*xvir + xoffset)*4;
-               break;
-       case  RGB888:
-               win->area[0].y_offset = (yoffset*xvir + xoffset)*3;
-               break;
-       case RGB565:
-               win->area[0].y_offset = (yoffset*xvir + xoffset)*2;
-               break;
-       case  YUV422:
-               win->area[0].y_offset = yoffset*xvir + xoffset;
-               win->area[0].c_offset = win->area[0].y_offset;
-               break;
-       case  YUV420:
-               win->area[0].y_offset = yoffset*xvir + xoffset;
-               win->area[0].c_offset = (yoffset>>1)*xvir + xoffset;
-               break;
-       case  YUV444:
-               win->area[0].y_offset = yoffset*xvir + xoffset;
-               win->area[0].c_offset = yoffset*2*xvir + (xoffset<<1);
-               break;
-       default:
-               break;
+       if (is_pic_yuv == 1) {
+               if (screen->y_mirror == 1) {
+                       if (screen->interlace == 1) {
+                               win->area[0].c_offset =
+                                   uv_y_off * uv_stride * 2 +
+                                   ((uv_y_act - 1) * 2 + 1) * uv_stride +
+                                   uv_x_off * pixel_width / 8;
+                       } else {
+                               win->area[0].c_offset = uv_y_off * uv_stride +
+                                   (uv_y_act - 1) * uv_stride +
+                                   uv_x_off * pixel_width / 8;
+                       }
+               } else {
+                       if (screen->interlace == 1) {
+                               win->area[0].c_offset =
+                                   uv_y_off * uv_stride * 2 +
+                                   uv_x_off * pixel_width / 8;
+                       } else {
+                               win->area[0].c_offset =
+                                   uv_y_off * uv_stride +
+                                   uv_x_off * pixel_width / 8;
+                       }
+               }
        }
+
        win->area[0].smem_start = fix->smem_start;
-       win->area[0].cbr_start = fix->smem_start + xvir * yvir;
-       win->state=1;
-       win->area[0].state=1;
+       win->area[0].cbr_start = fix->mmio_start;
+       win->area[0].state = 1;
        win->area_num = 1;
-       
+       win->state = 1;
+
        dev_drv->ops->pan_display(dev_drv, win_id);
        if (rk_fb->disp_mode == DUAL) {
                if (extend_win->state && (hdmi_switch_complete)) {
                        extend_win->area[0].y_offset = win->area[0].y_offset;
-               #if defined(CONFIG_FB_ROTATE) || !defined(CONFIG_THREE_FB_BUFFER)
-                       rk_fb_rotate(extend_info, info, win->area[0].y_offset);
-               #endif
-                       extend_dev_drv->ops->pan_display(extend_dev_drv, extend_win_id);
+                       if (extend_dev_drv->rotate_mode > X_Y_MIRROR) {
+                               rk_fb_rotate(extend_info, info,
+                                               win->area[0].y_offset);
+                       } else {
+                               extend_win->area[0].smem_start =
+                                               win->area[0].smem_start;
+                               extend_win->area[0].cbr_start =
+                                               win->area[0].cbr_start;
+                       }
+                       extend_dev_drv->ops->pan_display(extend_dev_drv,
+                                                        extend_win_id);
                }
        }
-
-       #ifdef  CONFIG_FB_MIRRORING
+#ifdef CONFIG_FB_MIRRORING
        if (video_data_to_mirroring)
                video_data_to_mirroring(info, NULL);
-       #endif
+#endif
+       dev_drv->ops->cfg_done(dev_drv);
        return 0;
 }
 
 static int rk_fb_get_list_stat(struct rk_lcdc_driver *dev_drv)
 {
-       int i,j;
+       int i, j;
        i = list_empty(&dev_drv->update_regs_list);
        j = list_empty(&saved_list);
-       return i==j?0:1;
+       return i == j ? 0 : 1;
 
 }
 
-void rk_fd_fence_wait(struct rk_lcdc_driver *dev_drv,
-       struct sync_fence *fence)
+void rk_fd_fence_wait(struct rk_lcdc_driver *dev_drv, struct sync_fence *fence)
 {
        int err = sync_fence_wait(fence, 1000);
-       
+
        if (err >= 0)
                return;
 
@@ -910,411 +1243,748 @@ void rk_fd_fence_wait(struct rk_lcdc_driver *dev_drv,
                printk("error waiting on fence\n");
 }
 
+static int rk_fb_copy_from_loader(struct fb_info *info)
+{
+       struct rk_lcdc_driver *dev_drv = (struct rk_lcdc_driver *)info->par;
+       void *dst = info->screen_base;
+       u32 dsp_addr[4];
+       u32 src;
+       u32 i;
+       struct rk_lcdc_win *win = dev_drv->win[0];
+       u32 size = (win->area[0].xact) * (win->area[0].yact) << 2;
+       dev_drv->ops->get_dsp_addr(dev_drv, dsp_addr);
+       src = dsp_addr[0];
+       dev_info(info->dev, "copy fb data %d x %d  from  dst_addr:%08x\n",
+                win->area[0].xact, win->area[0].yact, src);
+       for (i = 0; i < size; i += PAGE_SIZE) {
+               void *page = phys_to_page(i + src);
+               void *from_virt = kmap(page);
+               void *to_virt = dst + i;
+               memcpy(to_virt, from_virt, PAGE_SIZE);
+       }
+       return 0;
+}
+
+#ifdef CONFIG_ROCKCHIP_IOMMU
+static int g_last_addr[4];
+int g_last_timeout;
+u32 freed_addr[10];
+u32 freed_index;
+
+#define DUMP_CHUNK 256
+char buf[PAGE_SIZE];
 
-void rk_fb_free_dma_buf(struct rk_fb_reg_win_data *reg_win_data)
+int rk_fb_sysmmu_fault_handler(struct device *dev,
+                              enum rk_sysmmu_inttype itype,
+                              unsigned long pgtable_base,
+                              unsigned long fault_addr, unsigned int status)
 {
-#ifdef H_USE_FENCE
-       int i;
-       for(i=0;i<RK_WIN_MAX_AREA;i++){
-               if(reg_win_data->reg_area_data[i].acq_fence)
-                       sync_fence_put(reg_win_data->reg_area_data[i].acq_fence);
+       struct rk_lcdc_driver *dev_drv = rk_get_prmry_lcdc_drv();
+       int i = 0;
+       static int page_fault_cnt;
+       if ((page_fault_cnt++) >= 10)
+               return 0;
+       pr_err
+           ("PAGE FAULT occurred at 0x%lx (Page table base: 0x%lx),status=%d\n",
+            fault_addr, pgtable_base, status);
+       printk("last config addr:\n" "win0:0x%08x\n" "win1:0x%08x\n"
+              "win2:0x%08x\n" "win3:0x%08x\n", g_last_addr[0], g_last_addr[1],
+              g_last_addr[2], g_last_addr[3]);
+       printk("last freed buffer:\n");
+       for (i = 0; (freed_addr[i] != 0xfefefefe) && freed_addr[i]; i++)
+               printk("%d:0x%08x\n", i, freed_addr[i]);
+       printk("last timeout:%d\n", g_last_timeout);
+       dev_drv->ops->get_disp_info(dev_drv, buf, 0);
+       for (i = 0; i < PAGE_SIZE; i += DUMP_CHUNK) {
+               if ((PAGE_SIZE - i) > DUMP_CHUNK) {
+                       char c = buf[i + DUMP_CHUNK];
+                       buf[i + DUMP_CHUNK] = 0;
+                       pr_cont("%s", buf + i);
+                       buf[i + DUMP_CHUNK] = c;
+               } else {
+                       buf[PAGE_SIZE - 1] = 0;
+                       pr_cont("%s", buf + i);
+               }
        }
+
+       return 0;
+}
+#endif
+
+void rk_fb_free_dma_buf(struct rk_lcdc_driver *dev_drv,
+                       struct rk_fb_reg_win_data *reg_win_data)
+{
+       int i, index_buf;
+       struct rk_fb_reg_area_data *area_data;
+       struct rk_fb *rk_fb = platform_get_drvdata(fb_pdev);
+
+       for (i = 0; i < reg_win_data->area_num; i++) {
+               area_data = &reg_win_data->reg_area_data[i];
+               index_buf = area_data->index_buf;
+#if defined(CONFIG_ROCKCHIP_IOMMU)
+               if (dev_drv->iommu_enabled) {
+                       ion_unmap_iommu(dev_drv->dev, rk_fb->ion_client,
+                                       area_data->ion_handle);
+                       freed_addr[freed_index++] = area_data->smem_start;
+               }
 #endif
+               if (area_data->ion_handle != NULL) {
+                       ion_unmap_kernel(rk_fb->ion_client,
+                                        area_data->ion_handle);
+                       ion_free(rk_fb->ion_client, area_data->ion_handle);
+               }
+               if (area_data->acq_fence)
+                       sync_fence_put(area_data->acq_fence);
+       }
        memset(reg_win_data, 0, sizeof(struct rk_fb_reg_win_data));
 }
 
-static void rk_fb_update_driver(struct rk_lcdc_win *win,struct rk_fb_reg_win_data *reg_win_data)
+static void rk_fb_update_driver(struct rk_lcdc_win *win,
+                               struct rk_fb_reg_win_data *reg_win_data)
 {
-       int i=0;
-       //struct rk_lcdc_win *win;      
-       //win = dev_drv->win[reg_win_data->win_id];
+       int i = 0;
+/*
+       struct rk_lcdc_win *win;
+       win = dev_drv->win[reg_win_data->win_id];
+*/
        win->area_num = reg_win_data->area_num;
        win->format = reg_win_data->data_format;
        win->id = reg_win_data->win_id;
        win->z_order = reg_win_data->z_order;
-       
-       #if 0
-       for(i=0;i<win->area_num;i++)
-       {
-               printk("i=%d:area[%d]=%x,reg_area_data[%d]=%x,mem_start=%x\n",
-                       i,i,&win->area[i],i,&reg_win_data->reg_area_data[i],reg_win_data->reg_area_data[i].smem_start);
-               
-               win->area[i].smem_start = reg_win_data->reg_area_data[i].smem_start;
-               win->area[i].cbr_start  = reg_win_data->reg_area_data[i].cbr_start;
-               win->area[i].xpos          = reg_win_data->reg_area_data[i].xpos;
-               win->area[i].ypos          = reg_win_data->reg_area_data[i].ypos;
-               win->area[i].xsize         = reg_win_data->reg_area_data[i].xsize;
-               win->area[i].ysize         = reg_win_data->reg_area_data[i].ysize;
-               win->area[i].xact          = reg_win_data->reg_area_data[i].xact;
-               win->area[i].yact          = reg_win_data->reg_area_data[i].yact;
-               win->area[i].xvir          = reg_win_data->reg_area_data[i].xvir;
-               win->area[i].yvir          = reg_win_data->reg_area_data[i].yvir;
-               win->area[i].y_offset      = reg_win_data->reg_area_data[i].y_offset;
-               win->area[i].c_offset      = reg_win_data->reg_area_data[i].c_offset;
-               win->area[i].state = 1;
-       }       
-       #else
-       if(reg_win_data->reg_area_data[0].smem_start > 0){
+
+       if (reg_win_data->reg_area_data[0].smem_start > 0) {
                win->state = 1;
                win->area_num = reg_win_data->area_num;
                win->format = reg_win_data->data_format;
                win->id = reg_win_data->win_id;
                win->z_order = reg_win_data->z_order;
-               win->area[0].uv_vir_stride = reg_win_data->reg_area_data[0].uv_vir_stride;
-               win->area[0].cbr_start = reg_win_data->reg_area_data[0].cbr_start;
+               win->area[0].uv_vir_stride =
+                   reg_win_data->reg_area_data[0].uv_vir_stride;
+
+#if !defined(RK_FB_ROTATE) && defined(CONFIG_THREE_FB_BUFFER)
+               /* TODO Mofidy if HDMI info is change to hwc */
+               win->area[0].cbr_start =
+                   reg_win_data->reg_area_data[0].cbr_start;
+#endif
                win->area[0].c_offset = reg_win_data->reg_area_data[0].c_offset;
                win->alpha_en = reg_win_data->alpha_en;
                win->alpha_mode = reg_win_data->alpha_mode;
                win->g_alpha_val = reg_win_data->g_alpha_val;
-               for(i=0;i<RK_WIN_MAX_AREA;i++)
-               {
-                       if(reg_win_data->reg_area_data[i].smem_start > 0){
-                               win->area[i].smem_start = reg_win_data->reg_area_data[i].smem_start;
-                               win->area[i].xpos          = reg_win_data->reg_area_data[i].xpos;
-                               win->area[i].ypos          = reg_win_data->reg_area_data[i].ypos;
-                               win->area[i].xsize         = reg_win_data->reg_area_data[i].xsize;
-                               win->area[i].ysize         = reg_win_data->reg_area_data[i].ysize;
-                               win->area[i].xact          = reg_win_data->reg_area_data[i].xact;
-                               win->area[i].yact          = reg_win_data->reg_area_data[i].yact;
-                               win->area[i].xvir          = reg_win_data->reg_area_data[i].xvir;
-                               win->area[i].yvir          = reg_win_data->reg_area_data[i].yvir;
-                               win->area[i].y_offset      = reg_win_data->reg_area_data[i].y_offset;
-                               win->area[i].y_vir_stride  = reg_win_data->reg_area_data[i].y_vir_stride;
+               for (i = 0; i < RK_WIN_MAX_AREA; i++) {
+                       if (reg_win_data->reg_area_data[i].smem_start > 0) {
+#if !defined(RK_FB_ROTATE) && defined(CONFIG_THREE_FB_BUFFER)
+                               win->area[i].smem_start =
+                                   reg_win_data->reg_area_data[i].smem_start;
+#endif
+                               win->area[i].xpos =
+                                   reg_win_data->reg_area_data[i].xpos;
+                               win->area[i].ypos =
+                                   reg_win_data->reg_area_data[i].ypos;
+                               win->area[i].xsize =
+                                   reg_win_data->reg_area_data[i].xsize;
+                               win->area[i].ysize =
+                                   reg_win_data->reg_area_data[i].ysize;
+                               win->area[i].xact =
+                                   reg_win_data->reg_area_data[i].xact;
+                               win->area[i].yact =
+                                   reg_win_data->reg_area_data[i].yact;
+                               win->area[i].xvir =
+                                   reg_win_data->reg_area_data[i].xvir;
+                               win->area[i].yvir =
+                                   reg_win_data->reg_area_data[i].yvir;
+                               win->area[i].y_offset =
+                                   reg_win_data->reg_area_data[i].y_offset;
+                               win->area[i].y_vir_stride =
+                                   reg_win_data->reg_area_data[i].y_vir_stride;
                                win->area[i].state = 1;
-                       }else{
+                       } else {
                                win->area[i].state = 0;
                        }
                }
-       }else{
+       } else {
+       /*
                win->state = 0;
+               win->z_order = -1;
+       */
        }
-       #endif
 
 }
 
+static struct rk_fb_reg_win_data *rk_fb_get_win_data(struct rk_fb_reg_data
+                                                    *regs, int win_id)
+{
+       int i;
+       struct rk_fb_reg_win_data *win_data = NULL;
+       for (i = 0; i < regs->win_num; i++) {
+               if (regs->reg_win_data[i].win_id == win_id) {
+                       win_data = &(regs->reg_win_data[i]);
+                       break;
+               }
+       }
 
-static void rk_fb_update_reg(struct rk_lcdc_driver * dev_drv,struct rk_fb_reg_data *regs)
+       return win_data;
+}
+
+static void rk_fb_update_reg(struct rk_lcdc_driver *dev_drv,
+                            struct rk_fb_reg_data *regs)
 {
-       int i,j,ret=0;
+       int i, j;
        struct rk_lcdc_win *win;
        ktime_t timestamp = dev_drv->vsync_info.timestamp;
-       //struct rk_fb_reg_win_data old_reg_win_data[RK30_MAX_LAYER_SUPPORT];
+       struct rk_fb *rk_fb = platform_get_drvdata(fb_pdev);
+       struct rk_lcdc_driver *ext_dev_drv;
+       struct rk_lcdc_win *ext_win;
+       struct rk_fb_reg_win_data *win_data;
+       bool wait_for_vsync;
+       int count = 100;
+       unsigned int dsp_addr[4];
+       long timeout;
+
+       /* acq_fence wait */
+       for (i = 0; i < regs->win_num; i++) {
+               win_data = &regs->reg_win_data[i];
+               for (j = 0; j < RK_WIN_MAX_AREA; j++) {
+                       if (win_data->reg_area_data[j].acq_fence) {
+                               /* printk("acq_fence wait!!!!!\n"); */
+                               rk_fd_fence_wait(dev_drv, win_data->reg_area_data[j].acq_fence);
+                       }
+               }
+       }
 
-       for(i=0;i<dev_drv->lcdc_win_num;i++){ 
-               //old_reg_win_data[i]= regs->reg_win_data[i];
+       for (i = 0; i < dev_drv->lcdc_win_num; i++) {
                win = dev_drv->win[i];
-               for(j=0;j<regs->win_num;j++){
-                       if(i == regs->reg_win_data[j].win_id)
-                               break;
-               }
-               if(j<regs->win_num){
-                       rk_fb_update_driver(win,&regs->reg_win_data[j]);
+               win_data = rk_fb_get_win_data(regs, i);
+               if (win_data) {
+                       rk_fb_update_driver(win, win_data);
                        win->state = 1;
-               }else{
+                       dev_drv->ops->set_par(dev_drv, i);
+                       dev_drv->ops->pan_display(dev_drv, i);
+#if defined(CONFIG_ROCKCHIP_IOMMU)
+                       if (dev_drv->iommu_enabled) {
+                               g_last_addr[i] = win_data->reg_area_data[0].smem_start +
+                                       win_data->reg_area_data[0].y_offset;
+                       }
+#endif
+               } else {
+                       win->z_order = -1;
                        win->state = 0;
                }
        }
-#if 0
-       for(i=0;i<2;i++){
-               printk("win[%d]:drv_win_state=%d\n",i,dev_drv->win[i]->state);
-               for(j=0;j<4;j++){
-                       printk("area[%d]:state=%d,mem_addr=%x\n",
-                               i,dev_drv->win[i]->area[j].state,dev_drv->win[i]->area[j].smem_start);
-               }
-       }
-#endif 
-       dev_drv->atv_layer_cnt = regs->win_num;
-       dev_drv->cur_screen->post_xsize = regs->post_cfg.xsize;
-       dev_drv->cur_screen->post_ysize = regs->post_cfg.ysize;
-       dev_drv->cur_screen->post_dsp_stx = regs->post_cfg.xpos;
-       dev_drv->cur_screen->post_dsp_sty = regs->post_cfg.ypos;
-       dev_drv->ops->set_par(dev_drv,0);
+       dev_drv->ops->ovl_mgr(dev_drv, 0, 1);
 
-       ret = wait_event_interruptible_timeout(dev_drv->vsync_info.wait,
-                       !ktime_equal(timestamp, dev_drv->vsync_info.timestamp),msecs_to_jiffies(dev_drv->cur_screen->ft+5));
+       if ((rk_fb->disp_mode == DUAL)
+           && (hdmi_get_hotplug() == HDMI_HPD_ACTIVED)
+           && hdmi_switch_complete) {
+               for (i = 0; i < rk_fb->num_lcdc; i++) {
+                       if (rk_fb->lcdc_dev_drv[i]->prop == EXTEND) {
+                               ext_dev_drv = rk_fb->lcdc_dev_drv[i];
+                               break;
+                       }
+               }
+               if (i == rk_fb->num_lcdc) {
+                       printk(KERN_ERR "hdmi lcdc driver not found!\n");
+                       goto ext_win_exit;
+               }
+               /* hdmi just need set win0 only(win0 have only one area)
+                * other win is disable
+                */
+               win = dev_drv->win[0];
+               ext_win = ext_dev_drv->win[0];
+               for (j = 0; j < regs->win_num; j++) {
+                       if (0 == regs->reg_win_data[j].win_id)
+                               break;
+               }
+               if (j < regs->win_num) {
+                       rk_fb_update_driver(ext_win, &regs->reg_win_data[j]);
+                       if (win->area[0].xpos != 0 || win->area[0].ypos != 0) {
+                               ext_win->area[0].xsize =
+                                   (ext_dev_drv->cur_screen->xsize * win->area[0].xsize) /
+                                   dev_drv->cur_screen->mode.xres;
+                               ext_win->area[0].ysize =
+                                   (ext_dev_drv->cur_screen->ysize * win->area[0].ysize) /
+                                   dev_drv->cur_screen->mode.yres;
+                               ext_win->area[0].xpos =
+                                   ((ext_dev_drv->cur_screen->mode.xres - ext_dev_drv->cur_screen->xsize) >> 1) +
+                                   ext_dev_drv->cur_screen->xsize * win->area[0].xpos / dev_drv->cur_screen->mode.xres;
+                               ext_win->area[0].ypos =
+                                   ((ext_dev_drv->cur_screen->mode.yres - ext_dev_drv->cur_screen->ysize) >> 1) +
+                                   ext_dev_drv->cur_screen->ysize * win->area[0].ypos / dev_drv->cur_screen->mode.yres;
+                       } else {
+                               ext_win->area[0].xpos =
+                                   (ext_dev_drv->cur_screen->mode.xres - ext_dev_drv->cur_screen->xsize) >> 1;
+                               ext_win->area[0].ypos =
+                                   (ext_dev_drv->cur_screen->mode.yres - ext_dev_drv->cur_screen->ysize) >> 1;
+                               ext_win->area[0].xsize = ext_dev_drv->cur_screen->xsize;
+                               ext_win->area[0].ysize = ext_dev_drv->cur_screen->ysize;
+                       }
+                       /* hdmi only one win so disable alpha */
+                       ext_win->alpha_en = 0;
+                       ext_win->state = 1;
+               } else {
+                       ext_win->state = 0;
+               }
 
+               if (win->area[0].xact < win->area[0].yact) {
+                       int pixel_width, vir_width_bit, stride;
+                       ext_win->area[0].xact = win->area[0].yact;
+                       ext_win->area[0].yact = win->area[0].xact;
+                       ext_win->area[0].xvir = win->area[0].yact;
+                       pixel_width = rk_fb_pixel_width(ext_win->format);
+                       vir_width_bit = pixel_width * ext_win->area[0].xvir;
+                       stride = ALIGN_N_TIMES(vir_width_bit, 32) / 8;
+                       ext_win->area[0].y_vir_stride = stride >> 2;
+               }
+               if (ext_dev_drv->rotate_mode > X_Y_MIRROR)
+                       rk_fb_win_rotate(ext_win, win, ext_dev_drv->rotate_mode);
+
+               ext_dev_drv->ops->set_par(ext_dev_drv, 0);
+               ext_dev_drv->ops->pan_display(ext_dev_drv, 0);
+               ext_dev_drv->ops->cfg_done(ext_dev_drv);
+       }
+ext_win_exit:
+       dev_drv->ops->cfg_done(dev_drv);
+
+       do {
+               timestamp = dev_drv->vsync_info.timestamp;
+               timeout = wait_event_interruptible_timeout(dev_drv->vsync_info.wait,
+                               ktime_compare(dev_drv->vsync_info.timestamp, timestamp) > 0,
+                               msecs_to_jiffies(25));
+               dev_drv->ops->get_dsp_addr(dev_drv, dsp_addr);
+               wait_for_vsync = false;
+               for (i = 0; i < dev_drv->lcdc_win_num; i++) {
+                       if (dev_drv->win[i]->state == 1) {
+                               u32 new_start =
+                                   dev_drv->win[i]->area[0].smem_start +
+                                   dev_drv->win[i]->area[0].y_offset;
+                               u32 reg_start = dsp_addr[i];
+
+                               if (unlikely(new_start != reg_start)) {
+                                       wait_for_vsync = true;
+                                       dev_info(dev_drv->dev,
+                                              "win%d:new_addr:0x%08x cur_addr:0x%08x--%d\n",
+                                              i, new_start, reg_start, 101 - count);
+                                       break;
+                               }
+                       }
+               }
+       } while (wait_for_vsync && count--);
+#ifdef H_USE_FENCE
        sw_sync_timeline_inc(dev_drv->timeline, 1);
+#endif
+       if (!g_first_buf) {
+#if defined(CONFIG_ROCKCHIP_IOMMU)
+               if (dev_drv->iommu_enabled) {
+                       freed_index = 0;
+                       g_last_timeout = timeout;
+               }
+#endif
+               for (i = 0; i < g_last_win_num; i++)
+                       rk_fb_free_dma_buf(dev_drv, &g_reg_win_data[i]);
 
-       for(i=0;i<regs->win_num;i++){
-               rk_fb_free_dma_buf(&regs->reg_win_data[i]);
+#if defined(CONFIG_ROCKCHIP_IOMMU)
+               if (dev_drv->iommu_enabled)
+                       freed_addr[freed_index] = 0xfefefefe;
+#endif
        }
+       for (i = 0; i < regs->win_num; i++) {
+               memcpy(&g_reg_win_data[i], &(regs->reg_win_data[i]),
+                      sizeof(struct rk_fb_reg_win_data));
+       }
+       g_last_win_num = regs->win_num;
+       g_first_buf = 0;
+
 }
 
 static void rk_fb_update_regs_handler(struct kthread_work *work)
 {
-       struct rk_lcdc_driver * dev_drv =
-                       container_of(work, struct rk_lcdc_driver, update_regs_work);
+       struct rk_lcdc_driver *dev_drv =
+           container_of(work, struct rk_lcdc_driver, update_regs_work);
        struct rk_fb_reg_data *data, *next;
-       //struct list_head saved_list;
+       /* struct list_head saved_list; */
+
        mutex_lock(&dev_drv->update_regs_list_lock);
        saved_list = dev_drv->update_regs_list;
        list_replace_init(&dev_drv->update_regs_list, &saved_list);
        mutex_unlock(&dev_drv->update_regs_list_lock);
-       
+
        list_for_each_entry_safe(data, next, &saved_list, list) {
-               rk_fb_update_reg(dev_drv,data);
+               rk_fb_update_reg(dev_drv, data);
                list_del(&data->list);
                kfree(data);
        }
+
+       if (dev_drv->wait_fs && list_empty(&dev_drv->update_regs_list))
+               wake_up(&dev_drv->update_regs_wait);
+}
+
+static int rk_fb_check_config_var(struct rk_fb_area_par *area_par,
+                                 struct rk_screen *screen)
+{
+       if ((area_par->x_offset + area_par->xact > area_par->xvir) ||
+           (area_par->xact <= 0) || (area_par->yact <= 0) ||
+           (area_par->xvir <= 0) || (area_par->yvir <= 0)) {
+               pr_err("check config var fail 0:\n"
+                      "x_offset=%d,xact=%d,xvir=%d\n",
+                      area_par->x_offset, area_par->xact, area_par->xvir);
+               return -EINVAL;
+       }
+
+       if ((area_par->xpos + area_par->xsize > screen->mode.xres) ||
+           (area_par->ypos + area_par->ysize > screen->mode.yres) ||
+           (area_par->xsize <= 0) || (area_par->ysize <= 0)) {
+               pr_err("check config var fail 1:\n"
+                      "xpos=%d,xsize=%d,xres=%d\n"
+                      "ypos=%d,ysize=%d,yres=%d\n",
+                      area_par->xpos, area_par->xsize, screen->mode.xres,
+                      area_par->ypos, area_par->ysize, screen->mode.yres);
+               return -EINVAL;
+       }
+       return 0;
 }
 
 static int rk_fb_set_win_buffer(struct fb_info *info,
-       struct rk_fb_win_par *win_par,struct rk_fb_reg_win_data *reg_win_data)
+                               struct rk_fb_win_par *win_par,
+                               struct rk_fb_reg_win_data *reg_win_data)
 {
        struct rk_fb *rk_fb = dev_get_drvdata(info->device);
-       //struct fb_var_screeninfo *var = &info->var;
-       struct fb_fix_screeninfo *fix = &info->fix;
-       //struct rk_lcdc_driver * dev_drv = (struct rk_lcdc_driver * )info->par;
-
-       int i,j,ion_fd,acq_fence_fd;
-       u32 xvir,yvir;
-       u32 xoffset,yoffset;
+       struct fb_fix_screeninfo *fix = &info->fix;
+       struct rk_lcdc_driver *dev_drv = (struct rk_lcdc_driver *)info->par;
+       struct rk_screen *screen = dev_drv->cur_screen;
+       struct fb_info *fbi = rk_fb->fb[0];
+       int i, ion_fd, acq_fence_fd;
+       u32 xvir, yvir;
+       u32 xoffset, yoffset;
 
        struct ion_handle *hdl;
-       ion_phys_addr_t phy_addr;
        size_t len;
        int index_buf;
-       u8  fb_data_fmt;
-       u8  pixel_width;
+       u8 fb_data_fmt;
+       u8 pixel_width;
        u32 vir_width_bit;
-       u32 stride,uv_stride;
-       u32 stride_32bit_1;
-       u32 stride_32bit_2;
-       u32 stride_128bit_1;
-       u32 stride_128bit_2;
-       u16 uv_x_off,uv_y_off;
-       u8  is_pic_yuv=0;
-       u8  ppixel_a=0,global_a=0;
+       u32 stride, uv_stride;
+       u32 stride_32bit_1;
+       u32 stride_32bit_2;
+       u16 uv_x_off, uv_y_off, uv_y_act;
+       u8 is_pic_yuv = 0;
+       u8 ppixel_a = 0, global_a = 0;
+       ion_phys_addr_t phy_addr;
+
+       reg_win_data->reg_area_data[0].smem_start = -1;
        reg_win_data->area_num = 0;
-       if(win_par->area_par[0].phy_addr == 0){
-               for(i=0;i<RK_WIN_MAX_AREA;i++){ 
+       fbi = rk_fb->fb[reg_win_data->win_id];
+       if (win_par->area_par[0].phy_addr == 0) {
+               for (i = 0; i < RK_WIN_MAX_AREA; i++) {
                        ion_fd = win_par->area_par[i].ion_fd;
-                       if(ion_fd > 0){
-                               reg_win_data->area_num++;
-                               for(j=0;j<i;j++){
-                                       if(ion_fd == win_par->area_par[j].ion_fd){
-                                               printk("region[%d] fd is same to region[%d]:fd=%d",
-                                                       i,j,ion_fd);
-                                               break;
-                                       }       
-                               }
-                               if(j == i){
-                                       hdl = ion_import_dma_buf(rk_fb->ion_client, ion_fd);
-                                       ion_phys(rk_fb->ion_client, hdl, &phy_addr, &len);
-                                       reg_win_data->reg_area_data[i].smem_start = phy_addr;
-                                       reg_win_data->area_buf_num++;
-                                       reg_win_data->reg_area_data[i].index_buf = 1;
-                               }else{
-                                       reg_win_data->reg_area_data[i].smem_start = 
-                                               reg_win_data->reg_area_data[j].smem_start;                      
+                       if (ion_fd > 0) {
+                               hdl =
+                                   ion_import_dma_buf(rk_fb->ion_client,
+                                                      ion_fd);
+                               if (IS_ERR(hdl)) {
+                                       pr_info
+                                           ("%s: Could not import handle: %d\n",
+                                            __func__, (int)hdl);
+                                       /*return -EINVAL; */
+                                       break;
                                }
+                               fbi->screen_base =
+                                   ion_map_kernel(rk_fb->ion_client, hdl);
+                               reg_win_data->area_num++;
+                               reg_win_data->reg_area_data[i].ion_handle = hdl;
+#ifndef CONFIG_ROCKCHIP_IOMMU
+                               ion_phys(rk_fb->ion_client, hdl, &phy_addr,
+                                        &len);
+#else
+                               if (dev_drv->iommu_enabled)
+                                       ion_map_iommu(dev_drv->dev,
+                                                     rk_fb->ion_client,
+                                                     hdl,
+                                                     (unsigned long *)&phy_addr,
+                                                     (unsigned long *)&len);
+                               else
+                                       ion_phys(rk_fb->ion_client, hdl,
+                                                &phy_addr, &len);
+#endif
+                               reg_win_data->reg_area_data[i].smem_start = phy_addr;
+                               reg_win_data->area_buf_num++;
+                               reg_win_data->reg_area_data[i].index_buf = 1;
                        }
-                       #if 0
-                       printk("i=%d,ion_fd=%d,addr=0x%x,area_num=%d,area_buf_num=%d\n",
-                               i,ion_fd,reg_win_data->reg_area_data[i].smem_start,
-                               reg_win_data->area_num,reg_win_data->area_buf_num);
-                       #endif
-               }
-       }else{
-               reg_win_data->reg_area_data[0].smem_start = 
-               win_par->area_par[0].phy_addr;
+               }
+       } else {
+               reg_win_data->reg_area_data[0].smem_start =
+                   win_par->area_par[0].phy_addr;
                reg_win_data->area_num = 1;
-       }       
+               fbi->screen_base = phys_to_virt(win_par->area_par[0].phy_addr);
+       }
 
-       if(reg_win_data->area_num == 0){
+       if (reg_win_data->area_num == 0)
                return 0;
-       }
 
-       for(i=0;i<reg_win_data->area_num;i++){
+       for (i = 0; i < reg_win_data->area_num; i++) {
                acq_fence_fd = win_par->area_par[i].acq_fence_fd;
                index_buf = reg_win_data->reg_area_data[i].index_buf;
-               if((acq_fence_fd > 0)&&(index_buf == 1)){
-                       reg_win_data->reg_area_data[i].acq_fence = 
-                               sync_fence_fdget(win_par->area_par[i].acq_fence_fd);
+               if ((acq_fence_fd > 0) && (index_buf == 1)) {
+                       reg_win_data->reg_area_data[i].acq_fence =
+                           sync_fence_fdget(win_par->area_par[i].acq_fence_fd);
                }
        }
-       fb_data_fmt = rk_fb_data_fmt(win_par->data_format,0);
+       fb_data_fmt = rk_fb_data_fmt(win_par->data_format, 0);
        reg_win_data->data_format = fb_data_fmt;
        pixel_width = rk_fb_pixel_width(fb_data_fmt);
-       
-       ppixel_a = ((fb_data_fmt == ARGB888)||(fb_data_fmt == ABGR888)) ? 1:0;
-       global_a = (win_par->g_alpha_val == 0) ? 0:1;
+
+       ppixel_a = ((fb_data_fmt == ARGB888)
+                   || (fb_data_fmt == ABGR888)) ? 1 : 0;
+       global_a = (win_par->g_alpha_val == 0) ? 0 : 1;
        reg_win_data->alpha_en = ppixel_a | global_a;
-       
-       reg_win_data->z_order = win_par->z_order;
-       reg_win_data->win_id  = win_par->win_id;        
-       
-       for(i=0;i<reg_win_data->area_num;i++){  
-               reg_win_data->reg_area_data[i].xpos = win_par->area_par[i].xpos;//visiable pos in panel
+       reg_win_data->g_alpha_val = win_par->g_alpha_val;
+       reg_win_data->alpha_mode = win_par->alpha_mode;
+       if (reg_win_data->reg_area_data[0].smem_start > 0) {
+               reg_win_data->z_order = win_par->z_order;
+               reg_win_data->win_id = win_par->win_id;
+       } else {
+               reg_win_data->z_order = -1;
+               reg_win_data->win_id = -1;
+       }
+       for (i = 0; i < reg_win_data->area_num; i++) {
+               rk_fb_check_config_var(&win_par->area_par[i], screen);
+               /* visiable pos in panel */
+               reg_win_data->reg_area_data[i].xpos = win_par->area_par[i].xpos;
                reg_win_data->reg_area_data[i].ypos = win_par->area_par[i].ypos;
 
-               reg_win_data->reg_area_data[i].xsize= win_par->area_par[i].xsize;//realy size in panel
-               reg_win_data->reg_area_data[i].ysize= win_par->area_par[i].ysize;
+               /* realy size in panel */
+               reg_win_data->reg_area_data[i].xsize = win_par->area_par[i].xsize;
+               reg_win_data->reg_area_data[i].ysize = win_par->area_par[i].ysize;
 
-               reg_win_data->reg_area_data[i].xact= win_par->area_par[i].xact;//realy size in panel
-               reg_win_data->reg_area_data[i].yact= win_par->area_par[i].yact; 
+               /* realy size in panel */
+               reg_win_data->reg_area_data[i].xact = win_par->area_par[i].xact;
+               reg_win_data->reg_area_data[i].yact = win_par->area_par[i].yact;
 
-               xoffset = win_par->area_par[i].x_offset;//buf offset
+               xoffset = win_par->area_par[i].x_offset;        /* buf offset */
                yoffset = win_par->area_par[i].y_offset;
                xvir = win_par->area_par[i].xvir;
                reg_win_data->reg_area_data[i].xvir = xvir;
                yvir = win_par->area_par[i].yvir;
                reg_win_data->reg_area_data[i].yvir = yvir;
-               #if 0
-               printk("i=%d,xpos=%d,ypos=%d,xsize=%d,ysize=%d,xact=%d,yact=%d,x_off=%d,y_off=%d,xvir=%d,yvir=%d\n",
-               i,reg_win_data->reg_area_data[i].xpos,reg_win_data->reg_area_data[i].ypos,reg_win_data->reg_area_data[i].xsize,reg_win_data->reg_area_data[i].ysize,
-               reg_win_data->reg_area_data[i].xact,reg_win_data->reg_area_data[i].yact,xoffset,yoffset,xvir,yvir);
-               #endif
 
                vir_width_bit = pixel_width * xvir;
-               stride_128bit_1 = ((vir_width_bit   + 127) & (~127))/8; //pixel_width = byte_num *8
-               stride_128bit_2 = ((vir_width_bit*2 + 127) & (~127))/8; //pixel_width = byte_num *8
-               stride_32bit_1  = ((vir_width_bit   + 31 ) & (~31 ))/8; //pixel_width = byte_num *8
-               stride_32bit_2  = ((vir_width_bit*2 + 31 ) & (~31 ))/8; //pixel_width = byte_num *8
+               /* pixel_width = byte_num*8 */
+               stride_32bit_1 = ((vir_width_bit + 31) & (~31)) / 8;
+               stride_32bit_2 = ((vir_width_bit * 2 + 31) & (~31)) / 8;
 
-               stride    = stride_32bit_1;//default rgb
+               stride = stride_32bit_1;        /* default rgb */
                fix->line_length = stride;
                reg_win_data->reg_area_data[i].y_vir_stride = stride >> 2;
-               // x y mirror ,jump line
-               reg_win_data->reg_area_data[i].y_offset = yoffset*stride+xoffset*pixel_width/8;
+
+               /* x y mirror ,jump line
+                * reg_win_data->reg_area_data[i].y_offset =
+                *              yoffset*stride+xoffset*pixel_width/8;
+                */
+               if (screen->y_mirror == 1) {
+                       if (screen->interlace == 1) {
+                               reg_win_data->reg_area_data[i].y_offset =
+                                   yoffset * stride * 2 +
+                                   ((reg_win_data->reg_area_data[i].yact - 1) * 2 + 1) * stride +
+                                   xoffset * pixel_width / 8;
+                       } else {
+                               reg_win_data->reg_area_data[i].y_offset =
+                                   yoffset * stride +
+                                   (reg_win_data->reg_area_data[i].yact - 1) * stride +
+                                   xoffset * pixel_width / 8;
+                       }
+               } else {
+                       if (screen->interlace == 1) {
+                               reg_win_data->reg_area_data[i].y_offset =
+                                   yoffset * stride * 2 +
+                                   xoffset * pixel_width / 8;
+                       } else {
+                               reg_win_data->reg_area_data[i].y_offset =
+                                   yoffset * stride +
+                                   xoffset * pixel_width / 8;
+                       }
+               }
+
        }
-       switch (fb_data_fmt){
+       switch (fb_data_fmt) {
        case YUV422:
+       case YUV422_A:
                is_pic_yuv = 1;
-               stride     = stride_32bit_1;
-               uv_stride  = stride_32bit_1>> 1 ;//
-               uv_x_off   = xoffset >> 1 ;//
-               uv_y_off   = yoffset;//0
+               stride = stride_32bit_1;
+               uv_stride = stride_32bit_1 >> 1;
+               uv_x_off = xoffset >> 1;
+               uv_y_off = yoffset;
                fix->line_length = stride;
+               uv_y_act = win_par->area_par[0].yact >> 1;
                break;
-       case YUV420://420sp
+       case YUV420:            /* 420sp */
+       case YUV420_A:
                is_pic_yuv = 1;
-               stride     = stride_32bit_1;
-               uv_stride  = stride_32bit_1;
-               uv_x_off   = xoffset;
-               uv_y_off   = yoffset >> 1;
+               stride = stride_32bit_1;
+               uv_stride = stride_32bit_1;
+               uv_x_off = xoffset;
+               uv_y_off = yoffset >> 1;
                fix->line_length = stride;
+               uv_y_act = win_par->area_par[0].yact >> 1;
                break;
        case YUV444:
+       case YUV444_A:
                is_pic_yuv = 1;
-               stride     = stride_32bit_1;
-               uv_stride  = stride_32bit_2;
-               uv_x_off   = xoffset*2;
-               uv_y_off   = yoffset;
-               fix->line_length = stride<<2;
+               stride = stride_32bit_1;
+               uv_stride = stride_32bit_2;
+               uv_x_off = xoffset * 2;
+               uv_y_off = yoffset;
+               fix->line_length = stride << 2;
+               uv_y_act = win_par->area_par[0].yact;
                break;
        default:
                break;
        }
-       if(is_pic_yuv == 1){
-               reg_win_data->reg_area_data[0].cbr_start = 
-                       reg_win_data->reg_area_data[0].smem_start + xvir*yvir;          
-               reg_win_data->reg_area_data[0].c_offset = 
-                       uv_y_off*uv_stride+uv_x_off*pixel_width/8;
-               reg_win_data->reg_area_data[0].uv_vir_stride = 
-                       uv_stride >> 2;
-       }       
+       if (is_pic_yuv == 1) {
+               reg_win_data->reg_area_data[0].cbr_start =
+                   reg_win_data->reg_area_data[0].smem_start + xvir * yvir;
+               reg_win_data->reg_area_data[0].uv_vir_stride = uv_stride >> 2;
+               if (screen->y_mirror == 1) {
+                       if (screen->interlace == 1) {
+                               reg_win_data->reg_area_data[0].c_offset =
+                                   uv_y_off * uv_stride * 2 +
+                                   ((uv_y_act - 1) * 2 + 1) * uv_stride +
+                                   uv_x_off * pixel_width / 8;
+                       } else {
+                               reg_win_data->reg_area_data[0].c_offset =
+                                   uv_y_off * uv_stride +
+                                   (uv_y_act - 1) * uv_stride +
+                                   uv_x_off * pixel_width / 8;
+                       }
+               } else {
+                       if (screen->interlace == 1) {
+                               reg_win_data->reg_area_data[0].c_offset =
+                                   uv_y_off * uv_stride * 2 +
+                                   uv_x_off * pixel_width / 8;
+                       } else {
+                               reg_win_data->reg_area_data[0].c_offset =
+                                   uv_y_off * uv_stride +
+                                   uv_x_off * pixel_width / 8;
+                       }
+               }
+       }
        return 0;
 }
 
 static int rk_fb_set_win_config(struct fb_info *info,
-               struct rk_fb_win_cfg_data *win_data)
+                               struct rk_fb_win_cfg_data *win_data)
 {
-       //struct rk_fb *rk_fb = dev_get_drvdata(info->device);
        struct rk_lcdc_driver *dev_drv = (struct rk_lcdc_driver *)info->par;
        struct rk_fb_reg_data *regs;
-       struct rk_fb_reg_win_data *reg_win_data;
+#ifdef H_USE_FENCE
        struct sync_fence *release_fence[RK_MAX_BUF_NUM];
        struct sync_fence *retire_fence;
        struct sync_pt *release_sync_pt[RK_MAX_BUF_NUM];
        struct sync_pt *retire_sync_pt;
-       int ret,i,j=0,fence_fd;
        char fence_name[20];
+#endif
+       int ret = 0, i, j = 0;
+       int list_is_empty = 0;
 
-       //mutex_lock(&dev_drv->output_lock);
        regs = kzalloc(sizeof(struct rk_fb_reg_data), GFP_KERNEL);
        if (!regs) {
-               printk("could not allocate rk_fb_reg_data\n");
+               printk(KERN_INFO "could not allocate rk_fb_reg_data\n");
                ret = -ENOMEM;
                return ret;
        }
-       
+
+/*
        regs->post_cfg.xpos = win_data->post_cfg.xpos;
        regs->post_cfg.ypos = win_data->post_cfg.ypos;
        regs->post_cfg.xsize = win_data->post_cfg.xsize;
        regs->post_cfg.ysize = win_data->post_cfg.xsize;
-       for (i=0; i<dev_drv->lcdc_win_num; i++) {
-               if(win_data->win_par[i].win_id < dev_drv->lcdc_win_num){
-                       rk_fb_set_win_buffer(info,&win_data->win_par[i],&regs->reg_win_data[j]);
-                       if(regs->reg_win_data[j].area_num > 0){
+*/
+
+       for (i = 0; i < dev_drv->lcdc_win_num; i++) {
+               if (win_data->win_par[i].win_id < dev_drv->lcdc_win_num) {
+                       rk_fb_set_win_buffer(info, &win_data->win_par[i],
+                                            &regs->reg_win_data[j]);
+                       if (regs->reg_win_data[j].area_num > 0) {
                                regs->win_num++;
-                               regs->buf_num += regs->reg_win_data[j].area_buf_num;
+                               regs->buf_num +=
+                                   regs->reg_win_data[j].area_buf_num;
                        }
                        j++;
-               }else{
-                       printk("error:win_id bigger than lcdc_win_num\n");
-                       printk("i=%d,win_id=%d\n",i,win_data->win_par[i].win_id);
-               }
-       }       
-       for(i=0; i<regs->win_num; i++){
-               reg_win_data = &regs->reg_win_data[i];
-               for(j=0;j<RK_WIN_MAX_AREA;j++){
-                       if(reg_win_data->reg_area_data[j].acq_fence){
-                               printk("acq_fence wait!!!!!\n");
-                               rk_fd_fence_wait(dev_drv,
-                               reg_win_data->reg_area_data[j].acq_fence);
-                       }
+               } else {
+                       printk(KERN_INFO "error:win_id bigger than lcdc_win_num\n");
+                       printk(KERN_INFO "i=%d,win_id=%d\n", i,
+                              win_data->win_par[i].win_id);
                }
        }
 
        mutex_lock(&dev_drv->output_lock);
-       if(!(dev_drv->suspend_flag == 0)){
-               rk_fb_update_reg(dev_drv,regs);
-               printk("suspend_flag == 0\n");
+       if (!(dev_drv->suspend_flag == 0)) {
+               rk_fb_update_reg(dev_drv, regs);
+               kfree(regs);
+               printk(KERN_INFO "suspend_flag = 1\n");
                goto err;
        }
-       mutex_lock(&dev_drv->update_regs_list_lock);
+
        dev_drv->timeline_max++;
 #ifdef H_USE_FENCE
-       for(i=0;i<RK_MAX_BUF_NUM;i++){
-               if(i<regs->buf_num){
-                       sprintf(fence_name,"fence%d",i);
-                       win_data->rel_fence_fd[i] =  get_unused_fd();
-                       if (win_data->rel_fence_fd[i] < 0){
-                               printk("rel_fence_fd=%d\n",win_data->rel_fence_fd[i]);
-                               return -EFAULT;
+       for (i = 0; i < RK_MAX_BUF_NUM; i++) {
+               if (i < regs->buf_num) {
+                       sprintf(fence_name, "fence%d", i);
+                       win_data->rel_fence_fd[i] = get_unused_fd();
+                       if (win_data->rel_fence_fd[i] < 0) {
+                               printk(KERN_INFO "rel_fence_fd=%d\n",
+                                      win_data->rel_fence_fd[i]);
+                               ret = -EFAULT;
+                               goto err;
                        }
-                       release_sync_pt[i] = sw_sync_pt_create(dev_drv->timeline,
-                               dev_drv->timeline_max);
-                       release_fence[i] = sync_fence_create(fence_name, release_sync_pt[i]);
-                       sync_fence_install(release_fence[i], win_data->rel_fence_fd[i]);        
-               }else{
+                       release_sync_pt[i] =
+                           sw_sync_pt_create(dev_drv->timeline,
+                                             dev_drv->timeline_max);
+                       release_fence[i] =
+                           sync_fence_create(fence_name, release_sync_pt[i]);
+                       sync_fence_install(release_fence[i],
+                                          win_data->rel_fence_fd[i]);
+               } else {
                        win_data->rel_fence_fd[i] = -1;
                }
        }
-       
-       win_data->ret_fence_fd =  get_unused_fd();
-       if (win_data->ret_fence_fd < 0){
-               printk("ret_fence_fd=%d\n",win_data->ret_fence_fd);
-               return -EFAULT;
+
+       win_data->ret_fence_fd = get_unused_fd();
+       if (win_data->ret_fence_fd < 0) {
+               printk("ret_fence_fd=%d\n", win_data->ret_fence_fd);
+               ret = -EFAULT;
+               goto err;
        }
-       retire_sync_pt = sw_sync_pt_create(dev_drv->timeline, dev_drv->timeline_max);
+       retire_sync_pt =
+           sw_sync_pt_create(dev_drv->timeline, dev_drv->timeline_max);
        retire_fence = sync_fence_create("ret_fence", retire_sync_pt);
        sync_fence_install(retire_fence, win_data->ret_fence_fd);
 #else
-       for(i=0;i<RK_MAX_BUF_NUM;i++){
+       for (i = 0; i < RK_MAX_BUF_NUM; i++)
                win_data->rel_fence_fd[i] = -1;
-       }
-       win_data->ret_fence_fd = -1;    
-#endif 
-       if(dev_drv->wait_fs == 0){
-               list_add_tail(&regs->list,&dev_drv->update_regs_list);  
+
+       win_data->ret_fence_fd = -1;
+#endif
+       if (dev_drv->wait_fs == 0) {
+               mutex_lock(&dev_drv->update_regs_list_lock);
+               list_add_tail(&regs->list, &dev_drv->update_regs_list);
                mutex_unlock(&dev_drv->update_regs_list_lock);
                queue_kthread_work(&dev_drv->update_regs_worker,
-                               &dev_drv->update_regs_work);
-       }else{
+                                  &dev_drv->update_regs_work);
+       } else {
+               mutex_lock(&dev_drv->update_regs_list_lock);
+               list_is_empty = list_empty(&dev_drv->update_regs_list) &&
+                                       list_empty(&saved_list);
                mutex_unlock(&dev_drv->update_regs_list_lock);
-               rk_fb_update_reg(dev_drv,regs);
+               if (!list_is_empty) {
+                       ret = wait_event_timeout(dev_drv->update_regs_wait,
+                               list_empty(&dev_drv->update_regs_list) && list_empty(&saved_list),
+                               msecs_to_jiffies(60));
+                       if (ret > 0)
+                               rk_fb_update_reg(dev_drv, regs);
+                       else
+                               printk("%s: wait update_regs_wait timeout\n", __func__);
+               } else if (ret == 0) {
+                       rk_fb_update_reg(dev_drv, regs);
+               }
+               kfree(regs);
        }
 
 err:
@@ -1322,7 +1992,76 @@ err:
        return ret;
 }
 
-static int rk_fb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
+#if 1
+static int cfgdone_distlist[10] = { 0 };
+
+static int cfgdone_index;
+static int cfgdone_lasttime;
+
+int rk_get_real_fps(int before)
+{
+       struct timespec now;
+       int dist_curr;
+       int dist_total = 0;
+       int dist_count = 0;
+       int dist_first = 0;
+
+       int index = cfgdone_index;
+       int i = 0, fps = 0;
+       int total;
+
+       if (before > 100)
+               before = 100;
+       if (before < 0)
+               before = 0;
+
+       getnstimeofday(&now);
+       dist_curr = (now.tv_sec * 1000000 + now.tv_nsec / 1000) -
+                       cfgdone_lasttime;
+       total = dist_curr;
+       /*
+          printk("fps: ");
+        */
+       for (i = 0; i < 10; i++) {
+               if (--index < 0)
+                       index = 9;
+               total += cfgdone_distlist[index];
+               if (i == 0)
+                       dist_first = cfgdone_distlist[index];
+               if (total < (before * 1000)) {
+                       /*
+                          printk("[%d:%d] ", dist_count, cfgdone_distlist[index]);
+                        */
+                       dist_total += cfgdone_distlist[index];
+                       dist_count++;
+               } else {
+                       break;
+               }
+       }
+
+       /*
+          printk("total %d, count %d, curr %d, ", dist_total, dist_count, dist_curr);
+        */
+       dist_curr = (dist_curr > dist_first) ? dist_curr : dist_first;
+       dist_total += dist_curr;
+       dist_count++;
+
+       if (dist_total > 0)
+               fps = (1000000 * dist_count) / dist_total;
+       else
+               fps = 60;
+
+       /*
+          printk("curr2 %d, fps=%d\n", dist_curr, fps);
+        */
+       return fps;
+}
+EXPORT_SYMBOL(rk_get_real_fps);
+
+#endif
+
+static int rk_fb_ioctl(struct fb_info *info, unsigned int cmd,
+                      unsigned long arg)
 {
        struct rk_fb *rk_fb = dev_get_drvdata(info->device);
        struct rk_lcdc_driver *dev_drv = (struct rk_lcdc_driver *)info->par;
@@ -1332,37 +2071,37 @@ static int rk_fb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg
        struct rk_lcdc_driver *extend_dev_drv = NULL;
        struct rk_lcdc_win *extend_win = NULL;
        struct rk_lcdc_win *win;
-       int enable; /* enable fb:1 enable;0 disable*/
-       int ovl;   /*overlay:0 win1 on the top of win0;1,win0 on the top of win1*/
-       int num_buf; /*buffer_number*/
+       int enable;     /* enable fb:1 enable;0 disable */
+       int ovl;        /* overlay:0 win1 on the top of win0;1,win0 on the top of win1 */
+       int num_buf;    /* buffer_number */
        int ret;
        struct rk_fb_win_cfg_data win_data;
        unsigned int dsp_addr[4];
        int list_stat;
 
-       int  win_id = dev_drv->ops->fb_get_win_id(dev_drv, info->fix.id);
-       
+       int win_id = dev_drv->ops->fb_get_win_id(dev_drv, info->fix.id);
+
        void __user *argp = (void __user *)arg;
        win = dev_drv->win[win_id];
        if (rk_fb->disp_mode == DUAL) {
                fb_id = get_extend_fb_id(info);
-               extend_info = rk_fb->fb[(rk_fb->num_fb>>1) + fb_id];
-               extend_dev_drv  = (struct rk_lcdc_driver *)extend_info->par;
+               extend_info = rk_fb->fb[(rk_fb->num_fb >> 1) + fb_id];
+               extend_dev_drv = (struct rk_lcdc_driver *)extend_info->par;
                extend_win_id = dev_drv->ops->fb_get_win_id(extend_dev_drv,
-                                               extend_info->fix.id);
+                                                           extend_info->fix.id);
                extend_win = extend_dev_drv->win[extend_win_id];
        }
 
        switch (cmd) {
        case RK_FBIOSET_YUV_ADDR:
-       {
-               u32 yuv_phy[2];
-               if (copy_from_user(yuv_phy, argp, 8))
-                       return -EFAULT;
-               fix->smem_start = yuv_phy[0];
-               fix->mmio_start = yuv_phy[1];
-               break;
-       }
+               {
+                       u32 yuv_phy[2];
+                       if (copy_from_user(yuv_phy, argp, 8))
+                               return -EFAULT;
+                       fix->smem_start = yuv_phy[0];
+                       fix->mmio_start = yuv_phy[1];
+                       break;
+               }
        case RK_FBIOSET_ENABLE:
                if (copy_from_user(&enable, argp, sizeof(enable)))
                        return -EFAULT;
@@ -1373,12 +2112,12 @@ static int rk_fb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg
                if (copy_to_user(argp, &enable, sizeof(enable)))
                        return -EFAULT;
                break;
-       case RK_FBIOSET_OVERLAY_STATE:
+       case RK_FBIOSET_OVERLAY_STA:
                if (copy_from_user(&ovl, argp, sizeof(ovl)))
                        return -EFAULT;
                dev_drv->ops->ovl_mgr(dev_drv, ovl, 1);
                break;
-       case RK_FBIOGET_OVERLAY_STATE:
+       case RK_FBIOGET_OVERLAY_STA:
                ovl = dev_drv->ops->ovl_mgr(dev_drv, 0, 0);
                if (copy_to_user(argp, &ovl, sizeof(ovl)))
                        return -EFAULT;
@@ -1395,77 +2134,92 @@ static int rk_fb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg
                break;
 
        case RK_FBIOGET_DSP_ADDR:
-               dev_drv->ops->get_dsp_addr(dev_drv,dsp_addr);
+               dev_drv->ops->get_dsp_addr(dev_drv, dsp_addr);
                if (copy_to_user(argp, &dsp_addr, sizeof(dsp_addr)))
                        return -EFAULT;
                break;
-       case RK_FBIOGET_LIST_STAT:
+       case RK_FBIOGET_LIST_STA:
                list_stat = rk_fb_get_list_stat(dev_drv);
                if (copy_to_user(argp, &list_stat, sizeof(list_stat)))
                        return -EFAULT;
 
                break;
-
-#if defined(CONFIG_ION_ROCKCHIP)
-       case RK_FBIOSET_DMABUF_FD:
-       {
-               int usr_fd;
-               struct ion_handle *hdl;
-               ion_phys_addr_t phy_addr;
-               size_t len;
-               if (copy_from_user(&usr_fd, argp, sizeof(usr_fd)))
+       case RK_FBIOGET_IOMMU_STA:
+               if (copy_to_user(argp, &dev_drv->iommu_enabled,
+                                sizeof(dev_drv->iommu_enabled)))
                        return -EFAULT;
-               hdl = ion_import_dma_buf(rk_fb->ion_client, usr_fd);
-               ion_phys(rk_fb->ion_client, hdl, &phy_addr, &len);
-               fix->smem_start = phy_addr;
                break;
-       }
+#if defined(CONFIG_ION_ROCKCHIP)
+       case RK_FBIOSET_DMABUF_FD:
+               {
+                       int usr_fd;
+                       struct ion_handle *hdl;
+                       ion_phys_addr_t phy_addr;
+                       size_t len;
+                       if (copy_from_user(&usr_fd, argp, sizeof(usr_fd)))
+                               return -EFAULT;
+                       hdl = ion_import_dma_buf(rk_fb->ion_client, usr_fd);
+                       ion_phys(rk_fb->ion_client, hdl, &phy_addr, &len);
+                       fix->smem_start = phy_addr;
+                       break;
+               }
        case RK_FBIOGET_DMABUF_FD:
-       {
-               int fd = ion_share_dma_buf_fd(rk_fb->ion_client, win->area[0].ion_hdl);
-               if (fd < 0) {
-                       dev_err(info->dev, "ion_share_dma_buf_fd failed\n");
-                       return fd;
+               {
+                       int fd =
+                           ion_share_dma_buf_fd(rk_fb->ion_client,
+                                                win->area[0].ion_hdl);
+                       if (fd < 0) {
+                               dev_err(info->dev,
+                                       "ion_share_dma_buf_fd failed\n");
+                               return fd;
+                       }
+                       if (copy_to_user(argp, &fd, sizeof(fd)))
+                               return -EFAULT;
+                       break;
                }
-               if (copy_to_user(argp, &fd, sizeof(fd)))
-                       return -EFAULT;
-               break;
-       }
 #endif
+       case RK_FBIOSET_CLEAR_FB:
+               memset(info->screen_base, 0, get_fb_size());
+               break;
        case RK_FBIOSET_CONFIG_DONE:
-               if(copy_from_user(&win_data,
-                       (struct rk_fb_win_cfg_data __user *)argp,
-                       sizeof(win_data))){
+               {
+                       int curr = 0;
+                       struct timespec now;
+
+                       getnstimeofday(&now);
+                       curr = now.tv_sec * 1000000 + now.tv_nsec / 1000;
+                       cfgdone_distlist[cfgdone_index++] =
+                           curr - cfgdone_lasttime;
+                       /*
+                          printk("%d ", curr - cfgdone_lasttime);
+                        */
+                       cfgdone_lasttime = curr;
+                       if (cfgdone_index >= 10)
+                               cfgdone_index = 0;
+               }
+               if (copy_from_user(&win_data,
+                                  (struct rk_fb_win_cfg_data __user *)argp,
+                                  sizeof(win_data))) {
                        ret = -EFAULT;
                        break;
                };
 
                dev_drv->wait_fs = win_data.wait_fs;
-               rk_fb_set_win_config(info,&win_data);   
+               rk_fb_set_win_config(info, &win_data);
 
                if (copy_to_user((struct rk_fb_win_cfg_data __user *)arg,
-                        &win_data,
-                       sizeof(win_data))) {
+                                &win_data, sizeof(win_data))) {
                        ret = -EFAULT;
                        break;
-               }       
-               memset(&win_data, 0, sizeof(struct rk_fb_win_cfg_data));
-
-               if (rk_fb->disp_mode == DUAL) {
-                       if (extend_win->state && (hdmi_switch_complete)) {
-                               if (rk_fb->num_fb >= 2) {
-                                       if (extend_dev_drv->ops->lcdc_reg_update)
-                                               extend_dev_drv->ops->lcdc_reg_update(extend_dev_drv);
-                               }
-                       }
                }
+               memset(&win_data, 0, sizeof(struct rk_fb_win_cfg_data));
                break;
        default:
                dev_drv->ops->ioctl(dev_drv, cmd, arg, win_id);
                break;
        }
-       
-       return 0;       
+
+       return 0;
 }
 
 static int rk_fb_blank(int blank_mode, struct fb_info *info)
@@ -1479,9 +2233,10 @@ static int rk_fb_blank(int blank_mode, struct fb_info *info)
 
        win_id = dev_drv->ops->fb_get_win_id(dev_drv, fix->id);
        if (win_id < 0)
-               return  -ENODEV;
-#if defined(CONFIG_RK_HDMI)    
-       if ((rk_fb->disp_mode == ONE_DUAL) && (hdmi_get_hotplug() == HDMI_HPD_ACTIVED)) {
+               return -ENODEV;
+#if defined(CONFIG_RK_HDMI)
+       if ((rk_fb->disp_mode == ONE_DUAL)
+           && (hdmi_get_hotplug() == HDMI_HPD_ACTIVED)) {
                printk(KERN_INFO "hdmi is connect , not blank lcdc\n");
        } else
 #endif
@@ -1495,33 +2250,31 @@ static int rk_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
 {
 
        if ((0 == var->xres_virtual) || (0 == var->yres_virtual) ||
-               (0 == var->xres) || (0 == var->yres) || (var->xres < 16) ||
-               ((16 != var->bits_per_pixel) && (32 != var->bits_per_pixel))) {
+           (0 == var->xres) || (0 == var->yres) || (var->xres < 16) ||
+           ((16 != var->bits_per_pixel) &&
+           (32 != var->bits_per_pixel) &&
+           (24 != var->bits_per_pixel))) {
                dev_err(info->dev, "%s check var fail 1:\n"
-                               "xres_vir:%d>>yres_vir:%d\n"
-                               "xres:%d>>yres:%d\n"
-                               "bits_per_pixel:%d\n",
-                               info->fix.id,
-                               var->xres_virtual,
-                               var->yres_virtual,
-                               var->xres,
-                               var->yres,
-                               var->bits_per_pixel);
+                       "xres_vir:%d>>yres_vir:%d\n"
+                       "xres:%d>>yres:%d\n"
+                       "bits_per_pixel:%d\n",
+                       info->fix.id,
+                       var->xres_virtual,
+                       var->yres_virtual,
+                       var->xres, var->yres, var->bits_per_pixel);
                return -EINVAL;
        }
 
-       if (((var->xoffset+var->xres) > var->xres_virtual) ||
-               ((var->yoffset+var->yres) > (var->yres_virtual))) {
+       if (((var->xoffset + var->xres) > var->xres_virtual) ||
+           ((var->yoffset + var->yres) > (var->yres_virtual))) {
                dev_err(info->dev, "%s check_var fail 2:\n"
-                               "xoffset:%d>>xres:%d>>xres_vir:%d\n"
-                               "yoffset:%d>>yres:%d>>yres_vir:%d\n",
-                               info->fix.id,
-                               var->xoffset,
-                               var->xres,
-                               var->xres_virtual,
-                               var->yoffset,
-                               var->yres,
-                               var->yres_virtual);
+                       "xoffset:%d>>xres:%d>>xres_vir:%d\n"
+                       "yoffset:%d>>yres:%d>>yres_vir:%d\n",
+                       info->fix.id,
+                       var->xoffset,
+                       var->xres,
+                       var->xres_virtual,
+                       var->yoffset, var->yres, var->yres_virtual);
                return -EINVAL;
        }
 
@@ -1529,7 +2282,7 @@ static int rk_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
 }
 
 static ssize_t rk_fb_read(struct fb_info *info, char __user *buf,
-                          size_t count, loff_t *ppos)
+                         size_t count, loff_t *ppos)
 {
        unsigned long p = *ppos;
        u8 *buffer, *dst;
@@ -1539,22 +2292,21 @@ static ssize_t rk_fb_read(struct fb_info *info, char __user *buf,
        struct rk_lcdc_driver *dev_drv = (struct rk_lcdc_driver *)info->par;
        struct rk_lcdc_win *win = NULL;
        int win_id = 0;
-       int list_empty=0;
-
-       list_empty = rk_fb_get_list_stat(dev_drv);
-       printk("list_empty=%d\n",list_empty);
 
        win_id = dev_drv->ops->fb_get_win_id(dev_drv, info->fix.id);
        if (win_id < 0)
-               return  -ENODEV;
+               return -ENODEV;
        else
                win = dev_drv->win[win_id];
 
+       /* only read the current frame buffer */
        if (win->format == RGB565)
-               total_size = win->area[0].xact*win->area[0].yact<<1; /*only read the current frame buffer*/
-       else
-               total_size = win->area[0].xact*win->area[0].yact<<2;
-
+               total_size = win->area[0].y_vir_stride * win->area[0].yact << 1;
+       else if (win->format == YUV420) {
+               total_size =
+                   (win->area[0].y_vir_stride * win->area[0].yact * 6);
+       } else
+               total_size = win->area[0].y_vir_stride * win->area[0].yact << 2;
 
        if (p >= total_size)
                return 0;
@@ -1565,15 +2317,14 @@ static ssize_t rk_fb_read(struct fb_info *info, char __user *buf,
        if (count + p > total_size)
                count = total_size - p;
 
-       buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count,
-                        GFP_KERNEL);
+       buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL);
        if (!buffer)
                return -ENOMEM;
 
        src = (u8 __iomem *) (info->screen_base + p + win->area[0].y_offset);
 
        while (count) {
-               c  = (count > PAGE_SIZE) ? PAGE_SIZE : count;
+               c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
                dst = buffer;
                fb_memcpy_fromfb(dst, src, c);
                dst += c;
@@ -1595,7 +2346,7 @@ static ssize_t rk_fb_read(struct fb_info *info, char __user *buf,
 }
 
 static ssize_t rk_fb_write(struct fb_info *info, const char __user *buf,
-                           size_t count, loff_t *ppos)
+                          size_t count, loff_t *ppos)
 {
        unsigned long p = *ppos;
        u8 *buffer, *src;
@@ -1608,14 +2359,15 @@ static ssize_t rk_fb_write(struct fb_info *info, const char __user *buf,
 
        win_id = dev_drv->ops->fb_get_win_id(dev_drv, info->fix.id);
        if (win_id < 0)
-               return  -ENODEV;
+               return -ENODEV;
        else
                win = dev_drv->win[win_id];
 
+       /* write the current frame buffer */
        if (win->format == RGB565)
-               total_size = win->area[0].xact*win->area[0].yact<<1; /*write the current frame buffer*/
+               total_size = win->area[0].xact * win->area[0].yact << 1;
        else
-               total_size = win->area[0].xact*win->area[0].yact<<2;
+               total_size = win->area[0].xact * win->area[0].yact << 2;
 
        if (p > total_size)
                return -EFBIG;
@@ -1632,8 +2384,7 @@ static ssize_t rk_fb_write(struct fb_info *info, const char __user *buf,
                count = total_size - p;
        }
 
-       buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count,
-                        GFP_KERNEL);
+       buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL);
        if (!buffer)
                return -ENOMEM;
 
@@ -1677,153 +2428,239 @@ static int rk_fb_set_par(struct fb_info *info)
        struct rk_screen *screen = dev_drv->cur_screen;
        int win_id = 0;
        u32 cblen = 0, crlen = 0;
-       u16 xsize = 0, ysize = 0;                 /*winx display window height/width --->LCDC_WINx_DSP_INFO*/
-       u32 xoffset = var->xoffset;             /* offset from virtual to visible*/
+       u16 xsize = 0, ysize = 0;       /* winx display window height/width --->LCDC_WINx_DSP_INFO */
+       u32 xoffset = var->xoffset;     /* offset from virtual to visible */
        u32 yoffset = var->yoffset;
-       u16 xpos = (var->nonstd>>8) & 0xfff;   /*visiable pos in panel*/
-       u16 ypos = (var->nonstd>>20) & 0xfff;
+       u16 xpos = (var->nonstd >> 8) & 0xfff;  /*visiable pos in panel */
+       u16 ypos = (var->nonstd >> 20) & 0xfff;
        u32 xvir = var->xres_virtual;
        u32 yvir = var->yres_virtual;
-       u8  data_format = var->nonstd&0xff;
-       u8  fb_data_fmt;
-       u8  pixel_width;
+       u8 data_format = var->nonstd & 0xff;
+       u8 fb_data_fmt;
+       u8 pixel_width;
        u32 vir_width_bit;
-       u32 stride,uv_stride;
-       u32 stride_32bit_1;
-       u32 stride_32bit_2;
-       u32 stride_128bit_1;
-       u32 stride_128bit_2;
-       u16 uv_x_off,uv_y_off;
-       u8  is_pic_yuv=0;
+       u32 stride, uv_stride;
+       u32 stride_32bit_1;
+       u32 stride_32bit_2;
+       u16 uv_x_off, uv_y_off, uv_y_act;
+       u8 is_pic_yuv = 0;
 
        var->pixclock = dev_drv->pixclock;
        win_id = dev_drv->ops->fb_get_win_id(dev_drv, info->fix.id);
        if (win_id < 0)
-               return  -ENODEV;
+               return -ENODEV;
        else
                win = dev_drv->win[win_id];
        if (rk_fb->disp_mode == DUAL) {
                fb_id = get_extend_fb_id(info);
-               extend_info = rk_fb->fb[(rk_fb->num_fb>>1) + fb_id];
-               extend_dev_drv  = (struct rk_lcdc_driver *)extend_info->par;
+               extend_info = rk_fb->fb[(rk_fb->num_fb >> 1) + fb_id];
+               extend_dev_drv = (struct rk_lcdc_driver *)extend_info->par;
                extend_win_id = dev_drv->ops->fb_get_win_id(extend_dev_drv,
-                                       extend_info->fix.id);
+                                                           extend_info->fix.
+                                                           id);
                extend_win = extend_dev_drv->win[extend_win_id];
        }
-       if (var->grayscale>>8) { /*if the application has specific the horizontal and vertical display size*/
-               xsize = (var->grayscale>>8) & 0xfff;
-               ysize = (var->grayscale>>20) & 0xfff;
-       } else  { /*ohterwise  full  screen display*/
+       /* if the application has specific the horizontal and vertical display size */
+       if (var->grayscale >> 8) {
+               xsize = (var->grayscale >> 8) & 0xfff;
+               ysize = (var->grayscale >> 20) & 0xfff;
+       } else {                /*ohterwise  full  screen display */
                xsize = screen->mode.xres;
                ysize = screen->mode.yres;
        }
 
 /*this is for device like rk2928 ,whic have one lcdc but two display outputs*/
 /*save winameter set by android*/
-if (rk_fb->disp_mode != DUAL) {
-       if (screen->screen_id == 0) {
+       if (rk_fb->disp_mode != DUAL) {
+               if (screen->screen_id == 0) {
 
-               dev_drv->screen0->xsize = xsize;
-               dev_drv->screen0->ysize = ysize;
-               dev_drv->screen0->xpos  = xpos;
-               dev_drv->screen0->ypos = ypos;
-       } else {
-               xsize = dev_drv->screen1->xsize;
-               ysize = dev_drv->screen1->ysize;
-               xpos = dev_drv->screen1->xpos;
-               ypos = dev_drv->screen1->ypos;
+                       dev_drv->screen0->xsize = xsize;
+                       dev_drv->screen0->ysize = ysize;
+                       dev_drv->screen0->xpos = xpos;
+                       dev_drv->screen0->ypos = ypos;
+               } else {
+                       xsize = dev_drv->screen1->xsize;
+                       ysize = dev_drv->screen1->ysize;
+                       xpos = dev_drv->screen1->xpos;
+                       ypos = dev_drv->screen1->ypos;
+               }
        }
-}
 
-       fb_data_fmt = rk_fb_data_fmt(data_format,var->bits_per_pixel);
+       fb_data_fmt = rk_fb_data_fmt(data_format, var->bits_per_pixel);
        pixel_width = rk_fb_pixel_width(fb_data_fmt);
        vir_width_bit = pixel_width * xvir;
-       stride_128bit_1 = ((vir_width_bit   + 127) & (~127))/8; //pixel_width = byte_num *8
-       stride_128bit_2 = ((vir_width_bit*2 + 127) & (~127))/8; //pixel_width = byte_num *8
-       stride_32bit_1  = ((vir_width_bit   + 31 ) & (~31 ))/8; //pixel_width = byte_num *8
-       stride_32bit_2  = ((vir_width_bit*2 + 31 ) & (~31 ))/8; //pixel_width = byte_num *8
-
-       stride    = stride_32bit_1;//default rgb
-       fix->line_length = stride;
+       /* pixel_width = byte_num * 8 */
+       stride_32bit_1 = ALIGN_N_TIMES(vir_width_bit, 32) / 8;
+       stride_32bit_2 = ALIGN_N_TIMES(vir_width_bit * 2, 32) / 8;
 
-       switch (fb_data_fmt){
+       switch (fb_data_fmt) {
        case YUV422:
+       case YUV422_A:
                is_pic_yuv = 1;
-               stride     = stride_32bit_1;
-               uv_stride  = stride_32bit_1>> 1 ;//
-               uv_x_off   = xoffset >> 1 ;//
-               uv_y_off   = yoffset;//0
+               stride = stride_32bit_1;
+               uv_stride = stride_32bit_1 >> 1;
+               uv_x_off = xoffset >> 1;
+               uv_y_off = yoffset;
                fix->line_length = stride;
-               cblen = crlen = (xvir*yvir)>>1;
+               cblen = crlen = (xvir * yvir) >> 1;
+               uv_y_act = win->area[0].yact >> 1;
                break;
-       case YUV420://420sp
+       case YUV420:            /* 420sp */
+       case YUV420_A:
                is_pic_yuv = 1;
-               stride     = stride_32bit_1;
-               uv_stride  = stride_32bit_1;
-               uv_x_off   = xoffset;
-               uv_y_off   = yoffset >> 1;
+               stride = stride_32bit_1;
+               uv_stride = stride_32bit_1;
+               uv_x_off = xoffset;
+               uv_y_off = yoffset >> 1;
                fix->line_length = stride;
-               cblen = crlen = (xvir*yvir)>>2;
+               cblen = crlen = (xvir * yvir) >> 2;
+               uv_y_act = win->area[0].yact >> 1;
                break;
        case YUV444:
+       case YUV444_A:
                is_pic_yuv = 1;
-               stride     = stride_32bit_1;
-               uv_stride  = stride_32bit_2;
-               uv_x_off   = xoffset*2;
-               uv_y_off   = yoffset;
-               fix->line_length = stride<<2;
-               cblen = crlen = (xvir*yvir);
+               stride = stride_32bit_1;
+               uv_stride = stride_32bit_2;
+               uv_x_off = xoffset * 2;
+               uv_y_off = yoffset;
+               fix->line_length = stride << 2;
+               cblen = crlen = (xvir * yvir);
+               uv_y_act = win->area[0].yact;
                break;
        default:
+               stride = stride_32bit_1;        /* default rgb */
+               fix->line_length = stride;
                break;
        }
 
-       // x y mirror ,jump line
-       win->area[0].y_offset = yoffset*stride+xoffset*pixel_width/8;
-       if(is_pic_yuv == 1){
-               win->area[0].c_offset = uv_y_off*uv_stride+uv_x_off*pixel_width/8;
+       /* x y mirror ,jump line */
+       if (screen->y_mirror == 1) {
+               if (screen->interlace == 1) {
+                       win->area[0].y_offset = yoffset * stride * 2 +
+                           ((win->area[0].yact - 1) * 2 + 1) * stride +
+                           xoffset * pixel_width / 8;
+               } else {
+                       win->area[0].y_offset = yoffset * stride +
+                           (win->area[0].yact - 1) * stride +
+                           xoffset * pixel_width / 8;
+               }
+       } else {
+               if (screen->interlace == 1) {
+                       win->area[0].y_offset =
+                           yoffset * stride * 2 + xoffset * pixel_width / 8;
+               } else {
+                       win->area[0].y_offset =
+                           yoffset * stride + xoffset * pixel_width / 8;
+               }
+       }
+       if (is_pic_yuv == 1) {
+               if (screen->y_mirror == 1) {
+                       if (screen->interlace == 1) {
+                               win->area[0].c_offset =
+                                   uv_y_off * uv_stride * 2 +
+                                   ((uv_y_act - 1) * 2 + 1) * uv_stride +
+                                   uv_x_off * pixel_width / 8;
+                       } else {
+                               win->area[0].c_offset = uv_y_off * uv_stride +
+                                   (uv_y_act - 1) * uv_stride +
+                                   uv_x_off * pixel_width / 8;
+                       }
+               } else {
+                       if (screen->interlace == 1) {
+                               win->area[0].c_offset =
+                                   uv_y_off * uv_stride * 2 +
+                                   uv_x_off * pixel_width / 8;
+                       } else {
+                               win->area[0].c_offset =
+                                   uv_y_off * uv_stride +
+                                   uv_x_off * pixel_width / 8;
+                       }
+               }
        }
+
        win->format = fb_data_fmt;
-       win->area[0].y_vir_stride = stride>>2;
-       win->area[0].uv_vir_stride = uv_stride>>2;
+       win->area[0].y_vir_stride = stride >> 2;
+       win->area[0].uv_vir_stride = uv_stride >> 2;
        win->area[0].xpos = xpos;
        win->area[0].ypos = ypos;
        win->area[0].xsize = xsize;
        win->area[0].ysize = ysize;
 
        win->area[0].smem_start = fix->smem_start;
-       win->area[0].cbr_start = fix->smem_start+stride*yvir;//fix->mmio_start;
-       win->area[0].xact = var->xres;              /*winx active window height,is a wint of vir*/
+       win->area[0].cbr_start = fix->smem_start + stride * yvir;       /* fix->mmio_start; */
+       win->area[0].xact = var->xres;  /* winx active window height,is a wint of vir */
        win->area[0].yact = var->yres;
-       win->area[0].xvir =  var->xres_virtual;    /*virtual resolution  stride --->LCDC_WINx_VIR*/
-       win->area[0].yvir =  var->yres_virtual;
-       win->state=1;
-       win->area[0].state=1;
+       win->area[0].xvir = var->xres_virtual;  /* virtual resolution  stride --->LCDC_WINx_VIR */
+       win->area[0].yvir = var->yres_virtual;
+       win->area[0].state = 1;
        win->area_num = 1;
+       win->state = 1;
+       win->alpha_mode = 4;    /* AB_SRC_OVER; */
+       win->alpha_en = ((win->format == ARGB888)
+                        || (win->format == ABGR888)) ? 1 : 0;
+       win->g_alpha_val = 0;
 
        if (rk_fb->disp_mode == DUAL) {
                if (extend_win->state && (hdmi_switch_complete)) {
                        if (info != extend_info) {
                                if (win->area[0].xact < win->area[0].yact) {
-                                       //extend_win->xact = win->area[0].yact;
-                                       extend_win->area[0].xact = win->area[0].yact;
-                                       extend_win->area[0].yact = win->area[0].xact;
-                                       extend_win->area[0].xvir = win->area[0].yact;
+                                       extend_win->area[0].xact =
+                                           win->area[0].yact;
+                                       extend_win->area[0].yact =
+                                           win->area[0].xact;
+                                       extend_win->area[0].xvir =
+                                           win->area[0].yact;
                                        extend_info->var.xres = var->yres;
                                        extend_info->var.yres = var->xres;
-                                       extend_info->var.xres_virtual = var->yres;
+                                       extend_info->var.xres_virtual =
+                                           var->yres;
                                } else {
-                                       extend_win->area[0].xact = win->area[0].xact;
-                                       extend_win->area[0].yact = win->area[0].yact;
-                                       extend_win->area[0].xvir = win->area[0].xvir;
+                                       extend_win->area[0].xact =
+                                           win->area[0].xact;
+                                       extend_win->area[0].yact =
+                                           win->area[0].yact;
+                                       extend_win->area[0].xvir =
+                                           win->area[0].xvir;
                                        extend_info->var.xres = var->xres;
                                        extend_info->var.yres = var->yres;
-                                       extend_info->var.xres_virtual = var->xres_virtual;
+                                       extend_info->var.xres_virtual =
+                                           var->xres_virtual;
                                }
+                               extend_win->area[0].y_vir_stride =
+                                   win->area[0].y_vir_stride;
+                               extend_win->area[0].uv_vir_stride =
+                                   win->area[0].uv_vir_stride;
+                               if (win->area[0].xpos != 0
+                                   || win->area[0].ypos != 0) {
+                                       extend_win->area[0].xsize =
+                                           (extend_dev_drv->cur_screen->xsize * win->area[0].xsize) / screen->mode.xres;
+                                       extend_win->area[0].ysize =
+                                           (extend_dev_drv->cur_screen->ysize * win->area[0].ysize) / screen->mode.yres;
+                                       extend_win->area[0].xpos =
+                                           ((extend_dev_drv->cur_screen->mode.xres - extend_dev_drv->cur_screen->xsize) >> 1) +
+                                           extend_dev_drv->cur_screen->xsize * win->area[0].xpos / screen->mode.xres;
+                                       extend_win->area[0].ypos =
+                                           ((extend_dev_drv->cur_screen->mode.yres - extend_dev_drv->cur_screen->ysize) >> 1) +
+                                           extend_dev_drv->cur_screen->ysize * win->area[0].ypos / screen->mode.yres;
+                               } else {        /* the display image of the primary screen is full screen size */
+                                       extend_win->area[0].xpos =
+                                           (extend_dev_drv->cur_screen->mode.xres - extend_dev_drv->cur_screen->xsize) >> 1;
+                                       extend_win->area[0].ypos =
+                                           (extend_dev_drv->cur_screen->mode.yres - extend_dev_drv->cur_screen->ysize) >> 1;
+                                       extend_win->area[0].xsize =
+                                           extend_dev_drv->cur_screen->xsize;
+                                       extend_win->area[0].ysize =
+                                           extend_dev_drv->cur_screen->ysize;
+                               }
+
+                               extend_win->area[0].state = 1;
+                               extend_win->area_num = 1;
+                               extend_win->alpha_en = 0;
                                extend_win->format = win->format;
                                extend_info->var.nonstd &= 0xffffff00;
                                extend_info->var.nonstd |= data_format;
-                               extend_dev_drv->ops->set_par(extend_dev_drv, extend_win_id);
+                               extend_dev_drv->ops->set_par(extend_dev_drv,
+                                                            extend_win_id);
                        }
                }
        }
@@ -1841,8 +2678,8 @@ static inline unsigned int chan_to_field(unsigned int chan,
 }
 
 static int fb_setcolreg(unsigned regno,
-                              unsigned red, unsigned green, unsigned blue,
-                              unsigned transp, struct fb_info *info)
+                       unsigned red, unsigned green, unsigned blue,
+                       unsigned transp, struct fb_info *info)
 {
        unsigned int val;
 
@@ -1851,9 +2688,9 @@ static int fb_setcolreg(unsigned regno,
                /* true-colour, use pseudo-palette */
                if (regno < 16) {
                        u32 *pal = info->pseudo_palette;
-                       val  = chan_to_field(red,   &info->var.red);
+                       val = chan_to_field(red, &info->var.red);
                        val |= chan_to_field(green, &info->var.green);
-                       val |= chan_to_field(blue,  &info->var.blue);
+                       val |= chan_to_field(blue, &info->var.blue);
                        pal[regno] = val;
                }
                break;
@@ -1864,68 +2701,77 @@ static int fb_setcolreg(unsigned regno,
        return 0;
 }
 
-static struct fb_ops fb_ops = {
-       .owner          = THIS_MODULE,
-       .fb_open        = rk_fb_open,
-       .fb_release     = rk_fb_close,
-       .fb_check_var   = rk_fb_check_var,
-       .fb_set_par     = rk_fb_set_par,
-       .fb_blank       = rk_fb_blank,
-       .fb_ioctl       = rk_fb_ioctl,
-       .fb_pan_display = rk_pan_display,
-       .fb_read        = rk_fb_read,
-       .fb_write       = rk_fb_write,
-       .fb_setcolreg   = fb_setcolreg,
-       .fb_fillrect    = cfb_fillrect,
-       .fb_copyarea    = cfb_copyarea,
-       .fb_imageblit   = cfb_imageblit,
-};
+static int rk_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+       struct rk_lcdc_driver *dev_drv = (struct rk_lcdc_driver *)info->par;
+       int win_id = dev_drv->ops->fb_get_win_id(dev_drv, info->fix.id);
+       struct rk_lcdc_win *win;
+       win = dev_drv->win[win_id];
+
+       vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 
+       return dma_buf_mmap(win->area[0].dma_buf, vma, 0);
+}
 
+static struct fb_ops fb_ops = {
+       .owner = THIS_MODULE,
+       .fb_open = rk_fb_open,
+       .fb_release = rk_fb_close,
+       .fb_check_var = rk_fb_check_var,
+       .fb_set_par = rk_fb_set_par,
+       .fb_blank = rk_fb_blank,
+       .fb_ioctl = rk_fb_ioctl,
+       .fb_pan_display = rk_fb_pan_display,
+       .fb_read = rk_fb_read,
+       .fb_write = rk_fb_write,
+       .fb_setcolreg = fb_setcolreg,
+       .fb_fillrect = cfb_fillrect,
+       .fb_copyarea = cfb_copyarea,
+       .fb_imageblit = cfb_imageblit,
+};
 
 static struct fb_var_screeninfo def_var = {
 #if defined(CONFIG_LOGO_LINUX_BMP)
-       .red            = {16, 8, 0},
-       .green          = {8, 8, 0},
-       .blue           = {0, 8, 0},
-       .transp         = {0, 0, 0},
-       .nonstd         = HAL_PIXEL_FORMAT_BGRA_8888,
+       .red = {16, 8, 0},
+       .green = {8, 8, 0},
+       .blue = {0, 8, 0},
+       .transp = {0, 0, 0},
+       .nonstd = HAL_PIXEL_FORMAT_BGRA_8888,
 #else
-       .red            = {11, 5, 0},
-       .green          = {5, 6, 0},
-       .blue           = {0, 5, 0},
-       .transp         = {0, 0, 0},
-       .nonstd         = HAL_PIXEL_FORMAT_RGB_565,   /*(ypos<<20+xpos<<8+format) format*/
+       .red = {11, 5, 0},
+       .green = {5, 6, 0},
+       .blue = {0, 5, 0},
+       .transp = {0, 0, 0},
+       .nonstd = HAL_PIXEL_FORMAT_RGB_565,     /* (ypos<<20+xpos<<8+format) format */
 #endif
-       .grayscale      = 0,  /*(ysize<<20+xsize<<8)*/
-       .activate       = FB_ACTIVATE_NOW,
-       .accel_flags    = 0,
-       .vmode          = FB_VMODE_NONINTERLACED,
+       .grayscale = 0,         /* (ysize<<20+xsize<<8) */
+       .activate = FB_ACTIVATE_NOW,
+       .accel_flags = 0,
+       .vmode = FB_VMODE_NONINTERLACED,
 };
 
 static struct fb_fix_screeninfo def_fix = {
-       .type            = FB_TYPE_PACKED_PIXELS,
-       .type_aux        = 0,
-       .xpanstep        = 1,
-       .ypanstep        = 1,
-       .ywrapstep       = 0,
-       .accel           = FB_ACCEL_NONE,
-       .visual          = FB_VISUAL_TRUECOLOR,
+       .type = FB_TYPE_PACKED_PIXELS,
+       .type_aux = 0,
+       .xpanstep = 1,
+       .ypanstep = 1,
+       .ywrapstep = 0,
+       .accel = FB_ACCEL_NONE,
+       .visual = FB_VISUAL_TRUECOLOR,
 
 };
 
-
 static int rk_fb_wait_for_vsync_thread(void *data)
 {
-       struct rk_lcdc_driver  *dev_drv = data;
-       struct rk_fb *rk_fb =  platform_get_drvdata(fb_pdev);
+       struct rk_lcdc_driver *dev_drv = data;
+       struct rk_fb *rk_fb = platform_get_drvdata(fb_pdev);
        struct fb_info *fbi = rk_fb->fb[0];
 
        while (!kthread_should_stop()) {
                ktime_t timestamp = dev_drv->vsync_info.timestamp;
                int ret = wait_event_interruptible(dev_drv->vsync_info.wait,
-                       !ktime_equal(timestamp, dev_drv->vsync_info.timestamp) &&
-                       (dev_drv->vsync_info.active || dev_drv->vsync_info.irq_stop));
+                               !ktime_equal(timestamp, dev_drv->vsync_info.timestamp) &&
+                               (dev_drv->vsync_info.active || dev_drv->vsync_info.irq_stop));
 
                if (!ret)
                        sysfs_notify(&fbi->dev->kobj, NULL, "vsync");
@@ -1935,25 +2781,24 @@ static int rk_fb_wait_for_vsync_thread(void *data)
 }
 
 static ssize_t rk_fb_vsync_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
+                               struct device_attribute *attr, char *buf)
 {
        struct fb_info *fbi = dev_get_drvdata(dev);
        struct rk_lcdc_driver *dev_drv = (struct rk_lcdc_driver *)fbi->par;
        return scnprintf(buf, PAGE_SIZE, "%llu\n",
-                       ktime_to_ns(dev_drv->vsync_info.timestamp));
+                        ktime_to_ns(dev_drv->vsync_info.timestamp));
 }
 
 static DEVICE_ATTR(vsync, S_IRUGO, rk_fb_vsync_show, NULL);
 
-
-/*****************************************************************
-this two function is for other module that in the kernel which
-need show image directly through fb
-fb_id:we have 4 fb here,default we use fb0 for ui display
-*******************************************************************/
+/*
+ * this two function is for other module that in the kernel which
+ * need show image directly through fb
+ * fb_id:we have 4 fb here,default we use fb0 for ui display
+ */
 struct fb_info *rk_get_fb(int fb_id)
 {
-       struct rk_fb *inf =  platform_get_drvdata(fb_pdev);
+       struct rk_fb *inf = platform_get_drvdata(fb_pdev);
        struct fb_info *fb = inf->fb[fb_id];
        return fb;
 }
@@ -1962,15 +2807,14 @@ EXPORT_SYMBOL(rk_get_fb);
 void rk_direct_fb_show(struct fb_info *fbi)
 {
        rk_fb_set_par(fbi);
-       rk_pan_display(&fbi->var, fbi);
+       rk_fb_pan_display(&fbi->var, fbi);
 }
 EXPORT_SYMBOL(rk_direct_fb_show);
 
-
 static int set_xact_yact_for_hdmi(struct fb_var_screeninfo *pmy_var,
-                                       struct fb_var_screeninfo *hdmi_var)
+                                 struct fb_var_screeninfo *hdmi_var)
 {
-       if (pmy_var->xres < pmy_var->yres) {  /*vertical  lcd screen*/
+       if (pmy_var->xres < pmy_var->yres) {    /* vertical  lcd screen */
                hdmi_var->xres = pmy_var->yres;
                hdmi_var->yres = pmy_var->xres;
                hdmi_var->xres_virtual = pmy_var->yres;
@@ -1983,57 +2827,61 @@ static int set_xact_yact_for_hdmi(struct fb_var_screeninfo *pmy_var,
        return 0;
 
 }
+
 int rk_fb_dpi_open(bool open)
 {
        struct rk_lcdc_driver *dev_drv = NULL;
        dev_drv = rk_get_prmry_lcdc_drv();
-       dev_drv->ops->dpi_open(dev_drv, open);
+       if(dev_drv->ops->dpi_open)
+               dev_drv->ops->dpi_open(dev_drv, open);
 
        return 0;
 }
+
 int rk_fb_dpi_win_sel(int win_id)
 {
        struct rk_lcdc_driver *dev_drv = NULL;
        dev_drv = rk_get_prmry_lcdc_drv();
-       dev_drv->ops->dpi_win_sel(dev_drv, win_id);
+       if(dev_drv->ops->dpi_win_sel)
+               dev_drv->ops->dpi_win_sel(dev_drv, win_id);
 
        return 0;
 }
+
 int rk_fb_dpi_status(void)
 {
-       int ret;
+       int ret = 0;
        struct rk_lcdc_driver *dev_drv = NULL;
        dev_drv = rk_get_prmry_lcdc_drv();
-       ret = dev_drv->ops->dpi_status(dev_drv);
-
+       if(dev_drv->ops->dpi_status)
+               ret = dev_drv->ops->dpi_status(dev_drv);
+       
        return ret;
 }
 
-/******************************************
-*function:this function will be called by hdmi,when
-*             hdmi plug in/out
-*screen: the screen attached to hdmi
-*enable: 1,hdmi plug in,0,hdmi plug out
-*lcdc_id: the lcdc id the hdmi attached ,0 or 1
-******************************************/
-int rk_fb_switch_screen(struct rk_screen *screen , int enable, int lcdc_id)
+/*
+ * function:this function will be called by hdmi,when
+ *             hdmi plug in/out
+ * screen: the screen attached to hdmi
+ * enable: 1,hdmi plug in,0,hdmi plug out
+ * lcdc_id: the lcdc id the hdmi attached ,0 or 1
+ */
+int rk_fb_switch_screen(struct rk_screen *screen, int enable, int lcdc_id)
 {
-       struct rk_fb *rk_fb =  platform_get_drvdata(fb_pdev);
+       struct rk_fb *rk_fb = platform_get_drvdata(fb_pdev);
        struct fb_info *info = NULL;
        struct rk_lcdc_driver *dev_drv = NULL;
-       struct fb_var_screeninfo *hdmi_var    = NULL;
-       struct fb_var_screeninfo *pmy_var = NULL;      /*var for primary screen*/
-       struct fb_info *pmy_info = NULL;
-       struct fb_fix_screeninfo *pmy_fix = NULL;
+       struct fb_var_screeninfo *hdmi_var = NULL;
+       struct fb_var_screeninfo *pmy_var = NULL;       /* var for primary screen */
        int i;
-       struct fb_fix_screeninfo *hdmi_fix    = NULL;
+       struct fb_fix_screeninfo *hdmi_fix = NULL;
        char name[6];
        int ret;
        int win_id;
-
-       //if (rk_fb->disp_mode != DUAL)
-       //      rk29_backlight_set(0);
-
+/*
+       if (rk_fb->disp_mode != DUAL)
+               rk29_backlight_set(0);
+*/
        sprintf(name, "lcdc%d", lcdc_id);
 
        if (rk_fb->disp_mode != DUAL) {
@@ -2052,45 +2900,48 @@ int rk_fb_switch_screen(struct rk_screen *screen , int enable, int lcdc_id)
                        return -ENODEV;
                }
        }
-       printk("hdmi %s lcdc%d\n", enable ? "connect to" : "remove from", dev_drv->id);
+       printk("hdmi %s lcdc%d\n", enable ? "connect to" : "remove from",
+              dev_drv->id);
 
        if (rk_fb->num_lcdc == 1)
                info = rk_fb->fb[0];
        else if (rk_fb->num_lcdc == 2)
-               info = rk_fb->fb[dev_drv->lcdc_win_num]; /*the main fb of lcdc1*/
+               info = rk_fb->fb[dev_drv->lcdc_win_num];        /* the main fb of lcdc1 */
 
-       if (dev_drv->screen1) { /*device like rk2928 ,have only one lcdc but two outputs*/
+       if (dev_drv->screen1) { /* device like rk2928 ,have only one lcdc but two outputs */
                if (enable) {
-                       memcpy(dev_drv->screen1, screen, sizeof(struct rk_screen));
-                       dev_drv->screen1->lcdc_id = 0; /*connect screen1 to output interface 0*/
+                       memcpy(dev_drv->screen1, screen,
+                              sizeof(struct rk_screen));
+                       dev_drv->screen1->lcdc_id = 0;  /* connect screen1 to output interface 0 */
                        dev_drv->screen1->screen_id = 1;
-                       dev_drv->screen0->lcdc_id = 1; /*connect screen0 to output interface 1*/
+                       dev_drv->screen0->lcdc_id = 1;  /* connect screen0 to output interface 1 */
                        dev_drv->cur_screen = dev_drv->screen1;
                        dev_drv->screen0->ext_screen = dev_drv->screen1;
                        if (dev_drv->screen0->sscreen_get) {
                                dev_drv->screen0->sscreen_get(dev_drv->screen0,
-                                       dev_drv->cur_screen->hdmi_resolution);
+                                                             dev_drv->cur_screen->hdmi_resolution);
                        }
 
-
                } else {
-                       dev_drv->screen1->lcdc_id = 1; /*connect screen1 to output interface 1*/
-                       dev_drv->screen0->lcdc_id = 0; /*connect screen0 to output interface 0*/
+                       dev_drv->screen1->lcdc_id = 1;  /* connect screen1 to output interface 1 */
+                       dev_drv->screen0->lcdc_id = 0;  /* connect screen0 to output interface 0 */
                        dev_drv->cur_screen = dev_drv->screen0;
                        dev_drv->screen_ctr_info->set_screen_info(dev_drv->cur_screen,
-                                       dev_drv->screen_ctr_info->lcd_info);
+                                                                 dev_drv->screen_ctr_info->lcd_info);
                }
-       } else{
+       } else {
                if (enable)
                        memcpy(dev_drv->cur_screen, screen, sizeof(struct rk_screen));
        }
 
+       dev_drv->cur_screen->x_mirror = dev_drv->rotate_mode & X_MIRROR;
+       dev_drv->cur_screen->y_mirror = dev_drv->rotate_mode & Y_MIRROR;
 
        win_id = dev_drv->ops->fb_get_win_id(dev_drv, info->fix.id);
 
-       if (!enable && !dev_drv->screen1) { /*only double lcdc device need to close*/
+       if (!enable && !dev_drv->screen1) {     /* only double lcdc device need to close */
                if (dev_drv->win[win_id]->state)
-                       dev_drv->ops->open(dev_drv, win_id, enable); /*disable the win which attached to this fb*/
+                       dev_drv->ops->open(dev_drv, win_id, enable);    /* disable the win which attached to this fb */
                hdmi_switch_complete = 0;
 
                return 0;
@@ -2098,24 +2949,28 @@ int rk_fb_switch_screen(struct rk_screen *screen , int enable, int lcdc_id)
 
        hdmi_var = &info->var;
        hdmi_fix = &info->fix;
-       if (rk_fb->disp_mode  == DUAL) {
+       if (rk_fb->disp_mode == DUAL) {
                if (likely(rk_fb->num_lcdc == 2)) {
                        pmy_var = &rk_fb->fb[0]->var;
-                       pmy_fix = &rk_fb->fb[0]->fix;
                        set_xact_yact_for_hdmi(pmy_var, hdmi_var);
                        hdmi_var->nonstd &= 0xffffff00;
-                       hdmi_var->nonstd |= (pmy_var->nonstd & 0xff); /*use the same format as primary screen*/
+                       hdmi_var->nonstd |= (pmy_var->nonstd & 0xff);   /* use the same format as primary screen */
                } else {
-                       printk(KERN_WARNING "%s>>only one lcdc,dual display no supported!", __func__);
+                       printk(KERN_WARNING
+                              "%s>>only one lcdc,dual display no supported!",
+                              __func__);
                }
        }
        hdmi_var->grayscale &= 0xff;
-       hdmi_var->grayscale |= (dev_drv->cur_screen->mode.xres<<8) + (dev_drv->cur_screen->mode.yres<<20);
-       if (dev_drv->screen1) { /*device like rk2928,whic have one lcdc but two outputs*/
-       /*      info->var.nonstd &= 0xff;
+       hdmi_var->grayscale |=
+           (dev_drv->cur_screen->mode.xres << 8) + (dev_drv->cur_screen->mode.yres << 20);
+       if (dev_drv->screen1) { /* device like rk2928,whic have one lcdc but two outputs */
+               /*
+               info->var.nonstd &= 0xff;
                info->var.nonstd |= (dev_drv->cur_screen->mode.xpos<<8) + (dev_drv->cur_screen->mode.ypos<<20);
                info->var.grayscale &= 0xff;
-               info->var.grayscale |= (dev_drv->cur_screen->mode.x_res<<8) + (dev_drv->cur_screen->mode.y_res<<20);*/
+               info->var.grayscale |= (dev_drv->cur_screen->mode.x_res<<8) + (dev_drv->cur_screen->mode.y_res<<20);
+               */
                dev_drv->screen1->xsize = dev_drv->cur_screen->mode.xres;
                dev_drv->screen1->ysize = dev_drv->cur_screen->mode.yres;
                dev_drv->screen1->xpos = 0;
@@ -2128,17 +2983,10 @@ int rk_fb_switch_screen(struct rk_screen *screen , int enable, int lcdc_id)
        if (dev_drv->ops->lcdc_hdmi_process)
                dev_drv->ops->lcdc_hdmi_process(dev_drv, enable);
 
-       if (rk_fb->disp_mode == DUAL) {
-               if (likely(rk_fb->num_lcdc == 2)) {
-                       pmy_info = rk_fb->fb[0];
-                       pmy_info->fbops->fb_pan_display(pmy_var, pmy_info);
-               } else {
-                       printk(KERN_WARNING "%s>>only one lcdc,dual display no supported!", __func__);
-               }
-       } else {
-               info->fbops->fb_pan_display(hdmi_var, info);
-       }
-       info->fbops->fb_ioctl(info, RK_FBIOSET_CONFIG_DONE, 0);
+       hdmi_switch_complete = enable;
+       info->fbops->fb_pan_display(hdmi_var, info);
+
+       /* info->fbops->fb_ioctl(info, RK_FBIOSET_CONFIG_DONE, 0); */
        if (dev_drv->screen1) {
                if (dev_drv->screen0->sscreen_set) {
                        dev_drv->ops->blank(dev_drv, 0, FB_BLANK_NORMAL);
@@ -2147,34 +2995,29 @@ int rk_fb_switch_screen(struct rk_screen *screen , int enable, int lcdc_id)
                        dev_drv->ops->blank(dev_drv, 0, FB_BLANK_UNBLANK);
                }
        }
-
-       //if (rk_fb->disp_mode != DUAL)
-       //      rk29_backlight_set(1);
-       hdmi_switch_complete = enable;
+       /*
+       if (rk_fb->disp_mode != DUAL)
+               rk29_backlight_set(1);
+       */
        return 0;
 
 }
 
-
-
-
-/******************************************
-function:this function current only called by hdmi for
-       scale the display
-scale_x: scale rate of x resolution
-scale_y: scale rate of y resolution
-lcdc_id: the lcdc id the hdmi attached ,0 or 1
-******************************************/
-
+/*
+ * function:this function current only called by hdmi for
+ *     scale the display
+ * scale_x: scale rate of x resolution
+ * scale_y: scale rate of y resolution
+ * lcdc_id: the lcdc id the hdmi attached ,0 or 1
+ */
 int rk_fb_disp_scale(u8 scale_x, u8 scale_y, u8 lcdc_id)
 {
-       struct rk_fb *inf =  platform_get_drvdata(fb_pdev);
+       struct rk_fb *inf = platform_get_drvdata(fb_pdev);
        struct fb_info *info = NULL;
        struct fb_var_screeninfo *var = NULL;
        struct rk_lcdc_driver *dev_drv = NULL;
        u16 screen_x, screen_y;
        u16 xpos, ypos;
-       u16 xsize, ysize;
        char name[6];
        int i = 0;
        sprintf(name, "lcdc%d", lcdc_id);
@@ -2206,29 +3049,81 @@ int rk_fb_disp_scale(u8 scale_x, u8 scale_y, u8 lcdc_id)
 
 #if defined(CONFIG_ONE_LCDC_DUAL_OUTPUT_INF) || defined(CONFIG_NO_DUAL_DISP)
        if (dev_drv->cur_screen->screen_id == 1) {
-               dev_drv->cur_screen->xpos = (screen_x-screen_x*scale_x/100)>>1;
-               dev_drv->cur_screen->ypos = (screen_y-screen_y*scale_y/100)>>1;
-               dev_drv->cur_screen->xsize = screen_x*scale_x/100;
-               dev_drv->cur_screen->ysize = screen_y*scale_y/100;
+               dev_drv->cur_screen->xpos =
+                   (screen_x - screen_x * scale_x / 100) >> 1;
+               dev_drv->cur_screen->ypos =
+                   (screen_y - screen_y * scale_y / 100) >> 1;
+               dev_drv->cur_screen->xsize = screen_x * scale_x / 100;
+               dev_drv->cur_screen->ysize = screen_y * scale_y / 100;
        } else
 #endif
        {
-               xpos = (screen_x-screen_x*scale_x/100)>>1;
-               ypos = (screen_y-screen_y*scale_y/100)>>1;
-               xsize = screen_x*scale_x/100;
-               ysize = screen_y*scale_y/100;
+               xpos = (screen_x - screen_x * scale_x / 100) >> 1;
+               ypos = (screen_y - screen_y * scale_y / 100) >> 1;
+               dev_drv->cur_screen->xsize = screen_x * scale_x / 100;
+               dev_drv->cur_screen->ysize = screen_y * scale_y / 100;
                var->nonstd &= 0xff;
-               var->nonstd |= (xpos<<8) + (ypos<<20);
+               var->nonstd |= (xpos << 8) + (ypos << 20);
                var->grayscale &= 0xff;
-               var->grayscale |= (xsize<<8) + (ysize<<20);
+               var->grayscale |=
+                   (dev_drv->cur_screen->xsize << 8) + (dev_drv->cur_screen->ysize << 20);
        }
 
        info->fbops->fb_set_par(info);
-       info->fbops->fb_ioctl(info, RK_FBIOSET_CONFIG_DONE, 0);
+       /* info->fbops->fb_ioctl(info, RK_FBIOSET_CONFIG_DONE, 0); */
+       dev_drv->ops->cfg_done(dev_drv);
        return 0;
 
+}
+
+#if defined(CONFIG_ION_ROCKCHIP)
+static int rk_fb_alloc_buffer_by_ion(struct fb_info *fbi,
+                                    struct rk_lcdc_win *win,
+                                    unsigned long fb_mem_size)
+{
+       struct rk_fb *rk_fb = platform_get_drvdata(fb_pdev);
+       struct rk_lcdc_driver *dev_drv = (struct rk_lcdc_driver *)fbi->par;
+       struct ion_handle *handle;
+       ion_phys_addr_t phy_addr;
+       size_t len;
+       if (dev_drv->iommu_enabled)
+               handle = ion_alloc(rk_fb->ion_client, (size_t) fb_mem_size, 0,
+                                  ION_HEAP(ION_VMALLOC_HEAP_ID), 0);
+       else
+               handle = ion_alloc(rk_fb->ion_client, (size_t) fb_mem_size, 0,
+                                  ION_HEAP(ION_CMA_HEAP_ID), 0);
+       if (IS_ERR(handle)) {
+               dev_err(fbi->device, "failed to ion_alloc:%ld\n",
+                       PTR_ERR(handle));
+               return -ENOMEM;
+       }
+       win->area[0].dma_buf = ion_share_dma_buf(rk_fb->ion_client, handle);
+       if (IS_ERR_OR_NULL(win->area[0].dma_buf)) {
+               printk("ion_share_dma_buf() failed\n");
+               goto err_share_dma_buf;
+       }
+       win->area[0].ion_hdl = handle;
+       fbi->screen_base = ion_map_kernel(rk_fb->ion_client, handle);
+#ifdef CONFIG_ROCKCHIP_IOMMU
+       if (dev_drv->iommu_enabled)
+               ion_map_iommu(dev_drv->dev, rk_fb->ion_client, handle,
+                             (unsigned long *)&phy_addr,
+                             (unsigned long *)&len);
+       else
+               ion_phys(rk_fb->ion_client, handle, &phy_addr, &len);
+#else
+       ion_phys(rk_fb->ion_client, handle, &phy_addr, &len);
+#endif
+       fbi->fix.smem_start = phy_addr;
+       fbi->fix.smem_len = len;
+       printk(KERN_INFO "alloc_buffer:ion_phy_addr=0x%lx\n", phy_addr);
+       return 0;
 
+err_share_dma_buf:
+       ion_free(rk_fb->ion_client, handle);
+       return -ENOMEM;
 }
+#endif
 
 static int rk_fb_alloc_buffer(struct fb_info *fbi, int fb_id)
 {
@@ -2238,41 +3133,28 @@ static int rk_fb_alloc_buffer(struct fb_info *fbi, int fb_id)
        int win_id;
        int ret = 0;
        unsigned long fb_mem_size;
-#if defined(CONFIG_ION_ROCKCHIP)
-       struct ion_handle *handle;
-       ion_phys_addr_t phy_addr;
-       size_t len;
-#else
+#if !defined(CONFIG_ION_ROCKCHIP)
        dma_addr_t fb_mem_phys;
        void *fb_mem_virt;
 #endif
+
        win_id = dev_drv->ops->fb_get_win_id(dev_drv, fbi->fix.id);
        if (win_id < 0)
-               return  -ENODEV;
+               return -ENODEV;
        else
                win = dev_drv->win[win_id];
 
        if (!strcmp(fbi->fix.id, "fb0")) {
-               fb_mem_size = 3 * (fbi->var.xres * fbi->var.yres) << 2;
-               fb_mem_size = ALIGN(fb_mem_size, SZ_1M);
+               fb_mem_size = get_fb_size();
 #if defined(CONFIG_ION_ROCKCHIP)
-               handle = ion_alloc(rk_fb->ion_client, (size_t)fb_mem_size, 0, ION_HEAP(ION_CMA_HEAP_ID), 0);
-               if (IS_ERR(handle)) {
-                       dev_err(fbi->device, "failed to ion_alloc:%ld\n",PTR_ERR(handle));
+               if (rk_fb_alloc_buffer_by_ion(fbi, win, fb_mem_size) < 0)
                        return -ENOMEM;
-               }
-               win->area[0].ion_hdl = handle;
-               fbi->screen_base = ion_map_kernel(rk_fb->ion_client, handle);
-               ion_phys(rk_fb->ion_client, handle, &phy_addr, &len);
-               fbi->fix.smem_start = phy_addr;
-               fbi->fix.smem_len = len;
-               printk("alloc_buffer:smem_start=0x%x\n",phy_addr);
 #else
-
-               fb_mem_virt = dma_alloc_writecombine(fbi->dev, fb_mem_size, &fb_mem_phys,
-                       GFP_KERNEL);
+               fb_mem_virt = dma_alloc_writecombine(fbi->dev, fb_mem_size,
+                                                    &fb_mem_phys, GFP_KERNEL);
                if (!fb_mem_virt) {
-                       pr_err("%s: Failed to allocate framebuffer\n", __func__);
+                       pr_err("%s: Failed to allocate framebuffer\n",
+                              __func__);
                        return -ENOMEM;
                }
                fbi->fix.smem_len = fb_mem_size;
@@ -2281,28 +3163,35 @@ static int rk_fb_alloc_buffer(struct fb_info *fbi, int fb_id)
 #endif
                memset(fbi->screen_base, 0, fbi->fix.smem_len);
                printk(KERN_INFO "fb%d:phy:%lx>>vir:%p>>len:0x%x\n", fb_id,
-               fbi->fix.smem_start, fbi->screen_base, fbi->fix.smem_len);
+                      fbi->fix.smem_start, fbi->screen_base,
+                      fbi->fix.smem_len);
        } else {
-#if defined(CONFIG_FB_ROTATE) || !defined(CONFIG_THREE_FB_BUFFER)
-               res = platform_get_resource_byname(fb_pdev,
-                       IORESOURCE_MEM, "fb2 buf");
-               if (res == NULL) {
-                       dev_err(&fb_pdev->dev, "failed to get win0 memory \n");
-                       ret = -ENOENT;
-               }
-               fbi->fix.smem_start = res->start;
-               fbi->fix.smem_len = res->end - res->start + 1;
-               mem = request_mem_region(res->start, resource_size(res),
-                       fb_pdev->name);
-               fbi->screen_base = ioremap(res->start, fbi->fix.smem_len);
-               memset(fbi->screen_base, 0, fbi->fix.smem_len);
-#else    /*three buffer no need to copy*/
-               fbi->fix.smem_start = rk_fb->fb[0]->fix.smem_start;
-               fbi->fix.smem_len   = rk_fb->fb[0]->fix.smem_len;
-               fbi->screen_base    = rk_fb->fb[0]->screen_base;
+               if (dev_drv->rotate_mode > X_Y_MIRROR) {
+                       fb_mem_size = get_fb_size();
+#if defined(CONFIG_ION_ROCKCHIP)
+                       if (rk_fb_alloc_buffer_by_ion(fbi, win, fb_mem_size) < 0)
+                               return -ENOMEM;
+#else
+                       fb_mem_virt = dma_alloc_writecombine(fbi->dev,
+                                       fb_mem_size, &fb_mem_phys, GFP_KERNEL);
+                       if (!fb_mem_virt) {
+                               pr_err("%s: Failed to allocate framebuffer\n",
+                                       __func__);
+                               return -ENOMEM;
+                       }
+                       fbi->fix.smem_len = fb_mem_size;
+                       fbi->fix.smem_start = fb_mem_phys;
+                       fbi->screen_base = fb_mem_virt;
 #endif
+               } else {
+                       fbi->fix.smem_start = rk_fb->fb[0]->fix.smem_start;
+                       fbi->fix.smem_len = rk_fb->fb[0]->fix.smem_len;
+                       fbi->screen_base = rk_fb->fb[0]->screen_base;
+               }
+
                printk(KERN_INFO "fb%d:phy:%lx>>vir:%p>>len:0x%x\n", fb_id,
-                       fbi->fix.smem_start, fbi->screen_base, fbi->fix.smem_len);
+                      fbi->fix.smem_start, fbi->screen_base,
+                      fbi->fix.smem_len);
        }
 
        fbi->screen_size = fbi->fix.smem_len;
@@ -2315,60 +3204,74 @@ static int rk_fb_alloc_buffer(struct fb_info *fbi, int fb_id)
        return ret;
 }
 
+#if 0
 static int rk_release_fb_buffer(struct fb_info *fbi)
 {
-       if (!strcmp(fbi->fix.id, "fb1") || !strcmp(fbi->fix.id, "fb3"))  /*buffer for fb1 and fb3 are alloc by android*/
+       /* buffer for fb1 and fb3 are alloc by android */
+       if (!strcmp(fbi->fix.id, "fb1") || !strcmp(fbi->fix.id, "fb3"))
                return 0;
        iounmap(fbi->screen_base);
        release_mem_region(fbi->fix.smem_start, fbi->fix.smem_len);
        return 0;
 
 }
-static int init_lcdc_win(struct rk_lcdc_driver *dev_drv, struct rk_lcdc_win *def_win)
+#endif
+
+static int init_lcdc_win(struct rk_lcdc_driver *dev_drv,
+                        struct rk_lcdc_win *def_win)
 {
        int i;
        int lcdc_win_num = dev_drv->lcdc_win_num;
        for (i = 0; i < lcdc_win_num; i++) {
                struct rk_lcdc_win *win = NULL;
-               win =  kzalloc(sizeof(struct rk_lcdc_win), GFP_KERNEL);
+               win = kzalloc(sizeof(struct rk_lcdc_win), GFP_KERNEL);
                if (!win) {
                        dev_err(dev_drv->dev, "kzmalloc for win fail!");
-                       return   -ENOMEM;
+                       return -ENOMEM;
                }
 
-               strcpy(win->name, def_win->name);
-               win->id = def_win->id;
-               win->support_3d = def_win->support_3d;
+               strcpy(win->name, def_win[i].name);
+               win->id = def_win[i].id;
+               win->support_3d = def_win[i].support_3d;
                dev_drv->win[i] = win;
        }
 
        return 0;
 }
 
-
 static int init_lcdc_device_driver(struct rk_fb *rk_fb,
-                                       struct rk_lcdc_win *def_win, int index)
+                                  struct rk_lcdc_win *def_win, int index)
 {
        struct rk_lcdc_driver *dev_drv = rk_fb->lcdc_dev_drv[index];
        struct rk_screen *screen = devm_kzalloc(dev_drv->dev,
-                               sizeof(struct rk_screen), GFP_KERNEL);
+                                               sizeof(struct rk_screen),
+                                               GFP_KERNEL);
        if (!screen) {
                dev_err(dev_drv->dev, "malloc screen for lcdc%d fail!",
-                                       dev_drv->id);
+                       dev_drv->id);
                return -ENOMEM;
        }
-       
+
        screen->screen_id = 0;
        screen->lcdc_id = dev_drv->id;
+       screen->overscan.left = 100;
+       screen->overscan.top = 100;
+       screen->overscan.right = 100;
+       screen->overscan.bottom = 100;
+
+       screen->x_mirror = dev_drv->rotate_mode & X_MIRROR;
+       screen->y_mirror = dev_drv->rotate_mode & Y_MIRROR;
+
        dev_drv->screen0 = screen;
        dev_drv->cur_screen = screen;
-       /* devie use one lcdc + rk61x scaler for dual display*/
+       /* devie use one lcdc + rk61x scaler for dual display */
        if (rk_fb->disp_mode == ONE_DUAL) {
                struct rk_screen *screen1 = devm_kzalloc(dev_drv->dev,
-                                               sizeof(struct rk_screen), GFP_KERNEL);
+                                                        sizeof(struct rk_screen),
+                                                        GFP_KERNEL);
                if (screen1) {
                        dev_err(dev_drv->dev, "malloc screen1 for lcdc%d fail!",
-                                               dev_drv->id);
+                               dev_drv->id);
                        return -ENOMEM;
                }
                screen1->screen_id = 1;
@@ -2383,8 +3286,11 @@ static int init_lcdc_device_driver(struct rk_fb *rk_fb,
        dev_drv->ops->fb_win_remap(dev_drv, FB_DEFAULT_ORDER);
        dev_drv->first_frame = 1;
        rk_disp_pwr_ctr_parse_dt(dev_drv);
-       if (dev_drv->prop == PRMRY)
+       if (dev_drv->prop == PRMRY) {
+               dev_drv->ops->set_dsp_cabc(dev_drv, dev_drv->cabc_mode);
+               rk_fb_set_prmry_screen(screen);
                rk_fb_get_prmry_screen(screen);
+       }
        dev_drv->trsm_ops = rk_fb_trsm_ops_get(screen->type);
 
        return 0;
@@ -2407,37 +3313,39 @@ static void fb_show_bmp_logo(struct fb_info *info, int rotate)
        unsigned char *src = bmp_logo->data;
        unsigned char *dst = info->screen_base;
        int i;
-       unsigned int Needwidth = (*(src-24)<<8) | (*(src-23));
-       unsigned int Needheight = (*(src-22)<<8) | (*(src-21));
+       unsigned int Needwidth = (*(src - 24) << 8) | (*(src - 23));
+       unsigned int Needheight = (*(src - 22) << 8) | (*(src - 21));
 
        for (i = 0; i < Needheight; i++)
-               memcpy(dst+info->var.xres*i*4,
-                       src+bmp_logo->width*i*4, Needwidth*4);
+               memcpy(dst + info->var.xres * i * 4,
+                      src + bmp_logo->width * i * 4, Needwidth * 4);
 
 }
 #endif
 
-/********************************
-*check if the primary lcdc has registerd,
-the primary lcdc mas register first
-*********************************/
+/*
+ * check if the primary lcdc has registerd,
+ * the primary lcdc mas register first
+ */
 bool is_prmry_rk_lcdc_registered(void)
 {
        struct rk_fb *rk_fb = platform_get_drvdata(fb_pdev);
        if (rk_fb->lcdc_dev_drv[0])
-               return  true;
+               return true;
        else
                return false;
 
-
 }
+
 int rk_fb_register(struct rk_lcdc_driver *dev_drv,
-                               struct rk_lcdc_win *win, int id)
+                  struct rk_lcdc_win *win, int id)
 {
        struct rk_fb *rk_fb = platform_get_drvdata(fb_pdev);
        struct fb_info *fbi;
        int i = 0, ret = 0, index = 0;
-
+#if defined(CONFIG_ROCKCHIP_IOMMU)
+       struct device *mmu_dev = NULL;
+#endif
        if (rk_fb->num_lcdc == RK30_MAX_LCDC_SUPPORT)
                return -ENXIO;
 
@@ -2464,42 +3372,49 @@ int rk_fb_register(struct rk_lcdc_driver *dev_drv,
                fbi->fix = def_fix;
                sprintf(fbi->fix.id, "fb%d", rk_fb->num_fb);
                fb_videomode_to_var(&fbi->var, &dev_drv->cur_screen->mode);
-               fbi->var.grayscale |= (fbi->var.xres<<8) + (fbi->var.yres<<20);
+               fbi->var.grayscale |=
+                   (fbi->var.xres << 8) + (fbi->var.yres << 20);
 #if defined(CONFIG_LOGO_LINUX_BMP)
                fbi->var.bits_per_pixel = 32;
 #else
                fbi->var.bits_per_pixel = 16;
 #endif
-               fbi->fix.line_length  = (fbi->var.xres)*(fbi->var.bits_per_pixel>>3);
+               fbi->fix.line_length =
+                   (fbi->var.xres_virtual) * (fbi->var.bits_per_pixel >> 3);
                fbi->var.width = dev_drv->cur_screen->width;
                fbi->var.height = dev_drv->cur_screen->height;
                fbi->var.pixclock = dev_drv->pixclock;
+               if (dev_drv->iommu_enabled)
+                       fb_ops.fb_mmap = rk_fb_mmap;
                fbi->fbops = &fb_ops;
                fbi->flags = FBINFO_FLAG_DEFAULT;
                fbi->pseudo_palette = dev_drv->win[i]->pseudo_pal;
-               if (i == 0) /* only alloc memory for main fb*/
-                       rk_fb_alloc_buffer(fbi, rk_fb->num_fb);
                ret = register_framebuffer(fbi);
                if (ret < 0) {
-                       dev_err(&fb_pdev->dev, "%s fb%d register_framebuffer fail!\n",
-                                       __func__, rk_fb->num_fb);
+                       dev_err(&fb_pdev->dev,
+                               "%s fb%d register_framebuffer fail!\n",
+                               __func__, rk_fb->num_fb);
                        return ret;
                }
                rkfb_create_sysfs(fbi);
                rk_fb->fb[rk_fb->num_fb] = fbi;
-               dev_info(&fb_pdev->dev, "rockchip framebuffer registerd:%s\n",
-                                       fbi->fix.id);
+               dev_info(fbi->dev, "rockchip framebuffer registerd:%s\n",
+                        fbi->fix.id);
                rk_fb->num_fb++;
 
                if (i == 0) {
                        init_waitqueue_head(&dev_drv->vsync_info.wait);
+                       init_waitqueue_head(&dev_drv->update_regs_wait);
                        ret = device_create_file(fbi->dev, &dev_attr_vsync);
                        if (ret)
-                               dev_err(fbi->dev, "failed to create vsync file\n");
-                       dev_drv->vsync_info.thread = kthread_run(rk_fb_wait_for_vsync_thread,
-                                                               dev_drv, "fb-vsync");
+                               dev_err(fbi->dev,
+                                       "failed to create vsync file\n");
+                       dev_drv->vsync_info.thread =
+                           kthread_run(rk_fb_wait_for_vsync_thread, dev_drv,
+                                       "fb-vsync");
                        if (dev_drv->vsync_info.thread == ERR_PTR(-ENOMEM)) {
-                               dev_err(fbi->dev, "failed to run vsync thread\n");
+                               dev_err(fbi->dev,
+                                       "failed to run vsync thread\n");
                                dev_drv->vsync_info.thread = NULL;
                        }
                        dev_drv->vsync_info.active = 1;
@@ -2510,7 +3425,8 @@ int rk_fb_register(struct rk_lcdc_driver *dev_drv,
                        mutex_init(&dev_drv->update_regs_list_lock);
                        init_kthread_worker(&dev_drv->update_regs_worker);
 
-                       dev_drv->update_regs_thread = kthread_run(kthread_worker_fn,
+                       dev_drv->update_regs_thread =
+                           kthread_run(kthread_worker_fn,
                                        &dev_drv->update_regs_worker, "rk-fb");
                        if (IS_ERR(dev_drv->update_regs_thread)) {
                                int err = PTR_ERR(dev_drv->update_regs_thread);
@@ -2519,40 +3435,68 @@ int rk_fb_register(struct rk_lcdc_driver *dev_drv,
                                printk("failed to run update_regs thread\n");
                                return err;
                        }
-                       init_kthread_work(&dev_drv->update_regs_work, rk_fb_update_regs_handler);
+                       init_kthread_work(&dev_drv->update_regs_work,
+                                         rk_fb_update_regs_handler);
 
-                       dev_drv->timeline = sw_sync_timeline_create("fb-timeline");                     dev_drv->timeline_max = 1;
+                       dev_drv->timeline =
+                           sw_sync_timeline_create("fb-timeline");
+                       dev_drv->timeline_max = 1;
                }
 
        }
 
/*show logo for primary display device*/
      /* show logo for primary display device */
 #if !defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_LOGO)
-if (dev_drv->prop == PRMRY) {
-       struct fb_info *main_fbi = rk_fb->fb[0];
-       main_fbi->fbops->fb_open(main_fbi, 1);
-       main_fbi->fbops->fb_set_par(main_fbi);
+       if (dev_drv->prop == PRMRY) {
+               struct fb_info *main_fbi = rk_fb->fb[0];
+               main_fbi->fbops->fb_open(main_fbi, 1);
+#if defined(CONFIG_ROCKCHIP_IOMMU)
+               if (dev_drv->iommu_enabled) {
+                       mmu_dev =
+                           rockchip_get_sysmmu_device_by_compatible(dev_drv->mmu_dts_name);
+                       if (mmu_dev) {
+                               platform_set_sysmmu(mmu_dev, dev_drv->dev);
+                               rockchip_sysmmu_set_fault_handler(dev_drv->dev,
+                                                                 rk_fb_sysmmu_fault_handler);
+                               iovmm_activate(dev_drv->dev);
+                       } else
+                               dev_err(dev_drv->dev,
+                                       "failed to get rockchip iommu device\n");
+               }
+#endif
+               rk_fb_alloc_buffer(main_fbi, 0);        /* only alloc memory for main fb */
+               if (support_uboot_display()) {
+                       if (dev_drv->iommu_enabled) {
+                               rk_fb_copy_from_loader(main_fbi);
+                               dev_drv->ops->direct_set_addr(dev_drv, 0,
+                                                             main_fbi->fix.smem_start);
+                       }
+                       return 0;
+               }
+               main_fbi->fbops->fb_set_par(main_fbi);
 #if  defined(CONFIG_LOGO_LINUX_BMP)
-       if (fb_prewine_bmp_logo(main_fbi, FB_ROTATE_UR)) {
-               fb_set_cmap(&main_fbi->cmap, main_fbi);
-               fb_show_bmp_logo(main_fbi, FB_ROTATE_UR);
-               main_fbi->fbops->fb_pan_display(&main_fbi->var, main_fbi);
-       }
+               if (fb_prewine_bmp_logo(main_fbi, FB_ROTATE_UR)) {
+                       fb_set_cmap(&main_fbi->cmap, main_fbi);
+                       fb_show_bmp_logo(main_fbi, FB_ROTATE_UR);
+               }
 #else
-       if (fb_prepare_logo(main_fbi, FB_ROTATE_UR)) {
-               fb_set_cmap(&main_fbi->cmap, main_fbi);
-               fb_show_logo(main_fbi, FB_ROTATE_UR);
+               if (fb_prepare_logo(main_fbi, FB_ROTATE_UR)) {
+                       fb_set_cmap(&main_fbi->cmap, main_fbi);
+                       fb_show_logo(main_fbi, FB_ROTATE_UR);
+               }
+#endif
                main_fbi->fbops->fb_pan_display(&main_fbi->var, main_fbi);
+       } else {
+#if !defined(CONFIG_ROCKCHIP_IOMMU)
+               struct fb_info *extend_fbi = rk_fb->fb[rk_fb->num_fb >> 1];
+               int extend_fb_id = get_extend_fb_id(extend_fbi);
+               rk_fb_alloc_buffer(extend_fbi, extend_fb_id);
+#endif
        }
 #endif
-       //main_fbi->fbops->fb_ioctl(main_fbi, RK_FBIOSET_CONFIG_DONE, 0);
-       main_fbi->fbops->fb_set_par(main_fbi);
 
-}
-#endif
        return 0;
 
-
 }
 
 int rk_fb_unregister(struct rk_lcdc_driver *dev_drv)
@@ -2572,10 +3516,10 @@ int rk_fb_unregister(struct rk_lcdc_driver *dev_drv)
        for (i = 0; i < fb_num; i++)
                kfree(dev_drv->win[i]);
 
-       for (i = fb_index_base; i < (fb_index_base+fb_num); i++) {
+       for (i = fb_index_base; i < (fb_index_base + fb_num); i++) {
                fbi = fb_inf->fb[i];
                unregister_framebuffer(fbi);
-               /*rk_release_fb_buffer(fbi);*/
+               /* rk_release_fb_buffer(fbi); */
                framebuffer_release(fbi);
        }
        fb_inf->lcdc_dev_drv[dev_drv->id] = NULL;
@@ -2584,49 +3528,6 @@ int rk_fb_unregister(struct rk_lcdc_driver *dev_drv)
        return 0;
 }
 
-
-
-#if defined(CONFIG_HAS_EARLYSUSPEND)
-struct suspend_info {
-       struct early_suspend early_suspend;
-       struct rk_fb *inf;
-};
-
-static void rkfb_early_suspend(struct early_suspend *h)
-{
-       struct suspend_info *info = container_of(h, struct suspend_info,
-                                               early_suspend);
-       struct rk_fb *inf = info->inf;
-       int i;
-       for (i = 0; i < inf->num_lcdc; i++) {
-               if (!inf->lcdc_dev_drv[i])
-                       continue;
-               inf->lcdc_dev_drv[i]->suspend(inf->lcdc_dev_drv[i]);
-       }
-}
-static void rkfb_early_resume(struct early_suspend *h)
-{
-       struct suspend_info *info = container_of(h, struct suspend_info,
-                                               early_suspend);
-       struct rk_fb *inf = info->inf;
-       int i;
-       for (i = 0; i < inf->num_lcdc; i++) {
-               if (!inf->lcdc_dev_drv[i])
-                       continue;
-               inf->lcdc_dev_drv[i]->resume(inf->lcdc_dev_drv[i]);
-       }
-
-}
-
-
-
-static struct suspend_info suspend_info = {
-       .early_suspend.suspend = rkfb_early_suspend,
-       .early_suspend.resume = rkfb_early_resume,
-       .early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB,
-};
-#endif
-
 static int rk_fb_probe(struct platform_device *pdev)
 {
        struct rk_fb *rk_fb = NULL;
@@ -2641,7 +3542,7 @@ static int rk_fb_probe(struct platform_device *pdev)
        rk_fb = devm_kzalloc(&pdev->dev, sizeof(struct rk_fb), GFP_KERNEL);
        if (!rk_fb) {
                dev_err(&pdev->dev, "kmalloc for rk fb fail!");
-               return  -ENOMEM;
+               return -ENOMEM;
        }
        platform_set_drvdata(pdev, rk_fb);
 
@@ -2652,6 +3553,10 @@ static int rk_fb_probe(struct platform_device *pdev)
                dev_err(&pdev->dev, "no disp-mode node found!");
                return -ENODEV;
        }
+
+       if (!of_property_read_u32(np, "rockchip,uboot-logo-on", &uboot_logo_on))
+               printk("uboot-logo-on:%d\n", uboot_logo_on);
+
        dev_set_name(&pdev->dev, "rockchip-fb");
 #if defined(CONFIG_ION_ROCKCHIP)
        rk_fb->ion_client = rockchip_ion_client_create("rk_fb");
@@ -2663,10 +3568,6 @@ static int rk_fb_probe(struct platform_device *pdev)
        }
 #endif
 
-#if defined(CONFIG_HAS_EARLYSUSPEND)
-       suspend_info.inf = rk_fb;
-       register_early_suspend(&suspend_info.early_suspend);
-#endif
        fb_pdev = pdev;
        dev_info(&pdev->dev, "rockchip framebuffer driver probe\n");
        return 0;
@@ -2690,26 +3591,22 @@ static void rk_fb_shutdown(struct platform_device *pdev)
 
        }
 
-#if    defined(CONFIG_HAS_EARLYSUSPEND)
-       unregister_early_suspend(&suspend_info.early_suspend);
-#endif
 }
 
-
 static const struct of_device_id rkfb_dt_ids[] = {
-       { .compatible = "rockchip,rk-fb", },
+       {.compatible = "rockchip,rk-fb",},
        {}
 };
 
 static struct platform_driver rk_fb_driver = {
-       .probe          = rk_fb_probe,
-       .remove         = rk_fb_remove,
-       .driver         = {
-               .name   = "rk-fb",
-               .owner  = THIS_MODULE,
-               .of_match_table = of_match_ptr(rkfb_dt_ids),
-       },
-       .shutdown   = rk_fb_shutdown,
+       .probe = rk_fb_probe,
+       .remove = rk_fb_remove,
+       .driver = {
+                  .name = "rk-fb",
+                  .owner = THIS_MODULE,
+                  .of_match_table = of_match_ptr(rkfb_dt_ids),
+                  },
+       .shutdown = rk_fb_shutdown,
 };
 
 static int __init rk_fb_init(void)
@@ -2722,5 +3619,5 @@ static void __exit rk_fb_exit(void)
        platform_driver_unregister(&rk_fb_driver);
 }
 
-subsys_initcall_sync(rk_fb_init);
+fs_initcall(rk_fb_init);
 module_exit(rk_fb_exit);