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

Commit c976cb37 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

The summary:
. Add display mode check operaion to mixer driver
  - Mixer IP also can put certain restrictions on the proposed
    display modes and these restrictions need to be considered
    during mode negotiation, which happens immediately after
    edid parsing.
. Set correct mode for range of resolutions
  - With this patch, the mixer driver could find the correct mode
    for the range of resolutions upto 1080 vertical lines.
. Support extra resolution for hdmi
  - This patch programs the core and timing generator registers
    using the timing data provided in drm_display_mode without
    hard-coded configurations. So this patch adds additional PHY
    configs to allow us to support more permissible resolutions
    and refresh rates.
. Add device tree support for g2d
  - This patch adds just the compatible string for exynos5250 SoC
    so that with device tree enabling, this driver can be probed.
. And bug fixes and code cleanups.

* 'exynos-drm-next' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos:
  drm/exynos: Add device tree based discovery support for G2D
  drm/exynos: hdmi: support extra resolutions using drm_display_mode timings
  drm/exynos: mixer: set correct mode for range of resolutions
  drm/exynos: implement display-mode-check callback in mixer driver
  drm/exynos: add display-mode-check operation to exynos_mixer_ops struct
  drm/exynos: release resources properly when fb creation is failed.
  drm/exynos: fix wrong pointer access at vm close.
  drm/exynos: Add missing braces around sizeof
  drm/exynos: consider exception case to fb handle creation
  drm/exynos: fix iommu address allocation order
