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

Commit 2f3f2406 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

Inki writes:
"- add dmabuf attach/detach feature
  . This patch would resolve performance deterioration issue
    when v4l2-based driver is using the buffer imported from gem.
- drm/exynos: use DMA_ATTR_NO_KERNEL_MAPPING attribute
  . With gem allocation, kernel space mapping isn't allocated and
    also physical pages aren't mapped with the kernel space.
    The physical pages are mapped with kernel space though vmap
    function only for console framebuffer.
- add the below two patches I missed.
  drm: exynos: moved exynos drm device registration to drm driver
  drm: exynos: moved exynos drm hdmi device registration to drm driver
- add IPP subsystem framework and its-based device drivers.
  . This patch set includes fimc, rotator and gsc drivers to perform
    image scaling, rotation and color space conversion.
- add runtime pm support to hdmi driver.
- And fixups and cleanups."

* 'exynos-drm-next' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos: (30 commits)
  drm/exynos: add gsc ipp driver
  drm/exynos: add rotator ipp driver
  drm/exynos: add fimc ipp driver
  drm/exynos: add iommu support for ipp
  drm/exynos: add ipp subsystem
  drm/exynos: support device tree for fimd
  drm/exynos: support extended screen coordinate of fimd
  drm/exynos: fix x, y coordinates for right bottom pixel
  drm/exynos: fix fb offset calculation for plane
  drm/exynos: hdmi: Fix potential NULL pointer dereference error
  drm/exynos: hdmi: Add CONFIG_OF and use of_match_ptr() macro
  drm/exynos: add support for hdmiphy power control for exynos5
  drm/exynos: add runtime pm support for mixer
  drm/exynos: added runtime pm support for hdmi
  drm/exynos: fix allocation and cache mapping type
  drm/exynos: reorder framebuffer init sequence
  drm/exynos/iommu: fix return value check in drm_create_iommu_mapping()
  drm/exynos: remove unused vaddr member
  drm/exynos: use DMA_ATTR_NO_KERNEL_MAPPING attribute
  drm/exynos: add exception codes to exynos_drm_fbdev_create()
  ...
parents 652a1876 f2646380
Loading
Loading
Loading
Loading
+24 −0
Original line number Diff line number Diff line
@@ -45,3 +45,27 @@ config DRM_EXYNOS_G2D
	depends on DRM_EXYNOS && !VIDEO_SAMSUNG_S5P_G2D
	help
	  Choose this option if you want to use Exynos G2D for DRM.

config DRM_EXYNOS_IPP
	bool "Exynos DRM IPP"
	depends on DRM_EXYNOS
	help
	  Choose this option if you want to use IPP feature for DRM.

config DRM_EXYNOS_FIMC
	bool "Exynos DRM FIMC"
	depends on DRM_EXYNOS_IPP
	help
	  Choose this option if you want to use Exynos FIMC for DRM.

config DRM_EXYNOS_ROTATOR
	bool "Exynos DRM Rotator"
	depends on DRM_EXYNOS_IPP
	help
	  Choose this option if you want to use Exynos Rotator for DRM.

config DRM_EXYNOS_GSC
	bool "Exynos DRM GSC"
	depends on DRM_EXYNOS_IPP && ARCH_EXYNOS5
	help
	  Choose this option if you want to use Exynos GSC for DRM.
+4 −0
Original line number Diff line number Diff line
@@ -16,5 +16,9 @@ exynosdrm-$(CONFIG_DRM_EXYNOS_HDMI) += exynos_hdmi.o exynos_mixer.o \
					   exynos_drm_hdmi.o
exynosdrm-$(CONFIG_DRM_EXYNOS_VIDI)	+= exynos_drm_vidi.o
exynosdrm-$(CONFIG_DRM_EXYNOS_G2D)	+= exynos_drm_g2d.o
exynosdrm-$(CONFIG_DRM_EXYNOS_IPP)	+= exynos_drm_ipp.o
exynosdrm-$(CONFIG_DRM_EXYNOS_FIMC)	+= exynos_drm_fimc.o
exynosdrm-$(CONFIG_DRM_EXYNOS_ROTATOR)	+= exynos_drm_rotator.o
exynosdrm-$(CONFIG_DRM_EXYNOS_GSC)	+= exynos_drm_gsc.o

obj-$(CONFIG_DRM_EXYNOS)		+= exynosdrm.o
+3 −1
Original line number Diff line number Diff line
@@ -48,6 +48,7 @@ static struct i2c_device_id ddc_idtable[] = {
	{ },
};

