rk30fb :fix a bug in rk30_lcdc.c
[firefly-linux-kernel-4.4.55.git] / drivers / video / rockchip / rk_fb.c
index b79bee5cf325f13cd7d79e54684916efb75d71fc..480115c1976140917574619bc3cdfff591b8088e 100644 (file)
@@ -2,7 +2,8 @@
  * drivers/video/rockchip/rk_fb.c
  *
  * Copyright (C) 2012 ROCKCHIP, Inc.
- *
+ *Author:yzq<yzq@rock-chips.com>
+       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/device.h>
 #include <linux/fb.h>
 #include <linux/init.h>
-#include <linux/dma-mapping.h>
-#include <linux/interrupt.h>
 #include <linux/platform_device.h>
-#include <linux/clk.h>
-#include <linux/backlight.h>
-#include <linux/timer.h>
-#include <linux/time.h>
-#include <linux/wait.h>
 #include <linux/earlysuspend.h>
-#include <linux/cpufreq.h>
-#include <linux/wakelock.h>
-
-#include <asm/io.h>
 #include <asm/div64.h>
 #include <asm/uaccess.h>
-#include <asm/cacheflush.h>
-
-#include <mach/iomux.h>
-#include <mach/gpio.h>
-#include <mach/board.h>
-#include <mach/pmu.h>
+#include<linux/rk_fb.h>
 
-#include "../display/screen/screen.h"
-#include "rk_fb.h"
 
 #if 0
        #define fbprintk(msg...)        printk(msg);
        #define fbprintk(msg...)
 #endif
 
