Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 55cdb314 authored by Dave Airlie's avatar Dave Airlie
Browse files

Merge branch 'exynos-drm-next' of...

Merge branch 'exynos-drm-next' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos into drm-next

   This is a last pull request, which includes two g2d patches
   I missed, and more cleanup series of Exynos drm driver.

   The cleanup series makes Exynos drm driver more simple,
   and removes unnecessary codes, and considers multiple plane format
   of framebuffer. I hope this not to be late.

* 'exynos-drm-next' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos:
  drm/exynos: remove buf_cnt from struct exynos_drm_fb
  drm/exynos: remove exynos_drm_fb_get_buf_cnt()
  drm/exynos: cleanup exynos_user_fb_create()
  drm/exynos: update exynos_drm_framebuffer_init() for multiple buffers
  drm/exynos: cleanup to get gem object for fb
  drm/exynos: update fb_info via only one function
  drm/exynos: cleanup exynos_drm_fbdev_update()
  drm/exynos: s/exynos_gem_obj/obj in exynos_drm_fbdev.c
  drm/exynos: remove exynos_drm_fb_set_buf_cnt()
  drm/exynos: remove superfluous checks in g2d_check_reg_offset()
  drm/exynos: fix size check in g2d_check_buf_desc_is_valid()
parents 99495589 c3058579
Loading
Loading
Loading
Loading
+33 −82
Original line number Diff line number Diff line
@@ -23,7 +23,6 @@
#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"
#include "exynos_drm_crtc.h"

@@ -33,12 +32,10 @@
 * exynos specific framebuffer structure.
 *
 * @fb: drm framebuffer obejct.
 * @buf_cnt: a buffer count to drm framebuffer.
 * @exynos_gem_obj: array of exynos specific gem object containing a gem object.
 */
struct exynos_drm_fb {
	struct drm_framebuffer		fb;
	unsigned int			buf_cnt;
	struct exynos_drm_gem_obj	*exynos_gem_obj[MAX_FB_BUFFER];
};

@@ -98,10 +95,6 @@ static int exynos_drm_fb_create_handle(struct drm_framebuffer *fb,
{
	struct exynos_drm_fb *exynos_fb = to_exynos_fb(fb);

	/* This fb should have only one gem object. */
	if (WARN_ON(exynos_fb->buf_cnt != 1))
		return -EINVAL;

	return drm_gem_handle_create(file_priv,
			&exynos_fb->exynos_gem_obj[0]->base, handle);
}
@@ -122,119 +115,77 @@ static struct drm_framebuffer_funcs exynos_drm_fb_funcs = {
	.dirty		= exynos_drm_fb_dirty,
};

void exynos_drm_fb_set_buf_cnt(struct drm_framebuffer *fb,
						unsigned int cnt)
{
	struct exynos_drm_fb *exynos_fb;

	exynos_fb = to_exynos_fb(fb);

	exynos_fb->buf_cnt = cnt;
}

unsigned int exynos_drm_fb_get_buf_cnt(struct drm_framebuffer *fb)
{
	struct exynos_drm_fb *exynos_fb;

	exynos_fb = to_exynos_fb(fb);

	return exynos_fb->buf_cnt;
}

struct drm_framebuffer *
exynos_drm_framebuffer_init(struct drm_device *dev,
			    struct drm_mode_fb_cmd2 *mode_cmd,
			    struct drm_gem_object *obj)
			    struct exynos_drm_gem_obj **gem_obj,
			    int count)
{
	struct exynos_drm_fb *exynos_fb;
	struct exynos_drm_gem_obj *exynos_gem_obj;
	int i;
	int ret;

	exynos_gem_obj = to_exynos_gem_obj(obj);

	ret = check_fb_gem_memory_type(dev, exynos_gem_obj);
	if (ret < 0)
		return ERR_PTR(ret);

	exynos_fb = kzalloc(sizeof(*exynos_fb), GFP_KERNEL);
	if (!exynos_fb)
		return ERR_PTR(-ENOMEM);

	for (i = 0; i < count; i++) {
		ret = check_fb_gem_memory_type(dev, gem_obj[i]);
		if (ret < 0)
			goto err;

		exynos_fb->exynos_gem_obj[i] = gem_obj[i];
	}

	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) {
		kfree(exynos_fb);
	if (ret < 0) {
		DRM_ERROR("failed to initialize framebuffer\n");
		return ERR_PTR(ret);
		goto err;
	}

	return &exynos_fb->fb;

err:
	kfree(exynos_fb);
	return ERR_PTR(ret);
}

