Merge branch 'develop-3.0' of ssh://10.10.10.29/rk/kernel into hwg
[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/fb.h>
26 #include <linux/init.h>
27 #include <linux/interrupt.h>
28 #include <linux/platform_device.h>
29 #include <linux/earlysuspend.h>
30 #include <asm/div64.h>
31 #include <asm/uaccess.h>
32 #include <mach/board.h>
33 #include "../display/screen/screen.h"
34 #include<linux/rk_fb.h>
35
36
37 #if 0
38         #define fbprintk(msg...)        printk(msg);
39 #else
40         #define fbprintk(msg...)
41 #endif
42
43 #if 0
44 #define CHK_SUSPEND(inf)        \
45         if(inf->in_suspend)     {       \
46                 fbprintk(">>>>>> fb is in suspend! return! \n");        \
47                 return -EPERM;  \
48         }
49 #else
50 #define CHK_SUSPEND(inf)
51 #endif
52
53 static struct platform_device *g_fb_pdev;
54
55 static struct rk_fb_rgb def_rgb_16 = {
56      red:    { offset: 11, length: 5, },
57      green:  { offset: 5,  length: 6, },
58      blue:   { offset: 0,  length: 5, },
59      transp: { offset: 0,  length: 0, },
60 };
61
62
63 /***************************************************************************
64 fb0-----------lcdc0------------win1  for ui
65 fb1-----------lcdc0------------win0  for video,win0 support 3d display
66 fb2-----------lcdc1------------win1  for ui
67 fb3-----------lcdc1-------------win0 for video ,win0 support 3d display
68
69 defautl:we alloc three buffer,one for fb0 and fb2 display ui,one for ipp rotate
70         fb1 and fb3 are used for video play,the buffer is alloc by android,and
71         pass the phy addr to fix.smem_start by ioctl
72 ****************************************************************************/
73
74 int get_fb_layer_id(struct fb_fix_screeninfo *fix)
75 {
76         int layer_id;
77         if(!strcmp(fix->id,"fb1")||!strcmp(fix->id,"fb3"))
78         {
79                 layer_id = 0;
80         }
81         else if(!strcmp(fix->id,"fb0")||!strcmp(fix->id,"fb2"))
82         {
83                 layer_id = 1;
84         }
85         else
86         {
87                 printk(KERN_ERR "unsupported %s",fix->id);
88                 layer_id = -ENODEV;
89         }
90
91         return layer_id;
92 }
93
94 /**********************************************************************
95 this is for hdmi
96 id: lcdc id ,0 for lcdc0 ,1 for lcdc1
97 ***********************************************************************/
98 struct rk_lcdc_device_driver * rk_get_lcdc_drv(int  id)
99 {
100         struct rk_fb_inf *inf =  platform_get_drvdata(g_fb_pdev);
101         return inf->lcdc_dev_drv[id];
102         
103 }
104 static int rk_fb_open(struct fb_info *info,int user)
105 {
106     struct rk_fb_inf *inf = dev_get_drvdata(info->device);
107     struct rk_lcdc_device_driver *dev_drv = NULL;
108     struct fb_fix_screeninfo *fix = &info->fix;
109     int layer_id;
110     if(!strcmp(fix->id,"fb1")){
111         dev_drv = inf->lcdc_dev_drv[0];
112         layer_id = 0;
113         dev_drv->blank(dev_drv,1,FB_BLANK_NORMAL);  //when open fb1,defautl close fb0 layer win1
114         dev_drv->blank(dev_drv,layer_id,FB_BLANK_UNBLANK); //open fb1 layer win0
115         inf->video_mode = 1;
116     }
117     
118
119     return 0;
120     
121 }
122
123 static int rk_fb_release(struct fb_info *info,int user)
124 {
125     struct rk_fb_inf *inf = dev_get_drvdata(info->device);
126     struct fb_fix_screeninfo *fix = &info->fix;
127     if(!strcmp(fix->id,"fb1")){
128         inf->video_mode = 0;
129     }
130
131     return 0;
132 }
133
134 static int rk_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
135 {
136         struct fb_fix_screeninfo *fix = &info->fix;
137         struct rk_lcdc_device_driver * dev_drv = (struct rk_lcdc_device_driver * )info->par;
138         struct layer_par *par = NULL;
139         int layer_id = 0;
140         u32 xoffset = var->xoffset;             // offset from virtual to visible 
141         u32 yoffset = var->yoffset;                             
142         u32 xvir = var->xres_virtual;
143         u8 data_format = var->nonstd&0xff;
144         layer_id = get_fb_layer_id(fix);
145         if(layer_id < 0)
146         {
147                 return  -ENODEV;
148         }
149         else
150         {
151                  par = &dev_drv->layer_par[layer_id];
152         }
153         switch (par->format)
154         {
155                 case ARGB888:
156                         par->y_offset = (yoffset*xvir + xoffset)*4;
157                         break;
158                 case  RGB888:
159                         par->y_offset = (yoffset*xvir + xoffset)*3;
160                         break;
161                 case RGB565:
162                         par->y_offset = (yoffset*xvir + xoffset)*2;
163                         break;
164                 case  YUV422:
165                         par->y_offset = yoffset*xvir + xoffset;
166                         par->c_offset = par->y_offset;
167                         break;
168                 case  YUV420:
169                         par->y_offset = yoffset*xvir + xoffset;
170                         par->c_offset = (yoffset>>1)*xvir + xoffset;
171                         break;
172                 case  YUV444 : // yuv444
173                         par->y_offset = yoffset*xvir + xoffset;
174                         par->c_offset = yoffset*2*xvir +(xoffset<<1);
175                         break;
176                 default:
177                         printk("un supported format:0x%x\n",data_format);
178                         return -EINVAL;
179         }
180         
181         dev_drv->pan_display(dev_drv,layer_id);
182         
183         return 0;
184 }
185 static int rk_fb_ioctl(struct fb_info *info, unsigned int cmd,unsigned long arg)
186 {
187         struct rk_fb_inf *inf = dev_get_drvdata(info->device);
188         struct fb_fix_screeninfo *fix = &info->fix;
189         struct rk_lcdc_device_driver *dev_drv = (struct rk_lcdc_device_driver * )info->par;
190         u32 yuv_phy[2];
191         void __user *argp = (void __user *)arg;
192         fbprintk(">>>>>> %s : cmd:0x%x \n",__FUNCTION__,cmd);
193         CHK_SUSPEND(inf);
194         
195         switch(cmd)
196         {
197                 case FBIOPUT_FBPHYADD:
198                         return info->fix.smem_start;
199                 case FB1_IOCTL_SET_YUV_ADDR:   //when in video mode, buff alloc by android
200                         if((!strcmp(fix->id,"fb1"))||(!strcmp(fix->id,"fb3")))
201                         {
202                                 if (copy_from_user(yuv_phy, argp, 8))
203                                         return -EFAULT;
204                                 info->fix.smem_start = yuv_phy[0];  //four y
205                                 info->fix.mmio_start = yuv_phy[1];  //four uv
206                         }
207                         break;
208                 case FBIOGET_OVERLAY_STATE:
209                         return inf->video_mode;
210                 case FBIOGET_SCREEN_STATE:
211                 case FBIOPUT_SET_CURSOR_EN:
212                 case FBIOPUT_SET_CURSOR_POS:
213                 case FBIOPUT_SET_CURSOR_IMG:
214                 case FBIOPUT_SET_CURSOR_CMAP:
215                 case FBIOPUT_GET_CURSOR_RESOLUTION:
216                 case FBIOPUT_GET_CURSOR_EN:
217                 case FB0_IOCTL_STOP_TIMER_FLUSH:    //stop timer flush mcu panel after android is runing
218                 case FBIOPUT_16OR32:
219                 case FBIOGET_16OR32:
220                 case FBIOGET_IDLEFBUff_16OR32:
221                 case FBIOSET_COMPOSE_LAYER_COUNTS:
222                 case FBIOGET_COMPOSE_LAYER_COUNTS:
223                 default:
224                         dev_drv->ioctl(dev_drv,cmd,arg,0);
225             break;
226     }
227     return 0;
228 }
229
230 static int rk_fb_blank(int blank_mode, struct fb_info *info)
231 {
232         struct rk_lcdc_device_driver *dev_drv = (struct rk_lcdc_device_driver * )info->par;
233         struct fb_fix_screeninfo *fix = &info->fix;
234         int layer_id;
235         layer_id = get_fb_layer_id(fix);
236         if(layer_id < 0)
237         {
238                 return  -ENODEV;
239         }
240         
241         dev_drv->blank(dev_drv,layer_id,blank_mode);
242
243         return 0;
244 }
245
246 static int rk_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
247 {
248         CHK_SUSPEND(inf);
249  
250          if( 0==var->xres_virtual || 0==var->yres_virtual ||
251                  0==var->xres || 0==var->yres || var->xres<16 ||
252                  ((16!=var->bits_per_pixel)&&(32!=var->bits_per_pixel)) )
253          {
254                  printk(">>>>>> fb_check_var fail 1!!! \n");
255                  printk(">>>>>> 0==%d || 0==%d ", var->xres_virtual,var->yres_virtual);
256                  printk("0==%d || 0==%d || %d<16 || ", var->xres,var->yres,var->xres<16);
257                  printk("bits_per_pixel=%d \n", var->bits_per_pixel);
258                  return -EINVAL;
259          }
260  
261          if( (var->xoffset+var->xres)>var->xres_virtual ||
262                  (var->yoffset+var->yres)>var->yres_virtual*2 )
263          {
264                  printk(">>>>>> fb_check_var fail 2!!! \n");
265                  printk(">>>>>> (%d+%d)>%d || ", var->xoffset,var->xres,var->xres_virtual);
266                  printk("(%d+%d)>%d || ", var->yoffset,var->yres,var->yres_virtual);
267                  return -EINVAL;
268          }
269
270  
271     switch(var->nonstd&0x0f)
272     {
273         case 0: // rgb
274             switch(var->bits_per_pixel)
275             {
276             case 16:    // rgb565
277                 var->xres_virtual = (var->xres_virtual + 0x1) & (~0x1);
278                 var->xres = (var->xres + 0x1) & (~0x1);
279                 var->xoffset = (var->xoffset) & (~0x1);
280                 break;
281             default:    // rgb888
282                 var->bits_per_pixel = 32;
283                 break;
284             }
285             var->nonstd &= ~0xc0;  //not support I2P in this format
286             break;
287         case 1: // yuv422
288             var->xres_virtual = (var->xres_virtual + 0x3) & (~0x3);
289             var->xres = (var->xres + 0x3) & (~0x3);
290             var->xoffset = (var->xoffset) & (~0x3);
291             break;
292         case 2: // yuv4200
293             var->xres_virtual = (var->xres_virtual + 0x3) & (~0x3);
294             var->yres_virtual = (var->yres_virtual + 0x1) & (~0x1);
295             var->xres = (var->xres + 0x3) & (~0x3);
296             var->yres = (var->yres + 0x1) & (~0x1);
297             var->xoffset = (var->xoffset) & (~0x3);
298             var->yoffset = (var->yoffset) & (~0x1);
299             break;
300         case 3: // yuv4201
301             var->xres_virtual = (var->xres_virtual + 0x3) & (~0x3);
302             var->yres_virtual = (var->yres_virtual + 0x1) & (~0x1);
303             var->xres = (var->xres + 0x3) & (~0x3);
304             var->yres = (var->yres + 0x1) & (~0x1);
305             var->xoffset = (var->xoffset) & (~0x3);
306             var->yoffset = (var->yoffset) & (~0x1);
307             var->nonstd &= ~0xc0;   //not support I2P in this format
308             break;
309         case 4: // none
310         case 5: // yuv444
311             var->xres_virtual = (var->xres_virtual + 0x3) & (~0x3);
312             var->xres = (var->xres + 0x3) & (~0x3);
313             var->xoffset = (var->xoffset) & (~0x3);
314             var->nonstd &= ~0xc0;   //not support I2P in this format
315             break;
316         default:
317             printk(">>>>>> fb1 var->nonstd=%d is invalid! \n", var->nonstd);
318             return -EINVAL;
319         }
320          
321     return 0;
322 }
323
324
325 static int rk_fb_set_par(struct fb_info *info)
326 {
327     struct fb_var_screeninfo *var = &info->var;
328     struct fb_fix_screeninfo *fix = &info->fix;
329     struct rk_lcdc_device_driver * dev_drv = (struct rk_lcdc_device_driver * )info->par;
330     struct layer_par *par = NULL;
331     rk_screen *screen =dev_drv->screen;
332     int layer_id = 0;   
333     u32 cblen = 0,crlen = 0;
334     u16 xsize =0,ysize = 0;              //winx display window height/width --->LCDC_WINx_DSP_INFO
335     u32 xoffset = var->xoffset;                 // offset from virtual to visible 
336     u32 yoffset = var->yoffset;                 //resolution                    
337     u16 xpos = (var->nonstd>>8) & 0xfff; //visiable pos in panel
338     u16 ypos = (var->nonstd>>20) & 0xfff;
339     u32 xvir = var->xres_virtual;
340     u32 yvir = var->yres_virtual;
341     u8 data_format = var->nonstd&0xff;
342
343     layer_id = get_fb_layer_id(fix);
344     if(layer_id < 0)
345     {
346         return  -ENODEV;
347     }
348     else
349     {
350         par = &dev_drv->layer_par[layer_id];
351     }
352     if((!strcmp(fix->id,"fb0"))||(!strcmp(fix->id,"fb2")))  //four ui
353     {
354         xsize = screen->x_res;
355         ysize = screen->y_res;
356     }
357     else if((!strcmp(fix->id,"fb1"))||(!strcmp(fix->id,"fb3")))
358     {
359         xsize = (var->grayscale>>8) & 0xfff;  //visiable size in panel ,for vide0
360         ysize = (var->grayscale>>20) & 0xfff;
361     }
362         CHK_SUSPEND(inf);
363         /* calculate y_offset,c_offset,line_length,cblen and crlen  */
364 #if 1
365     switch (data_format)
366     {
367         case HAL_PIXEL_FORMAT_RGBA_8888 :      // rgb
368         case HAL_PIXEL_FORMAT_RGBX_8888: 
369                 par->format = ARGB888;
370                 fix->line_length = 4 * xvir;
371                 par->y_offset = (yoffset*xvir + xoffset)*4;
372                 break;
373         case HAL_PIXEL_FORMAT_RGB_888 :
374                 par->format = RGB888;
375                 fix->line_length = 3 * xvir;
376                 par->y_offset = (yoffset*xvir + xoffset)*3;
377                 break;
378         case HAL_PIXEL_FORMAT_RGB_565:  //RGB565
379                 par->format = RGB565;
380                 fix->line_length = 2 * xvir;
381                 par->y_offset = (yoffset*xvir + xoffset)*2;
382                 break;
383         case HAL_PIXEL_FORMAT_YCbCr_422_SP : // yuv422
384                 par->format = YUV422;
385                 fix->line_length = xvir;
386                 cblen = crlen = (xvir*yvir)>>1;
387                 par->y_offset = yoffset*xvir + xoffset;
388                 par->c_offset = par->y_offset;
389                 break;
390         case HAL_PIXEL_FORMAT_YCrCb_NV12   : // YUV420---uvuvuv
391                 par->format = YUV420;
392                 fix->line_length = xvir;
393                 cblen = crlen = (xvir*yvir)>>2;
394                 par->y_offset = yoffset*xvir + xoffset;
395                 par->c_offset = (yoffset>>1)*xvir + xoffset;
396                 break;
397         case HAL_PIXEL_FORMAT_YCrCb_444 : // yuv444
398                 par->format = 5;
399                 fix->line_length = xvir<<2;
400                 par->y_offset = yoffset*xvir + xoffset;
401                 par->c_offset = yoffset*2*xvir +(xoffset<<1);
402                 cblen = crlen = (xvir*yvir);
403                 break;
404         default:
405                 printk("un supported format:0x%x\n",data_format);
406             return -EINVAL;
407     }
408 #else
409         switch(var->bits_per_pixel)
410         {
411                 case 32:
412                         par->format = ARGB888;
413                         fix->line_length = 4 * xvir;
414                         par->y_offset = (yoffset*xvir + xoffset)*4;
415                         break;
416                 case 16:
417                         par->format = RGB565;
418                         fix->line_length = 2 * xvir;
419                         par->y_offset = (yoffset*xvir + xoffset)*2;
420                         break;
421                         
422         }
423 #endif
424
425     par->xpos = xpos;
426     par->ypos = ypos;
427     par->xsize = xsize;
428     par->ysize = ysize;
429     
430     par->smem_start =fix->smem_start;
431     par->cbr_start = fix->mmio_start;
432     par->xact = var->xres;              //winx active window height,is a part of vir
433     par->yact = var->yres;
434     par->xvir =  var->xres_virtual;             // virtual resolution    stride --->LCDC_WINx_VIR
435     par->yvir =  var->yres_virtual;
436     dev_drv->set_par(dev_drv,layer_id);
437     
438         return 0;
439 }
440
441 static inline unsigned int chan_to_field(unsigned int chan,
442                                          struct fb_bitfield *bf)
443 {
444         chan &= 0xffff;
445         chan >>= 16 - bf->length;
446         return chan << bf->offset;
447 }
448
449 static int fb_setcolreg(unsigned regno,
450                                unsigned red, unsigned green, unsigned blue,
451                                unsigned transp, struct fb_info *info)
452 {
453         unsigned int val;
454
455         switch (info->fix.visual) {
456         case FB_VISUAL_TRUECOLOR:
457                 /* true-colour, use pseudo-palette */
458                 if (regno < 16) {
459                         u32 *pal = info->pseudo_palette;
460                         val  = chan_to_field(red,   &info->var.red);
461                         val |= chan_to_field(green, &info->var.green);
462                         val |= chan_to_field(blue,  &info->var.blue);
463                         pal[regno] = val;
464                 }
465                 break;
466         default:
467                 return -1;      /* unknown type */
468         }
469
470         return 0;
471 }
472
473 static struct fb_ops fb_ops = {
474     .owner          = THIS_MODULE,
475     .fb_open        = rk_fb_open,
476     .fb_release     = rk_fb_release,
477     .fb_check_var   = rk_fb_check_var,
478     .fb_set_par     = rk_fb_set_par,
479     .fb_blank       = rk_fb_blank,
480     .fb_ioctl       = rk_fb_ioctl,
481     .fb_pan_display = rk_pan_display,
482     .fb_setcolreg   = fb_setcolreg,
483     .fb_fillrect    = cfb_fillrect,
484     .fb_copyarea    = cfb_copyarea,
485     .fb_imageblit   = cfb_imageblit,
486 };
487
488
489
490 static struct fb_var_screeninfo def_var = {
491     .red    = {11,5,0},//default set to rgb565,the boot logo is rgb565
492     .green  = {5,6,0},
493     .blue   = {0,5,0},
494     .transp = {0,0,0},  
495     .nonstd      = HAL_PIXEL_FORMAT_RGB_565,   //(ypos<<20+xpos<<8+format) format
496     .grayscale   = 0,  //(ysize<<20+xsize<<8)
497     .activate    = FB_ACTIVATE_NOW,
498     .accel_flags = 0,
499     .vmode       = FB_VMODE_NONINTERLACED,
500 };
501
502 static struct fb_fix_screeninfo def_fix = {
503         .type            = FB_TYPE_PACKED_PIXELS,
504         .type_aux        = 0,
505         .xpanstep        = 1,
506         .ypanstep        = 1,
507         .ywrapstep       = 0,
508         .accel           = FB_ACCEL_NONE,
509         .visual          = FB_VISUAL_TRUECOLOR,
510                 
511 };
512
513
514 /*****************************************************************
515 this two function is for other module that in the kernel which
516 need show image directly through fb
517 fb_id:we have 4 fb here,default we use fb0 for ui display
518 *******************************************************************/
519 struct fb_info * rk_get_fb(int fb_id)
520 {
521     struct rk_fb_inf *inf =  platform_get_drvdata(g_fb_pdev);
522     struct fb_info *fb = inf->fb[fb_id];
523     return fb;
524 }
525 EXPORT_SYMBOL(rk_get_fb);
526
527 void rk_direct_fb_show(struct fb_info * fbi)
528 {
529     rk_fb_set_par(fbi);
530     rk_pan_display(&fbi->var, fbi);
531 }
532 EXPORT_SYMBOL(rk_direct_fb_show);
533
534 static int rk_request_fb_buffer(struct fb_info *fbi,int fb_id)
535 {
536         struct resource *res;
537         struct resource *mem;
538         int ret = 0;
539         switch(fb_id)
540         {
541                 case 0:
542                         res = platform_get_resource_byname(g_fb_pdev, IORESOURCE_MEM, "fb0 buf");
543                         if (res == NULL)
544                         {
545                                 dev_err(&g_fb_pdev->dev, "failed to get win0 memory \n");
546                                 ret = -ENOENT;
547                         }
548                         fbi->fix.smem_start = res->start;
549                         fbi->fix.smem_len = res->end - res->start + 1;
550                         mem = request_mem_region(res->start, resource_size(res), g_fb_pdev->name);
551                         fbi->screen_base = ioremap(res->start, fbi->fix.smem_len);
552                         memset(fbi->screen_base, 0, fbi->fix.smem_len);
553                         printk("fb%d:phy:%lx>>vir:%p>>len:0x%x\n",fb_id,
554                                 fbi->fix.smem_start,fbi->screen_base,fbi->fix.smem_len);
555                 #ifdef CONFIG_FB_WORK_IPP // alloc ipp buf for rotate
556                         res = platform_get_resource_byname(g_fb_pdev, IORESOURCE_MEM, "ipp buf");
557                         if (res == NULL)
558                         {
559                                 dev_err(&g_fb_pdev->dev, "failed to get win1 ipp memory \n");
560                                 ret = -ENOENT;
561                         }
562                         fbi->fix.mmio_start = res->start;
563                         fbi->fix.mmio_len = res->end - res->start + 1;
564                 #endif
565                         break;
566                 case 2:
567                         res = platform_get_resource_byname(g_fb_pdev, IORESOURCE_MEM, "fb2 buf");
568                         if (res == NULL)
569                         {
570                         dev_err(&g_fb_pdev->dev, "failed to get win0 memory \n");
571                         ret = -ENOENT;
572                         }
573                         fbi->fix.smem_start = res->start;
574                         fbi->fix.smem_len = res->end - res->start + 1;
575                         mem = request_mem_region(res->start, resource_size(res), g_fb_pdev->name);
576                         fbi->screen_base = ioremap(res->start, fbi->fix.smem_len);
577                         memset(fbi->screen_base, 0, fbi->fix.smem_len);
578                         printk("fb%d:phy:%lx>>vir:%p>>len:0x%x\n",fb_id,
579                                 fbi->fix.smem_start,fbi->screen_base,fbi->fix.smem_len);
580                         break;
581                 default:
582                         ret = -EINVAL;
583                         break;          
584         }
585     return ret;
586 }
587
588 static int rk_release_fb_buffer(struct fb_info *fbi)
589 {
590         if(!fbi)
591         {
592                 printk("no need release null fb buffer!\n");
593                 return -EINVAL;
594         }
595         if(!strcmp(fbi->fix.id,"fb1")||!strcmp(fbi->fix.id,"fb3"))  //buffer for fb1 and fb3 are alloc by android
596                 return 0;
597         iounmap(fbi->screen_base);
598         release_mem_region(fbi->fix.smem_start,fbi->fix.smem_len);
599         return 0;
600         
601 }
602 int rk_fb_register(struct rk_lcdc_device_driver *dev_drv)
603 {
604         struct rk_fb_inf *fb_inf = platform_get_drvdata(g_fb_pdev);
605         struct fb_info *fbi;
606         int i=0,ret = 0;
607         int lcdc_id = 0;
608         if(NULL == dev_drv)
609         {
610                 printk("null lcdc device driver?");
611                 return -ENOENT;
612         }
613         for(i=0;i<RK30_MAX_LCDC_SUPPORT;i++)
614         {
615                 if(NULL==fb_inf->lcdc_dev_drv[i])
616                 {
617                         fb_inf->lcdc_dev_drv[i] = dev_drv;
618                         fb_inf->lcdc_dev_drv[i]->id = i;
619                         fb_inf->num_lcdc++;
620                         break;
621                 }
622         }
623         if(i==RK30_MAX_LCDC_SUPPORT)
624         {
625                 printk("rk_fb_register lcdc out of support %d",i);
626                 return -ENOENT;
627         }
628         lcdc_id = i;
629         
630         /************fb set,one layer one fb ***********/
631         dev_drv->fb_index_base = fb_inf->num_fb;
632     for(i=0;i<dev_drv->num_layer;i++)
633     {
634         fbi= framebuffer_alloc(0, &g_fb_pdev->dev);
635         if(!fbi)
636         {
637             dev_err(&g_fb_pdev->dev,">> fb framebuffer_alloc fail!");
638             fbi = NULL;
639             ret = -ENOMEM;
640         }
641         fbi->par = dev_drv;
642         fbi->var = def_var;
643         fbi->fix = def_fix;
644         sprintf(fbi->fix.id,"fb%d",fb_inf->num_fb);
645         fbi->var.xres = fb_inf->lcdc_dev_drv[lcdc_id]->screen->x_res;
646         fbi->var.yres = fb_inf->lcdc_dev_drv[lcdc_id]->screen->y_res;
647         fbi->var.bits_per_pixel = 16;
648         fbi->var.xres_virtual = fb_inf->lcdc_dev_drv[lcdc_id]->screen->x_res;
649         fbi->var.yres_virtual = fb_inf->lcdc_dev_drv[lcdc_id]->screen->y_res;
650         fbi->var.width = fb_inf->lcdc_dev_drv[lcdc_id]->screen->width;
651         fbi->var.height = fb_inf->lcdc_dev_drv[lcdc_id]->screen->height;
652         fbi->var.pixclock =fb_inf->lcdc_dev_drv[lcdc_id]->pixclock;
653         fbi->var.left_margin = fb_inf->lcdc_dev_drv[lcdc_id]->screen->left_margin;
654         fbi->var.right_margin = fb_inf->lcdc_dev_drv[lcdc_id]->screen->right_margin;
655         fbi->var.upper_margin = fb_inf->lcdc_dev_drv[lcdc_id]->screen->upper_margin;
656         fbi->var.lower_margin = fb_inf->lcdc_dev_drv[lcdc_id]->screen->lower_margin;
657         fbi->var.vsync_len = fb_inf->lcdc_dev_drv[lcdc_id]->screen->vsync_len;
658         fbi->var.hsync_len = fb_inf->lcdc_dev_drv[lcdc_id]->screen->hsync_len;
659         fbi->fbops                       = &fb_ops;
660         fbi->flags                       = FBINFO_FLAG_DEFAULT;
661         fbi->pseudo_palette  = fb_inf->lcdc_dev_drv[lcdc_id]->layer_par[i].pseudo_pal;
662         rk_request_fb_buffer(fbi,fb_inf->num_fb);
663         ret = register_framebuffer(fbi);
664         if(ret<0)
665         {
666             printk("%s>>fb%d register_framebuffer fail!\n",__func__,fb_inf->num_fb);
667             ret = -EINVAL;
668         }
669         rkfb_create_sysfs(fbi);
670         fb_inf->fb[fb_inf->num_fb] = fbi;
671         printk("%s>>>>>%s\n",__func__,fb_inf->fb[fb_inf->num_fb]->fix.id);
672         fb_inf->num_fb++;       
673         }
674 #if !defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_LOGO)
675     fb_inf->fb[fb_inf->num_fb-2]->fbops->fb_set_par(fb_inf->fb[fb_inf->num_fb-2]);
676     if(fb_prepare_logo(fb_inf->fb[fb_inf->num_fb-2], FB_ROTATE_UR)) {
677         /* Start display and show logo on boot */
678         fb_set_cmap(&fb_inf->fb[fb_inf->num_fb-2]->cmap, fb_inf->fb[fb_inf->num_fb-2]);
679         fb_show_logo(fb_inf->fb[fb_inf->num_fb-2], FB_ROTATE_UR);
680         fb_inf->fb[fb_inf->num_fb-2]->fbops->fb_blank(FB_BLANK_UNBLANK, fb_inf->fb[fb_inf->num_fb-2]);
681         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]);
682     }
683 #endif
684         return 0;
685         
686         
687 }
688 int rk_fb_unregister(struct rk_lcdc_device_driver *dev_drv)
689 {
690
691         struct rk_fb_inf *fb_inf = platform_get_drvdata(g_fb_pdev);
692         struct fb_info *fbi;
693         int fb_index_base = dev_drv->fb_index_base;
694         int fb_num = dev_drv->num_layer;
695         int i=0;
696         if(NULL == dev_drv)
697         {
698                 printk(" no need to unregister null lcdc device driver!\n");
699                 return -ENOENT;
700         }
701
702         for(i=fb_index_base;i<(fb_index_base+fb_num);i++)
703         {
704                 fbi = fb_inf->fb[i];
705                 unregister_framebuffer(fbi);
706                 rk_release_fb_buffer(fbi);
707                 framebuffer_release(fbi);       
708         }
709         fb_inf->lcdc_dev_drv[dev_drv->id]= NULL;
710
711         return 0;
712 }
713
714 int init_lcdc_device_driver(struct rk_lcdc_device_driver *def_drv,
715         struct rk_lcdc_device_driver *dev_drv,int id)
716 {
717         if(!def_drv)
718         {
719                 printk(KERN_ERR "default lcdc device driver is null!\n");
720                 return -EINVAL;
721         }
722         if(!dev_drv)
723         {
724                 printk(KERN_ERR "lcdc device driver is null!\n");
725                 return -EINVAL; 
726         }
727         sprintf(dev_drv->name, "lcdc%d",id);
728         dev_drv->layer_par = def_drv->layer_par;
729         dev_drv->num_layer = def_drv->num_layer;
730         dev_drv->ioctl = def_drv->ioctl;
731         dev_drv->blank = def_drv->blank;
732         dev_drv->set_par = def_drv->set_par;
733         dev_drv->pan_display = def_drv->pan_display;
734         dev_drv->suspend = def_drv->suspend;
735         dev_drv->resume = def_drv->resume;
736         dev_drv->load_screen = dev_drv->load_screen;
737         
738         return 0;
739 }
740 static int __devinit rk_fb_probe (struct platform_device *pdev)
741 {
742         struct rk_fb_inf *fb_inf = NULL;
743         struct rk29lcd_info *lcd_info = NULL;
744         int ret = 0;
745         g_fb_pdev=pdev;
746         lcd_info =  pdev->dev.platform_data;
747         /* Malloc rk_fb_inf and set it to pdev for drvdata */
748         fb_inf = kzalloc(sizeof(struct rk_fb_inf), GFP_KERNEL);
749         if(!fb_inf)
750         {
751                 dev_err(&pdev->dev, ">>fb inf kmalloc fail!");
752                 ret = -ENOMEM;
753         }
754         platform_set_drvdata(pdev,fb_inf);
755         if(lcd_info->io_init)
756                 lcd_info->io_init();
757         printk("rk fb probe ok!\n");
758     return 0;
759 }
760
761 static int __devexit rk_fb_remove(struct platform_device *pdev)
762 {
763         struct rk_fb_inf *fb_inf = platform_get_drvdata(pdev);
764         kfree(fb_inf);
765         platform_set_drvdata(pdev, NULL);
766         return 0;
767 }
768
769 static void rk_fb_shutdown(struct platform_device *pdev)
770 {
771         struct rk_fb_inf *fb_inf = platform_get_drvdata(pdev);
772         kfree(fb_inf);
773         platform_set_drvdata(pdev, NULL);
774 }
775
776 static struct platform_driver rk_fb_driver = {
777         .probe          = rk_fb_probe,
778         .remove         = __devexit_p(rk_fb_remove),
779         .driver         = {
780                 .name   = "rk-fb",
781                 .owner  = THIS_MODULE,
782         },
783         .shutdown   = rk_fb_shutdown,
784 };
785
786 static int __init rk_fb_init(void)
787 {
788     return platform_driver_register(&rk_fb_driver);
789 }
790
791 static void __exit rk_fb_exit(void)
792 {
793     platform_driver_unregister(&rk_fb_driver);
794 }
795
796 fs_initcall(rk_fb_init);
797 module_exit(rk_fb_exit);
798