unsigned long nr_pages;
struct page **pages;
struct sg_table *sgt;
- DEFINE_DMA_ATTRS(attrs);
phys_addr_t start, size;
struct resource res;
int i, ret;
}
sgt = drm_prime_pages_to_sg(pages, nr_pages);
if (IS_ERR(sgt)) {
- kfree(pages);
- return PTR_ERR(sgt);
+ ret = PTR_ERR(sgt);
+ goto err_free_pages;
+ }
+
+ if (private->domain) {
+ int prot = IOMMU_READ | IOMMU_WRITE;
+
+ memset(&logo->mm, 0, sizeof(logo->mm));
+ ret = drm_mm_insert_node_generic(&private->mm, &logo->mm,
+ size, PAGE_SIZE,
+ 0, 0, 0);
+ if (ret < 0) {
+ DRM_ERROR("out of I/O virtual memory: %d\n", ret);
+ goto err_free_pages;
+ }
+
+ logo->dma_addr = logo->mm.start;
+
+ if (iommu_map_sg(private->domain, logo->dma_addr, sgt->sgl,
+ sgt->nents, prot) < size) {
+ DRM_ERROR("failed to map buffer");
+ ret = -ENOMEM;
+ goto err_remove_node;
+ }
+ } else {
+ dma_map_sg(drm_dev->dev, sgt->sgl, sgt->nents, DMA_TO_DEVICE);
+ logo->dma_addr = sg_dma_address(sgt->sgl);
}
- dma_set_attr(DMA_ATTR_SKIP_CPU_SYNC, &attrs);
- dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &attrs);
- dma_map_sg_attrs(drm_dev->dev, sgt->sgl, sgt->nents,
- DMA_TO_DEVICE, &attrs);
- logo->dma_addr = sg_dma_address(sgt->sgl);
logo->sgt = sgt;
logo->start = res.start;
logo->size = size;
private->logo = logo;
return 0;
+
+err_remove_node:
+ drm_mm_remove_node(&logo->mm);
+err_free_pages:
+ kfree(pages);
+
+ return ret;
}
static struct drm_framebuffer *
#include <drm/drm_fb_helper.h>
#include <drm/drm_crtc_helper.h>
#include <linux/memblock.h>
+#include <linux/iommu.h>
#include "rockchip_drm_drv.h"
#include "rockchip_drm_gem.h"
static void rockchip_drm_fb_destroy(struct drm_framebuffer *fb)
{
struct rockchip_drm_fb *rockchip_fb = to_rockchip_fb(fb);
+ struct rockchip_drm_private *private = fb->dev->dev_private;
struct drm_gem_object *obj;
int i;
void *start = phys_to_virt(logo->start);
void *end = phys_to_virt(logo->size);
- dma_unmap_sg(fb->dev->dev, logo->sgt->sgl,
- logo->sgt->nents, DMA_TO_DEVICE);
+ if (private && private->domain) {
+ iommu_unmap(private->domain, logo->dma_addr,
+ logo->size);
+ drm_mm_remove_node(&logo->mm);
+ } else {
+ dma_unmap_sg(fb->dev->dev, logo->sgt->sgl,
+ logo->sgt->nents, DMA_TO_DEVICE);
+ }
sg_free_table(logo->sgt);
memblock_free(logo->start, logo->size);
free_reserved_area(start, end, -1, "drm_logo");