diff options
Diffstat (limited to 'drivers/gpu/drm/gma500/fbdev.c')
-rw-r--r-- | drivers/gpu/drm/gma500/fbdev.c | 153 |
1 files changed, 102 insertions, 51 deletions
diff --git a/drivers/gpu/drm/gma500/fbdev.c b/drivers/gpu/drm/gma500/fbdev.c index 74e843f8e64d..0433392c7fbf 100644 --- a/drivers/gpu/drm/gma500/fbdev.c +++ b/drivers/gpu/drm/gma500/fbdev.c @@ -8,6 +8,7 @@ #include <linux/pfn_t.h> #include <drm/drm_crtc_helper.h> +#include <drm/drm_drv.h> #include <drm/drm_fb_helper.h> #include <drm/drm_framebuffer.h> @@ -121,6 +122,27 @@ static int psb_fbdev_fb_mmap(struct fb_info *info, struct vm_area_struct *vma) return 0; } +static void psb_fbdev_fb_destroy(struct fb_info *info) +{ + struct drm_fb_helper *fb_helper = info->par; + struct drm_framebuffer *fb = fb_helper->fb; + struct drm_gem_object *obj = fb->obj[0]; + + drm_fb_helper_fini(fb_helper); + + drm_framebuffer_unregister_private(fb); + fb->obj[0] = NULL; + drm_framebuffer_cleanup(fb); + kfree(fb); + + drm_gem_object_put(obj); + + drm_client_release(&fb_helper->client); + + drm_fb_helper_unprepare(fb_helper); + kfree(fb_helper); +} + static const struct fb_ops psb_fbdev_fb_ops = { .owner = THIS_MODULE, DRM_FB_HELPER_DEFAULT_OPS, @@ -131,6 +153,7 @@ static const struct fb_ops psb_fbdev_fb_ops = { .fb_copyarea = drm_fb_helper_cfb_copyarea, .fb_imageblit = drm_fb_helper_cfb_imageblit, .fb_mmap = psb_fbdev_fb_mmap, + .fb_destroy = psb_fbdev_fb_destroy, }; /* @@ -190,14 +213,6 @@ static int psb_fbdev_fb_probe(struct drm_fb_helper *fb_helper, return PTR_ERR(backing); obj = &backing->base; - memset(dev_priv->vram_addr + backing->offset, 0, size); - - info = drm_fb_helper_alloc_info(fb_helper); - if (IS_ERR(info)) { - ret = PTR_ERR(info); - goto err_drm_gem_object_put; - } - fb = psb_framebuffer_create(dev, &mode_cmd, obj); if (IS_ERR(fb)) { ret = PTR_ERR(fb); @@ -206,28 +221,40 @@ static int psb_fbdev_fb_probe(struct drm_fb_helper *fb_helper, fb_helper->fb = fb; - info->fbops = &psb_fbdev_fb_ops; - - info->fix.smem_start = dev_priv->fb_base; - info->fix.smem_len = size; - info->fix.ywrapstep = 0; - info->fix.ypanstep = 0; + info = drm_fb_helper_alloc_info(fb_helper); + if (IS_ERR(info)) { + ret = PTR_ERR(info); + goto err_drm_framebuffer_unregister_private; + } + info->fbops = &psb_fbdev_fb_ops; + info->flags = FBINFO_DEFAULT; /* Accessed stolen memory directly */ info->screen_base = dev_priv->vram_addr + backing->offset; info->screen_size = size; drm_fb_helper_fill_info(info, fb_helper, sizes); + info->fix.smem_start = dev_priv->fb_base; + info->fix.smem_len = size; + info->fix.ywrapstep = 0; + info->fix.ypanstep = 0; info->fix.mmio_start = pci_resource_start(pdev, 0); info->fix.mmio_len = pci_resource_len(pdev, 0); + memset(info->screen_base, 0, info->screen_size); + /* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */ dev_dbg(dev->dev, "allocated %dx%d fb\n", fb->width, fb->height); return 0; +err_drm_framebuffer_unregister_private: + drm_framebuffer_unregister_private(fb); + fb->obj[0] = NULL; + drm_framebuffer_cleanup(fb); + kfree(fb); err_drm_gem_object_put: drm_gem_object_put(obj); return ret; @@ -237,68 +264,92 @@ static const struct drm_fb_helper_funcs psb_fbdev_fb_helper_funcs = { .fb_probe = psb_fbdev_fb_probe, }; -static int psb_fbdev_destroy(struct drm_device *dev, - struct drm_fb_helper *fb_helper) -{ - struct drm_framebuffer *fb = fb_helper->fb; - - drm_fb_helper_unregister_info(fb_helper); +/* + * struct drm_client_funcs and setup code + */ - drm_fb_helper_fini(fb_helper); - drm_framebuffer_unregister_private(fb); - drm_framebuffer_cleanup(fb); +static void psb_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_fb_helper_unprepare(fb_helper); + drm_client_release(&fb_helper->client); + kfree(fb_helper); + } +} - if (fb->obj[0]) - drm_gem_object_put(fb->obj[0]); - kfree(fb); +static int psb_fbdev_client_restore(struct drm_client_dev *client) +{ + drm_fb_helper_lastclose(client->dev); return 0; } -int psb_fbdev_init(struct drm_device *dev) +static int psb_fbdev_client_hotplug(struct drm_client_dev *client) { - struct drm_fb_helper *fb_helper; - struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client); + struct drm_device *dev = client->dev; int ret; - fb_helper = kzalloc(sizeof(*fb_helper), GFP_KERNEL); - if (!fb_helper) - return -ENOMEM; - - dev_priv->fb_helper = fb_helper; - - drm_fb_helper_prepare(dev, fb_helper, 32, &psb_fbdev_fb_helper_funcs); + if (dev->fb_helper) + return drm_fb_helper_hotplug_event(dev->fb_helper); ret = drm_fb_helper_init(dev, fb_helper); if (ret) - goto free; + goto err_drm_err; - /* disable all the possible outputs/crtcs before entering KMS mode */ - drm_helper_disable_unused_functions(dev); + if (!drm_drv_uses_atomic_modeset(dev)) + drm_helper_disable_unused_functions(dev); ret = drm_fb_helper_initial_config(fb_helper); if (ret) - goto fini; + goto err_drm_fb_helper_fini; return 0; -fini: +err_drm_fb_helper_fini: drm_fb_helper_fini(fb_helper); -free: - drm_fb_helper_unprepare(fb_helper); - kfree(fb_helper); +err_drm_err: + drm_err(dev, "Failed to setup gma500 fbdev emulation (ret=%d)\n", ret); return ret; } -void psb_fbdev_fini(struct drm_device *dev) +static const struct drm_client_funcs psb_fbdev_client_funcs = { + .owner = THIS_MODULE, + .unregister = psb_fbdev_client_unregister, + .restore = psb_fbdev_client_restore, + .hotplug = psb_fbdev_client_hotplug, +}; + +void psb_fbdev_setup(struct drm_psb_private *dev_priv) { - struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + struct drm_device *dev = &dev_priv->dev; + struct drm_fb_helper *fb_helper; + int ret; - if (!dev_priv->fb_helper) + fb_helper = kzalloc(sizeof(*fb_helper), GFP_KERNEL); + if (!fb_helper) return; + drm_fb_helper_prepare(dev, fb_helper, 32, &psb_fbdev_fb_helper_funcs); + + ret = drm_client_init(dev, &fb_helper->client, "fbdev-gma500", &psb_fbdev_client_funcs); + if (ret) { + drm_err(dev, "Failed to register client: %d\n", ret); + goto err_drm_fb_helper_unprepare; + } + + ret = psb_fbdev_client_hotplug(&fb_helper->client); + if (ret) + drm_dbg_kms(dev, "client hotplug ret=%d\n", ret); + + drm_client_register(&fb_helper->client); + + return; - psb_fbdev_destroy(dev, dev_priv->fb_helper); - drm_fb_helper_unprepare(dev_priv->fb_helper); - kfree(dev_priv->fb_helper); - dev_priv->fb_helper = NULL; +err_drm_fb_helper_unprepare: + drm_fb_helper_unprepare(fb_helper); + kfree(fb_helper); } |