aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/exynos/exynos_drm_fb.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/exynos/exynos_drm_fb.c')
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fb.c81
1 files changed, 71 insertions, 10 deletions
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c
index 7b47330..41009e4 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fb.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c
@@ -49,10 +49,19 @@ struct exynos_drm_fb {
struct exynos_drm_gem_obj *exynos_gem_obj[MAX_FB_BUFFER];
};
-static int check_fb_gem_memory_type(struct exynos_drm_gem_obj *exynos_gem_obj)
+static int check_fb_gem_memory_type(struct drm_device *drm_dev,
+ struct exynos_drm_gem_obj *exynos_gem_obj)
{
+ struct exynos_drm_private *private = drm_dev->dev_private;
unsigned int flags;
+ /*
+ * if exynos drm driver supports iommu then framebuffer can use
+ * all the buffer types.
+ */
+ if (private->vmm)
+ return 0;
+
flags = exynos_gem_obj->flags;
/* not support physically non-continuous memory for fb yet. TODO */
@@ -64,14 +73,63 @@ static int check_fb_gem_memory_type(struct exynos_drm_gem_obj *exynos_gem_obj)
return 0;
}
+static int check_fb_gem_size(struct drm_device *drm_dev,
+ struct drm_framebuffer *fb,
+ unsigned int nr)
+{
+ unsigned long fb_size;
+ struct drm_gem_object *obj;
+ struct exynos_drm_gem_obj *exynos_gem_obj;
+ struct exynos_drm_fb *exynos_fb = to_exynos_fb(fb);
+
+ /* in case of RGB format, only one plane is used. */
+ if (nr < 2) {
+ exynos_gem_obj = exynos_fb->exynos_gem_obj[0];
+ obj = &exynos_gem_obj->base;
+ fb_size = fb->pitches[0] * fb->height;
+
+ if (fb_size != exynos_gem_obj->packed_size) {
+ DRM_ERROR("invalid fb or gem size.\n");
+ return -EINVAL;
+ }
+ /* in case of NV12MT, YUV420M and so on, two and three planes. */
+ } else {
+ unsigned int i;
+
+ for (i = 0; i < nr; i++) {
+ exynos_gem_obj = exynos_fb->exynos_gem_obj[i];
+ obj = &exynos_gem_obj->base;
+ fb_size = fb->pitches[i] * fb->height;
+
+ if (fb_size != exynos_gem_obj->packed_size) {
+ DRM_ERROR("invalid fb or gem size.\n");
+ return -EINVAL;
+ }
+ }
+ }
+
+ return 0;
+}
+
static void exynos_drm_fb_destroy(struct drm_framebuffer *fb)
{
struct exynos_drm_fb *exynos_fb = to_exynos_fb(fb);
+ unsigned int i;
DRM_DEBUG_KMS("%s\n", __FILE__);
drm_framebuffer_cleanup(fb);
+ for (i = 0; i < ARRAY_SIZE(exynos_fb->exynos_gem_obj); i++) {
+ struct drm_gem_object *obj;
+
+ if (exynos_fb->exynos_gem_obj[i] == NULL)
+ continue;
+
+ obj = &exynos_fb->exynos_gem_obj[i]->base;
+ drm_gem_object_unreference_unlocked(obj);
+ }
+
kfree(exynos_fb);
exynos_fb = NULL;
}
@@ -117,7 +175,7 @@ exynos_drm_framebuffer_init(struct drm_device *dev,
exynos_gem_obj = to_exynos_gem_obj(obj);
- ret = check_fb_gem_memory_type(exynos_gem_obj);
+ ret = check_fb_gem_memory_type(dev, exynos_gem_obj);
if (ret < 0) {
DRM_ERROR("cannot use this gem memory type for fb.\n");
return ERR_PTR(-EINVAL);
@@ -149,8 +207,7 @@ exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv,
struct drm_gem_object *obj;
struct drm_framebuffer *fb;
struct exynos_drm_fb *exynos_fb;
- int nr;
- int i;
+ int nr, i, ret;
DRM_DEBUG_KMS("%s\n", __FILE__);
@@ -160,11 +217,11 @@ exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv,
return ERR_PTR(-ENOENT);
}
- drm_gem_object_unreference_unlocked(obj);
-
fb = exynos_drm_framebuffer_init(dev, mode_cmd, obj);
- if (IS_ERR(fb))
+ if (IS_ERR(fb)) {
+ drm_gem_object_unreference_unlocked(obj);
return fb;
+ }
exynos_fb = to_exynos_fb(fb);
nr = exynos_drm_format_num_buffers(fb->pixel_format);
@@ -181,11 +238,9 @@ exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv,
return ERR_PTR(-ENOENT);
}
- drm_gem_object_unreference_unlocked(obj);
-
exynos_gem_obj = to_exynos_gem_obj(obj);
- ret = check_fb_gem_memory_type(exynos_gem_obj);
+ ret = check_fb_gem_memory_type(dev, exynos_gem_obj);
if (ret < 0) {
DRM_ERROR("cannot use this gem memory type for fb.\n");
exynos_drm_fb_destroy(fb);
@@ -195,6 +250,12 @@ exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv,
exynos_fb->exynos_gem_obj[i] = to_exynos_gem_obj(obj);
}
+ ret = check_fb_gem_size(dev, fb, nr);
+ if (ret < 0) {
+ exynos_drm_fb_destroy(fb);
+ return ERR_PTR(ret);
+ }
+
return fb;
}