static int exynos_drm_fb_mmap(struct fb_info *info, struct vm_area_struct *vma) { struct drm_fb_helper *helper = info->par; struct exynos_drm_fbdev *exynos_fbd = to_exynos_fbdev(helper); struct exynos_drm_gem_obj *exynos_gem_obj = exynos_fbd->exynos_gem_obj; struct exynos_drm_gem_buf *buffer = exynos_gem_obj->buffer; unsigned long vm_size; int ret; vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP; vm_size = vma->vm_end - vma->vm_start; if (vm_size > buffer->size) return -EINVAL; ret = dma_mmap_attrs(helper->dev->dev, vma, buffer->pages, buffer->dma_addr, buffer->size, &buffer->dma_attrs); if (ret < 0) { DRM_ERROR("failed to mmap.\n"); return ret; } return 0; }
static int exynos_drm_fbdev_create(struct drm_fb_helper *helper, struct drm_fb_helper_surface_size *sizes) { struct exynos_drm_fbdev *exynos_fbdev = to_exynos_fbdev(helper); struct exynos_drm_gem_obj *exynos_gem_obj; struct exynos_drm_fb *exynos_fb; struct drm_device *dev = helper->dev; struct fb_info *fbi; struct drm_mode_fb_cmd2 mode_cmd = { 0 }; struct platform_device *pdev = dev->platformdev; unsigned long size; int ret; DRM_DEBUG_KMS("[FB:%d]: %dx%d surface: %dx%d bpp: %d\n", DRM_BASE_ID(helper->fb), sizes->fb_width, sizes->fb_height, sizes->surface_width, sizes->surface_height, sizes->surface_bpp); mode_cmd.width = sizes->surface_width; mode_cmd.height = sizes->surface_height; mode_cmd.pitches[0] = sizes->surface_width * (sizes->surface_bpp >> 3); mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, sizes->surface_depth); mutex_lock(&dev->struct_mutex); fbi = framebuffer_alloc(0, &pdev->dev); if (!fbi) { DRM_ERROR("failed to allocate fb info.\n"); ret = -ENOMEM; goto out; } 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); if (IS_ERR(exynos_gem_obj)) { ret = PTR_ERR(exynos_gem_obj); goto out; } exynos_fbdev->exynos_gem_obj = exynos_gem_obj; exynos_fb = exynos_drm_fb_init(dev, &mode_cmd); if (IS_ERR_OR_NULL(exynos_fb)) { DRM_ERROR("failed to create drm framebuffer.\n"); ret = PTR_ERR(exynos_fb); goto out; } exynos_fb->exynos_gem_obj[0] = exynos_gem_obj; helper->fb = &exynos_fb->fb; helper->fbdev = fbi; fbi->par = helper; fbi->flags = FBINFO_FLAG_DEFAULT; fbi->fbops = &exynos_drm_fb_ops; ret = fb_alloc_cmap(&fbi->cmap, 256, 0); if (ret) { DRM_ERROR("failed to allocate cmap.\n"); goto out; } /* RGB formats use only one buffer */ exynos_drm_fbdev_update(helper, helper->fb, exynos_gem_obj, sizes->fb_width, sizes->fb_height); /* * if failed, all resources allocated above would be released by * drm_mode_config_cleanup() when drm_load() had been called prior * to any specific driver such as fimd or hdmi driver. */ out: mutex_unlock(&dev->struct_mutex); return ret; }