All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH v3 0/4] drm driver for VED in Intel GPU
@ 2014-11-21 19:06 Yao Cheng
  2014-11-21 19:06 ` [RFC PATCH v3 1/4] drm/i915: add i915_ved.c to setup bridge for VED Yao Cheng
  2014-11-21 19:06 ` [RFC PATCH v3 2/4] drm/ipvr: drm driver " Yao Cheng
  0 siblings, 2 replies; 10+ messages in thread
From: Yao Cheng @ 2014-11-21 19:06 UTC (permalink / raw)
  To: intel-gfx, dri-devel, daniel.vetter, sean.v.kelley, john.chehab
  Cc: emil.l.velikov, fei.jiang

drm/ipvr is a new GEM driver for VED (PowerVR's VPU integrated in Intel GPU), which extends video capability.
A new Kconfig added for building ipvr driver:

  CONFIG_DRM_IPVR: Build option for ipvr module

The driver name "ipvr" means the PowerVR's core wrapped by Intel. The PowerVR VPUs are also integrated by non-i915 platforms such as GMA500, so we keep ipvr driver and i915 driver separated and independent to each other. To achieve this we do the minimum change in i915: i915_ved.c added for setting up the bridge between VED and i915, kerneldoc also updated.

User mode drm helper "libdrm_ipvr.so" and simple ioctl/execute test is included.

one test script "drv_module_reload" in i-g-t also updated to support ipvr loading and unloading. Due to restriction in Linux platform device model, we have to manually unload ipvr before unloading i915.

Yao Cheng (4):
[1/4] drm/i915: add i915_ved.c to setup bridge for VED
[2/4] drm/ipvr: drm driver for VED
[3/4] libdrm/ipvr: user mode helper for ipvr drm driver
[4/4] i-g-t: tests/drv_module_reload: add ipvr support

-- 
2.1.0

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [RFC PATCH v3 1/4] drm/i915: add i915_ved.c to setup bridge for VED
  2014-11-21 19:06 [RFC PATCH v3 0/4] drm driver for VED in Intel GPU Yao Cheng
@ 2014-11-21 19:06 ` Yao Cheng
  2014-11-28 16:59   ` Robert Beckett
  2014-11-21 19:06 ` [RFC PATCH v3 2/4] drm/ipvr: drm driver " Yao Cheng
  1 sibling, 1 reply; 10+ messages in thread
From: Yao Cheng @ 2014-11-21 19:06 UTC (permalink / raw)
  To: intel-gfx, dri-devel, daniel.vetter, sean.v.kelley, john.chehab
  Cc: emil.l.velikov, fei.jiang, dh.herrmann, daniel

Setup minimum required resources during i915_driver_load:
1. Create a platform device to share MMIO/IRQ resources
2. Make the platform device child of i915 device for runtime PM.
3. Create IRQ chip to forward the VED irqs.
VED driver (a standalone drm driver) probes the VED device and
creates a new dri card on install.
Currently only supports VED on valleyview.
Kerneldoc is updated for i915_ved.c.

v2:
take Daniel & Jani's comments
	- extract change to new file i915_ved.c
	- add kerneldoc
	- change 'ipvr-ved' to 'ipvr-vlv-ved' for extensibility
	- unregister platdev before irq_free_desc
	- add WARN_ON(!intel_irqs_enabled) in irq init code
	- remove unnecessary trace point
	- remove unnecessary BUG_ON

v3:
take Ville's comments and VED PRIME support
	- add HAS_VED() check
	- add ved struct to make code neat
	- no need to check platform in vlv_irq_handler
	- i915_reg.h update
	- no need to kmalloc for small amount of resource
	- remove unnecessary REG resource
	- follow vlv_display_irqs_install() to implement VED mask/unmask
	- workaround nommu_map_sg issue by set dma_mask to support VED PRIME.

Signed-off-by: Yao Cheng <yao.cheng@intel.com>
---
 Documentation/DocBook/drm.tmpl  |   5 +
 drivers/gpu/drm/i915/Makefile   |   3 +
 drivers/gpu/drm/i915/i915_dma.c |  11 ++
 drivers/gpu/drm/i915/i915_drv.h |  12 ++
 drivers/gpu/drm/i915/i915_irq.c |   2 +
 drivers/gpu/drm/i915/i915_reg.h |   4 +
 drivers/gpu/drm/i915/i915_ved.c | 255 ++++++++++++++++++++++++++++++++++++++++
 7 files changed, 292 insertions(+)
 create mode 100644 drivers/gpu/drm/i915/i915_ved.c

diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl
index 9d99772..b2d109f 100644
--- a/Documentation/DocBook/drm.tmpl
+++ b/Documentation/DocBook/drm.tmpl
@@ -3839,6 +3839,11 @@ int num_ioctls;</synopsis>
 !Fdrivers/gpu/drm/i915/i915_irq.c intel_runtime_pm_disable_interrupts
 !Fdrivers/gpu/drm/i915/i915_irq.c intel_runtime_pm_enable_interrupts
       </sect2>
+      <sect2>
+        <title>VED video core integration</title>
+!Pdrivers/gpu/drm/i915/i915_ved.c VED video core integration
+!Idrivers/gpu/drm/i915/i915_ved.c
+      </sect2>
     </sect1>
     <sect1>
       <title>Display Hardware Handling</title>
diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index 891e584..e2f2776 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -83,6 +83,9 @@ i915-y += dvo_ch7017.o \
 i915-y += i915_dma.o \
 	  i915_ums.o
 
+# VED for VLV
+i915-y += i915_ved.o
+
 obj-$(CONFIG_DRM_I915)  += i915.o
 
 CFLAGS_i915_trace_points.o := -I$(src)
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 9a73533..fbf2144 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -1791,6 +1791,13 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
 	if (IS_GEN5(dev))
 		intel_gpu_ips_init(dev_priv);
 
+	if (HAS_VED(dev)) {
+		ret = vlv_setup_ved(dev);
+		if (ret < 0) {
+			DRM_ERROR("failed to setup VED bridge: %d\n", ret);
+		}
+	}
+
 	intel_runtime_pm_enable(dev_priv);
 
 	return 0;
@@ -1833,6 +1840,10 @@ int i915_driver_unload(struct drm_device *dev)
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	int ret;
 
+	if (HAS_VED(dev)) {
+		vlv_teardown_ved(dev);
+	}
+
 	ret = i915_gem_suspend(dev);
 	if (ret) {
 		DRM_ERROR("failed to idle hardware: %d\n", ret);
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index f830596..6cfabac 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1762,6 +1762,12 @@ struct drm_i915_private {
 
 	uint32_t bios_vgacntr;
 
+	/* necessary resource sharing with ved driver. */
+	struct {
+		struct platform_device *platdev;
+		int	irq;
+	} ved;
+
 	/* Old dri1 support infrastructure, beware the dragons ya fools entering
 	 * here! */
 	struct i915_dri1_state dri1;
@@ -2257,6 +2263,7 @@ struct drm_i915_cmd_table {
 				 IS_BROADWELL(dev) || IS_VALLEYVIEW(dev))
 #define HAS_RC6(dev)		(INTEL_INFO(dev)->gen >= 6)
 #define HAS_RC6p(dev)		(INTEL_INFO(dev)->gen == 6 || IS_IVYBRIDGE(dev))
+#define HAS_VED(dev)		(INTEL_INFO(dev)->is_valleyview && IS_GEN7(dev))
 
 #define INTEL_PCH_DEVICE_ID_MASK		0xff00
 #define INTEL_PCH_IBX_DEVICE_ID_TYPE		0x3b00
@@ -2851,6 +2858,11 @@ void i915_restore_display_reg(struct drm_device *dev);
 void i915_setup_sysfs(struct drm_device *dev_priv);
 void i915_teardown_sysfs(struct drm_device *dev_priv);
 
+/* i915_ved.c */
+int vlv_setup_ved(struct drm_device *dev);
+void vlv_teardown_ved(struct drm_device *dev);
+void vlv_ved_irq_handler(struct drm_device *dev);
+
 /* intel_i2c.c */
 extern int intel_setup_gmbus(struct drm_device *dev);
 extern void intel_teardown_gmbus(struct drm_device *dev);
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 5fff287..a3394de 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -1865,6 +1865,8 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
 			snb_gt_irq_handler(dev, dev_priv, gt_iir);
 		if (pm_iir)
 			gen6_rps_irq_handler(dev_priv, pm_iir);
+		if (iir & VLV_VED_BLOCK_INTERRUPT)
+			vlv_ved_irq_handler(dev);
 		/* Call regardless, as some status bits might not be
 		 * signalled in iir */
 		valleyview_pipestat_irq_handler(dev, iir);
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index d43fa0e..1a46fe5 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -1284,6 +1284,9 @@ enum punit_power_well {
 #define VLV_DISPLAY_BASE 0x180000
 #define VLV_MIPI_BASE VLV_DISPLAY_BASE
 
+#define VLV_VED_BASE 0x170000
+#define VLV_VED_SIZE 0x010000
+
 #define VLV_GU_CTL0	(VLV_DISPLAY_BASE + 0x2030)
 #define VLV_GU_CTL1	(VLV_DISPLAY_BASE + 0x2034)
 #define SCPD0		0x0209c /* 915+ only */
@@ -1477,6 +1480,7 @@ enum punit_power_well {
 #define ILK_BSD_USER_INTERRUPT				(1<<5)
 
 #define I915_PM_INTERRUPT				(1<<31)
+#define VLV_VED_BLOCK_INTERRUPT			(1<<23)
 #define I915_ISP_INTERRUPT				(1<<22)
 #define I915_LPE_PIPE_B_INTERRUPT			(1<<21)
 #define I915_LPE_PIPE_A_INTERRUPT			(1<<20)
diff --git a/drivers/gpu/drm/i915/i915_ved.c b/drivers/gpu/drm/i915/i915_ved.c
new file mode 100644
index 0000000..982e69e
--- /dev/null
+++ b/drivers/gpu/drm/i915/i915_ved.c
@@ -0,0 +1,255 @@
+/*
+ * Copyright © 2014 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Yao Cheng <yao.cheng@intel.com>
+ *
+ */
+
+#include "i915_drv.h"
+
+/**
+ * DOC: VED video core integration
+ *
+ * Motivation:
+ * Some platforms (e.g. valleyview) integrates a VED inside GPU to extend the
+ * video decoding capability.
+ * The VED is driven by the standalone drm driver "ipvr" which covers PowerVR
+ * VPUs. Since the PowerVR VPUs are also integrated by non-i915 platforms such
+ * as GMA500, we'd like to keep ipvr driver and i915 driver separated and
+ * independent to each other. To achieve this we do the minimum work in i915
+ * to setup a bridge between ipvr and i915:
+ * 1. Create a platform device to share MMIO/IRQ resources
+ * 2. Make the platform device child of i915 device for runtime PM.
+ * 3. Create IRQ chip to forward the VED irqs.
+ * ipvr driver probes the VED device and creates a new dri card on install.
+ *
+ * Threats:
+ * Due to the restriction in Linux platform device model, user need manually
+ * uninstall ipvr driver before uninstalling i915 module, otherwise he might
+ * run into use-after-free issues after i915 removes the platform device.
+ *
+ * Implementation:
+ * The MMIO/REG platform resources are created according to the registers
+ * specification.
+ * When forwarding VED irqs, the flow control handler selection depends on the
+ * platform, for example on valleyview handle_simple_irq is enough.
+ *
+ */
+
+static struct platform_device* vlv_ved_platdev_create(struct drm_device *dev)
+{
+	int ret;
+	struct resource rsc[2] = { {0}, {0} };
+	struct platform_device *platdev;
+	u64 *dma_mask = NULL;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+
+	if (dev_priv->ved.irq < 0)
+		return ERR_PTR(-EINVAL);
+
+	platdev = platform_device_alloc("ipvr-ved-vlv", -1);
+	if (!platdev) {
+		ret = -ENOMEM;
+		DRM_ERROR("Failed to allocate VED platform device\n");
+		goto err;
+	}
+
+	/* to work-around check_addr in nommu_map_sg() */
+	dma_mask = kmalloc(sizeof(*platdev->dev.dma_mask), GFP_KERNEL);
+	if (!dma_mask) {
+		ret = -ENOMEM;
+		DRM_ERROR("Failed to allocate dma_mask\n");
+		goto err_put_dev;
+	}
+	*dma_mask = DMA_BIT_MASK(31);
+	platdev->dev.dma_mask = dma_mask;
+	platdev->dev.coherent_dma_mask = *dma_mask;
+
+	rsc[0].start    = rsc[0].end = dev_priv->ved.irq;
+	rsc[0].flags    = IORESOURCE_IRQ;
+	rsc[0].name     = "ipvr-ved-vlv-irq";
+
+	rsc[1].start    = pci_resource_start(dev->pdev, 0) + VLV_VED_BASE;
+	rsc[1].end      = pci_resource_start(dev->pdev, 0) + VLV_VED_BASE + VLV_VED_SIZE;
+	rsc[1].flags    = IORESOURCE_MEM;
+	rsc[1].name     = "ipvr-ved-vlv-mmio";
+
+	ret = platform_device_add_resources(platdev, rsc, 2);
+	if (ret) {
+		DRM_ERROR("Failed to add resource for VED platform device: %d\n", ret);
+		goto err_put_dev;
+	}
+
+	platdev->dev.parent = dev->dev; /* for VED driver's runtime-PM */
+	ret = platform_device_add(platdev);
+	if (ret) {
+		DRM_ERROR("Failed to add VED platform device: %d\n", ret);
+		goto err_put_dev;
+	}
+
+	return platdev;
+err_put_dev:
+	platform_device_put(platdev);
+err:
+	if (dma_mask)
+		kfree(dma_mask);
+	return ERR_PTR(ret);
+}
+
+static void vlv_ved_platdev_destroy(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	if (dev_priv->ved.platdev) {
+		kfree(dev_priv->ved.platdev->dev.dma_mask);
+		platform_device_unregister(dev_priv->ved.platdev);
+	}
+}
+
+static void vlv_ved_irq_unmask(struct irq_data *d)
+{
+	struct drm_device *dev = d->chip_data;
+	struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;
+	unsigned long irqflags;
+	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+
+	dev_priv->irq_mask &= ~VLV_VED_BLOCK_INTERRUPT;
+	I915_WRITE(VLV_IIR, VLV_VED_BLOCK_INTERRUPT);
+	I915_WRITE(VLV_IIR, VLV_VED_BLOCK_INTERRUPT);
+	I915_WRITE(VLV_IMR, dev_priv->irq_mask);
+	I915_WRITE(VLV_IER, ~dev_priv->irq_mask);
+	POSTING_READ(VLV_IER);
+
+	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+}
+
+static void vlv_ved_irq_mask(struct irq_data *d)
+{
+	struct drm_device *dev = d->chip_data;
+	struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;
+	unsigned long irqflags;
+	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+
+	dev_priv->irq_mask |= VLV_VED_BLOCK_INTERRUPT;
+	I915_WRITE(VLV_IER, ~dev_priv->irq_mask);
+	I915_WRITE(VLV_IMR, dev_priv->irq_mask);
+	I915_WRITE(VLV_IIR, VLV_VED_BLOCK_INTERRUPT);
+	I915_WRITE(VLV_IIR, VLV_VED_BLOCK_INTERRUPT);
+	POSTING_READ(VLV_IIR);
+
+	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+}
+
+static struct irq_chip vlv_ved_irqchip = {
+	.name = "ipvr_ved_irqchip",
+	.irq_mask = vlv_ved_irq_mask,
+	.irq_unmask = vlv_ved_irq_unmask,
+};
+
+static int vlv_ved_irq_init(struct drm_device *dev, int irq)
+{
+	struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;
+	WARN_ON(!intel_irqs_enabled(dev_priv));
+	irq_set_chip_and_handler_name(irq,
+		&vlv_ved_irqchip,
+		handle_simple_irq,
+		"ipvr_ved_vlv_irq_handler");
+	return irq_set_chip_data(irq, dev);
+}
+
+/**
+ * vlv_ved_irq_handler() - forwards the VED irq
+ * @dev: the i915 drm device
+ *
+ * the VED irq is forwarded to the irq handler registered by VED driver.
+ */
+void vlv_ved_irq_handler(struct drm_device *dev)
+{
+	int ret;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	if (dev_priv->ved.irq < 0 && printk_ratelimit()) {
+		DRM_ERROR("invalid ved irq number: %d\n", dev_priv->ved.irq);
+		return;
+	}
+	ret = generic_handle_irq(dev_priv->ved.irq);
+	if (ret && printk_ratelimit()) {
+		DRM_ERROR("error handling vlv ved irq: %d\n", ret);
+	}
+}
+
+/**
+ * vlv_setup_ved() - setup the bridge between VED driver and i915
+ * @dev: the i915 drm device
+ *
+ * set up the minimum required resources for the bridge: irq chip, platform
+ * resource and platform device. i915 device is set as parent of the new
+ * platform device.
+ *
+ * Return: 0 if successful. non-zero if allocation/initialization fails
+ */
+int vlv_setup_ved(struct drm_device *dev)
+{
+	int ret;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+
+	dev_priv->ved.irq = irq_alloc_descs(-1, 0, 1, 0);
+	if (dev_priv->ved.irq < 0) {
+		DRM_ERROR("Failed to allocate IRQ desc: %d\n", dev_priv->ved.irq);
+		ret = dev_priv->ved.irq;
+		goto err;
+	}
+
+	ret = vlv_ved_irq_init(dev, dev_priv->ved.irq);
+	if (ret) {
+		DRM_ERROR("Failed to initialize irqchip for vlv-ved: %d\n", ret);
+		goto err_free_irq;
+	}
+
+	dev_priv->ved.platdev = vlv_ved_platdev_create(dev);
+	if (IS_ERR(dev_priv->ved.platdev)) {
+		ret = PTR_ERR(dev_priv->ved.platdev);
+		DRM_ERROR("Failed to create platform device for vlv-ved: %d\n", ret);
+		goto err_free_irq;
+	}
+
+	return 0;
+err_free_irq:
+	irq_free_desc(dev_priv->ved.irq);
+err:
+	dev_priv->ved.irq = -1;
+	dev_priv->ved.platdev = NULL;
+	return ret;
+}
+
+/**
+ * vlv_teardown_ved() - destroy the bridge between VED driver and i915
+ * @dev: the i915 drm device
+ *
+ * release all the resources for VED <-> i915 bridge.
+ */
+void vlv_teardown_ved(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	vlv_ved_platdev_destroy(dev);
+	if (dev_priv->ved.irq >= 0)
+		irq_free_desc(dev_priv->ved.irq);
+}
-- 
2.1.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [RFC PATCH v3 2/4] drm/ipvr: drm driver for VED
  2014-11-21 19:06 [RFC PATCH v3 0/4] drm driver for VED in Intel GPU Yao Cheng
  2014-11-21 19:06 ` [RFC PATCH v3 1/4] drm/i915: add i915_ved.c to setup bridge for VED Yao Cheng
@ 2014-11-21 19:06 ` Yao Cheng
  2014-11-23 13:29   ` Cheng, Yao
                     ` (2 more replies)
  1 sibling, 3 replies; 10+ messages in thread
From: Yao Cheng @ 2014-11-21 19:06 UTC (permalink / raw)
  To: intel-gfx, dri-devel, daniel.vetter, sean.v.kelley, john.chehab
  Cc: emil.l.velikov, fei.jiang, dh.herrmann, daniel

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

Signed-off-by: Yao Cheng <yao.cheng@intel.com>
---
 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    |  546 +++++++++++++++++
 drivers/gpu/drm/ipvr/ipvr_bo.h    |   80 +++
 drivers/gpu/drm/ipvr/ipvr_debug.c |  347 +++++++++++
 drivers/gpu/drm/ipvr/ipvr_debug.h |   76 +++
 drivers/gpu/drm/ipvr/ipvr_drm.h   |  278 +++++++++
 drivers/gpu/drm/ipvr/ipvr_drv.c   |  614 +++++++++++++++++++
 drivers/gpu/drm/ipvr/ipvr_drv.h   |  294 +++++++++
 drivers/gpu/drm/ipvr/ipvr_exec.c  |  623 +++++++++++++++++++
 drivers/gpu/drm/ipvr/ipvr_exec.h  |   57 ++
 drivers/gpu/drm/ipvr/ipvr_fence.c |  490 +++++++++++++++
 drivers/gpu/drm/ipvr/ipvr_fence.h |   74 +++
 drivers/gpu/drm/ipvr/ipvr_gem.c   |  341 +++++++++++
 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 |  326 ++++++++++
 drivers/gpu/drm/ipvr/ved_cmd.c    |  882 +++++++++++++++++++++++++++
 drivers/gpu/drm/ipvr/ved_cmd.h    |   71 +++
 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     |  332 ++++++++++
 drivers/gpu/drm/ipvr/ved_pm.h     |   36 ++
 drivers/gpu/drm/ipvr/ved_reg.h    |  561 +++++++++++++++++
 30 files changed, 8555 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 b2d109f..07b5b19 100644
--- a/Documentation/DocBook/drm.tmpl
+++ b/Documentation/DocBook/drm.tmpl
@@ -4008,5 +4008,44 @@ int num_ioctls;</synopsis>
     </sect1>
   </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 e3b4b0f..ad7585d 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 c3cf64c..f877208 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..fb30cec
--- /dev/null
+++ b/drivers/gpu/drm/ipvr/ipvr_bo.c
@@ -0,0 +1,546 @@
+/**************************************************************************
+ * 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@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;
+	u32 mask = 0;
+	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);
+
+	/**
+	 * from vxd spec we should be able to set:
+	 *   mask |= IPVR_MMU_CACHED_MEMORY
+	 * for those object marked as IPVR_CACHE_NOACCESS
+	 * but test failed.
+	 * so we force all pages flaged as non-cached by vxd now
+	 */
+	return ipvr_mmu_insert_pages(dev_priv->mmu->default_pd,
+		obj->pages, entry, obj->base.size >> PAGE_SHIFT,
+		0, 0, mask);
+}
+
+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;
+	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 = 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);
+		return ret;
+	}
+
+	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);
+
+	return 0;
+}
+
+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_NOACCESS:
+	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_NOACCESS:
+	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.
+*/
+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_NOACCESS;
+	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@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..29e40fa
--- /dev/null
+++ b/drivers/gpu/drm/ipvr/ipvr_debug.c
@@ -0,0 +1,347 @@
+/**************************************************************************
+ * 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@intel.com>
+ *    Yao Cheng <yao.cheng@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);
+	if (obj->base.import_attach) {
+		dev_priv->ipvr_stat.imported_count++;
+		dev_priv->ipvr_stat.imported_memory += obj->base.size;
+	}
+	else {
+		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);
+	if (obj->base.import_attach) {
+		dev_priv->ipvr_stat.imported_count--;
+		dev_priv->ipvr_stat.imported_memory -= obj->base.size;
+	}
+	else {
+		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@intel.com>
+ *    Yao Cheng <yao.cheng@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..d1916fa
--- /dev/null
+++ b/drivers/gpu/drm/ipvr/ipvr_drm.h
@@ -0,0 +1,278 @@
+/**************************************************************************
+ * 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@intel.com>
+ *    Yao Cheng <yao.cheng@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;
+};
+
+enum drm_ipvr_misc_key {
+	IPVR_DEVICE_INFO,
+	IPVR_UPDATE_TILING,
+	IPVR_SET_DISPLAYING_FRAME,
+	IPVR_GET_DISPLAYING_FRAME,
+	IPVR_QUERY_ENTRY
+};
+
+/*
+ * different context maybe has different tiling stride,
+ * then tiling info need be bound with ctx
+ */
+struct drm_ipvr_update_tiling {
+	__u32 ctx_id;
+	__u32 tiling_stride;
+	__u32 tiling_scheme;
+	__u32 pad64;
+};
+
+/* Ioctl to set/get misc params:
+ */
+struct drm_ipvr_misc {
+	__u64 key;
+	__u64 arg;		/* argument pointer */
+	__u64 value;	/* feed back pointer */
+};
+
+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_NOACCESS,
+	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_MISC               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_MISC		\
+	DRM_IOWR(DRM_COMMAND_BASE + DRM_IPVR_MISC, struct drm_ipvr_misc)
+#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..9f71fbd
--- /dev/null
+++ b/drivers/gpu/drm/ipvr/ipvr_drv.c
@@ -0,0 +1,614 @@
+/**************************************************************************
+ * 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@intel.com>
+ *    Yao Cheng <yao.cheng@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_UNLOCKED),
+	DRM_IOCTL_DEF_DRV(IPVR_CONTEXT_DESTROY,
+			ipvr_context_destroy_ioctl, DRM_UNLOCKED),
+	DRM_IOCTL_DEF_DRV(IPVR_MISC,
+			ipvr_misc_ioctl, DRM_AUTH),
+	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_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_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;
+	struct platform_device *platdev = dev_priv->dev->platformdev;
+	BUG_ON(!platdev);
+	BUG_ON(atomic_read(&dev_priv->pending_events) < 0);
+	if ((pending = atomic_inc_return(&dev_priv->pending_events)) == 1) {
+		ret = pm_runtime_get_sync(&platdev->dev);
+		if (ret < 0) {
+			IPVR_ERROR("pm_runtime_get_sync returns %d\n", ret);
+			pending = atomic_dec_return(&dev_priv->pending_events);
+		}
+	}
+	trace_ipvr_get_power(atomic_read(&platdev->dev.power.usage_count),
+		pending);
+	return ret;
+}
+
+int ipvr_runtime_pm_put(struct drm_ipvr_private *dev_priv, bool async)
+{
+	int ret = 0;
+	int pending;
+	struct platform_device *platdev = dev_priv->dev->platformdev;
+	BUG_ON(!platdev);
+	BUG_ON(atomic_read(&dev_priv->pending_events) <= 0);
+	if ((pending = atomic_dec_return(&dev_priv->pending_events)) == 0) {
+		if (async)
+			ret = pm_runtime_put(&platdev->dev);
+		else
+			ret = pm_runtime_put_sync(&platdev->dev);
+		if (ret < 0)
+			IPVR_ERROR("pm_runtime_put returns %d\n", ret);
+	}
+	trace_ipvr_put_power(atomic_read(&platdev->dev.power.usage_count),
+		pending);
+	return ret;
+}
+
+int ipvr_runtime_pm_put_all(struct drm_ipvr_private *dev_priv, bool async)
+{
+	int ret = 0;
+	struct platform_device *platdev = dev_priv->dev->platformdev;
+	BUG_ON(!platdev);
+	if (atomic_read(&dev_priv->pending_events) > 0) {
+		atomic_set(&dev_priv->pending_events, 0);
+		if (async)
+			ret = pm_runtime_put(&platdev->dev);
+		else
+			ret = pm_runtime_put_sync(&platdev->dev);
+		if (ret < 0)
+			IPVR_ERROR("pm_runtime_put returns %d\n", ret);
+	}
+	trace_ipvr_put_power(atomic_read(&platdev->dev.power.usage_count),
+		0);
+	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);
+	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 */
+	INIT_LIST_HEAD(&dev_priv->ipvr_ctx_list);
+	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_KERNEL);
+	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 */
+	list_add(&dev_priv->default_ctx.head, &dev_priv->ipvr_ctx_list);
+	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 (unlikely(ipvr_fp == NULL))
+		return -ENOMEM;
+
+	file_priv->driver_priv = ipvr_fp;
+
+	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)
+{
+	/* if user didn't destory ctx explicitly, remove ctx here */
+	struct drm_ipvr_private *dev_priv;
+	struct drm_ipvr_file_private *ipvr_fpriv;
+	struct ved_private *ved_priv;
+	struct ipvr_context *ipvr_ctx  = 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;
+
+	if (ipvr_fpriv->ctx_id == IPVR_CONTEXT_INVALID_ID)
+		return;
+	ipvr_ctx = (struct ipvr_context *)
+			idr_find(&dev_priv->ipvr_ctx_idr, ipvr_fpriv->ctx_id);
+	if (!ipvr_ctx  || (ipvr_ctx->ipvr_fpriv != ipvr_fpriv)) {
+		IPVR_DEBUG_GENERAL("ctx for id %d has already destroyed\n",
+				ipvr_fpriv->ctx_id);
+		return;
+	}
+
+	/**
+	 * fixme: remove this work-around (WA the issue that calling
+	 * close() with queued cmd might cause state machine issue).
+	 * we should wait for only the cmds sent from contexts in this file
+	 * instead of all cmds
+	 */
+	ipvr_fence_wait_empty_locked(dev_priv);
+
+	IPVR_DEBUG_PM("Video:remove context type 0x%x\n", ipvr_ctx->ctx_type);
+	mutex_lock(&ved_priv->ved_mutex);
+	if (ved_priv->ipvr_ctx == ipvr_ctx )
+		ved_priv->ipvr_ctx = NULL;
+	mutex_unlock(&ved_priv->ved_mutex);
+
+	spin_lock_irqsave(&dev_priv->ipvr_ctx_lock, irq_flags);
+	list_del(&ipvr_ctx->head);
+	ipvr_fpriv->ctx_id = IPVR_CONTEXT_INVALID_ID;
+	spin_unlock_irqrestore(&dev_priv->ipvr_ctx_lock, irq_flags);
+
+	idr_remove(&dev_priv->ipvr_ctx_idr, ipvr_ctx->ctx_id);
+
+	kfree(ipvr_ctx );
+	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 workqueue for delayed power-off?
+		 */
+		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..87c7871
--- /dev/null
+++ b/drivers/gpu/drm/ipvr/ipvr_drv.h
@@ -0,0 +1,294 @@
+/**************************************************************************
+ * 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@intel.com>
+ *    Yao Cheng <yao.cheng@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 */
+	struct list_head ipvr_ctx_list;
+	spinlock_t ipvr_ctx_lock;
+	struct idr ipvr_ctx_idr;
+	struct ipvr_context default_ctx;
+
+	/* PM related */
+	atomic_t pending_events;
+
+	/* exec related */
+	struct ipvr_validate_context validate_ctx;
+
+	/* IMG MMU specific */
+	struct ipvr_mmu_driver *mmu;
+	/*struct ipvr_mmu_pd *pf_pd;*/
+	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;
+
+	/* error concealment related */
+	struct drm_file *tfile; /* protected by cmdbuf_mutex */
+	int num_cmd;
+
+	/* pm related */
+	int ved_needs_reset;
+
+	/* current ved decode context */
+	struct ipvr_context *ipvr_ctx;
+
+	struct page *mmu_recover_page;
+};
+
+struct drm_ipvr_file_private {
+	u32 ctx_id;
+};
+
+/* 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..e84cf9c
--- /dev/null
+++ b/drivers/gpu/drm/ipvr/ipvr_exec.c
@@ -0,0 +1,623 @@
+/**************************************************************************
+ * 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@intel.com>
+ *    Yao Cheng <yao.cheng@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 = NULL, *n = NULL;
+
+	if (unlikely(dev_priv == NULL)) {
+		return NULL;
+	}
+
+	spin_lock(&dev_priv->ipvr_ctx_lock);
+	list_for_each_entry_safe(pos, n, &dev_priv->ipvr_ctx_list, head) {
+		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:
+ * -ENOENT if context not found, or cmdbuf bo not found
+ * -EINVAL if referencing buffer fails, or executing cmdbuf fails
+ * -EINTR if fails to lock mutex
+ * -EBUSY if fails to get power well, or execution fails
+ * -ERESTARTSYS if reservating buffer fails
+ * -ENOMEM if execution fails
+ * -EFAULT if execution fails
+ * 0 if successful
+ */
+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);
+	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:
+ * -ENOENT if context not found, or cmdbuf bo not found
+ * -EINVAL if referencing buffer fails, or executing cmdbuf fails
+ * -EINTR if fails to lock mutex
+ * -EBUSY if fails to get power well, or execution fails
+ * -ERESTARTSYS if reservating buffer fails
+ * -ENOMEM if execution fails
+ * -EFAULT if execution fails
+ * 0 if successful
+ */
+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;
+
+	if (!context || !context->buffers) {
+		ret = -EINVAL;
+		return ret;
+	}
+
+	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);
+		return -EINVAL;
+	}
+
+	trace_ipvr_execbuffer(args);
+	ret = ipvr_gem_do_execbuffer(dev, file_priv, args,
+				    &dev_priv->addr_space);
+	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@intel.com>
+ *    Yao Cheng <yao.cheng@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..d18a602
--- /dev/null
+++ b/drivers/gpu/drm/ipvr/ipvr_fence.c
@@ -0,0 +1,490 @@
+/**************************************************************************
+ * 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@intel.com>
+ *    Yao Cheng <yao.cheng@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 0 on success, -ENOMEM on failure.
+ */
+int
+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 = kmalloc(sizeof(struct ipvr_fence), GFP_KERNEL);
+	if ((*fence) == NULL) {
+		return -ENOMEM;
+	}
+	if (IS_ERR((*fence)->file)) {
+		kfree(*fence);
+		IPVR_ERROR("ALARM!!! anon_inode_getfile call failed\n");
+		return -ENOMEM;
+	}
+
+	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;
+	dev_priv->fence_drv.sync_seq += ved_priv->num_cmd;
+	(*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);
+	return 0;
+}
+
+/**
+ * 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);
+
+	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..501d6b55
--- /dev/null
+++ b/drivers/gpu/drm/ipvr/ipvr_fence.h
@@ -0,0 +1,74 @@
+/**************************************************************************
+ * 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@intel.com>
+ *    Yao Cheng <yao.cheng@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;
+	/* fields for usrfence */
+	struct file *file;
+	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);
+
+int ipvr_fence_create(struct drm_ipvr_private *dev_priv, struct ipvr_fence **fence);
+
+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..4536dd7
--- /dev/null
+++ b/drivers/gpu/drm/ipvr/ipvr_gem.c
@@ -0,0 +1,341 @@
+/**************************************************************************
+ * 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@intel.com>
+ *    Yao Cheng <yao.cheng@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 ipvr_context *ipvr_ctx  = NULL;
+	unsigned long irq_flags;
+	int ctx_id, ret = 0;
+
+	IPVR_DEBUG_ENTRY("enter\n");
+	/* add video decode context */
+	ipvr_ctx = kzalloc(sizeof(struct ipvr_context), GFP_KERNEL);
+	if (ipvr_ctx  == NULL)
+		return -ENOMEM;
+
+	ctx_id = idr_alloc(&dev_priv->ipvr_ctx_idr, ipvr_ctx ,
+			   IPVR_MIN_CONTEXT_ID, IPVR_MAX_CONTEXT_ID,
+			   GFP_KERNEL);
+	if (ctx_id < 0)
+		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;
+	spin_lock_irqsave(&dev_priv->ipvr_ctx_lock, irq_flags);
+	list_add(&ipvr_ctx ->head, &dev_priv->ipvr_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);
+	/*
+	 * 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_ctx->tiling_scheme = args->tiling_scheme;
+		ipvr_ctx->tiling_stride = args->tiling_stride;
+	} else {
+		IPVR_DEBUG_WARN("unsupported tiling scheme %d and stide %d.\n",
+			args->tiling_scheme, args->tiling_stride);
+		ret = -EINVAL;
+	}
+
+	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 drm_ipvr_private *dev_priv = dev->dev_private;
+	struct drm_ipvr_file_private *fpriv = file_priv->driver_priv;
+	struct ved_private *ved_priv = dev_priv->ved_private;
+	struct ipvr_context *ipvr_ctx  = NULL;
+	unsigned long irq_flags;
+
+	IPVR_DEBUG_ENTRY("enter\n");
+	ipvr_ctx = (struct ipvr_context *)
+			idr_find(&dev_priv->ipvr_ctx_idr, args->ctx_id);
+	if (!ipvr_ctx  || (ipvr_ctx->ipvr_fpriv != file_priv->driver_priv)) {
+		return -ENOENT;
+	}
+
+	/**
+	 * fixme: remove this work-around (WA the issue that calling
+	 * ctx_destroy_ioctl with queued cmd might cause state machine issue).
+	 * we should wait for only the cmds sent from this context instead of
+	 * all cmds
+	 */
+	ipvr_fence_wait_empty_locked(dev_priv);
+
+	IPVR_DEBUG_PM("Video:remove context type 0x%x\n", ipvr_ctx->ctx_type);
+	mutex_lock(&ved_priv->ved_mutex);
+	if (ved_priv->ipvr_ctx == ipvr_ctx )
+		ved_priv->ipvr_ctx = NULL;
+	mutex_unlock(&ved_priv->ved_mutex);
+
+	spin_lock_irqsave(&dev_priv->ipvr_ctx_lock, irq_flags);
+	list_del(&ipvr_ctx->head);
+	fpriv->ctx_id = IPVR_CONTEXT_INVALID_ID;
+	spin_unlock_irqrestore(&dev_priv->ipvr_ctx_lock, irq_flags);
+
+	idr_remove(&dev_priv->ipvr_ctx_idr, ipvr_ctx->ctx_id);
+
+	kfree(ipvr_ctx);
+	return 0;
+}
+
+int
+ipvr_misc_ioctl(struct drm_device *dev, void *data,
+			struct drm_file *file_priv)
+{
+	struct drm_ipvr_private *dev_priv = dev->dev_private;
+	struct drm_ipvr_misc *args = data;
+	int ret = 0;
+	u64 value;
+
+	IPVR_DEBUG_ENTRY("enter\n");
+	if (!dev_priv) {
+		IPVR_DEBUG_WARN("called with no initialization.\n");
+		return -EINVAL;
+	}
+	switch (args->key) {
+	case IPVR_DEVICE_INFO: {
+		/* only vlv supported now
+		 */
+		u32 device_info = VLV_IPVR_DEV_ID << 16;
+		ret = copy_to_user((void __user *)((unsigned long)args->value),
+			&device_info, sizeof(device_info));
+		break;
+	}
+	case IPVR_UPDATE_TILING: {
+		struct drm_ipvr_update_tiling tiling;
+		struct ipvr_context *ipvr_ctx  = NULL;
+		ret = copy_from_user(&tiling,
+				(void __user *)((unsigned long)args->arg),
+				sizeof(tiling));
+		if (ret)
+			break;
+
+		ipvr_ctx  = (struct ipvr_context *)
+			idr_find(&dev_priv->ipvr_ctx_idr, tiling.ctx_id);
+		if (!ipvr_ctx ||
+			(ipvr_ctx->ipvr_fpriv != file_priv->driver_priv)) {
+			IPVR_DEBUG_WARN("fail to find ctx %d", tiling.ctx_id);
+			return -ENOENT;
+		}
+		IPVR_DEBUG_GENERAL("Video: update video tiling for ctx %d, "
+			"old tiling scheme is %d, old tiling stride is %d, "
+			"new tiling scheme is %d, new tiling stride is %d.\n",
+			tiling.ctx_id,
+			ipvr_ctx ->tiling_scheme, ipvr_ctx ->tiling_stride,
+			tiling.tiling_scheme, tiling.tiling_stride);
+		if ((tiling.tiling_scheme == 0 && tiling.tiling_stride <= 3) ||
+		(tiling.tiling_scheme == 1 && tiling.tiling_stride <= 2)) {
+			ipvr_ctx ->tiling_scheme = tiling.tiling_scheme;
+			ipvr_ctx ->tiling_stride = tiling.tiling_stride;
+		} else {
+			IPVR_ERROR("unsupported tile scheme: %d, stide: %d.\n",
+				tiling.tiling_scheme, tiling.tiling_stride);
+			ret = -EINVAL;
+		}
+		break;
+	}
+	default:
+		if (copy_from_user(&value,
+				(void __user *)((unsigned long)args->value),
+				sizeof(value))) {
+			IPVR_DEBUG_WARN("copy_from_user failed\n");
+			return -EFAULT;
+		}
+		if (copy_to_user((void __user *)((unsigned long)args->value),
+				&value, sizeof(value))) {
+			IPVR_DEBUG_WARN("copy_to_user failed\n");
+			return -EFAULT;
+		}
+		ret = -EFAULT;
+		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;
+	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);
+		return ret;
+	}
+	args->offset = drm_vma_node_offset_addr(&obj->base.vma_node);
+	return 0;
+}
diff --git a/drivers/gpu/drm/ipvr/ipvr_gem.h b/drivers/gpu/drm/ipvr/ipvr_gem.h
new file mode 100644
index 0000000..71ca172
--- /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@intel.com>
+ *    Yao Cheng <yao.cheng@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_misc_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@intel.com>
+ *    Yao Cheng <yao.cheng@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@anholt.net>
+ *    Fei Jiang <fei.jiang@intel.com>
+ *    Yao Cheng <yao.cheng@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@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..db08c82
--- /dev/null
+++ b/drivers/gpu/drm/ipvr/ipvr_trace.h
@@ -0,0 +1,326 @@
+/**************************************************************************
+ * 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@intel.com>
+ *    Yao Cheng <yao.cheng@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 cmd_id, u32 seq),
+	TP_ARGS(cmd_id, seq),
+	TP_STRUCT__entry(
+		__field(u32, cmd_id)
+		__field(u32, seq)
+	),
+	TP_fast_assign(
+		__entry->cmd_id = cmd_id;
+		__entry->seq = seq;
+	),
+	TP_printk("cmd_id=0x%08x, seq=0x%08x",
+		__entry->cmd_id, __entry->seq)
+);
+
+TRACE_EVENT(ved_cmd_copy,
+	TP_PROTO(u32 cmd_id, u32 seq),
+	TP_ARGS(cmd_id, seq),
+	TP_STRUCT__entry(
+		__field(u32, cmd_id)
+		__field(u32, seq)
+	),
+	TP_fast_assign(
+		__entry->cmd_id = cmd_id;
+		__entry->seq = seq;
+	),
+	TP_printk("cmd_id=0x%08x, seq=0x%08x",
+		__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 fw_completed_msg *completed_msg),
+	TP_ARGS(completed_msg),
+	TP_STRUCT__entry(
+		__field(u16, seqno)
+		__field(u32, flags)
+		__field(u32, vdebcr)
+		__field(u16, start_mb)
+		__field(u16, last_mb)
+	),
+	TP_fast_assign(
+		__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("seq=0x%04x, flags=0x%08x, vdebcr=0x%08x, mb=[%u, %u]",
+		__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..78c1f1e
--- /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@intel.com>
+ *    Yao Cheng <yao.cheng@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(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 -EINVAL;
+	}
+
+	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 = -EINVAL;
+	}
+
+	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 %lx cur_cmd_size = %d"
+			       " cur_cmd_id = %02x fence = %08x\n",
+			       (unsigned long)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;
+		if (((sequence++) & 0xf) == 0xf) {
+			ret = -EINVAL;
+			IPVR_DEBUG_WARN("VED: too many cmds, abort.\n");
+			goto out;
+		}
+	}
+
+	ved_priv->num_cmd = ((--sequence) & 0xf);
+
+	ipvr_fence_create(ved_priv->dev_priv, &fence);
+
+	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->ipvr_ctx->tiling_scheme,
+					ved_priv->ipvr_ctx->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->ipvr_ctx->tiling_scheme;
+	ved_cmd->tiling_stride = ved_priv->ipvr_ctx->tiling_stride;
+	ved_cmd->tfile =
+		ved_priv->tfile;
+	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(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);
+
+	ved_priv->ipvr_ctx = ipvr_ctx;
+
+	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_VED("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);
+	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;
+	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);
+
+	trace_ved_irq_completed(completed_msg);
+
+	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);
+	if (unlikely(ipvr_ctx == NULL)) {
+		IPVR_DEBUG_WARN("abnormal complete msg.\n");
+		return -EINVAL;
+	}
+
+	if (flags & FW_VA_RENDER_HOST_INT) {
+		/* Now send the next command from the msvdx cmd queue */
+		ved_cmd_dequeue_send(ved_priv);
+	}
+	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_MASK,
+			     MSVDX_MMU_CONTROL0_OFFSET);
+		wmb();
+
+		/* Clear this interupt bit only */
+		IPVR_REG_WRITE32(MSVDX_INTERRUPT_STATUS_MMU_FAULT_IRQ_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..cf932ed
--- /dev/null
+++ b/drivers/gpu/drm/ipvr/ved_cmd.h
@@ -0,0 +1,71 @@
+/**************************************************************************
+ * 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@intel.com>
+ *    Yao Cheng <yao.cheng@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 drm_file *tfile;
+	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@intel.com>
+ *    Yao Cheng <yao.cheng@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_IRQ_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_MASK,
+				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_MASK,
+			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@intel.com>
+ *    Yao Cheng <yao.cheng@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@intel.com>
+ *    Li Zeng <li.zeng@intel.com>
+ *    Yao Cheng <yao.cheng@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..7402f56
--- /dev/null
+++ b/drivers/gpu/drm/ipvr/ved_pm.c
@@ -0,0 +1,332 @@
+/**************************************************************************
+ * 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@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 (!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;
+		}
+	}
+
+	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@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@intel.com>
+ *    Yao Cheng <yao.cheng@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_MASK 		| \
+	MSVDX_MAN_CLK_ENABLE_VDEB_ACCESS_MAN_CLK_ENABLE_MASK 		| \
+	MSVDX_MAN_CLK_ENABLE_VDMC_MAN_CLK_ENABLE_MASK	 		| \
+	MSVDX_MAN_CLK_ENABLE_VEC_ENTDEC_MAN_CLK_ENABLE_MASK 		| \
+	MSVDX_MAN_CLK_ENABLE_VEC_ITRANS_MAN_CLK_ENABLE_MASK 		| \
+	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_MASK		| \
+	MSVDX_MAN_CLK_ENABLE_VDMC_AUTO_CLK_ENABLE_MASK			| \
+	MSVDX_MAN_CLK_ENABLE_VEC_ENTDEC_AUTO_CLK_ENABLE_MASK		| \
+	MSVDX_MAN_CLK_ENABLE_VEC_ITRANS_AUTO_CLK_ENABLE_MASK		| \
+	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

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* RE: [RFC PATCH v3 2/4] drm/ipvr: drm driver for VED
  2014-11-21 19:06 ` [RFC PATCH v3 2/4] drm/ipvr: drm driver " Yao Cheng
@ 2014-11-23 13:29   ` Cheng, Yao
  2014-11-26 16:50   ` Cheng, Yao
  2014-11-27 11:49   ` Cheng, Yao
  2 siblings, 0 replies; 10+ messages in thread
From: Cheng, Yao @ 2014-11-23 13:29 UTC (permalink / raw)
  To: intel-gfx, dri-devel, daniel.vetter, Kelley, Sean V, Chehab, John
  Cc: emil.l.velikov, Jiang, Fei

> -----Original Message-----
> From: Cheng, Yao
> Sent: Saturday, November 22, 2014 3:07
> To: intel-gfx@lists.freedesktop.org; dri-devel@lists.freedesktop.org;
> daniel.vetter@ffwll.ch; Kelley, Sean V; Chehab, John
> Cc: Jiang, Fei; dh.herrmann@gmail.com; jani.nikula@linux.intel.com;
> emil.l.velikov@gmail.com; ville.syrjala@linux.intel.com;
> jbarnes@virtuousgeek.org; daniel@fooishbar.org; Cheng, Yao
> Subject: [RFC PATCH v3 2/4] drm/ipvr: drm driver for VED
> 
> +
> +int ipvr_gem_mmap_offset_ioctl(struct drm_device *dev,
> +				void *data, struct drm_file *file_priv)
> +{
> +	int ret;
> +	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);
> +		return ret;
> +	}
> +	args->offset = drm_vma_node_offset_addr(&obj->base.vma_node);
> +	return 0;
> +}

I missed an unreferenced here.
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 10+ messages in thread

* RE: [RFC PATCH v3 2/4] drm/ipvr: drm driver for VED
  2014-11-21 19:06 ` [RFC PATCH v3 2/4] drm/ipvr: drm driver " Yao Cheng
  2014-11-23 13:29   ` Cheng, Yao
@ 2014-11-26 16:50   ` Cheng, Yao
  2014-11-27 11:49   ` Cheng, Yao
  2 siblings, 0 replies; 10+ messages in thread
From: Cheng, Yao @ 2014-11-26 16:50 UTC (permalink / raw)
  To: intel-gfx, dri-devel, daniel.vetter, Kelley, Sean V, Chehab, John
  Cc: emil.l.velikov, Jiang, Fei

> -----Original Message-----
> From: Cheng, Yao
> Sent: Saturday, November 22, 2014 3:07
> To: intel-gfx@lists.freedesktop.org; dri-devel@lists.freedesktop.org;
> daniel.vetter@ffwll.ch; Kelley, Sean V; Chehab, John
> Cc: Jiang, Fei; dh.herrmann@gmail.com; jani.nikula@linux.intel.com;
> emil.l.velikov@gmail.com; ville.syrjala@linux.intel.com;
> jbarnes@virtuousgeek.org; daniel@fooishbar.org; Cheng, Yao
> Subject: [RFC PATCH v3 2/4] drm/ipvr: drm driver for VED
> 
> +static void
> +ipvr_drm_preclose(struct drm_device *dev, struct drm_file *file_priv)
> +{
> +	/* if user didn't destory ctx explicitly, remove ctx here */
> +	struct drm_ipvr_private *dev_priv;
> +	struct drm_ipvr_file_private *ipvr_fpriv;
> +	struct ved_private *ved_priv;
> +	struct ipvr_context *ipvr_ctx  = 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;
> +
> +	if (ipvr_fpriv->ctx_id == IPVR_CONTEXT_INVALID_ID)
> +		return;
> +	ipvr_ctx = (struct ipvr_context *)
> +			idr_find(&dev_priv->ipvr_ctx_idr, ipvr_fpriv->ctx_id);

Need protection on ipvr_ctx_idr. Same to the other idr related code.

> +	if (!ipvr_ctx  || (ipvr_ctx->ipvr_fpriv != ipvr_fpriv)) {
> +		IPVR_DEBUG_GENERAL("ctx for id %d has already
> destroyed\n",
> +				ipvr_fpriv->ctx_id);
> +		return;
> +	}
> +
> +	/**
> +	 * fixme: remove this work-around (WA the issue that calling
> +	 * close() with queued cmd might cause state machine issue).
> +	 * we should wait for only the cmds sent from contexts in this file
> +	 * instead of all cmds
> +	 */
> +	ipvr_fence_wait_empty_locked(dev_priv);
> +
> +	IPVR_DEBUG_PM("Video:remove context type 0x%x\n", ipvr_ctx-
> >ctx_type);
> +	mutex_lock(&ved_priv->ved_mutex);
> +	if (ved_priv->ipvr_ctx == ipvr_ctx )
> +		ved_priv->ipvr_ctx = NULL;
> +	mutex_unlock(&ved_priv->ved_mutex);
> +
> +	spin_lock_irqsave(&dev_priv->ipvr_ctx_lock, irq_flags);
> +	list_del(&ipvr_ctx->head);
> +	ipvr_fpriv->ctx_id = IPVR_CONTEXT_INVALID_ID;
> +	spin_unlock_irqrestore(&dev_priv->ipvr_ctx_lock, irq_flags);
> +
> +	idr_remove(&dev_priv->ipvr_ctx_idr, ipvr_ctx->ctx_id);
> +
> +	kfree(ipvr_ctx );
> +	kfree(ipvr_fpriv);
> +}


_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC PATCH v3 2/4] drm/ipvr: drm driver for VED
  2014-11-21 19:06 ` [RFC PATCH v3 2/4] drm/ipvr: drm driver " Yao Cheng
  2014-11-23 13:29   ` Cheng, Yao
  2014-11-26 16:50   ` Cheng, Yao
@ 2014-11-27 11:49   ` Cheng, Yao
  2014-12-01  3:09     ` Cheng, Yao
  2 siblings, 1 reply; 10+ messages in thread
From: Cheng, Yao @ 2014-11-27 11:49 UTC (permalink / raw)
  To: intel-gfx, dri-devel, daniel.vetter, Kelley, Sean V, Chehab, John
  Cc: emil.l.velikov, Jiang, Fei, dh.herrmann, daniel

> -----Original Message-----
> From: Cheng, Yao
> Sent: Saturday, November 22, 2014 3:07
> To: intel-gfx@lists.freedesktop.org; dri-devel@lists.freedesktop.org;
> daniel.vetter@ffwll.ch; Kelley, Sean V; Chehab, John
> Cc: Jiang, Fei; dh.herrmann@gmail.com; jani.nikula@linux.intel.com;
> emil.l.velikov@gmail.com; ville.syrjala@linux.intel.com;
> jbarnes@virtuousgeek.org; daniel@fooishbar.org; Cheng, Yao
> Subject: [RFC PATCH v3 2/4] drm/ipvr: drm driver for VED
> +typedef struct drm_ipvr_private {
> +	struct drm_device *dev;
> +	struct pci_dev *pci_root;
> +
> +	/* IMG video context */
> +	struct list_head ipvr_ctx_list;

The current design leads to ctx leak. There's no ctx_list for each file struct, so each create_context_ioctl causes one ctx leak.
Need to move the ctx_list from dev_private to file_private.

> +	spinlock_t ipvr_ctx_lock;
> +	struct idr ipvr_ctx_idr;
> +	struct ipvr_context default_ctx;
> +
> +	/* PM related */
> +	atomic_t pending_events;
> +
> +	/* exec related */
> +	struct ipvr_validate_context validate_ctx;
> +
> +	/* IMG MMU specific */
> +	struct ipvr_mmu_driver *mmu;
> +	/*struct ipvr_mmu_pd *pf_pd;*/
> +	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;
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC PATCH v3 1/4] drm/i915: add i915_ved.c to setup bridge for VED
  2014-11-21 19:06 ` [RFC PATCH v3 1/4] drm/i915: add i915_ved.c to setup bridge for VED Yao Cheng
@ 2014-11-28 16:59   ` Robert Beckett
  2014-12-01  3:04     ` Cheng, Yao
  0 siblings, 1 reply; 10+ messages in thread
From: Robert Beckett @ 2014-11-28 16:59 UTC (permalink / raw)
  To: Yao Cheng, intel-gfx, dri-devel, daniel.vetter, sean.v.kelley,
	john.chehab
  Cc: emil.l.velikov, fei.jiang, daniel, dh.herrmann

On 21/11/2014 19:06, Yao Cheng wrote:
> Setup minimum required resources during i915_driver_load:
> 1. Create a platform device to share MMIO/IRQ resources
> 2. Make the platform device child of i915 device for runtime PM.
> 3. Create IRQ chip to forward the VED irqs.
> VED driver (a standalone drm driver) probes the VED device and
> creates a new dri card on install.
> Currently only supports VED on valleyview.
> Kerneldoc is updated for i915_ved.c.
>
> v2:
> take Daniel & Jani's comments
> 	- extract change to new file i915_ved.c
> 	- add kerneldoc
> 	- change 'ipvr-ved' to 'ipvr-vlv-ved' for extensibility
> 	- unregister platdev before irq_free_desc
> 	- add WARN_ON(!intel_irqs_enabled) in irq init code
> 	- remove unnecessary trace point
> 	- remove unnecessary BUG_ON
>
> v3:
> take Ville's comments and VED PRIME support
> 	- add HAS_VED() check
> 	- add ved struct to make code neat
> 	- no need to check platform in vlv_irq_handler
> 	- i915_reg.h update
> 	- no need to kmalloc for small amount of resource
> 	- remove unnecessary REG resource
> 	- follow vlv_display_irqs_install() to implement VED mask/unmask
> 	- workaround nommu_map_sg issue by set dma_mask to support VED PRIME.
>
> Signed-off-by: Yao Cheng <yao.cheng@intel.com>
> ---
>   Documentation/DocBook/drm.tmpl  |   5 +
>   drivers/gpu/drm/i915/Makefile   |   3 +
>   drivers/gpu/drm/i915/i915_dma.c |  11 ++
>   drivers/gpu/drm/i915/i915_drv.h |  12 ++
>   drivers/gpu/drm/i915/i915_irq.c |   2 +
>   drivers/gpu/drm/i915/i915_reg.h |   4 +
>   drivers/gpu/drm/i915/i915_ved.c | 255 ++++++++++++++++++++++++++++++++++++++++
>   7 files changed, 292 insertions(+)
>   create mode 100644 drivers/gpu/drm/i915/i915_ved.c
>
> diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl
> index 9d99772..b2d109f 100644
> --- a/Documentation/DocBook/drm.tmpl
> +++ b/Documentation/DocBook/drm.tmpl
> @@ -3839,6 +3839,11 @@ int num_ioctls;</synopsis>
>   !Fdrivers/gpu/drm/i915/i915_irq.c intel_runtime_pm_disable_interrupts
>   !Fdrivers/gpu/drm/i915/i915_irq.c intel_runtime_pm_enable_interrupts
>         </sect2>
> +      <sect2>
> +        <title>VED video core integration</title>
> +!Pdrivers/gpu/drm/i915/i915_ved.c VED video core integration
> +!Idrivers/gpu/drm/i915/i915_ved.c
> +      </sect2>
>       </sect1>
>       <sect1>
>         <title>Display Hardware Handling</title>
> diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
> index 891e584..e2f2776 100644
> --- a/drivers/gpu/drm/i915/Makefile
> +++ b/drivers/gpu/drm/i915/Makefile
> @@ -83,6 +83,9 @@ i915-y += dvo_ch7017.o \
>   i915-y += i915_dma.o \
>   	  i915_ums.o
>
> +# VED for VLV
> +i915-y += i915_ved.o
> +
>   obj-$(CONFIG_DRM_I915)  += i915.o
>
>   CFLAGS_i915_trace_points.o := -I$(src)
> diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
> index 9a73533..fbf2144 100644
> --- a/drivers/gpu/drm/i915/i915_dma.c
> +++ b/drivers/gpu/drm/i915/i915_dma.c
> @@ -1791,6 +1791,13 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
>   	if (IS_GEN5(dev))
>   		intel_gpu_ips_init(dev_priv);
>
> +	if (HAS_VED(dev)) {
> +		ret = vlv_setup_ved(dev);
> +		if (ret < 0) {
> +			DRM_ERROR("failed to setup VED bridge: %d\n", ret);
> +		}
> +	}
> +
>   	intel_runtime_pm_enable(dev_priv);
>
>   	return 0;
> @@ -1833,6 +1840,10 @@ int i915_driver_unload(struct drm_device *dev)
>   	struct drm_i915_private *dev_priv = dev->dev_private;
>   	int ret;
>
> +	if (HAS_VED(dev)) {
> +		vlv_teardown_ved(dev);
> +	}
> +
>   	ret = i915_gem_suspend(dev);
>   	if (ret) {
>   		DRM_ERROR("failed to idle hardware: %d\n", ret);
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index f830596..6cfabac 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -1762,6 +1762,12 @@ struct drm_i915_private {
>
>   	uint32_t bios_vgacntr;
>
> +	/* necessary resource sharing with ved driver. */
> +	struct {
> +		struct platform_device *platdev;
> +		int	irq;
> +	} ved;
> +
>   	/* Old dri1 support infrastructure, beware the dragons ya fools entering
>   	 * here! */
>   	struct i915_dri1_state dri1;
> @@ -2257,6 +2263,7 @@ struct drm_i915_cmd_table {
>   				 IS_BROADWELL(dev) || IS_VALLEYVIEW(dev))
>   #define HAS_RC6(dev)		(INTEL_INFO(dev)->gen >= 6)
>   #define HAS_RC6p(dev)		(INTEL_INFO(dev)->gen == 6 || IS_IVYBRIDGE(dev))
> +#define HAS_VED(dev)		(INTEL_INFO(dev)->is_valleyview && IS_GEN7(dev))
>
>   #define INTEL_PCH_DEVICE_ID_MASK		0xff00
>   #define INTEL_PCH_IBX_DEVICE_ID_TYPE		0x3b00
> @@ -2851,6 +2858,11 @@ void i915_restore_display_reg(struct drm_device *dev);
>   void i915_setup_sysfs(struct drm_device *dev_priv);
>   void i915_teardown_sysfs(struct drm_device *dev_priv);
>
> +/* i915_ved.c */
> +int vlv_setup_ved(struct drm_device *dev);
> +void vlv_teardown_ved(struct drm_device *dev);
> +void vlv_ved_irq_handler(struct drm_device *dev);
> +
>   /* intel_i2c.c */
>   extern int intel_setup_gmbus(struct drm_device *dev);
>   extern void intel_teardown_gmbus(struct drm_device *dev);
> diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
> index 5fff287..a3394de 100644
> --- a/drivers/gpu/drm/i915/i915_irq.c
> +++ b/drivers/gpu/drm/i915/i915_irq.c
> @@ -1865,6 +1865,8 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
>   			snb_gt_irq_handler(dev, dev_priv, gt_iir);
>   		if (pm_iir)
>   			gen6_rps_irq_handler(dev_priv, pm_iir);
> +		if (iir & VLV_VED_BLOCK_INTERRUPT)
> +			vlv_ved_irq_handler(dev);
>   		/* Call regardless, as some status bits might not be
>   		 * signalled in iir */
>   		valleyview_pipestat_irq_handler(dev, iir);
> diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
> index d43fa0e..1a46fe5 100644
> --- a/drivers/gpu/drm/i915/i915_reg.h
> +++ b/drivers/gpu/drm/i915/i915_reg.h
> @@ -1284,6 +1284,9 @@ enum punit_power_well {
>   #define VLV_DISPLAY_BASE 0x180000
>   #define VLV_MIPI_BASE VLV_DISPLAY_BASE
>
> +#define VLV_VED_BASE 0x170000
> +#define VLV_VED_SIZE 0x010000
> +
>   #define VLV_GU_CTL0	(VLV_DISPLAY_BASE + 0x2030)
>   #define VLV_GU_CTL1	(VLV_DISPLAY_BASE + 0x2034)
>   #define SCPD0		0x0209c /* 915+ only */
> @@ -1477,6 +1480,7 @@ enum punit_power_well {
>   #define ILK_BSD_USER_INTERRUPT				(1<<5)
>
>   #define I915_PM_INTERRUPT				(1<<31)
> +#define VLV_VED_BLOCK_INTERRUPT			(1<<23)
>   #define I915_ISP_INTERRUPT				(1<<22)
>   #define I915_LPE_PIPE_B_INTERRUPT			(1<<21)
>   #define I915_LPE_PIPE_A_INTERRUPT			(1<<20)
> diff --git a/drivers/gpu/drm/i915/i915_ved.c b/drivers/gpu/drm/i915/i915_ved.c
> new file mode 100644
> index 0000000..982e69e
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/i915_ved.c
> @@ -0,0 +1,255 @@
> +/*
> + * Copyright © 2014 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> + * IN THE SOFTWARE.
> + *
> + * Authors:
> + *    Yao Cheng <yao.cheng@intel.com>
> + *
> + */
> +
> +#include "i915_drv.h"
> +
> +/**
> + * DOC: VED video core integration
> + *
> + * Motivation:
> + * Some platforms (e.g. valleyview) integrates a VED inside GPU to extend the
> + * video decoding capability.
> + * The VED is driven by the standalone drm driver "ipvr" which covers PowerVR
> + * VPUs. Since the PowerVR VPUs are also integrated by non-i915 platforms such
> + * as GMA500, we'd like to keep ipvr driver and i915 driver separated and
> + * independent to each other. To achieve this we do the minimum work in i915
> + * to setup a bridge between ipvr and i915:
> + * 1. Create a platform device to share MMIO/IRQ resources
> + * 2. Make the platform device child of i915 device for runtime PM.
> + * 3. Create IRQ chip to forward the VED irqs.
> + * ipvr driver probes the VED device and creates a new dri card on install.
> + *
> + * Threats:
> + * Due to the restriction in Linux platform device model, user need manually
> + * uninstall ipvr driver before uninstalling i915 module, otherwise he might
> + * run into use-after-free issues after i915 removes the platform device.

Can you go in to more detail on what you consider to be the restriction 
in the platform device model?

When removing the device via platform_device_unregister, it will call 
the remove callback of any drivers handling this device (via the bus 
remove function). It is then up to the driver to ensure no further usage 
of the device from which it is being removed. This usually involves 
removing all user input vectors, disabling interrupts involved and 
flushing/canceling any delayed work. This should prevent any further use 
of the device by the driver.

The driver's remove function is called in a direct call chain from 
platform_device_unregister, so by the time it returns, there should be 
no further chance of accesses.

> + *
> + * Implementation:
> + * The MMIO/REG platform resources are created according to the registers
> + * specification.
> + * When forwarding VED irqs, the flow control handler selection depends on the
> + * platform, for example on valleyview handle_simple_irq is enough.
> + *
> + */
> +
> +static struct platform_device* vlv_ved_platdev_create(struct drm_device *dev)
> +{
> +	int ret;
> +	struct resource rsc[2] = { {0}, {0} };
> +	struct platform_device *platdev;
> +	u64 *dma_mask = NULL;
> +	struct drm_i915_private *dev_priv = dev->dev_private;
> +
> +	if (dev_priv->ved.irq < 0)
> +		return ERR_PTR(-EINVAL);
> +
> +	platdev = platform_device_alloc("ipvr-ved-vlv", -1);
> +	if (!platdev) {
> +		ret = -ENOMEM;
> +		DRM_ERROR("Failed to allocate VED platform device\n");
> +		goto err;
> +	}
> +
> +	/* to work-around check_addr in nommu_map_sg() */
> +	dma_mask = kmalloc(sizeof(*platdev->dev.dma_mask), GFP_KERNEL);
> +	if (!dma_mask) {
> +		ret = -ENOMEM;
> +		DRM_ERROR("Failed to allocate dma_mask\n");
> +		goto err_put_dev;
> +	}
> +	*dma_mask = DMA_BIT_MASK(31);
> +	platdev->dev.dma_mask = dma_mask;
> +	platdev->dev.coherent_dma_mask = *dma_mask;
> +
> +	rsc[0].start    = rsc[0].end = dev_priv->ved.irq;
> +	rsc[0].flags    = IORESOURCE_IRQ;
> +	rsc[0].name     = "ipvr-ved-vlv-irq";
> +
> +	rsc[1].start    = pci_resource_start(dev->pdev, 0) + VLV_VED_BASE;
> +	rsc[1].end      = pci_resource_start(dev->pdev, 0) + VLV_VED_BASE + VLV_VED_SIZE;
> +	rsc[1].flags    = IORESOURCE_MEM;
> +	rsc[1].name     = "ipvr-ved-vlv-mmio";
> +
> +	ret = platform_device_add_resources(platdev, rsc, 2);
> +	if (ret) {
> +		DRM_ERROR("Failed to add resource for VED platform device: %d\n", ret);
> +		goto err_put_dev;
> +	}
> +
> +	platdev->dev.parent = dev->dev; /* for VED driver's runtime-PM */
> +	ret = platform_device_add(platdev);
> +	if (ret) {
> +		DRM_ERROR("Failed to add VED platform device: %d\n", ret);
> +		goto err_put_dev;
> +	}
> +
> +	return platdev;
> +err_put_dev:
> +	platform_device_put(platdev);
> +err:
> +	if (dma_mask)
> +		kfree(dma_mask);
> +	return ERR_PTR(ret);
> +}
> +
> +static void vlv_ved_platdev_destroy(struct drm_device *dev)
> +{
> +	struct drm_i915_private *dev_priv = dev->dev_private;
> +	if (dev_priv->ved.platdev) {
> +		kfree(dev_priv->ved.platdev->dev.dma_mask);
> +		platform_device_unregister(dev_priv->ved.platdev);
> +	}
> +}
> +
> +static void vlv_ved_irq_unmask(struct irq_data *d)
> +{
> +	struct drm_device *dev = d->chip_data;
> +	struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;
> +	unsigned long irqflags;
> +	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
> +
> +	dev_priv->irq_mask &= ~VLV_VED_BLOCK_INTERRUPT;
> +	I915_WRITE(VLV_IIR, VLV_VED_BLOCK_INTERRUPT);
> +	I915_WRITE(VLV_IIR, VLV_VED_BLOCK_INTERRUPT);
> +	I915_WRITE(VLV_IMR, dev_priv->irq_mask);
> +	I915_WRITE(VLV_IER, ~dev_priv->irq_mask);
> +	POSTING_READ(VLV_IER);
> +
> +	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
> +}
> +
> +static void vlv_ved_irq_mask(struct irq_data *d)
> +{
> +	struct drm_device *dev = d->chip_data;
> +	struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;
> +	unsigned long irqflags;
> +	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
> +
> +	dev_priv->irq_mask |= VLV_VED_BLOCK_INTERRUPT;
> +	I915_WRITE(VLV_IER, ~dev_priv->irq_mask);
> +	I915_WRITE(VLV_IMR, dev_priv->irq_mask);
> +	I915_WRITE(VLV_IIR, VLV_VED_BLOCK_INTERRUPT);
> +	I915_WRITE(VLV_IIR, VLV_VED_BLOCK_INTERRUPT);
> +	POSTING_READ(VLV_IIR);
> +
> +	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
> +}
> +
> +static struct irq_chip vlv_ved_irqchip = {
> +	.name = "ipvr_ved_irqchip",
> +	.irq_mask = vlv_ved_irq_mask,
> +	.irq_unmask = vlv_ved_irq_unmask,
> +};
> +
> +static int vlv_ved_irq_init(struct drm_device *dev, int irq)
> +{
> +	struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;
> +	WARN_ON(!intel_irqs_enabled(dev_priv));
> +	irq_set_chip_and_handler_name(irq,
> +		&vlv_ved_irqchip,
> +		handle_simple_irq,
> +		"ipvr_ved_vlv_irq_handler");
> +	return irq_set_chip_data(irq, dev);
> +}
> +
> +/**
> + * vlv_ved_irq_handler() - forwards the VED irq
> + * @dev: the i915 drm device
> + *
> + * the VED irq is forwarded to the irq handler registered by VED driver.
> + */
> +void vlv_ved_irq_handler(struct drm_device *dev)
> +{
> +	int ret;
> +	struct drm_i915_private *dev_priv = dev->dev_private;
> +	if (dev_priv->ved.irq < 0 && printk_ratelimit()) {
> +		DRM_ERROR("invalid ved irq number: %d\n", dev_priv->ved.irq);
> +		return;
> +	}
> +	ret = generic_handle_irq(dev_priv->ved.irq);
> +	if (ret && printk_ratelimit()) {
> +		DRM_ERROR("error handling vlv ved irq: %d\n", ret);
> +	}
> +}
> +
> +/**
> + * vlv_setup_ved() - setup the bridge between VED driver and i915
> + * @dev: the i915 drm device
> + *
> + * set up the minimum required resources for the bridge: irq chip, platform
> + * resource and platform device. i915 device is set as parent of the new
> + * platform device.
> + *
> + * Return: 0 if successful. non-zero if allocation/initialization fails
> + */
> +int vlv_setup_ved(struct drm_device *dev)
> +{
> +	int ret;
> +	struct drm_i915_private *dev_priv = dev->dev_private;
> +
> +	dev_priv->ved.irq = irq_alloc_descs(-1, 0, 1, 0);
> +	if (dev_priv->ved.irq < 0) {
> +		DRM_ERROR("Failed to allocate IRQ desc: %d\n", dev_priv->ved.irq);
> +		ret = dev_priv->ved.irq;
> +		goto err;
> +	}
> +
> +	ret = vlv_ved_irq_init(dev, dev_priv->ved.irq);
> +	if (ret) {
> +		DRM_ERROR("Failed to initialize irqchip for vlv-ved: %d\n", ret);
> +		goto err_free_irq;
> +	}
> +
> +	dev_priv->ved.platdev = vlv_ved_platdev_create(dev);
> +	if (IS_ERR(dev_priv->ved.platdev)) {
> +		ret = PTR_ERR(dev_priv->ved.platdev);
> +		DRM_ERROR("Failed to create platform device for vlv-ved: %d\n", ret);
> +		goto err_free_irq;
> +	}
> +
> +	return 0;
> +err_free_irq:
> +	irq_free_desc(dev_priv->ved.irq);
> +err:
> +	dev_priv->ved.irq = -1;
> +	dev_priv->ved.platdev = NULL;
> +	return ret;
> +}
> +
> +/**
> + * vlv_teardown_ved() - destroy the bridge between VED driver and i915
> + * @dev: the i915 drm device
> + *
> + * release all the resources for VED <-> i915 bridge.
> + */
> +void vlv_teardown_ved(struct drm_device *dev)
> +{
> +	struct drm_i915_private *dev_priv = dev->dev_private;

you may want to mask the i915 interrupt for the VED block before 
removing the device.

> +	vlv_ved_platdev_destroy(dev);
> +	if (dev_priv->ved.irq >= 0)
> +		irq_free_desc(dev_priv->ved.irq);
> +}
>


Generally it is a nicely interfaced child device.


_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC PATCH v3 1/4] drm/i915: add i915_ved.c to setup bridge for VED
  2014-11-28 16:59   ` Robert Beckett
@ 2014-12-01  3:04     ` Cheng, Yao
  2014-12-01  8:32       ` [Intel-gfx] " Daniel Vetter
  0 siblings, 1 reply; 10+ messages in thread
From: Cheng, Yao @ 2014-12-01  3:04 UTC (permalink / raw)
  To: Beckett, Robert, intel-gfx, dri-devel, daniel.vetter, Kelley,
	Sean V, Chehab, John, Barbalho, Rafael
  Cc: emil.l.velikov, Jiang, Fei, daniel, dh.herrmann

> -----Original Message-----
> From: Beckett, Robert
> Sent: Saturday, November 29, 2014 0:59
> To: Cheng, Yao; intel-gfx@lists.freedesktop.org; dri-
> devel@lists.freedesktop.org; daniel.vetter@ffwll.ch; Kelley, Sean V; Chehab,
> John
> Cc: emil.l.velikov@gmail.com; Jiang, Fei; dh.herrmann@gmail.com;
> daniel@fooishbar.org
> Subject: Re: [Intel-gfx] [RFC PATCH v3 1/4] drm/i915: add i915_ved.c to setup
> bridge for VED
> > + * Threats:
> > + * Due to the restriction in Linux platform device model, user need
> > +manually
> > + * uninstall ipvr driver before uninstalling i915 module, otherwise
> > +he might
> > + * run into use-after-free issues after i915 removes the platform device.
> 
> Can you go in to more detail on what you consider to be the restriction in the
> platform device model?
> 
> When removing the device via platform_device_unregister, it will call the
> remove callback of any drivers handling this device (via the bus remove
> function). It is then up to the driver to ensure no further usage of the device
> from which it is being removed. This usually involves removing all user input
> vectors, disabling interrupts involved and flushing/canceling any delayed
> work. This should prevent any further use of the device by the driver.
> 
> The driver's remove function is called in a direct call chain from
> platform_device_unregister, so by the time it returns, there should be no
> further chance of accesses.
>

Bob, thx for your review comments.
The symptom is, after "rmmod i915", though drm_drv_release() is also called on the child device "ipvr", I still see the module exist in the system (check it by "lsmod"). This causes issue when I modprobe i915 and ipvr again later. Actually I don't understand why this restriction exists, but accroding to Daniel, grabbing a module refcount for the platform device doesn't work (it would pin the module forever).
 
> > +void vlv_teardown_ved(struct drm_device *dev) {
> > +	struct drm_i915_private *dev_priv = dev->dev_private;
> 
> you may want to mask the i915 interrupt for the VED block before removing
> the device.
> 

Thx, will add it.

> > +	vlv_ved_platdev_destroy(dev);
> > +	if (dev_priv->ved.irq >= 0)
> > +		irq_free_desc(dev_priv->ved.irq);
> > +}
> >
> 
> 
> Generally it is a nicely interfaced child device.
> 

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC PATCH v3 2/4] drm/ipvr: drm driver for VED
  2014-11-27 11:49   ` Cheng, Yao
@ 2014-12-01  3:09     ` Cheng, Yao
  0 siblings, 0 replies; 10+ messages in thread
