52d27971dbd9b4f4118b6c0bf6e1d27a68bb1ab3
[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/platform_device.h>
28 #include <linux/earlysuspend.h>
29 #include <asm/div64.h>
30 #include <asm/uaccess.h>
31 #include<linux/rk_fb.h>
32
33
34 #if 0
35         #define fbprintk(msg...)        printk(msg);
36 #else
37         #define fbprintk(msg...)
38 #endif
39
40 #if 1
41 #define CHK_SUSPEND(drv)        \
42         if(atomic_dec_and_test(&drv->in_suspend))       {       \
43                 printk(">>>>>> fb is in suspend! return! \n");  \
44                 return -EPERM;  \
45         }
46 #else
47 #define CHK_SUSPEND(inf)
48 #endif
49
50 static struct platform_device *g_fb_pdev;
51
52 static struct rk_fb_rgb def_rgb_16 = {
53      red:    { offset: 11, length: 5, },
54      green:  { offset: 5,  length: 6, },
55      blue:   { offset: 0,  length: 5, },
56      transp: { offset: 0,  length: 0, },
57 };
58
59
60 /***************************************************************************
61 fb0-----------lcdc0------------win1  for ui
62 fb1-----------lcdc0------------win0  for video,win0 support 3d display
63 fb2-----------lcdc1------------win1  for ui
64 fb3-----------lcdc1-------------win0 for video ,win0 support 3d display
65
66 defautl:we alloc three buffer,one for fb0 and fb2 display ui,one for ipp rotate
67         fb1 and fb3 are used for video play,the buffer is alloc by android,and
68         pass the phy addr to fix.smem_start by ioctl
69 ****************************************************************************/
70
71 int get_fb_layer_id(struct fb_fix_screeninfo *fix)
72 {
73         int layer_id;
74         if(!strcmp(fix->id,"fb1")||!strcmp(fix->id,"fb3"))
75         {
76                 layer_id = 0;
77         }
78         else if(!strcmp(fix->id,"fb0")||!strcmp(fix->id,"fb2"))
79         {
80                 layer_id = 1;
81         }
82         else
83         {
84                 printk(KERN_ERR "unsupported %s",fix->id);
85                 layer_id = -ENODEV;
86         }
87
88         return layer_id;
89 }
90
91 /**********************************************************************
92 this is for hdmi
93 name: lcdc device name ,lcdc0 , lcdc1
94 ***********************************************************************/
95 struct rk_lcdc_device_driver * rk_get_lcdc_drv(char *name)
96 {
97         struct rk_fb_inf *inf =  platform_get_drvdata(g_fb_pdev);
98         int i = 0;
99         for( i = 0; i < inf->num_lcdc; i++)
100         {
101                 if(!strcmp(inf->lcdc_dev_drv[i]->name,name))
102                         break;
103         }
104         return inf->lcdc_dev_drv[i];
105         
106 }
107 static int rk_fb_open(struct fb_info *info,int user)
108 {
109     struct rk_lcdc_device_driver * dev_drv = (struct rk_lcdc_device_driver * )info->par;
110     int layer_id;
111     CHK_SUSPEND(dev_drv);
112     layer_id = get_fb_layer_id(&info->fix);
113     dev_drv->open(dev_drv,layer_id,1);
114     
115     return 0;
116     
117 }
118
119 static int rk_fb_close(struct fb_info *info,int user)
120 {
121         struct rk_lcdc_device_driver * dev_drv = (struct rk_lcdc_device_driver * )info->par;
122         int layer_id;
123         CHK_SUSPEND(dev_drv);
124         layer_id = get_fb_layer_id(&info->fix);
125         dev_drv->open(dev_drv,layer_id,0);
126         
127         return 0;
128 }
129
130 static int rk_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
131 {
132         struct fb_fix_screeninfo *fix = &info->fix;
133         struct rk_lcdc_device_driver * dev_drv = (struct rk_lcdc_device_driver * )info->par;
134         struct layer_par *par = NULL;
135         int layer_id = 0;
136         u32 xoffset = var->xoffset;             // offset from virtual to visible 
137         u32 yoffset = var->yoffset;                             
138         u32 xvir = var->xres_virtual;
139         u8 data_format = var->nonstd&0xff;
140         layer_id = get_fb_layer_id(fix);
141         CHK_SUSPEND(dev_drv);
142         if(layer_id < 0)
143         {
144                 return  -ENODEV;
145         }
146         else
147         {
148                  par = &dev_drv->layer_par[layer_id];
149         }
150         switch (par->format)
151         {
152                 case ARGB888:
153                         par->y_offset = (yoffset*xvir + xoffset)*4;
154                         break;
155                 case  RGB888:
156                         par->y_offset = (yoffset*xvir + xoffset)*3;
157                         break;
158                 case RGB565:
159                         par->y_offset = (yoffset*xvir + xoffset)*2;
160                         break;
161                 case  YUV422:
162                         par->y_offset = yoffset*xvir + xoffset;
163                         par->c_offset = par->y_offset;
164                         break;
165                 case  YUV420:
166                         par->y_offset = yoffset*xvir + xoffset;
167                         par->c_offset = (yoffset>>1)*xvir + xoffset;
168                         break;
169                 case  YUV444 : // yuv444
170                         par->y_offset = yoffset*xvir + xoffset;
171                         par->c_offset = yoffset*2*xvir +(xoffset<<1);
172                         break;
173                 default:
174                         printk("un supported format:0x%x\n",data_format);
175                         return -EINVAL;
176         }
177         
178         dev_drv->pan_display(dev_drv,layer_id);
179         
180         return 0;
181 }
182 static int rk_fb_ioctl(struct fb_info *info, unsigned int cmd,unsigned long arg)
183 {
184         struct rk_fb_inf *inf = dev_get_drvdata(info->device);
185         struct fb_fix_screeninfo *fix = &info->fix;
186         struct rk_lcdc_device_driver *dev_drv = (struct rk_lcdc_device_driver * )info->par;
187         u32 yuv_phy[2];
188         void __user *argp = (void __user *)arg;
189         fbprintk(">>>>>> %s : cmd:0x%x \n",__FUNCTION__,cmd);
190         
191         CHK_SUSPEND(dev_drv);
192         switch(cmd)
193         {
194                 case FBIOPUT_FBPHYADD:
195                         return info->fix.smem_start;
196                 case FB1_IOCTL_SET_YUV_ADDR:   //when in video mode, buff alloc by android
197                         if((!strcmp(fix->id,"fb1"))||(!strcmp(fix->id,"fb3")))
198                         {
199                                 if (copy_from_user(yuv_phy, argp, 8))
200                                         return -EFAULT;
201                                 info->fix.smem_start = yuv_phy[0];  //four y
202                                 info->fix.mmio_start = yuv_phy[1];  //four uv
203                         }
204                         break;
205                 case FBIOGET_OVERLAY_STATE:
206                         return inf->video_mode;
207                 case FBIOGET_SCREEN_STATE:
208                 case FBIOPUT_SET_CURSOR_EN:
209                 case FBIOPUT_SET_CURSOR_POS:
210                 case FBIOPUT_SET_CURSOR_IMG:
211                 case FBIOPUT_SET_CURSOR_CMAP:
212                 case FBIOPUT_GET_CURSOR_RESOLUTION:
213                 case FBIOPUT_GET_CURSOR_EN:
214                 case FB0_IOCTL_STOP_TIMER_FLUSH:    //stop timer flush mcu panel after android is runing
215                 case FBIOPUT_16OR32:
216                 case FBIOGET_16OR32:
217                 case FBIOGET_IDLEFBUff_16OR32:
218                 case FBIOSET_COMPOSE_LAYER_COUNTS:
219                 case FBIOGET_COMPOSE_LAYER_COUNTS:
220                 default:
221                         dev_drv->ioctl(dev_drv,cmd,arg,0);
222             break;
223     }
224     return 0;
225 }
226
227 static int rk_fb_blank(int blank_mode, struct fb_info *info)
228 {
229         struct rk_lcdc_device_driver *dev_drv = (struct rk_lcdc_device_driver * )info->par;
230         struct fb_fix_screeninfo *fix = &info->fix;
231         int layer_id;
232         CHK_SUSPEND(dev_drv);
233         layer_id = get_fb_layer_id(fix);
234         if(layer_id < 0)
235         {
236                 return  -ENODEV;
237         }
238         
239         dev_drv->blank(dev_drv,layer_id,blank_mode);
240
241         return 0;
242 }
243
244 static int rk_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
245 {
246         struct rk_lcdc_device_driver *dev_drv = (struct rk_lcdc_device_driver * )info->par;
247         CHK_SUSPEND(dev_drv);
248  
249          if( 0==var->xres_virtual || 0==var->yres_virtual ||
250                  0==var->xres || 0==var->yres || var->xres<16 ||
251                  ((16!=var->bits_per_pixel)&&(32!=var->bits_per_pixel)) )
252          {
253                  printk(">>>>>> fb_check_var fail 1!!! \n");
254                  printk(">>>>>> 0==%d || 0==%d ", var->xres_virtual,var->yres_virtual);
255                  printk("0==%d || 0==%d || %d<16 || ", var->xres,var->yres,var->xres<16);
256                  printk("bits_per_pixel=%d \n", var->bits_per_pixel);
257                  return -EINVAL;
258          }
259  
260          if( (var->xoffset+var->xres)>var->xres_virtual ||
261                  (var->yoffset+var->yres)>var->yres_virtual*2 )
262          {
263                  printk(">>>>>> fb_check_var fail 2!!! \n");
264                  printk(">>>>>> (%d+%d)>%d || ", var->xoffset,var->xres,var->xres_virtual);
265                  printk("(%d+%d)>%d || ", var->yoffset,var->yres,var->yres_virtual);
266                  return -EINVAL;
267          }
268
269  
270     switch(var->nonstd&0x0f)
271     {
272         case 0: // rgb
273             switch(var->bits_per_pixel)
274             {
275             case 16:    // rgb565
276                 var->xres_virtual = (var->xres_virtual + 0x1) & (~0x1);
277                 var->xres = (var->xres + 0x1) & (~0x1);
278                 var->xoffset = (var->xoffset) & (~0x1);
279                 break;
280             default:    // rgb888
281                 var->bits_per_pixel = 32;
282                 break;
283             }
284             var->nonstd &= ~0xc0;  //not support I2P in this format
285             break;
286         case 1: // yuv422
287             var->xres_virtual = (var->xres_virtual + 0x3) & (~0x3);
288             var->xres = (var->xres + 0x3) & (~0x3);
289             var->xoffset = (var->xoffset) & (~0x3);
290             break;
291         case 2: // yuv4200
292             var->xres_virtual = (var->xres_virtual + 0x3) & (~0x3);
293             var->yres_virtual = (var->yres_virtual + 0x1) & (~0x1);
294             var->xres = (var->xres + 0x3) & (~0x3);
295             var->yres = (var->yres + 0x1) & (~0x1);
296             var->xoffset = (var->xoffset) & (~0x3);
297             var->yoffset = (var->yoffset) & (~0x1);
298             break;
299         case 3: // yuv4201
300             var->xres_virtual = (var->xres_virtual + 0x3) & (~0x3);
301             var->yres_virtual = (var->yres_virtual + 0x1) & (~0x1);
302             var->xres = (var->xres + 0x3) & (~0x3);
303             var->yres = (var->yres + 0x1) & (~0x1);
304             var->xoffset = (var->xoffset) & (~0x3);
305             var->yoffset = (var->yoffset) & (~0x1);
306             var->nonstd &= ~0xc0;   //not support I2P in this format
307             break;
308         case 4: // none
309         case 5: // yuv444
310             var->xres_virtual = (var->xres_virtual + 0x3) & (~0x3);
311             var->xres = (var->xres + 0x3) & (~0x3);
312             var->xoffset = (var->xoffset) & (~0x3);
313             var->nonstd &= ~0xc0;   //not support I2P in this format
314             break;
315         default:
316             printk(">>>>>> fb1 var->nonstd=%d is invalid! \n", var->nonstd);
317             return -EINVAL;
318         }
319          
320     return 0;
321 }
322
323
324 static int rk_fb_set_par(struct fb_info *info)
325 {
326     struct fb_var_screeninfo *var = &info->var;
327     struct fb_fix_screeninfo *fix = &info->fix;
328     struct rk_lcdc_device_driver * dev_drv = (struct rk_lcdc_device_driver * )info->par;
329     struct layer_par *par = NULL;
330     rk_screen *screen =dev_drv->screen;
331     int layer_id = 0;   
332     u32 cblen = 0,crlen = 0;
333     u16 xsize =0,ysize = 0;              //winx display window height/width --->LCDC_WINx_DSP_INFO
334     u32 xoffset = var->xoffset;                 // offset from virtual to visible 
335     u32 yoffset = var->yoffset;                 //resolution                    
336     u16 xpos = (var->nonstd>>8) & 0xfff; //visiable pos in panel
337     u16 ypos = (var->nonstd>>20) & 0xfff;
338     u32 xvir = var->xres_virtual;
339     u32 yvir = var->yres_virtual;
340     u8 data_format = var->nonstd&0xff;
341     var->pixclock = dev_drv->pixclock;
342     CHK_SUSPEND(dev_drv);
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     
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_close,
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         set_lcd_info(dev_drv->screen, fb_inf->mach_info->lcd_info);
630         dev_drv->init_lcdc(dev_drv);
631         dev_drv->load_screen(dev_drv,1);
632         /************fb set,one layer one fb ***********/
633         dev_drv->fb_index_base = fb_inf->num_fb;
634     for(i=0;i<dev_drv->num_layer;i++)
635     {
636         fbi= framebuffer_alloc(0, &g_fb_pdev->dev);
637         if(!fbi)
638         {
639             dev_err(&g_fb_pdev->dev,">> fb framebuffer_alloc fail!");
640             fbi = NULL;
641             ret = -ENOMEM;
642         }
643         fbi->par = dev_drv;
644         fbi->var = def_var;
645         fbi->fix = def_fix;
646         sprintf(fbi->fix.id,"fb%d",fb_inf->num_fb);
647         fbi->var.xres = fb_inf->lcdc_dev_drv[lcdc_id]->screen->x_res;
648         fbi->var.yres = fb_inf->lcdc_dev_drv[lcdc_id]->screen->y_res;
649         fbi->var.bits_per_pixel = 16;
650         fbi->var.xres_virtual = fb_inf->lcdc_dev_drv[lcdc_id]->screen->x_res;
651         fbi->var.yres_virtual = fb_inf->lcdc_dev_drv[lcdc_id]->screen->y_res;
652         fbi->var.width = fb_inf->lcdc_dev_drv[lcdc_id]->screen->width;
653         fbi->var.height = fb_inf->lcdc_dev_drv[lcdc_id]->screen->height;
654         fbi->var.pixclock =fb_inf->lcdc_dev_drv[lcdc_id]->pixclock;
655         fbi->var.left_margin = fb_inf->lcdc_dev_drv[lcdc_id]->screen->left_margin;
656         fbi->var.right_margin = fb_inf->lcdc_dev_drv[lcdc_id]->screen->right_margin;
657         fbi->var.upper_margin = fb_inf->lcdc_dev_drv[lcdc_id]->screen->upper_margin;
658         fbi->var.lower_margin = fb_inf->lcdc_dev_drv[lcdc_id]->screen->lower_margin;
659         fbi->var.vsync_len = fb_inf->lcdc_dev_drv[lcdc_id]->screen->vsync_len;
660         fbi->var.hsync_len = fb_inf->lcdc_dev_drv[lcdc_id]->screen->hsync_len;
661         fbi->fbops                       = &fb_ops;
662         fbi->flags                       = FBINFO_FLAG_DEFAULT;
663         fbi->pseudo_palette  = fb_inf->lcdc_dev_drv[lcdc_id]->layer_par[i].pseudo_pal;
664         rk_request_fb_buffer(fbi,fb_inf->num_fb);
665         ret = register_framebuffer(fbi);
666         if(ret<0)
667         {
668             printk("%s>>fb%d register_framebuffer fail!\n",__func__,fb_inf->num_fb);
669             ret = -EINVAL;
670         }
671         rkfb_create_sysfs(fbi);
672         fb_inf->fb[fb_inf->num_fb] = fbi;
673         printk("%s>>>>>%s\n",__func__,fb_inf->fb[fb_inf->num_fb]->fix.id);
674         fb_inf->num_fb++;       
675         }
676 #if !defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_LOGO)
677     fb_inf->fb[fb_inf->num_fb-2]->fbops->fb_set_par(fb_inf->fb[fb_inf->num_fb-2]);
678     if(fb_prepare_logo(fb_inf->fb[fb_inf->num_fb-2], FB_ROTATE_UR)) {
679         /* Start display and show logo on boot */
680         fb_set_cmap(&fb_inf->fb[fb_inf->num_fb-2]->cmap, fb_inf->fb[fb_inf->num_fb-2]);
681         fb_show_logo(fb_inf->fb[fb_inf->num_fb-2], FB_ROTATE_UR);
682         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]);
683     }
684 #endif
685         return 0;
686         
687         
688 }
689 int rk_fb_unregister(struct rk_lcdc_device_driver *dev_drv)
690 {
691
692         struct rk_fb_inf *fb_inf = platform_get_drvdata(g_fb_pdev);
693         struct fb_info *fbi;
694         int fb_index_base = dev_drv->fb_index_base;
695         int fb_num = dev_drv->num_layer;
696         int i=0;
697         if(NULL == dev_drv)
698         {
699                 printk(" no need to unregister null lcdc device driver!\n");
700                 return -ENOENT;
701         }
702
703         for(i=fb_index_base;i<(fb_index_base+fb_num);i++)
704         {
705                 fbi = fb_inf->fb[i];
706                 unregister_framebuffer(fbi);
707                 rk_release_fb_buffer(fbi);
708                 framebuffer_release(fbi);       
709         }
710         fb_inf->lcdc_dev_drv[dev_drv->id]= NULL;
711
712         return 0;
713 }
714
715 int init_lcdc_device_driver(struct rk_lcdc_device_driver *def_drv,
716         struct rk_lcdc_device_driver *dev_drv,int id)
717 {
718         if(!def_drv)
719         {
720                 printk(KERN_ERR "default lcdc device driver is null!\n");
721                 return -EINVAL;
722         }
723         if(!dev_drv)
724         {
725                 printk(KERN_ERR "lcdc device driver is null!\n");
726                 return -EINVAL; 
727         }
728         sprintf(dev_drv->name, "lcdc%d",id);
729         dev_drv->layer_par = def_drv->layer_par;
730         dev_drv->num_layer = def_drv->num_layer;
731         dev_drv->open      = def_drv->open;
732         dev_drv->init_lcdc = def_drv->init_lcdc;
733         dev_drv->ioctl = def_drv->ioctl;
734         dev_drv->blank = def_drv->blank;
735         dev_drv->set_par = def_drv->set_par;
736         dev_drv->pan_display = def_drv->pan_display;
737         dev_drv->suspend = def_drv->suspend;
738         dev_drv->resume = def_drv->resume;
739         dev_drv->load_screen = def_drv->load_screen;
740         init_completion(&dev_drv->frame_done);
741         spin_lock_init(&dev_drv->cpl_lock);
742         dev_drv->first_frame = 1;
743         
744         return 0;
745 }
746
747
748 #ifdef CONFIG_HAS_EARLYSUSPEND
749 struct suspend_info {
750         struct early_suspend early_suspend;
751         struct rk_fb_inf *inf;
752 };
753
754 static void rkfb_early_suspend(struct early_suspend *h)
755 {
756         struct suspend_info *info = container_of(h, struct suspend_info,
757                                                 early_suspend);
758         struct rk_fb_inf *inf = info->inf;
759         int i;
760         inf->mach_info->io_disable();
761         for(i = 0; i < inf->num_lcdc; i++)
762         {
763                 atomic_set(&inf->lcdc_dev_drv[i]->in_suspend,1);
764                 inf->lcdc_dev_drv[i]->suspend(inf->lcdc_dev_drv[i]);
765         }
766 }
767 static void rkfb_early_resume(struct early_suspend *h)
768 {
769         struct suspend_info *info = container_of(h, struct suspend_info,
770                                                 early_suspend);
771         struct rk_fb_inf *inf = info->inf;
772         int i;
773         inf->mach_info->io_enable();
774         for(i = 0; i < inf->num_lcdc; i++)
775         {
776                 inf->lcdc_dev_drv[i]->resume(inf->lcdc_dev_drv[i]);
777                 atomic_set(&inf->lcdc_dev_drv[i]->in_suspend,0);
778         }
779
780 }
781
782
783
784 static struct suspend_info suspend_info = {
785         .early_suspend.suspend = rkfb_early_suspend,
786         .early_suspend.resume = rkfb_early_resume,
787         .early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB,
788 };
789 #endif
790
791 static int __devinit rk_fb_probe (struct platform_device *pdev)
792 {
793         struct rk_fb_inf *fb_inf = NULL;
794         struct rk29fb_info * mach_info = NULL;
795         int ret = 0;
796         g_fb_pdev=pdev;
797         /* Malloc rk_fb_inf and set it to pdev for drvdata */
798         fb_inf = kzalloc(sizeof(struct rk_fb_inf), GFP_KERNEL);
799         if(!fb_inf)
800         {
801                 dev_err(&pdev->dev, ">>fb inf kmalloc fail!");
802                 ret = -ENOMEM;
803         }
804         platform_set_drvdata(pdev,fb_inf);
805         mach_info =  pdev->dev.platform_data;
806         fb_inf->mach_info = mach_info;
807         if(mach_info->io_init)
808                 mach_info->io_init(NULL);
809 #ifdef CONFIG_HAS_EARLYSUSPEND
810         suspend_info.inf = fb_inf;
811         register_early_suspend(&suspend_info.early_suspend);
812 #endif
813         printk("rk fb probe ok!\n");
814     return 0;
815 }
816
817 static int __devexit rk_fb_remove(struct platform_device *pdev)
818 {
819         struct rk_fb_inf *fb_inf = platform_get_drvdata(pdev);
820         kfree(fb_inf);
821         platform_set_drvdata(pdev, NULL);
822         return 0;
823 }
824
825 static void rk_fb_shutdown(struct platform_device *pdev)
826 {
827         struct rk_fb_inf *fb_inf = platform_get_drvdata(pdev);
828         kfree(fb_inf);
829         platform_set_drvdata(pdev, NULL);
830 }
831
832 static struct platform_driver rk_fb_driver = {
833         .probe          = rk_fb_probe,
834         .remove         = __devexit_p(rk_fb_remove),
835         .driver         = {
836                 .name   = "rk-fb",
837                 .owner  = THIS_MODULE,
838         },
839         .shutdown   = rk_fb_shutdown,
840 };
841
842 static int __init rk_fb_init(void)
843 {
844     return platform_driver_register(&rk_fb_driver);
845 }
846
847 static void __exit rk_fb_exit(void)
848 {
849     platform_driver_unregister(&rk_fb_driver);
850 }
851
852 subsys_initcall_sync(rk_fb_init);
853 module_exit(rk_fb_exit);
854