[Intel-gfx] [RFC PATCH v4 2/4] drm/ipvr: drm driver for VED

Cheng, Yao yao.cheng at intel.com
Wed Jan 14 18:52:11 PST 2015


+ commenters of v1~v3

Thanks,
Yao

> -----Original Message-----
> From: Sean V Kelley [mailto:seanvk at posteo.de]
> Sent: Thursday, January 8, 2015 8:35
> To: Intel-gfx at lists.freedesktop.org
> Cc: dri-devel at lists.freedesktop.org; Cheng, Yao; Sean V Kelley
> Subject: [RFC PATCH v4 2/4] drm/ipvr: drm driver for VED
> 
> From: Yao Cheng <yao.cheng at intel.com>
> 
> Probes VED and creates a new drm device for hardware accelerated
> video decoding.
> Currently support VP8 decoding on valleyview.
> 
> v2:
> take David's comments
> 	- add mmap support and remove mmap_ioctl
> 	- remove postclose since it's deprecated
> 	- NULL set_busid
> 
> v3:
> take David, Daniel and Jesse's comments and massive refine
> 	- use drm_dev_alloc+drm_dev_register to replace
> drm_platform_init
> 	- same as above in exit side
> 	- remove fd based explit fence
> 	- refine ipvr_drm.h, use __u32 series and refine paddings
> 	- add doc to describe ipvr/ved terminology
> 	- ioctl refine: remove unused code
> 	- use uintptr_t series for address/number conversion
> 	- runtime pm refine: guarantee get/put paring
> 	- add PRIME feature and remove USERPTR ioctl
> 	- implement relocation fixup in EXEC ioctl
> 	- call drm_gem_get_pages to replace my own implementation
> 	- code cleanup: remove unused code
> 
> v4:
> bug fixing,
> 	- add missing unreference in ipvr_gem_fault()
> 	- add struct_mutex lock around
> drm_mm_insert_node_in_range_generic()
> 	- move ipvr_ctx_list from dev_priv to file_priv and add spinlock
> 	- check EAGAIN for pm_runtime_get/put and add lock
> 	- add mutex lock for do_execbuffer
> 	- put power on fence lockup
> 	- define all ioctls as DRM_AUTH|DRM_UNLOCKED
> 	- correctly set ved_busy
> 	- rename ipvr_misc_ioctl to ipvr_get_info_ioctl and remove unused
> code
> 
> Signed-off-by: Yao Cheng <yao.cheng at intel.com>
> Signed-off-by: Sean V Kelley <seanvk at posteo.de>
> ---
>  Documentation/DocBook/drm.tmpl    |   39 ++
>  drivers/gpu/drm/Kconfig           |    2 +
>  drivers/gpu/drm/Makefile          |    1 +
>  drivers/gpu/drm/ipvr/Kconfig      |    9 +
>  drivers/gpu/drm/ipvr/Makefile     |   18 +
>  drivers/gpu/drm/ipvr/ipvr_bo.c    |  543 +++++++++++++++++
>  drivers/gpu/drm/ipvr/ipvr_bo.h    |   80 +++
>  drivers/gpu/drm/ipvr/ipvr_debug.c |  335 +++++++++++
>  drivers/gpu/drm/ipvr/ipvr_debug.h |   76 +++
>  drivers/gpu/drm/ipvr/ipvr_drm.h   |  259 ++++++++
>  drivers/gpu/drm/ipvr/ipvr_drv.c   |  617 +++++++++++++++++++
>  drivers/gpu/drm/ipvr/ipvr_drv.h   |  292 +++++++++
>  drivers/gpu/drm/ipvr/ipvr_exec.c  |  613 +++++++++++++++++++
>  drivers/gpu/drm/ipvr/ipvr_exec.h  |   57 ++
>  drivers/gpu/drm/ipvr/ipvr_fence.c |  487 +++++++++++++++
>  drivers/gpu/drm/ipvr/ipvr_fence.h |   72 +++
>  drivers/gpu/drm/ipvr/ipvr_gem.c   |  297 +++++++++
>  drivers/gpu/drm/ipvr/ipvr_gem.h   |   48 ++
>  drivers/gpu/drm/ipvr/ipvr_mmu.c   |  752 +++++++++++++++++++++++
>  drivers/gpu/drm/ipvr/ipvr_mmu.h   |  111 ++++
>  drivers/gpu/drm/ipvr/ipvr_trace.c |   11 +
>  drivers/gpu/drm/ipvr/ipvr_trace.h |  333 ++++++++++
>  drivers/gpu/drm/ipvr/ved_cmd.c    |  882
> +++++++++++++++++++++++++++
>  drivers/gpu/drm/ipvr/ved_cmd.h    |   70 +++
>  drivers/gpu/drm/ipvr/ved_fw.c     | 1199
> +++++++++++++++++++++++++++++++++++++
>  drivers/gpu/drm/ipvr/ved_fw.h     |   81 +++
>  drivers/gpu/drm/ipvr/ved_msg.h    |  256 ++++++++
>  drivers/gpu/drm/ipvr/ved_pm.c     |  335 +++++++++++
>  drivers/gpu/drm/ipvr/ved_pm.h     |   36 ++
>  drivers/gpu/drm/ipvr/ved_reg.h    |  561 +++++++++++++++++
>  30 files changed, 8472 insertions(+)
>  create mode 100644 drivers/gpu/drm/ipvr/Kconfig
>  create mode 100644 drivers/gpu/drm/ipvr/Makefile
>  create mode 100644 drivers/gpu/drm/ipvr/ipvr_bo.c
>  create mode 100644 drivers/gpu/drm/ipvr/ipvr_bo.h
>  create mode 100644 drivers/gpu/drm/ipvr/ipvr_debug.c
>  create mode 100644 drivers/gpu/drm/ipvr/ipvr_debug.h
>  create mode 100644 drivers/gpu/drm/ipvr/ipvr_drm.h
>  create mode 100644 drivers/gpu/drm/ipvr/ipvr_drv.c
>  create mode 100644 drivers/gpu/drm/ipvr/ipvr_drv.h
>  create mode 100644 drivers/gpu/drm/ipvr/ipvr_exec.c
>  create mode 100644 drivers/gpu/drm/ipvr/ipvr_exec.h
>  create mode 100644 drivers/gpu/drm/ipvr/ipvr_fence.c
>  create mode 100644 drivers/gpu/drm/ipvr/ipvr_fence.h
>  create mode 100644 drivers/gpu/drm/ipvr/ipvr_gem.c
>  create mode 100644 drivers/gpu/drm/ipvr/ipvr_gem.h
>  create mode 100644 drivers/gpu/drm/ipvr/ipvr_mmu.c
>  create mode 100644 drivers/gpu/drm/ipvr/ipvr_mmu.h
>  create mode 100644 drivers/gpu/drm/ipvr/ipvr_trace.c
>  create mode 100644 drivers/gpu/drm/ipvr/ipvr_trace.h
>  create mode 100644 drivers/gpu/drm/ipvr/ved_cmd.c
>  create mode 100644 drivers/gpu/drm/ipvr/ved_cmd.h
>  create mode 100644 drivers/gpu/drm/ipvr/ved_fw.c
>  create mode 100644 drivers/gpu/drm/ipvr/ved_fw.h
>  create mode 100644 drivers/gpu/drm/ipvr/ved_msg.h
>  create mode 100644 drivers/gpu/drm/ipvr/ved_pm.c
>  create mode 100644 drivers/gpu/drm/ipvr/ved_pm.h
>  create mode 100644 drivers/gpu/drm/ipvr/ved_reg.h
> 
> diff --git a/Documentation/DocBook/drm.tmpl
> b/Documentation/DocBook/drm.tmpl
> index 9db989c..e9cadf6 100644
> --- a/Documentation/DocBook/drm.tmpl
> +++ b/Documentation/DocBook/drm.tmpl
> @@ -4062,5 +4062,44 @@ int num_ioctls;</synopsis>
> 
>    </chapter>
>  !Cdrivers/gpu/drm/i915/i915_irq.c
> +  <chapter id="drmIpvr">
> +    <title>drm/ipvr Intel's driver for PowerVR video core</title>
> +    <para>
> +      The drm/ipvr driver intends to support the PowerVR video cores
> +	  integrated on Intel's platforms. The video cores can be categorized
> +	  into 3 types:
> +        <variablelist>
> +          <varlistentry>
> +            <term>VED</term>
> +            <listitem>
> +              <para>
> +                multi-format video decoder, various video codecs are supported,
> +				e.g. H.264, VP8, etc..
> +              </para>
> +            </listitem>
> +          </varlistentry>
> +          <varlistentry>
> +            <term>VEC</term>
> +            <listitem>
> +              <para>
> +                multi-format video encoder, various video codecs support like
> +				VED.
> +              </para>
> +            </listitem>
> +          </varlistentry>
> +          <varlistentry>
> +            <term>VSP</term>
> +            <listitem>
> +              <para>
> +		        multi-function video processing. supports various
> features such
> +				as color-space-conversion, sharpening,
> deblocking, etc..
> +              </para>
> +            </listitem>
> +          </varlistentry>
> +        </variablelist>
> +	  Now ipvr only supports VED on Valleyview platform. The names
> "VEC"
> +	  and "VSP" are reserved for possible future support.
> +    </para>
> +  </chapter>
>  </part>
>  </book>
> diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
> index 24c2d7c..c79b813 100644
> --- a/drivers/gpu/drm/Kconfig
> +++ b/drivers/gpu/drm/Kconfig
> @@ -165,6 +165,8 @@ config DRM_SAVAGE
>  	  Choose this option if you have a
> Savage3D/4/SuperSavage/Pro/Twister
>  	  chipset. If M is selected the module will be called savage.
> 
> +source "drivers/gpu/drm/ipvr/Kconfig"
> +
>  source "drivers/gpu/drm/exynos/Kconfig"
> 
>  source "drivers/gpu/drm/vmwgfx/Kconfig"
> diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
> index 47d8986..d364ea2 100644
> --- a/drivers/gpu/drm/Makefile
> +++ b/drivers/gpu/drm/Makefile
> @@ -41,6 +41,7 @@ obj-$(CONFIG_DRM_RADEON)+= radeon/
>  obj-$(CONFIG_DRM_MGA)	+= mga/
>  obj-$(CONFIG_DRM_I810)	+= i810/
>  obj-$(CONFIG_DRM_I915)  += i915/
> +obj-$(CONFIG_DRM_IPVR)  += ipvr/
>  obj-$(CONFIG_DRM_MGAG200) += mgag200/
>  obj-$(CONFIG_DRM_CIRRUS_QEMU) += cirrus/
>  obj-$(CONFIG_DRM_SIS)   += sis/
> diff --git a/drivers/gpu/drm/ipvr/Kconfig b/drivers/gpu/drm/ipvr/Kconfig
> new file mode 100644
> index 0000000..869bad4
> --- /dev/null
> +++ b/drivers/gpu/drm/ipvr/Kconfig
> @@ -0,0 +1,9 @@
> +config DRM_IPVR
> +       tristate "IPVR video decode driver"
> +       depends on DRM
> +       select SHMEM
> +       select TMPFS
> +       default m
> +       help
> +         Choose this option if you want to enable accelerated video decode
> with VED hardware.
> +		 Currently support VP8 decoding on valleyview.
> diff --git a/drivers/gpu/drm/ipvr/Makefile b/drivers/gpu/drm/ipvr/Makefile
> new file mode 100644
> index 0000000..280647e
> --- /dev/null
> +++ b/drivers/gpu/drm/ipvr/Makefile
> @@ -0,0 +1,18 @@
> +ccflags-y := -Iinclude/drm
> +
> +ipvr-y := \
> +        ipvr_drv.o \
> +        ipvr_bo.o \
> +        ipvr_exec.o \
> +        ipvr_fence.o \
> +        ipvr_gem.o \
> +        ipvr_mmu.o \
> +        ipvr_debug.o \
> +        ipvr_trace.o \
> +        ved_pm.o \
> +        ved_cmd.o \
> +        ved_fw.o
> +
> +obj-$(CONFIG_DRM_IPVR) += ipvr.o
> +
> +CFLAGS_ipvr_trace.o := -I$(src)
> diff --git a/drivers/gpu/drm/ipvr/ipvr_bo.c b/drivers/gpu/drm/ipvr/ipvr_bo.c
> new file mode 100644
> index 0000000..5fccf7e
> --- /dev/null
> +++ b/drivers/gpu/drm/ipvr/ipvr_bo.c
> @@ -0,0 +1,543 @@
> +/*********************************************************
> *****************
> + * ipvr_bo.c: IPVR buffer creation/destory, import/export, map etc
> + *
> + * Copyright (c) 2014 Intel Corporation, Hillsboro, OR, USA
> + * All Rights Reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of
> MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
> License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along
> with
> + * this program; if not, write to the Free Software Foundation, Inc.,
> + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
> + *
> + * Authors:
> + *    Yao Cheng <yao.cheng at intel.com>
> + *
> +
> **********************************************************
> ****************/
> +
> +#include "ipvr_bo.h"
> +#include "ipvr_trace.h"
> +#include "ipvr_debug.h"
> +#include <drmP.h>
> +#include <linux/dma-buf.h>
> +
> +static inline bool cpu_cache_is_coherent(enum ipvr_cache_level level)
> +{
> +	/* on valleyview no cache snooping */
> +	return (level != IPVR_CACHE_WRITEBACK);
> +}
> +
> +static inline bool clflush_object(struct drm_ipvr_gem_object *obj, bool
> force)
> +{
> +	if (obj->sg_table == NULL)
> +		return false;
> +
> +	/* no need to flush if cache is coherent */
> +	if (!force && cpu_cache_is_coherent(obj->cache_level))
> +		return false;
> +
> +	drm_clflush_sg(obj->sg_table);
> +
> +	return true;
> +}
> +
> +static void
> +ipvr_object_free(struct drm_ipvr_gem_object *obj)
> +{
> +	struct drm_ipvr_private *dev_priv = obj->base.dev->dev_private;
> +	kmem_cache_free(dev_priv->ipvr_bo_slab, obj);
> +}
> +
> +static struct drm_ipvr_gem_object *
> +ipvr_object_alloc(struct drm_ipvr_private *dev_priv, size_t size)
> +{
> +	struct drm_ipvr_gem_object *obj;
> +
> +	obj = kmem_cache_alloc(dev_priv->ipvr_bo_slab, GFP_KERNEL |
> __GFP_ZERO);
> +	if (obj == NULL)
> +		return NULL;
> +	memset(obj, 0, sizeof(*obj));
> +
> +	return obj;
> +}
> +
> +static int ipvr_gem_mmu_bind_object(struct drm_ipvr_gem_object *obj)
> +{
> +	struct drm_ipvr_private *dev_priv = obj->base.dev->dev_private;
> +	const unsigned long entry = ipvr_gem_object_mmu_offset(obj);
> +
> +	if (IPVR_IS_ERR(entry)) {
> +		return IPVR_OFFSET_ERR(entry);
> +	}
> +
> +	IPVR_DEBUG_GENERAL("entry is 0x%lx, size is %zu, nents is %d.\n",
> +			entry, obj->base.size, obj->sg_table->nents);
> +
> +	return ipvr_mmu_insert_pages(dev_priv->mmu->default_pd,
> +		obj->pages, entry, obj->base.size >> PAGE_SHIFT,
> +		0, 0, 0);
> +}
> +
> +static void ipvr_gem_mmu_unbind_object(struct drm_ipvr_gem_object
> *obj)
> +{
> +	struct drm_ipvr_private *dev_priv = obj->base.dev->dev_private;
> +	const unsigned long entry = ipvr_gem_object_mmu_offset(obj);
> +	IPVR_DEBUG_GENERAL("entry is 0x%lx, size is %zu.\n",
> +			entry, obj->base.size);
> +	ipvr_mmu_remove_pages(dev_priv->mmu->default_pd,
> +		entry, obj->base.size >> PAGE_SHIFT, 0, 0);
> +}
> +
> +static void ipvr_gem_object_pin_pages(struct drm_ipvr_gem_object *obj)
> +{
> +	BUG_ON(obj->sg_table == NULL);
> +	obj->pages_pin_count++;
> +}
> +
> +static void ipvr_gem_object_unpin_pages(struct drm_ipvr_gem_object
> *obj)
> +{
> +	BUG_ON(obj->pages_pin_count == 0);
> +	obj->pages_pin_count--;
> +}
> +
> +static int ipvr_gem_bind_to_drm_mm(struct drm_ipvr_gem_object* obj,
> +			struct ipvr_address_space *vm)
> +{
> +	int ret = 0;
> +	struct drm_mm *mm;
> +	unsigned long start, end;
> +	/* bind to VPU address space */
> +	if (obj->tiling) {
> +		mm = &vm->tiling_mm;
> +		start = vm->tiling_start;
> +		end = vm->tiling_start + vm->tiling_total;
> +	} else {
> +		mm = &vm->linear_mm;
> +		start = vm->linear_start;
> +		end = vm->linear_start + vm->linear_total;
> +	}
> +	IPVR_DEBUG_GENERAL("call
> drm_mm_insert_node_in_range_generic.\n");
> +	ret = mutex_lock_interruptible(&obj->base.dev->struct_mutex);
> +	if (ret)
> +		return ret;
> +	ret = drm_mm_insert_node_in_range_generic(mm, &obj-
> >mm_node, obj->base.size,
> +						PAGE_SIZE, obj->cache_level,
> +						start, end,
> +
> 	DRM_MM_SEARCH_DEFAULT,
> +
> 	DRM_MM_CREATE_DEFAULT);
> +	if (ret) {
> +		/* no shrinker implemented yet so simply return error */
> +		IPVR_ERROR("failed on
> drm_mm_insert_node_in_range_generic: %d\n", ret);
> +		goto out;
> +	}
> +
> +	IPVR_DEBUG_GENERAL("drm_mm_insert_node_in_range_generic
> success: "
> +		"start=0x%lx, size=%lu, color=%lu.\n",
> +		obj->mm_node.start, obj->mm_node.size, obj-
> >mm_node.color);
> +
> +out:
> +	mutex_unlock(&obj->base.dev->struct_mutex);
> +
> +	return ret;
> +}
> +
> +struct drm_ipvr_gem_object* ipvr_gem_create(struct drm_ipvr_private
> *dev_priv,
> +			size_t size, u32 tiling, u32 cache_level)
> +{
> +	struct drm_ipvr_gem_object *obj;
> +	int ret = 0;
> +	int npages;
> +	struct address_space *mapping;
> +	gfp_t mask;
> +
> +	BUG_ON(size & (PAGE_SIZE - 1));
> +	npages = size >> PAGE_SHIFT;
> +	IPVR_DEBUG_GENERAL("create bo size is %zu, tiling is %u, "
> +			"cache level is %u.\n",	size, tiling, cache_level);
> +
> +	/* Allocate the new object */
> +	obj = ipvr_object_alloc(dev_priv, size);
> +	if (!obj)
> +		return ERR_PTR(-ENOMEM);
> +
> +	/* initialization */
> +	ret = drm_gem_object_init(dev_priv->dev, &obj->base, size);
> +	if (ret) {
> +		IPVR_ERROR("failed on drm_gem_object_init: %d\n", ret);
> +		goto err_free_obj;
> +	}
> +	init_waitqueue_head(&obj->event_queue);
> +	/* todo: need set correct mask */
> +	mask = GFP_HIGHUSER | __GFP_RECLAIMABLE;
> +
> +	/* ipvr cannot relocate objects above 4GiB. */
> +	mask &= ~__GFP_HIGHMEM;
> +	mask |= __GFP_DMA32;
> +
> +	mapping = file_inode(obj->base.filp)->i_mapping;
> +	mapping_set_gfp_mask(mapping, mask);
> +
> +	obj->base.write_domain = IPVR_GEM_DOMAIN_CPU;
> +	obj->base.read_domains = IPVR_GEM_DOMAIN_CPU;
> +	obj->drv_name = "ipvr";
> +	obj->fence = NULL;
> +	obj->tiling = tiling;
> +	obj->cache_level = cache_level;
> +
> +	/* get physical pages */
> +	obj->pages = drm_gem_get_pages(&obj->base);
> +	if (IS_ERR(obj->pages)) {
> +		ret = PTR_ERR(obj->pages);
> +		IPVR_ERROR("failed on drm_gem_get_pages: %d\n", ret);
> +		goto err_free_obj;
> +	}
> +
> +	obj->sg_table = drm_prime_pages_to_sg(obj->pages, obj-
> >base.size >> PAGE_SHIFT);
> +	if (IS_ERR(obj->sg_table)) {
> +		ret = PTR_ERR(obj->sg_table);
> +		IPVR_ERROR("failed on drm_gem_get_pages: %d\n", ret);
> +		goto err_put_pages;
> +	}
> +
> +	/* set cacheability */
> +	switch (obj->cache_level) {
> +	case IPVR_CACHE_UNCACHED:
> +		ret = set_pages_array_uc(obj->pages, npages);
> +		break;
> +	case IPVR_CACHE_WRITECOMBINE:
> +		ret = set_pages_array_wc(obj->pages, npages);
> +		break;
> +	case IPVR_CACHE_WRITEBACK:
> +		ret = set_pages_array_wb(obj->pages, npages);
> +		break;
> +	default:
> +		ret = -EINVAL;
> +		break;
> +	}
> +	if (ret) {
> +		IPVR_DEBUG_WARN("failed to set page cache: %d.\n", ret);
> +		goto err_put_sg;
> +	}
> +
> +	ipvr_gem_object_pin_pages(obj);
> +
> +	/* bind to VPU address space */
> +	ret = ipvr_gem_bind_to_drm_mm(obj, &dev_priv->addr_space);
> +	if (ret) {
> +		IPVR_ERROR("failed to call
> ipvr_gem_bind_to_drm_mm: %d.\n", ret);
> +		goto err_put_sg;
> +	}
> +
> +	ret = ipvr_gem_mmu_bind_object(obj);
> +	if (ret) {
> +		IPVR_ERROR("failed to call
> ipvr_gem_mmu_bind_object: %d.\n", ret);
> +		goto err_remove_node;
> +	}
> +
> +	ipvr_stat_add_object(dev_priv, obj);
> +	trace_ipvr_create_object(obj, ipvr_gem_object_mmu_offset(obj));
> +	return obj;
> +err_remove_node:
> +	drm_mm_remove_node(&obj->mm_node);
> +err_put_sg:
> +	sg_free_table(obj->sg_table);
> +	kfree(obj->sg_table);
> +err_put_pages:
> +	drm_gem_put_pages(&obj->base, obj->pages, false, false);
> +err_free_obj:
> +	ipvr_object_free(obj);
> +	return ERR_PTR(ret);
> +}
> +
> +void *ipvr_gem_object_vmap(struct drm_ipvr_gem_object *obj)
> +{
> +	pgprot_t pg = PAGE_KERNEL;
> +	switch (obj->cache_level) {
> +	case IPVR_CACHE_WRITECOMBINE:
> +		pg = pgprot_writecombine(pg);
> +		break;
> +	case IPVR_CACHE_UNCACHED:
> +		pg = pgprot_noncached(pg);
> +		break;
> +	default:
> +		break;
> +	}
> +	return vmap(obj->pages, obj->base.size >> PAGE_SHIFT, VM_MAP,
> pg);
> +}
> +
> +/*
> + * When the last reference to a GEM object is released the GEM core calls
> the
> + * drm_driver .gem_free_object() operation. That operation is mandatory
> for
> + * GEM-enabled drivers and must free the GEM object and all associated
> + * resources.
> + * called with struct_mutex locked.
> + */
> +void ipvr_gem_free_object(struct drm_gem_object *gem_obj)
> +{
> +	struct drm_device *dev = gem_obj->dev;
> +	struct drm_ipvr_gem_object *obj = to_ipvr_bo(gem_obj);
> +	drm_ipvr_private_t *dev_priv = dev->dev_private;
> +	int ret;
> +	unsigned long mmu_offset;
> +	int npages = gem_obj->size >> PAGE_SHIFT;
> +
> +	/* fixme: consider unlocked case */
> +	WARN_ON(!mutex_is_locked(&dev->struct_mutex));
> +
> +	mmu_offset = ipvr_gem_object_mmu_offset(obj);
> +	ipvr_gem_mmu_unbind_object(obj);
> +
> +	if (unlikely(obj->fence)) {
> +		ret = ipvr_fence_wait(obj->fence, true, false);
> +		if (ret)
> +			IPVR_DEBUG_WARN("Failed to wait fence
> signaled: %d.\n", ret);
> +	}
> +
> +	drm_mm_remove_node(&obj->mm_node);
> +	ipvr_gem_object_unpin_pages(obj);
> +
> +	if (WARN_ON(obj->pages_pin_count))
> +		obj->pages_pin_count = 0;
> +
> +	BUG_ON(!obj->pages || !obj->sg_table);
> +	/* set back to page_wb */
> +	set_pages_array_wb(obj->pages, npages);
> +	if (obj->base.import_attach) {
> +		IPVR_DEBUG_GENERAL("free imported object (mmu_offset
> 0x%lx)\n", mmu_offset);
> +		drm_prime_gem_destroy(&obj->base, obj->sg_table);
> +		drm_free_large(obj->pages);
> +		ipvr_stat_remove_imported(dev_priv, obj);
> +	}
> +	else {
> +		IPVR_DEBUG_GENERAL("free object (mmu_offset 0x%lx)\n",
> mmu_offset);
> +		sg_free_table(obj->sg_table);
> +		kfree(obj->sg_table);
> +		drm_gem_put_pages(&obj->base, obj->pages, obj->dirty,
> true);
> +		ipvr_stat_remove_object(dev_priv, obj);
> +	}
> +
> +	/* mmap offset is freed by drm_gem_object_release */
> +	drm_gem_object_release(&obj->base);
> +
> +	trace_ipvr_free_object(obj);
> +
> +	ipvr_object_free(obj);
> +}
> +
> +static inline struct page *get_object_page(struct drm_ipvr_gem_object
> *obj, int n)
> +{
> +	struct sg_page_iter sg_iter;
> +
> +	for_each_sg_page(obj->sg_table->sgl, &sg_iter, obj->sg_table-
> >nents, n)
> +		return sg_page_iter_page(&sg_iter);
> +
> +	return NULL;
> +}
> +
> +int ipvr_gem_object_apply_reloc(struct drm_ipvr_gem_object *obj,
> +				u64 offset_in_bo, u32 value)
> +{
> +	u64 page_offset = offset_in_page(offset_in_bo);
> +	char *vaddr;
> +	struct page *target_page;
> +
> +	/* set to cpu domain */
> +	target_page = get_object_page(obj,	offset_in_bo >>
> PAGE_SHIFT);
> +	if (!target_page)
> +		return -EINVAL;
> +
> +	/**
> +	 * for efficiency we'd better record the page index,
> +	 * and avoid frequent map/unmap on the same page
> +	 */
> +	vaddr = kmap_atomic(target_page);
> +	if (!vaddr)
> +		return -ENOMEM;
> +	*(u32 *)(vaddr + page_offset) = value;
> +
> +	kunmap_atomic(vaddr);
> +
> +	return 0;
> +}
> +
> +int ipvr_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
> +{
> +	struct drm_gem_object *obj = vma->vm_private_data;
> +	struct drm_device *dev = obj->dev;
> +	unsigned long pfn;
> +	pgoff_t pgoff;
> +	int ret;
> +	struct drm_ipvr_gem_object *ipvr_obj = to_ipvr_bo(obj);
> +
> +	/* Make sure we don't parallel update on a fault, nor move or
> remove
> +	 * something from beneath our feet
> +	 */
> +	ret = mutex_lock_interruptible(&dev->struct_mutex);
> +	if (ret)
> +		goto out;
> +
> +	if (!ipvr_obj->sg_table) {
> +		ret = -ENODATA;
> +		goto out_unlock;
> +	}
> +
> +	/* We don't use vmf->pgoff since that has the fake offset: */
> +	pgoff = ((unsigned long)vmf->virtual_address -
> +			vma->vm_start) >> PAGE_SHIFT;
> +
> +	pfn = page_to_pfn(ipvr_obj->pages[pgoff]);
> +
> +	IPVR_DEBUG_GENERAL("Inserting %p pfn %lx, pa %lx\n", vmf-
> >virtual_address,
> +			pfn, pfn << PAGE_SHIFT);
> +
> +	ret = vm_insert_pfn(vma, (unsigned long)vmf->virtual_address, pfn);
> +
> +out_unlock:
> +	mutex_unlock(&dev->struct_mutex);
> +out:
> +	switch (ret) {
> +	case -EAGAIN:
> +	case 0:
> +	case -ERESTARTSYS:
> +	case -EINTR:
> +	case -EBUSY:
> +		/*
> +		 * EBUSY is ok: this just means that another thread
> +		 * already did the job.
> +		 */
> +		return VM_FAULT_NOPAGE;
> +	case -ENOMEM:
> +		return VM_FAULT_OOM;
> +	default:
> +		return VM_FAULT_SIGBUS;
> +	}
> +}
> +
> +struct sg_table *ipvr_gem_prime_get_sg_table(struct drm_gem_object
> *obj)
> +{
> +	struct drm_ipvr_gem_object *ipvr_obj = to_ipvr_bo(obj);
> +	struct sg_table *sgt = NULL;
> +	int ret;
> +
> +	if (!ipvr_obj->sg_table) {
> +		ret = -ENOENT;
> +		goto out;
> +	}
> +
> +	sgt = drm_prime_pages_to_sg(ipvr_obj->pages, obj->size >>
> PAGE_SHIFT);
> +	if (IS_ERR(sgt)) {
> +		goto out;
> +	}
> +
> +	IPVR_DEBUG_GENERAL("exported sg_table for obj (mmu_offset
> 0x%lx)\n",
> +		ipvr_gem_object_mmu_offset(ipvr_obj));
> +out:
> +	return sgt;
> +}
> +
> +struct drm_gem_object *ipvr_gem_prime_import_sg_table(struct
> drm_device *dev,
> +		struct dma_buf_attachment *attach, struct sg_table *sg)
> +{
> +	struct drm_ipvr_gem_object *obj;
> +	int ret = 0;
> +	int i, npages;
> +	unsigned long pfn;
> +	struct drm_ipvr_private *dev_priv = dev->dev_private;
> +
> +	if (!sg || !attach || (attach->dmabuf->size & (PAGE_SIZE - 1)))
> +		return ERR_PTR(-EINVAL);
> +
> +	IPVR_DEBUG_ENTRY("enter, size=0x%zx\n", attach->dmabuf->size);
> +
> +	obj = ipvr_object_alloc(dev_priv, attach->dmabuf->size);
> +	if (!obj)
> +		return ERR_PTR(-ENOMEM);
> +
> +	memset(obj, 0, sizeof(*obj));
> +
> +	drm_gem_private_object_init(dev, &obj->base, attach->dmabuf-
> >size);
> +
> +	init_waitqueue_head(&obj->event_queue);
> +
> +	obj->drv_name = "ipvr";
> +	obj->fence = NULL;
> +	obj->cache_level = IPVR_CACHE_UNCACHED;
> +	obj->tiling = 0;
> +
> +	npages = attach->dmabuf->size >> PAGE_SHIFT;
> +
> +	obj->sg_table = sg;
> +	obj->pages = drm_malloc_ab(npages, sizeof(struct page *));
> +	if (!obj->pages) {
> +		ret = -ENOMEM;
> +		goto err_free_obj;
> +	}
> +
> +	ret = drm_prime_sg_to_page_addr_arrays(sg, obj->pages, NULL,
> npages);
> +	if (ret)
> +		goto err_put_pages;
> +
> +	/* validate sg_table
> +	 * should be under 4GiB
> +	 */
> +	for (i = 0; i < npages; ++i) {
> +		pfn = page_to_pfn(obj->pages[i]);
> +		if (pfn >= 0x00100000UL) {
> +			IPVR_ERROR("cannot support pfn 0x%lx.\n", pfn);
> +			ret = -EINVAL; /* what's the better err code? */
> +			goto err_put_pages;
> +		}
> +	}
> +
> +	ret = ipvr_gem_bind_to_drm_mm(obj, &dev_priv->addr_space);
> +	if (ret) {
> +		IPVR_ERROR("failed to call
> ipvr_gem_bind_to_drm_mm: %d.\n", ret);
> +		goto err_put_pages;
> +	}
> +
> +	/* do we really have to set the external pages uncached?
> +	 * this might causes perf issue in exporter side */
> +	ret = set_pages_array_uc(obj->pages, npages);
> +	if (ret)
> +		IPVR_DEBUG_WARN("failed to set imported pages as
> uncached: %d, ignore\n", ret);
> +
> +	ret = ipvr_gem_mmu_bind_object(obj);
> +	if (ret) {
> +		IPVR_ERROR("failed to call
> ipvr_gem_mmu_bind_object: %d.\n", ret);
> +		goto err_remove_node;
> +	}
> +	IPVR_DEBUG_GENERAL("imported sg_table, new bo mmu
> offset=0x%lx.\n",
> +		ipvr_gem_object_mmu_offset(obj));
> +	ipvr_stat_add_imported(dev_priv, obj);
> +	ipvr_gem_object_pin_pages(obj);
> +	return &obj->base;
> +err_remove_node:
> +	drm_mm_remove_node(&obj->mm_node);
> +err_put_pages:
> +	drm_free_large(obj->pages);
> +err_free_obj:
> +	ipvr_object_free(obj);
> +	return ERR_PTR(ret);
> +}
> +
> +int ipvr_gem_prime_pin(struct drm_gem_object *obj)
> +{
> +	struct drm_ipvr_private *dev_priv = obj->dev->dev_private;
> +	IPVR_DEBUG_ENTRY("mmu offset 0x%lx\n",
> ipvr_gem_object_mmu_offset(to_ipvr_bo(obj)));
> +	ipvr_stat_add_exported(dev_priv, to_ipvr_bo(obj));
> +	return 0;
> +}
> +
> +void ipvr_gem_prime_unpin(struct drm_gem_object *obj)
> +{
> +	struct drm_ipvr_private *dev_priv = obj->dev->dev_private;
> +	IPVR_DEBUG_ENTRY("mmu offset 0x%lx\n",
> ipvr_gem_object_mmu_offset(to_ipvr_bo(obj)));
> +	ipvr_stat_remove_exported(dev_priv, to_ipvr_bo(obj));
> +}
> diff --git a/drivers/gpu/drm/ipvr/ipvr_bo.h
> b/drivers/gpu/drm/ipvr/ipvr_bo.h
> new file mode 100644
> index 0000000..4981587
> --- /dev/null
> +++ b/drivers/gpu/drm/ipvr/ipvr_bo.h
> @@ -0,0 +1,80 @@
> +/*********************************************************
> *****************
> + * ipvr_bo.h: IPVR buffer creation/destory, import/export, map etc
> + *
> + * Copyright (c) 2014 Intel Corporation, Hillsboro, OR, USA
> + * All Rights Reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of
> MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
> License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along
> with
> + * this program; if not, write to the Free Software Foundation, Inc.,
> + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
> + *
> + * Authors:
> + *    Yao Cheng <yao.cheng at intel.com>
> + *
> +
> **********************************************************
> ****************/
> +
> +
> +#ifndef _IPVR_BO_H_
> +#define _IPVR_BO_H_
> +
> +#include "ipvr_drv.h"
> +#include "ipvr_drm.h"
> +#include "ipvr_fence.h"
> +#include <drmP.h>
> +#include <drm_gem.h>
> +
> +struct ipvr_fence;
> +
> +struct drm_ipvr_gem_object {
> +	struct drm_gem_object base;
> +
> +	/* used to disinguish between i915 and ipvr */
> +	char *drv_name;
> +
> +	/** MM related */
> +	struct drm_mm_node mm_node;
> +
> +	bool tiling;
> +
> +	enum ipvr_cache_level cache_level;
> +
> +	bool dirty;
> +
> +	struct sg_table *sg_table;
> +	struct page **pages;
> +	int pages_pin_count;
> +
> +	struct ipvr_fence *fence;
> +	atomic_t reserved;
> +	wait_queue_head_t event_queue;
> +};
> +
> +struct drm_ipvr_gem_object* ipvr_gem_create(struct drm_ipvr_private
> *dev_priv,
> +			size_t size, u32 tiling, u32 cache_level);
> +void ipvr_gem_free_object(struct drm_gem_object *obj);
> +void *ipvr_gem_object_vmap(struct drm_ipvr_gem_object *obj);
> +int ipvr_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
> +int ipvr_gem_object_apply_reloc(struct drm_ipvr_gem_object *obj,
> +			u64 offset_in_bo, u32 value);
> +struct sg_table *ipvr_gem_prime_get_sg_table(struct drm_gem_object
> *obj);
> +struct drm_gem_object *ipvr_gem_prime_import_sg_table(struct
> drm_device *dev,
> +			struct dma_buf_attachment *attach, struct sg_table
> *sg);
> +int ipvr_gem_prime_pin(struct drm_gem_object *obj);
> +void ipvr_gem_prime_unpin(struct drm_gem_object *obj);
> +
> +static inline unsigned long
> +ipvr_gem_object_mmu_offset(struct drm_ipvr_gem_object *obj)
> +{
> +	return obj->mm_node.start;
> +}
> +
> +#endif
> diff --git a/drivers/gpu/drm/ipvr/ipvr_debug.c
> b/drivers/gpu/drm/ipvr/ipvr_debug.c
> new file mode 100644
> index 0000000..c30a78a
> --- /dev/null
> +++ b/drivers/gpu/drm/ipvr/ipvr_debug.c
> @@ -0,0 +1,335 @@
> +/*********************************************************
> *****************
> + * ipvr_debug.c: IPVR debugfs support to assist bug triage
> + *
> + * Copyright (c) 2014 Intel Corporation, Hillsboro, OR, USA
> + * All Rights Reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of
> MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
> License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along
> with
> + * this program; if not, write to the Free Software Foundation, Inc.,
> + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
> + *
> + * Authors:
> + *    Fei Jiang <fei.jiang at intel.com>
> + *    Yao Cheng <yao.cheng at intel.com>
> + *
> +
> **********************************************************
> ****************/
> +
> +#if defined(CONFIG_DEBUG_FS)
> +
> +#include "ipvr_debug.h"
> +#include "ipvr_drv.h"
> +#include "ved_reg.h"
> +#include <linux/seq_file.h>
> +#include <linux/debugfs.h>
> +
> +union ipvr_debugfs_vars debugfs_vars;
> +
> +static int ipvr_debug_info(struct seq_file *m, void *data)
> +{
> +	seq_printf(m, "ipvr platform\n");
> +	return 0;
> +}
> +
> +/* some bookkeeping */
> +void
> +ipvr_stat_add_object(struct drm_ipvr_private *dev_priv, struct
> drm_ipvr_gem_object *obj)
> +{
> +	spin_lock(&dev_priv->ipvr_stat.object_stat_lock);
> +	dev_priv->ipvr_stat.allocated_count++;
> +	dev_priv->ipvr_stat.allocated_memory += obj->base.size;
> +	spin_unlock(&dev_priv->ipvr_stat.object_stat_lock);
> +}
> +
> +void
> +ipvr_stat_remove_object(struct drm_ipvr_private *dev_priv, struct
> drm_ipvr_gem_object *obj)
> +{
> +	spin_lock(&dev_priv->ipvr_stat.object_stat_lock);
> +	dev_priv->ipvr_stat.allocated_count--;
> +	dev_priv->ipvr_stat.allocated_memory -= obj->base.size;
> +	spin_unlock(&dev_priv->ipvr_stat.object_stat_lock);
> +}
> +
> +void
> +ipvr_stat_add_imported(struct drm_ipvr_private *dev_priv, struct
> drm_ipvr_gem_object *obj)
> +{
> +	spin_lock(&dev_priv->ipvr_stat.object_stat_lock);
> +	dev_priv->ipvr_stat.imported_count++;
> +	dev_priv->ipvr_stat.imported_memory += obj->base.size;
> +	spin_unlock(&dev_priv->ipvr_stat.object_stat_lock);
> +}
> +
> +void
> +ipvr_stat_remove_imported(struct drm_ipvr_private *dev_priv, struct
> drm_ipvr_gem_object *obj)
> +{
> +	spin_lock(&dev_priv->ipvr_stat.object_stat_lock);
> +	dev_priv->ipvr_stat.imported_count--;
> +	dev_priv->ipvr_stat.imported_memory -= obj->base.size;
> +	spin_unlock(&dev_priv->ipvr_stat.object_stat_lock);
> +}
> +
> +void
> +ipvr_stat_add_exported(struct drm_ipvr_private *dev_priv, struct
> drm_ipvr_gem_object *obj)
> +{
> +	spin_lock(&dev_priv->ipvr_stat.object_stat_lock);
> +	dev_priv->ipvr_stat.exported_count++;
> +	dev_priv->ipvr_stat.exported_memory += obj->base.size;
> +	spin_unlock(&dev_priv->ipvr_stat.object_stat_lock);
> +}
> +
> +void
> +ipvr_stat_remove_exported(struct drm_ipvr_private *dev_priv, struct
> drm_ipvr_gem_object *obj)
> +{
> +	spin_lock(&dev_priv->ipvr_stat.object_stat_lock);
> +	dev_priv->ipvr_stat.exported_count--;
> +	dev_priv->ipvr_stat.exported_memory -= obj->base.size;
> +	spin_unlock(&dev_priv->ipvr_stat.object_stat_lock);
> +}
> +
> +void ipvr_stat_add_mmu_bind(struct drm_ipvr_private *dev_priv, size_t
> size)
> +{
> +	spin_lock(&dev_priv->ipvr_stat.object_stat_lock);
> +	dev_priv->ipvr_stat.mmu_used_size += size;
> +	spin_unlock(&dev_priv->ipvr_stat.object_stat_lock);
> +}
> +
> +void ipvr_stat_remove_mmu_bind(struct drm_ipvr_private *dev_priv,
> size_t size)
> +{
> +	spin_lock(&dev_priv->ipvr_stat.object_stat_lock);
> +	dev_priv->ipvr_stat.mmu_used_size -= size;
> +	spin_unlock(&dev_priv->ipvr_stat.object_stat_lock);
> +}
> +
> +static int ipvr_debug_gem_object_info(struct seq_file *m, void* data)
> +{
> +	struct drm_info_node *node = (struct drm_info_node *) m->private;
> +	struct drm_device *dev = node->minor->dev;
> +	struct drm_ipvr_private *dev_priv = dev->dev_private;
> +	int ret;
> +
> +	ret = mutex_lock_interruptible(&dev->struct_mutex);
> +	if (ret)
> +		return ret;
> +
> +	seq_printf(m, "total allocate %u objects, %zu bytes\n\n",
> +		   dev_priv->ipvr_stat.allocated_count,
> +		   dev_priv->ipvr_stat.allocated_memory);
> +	seq_printf(m, "total imported %u objects, %zu bytes\n\n",
> +		   dev_priv->ipvr_stat.imported_count,
> +		   dev_priv->ipvr_stat.imported_memory);
> +	seq_printf(m, "total exported %u objects, %zu bytes\n\n",
> +		   dev_priv->ipvr_stat.exported_count,
> +		   dev_priv->ipvr_stat.exported_memory);
> +	seq_printf(m, "total used MMU size %zu bytes\n\n",
> +		   dev_priv->ipvr_stat.mmu_used_size);
> +
> +	mutex_unlock(&dev->struct_mutex);
> +
> +	return 0;
> +}
> +
> +static int ipvr_debug_gem_seqno_info(struct seq_file *m, void *data)
> +{
> +	struct drm_info_node *node = (struct drm_info_node *) m->private;
> +	struct drm_device *dev = node->minor->dev;
> +	drm_ipvr_private_t *dev_priv = dev->dev_private;
> +	int ret;
> +
> +	ret = mutex_lock_interruptible(&dev->struct_mutex);
> +	if (ret)
> +		return ret;
> +
> +	seq_printf(m, "last signaled seq is %d, last emitted seq is %d\n",
> +		atomic_read(&dev_priv->fence_drv.signaled_seq),
> +		dev_priv->fence_drv.sync_seq);
> +
> +	mutex_unlock(&dev->struct_mutex);
> +
> +	return 0;
> +}
> +
> +static ssize_t ipvr_debug_ved_reg_read(struct file *filp, char __user *ubuf,
> +					size_t max, loff_t *ppos)
> +{
> +	struct drm_device *dev = filp->private_data;
> +	drm_ipvr_private_t *dev_priv = dev->dev_private;
> +	char buf[200], offset[20], operation[10], format[20], val[20];
> +	int len = 0, ret, no_of_tokens;
> +	unsigned long reg_offset, reg_to_write;
> +
> +	if (debugfs_vars.reg.reg_input == 0)
> +		return len;
> +
> +	snprintf(format, sizeof(format), "%%%zus %%%zus %%%zus",
> +			sizeof(operation), sizeof(offset), sizeof(val));
> +
> +	no_of_tokens = sscanf(debugfs_vars.reg.reg_vars,
> +					format, operation, offset, val);
> +
> +	if (no_of_tokens < 3)
> +		return len;
> +
> +	len = sizeof(debugfs_vars.reg.reg_vars);
> +
> +	if (strcmp(operation, IPVR_READ_TOKEN) == 0) {
> +		ret = kstrtoul(offset, 16, &reg_offset);
> +		if (ret)
> +			return -EINVAL;
> +
> +		len = scnprintf(buf, sizeof(buf), "0x%x: 0x%x\n",
> +			(u32)reg_offset,
> +			IPVR_REG_READ32((u32)reg_offset));
> +	} else if (strcmp(operation, IPVR_WRITE_TOKEN) == 0) {
> +		ret = kstrtoul(offset, 16, &reg_offset);
> +		if (ret)
> +			return -EINVAL;
> +
> +		ret = kstrtoul(val, 16, &reg_to_write);
> +		if (ret)
> +			return -EINVAL;
> +
> +		IPVR_REG_WRITE32(reg_offset, reg_to_write);
> +		len = scnprintf(buf, sizeof(buf),
> +				"0x%x: 0x%x\n",
> +				(u32)reg_offset,
> +				(u32)IPVR_REG_READ32(reg_offset));
> +	} else {
> +		len = scnprintf(buf, sizeof(buf), "Operation Not
> Supported\n");
> +	}
> +
> +	debugfs_vars.reg.reg_input = 0;
> +
> +	simple_read_from_buffer(ubuf, max, ppos, buf, len);
> +
> +	return len;
> +}
> +
> +static ssize_t
> +ipvr_debug_ved_reg_write(struct file *filp,const char __user *ubuf,
> +			size_t cnt, loff_t *ppos)
> +{
> +	/* reset the string */
> +	memset(debugfs_vars.reg.reg_vars, 0,
> IPVR_MAX_BUFFER_STR_LEN);
> +
> +	if (cnt > 0) {
> +		if (cnt > sizeof(debugfs_vars.reg.reg_vars) - 1)
> +			return -EINVAL;
> +
> +		if (copy_from_user(debugfs_vars.reg.reg_vars, ubuf, cnt))
> +			return -EFAULT;
> +
> +		debugfs_vars.reg.reg_vars[cnt] = 0;
> +
> +		/* Enable Read */
> +		debugfs_vars.reg.reg_input = 1;
> +	}
> +
> +	return cnt;
> +}
> +
> +/* As the drm_debugfs_init() routines are called before dev->dev_private
> is
> + * allocated we need to hook into the minor for release. */
> +static int ipvr_add_fake_info_node(struct drm_minor *minor,
> +					struct dentry *ent, const void *key)
> +{
> +	struct drm_info_node *node;
> +
> +	node = kmalloc(sizeof(struct drm_info_node), GFP_KERNEL);
> +	if (node == NULL) {
> +		debugfs_remove(ent);
> +		return -ENOMEM;
> +	}
> +
> +	node->minor = minor;
> +	node->dent = ent;
> +	node->info_ent = (void *) key;
> +
> +	mutex_lock(&minor->debugfs_lock);
> +	list_add(&node->list, &minor->debugfs_list);
> +	mutex_unlock(&minor->debugfs_lock);
> +
> +	return 0;
> +}
> +
> +static int ipvr_debugfs_create(struct dentry *root,
> +			       struct drm_minor *minor,
> +			       const char *name,
> +			       const struct file_operations *fops)
> +{
> +	struct drm_device *dev = minor->dev;
> +	struct dentry *ent;
> +
> +	ent = debugfs_create_file(name,
> +				  S_IRUGO | S_IWUSR,
> +				  root, dev,
> +				  fops);
> +	if (IS_ERR(ent))
> +		return PTR_ERR(ent);
> +
> +	return ipvr_add_fake_info_node(minor, ent, fops);
> +}
> +
> +static const struct file_operations ipvr_ved_reg_fops = {
> +	.owner = THIS_MODULE,
> +	.open = simple_open,
> +	.read = ipvr_debug_ved_reg_read,
> +	.write = ipvr_debug_ved_reg_write,
> +	.llseek = default_llseek,
> +};
> +
> +static struct drm_info_list ipvr_debugfs_list[] = {
> +	{"ipvr_capabilities", ipvr_debug_info, 0},
> +	{"ipvr_gem_objects", ipvr_debug_gem_object_info, 0},
> +	{"ipvr_gem_seqno", ipvr_debug_gem_seqno_info, 0},
> +
> +};
> +#define IPVR_DEBUGFS_ENTRIES ARRAY_SIZE(ipvr_debugfs_list)
> +
> +static struct ipvr_debugfs_files {
> +	const char *name;
> +	const struct file_operations *fops;
> +} ipvr_debugfs_files[] = {
> +	{"ipvr_ved_reg_api", &ipvr_ved_reg_fops},
> +};
> +
> +int ipvr_debugfs_init(struct drm_minor *minor)
> +{
> +	int ret, i;
> +
> +	for (i = 0; i < ARRAY_SIZE(ipvr_debugfs_files); i++) {
> +		ret = ipvr_debugfs_create(minor->debugfs_root, minor,
> +				   ipvr_debugfs_files[i].name,
> +				   ipvr_debugfs_files[i].fops);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return drm_debugfs_create_files(ipvr_debugfs_list,
> +				 IPVR_DEBUGFS_ENTRIES,
> +				 minor->debugfs_root, minor);
> +}
> +
> +void ipvr_debugfs_cleanup(struct drm_minor *minor)
> +{
> +	int i;
> +
> +	drm_debugfs_remove_files(ipvr_debugfs_list,
> +			  IPVR_DEBUGFS_ENTRIES, minor);
> +
> +	for (i = 0; i < ARRAY_SIZE(ipvr_debugfs_files); i++) {
> +		struct drm_info_list *info_list =
> +			(struct drm_info_list *)ipvr_debugfs_files[i].fops;
> +
> +		drm_debugfs_remove_files(info_list, 1, minor);
> +	}
> +}
> +
> +#endif /* CONFIG_DEBUG_FS */
> diff --git a/drivers/gpu/drm/ipvr/ipvr_debug.h
> b/drivers/gpu/drm/ipvr/ipvr_debug.h
> new file mode 100644
> index 0000000..a88382e
> --- /dev/null
> +++ b/drivers/gpu/drm/ipvr/ipvr_debug.h
> @@ -0,0 +1,76 @@
> +/*********************************************************
> *****************
> + * ipvr_debug.h: IPVR debugfs support header file
> + *
> + * Copyright (c) 2014 Intel Corporation, Hillsboro, OR, USA
> + * All Rights Reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of
> MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
> License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along
> with
> + * this program; if not, write to the Free Software Foundation, Inc.,
> + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
> + *
> + * Authors:
> + *    Fei Jiang <fei.jiang at intel.com>
> + *    Yao Cheng <yao.cheng at intel.com>
> + *
> +
> **********************************************************
> ****************/
> +
> +
> +#ifndef _IPVR_DEBUG_H_
> +#define _IPVR_DEBUG_H_
> +
> +#include "ipvr_bo.h"
> +#include "drmP.h"
> +
> +/* Operations supported */
> +#define IPVR_MAX_BUFFER_STR_LEN		200
> +
> +#define IPVR_READ_TOKEN			"READ"
> +#define IPVR_WRITE_TOKEN		"WRITE"
> +
> +/* DebugFS Variable declaration */
> +struct ipvr_debugfs_reg_vars {
> +	char reg_vars[IPVR_MAX_BUFFER_STR_LEN];
> +	u32 reg_input;
> +};
> +
> +union ipvr_debugfs_vars {
> +	struct ipvr_debugfs_reg_vars reg;
> +};
> +
> +int ipvr_debugfs_init(struct drm_minor *minor);
> +void ipvr_debugfs_cleanup(struct drm_minor *minor);
> +
> +void ipvr_stat_add_object(struct drm_ipvr_private *dev_priv,
> +			struct drm_ipvr_gem_object *obj);
> +
> +void ipvr_stat_remove_object(struct drm_ipvr_private *dev_priv,
> +			struct drm_ipvr_gem_object *obj);
> +
> +void ipvr_stat_add_imported(struct drm_ipvr_private *dev_priv,
> +			struct drm_ipvr_gem_object *obj);
> +
> +void ipvr_stat_remove_imported(struct drm_ipvr_private *dev_priv,
> +			struct drm_ipvr_gem_object *obj);
> +
> +void ipvr_stat_add_exported(struct drm_ipvr_private *dev_priv,
> +			struct drm_ipvr_gem_object *obj);
> +
> +void ipvr_stat_remove_exported(struct drm_ipvr_private *dev_priv,
> +			struct drm_ipvr_gem_object *obj);
> +
> +void ipvr_stat_add_mmu_bind(struct drm_ipvr_private *dev_priv,
> +			size_t size);
> +
> +void ipvr_stat_remove_mmu_bind(struct drm_ipvr_private *dev_priv,
> +			size_t size);
> +
> +#endif
> diff --git a/drivers/gpu/drm/ipvr/ipvr_drm.h
> b/drivers/gpu/drm/ipvr/ipvr_drm.h
> new file mode 100644
> index 0000000..fade9a3
> --- /dev/null
> +++ b/drivers/gpu/drm/ipvr/ipvr_drm.h
> @@ -0,0 +1,259 @@
> +/*********************************************************
> *****************
> + * ipvr_drm.h: IPVR header file exported to user space
> + *
> + * Copyright (c) 2014 Intel Corporation, Hillsboro, OR, USA
> + * All Rights Reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of
> MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
> License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along
> with
> + * this program; if not, write to the Free Software Foundation, Inc.,
> + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
> + *
> + * Authors:
> + *    Fei Jiang <fei.jiang at intel.com>
> + *    Yao Cheng <yao.cheng at intel.com>
> + *
> +
> **********************************************************
> ****************/
> +
> +
> +/* this file only define structs and macro which need export to user space
> */
> +#ifndef _IPVR_DRM_H_
> +#define _IPVR_DRM_H_
> +
> +#include <drm/drm.h>
> +struct drm_ipvr_context_create {
> +	/* passed ctx_info, including codec, profile info */
> +#define IPVR_CONTEXT_TYPE_VED   (0x1)
> +	__u32 ctx_type;
> +	/* returned back ctx_id */
> +	__u32 ctx_id;
> +	/*
> +	 * following tiling strides for VED are supported:
> +	 * stride 0: 512 for scheme 0, 1024 for scheme 1
> +	 * stride 1: 1024 for scheme 0, 2048 for scheme 1
> +	 * stride 2: 2048 for scheme 0, 4096 for scheme 1
> +	 * stride 3: 4096 for scheme 0
> +	 */
> +	__u32 tiling_stride;
> +	/*
> +	 * scheme 0: tile is 256x16, while minimal tile stride is 512
> +	 * scheme 1: tile is 512x8, while minimal tile stride is 1024
> +	 */
> +	__u32 tiling_scheme;
> +};
> +
> +struct drm_ipvr_context_destroy {
> +	__u32 ctx_id;
> +	__u32 pad64;
> +};
> +
> +/* ioctl used for querying info from driver */
> +enum drm_ipvr_misc_key {
> +	IPVR_DEVICE_INFO,
> +};
> +struct drm_ipvr_get_info {
> +	__u64 key;
> +	__u64 value;
> +};
> +
> +struct drm_ipvr_gem_relocation_entry {
> +	/**
> +	 * Handle of the buffer being pointed to by this relocation entry.
> +	 *
> +	 * It's appealing to make this be an index into the mm_validate_entry
> +	 * list to refer to the buffer, but this allows the driver to create
> +	 * a relocation list for state buffers and not re-write it per
> +	 * exec using the buffer.
> +	 */
> +	__u32 target_handle;
> +
> +	/**
> +	 * Value to be added to the offset of the target buffer to make up
> +	 * the relocation entry.
> +	 */
> +	__u32 delta;
> +
> +	/** Offset in the buffer the relocation entry will be written into */
> +	__u64 offset;
> +
> +	/**
> +	 * Offset value of the target buffer that the relocation entry was last
> +	 * written as.
> +	 *
> +	 * If the buffer has the same offset as last time, we can skip syncing
> +	 * and writing the relocation.  This value is written back out by
> +	 * the execbuffer ioctl when the relocation is written.
> +	 */
> +	__u64 presumed_offset;
> +
> +	/**
> +	 * Target memory domains read by this operation.
> +	 */
> +	__u32 read_domains;
> +
> +	/**
> +	 * Target memory domains written by this operation.
> +	 *
> +	 * Note that only one domain may be written by the whole
> +	 * execbuffer operation, so that where there are conflicts,
> +	 * the application will get -EINVAL back.
> +	 */
> +	__u32 write_domain;
> +};
> +
> +struct drm_ipvr_gem_exec_object {
> +	/**
> +	 * User's handle for a buffer to be bound into the MMU for this
> +	 * operation.
> +	 */
> +	__u32 handle;
> +
> +	/** Number of relocations to be performed on this buffer */
> +	__u32 relocation_count;
> +	/**
> +	 * Pointer to array of struct drm_i915_gem_relocation_entry
> containing
> +	 * the relocations to be performed in this buffer.
> +	 */
> +	__u64 relocs_ptr;
> +
> +	/** Required alignment in graphics aperture */
> +	__u64 alignment;
> +
> +	/**
> +	 * Returned value of the updated offset of the object, for future
> +	 * presumed_offset writes.
> +	 */
> +	__u64 offset;
> +
> +#define IPVR_EXEC_OBJECT_NEED_FENCE (1 << 0)
> +#define IPVR_EXEC_OBJECT_SUBMIT     (1 << 1)
> +	__u64 flags;
> +
> +	__u64 rsvd1;
> +	__u64 rsvd2;
> +};
> +
> +struct drm_ipvr_gem_execbuffer {
> +	/**
> +	 * List of gem_exec_object2 structs
> +	 */
> +	__u64 buffers_ptr;
> +	__u32 buffer_count;
> +
> +	/** Offset in the batchbuffer to start execution from. */
> +	__u32 exec_start_offset;
> +	/** Bytes used in batchbuffer from batch_start_offset */
> +	__u32 exec_len;
> +
> +	/**
> +	 * ID of hardware context.
> +	 */
> +	__u32 ctx_id;
> +
> +	__u64 flags;
> +	__u64 rsvd1;
> +	__u64 rsvd2;
> +};
> +
> +enum ipvr_cache_level
> +{
> +	IPVR_CACHE_UNCACHED,
> +	IPVR_CACHE_WRITEBACK,
> +	IPVR_CACHE_WRITECOMBINE,
> +	IPVR_CACHE_MAX,
> +};
> +
> +struct drm_ipvr_gem_create {
> +	/*
> +	 * Requested size for the object.
> +	 * The (page-aligned) allocated size for the object will be returned.
> +	 */
> +	__u64 size;
> +	__u64 rounded_size;
> +	__u64 mmu_offset;
> +	/*
> +	 * Returned handle for the object.
> +	 * Object handles are nonzero.
> +	 */
> +	__u32 handle;
> +	__u32 tiling;
> +
> +	__u32 cache_level;
> +	__u32 pad64;
> +	/*
> +	 * Handle used for user to mmap BO
> +	 */
> +	__u64 map_offset;
> +};
> +
> +struct drm_ipvr_gem_busy {
> +	/* Handle of the buffer to check for busy */
> +	__u32 handle;
> +
> +	/*
> +	 * Return busy status (1 if busy, 0 if idle).
> +	 * The high word is used to indicate on which rings the object
> +	 * currently resides:
> +	 *  16:31 - busy (r or r/w) rings (16 render, 17 bsd, 18 blt, etc)
> +	 */
> +	__u32 busy;
> +};
> +
> +struct drm_ipvr_gem_mmap_offset {
> +	/** Handle for the object being mapped. */
> +	__u32 handle;
> +	__u32 pad64;
> +	/**
> +	 * Fake offset to use for subsequent mmap call
> +	 *
> +	 * This is a fixed-size type for 32/64 compatibility.
> +	 */
> +	__u64 offset;
> +};
> +
> +struct drm_ipvr_gem_wait {
> +	/* Handle of BO we shall wait on */
> +	__u32 handle;
> +	__u32 flags;
> +	/** Number of nanoseconds to wait, Returns time remaining. */
> +	__s64 timeout_ns;
> +};
> +
> +/*
> + * IPVR GEM specific ioctls
> + */
> +#define DRM_IPVR_CONTEXT_CREATE     0x00
> +#define DRM_IPVR_CONTEXT_DESTROY    0x01
> +#define DRM_IPVR_GET_INFO           0x02
> +#define DRM_IPVR_GEM_EXECBUFFER     0x03
> +#define DRM_IPVR_GEM_BUSY           0x04
> +#define DRM_IPVR_GEM_CREATE         0x05
> +#define DRM_IPVR_GEM_WAIT           0x06
> +#define DRM_IPVR_GEM_MMAP_OFFSET    0x07
> +
> +#define DRM_IOCTL_IPVR_CONTEXT_CREATE	\
> +	DRM_IOWR(DRM_COMMAND_BASE +
> DRM_IPVR_CONTEXT_CREATE, struct drm_ipvr_context_create)
> +#define DRM_IOCTL_IPVR_CONTEXT_DESTROY	\
> +	DRM_IOW(DRM_COMMAND_BASE +
> DRM_IPVR_CONTEXT_DESTROY, struct drm_ipvr_context_destroy)
> +#define DRM_IOCTL_IPVR_GET_INFO		\
> +	DRM_IOWR(DRM_COMMAND_BASE + DRM_IPVR_GET_INFO, struct
> drm_ipvr_get_info)
> +#define DRM_IOCTL_IPVR_GEM_EXECBUFFER	\
> +	DRM_IOWR(DRM_COMMAND_BASE +
> DRM_IPVR_GEM_EXECBUFFER, struct drm_ipvr_gem_execbuffer)
> +#define DRM_IOCTL_IPVR_GEM_BUSY		\
> +	DRM_IOWR(DRM_COMMAND_BASE + DRM_IPVR_GEM_BUSY,
> struct drm_ipvr_gem_busy)
> +#define DRM_IOCTL_IPVR_GEM_CREATE	\
> +	DRM_IOWR(DRM_COMMAND_BASE + DRM_IPVR_GEM_CREATE,
> struct drm_ipvr_gem_create)
> +#define DRM_IOCTL_IPVR_GEM_WAIT		\
> +	DRM_IOWR(DRM_COMMAND_BASE + DRM_IPVR_GEM_WAIT,
> struct drm_ipvr_gem_wait)
> +#define DRM_IOCTL_IPVR_GEM_MMAP_OFFSET	\
> +	DRM_IOWR(DRM_COMMAND_BASE +
> DRM_IPVR_GEM_MMAP_OFFSET, struct drm_ipvr_gem_mmap_offset)
> +
> +#endif
> diff --git a/drivers/gpu/drm/ipvr/ipvr_drv.c
> b/drivers/gpu/drm/ipvr/ipvr_drv.c
> new file mode 100644
> index 0000000..29ffe39
> --- /dev/null
> +++ b/drivers/gpu/drm/ipvr/ipvr_drv.c
> @@ -0,0 +1,617 @@
> +/*********************************************************
> *****************
> + * ipvr_drv.c: IPVR driver common file for initialization/de-initialization
> + *
> + * Copyright (c) 2014 Intel Corporation, Hillsboro, OR, USA
> + * All Rights Reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of
> MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
> License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along
> with
> + * this program; if not, write to the Free Software Foundation, Inc.,
> + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
> + *
> + * Authors:
> + *    Fei Jiang <fei.jiang at intel.com>
> + *    Yao Cheng <yao.cheng at intel.com>
> + *
> +
> **********************************************************
> ****************/
> +
> +#include "ipvr_drv.h"
> +#include "ipvr_gem.h"
> +#include "ipvr_mmu.h"
> +#include "ipvr_exec.h"
> +#include "ipvr_bo.h"
> +#include "ipvr_debug.h"
> +#include "ipvr_trace.h"
> +#include "ved_fw.h"
> +#include "ved_pm.h"
> +#include "ved_reg.h"
> +#include "ved_cmd.h"
> +#include <linux/device.h>
> +#include <linux/version.h>
> +#include <uapi/drm/drm.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/console.h>
> +#include <linux/module.h>
> +#include <asm/uaccess.h>
> +
> +int drm_ipvr_debug = 0x80;
> +int drm_ipvr_freq = 320;
> +
> +module_param_named(debug, drm_ipvr_debug, int, 0600);
> +module_param_named(freq, drm_ipvr_freq, int, 0600);
> +
> +MODULE_PARM_DESC(debug,
> +		"control debug info output"
> +		"default: 0"
> +		"0x01:IPVR_D_GENERAL, 0x02:IPVR_D_INIT,
> 0x04:IPVR_D_IRQ, 0x08:IPVR_D_ENTRY"
> +		"0x10:IPVR_D_PM, 0x20:IPVR_D_REG, 0x40:IPVR_D_VED,
> 0x80:IPVR_D_WARN");
> +MODULE_PARM_DESC(freq,
> +		"prefered VED frequency"
> +		"default: 320 MHz");
> +
> +static struct drm_ioctl_desc ipvr_gem_ioctls[] = {
> +	DRM_IOCTL_DEF_DRV(IPVR_CONTEXT_CREATE,
> +			ipvr_context_create_ioctl,
> DRM_AUTH|DRM_UNLOCKED),
> +	DRM_IOCTL_DEF_DRV(IPVR_CONTEXT_DESTROY,
> +			ipvr_context_destroy_ioctl,
> DRM_AUTH|DRM_UNLOCKED),
> +	DRM_IOCTL_DEF_DRV(IPVR_GET_INFO,
> +			ipvr_get_info_ioctl, DRM_AUTH|DRM_UNLOCKED),
> +	DRM_IOCTL_DEF_DRV(IPVR_GEM_EXECBUFFER,
> +			ipvr_gem_execbuffer_ioctl,
> DRM_AUTH|DRM_UNLOCKED),
> +	DRM_IOCTL_DEF_DRV(IPVR_GEM_BUSY,
> +			ipvr_gem_busy_ioctl, DRM_AUTH|DRM_UNLOCKED),
> +	DRM_IOCTL_DEF_DRV(IPVR_GEM_CREATE,
> +			ipvr_gem_create_ioctl,
> DRM_AUTH|DRM_UNLOCKED),
> +	DRM_IOCTL_DEF_DRV(IPVR_GEM_WAIT,
> +			ipvr_gem_wait_ioctl, DRM_AUTH|DRM_UNLOCKED),
> +	DRM_IOCTL_DEF_DRV(IPVR_GEM_MMAP_OFFSET,
> +			ipvr_gem_mmap_offset_ioctl,
> DRM_AUTH|DRM_UNLOCKED),
> +};
> +
> +static void ipvr_gem_init(struct drm_device *dev)
> +{
> +	struct drm_ipvr_private *dev_priv = dev->dev_private;
> +
> +	dev_priv->ipvr_bo_slab = kmem_cache_create("ipvr_gem_object",
> +				  sizeof(struct drm_ipvr_gem_object), 0,
> +				  SLAB_HWCACHE_ALIGN, NULL);
> +
> +	spin_lock_init(&dev_priv->ipvr_stat.object_stat_lock);
> +	dev_priv->ipvr_stat.interruptible = true;
> +}
> +
> +static void ipvr_gem_setup_mmu(struct drm_device *dev,
> +				       unsigned long linear_start,
> +				       unsigned long linear_end,
> +				       unsigned long tiling_start,
> +				       unsigned long tiling_end)
> +{
> +	/* Let GEM Manage all of the aperture.
> +	 */
> +	struct drm_ipvr_private *dev_priv = dev->dev_private;
> +	struct ipvr_address_space *addr_space = &dev_priv->addr_space;
> +
> +	addr_space->dev = dev_priv->dev;
> +
> +	/* Subtract the guard page ... */
> +	drm_mm_init(&addr_space->linear_mm, linear_start,
> +		    linear_end - linear_start - PAGE_SIZE);
> +	dev_priv->addr_space.linear_start = linear_start;
> +	dev_priv->addr_space.linear_total = linear_end - linear_start;
> +
> +	drm_mm_init(&addr_space->tiling_mm, tiling_start,
> +		    tiling_end - tiling_start - PAGE_SIZE);
> +	dev_priv->addr_space.tiling_start = tiling_start;
> +	dev_priv->addr_space.tiling_total = tiling_end - tiling_start;
> +}
> +
> +int ipvr_runtime_pm_get(struct drm_ipvr_private *dev_priv)
> +{
> +	int ret = 0;
> +	int pending;
> +	unsigned long irq_flags;
> +	struct platform_device *platdev = dev_priv->dev->platformdev;
> +	BUG_ON(!platdev);
> +	BUG_ON(atomic_read(&dev_priv->pending_events) < 0);
> +	spin_lock_irqsave(&dev_priv->power_usage_lock, irq_flags);
> +	if ((pending = atomic_inc_return(&dev_priv->pending_events)) == 1)
> {
> +		do {
> +			ret = pm_runtime_get_sync(&platdev->dev);
> +			if (ret == -EAGAIN) {
> +
> 	IPVR_DEBUG_WARN("pm_runtime_get_sync returns EAGAIN\n");
> +			}
> +			else if (ret < 0) {
> +				IPVR_ERROR("pm_runtime_get_sync
> returns %d\n", ret);
> +				pending = atomic_dec_return(&dev_priv-
> >pending_events);
> +			}
> +		} while (ret == -EAGAIN);
> +	}
> +	trace_ipvr_get_power(atomic_read(&platdev-
> >dev.power.usage_count),
> +		pending);
> +	spin_unlock_irqrestore(&dev_priv->power_usage_lock, irq_flags);
> +	return ret;
> +}
> +
> +int ipvr_runtime_pm_put(struct drm_ipvr_private *dev_priv, bool async)
> +{
> +	int ret = 0;
> +	int pending;
> +	unsigned long irq_flags;
> +	struct platform_device *platdev = dev_priv->dev->platformdev;
> +	BUG_ON(!platdev);
> +	BUG_ON(atomic_read(&dev_priv->pending_events) <= 0);
> +	spin_lock_irqsave(&dev_priv->power_usage_lock, irq_flags);
> +	if ((pending = atomic_dec_return(&dev_priv->pending_events)) ==
> 0) {
> +		do {
> +			if (async)
> +				ret = pm_runtime_put(&platdev->dev);
> +			else
> +				ret = pm_runtime_put_sync(&platdev->dev);
> +			if (ret == -EAGAIN)
> +				IPVR_DEBUG_WARN("pm_runtime_put
> returns EAGAIN\n");
> +			else if (ret < 0)
> +				IPVR_ERROR("pm_runtime_put
> returns %d\n", ret);
> +		} while (ret == -EAGAIN);
> +	}
> +	trace_ipvr_put_power(atomic_read(&platdev-
> >dev.power.usage_count),
> +		pending);
> +	spin_unlock_irqrestore(&dev_priv->power_usage_lock, irq_flags);
> +	return ret;
> +}
> +
> +int ipvr_runtime_pm_put_all(struct drm_ipvr_private *dev_priv, bool
> async)
> +{
> +	int ret = 0;
> +	unsigned long irq_flags;
> +	struct platform_device *platdev = dev_priv->dev->platformdev;
> +	BUG_ON(!platdev);
> +	spin_lock_irqsave(&dev_priv->power_usage_lock, irq_flags);
> +	if (atomic_read(&dev_priv->pending_events) > 0) {
> +		atomic_set(&dev_priv->pending_events, 0);
> +		do {
> +			if (async)
> +				ret = pm_runtime_put(&platdev->dev);
> +			else
> +				ret = pm_runtime_put_sync(&platdev->dev);
> +			if (ret == -EAGAIN)
> +				IPVR_DEBUG_WARN("pm_runtime_put
> returns EAGAIN\n");
> +			else if (ret < 0)
> +				IPVR_ERROR("pm_runtime_put
> returns %d\n", ret);
> +		} while (ret == -EAGAIN);
> +	}
> +	trace_ipvr_put_power(atomic_read(&platdev-
> >dev.power.usage_count),
> +		0);
> +	spin_unlock_irqrestore(&dev_priv->power_usage_lock, irq_flags);
> +	return ret;
> +}
> +
> +static int ipvr_drm_unload(struct drm_device *dev)
> +{
> +	struct drm_ipvr_private *dev_priv = dev->dev_private;
> +	IPVR_DEBUG_ENTRY("entered.");
> +	BUG_ON(!dev->platformdev);
> +
> +	if (dev_priv) {
> +		if (dev_priv->ipvr_bo_slab)
> +			kmem_cache_destroy(dev_priv->ipvr_bo_slab);
> +		ipvr_fence_driver_fini(dev_priv);
> +
> +		if (WARN_ON(ipvr_runtime_pm_get(dev_priv) < 0))
> +			IPVR_DEBUG_WARN("Error getting ipvr power\n");
> +		else {
> +			ved_core_deinit(dev_priv);
> +			if (WARN_ON(ipvr_runtime_pm_put_all(dev_priv,
> false) < 0))
> +				IPVR_DEBUG_WARN("Error getting ipvr
> power\n");
> +		}
> +		if (dev_priv->validate_ctx.buffers)
> +			vfree(dev_priv->validate_ctx.buffers);
> +
> +		if (dev_priv->mmu) {
> +			ipvr_mmu_driver_takedown(dev_priv->mmu);
> +			dev_priv->mmu = NULL;
> +		}
> +
> +		if (dev_priv->reg_base) {
> +			iounmap(dev_priv->reg_base);
> +			dev_priv->reg_base = NULL;
> +		}
> +
> +		list_del(&dev_priv->default_ctx.head);
> +		idr_remove(&dev_priv->ipvr_ctx_idr, dev_priv-
> >default_ctx.ctx_id);
> +		kfree(dev_priv);
> +
> +	}
> +	pm_runtime_disable(&dev->platformdev->dev);
> +
> +	return 0;
> +}
> +
> +static int ipvr_drm_load(struct drm_device *dev, unsigned long flags)
> +{
> +	struct drm_ipvr_private *dev_priv;
> +	u32 ctx_id;
> +	int ret = 0;
> +	struct resource *res_mmio;
> +	void __iomem* mmio_start;
> +
> +	if (!dev->platformdev)
> +		return -ENODEV;
> +
> +	dev_priv = kzalloc(sizeof(*dev_priv), GFP_KERNEL);
> +	if (dev_priv == NULL)
> +		return -ENOMEM;
> +
> +	dev->dev_private = dev_priv;
> +	dev_priv->dev = dev;
> +
> +	INIT_LIST_HEAD(&dev_priv->validate_ctx.validate_list);
> +
> +	dev_priv->pci_root = pci_get_bus_and_slot(0, PCI_DEVFN(0, 0));
> +	if (!dev_priv->pci_root) {
> +		kfree(dev_priv);
> +		return -ENODEV;
> +	}
> +
> +	dev->irq = platform_get_irq(dev->platformdev, 0);
> +	if (dev->irq < 0) {
> +		kfree(dev_priv);
> +		return -ENODEV;
> +	}
> +
> +	res_mmio = platform_get_resource(dev->platformdev,
> IORESOURCE_MEM, 0);
> +	if (!res_mmio) {
> +		kfree(dev_priv);
> +		return -ENXIO;
> +	}
> +
> +	mmio_start = ioremap_nocache(res_mmio->start,
> +					res_mmio->end - res_mmio->start);
> +	if (!mmio_start) {
> +		kfree(dev_priv);
> +		return -EACCES;
> +	}
> +
> +	dev_priv->reg_base = mmio_start;
> +	IPVR_DEBUG_VED("reg_base is %p - 0x%p.\n",
> +		dev_priv->reg_base,
> +		dev_priv->reg_base + (res_mmio->end - res_mmio->start));
> +
> +	atomic_set(&dev_priv->pending_events, 0);
> +	spin_lock_init(&dev_priv->power_usage_lock);
> +	pm_runtime_enable(&dev->platformdev->dev);
> +	if (WARN_ON(ipvr_runtime_pm_get(dev_priv) < 0)) {
> +		IPVR_ERROR("Error getting ipvr power\n");
> +		ret = -EBUSY;
> +		goto out_err;
> +	}
> +
> +	IPVR_DEBUG_INIT("MSVDX_CORE_REV_OFFSET by readl is 0x%x.\n",
> +		readl(dev_priv->reg_base + 0x640));
> +	IPVR_DEBUG_INIT("MSVDX_CORE_REV_OFFSET by
> VED_REG_READ32 is 0x%x.\n",
> +		IPVR_REG_READ32(MSVDX_CORE_REV_OFFSET));
> +
> +	/* mmu init */
> +	dev_priv->mmu = ipvr_mmu_driver_init(NULL, 0, dev_priv);
> +	if (!dev_priv->mmu) {
> +		ret = -EBUSY;
> +		goto out_err;
> +	}
> +
> +	ipvr_mmu_set_pd_context(ipvr_mmu_get_default_pd(dev_priv-
> >mmu), 0);
> +
> +	/*
> +	 * Initialize sequence numbers for the different command
> +	 * submission mechanisms.
> +	 */
> +	dev_priv->last_seq = 1;
> +
> +	ipvr_gem_init(dev);
> +
> +	ipvr_gem_setup_mmu(dev,
> +		IPVR_MEM_MMU_LINEAR_START,
> +		IPVR_MEM_MMU_LINEAR_END,
> +		IPVR_MEM_MMU_TILING_START,
> +		IPVR_MEM_MMU_TILING_END);
> +
> +	ved_core_init(dev_priv);
> +
> +	if (WARN_ON(ipvr_runtime_pm_put(dev_priv, false) < 0))
> +		IPVR_DEBUG_WARN("Error putting ipvr power\n");
> +
> +	dev_priv->ved_private->ved_needs_reset = 1;
> +
> +	ipvr_fence_driver_init(dev_priv);
> +
> +	dev_priv->validate_ctx.buffers =
> +		vmalloc(IPVR_NUM_VALIDATE_BUFFERS *
> +			sizeof(struct ipvr_validate_buffer));
> +	if (!dev_priv->validate_ctx.buffers) {
> +		ret = -ENOMEM;
> +		goto out_err;
> +	}
> +
> +	/* ipvr context initialization */
> +	spin_lock_init(&dev_priv->ipvr_ctx_lock);
> +	idr_init(&dev_priv->ipvr_ctx_idr);
> +	/* default ipvr context is used for scaling, rotation case */
> +	ctx_id = idr_alloc(&dev_priv->ipvr_ctx_idr, &dev_priv->default_ctx,
> +			   IPVR_MIN_CONTEXT_ID, IPVR_MAX_CONTEXT_ID,
> +			   GFP_NOWAIT);
> +	if (ctx_id < 0) {
> +		return -ENOMEM;
> +		goto out_err;
> +	}
> +	dev_priv->default_ctx.ctx_id = ctx_id;
> +	INIT_LIST_HEAD(&dev_priv->default_ctx.head);
> +	dev_priv->default_ctx.ctx_type = 0;
> +	dev_priv->default_ctx.ipvr_fpriv = NULL;
> +
> +	/* don't need protect with spinlock during module load stage */
> +	dev_priv->default_ctx.tiling_scheme = 0;
> +	dev_priv->default_ctx.tiling_stride = 0;
> +
> +	return 0;
> +out_err:
> +	ipvr_drm_unload(dev);
> +	return ret;
> +}
> +
> +/*
> + * The .open() method is called every time the device is opened by an
> + * application. Drivers can allocate per-file private data in this method and
> + * store them in the struct drm_file::driver_priv field. Note that the .open()
> + * method is called before .firstopen().
> + */
> +static int
> +ipvr_drm_open(struct drm_device *dev, struct drm_file *file_priv)
> +{
> +	struct drm_ipvr_file_private *ipvr_fp;
> +	IPVR_DEBUG_ENTRY("enter\n");
> +
> +	ipvr_fp = kzalloc(sizeof(*ipvr_fp), GFP_KERNEL);
> +	if (!ipvr_fp)
> +		return -ENOMEM;
> +
> +	file_priv->driver_priv = ipvr_fp;
> +	INIT_LIST_HEAD(&ipvr_fp->ctx_list);
> +	return 0;
> +}
> +
> +/*
> + * The close operation is split into .preclose() and .postclose() methods.
> + * Since .postclose() is deprecated, all resource destruction related to file
> + * handle are now done in .preclose() method.
> + */
> +static void
> +ipvr_drm_preclose(struct drm_device *dev, struct drm_file *file_priv)
> +{
> +	/* force close all contexts not explicitly closed by user */
> +	struct drm_ipvr_private *dev_priv;
> +	struct drm_ipvr_file_private *ipvr_fpriv;
> +	struct ved_private *ved_priv;
> +	struct ipvr_context *pos = NULL, *n = NULL;
> +	unsigned long irq_flags;
> +
> +	IPVR_DEBUG_ENTRY("enter\n");
> +	dev_priv = dev->dev_private;
> +	ipvr_fpriv = file_priv->driver_priv;
> +	ved_priv = dev_priv->ved_private;
> +
> +	spin_lock_irqsave(&dev_priv->ipvr_ctx_lock, irq_flags);
> +	if (ved_priv && (!list_empty(&ved_priv->ved_queue)
> +			|| (atomic_read(&dev_priv->pending_events) > 0)))
> {
> +		IPVR_DEBUG_WARN("Closing the FD while pending cmds
> exist!\n");
> +	}
> +	list_for_each_entry_safe(pos, n, &ipvr_fpriv->ctx_list, head) {
> +		IPVR_DEBUG_GENERAL("Video:remove context %d type
> 0x%x\n",
> +			pos->ctx_id, pos->ctx_type);
> +		list_del(&pos->head);
> +		idr_remove(&dev_priv->ipvr_ctx_idr, pos->ctx_id);
> +		kfree(pos);
> +	}
> +
> +	spin_unlock_irqrestore(&dev_priv->ipvr_ctx_lock, irq_flags);
> +	kfree(ipvr_fpriv);
> +}
> +
> +static irqreturn_t ipvr_irq_handler(int irq, void *arg)
> +{
> +	struct drm_device *dev = (struct drm_device *) arg;
> +	struct drm_ipvr_private *dev_priv = dev->dev_private;
> +	WARN_ON(ved_irq_handler(dev_priv->ved_private));
> +	return IRQ_HANDLED;
> +}
> +
> +static const struct file_operations ipvr_fops = {
> +	.owner = THIS_MODULE,
> +	.open = drm_open,
> +	.release = drm_release,
> +	.unlocked_ioctl = drm_ioctl,
> +#ifdef CONFIG_COMPAT
> +	.compat_ioctl = drm_ioctl,
> +#endif
> +	.mmap = drm_gem_mmap,
> +};
> +
> +static int ipvr_drm_freeze(struct drm_device *dev)
> +{
> +	int ret;
> +	struct drm_ipvr_private *dev_priv = dev->dev_private;
> +	IPVR_DEBUG_ENTRY("enter\n");
> +
> +	ret = ved_check_idle(dev_priv->ved_private);
> +	if (ret) {
> +		IPVR_DEBUG_PM("VED check idle fail: %d, skip freezing\n",
> ret);
> +		/**
> +		 * fixme: better to schedule a delayed task?
> +		 */
> +		return 0;
> +	}
> +
> +	if (dev->irq_enabled) {
> +		ret = drm_irq_uninstall(dev);
> +		if (ret) {
> +			IPVR_ERROR("Failed to uninstall drm irq
> handler: %d\n", ret);
> +		}
> +	}
> +
> +	if (is_ved_on(dev_priv)) {
> +		if (!ved_power_off(dev_priv)) {
> +			IPVR_ERROR("Failed to power off VED\n");
> +			return -EFAULT;
> +		}
> +		IPVR_DEBUG_PM("Successfully powered off\n");
> +	} else {
> +		IPVR_DEBUG_PM("Skiped power-off since already powered
> off\n");
> +	}
> +
> +	return 0;
> +}
> +
> +static int ipvr_drm_thaw(struct drm_device *dev)
> +{
> +	int ret;
> +	struct drm_ipvr_private *dev_priv = dev->dev_private;
> +	IPVR_DEBUG_ENTRY("enter\n");
> +	if (!is_ved_on(dev_priv)) {
> +		if (!ved_power_on(dev_priv)) {
> +			IPVR_ERROR("Failed to power on VED\n");
> +			return -EFAULT;
> +		}
> +		IPVR_DEBUG_PM("Successfully powered on\n");
> +	} else {
> +		IPVR_DEBUG_PM("Skiped power-on since already powered
> on\n");
> +	}
> +
> +	if (!dev->irq_enabled) {
> +		ret = drm_irq_install(dev, dev->irq);
> +		if (ret) {
> +			IPVR_ERROR("Failed to install drm irq handler: %d\n",
> ret);
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static int ipvr_pm_suspend(struct device *dev)
> +{
> +	struct platform_device *platformdev = to_platform_device(dev);
> +	struct drm_device *drm_dev = platform_get_drvdata(platformdev);
> +	IPVR_DEBUG_PM("PM suspend called\n");
> +	return drm_dev? ipvr_drm_freeze(drm_dev): 0;
> +}
> +static int ipvr_pm_resume(struct device *dev)
> +{
> +	struct platform_device *platformdev = to_platform_device(dev);
> +	struct drm_device *drm_dev = platform_get_drvdata(platformdev);
> +	IPVR_DEBUG_PM("PM resume called\n");
> +	return drm_dev? ipvr_drm_thaw(drm_dev): 0;
> +}
> +
> +static const struct vm_operations_struct ipvr_gem_vm_ops = {
> +	.fault = ipvr_gem_fault,
> +	.open = drm_gem_vm_open,
> +	.close = drm_gem_vm_close,
> +};
> +
> +static struct drm_driver ipvr_drm_driver = {
> +	.driver_features = DRIVER_HAVE_IRQ | DRIVER_GEM |
> DRIVER_PRIME,
> +	.load = ipvr_drm_load,
> +	.unload = ipvr_drm_unload,
> +	.open = ipvr_drm_open,
> +	.preclose = ipvr_drm_preclose,
> +	.irq_handler = ipvr_irq_handler,
> +	.gem_free_object = ipvr_gem_free_object,
> +	.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
> +	.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
> +	.gem_prime_export	= drm_gem_prime_export,
> +	.gem_prime_import	= drm_gem_prime_import,
> +	.gem_prime_get_sg_table = ipvr_gem_prime_get_sg_table,
> +	.gem_prime_import_sg_table = ipvr_gem_prime_import_sg_table,
> +	.gem_prime_pin		= ipvr_gem_prime_pin,
> +	.gem_prime_unpin	= ipvr_gem_prime_unpin,
> +#ifdef CONFIG_DEBUG_FS
> +	.debugfs_init = ipvr_debugfs_init,
> +	.debugfs_cleanup = ipvr_debugfs_cleanup,
> +#endif
> +	.gem_vm_ops = &ipvr_gem_vm_ops,
> +	.ioctls = ipvr_gem_ioctls,
> +	.num_ioctls = ARRAY_SIZE(ipvr_gem_ioctls),
> +	.fops = &ipvr_fops,
> +	.name = IPVR_DRIVER_NAME,
> +	.desc = IPVR_DRIVER_DESC,
> +	.date = IPVR_DRIVER_DATE,
> +	.major = IPVR_DRIVER_MAJOR,
> +	.minor = IPVR_DRIVER_MINOR,
> +	.patchlevel = IPVR_DRIVER_PATCHLEVEL,
> +};
> +
> +static int ipvr_plat_probe(struct platform_device *device)
> +{
> +	struct drm_device *drm_dev;
> +	int ret;
> +
> +	drm_dev = drm_dev_alloc(&ipvr_drm_driver, &device->dev);
> +	if (!drm_dev)
> +		return -ENOMEM;
> +
> +	drm_dev->platformdev = device;
> +	platform_set_drvdata(device, drm_dev);
> +	ret = drm_dev_register(drm_dev, 0);
> +	if (ret)
> +		goto err_free;
> +
> +	DRM_INFO("Initialized IPVR on minor %d\n", drm_dev->primary-
> >index);
> +
> +	return 0;
> +err_free:
> +	drm_dev_unref(drm_dev);
> +	return ret;
> +}
> +
> +static int ipvr_plat_remove(struct platform_device *device)
> +{
> +	struct drm_device *drm_dev = platform_get_drvdata(device);
> +	if (drm_dev) {
> +		drm_dev_unregister(drm_dev);
> +		drm_dev_unref(drm_dev);
> +		platform_set_drvdata(device, NULL);
> +	}
> +	return 0;
> +}
> +
> +static struct dev_pm_ops ipvr_pm_ops = {
> +	.suspend = ipvr_pm_suspend,
> +	.resume = ipvr_pm_resume,
> +	.freeze = ipvr_pm_suspend,
> +	.thaw = ipvr_pm_resume,
> +	.poweroff = ipvr_pm_suspend,
> +	.restore = ipvr_pm_resume,
> +#ifdef CONFIG_PM_RUNTIME
> +	.runtime_suspend = ipvr_pm_suspend,
> +	.runtime_resume = ipvr_pm_resume,
> +#endif
> +};
> +
> +static struct platform_driver ipvr_vlv_plat_driver = {
> +	.driver = {
> +		.name = "ipvr-ved-vlv",
> +		.owner = THIS_MODULE,
> +#ifdef CONFIG_PM
> +		.pm = &ipvr_pm_ops,
> +#endif
> +	},
> +	.probe = ipvr_plat_probe,
> +	.remove = ipvr_plat_remove,
> +};
> +
> +module_platform_driver(ipvr_vlv_plat_driver);
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/gpu/drm/ipvr/ipvr_drv.h
> b/drivers/gpu/drm/ipvr/ipvr_drv.h
> new file mode 100644
> index 0000000..7f88380
> --- /dev/null
> +++ b/drivers/gpu/drm/ipvr/ipvr_drv.h
> @@ -0,0 +1,292 @@
> +/*********************************************************
> *****************
> + * ipvr_drv.h: IPVR driver common header file
> + *
> + * Copyright (c) 2014 Intel Corporation, Hillsboro, OR, USA
> + * All Rights Reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of
> MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
> License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along
> with
> + * this program; if not, write to the Free Software Foundation, Inc.,
> + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
> + *
> + * Authors:
> + *    Fei Jiang <fei.jiang at intel.com>
> + *    Yao Cheng <yao.cheng at intel.com>
> + *
> +
> **********************************************************
> ****************/
> +
> +#ifndef _IPVR_DRV_H_
> +#define _IPVR_DRV_H_
> +#include "drmP.h"
> +#include "ipvr_drm.h"
> +#include "ipvr_mmu.h"
> +#include <linux/version.h>
> +#include <linux/io-mapping.h>
> +#include <linux/i2c.h>
> +#include <linux/i2c-algo-bit.h>
> +#include <linux/backlight.h>
> +#include <linux/intel-iommu.h>
> +#include <linux/kref.h>
> +#include <linux/pm_qos.h>
> +#include <linux/mmu_notifier.h>
> +
> +#define IPVR_DRIVER_AUTHOR		"Intel, Inc."
> +#define IPVR_DRIVER_NAME		"ipvr"
> +#define IPVR_DRIVER_DESC		"PowerVR video drm driver"
> +#define IPVR_DRIVER_DATE		"20141113"
> +#define IPVR_DRIVER_MAJOR		0
> +#define IPVR_DRIVER_MINOR		1
> +#define IPVR_DRIVER_PATCHLEVEL	0
> +
> +/* read/write domains */
> +#define IPVR_GEM_DOMAIN_CPU		0x00000001
> +#define IPVR_GEM_DOMAIN_VPU		0x00000002
> +
> +/* context ID and type */
> +#define IPVR_CONTEXT_INVALID_ID 0
> +#define IPVR_MIN_CONTEXT_ID 1
> +#define IPVR_MAX_CONTEXT_ID 0xff
> +
> +/*
> + *Debug print bits setting
> + */
> +#define IPVR_D_GENERAL   (1 << 0)
> +#define IPVR_D_INIT      (1 << 1)
> +#define IPVR_D_IRQ       (1 << 2)
> +#define IPVR_D_ENTRY     (1 << 3)
> +#define IPVR_D_PM        (1 << 4)
> +#define IPVR_D_REG       (1 << 5)
> +#define IPVR_D_VED       (1 << 6)
> +#define IPVR_D_WARN      (1 << 7)
> +
> +#define IPVR_DEBUG_GENERAL(_fmt, _arg...) \
> +	IPVR_DEBUG(IPVR_D_GENERAL, _fmt, ##_arg)
> +#define IPVR_DEBUG_INIT(_fmt, _arg...) \
> +	IPVR_DEBUG(IPVR_D_INIT, _fmt, ##_arg)
> +#define IPVR_DEBUG_IRQ(_fmt, _arg...) \
> +	IPVR_DEBUG(IPVR_D_IRQ, _fmt, ##_arg)
> +#define IPVR_DEBUG_ENTRY(_fmt, _arg...) \
> +	IPVR_DEBUG(IPVR_D_ENTRY, _fmt, ##_arg)
> +#define IPVR_DEBUG_PM(_fmt, _arg...) \
> +	IPVR_DEBUG(IPVR_D_PM, _fmt, ##_arg)
> +#define IPVR_DEBUG_REG(_fmt, _arg...) \
> +	IPVR_DEBUG(IPVR_D_REG, _fmt, ##_arg)
> +#define IPVR_DEBUG_VED(_fmt, _arg...) \
> +	IPVR_DEBUG(IPVR_D_VED, _fmt, ##_arg)
> +#define IPVR_DEBUG_WARN(_fmt, _arg...) \
> +	IPVR_DEBUG(IPVR_D_WARN, _fmt, ##_arg)
> +
> +#define IPVR_DEBUG(_flag, _fmt, _arg...) \
> +	do { \
> +		if (unlikely((_flag) & drm_ipvr_debug)) \
> +			printk(KERN_INFO \
> +			       "[ipvr:0x%02x:%s] " _fmt , _flag, \
> +			       __func__ , ##_arg); \
> +	} while (0)
> +
> +#define IPVR_ERROR(_fmt, _arg...) \
> +	do { \
> +			printk(KERN_ERR \
> +			       "[ipvr:ERROR:%s] " _fmt, \
> +			       __func__ , ##_arg); \
> +	} while (0)
> +
> +#define IPVR_UDELAY(usec) \
> +	do { \
> +		cpu_relax(); \
> +	} while (0)
> +
> +#define IPVR_REG_WRITE32(_val, _offs) \
> +	iowrite32(_val, dev_priv->reg_base + (_offs))
> +#define IPVR_REG_READ32(_offs) \
> +	ioread32(dev_priv->reg_base + (_offs))
> +
> +typedef struct ipvr_validate_buffer ipvr_validate_buffer_t;
> +
> +#define to_ipvr_bo(x) container_of(x, struct drm_ipvr_gem_object, base)
> +
> +extern int drm_ipvr_debug;
> +extern int drm_ipvr_freq;
> +
> +struct ipvr_validate_context {
> +	ipvr_validate_buffer_t *buffers;
> +	int used_buffers;
> +	struct list_head validate_list;
> +};
> +
> +struct ipvr_mmu_driver;
> +struct ipvr_mmu_pd;
> +
> +struct ipvr_gem_stat {
> +	/**
> +	 * Are we in a non-interruptible section of code?
> +	 */
> +	bool interruptible;
> +
> +	/* accounting, useful for userland debugging */
> +	spinlock_t object_stat_lock;
> +	size_t allocated_memory;
> +	int allocated_count;
> +	size_t imported_memory;
> +	int imported_count;
> +	size_t exported_memory;
> +	int exported_count;
> +	size_t mmu_used_size;
> +};
> +
> +struct ipvr_address_space {
> +	struct drm_mm linear_mm;
> +	struct drm_mm tiling_mm;
> +	struct drm_device *dev;
> +	unsigned long linear_start;
> +	size_t linear_total;
> +	unsigned long tiling_start;
> +	size_t tiling_total;
> +
> +	/* need it during clear_range */
> +	struct {
> +		dma_addr_t addr;
> +		struct page *page;
> +	} scratch;
> +};
> +
> +struct ipvr_fence_driver {
> +	u16	sync_seq;
> +	atomic_t signaled_seq;
> +	unsigned long last_activity;
> +	bool initialized;
> +	spinlock_t fence_lock;
> +};
> +
> +struct ipvr_context {
> +	/* used to link into ipvr_ctx_list */
> +	struct list_head head;
> +	u32 ctx_id;
> +	/* used to double check ctx when find with idr, may be removed */
> +	struct drm_ipvr_file_private *ipvr_fpriv; /* DRM device file pointer
> */
> +	u32 ctx_type;
> +
> +	u16 cur_seq;
> +
> +	/* for IMG DDK, only use tiling for 2k and 4k buffer stride */
> +	/*
> +	 * following tiling strides for VED are supported:
> +	 * stride 0: 512 for scheme 0, 1024 for scheme 1
> +	 * stride 1: 1024 for scheme 0, 2048 for scheme 1
> +	 * stride 2: 2048 for scheme 0, 4096 for scheme 1
> +	 * stride 3: 4096 for scheme 0
> +	 */
> +	u8 tiling_stride;
> +	/*
> +	 * scheme 0: tile is 256x16, while minimal tile stride is 512
> +	 * scheme 1: tile is 512x8, while minimal tile stride is 1024
> +	 */
> +	u8 tiling_scheme;
> +};
> +
> +typedef struct drm_ipvr_private {
> +	struct drm_device *dev;
> +	struct pci_dev *pci_root;
> +
> +	/* IMG video context */
> +	spinlock_t ipvr_ctx_lock;
> +	struct idr ipvr_ctx_idr;
> +	struct ipvr_context default_ctx;
> +
> +	/* PM related */
> +	atomic_t pending_events;
> +	spinlock_t power_usage_lock;
> +
> +	/* exec related */
> +	struct ipvr_validate_context validate_ctx;
> +
> +	/* IMG MMU specific */
> +	struct ipvr_mmu_driver *mmu;
> +	atomic_t ipvr_mmu_invaldc;
> +
> +	/* GEM mm related */
> +	struct ipvr_gem_stat ipvr_stat;
> +	struct kmem_cache *ipvr_bo_slab;
> +	struct ipvr_address_space addr_space;
> +
> +	/* fence related */
> +	u32 last_seq;
> +	wait_queue_head_t fence_queue;
> +	struct ipvr_fence_driver fence_drv;
> +
> +	/* MMIO window shared from parent device */
> +	u8 __iomem* reg_base;
> +
> +	/*
> +	 * VED specific
> +	 */
> +	struct ved_private *ved_private;
> +}drm_ipvr_private_t;
> +
> +struct drm_ipvr_gem_object;
> +
> +/* VED private structure */
> +struct ved_private {
> +	struct drm_ipvr_private *dev_priv;
> +
> +	/* used to record seq got from irq fw-to-host msg */
> +	u16 ved_cur_seq;
> +
> +	/*
> +	 * VED Rendec Memory
> +	 */
> +	struct drm_ipvr_gem_object *ccb0;
> +	u32 base_addr0;
> +	struct drm_ipvr_gem_object *ccb1;
> +	u32 base_addr1;
> +	bool rendec_initialized;
> +
> +	/* VED firmware related */
> +	struct drm_ipvr_gem_object  *fw_bo;
> +	u32 fw_offset;
> +	u32 mtx_mem_size;
> +	bool fw_loaded_to_bo;
> +	bool ved_fw_loaded;
> +	void *ved_fw_ptr;
> +	size_t ved_fw_size;
> +
> +	/*
> +	 * ved command queue
> +	 */
> +	spinlock_t ved_lock;
> +	struct mutex ved_mutex;
> +	struct list_head ved_queue;
> +	/* busy means cmd submitted to fw, while irq hasn't been receieved
> */
> +	bool ved_busy;
> +	u32 ved_dash_access_ctrl;
> +
> +	/* pm related */
> +	int ved_needs_reset;
> +
> +	int default_tiling_stride;
> +	int default_tiling_scheme;
> +
> +	struct page *mmu_recover_page;
> +};
> +
> +struct drm_ipvr_file_private {
> +	/**
> +	 * protected by dev_priv->ipvr_ctx_lock
> +	 */
> +	struct list_head ctx_list;
> +};
> +
> +/* helpers for runtime pm */
> +int ipvr_runtime_pm_get(struct drm_ipvr_private *dev_priv);
> +int ipvr_runtime_pm_put(struct drm_ipvr_private *dev_priv, bool async);
> +int ipvr_runtime_pm_put_all(struct drm_ipvr_private *dev_priv, bool
> async);
> +
> +#endif
> diff --git a/drivers/gpu/drm/ipvr/ipvr_exec.c
> b/drivers/gpu/drm/ipvr/ipvr_exec.c
> new file mode 100644
> index 0000000..2e52dea
> --- /dev/null
> +++ b/drivers/gpu/drm/ipvr/ipvr_exec.c
> @@ -0,0 +1,613 @@
> +/*********************************************************
> *****************
> + * ipvr_exec.c: IPVR command buffer execution
> + *
> + * Copyright (c) 2014 Intel Corporation, Hillsboro, OR, USA
> + * All Rights Reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of
> MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
> License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along
> with
> + * this program; if not, write to the Free Software Foundation, Inc.,
> + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
> + *
> + * Authors:
> + *    Fei Jiang <fei.jiang at intel.com>
> + *    Yao Cheng <yao.cheng at intel.com>
> + *
> +
> **********************************************************
> ****************/
> +
> +#include "ipvr_exec.h"
> +#include "ipvr_gem.h"
> +#include "ipvr_mmu.h"
> +#include "ipvr_bo.h"
> +#include "ipvr_fence.h"
> +#include "ipvr_trace.h"
> +#include "ved_fw.h"
> +#include "ved_msg.h"
> +#include "ved_reg.h"
> +#include "ved_pm.h"
> +#include "ved_cmd.h"
> +#include <linux/io.h>
> +#include <linux/delay.h>
> +#include <linux/pm_runtime.h>
> +
> +static inline bool ipvr_bo_is_reserved(struct drm_ipvr_gem_object *obj)
> +{
> +	return atomic_read(&obj->reserved);
> +}
> +
> +static int
> +ipvr_bo_wait_unreserved(struct drm_ipvr_gem_object *obj, bool
> interruptible)
> +{
> +	if (interruptible) {
> +		return wait_event_interruptible(obj->event_queue,
> +					       !ipvr_bo_is_reserved(obj));
> +	} else {
> +		wait_event(obj->event_queue, !ipvr_bo_is_reserved(obj));
> +		return 0;
> +	}
> +}
> +
> +/**
> + * ipvr_bo_reserve - reserve the given bo
> + *
> + * @obj:     The buffer object to reserve.
> + * @interruptible:     whether the waiting is interruptible or not.
> + * @no_wait:    flag to indicate returning immediately
> + *
> + * Returns: 0 if successful, error code otherwise
> + */
> +int ipvr_bo_reserve(struct drm_ipvr_gem_object *obj,
> +			bool interruptible, bool no_wait)
> +{
> +	int ret;
> +
> +	while (unlikely(atomic_xchg(&obj->reserved, 1) != 0)) {
> +		if (no_wait)
> +			return -EBUSY;
> +		IPVR_DEBUG_GENERAL("wait bo unreserved, add to wait
> queue.\n");
> +		ret = ipvr_bo_wait_unreserved(obj, interruptible);
> +		if (unlikely(ret))
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +/**
> + * ipvr_bo_unreserve - unreserve the given bo
> + *
> + * @obj:     The buffer object to reserve.
> + *
> + * No return value.
> + */
> +void ipvr_bo_unreserve(struct drm_ipvr_gem_object *obj)
> +{
> +	atomic_set(&obj->reserved, 0);
> +	wake_up_all(&obj->event_queue);
> +}
> +
> +static void ipvr_backoff_reservation(struct list_head *list)
> +{
> +	struct ipvr_validate_buffer *entry;
> +
> +	list_for_each_entry(entry, list, head) {
> +		struct drm_ipvr_gem_object *obj = entry->ipvr_gem_bo;
> +		if (!atomic_read(&obj->reserved))
> +			continue;
> +		atomic_set(&obj->reserved, 0);
> +		wake_up_all(&obj->event_queue);
> +	}
> +}
> +
> +/*
> + * ipvr_reserve_buffers - Reserve buffers for validation.
> + *
> + * @list:     points to a bo list to be backoffed
> + *
> + * If a buffer in the list is marked for CPU access, we back off and
> + * wait for that buffer to become free for VPU access.
> + *
> + * If a buffer is reserved for another validation, the validator with
> + * the highest validation sequence backs off and waits for that buffer
> + * to become unreserved. This prevents deadlocks when validating multiple
> + * buffers in different orders.
> + *
> + * Returns:
> + * 0 on success, error code on failure.
> + */
> +int ipvr_reserve_buffers(struct list_head *list)
> +{
> +	struct ipvr_validate_buffer *entry;
> +	int ret;
> +
> +	if (list_empty(list))
> +		return 0;
> +
> +	list_for_each_entry(entry, list, head) {
> +		struct drm_ipvr_gem_object *bo = entry->ipvr_gem_bo;
> +
> +		ret = ipvr_bo_reserve(bo, true, true);
> +		switch (ret) {
> +		case 0:
> +			break;
> +		case -EBUSY:
> +			ret = ipvr_bo_reserve(bo, true, false);
> +			if (!ret)
> +				break;
> +			else
> +				goto err;
> +		default:
> +			goto err;
> +		}
> +	}
> +
> +	return 0;
> +err:
> +	ipvr_backoff_reservation(list);
> +	return ret;
> +}
> +
> +/**
> + * ipvr_set_tile - global setting of tiling info
> + *
> + * @dev:     the ipvr drm device
> + * @tiling_scheme:     see ipvr_drm.h for details
> + * @tiling_stride:     see ipvr_drm.h for details
> + *
> + * vxd392 hardware supports only one tile region so this configuration
> + * is global.
> + */
> +void ipvr_set_tile(struct drm_ipvr_private *dev_priv,
> +		u8 tiling_scheme, u8 tiling_stride)
> +{
> +	u32 cmd;
> +	u32 start = IPVR_MEM_MMU_TILING_START;
> +	u32 end = IPVR_MEM_MMU_TILING_END;
> +
> +	/* Enable memory tiling */
> +	cmd = ((start >> 20) + (((end >> 20) - 1) << 12) +
> +				((0x8 | tiling_stride) << 24));
> +	IPVR_DEBUG_GENERAL("VED: MMU Tiling register0 %08x.\n", cmd);
> +	IPVR_DEBUG_GENERAL("Region 0x%08x-0x%08x.\n", start, end);
> +	IPVR_REG_WRITE32(cmd, MSVDX_MMU_TILE_BASE0_OFFSET);
> +
> +	/* we need set tile format as 512x8 on Baytrail, which is shceme 1 */
> +	IPVR_REG_WRITE32(tiling_scheme << 3,
> MSVDX_MMU_CONTROL2_OFFSET);
> +}
> +
> +/**
> + * ipvr_find_ctx_with_fence - lookup the context with given fence seqno
> + *
> + * @dev_priv:     the ipvr drm device
> + * @fence:     fence seqno generated by the context
> + *
> + * Returns:
> + * context pointer if found.
> + * NULL if not found.
> + */
> +struct ipvr_context*
> +ipvr_find_ctx_with_fence(struct drm_ipvr_private *dev_priv, u16 fence)
> +{
> +	struct ipvr_context *pos;
> +	int id = 0;
> +
> +	spin_lock(&dev_priv->ipvr_ctx_lock);
> +	idr_for_each_entry(&dev_priv->ipvr_ctx_idr, pos, id) {
> +		if (pos->cur_seq == fence) {
> +			spin_unlock(&dev_priv->ipvr_ctx_lock);
> +			return pos;
> +		}
> +	}
> +	spin_unlock(&dev_priv->ipvr_ctx_lock);
> +
> +	return NULL;
> +}
> +
> +static void ipvr_unreference_buffers(struct ipvr_validate_context *context)
> +{
> +	struct ipvr_validate_buffer *entry, *next;
> +	struct drm_ipvr_gem_object *obj;
> +	struct list_head *list = &context->validate_list;
> +
> +	list_for_each_entry_safe(entry, next, list, head) {
> +		obj = entry->ipvr_gem_bo;
> +		list_del(&entry->head);
> +		drm_gem_object_unreference_unlocked(&obj->base);
> +		context->used_buffers--;
> +	}
> +}
> +
> +static int ipvr_update_buffers(struct drm_file *file_priv,
> +					struct ipvr_validate_context *context,
> +					u64 buffer_list,
> +					int count)
> +{
> +	struct ipvr_validate_buffer *entry;
> +	struct drm_ipvr_gem_exec_object __user *val_arg
> +		= (struct drm_ipvr_gem_exec_object __user
> *)(uintptr_t)buffer_list;
> +
> +	if (list_empty(&context->validate_list))
> +		return 0;
> +
> +	list_for_each_entry(entry, &context->validate_list, head) {
> +		if (!val_arg) {
> +			IPVR_DEBUG_WARN("unexpected end of val_arg
> list!!!\n");
> +			return -EINVAL;
> +		}
> +		if (unlikely(copy_to_user(val_arg, &entry->val_req,
> +					    sizeof(entry->val_req)))) {
> +			IPVR_ERROR("copy_to_user fault.\n");
> +			return -EFAULT;
> +		}
> +		val_arg ++;
> +	}
> +	return 0;
> +}
> +
> +static int ipvr_reference_buffers(struct drm_file *file_priv,
> +					struct ipvr_validate_context *context,
> +					u64 buffer_list,
> +					int count)
> +{
> +	struct drm_device *dev = file_priv->minor->dev;
> +	struct drm_ipvr_gem_exec_object __user *val_arg
> +		= (struct drm_ipvr_gem_exec_object __user
> *)(uintptr_t)buffer_list;
> +	struct ipvr_validate_buffer *item;
> +	struct drm_ipvr_gem_object *obj;
> +	int ret = 0;
> +	int i = 0;
> +
> +	for (i = 0; i < count; ++i) {
> +		if (unlikely(context->used_buffers >=
> IPVR_NUM_VALIDATE_BUFFERS)) {
> +			IPVR_ERROR("Too many buffers on validate list.\n");
> +			ret = -EINVAL;
> +			goto out_err;
> +		}
> +		item = &context->buffers[context->used_buffers];
> +		if (unlikely(copy_from_user(&item->val_req, val_arg,
> +					    sizeof(item->val_req)) != 0)) {
> +			IPVR_ERROR("copy_from_user fault.\n");
> +			ret = -EFAULT;
> +			goto out_err;
> +		}
> +		INIT_LIST_HEAD(&item->head);
> +		obj = to_ipvr_bo(drm_gem_object_lookup(dev, file_priv,
> +						item->val_req.handle));
> +		if (&obj->base == NULL) {
> +			IPVR_ERROR("cannot find obj for handle %u at
> position %d.\n",
> +				item->val_req.handle, i);
> +			ret = -ENOENT;
> +			goto out_err;
> +		}
> +		item->ipvr_gem_bo = obj;
> +
> +		list_add_tail(&item->head, &context->validate_list);
> +		context->used_buffers++;
> +
> +		val_arg++;
> +	}
> +
> +	return 0;
> +
> +out_err:
> +	ipvr_unreference_buffers(context);
> +	return ret;
> +}
> +
> +static int ipvr_fixup_reloc_entries(struct drm_device *dev,
> +					struct drm_file *filp,
> +					struct ipvr_validate_buffer *val_obj)
> +{
> +	int i, ret;
> +	u64 mmu_offset;
> +	struct drm_ipvr_gem_object *obj, *target_obj;
> +	struct drm_ipvr_gem_exec_object *exec_obj = &val_obj->val_req;
> +	struct drm_ipvr_gem_relocation_entry __user *reloc_entries
> +		= (struct drm_ipvr_gem_relocation_entry __user
> *)(uintptr_t)exec_obj->relocs_ptr;
> +	struct drm_ipvr_gem_relocation_entry local_reloc_entry;
> +
> +	obj = val_obj->ipvr_gem_bo;
> +	if (!obj)
> +		return -ENOENT;
> +
> +	/* todo: check write access */
> +
> +	/* overwrite user content and update relocation entries */
> +	mmu_offset = ipvr_gem_object_mmu_offset(obj);
> +	if (mmu_offset != exec_obj->offset) {
> +		exec_obj->offset = mmu_offset;
> +		IPVR_DEBUG_GENERAL("Fixup BO %u offset to 0x%llx\n",
> +			exec_obj->handle, exec_obj->offset);
> +	}
> +	for (i = 0; i < exec_obj->relocation_count; ++i) {
> +		if (unlikely(copy_from_user(&local_reloc_entry,
> &reloc_entries[i],
> +					    sizeof(local_reloc_entry)) != 0)) {
> +			IPVR_ERROR("copy_from_user fault.\n");
> +			return -EFAULT;
> +		}
> +		target_obj = to_ipvr_bo(drm_gem_object_lookup(dev, filp,
> +
> 	local_reloc_entry.target_handle));
> +		if (&target_obj->base == NULL) {
> +			IPVR_ERROR("cannot find obj for handle %u at
> position %d.\n",
> +				local_reloc_entry.target_handle, i);
> +			return -ENOENT;
> +		}
> +		ret = ipvr_gem_object_apply_reloc(obj,
> +				local_reloc_entry.offset,
> +				local_reloc_entry.delta +
> ipvr_gem_object_mmu_offset(target_obj));
> +		if (ret) {
> +			IPVR_ERROR("Failed applying reloc: %d\n", ret);
> +
> 	drm_gem_object_unreference_unlocked(&target_obj->base);
> +			return ret;
> +		}
> +		if (unlikely(copy_to_user(&reloc_entries[i],
> &local_reloc_entry,
> +						sizeof(local_reloc_entry)) !=
> 0)) {
> +			IPVR_DEBUG_WARN("copy_to_user fault.\n");
> +		}
> +		IPVR_DEBUG_GENERAL("Fixup offset %llx in BO %u to
> 0x%lx\n",
> +			local_reloc_entry.offset, exec_obj->handle,
> +			local_reloc_entry.delta +
> ipvr_gem_object_mmu_offset(target_obj));
> +		drm_gem_object_unreference_unlocked(&target_obj-
> >base);
> +	}
> +	return 0;
> +}
> +
> +static int ipvr_fixup_relocs(struct drm_device *dev,
> +					struct drm_file *filp,
> +					struct ipvr_validate_context *context)
> +{
> +	int ret;
> +	struct ipvr_validate_buffer *entry;
> +
> +	if (list_empty(&context->validate_list)) {
> +		IPVR_DEBUG_WARN("No relocs required in validate contex,
> skip\n");
> +		return 0;
> +	}
> +
> +	list_for_each_entry(entry, &context->validate_list, head) {
> +		IPVR_DEBUG_GENERAL("Fixing up reloc for BO handle %u\n",
> +			entry->val_req.handle);
> +		ret = ipvr_fixup_reloc_entries(dev, filp, entry);
> +		if (ret) {
> +			IPVR_ERROR("Failed to fixup reloc for BO
> handle %u\n",
> +				entry->val_req.handle);
> +			return ret;
> +		}
> +	}
> +	return 0;
> +}
> +
> +static int ipvr_validate_buffer_list(struct drm_file *file_priv,
> +					struct ipvr_validate_context *context,
> +					bool *need_fixup_relocs,
> +					struct drm_ipvr_gem_object
> **cmd_buffer)
> +{
> +	struct ipvr_validate_buffer *entry;
> +	struct drm_ipvr_gem_object *obj;
> +	struct list_head *list = &context->validate_list;
> +	int ret = 0;
> +	u64 real_mmu_offset;
> +
> +	list_for_each_entry(entry, list, head) {
> +		obj = entry->ipvr_gem_bo;
> +		/**
> +		 * need validate bo locate in the mmu space
> +		 * check if presumed offset is correct
> +		 * with ved_check_presumed, if presume is not correct,
> +		 * call fixup relocs with ved_fixup_relocs.
> +		 * current implementation doesn't support shrink/evict,
> +		 * so needn't validate mmu offset.
> +		 * need be implemented in the future if shrink/evict
> +		 * is supported.
> +		 */
> +		real_mmu_offset = ipvr_gem_object_mmu_offset(obj);
> +		if (IPVR_IS_ERR(real_mmu_offset))
> +			return -ENOENT;
> +		if (entry->val_req.offset != real_mmu_offset) {
> +			IPVR_DEBUG_GENERAL("BO %u offset doesn't
> match MMU, need fixup reloc\n", entry->val_req.handle);
> +			*need_fixup_relocs = true;
> +		}
> +		if (entry->val_req.flags & IPVR_EXEC_OBJECT_SUBMIT) {
> +			if (*cmd_buffer != NULL) {
> +				IPVR_ERROR("Only one BO can be submitted
> in one exec ioctl\n");
> +				return -EINVAL;
> +			}
> +			*cmd_buffer = obj;
> +		}
> +	}
> +
> +	return ret;
> +}
> +
> +/**
> + * ipvr_gem_do_execbuffer - lookup the context with given fence seqno
> + *
> + * @dev:     the ipvr drm device
> + * @file_priv:      the ipvr drm file pointer
> + * @args:      input argument passed from userland
> + * @vm:      ipvr address space for all the bo to bind to
> + *
> + * Returns: 0 on success, error code on failure
> + */
> +static int ipvr_gem_do_execbuffer(struct drm_device *dev,
> +					struct drm_file *file_priv,
> +					struct drm_ipvr_gem_execbuffer
> *args,
> +					struct ipvr_address_space *vm)
> +{
> +	drm_ipvr_private_t *dev_priv = dev->dev_private;
> +	struct ipvr_validate_context *context = &dev_priv->validate_ctx;
> +	struct ved_private *ved_priv = dev_priv->ved_private;
> +	struct drm_ipvr_gem_object *cmd_buffer = NULL;
> +	struct ipvr_context *ipvr_ctx  = NULL;
> +	int ret, ctx_id;
> +	bool need_fixup_relocs = false;
> +
> +	/* if not pass 0, use default context instead */
> +	if (args->ctx_id == 0)
> +		ctx_id = dev_priv->default_ctx.ctx_id;
> +	else
> +		ctx_id = args->ctx_id;
> +
> +	IPVR_DEBUG_GENERAL("try to find ctx according ctx_id %d.\n",
> ctx_id);
> +
> +	/* we're already in struct_mutex lock */
> +	ipvr_ctx = (struct ipvr_context *)
> +			idr_find(&dev_priv->ipvr_ctx_idr, ctx_id);
> +	if (!ipvr_ctx) {
> +		IPVR_DEBUG_WARN("video ctx is not found.\n");
> +		return -ENOENT;
> +	}
> +
> +	IPVR_DEBUG_GENERAL("reference all buffers passed through
> buffer_list.\n");
> +	ret = ipvr_reference_buffers(file_priv, context,
> +				args->buffers_ptr, args->buffer_count);
> +	if (unlikely(ret)) {
> +		IPVR_DEBUG_WARN("reference buffer failed: %d.\n", ret);
> +		return ret;
> +	}
> +
> +	IPVR_DEBUG_GENERAL("reserve all buffers to make them not
> accessed "
> +			"by other threads.\n");
> +	ret = ipvr_reserve_buffers(&context->validate_list);
> +	if (unlikely(ret)) {
> +		IPVR_ERROR("reserve buffers failed.\n");
> +		/* -EBUSY or -ERESTARTSYS */
> +		goto out_unref_buf;
> +	}
> +
> +	IPVR_DEBUG_GENERAL("validate buffer list, mainly check "
> +			"the bo mmu offset.\n");
> +	ret = ipvr_validate_buffer_list(file_priv, context,
> &need_fixup_relocs, &cmd_buffer);
> +	if (unlikely(ret)) {
> +		IPVR_ERROR("validate buffers failed: %d.\n", ret);
> +		goto out_backoff_reserv;
> +	}
> +
> +	if (unlikely(cmd_buffer == NULL)) {
> +		IPVR_ERROR("No cmd BO found.\n");
> +		ret = -EINVAL;
> +		goto out_backoff_reserv;
> +	}
> +
> +	if (unlikely(need_fixup_relocs)) {
> +		ret = ipvr_fixup_relocs(dev, file_priv, context);
> +		if (ret) {
> +			IPVR_ERROR("fixup relocs failed.\n");
> +			goto out_backoff_reserv;
> +		}
> +	}
> +
> +#if 0
> +	bo = idr_find(&file_priv->object_idr, args->cmdbuf_handle);
> +	if (!bo) {
> +		IPVR_DEBUG_WARN("Invalid cmd object handle 0x%x.\n",
> +			args->cmdbuf_handle);
> +		ret = -EINVAL;
> +		goto out_backoff_reserv;
> +	}
> +
> +	cmd_buffer = to_ipvr_bo(bo);
> +#endif
> +	/**
> +	 * check contex id and type
> +	 */
> +	/*
> +	 * only VED is supported currently
> +	 */
> +	if (ipvr_ctx->ctx_type == IPVR_CONTEXT_TYPE_VED)
> +	{
> +		/* fixme: should support non-zero start_offset */
> +		if (unlikely(args->exec_start_offset != 0)) {
> +			IPVR_ERROR("Unsupported exec_start_offset %u\n",
> args->exec_start_offset);
> +			ret = -EINVAL;
> +			goto out_backoff_reserv;
> +		}
> +
> +		ret = mutex_lock_interruptible(&ved_priv->ved_mutex);
> +		if (unlikely(ret)) {
> +			IPVR_ERROR("Error get VED mutex: %d\n", ret);
> +			/* -EINTR */
> +			goto out_backoff_reserv;
> +		}
> +
> +		IPVR_DEBUG_GENERAL("parse cmd buffer and send to
> VED.\n");
> +		ret = ved_cmdbuf_video(ved_priv, cmd_buffer,
> +				args->exec_len, ipvr_ctx );
> +		if (unlikely(ret)) {
> +			IPVR_ERROR("ved_cmdbuf_video returns %d.\n",
> ret);
> +			/* -EINVAL, -ENOMEM, -EFAULT, -EBUSY */
> +			mutex_unlock(&ved_priv->ved_mutex);
> +			goto out_backoff_reserv;
> +		}
> +
> +		mutex_unlock(&ved_priv->ved_mutex);
> +	}
> +
> +	/**
> +	 * update mmu_offsets and fence fds to user
> +	 */
> +	ret = ipvr_update_buffers(file_priv, context,
> +				args->buffers_ptr, args->buffer_count);
> +	if (unlikely(ret)) {
> +		IPVR_DEBUG_WARN("ipvr_update_buffers returns
> error %d.\n", ret);
> +		ret = 0;
> +	}
> +
> +out_backoff_reserv:
> +	IPVR_DEBUG_GENERAL("unreserve buffer list.\n");
> +	ipvr_backoff_reservation(&context->validate_list);
> +out_unref_buf:
> +	IPVR_DEBUG_GENERAL("unref bufs which are refered during bo
> lookup.\n");
> +	ipvr_unreference_buffers(context);
> +	return ret;
> +}
> +
> +/**
> + * ipvr_gem_do_execbuffer - lookup the context with given fence seqno
> + *
> + * ioctl entry for DRM_IPVR_GEM_EXECBUFFER
> + *
> + * Returns: 0 on success, error code on failure
> + */
> +int ipvr_gem_execbuffer_ioctl(struct drm_device *dev, void *data,
> +				struct drm_file *file_priv)
> +{
> +	struct drm_ipvr_private *dev_priv = dev->dev_private;
> +	struct drm_ipvr_gem_execbuffer *args = data;
> +	int ret;
> +	struct ipvr_validate_context *context = &dev_priv->validate_ctx;
> +
> +	ret = mutex_lock_interruptible(&dev->struct_mutex);
> +	if (ret)
> +		return ret;
> +
> +	if (!context || !context->buffers) {
> +		ret = -EINVAL;
> +		goto out;
> +	}
> +
> +	context->used_buffers = 0;
> +
> +	if (args->buffer_count < 1 ||
> +		args->buffer_count >
> +			(UINT_MAX / sizeof(struct ipvr_validate_buffer))) {
> +		IPVR_ERROR("validate %d buffers.\n", args->buffer_count);
> +		ret = -EINVAL;
> +		goto out;
> +	}
> +
> +	trace_ipvr_execbuffer(args);
> +	ret = ipvr_gem_do_execbuffer(dev, file_priv, args,
> +				    &dev_priv->addr_space);
> +out:
> +	mutex_unlock(&dev->struct_mutex);
> +	return ret;
> +}
> diff --git a/drivers/gpu/drm/ipvr/ipvr_exec.h
> b/drivers/gpu/drm/ipvr/ipvr_exec.h
> new file mode 100644
> index 0000000..cd174a8
> --- /dev/null
> +++ b/drivers/gpu/drm/ipvr/ipvr_exec.h
> @@ -0,0 +1,57 @@
> +/*********************************************************
> *****************
> + * ipvr_exec.h: IPVR header file for command buffer execution
> + *
> + * Copyright (c) 2014 Intel Corporation, Hillsboro, OR, USA
> + * All Rights Reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of
> MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
> License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along
> with
> + * this program; if not, write to the Free Software Foundation, Inc.,
> + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
> + *
> + * Authors:
> + *    Fei Jiang <fei.jiang at intel.com>
> + *    Yao Cheng <yao.cheng at intel.com>
> + *
> +
> **********************************************************
> ****************/
> +
> +#ifndef _IPVR_EXEC_H_
> +#define _IPVR_EXEC_H_
> +
> +#include "ipvr_drv.h"
> +#include "ipvr_drm.h"
> +#include "ipvr_gem.h"
> +#include "ipvr_fence.h"
> +
> +struct drm_ipvr_private;
> +
> +#define IPVR_NUM_VALIDATE_BUFFERS 2048
> +#define IPVR_MAX_RELOC_PAGES 1024
> +
> +struct ipvr_validate_buffer {
> +	struct drm_ipvr_gem_exec_object val_req;
> +	struct list_head head;
> +	struct drm_ipvr_gem_object *ipvr_gem_bo;
> +	struct ipvr_fence *old_fence;
> +};
> +
> +int ipvr_bo_reserve(struct drm_ipvr_gem_object *obj,
> +			bool interruptible, bool no_wait);
> +
> +void ipvr_bo_unreserve(struct drm_ipvr_gem_object *obj);
> +
> +struct ipvr_context*
> +ipvr_find_ctx_with_fence(struct drm_ipvr_private *dev_priv, u16 fence);
> +
> +void ipvr_set_tile(struct drm_ipvr_private *dev_priv,
> +			u8 tiling_scheme, u8 tiling_stride);
> +
> +#endif
> diff --git a/drivers/gpu/drm/ipvr/ipvr_fence.c
> b/drivers/gpu/drm/ipvr/ipvr_fence.c
> new file mode 100644
> index 0000000..ef8212a
> --- /dev/null
> +++ b/drivers/gpu/drm/ipvr/ipvr_fence.c
> @@ -0,0 +1,487 @@
> +/*********************************************************
> *****************
> + * ipvr_fence.c: IPVR fence handling to track command exectuion status
> + *
> + * Copyright (c) 2014 Intel Corporation, Hillsboro, OR, USA
> + * All Rights Reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of
> MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
> License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along
> with
> + * this program; if not, write to the Free Software Foundation, Inc.,
> + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
> + *
> + * Authors:
> + *    Fei Jiang <fei.jiang at intel.com>
> + *    Yao Cheng <yao.cheng at intel.com>
> + *
> +
> **********************************************************
> ****************/
> +
> +#include "ipvr_fence.h"
> +#include "ipvr_exec.h"
> +#include "ipvr_bo.h"
> +#include "ipvr_trace.h"
> +#include "ved_reg.h"
> +#include "ved_fw.h"
> +#include "ved_cmd.h"
> +#include <linux/debugfs.h>
> +#include <linux/export.h>
> +#include <linux/file.h>
> +#include <linux/fs.h>
> +#include <linux/kernel.h>
> +#include <linux/poll.h>
> +#include <linux/sched.h>
> +#include <linux/seq_file.h>
> +#include <linux/slab.h>
> +#include <linux/uaccess.h>
> +#include <linux/anon_inodes.h>
> +
> +/**
> + * ipvr_fence_create - create and init a fence
> + *
> + * @dev_priv: drm_ipvr_private pointer
> + * @fence: ipvr fence object
> + * @fence_fd: file descriptor for exporting fence
> + *
> + * Create a fence, actually the fence is written to ipvr through msg.
> + * exporting a new file descriptor to userspace.
> + * Returns pointer on success, ERR_PTR otherwise.
> + */
> +struct ipvr_fence* __must_check
> +ipvr_fence_create(struct drm_ipvr_private *dev_priv)
> +{
> +	struct ipvr_fence *fence;
> +	unsigned long irq_flags;
> +	u16 old_seq;
> +	struct ved_private *ved_priv;
> +
> +	ved_priv = dev_priv->ved_private;
> +
> +	fence = kzalloc(sizeof(struct ipvr_fence), GFP_KERNEL);
> +	if (!fence) {
> +		fence = ERR_PTR(-ENOMEM);
> +		goto out;
> +	}
> +
> +	kref_init(&fence->kref);
> +	fence->dev_priv = dev_priv;
> +
> +	spin_lock_irqsave(&dev_priv->fence_drv.fence_lock, irq_flags);
> +	/* cmds in one batch use different fence value */
> +	old_seq = dev_priv->fence_drv.sync_seq;
> +	dev_priv->fence_drv.sync_seq = dev_priv->last_seq++;
> +	dev_priv->fence_drv.sync_seq <<= 4;
> +	fence->seq = dev_priv->fence_drv.sync_seq;
> +
> +	spin_unlock_irqrestore(&dev_priv->fence_drv.fence_lock, irq_flags);
> +
> +	kref_get(&fence->kref);
> +	IPVR_DEBUG_GENERAL("fence is created and its seq is %u
> (0x%04x).\n",
> +		fence->seq, fence->seq);
> +out:
> +	return fence;
> +}
> +
> +/**
> + * ipvr_fence_destroy - destroy a fence
> + *
> + * @kref: fence kref
> + *
> + * Frees the fence object (all asics).
> + */
> +static void ipvr_fence_destroy(struct kref *kref)
> +{
> +	struct ipvr_fence *fence;
> +
> +	fence = container_of(kref, struct ipvr_fence, kref);
> +	kfree(fence);
> +}
> +
> +/**
> + * ipvr_fence_process - process a fence
> + *
> + * @dev_priv: drm_ipvr_private pointer
> + * @seq: indicate the fence seq has been signaled
> + * @err: indicate if err happened, for future use
> + *
> + * Checks the current fence value and wakes the fence queue
> + * if the sequence number has increased (all asics).
> + */
> +void ipvr_fence_process(struct drm_ipvr_private *dev_priv, u16 seq, u8 err)
> +{
> +	int signaled_seq_int;
> +	u16 signaled_seq;
> +	u16 last_emitted;
> +
> +	signaled_seq_int = atomic_read(&dev_priv-
> >fence_drv.signaled_seq);
> +	signaled_seq = (u16)signaled_seq_int;
> +	last_emitted = dev_priv->fence_drv.sync_seq;
> +
> +	if (ipvr_seq_after(seq, last_emitted)) {
> +		IPVR_DEBUG_WARN("seq error, seq is %u, signaled_seq
> is %u, "
> +				"last_emitted is %u.\n",
> +				seq, signaled_seq, last_emitted);
> +		return;
> +	}
> +	if (ipvr_seq_after(seq, signaled_seq)) {
> +		atomic_xchg(&dev_priv->fence_drv.signaled_seq, seq);
> +		dev_priv->fence_drv.last_activity = jiffies;
> +		IPVR_DEBUG_GENERAL("last emitted seq %u is updated.\n",
> seq);
> +		wake_up_all(&dev_priv->fence_queue);
> +	}
> +}
> +
> +/**
> + * ipvr_fence_signaled - check if a fence sequeuce number has signaled
> + *
> + * @dev_priv: ipvr device pointer
> + * @seq: sequence number
> + *
> + * Check if the last singled fence sequnce number is >= the requested
> + * sequence number (all asics).
> + * Returns true if the fence has signaled (current fence value
> + * is >= requested value) or false if it has not (current fence
> + * value is < the requested value.
> + */
> +static bool ipvr_fence_signaled(struct drm_ipvr_private *dev_priv, u16 seq)
> +{
> +	u16 curr_seq, signaled_seq;
> +	unsigned long irq_flags;
> +	spin_lock_irqsave(&dev_priv->fence_drv.fence_lock, irq_flags);
> +	curr_seq = dev_priv->ved_private->ved_cur_seq;
> +	signaled_seq = atomic_read(&dev_priv->fence_drv.signaled_seq);
> +
> +	if (ipvr_seq_after(seq, signaled_seq)) {
> +		/* poll new last sequence at least once */
> +		ipvr_fence_process(dev_priv, curr_seq,
> IPVR_CMD_SUCCESS);
> +		signaled_seq = atomic_read(&dev_priv-
> >fence_drv.signaled_seq);
> +		if (ipvr_seq_after(seq, signaled_seq)) {
> +			spin_unlock_irqrestore(&dev_priv-
> >fence_drv.fence_lock,
> +						irq_flags);
> +			return false;
> +		}
> +	}
> +	spin_unlock_irqrestore(&dev_priv->fence_drv.fence_lock, irq_flags);
> +	return true;
> +}
> +
> +/**
> + * ipvr_fence_lockup - ipvr lockup is detected
> + *
> + * @dev_priv: ipvr device pointer
> + * @fence: lockup detected when wait the specific fence
> + *
> + * During the calling of ipvr_fence_wait, if wait to timeout,
> + * indicate lockup happened, need flush cmd queue and reset ved
> + * If ipvr_fence_wait_empty_locked encounter lockup, fence is NULL
> + */
> +static void
> +ipvr_fence_lockup(struct drm_ipvr_private *dev_priv, struct ipvr_fence
> *fence)
> +{
> +	unsigned long irq_flags;
> +	struct ved_private *ved_priv = dev_priv->ved_private;
> +
> +	IPVR_DEBUG_WARN("timeout detected, flush queued cmd, maybe
> lockup.\n");
> +	IPVR_DEBUG_WARN("MSVDX_COMMS_FW_STATUS reg is 0x%x.\n",
> +			IPVR_REG_READ32(MSVDX_COMMS_FW_STATUS));
> +
> +	if (fence) {
> +		spin_lock_irqsave(&dev_priv->fence_drv.fence_lock,
> irq_flags);
> +		ipvr_fence_process(dev_priv, fence->seq,
> IPVR_CMD_LOCKUP);
> +		spin_unlock_irqrestore(&dev_priv->fence_drv.fence_lock,
> irq_flags);
> +	}
> +
> +	/* should behave according to ctx type in the future */
> +	ved_flush_cmd_queue(dev_priv->ved_private);
> +	ipvr_runtime_pm_put_all(dev_priv, false);
> +
> +	ved_priv->ved_needs_reset = 1;
> +}
> +
> +/**
> + * ipvr_fence_wait_seq - wait for a specific sequence number
> + *
> + * @dev_priv: ipvr device pointer
> + * @target_seq: sequence number we want to wait for
> + * @intr: use interruptable sleep
> + *
> + * Wait for the requested sequence number to be written.
> + * @intr selects whether to use interruptable (true) or non-interruptable
> + * (false) sleep when waiting for the sequence number.
> + * Returns 0 if the sequence number has passed, error for all other cases.
> + * -EDEADLK is returned when a VPU lockup has been detected.
> + */
> +static int ipvr_fence_wait_seq(struct drm_ipvr_private *dev_priv,
> +					u16 target_seq, bool intr)
> +{
> +	struct ipvr_fence_driver	*fence_drv = &dev_priv->fence_drv;
> +	unsigned long timeout, last_activity;
> +	u16 signaled_seq;
> +	int ret;
> +	unsigned long irq_flags;
> +	bool signaled;
> +	spin_lock_irqsave(&dev_priv->fence_drv.fence_lock, irq_flags);
> +
> +	while (ipvr_seq_after(target_seq,
> +			(u16)atomic_read(&fence_drv->signaled_seq))) {
> +		/* seems the fence_drv->last_activity is useless? */
> +		timeout = IPVR_FENCE_JIFFIES_TIMEOUT;
> +		signaled_seq = atomic_read(&fence_drv->signaled_seq);
> +		/* save last activity valuee, used to check for VPU lockups */
> +		last_activity = fence_drv->last_activity;
> +
> +		spin_unlock_irqrestore(&dev_priv->fence_drv.fence_lock,
> irq_flags);
> +		if (intr) {
> +			ret = wait_event_interruptible_timeout(
> +				dev_priv->fence_queue,
> +				(signaled = ipvr_fence_signaled(dev_priv,
> target_seq)),
> +				timeout);
> +		} else {
> +			ret = wait_event_timeout(
> +				dev_priv->fence_queue,
> +				(signaled = ipvr_fence_signaled(dev_priv,
> target_seq)),
> +				timeout);
> +		}
> +		spin_lock_irqsave(&dev_priv->fence_drv.fence_lock,
> irq_flags);
> +
> +		if (unlikely(!signaled)) {
> +			/* we were interrupted for some reason and fence
> +			 * isn't signaled yet, resume waiting until timeout  */
> +			if (unlikely(ret < 0)) {
> +				/* should return -ERESTARTSYS,
> +				 * interrupted by a signal */
> +				continue;
> +			}
> +
> +			/* check if sequence value has changed since
> +			 * last_activity */
> +			if (signaled_seq !=
> +				atomic_read(&fence_drv->signaled_seq)) {
> +				continue;
> +			}
> +
> +			if (last_activity != fence_drv->last_activity) {
> +				continue;
> +			}
> +
> +			/* lockup happen, it is better have some reg to check
> */
> +			IPVR_DEBUG_WARN("VPU lockup (waiting for 0x%0x
> last "
> +					"signaled fence id 0x%x).\n",
> +					target_seq, signaled_seq);
> +
> +			/* change last activity so nobody else
> +			 * think there is a lockup */
> +			fence_drv->last_activity = jiffies;
> +			spin_unlock_irqrestore(&dev_priv-
> >fence_drv.fence_lock,
> +					irq_flags);
> +			return -EDEADLK;
> +
> +		}
> +	}
> +	spin_unlock_irqrestore(&dev_priv->fence_drv.fence_lock, irq_flags);
> +	return 0;
> +}
> +
> +/**
> + * ipvr_fence_wait - wait for a fence to signal
> + *
> + * @fence: ipvr fence object
> + * @intr: use interruptable sleep
> + * @no_wait: not signaled, if need add into wait queue
> + *
> + * Wait for the requested fence to signal (all asics).
> + * @intr selects whether to use interruptable (true) or non-interruptable
> + * (false) sleep when waiting for the fence.
> + * Returns 0 if the fence has passed, error for all other cases.
> + */
> +int ipvr_fence_wait(struct ipvr_fence *fence, bool intr, bool no_wait)
> +{
> +	int ret;
> +	struct drm_ipvr_private *dev_priv;
> +
> +	if (fence == NULL || fence->seq == IPVR_FENCE_SIGNALED_SEQ) {
> +		IPVR_DEBUG_GENERAL("fence is NULL or has been
> singaled.\n");
> +		return 0;
> +	}
> +	dev_priv = fence->dev_priv;
> +
> +	IPVR_DEBUG_GENERAL("wait fence seq %u, last signaled seq is %d, "
> +			"last emitted seq is %u.\n", fence->seq,
> +			atomic_read(&dev_priv->fence_drv.signaled_seq),
> +			dev_priv->fence_drv.sync_seq);
> +	if (!no_wait)
> +		trace_ipvr_fence_wait_begin(fence,
> +			atomic_read(&dev_priv->fence_drv.signaled_seq),
> +			dev_priv->fence_drv.sync_seq);
> +
> +	if (ipvr_fence_signaled(dev_priv, fence->seq)) {
> +		IPVR_DEBUG_GENERAL("fence has been signaled.\n");
> +		/*
> +		 * compare with ttm_bo_wait, don't need create a tmp_obj
> +		 * it is better we also set bo->fence = NULL
> +		 */
> +		if (!no_wait)
> +			trace_ipvr_fence_wait_end(fence,
> +				atomic_read(&dev_priv-
> >fence_drv.signaled_seq),
> +				dev_priv->fence_drv.sync_seq);
> +		fence->seq = IPVR_FENCE_SIGNALED_SEQ;
> +		ipvr_fence_unref(&fence);
> +		return 0;
> +	}
> +
> +	if (no_wait)
> +		return -EBUSY;
> +
> +	ret = ipvr_fence_wait_seq(dev_priv, fence->seq, intr);
> +	if (ret) {
> +		if (ret == -EDEADLK) {
> +			trace_ipvr_fence_wait_lockup(fence,
> +					atomic_read(&dev_priv-
> >fence_drv.signaled_seq),
> +					dev_priv->fence_drv.sync_seq);
> +			ipvr_fence_lockup(dev_priv, fence);
> +		}
> +		return ret;
> +	}
> +	trace_ipvr_fence_wait_end(fence,
> +			atomic_read(&dev_priv->fence_drv.signaled_seq),
> +			dev_priv->fence_drv.sync_seq);
> +	fence->seq = IPVR_FENCE_SIGNALED_SEQ;
> +
> +	return 0;
> +}
> +
> +/**
> + * ipvr_fence_driver_init - init the fence driver
> + *
> + * @dev_priv: ipvr device pointer
> + *
> + * Init the fence driver, will not fail
> + */
> +void ipvr_fence_driver_init(struct drm_ipvr_private *dev_priv)
> +{
> +	spin_lock_init(&dev_priv->fence_drv.fence_lock);
> +	init_waitqueue_head(&dev_priv->fence_queue);
> +	dev_priv->fence_drv.sync_seq = 0;
> +	atomic_set(&dev_priv->fence_drv.signaled_seq, 0);
> +	dev_priv->fence_drv.last_activity = jiffies;
> +	dev_priv->fence_drv.initialized = false;
> +}
> +
> +/**
> + * ipvr_fence_wait_empty_locked - wait for all fences to signal
> + *
> + * @dev_priv: ipvr device pointer
> + *
> + * Wait for all fences to be signalled.
> + */
> +void ipvr_fence_wait_empty_locked(struct drm_ipvr_private *dev_priv)
> +{
> +	u16 seq;
> +
> +	seq = dev_priv->fence_drv.sync_seq;
> +
> +	while(1) {
> +		int ret;
> +		ret = ipvr_fence_wait_seq(dev_priv, seq, false);
> +		if (ret == 0) {
> +			return;
> +		} else if (ret == -EDEADLK) {
> +			ipvr_fence_lockup(dev_priv, NULL);
> +			IPVR_DEBUG_WARN("Lockup found waiting for
> seq %d.\n",
> +					seq);
> +			return;
> +		} else {
> +			continue;
> +		}
> +	}
> +}
> +
> +/**
> + * ipvr_fence_driver_fini - tear down the fence driver
> + * for all possible rings.
> + *
> + * @dev_priv: ipvr device pointer
> + *
> + * Tear down the fence driver for all possible rings (all asics).
> + */
> +void ipvr_fence_driver_fini(struct drm_ipvr_private *dev_priv)
> +{
> +	if (!dev_priv->fence_drv.initialized)
> +		return;
> +	ipvr_fence_wait_empty_locked(dev_priv);
> +	wake_up_all(&dev_priv->fence_queue);
> +	dev_priv->fence_drv.initialized = false;
> +}
> +
> +/**
> + * ipvr_fence_ref - take a ref on a fence
> + *
> + * @fence: fence object
> + *
> + * Take a reference on a fence (all asics).
> + * Returns the fence.
> + */
> +struct ipvr_fence *ipvr_fence_ref(struct ipvr_fence *fence)
> +{
> +	kref_get(&fence->kref);
> +	return fence;
> +}
> +
> +/**
> + * ipvr_fence_unref - remove a ref on a fence
> + *
> + * @fence: ipvr fence object
> + *
> + * Remove a reference on a fence, if ref == 0, destory the fence.
> + */
> +void ipvr_fence_unref(struct ipvr_fence **fence)
> +{
> +	struct ipvr_fence *tmp = *fence;
> +
> +	*fence = NULL;
> +	if (tmp) {
> +		kref_put(&tmp->kref, &ipvr_fence_destroy);
> +	}
> +}
> +
> +/**
> + * ipvr_fence_buffer_objects - bind fence to buffer list
> + *
> + * @list: validation buffer list
> + * @fence: ipvr fence object
> + *
> + * bind a fence to all obj in the validation list
> + */
> +void
> +ipvr_fence_buffer_objects(struct list_head *list, struct ipvr_fence *fence)
> +{
> +	struct ipvr_validate_buffer *entry;
> +	struct drm_ipvr_gem_object *obj;
> +
> +	if (list_empty(list))
> +		return;
> +
> +	list_for_each_entry(entry, list, head) {
> +		obj = entry->ipvr_gem_bo;
> +		/**
> +		 * do not update fence if val_args specifies so
> +		 */
> +		if (entry->val_req.flags & IPVR_EXEC_OBJECT_NEED_FENCE)
> {
> +			entry->old_fence = obj->fence;
> +			obj->fence = ipvr_fence_ref(fence);
> +			if (entry->old_fence)
> +				ipvr_fence_unref(&entry->old_fence);
> +		}
> +		else {
> +			IPVR_DEBUG_GENERAL("obj 0x%lx marked as non-
> fence\n",
> +				ipvr_gem_object_mmu_offset(obj));
> +		}
> +		ipvr_bo_unreserve(obj);
> +	}
> +}
> diff --git a/drivers/gpu/drm/ipvr/ipvr_fence.h
> b/drivers/gpu/drm/ipvr/ipvr_fence.h
> new file mode 100644
> index 0000000..91c1bc6
> --- /dev/null
> +++ b/drivers/gpu/drm/ipvr/ipvr_fence.h
> @@ -0,0 +1,72 @@
> +/*********************************************************
> *****************
> + * ipvr_fence.h: IPVR header file for fence handling
> + *
> + * Copyright (c) 2014 Intel Corporation, Hillsboro, OR, USA
> + * All Rights Reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of
> MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
> License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along
> with
> + * this program; if not, write to the Free Software Foundation, Inc.,
> + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
> + *
> + * Authors:
> + *    Fei Jiang <fei.jiang at intel.com>
> + *    Yao Cheng <yao.cheng at intel.com>
> + *
> +
> **********************************************************
> ****************/
> +
> +#ifndef _IPVR_FENCE_H_
> +#define _IPVR_FENCE_H_
> +
> +#include "ipvr_drv.h"
> +
> +/* seq_after(a,b) returns true if the seq a is after seq b.*/
> +#define ipvr_seq_after(a,b) \
> +    (typecheck(u16, a) && \
> +     typecheck(u16, b) && \
> +     ((s16)(a - b) > 0))
> +
> +enum ipvr_cmd_status {
> +   IPVR_CMD_SUCCESS,
> +   IPVR_CMD_FAILED,
> +   IPVR_CMD_LOCKUP,
> +   IPVR_CMD_SKIP
> +};
> +
> +#define IPVR_FENCE_JIFFIES_TIMEOUT		(HZ / 2)
> +/* fence seq are set to this number when signaled */
> +#define IPVR_FENCE_SIGNALED_SEQ		0LL
> +
> +struct ipvr_fence {
> +	struct drm_ipvr_private *dev_priv;
> +	struct kref kref;
> +	/* protected by dev_priv->fence_drv.fence_lock */
> +	u16 seq;
> +	char name[32];
> +};
> +
> +int ipvr_fence_wait(struct ipvr_fence *fence, bool intr, bool no_wait);
> +
> +void ipvr_fence_process(struct drm_ipvr_private *dev_priv, u16 seq, u8
> err);
> +
> +void ipvr_fence_driver_init(struct drm_ipvr_private *dev_priv);
> +
> +void ipvr_fence_driver_fini(struct drm_ipvr_private *dev_priv);
> +
> +struct ipvr_fence* __must_check ipvr_fence_create(struct
> drm_ipvr_private *dev_priv);
> +
> +void ipvr_fence_buffer_objects(struct list_head *list, struct ipvr_fence
> *fence);
> +
> +void ipvr_fence_unref(struct ipvr_fence **fence);
> +
> +void ipvr_fence_wait_empty_locked(struct drm_ipvr_private *dev_priv);
> +
> +#endif
> diff --git a/drivers/gpu/drm/ipvr/ipvr_gem.c
> b/drivers/gpu/drm/ipvr/ipvr_gem.c
> new file mode 100644
> index 0000000..94c266a
> --- /dev/null
> +++ b/drivers/gpu/drm/ipvr/ipvr_gem.c
> @@ -0,0 +1,297 @@
> +/*********************************************************
> *****************
> + * ipvr_gem.c: IPVR hook file for gem ioctls
> + *
> + * Copyright (c) 2014 Intel Corporation, Hillsboro, OR, USA
> + * All Rights Reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of
> MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
> License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along
> with
> + * this program; if not, write to the Free Software Foundation, Inc.,
> + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
> + *
> + * Authors:
> + *    Fei Jiang <fei.jiang at intel.com>
> + *    Yao Cheng <yao.cheng at intel.com>
> + *
> +
> **********************************************************
> ****************/
> +
> +#include "ipvr_gem.h"
> +#include "ipvr_bo.h"
> +#include "ipvr_fence.h"
> +#include "ipvr_exec.h"
> +#include "ipvr_trace.h"
> +#include <drm_gem.h>
> +#include <linux/slab.h>
> +#include <linux/swap.h>
> +#include <linux/pci.h>
> +#include <linux/dma-buf.h>
> +
> +#define VLV_IPVR_DEV_ID (0xf31)
> +
> +int
> +ipvr_context_create_ioctl(struct drm_device *dev,
> +			void *data, struct drm_file *file_priv)
> +{
> +	struct drm_ipvr_context_create *args = data;
> +	struct drm_ipvr_private *dev_priv = dev->dev_private;
> +	struct drm_ipvr_file_private *fpriv = file_priv->driver_priv;
> +	struct ipvr_context *ipvr_ctx  = NULL;
> +	unsigned long irq_flags;
> +	int ctx_id, ret = 0;
> +
> +	IPVR_DEBUG_ENTRY("enter\n");
> +	/*
> +	 * todo: only one tiling region is supported now,
> +	 * maybe we need create additional tiling region for rotation case,
> +	 * which has different tiling stride
> +	 */
> +	if (!(args->tiling_scheme == 0 && args->tiling_stride <= 3) &&
> +		!(args->tiling_scheme == 1 && args->tiling_stride <= 2)) {
> +		IPVR_DEBUG_WARN("unsupported tiling scheme %d and
> stide %d.\n",
> +			args->tiling_scheme, args->tiling_stride);
> +		return -EINVAL;
> +	}
> +	/* add video decode context */
> +	ipvr_ctx = kzalloc(sizeof(struct ipvr_context), GFP_KERNEL);
> +	if (ipvr_ctx  == NULL)
> +		return -ENOMEM;
> +
> +	spin_lock_irqsave(&dev_priv->ipvr_ctx_lock, irq_flags);
> +	ctx_id = idr_alloc(&dev_priv->ipvr_ctx_idr, ipvr_ctx ,
> +			   IPVR_MIN_CONTEXT_ID, IPVR_MAX_CONTEXT_ID,
> +			   GFP_NOWAIT);
> +	if (ctx_id < 0) {
> +		IPVR_ERROR("idr_alloc got %d, return ENOMEM\n", ctx_id);
> +		spin_unlock_irqrestore(&dev_priv->ipvr_ctx_lock, irq_flags);
> +		return -ENOMEM;
> +	}
> +	ipvr_ctx->ctx_id = ctx_id;
> +
> +	INIT_LIST_HEAD(&ipvr_ctx->head);
> +	ipvr_ctx->ctx_type = args->ctx_type;
> +	ipvr_ctx->ipvr_fpriv = file_priv->driver_priv;
> +	list_add(&ipvr_ctx ->head, &fpriv->ctx_list);
> +	spin_unlock_irqrestore(&dev_priv->ipvr_ctx_lock, irq_flags);
> +	args->ctx_id = ctx_id;
> +	IPVR_DEBUG_INIT("add ctx type 0x%x, ctx_id is %d.\n",
> +			ipvr_ctx->ctx_type, ctx_id);
> +
> +	ipvr_ctx->tiling_scheme = args->tiling_scheme;
> +	ipvr_ctx->tiling_stride = args->tiling_stride;
> +
> +	return ret;
> +}
> +
> +int
> +ipvr_context_destroy_ioctl(struct drm_device *dev,
> +			void *data, struct drm_file *file_priv)
> +{
> +	struct drm_ipvr_context_destroy *args = data;
> +	struct ved_private *ved_priv;
> +	struct drm_ipvr_private *dev_priv = dev->dev_private;
> +	struct ipvr_context *ipvr_ctx  = NULL;
> +	unsigned long irq_flags;
> +
> +	IPVR_DEBUG_ENTRY("enter\n");
> +	spin_lock_irqsave(&dev_priv->ipvr_ctx_lock, irq_flags);
> +	ved_priv = dev_priv->ved_private;
> +	if (ved_priv && (!list_empty(&ved_priv->ved_queue)
> +			|| (atomic_read(&dev_priv->pending_events) > 0)))
> {
> +		IPVR_DEBUG_WARN("Destroying the context while pending
> cmds exist!\n");
> +	}
> +	ipvr_ctx = (struct ipvr_context *)
> +			idr_find(&dev_priv->ipvr_ctx_idr, args->ctx_id);
> +	if (!ipvr_ctx) {
> +		IPVR_ERROR("can not find given context %u\n", args-
> >ctx_id);
> +		spin_unlock_irqrestore(&dev_priv->ipvr_ctx_lock, irq_flags);
> +		return -EINVAL;
> +	}
> +
> +	if (ipvr_ctx->ipvr_fpriv != file_priv->driver_priv) {
> +		IPVR_ERROR("given contex %u doesn't belong to the file\n",
> args->ctx_id);
> +		spin_unlock_irqrestore(&dev_priv->ipvr_ctx_lock, irq_flags);
> +		return -ENOENT;
> +	}
> +
> +	IPVR_DEBUG_GENERAL("Video:remove context %d type 0x%x\n",
> +		ipvr_ctx->ctx_id, ipvr_ctx->ctx_type);
> +	list_del(&ipvr_ctx->head);
> +	idr_remove(&dev_priv->ipvr_ctx_idr, ipvr_ctx->ctx_id);
> +	kfree(ipvr_ctx);
> +	spin_unlock_irqrestore(&dev_priv->ipvr_ctx_lock, irq_flags);
> +	return 0;
> +}
> +
> +int
> +ipvr_get_info_ioctl(struct drm_device *dev, void *data,
> +			struct drm_file *file_priv)
> +{
> +	struct drm_ipvr_private *dev_priv = dev->dev_private;
> +	struct drm_ipvr_get_info *args = data;
> +	int ret = 0;
> +
> +	IPVR_DEBUG_ENTRY("enter\n");
> +	if (!dev_priv) {
> +		IPVR_DEBUG_WARN("called with no initialization.\n");
> +		return -ENODEV;
> +	}
> +	switch (args->key) {
> +	case IPVR_DEVICE_INFO: {
> +		/* only vlv supported now
> +		 */
> +		args->value = VLV_IPVR_DEV_ID << 16;
> +		break;
> +	}
> +	default:
> +		ret = -EINVAL;
> +		break;
> +	}
> +	return ret;
> +}
> +
> +int ipvr_gem_create_ioctl(struct drm_device *dev, void *data,
> +				struct drm_file *file_priv)
> +{
> +	int ret;
> +	struct drm_ipvr_gem_create *args = data;
> +	struct drm_ipvr_gem_object *obj;
> +	struct drm_ipvr_private *dev_priv = dev->dev_private;
> +	if (args->cache_level >= IPVR_CACHE_MAX)
> +		return -EINVAL;
> +	if (args->size == 0)
> +		return -EINVAL;
> +	args->rounded_size = roundup(args->size, PAGE_SIZE);
> +	obj = ipvr_gem_create(dev_priv, args->rounded_size, args->tiling,
> +			      args->cache_level);
> +	if (IS_ERR(obj)) {
> +		ret = PTR_ERR(obj);
> +		goto out;
> +	}
> +	args->mmu_offset = ipvr_gem_object_mmu_offset(obj);
> +	/* create handle */
> +	ret = drm_gem_handle_create(file_priv, &obj->base, &args-
> >handle);
> +	if (ret) {
> +		IPVR_ERROR("could not allocate mmap offset: %d\n", ret);
> +		goto out_free;
> +	}
> +	/* drop reference from allocate - handle holds it now */
> +	drm_gem_object_unreference_unlocked(&obj->base);
> +	/* create map offset */
> +	ret = drm_gem_create_mmap_offset(&obj->base);
> +	if (ret) {
> +		IPVR_ERROR("could not allocate mmap offset: %d\n", ret);
> +		goto out_free;
> +	}
> +	args->map_offset = drm_vma_node_offset_addr(&obj-
> >base.vma_node);
> +	IPVR_DEBUG_GENERAL("bo create done, handle: %u, vpu offset:
> 0x%llx.\n",
> +		args->handle, args->mmu_offset);
> +	return 0;
> +out_free:
> +	ipvr_gem_free_object(&obj->base);
> +out:
> +	return ret;
> +}
> +
> +int ipvr_gem_busy_ioctl(struct drm_device *dev, void *data,
> +				struct drm_file *file_priv)
> +{
> +	struct drm_ipvr_gem_busy *args = data;
> +	struct drm_ipvr_gem_object *obj;
> +	int ret = 0;
> +
> +	obj = to_ipvr_bo(drm_gem_object_lookup(dev, file_priv, args-
> >handle));
> +	if (!obj || &obj->base == NULL) {
> +		return -ENOENT;
> +	}
> +	IPVR_DEBUG_GENERAL("Checking bo %p (fence %p seq %u) busy
> status\n",
> +        obj, obj->fence, ((obj->fence)? obj->fence->seq: 0));
> +
> +	ret = ipvr_bo_reserve(obj, true, false);
> +	if (unlikely(ret != 0))
> +		goto out;
> +	ret = ipvr_fence_wait(obj->fence, true, true);
> +	ipvr_bo_unreserve(obj);
> +
> +    args->busy = ret? 1: 0;
> +out:
> +	drm_gem_object_unreference_unlocked(&obj->base);
> +	return ret;
> +}
> +
> +/**
> + * ipvr_gem_wait_ioctl - implements DRM_IOCTL_IPVR_GEM_WAIT
> + * @DRM_IOCTL_ARGS: standard ioctl arguments
> + *
> + * Returns 0 if successful, else an error is returned with the remaining time
> in
> + * the timeout parameter.
> + *  -ETIME: object is still busy after timeout
> + *  -ERESTARTSYS: signal interrupted the wait
> + *  -ENONENT: object doesn't exist
> + * Also possible, but rare:
> + *  -EAGAIN: VPU wedged
> + *  -ENOMEM: damn
> + *  -ENODEV: Internal IRQ fail
> + *  -E?: The add request failed
> + *
> + * The wait ioctl with a timeout of 0 reimplements the busy ioctl. With any
> + * non-zero timeout parameter the wait ioctl will wait for the given number
> of
> + * nanoseconds on an object becoming unbusy. Since the wait itself does so
> + * without holding struct_mutex the object may become re-busied before
> this
> + * function completes. A similar but shorter * race condition exists in the
> busy
> + * ioctl
> + */
> +int ipvr_gem_wait_ioctl(struct drm_device *dev,
> +				void *data, struct drm_file *file_priv)
> +{
> +	struct drm_ipvr_gem_wait *args = data;
> +	struct drm_ipvr_gem_object *obj;
> +	int ret = 0;
> +
> +	IPVR_DEBUG_ENTRY("wait %d buffer to finish execution.\n", args-
> >handle);
> +	obj = to_ipvr_bo(drm_gem_object_lookup(dev, file_priv, args-
> >handle));
> +	if (&obj->base == NULL) {
> +		return -ENOENT;
> +	}
> +
> +	ret = ipvr_bo_reserve(obj, true, false);
> +	if (unlikely(ret != 0))
> +		goto out;
> +
> +	ret = ipvr_fence_wait(obj->fence, true, false);
> +
> +	ipvr_bo_unreserve(obj);
> +
> +out:
> +	drm_gem_object_unreference_unlocked(&obj->base);
> +	return ret;
> +}
> +
> +int ipvr_gem_mmap_offset_ioctl(struct drm_device *dev,
> +				void *data, struct drm_file *file_priv)
> +{
> +	int ret = 0;
> +	struct drm_ipvr_gem_mmap_offset *args = data;
> +	struct drm_ipvr_gem_object *obj;
> +
> +	IPVR_DEBUG_ENTRY("getting mmap offset for BO %u.\n", args-
> >handle);
> +	obj = to_ipvr_bo(drm_gem_object_lookup(dev, file_priv, args-
> >handle));
> +
> +	/* create map offset */
> +	ret = drm_gem_create_mmap_offset(&obj->base);
> +	if (ret) {
> +		IPVR_ERROR("could not allocate mmap offset: %d\n", ret);
> +		goto out;
> +	}
> +	args->offset = drm_vma_node_offset_addr(&obj->base.vma_node);
> +out:
> +	drm_gem_object_unreference_unlocked(&obj->base);
> +	return ret;
> +}
> diff --git a/drivers/gpu/drm/ipvr/ipvr_gem.h
> b/drivers/gpu/drm/ipvr/ipvr_gem.h
> new file mode 100644
> index 0000000..525f630
> --- /dev/null
> +++ b/drivers/gpu/drm/ipvr/ipvr_gem.h
> @@ -0,0 +1,48 @@
> +/*********************************************************
> *****************
> + * ipvr_gem.h: IPVR header file for GEM ioctls
> + *
> + * Copyright (c) 2014 Intel Corporation, Hillsboro, OR, USA
> + * All Rights Reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of
> MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
> License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along
> with
> + * this program; if not, write to the Free Software Foundation, Inc.,
> + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
> + *
> + * Authors:
> + *    Fei Jiang <fei.jiang at intel.com>
> + *    Yao Cheng <yao.cheng at intel.com>
> + *
> +
> **********************************************************
> ****************/
> +
> +#ifndef _IPVR_GEM_H_
> +#define _IPVR_GEM_H_
> +
> +#include "ipvr_drv.h"
> +
> +int ipvr_context_create_ioctl(struct drm_device *dev,
> +			void *data, struct drm_file *file_priv);
> +int ipvr_context_destroy_ioctl(struct drm_device *dev,
> +			void *data, struct drm_file *file_priv);
> +int ipvr_get_info_ioctl(struct drm_device *dev,
> +			void *data,	struct drm_file *file_priv);
> +int ipvr_gem_execbuffer_ioctl(struct drm_device *dev,
> +			void *data, struct drm_file *file_priv);
> +int ipvr_gem_busy_ioctl(struct drm_device *dev,
> +			void *data, struct drm_file *file_priv);
> +int ipvr_gem_create_ioctl(struct drm_device *dev,
> +			void *data, struct drm_file *file_priv);
> +int ipvr_gem_wait_ioctl(struct drm_device *dev,
> +			void *data, struct drm_file *file_priv);
> +int ipvr_gem_mmap_offset_ioctl(struct drm_device *dev,
> +			void *data, struct drm_file *file_priv);
> +
> +#endif
> diff --git a/drivers/gpu/drm/ipvr/ipvr_mmu.c
> b/drivers/gpu/drm/ipvr/ipvr_mmu.c
> new file mode 100644
> index 0000000..0f8f364
> --- /dev/null
> +++ b/drivers/gpu/drm/ipvr/ipvr_mmu.c
> @@ -0,0 +1,752 @@
> +/*********************************************************
> *****************
> + * ipvr_mmu.c: IPVR MMU handling to support VED, VEC, VSP buffer access
> + *
> + * Copyright (c) 2014 Intel Corporation, Hillsboro, OR, USA
> + * Copyright (c) Imagination Technologies Limited, UK
> + * Copyright (c) 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
> + * All Rights Reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of
> MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
> License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along
> with
> + * this program; if not, write to the Free Software Foundation, Inc.,
> + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
> + *
> + * Authors:
> + *    Fei Jiang <fei.jiang at intel.com>
> + *    Yao Cheng <yao.cheng at intel.com>
> + *
> +
> **********************************************************
> ****************/
> +
> +#include "ipvr_mmu.h"
> +#include "ipvr_debug.h"
> +
> +/*
> + * Code for the VED MMU
> + * Assumes system page size is same with VED (4KiB).
> + * Doesn't work for the case of page size mismatch.
> + */
> +
> +/*
> + * clflush on one processor only:
> + * clflush should apparently flush the cache line on all processors in an
> + * SMP system.
> + */
> +
> +/*
> + * kmap atomic:
> + * Usage of the slots must be completely encapsulated within a spinlock,
> and
> + * no other functions that may be using the locks for other purposed may
> be
> + * called from within the locked region.
> + * Since the slots are per processor, this will guarantee that we are the only
> + * user.
> + */
> +
> +/*
> + *PTE's and PDE's
> + */
> +#define IPVR_PDE_MASK		0x003FFFFF
> +#define IPVR_PDE_SHIFT		22
> +#define IPVR_PTE_SHIFT		12
> +#define IPVR_PTE_VALID		0x0001	/* PTE / PDE valid */
> +#define IPVR_PTE_WO			0x0002	/* Write only */
> +#define IPVR_PTE_RO			0x0004	/* Read only */
> +#define IPVR_PTE_CACHED		0x0008	/* CPU cache coherent */
> +
> +struct ipvr_mmu_pt {
> +	struct ipvr_mmu_pd *pd;
> +	u32 index;
> +	u32 count;
> +	struct page *p;
> +	u32 *v;
> +};
> +
> +struct ipvr_mmu_pd {
> +	struct ipvr_mmu_driver *driver;
> +	u32 hw_context;
> +	struct ipvr_mmu_pt **tables;
> +	struct page *p;
> +	struct page *dummy_pt;
> +	struct page *dummy_page;
> +	u32 pd_mask;
> +	u32 invalid_pde;
> +	u32 invalid_pte;
> +};
> +
> +static inline u32 ipvr_mmu_pt_index(u32 offset)
> +{
> +	return (offset >> IPVR_PTE_SHIFT) & 0x3FF;
> +}
> +
> +static inline u32 ipvr_mmu_pd_index(u32 offset)
> +{
> +	return offset >> IPVR_PDE_SHIFT;
> +}
> +
> +#if defined(CONFIG_X86)
> +static inline void ipvr_clflush(void *addr)
> +{
> +	__asm__ __volatile__("clflush (%0)\n" : : "r"(addr) : "memory");
> +}
> +
> +static inline void
> +ipvr_mmu_clflush(struct ipvr_mmu_driver *driver, void *addr)
> +{
> +	if (!driver->has_clflush)
> +		return;
> +
> +	mb();
> +	ipvr_clflush(addr);
> +	mb();
> +}
> +
> +static void
> +ipvr_mmu_page_clflush(struct ipvr_mmu_driver *driver, struct page* page)
> +{
> +	u32 clflush_add = driver->clflush_add >> PAGE_SHIFT;
> +	u32 clflush_count = PAGE_SIZE / clflush_add;
> +	int i;
> +	u8 *clf;
> +
> +	clf = kmap_atomic(page);
> +
> +	mb();
> +	for (i = 0; i < clflush_count; ++i) {
> +		ipvr_clflush(clf);
> +		clf += clflush_add;
> +	}
> +	mb();
> +
> +	kunmap_atomic(clf);
> +}
> +
> +static void ipvr_mmu_pages_clflush(struct ipvr_mmu_driver *driver,
> +				struct page *page[], int num_pages)
> +{
> +	int i;
> +
> +	if (!driver->has_clflush)
> +		return ;
> +
> +	for (i = 0; i < num_pages; i++)
> +		ipvr_mmu_page_clflush(driver, *page++);
> +}
> +#else
> +
> +static inline void
> +ipvr_mmu_clflush(struct ipvr_mmu_driver *driver, void *addr)
> +{
> +	;
> +}
> +
> +static void ipvr_mmu_pages_clflush(struct ipvr_mmu_driver *driver,
> +				struct page *page[], int num_pages)
> +{
> +	IPVR_DEBUG_GENERAL("Dumy ipvr_mmu_pages_clflush\n");
> +}
> +
> +#endif
> +
> +static void
> +ipvr_mmu_flush_pd_locked(struct ipvr_mmu_driver *driver, bool force)
> +{
> +	if (atomic_read(&driver->needs_tlbflush) || force) {
> +		if (!driver->dev_priv)
> +			goto out;
> +
> +		atomic_set(&driver->dev_priv->ipvr_mmu_invaldc, 1);
> +	}
> +out:
> +	atomic_set(&driver->needs_tlbflush, 0);
> +}
> +
> +static void ipvr_mmu_flush(struct ipvr_mmu_driver *driver, bool rc_prot)
> +{
> +	if (rc_prot)
> +		down_write(&driver->sem);
> +
> +	if (!driver->dev_priv)
> +		goto out;
> +
> +	atomic_set(&driver->dev_priv->ipvr_mmu_invaldc, 1);
> +
> +out:
> +	if (rc_prot)
> +		up_write(&driver->sem);
> +}
> +
> +void ipvr_mmu_set_pd_context(struct ipvr_mmu_pd *pd, u32 hw_context)
> +{
> +	ipvr_mmu_pages_clflush(pd->driver, &pd->p, 1);
> +	down_write(&pd->driver->sem);
> +	wmb();
> +	ipvr_mmu_flush_pd_locked(pd->driver, 1);
> +	pd->hw_context = hw_context;
> +	up_write(&pd->driver->sem);
> +}
> +
> +static inline unsigned long
> +ipvr_pd_addr_end(unsigned long addr, unsigned long end)
> +{
> +
> +	addr = (addr + IPVR_PDE_MASK + 1) & ~IPVR_PDE_MASK;
> +	return (addr < end) ? addr : end;
> +}
> +
> +static inline u32 ipvr_mmu_mask_pte(u32 pfn, u32 type)
> +{
> +	u32 mask = IPVR_PTE_VALID;
> +
> +	if (type & IPVR_MMU_CACHED_MEMORY)
> +		mask |= IPVR_PTE_CACHED;
> +	if (type & IPVR_MMU_RO_MEMORY)
> +		mask |= IPVR_PTE_RO;
> +	if (type & IPVR_MMU_WO_MEMORY)
> +		mask |= IPVR_PTE_WO;
> +
> +	return (pfn << PAGE_SHIFT) | mask;
> +}
> +
> +static struct ipvr_mmu_pd* __must_check
> +ipvr_mmu_alloc_pd(struct ipvr_mmu_driver *driver, u32 invalid_type)
> +{
> +	struct ipvr_mmu_pd *pd = kmalloc(sizeof(*pd), GFP_KERNEL);
> +	u32 *v;
> +	int i;
> +
> +	if (!pd)
> +		return NULL;
> +
> +	pd->p = alloc_page(GFP_DMA32);
> +	if (!pd->p)
> +		goto out_err1;
> +	pd->dummy_pt = alloc_page(GFP_DMA32);
> +	if (!pd->dummy_pt)
> +		goto out_err2;
> +	pd->dummy_page = alloc_page(GFP_DMA32);
> +	if (!pd->dummy_page)
> +		goto out_err3;
> +
> +	pd->invalid_pde =
> +		ipvr_mmu_mask_pte(page_to_pfn(pd->dummy_pt),
> invalid_type);
> +	pd->invalid_pte =
> +		ipvr_mmu_mask_pte(page_to_pfn(pd->dummy_page),
> invalid_type);
> +
> +	v = kmap(pd->dummy_pt);
> +	if (!v)
> +		goto out_err4;
> +	for (i = 0; i < (PAGE_SIZE / sizeof(u32)); ++i)
> +		v[i] = pd->invalid_pte;
> +
> +	kunmap(pd->dummy_pt);
> +
> +	v = kmap(pd->p);
> +	if (!v)
> +		goto out_err4;
> +	for (i = 0; i < (PAGE_SIZE / sizeof(u32)); ++i)
> +		v[i] = pd->invalid_pde;
> +
> +	kunmap(pd->p);
> +
> +	v = kmap(pd->dummy_page);
> +	if (!v)
> +		goto out_err4;
> +	clear_page(v);
> +	kunmap(pd->dummy_page);
> +
> +	pd->tables = vmalloc_user(sizeof(struct ipvr_mmu_pt *) * 1024);
> +	if (!pd->tables)
> +		goto out_err4;
> +
> +	pd->hw_context = -1;
> +	pd->pd_mask = IPVR_PTE_VALID;
> +	pd->driver = driver;
> +
> +	return pd;
> +
> +out_err4:
> +	__free_page(pd->dummy_page);
> +out_err3:
> +	__free_page(pd->dummy_pt);
> +out_err2:
> +	__free_page(pd->p);
> +out_err1:
> +	kfree(pd);
> +	return NULL;
> +}
> +
> +static void ipvr_mmu_free_pt(struct ipvr_mmu_pt *pt)
> +{
> +	__free_page(pt->p);
> +	kfree(pt);
> +}
> +
> +static void ipvr_mmu_free_pagedir(struct ipvr_mmu_pd *pd)
> +{
> +	struct ipvr_mmu_driver *driver = pd->driver;
> +	struct ipvr_mmu_pt *pt;
> +	int i;
> +
> +	down_write(&driver->sem);
> +	if (pd->hw_context != -1)
> +		ipvr_mmu_flush_pd_locked(driver, 1);
> +
> +	/* Should take the spinlock here, but we don't need to do that
> +	   since we have the semaphore in write mode. */
> +
> +	for (i = 0; i < 1024; ++i) {
> +		pt = pd->tables[i];
> +		if (pt)
> +			ipvr_mmu_free_pt(pt);
> +	}
> +
> +	vfree(pd->tables);
> +	__free_page(pd->dummy_page);
> +	__free_page(pd->dummy_pt);
> +	__free_page(pd->p);
> +	kfree(pd);
> +	up_write(&driver->sem);
> +}
> +
> +static struct ipvr_mmu_pt *ipvr_mmu_alloc_pt(struct ipvr_mmu_pd *pd)
> +{
> +	struct ipvr_mmu_pt *pt = kmalloc(sizeof(*pt), GFP_KERNEL);
> +	void *v;
> +	u32 clflush_add = pd->driver->clflush_add >> PAGE_SHIFT;
> +	u32 clflush_count = PAGE_SIZE / clflush_add;
> +	spinlock_t *lock = &pd->driver->lock;
> +	u8 *clf;
> +	u32 *ptes;
> +	int i;
> +
> +	if (!pt)
> +		return NULL;
> +
> +	pt->p = alloc_page(GFP_DMA32);
> +	if (!pt->p) {
> +		kfree(pt);
> +		return NULL;
> +	}
> +
> +	spin_lock(lock);
> +
> +	v = kmap_atomic(pt->p);
> +
> +	clf = (u8 *) v;
> +	ptes = (u32 *) v;
> +	for (i = 0; i < (PAGE_SIZE / sizeof(u32)); ++i)
> +		*ptes++ = pd->invalid_pte;
> +
> +
> +#if defined(CONFIG_X86)
> +	if (pd->driver->has_clflush && pd->hw_context != -1) {
> +		mb();
> +		for (i = 0; i < clflush_count; ++i) {
> +			ipvr_clflush(clf);
> +			clf += clflush_add;
> +		}
> +		mb();
> +	}
> +#endif
> +	kunmap_atomic(v);
> +
> +	spin_unlock(lock);
> +
> +	pt->count = 0;
> +	pt->pd = pd;
> +	pt->index = 0;
> +
> +	return pt;
> +}
> +
> +static struct ipvr_mmu_pt *
> +ipvr_mmu_pt_alloc_map_lock(struct ipvr_mmu_pd *pd, unsigned long
> addr)
> +{
> +	u32 index = ipvr_mmu_pd_index(addr);
> +	struct ipvr_mmu_pt *pt;
> +	u32 *v;
> +	spinlock_t *lock = &pd->driver->lock;
> +
> +	spin_lock(lock);
> +	pt = pd->tables[index];
> +	while (!pt) {
> +		spin_unlock(lock);
> +		pt = ipvr_mmu_alloc_pt(pd);
> +		if (!pt)
> +			return NULL;
> +		spin_lock(lock);
> +
> +		if (pd->tables[index]) {
> +			spin_unlock(lock);
> +			ipvr_mmu_free_pt(pt);
> +			spin_lock(lock);
> +			pt = pd->tables[index];
> +			continue;
> +		}
> +
> +		v = kmap_atomic(pd->p);
> +
> +		pd->tables[index] = pt;
> +		v[index] = (page_to_pfn(pt->p) << 12) |
> +			pd->pd_mask;
> +
> +
> +		pt->index = index;
> +
> +		kunmap_atomic((void *) v);
> +
> +		if (pd->hw_context != -1) {
> +			ipvr_mmu_clflush(pd->driver, (void *) &v[index]);
> +			atomic_set(&pd->driver->needs_tlbflush, 1);
> +		}
> +	}
> +
> +	pt->v = kmap_atomic(pt->p);
> +
> +	return pt;
> +}
> +
> +static struct ipvr_mmu_pt *
> +ipvr_mmu_pt_map_lock(struct ipvr_mmu_pd *pd, unsigned long addr)
> +{
> +	u32 index = ipvr_mmu_pd_index(addr);
> +	struct ipvr_mmu_pt *pt;
> +	spinlock_t *lock = &pd->driver->lock;
> +
> +	spin_lock(lock);
> +	pt = pd->tables[index];
> +	if (!pt) {
> +		spin_unlock(lock);
> +		return NULL;
> +	}
> +
> +	pt->v = kmap_atomic(pt->p);
> +
> +	return pt;
> +}
> +
> +static void ipvr_mmu_pt_unmap_unlock(struct ipvr_mmu_pt *pt)
> +{
> +	struct ipvr_mmu_pd *pd = pt->pd;
> +	u32 *v;
> +
> +	kunmap_atomic(pt->v);
> +
> +	if (pt->count == 0) {
> +		v = kmap_atomic(pd->p);
> +
> +		v[pt->index] = pd->invalid_pde;
> +		pd->tables[pt->index] = NULL;
> +
> +		if (pd->hw_context != -1) {
> +			ipvr_mmu_clflush(pd->driver,
> +					(void *) &v[pt->index]);
> +			atomic_set(&pd->driver->needs_tlbflush, 1);
> +		}
> +
> +		kunmap_atomic(pt->v);
> +
> +		spin_unlock(&pd->driver->lock);
> +		ipvr_mmu_free_pt(pt);
> +		return;
> +	}
> +	spin_unlock(&pd->driver->lock);
> +}
> +
> +static inline void
> +ipvr_mmu_set_pte(struct ipvr_mmu_pt *pt, unsigned long addr, u32 pte)
> +{
> +	pt->v[ipvr_mmu_pt_index(addr)] = pte;
> +}
> +
> +static inline void
> +ipvr_mmu_invalidate_pte(struct ipvr_mmu_pt *pt, unsigned long addr)
> +{
> +	pt->v[ipvr_mmu_pt_index(addr)] = pt->pd->invalid_pte;
> +}
> +
> +struct ipvr_mmu_pd *ipvr_mmu_get_default_pd(struct ipvr_mmu_driver
> *driver)
> +{
> +	struct ipvr_mmu_pd *pd;
> +
> +	/* down_read(&driver->sem); */
> +	pd = driver->default_pd;
> +	/* up_read(&driver->sem); */
> +
> +	return pd;
> +}
> +
> +/* Returns the physical address of the PD shared by sgx/msvdx */
> +u32 __must_check ipvr_get_default_pd_addr32(struct ipvr_mmu_driver
> *driver)
> +{
> +	struct ipvr_mmu_pd *pd;
> +	unsigned long pfn;
> +	pd = ipvr_mmu_get_default_pd(driver);
> +	pfn = page_to_pfn(pd->p);
> +	if (pfn >= 0x00100000UL)
> +		return 0;
> +	return pfn << PAGE_SHIFT;
> +}
> +
> +void ipvr_mmu_driver_takedown(struct ipvr_mmu_driver *driver)
> +{
> +	ipvr_mmu_free_pagedir(driver->default_pd);
> +	kfree(driver);
> +}
> +
> +struct ipvr_mmu_driver * __must_check
> +ipvr_mmu_driver_init(u8 __iomem * registers, u32 invalid_type,
> +			struct drm_ipvr_private *dev_priv)
> +{
> +	struct ipvr_mmu_driver *driver;
> +
> +	driver = kmalloc(sizeof(*driver), GFP_KERNEL);
> +	if (!driver)
> +		return NULL;
> +
> +	driver->dev_priv = dev_priv;
> +
> +	driver->default_pd =
> +		ipvr_mmu_alloc_pd(driver, invalid_type);
> +	if (!driver->default_pd)
> +		goto out_err1;
> +
> +	spin_lock_init(&driver->lock);
> +	init_rwsem(&driver->sem);
> +	down_write(&driver->sem);
> +	driver->register_map = registers;
> +	atomic_set(&driver->needs_tlbflush, 1);
> +
> +	driver->has_clflush = false;
> +
> +#if defined(CONFIG_X86)
> +	if (cpu_has_clflush) {
> +		u32 tfms, misc, cap0, cap4, clflush_size;
> +
> +		/*
> +		 * clflush size is determined at kernel setup for x86_64
> +		 *  but not for i386. We have to do it here.
> +		 */
> +
> +		cpuid(0x00000001, &tfms, &misc, &cap0, &cap4);
> +		clflush_size = ((misc >> 8) & 0xff) * 8;
> +		driver->has_clflush = true;
> +		driver->clflush_add =
> +			PAGE_SIZE * clflush_size / sizeof(u32);
> +		driver->clflush_mask = driver->clflush_add - 1;
> +		driver->clflush_mask = ~driver->clflush_mask;
> +	}
> +#endif
> +
> +	up_write(&driver->sem);
> +	return driver;
> +
> +out_err1:
> +	kfree(driver);
> +	return NULL;
> +}
> +
> +#if defined(CONFIG_X86)
> +static void ipvr_mmu_flush_ptes(struct ipvr_mmu_pd *pd,
> +			unsigned long address,
> +			int num_pages,
> +			u32 desired_tile_stride,
> +			u32 hw_tile_stride)
> +{
> +	struct ipvr_mmu_pt *pt;
> +	int rows = 1;
> +	int i;
> +	unsigned long addr;
> +	unsigned long end;
> +	unsigned long next;
> +	unsigned long add;
> +	unsigned long row_add;
> +	unsigned long clflush_add = pd->driver->clflush_add;
> +	unsigned long clflush_mask = pd->driver->clflush_mask;
> +	IPVR_DEBUG_GENERAL("call x86 ipvr_mmu_flush_ptes, address is
> 0x%lx, "
> +			"num pages is %d.\n", address, num_pages);
> +	if (!pd->driver->has_clflush) {
> +		IPVR_DEBUG_GENERAL("call ipvr_mmu_pages_clflush.\n");
> +		ipvr_mmu_pages_clflush(pd->driver, &pd->p, num_pages);
> +		return;
> +	}
> +
> +	if (hw_tile_stride)
> +		rows = num_pages / desired_tile_stride;
> +	else
> +		desired_tile_stride = num_pages;
> +
> +	add = desired_tile_stride << PAGE_SHIFT;
> +	row_add = hw_tile_stride << PAGE_SHIFT;
> +	mb();
> +	for (i = 0; i < rows; ++i) {
> +		addr = address;
> +		end = addr + add;
> +
> +		do {
> +			next = ipvr_pd_addr_end(addr, end);
> +			pt = ipvr_mmu_pt_map_lock(pd, addr);
> +			if (!pt)
> +				continue;
> +			do {
> +				ipvr_clflush(&pt-
> >v[ipvr_mmu_pt_index(addr)]);
> +			} while (addr +=
> +					 clflush_add,
> +				 (addr & clflush_mask) < next);
> +
> +			ipvr_mmu_pt_unmap_unlock(pt);
> +		} while (addr = next, next != end);
> +		address += row_add;
> +	}
> +	mb();
> +}
> +#else
> +
> +static void ipvr_mmu_flush_ptes(struct ipvr_mmu_pd *pd,
> +					unsigned long address,
> +					int num_pages,
> +					u32 desired_tile_stride,
> +					u32 hw_tile_stride)
> +{
> +	IPVR_DEBUG_GENERAL("call non-x86 ipvr_mmu_flush_ptes.\n");
> +}
> +#endif
> +
> +void ipvr_mmu_remove_pages(struct ipvr_mmu_pd *pd, unsigned long
> address,
> +			int num_pages, u32 desired_tile_stride,
> +			u32 hw_tile_stride)
> +{
> +	struct ipvr_mmu_pt *pt;
> +	int rows = 1;
> +	int i;
> +	unsigned long addr;
> +	unsigned long end;
> +	unsigned long next;
> +	unsigned long add;
> +	unsigned long row_add;
> +	unsigned long f_address = address;
> +
> +	if (hw_tile_stride)
> +		rows = num_pages / desired_tile_stride;
> +	else
> +		desired_tile_stride = num_pages;
> +
> +	add = desired_tile_stride << PAGE_SHIFT;
> +	row_add = hw_tile_stride << PAGE_SHIFT;
> +
> +	/* down_read(&pd->driver->sem); */
> +
> +	/* Make sure we only need to flush this processor's cache */
> +
> +	for (i = 0; i < rows; ++i) {
> +
> +		addr = address;
> +		end = addr + add;
> +
> +		do {
> +			next = ipvr_pd_addr_end(addr, end);
> +			pt = ipvr_mmu_pt_map_lock(pd, addr);
> +			if (!pt)
> +				continue;
> +			do {
> +				ipvr_mmu_invalidate_pte(pt, addr);
> +				--pt->count;
> +
> +			} while (addr += PAGE_SIZE, addr < next);
> +			ipvr_mmu_pt_unmap_unlock(pt);
> +
> +		} while (addr = next, next != end);
> +		address += row_add;
> +	}
> +	if (pd->hw_context != -1)
> +		ipvr_mmu_flush_ptes(pd, f_address, num_pages,
> +				   desired_tile_stride, hw_tile_stride);
> +
> +	/* up_read(&pd->driver->sem); */
> +
> +	if (pd->hw_context != -1)
> +		ipvr_mmu_flush(pd->driver, 0);
> +	ipvr_stat_remove_mmu_bind(pd->driver->dev_priv, num_pages <<
> PAGE_SHIFT);
> +}
> +
> +int ipvr_mmu_insert_pages(struct ipvr_mmu_pd *pd, struct page **pages,
> +			unsigned long address, int num_pages,
> +			u32 desired_tile_stride,
> +			u32 hw_tile_stride, u32 type)
> +{
> +	struct ipvr_mmu_pt *pt;
> +	int rows = 1;
> +	int i;
> +	u32 pte;
> +	unsigned long addr;
> +	unsigned long end;
> +	unsigned long next;
> +	unsigned long add;
> +	unsigned long row_add;
> +	unsigned long f_address = address;
> +	unsigned long pfn;
> +	int ret = 0;
> +
> +	if (hw_tile_stride) {
> +		if (num_pages % desired_tile_stride != 0)
> +			return -EINVAL;
> +		rows = num_pages / desired_tile_stride;
> +	} else {
> +		desired_tile_stride = num_pages;
> +	}
> +
> +	add = desired_tile_stride << PAGE_SHIFT;
> +	row_add = hw_tile_stride << PAGE_SHIFT;
> +
> +	down_read(&pd->driver->sem);
> +
> +	for (i = 0; i < rows; ++i) {
> +
> +		addr = address;
> +		end = addr + add;
> +
> +		do {
> +			next = ipvr_pd_addr_end(addr, end);
> +			pt = ipvr_mmu_pt_alloc_map_lock(pd, addr);
> +			if (!pt) {
> +				ret = -ENOMEM;
> +				goto out;
> +			}
> +			do {
> +				pfn = page_to_pfn(*pages++);
> +				/* should be under 4GiB */
> +				if (pfn >= 0x00100000UL) {
> +					IPVR_ERROR("cannot support pfn
> 0x%lx\n", pfn);
> +					ret = -EINVAL;
> +					goto out;
> +				}
> +				pte = ipvr_mmu_mask_pte(pfn, type);
> +				ipvr_mmu_set_pte(pt, addr, pte);
> +				pt->count++;
> +			} while (addr += PAGE_SIZE, addr < next);
> +			ipvr_mmu_pt_unmap_unlock(pt);
> +
> +		} while (addr = next, next != end);
> +
> +		address += row_add;
> +	}
> +out:
> +	if (pd->hw_context != -1)
> +		ipvr_mmu_flush_ptes(pd, f_address, num_pages,
> +				   desired_tile_stride, hw_tile_stride);
> +
> +	up_read(&pd->driver->sem);
> +
> +	if (pd->hw_context != -1)
> +		ipvr_mmu_flush(pd->driver, 1);
> +
> +	ipvr_stat_add_mmu_bind(pd->driver->dev_priv, num_pages <<
> PAGE_SHIFT);
> +	return ret;
> +}
> diff --git a/drivers/gpu/drm/ipvr/ipvr_mmu.h
> b/drivers/gpu/drm/ipvr/ipvr_mmu.h
> new file mode 100644
> index 0000000..1f524d4
> --- /dev/null
> +++ b/drivers/gpu/drm/ipvr/ipvr_mmu.h
> @@ -0,0 +1,111 @@
> +/*********************************************************
> *****************
> + * ipvr_mmu.h: IPVR header file for VED/VEC/VSP MMU handling
> + *
> + * Copyright (c) 2014 Intel Corporation, Hillsboro, OR, USA
> + * Copyright (c) Imagination Technologies Limited, UK
> + * Copyright (c) 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
> + * All Rights Reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of
> MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
> License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along
> with
> + * this program; if not, write to the Free Software Foundation, Inc.,
> + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
> + *
> + * Authors:
> + *    Eric Anholt <eric at anholt.net>
> + *    Fei Jiang <fei.jiang at intel.com>
> + *    Yao Cheng <yao.cheng at intel.com>
> + *
> +
> **********************************************************
> ****************/
> +
> +#ifndef _IPVR_MMU_H_
> +#define _IPVR_MMU_H_
> +
> +#include "ipvr_drv.h"
> +
> +static inline bool __must_check IPVR_IS_ERR(__force const unsigned long
> offset)
> +{
> +	return unlikely((offset) >= (unsigned long)-MAX_ERRNO);
> +}
> +
> +static inline long __must_check IPVR_OFFSET_ERR(__force const unsigned
> long offset)
> +{
> +	return (long)offset;
> +}
> +
> +static inline unsigned long __must_check IPVR_ERR_OFFSET(__force const
> long err)
> +{
> +	return (unsigned long)err;
> +}
> +
> +/**
> + * memory access control for VPU
> + */
> +#define IPVR_MMU_CACHED_MEMORY	  (1 << 0)	/* Bind to
> MMU only */
> +#define IPVR_MMU_RO_MEMORY	  	  (1 << 1)	/* MMU RO
> memory */
> +#define IPVR_MMU_WO_MEMORY	      (1 << 2)	/* MMU WO memory
> */
> +
> +/*
> + * linear MMU size is 512M : 0 - 512M
> + * tiling MMU size is 512M : 512M - 1024M
> + */
> +#define IPVR_MEM_MMU_LINEAR_START	0x00000000
> +#define IPVR_MEM_MMU_LINEAR_END		0x20000000
> +#define IPVR_MEM_MMU_TILING_START	0x20000000
> +#define IPVR_MEM_MMU_TILING_END		0x40000000
> +
> +struct ipvr_mmu_pd;
> +struct ipvr_mmu_pt;
> +
> +struct ipvr_mmu_driver {
> +	/* protects driver- and pd structures. Always take in read mode
> +	 * before taking the page table spinlock.
> +	 */
> +	struct rw_semaphore sem;
> +
> +	/* protects page tables, directory tables and pt tables.
> +	 * and pt structures.
> +	 */
> +	spinlock_t lock;
> +
> +	atomic_t needs_tlbflush;
> +
> +	u8 __iomem *register_map;
> +	struct ipvr_mmu_pd *default_pd;
> +
> +	bool has_clflush;
> +	u32 clflush_add;
> +	unsigned long clflush_mask;
> +
> +	struct drm_ipvr_private *dev_priv;
> +};
> +
> +struct ipvr_mmu_driver *__must_check ipvr_mmu_driver_init(u8
> __iomem *registers,
> +			u32 invalid_type, struct drm_ipvr_private *dev_priv);
> +
> +void ipvr_mmu_driver_takedown(struct ipvr_mmu_driver *driver);
> +
> +struct ipvr_mmu_pd *
> +ipvr_mmu_get_default_pd(struct ipvr_mmu_driver *driver);
> +
> +void ipvr_mmu_set_pd_context(struct ipvr_mmu_pd *pd, u32
> hw_context);
> +
> +u32 __must_check ipvr_get_default_pd_addr32(struct ipvr_mmu_driver
> *driver);
> +
> +int ipvr_mmu_insert_pages(struct ipvr_mmu_pd *pd, struct page **pages,
> +			unsigned long address, int num_pages,
> +			u32 desired_tile_stride, u32 hw_tile_stride, u32
> type);
> +
> +void ipvr_mmu_remove_pages(struct ipvr_mmu_pd *pd,
> +			unsigned long address, int num_pages,
> +			u32 desired_tile_stride, u32 hw_tile_stride);
> +
> +#endif
> diff --git a/drivers/gpu/drm/ipvr/ipvr_trace.c
> b/drivers/gpu/drm/ipvr/ipvr_trace.c
> new file mode 100644
> index 0000000..91c0bda
> --- /dev/null
> +++ b/drivers/gpu/drm/ipvr/ipvr_trace.c
> @@ -0,0 +1,11 @@
> +/*
> + * Copyright © 2014 Intel Corporation
> + *
> + * Authors:
> + *    Yao Cheng <yao.cheng at intel.com>>
> + */
> +
> +#ifndef __CHECKER__
> +#define CREATE_TRACE_POINTS
> +#include "ipvr_trace.h"
> +#endif
> diff --git a/drivers/gpu/drm/ipvr/ipvr_trace.h
> b/drivers/gpu/drm/ipvr/ipvr_trace.h
> new file mode 100644
> index 0000000..6ea8b9a
> --- /dev/null
> +++ b/drivers/gpu/drm/ipvr/ipvr_trace.h
> @@ -0,0 +1,333 @@
> +/*********************************************************
> *****************
> + * ipvr_trace.h: IPVR header file for trace support
> + *
> + * Copyright (c) 2014 Intel Corporation, Hillsboro, OR, USA
> + * All Rights Reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of
> MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
> License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along
> with
> + * this program; if not, write to the Free Software Foundation, Inc.,
> + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
> + *
> + * Authors:
> + *    Fei Jiang <fei.jiang at intel.com>
> + *    Yao Cheng <yao.cheng at intel.com>
> + *
> +
> **********************************************************
> ****************/
> +
> +#if !defined(_IPVR_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ)
> +#define _IPVR_TRACE_H_
> +
> +#include "ipvr_bo.h"
> +#include "ipvr_fence.h"
> +#include "ved_msg.h"
> +#include <drm/drmP.h>
> +#include <linux/stringify.h>
> +#include <linux/types.h>
> +#include <linux/tracepoint.h>
> +
> +#undef TRACE_SYSTEM
> +#define TRACE_SYSTEM ipvr
> +#define TRACE_SYSTEM_STRING __stringify(TRACE_SYSTEM)
> +#define TRACE_INCLUDE_FILE ipvr_trace
> +
> +/* object tracking */
> +
> +TRACE_EVENT(ipvr_create_object,
> +	TP_PROTO(struct drm_ipvr_gem_object *obj, u64 mmu_offset),
> +	TP_ARGS(obj, mmu_offset),
> +	TP_STRUCT__entry(
> +		__field(struct drm_ipvr_gem_object *, obj)
> +		__field(u32, size)
> +		__field(bool, tiling)
> +		__field(u32, cache_level)
> +		__field(u64, mmu_offset)
> +	),
> +	TP_fast_assign(
> +		__entry->obj = obj;
> +		__entry->size = obj->base.size;
> +		__entry->tiling = obj->tiling;
> +		__entry->cache_level = obj->cache_level;
> +		__entry->mmu_offset = mmu_offset;
> +	),
> +	TP_printk("obj=0x%p, size=%u, tiling=%u, cache=%u,
> mmu_offset=0x%llx",
> +		__entry->obj, __entry->size, __entry->tiling,
> +		__entry->cache_level, __entry->mmu_offset)
> +);
> +
> +TRACE_EVENT(ipvr_free_object,
> +	TP_PROTO(struct drm_ipvr_gem_object *obj),
> +	TP_ARGS(obj),
> +	TP_STRUCT__entry(
> +		__field(struct drm_ipvr_gem_object *, obj)
> +	),
> +	TP_fast_assign(
> +		__entry->obj = obj;
> +	),
> +	TP_printk("obj=0x%p", __entry->obj)
> +);
> +
> +TRACE_EVENT(ipvr_fence_wait_begin,
> +	TP_PROTO(struct ipvr_fence *fence,
> +		u32 signaled_seq,
> +		u16 sync_seq),
> +	TP_ARGS(fence, signaled_seq, sync_seq),
> +	TP_STRUCT__entry(
> +		__field(struct ipvr_fence *, fence)
> +		__field(u16, fence_seq)
> +		__field(u32, signaled_seq)
> +		__field(u16, sync_seq)
> +	),
> +	TP_fast_assign(
> +		__entry->fence = fence;
> +		__entry->fence_seq = fence->seq;
> +		__entry->signaled_seq = signaled_seq;
> +		__entry->sync_seq = sync_seq;
> +	),
> +	TP_printk("fence=%p, fence_seq=%d, signaled_seq=%d,
> sync_seq=%d",
> +		__entry->fence, __entry->fence_seq,
> +		__entry->signaled_seq, __entry->sync_seq)
> +);
> +
> +TRACE_EVENT(ipvr_fence_wait_end,
> +	TP_PROTO(struct ipvr_fence *fence,
> +		u32 signaled_seq,
> +		u16 sync_seq),
> +	TP_ARGS(fence, signaled_seq, sync_seq),
> +	TP_STRUCT__entry(
> +		__field(struct ipvr_fence *, fence)
> +		__field(u16, fence_seq)
> +		__field(u32, signaled_seq)
> +		__field(u16, sync_seq)
> +	),
> +	TP_fast_assign(
> +		__entry->fence = fence;
> +		__entry->fence_seq = fence->seq;
> +		__entry->signaled_seq = signaled_seq;
> +		__entry->sync_seq = sync_seq;
> +	),
> +	TP_printk("fence=%p, fence_seq=%d, signaled_seq=%d,
> sync_seq=%d",
> +		__entry->fence, __entry->fence_seq,
> +		__entry->signaled_seq, __entry->sync_seq)
> +);
> +
> +
> +TRACE_EVENT(ipvr_fence_wait_lockup,
> +	TP_PROTO(struct ipvr_fence *fence,
> +		u32 signaled_seq,
> +		u16 sync_seq),
> +	TP_ARGS(fence, signaled_seq, sync_seq),
> +	TP_STRUCT__entry(
> +		__field(struct ipvr_fence *, fence)
> +		__field(u16, fence_seq)
> +		__field(u32, signaled_seq)
> +		__field(u16, sync_seq)
> +	),
> +	TP_fast_assign(
> +		__entry->fence = fence;
> +		__entry->fence_seq = fence->seq;
> +		__entry->signaled_seq = signaled_seq;
> +		__entry->sync_seq = sync_seq;
> +	),
> +	TP_printk("fence=%p, fence_seq=%d, signaled_seq=%d,
> sync_seq=%d",
> +		__entry->fence, __entry->fence_seq,
> +		__entry->signaled_seq, __entry->sync_seq)
> +);
> +
> +TRACE_EVENT(ipvr_execbuffer,
> +	TP_PROTO(struct drm_ipvr_gem_execbuffer *exec),
> +	TP_ARGS(exec),
> +	TP_STRUCT__entry(
> +		__field(u64, buffers_ptr)
> +		__field(u32, buffer_count)
> +		__field(u32, exec_start_offset)
> +		__field(u32, exec_len)
> +		__field(u32, ctx_id)
> +	),
> +	TP_fast_assign(
> +		__entry->buffers_ptr = exec->buffers_ptr;
> +		__entry->buffer_count = exec->buffer_count;
> +		__entry->exec_start_offset = exec->exec_start_offset;
> +		__entry->exec_len = exec->exec_len;
> +		__entry->ctx_id = exec->ctx_id;
> +	),
> +	TP_printk("buffers_ptr=0x%llx, buffer_count=0x%d, "
> +		"exec_start_offset=0x%x, exec_len=%u, ctx_id=%d",
> +		__entry->buffers_ptr, __entry->buffer_count,
> +		__entry->exec_start_offset, __entry->exec_len,
> +		__entry->ctx_id)
> +);
> +
> +TRACE_EVENT(ved_cmd_send,
> +	TP_PROTO(u32 ctx_id, u32 cmd_id, u32 seq),
> +	TP_ARGS(ctx_id, cmd_id, seq),
> +	TP_STRUCT__entry(
> +		__field(u32, ctx_id)
> +		__field(u32, cmd_id)
> +		__field(u32, seq)
> +	),
> +	TP_fast_assign(
> +		__entry->ctx_id = ctx_id;
> +		__entry->cmd_id = cmd_id;
> +		__entry->seq = seq;
> +	),
> +	TP_printk("ctx_id=0x%08x, cmd_id=0x%08x, seq=0x%08x",
> +		__entry->ctx_id, __entry->cmd_id, __entry->seq)
> +);
> +
> +TRACE_EVENT(ved_cmd_copy,
> +	TP_PROTO(u32 ctx_id, u32 cmd_id, u32 seq),
> +	TP_ARGS(ctx_id, cmd_id, seq),
> +	TP_STRUCT__entry(
> +		__field(u32, ctx_id)
> +		__field(u32, cmd_id)
> +		__field(u32, seq)
> +	),
> +	TP_fast_assign(
> +		__entry->ctx_id = ctx_id;
> +		__entry->cmd_id = cmd_id;
> +		__entry->seq = seq;
> +	),
> +	TP_printk("ctx_id=0x%08x, cmd_id=0x%08x, seq=0x%08x",
> +		__entry->ctx_id, __entry->cmd_id, __entry->seq)
> +);
> +
> +TRACE_EVENT(ipvr_get_power,
> +	TP_PROTO(int usage, int pending),
> +	TP_ARGS(usage, pending),
> +	TP_STRUCT__entry(
> +		__field(int, usage)
> +		__field(int, pending)
> +	),
> +	TP_fast_assign(
> +		__entry->usage = usage;
> +		__entry->pending = pending;
> +	),
> +	TP_printk("power usage %d, pending events %d",
> +		__entry->usage,
> +		__entry->pending)
> +);
> +
> +TRACE_EVENT(ipvr_put_power,
> +	TP_PROTO(int usage, int pending),
> +	TP_ARGS(usage, pending),
> +	TP_STRUCT__entry(
> +		__field(int, usage)
> +		__field(int, pending)
> +	),
> +	TP_fast_assign(
> +		__entry->usage = usage;
> +		__entry->pending = pending;
> +	),
> +	TP_printk("power usage %d, pending events %d",
> +		__entry->usage,
> +		__entry->pending)
> +);
> +
> +TRACE_EVENT(ved_power_on,
> +	TP_PROTO(int freq),
> +	TP_ARGS(freq),
> +	TP_STRUCT__entry(
> +		__field(int, freq)
> +	),
> +	TP_fast_assign(
> +		__entry->freq = freq;
> +	),
> +	TP_printk("frequency %d MHz", __entry->freq)
> +);
> +
> +TRACE_EVENT(ved_power_off,
> +	TP_PROTO(int freq),
> +	TP_ARGS(freq),
> +	TP_STRUCT__entry(
> +		__field(int, freq)
> +	),
> +	TP_fast_assign(
> +		__entry->freq = freq;
> +	),
> +	TP_printk("frequency %d MHz", __entry->freq)
> +);
> +
> +TRACE_EVENT(ved_irq_completed,
> +	TP_PROTO(struct ipvr_context *ctx, struct fw_completed_msg
> *completed_msg),
> +	TP_ARGS(ctx, completed_msg),
> +	TP_STRUCT__entry(
> +		__field(s64, ctx_id)
> +		__field(u16, seqno)
> +		__field(u32, flags)
> +		__field(u32, vdebcr)
> +		__field(u16, start_mb)
> +		__field(u16, last_mb)
> +	),
> +	TP_fast_assign(
> +		__entry->ctx_id = ctx? ctx->ctx_id: -1;
> +		__entry->seqno = completed_msg->header.bits.msg_fence;
> +		__entry->flags = completed_msg->flags;
> +		__entry->vdebcr = completed_msg->vdebcr;
> +		__entry->start_mb = completed_msg->mb.bits.start_mb;
> +		__entry->last_mb = completed_msg->mb.bits.last_mb;
> +	),
> +	TP_printk("ctx=%lld, seq=0x%04x, flags=0x%08x, vdebcr=0x%08x,
> mb=[%u, %u]",
> +		__entry->ctx_id,
> +		__entry->seqno,
> +		__entry->flags,
> +		__entry->vdebcr,
> +		__entry->start_mb,
> +		__entry->last_mb)
> +);
> +
> +TRACE_EVENT(ved_irq_panic,
> +	TP_PROTO(struct fw_panic_msg *panic_msg, u32 err_trig,
> +		u32 irq_status, u32 mmu_status, u32 dmac_status),
> +	TP_ARGS(panic_msg, err_trig, irq_status, mmu_status, dmac_status),
> +	TP_STRUCT__entry(
> +		__field(u16, seqno)
> +		__field(u32, fe_status)
> +		__field(u32, be_status)
> +		__field(u16, rsvd)
> +		__field(u16, last_mb)
> +		__field(u32, err_trig)
> +		__field(u32, irq_status)
> +		__field(u32, mmu_status)
> +		__field(u32, dmac_status)
> +
> +	),
> +	TP_fast_assign(
> +		__entry->seqno = panic_msg->header.bits.msg_fence;
> +		__entry->fe_status = panic_msg->fe_status;
> +		__entry->be_status = panic_msg->be_status;
> +		__entry->rsvd = panic_msg->mb.bits.reserved2;
> +		__entry->last_mb = panic_msg->mb.bits.last_mb;
> +		__entry->err_trig = err_trig;
> +		__entry->irq_status = irq_status;
> +		__entry->mmu_status = mmu_status;
> +		__entry->dmac_status = dmac_status;
> +	),
> +	TP_printk("seq=0x%04x, status=[fe 0x%08x be 0x%08x],
> rsvd=0x%04x, "
> +		"last_mb=%u, err_trig=0x%08x, irq_status=0x%08x, "
> +		"mmu_status=0x%08x, dmac_status=0x%08x",
> +		__entry->seqno,
> +		__entry->fe_status,
> +		__entry->be_status,
> +		__entry->rsvd,
> +		__entry->last_mb,
> +		__entry->err_trig,
> +		__entry->irq_status,
> +		__entry->mmu_status,
> +		__entry->dmac_status)
> +);
> +
> +#endif /* _IPVR_TRACE_H_ */
> +
> + /* This part must be outside protection */
> +#undef TRACE_INCLUDE_PATH
> +#define TRACE_INCLUDE_PATH .
> +#include <trace/define_trace.h>
> diff --git a/drivers/gpu/drm/ipvr/ved_cmd.c
> b/drivers/gpu/drm/ipvr/ved_cmd.c
> new file mode 100644
> index 0000000..d9de33e
> --- /dev/null
> +++ b/drivers/gpu/drm/ipvr/ved_cmd.c
> @@ -0,0 +1,882 @@
> +/*********************************************************
> *****************
> + * ved_cmd.c: VED command handling between host driver and VED
> firmware
> + *
> + * Copyright (c) 2014 Intel Corporation, Hillsboro, OR, USA
> + * Copyright (c) Imagination Technologies Limited, UK
> + * Copyright (c) 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
> + * All Rights Reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of
> MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
> License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along
> with
> + * this program; if not, write to the Free Software Foundation, Inc.,
> + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
> + *
> + * Authors:
> + *    Fei Jiang <fei.jiang at intel.com>
> + *    Yao Cheng <yao.cheng at intel.com>
> + *
> +
> **********************************************************
> ****************/
> +
> +#include "ipvr_gem.h"
> +#include "ipvr_mmu.h"
> +#include "ipvr_bo.h"
> +#include "ipvr_trace.h"
> +#include "ipvr_fence.h"
> +#include "ved_cmd.h"
> +#include "ved_fw.h"
> +#include "ved_msg.h"
> +#include "ved_reg.h"
> +#include "ved_pm.h"
> +#include <linux/pm_runtime.h>
> +#include <linux/io.h>
> +#include <linux/delay.h>
> +
> +#ifndef list_first_entry
> +#define list_first_entry(ptr, type, member) \
> +	list_entry((ptr)->next, type, member)
> +#endif
> +
> +int ved_mtx_send(struct ved_private *ved_priv, const void *msg)
> +{
> +	static struct fw_padding_msg pad_msg;
> +	const u32 *p_msg = (u32 *)msg;
> +	struct drm_ipvr_private *dev_priv = ved_priv->dev_priv;
> +	u32 msg_num, words_free, ridx, widx, buf_size, buf_offset;
> +	int ret = 0;
> +	int i;
> +	union msg_header *header;
> +	header = (union msg_header *)msg;
> +
> +	IPVR_DEBUG_ENTRY("enter.\n");
> +
> +	/* we need clocks enabled before we touch VEC local ram,
> +	 * but fw will take care of the clock after fw is loaded
> +	 */
> +
> +	msg_num = (header->bits.msg_size + 3) / 4;
> +
> +	/* debug code for msg dump */
> +	IPVR_DEBUG_VED("MSVDX: ved_mtx_send is %dDW\n", msg_num);
> +
> +	for (i = 0; i < msg_num; i++)
> +		IPVR_DEBUG_VED("   0x%08x\n", p_msg[i]);
> +
> +	buf_size = IPVR_REG_READ32(MSVDX_COMMS_TO_MTX_BUF_SIZE)
> &
> +		   ((1 << 16) - 1);
> +
> +	if (msg_num > buf_size) {
> +		ret = -EINVAL;
> +		IPVR_ERROR("VED: message exceed maximum, ret:%d\n",
> ret);
> +		goto out;
> +	}
> +
> +	ridx = IPVR_REG_READ32(MSVDX_COMMS_TO_MTX_RD_INDEX);
> +	widx = IPVR_REG_READ32(MSVDX_COMMS_TO_MTX_WRT_INDEX);
> +
> +
> +	buf_size = IPVR_REG_READ32(MSVDX_COMMS_TO_MTX_BUF_SIZE)
> &
> +		   ((1 << 16) - 1);
> +	/*0x2000 is VEC Local Ram offset*/
> +	buf_offset =
> +
> 	(IPVR_REG_READ32(MSVDX_COMMS_TO_MTX_BUF_SIZE) >> 16) +
> 0x2000;
> +
> +	/* message would wrap, need to send a pad message */
> +	if (widx + msg_num > buf_size) {
> +		/* Shouldn't happen for a PAD message itself */
> +		if (header->bits.msg_type == MTX_MSGID_PADDING)
> +			IPVR_DEBUG_WARN("VED: should not wrap pad msg,
> "
> +				"buf_size is %d, widx is %d, msg_num
> is %d.\n",
> +				buf_size, widx, msg_num);
> +
> +		/* if the read pointer is at zero then we must wait for it to
> +		 * change otherwise the write pointer will equal the read
> +		 * pointer,which should only happen when the buffer is
> empty
> +		 *
> +		 * This will only happens if we try to overfill the queue,
> +		 * queue management should make
> +		 * sure this never happens in the first place.
> +		 */
> +		if (0 == ridx) {
> +			ret = -EINVAL;
> +			IPVR_ERROR("MSVDX: RIndex=0, ret:%d\n", ret);
> +			goto out;
> +		}
> +
> +		/* Send a pad message */
> +		pad_msg.header.bits.msg_size = (buf_size - widx) << 2;
> +		pad_msg.header.bits.msg_type = MTX_MSGID_PADDING;
> +		ved_mtx_send(ved_priv, (void *)&pad_msg);
> +		widx =
> IPVR_REG_READ32(MSVDX_COMMS_TO_MTX_WRT_INDEX);
> +	}
> +
> +	if (widx >= ridx)
> +		words_free = buf_size - (widx - ridx) - 1;
> +	else
> +		words_free = ridx - widx - 1;
> +
> +	if (msg_num > words_free) {
> +		ret = -EINVAL;
> +		IPVR_ERROR("MSVDX: msg_num > words_free, ret:%d\n",
> ret);
> +		goto out;
> +	}
> +	while (msg_num > 0) {
> +		IPVR_REG_WRITE32(*p_msg++, buf_offset + (widx << 2));
> +		msg_num--;
> +		widx++;
> +		if (buf_size == widx)
> +			widx = 0;
> +	}
> +
> +	IPVR_REG_WRITE32(widx, MSVDX_COMMS_TO_MTX_WRT_INDEX);
> +
> +	/* Make sure clocks are enabled before we kick
> +	 * but fw will take care of the clock after fw is loaded
> +	 */
> +
> +	/* signal an interrupt to let the mtx know there is a new message */
> +	IPVR_REG_WRITE32(1, MTX_KICK_INPUT_OFFSET);
> +
> +	/* Read MSVDX Register several times in case Idle signal assert */
> +	IPVR_REG_READ32(MSVDX_INTERRUPT_STATUS_OFFSET);
> +	IPVR_REG_READ32(MSVDX_INTERRUPT_STATUS_OFFSET);
> +	IPVR_REG_READ32(MSVDX_INTERRUPT_STATUS_OFFSET);
> +	IPVR_REG_READ32(MSVDX_INTERRUPT_STATUS_OFFSET);
> +
> +out:
> +	return ret;
> +}
> +
> +static int ved_cmd_send(struct ved_private *ved_priv, void *cmd,
> +			u32 cmd_size, struct ipvr_context *ipvr_ctx)
> +{
> +	int ret = 0;
> +	union msg_header *header;
> +	u32 cur_seq = 0xffffffff;
> +
> +	while (cmd_size > 0) {
> +		u32 cur_cmd_size, cur_cmd_id;
> +		header = (union msg_header *)cmd;
> +		cur_cmd_size = header->bits.msg_size;
> +		cur_cmd_id = header->bits.msg_type;
> +
> +		cur_seq = ((struct fw_msg_header *)cmd)-
> >header.bits.msg_fence;
> +
> +		if (cur_seq != 0xffffffff) {
> +			ipvr_ctx->cur_seq = cur_seq;
> +		}
> +
> +		if (cur_cmd_size > cmd_size) {
> +			ret = -EINVAL;
> +			IPVR_ERROR("VED: cmd_size %u
> cur_cmd_size %u.\n",
> +				  cmd_size, cur_cmd_size);
> +			goto out;
> +		}
> +
> +		/* Send the message to h/w */
> +		trace_ved_cmd_send(ipvr_ctx->ctx_id, cur_cmd_id,
> cur_seq);
> +		ret = ved_mtx_send(ved_priv, cmd);
> +		if (ret) {
> +			IPVR_DEBUG_WARN("VED: ret:%d\n", ret);
> +			goto out;
> +		}
> +		cmd += cur_cmd_size;
> +		cmd_size -= cur_cmd_size;
> +		if (cur_cmd_id == MTX_MSGID_HOST_BE_OPP ||
> +			cur_cmd_id == MTX_MSGID_DEBLOCK ||
> +			cur_cmd_id == MTX_MSGID_INTRA_OOLD) {
> +			cmd += (sizeof(struct fw_deblock_msg) -
> cur_cmd_size);
> +			cmd_size -=
> +				(sizeof(struct fw_deblock_msg) -
> cur_cmd_size);
> +		}
> +	}
> +out:
> +	IPVR_DEBUG_VED("VED: ret:%d\n", ret);
> +	return ret;
> +}
> +
> +int ved_cmd_dequeue_send(struct ved_private *ved_priv)
> +{
> +	struct ved_cmd_queue *ved_cmd = NULL;
> +	int ret = 0;
> +	unsigned long irq_flags;
> +
> +	spin_lock_irqsave(&ved_priv->ved_lock, irq_flags);
> +	if (list_empty(&ved_priv->ved_queue)) {
> +		IPVR_DEBUG_VED("VED: ved cmd queue empty.\n");
> +		ved_priv->ved_busy = false;
> +		spin_unlock_irqrestore(&ved_priv->ved_lock, irq_flags);
> +		return -ENODATA;
> +	}
> +
> +	ved_cmd = list_first_entry(&ved_priv->ved_queue,
> +				     struct ved_cmd_queue, head);
> +	list_del(&ved_cmd->head);
> +	spin_unlock_irqrestore(&ved_priv->ved_lock, irq_flags);
> +
> +	IPVR_DEBUG_VED("VED: cmd queue seq is %08x.\n", ved_cmd-
> >cmd_seq);
> +
> +	ipvr_set_tile(ved_priv->dev_priv, ved_cmd->tiling_scheme,
> +				   ved_cmd->tiling_stride);
> +
> +	ret = ved_cmd_send(ved_priv, ved_cmd->cmd,
> +			   ved_cmd->cmd_size, ved_cmd->ipvr_ctx);
> +	if (ret) {
> +		IPVR_ERROR("VED: ved_cmd_send failed.\n");
> +		ret = -EFAULT;
> +	}
> +
> +	kfree(ved_cmd->cmd);
> +	kfree(ved_cmd);
> +
> +	return ret;
> +}
> +
> +void ved_flush_cmd_queue(struct ved_private *ved_priv)
> +{
> +	struct ved_cmd_queue *ved_cmd;
> +	struct list_head *list, *next;
> +	unsigned long irq_flags;
> +	spin_lock_irqsave(&ved_priv->ved_lock, irq_flags);
> +	/* Flush the VED cmd queue and signal all fences in the queue */
> +	list_for_each_safe(list, next, &ved_priv->ved_queue) {
> +		ved_cmd = list_entry(list, struct ved_cmd_queue, head);
> +		list_del(list);
> +		IPVR_DEBUG_VED("VED: flushing sequence:0x%08x.\n",
> +				  ved_cmd->cmd_seq);
> +		ved_priv->ved_cur_seq = ved_cmd->cmd_seq;
> +
> +		ipvr_fence_process(ved_priv->dev_priv, ved_cmd-
> >cmd_seq, IPVR_CMD_SKIP);
> +		kfree(ved_cmd->cmd);
> +		kfree(ved_cmd);
> +	}
> +	ved_priv->ved_busy = false;
> +	spin_unlock_irqrestore(&ved_priv->ved_lock, irq_flags);
> +}
> +
> +static int
> +ved_map_command(struct ved_private *ved_priv,
> +				struct drm_ipvr_gem_object *cmd_buffer,
> +				u32 cmd_size, void **ved_cmd,
> +				u16 sequence, s32 copy_cmd,
> +				struct ipvr_context *ipvr_ctx)
> +{
> +	int ret = 0;
> +	u32 cmd_size_remain;
> +	void *cmd, *cmd_copy, *cmd_start;
> +	union msg_header *header;
> +	struct ipvr_fence *fence = NULL;
> +
> +	/* command buffers may not exceed page boundary */
> +	if (cmd_size > PAGE_SIZE)
> +		return -EINVAL;
> +
> +	cmd_start = kmap(sg_page(cmd_buffer->sg_table->sgl));
> +	if (!cmd_start) {
> +		IPVR_ERROR("VED: kmap failed.\n");
> +		return -EFAULT;
> +	}
> +
> +	cmd = cmd_start;
> +	cmd_size_remain = cmd_size;
> +
> +	while (cmd_size_remain > 0) {
> +		u32 cur_cmd_size, cur_cmd_id, mmu_ptd,
> msvdx_mmu_invalid;
> +		if (cmd_size_remain < MTX_GENMSG_HEADER_SIZE) {
> +			ret = -EINVAL;
> +			goto out;
> +		}
> +		header = (union msg_header *)cmd;
> +		cur_cmd_size = header->bits.msg_size;
> +		cur_cmd_id = header->bits.msg_type;
> +		mmu_ptd = 0;
> +		msvdx_mmu_invalid = 0;
> +
> +		IPVR_DEBUG_VED("cmd start at %p cur_cmd_size = %d"
> +			       " cur_cmd_id = %02x fence = %08x\n",
> +			       cmd, cur_cmd_size,
> +			       cur_cmd_id, sequence);
> +		if ((cur_cmd_size % sizeof(u32))
> +		    || (cur_cmd_size > cmd_size_remain)) {
> +			ret = -EINVAL;
> +			IPVR_ERROR("VED: cmd size err, ret:%d.\n", ret);
> +			goto out;
> +		}
> +
> +		switch (cur_cmd_id) {
> +		case MTX_MSGID_DECODE_FE: {
> +			struct fw_decode_msg *decode_msg;
> +			if (sizeof(struct fw_decode_msg) > cmd_size_remain)
> {
> +				/* Msg size is not correct */
> +				ret = -EINVAL;
> +				IPVR_DEBUG_WARN("MSVDX: wrong msg
> size.\n");
> +				goto out;
> +			}
> +			decode_msg = (struct fw_decode_msg *)cmd;
> +			decode_msg->header.bits.msg_fence = sequence;
> +
> +			mmu_ptd = ipvr_get_default_pd_addr32(ved_priv-
> >dev_priv->mmu);
> +			if (mmu_ptd == 0) {
> +				ret = -EINVAL;
> +				IPVR_DEBUG_WARN("MSVDX: invalid PD
> addr32.\n");
> +				goto out;
> +			}
> +			msvdx_mmu_invalid = atomic_cmpxchg(&ved_priv-
> >dev_priv->ipvr_mmu_invaldc, 1, 0);
> +			if (msvdx_mmu_invalid == 1) {
> +				decode_msg->flag_size.bits.flags |=
> FW_INVALIDATE_MMU;
> +				IPVR_DEBUG_VED("VED: Set MMU
> invalidate\n");
> +			}
> +			/* if ctx_id is not passed, use default id */
> +			if (decode_msg->mmu_context.bits.context == 0)
> +				decode_msg->mmu_context.bits.context =
> +					ved_priv->dev_priv-
> >default_ctx.ctx_id;
> +
> +			decode_msg->mmu_context.bits.mmu_ptd =
> mmu_ptd >> 8;
> +			IPVR_DEBUG_VED("VED: MSGID_DECODE_FE:"
> +					" - fence: %08x"
> +					" - flags: %08x - buffer_size: %08x"
> +					" - crtl_alloc_addr: %08x"
> +					" - context: %08x - mmu_ptd: %08x"
> +					" - operating_mode: %08x.\n",
> +					decode_msg-
> >header.bits.msg_fence,
> +					decode_msg->flag_size.bits.flags,
> +					decode_msg-
> >flag_size.bits.buffer_size,
> +					decode_msg->crtl_alloc_addr,
> +					decode_msg-
> >mmu_context.bits.context,
> +					decode_msg-
> >mmu_context.bits.mmu_ptd,
> +					decode_msg->operating_mode);
> +			break;
> +		}
> +		default:
> +			/* Msg not supported */
> +			ret = -EINVAL;
> +			IPVR_DEBUG_WARN("VED: msg not supported.\n");
> +			goto out;
> +		}
> +
> +		cmd += cur_cmd_size;
> +		cmd_size_remain -= cur_cmd_size;
> +	}
> +
> +	fence = ipvr_fence_create(ved_priv->dev_priv);
> +	if (IS_ERR(fence)) {
> +		ret = PTR_ERR(fence);
> +		IPVR_ERROR("Failed calling ipvr_fence_create: %d\n", ret);
> +		goto out;
> +	}
> +
> +	ipvr_fence_buffer_objects(&ved_priv->dev_priv-
> >validate_ctx.validate_list,
> +				fence);
> +
> +	if (copy_cmd) {
> +		IPVR_DEBUG_VED("VED: copying command.\n");
> +
> +		cmd_copy = kzalloc(cmd_size, GFP_KERNEL);
> +		if (cmd_copy == NULL) {
> +			ret = -ENOMEM;
> +			IPVR_ERROR("VED: fail to callc, ret=:%d\n", ret);
> +			goto out;
> +		}
> +		memcpy(cmd_copy, cmd_start, cmd_size);
> +		*ved_cmd = cmd_copy;
> +	} else {
> +		IPVR_DEBUG_VED("VED: did NOT copy command.\n");
> +		ipvr_set_tile(ved_priv->dev_priv, ved_priv-
> >default_tiling_scheme,
> +					ved_priv->default_tiling_stride);
> +
> +		ret = ved_cmd_send(ved_priv, cmd_start, cmd_size,
> ipvr_ctx);
> +		if (ret) {
> +			IPVR_ERROR("VED: ved_cmd_send failed\n");
> +			ret = -EINVAL;
> +		}
> +	}
> +
> +out:
> +	kunmap(sg_page(cmd_buffer->sg_table->sgl));
> +
> +	return ret;
> +}
> +
> +static int
> +ved_submit_cmdbuf_copy(struct ved_private *ved_priv,
> +				struct drm_ipvr_gem_object *cmd_buffer,
> +				u32 cmd_size,
> +				struct ipvr_context *ipvr_ctx,
> +				u32 fence_flag)
> +{
> +	struct ved_cmd_queue *ved_cmd;
> +	u16 sequence =  (ved_priv->dev_priv->last_seq << 4);
> +	unsigned long irq_flags;
> +	void *cmd = NULL;
> +	int ret;
> +	union msg_header *header;
> +
> +	/* queue the command to be sent when the h/w is ready */
> +	IPVR_DEBUG_VED("VED: queueing sequence:%08x.\n",
> +			  sequence);
> +	ved_cmd = kzalloc(sizeof(struct ved_cmd_queue),
> +			    GFP_KERNEL);
> +	if (ved_cmd == NULL) {
> +		IPVR_ERROR("MSVDXQUE: Out of memory...\n");
> +		return -ENOMEM;
> +	}
> +
> +	ret = ved_map_command(ved_priv, cmd_buffer, cmd_size,
> +				&cmd, sequence, 1, ipvr_ctx);
> +	if (ret) {
> +		IPVR_ERROR("VED: Failed to extract cmd\n");
> +		kfree(ved_cmd);
> +		/* -EINVAL or -EFAULT or -ENOMEM */
> +		return ret;
> +	}
> +	header = (union msg_header *)cmd;
> +	ved_cmd->cmd = cmd;
> +	ved_cmd->cmd_size = cmd_size;
> +	ved_cmd->cmd_seq = sequence;
> +
> +	ved_cmd->tiling_scheme = ved_priv->default_tiling_scheme;
> +	ved_cmd->tiling_stride = ved_priv->default_tiling_stride;
> +	ved_cmd->ipvr_ctx = ipvr_ctx;
> +	spin_lock_irqsave(&ved_priv->ved_lock, irq_flags);
> +	list_add_tail(&ved_cmd->head, &ved_priv->ved_queue);
> +	spin_unlock_irqrestore(&ved_priv->ved_lock, irq_flags);
> +	if (!ved_priv->ved_busy) {
> +		ved_priv->ved_busy = true;
> +		IPVR_DEBUG_VED("VED: Need immediate dequeue.\n");
> +		ved_cmd_dequeue_send(ved_priv);
> +	}
> +	trace_ved_cmd_copy(ipvr_ctx->ctx_id, header->bits.msg_type,
> sequence);
> +
> +	return ret;
> +}
> +
> +int
> +ved_submit_video_cmdbuf(struct ved_private *ved_priv,
> +				struct drm_ipvr_gem_object *cmd_buffer,
> +				u32 cmd_size,
> +				struct ipvr_context *ipvr_ctx,
> +				u32 fence_flag)
> +{
> +	unsigned long irq_flags;
> +	struct drm_ipvr_private *dev_priv = ved_priv->dev_priv;
> +	u16 sequence =  (dev_priv->last_seq << 4) & 0xffff;
> +	int ret = 0;
> +
> +	if (sequence == IPVR_FENCE_SIGNALED_SEQ) {
> +		sequence =  (++ved_priv->dev_priv->last_seq << 4) & 0xffff;
> +	}
> +
> +	if (!ipvr_ctx) {
> +		IPVR_ERROR("VED: null ctx\n");
> +		return -ENOENT;
> +	}
> +
> +	spin_lock_irqsave(&ved_priv->ved_lock, irq_flags);
> +
> +	IPVR_DEBUG_VED("sequence is 0x%x, needs_reset is 0x%x.\n",
> +			sequence, ved_priv->ved_needs_reset);
> +
> +	if (WARN_ON(ipvr_runtime_pm_get(ved_priv->dev_priv) < 0)) {
> +		IPVR_ERROR("Failed to get ipvr power\n");
> +		spin_unlock_irqrestore(&ved_priv->ved_lock, irq_flags);
> +		return -EBUSY;
> +	}
> +
> +	if (ved_priv->ved_busy) {
> +		spin_unlock_irqrestore(&ved_priv->ved_lock, irq_flags);
> +		ret = ved_submit_cmdbuf_copy(ved_priv, cmd_buffer,
> +			    cmd_size, ipvr_ctx, fence_flag);
> +
> +		return ret;
> +	}
> +
> +	if (ved_priv->ved_needs_reset) {
> +		spin_unlock_irqrestore(&ved_priv->ved_lock, irq_flags);
> +		IPVR_DEBUG_VED("VED: will reset msvdx.\n");
> +
> +		if (ved_core_reset(ved_priv)) {
> +			ret = -EBUSY;
> +			IPVR_ERROR("VED: Reset failed.\n");
> +			goto out_power_put;
> +		}
> +
> +		ved_priv->ved_needs_reset = 0;
> +		ved_priv->ved_busy = false;
> +
> +		if (ved_core_init(ved_priv->dev_priv)) {
> +			ret = -EBUSY;
> +			IPVR_DEBUG_WARN("VED: ved_core_init fail.\n");
> +			goto out_power_put;
> +		}
> +
> +		spin_lock_irqsave(&ved_priv->ved_lock, irq_flags);
> +	}
> +
> +	if (!ved_priv->ved_fw_loaded) {
> +		spin_unlock_irqrestore(&ved_priv->ved_lock, irq_flags);
> +		IPVR_DEBUG_VED("VED: reload FW to MTX\n");
> +		ret = ved_setup_fw(ved_priv);
> +		if (ret) {
> +			IPVR_ERROR("VED: fail to load FW\n");
> +			/* FIXME: find a proper return value */
> +			ret = -EFAULT;
> +			goto out_power_put;
> +		}
> +		ved_priv->ved_fw_loaded = true;
> +
> +		IPVR_DEBUG_VED("VED: load firmware successfully\n");
> +		spin_lock_irqsave(&ved_priv->ved_lock, irq_flags);
> +	}
> +
> +	ved_priv->ved_busy = true;
> +	spin_unlock_irqrestore(&ved_priv->ved_lock, irq_flags);
> +	IPVR_DEBUG_VED("VED: commit command to HW,seq=0x%08x\n",
> +			  sequence);
> +	ret = ved_map_command(ved_priv, cmd_buffer, cmd_size,
> +				NULL, sequence, 0, ipvr_ctx);
> +	if (ret) {
> +		IPVR_ERROR("VED: Failed to extract cmd.\n");
> +		goto out_power_put;
> +	}
> +
> +	return 0;
> +out_power_put:
> +	if (WARN_ON(ipvr_runtime_pm_put(ved_priv->dev_priv, false) < 0))
> +		IPVR_ERROR("Failed to put ipvr power\n");
> +	return ret;
> +}
> +
> +int ved_cmdbuf_video(struct ved_private *ved_priv,
> +						struct drm_ipvr_gem_object
> *cmd_buffer,
> +						u32 cmdbuf_size,
> +						struct ipvr_context *ipvr_ctx)
> +{
> +	return ved_submit_video_cmdbuf(ved_priv, cmd_buffer,
> cmdbuf_size, ipvr_ctx, 0);
> +}
> +
> +static int ved_handle_panic_msg(struct ved_private *ved_priv,
> +					struct fw_panic_msg *panic_msg)
> +{
> +	/* For VXD385 firmware, fence value is not validate here */
> +	u32 diff = 0;
> +	u16 fence;
> +	u32 err_trig, irq_sts, mmu_sts, dmac_sts;
> +	struct drm_ipvr_private *dev_priv = ved_priv->dev_priv;
> +	IPVR_DEBUG_WARN("MSVDX: MSGID_CMD_HW_PANIC:"
> +		  "Fault detected"
> +		  " - Fence: %08x"
> +		  " - fe_status mb: %08x"
> +		  " - be_status mb: %08x"
> +		  " - reserved2: %08x"
> +		  " - last mb: %08x"
> +		  " - resetting and ignoring error\n",
> +		  panic_msg->header.bits.msg_fence,
> +		  panic_msg->fe_status,
> +		  panic_msg->be_status,
> +		  panic_msg->mb.bits.reserved2,
> +		  panic_msg->mb.bits.last_mb);
> +	/*
> +	 * If bit 8 of MSVDX_INTERRUPT_STATUS is set the fault
> +	 * was caused in the DMAC. In this case you should
> +	 * check bits 20:22 of MSVDX_INTERRUPT_STATUS.
> +	 * If bit 20 is set there was a problem DMAing the buffer
> +	 * back to host. If bit 22 is set you'll need to get the
> +	 * value of MSVDX_DMAC_STREAM_STATUS (0x648).
> +	 * If bit 1 is set then there was an issue DMAing
> +	 * the bitstream or termination code for parsing.
> +	 */
> +	err_trig = IPVR_REG_READ32(MSVDX_COMMS_ERROR_TRIG);
> +	irq_sts = IPVR_REG_READ32(MSVDX_INTERRUPT_STATUS_OFFSET);
> +	mmu_sts = IPVR_REG_READ32(MSVDX_MMU_STATUS_OFFSET);
> +	dmac_sts =
> IPVR_REG_READ32(MSVDX_DMAC_STREAM_STATUS_OFFSET);
> +	IPVR_DEBUG_WARN("MSVDX: MSVDX_COMMS_ERROR_TRIG is
> 0x%x,"
> +		"MSVDX_INTERRUPT_STATUS is 0x%x,"
> +		"MSVDX_MMU_STATUS is 0x%x,"
> +		"MSVDX_DMAC_STREAM_STATUS is 0x%x.\n",
> +		err_trig, irq_sts, mmu_sts, dmac_sts);
> +
> +	trace_ved_irq_panic(panic_msg, err_trig, irq_sts, mmu_sts,
> dmac_sts);
> +
> +	fence = panic_msg->header.bits.msg_fence;
> +
> +	ved_priv->ved_needs_reset = 1;
> +
> +	diff = ved_priv->ved_cur_seq - dev_priv->last_seq;
> +	if (diff > 0x0FFFFFFF)
> +		ved_priv->ved_cur_seq++;
> +
> +	IPVR_DEBUG_WARN("VED: Fence ID missing, assuming %08x\n",
> +			ved_priv->ved_cur_seq);
> +
> +	ipvr_fence_process(dev_priv, ved_priv->ved_cur_seq,
> IPVR_CMD_FAILED);
> +
> +	/* Flush the command queue */
> +	ved_flush_cmd_queue(ved_priv);
> +	ved_priv->ved_busy = false;
> +	return 0;
> +}
> +
> +static int
> +ved_handle_completed_msg(struct ved_private *ved_priv,
> +				struct fw_completed_msg *completed_msg)
> +{
> +	struct drm_ipvr_private *dev_priv = ved_priv->dev_priv;
> +	u16 fence, flags;
> +	int ret = 0;
> +	struct ipvr_context *ipvr_ctx;
> +
> +	IPVR_DEBUG_VED("VED: MSGID_CMD_COMPLETED:"
> +		" - Fence: %08x - flags: %08x - vdebcr: %08x"
> +		" - first_mb : %d - last_mb: %d\n",
> +		completed_msg->header.bits.msg_fence,
> +		completed_msg->flags, completed_msg->vdebcr,
> +		completed_msg->mb.bits.start_mb,
> +		completed_msg->mb.bits.last_mb);
> +
> +	flags = completed_msg->flags;
> +	fence = completed_msg->header.bits.msg_fence;
> +
> +	ved_priv->ved_cur_seq = fence;
> +
> +	ipvr_fence_process(dev_priv, fence, IPVR_CMD_SUCCESS);
> +
> +	ipvr_ctx = ipvr_find_ctx_with_fence(dev_priv, fence);
> +	trace_ved_irq_completed(ipvr_ctx, completed_msg);
> +	if (unlikely(ipvr_ctx == NULL)) {
> +		IPVR_DEBUG_WARN("abnormal complete msg:
> seq=0x%04x.\n", fence);
> +		ret = -EINVAL;
> +		goto out_clear_busy;
> +	}
> +
> +	if (flags & FW_VA_RENDER_HOST_INT) {
> +		/* Now send the next command from the msvdx cmd queue
> */
> +		if (ved_cmd_dequeue_send(ved_priv) == 0)
> +			goto out;
> +	}
> +
> +out_clear_busy:
> +	ved_priv->ved_busy = false;
> +out:
> +	return 0;
> +}
> +
> +/*
> + * MSVDX MTX interrupt
> + */
> +static void ved_mtx_interrupt(struct ved_private *ved_priv)
> +{
> +	static u32 buf[128]; /* message buffer */
> +	u32 ridx, widx, buf_size, buf_offset;
> +	u32 num, ofs; /* message num and offset */
> +	union msg_header *header;
> +	int cmd_complete = 0;
> +	struct drm_ipvr_private *dev_priv = ved_priv->dev_priv;
> +	IPVR_DEBUG_VED("VED: Got a VED MTX interrupt.\n");
> +
> +	/* we need clocks enabled before we touch VEC local ram,
> +	 * but fw will take care of the clock after fw is loaded
> +	 */
> +
> +loop: /* just for coding style check */
> +	ridx = IPVR_REG_READ32(MSVDX_COMMS_TO_HOST_RD_INDEX);
> +	widx =
> IPVR_REG_READ32(MSVDX_COMMS_TO_HOST_WRT_INDEX);
> +
> +	/* Get out of here if nothing */
> +	if (ridx == widx)
> +		goto done;
> +
> +	buf_size =
> IPVR_REG_READ32(MSVDX_COMMS_TO_HOST_BUF_SIZE) &
> +		((1 << 16) - 1);
> +	/*0x2000 is VEC Local Ram offset*/
> +	buf_offset =
> (IPVR_REG_READ32(MSVDX_COMMS_TO_HOST_BUF_SIZE) >> 16)
> +		+ 0x2000;
> +
> +	ofs = 0;
> +	buf[ofs] = IPVR_REG_READ32(buf_offset + (ridx << 2));
> +	header = (union msg_header *)buf;
> +
> +	/* round to nearest word */
> +	num = (header->bits.msg_size + 3) / 4;
> +
> +	/* ASSERT(num <= sizeof(buf) / sizeof(u32)); */
> +
> +	if (++ridx >= buf_size)
> +		ridx = 0;
> +
> +	for (ofs++; ofs < num; ofs++) {
> +		buf[ofs] = IPVR_REG_READ32(buf_offset + (ridx << 2));
> +
> +		if (++ridx >= buf_size)
> +			ridx = 0;
> +	}
> +
> +	/* Update the Read index */
> +	IPVR_REG_WRITE32(ridx, MSVDX_COMMS_TO_HOST_RD_INDEX);
> +
> +	if (ved_priv->ved_needs_reset)
> +		goto loop;
> +
> +	switch (header->bits.msg_type) {
> +	case MTX_MSGID_HW_PANIC: {
> +		struct fw_panic_msg *panic_msg = (struct fw_panic_msg
> *)buf;
> +		cmd_complete = 1;
> +		ved_handle_panic_msg(ved_priv, panic_msg);
> +		/**
> +		 * panic msg clears all pending cmds and breaks the cmd<-
> >irq pairing
> +		 */
> +		if (WARN_ON(ipvr_runtime_pm_put_all(ved_priv->dev_priv,
> true) < 0)) {
> +			IPVR_ERROR("Error clearing pending events and put
> power\n");
> +		}
> +		goto done;
> +	}
> +
> +	case MTX_MSGID_COMPLETED: {
> +		struct fw_completed_msg *completed_msg =
> +					(struct fw_completed_msg *)buf;
> +		cmd_complete = 1;
> +		if (ved_handle_completed_msg(ved_priv, completed_msg))
> +			cmd_complete = 0;
> +		/**
> +		 * for VP8, cmd and COMPLETED msg are paired. we can
> safely call
> +		 * get in execbuf_ioctl and call put here
> +		 */
> +		if (WARN_ON(ipvr_runtime_pm_put(ved_priv->dev_priv,
> true) < 0)) {
> +			IPVR_ERROR("Error put power\n");
> +		}
> +		break;
> +	}
> +
> +	default:
> +		IPVR_ERROR("VED: unknown message from MTX,
> ID:0x%08x.\n",
> +			header->bits.msg_type);
> +		goto done;
> +	}
> +
> +done:
> +	IPVR_DEBUG_VED("VED Interrupt: finish process a message.\n");
> +	if (ridx != widx) {
> +		IPVR_DEBUG_VED("VED: there are more message to be
> read.\n");
> +		goto loop;
> +	}
> +
> +	mb();	/* TBD check this... */
> +}
> +
> +/*
> + * MSVDX interrupt.
> + */
> +int ved_irq_handler(struct ved_private *ved_priv)
> +{
> +	u32 msvdx_stat;
> +	struct drm_ipvr_private *dev_priv = ved_priv->dev_priv;
> +	msvdx_stat =
> IPVR_REG_READ32(MSVDX_INTERRUPT_STATUS_OFFSET);
> +
> +	/* driver only needs to handle mtx irq
> +	 * For MMU fault irq, there's always a HW PANIC generated
> +	 * if HW/FW is totally hang, the lockup function will handle
> +	 * the reseting
> +	 */
> +	if (msvdx_stat &
> MSVDX_INTERRUPT_STATUS_MMU_FAULT_IRQ_MASK) {
> +		/*Ideally we should we should never get to this */
> +		IPVR_DEBUG_IRQ("VED: MMU Fault:0x%x\n", msvdx_stat);
> +
> +		/* Pause MMU */
> +
> 	IPVR_REG_WRITE32(MSVDX_MMU_CONTROL0_MMU_PAUSE_MAS
> K,
> +			     MSVDX_MMU_CONTROL0_OFFSET);
> +		wmb();
> +
> +		/* Clear this interupt bit only */
> +
> 	IPVR_REG_WRITE32(MSVDX_INTERRUPT_STATUS_MMU_FAULT_IR
> Q_MASK,
> +			     MSVDX_INTERRUPT_CLEAR_OFFSET);
> +		IPVR_REG_READ32(MSVDX_INTERRUPT_CLEAR_OFFSET);
> +		rmb();
> +
> +		ved_priv->ved_needs_reset = 1;
> +	} else if (msvdx_stat &
> MSVDX_INTERRUPT_STATUS_MTX_IRQ_MASK) {
> +		IPVR_DEBUG_IRQ("VED: msvdx_stat: 0x%x(MTX)\n",
> msvdx_stat);
> +
> +		/* Clear all interupt bits */
> +		IPVR_REG_WRITE32(0xffff,
> MSVDX_INTERRUPT_CLEAR_OFFSET);
> +
> +		IPVR_REG_READ32(MSVDX_INTERRUPT_CLEAR_OFFSET);
> +		rmb();
> +
> +		ved_mtx_interrupt(ved_priv);
> +	}
> +
> +	return 0;
> +}
> +
> +int ved_check_idle(struct ved_private *ved_priv)
> +{
> +	int loop, ret;
> +	struct drm_ipvr_private *dev_priv;
> +	if (!ved_priv)
> +		return 0;
> +
> +	dev_priv = ved_priv->dev_priv;
> +	if (!ved_priv->ved_fw_loaded)
> +		return 0;
> +
> +	if (ved_priv->ved_busy) {
> +		IPVR_DEBUG_PM("VED: ved_busy was set, return busy.\n");
> +		return -EBUSY;
> +	}
> +
> +	/* on some cores below 50502, there is one instance that
> +	 * read requests may not go to zero is in the case of a page fault,
> +	 * check core revision by reg MSVDX_CORE_REV, 385 core is 0x20001
> +	 * check if mmu page fault happend by reg
> MSVDX_INTERRUPT_STATUS,
> +	 * check was it a page table rather than a protection fault
> +	 * by reg MSVDX_MMU_STATUS, for such case,
> +	 * need call ved_core_reset as the work around */
> +	if ((IPVR_REG_READ32(MSVDX_CORE_REV_OFFSET) < 0x00050502)
> &&
> +		(IPVR_REG_READ32(MSVDX_INTERRUPT_STATUS_OFFSET)
> +			&
> MSVDX_INTERRUPT_STATUS_MMU_FAULT_IRQ_MASK) &&
> +		(IPVR_REG_READ32(MSVDX_MMU_STATUS_OFFSET) & 1)) {
> +		IPVR_DEBUG_WARN("mmu page fault, recover by
> core_reset.\n");
> +		return 0;
> +	}
> +
> +	/* check MSVDX_MMU_MEM_REQ to confirm there's no memory
> requests */
> +	for (loop = 0; loop < 10; loop++)
> +		ret = ved_wait_for_register(ved_priv,
> +					MSVDX_MMU_MEM_REQ_OFFSET,
> +					0, 0xff, 100, 1);
> +	if (ret) {
> +		IPVR_DEBUG_WARN("MSVDX: MSVDX_MMU_MEM_REQ
> reg is 0x%x,\n"
> +				"indicate mem busy, prevent power off ved,"
> +				"MSVDX_COMMS_FW_STATUS reg is 0x%x,"
> +				"MSVDX_COMMS_ERROR_TRIG reg is 0x%x,",
> +
> 	IPVR_REG_READ32(MSVDX_MMU_MEM_REQ_OFFSET),
> +
> 	IPVR_REG_READ32(MSVDX_COMMS_FW_STATUS),
> +
> 	IPVR_REG_READ32(MSVDX_COMMS_ERROR_TRIG));
> +		return -EBUSY;
> +	}
> +
> +	return 0;
> +}
> +
> +void ved_check_reset_fw(struct ved_private *ved_priv)
> +{
> +	unsigned long irq_flags;
> +
> +	spin_lock_irqsave(&ved_priv->ved_lock, irq_flags);
> +
> +	/* handling fw upload here if required */
> +	/* power off first, then hw_begin will power up/upload FW correctly
> */
> +	if (ved_priv->ved_needs_reset &
> MSVDX_RESET_NEEDS_REUPLOAD_FW) {
> +		ved_priv->ved_needs_reset &=
> ~MSVDX_RESET_NEEDS_REUPLOAD_FW;
> +		spin_unlock_irqrestore(&ved_priv->ved_lock, irq_flags);
> +		IPVR_DEBUG_VED("VED: force power off VED due to decode
> err\n");
> +		spin_lock_irqsave(&ved_priv->ved_lock, irq_flags);
> +	}
> +	spin_unlock_irqrestore(&ved_priv->ved_lock, irq_flags);
> +}
> diff --git a/drivers/gpu/drm/ipvr/ved_cmd.h
> b/drivers/gpu/drm/ipvr/ved_cmd.h
> new file mode 100644
> index 0000000..f604b02
> --- /dev/null
> +++ b/drivers/gpu/drm/ipvr/ved_cmd.h
> @@ -0,0 +1,70 @@
> +/*********************************************************
> *****************
> + * ved_cmd.h: VED header file to support command buffer handling
> + *
> + * Copyright (c) 2014 Intel Corporation, Hillsboro, OR, USA
> + * Copyright (c) Imagination Technologies Limited, UK
> + * Copyright (c) 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
> + * All Rights Reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of
> MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
> License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along
> with
> + * this program; if not, write to the Free Software Foundation, Inc.,
> + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
> + *
> + * Authors:
> + *    Fei Jiang <fei.jiang at intel.com>
> + *    Yao Cheng <yao.cheng at intel.com>
> + *
> +
> **********************************************************
> ****************/
> +
> +#ifndef _VED_CMD_H_
> +#define _VED_CMD_H_
> +
> +#include "ipvr_drv.h"
> +#include "ipvr_drm.h"
> +#include "ipvr_gem.h"
> +#include "ipvr_fence.h"
> +#include "ipvr_exec.h"
> +#include "ved_reg.h"
> +#include "ved_pm.h"
> +
> +struct ved_cmd_queue {
> +	struct list_head head;
> +	void *cmd;
> +	u32 cmd_size;
> +	u16 cmd_seq;
> +	u32 fence_flag;
> +	u8 tiling_scheme;
> +	u8 tiling_stride;
> +	struct ipvr_context *ipvr_ctx;
> +};
> +
> +int ved_irq_handler(struct ved_private *ved_priv);
> +
> +int ved_mtx_send(struct ved_private *ved_priv, const void *msg);
> +
> +int ved_check_idle(struct ved_private *ved_priv);
> +
> +void ved_check_reset_fw(struct ved_private *ved_priv);
> +
> +void ved_flush_cmd_queue(struct ved_private *ved_priv);
> +
> +int ved_cmdbuf_video(struct ved_private *ved_priv,
> +			struct drm_ipvr_gem_object *cmd_buffer,
> +			u32 cmdbuf_size, struct ipvr_context *ipvr_ctx);
> +
> +int ved_submit_video_cmdbuf(struct ved_private *ved_priv,
> +			struct drm_ipvr_gem_object *cmd_buffer, u32
> cmd_size,
> +			struct ipvr_context *ipvr_ctx, u32 fence_flag);
> +
> +int ved_cmd_dequeue_send(struct ved_private *ved_priv);
> +
> +#endif
> diff --git a/drivers/gpu/drm/ipvr/ved_fw.c b/drivers/gpu/drm/ipvr/ved_fw.c
> new file mode 100644
> index 0000000..43682da
> --- /dev/null
> +++ b/drivers/gpu/drm/ipvr/ved_fw.c
> @@ -0,0 +1,1199 @@
> +/*********************************************************
> *****************
> + * ved_fw.c: VED initialization and mtx-firmware upload
> + *
> + * Copyright (c) 2014 Intel Corporation, Hillsboro, OR, USA
> + * Copyright (c) Imagination Technologies Limited, UK
> + * Copyright (c) 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
> + * All Rights Reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of
> MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
> License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along
> with
> + * this program; if not, write to the Free Software Foundation, Inc.,
> + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
> + *
> + * Authors:
> + *    Fei Jiang <fei.jiang at intel.com>
> + *    Yao Cheng <yao.cheng at intel.com>
> + *
> +
> **********************************************************
> ****************/
> +
> +#include "ipvr_bo.h"
> +#include "ipvr_mmu.h"
> +#include "ipvr_gem.h"
> +#include "ved_fw.h"
> +#include "ved_cmd.h"
> +#include "ved_msg.h"
> +#include "ved_reg.h"
> +#include <linux/firmware.h>
> +#include <linux/module.h>
> +#include <asm/cacheflush.h>
> +
> +#define STACKGUARDWORD			0x10101010
> +#define MSVDX_MTX_DATA_LOCATION		0x82880000
> +#define UNINITILISE_MEM			0xcdcdcdcd
> +#define FIRMWARE_NAME "msvdx_fw_mfld_DE2.0.bin"
> +
> +/* VED FW header */
> +struct ved_fw {
> +	u32 ver;
> +	u32 text_size;
> +	u32 data_size;
> +	u32 data_location;
> +};
> +
> +
> +void ved_clear_irq(struct ved_private *ved_priv)
> +{
> +	u32 mtx_int = 0;
> +	struct drm_ipvr_private *dev_priv = ved_priv->dev_priv;
> +	/* Clear MTX interrupt */
> +	REGIO_WRITE_FIELD_LITE(mtx_int, MSVDX_INTERRUPT_STATUS,
> MTX_IRQ, 1);
> +	IPVR_REG_WRITE32(mtx_int, MSVDX_INTERRUPT_CLEAR_OFFSET);
> +}
> +
> +/* following two functions also works for CLV and MFLD */
> +/* IPVR_INT_ENABLE_R is set in ipvr_irq_(un)install_islands */
> +void ved_disable_irq(struct ved_private *ved_priv)
> +{
> +	u32 enables = 0;
> +	struct drm_ipvr_private *dev_priv = ved_priv->dev_priv;
> +	REGIO_WRITE_FIELD_LITE(enables, MSVDX_INTERRUPT_STATUS,
> MTX_IRQ, 0);
> +	IPVR_REG_WRITE32(enables,
> MSVDX_HOST_INTERRUPT_ENABLE_OFFSET);
> +}
> +
> +void ved_enable_irq(struct ved_private *ved_priv)
> +{
> +	u32 enables = 0;
> +	struct drm_ipvr_private *dev_priv = ved_priv->dev_priv;
> +	/* Only enable the master core IRQ*/
> +	REGIO_WRITE_FIELD_LITE(enables, MSVDX_INTERRUPT_STATUS,
> MTX_IRQ,
> +			       1);
> +	IPVR_REG_WRITE32(enables,
> MSVDX_HOST_INTERRUPT_ENABLE_OFFSET);
> +}
> +
> +/*
> + * the original 1000 of udelay is derive from reference driver
> + * From Liu, Haiyang, changed the originial udelay value from 1000 to 5
> + * can save 3% C0 residence
> + */
> +int
> +ved_wait_for_register(struct ved_private *ved_priv,
> +			    u32 offset, u32 value, u32 enable,
> +			    u32 poll_cnt, u32 timeout)
> +{
> +	u32 reg_value = 0;
> +	struct drm_ipvr_private *dev_priv = ved_priv->dev_priv;
> +	while (poll_cnt) {
> +		reg_value = IPVR_REG_READ32(offset);
> +		if (value == (reg_value & enable))
> +			return 0;
> +
> +		/* Wait a bit */
> +		IPVR_UDELAY(timeout);
> +		poll_cnt--;
> +	}
> +	IPVR_DEBUG_REG("MSVDX: Timeout while waiting for
> register %08x:"
> +		       " expecting %08x (mask %08x), got %08x\n",
> +		       offset, value, enable, reg_value);
> +
> +	return -EFAULT;
> +}
> +
> +void
> +ved_set_clocks(struct ved_private *ved_priv, u32 clock_state)
> +{
> +	u32 old_clock_state = 0;
> +	struct drm_ipvr_private *dev_priv = ved_priv->dev_priv;
> +	/* IPVR_DEBUG_VED("SetClocks to %x.\n", clock_state); */
> +	old_clock_state =
> IPVR_REG_READ32(MSVDX_MAN_CLK_ENABLE_OFFSET);
> +	if (old_clock_state == clock_state)
> +		return;
> +
> +	if (clock_state == 0) {
> +		/* Turn off clocks procedure */
> +		if (old_clock_state) {
> +			/* Turn off all the clocks except core */
> +			IPVR_REG_WRITE32(
> +
> 	MSVDX_MAN_CLK_ENABLE_CORE_MAN_CLK_ENABLE_MASK,
> +				MSVDX_MAN_CLK_ENABLE_OFFSET);
> +
> +			/* Make sure all the clocks are off except core */
> +			ved_wait_for_register(ved_priv,
> +				MSVDX_MAN_CLK_ENABLE_OFFSET,
> +
> 	MSVDX_MAN_CLK_ENABLE_CORE_MAN_CLK_ENABLE_MASK,
> +				0xffffffff, 2000000, 5);
> +
> +			/* Turn off core clock */
> +			IPVR_REG_WRITE32(0,
> MSVDX_MAN_CLK_ENABLE_OFFSET);
> +		}
> +	} else {
> +		u32 clocks_en = clock_state;
> +
> +		/*Make sure that core clock is not accidentally turned off */
> +		clocks_en |=
> MSVDX_MAN_CLK_ENABLE_CORE_MAN_CLK_ENABLE_MASK;
> +
> +		/* If all clocks were disable do the bring up procedure */
> +		if (old_clock_state == 0) {
> +			/* turn on core clock */
> +			IPVR_REG_WRITE32(
> +
> 	MSVDX_MAN_CLK_ENABLE_CORE_MAN_CLK_ENABLE_MASK,
> +				MSVDX_MAN_CLK_ENABLE_OFFSET);
> +
> +			/* Make sure core clock is on */
> +			ved_wait_for_register(ved_priv,
> +				MSVDX_MAN_CLK_ENABLE_OFFSET,
> +
> 	MSVDX_MAN_CLK_ENABLE_CORE_MAN_CLK_ENABLE_MASK,
> +				0xffffffff, 2000000, 5);
> +
> +			/* turn on the other clocks as well */
> +			IPVR_REG_WRITE32(clocks_en,
> MSVDX_MAN_CLK_ENABLE_OFFSET);
> +
> +			/* Make sure that all they are on */
> +			ved_wait_for_register(ved_priv,
> +					MSVDX_MAN_CLK_ENABLE_OFFSET,
> +					clocks_en, 0xffffffff, 2000000, 5);
> +		} else {
> +			IPVR_REG_WRITE32(clocks_en,
> MSVDX_MAN_CLK_ENABLE_OFFSET);
> +
> +			/* Make sure that they are on */
> +			ved_wait_for_register(ved_priv,
> +					MSVDX_MAN_CLK_ENABLE_OFFSET,
> +					clocks_en, 0xffffffff, 2000000, 5);
> +		}
> +	}
> +}
> +
> +int ved_core_reset(struct ved_private *ved_priv)
> +{
> +	int ret = 0;
> +	int loop;
> +	u32 cmd;
> +	struct drm_ipvr_private *dev_priv = ved_priv->dev_priv;
> +	/* Enable Clocks */
> +	IPVR_DEBUG_GENERAL("Enabling clocks.\n");
> +	ved_set_clocks(ved_priv, clk_enable_all);
> +
> +	/* Always pause the MMU as the core may be still active
> +	 * when resetting.  It is very bad to have memory
> +	 * activity at the same time as a reset - Very Very bad
> +	 */
> +	IPVR_REG_WRITE32(2, MSVDX_MMU_CONTROL0_OFFSET);
> +
> +	/* BRN26106, BRN23944, BRN33671 */
> +	/* This is neccessary for all cores up to Tourmaline */
> +	if ((IPVR_REG_READ32(MSVDX_CORE_REV_OFFSET) < 0x00050502)
> &&
> +		(IPVR_REG_READ32(MSVDX_INTERRUPT_STATUS_OFFSET)
> +			&
> MSVDX_INTERRUPT_STATUS_MMU_FAULT_IRQ_MASK) &&
> +		(IPVR_REG_READ32(MSVDX_MMU_STATUS_OFFSET) & 1)) {
> +		u32 *pptd;
> +		int loop;
> +		unsigned long ptd_addr;
> +
> +		/* do work around */
> +		ptd_addr = page_to_pfn(ved_priv->mmu_recover_page) <<
> PAGE_SHIFT;
> +		/* fixme: check ptd_addr bit length */
> +		pptd = kmap(ved_priv->mmu_recover_page);
> +		if (!pptd) {
> +			IPVR_ERROR("failed to kmap mmu recover page.\n");
> +			return -ENOMEM;
> +		}
> +		for (loop = 0; loop < 1024; loop++)
> +			pptd[loop] = ptd_addr | 0x00000003;
> +		IPVR_REG_WRITE32(ptd_addr,
> MSVDX_MMU_DIR_LIST_BASE_OFFSET +  0);
> +		IPVR_REG_WRITE32(ptd_addr,
> MSVDX_MMU_DIR_LIST_BASE_OFFSET +  4);
> +		IPVR_REG_WRITE32(ptd_addr,
> MSVDX_MMU_DIR_LIST_BASE_OFFSET +  8);
> +		IPVR_REG_WRITE32(ptd_addr,
> MSVDX_MMU_DIR_LIST_BASE_OFFSET + 12);
> +
> +		IPVR_REG_WRITE32(6, MSVDX_MMU_CONTROL0_OFFSET);
> +
> 	IPVR_REG_WRITE32(MSVDX_INTERRUPT_STATUS_MMU_FAULT_IR
> Q_MASK,
> +
> 	MSVDX_INTERRUPT_STATUS_OFFSET);
> +		kunmap(ved_priv->mmu_recover_page);
> +	}
> +
> +	/* make sure *ALL* outstanding reads have gone away */
> +	for (loop = 0; loop < 10; loop++)
> +		ret = ved_wait_for_register(ved_priv,
> MSVDX_MMU_MEM_REQ_OFFSET,
> +					    0, 0xff, 100, 1);
> +	if (ret) {
> +		IPVR_DEBUG_WARN("MSVDX_MMU_MEM_REQ is %d,\n"
> +			"indicate outstanding read request 0.\n",
> +
> 	IPVR_REG_READ32(MSVDX_MMU_MEM_REQ_OFFSET));
> +		ret = -1;
> +		return ret;
> +	}
> +	/* disconnect RENDEC decoders from memory */
> +	cmd = IPVR_REG_READ32(MSVDX_RENDEC_CONTROL1_OFFSET);
> +	REGIO_WRITE_FIELD(cmd, MSVDX_RENDEC_CONTROL1,
> RENDEC_DEC_DISABLE, 1);
> +	IPVR_REG_WRITE32(cmd, MSVDX_RENDEC_CONTROL1_OFFSET);
> +
> +	/* Issue software reset for all but core */
> +	IPVR_REG_WRITE32((unsigned
> int)~MSVDX_CONTROL_MSVDX_SOFT_RESET_MASK,
> +			MSVDX_CONTROL_OFFSET);
> +	IPVR_REG_READ32(MSVDX_CONTROL_OFFSET);
> +	/* bit format is set as little endian */
> +	IPVR_REG_WRITE32(0, MSVDX_CONTROL_OFFSET);
> +	/* make sure read requests are zero */
> +	ret = ved_wait_for_register(ved_priv,
> MSVDX_MMU_MEM_REQ_OFFSET,
> +				    0, 0xff, 100, 100);
> +	if (!ret) {
> +		/* Issue software reset */
> +
> 	IPVR_REG_WRITE32(MSVDX_CONTROL_MSVDX_SOFT_RESET_MAS
> K,
> +				MSVDX_CONTROL_OFFSET);
> +
> +		ret = ved_wait_for_register(ved_priv,
> MSVDX_CONTROL_OFFSET, 0,
> +
> 	MSVDX_CONTROL_MSVDX_SOFT_RESET_MASK,
> +					2000000, 5);
> +		if (!ret) {
> +			/* Clear interrupt enabled flag */
> +			IPVR_REG_WRITE32(0,
> MSVDX_HOST_INTERRUPT_ENABLE_OFFSET);
> +
> +			/* Clear any pending interrupt flags */
> +			IPVR_REG_WRITE32(0xFFFFFFFF,
> MSVDX_INTERRUPT_CLEAR_OFFSET);
> +		} else {
> +			IPVR_DEBUG_WARN("MSVDX_CONTROL_OFFSET
> is %d,\n"
> +				"indicate software reset failed.\n",
> +
> 	IPVR_REG_READ32(MSVDX_CONTROL_OFFSET));
> +		}
> +	} else {
> +		IPVR_DEBUG_WARN("MSVDX_MMU_MEM_REQ is %d,\n"
> +			"indicate outstanding read request 1.\n",
> +
> 	IPVR_REG_READ32(MSVDX_MMU_MEM_REQ_OFFSET));
> +	}
> +	return ret;
> +}
> +
> +/*
> + * Reset chip and disable interrupts.
> + * Return 0 success, 1 failure
> + * use ved_core_reset instead of ved_reset
> + */
> +int ved_reset(struct ved_private *ved_priv)
> +{
> +	int ret = 0;
> +	struct drm_ipvr_private *dev_priv = ved_priv->dev_priv;
> +	/* Issue software reset */
> +	/* IPVR_REG_WRITE32(msvdx_sw_reset_all, MSVDX_CONTROL); */
> +
> 	IPVR_REG_WRITE32(MSVDX_CONTROL_MSVDX_SOFT_RESET_MAS
> K,
> +			MSVDX_CONTROL_OFFSET);
> +
> +	ret = ved_wait_for_register(ved_priv, MSVDX_CONTROL_OFFSET, 0,
> +			MSVDX_CONTROL_MSVDX_SOFT_RESET_MASK,
> 2000000, 5);
> +	if (!ret) {
> +		/* Clear interrupt enabled flag */
> +		IPVR_REG_WRITE32(0,
> MSVDX_HOST_INTERRUPT_ENABLE_OFFSET);
> +
> +		/* Clear any pending interrupt flags */
> +		IPVR_REG_WRITE32(0xFFFFFFFF,
> MSVDX_INTERRUPT_CLEAR_OFFSET);
> +	} else {
> +		IPVR_DEBUG_WARN("MSVDX_CONTROL_OFFSET is %d,\n"
> +			"indicate software reset failed.\n",
> +			IPVR_REG_READ32(MSVDX_CONTROL_OFFSET));
> +	}
> +
> +	return ret;
> +}
> +
> +static int ved_alloc_ccb_for_rendec(struct ved_private *ved_priv,
> +
> 	int32_t ccb0_size,
> +
> 	int32_t ccb1_size)
> +{
> +	int ret;
> +	size_t size;
> +	u8 *ccb0_addr = NULL;
> +	u8 *ccb1_addr = NULL;
> +
> +	IPVR_DEBUG_INIT("VED: setting up RENDEC, allocate CCB 0/1\n");
> +
> +	/*handling for ccb0*/
> +	if (ved_priv->ccb0 == NULL) {
> +		size = roundup(ccb0_size, PAGE_SIZE);
> +		if (size == 0)
> +			return -EINVAL;
> +
> +		/* Allocate the new object */
> +		ved_priv->ccb0 = ipvr_gem_create(ved_priv->dev_priv, size,
> 0, 0);
> +		if (IS_ERR(ved_priv->ccb0)) {
> +			ret = PTR_ERR(ved_priv->ccb0);
> +			IPVR_ERROR("VED: failed to allocate ccb0
> buffer: %d.\n", ret);
> +			ved_priv->ccb0 = NULL;
> +			return -ENOMEM;
> +		}
> +
> +		ved_priv->base_addr0 =
> ipvr_gem_object_mmu_offset(ved_priv->ccb0);
> +
> +		ccb0_addr = ipvr_gem_object_vmap(ved_priv->ccb0);
> +		if (!ccb0_addr) {
> +			ret = -ENOMEM;
> +			IPVR_ERROR("VED: kmap failed for ccb0
> buffer: %d.\n", ret);
> +			goto err_free_ccb0;
> +		}
> +
> +		memset(ccb0_addr, 0, size);
> +		vunmap(ccb0_addr);
> +	}
> +
> +	/*handling for ccb1*/
> +	if (ved_priv->ccb1 == NULL) {
> +		size = roundup(ccb1_size, PAGE_SIZE);
> +		if (size == 0) {
> +			return -EINVAL;
> +			goto err_free_ccb0;
> +		}
> +
> +		/* Allocate the new object */
> +		ved_priv->ccb1 = ipvr_gem_create(ved_priv->dev_priv, size,
> 0, 0);
> +		if (IS_ERR(ved_priv->ccb1)) {
> +			ret = PTR_ERR(ved_priv->ccb1);
> +			IPVR_ERROR("VED: failed to allocate ccb1
> buffer: %d.\n", ret);
> +			goto err_free_ccb0;
> +		}
> +
> +		ved_priv->base_addr1 =
> ipvr_gem_object_mmu_offset(ved_priv->ccb1);
> +
> +		ccb1_addr = ipvr_gem_object_vmap(ved_priv->ccb1);
> +		if (!ccb1_addr) {
> +			ret = -ENOMEM;
> +			IPVR_ERROR("VED: kmap failed for ccb1
> buffer: %d.\n", ret);
> +			goto err_free_ccb1;
> +		}
> +
> +		memset(ccb1_addr, 0, size);
> +		vunmap(ccb1_addr);
> +	}
> +
> +	IPVR_DEBUG_INIT("VED: RENDEC A: %08x RENDEC B: %08x\n",
> +			ved_priv->base_addr0, ved_priv->base_addr1);
> +
> +	return 0;
> +err_free_ccb1:
> +	drm_gem_object_unreference_unlocked(&ved_priv->ccb1->base);
> +	ved_priv->ccb1 = NULL;
> +err_free_ccb0:
> +	drm_gem_object_unreference_unlocked(&ved_priv->ccb0->base);
> +	ved_priv->ccb0 = NULL;
> +	return ret;
> +}
> +
> +static void ved_free_ccb(struct ved_private *ved_priv)
> +{
> +	if (ved_priv->ccb0) {
> +		drm_gem_object_unreference_unlocked(&ved_priv->ccb0-
> >base);
> +		ved_priv->ccb0 = NULL;
> +	}
> +	if (ved_priv->ccb1) {
> +		drm_gem_object_unreference_unlocked(&ved_priv->ccb1-
> >base);
> +		ved_priv->ccb1 = NULL;
> +	}
> +}
> +
> +static void ved_rendec_init_by_reg(struct ved_private *ved_priv)
> +{
> +	u32 cmd;
> +	struct drm_ipvr_private *dev_priv = ved_priv->dev_priv;
> +
> +	IPVR_REG_WRITE32(ved_priv->base_addr0,
> MSVDX_RENDEC_BASE_ADDR0_OFFSET);
> +	IPVR_REG_WRITE32(ved_priv->base_addr1,
> MSVDX_RENDEC_BASE_ADDR1_OFFSET);
> +
> +	cmd = 0;
> +	REGIO_WRITE_FIELD(cmd, MSVDX_RENDEC_BUFFER_SIZE,
> +			RENDEC_BUFFER_SIZE0, RENDEC_A_SIZE / 4096);
> +	REGIO_WRITE_FIELD(cmd, MSVDX_RENDEC_BUFFER_SIZE,
> +			RENDEC_BUFFER_SIZE1, RENDEC_B_SIZE / 4096);
> +	IPVR_REG_WRITE32(cmd, MSVDX_RENDEC_BUFFER_SIZE_OFFSET);
> +
> +	cmd = 0;
> +	REGIO_WRITE_FIELD(cmd, MSVDX_RENDEC_CONTROL1,
> +			RENDEC_DECODE_START_SIZE, 0);
> +	REGIO_WRITE_FIELD(cmd, MSVDX_RENDEC_CONTROL1,
> +			RENDEC_BURST_SIZE_W, 1);
> +	REGIO_WRITE_FIELD(cmd, MSVDX_RENDEC_CONTROL1,
> +			RENDEC_BURST_SIZE_R, 1);
> +	REGIO_WRITE_FIELD(cmd, MSVDX_RENDEC_CONTROL1,
> +			RENDEC_EXTERNAL_MEMORY, 1);
> +	IPVR_REG_WRITE32(cmd, MSVDX_RENDEC_CONTROL1_OFFSET);
> +
> +	cmd = 0x00101010;
> +	IPVR_REG_WRITE32(cmd, MSVDX_RENDEC_CONTEXT0_OFFSET);
> +	IPVR_REG_WRITE32(cmd, MSVDX_RENDEC_CONTEXT1_OFFSET);
> +	IPVR_REG_WRITE32(cmd, MSVDX_RENDEC_CONTEXT2_OFFSET);
> +	IPVR_REG_WRITE32(cmd, MSVDX_RENDEC_CONTEXT3_OFFSET);
> +	IPVR_REG_WRITE32(cmd, MSVDX_RENDEC_CONTEXT4_OFFSET);
> +	IPVR_REG_WRITE32(cmd, MSVDX_RENDEC_CONTEXT5_OFFSET);
> +
> +	cmd = 0;
> +	REGIO_WRITE_FIELD(cmd, MSVDX_RENDEC_CONTROL0,
> RENDEC_INITIALISE, 1);
> +	IPVR_REG_WRITE32(cmd, MSVDX_RENDEC_CONTROL0_OFFSET);
> +}
> +
> +int ved_rendec_init_by_msg(struct ved_private *ved_priv)
> +{
> +	/* at this stage, FW is uplaoded successfully,
> +	 * can send RENDEC init message */
> +	struct fw_init_msg init_msg;
> +	init_msg.header.bits.msg_size = sizeof(struct fw_init_msg);
> +	init_msg.header.bits.msg_type = MTX_MSGID_INIT;
> +	init_msg.rendec_addr0 = ved_priv->base_addr0;
> +	init_msg.rendec_addr1 = ved_priv->base_addr1;
> +	init_msg.rendec_size.bits.rendec_size0 = RENDEC_A_SIZE / (4 *
> 1024);
> +	init_msg.rendec_size.bits.rendec_size1 = RENDEC_B_SIZE / (4 *
> 1024);
> +	return ved_mtx_send(ved_priv, (void *)&init_msg);
> +}
> +
> +static void ved_get_mtx_control_from_dash(struct ved_private *ved_priv)
> +{
> +	int count = 0;
> +	u32 reg_val = 0;
> +	struct drm_ipvr_private *dev_priv = ved_priv->dev_priv;
> +
> +	REGIO_WRITE_FIELD(reg_val, MSVDX_MTX_DEBUG,
> MTX_DBG_IS_SLAVE, 1);
> +	REGIO_WRITE_FIELD(reg_val, MSVDX_MTX_DEBUG,
> MTX_DBG_GPIO_IN, 0x02);
> +	IPVR_REG_WRITE32(reg_val, MSVDX_MTX_DEBUG_OFFSET);
> +
> +	do {
> +		reg_val = IPVR_REG_READ32(MSVDX_MTX_DEBUG_OFFSET);
> +		count++;
> +	} while (((reg_val & 0x18) != 0) && count < 50000);
> +
> +	if (count >= 50000)
> +		IPVR_DEBUG_VED("VED: timeout in
> get_mtx_control_from_dash.\n");
> +
> +	/* Save the access control register...*/
> +	ved_priv->ved_dash_access_ctrl =
> IPVR_REG_READ32(MTX_RAM_ACCESS_CONTROL_OFFSET);
> +}
> +
> +static void
> +ved_release_mtx_control_from_dash(struct ved_private *ved_priv)
> +{
> +	struct drm_ipvr_private *dev_priv = ved_priv->dev_priv;
> +	/* restore access control */
> +	IPVR_REG_WRITE32(ved_priv->ved_dash_access_ctrl,
> MTX_RAM_ACCESS_CONTROL_OFFSET);
> +	/* release bus */
> +	IPVR_REG_WRITE32(0x4, MSVDX_MTX_DEBUG_OFFSET);
> +}
> +
> +/* for future debug info of msvdx related registers */
> +static void
> +ved_setup_fw_dump(struct ved_private *ved_priv, u32 dma_channel)
> +{
> +	struct drm_ipvr_private *dev_priv = ved_priv->dev_priv;
> +	IPVR_DEBUG_REG("dump registers during fw upload for debug:\n");
> +	/* for DMAC REGISTER */
> +	IPVR_DEBUG_REG("MTX_SYSC_CDMAA is 0x%x\n",
> +			IPVR_REG_READ32(MTX_SYSC_CDMAA_OFFSET));
> +	IPVR_DEBUG_REG("MTX_SYSC_CDMAC value is 0x%x\n",
> +			IPVR_REG_READ32(MTX_SYSC_CDMAC_OFFSET));
> +	IPVR_DEBUG_REG("DMAC_SETUP value is 0x%x\n",
> +			IPVR_REG_READ32(DMAC_DMAC_SETUP_OFFSET +
> dma_channel));
> +	IPVR_DEBUG_REG("DMAC_DMAC_COUNT value is 0x%x\n",
> +			IPVR_REG_READ32(DMAC_DMAC_COUNT_OFFSET +
> dma_channel));
> +	IPVR_DEBUG_REG("DMAC_DMAC_PERIPH_OFFSET value is 0x%x\n",
> +			IPVR_REG_READ32(DMAC_DMAC_PERIPH_OFFSET +
> dma_channel));
> +	IPVR_DEBUG_REG("DMAC_DMAC_PERIPHERAL_ADDR value is
> 0x%x\n",
> +
> 	IPVR_REG_READ32(DMAC_DMAC_PERIPHERAL_ADDR_OFFSET +
> +				       dma_channel));
> +	IPVR_DEBUG_REG("MSVDX_CONTROL value is 0x%x\n",
> +			IPVR_REG_READ32(MSVDX_CONTROL_OFFSET));
> +	IPVR_DEBUG_REG("DMAC_DMAC_IRQ_STAT value is 0x%x\n",
> +
> 	IPVR_REG_READ32(DMAC_DMAC_IRQ_STAT_OFFSET));
> +	IPVR_DEBUG_REG("MSVDX_MMU_CONTROL0 value is 0x%x\n",
> +
> 	IPVR_REG_READ32(MSVDX_MMU_CONTROL0_OFFSET));
> +	IPVR_DEBUG_REG("DMAC_DMAC_COUNT 2222 value is 0x%x\n",
> +			IPVR_REG_READ32(DMAC_DMAC_COUNT_OFFSET +
> dma_channel));
> +
> +	/* for MTX REGISTER */
> +	IPVR_DEBUG_REG("MTX_ENABLE_OFFSET is 0x%x\n",
> +			IPVR_REG_READ32(MTX_ENABLE_OFFSET));
> +	IPVR_DEBUG_REG("MTX_KICK_INPUT_OFFSET value is 0x%x\n",
> +			IPVR_REG_READ32(MTX_KICK_INPUT_OFFSET));
> +	IPVR_DEBUG_REG("MTX_REG_READ_WRITE_REQUEST_OFFSET
> value is 0x%x\n",
> +
> 	IPVR_REG_READ32(MTX_REGISTER_READ_WRITE_REQUEST_OFFSET
> ));
> +	IPVR_DEBUG_REG("MTX_RAM_ACCESS_CONTROL_OFFSET value is
> 0x%x\n",
> +
> 	IPVR_REG_READ32(MTX_RAM_ACCESS_CONTROL_OFFSET));
> +	IPVR_DEBUG_REG("MTX_RAM_ACCESS_STATUS_OFFSET value is
> 0x%x\n",
> +
> 	IPVR_REG_READ32(MTX_RAM_ACCESS_STATUS_OFFSET));
> +	IPVR_DEBUG_REG("MTX_SYSC_TIMERDIV_OFFSET value is 0x%x\n",
> +			IPVR_REG_READ32(MTX_SYSC_TIMERDIV_OFFSET));
> +	IPVR_DEBUG_REG("MTX_SYSC_CDMAC_OFFSET value is 0x%x\n",
> +			IPVR_REG_READ32(MTX_SYSC_CDMAC_OFFSET));
> +	IPVR_DEBUG_REG("MTX_SYSC_CDMAA_OFFSET value is 0x%x\n",
> +			IPVR_REG_READ32(MTX_SYSC_CDMAA_OFFSET));
> +	IPVR_DEBUG_REG("MTX_SYSC_CDMAS0_OFFSET value is 0x%x\n",
> +			IPVR_REG_READ32(MTX_SYSC_CDMAS0_OFFSET));
> +	IPVR_DEBUG_REG("MTX_SYSC_CDMAT_OFFSET value is 0x%x\n",
> +			IPVR_REG_READ32(MTX_SYSC_CDMAT_OFFSET));
> +
> +	/* for MSVDX CORE REGISTER */
> +	IPVR_DEBUG_REG("MSVDX_CONTROL_OFFSET is 0x%x\n",
> +			IPVR_REG_READ32(MSVDX_CONTROL_OFFSET));
> +	IPVR_DEBUG_REG("MSVDX_INTERRUPT_CLEAR_OFFSET value is
> 0x%x\n",
> +
> 	IPVR_REG_READ32(MSVDX_INTERRUPT_CLEAR_OFFSET));
> +	IPVR_DEBUG_REG("MSVDX_INTERRUPT_STATUS_OFFSET value is
> 0x%x\n",
> +
> 	IPVR_REG_READ32(MSVDX_INTERRUPT_STATUS_OFFSET));
> +	IPVR_DEBUG_REG("MMSVDX_HOST_INTERRUPT_ENABLE_OFFSET
> value is 0x%x\n",
> +
> 	IPVR_REG_READ32(MSVDX_HOST_INTERRUPT_ENABLE_OFFSET));
> +	IPVR_DEBUG_REG("MSVDX_MAN_CLK_ENABLE_OFFSET value is
> 0x%x\n",
> +
> 	IPVR_REG_READ32(MSVDX_MAN_CLK_ENABLE_OFFSET));
> +	IPVR_DEBUG_REG("MSVDX_CORE_ID_OFFSET value is 0x%x\n",
> +			IPVR_REG_READ32(MSVDX_CORE_ID_OFFSET));
> +	IPVR_DEBUG_REG("MSVDX_MMU_STATUS_OFFSET value is
> 0x%x\n",
> +
> 	IPVR_REG_READ32(MSVDX_MMU_STATUS_OFFSET));
> +	IPVR_DEBUG_REG("FE_MSVDX_WDT_CONTROL_OFFSET value is
> 0x%x\n",
> +
> 	IPVR_REG_READ32(FE_MSVDX_WDT_CONTROL_OFFSET));
> +	IPVR_DEBUG_REG("FE_MSVDX_WDTIMER_OFFSET value is 0x%x\n",
> +			IPVR_REG_READ32(FE_MSVDX_WDTIMER_OFFSET));
> +	IPVR_DEBUG_REG("BE_MSVDX_WDT_CONTROL_OFFSET value is
> 0x%x\n",
> +
> 	IPVR_REG_READ32(BE_MSVDX_WDT_CONTROL_OFFSET));
> +	IPVR_DEBUG_REG("BE_MSVDX_WDTIMER_OFFSET value is 0x%x\n",
> +			IPVR_REG_READ32(BE_MSVDX_WDTIMER_OFFSET));
> +
> +	/* for MSVDX RENDEC REGISTER */
> +	IPVR_DEBUG_REG("VEC_SHIFTREG_CONTROL_OFFSET is 0x%x\n",
> +
> 	IPVR_REG_READ32(VEC_SHIFTREG_CONTROL_OFFSET));
> +	IPVR_DEBUG_REG("MSVDX_RENDEC_CONTROL0_OFFSET value is
> 0x%x\n",
> +
> 	IPVR_REG_READ32(MSVDX_RENDEC_CONTROL0_OFFSET));
> +	IPVR_DEBUG_REG("MSVDX_RENDEC_BUFFER_SIZE_OFFSET value is
> 0x%x\n",
> +
> 	IPVR_REG_READ32(MSVDX_RENDEC_BUFFER_SIZE_OFFSET));
> +	IPVR_DEBUG_REG("MSVDX_RENDEC_BASE_ADDR0_OFFSET value is
> 0x%x\n",
> +
> 	IPVR_REG_READ32(MSVDX_RENDEC_BASE_ADDR0_OFFSET));
> +	IPVR_DEBUG_REG("MMSVDX_RENDEC_BASE_ADDR1_OFFSET value
> is 0x%x\n",
> +
> 	IPVR_REG_READ32(MSVDX_RENDEC_BASE_ADDR1_OFFSET));
> +	IPVR_DEBUG_REG("MSVDX_RENDEC_READ_DATA_OFFSET value is
> 0x%x\n",
> +
> 	IPVR_REG_READ32(MSVDX_RENDEC_READ_DATA_OFFSET));
> +	IPVR_DEBUG_REG("MSVDX_RENDEC_CONTEXT0_OFFSET value is
> 0x%x\n",
> +
> 	IPVR_REG_READ32(MSVDX_RENDEC_CONTEXT0_OFFSET));
> +	IPVR_DEBUG_REG("MSVDX_RENDEC_CONTEXT1_OFFSET value is
> 0x%x\n",
> +
> 	IPVR_REG_READ32(MSVDX_RENDEC_CONTEXT1_OFFSET));
> +	IPVR_DEBUG_REG("MSVDX_CMDS_END_SLICE_PICTURE_OFFSET
> value is 0x%x\n",
> +
> 	IPVR_REG_READ32(MSVDX_CMDS_END_SLICE_PICTURE_OFFSET));
> +
> +	IPVR_DEBUG_REG("MSVDX_MMU_MEM_REQ value is 0x%x\n",
> +
> 	IPVR_REG_READ32(MSVDX_MMU_MEM_REQ_OFFSET));
> +	IPVR_DEBUG_REG("MSVDX_SYS_MEMORY_DEBUG2 value is
> 0x%x\n",
> +			IPVR_REG_READ32(0x6fc));
> +}
> +
> +static void ved_upload_fw(struct ved_private *ved_priv,
> +				u32 address, const u32 words)
> +{
> +	u32 reg_val = 0;
> +	u32 cmd;
> +	u32 uCountReg, offset, mmu_ptd;
> +	u32 size = words * 4; /* byte count */
> +	u32 dma_channel = 0; /* Setup a Simple DMA for Ch0 */
> +	struct drm_ipvr_private *dev_priv = ved_priv->dev_priv;
> +
> +	IPVR_DEBUG_VED("VED: Upload firmware by DMA.\n");
> +	ved_get_mtx_control_from_dash(ved_priv);
> +
> +	/*
> +	 * dma transfers to/from the mtx have to be 32-bit aligned and
> +	 * in multiples of 32 bits
> +	 */
> +	IPVR_REG_WRITE32(address, MTX_SYSC_CDMAA_OFFSET);
> +
> +	/* burst size in multiples of 64 bits (allowed values are 2 or 4) */
> +	REGIO_WRITE_FIELD_LITE(reg_val, MTX_SYSC_CDMAC, BURSTSIZE,
> 4);
> +	/* false means write to mtx mem, true means read from mtx mem
> */
> +	REGIO_WRITE_FIELD_LITE(reg_val, MTX_SYSC_CDMAC, RNW, 0);
> +	/* begin transfer */
> +	REGIO_WRITE_FIELD_LITE(reg_val, MTX_SYSC_CDMAC, ENABLE,
> 	1);
> +	/* specifies transfer size of the DMA operation by 32-bit words */
> +	REGIO_WRITE_FIELD_LITE(reg_val, MTX_SYSC_CDMAC, LENGTH,
> 	words);
> +	IPVR_REG_WRITE32(reg_val, MTX_SYSC_CDMAC_OFFSET);
> +
> +	/* toggle channel 0 usage between mtx and other msvdx peripherals
> */
> +	{
> +		reg_val = IPVR_REG_READ32(MSVDX_CONTROL_OFFSET);
> +		REGIO_WRITE_FIELD(reg_val, MSVDX_CONTROL,
> DMAC_CH0_SELECT,  0);
> +		IPVR_REG_WRITE32(reg_val, MSVDX_CONTROL_OFFSET);
> +	}
> +
> +	/* Clear the DMAC Stats */
> +	IPVR_REG_WRITE32(0 , DMAC_DMAC_IRQ_STAT_OFFSET +
> dma_channel);
> +
> +	offset = ved_priv->fw_offset;
> +	IPVR_DEBUG_VED("fw mmu offset is 0x%x.\n", offset);
> +
> +	/* use bank 0 */
> +	cmd = 0;
> +	IPVR_REG_WRITE32(cmd, MSVDX_MMU_BANK_INDEX_OFFSET);
> +
> +	/* Write PTD to mmu base 0*/
> +	mmu_ptd = ipvr_get_default_pd_addr32(ved_priv->dev_priv-
> >mmu);
> +	BUG_ON(mmu_ptd == 0);
> +	IPVR_REG_WRITE32(mmu_ptd,
> MSVDX_MMU_DIR_LIST_BASE_OFFSET + 0);
> +	IPVR_DEBUG_VED("mmu_ptd is %d.\n", mmu_ptd);
> +
> +	/* Invalidate */
> +	reg_val = IPVR_REG_READ32(MSVDX_MMU_CONTROL0_OFFSET);
> +	reg_val &= ~0xf;
> +	REGIO_WRITE_FIELD(reg_val, MSVDX_MMU_CONTROL0,
> MMU_INVALDC, 1);
> +	IPVR_REG_WRITE32(reg_val, MSVDX_MMU_CONTROL0_OFFSET);
> +
> +	IPVR_REG_WRITE32(offset, DMAC_DMAC_SETUP_OFFSET +
> dma_channel);
> +
> +	/* Only use a single dma - assert that this is valid */
> +	if ((size >> 2) >= (1 << 15)) {
> +		IPVR_ERROR("DMA size beyond limit, abort firmware
> upload.\n");
> +		return;
> +	}
> +
> +	uCountReg =
> IPVR_DMAC_VALUE_COUNT(IPVR_DMAC_BSWAP_NO_SWAP, 0,
> +					 IPVR_DMAC_DIR_MEM_TO_PERIPH,
> 0, (size >> 2));
> +	/* Set the number of bytes to dma*/
> +	IPVR_REG_WRITE32(uCountReg, DMAC_DMAC_COUNT_OFFSET +
> dma_channel);
> +
> +	cmd =
> IPVR_DMAC_VALUE_PERIPH_PARAM(IPVR_DMAC_ACC_DEL_0,
> +					  IPVR_DMAC_INCR_OFF,
> +					  IPVR_DMAC_BURST_2);
> +	IPVR_REG_WRITE32(cmd, DMAC_DMAC_PERIPH_OFFSET +
> dma_channel);
> +
> +	/* Set destination port for dma */
> +	cmd = 0;
> +	REGIO_WRITE_FIELD(cmd, DMAC_DMAC_PERIPHERAL_ADDR, ADDR,
> +			  MTX_SYSC_CDMAT_OFFSET);
> +	IPVR_REG_WRITE32(cmd,
> DMAC_DMAC_PERIPHERAL_ADDR_OFFSET + dma_channel);
> +
> +
> +	/* Finally, rewrite the count register with the enable bit set */
> +	IPVR_REG_WRITE32(uCountReg | DMAC_DMAC_COUNT_EN_MASK,
> +			DMAC_DMAC_COUNT_OFFSET + dma_channel);
> +
> +	/* Wait for all to be done */
> +	if (ved_wait_for_register(ved_priv,
> +				  DMAC_DMAC_IRQ_STAT_OFFSET +
> dma_channel,
> +
> DMAC_DMAC_IRQ_STAT_TRANSFER_FIN_MASK,
> +
> DMAC_DMAC_IRQ_STAT_TRANSFER_FIN_MASK,
> +				  2000000, 5)) {
> +		ved_setup_fw_dump(ved_priv, dma_channel);
> +		ved_release_mtx_control_from_dash(ved_priv);
> +		return;
> +	}
> +
> +	/* Assert that the MTX DMA port is all done aswell */
> +	if (ved_wait_for_register(ved_priv,
> +			MTX_SYSC_CDMAS0_OFFSET,
> +			1, 1, 2000000, 5)) {
> +		ved_release_mtx_control_from_dash(ved_priv);
> +		return;
> +	}
> +
> +	ved_release_mtx_control_from_dash(ved_priv);
> +
> +	IPVR_DEBUG_VED("VED: Upload done\n");
> +}
> +
> +static int ved_get_fw_bo(struct ved_private *ved_priv,
> +				   const struct firmware **raw, char *name)
> +{
> +	int rc = 0;
> +	size_t fw_size;
> +	void *ptr = NULL;
> +	void *fw_bo_addr = NULL;
> +	u32 *last_word;
> +	struct ved_fw *fw;
> +
> +	rc = request_firmware(raw, name, &ved_priv->dev_priv->dev-
> >platformdev->dev);
> +	if (rc)
> +		return rc;
> +
> +	if (!*raw) {
> +		rc = -ENOMEM;
> +		IPVR_ERROR("VED: %s request_firmware failed:
> Reason %d.\n", name, rc);
> +		goto out;
> +	}
> +
> +	if ((*raw)->size < sizeof(struct ved_fw)) {
> +		rc = -ENOMEM;
> +		IPVR_ERROR("VED: %s is is not correct size(%zd).\n", name,
> (*raw)->size);
> +		goto out;
> +	}
> +
> +	ptr = (void *)((*raw))->data;
> +	if (!ptr) {
> +		rc = -ENOMEM;
> +		IPVR_ERROR("VED: Failed to load %s.\n", name);
> +		goto out;
> +	}
> +
> +	/* another sanity check... */
> +	fw_size = sizeof(struct ved_fw) +
> +		  sizeof(u32) * ((struct ved_fw *) ptr)->text_size +
> +		  sizeof(u32) * ((struct ved_fw *) ptr)->data_size;
> +	if ((*raw)->size < fw_size) {
> +		rc = -ENOMEM;
> +		IPVR_ERROR("VED: %s is is not correct size(%zd).\n",
> +			  name, (*raw)->size);
> +		goto out;
> +	}
> +
> +	fw_bo_addr = ipvr_gem_object_vmap(ved_priv->fw_bo);
> +	if (!fw_bo_addr) {
> +		rc = -ENOMEM;
> +		IPVR_ERROR("VED: kmap failed for fw buffer.\n");
> +		goto out;
> +	}
> +
> +	fw = (struct ved_fw *)ptr;
> +	memset(fw_bo_addr, UNINITILISE_MEM, ved_priv-
> >mtx_mem_size);
> +	memcpy(fw_bo_addr, ptr + sizeof(struct ved_fw),
> +	       sizeof(u32) * fw->text_size);
> +	memcpy(fw_bo_addr + (fw->data_location -
> MSVDX_MTX_DATA_LOCATION),
> +	       (void *)ptr + sizeof(struct ved_fw) + sizeof(u32) * fw->text_size,
> +	       sizeof(u32) * fw->data_size);
> +	last_word = (u32 *)(fw_bo_addr + ved_priv->mtx_mem_size - 4);
> +	/*
> +	 * Write a know value to last word in mtx memory
> +	 * Usefull for detection of stack overrun
> +	 */
> +	*last_word = STACKGUARDWORD;
> +
> +	vunmap(fw_bo_addr);
> +	IPVR_DEBUG_VED("VED: releasing firmware resouces.\n");
> +	IPVR_DEBUG_VED("VED: Load firmware into BO successfully.\n");
> +out:
> +	release_firmware(*raw);
> +	return rc;
> +}
> +
> +static u32 *
> +ved_get_fw(struct ved_private *ved_priv, const struct firmware **raw,
> char *name)
> +{
> +	int rc = 0;
> +	size_t fw_size;
> +	void *ptr = NULL;
> +	struct ved_fw *fw;
> +	ved_priv->ved_fw_ptr = NULL;
> +
> +	rc = request_firmware(raw, name, &ved_priv->dev_priv->dev-
> >platformdev->dev);
> +	if (rc)
> +		return NULL;
> +
> +	if (!*raw) {
> +		IPVR_ERROR("VED: %s request_firmware failed:
> Reason %d\n",
> +			  name, rc);
> +		goto out;
> +	}
> +
> +	if ((*raw)->size < sizeof(struct ved_fw)) {
> +		IPVR_ERROR("VED: %s is is not correct size(%zd)\n",
> +			  name, (*raw)->size);
> +		goto out;
> +	}
> +
> +	ptr = (int *)((*raw))->data;
> +	if (!ptr) {
> +		IPVR_ERROR("VED: Failed to load %s.\n", name);
> +		goto out;
> +	}
> +	fw = (struct ved_fw *)ptr;
> +
> +	/* another sanity check... */
> +	fw_size = sizeof(fw) +
> +		  sizeof(u32) * fw->text_size +
> +		  sizeof(u32) * fw->data_size;
> +	if ((*raw)->size < fw_size) {
> +		IPVR_ERROR("VED: %s is is not correct size(%zd).\n",
> +			   name, (*raw)->size);
> +		goto out;
> +	}
> +
> +	ved_priv->ved_fw_ptr = kzalloc(fw_size, GFP_KERNEL);
> +	if (!ved_priv->ved_fw_ptr)
> +		IPVR_ERROR("VED: allocate FW buffer failed.\n");
> +	else {
> +		memcpy(ved_priv->ved_fw_ptr, ptr, fw_size);
> +		ved_priv->ved_fw_size = fw_size;
> +	}
> +
> +out:
> +	IPVR_DEBUG_VED("VED: releasing firmware resouces.\n");
> +	release_firmware(*raw);
> +	return ved_priv->ved_fw_ptr;
> +}
> +
> +static void
> +ved_write_mtx_core_reg(struct ved_private *ved_priv,
> +			       const u32 core_reg, const u32 val)
> +{
> +	u32 reg = 0;
> +	struct drm_ipvr_private *dev_priv = ved_priv->dev_priv;
> +
> +	/* Put data in MTX_RW_DATA */
> +	IPVR_REG_WRITE32(val,
> MTX_REGISTER_READ_WRITE_DATA_OFFSET);
> +
> +	/* DREADY is set to 0 and request a write */
> +	reg = core_reg;
> +	REGIO_WRITE_FIELD_LITE(reg,
> MTX_REGISTER_READ_WRITE_REQUEST,
> +			       MTX_RNW, 0);
> +	REGIO_WRITE_FIELD_LITE(reg,
> MTX_REGISTER_READ_WRITE_REQUEST,
> +			       MTX_DREADY, 0);
> +	IPVR_REG_WRITE32(reg,
> MTX_REGISTER_READ_WRITE_REQUEST_OFFSET);
> +
> +	ved_wait_for_register(ved_priv,
> +			      MTX_REGISTER_READ_WRITE_REQUEST_OFFSET,
> +
> MTX_REGISTER_READ_WRITE_REQUEST_MTX_DREADY_MASK,
> +
> MTX_REGISTER_READ_WRITE_REQUEST_MTX_DREADY_MASK,
> +			      2000000, 5);
> +}
> +
> +int ved_alloc_fw_bo(struct ved_private *ved_priv)
> +{
> +	u32 core_rev;
> +	int ret;
> +	struct drm_ipvr_private *dev_priv = ved_priv->dev_priv;
> +
> +	core_rev = IPVR_REG_READ32(MSVDX_CORE_REV_OFFSET);
> +
> +	if ((core_rev & 0xffffff) < 0x020000)
> +		ved_priv->mtx_mem_size = 16 * 1024;
> +	else
> +		ved_priv->mtx_mem_size = 56 * 1024;
> +
> +	IPVR_DEBUG_INIT("VED: MTX mem size is 0x%08x bytes,"
> +			"allocate firmware BO size 0x%08x.\n",
> +			ved_priv->mtx_mem_size,
> +			ved_priv->mtx_mem_size + 4096);
> +
> +	/* Allocate the new object */
> +	ved_priv->fw_bo = ipvr_gem_create(ved_priv->dev_priv,
> +						ved_priv->mtx_mem_size +
> 4096, 0, 0);
> +	if (IS_ERR(ved_priv->fw_bo)) {
> +		IPVR_ERROR("VED: failed to allocate fw buffer: %ld.\n",
> +			PTR_ERR(ved_priv->fw_bo));
> +		ved_priv->fw_bo = NULL;
> +		return -ENOMEM;
> +	}
> +	ved_priv->fw_offset = ipvr_gem_object_mmu_offset(ved_priv-
> >fw_bo);
> +	if (IPVR_IS_ERR(ved_priv->fw_offset)) {
> +		ved_priv->fw_bo = NULL;
> +		goto err_free_fw_bo;
> +	}
> +	return 0;
> +err_free_fw_bo:
> +	drm_gem_object_unreference_unlocked(&ved_priv->fw_bo-
> >base);
> +	return ret;
> +}
> +
> +int ved_setup_fw(struct ved_private *ved_priv)
> +{
> +	u32 ram_bank_size;
> +	struct drm_ipvr_private *dev_priv = ved_priv->dev_priv;
> +	int ret = 0;
> +	struct ved_fw *fw;
> +	u32 *fw_ptr = NULL;
> +	u32 *text_ptr = NULL;
> +	u32 *data_ptr = NULL;
> +	const struct firmware *raw = NULL;
> +
> +	/* todo : Assert the clock is on - if not turn it on to upload code */
> +	IPVR_DEBUG_VED("VED: ved_setup_fw.\n");
> +
> +	ved_set_clocks(ved_priv, clk_enable_all);
> +
> +	/* Reset MTX */
> +	IPVR_REG_WRITE32(MTX_SOFT_RESET_MTX_RESET_MASK,
> +			MTX_SOFT_RESET_OFFSET);
> +
> +	IPVR_REG_WRITE32(FIRMWAREID,
> MSVDX_COMMS_FIRMWARE_ID);
> +
> +	IPVR_REG_WRITE32(0, MSVDX_COMMS_ERROR_TRIG);
> +	IPVR_REG_WRITE32(199, MTX_SYSC_TIMERDIV_OFFSET); /*
> MTX_SYSC_TIMERDIV */
> +	IPVR_REG_WRITE32(0, MSVDX_EXT_FW_ERROR_STATE); /*
> EXT_FW_ERROR_STATE */
> +	IPVR_REG_WRITE32(0, MSVDX_COMMS_MSG_COUNTER);
> +	IPVR_REG_WRITE32(0, MSVDX_COMMS_SIGNATURE);
> +	IPVR_REG_WRITE32(0, MSVDX_COMMS_TO_HOST_RD_INDEX);
> +	IPVR_REG_WRITE32(0, MSVDX_COMMS_TO_HOST_WRT_INDEX);
> +	IPVR_REG_WRITE32(0, MSVDX_COMMS_TO_MTX_RD_INDEX);
> +	IPVR_REG_WRITE32(0, MSVDX_COMMS_TO_MTX_WRT_INDEX);
> +	IPVR_REG_WRITE32(0, MSVDX_COMMS_FW_STATUS);
> +	IPVR_REG_WRITE32(DSIABLE_IDLE_GPIO_SIG |
> +			DSIABLE_Auto_CLOCK_GATING |
> +			RETURN_VDEB_DATA_IN_COMPLETION |
> +			NOT_ENABLE_ON_HOST_CONCEALMENT,
> +			MSVDX_COMMS_OFFSET_FLAGS);
> +	IPVR_REG_WRITE32(0, MSVDX_COMMS_SIGNATURE);
> +
> +	/* read register bank size */
> +	{
> +		u32 bank_size, reg;
> +		reg =
> IPVR_REG_READ32(MSVDX_MTX_RAM_BANK_OFFSET);
> +		bank_size =
> +			REGIO_READ_FIELD(reg, MSVDX_MTX_RAM_BANK,
> +					 MTX_RAM_BANK_SIZE);
> +		ram_bank_size = (u32)(1 << (bank_size + 2));
> +	}
> +
> +	IPVR_DEBUG_VED("VED: RAM bank size = %d bytes\n",
> ram_bank_size);
> +
> +	/* if FW already loaded from storage */
> +	if (ved_priv->ved_fw_ptr) {
> +		fw_ptr = ved_priv->ved_fw_ptr;
> +	} else {
> +		fw_ptr = ved_get_fw(ved_priv, &raw, FIRMWARE_NAME);
> +		IPVR_DEBUG_VED("VED:load msvdx_fw_mfld_DE2.0.bin by
> udevd\n");
> +	}
> +	if (!fw_ptr) {
> +		IPVR_ERROR("VED:load ved_fw.bin failed,is udevd
> running?\n");
> +		ret = 1;
> +		goto out;
> +	}
> +
> +	if (!ved_priv->fw_loaded_to_bo) { /* Load firmware into BO */
> +		IPVR_DEBUG_VED("MSVDX:load ved_fw.bin by udevd into
> BO\n");
> +		ret = ved_get_fw_bo(ved_priv, &raw, FIRMWARE_NAME);
> +		if (ret) {
> +			IPVR_ERROR("VED: failed to call
> ved_get_fw_bo: %d.\n", ret);
> +			goto out;
> +		}
> +		ved_priv->fw_loaded_to_bo = true;
> +	}
> +
> +	fw = (struct ved_fw *) fw_ptr;
> +
> +	/* need check fw->ver? */
> +	text_ptr = (u32 *)((u8 *) fw_ptr + sizeof(struct ved_fw));
> +	data_ptr = text_ptr + fw->text_size;
> +
> +	/* maybe we can judge fw version according to fw text size */
> +
> +	IPVR_DEBUG_VED("VED: Retrieved pointers for firmware\n");
> +	IPVR_DEBUG_VED("VED: text_size: %d\n", fw->text_size);
> +	IPVR_DEBUG_VED("VED: data_size: %d\n", fw->data_size);
> +	IPVR_DEBUG_VED("VED: data_location: 0x%x\n", fw-
> >data_location);
> +	IPVR_DEBUG_VED("VED: First 4 bytes of text: 0x%x\n", *text_ptr);
> +	IPVR_DEBUG_VED("VED: First 4 bytes of data: 0x%x\n", *data_ptr);
> +	IPVR_DEBUG_VED("VED: Uploading firmware\n");
> +
> +	ved_upload_fw(ved_priv, 0, ved_priv->mtx_mem_size / 4);
> +
> +	/*	-- Set starting PC address	*/
> +	ved_write_mtx_core_reg(ved_priv, MTX_PC, PC_START_ADDRESS);
> +
> +	/*	-- Turn on the thread	*/
> +	IPVR_REG_WRITE32(MTX_ENABLE_MTX_ENABLE_MASK,
> MTX_ENABLE_OFFSET);
> +
> +	/* Wait for the signature value to be written back */
> +	ret = ved_wait_for_register(ved_priv, MSVDX_COMMS_SIGNATURE,
> +				    MSVDX_COMMS_SIGNATURE_VALUE,
> +				    0xffffffff, /* Enabled bits */
> +				    2000000, 5);
> +	if (ret) {
> +		IPVR_ERROR("VED: firmware fails to initialize.\n");
> +		goto out;
> +	}
> +
> +	IPVR_DEBUG_VED("VED: MTX Initial indications OK.\n");
> +	IPVR_DEBUG_VED("VED: MSVDX_COMMS_AREA_ADDR = %08x.\n",
> +		       MSVDX_COMMS_AREA_ADDR);
> +out:
> +	/* no need to put fw bo, we will do it at driver unload */
> +	return ret;
> +}
> +
> +
> +/* This value is hardcoded in FW */
> +#define WDT_CLOCK_DIVIDER 128
> +int ved_post_boot_init(struct ved_private *ved_priv)
> +{
> +	u32 device_node_flags =
> +			DSIABLE_IDLE_GPIO_SIG |
> DSIABLE_Auto_CLOCK_GATING |
> +			RETURN_VDEB_DATA_IN_COMPLETION |
> +			NOT_ENABLE_ON_HOST_CONCEALMENT;
> +	int reg_val = 0;
> +
> +	/* DDK set fe_wdt_clks as 0x820 and be_wdt_clks as 0x8200 */
> +	u32 fe_wdt_clks = 0x334 * WDT_CLOCK_DIVIDER;
> +	u32 be_wdt_clks = 0x2008 * WDT_CLOCK_DIVIDER;
> +	struct drm_ipvr_private *dev_priv = ved_priv->dev_priv;
> +
> +	IPVR_REG_WRITE32(FIRMWAREID,
> MSVDX_COMMS_FIRMWARE_ID);
> +	IPVR_REG_WRITE32(device_node_flags,
> MSVDX_COMMS_OFFSET_FLAGS);
> +
> +	/* read register bank size */
> +	{
> +		u32 ram_bank_size;
> +		u32 bank_size, reg;
> +		reg =
> IPVR_REG_READ32(MSVDX_MTX_RAM_BANK_OFFSET);
> +		bank_size =
> +			REGIO_READ_FIELD(reg, MSVDX_MTX_RAM_BANK,
> +					 MTX_RAM_BANK_SIZE);
> +		ram_bank_size = (u32)(1 << (bank_size + 2));
> +		IPVR_DEBUG_INIT("VED: RAM bank size = %d bytes\n",
> +				ram_bank_size);
> +	}
> +	/* host end */
> +
> +	/* DDK setup tiling region here */
> +	/* DDK set MMU_CONTROL2 register */
> +
> +	/* set watchdog timer here */
> +	REGIO_WRITE_FIELD(reg_val, FE_MSVDX_WDT_CONTROL,
> +			  FE_WDT_CNT_CTRL, 0x3);
> +	REGIO_WRITE_FIELD(reg_val, FE_MSVDX_WDT_CONTROL,
> +			  FE_WDT_ENABLE, 0);
> +	REGIO_WRITE_FIELD(reg_val, FE_MSVDX_WDT_CONTROL,
> +			  FE_WDT_ACTION0, 1);
> +	REGIO_WRITE_FIELD(reg_val, FE_MSVDX_WDT_CONTROL,
> +			  FE_WDT_CLEAR_SELECT, 1);
> +	REGIO_WRITE_FIELD(reg_val, FE_MSVDX_WDT_CONTROL,
> +			  FE_WDT_CLKDIV_SELECT, 7);
> +	IPVR_REG_WRITE32(fe_wdt_clks / WDT_CLOCK_DIVIDER,
> +			FE_MSVDX_WDT_COMPAREMATCH_OFFSET);
> +	IPVR_REG_WRITE32(reg_val, FE_MSVDX_WDT_CONTROL_OFFSET);
> +
> +	reg_val = 0;
> +	/* DDK set BE_WDT_CNT_CTRL as 0x5 and BE_WDT_CLEAR_SELECT
> as 0x1 */
> +	REGIO_WRITE_FIELD(reg_val, BE_MSVDX_WDT_CONTROL,
> +			  BE_WDT_CNT_CTRL, 0x7);
> +	REGIO_WRITE_FIELD(reg_val, BE_MSVDX_WDT_CONTROL,
> +			  BE_WDT_ENABLE, 0);
> +	REGIO_WRITE_FIELD(reg_val, BE_MSVDX_WDT_CONTROL,
> +			  BE_WDT_ACTION0, 1);
> +	REGIO_WRITE_FIELD(reg_val, BE_MSVDX_WDT_CONTROL,
> +			  BE_WDT_CLEAR_SELECT, 0xd);
> +	REGIO_WRITE_FIELD(reg_val, BE_MSVDX_WDT_CONTROL,
> +			  BE_WDT_CLKDIV_SELECT, 7);
> +
> +	IPVR_REG_WRITE32(be_wdt_clks / WDT_CLOCK_DIVIDER,
> +			BE_MSVDX_WDT_COMPAREMATCH_OFFSET);
> +	IPVR_REG_WRITE32(reg_val, BE_MSVDX_WDT_CONTROL_OFFSET);
> +
> +	return ved_rendec_init_by_msg(ved_priv);
> +}
> +
> +int ved_post_init(struct ved_private *ved_priv)
> +{
> +	u32 cmd;
> +	int ret;
> +	struct drm_ipvr_private *dev_priv;
> +
> +	if (!ved_priv)
> +		return -EINVAL;
> +
> +	ved_priv->ved_busy = false;
> +	dev_priv = ved_priv->dev_priv;
> +
> +	/* Enable MMU by removing all bypass bits */
> +	IPVR_REG_WRITE32(0, MSVDX_MMU_CONTROL0_OFFSET);
> +
> +	ved_rendec_init_by_reg(ved_priv);
> +	if (!ved_priv->fw_bo) {
> +		ret = ved_alloc_fw_bo(ved_priv);
> +		if (ret) {
> +			IPVR_ERROR("VED: ved_alloc_fw_bo failed: %d.\n",
> ret);
> +			return ret;
> +		}
> +	}
> +	/* move fw loading to the place receiving first cmd buffer */
> +	ved_priv->ved_fw_loaded = false; /* need to load firware */
> +	/* it should be set at punit post boot init phase */
> +	IPVR_REG_WRITE32(820,
> FE_MSVDX_WDT_COMPAREMATCH_OFFSET);
> +	IPVR_REG_WRITE32(8200,
> BE_MSVDX_WDT_COMPAREMATCH_OFFSET);
> +
> +	IPVR_REG_WRITE32(820,
> FE_MSVDX_WDT_COMPAREMATCH_OFFSET);
> +	IPVR_REG_WRITE32(8200,
> BE_MSVDX_WDT_COMPAREMATCH_OFFSET);
> +
> +	ved_clear_irq(ved_priv);
> +	ved_enable_irq(ved_priv);
> +
> +	cmd = 0;
> +	cmd = IPVR_REG_READ32(VEC_SHIFTREG_CONTROL_OFFSET);
> +	REGIO_WRITE_FIELD(cmd, VEC_SHIFTREG_CONTROL,
> +	  SR_MASTER_SELECT, 1);  /* Host */
> +	IPVR_REG_WRITE32(cmd, VEC_SHIFTREG_CONTROL_OFFSET);
> +
> +	return 0;
> +}
> +
> +int __must_check ved_core_init(struct drm_ipvr_private *dev_priv)
> +{
> +	int ret;
> +	struct ved_private *ved_priv;
> +	if (!dev_priv->ved_private) {
> +		ved_priv = kzalloc(sizeof(struct ved_private), GFP_KERNEL);
> +		if (!ved_priv) {
> +			IPVR_ERROR("VED: alloc ved_private failed.\n");
> +			return -ENOMEM;
> +		}
> +
> +		dev_priv->ved_private = ved_priv;
> +		ved_priv->dev_priv = dev_priv;
> +
> +		/* Initialize comand ved queueing */
> +		INIT_LIST_HEAD(&ved_priv->ved_queue);
> +		mutex_init(&ved_priv->ved_mutex);
> +		spin_lock_init(&ved_priv->ved_lock);
> +		ved_priv->mmu_recover_page = alloc_page(GFP_DMA32);
> +		if (!ved_priv->mmu_recover_page) {
> +			ret = -ENOMEM;
> +			IPVR_ERROR("VED: alloc mmu_recover_page
> failed: %d.\n", ret);
> +			goto err_free_ved_priv;
> +		}
> +		IPVR_DEBUG_INIT("VED: successfully initialized
> ved_private.\n");
> +		dev_priv->ved_private= ved_priv;
> +	}
> +	ved_priv = dev_priv->ved_private;
> +
> +	ret = ved_alloc_ccb_for_rendec(dev_priv->ved_private,
> +			RENDEC_A_SIZE, RENDEC_B_SIZE);
> +	if (unlikely(ret)) {
> +		IPVR_ERROR("VED: msvdx_alloc_ccb_for_rendec
> failed: %d.\n", ret);
> +		goto err_free_mmu_recover_page;
> +	}
> +
> +	ret = ved_post_init(ved_priv);
> +	if (unlikely(ret)) {
> +		IPVR_ERROR("VED: ved_post_init failed: %d.\n", ret);
> +		goto err_free_ccb;
> +	}
> +
> +	return 0;
> +err_free_ccb:
> +	ved_free_ccb(ved_priv);
> +err_free_mmu_recover_page:
> +	__free_page(ved_priv->mmu_recover_page);
> +err_free_ved_priv:
> +	kfree(ved_priv);
> +	dev_priv->ved_private = NULL;
> +	return ret;
> +}
> +
> +int ved_core_deinit(struct drm_ipvr_private *dev_priv)
> +{
> +	struct ved_private *ved_priv = dev_priv->ved_private;
> +	if (NULL == ved_priv) {
> +		IPVR_ERROR("VED: ved_priv is NULL!\n");
> +		return -1;
> +	}
> +
> +	IPVR_DEBUG_INIT("VED: set the VED clock to 0.\n");
> +	ved_set_clocks(ved_priv, 0);
> +
> +	if (ved_priv->ccb0 || ved_priv->ccb1)
> +		ved_free_ccb(ved_priv);
> +
> +	if (ved_priv->fw_bo) {
> +		drm_gem_object_unreference_unlocked(&ved_priv-
> >fw_bo->base);
> +		ved_priv->fw_bo = NULL;
> +	}
> +
> +	if (ved_priv->ved_fw_ptr)
> +		kfree(ved_priv->ved_fw_ptr);
> +
> +	if (ved_priv->mmu_recover_page)
> +		__free_page(ved_priv->mmu_recover_page);
> +
> +	kfree(ved_priv);
> +	dev_priv->ved_private = NULL;
> +
> +	return 0;
> +}
> diff --git a/drivers/gpu/drm/ipvr/ved_fw.h
> b/drivers/gpu/drm/ipvr/ved_fw.h
> new file mode 100644
> index 0000000..3ced466
> --- /dev/null
> +++ b/drivers/gpu/drm/ipvr/ved_fw.h
> @@ -0,0 +1,81 @@
> +/*********************************************************
> *****************
> + * ved_fw.h: VED firmware support header file
> + *
> + * Copyright (c) 2014 Intel Corporation, Hillsboro, OR, USA
> + * Copyright (c) Imagination Technologies Limited, UK
> + * Copyright (c) 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
> + * All Rights Reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of
> MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
> License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along
> with
> + * this program; if not, write to the Free Software Foundation, Inc.,
> + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
> + *
> + * Authors:
> + *    Fei Jiang <fei.jiang at intel.com>
> + *    Yao Cheng <yao.cheng at intel.com>
> + *
> +
> **********************************************************
> ****************/
> +
> +
> +#ifndef _VED_FW_H_
> +#define _VED_FW_H_
> +
> +#include "ipvr_drv.h"
> +
> +#define FIRMWAREID		0x014d42ab
> +
> +/*  Non-Optimal Invalidation is not default */
> +#define MSVDX_DEVICE_NODE_FLAGS_MMU_NONOPT_INV	2
> +
> +#define FW_VA_RENDER_HOST_INT		0x00004000
> +#define MSVDX_DEVICE_NODE_FLAGS_MMU_HW_INVALIDATION
> 	0x00000020
> +#define FW_DEVA_ERROR_DETECTED 0x08000000
> +
> +/* There is no work currently underway on the hardware */
> +#define MSVDX_FW_STATUS_HW_IDLE	0x00000001
> +#define MSVDX_DEVICE_NODE_FLAG_BRN23154_BLOCK_ON_FE
> 	0x00000200
> +#define MSVDX_DEVICE_NODE_FLAGS_DEFAULT_D0
> 		\
> +	(MSVDX_DEVICE_NODE_FLAGS_MMU_NONOPT_INV |
> 		\
> +		MSVDX_DEVICE_NODE_FLAGS_MMU_HW_INVALIDATION |
> 		\
> +		MSVDX_DEVICE_NODE_FLAG_BRN23154_BLOCK_ON_FE)
> +
> +#define MSVDX_DEVICE_NODE_FLAGS_DEFAULT_D1
> 		\
> +	(MSVDX_DEVICE_NODE_FLAGS_MMU_HW_INVALIDATION |
> 		\
> +		MSVDX_DEVICE_NODE_FLAG_BRN23154_BLOCK_ON_FE)
> +
> +#define MTX_CODE_BASE		(0x80900000)
> +#define MTX_DATA_BASE		(0x82880000)
> +#define PC_START_ADDRESS	(0x80900000)
> +
> +#define MTX_CORE_CODE_MEM	(0x10)
> +#define MTX_CORE_DATA_MEM	(0x18)
> +
> +#define RENDEC_A_SIZE	(4 * 1024 * 1024)
> +#define RENDEC_B_SIZE	(1024 * 1024)
> +
> +#define TERMINATION_SIZE	48
> +
> +#define MSVDX_RESET_NEEDS_REUPLOAD_FW		(0x2)
> +#define MSVDX_RESET_NEEDS_INIT_FW		(0x1)
> +
> +/* init/deinit all ved_private related */
> +int __must_check ved_core_init(struct drm_ipvr_private *dev_priv);
> +int ved_core_deinit(struct drm_ipvr_private *dev_priv);
> +
> +/* used for resetting VED after power saving */
> +int ved_setup_fw(struct ved_private *ved_priv);
> +int ved_core_reset(struct ved_private *ved_priv);
> +int ved_wait_for_register(struct ved_private *ved_priv,
> +			u32 offset, u32 value, u32 enable,
> +			u32 poll_cnt, u32 timeout);
> +
> +#endif
> diff --git a/drivers/gpu/drm/ipvr/ved_msg.h
> b/drivers/gpu/drm/ipvr/ved_msg.h
> new file mode 100644
> index 0000000..1a1e89d
> --- /dev/null
> +++ b/drivers/gpu/drm/ipvr/ved_msg.h
> @@ -0,0 +1,256 @@
> +/*********************************************************
> *****************
> + * ved_msg.h: VED message definition
> + *
> + * Copyright (c) 2014 Intel Corporation, Hillsboro, OR, USA
> + * Copyright (c) 2003 Imagination Technologies Limited, UK
> + * All Rights Reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of
> MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
> License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along
> with
> + * this program; if not, write to the Free Software Foundation, Inc.,
> + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
> + *
> + * Authors:
> + *    Fei Jiang <fei.jiang at intel.com>
> + *    Li Zeng <li.zeng at intel.com>
> + *    Yao Cheng <yao.cheng at intel.com>
> + *
> +
> **********************************************************
> ****************/
> +
> +#ifndef _VED_MSG_H_
> +#define _VED_MSG_H_
> +
> +/* Start of parser specific Host->MTX messages. */
> +#define	FWRK_MSGID_START_PSR_HOSTMTX_MSG	(0x80)
> +
> +/* Start of parser specific MTX->Host messages. */
> +#define	FWRK_MSGID_START_PSR_MTXHOST_MSG	(0xC0)
> +
> +/* Host defined msg, just for host use, MTX not recgnize */
> +#define	FWRK_MSGID_HOST_EMULATED		(0x40)
> +
> +/* This type defines the framework specified message ids */
> +enum {
> +	/* ! Sent by the VA driver on the host to the mtx firmware.
> +	 */
> +	MTX_MSGID_PADDING = 0,
> +	MTX_MSGID_INIT = FWRK_MSGID_START_PSR_HOSTMTX_MSG,
> +	MTX_MSGID_DECODE_FE,
> +	MTX_MSGID_DEBLOCK,
> +	MTX_MSGID_INTRA_OOLD,
> +	MTX_MSGID_DECODE_BE,
> +	MTX_MSGID_HOST_BE_OPP,
> +
> +	/*! Sent by the mtx firmware to itself.
> +	 */
> +	MTX_MSGID_RENDER_MC_INTERRUPT,
> +
> +	/* used to ditinguish mrst and mfld */
> +	MTX_MSGID_DEBLOCK_MFLD = FWRK_MSGID_HOST_EMULATED,
> +	MTX_MSGID_INTRA_OOLD_MFLD,
> +	MTX_MSGID_DECODE_BE_MFLD,
> +	MTX_MSGID_HOST_BE_OPP_MFLD,
> +
> +	/*! Sent by the DXVA firmware on the MTX to the host.
> +	 */
> +	MTX_MSGID_COMPLETED =
> FWRK_MSGID_START_PSR_MTXHOST_MSG,
> +	MTX_MSGID_COMPLETED_BATCH,
> +	MTX_MSGID_DEBLOCK_REQUIRED,
> +	MTX_MSGID_TEST_RESPONCE,
> +	MTX_MSGID_ACK,
> +	MTX_MSGID_FAILED,
> +	MTX_MSGID_CONTIGUITY_WARNING,
> +	MTX_MSGID_HW_PANIC,
> +};
> +
> +#define MTX_GENMSG_SIZE_TYPE		u8
> +#define MTX_GENMSG_SIZE_MASK		(0xFF)
> +#define MTX_GENMSG_SIZE_SHIFT		(0)
> +#define MTX_GENMSG_SIZE_OFFSET		(0x0000)
> +
> +#define MTX_GENMSG_ID_TYPE		u8
> +#define MTX_GENMSG_ID_MASK		(0xFF)
> +#define MTX_GENMSG_ID_SHIFT		(0)
> +#define MTX_GENMSG_ID_OFFSET		(0x0001)
> +
> +#define MTX_GENMSG_HEADER_SIZE		2
> +
> +#define MTX_GENMSG_FENCE_TYPE		u16
> +#define MTX_GENMSG_FENCE_MASK		(0xFFFF)
> +#define MTX_GENMSG_FENCE_OFFSET		(0x0002)
> +#define MTX_GENMSG_FENCE_SHIFT		(0)
> +
> +#define FW_INVALIDATE_MMU		(0x0010)
> +
> +union msg_header {
> +	struct {
> +		u32 msg_size:8;
> +		u32 msg_type:8;
> +		u32 msg_fence:16;
> +	} bits;
> +	u32 value;
> +};
> +
> +struct fw_init_msg {
> +	union {
> +		struct {
> +			u32 msg_size:8;
> +			u32 msg_type:8;
> +			u32 reserved:16;
> +		} bits;
> +		u32 value;
> +	} header;
> +	u32 rendec_addr0;
> +	u32 rendec_addr1;
> +	union {
> +		struct {
> +			u32 rendec_size0:16;
> +			u32 rendec_size1:16;
> +		} bits;
> +		u32 value;
> +	} rendec_size;
> +};
> +
> +struct fw_decode_msg {
> +	union {
> +		struct {
> +			u32 msg_size:8;
> +			u32 msg_type:8;
> +			u32 msg_fence:16;
> +		} bits;
> +		u32 value;
> +	} header;
> +	union {
> +		struct {
> +			u32 flags:16;
> +			u32 buffer_size:16;
> +		} bits;
> +		u32 value;
> +	} flag_size;
> +	u32 crtl_alloc_addr;
> +	union {
> +		struct {
> +			u32 context:8;
> +			u32 mmu_ptd:24;
> +		} bits;
> +		u32 value;
> +	} mmu_context;
> +	u32 operating_mode;
> +};
> +
> +struct fw_deblock_msg {
> +	union {
> +		struct {
> +			u32 msg_size:8;
> +			u32 msg_type:8;
> +			u32 msg_fence:16;
> +		} bits;
> +		u32 value;
> +	} header;
> +	union {
> +		struct {
> +			u32 flags:16;
> +			u32 slice_field_type:2;
> +			u32 reserved:14;
> +		} bits;
> +		u32 value;
> +	} flag_type;
> +	u32 operating_mode;
> +	union {
> +		struct {
> +			u32 context:8;
> +			u32 mmu_ptd:24;
> +		} bits;
> +		u32 value;
> +	} mmu_context;
> +	union {
> +		struct {
> +			u32 frame_height_mb:16;
> +			u32 pic_width_mb:16;
> +		} bits;
> +		u32 value;
> +	} pic_size;
> +	u32 address_a0;
> +	u32 address_a1;
> +	u32 mb_param_address;
> +	u32 ext_stride_a;
> +	u32 address_b0;
> +	u32 address_b1;
> +	u32 alt_output_flags_b;
> +	/* additional msg outside of IMG msg */
> +	u32 address_c0;
> +	u32 address_c1;
> +};
> +
> +#define MTX_PADMSG_SIZE 2
> +struct fw_padding_msg {
> +	union {
> +		struct {
> +			u32 msg_size:8;
> +			u32 msg_type:8;
> +		} bits;
> +		u16 value;
> +	} header;
> +};
> +
> +struct fw_msg_header {
> +	union {
> +		struct {
> +			u32 msg_size:8;
> +			u32 msg_type:8;
> +			u32 msg_fence:16;
> +		} bits;
> +		u32 value;
> +	} header;
> +};
> +
> +struct fw_completed_msg {
> +	union {
> +		struct {
> +			u32 msg_size:8;
> +			u32 msg_type:8;
> +			u32 msg_fence:16;
> +		} bits;
> +		u32 value;
> +	} header;
> +	union {
> +		struct {
> +			u32 start_mb:16;
> +			u32 last_mb:16;
> +		} bits;
> +		u32 value;
> +	} mb;
> +	u32 flags;
> +	u32 vdebcr;
> +};
> +
> +struct fw_panic_msg {
> +	union {
> +		struct {
> +			u32 msg_size:8;
> +			u32 msg_type:8;
> +			u32 msg_fence:16;
> +		} bits;
> +		u32 value;
> +	} header;
> +	u32 fe_status;
> +	u32 be_status;
> +	union {
> +		struct {
> +			u32 last_mb:16;
> +			u32 reserved2:16;
> +		} bits;
> +		u32 value;
> +	} mb;
> +};
> +
> +
> +#endif
> diff --git a/drivers/gpu/drm/ipvr/ved_pm.c
> b/drivers/gpu/drm/ipvr/ved_pm.c
> new file mode 100644
> index 0000000..ee11c39
> --- /dev/null
> +++ b/drivers/gpu/drm/ipvr/ved_pm.c
> @@ -0,0 +1,335 @@
> +/*********************************************************
> *****************
> + * ved_pm.c: VED power management support
> + *
> + * Copyright (c) 2014 Intel Corporation, Hillsboro, OR, USA
> + * All Rights Reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of
> MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
> License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along
> with
> + * this program; if not, write to the Free Software Foundation, Inc.,
> + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
> + *
> + * Authors:
> + *    Yao Cheng <yao.cheng at intel.com>
> + *
> +
> **********************************************************
> ****************/
> +
> +
> +#include "ipvr_trace.h"
> +#include "ved_pm.h"
> +#include "ved_reg.h"
> +#include "ved_cmd.h"
> +#include "ved_fw.h"
> +#ifdef CONFIG_INTEL_SOC_PMC
> +#include <linux/intel_mid_pm.h>
> +#endif
> +#include <linux/module.h>
> +#include <linux/pm_runtime.h>
> +
> +extern int drm_ipvr_freq;
> +
> +#define PCI_ROOT_MSGBUS_CTRL_REG      0xD0
> +#define PCI_ROOT_MSGBUS_DATA_REG      0xD4
> +#define PCI_ROOT_MSGBUS_CTRL_EXT_REG  0xD8
> +#define PCI_ROOT_MSGBUS_READ          0x10
> +#define PCI_ROOT_MSGBUS_WRITE         0x11
> +#define PCI_ROOT_MSGBUS_DWORD_ENABLE  0xf0
> +
> +/* VED power state set/get */
> +#define PUNIT_PORT			0x04
> +#define VEDSSPM0 			0x32
> +#define VEDSSPM1 			0x33
> +#define VEDSSC				0x1
> +
> +/* VED frequency set/get */
> +#define IP_FREQ_VALID     0x80     /* Freq is valid bit */
> +
> +#define IP_FREQ_SIZE         5     /* number of bits in freq fields */
> +#define IP_FREQ_MASK      0x1f     /* Bit mask for freq field */
> +
> +/*  Positions of various frequency fields */
> +#define IP_FREQ_POS          0     /* Freq control [4:0] */
> +#define IP_FREQ_GUAR_POS     8     /* Freq guar   [12:8] */
> +#define IP_FREQ_STAT_POS    24     /* Freq status [28:24] */
> +
> +enum APM_VED_STATUS {
> +	VED_APM_STS_D0 = 0,
> +	VED_APM_STS_D1,
> +	VED_APM_STS_D2,
> +	VED_APM_STS_D3
> +};
> +
> +#define GET_FREQ_NUMBER(freq_code)	((1600 * 2)/((freq_code) + 1))
> +/* valid freq code: 0x9, 0xb, 0xd, 0xf, 0x11, 0x13 */
> +#define FREQ_CODE_CLAMP(code) ((code < 0x9)? 0x9: ((code > 0x13)?
> 0x13: code))
> +#define GET_FREQ_CODE(freq_num)	FREQ_CODE_CLAMP((((1600 *
> 2/freq_num + 1) >> 1) << 1) - 1)
> +
> +#ifdef CONFIG_INTEL_SOC_PMC
> +extern int pmc_nc_set_power_state(int islands, int state_type, int reg);
> +extern int pmc_nc_get_power_state(int islands, int reg);
> +#endif
> +
> +static int ved_save_context(struct ved_private *ved_priv)
> +{
> +	int offset;
> +	int ret;
> +	struct drm_ipvr_private *dev_priv = ved_priv->dev_priv;
> +
> +	ved_priv->ved_needs_reset = 1;
> +	/* Reset MTX */
> +	IPVR_REG_WRITE32(MTX_SOFT_RESET_MTXRESET,
> MTX_SOFT_RESET_OFFSET);
> +
> +	/* why need reset msvdx before power off it, need check IMG */
> +	ret = ved_core_reset(ved_priv);
> +	if (unlikely(ret))
> +		IPVR_DEBUG_WARN("failed to call ved_core_reset: %d\n",
> ret);
> +
> +	/* Initialize VEC Local RAM */
> +	for (offset = 0; offset < VEC_LOCAL_MEM_BYTE_SIZE / 4; ++offset)
> +		IPVR_REG_WRITE32(0, VEC_LOCAL_MEM_OFFSET + offset *
> 4);
> +
> +	return 0;
> +}
> +
> +static u32 ipvr_msgbus_read32(struct pci_dev *pci_root, u8 port, u32 addr)
> +{
> +    u32 data;
> +    u32 cmd;
> +    u32 cmdext;
> +
> +    cmd = (PCI_ROOT_MSGBUS_READ << 24) | (port << 16) |
> +        ((addr & 0xff) << 8) | PCI_ROOT_MSGBUS_DWORD_ENABLE;
> +    cmdext = addr & 0xffffff00;
> +
> +    if (cmdext) {
> +        /* This resets to 0 automatically, no need to write 0 */
> +        pci_write_config_dword(pci_root,
> PCI_ROOT_MSGBUS_CTRL_EXT_REG,
> +                    cmdext);
> +    }
> +
> +    pci_write_config_dword(pci_root, PCI_ROOT_MSGBUS_CTRL_REG, cmd);
> +    pci_read_config_dword(pci_root, PCI_ROOT_MSGBUS_DATA_REG,
> &data);
> +
> +    return data;
> +}
> +
> +static void ipvr_msgbus_write32(struct pci_dev *pci_root, u8 port, u32 addr,
> u32 data)
> +{
> +    u32 cmd;
> +    u32 cmdext;
> +
> +    cmd = (PCI_ROOT_MSGBUS_WRITE << 24) | (port << 16) |
> +        ((addr & 0xFF) << 8) | PCI_ROOT_MSGBUS_DWORD_ENABLE;
> +    cmdext = addr & 0xffffff00;
> +
> +    pci_write_config_dword(pci_root, PCI_ROOT_MSGBUS_DATA_REG,
> data);
> +
> +    if (cmdext) {
> +        /* This resets to 0 automatically, no need to write 0 */
> +        pci_write_config_dword(pci_root,
> PCI_ROOT_MSGBUS_CTRL_EXT_REG,
> +            cmdext);
> +    }
> +
> +    pci_write_config_dword(pci_root, PCI_ROOT_MSGBUS_CTRL_REG, cmd);
> +}
> +
> +static int ipvr_pm_cmd_freq_wait(struct pci_dev *pci_root, u32 reg_freq,
> u32 *freq_code_rlzd)
> +{
> +	int tcount;
> +	u32 freq_val;
> +
> +	for (tcount = 0; ; tcount++) {
> +		freq_val = ipvr_msgbus_read32(pci_root, PUNIT_PORT,
> reg_freq);
> +		if ((freq_val & IP_FREQ_VALID) == 0)
> +			break;
> +		if (tcount > 500) {
> +			IPVR_ERROR("P-Unit freq request wait timeout %x",
> +				freq_val);
> +			return -EBUSY;
> +		}
> +		udelay(1);
> +	}
> +
> +	if (freq_code_rlzd) {
> +		*freq_code_rlzd = ((freq_val >> IP_FREQ_STAT_POS) &
> +			IP_FREQ_MASK);
> +	}
> +
> +	return 0;
> +}
> +
> +static int ipvr_pm_cmd_freq_get(struct pci_dev *pci_root, u32 reg_freq)
> +{
> +	u32 freq_val;
> +	int freq_code = 0;
> +
> +	ipvr_pm_cmd_freq_wait(pci_root, reg_freq, NULL);
> +
> +	freq_val = ipvr_msgbus_read32(pci_root, PUNIT_PORT, reg_freq);
> +	freq_code =(int)((freq_val>>IP_FREQ_STAT_POS) &
> ~IP_FREQ_VALID);
> +	return freq_code;
> +}
> +
> +static int ipvr_pm_cmd_freq_set(struct pci_dev *pci_root, u32 reg_freq,
> u32 freq_code, u32 *p_freq_code_rlzd)
> +{
> +	u32 freq_val;
> +	u32 freq_code_realized;
> +	int rva;
> +
> +	rva = ipvr_pm_cmd_freq_wait(pci_root, reg_freq, NULL);
> +	if (rva < 0) {
> +		IPVR_ERROR("pm_cmd_freq_wait 1 failed: %d\n", rva);
> +		return rva;
> +	}
> +
> +	freq_val = IP_FREQ_VALID | freq_code;
> +	ipvr_msgbus_write32(pci_root, PUNIT_PORT, reg_freq, freq_val);
> +
> +	rva = ipvr_pm_cmd_freq_wait(pci_root, reg_freq,
> &freq_code_realized);
> +	if (rva < 0) {
> +		IPVR_ERROR("pm_cmd_freq_wait 2 failed: %d\n", rva);
> +		return rva;
> +	}
> +
> +	if (p_freq_code_rlzd)
> +		*p_freq_code_rlzd = freq_code_realized;
> +
> +	return rva;
> +}
> +
> +static int ved_set_freq(struct drm_ipvr_private *dev_priv, u32 freq_code)
> +{
> +	u32 freq_code_rlzd = 0;
> +	int ret;
> +
> +	ret = ipvr_pm_cmd_freq_set(dev_priv->pci_root,
> +		VEDSSPM1, freq_code, &freq_code_rlzd);
> +	if (ret < 0) {
> +		IPVR_ERROR("failed to set freqency, current is %x\n",
> +			freq_code_rlzd);
> +	}
> +
> +	return ret;
> +}
> +
> +static int ved_get_freq(struct drm_ipvr_private *dev_priv)
> +{
> +	return ipvr_pm_cmd_freq_get(dev_priv->pci_root, VEDSSPM1);
> +}
> +
> +#ifdef CONFIG_INTEL_SOC_PMC
> +static inline bool do_power_on(struct drm_ipvr_private *dev_priv)
> +{
> +	if (pmc_nc_set_power_state(VEDSSC, 0, VEDSSPM0)) {
> +		IPVR_ERROR("VED: pmu_nc_set_power_state ON fail!\n");
> +		return false;
> +	}
> +	return true;
> +}
> +static inline bool do_power_off(struct drm_ipvr_private *dev_priv)
> +{
> +	if (pmc_nc_set_power_state(VEDSSC, 1, VEDSSPM0)) {
> +		IPVR_ERROR("VED: pmu_nc_set_power_state OFF fail!\n");
> +		return false;
> +	}
> +	return true;
> +}
> +#else
> +static inline bool do_power_on(struct drm_ipvr_private *dev_priv)
> +{
> +	u32 pwr_sts;
> +	do {
> +		ipvr_msgbus_write32(dev_priv->pci_root, PUNIT_PORT,
> VEDSSPM0, VED_APM_STS_D0);
> +		udelay(10);
> +		pwr_sts = ipvr_msgbus_read32(dev_priv->pci_root,
> PUNIT_PORT, VEDSSPM0);
> +	} while (pwr_sts != 0x0);
> +	do {
> +		ipvr_msgbus_write32(dev_priv->pci_root, PUNIT_PORT,
> VEDSSPM0, VED_APM_STS_D3);
> +		udelay(10);
> +		pwr_sts = ipvr_msgbus_read32(dev_priv->pci_root,
> PUNIT_PORT, VEDSSPM0);
> +	} while (pwr_sts != 0x03000003);
> +	do {
> +		ipvr_msgbus_write32(dev_priv->pci_root, PUNIT_PORT,
> VEDSSPM0, VED_APM_STS_D0);
> +		udelay(10);
> +		pwr_sts = ipvr_msgbus_read32(dev_priv->pci_root,
> PUNIT_PORT, VEDSSPM0);
> +	} while (pwr_sts != 0x0);
> +	return true;
> +}
> +static inline bool do_power_off(struct drm_ipvr_private *dev_priv)
> +{
> +	u32 pwr_sts;
> +	do {
> +		ipvr_msgbus_write32(dev_priv->pci_root, PUNIT_PORT,
> VEDSSPM0, VED_APM_STS_D3);
> +		udelay(10);
> +		pwr_sts = ipvr_msgbus_read32(dev_priv->pci_root,
> PUNIT_PORT, VEDSSPM0);
> +	} while (pwr_sts != 0x03000003);
> +	return true;
> +}
> +#endif
> +
> +bool ved_power_on(struct drm_ipvr_private *dev_priv)
> +{
> +	int ved_freq_code_before, ved_freq_code_requested,
> ved_freq_code_after;
> +	IPVR_DEBUG_PM("VED: power on msvdx.\n");
> +
> +	if (dev_priv->ved_private)
> +		dev_priv->ved_private->ved_busy = false;
> +	if (!do_power_on(dev_priv))
> +		return false;
> +
> +	ved_freq_code_before = ved_get_freq(dev_priv);
> +	ved_freq_code_requested = GET_FREQ_CODE(drm_ipvr_freq);
> +	if (ved_set_freq(dev_priv, ved_freq_code_requested)) {
> +		IPVR_ERROR("Failed to set VED frequency\n");
> +	}
> +
> +	ved_freq_code_after = ved_get_freq(dev_priv);
> +	IPVR_DEBUG_PM("VED freqency requested %dMHz: actual %dMHz
> => %dMHz\n",
> +		drm_ipvr_freq,
> GET_FREQ_NUMBER(ved_freq_code_before),
> +		GET_FREQ_NUMBER(ved_freq_code_after));
> +	drm_ipvr_freq = GET_FREQ_NUMBER(ved_freq_code_after);
> +
> +	trace_ved_power_on(drm_ipvr_freq);
> +	return true;
> +}
> +
> +bool ved_power_off(struct drm_ipvr_private *dev_priv)
> +{
> +	int ved_freq_code;
> +	int ret;
> +	IPVR_DEBUG_PM("VED: power off msvdx.\n");
> +
> +	if (dev_priv->ved_private) {
> +		ret = ved_save_context(dev_priv->ved_private);
> +		if (unlikely(ret)) {
> +			IPVR_ERROR("Failed to save VED context: %d, stop
> powering off\n", ret);
> +			return false;
> +		}
> +		dev_priv->ved_private->ved_busy = false;
> +	}
> +
> +	ved_freq_code = ved_get_freq(dev_priv);
> +	drm_ipvr_freq = GET_FREQ_NUMBER(ved_freq_code);
> +	IPVR_DEBUG_PM("VED freqency: code %d (%dMHz)\n",
> ved_freq_code, drm_ipvr_freq);
> +
> +	if (!do_power_off(dev_priv))
> +		return false;
> +
> +	trace_ved_power_off(drm_ipvr_freq);
> +	return true;
> +}
> +
> +bool is_ved_on(struct drm_ipvr_private *dev_priv)
> +{
> +	u32 pwr_sts;
> +	pwr_sts = ipvr_msgbus_read32(dev_priv->pci_root, PUNIT_PORT,
> VEDSSPM0);
> +	return (pwr_sts == VED_APM_STS_D0);
> +}
> diff --git a/drivers/gpu/drm/ipvr/ved_pm.h
> b/drivers/gpu/drm/ipvr/ved_pm.h
> new file mode 100644
> index 0000000..4ed1485
> --- /dev/null
> +++ b/drivers/gpu/drm/ipvr/ved_pm.h
> @@ -0,0 +1,36 @@
> +/*********************************************************
> *****************
> + * ved_pm.h: VED power management header file
> + *
> + * Copyright (c) 2014 Intel Corporation, Hillsboro, OR, USA
> + * All Rights Reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of
> MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
> License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along
> with
> + * this program; if not, write to the Free Software Foundation, Inc.,
> + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
> + *
> + * Authors:
> + *    Yao Cheng <yao.cheng at intel.com>
> + *
> +
> **********************************************************
> ****************/
> +
> +#ifndef _VED_PM_H_
> +#define _VED_PM_H_
> +
> +#include "ipvr_drv.h"
> +
> +bool is_ved_on(struct drm_ipvr_private *dev_priv);
> +
> +bool __must_check ved_power_on(struct drm_ipvr_private *dev_priv);
> +
> +bool ved_power_off(struct drm_ipvr_private *dev_priv);
> +
> +#endif
> diff --git a/drivers/gpu/drm/ipvr/ved_reg.h
> b/drivers/gpu/drm/ipvr/ved_reg.h
> new file mode 100644
> index 0000000..b7c69cf
> --- /dev/null
> +++ b/drivers/gpu/drm/ipvr/ved_reg.h
> @@ -0,0 +1,561 @@
> +/*********************************************************
> *****************
> + * ved_reg.h: VED register definition
> + *
> + * Copyright (c) 2014 Intel Corporation, Hillsboro, OR, USA
> + * Copyright (c) Imagination Technologies Limited, UK
> + * All Rights Reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of
> MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
> License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along
> with
> + * this program; if not, write to the Free Software Foundation, Inc.,
> + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
> + *
> + * Authors:
> + *    Fei Jiang <fei.jiang at intel.com>
> + *    Yao Cheng <yao.cheng at intel.com>
> + *
> +
> **********************************************************
> ****************/
> +
> +#ifndef _VED_REG_H_
> +#define _VED_REG_H_
> +
> +#include "ipvr_drv.h"
> +
> +#define REGISTER(__group__, __reg__)
> (__group__##_##__reg__##_OFFSET)
> +
> +#define MTX_INTERNAL_REG(R_SPECIFIER , U_SPECIFIER)	\
> +	(((R_SPECIFIER)<<4) | (U_SPECIFIER))
> +#define MTX_PC		MTX_INTERNAL_REG(0, 5)
> +
> +#define MEMIO_READ_FIELD(vpMem, field)
> 		\
> +	((u32)(((*((field##_TYPE*)(((u32)vpMem) + field##_OFFSET))) \
> +			& field##_MASK) >> field##_SHIFT))
> 	\
> +
> +#define MEMIO_WRITE_FIELD(vpMem, field, value)
> 		\
> +do {
> 	\
> +	((*((field##_TYPE*)(((u32)vpMem) + field##_OFFSET))) =	\
> +		((*((field##_TYPE*)(((u32)vpMem) + field##_OFFSET)))
> 	\
> +			& (field##_TYPE)~field##_MASK) |
> 	\
> +	(field##_TYPE)(((u32)(value) << field##_SHIFT) & field##_MASK)); \
> +} while (0)
> +
> +#define MEMIO_WRITE_FIELD_LITE(vpMem, field, value)
> 		\
> +do {
> 	\
> +	 (*((field##_TYPE*)(((u32)vpMem) + field##_OFFSET))) =
> 	\
> +	((*((field##_TYPE*)(((u32)vpMem) + field##_OFFSET))) |
> 	\
> +		(field##_TYPE)(((u32)(value) << field##_SHIFT)));	\
> +} while (0)
> +
> +#define REGIO_READ_FIELD(reg_val, reg, field)
> 		\
> +	((reg_val & reg##_##field##_MASK) >> reg##_##field##_SHIFT)
> +
> +#define REGIO_WRITE_FIELD(reg_val, reg, field, value)
> 		\
> +do {
> 	\
> +	(reg_val) =
> 	\
> +	((reg_val) & ~(reg##_##field##_MASK)) |
> 	\
> +	(((value) << (reg##_##field##_SHIFT)) & (reg##_##field##_MASK));
> 	\
> +} while (0)
> +
> +
> +#define REGIO_WRITE_FIELD_LITE(reg_val, reg, field, value)
> 	\
> +do {
> 	\
> +	(reg_val) = ((reg_val) | ((value) << (reg##_##field##_SHIFT)));	\
> +} while (0)
> +
> +/****** MSVDX.Technical Reference Manual.2.0.2.4.External VXD38x
> **************
> +Offset address 			Name 			Identifier
> +0x0000 - 0x03FF (1024B)		MTX Register
> 	REG_MSVDX_MTX
> +0x0400 - 0x047F (128B)		VDMC Register		REG_MSVDX
> _VDMC
> +0x0480 - 0x04FF (128B)		VDEB Register		REG_MSVDX
> _VDEB
> +0x0500 - 0x05FF (256B)		DMAC Register		REG_MSVDX
> _DMAC
> +0x0600 - 0x06FF (256B)		MSVDX Core Register	REG_MSVDX
> _SYS
> +0x0700 - 0x07FF (256B)		VEC iQ Matrix RAM
> 	REG_MSVDX_VEC_IQRAM
> +0x0800 - 0x0FFF (2048B)		VEC Registers		REG_MSVDX
> _VEC
> +0x1000 - 0x1FFF (4kB)		Command Register	REG_MSVDX _CMD
> +0x2000 - 0x2FFF (4kB)		VEC Local RAM		REG_MSVDX
> _VEC_RAM
> +0x3000 - 0x4FFF (8kB)		VEC VLC Table		RAM REG_MSVDX
> _VEC_VLC
> +0x5000 - 0x5FFF (4kB)		AXI Register		REG_MSVDX _AXI
> +*********************************************************
> *********************/
> +
> +/*************** MTX registers start: 0x0000 - 0x03FF (1024B)
> ****************/
> +#define MTX_ENABLE_OFFSET				(0x0000)
> +#define MTX_ENABLE_MTX_ENABLE_MASK
> 	(0x00000001)
> +#define MTX_ENABLE_MTX_ENABLE_SHIFT				(0)
> +
> +#define MTX_KICK_INPUT_OFFSET				(0x0080)
> +
> +#define MTX_REGISTER_READ_WRITE_REQUEST_OFFSET
> 	(0x00FC)
> +#define MTX_REGISTER_READ_WRITE_REQUEST_MTX_DREADY_MASK
> 	(0x80000000)
> +#define MTX_REGISTER_READ_WRITE_REQUEST_MTX_DREADY_SHIFT
> 	(31)
> +#define MTX_REGISTER_READ_WRITE_REQUEST_MTX_RNW_MASK
> 	(0x00010000)
> +#define MTX_REGISTER_READ_WRITE_REQUEST_MTX_RNW_SHIFT
> 	(16)
> +
> +#define MTX_REGISTER_READ_WRITE_DATA_OFFSET
> 	(0x00F8)
> +
> +#define MTX_RAM_ACCESS_DATA_TRANSFER_OFFSET
> 	(0x0104)
> +
> +#define MTX_RAM_ACCESS_CONTROL_OFFSET
> 	(0x0108)
> +#define MTX_RAM_ACCESS_CONTROL_MTX_MCMID_MASK
> 	(0x0FF00000)
> +#define MTX_RAM_ACCESS_CONTROL_MTX_MCMID_SHIFT
> 	(20)
> +#define MTX_RAM_ACCESS_CONTROL_MTX_MCM_ADDR_MASK
> 	(0x000FFFFC)
> +#define MTX_RAM_ACCESS_CONTROL_MTX_MCM_ADDR_SHIFT
> 	(2)
> +#define MTX_RAM_ACCESS_CONTROL_MTX_MCMAI_MASK
> 	(0x00000002)
> +#define MTX_RAM_ACCESS_CONTROL_MTX_MCMAI_SHIFT
> 	(1)
> +#define MTX_RAM_ACCESS_CONTROL_MTX_MCMR_MASK
> 	(0x00000001)
> +#define MTX_RAM_ACCESS_CONTROL_MTX_MCMR_SHIFT
> 	(0)
> +
> +#define MTX_RAM_ACCESS_STATUS_OFFSET
> 	(0x010C)
> +
> +#define MTX_SOFT_RESET_OFFSET				(0x0200)
> +#define MTX_SOFT_RESET_MTX_RESET_MASK
> 	(0x00000001)
> +#define MTX_SOFT_RESET_MTX_RESET_SHIFT
> 	(0)
> +#define	MTX_SOFT_RESET_MTXRESET
> 	(0x00000001)
> +
> +#define MTX_SYSC_TIMERDIV_OFFSET			(0x0208)
> +
> +#define MTX_SYSC_CDMAC_OFFSET				(0x0340)
> +#define MTX_SYSC_CDMAC_BURSTSIZE_MASK
> 	(0x07000000)
> +#define MTX_SYSC_CDMAC_BURSTSIZE_SHIFT
> 	(24)
> +#define MTX_SYSC_CDMAC_RNW_MASK
> 	(0x00020000)
> +#define MTX_SYSC_CDMAC_RNW_SHIFT				(17)
> +#define MTX_SYSC_CDMAC_ENABLE_MASK
> 	(0x00010000)
> +#define MTX_SYSC_CDMAC_ENABLE_SHIFT				(16)
> +#define MTX_SYSC_CDMAC_LENGTH_MASK
> 	(0x0000FFFF)
> +#define MTX_SYSC_CDMAC_LENGTH_SHIFT				(0)
> +
> +#define MTX_SYSC_CDMAA_OFFSET				(0x0344)
> +
> +#define MTX_SYSC_CDMAS0_OFFSET      			(0x0348)
> +
> +#define MTX_SYSC_CDMAT_OFFSET				(0x0350)
> +/************************** MTX registers end
> **************************/
> +
> +/**************** DMAC Registers: 0x0500 - 0x05FF (256B)
> ***************/
> +#define DMAC_DMAC_COUNT_EN_MASK         		(0x00010000)
> +#define DMAC_DMAC_IRQ_STAT_TRANSFER_FIN_MASK            (0x00020000)
> +
> +#define DMAC_DMAC_SETUP_OFFSET
> 	(0x0500)
> +
> +#define DMAC_DMAC_COUNT_OFFSET
> 	(0x0504)
> +#define DMAC_DMAC_COUNT_BSWAP_LSBMASK
> 	(0x00000001)
> +#define DMAC_DMAC_COUNT_BSWAP_SHIFT            		(30)
> +#define DMAC_DMAC_COUNT_PW_LSBMASK
> 	(0x00000003)
> +#define DMAC_DMAC_COUNT_PW_SHIFT                		(27)
> +#define DMAC_DMAC_COUNT_DIR_LSBMASK
> 	(0x00000001)
> +#define DMAC_DMAC_COUNT_DIR_SHIFT				(26)
> +#define DMAC_DMAC_COUNT_PI_LSBMASK
> 	(0x00000003)
> +#define DMAC_DMAC_COUNT_PI_SHIFT				(24)
> +#define DMAC_DMAC_COUNT_CNT_LSBMASK
> 	(0x0000FFFF)
> +#define DMAC_DMAC_COUNT_CNT_SHIFT				(0)
> +#define DMAC_DMAC_COUNT_EN_MASK
> 	(0x00010000)
> +#define DMAC_DMAC_COUNT_EN_SHIFT				(16)
> +
> +#define DMAC_DMAC_PERIPH_OFFSET
> 	(0x0508)
> +#define DMAC_DMAC_PERIPH_ACC_DEL_LSBMASK
> 	(0x00000007)
> +#define DMAC_DMAC_PERIPH_ACC_DEL_SHIFT
> 	(29)
> +#define DMAC_DMAC_PERIPH_INCR_LSBMASK
> 	(0x00000001)
> +#define DMAC_DMAC_PERIPH_INCR_SHIFT				(27)
> +#define DMAC_DMAC_PERIPH_BURST_LSBMASK
> 	(0x00000007)
> +#define DMAC_DMAC_PERIPH_BURST_SHIFT
> 	(24)
> +
> +#define DMAC_DMAC_IRQ_STAT_OFFSET			(0x050C)
> +#define DMAC_DMAC_IRQ_STAT_TRANSFER_FIN_MASK
> 	(0x00020000)
> +
> +#define DMAC_DMAC_PERIPHERAL_ADDR_OFFSET		(0x0514)
> +#define DMAC_DMAC_PERIPHERAL_ADDR_ADDR_MASK
> 	(0x007FFFFF)
> +#define DMAC_DMAC_PERIPHERAL_ADDR_ADDR_LSBMASK
> 	(0x007FFFFF)
> +#define DMAC_DMAC_PERIPHERAL_ADDR_ADDR_SHIFT
> 	(0)
> +
> +/* DMAC control */
> +#define IPVR_DMAC_VALUE_COUNT(BSWAP, PW, DIR, PERIPH_INCR,
> COUNT) 	\
> +		((((BSWAP) & DMAC_DMAC_COUNT_BSWAP_LSBMASK) <<
> 	\
> +			DMAC_DMAC_COUNT_BSWAP_SHIFT) |
> 	\
> +		(((PW) & DMAC_DMAC_COUNT_PW_LSBMASK) <<
> 	\
> +			DMAC_DMAC_COUNT_PW_SHIFT) |
> 	\
> +		(((DIR) & DMAC_DMAC_COUNT_DIR_LSBMASK) <<
> 	\
> +			DMAC_DMAC_COUNT_DIR_SHIFT) |
> 	\
> +		(((PERIPH_INCR) & DMAC_DMAC_COUNT_PI_LSBMASK) <<
> 	\
> +			DMAC_DMAC_COUNT_PI_SHIFT) |
> 	\
> +		(((COUNT) & DMAC_DMAC_COUNT_CNT_LSBMASK) <<
> 		\
> +			DMAC_DMAC_COUNT_CNT_SHIFT))
> +
> +#define IPVR_DMAC_VALUE_PERIPH_PARAM(ACC_DEL, INCR, BURST)
> 		\
> +		((((ACC_DEL) & DMAC_DMAC_PERIPH_ACC_DEL_LSBMASK)
> <<	\
> +			DMAC_DMAC_PERIPH_ACC_DEL_SHIFT) |
> 	\
> +		(((INCR) & DMAC_DMAC_PERIPH_INCR_LSBMASK) <<
> 	\
> +			DMAC_DMAC_PERIPH_INCR_SHIFT) | 		\
> +		(((BURST) & DMAC_DMAC_PERIPH_BURST_LSBMASK) <<
> 		\
> +			DMAC_DMAC_PERIPH_BURST_SHIFT))
> +
> +typedef enum {
> +	/* !< No byte swapping will be performed. */
> +	IPVR_DMAC_BSWAP_NO_SWAP = 0x0,
> +	/* !< Byte order will be reversed. */
> +	IPVR_DMAC_BSWAP_REVERSE = 0x1,
> +} DMAC_eBSwap;
> +
> +typedef enum {
> +	/* !< Data from memory to peripheral. */
> +	IPVR_DMAC_DIR_MEM_TO_PERIPH = 0x0,
> +	/* !< Data from peripheral to memory. */
> +	IPVR_DMAC_DIR_PERIPH_TO_MEM = 0x1,
> +} DMAC_eDir;
> +
> +typedef enum {
> +	IPVR_DMAC_ACC_DEL_0	= 0x0,	/* !< Access delay zero clock
> cycles */
> +	IPVR_DMAC_ACC_DEL_256    = 0x1,	/* !< Access delay 256 clock
> cycles */
> +	IPVR_DMAC_ACC_DEL_512    = 0x2,	/* !< Access delay 512 clock
> cycles */
> +	IPVR_DMAC_ACC_DEL_768    = 0x3,	/* !< Access delay 768 clock
> cycles */
> +	IPVR_DMAC_ACC_DEL_1024   = 0x4,	/* !< Access delay 1024 clock
> cycles */
> +	IPVR_DMAC_ACC_DEL_1280   = 0x5,	/* !< Access delay 1280 clock
> cycles */
> +	IPVR_DMAC_ACC_DEL_1536   = 0x6,	/* !< Access delay 1536 clock
> cycles */
> +	IPVR_DMAC_ACC_DEL_1792   = 0x7,	/* !< Access delay 1792 clock
> cycles */
> +} DMAC_eAccDel;
> +
> +typedef enum {
> +	IPVR_DMAC_INCR_OFF	= 0,	/* !< Static peripheral
> address. */
> +	IPVR_DMAC_INCR_ON	= 1,	/* !< Incrementing peripheral
> address. */
> +} DMAC_eIncr;
> +
> +typedef enum {
> +	IPVR_DMAC_BURST_0	= 0x0,	/* !< burst size of 0 */
> +	IPVR_DMAC_BURST_1        = 0x1,	/* !< burst size of 1 */
> +	IPVR_DMAC_BURST_2        = 0x2,	/* !< burst size of 2 */
> +	IPVR_DMAC_BURST_3        = 0x3,	/* !< burst size of 3 */
> +	IPVR_DMAC_BURST_4        = 0x4,	/* !< burst size of 4 */
> +	IPVR_DMAC_BURST_5        = 0x5,	/* !< burst size of 5 */
> +	IPVR_DMAC_BURST_6        = 0x6,	/* !< burst size of 6 */
> +	IPVR_DMAC_BURST_7        = 0x7,	/* !< burst size of 7 */
> +} DMAC_eBurst;
> +/************************** DMAC Registers end
> **************************/
> +
> +/**************** MSVDX Core Registers: 0x0600 - 0x06FF (256B)
> ***************/
> +#define MSVDX_CONTROL_OFFSET
> 	(0x0600)
> +#define MSVDX_CONTROL_MSVDX_SOFT_RESET_MASK
> 	(0x00000100)
> +#define MSVDX_CONTROL_MSVDX_SOFT_RESET_SHIFT
> 	(8)
> +#define MSVDX_CONTROL_DMAC_CH0_SELECT_MASK
> 	(0x00001000)
> +#define MSVDX_CONTROL_DMAC_CH0_SELECT_SHIFT
> 	(12)
> +#define MSVDX_CONTROL_MSVDX_SOFT_RESET_MASK
> 	(0x00000100)
> +#define MSVDX_CONTROL_MSVDX_SOFT_RESET_SHIFT
> 	(8)
> +#define MSVDX_CONTROL_MSVDX_FE_SOFT_RESET_MASK
> 	(0x00010000)
> +#define MSVDX_CONTROL_MSVDX_BE_SOFT_RESET_MASK
> 	(0x00100000)
> +#define MSVDX_CONTROL_MSVDX_VEC_MEMIF_SOFT_RESET_MASK
> 		(0x01000000)
> +#define
> MSVDX_CONTROL_MSVDX_VEC_RENDEC_DEC_SOFT_RESET_MASK
> 	(0x10000000)
> +#define msvdx_sw_reset_all \
> +	(MSVDX_CONTROL_MSVDX_SOFT_RESET_MASK |
> 	\
> +	MSVDX_CONTROL_MSVDX_FE_SOFT_RESET_MASK |		\
> +	MSVDX_CONTROL_MSVDX_BE_SOFT_RESET_MASK	|
> 	\
> +	MSVDX_CONTROL_MSVDX_VEC_MEMIF_SOFT_RESET_MASK |
> 	\
> +	MSVDX_CONTROL_MSVDX_VEC_RENDEC_DEC_SOFT_RESET_MASK)
> +
> +#define MSVDX_INTERRUPT_CLEAR_OFFSET			(0x060C)
> +
> +#define MSVDX_INTERRUPT_STATUS_OFFSET
> 	(0x0608)
> +#define MSVDX_INTERRUPT_STATUS_MMU_FAULT_IRQ_MASK
> 	(0x00000F00)
> +#define MSVDX_INTERRUPT_STATUS_MMU_FAULT_IRQ_SHIFT
> 	(8)
> +#define MSVDX_INTERRUPT_STATUS_MTX_IRQ_MASK
> 	(0x00004000)
> +#define MSVDX_INTERRUPT_STATUS_MTX_IRQ_SHIFT
> 	(14)
> +
> +#define MSVDX_HOST_INTERRUPT_ENABLE_OFFSET		(0x0610)
> +
> +#define MSVDX_MAN_CLK_ENABLE_OFFSET			(0x0620)
> +#define MSVDX_MAN_CLK_ENABLE_CORE_MAN_CLK_ENABLE_MASK
> 		(0x00000001)
> +#define
> MSVDX_MAN_CLK_ENABLE_VDEB_PROCESS_MAN_CLK_ENABLE_MASK
> 	(0x00000002)
> +#define
> MSVDX_MAN_CLK_ENABLE_VDEB_ACCESS_MAN_CLK_ENABLE_MASK
> 	(0x00000004)
> +#define MSVDX_MAN_CLK_ENABLE_VDMC_MAN_CLK_ENABLE_MASK
> 		(0x00000008)
> +#define
> MSVDX_MAN_CLK_ENABLE_VEC_ENTDEC_MAN_CLK_ENABLE_MASK
> 	(0x00000010)
> +#define
> MSVDX_MAN_CLK_ENABLE_VEC_ITRANS_MAN_CLK_ENABLE_MASK
> 	(0x00000020)
> +#define MSVDX_MAN_CLK_ENABLE_MTX_MAN_CLK_ENABLE_MASK
> 		(0x00000040)
> +#define
> MSVDX_MAN_CLK_ENABLE_VDEB_PROCESS_AUTO_CLK_ENABLE_MASK
> (0x00020000)
> +#define
> MSVDX_MAN_CLK_ENABLE_VDEB_ACCESS_AUTO_CLK_ENABLE_MASK
> 	(0x00040000)
> +#define MSVDX_MAN_CLK_ENABLE_VDMC_AUTO_CLK_ENABLE_MASK
> 	(0x00080000)
> +#define
> MSVDX_MAN_CLK_ENABLE_VEC_ENTDEC_AUTO_CLK_ENABLE_MASK
> 	(0x00100000)
> +#define
> MSVDX_MAN_CLK_ENABLE_VEC_ITRANS_AUTO_CLK_ENABLE_MASK
> 	(0x00200000)
> +
> +#define clk_enable_all	\
> +	(MSVDX_MAN_CLK_ENABLE_CORE_MAN_CLK_ENABLE_MASK
> 			| \
> +
> 	MSVDX_MAN_CLK_ENABLE_VDEB_PROCESS_MAN_CLK_ENABLE_M
> ASK 		| \
> +
> 	MSVDX_MAN_CLK_ENABLE_VDEB_ACCESS_MAN_CLK_ENABLE_MA
> SK 		| \
> +	MSVDX_MAN_CLK_ENABLE_VDMC_MAN_CLK_ENABLE_MASK
> 	 		| \
> +
> 	MSVDX_MAN_CLK_ENABLE_VEC_ENTDEC_MAN_CLK_ENABLE_MAS
> K 		| \
> +
> 	MSVDX_MAN_CLK_ENABLE_VEC_ITRANS_MAN_CLK_ENABLE_MAS
> K 		| \
> +	MSVDX_MAN_CLK_ENABLE_MTX_MAN_CLK_ENABLE_MASK)
> +
> +#define clk_enable_minimal \
> +	(MSVDX_MAN_CLK_ENABLE_CORE_MAN_CLK_ENABLE_MASK | \
> +	MSVDX_MAN_CLK_ENABLE_MTX_MAN_CLK_ENABLE_MASK)
> +
> +#define clk_enable_auto	\
> +
> 	(MSVDX_MAN_CLK_ENABLE_VDEB_PROCESS_AUTO_CLK_ENABLE_
> MASK	| \
> +
> 	MSVDX_MAN_CLK_ENABLE_VDEB_ACCESS_AUTO_CLK_ENABLE_M
> ASK		| \
> +	MSVDX_MAN_CLK_ENABLE_VDMC_AUTO_CLK_ENABLE_MASK
> 			| \
> +
> 	MSVDX_MAN_CLK_ENABLE_VEC_ENTDEC_AUTO_CLK_ENABLE_MA
> SK		| \
> +
> 	MSVDX_MAN_CLK_ENABLE_VEC_ITRANS_AUTO_CLK_ENABLE_MAS
> K		| \
> +	MSVDX_MAN_CLK_ENABLE_CORE_MAN_CLK_ENABLE_MASK
> 		| \
> +	MSVDX_MAN_CLK_ENABLE_MTX_MAN_CLK_ENABLE_MASK)
> +
> +#define MSVDX_CORE_ID_OFFSET				(0x0630)
> +#define MSVDX_CORE_REV_OFFSET				(0x0640)
> +
> +#define MSVDX_DMAC_STREAM_STATUS_OFFSET
> 	(0x0648)
> +
> +#define MSVDX_MMU_CONTROL0_OFFSET			(0x0680)
> +#define MSVDX_MMU_CONTROL0_MMU_PAUSE_MASK
> 	(0x00000002)
> +#define MSVDX_MMU_CONTROL0_MMU_PAUSE_SHIFT
> 	(1)
> +#define MSVDX_MMU_CONTROL0_MMU_INVALDC_MASK
> 	(0x00000008)
> +#define MSVDX_MMU_CONTROL0_MMU_INVALDC_SHIFT
> 	(3)
> +
> +#define MSVDX_MMU_BANK_INDEX_OFFSET
> 	(0x0688)
> +
> +#define MSVDX_MMU_STATUS_OFFSET
> 	(0x068C)
> +
> +#define MSVDX_MMU_CONTROL2_OFFSET			(0x0690)
> +
> +#define MSVDX_MMU_DIR_LIST_BASE_OFFSET
> 	(0x0694)
> +
> +#define MSVDX_MMU_MEM_REQ_OFFSET			(0x06D0)
> +
> +#define MSVDX_MMU_TILE_BASE0_OFFSET			(0x06D4)
> +
> +#define MSVDX_MMU_TILE_BASE1_OFFSET			(0x06D8)
> +
> +#define MSVDX_MTX_RAM_BANK_OFFSET			(0x06F0)
> +#define MSVDX_MTX_RAM_BANK_MTX_RAM_BANK_SIZE_MASK
> 	(0x000F0000)
> +#define MSVDX_MTX_RAM_BANK_MTX_RAM_BANK_SIZE_SHIFT
> 	(16)
> +
> +#define MSVDX_MTX_DEBUG_OFFSET
> 	MSVDX_MTX_RAM_BANK_OFFSET
> +#define MSVDX_MTX_DEBUG_MTX_DBG_IS_SLAVE_MASK
> 	(0x00000004)
> +#define MSVDX_MTX_DEBUG_MTX_DBG_IS_SLAVE_LSBMASK
> 	(0x00000001)
> +#define MSVDX_MTX_DEBUG_MTX_DBG_IS_SLAVE_SHIFT
> 	(2)
> +#define MSVDX_MTX_DEBUG_MTX_DBG_GPIO_IN_MASK
> 	(0x00000003)
> +#define MSVDX_MTX_DEBUG_MTX_DBG_GPIO_IN_LSBMASK
> 	(0x00000003)
> +#define MSVDX_MTX_DEBUG_MTX_DBG_GPIO_IN_SHIFT
> 	(0)
> +
> +/*watch dog for FE and BE*/
> +#define FE_MSVDX_WDT_CONTROL_OFFSET			(0x0664)
> +/* MSVDX_CORE, CR_FE_MSVDX_WDT_CONTROL, FE_WDT_CNT_CTRL */
> +#define FE_MSVDX_WDT_CONTROL_FE_WDT_CNT_CTRL_MASK
> 	(0x00060000)
> +#define FE_MSVDX_WDT_CONTROL_FE_WDT_CNT_CTRL_LSBMASK
> 	(0x00000003)
> +#define FE_MSVDX_WDT_CONTROL_FE_WDT_CNT_CTRL_SHIFT
> 	(17)
> +/* MSVDX_CORE, CR_FE_MSVDX_WDT_CONTROL, FE_WDT_ENABLE */
> +#define FE_MSVDX_WDT_CONTROL_FE_WDT_ENABLE_MASK
> 	(0x00010000)
> +#define FE_MSVDX_WDT_CONTROL_FE_WDT_ENABLE_LSBMASK
> 	(0x00000001)
> +#define FE_MSVDX_WDT_CONTROL_FE_WDT_ENABLE_SHIFT
> 	(16)
> +/* MSVDX_CORE, CR_FE_MSVDX_WDT_CONTROL, FE_WDT_ACTION1 */
> +#define FE_MSVDX_WDT_CONTROL_FE_WDT_ACTION1_MASK
> 	(0x00003000)
> +#define FE_MSVDX_WDT_CONTROL_FE_WDT_ACTION1_LSBMASK
> 	(0x00000003)
> +#define FE_MSVDX_WDT_CONTROL_FE_WDT_ACTION1_SHIFT
> 	(12)
> +/* MSVDX_CORE, CR_FE_MSVDX_WDT_CONTROL, FE_WDT_ACTION0 */
> +#define FE_MSVDX_WDT_CONTROL_FE_WDT_ACTION0_MASK
> 	(0x00000100)
> +#define FE_MSVDX_WDT_CONTROL_FE_WDT_ACTION0_LSBMASK
> 	(0x00000001)
> +#define FE_MSVDX_WDT_CONTROL_FE_WDT_ACTION0_SHIFT
> 	(8)
> +/* MSVDX_CORE, CR_FE_MSVDX_WDT_CONTROL, FE_WDT_CLEAR_SELECT
> */
> +#define FE_MSVDX_WDT_CONTROL_FE_WDT_CLEAR_SELECT_MASK
> 		(0x00000030)
> +#define FE_MSVDX_WDT_CONTROL_FE_WDT_CLEAR_SELECT_LSBMASK
> 	(0x00000003)
> +#define FE_MSVDX_WDT_CONTROL_FE_WDT_CLEAR_SELECT_SHIFT
> 	(4)
> +/* MSVDX_CORE, CR_FE_MSVDX_WDT_CONTROL,
> FE_WDT_CLKDIV_SELECT */
> +#define FE_MSVDX_WDT_CONTROL_FE_WDT_CLKDIV_SELECT_MASK
> 		(0x00000007)
> +#define FE_MSVDX_WDT_CONTROL_FE_WDT_CLKDIV_SELECT_LSBMASK
> 	(0x00000007)
> +#define FE_MSVDX_WDT_CONTROL_FE_WDT_CLKDIV_SELECT_SHIFT
> 	(0)
> +
> +#define FE_MSVDX_WDTIMER_OFFSET
> 	(0x0668)
> +/* MSVDX_CORE, CR_FE_MSVDX_WDTIMER, FE_WDT_COUNTER */
> +#define FE_MSVDX_WDTIMER_FE_WDT_COUNTER_MASK
> 	(0x0000FFFF)
> +#define FE_MSVDX_WDTIMER_FE_WDT_COUNTER_LSBMASK
> 	(0x0000FFFF)
> +#define FE_MSVDX_WDTIMER_FE_WDT_COUNTER_SHIFT
> 	(0)
> +
> +#define FE_MSVDX_WDT_COMPAREMATCH_OFFSET		(0x066c)
> +/* MSVDX_CORE, CR_FE_MSVDX_WDT_COMPAREMATCH, FE_WDT_CM1
> */
> +#define FE_MSVDX_WDT_COMPAREMATCH_FE_WDT_CM1_MASK
> 	(0xFFFF0000)
> +#define FE_MSVDX_WDT_COMPAREMATCH_FE_WDT_CM1_LSBMASK
> 		(0x0000FFFF)
> +#define FE_MSVDX_WDT_COMPAREMATCH_FE_WDT_CM1_SHIFT
> 	(16)
> +/* MSVDX_CORE, CR_FE_MSVDX_WDT_COMPAREMATCH, FE_WDT_CM0
> */
> +#define FE_MSVDX_WDT_COMPAREMATCH_FE_WDT_CM0_MASK
> 	(0x0000FFFF)
> +#define FE_MSVDX_WDT_COMPAREMATCH_FE_WDT_CM0_LSBMASK
> 		(0x0000FFFF)
> +#define FE_MSVDX_WDT_COMPAREMATCH_FE_WDT_CM0_SHIFT
> 	(0)
> +
> +#define BE_MSVDX_WDT_CONTROL_OFFSET			(0x0670)
> +/* MSVDX_CORE, CR_BE_MSVDX_WDT_CONTROL, BE_WDT_CNT_CTRL */
> +#define BE_MSVDX_WDT_CONTROL_BE_WDT_CNT_CTRL_MASK
> 	(0x001E0000)
> +#define BE_MSVDX_WDT_CONTROL_BE_WDT_CNT_CTRL_LSBMASK
> 	(0x0000000F)
> +#define BE_MSVDX_WDT_CONTROL_BE_WDT_CNT_CTRL_SHIFT
> 	(17)
> +/* MSVDX_CORE, CR_BE_MSVDX_WDT_CONTROL, BE_WDT_ENABLE */
> +#define BE_MSVDX_WDT_CONTROL_BE_WDT_ENABLE_MASK
> 	(0x00010000)
> +#define BE_MSVDX_WDT_CONTROL_BE_WDT_ENABLE_LSBMASK
> 	(0x00000001)
> +#define BE_MSVDX_WDT_CONTROL_BE_WDT_ENABLE_SHIFT
> 	(16)
> +/* MSVDX_CORE, CR_BE_MSVDX_WDT_CONTROL, BE_WDT_ACTION0 */
> +#define BE_MSVDX_WDT_CONTROL_BE_WDT_ACTION0_MASK
> 	(0x00000100)
> +#define BE_MSVDX_WDT_CONTROL_BE_WDT_ACTION0_LSBMASK
> 	(0x00000001)
> +#define BE_MSVDX_WDT_CONTROL_BE_WDT_ACTION0_SHIFT
> 	(8)
> +/* MSVDX_CORE, CR_BE_MSVDX_WDT_CONTROL,
> BE_WDT_CLEAR_SELECT */
> +#define BE_MSVDX_WDT_CONTROL_BE_WDT_CLEAR_SELECT_MASK
> 		(0x000000F0)
> +#define BE_MSVDX_WDT_CONTROL_BE_WDT_CLEAR_SELECT_LSBMASK
> 	(0x0000000F)
> +#define BE_MSVDX_WDT_CONTROL_BE_WDT_CLEAR_SELECT_SHIFT
> 	(4)
> +/* MSVDX_CORE, CR_BE_MSVDX_WDT_CONTROL,
> BE_WDT_CLKDIV_SELECT */
> +#define BE_MSVDX_WDT_CONTROL_BE_WDT_CLKDIV_SELECT_MASK
> 		(0x00000007)
> +#define BE_MSVDX_WDT_CONTROL_BE_WDT_CLKDIV_SELECT_LSBMASK
> 	(0x00000007)
> +#define BE_MSVDX_WDT_CONTROL_BE_WDT_CLKDIV_SELECT_SHIFT
> 	(0)
> +
> +#define BE_MSVDX_WDTIMER_OFFSET
> 	(0x0674)
> +/* MSVDX_CORE, CR_BE_MSVDX_WDTIMER, BE_WDT_COUNTER */
> +#define BE_MSVDX_WDTIMER_BE_WDT_COUNTER_MASK
> 	(0x0000FFFF)
> +#define BE_MSVDX_WDTIMER_BE_WDT_COUNTER_LSBMASK
> 	(0x0000FFFF)
> +#define BE_MSVDX_WDTIMER_BE_WDT_COUNTER_SHIFT
> 	(0)
> +
> +#define BE_MSVDX_WDT_COMPAREMATCH_OFFSET
> 	(0x678)
> +/* MSVDX_CORE, CR_BE_MSVDX_WDT_COMPAREMATCH, BE_WDT_CM0
> */
> +#define BE_MSVDX_WDT_COMPAREMATCH_BE_WDT_CM0_MASK
> 	(0x0000FFFF)
> +#define BE_MSVDX_WDT_COMPAREMATCH_BE_WDT_CM0_LSBMASK
> 		(0x0000FFFF)
> +#define BE_MSVDX_WDT_COMPAREMATCH_BE_WDT_CM0_SHIFT
> 	(0)
> +
> +/*watch dog end*/
> +/************************** MSVDX Core Registers end
> *************************/
> +
> +/******************* VEC Registers: 0x0800 - 0x0FFF (2048B)
> ******************/
> +#define VEC_SHIFTREG_CONTROL_OFFSET			(0x0818)
> +#define VEC_SHIFTREG_CONTROL_SR_MASTER_SELECT_MASK
> 	(0x00000300)
> +#define VEC_SHIFTREG_CONTROL_SR_MASTER_SELECT_SHIFT
> 	(8)
> +/************************** VEC Registers end
> **************************/
> +
> +/************************** RENDEC Registers
> **************************/
> +#define MSVDX_RENDEC_CONTROL0_OFFSET
> 	(0x0868)
> +#define MSVDX_RENDEC_CONTROL0_RENDEC_INITIALISE_MASK
> 	(0x00000001)
> +#define MSVDX_RENDEC_CONTROL0_RENDEC_INITIALISE_SHIFT
> 	(0)
> +
> +#define MSVDX_RENDEC_CONTROL1_OFFSET
> 	(0x086C)
> +#define
> MSVDX_RENDEC_CONTROL1_RENDEC_DECODE_START_SIZE_MASK
> 	(0x000000FF)
> +#define
> MSVDX_RENDEC_CONTROL1_RENDEC_DECODE_START_SIZE_SHIFT	(0)
> +#define MSVDX_RENDEC_CONTROL1_RENDEC_BURST_SIZE_W_MASK
> 		(0x000C0000)
> +#define MSVDX_RENDEC_CONTROL1_RENDEC_BURST_SIZE_W_SHIFT
> 		(18)
> +#define MSVDX_RENDEC_CONTROL1_RENDEC_BURST_SIZE_R_MASK
> 		(0x00030000)
> +#define MSVDX_RENDEC_CONTROL1_RENDEC_BURST_SIZE_R_SHIFT
> 		(16)
> +#define
> MSVDX_RENDEC_CONTROL1_RENDEC_EXTERNAL_MEMORY_MASK
> 	(0x01000000)
> +#define
> MSVDX_RENDEC_CONTROL1_RENDEC_EXTERNAL_MEMORY_SHIFT	(24)
> +#define MSVDX_RENDEC_CONTROL1_RENDEC_DEC_DISABLE_MASK
> 	(0x08000000)
> +#define MSVDX_RENDEC_CONTROL1_RENDEC_DEC_DISABLE_SHIFT
> 	(27)
> +
> +#define MSVDX_RENDEC_BUFFER_SIZE_OFFSET
> 	(0x0870)
> +#define MSVDX_RENDEC_BUFFER_SIZE_RENDEC_BUFFER_SIZE0_MASK
> 	(0x0000FFFF)
> +#define MSVDX_RENDEC_BUFFER_SIZE_RENDEC_BUFFER_SIZE0_SHIFT
> 	(0)
> +#define MSVDX_RENDEC_BUFFER_SIZE_RENDEC_BUFFER_SIZE1_MASK
> 	(0xFFFF0000)
> +#define MSVDX_RENDEC_BUFFER_SIZE_RENDEC_BUFFER_SIZE1_SHIFT
> 	(16)
> +
> +#define MSVDX_RENDEC_BASE_ADDR0_OFFSET
> 	(0x0874)
> +
> +#define MSVDX_RENDEC_BASE_ADDR1_OFFSET
> 	(0x0878)
> +
> +#define MSVDX_RENDEC_READ_DATA_OFFSET
> 	(0x0898)
> +
> +#define MSVDX_RENDEC_CONTEXT0_OFFSET
> 	(0x0950)
> +
> +#define MSVDX_RENDEC_CONTEXT1_OFFSET
> 	(0x0954)
> +
> +#define MSVDX_RENDEC_CONTEXT2_OFFSET
> 	(0x0958)
> +
> +#define MSVDX_RENDEC_CONTEXT3_OFFSET
> 	(0x095C)
> +
> +#define MSVDX_RENDEC_CONTEXT4_OFFSET
> 	(0x0960)
> +
> +#define MSVDX_RENDEC_CONTEXT5_OFFSET
> 	(0x0964)
> +/*************************** RENDEC registers end
> ****************************/
> +
> +/******************** CMD Register: 0x1000 - 0x1FFF (4kB)
> ********************/
> +#define MSVDX_CMDS_END_SLICE_PICTURE_OFFSET
> 	(0x1404)
> +/****************************** CMD Register end
> *****************************/
> +
> +/******************** VEC Local RAM: 0x2000 - 0x2FFF (4kB)
> *******************/
> +/* vec local MEM save/restore */
> +#define VEC_LOCAL_MEM_BYTE_SIZE (4 * 1024)
> +#define VEC_LOCAL_MEM_OFFSET 0x2000
> +
> +#define MSVDX_EXT_FW_ERROR_STATE 		(0x2CC4)
> +/* Decode operations in progress or not complete */
> +#define MSVDX_FW_STATUS_IN_PROGRESS			0x00000000
> +/* there's no work underway on the hardware, idle, can be powered down
> */
> +#define MSVDX_FW_STATUS_HW_IDLE
> 	0x00000001
> +/* Panic, waiting to be reloaded */
> +#define MSVDX_FW_STATUS_HW_PANIC			0x00000003
> +
> +/*
> + * This defines the MSVDX communication buffer
> + */
> +#define MSVDX_COMMS_SIGNATURE_VALUE	(0xA5A5A5A5)	/*!<
> Signature value */
> +/*!< Host buffer size (in 32-bit words) */
> +#define NUM_WORDS_HOST_BUF		(100)
> +/*!< MTX buffer size (in 32-bit words) */
> +#define NUM_WORDS_MTX_BUF		(100)
> +
> +#define MSVDX_COMMS_AREA_ADDR			(0x02fe0)
> +#define MSVDX_COMMS_CORE_WTD
> 	(MSVDX_COMMS_AREA_ADDR - 0x08)
> +#define MSVDX_COMMS_ERROR_TRIG
> 	(MSVDX_COMMS_AREA_ADDR - 0x08)
> +#define MSVDX_COMMS_FIRMWARE_ID
> 	(MSVDX_COMMS_AREA_ADDR - 0x0C)
> +#define MSVDX_COMMS_OFFSET_FLAGS
> 	(MSVDX_COMMS_AREA_ADDR + 0x18)
> +#define	MSVDX_COMMS_MSG_COUNTER
> 	(MSVDX_COMMS_AREA_ADDR - 0x04)
> +#define MSVDX_COMMS_FW_STATUS
> 	(MSVDX_COMMS_AREA_ADDR - 0x10)
> +#define	MSVDX_COMMS_SIGNATURE
> 	(MSVDX_COMMS_AREA_ADDR + 0x00)
> +#define	MSVDX_COMMS_TO_HOST_BUF_SIZE
> 	(MSVDX_COMMS_AREA_ADDR + 0x04)
> +#define MSVDX_COMMS_TO_HOST_RD_INDEX
> 	(MSVDX_COMMS_AREA_ADDR + 0x08)
> +#define MSVDX_COMMS_TO_HOST_WRT_INDEX
> 	(MSVDX_COMMS_AREA_ADDR + 0x0C)
> +#define MSVDX_COMMS_TO_MTX_BUF_SIZE
> 	(MSVDX_COMMS_AREA_ADDR + 0x10)
> +#define MSVDX_COMMS_TO_MTX_RD_INDEX
> 	(MSVDX_COMMS_AREA_ADDR + 0x14)
> +#define MSVDX_COMMS_TO_MTX_CB_RD_INDEX
> 	(MSVDX_COMMS_AREA_ADDR + 0x18)
> +#define MSVDX_COMMS_TO_MTX_WRT_INDEX
> 	(MSVDX_COMMS_AREA_ADDR + 0x1C)
> +#define MSVDX_COMMS_TO_HOST_BUF
> 	(MSVDX_COMMS_AREA_ADDR + 0x20)
> +#define MSVDX_COMMS_TO_MTX_BUF	\
> +			(MSVDX_COMMS_TO_HOST_BUF +
> (NUM_WORDS_HOST_BUF << 2))
> +
> +/*
> + * FW FLAGs: it shall be written by the host prior to starting the Firmware.
> + */
> +/* Disable Firmware based Watch dog timers. */
> +#define DSIABLE_FW_WDT				0x0008
> +	/* Abort Immediately on errors */
> +#define ABORT_ON_ERRORS_IMMEDIATE		0x0010
> +	/* Aborts faulted slices as soon as possible. Allows non faulted slices
> +	 * to reach backend but faulted slice will not be allowed to start. */
> +#define ABORT_FAULTED_SLICE_IMMEDIATE		0x0020
> +	/* Flush faulted slices - Debug option */
> +#define FLUSH_FAULTED_SLICES			0x0080
> +	/* Don't interrupt host when to host buffer becomes full.
> +	 * Stall until space is freed up by host on it's own. */
> +#define NOT_INTERRUPT_WHEN_HOST_IS_FULL		0x0200
> +	/* Contiguity warning msg will be send to host for stream with
> +         * FW_ERROR_DETECTION_AND_RECOVERY flag set if non-contiguous
> +	 * macroblocks are detected. */
> +#define NOT_ENABLE_ON_HOST_CONCEALMENT		0x0400
> +	/* Return VDEB Signature Value in Completion message.
> +	 * This requires a VDEB data flush every slice for constant results.*/
> +#define RETURN_VDEB_DATA_IN_COMPLETION		0x0800
> +	/* Disable Auto Clock Gating. */
> +#define DSIABLE_Auto_CLOCK_GATING		0x1000
> +	/* Disable Idle GPIO signal. */
> +#define DSIABLE_IDLE_GPIO_SIG			0x2000
> +	/* Enable Setup, FE and BE Time stamps in completion message.
> +	 * Used by IMG only for firmware profiling. */
> +#define ENABLE_TIMESTAMPS_IN_COMPLETE_MSG	0x4000
> +	/* Disable off-host 2nd pass Deblocking in Firmware.  */
> +#define DSIABLE_OFFHOST_SECOND_DEBLOCK		0x20000
> +	/* Sum address signature to data signature
> +	 * when returning VDEB signature values. */
> +#define SUM_ADD_SIG_TO_DATA_SIGNATURE		0x80000
> +
> +/*
> +#define MSVDX_COMMS_AREA_END	\
> +  (MSVDX_COMMS_TO_MTX_BUF + (NUM_WORDS_HOST_BUF << 2))
> +*/
> +#define MSVDX_COMMS_AREA_END 0x03000
> +
> +#if (MSVDX_COMMS_AREA_END != 0x03000)
> +#error
> +#endif
> +/***************************** VEC Local RAM end
> *****************************/
> +
> +#endif
> --
> 2.1.0



More information about the Intel-gfx mailing list