Skip to content

Commit

Permalink
Merge branch 'exynos-drm-next' of git://git.kernel.org/pub/scm/linux/…
Browse files Browse the repository at this point in the history
…kernel/git/daeinki/drm-exynos into drm-next

This patch set adds iommu support, userptr feature to g2d, minor fixups
and code cleanups.

And the iommu feature has dependency of the below patches related to
dma mapping framework.

This patch is used to allocate fully physically contiguous memory region.
- add sending AVI and AVI info frames.
  . this adds some codes for composing AVI and AUI info frames
    and send them every VSYNC for HDMI Certification.
- bug fix to previous pull request.
- add some code cleanup

* 'exynos-drm-next' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos: (32 commits)
  drm/exynos: sending AVI and AUI info frames
  drm/exynos: Use devm_clk_get in exynos_drm_fimd.c
  drm/exynos: Use devm_* APIs in exynos_hdmi.c
  drm/exynos: Use devm_clk_get in exynos_mixer.c
  drm/exynos: Fix potential NULL pointer dereference
  drm/exynos: Use devm_clk_get in exynos_drm_g2d.c
  drm/exynos: use sgt instead of pages for framebuffer address
  drm: exynos: fix for loosing display mode header during mode adjustment
  drm/exynos: fix memory leak to EDID block
  drm/exynos: remove 'pages' and 'page_size' elements in exynos gem buffer
  drm/exynos: add exynos drm specific fb_mmap function
  drm/exynos: make sure that overlay data are updated
  drm/exynos: add vm_ops to specific gem mmaper
  drm/exynos: add userptr feature for g2d module
  drm/exynos: remove unnecessary sg_alloc_table call
  drm: exynos: fix for mapping of dma buffers
  drm/exynos: remove EXYNOS_BO_NONCONTIG type checking.
  drm/exynos: add iommu support for g2d
  drm/exynos: add iommu support for hdmi driver
  drm/exynos: add iommu support to fimd driver
  ...
  • Loading branch information
Dave Airlie committed Dec 5, 2012
2 parents 7136470 + a144c2e commit 00f09af
Show file tree
Hide file tree
Showing 30 changed files with 1,469 additions and 637 deletions.
9 changes: 9 additions & 0 deletions Documentation/DMA-attributes.txt
Original file line number Diff line number Diff line change
Expand Up @@ -91,3 +91,12 @@ transferred to 'device' domain. This attribute can be also used for
dma_unmap_{single,page,sg} functions family to force buffer to stay in
device domain after releasing a mapping for it. Use this attribute with
care!

DMA_ATTR_FORCE_CONTIGUOUS
-------------------------

By default DMA-mapping subsystem is allowed to assemble the buffer
allocated by dma_alloc_attrs() function from individual pages if it can
be mapped as contiguous chunk into device dma address space. By
specifing this attribute the allocated buffer is forced to be contiguous
also in physical memory.
41 changes: 33 additions & 8 deletions arch/arm/mm/dma-mapping.c
Original file line number Diff line number Diff line change
Expand Up @@ -1036,7 +1036,8 @@ static inline void __free_iova(struct dma_iommu_mapping *mapping,
spin_unlock_irqrestore(&mapping->lock, flags);
}