From: Cheng, Yao @ 2014-12-01  3:09 UTC (permalink / raw)
  To: Cheng, Yao, intel-gfx, dri-devel, daniel.vetter, Kelley, Sean V,
	Chehab, John, Ewins, Jon, Beckett, Robert, Barbalho, Rafael
  Cc: emil.l.velikov, Jiang, Fei

Add Jon/Bob/Raf for detail review.
> -----Original Message-----
> From: dri-devel [mailto:dri-devel-bounces@lists.freedesktop.org] On Behalf
> Of Cheng, Yao
> Sent: Thursday, November 27, 2014 19:49
> To: intel-gfx@lists.freedesktop.org; dri-devel@lists.freedesktop.org;
> daniel.vetter@ffwll.ch; Kelley, Sean V; Chehab, John
> Cc: emil.l.velikov@gmail.com; Jiang, Fei
> Subject: RE: [RFC PATCH v3 2/4] drm/ipvr: drm driver for VED
> 
> > -----Original Message-----
> > From: Cheng, Yao
> > Sent: Saturday, November 22, 2014 3:07
> > To: intel-gfx@lists.freedesktop.org; dri-devel@lists.freedesktop.org;
> > daniel.vetter@ffwll.ch; Kelley, Sean V; Chehab, John
> > Cc: Jiang, Fei; dh.herrmann@gmail.com; jani.nikula@linux.intel.com;
> > emil.l.velikov@gmail.com; ville.syrjala@linux.intel.com;
> > jbarnes@virtuousgeek.org; daniel@fooishbar.org; Cheng, Yao
> > Subject: [RFC PATCH v3 2/4] drm/ipvr: drm driver for VED
> > +typedef struct drm_ipvr_private {
> > +	struct drm_device *dev;
> > +	struct pci_dev *pci_root;
> > +
> > +	/* IMG video context */
> > +	struct list_head ipvr_ctx_list;
> 
> The current design leads to ctx leak. There's no ctx_list for each file struct, so
> each create_context_ioctl causes one ctx leak.
> Need to move the ctx_list from dev_private to file_private.
> 
> > +	spinlock_t ipvr_ctx_lock;
> > +	struct idr ipvr_ctx_idr;
> > +	struct ipvr_context default_ctx;
> > +
> > +	/* PM related */
> > +	atomic_t pending_events;
> > +
> > +	/* exec related */
> > +	struct ipvr_validate_context validate_ctx;
> > +
> > +	/* IMG MMU specific */
> > +	struct ipvr_mmu_driver *mmu;
> > +	/*struct ipvr_mmu_pd *pf_pd;*/
> > +	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;
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Intel-gfx] [RFC PATCH v3 1/4] drm/i915: add i915_ved.c to setup bridge for VED
  2014-12-01  3:04     ` Cheng, Yao
@ 2014-12-01  8:32       ` Daniel Vetter
  0 siblings, 0 replies; 10+ messages in thread