static struct drm_framebuffer *
exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv,
		      struct drm_mode_fb_cmd2 *mode_cmd)
{
	struct exynos_drm_gem_obj *gem_objs[MAX_FB_BUFFER];
	struct drm_gem_object *obj;
	struct exynos_drm_gem_obj *exynos_gem_obj;
	struct exynos_drm_fb *exynos_fb;
	int i, ret;

	exynos_fb = kzalloc(sizeof(*exynos_fb), GFP_KERNEL);
	if (!exynos_fb)
		return ERR_PTR(-ENOMEM);

	obj = drm_gem_object_lookup(dev, file_priv, mode_cmd->handles[0]);
	if (!obj) {
		DRM_ERROR("failed to lookup gem object\n");
		ret = -ENOENT;
		goto err_free;
	}

	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 = drm_format_num_planes(mode_cmd->pixel_format);

	DRM_DEBUG_KMS("buf_cnt = %d\n", exynos_fb->buf_cnt);
	struct drm_framebuffer *fb;
	int i;
	int ret;

	for (i = 1; i < exynos_fb->buf_cnt; i++) {
	for (i = 0; i < drm_format_num_planes(mode_cmd->pixel_format); i++) {
		obj = drm_gem_object_lookup(dev, file_priv,
					    mode_cmd->handles[i]);
		if (!obj) {
			DRM_ERROR("failed to lookup gem object\n");
			ret = -ENOENT;
			exynos_fb->buf_cnt = i;
			goto err_unreference;
			goto err;
		}

		exynos_gem_obj = to_exynos_gem_obj(obj);
		exynos_fb->exynos_gem_obj[i] = exynos_gem_obj;

		ret = check_fb_gem_memory_type(dev, exynos_gem_obj);
		if (ret < 0)
			goto err_unreference;
		gem_objs[i] = to_exynos_gem_obj(obj);
	}

	ret = drm_framebuffer_init(dev, &exynos_fb->fb, &exynos_drm_fb_funcs);
	if (ret) {
		DRM_ERROR("failed to init framebuffer.\n");
		goto err_unreference;
	fb = exynos_drm_framebuffer_init(dev, mode_cmd, gem_objs, i);
	if (IS_ERR(fb)) {
		ret = PTR_ERR(fb);
		goto err;
	}

	return &exynos_fb->fb;
	return fb;

err_unreference:
	for (i = 0; i < exynos_fb->buf_cnt; i++) {
		struct drm_gem_object *obj;
err:
	while (i--)
		drm_gem_object_unreference_unlocked(&gem_objs[i]->base);

		obj = &exynos_fb->exynos_gem_obj[i]->base;
		if (obj)
			drm_gem_object_unreference_unlocked(obj);
	}
err_free:
	kfree(exynos_fb);
	return ERR_PTR(ret);
}

+4 −8
Original line number Diff line number Diff line
@@ -14,10 +14,13 @@
#ifndef _EXYNOS_DRM_FB_H_
#define _EXYNOS_DRM_FB_H

#include "exynos_drm_gem.h"

struct drm_framebuffer *
exynos_drm_framebuffer_init(struct drm_device *dev,
			    struct drm_mode_fb_cmd2 *mode_cmd,
			    struct drm_gem_object *obj);
			    struct exynos_drm_gem_obj **gem_obj,
			    int count);

/* get gem object of a drm framebuffer */
struct exynos_drm_gem_obj *exynos_drm_fb_gem_obj(struct drm_framebuffer *fb,
@@ -25,11 +28,4 @@ struct exynos_drm_gem_obj *exynos_drm_fb_gem_obj(struct drm_framebuffer *fb,

void exynos_drm_mode_config_init(struct drm_device *dev);

/* set a buffer count to drm framebuffer. */
void exynos_drm_fb_set_buf_cnt(struct drm_framebuffer *fb,
						unsigned int cnt);

/* get a buffer count to drm framebuffer. */
unsigned int exynos_drm_fb_get_buf_cnt(struct drm_framebuffer *fb);

#endif
+31 −47
Original line number Diff line number Diff line
@@ -21,7 +21,6 @@
#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"

#define MAX_CONNECTOR		4
@@ -32,7 +31,7 @@

struct exynos_drm_fbdev {
	struct drm_fb_helper		drm_fb_helper;
	struct exynos_drm_gem_obj	*exynos_gem_obj;
	struct exynos_drm_gem_obj	*obj;
};

static int exynos_drm_fb_mmap(struct fb_info *info,
@@ -40,7 +39,7 @@ static int exynos_drm_fb_mmap(struct fb_info *info,
{
	struct drm_fb_helper *helper = info->par;
	struct exynos_drm_fbdev *exynos_fbd = to_exynos_fbdev(helper);
	struct exynos_drm_gem_obj *obj = exynos_fbd->exynos_gem_obj;
	struct exynos_drm_gem_obj *obj = exynos_fbd->obj;
	unsigned long vm_size;
	int ret;

@@ -76,36 +75,37 @@ static struct fb_ops exynos_drm_fb_ops = {

static int exynos_drm_fbdev_update(struct drm_fb_helper *helper,
				   struct drm_fb_helper_surface_size *sizes,
				     struct drm_framebuffer *fb)
				   struct exynos_drm_gem_obj *obj)
{
	struct fb_info *fbi = helper->fbdev;
	struct exynos_drm_gem_obj *obj;
	struct fb_info *fbi;
	struct drm_framebuffer *fb = helper->fb;
	unsigned int size = fb->width * fb->height * (fb->bits_per_pixel >> 3);
	unsigned int nr_pages;
	unsigned long offset;

	fbi = drm_fb_helper_alloc_fbi(helper);
	if (IS_ERR(fbi)) {
		DRM_ERROR("failed to allocate fb info.\n");
		return PTR_ERR(fbi);
	}

	fbi->par = helper;
	fbi->flags = FBINFO_FLAG_DEFAULT;
	fbi->fbops = &exynos_drm_fb_ops;

	drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->depth);
	drm_fb_helper_fill_var(fbi, helper, sizes->fb_width, sizes->fb_height);

	/* RGB formats use only one buffer */
	obj = exynos_drm_fb_gem_obj(fb, 0);
	if (!obj) {
		DRM_DEBUG_KMS("gem object is null.\n");
		return -EFAULT;
	}

	nr_pages = obj->size >> PAGE_SHIFT;

	obj->kvaddr = (void __iomem *) vmap(obj->pages, nr_pages, VM_MAP,
			pgprot_writecombine(PAGE_KERNEL));
	if (!obj->kvaddr) {
		DRM_ERROR("failed to map pages to kernel space.\n");
		drm_fb_helper_release_fbi(helper);
		return -EIO;
	}

	/* buffer count to framebuffer always is 1 at booting time. */
	exynos_drm_fb_set_buf_cnt(fb, 1);

	offset = fbi->var.xoffset * (fb->bits_per_pixel >> 3);
	offset += fbi->var.yoffset * fb->pitches[0];

@@ -120,9 +120,8 @@ 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_gem_obj *obj;
	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;
@@ -140,47 +139,34 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper,

	mutex_lock(&dev->struct_mutex);

	fbi = drm_fb_helper_alloc_fbi(helper);
	if (IS_ERR(fbi)) {
		DRM_ERROR("failed to allocate fb info.\n");
		ret = PTR_ERR(fbi);
		goto out;
	}

	size = mode_cmd.pitches[0] * mode_cmd.height;

	exynos_gem_obj = exynos_drm_gem_create(dev, EXYNOS_BO_CONTIG, size);
	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)) {
	if (IS_ERR(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);
		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_fbi;
	if (IS_ERR(obj)) {
		ret = PTR_ERR(obj);
		goto out;
	}

	exynos_fbdev->exynos_gem_obj = exynos_gem_obj;
	exynos_fbdev->obj = obj;

	helper->fb = exynos_drm_framebuffer_init(dev, &mode_cmd,
			&exynos_gem_obj->base);
	helper->fb = exynos_drm_framebuffer_init(dev, &mode_cmd, &obj, 1);
	if (IS_ERR(helper->fb)) {
		DRM_ERROR("failed to create drm framebuffer.\n");
		ret = PTR_ERR(helper->fb);
		goto err_destroy_gem;
	}

	fbi->par = helper;
	fbi->flags = FBINFO_FLAG_DEFAULT;
	fbi->fbops = &exynos_drm_fb_ops;

	ret = exynos_drm_fbdev_update(helper, sizes, helper->fb);
	ret = exynos_drm_fbdev_update(helper, sizes, obj);
	if (ret < 0)
		goto err_destroy_framebuffer;

@@ -190,9 +176,7 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper,
err_destroy_framebuffer:
	drm_framebuffer_cleanup(helper->fb);
err_destroy_gem:
	exynos_drm_gem_destroy(exynos_gem_obj);
err_release_fbi:
	drm_fb_helper_release_fbi(helper);
	exynos_drm_gem_destroy(obj);

/*
 * if failed, all resources allocated above would be released by
@@ -285,11 +269,11 @@ static void exynos_drm_fbdev_destroy(struct drm_device *dev,
				      struct drm_fb_helper *fb_helper)
{
	struct exynos_drm_fbdev *exynos_fbd = to_exynos_fbdev(fb_helper);
	struct exynos_drm_gem_obj *exynos_gem_obj = exynos_fbd->exynos_gem_obj;
	struct exynos_drm_gem_obj *obj = exynos_fbd->obj;
	struct drm_framebuffer *fb;

	if (exynos_gem_obj->kvaddr)
		vunmap(exynos_gem_obj->kvaddr);
	if (obj->kvaddr)
		vunmap(obj->kvaddr);

	/* release drm framebuffer and real buffer */
	if (fb_helper->fb && fb_helper->fb->funcs) {
+41 −18
Original line number Diff line number Diff line
@@ -48,11 +48,13 @@

/* registers for base address */
#define G2D_SRC_BASE_ADDR		0x0304
#define G2D_SRC_STRIDE_REG		0x0308
#define G2D_SRC_COLOR_MODE		0x030C
#define G2D_SRC_LEFT_TOP		0x0310
#define G2D_SRC_RIGHT_BOTTOM		0x0314
#define G2D_SRC_PLANE2_BASE_ADDR	0x0318
#define G2D_DST_BASE_ADDR		0x0404
#define G2D_DST_STRIDE_REG		0x0408
#define G2D_DST_COLOR_MODE		0x040C
#define G2D_DST_LEFT_TOP		0x0410
#define G2D_DST_RIGHT_BOTTOM		0x0414
@@ -148,6 +150,7 @@ struct g2d_cmdlist {
 * A structure of buffer description
 *
 * @format: color format
 * @stride: buffer stride/pitch in bytes
 * @left_x: the x coordinates of left top corner
 * @top_y: the y coordinates of left top corner
 * @right_x: the x coordinates of right bottom corner
@@ -156,6 +159,7 @@ struct g2d_cmdlist {
 */
struct g2d_buf_desc {
	unsigned int	format;
	unsigned int	stride;
	unsigned int	left_x;
	unsigned int	top_y;
	unsigned int	right_x;
@@ -589,6 +593,7 @@ static enum g2d_reg_type g2d_get_reg_type(int reg_offset)

	switch (reg_offset) {
	case G2D_SRC_BASE_ADDR:
	case G2D_SRC_STRIDE_REG:
	case G2D_SRC_COLOR_MODE:
	case G2D_SRC_LEFT_TOP:
	case G2D_SRC_RIGHT_BOTTOM:
@@ -598,6 +603,7 @@ static enum g2d_reg_type g2d_get_reg_type(int reg_offset)
		reg_type = REG_TYPE_SRC_PLANE2;
		break;
	case G2D_DST_BASE_ADDR:
	case G2D_DST_STRIDE_REG:
	case G2D_DST_COLOR_MODE:
	case G2D_DST_LEFT_TOP:
	case G2D_DST_RIGHT_BOTTOM:
@@ -652,8 +658,8 @@ static bool g2d_check_buf_desc_is_valid(struct g2d_buf_desc *buf_desc,
						enum g2d_reg_type reg_type,
						unsigned long size)
{
	unsigned int width, height;
	unsigned long area;
	int width, height;
	unsigned long bpp, last_pos;

	/*
	 * check source and destination buffers only.
@@ -662,22 +668,37 @@ static bool g2d_check_buf_desc_is_valid(struct g2d_buf_desc *buf_desc,
	if (reg_type != REG_TYPE_SRC && reg_type != REG_TYPE_DST)
		return true;

	width = buf_desc->right_x - buf_desc->left_x;
	/* This check also makes sure that right_x > left_x. */
	width = (int)buf_desc->right_x - (int)buf_desc->left_x;
	if (width < G2D_LEN_MIN || width > G2D_LEN_MAX) {
		DRM_ERROR("width[%u] is out of range!\n", width);
		DRM_ERROR("width[%d] is out of range!\n", width);
		return false;
	}

	height = buf_desc->bottom_y - buf_desc->top_y;
	/* This check also makes sure that bottom_y > top_y. */
	height = (int)buf_desc->bottom_y - (int)buf_desc->top_y;
	if (height < G2D_LEN_MIN || height > G2D_LEN_MAX) {
		DRM_ERROR("height[%u] is out of range!\n", height);
		DRM_ERROR("height[%d] is out of range!\n", height);
		return false;
	}

	area = (unsigned long)width * (unsigned long)height *
					g2d_get_buf_bpp(buf_desc->format);
	if (area > size) {
		DRM_ERROR("area[%lu] is out of range[%lu]!\n", area, size);
	bpp = g2d_get_buf_bpp(buf_desc->format);

	/* Compute the position of the last byte that the engine accesses. */
	last_pos = ((unsigned long)buf_desc->bottom_y - 1) *
		(unsigned long)buf_desc->stride +
		(unsigned long)buf_desc->right_x * bpp - 1;

	/*
	 * Since right_x > left_x and bottom_y > top_y we already know
	 * that the first_pos < last_pos (first_pos being the position
	 * of the first byte the engine accesses), it just remains to
	 * check if last_pos is smaller then the buffer size.
	 */

	if (last_pos >= size) {
		DRM_ERROR("last engine access position [%lu] "
			"is out of range [%lu]!\n", last_pos, size);
		return false;
	}

@@ -973,8 +994,6 @@ static int g2d_check_reg_offset(struct device *dev,
				goto err;

			reg_type = g2d_get_reg_type(reg_offset);
			if (reg_type == REG_TYPE_NONE)
				goto err;

			/* check userptr buffer type. */
			if ((cmdlist->data[index] & ~0x7fffffff) >> 31) {
@@ -983,14 +1002,22 @@ static int g2d_check_reg_offset(struct device *dev,
			} else
				buf_info->types[reg_type] = BUF_TYPE_GEM;
			break;
		case G2D_SRC_STRIDE_REG:
		case G2D_DST_STRIDE_REG:
			if (for_addr)
				goto err;

			reg_type = g2d_get_reg_type(reg_offset);

			buf_desc = &buf_info->descs[reg_type];
			buf_desc->stride = cmdlist->data[index + 1];
			break;
		case G2D_SRC_COLOR_MODE:
		case G2D_DST_COLOR_MODE:
			if (for_addr)
				goto err;

			reg_type = g2d_get_reg_type(reg_offset);
			if (reg_type == REG_TYPE_NONE)
				goto err;

			buf_desc = &buf_info->descs[reg_type];
			value = cmdlist->data[index + 1];
@@ -1003,8 +1030,6 @@ static int g2d_check_reg_offset(struct device *dev,
				goto err;

			reg_type = g2d_get_reg_type(reg_offset);
			if (reg_type == REG_TYPE_NONE)
				goto err;

			buf_desc = &buf_info->descs[reg_type];
			value = cmdlist->data[index + 1];
@@ -1018,8 +1043,6 @@ static int g2d_check_reg_offset(struct device *dev,
				goto err;

			reg_type = g2d_get_reg_type(reg_offset);
			if (reg_type == REG_TYPE_NONE)
				goto err;

			buf_desc = &buf_info->descs[reg_type];
			value = cmdlist->data[index + 1];
+1 −1
Original line number Diff line number Diff line
@@ -126,7 +126,7 @@ static int exynos_plane_atomic_check(struct drm_plane *plane,
	if (!state->fb)
		return 0;

	nr = exynos_drm_fb_get_buf_cnt(state->fb);
	nr = drm_format_num_planes(state->fb->pixel_format);
	for (i = 0; i < nr; i++) {
		struct exynos_drm_gem_obj *obj =
					exynos_drm_fb_gem_obj(state->fb, i);