-#if 0
-#define CHK_SUSPEND(inf)       \
-       if(inf->in_suspend)     {       \
-               fbprintk(">>>>>> fb is in suspend! return! \n");        \
+#if 1
+#define CHK_SUSPEND(drv)       \
+       if(atomic_dec_and_test(&drv->in_suspend))       {       \
+               printk(">>>>>> fb is in suspend! return! \n");  \
                return -EPERM;  \
        }
 #else
@@ -85,45 +68,157 @@ defautl:we alloc three buffer,one for fb0 and fb2 display ui,one for ipp rotate
         pass the phy addr to fix.smem_start by ioctl
 ****************************************************************************/
 
-static int rk_fb_ioctl(struct fb_info *info, unsigned int cmd,
-                       unsigned long arg)
+int get_fb_layer_id(struct fb_fix_screeninfo *fix)
 {
-    struct rk_fb_inf *inf = dev_get_drvdata(info->device);
-    u32 yuv_phy[2];
-    fbprintk(">>>>>> %s : cmd:0x%x \n",__FUNCTION__,cmd);
+       int layer_id;
+       if(!strcmp(fix->id,"fb1")||!strcmp(fix->id,"fb3"))
+       {
+               layer_id = 0;
+       }
+       else if(!strcmp(fix->id,"fb0")||!strcmp(fix->id,"fb2"))
+       {
+               layer_id = 1;
+       }
+       else
+       {
+               printk(KERN_ERR "unsupported %s",fix->id);
+               layer_id = -ENODEV;
+       }
 
-       CHK_SUSPEND(inf);
+       return layer_id;
+}
 
-    switch(cmd)
-    {
-        case FB0_IOCTL_STOP_TIMER_FLUSH:    //stop timer flush mcu panel after android is runing
-            break;
-        case FBIOPUT_16OR32:
-               break;
-        case FBIOGET_16OR32:
-            break;
-        case FBIOGET_IDLEFBUff_16OR32:
-        case FBIOSET_COMPOSE_LAYER_COUNTS:
-            break;
-        case FBIOGET_COMPOSE_LAYER_COUNTS:
-           case FBIOPUT_FBPHYADD:
-            return info->fix.smem_start;
-        case FB1_IOCTL_SET_YUV_ADDR:
-            if (copy_from_user(yuv_phy, arg, 8))
-                           return -EFAULT;
-            info->fix.smem_start = yuv_phy[0];
-            info->fix.mmio_start = yuv_phy[1];
-            break;
-        case FBIOGET_OVERLAY_STATE:
-            return inf->video_mode;
-        case FBIOGET_SCREEN_STATE:
-        case FBIOPUT_SET_CURSOR_EN:
-        case FBIOPUT_SET_CURSOR_POS:
-        case FBIOPUT_SET_CURSOR_IMG:
-        case FBIOPUT_SET_CURSOR_CMAP:
-        case FBIOPUT_GET_CURSOR_RESOLUTION:
-        case FBIOPUT_GET_CURSOR_EN:
-        default:
+/**********************************************************************
+this is for hdmi
+name: lcdc device name ,lcdc0 , lcdc1
+***********************************************************************/
+struct rk_lcdc_device_driver * rk_get_lcdc_drv(char *name)
+{
+       struct rk_fb_inf *inf =  platform_get_drvdata(g_fb_pdev);
+       int i = 0;
+       for( i = 0; i < inf->num_lcdc; i++)
+       {
+               if(!strcmp(inf->lcdc_dev_drv[i]->name,name))
+                       break;
+       }
+       return inf->lcdc_dev_drv[i];
+       
+}
+static int rk_fb_open(struct fb_info *info,int user)
+{
+    struct rk_lcdc_device_driver * dev_drv = (struct rk_lcdc_device_driver * )info->par;
+    int layer_id;
+    CHK_SUSPEND(dev_drv);
+    layer_id = get_fb_layer_id(&info->fix);
+    dev_drv->open(dev_drv,layer_id,1);
+    
+    return 0;
+    
+}
+
+static int rk_fb_close(struct fb_info *info,int user)
+{
+       struct rk_lcdc_device_driver * dev_drv = (struct rk_lcdc_device_driver * )info->par;
+       int layer_id;
+       CHK_SUSPEND(dev_drv);
+       layer_id = get_fb_layer_id(&info->fix);
+       dev_drv->open(dev_drv,layer_id,0);
+       
+       return 0;
+}
+
+static int rk_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+       struct fb_fix_screeninfo *fix = &info->fix;
+       struct rk_lcdc_device_driver * dev_drv = (struct rk_lcdc_device_driver * )info->par;
+       struct layer_par *par = NULL;
+       int layer_id = 0;
+       u32 xoffset = var->xoffset;             // offset from virtual to visible 
+       u32 yoffset = var->yoffset;                             
+       u32 xvir = var->xres_virtual;
+       u8 data_format = var->nonstd&0xff;
+       layer_id = get_fb_layer_id(fix);
+       CHK_SUSPEND(dev_drv);
+       if(layer_id < 0)
+       {
+               return  -ENODEV;
+       }
+       else
+       {
+                par = dev_drv->layer_par[layer_id];
+       }
+       switch (par->format)
+       {
+               case ARGB888:
+                       par->y_offset = (yoffset*xvir + xoffset)*4;
+                       break;
+               case  RGB888:
+                       par->y_offset = (yoffset*xvir + xoffset)*3;
+                       break;
+               case RGB565:
+                       par->y_offset = (yoffset*xvir + xoffset)*2;
+                       break;
+               case  YUV422:
+                       par->y_offset = yoffset*xvir + xoffset;
+                       par->c_offset = par->y_offset;
+                       break;
+               case  YUV420:
+                       par->y_offset = yoffset*xvir + xoffset;
+                       par->c_offset = (yoffset>>1)*xvir + xoffset;
+                       break;
+               case  YUV444 : // yuv444
+                       par->y_offset = yoffset*xvir + xoffset;
+                       par->c_offset = yoffset*2*xvir +(xoffset<<1);
+                       break;
+               default:
+                       printk("un supported format:0x%x\n",data_format);
+                       return -EINVAL;
+       }
+       
+       dev_drv->pan_display(dev_drv,layer_id);
+       
+       return 0;
+}
+static int rk_fb_ioctl(struct fb_info *info, unsigned int cmd,unsigned long arg)
+{
+       struct rk_fb_inf *inf = dev_get_drvdata(info->device);
+       struct fb_fix_screeninfo *fix = &info->fix;
+       struct rk_lcdc_device_driver *dev_drv = (struct rk_lcdc_device_driver * )info->par;
+       u32 yuv_phy[2];
+       void __user *argp = (void __user *)arg;
+       fbprintk(">>>>>> %s : cmd:0x%x \n",__FUNCTION__,cmd);
+       
+       CHK_SUSPEND(dev_drv);
+       switch(cmd)
+       {
+               case FBIOPUT_FBPHYADD:
+                       return info->fix.smem_start;
+               case FB1_IOCTL_SET_YUV_ADDR:   //when in video mode, buff alloc by android
+                       if((!strcmp(fix->id,"fb1"))||(!strcmp(fix->id,"fb3")))
+                       {
+                               if (copy_from_user(yuv_phy, argp, 8))
+                                       return -EFAULT;
+                               info->fix.smem_start = yuv_phy[0];  //four y
+                               info->fix.mmio_start = yuv_phy[1];  //four uv
+                       }
+                       break;
+               case FBIOGET_OVERLAY_STATE:
+                       return inf->video_mode;
+               case FBIOGET_SCREEN_STATE:
+               case FBIOPUT_SET_CURSOR_EN:
+               case FBIOPUT_SET_CURSOR_POS:
+               case FBIOPUT_SET_CURSOR_IMG:
+               case FBIOPUT_SET_CURSOR_CMAP:
+               case FBIOPUT_GET_CURSOR_RESOLUTION:
+               case FBIOPUT_GET_CURSOR_EN:
+               case FB0_IOCTL_STOP_TIMER_FLUSH:    //stop timer flush mcu panel after android is runing
+               case FBIOPUT_16OR32:
+               case FBIOGET_16OR32:
+               case FBIOGET_IDLEFBUff_16OR32:
+               case FBIOSET_COMPOSE_LAYER_COUNTS:
+               case FBIOGET_COMPOSE_LAYER_COUNTS:
+               default:
+                       dev_drv->ioctl(dev_drv,cmd,arg,0);
             break;
     }
     return 0;
@@ -131,34 +226,25 @@ static int rk_fb_ioctl(struct fb_info *info, unsigned int cmd,
 
 static int rk_fb_blank(int blank_mode, struct fb_info *info)
 {
-    struct rk_fb_inf *inf = dev_get_drvdata(info->device);
-    struct rk_lcdc_device_driver *dev_drv = NULL;
-    struct fb_fix_screeninfo *fix = &info->fix;
-    int layer_id;
-    if(!strcmp(fix->id,"fb1")){
-        dev_drv = inf->rk_lcdc_device[0];
-        layer_id = 0;
-    }else if(!strcmp(fix->id,"fb0")){
-        dev_drv = inf->rk_lcdc_device[0];
-        layer_id = 1;
-    }else if(!strcmp(fix->id,"fb3")){
-        dev_drv = inf->rk_lcdc_device[1];
-        layer_id = 0;
-    }else if(!strcmp(fix->id,"fb2")){
-        dev_drv = inf->rk_lcdc_device[1];
-        layer_id = 1;
-    }else{
-        dev_drv = inf->rk_lcdc_device[0];
-        layer_id = 0;
-    }
-    dev_drv->blank(dev_drv,layer_id,blank_mode);
+       struct rk_lcdc_device_driver *dev_drv = (struct rk_lcdc_device_driver * )info->par;
+       struct fb_fix_screeninfo *fix = &info->fix;
+       int layer_id;
+       CHK_SUSPEND(dev_drv);
+       layer_id = get_fb_layer_id(fix);
+       if(layer_id < 0)
+       {
+               return  -ENODEV;
+       }
+       
+       dev_drv->blank(dev_drv,layer_id,blank_mode);
 
-    return 0;
+       return 0;
 }
 
 static int rk_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
 {
-       CHK_SUSPEND(inf);
+       struct rk_lcdc_device_driver *dev_drv = (struct rk_lcdc_device_driver * )info->par;
+       CHK_SUSPEND(dev_drv);
  
         if( 0==var->xres_virtual || 0==var->yres_virtual ||
                 0==var->xres || 0==var->yres || var->xres<16 ||
@@ -237,52 +323,35 @@ static int rk_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
 
 static int rk_fb_set_par(struct fb_info *info)
 {
-    struct rk_fb_inf *inf = dev_get_drvdata(info->device);
     struct fb_var_screeninfo *var = &info->var;
     struct fb_fix_screeninfo *fix = &info->fix;
-    struct rk_lcdc_device_driver * dev_drv = NULL;
+    struct rk_lcdc_device_driver * dev_drv = (struct rk_lcdc_device_driver * )info->par;
     struct layer_par *par = NULL;
-    rk_screen *screen = NULL;
+    rk_screen *screen =dev_drv->screen;
     int layer_id = 0;  
-    u32 smem_len=0,map_size = 0;
     u32 cblen = 0,crlen = 0;
-    u32 xvir = var->xres_virtual;              /* virtual resolution           */
-    u32 yvir = var->yres_virtual;
-    u32 xoffset = var->xoffset;                        /* offset from virtual to visible */
-    u32 yoffset = var->yoffset;                        /* resolution                   */
-
-    
-    u16 xpos = (var->nonstd>>8) & 0xfff;      //visiable pos in panel
+    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;                        //resolution                    
+    u16 xpos = (var->nonstd>>8) & 0xfff; //visiable pos in panel
     u16 ypos = (var->nonstd>>20) & 0xfff;
-    u16 xsize =0,ysize = 0;
-    u8 data_format = var->nonstd&0x0f;
-
-    if(!strcmp(fix->id,"fb1")){
-        dev_drv = inf->rk_lcdc_device[0];
-        par = &dev_drv->layer_par[0];
-        layer_id = 0;
-    }else if(!strcmp(fix->id,"fb0")){
-        dev_drv = inf->rk_lcdc_device[0];
-        par = &dev_drv->layer_par[1];
-        layer_id = 1;
-    }else if(!strcmp(fix->id,"fb3")){
-        dev_drv = inf->rk_lcdc_device[1];
-        par = &dev_drv->layer_par[0];
-        layer_id = 0;
-    }else if(!strcmp(fix->id,"fb2")){
-        dev_drv = inf->rk_lcdc_device[1];
-        par = &dev_drv->layer_par[1];
-        layer_id = 1;
-    }else{
-        dev_drv = inf->rk_lcdc_device[0];
-        par = &dev_drv->layer_par[1];
-        layer_id = 0;
+    u32 xvir = var->xres_virtual;
+    u32 yvir = var->yres_virtual;
+    u8 data_format = var->nonstd&0xff;
+    var->pixclock = dev_drv->pixclock;
+    CHK_SUSPEND(dev_drv);
+    layer_id = get_fb_layer_id(fix);
+    if(layer_id < 0)
+    {
+       return  -ENODEV;
+    }
+    else
+    {
+       par = dev_drv->layer_par[layer_id];
     }
-    screen = &dev_drv->screen;
-
     if((!strcmp(fix->id,"fb0"))||(!strcmp(fix->id,"fb2")))  //four ui
     {
-        xsize = screen->x_res;
+       xsize = screen->x_res;
         ysize = screen->y_res;
     }
     else if((!strcmp(fix->id,"fb1"))||(!strcmp(fix->id,"fb3")))
@@ -290,70 +359,80 @@ static int rk_fb_set_par(struct fb_info *info)
         xsize = (var->grayscale>>8) & 0xfff;  //visiable size in panel ,for vide0
         ysize = (var->grayscale>>20) & 0xfff;
     }
-       CHK_SUSPEND(inf);
+    
        /* calculate y_offset,c_offset,line_length,cblen and crlen  */
+#if 1
     switch (data_format)
     {
-        case 0:                    // rgb
-            switch(var->bits_per_pixel)
-            {
-                case 16:    // rgb565
-                    par->format =RGB565;
-                    fix->line_length = 2 * xvir;
-                    par->y_offset = (yoffset*xvir + xoffset)*2;
-                    break;
-                case 32:   // rgb888
-                    if(var->transp.length)      //we need ditinguish ARGB888 and RGB888
-                        par->format = ARGB888;  //in some register,they have different configration
-                    else
-                        par->format = RGB888;
-                    fix->line_length = 4 * xvir;
-                    par->y_offset = (yoffset*xvir + xoffset)*4;
-                    break;
-                default:
-                    return -EINVAL;
-            }
-            break;
-        case 1: // yuv422
-            par->format = YUV422;
-            fix->line_length = xvir;
-            cblen = crlen = (xvir*yvir)>>1;
-            par->y_offset = yoffset*xvir + xoffset;
-            par->c_offset = par->y_offset;
-            break;
-        case 2: // yuv4200
-            par->format = YUV420;
-            fix->line_length = xvir;
-            cblen = crlen = (xvir*yvir)>>2;
-            par->y_offset = yoffset*xvir + xoffset;
-            par->c_offset = (yoffset>>1)*xvir + xoffset;
-            break;
-        case 4: // none
-        case 5: // yuv444
-            par->format = 5;
-            fix->line_length = xvir<<2;
-            par->y_offset = yoffset*xvir + xoffset;
-            par->c_offset = yoffset*2*xvir +(xoffset<<1);
-            cblen = crlen = (xvir*yvir);
-            break;
-        default:
+       case HAL_PIXEL_FORMAT_RGBA_8888 :      // rgb
+       case HAL_PIXEL_FORMAT_RGBX_8888: 
+               par->format = ARGB888;
+               fix->line_length = 4 * xvir;
+               par->y_offset = (yoffset*xvir + xoffset)*4;
+               break;
+       case HAL_PIXEL_FORMAT_RGB_888 :
+               par->format = RGB888;
+               fix->line_length = 3 * xvir;
+               par->y_offset = (yoffset*xvir + xoffset)*3;
+               break;
+       case HAL_PIXEL_FORMAT_RGB_565:  //RGB565
+               par->format = RGB565;
+               fix->line_length = 2 * xvir;
+               par->y_offset = (yoffset*xvir + xoffset)*2;
+               break;
+       case HAL_PIXEL_FORMAT_YCbCr_422_SP : // yuv422
+               par->format = YUV422;
+               fix->line_length = xvir;
+               cblen = crlen = (xvir*yvir)>>1;
+               par->y_offset = yoffset*xvir + xoffset;
+               par->c_offset = par->y_offset;
+               break;
+       case HAL_PIXEL_FORMAT_YCrCb_NV12   : // YUV420---uvuvuv
+               par->format = YUV420;
+               fix->line_length = xvir;
+               cblen = crlen = (xvir*yvir)>>2;
+               par->y_offset = yoffset*xvir + xoffset;
+               par->c_offset = (yoffset>>1)*xvir + xoffset;
+               break;
+       case HAL_PIXEL_FORMAT_YCrCb_444 : // yuv444
+               par->format = 5;
+               fix->line_length = xvir<<2;
+               par->y_offset = yoffset*xvir + xoffset;
+               par->c_offset = yoffset*2*xvir +(xoffset<<1);
+               cblen = crlen = (xvir*yvir);
+               break;
+       default:
+               printk("un supported format:0x%x\n",data_format);
             return -EINVAL;
     }
+#else
+       switch(var->bits_per_pixel)
+       {
+               case 32:
+                       par->format = ARGB888;
+                       fix->line_length = 4 * xvir;
+                       par->y_offset = (yoffset*xvir + xoffset)*4;
+                       break;
+               case 16:
+                       par->format = RGB565;
+                       fix->line_length = 2 * xvir;
+                       par->y_offset = (yoffset*xvir + xoffset)*2;
+                       break;
+                       
+       }
+#endif
 
-    smem_len = fix->line_length * yvir + cblen + crlen;
-   // map_size = PAGE_ALIGN(smem_len);
-
-    fix->smem_len = smem_len;
     par->xpos = xpos;
     par->ypos = ypos;
     par->xsize = xsize;
     par->ysize = ysize;
     
     par->smem_start =fix->smem_start;
-    par->xact = var->xres;
+    par->cbr_start = fix->mmio_start;
+    par->xact = var->xres;              //winx active window height,is a part of vir
     par->yact = var->yres;
-    par->xres_virtual = xvir;          // virtuail resolution  
-    par->yres_virtual = yvir;
+    par->xvir =  var->xres_virtual;            // virtual resolution    stride --->LCDC_WINx_VIR
+    par->yvir =  var->yres_virtual;
     dev_drv->set_par(dev_drv,layer_id);
     
        return 0;
@@ -372,7 +451,6 @@ static int fb_setcolreg(unsigned regno,
                               unsigned transp, struct fb_info *info)
 {
        unsigned int val;
-//     fbprintk(">>>>>> %s : %s \n", __FILE__, __FUNCTION__);
 
        switch (info->fix.visual) {
        case FB_VISUAL_TRUECOLOR:
@@ -394,10 +472,13 @@ static int fb_setcolreg(unsigned regno,
 
 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_setcolreg   = fb_setcolreg,
     .fb_fillrect    = cfb_fillrect,
     .fb_copyarea    = cfb_copyarea,
@@ -411,8 +492,8 @@ static struct fb_var_screeninfo def_var = {
     .green  = {5,6,0},
     .blue   = {0,5,0},
     .transp = {0,0,0}, 
-    .nonstd      = 0, //win1 format & ypos & xpos (ypos<<20 + xpos<<8 + format)
-    .grayscale   = 0,  //win1 transprent mode & value(mode<<8 + value)
+    .nonstd      = HAL_PIXEL_FORMAT_RGB_565,   //(ypos<<20+xpos<<8+format) format
+    .grayscale   = 0,  //(ysize<<20+xsize<<8)
     .activate    = FB_ACTIVATE_NOW,
     .accel_flags = 0,
     .vmode       = FB_VMODE_NONINTERLACED,
@@ -441,86 +522,178 @@ struct fb_info * rk_get_fb(int fb_id)
     struct fb_info *fb = inf->fb[fb_id];
     return fb;
 }
-EXPORT_SYMBOL(get_fb);
+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);
 }
-EXPORT_SYMBOL(direct_fb_show);
+EXPORT_SYMBOL(rk_direct_fb_show);
 
-static int request_fb_buffer(struct fb_info *fbi,int fb_id)
+static int rk_request_fb_buffer(struct fb_info *fbi,int fb_id)
 {
-    struct resource *res;
-    int ret = 0;
-    switch(fb_id)
-    {
-        case 0:
-            res = platform_get_resource_byname(g_fb_pdev, IORESOURCE_MEM, "fb0 buf");
-            if (res == NULL)
-            {
-                dev_err(&g_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;
-            fbi->screen_base = ioremap(res->start, fbi->fix.smem_len);
-            memset(fbi->screen_base, 0, fbi->fix.smem_len);
-        #ifdef CONFIG_FB_WORK_IPP
-        /* alloc ipp buf for rotate */
-            res = platform_get_resource_byname(g_fb_pdev, IORESOURCE_MEM, "ipp buf");
-            if (res == NULL)
-            {
-                dev_err(&g_fb_pdev->dev, "failed to get win1 ipp memory \n");
-                ret = -ENOENT;
-            }
-            fbi->fix.mmio_start = res->start;
-            fbi->fix.mmio_len = res->end - res->start + 1;
-            break;
-        #endif
-        case 2:
-            res = platform_get_resource_byname(g_fb_pdev, IORESOURCE_MEM, "fb2 buf");
-            if (res == NULL)
-            {
-                dev_err(&g_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;
-            fbi->screen_base = ioremap(res->start, fbi->fix.smem_len);
-            memset(fbi->screen_base, 0, fbi->fix.smem_len);
-            break;
-        default:
-            ret = -EINVAL;
-            break;             
+       struct resource *res;
+       struct resource *mem;
+       int ret = 0;
+       switch(fb_id)
+       {
+               case 0:
+                       res = platform_get_resource_byname(g_fb_pdev, IORESOURCE_MEM, "fb0 buf");
+                       if (res == NULL)
+                       {
+                               dev_err(&g_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), g_fb_pdev->name);
+                       fbi->screen_base = ioremap(res->start, fbi->fix.smem_len);
+                       memset(fbi->screen_base, 0, fbi->fix.smem_len);
+                       printk("fb%d:phy:%lx>>vir:%p>>len:0x%x\n",fb_id,
+                               fbi->fix.smem_start,fbi->screen_base,fbi->fix.smem_len);
+               #ifdef CONFIG_FB_WORK_IPP // alloc ipp buf for rotate
+                       res = platform_get_resource_byname(g_fb_pdev, IORESOURCE_MEM, "ipp buf");
+                       if (res == NULL)
+                       {
+                               dev_err(&g_fb_pdev->dev, "failed to get win1 ipp memory \n");
+                               ret = -ENOENT;
+                       }
+                       fbi->fix.mmio_start = res->start;
+                       fbi->fix.mmio_len = res->end - res->start + 1;
+               #endif
+                       break;
+               case 2:
+                       res = platform_get_resource_byname(g_fb_pdev, IORESOURCE_MEM, "fb2 buf");
+                       if (res == NULL)
+                       {
+                       dev_err(&g_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), g_fb_pdev->name);
+                       fbi->screen_base = ioremap(res->start, fbi->fix.smem_len);
+                       memset(fbi->screen_base, 0, fbi->fix.smem_len);
+                       printk("fb%d:phy:%lx>>vir:%p>>len:0x%x\n",fb_id,
+                               fbi->fix.smem_start,fbi->screen_base,fbi->fix.smem_len);
+                       break;
+               default:
+                       ret = -EINVAL;
+                       break;          
        }
     return ret;
 }
-int rk_fb_register(struct rk_lcdc_device_driver *dev_drv)
+
+static int rk_release_fb_buffer(struct fb_info *fbi)
+{
+       if(!fbi)
+       {
+               printk("no need release null fb buffer!\n");
+               return -EINVAL;
+       }
+       if(!strcmp(fbi->fix.id,"fb1")||!strcmp(fbi->fix.id,"fb3"))  //buffer for fb1 and fb3 are alloc by android
+               return 0;
+       iounmap(fbi->screen_base);
+       release_mem_region(fbi->fix.smem_start,fbi->fix.smem_len);
+       return 0;
+       
+}
+static int init_layer_par(struct rk_lcdc_device_driver *dev_drv)
+{
+       int i;
+       struct layer_par * def_par = NULL;
+       int num_par = dev_drv->num_layer;
+       for(i = 0; i < num_par; i++)
+       {
+               struct layer_par *par = NULL;
+               par =  kzalloc(sizeof(struct layer_par), GFP_KERNEL);
+               if(!par)
+               {
+                       printk(KERN_ERR "kzmalloc for layer_par fail!");
+                       return   -ENOMEM;
+                       
+               }
+              def_par = &dev_drv->def_layer_par[i];
+               strcpy(par->name,def_par->name);
+               par->id = def_par->id;
+               par->support_3d = def_par->support_3d;
+               dev_drv->layer_par[i] = par;
+       }
+               
+       return 0;
+       
+       
+}
+
+
+static int init_lcdc_device_driver(struct rk_lcdc_device_driver *dev_drv,
+       struct rk_lcdc_device_driver *def_drv,int id)
+{
+       if(!def_drv)
+       {
+               printk(KERN_ERR "default lcdc device driver is null!\n");
+               return -EINVAL;
+       }
+       if(!dev_drv)
+       {
+               printk(KERN_ERR "lcdc device driver is null!\n");
+               return -EINVAL; 
+       }
+       sprintf(dev_drv->name, "lcdc%d",id);
+       dev_drv->open           = def_drv->open;
+       dev_drv->init_lcdc      = def_drv->init_lcdc;
+       dev_drv->ioctl          = def_drv->ioctl;
+       dev_drv->blank          = def_drv->blank;
+       dev_drv->set_par        = def_drv->set_par;
+       dev_drv->pan_display    = def_drv->pan_display;
+       dev_drv->suspend        = def_drv->suspend;
+       dev_drv->resume         = def_drv->resume;
+       dev_drv->load_screen    = def_drv->load_screen;
+       dev_drv->def_layer_par  = def_drv->def_layer_par;
+       dev_drv->num_layer      = def_drv->num_layer;
+       init_layer_par(dev_drv);
+       init_completion(&dev_drv->frame_done);
+       spin_lock_init(&dev_drv->cpl_lock);
+       dev_drv->first_frame = 1;
+       
+       return 0;
+}
+
+int rk_fb_register(struct rk_lcdc_device_driver *dev_drv,
+       struct rk_lcdc_device_driver *def_drv,int id)
 {
        struct rk_fb_inf *fb_inf = platform_get_drvdata(g_fb_pdev);
        struct fb_info *fbi;
        int i=0,ret = 0;
        int lcdc_id = 0;
-       if(NULL==dev_drv){
-        printk("null lcdc device driver?");
-        return -ENOENT;
-    }
-    for(i=0;i<RK30_MAX_LCDC_SUPPORT;i++){
-        if(NULL==fb_inf->rk_lcdc_device[i]){
-            fb_inf->rk_lcdc_device[i] = dev_drv;
-            fb_inf->rk_lcdc_device[i]->id = i;
-            fb_inf->num_lcdc++;
-            break;
-        }
-    }
-    if(i==RK30_MAX_LCDC_SUPPORT){
-        printk("rk_fb_register lcdc out of support %d",i);
-        return -ENOENT;
-    }
-    lcdc_id = i;
-       
+       if(NULL == dev_drv)
+       {
+               printk("null lcdc device driver?");
+               return -ENOENT;
+       }
+       for(i=0;i<RK30_MAX_LCDC_SUPPORT;i++)
+       {
+               if(NULL==fb_inf->lcdc_dev_drv[i])
+               {
+                       fb_inf->lcdc_dev_drv[i] = dev_drv;
+                       fb_inf->lcdc_dev_drv[i]->id = i;
+                       fb_inf->num_lcdc++;
+                       break;
+               }
+       }
+       if(i==RK30_MAX_LCDC_SUPPORT)
+       {
+               printk("rk_fb_register lcdc out of support %d",i);
+               return -ENOENT;
+       }
+       lcdc_id = i;
+       init_lcdc_device_driver(dev_drv, def_drv,id);
+       set_lcd_info(dev_drv->screen, fb_inf->mach_info->lcd_info);
+       dev_drv->init_lcdc(dev_drv);
+       dev_drv->load_screen(dev_drv,1);
        /************fb set,one layer one fb ***********/
+       dev_drv->fb_index_base = fb_inf->num_fb;
     for(i=0;i<dev_drv->num_layer;i++)
     {
         fbi= framebuffer_alloc(0, &g_fb_pdev->dev);
@@ -530,33 +703,35 @@ int rk_fb_register(struct rk_lcdc_device_driver *dev_drv)
             fbi = NULL;
             ret = -ENOMEM;
         }
+       fbi->par = dev_drv;
         fbi->var = def_var;
         fbi->fix = def_fix;
         sprintf(fbi->fix.id,"fb%d",fb_inf->num_fb);
-        fbi->var.xres = fb_inf->rk_lcdc_device[lcdc_id]->screen.x_res;
-        fbi->var.yres = fb_inf->rk_lcdc_device[lcdc_id]->screen.y_res;
+        fbi->var.xres = fb_inf->lcdc_dev_drv[lcdc_id]->screen->x_res;
+        fbi->var.yres = fb_inf->lcdc_dev_drv[lcdc_id]->screen->y_res;
         fbi->var.bits_per_pixel = 16;
-        fbi->var.xres_virtual = fb_inf->rk_lcdc_device[lcdc_id]->screen.x_res;
-        fbi->var.yres_virtual = fb_inf->rk_lcdc_device[lcdc_id]->screen.y_res;
-        fbi->var.width = fb_inf->rk_lcdc_device[lcdc_id]->screen.width;
-        fbi->var.height = fb_inf->rk_lcdc_device[lcdc_id]->screen.height;
-        fbi->var.pixclock =fb_inf->rk_lcdc_device[lcdc_id]->pixclock;
-        fbi->var.left_margin = fb_inf->rk_lcdc_device[lcdc_id]->screen.left_margin;
-        fbi->var.right_margin = fb_inf->rk_lcdc_device[lcdc_id]->screen.right_margin;
-        fbi->var.upper_margin = fb_inf->rk_lcdc_device[lcdc_id]->screen.upper_margin;
-        fbi->var.lower_margin = fb_inf->rk_lcdc_device[lcdc_id]->screen.lower_margin;
-        fbi->var.vsync_len = fb_inf->rk_lcdc_device[lcdc_id]->screen.vsync_len;
-        fbi->var.hsync_len = fb_inf->rk_lcdc_device[lcdc_id]->screen.hsync_len;
+        fbi->var.xres_virtual = fb_inf->lcdc_dev_drv[lcdc_id]->screen->x_res;
+        fbi->var.yres_virtual = fb_inf->lcdc_dev_drv[lcdc_id]->screen->y_res;
+        fbi->var.width = fb_inf->lcdc_dev_drv[lcdc_id]->screen->width;
+        fbi->var.height = fb_inf->lcdc_dev_drv[lcdc_id]->screen->height;
+        fbi->var.pixclock =fb_inf->lcdc_dev_drv[lcdc_id]->pixclock;
+        fbi->var.left_margin = fb_inf->lcdc_dev_drv[lcdc_id]->screen->left_margin;
+        fbi->var.right_margin = fb_inf->lcdc_dev_drv[lcdc_id]->screen->right_margin;
+        fbi->var.upper_margin = fb_inf->lcdc_dev_drv[lcdc_id]->screen->upper_margin;
+        fbi->var.lower_margin = fb_inf->lcdc_dev_drv[lcdc_id]->screen->lower_margin;
+        fbi->var.vsync_len = fb_inf->lcdc_dev_drv[lcdc_id]->screen->vsync_len;
+        fbi->var.hsync_len = fb_inf->lcdc_dev_drv[lcdc_id]->screen->hsync_len;
         fbi->fbops                      = &fb_ops;
         fbi->flags                      = FBINFO_FLAG_DEFAULT;
-        fbi->pseudo_palette  = fb_inf->rk_lcdc_device[lcdc_id]->layer_par[i].pseudo_pal;
-        request_fb_buffer(fbi,fb_inf->num_fb);
+        fbi->pseudo_palette  = fb_inf->lcdc_dev_drv[lcdc_id]->layer_par[i]->pseudo_pal;
+        rk_request_fb_buffer(fbi,fb_inf->num_fb);
         ret = register_framebuffer(fbi);
         if(ret<0)
         {
             printk("%s>>fb%d register_framebuffer fail!\n",__func__,fb_inf->num_fb);
             ret = -EINVAL;
         }
+       rkfb_create_sysfs(fbi);
         fb_inf->fb[fb_inf->num_fb] = fbi;
         printk("%s>>>>>%s\n",__func__,fb_inf->fb[fb_inf->num_fb]->fix.id);
         fb_inf->num_fb++;      
@@ -567,64 +742,128 @@ int rk_fb_register(struct rk_lcdc_device_driver *dev_drv)
         /* Start display and show logo on boot */
         fb_set_cmap(&fb_inf->fb[fb_inf->num_fb-2]->cmap, fb_inf->fb[fb_inf->num_fb-2]);
         fb_show_logo(fb_inf->fb[fb_inf->num_fb-2], FB_ROTATE_UR);
-        fb_inf->fb[fb_inf->num_fb-2]->fbops->fb_blank(FB_BLANK_UNBLANK, fb_inf->fb[fb_inf->num_fb-2]);
+       fb_inf->fb[fb_inf->num_fb-2]->fbops->fb_pan_display(&(fb_inf->fb[fb_inf->num_fb-2]->var), fb_inf->fb[fb_inf->num_fb-2]);
     }
 #endif
        return 0;
        
        
 }
-int rk_fb_unregister(struct rk_lcdc_device_driver *fb_device_driver)
+int rk_fb_unregister(struct rk_lcdc_device_driver *dev_drv)
 {
 
        struct rk_fb_inf *fb_inf = platform_get_drvdata(g_fb_pdev);
+       struct fb_info *fbi;
+       int fb_index_base = dev_drv->fb_index_base;
+       int fb_num = dev_drv->num_layer;
        int i=0;
-       if(NULL==fb_device_driver){
-               printk("rk_fb_register lcdc register fail");
+       if(NULL == dev_drv)
+       {
+               printk(" no need to unregister null lcdc device driver!\n");
                return -ENOENT;
-               }
-       for(i=0;i<RK30_MAX_LCDC_SUPPORT;i++){
-               if(fb_inf->rk_lcdc_device[i]->id == i ){
-               fb_inf->rk_lcdc_device[i] = NULL;
-               fb_inf->num_lcdc--;
-               break;
-               }
        }
-       if(i==RK30_MAX_LCDC_SUPPORT){
-               printk("rk_fb_unregister lcdc out of support %d",i);
-               return -ENOENT;
+
+       for(i = 0; i < fb_num; i++)
+       {
+               kfree(dev_drv->layer_par[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);
+               framebuffer_release(fbi);       
+       }
+       fb_inf->lcdc_dev_drv[dev_drv->id]= NULL;
 
        return 0;
 }
 
+
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+struct suspend_info {
+       struct early_suspend early_suspend;
+       struct rk_fb_inf *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 *inf = info->inf;
+       int i;
+       inf->mach_info->io_disable();
+       for(i = 0; i < inf->num_lcdc; i++)
+       {
+               atomic_set(&inf->lcdc_dev_drv[i]->in_suspend,1);
+               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 *inf = info->inf;
+       int i;
+       inf->mach_info->io_enable();
+       for(i = 0; i < inf->num_lcdc; i++)
+       {
+               inf->lcdc_dev_drv[i]->resume(inf->lcdc_dev_drv[i]);
+               atomic_set(&inf->lcdc_dev_drv[i]->in_suspend,0);
+       }
+
+}
+
+
+
+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 __devinit rk_fb_probe (struct platform_device *pdev)
 {
-       struct rk_fb_inf *fb_inf        = NULL;
+       struct rk_fb_inf *fb_inf = NULL;
+       struct rk29fb_info * mach_info = NULL;
        int ret = 0;
        g_fb_pdev=pdev;
-    /* Malloc rk29fb_inf and set it to pdev for drvdata */
-    fb_inf = kmalloc(sizeof(struct rk_fb_inf), GFP_KERNEL);
-    if(!fb_inf)
-    {
-        dev_err(&pdev->dev, ">>fb inf kmalloc fail!");
-        ret = -ENOMEM;
-    }
-    memset(fb_inf, 0, sizeof(struct rk_fb_inf));
-       platform_set_drvdata(pdev, fb_inf);
+       /* Malloc rk_fb_inf and set it to pdev for drvdata */
+       fb_inf = kzalloc(sizeof(struct rk_fb_inf), GFP_KERNEL);
+       if(!fb_inf)
+       {
+               dev_err(&pdev->dev, ">>fb inf kmalloc fail!");
+               ret = -ENOMEM;
+       }
+       platform_set_drvdata(pdev,fb_inf);
+       mach_info =  pdev->dev.platform_data;
+       fb_inf->mach_info = mach_info;
+       if(mach_info->io_init)
+               mach_info->io_init(NULL);
+#ifdef CONFIG_HAS_EARLYSUSPEND
+       suspend_info.inf = fb_inf;
+       register_early_suspend(&suspend_info.early_suspend);
+#endif
        printk("rk fb probe ok!\n");
     return 0;
 }
 
 static int __devexit rk_fb_remove(struct platform_device *pdev)
 {
-    return 0;
+       struct rk_fb_inf *fb_inf = platform_get_drvdata(pdev);
+       kfree(fb_inf);
+       platform_set_drvdata(pdev, NULL);
+       return 0;
 }
 
 static void rk_fb_shutdown(struct platform_device *pdev)
 {
-
+       struct rk_fb_inf *fb_inf = platform_get_drvdata(pdev);
+       kfree(fb_inf);
+       platform_set_drvdata(pdev, NULL);
 }
 
 static struct platform_driver rk_fb_driver = {
@@ -647,6 +886,6 @@ static void __exit rk_fb_exit(void)
     platform_driver_unregister(&rk_fb_driver);
 }
 
-fs_initcall(rk_fb_init);
+subsys_initcall_sync(rk_fb_init);
 module_exit(rk_fb_exit);