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-mapping.h>
862306a36Sopenharmony_ci#include <linux/seq_file.h>
962306a36Sopenharmony_ci#include <linux/shmem_fs.h>
1062306a36Sopenharmony_ci#include <linux/spinlock.h>
1162306a36Sopenharmony_ci#include <linux/pfn_t.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include <drm/drm_prime.h>
1462306a36Sopenharmony_ci#include <drm/drm_vma_manager.h>
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#include "omap_drv.h"
1762306a36Sopenharmony_ci#include "omap_dmm_tiler.h"
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci/*
2062306a36Sopenharmony_ci * GEM buffer object implementation.
2162306a36Sopenharmony_ci */
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci/* note: we use upper 8 bits of flags for driver-internal flags: */
2462306a36Sopenharmony_ci#define OMAP_BO_MEM_DMA_API	0x01000000	/* memory allocated with the dma_alloc_* API */
2562306a36Sopenharmony_ci#define OMAP_BO_MEM_SHMEM	0x02000000	/* memory allocated through shmem backing */
2662306a36Sopenharmony_ci#define OMAP_BO_MEM_DMABUF	0x08000000	/* memory imported from a dmabuf */
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cistruct omap_gem_object {
2962306a36Sopenharmony_ci	struct drm_gem_object base;
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci	struct list_head mm_list;
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci	u32 flags;
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci	/** width/height for tiled formats (rounded up to slot boundaries) */
3662306a36Sopenharmony_ci	u16 width, height;
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	/** roll applied when mapping to DMM */
3962306a36Sopenharmony_ci	u32 roll;
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci	/** protects pin_cnt, block, pages, dma_addrs and vaddr */
4262306a36Sopenharmony_ci	struct mutex lock;
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	/**
4562306a36Sopenharmony_ci	 * dma_addr contains the buffer DMA address. It is valid for
4662306a36Sopenharmony_ci	 *
4762306a36Sopenharmony_ci	 * - buffers allocated through the DMA mapping API (with the
4862306a36Sopenharmony_ci	 *   OMAP_BO_MEM_DMA_API flag set)
4962306a36Sopenharmony_ci	 *
5062306a36Sopenharmony_ci	 * - buffers imported from dmabuf (with the OMAP_BO_MEM_DMABUF flag set)
5162306a36Sopenharmony_ci	 *   if they are physically contiguous (when sgt->orig_nents == 1)
5262306a36Sopenharmony_ci	 *
5362306a36Sopenharmony_ci	 * - buffers mapped through the TILER when pin_cnt is not zero, in which
5462306a36Sopenharmony_ci	 *   case the DMA address points to the TILER aperture
5562306a36Sopenharmony_ci	 *
5662306a36Sopenharmony_ci	 * Physically contiguous buffers have their DMA address equal to the
5762306a36Sopenharmony_ci	 * physical address as we don't remap those buffers through the TILER.
5862306a36Sopenharmony_ci	 *
5962306a36Sopenharmony_ci	 * Buffers mapped to the TILER have their DMA address pointing to the
6062306a36Sopenharmony_ci	 * TILER aperture. As TILER mappings are refcounted (through pin_cnt)
6162306a36Sopenharmony_ci	 * the DMA address must be accessed through omap_gem_pin() to ensure
6262306a36Sopenharmony_ci	 * that the mapping won't disappear unexpectedly. References must be
6362306a36Sopenharmony_ci	 * released with omap_gem_unpin().
6462306a36Sopenharmony_ci	 */
6562306a36Sopenharmony_ci	dma_addr_t dma_addr;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	/**
6862306a36Sopenharmony_ci	 * # of users
6962306a36Sopenharmony_ci	 */
7062306a36Sopenharmony_ci	refcount_t pin_cnt;
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	/**
7362306a36Sopenharmony_ci	 * If the buffer has been imported from a dmabuf the OMAP_DB_DMABUF flag
7462306a36Sopenharmony_ci	 * is set and the sgt field is valid.
7562306a36Sopenharmony_ci	 */
7662306a36Sopenharmony_ci	struct sg_table *sgt;
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	/**
7962306a36Sopenharmony_ci	 * tiler block used when buffer is remapped in DMM/TILER.
8062306a36Sopenharmony_ci	 */
8162306a36Sopenharmony_ci	struct tiler_block *block;
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	/**
8462306a36Sopenharmony_ci	 * Array of backing pages, if allocated.  Note that pages are never
8562306a36Sopenharmony_ci	 * allocated for buffers originally allocated from contiguous memory
8662306a36Sopenharmony_ci	 */
8762306a36Sopenharmony_ci	struct page **pages;
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	/** addresses corresponding to pages in above array */
9062306a36Sopenharmony_ci	dma_addr_t *dma_addrs;
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	/**
9362306a36Sopenharmony_ci	 * Virtual address, if mapped.
9462306a36Sopenharmony_ci	 */
9562306a36Sopenharmony_ci	void *vaddr;
9662306a36Sopenharmony_ci};
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci#define to_omap_bo(x) container_of(x, struct omap_gem_object, base)
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci/* To deal with userspace mmap'ings of 2d tiled buffers, which (a) are
10162306a36Sopenharmony_ci * not necessarily pinned in TILER all the time, and (b) when they are
10262306a36Sopenharmony_ci * they are not necessarily page aligned, we reserve one or more small
10362306a36Sopenharmony_ci * regions in each of the 2d containers to use as a user-GART where we
10462306a36Sopenharmony_ci * can create a second page-aligned mapping of parts of the buffer
10562306a36Sopenharmony_ci * being accessed from userspace.
10662306a36Sopenharmony_ci *
10762306a36Sopenharmony_ci * Note that we could optimize slightly when we know that multiple
10862306a36Sopenharmony_ci * tiler containers are backed by the same PAT.. but I'll leave that
10962306a36Sopenharmony_ci * for later..
11062306a36Sopenharmony_ci */
11162306a36Sopenharmony_ci#define NUM_USERGART_ENTRIES 2
11262306a36Sopenharmony_cistruct omap_drm_usergart_entry {
11362306a36Sopenharmony_ci	struct tiler_block *block;	/* the reserved tiler block */
11462306a36Sopenharmony_ci	dma_addr_t dma_addr;
11562306a36Sopenharmony_ci	struct drm_gem_object *obj;	/* the current pinned obj */
11662306a36Sopenharmony_ci	pgoff_t obj_pgoff;		/* page offset of obj currently
11762306a36Sopenharmony_ci					   mapped in */
11862306a36Sopenharmony_ci};
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_cistruct omap_drm_usergart {
12162306a36Sopenharmony_ci	struct omap_drm_usergart_entry entry[NUM_USERGART_ENTRIES];
12262306a36Sopenharmony_ci	int height;				/* height in rows */
12362306a36Sopenharmony_ci	int height_shift;		/* ilog2(height in rows) */
12462306a36Sopenharmony_ci	int slot_shift;			/* ilog2(width per slot) */
12562306a36Sopenharmony_ci	int stride_pfn;			/* stride in pages */
12662306a36Sopenharmony_ci	int last;				/* index of last used entry */
12762306a36Sopenharmony_ci};
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci/* -----------------------------------------------------------------------------
13062306a36Sopenharmony_ci * Helpers
13162306a36Sopenharmony_ci */
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci/** get mmap offset */
13462306a36Sopenharmony_ciu64 omap_gem_mmap_offset(struct drm_gem_object *obj)
13562306a36Sopenharmony_ci{
13662306a36Sopenharmony_ci	struct drm_device *dev = obj->dev;
13762306a36Sopenharmony_ci	int ret;
13862306a36Sopenharmony_ci	size_t size;
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	/* Make it mmapable */
14162306a36Sopenharmony_ci	size = omap_gem_mmap_size(obj);
14262306a36Sopenharmony_ci	ret = drm_gem_create_mmap_offset_size(obj, size);
14362306a36Sopenharmony_ci	if (ret) {
14462306a36Sopenharmony_ci		dev_err(dev->dev, "could not allocate mmap offset\n");
14562306a36Sopenharmony_ci		return 0;
14662306a36Sopenharmony_ci	}
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	return drm_vma_node_offset_addr(&obj->vma_node);
14962306a36Sopenharmony_ci}
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_cistatic bool omap_gem_is_contiguous(struct omap_gem_object *omap_obj)
15262306a36Sopenharmony_ci{
15362306a36Sopenharmony_ci	if (omap_obj->flags & OMAP_BO_MEM_DMA_API)
15462306a36Sopenharmony_ci		return true;
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	if ((omap_obj->flags & OMAP_BO_MEM_DMABUF) && omap_obj->sgt->nents == 1)
15762306a36Sopenharmony_ci		return true;
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	return false;
16062306a36Sopenharmony_ci}
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci/* -----------------------------------------------------------------------------
16362306a36Sopenharmony_ci * Eviction
16462306a36Sopenharmony_ci */
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_cistatic void omap_gem_evict_entry(struct drm_gem_object *obj,
16762306a36Sopenharmony_ci		enum tiler_fmt fmt, struct omap_drm_usergart_entry *entry)
16862306a36Sopenharmony_ci{
16962306a36Sopenharmony_ci	struct omap_gem_object *omap_obj = to_omap_bo(obj);
17062306a36Sopenharmony_ci	struct omap_drm_private *priv = obj->dev->dev_private;
17162306a36Sopenharmony_ci	int n = priv->usergart[fmt].height;
17262306a36Sopenharmony_ci	size_t size = PAGE_SIZE * n;
17362306a36Sopenharmony_ci	loff_t off = omap_gem_mmap_offset(obj) +
17462306a36Sopenharmony_ci			(entry->obj_pgoff << PAGE_SHIFT);
17562306a36Sopenharmony_ci	const int m = DIV_ROUND_UP(omap_obj->width << fmt, PAGE_SIZE);
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	if (m > 1) {
17862306a36Sopenharmony_ci		int i;
17962306a36Sopenharmony_ci		/* if stride > than PAGE_SIZE then sparse mapping: */
18062306a36Sopenharmony_ci		for (i = n; i > 0; i--) {
18162306a36Sopenharmony_ci			unmap_mapping_range(obj->dev->anon_inode->i_mapping,
18262306a36Sopenharmony_ci					    off, PAGE_SIZE, 1);
18362306a36Sopenharmony_ci			off += PAGE_SIZE * m;
18462306a36Sopenharmony_ci		}
18562306a36Sopenharmony_ci	} else {
18662306a36Sopenharmony_ci		unmap_mapping_range(obj->dev->anon_inode->i_mapping,
18762306a36Sopenharmony_ci				    off, size, 1);
18862306a36Sopenharmony_ci	}
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	entry->obj = NULL;
19162306a36Sopenharmony_ci}
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci/* Evict a buffer from usergart, if it is mapped there */
19462306a36Sopenharmony_cistatic void omap_gem_evict(struct drm_gem_object *obj)
19562306a36Sopenharmony_ci{
19662306a36Sopenharmony_ci	struct omap_gem_object *omap_obj = to_omap_bo(obj);
19762306a36Sopenharmony_ci	struct omap_drm_private *priv = obj->dev->dev_private;
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	if (omap_obj->flags & OMAP_BO_TILED_MASK) {
20062306a36Sopenharmony_ci		enum tiler_fmt fmt = gem2fmt(omap_obj->flags);
20162306a36Sopenharmony_ci		int i;
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci		for (i = 0; i < NUM_USERGART_ENTRIES; i++) {
20462306a36Sopenharmony_ci			struct omap_drm_usergart_entry *entry =
20562306a36Sopenharmony_ci				&priv->usergart[fmt].entry[i];
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci			if (entry->obj == obj)
20862306a36Sopenharmony_ci				omap_gem_evict_entry(obj, fmt, entry);
20962306a36Sopenharmony_ci		}
21062306a36Sopenharmony_ci	}
21162306a36Sopenharmony_ci}
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci/* -----------------------------------------------------------------------------
21462306a36Sopenharmony_ci * Page Management
21562306a36Sopenharmony_ci */
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci/*
21862306a36Sopenharmony_ci * Ensure backing pages are allocated. Must be called with the omap_obj.lock
21962306a36Sopenharmony_ci * held.
22062306a36Sopenharmony_ci */
22162306a36Sopenharmony_cistatic int omap_gem_attach_pages(struct drm_gem_object *obj)
22262306a36Sopenharmony_ci{
22362306a36Sopenharmony_ci	struct drm_device *dev = obj->dev;
22462306a36Sopenharmony_ci	struct omap_gem_object *omap_obj = to_omap_bo(obj);
22562306a36Sopenharmony_ci	struct page **pages;
22662306a36Sopenharmony_ci	int npages = obj->size >> PAGE_SHIFT;
22762306a36Sopenharmony_ci	int i, ret;
22862306a36Sopenharmony_ci	dma_addr_t *addrs;
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	lockdep_assert_held(&omap_obj->lock);
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	/*
23362306a36Sopenharmony_ci	 * If not using shmem (in which case backing pages don't need to be
23462306a36Sopenharmony_ci	 * allocated) or if pages are already allocated we're done.
23562306a36Sopenharmony_ci	 */
23662306a36Sopenharmony_ci	if (!(omap_obj->flags & OMAP_BO_MEM_SHMEM) || omap_obj->pages)
23762306a36Sopenharmony_ci		return 0;
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	pages = drm_gem_get_pages(obj);
24062306a36Sopenharmony_ci	if (IS_ERR(pages)) {
24162306a36Sopenharmony_ci		dev_err(obj->dev->dev, "could not get pages: %ld\n", PTR_ERR(pages));
24262306a36Sopenharmony_ci		return PTR_ERR(pages);
24362306a36Sopenharmony_ci	}
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	/* for non-cached buffers, ensure the new pages are clean because
24662306a36Sopenharmony_ci	 * DSS, GPU, etc. are not cache coherent:
24762306a36Sopenharmony_ci	 */
24862306a36Sopenharmony_ci	if (omap_obj->flags & (OMAP_BO_WC|OMAP_BO_UNCACHED)) {
24962306a36Sopenharmony_ci		addrs = kmalloc_array(npages, sizeof(*addrs), GFP_KERNEL);
25062306a36Sopenharmony_ci		if (!addrs) {
25162306a36Sopenharmony_ci			ret = -ENOMEM;
25262306a36Sopenharmony_ci			goto free_pages;
25362306a36Sopenharmony_ci		}
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci		for (i = 0; i < npages; i++) {
25662306a36Sopenharmony_ci			addrs[i] = dma_map_page(dev->dev, pages[i],
25762306a36Sopenharmony_ci					0, PAGE_SIZE, DMA_TO_DEVICE);
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci			if (dma_mapping_error(dev->dev, addrs[i])) {
26062306a36Sopenharmony_ci				dev_warn(dev->dev,
26162306a36Sopenharmony_ci					"%s: failed to map page\n", __func__);
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci				for (i = i - 1; i >= 0; --i) {
26462306a36Sopenharmony_ci					dma_unmap_page(dev->dev, addrs[i],
26562306a36Sopenharmony_ci						PAGE_SIZE, DMA_TO_DEVICE);
26662306a36Sopenharmony_ci				}
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci				ret = -ENOMEM;
26962306a36Sopenharmony_ci				goto free_addrs;
27062306a36Sopenharmony_ci			}
27162306a36Sopenharmony_ci		}
27262306a36Sopenharmony_ci	} else {
27362306a36Sopenharmony_ci		addrs = kcalloc(npages, sizeof(*addrs), GFP_KERNEL);
27462306a36Sopenharmony_ci		if (!addrs) {
27562306a36Sopenharmony_ci			ret = -ENOMEM;
27662306a36Sopenharmony_ci			goto free_pages;
27762306a36Sopenharmony_ci		}
27862306a36Sopenharmony_ci	}
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	omap_obj->dma_addrs = addrs;
28162306a36Sopenharmony_ci	omap_obj->pages = pages;
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	return 0;
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_cifree_addrs:
28662306a36Sopenharmony_ci	kfree(addrs);
28762306a36Sopenharmony_cifree_pages:
28862306a36Sopenharmony_ci	drm_gem_put_pages(obj, pages, true, false);
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	return ret;
29162306a36Sopenharmony_ci}
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci/* Release backing pages. Must be called with the omap_obj.lock held. */
29462306a36Sopenharmony_cistatic void omap_gem_detach_pages(struct drm_gem_object *obj)
29562306a36Sopenharmony_ci{
29662306a36Sopenharmony_ci	struct omap_gem_object *omap_obj = to_omap_bo(obj);
29762306a36Sopenharmony_ci	unsigned int npages = obj->size >> PAGE_SHIFT;
29862306a36Sopenharmony_ci	unsigned int i;
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	lockdep_assert_held(&omap_obj->lock);
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	for (i = 0; i < npages; i++) {
30362306a36Sopenharmony_ci		if (omap_obj->dma_addrs[i])
30462306a36Sopenharmony_ci			dma_unmap_page(obj->dev->dev, omap_obj->dma_addrs[i],
30562306a36Sopenharmony_ci				       PAGE_SIZE, DMA_TO_DEVICE);
30662306a36Sopenharmony_ci	}
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	kfree(omap_obj->dma_addrs);
30962306a36Sopenharmony_ci	omap_obj->dma_addrs = NULL;
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	drm_gem_put_pages(obj, omap_obj->pages, true, false);
31262306a36Sopenharmony_ci	omap_obj->pages = NULL;
31362306a36Sopenharmony_ci}
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci/* get buffer flags */
31662306a36Sopenharmony_ciu32 omap_gem_flags(struct drm_gem_object *obj)
31762306a36Sopenharmony_ci{
31862306a36Sopenharmony_ci	return to_omap_bo(obj)->flags;
31962306a36Sopenharmony_ci}
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci/** get mmap size */
32262306a36Sopenharmony_cisize_t omap_gem_mmap_size(struct drm_gem_object *obj)
32362306a36Sopenharmony_ci{
32462306a36Sopenharmony_ci	struct omap_gem_object *omap_obj = to_omap_bo(obj);
32562306a36Sopenharmony_ci	size_t size = obj->size;
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	if (omap_obj->flags & OMAP_BO_TILED_MASK) {
32862306a36Sopenharmony_ci		/* for tiled buffers, the virtual size has stride rounded up
32962306a36Sopenharmony_ci		 * to 4kb.. (to hide the fact that row n+1 might start 16kb or
33062306a36Sopenharmony_ci		 * 32kb later!).  But we don't back the entire buffer with
33162306a36Sopenharmony_ci		 * pages, only the valid picture part.. so need to adjust for
33262306a36Sopenharmony_ci		 * this in the size used to mmap and generate mmap offset
33362306a36Sopenharmony_ci		 */
33462306a36Sopenharmony_ci		size = tiler_vsize(gem2fmt(omap_obj->flags),
33562306a36Sopenharmony_ci				omap_obj->width, omap_obj->height);
33662306a36Sopenharmony_ci	}
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	return size;
33962306a36Sopenharmony_ci}
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci/* -----------------------------------------------------------------------------
34262306a36Sopenharmony_ci * Fault Handling
34362306a36Sopenharmony_ci */
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci/* Normal handling for the case of faulting in non-tiled buffers */
34662306a36Sopenharmony_cistatic vm_fault_t omap_gem_fault_1d(struct drm_gem_object *obj,
34762306a36Sopenharmony_ci		struct vm_area_struct *vma, struct vm_fault *vmf)
34862306a36Sopenharmony_ci{
34962306a36Sopenharmony_ci	struct omap_gem_object *omap_obj = to_omap_bo(obj);
35062306a36Sopenharmony_ci	unsigned long pfn;
35162306a36Sopenharmony_ci	pgoff_t pgoff;
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	/* We don't use vmf->pgoff since that has the fake offset: */
35462306a36Sopenharmony_ci	pgoff = (vmf->address - vma->vm_start) >> PAGE_SHIFT;
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	if (omap_obj->pages) {
35762306a36Sopenharmony_ci		omap_gem_cpu_sync_page(obj, pgoff);
35862306a36Sopenharmony_ci		pfn = page_to_pfn(omap_obj->pages[pgoff]);
35962306a36Sopenharmony_ci	} else {
36062306a36Sopenharmony_ci		BUG_ON(!omap_gem_is_contiguous(omap_obj));
36162306a36Sopenharmony_ci		pfn = (omap_obj->dma_addr >> PAGE_SHIFT) + pgoff;
36262306a36Sopenharmony_ci	}
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	VERB("Inserting %p pfn %lx, pa %lx", (void *)vmf->address,
36562306a36Sopenharmony_ci			pfn, pfn << PAGE_SHIFT);
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	return vmf_insert_mixed(vma, vmf->address,
36862306a36Sopenharmony_ci			__pfn_to_pfn_t(pfn, PFN_DEV));
36962306a36Sopenharmony_ci}
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci/* Special handling for the case of faulting in 2d tiled buffers */
37262306a36Sopenharmony_cistatic vm_fault_t omap_gem_fault_2d(struct drm_gem_object *obj,
37362306a36Sopenharmony_ci		struct vm_area_struct *vma, struct vm_fault *vmf)
37462306a36Sopenharmony_ci{
37562306a36Sopenharmony_ci	struct omap_gem_object *omap_obj = to_omap_bo(obj);
37662306a36Sopenharmony_ci	struct omap_drm_private *priv = obj->dev->dev_private;
37762306a36Sopenharmony_ci	struct omap_drm_usergart_entry *entry;
37862306a36Sopenharmony_ci	enum tiler_fmt fmt = gem2fmt(omap_obj->flags);
37962306a36Sopenharmony_ci	struct page *pages[64];  /* XXX is this too much to have on stack? */
38062306a36Sopenharmony_ci	unsigned long pfn;
38162306a36Sopenharmony_ci	pgoff_t pgoff, base_pgoff;
38262306a36Sopenharmony_ci	unsigned long vaddr;
38362306a36Sopenharmony_ci	int i, err, slots;
38462306a36Sopenharmony_ci	vm_fault_t ret = VM_FAULT_NOPAGE;
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	/*
38762306a36Sopenharmony_ci	 * Note the height of the slot is also equal to the number of pages
38862306a36Sopenharmony_ci	 * that need to be mapped in to fill 4kb wide CPU page.  If the slot
38962306a36Sopenharmony_ci	 * height is 64, then 64 pages fill a 4kb wide by 64 row region.
39062306a36Sopenharmony_ci	 */
39162306a36Sopenharmony_ci	const int n = priv->usergart[fmt].height;
39262306a36Sopenharmony_ci	const int n_shift = priv->usergart[fmt].height_shift;
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	/*
39562306a36Sopenharmony_ci	 * If buffer width in bytes > PAGE_SIZE then the virtual stride is
39662306a36Sopenharmony_ci	 * rounded up to next multiple of PAGE_SIZE.. this need to be taken
39762306a36Sopenharmony_ci	 * into account in some of the math, so figure out virtual stride
39862306a36Sopenharmony_ci	 * in pages
39962306a36Sopenharmony_ci	 */
40062306a36Sopenharmony_ci	const int m = DIV_ROUND_UP(omap_obj->width << fmt, PAGE_SIZE);
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	/* We don't use vmf->pgoff since that has the fake offset: */
40362306a36Sopenharmony_ci	pgoff = (vmf->address - vma->vm_start) >> PAGE_SHIFT;
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	/*
40662306a36Sopenharmony_ci	 * Actual address we start mapping at is rounded down to previous slot
40762306a36Sopenharmony_ci	 * boundary in the y direction:
40862306a36Sopenharmony_ci	 */
40962306a36Sopenharmony_ci	base_pgoff = round_down(pgoff, m << n_shift);
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	/* figure out buffer width in slots */
41262306a36Sopenharmony_ci	slots = omap_obj->width >> priv->usergart[fmt].slot_shift;
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	vaddr = vmf->address - ((pgoff - base_pgoff) << PAGE_SHIFT);
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	entry = &priv->usergart[fmt].entry[priv->usergart[fmt].last];
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	/* evict previous buffer using this usergart entry, if any: */
41962306a36Sopenharmony_ci	if (entry->obj)
42062306a36Sopenharmony_ci		omap_gem_evict_entry(entry->obj, fmt, entry);
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	entry->obj = obj;
42362306a36Sopenharmony_ci	entry->obj_pgoff = base_pgoff;
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	/* now convert base_pgoff to phys offset from virt offset: */
42662306a36Sopenharmony_ci	base_pgoff = (base_pgoff >> n_shift) * slots;
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	/* for wider-than 4k.. figure out which part of the slot-row we want: */
42962306a36Sopenharmony_ci	if (m > 1) {
43062306a36Sopenharmony_ci		int off = pgoff % m;
43162306a36Sopenharmony_ci		entry->obj_pgoff += off;
43262306a36Sopenharmony_ci		base_pgoff /= m;
43362306a36Sopenharmony_ci		slots = min(slots - (off << n_shift), n);
43462306a36Sopenharmony_ci		base_pgoff += off << n_shift;
43562306a36Sopenharmony_ci		vaddr += off << PAGE_SHIFT;
43662306a36Sopenharmony_ci	}
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	/*
43962306a36Sopenharmony_ci	 * Map in pages. Beyond the valid pixel part of the buffer, we set
44062306a36Sopenharmony_ci	 * pages[i] to NULL to get a dummy page mapped in.. if someone
44162306a36Sopenharmony_ci	 * reads/writes it they will get random/undefined content, but at
44262306a36Sopenharmony_ci	 * least it won't be corrupting whatever other random page used to
44362306a36Sopenharmony_ci	 * be mapped in, or other undefined behavior.
44462306a36Sopenharmony_ci	 */
44562306a36Sopenharmony_ci	memcpy(pages, &omap_obj->pages[base_pgoff],
44662306a36Sopenharmony_ci			sizeof(struct page *) * slots);
44762306a36Sopenharmony_ci	memset(pages + slots, 0,
44862306a36Sopenharmony_ci			sizeof(struct page *) * (n - slots));
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	err = tiler_pin(entry->block, pages, ARRAY_SIZE(pages), 0, true);
45162306a36Sopenharmony_ci	if (err) {
45262306a36Sopenharmony_ci		ret = vmf_error(err);
45362306a36Sopenharmony_ci		dev_err(obj->dev->dev, "failed to pin: %d\n", err);
45462306a36Sopenharmony_ci		return ret;
45562306a36Sopenharmony_ci	}
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	pfn = entry->dma_addr >> PAGE_SHIFT;
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci	VERB("Inserting %p pfn %lx, pa %lx", (void *)vmf->address,
46062306a36Sopenharmony_ci			pfn, pfn << PAGE_SHIFT);
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	for (i = n; i > 0; i--) {
46362306a36Sopenharmony_ci		ret = vmf_insert_mixed(vma,
46462306a36Sopenharmony_ci			vaddr, __pfn_to_pfn_t(pfn, PFN_DEV));
46562306a36Sopenharmony_ci		if (ret & VM_FAULT_ERROR)
46662306a36Sopenharmony_ci			break;
46762306a36Sopenharmony_ci		pfn += priv->usergart[fmt].stride_pfn;
46862306a36Sopenharmony_ci		vaddr += PAGE_SIZE * m;
46962306a36Sopenharmony_ci	}
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	/* simple round-robin: */
47262306a36Sopenharmony_ci	priv->usergart[fmt].last = (priv->usergart[fmt].last + 1)
47362306a36Sopenharmony_ci				 % NUM_USERGART_ENTRIES;
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	return ret;
47662306a36Sopenharmony_ci}
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci/**
47962306a36Sopenharmony_ci * omap_gem_fault		-	pagefault handler for GEM objects
48062306a36Sopenharmony_ci * @vmf: fault detail
48162306a36Sopenharmony_ci *
48262306a36Sopenharmony_ci * Invoked when a fault occurs on an mmap of a GEM managed area. GEM
48362306a36Sopenharmony_ci * does most of the work for us including the actual map/unmap calls
48462306a36Sopenharmony_ci * but we need to do the actual page work.
48562306a36Sopenharmony_ci *
48662306a36Sopenharmony_ci * The VMA was set up by GEM. In doing so it also ensured that the
48762306a36Sopenharmony_ci * vma->vm_private_data points to the GEM object that is backing this
48862306a36Sopenharmony_ci * mapping.
48962306a36Sopenharmony_ci */
49062306a36Sopenharmony_cistatic vm_fault_t omap_gem_fault(struct vm_fault *vmf)
49162306a36Sopenharmony_ci{
49262306a36Sopenharmony_ci	struct vm_area_struct *vma = vmf->vma;
49362306a36Sopenharmony_ci	struct drm_gem_object *obj = vma->vm_private_data;
49462306a36Sopenharmony_ci	struct omap_gem_object *omap_obj = to_omap_bo(obj);
49562306a36Sopenharmony_ci	int err;
49662306a36Sopenharmony_ci	vm_fault_t ret;
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	/* Make sure we don't parallel update on a fault, nor move or remove
49962306a36Sopenharmony_ci	 * something from beneath our feet
50062306a36Sopenharmony_ci	 */
50162306a36Sopenharmony_ci	mutex_lock(&omap_obj->lock);
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci	/* if a shmem backed object, make sure we have pages attached now */
50462306a36Sopenharmony_ci	err = omap_gem_attach_pages(obj);
50562306a36Sopenharmony_ci	if (err) {
50662306a36Sopenharmony_ci		ret = vmf_error(err);
50762306a36Sopenharmony_ci		goto fail;
50862306a36Sopenharmony_ci	}
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci	/* where should we do corresponding put_pages().. we are mapping
51162306a36Sopenharmony_ci	 * the original page, rather than thru a GART, so we can't rely
51262306a36Sopenharmony_ci	 * on eviction to trigger this.  But munmap() or all mappings should
51362306a36Sopenharmony_ci	 * probably trigger put_pages()?
51462306a36Sopenharmony_ci	 */
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	if (omap_obj->flags & OMAP_BO_TILED_MASK)
51762306a36Sopenharmony_ci		ret = omap_gem_fault_2d(obj, vma, vmf);
51862306a36Sopenharmony_ci	else
51962306a36Sopenharmony_ci		ret = omap_gem_fault_1d(obj, vma, vmf);
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_cifail:
52362306a36Sopenharmony_ci	mutex_unlock(&omap_obj->lock);
52462306a36Sopenharmony_ci	return ret;
52562306a36Sopenharmony_ci}
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_cistatic int omap_gem_object_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma)
52862306a36Sopenharmony_ci{
52962306a36Sopenharmony_ci	struct omap_gem_object *omap_obj = to_omap_bo(obj);
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci	vm_flags_set(vma, VM_DONTEXPAND | VM_DONTDUMP | VM_IO | VM_MIXEDMAP);
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	if (omap_obj->flags & OMAP_BO_WC) {
53462306a36Sopenharmony_ci		vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
53562306a36Sopenharmony_ci	} else if (omap_obj->flags & OMAP_BO_UNCACHED) {
53662306a36Sopenharmony_ci		vma->vm_page_prot = pgprot_noncached(vm_get_page_prot(vma->vm_flags));
53762306a36Sopenharmony_ci	} else {
53862306a36Sopenharmony_ci		/*
53962306a36Sopenharmony_ci		 * We do have some private objects, at least for scanout buffers
54062306a36Sopenharmony_ci		 * on hardware without DMM/TILER.  But these are allocated write-
54162306a36Sopenharmony_ci		 * combine
54262306a36Sopenharmony_ci		 */
54362306a36Sopenharmony_ci		if (WARN_ON(!obj->filp))
54462306a36Sopenharmony_ci			return -EINVAL;
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci		/*
54762306a36Sopenharmony_ci		 * Shunt off cached objs to shmem file so they have their own
54862306a36Sopenharmony_ci		 * address_space (so unmap_mapping_range does what we want,
54962306a36Sopenharmony_ci		 * in particular in the case of mmap'd dmabufs)
55062306a36Sopenharmony_ci		 */
55162306a36Sopenharmony_ci		vma->vm_pgoff -= drm_vma_node_start(&obj->vma_node);
55262306a36Sopenharmony_ci		vma_set_file(vma, obj->filp);
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci		vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
55562306a36Sopenharmony_ci	}
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci	vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot);
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	return 0;
56062306a36Sopenharmony_ci}
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci/* -----------------------------------------------------------------------------
56362306a36Sopenharmony_ci * Dumb Buffers
56462306a36Sopenharmony_ci */
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci/**
56762306a36Sopenharmony_ci * omap_gem_dumb_create	-	create a dumb buffer
56862306a36Sopenharmony_ci * @file: our client file
56962306a36Sopenharmony_ci * @dev: our device
57062306a36Sopenharmony_ci * @args: the requested arguments copied from userspace
57162306a36Sopenharmony_ci *
57262306a36Sopenharmony_ci * Allocate a buffer suitable for use for a frame buffer of the
57362306a36Sopenharmony_ci * form described by user space. Give userspace a handle by which
57462306a36Sopenharmony_ci * to reference it.
57562306a36Sopenharmony_ci */
57662306a36Sopenharmony_ciint omap_gem_dumb_create(struct drm_file *file, struct drm_device *dev,
57762306a36Sopenharmony_ci		struct drm_mode_create_dumb *args)
57862306a36Sopenharmony_ci{
57962306a36Sopenharmony_ci	union omap_gem_size gsize;
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci	args->pitch = DIV_ROUND_UP(args->width * args->bpp, 8);
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	args->size = PAGE_ALIGN(args->pitch * args->height);
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci	gsize = (union omap_gem_size){
58662306a36Sopenharmony_ci		.bytes = args->size,
58762306a36Sopenharmony_ci	};
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci	return omap_gem_new_handle(dev, file, gsize,
59062306a36Sopenharmony_ci			OMAP_BO_SCANOUT | OMAP_BO_WC, &args->handle);
59162306a36Sopenharmony_ci}
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci/**
59462306a36Sopenharmony_ci * omap_gem_dumb_map_offset - create an offset for a dumb buffer
59562306a36Sopenharmony_ci * @file: our drm client file
59662306a36Sopenharmony_ci * @dev: drm device
59762306a36Sopenharmony_ci * @handle: GEM handle to the object (from dumb_create)
59862306a36Sopenharmony_ci * @offset: memory map offset placeholder
59962306a36Sopenharmony_ci *
60062306a36Sopenharmony_ci * Do the necessary setup to allow the mapping of the frame buffer
60162306a36Sopenharmony_ci * into user memory. We don't have to do much here at the moment.
60262306a36Sopenharmony_ci */
60362306a36Sopenharmony_ciint omap_gem_dumb_map_offset(struct drm_file *file, struct drm_device *dev,
60462306a36Sopenharmony_ci		u32 handle, u64 *offset)
60562306a36Sopenharmony_ci{
60662306a36Sopenharmony_ci	struct drm_gem_object *obj;
60762306a36Sopenharmony_ci	int ret = 0;
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	/* GEM does all our handle to object mapping */
61062306a36Sopenharmony_ci	obj = drm_gem_object_lookup(file, handle);
61162306a36Sopenharmony_ci	if (obj == NULL) {
61262306a36Sopenharmony_ci		ret = -ENOENT;
61362306a36Sopenharmony_ci		goto fail;
61462306a36Sopenharmony_ci	}
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	*offset = omap_gem_mmap_offset(obj);
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci	drm_gem_object_put(obj);
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_cifail:
62162306a36Sopenharmony_ci	return ret;
62262306a36Sopenharmony_ci}
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci#ifdef CONFIG_DRM_FBDEV_EMULATION
62562306a36Sopenharmony_ci/* Set scrolling position.  This allows us to implement fast scrolling
62662306a36Sopenharmony_ci * for console.
62762306a36Sopenharmony_ci *
62862306a36Sopenharmony_ci * Call only from non-atomic contexts.
62962306a36Sopenharmony_ci */
63062306a36Sopenharmony_ciint omap_gem_roll(struct drm_gem_object *obj, u32 roll)
63162306a36Sopenharmony_ci{
63262306a36Sopenharmony_ci	struct omap_gem_object *omap_obj = to_omap_bo(obj);
63362306a36Sopenharmony_ci	u32 npages = obj->size >> PAGE_SHIFT;
63462306a36Sopenharmony_ci	int ret = 0;
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ci	if (roll > npages) {
63762306a36Sopenharmony_ci		dev_err(obj->dev->dev, "invalid roll: %d\n", roll);
63862306a36Sopenharmony_ci		return -EINVAL;
63962306a36Sopenharmony_ci	}
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci	omap_obj->roll = roll;
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci	mutex_lock(&omap_obj->lock);
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci	/* if we aren't mapped yet, we don't need to do anything */
64662306a36Sopenharmony_ci	if (omap_obj->block) {
64762306a36Sopenharmony_ci		ret = omap_gem_attach_pages(obj);
64862306a36Sopenharmony_ci		if (ret)
64962306a36Sopenharmony_ci			goto fail;
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci		ret = tiler_pin(omap_obj->block, omap_obj->pages, npages,
65262306a36Sopenharmony_ci				roll, true);
65362306a36Sopenharmony_ci		if (ret)
65462306a36Sopenharmony_ci			dev_err(obj->dev->dev, "could not repin: %d\n", ret);
65562306a36Sopenharmony_ci	}
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_cifail:
65862306a36Sopenharmony_ci	mutex_unlock(&omap_obj->lock);
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci	return ret;
66162306a36Sopenharmony_ci}
66262306a36Sopenharmony_ci#endif
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci/* -----------------------------------------------------------------------------
66562306a36Sopenharmony_ci * Memory Management & DMA Sync
66662306a36Sopenharmony_ci */
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci/*
66962306a36Sopenharmony_ci * shmem buffers that are mapped cached are not coherent.
67062306a36Sopenharmony_ci *
67162306a36Sopenharmony_ci * We keep track of dirty pages using page faulting to perform cache management.
67262306a36Sopenharmony_ci * When a page is mapped to the CPU in read/write mode the device can't access
67362306a36Sopenharmony_ci * it and omap_obj->dma_addrs[i] is NULL. When a page is mapped to the device
67462306a36Sopenharmony_ci * the omap_obj->dma_addrs[i] is set to the DMA address, and the page is
67562306a36Sopenharmony_ci * unmapped from the CPU.
67662306a36Sopenharmony_ci */
67762306a36Sopenharmony_cistatic inline bool omap_gem_is_cached_coherent(struct drm_gem_object *obj)
67862306a36Sopenharmony_ci{
67962306a36Sopenharmony_ci	struct omap_gem_object *omap_obj = to_omap_bo(obj);
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci	return !((omap_obj->flags & OMAP_BO_MEM_SHMEM) &&
68262306a36Sopenharmony_ci		((omap_obj->flags & OMAP_BO_CACHE_MASK) == OMAP_BO_CACHED));
68362306a36Sopenharmony_ci}
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci/* Sync the buffer for CPU access.. note pages should already be
68662306a36Sopenharmony_ci * attached, ie. omap_gem_get_pages()
68762306a36Sopenharmony_ci */
68862306a36Sopenharmony_civoid omap_gem_cpu_sync_page(struct drm_gem_object *obj, int pgoff)
68962306a36Sopenharmony_ci{
69062306a36Sopenharmony_ci	struct drm_device *dev = obj->dev;
69162306a36Sopenharmony_ci	struct omap_gem_object *omap_obj = to_omap_bo(obj);
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ci	if (omap_gem_is_cached_coherent(obj))
69462306a36Sopenharmony_ci		return;
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci	if (omap_obj->dma_addrs[pgoff]) {
69762306a36Sopenharmony_ci		dma_unmap_page(dev->dev, omap_obj->dma_addrs[pgoff],
69862306a36Sopenharmony_ci				PAGE_SIZE, DMA_TO_DEVICE);
69962306a36Sopenharmony_ci		omap_obj->dma_addrs[pgoff] = 0;
70062306a36Sopenharmony_ci	}
70162306a36Sopenharmony_ci}
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci/* sync the buffer for DMA access */
70462306a36Sopenharmony_civoid omap_gem_dma_sync_buffer(struct drm_gem_object *obj,
70562306a36Sopenharmony_ci		enum dma_data_direction dir)
70662306a36Sopenharmony_ci{
70762306a36Sopenharmony_ci	struct drm_device *dev = obj->dev;
70862306a36Sopenharmony_ci	struct omap_gem_object *omap_obj = to_omap_bo(obj);
70962306a36Sopenharmony_ci	int i, npages = obj->size >> PAGE_SHIFT;
71062306a36Sopenharmony_ci	struct page **pages = omap_obj->pages;
71162306a36Sopenharmony_ci	bool dirty = false;
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci	if (omap_gem_is_cached_coherent(obj))
71462306a36Sopenharmony_ci		return;
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_ci	for (i = 0; i < npages; i++) {
71762306a36Sopenharmony_ci		if (!omap_obj->dma_addrs[i]) {
71862306a36Sopenharmony_ci			dma_addr_t addr;
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci			addr = dma_map_page(dev->dev, pages[i], 0,
72162306a36Sopenharmony_ci					    PAGE_SIZE, dir);
72262306a36Sopenharmony_ci			if (dma_mapping_error(dev->dev, addr)) {
72362306a36Sopenharmony_ci				dev_warn(dev->dev, "%s: failed to map page\n",
72462306a36Sopenharmony_ci					__func__);
72562306a36Sopenharmony_ci				break;
72662306a36Sopenharmony_ci			}
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci			dirty = true;
72962306a36Sopenharmony_ci			omap_obj->dma_addrs[i] = addr;
73062306a36Sopenharmony_ci		}
73162306a36Sopenharmony_ci	}
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci	if (dirty) {
73462306a36Sopenharmony_ci		unmap_mapping_range(obj->filp->f_mapping, 0,
73562306a36Sopenharmony_ci				    omap_gem_mmap_size(obj), 1);
73662306a36Sopenharmony_ci	}
73762306a36Sopenharmony_ci}
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_cistatic int omap_gem_pin_tiler(struct drm_gem_object *obj)
74062306a36Sopenharmony_ci{
74162306a36Sopenharmony_ci	struct omap_gem_object *omap_obj = to_omap_bo(obj);
74262306a36Sopenharmony_ci	u32 npages = obj->size >> PAGE_SHIFT;
74362306a36Sopenharmony_ci	enum tiler_fmt fmt = gem2fmt(omap_obj->flags);
74462306a36Sopenharmony_ci	struct tiler_block *block;
74562306a36Sopenharmony_ci	int ret;
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci	BUG_ON(omap_obj->block);
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_ci	if (omap_obj->flags & OMAP_BO_TILED_MASK) {
75062306a36Sopenharmony_ci		block = tiler_reserve_2d(fmt, omap_obj->width, omap_obj->height,
75162306a36Sopenharmony_ci					 PAGE_SIZE);
75262306a36Sopenharmony_ci	} else {
75362306a36Sopenharmony_ci		block = tiler_reserve_1d(obj->size);
75462306a36Sopenharmony_ci	}
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci	if (IS_ERR(block)) {
75762306a36Sopenharmony_ci		ret = PTR_ERR(block);
75862306a36Sopenharmony_ci		dev_err(obj->dev->dev, "could not remap: %d (%d)\n", ret, fmt);
75962306a36Sopenharmony_ci		goto fail;
76062306a36Sopenharmony_ci	}
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_ci	/* TODO: enable async refill.. */
76362306a36Sopenharmony_ci	ret = tiler_pin(block, omap_obj->pages, npages, omap_obj->roll, true);
76462306a36Sopenharmony_ci	if (ret) {
76562306a36Sopenharmony_ci		tiler_release(block);
76662306a36Sopenharmony_ci		dev_err(obj->dev->dev, "could not pin: %d\n", ret);
76762306a36Sopenharmony_ci		goto fail;
76862306a36Sopenharmony_ci	}
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci	omap_obj->dma_addr = tiler_ssptr(block);
77162306a36Sopenharmony_ci	omap_obj->block = block;
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci	DBG("got dma address: %pad", &omap_obj->dma_addr);
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_cifail:
77662306a36Sopenharmony_ci	return ret;
77762306a36Sopenharmony_ci}
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci/**
78062306a36Sopenharmony_ci * omap_gem_pin() - Pin a GEM object in memory
78162306a36Sopenharmony_ci * @obj: the GEM object
78262306a36Sopenharmony_ci * @dma_addr: the DMA address
78362306a36Sopenharmony_ci *
78462306a36Sopenharmony_ci * Pin the given GEM object in memory and fill the dma_addr pointer with the
78562306a36Sopenharmony_ci * object's DMA address. If the buffer is not physically contiguous it will be
78662306a36Sopenharmony_ci * remapped through the TILER to provide a contiguous view.
78762306a36Sopenharmony_ci *
78862306a36Sopenharmony_ci * Pins are reference-counted, calling this function multiple times is allowed
78962306a36Sopenharmony_ci * as long the corresponding omap_gem_unpin() calls are balanced.
79062306a36Sopenharmony_ci *
79162306a36Sopenharmony_ci * Return 0 on success or a negative error code otherwise.
79262306a36Sopenharmony_ci */
79362306a36Sopenharmony_ciint omap_gem_pin(struct drm_gem_object *obj, dma_addr_t *dma_addr)
79462306a36Sopenharmony_ci{
79562306a36Sopenharmony_ci	struct omap_drm_private *priv = obj->dev->dev_private;
79662306a36Sopenharmony_ci	struct omap_gem_object *omap_obj = to_omap_bo(obj);
79762306a36Sopenharmony_ci	int ret = 0;
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci	mutex_lock(&omap_obj->lock);
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_ci	if (!omap_gem_is_contiguous(omap_obj)) {
80262306a36Sopenharmony_ci		if (refcount_read(&omap_obj->pin_cnt) == 0) {
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_ci			refcount_set(&omap_obj->pin_cnt, 1);
80562306a36Sopenharmony_ci
80662306a36Sopenharmony_ci			ret = omap_gem_attach_pages(obj);
80762306a36Sopenharmony_ci			if (ret)
80862306a36Sopenharmony_ci				goto fail;
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci			if (omap_obj->flags & OMAP_BO_SCANOUT) {
81162306a36Sopenharmony_ci				if (priv->has_dmm) {
81262306a36Sopenharmony_ci					ret = omap_gem_pin_tiler(obj);
81362306a36Sopenharmony_ci					if (ret)
81462306a36Sopenharmony_ci						goto fail;
81562306a36Sopenharmony_ci				}
81662306a36Sopenharmony_ci			}
81762306a36Sopenharmony_ci		} else {
81862306a36Sopenharmony_ci			refcount_inc(&omap_obj->pin_cnt);
81962306a36Sopenharmony_ci		}
82062306a36Sopenharmony_ci	}
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_ci	if (dma_addr)
82362306a36Sopenharmony_ci		*dma_addr = omap_obj->dma_addr;
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_cifail:
82662306a36Sopenharmony_ci	mutex_unlock(&omap_obj->lock);
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_ci	return ret;
82962306a36Sopenharmony_ci}
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci/**
83262306a36Sopenharmony_ci * omap_gem_unpin_locked() - Unpin a GEM object from memory
83362306a36Sopenharmony_ci * @obj: the GEM object
83462306a36Sopenharmony_ci *
83562306a36Sopenharmony_ci * omap_gem_unpin() without locking.
83662306a36Sopenharmony_ci */
83762306a36Sopenharmony_cistatic void omap_gem_unpin_locked(struct drm_gem_object *obj)
83862306a36Sopenharmony_ci{
83962306a36Sopenharmony_ci	struct omap_drm_private *priv = obj->dev->dev_private;
84062306a36Sopenharmony_ci	struct omap_gem_object *omap_obj = to_omap_bo(obj);
84162306a36Sopenharmony_ci	int ret;
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci	if (omap_gem_is_contiguous(omap_obj))
84462306a36Sopenharmony_ci		return;
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_ci	if (refcount_dec_and_test(&omap_obj->pin_cnt)) {
84762306a36Sopenharmony_ci		if (omap_obj->sgt) {
84862306a36Sopenharmony_ci			sg_free_table(omap_obj->sgt);
84962306a36Sopenharmony_ci			kfree(omap_obj->sgt);
85062306a36Sopenharmony_ci			omap_obj->sgt = NULL;
85162306a36Sopenharmony_ci		}
85262306a36Sopenharmony_ci		if (!(omap_obj->flags & OMAP_BO_SCANOUT))
85362306a36Sopenharmony_ci			return;
85462306a36Sopenharmony_ci		if (priv->has_dmm) {
85562306a36Sopenharmony_ci			ret = tiler_unpin(omap_obj->block);
85662306a36Sopenharmony_ci			if (ret) {
85762306a36Sopenharmony_ci				dev_err(obj->dev->dev,
85862306a36Sopenharmony_ci					"could not unpin pages: %d\n", ret);
85962306a36Sopenharmony_ci			}
86062306a36Sopenharmony_ci			ret = tiler_release(omap_obj->block);
86162306a36Sopenharmony_ci			if (ret) {
86262306a36Sopenharmony_ci				dev_err(obj->dev->dev,
86362306a36Sopenharmony_ci					"could not release unmap: %d\n", ret);
86462306a36Sopenharmony_ci			}
86562306a36Sopenharmony_ci			omap_obj->dma_addr = 0;
86662306a36Sopenharmony_ci			omap_obj->block = NULL;
86762306a36Sopenharmony_ci		}
86862306a36Sopenharmony_ci	}
86962306a36Sopenharmony_ci}
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_ci/**
87262306a36Sopenharmony_ci * omap_gem_unpin() - Unpin a GEM object from memory
87362306a36Sopenharmony_ci * @obj: the GEM object
87462306a36Sopenharmony_ci *
87562306a36Sopenharmony_ci * Unpin the given GEM object previously pinned with omap_gem_pin(). Pins are
87662306a36Sopenharmony_ci * reference-counted, the actual unpin will only be performed when the number
87762306a36Sopenharmony_ci * of calls to this function matches the number of calls to omap_gem_pin().
87862306a36Sopenharmony_ci */
87962306a36Sopenharmony_civoid omap_gem_unpin(struct drm_gem_object *obj)
88062306a36Sopenharmony_ci{
88162306a36Sopenharmony_ci	struct omap_gem_object *omap_obj = to_omap_bo(obj);
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_ci	mutex_lock(&omap_obj->lock);
88462306a36Sopenharmony_ci	omap_gem_unpin_locked(obj);
88562306a36Sopenharmony_ci	mutex_unlock(&omap_obj->lock);
88662306a36Sopenharmony_ci}
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ci/* Get rotated scanout address (only valid if already pinned), at the
88962306a36Sopenharmony_ci * specified orientation and x,y offset from top-left corner of buffer
89062306a36Sopenharmony_ci * (only valid for tiled 2d buffers)
89162306a36Sopenharmony_ci */
89262306a36Sopenharmony_ciint omap_gem_rotated_dma_addr(struct drm_gem_object *obj, u32 orient,
89362306a36Sopenharmony_ci		int x, int y, dma_addr_t *dma_addr)
89462306a36Sopenharmony_ci{
89562306a36Sopenharmony_ci	struct omap_gem_object *omap_obj = to_omap_bo(obj);
89662306a36Sopenharmony_ci	int ret = -EINVAL;
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci	mutex_lock(&omap_obj->lock);
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_ci	if ((refcount_read(&omap_obj->pin_cnt) > 0) && omap_obj->block &&
90162306a36Sopenharmony_ci			(omap_obj->flags & OMAP_BO_TILED_MASK)) {
90262306a36Sopenharmony_ci		*dma_addr = tiler_tsptr(omap_obj->block, orient, x, y);
90362306a36Sopenharmony_ci		ret = 0;
90462306a36Sopenharmony_ci	}
90562306a36Sopenharmony_ci
90662306a36Sopenharmony_ci	mutex_unlock(&omap_obj->lock);
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ci	return ret;
90962306a36Sopenharmony_ci}
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_ci/* Get tiler stride for the buffer (only valid for 2d tiled buffers) */
91262306a36Sopenharmony_ciint omap_gem_tiled_stride(struct drm_gem_object *obj, u32 orient)
91362306a36Sopenharmony_ci{
91462306a36Sopenharmony_ci	struct omap_gem_object *omap_obj = to_omap_bo(obj);
91562306a36Sopenharmony_ci	int ret = -EINVAL;
91662306a36Sopenharmony_ci	if (omap_obj->flags & OMAP_BO_TILED_MASK)
91762306a36Sopenharmony_ci		ret = tiler_stride(gem2fmt(omap_obj->flags), orient);
91862306a36Sopenharmony_ci	return ret;
91962306a36Sopenharmony_ci}
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_ci/* if !remap, and we don't have pages backing, then fail, rather than
92262306a36Sopenharmony_ci * increasing the pin count (which we don't really do yet anyways,
92362306a36Sopenharmony_ci * because we don't support swapping pages back out).  And 'remap'
92462306a36Sopenharmony_ci * might not be quite the right name, but I wanted to keep it working
92562306a36Sopenharmony_ci * similarly to omap_gem_pin().  Note though that mutex is not
92662306a36Sopenharmony_ci * aquired if !remap (because this can be called in atomic ctxt),
92762306a36Sopenharmony_ci * but probably omap_gem_unpin() should be changed to work in the
92862306a36Sopenharmony_ci * same way.  If !remap, a matching omap_gem_put_pages() call is not
92962306a36Sopenharmony_ci * required (and should not be made).
93062306a36Sopenharmony_ci */
93162306a36Sopenharmony_ciint omap_gem_get_pages(struct drm_gem_object *obj, struct page ***pages,
93262306a36Sopenharmony_ci		bool remap)
93362306a36Sopenharmony_ci{
93462306a36Sopenharmony_ci	struct omap_gem_object *omap_obj = to_omap_bo(obj);
93562306a36Sopenharmony_ci	int ret = 0;
93662306a36Sopenharmony_ci
93762306a36Sopenharmony_ci	mutex_lock(&omap_obj->lock);
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci	if (remap) {
94062306a36Sopenharmony_ci		ret = omap_gem_attach_pages(obj);
94162306a36Sopenharmony_ci		if (ret)
94262306a36Sopenharmony_ci			goto unlock;
94362306a36Sopenharmony_ci	}
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_ci	if (!omap_obj->pages) {
94662306a36Sopenharmony_ci		ret = -ENOMEM;
94762306a36Sopenharmony_ci		goto unlock;
94862306a36Sopenharmony_ci	}
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_ci	*pages = omap_obj->pages;
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_ciunlock:
95362306a36Sopenharmony_ci	mutex_unlock(&omap_obj->lock);
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ci	return ret;
95662306a36Sopenharmony_ci}
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_ci/* release pages when DMA no longer being performed */
95962306a36Sopenharmony_ciint omap_gem_put_pages(struct drm_gem_object *obj)
96062306a36Sopenharmony_ci{
96162306a36Sopenharmony_ci	/* do something here if we dynamically attach/detach pages.. at
96262306a36Sopenharmony_ci	 * least they would no longer need to be pinned if everyone has
96362306a36Sopenharmony_ci	 * released the pages..
96462306a36Sopenharmony_ci	 */
96562306a36Sopenharmony_ci	return 0;
96662306a36Sopenharmony_ci}
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_cistruct sg_table *omap_gem_get_sg(struct drm_gem_object *obj,
96962306a36Sopenharmony_ci		enum dma_data_direction dir)
97062306a36Sopenharmony_ci{
97162306a36Sopenharmony_ci	struct omap_gem_object *omap_obj = to_omap_bo(obj);
97262306a36Sopenharmony_ci	dma_addr_t addr;
97362306a36Sopenharmony_ci	struct sg_table *sgt;
97462306a36Sopenharmony_ci	struct scatterlist *sg;
97562306a36Sopenharmony_ci	unsigned int count, len, stride, i;
97662306a36Sopenharmony_ci	int ret;
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ci	ret = omap_gem_pin(obj, &addr);
97962306a36Sopenharmony_ci	if (ret)
98062306a36Sopenharmony_ci		return ERR_PTR(ret);
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_ci	mutex_lock(&omap_obj->lock);
98362306a36Sopenharmony_ci
98462306a36Sopenharmony_ci	sgt = omap_obj->sgt;
98562306a36Sopenharmony_ci	if (sgt)
98662306a36Sopenharmony_ci		goto out;
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_ci	sgt = kzalloc(sizeof(*sgt), GFP_KERNEL);
98962306a36Sopenharmony_ci	if (!sgt) {
99062306a36Sopenharmony_ci		ret = -ENOMEM;
99162306a36Sopenharmony_ci		goto err_unpin;
99262306a36Sopenharmony_ci	}
99362306a36Sopenharmony_ci
99462306a36Sopenharmony_ci	if (addr) {
99562306a36Sopenharmony_ci		if (omap_obj->flags & OMAP_BO_TILED_MASK) {
99662306a36Sopenharmony_ci			enum tiler_fmt fmt = gem2fmt(omap_obj->flags);
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_ci			len = omap_obj->width << (int)fmt;
99962306a36Sopenharmony_ci			count = omap_obj->height;
100062306a36Sopenharmony_ci			stride = tiler_stride(fmt, 0);
100162306a36Sopenharmony_ci		} else {
100262306a36Sopenharmony_ci			len = obj->size;
100362306a36Sopenharmony_ci			count = 1;
100462306a36Sopenharmony_ci			stride = 0;
100562306a36Sopenharmony_ci		}
100662306a36Sopenharmony_ci	} else {
100762306a36Sopenharmony_ci		count = obj->size >> PAGE_SHIFT;
100862306a36Sopenharmony_ci	}
100962306a36Sopenharmony_ci
101062306a36Sopenharmony_ci	ret = sg_alloc_table(sgt, count, GFP_KERNEL);
101162306a36Sopenharmony_ci	if (ret)
101262306a36Sopenharmony_ci		goto err_free;
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_ci	/* this must be after omap_gem_pin() to ensure we have pages attached */
101562306a36Sopenharmony_ci	omap_gem_dma_sync_buffer(obj, dir);
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_ci	if (addr) {
101862306a36Sopenharmony_ci		for_each_sg(sgt->sgl, sg, count, i) {
101962306a36Sopenharmony_ci			sg_set_page(sg, phys_to_page(addr), len,
102062306a36Sopenharmony_ci				offset_in_page(addr));
102162306a36Sopenharmony_ci			sg_dma_address(sg) = addr;
102262306a36Sopenharmony_ci			sg_dma_len(sg) = len;
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_ci			addr += stride;
102562306a36Sopenharmony_ci		}
102662306a36Sopenharmony_ci	} else {
102762306a36Sopenharmony_ci		for_each_sg(sgt->sgl, sg, count, i) {
102862306a36Sopenharmony_ci			sg_set_page(sg, omap_obj->pages[i], PAGE_SIZE, 0);
102962306a36Sopenharmony_ci			sg_dma_address(sg) = omap_obj->dma_addrs[i];
103062306a36Sopenharmony_ci			sg_dma_len(sg) =  PAGE_SIZE;
103162306a36Sopenharmony_ci		}
103262306a36Sopenharmony_ci	}
103362306a36Sopenharmony_ci
103462306a36Sopenharmony_ci	omap_obj->sgt = sgt;
103562306a36Sopenharmony_ciout:
103662306a36Sopenharmony_ci	mutex_unlock(&omap_obj->lock);
103762306a36Sopenharmony_ci	return sgt;
103862306a36Sopenharmony_ci
103962306a36Sopenharmony_cierr_free:
104062306a36Sopenharmony_ci	kfree(sgt);
104162306a36Sopenharmony_cierr_unpin:
104262306a36Sopenharmony_ci	mutex_unlock(&omap_obj->lock);
104362306a36Sopenharmony_ci	omap_gem_unpin(obj);
104462306a36Sopenharmony_ci	return ERR_PTR(ret);
104562306a36Sopenharmony_ci}
104662306a36Sopenharmony_ci
104762306a36Sopenharmony_civoid omap_gem_put_sg(struct drm_gem_object *obj, struct sg_table *sgt)
104862306a36Sopenharmony_ci{
104962306a36Sopenharmony_ci	struct omap_gem_object *omap_obj = to_omap_bo(obj);
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_ci	if (WARN_ON(omap_obj->sgt != sgt))
105262306a36Sopenharmony_ci		return;
105362306a36Sopenharmony_ci
105462306a36Sopenharmony_ci	omap_gem_unpin(obj);
105562306a36Sopenharmony_ci}
105662306a36Sopenharmony_ci
105762306a36Sopenharmony_ci#ifdef CONFIG_DRM_FBDEV_EMULATION
105862306a36Sopenharmony_ci/*
105962306a36Sopenharmony_ci * Get kernel virtual address for CPU access.. this more or less only
106062306a36Sopenharmony_ci * exists for omap_fbdev.
106162306a36Sopenharmony_ci */
106262306a36Sopenharmony_civoid *omap_gem_vaddr(struct drm_gem_object *obj)
106362306a36Sopenharmony_ci{
106462306a36Sopenharmony_ci	struct omap_gem_object *omap_obj = to_omap_bo(obj);
106562306a36Sopenharmony_ci	void *vaddr;
106662306a36Sopenharmony_ci	int ret;
106762306a36Sopenharmony_ci
106862306a36Sopenharmony_ci	mutex_lock(&omap_obj->lock);
106962306a36Sopenharmony_ci
107062306a36Sopenharmony_ci	if (!omap_obj->vaddr) {
107162306a36Sopenharmony_ci		ret = omap_gem_attach_pages(obj);
107262306a36Sopenharmony_ci		if (ret) {
107362306a36Sopenharmony_ci			vaddr = ERR_PTR(ret);
107462306a36Sopenharmony_ci			goto unlock;
107562306a36Sopenharmony_ci		}
107662306a36Sopenharmony_ci
107762306a36Sopenharmony_ci		omap_obj->vaddr = vmap(omap_obj->pages, obj->size >> PAGE_SHIFT,
107862306a36Sopenharmony_ci				VM_MAP, pgprot_writecombine(PAGE_KERNEL));
107962306a36Sopenharmony_ci	}
108062306a36Sopenharmony_ci
108162306a36Sopenharmony_ci	vaddr = omap_obj->vaddr;
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_ciunlock:
108462306a36Sopenharmony_ci	mutex_unlock(&omap_obj->lock);
108562306a36Sopenharmony_ci	return vaddr;
108662306a36Sopenharmony_ci}
108762306a36Sopenharmony_ci#endif
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_ci/* -----------------------------------------------------------------------------
109062306a36Sopenharmony_ci * Power Management
109162306a36Sopenharmony_ci */
109262306a36Sopenharmony_ci
109362306a36Sopenharmony_ci#ifdef CONFIG_PM
109462306a36Sopenharmony_ci/* re-pin objects in DMM in resume path: */
109562306a36Sopenharmony_ciint omap_gem_resume(struct drm_device *dev)
109662306a36Sopenharmony_ci{
109762306a36Sopenharmony_ci	struct omap_drm_private *priv = dev->dev_private;
109862306a36Sopenharmony_ci	struct omap_gem_object *omap_obj;
109962306a36Sopenharmony_ci	int ret = 0;
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_ci	mutex_lock(&priv->list_lock);
110262306a36Sopenharmony_ci	list_for_each_entry(omap_obj, &priv->obj_list, mm_list) {
110362306a36Sopenharmony_ci		if (omap_obj->block) {
110462306a36Sopenharmony_ci			struct drm_gem_object *obj = &omap_obj->base;
110562306a36Sopenharmony_ci			u32 npages = obj->size >> PAGE_SHIFT;
110662306a36Sopenharmony_ci
110762306a36Sopenharmony_ci			WARN_ON(!omap_obj->pages);  /* this can't happen */
110862306a36Sopenharmony_ci			ret = tiler_pin(omap_obj->block,
110962306a36Sopenharmony_ci					omap_obj->pages, npages,
111062306a36Sopenharmony_ci					omap_obj->roll, true);
111162306a36Sopenharmony_ci			if (ret) {
111262306a36Sopenharmony_ci				dev_err(dev->dev, "could not repin: %d\n", ret);
111362306a36Sopenharmony_ci				goto done;
111462306a36Sopenharmony_ci			}
111562306a36Sopenharmony_ci		}
111662306a36Sopenharmony_ci	}
111762306a36Sopenharmony_ci
111862306a36Sopenharmony_cidone:
111962306a36Sopenharmony_ci	mutex_unlock(&priv->list_lock);
112062306a36Sopenharmony_ci	return ret;
112162306a36Sopenharmony_ci}
112262306a36Sopenharmony_ci#endif
112362306a36Sopenharmony_ci
112462306a36Sopenharmony_ci/* -----------------------------------------------------------------------------
112562306a36Sopenharmony_ci * DebugFS
112662306a36Sopenharmony_ci */
112762306a36Sopenharmony_ci
112862306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS
112962306a36Sopenharmony_civoid omap_gem_describe(struct drm_gem_object *obj, struct seq_file *m)
113062306a36Sopenharmony_ci{
113162306a36Sopenharmony_ci	struct omap_gem_object *omap_obj = to_omap_bo(obj);
113262306a36Sopenharmony_ci	u64 off;
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ci	off = drm_vma_node_start(&obj->vma_node);
113562306a36Sopenharmony_ci
113662306a36Sopenharmony_ci	mutex_lock(&omap_obj->lock);
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_ci	seq_printf(m, "%08x: %2d (%2d) %08llx %pad (%2d) %p %4d",
113962306a36Sopenharmony_ci			omap_obj->flags, obj->name, kref_read(&obj->refcount),
114062306a36Sopenharmony_ci			off, &omap_obj->dma_addr,
114162306a36Sopenharmony_ci			refcount_read(&omap_obj->pin_cnt),
114262306a36Sopenharmony_ci			omap_obj->vaddr, omap_obj->roll);
114362306a36Sopenharmony_ci
114462306a36Sopenharmony_ci	if (omap_obj->flags & OMAP_BO_TILED_MASK) {
114562306a36Sopenharmony_ci		seq_printf(m, " %dx%d", omap_obj->width, omap_obj->height);
114662306a36Sopenharmony_ci		if (omap_obj->block) {
114762306a36Sopenharmony_ci			struct tcm_area *area = &omap_obj->block->area;
114862306a36Sopenharmony_ci			seq_printf(m, " (%dx%d, %dx%d)",
114962306a36Sopenharmony_ci					area->p0.x, area->p0.y,
115062306a36Sopenharmony_ci					area->p1.x, area->p1.y);
115162306a36Sopenharmony_ci		}
115262306a36Sopenharmony_ci	} else {
115362306a36Sopenharmony_ci		seq_printf(m, " %zu", obj->size);
115462306a36Sopenharmony_ci	}
115562306a36Sopenharmony_ci
115662306a36Sopenharmony_ci	mutex_unlock(&omap_obj->lock);
115762306a36Sopenharmony_ci
115862306a36Sopenharmony_ci	seq_printf(m, "\n");
115962306a36Sopenharmony_ci}
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_civoid omap_gem_describe_objects(struct list_head *list, struct seq_file *m)
116262306a36Sopenharmony_ci{
116362306a36Sopenharmony_ci	struct omap_gem_object *omap_obj;
116462306a36Sopenharmony_ci	int count = 0;
116562306a36Sopenharmony_ci	size_t size = 0;
116662306a36Sopenharmony_ci
116762306a36Sopenharmony_ci	list_for_each_entry(omap_obj, list, mm_list) {
116862306a36Sopenharmony_ci		struct drm_gem_object *obj = &omap_obj->base;
116962306a36Sopenharmony_ci		seq_printf(m, "   ");
117062306a36Sopenharmony_ci		omap_gem_describe(obj, m);
117162306a36Sopenharmony_ci		count++;
117262306a36Sopenharmony_ci		size += obj->size;
117362306a36Sopenharmony_ci	}
117462306a36Sopenharmony_ci
117562306a36Sopenharmony_ci	seq_printf(m, "Total %d objects, %zu bytes\n", count, size);
117662306a36Sopenharmony_ci}
117762306a36Sopenharmony_ci#endif
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_ci/* -----------------------------------------------------------------------------
118062306a36Sopenharmony_ci * Constructor & Destructor
118162306a36Sopenharmony_ci */
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_cistatic void omap_gem_free_object(struct drm_gem_object *obj)
118462306a36Sopenharmony_ci{
118562306a36Sopenharmony_ci	struct drm_device *dev = obj->dev;
118662306a36Sopenharmony_ci	struct omap_drm_private *priv = dev->dev_private;
118762306a36Sopenharmony_ci	struct omap_gem_object *omap_obj = to_omap_bo(obj);
118862306a36Sopenharmony_ci
118962306a36Sopenharmony_ci	omap_gem_evict(obj);
119062306a36Sopenharmony_ci
119162306a36Sopenharmony_ci	mutex_lock(&priv->list_lock);
119262306a36Sopenharmony_ci	list_del(&omap_obj->mm_list);
119362306a36Sopenharmony_ci	mutex_unlock(&priv->list_lock);
119462306a36Sopenharmony_ci
119562306a36Sopenharmony_ci	/*
119662306a36Sopenharmony_ci	 * We own the sole reference to the object at this point, but to keep
119762306a36Sopenharmony_ci	 * lockdep happy, we must still take the omap_obj_lock to call
119862306a36Sopenharmony_ci	 * omap_gem_detach_pages(). This should hardly make any difference as
119962306a36Sopenharmony_ci	 * there can't be any lock contention.
120062306a36Sopenharmony_ci	 */
120162306a36Sopenharmony_ci	mutex_lock(&omap_obj->lock);
120262306a36Sopenharmony_ci
120362306a36Sopenharmony_ci	/* The object should not be pinned. */
120462306a36Sopenharmony_ci	WARN_ON(refcount_read(&omap_obj->pin_cnt) > 0);
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_ci	if (omap_obj->pages) {
120762306a36Sopenharmony_ci		if (omap_obj->flags & OMAP_BO_MEM_DMABUF)
120862306a36Sopenharmony_ci			kfree(omap_obj->pages);
120962306a36Sopenharmony_ci		else
121062306a36Sopenharmony_ci			omap_gem_detach_pages(obj);
121162306a36Sopenharmony_ci	}
121262306a36Sopenharmony_ci
121362306a36Sopenharmony_ci	if (omap_obj->flags & OMAP_BO_MEM_DMA_API) {
121462306a36Sopenharmony_ci		dma_free_wc(dev->dev, obj->size, omap_obj->vaddr,
121562306a36Sopenharmony_ci			    omap_obj->dma_addr);
121662306a36Sopenharmony_ci	} else if (omap_obj->vaddr) {
121762306a36Sopenharmony_ci		vunmap(omap_obj->vaddr);
121862306a36Sopenharmony_ci	} else if (obj->import_attach) {
121962306a36Sopenharmony_ci		drm_prime_gem_destroy(obj, omap_obj->sgt);
122062306a36Sopenharmony_ci	}
122162306a36Sopenharmony_ci
122262306a36Sopenharmony_ci	mutex_unlock(&omap_obj->lock);
122362306a36Sopenharmony_ci
122462306a36Sopenharmony_ci	drm_gem_object_release(obj);
122562306a36Sopenharmony_ci
122662306a36Sopenharmony_ci	mutex_destroy(&omap_obj->lock);
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_ci	kfree(omap_obj);
122962306a36Sopenharmony_ci}
123062306a36Sopenharmony_ci
123162306a36Sopenharmony_cistatic bool omap_gem_validate_flags(struct drm_device *dev, u32 flags)
123262306a36Sopenharmony_ci{
123362306a36Sopenharmony_ci	struct omap_drm_private *priv = dev->dev_private;
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_ci	switch (flags & OMAP_BO_CACHE_MASK) {
123662306a36Sopenharmony_ci	case OMAP_BO_CACHED:
123762306a36Sopenharmony_ci	case OMAP_BO_WC:
123862306a36Sopenharmony_ci	case OMAP_BO_CACHE_MASK:
123962306a36Sopenharmony_ci		break;
124062306a36Sopenharmony_ci
124162306a36Sopenharmony_ci	default:
124262306a36Sopenharmony_ci		return false;
124362306a36Sopenharmony_ci	}
124462306a36Sopenharmony_ci
124562306a36Sopenharmony_ci	if (flags & OMAP_BO_TILED_MASK) {
124662306a36Sopenharmony_ci		if (!priv->usergart)
124762306a36Sopenharmony_ci			return false;
124862306a36Sopenharmony_ci
124962306a36Sopenharmony_ci		switch (flags & OMAP_BO_TILED_MASK) {
125062306a36Sopenharmony_ci		case OMAP_BO_TILED_8:
125162306a36Sopenharmony_ci		case OMAP_BO_TILED_16:
125262306a36Sopenharmony_ci		case OMAP_BO_TILED_32:
125362306a36Sopenharmony_ci			break;
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_ci		default:
125662306a36Sopenharmony_ci			return false;
125762306a36Sopenharmony_ci		}
125862306a36Sopenharmony_ci	}
125962306a36Sopenharmony_ci
126062306a36Sopenharmony_ci	return true;
126162306a36Sopenharmony_ci}
126262306a36Sopenharmony_ci
126362306a36Sopenharmony_cistatic const struct vm_operations_struct omap_gem_vm_ops = {
126462306a36Sopenharmony_ci	.fault = omap_gem_fault,
126562306a36Sopenharmony_ci	.open = drm_gem_vm_open,
126662306a36Sopenharmony_ci	.close = drm_gem_vm_close,
126762306a36Sopenharmony_ci};
126862306a36Sopenharmony_ci
126962306a36Sopenharmony_cistatic const struct drm_gem_object_funcs omap_gem_object_funcs = {
127062306a36Sopenharmony_ci	.free = omap_gem_free_object,
127162306a36Sopenharmony_ci	.export = omap_gem_prime_export,
127262306a36Sopenharmony_ci	.mmap = omap_gem_object_mmap,
127362306a36Sopenharmony_ci	.vm_ops = &omap_gem_vm_ops,
127462306a36Sopenharmony_ci};
127562306a36Sopenharmony_ci
127662306a36Sopenharmony_ci/* GEM buffer object constructor */
127762306a36Sopenharmony_cistruct drm_gem_object *omap_gem_new(struct drm_device *dev,
127862306a36Sopenharmony_ci		union omap_gem_size gsize, u32 flags)
127962306a36Sopenharmony_ci{
128062306a36Sopenharmony_ci	struct omap_drm_private *priv = dev->dev_private;
128162306a36Sopenharmony_ci	struct omap_gem_object *omap_obj;
128262306a36Sopenharmony_ci	struct drm_gem_object *obj;
128362306a36Sopenharmony_ci	struct address_space *mapping;
128462306a36Sopenharmony_ci	size_t size;
128562306a36Sopenharmony_ci	int ret;
128662306a36Sopenharmony_ci
128762306a36Sopenharmony_ci	if (!omap_gem_validate_flags(dev, flags))
128862306a36Sopenharmony_ci		return NULL;
128962306a36Sopenharmony_ci
129062306a36Sopenharmony_ci	/* Validate the flags and compute the memory and cache flags. */
129162306a36Sopenharmony_ci	if (flags & OMAP_BO_TILED_MASK) {
129262306a36Sopenharmony_ci		/*
129362306a36Sopenharmony_ci		 * Tiled buffers are always shmem paged backed. When they are
129462306a36Sopenharmony_ci		 * scanned out, they are remapped into DMM/TILER.
129562306a36Sopenharmony_ci		 */
129662306a36Sopenharmony_ci		flags |= OMAP_BO_MEM_SHMEM;
129762306a36Sopenharmony_ci
129862306a36Sopenharmony_ci		/*
129962306a36Sopenharmony_ci		 * Currently don't allow cached buffers. There is some caching
130062306a36Sopenharmony_ci		 * stuff that needs to be handled better.
130162306a36Sopenharmony_ci		 */
130262306a36Sopenharmony_ci		flags &= ~(OMAP_BO_CACHED|OMAP_BO_WC|OMAP_BO_UNCACHED);
130362306a36Sopenharmony_ci		flags |= tiler_get_cpu_cache_flags();
130462306a36Sopenharmony_ci	} else if ((flags & OMAP_BO_SCANOUT) && !priv->has_dmm) {
130562306a36Sopenharmony_ci		/*
130662306a36Sopenharmony_ci		 * If we don't have DMM, we must allocate scanout buffers
130762306a36Sopenharmony_ci		 * from contiguous DMA memory.
130862306a36Sopenharmony_ci		 */
130962306a36Sopenharmony_ci		flags |= OMAP_BO_MEM_DMA_API;
131062306a36Sopenharmony_ci	} else if (!(flags & OMAP_BO_MEM_DMABUF)) {
131162306a36Sopenharmony_ci		/*
131262306a36Sopenharmony_ci		 * All other buffers not backed by dma_buf are shmem-backed.
131362306a36Sopenharmony_ci		 */
131462306a36Sopenharmony_ci		flags |= OMAP_BO_MEM_SHMEM;
131562306a36Sopenharmony_ci	}
131662306a36Sopenharmony_ci
131762306a36Sopenharmony_ci	/* Allocate the initialize the OMAP GEM object. */
131862306a36Sopenharmony_ci	omap_obj = kzalloc(sizeof(*omap_obj), GFP_KERNEL);
131962306a36Sopenharmony_ci	if (!omap_obj)
132062306a36Sopenharmony_ci		return NULL;
132162306a36Sopenharmony_ci
132262306a36Sopenharmony_ci	obj = &omap_obj->base;
132362306a36Sopenharmony_ci	omap_obj->flags = flags;
132462306a36Sopenharmony_ci	mutex_init(&omap_obj->lock);
132562306a36Sopenharmony_ci
132662306a36Sopenharmony_ci	if (flags & OMAP_BO_TILED_MASK) {
132762306a36Sopenharmony_ci		/*
132862306a36Sopenharmony_ci		 * For tiled buffers align dimensions to slot boundaries and
132962306a36Sopenharmony_ci		 * calculate size based on aligned dimensions.
133062306a36Sopenharmony_ci		 */
133162306a36Sopenharmony_ci		tiler_align(gem2fmt(flags), &gsize.tiled.width,
133262306a36Sopenharmony_ci			    &gsize.tiled.height);
133362306a36Sopenharmony_ci
133462306a36Sopenharmony_ci		size = tiler_size(gem2fmt(flags), gsize.tiled.width,
133562306a36Sopenharmony_ci				  gsize.tiled.height);
133662306a36Sopenharmony_ci
133762306a36Sopenharmony_ci		omap_obj->width = gsize.tiled.width;
133862306a36Sopenharmony_ci		omap_obj->height = gsize.tiled.height;
133962306a36Sopenharmony_ci	} else {
134062306a36Sopenharmony_ci		size = PAGE_ALIGN(gsize.bytes);
134162306a36Sopenharmony_ci	}
134262306a36Sopenharmony_ci
134362306a36Sopenharmony_ci	obj->funcs = &omap_gem_object_funcs;
134462306a36Sopenharmony_ci
134562306a36Sopenharmony_ci	/* Initialize the GEM object. */
134662306a36Sopenharmony_ci	if (!(flags & OMAP_BO_MEM_SHMEM)) {
134762306a36Sopenharmony_ci		drm_gem_private_object_init(dev, obj, size);
134862306a36Sopenharmony_ci	} else {
134962306a36Sopenharmony_ci		ret = drm_gem_object_init(dev, obj, size);
135062306a36Sopenharmony_ci		if (ret)
135162306a36Sopenharmony_ci			goto err_free;
135262306a36Sopenharmony_ci
135362306a36Sopenharmony_ci		mapping = obj->filp->f_mapping;
135462306a36Sopenharmony_ci		mapping_set_gfp_mask(mapping, GFP_USER | __GFP_DMA32);
135562306a36Sopenharmony_ci	}
135662306a36Sopenharmony_ci
135762306a36Sopenharmony_ci	/* Allocate memory if needed. */
135862306a36Sopenharmony_ci	if (flags & OMAP_BO_MEM_DMA_API) {
135962306a36Sopenharmony_ci		omap_obj->vaddr = dma_alloc_wc(dev->dev, size,
136062306a36Sopenharmony_ci					       &omap_obj->dma_addr,
136162306a36Sopenharmony_ci					       GFP_KERNEL);
136262306a36Sopenharmony_ci		if (!omap_obj->vaddr)
136362306a36Sopenharmony_ci			goto err_release;
136462306a36Sopenharmony_ci	}
136562306a36Sopenharmony_ci
136662306a36Sopenharmony_ci	mutex_lock(&priv->list_lock);
136762306a36Sopenharmony_ci	list_add(&omap_obj->mm_list, &priv->obj_list);
136862306a36Sopenharmony_ci	mutex_unlock(&priv->list_lock);
136962306a36Sopenharmony_ci
137062306a36Sopenharmony_ci	return obj;
137162306a36Sopenharmony_ci
137262306a36Sopenharmony_cierr_release:
137362306a36Sopenharmony_ci	drm_gem_object_release(obj);
137462306a36Sopenharmony_cierr_free:
137562306a36Sopenharmony_ci	kfree(omap_obj);
137662306a36Sopenharmony_ci	return NULL;
137762306a36Sopenharmony_ci}
137862306a36Sopenharmony_ci
137962306a36Sopenharmony_cistruct drm_gem_object *omap_gem_new_dmabuf(struct drm_device *dev, size_t size,
138062306a36Sopenharmony_ci					   struct sg_table *sgt)
138162306a36Sopenharmony_ci{
138262306a36Sopenharmony_ci	struct omap_drm_private *priv = dev->dev_private;
138362306a36Sopenharmony_ci	struct omap_gem_object *omap_obj;
138462306a36Sopenharmony_ci	struct drm_gem_object *obj;
138562306a36Sopenharmony_ci	union omap_gem_size gsize;
138662306a36Sopenharmony_ci
138762306a36Sopenharmony_ci	/* Without a DMM only physically contiguous buffers can be supported. */
138862306a36Sopenharmony_ci	if (sgt->orig_nents != 1 && !priv->has_dmm)
138962306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
139062306a36Sopenharmony_ci
139162306a36Sopenharmony_ci	gsize.bytes = PAGE_ALIGN(size);
139262306a36Sopenharmony_ci	obj = omap_gem_new(dev, gsize, OMAP_BO_MEM_DMABUF | OMAP_BO_WC);
139362306a36Sopenharmony_ci	if (!obj)
139462306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
139562306a36Sopenharmony_ci
139662306a36Sopenharmony_ci	omap_obj = to_omap_bo(obj);
139762306a36Sopenharmony_ci
139862306a36Sopenharmony_ci	mutex_lock(&omap_obj->lock);
139962306a36Sopenharmony_ci
140062306a36Sopenharmony_ci	omap_obj->sgt = sgt;
140162306a36Sopenharmony_ci
140262306a36Sopenharmony_ci	if (sgt->orig_nents == 1) {
140362306a36Sopenharmony_ci		omap_obj->dma_addr = sg_dma_address(sgt->sgl);
140462306a36Sopenharmony_ci	} else {
140562306a36Sopenharmony_ci		/* Create pages list from sgt */
140662306a36Sopenharmony_ci		struct page **pages;
140762306a36Sopenharmony_ci		unsigned int npages;
140862306a36Sopenharmony_ci		unsigned int ret;
140962306a36Sopenharmony_ci
141062306a36Sopenharmony_ci		npages = DIV_ROUND_UP(size, PAGE_SIZE);
141162306a36Sopenharmony_ci		pages = kcalloc(npages, sizeof(*pages), GFP_KERNEL);
141262306a36Sopenharmony_ci		if (!pages) {
141362306a36Sopenharmony_ci			omap_gem_free_object(obj);
141462306a36Sopenharmony_ci			obj = ERR_PTR(-ENOMEM);
141562306a36Sopenharmony_ci			goto done;
141662306a36Sopenharmony_ci		}
141762306a36Sopenharmony_ci
141862306a36Sopenharmony_ci		omap_obj->pages = pages;
141962306a36Sopenharmony_ci		ret = drm_prime_sg_to_page_array(sgt, pages, npages);
142062306a36Sopenharmony_ci		if (ret) {
142162306a36Sopenharmony_ci			omap_gem_free_object(obj);
142262306a36Sopenharmony_ci			obj = ERR_PTR(-ENOMEM);
142362306a36Sopenharmony_ci			goto done;
142462306a36Sopenharmony_ci		}
142562306a36Sopenharmony_ci	}
142662306a36Sopenharmony_ci
142762306a36Sopenharmony_cidone:
142862306a36Sopenharmony_ci	mutex_unlock(&omap_obj->lock);
142962306a36Sopenharmony_ci	return obj;
143062306a36Sopenharmony_ci}
143162306a36Sopenharmony_ci
143262306a36Sopenharmony_ci/* convenience method to construct a GEM buffer object, and userspace handle */
143362306a36Sopenharmony_ciint omap_gem_new_handle(struct drm_device *dev, struct drm_file *file,
143462306a36Sopenharmony_ci		union omap_gem_size gsize, u32 flags, u32 *handle)
143562306a36Sopenharmony_ci{
143662306a36Sopenharmony_ci	struct drm_gem_object *obj;
143762306a36Sopenharmony_ci	int ret;
143862306a36Sopenharmony_ci
143962306a36Sopenharmony_ci	obj = omap_gem_new(dev, gsize, flags);
144062306a36Sopenharmony_ci	if (!obj)
144162306a36Sopenharmony_ci		return -ENOMEM;
144262306a36Sopenharmony_ci
144362306a36Sopenharmony_ci	ret = drm_gem_handle_create(file, obj, handle);
144462306a36Sopenharmony_ci	if (ret) {
144562306a36Sopenharmony_ci		omap_gem_free_object(obj);
144662306a36Sopenharmony_ci		return ret;
144762306a36Sopenharmony_ci	}
144862306a36Sopenharmony_ci
144962306a36Sopenharmony_ci	/* drop reference from allocate - handle holds it now */
145062306a36Sopenharmony_ci	drm_gem_object_put(obj);
145162306a36Sopenharmony_ci
145262306a36Sopenharmony_ci	return 0;
145362306a36Sopenharmony_ci}
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_ci/* -----------------------------------------------------------------------------
145662306a36Sopenharmony_ci * Init & Cleanup
145762306a36Sopenharmony_ci */
145862306a36Sopenharmony_ci
145962306a36Sopenharmony_ci/* If DMM is used, we need to set some stuff up.. */
146062306a36Sopenharmony_civoid omap_gem_init(struct drm_device *dev)
146162306a36Sopenharmony_ci{
146262306a36Sopenharmony_ci	struct omap_drm_private *priv = dev->dev_private;
146362306a36Sopenharmony_ci	struct omap_drm_usergart *usergart;
146462306a36Sopenharmony_ci	const enum tiler_fmt fmts[] = {
146562306a36Sopenharmony_ci			TILFMT_8BIT, TILFMT_16BIT, TILFMT_32BIT
146662306a36Sopenharmony_ci	};
146762306a36Sopenharmony_ci	int i, j;
146862306a36Sopenharmony_ci
146962306a36Sopenharmony_ci	if (!dmm_is_available()) {
147062306a36Sopenharmony_ci		/* DMM only supported on OMAP4 and later, so this isn't fatal */
147162306a36Sopenharmony_ci		dev_warn(dev->dev, "DMM not available, disable DMM support\n");
147262306a36Sopenharmony_ci		return;
147362306a36Sopenharmony_ci	}
147462306a36Sopenharmony_ci
147562306a36Sopenharmony_ci	usergart = kcalloc(3, sizeof(*usergart), GFP_KERNEL);
147662306a36Sopenharmony_ci	if (!usergart)
147762306a36Sopenharmony_ci		return;
147862306a36Sopenharmony_ci
147962306a36Sopenharmony_ci	/* reserve 4k aligned/wide regions for userspace mappings: */
148062306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(fmts); i++) {
148162306a36Sopenharmony_ci		u16 h = 1, w = PAGE_SIZE >> i;
148262306a36Sopenharmony_ci
148362306a36Sopenharmony_ci		tiler_align(fmts[i], &w, &h);
148462306a36Sopenharmony_ci		/* note: since each region is 1 4kb page wide, and minimum
148562306a36Sopenharmony_ci		 * number of rows, the height ends up being the same as the
148662306a36Sopenharmony_ci		 * # of pages in the region
148762306a36Sopenharmony_ci		 */
148862306a36Sopenharmony_ci		usergart[i].height = h;
148962306a36Sopenharmony_ci		usergart[i].height_shift = ilog2(h);
149062306a36Sopenharmony_ci		usergart[i].stride_pfn = tiler_stride(fmts[i], 0) >> PAGE_SHIFT;
149162306a36Sopenharmony_ci		usergart[i].slot_shift = ilog2((PAGE_SIZE / h) >> i);
149262306a36Sopenharmony_ci		for (j = 0; j < NUM_USERGART_ENTRIES; j++) {
149362306a36Sopenharmony_ci			struct omap_drm_usergart_entry *entry;
149462306a36Sopenharmony_ci			struct tiler_block *block;
149562306a36Sopenharmony_ci
149662306a36Sopenharmony_ci			entry = &usergart[i].entry[j];
149762306a36Sopenharmony_ci			block = tiler_reserve_2d(fmts[i], w, h, PAGE_SIZE);
149862306a36Sopenharmony_ci			if (IS_ERR(block)) {
149962306a36Sopenharmony_ci				dev_err(dev->dev,
150062306a36Sopenharmony_ci						"reserve failed: %d, %d, %ld\n",
150162306a36Sopenharmony_ci						i, j, PTR_ERR(block));
150262306a36Sopenharmony_ci				return;
150362306a36Sopenharmony_ci			}
150462306a36Sopenharmony_ci			entry->dma_addr = tiler_ssptr(block);
150562306a36Sopenharmony_ci			entry->block = block;
150662306a36Sopenharmony_ci
150762306a36Sopenharmony_ci			DBG("%d:%d: %dx%d: dma_addr=%pad stride=%d", i, j, w, h,
150862306a36Sopenharmony_ci					&entry->dma_addr,
150962306a36Sopenharmony_ci					usergart[i].stride_pfn << PAGE_SHIFT);
151062306a36Sopenharmony_ci		}
151162306a36Sopenharmony_ci	}
151262306a36Sopenharmony_ci
151362306a36Sopenharmony_ci	priv->usergart = usergart;
151462306a36Sopenharmony_ci	priv->has_dmm = true;
151562306a36Sopenharmony_ci}
151662306a36Sopenharmony_ci
151762306a36Sopenharmony_civoid omap_gem_deinit(struct drm_device *dev)
151862306a36Sopenharmony_ci{
151962306a36Sopenharmony_ci	struct omap_drm_private *priv = dev->dev_private;
152062306a36Sopenharmony_ci
152162306a36Sopenharmony_ci	/* I believe we can rely on there being no more outstanding GEM
152262306a36Sopenharmony_ci	 * objects which could depend on usergart/dmm at this point.
152362306a36Sopenharmony_ci	 */
152462306a36Sopenharmony_ci	kfree(priv->usergart);
152562306a36Sopenharmony_ci}
1526