static struct page **__iommu_alloc_buffer(struct device *dev, size_t size, gfp_t gfp)
static struct page **__iommu_alloc_buffer(struct device *dev, size_t size,
gfp_t gfp, struct dma_attrs *attrs)
{
struct page **pages;
int count = size >> PAGE_SHIFT;
Expand All @@ -1050,6 +1051,23 @@ static struct page **__iommu_alloc_buffer(struct device *dev, size_t size, gfp_t
if (!pages)
return NULL;

if (dma_get_attr(DMA_ATTR_FORCE_CONTIGUOUS, attrs))
{
unsigned long order = get_order(size);
struct page *page;

page = dma_alloc_from_contiguous(dev, count, order);
if (!page)
goto error;

__dma_clear_buffer(page, size);

for (i = 0; i < count; i++)
pages[i] = page + i;

return pages;
}

while (count) {
int j, order = __fls(count);

Expand Down Expand Up @@ -1083,14 +1101,21 @@ static struct page **__iommu_alloc_buffer(struct device *dev, size_t size, gfp_t
return NULL;
}

static int __iommu_free_buffer(struct device *dev, struct page **pages, size_t size)
static int __iommu_free_buffer(struct device *dev, struct page **pages,
size_t size, struct dma_attrs *attrs)
{
int count = size >> PAGE_SHIFT;
int array_size = count * sizeof(struct page *);
int i;
for (i = 0; i < count; i++)
if (pages[i])
__free_pages(pages[i], 0);

if (dma_get_attr(DMA_ATTR_FORCE_CONTIGUOUS, attrs)) {
dma_release_from_contiguous(dev, pages[0], count);
} else {
for (i = 0; i < count; i++)
if (pages[i])
__free_pages(pages[i], 0);
}

if (array_size <= PAGE_SIZE)
kfree(pages);
else
Expand Down Expand Up @@ -1252,7 +1277,7 @@ static void *arm_iommu_alloc_attrs(struct device *dev, size_t size,
if (gfp & GFP_ATOMIC)
return __iommu_alloc_atomic(dev, size, handle);

pages = __iommu_alloc_buffer(dev, size, gfp);
pages = __iommu_alloc_buffer(dev, size, gfp, attrs);
if (!pages)
return NULL;

Expand All @@ -1273,7 +1298,7 @@ static void *arm_iommu_alloc_attrs(struct device *dev, size_t size,
err_mapping:
__iommu_remove_mapping(dev, *handle, size);
err_buffer:
__iommu_free_buffer(dev, pages, size);
__iommu_free_buffer(dev, pages, size, attrs);
return NULL;
}

Expand Down Expand Up @@ -1329,7 +1354,7 @@ void arm_iommu_free_attrs(struct device *dev, size_t size, void *cpu_addr,
}

__iommu_remove_mapping(dev, handle, size);
__iommu_free_buffer(dev, pages, size);
__iommu_free_buffer(dev, pages, size, attrs);
}

static int arm_iommu_get_sgtable(struct device *dev, struct sg_table *sgt,
Expand Down
3 changes: 3 additions & 0 deletions drivers/gpu/drm/drm_irq.c
Original file line number Diff line number Diff line change
Expand Up @@ -1021,6 +1021,8 @@ void drm_vblank_off(struct drm_device *dev, int crtc)

/* Send any queued vblank events, lest the natives grow disquiet */
seq = drm_vblank_count_and_time(dev, crtc, &now);

spin_lock(&dev->event_lock);
list_for_each_entry_safe(e, t, &dev->vblank_event_list, base.link) {
if (e->pipe != crtc)
continue;
Expand All @@ -1031,6 +1033,7 @@ void drm_vblank_off(struct drm_device *dev, int crtc)
drm_vblank_put(dev, e->pipe);
send_vblank_event(dev, e, seq, &now);
}
spin_unlock(&dev->event_lock);

spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
}
Expand Down
6 changes: 6 additions & 0 deletions drivers/gpu/drm/exynos/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ config DRM_EXYNOS
Choose this option if you have a Samsung SoC EXYNOS chipset.
If M is selected the module will be called exynosdrm.

config DRM_EXYNOS_IOMMU
bool "EXYNOS DRM IOMMU Support"
depends on DRM_EXYNOS && EXYNOS_IOMMU && ARM_DMA_USE_IOMMU
help
Choose this option if you want to use IOMMU feature for DRM.

config DRM_EXYNOS_DMABUF
bool "EXYNOS DRM DMABUF"
depends on DRM_EXYNOS
Expand Down
1 change: 1 addition & 0 deletions drivers/gpu/drm/exynos/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ exynosdrm-y := exynos_drm_drv.o exynos_drm_encoder.o exynos_drm_connector.o \
exynos_drm_buf.o exynos_drm_gem.o exynos_drm_core.o \
exynos_drm_plane.o

exynosdrm-$(CONFIG_DRM_EXYNOS_IOMMU) += exynos_drm_iommu.o
exynosdrm-$(CONFIG_DRM_EXYNOS_DMABUF) += exynos_drm_dmabuf.o
exynosdrm-$(CONFIG_DRM_EXYNOS_FIMD) += exynos_drm_fimd.o
exynosdrm-$(CONFIG_DRM_EXYNOS_HDMI) += exynos_hdmi.o exynos_mixer.o \
Expand Down
94 changes: 25 additions & 69 deletions drivers/gpu/drm/exynos/exynos_drm_buf.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,73 +33,42 @@
static int lowlevel_buffer_allocate(struct drm_device *dev,
unsigned int flags, struct exynos_drm_gem_buf *buf)
{
dma_addr_t start_addr;
unsigned int npages, i = 0;
struct scatterlist *sgl;
int ret = 0;
enum dma_attr attr = DMA_ATTR_FORCE_CONTIGUOUS;

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

if (IS_NONCONTIG_BUFFER(flags)) {
DRM_DEBUG_KMS("not support allocation type.\n");
return -EINVAL;
}

if (buf->dma_addr) {
DRM_DEBUG_KMS("already allocated.\n");
return 0;
}

if (buf->size >= SZ_1M) {
npages = buf->size >> SECTION_SHIFT;
buf->page_size = SECTION_SIZE;
} else if (buf->size >= SZ_64K) {
npages = buf->size >> 16;
buf->page_size = SZ_64K;
} else {
npages = buf->size >> PAGE_SHIFT;
buf->page_size = PAGE_SIZE;
}
init_dma_attrs(&buf->dma_attrs);

buf->sgt = kzalloc(sizeof(struct sg_table), GFP_KERNEL);
if (!buf->sgt) {
DRM_ERROR("failed to allocate sg table.\n");
return -ENOMEM;
}
if (flags & EXYNOS_BO_NONCONTIG)
attr = DMA_ATTR_WRITE_COMBINE;

ret = sg_alloc_table(buf->sgt, npages, GFP_KERNEL);
if (ret < 0) {
DRM_ERROR("failed to initialize sg table.\n");
kfree(buf->sgt);
buf->sgt = NULL;
return -ENOMEM;
}
dma_set_attr(attr, &buf->dma_attrs);

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

buf->pages = kzalloc(sizeof(struct page) * npages, GFP_KERNEL);
if (!buf->pages) {
DRM_ERROR("failed to allocate pages.\n");
buf->sgt = kzalloc(sizeof(struct sg_table), GFP_KERNEL);
if (!buf->sgt) {
DRM_ERROR("failed to allocate sg table.\n");
ret = -ENOMEM;
goto err2;
goto err_free_attrs;
}

sgl = buf->sgt->sgl;
start_addr = buf->dma_addr;

while (i < npages) {
buf->pages[i] = phys_to_page(start_addr);
sg_set_page(sgl, buf->pages[i], buf->page_size, 0);
sg_dma_address(sgl) = start_addr;
start_addr += buf->page_size;
sgl = sg_next(sgl);
i++;
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",
Expand All @@ -108,14 +77,14 @@ static int lowlevel_buffer_allocate(struct drm_device *dev,
buf->size);

return ret;
err2:
dma_free_writecombine(dev->dev, buf->size, buf->kvaddr,
(dma_addr_t)buf->dma_addr);
buf->dma_addr = (dma_addr_t)NULL;
err1:
sg_free_table(buf->sgt);

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

return ret;
}
Expand All @@ -125,16 +94,6 @@ static void lowlevel_buffer_deallocate(struct drm_device *dev,
{
DRM_DEBUG_KMS("%s.\n", __FILE__);

/*
* release only physically continuous memory and
* non-continuous memory would be released by exynos
* gem framework.
*/
if (IS_NONCONTIG_BUFFER(flags)) {
DRM_DEBUG_KMS("not support allocation type.\n");
return;
}

if (!buf->dma_addr) {
DRM_DEBUG_KMS("dma_addr is invalid.\n");
return;
Expand All @@ -150,11 +109,8 @@ static void lowlevel_buffer_deallocate(struct drm_device *dev,
kfree(buf->sgt);
buf->sgt = NULL;

kfree(buf->pages);
buf->pages = NULL;

dma_free_writecombine(dev->dev, buf->size, buf->kvaddr,
(dma_addr_t)buf->dma_addr);
dma_free_attrs(dev->dev, buf->size, buf->kvaddr,
(dma_addr_t)buf->dma_addr, &buf->dma_attrs);
buf->dma_addr = (dma_addr_t)NULL;
}

Expand Down
4 changes: 2 additions & 2 deletions drivers/gpu/drm/exynos/exynos_drm_buf.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,12 @@ struct exynos_drm_gem_buf *exynos_drm_init_buf(struct drm_device *dev,
void exynos_drm_fini_buf(struct drm_device *dev,
struct exynos_drm_gem_buf *buffer);

/* allocate physical memory region and setup sgt and pages. */
/* allocate physical memory region and setup sgt. */
int exynos_drm_alloc_buf(struct drm_device *dev,
struct exynos_drm_gem_buf *buf,
unsigned int flags);

/* release physical memory region, sgt and pages. */
/* release physical memory region, and sgt. */
void exynos_drm_free_buf(struct drm_device *dev,
unsigned int flags,
struct exynos_drm_gem_buf *buffer);
Expand Down
5 changes: 5 additions & 0 deletions drivers/gpu/drm/exynos/exynos_drm_crtc.c
Original file line number Diff line number Diff line change
Expand Up @@ -236,16 +236,21 @@ static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc,
goto out;
}

spin_lock_irq(&dev->event_lock);
list_add_tail(&event->base.link,
&dev_priv->pageflip_event_list);
spin_unlock_irq(&dev->event_lock);

crtc->fb = fb;
ret = exynos_drm_crtc_mode_set_base(crtc, crtc->x, crtc->y,
NULL);
if (ret) {
crtc->fb = old_fb;

spin_lock_irq(&dev->event_lock);
drm_vblank_put(dev, exynos_crtc->pipe);
list_del(&event->base.link);
spin_unlock_irq(&dev->event_lock);

goto out;
}
Expand Down
Loading

0 comments on commit 00f09af

Please sign in to comment.