diff options
Diffstat (limited to 'drivers/gpu/drm/exynos/exynos_drm_fbdev.c')
| -rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_fbdev.c | 118 |
1 files changed, 58 insertions, 60 deletions
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c index 9526a25e90ac..8641c9e84d4c 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c @@ -16,11 +16,13 @@ #include <drm/drm_framebuffer.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_prime.h> +#include <drm/drm_print.h> #include <drm/exynos_drm.h> #include "exynos_drm_drv.h" #include "exynos_drm_fb.h" #include "exynos_drm_fbdev.h" +#include "exynos_drm_gem.h" #define MAX_CONNECTOR 4 @@ -35,15 +37,11 @@ static int exynos_drm_fb_mmap(struct fb_info *info, struct vm_area_struct *vma) static void exynos_drm_fb_destroy(struct fb_info *info) { struct drm_fb_helper *fb_helper = info->par; - struct drm_framebuffer *fb = fb_helper->fb; drm_fb_helper_fini(fb_helper); - drm_framebuffer_remove(fb); - + drm_client_buffer_delete(fb_helper->buffer); drm_client_release(&fb_helper->client); - drm_fb_helper_unprepare(fb_helper); - kfree(fb_helper); } static const struct fb_ops exynos_drm_fb_ops = { @@ -55,47 +53,23 @@ static const struct fb_ops exynos_drm_fb_ops = { .fb_destroy = exynos_drm_fb_destroy, }; -static int exynos_drm_fbdev_update(struct drm_fb_helper *helper, - struct drm_fb_helper_surface_size *sizes, - struct exynos_drm_gem *exynos_gem) -{ - struct fb_info *fbi; - struct drm_framebuffer *fb = helper->fb; - unsigned int size = fb->width * fb->height * fb->format->cpp[0]; - unsigned long offset; - - fbi = drm_fb_helper_alloc_info(helper); - if (IS_ERR(fbi)) { - DRM_DEV_ERROR(to_dma_dev(helper->dev), - "failed to allocate fb info.\n"); - return PTR_ERR(fbi); - } - - fbi->fbops = &exynos_drm_fb_ops; - - drm_fb_helper_fill_info(fbi, helper, sizes); - - offset = fbi->var.xoffset * fb->format->cpp[0]; - offset += fbi->var.yoffset * fb->pitches[0]; - - fbi->flags |= FBINFO_VIRTFB; - fbi->screen_buffer = exynos_gem->kvaddr + offset; - fbi->screen_size = size; - fbi->fix.smem_len = size; - - return 0; -} - static const struct drm_fb_helper_funcs exynos_drm_fbdev_helper_funcs = { }; int exynos_drm_fbdev_driver_fbdev_probe(struct drm_fb_helper *helper, struct drm_fb_helper_surface_size *sizes) { + struct drm_client_dev *client = &helper->client; + struct drm_device *dev = client->dev; + struct drm_file *file = client->file; + struct fb_info *info = helper->info; + u32 fourcc, pitch; + u64 size; + const struct drm_format_info *format; struct exynos_drm_gem *exynos_gem; - struct drm_device *dev = helper->dev; - struct drm_mode_fb_cmd2 mode_cmd = { 0 }; - unsigned long size; + struct drm_gem_object *obj; + struct drm_client_buffer *buffer; + u32 handle; int ret; DRM_DEV_DEBUG_KMS(dev->dev, @@ -103,37 +77,61 @@ int exynos_drm_fbdev_driver_fbdev_probe(struct drm_fb_helper *helper, sizes->surface_width, sizes->surface_height, sizes->surface_bpp); - mode_cmd.width = sizes->surface_width; - mode_cmd.height = sizes->surface_height; - mode_cmd.pitches[0] = sizes->surface_width * (sizes->surface_bpp >> 3); - mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, - sizes->surface_depth); - - size = mode_cmd.pitches[0] * mode_cmd.height; + fourcc = drm_mode_legacy_fb_format(sizes->surface_bpp, sizes->surface_depth); + if (fourcc == DRM_FORMAT_INVALID) + return -EINVAL; + format = drm_get_format_info(dev, fourcc, DRM_FORMAT_MOD_LINEAR); + if (!format) + return -EINVAL; + pitch = drm_format_info_min_pitch(format, 0, sizes->surface_width); + if (!pitch) + return -EINVAL; + if (check_mul_overflow(pitch, sizes->surface_height, &size)) + return -EINVAL; + size = ALIGN(size, PAGE_SIZE); + if (size < PAGE_SIZE) + return -EINVAL; exynos_gem = exynos_drm_gem_create(dev, EXYNOS_BO_WC, size, true); if (IS_ERR(exynos_gem)) return PTR_ERR(exynos_gem); + obj = &exynos_gem->base; - helper->fb = - exynos_drm_framebuffer_init(dev, &mode_cmd, &exynos_gem, 1); - if (IS_ERR(helper->fb)) { - DRM_DEV_ERROR(dev->dev, "failed to create drm framebuffer.\n"); - ret = PTR_ERR(helper->fb); - goto err_destroy_gem; + ret = drm_gem_handle_create(file, obj, &handle); + if (ret) + goto err_drm_gem_object_put; + + buffer = drm_client_buffer_create(client, sizes->surface_width, sizes->surface_height, + fourcc, handle, pitch); + if (IS_ERR(buffer)) { + ret = PTR_ERR(buffer); + goto err_drm_gem_handle_delete; } + helper->funcs = &exynos_drm_fbdev_helper_funcs; + helper->buffer = buffer; + helper->fb = buffer->fb; + + info->fbops = &exynos_drm_fb_ops; + + drm_fb_helper_fill_info(info, helper, sizes); + + info->flags |= FBINFO_VIRTFB; + info->screen_buffer = exynos_gem->kvaddr; + info->screen_size = obj->size; + info->fix.smem_len = obj->size; + + /* The handle is only needed for creating the framebuffer. */ + drm_gem_handle_delete(file, handle); - ret = exynos_drm_fbdev_update(helper, sizes, exynos_gem); - if (ret < 0) - goto err_destroy_framebuffer; + /* The framebuffer still holds a reference on the GEM object. */ + drm_gem_object_put(obj); return 0; -err_destroy_framebuffer: - drm_framebuffer_cleanup(helper->fb); - helper->fb = NULL; -err_destroy_gem: - exynos_drm_gem_destroy(exynos_gem); +err_drm_gem_handle_delete: + drm_gem_handle_delete(file, handle); +err_drm_gem_object_put: + drm_gem_object_put(obj); return ret; } |
