Skip to contentSkip to conversation

drm driver for VED in Intel GPU

RFC PATCH Superseded Yao Cheng 3 participants 16 messages Oct 21, 2014 – Oct 23, 2014 Page 1 of 2

Subsystems (4)

v2 of 3 Superseded Latest is v3 →

lore
Share & tools
lore

Yao Cheng

author
#0 lore raw

v2 cover drm driver for VED in Intel GPU

drm/ipvr is a new GEM driver for VED (PowerVR's VPU integrated in Intel GPU), which extends video decoding capability.
Two new Kconfig added for building ipvr driver:
CONFIG_DRM_IPVR: Build option for ipvr module
CONFIG_DRM_IPVR_EC: Experimental feature of error concealment

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/decode test are 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

Signature · 1 line
1.9.1
author
#1 lore raw

RFC PATCH v2 1/4 drm/i915: add i915_ved.c to setup bridge for VED

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.

---
 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 |   9 ++
 drivers/gpu/drm/i915/i915_irq.c |   2 +
 drivers/gpu/drm/i915/i915_reg.h |   5 +
 drivers/gpu/drm/i915/i915_ved.c | 264 ++++++++++++++++++++++++++++++++++++++++
 7 files changed, 299 insertions(+)
 create mode 100644 drivers/gpu/drm/i915/i915_ved.c
Documentation/DocBook/drm.tmpl +5 -0
index d7cfc98..f1787b4 100644
@@ -3806,6 +3806,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>
drivers/gpu/drm/i915/Makefile +3 -0
index 3a6bce0..a4b9252 100644
@@ -80,6 +80,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)
drivers/gpu/drm/i915/i915_dma.c +11 -0
index 85d14e1..47714e1 100644
@@ -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 (IS_VALLEYVIEW(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 (IS_VALLEYVIEW(dev)) {
+		vlv_teardown_ved(dev);
+	}
+
 	ret = i915_gem_suspend(dev);
 	if (ret) {
 		DRM_ERROR("failed to idle hardware: %d\n", ret);
drivers/gpu/drm/i915/i915_drv.h +9 -0
index 821ba26..952df34 100644
@@ -1709,6 +1709,10 @@ struct drm_i915_private {
 
 	uint32_t bios_vgacntr;
 
+	/* used for setup VED bridge */
+	struct platform_device *ved_platdev;
+	int	ved_irq;
+
 	/* Old dri1 support infrastructure, beware the dragons ya fools entering
 	 * here! */
 	struct i915_dri1_state dri1;
@@ -2785,6 +2789,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);
drivers/gpu/drm/i915/i915_irq.c +2 -0
index 737b239..68c2977 100644
@@ -2177,6 +2177,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 (IS_VALLEYVIEW(dev) && (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);
drivers/gpu/drm/i915/i915_reg.h +5 -0
index 2ed02c3..95421ef 100644
@@ -1284,6 +1284,11 @@ enum punit_power_well {
 #define VLV_DISPLAY_BASE 0x180000
 #define VLV_MIPI_BASE VLV_DISPLAY_BASE
 
+/* forwarding VED irq and sharing MMIO to the VED driver */
+#define VLV_VED_BLOCK_INTERRUPT			(1 << 23)
+#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 */
drivers/gpu/drm/i915/i915_ved.c new file +264 -0

264 lines not on this page · raw message

Signature · 6 lines
1.9.1

_______________________________________________
dri-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/dri-devel
#2 lore raw

Re: [RFC PATCH v2 1/4] drm/i915: add i915_ved.c to setup bridge for VED

Quoted 57 lines · Yao Cheng

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.

---
 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 |   9 ++
 drivers/gpu/drm/i915/i915_irq.c |   2 +
 drivers/gpu/drm/i915/i915_reg.h |   5 +
 drivers/gpu/drm/i915/i915_ved.c | 264 ++++++++++++++++++++++++++++++++++++++++
 7 files changed, 299 insertions(+)
 create mode 100644 drivers/gpu/drm/i915/i915_ved.c
Documentation/DocBook/drm.tmpl +5 -0
index d7cfc98..f1787b4 100644
@@ -3806,6 +3806,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>
drivers/gpu/drm/i915/Makefile +3 -0
index 3a6bce0..a4b9252 100644
@@ -80,6 +80,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)
drivers/gpu/drm/i915/i915_dma.c +0 -0
index 85d14e1..47714e1 100644

drivers/gpu/drm/i915/i915_dma.c int i915_driver_load(struct drm_device *dev, unsigned long flags) · line 1794

Quoted 4 lines
drivers/gpu/drm/i915/i915_dma.c +1 -0
@@ -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 (IS_VALLEYVIEW(dev)) {

These must be (IS_VLV && !IS_CHV), or maybe define some HAS_VED() macro to hide that.

Quoted 25 lines
drivers/gpu/drm/i915/i915_dma.c +10 -0
+		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 (IS_VALLEYVIEW(dev)) {
+		vlv_teardown_ved(dev);
+	}
+
 	ret = i915_gem_suspend(dev);
 	if (ret) {
 		DRM_ERROR("failed to idle hardware: %d\n", ret);
drivers/gpu/drm/i915/i915_drv.h +0 -0
index 821ba26..952df34 100644

drivers/gpu/drm/i915/i915_drv.h struct drm_i915_private { · line 1715

Quoted 7 lines
drivers/gpu/drm/i915/i915_drv.h +4 -0
@@ -1709,6 +1709,10 @@ struct drm_i915_private {
 
 	uint32_t bios_vgacntr;
 
+	/* used for setup VED bridge */
+	struct platform_device *ved_platdev;
+	int	ved_irq;
+

Could be neater to wrap this in a struct:

struct {
	struct platform_device *platdev;
	int irq;
} ved;
Quoted 20 lines
drivers/gpu/drm/i915/i915_drv.h +5 -0
 	/* Old dri1 support infrastructure, beware the dragons ya fools entering
 	 * here! */
 	struct i915_dri1_state dri1;
@@ -2785,6 +2789,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);
drivers/gpu/drm/i915/i915_irq.c +0 -0
index 737b239..68c2977 100644

drivers/gpu/drm/i915/i915_irq.c static irqreturn_t valleyview_irq_handler(int irq, void *arg) · line 2181

Quoted 5 lines
drivers/gpu/drm/i915/i915_irq.c +2 -0
@@ -2177,6 +2177,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 (IS_VALLEYVIEW(dev) && (iir & VLV_VED_BLOCK_INTERRUPT))
+			vlv_ved_irq_handler(dev);

This is the vlv irq handler so no need to check the platform type.

drivers/gpu/drm/i915/i915_reg.h enum punit_power_well { · line 1288

Quoted 13 lines
drivers/gpu/drm/i915/i915_irq.c +0 -0
 		/* Call regardless, as some status bits might not be
 		 * signalled in iir */
 		valleyview_pipestat_irq_handler(dev, iir);
drivers/gpu/drm/i915/i915_reg.h +2 -0
index 2ed02c3..95421ef 100644
@@ -1284,6 +1284,11 @@ enum punit_power_well {
 #define VLV_DISPLAY_BASE 0x180000
 #define VLV_MIPI_BASE VLV_DISPLAY_BASE
 
+/* forwarding VED irq and sharing MMIO to the VED driver */
+#define VLV_VED_BLOCK_INTERRUPT			(1 << 23)

This define should be alongside the other IxR bits.

Quoted 75 lines
drivers/gpu/drm/i915/i915_reg.h +3 -0
+#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 */
drivers/gpu/drm/i915/i915_ved.c new file +63 -0
new file mode 100644
index 0000000..5dfe4af
@@ -0,0 +1,264 @@
+/*
+ * 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 <[email protected]>
+ *
+ */
+
+#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 = NULL;
+	struct platform_device *platdev;

drivers/gpu/drm/i915/i915_ved.c line 73

Quoted 10 lines
drivers/gpu/drm/i915/i915_ved.c new file +10 -0
+	struct drm_i915_private *dev_priv = dev->dev_private;
+
+	platdev = platform_device_alloc("ipvr-ved-vlv", -1);
+	if (!platdev) {
+		DRM_ERROR("Failed to allocate VED platform device\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	rsc = kzalloc(sizeof(*rsc) * 3, GFP_KERNEL);

struct resource seems small enough that this could be on the stack.

Quoted 11 lines
drivers/gpu/drm/i915/i915_ved.c new file +11 -0
+	if (!rsc) {
+		DRM_ERROR("Failed to allocate resource for VED platform device\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	WARN_ON(dev_priv->ved_irq < 0);
+	rsc[0].start    = rsc[0].end = dev_priv->ved_irq;
+	rsc[0].flags    = IORESOURCE_IRQ;
+	rsc[0].name     = "ipvr-ved-vlv-irq";
+

drivers/gpu/drm/i915/i915_ved.c line 94

Quoted 10 lines
drivers/gpu/drm/i915/i915_ved.c new file +10 -0
+	/* MMIO/REG for child's use */
+	rsc[1].start    = pci_resource_start(dev->pdev, 0);
+	rsc[1].end      = pci_resource_start(dev->pdev, 0) + 2*1024*1024; /* gen7 */
+	rsc[1].flags    = IORESOURCE_MEM;
+	rsc[1].name     = "ipvr-ved-vlv-mmio";
+
+	rsc[2].start    = VLV_VED_BASE;
+	rsc[2].end      = VLV_VED_BASE + VLV_VED_SIZE;
+	rsc[2].flags    = IORESOURCE_REG;
+	rsc[2].name     = "ipvr-ved-vlv-reg";

I don't see why you need both MEM and REG resources. Just the MEM itself should suffice:

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";

Also in the ved driver you're mapping it with ioremap_wc() which isn't generally safe to do with registers. I'm not sure the kernel would even allow it since i915 has already mapped it as UC.

Quoted 40 lines
drivers/gpu/drm/i915/i915_ved.c new file +40 -0
+
+	ret = platform_device_add_resources(platdev, rsc, 3);
+	if (ret) {
+		DRM_ERROR("Failed to add resource for VED platform device: %d\n", ret);
+		goto err;
+	}
+
+	/* Runtime-PM hook */
+	platdev->dev.parent = dev->dev;
+	ret = platform_device_add(platdev);
+	if (ret) {
+		DRM_ERROR("Failed to add VED platform device: %d\n", ret);
+		goto err;
+	}
+
+	kfree(rsc);
+	return platdev;
+err:
+	if (rsc)
+		kfree(rsc);
+	if (platdev)
+		platform_device_unregister(platdev);
+	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)
+		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;
+	u32 imr, ier;
+	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+

drivers/gpu/drm/i915/i915_ved.c line 144

Quoted 10 lines
drivers/gpu/drm/i915/i915_ved.c new file +10 -0
+	ier = I915_READ(VLV_IER);
+	ier |= VLV_VED_BLOCK_INTERRUPT;
+	I915_WRITE(VLV_IER, ier);
+	POSTING_READ(VLV_IER);
+
+	imr = I915_READ(VLV_IMR);
+	imr &= ~VLV_VED_BLOCK_INTERRUPT;
+	dev_priv->irq_mask = imr;
+	I915_WRITE(VLV_IMR, imr);
+	POSTING_READ(VLV_IMR);

I think you could just follow the same procedure that valleyview_display_irqs_install() uses:

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);

Quoted 12 lines
drivers/gpu/drm/i915/i915_ved.c new file +12 -0
+
+	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;
+	u32 imr, ier;
+	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+

drivers/gpu/drm/i915/i915_ved.c line 166

Quoted 10 lines
drivers/gpu/drm/i915/i915_ved.c new file +10 -0
+	ier = I915_READ(VLV_IER);
+	ier &= ~VLV_VED_BLOCK_INTERRUPT;
+	I915_WRITE(VLV_IER, ier);
+	POSTING_READ(VLV_IER);
+
+	imr = I915_READ(VLV_IMR);
+	imr |= VLV_VED_BLOCK_INTERRUPT;
+	dev_priv->irq_mask = imr;
+	I915_WRITE(VLV_IMR, imr);
+	POSTING_READ(VLV_IMR);

Same here.

Quoted 105 lines
drivers/gpu/drm/i915/i915_ved.c new file +98 -0
+
+	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,
+};
+
+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);
+}
+
+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 irq;
+	int ret;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct platform_device *platdev;
+	dev_priv->ved_irq = -1;
+	dev_priv->ved_platdev = NULL;
+
+	irq = irq_alloc_descs(-1, 0, 1, 0);
+	if (irq < 0) {
+		DRM_ERROR("Failed to allocate IRQ desc: %d\n", irq);
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	ret = vlv_ved_irq_init(dev, irq);
+	if (ret) {
+		DRM_ERROR("Failed to initialize irqchip for vlv-ved: %d\n", ret);
+		goto err;
+	}
+	dev_priv->ved_irq = irq;
+
+	platdev = vlv_ved_platdev_create(dev);
+	if (IS_ERR(platdev)) {
+		DRM_ERROR("Failed to create platform device for vlv-ved: %ld\n", PTR_ERR(platdev));
+		ret = -EINVAL;
+		goto err;
+	}
+
+	dev_priv->ved_platdev = platdev;
+	return 0;
+err:
+	vlv_teardown_ved(dev);
+	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);
+	dev_priv->ved_platdev = NULL;
+	if (dev_priv->ved_irq >= 0) {
+		irq_free_desc(dev_priv->ved_irq);
+	}
+	dev_priv->ved_irq = -1;
+}
Signature · 6 lines
1.9.1

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Signature · 2 lines
Ville Syrjälä
Intel OTC
author
#3 lore raw

Re: [RFC PATCH v2 1/4] drm/i915: add i915_ved.c to setup bridge for VED

Quoted 68 lines

-----Original Message-----
From: Ville Syrjälä [mailto:[email protected]]
Sent: Tuesday, October 21, 2014 6:30 PM
To: Cheng, Yao
Cc: [email protected]; [email protected]; Kelley, Sean V; Vetter, Daniel; Abel, Michael J; Jiang, Fei; Rao, Ram R
Subject: Re: [Intel-gfx] [RFC PATCH v2 1/4] drm/i915: add i915_ved.c to setup bridge for VED

drivers/gpu/drm/i915/i915_dma.c int i915_driver_load(struct drm_device *dev,

Quoted 57 lines · Yao Cheng

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.

---
 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 |   9 ++
 drivers/gpu/drm/i915/i915_irq.c |   2 +
 drivers/gpu/drm/i915/i915_reg.h |   5 +
 drivers/gpu/drm/i915/i915_ved.c | 264
++++++++++++++++++++++++++++++++++++++++
 7 files changed, 299 insertions(+)
 create mode 100644 drivers/gpu/drm/i915/i915_ved.c
(quoted diff) +0 -0

b/Documentation/DocBook/drm.tmpl index d7cfc98..f1787b4 100644

Documentation/DocBook/drm.tmpl +0 -0
@@ -3806,6 +3806,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>
Documentation/DocBook/drm.tmpl +5 -0
+      <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 3a6bce0..a4b9252 100644

drivers/gpu/drm/i915/Makefile +3 -0
@@ -80,6 +80,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 85d14e1..47714e1 100644

drivers/gpu/drm/i915/i915_dma.c +0 -0
@@ -1791,6 +1791,13 @@ int i915_driver_load(struct drm_device *dev,

unsigned long flags)

Quoted 7 lines

drivers/gpu/drm/i915/i915_dma.c int i915_driver_load(struct drm_device *dev, unsigned long flags) · line 1794

Quoted 4 lines
drivers/gpu/drm/i915/i915_dma.c +1 -0
 	if (IS_GEN5(dev))
 		intel_gpu_ips_init(dev_priv);
 
+	if (IS_VALLEYVIEW(dev)) {

These must be (IS_VLV && !IS_CHV), or maybe define some HAS_VED() macro to hide that.

Accepted. Will add HAS_VED() to hide this.

Quoted 36 lines
Quoted 26 lines
drivers/gpu/drm/i915/i915_dma.c +10 -0
+		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 (IS_VALLEYVIEW(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 821ba26..952df34 100644

drivers/gpu/drm/i915/i915_drv.h struct drm_i915_private { · line 1715

Quoted 7 lines
drivers/gpu/drm/i915/i915_drv.h +4 -0
@@ -1709,6 +1709,10 @@ struct drm_i915_private {
 
 	uint32_t bios_vgacntr;
 
+	/* used for setup VED bridge */
+	struct platform_device *ved_platdev;
+	int	ved_irq;
+

Could be neater to wrap this in a struct:

Quoted 4 lines
struct {
	struct platform_device *platdev;
	int irq;
} ved;

Ok, thanks for the suggestion.

Quoted 25 lines

drivers/gpu/drm/i915/i915_drv.h struct drm_i915_private { · line 1716

Quoted 3 lines
drivers/gpu/drm/i915/i915_drv.h +0 -0
 	/* Old dri1 support infrastructure, beware the dragons ya fools

entering

drivers/gpu/drm/i915/i915_drv.h void i915_restore_display_reg(struct

Quoted 3 lines
drivers/gpu/drm/i915/i915_drv.h +0 -0
 	 * here! */
 	struct i915_dri1_state dri1;
@@ -2785,6 +2789,11 @@ void i915_restore_display_reg(struct

drm_device

drivers/gpu/drm/i915/i915_irq.c static irqreturn_t valleyview_irq_handler(int irq,

Quoted 16 lines
drivers/gpu/drm/i915/i915_drv.h +5 -0
 *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 737b239..68c2977 100644

drivers/gpu/drm/i915/i915_irq.c +0 -0
@@ -2177,6 +2177,8 @@ static irqreturn_t valleyview_irq_handler(int irq,

void *arg)

Quoted 8 lines

drivers/gpu/drm/i915/i915_irq.c static irqreturn_t valleyview_irq_handler(int irq, void *arg)

Quoted 4 lines
drivers/gpu/drm/i915/i915_irq.c +1 -0
 			snb_gt_irq_handler(dev, dev_priv, gt_iir);
 		if (pm_iir)
 			gen6_rps_irq_handler(dev_priv, pm_iir);
+		if (IS_VALLEYVIEW(dev) && (iir &

VLV_VED_BLOCK_INTERRUPT))

drivers/gpu/drm/i915/i915_irq.c static irqreturn_t valleyview_irq_handler(int irq, void *arg) · line 2181

Quoted 1 line
drivers/gpu/drm/i915/i915_irq.c +1 -0
+			vlv_ved_irq_handler(dev);

This is the vlv irq handler so no need to check the platform type.

Thnks for pointing out this. Will remove the platform check.

Quoted 12 lines
Quoted 10 lines
drivers/gpu/drm/i915/i915_irq.c +0 -0
 		/* 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 2ed02c3..95421ef 100644

drivers/gpu/drm/i915/i915_reg.h +0 -0
@@ -1284,6 +1284,11 @@ enum punit_power_well {  #define

VLV_DISPLAY_BASE 0x180000 #define VLV_MIPI_BASE

VLV_DISPLAY_BASE

Quoted 1 line
Quoted 4 lines

drivers/gpu/drm/i915/i915_reg.h enum punit_power_well { · line 1288

Quoted 2 lines
drivers/gpu/drm/i915/i915_reg.h +2 -0
+/* forwarding VED irq and sharing MMIO to the VED driver */
+#define VLV_VED_BLOCK_INTERRUPT			(1 << 23)

This define should be alongside the other IxR bits.

Do you mean like this:
Rename it to VLV_VED_IRQ and put alongside VLV_IIR?

Similar to the following:
#define GTIER 0x4401c
#define GEN8_PCU_IRQ (1<<30)

Quoted 106 lines
Quoted 25 lines
drivers/gpu/drm/i915/i915_reg.h +3 -0
+#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 */
(quoted diff) +0 -0

b/drivers/gpu/drm/i915/i915_ved.c new file mode 100644 index 0000000..5dfe4af

drivers/gpu/drm/i915/i915_ved.c new file +12 -0
@@ -0,0 +1,264 @@
+/*
+ * 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

drivers/gpu/drm/i915/i915_ved.c line 22

Quoted 10 lines
drivers/gpu/drm/i915/i915_ved.c new file +10 -0
+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,

drivers/gpu/drm/i915/i915_ved.c line 26

Quoted 4 lines
drivers/gpu/drm/i915/i915_ved.c new file +4 -0
+EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN

NO EVENT

drivers/gpu/drm/i915/i915_ved.c line 28

Quoted 2 lines
drivers/gpu/drm/i915/i915_ved.c new file +2 -0
+SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,

DAMAGES

drivers/gpu/drm/i915/i915_ved.c line 32

Quoted 4 lines
drivers/gpu/drm/i915/i915_ved.c new file +4 -0
+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

Quoted 57 lines
drivers/gpu/drm/i915/i915_ved.c new file +57 -0
+OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Yao Cheng <[email protected]>
+ *
+ */
+
+#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 = NULL;
+	struct platform_device *platdev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+
+	platdev = platform_device_alloc("ipvr-ved-vlv", -1);
+	if (!platdev) {
Quoted 8 lines

drivers/gpu/drm/i915/i915_ved.c line 73

Quoted 6 lines
drivers/gpu/drm/i915/i915_ved.c new file +6 -0
+		DRM_ERROR("Failed to allocate VED platform device\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	rsc = kzalloc(sizeof(*rsc) * 3, GFP_KERNEL);

struct resource seems small enough that this could be on the stack.

Accepted. Thanks for pointing out.

Quoted 28 lines

drivers/gpu/drm/i915/i915_ved.c line 97

Quoted 3 lines
drivers/gpu/drm/i915/i915_ved.c new file +2 -0
+	if (!rsc) {
+		DRM_ERROR("Failed to allocate resource for VED platform

device\n");

drivers/gpu/drm/i915/i915_ved.c

Quoted 12 lines
drivers/gpu/drm/i915/i915_ved.c new file +12 -0
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	WARN_ON(dev_priv->ved_irq < 0);
+	rsc[0].start    = rsc[0].end = dev_priv->ved_irq;
+	rsc[0].flags    = IORESOURCE_IRQ;
+	rsc[0].name     = "ipvr-ved-vlv-irq";
+
+	/* MMIO/REG for child's use */
+	rsc[1].start    = pci_resource_start(dev->pdev, 0);
+	rsc[1].end      = pci_resource_start(dev->pdev, 0) + 2*1024*1024; /*

gen7 */

drivers/gpu/drm/i915/i915_ved.c line 94

Quoted 7 lines
drivers/gpu/drm/i915/i915_ved.c new file +7 -0
+	rsc[1].flags    = IORESOURCE_MEM;
+	rsc[1].name     = "ipvr-ved-vlv-mmio";
+
+	rsc[2].start    = VLV_VED_BASE;
+	rsc[2].end      = VLV_VED_BASE + VLV_VED_SIZE;
+	rsc[2].flags    = IORESOURCE_REG;
+	rsc[2].name     = "ipvr-ved-vlv-reg";

I don't see why you need both MEM and REG resources. Just the MEM itself should suffice:

Quoted 6 lines

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";

When I write the original code on k3.10 I always got ioremap conflict by binding only one MMIO resource. I just tested this on k3.17 and no conflict. :) thanks for pointing out this and I will update the code. BTW, it's interesting, is there any update on the ioremap code from 3.10 to 3.17?

Quoted 3 lines

Also in the ved driver you're mapping it with ioremap_wc() which isn't generally safe to do with registers. I'm not sure the kernel would even allow it since i915 has already mapped it as UC.

Thanks, I'll change it to UC.

Quoted 55 lines

drivers/gpu/drm/i915/i915_ved.c

Quoted 5 lines
drivers/gpu/drm/i915/i915_ved.c new file +4 -0
+
+	ret = platform_device_add_resources(platdev, rsc, 3);
+	if (ret) {
+		DRM_ERROR("Failed to add resource for VED platform

device: %d\n", ret);

Quoted 20 lines
drivers/gpu/drm/i915/i915_ved.c new file +20 -0
+		goto err;
+	}
+
+	/* Runtime-PM hook */
+	platdev->dev.parent = dev->dev;
+	ret = platform_device_add(platdev);
+	if (ret) {
+		DRM_ERROR("Failed to add VED platform device: %d\n", ret);
+		goto err;
+	}
+
+	kfree(rsc);
+	return platdev;
+err:
+	if (rsc)
+		kfree(rsc);
+	if (platdev)
+		platform_device_unregister(platdev);
+	return ERR_PTR(ret);
+}

drivers/gpu/drm/i915/i915_ved.c

Quoted 10 lines
drivers/gpu/drm/i915/i915_ved.c new file +10 -0
+
+static void vlv_ved_platdev_destroy(struct drm_device *dev) {
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	if (dev_priv->ved_platdev)
+		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;

Quoted 4 lines
drivers/gpu/drm/i915/i915_ved.c new file +4 -0
+	unsigned long irqflags;
+	u32 imr, ier;
+	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+

drivers/gpu/drm/i915/i915_ved.c line 144

Quoted 10 lines
drivers/gpu/drm/i915/i915_ved.c new file +10 -0
+	ier = I915_READ(VLV_IER);
+	ier |= VLV_VED_BLOCK_INTERRUPT;
+	I915_WRITE(VLV_IER, ier);
+	POSTING_READ(VLV_IER);
+
+	imr = I915_READ(VLV_IMR);
+	imr &= ~VLV_VED_BLOCK_INTERRUPT;
+	dev_priv->irq_mask = imr;
+	I915_WRITE(VLV_IMR, imr);
+	POSTING_READ(VLV_IMR);

I think you could just follow the same procedure that valleyview_display_irqs_install() uses:

Quoted 4 lines

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);

Thanks, accepted.

Quoted 8 lines

drivers/gpu/drm/i915/i915_ved.c

Quoted 7 lines
drivers/gpu/drm/i915/i915_ved.c new file +6 -0
+
+	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;

Quoted 16 lines
Quoted 4 lines
drivers/gpu/drm/i915/i915_ved.c new file +4 -0
+	unsigned long irqflags;
+	u32 imr, ier;
+	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+

drivers/gpu/drm/i915/i915_ved.c line 166

Quoted 10 lines
drivers/gpu/drm/i915/i915_ved.c new file +10 -0
+	ier = I915_READ(VLV_IER);
+	ier &= ~VLV_VED_BLOCK_INTERRUPT;
+	I915_WRITE(VLV_IER, ier);
+	POSTING_READ(VLV_IER);
+
+	imr = I915_READ(VLV_IMR);
+	imr |= VLV_VED_BLOCK_INTERRUPT;
+	dev_priv->irq_mask = imr;
+	I915_WRITE(VLV_IMR, imr);
+	POSTING_READ(VLV_IMR);

Same here.

Accepted.

Quoted 111 lines

drivers/gpu/drm/i915/i915_ved.c

Quoted 12 lines
drivers/gpu/drm/i915/i915_ved.c new file +11 -0
+
+	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,
+};
+
+int vlv_ved_irq_init(struct drm_device *dev, int irq) {
+	struct drm_i915_private *dev_priv = (struct drm_i915_private *)

dev->dev_private;

Quoted 41 lines
drivers/gpu/drm/i915/i915_ved.c new file +13 -0
+	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);
+}
+
+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);

drivers/gpu/drm/i915/i915_ved.c new file +27 -0
+		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 irq;
+	int ret;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct platform_device *platdev;
+	dev_priv->ved_irq = -1;
+	dev_priv->ved_platdev = NULL;
+

drivers/gpu/drm/i915/i915_ved.c

Quoted 10 lines
drivers/gpu/drm/i915/i915_ved.c new file +10 -0
+	irq = irq_alloc_descs(-1, 0, 1, 0);
+	if (irq < 0) {
+		DRM_ERROR("Failed to allocate IRQ desc: %d\n", irq);
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	ret = vlv_ved_irq_init(dev, irq);
+	if (ret) {
+		DRM_ERROR("Failed to initialize irqchip for vlv-ved: %d\n",

ret);

drivers/gpu/drm/i915/i915_ved.c

Quoted 7 lines
drivers/gpu/drm/i915/i915_ved.c new file +7 -0
+		goto err;
+	}
+	dev_priv->ved_irq = irq;
+
+	platdev = vlv_ved_platdev_create(dev);
+	if (IS_ERR(platdev)) {
+		DRM_ERROR("Failed to create platform device for vlv-

ved: %ld\n", PTR_ERR(platdev));

Quoted 30 lines
drivers/gpu/drm/i915/i915_ved.c new file +27 -1
+		ret = -EINVAL;
+		goto err;
+	}
+
+	dev_priv->ved_platdev = platdev;
+	return 0;
+err:
+	vlv_teardown_ved(dev);
+	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);
+	dev_priv->ved_platdev = NULL;
+	if (dev_priv->ved_irq >= 0) {
+		irq_free_desc(dev_priv->ved_irq);
+	}
+	dev_priv->ved_irq = -1;
+}
--

1.9.1

Quoted 4 lines

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

--
Ville Syrjälä
Intel OTC

#4 lore raw

Re: [RFC PATCH v2 1/4] drm/i915: add i915_ved.c to setup bridge for VED

Quoted 10 lines · Yao
Quoted 10 lines

-----Original Message-----
From: Ville Syrjälä [mailto:[email protected]]
Sent: Tuesday, October 21, 2014 6:30 PM
To: Cheng, Yao
Cc: [email protected]; [email protected]; Kelley, Sean V; Vetter, Daniel; Abel, Michael J; Jiang, Fei; Rao, Ram R
Subject: Re: [Intel-gfx] [RFC PATCH v2 1/4] drm/i915: add i915_ved.c to setup bridge for VED

On Tue, Oct 21, 2014 at 02:36:41PM +0800, Yao Cheng wrote:

<snip>

Quoted 12 lines
Quoted 12 lines
Quoted 10 lines
drivers/gpu/drm/i915/i915_irq.c +0 -0
 		/* 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 2ed02c3..95421ef 100644

drivers/gpu/drm/i915/i915_reg.h +0 -0
@@ -1284,6 +1284,11 @@ enum punit_power_well {  #define

VLV_DISPLAY_BASE 0x180000 #define VLV_MIPI_BASE

VLV_DISPLAY_BASE

Quoted 1 line
Quoted 7 lines
Quoted 4 lines

drivers/gpu/drm/i915/i915_reg.h enum punit_power_well { · line 1288

Quoted 2 lines
drivers/gpu/drm/i915/i915_reg.h +2 -0
+/* forwarding VED irq and sharing MMIO to the VED driver */
+#define VLV_VED_BLOCK_INTERRUPT			(1 << 23)

This define should be alongside the other IxR bits.

Do you mean like this:
Rename it to VLV_VED_IRQ and put alongside VLV_IIR?

No, I think the name is fine as is, but it should be where the other "old" IxR bits are defined. So between I915_PM_INTERRUPT and I915_ISP_INTERRUPT looks like right spot to me.

I'm not sure why those defines are where they are. We should probably move the lot to sit next to the IxR register defines themselves, but that's a separate issue.

<snip>

Quoted 35 lines
Quoted 28 lines

drivers/gpu/drm/i915/i915_reg.h

Quoted 3 lines
drivers/gpu/drm/i915/i915_reg.h +2 -0
+	if (!rsc) {
+		DRM_ERROR("Failed to allocate resource for VED platform

device\n");

drivers/gpu/drm/i915/i915_reg.h

Quoted 12 lines
drivers/gpu/drm/i915/i915_reg.h +12 -0
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	WARN_ON(dev_priv->ved_irq < 0);
+	rsc[0].start    = rsc[0].end = dev_priv->ved_irq;
+	rsc[0].flags    = IORESOURCE_IRQ;
+	rsc[0].name     = "ipvr-ved-vlv-irq";
+
+	/* MMIO/REG for child's use */
+	rsc[1].start    = pci_resource_start(dev->pdev, 0);
+	rsc[1].end      = pci_resource_start(dev->pdev, 0) + 2*1024*1024; /*

gen7 */

drivers/gpu/drm/i915/i915_reg.h

Quoted 7 lines
drivers/gpu/drm/i915/i915_reg.h +7 -0
+	rsc[1].flags    = IORESOURCE_MEM;
+	rsc[1].name     = "ipvr-ved-vlv-mmio";
+
+	rsc[2].start    = VLV_VED_BASE;
+	rsc[2].end      = VLV_VED_BASE + VLV_VED_SIZE;
+	rsc[2].flags    = IORESOURCE_REG;
+	rsc[2].name     = "ipvr-ved-vlv-reg";

I don't see why you need both MEM and REG resources. Just the MEM itself should suffice:

Quoted 6 lines

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";

Quoted 3 lines

When I write the original code on k3.10 I always got ioremap conflict by binding only one MMIO resource. I just tested this on k3.17 and no conflict. :) thanks for pointing out this and I will update the code. BTW, it's interesting, is there any update on the ioremap code from 3.10 to 3.17?

Not sure. But the UC vs. WC could be one explanation for the conflict.

Quoted 6 lines
Quoted 4 lines

Also in the ved driver you're mapping it with ioremap_wc() which isn't generally safe to do with registers. I'm not sure the kernel would even allow it since i915 has already mapped it as UC.

Thanks, I'll change it to UC.

Signature · 2 lines
Ville Syrjälä
Intel OTC
author
#5 lore raw

RE: [Intel-gfx] [RFC PATCH v2 1/4] drm/i915: add i915_ved.c to setup bridge for VED

In reply to Cheng, Yao

Cc Jani for notifying the patch update:

Add missing v2 changelog:
Take Jani's comment: remove BUG_ON in i915_driver_load
Take Daniel's comment: extract the VED setup related functions to i915_ved.c Take Daniel's comment: add kerneldoc to describe i915_ved.c
Take Daniel's comment: rename "ipvr-ved" to "ipvr-ved-vlv"
Take Daniel's comment: unregister platform device before irq_free_desc() when teardown VED. Take Daniel's comment: update i-g-t to manually unload ipvr.ko before unloading i915.ko Take Daniels' comment: add WARN_ON(!intel_irqs_enabled()) in VED irqchip initialization function. Take Daniel's comment: remove the trace point for VED interrupt.

Quoted 569 lines

-----Original Message-----
From: Intel-gfx [mailto:[email protected]] On Behalf Of Cheng, Yao
Sent: Wednesday, October 22, 2014 15:09
To: Ville Syrjälä
Cc: Rao, Ram R; [email protected]; dri- [email protected]; Jiang, Fei; Abel, Michael J; Vetter, Daniel
Subject: Re: [Intel-gfx] [RFC PATCH v2 1/4] drm/i915: add i915_ved.c to setup bridge for VED

Quoted 71 lines

-----Original Message-----
From: Ville Syrjälä [mailto:[email protected]]
Sent: Tuesday, October 21, 2014 6:30 PM
To: Cheng, Yao
Cc: [email protected]; [email protected]; Kelley, Sean V; Vetter, Daniel; Abel, Michael J; Jiang, Fei; Rao, Ram R
Subject: Re: [Intel-gfx] [RFC PATCH v2 1/4] drm/i915: add i915_ved.c to setup bridge for VED

drivers/gpu/drm/i915/i915_dma.c int i915_driver_load(struct drm_device *dev,

Quoted 59 lines · Yao Cheng

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.

---
 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 |   9 ++
 drivers/gpu/drm/i915/i915_irq.c |   2 +
 drivers/gpu/drm/i915/i915_reg.h |   5 +
 drivers/gpu/drm/i915/i915_ved.c | 264
++++++++++++++++++++++++++++++++++++++++
 7 files changed, 299 insertions(+)
 create mode 100644 drivers/gpu/drm/i915/i915_ved.c
(quoted diff) +0 -0

b/Documentation/DocBook/drm.tmpl index d7cfc98..f1787b4 100644

Documentation/DocBook/drm.tmpl +0 -0
@@ -3806,6 +3806,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>
Documentation/DocBook/drm.tmpl +5 -0
+      <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
3a6bce0..a4b9252 100644

drivers/gpu/drm/i915/Makefile +3 -0
@@ -80,6 +80,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 85d14e1..47714e1 100644

drivers/gpu/drm/i915/i915_dma.c +0 -0
@@ -1791,6 +1791,13 @@ int i915_driver_load(struct drm_device *dev,

unsigned long flags)

Quoted 7 lines

drivers/gpu/drm/i915/i915_dma.c int i915_driver_load(struct drm_device *dev, unsigned long flags) · line 1794

Quoted 4 lines
drivers/gpu/drm/i915/i915_dma.c +1 -0
 	if (IS_GEN5(dev))
 		intel_gpu_ips_init(dev_priv);
 
+	if (IS_VALLEYVIEW(dev)) {

These must be (IS_VLV && !IS_CHV), or maybe define some HAS_VED() macro to hide that.

Accepted. Will add HAS_VED() to hide this.

Quoted 11 lines

drivers/gpu/drm/i915/i915_dma.c int i915_driver_unload(struct drm_device

Quoted 11 lines
drivers/gpu/drm/i915/i915_dma.c +6 -0
+		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)

Quoted 25 lines
Quoted 15 lines
drivers/gpu/drm/i915/i915_dma.c +4 -0
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	int ret;
 
+	if (IS_VALLEYVIEW(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 821ba26..952df34 100644

drivers/gpu/drm/i915/i915_drv.h struct drm_i915_private { · line 1715

Quoted 7 lines
drivers/gpu/drm/i915/i915_drv.h +4 -0
@@ -1709,6 +1709,10 @@ struct drm_i915_private {
 
 	uint32_t bios_vgacntr;
 
+	/* used for setup VED bridge */
+	struct platform_device *ved_platdev;
+	int	ved_irq;
+

Could be neater to wrap this in a struct:

Quoted 4 lines
struct {
	struct platform_device *platdev;
	int irq;
} ved;

Ok, thanks for the suggestion.

Quoted 26 lines

drivers/gpu/drm/i915/i915_drv.h struct drm_i915_private { · line 1716

Quoted 3 lines
drivers/gpu/drm/i915/i915_drv.h +0 -0
 	/* Old dri1 support infrastructure, beware the dragons ya fools

entering

drivers/gpu/drm/i915/i915_drv.h void i915_restore_display_reg(struct

Quoted 3 lines
drivers/gpu/drm/i915/i915_drv.h +0 -0
 	 * here! */
 	struct i915_dri1_state dri1;
@@ -2785,6 +2789,11 @@ void i915_restore_display_reg(struct

drm_device

Quoted 16 lines
drivers/gpu/drm/i915/i915_drv.h +5 -0
 *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 737b239..68c2977 100644

drivers/gpu/drm/i915/i915_irq.c static irqreturn_t valleyview_irq_handler(int · line 2177

Quoted 1 line
drivers/gpu/drm/i915/i915_irq.c +0 -0
@@ -2177,6 +2177,8 @@ static irqreturn_t valleyview_irq_handler(int
 irq,

void *arg)

Quoted 8 lines

drivers/gpu/drm/i915/i915_irq.c static irqreturn_t valleyview_irq_handler(int irq, void *arg)

Quoted 4 lines
drivers/gpu/drm/i915/i915_irq.c +1 -0
 			snb_gt_irq_handler(dev, dev_priv, gt_iir);
 		if (pm_iir)
 			gen6_rps_irq_handler(dev_priv, pm_iir);
+		if (IS_VALLEYVIEW(dev) && (iir &

VLV_VED_BLOCK_INTERRUPT))

drivers/gpu/drm/i915/i915_irq.c static irqreturn_t valleyview_irq_handler(int irq, void *arg) · line 2181

Quoted 1 line
drivers/gpu/drm/i915/i915_irq.c +1 -0
+			vlv_ved_irq_handler(dev);

This is the vlv irq handler so no need to check the platform type.

Thnks for pointing out this. Will remove the platform check.

Quoted 12 lines
Quoted 10 lines
drivers/gpu/drm/i915/i915_irq.c +0 -0
 		/* 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 2ed02c3..95421ef 100644

drivers/gpu/drm/i915/i915_reg.h +0 -0
@@ -1284,6 +1284,11 @@ enum punit_power_well {  #define

VLV_DISPLAY_BASE 0x180000 #define VLV_MIPI_BASE

VLV_DISPLAY_BASE

Quoted 1 line
Quoted 4 lines

drivers/gpu/drm/i915/i915_reg.h enum punit_power_well { · line 1288

Quoted 2 lines
drivers/gpu/drm/i915/i915_reg.h +2 -0
+/* forwarding VED irq and sharing MMIO to the VED driver */
+#define VLV_VED_BLOCK_INTERRUPT			(1 << 23)

This define should be alongside the other IxR bits.

Do you mean like this:
Rename it to VLV_VED_IRQ and put alongside VLV_IIR?

Similar to the following:
#define GTIER 0x4401c
#define GEN8_PCU_IRQ (1<<30)

Quoted 36 lines
Quoted 25 lines
drivers/gpu/drm/i915/i915_reg.h +3 -0
+#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 */
(quoted diff) +0 -0

b/drivers/gpu/drm/i915/i915_ved.c new file mode 100644 index 0000000..5dfe4af

drivers/gpu/drm/i915/i915_ved.c new file +12 -0
@@ -0,0 +1,264 @@
+/*
+ * 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

drivers/gpu/drm/i915/i915_ved.c line 22

Quoted 10 lines
drivers/gpu/drm/i915/i915_ved.c new file +10 -0
+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,

Quoted 10 lines

drivers/gpu/drm/i915/i915_ved.c line 26

Quoted 4 lines
drivers/gpu/drm/i915/i915_ved.c new file +4 -0
+EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN

NO EVENT

drivers/gpu/drm/i915/i915_ved.c line 28

Quoted 2 lines
drivers/gpu/drm/i915/i915_ved.c new file +2 -0
+SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,

DAMAGES

Quoted 2 lines
drivers/gpu/drm/i915/i915_ved.c new file +2 -0
+OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR

OTHERWISE,

Quoted 60 lines

drivers/gpu/drm/i915/i915_ved.c line 32

Quoted 2 lines
drivers/gpu/drm/i915/i915_ved.c new file +2 -0
+ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE

OR

Quoted 57 lines
drivers/gpu/drm/i915/i915_ved.c new file +57 -0
+OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Yao Cheng <[email protected]>
+ *
+ */
+
+#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 = NULL;
+	struct platform_device *platdev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+
+	platdev = platform_device_alloc("ipvr-ved-vlv", -1);
+	if (!platdev) {
Quoted 8 lines

drivers/gpu/drm/i915/i915_ved.c line 73

Quoted 6 lines
drivers/gpu/drm/i915/i915_ved.c new file +6 -0
+		DRM_ERROR("Failed to allocate VED platform device\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	rsc = kzalloc(sizeof(*rsc) * 3, GFP_KERNEL);

struct resource seems small enough that this could be on the stack.

Accepted. Thanks for pointing out.

Quoted 28 lines

drivers/gpu/drm/i915/i915_ved.c line 97

Quoted 3 lines
drivers/gpu/drm/i915/i915_ved.c new file +2 -0
+	if (!rsc) {
+		DRM_ERROR("Failed to allocate resource for VED platform

device\n");

drivers/gpu/drm/i915/i915_ved.c

Quoted 12 lines
drivers/gpu/drm/i915/i915_ved.c new file +12 -0
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	WARN_ON(dev_priv->ved_irq < 0);
+	rsc[0].start    = rsc[0].end = dev_priv->ved_irq;
+	rsc[0].flags    = IORESOURCE_IRQ;
+	rsc[0].name     = "ipvr-ved-vlv-irq";
+
+	/* MMIO/REG for child's use */
+	rsc[1].start    = pci_resource_start(dev->pdev, 0);
+	rsc[1].end      = pci_resource_start(dev->pdev, 0) + 2*1024*1024; /*

gen7 */

drivers/gpu/drm/i915/i915_ved.c line 94

Quoted 7 lines
drivers/gpu/drm/i915/i915_ved.c new file +7 -0
+	rsc[1].flags    = IORESOURCE_MEM;
+	rsc[1].name     = "ipvr-ved-vlv-mmio";
+
+	rsc[2].start    = VLV_VED_BASE;
+	rsc[2].end      = VLV_VED_BASE + VLV_VED_SIZE;
+	rsc[2].flags    = IORESOURCE_REG;
+	rsc[2].name     = "ipvr-ved-vlv-reg";

I don't see why you need both MEM and REG resources. Just the MEM itself should suffice:

Quoted 6 lines

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";

When I write the original code on k3.10 I always got ioremap conflict by binding only one MMIO resource.
I just tested this on k3.17 and no conflict. :) thanks for pointing out this and I will update the code.
BTW, it's interesting, is there any update on the ioremap code from 3.10 to 3.17?

Quoted 3 lines

Also in the ved driver you're mapping it with ioremap_wc() which isn't generally safe to do with registers. I'm not sure the kernel would even allow it since i915 has already mapped it as UC.

Thanks, I'll change it to UC.

Quoted 55 lines

drivers/gpu/drm/i915/i915_ved.c

Quoted 5 lines
drivers/gpu/drm/i915/i915_ved.c new file +4 -0
+
+	ret = platform_device_add_resources(platdev, rsc, 3);
+	if (ret) {
+		DRM_ERROR("Failed to add resource for VED platform

device: %d\n", ret);

Quoted 20 lines
drivers/gpu/drm/i915/i915_ved.c new file +20 -0
+		goto err;
+	}
+
+	/* Runtime-PM hook */
+	platdev->dev.parent = dev->dev;
+	ret = platform_device_add(platdev);
+	if (ret) {
+		DRM_ERROR("Failed to add VED platform device: %d\n", ret);
+		goto err;
+	}
+
+	kfree(rsc);
+	return platdev;
+err:
+	if (rsc)
+		kfree(rsc);
+	if (platdev)
+		platform_device_unregister(platdev);
+	return ERR_PTR(ret);
+}

drivers/gpu/drm/i915/i915_ved.c

Quoted 10 lines
drivers/gpu/drm/i915/i915_ved.c new file +10 -0
+
+static void vlv_ved_platdev_destroy(struct drm_device *dev) {
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	if (dev_priv->ved_platdev)
+		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;

Quoted 4 lines
drivers/gpu/drm/i915/i915_ved.c new file +4 -0
+	unsigned long irqflags;
+	u32 imr, ier;
+	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+

drivers/gpu/drm/i915/i915_ved.c line 144

Quoted 10 lines
drivers/gpu/drm/i915/i915_ved.c new file +10 -0
+	ier = I915_READ(VLV_IER);
+	ier |= VLV_VED_BLOCK_INTERRUPT;
+	I915_WRITE(VLV_IER, ier);
+	POSTING_READ(VLV_IER);
+
+	imr = I915_READ(VLV_IMR);
+	imr &= ~VLV_VED_BLOCK_INTERRUPT;
+	dev_priv->irq_mask = imr;
+	I915_WRITE(VLV_IMR, imr);
+	POSTING_READ(VLV_IMR);

I think you could just follow the same procedure that valleyview_display_irqs_install() uses:

Quoted 1 line

dev_priv->irq_mask &= ~VLV_VED_BLOCK_INTERRUPT;

I915_WRITE(VLV_IIR,

Quoted 4 lines

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);

Thanks, accepted.

Quoted 8 lines

drivers/gpu/drm/i915/i915_ved.c

Quoted 7 lines
drivers/gpu/drm/i915/i915_ved.c new file +6 -0
+
+	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;

Quoted 16 lines
Quoted 4 lines
drivers/gpu/drm/i915/i915_ved.c new file +4 -0
+	unsigned long irqflags;
+	u32 imr, ier;
+	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+

drivers/gpu/drm/i915/i915_ved.c line 166

Quoted 10 lines
drivers/gpu/drm/i915/i915_ved.c new file +10 -0
+	ier = I915_READ(VLV_IER);
+	ier &= ~VLV_VED_BLOCK_INTERRUPT;
+	I915_WRITE(VLV_IER, ier);
+	POSTING_READ(VLV_IER);
+
+	imr = I915_READ(VLV_IMR);
+	imr |= VLV_VED_BLOCK_INTERRUPT;
+	dev_priv->irq_mask = imr;
+	I915_WRITE(VLV_IMR, imr);
+	POSTING_READ(VLV_IMR);

Same here.

Accepted.

Quoted 102 lines

drivers/gpu/drm/i915/i915_ved.c

Quoted 12 lines
drivers/gpu/drm/i915/i915_ved.c new file +11 -0
+
+	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,
+};
+
+int vlv_ved_irq_init(struct drm_device *dev, int irq) {
+	struct drm_i915_private *dev_priv = (struct drm_i915_private *)

dev->dev_private;

Quoted 40 lines
drivers/gpu/drm/i915/i915_ved.c new file +12 -0
+	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); }
+
+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);

drivers/gpu/drm/i915/i915_ved.c new file +27 -0
+		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 irq;
+	int ret;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct platform_device *platdev;
+	dev_priv->ved_irq = -1;
+	dev_priv->ved_platdev = NULL;
+

drivers/gpu/drm/i915/i915_ved.c

Quoted 10 lines
drivers/gpu/drm/i915/i915_ved.c new file +10 -0
+	irq = irq_alloc_descs(-1, 0, 1, 0);
+	if (irq < 0) {
+		DRM_ERROR("Failed to allocate IRQ desc: %d\n", irq);
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	ret = vlv_ved_irq_init(dev, irq);
+	if (ret) {
+		DRM_ERROR("Failed to initialize irqchip for vlv-ved: %d\n",

ret);

drivers/gpu/drm/i915/i915_ved.c

Quoted 7 lines
drivers/gpu/drm/i915/i915_ved.c new file +7 -0
+		goto err;
+	}
+	dev_priv->ved_irq = irq;
+
+	platdev = vlv_ved_platdev_create(dev);
+	if (IS_ERR(platdev)) {
+		DRM_ERROR("Failed to create platform device for vlv-

ved: %ld\n", PTR_ERR(platdev));

Quoted 30 lines
drivers/gpu/drm/i915/i915_ved.c new file +27 -1
+		ret = -EINVAL;
+		goto err;
+	}
+
+	dev_priv->ved_platdev = platdev;
+	return 0;
+err:
+	vlv_teardown_ved(dev);
+	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);
+	dev_priv->ved_platdev = NULL;
+	if (dev_priv->ved_irq >= 0) {
+		irq_free_desc(dev_priv->ved_irq);
+	}
+	dev_priv->ved_irq = -1;
+}
--

1.9.1

Quoted 8 lines
Quoted 4 lines

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

--
Ville Syrjälä
Intel OTC

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

#6 lore raw

Re: [RFC PATCH v2 1/4] drm/i915: add i915_ved.c to setup bridge for VED

In reply to Yao Cheng
Quoted 11 lines · Yao Cheng

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.

Please resend with a patch changelog to account for my review comments. And Ville's. Plus cc us both. And if there's anything you didn't address, you must reply to the review and we need to further discuss this.

Thanks, Daniel

Quoted 403 lines
---
 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 |   9 ++
 drivers/gpu/drm/i915/i915_irq.c |   2 +
 drivers/gpu/drm/i915/i915_reg.h |   5 +
 drivers/gpu/drm/i915/i915_ved.c | 264 ++++++++++++++++++++++++++++++++++++++++
 7 files changed, 299 insertions(+)
 create mode 100644 drivers/gpu/drm/i915/i915_ved.c
Documentation/DocBook/drm.tmpl +5 -0
index d7cfc98..f1787b4 100644
@@ -3806,6 +3806,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>
drivers/gpu/drm/i915/Makefile +3 -0
index 3a6bce0..a4b9252 100644
@@ -80,6 +80,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)
drivers/gpu/drm/i915/i915_dma.c +11 -0
index 85d14e1..47714e1 100644
@@ -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 (IS_VALLEYVIEW(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 (IS_VALLEYVIEW(dev)) {
+		vlv_teardown_ved(dev);
+	}
+
 	ret = i915_gem_suspend(dev);
 	if (ret) {
 		DRM_ERROR("failed to idle hardware: %d\n", ret);
drivers/gpu/drm/i915/i915_drv.h +9 -0
index 821ba26..952df34 100644
@@ -1709,6 +1709,10 @@ struct drm_i915_private {
 
 	uint32_t bios_vgacntr;
 
+	/* used for setup VED bridge */
+	struct platform_device *ved_platdev;
+	int	ved_irq;
+
 	/* Old dri1 support infrastructure, beware the dragons ya fools entering
 	 * here! */
 	struct i915_dri1_state dri1;
@@ -2785,6 +2789,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);
drivers/gpu/drm/i915/i915_irq.c +2 -0
index 737b239..68c2977 100644
@@ -2177,6 +2177,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 (IS_VALLEYVIEW(dev) && (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);
drivers/gpu/drm/i915/i915_reg.h +5 -0
index 2ed02c3..95421ef 100644
@@ -1284,6 +1284,11 @@ enum punit_power_well {
 #define VLV_DISPLAY_BASE 0x180000
 #define VLV_MIPI_BASE VLV_DISPLAY_BASE
 
+/* forwarding VED irq and sharing MMIO to the VED driver */
+#define VLV_VED_BLOCK_INTERRUPT			(1 << 23)
+#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 */
drivers/gpu/drm/i915/i915_ved.c new file +264 -0
new file mode 100644
index 0000000..5dfe4af
@@ -0,0 +1,264 @@
+/*
+ * 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 <[email protected]>
+ *
+ */
+
+#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 = NULL;
+	struct platform_device *platdev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+
+	platdev = platform_device_alloc("ipvr-ved-vlv", -1);
+	if (!platdev) {
+		DRM_ERROR("Failed to allocate VED platform device\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	rsc = kzalloc(sizeof(*rsc) * 3, GFP_KERNEL);
+	if (!rsc) {
+		DRM_ERROR("Failed to allocate resource for VED platform device\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	WARN_ON(dev_priv->ved_irq < 0);
+	rsc[0].start    = rsc[0].end = dev_priv->ved_irq;
+	rsc[0].flags    = IORESOURCE_IRQ;
+	rsc[0].name     = "ipvr-ved-vlv-irq";
+
+	/* MMIO/REG for child's use */
+	rsc[1].start    = pci_resource_start(dev->pdev, 0);
+	rsc[1].end      = pci_resource_start(dev->pdev, 0) + 2*1024*1024; /* gen7 */
+	rsc[1].flags    = IORESOURCE_MEM;
+	rsc[1].name     = "ipvr-ved-vlv-mmio";
+
+	rsc[2].start    = VLV_VED_BASE;
+	rsc[2].end      = VLV_VED_BASE + VLV_VED_SIZE;
+	rsc[2].flags    = IORESOURCE_REG;
+	rsc[2].name     = "ipvr-ved-vlv-reg";
+
+	ret = platform_device_add_resources(platdev, rsc, 3);
+	if (ret) {
+		DRM_ERROR("Failed to add resource for VED platform device: %d\n", ret);
+		goto err;
+	}
+
+	/* Runtime-PM hook */
+	platdev->dev.parent = dev->dev;
+	ret = platform_device_add(platdev);
+	if (ret) {
+		DRM_ERROR("Failed to add VED platform device: %d\n", ret);
+		goto err;
+	}
+
+	kfree(rsc);
+	return platdev;
+err:
+	if (rsc)
+		kfree(rsc);
+	if (platdev)
+		platform_device_unregister(platdev);
+	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)
+		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;
+	u32 imr, ier;
+	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+
+	ier = I915_READ(VLV_IER);
+	ier |= VLV_VED_BLOCK_INTERRUPT;
+	I915_WRITE(VLV_IER, ier);
+	POSTING_READ(VLV_IER);
+
+	imr = I915_READ(VLV_IMR);
+	imr &= ~VLV_VED_BLOCK_INTERRUPT;
+	dev_priv->irq_mask = imr;
+	I915_WRITE(VLV_IMR, imr);
+	POSTING_READ(VLV_IMR);
+
+	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;
+	u32 imr, ier;
+	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+
+	ier = I915_READ(VLV_IER);
+	ier &= ~VLV_VED_BLOCK_INTERRUPT;
+	I915_WRITE(VLV_IER, ier);
+	POSTING_READ(VLV_IER);
+
+	imr = I915_READ(VLV_IMR);
+	imr |= VLV_VED_BLOCK_INTERRUPT;
+	dev_priv->irq_mask = imr;
+	I915_WRITE(VLV_IMR, imr);
+	POSTING_READ(VLV_IMR);
+
+	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,
+};
+
+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);
+}
+
+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 irq;
+	int ret;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct platform_device *platdev;
+	dev_priv->ved_irq = -1;
+	dev_priv->ved_platdev = NULL;
+
+	irq = irq_alloc_descs(-1, 0, 1, 0);
+	if (irq < 0) {
+		DRM_ERROR("Failed to allocate IRQ desc: %d\n", irq);
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	ret = vlv_ved_irq_init(dev, irq);
+	if (ret) {
+		DRM_ERROR("Failed to initialize irqchip for vlv-ved: %d\n", ret);
+		goto err;
+	}
+	dev_priv->ved_irq = irq;
+
+	platdev = vlv_ved_platdev_create(dev);
+	if (IS_ERR(platdev)) {
+		DRM_ERROR("Failed to create platform device for vlv-ved: %ld\n", PTR_ERR(platdev));
+		ret = -EINVAL;
+		goto err;
+	}
+
+	dev_priv->ved_platdev = platdev;
+	return 0;
+err:
+	vlv_teardown_ved(dev);
+	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);
+	dev_priv->ved_platdev = NULL;
+	if (dev_priv->ved_irq >= 0) {
+		irq_free_desc(dev_priv->ved_irq);
+	}
+	dev_priv->ved_irq = -1;
+}
Signature · 6 lines
1.9.1

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
author
#7 lore raw

Re: [RFC PATCH v2 1/4] drm/i915: add i915_ved.c to setup bridge for VED

Quoted 18 lines

-----Original Message-----
From: Daniel Vetter [mailto:[email protected]] On Behalf Of Daniel Vetter
Sent: Tuesday, October 21, 2014 8:09 PM
To: Cheng, Yao
Cc: [email protected]; [email protected]; Kelley, Sean V; Vetter, Daniel; Abel, Michael J; Jiang, Fei; Rao, Ram R
Subject: Re: [Intel-gfx] [RFC PATCH v2 1/4] drm/i915: add i915_ved.c to setup bridge for VED

Quoted 7 lines · Yao Cheng

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.

Quoted 9 lines
Quoted 4 lines

Currently only supports VED on valleyview.
Kerneldoc is updated for i915_ved.c.

Please resend with a patch changelog to account for my review comments. And Ville's. Plus cc us both. And if there's anything you didn't address, you must reply to the review and we need to further discuss this.

Daniel, I see, thanks for the instruction.
Do you mean resending the [RFC PATCH v2] with changelog and cc list? Or adding changelog/cc when sending [RFC PATCH v3]?

Quoted 442 lines

Thanks, Daniel

drivers/gpu/drm/i915/i915_dma.c int i915_driver_load(struct drm_device *dev,

Quoted 46 lines
---
 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 |   9 ++
 drivers/gpu/drm/i915/i915_irq.c |   2 +
 drivers/gpu/drm/i915/i915_reg.h |   5 +
 drivers/gpu/drm/i915/i915_ved.c | 264
++++++++++++++++++++++++++++++++++++++++
 7 files changed, 299 insertions(+)
 create mode 100644 drivers/gpu/drm/i915/i915_ved.c
(quoted diff) +0 -0

b/Documentation/DocBook/drm.tmpl index d7cfc98..f1787b4 100644

Documentation/DocBook/drm.tmpl +0 -0
@@ -3806,6 +3806,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>
Documentation/DocBook/drm.tmpl +5 -0
+      <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 3a6bce0..a4b9252 100644

drivers/gpu/drm/i915/Makefile +3 -0
@@ -80,6 +80,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 85d14e1..47714e1 100644

drivers/gpu/drm/i915/i915_dma.c +0 -0
@@ -1791,6 +1791,13 @@ int i915_driver_load(struct drm_device *dev,

unsigned long flags)

Quoted 29 lines
drivers/gpu/drm/i915/i915_dma.c +11 -0
 	if (IS_GEN5(dev))
 		intel_gpu_ips_init(dev_priv);
 
+	if (IS_VALLEYVIEW(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 (IS_VALLEYVIEW(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 821ba26..952df34 100644

drivers/gpu/drm/i915/i915_drv.h struct drm_i915_private { · line 1716

Quoted 8 lines
drivers/gpu/drm/i915/i915_drv.h +4 -0
@@ -1709,6 +1709,10 @@ struct drm_i915_private {
 
 	uint32_t bios_vgacntr;
 
+	/* used for setup VED bridge */
+	struct platform_device *ved_platdev;
+	int	ved_irq;
+
 	/* Old dri1 support infrastructure, beware the dragons ya fools

entering

drivers/gpu/drm/i915/i915_drv.h void i915_restore_display_reg(struct

Quoted 3 lines
drivers/gpu/drm/i915/i915_drv.h +0 -0
 	 * here! */
 	struct i915_dri1_state dri1;
@@ -2785,6 +2789,11 @@ void i915_restore_display_reg(struct

drm_device

drivers/gpu/drm/i915/i915_irq.c static irqreturn_t valleyview_irq_handler(int irq,

Quoted 16 lines
drivers/gpu/drm/i915/i915_drv.h +5 -0
 *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 737b239..68c2977 100644

drivers/gpu/drm/i915/i915_irq.c +0 -0
@@ -2177,6 +2177,8 @@ static irqreturn_t valleyview_irq_handler(int irq,

void *arg)

drivers/gpu/drm/i915/i915_irq.c static irqreturn_t valleyview_irq_handler(int irq, void *arg)

Quoted 4 lines
drivers/gpu/drm/i915/i915_irq.c +1 -0
 			snb_gt_irq_handler(dev, dev_priv, gt_iir);
 		if (pm_iir)
 			gen6_rps_irq_handler(dev_priv, pm_iir);
+		if (IS_VALLEYVIEW(dev) && (iir &

VLV_VED_BLOCK_INTERRUPT))

Quoted 10 lines
drivers/gpu/drm/i915/i915_irq.c +1 -0
+			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 2ed02c3..95421ef 100644

drivers/gpu/drm/i915/i915_reg.h +0 -0
@@ -1284,6 +1284,11 @@ enum punit_power_well {  #define

VLV_DISPLAY_BASE 0x180000 #define VLV_MIPI_BASE

VLV_DISPLAY_BASE

Quoted 27 lines
drivers/gpu/drm/i915/i915_reg.h +5 -0
+/* forwarding VED irq and sharing MMIO to the VED driver */
+#define VLV_VED_BLOCK_INTERRUPT			(1 << 23)
+#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 */
(quoted diff) +0 -0

b/drivers/gpu/drm/i915/i915_ved.c new file mode 100644 index 0000000..5dfe4af

drivers/gpu/drm/i915/i915_ved.c new file +12 -0
@@ -0,0 +1,264 @@
+/*
+ * Copyright (c) 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

drivers/gpu/drm/i915/i915_ved.c line 22

Quoted 10 lines
drivers/gpu/drm/i915/i915_ved.c new file +10 -0
+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,

drivers/gpu/drm/i915/i915_ved.c line 26

Quoted 4 lines
drivers/gpu/drm/i915/i915_ved.c new file +4 -0
+EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN

NO EVENT

drivers/gpu/drm/i915/i915_ved.c line 28

Quoted 2 lines
drivers/gpu/drm/i915/i915_ved.c new file +2 -0
+SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,

DAMAGES

drivers/gpu/drm/i915/i915_ved.c line 32

Quoted 4 lines
drivers/gpu/drm/i915/i915_ved.c new file +4 -0
+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

Quoted 55 lines
drivers/gpu/drm/i915/i915_ved.c new file +55 -0
+OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Yao Cheng <[email protected]>
+ *
+ */
+
+#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 = NULL;
+	struct platform_device *platdev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+

drivers/gpu/drm/i915/i915_ved.c

Quoted 10 lines
drivers/gpu/drm/i915/i915_ved.c new file +10 -0
+	platdev = platform_device_alloc("ipvr-ved-vlv", -1);
+	if (!platdev) {
+		DRM_ERROR("Failed to allocate VED platform device\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	rsc = kzalloc(sizeof(*rsc) * 3, GFP_KERNEL);
+	if (!rsc) {
+		DRM_ERROR("Failed to allocate resource for VED platform

device\n");

drivers/gpu/drm/i915/i915_ved.c

Quoted 12 lines
drivers/gpu/drm/i915/i915_ved.c new file +12 -0
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	WARN_ON(dev_priv->ved_irq < 0);
+	rsc[0].start    = rsc[0].end = dev_priv->ved_irq;
+	rsc[0].flags    = IORESOURCE_IRQ;
+	rsc[0].name     = "ipvr-ved-vlv-irq";
+
+	/* MMIO/REG for child's use */
+	rsc[1].start    = pci_resource_start(dev->pdev, 0);
+	rsc[1].end      = pci_resource_start(dev->pdev, 0) + 2*1024*1024; /*

gen7 */

drivers/gpu/drm/i915/i915_ved.c

Quoted 11 lines
drivers/gpu/drm/i915/i915_ved.c new file +11 -0
+	rsc[1].flags    = IORESOURCE_MEM;
+	rsc[1].name     = "ipvr-ved-vlv-mmio";
+
+	rsc[2].start    = VLV_VED_BASE;
+	rsc[2].end      = VLV_VED_BASE + VLV_VED_SIZE;
+	rsc[2].flags    = IORESOURCE_REG;
+	rsc[2].name     = "ipvr-ved-vlv-reg";
+
+	ret = platform_device_add_resources(platdev, rsc, 3);
+	if (ret) {
+		DRM_ERROR("Failed to add resource for VED platform

device: %d\n", ret);

Quoted 20 lines
drivers/gpu/drm/i915/i915_ved.c new file +20 -0
+		goto err;
+	}
+
+	/* Runtime-PM hook */
+	platdev->dev.parent = dev->dev;
+	ret = platform_device_add(platdev);
+	if (ret) {
+		DRM_ERROR("Failed to add VED platform device: %d\n", ret);
+		goto err;
+	}
+
+	kfree(rsc);
+	return platdev;
+err:
+	if (rsc)
+		kfree(rsc);
+	if (platdev)
+		platform_device_unregister(platdev);
+	return ERR_PTR(ret);
+}

drivers/gpu/drm/i915/i915_ved.c

Quoted 10 lines
drivers/gpu/drm/i915/i915_ved.c new file +10 -0
+
+static void vlv_ved_platdev_destroy(struct drm_device *dev) {
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	if (dev_priv->ved_platdev)
+		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;

Quoted 10 lines
drivers/gpu/drm/i915/i915_ved.c new file +10 -0
+	unsigned long irqflags;
+	u32 imr, ier;
+	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+
+	ier = I915_READ(VLV_IER);
+	ier |= VLV_VED_BLOCK_INTERRUPT;
+	I915_WRITE(VLV_IER, ier);
+	POSTING_READ(VLV_IER);
+
+	imr = I915_READ(VLV_IMR);

drivers/gpu/drm/i915/i915_ved.c

Quoted 10 lines
drivers/gpu/drm/i915/i915_ved.c new file +10 -0
+	imr &= ~VLV_VED_BLOCK_INTERRUPT;
+	dev_priv->irq_mask = imr;
+	I915_WRITE(VLV_IMR, imr);
+	POSTING_READ(VLV_IMR);
+
+	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;

Quoted 15 lines
drivers/gpu/drm/i915/i915_ved.c new file +15 -0
+	unsigned long irqflags;
+	u32 imr, ier;
+	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+
+	ier = I915_READ(VLV_IER);
+	ier &= ~VLV_VED_BLOCK_INTERRUPT;
+	I915_WRITE(VLV_IER, ier);
+	POSTING_READ(VLV_IER);
+
+	imr = I915_READ(VLV_IMR);
+	imr |= VLV_VED_BLOCK_INTERRUPT;
+	dev_priv->irq_mask = imr;
+	I915_WRITE(VLV_IMR, imr);
+	POSTING_READ(VLV_IMR);
+

drivers/gpu/drm/i915/i915_ved.c

Quoted 10 lines
drivers/gpu/drm/i915/i915_ved.c new file +10 -0
+	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,
+};
+
+int vlv_ved_irq_init(struct drm_device *dev, int irq) {
+	struct drm_i915_private *dev_priv = (struct drm_i915_private *)

dev->dev_private;

Quoted 41 lines
drivers/gpu/drm/i915/i915_ved.c new file +13 -0
+	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);
+}
+
+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);

drivers/gpu/drm/i915/i915_ved.c new file +27 -0
+		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 irq;
+	int ret;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct platform_device *platdev;
+	dev_priv->ved_irq = -1;
+	dev_priv->ved_platdev = NULL;
+

drivers/gpu/drm/i915/i915_ved.c

Quoted 10 lines
drivers/gpu/drm/i915/i915_ved.c new file +10 -0
+	irq = irq_alloc_descs(-1, 0, 1, 0);
+	if (irq < 0) {
+		DRM_ERROR("Failed to allocate IRQ desc: %d\n", irq);
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	ret = vlv_ved_irq_init(dev, irq);
+	if (ret) {
+		DRM_ERROR("Failed to initialize irqchip for vlv-ved: %d\n",

ret);

drivers/gpu/drm/i915/i915_ved.c

Quoted 7 lines
drivers/gpu/drm/i915/i915_ved.c new file +7 -0
+		goto err;
+	}
+	dev_priv->ved_irq = irq;
+
+	platdev = vlv_ved_platdev_create(dev);
+	if (IS_ERR(platdev)) {
+		DRM_ERROR("Failed to create platform device for vlv-

ved: %ld\n", PTR_ERR(platdev));

Quoted 30 lines
drivers/gpu/drm/i915/i915_ved.c new file +27 -1
+		ret = -EINVAL;
+		goto err;
+	}
+
+	dev_priv->ved_platdev = platdev;
+	return 0;
+err:
+	vlv_teardown_ved(dev);
+	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);
+	dev_priv->ved_platdev = NULL;
+	if (dev_priv->ved_irq >= 0) {
+		irq_free_desc(dev_priv->ved_irq);
+	}
+	dev_priv->ved_irq = -1;
+}
--

1.9.1

Quoted 4 lines

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

--
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

#8 lore raw

Re: [Intel-gfx] [RFC PATCH v2 1/4] drm/i915: add i915_ved.c to setup bridge for VED

Quoted 23 lines · Yao
Quoted 23 lines

-----Original Message-----
From: Daniel Vetter [mailto:[email protected]] On Behalf Of Daniel Vetter
Sent: Tuesday, October 21, 2014 8:09 PM
To: Cheng, Yao
Cc: [email protected]; [email protected]; Kelley, Sean V; Vetter, Daniel; Abel, Michael J; Jiang, Fei; Rao, Ram R
Subject: Re: [Intel-gfx] [RFC PATCH v2 1/4] drm/i915: add i915_ved.c to setup bridge for VED

Quoted 11 lines · Yao Cheng

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.

Quoted 8 lines
Quoted 4 lines

Please resend with a patch changelog to account for my review comments. And Ville's. Plus cc us both. And if there's anything you didn't address, you must reply to the review and we need to further discuss this.

Daniel, I see, thanks for the instruction.
Do you mean resending the [RFC PATCH v2] with changelog and cc list? Or adding changelog/cc when sending [RFC PATCH v3]?

I think you could just add the per-patch changelog for both v2 and v3 when sending out v3.
-Daniel

Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
author
#9 lore raw

RE: [Intel-gfx] [RFC PATCH v2 1/4] drm/i915: add i915_ved.c to setup bridge for VED

Quoted 6 lines
Quoted 1 line
Quoted 1 line

Please resend with a patch changelog to account for my review

comments.

Quoted 4 lines
Quoted 3 lines

And Ville's. Plus cc us both. And if there's anything you didn't address, you must reply to the review and we need to further discuss this.

Quoted 7 lines
Quoted 3 lines

Daniel, I see, thanks for the instruction.
Do you mean resending the [RFC PATCH v2] with changelog and cc list? Or adding changelog/cc when sending [RFC PATCH v3]?

I think you could just add the per-patch changelog for both v2 and v3 when sending out v3.
-Daniel

Got it! Many thanks!

Quoted 4 lines

--
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

author
#10 lore raw

RFC PATCH v2 2/4 drm/ipvr: drm driver for VED

In reply to Yao Cheng

Probes VED and creates a new drm device for hardware accelerated video decoding.
Currently support VP8 decoding on valleyview.

---
 drivers/gpu/drm/Kconfig            |    2 +
 drivers/gpu/drm/Makefile           |    1 +
 drivers/gpu/drm/ipvr/Kconfig       |   16 +
 drivers/gpu/drm/ipvr/Makefile      |   21 +
 drivers/gpu/drm/ipvr/ipvr_buffer.c | 1264 +++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/ipvr/ipvr_buffer.h |  188 ++++++
 drivers/gpu/drm/ipvr/ipvr_debug.c  |  263 ++++++++
 drivers/gpu/drm/ipvr/ipvr_debug.h  |   50 ++
 drivers/gpu/drm/ipvr/ipvr_drm.h    |  267 ++++++++
 drivers/gpu/drm/ipvr/ipvr_drv.c    |  759 +++++++++++++++++++++
 drivers/gpu/drm/ipvr/ipvr_drv.h    |  442 +++++++++++++
 drivers/gpu/drm/ipvr/ipvr_exec.c   |  530 +++++++++++++++
 drivers/gpu/drm/ipvr/ipvr_exec.h   |   68 ++
 drivers/gpu/drm/ipvr/ipvr_fence.c  |  550 ++++++++++++++++
 drivers/gpu/drm/ipvr/ipvr_fence.h  |   68 ++
 drivers/gpu/drm/ipvr/ipvr_gem.c    |  191 ++++++
 drivers/gpu/drm/ipvr/ipvr_gem.h    |   46 ++
 drivers/gpu/drm/ipvr/ipvr_mmu.c    |  807 +++++++++++++++++++++++
 drivers/gpu/drm/ipvr/ipvr_mmu.h    |  135 ++++
 drivers/gpu/drm/ipvr/ipvr_trace.c  |   11 +
 drivers/gpu/drm/ipvr/ipvr_trace.h  |  296 +++++++++
 drivers/gpu/drm/ipvr/ved_cmd.c     | 1269 ++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/ipvr/ved_cmd.h     |  104 +++
 drivers/gpu/drm/ipvr/ved_ec.c      |  584 +++++++++++++++++
 drivers/gpu/drm/ipvr/ved_ec.h      |  207 ++++++
 drivers/gpu/drm/ipvr/ved_fw.c      |  660 +++++++++++++++++++
 drivers/gpu/drm/ipvr/ved_fw.h      |   73 +++
 drivers/gpu/drm/ipvr/ved_init.c    |  829 +++++++++++++++++++++++
 drivers/gpu/drm/ipvr/ved_init.h    |   61 ++
 drivers/gpu/drm/ipvr/ved_msg.h     |  364 +++++++++++
 drivers/gpu/drm/ipvr/ved_pm.c      |  392 +++++++++++
 drivers/gpu/drm/ipvr/ved_pm.h      |   55 ++
 drivers/gpu/drm/ipvr/ved_reg.h     |  609 +++++++++++++++++
 33 files changed, 11182 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_buffer.c
 create mode 100644 drivers/gpu/drm/ipvr/ipvr_buffer.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_ec.c
 create mode 100644 drivers/gpu/drm/ipvr/ved_ec.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_init.c
 create mode 100644 drivers/gpu/drm/ipvr/ved_init.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
drivers/gpu/drm/Kconfig +2 -0
index e3b4b0f..ad7585d 100644
@@ -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"
drivers/gpu/drm/Makefile +1 -0
index 9292a76..8ec4bda 100644
@@ -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/
drivers/gpu/drm/ipvr/Kconfig new file +16 -0
new file mode 100644
index 0000000..61d3117
@@ -0,0 +1,16 @@
+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.
+
+config DRM_IPVR_EC
+       bool "[EXPERIMENTAL] error concealment for IPVR decoding"
+       depends on DRM_IPVR
+       default y
+       help
+         Choose this option if you want to enable hardware error concealment for VED video decoding
drivers/gpu/drm/ipvr/Makefile new file +21 -0
new file mode 100644
index 0000000..e25a7d3
@@ -0,0 +1,21 @@
+
+ccflags-y := -Iinclude/drm
+
+ipvr-y := \
+        ipvr_gem.o \
+        ipvr_drv.o \
+        ipvr_buffer.o \
+        ipvr_exec.o \
+        ipvr_fence.o \
+        ipvr_mmu.o \
+        ipvr_debug.o \
+        ipvr_trace.o \
+        ved_pm.o \
+        ved_ec.o \
+        ved_cmd.o \
+        ved_fw.o \
+        ved_init.o
+
+obj-$(CONFIG_DRM_IPVR) += ipvr.o
+
+CFLAGS_ipvr_trace.o := -I$(src)
drivers/gpu/drm/ipvr/ipvr_buffer.c new file +1264 -0

1,264 lines not on this page · raw message

drivers/gpu/drm/ipvr/ipvr_buffer.h new file +188 -0

188 lines not on this page · raw message

drivers/gpu/drm/ipvr/ipvr_debug.c new file +263 -0

263 lines not on this page · raw message

drivers/gpu/drm/ipvr/ipvr_debug.h new file +50 -0

50 lines not on this page · raw message

drivers/gpu/drm/ipvr/ipvr_drm.h new file +267 -0

267 lines not on this page · raw message

drivers/gpu/drm/ipvr/ipvr_drv.c new file +759 -0

759 lines not on this page · raw message

drivers/gpu/drm/ipvr/ipvr_drv.h new file +442 -0

157 lines not on this page · raw message

drivers/gpu/drm/ipvr/ipvr_exec.c new file +530 -0

530 lines not on this page · raw message

drivers/gpu/drm/ipvr/ipvr_exec.h new file +68 -0

68 lines not on this page · raw message

drivers/gpu/drm/ipvr/ipvr_fence.c new file +550 -0

550 lines not on this page · raw message

drivers/gpu/drm/ipvr/ipvr_fence.h new file +68 -0

68 lines not on this page · raw message

drivers/gpu/drm/ipvr/ipvr_gem.c new file +191 -0

191 lines not on this page · raw message

drivers/gpu/drm/ipvr/ipvr_gem.h new file +46 -0

46 lines not on this page · raw message

drivers/gpu/drm/ipvr/ipvr_mmu.c new file +807 -0

807 lines not on this page · raw message

drivers/gpu/drm/ipvr/ipvr_mmu.h new file +135 -0

135 lines not on this page · raw message

drivers/gpu/drm/ipvr/ipvr_trace.c new file +11 -0
new file mode 100644
index 0000000..91c0bda

Lines of this file are not shown. View the raw message.

drivers/gpu/drm/ipvr/ipvr_trace.h new file +296 -0

296 lines not on this page · raw message

drivers/gpu/drm/ipvr/ved_cmd.c new file +1269 -0

1,269 lines not on this page · raw message

drivers/gpu/drm/ipvr/ved_cmd.h new file +104 -0

104 lines not on this page · raw message

drivers/gpu/drm/ipvr/ved_ec.c new file +584 -0

584 lines not on this page · raw message

drivers/gpu/drm/ipvr/ved_ec.h new file +207 -0

207 lines not on this page · raw message

drivers/gpu/drm/ipvr/ved_fw.c new file +660 -0

660 lines not on this page · raw message

drivers/gpu/drm/ipvr/ved_fw.h new file +73 -0

73 lines not on this page · raw message

drivers/gpu/drm/ipvr/ved_init.c new file +829 -0

829 lines not on this page · raw message

drivers/gpu/drm/ipvr/ved_init.h new file +61 -0

61 lines not on this page · raw message

drivers/gpu/drm/ipvr/ved_msg.h new file +364 -0

364 lines not on this page · raw message

drivers/gpu/drm/ipvr/ved_pm.c new file +392 -0

392 lines not on this page · raw message

drivers/gpu/drm/ipvr/ved_pm.h new file +55 -0

55 lines not on this page · raw message

drivers/gpu/drm/ipvr/ved_reg.h new file +609 -0

609 lines not on this page · raw message

The rest of this diff is not shown. View the raw message.

Signature · 6 lines
1.9.1

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

Part of the diff is not shown here. View the raw message.

#11 lore raw

Re: [RFC PATCH v2 2/4] drm/ipvr: drm driver for VED

Quoted 5 lines · Yao Cheng

Probes VED and creates a new drm device for hardware accelerated video decoding.
Currently support VP8 decoding on valleyview.

The in-patch changelog here is missing, and there's also no indication in the cover letter for what changes you've made. On a quick look you've incorporated some of David's feedback, but not all of it. That's not good, since if you only partially apply review feedback then you essentially force reviewers to read the entire patch again, which is a good way to driver them away. Also you should Cc: (in the sob section of the patch) all the people who have commented on your patch already.

With that out of the way some high-level review:
- I think we need the full libva implementation to review the interfaces properly. At least the little libdrm test program doesn't seem to fully exercise it all.

- The ioctl structs need to be cleaned up. You can't use uint32_t and similar typedefs since they can clash with userspace. You must use __u32 and friends. Also, some of the padding fields arent' really required - if you only have 4byte types then you don't need to align to 8 bytes.

- Input validation on ioctls looks spotty at best. E.g. if you have any padding fields you need to check that they are 0, otherwise we can't ever reuse them as flags fields. And on principle _all_ input fields must be validated first.

For some good guidelines for ioctls see
http://blog.ffwll.ch/2013/11/botching-up-ioctls.html

- Locking seems to be inexistent in places, at least some of the idr manipulation very much looks like it's done lock-free. That doesn't work well.

- You implement file-descriptor based fences, but then also have the more gem-traditional wait ioctl working on buffer objects. That's a bit a funky mix of implicit and explicit fencing. Furthermore adding new private fence objects isn't a good idea now that everyon is talking about de-staging android syncpts as the official userspace interface.

Also, your userspace patches don't use this, so maybe we can just rip it all out?

- I'm a bit unclear on your usage of vxd_/pvr_ prefixes.

The driver is fairly big and I don't really have the time to do a full blown review of even just the interfaces. I think we need to have some internal discussions about how to do this, but meanwhile we can cover some of the high-level bits.

Cheers, Daniel

Quoted 11,464 lines
---
 drivers/gpu/drm/Kconfig            |    2 +
 drivers/gpu/drm/Makefile           |    1 +
 drivers/gpu/drm/ipvr/Kconfig       |   16 +
 drivers/gpu/drm/ipvr/Makefile      |   21 +
 drivers/gpu/drm/ipvr/ipvr_buffer.c | 1264 +++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/ipvr/ipvr_buffer.h |  188 ++++++
 drivers/gpu/drm/ipvr/ipvr_debug.c  |  263 ++++++++
 drivers/gpu/drm/ipvr/ipvr_debug.h  |   50 ++
 drivers/gpu/drm/ipvr/ipvr_drm.h    |  267 ++++++++
 drivers/gpu/drm/ipvr/ipvr_drv.c    |  759 +++++++++++++++++++++
 drivers/gpu/drm/ipvr/ipvr_drv.h    |  442 +++++++++++++
 drivers/gpu/drm/ipvr/ipvr_exec.c   |  530 +++++++++++++++
 drivers/gpu/drm/ipvr/ipvr_exec.h   |   68 ++
 drivers/gpu/drm/ipvr/ipvr_fence.c  |  550 ++++++++++++++++
 drivers/gpu/drm/ipvr/ipvr_fence.h  |   68 ++
 drivers/gpu/drm/ipvr/ipvr_gem.c    |  191 ++++++
 drivers/gpu/drm/ipvr/ipvr_gem.h    |   46 ++
 drivers/gpu/drm/ipvr/ipvr_mmu.c    |  807 +++++++++++++++++++++++
 drivers/gpu/drm/ipvr/ipvr_mmu.h    |  135 ++++
 drivers/gpu/drm/ipvr/ipvr_trace.c  |   11 +
 drivers/gpu/drm/ipvr/ipvr_trace.h  |  296 +++++++++
 drivers/gpu/drm/ipvr/ved_cmd.c     | 1269 ++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/ipvr/ved_cmd.h     |  104 +++
 drivers/gpu/drm/ipvr/ved_ec.c      |  584 +++++++++++++++++
 drivers/gpu/drm/ipvr/ved_ec.h      |  207 ++++++
 drivers/gpu/drm/ipvr/ved_fw.c      |  660 +++++++++++++++++++
 drivers/gpu/drm/ipvr/ved_fw.h      |   73 +++
 drivers/gpu/drm/ipvr/ved_init.c    |  829 +++++++++++++++++++++++
 drivers/gpu/drm/ipvr/ved_init.h    |   61 ++
 drivers/gpu/drm/ipvr/ved_msg.h     |  364 +++++++++++
 drivers/gpu/drm/ipvr/ved_pm.c      |  392 +++++++++++
 drivers/gpu/drm/ipvr/ved_pm.h      |   55 ++
 drivers/gpu/drm/ipvr/ved_reg.h     |  609 +++++++++++++++++
 33 files changed, 11182 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_buffer.c
 create mode 100644 drivers/gpu/drm/ipvr/ipvr_buffer.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_ec.c
 create mode 100644 drivers/gpu/drm/ipvr/ved_ec.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_init.c
 create mode 100644 drivers/gpu/drm/ipvr/ved_init.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
drivers/gpu/drm/Kconfig +2 -0
index e3b4b0f..ad7585d 100644
@@ -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"
drivers/gpu/drm/Makefile +1 -0
index 9292a76..8ec4bda 100644
@@ -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/
drivers/gpu/drm/ipvr/Kconfig new file +16 -0
new file mode 100644
index 0000000..61d3117
@@ -0,0 +1,16 @@
+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.
+
+config DRM_IPVR_EC
+       bool "[EXPERIMENTAL] error concealment for IPVR decoding"
+       depends on DRM_IPVR
+       default y
+       help
+         Choose this option if you want to enable hardware error concealment for VED video decoding
drivers/gpu/drm/ipvr/Makefile new file +21 -0
new file mode 100644
index 0000000..e25a7d3
@@ -0,0 +1,21 @@
+
+ccflags-y := -Iinclude/drm
+
+ipvr-y := \
+        ipvr_gem.o \
+        ipvr_drv.o \
+        ipvr_buffer.o \
+        ipvr_exec.o \
+        ipvr_fence.o \
+        ipvr_mmu.o \
+        ipvr_debug.o \
+        ipvr_trace.o \
+        ved_pm.o \
+        ved_ec.o \
+        ved_cmd.o \
+        ved_fw.o \
+        ved_init.o
+
+obj-$(CONFIG_DRM_IPVR) += ipvr.o
+
+CFLAGS_ipvr_trace.o := -I$(src)
drivers/gpu/drm/ipvr/ipvr_buffer.c new file +1264 -0
new file mode 100644
index 0000000..bd291e0
@@ -0,0 +1,1264 @@
+/**************************************************************************
+ * ipvr_buffer.c: IPVR buffer creation, destory, 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:
+ *    Fei Jiang <[email protected]>
+ *    Yao Cheng <[email protected]>
+ *
+ **************************************************************************/
+
+#include <drmP.h>
+#include "ipvr_buffer.h"
+#include "ipvr_trace.h"
+
+extern int fake_bo_debug;
+
+/* Ensure that the associated pages are gathered from the backing storage
+ * and pinned into our object. ipvr_gem_object_get_pages() may be called
+ * multiple times before they are released by a single call to
+ * ipvr_gem_object_put_pages() - once the pages are no longer referenced
+ * either as a result of memory pressure (reaping pages under the shrinker)
+ * or as the object is itself released.
+ */
+/* for fake debug, will allocate bo with alloc_page, instead of using sg  */
+static int32_t ipvr_gem_object_get_pages(struct drm_ipvr_gem_object *obj)
+{
+	struct drm_ipvr_private *dev_priv = obj->base.dev->dev_private;
+	const struct drm_ipvr_gem_object_ops *ops = obj->ops;
+	int32_t ret, r;
+
+	if (obj->sg_table)
+		return 0;
+
+	BUG_ON(obj->pages_pin_count);
+
+	if (fake_bo_debug) {
+		gfp_t gfp_flags = GFP_USER | GFP_DMA32 | __GFP_IO;
+		struct page *p = NULL;
+		obj->fake_pages =
+			drm_calloc_large(obj->base.size / 4096, sizeof(void*));
+		IPVR_DEBUG_GENERAL("fake call alloc_page to alloc pages.\n");
+		for (r = 0; r < obj->base.size / 4096; ++r) {
+			p = alloc_page(gfp_flags);
+			if (!p) {
+				IPVR_ERROR("Unable to allocate page\n");
+				return -ENOMEM;
+			}
+			obj->fake_pages[r] = p;
+			switch (obj->cache_level) {
+			case IPVR_CACHE_NONE:
+				ret = set_pages_uc(p, 1);
+				break;
+			case IPVR_CACHE_WC:
+				ret = set_memory_wc(
+					(unsigned long)page_address(p), 1);
+				break;
+			case IPVR_CACHE_WB:
+				ret = set_pages_wb(p, 1);
+				break;
+			default:
+				ret = -EINVAL;
+				break;
+			}
+			if (ret) {
+				IPVR_DEBUG_WARN("failed to set page cache.\n");
+				return -ENOMEM;
+			}
+		}
+	}
+	/* will call ipvr_gem_object_get_pages_mmu */
+	ret = ops->get_pages(obj);
+	if (ret) {
+		IPVR_ERROR("failed to call ops->get_pages\n");
+		return ret;
+	}
+
+	/* do we need lock here? */
+	list_add_tail(&obj->global_list, &dev_priv->ipvr_mm.unbound_list);
+	return 0;
+}
+
+static int32_t ipvr_gem_object_put_pages(struct drm_ipvr_gem_object *obj)
+{
+	const struct drm_ipvr_gem_object_ops *ops = obj->ops;
+
+	if (obj->sg_table == NULL)
+		return 0;
+
+	if (obj->pages_pin_count)
+		return -EBUSY;
+
+	list_del(&obj->global_list);
+
+	ops->put_pages(obj);
+	obj->sg_table = NULL;
+
+	return 0;
+}
+
+static int32_t ipvr_gem_object_get_pages_sg(struct drm_ipvr_gem_object *obj)
+{
+	uint32_t page_count, i;
+	struct address_space *mapping;
+	struct sg_table *st;
+	struct scatterlist *sg;
+	struct sg_page_iter sg_iter;
+	struct page *page = NULL;
+	struct page **page_array = NULL;
+	int carray = 0;
+	unsigned long last_pfn = 0;	/* suppress gcc warning */
+	gfp_t gfp;
+	int32_t ret;
+
+	/* Assert that the object is not currently in any GPU domain. As it
+	 * wasn't in the MMU, there shouldn't be any way it could have been in
+	 * a GPU cache
+	 */
+	BUG_ON(obj->base.read_domains & IPVR_GEM_DOMAIN_GPU);
+	BUG_ON(obj->base.write_domain & IPVR_GEM_DOMAIN_GPU);
+
+	st = kmalloc(sizeof(*st), GFP_KERNEL);
+	if (st == NULL)
+		return -ENOMEM;
+
+	page_count = obj->base.size / PAGE_SIZE;
+
+	if (sg_alloc_table(st, page_count, GFP_KERNEL)) {
+		sg_free_table(st);
+		kfree(st);
+		return -ENOMEM;
+	}
+
+	page_array = kmalloc(page_count * sizeof(struct page *), GFP_KERNEL);
+	if (unlikely(!page_array)) {
+		sg_free_table(st);
+		kfree(st);
+		return -ENOMEM;
+	}
+	/* Get the list of pages out of our struct file.  They'll be pinned
+	 * at this point until we release them.
+	 *
+	 * Fail silently without starting the shrinker
+	 */
+	mapping = file_inode(obj->base.filp)->i_mapping;
+	gfp = mapping_gfp_mask(mapping);
+	/* todo: need set correct gfp */
+	gfp |= __GFP_NORETRY | __GFP_NOWARN | __GFP_NO_KSWAPD;
+	gfp |= GFP_DMA32 | __GFP_IO;
+	sg = st->sgl;
+	st->nents = 0;
+	for (i = 0; i < page_count; i++) {
+		page = shmem_read_mapping_page_gfp(mapping, i, gfp);
+		if (IS_ERR(page)) {
+			/* doesn't support shrink
+			 * since ipvr has 4GiB address space */
+			goto err_pages;
+		}
+		page_array[carray++] = page;
+
+#ifdef CONFIG_SWIOTLB
+		if (swiotlb_nr_tbl()) {
+			st->nents++;
+			sg_set_page(sg, page, PAGE_SIZE, 0);
+			sg = sg_next(sg);
+			continue;
+		}
+#endif
+		if (!i || page_to_pfn(page) != last_pfn + 1) {
+			if (i)
+				sg = sg_next(sg);
+			st->nents++;
+			sg_set_page(sg, page, PAGE_SIZE, 0);
+		} else {
+			sg->length += PAGE_SIZE;
+		}
+		last_pfn = page_to_pfn(page);
+	}
+#ifdef CONFIG_SWIOTLB
+	if (!swiotlb_nr_tbl())
+#endif
+		sg_mark_end(sg);
+	obj->sg_table = st;
+
+	switch (obj->cache_level) {
+	case IPVR_CACHE_NONE:
+		ret = set_pages_array_uc(page_array, carray);
+		break;
+	case IPVR_CACHE_WC:
+		ret = set_pages_array_wc(page_array, carray);
+		break;
+	case IPVR_CACHE_WB:
+		ret = set_pages_array_wb(page_array, carray);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	if (ret) {
+		IPVR_DEBUG_WARN("failed to set page cache.\n");
+		goto err_pages;
+	}
+	kfree(page_array);
+	return 0;
+
+err_pages:
+	sg_mark_end(sg);
+	for_each_sg_page(st->sgl, &sg_iter, st->nents, 0)
+		page_cache_release(sg_page_iter_page(&sg_iter));
+	sg_free_table(st);
+	kfree(st);
+	if (page_array)
+		kfree(page_array);
+	return PTR_ERR(page);
+}
+
+static bool cpu_cache_is_coherent(struct drm_device *dev,
+					enum ipvr_cache_level level)
+{
+	/* todo: need check if cache snoop is enabled */
+	if (level == IPVR_CACHE_WB)
+		return false;
+	else
+		return true;
+}
+
+bool ipvr_gem_clflush_object(struct drm_ipvr_gem_object *obj, bool force)
+{
+	/* If we don't have a page list set up, then we're not pinned
+	 * to GPU, and we can ignore the cache flush because it'll happen
+	 * again at bind time.
+	 */
+	if (obj->sg_table == NULL)
+		return false;
+
+	/* If the GPU is snooping the contents of the CPU cache,
+	 * we do not need to manually clear the CPU cache lines.  However,
+	 * the caches are only snooped when the render cache is
+	 * flushed/invalidated.  As we always have to emit invalidations
+	 * and flushes when moving into and out of the RENDER domain, correct
+	 * snooping behaviour occurs naturally as the result of our domain
+	 * tracking.
+	 */
+	if (!force && cpu_cache_is_coherent(obj->base.dev, obj->cache_level))
+		return false;
+
+	drm_clflush_sg(obj->sg_table);
+
+	return true;
+}
+
+/**
+ * Moves a single object to the CPU read, and possibly write domain.
+ *
+ * This function returns when the move is complete, including waiting on
+ * flushes to occur.
+ */
+int32_t
+ipvr_gem_object_set_to_cpu_domain(struct drm_ipvr_gem_object *obj, bool write)
+{
+	uint32_t old_write_domain, old_read_domains;
+	int32_t ret;
+
+	if (obj->base.write_domain == IPVR_GEM_DOMAIN_CPU)
+		return 0;
+
+	ret = ipvr_fence_wait(obj->fence, true, false);
+	if (ret)
+		return ret;
+
+	old_write_domain = obj->base.write_domain;
+	old_read_domains = obj->base.read_domains;
+
+	/* Flush the CPU cache if it's still invalid. */
+	if ((obj->base.read_domains & IPVR_GEM_DOMAIN_CPU) == 0) {
+		ipvr_gem_clflush_object(obj, false);
+
+		obj->base.read_domains |= IPVR_GEM_DOMAIN_CPU;
+	}
+
+	/* It should now be out of any other write domains, and we can update
+	 * the domain values for our changes.
+	 */
+	BUG_ON((obj->base.write_domain & ~IPVR_GEM_DOMAIN_CPU) != 0);
+
+	/* If we're writing through the CPU, then the GPU read domains will
+	 * need to be invalidated at next use.
+	 */
+	if (write) {
+		obj->base.read_domains = IPVR_GEM_DOMAIN_CPU;
+		obj->base.write_domain = IPVR_GEM_DOMAIN_CPU;
+	}
+
+	return 0;
+}
+
+static void ipvr_gem_object_put_pages_sg(struct drm_ipvr_gem_object *obj)
+{
+	struct sg_page_iter sg_iter;
+	int32_t ret;
+
+	ret = ipvr_gem_object_set_to_cpu_domain(obj, true);
+	if (ret) {
+		/* In the event of a disaster, abandon all caches and
+		 * hope for the best.
+		 */
+		WARN_ON(ret != -EIO);
+		ipvr_gem_clflush_object(obj, true);
+		obj->base.read_domains = IPVR_GEM_DOMAIN_CPU;
+		obj->base.write_domain = IPVR_GEM_DOMAIN_CPU;
+	}
+
+	IPVR_DEBUG_GENERAL("start to free pages.\n");
+	for_each_sg_page(obj->sg_table->sgl,
+			&sg_iter, obj->sg_table->nents, 0) {
+		struct page *page = sg_page_iter_page(&sg_iter);
+
+		if (obj->dirty)
+			set_page_dirty(page);
+		/* need set back to wb before release page */
+		ret = set_pages_wb(page, 1);
+		if (ret)
+			IPVR_ERROR("failed to set page as wb.\n");
+		page_cache_release(page);
+	}
+	obj->dirty = 0;
+
+	sg_free_table(obj->sg_table);
+	kfree(obj->sg_table);
+}
+
+static const struct drm_ipvr_gem_object_ops ipvr_gem_object_ops = {
+	.get_pages = ipvr_gem_object_get_pages_sg,
+	.put_pages = ipvr_gem_object_put_pages_sg,
+};
+
+/* All the new VM stuff */
+unsigned long ipvr_gem_obj_mmu_offset(struct drm_ipvr_gem_object *obj)
+{
+	struct drm_ipvr_private *dev_priv = obj->base.dev->dev_private;
+	struct ipvr_vma *vma;
+
+	struct ipvr_address_space *vm = &dev_priv->addr_space;
+
+	BUG_ON(list_empty(&obj->vma_list));
+	list_for_each_entry(vma, &obj->vma_list, vma_link) {
+		/* todo: for user ptr obj, need consider offset in page in future */
+		if (vma->vm == vm) {
+			IPVR_DEBUG_GENERAL("node start is 0x%lx.\n",
+					vma->node.start);
+			return vma->node.start;
+		}
+	}
+
+	IPVR_ERROR("failed to find vma corresponding to this bo.\n");
+	return IPVR_ERR_OFFSET(-EINVAL);
+}
+
+static void *ipvr_gem_object_alloc(struct drm_device *dev)
+{
+	struct drm_ipvr_private *dev_priv = dev->dev_private;
+	if (dev_priv == NULL)
+		IPVR_ERROR("error: dev_prive is NULL.\n");
+	return kmem_cache_alloc(dev_priv->ipvr_bo_slab, GFP_KERNEL | __GFP_ZERO);
+}
+
+static void ipvr_gem_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);
+}
+
+/* some bookkeeping */
+static void
+ipvr_gem_info_add_obj(struct drm_ipvr_private *dev_priv, size_t size)
+{
+	spin_lock(&dev_priv->ipvr_mm.object_stat_lock);
+	dev_priv->ipvr_mm.object_count++;
+	dev_priv->ipvr_mm.object_memory += size;
+	spin_unlock(&dev_priv->ipvr_mm.object_stat_lock);
+}
+
+static void
+ipvr_gem_info_remove_obj(struct drm_ipvr_private *dev_priv, size_t size)
+{
+	spin_lock(&dev_priv->ipvr_mm.object_stat_lock);
+	dev_priv->ipvr_mm.object_count--;
+	dev_priv->ipvr_mm.object_memory -= size;
+	spin_unlock(&dev_priv->ipvr_mm.object_stat_lock);
+}
+
+void ipvr_gem_object_init(struct drm_ipvr_gem_object *obj,
+				const struct drm_ipvr_gem_object_ops *ops)
+{
+	INIT_LIST_HEAD(&obj->global_list);
+	INIT_LIST_HEAD(&obj->vma_list);
+
+	obj->ops = ops;
+
+	ipvr_gem_info_add_obj(obj->base.dev->dev_private, obj->base.size);
+}
+
+struct drm_ipvr_gem_object *
+ipvr_gem_alloc_object(struct drm_device *dev, size_t size)
+{
+	struct drm_ipvr_gem_object *obj;
+	struct address_space *mapping;
+	gfp_t mask;
+
+	obj = ipvr_gem_object_alloc(dev);
+	if (obj == NULL)
+		return NULL;
+	memset(obj, 0, sizeof(*obj));
+
+	if (drm_gem_object_init(dev, &obj->base, size) != 0) {
+		ipvr_gem_object_free(obj);
+		return NULL;
+	}
+
+	init_waitqueue_head(&obj->event_queue);
+	atomic_set(&obj->cpu_writers, 0);
+	/* 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);
+
+	ipvr_gem_object_init(obj, &ipvr_gem_object_ops);
+
+	obj->base.write_domain = IPVR_GEM_DOMAIN_CPU;
+	obj->base.read_domains = IPVR_GEM_DOMAIN_CPU;
+
+	return obj;
+}
+
+int32_t ipvr_gem_mmu_bind_object(struct drm_ipvr_gem_object *obj)
+{
+	struct drm_ipvr_private *dev_priv = obj->base.dev->dev_private;
+	uint32_t ret, type = 0;
+	const unsigned long entry = ipvr_gem_obj_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);
+
+	/* todo: it is better also pass RO, WO info */
+	type = (obj->cache_level == IPVR_CACHE_WB) ?
+						IPVR_MMU_CACHED_MEMORY : 0;
+
+	/* should not use dev_priv->pf_pd */
+	if (fake_bo_debug) {
+		ret = ipvr_mmu_insert_pages(dev_priv->mmu->default_pd,
+			obj->fake_pages,
+			entry, obj->base.size >> PAGE_SHIFT,
+			0,
+			0, type);
+	} else {
+		uint32_t i = 0;
+		struct page **pages;
+		struct sg_page_iter sg_iter;
+		pages = drm_malloc_ab(obj->base.size >> PAGE_SHIFT,
+				sizeof(*pages));
+		if (pages == NULL) {
+			IPVR_ERROR("Failed to get space for pages\n");
+			return -ENOMEM;
+		}
+		for_each_sg_page(obj->sg_table->sgl, &sg_iter,
+				obj->sg_table->nents, 0)
+			pages[i++] = sg_page_iter_page(&sg_iter);
+		ret = ipvr_mmu_insert_pages(dev_priv->mmu->default_pd,
+			pages, entry, obj->base.size >> PAGE_SHIFT,
+			0, 0, type);
+		if (pages)
+			drm_free_large(pages);
+	}
+	return ret;
+}
+
+uint64_t ipvr_gem_mmap_offset(struct drm_ipvr_gem_object *obj)
+{
+	int32_t ret;
+	ret = drm_gem_create_mmap_offset(&obj->base);
+
+	if (ret) {
+		IPVR_ERROR("could not allocate mmap offset: %d\n", ret);
+		return 0;
+	}
+
+	return drm_vma_node_offset_addr(&obj->base.vma_node);
+}
+
+int32_t ipvr_gem_create(struct drm_file *file_priv, struct drm_device *dev,
+			uint64_t size, uint32_t tiling, uint32_t cache_level,
+			uint64_t *rsize_p, uint32_t *handle_p,
+			uint64_t *offset_p, uint64_t *map_handle_p)
+{
+	struct drm_ipvr_gem_object *obj;
+	int32_t ret;
+	uint32_t handle;
+	struct drm_ipvr_private *dev_priv = dev->dev_private;
+	IPVR_DEBUG_GENERAL("create bo size is %lld, tiling is %d, "
+			"cache level is %d.\n",
+			size, tiling, cache_level);
+
+	size = roundup(size, PAGE_SIZE);
+	if (size == 0)
+		return -EINVAL;
+	*rsize_p = size;
+
+	/* Allocate the new object */
+	obj = ipvr_gem_alloc_object(dev, size);
+	if (obj == NULL)
+		return -ENOMEM;
+	obj->drv_name = "ipvr";
+	obj->fence = NULL;
+	obj->tiling = tiling;
+	obj->cache_level = cache_level;
+	ret = drm_gem_handle_create(file_priv, &obj->base, &handle);
+	/* drop reference from allocate - handle holds it now */
+	drm_gem_object_unreference_unlocked(&obj->base);
+	if (ret)
+		return ret;
+	*handle_p = handle;
+
+	/* force to get pages at allocation stage */
+	ret = ipvr_gem_object_bind_to_vm(obj, &dev_priv->addr_space, 4096);
+	if (ret) {
+		IPVR_ERROR("failed to call ipvr_gem_object_bind_to_vm: %d.\n", ret);
+		ipvr_gem_free_object(&obj->base);
+		return ret;
+	}
+
+	ret = ipvr_gem_mmu_bind_object(obj);
+	if (ret) {
+		IPVR_ERROR("failed to call ipvr_gem_mmu_bind_object: %d.\n", ret);
+		ipvr_gem_free_object(&obj->base);
+		return ret;
+	}
+
+	*offset_p = ipvr_gem_obj_mmu_offset(obj);
+	if (IPVR_IS_ERR(*offset_p))
+		return IPVR_OFFSET_ERR(*offset_p);
+
+	/* Make it mmapable */
+	*map_handle_p = ipvr_gem_mmap_offset(obj);
+
+	IPVR_DEBUG_GENERAL("bo create done, gpu offset: 0x%llx.\n", *offset_p);
+
+	trace_ipvr_gem_create(obj, *offset_p);
+
+	return 0;
+}
+
+struct drm_ipvr_gem_object *
+ipvr_gem_obj_create_and_bind(struct drm_device *dev, size_t size)
+{
+	uint32_t ret;
+	struct drm_ipvr_gem_object *obj;
+	struct drm_ipvr_private *dev_priv = dev->dev_private;
+
+	size = roundup(size, PAGE_SIZE);
+	if (size == 0) {
+		IPVR_ERROR("Passed size is 0, not correct.\n");
+		return NULL;
+	}
+
+	/* Allocate the new object */
+	obj = ipvr_gem_alloc_object(dev, size);
+	if (obj == NULL) {
+		IPVR_ERROR("Failed to allocate ipvr object.\n");
+		return NULL;
+	}
+
+	ret = ipvr_gem_object_bind_to_vm(obj, &dev_priv->addr_space, 4096);
+	if (ret) {
+		IPVR_ERROR("Failed to bind obj to vm.\n");
+		ipvr_gem_free_object(&obj->base);
+		return NULL;
+	}
+	ret = ipvr_gem_mmu_bind_object(obj);
+	if (ret) {
+		IPVR_ERROR("Failed to bind obj to mmu.\n");
+		ipvr_gem_free_object(&obj->base);
+		return NULL;
+	}
+
+	return obj;
+}
+
+struct ipvr_vma *ipvr_gem_obj_to_vma(struct drm_ipvr_gem_object *obj,
+					struct ipvr_address_space *vm)
+{
+	struct ipvr_vma *vma;
+	list_for_each_entry(vma, &obj->vma_list, vma_link)
+		if (vma->vm == vm)
+			return vma;
+
+	return NULL;
+}
+
+struct ipvr_vma *ipvr_gem_vma_create(struct drm_ipvr_gem_object *obj,
+					struct ipvr_address_space *vm)
+{
+	struct ipvr_vma *vma = kzalloc(sizeof(*vma), GFP_KERNEL);
+	if (vma == NULL)
+		return ERR_PTR(-ENOMEM);
+
+	INIT_LIST_HEAD(&vma->vma_link);
+	INIT_LIST_HEAD(&vma->mm_list);
+	vma->vm = vm;
+	vma->obj = obj;
+
+	list_add_tail(&vma->vma_link, &obj->vma_list);
+
+	return vma;
+}
+
+static void ipvr_gem_vma_destroy(struct ipvr_vma *vma)
+{
+	WARN_ON(vma->node.allocated);
+	list_del(&vma->vma_link);
+	kfree(vma);
+}
+
+struct ipvr_vma *
+ipvr_gem_obj_lookup_or_create_vma(struct drm_ipvr_gem_object *obj,
+						struct ipvr_address_space *vm)
+{
+	struct ipvr_vma *vma;
+
+	vma = ipvr_gem_obj_to_vma(obj, vm);
+	if (!vma)
+		vma = ipvr_gem_vma_create(obj, vm);
+
+	return vma;
+}
+
+void ipvr_gem_object_pin_pages(struct drm_ipvr_gem_object *obj)
+{
+	BUG_ON(obj->sg_table == NULL);
+	obj->pages_pin_count++;
+}
+
+void ipvr_gem_object_unpin_pages(struct drm_ipvr_gem_object *obj)
+{
+	BUG_ON(obj->pages_pin_count == 0);
+	obj->pages_pin_count--;
+}
+
+static bool ipvr_gem_valid_mmu_space(struct drm_device *dev,
+						struct drm_mm_node *mmu_space,
+						uint32_t cache_level)
+{
+	struct drm_mm_node *other;
+
+	if (!drm_mm_node_allocated(mmu_space))
+		return true;
+
+	if (list_empty(&mmu_space->node_list))
+		return true;
+
+	other = list_entry(mmu_space->node_list.prev,
+			struct drm_mm_node, node_list);
+	if (other->allocated && !other->hole_follows &&
+				other->color != cache_level)
+		return false;
+
+	other = list_entry(mmu_space->node_list.next,
+			struct drm_mm_node, node_list);
+	if (other->allocated && !mmu_space->hole_follows &&
+				other->color != cache_level)
+		return false;
+
+	return true;
+}
+
+/**
+ * Finds free space in the MMU aperture and binds the object there.
+ */
+int32_t ipvr_gem_object_bind_to_vm(struct drm_ipvr_gem_object *obj,
+					struct ipvr_address_space *vm,
+					uint32_t alignment)
+{
+	struct drm_device *dev = obj->base.dev;
+	struct drm_ipvr_private *dev_priv = dev->dev_private;
+	struct ipvr_vma *vma;
+	unsigned long start, end, size;
+	int32_t ret;
+	struct drm_mm *mm;
+	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;
+	}
+	size = obj->base.size;
+
+	ret = ipvr_gem_object_get_pages(obj);
+	if (ret) {
+		IPVR_ERROR("failed to call ipvr_gem_object_get_pages.\n");
+		return ret;
+	}
+
+	ipvr_gem_object_pin_pages(obj);
+
+	vma = ipvr_gem_obj_lookup_or_create_vma(obj, vm);
+	if (IS_ERR(vma)) {
+		ret = PTR_ERR(vma);
+		IPVR_ERROR("failed on ipvr_gem_obj_lookup_or_create_vma.\n");
+		goto err_unpin;
+	}
+
+	/* For now we only ever use 1 vma per object */
+	BUG_ON(!list_is_singular(&obj->vma_list));
+
+	IPVR_DEBUG_GENERAL("call drm_mm_insert_node_in_range_generic.\n");
+	ret = drm_mm_insert_node_in_range_generic(mm, &vma->node, size,
+						alignment, obj->cache_level,
+						start, end,
+						DRM_MM_SEARCH_DEFAULT,
+						DRM_MM_CREATE_DEFAULT);
+	if (ret) {
+		/*
+		 * ipvr doesn't support shrink so far since it has 4GiB addr space
+		 */
+		IPVR_ERROR("failed on drm_mm_insert_node_in_range_generic.\n");
+		goto err_free_vma;
+	}
+
+	if (unlikely(!ipvr_gem_valid_mmu_space(dev, &vma->node,
+					obj->cache_level))) {
+		ret = -EINVAL;
+		IPVR_ERROR("failed on ipvr_gem_valid_mmu_space.\n");
+		goto err_remove_node;
+	}
+
+	list_move_tail(&obj->global_list, &dev_priv->ipvr_mm.bound_list);
+	list_add_tail(&vma->mm_list, &vm->inactive_list);
+
+	/* ipvr_gem_verify_gtt can be added here for debug */
+	return 0;
+
+err_remove_node:
+	drm_mm_remove_node(&vma->node);
+err_free_vma:
+	ipvr_gem_vma_destroy(vma);
+err_unpin:
+	ipvr_gem_object_unpin_pages(obj);
+	return ret;
+}
+
+void *ipvr_gem_object_vmap(struct drm_ipvr_gem_object *obj)
+{
+	int32_t i;
+	void *addr = NULL;
+	struct sg_page_iter sg_iter;
+	struct page **pages;
+
+	if (fake_bo_debug) {
+		addr = vmap(obj->fake_pages, obj->base.size / 4096,
+			VM_MAP, pgprot_writecombine(PAGE_KERNEL));
+		if (addr == NULL) {
+			IPVR_ERROR("Failed to vmap pages\n");
+			return ERR_PTR(-ENOMEM);
+		}
+		return addr;
+	}
+
+	pages = drm_malloc_ab(obj->base.size >> PAGE_SHIFT, sizeof(*pages));
+	if (pages == NULL) {
+		IPVR_ERROR("Failed to get space for pages\n");
+		goto finish;
+	}
+
+	i = 0;
+	for_each_sg_page(obj->sg_table->sgl, &sg_iter,
+			obj->sg_table->nents, 0) {
+		pages[i] = sg_page_iter_page(&sg_iter);
+		i++;
+	}
+
+	addr = vmap(pages, i, VM_MAP, pgprot_writecombine(PAGE_KERNEL));
+	if (addr == NULL) {
+		IPVR_ERROR("Failed to vmap pages\n");
+		goto finish;
+	}
+
+finish:
+	if (pages)
+		drm_free_large(pages);
+	return addr;
+}
+
+int32_t ipvr_gem_object_finish_gpu(struct drm_ipvr_gem_object *obj)
+{
+	int32_t ret = 0;
+
+	if ((obj->base.read_domains & IPVR_GEM_DOMAIN_GPU) == 0)
+		return ret;
+
+	/* Ensure that we invalidate the GPU's caches and TLBs. */
+	obj->base.read_domains &= ~IPVR_GEM_DOMAIN_GPU;
+	return ret;
+}
+
+/**
+ * ipvr_gem_release_mmap - remove physical page mappings
+ * @obj: obj in question
+ *
+ * If the object has been moved out of the aperture,
+ * then pages mapped into userspace must be revoked. Removing the
+ * mapping will then trigger a page fault on the next user access, allowing
+ * fixup by ipvr_gem_fault().
+ */
+void ipvr_gem_release_mmap(struct drm_ipvr_gem_object *obj)
+{
+	/* todo:
+	 * will not call drm_gem_create_mmap_offset,
+	 * ipvr dont' need use mmap for dev map
+	 */
+	drm_vma_node_unmap(&obj->base.vma_node,
+			   obj->base.dev->anon_inode->i_mapping);
+
+	/* todo:
+	 * it seems it need cause kernel panic, disable vm_munmap as workaround
+	 */
+	if (obj->mmap_base) {
+		IPVR_DEBUG_GENERAL("call vm_munmap to unmap bo, base is 0x%lx.\n",
+				obj->mmap_base);
+		obj->mmap_base = 0;
+	}
+}
+
+int32_t ipvr_gem_object_vma_unbind(struct ipvr_vma *vma)
+{
+	struct drm_ipvr_gem_object *obj = vma->obj;
+	drm_ipvr_private_t *dev_priv = obj->base.dev->dev_private;
+	unsigned long entry;
+	int32_t ret;
+
+	if (list_empty(&vma->vma_link))
+		return 0;
+
+	if (!drm_mm_node_allocated(&vma->node))
+		goto destroy;
+
+	if (obj->pin_count)
+		return -EBUSY;
+
+	BUG_ON(obj->sg_table == NULL);
+	entry = ipvr_gem_obj_mmu_offset(obj);
+	if (IPVR_IS_ERR(entry))
+		return IPVR_OFFSET_ERR(entry);
+
+	ret = ipvr_gem_object_finish_gpu(obj);
+	if (ret)
+		return ret;
+
+	/* Continue on if we fail due to EIO, the GPU is hung so we
+	 * should be safe and we need to cleanup or else we might
+	 * cause memory corruption through use-after-free.
+	 */
+	ipvr_gem_release_mmap(obj);
+
+	/* remove the bo from the mmu */
+	ipvr_mmu_remove_pages(dev_priv->mmu->default_pd, entry,
+			obj->base.size >> PAGE_SHIFT, 0, 0);
+
+	ipvr_gem_object_unpin_pages(obj);
+
+	list_del(&vma->mm_list);
+
+	drm_mm_remove_node(&vma->node);
+
+destroy:
+	ipvr_gem_vma_destroy(vma);
+
+	/* Since the unbound list is global, only move to that list if
+	 * no more VMAs exist.
+	 * NB: Until we have real VMAs there will only ever be one */
+	WARN_ON(!list_empty(&obj->vma_list));
+	if (list_empty(&obj->vma_list))
+		list_move_tail(&obj->global_list,
+			&dev_priv->ipvr_mm.unbound_list);
+
+	return 0;
+}
+
+static void ipvr_gem_object_free_mmap_offset(struct drm_ipvr_gem_object *obj)
+{
+	drm_gem_free_mmap_offset(&obj->base);
+}
+
+/**
+ * Called after the last reference to the object has been lost.
+ * Must be called holding struct_ mutex
+ *
+ * Frees the object
+ */
+static void ipvr__gem_free_object(struct kref *kref)
+{
+	struct drm_gem_object *gem_obj = (struct drm_gem_object *)kref;
+	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;
+	struct ipvr_vma *vma, *next;
+	int32_t ret;
+
+	// FIXME: consider unlocked case
+	WARN_ON(!mutex_is_locked(&dev->struct_mutex));
+
+	drm_gem_free_mmap_offset(gem_obj);
+
+	if (obj->fence) {
+		ret = ipvr_fence_wait(obj->fence, true, false);
+		if (ret)
+			IPVR_DEBUG_WARN("Failed to wait fence signaled.\n");
+	}
+
+	obj->pin_count = 0;
+	/* NB: 0 or 1 elements */
+	WARN_ON(!list_empty(&obj->vma_list) &&
+		!list_is_singular(&obj->vma_list));
+	list_for_each_entry_safe(vma, next, &obj->vma_list, vma_link) {
+		int ret = ipvr_gem_object_vma_unbind(vma);
+		if (WARN_ON(ret == -ERESTARTSYS)) {
+			bool was_interruptible;
+
+			was_interruptible = dev_priv->ipvr_mm.interruptible;
+			dev_priv->ipvr_mm.interruptible = false;
+
+			WARN_ON(ipvr_gem_object_vma_unbind(vma));
+
+			dev_priv->ipvr_mm.interruptible = was_interruptible;
+		}
+	}
+
+	if (WARN_ON(obj->pages_pin_count))
+		obj->pages_pin_count = 0;
+	ipvr_gem_object_put_pages(obj);
+	ipvr_gem_object_free_mmap_offset(obj);
+
+	BUG_ON(obj->sg_table);
+
+	if (obj->base.import_attach)
+		drm_prime_gem_destroy(&obj->base, NULL);
+
+	if (obj->ops->release)
+		obj->ops->release(obj);
+
+	drm_gem_object_release(&obj->base);
+	ipvr_gem_info_remove_obj(dev_priv, obj->base.size);
+
+	trace_ipvr__gem_free_object(obj);
+
+	ipvr_gem_object_free(obj);
+}
+
+/*
+ * 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)
+{
+	ipvr__gem_free_object((struct kref *)gem_obj);
+}
+
+static struct
+ipvr_gem_userptr_object *to_userptr_object(struct drm_ipvr_gem_object *obj)
+{
+	return container_of(obj, struct ipvr_gem_userptr_object, gem);
+}
+
+static int32_t ipvr_gem_userptr_get_pages_sg(struct drm_ipvr_gem_object *obj) {
+	struct ipvr_gem_userptr_object *vmap = to_userptr_object(obj);
+	int32_t num_pages = obj->base.size >> PAGE_SHIFT;
+	struct sg_table *st;
+	struct scatterlist *sg;
+	struct page **pvec;
+	int32_t n, pinned, ret;
+
+	if (!access_ok(vmap->read_only ? VERIFY_READ : VERIFY_WRITE,
+		       (char __user *)vmap->user_ptr, vmap->user_size)) {
+		IPVR_ERROR("access_ok check failed.\n");
+		return -EFAULT;
+	}
+
+	/* If userspace should engineer that these pages are replaced in
+	 * the vma between us binding this page into the GTT and completion
+	 * of rendering... Their loss. If they change the mapping of their
+	 * pages they need to create a new bo to point to the new vma.
+	 *
+	 * However, that still leaves open the possibility of the vma
+	 * being copied upon fork. Which falls under the same userspace
+	 * synchronisation issue as a regular bo, except that this time
+	 * the process may not be expecting that a particular piece of
+	 * memory is tied to the GPU.
+	 *
+	 * Fortunately, we can hook into the mmu_notifier in order to
+	 * discard the page references prior to anything nasty happening
+	 * to the vma (discard or cloning) which should prevent the more
+	 * egregious cases from causing harm.
+	 */
+
+	pvec = kmalloc(num_pages * sizeof(struct page *),
+		       GFP_KERNEL | __GFP_NOWARN | __GFP_NORETRY);
+	if (pvec == NULL) {
+		pvec = drm_malloc_ab(num_pages, sizeof(struct page *));
+		if (pvec == NULL) {
+			IPVR_ERROR("pvec alloc failure\n");
+			return -ENOMEM;
+		}
+	}
+
+	pinned = __get_user_pages_fast(vmap->user_ptr, num_pages,
+				!vmap->read_only, pvec);
+	if (pinned < num_pages) {
+		struct mm_struct *mm = current->mm;
+		ret = 0;
+		down_read(&mm->mmap_sem);
+		ret = get_user_pages(current, mm,
+				vmap->user_ptr + (pinned << PAGE_SHIFT),
+				num_pages - pinned,
+				!vmap->read_only, 0,
+				pvec + pinned,
+				NULL);
+		up_read(&mm->mmap_sem);
+		if (ret > 0)
+			pinned += ret;
+
+		if (obj->sg_table || pinned < num_pages) {
+			ret = obj->sg_table ? 0 : -EFAULT;
+			IPVR_ERROR("obj->sg_table is NULL\n");
+			goto cleanup_pinned;
+		}
+	}
+
+	st = kmalloc(sizeof(*st), GFP_KERNEL);
+	if (st == NULL) {
+		ret = -ENOMEM;
+		goto cleanup_pinned;
+	}
+
+	if (sg_alloc_table(st, num_pages, GFP_KERNEL)) {
+		ret = -ENOMEM;
+		goto cleanup_st;
+	}
+
+	for_each_sg(st->sgl, sg, num_pages, n)
+		sg_set_page(sg, pvec[n], PAGE_SIZE, 0);
+	drm_free_large(pvec);
+
+	obj->sg_table = st;
+	return 0;
+
+cleanup_st:
+	kfree(st);
+cleanup_pinned:
+	release_pages(pvec, pinned, 0);
+	drm_free_large(pvec);
+	return ret;
+}
+
+static void ipvr_gem_userptr_put_pages_sg(struct drm_ipvr_gem_object *obj) {
+	struct scatterlist *sg;
+	int32_t i;
+
+	for_each_sg(obj->sg_table->sgl, sg, obj->sg_table->nents, i) {
+		struct page *page = sg_page(sg);
+
+		if (obj->dirty)
+			set_page_dirty(page);
+
+		mark_page_accessed(page);
+		page_cache_release(page);
+	}
+	obj->dirty = 0;
+
+	sg_free_table(obj->sg_table);
+	kfree(obj->sg_table);
+}
+
+static const struct drm_ipvr_gem_object_ops ipvr_gem_userptr_ops = {
+	.get_pages = ipvr_gem_userptr_get_pages_sg,
+	.put_pages = ipvr_gem_userptr_put_pages_sg,
+};
+
+int32_t ipvr_gem_userptr(struct drm_file *file_priv, struct drm_device *dev,
+			uint64_t user_ptr, uint64_t user_size,
+			uint32_t cache_level, uint32_t tiling, uint32_t *handle_p,
+			uint64_t *offset_p)
+{
+	struct ipvr_gem_userptr_object *obj;
+	int32_t ret = 0;
+	uint32_t handle, num_pages;
+	loff_t first_data_page, last_data_page;
+
+	struct drm_ipvr_private *dev_priv = dev->dev_private;
+	IPVR_DEBUG_GENERAL("create user bo userptr is %llx, size is %lld, "
+			"cache level is %d.\n",
+			user_ptr, user_size, cache_level);
+
+	first_data_page = user_ptr / PAGE_SIZE;
+	last_data_page = (user_ptr + user_size - 1) / PAGE_SIZE;
+	num_pages = last_data_page - first_data_page + 1;
+
+	/* only support page aligned buffer for now */
+	if (offset_in_page(user_ptr) != 0 || (user_size & (PAGE_SIZE - 1)) != 0)
+		return -EINVAL;
+
+	/* Allocate the new object */
+	obj = ipvr_gem_object_alloc(dev);
+	if (obj == NULL)
+		return -ENOMEM;
+	memset(obj, 0, sizeof(*obj));
+
+	drm_gem_private_object_init(dev, &obj->gem.base,
+					num_pages * PAGE_SIZE);
+
+	ipvr_gem_object_init(&obj->gem, &ipvr_gem_userptr_ops);
+
+	init_waitqueue_head(&obj->gem.event_queue);
+	atomic_set(&obj->gem.cpu_writers, 0);
+
+	obj->gem.drv_name = "ipvr";
+	obj->gem.fence = NULL;
+	obj->gem.cache_level = cache_level;
+	obj->gem.tiling = tiling;
+
+	obj->user_ptr = user_ptr;
+	obj->user_size = user_size;
+
+	ret = drm_gem_handle_create(file_priv, &obj->gem.base, &handle);
+	/* drop reference from allocate - handle holds it now */
+	drm_gem_object_unreference_unlocked(&obj->gem.base);
+	if (ret) {
+		IPVR_ERROR("failed drm_gem_handle_create for obj 0x%lx\n",
+			(unsigned long)obj);
+		goto err;
+	}
+
+	*handle_p = handle;
+
+	/* force to get pages at allocation stage */
+	ret = ipvr_gem_object_bind_to_vm(&obj->gem,
+					&dev_priv->addr_space, 4096);
+	if (ret) {
+		IPVR_ERROR("failed ipvr_gem_object_bind_to_vm for obj 0x%lx\n",
+			(unsigned long)obj);
+		goto err;
+	}
+
+	ret = ipvr_gem_mmu_bind_object(&obj->gem);
+	if (ret) {
+		IPVR_ERROR("failed ipvr_gem_mmu_bind_object for obj 0x%lx\n",
+			(unsigned long)obj);
+		goto err;
+	}
+
+	*offset_p = ipvr_gem_obj_mmu_offset(&obj->gem) + offset_in_page(user_ptr);
+	if (IPVR_IS_ERR(*offset_p)) {
+		ret = IPVR_OFFSET_ERR(*offset_p);
+		goto err;
+	}
+
+	IPVR_DEBUG_GENERAL("bo create done, gpu offset: 0x%llx.\n", *offset_p);
+
+err:
+	if (ret)
+		ipvr_gem_object_free(&obj->gem);
+	return ret;
+}
+
+int32_t 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;
+	struct page **pages;
+	unsigned long pfn;
+	pgoff_t pgoff;
+	int ret;
+	struct drm_ipvr_gem_object *ipvr_obj = to_ipvr_bo(obj);
+
+	pages = drm_malloc_ab(obj->size >> PAGE_SHIFT,
+			sizeof(*pages));
+
+	/* 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;
+	}
+
+	ret = drm_prime_sg_to_page_addr_arrays(ipvr_obj->sg_table,
+		pages, NULL, obj->size >> PAGE_SHIFT);
+	if (ret) {
+		IPVR_ERROR("failed to call drm_prime_sg_to_page_addr_arrays: %d.\n", ret);
+		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(pages[pgoff]);
+
+	IPVR_DEBUG_GENERAL("Inserting %p pfn %lx, pa %lx", 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:
+	if (pages)
+		drm_free_large(pages);
+	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;
+	}
+}
drivers/gpu/drm/ipvr/ipvr_buffer.h new file +188 -0
new file mode 100644
index 0000000..8473d10
@@ -0,0 +1,188 @@
+/**************************************************************************
+ * ipvr_buffer.h: IPVR buffer handling 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 <[email protected]>
+ *    Yao Cheng <[email protected]>
+ *
+ **************************************************************************/
+
+
+#ifndef _IPVR_BUFFER_H_
+#define _IPVR_BUFFER_H_
+
+#include <drmP.h>
+#include <drm_gem.h>
+#include <linux/shmem_fs.h>
+#include "ipvr_drv.h"
+#include "ipvr_drm.h"
+#include "ipvr_fence.h"
+
+struct ipvr_fence;
+
+struct drm_ipvr_gem_object {
+	struct drm_gem_object base;
+
+	/* used to disinguish between i915 and ipvr */
+	char *drv_name;
+
+	const struct drm_ipvr_gem_object_ops *ops;
+
+	/** List of VMAs backed by this object */
+	struct list_head vma_list;
+
+	/* for ipvr case, buffer is bound into mmu, will not be unbound */
+	struct list_head global_list;
+
+	/**
+	 * if this bo is a tiling buffer
+	 * we can support multiple mode of tiling, which has different stride
+	 * but only one tiling mode can be enabled.
+	 */
+	bool tiling;
+
+	enum ipvr_cache_level cache_level;
+
+	/**
+	 * This is set if the object is on the active lists (has pending
+	 * rendering and so a non-zero seqno), and is not set if it is on
+	 * inactive (ready to be unbound) list.
+	 */
+	uint32_t active:1;
+
+	/**
+	 * This is set if the object has been written to since last bound
+	 * to the GTT
+	 */
+	uint32_t dirty:1;
+
+	uint32_t pin_count:5;
+#define DRM_IPVR_GEM_OBJECT_MAX_PIN_COUNT 0x1f
+
+	struct sg_table *sg_table;
+	int32_t pages_pin_count;
+
+	/** User space pin count and filp owning the pin */
+	uint32_t user_pin_count;
+	struct drm_file *pin_filp;
+
+	struct ipvr_fence *fence;
+	atomic_t reserved;
+	wait_queue_head_t event_queue;
+	atomic_t cpu_writers;
+
+	unsigned long mmap_base;
+	uint64_t mmap_size;
+
+	struct page **fake_pages;
+};
+
+struct ipvr_gem_userptr_object {
+	struct drm_ipvr_gem_object gem;
+	uintptr_t user_ptr;
+	size_t user_size;
+	int32_t read_only;
+	struct mm_struct *mm;
+#if defined(CONFIG_MMU_NOTIFIER)
+	struct mmu_notifier mn;
+#endif
+};
+
+union drm_ipvr_gem_objects {
+	struct drm_ipvr_gem_object base;
+	struct ipvr_gem_userptr_object vmap;
+};
+
+struct drm_ipvr_gem_object_ops {
+	/*
+	 * Interface between the GEM object and its backing storage.
+	 * get_pages() is called once prior to the use of the associated set
+	 * of pages before to binding them into the GTT, and put_pages() is
+	 * called after we no longer need them. As we expect there to be
+	 * associated cost with migrating pages between the backing storage
+	 * and making them available for the GPU (e.g. clflush), we may hold
+	 * onto the pages after they are no longer referenced by the GPU
+	 * in case they may be used again shortly (for example migrating the
+	 * pages to a different memory domain within the GTT). put_pages()
+	 * will therefore most likely be called when the object itself is
+	 * being released or under memory pressure (where we attempt to
+	 * reap pages for the shrinker).
+	 */
+	int (*get_pages)(struct drm_ipvr_gem_object *);
+	void (*put_pages)(struct drm_ipvr_gem_object *);
+	void (*release)(struct drm_ipvr_gem_object *);
+	bool (*is_userptr_obj)(void);
+};
+
+/*
+ * A VMA represents a GEM BO that is bound into an address space. Therefore, a
+ * VMA's presence cannot be guaranteed before binding, or after unbinding the
+ * object into/from the address space.
+ *
+ * To make things as simple as possible (ie. no refcounting), a VMA's lifetime
+ * will always be <= an objects lifetime. So object refcounting should cover us.
+ */
+struct ipvr_vma {
+	struct drm_mm_node node;
+	struct drm_ipvr_gem_object *obj;
+	struct ipvr_address_space *vm;
+
+	/* This object's place on the active/inactive lists */
+	struct list_head mm_list;
+
+	struct list_head vma_link; /* Link in the object's VMA list */
+};
+
+int32_t ipvr_gem_create(struct drm_file *file_priv, struct drm_device *dev,
+			uint64_t size, uint32_t tiling, uint32_t cache_level,
+			uint64_t *rsize_p, uint32_t *handle_p,
+			uint64_t *offset_p, uint64_t *map_handle_p);
+
+struct drm_ipvr_gem_object *
+ipvr_gem_obj_create_and_bind(struct drm_device *dev, size_t size);
+
+struct drm_ipvr_gem_object *
+ipvr_gem_alloc_object(struct drm_device *dev, size_t size);
+
+int32_t ipvr_gem_object_bind_to_vm(struct drm_ipvr_gem_object *obj,
+			struct ipvr_address_space *vm,
+			uint32_t alignment);
+
+unsigned long ipvr_gem_obj_mmu_offset(struct drm_ipvr_gem_object *obj);
+
+int32_t ipvr_gem_mmu_bind_object(struct drm_ipvr_gem_object *obj);
+
+void *ipvr_gem_object_vmap(struct drm_ipvr_gem_object *obj);
+
+int ipvr_gem_init_object(struct drm_gem_object *obj);
+
+void ipvr_gem_free_object(struct drm_gem_object *obj);
+
+bool ipvr_gem_clflush_object(struct drm_ipvr_gem_object *obj, bool force);
+
+uint64_t ipvr_gem_mmap_offset(struct drm_ipvr_gem_object *obj);
+
+int32_t ipvr_gem_userptr(struct drm_file *file_priv, struct drm_device *dev,
+			uint64_t user_ptr, uint64_t user_size,
+			uint32_t cache_level, uint32_t tiling,
+			uint32_t *handle_p, uint64_t *offset_p);
+
+int32_t ipvr_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
+
+#endif
drivers/gpu/drm/ipvr/ipvr_debug.c new file +263 -0
new file mode 100644
index 0000000..eecf8de
@@ -0,0 +1,263 @@
+/**************************************************************************
+ * 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 <[email protected]>
+ *
+ **************************************************************************/
+
+#if defined(CONFIG_DEBUG_FS)
+
+#include <linux/seq_file.h>
+#include <linux/debugfs.h>
+#include "ipvr_debug.h"
+#include "ipvr_drv.h"
+#include "ved_reg.h"
+
+union ipvr_debugfs_vars debugfs_vars;
+
+static int32_t ipvr_debug_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;
+
+	seq_printf(m, "ipvr platform revison id: 0x%x\n",
+		dev_priv->platform_rev_id);
+
+	return 0;
+}
+
+static int32_t 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;
+	int32_t ret;
+
+	ret = mutex_lock_interruptible(&dev->struct_mutex);
+	if (ret)
+		return ret;
+
+	seq_printf(m, "ipvr total allocate %u objects, %zu bytes\n",
+		   dev_priv->ipvr_mm.object_count,
+		   dev_priv->ipvr_mm.object_memory);
+
+	mutex_unlock(&dev->struct_mutex);
+
+	return 0;
+}
+
+static int32_t 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;
+	int32_t 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];
+	int32_t 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",
+			(uint32_t)reg_offset,
+			VED_REG_READ32((uint32_t)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;
+
+		VED_REG_WRITE32(reg_offset, reg_to_write);
+		len = scnprintf(buf, sizeof(buf),
+				"0x%x: 0x%x\n",
+				(uint32_t)reg_offset,
+				(uint32_t)VED_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 int32_t 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 int32_t 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},
+};
+
+int32_t ipvr_debugfs_init(struct drm_minor *minor)
+{
+	int32_t 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)
+{
+	int32_t 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 */
drivers/gpu/drm/ipvr/ipvr_debug.h new file +50 -0
new file mode 100644
index 0000000..3cbeb73
@@ -0,0 +1,50 @@
+/**************************************************************************
+ * 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 <[email protected]>
+ *
+ **************************************************************************/
+
+
+#ifndef _IPVR_DEBUG_H_
+#define _IPVR_DEBUG_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];
+	uint32_t reg_input;
+};
+
+union ipvr_debugfs_vars {
+	struct ipvr_debugfs_reg_vars reg;
+};
+
+int32_t ipvr_debugfs_init(struct drm_minor *minor);
+void ipvr_debugfs_cleanup(struct drm_minor *minor);
+
+#endif
drivers/gpu/drm/ipvr/ipvr_drm.h new file +267 -0
new file mode 100644
index 0000000..ca13439
@@ -0,0 +1,267 @@
+/**************************************************************************
+ * 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 <[email protected]>
+ *    Yao Cheng <[email protected]>
+ *
+ **************************************************************************/
+
+
+/* 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 */
+	uint32_t ctx_type;
+	/* returned back ctx_id */
+	uint32_t 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
+	 */
+	uint32_t tiling_stride;
+	/*
+	 * scheme 0: tile is 256x16, while minimal tile stride is 512
+	 * scheme 1: tile is 512x8, while minimal tile stride is 1024
+	 */
+	uint32_t tiling_scheme;
+};
+
+struct drm_ipvr_context_destroy {
+	uint32_t ctx_id;
+	uint32_t 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 {
+	uint32_t ctx_id;
+	uint32_t tiling_stride;
+	uint32_t tiling_scheme;
+	uint32_t pad64;
+};
+
+/* Ioctl to set/get misc params:
+ */
+struct drm_ipvr_misc {
+	uint64_t key;
+	uint64_t arg;		/* argument pointer */
+	uint64_t value;	/* feed back pointer */
+};
+
+struct ipvr_validate_arg {
+	/* point to next ipvr_validate_arg */
+	uint64_t next;
+	uint64_t presumed_gpu_offset;
+	/* User's handle for a buffer */
+	uint32_t handle;
+	uint32_t pad;
+	/* fencing */
+	uint32_t skip_fence;
+	int32_t fence_fd;
+};
+
+#define MAX_SLICES_PER_PICTURE 72
+struct drm_ipvr_mb_region {
+	uint32_t start;
+	uint32_t end;
+};
+
+struct drm_ipvr_decode_status {
+	uint32_t num_region;
+	uint32_t pad;
+	struct drm_ipvr_mb_region mb_regions[MAX_SLICES_PER_PICTURE];
+};
+
+struct drm_ipvr_gem_execbuffer {
+	/*
+	 * List of ipvr_validate_arg structs
+	 */
+	uint64_t buffer_list;
+	uint32_t buffer_count;
+
+	/* from user space point, this is msg buffer actually */
+	uint32_t cmdbuf_handle;
+	uint32_t cmdbuf_size;
+
+	uint32_t ctx_id;
+};
+
+enum ipvr_cache_level {
+	IPVR_CACHE_NONE = 0,	/* uncacheable */
+	IPVR_CACHE_WB,		/* write back cacheable */
+	IPVR_CACHE_WC,		/* write combine, uncacheable */
+	IPVR_CACHE_MAX,
+};
+
+struct drm_ipvr_gem_create {
+	/*
+	 * Requested size for the object.
+	 * The (page-aligned) allocated size for the object will be returned.
+	 */
+	uint64_t size;
+	uint64_t rounded_size;
+	uint64_t gpu_offset;
+	/*
+	 * Returned handle for the object.
+	 * Object handles are nonzero.
+	 */
+	uint32_t handle;
+	uint32_t tiling;
+	uint32_t cache_level;
+	uint32_t pad64;
+	/*
+	 * Handle used for user to mmap BO
+	 */
+	uint64_t map_handle;
+};
+
+struct drm_ipvr_gem_busy {
+	/* Handle of the buffer to check for busy */
+	uint32_t 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)
+	 */
+	uint32_t busy;
+};
+
+struct drm_ipvr_gem_mmap_offset {
+	/** Handle for the object being mapped. */
+	uint32_t handle;
+	uint32_t pad;
+	/**
+	 * Fake offset to use for subsequent mmap call
+	 *
+	 * This is a fixed-size type for 32/64 compatibility.
+	 */
+	uint64_t offset;
+};
+
+/*
+ * ACCESS mode flags for SYNCCPU.
+ *
+ * IPVR_SYNCCPU_MODE_READ will guarantee that the GPU is not
+ * writing to the buffer.
+ *
+ * IPVR_SYNCCPU_MODE_WRITE will guarantee that the GPU is not
+ * accessing the buffer.
+ *
+ * IPVR_SYNCCPU_MODE_NO_BLOCK makes sure the call does not wait
+ * for GPU accesses to finish but return -EBUSY.
+ *
+ * IPVR_SYNCCPU_MODE_TRYCACHED Try to place the buffer in cacheable
+ * memory while synchronized for CPU.
+ *
+ */
+
+#define IPVR_SYNCCPU_MODE_READ      (1 << 0)
+#define IPVR_SYNCCPU_MODE_WRITE     (1 << 1)
+#define IPVR_SYNCCPU_MODE_NO_BLOCK  (1 << 2)
+#define IPVR_SYNCCPU_MODE_TRYCACHED (1 << 3)
+
+enum drm_ipvr_sync_cpu_op {
+	IPVR_SYNCCPU_OP_GRAB,
+	IPVR_SYNCCPU_OP_RELEASE,
+};
+
+struct drm_ipvr_sync_cpu {
+	/* Handle for the object */
+	uint32_t handle;
+	uint32_t access_mode;
+	uint32_t op;
+	uint32_t pad64;
+};
+
+struct drm_ipvr_gem_wait {
+	/* Handle of BO we shall wait on */
+	uint32_t handle;
+	uint32_t flags;
+};
+
+struct drm_ipvr_gem_userptr {
+	uint64_t user_ptr;
+	uint64_t user_size;
+	uint64_t gpu_offset;
+	uint32_t cache_level;
+    uint32_t tiling;
+	/*
+	 * Returned handle for the object.
+	 * Object handles are nonzero.
+	 */
+	uint32_t handle;
+	uint32_t pad;
+};
+
+/*
+ * IPVR GEM specific ioctls
+ * The device specific ioctl range is 0x50 to 0x5f.
+ */
+#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_SYNC_CPU			0x06
+#define DRM_IPVR_GEM_WAIT			0x07
+#define DRM_IPVR_GEM_USERPTR		0x08
+#define DRM_IPVR_GEM_MMAP_OFFSET	0x09
+
+#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_SYNC_CPU	\
+	DRM_IOW(DRM_COMMAND_BASE + DRM_IPVR_SYNC_CPU, struct drm_ipvr_sync_cpu)
+#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_USERPTR	\
+	DRM_IOWR(DRM_COMMAND_BASE + DRM_IPVR_GEM_USERPTR, struct drm_ipvr_gem_userptr)
+#define DRM_IOCTL_IPVR_GEM_MMAP_OFFSET	\
+	DRM_IOWR(DRM_COMMAND_BASE + DRM_IPVR_GEM_MMAP_OFFSET, struct drm_ipvr_gem_mmap_offset)
+
+#endif
drivers/gpu/drm/ipvr/ipvr_drv.c new file +759 -0
new file mode 100644
index 0000000..c99a338
@@ -0,0 +1,759 @@
+/**************************************************************************
+ * 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 <[email protected]>
+ *    Yao Cheng <[email protected]>
+ *
+ **************************************************************************/
+
+
+#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>
+
+#include "ipvr_drv.h"
+#include "ipvr_gem.h"
+#include "ipvr_mmu.h"
+#include "ipvr_exec.h"
+#include "ipvr_buffer.h"
+#include "ipvr_debug.h"
+#include "ved_init.h"
+#include "ved_pm.h"
+#include "ved_reg.h"
+#include "ved_cmd.h"
+#include "ipvr_trace.h"
+
+int32_t drm_ipvr_cpurelax = 0;
+int32_t drm_ipvr_udelaydivider = 1;
+int32_t drm_ipvr_trap_pagefaults = 0;
+int32_t drm_ipvr_tiling = 1;
+int32_t drm_ipvr_debug = 0x80;
+bool fake_bo_debug = false;
+int32_t drm_ipvr_freq = IP_FREQ_320_00;
+
+module_param_named(trap_pagefaults, drm_ipvr_trap_pagefaults, int, 0600);
+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,
+		"control VED frequency"
+		"default: 0x0b (266.67 MHz)"
+		"0x1f: 100.00 MHz"
+		"0x1d: 106.67 MHz"
+		"0x17: 133.30 MHz"
+		"0x13: 160.00 MHz"
+		"0x11: 177.78 MHz"
+		"0x0f: 200.00 MHz"
+		"0x0e: 213.33 MHz"
+		"0x0b: 266.67 MHz"
+		"0x09: 320.00 MHz");
+
+uint32_t REGISTER_READ(struct drm_device *dev, uint32_t reg)
+{
+	struct drm_ipvr_private *dev_priv = dev->dev_private;
+	return ioread32(dev_priv->ved_reg_base + dev_priv->ved_reg_offset + reg);
+}
+
+static int32_t
+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;
+	int32_t 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 profile %d, entry %d, ctx_id is %d, "
+			"protected is %d.\n",
+			(ipvr_ctx->ctx_type >> 8) & 0xff,
+			ipvr_ctx->ctx_type & 0xff, ctx_id,
+			ipvr_ctx->ctx_type & VA_RT_FORMAT_PROTECTED);
+	/*
+	 * 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;
+}
+
+static int32_t
+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;
+	}
+	IPVR_DEBUG_PM("Video:remove context profile %d, entrypoint %d\n",
+		(ipvr_ctx->ctx_type >> 8) & 0xff,
+		(ipvr_ctx->ctx_type & 0xff));
+	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;
+}
+
+static int32_t
+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;
+	int32_t ret = 0;
+	uint64_t 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: {
+		/* todo: remove hard-coding */
+		uint32_t device_info = 0xf31 << 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;
+}
+
+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_SYNC_CPU,
+			ipvr_gem_synccpu_ioctl, DRM_UNLOCKED),
+	DRM_IOCTL_DEF_DRV(IPVR_GEM_WAIT,
+			ipvr_gem_wait_ioctl, DRM_AUTH|DRM_UNLOCKED),
+	DRM_IOCTL_DEF_DRV(IPVR_GEM_USERPTR,
+			ipvr_gem_userptr_ioctl, 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(union drm_ipvr_gem_objects), 0,
+				  SLAB_HWCACHE_ALIGN, NULL);
+
+	INIT_LIST_HEAD(&dev_priv->ipvr_mm.unbound_list);
+	INIT_LIST_HEAD(&dev_priv->ipvr_mm.bound_list);
+	spin_lock_init(&dev_priv->ipvr_mm.object_stat_lock);
+
+	dev_priv->ipvr_mm.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.
+	 *
+	 * However, leave one page at the end still bound to the scratch page.
+	 * There are a number of places where hardware apparently prefetches
+	 * past the end of the object, and we've seen multiple hangs with the
+	 * GPU head pointer stuck in a batchbuffer bound at last page of the
+	 * aperture.  One page should be enough to keep any prefetching inside
+	 * of the aperture.
+	 */
+	struct drm_ipvr_private *dev_priv = dev->dev_private;
+	struct ipvr_address_space *addr_space = &dev_priv->addr_space;
+
+	/* todo: add sanity check */
+	addr_space->dev = dev_priv->dev;
+	INIT_LIST_HEAD(&addr_space->active_list);
+	INIT_LIST_HEAD(&addr_space->inactive_list);
+
+	/* 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;
+}
+
+static void ipvr_do_takedown(struct drm_device *dev)
+{
+	/* todo: need check if need clean up mm here */
+	ipvr_ved_uninit(dev);
+}
+
+static int32_t ipvr_drm_unload(struct drm_device *dev)
+{
+	struct drm_ipvr_private *dev_priv = dev->dev_private;
+
+	BUG_ON(!dev->platformdev);
+	BUG_ON(atomic_read(&dev_priv->ved_power_usage));
+
+	IPVR_DEBUG_ENTRY("entered.");
+	pm_runtime_disable(&dev->platformdev->dev);
+	if (dev_priv) {
+		if (dev_priv->ipvr_bo_slab)
+			kmem_cache_destroy(dev_priv->ipvr_bo_slab);
+		ipvr_fence_driver_fini(dev_priv);
+
+		if (ved_power_on(dev)) {
+			ipvr_do_takedown(dev);
+			WARN_ON(!ved_power_off(dev));
+		}
+		else
+			IPVR_ERROR("failed to power on VED\n");
+
+		if (dev_priv->validate_ctx.buffers)
+			vfree(dev_priv->validate_ctx.buffers);
+
+		if (dev_priv->pf_pd) {
+			ipvr_mmu_free_pagedir(dev_priv->pf_pd);
+			dev_priv->pf_pd = NULL;
+		}
+		if (dev_priv->mmu) {
+			ipvr_mmu_driver_takedown(dev_priv->mmu);
+			dev_priv->mmu = NULL;
+		}
+
+		if (dev_priv->ved_reg_base) {
+			iounmap(dev_priv->ved_reg_base - dev_priv->ved_reg_offset);
+			dev_priv->ved_reg_base = NULL;
+			dev_priv->ved_reg_offset = 0;
+		}
+
+		list_del(&dev_priv->default_ctx.head);
+		idr_remove(&dev_priv->ipvr_ctx_idr, dev_priv->default_ctx.ctx_id);
+		kfree(dev_priv);
+
+	}
+
+	return 0;
+}
+
+static int32_t ipvr_drm_load(struct drm_device *dev, unsigned long flags)
+{
+	struct drm_ipvr_private *dev_priv;
+	int32_t ctx_id, ret = 0;
+	struct platform_device *platdev;
+	struct resource *res_mmio, *res_reg;
+	void __iomem* mmio_addr;
+
+	dev_priv = kzalloc(sizeof(*dev_priv), GFP_KERNEL);
+	if (dev_priv == NULL)
+		return -ENOMEM;
+
+	dev->dev_private = dev_priv;
+	dev_priv->dev = dev;
+
+	BUG_ON(!dev->platformdev);
+	platdev = dev->platformdev;
+
+	mutex_init(&dev_priv->cmdbuf_mutex);
+	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(platdev, 0);
+	if (dev->irq < 0) {
+		ret = -ENODEV;
+		goto out_err;
+	}
+
+	res_mmio = platform_get_resource(platdev, IORESOURCE_MEM, 0);
+	res_reg = platform_get_resource(platdev, IORESOURCE_REG, 0);
+	if (!res_mmio || !res_reg) {
+		ret = -ENXIO;
+		goto out_err;
+	}
+
+	mmio_addr = ioremap_wc(res_mmio->start,
+					res_mmio->end - res_mmio->start);
+	if (IS_ERR(mmio_addr)) {
+		ret = -EACCES;
+		goto out_err;
+	}
+
+	dev_priv->ved_reg_base = mmio_addr + res_reg->start;
+	dev_priv->ved_reg_offset = res_reg->start;
+	IPVR_DEBUG_VED("ved_reg_base is %p, range is 0x%llx - 0x%llx.\n",
+		dev_priv->ved_reg_base,
+		res_reg->start, res_reg->end);
+
+	if (!ved_power_on(dev)) {
+		ret = -EBUSY;
+		goto out_err;
+	}
+
+	IPVR_DEBUG_INIT("MSVDX_CORE_REV_OFFSET by readl is 0x%x.\n",
+		readl(dev_priv->ved_reg_base + 0x640));
+	IPVR_DEBUG_INIT("MSVDX_CORE_REV_OFFSET by VED_REG_READ32 is 0x%x.\n",
+		VED_REG_READ32(MSVDX_CORE_REV_OFFSET));
+
+	/* mmu init */
+	dev_priv->mmu = ipvr_mmu_driver_init((void *)0,
+		drm_ipvr_trap_pagefaults,
+		0, dev_priv);
+	if (!dev_priv->mmu) {
+		ret = -EBUSY;
+		goto out_err;
+	}
+
+	dev_priv->pf_pd = ipvr_mmu_alloc_pd(dev_priv->mmu, 1, 0);
+	if (!dev_priv->pf_pd) {
+		ret = -ENOMEM;
+		goto out_err;
+	}
+
+	ipvr_mmu_set_pd_context(ipvr_mmu_get_default_pd(dev_priv->mmu), 0);
+	ipvr_mmu_set_pd_context(dev_priv->pf_pd, 1);
+
+	/*
+	 * 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);
+
+	ipvr_ved_init(dev);
+
+	WARN_ON(!ved_power_off(dev));
+
+	dev_priv->ved_private->ved_needs_reset = 1;
+	mutex_init(&dev_priv->ved_pm_mutex);
+	atomic_set(&dev_priv->ved_power_usage, 0);
+
+	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;
+
+	platform_set_drvdata(dev->platformdev, dev);
+	pm_runtime_enable(&dev->platformdev->dev);
+
+	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 int32_t
+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.
+ * Drivers must stop and cleanup all per-file operations in the .preclose()
+ * method. For instance pending vertical blanking and page flip events must be
+ * cancelled. No per-file operation is allowed on the file handle after
+ * returning from the .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;
+	}
+	IPVR_DEBUG_PM("Video:remove context profile %d, entrypoint %d\n",
+		(ipvr_ctx->ctx_type >> 8) & 0xff,
+		(ipvr_ctx->ctx_type & 0xff));
+	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(int32_t irq, void *arg)
+{
+	struct drm_device *dev = (struct drm_device *) arg;
+	WARN_ON(ved_irq_handler(dev));
+	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 int32_t ipvr_drm_freeze(struct drm_device *dev)
+{
+	int32_t ret;
+	int32_t power_usage;
+	struct drm_ipvr_private *dev_priv = dev->dev_private;
+	IPVR_DEBUG_ENTRY("enter\n");
+	power_usage = atomic_read(&dev_priv->ved_power_usage);
+	WARN_ON(power_usage < 0);
+	if (power_usage > 0) {
+		IPVR_DEBUG_PM("VED power usage is %d, skip freezing\n", power_usage);
+		return 0;
+	}
+
+	ret = ved_check_idle(dev);
+	if (ret) {
+		IPVR_DEBUG_PM("VED check idle fail: %d, skip freezing\n", ret);
+		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)) {
+		if (!ved_power_off(dev)) {
+			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 int32_t ipvr_drm_thaw(struct drm_device *dev)
+{
+	int ret;
+	IPVR_DEBUG_ENTRY("enter\n");
+	if (!is_ved_on(dev)) {
+		if (!ved_power_on(dev)) {
+			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 int32_t 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 int32_t 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,
+};
+
+/*
+ * dump GEM API is mainly for dumb buffers suitable for scanout,
+ * it is not needed for ipvr driver.
+ * gem_vm_ops is used for mmap case, also not needed for ipvr
+ * todo: prime support can be enabled later
+ */
+static struct drm_driver ipvr_drm_driver = {
+	.driver_features = DRIVER_HAVE_IRQ | DRIVER_GEM,
+	.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,
+#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 int32_t ipvr_plat_probe(struct platform_device *device)
+{
+	return drm_platform_init(&ipvr_drm_driver, device);
+}
+
+static int32_t ipvr_plat_remove(struct platform_device *device)
+{
+	struct drm_device *drm_dev = platform_get_drvdata(device);
+	IPVR_DEBUG_PM("enter\n");
+	drm_put_dev(drm_dev);
+	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");
drivers/gpu/drm/ipvr/ipvr_drv.h new file +442 -0
new file mode 100644
index 0000000..7eda95e
@@ -0,0 +1,442 @@
+/**************************************************************************
+ * 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 <[email protected]>
+ *    Yao Cheng <[email protected]>
+ *
+ **************************************************************************/
+
+#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		"Vxd392 VP8 driver for Baytrail"
+#define IPVR_DRIVER_DATE		"20141020"
+#define IPVR_DRIVER_MAJOR		0
+#define IPVR_DRIVER_MINOR		1
+#define IPVR_DRIVER_PATCHLEVEL	0
+
+/* General customization:
+ */
+
+#define IPVR_MMU_CACHED_MEMORY	  0x0001	/* Bind to MMU only */
+#define IPVR_MMU_RO_MEMORY	  	  0x0002	/* MMU RO memory */
+#define IPVR_MMU_WO_MEMORY	      0x0004	/* MMU WO memory */
+
+/*
+ *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 */
+
+/*
+ * 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
+
+#define IPVR_GEM_DOMAIN_CPU		0x00000001
+#define IPVR_GEM_DOMAIN_GPU		0x00000002
+
+/* video context */
+#define VA_RT_FORMAT_PROTECTED	0x80000000
+
+#define IPVR_CONTEXT_INVALID_ID 0
+#define IPVR_MIN_CONTEXT_ID 1
+#define IPVR_MAX_CONTEXT_ID 0xff
+
+/* video error status report */
+#define MAX_SLICES_PER_PICTURE 72
+#define MAX_DECODE_BUFFERS (24)
+#define VED_MAX_EC_INSTANCE (4)
+
+/*
+ *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)
+
+/*
+ * set cpu_relax = 1 in sysfs to use cpu_relax instead of udelay bysy loop
+ * set udelay_divider to reduce the udelay values,e.g.= 10, reduce 10 times
+ */
+#define IPVR_UDELAY(usec)					\
+do {								\
+	if (drm_ipvr_cpurelax == 0)				\
+		DRM_UDELAY(usec / drm_ipvr_udelaydivider);	\
+	else							\
+		cpu_relax();					\
+} while (0)
+
+typedef struct ipvr_validate_buffer ipvr_validate_buffer_t;
+
+uint32_t REGISTER_READ(struct drm_device *dev, uint32_t reg);
+#define REG_READ(reg)	       REGISTER_READ(dev, (reg))
+
+#define to_ipvr_bo(x) container_of(x, struct drm_ipvr_gem_object, base)
+
+extern int drm_ipvr_debug;
+extern int drm_ipvr_udelaydivider;
[… more lines in the raw message]

Lines of this file are not shown. View the raw message.

drivers/gpu/drm/ipvr/ipvr_exec.c new file +530 -0
new file mode 100644
index 0000000..b79e67f

Lines of this file are not shown. View the raw message.

drivers/gpu/drm/ipvr/ipvr_exec.h new file +68 -0
new file mode 100644
index 0000000..68405df

Lines of this file are not shown. View the raw message.

drivers/gpu/drm/ipvr/ipvr_fence.c new file +550 -0
new file mode 100644
index 0000000..838e0d4

Lines of this file are not shown. View the raw message.

drivers/gpu/drm/ipvr/ipvr_fence.h new file +68 -0
new file mode 100644
index 0000000..54846da

Lines of this file are not shown. View the raw message.

drivers/gpu/drm/ipvr/ipvr_gem.c new file +191 -0
new file mode 100644
index 0000000..e724819

Lines of this file are not shown. View the raw message.

drivers/gpu/drm/ipvr/ipvr_gem.h new file +46 -0
new file mode 100644
index 0000000..16b15c5

Lines of this file are not shown. View the raw message.

drivers/gpu/drm/ipvr/ipvr_mmu.c new file +807 -0
new file mode 100644
index 0000000..4d6f536

Lines of this file are not shown. View the raw message.

drivers/gpu/drm/ipvr/ipvr_mmu.h new file +135 -0
new file mode 100644
index 0000000..9ba4b69

Lines of this file are not shown. View the raw message.

drivers/gpu/drm/ipvr/ipvr_trace.c new file +11 -0
new file mode 100644
index 0000000..91c0bda

Lines of this file are not shown. View the raw message.

drivers/gpu/drm/ipvr/ipvr_trace.h new file +296 -0
new file mode 100644
index 0000000..d3209df

Lines of this file are not shown. View the raw message.

drivers/gpu/drm/ipvr/ved_cmd.c new file +1269 -0
new file mode 100644
index 0000000..0ae46e5

Lines of this file are not shown. View the raw message.

drivers/gpu/drm/ipvr/ved_cmd.h new file +104 -0
new file mode 100644
index 0000000..f3b5138

Lines of this file are not shown. View the raw message.

drivers/gpu/drm/ipvr/ved_ec.c new file +584 -0
new file mode 100644
index 0000000..2aa52cc

Lines of this file are not shown. View the raw message.

drivers/gpu/drm/ipvr/ved_ec.h new file +207 -0
new file mode 100644
index 0000000..c5f9fe6

Lines of this file are not shown. View the raw message.

drivers/gpu/drm/ipvr/ved_fw.c new file +660 -0
new file mode 100644
index 0000000..47fbad4

Lines of this file are not shown. View the raw message.

drivers/gpu/drm/ipvr/ved_fw.h new file +73 -0
new file mode 100644
index 0000000..8c2da56

Lines of this file are not shown. View the raw message.

drivers/gpu/drm/ipvr/ved_init.c new file +829 -0
new file mode 100644
index 0000000..bf82dfd

Lines of this file are not shown. View the raw message.

drivers/gpu/drm/ipvr/ved_init.h new file +61 -0
new file mode 100644
index 0000000..ab57f025

Lines of this file are not shown. View the raw message.

drivers/gpu/drm/ipvr/ved_msg.h new file +364 -0
new file mode 100644
index 0000000..1ffba7e

Lines of this file are not shown. View the raw message.

drivers/gpu/drm/ipvr/ved_pm.c new file +392 -0
new file mode 100644
index 0000000..9aee650

Lines of this file are not shown. View the raw message.

drivers/gpu/drm/ipvr/ved_pm.h new file +55 -0
new file mode 100644
index 0000000..1f00f8b

Lines of this file are not shown. View the raw message.

drivers/gpu/drm/ipvr/ved_reg.h new file +609 -0
new file mode 100644
index 0000000..1d55f2a

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

Signature · 6 lines
1.9.1

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

Part of the diff is not shown here. View the raw message.