parents 907a773b 95fc6337
Loading
Loading
Loading
Loading
+31 −24
Original line number Original line Diff line number Diff line
@@ -99,6 +99,10 @@ static int exynos_drm_fb_create_handle(struct drm_framebuffer *fb,


	DRM_DEBUG_KMS("%s\n", __FILE__);
	DRM_DEBUG_KMS("%s\n", __FILE__);


	/* 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,
	return drm_gem_handle_create(file_priv,
			&exynos_fb->exynos_gem_obj[0]->base, handle);
			&exynos_fb->exynos_gem_obj[0]->base, handle);
}
}
@@ -217,23 +221,25 @@ exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv,
		      struct drm_mode_fb_cmd2 *mode_cmd)
		      struct drm_mode_fb_cmd2 *mode_cmd)
{
{
	struct drm_gem_object *obj;
	struct drm_gem_object *obj;
	struct exynos_drm_gem_obj *exynos_gem_obj;
	struct exynos_drm_fb *exynos_fb;
	struct exynos_drm_fb *exynos_fb;
	int i, ret;
	int i, ret;


	DRM_DEBUG_KMS("%s\n", __FILE__);
	DRM_DEBUG_KMS("%s\n", __FILE__);


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

	exynos_fb = kzalloc(sizeof(*exynos_fb), GFP_KERNEL);
	exynos_fb = kzalloc(sizeof(*exynos_fb), GFP_KERNEL);
	if (!exynos_fb) {
	if (!exynos_fb) {
		DRM_ERROR("failed to allocate exynos drm framebuffer\n");
		DRM_ERROR("failed to allocate exynos drm framebuffer\n");
		return ERR_PTR(-ENOMEM);
		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);
	drm_helper_mode_fill_fb_struct(&exynos_fb->fb, mode_cmd);
	exynos_fb->exynos_gem_obj[0] = to_exynos_gem_obj(obj);
	exynos_fb->exynos_gem_obj[0] = to_exynos_gem_obj(obj);
	exynos_fb->buf_cnt = exynos_drm_format_num_buffers(mode_cmd);
	exynos_fb->buf_cnt = exynos_drm_format_num_buffers(mode_cmd);
@@ -241,45 +247,46 @@ exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv,
	DRM_DEBUG_KMS("buf_cnt = %d\n", exynos_fb->buf_cnt);
	DRM_DEBUG_KMS("buf_cnt = %d\n", exynos_fb->buf_cnt);


	for (i = 1; i < exynos_fb->buf_cnt; i++) {
	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,
		obj = drm_gem_object_lookup(dev, file_priv,
				mode_cmd->handles[i]);
				mode_cmd->handles[i]);
		if (!obj) {
		if (!obj) {
			DRM_ERROR("failed to lookup gem object\n");
			DRM_ERROR("failed to lookup gem object\n");
			kfree(exynos_fb);
			ret = -ENOENT;
			return ERR_PTR(-ENOENT);
			exynos_fb->buf_cnt = i;
			goto err_unreference;
		}
		}


		exynos_gem_obj = to_exynos_gem_obj(obj);
		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);
		ret = check_fb_gem_memory_type(dev, exynos_gem_obj);
		if (ret < 0) {
		if (ret < 0) {
			DRM_ERROR("cannot use this gem memory type for fb.\n");
			DRM_ERROR("cannot use this gem memory type for fb.\n");
			kfree(exynos_fb);
			goto err_unreference;
			return ERR_PTR(ret);
		}
		}

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


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

	return &exynos_fb->fb;

err_unreference:
	for (i = 0; i < exynos_fb->buf_cnt; i++) {
	for (i = 0; i < exynos_fb->buf_cnt; i++) {
			struct exynos_drm_gem_obj *gem_obj;
		struct drm_gem_object *obj;


			gem_obj = exynos_fb->exynos_gem_obj[i];
		obj = &exynos_fb->exynos_gem_obj[i]->base;
			drm_gem_object_unreference_unlocked(&gem_obj->base);
		if (obj)
			drm_gem_object_unreference_unlocked(obj);
	}
	}

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


	return &exynos_fb->fb;
}

struct exynos_drm_gem_buf *exynos_drm_fb_buffer(struct drm_framebuffer *fb,
struct exynos_drm_gem_buf *exynos_drm_fb_buffer(struct drm_framebuffer *fb,
						int index)
						int index)
{
{
+11 −1
Original line number Original line Diff line number Diff line
@@ -19,6 +19,7 @@
#include <linux/workqueue.h>
#include <linux/workqueue.h>
#include <linux/dma-mapping.h>
#include <linux/dma-mapping.h>
#include <linux/dma-attrs.h>
#include <linux/dma-attrs.h>
#include <linux/of.h>


#include <drm/drmP.h>
#include <drm/drmP.h>
#include <drm/exynos_drm.h>
#include <drm/exynos_drm.h>
@@ -429,7 +430,7 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct drm_device *drm_dev,


	g2d_userptr->pages = pages;
	g2d_userptr->pages = pages;


	sgt = kzalloc(sizeof *sgt, GFP_KERNEL);
	sgt = kzalloc(sizeof(*sgt), GFP_KERNEL);
	if (!sgt) {
	if (!sgt) {
		DRM_ERROR("failed to allocate sg table.\n");
		DRM_ERROR("failed to allocate sg table.\n");
		ret = -ENOMEM;
		ret = -ENOMEM;
@@ -1240,6 +1241,14 @@ static int g2d_resume(struct device *dev)


static SIMPLE_DEV_PM_OPS(g2d_pm_ops, g2d_suspend, g2d_resume);
static SIMPLE_DEV_PM_OPS(g2d_pm_ops, g2d_suspend, g2d_resume);


#ifdef CONFIG_OF
static const struct of_device_id exynos_g2d_match[] = {
	{ .compatible = "samsung,exynos5250-g2d" },
	{},
};
MODULE_DEVICE_TABLE(of, exynos_g2d_match);
#endif

struct platform_driver g2d_driver = {
struct platform_driver g2d_driver = {
	.probe		= g2d_probe,
	.probe		= g2d_probe,
	.remove		= g2d_remove,
	.remove		= g2d_remove,
@@ -1247,5 +1256,6 @@ struct platform_driver g2d_driver = {
		.name	= "s5p-g2d",
		.name	= "s5p-g2d",
		.owner	= THIS_MODULE,
		.owner	= THIS_MODULE,
		.pm	= &g2d_pm_ops,
		.pm	= &g2d_pm_ops,
		.of_match_table = of_match_ptr(exynos_g2d_match),
	},
	},
};
};
+21 −12
Original line number Original line Diff line number Diff line
@@ -329,17 +329,11 @@ static struct drm_file *exynos_drm_find_drm_file(struct drm_device *drm_dev,
{
{
	struct drm_file *file_priv;
	struct drm_file *file_priv;


	mutex_lock(&drm_dev->struct_mutex);

	/* find current process's drm_file from filelist. */
	/* find current process's drm_file from filelist. */
	list_for_each_entry(file_priv, &drm_dev->filelist, lhead) {
	list_for_each_entry(file_priv, &drm_dev->filelist, lhead)
		if (file_priv->filp == filp) {
		if (file_priv->filp == filp)
			mutex_unlock(&drm_dev->struct_mutex);
			return file_priv;
			return file_priv;
		}
	}


	mutex_unlock(&drm_dev->struct_mutex);
	WARN_ON(1);
	WARN_ON(1);


	return ERR_PTR(-EFAULT);
	return ERR_PTR(-EFAULT);
@@ -400,9 +394,7 @@ static int exynos_drm_gem_mmap_buffer(struct file *filp,
	 */
	 */
	drm_gem_object_reference(obj);
	drm_gem_object_reference(obj);


	mutex_lock(&drm_dev->struct_mutex);
	drm_vm_open_locked(drm_dev, vma);
	drm_vm_open_locked(drm_dev, vma);
	mutex_unlock(&drm_dev->struct_mutex);


	return 0;
	return 0;
}
}
@@ -431,6 +423,16 @@ int exynos_drm_gem_mmap_ioctl(struct drm_device *dev, void *data,
		return -EINVAL;
		return -EINVAL;
	}
	}


	/*
	 * We have to use gem object and its fops for specific mmaper,
	 * but vm_mmap() can deliver only filp. So we have to change
	 * filp->f_op and filp->private_data temporarily, then restore
	 * again. So it is important to keep lock until restoration the
	 * settings to prevent others from misuse of filp->f_op or
	 * filp->private_data.
	 */
	mutex_lock(&dev->struct_mutex);

	/*
	/*
	 * Set specific mmper's fops. And it will be restored by
	 * Set specific mmper's fops. And it will be restored by
	 * exynos_drm_gem_mmap_buffer to dev->driver->fops.
	 * exynos_drm_gem_mmap_buffer to dev->driver->fops.
@@ -448,13 +450,20 @@ int exynos_drm_gem_mmap_ioctl(struct drm_device *dev, void *data,
	addr = vm_mmap(file_priv->filp, 0, args->size,
	addr = vm_mmap(file_priv->filp, 0, args->size,
			PROT_READ | PROT_WRITE, MAP_SHARED, 0);
			PROT_READ | PROT_WRITE, MAP_SHARED, 0);


	drm_gem_object_unreference_unlocked(obj);
	drm_gem_object_unreference(obj);


	if (IS_ERR((void *)addr)) {
	if (IS_ERR((void *)addr)) {
		/* check filp->f_op, filp->private_data are restored */
		if (file_priv->filp->f_op == &exynos_drm_gem_fops) {
			file_priv->filp->f_op = fops_get(dev->driver->fops);
			file_priv->filp->private_data = file_priv;
			file_priv->filp->private_data = file_priv;
		}
		mutex_unlock(&dev->struct_mutex);
		return PTR_ERR((void *)addr);
		return PTR_ERR((void *)addr);
	}
	}


	mutex_unlock(&dev->struct_mutex);

	args->mapped = addr;
	args->mapped = addr;


	DRM_DEBUG_KMS("mapped = 0x%lx\n", (unsigned long)args->mapped);
	DRM_DEBUG_KMS("mapped = 0x%lx\n", (unsigned long)args->mapped);