From: Daniel Vetter @ 2014-12-01  8:32 UTC (permalink / raw)
  To: Cheng, Yao
  Cc: daniel.vetter, intel-gfx, emil.l.velikov, dri-devel, Chehab,
	John, Jiang, Fei, Barbalho, Rafael, Beckett, Robert

On Mon, Dec 01, 2014 at 03:04:27AM +0000, Cheng, Yao wrote:
> > -----Original Message-----
> > From: Beckett, Robert
> > Sent: Saturday, November 29, 2014 0:59
> > To: Cheng, Yao; intel-gfx@lists.freedesktop.org; dri-
> > devel@lists.freedesktop.org; daniel.vetter@ffwll.ch; Kelley, Sean V; Chehab,
> > John
> > Cc: emil.l.velikov@gmail.com; Jiang, Fei; dh.herrmann@gmail.com;
> > daniel@fooishbar.org
> > Subject: Re: [Intel-gfx] [RFC PATCH v3 1/4] drm/i915: add i915_ved.c to setup
> > bridge for VED
> > > + * Threats:
> > > + * Due to the restriction in Linux platform device model, user need
> > > +manually
> > > + * uninstall ipvr driver before uninstalling i915 module, otherwise
> > > +he might
> > > + * run into use-after-free issues after i915 removes the platform device.
> > 
> > Can you go in to more detail on what you consider to be the restriction in the
> > platform device model?
> > 
> > When removing the device via platform_device_unregister, it will call the
> > remove callback of any drivers handling this device (via the bus remove
> > function). It is then up to the driver to ensure no further usage of the device
> > from which it is being removed. This usually involves removing all user input
> > vectors, disabling interrupts involved and flushing/canceling any delayed
> > work. This should prevent any further use of the device by the driver.
> > 
> > The driver's remove function is called in a direct call chain from
> > platform_device_unregister, so by the time it returns, there should be no
> > further chance of accesses.
> >
> 
> Bob, thx for your review comments.
> The symptom is, after "rmmod i915", though drm_drv_release() is also
> called on the child device "ipvr", I still see the module exist in the
> system (check it by "lsmod"). This causes issue when I modprobe i915 and
> ipvr again later. Actually I don't understand why this restriction
> exists, but accroding to Daniel, grabbing a module refcount for the
> platform device doesn't work (it would pin the module forever).

Btw this entire story with platform drivers make unload a mess was just a
best guess from my side why module unloading doesn't work well or could
blow up. I've thought platform drivers registered from modules are
inheritely racy, but I'll be very happy to learn that this is a
misunderstanding on my side ;-)

Wrt the testcase I'm fairly pragmatic though: Whatever makes it work
reliably is good enough for me, even if it's a gross hack (we already need
to manually kick fbcon anyway).
Cheers, Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2014-12-01  8:31 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-11-21 19:06 [RFC PATCH v3 0/4] drm driver for VED in Intel GPU Yao Cheng
2014-11-21 19:06 ` [RFC PATCH v3 1/4] drm/i915: add i915_ved.c to setup bridge for VED Yao Cheng
2014-11-28 16:59   ` Robert Beckett
2014-12-01  3:04     ` Cheng, Yao
2014-12-01  8:32       ` [Intel-gfx] " Daniel Vetter
2014-11-21 19:06 ` [RFC PATCH v3 2/4] drm/ipvr: drm driver " Yao Cheng
2014-11-23 13:29   ` Cheng, Yao
2014-11-26 16:50   ` Cheng, Yao
2014-11-27 11:49   ` Cheng, Yao
2014-12-01  3:09     ` Cheng, Yao

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.