diff options
Diffstat (limited to 'drivers/gpu/drm/exynos/exynos_drm_fbdev.c')
| -rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_fbdev.c | 95 |
1 files changed, 44 insertions, 51 deletions
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c index 71f867340a8..d771b467cf0 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c @@ -16,9 +16,11 @@ #include <drm/drm_crtc.h> #include <drm/drm_fb_helper.h> #include <drm/drm_crtc_helper.h> +#include <drm/exynos_drm.h> #include "exynos_drm_drv.h" #include "exynos_drm_fb.h" +#include "exynos_drm_fbdev.h" #include "exynos_drm_gem.h" #include "exynos_drm_iommu.h" @@ -43,8 +45,6 @@ static int exynos_drm_fb_mmap(struct fb_info *info, unsigned long vm_size; int ret; - DRM_DEBUG_KMS("%s\n", __func__); - vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP; vm_size = vma->vm_end - vma->vm_start; @@ -84,15 +84,13 @@ static int exynos_drm_fbdev_update(struct drm_fb_helper *helper, unsigned int size = fb->width * fb->height * (fb->bits_per_pixel >> 3); unsigned long offset; - DRM_DEBUG_KMS("%s\n", __FILE__); - drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->depth); drm_fb_helper_fill_var(fbi, helper, fb->width, fb->height); /* RGB formats use only one buffer */ buffer = exynos_drm_fb_buffer(fb, 0); if (!buffer) { - DRM_LOG_KMS("buffer is null.\n"); + DRM_DEBUG_KMS("buffer is null.\n"); return -EFAULT; } @@ -101,12 +99,13 @@ static int exynos_drm_fbdev_update(struct drm_fb_helper *helper, if (is_drm_iommu_supported(dev)) { unsigned int nr_pages = buffer->size >> PAGE_SHIFT; - buffer->kvaddr = vmap(buffer->pages, nr_pages, VM_MAP, + buffer->kvaddr = (void __iomem *) vmap(buffer->pages, + nr_pages, VM_MAP, pgprot_writecombine(PAGE_KERNEL)); } else { phys_addr_t dma_addr = buffer->dma_addr; if (dma_addr) - buffer->kvaddr = phys_to_virt(dma_addr); + buffer->kvaddr = (void __iomem *)phys_to_virt(dma_addr); else buffer->kvaddr = (void __iomem *)NULL; } @@ -122,16 +121,8 @@ static int exynos_drm_fbdev_update(struct drm_fb_helper *helper, offset = fbi->var.xoffset * (fb->bits_per_pixel >> 3); offset += fbi->var.yoffset * fb->pitches[0]; - dev->mode_config.fb_base = (resource_size_t)buffer->dma_addr; fbi->screen_base = buffer->kvaddr + offset; - if (is_drm_iommu_supported(dev)) - fbi->fix.smem_start = (unsigned long) - (page_to_phys(sg_page(buffer->sgt->sgl)) + offset); - else - fbi->fix.smem_start = (unsigned long)buffer->dma_addr; - fbi->screen_size = size; - fbi->fix.smem_len = size; return 0; } @@ -148,8 +139,6 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper, unsigned long size; int ret; - DRM_DEBUG_KMS("%s\n", __FILE__); - DRM_DEBUG_KMS("surface width(%d), height(%d) and bpp(%d\n", sizes->surface_width, sizes->surface_height, sizes->surface_bpp); @@ -171,8 +160,18 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper, size = mode_cmd.pitches[0] * mode_cmd.height; - /* 0 means to allocate physically continuous memory */ - exynos_gem_obj = exynos_drm_gem_create(dev, 0, size); + exynos_gem_obj = exynos_drm_gem_create(dev, EXYNOS_BO_CONTIG, size); + /* + * If physically contiguous memory allocation fails and if IOMMU is + * supported then try to get buffer from non physically contiguous + * memory area. + */ + if (IS_ERR(exynos_gem_obj) && is_drm_iommu_supported(dev)) { + dev_warn(&pdev->dev, "contiguous FB allocation failed, falling back to non-contiguous\n"); + exynos_gem_obj = exynos_drm_gem_create(dev, EXYNOS_BO_NONCONTIG, + size); + } + if (IS_ERR(exynos_gem_obj)) { ret = PTR_ERR(exynos_gem_obj); goto err_release_framebuffer; @@ -182,7 +181,7 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper, helper->fb = exynos_drm_framebuffer_init(dev, &mode_cmd, &exynos_gem_obj->base); - if (IS_ERR_OR_NULL(helper->fb)) { + if (IS_ERR(helper->fb)) { DRM_ERROR("failed to create drm framebuffer.\n"); ret = PTR_ERR(helper->fb); goto err_destroy_gem; @@ -226,38 +225,28 @@ out: return ret; } -static int exynos_drm_fbdev_probe(struct drm_fb_helper *helper, - struct drm_fb_helper_surface_size *sizes) -{ - int ret = 0; +static struct drm_fb_helper_funcs exynos_drm_fb_helper_funcs = { + .fb_probe = exynos_drm_fbdev_create, +}; - DRM_DEBUG_KMS("%s\n", __FILE__); +static bool exynos_drm_fbdev_is_anything_connected(struct drm_device *dev) +{ + struct drm_connector *connector; + bool ret = false; - /* - * with !helper->fb, it means that this funcion is called first time - * and after that, the helper->fb would be used as clone mode. - */ - if (!helper->fb) { - ret = exynos_drm_fbdev_create(helper, sizes); - if (ret < 0) { - DRM_ERROR("failed to create fbdev.\n"); - return ret; - } + mutex_lock(&dev->mode_config.mutex); + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + if (connector->status != connector_status_connected) + continue; - /* - * fb_helper expects a value more than 1 if succeed - * because register_framebuffer() should be called. - */ - ret = 1; + ret = true; + break; } + mutex_unlock(&dev->mode_config.mutex); return ret; } -static struct drm_fb_helper_funcs exynos_drm_fb_helper_funcs = { - .fb_probe = exynos_drm_fbdev_probe, -}; - int exynos_drm_fbdev_init(struct drm_device *dev) { struct exynos_drm_fbdev *fbdev; @@ -266,16 +255,15 @@ int exynos_drm_fbdev_init(struct drm_device *dev) unsigned int num_crtc; int ret; - DRM_DEBUG_KMS("%s\n", __FILE__); - if (!dev->mode_config.num_crtc || !dev->mode_config.num_connector) return 0; + if (!exynos_drm_fbdev_is_anything_connected(dev)) + return 0; + fbdev = kzalloc(sizeof(*fbdev), GFP_KERNEL); - if (!fbdev) { - DRM_ERROR("failed to allocate drm fbdev.\n"); + if (!fbdev) return -ENOMEM; - } private->fb_helper = helper = &fbdev->drm_fb_helper; helper->funcs = &exynos_drm_fb_helper_funcs; @@ -295,6 +283,9 @@ int exynos_drm_fbdev_init(struct drm_device *dev) } + /* disable all the possible outputs/crtcs before entering KMS mode */ + drm_helper_disable_unused_functions(dev); + ret = drm_fb_helper_initial_config(helper, PREFERRED_BPP); if (ret < 0) { DRM_ERROR("failed to set up hw configuration.\n"); @@ -326,8 +317,10 @@ static void exynos_drm_fbdev_destroy(struct drm_device *dev, /* release drm framebuffer and real buffer */ if (fb_helper->fb && fb_helper->fb->funcs) { fb = fb_helper->fb; - if (fb) + if (fb) { + drm_framebuffer_unregister_private(fb); drm_framebuffer_remove(fb); + } } /* release linux framebuffer */ @@ -374,5 +367,5 @@ void exynos_drm_fbdev_restore_mode(struct drm_device *dev) if (!private || !private->fb_helper) return; - drm_fb_helper_restore_fbdev_mode(private->fb_helper); + drm_fb_helper_restore_fbdev_mode_unlocked(private->fb_helper); } |
