diff options
Diffstat (limited to 'drivers/gpu/drm/exynos/exynos_drm_fb.c')
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_fb.c | 190 |
1 files changed, 72 insertions, 118 deletions
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c index 48d29cfd5240..3733fe6723d3 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fb.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c @@ -29,9 +29,10 @@ #include "drmP.h" #include "drm_crtc.h" #include "drm_crtc_helper.h" +#include "drm_fb_helper.h" +#include "exynos_drm_drv.h" #include "exynos_drm_fb.h" -#include "exynos_drm_buf.h" #include "exynos_drm_gem.h" #define to_exynos_fb(x) container_of(x, struct exynos_drm_fb, fb) @@ -40,15 +41,11 @@ * exynos specific framebuffer structure. * * @fb: drm framebuffer obejct. - * @exynos_gem_obj: exynos specific gem object containing a gem object. - * @entry: pointer to exynos drm buffer entry object. - * - containing only the information to physically continuous memory - * region allocated at default framebuffer creation. + * @exynos_gem_obj: array of exynos specific gem object containing a gem object. */ struct exynos_drm_fb { struct drm_framebuffer fb; - struct exynos_drm_gem_obj *exynos_gem_obj; - struct exynos_drm_buf_entry *entry; + struct exynos_drm_gem_obj *exynos_gem_obj[MAX_FB_BUFFER]; }; static void exynos_drm_fb_destroy(struct drm_framebuffer *fb) @@ -59,13 +56,6 @@ static void exynos_drm_fb_destroy(struct drm_framebuffer *fb) drm_framebuffer_cleanup(fb); - /* - * default framebuffer has no gem object so - * a buffer of the default framebuffer should be released at here. - */ - if (!exynos_fb->exynos_gem_obj && exynos_fb->entry) - exynos_drm_buf_destroy(fb->dev, exynos_fb->entry); - kfree(exynos_fb); exynos_fb = NULL; } @@ -79,7 +69,7 @@ static int exynos_drm_fb_create_handle(struct drm_framebuffer *fb, DRM_DEBUG_KMS("%s\n", __FILE__); return drm_gem_handle_create(file_priv, - &exynos_fb->exynos_gem_obj->base, handle); + &exynos_fb->exynos_gem_obj[0]->base, handle); } static int exynos_drm_fb_dirty(struct drm_framebuffer *fb, @@ -100,146 +90,110 @@ static struct drm_framebuffer_funcs exynos_drm_fb_funcs = { .dirty = exynos_drm_fb_dirty, }; -static struct drm_framebuffer * -exynos_drm_fb_init(struct drm_file *file_priv, struct drm_device *dev, - struct drm_mode_fb_cmd *mode_cmd) +struct drm_framebuffer * +exynos_drm_framebuffer_init(struct drm_device *dev, + struct drm_mode_fb_cmd2 *mode_cmd, + struct drm_gem_object *obj) { struct exynos_drm_fb *exynos_fb; - struct drm_framebuffer *fb; - struct exynos_drm_gem_obj *exynos_gem_obj = NULL; - struct drm_gem_object *obj; - unsigned int size; int ret; - DRM_DEBUG_KMS("%s\n", __FILE__); - - mode_cmd->pitch = max(mode_cmd->pitch, - mode_cmd->width * (mode_cmd->bpp >> 3)); - - DRM_LOG_KMS("drm fb create(%dx%d)\n", - mode_cmd->width, mode_cmd->height); - exynos_fb = kzalloc(sizeof(*exynos_fb), GFP_KERNEL); if (!exynos_fb) { - DRM_ERROR("failed to allocate exynos drm framebuffer.\n"); + DRM_ERROR("failed to allocate exynos drm framebuffer\n"); return ERR_PTR(-ENOMEM); } - fb = &exynos_fb->fb; - ret = drm_framebuffer_init(dev, fb, &exynos_drm_fb_funcs); + ret = drm_framebuffer_init(dev, &exynos_fb->fb, &exynos_drm_fb_funcs); if (ret) { - DRM_ERROR("failed to initialize framebuffer.\n"); - goto err_init; + DRM_ERROR("failed to initialize framebuffer\n"); + return ERR_PTR(ret); } - DRM_LOG_KMS("create: fb id: %d\n", fb->base.id); + drm_helper_mode_fill_fb_struct(&exynos_fb->fb, mode_cmd); + exynos_fb->exynos_gem_obj[0] = to_exynos_gem_obj(obj); - size = mode_cmd->pitch * mode_cmd->height; + return &exynos_fb->fb; +} - /* - * mode_cmd->handle could be NULL at booting time or - * with user request. if NULL, a new buffer or a gem object - * would be allocated. - */ - if (!mode_cmd->handle) { - if (!file_priv) { - struct exynos_drm_buf_entry *entry; - - /* - * in case that file_priv is NULL, it allocates - * only buffer and this buffer would be used - * for default framebuffer. - */ - entry = exynos_drm_buf_create(dev, size); - if (IS_ERR(entry)) { - ret = PTR_ERR(entry); - goto err_buffer; - } - - exynos_fb->entry = entry; - - DRM_LOG_KMS("default fb: paddr = 0x%lx, size = 0x%x\n", - (unsigned long)entry->paddr, size); - - goto out; - } else { - exynos_gem_obj = exynos_drm_gem_create(file_priv, dev, - size, - &mode_cmd->handle); - if (IS_ERR(exynos_gem_obj)) { - ret = PTR_ERR(exynos_gem_obj); - goto err_buffer; - } - } - } else { - obj = drm_gem_object_lookup(dev, file_priv, mode_cmd->handle); - if (!obj) { - DRM_ERROR("failed to lookup gem object.\n"); - goto err_buffer; - } +static struct drm_framebuffer * +exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv, + struct drm_mode_fb_cmd2 *mode_cmd) +{ + struct drm_gem_object *obj; + struct drm_framebuffer *fb; + struct exynos_drm_fb *exynos_fb; + int nr; + int i; - exynos_gem_obj = to_exynos_gem_obj(obj); + DRM_DEBUG_KMS("%s\n", __FILE__); - drm_gem_object_unreference_unlocked(obj); + obj = drm_gem_object_lookup(dev, file_priv, mode_cmd->handles[0]); + if (!obj) { + DRM_ERROR("failed to lookup gem object\n"); + return ERR_PTR(-ENOENT); } - /* - * if got a exynos_gem_obj from either a handle or - * a new creation then exynos_fb->exynos_gem_obj is NULL - * so that default framebuffer has no its own gem object, - * only its own buffer object. - */ - exynos_fb->entry = exynos_gem_obj->entry; - - DRM_LOG_KMS("paddr = 0x%lx, size = 0x%x, gem object = 0x%x\n", - (unsigned long)exynos_fb->entry->paddr, size, - (unsigned int)&exynos_gem_obj->base); + drm_gem_object_unreference_unlocked(obj); -out: - exynos_fb->exynos_gem_obj = exynos_gem_obj; + fb = exynos_drm_framebuffer_init(dev, mode_cmd, obj); + if (IS_ERR(fb)) + return fb; - drm_helper_mode_fill_fb_struct(fb, mode_cmd); + exynos_fb = to_exynos_fb(fb); + nr = exynos_drm_format_num_buffers(fb->pixel_format); - return fb; - -err_buffer: - drm_framebuffer_cleanup(fb); - -err_init: - kfree(exynos_fb); + for (i = 1; i < nr; i++) { + obj = drm_gem_object_lookup(dev, file_priv, + mode_cmd->handles[i]); + if (!obj) { + DRM_ERROR("failed to lookup gem object\n"); + exynos_drm_fb_destroy(fb); + return ERR_PTR(-ENOENT); + } - return ERR_PTR(ret); -} + drm_gem_object_unreference_unlocked(obj); -struct drm_framebuffer *exynos_drm_fb_create(struct drm_device *dev, - struct drm_file *file_priv, - struct drm_mode_fb_cmd *mode_cmd) -{ - DRM_DEBUG_KMS("%s\n", __FILE__); + exynos_fb->exynos_gem_obj[i] = to_exynos_gem_obj(obj); + } - return exynos_drm_fb_init(file_priv, dev, mode_cmd); + return fb; } -struct exynos_drm_buf_entry *exynos_drm_fb_get_buf(struct drm_framebuffer *fb) +struct exynos_drm_gem_buf *exynos_drm_fb_buffer(struct drm_framebuffer *fb, + int index) { struct exynos_drm_fb *exynos_fb = to_exynos_fb(fb); - struct exynos_drm_buf_entry *entry; + struct exynos_drm_gem_buf *buffer; DRM_DEBUG_KMS("%s\n", __FILE__); - entry = exynos_fb->entry; - if (!entry) + if (index >= MAX_FB_BUFFER) return NULL; - DRM_DEBUG_KMS("vaddr = 0x%lx, paddr = 0x%lx\n", - (unsigned long)entry->vaddr, - (unsigned long)entry->paddr); + buffer = exynos_fb->exynos_gem_obj[index]->buffer; + if (!buffer) + return NULL; + + DRM_DEBUG_KMS("vaddr = 0x%lx, dma_addr = 0x%lx\n", + (unsigned long)buffer->kvaddr, + (unsigned long)buffer->dma_addr); + + return buffer; +} + +static void exynos_drm_output_poll_changed(struct drm_device *dev) +{ + struct exynos_drm_private *private = dev->dev_private; + struct drm_fb_helper *fb_helper = private->fb_helper; - return entry; + if (fb_helper) + drm_fb_helper_hotplug_event(fb_helper); } static struct drm_mode_config_funcs exynos_drm_mode_config_funcs = { - .fb_create = exynos_drm_fb_create, + .fb_create = exynos_user_fb_create, + .output_poll_changed = exynos_drm_output_poll_changed, }; void exynos_drm_mode_config_init(struct drm_device *dev) |