+12 −0
Original line number Original line Diff line number Diff line
@@ -124,9 +124,21 @@ static struct edid *drm_hdmi_get_edid(struct device *dev,
static int drm_hdmi_check_timing(struct device *dev, void *timing)
static int drm_hdmi_check_timing(struct device *dev, void *timing)
{
{
	struct drm_hdmi_context *ctx = to_context(dev);
	struct drm_hdmi_context *ctx = to_context(dev);
	int ret = 0;


	DRM_DEBUG_KMS("%s\n", __FILE__);
	DRM_DEBUG_KMS("%s\n", __FILE__);


	/*
	* Both, mixer and hdmi should be able to handle the requested mode.
	* If any of the two fails, return mode as BAD.
	*/

	if (mixer_ops && mixer_ops->check_timing)
		ret = mixer_ops->check_timing(ctx->mixer_ctx->ctx, timing);

	if (ret)
		return ret;

	if (hdmi_ops && hdmi_ops->check_timing)
	if (hdmi_ops && hdmi_ops->check_timing)
		return hdmi_ops->check_timing(ctx->hdmi_ctx->ctx, timing);
		return hdmi_ops->check_timing(ctx->hdmi_ctx->ctx, timing);


+4 −1
Original line number Original line Diff line number Diff line
@@ -32,7 +32,7 @@ struct exynos_hdmi_ops {
	bool (*is_connected)(void *ctx);
	bool (*is_connected)(void *ctx);
	struct edid *(*get_edid)(void *ctx,
	struct edid *(*get_edid)(void *ctx,
			struct drm_connector *connector);
			struct drm_connector *connector);
	int (*check_timing)(void *ctx, void *timing);
	int (*check_timing)(void *ctx, struct fb_videomode *timing);
	int (*power_on)(void *ctx, int mode);
	int (*power_on)(void *ctx, int mode);


	/* manager */
	/* manager */
@@ -58,6 +58,9 @@ struct exynos_mixer_ops {
	void (*win_mode_set)(void *ctx, struct exynos_drm_overlay *overlay);
	void (*win_mode_set)(void *ctx, struct exynos_drm_overlay *overlay);
	void (*win_commit)(void *ctx, int zpos);
	void (*win_commit)(void *ctx, int zpos);
	void (*win_disable)(void *ctx, int zpos);
	void (*win_disable)(void *ctx, int zpos);

	/* display */
	int (*check_timing)(void *ctx, struct fb_videomode *timing);
};
};


void exynos_hdmi_drv_attach(struct exynos_drm_hdmi_context *ctx);
void exynos_hdmi_drv_attach(struct exynos_drm_hdmi_context *ctx);
Loading