#include <linux/device.h>
#include <linux/fb.h>
#include <linux/init.h>
-#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/earlysuspend.h>
#include <asm/div64.h>
#include <asm/uaccess.h>
-#include <mach/board.h>
+#include<linux/rk_fb.h>
-#include "../display/screen/screen.h"
-#include "rk_fb.h"
#if 0
#define fbprintk(msg...) printk(msg);
#define fbprintk(msg...)
#endif
-#if 0
-#define CHK_SUSPEND(inf) \
- if(inf->in_suspend) { \
- fbprintk(">>>>>> fb is in suspend! return! \n"); \
+#if 1
+#define CHK_SUSPEND(drv) \
+ if(atomic_dec_and_test(&drv->in_suspend)) { \
+ printk(">>>>>> fb is in suspend! return! \n"); \
return -EPERM; \
}
#else
pass the phy addr to fix.smem_start by ioctl
****************************************************************************/
-static int get_fb_layer_id(struct fb_fix_screeninfo *fix)
+int get_fb_layer_id(struct fb_fix_screeninfo *fix)
{
int layer_id;
if(!strcmp(fix->id,"fb1")||!strcmp(fix->id,"fb3"))
return layer_id;
}
+
+/**********************************************************************
+this is for hdmi
+name: lcdc device name ,lcdc0 , lcdc1
+***********************************************************************/
+struct rk_lcdc_device_driver * rk_get_lcdc_drv(char *name)
+{
+ struct rk_fb_inf *inf = platform_get_drvdata(g_fb_pdev);
+ int i = 0;
+ for( i = 0; i < inf->num_lcdc; i++)
+ {
+ if(!strcmp(inf->lcdc_dev_drv[i]->name,name))
+ break;
+ }
+ return inf->lcdc_dev_drv[i];
+
+}
static int rk_fb_open(struct fb_info *info,int user)
{
- struct rk_fb_inf *inf = dev_get_drvdata(info->device);
- struct rk_lcdc_device_driver *dev_drv = NULL;
- struct fb_fix_screeninfo *fix = &info->fix;
+ struct rk_lcdc_device_driver * dev_drv = (struct rk_lcdc_device_driver * )info->par;
int layer_id;
- if(!strcmp(fix->id,"fb1")){
- dev_drv = inf->lcdc_dev_drv[0];
- layer_id = 0;
- dev_drv->blank(dev_drv,1,FB_BLANK_NORMAL); //when open fb1,defautl close fb0 layer win1
- dev_drv->blank(dev_drv,layer_id,FB_BLANK_UNBLANK); //open fb1 layer win0
- inf->video_mode = 1;
- }
+ CHK_SUSPEND(dev_drv);
+ layer_id = get_fb_layer_id(&info->fix);
+ dev_drv->open(dev_drv,layer_id,1);
-
return 0;
}
-static int rk_fb_release(struct fb_info *info,int user)
+static int rk_fb_close(struct fb_info *info,int user)
{
- struct rk_fb_inf *inf = dev_get_drvdata(info->device);
- struct fb_fix_screeninfo *fix = &info->fix;
- if(!strcmp(fix->id,"fb1")){
- inf->video_mode = 0;
- }
-
- return 0;
+ struct rk_lcdc_device_driver * dev_drv = (struct rk_lcdc_device_driver * )info->par;
+ int layer_id;
+ CHK_SUSPEND(dev_drv);
+ layer_id = get_fb_layer_id(&info->fix);
+ dev_drv->open(dev_drv,layer_id,0);
+
+ return 0;
}
static int rk_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
u32 xvir = var->xres_virtual;
u8 data_format = var->nonstd&0xff;
layer_id = get_fb_layer_id(fix);
+ CHK_SUSPEND(dev_drv);
if(layer_id < 0)
{
return -ENODEV;
}
else
{
- par = &dev_drv->layer_par[layer_id];
+ par = dev_drv->layer_par[layer_id];
}
switch (par->format)
{
u32 yuv_phy[2];
void __user *argp = (void __user *)arg;
fbprintk(">>>>>> %s : cmd:0x%x \n",__FUNCTION__,cmd);
- CHK_SUSPEND(inf);
+ CHK_SUSPEND(dev_drv);
switch(cmd)
{
case FBIOPUT_FBPHYADD:
struct rk_lcdc_device_driver *dev_drv = (struct rk_lcdc_device_driver * )info->par;
struct fb_fix_screeninfo *fix = &info->fix;
int layer_id;
+ CHK_SUSPEND(dev_drv);
layer_id = get_fb_layer_id(fix);
if(layer_id < 0)
{
static int rk_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
{
- CHK_SUSPEND(inf);
+ struct rk_lcdc_device_driver *dev_drv = (struct rk_lcdc_device_driver * )info->par;
+ CHK_SUSPEND(dev_drv);
if( 0==var->xres_virtual || 0==var->yres_virtual ||
0==var->xres || 0==var->yres || var->xres<16 ||
u32 xvir = var->xres_virtual;
u32 yvir = var->yres_virtual;
u8 data_format = var->nonstd&0xff;
-
+ var->pixclock = dev_drv->pixclock;
+ CHK_SUSPEND(dev_drv);
layer_id = get_fb_layer_id(fix);
if(layer_id < 0)
{
}
else
{
- par = &dev_drv->layer_par[layer_id];
+ par = dev_drv->layer_par[layer_id];
}
if((!strcmp(fix->id,"fb0"))||(!strcmp(fix->id,"fb2"))) //four ui
{
xsize = (var->grayscale>>8) & 0xfff; //visiable size in panel ,for vide0
ysize = (var->grayscale>>20) & 0xfff;
}
- CHK_SUSPEND(inf);
+
/* calculate y_offset,c_offset,line_length,cblen and crlen */
#if 1
switch (data_format)
static struct fb_ops fb_ops = {
.owner = THIS_MODULE,
.fb_open = rk_fb_open,
- .fb_release = rk_fb_release,
+ .fb_release = rk_fb_close,
.fb_check_var = rk_fb_check_var,
.fb_set_par = rk_fb_set_par,
.fb_blank = rk_fb_blank,
void rk_direct_fb_show(struct fb_info * fbi)
{
rk_fb_set_par(fbi);
+ rk_pan_display(&fbi->var, fbi);
}
EXPORT_SYMBOL(rk_direct_fb_show);
-static int request_fb_buffer(struct fb_info *fbi,int fb_id)
+static int rk_request_fb_buffer(struct fb_info *fbi,int fb_id)
{
- struct resource *res;
- struct resource *mem;
- int ret = 0;
- switch(fb_id)
- {
- case 0:
- res = platform_get_resource_byname(g_fb_pdev, IORESOURCE_MEM, "fb0 buf");
- if (res == NULL)
- {
- dev_err(&g_fb_pdev->dev, "failed to get win0 memory \n");
- ret = -ENOENT;
- }
-
- fbi->fix.smem_start = res->start;
- fbi->fix.smem_len = res->end - res->start + 1;
- mem = request_mem_region(res->start, resource_size(res), g_fb_pdev->name);
- fbi->screen_base = ioremap(res->start, fbi->fix.smem_len);
- memset(fbi->screen_base, 0, fbi->fix.smem_len);
- printk("fb%d:phy:%lx>>vir:%p\n",fb_id,fbi->fix.smem_start,fbi->screen_base);
- #ifdef CONFIG_FB_WORK_IPP
- /* alloc ipp buf for rotate */
- res = platform_get_resource_byname(g_fb_pdev, IORESOURCE_MEM, "ipp buf");
- if (res == NULL)
- {
- dev_err(&g_fb_pdev->dev, "failed to get win1 ipp memory \n");
- ret = -ENOENT;
- }
- fbi->fix.mmio_start = res->start;
- fbi->fix.mmio_len = res->end - res->start + 1;
- #endif
- break;
- case 2:
- res = platform_get_resource_byname(g_fb_pdev, IORESOURCE_MEM, "fb2 buf");
- if (res == NULL)
- {
- dev_err(&g_fb_pdev->dev, "failed to get win0 memory \n");
- ret = -ENOENT;
- }
- fbi->fix.smem_start = res->start;
- fbi->fix.smem_len = res->end - res->start + 1;
- fbi->screen_base = ioremap(res->start, fbi->fix.smem_len);
- memset(fbi->screen_base, 0, fbi->fix.smem_len);
- break;
- default:
- ret = -EINVAL;
- break;
+ struct resource *res;
+ struct resource *mem;
+ int ret = 0;
+ switch(fb_id)
+ {
+ case 0:
+ res = platform_get_resource_byname(g_fb_pdev, IORESOURCE_MEM, "fb0 buf");
+ if (res == NULL)
+ {
+ dev_err(&g_fb_pdev->dev, "failed to get win0 memory \n");
+ ret = -ENOENT;
+ }
+ fbi->fix.smem_start = res->start;
+ fbi->fix.smem_len = res->end - res->start + 1;
+ mem = request_mem_region(res->start, resource_size(res), g_fb_pdev->name);
+ fbi->screen_base = ioremap(res->start, fbi->fix.smem_len);
+ memset(fbi->screen_base, 0, fbi->fix.smem_len);
+ printk("fb%d:phy:%lx>>vir:%p>>len:0x%x\n",fb_id,
+ fbi->fix.smem_start,fbi->screen_base,fbi->fix.smem_len);
+ #ifdef CONFIG_FB_WORK_IPP // alloc ipp buf for rotate
+ res = platform_get_resource_byname(g_fb_pdev, IORESOURCE_MEM, "ipp buf");
+ if (res == NULL)
+ {
+ dev_err(&g_fb_pdev->dev, "failed to get win1 ipp memory \n");
+ ret = -ENOENT;
+ }
+ fbi->fix.mmio_start = res->start;
+ fbi->fix.mmio_len = res->end - res->start + 1;
+ #endif
+ break;
+ case 2:
+ res = platform_get_resource_byname(g_fb_pdev, IORESOURCE_MEM, "fb2 buf");
+ if (res == NULL)
+ {
+ dev_err(&g_fb_pdev->dev, "failed to get win0 memory \n");
+ ret = -ENOENT;
+ }
+ fbi->fix.smem_start = res->start;
+ fbi->fix.smem_len = res->end - res->start + 1;
+ mem = request_mem_region(res->start, resource_size(res), g_fb_pdev->name);
+ fbi->screen_base = ioremap(res->start, fbi->fix.smem_len);
+ memset(fbi->screen_base, 0, fbi->fix.smem_len);
+ printk("fb%d:phy:%lx>>vir:%p>>len:0x%x\n",fb_id,
+ fbi->fix.smem_start,fbi->screen_base,fbi->fix.smem_len);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
}
return ret;
}
-int rk_fb_register(struct rk_lcdc_device_driver *dev_drv)
+
+static int rk_release_fb_buffer(struct fb_info *fbi)
+{
+ if(!fbi)
+ {
+ printk("no need release null fb buffer!\n");
+ return -EINVAL;
+ }
+ if(!strcmp(fbi->fix.id,"fb1")||!strcmp(fbi->fix.id,"fb3")) //buffer for fb1 and fb3 are alloc by android
+ return 0;
+ iounmap(fbi->screen_base);
+ release_mem_region(fbi->fix.smem_start,fbi->fix.smem_len);
+ return 0;
+
+}
+static int init_layer_par(struct rk_lcdc_device_driver *dev_drv)
+{
+ int i;
+ struct layer_par * def_par = NULL;
+ int num_par = dev_drv->num_layer;
+ for(i = 0; i < num_par; i++)
+ {
+ struct layer_par *par = NULL;
+ par = kzalloc(sizeof(struct layer_par), GFP_KERNEL);
+ if(!par)
+ {
+ printk(KERN_ERR "kzmalloc for layer_par fail!");
+ return -ENOMEM;
+
+ }
+ def_par = &dev_drv->def_layer_par[i];
+ strcpy(par->name,def_par->name);
+ par->id = def_par->id;
+ par->support_3d = def_par->support_3d;
+ dev_drv->layer_par[i] = par;
+ }
+
+ return 0;
+
+
+}
+
+
+static int init_lcdc_device_driver(struct rk_lcdc_device_driver *dev_drv,
+ struct rk_lcdc_device_driver *def_drv,int id)
+{
+ if(!def_drv)
+ {
+ printk(KERN_ERR "default lcdc device driver is null!\n");
+ return -EINVAL;
+ }
+ if(!dev_drv)
+ {
+ printk(KERN_ERR "lcdc device driver is null!\n");
+ return -EINVAL;
+ }
+ sprintf(dev_drv->name, "lcdc%d",id);
+ dev_drv->open = def_drv->open;
+ dev_drv->init_lcdc = def_drv->init_lcdc;
+ dev_drv->ioctl = def_drv->ioctl;
+ dev_drv->blank = def_drv->blank;
+ dev_drv->set_par = def_drv->set_par;
+ dev_drv->pan_display = def_drv->pan_display;
+ dev_drv->suspend = def_drv->suspend;
+ dev_drv->resume = def_drv->resume;
+ dev_drv->load_screen = def_drv->load_screen;
+ dev_drv->def_layer_par = def_drv->def_layer_par;
+ dev_drv->num_layer = def_drv->num_layer;
+ init_layer_par(dev_drv);
+ init_completion(&dev_drv->frame_done);
+ spin_lock_init(&dev_drv->cpl_lock);
+ dev_drv->first_frame = 1;
+
+ return 0;
+}
+
+int rk_fb_register(struct rk_lcdc_device_driver *dev_drv,
+ struct rk_lcdc_device_driver *def_drv,int id)
{
struct rk_fb_inf *fb_inf = platform_get_drvdata(g_fb_pdev);
struct fb_info *fbi;
int i=0,ret = 0;
int lcdc_id = 0;
- if(NULL==dev_drv)
+ if(NULL == dev_drv)
{
printk("null lcdc device driver?");
return -ENOENT;
return -ENOENT;
}
lcdc_id = i;
-
+ init_lcdc_device_driver(dev_drv, def_drv,id);
+ set_lcd_info(dev_drv->screen, fb_inf->mach_info->lcd_info);
+ dev_drv->init_lcdc(dev_drv);
+ dev_drv->load_screen(dev_drv,1);
/************fb set,one layer one fb ***********/
+ dev_drv->fb_index_base = fb_inf->num_fb;
for(i=0;i<dev_drv->num_layer;i++)
{
fbi= framebuffer_alloc(0, &g_fb_pdev->dev);
fbi->var.hsync_len = fb_inf->lcdc_dev_drv[lcdc_id]->screen->hsync_len;
fbi->fbops = &fb_ops;
fbi->flags = FBINFO_FLAG_DEFAULT;
- fbi->pseudo_palette = fb_inf->lcdc_dev_drv[lcdc_id]->layer_par[i].pseudo_pal;
- request_fb_buffer(fbi,fb_inf->num_fb);
+ fbi->pseudo_palette = fb_inf->lcdc_dev_drv[lcdc_id]->layer_par[i]->pseudo_pal;
+ rk_request_fb_buffer(fbi,fb_inf->num_fb);
ret = register_framebuffer(fbi);
if(ret<0)
{
printk("%s>>fb%d register_framebuffer fail!\n",__func__,fb_inf->num_fb);
ret = -EINVAL;
}
+ rkfb_create_sysfs(fbi);
fb_inf->fb[fb_inf->num_fb] = fbi;
printk("%s>>>>>%s\n",__func__,fb_inf->fb[fb_inf->num_fb]->fix.id);
fb_inf->num_fb++;
/* Start display and show logo on boot */
fb_set_cmap(&fb_inf->fb[fb_inf->num_fb-2]->cmap, fb_inf->fb[fb_inf->num_fb-2]);
fb_show_logo(fb_inf->fb[fb_inf->num_fb-2], FB_ROTATE_UR);
- fb_inf->fb[fb_inf->num_fb-2]->fbops->fb_blank(FB_BLANK_UNBLANK, fb_inf->fb[fb_inf->num_fb-2]);
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]);
}
#endif
}
-int rk_fb_unregister(struct rk_lcdc_device_driver *fb_device_driver)
+int rk_fb_unregister(struct rk_lcdc_device_driver *dev_drv)
{
struct rk_fb_inf *fb_inf = platform_get_drvdata(g_fb_pdev);
+ struct fb_info *fbi;
+ int fb_index_base = dev_drv->fb_index_base;
+ int fb_num = dev_drv->num_layer;
int i=0;
- if(NULL==fb_device_driver){
- printk("rk_fb_register lcdc register fail");
+ if(NULL == dev_drv)
+ {
+ printk(" no need to unregister null lcdc device driver!\n");
return -ENOENT;
- }
- for(i=0;i<RK30_MAX_LCDC_SUPPORT;i++){
- if(fb_inf->lcdc_dev_drv[i]->id == i ){
- fb_inf->lcdc_dev_drv[i] = NULL;
- fb_inf->num_lcdc--;
- break;
- }
}
- if(i==RK30_MAX_LCDC_SUPPORT){
- printk("rk_fb_unregister lcdc out of support %d",i);
- return -ENOENT;
+
+ for(i = 0; i < fb_num; i++)
+ {
+ kfree(dev_drv->layer_par[i]);
}
-
+
+ for(i=fb_index_base;i<(fb_index_base+fb_num);i++)
+ {
+ fbi = fb_inf->fb[i];
+ unregister_framebuffer(fbi);
+ rk_release_fb_buffer(fbi);
+ framebuffer_release(fbi);
+ }
+ fb_inf->lcdc_dev_drv[dev_drv->id]= NULL;
return 0;
}
-int init_lcdc_device_driver(struct rk_lcdc_device_driver *def_drv,
- struct rk_lcdc_device_driver *dev_drv,int id)
+
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+struct suspend_info {
+ struct early_suspend early_suspend;
+ struct rk_fb_inf *inf;
+};
+
+static void rkfb_early_suspend(struct early_suspend *h)
{
- if(!def_drv)
+ struct suspend_info *info = container_of(h, struct suspend_info,
+ early_suspend);
+ struct rk_fb_inf *inf = info->inf;
+ int i;
+ inf->mach_info->io_disable();
+ for(i = 0; i < inf->num_lcdc; i++)
{
- printk(KERN_ERR "default lcdc device driver is null!\n");
- return -EINVAL;
+ atomic_set(&inf->lcdc_dev_drv[i]->in_suspend,1);
+ inf->lcdc_dev_drv[i]->suspend(inf->lcdc_dev_drv[i]);
}
- if(!dev_drv)
+}
+static void rkfb_early_resume(struct early_suspend *h)
+{
+ struct suspend_info *info = container_of(h, struct suspend_info,
+ early_suspend);
+ struct rk_fb_inf *inf = info->inf;
+ int i;
+ inf->mach_info->io_enable();
+ for(i = 0; i < inf->num_lcdc; i++)
{
- printk(KERN_ERR "lcdc device driver is null!\n");
- return -EINVAL;
+ inf->lcdc_dev_drv[i]->resume(inf->lcdc_dev_drv[i]);
+ atomic_set(&inf->lcdc_dev_drv[i]->in_suspend,0);
}
- sprintf(dev_drv->name, "lcdc%d",id);
- dev_drv->layer_par = def_drv->layer_par;
- dev_drv->num_layer = def_drv->num_layer;
- dev_drv->ioctl = def_drv->ioctl;
- dev_drv->blank = def_drv->blank;
- dev_drv->set_par = def_drv->set_par;
- dev_drv->pan_display = def_drv->pan_display;
- dev_drv->suspend = def_drv->suspend;
- dev_drv->resume = def_drv->resume;
-
- return 0;
+
}
+
+
+
+static struct suspend_info suspend_info = {
+ .early_suspend.suspend = rkfb_early_suspend,
+ .early_suspend.resume = rkfb_early_resume,
+ .early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB,
+};
+#endif
+
static int __devinit rk_fb_probe (struct platform_device *pdev)
{
- struct rk_fb_inf *fb_inf = NULL;
- struct rk29lcd_info *lcd_info = NULL;
+ struct rk_fb_inf *fb_inf = NULL;
+ struct rk29fb_info * mach_info = NULL;
int ret = 0;
g_fb_pdev=pdev;
- lcd_info = pdev->dev.platform_data;
- /* Malloc rk_fb_inf and set it to pdev for drvdata */
- fb_inf = kmalloc(sizeof(struct rk_fb_inf), GFP_KERNEL);
+ /* Malloc rk_fb_inf and set it to pdev for drvdata */
+ fb_inf = kzalloc(sizeof(struct rk_fb_inf), GFP_KERNEL);
if(!fb_inf)
{
dev_err(&pdev->dev, ">>fb inf kmalloc fail!");
ret = -ENOMEM;
}
- memset(fb_inf, 0, sizeof(struct rk_fb_inf));
- platform_set_drvdata(pdev, fb_inf);
- if(lcd_info->io_init)
- lcd_info->io_init();
+ platform_set_drvdata(pdev,fb_inf);
+ mach_info = pdev->dev.platform_data;
+ fb_inf->mach_info = mach_info;
+ if(mach_info->io_init)
+ mach_info->io_init(NULL);
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ suspend_info.inf = fb_inf;
+ register_early_suspend(&suspend_info.early_suspend);
+#endif
printk("rk fb probe ok!\n");
return 0;
}
static int __devexit rk_fb_remove(struct platform_device *pdev)
{
- return 0;
+ struct rk_fb_inf *fb_inf = platform_get_drvdata(pdev);
+ kfree(fb_inf);
+ platform_set_drvdata(pdev, NULL);
+ return 0;
}
static void rk_fb_shutdown(struct platform_device *pdev)
{
-
+ struct rk_fb_inf *fb_inf = platform_get_drvdata(pdev);
+ kfree(fb_inf);
+ platform_set_drvdata(pdev, NULL);
}
static struct platform_driver rk_fb_driver = {
platform_driver_unregister(&rk_fb_driver);
}
-fs_initcall(rk_fb_init);
+subsys_initcall_sync(rk_fb_init);
module_exit(rk_fb_exit);