2 * drivers/video/rockchip/rk_fb.c
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.
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.
17 #include <linux/module.h>
18 #include <linux/kernel.h>
19 #include <linux/errno.h>
20 #include <linux/string.h>
22 #include <linux/slab.h>
23 #include <linux/delay.h>
24 #include <linux/device.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>
35 #define fbprintk(msg...) printk(msg);
37 #define fbprintk(msg...)
41 #define CHK_SUSPEND(drv) \
42 if(atomic_dec_and_test(&drv->in_suspend)) { \
43 printk(">>>>>> fb is in suspend! return! \n"); \
47 #define CHK_SUSPEND(inf)
50 static struct platform_device *g_fb_pdev;
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, },
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
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 ****************************************************************************/
71 int get_fb_layer_id(struct fb_fix_screeninfo *fix)
74 if(!strcmp(fix->id,"fb1")||!strcmp(fix->id,"fb3"))
78 else if(!strcmp(fix->id,"fb0")||!strcmp(fix->id,"fb2"))
84 printk(KERN_ERR "unsupported %s",fix->id);
91 /**********************************************************************
93 name: lcdc device name ,lcdc0 , lcdc1
94 ***********************************************************************/
95 struct rk_lcdc_device_driver * rk_get_lcdc_drv(char *name)
97 struct rk_fb_inf *inf = platform_get_drvdata(g_fb_pdev);
99 for( i = 0; i < inf->num_lcdc; i++)
101 if(!strcmp(inf->lcdc_dev_drv[i]->name,name))
104 return inf->lcdc_dev_drv[i];
107 static int rk_fb_open(struct fb_info *info,int user)
109 struct rk_lcdc_device_driver * dev_drv = (struct rk_lcdc_device_driver * )info->par;
111 CHK_SUSPEND(dev_drv);
112 layer_id = get_fb_layer_id(&info->fix);
113 dev_drv->open(dev_drv,layer_id,1);
119 static int rk_fb_close(struct fb_info *info,int user)
121 struct rk_lcdc_device_driver * dev_drv = (struct rk_lcdc_device_driver * )info->par;
123 CHK_SUSPEND(dev_drv);
124 layer_id = get_fb_layer_id(&info->fix);
125 dev_drv->open(dev_drv,layer_id,0);
130 static int rk_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
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;
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);
148 par = &dev_drv->layer_par[layer_id];
153 par->y_offset = (yoffset*xvir + xoffset)*4;
156 par->y_offset = (yoffset*xvir + xoffset)*3;
159 par->y_offset = (yoffset*xvir + xoffset)*2;
162 par->y_offset = yoffset*xvir + xoffset;
163 par->c_offset = par->y_offset;
166 par->y_offset = yoffset*xvir + xoffset;
167 par->c_offset = (yoffset>>1)*xvir + xoffset;
169 case YUV444 : // yuv444
170 par->y_offset = yoffset*xvir + xoffset;
171 par->c_offset = yoffset*2*xvir +(xoffset<<1);
174 printk("un supported format:0x%x\n",data_format);
178 dev_drv->pan_display(dev_drv,layer_id);
182 static int rk_fb_ioctl(struct fb_info *info, unsigned int cmd,unsigned long arg)
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;
188 void __user *argp = (void __user *)arg;
189 fbprintk(">>>>>> %s : cmd:0x%x \n",__FUNCTION__,cmd);
191 CHK_SUSPEND(dev_drv);
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")))
199 if (copy_from_user(yuv_phy, argp, 8))
201 info->fix.smem_start = yuv_phy[0]; //four y
202 info->fix.mmio_start = yuv_phy[1]; //four uv
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
217 case FBIOGET_IDLEFBUff_16OR32:
218 case FBIOSET_COMPOSE_LAYER_COUNTS:
219 case FBIOGET_COMPOSE_LAYER_COUNTS:
221 dev_drv->ioctl(dev_drv,cmd,arg,0);
227 static int rk_fb_blank(int blank_mode, struct fb_info *info)
229 struct rk_lcdc_device_driver *dev_drv = (struct rk_lcdc_device_driver * )info->par;
230 struct fb_fix_screeninfo *fix = &info->fix;
232 CHK_SUSPEND(dev_drv);
233 layer_id = get_fb_layer_id(fix);
239 dev_drv->blank(dev_drv,layer_id,blank_mode);
244 static int rk_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
246 struct rk_lcdc_device_driver *dev_drv = (struct rk_lcdc_device_driver * )info->par;
247 CHK_SUSPEND(dev_drv);
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)) )
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);
260 if( (var->xoffset+var->xres)>var->xres_virtual ||
261 (var->yoffset+var->yres)>var->yres_virtual*2 )
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);
270 switch(var->nonstd&0x0f)
273 switch(var->bits_per_pixel)
276 var->xres_virtual = (var->xres_virtual + 0x1) & (~0x1);
277 var->xres = (var->xres + 0x1) & (~0x1);
278 var->xoffset = (var->xoffset) & (~0x1);
281 var->bits_per_pixel = 32;
284 var->nonstd &= ~0xc0; //not support I2P in this format
287 var->xres_virtual = (var->xres_virtual + 0x3) & (~0x3);
288 var->xres = (var->xres + 0x3) & (~0x3);
289 var->xoffset = (var->xoffset) & (~0x3);
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);
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
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
316 printk(">>>>>> fb1 var->nonstd=%d is invalid! \n", var->nonstd);
324 static int rk_fb_set_par(struct fb_info *info)
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;
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);
350 par = &dev_drv->layer_par[layer_id];
352 if((!strcmp(fix->id,"fb0"))||(!strcmp(fix->id,"fb2"))) //four ui
354 xsize = screen->x_res;
355 ysize = screen->y_res;
357 else if((!strcmp(fix->id,"fb1"))||(!strcmp(fix->id,"fb3")))
359 xsize = (var->grayscale>>8) & 0xfff; //visiable size in panel ,for vide0
360 ysize = (var->grayscale>>20) & 0xfff;
363 /* calculate y_offset,c_offset,line_length,cblen and crlen */
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;
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;
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;
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;
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;
397 case HAL_PIXEL_FORMAT_YCrCb_444 : // yuv444
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);
405 printk("un supported format:0x%x\n",data_format);
409 switch(var->bits_per_pixel)
412 par->format = ARGB888;
413 fix->line_length = 4 * xvir;
414 par->y_offset = (yoffset*xvir + xoffset)*4;
417 par->format = RGB565;
418 fix->line_length = 2 * xvir;
419 par->y_offset = (yoffset*xvir + xoffset)*2;
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);
441 static inline unsigned int chan_to_field(unsigned int chan,
442 struct fb_bitfield *bf)
445 chan >>= 16 - bf->length;
446 return chan << bf->offset;
449 static int fb_setcolreg(unsigned regno,
450 unsigned red, unsigned green, unsigned blue,
451 unsigned transp, struct fb_info *info)
455 switch (info->fix.visual) {
456 case FB_VISUAL_TRUECOLOR:
457 /* true-colour, use pseudo-palette */
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);
467 return -1; /* unknown type */
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,
490 static struct fb_var_screeninfo def_var = {
491 .red = {11,5,0},//default set to rgb565,the boot logo is rgb565
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,
499 .vmode = FB_VMODE_NONINTERLACED,
502 static struct fb_fix_screeninfo def_fix = {
503 .type = FB_TYPE_PACKED_PIXELS,
508 .accel = FB_ACCEL_NONE,
509 .visual = FB_VISUAL_TRUECOLOR,
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)
521 struct rk_fb_inf *inf = platform_get_drvdata(g_fb_pdev);
522 struct fb_info *fb = inf->fb[fb_id];
525 EXPORT_SYMBOL(rk_get_fb);
527 void rk_direct_fb_show(struct fb_info * fbi)
530 rk_pan_display(&fbi->var, fbi);
532 EXPORT_SYMBOL(rk_direct_fb_show);
534 static int rk_request_fb_buffer(struct fb_info *fbi,int fb_id)
536 struct resource *res;
537 struct resource *mem;
542 res = platform_get_resource_byname(g_fb_pdev, IORESOURCE_MEM, "fb0 buf");
545 dev_err(&g_fb_pdev->dev, "failed to get win0 memory \n");
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");
559 dev_err(&g_fb_pdev->dev, "failed to get win1 ipp memory \n");
562 fbi->fix.mmio_start = res->start;
563 fbi->fix.mmio_len = res->end - res->start + 1;
567 res = platform_get_resource_byname(g_fb_pdev, IORESOURCE_MEM, "fb2 buf");
570 dev_err(&g_fb_pdev->dev, "failed to get win0 memory \n");
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);
588 static int rk_release_fb_buffer(struct fb_info *fbi)
592 printk("no need release null fb buffer!\n");
595 if(!strcmp(fbi->fix.id,"fb1")||!strcmp(fbi->fix.id,"fb3")) //buffer for fb1 and fb3 are alloc by android
597 iounmap(fbi->screen_base);
598 release_mem_region(fbi->fix.smem_start,fbi->fix.smem_len);
602 int rk_fb_register(struct rk_lcdc_device_driver *dev_drv)
604 struct rk_fb_inf *fb_inf = platform_get_drvdata(g_fb_pdev);
610 printk("null lcdc device driver?");
613 for(i=0;i<RK30_MAX_LCDC_SUPPORT;i++)
615 if(NULL==fb_inf->lcdc_dev_drv[i])
617 fb_inf->lcdc_dev_drv[i] = dev_drv;
618 fb_inf->lcdc_dev_drv[i]->id = i;
623 if(i==RK30_MAX_LCDC_SUPPORT)
625 printk("rk_fb_register lcdc out of support %d",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++)
636 fbi= framebuffer_alloc(0, &g_fb_pdev->dev);
639 dev_err(&g_fb_pdev->dev,">> fb framebuffer_alloc fail!");
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);
668 printk("%s>>fb%d register_framebuffer fail!\n",__func__,fb_inf->num_fb);
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);
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]);
689 int rk_fb_unregister(struct rk_lcdc_device_driver *dev_drv)
692 struct rk_fb_inf *fb_inf = platform_get_drvdata(g_fb_pdev);
694 int fb_index_base = dev_drv->fb_index_base;
695 int fb_num = dev_drv->num_layer;
699 printk(" no need to unregister null lcdc device driver!\n");
703 for(i=fb_index_base;i<(fb_index_base+fb_num);i++)
706 unregister_framebuffer(fbi);
707 rk_release_fb_buffer(fbi);
708 framebuffer_release(fbi);
710 fb_inf->lcdc_dev_drv[dev_drv->id]= NULL;
715 int init_lcdc_device_driver(struct rk_lcdc_device_driver *def_drv,
716 struct rk_lcdc_device_driver *dev_drv,int id)
720 printk(KERN_ERR "default lcdc device driver is null!\n");
725 printk(KERN_ERR "lcdc device driver is null!\n");
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;
748 #ifdef CONFIG_HAS_EARLYSUSPEND
749 struct suspend_info {
750 struct early_suspend early_suspend;
751 struct rk_fb_inf *inf;
754 static void rkfb_early_suspend(struct early_suspend *h)
756 struct suspend_info *info = container_of(h, struct suspend_info,
758 struct rk_fb_inf *inf = info->inf;
760 inf->mach_info->io_disable();
761 for(i = 0; i < inf->num_lcdc; i++)
763 atomic_set(&inf->lcdc_dev_drv[i]->in_suspend,1);
764 inf->lcdc_dev_drv[i]->suspend(inf->lcdc_dev_drv[i]);
767 static void rkfb_early_resume(struct early_suspend *h)
769 struct suspend_info *info = container_of(h, struct suspend_info,
771 struct rk_fb_inf *inf = info->inf;
773 inf->mach_info->io_enable();
774 for(i = 0; i < inf->num_lcdc; i++)
776 inf->lcdc_dev_drv[i]->resume(inf->lcdc_dev_drv[i]);
777 atomic_set(&inf->lcdc_dev_drv[i]->in_suspend,0);
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,
791 static int __devinit rk_fb_probe (struct platform_device *pdev)
793 struct rk_fb_inf *fb_inf = NULL;
794 struct rk29fb_info * mach_info = NULL;
797 /* Malloc rk_fb_inf and set it to pdev for drvdata */
798 fb_inf = kzalloc(sizeof(struct rk_fb_inf), GFP_KERNEL);
801 dev_err(&pdev->dev, ">>fb inf kmalloc fail!");
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);
813 printk("rk fb probe ok!\n");
817 static int __devexit rk_fb_remove(struct platform_device *pdev)
819 struct rk_fb_inf *fb_inf = platform_get_drvdata(pdev);
821 platform_set_drvdata(pdev, NULL);
825 static void rk_fb_shutdown(struct platform_device *pdev)
827 struct rk_fb_inf *fb_inf = platform_get_drvdata(pdev);
829 platform_set_drvdata(pdev, NULL);
832 static struct platform_driver rk_fb_driver = {
833 .probe = rk_fb_probe,
834 .remove = __devexit_p(rk_fb_remove),
837 .owner = THIS_MODULE,
839 .shutdown = rk_fb_shutdown,
842 static int __init rk_fb_init(void)
844 return platform_driver_register(&rk_fb_driver);
847 static void __exit rk_fb_exit(void)
849 platform_driver_unregister(&rk_fb_driver);
852 subsys_initcall_sync(rk_fb_init);
853 module_exit(rk_fb_exit);