diff options
author | Dave Airlie <airlied@redhat.com> | 2014-11-15 09:38:55 +1000 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2014-11-15 09:38:55 +1000 |
commit | b0654103f55ebae8f72700b37f152942f34806cc (patch) | |
tree | 21c9796f4421e5cfdeece759a54c214010aca493 /drivers/gpu/drm/tegra/fb.c | |
parent | 4fb2ac6ebe3ece9cafb2bb6d4a2e8e4edb124637 (diff) | |
parent | 7e0180e3570cc791e95e6b6cd5fbeb0aedc62776 (diff) |
Merge tag 'drm/tegra/for-3.19-rc1' of git://people.freedesktop.org/~tagr/linux into drm-next
drm/tegra: Changes for v3.19-rc1
The highlights in this pull request are:
* IOMMU support: The Tegra DRM driver can now deal with discontiguous
buffers if an IOMMU exists in the system. That means it can allocate
using drm_gem_get_pages() and will map them into IOVA space via the
IOMMU API. Similarly, non-contiguous PRIME buffers can be imported
from a different driver, which allows better integration with gk20a
(nouveau) and less hacks.
* Universal planes: This is precursory work for atomic modesetting and
will allow hardware cursor support to be implemented on pre-Tegra114
where RGB cursors were not supported.
* DSI ganged-mode support: The DSI controller can now gang up with a
second DSI controller to drive high resolution DSI panels.
Besides those bigger changes there is a slew of fixes, cleanups, plugged
memory leaks and so on.
* tag 'drm/tegra/for-3.19-rc1' of git://people.freedesktop.org/~tagr/linux: (44 commits)
drm/tegra: gem: Check before freeing CMA memory
drm/tegra: fb: Add error codes to error messages
drm/tegra: fb: Properly release GEM objects on failure
drm/tegra: Detach panel when a connector is removed
drm/tegra: Plug memory leak
drm/tegra: gem: Use more consistent data types
drm/tegra: fb: Do not destroy framebuffer
drm/tegra: gem: dumb: pitch and size are outputs
drm/tegra: Enable the hotplug interrupt only when necessary
drm/tegra: dc: Universal plane support
drm/tegra: dc: Registers are 32 bits wide
drm/tegra: dc: Factor out DC, window and cursor commit
drm/tegra: Add IOMMU support
drm/tegra: Fix error handling cleanup
drm/tegra: gem: Use dma_mmap_writecombine()
drm/tegra: gem: Remove redundant drm_gem_free_mmap_offset()
drm/tegra: gem: Cleanup tegra_bo_create_with_handle()
drm/tegra: gem: Extract tegra_bo_alloc_object()
drm/tegra: dsi: Set up PHY_TIMING & BTA_TIMING registers earlier
drm/tegra: dsi: Replace 1000000 by USEC_PER_SEC
...
Diffstat (limited to 'drivers/gpu/drm/tegra/fb.c')
-rw-r--r-- | drivers/gpu/drm/tegra/fb.c | 52 |
1 files changed, 42 insertions, 10 deletions
diff --git a/drivers/gpu/drm/tegra/fb.c b/drivers/gpu/drm/tegra/fb.c index 3513d12d5aa1..e9c715d89261 100644 --- a/drivers/gpu/drm/tegra/fb.c +++ b/drivers/gpu/drm/tegra/fb.c @@ -65,8 +65,12 @@ static void tegra_fb_destroy(struct drm_framebuffer *framebuffer) for (i = 0; i < fb->num_planes; i++) { struct tegra_bo *bo = fb->planes[i]; - if (bo) + if (bo) { + if (bo->pages && bo->vaddr) + vunmap(bo->vaddr); + drm_gem_object_unreference_unlocked(&bo->gem); + } } drm_framebuffer_cleanup(framebuffer); @@ -223,14 +227,16 @@ static int tegra_fbdev_probe(struct drm_fb_helper *helper, info = framebuffer_alloc(0, drm->dev); if (!info) { dev_err(drm->dev, "failed to allocate framebuffer info\n"); - tegra_bo_free_object(&bo->gem); + drm_gem_object_unreference_unlocked(&bo->gem); return -ENOMEM; } fbdev->fb = tegra_fb_alloc(drm, &cmd, &bo, 1); if (IS_ERR(fbdev->fb)) { - dev_err(drm->dev, "failed to allocate DRM framebuffer\n"); err = PTR_ERR(fbdev->fb); + dev_err(drm->dev, "failed to allocate DRM framebuffer: %d\n", + err); + drm_gem_object_unreference_unlocked(&bo->gem); goto release; } @@ -254,6 +260,16 @@ static int tegra_fbdev_probe(struct drm_fb_helper *helper, offset = info->var.xoffset * bytes_per_pixel + info->var.yoffset * fb->pitches[0]; + if (bo->pages) { + bo->vaddr = vmap(bo->pages, bo->num_pages, VM_MAP, + pgprot_writecombine(PAGE_KERNEL)); + if (!bo->vaddr) { + dev_err(drm->dev, "failed to vmap() framebuffer\n"); + err = -ENOMEM; + goto destroy; + } + } + drm->mode_config.fb_base = (resource_size_t)bo->paddr; info->screen_base = (void __iomem *)bo->vaddr + offset; info->screen_size = size; @@ -289,6 +305,11 @@ static struct tegra_fbdev *tegra_fbdev_create(struct drm_device *drm) return fbdev; } +static void tegra_fbdev_free(struct tegra_fbdev *fbdev) +{ + kfree(fbdev); +} + static int tegra_fbdev_init(struct tegra_fbdev *fbdev, unsigned int preferred_bpp, unsigned int num_crtc, @@ -299,19 +320,21 @@ static int tegra_fbdev_init(struct tegra_fbdev *fbdev, err = drm_fb_helper_init(drm, &fbdev->base, num_crtc, max_connectors); if (err < 0) { - dev_err(drm->dev, "failed to initialize DRM FB helper\n"); + dev_err(drm->dev, "failed to initialize DRM FB helper: %d\n", + err); return err; } err = drm_fb_helper_single_add_all_connectors(&fbdev->base); if (err < 0) { - dev_err(drm->dev, "failed to add connectors\n"); + dev_err(drm->dev, "failed to add connectors: %d\n", err); goto fini; } err = drm_fb_helper_initial_config(&fbdev->base, preferred_bpp); if (err < 0) { - dev_err(drm->dev, "failed to set initial configuration\n"); + dev_err(drm->dev, "failed to set initial configuration: %d\n", + err); goto fini; } @@ -322,7 +345,7 @@ fini: return err; } -static void tegra_fbdev_free(struct tegra_fbdev *fbdev) +static void tegra_fbdev_exit(struct tegra_fbdev *fbdev) { struct fb_info *info = fbdev->base.fbdev; @@ -341,11 +364,11 @@ static void tegra_fbdev_free(struct tegra_fbdev *fbdev) if (fbdev->fb) { drm_framebuffer_unregister_private(&fbdev->fb->base); - tegra_fb_destroy(&fbdev->fb->base); + drm_framebuffer_remove(&fbdev->fb->base); } drm_fb_helper_fini(&fbdev->base); - kfree(fbdev); + tegra_fbdev_free(fbdev); } void tegra_fbdev_restore_mode(struct tegra_fbdev *fbdev) @@ -393,6 +416,15 @@ int tegra_drm_fb_prepare(struct drm_device *drm) return 0; } +void tegra_drm_fb_free(struct drm_device *drm) +{ +#ifdef CONFIG_DRM_TEGRA_FBDEV + struct tegra_drm *tegra = drm->dev_private; + + tegra_fbdev_free(tegra->fbdev); +#endif +} + int tegra_drm_fb_init(struct drm_device *drm) { #ifdef CONFIG_DRM_TEGRA_FBDEV @@ -413,6 +445,6 @@ void tegra_drm_fb_exit(struct drm_device *drm) #ifdef CONFIG_DRM_TEGRA_FBDEV struct tegra_drm *tegra = drm->dev_private; - tegra_fbdev_free(tegra->fbdev); + tegra_fbdev_exit(tegra->fbdev); #endif } |