[Meego-kernel] [MFLD Camera - PATCH v3 5/9] ISP driver - The low level memory management of ISP MMU block.

Zhang, Xiaolin xiaolin.zhang at intel.com
Wed Dec 1 10:53:03 PST 2010


>From 49ef7ea85e424b2622cc1263a55a5dce4f02383e Mon Sep 17 00:00:00 2001
From: Xiaolin Zhang <xiaolin.zhang at intel.com>
Date: Wed, 1 Dec 2010 22:13:58 +0800
Subject: [MFLD Camera - PATCH v3 5/9] ISP driver - The low level memory management of ISP MMU block.

Signed-off-by: Xiaolin Zhang <xiaolin.zhang at intel.com>
---
 drivers/media/video/mfld_ci/mfldisp/hmm/hmm.c      |  372 +++++++
 drivers/media/video/mfld_ci/mfldisp/hmm/hmm_bo.c   | 1159 ++++++++++++++++++++
 .../media/video/mfld_ci/mfldisp/hmm/hmm_bo_dev.c   |  294 +++++
 drivers/media/video/mfld_ci/mfldisp/hmm/hmm_vm.c   |  204 ++++
 .../mfld_ci/mfldisp/hrt/hive_isp_css_ddr_hrt.c     |  317 ++++++
 .../mfld_ci/mfldisp/hrt/hive_isp_css_mm_hrt.c      |  138 +++
 .../media/video/mfld_ci/mfldisp/include/hmm/hmm.h  |   71 ++
 .../video/mfld_ci/mfldisp/include/hmm/hmm_bo.h     |  313 ++++++
 .../video/mfld_ci/mfldisp/include/hmm/hmm_bo_dev.h |  124 +++
 .../video/mfld_ci/mfldisp/include/hmm/hmm_common.h |  121 ++
 .../video/mfld_ci/mfldisp/include/hmm/hmm_vm.h     |   67 ++
 11 files changed, 3180 insertions(+), 0 deletions(-)
 create mode 100644 drivers/media/video/mfld_ci/mfldisp/hmm/hmm.c
 create mode 100644 drivers/media/video/mfld_ci/mfldisp/hmm/hmm_bo.c
 create mode 100644 drivers/media/video/mfld_ci/mfldisp/hmm/hmm_bo_dev.c
 create mode 100644 drivers/media/video/mfld_ci/mfldisp/hmm/hmm_vm.c
 create mode 100644 drivers/media/video/mfld_ci/mfldisp/hrt/hive_isp_css_ddr_hrt.c
 create mode 100644 drivers/media/video/mfld_ci/mfldisp/hrt/hive_isp_css_mm_hrt.c
 create mode 100644 drivers/media/video/mfld_ci/mfldisp/include/hmm/hmm.h
 create mode 100644 drivers/media/video/mfld_ci/mfldisp/include/hmm/hmm_bo.h
 create mode 100644 drivers/media/video/mfld_ci/mfldisp/include/hmm/hmm_bo_dev.h
 create mode 100644 drivers/media/video/mfld_ci/mfldisp/include/hmm/hmm_common.h
 create mode 100644 drivers/media/video/mfld_ci/mfldisp/include/hmm/hmm_vm.h

