diff options
-rw-r--r-- | drivers/gpu/drm/tegra/drm.c | 23 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/drm.h | 18 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/fbdev.c | 177 |
3 files changed, 86 insertions, 132 deletions
diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index 6ca9f396e55b..85ba96cddd51 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c @@ -56,9 +56,6 @@ static int tegra_atomic_check(struct drm_device *drm, static const struct drm_mode_config_funcs tegra_drm_mode_config_funcs = { .fb_create = tegra_fb_create, -#ifdef CONFIG_DRM_FBDEV_EMULATION - .output_poll_changed = drm_fb_helper_output_poll_changed, -#endif .atomic_check = tegra_atomic_check, .atomic_commit = drm_atomic_helper_commit, }; @@ -885,7 +882,6 @@ static const struct drm_driver tegra_drm_driver = { DRIVER_ATOMIC | DRIVER_RENDER | DRIVER_SYNCOBJ, .open = tegra_drm_open, .postclose = tegra_drm_postclose, - .lastclose = drm_fb_helper_lastclose, #if defined(CONFIG_DEBUG_FS) .debugfs_init = tegra_debugfs_init, @@ -1185,15 +1181,11 @@ static int host1x_drm_probe(struct host1x_device *dev) drm->mode_config.funcs = &tegra_drm_mode_config_funcs; drm->mode_config.helper_private = &tegra_drm_mode_config_helpers; - err = tegra_drm_fb_prepare(drm); - if (err < 0) - goto config; - drm_kms_helper_poll_init(drm); err = host1x_device_init(dev); if (err < 0) - goto fbdev; + goto poll; /* * Now that all display controller have been initialized, the maximum @@ -1256,18 +1248,14 @@ static int host1x_drm_probe(struct host1x_device *dev) if (err < 0) goto hub; - err = tegra_drm_fb_init(drm); + err = drm_dev_register(drm, 0); if (err < 0) goto hub; - err = drm_dev_register(drm, 0); - if (err < 0) - goto fb; + tegra_fbdev_setup(drm); return 0; -fb: - tegra_drm_fb_exit(drm); hub: if (tegra->hub) tegra_display_hub_cleanup(tegra->hub); @@ -1280,10 +1268,8 @@ device: } host1x_device_exit(dev); -fbdev: +poll: drm_kms_helper_poll_fini(drm); - tegra_drm_fb_free(drm); -config: drm_mode_config_cleanup(drm); domain: if (tegra->domain) @@ -1304,7 +1290,6 @@ static int host1x_drm_remove(struct host1x_device *dev) drm_dev_unregister(drm); drm_kms_helper_poll_fini(drm); - tegra_drm_fb_exit(drm); drm_atomic_helper_shutdown(drm); drm_mode_config_cleanup(drm); diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h index 576f03b8434e..f9d18e8cf6ab 100644 --- a/drivers/gpu/drm/tegra/drm.h +++ b/drivers/gpu/drm/tegra/drm.h @@ -15,7 +15,6 @@ #include <drm/drm_bridge.h> #include <drm/drm_edid.h> #include <drm/drm_encoder.h> -#include <drm/drm_fb_helper.h> #include <drm/drm_fixed.h> #include <drm/drm_probe_helper.h> #include <uapi/drm/tegra_drm.h> @@ -194,22 +193,9 @@ struct drm_framebuffer *tegra_fb_create(struct drm_device *drm, const struct drm_mode_fb_cmd2 *cmd); #ifdef CONFIG_DRM_FBDEV_EMULATION -int tegra_drm_fb_prepare(struct drm_device *drm); -void tegra_drm_fb_free(struct drm_device *drm); -int tegra_drm_fb_init(struct drm_device *drm); -void tegra_drm_fb_exit(struct drm_device *drm); +void tegra_fbdev_setup(struct drm_device *drm); #else -static inline int tegra_drm_fb_prepare(struct drm_device *drm) -{ - return 0; -} -static inline void tegra_drm_fb_free(struct drm_device *drm) -{ } -static inline int tegra_drm_fb_init(struct drm_device *drm) -{ - return 0; -} -static inline void tegra_drm_fb_exit(struct drm_device *drm) +static inline void tegra_fbdev_setup(struct drm_device *drm) { } #endif diff --git a/drivers/gpu/drm/tegra/fbdev.c b/drivers/gpu/drm/tegra/fbdev.c index 6ff7106f440e..dca9eccae466 100644 --- a/drivers/gpu/drm/tegra/fbdev.c +++ b/drivers/gpu/drm/tegra/fbdev.c @@ -10,6 +10,9 @@ #include <linux/console.h> #include <linux/vmalloc.h> +#include <drm/drm_drv.h> +#include <drm/drm_crtc_helper.h> +#include <drm/drm_fb_helper.h> #include <drm/drm_fourcc.h> #include <drm/drm_framebuffer.h> #include <drm/drm_gem_framebuffer_helper.h> @@ -33,6 +36,26 @@ static int tegra_fb_mmap(struct fb_info *info, struct vm_area_struct *vma) return __tegra_gem_mmap(&bo->gem, vma); } +static void tegra_fbdev_fb_destroy(struct fb_info *info) +{ + struct drm_fb_helper *helper = info->par; + struct drm_framebuffer *fb = helper->fb; + struct tegra_bo *bo = tegra_fb_get_plane(fb, 0); + + drm_fb_helper_fini(helper); + + /* Undo the special mapping we made in fbdev probe. */ + if (bo->pages) { + vunmap(bo->vaddr); + bo->vaddr = NULL; + } + drm_framebuffer_remove(fb); + + drm_client_release(&helper->client); + drm_fb_helper_unprepare(helper); + kfree(helper); +} + static const struct fb_ops tegra_fb_ops = { .owner = THIS_MODULE, DRM_FB_HELPER_DEFAULT_OPS, @@ -42,6 +65,7 @@ static const struct fb_ops tegra_fb_ops = { .fb_copyarea = drm_fb_helper_sys_copyarea, .fb_imageblit = drm_fb_helper_sys_imageblit, .fb_mmap = tegra_fb_mmap, + .fb_destroy = tegra_fbdev_fb_destroy, }; static int tegra_fbdev_probe(struct drm_fb_helper *helper, @@ -131,16 +155,52 @@ static const struct drm_fb_helper_funcs tegra_fb_helper_funcs = { */ static void tegra_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 tregra_fbdev_client_restore(struct drm_client_dev *client) +static int tegra_fbdev_client_restore(struct drm_client_dev *client) { + drm_fb_helper_lastclose(client->dev); + return 0; } static int tegra_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 tegra_fbdev_client_funcs = { @@ -150,109 +210,32 @@ static const struct drm_client_funcs tegra_fbdev_client_funcs = { .hotplug = tegra_fbdev_client_hotplug, }; -static struct drm_fb_helper *tegra_fbdev_create(struct drm_device *drm) +void tegra_fbdev_setup(struct drm_device *dev) { struct drm_fb_helper *helper; + int ret; + + 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 ERR_PTR(-ENOMEM); - - drm_fb_helper_prepare(drm, helper, 32, &tegra_fb_helper_funcs); - - return helper; -} - -static void tegra_fbdev_free(struct drm_fb_helper *helper) -{ - drm_fb_helper_unprepare(helper); - kfree(helper); -} - -static int tegra_fbdev_init(struct drm_fb_helper *helper, - unsigned int num_crtc, - unsigned int max_connectors) -{ - struct drm_device *drm = helper->dev; - int err; - - err = drm_client_init(dev, &helper->client, "fbdev", &tegra_fbdev_client_funcs); - if (err) - return err; - - err = drm_fb_helper_init(drm, helper); - if (err < 0) { - dev_err(drm->dev, "failed to initialize DRM FB helper: %d\n", - err); - goto err_drm_client_release; - } + return; + drm_fb_helper_prepare(dev, helper, 32, &tegra_fb_helper_funcs); - err = drm_fb_helper_initial_config(helper); - if (err < 0) { - dev_err(drm->dev, "failed to set initial configuration: %d\n", - err); - goto fini; - } + ret = drm_client_init(dev, &helper->client, "fbdev", &tegra_fbdev_client_funcs); + if (ret) + goto err_drm_client_init; - return 0; + ret = tegra_fbdev_client_hotplug(&helper->client); + if (ret) + drm_dbg_kms(dev, "client hotplug ret=%d\n", ret); -fini: - drm_fb_helper_fini(helper); -err_drm_client_release: - drm_client_release(&helper->client); - return err; -} + drm_client_register(&helper->client); -static void tegra_fbdev_exit(struct drm_fb_helper *helper) -{ - struct drm_framebuffer *fb = helper->fb; - - drm_fb_helper_unregister_info(helper); - - if (fb) { - struct tegra_bo *bo = tegra_fb_get_plane(fb, 0); - - /* Undo the special mapping we made in fbdev probe. */ - if (bo && bo->pages) { - vunmap(bo->vaddr); - bo->vaddr = NULL; - } - - drm_framebuffer_remove(fb); - } - - drm_fb_helper_fini(helper); - drm_client_release(&helper->client); - tegra_fbdev_free(helper); -} + return; -int tegra_drm_fb_prepare(struct drm_device *drm) -{ - drm->fb_helper = tegra_fbdev_create(drm); - if (IS_ERR(drm->fb_helper)) - return PTR_ERR(drm->fb_helper); - - return 0; -} - -void tegra_drm_fb_free(struct drm_device *drm) -{ - tegra_fbdev_free(drm->fb_helper); -} - -int tegra_drm_fb_init(struct drm_device *drm) -{ - int err; - - err = tegra_fbdev_init(drm->fb_helper, drm->mode_config.num_crtc, - drm->mode_config.num_connector); - if (err < 0) - return err; - - return 0; -} - -void tegra_drm_fb_exit(struct drm_device *drm) -{ - tegra_fbdev_exit(drm->fb_helper); +err_drm_client_init: + drm_fb_helper_unprepare(helper); + kfree(helper); } |