diff options
Diffstat (limited to 'drivers/gpu/drm/exynos/exynos_drm_fbdev.c')
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_fbdev.c | 150 |
1 files changed, 72 insertions, 78 deletions
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c index d1de49530c48..ea4b3d248aac 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c @@ -8,17 +8,12 @@ * Seung-Woo Kim <sw0312.kim@samsung.com> */ -#include <linux/console.h> -#include <linux/dma-mapping.h> -#include <linux/vmalloc.h> - -#include <drm/drm_crtc.h> +#include <drm/drm_crtc_helper.h> +#include <drm/drm_drv.h> #include <drm/drm_fb_helper.h> -#include <drm/drm_fourcc.h> #include <drm/drm_framebuffer.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_prime.h> -#include <drm/drm_probe_helper.h> #include <drm/exynos_drm.h> #include "exynos_drm_drv.h" @@ -36,6 +31,20 @@ static int exynos_drm_fb_mmap(struct fb_info *info, struct vm_area_struct *vma) return drm_gem_prime_mmap(obj, 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_release(&fb_helper->client); + drm_fb_helper_unprepare(fb_helper); + kfree(fb_helper); +} + static const struct fb_ops exynos_drm_fb_ops = { .owner = THIS_MODULE, DRM_FB_HELPER_DEFAULT_OPS, @@ -45,6 +54,7 @@ static const struct fb_ops exynos_drm_fb_ops = { .fb_fillrect = drm_fb_helper_cfb_fillrect, .fb_copyarea = drm_fb_helper_cfb_copyarea, .fb_imageblit = drm_fb_helper_cfb_imageblit, + .fb_destroy = exynos_drm_fb_destroy, }; static int exynos_drm_fbdev_update(struct drm_fb_helper *helper, @@ -115,19 +125,13 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper, if (ret < 0) goto err_destroy_framebuffer; - return ret; + return 0; err_destroy_framebuffer: drm_framebuffer_cleanup(helper->fb); + helper->fb = NULL; err_destroy_gem: exynos_drm_gem_destroy(exynos_gem); - - /* - * if failed, all resources allocated above would be released by - * drm_mode_config_cleanup() when drm_load() had been called prior - * to any specific driver such as fimd or hdmi driver. - */ - return ret; } @@ -140,16 +144,52 @@ static const struct drm_fb_helper_funcs exynos_drm_fb_helper_funcs = { */ static void exynos_drm_fbdev_client_unregister(struct drm_client_dev *client) -{ } +{ + struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client); + + if (fb_helper->info) { + drm_fb_helper_unregister_info(fb_helper); + } else { + drm_client_release(&fb_helper->client); + drm_fb_helper_unprepare(fb_helper); + kfree(fb_helper); + } +} static int exynos_drm_fbdev_client_restore(struct drm_client_dev *client) { + drm_fb_helper_lastclose(client->dev); + return 0; } static int exynos_drm_fbdev_client_hotplug(struct drm_client_dev *client) { + struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client); + struct drm_device *dev = client->dev; + int ret; + + if (dev->fb_helper) + return drm_fb_helper_hotplug_event(dev->fb_helper); + + ret = drm_fb_helper_init(dev, fb_helper); + if (ret) + goto err_drm_err; + + if (!drm_drv_uses_atomic_modeset(dev)) + drm_helper_disable_unused_functions(dev); + + ret = drm_fb_helper_initial_config(fb_helper); + if (ret) + goto err_drm_fb_helper_fini; + return 0; + +err_drm_fb_helper_fini: + drm_fb_helper_fini(fb_helper); +err_drm_err: + drm_err(dev, "Failed to setup fbdev emulation (ret=%d)\n", ret); + return ret; } static const struct drm_client_funcs exynos_drm_fbdev_client_funcs = { @@ -159,78 +199,32 @@ static const struct drm_client_funcs exynos_drm_fbdev_client_funcs = { .hotplug = exynos_drm_fbdev_client_hotplug, }; -int exynos_drm_fbdev_init(struct drm_device *dev) +void exynos_drm_fbdev_setup(struct drm_device *dev) { - struct drm_fb_helper *helper; + struct drm_fb_helper *fb_helper; int ret; - if (!dev->mode_config.num_crtc) - return 0; + drm_WARN(dev, !dev->registered, "Device has not been registered.\n"); + drm_WARN(dev, dev->fb_helper, "fb_helper is already set!\n"); - helper = kzalloc(sizeof(*helper), GFP_KERNEL); - if (!helper) - return -ENOMEM; - - drm_fb_helper_prepare(dev, helper, PREFERRED_BPP, &exynos_drm_fb_helper_funcs); + fb_helper = kzalloc(sizeof(*fb_helper), GFP_KERNEL); + if (!fb_helper) + return; + drm_fb_helper_prepare(dev, fb_helper, PREFERRED_BPP, &exynos_drm_fb_helper_funcs); - ret = drm_client_init(dev, &helper->client, "exynos-fbdev", &exynos_drm_fbdev_client_funcs); + ret = drm_client_init(dev, &fb_helper->client, "fbdev", &exynos_drm_fbdev_client_funcs); if (ret) - goto err_drm_fb_helper_unprepare; - - ret = drm_fb_helper_init(dev, helper); - if (ret < 0) { - DRM_DEV_ERROR(dev->dev, - "failed to initialize drm fb helper.\n"); - goto err_drm_client_release; - } - - ret = drm_fb_helper_initial_config(helper); - if (ret < 0) { - DRM_DEV_ERROR(dev->dev, - "failed to set up hw configuration.\n"); - goto err_setup; - } - - return 0; - -err_setup: - drm_fb_helper_fini(helper); -err_drm_client_release: - drm_client_release(&helper->client); -err_drm_fb_helper_unprepare: - drm_fb_helper_unprepare(helper); - kfree(helper); - - return ret; -} - -static void exynos_drm_fbdev_destroy(struct drm_device *dev, - struct drm_fb_helper *fb_helper) -{ - struct drm_framebuffer *fb; + goto err_drm_client_init; - /* release drm framebuffer and real buffer */ - if (fb_helper->fb && fb_helper->fb->funcs) { - fb = fb_helper->fb; - if (fb) - drm_framebuffer_remove(fb); - } - - drm_fb_helper_unregister_info(fb_helper); - - drm_fb_helper_fini(fb_helper); -} + ret = exynos_drm_fbdev_client_hotplug(&fb_helper->client); + if (ret) + drm_dbg_kms(dev, "client hotplug ret=%d\n", ret); -void exynos_drm_fbdev_fini(struct drm_device *dev) -{ - struct drm_fb_helper *fb_helper = dev->fb_helper; + drm_client_register(&fb_helper->client); - if (!fb_helper) - return; + return; - exynos_drm_fbdev_destroy(dev, fb_helper); - drm_client_release(&fb_helper->client); +err_drm_client_init: drm_fb_helper_unprepare(fb_helper); kfree(fb_helper); } - |