diff --git a/drivers/media/video/mfld_ci/mfldisp/hmm/hmm.c b/drivers/media/video/mfld_ci/mfldisp/hmm/hmm.c
new file mode 100644
index 0000000..8504fe5
--- /dev/null
+++ b/drivers/media/video/mfld_ci/mfldisp/hmm/hmm.c
@@ -0,0 +1,372 @@
+/*
+ * Support for Medifield PNW Camera Imaging ISP subsystem.
+ *
+ * Copyright (c) 2010 Intel Corporation. All Rights Reserved.
+ *
+ * Copyright (c) 2010 Silicon Hive www.siliconhive.com.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that 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 Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/highmem.h>     /* for kmap */
+
+#include <linux/io.h>          /* for page_to_phys */
+
+#include "hmm/hmm.h"
+#include "hmm/hmm_bo.h"
+#include "hmm/hmm_bo_dev.h"
+
+#include "mmu/isp_mmu.h"
+#include "mmu/sh_mmu.h"
+#include "mfldisp_internal.h"
+
+static struct hmm_bo_device __bo_device;
+void *__dummy_ptr;
+
+int hmm_init()
+{
+       int ret;
+
+       ret = hmm_bo_device_init(&__bo_device, &sh_mmu_driver,
+                                ISP_VM_START, ISP_VM_SIZE);
+       if (ret)
+               mfld_isp_dbg(KERN_ERR, "hmm_bo_device_init failed.\n");
+
+       /*
+        * As hmm use NULL to indicate invalid ISP virtual address,
+        * and ISP_VM_START is defined to 0 too, so we allocate
+        * one piece of dummy memory, which should return value 0,
+        * at the beginning, to avoid hmm_alloc return 0 in the
+        * further allocation.
+        */
+       __dummy_ptr = hmm_alloc(1, HMM_BO_PRIVATE, 0, 0);
+       return ret;
+}
+
+void hmm_cleanup()
+{
+       /*
+        * free dummy memory first
+        */
+       hmm_free(__dummy_ptr);
+       __dummy_ptr = NULL;
+
+       hmm_bo_device_exit(&__bo_device);
+}
+
+void *hmm_alloc(size_t bytes, enum hmm_bo_type type,
+               int from_highmem, unsigned int userptr)
+{
+       unsigned int pgnr;
+       struct hmm_buffer_object *bo;
+       int ret;
+
+       pgnr = __size_to_pgnr_ceil(bytes);
+
+       bo = hmm_bo_create(&__bo_device, pgnr);
+       if (!bo) {
+               mfld_isp_dbg(KERN_ERR, "hmm_bo_create failed.\n");
+               goto create_bo_err;
+       }
+
+       ret = hmm_bo_alloc_vm(bo);
+       if (ret) {
+               mfld_isp_dbg(KERN_ERR, "hmm_bo_alloc_vm failed.\n");
+               goto alloc_vm_err;
+       }
+
+       ret = hmm_bo_alloc_pages(bo, type, from_highmem, userptr);
+       if (ret) {
+               mfld_isp_dbg(KERN_ERR, "hmm_bo_alloc_pages failed.\n");
+               goto alloc_page_err;
+       }
+
+       ret = hmm_bo_bind(bo);
+       if (ret) {
+               mfld_isp_dbg(KERN_ERR, "hmm_bo_bind failed.\n");
+               goto bind_err;
+       }
+
+       return (void *)bo->vm_node->start;
+
+bind_err:
+       hmm_bo_free_pages(bo);
+alloc_page_err:
+       hmm_bo_free_vm(bo);
+alloc_vm_err:
+       hmm_bo_unref(bo);
+create_bo_err:
+       return NULL;
+}
+
+void hmm_free(void *virt)
+{
+       struct hmm_buffer_object *bo;
+
+       bo = hmm_bo_device_search_start(&__bo_device, (unsigned int)virt);
+
+       if (!bo) {
+               mfld_isp_dbg(KERN_ERR, "can not find buffer object start with "
+                            "address 0x%x\n", (unsigned int)virt);
+               return;
+       }
+
+       hmm_bo_unbind(bo);
+
+       hmm_bo_free_pages(bo);
+
+       hmm_bo_free_vm(bo);
+
+       hmm_bo_unref(bo);
+}
+
+int hmm_load(void *virt, void *data, unsigned int bytes)
+{
+       unsigned int ptr;
+       struct hmm_buffer_object *bo;
+       unsigned int idx, offset, len;
+       char *src, *des;
+
+       ptr = (unsigned int)virt;
+
+       bo = hmm_bo_device_search_in_range(&__bo_device, ptr);
+       if (!bo) {
+               mfld_isp_dbg(KERN_ERR, "can not find buffer object contains "
+                            "address 0x%x\n", (unsigned int)ptr);
+               return -EINVAL;
+       }
+
+       if (!hmm_bo_page_allocated(bo)) {
+               mfld_isp_dbg(KERN_ERR,
+                            "buffer object has no page allocated.\n");
+               return -EINVAL;
+       }
+
+       if (!hmm_bo_vm_allocated(bo)) {
+               mfld_isp_dbg(KERN_ERR,
+                            "buffer object has no virtual"
+                            " address space allocated.\n");
+               return -EINVAL;
+       }
+
+       des = (char *)data;
+       while (bytes) {
+               idx = (ptr - bo->vm_node->start) >> PAGE_SHIFT;
+               offset = (ptr - bo->vm_node->start) - (idx << PAGE_SHIFT);
+
+               src = (char *)kmap(bo->pages[idx]);
+               if (!src) {
+                       mfld_isp_dbg(KERN_ERR,
+                                    "kmap buffer object page failed: "
+                                    "pg_idx = %d\n", idx);
+                       return -EINVAL;
+               }
+
+               src += offset;
+
+               if ((bytes + offset) >= PAGE_SIZE) {
+                       len = PAGE_SIZE - offset;
+                       bytes -= len;
+               } else {
+                       len = bytes;
+                       bytes = 0;
+               }
+
+               ptr += len;     /* update ptr for next loop */
+
+               while (len--)
+                       *des++ = *src++;
+
+               kunmap(bo->pages[idx]);
+       }
+
+       return 0;
+}
+
+int hmm_store(void *virt, const void *data, unsigned int bytes)
+{
+       unsigned int ptr;
+       struct hmm_buffer_object *bo;
+       unsigned int idx, offset, len;
+       char *src, *des;
+
+       ptr = (unsigned int)virt;
+
+       bo = hmm_bo_device_search_in_range(&__bo_device, ptr);
+       if (!bo) {
+               mfld_isp_dbg(KERN_ERR, "can not find buffer object contains "
+                            "address 0x%x\n", (unsigned int)ptr);
+               return -EINVAL;
+       }
+
+       if (!hmm_bo_page_allocated(bo)) {
+               mfld_isp_dbg(KERN_ERR,
+                            "buffer object has no page allocated.\n");
+               return -EINVAL;
+       }
+
+       if (!hmm_bo_vm_allocated(bo)) {
+               mfld_isp_dbg(KERN_ERR,
+                            "buffer object has no virtual address"
+                            " space allocated.\n");
+               return -EINVAL;
+       }
+
+       src = (char *)data;
+       while (bytes) {
+               idx = (ptr - bo->vm_node->start) >> PAGE_SHIFT;
+               offset = (ptr - bo->vm_node->start) - (idx << PAGE_SHIFT);
+
+               des = (char *)kmap(bo->pages[idx]);
+               if (!des) {
+                       mfld_isp_dbg(KERN_ERR,
+                                    "kmap buffer object page failed: "
+                                    "pg_idx = %d\n", idx);
+                       return -EINVAL;
+               }
+
+               des += offset;
+
+               if ((bytes + offset) >= PAGE_SIZE) {
+                       len = PAGE_SIZE - offset;
+                       bytes -= len;
+               } else {
+                       len = bytes;
+                       bytes = 0;
+               }
+
+               ptr += len;
+
+               while (len--)
+                       *des++ = *src++;
+
+               kunmap(bo->pages[idx]);
+       }
+
+       return 0;
+}
+
+int hmm_set(void *virt, char c, unsigned int bytes)
+{
+       unsigned int ptr;
+       struct hmm_buffer_object *bo;
+       unsigned int idx, offset, len;
+       char *des;
+
+       ptr = (unsigned int)virt;
+
+       bo = hmm_bo_device_search_in_range(&__bo_device, ptr);
+       if (!bo) {
+               mfld_isp_dbg(KERN_ERR, "can not find buffer object contains "
+                            "address 0x%x\n", (unsigned int)ptr);
+               return -EINVAL;
+       }
+
+       if (!hmm_bo_page_allocated(bo)) {
+               mfld_isp_dbg(KERN_ERR,
+                            "buffer object has no page allocated.\n");
+               return -EINVAL;
+       }
+
+       if (!hmm_bo_vm_allocated(bo)) {
+               mfld_isp_dbg(KERN_ERR,
+                            "buffer object has no virtual address"
+                            " space allocated.\n");
+               return -EINVAL;
+       }
+
+       while (bytes) {
+               idx = (ptr - bo->vm_node->start) >> PAGE_SHIFT;
+               offset = (ptr - bo->vm_node->start) - (idx << PAGE_SHIFT);
+
+               des = (char *)kmap(bo->pages[idx]);
+               if (!des) {
+                       mfld_isp_dbg(KERN_ERR,
+                                    "kmap buffer object page failed: "
+                                    "pg_idx = %d\n", idx);
+                       return -EINVAL;
+               }
+               des += offset;
+
+               if ((bytes + offset) >= PAGE_SIZE) {
+                       len = PAGE_SIZE - offset;
+                       bytes -= len;
+               } else {
+                       len = bytes;
+                       bytes = 0;
+               }
+
+               ptr += len;
+
+               while (len--)
+                       *des++ = c;
+
+               kunmap(bo->pages[idx]);
+       }
+
+       return 0;
+}
+
+unsigned int hmm_virt_to_phys(void *virt)
+{
+       unsigned int ptr = (unsigned int)virt;
+       unsigned int idx, offset;
+       struct hmm_buffer_object *bo;
+
+       bo = hmm_bo_device_search_in_range(&__bo_device, ptr);
+       if (!bo) {
+               mfld_isp_dbg(KERN_ERR, "can not find buffer object contains "
+                            "address 0x%x\n", ptr);
+               return -1;
+       }
+
+       idx = (ptr - bo->vm_node->start) >> PAGE_SHIFT;
+       offset = (ptr - bo->vm_node->start) - (idx << PAGE_SHIFT);
+
+       return page_to_phys(bo->pages[idx]) + offset;
+}
+
+int hmm_mmap(struct vm_area_struct *vma, void *virt)
+{
+       unsigned int ptr = (unsigned int)virt;
+       struct hmm_buffer_object *bo;
+
+       bo = hmm_bo_device_search_start(&__bo_device, ptr);
+       if (!bo) {
+               mfld_isp_dbg(KERN_ERR, "can not find buffer object start with "
+                            "address 0x%x\n", (unsigned int)virt);
+               return -EINVAL;
+       }
+
+       return hmm_bo_mmap(vma, bo);
+}
+
+void *hmm_vmap(void *virt)
+{
+       unsigned int ptr = (unsigned int)virt;
+       struct hmm_buffer_object *bo;
+
+       bo = hmm_bo_device_search_start(&__bo_device, ptr);
+       if (!bo) {
+               mfld_isp_dbg(KERN_ERR, "can not find buffer object start with "
+                            "address 0x%x\n", (unsigned int)virt);
+               return NULL;
+       }
+
+       return hmm_bo_vmap(bo);
+}
diff --git a/drivers/media/video/mfld_ci/mfldisp/hmm/hmm_bo.c b/drivers/media/video/mfld_ci/mfldisp/hmm/hmm_bo.c
new file mode 100644
index 0000000..b6b5632
--- /dev/null
+++ b/drivers/media/video/mfld_ci/mfldisp/hmm/hmm_bo.c
@@ -0,0 +1,1159 @@
+/*
+ * Support for Medifield PNW Camera Imaging ISP subsystem.
+ *
+ * Copyright (c) 2010 Intel Corporation. All Rights Reserved.
+ *
+ * Copyright (c) 2010 Silicon Hive www.siliconhive.com.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that 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 Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/gfp.h>         /* for GFP_ATOMIC */
+#include <linux/mm.h>
+#include <linux/mm_types.h>
+#include <linux/slab.h>                /* for kmalloc */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/string.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <asm/cacheflush.h>
+#include <linux/io.h>
+#include <asm/current.h>
+#include <linux/sched.h>
+
+#ifdef USE_DRM_MM
+#include <drm/drm_mm.h>
+#else
+#include "hmm/hmm_vm.h"
+#endif
+
+#include "hmm/hmm_bo.h"
+#include "hmm/hmm_bo_dev.h"
+#include "hmm/hmm_common.h"
+#include "mfldisp_internal.h"
+
+#define        __check_bo_status_yes_goto(bo, _status, label) \
+       __var_not_equal_goto((bo->status & (_status)), (_status), \
+                       label, \
+                       "HMM buffer status not contain %s.\n", \
+                       #_status)
+
+#define        __check_bo_status_no_goto(bo, _status, label) \
+       __var_equal_goto((bo->status & (_status)), (_status), \
+                       label, \
+                       "HMM buffer status contains %s.\n", \
+                       #_status)
+#define        HMM_MAX_ORDER   10
+
+static inline unsigned int order_to_nr(unsigned int order)
+{
+       return 1U << order;
+}
+
+static inline unsigned int nr_to_order_ceil(unsigned int nr)
+{
+       unsigned int order = 0;
+
+       for (; nr / 2; nr = nr / 2 + nr % 2)
+               order++;
+
+       return order;
+}
+
+static inline unsigned int nr_to_order_bottom(unsigned int nr)
+{
+       unsigned int order = 0;
+
+       for (; nr /= 2;)
+               order++;
+
+       return order;
+}
+
+static void __free_bo_internal(struct hmm_buffer_object *bo)
+{
+       kfree(bo);
+}
+
+/*
+ * use these functions to dynamically alloc hmm_buffer_object.
+ * hmm_bo_init will called for that allocated buffer object, and
+ * the release callback is set to kfree.
+ */
+struct hmm_buffer_object *hmm_bo_create(struct hmm_bo_device *bdev, int pgnr)
+{
+       struct hmm_buffer_object *bo;
+       int ret;
+
+       bo = kmalloc(sizeof(*bo), GFP_KERNEL);
+       if (!bo) {
+               mfld_isp_dbg(KERN_ERR, "out of memory.\n");
+               return NULL;
+       }
+
+       ret = hmm_bo_init(bdev, bo, pgnr, __free_bo_internal);
+       if (ret) {
+               mfld_isp_dbg(KERN_ERR, "hmm_bo_init failed\n");
+               kfree(bo);
+               return NULL;
+       }
+
+       return bo;
+}
+
+/*
+ * use this function to initialize pre-allocated hmm_buffer_object.
+ * as hmm_buffer_object may be used as an embedded object in an upper
+ * level object, a release callback must be provided. if it is
+ * embedded in upper level object, set release call back to release
+ * function of that object. if no upper level object, set release
+ * callback to NULL.
+ *
+ * bo->kref is inited to 1.
+ */
+int hmm_bo_init(struct hmm_bo_device *bdev,
+               struct hmm_buffer_object *bo,
+               unsigned int pgnr, void (*release) (struct hmm_buffer_object *))
+{
+       if (bdev == NULL) {
+               mfld_isp_dbg(KERN_WARNING, "NULL hmm_bo_device.\n");
+               return -EINVAL;
+       }
+
+       /* hmm_bo_device must be already inited */
+       __var_equal_return(hmm_bo_device_inited(bdev), 0, -EINVAL,
+                          "hmm_bo_device not inited yet.\n");
+
+       /* prevent zero size buffer object */
+       if (pgnr == 0) {
+               mfld_isp_dbg(KERN_ERR, "0 size buffer is not allowed.\n");
+               return -EINVAL;
+       }
+
+       memset(bo, 0, sizeof(*bo));
+
+       kref_init(&bo->kref);
+
+       mutex_init(&bo->mutex);
+
+       INIT_LIST_HEAD(&bo->list);
+
+       bo->pgnr = pgnr;
+       bo->bdev = bdev;
+
+       INIT_LIST_HEAD(&bo->pgblocks);
+
+       bo->release = release;
+
+       if (!bo->release)
+               mfld_isp_dbg(KERN_WARNING, "no release callback specified.\n");
+
+       /*
+        * add to active_bo_list
+        */
+       mutex_lock(&bdev->ablist_mutex);
+       list_add_tail(&bo->list, &bdev->active_bo_list);
+       bo->status |= HMM_BO_ACTIVE;
+       mutex_unlock(&bdev->ablist_mutex);
+
+       return 0;
+}
+
+static void hmm_bo_release(struct hmm_buffer_object *bo)
+{
+       struct hmm_bo_device *bdev;
+
+       __check_bo_null_return(bo, (void)0);
+
+       bdev = bo->bdev;
+
+       /*
+        * FIX ME:
+        *
+        * how to destroy the bo when it is stilled MMAPED?
+        *
+        * ideally, this will not happened as hmm_bo_release
+        * will only be called when kref reaches 0, and in mmap
+        * operation the hmm_bo_ref will eventually be called.
+        * so, if this happened, something goes wrong.
+        */
+       if (bo->status & HMM_BO_MMAPED) {
+               mfld_isp_dbg(KERN_ERR,
+                            "destroy bo which is MMAPED, do nothing\n");
+               goto err;
+       }
+#ifdef HMM_BO_VMAP_SUPPORT
+       if (bo->status & HMM_BO_VMAPED) {
+               mfld_isp_dbg(KERN_WARNING,
+                            "the bo is still vmapped, unmap it first...\n");
+               hmm_bo_vunmap(bo);
+       }
+#endif
+
+       if (bo->status & HMM_BO_BINDED) {
+               mfld_isp_dbg(KERN_WARNING,
+                            "the bo is still binded, unbind it first...\n");
+               hmm_bo_unbind(bo);
+       }
+       if (bo->status & HMM_BO_PAGE_ALLOCED) {
+               mfld_isp_dbg(KERN_WARNING,
+                            "the pages is not freed, free pages first\n");
+               hmm_bo_free_pages(bo);
+       }
+       if (bo->status & HMM_BO_VM_ALLOCED) {
+               mfld_isp_dbg(KERN_WARNING,
+                            "the vm is still not freed, free vm first...\n");
+               hmm_bo_free_vm(bo);
+       }
+
+       /*
+        * remove it from buffer device's buffer object list.
+        */
+       if (hmm_bo_activated(bo)) {
+               mutex_lock(&bdev->ablist_mutex);
+               list_del(&bo->list);
+               mutex_unlock(&bdev->ablist_mutex);
+       } else {
+               mutex_lock(&bdev->fblist_mutex);
+               list_del(&bo->list);
+               mutex_unlock(&bdev->fblist_mutex);
+       }
+
+       if (bo->release)
+               bo->release(bo);
+err:
+       return;
+}
+
+int hmm_bo_activated(struct hmm_buffer_object *bo)
+{
+       __check_bo_null_return(bo, 0);
+
+       return bo->status & HMM_BO_ACTIVE;
+}
+
+void hmm_bo_unactivate(struct hmm_buffer_object *bo)
+{
+       struct hmm_bo_device *bdev;
+
+       __check_bo_null_return(bo, (void)0);
+
+       __check_bo_status_no_goto(bo, HMM_BO_ACTIVE, status_err);
+
+       bdev = bo->bdev;
+
+       mutex_lock(&bdev->ablist_mutex);
+       list_del(&bo->list);
+       mutex_unlock(&bdev->ablist_mutex);
+
+       mutex_lock(&bdev->fblist_mutex);
+       list_add_tail(&bo->list, &bdev->free_bo_list);
+       bo->status &= (~HMM_BO_ACTIVE);
+       mutex_unlock(&bdev->fblist_mutex);
+
+       return;
+
+status_err:
+       mfld_isp_dbg(KERN_ERR, "buffer object already unactivated.\n");
+       return;
+}
+
+int hmm_bo_alloc_vm(struct hmm_buffer_object *bo)
+{
+       struct hmm_bo_device *bdev;
+
+       __check_bo_null_return(bo, -EINVAL);
+
+       mutex_lock(&bo->mutex);
+
+       __check_bo_status_no_goto(bo, HMM_BO_VM_ALLOCED, status_err);
+
+       bdev = bo->bdev;
+
+#ifdef USE_DRM_MM
+retry:
+       ret = drm_mm_pre_get(&bdev->vaddr_space);
+       if (unlikely(ret != 0)) {
+               ret = -ENOMEM;
+               goto out_of_vm;
+       }
+
+       write_lock(&bdev->vm_lock);
+       /*
+        * unit of size parameter is page number or bytes?
+        * how to use alignment?
+        */
+       bo->vm_node = drm_mm_search_free(&bdev->vaddr_space, bo->pgnr, 0, 0);
+
+       if (unlikely(ret != 0)) {
+               ret = -ENOMEM;
+               goto out_of_vm_lock;
+       }
+
+       bo->vm_node = drm_mm_get_block_atomic(bo->vm_node, bo->pgnr, 0);
+
+       if (unlikely(ret != 0)) {
+               write_unlock(&bdev->vm_lock);
+               goto retry;
+       }
+
+       bo->status |= HMM_BO_VM_ALLOCED;
+
+       write_unlock(&bdev->vm_lock);
+
+       mutex_unlock(&bo->mutex);
+
+       return 0;
+
+out_of_vm_lock:
+       write_unlock(&bdev->vm_lock);
+out_of_vm:
+       mutex_unlock(&bo->mutex);
+       return ret;
+
+#else
+       bo->vm_node = hmm_vm_alloc_node(&bdev->vaddr_space, bo->pgnr);
+       if (unlikely(!bo->vm_node)) {
+               mfld_isp_dbg(KERN_ERR, "hmm_vm_alloc_node err.\n");
+               goto null_vm;
+       }
+
+       bo->status |= HMM_BO_VM_ALLOCED;
+
+       mutex_unlock(&bo->mutex);
+
+       return 0;
+null_vm:
+       mutex_unlock(&bo->mutex);
+       return -ENOMEM;
+#endif
+
+status_err:
+       mutex_unlock(&bo->mutex);
+       mfld_isp_dbg(KERN_ERR, "buffer object already has vm allocated.\n");
+       return -EINVAL;
+}
+
+void hmm_bo_free_vm(struct hmm_buffer_object *bo)
+{
+       struct hmm_bo_device *bdev;
+
+       __check_bo_null_return(bo, (void)0);
+
+       mutex_lock(&bo->mutex);
+
+       __check_bo_status_yes_goto(bo, HMM_BO_VM_ALLOCED, status_err);
+
+       bdev = bo->bdev;
+
+#ifdef USE_DRM_MM
+       write_lock(&bdev->vm_lock);
+
+       drm_mm_put_block(bo->vm_node);
+       bo->vm_node = NULL;
+
+       bo->status &= (~HMM_BO_VM_ALLOCED);
+
+       write_unlock(&bdev->vm_lock);
+#else
+       hmm_vm_free_node(bo->vm_node);
+       bo->vm_node = NULL;
+       bo->status &= (~HMM_BO_VM_ALLOCED);
+#endif
+       mutex_unlock(&bo->mutex);
+
+       return;
+
+status_err:
+       mutex_unlock(&bo->mutex);
+       mfld_isp_dbg(KERN_ERR, "buffer object has no vm allocated.\n");
+}
+
+int hmm_bo_vm_allocated(struct hmm_buffer_object *bo)
+{
+       int ret;
+
+       __check_bo_null_return(bo, 0);
+
+       mutex_lock(&bo->mutex);
+
+       ret = (bo->status & HMM_BO_VM_ALLOCED);
+
+       mutex_unlock(&bo->mutex);
+
+       return ret;
+}
+
+#ifdef CI_VA_SHARE_BUFFER
+static int __alloc_share_pages(struct hmm_buffer_object *bo, int from_highmem)
+{
+       int ret;
+
+       /*
+        * FIX ME:
+        *
+        * how to control ttm to alloc memory from/not from highmem.
+        */
+
+       ret = drm_bo_create_external(0, (bo->pgnr) << PAGE_SHIFT, &bo->handle);
+
+       if (ret) {
+               mfld_isp_dbg(KERN_ERR, "unable to alloc pages: %d\n", pgnr);
+               return ret;
+       }
+
+       /*
+        * Will bo->pgnr be larger than pgnr that we want to
+        * allocate?
+        */
+       drm_bo_external_get_pages(bo->handle, &bo->pages, &bo->pgnr);
+}
+
+static void __free_share_pages(struct hmm_buffer_object *bo)
+{
+       return drm_bo_external_destroy(bo->handle);
+}
+#endif
+
+static int __alloc_private_pages(struct hmm_buffer_object *bo, int from_highmem)
+{
+       int ret;
+       unsigned int pgnr, order, blk_pgnr;
+       struct page *pages;
+       struct __page_block *pgblk;
+       gfp_t gfp;
+       int i, j;
+
+       gfp = GFP_KERNEL;
+       if (from_highmem)
+               gfp |= __GFP_HIGHMEM;
+
+       pgnr = bo->pgnr;
+
+       bo->pages = kmalloc(sizeof(struct page *) *pgnr, GFP_KERNEL);
+       if (unlikely(!bo->pages))
+               goto out_of_mem;
+
+       i = 0;
+       while (pgnr) {
+               order = nr_to_order_bottom(pgnr);
+               if (order > HMM_MAX_ORDER)
+                       order = HMM_MAX_ORDER;
+retry:
+               pages = alloc_pages(gfp, order);
+               if (unlikely(!pages)) {
+                       order--;
+                       if (order < 0)
+                               goto out_of_mem;
+                       else
+                               goto retry;
+               } else {
+                       blk_pgnr = order_to_nr(order);
+
+                       pgblk = kmalloc(sizeof(*pgblk), GFP_KERNEL);
+                       if (unlikely(!pgblk))
+                               goto out_of_mem;
+
+                       INIT_LIST_HEAD(&pgblk->list);
+                       pgblk->pages = pages;
+                       pgblk->order = order;
+
+                       list_add_tail(&pgblk->list, &bo->pgblocks);
+
+                       for (j = 0; j < blk_pgnr; j++)
+                               bo->pages[i++] = pages + j;
+
+                       pgnr -= blk_pgnr;
+
+                       /*
+                        * set memory to uncacheable -- UC_MINUS
+                        */
+                       ret = set_pages_uc(pages, blk_pgnr);
+                       if (ret) {
+                               mfld_isp_dbg(KERN_ERR,
+                                            "set page uncacheable failed.\n");
+                               goto set_uc_mem_fail;
+                       }
+               }
+       }
+
+       return 0;
+set_uc_mem_fail:
+       /* FIX ME: select one better */
+       ret = -ENOMEM;
+       goto cleanup;
+out_of_mem:
+       ret = -ENOMEM;
+       goto cleanup;
+cleanup:
+       while (!list_empty(&bo->pgblocks)) {
+               pgblk = list_first_entry(&bo->pgblocks,
+                                        struct __page_block, list);
+
+               list_del(&pgblk->list);
+
+               ret = set_pages_wb(pgblk->pages, order_to_nr(pgblk->order));
+               if (ret)
+                       mfld_isp_dbg(KERN_ERR, "set page to WB err...\n");
+
+               __free_pages(pgblk->pages, pgblk->order);
+               kfree(pgblk);
+       }
+
+       return ret;
+}
+
+static void __free_private_pages(struct hmm_buffer_object *bo)
+{
+       struct __page_block *pgblk;
+       int ret;
+
+       while (!list_empty(&bo->pgblocks)) {
+               pgblk = list_first_entry(&bo->pgblocks,
+                                        struct __page_block, list);
+
+               list_del(&pgblk->list);
+
+               ret = set_pages_wb(pgblk->pages, order_to_nr(pgblk->order));
+               if (ret)
+                       mfld_isp_dbg(KERN_ERR, "set page to WB err...\n");
+
+               __free_pages(pgblk->pages, pgblk->order);
+               kfree(pgblk);
+       }
+
+       kfree(bo->pages);
+}
+
+static int __alloc_user_pages(struct hmm_buffer_object *bo,
+                             unsigned int userptr)
+{
+       unsigned int page_nr;
+       unsigned int i;
+       struct __page_block *pgblk;
+       int ret;
+
+       bo->pages = kmalloc(sizeof(struct page *) *bo->pgnr, GFP_KERNEL);
+       if (unlikely(!bo->pages)) {
+               mfld_isp_dbg(KERN_ERR, "out of memory...\n");
+               return -ENOMEM;
+       }
+
+       page_nr = get_user_pages(current, current->mm, (unsigned long)userptr,
+                                (int)(bo->pgnr), 1, 0, bo->pages, NULL);
+       /* can be written by caller, not forced */
+       if (page_nr != bo->pgnr) {
+               mfld_isp_dbg(KERN_ERR, "get_user_pages err: bo->pgnr = %d, "
+                            "pgnr actually pinned = %d.\n", bo->pgnr, page_nr);
+               return -ENOMEM;
+       }
+
+       for (i = 0; i < bo->pgnr; i++) {
+               pgblk = kmalloc(sizeof(*pgblk), GFP_KERNEL);
+               if (unlikely(!pgblk))
+                       goto out_of_mem;
+
+               INIT_LIST_HEAD(&pgblk->list);
+               pgblk->pages = bo->pages[i];
+               pgblk->order = 0;
+
+               list_add_tail(&pgblk->list, &bo->pgblocks);
+       }
+
+       for (i = 0; i < bo->pgnr; i++) {
+               ret = set_pages_uc(bo->pages[i], 1);
+               if (ret) {
+                       mfld_isp_dbg(KERN_ERR,
+                                    "set page to uncacheable failed.\n");
+                       goto cleanup;
+               }
+       }
+
+       return 0;
+
+out_of_mem:
+       ret = -ENOMEM;
+       goto cleanup;
+cleanup:
+       while (!list_empty(&bo->pgblocks)) {
+               pgblk = list_first_entry(&bo->pgblocks,
+                                        struct __page_block, list);
+
+               list_del(&pgblk->list);
+
+               kfree(pgblk);
+       }
+
+       return ret;
+}
+
+static void __free_user_pages(struct hmm_buffer_object *bo)
+{
+       unsigned int i;
+       struct __page_block *pgblk;
+       int ret;
+
+       for (i = 0; i < bo->pgnr; i++) {
+               ret = set_pages_wb(bo->pages[i], 1);
+               if (ret)
+                       mfld_isp_dbg(KERN_ERR,
+                                    "set page to WB again failed.\n");
+       }
+
+       while (!list_empty(&bo->pgblocks)) {
+               pgblk = list_first_entry(&bo->pgblocks,
+                                        struct __page_block, list);
+
+               list_del(&pgblk->list);
+
+               kfree(pgblk);
+       }
+
+       kfree(bo->pages);
+}
+
+/*
+ * allocate/free physical pages for the bo.
+ *
+ * type indicate where are the pages from. currently we have 3 types
+ * of memory: HMM_BO_PRIVATE, HMM_BO_USER, HMM_BO_SHARE.
+ *
+ * from_highmem is only valid when type is HMM_BO_PRIVATE, it will
+ * try to alloc memory from highmem if from_highmem is set.
+ *
+ * userptr is only valid when type is HMM_BO_USER, it indicates
+ * the start address from user space task.
+ *
+ * from_highmem and userptr will both be ignored when type is
+ * HMM_BO_SHARE.
+ */
+int hmm_bo_alloc_pages(struct hmm_buffer_object *bo,
+                      enum hmm_bo_type type, int from_highmem,
+                      unsigned int userptr)
+{
+       int ret;
+
+       __check_bo_null_return(bo, -EINVAL);
+
+       mutex_lock(&bo->mutex);
+
+       __check_bo_status_no_goto(bo, HMM_BO_PAGE_ALLOCED, status_err);
+
+       /*
+        * TO DO:
+        * add HMM_BO_USER type
+        */
+       if (type == HMM_BO_PRIVATE)
+               ret = __alloc_private_pages(bo, from_highmem);
+       else if (type == HMM_BO_USER)
+               ret = __alloc_user_pages(bo, userptr);
+#ifdef CI_VA_SHARE_BUFFER
+       else if (type == HMM_BO_SHARE)
+               ret = __alloc_share_pages(bo, from_highmem);
+#endif
+       else {
+               mfld_isp_dbg(KERN_ERR, "invalid buffer type.\n");
+               ret = -EINVAL;
+       }
+
+       if (ret)
+               goto alloc_err;
+
+       bo->type = type;
+
+       bo->status |= HMM_BO_PAGE_ALLOCED;
+
+       mutex_unlock(&bo->mutex);
+
+       return 0;
+
+alloc_err:
+       mutex_unlock(&bo->mutex);
+       mfld_isp_dbg(KERN_ERR, "alloc pages err...\n");
+       return ret;
+status_err:
+       mutex_unlock(&bo->mutex);
+       mfld_isp_dbg(KERN_ERR, "buffer object has already page allocated.\n");
+       return -EINVAL;
+}
+
+/*
+ * free physical pages of the bo.
+ */
+void hmm_bo_free_pages(struct hmm_buffer_object *bo)
+{
+       __check_bo_null_return(bo, (void)0);
+
+       mutex_lock(&bo->mutex);
+
+#ifdef HMM_BO_VMAP_SUPPORT
+       __check_bo_status_no_goto(bo, HMM_BO_VMAPED, status_err1);
+#endif
+
+       __check_bo_status_yes_goto(bo, HMM_BO_PAGE_ALLOCED, status_err2);
+
+       if (bo->type == HMM_BO_PRIVATE)
+               __free_private_pages(bo);
+       else if (bo->type == HMM_BO_USER)
+               __free_user_pages(bo);
+#ifdef CI_VA_SHARE_BUFFER
+       else if __free_share_pages
+               (bo);
+#endif
+       else
+               mfld_isp_dbg(KERN_ERR, "invalid buffer type.\n");
+       /* clear the flag anyway. */
+       bo->status &= (~HMM_BO_PAGE_ALLOCED);
+
+       mutex_unlock(&bo->mutex);
+
+       return;
+
+status_err2:
+       mutex_unlock(&bo->mutex);
+       mfld_isp_dbg(KERN_ERR, "buffer object not page allocated yet.\n");
+
+#ifdef HMM_BO_VMAP_SUPPORT
+status_err1:
+       mutex_unlock(&bo->mutex);
+       mfld_isp_dbg(KERN_ERR,
+                    "buffer object still vmapped, dont free pages here.\n");
+#endif
+}
+
+int hmm_bo_page_allocated(struct hmm_buffer_object *bo)
+{
+       int ret;
+
+       __check_bo_null_return(bo, 0);
+
+       mutex_lock(&bo->mutex);
+
+       ret = bo->status & HMM_BO_PAGE_ALLOCED;
+
+       mutex_unlock(&bo->mutex);
+
+       return ret;
+}
+
+/*
+ * get physical page info of the bo.
+ */
+int hmm_bo_get_page_info(struct hmm_buffer_object *bo,
+                        struct page ***pages, int *pgnr)
+{
+       __check_bo_null_return(bo, -EINVAL);
+
+       mutex_lock(&bo->mutex);
+
+       __check_bo_status_yes_goto(bo, HMM_BO_PAGE_ALLOCED, status_err);
+
+       *pages = bo->pages;
+       *pgnr = bo->pgnr;
+
+       mutex_unlock(&bo->mutex);
+
+       return 0;
+
+status_err:
+       mfld_isp_dbg(KERN_ERR, "buffer object not page allocated yet.\n");
+       mutex_unlock(&bo->mutex);
+       return -EINVAL;
+}
+
+/*
+ * bind the physical pages to a virtual address space.
+ */
+int hmm_bo_bind(struct hmm_buffer_object *bo)
+{
+       int ret;
+       unsigned int virt;
+       struct hmm_bo_device *bdev;
+#ifdef __MMU_MAP_BLOCK
+       struct list_head *pos;
+       struct __page_block *pgblk;
+       unsigned int blk_pgnr;
+#else
+       unsigned int i;
+#endif
+
+       __check_bo_null_return(bo, -EINVAL);
+
+       mutex_lock(&bo->mutex);
+
+       __check_bo_status_yes_goto(bo,
+                                  HMM_BO_PAGE_ALLOCED | HMM_BO_VM_ALLOCED,
+                                  status_err1);
+
+       __check_bo_status_no_goto(bo, HMM_BO_BINDED, status_err2);
+
+       bdev = bo->bdev;
+
+       virt = bo->vm_node->start;
+
+#ifdef __MMU_MAP_BLOCK
+       /*
+        * FIXME:
+        *
+        * bo->pgblocks is empty in case of HMM_BO_USER, so CANNOT use this way
+        * to setup address mapping.
+        * DONOT define __MMU_MAP_BLOCK macro currently.
+        */
+       list_for_each(pos, &bo->pgblocks) {
+               pgblk = list_entry(pos, struct __page_block, list);
+               blk_pgnr = order_to_nr(pgblk->order);
+               ret = isp_mmu_map(&bdev->mmu, virt, page_to_phys(pgblk->pages),
+                                 blk_pgnr);
+               if (ret)
+                       goto map_err;
+               virt += (blk_pgnr << PAGE_SHIFT);
+       }
+#else
+       for (i = 0; i < bo->pgnr; i++) {
+               ret =
+                   isp_mmu_map(&bdev->mmu, virt, page_to_phys(bo->pages[i]),
+                               1);
+               if (ret)
+                       goto map_err;
+               virt += (1 << PAGE_SHIFT);
+       }
+#endif
+       /*
+        * flush TBL here.
+        *
+        * theoretically, we donot need to flush TLB as we didnot change
+        * any existed address mappings, but for Silicon Hive's MMU, its
+        * really a bug here. I guess when fetching PTEs (page table entity)
+        * to TLB, its MMU will fetch additional INVALID PTEs automatically
+        * for performance issue. EX, we only set up 1 page address mapping,
+        * meaning updating 1 PTE, but the MMU fetches 4 PTE at one time,
+        * so the additional 3 PTEs are invalid.
+        */
+       isp_mmu_flush_tlb_range(&bdev->mmu, bo->vm_node->start,
+                               (bo->pgnr << PAGE_SHIFT));
+
+       bo->status |= HMM_BO_BINDED;
+
+       mutex_unlock(&bo->mutex);
+
+       return 0;
+
+map_err:
+       mutex_unlock(&bo->mutex);
+       mfld_isp_dbg(KERN_ERR, "setup MMU address mapping failed.\n");
+       return ret;
+#if 0
+size_err:
+       mfld_isp_dbg(KERN_ERR, "vm size and page size not equal.\n");
+       return -EINVAL;
+#endif
+status_err2:
+       mutex_unlock(&bo->mutex);
+       mfld_isp_dbg(KERN_ERR, "buffer object already binded.\n");
+       return -EINVAL;
+status_err1:
+       mutex_unlock(&bo->mutex);
+       mfld_isp_dbg(KERN_ERR,
+                    "buffer object vm_node or page not allocated.\n");
+       return -EINVAL;
+}
+
+/*
+ * unbind the physical pages with related virtual address space.
+ */
+void hmm_bo_unbind(struct hmm_buffer_object *bo)
+{
+       unsigned int virt;
+       struct hmm_bo_device *bdev;
+#ifdef __MMU_MAP_BLOCK
+       struct list_head *pos;
+       struct __page_block *pgblk;
+       unsigned int blk_pgnr;
+#else
+       unsigned int i;
+#endif
+
+       __check_bo_null_return(bo, (void)0);
+
+       mutex_lock(&bo->mutex);
+
+       __check_bo_status_yes_goto(bo,
+                                  HMM_BO_PAGE_ALLOCED |
+                                  HMM_BO_VM_ALLOCED |
+                                  HMM_BO_BINDED, status_err);
+
+       bdev = bo->bdev;
+
+       virt = bo->vm_node->start;
+
+#ifdef __MMU_MAP_BLOCK
+       list_for_each(pos, &bo->pgblocks) {
+               pgblk = list_entry(pos, struct __page_block, list);
+               blk_pgnr = order_to_nr(pgblk->order);
+               isp_mmu_unmap(&bdev->mmu, virt, blk_pgnr);
+               virt += __pgnr_to_size(blk_pgnr);
+       }
+#else
+       for (i = 0; i < bo->pgnr; i++) {
+               isp_mmu_unmap(&bdev->mmu, virt, 1);
+               virt += __pgnr_to_size(1);
+       }
+#endif
+       /*
+        * flush TLB as the address mapping has been removed and
+        * related TLBs should be invalidated.
+        */
+       isp_mmu_flush_tlb_range(&bdev->mmu, bo->vm_node->start,
+                               (bo->pgnr << PAGE_SHIFT));
+
+       bo->status &= (~HMM_BO_BINDED);
+
+       mutex_unlock(&bo->mutex);
+
+       return;
+
+status_err:
+       mutex_unlock(&bo->mutex);
+       mfld_isp_dbg(KERN_ERR,
+                    "buffer vm or page not allocated or not binded yet.\n");
+}
+
+int hmm_bo_binded(struct hmm_buffer_object *bo)
+{
+       int ret;
+
+       __check_bo_null_return(bo, 0);
+
+       mutex_lock(&bo->mutex);
+
+       ret = bo->status & HMM_BO_BINDED;
+
+       mutex_unlock(&bo->mutex);
+
+       return ret;
+}
+
+#ifdef HMM_BO_VMAP_SUPPORT
+
+int hmm_bo_vmap(struct hmm_buffer_object *bo)
+{
+       int ret;
+
+       __check_bo_null_return(bo, -EINVAL);
+
+       mutex_lock(&bo->mutex);
+
+       __check_bo_status_yes_goto(bo, HMM_BO_PAGE_ALLOCED, status_err1);
+
+       __check_bo_status_no_goto(bo, HMM_BO_VMAPED, status_err2);
+
+       bo->virt = vmap(bo->pages, bo->pgnr, VM_MAP, PAGE_KERNEL_NOCACHE);
+
+       if (bo->virt)
+               goto vmap_err;
+
+       bo->status |= HMM_BO_VMAPED;
+
+       mutex_unlock(&bo->mutex);
+
+       return 0;
+vmap_err:
+       mutex_unlock(&bo->mutex);
+       mfld_isp_dbg(KERN_ERR, "buffer object vmap failed.\n");
+       return -ENOMEM;
+status_err2:
+       mutex_unlock(&bo->mutex);
+       mfld_isp_dbg(KERN_ERR, "buffer object already vmapped.\n");
+       return -EINVAL;
+status_err1:
+       mutex_unlock(&bo->mutex);
+       mfld_isp_dbg(KERN_ERR, "buffer object has no pages allocated.\n");
+       return -EINVAL;
+}
+
+void hmm_bo_vunmap(struct hmm_buffer_object *bo)
+{
+       __check_bo_null_return(bo, (void)0);
+
+       mutex_lock(&bo->mutex);
+
+       __check_bo_status_yes_goto(bo, HMM_BO_VMAPED, status_err);
+
+       vunmap(bo->virt);
+
+       bo->status &= (~HMM_BO_VMAPED);
+
+       mutex_unlock(&bo->mutex);
+
+status_err:
+       mutex_unlock(&bo->mutex);
+       mfld_isp_dbg(KERN_ERR, "buffer object not vmapped.\n");
+}
+
+int hmm_bo_vmapped(struct hmm_buffer_object *bo)
+{
+       int ret;
+
+       __check_bo_null_return(bo, 0);
+
+       mutex_lock(&bo->mutex);
+
+       ret = bo->status & HMM_BO_VMAPED;
+
+       mutex_unlock(&bo->mutex);
+
+       return ret;
+}
+
+#else
+
+void *hmm_bo_vmap(struct hmm_buffer_object *bo)
+{
+       __check_bo_null_return(bo, NULL);
+
+       return vmap(bo->pages, bo->pgnr, VM_MAP, PAGE_KERNEL_NOCACHE);
+}
+
+#endif
+
+void hmm_bo_ref(struct hmm_buffer_object *bo)
+{
+       __check_bo_null_return(bo, (void)0);
+
+       kref_get(&bo->kref);
+}
+
+#define        __kref_to_hmm_bo(kref_ptr) \
+       list_entry((kref_ptr), struct hmm_buffer_object, kref)
+
+static void __kref_hmm_bo_release(struct kref *kref)
+{
+       if (!kref)
+               return;
+
+       hmm_bo_release(__kref_to_hmm_bo(kref));
+}
+
+void hmm_bo_unref(struct hmm_buffer_object *bo)
+{
+       __check_bo_null_return(bo, (void)0);
+
+       kref_put(&bo->kref, __kref_hmm_bo_release);
+}
+
+static void hmm_bo_vm_open(struct vm_area_struct *vma)
+{
+       struct hmm_buffer_object *bo =
+           (struct hmm_buffer_object *)vma->vm_private_data;
+
+       __check_bo_null_return(bo, (void)0);
+
+       hmm_bo_ref(bo);
+
+       mutex_lock(&bo->mutex);
+
+       bo->status |= HMM_BO_MMAPED;
+
+       bo->mmap_count++;
+
+       mutex_unlock(&bo->mutex);
+}
+
+static void hmm_bo_vm_close(struct vm_area_struct *vma)
+{
+       struct hmm_buffer_object *bo =
+           (struct hmm_buffer_object *)vma->vm_private_data;
+
+       __check_bo_null_return(bo, (void)0);
+
+       hmm_bo_unref(bo);
+
+       mutex_lock(&bo->mutex);
+
+       bo->mmap_count--;
+
+       if (!bo->mmap_count) {
+               bo->status &= (~HMM_BO_MMAPED);
+               vma->vm_private_data = NULL;
+       }
+
+       mutex_unlock(&bo->mutex);
+}
+
+static const struct vm_operations_struct hmm_bo_vm_ops = {
+       .open = hmm_bo_vm_open,
+       .close = hmm_bo_vm_close,
+};
+
+/*
+ * mmap the bo to user space.
+ */
+int hmm_bo_mmap(struct vm_area_struct *vma, struct hmm_buffer_object *bo)
+{
+       unsigned int start, end;
+       unsigned int virt;
+       unsigned int pgnr, i;
+       unsigned int pfn;
+
+       __check_bo_null_return(bo, -EINVAL);
+
+       __check_bo_status_yes_goto(bo, HMM_BO_PAGE_ALLOCED, status_err);
+
+       pgnr = bo->pgnr;
+       start = vma->vm_start;
+       end = vma->vm_end;
+
+       /*
+        * check vma's virtual address space size and buffer object's size.
+        * must be the same.
+        */
+       if ((start + __pgnr_to_size(pgnr)) != end) {
+               mfld_isp_dbg(KERN_WARNING,
+                            "vma's address space size not equal"
+                            " to buffer object's size");
+               return -EINVAL;
+       }
+
+       virt = vma->vm_start;
+       for (i = 0; i < pgnr; i++) {
+               pfn = page_to_pfn(bo->pages[i]);
+               if (remap_pfn_range(vma, virt, pfn, PAGE_SIZE, PAGE_SHARED)) {
+                       mfld_isp_dbg(KERN_WARNING, "remap_pfn_range failed: "
+                                    "virt = 0x%x, pfn = 0x%x,"
+                                    " mapped_pgnr = %d\n", virt, pfn, 1);
+                       return -EINVAL;
+               }
+               virt += PAGE_SIZE;
+       }
+
+       vma->vm_private_data = bo;
+
+       vma->vm_ops = &hmm_bo_vm_ops;
+       vma->vm_flags |= (VM_RESERVED | VM_IO);
+
+       /*
+        * call hmm_bo_vm_open explictly.
+        */
+       hmm_bo_vm_open(vma);
+
+       return 0;
+
+status_err:
+       mfld_isp_dbg(KERN_ERR, "buffer page not allocated yet.\n");
+       return -EINVAL;
+}
diff --git a/drivers/media/video/mfld_ci/mfldisp/hmm/hmm_bo_dev.c b/drivers/media/video/mfld_ci/mfldisp/hmm/hmm_bo_dev.c
new file mode 100644
index 0000000..2d95221
--- /dev/null
+++ b/drivers/media/video/mfld_ci/mfldisp/hmm/hmm_bo_dev.c
@@ -0,0 +1,294 @@
+/*
+ * Support for Medifield PNW Camera Imaging ISP subsystem.
+ *
+ * Copyright (c) 2010 Intel Corporation. All Rights Reserved.
+ *
+ * Copyright (c) 2010 Silicon Hive www.siliconhive.com.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that 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 Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/gfp.h>
+#include <linux/mm.h>          /* for GFP_ATOMIC */
+#include <linux/slab.h>                /* for kmalloc */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/string.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+
+#include "hmm/hmm_common.h"
+#include "hmm/hmm_bo_dev.h"
+#include "hmm/hmm_bo.h"
+#include "mfldisp_internal.h"
+
+/*
+ * hmm_bo_device functions.
+ */
+int hmm_bo_device_init(struct hmm_bo_device *bdev,
+                      struct isp_mmu_driver *mmu_driver,
+                      unsigned int vaddr_start, unsigned int size)
+{
+       int ret;
+
+       __check_bodev_null_return(bdev, -EINVAL);
+
+       ret = isp_mmu_init(&bdev->mmu, mmu_driver);
+       if (ret) {
+               mfld_isp_dbg(KERN_ERR, "isp_mmu_init failed.\n");
+               goto isp_mmu_init_err;
+       }
+
+#ifdef USE_DRM_MM
+       ret = drm_mm_init(&bdev->vaddr_space, vaddr_start, size);
+       if (ret) {
+               mfld_isp_dbg(KERN_ERR, "drm_mm_init falied. "
+                            "vaddr_start = 0x%x, size = %d\n", vaddr_start,
+                            size);
+               goto vm_init_err;
+       }
+       rwlock_init(&bdev->vm_lock);
+#else
+       ret = hmm_vm_init(&bdev->vaddr_space, vaddr_start, size);
+       if (ret) {
+               mfld_isp_dbg(KERN_ERR, "hmm_vm_init falied. "
+                            "vaddr_start = 0x%x, size = %d\n", vaddr_start,
+                            size);
+               goto vm_init_err;
+       }
+#endif
+
+       INIT_LIST_HEAD(&bdev->free_bo_list);
+       INIT_LIST_HEAD(&bdev->active_bo_list);
+
+       mutex_init(&bdev->fblist_mutex);
+       mutex_init(&bdev->ablist_mutex);
+
+       bdev->flag = HMM_BO_DEVICE_INITED;
+
+       return 0;
+
+vm_init_err:
+       isp_mmu_exit(&bdev->mmu);
+isp_mmu_init_err:
+       return ret;
+}
+
+void hmm_bo_device_exit(struct hmm_bo_device *bdev)
+{
+       __check_bodev_null_return(bdev, (void)0);
+
+       /*
+        * destroy all bos in the bo list, even they are in use.
+        */
+       if (!list_empty(&bdev->active_bo_list))
+               mfld_isp_dbg(KERN_WARNING,
+                            "there're still activated bo in use. "
+                            "force to free them.\n");
+
+       while (!list_empty(&bdev->active_bo_list))
+               hmm_bo_unref(__list_to_hmm_bo(bdev->active_bo_list.next));
+
+       if (!list_empty(&bdev->free_bo_list))
+               mfld_isp_dbg(KERN_WARNING, "there're still bo in free_bo_list. "
+                            "force to free them.\n");
+
+       while (!list_empty(&bdev->free_bo_list))
+               hmm_bo_unref(__list_to_hmm_bo(bdev->free_bo_list.next));
+
+       isp_mmu_exit(&bdev->mmu);
+
+#ifdef USE_DRM_MM
+       drm_mm_takedown(&bdev->vaddr_space);
+#else
+       hmm_vm_clean(&bdev->vaddr_space);
+#endif
+}
+
+int hmm_bo_device_inited(struct hmm_bo_device *bdev)
+{
+       __check_bodev_null_return(bdev, -EINVAL);
+
+       return bdev->flag == HMM_BO_DEVICE_INITED;
+}
+
+/*
+ * find the buffer object with virtual address vaddr.
+ * return NULL if no such buffer object found.
+ */
+struct hmm_buffer_object *hmm_bo_device_search_start(struct hmm_bo_device *bdev,
+                                                    unsigned int vaddr)
+{
+       struct list_head *pos;
+       struct hmm_buffer_object *bo;
+
+       __check_bodev_null_return(bdev, NULL);
+
+       mutex_lock(&bdev->ablist_mutex);
+       list_for_each(pos, &bdev->active_bo_list) {
+               bo = __list_to_hmm_bo(pos);
+               /* pass bo which has no vm_node allocated */
+               if (!hmm_bo_vm_allocated(bo))
+                       continue;
+               if (bo->vm_node->start == vaddr)
+                       goto found;
+       }
+       mutex_unlock(&bdev->ablist_mutex);
+       return NULL;
+found:
+       mutex_unlock(&bdev->ablist_mutex);
+       return bo;
+}
+
+static int __in_range(unsigned int start, unsigned int size, unsigned int addr)
+{
+       return (start <= addr) && (start + size > addr);
+}
+
+struct hmm_buffer_object *hmm_bo_device_search_in_range(struct hmm_bo_device
+                                                       *bdev,
+                                                       unsigned int vaddr)
+{
+       struct list_head *pos;
+       struct hmm_buffer_object *bo;
+
+       __check_bodev_null_return(bdev, NULL);
+
+       mutex_lock(&bdev->fblist_mutex);
+       list_for_each(pos, &bdev->active_bo_list) {
+               bo = __list_to_hmm_bo(pos);
+               /* pass bo which has no vm_node allocated */
+               if (!hmm_bo_vm_allocated(bo))
+                       continue;
+               if (__in_range(bo->vm_node->start, bo->vm_node->size, vaddr))
+                       goto found;
+       }
+       mutex_unlock(&bdev->fblist_mutex);
+       return NULL;
+found:
+       mutex_unlock(&bdev->fblist_mutex);
+       return bo;
+}
+
+/*
+ * find a buffer object with pgnr pages from free_bo_list and
+ * activate it (remove from free_bo_list and add to
+ * active_bo_list)
+ *
+ * return NULL if no such buffer object found.
+ */
+struct hmm_buffer_object *hmm_bo_device_get_bo(struct hmm_bo_device *bdev,
+                                              unsigned int pgnr)
+{
+       struct list_head *pos;
+       struct hmm_buffer_object *bo;
+
+       __check_bodev_null_return(bdev, NULL);
+
+       mutex_lock(&bdev->fblist_mutex);
+       list_for_each(pos, &bdev->free_bo_list) {
+               bo = __list_to_hmm_bo(pos);
+               if (bo->pgnr == pgnr)
+                       goto found;
+       }
+       mutex_unlock(&bdev->fblist_mutex);
+       return NULL;
+found:
+       list_del(&bo->list);
+       mutex_unlock(&bdev->fblist_mutex);
+
+       mutex_lock(&bdev->ablist_mutex);
+       list_add(&bo->list, &bdev->active_bo_list);
+       mutex_unlock(&bdev->ablist_mutex);
+
+       return bo;
+}
+
+/*
+ * destroy all buffer objects in the free_bo_list.
+ */
+void hmm_bo_device_destroy_free_bo_list(struct hmm_bo_device *bdev)
+{
+       struct hmm_buffer_object *bo;
+
+       __check_bodev_null_return(bdev, (void)0);
+
+       mutex_lock(&bdev->fblist_mutex);
+       while (!list_empty(&bdev->free_bo_list)) {
+               bo = list_first_entry(&bdev->free_bo_list,
+                                     struct hmm_buffer_object, list);
+
+               list_del(&bo->list);
+               hmm_bo_unref(bo);
+       }
+       mutex_unlock(&bdev->fblist_mutex);
+}
+
+/*
+ * destroy buffer object with start virtual address vaddr.
+ */
+void hmm_bo_device_destroy_free_bo_addr(struct hmm_bo_device *bdev,
+                                       unsigned int vaddr)
+{
+       struct list_head *pos;
+       struct hmm_buffer_object *bo;
+
+       __check_bodev_null_return(bdev, (void)0);
+
+       mutex_lock(&bdev->fblist_mutex);
+       list_for_each(pos, &bdev->free_bo_list) {
+               bo = __list_to_hmm_bo(pos);
+               /* pass bo which has no vm_node allocated */
+               if (!hmm_bo_vm_allocated(bo))
+                       continue;
+               if (bo->vm_node->start == vaddr)
+                       goto found;
+       }
+       mutex_unlock(&bdev->fblist_mutex);
+       return;
+found:
+       list_del(&bo->list);
+       mutex_unlock(&bdev->fblist_mutex);
+       hmm_bo_unref(bo);
+}
+
+/*
+ * destroy all buffer objects with pgnr pages.
+ */
+void hmm_bo_device_destroy_free_bo_size(struct hmm_bo_device *bdev,
+                                       unsigned int pgnr)
+{
+       struct list_head *pos;
+       struct hmm_buffer_object *bo;
+
+       __check_bodev_null_return(bdev, (void)0);
+
+retry:
+       mutex_lock(&bdev->fblist_mutex);
+       list_for_each(pos, &bdev->free_bo_list) {
+               bo = __list_to_hmm_bo(pos);
+               if (bo->pgnr == pgnr)
+                       goto found;
+       }
+       mutex_unlock(&bdev->fblist_mutex);
+       return;
+found:
+       list_del(&bo->list);
+       mutex_unlock(&bdev->fblist_mutex);
+       hmm_bo_unref(bo);
+       goto retry;
+}
diff --git a/drivers/media/video/mfld_ci/mfldisp/hmm/hmm_vm.c b/drivers/media/video/mfld_ci/mfldisp/hmm/hmm_vm.c
new file mode 100644
index 0000000..8080967
--- /dev/null
+++ b/drivers/media/video/mfld_ci/mfldisp/hmm/hmm_vm.c
@@ -0,0 +1,204 @@
+/*
+ * Support for Medifield PNW Camera Imaging ISP subsystem.
+ *
+ * Copyright (c) 2010 Intel Corporation. All Rights Reserved.
+ *
+ * Copyright (c) 2010 Silicon Hive www.siliconhive.com.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that 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 Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <asm/page.h>
+
+#include "mmu/isp_mmu.h"
+#include "hmm/hmm_vm.h"
+#include "hmm/hmm_common.h"
+#include "mfldisp_internal.h"
+
+static unsigned int vm_node_end(unsigned int start, unsigned int pgnr)
+{
+       return start + __pgnr_to_size(pgnr);
+}
+
+static int addr_in_vm_node(unsigned int addr,
+               struct hmm_vm_node *node)
+{
+       return (addr >= node->start) && (addr < (node->start + node->size));
+}
+
+int hmm_vm_init(struct hmm_vm *vm, unsigned int start,
+               unsigned int size)
+{
+       if (!vm)
+               return -1;
+
+       vm->start = start;
+       vm->pgnr = __size_to_pgnr_ceil(size);
+       vm->size = __pgnr_to_size(vm->pgnr);
+
+       INIT_LIST_HEAD(&vm->vm_node_list);
+       spin_lock_init(&vm->lock);
+
+       return 0;
+}
+
+void hmm_vm_clean(struct hmm_vm *vm)
+{
+       if (!vm)
+               return;
+
+       while (!list_empty(&vm->vm_node_list))
+               hmm_vm_free_node(__hmm_vm_node(vm->vm_node_list.next));
+}
+
+static struct hmm_vm_node *__alloc_hmm_vm_node(unsigned int start,
+                                              unsigned int pgnr,
+                                              struct hmm_vm *vm)
+{
+       struct hmm_vm_node *node;
+
+       node = kmalloc(sizeof(struct hmm_vm_node), GFP_KERNEL);
+       if (!node) {
+               mfld_isp_dbg(KERN_ERR, "out of memory.\n");
+               return NULL;
+       }
+
+       INIT_LIST_HEAD(&node->list);
+       node->start = start;
+       node->pgnr = pgnr;
+       node->size = __pgnr_to_size(pgnr);
+       node->vm = vm;
+
+       return node;
+}
+
+struct hmm_vm_node *hmm_vm_alloc_node(struct hmm_vm *vm, unsigned int pgnr)
+{
+       struct list_head *head, *p, *pos;
+       struct hmm_vm_node *node, *cur, *next;
+       unsigned int vm_start, vm_end;
+       unsigned int addr;
+       unsigned int size;
+
+       if (!vm)
+               return NULL;
+
+       vm_start = vm->start;
+       vm_end = vm_node_end(vm->start, vm->pgnr);
+       size = __pgnr_to_size(pgnr);
+
+       addr = vm_start;
+       pos = head = &vm->vm_node_list;
+
+       spin_lock(&vm->lock);
+
+       /*
+        * if list is empty, the loop code will not be executed.
+        */
+       list_for_each(p, head) {
+               pos = p;
+               cur = __hmm_vm_node(pos);
+               addr = vm_node_end(cur->start, cur->pgnr);
+               if (pos->next != head) {
+                       next = __hmm_vm_node(pos->next);
+                       if ((next->start - addr) >= size)
+                               goto found;
+               }
+       }
+
+       if (addr + size > vm_end) {
+               mfld_isp_dbg(KERN_INFO, "no enough virtual address space.\n");
+               goto failed;
+       }
+
+found:
+
+       node = __alloc_hmm_vm_node(addr, pgnr, vm);
+       if (!node)
+               goto failed;
+
+       list_add(&node->list, pos);
+
+       spin_unlock(&vm->lock);
+
+       return node;
+failed:
+       mfld_isp_dbg(KERN_ERR, "failed...\n");
+       spin_unlock(&vm->lock);
+
+       return NULL;
+}
+
+void hmm_vm_free_node(struct hmm_vm_node *node)
+{
+       if (node) {
+               struct hmm_vm *vm = node->vm;
+               spin_lock(&vm->lock);
+               list_del(&node->list);
+               spin_unlock(&vm->lock);
+               kfree(node);
+       }
+}
+
+struct hmm_vm_node *hmm_vm_find_node_start(struct hmm_vm *vm, unsigned int addr)
+{
+       struct list_head *pos;
+       struct hmm_vm_node *node;
+
+       if (!vm)
+               return NULL;
+
+       spin_lock(&vm->lock);
+
+       list_for_each(pos, &vm->vm_node_list) {
+               node = __hmm_vm_node(pos);
+               if (node->start == addr)
+                       goto found;
+       }
+
+       spin_unlock(&vm->lock);
+       return NULL;
+found:
+       spin_unlock(&vm->lock);
+       return node;
+}
+
+struct hmm_vm_node *hmm_vm_find_node_in_range(struct hmm_vm *vm,
+                                             unsigned int addr)
+{
+       struct list_head *pos;
+       struct hmm_vm_node *node;
+
+       if (!vm)
+               return NULL;
+
+       spin_lock(&vm->lock);
+
+       list_for_each(pos, &vm->vm_node_list) {
+               node = __hmm_vm_node(pos);
+               if (addr_in_vm_node(addr, node))
+                       goto found;
+       }
+
+       spin_unlock(&vm->lock);
+       return NULL;
+found:
+       spin_unlock(&vm->lock);
+       return node;
+}
diff --git a/drivers/media/video/mfld_ci/mfldisp/hrt/hive_isp_css_ddr_hrt.c b/drivers/media/video/mfld_ci/mfldisp/hrt/hive_isp_css_ddr_hrt.c
new file mode 100644
index 0000000..766fab1
--- /dev/null
+++ b/drivers/media/video/mfld_ci/mfldisp/hrt/hive_isp_css_ddr_hrt.c
@@ -0,0 +1,317 @@
+/*
+ * Support for Medifield PNW Camera Imaging ISP subsystem.
+ *
+ * Copyright (c) 2010 Intel Corporation. All Rights Reserved.
+ *
+ * Copyright (c) 2010 Silicon Hive www.siliconhive.com.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that 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 Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+#include <vector.h>
+#ifdef HRT_CSIM
+#include <error.h>
+#endif
+#include "hive_isp_css_defs.h"
+#include "hive_isp_css_ddr_hrt.h"
+#include "hive_isp_css_mm_hrt.h"
+#include "mfldisp_internal.h"
+#define BYTES_PER_XWORD (HIVE_ISP_DDR_WORD_BITS/8)
+#define ceil_div(a, b) (((a)+(b)-1)/(b))
+
+struct dma_spec_s {
+       unsigned int num_elems;
+       unsigned int elem_bits;
+};
+
+static struct dma_spec_s specs[] = HIVE_ISP_DDR_DMA_SPECS;
+static unsigned int num_specs = sizeof(specs) / sizeof(*specs);
+
+static unsigned int
+dma_num_elems_to_elem_width(unsigned int num_elems, unsigned int *bits)
+{
+       unsigned int i;
+       for (i = 0; i < num_specs; i++) {
+               if (specs[i].num_elems == num_elems) {
+                       *bits = specs[i].elem_bits;
+                       return 1;
+               }
+       }
+       mfld_isp_dbg(KERN_WARNING,
+                    "cannot translate number of elements (%d) to"
+                    "element bits in dma",
+                    num_elems);
+       return 0;
+}
+
+static unsigned int
+dma_elem_width_to_num_elems(unsigned int bits, unsigned int *num_elems)
+{
+       unsigned int i;
+       for (i = 0; i < num_specs; i++) {
+               if (specs[i].elem_bits == bits) {
+                       *num_elems = specs[i].num_elems;
+                       return 1;
+               }
+       }
+       mfld_isp_dbg(KERN_WARNING,
+                    "cannot translate element width (%u) to number"
+                    " of elements per word",
+                    *num_elems);
+       return 0;
+}
+
+unsigned int
+hrt_isp_css_stride_of_image_in_ddr(unsigned int width,
+                                  unsigned int bits_per_element)
+{
+       unsigned int elems_per_xword, xwords_per_line;
+
+       if (dma_elem_width_to_num_elems(bits_per_element, &elems_per_xword) ==
+           0)
+               return 0;
+       xwords_per_line = ceil_div(width, elems_per_xword);
+       return xwords_per_line * BYTES_PER_XWORD;
+}
+
+unsigned int
+hrt_isp_css_sizeof_image_in_ddr(unsigned int width,
+                               unsigned int height,
+                               unsigned int bits_per_element)
+{
+       return hrt_isp_css_stride_of_image_in_ddr(width,
+                                                 bits_per_element) * height;
+}
+
+void *
+hrt_isp_css_alloc_image_in_ddr(unsigned int width,
+                              unsigned int height,
+                                    unsigned int elems_per_xword)
+{
+       unsigned int elem_bits;
+       size_t bytes;
+
+       if (!dma_num_elems_to_elem_width(elems_per_xword, &elem_bits))
+               return NULL;
+       bytes = hrt_isp_css_sizeof_image_in_ddr(width, height, elem_bits);
+       return hrt_isp_css_mm_alloc(bytes);
+}
+
+void *
+hrt_isp_css_calloc_image_in_ddr(unsigned int width,
+                               unsigned int height,
+                               unsigned int elems_per_xword)
+{
+       unsigned int elem_bits;
+       size_t bytes;
+
+       if (!dma_num_elems_to_elem_width(elems_per_xword, &elem_bits))
+               return NULL;
+       bytes = hrt_isp_css_sizeof_image_in_ddr(width, height, elem_bits);
+       return hrt_isp_css_mm_calloc(bytes);
+}
+
+unsigned int
+hrt_isp_css_read_image_from_ddr(unsigned short *img_buf,
+                               unsigned int width,
+                               unsigned int height,
+                               unsigned int elems_per_xword,
+                               unsigned int sign_extend,
+                               void *virt_addr)
+{
+       unsigned int i, j, k, elem_bits, xwords_per_line;
+       char xword_buf[BYTES_PER_XWORD];
+       /* this is the maximum number of elements in an xword */
+       int elem_buf[BYTES_PER_XWORD];
+
+       if (!dma_num_elems_to_elem_width(elems_per_xword, &elem_bits))
+               return 0;
+       if (elem_bits == 0)
+               return 0;
+       xwords_per_line = ceil_div(width, elems_per_xword);
+
+       for (i = 0; i < height; i++) {
+               unsigned int elems_in_line = width;
+               for (j = 0; j < xwords_per_line; j++) {
+                       unsigned int elems_in_word = elems_per_xword;
+                       if (elems_in_word > elems_in_line)
+                               elems_in_word = elems_in_line;
+                       hrt_isp_css_mm_load(virt_addr, xword_buf,
+                                           BYTES_PER_XWORD);
+                       _hrt_decode_vector(xword_buf, elem_buf, elem_bits,
+                                          elem_bits, elems_per_xword,
+                                          sign_extend);
+                       for (k = 0; k < elems_in_word;
+                            k++, elems_in_line--, img_buf++)
+                               *img_buf = (unsigned short)elem_buf[k];
+                       virt_addr += BYTES_PER_XWORD;
+               }
+       }
+
+       return 1;
+}
+
+unsigned int
+hrt_isp_css_write_image_to_ddr(const unsigned short *img_buf,
+                              unsigned int width,
+                              unsigned int height,
+                              unsigned int elems_per_xword,
+                              unsigned int sign_extend,
+                              void *virt_addr)
+{
+       unsigned int i, j, k, elem_bits, xwords_per_line;
+       char xword_buf[BYTES_PER_XWORD];
+       int elem_buf[BYTES_PER_XWORD];
+
+       if (!dma_num_elems_to_elem_width(elems_per_xword, &elem_bits))
+               return 0;
+       if (elem_bits == 0)
+               return 0;
+       xwords_per_line = ceil_div(width, elems_per_xword);
+
+       for (i = 0; i < height; i++) {
+               unsigned int elems_in_line = width;
+               for (j = 0; j < xwords_per_line; j++) {
+                       unsigned int elems_in_word = elems_per_xword;
+                       if (elems_in_word > elems_in_line)
+                               elems_in_word = elems_in_line;
+                       for (k = 0; k < elems_in_word;
+                            k++, elems_in_line--, img_buf++)
+                               elem_buf[k] = *img_buf;
+                       _hrt_encode_vector(elem_buf, xword_buf, elem_bits,
+                                          elem_bits, elems_per_xword,
+                                          sign_extend);
+                       hrt_isp_css_mm_store(virt_addr, xword_buf,
+                                            BYTES_PER_XWORD);
+                       virt_addr += BYTES_PER_XWORD;
+               }
+       }
+
+       return 1;
+}
+
+void *
+hrt_isp_css_alloc_gdc_lut_in_ddr(void)
+{
+       return hrt_isp_css_mm_alloc(HRT_GDC_LUT_BYTES);
+}
+
+void
+hrt_isp_css_write_gdc_lut_to_ddr(short lut[4][HRT_GDC_N], void *virt_addr)
+{
+       unsigned int i;
+       for (i = 0; i < HRT_GDC_N; i++) {
+               unsigned int entry_0 = lut[0][i] & HRT_GDC_BCI_COEF_MASK,
+                   entry_1 = lut[1][i] & HRT_GDC_BCI_COEF_MASK,
+                   entry_2 = lut[2][i] & HRT_GDC_BCI_COEF_MASK,
+                   entry_3 = lut[3][i] & HRT_GDC_BCI_COEF_MASK,
+                   word_0 = entry_0 | (entry_1 << HRT_GDC_BCI_COEF_BITS),
+                   word_1 = entry_2 | (entry_3 << HRT_GDC_BCI_COEF_BITS);
+               hrt_isp_css_mm_store_int(virt_addr, word_0);
+               virt_addr += 4;
+               hrt_isp_css_mm_store_int(virt_addr, word_1);
+               virt_addr += 4;
+       }
+}
+
+unsigned int
+hrt_isp_css_read_unsigned(unsigned short *target,
+                         unsigned int width,
+                         unsigned int height,
+                         unsigned int source_bits_per_element,
+                         void *source)
+{
+       unsigned int elems_per_xword;
+
+       if (dma_elem_width_to_num_elems(source_bits_per_element,
+                                       &elems_per_xword) == 0)
+               return 0;
+       return hrt_isp_css_read_image_from_ddr(target, width, height,
+                                              elems_per_xword, 0, source);
+}
+
+unsigned int
+hrt_isp_css_read_signed(short *target,
+                       unsigned int width,
+                       unsigned int height,
+                       unsigned int source_bits_per_element,
+                       void *source)
+{
+       unsigned int elems_per_xword;
+
+       if (dma_elem_width_to_num_elems(source_bits_per_element,
+                                       &elems_per_xword) == 0)
+               return 0;
+       return hrt_isp_css_read_image_from_ddr((unsigned short *)target, width,
+                                              height, elems_per_xword, 1,
+                                              source);
+}
+
+unsigned int
+hrt_isp_css_write_unsigned(const unsigned short *source,
+                          unsigned int width,
+                          unsigned int height,
+                          unsigned int target_bits_per_element,
+                          void *target)
+{
+       unsigned int elems_per_xword;
+
+       if (dma_elem_width_to_num_elems(target_bits_per_element,
+                                       &elems_per_xword) == 0)
+               return 0;
+       return hrt_isp_css_write_image_to_ddr(source, width, height,
+                                             elems_per_xword, 0, target);
+}
+
+unsigned int
+hrt_isp_css_write_signed(const short *source,
+                        unsigned int width,
+                        unsigned int height,
+                        unsigned int target_bits_per_element,
+                        void *target)
+{
+       unsigned int elems_per_xword;
+
+       if (dma_elem_width_to_num_elems(target_bits_per_element,
+                                       &elems_per_xword) == 0)
+               return 0;
+       return hrt_isp_css_write_image_to_ddr((const unsigned short *)source,
+                                             width, height, elems_per_xword, 1,
+                                             target);
+}
+
+void *
+hrt_isp_css_alloc(unsigned int width,
+                 unsigned int height,
+                 unsigned int bits_per_element)
+{
+       size_t bytes;
+
+       bytes =
+           hrt_isp_css_sizeof_image_in_ddr(width, height, bits_per_element);
+       return hrt_isp_css_mm_alloc(bytes);
+}
+
+void *
+hrt_isp_css_calloc(unsigned int width,
+                  unsigned int height,
+                  unsigned int bits_per_element)
+{
+       size_t bytes;
+
+       bytes =
+           hrt_isp_css_sizeof_image_in_ddr(width, height, bits_per_element);
+       return hrt_isp_css_mm_calloc(bytes);
+}
diff --git a/drivers/media/video/mfld_ci/mfldisp/hrt/hive_isp_css_mm_hrt.c b/drivers/media/video/mfld_ci/mfldisp/hrt/hive_isp_css_mm_hrt.c
new file mode 100644
index 0000000..e11cd9f
--- /dev/null
+++ b/drivers/media/video/mfld_ci/mfldisp/hrt/hive_isp_css_mm_hrt.c
@@ -0,0 +1,138 @@
+/*
+ * Support for Medifield PNW Camera Imaging ISP subsystem.
+ *
+ * Copyright (c) 2010 Intel Corporation. All Rights Reserved.
+ *
+ * Copyright (c) 2010 Silicon Hive www.siliconhive.com.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that 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 Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+#include <hmm/hmm.h>
+
+/* not sure if we need these two for page related macros,
+ * need to double check */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include "mfldisp_internal.h"
+
+#define __page_align(size)     (((size) + (PAGE_SIZE-1)) & (~(PAGE_SIZE-1)))
+
+static unsigned init_done;
+void hrt_isp_css_mm_init(void)
+{
+       mfld_isp_dbg(KERN_DEBUG, "hrt_isp_css_mm_init...\n");
+       hmm_init();
+       init_done = 1;
+       mfld_isp_dbg(KERN_DEBUG, "hrt_isp_css_mm_init... done\n");
+}
+
+void hrt_isp_css_mm_load(void *virt_addr, void *data, size_t bytes)
+{
+       hmm_load(virt_addr, data, bytes);
+}
+
+void hrt_isp_css_mm_store(void *virt_addr, const void *data, size_t bytes)
+{
+       hmm_store(virt_addr, data, bytes);
+}
+
+void hrt_isp_css_mm_free(void *virt_addr)
+{
+       hmm_free(virt_addr);
+}
+
+void hrt_isp_css_mm_clear(void)
+{
+       if (init_done) {
+               hmm_cleanup();
+               init_done = 0;
+       }
+}
+
+static unsigned int my_userptr, my_num_pages;
+void hrt_isp_css_mm_set_user_ptr(unsigned int userptr, unsigned int num_pages)
+{
+       my_userptr = userptr;
+       my_num_pages = num_pages;
+}
+
+void *hrt_isp_css_mm_alloc(size_t bytes)
+{
+       if (!init_done)
+               hrt_isp_css_mm_init();
+
+       if (my_userptr == 0)
+               return (void *)hmm_alloc(bytes, HMM_BO_PRIVATE, 0, 0);
+       else {
+               if (my_num_pages < ((__page_align(bytes)) >> PAGE_SHIFT))
+                       mfld_isp_dbg(KERN_ERR, "user space memory size is less"
+                                    " than the expected size..\n");
+               else if (my_num_pages > ((__page_align(bytes)) >> PAGE_SHIFT))
+                       mfld_isp_dbg(KERN_ERR, "user space memory size is"
+                                    " large than the expected size..\n");
+               return (void *)hmm_alloc(bytes, HMM_BO_USER, 0, my_userptr);
+       }
+}
+
+void *hrt_isp_css_mm_calloc(size_t bytes)
+{
+       void *ptr = hrt_isp_css_mm_alloc(bytes);
+       if (!ptr)
+               hmm_set(ptr, 0, bytes);
+       return ptr;
+}
+
+int hrt_isp_css_mm_load_int(void *virt_addr)
+{
+       int v = 0;
+       hrt_isp_css_mm_load(virt_addr, &v, sizeof(v));
+       return v;
+}
+
+short hrt_isp_css_mm_load_short(void *virt_addr)
+{
+       short v = 0;
+       hrt_isp_css_mm_load(virt_addr, &v, sizeof(v));
+       return v;
+}
+
+char hrt_isp_css_mm_load_char(void *virt_addr)
+{
+       char v = 0;
+       hrt_isp_css_mm_load(virt_addr, &v, sizeof(v));
+       return v;
+}
+
+void hrt_isp_css_mm_store_char(void *virt_addr, char data)
+{
+       hrt_isp_css_mm_store(virt_addr, &data, sizeof(data));
+}
+
+void hrt_isp_css_mm_store_short(void *virt_addr, short data)
+{
+       hrt_isp_css_mm_store(virt_addr, &data, sizeof(data));
+}
+
+void hrt_isp_css_mm_store_int(void *virt_addr, int data)
+{
+       hrt_isp_css_mm_store(virt_addr, &data, sizeof(data));
+}
+
+void *hrt_isp_css_virt_to_phys(void *virt_addr)
+{
+       return (void *)hmm_virt_to_phys(virt_addr);
+}
diff --git a/drivers/media/video/mfld_ci/mfldisp/include/hmm/hmm.h b/drivers/media/video/mfld_ci/mfldisp/include/hmm/hmm.h
new file mode 100644
index 0000000..05c5e35
--- /dev/null
+++ b/drivers/media/video/mfld_ci/mfldisp/include/hmm/hmm.h
@@ -0,0 +1,71 @@
+/*
+ * Support for Medifield PNW Camera Imaging ISP subsystem.
+ *
+ * Copyright (c) 2010 Intel Corporation. All Rights Reserved.
+ *
+ * Copyright (c) 2010 Silicon Hive www.siliconhive.com.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that 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 Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#ifndef        __HMM_H__
+#define        __HMM_H__
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+
+#include "hmm/hmm_bo.h"
+
+int hmm_init(void);
+void hmm_cleanup(void);
+
+void *hmm_alloc(size_t bytes, enum hmm_bo_type type,
+               int from_highmem, unsigned int userptr);
+void hmm_free(void *ptr);
+int hmm_load(void *virt, void *data, unsigned int bytes);
+int hmm_store(void *virt, const void *data, unsigned int bytes);
+int hmm_set(void *virt, char c, unsigned int bytes);
+
+/*
+ * get kernel memory physical address from ISP virtual address.
+ */
+unsigned int hmm_virt_to_phys(void *virt);
+
+/*
+ * map ISP memory starts with virt to kernel virtual address
+ * by using vmap. return NULL if failed.
+ *
+ * !! user needs to use vunmap to unmap it manually before calling
+ * hmm_free to free the memory.
+ *
+ * virt must be the start address of ISP memory (return by hmm_alloc),
+ * do not pass any other address.
+ */
+void *hmm_vmap(void *virt);
+
+/*
+ * map ISP memory starts with virt to specific vma.
+ *
+ * used for mmap operation.
+ *
+ * virt must be the start address of ISP memory (return by hmm_alloc),
+ * do not pass any other address.
+ */
+int hmm_mmap(struct vm_area_struct *vma, void *virt);
+
+#endif
diff --git a/drivers/media/video/mfld_ci/mfldisp/include/hmm/hmm_bo.h b/drivers/media/video/mfld_ci/mfldisp/include/hmm/hmm_bo.h
new file mode 100644
index 0000000..50fc75b
--- /dev/null
+++ b/drivers/media/video/mfld_ci/mfldisp/include/hmm/hmm_bo.h
@@ -0,0 +1,313 @@
+/*
+ * Support for Medifield PNW Camera Imaging ISP subsystem.
+ *
+ * Copyright (c) 2010 Intel Corporation. All Rights Reserved.
+ *
+ * Copyright (c) 2010 Silicon Hive www.siliconhive.com.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that 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 Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#ifndef        __HMM_BO_H__
+#define        __HMM_BO_H__
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+#include <linux/kref.h>
+
+#include "hmm_common.h"
+
+#ifdef USE_DRM_MM
+#include <drm/drm_mm.h>
+#else
+#include "hmm/hmm_vm.h"
+#endif
+
+#define        __check_bo_null_return(bo, exp) \
+       __check_null_return(bo, exp, "NULL hmm buffer object.\n")
+
+struct hmm_bo_device;
+
+/*
+ * buffer object type.
+ *
+ *     HMM_BO_PRIVATE:
+ *     pages are allocated by driver itself.
+ *     HMM_BO_SHARE:
+ *     pages are allocated by other component. currently: video driver.
+ *     HMM_BO_USER:
+ *     pages are allocated in user space process.
+ *
+ */
+enum hmm_bo_type {
+       HMM_BO_PRIVATE,
+       HMM_BO_SHARE,
+       HMM_BO_USER,
+};
+
+#define        HMM_BO_VM_ALLOCED       0x1
+#define        HMM_BO_PAGE_ALLOCED     0x2
+#define        HMM_BO_BINDED           0x4
+#define        HMM_BO_MMAPED           0x8
+
+#ifdef HMM_BO_VMAP_SUPPORT
+#define        HMM_BO_VMAPED           0x10
+#endif
+
+#define        HMM_BO_ACTIVE           0x1000
+
+struct __page_block {
+       struct list_head        list;
+       struct page             *pages;
+       int                     order;
+};
+
+struct hmm_buffer_object {
+       struct hmm_bo_device    *bdev;
+       struct list_head        list;
+       struct kref             kref;
+
+       /* mutex protecting this BO */
+       struct mutex            mutex;
+
+       enum hmm_bo_type        type;
+
+#ifdef HMM_BO_VMAP_SUPPORT
+       /*
+        * kernel virtual address got by vmap, used by kernel
+        * to access the buffer object's pages contiguously.
+        */
+       void                    *virt;
+#endif
+
+       struct list_head        pgblocks;
+       struct page             **pages;        /* physical pages */
+       unsigned int            pgnr;   /* page number */
+       int                     from_highmem;
+#ifdef CI_VA_SHARE_BUFFER
+       /* for share buffer created by video driver */
+       unsigned int            handle;
+#endif
+       int                     mmap_count;
+#ifdef USE_DRM_MM
+       /* protected by bdev->vm_lock */
+       struct drm_mm_node      *vm_node;
+#else
+       struct hmm_vm_node      *vm_node;
+#endif
+       int                     status;
+
+       /*
+        * release callback for releasing buffer object.
+        *
+        * usually set to the release function to release the
+        * upper level buffer object which has hmm_buffer_object
+        * embedded in. if the hmm_buffer_object is dynamically
+        * created by hmm_bo_create, release will set to kfree.
+        *
+        */
+       void (*release)(struct hmm_buffer_object *bo);
+};
+
+#define        __list_to_hmm_bo(list_ptr)      \
+       list_entry((list_ptr), struct hmm_buffer_object, list)
+
+/*
+ * use this function to initialize pre-allocated hmm_buffer_object.
+ *
+ * the hmm_buffer_object use reference count to manage its life cycle.
+ *
+ * bo->kref is inited to 1.
+ *
+ * use hmm_bo_ref/hmm_bo_unref increase/decrease the reference count,
+ * and hmm_bo_unref will free resource of buffer object (but not the
+ * buffer object itself as it can be both pre-allocated or dynamically
+ * allocated) when reference reaches 0.
+ *
+ * see detailed description of hmm_bo_ref/hmm_bo_unref below.
+ *
+ * as hmm_buffer_object may be used as an embedded object in an upper
+ * level object, a release callback must be provided. if it is
+ * embedded in upper level object, set release call back to release
+ * function of that object. if no upper level object, set release
+ * callback to NULL.
+ *
+ * ex:
+ *     struct hmm_buffer_object bo;
+ *     hmm_bo_init(bdev, &bo, pgnr, NULL);
+ *
+ * or
+ *     struct my_buffer_object {
+ *             struct hmm_buffer_object bo;
+ *             ...
+ *     };
+ *
+ *     void my_buffer_release(struct hmm_buffer_object *bo)
+ *     {
+ *             struct my_buffer_object *my_bo =
+ *                     container_of(bo, struct my_buffer_object, bo);
+ *
+ *             ...     // release resource in my_buffer_object
+ *
+ *             kfree(my_bo);
+ *     }
+ *
+ *     struct my_buffer_object *my_bo =
+ *             kmalloc(sizeof(*my_bo), GFP_KERNEL);
+ *
+ *     hmm_bo_init(bdev, &my_bo->bo, pgnr, my_buffer_release);
+ *     ...
+ *
+ *     hmm_bo_unref(&my_bo->bo);
+ */
+int hmm_bo_init(struct hmm_bo_device *bdev,
+               struct hmm_buffer_object *bo,
+               unsigned int pgnr,
+               void (*release)(struct hmm_buffer_object *));
+
+/*
+ * use these functions to dynamically alloc hmm_buffer_object.
+ *
+ * hmm_bo_init will called for that allocated buffer object, and
+ * the release callback is set to kfree.
+ *
+ * ex:
+ *     hmm_buffer_object *bo = hmm_bo_create(bdev, pgnr);
+ *     ...
+ *     hmm_bo_unref(bo);
+ */
+struct hmm_buffer_object *hmm_bo_create(struct hmm_bo_device *bdev,
+               int pgnr);
+
+/*
+ * increse buffer object reference.
+ */
+void hmm_bo_ref(struct hmm_buffer_object *bo);
+
+/*
+ * decrese buffer object reference. if reference reaches 0,
+ * release function of the buffer object will be called.
+ *
+ * this call is also used to release hmm_buffer_object or its
+ * upper level object with it embedded in. you need to call
+ * this function when it is no longer used.
+ *
+ * Note:
+ *
+ * user dont need to care about internal resource release of
+ * the buffer object in the release callback, it will be
+ * handled internally.
+ *
+ * this call will only release internal resource of the buffer
+ * object but will not free the buffer object itself, as the
+ * buffer object can be both pre-allocated statically or
+ * dynamically allocated. so user need to deal with the release
+ * of the buffer object itself manually. below example shows
+ * the normal case of using the buffer object.
+ *
+ *     struct hmm_buffer_object *bo = hmm_bo_create(bdev, pgnr);
+ *     ......
+ *     hmm_bo_unref(bo);
+ *
+ * or:
+ *
+ *     struct hmm_buffer_object bo;
+ *
+ *     hmm_bo_init(bdev, &bo, pgnr, NULL);
+ *     ...
+ *     hmm_bo_unref(&bo);
+ */
+void hmm_bo_unref(struct hmm_buffer_object *bo);
+
+
+/*
+ * put buffer object to unactivated status, meaning put it into
+ * bo->bdev->free_bo_list, but not destroy it.
+ *
+ * this can be used to instead of hmm_bo_destroy if there are
+ * lots of petential hmm_bo_init/hmm_bo_destroy operations with
+ * the same buffer object size. using this with hmm_bo_device_get_bo
+ * can improve performace as lots of memory allocation/free are
+ * avoided..
+ */
+void hmm_bo_unactivate(struct hmm_buffer_object *bo);
+int hmm_bo_activated(struct hmm_buffer_object *bo);
+
+/*
+ * allocate/free virtual address space for the bo.
+ */
+int hmm_bo_alloc_vm(struct hmm_buffer_object *bo);
+void hmm_bo_free_vm(struct hmm_buffer_object *bo);
+int hmm_bo_vm_allocated(struct hmm_buffer_object *bo);
+
+/*
+ * allocate/free physical pages for the bo. will try to alloc mem
+ * from highmem if from_highmem is set, and type indicate that the
+ * pages will be allocated by using video driver (for share buffer)
+ * or by ISP driver itself.
+ */
+int hmm_bo_alloc_pages(struct hmm_buffer_object *bo,
+               enum hmm_bo_type type, int from_highmem,
+               unsigned int userptr);
+void hmm_bo_free_pages(struct hmm_buffer_object *bo);
+int hmm_bo_page_allocated(struct hmm_buffer_object *bo);
+
+/*
+ * get physical page info of the bo.
+ */
+int hmm_bo_get_page_info(struct hmm_buffer_object *bo,
+               struct page ***pages, int *pgnr);
+
+/*
+ * bind/unbind the physical pages to a virtual address space.
+ */
+int hmm_bo_bind(struct hmm_buffer_object *bo);
+void hmm_bo_unbind(struct hmm_buffer_object *bo);
+int hmm_bo_binded(struct hmm_buffer_object *bo);
+
+#ifdef HMM_BO_VMAP_SUPPORT
+/*
+ * map/unmap buffer object's physical pages to contiguous kernel
+ * virtual address. the mapped virtual address is kept in bo->virt.
+ *
+ * return non-zero if failed.
+ */
+int hmm_bo_vmap(struct hmm_buffer_object *bo);
+void hmm_bo_vunmap(struct hmm_buffer_object *bo);
+int hmm_bo_vmapped(struct hmm_buffer_object *bo);
+#else
+/*
+ * vmap buffer object's pages to contiguous kernel virtual address.
+ * user needs to call vunmap manually to unmap it.
+ */
+void *hmm_bo_vmap(struct hmm_buffer_object *bo);
+#endif
+
+/*
+ * mmap the bo's physical pages to specific vma.
+ *
+ * vma's address space size must be the same as bo's size,
+ * otherwise it will return -EINVAL.
+ *
+ * vma->vm_flags will be set to (VM_RESERVED | VM_IO).
+ */
+int hmm_bo_mmap(struct vm_area_struct *vma,
+               struct hmm_buffer_object *bo);
+
+#endif
diff --git a/drivers/media/video/mfld_ci/mfldisp/include/hmm/hmm_bo_dev.h b/drivers/media/video/mfld_ci/mfldisp/include/hmm/hmm_bo_dev.h
new file mode 100644
index 0000000..dbd5056
--- /dev/null
+++ b/drivers/media/video/mfld_ci/mfldisp/include/hmm/hmm_bo_dev.h
@@ -0,0 +1,124 @@
+/*
+ * Support for Medifield PNW Camera Imaging ISP subsystem.
+ *
+ * Copyright (c) 2010 Intel Corporation. All Rights Reserved.
+ *
+ * Copyright (c) 2010 Silicon Hive www.siliconhive.com.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that 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 Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#ifndef        __HMM_BO_DEV_H__
+#define        __HMM_BO_DEV_H__
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+
+#include "mmu/isp_mmu.h"
+#include "hmm/hmm_common.h"
+
+#ifdef USE_DRM_MM
+#include <drm/drm_mm.h>
+#else
+#include "hmm/hmm_vm.h"
+#endif
+
+#define        __check_bodev_null_return(bdev, exp)    \
+               __check_null_return(bdev, exp, \
+                       "NULL hmm_bo_device.\n")
+
+#define        HMM_BO_DEVICE_INITED    0x1
+
+struct hmm_buffer_object;
+
+struct hmm_bo_device {
+       /* isp_mmu provides lock itself */
+       struct isp_mmu          mmu;
+
+#ifdef USE_DRM_MM
+       /* drm_mm does not support lock itself */
+       struct drm_mm           vaddr_space;
+       rwlock_t                vm_lock;
+#else
+       /* hmm_vm provides lock itself */
+       struct hmm_vm           vaddr_space;
+#endif
+
+       struct list_head        free_bo_list;
+       struct mutex            fblist_mutex;
+       struct list_head        active_bo_list;
+       struct mutex            ablist_mutex;
+
+       int                     flag;
+};
+
+int hmm_bo_device_init(struct hmm_bo_device *bdev,
+               struct isp_mmu_driver *mmu_driver,
+               unsigned int vaddr_start, unsigned int size);
+
+/*
+ * clean up all hmm_bo_device related things.
+ */
+void hmm_bo_device_exit(struct hmm_bo_device *bdev);
+
+/*
+ * whether the bo device is inited or not.
+ */
+int hmm_bo_device_inited(struct hmm_bo_device *bdev);
+
+/*
+ * find the buffer object with virtual address vaddr.
+ * return NULL if no such buffer object found.
+ */
+struct hmm_buffer_object *hmm_bo_device_search_start(
+               struct hmm_bo_device *bdev, unsigned int vaddr);
+
+/*
+ * find the buffer object with virtual address vaddr.
+ * return NULL if no such buffer object found.
+ */
+struct hmm_buffer_object *hmm_bo_device_search_in_range(
+               struct hmm_bo_device *bdev, unsigned int vaddr);
+
+/*
+ * find a buffer object with pgnr pages from free_bo_list and
+ * activate it (remove from free_bo_list and add to
+ * active_bo_list)
+ *
+ * return NULL if no such buffer object found.
+ */
+struct hmm_buffer_object *hmm_bo_device_get_bo(
+               struct hmm_bo_device *bdev, unsigned int pgnr);
+
+/*
+ * destroy all buffer objects in the free_bo_list.
+ */
+void hmm_bo_device_destroy_free_bo_list(struct hmm_bo_device *bdev);
+/*
+ * destroy buffer object with start virtual address vaddr.
+ */
+void hmm_bo_device_destroy_free_bo_addr(struct hmm_bo_device *bdev,
+               unsigned int vaddr);
+/*
+ * destroy all buffer objects with pgnr pages.
+ */
+void hmm_bo_device_destroy_free_bo_size(struct hmm_bo_device *bdev,
+               unsigned int pgnr);
+
+#endif
diff --git a/drivers/media/video/mfld_ci/mfldisp/include/hmm/hmm_common.h b/drivers/media/video/mfld_ci/mfldisp/include/hmm/hmm_common.h
new file mode 100644
index 0000000..8a1368f
--- /dev/null
+++ b/drivers/media/video/mfld_ci/mfldisp/include/hmm/hmm_common.h
@@ -0,0 +1,121 @@
+/*
+ * Support for Medifield PNW Camera Imaging ISP subsystem.
+ *
+ * Copyright (c) 2010 Intel Corporation. All Rights Reserved.
+ *
+ * Copyright (c) 2010 Silicon Hive www.siliconhive.com.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that 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 Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#ifndef        __HMM_BO_COMMON_H__
+#define        __HMM_BO_COMMON_H__
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+
+/*
+ * print and debug micros.
+ */
+#define        HMM_BO_NAME     "HMM"
+
+#define        __hmm_printk(level, fmt, arg ...) \
+       do { \
+               printk(level "%s: " fmt, HMM_BO_NAME, ## arg); \
+               udelay(10000); \
+       } while (0)
+
+#define        __hmm_printk_detail(level, fmt, arg ...)        \
+       do { \
+               printk(level "%s: %s: %d: " fmt, HMM_BO_NAME, \
+                       __func__, __LINE__, ## arg); \
+               udelay(10000); \
+       } while (0)
+
+#define        __hmm_info(fmt, arg ...)                \
+       __hmm_printk(KERN_INFO, fmt, ## arg)
+
+#define        __hmm_warn(fmt, arg ...)                \
+       __hmm_printk_detail(KERN_WARNING, fmt, ## arg)
+
+#define        __hmm_err(fmt, arg ...)         \
+       __hmm_printk_detail(KERN_ERR, fmt, ## arg)
+
+extern int hmm_dbg;
+#define        __hmm_dbg(level, fmt, arg...) \
+       do {\
+               if ((hmm_dbg) >= (level)) \
+                       __hmm_printk_detail(KERN_DEBUG, fmt, ## arg);\
+       } while (0)
+
+/*
+ * some common use micros
+ */
+#define        __var_equal(var1, var2, fmt, arg ...)   \
+       do { \
+               if ((var1) == (var2))\
+                       __hmm_err(fmt, ## arg); \
+       } while (0)
+
+#define        __var_equal_return(var1, var2, exp, fmt, arg ...)       \
+       do { \
+               if ((var1) == (var2)) { \
+                       __hmm_err(fmt, ## arg); \
+                       return exp;\
+               } \
+       } while (0)
+
+#define        __var_equal_goto(var1, var2, label, fmt, arg ...)       \
+       do { \
+               if ((var1) == (var2)) { \
+                       __hmm_err(fmt, ## arg); \
+                       goto label;\
+               } \
+       } while (0)
+
+
+#define        __var_not_equal(var1, var2, fmt, arg ...)       \
+       do { \
+               if ((var1) != (var2))\
+                       __hmm_err(fmt, ## arg); \
+       } while (0)
+
+#define        __var_not_equal_return(var1, var2, exp, fmt, arg ...)   \
+       do { \
+               if ((var1) != (var2)) { \
+                       __hmm_err(fmt, ## arg); \
+                       return exp;\
+               } \
+       } while (0)
+
+#define        __var_not_equal_goto(var1, var2, label, fmt, arg ...)   \
+       do { \
+               if ((var1) != (var2)) { \
+                       __hmm_err(fmt, ## arg); \
+                       goto label;\
+               } \
+       } while (0)
+
+#define        __check_null(ptr, fmt, arg...)  \
+               __var_equal(ptr, NULL, fmt, ## arg)
+
+#define        __check_null_return(ptr, exp, fmt, arg ...)     \
+               __var_equal_return(ptr, NULL, exp, fmt, ## arg)
+
+#define        __check_null_goto(ptr, label, fmt, arg...)      \
+               __var_equal_goto(ptr, NULL, label, fmt, ## arg)
+
+#endif
diff --git a/drivers/media/video/mfld_ci/mfldisp/include/hmm/hmm_vm.h b/drivers/media/video/mfld_ci/mfldisp/include/hmm/hmm_vm.h
new file mode 100644
index 0000000..24e3310
--- /dev/null
+++ b/drivers/media/video/mfld_ci/mfldisp/include/hmm/hmm_vm.h
@@ -0,0 +1,67 @@
+/*
+ * Support for Medifield PNW Camera Imaging ISP subsystem.
+ *
+ * Copyright (c) 2010 Intel Corporation. All Rights Reserved.
+ *
+ * Copyright (c) 2010 Silicon Hive www.siliconhive.com.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that 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 Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#ifndef        __HMM_VM_H__
+#define        __HMM_VM_H__
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include <linux/list.h>
+
+struct hmm_vm {
+       unsigned int start;
+       unsigned int pgnr;
+       unsigned int size;
+       struct list_head vm_node_list;
+       spinlock_t lock;
+};
+
+struct hmm_vm_node {
+       struct list_head list;
+       unsigned int start;
+       unsigned int pgnr;
+       unsigned int size;
+       struct hmm_vm *vm;
+};
+
+#define        __hmm_vm_node(list_ptr) \
+       list_entry((list_ptr), struct hmm_vm_node, list)
+
+int hmm_vm_init(struct hmm_vm *vm, unsigned int start,
+               unsigned int size);
+
+void hmm_vm_clean(struct hmm_vm *vm);
+
+struct hmm_vm_node *hmm_vm_alloc_node(struct hmm_vm *vm,
+               unsigned int pgnr);
+
+void hmm_vm_free_node(struct hmm_vm_node *node);
+
+struct hmm_vm_node *hmm_vm_find_node_start(struct hmm_vm *vm,
+               unsigned int addr);
+
+struct hmm_vm_node *hmm_vm_find_node_in_range(struct hmm_vm *vm,
+               unsigned int addr);
+
+#endif
--
1.6.2.5

-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0005-ISP-driver-The-low-level-memory-management-of-ISP.patch
Type: application/octet-stream
Size: 82603 bytes
Desc: 0005-ISP-driver-The-low-level-memory-management-of-ISP.patch
URL: <http://lists.meego.com/pipermail/meego-kernel/attachments/20101202/64cf85a2/attachment-0001.obj>


More information about the MeeGo-kernel mailing list