From 17deffbf4281e3364b1bb1fb382976004aaddf91 Mon Sep 17 00:00:00 2001 From: Mark Yao Date: Mon, 1 Aug 2016 17:34:23 +0800 Subject: [PATCH] drm/rockchip: support add fb from dev resource Change-Id: I980af965d83de25c433ba5424bab2ad063534bcb Signed-off-by: Mark Yao --- drivers/gpu/drm/rockchip/rockchip_drm_fb.c | 116 ++++++++++++++++---- drivers/gpu/drm/rockchip/rockchip_drm_fb.h | 9 +- drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 15 +-- 3 files changed, 105 insertions(+), 35 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c index f1631e3dd3d9..0406702c74e2 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "rockchip_drm_drv.h" #include "rockchip_drm_gem.h" @@ -26,23 +27,28 @@ struct rockchip_drm_fb { struct drm_framebuffer fb; + dma_addr_t dma_addr[ROCKCHIP_MAX_FB_BUFFER]; struct drm_gem_object *obj[ROCKCHIP_MAX_FB_BUFFER]; + struct sg_table *sgt; + phys_addr_t start; + phys_addr_t size; }; -struct drm_gem_object *rockchip_fb_get_gem_obj(struct drm_framebuffer *fb, - unsigned int plane) +dma_addr_t rockchip_fb_get_dma_addr(struct drm_framebuffer *fb, + unsigned int plane, struct device *dev) { struct rockchip_drm_fb *rk_fb = to_rockchip_fb(fb); - if (plane >= ROCKCHIP_MAX_FB_BUFFER) - return NULL; + if (WARN_ON(plane >= ROCKCHIP_MAX_FB_BUFFER)) + return 0; - return rk_fb->obj[plane]; + return rk_fb->dma_addr[plane]; } static void rockchip_drm_fb_destroy(struct drm_framebuffer *fb) { struct rockchip_drm_fb *rockchip_fb = to_rockchip_fb(fb); + struct drm_device *dev = fb->dev; struct drm_gem_object *obj; int i; @@ -52,6 +58,17 @@ static void rockchip_drm_fb_destroy(struct drm_framebuffer *fb) drm_gem_object_unreference_unlocked(obj); } + if (rockchip_fb->sgt) { + void *start = phys_to_virt(rockchip_fb->start); + void *end = phys_to_virt(rockchip_fb->size); + + dma_unmap_sg(dev->dev, rockchip_fb->sgt->sgl, + rockchip_fb->sgt->nents, DMA_TO_DEVICE); + sg_free_table(rockchip_fb->sgt); + memblock_free(rockchip_fb->start, rockchip_fb->size); + free_reserved_area(start, end, -1, "drm_fb"); + } + drm_framebuffer_cleanup(fb); kfree(rockchip_fb); } @@ -71,12 +88,14 @@ static const struct drm_framebuffer_funcs rockchip_drm_fb_funcs = { .create_handle = rockchip_drm_fb_create_handle, }; -static struct rockchip_drm_fb * +struct drm_framebuffer * rockchip_fb_alloc(struct drm_device *dev, struct drm_mode_fb_cmd2 *mode_cmd, - struct drm_gem_object **obj, unsigned int num_planes) + struct drm_gem_object **obj, struct resource *res, + unsigned int num_planes) { struct rockchip_drm_fb *rockchip_fb; - int ret; + struct rockchip_gem_object *rk_obj; + int ret = 0; int i; rockchip_fb = kzalloc(sizeof(*rockchip_fb), GFP_KERNEL); @@ -85,26 +104,77 @@ rockchip_fb_alloc(struct drm_device *dev, struct drm_mode_fb_cmd2 *mode_cmd, drm_helper_mode_fill_fb_struct(&rockchip_fb->fb, mode_cmd); - for (i = 0; i < num_planes; i++) - rockchip_fb->obj[i] = obj[i]; - ret = drm_framebuffer_init(dev, &rockchip_fb->fb, &rockchip_drm_fb_funcs); if (ret) { dev_err(dev->dev, "Failed to initialize framebuffer: %d\n", ret); - kfree(rockchip_fb); - return ERR_PTR(ret); + goto err_free_fb; } - return rockchip_fb; + if (obj) { + for (i = 0; i < num_planes; i++) + rockchip_fb->obj[i] = obj[i]; + + for (i = 0; i < num_planes; i++) { + rk_obj = to_rockchip_obj(obj[i]); + rockchip_fb->dma_addr[i] = rk_obj->dma_addr; + } + } else if (res) { + unsigned long nr_pages; + struct page **pages; + struct sg_table *sgt; + DEFINE_DMA_ATTRS(attrs); + phys_addr_t start = res->start; + phys_addr_t size = res->end - res->start; + + nr_pages = PAGE_ALIGN(size) >> PAGE_SHIFT; + pages = kmalloc_array(nr_pages, sizeof(*pages), GFP_KERNEL); + if (!pages) { + ret = -ENOMEM; + goto err_deinit_drm_fb; + } + i = 0; + while (i < nr_pages) { + pages[i] = phys_to_page(start); + start += PAGE_SIZE; + i++; + } + sgt = drm_prime_pages_to_sg(pages, nr_pages); + if (IS_ERR(sgt)) { + kfree(pages); + ret = PTR_ERR(sgt); + goto err_deinit_drm_fb; + } + + dma_set_attr(DMA_ATTR_SKIP_CPU_SYNC, &attrs); + dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &attrs); + dma_map_sg_attrs(dev->dev, sgt->sgl, sgt->nents, + DMA_TO_DEVICE, &attrs); + rockchip_fb->dma_addr[0] = sg_dma_address(sgt->sgl); + rockchip_fb->sgt = sgt; + rockchip_fb->start = res->start; + rockchip_fb->size = size; + } else { + ret = -EINVAL; + dev_err(dev->dev, "Failed to find available buffer\n"); + goto err_deinit_drm_fb; + } + + return &rockchip_fb->fb; + +err_deinit_drm_fb: + drm_framebuffer_cleanup(&rockchip_fb->fb); +err_free_fb: + kfree(rockchip_fb); + return ERR_PTR(ret); } static struct drm_framebuffer * rockchip_user_fb_create(struct drm_device *dev, struct drm_file *file_priv, struct drm_mode_fb_cmd2 *mode_cmd) { - struct rockchip_drm_fb *rockchip_fb; + struct drm_framebuffer *fb; struct drm_gem_object *objs[ROCKCHIP_MAX_FB_BUFFER]; struct drm_gem_object *obj; unsigned int hsub; @@ -143,13 +213,13 @@ rockchip_user_fb_create(struct drm_device *dev, struct drm_file *file_priv, objs[i] = obj; } - rockchip_fb = rockchip_fb_alloc(dev, mode_cmd, objs, i); - if (IS_ERR(rockchip_fb)) { - ret = PTR_ERR(rockchip_fb); + fb = rockchip_fb_alloc(dev, mode_cmd, objs, NULL, i); + if (IS_ERR(fb)) { + ret = PTR_ERR(fb); goto err_gem_object_unreference; } - return &rockchip_fb->fb; + return fb; err_gem_object_unreference: for (i--; i >= 0; i--) @@ -317,13 +387,13 @@ rockchip_drm_framebuffer_init(struct drm_device *dev, struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object *obj) { - struct rockchip_drm_fb *rockchip_fb; + struct drm_framebuffer *fb; - rockchip_fb = rockchip_fb_alloc(dev, mode_cmd, &obj, 1); - if (IS_ERR(rockchip_fb)) + fb = rockchip_fb_alloc(dev, mode_cmd, &obj, NULL, 1); + if (IS_ERR(fb)) return NULL; - return &rockchip_fb->fb; + return fb; } void rockchip_drm_mode_config_init(struct drm_device *dev) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.h b/drivers/gpu/drm/rockchip/rockchip_drm_fb.h index 09574d48226f..df6111ef2a58 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.h @@ -23,6 +23,11 @@ void rockchip_drm_framebuffer_fini(struct drm_framebuffer *fb); void rockchip_drm_mode_config_init(struct drm_device *dev); -struct drm_gem_object *rockchip_fb_get_gem_obj(struct drm_framebuffer *fb, - unsigned int plane); +struct drm_framebuffer * +rockchip_fb_alloc(struct drm_device *dev, struct drm_mode_fb_cmd2 *mode_cmd, + struct drm_gem_object **obj, struct resource *res, + unsigned int num_planes); + +dma_addr_t rockchip_fb_get_dma_addr(struct drm_framebuffer *fb, + unsigned int plane, struct device *dev); #endif /* _ROCKCHIP_DRM_FB_H */ diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index 1013131dde47..aeb5b6cd74bd 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -760,8 +760,6 @@ static void vop_plane_atomic_update(struct drm_plane *plane, uint32_t act_info, dsp_info, dsp_st; struct drm_rect *src = &vop_plane_state->src; struct drm_rect *dest = &vop_plane_state->dest; - struct drm_gem_object *obj, *uv_obj; - struct rockchip_gem_object *rk_obj, *rk_uv_obj; unsigned long offset; dma_addr_t dma_addr; int ymirror, xmirror; @@ -779,9 +777,6 @@ static void vop_plane_atomic_update(struct drm_plane *plane, return; } - obj = rockchip_fb_get_gem_obj(fb, 0); - rk_obj = to_rockchip_obj(obj); - actual_w = drm_rect_width(src) >> 16; actual_h = drm_rect_height(src) >> 16; act_info = (actual_h - 1) << 16 | ((actual_w - 1) & 0xffff); @@ -798,7 +793,9 @@ static void vop_plane_atomic_update(struct drm_plane *plane, offset += ((src->y2 >> 16) - 1) * fb->pitches[0]; else offset += (src->y1 >> 16) * fb->pitches[0]; - vop_plane_state->yrgb_mst = rk_obj->dma_addr + offset + fb->offsets[0]; + + dma_addr = rockchip_fb_get_dma_addr(fb, 0, vop->dev); + vop_plane_state->yrgb_mst = dma_addr + offset + fb->offsets[0]; ymirror = !!(state->rotation & BIT(DRM_REFLECT_Y)); xmirror = !!(state->rotation & BIT(DRM_REFLECT_X)); @@ -815,13 +812,11 @@ static void vop_plane_atomic_update(struct drm_plane *plane, int vsub = drm_format_vert_chroma_subsampling(fb->pixel_format); int bpp = drm_format_plane_cpp(fb->pixel_format, 1); - uv_obj = rockchip_fb_get_gem_obj(fb, 1); - rk_uv_obj = to_rockchip_obj(uv_obj); - offset = (src->x1 >> 16) * bpp / hsub; offset += (src->y1 >> 16) * fb->pitches[1] / vsub; - dma_addr = rk_uv_obj->dma_addr + offset + fb->offsets[1]; + dma_addr = rockchip_fb_get_dma_addr(fb, 1, vop->dev); + dma_addr += offset + fb->offsets[1]; VOP_WIN_SET(vop, win, uv_vir, fb->pitches[1] >> 2); VOP_WIN_SET(vop, win, uv_mst, dma_addr); } -- 2.34.1