diff options
Diffstat (limited to 'drivers/gpu/drm/exynos/exynos_drm_fb.c')
| -rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_fb.c | 94 | 
1 files changed, 79 insertions, 15 deletions
| diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c index 4ef4cd3f9936..5426cc5a5e8d 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fb.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c @@ -30,10 +30,13 @@  #include <drm/drm_crtc.h>  #include <drm/drm_crtc_helper.h>  #include <drm/drm_fb_helper.h> +#include <uapi/drm/exynos_drm.h>  #include "exynos_drm_drv.h"  #include "exynos_drm_fb.h"  #include "exynos_drm_gem.h" +#include "exynos_drm_iommu.h" +#include "exynos_drm_encoder.h"  #define to_exynos_fb(x)	container_of(x, struct exynos_drm_fb, fb) @@ -50,6 +53,32 @@ struct exynos_drm_fb {  	struct exynos_drm_gem_obj	*exynos_gem_obj[MAX_FB_BUFFER];  }; +static int check_fb_gem_memory_type(struct drm_device *drm_dev, +				struct exynos_drm_gem_obj *exynos_gem_obj) +{ +	unsigned int flags; + +	/* +	 * if exynos drm driver supports iommu then framebuffer can use +	 * all the buffer types. +	 */ +	if (is_drm_iommu_supported(drm_dev)) +		return 0; + +	flags = exynos_gem_obj->flags; + +	/* +	 * without iommu support, not support physically non-continuous memory +	 * for framebuffer. +	 */ +	if (IS_NONCONTIG_BUFFER(flags)) { +		DRM_ERROR("cannot use this gem memory type for fb.\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); @@ -57,6 +86,9 @@ static void exynos_drm_fb_destroy(struct drm_framebuffer *fb)  	DRM_DEBUG_KMS("%s\n", __FILE__); +	/* make sure that overlay data are updated before relesing fb. */ +	exynos_drm_encoder_complete_scanout(fb); +  	drm_framebuffer_cleanup(fb);  	for (i = 0; i < ARRAY_SIZE(exynos_fb->exynos_gem_obj); i++) { @@ -128,23 +160,32 @@ exynos_drm_framebuffer_init(struct drm_device *dev,  			    struct drm_gem_object *obj)  {  	struct exynos_drm_fb *exynos_fb; +	struct exynos_drm_gem_obj *exynos_gem_obj;  	int ret; +	exynos_gem_obj = to_exynos_gem_obj(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); +	} +  	exynos_fb = kzalloc(sizeof(*exynos_fb), GFP_KERNEL);  	if (!exynos_fb) {  		DRM_ERROR("failed to allocate exynos drm framebuffer\n");  		return ERR_PTR(-ENOMEM);  	} +	drm_helper_mode_fill_fb_struct(&exynos_fb->fb, mode_cmd); +	exynos_fb->exynos_gem_obj[0] = exynos_gem_obj; +  	ret = drm_framebuffer_init(dev, &exynos_fb->fb, &exynos_drm_fb_funcs);  	if (ret) {  		DRM_ERROR("failed to initialize framebuffer\n");  		return ERR_PTR(ret);  	} -	drm_helper_mode_fill_fb_struct(&exynos_fb->fb, mode_cmd); -	exynos_fb->exynos_gem_obj[0] = to_exynos_gem_obj(obj); -  	return &exynos_fb->fb;  } @@ -190,9 +231,8 @@ exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv,  		      struct drm_mode_fb_cmd2 *mode_cmd)  {  	struct drm_gem_object *obj; -	struct drm_framebuffer *fb;  	struct exynos_drm_fb *exynos_fb; -	int i; +	int i, ret;  	DRM_DEBUG_KMS("%s\n", __FILE__); @@ -202,30 +242,56 @@ exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv,  		return ERR_PTR(-ENOENT);  	} -	fb = exynos_drm_framebuffer_init(dev, mode_cmd, obj); -	if (IS_ERR(fb)) { -		drm_gem_object_unreference_unlocked(obj); -		return fb; +	exynos_fb = kzalloc(sizeof(*exynos_fb), GFP_KERNEL); +	if (!exynos_fb) { +		DRM_ERROR("failed to allocate exynos drm framebuffer\n"); +		return ERR_PTR(-ENOMEM);  	} -	exynos_fb = to_exynos_fb(fb); +	drm_helper_mode_fill_fb_struct(&exynos_fb->fb, mode_cmd); +	exynos_fb->exynos_gem_obj[0] = to_exynos_gem_obj(obj);  	exynos_fb->buf_cnt = exynos_drm_format_num_buffers(mode_cmd);  	DRM_DEBUG_KMS("buf_cnt = %d\n", exynos_fb->buf_cnt);  	for (i = 1; i < exynos_fb->buf_cnt; i++) { +		struct exynos_drm_gem_obj *exynos_gem_obj; +		int ret; +  		obj = drm_gem_object_lookup(dev, file_priv,  				mode_cmd->handles[i]);  		if (!obj) {  			DRM_ERROR("failed to lookup gem object\n"); -			exynos_drm_fb_destroy(fb); +			kfree(exynos_fb);  			return ERR_PTR(-ENOENT);  		} +		exynos_gem_obj = to_exynos_gem_obj(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"); +			kfree(exynos_fb); +			return ERR_PTR(ret); +		} +  		exynos_fb->exynos_gem_obj[i] = to_exynos_gem_obj(obj);  	} -	return fb; +	ret = drm_framebuffer_init(dev, &exynos_fb->fb, &exynos_drm_fb_funcs); +	if (ret) { +		for (i = 0; i < exynos_fb->buf_cnt; i++) { +			struct exynos_drm_gem_obj *gem_obj; + +			gem_obj = exynos_fb->exynos_gem_obj[i]; +			drm_gem_object_unreference_unlocked(&gem_obj->base); +		} + +		kfree(exynos_fb); +		return ERR_PTR(ret); +	} + +	return &exynos_fb->fb;  }  struct exynos_drm_gem_buf *exynos_drm_fb_buffer(struct drm_framebuffer *fb, @@ -243,9 +309,7 @@ struct exynos_drm_gem_buf *exynos_drm_fb_buffer(struct drm_framebuffer *fb,  	if (!buffer)  		return NULL; -	DRM_DEBUG_KMS("vaddr = 0x%lx, dma_addr = 0x%lx\n", -			(unsigned long)buffer->kvaddr, -			(unsigned long)buffer->dma_addr); +	DRM_DEBUG_KMS("dma_addr = 0x%lx\n", (unsigned long)buffer->dma_addr);  	return buffer;  } |