summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/exynos/exynos_drm_fbdev.c')
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fbdev.c118
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;
}