162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2011 Texas Instruments Incorporated - https://www.ti.com/
462306a36Sopenharmony_ci * Author: Rob Clark <rob.clark@linaro.org>
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <linux/dma-buf.h>
862306a36Sopenharmony_ci#include <linux/highmem.h>
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <drm/drm_prime.h>
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include "omap_drv.h"
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ciMODULE_IMPORT_NS(DMA_BUF);
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci/* -----------------------------------------------------------------------------
1762306a36Sopenharmony_ci * DMABUF Export
1862306a36Sopenharmony_ci */
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_cistatic struct sg_table *omap_gem_map_dma_buf(
2162306a36Sopenharmony_ci		struct dma_buf_attachment *attachment,
2262306a36Sopenharmony_ci		enum dma_data_direction dir)
2362306a36Sopenharmony_ci{
2462306a36Sopenharmony_ci	struct drm_gem_object *obj = attachment->dmabuf->priv;
2562306a36Sopenharmony_ci	struct sg_table *sg;
2662306a36Sopenharmony_ci	sg = omap_gem_get_sg(obj, dir);
2762306a36Sopenharmony_ci	if (IS_ERR(sg))
2862306a36Sopenharmony_ci		return sg;
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci	return sg;
3162306a36Sopenharmony_ci}
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_cistatic void omap_gem_unmap_dma_buf(struct dma_buf_attachment *attachment,
3462306a36Sopenharmony_ci		struct sg_table *sg, enum dma_data_direction dir)
3562306a36Sopenharmony_ci{
3662306a36Sopenharmony_ci	struct drm_gem_object *obj = attachment->dmabuf->priv;
3762306a36Sopenharmony_ci	omap_gem_put_sg(obj, sg);
3862306a36Sopenharmony_ci}
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_cistatic int omap_gem_dmabuf_begin_cpu_access(struct dma_buf *buffer,
4162306a36Sopenharmony_ci		enum dma_data_direction dir)
4262306a36Sopenharmony_ci{
4362306a36Sopenharmony_ci	struct drm_gem_object *obj = buffer->priv;
4462306a36Sopenharmony_ci	struct page **pages;
4562306a36Sopenharmony_ci	if (omap_gem_flags(obj) & OMAP_BO_TILED_MASK) {
4662306a36Sopenharmony_ci		/* TODO we would need to pin at least part of the buffer to
4762306a36Sopenharmony_ci		 * get de-tiled view.  For now just reject it.
4862306a36Sopenharmony_ci		 */
4962306a36Sopenharmony_ci		return -ENOMEM;
5062306a36Sopenharmony_ci	}
5162306a36Sopenharmony_ci	/* make sure we have the pages: */
5262306a36Sopenharmony_ci	return omap_gem_get_pages(obj, &pages, true);
5362306a36Sopenharmony_ci}
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_cistatic int omap_gem_dmabuf_end_cpu_access(struct dma_buf *buffer,
5662306a36Sopenharmony_ci					  enum dma_data_direction dir)
5762306a36Sopenharmony_ci{
5862306a36Sopenharmony_ci	struct drm_gem_object *obj = buffer->priv;
5962306a36Sopenharmony_ci	omap_gem_put_pages(obj);
6062306a36Sopenharmony_ci	return 0;
6162306a36Sopenharmony_ci}
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_cistatic int omap_gem_dmabuf_mmap(struct dma_buf *buffer,
6462306a36Sopenharmony_ci		struct vm_area_struct *vma)
6562306a36Sopenharmony_ci{
6662306a36Sopenharmony_ci	struct drm_gem_object *obj = buffer->priv;
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	return drm_gem_mmap_obj(obj, omap_gem_mmap_size(obj), vma);
6962306a36Sopenharmony_ci}
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_cistatic const struct dma_buf_ops omap_dmabuf_ops = {
7262306a36Sopenharmony_ci	.map_dma_buf = omap_gem_map_dma_buf,
7362306a36Sopenharmony_ci	.unmap_dma_buf = omap_gem_unmap_dma_buf,
7462306a36Sopenharmony_ci	.release = drm_gem_dmabuf_release,
7562306a36Sopenharmony_ci	.begin_cpu_access = omap_gem_dmabuf_begin_cpu_access,
7662306a36Sopenharmony_ci	.end_cpu_access = omap_gem_dmabuf_end_cpu_access,
7762306a36Sopenharmony_ci	.mmap = omap_gem_dmabuf_mmap,
7862306a36Sopenharmony_ci};
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_cistruct dma_buf *omap_gem_prime_export(struct drm_gem_object *obj, int flags)
8162306a36Sopenharmony_ci{
8262306a36Sopenharmony_ci	DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	exp_info.ops = &omap_dmabuf_ops;
8562306a36Sopenharmony_ci	exp_info.size = omap_gem_mmap_size(obj);
8662306a36Sopenharmony_ci	exp_info.flags = flags;
8762306a36Sopenharmony_ci	exp_info.priv = obj;
8862306a36Sopenharmony_ci	exp_info.resv = obj->resv;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	return drm_gem_dmabuf_export(obj->dev, &exp_info);
9162306a36Sopenharmony_ci}
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci/* -----------------------------------------------------------------------------
9462306a36Sopenharmony_ci * DMABUF Import
9562306a36Sopenharmony_ci */
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_cistruct drm_gem_object *omap_gem_prime_import(struct drm_device *dev,
9862306a36Sopenharmony_ci					     struct dma_buf *dma_buf)
9962306a36Sopenharmony_ci{
10062306a36Sopenharmony_ci	struct dma_buf_attachment *attach;
10162306a36Sopenharmony_ci	struct drm_gem_object *obj;
10262306a36Sopenharmony_ci	struct sg_table *sgt;
10362306a36Sopenharmony_ci	int ret;
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	if (dma_buf->ops == &omap_dmabuf_ops) {
10662306a36Sopenharmony_ci		obj = dma_buf->priv;
10762306a36Sopenharmony_ci		if (obj->dev == dev) {
10862306a36Sopenharmony_ci			/*
10962306a36Sopenharmony_ci			 * Importing dmabuf exported from out own gem increases
11062306a36Sopenharmony_ci			 * refcount on gem itself instead of f_count of dmabuf.
11162306a36Sopenharmony_ci			 */
11262306a36Sopenharmony_ci			drm_gem_object_get(obj);
11362306a36Sopenharmony_ci			return obj;
11462306a36Sopenharmony_ci		}
11562306a36Sopenharmony_ci	}
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	attach = dma_buf_attach(dma_buf, dev->dev);
11862306a36Sopenharmony_ci	if (IS_ERR(attach))
11962306a36Sopenharmony_ci		return ERR_CAST(attach);
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	get_dma_buf(dma_buf);
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	sgt = dma_buf_map_attachment_unlocked(attach, DMA_TO_DEVICE);
12462306a36Sopenharmony_ci	if (IS_ERR(sgt)) {
12562306a36Sopenharmony_ci		ret = PTR_ERR(sgt);
12662306a36Sopenharmony_ci		goto fail_detach;
12762306a36Sopenharmony_ci	}
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	obj = omap_gem_new_dmabuf(dev, dma_buf->size, sgt);
13062306a36Sopenharmony_ci	if (IS_ERR(obj)) {
13162306a36Sopenharmony_ci		ret = PTR_ERR(obj);
13262306a36Sopenharmony_ci		goto fail_unmap;
13362306a36Sopenharmony_ci	}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	obj->import_attach = attach;
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	return obj;
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_cifail_unmap:
14062306a36Sopenharmony_ci	dma_buf_unmap_attachment_unlocked(attach, sgt, DMA_TO_DEVICE);
14162306a36Sopenharmony_cifail_detach:
14262306a36Sopenharmony_ci	dma_buf_detach(dma_buf, attach);
14362306a36Sopenharmony_ci	dma_buf_put(dma_buf);
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	return ERR_PTR(ret);
14662306a36Sopenharmony_ci}
147