diff options
Diffstat (limited to 'drivers/gpu/drm/omapdrm/omap_fbdev.c')
| -rw-r--r-- | drivers/gpu/drm/omapdrm/omap_fbdev.c | 163 | 
1 files changed, 103 insertions, 60 deletions
diff --git a/drivers/gpu/drm/omapdrm/omap_fbdev.c b/drivers/gpu/drm/omapdrm/omap_fbdev.c index a6c8542087ec..b950e93b3846 100644 --- a/drivers/gpu/drm/omapdrm/omap_fbdev.c +++ b/drivers/gpu/drm/omapdrm/omap_fbdev.c @@ -4,14 +4,17 @@   * Author: Rob Clark <[email protected]>   */ -#include <drm/drm_crtc.h> -#include <drm/drm_util.h> +#include <drm/drm_drv.h> +#include <drm/drm_crtc_helper.h>  #include <drm/drm_fb_helper.h>  #include <drm/drm_file.h>  #include <drm/drm_fourcc.h>  #include <drm/drm_framebuffer.h> +#include <drm/drm_gem_framebuffer_helper.h> +#include <drm/drm_util.h>  #include "omap_drv.h" +#include "omap_fbdev.h"  MODULE_PARM_DESC(ywrap, "Enable ywrap scrolling (omap44xx and later, default 'y')");  static bool ywrap_enabled = true; @@ -25,8 +28,6 @@ module_param_named(ywrap, ywrap_enabled, bool, 0644);  struct omap_fbdev {  	struct drm_fb_helper base; -	struct drm_framebuffer *fb; -	struct drm_gem_object *bo;  	bool ywrap_enabled;  	/* for deferred dmm roll when getting called in atomic ctx */ @@ -38,12 +39,14 @@ static struct drm_fb_helper *get_fb(struct fb_info *fbi);  static void pan_worker(struct work_struct *work)  {  	struct omap_fbdev *fbdev = container_of(work, struct omap_fbdev, work); -	struct fb_info *fbi = fbdev->base.info; +	struct drm_fb_helper *helper = &fbdev->base; +	struct fb_info *fbi = helper->info; +	struct drm_gem_object *bo = drm_gem_fb_get_obj(helper->fb, 0);  	int npages;  	/* DMM roll shifts in 4K pages: */  	npages = fbi->fix.line_length >> PAGE_SHIFT; -	omap_gem_roll(fbdev->bo, fbi->var.yoffset * npages); +	omap_gem_roll(bo, fbi->var.yoffset * npages);  }  static int omap_fbdev_pan_display(struct fb_var_screeninfo *var, @@ -71,6 +74,25 @@ fallback:  	return drm_fb_helper_pan_display(var, fbi);  } +static void omap_fbdev_fb_destroy(struct fb_info *info) +{ +	struct drm_fb_helper *helper = info->par; +	struct drm_framebuffer *fb = helper->fb; +	struct drm_gem_object *bo = drm_gem_fb_get_obj(fb, 0); +	struct omap_fbdev *fbdev = to_omap_fbdev(helper); + +	DBG(); + +	drm_fb_helper_fini(helper); + +	omap_gem_unpin(bo); +	drm_framebuffer_remove(fb); + +	drm_client_release(&helper->client); +	drm_fb_helper_unprepare(helper); +	kfree(fbdev); +} +  static const struct fb_ops omap_fb_ops = {  	.owner = THIS_MODULE, @@ -86,6 +108,8 @@ static const struct fb_ops omap_fb_ops = {  	.fb_fillrect = drm_fb_helper_sys_fillrect,  	.fb_copyarea = drm_fb_helper_sys_copyarea,  	.fb_imageblit = drm_fb_helper_sys_imageblit, + +	.fb_destroy = omap_fbdev_fb_destroy,  };  static int omap_fbdev_create(struct drm_fb_helper *helper, @@ -98,6 +122,7 @@ static int omap_fbdev_create(struct drm_fb_helper *helper,  	union omap_gem_size gsize;  	struct fb_info *fbi = NULL;  	struct drm_mode_fb_cmd2 mode_cmd = {0}; +	struct drm_gem_object *bo;  	dma_addr_t dma_addr;  	int ret; @@ -128,20 +153,20 @@ static int omap_fbdev_create(struct drm_fb_helper *helper,  		.bytes = PAGE_ALIGN(mode_cmd.pitches[0] * mode_cmd.height),  	};  	DBG("allocating %d bytes for fb %d", gsize.bytes, dev->primary->index); -	fbdev->bo = omap_gem_new(dev, gsize, OMAP_BO_SCANOUT | OMAP_BO_WC); -	if (!fbdev->bo) { +	bo = omap_gem_new(dev, gsize, OMAP_BO_SCANOUT | OMAP_BO_WC); +	if (!bo) {  		dev_err(dev->dev, "failed to allocate buffer object\n");  		ret = -ENOMEM;  		goto fail;  	} -	fb = omap_framebuffer_init(dev, &mode_cmd, &fbdev->bo); +	fb = omap_framebuffer_init(dev, &mode_cmd, &bo);  	if (IS_ERR(fb)) {  		dev_err(dev->dev, "failed to allocate fb\n");  		/* note: if fb creation failed, we can't rely on fb destroy  		 * to unref the bo:  		 */ -		drm_gem_object_put(fbdev->bo); +		drm_gem_object_put(bo);  		ret = PTR_ERR(fb);  		goto fail;  	} @@ -154,7 +179,7 @@ static int omap_fbdev_create(struct drm_fb_helper *helper,  	 * to it).  Then we just need to be sure that we are able to re-  	 * pin it in case of an opps.  	 */ -	ret = omap_gem_pin(fbdev->bo, &dma_addr); +	ret = omap_gem_pin(bo, &dma_addr);  	if (ret) {  		dev_err(dev->dev, "could not pin framebuffer\n");  		ret = -ENOMEM; @@ -170,17 +195,16 @@ static int omap_fbdev_create(struct drm_fb_helper *helper,  	DBG("fbi=%p, dev=%p", fbi, dev); -	fbdev->fb = fb;  	helper->fb = fb;  	fbi->fbops = &omap_fb_ops;  	drm_fb_helper_fill_info(fbi, helper, sizes); -	fbi->screen_buffer = omap_gem_vaddr(fbdev->bo); -	fbi->screen_size = fbdev->bo->size; +	fbi->screen_buffer = omap_gem_vaddr(bo); +	fbi->screen_size = bo->size;  	fbi->fix.smem_start = dma_addr; -	fbi->fix.smem_len = fbdev->bo->size; +	fbi->fix.smem_len = bo->size;  	/* if we have DMM, then we can use it for scrolling by just  	 * shuffling pages around in DMM rather than doing sw blit. @@ -193,7 +217,7 @@ static int omap_fbdev_create(struct drm_fb_helper *helper,  	DBG("par=%p, %dx%d", fbi->par, fbi->var.xres, fbi->var.yres); -	DBG("allocated %dx%d fb", fbdev->fb->width, fbdev->fb->height); +	DBG("allocated %dx%d fb", fb->width, fb->height);  	return 0; @@ -220,75 +244,94 @@ static struct drm_fb_helper *get_fb(struct fb_info *fbi)  	return fbi->par;  } -/* initialize fbdev helper */ -void omap_fbdev_init(struct drm_device *dev) +/* + * struct drm_client + */ + +static void omap_fbdev_client_unregister(struct drm_client_dev *client)  { -	struct omap_drm_private *priv = dev->dev_private; -	struct omap_fbdev *fbdev = NULL; -	struct drm_fb_helper *helper; -	int ret = 0; +	struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client); -	if (!priv->num_pipes) -		return; +	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); +	} +} -	fbdev = kzalloc(sizeof(*fbdev), GFP_KERNEL); -	if (!fbdev) -		return; +static int omap_fbdev_client_restore(struct drm_client_dev *client) +{ +	drm_fb_helper_lastclose(client->dev); -	INIT_WORK(&fbdev->work, pan_worker); +	return 0; +} -	helper = &fbdev->base; +static int omap_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; -	drm_fb_helper_prepare(dev, helper, 32, &omap_fb_helper_funcs); +	if (dev->fb_helper) +		return drm_fb_helper_hotplug_event(dev->fb_helper); -	ret = drm_fb_helper_init(dev, helper); +	ret = drm_fb_helper_init(dev, fb_helper);  	if (ret) -		goto fail; +		goto err_drm_err; -	ret = drm_fb_helper_initial_config(helper); +	ret = drm_fb_helper_initial_config(fb_helper);  	if (ret) -		goto fini; - -	priv->fbdev = helper; - -	return; +		goto err_drm_fb_helper_fini; -fini: -	drm_fb_helper_fini(helper); -fail: -	drm_fb_helper_unprepare(helper); -	kfree(fbdev); +	return 0; -	dev_warn(dev->dev, "omap_fbdev_init failed\n"); +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;  } -void omap_fbdev_fini(struct drm_device *dev) +static const struct drm_client_funcs omap_fbdev_client_funcs = { +	.owner		= THIS_MODULE, +	.unregister	= omap_fbdev_client_unregister, +	.restore	= omap_fbdev_client_restore, +	.hotplug	= omap_fbdev_client_hotplug, +}; + +void omap_fbdev_setup(struct drm_device *dev)  { -	struct omap_drm_private *priv = dev->dev_private; -	struct drm_fb_helper *helper = priv->fbdev;  	struct omap_fbdev *fbdev; +	struct drm_fb_helper *helper; +	int ret; -	DBG(); +	drm_WARN(dev, !dev->registered, "Device has not been registered.\n"); +	drm_WARN(dev, dev->fb_helper, "fb_helper is already set!\n"); -	if (!helper) +	fbdev = kzalloc(sizeof(*fbdev), GFP_KERNEL); +	if (!fbdev)  		return; +	helper = &fbdev->base; -	drm_fb_helper_unregister_info(helper); +	drm_fb_helper_prepare(dev, helper, 32, &omap_fb_helper_funcs); -	drm_fb_helper_fini(helper); +	ret = drm_client_init(dev, &helper->client, "fbdev", &omap_fbdev_client_funcs); +	if (ret) +		goto err_drm_client_init; + +	INIT_WORK(&fbdev->work, pan_worker); -	fbdev = to_omap_fbdev(helper); +	ret = omap_fbdev_client_hotplug(&helper->client); +	if (ret) +		drm_dbg_kms(dev, "client hotplug ret=%d\n", ret); -	/* unpin the GEM object pinned in omap_fbdev_create() */ -	if (fbdev->bo) -		omap_gem_unpin(fbdev->bo); +	drm_client_register(&helper->client); -	/* this will free the backing object */ -	if (fbdev->fb) -		drm_framebuffer_remove(fbdev->fb); +	return; +err_drm_client_init:  	drm_fb_helper_unprepare(helper);  	kfree(fbdev); - -	priv->fbdev = NULL;  }  |