#ifdef CONFIG_OF
static struct of_device_id hdmiddc_match_types[] = {
	{
		.compatible = "samsung,exynos5-hdmiddc",
@@ -55,12 +56,13 @@ static struct of_device_id hdmiddc_match_types[] = {
		/* end node */
	}
};
#endif

struct i2c_driver ddc_driver = {
	.driver = {
		.name = "exynos-hdmiddc",
		.owner = THIS_MODULE,
		.of_match_table = hdmiddc_match_types,
		.of_match_table = of_match_ptr(hdmiddc_match_types),
	},
	.id_table	= ddc_idtable,
	.probe		= s5p_ddc_probe,
+27 −22
Original line number Diff line number Diff line
@@ -34,7 +34,8 @@ static int lowlevel_buffer_allocate(struct drm_device *dev,
		unsigned int flags, struct exynos_drm_gem_buf *buf)
{
	int ret = 0;
	enum dma_attr attr = DMA_ATTR_FORCE_CONTIGUOUS;
	enum dma_attr attr;
	unsigned int nr_pages;

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

@@ -45,44 +46,49 @@ static int lowlevel_buffer_allocate(struct drm_device *dev,

	init_dma_attrs(&buf->dma_attrs);

	if (flags & EXYNOS_BO_NONCONTIG)
	/*
	 * if EXYNOS_BO_CONTIG, fully physically contiguous memory
	 * region will be allocated else physically contiguous
	 * as possible.
	 */
	if (flags & EXYNOS_BO_CONTIG)
		dma_set_attr(DMA_ATTR_FORCE_CONTIGUOUS, &buf->dma_attrs);

	/*
	 * if EXYNOS_BO_WC or EXYNOS_BO_NONCACHABLE, writecombine mapping
	 * else cachable mapping.
	 */
	if (flags & EXYNOS_BO_WC || !(flags & EXYNOS_BO_CACHABLE))
		attr = DMA_ATTR_WRITE_COMBINE;
	else
		attr = DMA_ATTR_NON_CONSISTENT;

	dma_set_attr(attr, &buf->dma_attrs);
	dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &buf->dma_attrs);

	buf->kvaddr = dma_alloc_attrs(dev->dev, buf->size,
	buf->pages = dma_alloc_attrs(dev->dev, buf->size,
			&buf->dma_addr, GFP_KERNEL, &buf->dma_attrs);
	if (!buf->kvaddr) {
	if (!buf->pages) {
		DRM_ERROR("failed to allocate buffer.\n");
		return -ENOMEM;
	}

	buf->sgt = kzalloc(sizeof(struct sg_table), GFP_KERNEL);
	nr_pages = buf->size >> PAGE_SHIFT;
	buf->sgt = drm_prime_pages_to_sg(buf->pages, nr_pages);
	if (!buf->sgt) {
		DRM_ERROR("failed to allocate sg table.\n");
		DRM_ERROR("failed to get sg table.\n");
		ret = -ENOMEM;
		goto err_free_attrs;
	}

	ret = dma_get_sgtable(dev->dev, buf->sgt, buf->kvaddr, buf->dma_addr,
			buf->size);
	if (ret < 0) {
		DRM_ERROR("failed to get sgtable.\n");
		goto err_free_sgt;
	}

	DRM_DEBUG_KMS("vaddr(0x%lx), dma_addr(0x%lx), size(0x%lx)\n",
			(unsigned long)buf->kvaddr,
	DRM_DEBUG_KMS("dma_addr(0x%lx), size(0x%lx)\n",
			(unsigned long)buf->dma_addr,
			buf->size);

	return ret;

err_free_sgt:
	kfree(buf->sgt);
	buf->sgt = NULL;
err_free_attrs:
	dma_free_attrs(dev->dev, buf->size, buf->kvaddr,
	dma_free_attrs(dev->dev, buf->size, buf->pages,
			(dma_addr_t)buf->dma_addr, &buf->dma_attrs);
	buf->dma_addr = (dma_addr_t)NULL;

@@ -99,8 +105,7 @@ static void lowlevel_buffer_deallocate(struct drm_device *dev,
		return;
	}

	DRM_DEBUG_KMS("vaddr(0x%lx), dma_addr(0x%lx), size(0x%lx)\n",
			(unsigned long)buf->kvaddr,
	DRM_DEBUG_KMS("dma_addr(0x%lx), size(0x%lx)\n",
			(unsigned long)buf->dma_addr,
			buf->size);

@@ -109,7 +114,7 @@ static void lowlevel_buffer_deallocate(struct drm_device *dev,
	kfree(buf->sgt);
	buf->sgt = NULL;

	dma_free_attrs(dev->dev, buf->size, buf->kvaddr,
	dma_free_attrs(dev->dev, buf->size, buf->pages,
				(dma_addr_t)buf->dma_addr, &buf->dma_attrs);
	buf->dma_addr = (dma_addr_t)NULL;
}
+73 −31
Original line number Diff line number Diff line
@@ -30,63 +30,107 @@

#include <linux/dma-buf.h>

static struct sg_table *exynos_get_sgt(struct drm_device *drm_dev,
					struct exynos_drm_gem_buf *buf)
struct exynos_drm_dmabuf_attachment {
	struct sg_table sgt;
	enum dma_data_direction dir;
};

static int exynos_gem_attach_dma_buf(struct dma_buf *dmabuf,
					struct device *dev,
					struct dma_buf_attachment *attach)
{
	struct sg_table *sgt = NULL;
	int ret;
	struct exynos_drm_dmabuf_attachment *exynos_attach;

	sgt = kzalloc(sizeof(*sgt), GFP_KERNEL);
	if (!sgt)
		goto out;
	exynos_attach = kzalloc(sizeof(*exynos_attach), GFP_KERNEL);
	if (!exynos_attach)
		return -ENOMEM;

	ret = dma_get_sgtable(drm_dev->dev, sgt, buf->kvaddr,
				buf->dma_addr, buf->size);
	if (ret < 0) {
		DRM_ERROR("failed to get sgtable.\n");
		goto err_free_sgt;
	exynos_attach->dir = DMA_NONE;
	attach->priv = exynos_attach;

	return 0;
}

	return sgt;
static void exynos_gem_detach_dma_buf(struct dma_buf *dmabuf,
					struct dma_buf_attachment *attach)
{
	struct exynos_drm_dmabuf_attachment *exynos_attach = attach->priv;
	struct sg_table *sgt;

err_free_sgt:
	kfree(sgt);
	sgt = NULL;
out:
	return NULL;
	if (!exynos_attach)
		return;

	sgt = &exynos_attach->sgt;

	if (exynos_attach->dir != DMA_NONE)
		dma_unmap_sg(attach->dev, sgt->sgl, sgt->nents,
				exynos_attach->dir);

	sg_free_table(sgt);
	kfree(exynos_attach);
	attach->priv = NULL;
}

static struct sg_table *
		exynos_gem_map_dma_buf(struct dma_buf_attachment *attach,
					enum dma_data_direction dir)
{
	struct exynos_drm_dmabuf_attachment *exynos_attach = attach->priv;
	struct exynos_drm_gem_obj *gem_obj = attach->dmabuf->priv;
	struct drm_device *dev = gem_obj->base.dev;
	struct exynos_drm_gem_buf *buf;
	struct scatterlist *rd, *wr;
	struct sg_table *sgt = NULL;
	int nents;
	unsigned int i;
	int nents, ret;

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

	if (WARN_ON(dir == DMA_NONE))
		return ERR_PTR(-EINVAL);

	/* just return current sgt if already requested. */
	if (exynos_attach->dir == dir)
		return &exynos_attach->sgt;

	/* reattaching is not allowed. */
	if (WARN_ON(exynos_attach->dir != DMA_NONE))
		return ERR_PTR(-EBUSY);

	buf = gem_obj->buffer;
	if (!buf) {
		DRM_ERROR("buffer is null.\n");
		return sgt;
		return ERR_PTR(-ENOMEM);
	}

	sgt = &exynos_attach->sgt;

	ret = sg_alloc_table(sgt, buf->sgt->orig_nents, GFP_KERNEL);
	if (ret) {
		DRM_ERROR("failed to alloc sgt.\n");
		return ERR_PTR(-ENOMEM);
	}

	mutex_lock(&dev->struct_mutex);

	sgt = exynos_get_sgt(dev, buf);
	if (!sgt)
		goto err_unlock;
	rd = buf->sgt->sgl;
	wr = sgt->sgl;
	for (i = 0; i < sgt->orig_nents; ++i) {
		sg_set_page(wr, sg_page(rd), rd->length, rd->offset);
		rd = sg_next(rd);
		wr = sg_next(wr);
	}

	nents = dma_map_sg(attach->dev, sgt->sgl, sgt->nents, dir);
	nents = dma_map_sg(attach->dev, sgt->sgl, sgt->orig_nents, dir);
	if (!nents) {
		DRM_ERROR("failed to map sgl with iommu.\n");
		sgt = NULL;
		sgt = ERR_PTR(-EIO);
		goto err_unlock;
	}

	exynos_attach->dir = dir;
	attach->priv = exynos_attach;

	DRM_DEBUG_PRIME("buffer size = 0x%lx\n", buf->size);

err_unlock:
@@ -98,11 +142,7 @@ static void exynos_gem_unmap_dma_buf(struct dma_buf_attachment *attach,
						struct sg_table *sgt,
						enum dma_data_direction dir)
{
	dma_unmap_sg(attach->dev, sgt->sgl, sgt->nents, dir);

	sg_free_table(sgt);
	kfree(sgt);
	sgt = NULL;
	/* Nothing to do. */
}

static void exynos_dmabuf_release(struct dma_buf *dmabuf)
@@ -164,6 +204,8 @@ static int exynos_gem_dmabuf_mmap(struct dma_buf *dma_buf,
}

static struct dma_buf_ops exynos_dmabuf_ops = {
	.attach			= exynos_gem_attach_dma_buf,
	.detach			= exynos_gem_detach_dma_buf,
	.map_dma_buf		= exynos_gem_map_dma_buf,
	.unmap_dma_buf		= exynos_gem_unmap_dma_buf,
	.kmap			= exynos_gem_dmabuf_kmap,
Loading