drm/rockchip: fix some loader logo bugs
authorMark Yao <mark.yao@rock-chips.com>
Fri, 31 Mar 2017 12:15:02 +0000 (20:15 +0800)
committerHuang, Tao <huangtao@rock-chips.com>
Sat, 1 Apr 2017 10:26:31 +0000 (18:26 +0800)
fix some bugs:
  1, If all connector failed to display, loader logo can't free.
  2, if first route failed to display, loder logo free unexpect,
     cause iommu crash.

Change-Id: I838c9fd6768a5ac48d8ce4175038b4620a95cd42
Signed-off-by: Mark Yao <mark.yao@rock-chips.com>
drivers/gpu/drm/rockchip/rockchip_drm_drv.c
drivers/gpu/drm/rockchip/rockchip_drm_drv.h
drivers/gpu/drm/rockchip/rockchip_drm_fb.c

index cf83cd1ec6768f970998551a0cef0f69ff3023d4..e7846ae7f9f604507457f2ab02781047e82f1daa 100644 (file)
@@ -67,6 +67,7 @@ struct rockchip_drm_mode_set {
        int ratio;
 };
 
+#ifndef MODULE
 static struct drm_crtc *find_crtc_by_node(struct drm_device *drm_dev,
                                          struct device_node *node)
 {
@@ -103,6 +104,34 @@ static struct drm_connector *find_connector_by_node(struct drm_device *drm_dev,
        return NULL;
 }
 
+void rockchip_free_loader_memory(struct drm_device *drm)
+{
+       struct rockchip_drm_private *private = drm->dev_private;
+       struct rockchip_logo *logo;
+       void *start, *end;
+
+       if (!private || !private->logo || --private->logo->count)
+               return;
+
+       logo = private->logo;
+       start = phys_to_virt(logo->start);
+       end = phys_to_virt(logo->size);
+
+       if (private->domain) {
+               iommu_unmap(private->domain, logo->dma_addr,
+                           logo->iommu_map_size);
+               drm_mm_remove_node(&logo->mm);
+       } else {
+               dma_unmap_sg(drm->dev, logo->sgt->sgl,
+                            logo->sgt->nents, DMA_TO_DEVICE);
+       }
+       sg_free_table(logo->sgt);
+       memblock_free(logo->start, logo->size);
+       free_reserved_area(start, end, -1, "drm_logo");
+       kfree(logo);
+       private->logo = NULL;
+}
+
 static int init_loader_memory(struct drm_device *drm_dev)
 {
        struct rockchip_drm_private *private = drm_dev->dev_private;
@@ -116,10 +145,6 @@ static int init_loader_memory(struct drm_device *drm_dev)
        struct resource res;
        int i, ret;
 
-       logo = devm_kmalloc(drm_dev->dev, sizeof(*logo), GFP_KERNEL);
-       if (!logo)
-               return -ENOMEM;
-
        node = of_parse_phandle(np, "memory-region", 0);
        if (!node)
                return -ENOMEM;
@@ -132,10 +157,14 @@ static int init_loader_memory(struct drm_device *drm_dev)
        if (!size)
                return -ENOMEM;
 
+       logo = kmalloc(sizeof(*logo), GFP_KERNEL);
+       if (!logo)
+               return -ENOMEM;
+
        nr_pages = PAGE_ALIGN(size) >> PAGE_SHIFT;
        pages = kmalloc_array(nr_pages, sizeof(*pages), GFP_KERNEL);
        if (!pages)
-               return -ENOMEM;
+               goto err_free_logo;
        i = 0;
        while (i < nr_pages) {
                pages[i] = phys_to_page(start);
@@ -176,7 +205,7 @@ static int init_loader_memory(struct drm_device *drm_dev)
        logo->sgt = sgt;
        logo->start = res.start;
        logo->size = size;
-       logo->count = 0;
+       logo->count = 1;
        private->logo = logo;
 
        return 0;
@@ -185,6 +214,8 @@ err_remove_node:
        drm_mm_remove_node(&logo->mm);
 err_free_pages:
        kfree(pages);
+err_free_logo:
+       kfree(logo);
 
        return ret;
 }
@@ -633,6 +664,8 @@ static void show_loader_logo(struct drm_device *drm_dev)
        if (ret)
                goto err_free_state;
 
+       rockchip_free_loader_memory(drm_dev);
+
        drm_modeset_unlock_all(drm_dev);
        return;
 
@@ -643,6 +676,7 @@ err_unlock:
        if (ret)
                dev_err(drm_dev->dev, "failed to show loader logo\n");
 }
+#endif
 
 /*
  * Attach a (component) device to the shared drm dma mapping from master drm
@@ -910,7 +944,9 @@ static int rockchip_drm_bind(struct device *dev)
 
        drm_mode_config_reset(drm_dev);
 
+#ifndef MODULE
        show_loader_logo(drm_dev);
+#endif
 
        ret = rockchip_drm_fbdev_init(drm_dev);
        if (ret)
index 521331acbf40f646117779ed71902fe72ad77ef7..f41cf66dfd91d7a0d22b97bf8ed7095a2d722b02 100644 (file)
@@ -135,6 +135,9 @@ struct rockchip_drm_private {
        struct drm_mm mm;
 };
 
+#ifndef MODULE
+void rockchip_free_loader_memory(struct drm_device *drm);
+#endif
 void rockchip_drm_atomic_work(struct work_struct *work);
 int rockchip_register_crtc_funcs(struct drm_crtc *crtc,
                                 const struct rockchip_crtc_funcs *crtc_funcs);
index 9b8d15b1e26778315cac048b5ff79bf70bba8473..c261a166ca22277ae828ce517cac229139b75e02 100644 (file)
@@ -57,27 +57,8 @@ static void rockchip_drm_fb_destroy(struct drm_framebuffer *fb)
        }
 
 #ifndef MODULE
-       if (rockchip_fb->logo) {
-               struct rockchip_drm_private *private = fb->dev->dev_private;
-               struct rockchip_logo *logo = rockchip_fb->logo;
-
-               if (!--logo->count) {
-                       void *start = phys_to_virt(logo->start);
-                       void *end = phys_to_virt(logo->size);
-
-                       if (private && private->domain) {
-                               iommu_unmap(private->domain, logo->dma_addr,
-                                           logo->iommu_map_size);
-                               drm_mm_remove_node(&logo->mm);
-                       } else {
-                               dma_unmap_sg(fb->dev->dev, logo->sgt->sgl,
-                                            logo->sgt->nents, DMA_TO_DEVICE);
-                       }
-                       sg_free_table(logo->sgt);
-                       memblock_free(logo->start, logo->size);
-                       free_reserved_area(start, end, -1, "drm_logo");
-               }
-       }
+       if (rockchip_fb->logo)
+               rockchip_free_loader_memory(fb->dev);
 #else
        WARN_ON(rockchip_fb->logo);
 #endif