From b8ca73f2480b55ed6227fe147f6d9b4db95298cc Mon Sep 17 00:00:00 2001 From: yxj Date: Wed, 28 Mar 2012 19:44:30 +0800 Subject: [PATCH] rk30 fb:add remove and shutdown code --- drivers/video/rockchip/chips/rk30_lcdc.c | 76 +++++++---- drivers/video/rockchip/rk_fb.c | 163 +++++++++++++---------- drivers/video/rockchip/rk_fb.h | 1 + 3 files changed, 143 insertions(+), 97 deletions(-) diff --git a/drivers/video/rockchip/chips/rk30_lcdc.c b/drivers/video/rockchip/chips/rk30_lcdc.c index c6a1693fb11e..a4517a590714 100644 --- a/drivers/video/rockchip/chips/rk30_lcdc.c +++ b/drivers/video/rockchip/chips/rk30_lcdc.c @@ -67,17 +67,24 @@ static int init_rk30_lcdc(struct rk30_lcdc_device *lcdc_dev) } if ((IS_ERR(lcdc_dev->aclk)) ||(IS_ERR(lcdc_dev->dclk)) || (IS_ERR(lcdc_dev->hclk))) { - printk(KERN_ERR "failed to get lcdc clk source\n"); - } + printk(KERN_ERR "failed to get lcdc%d clk source\n",lcdc_dev->id); + } clk_enable(lcdc_dev->hclk); //enable aclk for register config LcdSetBit(lcdc_dev,DSP_CTRL0, m_LCDC_AXICLK_AUTO_ENABLE);//eanble axi-clk auto gating for low power LcdWrReg(lcdc_dev, REG_CFG_DONE, 0x01); // write any value to REG_CFG_DONE let config become effective return 0; } -int rk30_lcdc_deinit(void) +static int rk30_lcdc_deinit(struct rk30_lcdc_device *lcdc_dev) { - return 0; + clk_disable(lcdc_dev->aclk); + clk_disable(lcdc_dev->dclk); + clk_disable(lcdc_dev->hclk); + clk_put(lcdc_dev->aclk); + clk_put(lcdc_dev->dclk); + clk_put(lcdc_dev->hclk); + + return 0; } int rk30_load_screen(struct rk30_lcdc_device*lcdc_dev, bool initscreen) @@ -183,7 +190,7 @@ int rk30_load_screen(struct rk30_lcdc_device*lcdc_dev, bool initscreen) ret = clk_set_rate(lcdc_dev->dclk, screen->pixclock); if(ret) { - printk(KERN_ERR ">>>>>> set lcdc dclk failed\n"); + printk(KERN_ERR ">>>>>> set lcdc%d dclk failed\n",lcdc_dev->id); } lcdc_dev->driver.pixclock = lcdc_dev->pixclock = div_u64(1000000000000llu, clk_get_rate(lcdc_dev->dclk)); clk_enable(lcdc_dev->dclk); @@ -195,7 +202,7 @@ int rk30_load_screen(struct rk30_lcdc_device*lcdc_dev, bool initscreen) ret = clk_set_rate(lcdc_dev->aclk, screen->lcdc_aclk); if(ret) { - printk(KERN_ERR ">>>>>> set lcdc aclk rate failed\n"); + printk(KERN_ERR ">>>>>> set lcdc%d aclk rate failed\n",lcdc_dev->id); } clk_enable(lcdc_dev->aclk); @@ -224,14 +231,14 @@ static int win0_blank(int blank_mode,struct rk30_lcdc_device *lcdc_dev) switch(blank_mode) { case FB_BLANK_UNBLANK: - LcdMskReg(lcdc_dev, SYS_CTRL1, m_W0_EN, v_W0_EN(1)); - break; - case FB_BLANK_NORMAL: - LcdMskReg(lcdc_dev, SYS_CTRL1, m_W0_EN, v_W0_EN(0)); - break; - default: - LcdMskReg(lcdc_dev, SYS_CTRL1, m_W0_EN, v_W1_EN(1)); - break; + LcdMskReg(lcdc_dev, SYS_CTRL1, m_W0_EN, v_W0_EN(1)); + break; + case FB_BLANK_NORMAL: + LcdMskReg(lcdc_dev, SYS_CTRL1, m_W0_EN, v_W0_EN(0)); + break; + default: + LcdMskReg(lcdc_dev, SYS_CTRL1, m_W0_EN, v_W1_EN(1)); + break; } mcu_refresh(lcdc_dev); return 0; @@ -241,17 +248,17 @@ static int win1_blank(int blank_mode, struct rk30_lcdc_device *lcdc_dev) { printk(KERN_INFO "%s>>>>>>>>>>mode:%d\n",__func__,blank_mode); switch(blank_mode) - { - case FB_BLANK_UNBLANK: - LcdMskReg(lcdc_dev, SYS_CTRL1, m_W1_EN, v_W1_EN(1)); - break; - case FB_BLANK_NORMAL: - LcdMskReg(lcdc_dev, SYS_CTRL1, m_W1_EN, v_W1_EN(0)); - break; - default: - LcdMskReg(lcdc_dev, SYS_CTRL1, m_W1_EN, v_W1_EN(0)); - break; - } + { + case FB_BLANK_UNBLANK: + LcdMskReg(lcdc_dev, SYS_CTRL1, m_W1_EN, v_W1_EN(1)); + break; + case FB_BLANK_NORMAL: + LcdMskReg(lcdc_dev, SYS_CTRL1, m_W1_EN, v_W1_EN(0)); + break; + default: + LcdMskReg(lcdc_dev, SYS_CTRL1, m_W1_EN, v_W1_EN(0)); + break; + } //mcu_refresh(inf); return 0; @@ -269,7 +276,8 @@ static int rk30_lcdc_blank(struct rk_lcdc_device_driver*lcdc_drv,int layer_id,in } LcdWrReg(lcdc_dev, REG_CFG_DONE, 0x01); - return 0; + + return 0; } static int win0_display(struct rk30_lcdc_device *lcdc_dev,struct layer_par *par ) @@ -581,6 +589,7 @@ static int __devinit rk30_lcdc_probe (struct platform_device *pdev) goto err1; } lcdc_dev->reg_phy_base = res->start; + lcdc_dev->len = resource_size(res); mem = request_mem_region(lcdc_dev->reg_phy_base, resource_size(res), pdev->name); if (mem == NULL) { @@ -641,12 +650,25 @@ err0: } static int __devexit rk30_lcdc_remove(struct platform_device *pdev) { + struct rk30_lcdc_device *lcdc_dev = platform_get_drvdata(pdev); + rk_fb_unregister(&(lcdc_dev->driver)); + rk30_lcdc_deinit(lcdc_dev); + iounmap(lcdc_dev->reg_vir_base); + release_mem_region(lcdc_dev->reg_phy_base,lcdc_dev->len); + kfree(lcdc_dev->screen); + kfree(lcdc_dev); return 0; } static void rk30_lcdc_shutdown(struct platform_device *pdev) { - + struct rk30_lcdc_device *lcdc_dev = platform_get_drvdata(pdev); + rk_fb_unregister(&(lcdc_dev->driver)); + rk30_lcdc_deinit(lcdc_dev); + iounmap(lcdc_dev->reg_vir_base); + release_mem_region(lcdc_dev->reg_phy_base,lcdc_dev->len); + kfree(lcdc_dev->screen); + kfree(lcdc_dev); } diff --git a/drivers/video/rockchip/rk_fb.c b/drivers/video/rockchip/rk_fb.c index f1abbee15593..4cebdf078b09 100644 --- a/drivers/video/rockchip/rk_fb.c +++ b/drivers/video/rockchip/rk_fb.c @@ -519,64 +519,81 @@ void rk_direct_fb_show(struct fb_info * 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; } + +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; + +} int rk_fb_register(struct rk_lcdc_device_driver *dev_drv) { 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; @@ -599,6 +616,7 @@ int rk_fb_register(struct rk_lcdc_device_driver *dev_drv) lcdc_id = i; /************fb set,one layer one fb ***********/ + dev_drv->fb_index_base = fb_inf->num_fb; for(i=0;inum_layer;i++) { fbi= framebuffer_alloc(0, &g_fb_pdev->dev); @@ -629,7 +647,7 @@ int rk_fb_register(struct rk_lcdc_device_driver *dev_drv) 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); + rk_request_fb_buffer(fbi,fb_inf->num_fb); ret = register_framebuffer(fbi); if(ret<0) { @@ -654,27 +672,28 @@ int rk_fb_register(struct rk_lcdc_device_driver *dev_drv) } -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;ilcdc_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=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; } @@ -706,20 +725,19 @@ int init_lcdc_device_driver(struct rk_lcdc_device_driver *def_drv, } static int __devinit rk_fb_probe (struct platform_device *pdev) { - struct rk_fb_inf *fb_inf = NULL; + struct rk_fb_inf *fb_inf = NULL; struct rk29lcd_info *lcd_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); + platform_set_drvdata(pdev,fb_inf); if(lcd_info->io_init) lcd_info->io_init(); printk("rk fb probe ok!\n"); @@ -728,12 +746,17 @@ static int __devinit rk_fb_probe (struct platform_device *pdev) 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 = { diff --git a/drivers/video/rockchip/rk_fb.h b/drivers/video/rockchip/rk_fb.h index 4c3795eb43ce..85433919afba 100644 --- a/drivers/video/rockchip/rk_fb.h +++ b/drivers/video/rockchip/rk_fb.h @@ -180,6 +180,7 @@ struct rk_lcdc_device_driver{ struct layer_par *layer_par; int num_layer; + int fb_index_base; //the first fb index of the lcdc device rk_screen *screen; u32 pixclock; int (*ioctl)(struct rk_lcdc_device_driver *dev_drv, unsigned int cmd,unsigned long arg,int layer_id); -- 2.34.1