rk30fb :fix a bug in rk30_lcdc.c
[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 static int init_layer_par(struct rk_lcdc_device_driver *dev_drv)
603 {
604        int i;
605        struct layer_par * def_par = NULL;
606        int num_par = dev_drv->num_layer;
607        for(i = 0; i < num_par; i++)
608        {
609                struct layer_par *par = NULL;
610                par =  kzalloc(sizeof(struct layer_par), GFP_KERNEL);
611                if(!par)
612                {
613                        printk(KERN_ERR "kzmalloc for layer_par fail!");
614                        return   -ENOMEM;
615                        
616                }
617                def_par = &dev_drv->def_layer_par[i];
618                strcpy(par->name,def_par->name);
619                par->id = def_par->id;
620                par->support_3d = def_par->support_3d;
621                dev_drv->layer_par[i] = par;
622        }
623                
624        return 0;
625        
626        
627 }
628
629
630 static int init_lcdc_device_driver(struct rk_lcdc_device_driver *dev_drv,
631         struct rk_lcdc_device_driver *def_drv,int id)
632 {
633         if(!def_drv)
634         {
635                 printk(KERN_ERR "default lcdc device driver is null!\n");
636                 return -EINVAL;
637         }
638         if(!dev_drv)
639         {
640                 printk(KERN_ERR "lcdc device driver is null!\n");
641                 return -EINVAL; 
642         }
643         sprintf(dev_drv->name, "lcdc%d",id);
644         dev_drv->open           = def_drv->open;
645         dev_drv->init_lcdc      = def_drv->init_lcdc;
646         dev_drv->ioctl          = def_drv->ioctl;
647         dev_drv->blank          = def_drv->blank;
648         dev_drv->set_par        = def_drv->set_par;
649         dev_drv->pan_display    = def_drv->pan_display;
650         dev_drv->suspend        = def_drv->suspend;
651         dev_drv->resume         = def_drv->resume;
652         dev_drv->load_screen    = def_drv->load_screen;
653         dev_drv->def_layer_par  = def_drv->def_layer_par;
654         dev_drv->num_layer      = def_drv->num_layer;
655         init_layer_par(dev_drv);
656         init_completion(&dev_drv->frame_done);
657         spin_lock_init(&dev_drv->cpl_lock);
658         dev_drv->first_frame = 1;
659         
660         return 0;
661 }
662
663 int rk_fb_register(struct rk_lcdc_device_driver *dev_drv,
664         struct rk_lcdc_device_driver *def_drv,int id)
665 {
666         struct rk_fb_inf *fb_inf = platform_get_drvdata(g_fb_pdev);
667         struct fb_info *fbi;
668         int i=0,ret = 0;
669         int lcdc_id = 0;
670         if(NULL == dev_drv)
671         {
672                 printk("null lcdc device driver?");
673                 return -ENOENT;
674         }
675         for(i=0;i<RK30_MAX_LCDC_SUPPORT;i++)
676         {
677                 if(NULL==fb_inf->lcdc_dev_drv[i])
678                 {
679                         fb_inf->lcdc_dev_drv[i] = dev_drv;
680                         fb_inf->lcdc_dev_drv[i]->id = i;
681                         fb_inf->num_lcdc++;
682                         break;
683                 }
684         }
685         if(i==RK30_MAX_LCDC_SUPPORT)
686         {
687                 printk("rk_fb_register lcdc out of support %d",i);
688                 return -ENOENT;
689         }
690         lcdc_id = i;
691         init_lcdc_device_driver(dev_drv, def_drv,id);
692         set_lcd_info(dev_drv->screen, fb_inf->mach_info->lcd_info);
693         dev_drv->init_lcdc(dev_drv);
694         dev_drv->load_screen(dev_drv,1);
695         /************fb set,one layer one fb ***********/
696         dev_drv->fb_index_base = fb_inf->num_fb;
697     for(i=0;i<dev_drv->num_layer;i++)
698     {
699         fbi= framebuffer_alloc(0, &g_fb_pdev->dev);
700         if(!fbi)
701         {
702             dev_err(&g_fb_pdev->dev,">> fb framebuffer_alloc fail!");
703             fbi = NULL;
704             ret = -ENOMEM;
705         }
706         fbi->par = dev_drv;
707         fbi->var = def_var;
708         fbi->fix = def_fix;
709         sprintf(fbi->fix.id,"fb%d",fb_inf->num_fb);
710         fbi->var.xres = fb_inf->lcdc_dev_drv[lcdc_id]->screen->x_res;
711         fbi->var.yres = fb_inf->lcdc_dev_drv[lcdc_id]->screen->y_res;
712         fbi->var.bits_per_pixel = 16;
713         fbi->var.xres_virtual = fb_inf->lcdc_dev_drv[lcdc_id]->screen->x_res;
714         fbi->var.yres_virtual = fb_inf->lcdc_dev_drv[lcdc_id]->screen->y_res;
715         fbi->var.width = fb_inf->lcdc_dev_drv[lcdc_id]->screen->width;
716         fbi->var.height = fb_inf->lcdc_dev_drv[lcdc_id]->screen->height;
717         fbi->var.pixclock =fb_inf->lcdc_dev_drv[lcdc_id]->pixclock;
718         fbi->var.left_margin = fb_inf->lcdc_dev_drv[lcdc_id]->screen->left_margin;
719         fbi->var.right_margin = fb_inf->lcdc_dev_drv[lcdc_id]->screen->right_margin;
720         fbi->var.upper_margin = fb_inf->lcdc_dev_drv[lcdc_id]->screen->upper_margin;
721         fbi->var.lower_margin = fb_inf->lcdc_dev_drv[lcdc_id]->screen->lower_margin;
722         fbi->var.vsync_len = fb_inf->lcdc_dev_drv[lcdc_id]->screen->vsync_len;
723         fbi->var.hsync_len = fb_inf->lcdc_dev_drv[lcdc_id]->screen->hsync_len;
724         fbi->fbops                       = &fb_ops;
725         fbi->flags                       = FBINFO_FLAG_DEFAULT;
726         fbi->pseudo_palette  = fb_inf->lcdc_dev_drv[lcdc_id]->layer_par[i]->pseudo_pal;
727         rk_request_fb_buffer(fbi,fb_inf->num_fb);
728         ret = register_framebuffer(fbi);
729         if(ret<0)
730         {
731             printk("%s>>fb%d register_framebuffer fail!\n",__func__,fb_inf->num_fb);
732             ret = -EINVAL;
733         }
734         rkfb_create_sysfs(fbi);
735         fb_inf->fb[fb_inf->num_fb] = fbi;
736         printk("%s>>>>>%s\n",__func__,fb_inf->fb[fb_inf->num_fb]->fix.id);
737         fb_inf->num_fb++;       
738         }
739 #if !defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_LOGO)
740     fb_inf->fb[fb_inf->num_fb-2]->fbops->fb_set_par(fb_inf->fb[fb_inf->num_fb-2]);
741     if(fb_prepare_logo(fb_inf->fb[fb_inf->num_fb-2], FB_ROTATE_UR)) {
742         /* Start display and show logo on boot */
743         fb_set_cmap(&fb_inf->fb[fb_inf->num_fb-2]->cmap, fb_inf->fb[fb_inf->num_fb-2]);
744         fb_show_logo(fb_inf->fb[fb_inf->num_fb-2], FB_ROTATE_UR);
745         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]);
746     }
747 #endif
748         return 0;
749         
750         
751 }
752 int rk_fb_unregister(struct rk_lcdc_device_driver *dev_drv)
753 {
754
755         struct rk_fb_inf *fb_inf = platform_get_drvdata(g_fb_pdev);
756         struct fb_info *fbi;
757         int fb_index_base = dev_drv->fb_index_base;
758         int fb_num = dev_drv->num_layer;
759         int i=0;
760         if(NULL == dev_drv)
761         {
762                 printk(" no need to unregister null lcdc device driver!\n");
763                 return -ENOENT;
764         }
765
766         for(i = 0; i < fb_num; i++)
767         {
768                 kfree(dev_drv->layer_par[i]);
769         }
770
771         for(i=fb_index_base;i<(fb_index_base+fb_num);i++)
772         {
773                 fbi = fb_inf->fb[i];
774                 unregister_framebuffer(fbi);
775                 rk_release_fb_buffer(fbi);
776                 framebuffer_release(fbi);       
777         }
778         fb_inf->lcdc_dev_drv[dev_drv->id]= NULL;
779
780         return 0;
781 }
782
783
784
785 #ifdef CONFIG_HAS_EARLYSUSPEND
786 struct suspend_info {
787         struct early_suspend early_suspend;
788         struct rk_fb_inf *inf;
789 };
790
791 static void rkfb_early_suspend(struct early_suspend *h)
792 {
793         struct suspend_info *info = container_of(h, struct suspend_info,
794                                                 early_suspend);
795         struct rk_fb_inf *inf = info->inf;
796         int i;
797         inf->mach_info->io_disable();
798         for(i = 0; i < inf->num_lcdc; i++)
799         {
800                 atomic_set(&inf->lcdc_dev_drv[i]->in_suspend,1);
801                 inf->lcdc_dev_drv[i]->suspend(inf->lcdc_dev_drv[i]);
802         }
803 }
804 static void rkfb_early_resume(struct early_suspend *h)
805 {
806         struct suspend_info *info = container_of(h, struct suspend_info,
807                                                 early_suspend);
808         struct rk_fb_inf *inf = info->inf;
809         int i;
810         inf->mach_info->io_enable();
811         for(i = 0; i < inf->num_lcdc; i++)
812         {
813                 inf->lcdc_dev_drv[i]->resume(inf->lcdc_dev_drv[i]);
814                 atomic_set(&inf->lcdc_dev_drv[i]->in_suspend,0);
815         }
816
817 }
818
819
820
821 static struct suspend_info suspend_info = {
822         .early_suspend.suspend = rkfb_early_suspend,
823         .early_suspend.resume = rkfb_early_resume,
824         .early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB,
825 };
826 #endif
827
828 static int __devinit rk_fb_probe (struct platform_device *pdev)
829 {
830         struct rk_fb_inf *fb_inf = NULL;
831         struct rk29fb_info * mach_info = NULL;
832         int ret = 0;
833         g_fb_pdev=pdev;
834         /* Malloc rk_fb_inf and set it to pdev for drvdata */
835         fb_inf = kzalloc(sizeof(struct rk_fb_inf), GFP_KERNEL);
836         if(!fb_inf)
837         {
838                 dev_err(&pdev->dev, ">>fb inf kmalloc fail!");
839                 ret = -ENOMEM;
840         }
841         platform_set_drvdata(pdev,fb_inf);
842         mach_info =  pdev->dev.platform_data;
843         fb_inf->mach_info = mach_info;
844         if(mach_info->io_init)
845                 mach_info->io_init(NULL);
846 #ifdef CONFIG_HAS_EARLYSUSPEND
847         suspend_info.inf = fb_inf;
848         register_early_suspend(&suspend_info.early_suspend);
849 #endif
850         printk("rk fb probe ok!\n");
851     return 0;
852 }
853
854 static int __devexit rk_fb_remove(struct platform_device *pdev)
855 {
856         struct rk_fb_inf *fb_inf = platform_get_drvdata(pdev);
857         kfree(fb_inf);
858         platform_set_drvdata(pdev, NULL);
859         return 0;
860 }
861
862 static void rk_fb_shutdown(struct platform_device *pdev)
863 {
864         struct rk_fb_inf *fb_inf = platform_get_drvdata(pdev);
865         kfree(fb_inf);
866         platform_set_drvdata(pdev, NULL);
867 }
868
869 static struct platform_driver rk_fb_driver = {
870         .probe          = rk_fb_probe,
871         .remove         = __devexit_p(rk_fb_remove),
872         .driver         = {
873                 .name   = "rk-fb",
874                 .owner  = THIS_MODULE,
875         },
876         .shutdown   = rk_fb_shutdown,
877 };
878
879 static int __init rk_fb_init(void)
880 {
881     return platform_driver_register(&rk_fb_driver);
882 }
883
884 static void __exit rk_fb_exit(void)
885 {
886     platform_driver_unregister(&rk_fb_driver);
887 }
888
889 subsys_initcall_sync(rk_fb_init);
890 module_exit(rk_fb_exit);
891