rk30 fb:add remove and shutdown code
authoryxj <yxj@rock-chips.com>
Wed, 28 Mar 2012 11:44:30 +0000 (19:44 +0800)
committeryxj <yxj@rock-chips.com>
Wed, 28 Mar 2012 11:45:28 +0000 (19:45 +0800)
drivers/video/rockchip/chips/rk30_lcdc.c
drivers/video/rockchip/rk_fb.c
drivers/video/rockchip/rk_fb.h

index c6a1693fb11e5bb77936180d9023bb94c24369a7..a4517a590714795e06754782b48e9bb4ab661456 100644 (file)
@@ -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);
 }
 
 
index f1abbee15593027dddca97ef7e4e01a90d51b001..4cebdf078b0977810def4088697c22dcd9ed234a 100644 (file)
@@ -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;i<dev_drv->num_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;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=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 = {
index 4c3795eb43ce5261dc236b25d1018adc1b1c4bdd..85433919afba862dae16c06fedf1b96dd2f76fb5 100644 (file)
@@ -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);