Merge remote-tracking branch 'aosp/android-3.0' into develop-3.0
[firefly-linux-kernel-4.4.55.git] / drivers / video / rockchip / rk_fb.c
1 /*
2  * drivers/video/rockchip/rk_fb.c
3  *
4  * Copyright (C) 2012 ROCKCHIP, Inc.
5  *Author:yzq<yzq@rock-chips.com>
6         yxj<yxj@rock-chips.com>
7  * This software is licensed under the terms of the GNU General Public
8  * License version 2, as published by the Free Software Foundation, and
9  * may be copied, distributed, and modified under those terms.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  */
16
17 #include <linux/module.h>
18 #include <linux/kernel.h>
19 #include <linux/errno.h>
20 #include <linux/string.h>
21 #include <linux/mm.h>
22 #include <linux/slab.h>
23 #include <linux/delay.h>
24 #include <linux/device.h>
25 #include <linux/kthread.h>
26 #include <linux/fb.h>
27 #include <linux/init.h>
28 #include <linux/platform_device.h>
29 #include <linux/earlysuspend.h>
30 #include <asm/div64.h>
31 #include <asm/uaccess.h>
32 #include<linux/rk_fb.h>
33 #include <plat/ipp.h>
34 #include "hdmi/rk_hdmi.h"
35 #include <linux/linux_logo.h>
36
37 void rk29_backlight_set(bool on);
38 bool rk29_get_backlight_status(void);
39
40 #ifdef  CONFIG_FB_MIRRORING
41
42
43 int (*video_data_to_mirroring)(struct fb_info *info,u32 yuv_phy[2]) = NULL;
44 EXPORT_SYMBOL(video_data_to_mirroring);
45
46 #endif
47 static struct platform_device *g_fb_pdev;
48
49 static struct rk_fb_rgb def_rgb_16 = {
50      red:    { offset: 11, length: 5, },
51      green:  { offset: 5,  length: 6, },
52      blue:   { offset: 0,  length: 5, },
53      transp: { offset: 0,  length: 0, },
54 };
55
56
57 /***************************************************************************
58 fb0-----------lcdc0------------win1  for ui
59 fb1-----------lcdc0------------win0  for video,win0 support 3d display
60 fb2-----------lcdc1------------win1  for ui
61 fb3-----------lcdc1-------------win0 for video ,win0 support 3d display
62
63 defautl:we alloc three buffer,one for fb0 and fb2 display ui,one for ipp rotate
64         fb1 and fb3 are used for video play,the buffer is alloc by android,and
65         pass the phy addr to fix.smem_start by ioctl
66 ****************************************************************************/
67
68
69
70 /**********************************************************************
71 this is for hdmi
72 name: lcdc device name ,lcdc0 , lcdc1
73 ***********************************************************************/
74 struct rk_lcdc_device_driver * rk_get_lcdc_drv(char *name)
75 {
76         struct rk_fb_inf *inf =  platform_get_drvdata(g_fb_pdev);
77         int i = 0;
78         for( i = 0; i < inf->num_lcdc; i++)
79         {
80                 if(!strcmp(inf->lcdc_dev_drv[i]->name,name))
81                         break;
82         }
83         return inf->lcdc_dev_drv[i];
84         
85 }
86 static int rk_fb_open(struct fb_info *info,int user)
87 {
88     struct rk_lcdc_device_driver * dev_drv = (struct rk_lcdc_device_driver * )info->par;
89     int layer_id;
90   
91     layer_id = dev_drv->fb_get_layer(dev_drv,info->fix.id);
92     if(dev_drv->layer_par[layer_id]->state)
93     {
94         return 0;    // if this layer aready opened ,no need to reopen
95     }
96     else
97     {
98         dev_drv->open(dev_drv,layer_id,1);
99     }
100     
101     return 0;
102     
103 }
104
105 static int rk_fb_close(struct fb_info *info,int user)
106 {
107         /*struct rk_lcdc_device_driver * dev_drv = (struct rk_lcdc_device_driver * )info->par;
108         int layer_id;
109         CHK_SUSPEND(dev_drv);
110         layer_id = get_fb_layer_id(&info->fix);
111         if(!dev_drv->layer_par[layer_id]->state)
112         {
113                 return 0;
114         }
115         else
116         {
117                 dev_drv->open(dev_drv,layer_id,0);
118         }*/
119         
120         return 0;
121 }
122 static void fb_copy_by_ipp(struct fb_info *dst_info, struct fb_info *src_info,int offset)
123 {
124         struct rk29_ipp_req ipp_req;
125
126         uint32_t  rotation = 0;
127 #if defined(CONFIG_FB_ROTATE)
128         int orientation = orientation = 270 - CONFIG_ROTATE_ORIENTATION;
129         switch(orientation)
130         {
131                 case 0:
132                         rotation = IPP_ROT_0;
133                         break;
134                 case 90:
135                         rotation = IPP_ROT_90;
136                         break;
137                 case 180:
138                         rotation = IPP_ROT_180;
139                         break;
140                 case 270:
141                         rotation = IPP_ROT_270;
142                         break;
143                 default:
144                         rotation = IPP_ROT_270;
145                         break;
146                         
147         }
148 #endif
149         memset(&ipp_req, 0, sizeof(struct rk29_ipp_req));
150         ipp_req.src0.YrgbMst = src_info->fix.smem_start + offset;
151         ipp_req.src0.w = src_info->var.xres;
152         ipp_req.src0.h = src_info->var.yres;
153
154         ipp_req.dst0.YrgbMst = dst_info->fix.smem_start + offset;
155         ipp_req.dst0.w = src_info->var.xres;
156         ipp_req.dst0.h = src_info->var.yres;
157
158         ipp_req.src_vir_w = src_info->var.xres_virtual;
159         ipp_req.dst_vir_w = src_info->var.xres_virtual;
160         ipp_req.timeout = 100;
161         ipp_req.flag = rotation;
162         ipp_blit_sync(&ipp_req);
163         
164 }
165
166
167 #if 0
168
169 static void hdmi_post_work(struct work_struct *work)
170 {       
171         struct rk_fb_inf *inf = container_of(to_delayed_work(work), struct rk_fb_inf, delay_work);
172         struct fb_info * info2 = inf->fb[2];    
173         struct fb_info * info = inf->fb[0];     
174         struct rk_lcdc_device_driver * dev_drv1  = (struct rk_lcdc_device_driver * )info2->par;
175         struct rk_lcdc_device_driver * dev_drv  = (struct rk_lcdc_device_driver * )info->par;
176         struct layer_par *par = dev_drv->layer_par[1];
177         struct layer_par *par2 = dev_drv1->layer_par[1];        
178         struct fb_var_screeninfo *var = &info->var;   
179         u32 xvir = var->xres_virtual;   
180         dev_drv1->xoffset = var->xoffset;             // offset from virtual to visible 
181         dev_drv1->yoffset += var->yres; 
182         if(dev_drv1->yoffset >= 3*var->yres)
183                 dev_drv1->yoffset = 0;++        
184                 rk_bufferoffset_tran(dev_drv1->xoffset, dev_drv1->yoffset, xvir , par2);
185         fb_copy_by_ipp(info2,info,par->y_offset,par2->y_offset);
186         dev_drv1->pan_display(dev_drv1,1);
187         complete(&(dev_drv1->ipp_done));
188 }
189 #endif
190
191 static int rk_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
192 {
193         struct rk_fb_inf *inf = dev_get_drvdata(info->device);
194         struct fb_fix_screeninfo *fix = &info->fix;
195         struct rk_lcdc_device_driver * dev_drv = (struct rk_lcdc_device_driver * )info->par;
196         struct fb_info * info2 = NULL; 
197         struct rk_lcdc_device_driver * dev_drv1  = NULL; 
198         struct layer_par *par = NULL;
199         struct layer_par *par2 = NULL;
200         int layer_id = 0;
201         u32 xoffset = var->xoffset;             // offset from virtual to visible 
202         u32 yoffset = var->yoffset;                             
203         u32 xvir = var->xres_virtual;
204         u8 data_format = var->nonstd&0xff;
205         
206         layer_id = dev_drv->fb_get_layer(dev_drv,info->fix.id);
207         if(layer_id < 0)
208         {
209                 return  -ENODEV;
210         }
211         else
212         {
213                  par = dev_drv->layer_par[layer_id];
214         }
215         switch (par->format)
216         {
217                 case XBGR888:
218                 case ARGB888:
219                 case ABGR888:
220                         par->y_offset = (yoffset*xvir + xoffset)*4;
221                         break;
222                 case  RGB888:
223                         par->y_offset = (yoffset*xvir + xoffset)*3;
224                         break;
225                 case RGB565:
226                         par->y_offset = (yoffset*xvir + xoffset)*2;
227                         break;
228                 case  YUV422:
229                         par->y_offset = yoffset*xvir + xoffset;
230                         par->c_offset = par->y_offset;
231                         break;
232                 case  YUV420:
233                         par->y_offset = yoffset*xvir + xoffset;
234                         par->c_offset = (yoffset>>1)*xvir + xoffset;
235                         break;
236                 case  YUV444 : // yuv444
237                         par->y_offset = yoffset*xvir + xoffset;
238                         par->c_offset = yoffset*2*xvir +(xoffset<<1);
239                         break;
240                 default:
241                         printk("un supported format:0x%x\n",data_format);
242                         return -EINVAL;
243         }
244
245         #if defined(CONFIG_RK_HDMI)
246                 #if defined(CONFIG_DUAL_LCDC_DUAL_DISP_IN_KERNEL)
247                         if(hdmi_get_hotplug() == HDMI_HPD_ACTIVED)
248                         {
249                                 if(inf->num_fb >= 2)
250                                 {
251                                         info2 = inf->fb[inf->num_fb>>1];
252                                         dev_drv1 = (struct rk_lcdc_device_driver * )info2->par;
253                                         par2 = dev_drv1->layer_par[layer_id];
254                                         par2->y_offset = par->y_offset;
255                                         //memcpy(info2->screen_base+par2->y_offset,info->screen_base+par->y_offset,
256                                         //      var->xres*var->yres*var->bits_per_pixel>>3);
257                                         #if defined(CONFIG_FB_ROTATE) || !defined(CONFIG_THREE_FB_BUFFER)
258                                         fb_copy_by_ipp(info2,info,par->y_offset);
259                                         #endif
260                                         dev_drv1->pan_display(dev_drv1,layer_id);
261                                         //queue_delayed_work(inf->workqueue, &inf->delay_work,0);
262                                 }
263                         }
264                 #endif
265         #endif
266         dev_drv->pan_display(dev_drv,layer_id);
267         #ifdef  CONFIG_FB_MIRRORING
268         if(video_data_to_mirroring!=NULL)
269                 video_data_to_mirroring(info,NULL);
270         #endif
271         return 0;
272 }
273 static int rk_fb_ioctl(struct fb_info *info, unsigned int cmd,unsigned long arg)
274 {
275         struct fb_fix_screeninfo *fix = &info->fix;
276         struct rk_lcdc_device_driver *dev_drv = (struct rk_lcdc_device_driver * )info->par;
277         u32 yuv_phy[2];
278         int  layer_id = dev_drv->fb_get_layer(dev_drv,info->fix.id);
279         int enable; // enable fb:1 enable;0 disable 
280         int ovl;        //overlay:0 win1 on the top of win0;1,win0 on the top of win1
281         int num_buf; //buffer_number
282         void __user *argp = (void __user *)arg;
283         
284         switch(cmd)
285         {
286                 case FBIOPUT_FBPHYADD:
287                         return info->fix.smem_start;
288                         break;
289                 case RK_FBIOSET_YUV_ADDR:   //when in video mode, buff alloc by android
290                         //if((!strcmp(fix->id,"fb1"))||(!strcmp(fix->id,"fb3")))
291                         {
292                                 if (copy_from_user(yuv_phy, argp, 8))
293                                         return -EFAULT;
294                                 info->fix.smem_start = yuv_phy[0];  //four y
295                                 info->fix.mmio_start = yuv_phy[1];  //four uv
296                         }
297                         break;
298                 case RK_FBIOSET_ENABLE:
299                         if (copy_from_user(&enable, argp, sizeof(enable)))
300                                 return -EFAULT;
301                         dev_drv->open(dev_drv,layer_id,enable);
302                         break;
303                 case RK_FBIOGET_ENABLE:
304                         enable = dev_drv->get_layer_state(dev_drv,layer_id);
305                         if(copy_to_user(argp,&enable,sizeof(enable)))
306                                 return -EFAULT;
307                         break;
308                 case RK_FBIOSET_OVERLAY_STATE:
309                         if (copy_from_user(&ovl, argp, sizeof(ovl)))
310                                 return -EFAULT;
311                         dev_drv->ovl_mgr(dev_drv,ovl,1);
312                         break;
313                 case RK_FBIOGET_OVERLAY_STATE:
314                         ovl = dev_drv->ovl_mgr(dev_drv,0,0);
315                         if (copy_to_user(argp, &ovl, sizeof(ovl)))
316                                 return -EFAULT;
317                         break;
318                 case RK_FBIOPUT_NUM_BUFFERS:
319                         if (copy_from_user(&num_buf, argp, sizeof(num_buf)))
320                                 return -EFAULT;
321                         dev_drv->num_buf = num_buf;
322                         printk("rk fb use %d buffers\n",num_buf);
323                         break;
324                 case RK_FBIOSET_VSYNC_ENABLE:
325                         if (copy_from_user(&enable, argp, sizeof(enable)))
326                                 return -EFAULT;
327                         dev_drv->vsync_info.active = enable;
328                         break;
329                 default:
330                         dev_drv->ioctl(dev_drv,cmd,arg,layer_id);
331                         break;
332     }
333     return 0;
334 }
335
336 static int rk_fb_blank(int blank_mode, struct fb_info *info)
337 {
338         struct rk_lcdc_device_driver *dev_drv = (struct rk_lcdc_device_driver * )info->par;
339         struct fb_fix_screeninfo *fix = &info->fix;
340         int layer_id;
341         
342         layer_id = dev_drv->fb_get_layer(dev_drv,info->fix.id);
343         if(layer_id < 0)
344         {
345                 return  -ENODEV;
346         }
347 #if defined(CONFIG_RK_HDMI)
348 #if defined(CONFIG_ONE_LCDC_DUAL_OUTPUT_INF)
349         if(hdmi_get_hotplug() == HDMI_HPD_ACTIVED){
350                 printk("hdmi is connect , not blank lcdc\n");
351         }else
352 #endif
353 #endif
354         {
355                 dev_drv->blank(dev_drv,layer_id,blank_mode);
356         }
357         return 0;
358 }
359
360 static int rk_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
361 {
362         
363         if( 0==var->xres_virtual || 0==var->yres_virtual ||
364                  0==var->xres || 0==var->yres || var->xres<16 ||
365                  ((16!=var->bits_per_pixel)&&(32!=var->bits_per_pixel)) )
366          {
367                  printk("%s check var fail 1!!! \n",info->fix.id);
368                  printk("xres_vir:%d>>yres_vir:%d\n", var->xres_virtual,var->yres_virtual);
369                  printk("xres:%d>>yres:%d\n", var->xres,var->yres);
370                  printk("bits_per_pixel:%d \n", var->bits_per_pixel);
371                  return -EINVAL;
372          }
373  
374          if( ((var->xoffset+var->xres) > var->xres_virtual) ||
375              ((var->yoffset+var->yres) > (var->yres_virtual)) )
376          {
377                  printk("%s check_var fail 2!!! \n",info->fix.id);
378                  printk("xoffset:%d>>xres:%d>>xres_vir:%d\n",var->xoffset,var->xres,var->xres_virtual);
379                  printk("yoffset:%d>>yres:%d>>yres_vir:%d\n",var->yoffset,var->yres,var->yres_virtual);
380                  return -EINVAL;
381          }
382
383     return 0;
384 }
385
386
387 static int rk_fb_set_par(struct fb_info *info)
388 {
389         struct rk_fb_inf *inf = dev_get_drvdata(info->device);
390         struct fb_var_screeninfo *var = &info->var;
391         struct fb_fix_screeninfo *fix = &info->fix;
392         struct rk_lcdc_device_driver * dev_drv = (struct rk_lcdc_device_driver * )info->par;
393         struct layer_par *par = NULL;
394         rk_screen *screen =dev_drv->cur_screen;
395         struct fb_info * info2 = NULL;
396         struct rk_lcdc_device_driver * dev_drv1  = NULL;
397         struct layer_par *par2 = NULL;
398         int layer_id = 0;       
399         u32 cblen = 0,crlen = 0;
400         u16 xsize =0,ysize = 0;              //winx display window height/width --->LCDC_WINx_DSP_INFO
401         u32 xoffset = var->xoffset;             // offset from virtual to visible 
402         u32 yoffset = var->yoffset;             //resolution                    
403         u16 xpos = (var->nonstd>>8) & 0xfff; //visiable pos in panel
404         u16 ypos = (var->nonstd>>20) & 0xfff;
405         u32 xvir = var->xres_virtual;
406         u32 yvir = var->yres_virtual;
407         u8 data_format = var->nonstd&0xff;
408         var->pixclock = dev_drv->pixclock;
409         
410         #if defined(CONFIG_RK_HDMI)
411                 #if defined(CONFIG_DUAL_LCDC_DUAL_DISP_IN_KERNEL)
412                         if(hdmi_get_hotplug() == HDMI_HPD_ACTIVED)
413                         {
414                                 if(inf->num_fb >= 2)
415                                 {
416                                         info2 = inf->fb[inf->num_fb>>1];
417                                         dev_drv1 = (struct rk_lcdc_device_driver * )info2->par;
418                                 }
419                         }
420                 #endif 
421         #endif
422         layer_id = dev_drv->fb_get_layer(dev_drv,info->fix.id);
423         if(layer_id < 0)
424         {
425                 return  -ENODEV;
426         }
427         else
428         {
429                 par = dev_drv->layer_par[layer_id];
430                 if(dev_drv1)
431                 {
432                         par2 = dev_drv1->layer_par[layer_id];
433                 }
434         }
435         
436         if(var->grayscale>>8)  //if the application has specific the horizontal and vertical display size
437         {
438                 xsize = (var->grayscale>>8) & 0xfff;  //visiable size in panel ,for vide0
439                 ysize = (var->grayscale>>20) & 0xfff;
440         }
441         else  //ohterwise  full  screen display
442         {
443                 xsize = screen->x_res;
444                 ysize = screen->y_res;
445         }
446
447 #if defined(CONFIG_ONE_LCDC_DUAL_OUTPUT_INF) || defined(CONFIG_NO_DUAL_DISP)
448         if(screen->screen_id == 0) //this is for device like rk2928 ,whic have one lcdc but two display outputs
449         {                          //save parameter set by android
450                 dev_drv->screen0->xsize = xsize;
451                 dev_drv->screen0->ysize = ysize;
452                 dev_drv->screen0->xpos  = xpos;
453                 dev_drv->screen0->ypos = ypos;
454         }
455         else
456         {
457                 xsize = dev_drv->screen1->xsize; 
458                 ysize = dev_drv->screen1->ysize;
459                 xpos = dev_drv->screen1->xpos;
460                 ypos = dev_drv->screen1->ypos;
461         }
462 #endif
463         /* calculate y_offset,c_offset,line_length,cblen and crlen  */
464 #if 1
465         switch (data_format)
466         {
467                 case HAL_PIXEL_FORMAT_RGBX_8888: 
468                         par->format = XBGR888;
469                         fix->line_length = 4 * xvir;
470                         par->y_offset = (yoffset*xvir + xoffset)*4;
471                         break;
472                 case HAL_PIXEL_FORMAT_RGBA_8888 :      // rgb
473                         par->format = ABGR888;
474                         fix->line_length = 4 * xvir;
475                         par->y_offset = (yoffset*xvir + xoffset)*4;
476                         break;
477                 case HAL_PIXEL_FORMAT_BGRA_8888 :      // rgb
478                         par->format = ARGB888;
479                         fix->line_length = 4 * xvir;
480                         par->y_offset = (yoffset*xvir + xoffset)*4;
481                         break;
482                 case HAL_PIXEL_FORMAT_RGB_888 :
483                         par->format = RGB888;
484                         fix->line_length = 3 * xvir;
485                         par->y_offset = (yoffset*xvir + xoffset)*3;
486                         break;
487                 case HAL_PIXEL_FORMAT_RGB_565:  //RGB565
488                         par->format = RGB565;
489                         fix->line_length = 2 * xvir;
490                         par->y_offset = (yoffset*xvir + xoffset)*2;
491                         break;
492                 case HAL_PIXEL_FORMAT_YCbCr_422_SP : // yuv422
493                         par->format = YUV422;
494                         fix->line_length = xvir;
495                         cblen = crlen = (xvir*yvir)>>1;
496                         par->y_offset = yoffset*xvir + xoffset;
497                         par->c_offset = par->y_offset;
498                         break;
499                 case HAL_PIXEL_FORMAT_YCrCb_NV12   : // YUV420---uvuvuv
500                         par->format = YUV420;
501                         fix->line_length = xvir;
502                         cblen = crlen = (xvir*yvir)>>2;
503                         par->y_offset = yoffset*xvir + xoffset;
504                         par->c_offset = (yoffset>>1)*xvir + xoffset;
505                         break;
506                 case HAL_PIXEL_FORMAT_YCrCb_444 : // yuv444
507                         par->format = 5;
508                         fix->line_length = xvir<<2;
509                         par->y_offset = yoffset*xvir + xoffset;
510                         par->c_offset = yoffset*2*xvir +(xoffset<<1);
511                         cblen = crlen = (xvir*yvir);
512                         break;
513                 default:
514                         printk("%s:un supported format:0x%x\n",__func__,data_format);
515                     return -EINVAL;
516         }
517 #else
518         switch(var->bits_per_pixel)
519         {
520                 case 32:
521                         par->format = ARGB888;
522                         fix->line_length = 4 * xvir;
523                         par->y_offset = (yoffset*xvir + xoffset)*4;
524                         break;
525                 case 16:
526                         par->format = RGB565;
527                         fix->line_length = 2 * xvir;
528                         par->y_offset = (yoffset*xvir + xoffset)*2;
529                         break;
530                         
531         }
532 #endif
533
534         par->xpos = xpos;
535         par->ypos = ypos;
536         par->xsize = xsize;
537         par->ysize = ysize;
538
539         par->smem_start =fix->smem_start;
540         par->cbr_start = fix->mmio_start;
541         par->xact = var->xres;              //winx active window height,is a part of vir
542         par->yact = var->yres;
543         par->xvir =  var->xres_virtual;         // virtual resolution    stride --->LCDC_WINx_VIR
544         par->yvir =  var->yres_virtual;
545
546         #if defined(CONFIG_RK_HDMI)
547                 #if defined(CONFIG_DUAL_LCDC_DUAL_DISP_IN_KERNEL)
548                         if(hdmi_get_hotplug() == HDMI_HPD_ACTIVED)
549                         {
550                                 if(info != info2)
551                                 {
552                                         par2->xact = par->xact;
553                                         par2->yact = par->yact;
554                                         par2->format = par->format;
555                                         par2->xvir = par->xvir;
556                                         info2->var.nonstd &= 0xffffff00;
557                                         info2->var.nonstd |= data_format;
558                                         dev_drv1->set_par(dev_drv1,layer_id);
559                                 }
560                         }
561                 #endif
562         #endif
563         dev_drv->set_par(dev_drv,layer_id);
564
565     
566         return 0;
567 }
568
569 static inline unsigned int chan_to_field(unsigned int chan,
570                                          struct fb_bitfield *bf)
571 {
572         chan &= 0xffff;
573         chan >>= 16 - bf->length;
574         return chan << bf->offset;
575 }
576
577 static int fb_setcolreg(unsigned regno,
578                                unsigned red, unsigned green, unsigned blue,
579                                unsigned transp, struct fb_info *info)
580 {
581         unsigned int val;
582
583         switch (info->fix.visual) {
584         case FB_VISUAL_TRUECOLOR:
585                 /* true-colour, use pseudo-palette */
586                 if (regno < 16) {
587                         u32 *pal = info->pseudo_palette;
588                         val  = chan_to_field(red,   &info->var.red);
589                         val |= chan_to_field(green, &info->var.green);
590                         val |= chan_to_field(blue,  &info->var.blue);
591                         pal[regno] = val;
592                 }
593                 break;
594         default:
595                 return -1;      /* unknown type */
596         }
597
598         return 0;
599 }
600
601 static struct fb_ops fb_ops = {
602     .owner          = THIS_MODULE,
603     .fb_open        = rk_fb_open,
604     .fb_release     = rk_fb_close,
605     .fb_check_var   = rk_fb_check_var,
606     .fb_set_par     = rk_fb_set_par,
607     .fb_blank       = rk_fb_blank,
608     .fb_ioctl       = rk_fb_ioctl,
609     .fb_pan_display = rk_pan_display,
610     .fb_setcolreg   = fb_setcolreg,
611     .fb_fillrect    = cfb_fillrect,
612     .fb_copyarea    = cfb_copyarea,
613     .fb_imageblit   = cfb_imageblit,
614 };
615
616
617
618 static struct fb_var_screeninfo def_var = {
619         .red    = {11,5,0},//default set to rgb565,the boot logo is rgb565
620         .green  = {5,6,0},
621         .blue   = {0,5,0},
622         .transp = {0,0,0},      
623 #ifdef  CONFIG_LOGO_LINUX_BMP
624         .nonstd      = HAL_PIXEL_FORMAT_RGBA_8888,
625 #else
626         .nonstd      = HAL_PIXEL_FORMAT_RGB_565,   //(ypos<<20+xpos<<8+format) format
627 #endif
628         .grayscale   = 0,  //(ysize<<20+xsize<<8)
629         .activate    = FB_ACTIVATE_NOW,
630         .accel_flags = 0,
631         .vmode       = FB_VMODE_NONINTERLACED,
632 };
633
634 static struct fb_fix_screeninfo def_fix = {
635         .type            = FB_TYPE_PACKED_PIXELS,
636         .type_aux        = 0,
637         .xpanstep        = 1,
638         .ypanstep        = 1,
639         .ywrapstep       = 0,
640         .accel           = FB_ACCEL_NONE,
641         .visual          = FB_VISUAL_TRUECOLOR,
642                 
643 };
644
645
646 static int rk_fb_wait_for_vsync_thread(void *data)
647 {
648         struct rk_lcdc_device_driver  *dev_drv = data;
649         struct rk_fb_inf *inf =  platform_get_drvdata(g_fb_pdev);
650         struct fb_info *fbi = inf->fb[0];
651
652         while (!kthread_should_stop()) {
653                 ktime_t timestamp = dev_drv->vsync_info.timestamp;
654                 int ret = wait_event_interruptible(dev_drv->vsync_info.wait,
655                         !ktime_equal(timestamp, dev_drv->vsync_info.timestamp) &&
656                         dev_drv->vsync_info.active);
657
658                 if (!ret) {
659                         sysfs_notify(&fbi->dev->kobj, NULL, "vsync");
660                 }
661         }
662
663         return 0;
664 }
665
666 static ssize_t rk_fb_vsync_show(struct device *dev,
667                 struct device_attribute *attr, char *buf)
668 {
669         struct fb_info *fbi = dev_get_drvdata(dev);
670         struct rk_lcdc_device_driver * dev_drv = 
671                 (struct rk_lcdc_device_driver * )fbi->par;
672         return scnprintf(buf, PAGE_SIZE, "%llu\n",
673                         ktime_to_ns(dev_drv->vsync_info.timestamp));
674 }
675
676 static DEVICE_ATTR(vsync, S_IRUGO, rk_fb_vsync_show, NULL);
677
678
679 /*****************************************************************
680 this two function is for other module that in the kernel which
681 need show image directly through fb
682 fb_id:we have 4 fb here,default we use fb0 for ui display
683 *******************************************************************/
684 struct fb_info * rk_get_fb(int fb_id)
685 {
686     struct rk_fb_inf *inf =  platform_get_drvdata(g_fb_pdev);
687     struct fb_info *fb = inf->fb[fb_id];
688     return fb;
689 }
690 EXPORT_SYMBOL(rk_get_fb);
691
692 void rk_direct_fb_show(struct fb_info * fbi)
693 {
694     rk_fb_set_par(fbi);
695     rk_pan_display(&fbi->var, fbi);
696 }
697 EXPORT_SYMBOL(rk_direct_fb_show);
698
699
700
701 /******************************************
702 function:this function will be called by hdmi,when 
703               hdmi plug in/out
704 screen: the screen attached to hdmi
705 enable: 1,hdmi plug in,0,hdmi plug out
706 lcdc_id: the lcdc id the hdmi attached ,0 or 1
707 ******************************************/
708 int rk_fb_switch_screen(rk_screen *screen ,int enable ,int lcdc_id)
709 {
710         struct rk_fb_inf *inf =  platform_get_drvdata(g_fb_pdev);
711         struct fb_info *info = NULL;
712         struct fb_info *pmy_info = NULL;
713         struct rk_lcdc_device_driver * dev_drv = NULL;
714         struct fb_var_screeninfo *pmy_var = NULL;      //var for primary screen
715         struct fb_var_screeninfo *hdmi_var    = NULL;
716         struct fb_fix_screeninfo *pmy_fix = NULL;
717         struct fb_fix_screeninfo *hdmi_fix    = NULL;
718         char name[6];
719         int ret;
720         int i;
721         int layer_id;
722
723 #if defined(CONFIG_ONE_LCDC_DUAL_OUTPUT_INF) || defined(CONFIG_NO_DUAL_DISP)
724         rk29_backlight_set(0);
725 #endif
726         
727         sprintf(name, "lcdc%d",lcdc_id);
728         for(i = 0; i < inf->num_lcdc; i++)  //find the driver for the extend display device
729         {
730                 if(inf->lcdc_dev_drv[i]->screen_ctr_info->prop == EXTEND)
731                 {
732                         dev_drv = inf->lcdc_dev_drv[i];
733                         printk("hdmi connect to lcdc%d\n",dev_drv->id);
734                         break;
735                 }
736         }
737
738         if(i == inf->num_lcdc)
739         {
740                 printk(KERN_ERR "%s driver not found!",name);
741                 return -ENODEV;
742                 
743         }
744
745         
746         if(inf->num_lcdc == 1)
747         {
748                 info = inf->fb[0];
749         }
750         else if(inf->num_lcdc == 2)
751         {
752                 info = inf->fb[dev_drv->num_layer]; //the main fb of lcdc1
753         }
754
755         if(dev_drv->screen1) //device like rk2928 ,have only one lcdc but two outputs
756         {
757                 if(enable)
758                 {
759                         memcpy(dev_drv->screen1,screen,sizeof(rk_screen ));
760                         dev_drv->screen1->lcdc_id = 0; //connect screen1 to output interface 0
761                         dev_drv->screen1->screen_id = 1;
762                         dev_drv->screen0->lcdc_id = 1; //connect screen0 to output interface 1
763                         dev_drv->cur_screen = dev_drv->screen1;
764                         if(dev_drv->screen0->sscreen_get)
765                         {
766                                 dev_drv->screen0->sscreen_get(dev_drv->screen0,
767                                         dev_drv->cur_screen->hdmi_resolution);
768                         }
769                         if(dev_drv->screen0->sscreen_set)
770                         {
771                                 dev_drv->screen0->sscreen_set(dev_drv->screen0,enable);
772                         }
773                         
774                 }
775                 else
776                 {
777                         dev_drv->screen1->lcdc_id = 1; //connect screen1 to output interface 1
778                         dev_drv->screen0->lcdc_id = 0; //connect screen0 to output interface 0
779                         dev_drv->cur_screen = dev_drv->screen0;
780                         dev_drv->screen_ctr_info->set_screen_info(dev_drv->cur_screen,
781                         dev_drv->screen_ctr_info->lcd_info);
782                         
783                 }
784         }
785         else
786         {
787                 if(enable)
788                 {
789                         memcpy(dev_drv->cur_screen,screen,sizeof(rk_screen ));
790                 }
791         }
792
793         
794         layer_id = dev_drv->fb_get_layer(dev_drv,info->fix.id);
795         
796         if(!enable && !dev_drv->screen1) //only double lcdc device need to close
797         {
798                 if(dev_drv->layer_par[layer_id]->state) 
799                 {
800                         dev_drv->open(dev_drv,layer_id,enable); //disable the layer which attached to this fb
801                 }
802                 return 0;
803         }
804         
805         hdmi_var = &info->var;
806         hdmi_fix = &info->fix;
807         #if defined(CONFIG_DUAL_LCDC_DUAL_DISP_IN_KERNEL)
808                 if(likely(inf->num_lcdc == 2))
809                 {
810                         pmy_var = &inf->fb[0]->var;
811                         pmy_fix = &inf->fb[0]->fix;
812                         hdmi_var->xres = pmy_var->xres;
813                         hdmi_var->yres = pmy_var->yres;
814                         hdmi_var->xres_virtual = pmy_var->xres_virtual;
815                         hdmi_var->yres_virtual = pmy_var->yres_virtual;
816                         hdmi_var->nonstd &= 0xffffff00;
817                         hdmi_var->nonstd |= (pmy_var->nonstd & 0xff); //use the same format as primary screen
818                 }
819                 else
820                 {
821                         printk(KERN_WARNING "%s>>only one lcdc,dual display no supported!",__func__);
822                 }
823         #endif
824         hdmi_var->grayscale &= 0xff;
825         hdmi_var->grayscale |= (dev_drv->cur_screen->x_res<<8) + (dev_drv->cur_screen->y_res<<20);
826
827         if(dev_drv->screen1)  //device like rk2928,whic have one lcdc but two outputs
828         {
829         //      info->var.nonstd &= 0xff;
830         //      info->var.nonstd |= (dev_drv->cur_screen->xpos<<8) + (dev_drv->cur_screen->ypos<<20);
831         //      info->var.grayscale &= 0xff;
832         //      info->var.grayscale |= (dev_drv->cur_screen->x_res<<8) + (dev_drv->cur_screen->y_res<<20);
833                 dev_drv->screen1->xsize = dev_drv->cur_screen->x_res;
834                 dev_drv->screen1->ysize = dev_drv->cur_screen->y_res;
835                 dev_drv->screen1->xpos = 0;
836                 dev_drv->screen1->ypos = 0;
837         }
838         ret = info->fbops->fb_open(info,1);
839         dev_drv->load_screen(dev_drv,1);
840         ret = info->fbops->fb_set_par(info);
841         if(dev_drv->lcdc_hdmi_process)
842                 dev_drv->lcdc_hdmi_process(dev_drv,enable);
843
844         #if defined(CONFIG_DUAL_LCDC_DUAL_DISP_IN_KERNEL)
845                 if(likely(inf->num_lcdc == 2))
846                 {
847                         pmy_info = inf->fb[0];
848                         pmy_info->fbops->fb_pan_display(pmy_var,pmy_info);
849                 }
850                 else
851                 {
852                         printk(KERN_WARNING "%s>>only one lcdc,dual display no supported!",__func__);
853                 }
854         #elif defined(CONFIG_ONE_LCDC_DUAL_OUTPUT_INF)
855                 info->fbops->fb_pan_display(hdmi_var,info);
856         #endif 
857
858 #if defined(CONFIG_NO_DUAL_DISP)  //close backlight for device whic do not support dual display
859         if(!enable)
860                 rk29_backlight_set(1);
861 #elif defined(CONFIG_ONE_LCDC_DUAL_OUTPUT_INF)  //close backlight for device whic do not support dual display
862         rk29_backlight_set(1);
863 #endif
864         return 0;
865
866 }
867
868
869
870
871 /******************************************
872 function:this function current only called by hdmi for 
873         scale the display
874 scale_x: scale rate of x resolution
875 scale_y: scale rate of y resolution
876 lcdc_id: the lcdc id the hdmi attached ,0 or 1
877 ******************************************/
878
879 int rk_fb_disp_scale(u8 scale_x, u8 scale_y,u8 lcdc_id)
880 {
881         struct rk_fb_inf *inf =  platform_get_drvdata(g_fb_pdev);
882         struct fb_info *info = NULL;
883         struct fb_var_screeninfo *var = NULL;
884         struct rk_lcdc_device_driver * dev_drv = NULL;
885         u16 screen_x,screen_y;
886         u16 xpos,ypos;
887         u16 xsize,ysize;
888         
889         char name[6];
890         int i;
891         sprintf(name, "lcdc%d",lcdc_id);
892         for(i = 0; i < inf->num_lcdc; i++)
893         {
894                 if(inf->lcdc_dev_drv[i]->screen_ctr_info->prop == EXTEND)
895                 {
896                         dev_drv = inf->lcdc_dev_drv[i];
897                         break;
898                 }
899         }
900
901         if(i == inf->num_lcdc)
902         {
903                 printk(KERN_ERR "%s driver not found!",name);
904                 return -ENODEV;
905                 
906         }
907
908         if(inf->num_lcdc == 1)
909         {
910                 info = inf->fb[0];
911         }
912         else if(inf->num_lcdc == 2)
913         {
914                 info = inf->fb[dev_drv->num_layer];
915         }
916
917         var = &info->var;
918         screen_x = dev_drv->cur_screen->x_res;
919         screen_y = dev_drv->cur_screen->y_res;
920         
921 #if defined(CONFIG_ONE_LCDC_DUAL_OUTPUT_INF)||defined(CONFIG_NO_DUAL_DISP)
922         if(dev_drv->cur_screen->screen_id == 1){
923                 dev_drv->cur_screen->xpos = (screen_x-screen_x*scale_x/100)>>1;
924                 dev_drv->cur_screen->ypos = (screen_y-screen_y*scale_y/100)>>1;
925                 dev_drv->cur_screen->xsize = screen_x*scale_x/100;
926                 dev_drv->cur_screen->ysize = screen_y*scale_y/100;
927         }else
928 #endif
929         {
930                 xpos = (screen_x-screen_x*scale_x/100)>>1;
931                 ypos = (screen_y-screen_y*scale_y/100)>>1;
932                 xsize = screen_x*scale_x/100;
933                 ysize = screen_y*scale_y/100;
934                 var->nonstd &= 0xff;
935                 var->nonstd |= (xpos<<8) + (ypos<<20);
936                 var->grayscale &= 0xff;
937                 var->grayscale |= (xsize<<8) + (ysize<<20);     
938         }
939
940         info->fbops->fb_set_par(info);
941         return 0;
942         
943         
944 }
945
946 static int rk_request_fb_buffer(struct fb_info *fbi,int fb_id)
947 {
948         struct resource *res;
949         struct resource *mem;
950         int ret = 0;
951         struct rk_fb_inf *fb_inf = platform_get_drvdata(g_fb_pdev);
952         if (!strcmp(fbi->fix.id,"fb0"))
953         {
954                 res = platform_get_resource_byname(g_fb_pdev, IORESOURCE_MEM, "fb0 buf");
955                 if (res == NULL)
956                 {
957                         dev_err(&g_fb_pdev->dev, "failed to get memory for fb0 \n");
958                         ret = -ENOENT;
959                 }
960                 fbi->fix.smem_start = res->start;
961                 fbi->fix.smem_len = res->end - res->start + 1;
962                 mem = request_mem_region(res->start, resource_size(res), g_fb_pdev->name);
963                 fbi->screen_base = ioremap(res->start, fbi->fix.smem_len);
964                 memset(fbi->screen_base, 0, fbi->fix.smem_len);
965                 printk("fb%d:phy:%lx>>vir:%p>>len:0x%x\n",fb_id,
966                 fbi->fix.smem_start,fbi->screen_base,fbi->fix.smem_len);
967         }
968         else
969         {       
970 #if defined(CONFIG_FB_ROTATE) || !defined(CONFIG_THREE_FB_BUFFER)
971                 res = platform_get_resource_byname(g_fb_pdev, IORESOURCE_MEM, "fb2 buf");
972                 if (res == NULL)
973                 {
974                         dev_err(&g_fb_pdev->dev, "failed to get win0 memory \n");
975                         ret = -ENOENT;
976                 }
977                 fbi->fix.smem_start = res->start;
978                 fbi->fix.smem_len = res->end - res->start + 1;
979                 mem = request_mem_region(res->start, resource_size(res), g_fb_pdev->name);
980                 fbi->screen_base = ioremap(res->start, fbi->fix.smem_len);
981                 memset(fbi->screen_base, 0, fbi->fix.smem_len);
982 #else    //three buffer no need to copy
983                 fbi->fix.smem_start = fb_inf->fb[0]->fix.smem_start;
984                 fbi->fix.smem_len   = fb_inf->fb[0]->fix.smem_len;
985                 fbi->screen_base    = fb_inf->fb[0]->screen_base;
986 #endif
987                 printk("fb%d:phy:%lx>>vir:%p>>len:0x%x\n",fb_id,
988                         fbi->fix.smem_start,fbi->screen_base,fbi->fix.smem_len);        
989         }
990     return ret;
991 }
992
993 static int rk_release_fb_buffer(struct fb_info *fbi)
994 {
995         if(!fbi)
996         {
997                 printk("no need release null fb buffer!\n");
998                 return -EINVAL;
999         }
1000         if(!strcmp(fbi->fix.id,"fb1")||!strcmp(fbi->fix.id,"fb3"))  //buffer for fb1 and fb3 are alloc by android
1001                 return 0;
1002         iounmap(fbi->screen_base);
1003         release_mem_region(fbi->fix.smem_start,fbi->fix.smem_len);
1004         return 0;
1005         
1006 }
1007 static int init_layer_par(struct rk_lcdc_device_driver *dev_drv)
1008 {
1009        int i;
1010        struct layer_par * def_par = NULL;
1011        int num_par = dev_drv->num_layer;
1012        for(i = 0; i < num_par; i++)
1013        {
1014                struct layer_par *par = NULL;
1015                par =  kzalloc(sizeof(struct layer_par), GFP_KERNEL);
1016                if(!par)
1017                {
1018                        printk(KERN_ERR "kzmalloc for layer_par fail!");
1019                        return   -ENOMEM;
1020                        
1021                }
1022                def_par = &dev_drv->def_layer_par[i];
1023                strcpy(par->name,def_par->name);
1024                par->id = def_par->id;
1025                par->support_3d = def_par->support_3d;
1026                dev_drv->layer_par[i] = par;
1027        }
1028                
1029        return 0;
1030        
1031        
1032 }
1033
1034
1035 static int init_lcdc_device_driver(struct rk_lcdc_device_driver *dev_drv,
1036         struct rk_lcdc_device_driver *def_drv,int id)
1037 {
1038         if(!def_drv)
1039         {
1040                 printk(KERN_ERR "default lcdc device driver is null!\n");
1041                 return -EINVAL;
1042         }
1043         if(!dev_drv)
1044         {
1045                 printk(KERN_ERR "lcdc device driver is null!\n");
1046                 return -EINVAL; 
1047         }
1048         sprintf(dev_drv->name, "lcdc%d",id);
1049         dev_drv->id             = id;
1050         dev_drv->open           = def_drv->open;
1051         dev_drv->init_lcdc      = def_drv->init_lcdc;
1052         dev_drv->ioctl          = def_drv->ioctl;
1053         dev_drv->blank          = def_drv->blank;
1054         dev_drv->set_par        = def_drv->set_par;
1055         dev_drv->pan_display    = def_drv->pan_display;
1056         dev_drv->suspend        = def_drv->suspend;
1057         dev_drv->resume         = def_drv->resume;
1058         dev_drv->load_screen    = def_drv->load_screen;
1059         dev_drv->def_layer_par  = def_drv->def_layer_par;
1060         dev_drv->num_layer      = def_drv->num_layer;
1061         dev_drv->get_layer_state= def_drv->get_layer_state;
1062         dev_drv->get_disp_info  = def_drv->get_disp_info;
1063         dev_drv->ovl_mgr        = def_drv->ovl_mgr;
1064         dev_drv->fps_mgr        = def_drv->fps_mgr;
1065         if(def_drv->fb_get_layer)
1066                 dev_drv->fb_get_layer   = def_drv->fb_get_layer;
1067         if(def_drv->fb_layer_remap)
1068                 dev_drv->fb_layer_remap = def_drv->fb_layer_remap;
1069         if(def_drv->set_dsp_lut)
1070                 dev_drv->set_dsp_lut    = def_drv->set_dsp_lut;
1071         if(def_drv->read_dsp_lut)
1072                 dev_drv->read_dsp_lut   = def_drv->read_dsp_lut;
1073         if(def_drv->lcdc_hdmi_process)
1074                 dev_drv->lcdc_hdmi_process = def_drv->lcdc_hdmi_process;
1075         init_layer_par(dev_drv);
1076         init_completion(&dev_drv->frame_done);
1077         spin_lock_init(&dev_drv->cpl_lock);
1078         mutex_init(&dev_drv->fb_win_id_mutex);
1079         dev_drv->fb_layer_remap(dev_drv,FB_DEFAULT_ORDER); //102
1080         dev_drv->first_frame = 1;
1081         
1082         return 0;
1083 }
1084  
1085 #ifdef CONFIG_LOGO_LINUX_BMP
1086 static struct linux_logo *bmp_logo;
1087 static int fb_prepare_bmp_logo(struct fb_info *info, int rotate)
1088 {
1089         bmp_logo = fb_find_logo(24);
1090         if (bmp_logo == NULL) {
1091                 printk("%s error\n", __func__);
1092                 return 0;
1093         }
1094         return 1;
1095 }
1096
1097 static void fb_show_bmp_logo(struct fb_info *info, int rotate)
1098 {
1099         unsigned char *src=bmp_logo->data;
1100         unsigned char *dst=info->screen_base;
1101         int i;
1102         unsigned int Needwidth=(*(src-24)<<8)|(*(src-23));
1103         unsigned int Needheight=(*(src-22)<<8)|(*(src-21));
1104                 
1105         for(i=0;i<Needheight;i++)
1106                 memcpy(dst+info->var.xres*i*4, src+bmp_logo->width*i*4, Needwidth*4);
1107         
1108 }
1109 #endif
1110
1111 int rk_fb_register(struct rk_lcdc_device_driver *dev_drv,
1112         struct rk_lcdc_device_driver *def_drv,int id)
1113 {
1114         struct rk_fb_inf *fb_inf = platform_get_drvdata(g_fb_pdev);
1115         struct fb_info *fbi;
1116         int i=0,ret = 0;
1117         int lcdc_id = 0;
1118         if(NULL == dev_drv)
1119         {
1120                 printk("null lcdc device driver?");
1121                 return -ENOENT;
1122         }
1123         for(i=0;i<RK30_MAX_LCDC_SUPPORT;i++)
1124         {
1125                 if(NULL==fb_inf->lcdc_dev_drv[i])
1126                 {
1127                         fb_inf->lcdc_dev_drv[i] = dev_drv;
1128                         fb_inf->lcdc_dev_drv[i]->id = id;
1129                         fb_inf->num_lcdc++;
1130                         break;
1131                 }
1132         }
1133         if(i==RK30_MAX_LCDC_SUPPORT)
1134         {
1135                 printk("rk_fb_register lcdc out of support %d",i);
1136                 return -ENOENT;
1137         }
1138         lcdc_id = i;
1139         init_lcdc_device_driver(dev_drv, def_drv,id);
1140         
1141         dev_drv->init_lcdc(dev_drv);
1142         /************fb set,one layer one fb ***********/
1143         dev_drv->fb_index_base = fb_inf->num_fb;
1144         for(i=0;i<dev_drv->num_layer;i++)
1145         {
1146                 fbi= framebuffer_alloc(0, &g_fb_pdev->dev);
1147                 if(!fbi)
1148                 {
1149                     dev_err(&g_fb_pdev->dev,">> fb framebuffer_alloc fail!");
1150                     fbi = NULL;
1151                     ret = -ENOMEM;
1152                 }
1153                 fbi->par = dev_drv;
1154                 fbi->var = def_var;
1155                 fbi->fix = def_fix;
1156                 sprintf(fbi->fix.id,"fb%d",fb_inf->num_fb);
1157                 fbi->var.xres = fb_inf->lcdc_dev_drv[lcdc_id]->cur_screen->x_res;
1158                 fbi->var.yres = fb_inf->lcdc_dev_drv[lcdc_id]->cur_screen->y_res;
1159                 fbi->var.grayscale |= (fbi->var.xres<<8) + (fbi->var.yres<<20);
1160 #ifdef  CONFIG_LOGO_LINUX_BMP
1161                 fbi->var.bits_per_pixel = 32; 
1162 #else
1163                 fbi->var.bits_per_pixel = 16; 
1164 #endif
1165                 fbi->fix.line_length  = (fbi->var.xres)*(fbi->var.bits_per_pixel>>3);
1166                 fbi->var.xres_virtual = fbi->var.xres;
1167                 fbi->var.yres_virtual = fbi->var.yres;
1168                 fbi->var.width =  fb_inf->lcdc_dev_drv[lcdc_id]->cur_screen->width;
1169                 fbi->var.height = fb_inf->lcdc_dev_drv[lcdc_id]->cur_screen->height;
1170                 fbi->var.pixclock = fb_inf->lcdc_dev_drv[lcdc_id]->pixclock;
1171                 fbi->var.left_margin = fb_inf->lcdc_dev_drv[lcdc_id]->cur_screen->left_margin;
1172                 fbi->var.right_margin = fb_inf->lcdc_dev_drv[lcdc_id]->cur_screen->right_margin;
1173                 fbi->var.upper_margin = fb_inf->lcdc_dev_drv[lcdc_id]->cur_screen->upper_margin;
1174                 fbi->var.lower_margin = fb_inf->lcdc_dev_drv[lcdc_id]->cur_screen->lower_margin;
1175                 fbi->var.vsync_len = fb_inf->lcdc_dev_drv[lcdc_id]->cur_screen->vsync_len;
1176                 fbi->var.hsync_len = fb_inf->lcdc_dev_drv[lcdc_id]->cur_screen->hsync_len;
1177                 fbi->fbops                       = &fb_ops;
1178                 fbi->flags                       = FBINFO_FLAG_DEFAULT;
1179                 fbi->pseudo_palette  = fb_inf->lcdc_dev_drv[lcdc_id]->layer_par[i]->pseudo_pal;
1180                 if (i == 0) //only alloc memory for main fb
1181                 {
1182                         rk_request_fb_buffer(fbi,fb_inf->num_fb);
1183                 }
1184                 ret = register_framebuffer(fbi);
1185                 if(ret<0)
1186                 {
1187                     printk("%s>>fb%d register_framebuffer fail!\n",__func__,fb_inf->num_fb);
1188                     ret = -EINVAL;
1189                 }
1190                 rkfb_create_sysfs(fbi);
1191
1192                 if(i == 0)
1193                 {
1194                         init_waitqueue_head(&dev_drv->vsync_info.wait);
1195                         ret = device_create_file(fbi->dev,&dev_attr_vsync);
1196                         if (ret) 
1197                         {
1198                                 dev_err(fbi->dev, "failed to create vsync file\n");
1199                         }
1200                         dev_drv->vsync_info.thread = kthread_run(rk_fb_wait_for_vsync_thread,
1201                                 dev_drv, "fb-vsync");
1202
1203                         
1204                         if (dev_drv->vsync_info.thread == ERR_PTR(-ENOMEM)) 
1205                         {
1206                                 dev_err(fbi->dev, "failed to run vsync thread\n");
1207                                 dev_drv->vsync_info.thread = NULL;
1208                         }
1209                         dev_drv->vsync_info.active = 1;
1210                 }
1211                 fb_inf->fb[fb_inf->num_fb] = fbi;
1212                 printk("%s>>>>>%s\n",__func__,fb_inf->fb[fb_inf->num_fb]->fix.id);
1213                 fb_inf->num_fb++;       
1214         }
1215 #if !defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_LOGO)
1216     if(dev_drv->screen_ctr_info->prop == PRMRY) //show logo for primary display device
1217     {
1218             fb_inf->fb[0]->fbops->fb_open(fb_inf->fb[0],1);
1219             fb_inf->fb[0]->fbops->fb_set_par(fb_inf->fb[0]);
1220
1221 #if  defined(CONFIG_LOGO_LINUX_BMP)
1222                 if(fb_prepare_bmp_logo(fb_inf->fb[0], FB_ROTATE_UR)) {
1223                         /* Start display and show logo on boot */
1224                         fb_set_cmap(&fb_inf->fb[0]->cmap, fb_inf->fb[0]);
1225                         fb_show_bmp_logo(fb_inf->fb[0], FB_ROTATE_UR);
1226                         fb_inf->fb[0]->fbops->fb_pan_display(&(fb_inf->fb[0]->var), fb_inf->fb[0]);
1227                 }
1228 #else
1229                 if(fb_prepare_logo(fb_inf->fb[0], FB_ROTATE_UR)) {
1230                         /* Start display and show logo on boot */
1231                         fb_set_cmap(&fb_inf->fb[0]->cmap, fb_inf->fb[0]);
1232                         fb_show_logo(fb_inf->fb[0], FB_ROTATE_UR);
1233                         fb_inf->fb[0]->fbops->fb_pan_display(&(fb_inf->fb[0]->var), fb_inf->fb[0]);
1234                 }
1235 #endif
1236                 
1237     }
1238 #endif
1239         return 0;
1240         
1241         
1242 }
1243 int rk_fb_unregister(struct rk_lcdc_device_driver *dev_drv)
1244 {
1245
1246         struct rk_fb_inf *fb_inf = platform_get_drvdata(g_fb_pdev);
1247         struct fb_info *fbi;
1248         int fb_index_base = dev_drv->fb_index_base;
1249         int fb_num = dev_drv->num_layer;
1250         int i=0;
1251         if(NULL == dev_drv)
1252         {
1253                 printk(" no need to unregister null lcdc device driver!\n");
1254                 return -ENOENT;
1255         }
1256
1257         for(i = 0; i < fb_num; i++)
1258         {
1259                 kfree(dev_drv->layer_par[i]);
1260         }
1261
1262         for(i=fb_index_base;i<(fb_index_base+fb_num);i++)
1263         {
1264                 fbi = fb_inf->fb[i];
1265                 unregister_framebuffer(fbi);
1266                 //rk_release_fb_buffer(fbi);
1267                 framebuffer_release(fbi);       
1268         }
1269         fb_inf->lcdc_dev_drv[dev_drv->id]= NULL;
1270         fb_inf->num_lcdc--;
1271
1272         return 0;
1273 }
1274
1275
1276
1277 #ifdef CONFIG_HAS_EARLYSUSPEND
1278 struct suspend_info {
1279         struct early_suspend early_suspend;
1280         struct rk_fb_inf *inf;
1281 };
1282
1283 static void rkfb_early_suspend(struct early_suspend *h)
1284 {
1285         struct suspend_info *info = container_of(h, struct suspend_info,
1286                                                 early_suspend);
1287         struct rk_fb_inf *inf = info->inf;
1288         int i;
1289         for(i = 0; i < inf->num_lcdc; i++)
1290         {
1291                 if (!inf->lcdc_dev_drv[i])
1292                         continue;
1293                         
1294                 inf->lcdc_dev_drv[i]->suspend(inf->lcdc_dev_drv[i]);
1295         }
1296 }
1297 static void rkfb_early_resume(struct early_suspend *h)
1298 {
1299         struct suspend_info *info = container_of(h, struct suspend_info,
1300                                                 early_suspend);
1301         struct rk_fb_inf *inf = info->inf;
1302         int i;
1303         for(i = 0; i < inf->num_lcdc; i++)
1304         {
1305                 if (!inf->lcdc_dev_drv[i])
1306                         continue;
1307                 
1308                 inf->lcdc_dev_drv[i]->resume(inf->lcdc_dev_drv[i]);            // data out
1309         }
1310
1311 }
1312
1313
1314
1315 static struct suspend_info suspend_info = {
1316         .early_suspend.suspend = rkfb_early_suspend,
1317         .early_suspend.resume = rkfb_early_resume,
1318         .early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB,
1319 };
1320 #endif
1321
1322 static int __devinit rk_fb_probe (struct platform_device *pdev)
1323 {
1324         struct rk_fb_inf *fb_inf = NULL;
1325         int ret = 0;
1326         g_fb_pdev=pdev;
1327         /* Malloc rk_fb_inf and set it to pdev for drvdata */
1328         fb_inf = kzalloc(sizeof(struct rk_fb_inf), GFP_KERNEL);
1329         if(!fb_inf)
1330         {
1331                 dev_err(&pdev->dev, ">>fb inf kmalloc fail!");
1332                 ret = -ENOMEM;
1333         }
1334         platform_set_drvdata(pdev,fb_inf);
1335
1336 #ifdef CONFIG_HAS_EARLYSUSPEND
1337         suspend_info.inf = fb_inf;
1338         register_early_suspend(&suspend_info.early_suspend);
1339 #endif
1340         printk("rk fb probe ok!\n");
1341     return 0;
1342 }
1343
1344 static int __devexit rk_fb_remove(struct platform_device *pdev)
1345 {
1346         struct rk_fb_inf *fb_inf = platform_get_drvdata(pdev);
1347         kfree(fb_inf);
1348         platform_set_drvdata(pdev, NULL);
1349         return 0;
1350 }
1351
1352 static void rk_fb_shutdown(struct platform_device *pdev)
1353 {
1354         struct rk_fb_inf *inf = platform_get_drvdata(pdev);
1355         int i;
1356         for(i = 0; i < inf->num_lcdc; i++)
1357         {
1358                 if (!inf->lcdc_dev_drv[i])
1359                         continue;
1360
1361                 if(inf->lcdc_dev_drv[i]->vsync_info.thread)
1362                         kthread_stop(inf->lcdc_dev_drv[i]->vsync_info.thread);
1363         }
1364 //      kfree(fb_inf);
1365 //      platform_set_drvdata(pdev, NULL);
1366 #ifdef CONFIG_HAS_EARLYSUSPEND
1367         unregister_early_suspend(&suspend_info.early_suspend);
1368 #endif
1369 }
1370
1371 static struct platform_driver rk_fb_driver = {
1372         .probe          = rk_fb_probe,
1373         .remove         = __devexit_p(rk_fb_remove),
1374         .driver         = {
1375                 .name   = "rk-fb",
1376                 .owner  = THIS_MODULE,
1377         },
1378         .shutdown   = rk_fb_shutdown,
1379 };
1380
1381 static int __init rk_fb_init(void)
1382 {
1383     return platform_driver_register(&rk_fb_driver);
1384 }
1385
1386 static void __exit rk_fb_exit(void)
1387 {
1388     platform_driver_unregister(&rk_fb_driver);
1389 }
1390
1391 subsys_initcall_sync(rk_fb_init);
1392 module_exit(rk_fb_exit);
1393