drm/rockchip: fix some loader logo bugs

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>
This commit is contained in:
Mark Yao
2017-03-31 20:15:02 +08:00
committed by Huang, Tao
parent 285e2a5602
commit b52e568407
3 changed files with 47 additions and 27 deletions

View 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)

View 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);

View 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