First hwcomposer code drop for marvin

Issued from Intel internal commit : 58771d

Change-Id: I8437d663e3b9baa0164517c0ece83b77b5864e8f
Signed-off-by: Benjamin Pujol <benjamin.pujol@intel.com>
Signed-off-by: Victor Tasayco Loarte <victorx.tasayco.loarte@intel.com>
Signed-off-by: Guilhem IMBERTON <guilhem.imberton@intel.com>
diff --git a/merrifield/Android.mk b/merrifield/Android.mk
new file mode 100644
index 0000000..8dbd160
--- /dev/null
+++ b/merrifield/Android.mk
@@ -0,0 +1,26 @@
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+LOCAL_ROOT_PATH := $(call my-dir)
+
+ifeq ($(INTEL_HWC_MERRIFIELD),true)
+include $(LOCAL_PATH)/platforms/merrifield/Android.mk
+endif
+
+ifeq ($(INTEL_HWC_MOOREFIELD),true)
+include $(LOCAL_PATH)/platforms/merrifield_plus/Android.mk
+endif
+
diff --git a/merrifield/common/base/DisplayAnalyzer.cpp b/merrifield/common/base/DisplayAnalyzer.cpp
new file mode 100755
index 0000000..5da7403
--- /dev/null
+++ b/merrifield/common/base/DisplayAnalyzer.cpp
@@ -0,0 +1,907 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#include <HwcTrace.h>
+#include <IDisplayDevice.h>
+#include <DisplayQuery.h>
+#include <BufferManager.h>
+#include <DisplayPlaneManager.h>
+#include <Hwcomposer.h>
+#include <DisplayAnalyzer.h>
+#include <cutils/properties.h>
+#include <GraphicBuffer.h>
+#include <ExternalDevice.h>
+#ifdef INTEL_WIDI_MERRIFIELD
+#include <VirtualDevice.h>
+#endif
+
+namespace android {
+namespace intel {
+
+DisplayAnalyzer::DisplayAnalyzer()
+    : mInitialized(false),
+      mVideoExtModeEnabled(true),
+      mVideoExtModeEligible(false),
+      mVideoExtModeActive(false),
+      mBlankDevice(false),
+      mOverlayAllowed(true),
+      mActiveInputState(true),
+      mIgnoreVideoSkipFlag(false),
+      mProtectedVideoSession(false),
+      mCachedNumDisplays(0),
+      mCachedDisplays(0),
+      mPendingEvents(),
+      mEventMutex(),
+      mEventHandledCondition()
+{
+}
+
+DisplayAnalyzer::~DisplayAnalyzer()
+{
+}
+
+bool DisplayAnalyzer::initialize()
+{
+    // by default video extended mode is enabled
+    char prop[PROPERTY_VALUE_MAX];
+    if (property_get("hwc.video.extmode.enable", prop, "1") > 0) {
+        mVideoExtModeEnabled = atoi(prop) ? true : false;
+    }
+    mVideoExtModeEligible = false;
+    mVideoExtModeActive = false;
+    mBlankDevice = false;
+    mOverlayAllowed = true;
+    mActiveInputState = true;
+    mIgnoreVideoSkipFlag = false;
+    mProtectedVideoSession = false;
+    mCachedNumDisplays = 0;
+    mCachedDisplays = 0;
+    mPendingEvents.clear();
+    mVideoStateMap.clear();
+    mInitialized = true;
+
+    return true;
+}
+
+void DisplayAnalyzer::deinitialize()
+{
+    mPendingEvents.clear();
+    mVideoStateMap.clear();
+    mInitialized = false;
+}
+
+void DisplayAnalyzer::analyzeContents(
+        size_t numDisplays, hwc_display_contents_1_t** displays)
+{
+    // cache and use them only in this context during analysis
+    mCachedNumDisplays = numDisplays;
+    mCachedDisplays = displays;
+
+    handlePendingEvents();
+
+    if (mVideoExtModeEnabled) {
+        handleVideoExtMode();
+    }
+
+    if (mBlankDevice) {
+        // this will make sure device is blanked after geometry changes.
+        // blank event is only processed once
+        blankSecondaryDevice();
+    }
+}
+
+void DisplayAnalyzer::handleVideoExtMode()
+{
+    bool eligible = mVideoExtModeEligible;
+    checkVideoExtMode();
+    if (eligible == mVideoExtModeEligible) {
+        if (mVideoExtModeActive) {
+            // need to mark all layers
+            setCompositionType(0, HWC_OVERLAY, false);
+        }
+        return;
+    }
+
+    if (mVideoExtModeEligible) {
+        if (mActiveInputState) {
+            VTRACE("input is active");
+        } else {
+            enterVideoExtMode();
+        }
+    } else {
+        exitVideoExtMode();
+    }
+}
+
+void DisplayAnalyzer::checkVideoExtMode()
+{
+    if (mVideoStateMap.size() != 1) {
+        mVideoExtModeEligible = false;
+        return;
+    }
+
+    Hwcomposer *hwc = &Hwcomposer::getInstance();
+
+    ExternalDevice *eDev = static_cast<ExternalDevice *>(hwc->getDisplayDevice(IDisplayDevice::DEVICE_EXTERNAL));
+#ifdef INTEL_WIDI_MERRIFIELD
+    VirtualDevice  *vDev = static_cast<VirtualDevice  *>(hwc->getDisplayDevice(IDisplayDevice::DEVICE_VIRTUAL));
+
+    if ((!eDev || !eDev->isConnected()) && (!vDev || !vDev->isFrameServerActive())) {
+        mVideoExtModeEligible = false;
+        return;
+    }
+#else
+    if (!eDev || !eDev->isConnected()) {
+        mVideoExtModeEligible = false;
+        return;
+    }
+#endif /*INTEL_WIDI_MERRIFIELD*/
+
+    bool geometryChanged = false;
+    int activeDisplays = 0;
+
+    hwc_display_contents_1_t *content = NULL;
+    for (int i = 0; i < (int)mCachedNumDisplays; i++) {
+        content = mCachedDisplays[i];
+        if (content == NULL) {
+            continue;
+        }
+        activeDisplays++;
+        if (content->flags & HWC_GEOMETRY_CHANGED) {
+            geometryChanged = true;
+        }
+    }
+
+    if (activeDisplays <= 1) {
+        mVideoExtModeEligible = false;
+        return;
+    }
+
+    // video state update event may come later than geometry change event.
+    // in that case, video extended mode is not detected properly.
+#if 0
+    if (geometryChanged == false) {
+        // use previous analysis result
+        return;
+    }
+#endif
+    // reset eligibility of video extended mode
+    mVideoExtModeEligible = false;
+
+    // check if there is video layer in the primary device
+    content = mCachedDisplays[0];
+    if (content == NULL) {
+        return;
+    }
+
+    buffer_handle_t videoHandle = 0;
+    bool videoLayerExist = false;
+    bool videoFullScreenOnPrimary = false;
+    bool isVideoLayerSkipped = false;
+
+    // exclude the frame buffer target layer
+    for (int j = 0; j < (int)content->numHwLayers - 1; j++) {
+        videoLayerExist = isVideoLayer(content->hwLayers[j]);
+        if (videoLayerExist) {
+            if ((content->hwLayers[j].flags & HWC_SKIP_LAYER)) {
+                isVideoLayerSkipped = true;
+            }
+            videoHandle = content->hwLayers[j].handle;
+            videoFullScreenOnPrimary = isVideoFullScreen(0, content->hwLayers[j]);
+            break;
+        }
+    }
+
+    if (videoLayerExist == false) {
+        // no video layer is found in the primary layer
+        return;
+    }
+
+    // check whether video layer exists in external device or virtual device
+    // TODO: video may exist in virtual device but no in external device or vice versa
+    // TODO: multiple video layers are not addressed here
+    for (int i = 1; i < (int)mCachedNumDisplays; i++) {
+        content = mCachedDisplays[i];
+        if (content == NULL) {
+            continue;
+        }
+
+        // exclude the frame buffer target layer
+        for (int j = 0; j < (int)content->numHwLayers - 1; j++) {
+            if (content->hwLayers[j].handle == videoHandle) {
+                isVideoLayerSkipped |= (content->hwLayers[j].flags & HWC_SKIP_LAYER);
+                VTRACE("video layer exists in device %d", i);
+                if (isVideoLayerSkipped || videoFullScreenOnPrimary){
+                    VTRACE("Video ext mode eligible, %d, %d",
+                            isVideoLayerSkipped, videoFullScreenOnPrimary);
+                    mVideoExtModeEligible = true;
+                } else {
+                    mVideoExtModeEligible = isVideoFullScreen(i, content->hwLayers[j]);
+                }
+                return;
+            }
+        }
+    }
+}
+
+bool DisplayAnalyzer::isVideoExtModeActive()
+{
+    return mVideoExtModeActive;
+}
+
+bool DisplayAnalyzer::isVideoExtModeEnabled()
+{
+#if 1
+    // enable it for run-time debugging purpose.
+    char prop[PROPERTY_VALUE_MAX];
+    if (property_get("hwc.video.extmode.enable", prop, "1") > 0) {
+        mVideoExtModeEnabled = atoi(prop) ? true : false;
+    }
+    ITRACE("video extended mode enabled: %d", mVideoExtModeEnabled);
+#endif
+
+    return mVideoExtModeEnabled;
+}
+
+bool DisplayAnalyzer::isVideoLayer(hwc_layer_1_t &layer)
+{
+    bool ret = false;
+    BufferManager *bm = Hwcomposer::getInstance().getBufferManager();
+    if (!layer.handle) {
+        return false;
+    }
+    DataBuffer *buffer = bm->lockDataBuffer(layer.handle);
+     if (!buffer) {
+         ETRACE("failed to get buffer");
+     } else {
+        ret = DisplayQuery::isVideoFormat(buffer->getFormat());
+        bm->unlockDataBuffer(buffer);
+    }
+    return ret;
+}
+
+bool DisplayAnalyzer::isVideoFullScreen(int device, hwc_layer_1_t &layer)
+{
+    IDisplayDevice *displayDevice = Hwcomposer::getInstance().getDisplayDevice(device);
+    if (!displayDevice) {
+        return false;
+    }
+    int width = 0, height = 0;
+    if (!displayDevice->getDisplaySize(&width, &height)) {
+        return false;
+    }
+
+    VTRACE("video left %d, right %d, top %d, bottom %d, device width %d, height %d",
+        layer.displayFrame.left, layer.displayFrame.right,
+        layer.displayFrame.top, layer.displayFrame.bottom,
+        width, height);
+
+    // full-screen defintion:
+    // width of target display frame == width of target device, with 1 pixel of tolerance, or
+    // Height of target display frame == height of target device, with 1 pixel of tolerance, or
+    // width * height of display frame > 90% of width * height of display device, or
+    // any of above condition is met on either primary display or secondary display
+    int dstW = layer.displayFrame.right - layer.displayFrame.left;
+    int dstH = layer.displayFrame.bottom - layer.displayFrame.top;
+
+    if (abs(dstW - width) > 1 &&
+        abs(dstH - height) > 1 &&
+        dstW * dstH * 10 < width * height * 9) {
+        VTRACE("video is not full-screen");
+        return false;
+    }
+    return true;
+}
+
+bool DisplayAnalyzer::isOverlayAllowed()
+{
+    return mOverlayAllowed;
+}
+
+int DisplayAnalyzer::getVideoInstances()
+{
+    return (int)mVideoStateMap.size();
+}
+
+void DisplayAnalyzer::postHotplugEvent(bool connected)
+{
+    if (!connected) {
+        // enable vsync on the primary device immediately
+        Hwcomposer::getInstance().getVsyncManager()->enableDynamicVsync(true);
+    }
+
+    // handle hotplug event (vsync switch) asynchronously
+    Event e;
+    e.type = HOTPLUG_EVENT;
+    e.bValue = connected;
+    postEvent(e);
+    Hwcomposer::getInstance().invalidate();
+}
+
+void DisplayAnalyzer::postVideoEvent(int instanceID, int state)
+{
+    Event e;
+    e.type = VIDEO_EVENT;
+    e.videoEvent.instanceID = instanceID;
+    e.videoEvent.state = state;
+    postEvent(e);
+    if ((state == VIDEO_PLAYBACK_STARTING) ||
+        (state == VIDEO_PLAYBACK_STOPPING && mProtectedVideoSession)) {
+        Hwcomposer::getInstance().invalidate();
+        mOverlayAllowed = false;
+        hwc_display_contents_1_t *content = NULL;
+        for (int i = 0; i < (int)mCachedNumDisplays; i++) {
+            setCompositionType(i, HWC_FRAMEBUFFER, true);
+        }
+        // wait for up to 100ms until overlay is disabled.
+        int loop = 0;
+        while (loop++ < 6) {
+            if (Hwcomposer::getInstance().getPlaneManager()->isOverlayPlanesDisabled())
+                break;
+            usleep(16700);
+        }
+        if (loop >= 6) {
+            WTRACE("timeout disabling overlay ");
+        }
+    }
+}
+
+void DisplayAnalyzer::postBlankEvent(bool blank)
+{
+    Event e;
+    e.type = BLANK_EVENT;
+    e.bValue = blank;
+    postEvent(e);
+    Hwcomposer::getInstance().invalidate();
+}
+
+void DisplayAnalyzer::postInputEvent(bool active)
+{
+    Event e;
+    e.type = INPUT_EVENT;
+    e.bValue = active;
+    postEvent(e);
+    Hwcomposer::getInstance().invalidate();
+}
+
+void DisplayAnalyzer::postIdleEntryEvent(void)
+{
+    Event e;
+    e.type = IDLE_ENTRY_EVENT;
+    e.nValue = 0;
+    postEvent(e);
+}
+
+void DisplayAnalyzer::postEvent(Event& e)
+{
+    Mutex::Autolock lock(mEventMutex);
+    mPendingEvents.add(e);
+}
+
+bool DisplayAnalyzer::getEvent(Event& e)
+{
+    Mutex::Autolock lock(mEventMutex);
+    if (mPendingEvents.size() == 0) {
+        return false;
+    }
+    e = mPendingEvents[0];
+    mPendingEvents.removeAt(0);
+    return true;
+}
+
+void DisplayAnalyzer::handlePendingEvents()
+{
+    // handle one event per analysis to avoid blocking surface flinger
+    // some event may take lengthy time to process
+    Event e;
+    if (!getEvent(e)) {
+        return;
+    }
+
+    switch (e.type) {
+    case HOTPLUG_EVENT:
+        handleHotplugEvent(e.bValue);
+        break;
+    case BLANK_EVENT:
+        handleBlankEvent(e.bValue);
+        break;
+    case VIDEO_EVENT:
+        handleVideoEvent(e.videoEvent.instanceID, e.videoEvent.state);
+        break;
+    case TIMING_EVENT:
+        handleTimingEvent();
+        break;
+    case INPUT_EVENT:
+        handleInputEvent(e.bValue);
+        break;
+    case DPMS_EVENT:
+        handleDpmsEvent(e.nValue);
+        break;
+    case IDLE_ENTRY_EVENT:
+        handleIdleEntryEvent(e.nValue);
+        break;
+    case IDLE_EXIT_EVENT:
+        handleIdleExitEvent();
+        break;
+    case VIDEO_CHECK_EVENT:
+        handleVideoCheckEvent();
+        break;
+    }
+}
+
+void DisplayAnalyzer::handleHotplugEvent(bool connected)
+{
+    Hwcomposer *hwc = &Hwcomposer::getInstance();
+    if (connected) {
+        if (mVideoStateMap.size() == 1) {
+            // Some video apps wouldn't update video state again when plugin HDMI
+            // and fail to reset refresh rate
+            ExternalDevice *dev = NULL;
+            dev = (ExternalDevice *)hwc->getDisplayDevice(IDisplayDevice::DEVICE_EXTERNAL);
+            if (!dev || !dev->isConnected()) {
+                ITRACE("External device isn't connected");
+                return;
+            }
+            if (hwc->getMultiDisplayObserver()->isExternalDeviceTimingFixed()) {
+                VTRACE("Timing of external device is fixed.");
+                return;
+            }
+            VideoSourceInfo info;
+            int instanceID = mVideoStateMap.keyAt(0);
+            status_t err = hwc->getMultiDisplayObserver()->getVideoSourceInfo(
+                    instanceID, &info);
+            if (err == NO_ERROR) {
+                int hz = dev->getRefreshRate();
+                if (hz > 0 && info.frameRate > 0 && hz != info.frameRate) {
+                    ITRACE("Old Hz %d, new one %d", hz, info.frameRate);
+                    dev->setRefreshRate(info.frameRate);
+                } else
+                    WTRACE("Old Hz %d is invalid, %d", hz, info.frameRate);
+            }
+        }
+    } else {
+        if (mVideoStateMap.size() == 1) {
+            // Reset input state if HDMI is plug out to
+            // avoid entering extended mode immediately after HDMI is plug in
+            mActiveInputState = true;
+        }
+    }
+}
+
+void DisplayAnalyzer::handleBlankEvent(bool blank)
+{
+    mBlankDevice = blank;
+    // force geometry changed in the secondary device to reset layer composition type
+    for (int i = 0; i < (int)mCachedNumDisplays; i++) {
+        if (i == IDisplayDevice::DEVICE_PRIMARY) {
+            continue;
+        }
+        if (mCachedDisplays[i]) {
+            mCachedDisplays[i]->flags |= HWC_GEOMETRY_CHANGED;
+        }
+    }
+    blankSecondaryDevice();
+}
+
+void DisplayAnalyzer::handleTimingEvent()
+{
+    // check whether external device is connected, reset refresh rate to match video frame rate
+    // if video is in playing state or reset refresh rate to default preferred one if video is not
+    // at playing state
+    Hwcomposer *hwc = &Hwcomposer::getInstance();
+    ExternalDevice *dev = NULL;
+    dev = (ExternalDevice *)hwc->getDisplayDevice(IDisplayDevice::DEVICE_EXTERNAL);
+    if (!dev) {
+        return;
+    }
+
+    if (!dev->isConnected()) {
+        return;
+    }
+
+    if (hwc->getMultiDisplayObserver()->isExternalDeviceTimingFixed()) {
+        VTRACE("Timing of external device is fixed.");
+        return;
+    }
+
+    int hz = 0;
+    if (mVideoStateMap.size() == 1) {
+        VideoSourceInfo info;
+        int instanceID = mVideoStateMap.keyAt(0);
+        status_t err = hwc->getMultiDisplayObserver()->getVideoSourceInfo(
+                instanceID, &info);
+        if (err == NO_ERROR) {
+            hz = info.frameRate;
+        }
+    }
+
+    dev->setRefreshRate(hz);
+}
+
+void DisplayAnalyzer::handleVideoEvent(int instanceID, int state)
+{
+    mVideoStateMap.removeItem(instanceID);
+    if (state != VIDEO_PLAYBACK_STOPPED) {
+        mVideoStateMap.add(instanceID, state);
+    }
+
+    Hwcomposer *hwc = &Hwcomposer::getInstance();
+
+    // sanity check
+    if (hwc->getMultiDisplayObserver()->getVideoSessionNumber() !=
+        (int)mVideoStateMap.size()) {
+        WTRACE("session number does not match!!");
+        mVideoStateMap.clear();
+        if (state != VIDEO_PLAYBACK_STOPPED) {
+            mVideoStateMap.add(instanceID, state);
+        }
+    }
+
+    // check if composition type needs to be reset
+    bool reset = false;
+    if ((state == VIDEO_PLAYBACK_STARTING) ||
+        (state == VIDEO_PLAYBACK_STOPPING && mProtectedVideoSession)) {
+        // if video is in starting or stopping stage, overlay use is temporarily not allowed to
+        // avoid scrambed RGB overlay if video is protected.
+        mOverlayAllowed = false;
+        reset = true;
+    } else {
+        reset = !mOverlayAllowed;
+        mOverlayAllowed = true;
+    }
+
+    if (reset) {
+        hwc_display_contents_1_t *content = NULL;
+        for (int i = 0; i < (int)mCachedNumDisplays; i++) {
+            setCompositionType(i, HWC_FRAMEBUFFER, true);
+        }
+    }
+
+    if (mVideoStateMap.size() == 0) {
+        // reset active input state after video playback stops.
+        // MDS should update input state in 5 seconds after video playback starts
+        mActiveInputState = true;
+    }
+
+    mProtectedVideoSession = false;
+    if (state == VIDEO_PLAYBACK_STARTED) {
+        VideoSourceInfo info;
+        hwc->getMultiDisplayObserver()->getVideoSourceInfo(
+                getFirstVideoInstanceSessionID(), &info);
+        mProtectedVideoSession = info.isProtected;
+    }
+    // Setting timing immediately,
+    // Don't posthone to next circle
+    handleTimingEvent();
+
+    handleVideoCheckEvent();
+}
+
+void DisplayAnalyzer::blankSecondaryDevice()
+{
+    hwc_display_contents_1_t *content = NULL;
+    hwc_layer_1 *layer = NULL;
+    for (int i = 0; i < (int)mCachedNumDisplays; i++) {
+        if (i == IDisplayDevice::DEVICE_PRIMARY) {
+            continue;
+        }
+        content = mCachedDisplays[i];
+        if (content == NULL) {
+            continue;
+        }
+
+        for (int j = 0; j < (int)content->numHwLayers - 1; j++) {
+            layer = &content->hwLayers[j];
+            if (!layer) {
+                continue;
+            }
+            if (mBlankDevice) {
+                layer->hints |= HWC_HINT_CLEAR_FB;
+                layer->flags &= ~HWC_SKIP_LAYER;
+                layer->compositionType = HWC_OVERLAY;
+            } else {
+                layer->hints &= ~HWC_HINT_CLEAR_FB;
+                layer->compositionType = HWC_FRAMEBUFFER;
+            }
+        }
+    }
+}
+
+void DisplayAnalyzer::handleInputEvent(bool active)
+{
+    if (active == mActiveInputState) {
+        WTRACE("same input state: %d", active);
+    }
+    mActiveInputState = active;
+    if (!mVideoExtModeEligible) {
+        ITRACE("not eligible for video extended mode");
+        return;
+    }
+
+    if (active) {
+        exitVideoExtMode();
+    } else {
+        enterVideoExtMode();
+    }
+}
+
+void DisplayAnalyzer::handleDpmsEvent(int delayCount)
+{
+    if (mActiveInputState || !mVideoExtModeEligible) {
+        ITRACE("aborting display power off in video extended mode");
+        return;
+    }
+
+    if (delayCount < DELAY_BEFORE_DPMS_OFF) {
+        Event e;
+        e.type = DPMS_EVENT;
+        e.nValue = delayCount + 1;
+        postEvent(e);
+        Hwcomposer::getInstance().invalidate();
+        return;
+    }
+
+    if (Hwcomposer::getInstance().getVsyncManager()->getVsyncSource() ==
+        IDisplayDevice::DEVICE_PRIMARY) {
+            Hwcomposer::getInstance().getDrm()->setDpmsMode(
+            IDisplayDevice::DEVICE_PRIMARY,
+                IDisplayDevice::DEVICE_DISPLAY_STANDBY);
+        ETRACE("primary display is source of vsync, we only dim backlight");
+        return;
+    }
+
+    // panel can't be powered off as touch panel shares the power supply with LCD.
+    DTRACE("primary display coupled with touch on Saltbay, only dim backlight");
+    Hwcomposer::getInstance().getDrm()->setDpmsMode(
+               IDisplayDevice::DEVICE_PRIMARY,
+               IDisplayDevice::DEVICE_DISPLAY_STANDBY);
+               //IDisplayDevice::DEVICE_DISPLAY_OFF);
+    return;
+}
+
+
+void DisplayAnalyzer::handleIdleEntryEvent(int count)
+{
+    DTRACE("handling idle entry event, count %d", count);
+    if (hasProtectedLayer()) {
+        ITRACE("Ignoring idle entry as protected layer exists.");
+        setCompositionType(0, HWC_FRAMEBUFFER, true);
+        return;
+    }
+
+    // stop idle entry if external device is connected
+    if (mCachedDisplays && mCachedDisplays[IDisplayDevice::DEVICE_EXTERNAL]) {
+        ITRACE("Ignoring idle entry as external device is connected.");
+        setCompositionType(0, HWC_FRAMEBUFFER, true);
+        return;
+    }
+
+    // stop idle entry if video playback is active
+    // TODO: remove this check for Annidale
+    if (mVideoStateMap.size() > 0) {
+        ITRACE("Ignoring idle entry as video session is active.");
+        setCompositionType(0, HWC_FRAMEBUFFER, true);
+        return;
+    }
+
+    setCompositionType(0, HWC_FORCE_FRAMEBUFFER, true);
+
+    // next prepare/set will exit idle state.
+    Event e;
+    e.type = IDLE_EXIT_EVENT;
+    postEvent(e);
+}
+
+void DisplayAnalyzer::handleIdleExitEvent()
+{
+    DTRACE("handling idle exit event");
+
+    setCompositionType(0, HWC_FRAMEBUFFER, true);
+}
+
+void DisplayAnalyzer::handleVideoCheckEvent()
+{
+    // check if the first seen video layer on secondary device (HDMI/WFD) is marked as skipped
+    // it is assumed video is always skipped if the first seen video layer is skipped
+    // this is to workaround secure video layer transmitted over non secure output
+    // and HWC_SKIP_LAYER set during rotation animation.
+    mIgnoreVideoSkipFlag = false;
+
+    if (mVideoStateMap.size() != 1 ||
+        mCachedNumDisplays <= 1) {
+        return;
+    }
+
+    intptr_t videoHandles[mCachedNumDisplays];
+    for (int i = 0; i < (int)mCachedNumDisplays; i++) {
+        videoHandles[i] = 0;
+        hwc_display_contents_1_t *content = mCachedDisplays[i];
+        if (content == NULL) {
+            continue;
+        }
+        for (int j = 0; j < (int)content->numHwLayers - 1; j++) {
+            if (isVideoLayer(content->hwLayers[j])) {
+                videoHandles[i] = (intptr_t)content->hwLayers[j].handle;
+                if (i > 0) {
+                    mIgnoreVideoSkipFlag = !(content->hwLayers[j].flags & HWC_SKIP_LAYER);
+                    ITRACE("Ignoring video HWC_SKIP_LAYER: %d on output %d", mIgnoreVideoSkipFlag, i);
+                    return;
+                }
+                break;
+            }
+        }
+    }
+
+    if (videoHandles[0]) {
+        WTRACE("Video is on the primary panel only");
+        return;
+    }
+
+    // video state map indicates video session is active and there is secondary
+    // display, need to continue checking as video is not found in the buffers yet
+    Event e;
+    e.type = VIDEO_CHECK_EVENT;
+    postEvent(e);
+}
+
+void DisplayAnalyzer::enterVideoExtMode()
+{
+    if (mVideoExtModeActive) {
+        WTRACE("already in video extended mode.");
+        return;
+    }
+
+    ITRACE("entering video extended mode...");
+    mVideoExtModeActive = true;
+    Hwcomposer::getInstance().getVsyncManager()->resetVsyncSource();
+
+    setCompositionType(0, HWC_OVERLAY, true);
+
+    // Do not power off primary display immediately as flip is asynchronous
+    Event e;
+    e.type = DPMS_EVENT;
+    e.nValue = 0;
+    postEvent(e);
+    Hwcomposer::getInstance().invalidate();
+}
+
+void DisplayAnalyzer::exitVideoExtMode()
+{
+    if (!mVideoExtModeActive) {
+        WTRACE("Not in video extended mode");
+        return;
+    }
+
+    ITRACE("exiting video extended mode...");
+
+    mVideoExtModeActive = false;
+
+    Hwcomposer::getInstance().getDrm()->setDpmsMode(
+        IDisplayDevice::DEVICE_PRIMARY,
+        IDisplayDevice::DEVICE_DISPLAY_ON);
+
+    Hwcomposer::getInstance().getVsyncManager()->resetVsyncSource();
+
+    setCompositionType(0, HWC_FRAMEBUFFER, true);
+}
+
+bool DisplayAnalyzer::isPresentationLayer(hwc_layer_1_t &layer)
+{
+    if (layer.handle == NULL) {
+        return false;
+    }
+    if (mCachedDisplays == NULL) {
+        return false;
+    }
+    // check if the given layer exists in the primary device
+    hwc_display_contents_1_t *content = mCachedDisplays[0];
+    if (content == NULL) {
+        return false;
+    }
+    for (size_t i = 0; i < content->numHwLayers - 1; i++) {
+        if (content->hwLayers[i].handle == layer.handle) {
+            VTRACE("Layer exists for Primary device");
+            return false;
+        }
+    }
+    return true;
+}
+
+bool DisplayAnalyzer::hasProtectedLayer()
+{
+    DataBuffer * buffer = NULL;
+    hwc_display_contents_1_t *content = NULL;
+    BufferManager *bm = Hwcomposer::getInstance().getBufferManager();
+
+    if (bm == NULL){
+        return false;
+    }
+
+    if (mCachedDisplays == NULL) {
+        return false;
+    }
+    // check if the given layer exists in the primary device
+    for (int index = 0; index < (int)mCachedNumDisplays; index++) {
+        content = mCachedDisplays[index];
+        if (content == NULL) {
+            continue;
+        }
+
+        for (size_t i = 0; i < content->numHwLayers - 1; i++) {
+            if (isProtectedLayer(content->hwLayers[i]))
+                return true;
+        }
+    }
+
+    return false;
+}
+
+bool DisplayAnalyzer::isProtectedLayer(hwc_layer_1_t &layer)
+{
+    if (!layer.handle) {
+        return false;
+    }
+    bool ret = false;
+    BufferManager *bm = Hwcomposer::getInstance().getBufferManager();
+    DataBuffer *buffer = bm->lockDataBuffer(layer.handle);
+    if (!buffer) {
+        ETRACE("failed to get buffer");
+    } else {
+        ret = GraphicBuffer::isProtectedBuffer((GraphicBuffer*)buffer);
+        bm->unlockDataBuffer(buffer);
+    }
+    return ret;
+}
+
+bool DisplayAnalyzer::ignoreVideoSkipFlag()
+{
+    return mIgnoreVideoSkipFlag;
+}
+
+void DisplayAnalyzer::setCompositionType(hwc_display_contents_1_t *display, int type)
+{
+    for (size_t i = 0; i < display->numHwLayers - 1; i++) {
+        hwc_layer_1_t *layer = &display->hwLayers[i];
+        if (layer) layer->compositionType = type;
+    }
+}
+
+void DisplayAnalyzer::setCompositionType(int device, int type, bool reset)
+{
+    hwc_display_contents_1_t *content = mCachedDisplays[device];
+    if (content == NULL) {
+        ETRACE("Invalid device %d", device);
+        return;
+    }
+
+    // don't need to set geometry changed if layers are just needed to be marked
+    if (reset) {
+        content->flags |= HWC_GEOMETRY_CHANGED;
+    }
+
+    setCompositionType(content, type);
+}
+
+int DisplayAnalyzer::getFirstVideoInstanceSessionID() {
+    if (mVideoStateMap.size() >= 1) {
+        return mVideoStateMap.keyAt(0);
+    }
+    return -1;
+}
+
+} // namespace intel
+} // namespace android
+
diff --git a/merrifield/common/base/DisplayAnalyzer.h b/merrifield/common/base/DisplayAnalyzer.h
new file mode 100755
index 0000000..abe5d91
--- /dev/null
+++ b/merrifield/common/base/DisplayAnalyzer.h
@@ -0,0 +1,145 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef DISPLAY_ANALYZER_H
+#define DISPLAY_ANALYZER_H
+
+#include <utils/threads.h>
+#include <utils/Vector.h>
+
+
+namespace android {
+namespace intel {
+
+
+class DisplayAnalyzer {
+public:
+    DisplayAnalyzer();
+    virtual ~DisplayAnalyzer();
+
+public:
+    bool initialize();
+    void deinitialize();
+    void analyzeContents(size_t numDisplays, hwc_display_contents_1_t** displays);
+    bool isVideoExtModeActive();
+    bool isVideoExtModeEnabled();
+    bool isVideoLayer(hwc_layer_1_t &layer);
+    bool isVideoFullScreen(int device, hwc_layer_1_t &layer);
+    bool isOverlayAllowed();
+    int  getVideoInstances();
+    void postHotplugEvent(bool connected);
+    void postVideoEvent(int instanceID, int state);
+    void postInputEvent(bool active);
+    void postVideoEvent(int instances, int instanceID, bool preparing, bool playing);
+    void postBlankEvent(bool blank);
+    void postIdleEntryEvent();
+    bool isPresentationLayer(hwc_layer_1_t &layer);
+    bool isProtectedLayer(hwc_layer_1_t &layer);
+    bool ignoreVideoSkipFlag();
+    int  getFirstVideoInstanceSessionID();
+
+private:
+    enum DisplayEventType {
+        HOTPLUG_EVENT,
+        BLANK_EVENT,
+        VIDEO_EVENT,
+        TIMING_EVENT,
+        INPUT_EVENT,
+        DPMS_EVENT,
+        IDLE_ENTRY_EVENT,
+        IDLE_EXIT_EVENT,
+        VIDEO_CHECK_EVENT,
+    };
+
+    struct Event {
+        int type;
+
+        struct VideoEvent {
+            int instanceID;
+            int state;
+        };
+
+        union {
+            bool bValue;
+            int  nValue;
+            VideoEvent videoEvent;
+        };
+    };
+    inline void postEvent(Event& e);
+    inline bool getEvent(Event& e);
+    void handlePendingEvents();
+    void handleHotplugEvent(bool connected);
+    void handleBlankEvent(bool blank);
+    void handleVideoEvent(int instanceID, int state);
+    void handleTimingEvent();
+    void handleInputEvent(bool active);
+    void handleDpmsEvent(int delayCount);
+    void handleIdleEntryEvent(int count);
+    void handleIdleExitEvent();
+    void handleVideoCheckEvent();
+
+    void blankSecondaryDevice();
+    void handleVideoExtMode();
+    void checkVideoExtMode();
+    void enterVideoExtMode();
+    void exitVideoExtMode();
+    bool hasProtectedLayer();
+    inline void setCompositionType(hwc_display_contents_1_t *content, int type);
+    inline void setCompositionType(int device, int type, bool reset);
+
+private:
+    // Video playback state, must match defintion in Multi Display Service
+    enum
+    {
+        VIDEO_PLAYBACK_IDLE,
+        VIDEO_PLAYBACK_STARTING,
+        VIDEO_PLAYBACK_STARTED,
+        VIDEO_PLAYBACK_STOPPING,
+        VIDEO_PLAYBACK_STOPPED,
+    };
+
+    enum
+    {
+        // number of flips before display can be powered off in video extended mode
+        DELAY_BEFORE_DPMS_OFF = 0,
+    };
+
+private:
+    bool mInitialized;
+    bool mVideoExtModeEnabled;
+    bool mVideoExtModeEligible;
+    bool mVideoExtModeActive;
+    bool mBlankDevice;
+    bool mOverlayAllowed;
+    bool mActiveInputState;
+    // workaround HWC_SKIP_LAYER set during rotation for extended video mode
+    // by default if layer has HWC_SKIP_LAYER flag it should not be processed by HWC
+    bool mIgnoreVideoSkipFlag;
+    bool mProtectedVideoSession;
+    // map video instance ID to video state
+    KeyedVector<int, int> mVideoStateMap;
+    int mCachedNumDisplays;
+    hwc_display_contents_1_t** mCachedDisplays;
+    Vector<Event> mPendingEvents;
+    Mutex mEventMutex;
+    Condition mEventHandledCondition;
+};
+
+} // namespace intel
+} // namespace android
+
+
+
+#endif /* DISPLAY_ANALYZER_H */
diff --git a/merrifield/common/base/Drm.cpp b/merrifield/common/base/Drm.cpp
new file mode 100644
index 0000000..619e4e5
--- /dev/null
+++ b/merrifield/common/base/Drm.cpp
@@ -0,0 +1,721 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#include <fcntl.h>
+#include <errno.h>
+#include <HwcTrace.h>
+#include <IDisplayDevice.h>
+#include <DrmConfig.h>
+#include <Drm.h>
+#include <Hwcomposer.h>
+
+namespace android {
+namespace intel {
+
+Drm::Drm()
+    : mDrmFd(0),
+      mLock(),
+      mInitialized(false)
+{
+    memset(&mOutputs, 0, sizeof(mOutputs));
+}
+
+Drm::~Drm()
+{
+    WARN_IF_NOT_DEINIT();
+}
+
+bool Drm::initialize()
+{
+    if (mInitialized) {
+        WTRACE("Drm object has been initialized");
+        return true;
+    }
+
+    const char *path = DrmConfig::getDrmPath();
+    mDrmFd = open(path, O_RDWR, 0);
+    if (mDrmFd < 0) {
+        ETRACE("failed to open Drm, error: %s", strerror(errno));
+        return false;
+    }
+    DTRACE("mDrmFd = %d", mDrmFd);
+
+    memset(&mOutputs, 0, sizeof(mOutputs));
+    mInitialized = true;
+    return true;
+}
+
+void Drm::deinitialize()
+{
+    for (int i = 0; i < OUTPUT_MAX; i++) {
+        resetOutput(i);
+    }
+
+    if (mDrmFd) {
+        close(mDrmFd);
+        mDrmFd = 0;
+    }
+    mInitialized = false;
+}
+
+bool Drm::detect(int device)
+{
+    RETURN_FALSE_IF_NOT_INIT();
+
+    Mutex::Autolock _l(mLock);
+    int outputIndex = getOutputIndex(device);
+    if (outputIndex < 0 ) {
+        return false;
+    }
+
+    resetOutput(outputIndex);
+
+    // get drm resources
+    drmModeResPtr resources = drmModeGetResources(mDrmFd);
+    if (!resources) {
+        ETRACE("fail to get drm resources, error: %s", strerror(errno));
+        return false;
+    }
+
+    drmModeConnectorPtr connector = NULL;
+    DrmOutput *output = &mOutputs[outputIndex];
+    bool ret = false;
+
+    // find connector for the given device
+    for (int i = 0; i < resources->count_connectors; i++) {
+        if (!resources->connectors || !resources->connectors[i]) {
+            ETRACE("fail to get drm resources connectors, error: %s", strerror(errno));
+            continue;
+        }
+
+        connector = drmModeGetConnector(mDrmFd, resources->connectors[i]);
+        if (!connector) {
+            ETRACE("drmModeGetConnector failed");
+            continue;
+        }
+
+        if (connector->connector_type != DrmConfig::getDrmConnector(device)) {
+            drmModeFreeConnector(connector);
+            continue;
+        }
+
+        if (connector->connection != DRM_MODE_CONNECTED) {
+            ITRACE("device %d is not connected", device);
+            drmModeFreeConnector(connector);
+            ret = true;
+            break;
+        }
+
+        output->connector = connector;
+        output->connected = true;
+
+        // get proper encoder for the given connector
+        if (connector->encoder_id) {
+            ITRACE("Drm connector has encoder attached on device %d", device);
+            output->encoder = drmModeGetEncoder(mDrmFd, connector->encoder_id);
+            if (!output->encoder) {
+                ETRACE("failed to get encoder from a known encoder id");
+                // fall through to get an encoder
+            }
+        }
+        if (!output->encoder) {
+            ITRACE("getting encoder for device %d", device);
+            drmModeEncoderPtr encoder;
+            for (int j = 0; j < resources->count_encoders; j++) {
+                if (!resources->encoders || !resources->encoders[j]) {
+                    ETRACE("fail to get drm resources encoders, error: %s", strerror(errno));
+                    continue;
+                }
+
+                encoder = drmModeGetEncoder(mDrmFd, resources->encoders[i]);
+                if (!encoder) {
+                    ETRACE("drmModeGetEncoder failed");
+                    continue;
+                }
+                if (encoder->encoder_type == DrmConfig::getDrmEncoder(device)) {
+                    output->encoder = encoder;
+                    break;
+                }
+                drmModeFreeEncoder(encoder);
+                encoder = NULL;
+            }
+        }
+        if (!output->encoder) {
+            ETRACE("failed to get drm encoder");
+            break;
+        }
+
+        // get an attached crtc or spare crtc
+        if (output->encoder->crtc_id) {
+            ITRACE("Drm encoder has crtc attached on device %d", device);
+            output->crtc = drmModeGetCrtc(mDrmFd, output->encoder->crtc_id);
+            if (!output->crtc) {
+                ETRACE("failed to get crtc from a known crtc id");
+                // fall through to get a spare crtc
+            }
+        }
+        if (!output->crtc) {
+            ITRACE("getting crtc for device %d", device);
+            drmModeCrtcPtr crtc;
+            for (int j = 0; j < resources->count_crtcs; j++) {
+                if (!resources->crtcs || !resources->crtcs[j]) {
+                    ETRACE("fail to get drm resources crtcs, error: %s", strerror(errno));
+                    continue;
+                }
+
+                crtc = drmModeGetCrtc(mDrmFd, resources->crtcs[j]);
+                if (!crtc) {
+                    ETRACE("drmModeGetCrtc failed");
+                    continue;
+                }
+                if (crtc->buffer_id == 0) {
+                    output->crtc = crtc;
+                    break;
+                }
+                drmModeFreeCrtc(crtc);
+            }
+        }
+        if (!output->crtc) {
+            ETRACE("failed to get drm crtc");
+            break;
+        }
+
+        // current mode
+        if (output->crtc->mode_valid) {
+            ITRACE("mode is valid, kernel mode settings");
+            memcpy(&output->mode, &output->crtc->mode, sizeof(drmModeModeInfo));
+            ret = true;
+        } else {
+            ITRACE("mode is invalid, setting preferred mode");
+            ret = initDrmMode(outputIndex);
+        }
+
+        if (outputIndex == OUTPUT_PRIMARY) {
+            if (!readIoctl(DRM_PSB_PANEL_ORIENTATION, &output->panelOrientation, sizeof(int))) {
+                ETRACE("failed to get device %d orientation", device);
+                output->panelOrientation = PANEL_ORIENTATION_0;
+            }
+        } else {
+            output->panelOrientation = PANEL_ORIENTATION_0;
+        }
+        break;
+    }
+
+    if (!ret) {
+        if (output->connector == NULL && outputIndex != OUTPUT_PRIMARY) {
+            // a fatal failure on primary device
+            // non fatal on secondary device
+            WTRACE("device %d is disabled?", device);
+            ret = true;
+        }
+         resetOutput(outputIndex);
+    } else if (output->connected) {
+        ITRACE("mode is: %dx%d@%dHz", output->mode.hdisplay, output->mode.vdisplay, output->mode.vrefresh);
+    }
+
+    drmModeFreeResources(resources);
+    return ret;
+}
+
+bool Drm::isSameDrmMode(drmModeModeInfoPtr value,
+        drmModeModeInfoPtr base) const
+{
+    if (base->hdisplay == value->hdisplay &&
+        base->vdisplay == value->vdisplay &&
+        base->vrefresh == value->vrefresh &&
+        (base->flags & value->flags) == value->flags) {
+        VTRACE("Drm mode is not changed");
+        return true;
+    }
+
+    return false;
+}
+
+bool Drm::setDrmMode(int device, drmModeModeInfo& value)
+{
+    RETURN_FALSE_IF_NOT_INIT();
+    Mutex::Autolock _l(mLock);
+
+    if (device != IDisplayDevice::DEVICE_EXTERNAL) {
+        WTRACE("Setting mode on invalid device %d", device);
+        return false;
+    }
+
+    int outputIndex = getOutputIndex(device);
+    if (outputIndex < 0 ) {
+        ETRACE("invalid device");
+        return false;
+    }
+
+    DrmOutput *output= &mOutputs[outputIndex];
+    if (!output->connected) {
+        ETRACE("device is not connected");
+        return false;
+    }
+
+    if (output->connector->count_modes <= 0) {
+        ETRACE("invalid count of modes");
+        return false;
+    }
+
+    drmModeModeInfoPtr mode;
+    int index = 0;
+    for (int i = 0; i < output->connector->count_modes; i++) {
+        mode = &output->connector->modes[i];
+        if (mode->type & DRM_MODE_TYPE_PREFERRED) {
+            index = i;
+        }
+        if (isSameDrmMode(&value, mode)) {
+            index = i;
+            break;
+        }
+    }
+
+    mode = &output->connector->modes[index];
+    return setDrmMode(outputIndex, mode);
+}
+
+bool Drm::setRefreshRate(int device, int hz)
+{
+    RETURN_FALSE_IF_NOT_INIT();
+    Mutex::Autolock _l(mLock);
+
+    if (device != IDisplayDevice::DEVICE_EXTERNAL) {
+        WTRACE("Setting mode on invalid device %d", device);
+        return false;
+    }
+
+    int outputIndex = getOutputIndex(device);
+    if (outputIndex < 0 ) {
+        ETRACE("invalid device");
+        return false;
+    }
+
+    DrmOutput *output= &mOutputs[outputIndex];
+    if (!output->connected) {
+        ETRACE("device is not connected");
+        return false;
+    }
+
+    if (output->connector->count_modes <= 0) {
+        ETRACE("invalid count of modes");
+        return false;
+    }
+
+    drmModeModeInfoPtr mode;
+    int index = 0;
+    for (int i = 0; i < output->connector->count_modes; i++) {
+        mode = &output->connector->modes[i];
+        if (mode->type & DRM_MODE_TYPE_PREFERRED) {
+            index = i;
+        }
+        if (mode->hdisplay == output->mode.hdisplay &&
+            mode->vdisplay == output->mode.vdisplay &&
+            mode->vrefresh == (uint32_t)hz) {
+            index = i;
+            break;
+        }
+    }
+
+    mode = &output->connector->modes[index];
+    return setDrmMode(outputIndex, mode);
+}
+
+bool Drm::writeReadIoctl(unsigned long cmd, void *data,
+                           unsigned long size)
+{
+    int err;
+
+    if (mDrmFd <= 0) {
+        ETRACE("drm is not initialized");
+        return false;
+    }
+
+    if (!data || !size) {
+        ETRACE("invalid parameters");
+        return false;
+    }
+
+    err = drmCommandWriteRead(mDrmFd, cmd, data, size);
+    if (err) {
+        WTRACE("failed to call %ld ioctl with failure %d", cmd, err);
+        return false;
+    }
+
+    return true;
+}
+
+bool Drm::writeIoctl(unsigned long cmd, void *data,
+                       unsigned long size)
+{
+    int err;
+
+    if (mDrmFd <= 0) {
+        ETRACE("drm is not initialized");
+        return false;
+    }
+
+    if (!data || !size) {
+        ETRACE("invalid parameters");
+        return false;
+    }
+
+    err = drmCommandWrite(mDrmFd, cmd, data, size);
+    if (err) {
+        WTRACE("failed to call %ld ioctl with failure %d", cmd, err);
+        return false;
+    }
+
+    return true;
+}
+
+
+bool Drm::readIoctl(unsigned long cmd, void *data,
+                       unsigned long size)
+{
+    int err;
+
+    if (mDrmFd <= 0) {
+        ETRACE("drm is not initialized");
+        return false;
+    }
+
+    if (!data || !size) {
+        ETRACE("invalid parameters");
+        return false;
+    }
+
+    err = drmCommandRead(mDrmFd, cmd, data, size);
+    if (err) {
+        WTRACE("failed to call %ld ioctl with failure %d", cmd, err);
+        return false;
+    }
+
+    return true;
+}
+
+
+int Drm::getDrmFd() const
+{
+    return mDrmFd;
+}
+
+bool Drm::getModeInfo(int device, drmModeModeInfo& mode)
+{
+    Mutex::Autolock _l(mLock);
+
+    int outputIndex = getOutputIndex(device);
+    if (outputIndex < 0 ) {
+        return false;
+    }
+
+    DrmOutput *output= &mOutputs[outputIndex];
+    if (output->connected == false) {
+        ETRACE("device is not connected");
+        return false;
+    }
+
+    if (output->mode.hdisplay == 0 || output->mode.vdisplay == 0) {
+        ETRACE("invalid width or height");
+        return false;
+    }
+
+    memcpy(&mode, &output->mode, sizeof(drmModeModeInfo));
+    return true;
+}
+
+bool Drm::getPhysicalSize(int device, uint32_t& width, uint32_t& height)
+{
+    Mutex::Autolock _l(mLock);
+
+    int outputIndex = getOutputIndex(device);
+    if (outputIndex < 0 ) {
+        return false;
+    }
+
+    DrmOutput *output= &mOutputs[outputIndex];
+    if (output->connected == false) {
+        ETRACE("device is not connected");
+        return false;
+    }
+
+    width = output->connector->mmWidth;
+    height = output->connector->mmHeight;
+    return true;
+}
+
+bool Drm::isConnected(int device)
+{
+    Mutex::Autolock _l(mLock);
+
+    int output = getOutputIndex(device);
+    if (output < 0 ) {
+        return false;
+    }
+
+    return mOutputs[output].connected;
+}
+
+bool Drm::setDpmsMode(int device, int mode)
+{
+    Mutex::Autolock _l(mLock);
+
+    int output = getOutputIndex(device);
+    if (output < 0 ) {
+        return false;
+    }
+
+    if (mode != IDisplayDevice::DEVICE_DISPLAY_OFF &&
+            mode != IDisplayDevice::DEVICE_DISPLAY_STANDBY &&
+            mode != IDisplayDevice::DEVICE_DISPLAY_ON) {
+        ETRACE("invalid mode %d", mode);
+        return false;
+    }
+
+    DrmOutput *out = &mOutputs[output];
+    if (!out->connected) {
+        ETRACE("device is not connected");
+        return false;
+    }
+
+    drmModePropertyPtr props;
+    for (int i = 0; i < out->connector->count_props; i++) {
+        props = drmModeGetProperty(mDrmFd, out->connector->props[i]);
+        if (!props) {
+            continue;
+        }
+
+        if (strcmp(props->name, "DPMS") == 0) {
+            int ret = drmModeConnectorSetProperty(
+                mDrmFd,
+                out->connector->connector_id,
+                props->prop_id,
+                (mode == IDisplayDevice::DEVICE_DISPLAY_ON) ? DRM_MODE_DPMS_ON :
+                        IDisplayDevice::DEVICE_DISPLAY_STANDBY == mode ?
+                        DRM_MODE_DPMS_STANDBY : DRM_MODE_DPMS_OFF);
+            drmModeFreeProperty(props);
+            if (ret != 0) {
+                ETRACE("unable to set DPMS %d", mode);
+                return false;
+            } else {
+                return true;
+            }
+        }
+        drmModeFreeProperty(props);
+    }
+    return false;
+}
+
+void Drm::resetOutput(int index)
+{
+    DrmOutput *output = &mOutputs[index];
+
+    output->connected = false;
+    memset(&output->mode, 0, sizeof(drmModeModeInfo));
+
+    if (output->connector) {
+        drmModeFreeConnector(output->connector);
+        output->connector = 0;
+    }
+    if (output->encoder) {
+        drmModeFreeEncoder(output->encoder);
+        output->encoder = 0;
+    }
+    if (output->crtc) {
+        drmModeFreeCrtc(output->crtc);
+        output->crtc = 0;
+    }
+    if (output->fbId) {
+        drmModeRmFB(mDrmFd, output->fbId);
+        output->fbId = 0;
+    }
+    if (output->fbHandle) {
+        Hwcomposer::getInstance().getBufferManager()->freeFrameBuffer(
+            (buffer_handle_t)output->fbHandle);
+        output->fbHandle = 0;
+    }
+}
+
+bool Drm::initDrmMode(int outputIndex)
+{
+    DrmOutput *output= &mOutputs[outputIndex];
+    if (output->connector->count_modes <= 0) {
+        ETRACE("invalid count of modes");
+        return false;
+    }
+
+    drmModeModeInfoPtr mode;
+    int index = 0;
+    for (int i = 0; i < output->connector->count_modes; i++) {
+        mode = &output->connector->modes[i];
+        if (mode->type & DRM_MODE_TYPE_PREFERRED) {
+            index = i;
+            break;
+        }
+    }
+
+    return setDrmMode(outputIndex, &output->connector->modes[index]);
+}
+
+bool Drm::setDrmMode(int index, drmModeModeInfoPtr mode)
+{
+    DrmOutput *output = &mOutputs[index];
+
+    int oldFbId =0;
+    buffer_handle_t oldFbHandle = 0;
+
+    drmModeModeInfo currentMode;
+    memcpy(&currentMode, &output->mode, sizeof(drmModeModeInfo));
+
+    if (isSameDrmMode(mode, &currentMode))
+        return true;
+
+
+    if (output->fbId) {
+        oldFbId = output->fbId;
+        output->fbId = 0;
+    }
+
+    if (output->fbHandle) {
+        oldFbHandle = output->fbHandle;
+        output->fbHandle = 0;
+    }
+
+    // allocate frame buffer
+    int stride = 0;
+    output->fbHandle = Hwcomposer::getInstance().getBufferManager()->allocFrameBuffer(
+        mode->hdisplay, mode->vdisplay, &stride);
+    if (output->fbHandle == 0) {
+        ETRACE("failed to allocate frame buffer");
+        return false;
+    }
+
+    uint32_t bo_handles[4] = {0};
+    uint32_t pitches[4] = {0};
+    uint32_t offsets[4] = {0};
+    int ret = 0;
+
+    // We use bo_handles[0] and bo_handles[1] to store buffer_handle_t
+    // to support 32 and 64 platforms.
+    bo_handles[0] = ((unsigned long)(output->fbHandle)) & 0xffffffff;
+    bo_handles[1] = ((unsigned long)(output->fbHandle) >> 32) & 0xffffffff;
+    pitches[0] = stride * DrmConfig::getFrameBufferBpp() / 8;
+
+    ret = drmModeAddFB2(
+        mDrmFd,
+        mode->hdisplay,
+        mode->vdisplay,
+        DrmConfig::convertHalFormatToDrmFormat(DrmConfig::getFrameBufferFormat()),
+        bo_handles,
+        pitches,
+        offsets,
+        &output->fbId,
+        0);
+    if (ret != 0) {
+        ETRACE("drmModeAddFB2 failed, error: %d", ret);
+        return false;
+    }
+
+    ITRACE("mode set: %dx%d@%dHz", mode->hdisplay, mode->vdisplay, mode->vrefresh);
+
+    ret = drmModeSetCrtc(mDrmFd, output->crtc->crtc_id, output->fbId, 0, 0,
+                   &output->connector->connector_id, 1, mode);
+    if (ret == 0) {
+        //save mode
+        memcpy(&output->mode, mode, sizeof(drmModeModeInfo));
+    } else {
+        ETRACE("drmModeSetCrtc failed. error: %d", ret);
+    }
+
+    if (oldFbId) {
+        drmModeRmFB(mDrmFd, oldFbId);
+    }
+
+    if (oldFbHandle) {
+        Hwcomposer::getInstance().getBufferManager()->freeFrameBuffer((buffer_handle_t)oldFbHandle);
+    }
+
+    return ret == 0;
+}
+
+int Drm::getOutputIndex(int device)
+{
+    switch (device) {
+    case IDisplayDevice::DEVICE_PRIMARY:
+        return OUTPUT_PRIMARY;
+    case IDisplayDevice::DEVICE_EXTERNAL:
+        return OUTPUT_EXTERNAL;
+    default:
+        ETRACE("invalid display device");
+        break;
+    }
+
+    return -1;
+}
+
+int Drm::getPanelOrientation(int device)
+{
+    int outputIndex = getOutputIndex(device);
+    if (outputIndex < 0) {
+        ETRACE("invalid device");
+        return PANEL_ORIENTATION_0;
+    }
+
+    DrmOutput *output= &mOutputs[outputIndex];
+    if (output->connected == false) {
+        ETRACE("device is not connected");
+        return PANEL_ORIENTATION_0;
+    }
+
+    return output->panelOrientation;
+}
+
+// HWC 1.4 requires that we return all of the compatible configs in getDisplayConfigs
+// this is needed so getActiveConfig/setActiveConfig work correctly.  It is up to the
+// user space to decide what speed to send.
+drmModeModeInfoPtr Drm::detectAllConfigs(int device, int *modeCount)
+{
+    RETURN_NULL_IF_NOT_INIT();
+    Mutex::Autolock _l(mLock);
+
+    if (modeCount != NULL)
+        *modeCount = 0;
+    else
+        return NULL;
+
+    int outputIndex = getOutputIndex(device);
+    if (outputIndex < 0) {
+        ETRACE("invalid device");
+        return NULL;
+    }
+
+    DrmOutput *output= &mOutputs[outputIndex];
+    if (!output->connected) {
+        ETRACE("device is not connected");
+        return NULL;
+    }
+
+    if (output->connector->count_modes <= 0) {
+        ETRACE("invalid count of modes");
+        return NULL;
+    }
+
+    *modeCount = output->connector->count_modes;
+    return output->connector->modes;
+}
+
+} // namespace intel
+} // namespace android
+
diff --git a/merrifield/common/base/Drm.h b/merrifield/common/base/Drm.h
new file mode 100644
index 0000000..4db0bc6
--- /dev/null
+++ b/merrifield/common/base/Drm.h
@@ -0,0 +1,101 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef __DRM_H__
+#define __DRM_H__
+
+#include <utils/Mutex.h>
+#include <hardware/hwcomposer.h>
+
+// TODO: psb_drm.h is IP specific defintion
+#include <linux/psb_drm.h>
+
+extern "C" {
+#include "xf86drm.h"
+#include "xf86drmMode.h"
+}
+
+namespace android {
+namespace intel {
+
+enum {
+    PANEL_ORIENTATION_0 = 0,
+    PANEL_ORIENTATION_180
+};
+
+class Drm {
+public:
+    Drm();
+    virtual ~Drm();
+public:
+    bool initialize();
+    void deinitialize();
+    bool detect(int device);
+    bool setDrmMode(int device, drmModeModeInfo& value);
+    bool setRefreshRate(int device, int hz);
+    bool writeReadIoctl(unsigned long cmd, void *data,
+                      unsigned long size);
+    bool writeIoctl(unsigned long cmd, void *data,
+                      unsigned long size);
+    bool readIoctl(unsigned long cmd, void *data,
+                      unsigned long size);
+
+    bool isConnected(int device);
+    bool setDpmsMode(int device, int mode);
+    int getDrmFd() const;
+    bool getModeInfo(int device, drmModeModeInfo& mode);
+    bool getPhysicalSize(int device, uint32_t& width, uint32_t& height);
+    bool isSameDrmMode(drmModeModeInfoPtr mode, drmModeModeInfoPtr base) const;
+    int getPanelOrientation(int device);
+    drmModeModeInfoPtr detectAllConfigs(int device, int *modeCount);
+
+private:
+    bool initDrmMode(int index);
+    bool setDrmMode(int index, drmModeModeInfoPtr mode);
+    void resetOutput(int index);
+
+    // map device type to output index, return -1 if not mapped
+    inline int getOutputIndex(int device);
+
+private:
+    // DRM object index
+    enum {
+        OUTPUT_PRIMARY = 0,
+        OUTPUT_EXTERNAL,
+        OUTPUT_MAX,
+    };
+
+    struct DrmOutput {
+        drmModeConnectorPtr connector;
+        drmModeEncoderPtr encoder;
+        drmModeCrtcPtr crtc;
+        drmModeModeInfo mode;
+        buffer_handle_t fbHandle;
+        uint32_t fbId;
+        int connected;
+        int panelOrientation;
+    } mOutputs[OUTPUT_MAX];
+
+    int mDrmFd;
+    Mutex mLock;
+    bool mInitialized;
+};
+
+} // namespace intel
+} // namespace android
+
+
+
+#endif /* __DRM_H__ */
diff --git a/merrifield/common/base/HwcLayer.cpp b/merrifield/common/base/HwcLayer.cpp
new file mode 100755
index 0000000..04fd1bb
--- /dev/null
+++ b/merrifield/common/base/HwcLayer.cpp
@@ -0,0 +1,409 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#include <HwcTrace.h>
+#include <Drm.h>
+#include <HwcLayer.h>
+#include <Hwcomposer.h>
+#include <GraphicBuffer.h>
+#include <IDisplayDevice.h>
+#include <DisplayQuery.h>
+#include <PlaneCapabilities.h>
+#include <cutils/properties.h>
+
+
+namespace android {
+namespace intel {
+
+inline bool operator==(const hwc_rect_t& x, const hwc_rect_t& y)
+{
+    return (x.top == y.top &&
+            x.bottom == y.bottom &&
+            x.left == y.left &&
+            x.right == y.right);
+}
+
+inline bool operator !=(const hwc_rect_t& x, const hwc_rect_t& y)
+{
+    return !operator==(x, y);
+}
+
+inline bool operator ==(const hwc_frect_t& x, const hwc_frect_t& y)
+{
+    return (x.top == y.top &&
+            x.bottom == y.bottom &&
+            x.left == y.left &&
+            x.right == y.right);
+}
+
+inline bool operator !=(const hwc_frect_t& x, const hwc_frect_t& y)
+{
+    return !operator==(x, y);
+}
+
+HwcLayer::HwcLayer(int index, hwc_layer_1_t *layer)
+    : mIndex(index),
+      mZOrder(index + 1),  // 0 is reserved for frame buffer target
+      mDevice(0),
+      mLayer(layer),
+      mPlane(0),
+      mFormat(DataBuffer::FORMAT_INVALID),
+      mWidth(0),
+      mHeight(0),
+      mUsage(0),
+      mHandle(0),
+      mIsProtected(false),
+      mType(LAYER_FB),
+      mPriority(0),
+      mTransform(0),
+      mStaticCount(0),
+      mUpdated(false)
+{
+    memset(&mSourceCropf, 0, sizeof(mSourceCropf));
+    memset(&mDisplayFrame, 0, sizeof(mDisplayFrame));
+    memset(&mStride, 0, sizeof(mStride));
+
+    mPlaneCandidate = false;
+    setupAttributes();
+
+#ifdef HWC_TRACE_FPS
+    mTraceFps = false;
+    char prop[PROPERTY_VALUE_MAX];
+    if (property_get("debug.hwc.fps_trace.enable", prop, "0") > 0) {
+        mTraceFps = atoi(prop);
+    }
+    mLastHandle = NULL;
+
+    if (mTraceFps) {
+        // holding up to 6 seconds of samples at 60Hz
+        mFrames.setCapacity(6 * 60);
+    }
+#endif
+}
+
+HwcLayer::~HwcLayer()
+{
+    if (mPlane) {
+        WTRACE("HwcLayer is not cleaned up");
+    }
+
+    mLayer = NULL;
+    mPlane = NULL;
+
+#ifdef HWC_TRACE_FPS
+    mFrames.clear();
+#endif
+}
+
+bool HwcLayer::attachPlane(DisplayPlane* plane, int device)
+{
+    if (mPlane) {
+        ETRACE("failed to attach plane, plane exists");
+        return false;
+    }
+
+    if (!plane) {
+        ETRACE("Invalid plane");
+        return false;
+    }
+
+    mDevice = device;
+    //plane->setZOrder(mIndex);
+    plane->assignToDevice(device);
+    mPlane = plane;
+    return true;
+}
+
+DisplayPlane* HwcLayer::detachPlane()
+{
+    // reset plane's z order
+    if (mPlane)
+        mPlane->setZOrder(-1);
+    DisplayPlane *plane = mPlane;
+    mPlane = 0;
+    mDevice = 0;
+    return plane;
+}
+
+void HwcLayer::setType(uint32_t type)
+{
+    if (!mLayer)
+        return;
+
+    switch (type) {
+    case LAYER_OVERLAY:
+    case LAYER_SKIPPED:
+        mLayer->compositionType = HWC_OVERLAY;
+        mLayer->hints |= HWC_HINT_CLEAR_FB;
+        break;
+    // NOTE: set compositionType to HWC_FRAMEBUFFER here so that we have
+    // a chance to submit the primary changes to HW.
+    // Upper layer HWComposer will reset the compositionType automatically.
+    case LAYER_FB:
+    case LAYER_FORCE_FB:
+        mLayer->compositionType = HWC_FRAMEBUFFER;
+        break;
+    case LAYER_SIDEBAND:
+        mLayer->compositionType = HWC_SIDEBAND;
+        break;
+    case LAYER_CURSOR_OVERLAY:
+        mLayer->compositionType = HWC_CURSOR_OVERLAY;
+        break;
+    default:
+        break;
+    }
+
+    mType = type;
+}
+
+uint32_t HwcLayer::getType() const
+{
+    return mType;
+}
+
+void HwcLayer::setCompositionType(int32_t type)
+{
+    mLayer->compositionType = type;
+}
+
+int32_t HwcLayer::getCompositionType() const
+{
+    return mLayer->compositionType;
+}
+
+int HwcLayer::getIndex() const
+{
+    return mIndex;
+}
+
+int HwcLayer::getZOrder() const
+{
+    return mZOrder;
+}
+
+uint32_t HwcLayer::getFormat() const
+{
+    return mFormat;
+}
+
+uint32_t HwcLayer::getBufferWidth() const
+{
+    return mWidth;
+}
+
+uint32_t HwcLayer::getBufferHeight() const
+{
+    return mHeight;
+}
+
+const stride_t& HwcLayer::getBufferStride() const
+{
+    return mStride;
+}
+
+uint32_t HwcLayer::getUsage() const
+{
+    return mUsage;
+}
+
+buffer_handle_t HwcLayer::getHandle() const
+{
+    return mHandle;
+}
+
+uint32_t HwcLayer::getTransform() const
+{
+    return mTransform;
+}
+
+bool HwcLayer::isProtected() const
+{
+    return mIsProtected;
+}
+
+hwc_layer_1_t* HwcLayer::getLayer() const
+{
+    return mLayer;
+}
+
+DisplayPlane* HwcLayer::getPlane() const
+{
+    return mPlane;
+}
+
+void HwcLayer::setPriority(uint32_t priority)
+{
+    mPriority = priority;
+}
+
+uint32_t HwcLayer::getPriority() const
+{
+    return mPriority;
+}
+
+bool HwcLayer::update(hwc_layer_1_t *layer)
+{
+    // update layer
+    mLayer = layer;
+    setupAttributes();
+
+#ifdef HWC_TRACE_FPS
+    if (mTraceFps && mLayer && mLayer->compositionType != HWC_FRAMEBUFFER_TARGET ) {
+        // 1 second = 1000000000 nano seconds
+        uint64_t now = systemTime(CLOCK_MONOTONIC);
+        if (mLastHandle != mHandle) {
+            mLastHandle = mHandle;
+            mFrames.push(now);
+        }
+        // calculate fps in 5-second time window
+        int frames = mFrames.size();
+        while (frames && now - mFrames[0] > 5000000000LL) {
+            mFrames.removeItemsAt(0);
+            frames--;
+        }
+        double fps = 0;
+        if (frames > 1) {
+            fps = frames * 1000000000.0/ (now - mFrames[0]);
+        }
+        ITRACE("fps of layer %d is %.1f", mIndex, fps);
+    }
+#endif
+
+    // if not a FB layer & a plane was attached update plane's data buffer
+    if (mPlane) {
+        mPlane->setPosition(layer->displayFrame.left,
+                            layer->displayFrame.top,
+                            layer->displayFrame.right - layer->displayFrame.left,
+                            layer->displayFrame.bottom - layer->displayFrame.top);
+        mPlane->setSourceCrop(layer->sourceCropf.left,
+                              layer->sourceCropf.top,
+                              layer->sourceCropf.right - layer->sourceCropf.left,
+                              layer->sourceCropf.bottom - layer->sourceCropf.top);
+        mPlane->setTransform(layer->transform);
+        mPlane->setPlaneAlpha(layer->planeAlpha, layer->blending);
+        bool ret = mPlane->setDataBuffer(layer->handle);
+        if (ret == true) {
+            return true;
+        }
+        DTRACE("failed to set data buffer, reset handle to 0!!");
+        mHandle = 0;
+        if (!mIsProtected) {
+            // typical case: rotated buffer is not ready or handle is null
+            return false;
+        } else {
+            // protected video has to be rendered using overlay.
+            // if buffer is not ready overlay will still be attached to this layer
+            // but rendering needs to be skipped.
+            WTRACE("ignoring result of data buffer setting for protected video");
+            return true;
+        }
+    }
+
+    return true;
+}
+
+bool HwcLayer::isUpdated()
+{
+    return mUpdated;
+}
+
+uint32_t HwcLayer::getStaticCount()
+{
+    return mStaticCount;
+}
+
+void HwcLayer::postFlip()
+{
+    mUpdated = false;
+    if (mPlane) {
+        mPlane->postFlip();
+
+        // flip frame buffer target once in video extended mode to refresh screen,
+        // then mark type as LAYER_SKIPPED so it will not be flipped again.
+        // by doing this pipe for primary device can enter idle state
+        if (mDevice == IDisplayDevice::DEVICE_PRIMARY &&
+            mType == LAYER_FRAMEBUFFER_TARGET &&
+            Hwcomposer::getInstance().getDisplayAnalyzer()->isVideoExtModeActive()) {
+            DTRACE("Skipping frame buffer target...");
+            mType = LAYER_SKIPPED;
+        }
+    }
+}
+
+void HwcLayer::setupAttributes()
+{
+    if ((mLayer->flags & HWC_SKIP_LAYER) ||
+        mTransform != mLayer->transform ||
+        mSourceCropf != mLayer->sourceCropf ||
+        mDisplayFrame != mLayer->displayFrame ||
+        mHandle != mLayer->handle ||
+        DisplayQuery::isVideoFormat(mFormat)) {
+        // TODO: same handle does not mean there is always no update
+        mUpdated = true;
+        mStaticCount = 0;
+    } else {
+        // protect it from exceeding its max
+        if (++mStaticCount > 1000)
+            mStaticCount = LAYER_STATIC_THRESHOLD + 1;
+    }
+
+    // update handle always as it can become "NULL"
+    // if the given layer is not ready
+    mTransform = mLayer->transform;
+    mSourceCropf = mLayer->sourceCropf;
+    mDisplayFrame = mLayer->displayFrame;
+    mHandle = mLayer->handle;
+
+    if (mFormat != DataBuffer::FORMAT_INVALID) {
+        // other attributes have been set.
+        return;
+    }
+
+    if (mLayer->handle == NULL) {
+        VTRACE("invalid handle");
+        return;
+    }
+
+    BufferManager *bm = Hwcomposer::getInstance().getBufferManager();
+    if (bm == NULL) {
+        // TODO: this check is redundant
+        return;
+    }
+
+    DataBuffer *buffer = bm->lockDataBuffer(mLayer->handle);
+     if (!buffer) {
+         ETRACE("failed to get buffer");
+     } else {
+        mFormat = buffer->getFormat();
+        mWidth = buffer->getWidth();
+        mHeight = buffer->getHeight();
+        mStride = buffer->getStride();
+        mPriority = (mSourceCropf.right - mSourceCropf.left) * (mSourceCropf.bottom - mSourceCropf.top);
+        mPriority <<= LAYER_PRIORITY_SIZE_OFFSET;
+        mPriority |= mIndex;
+        GraphicBuffer *gBuffer = (GraphicBuffer*)buffer;
+        mUsage = gBuffer->getUsage();
+        mIsProtected = GraphicBuffer::isProtectedBuffer((GraphicBuffer*)buffer);
+        if (mIsProtected) {
+            mPriority |= LAYER_PRIORITY_PROTECTED;
+        } else if (PlaneCapabilities::isFormatSupported(DisplayPlane::PLANE_OVERLAY, this)) {
+            mPriority |= LAYER_PRIORITY_OVERLAY;
+        }
+        bm->unlockDataBuffer(buffer);
+    }
+}
+
+} // namespace intel
+} // namespace android
diff --git a/merrifield/common/base/HwcLayer.h b/merrifield/common/base/HwcLayer.h
new file mode 100755
index 0000000..07b91e6
--- /dev/null
+++ b/merrifield/common/base/HwcLayer.h
@@ -0,0 +1,137 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef HWC_LAYER_H
+#define HWC_LAYER_H
+
+#include <hardware/hwcomposer.h>
+#include <DisplayPlane.h>
+#include <utils/Vector.h>
+
+//#define HWC_TRACE_FPS
+
+namespace android {
+namespace intel {
+
+enum {
+    LAYER_STATIC_THRESHOLD = 10,
+};
+
+class HwcLayer {
+public:
+    enum {
+        // LAYER_FB layers are marked as HWC_FRAMEBUFFER.
+        // And a LAYER_FB can become HWC_OVERLAY layers during
+        // revisiting layer list.
+        LAYER_FB = 0,
+        // LAYER_FORCE_FB layers are marked as HWC_FRAMEBUFFER.
+        // And a LAYER_FORCE_FB can never become HWC_OVERLAY layers during
+        // revisiting layer list.
+        LAYER_FORCE_FB,
+        // LAYER_OVERLAY layers are marked as HWC_OVERLAY
+        LAYER_OVERLAY,
+        // LAYER_SKIPPED layers are marked as HWC_OVERLAY with no plane attached
+        LAYER_SKIPPED,
+        // LAYER_FRAMEBUFFER_TARGET layers are marked as HWC_FRAMEBUFFER_TARGET
+        LAYER_FRAMEBUFFER_TARGET,
+        // LAYER_SIDEBAND layers have alternate path bypassing HWC after setup
+        LAYER_SIDEBAND,
+        // LAYER_CURSOR_OVERLAY layers support hardware cursor planes
+        LAYER_CURSOR_OVERLAY,
+    };
+
+    enum {
+        LAYER_PRIORITY_OVERLAY = 0x60000000UL,
+        LAYER_PRIORITY_PROTECTED = 0x70000000UL,
+        LAYER_PRIORITY_SIZE_OFFSET = 4,
+    };
+public:
+    HwcLayer(int index, hwc_layer_1_t *layer);
+    virtual ~HwcLayer();
+
+    // plane operations
+    bool attachPlane(DisplayPlane *plane, int device);
+    DisplayPlane* detachPlane();
+
+    void setType(uint32_t type);
+    uint32_t getType() const;
+    int32_t getCompositionType() const;
+    void setCompositionType(int32_t type);
+
+    int getIndex() const;
+    int getZOrder() const;
+    uint32_t getFormat() const;
+    uint32_t getBufferWidth() const;
+    uint32_t getBufferHeight() const;
+    const stride_t& getBufferStride() const;
+    uint32_t getUsage() const;
+    buffer_handle_t getHandle() const;
+    uint32_t getTransform() const;
+    bool isProtected() const;
+    hwc_layer_1_t* getLayer() const;
+    DisplayPlane* getPlane() const;
+
+    void setPriority(uint32_t priority);
+    uint32_t getPriority() const;
+
+    bool update(hwc_layer_1_t *layer);
+    void postFlip();
+    bool isUpdated();
+    uint32_t getStaticCount();
+
+public:
+    // temporary solution for plane assignment
+    bool mPlaneCandidate;
+
+private:
+    void setupAttributes();
+
+private:
+    const int mIndex;
+    int mZOrder;
+    int mDevice;
+    hwc_layer_1_t *mLayer;
+    DisplayPlane *mPlane;
+    uint32_t mFormat;
+    uint32_t mWidth;
+    uint32_t mHeight;
+    stride_t mStride;
+    uint32_t mUsage;
+    buffer_handle_t mHandle;
+    bool mIsProtected;
+    uint32_t mType;
+    uint32_t mPriority;
+    uint32_t mTransform;
+
+    // for smart composition
+    hwc_frect_t mSourceCropf;
+    hwc_rect_t mDisplayFrame;
+    uint32_t mStaticCount;
+    bool mUpdated;
+
+#ifdef HWC_TRACE_FPS
+    // for frame per second trace
+    bool mTraceFps;
+    buffer_handle_t mLastHandle;
+    Vector<uint64_t>  mFrames;
+#endif
+};
+
+
+} // namespace intel
+} // namespace android
+
+
+#endif /* HWC_LAYER_H */
diff --git a/merrifield/common/base/HwcLayerList.cpp b/merrifield/common/base/HwcLayerList.cpp
new file mode 100644
index 0000000..8df6ac9
--- /dev/null
+++ b/merrifield/common/base/HwcLayerList.cpp
@@ -0,0 +1,1096 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#include <HwcTrace.h>
+#include <Drm.h>
+#include <HwcLayerList.h>
+#include <Hwcomposer.h>
+#include <GraphicBuffer.h>
+#include <IDisplayDevice.h>
+#include <PlaneCapabilities.h>
+#include <DisplayQuery.h>
+
+namespace android {
+namespace intel {
+
+HwcLayerList::HwcLayerList(hwc_display_contents_1_t *list, int disp)
+    : mList(list),
+      mLayerCount(0),
+      mLayers(),
+      mFBLayers(),
+      mStaticLayersIndex(),
+      mSpriteCandidates(),
+      mOverlayCandidates(),
+      mZOrderConfig(),
+      mFrameBufferTarget(NULL),
+      mDisplayIndex(disp),
+      mLayerSize(0)
+{
+    initialize();
+}
+
+HwcLayerList::~HwcLayerList()
+{
+    deinitialize();
+}
+
+bool HwcLayerList::checkSupported(int planeType, HwcLayer *hwcLayer)
+{
+    bool valid = false;
+    hwc_layer_1_t& layer = *(hwcLayer->getLayer());
+
+    // if layer was forced to use FB
+    if (hwcLayer->getType() == HwcLayer::LAYER_FORCE_FB) {
+        VTRACE("layer was forced to use HWC_FRAMEBUFFER");
+        return false;
+    }
+
+    // check layer flags
+    if (layer.flags & HWC_SKIP_LAYER) {
+        VTRACE("plane type %d: (skip layer flag was set)", planeType);
+        return false;
+    }
+
+    if (layer.handle == 0) {
+        WTRACE("invalid buffer handle");
+        return false;
+    }
+
+    // check usage
+    if (!hwcLayer->getUsage() & GRALLOC_USAGE_HW_COMPOSER) {
+        WTRACE("not a composer layer");
+        return false;
+    }
+
+    // check layer transform
+    valid = PlaneCapabilities::isTransformSupported(planeType, hwcLayer);
+    if (!valid) {
+        VTRACE("plane type %d: (bad transform)", planeType);
+        return false;
+    }
+
+    // check buffer format
+    valid = PlaneCapabilities::isFormatSupported(planeType, hwcLayer);
+    if (!valid) {
+        VTRACE("plane type %d: (bad buffer format)", planeType);
+        return false;
+    }
+
+    // check buffer size
+    valid = PlaneCapabilities::isSizeSupported(planeType, hwcLayer);
+    if (!valid) {
+        VTRACE("plane type %d: (bad buffer size)", planeType);
+        return false;
+    }
+
+    // check layer blending
+    valid = PlaneCapabilities::isBlendingSupported(planeType, hwcLayer);
+    if (!valid) {
+        VTRACE("plane type %d: (bad blending)", planeType);
+        return false;
+    }
+
+    // check layer scaling
+    valid = PlaneCapabilities::isScalingSupported(planeType, hwcLayer);
+    if (!valid) {
+        VTRACE("plane type %d: (bad scaling)", planeType);
+        return false;
+    }
+
+    // TODO: check visible region?
+    return true;
+}
+
+bool HwcLayerList::checkCursorSupported(HwcLayer *hwcLayer)
+{
+    hwc_layer_1_t& layer = *(hwcLayer->getLayer());
+
+    // if layer was forced to use FB
+    if (hwcLayer->getType() == HwcLayer::LAYER_FORCE_FB) {
+        VTRACE("layer was forced to use HWC_FRAMEBUFFER");
+        return false;
+    }
+
+    // check layer flags
+    if (layer.flags & HWC_SKIP_LAYER) {
+        VTRACE("skip layer flag was set");
+        return false;
+    }
+
+    if (!(layer.flags & HWC_IS_CURSOR_LAYER)) {
+        VTRACE("not a cursor layer");
+        return false;
+    }
+
+    if (hwcLayer->getIndex() != mLayerCount - 2) {
+        WTRACE("cursor layer is not on top of zorder");
+        return false;
+    }
+
+    if (layer.handle == 0) {
+        WTRACE("invalid buffer handle");
+        return false;
+    }
+
+    // check usage
+    if (!(hwcLayer->getUsage() & GRALLOC_USAGE_HW_COMPOSER)) {
+        WTRACE("not a composer layer");
+        return false;
+    }
+
+    uint32_t format = hwcLayer->getFormat();
+    if (format != HAL_PIXEL_FORMAT_BGRA_8888 &&
+        format != HAL_PIXEL_FORMAT_RGBA_8888) {
+        WTRACE("unexpected color format %u for cursor", format);
+        return false;
+    }
+
+    uint32_t trans = hwcLayer->getLayer()->transform;
+    if (trans != 0) {
+        WTRACE("unexpected transform %u for cursor", trans);
+        return false;
+    }
+
+    hwc_frect_t& src = hwcLayer->getLayer()->sourceCropf;
+    hwc_rect_t& dest = hwcLayer->getLayer()->displayFrame;
+    int srcW = (int)src.right - (int)src.left;
+    int srcH = (int)src.bottom - (int)src.top;
+    int dstW = dest.right - dest.left;
+    int dstH = dest.bottom - dest.top;
+    if (srcW != dstW || srcH != dstH) {
+        WTRACE("unexpected scaling for cursor: %dx%d => %dx%d",
+        srcW, srcH, dstW, dstH);
+        //return false;
+    }
+
+    if (srcW > 256 || srcH > 256) {
+        WTRACE("unexpected size %dx%d for cursor", srcW, srcH);
+        return false;
+    }
+
+    BufferManager *bm = Hwcomposer::getInstance().getBufferManager();
+    if (bm) {
+        DataBuffer *buffer = bm->lockDataBuffer(hwcLayer->getHandle());
+        if (buffer) {
+            uint32_t w = buffer->getWidth();
+            uint32_t h = buffer->getHeight();
+
+            if ((w != 64 || h != 64) &&
+                (w != 128 || h != 128) &&
+                (w != 256 || h != 256)) {
+                bm->unlockDataBuffer(buffer);
+                return false;
+            }
+        }
+        bm->unlockDataBuffer(buffer);
+    }
+
+    return true;
+}
+
+bool HwcLayerList::initialize()
+{
+    if (!mList || mList->numHwLayers == 0) {
+        ETRACE("invalid hwc list");
+        return false;
+    }
+
+    mLayerCount = (int)mList->numHwLayers;
+    mLayers.setCapacity(mLayerCount);
+    mFBLayers.setCapacity(mLayerCount);
+    mSpriteCandidates.setCapacity(mLayerCount);
+    mOverlayCandidates.setCapacity(mLayerCount);
+    mCursorCandidates.setCapacity(mLayerCount);
+    mZOrderConfig.setCapacity(mLayerCount);
+    Hwcomposer& hwc = Hwcomposer::getInstance();
+
+    for (int i = 0; i < mLayerCount; i++) {
+        hwc_layer_1_t *layer = &mList->hwLayers[i];
+        if (!layer) {
+            DEINIT_AND_RETURN_FALSE("layer %d is null", i);
+        }
+
+        HwcLayer *hwcLayer = new HwcLayer(i, layer);
+        if (!hwcLayer) {
+            DEINIT_AND_RETURN_FALSE("failed to allocate hwc layer %d", i);
+        }
+
+        if (layer->compositionType == HWC_FRAMEBUFFER_TARGET) {
+            hwcLayer->setType(HwcLayer::LAYER_FRAMEBUFFER_TARGET);
+            mFrameBufferTarget = hwcLayer;
+        } else if (layer->compositionType == HWC_OVERLAY){
+            // skipped layer, filtered by Display Analyzer
+            hwcLayer->setType(HwcLayer::LAYER_SKIPPED);
+        } else if (layer->compositionType == HWC_FORCE_FRAMEBUFFER) {
+            layer->compositionType = HWC_FRAMEBUFFER;
+            hwcLayer->setType(HwcLayer::LAYER_FORCE_FB);
+            // add layer to FB layer list for zorder check during plane assignment
+            mFBLayers.add(hwcLayer);
+        } else  if (layer->compositionType == HWC_FRAMEBUFFER) {
+            // by default use GPU composition
+            hwcLayer->setType(HwcLayer::LAYER_FB);
+            mFBLayers.add(hwcLayer);
+            if (checkCursorSupported(hwcLayer)) {
+                mCursorCandidates.add(hwcLayer);
+            } else if (checkSupported(DisplayPlane::PLANE_SPRITE, hwcLayer)) {
+                mSpriteCandidates.add(hwcLayer);
+            } else if (hwc.getDisplayAnalyzer()->isOverlayAllowed() &&
+                checkSupported(DisplayPlane::PLANE_OVERLAY, hwcLayer)) {
+                mOverlayCandidates.add(hwcLayer);
+            } else {
+                // noncandidate layer
+            }
+        } else if (layer->compositionType == HWC_SIDEBAND){
+            hwcLayer->setType(HwcLayer::LAYER_SIDEBAND);
+        } else {
+            DEINIT_AND_RETURN_FALSE("invalid composition type %d", layer->compositionType);
+        }
+        // add layer to layer list
+        mLayers.add(hwcLayer);
+    }
+
+    if (mFrameBufferTarget == NULL) {
+        ETRACE("no frame buffer target?");
+        return false;
+    }
+
+    // If has layer besides of FB_Target, but no FBLayers, skip plane allocation
+    // Note: There is case that SF passes down a layerlist with only FB_Target
+    // layer; we need to have this FB_Target to be flipped as well, otherwise it
+    // will have the buffer queue blocked. (The buffer hold by driver cannot be
+    // released if new buffers' flip is skipped).
+    if ((mFBLayers.size() == 0) && (mLayers.size() > 1)) {
+        VTRACE("no FB layers, skip plane allocation");
+        return true;
+    }
+
+    allocatePlanes();
+
+    //dump();
+    return true;
+}
+
+void HwcLayerList::deinitialize()
+{
+    if (mLayerCount == 0) {
+        return;
+    }
+
+    DisplayPlaneManager *planeManager = Hwcomposer::getInstance().getPlaneManager();
+    for (int i = 0; i < mLayerCount; i++) {
+        HwcLayer *hwcLayer = mLayers.itemAt(i);
+        if (hwcLayer) {
+            DisplayPlane *plane = hwcLayer->detachPlane();
+            if (plane) {
+                planeManager->reclaimPlane(mDisplayIndex, *plane);
+            }
+        }
+        delete hwcLayer;
+    }
+
+    mLayers.clear();
+    mFBLayers.clear();
+    mOverlayCandidates.clear();
+    mSpriteCandidates.clear();
+    mCursorCandidates.clear();
+    mZOrderConfig.clear();
+    mFrameBufferTarget = NULL;
+    mLayerCount = 0;
+}
+
+
+bool HwcLayerList::allocatePlanes()
+{
+    return assignCursorPlanes();
+}
+
+bool HwcLayerList::assignCursorPlanes()
+{
+    int cursorCandidates = (int)mCursorCandidates.size();
+    if (cursorCandidates == 0) {
+        return assignOverlayPlanes();
+    }
+
+    DisplayPlaneManager *planeManager = Hwcomposer::getInstance().getPlaneManager();
+    int planeNumber = planeManager->getFreePlanes(mDisplayIndex, DisplayPlane::PLANE_CURSOR);
+    if (planeNumber == 0) {
+        DTRACE("no cursor plane available. candidates %d", cursorCandidates);
+        return assignOverlayPlanes();
+    }
+
+    if (planeNumber > cursorCandidates) {
+        // assuming all cursor planes have the same capabilities, just
+        // need up to number of candidates for plane assignment
+        planeNumber = cursorCandidates;
+    }
+
+    for (int i = planeNumber; i >= 0; i--) {
+        // assign as many cursor planes as possible
+        if (assignCursorPlanes(0, i)) {
+            return true;
+        }
+        if (mZOrderConfig.size() != 0) {
+            ETRACE("ZOrder config is not cleaned up!");
+        }
+    }
+    return false;
+}
+
+bool HwcLayerList::assignCursorPlanes(int index, int planeNumber)
+{
+    // index indicates position in mCursorCandidates to start plane assignment
+    if (planeNumber == 0) {
+        return assignOverlayPlanes();
+    }
+
+    int cursorCandidates = (int)mCursorCandidates.size();
+    for (int i = index; i <= cursorCandidates - planeNumber; i++) {
+        ZOrderLayer *zlayer = addZOrderLayer(DisplayPlane::PLANE_CURSOR, mCursorCandidates[i]);
+        if (assignCursorPlanes(i + 1, planeNumber - 1)) {
+            return true;
+        }
+        removeZOrderLayer(zlayer);
+    }
+    return false;
+}
+
+bool HwcLayerList::assignOverlayPlanes()
+{
+    int overlayCandidates = (int)mOverlayCandidates.size();
+    if (overlayCandidates == 0) {
+        return assignSpritePlanes();
+    }
+
+    DisplayPlaneManager *planeManager = Hwcomposer::getInstance().getPlaneManager();
+    int planeNumber = planeManager->getFreePlanes(mDisplayIndex, DisplayPlane::PLANE_OVERLAY);
+    if (planeNumber == 0) {
+        DTRACE("no overlay plane available. candidates %d", overlayCandidates);
+        return assignSpritePlanes();
+    }
+
+    if (planeNumber > overlayCandidates) {
+        // assuming all overlay planes have the same capabilities, just
+        // need up to number of candidates for plane assignment
+        planeNumber = overlayCandidates;
+    }
+
+    for (int i = planeNumber; i >= 0; i--) {
+        // assign as many overlay planes as possible
+        if (assignOverlayPlanes(0, i)) {
+            return true;
+        }
+        if (mZOrderConfig.size() != 0) {
+            ETRACE("ZOrder config is not cleaned up!");
+        }
+    }
+    return false;
+}
+
+
+bool HwcLayerList::assignOverlayPlanes(int index, int planeNumber)
+{
+    // index indicates position in mOverlayCandidates to start plane assignment
+    if (planeNumber == 0) {
+        return assignSpritePlanes();
+    }
+
+    int overlayCandidates = (int)mOverlayCandidates.size();
+    for (int i = index; i <= overlayCandidates - planeNumber; i++) {
+        ZOrderLayer *zlayer = addZOrderLayer(DisplayPlane::PLANE_OVERLAY, mOverlayCandidates[i]);
+        if (assignOverlayPlanes(i + 1, planeNumber - 1)) {
+            return true;
+        }
+        removeZOrderLayer(zlayer);
+    }
+    return false;
+}
+
+bool HwcLayerList::assignSpritePlanes()
+{
+    int spriteCandidates = (int)mSpriteCandidates.size();
+    if (spriteCandidates == 0) {
+        return assignPrimaryPlane();
+    }
+
+    //  number does not include primary plane
+    DisplayPlaneManager *planeManager = Hwcomposer::getInstance().getPlaneManager();
+    int planeNumber = planeManager->getFreePlanes(mDisplayIndex, DisplayPlane::PLANE_SPRITE);
+    if (planeNumber == 0) {
+        VTRACE("no sprite plane available, candidates %d", spriteCandidates);
+        return assignPrimaryPlane();
+    }
+
+    if (planeNumber > spriteCandidates) {
+        // assuming all sprite planes have the same capabilities, just
+        // need up to number of candidates for plane assignment
+        planeNumber = spriteCandidates;
+    }
+
+    for (int i = planeNumber; i >= 0; i--) {
+        // assign as many sprite planes as possible
+        if (assignSpritePlanes(0, i)) {
+            return true;
+        }
+
+        if (mOverlayCandidates.size() == 0 && mZOrderConfig.size() != 0) {
+            ETRACE("ZOrder config is not cleaned up!");
+        }
+    }
+    return false;
+}
+
+
+bool HwcLayerList::assignSpritePlanes(int index, int planeNumber)
+{
+    if (planeNumber == 0) {
+        return assignPrimaryPlane();
+    }
+
+    int spriteCandidates = (int)mSpriteCandidates.size();
+    for (int i = index; i <= spriteCandidates - planeNumber; i++) {
+        ZOrderLayer *zlayer = addZOrderLayer(DisplayPlane::PLANE_SPRITE, mSpriteCandidates[i]);
+        if (assignSpritePlanes(i + 1, planeNumber - 1)) {
+            return true;
+        }
+        removeZOrderLayer(zlayer);
+    }
+    return false;
+}
+
+bool HwcLayerList::assignPrimaryPlane()
+{
+    // find a sprit layer that is not candidate but has lower priority than candidates.
+    HwcLayer *spriteLayer = NULL;
+    for (int i = (int)mSpriteCandidates.size() - 1; i >= 0; i--) {
+        if (mSpriteCandidates[i]->mPlaneCandidate)
+            break;
+
+        spriteLayer = mSpriteCandidates[i];
+    }
+
+    int candidates = (int)mZOrderConfig.size();
+    int layers = (int)mFBLayers.size();
+    bool ok = false;
+
+    if (candidates == layers - 1 && spriteLayer != NULL) {
+        // primary plane is configured as sprite, all sprite candidates are offloaded to display planes
+        ok = assignPrimaryPlaneHelper(spriteLayer);
+        if (!ok) {
+            VTRACE("failed to use primary as sprite plane");
+        }
+    } else if (candidates == 0) {
+        // none assigned, use primary plane for frame buffer target and set zorder to 0
+        ok = assignPrimaryPlaneHelper(mFrameBufferTarget, 0);
+        if (!ok) {
+            ETRACE("failed to compose all layers to primary plane, should never happen");
+        }
+    } else if (candidates == layers) {
+        // all assigned, primary plane may be used during ZOrder config.
+        ok = attachPlanes();
+        if (!ok) {
+            VTRACE("failed to assign layers without primary");
+        }
+    } else {
+        // check if the remaining planes can be composed to frame buffer target (FBT)
+        // look up a legitimate Z order position to place FBT.
+        for (int i = 0; i < layers && !ok; i++) {
+            if (mFBLayers[i]->mPlaneCandidate) {
+                continue;
+            }
+            if (useAsFrameBufferTarget(mFBLayers[i])) {
+                ok = assignPrimaryPlaneHelper(mFrameBufferTarget, mFBLayers[i]->getZOrder());
+                if (!ok) {
+                    VTRACE("failed to use zorder %d for frame buffer target",
+                        mFBLayers[i]->getZOrder());
+                }
+            }
+        }
+        if (!ok) {
+            VTRACE("no possible zorder for frame buffer target");
+        }
+
+    }
+    return ok;
+}
+
+bool HwcLayerList::assignPrimaryPlaneHelper(HwcLayer *hwcLayer, int zorder)
+{
+    ZOrderLayer *zlayer = addZOrderLayer(DisplayPlane::PLANE_PRIMARY, hwcLayer, zorder);
+    bool ok = attachPlanes();
+    if (!ok) {
+        removeZOrderLayer(zlayer);
+    }
+    return ok;
+}
+
+bool HwcLayerList::attachPlanes()
+{
+    DisplayPlaneManager *planeManager = Hwcomposer::getInstance().getPlaneManager();
+    if (!planeManager->isValidZOrder(mDisplayIndex, mZOrderConfig)) {
+        VTRACE("invalid z order, size of config %d", mZOrderConfig.size());
+        return false;
+    }
+
+    if (!planeManager->assignPlanes(mDisplayIndex, mZOrderConfig)) {
+        WTRACE("failed to assign planes");
+        return false;
+    }
+
+    VTRACE("============= plane assignment===================");
+    for (int i = 0; i < (int)mZOrderConfig.size(); i++) {
+        ZOrderLayer *zlayer = mZOrderConfig.itemAt(i);
+        if (zlayer->plane == NULL || zlayer->hwcLayer == NULL) {
+            ETRACE("invalid ZOrderLayer, should never happen!!");
+            return false;
+        }
+
+        zlayer->plane->setZOrder(i);
+
+        if (zlayer->plane->getType() == DisplayPlane::PLANE_CURSOR) {
+            zlayer->hwcLayer->setType(HwcLayer::LAYER_CURSOR_OVERLAY);
+            mFBLayers.remove(zlayer->hwcLayer);
+        } else if (zlayer->hwcLayer != mFrameBufferTarget) {
+            zlayer->hwcLayer->setType(HwcLayer::LAYER_OVERLAY);
+            // update FB layers for smart composition
+            mFBLayers.remove(zlayer->hwcLayer);
+        }
+
+        zlayer->hwcLayer->attachPlane(zlayer->plane, mDisplayIndex);
+
+        VTRACE("total %d, layer %d, type %d, index %d, zorder %d",
+            mLayerCount - 1,
+            zlayer->hwcLayer->getIndex(),
+            zlayer->plane->getType(),
+            zlayer->plane->getIndex(),
+            zlayer->zorder);
+
+        delete zlayer;
+    }
+
+    mZOrderConfig.clear();
+    return true;
+}
+
+bool HwcLayerList::useAsFrameBufferTarget(HwcLayer *target)
+{
+    // check if zorder of target can be used as zorder of frame buffer target
+    // eligible only when all noncandidate layers can be merged to the target layer:
+    // 1) noncandidate layer and candidate layer below the target layer can't overlap
+    // if candidate layer is on top of non candidate layer, as "noncandidate layer" needs
+    // to be moved up to target layer in z order;
+    // 2) noncandidate layer and candidate layers above the target layer can't overlap
+    // if candidate layer is below noncandidate layer, as "noncandidate layer" needs
+    // to be moved down to target layer in z order.
+
+    int targetLayerIndex = target->getIndex();
+
+    // check candidate and noncandidate layers below this candidate does not overlap
+    for (int below = 0; below < targetLayerIndex; below++) {
+        if (mFBLayers[below]->mPlaneCandidate) {
+            continue;
+        } else {
+            // check candidate layer above this noncandidate layer does not overlap
+            for (int above = below + 1; above < targetLayerIndex; above++) {
+                if (mFBLayers[above]->mPlaneCandidate == false) {
+                    continue;
+                }
+                if (hasIntersection(mFBLayers[above], mFBLayers[below])) {
+                    return false;
+                }
+            }
+        }
+    }
+
+    // check candidate and noncandidate layers above this candidate does not overlap
+    for (int above = targetLayerIndex + 1; above < mFBLayers.size(); above++) {
+        if (mFBLayers[above]->mPlaneCandidate) {
+            continue;
+        } else {
+            // check candidate layer below this noncandidate layer does not overlap
+            for (int below = targetLayerIndex + 1; below < above; below++) {
+                if (mFBLayers[below]->mPlaneCandidate == false) {
+                    continue;
+                }
+                if (hasIntersection(mFBLayers[above], mFBLayers[below])) {
+                    return false;
+                }
+            }
+        }
+    }
+
+    return true;
+}
+
+bool HwcLayerList::hasIntersection(HwcLayer *la, HwcLayer *lb)
+{
+    hwc_layer_1_t *a = la->getLayer();
+    hwc_layer_1_t *b = lb->getLayer();
+    hwc_rect_t *aRect = &a->displayFrame;
+    hwc_rect_t *bRect = &b->displayFrame;
+
+    if (bRect->right <= aRect->left ||
+        bRect->left >= aRect->right ||
+        bRect->top >= aRect->bottom ||
+        bRect->bottom <= aRect->top)
+        return false;
+
+    return true;
+}
+
+ZOrderLayer* HwcLayerList::addZOrderLayer(int type, HwcLayer *hwcLayer, int zorder)
+{
+    ZOrderLayer *layer = new ZOrderLayer;
+    layer->planeType = type;
+    layer->hwcLayer = hwcLayer;
+    layer->zorder = (zorder != -1) ? zorder : hwcLayer->getZOrder();
+    layer->plane = NULL;
+
+    if (hwcLayer->mPlaneCandidate) {
+        ETRACE("plane is candidate!, order = %d", zorder);
+    }
+
+    hwcLayer->mPlaneCandidate = true;
+
+    if ((int)mZOrderConfig.indexOf(layer) >= 0) {
+        ETRACE("layer exists!");
+    }
+
+    mZOrderConfig.add(layer);
+    return layer;
+}
+
+void HwcLayerList::removeZOrderLayer(ZOrderLayer *layer)
+{
+    if ((int)mZOrderConfig.indexOf(layer) < 0) {
+        ETRACE("layer does not exist!");
+    }
+
+    mZOrderConfig.remove(layer);
+
+    if (layer->hwcLayer->mPlaneCandidate == false) {
+        ETRACE("plane is not candidate!, order %d", layer->zorder);
+    }
+    layer->hwcLayer->mPlaneCandidate = false;
+    delete layer;
+}
+
+void HwcLayerList::addStaticLayerSize(HwcLayer *hwcLayer)
+{
+    // Calculate static layer size to avoid only composition navigation bar
+    // and status bar etc.
+    hwc_layer_1_t *a = hwcLayer->getLayer();
+    hwc_rect_t *Rect = &a->displayFrame;
+
+    mLayerSize = mLayerSize + ((Rect->right - Rect->left) * (Rect->bottom - Rect->top));
+}
+
+bool HwcLayerList::checkStaticLayerSize()
+{
+    // Check static layer size if over threshold: half display size
+    bool ret = false;
+    int width = 0;
+    int height = 0;
+    drmModeModeInfo mode;
+    Drm *drm = Hwcomposer::getInstance().getDrm();
+    drm->getModeInfo(mDisplayIndex, mode);
+    width = mode.hdisplay;
+    height = mode.vdisplay;
+
+    if (mLayerSize > (width * height/2))
+        ret = true;
+
+    return ret;
+}
+
+void HwcLayerList::setupSmartComposition()
+{
+    uint32_t compositionType = HWC_OVERLAY;
+    HwcLayer *hwcLayer = NULL;
+
+    // setup smart composition only there's no update on all FB layers
+    for (size_t i = 0; i < mFBLayers.size(); i++) {
+        hwcLayer = mFBLayers.itemAt(i);
+        if (hwcLayer->isUpdated() ||
+            hwcLayer->getStaticCount() == LAYER_STATIC_THRESHOLD) {
+            compositionType = HWC_FRAMEBUFFER;
+        }
+    }
+
+    VTRACE("smart composition enabled %s",
+           (compositionType == HWC_OVERLAY) ? "TRUE" : "FALSE");
+    for (size_t i = 0; i < mFBLayers.size(); i++) {
+        hwcLayer = mFBLayers.itemAt(i);
+        switch (hwcLayer->getType()) {
+        case HwcLayer::LAYER_FB:
+        case HwcLayer::LAYER_FORCE_FB:
+            hwcLayer->setCompositionType(compositionType);
+            break;
+        default:
+            ETRACE("Invalid layer type %d", hwcLayer->getType());
+            break;
+        }
+    }
+}
+
+bool HwcLayerList::setupSmartComposition2()
+{
+    bool ret = false;
+    HwcLayer *hwcLayer = NULL;
+    int layerIndex = 0;
+    int i = 0;
+
+    if (mList->flags & HWC_GEOMETRY_CHANGED) {
+        // clear static layers vector once geometry changed
+        mStaticLayersIndex.setCapacity(mLayerCount);
+        mStaticLayersIndex.clear();
+        return ret;
+    }
+
+    if (mStaticLayersIndex.size() > 0) {
+        // exit criteria: once either static layer has update
+        for (i = 0; i < mStaticLayersIndex.size(); i++) {
+            layerIndex = mStaticLayersIndex.itemAt(i);
+            hwcLayer = mLayers.itemAt(layerIndex);
+
+            if (hwcLayer->isUpdated()) {
+                ret = true;
+            }
+        }
+
+        if (ret == true) {
+            for (i = 0; i < mStaticLayersIndex.size(); i++) {
+                layerIndex = mStaticLayersIndex.itemAt(i);
+                hwcLayer = mLayers.itemAt(layerIndex);
+
+                hwcLayer->setCompositionType(HWC_FRAMEBUFFER);
+            }
+
+            DTRACE("Exit Smart Composition2 !");
+            mLayerSize = 0;
+            mStaticLayersIndex.clear();
+        }
+    } else {
+        // entry criteria: hwc layers has no update
+        if (mFBLayers.size() == 0) {
+            for (i = 0; i < mLayerCount - 1; i++) {
+                hwcLayer = mLayers.itemAt(i);
+                if (hwcLayer->getPlane() &&
+                    hwcLayer->getCompositionType() == HWC_OVERLAY &&
+                    hwcLayer->getStaticCount() >= LAYER_STATIC_THRESHOLD) {
+                    mStaticLayersIndex.add(i);
+                }
+            }
+
+            // check if all static layers in sequence
+            // if all in sequence, set FORCE_FB for static layers
+            // TODO: optimization here
+            //    1. If two connected, can trigger smart composition2
+            //    2. Caculate layer size to see if it saves more bandwidth
+            //    3. Dynamically check and add new static layers
+            int staticLayerCount = mStaticLayersIndex.size();
+
+            if (staticLayerCount > 1 && staticLayerCount < mLayerCount-1) {
+                layerIndex = mStaticLayersIndex.itemAt(0);
+                hwcLayer = mLayers.itemAt(layerIndex);
+                mLayerSize = 0;
+                addStaticLayerSize(hwcLayer);
+                int preIndex = hwcLayer->getIndex();
+
+                for (i = 1; i < staticLayerCount; i++) {
+                    layerIndex = mStaticLayersIndex.itemAt(i);
+                    hwcLayer = mLayers.itemAt(layerIndex);
+                    int index = hwcLayer->getIndex();
+
+                    if (index == preIndex + 1) {
+                        addStaticLayerSize(hwcLayer);
+                        preIndex = index;
+                    } else
+                        break;
+                }
+
+                if ((i == staticLayerCount) && checkStaticLayerSize()) {
+                    for (i =0; i < staticLayerCount; i++) {
+                        layerIndex = mStaticLayersIndex.itemAt(i);
+                        hwcLayer = mLayers.itemAt(layerIndex);
+                        hwcLayer->setCompositionType(HWC_FORCE_FRAMEBUFFER);
+                    }
+                    DTRACE("In Smart Composition2 !");
+                    ret = true;
+                } else {
+                    mLayerSize = 0;
+                }
+            }
+
+            if (!ret)
+                mStaticLayersIndex.clear();
+        }
+    }
+
+    // return ture to trigger remap layers with HW plane
+    return ret;
+}
+
+#if 1  // support overlay fallback to GLES
+
+bool HwcLayerList::update(hwc_display_contents_1_t *list)
+{
+    bool ret;
+
+    // basic check to make sure the consistance
+    if (!list) {
+        ETRACE("null layer list");
+        return false;
+    }
+
+    if ((int)list->numHwLayers != mLayerCount) {
+        ETRACE("layer count doesn't match (%zd, %d)", list->numHwLayers, mLayerCount);
+        return false;
+    }
+
+    // update list
+    mList = list;
+
+    bool ok = true;
+    // update all layers, call each layer's update()
+    for (int i = 0; i < mLayerCount; i++) {
+        HwcLayer *hwcLayer = mLayers.itemAt(i);
+        if (!hwcLayer) {
+            ETRACE("no HWC layer for layer %d", i);
+            continue;
+        }
+
+        if (!hwcLayer->update(&list->hwLayers[i])) {
+            ok = false;
+            hwcLayer->setCompositionType(HWC_FORCE_FRAMEBUFFER);
+        }
+    }
+
+    if (!ok || setupSmartComposition2()) {
+        ITRACE("overlay fallback to GLES. flags: %#x", list->flags);
+        for (int i = 0; i < mLayerCount - 1; i++) {
+            HwcLayer *hwcLayer = mLayers.itemAt(i);
+            if (hwcLayer->getPlane() &&
+                (hwcLayer->getCompositionType() == HWC_OVERLAY ||
+                hwcLayer->getCompositionType() == HWC_CURSOR_OVERLAY)) {
+                hwcLayer->setCompositionType(HWC_FRAMEBUFFER);
+            }
+        }
+        mLayers.itemAt(mLayerCount - 1)->setCompositionType(HWC_FRAMEBUFFER_TARGET);
+        deinitialize();
+        mList = list;
+        initialize();
+
+        // update all layers again after plane re-allocation
+        for (int i = 0; i < mLayerCount; i++) {
+            HwcLayer *hwcLayer = mLayers.itemAt(i);
+            if (!hwcLayer) {
+                ETRACE("no HWC layer for layer %d", i);
+                continue;
+            }
+
+            if (!hwcLayer->update(&list->hwLayers[i])) {
+                DTRACE("fallback to GLES update failed on layer[%d]!\n", i);
+            }
+        }
+    }
+
+    setupSmartComposition();
+    return true;
+}
+
+#else
+
+bool HwcLayerList::update(hwc_display_contents_1_t *list)
+{
+    bool ret;
+
+    // basic check to make sure the consistance
+    if (!list) {
+        ETRACE("null layer list");
+        return false;
+    }
+
+    if ((int)list->numHwLayers != mLayerCount) {
+        ETRACE("layer count doesn't match (%d, %d)", list->numHwLayers, mLayerCount);
+        return false;
+    }
+
+    // update list
+    mList = list;
+
+    // update all layers, call each layer's update()
+    for (int i = 0; i < mLayerCount; i++) {
+        HwcLayer *hwcLayer = mLayers.itemAt(i);
+        if (!hwcLayer) {
+            ETRACE("no HWC layer for layer %d", i);
+            continue;
+        }
+
+        hwcLayer->update(&list->hwLayers[i]);
+    }
+
+    setupSmartComposition();
+    return true;
+}
+
+#endif
+
+DisplayPlane* HwcLayerList::getPlane(uint32_t index) const
+{
+    HwcLayer *hwcLayer;
+
+    if (index >= mLayers.size()) {
+        ETRACE("invalid layer index %d", index);
+        return 0;
+    }
+
+    hwcLayer = mLayers.itemAt(index);
+    if ((hwcLayer->getType() == HwcLayer::LAYER_FB) ||
+        (hwcLayer->getType() == HwcLayer::LAYER_FORCE_FB) ||
+        (hwcLayer->getType() == HwcLayer::LAYER_SKIPPED)) {
+        return 0;
+    }
+
+    if (hwcLayer->getHandle() == 0) {
+        DTRACE("plane is attached with invalid handle");
+        return 0;
+    }
+
+    return hwcLayer->getPlane();
+}
+
+void HwcLayerList::postFlip()
+{
+    for (size_t i = 0; i < mLayers.size(); i++) {
+        HwcLayer *hwcLayer = mLayers.itemAt(i);
+        hwcLayer->postFlip();
+    }
+}
+
+void HwcLayerList::dump(Dump& d)
+{
+    d.append("Layer list: (number of layers %d):\n", mLayers.size());
+    d.append(" LAYER |          TYPE          |   PLANE  | INDEX | Z Order \n");
+    d.append("-------+------------------------+----------------------------\n");
+    for (size_t i = 0; i < mLayers.size(); i++) {
+        HwcLayer *hwcLayer = mLayers.itemAt(i);
+        DisplayPlane *plane;
+        long int planeIndex = -1;
+        long int zorder = -1;
+        const char *type = "HWC_FB";
+        const char *planeType = "N/A";
+
+        if (hwcLayer) {
+            switch (hwcLayer->getType()) {
+            case HwcLayer::LAYER_FB:
+            case HwcLayer::LAYER_FORCE_FB:
+                type = "HWC_FB";
+                break;
+            case HwcLayer::LAYER_OVERLAY:
+            case HwcLayer::LAYER_SKIPPED:
+                type = "HWC_OVERLAY";
+                break;
+            case HwcLayer::LAYER_FRAMEBUFFER_TARGET:
+                type = "HWC_FRAMEBUFFER_TARGET";
+                break;
+            case HwcLayer::LAYER_SIDEBAND:
+                type = "HWC_SIDEBAND";
+                break;
+            case HwcLayer::LAYER_CURSOR_OVERLAY:
+                type = "HWC_CURSOR_OVERLAY";
+                break;
+            default:
+                type = "Unknown";
+            }
+
+            plane = hwcLayer->getPlane();
+            if (plane) {
+                planeIndex = plane->getIndex();
+                zorder = plane->getZOrder();
+                switch (plane->getType()) {
+                case DisplayPlane::PLANE_OVERLAY:
+                    planeType = "OVERLAY";
+                    break;
+                case DisplayPlane::PLANE_SPRITE:
+                    planeType = "SPRITE";
+                    break;
+                case DisplayPlane::PLANE_PRIMARY:
+                    planeType = "PRIMARY";
+                    break;
+                case DisplayPlane::PLANE_CURSOR:
+                    planeType = "CURSOR";
+                    break;
+                default:
+                    planeType = "Unknown";
+                }
+            }
+
+            d.append("  %2d   | %22s | %8s | %3ld   | %3ld \n",
+                     i, type, planeType, planeIndex, zorder);
+        }
+    }
+}
+
+
+void HwcLayerList::dump()
+{
+    static char const* compositionTypeName[] = {
+        "GLES",
+        "HWC",
+        "BG",
+        "FBT",
+        "SB",
+        "CUR",
+        "N/A"};
+
+    static char const* planeTypeName[] = {
+        "SPRITE",
+        "OVERLAY",
+        "PRIMARY",
+        "CURSOR",
+        "UNKNOWN"};
+
+    DTRACE(" numHwLayers = %zu, flags = %08x", mList->numHwLayers, mList->flags);
+
+    DTRACE(" type |  handle  | hints | flags | tr | blend | alpha |  format  |           source crop             |            frame          | index | zorder |  plane  ");
+    DTRACE("------+----------+-------+-------+----+-------+-------+----------+-----------------------------------+---------------------------+-------+--------+---------");
+
+
+    for (int i = 0 ; i < mLayerCount ; i++) {
+        const hwc_layer_1_t&l = mList->hwLayers[i];
+        DisplayPlane *plane = mLayers[i]->getPlane();
+        int planeIndex = -1;
+        int zorder = -1;
+        const char *planeType = "N/A";
+        if (plane) {
+            planeIndex = plane->getIndex();
+            zorder = plane->getZOrder();
+            planeType = planeTypeName[plane->getType()];
+        }
+
+        DTRACE(
+            " %4s | %p | %5x | %5x | %2x | %5x | %5x | %8x | [%7.1f,%7.1f,%7.1f,%7.1f] | [%5d,%5d,%5d,%5d] | %5d | %6d | %7s ",
+            compositionTypeName[l.compositionType],
+            mLayers[i]->getHandle(), l.hints, l.flags, l.transform, l.blending, l.planeAlpha, mLayers[i]->getFormat(),
+            l.sourceCropf.left, l.sourceCropf.top, l.sourceCropf.right, l.sourceCropf.bottom,
+            l.displayFrame.left, l.displayFrame.top, l.displayFrame.right, l.displayFrame.bottom,
+            planeIndex, zorder, planeType);
+    }
+
+}
+
+
+} // namespace intel
+} // namespace android
diff --git a/merrifield/common/base/HwcLayerList.h b/merrifield/common/base/HwcLayerList.h
new file mode 100644
index 0000000..d4eb9b9
--- /dev/null
+++ b/merrifield/common/base/HwcLayerList.h
@@ -0,0 +1,112 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef HWC_LAYER_LIST_H
+#define HWC_LAYER_LIST_H
+
+#include <Dump.h>
+#include <hardware/hwcomposer.h>
+#include <utils/SortedVector.h>
+#include <DataBuffer.h>
+#include <DisplayPlane.h>
+#include <DisplayPlaneManager.h>
+#include <HwcLayer.h>
+
+namespace android {
+namespace intel {
+
+
+class HwcLayerList {
+public:
+    HwcLayerList(hwc_display_contents_1_t *list, int disp);
+    virtual ~HwcLayerList();
+
+public:
+    virtual bool initialize();
+    virtual void deinitialize();
+
+    virtual bool update(hwc_display_contents_1_t *list);
+    virtual DisplayPlane* getPlane(uint32_t index) const;
+
+    void postFlip();
+
+    // dump interface
+    virtual void dump(Dump& d);
+
+private:
+    bool checkSupported(int planeType, HwcLayer *hwcLayer);
+    bool checkCursorSupported(HwcLayer *hwcLayer);
+    bool allocatePlanes();
+    bool assignCursorPlanes();
+    bool assignCursorPlanes(int index, int planeNumber);
+    bool assignOverlayPlanes();
+    bool assignOverlayPlanes(int index, int planeNumber);
+    bool assignSpritePlanes();
+    bool assignSpritePlanes(int index, int planeNumber);
+    bool assignPrimaryPlane();
+    bool assignPrimaryPlaneHelper(HwcLayer *hwcLayer, int zorder = -1);
+    bool attachPlanes();
+    bool useAsFrameBufferTarget(HwcLayer *target);
+    bool hasIntersection(HwcLayer *la, HwcLayer *lb);
+    void addStaticLayerSize(HwcLayer *hwcLayer);
+    bool checkStaticLayerSize();
+    ZOrderLayer* addZOrderLayer(int type, HwcLayer *hwcLayer, int zorder = -1);
+    void removeZOrderLayer(ZOrderLayer *layer);
+    void setupSmartComposition();
+    bool setupSmartComposition2();
+    void dump();
+
+private:
+    class HwcLayerVector : public SortedVector<HwcLayer*> {
+    public:
+        HwcLayerVector() {}
+        virtual int do_compare(const void* lhs, const void* rhs) const {
+            const HwcLayer* l = *(HwcLayer**)lhs;
+            const HwcLayer* r = *(HwcLayer**)rhs;
+            // sorted from index 0 to n
+            return l->getIndex() - r->getIndex();
+        }
+    };
+
+    class PriorityVector : public SortedVector<HwcLayer*> {
+    public:
+        PriorityVector() {}
+        virtual int do_compare(const void* lhs, const void* rhs) const {
+            const HwcLayer* l = *(HwcLayer**)lhs;
+            const HwcLayer* r = *(HwcLayer**)rhs;
+            return r->getPriority() - l->getPriority();
+        }
+    };
+
+    hwc_display_contents_1_t *mList;
+    int mLayerCount;
+
+    HwcLayerVector mLayers;
+    HwcLayerVector mFBLayers;
+    Vector<int> mStaticLayersIndex;
+    PriorityVector mSpriteCandidates;
+    PriorityVector mOverlayCandidates;
+    PriorityVector mCursorCandidates;
+    ZOrderConfig mZOrderConfig;
+    HwcLayer *mFrameBufferTarget;
+    int mDisplayIndex;
+    int mLayerSize;
+};
+
+} // namespace intel
+} // namespace android
+
+
+#endif /* HWC_LAYER_LIST_H */
diff --git a/merrifield/common/base/HwcModule.cpp b/merrifield/common/base/HwcModule.cpp
new file mode 100644
index 0000000..5894b9b
--- /dev/null
+++ b/merrifield/common/base/HwcModule.cpp
@@ -0,0 +1,299 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#include <hardware/hardware.h>
+#include <string.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <HwcTrace.h>
+#include <Hwcomposer.h>
+
+#define GET_HWC_RETURN_X_IF_NULL(X) \
+    CTRACE(); \
+    Hwcomposer *hwc = static_cast<Hwcomposer*>(dev); \
+    do {\
+        if (!hwc) { \
+            ETRACE("invalid HWC device."); \
+            return X; \
+        } \
+    } while (0)
+
+
+#define GET_HWC_RETURN_ERROR_IF_NULL()        GET_HWC_RETURN_X_IF_NULL(-EINVAL)
+#define GET_HWC_RETURN_VOID_IF_NULL()         GET_HWC_RETURN_X_IF_NULL()
+
+
+namespace android {
+namespace intel {
+
+static int hwc_prepare(struct hwc_composer_device_1 *dev,
+                          size_t numDisplays,
+                          hwc_display_contents_1_t** displays)
+{
+    GET_HWC_RETURN_ERROR_IF_NULL();
+    if (!hwc->prepare(numDisplays, displays)) {
+        ETRACE("failed to prepare");
+        return -EINVAL;
+    }
+    return 0;
+}
+
+static int hwc_set(struct hwc_composer_device_1 *dev,
+                     size_t numDisplays,
+                     hwc_display_contents_1_t **displays)
+{
+    GET_HWC_RETURN_ERROR_IF_NULL();
+    if (!hwc->commit(numDisplays, displays)) {
+        ETRACE("failed to commit");
+        return -EINVAL;
+    }
+    return 0;
+}
+
+static void hwc_dump(struct hwc_composer_device_1 *dev,
+                       char *buff,
+                       int buff_len)
+{
+    GET_HWC_RETURN_VOID_IF_NULL();
+    hwc->dump(buff, buff_len, 0);
+}
+
+void hwc_registerProcs(struct hwc_composer_device_1 *dev,
+                          hwc_procs_t const *procs)
+{
+    GET_HWC_RETURN_VOID_IF_NULL();
+    hwc->registerProcs(procs);
+}
+
+static int hwc_device_close(struct hw_device_t *dev)
+{
+    CTRACE();
+    Hwcomposer::releaseInstance();
+    return 0;
+}
+
+static int hwc_query(struct hwc_composer_device_1 *dev,
+                       int what,
+                       int* value)
+{
+    ATRACE("what = %d", what);
+    return -EINVAL;
+}
+
+static int hwc_eventControl(struct hwc_composer_device_1 *dev,
+                                int disp,
+                                int event,
+                                int enabled)
+{
+    bool ret;
+    GET_HWC_RETURN_ERROR_IF_NULL();
+
+    switch (event) {
+    case HWC_EVENT_VSYNC:
+        ret = hwc->vsyncControl(disp, enabled);
+        if (ret == false) {
+            ETRACE("failed to control vsync");
+            return -EINVAL;
+        }
+        break;
+    default:
+        WTRACE("unsupported event %d", event);
+        break;
+    }
+
+    return 0;
+}
+
+static int hwc_blank(hwc_composer_device_1_t *dev, int disp, int blank)
+{
+    GET_HWC_RETURN_ERROR_IF_NULL();
+    bool ret = hwc->blank(disp, blank);
+    if (ret == false) {
+        ETRACE("failed to blank disp %d, blank %d", disp, blank);
+        return -EINVAL;
+    }
+
+    return 0;
+}
+
+static int hwc_getDisplayConfigs(hwc_composer_device_1_t *dev,
+                                     int disp,
+                                     uint32_t *configs,
+                                     size_t *numConfigs)
+{
+    GET_HWC_RETURN_ERROR_IF_NULL();
+    bool ret = hwc->getDisplayConfigs(disp, configs, numConfigs);
+    if (ret == false) {
+        WTRACE("failed to get configs of disp %d", disp);
+        return -EINVAL;
+    }
+
+    return 0;
+}
+
+static int hwc_getDisplayAttributes(hwc_composer_device_1_t *dev,
+                                        int disp,
+                                        uint32_t config,
+                                        const uint32_t *attributes,
+                                        int32_t *values)
+{
+    GET_HWC_RETURN_ERROR_IF_NULL();
+    bool ret = hwc->getDisplayAttributes(disp, config, attributes, values);
+    if (ret == false) {
+        WTRACE("failed to get attributes of disp %d", disp);
+        return -EINVAL;
+    }
+
+    return 0;
+}
+
+static int hwc_compositionComplete(hwc_composer_device_1_t *dev, int disp)
+{
+    GET_HWC_RETURN_ERROR_IF_NULL();
+    bool ret = hwc->compositionComplete(disp);
+    if (ret == false) {
+        ETRACE("failed for disp %d", disp);
+        return -EINVAL;
+    }
+
+    return 0;
+}
+
+static int hwc_setPowerMode(hwc_composer_device_1_t *dev, int disp, int mode)
+{
+    GET_HWC_RETURN_ERROR_IF_NULL();
+    bool ret = hwc->setPowerMode(disp, mode);
+    if (ret == false) {
+        WTRACE("failed to set power mode of disp %d", disp);
+        return -EINVAL;
+    }
+
+    return 0;
+}
+
+static int hwc_getActiveConfig(hwc_composer_device_1_t *dev, int disp)
+{
+    GET_HWC_RETURN_ERROR_IF_NULL();
+    int ret = hwc->getActiveConfig(disp);
+    if (ret == -1) {
+        WTRACE("failed to get active config of disp %d", disp);
+        return -EINVAL;
+    }
+
+    return ret;
+}
+
+static int hwc_setActiveConfig(hwc_composer_device_1_t *dev, int disp, int index)
+{
+    GET_HWC_RETURN_ERROR_IF_NULL();
+    bool ret = hwc->setActiveConfig(disp, index);
+    if (ret == false) {
+        WTRACE("failed to set active config of disp %d", disp);
+        return -EINVAL;
+    }
+
+    return 0;
+}
+
+static int hwc_setCursorPositionAsync(hwc_composer_device_1_t *dev, int disp, int x, int y)
+{
+    GET_HWC_RETURN_ERROR_IF_NULL();
+    bool ret = hwc->setCursorPositionAsync(disp, x, y);
+    if (ret == false) {
+        WTRACE("failed to set cursor position of disp %d", disp);
+        return -EINVAL;
+    }
+
+    return 0;
+}
+
+//------------------------------------------------------------------------------
+
+static int hwc_device_open(const struct hw_module_t* module,
+                              const char* name,
+                              struct hw_device_t** device)
+{
+    if (!name) {
+        ETRACE("invalid name.");
+        return -EINVAL;
+    }
+
+    ATRACE("open device %s", name);
+
+    if (strcmp(name, HWC_HARDWARE_COMPOSER) != 0) {
+        ETRACE("try to open unknown HWComposer %s", name);
+        return -EINVAL;
+    }
+
+    Hwcomposer& hwc = Hwcomposer::getInstance();
+    // initialize our state here
+    if (hwc.initialize() == false) {
+        ETRACE("failed to intialize HWComposer");
+        Hwcomposer::releaseInstance();
+        return -EINVAL;
+    }
+
+    // initialize the procs
+    hwc.hwc_composer_device_1_t::common.tag = HARDWARE_DEVICE_TAG;
+    hwc.hwc_composer_device_1_t::common.module =
+        const_cast<hw_module_t*>(module);
+    hwc.hwc_composer_device_1_t::common.close = hwc_device_close;
+
+    hwc.hwc_composer_device_1_t::prepare = hwc_prepare;
+    hwc.hwc_composer_device_1_t::set = hwc_set;
+    hwc.hwc_composer_device_1_t::dump = hwc_dump;
+    hwc.hwc_composer_device_1_t::registerProcs = hwc_registerProcs;
+    hwc.hwc_composer_device_1_t::query = hwc_query;
+
+    hwc.hwc_composer_device_1_t::blank = hwc_blank;
+    hwc.hwc_composer_device_1_t::eventControl = hwc_eventControl;
+    hwc.hwc_composer_device_1_t::getDisplayConfigs = hwc_getDisplayConfigs;
+    hwc.hwc_composer_device_1_t::getDisplayAttributes = hwc_getDisplayAttributes;
+
+    // This is used to hack FBO switch flush issue in SurfaceFlinger.
+    hwc.hwc_composer_device_1_t::reserved_proc[0] = (void*)hwc_compositionComplete;
+    hwc.hwc_composer_device_1_t::common.version = HWC_DEVICE_API_VERSION_1_4;
+    hwc.hwc_composer_device_1_t::setPowerMode = hwc_setPowerMode;
+    hwc.hwc_composer_device_1_t::getActiveConfig = hwc_getActiveConfig;
+    hwc.hwc_composer_device_1_t::setActiveConfig = hwc_setActiveConfig;
+    // Todo: add hwc_setCursorPositionAsync after supporting patches
+    hwc.hwc_composer_device_1_t::setCursorPositionAsync = NULL;
+
+    *device = &hwc.hwc_composer_device_1_t::common;
+
+    return 0;
+}
+
+} // namespace intel
+} // namespace android
+
+static struct hw_module_methods_t hwc_module_methods = {
+    open: android::intel::hwc_device_open
+};
+
+hwc_module_t HAL_MODULE_INFO_SYM = {
+    common: {
+        tag: HARDWARE_MODULE_TAG,
+        version_major: 1,
+        version_minor: 4,
+        id: HWC_HARDWARE_MODULE_ID,
+        name: "Intel Hardware Composer",
+        author: "Intel",
+        methods: &hwc_module_methods,
+        dso: NULL,
+        reserved: {0},
+    }
+};
diff --git a/merrifield/common/base/Hwcomposer.cpp b/merrifield/common/base/Hwcomposer.cpp
new file mode 100644
index 0000000..bb08c73
--- /dev/null
+++ b/merrifield/common/base/Hwcomposer.cpp
@@ -0,0 +1,550 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#include <HwcTrace.h>
+#include <Hwcomposer.h>
+#include <Dump.h>
+#include <UeventObserver.h>
+
+namespace android {
+namespace intel {
+
+Hwcomposer* Hwcomposer::sInstance(0);
+
+Hwcomposer::Hwcomposer(IPlatFactory *factory)
+    : mProcs(0),
+      mDrm(0),
+      mPlatFactory(factory),
+      mVsyncManager(0),
+      mDisplayAnalyzer(0),
+      mMultiDisplayObserver(0),
+      mUeventObserver(0),
+      mPlaneManager(0),
+      mBufferManager(0),
+      mDisplayContext(0),
+      mInitialized(false)
+{
+    CTRACE();
+
+    mDisplayDevices.setCapacity(IDisplayDevice::DEVICE_COUNT);
+    mDisplayDevices.clear();
+}
+
+Hwcomposer::~Hwcomposer()
+{
+    CTRACE();
+    deinitialize();
+}
+
+bool Hwcomposer::initCheck() const
+{
+    return mInitialized;
+}
+
+bool Hwcomposer::prepare(size_t numDisplays,
+                          hwc_display_contents_1_t** displays)
+{
+    bool ret = true;
+
+    RETURN_FALSE_IF_NOT_INIT();
+    ATRACE("display count = %d", numDisplays);
+
+    if (!numDisplays || !displays) {
+        ETRACE("invalid parameters");
+        return false;
+    }
+
+    mDisplayAnalyzer->analyzeContents(numDisplays, displays);
+
+    // disable reclaimed planes
+    mPlaneManager->disableReclaimedPlanes();
+
+        if(numDisplays > mDisplayDevices.size())
+                numDisplays = mDisplayDevices.size();
+
+    // reclaim all allocated planes if possible
+    for (size_t i = 0; i < numDisplays; i++) {
+        IDisplayDevice *device = mDisplayDevices.itemAt(i);
+        if (!device) {
+            VTRACE("device %d doesn't exist", i);
+            continue;
+        }
+
+        device->prePrepare(displays[i]);
+    }
+
+    for (size_t i = 0; i < numDisplays; i++) {
+        IDisplayDevice *device = mDisplayDevices.itemAt(i);
+        if (!device) {
+            VTRACE("device %d doesn't exist", i);
+            continue;
+        }
+
+        ret = device->prepare(displays[i]);
+        if (ret == false) {
+            ETRACE("failed to do prepare for device %d", i);
+            continue;
+        }
+    }
+
+    return ret;
+}
+
+bool Hwcomposer::commit(size_t numDisplays,
+                         hwc_display_contents_1_t **displays)
+{
+    bool ret = true;
+
+    RETURN_FALSE_IF_NOT_INIT();
+    ATRACE("display count = %d", numDisplays);
+
+    if (!numDisplays || !displays) {
+        ETRACE("invalid parameters");
+        return false;
+    }
+
+        if(numDisplays > mDisplayDevices.size())
+                numDisplays = mDisplayDevices.size();
+
+    mDisplayContext->commitBegin(numDisplays, displays);
+
+    for (size_t i = 0; i < numDisplays; i++) {
+        IDisplayDevice *device = mDisplayDevices.itemAt(i);
+        if (!device) {
+            VTRACE("device %d doesn't exist", i);
+            continue;
+        }
+
+        if (!device->isConnected()) {
+            VTRACE("device %d is disconnected", i);
+            continue;
+        }
+
+        ret = device->commit(displays[i], mDisplayContext);
+        if (ret == false) {
+            ETRACE("failed to do commit for device %d", i);
+            continue;
+        }
+    }
+
+    mDisplayContext->commitEnd(numDisplays, displays);
+    // return true always
+    return true;
+}
+
+bool Hwcomposer::setPowerMode(int disp, int mode)
+{
+    RETURN_FALSE_IF_NOT_INIT();
+
+    if (disp < 0 || disp >= IDisplayDevice::DEVICE_COUNT) {
+        ETRACE("invalid disp %d", disp);
+        return false;
+    }
+
+    if(disp >= mDisplayDevices.size()){
+        ETRACE("no device found");
+        return false;
+    }
+
+    IDisplayDevice *device = mDisplayDevices.itemAt(disp);
+    if (!device) {
+        ETRACE("no device found");
+        return false;
+    }
+
+    return device->setPowerMode(mode);
+}
+
+int Hwcomposer::getActiveConfig(int disp)
+{
+    RETURN_NULL_IF_NOT_INIT();
+
+    if (disp < 0 || disp >= IDisplayDevice::DEVICE_COUNT) {
+        ETRACE("invalid disp %d", disp);
+        return -1;
+    }
+
+    IDisplayDevice *device = mDisplayDevices.itemAt(disp);
+    if (!device) {
+        ETRACE("no device found");
+        return -1;
+    }
+
+    return device->getActiveConfig();
+}
+
+bool Hwcomposer::setActiveConfig(int disp, int index)
+{
+    RETURN_FALSE_IF_NOT_INIT();
+
+    if (disp < 0 || disp >= IDisplayDevice::DEVICE_COUNT) {
+        ETRACE("invalid disp %d", disp);
+        return false;
+    }
+
+    IDisplayDevice *device = mDisplayDevices.itemAt(disp);
+    if (!device) {
+        ETRACE("no device found");
+        return false;
+    }
+
+    return device->setActiveConfig(index);
+}
+
+bool Hwcomposer::setCursorPositionAsync(int disp, int x, int y)
+{
+    RETURN_FALSE_IF_NOT_INIT();
+
+    if (disp != HWC_DISPLAY_PRIMARY && disp != HWC_DISPLAY_EXTERNAL) {
+        ETRACE("invalid disp %d", disp);
+        return false;
+    }
+
+    return mDisplayContext->setCursorPosition(disp, x, y);
+}
+
+bool Hwcomposer::vsyncControl(int disp, int enabled)
+{
+    RETURN_FALSE_IF_NOT_INIT();
+    ATRACE("disp = %d, enabled = %d", disp, enabled);
+    return mVsyncManager->handleVsyncControl(disp, enabled ? true : false);
+}
+
+bool Hwcomposer::blank(int disp, int blank)
+{
+    RETURN_FALSE_IF_NOT_INIT();
+    ATRACE("disp = %d, blank = %d", disp, blank);
+
+    if (disp < 0 || disp >= IDisplayDevice::DEVICE_COUNT) {
+        ETRACE("invalid disp %d", disp);
+        return false;
+    }
+
+    IDisplayDevice *device = mDisplayDevices.itemAt(disp);
+    if (!device) {
+        ETRACE("no device found");
+        return false;
+    }
+
+    return device->blank(blank ? true : false);
+}
+
+bool Hwcomposer::getDisplayConfigs(int disp,
+                                      uint32_t *configs,
+                                      size_t *numConfigs)
+{
+    RETURN_FALSE_IF_NOT_INIT();
+
+    if (disp < 0 || disp >= IDisplayDevice::DEVICE_COUNT) {
+        ETRACE("invalid disp %d", disp);
+        return false;
+    }
+
+    if(disp >= mDisplayDevices.size()){
+        ETRACE("no device found");
+        return false;
+    }
+
+    IDisplayDevice *device = mDisplayDevices.itemAt(disp);
+    if (!device) {
+        ETRACE("no device %d found", disp);
+        return false;
+    }
+
+    return device->getDisplayConfigs(configs, numConfigs);
+}
+
+bool Hwcomposer::getDisplayAttributes(int disp,
+                                         uint32_t config,
+                                         const uint32_t *attributes,
+                                         int32_t *values)
+{
+    RETURN_FALSE_IF_NOT_INIT();
+
+    if (disp < 0 || disp >= IDisplayDevice::DEVICE_COUNT) {
+        ETRACE("invalid disp %d", disp);
+        return false;
+    }
+    if(disp >= mDisplayDevices.size()){
+        ETRACE("no device found");
+        return false;
+    }
+
+
+    IDisplayDevice *device = mDisplayDevices.itemAt(disp);
+    if (!device) {
+        ETRACE("no device found");
+        return false;
+    }
+
+    return device->getDisplayAttributes(config, attributes, values);
+}
+
+bool Hwcomposer::compositionComplete(int disp)
+{
+    RETURN_FALSE_IF_NOT_INIT();
+
+    if (disp < 0 || disp >= IDisplayDevice::DEVICE_COUNT) {
+        ETRACE("invalid disp %d", disp);
+        return false;
+    }
+
+    mDisplayContext->compositionComplete();
+
+    if(disp >= mDisplayDevices.size()){
+        ETRACE("no device found");
+        return false;
+    }
+
+    IDisplayDevice *device = mDisplayDevices.itemAt(disp);
+    if (!device) {
+        ETRACE("no device found");
+        return false;
+    }
+
+    return device->compositionComplete();
+}
+
+void Hwcomposer::vsync(int disp, int64_t timestamp)
+{
+    RETURN_VOID_IF_NOT_INIT();
+
+    if (mProcs && mProcs->vsync) {
+        VTRACE("report vsync on disp %d, timestamp %llu", disp, timestamp);
+        // workaround to pretend vsync is from primary display
+        // Display will freeze if vsync is from external display.
+        mProcs->vsync(const_cast<hwc_procs_t*>(mProcs), IDisplayDevice::DEVICE_PRIMARY, timestamp);
+    }
+}
+
+void Hwcomposer::hotplug(int disp, bool connected)
+{
+    RETURN_VOID_IF_NOT_INIT();
+
+    // TODO: Two fake hotplug events are sent during mode setting. To avoid
+    // unnecessary audio switch, real connection status should be sent to MDS
+    mMultiDisplayObserver->notifyHotPlug(mDrm->isConnected(disp));
+
+    if (mProcs && mProcs->hotplug) {
+        DTRACE("report hotplug on disp %d, connected %d", disp, connected);
+        mProcs->hotplug(const_cast<hwc_procs_t*>(mProcs), disp, connected);
+        DTRACE("hotplug callback processed and returned!");
+    }
+
+    mDisplayAnalyzer->postHotplugEvent(connected);
+}
+
+void Hwcomposer::invalidate()
+{
+    RETURN_VOID_IF_NOT_INIT();
+
+    if (mProcs && mProcs->invalidate) {
+        DTRACE("invalidating screen...");
+        mProcs->invalidate(const_cast<hwc_procs_t*>(mProcs));
+    }
+}
+
+bool Hwcomposer::release()
+{
+    RETURN_FALSE_IF_NOT_INIT();
+
+    return true;
+}
+
+bool Hwcomposer::dump(char *buff, int buff_len, int *cur_len)
+{
+    RETURN_FALSE_IF_NOT_INIT();
+
+    Dump d(buff, buff_len);
+
+    // dump composer status
+    d.append("Hardware Composer state:");
+    // dump device status
+    for (size_t i= 0; i < mDisplayDevices.size(); i++) {
+        IDisplayDevice *device = mDisplayDevices.itemAt(i);
+        if (device)
+            device->dump(d);
+    }
+
+    // dump plane manager status
+    if (mPlaneManager)
+        mPlaneManager->dump(d);
+
+    // dump buffer manager status
+    if (mBufferManager)
+        mBufferManager->dump(d);
+
+    return true;
+}
+
+void Hwcomposer::registerProcs(hwc_procs_t const *procs)
+{
+    CTRACE();
+
+    if (!procs) {
+        WTRACE("procs is NULL");
+    }
+    mProcs = procs;
+}
+
+bool Hwcomposer::initialize()
+{
+    CTRACE();
+
+    // create drm
+    mDrm = new Drm();
+    if (!mDrm || !mDrm->initialize()) {
+        DEINIT_AND_RETURN_FALSE("failed to create DRM");
+    }
+
+    if (!mPlatFactory){
+        DEINIT_AND_RETURN_FALSE("failed to provide a PlatFactory");
+    }
+
+    // create buffer manager
+    mBufferManager = mPlatFactory->createBufferManager();
+    if (!mBufferManager || !mBufferManager->initialize()) {
+        DEINIT_AND_RETURN_FALSE("failed to create buffer manager");
+    }
+
+    // create display plane manager
+    mPlaneManager = mPlatFactory->createDisplayPlaneManager();
+    if (!mPlaneManager || !mPlaneManager->initialize()) {
+        DEINIT_AND_RETURN_FALSE("failed to create display plane manager");
+    }
+
+    mDisplayContext = mPlatFactory->createDisplayContext();
+    if (!mDisplayContext || !mDisplayContext->initialize()) {
+        DEINIT_AND_RETURN_FALSE("failed to create display context");
+    }
+
+    mUeventObserver = new UeventObserver();
+    if (!mUeventObserver || !mUeventObserver->initialize()) {
+        DEINIT_AND_RETURN_FALSE("failed to initialize uevent observer");
+    }
+
+    // create display device
+    mDisplayDevices.clear();
+    for (int i = 0; i < IDisplayDevice::DEVICE_COUNT; i++) {
+        IDisplayDevice *device = mPlatFactory->createDisplayDevice(i);
+        if (!device || !device->initialize()) {
+            DEINIT_AND_DELETE_OBJ(device);
+            DEINIT_AND_RETURN_FALSE("failed to create device %d", i);
+        }
+        // add this device
+        ETRACE("HWC devices initialize device is %p at %d", device, i);
+        mDisplayDevices.insertAt(device, i, 1);
+    }
+
+    mVsyncManager = new VsyncManager(*this);
+    if (!mVsyncManager || !mVsyncManager->initialize()) {
+        DEINIT_AND_RETURN_FALSE("failed to create Vsync Manager");
+    }
+
+    mDisplayAnalyzer = new DisplayAnalyzer();
+    if (!mDisplayAnalyzer || !mDisplayAnalyzer->initialize()) {
+        DEINIT_AND_RETURN_FALSE("failed to initialize display analyzer");
+    }
+
+    mMultiDisplayObserver = new MultiDisplayObserver();
+    if (!mMultiDisplayObserver || !mMultiDisplayObserver->initialize()) {
+        DEINIT_AND_RETURN_FALSE("failed to initialize display observer");
+    }
+
+    // all initialized, starting uevent observer
+    mUeventObserver->start();
+
+    mInitialized = true;
+    return true;
+}
+
+void Hwcomposer::deinitialize()
+{
+    DEINIT_AND_DELETE_OBJ(mMultiDisplayObserver);
+    DEINIT_AND_DELETE_OBJ(mDisplayAnalyzer);
+    // delete mVsyncManager first as it holds reference to display devices.
+    DEINIT_AND_DELETE_OBJ(mVsyncManager);
+
+    DEINIT_AND_DELETE_OBJ(mUeventObserver);
+    // destroy display devices
+    for (size_t i = 0; i < mDisplayDevices.size(); i++) {
+        IDisplayDevice *device = mDisplayDevices.itemAt(i);
+        DEINIT_AND_DELETE_OBJ(device);
+    }
+    mDisplayDevices.clear();
+
+    if (mPlatFactory) {
+        delete mPlatFactory;
+        mPlatFactory = 0;
+    }
+
+    DEINIT_AND_DELETE_OBJ(mDisplayContext);
+    DEINIT_AND_DELETE_OBJ(mPlaneManager);
+    DEINIT_AND_DELETE_OBJ(mBufferManager);
+    DEINIT_AND_DELETE_OBJ(mDrm);
+    mInitialized = false;
+}
+
+Drm* Hwcomposer::getDrm()
+{
+    return mDrm;
+}
+
+DisplayPlaneManager* Hwcomposer::getPlaneManager()
+{
+    return mPlaneManager;
+}
+
+BufferManager* Hwcomposer::getBufferManager()
+{
+    return mBufferManager;
+}
+
+IDisplayContext* Hwcomposer::getDisplayContext()
+{
+    return mDisplayContext;
+}
+
+DisplayAnalyzer* Hwcomposer::getDisplayAnalyzer()
+{
+    return mDisplayAnalyzer;
+}
+
+MultiDisplayObserver* Hwcomposer::getMultiDisplayObserver()
+{
+    return mMultiDisplayObserver;
+}
+
+IDisplayDevice* Hwcomposer::getDisplayDevice(int disp)
+{
+    if (disp < 0 || disp >= IDisplayDevice::DEVICE_COUNT) {
+        ETRACE("invalid disp %d", disp);
+        return NULL;
+    }
+    return mDisplayDevices.itemAt(disp);
+}
+
+VsyncManager* Hwcomposer::getVsyncManager()
+{
+    return mVsyncManager;
+}
+
+UeventObserver* Hwcomposer::getUeventObserver()
+{
+    return mUeventObserver;
+}
+
+} // namespace intel
+} // namespace android
diff --git a/merrifield/common/base/SimpleThread.h b/merrifield/common/base/SimpleThread.h
new file mode 100644
index 0000000..ade0e84
--- /dev/null
+++ b/merrifield/common/base/SimpleThread.h
@@ -0,0 +1,38 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#ifndef SIMPLE_THREAD_H
+#define SIMPLE_THREAD_H
+
+#include <utils/threads.h>
+
+#define DECLARE_THREAD(THREADNAME, THREADOWNER) \
+    class THREADNAME: public Thread { \
+    public: \
+        THREADNAME(THREADOWNER *owner) { mOwner = owner; } \
+        THREADNAME() { mOwner = NULL; } \
+    private: \
+        virtual bool threadLoop() { return mOwner->threadLoop(); } \
+    private: \
+        THREADOWNER *mOwner; \
+    }; \
+    friend class THREADNAME; \
+    bool threadLoop(); \
+    sp<THREADNAME> mThread;
+
+
+#endif /* SIMPLE_THREAD_H */
+
diff --git a/merrifield/common/base/VsyncManager.cpp b/merrifield/common/base/VsyncManager.cpp
new file mode 100644
index 0000000..56e935e
--- /dev/null
+++ b/merrifield/common/base/VsyncManager.cpp
@@ -0,0 +1,218 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#include <HwcTrace.h>
+#include <IDisplayDevice.h>
+#include <DisplayQuery.h>
+#include <BufferManager.h>
+#include <DisplayPlaneManager.h>
+#include <Hwcomposer.h>
+#include <VsyncManager.h>
+
+
+namespace android {
+namespace intel {
+
+VsyncManager::VsyncManager(Hwcomposer &hwc)
+     :mHwc(hwc),
+      mInitialized(false),
+      mEnableDynamicVsync(true),
+      mEnabled(false),
+      mVsyncSource(IDisplayDevice::DEVICE_COUNT),
+      mLock()
+{
+}
+
+VsyncManager::~VsyncManager()
+{
+    WARN_IF_NOT_DEINIT();
+}
+
+bool VsyncManager::initialize()
+{
+
+    mEnabled = false;
+    mVsyncSource = IDisplayDevice::DEVICE_COUNT;
+    mEnableDynamicVsync = !scUsePrimaryVsyncOnly;
+    mInitialized = true;
+    return true;
+}
+
+void VsyncManager::deinitialize()
+{
+    if (mEnabled) {
+        WTRACE("vsync is still enabled");
+    }
+
+    mVsyncSource = IDisplayDevice::DEVICE_COUNT;
+    mEnabled = false;
+    mEnableDynamicVsync = !scUsePrimaryVsyncOnly;
+    mInitialized = false;
+}
+
+bool VsyncManager::handleVsyncControl(int disp, bool enabled)
+{
+    Mutex::Autolock l(mLock);
+
+    if (disp != IDisplayDevice::DEVICE_PRIMARY) {
+        WTRACE("vsync control on non-primary device %d", disp);
+        return false;
+    }
+
+    if (mEnabled == enabled) {
+        WTRACE("vsync state %d is not changed", enabled);
+        return true;
+    }
+
+    if (!enabled) {
+        disableVsync();
+        mEnabled = false;
+        return true;
+    } else {
+        mEnabled = enableVsync(getCandidate());
+        return mEnabled;
+    }
+
+    return false;
+}
+
+void VsyncManager::resetVsyncSource()
+{
+    Mutex::Autolock l(mLock);
+
+    if (!mEnableDynamicVsync) {
+        ITRACE("dynamic vsync source switch is not supported");
+        return;
+    }
+
+    if (!mEnabled) {
+        return;
+    }
+
+    int vsyncSource = getCandidate();
+    if (vsyncSource == mVsyncSource) {
+        return;
+    }
+
+    disableVsync();
+    enableVsync(vsyncSource);
+}
+
+int VsyncManager::getVsyncSource()
+{
+    return mVsyncSource;
+}
+
+void VsyncManager::enableDynamicVsync(bool enable)
+{
+    Mutex::Autolock l(mLock);
+    if (scUsePrimaryVsyncOnly) {
+        WTRACE("dynamic vsync is not supported");
+        return;
+    }
+
+    mEnableDynamicVsync = enable;
+
+    if (!mEnabled) {
+        return;
+    }
+
+    int vsyncSource = getCandidate();
+    if (vsyncSource == mVsyncSource) {
+        return;
+    }
+
+    disableVsync();
+    enableVsync(vsyncSource);
+}
+
+IDisplayDevice* VsyncManager::getDisplayDevice(int dispType ) {
+    return mHwc.getDisplayDevice(dispType);
+}
+
+int VsyncManager::getCandidate()
+{
+    if (!mEnableDynamicVsync) {
+        return IDisplayDevice::DEVICE_PRIMARY;
+    }
+
+    IDisplayDevice *device = NULL;
+    // use HDMI vsync when connected
+    device = getDisplayDevice(IDisplayDevice::DEVICE_EXTERNAL);
+    if (device && device->isConnected()) {
+        return IDisplayDevice::DEVICE_EXTERNAL;
+    }
+
+#ifdef INTEL_WIDI_MERRIFIELD
+    // use vsync from virtual display when video extended mode is entered
+    if (Hwcomposer::getInstance().getDisplayAnalyzer()->isVideoExtModeActive()) {
+        device = getDisplayDevice(IDisplayDevice::DEVICE_VIRTUAL);
+        if (device && device->isConnected()) {
+            return IDisplayDevice::DEVICE_VIRTUAL;
+        }
+        WTRACE("Could not use vsync from secondary device");
+    }
+#endif
+    return IDisplayDevice::DEVICE_PRIMARY;
+}
+
+bool VsyncManager::enableVsync(int candidate)
+{
+    if (mVsyncSource != IDisplayDevice::DEVICE_COUNT) {
+        WTRACE("vsync has been enabled on %d", mVsyncSource);
+        return true;
+    }
+
+    IDisplayDevice *device = getDisplayDevice(candidate);
+    if (!device) {
+        ETRACE("invalid vsync source candidate %d", candidate);
+        return false;
+    }
+
+    if (device->vsyncControl(true)) {
+        mVsyncSource = candidate;
+        return true;
+    }
+
+    if (candidate != IDisplayDevice::DEVICE_PRIMARY) {
+        WTRACE("failed to enable vsync on display %d, fall back to primary", candidate);
+        device = getDisplayDevice(IDisplayDevice::DEVICE_PRIMARY);
+        if (device && device->vsyncControl(true)) {
+            mVsyncSource = IDisplayDevice::DEVICE_PRIMARY;
+            return true;
+        }
+    }
+    ETRACE("failed to enable vsync on the primary display");
+    return false;
+}
+
+void VsyncManager::disableVsync()
+{
+    if (mVsyncSource == IDisplayDevice::DEVICE_COUNT) {
+        WTRACE("vsync has been disabled");
+        return;
+    }
+
+    IDisplayDevice *device = getDisplayDevice(mVsyncSource);
+    if (device && !device->vsyncControl(false)) {
+        WTRACE("failed to disable vsync on device %d", mVsyncSource);
+    }
+    mVsyncSource = IDisplayDevice::DEVICE_COUNT;
+}
+
+} // namespace intel
+} // namespace android
+
diff --git a/merrifield/common/base/VsyncManager.h b/merrifield/common/base/VsyncManager.h
new file mode 100644
index 0000000..4af10ed
--- /dev/null
+++ b/merrifield/common/base/VsyncManager.h
@@ -0,0 +1,65 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef VSYNC_MANAGER_H
+#define VSYNC_MANAGER_H
+
+#include <IDisplayDevice.h>
+#include <utils/threads.h>
+
+namespace android {
+namespace intel {
+
+
+class Hwcomposer;
+
+class VsyncManager {
+public:
+    VsyncManager(Hwcomposer& hwc);
+    virtual ~VsyncManager();
+
+public:
+    bool initialize();
+    void deinitialize();
+    bool handleVsyncControl(int disp, bool enabled);
+    void resetVsyncSource();
+    int getVsyncSource();
+    void enableDynamicVsync(bool enable);
+
+private:
+    inline int getCandidate();
+    inline bool enableVsync(int candidate);
+    inline void disableVsync();
+    IDisplayDevice* getDisplayDevice(int dispType);
+
+private:
+    Hwcomposer &mHwc;
+    bool mInitialized;
+    bool mEnableDynamicVsync;
+    bool mEnabled;
+    int  mVsyncSource;
+    Mutex mLock;
+
+private:
+    // toggle this constant to use primary vsync only or enable dynamic vsync.
+    static const bool scUsePrimaryVsyncOnly = false;
+};
+
+} // namespace intel
+} // namespace android
+
+
+
+#endif /* VSYNC_MANAGER_H */
diff --git a/merrifield/common/buffers/BufferCache.cpp b/merrifield/common/buffers/BufferCache.cpp
new file mode 100644
index 0000000..cfd14d3
--- /dev/null
+++ b/merrifield/common/buffers/BufferCache.cpp
@@ -0,0 +1,97 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#include <HwcTrace.h>
+#include <BufferCache.h>
+
+namespace android {
+namespace intel {
+
+BufferCache::BufferCache(int size)
+{
+    mBufferPool.setCapacity(size);
+}
+
+BufferCache::~BufferCache()
+{
+    if (mBufferPool.size() != 0) {
+        ETRACE("buffer cache is not empty");
+    }
+    mBufferPool.clear();
+}
+
+bool BufferCache::addMapper(uint64_t handle, BufferMapper* mapper)
+{
+    ssize_t index = mBufferPool.indexOfKey(handle);
+    if (index >= 0) {
+        ETRACE("buffer %#llx exists", handle);
+        return false;
+    }
+
+    // add mapper
+    index = mBufferPool.add(handle, mapper);
+    if (index < 0) {
+        ETRACE("failed to add mapper. err = %d", (int)index);
+        return false;
+    }
+
+    return true;
+}
+
+bool BufferCache::removeMapper(BufferMapper* mapper)
+{
+    ssize_t index;
+
+    if (!mapper) {
+        ETRACE("invalid mapper");
+        return false;
+    }
+
+    index = mBufferPool.removeItem(mapper->getKey());
+    if (index < 0) {
+        WTRACE("failed to remove mapper. err = %d", (int)index);
+        return false;
+    }
+
+    return true;
+}
+
+BufferMapper* BufferCache::getMapper(uint64_t handle)
+{
+    ssize_t index = mBufferPool.indexOfKey(handle);
+    if (index < 0) {
+        // don't add ETRACE here as this condition will happen frequently
+        return 0;
+    }
+    return mBufferPool.valueAt(index);
+}
+
+size_t BufferCache::getCacheSize() const
+{
+    return mBufferPool.size();
+}
+
+BufferMapper* BufferCache::getMapper(uint32_t index)
+{
+    if (index >= mBufferPool.size()) {
+        ETRACE("invalid index");
+        return 0;
+    }
+    BufferMapper* mapper = mBufferPool.valueAt(index);
+    return mapper;
+}
+
+} // namespace intel
+} // namespace android
diff --git a/merrifield/common/buffers/BufferCache.h b/merrifield/common/buffers/BufferCache.h
new file mode 100644
index 0000000..fc1ab86
--- /dev/null
+++ b/merrifield/common/buffers/BufferCache.h
@@ -0,0 +1,48 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef BUFFERCACHE_H_
+#define BUFFERCACHE_H_
+
+#include <utils/KeyedVector.h>
+#include <BufferMapper.h>
+
+namespace android {
+namespace intel {
+
+// Generic buffer cache
+class BufferCache {
+public:
+    BufferCache(int size);
+    virtual ~BufferCache();
+    // add a new mapper into buffer cache
+    virtual bool addMapper(uint64_t handle, BufferMapper* mapper);
+    //remove mapper
+    virtual bool removeMapper(BufferMapper* mapper);
+    // get a buffer mapper
+    virtual BufferMapper* getMapper(uint64_t handle);
+    // get cache size
+    virtual size_t getCacheSize() const;
+    // get mapper with an index
+    virtual BufferMapper* getMapper(uint32_t index);
+private:
+    KeyedVector<uint64_t, BufferMapper*> mBufferPool;
+};
+
+}
+}
+
+
+#endif /* BUFFERCACHE_H_ */
diff --git a/merrifield/common/buffers/BufferManager.cpp b/merrifield/common/buffers/BufferManager.cpp
new file mode 100644
index 0000000..fc460b3
--- /dev/null
+++ b/merrifield/common/buffers/BufferManager.cpp
@@ -0,0 +1,358 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#include <HwcTrace.h>
+#include <hardware/hwcomposer.h>
+#include <BufferManager.h>
+#include <DrmConfig.h>
+
+namespace android {
+namespace intel {
+
+BufferManager::BufferManager()
+    : mGrallocModule(NULL),
+      mAllocDev(NULL),
+      mFrameBuffers(),
+      mBufferPool(NULL),
+      mDataBuffer(NULL),
+      mDataBufferLock(),
+      mInitialized(false)
+{
+    CTRACE();
+}
+
+BufferManager::~BufferManager()
+{
+    WARN_IF_NOT_DEINIT();
+}
+
+bool BufferManager::initCheck() const
+{
+    return mInitialized;
+}
+
+bool BufferManager::initialize()
+{
+    CTRACE();
+
+    // create buffer pool
+    mBufferPool = new BufferCache(DEFAULT_BUFFER_POOL_SIZE);
+    if (!mBufferPool) {
+        ETRACE("failed to create gralloc buffer cache");
+        return false;
+    }
+
+    // init gralloc module
+    hw_module_t const* module;
+    if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module)) {
+        DEINIT_AND_RETURN_FALSE("failed to get gralloc module");
+    }
+    mGrallocModule = (gralloc_module_t*)module;
+
+    gralloc_open(module, &mAllocDev);
+    if (!mAllocDev) {
+        WTRACE("failed to open alloc device");
+    }
+
+    // create a dummy data buffer
+    mDataBuffer = createDataBuffer(mGrallocModule, 0);
+    if (!mDataBuffer) {
+        DEINIT_AND_RETURN_FALSE("failed to create data buffer");
+    }
+
+    mInitialized = true;
+    return true;
+}
+
+void BufferManager::deinitialize()
+{
+    mInitialized = false;
+
+    if (mBufferPool) {
+        // unmap & delete all cached buffer mappers
+        for (size_t i = 0; i < mBufferPool->getCacheSize(); i++) {
+            BufferMapper *mapper = mBufferPool->getMapper(i);
+            mapper->unmap();
+            delete mapper;
+        }
+
+        delete mBufferPool;
+        mBufferPool = NULL;
+    }
+
+    for (size_t j = 0; j < mFrameBuffers.size(); j++) {
+        BufferMapper *mapper = mFrameBuffers.valueAt(j);
+        mapper->unmap();
+        delete mapper;
+    }
+    mFrameBuffers.clear();
+
+    if (mAllocDev) {
+        gralloc_close(mAllocDev);
+        mAllocDev = NULL;
+    }
+
+    if (mDataBuffer) {
+        delete mDataBuffer;
+        mDataBuffer = NULL;
+    }
+}
+
+void BufferManager::dump(Dump& d)
+{
+    d.append("Buffer Manager status: pool size %d\n", mBufferPool->getCacheSize());
+    d.append("-------------------------------------------------------------\n");
+    for (uint32_t i = 0; i < mBufferPool->getCacheSize(); i++) {
+        BufferMapper *mapper = mBufferPool->getMapper(i);
+        d.append("Buffer %d: handle %#x, (%dx%d), format %d, refCount %d\n",
+                 i,
+                 mapper->getHandle(),
+                 mapper->getWidth(),
+                 mapper->getHeight(),
+                 mapper->getFormat(),
+                 mapper->getRef());
+    }
+    return;
+}
+
+DataBuffer* BufferManager::lockDataBuffer(buffer_handle_t handle)
+{
+    mDataBufferLock.lock();
+    mDataBuffer->resetBuffer(handle);
+    return mDataBuffer;
+}
+
+void BufferManager::unlockDataBuffer(DataBuffer *buffer)
+{
+    mDataBufferLock.unlock();
+}
+
+DataBuffer* BufferManager::get(buffer_handle_t handle)
+{
+    return createDataBuffer(mGrallocModule, handle);
+}
+
+void BufferManager::put(DataBuffer *buffer)
+{
+    delete buffer;
+}
+
+BufferMapper* BufferManager::map(DataBuffer& buffer)
+{
+    bool ret;
+    BufferMapper* mapper;
+
+    CTRACE();
+    Mutex::Autolock _l(mLock);
+    //try to get mapper from pool
+    mapper = mBufferPool->getMapper(buffer.getKey());
+    if (mapper) {
+        // increase mapper ref count
+        mapper->incRef();
+        return mapper;
+    }
+
+    // create a new buffer mapper and add it to pool
+    do {
+        VTRACE("new buffer, will add it");
+        mapper = createBufferMapper(mGrallocModule, buffer);
+        if (!mapper) {
+            ETRACE("failed to allocate mapper");
+            break;
+        }
+        ret = mapper->map();
+        if (!ret) {
+            ETRACE("failed to map");
+            delete mapper;
+            mapper = NULL;
+            break;
+        }
+        ret = mBufferPool->addMapper(buffer.getKey(), mapper);
+        if (!ret) {
+            ETRACE("failed to add mapper");
+            break;
+        }
+        // increase mapper ref count
+        mapper->incRef();
+        return mapper;
+    } while (0);
+
+    // error handling
+    if (mapper) {
+        mapper->unmap();
+        delete mapper;
+    }
+    return NULL;
+}
+
+void BufferManager::unmap(BufferMapper *mapper)
+{
+    Mutex::Autolock _l(mLock);
+    if (!mapper) {
+        ETRACE("invalid mapper");
+        return;
+    }
+
+    // unmap & remove this mapper from buffer when refCount = 0
+    int refCount = mapper->decRef();
+    if (refCount < 0) {
+        ETRACE("invalid ref count");
+    } else if (!refCount) {
+        // remove mapper from buffer pool
+        mBufferPool->removeMapper(mapper);
+        mapper->unmap();
+        delete mapper;
+    }
+}
+
+buffer_handle_t BufferManager::allocFrameBuffer(int width, int height, int *stride)
+{
+    RETURN_NULL_IF_NOT_INIT();
+
+    if (!mAllocDev) {
+        WTRACE("Alloc device is not available");
+        return 0;
+    }
+
+    if (!width || !height || !stride) {
+        ETRACE("invalid input parameter");
+        return 0;
+    }
+
+    ITRACE("size of frame buffer to create: %dx%d", width, height);
+    buffer_handle_t handle = 0;
+    status_t err  = mAllocDev->alloc(
+            mAllocDev,
+            width,
+            height,
+            DrmConfig::getFrameBufferFormat(),
+            0, // GRALLOC_USAGE_HW_FB
+            &handle,
+            stride);
+
+    if (err != 0) {
+        ETRACE("failed to allocate frame buffer, error = %d", err);
+        return 0;
+    }
+
+    DataBuffer *buffer = NULL;
+    BufferMapper *mapper = NULL;
+
+    do {
+        buffer = lockDataBuffer(handle);
+        if (!buffer) {
+            ETRACE("failed to get data buffer, handle = %p", handle);
+            break;
+        }
+
+        mapper = createBufferMapper(mGrallocModule, *buffer);
+        if (!mapper) {
+            ETRACE("failed to create buffer mapper");
+            break;
+        }
+
+        buffer_handle_t fbHandle;
+         if (!(fbHandle = mapper->getFbHandle(0))) {
+             ETRACE("failed to get Fb handle");
+             break;
+         }
+
+        mFrameBuffers.add(fbHandle, mapper);
+        unlockDataBuffer(buffer);
+        return fbHandle;
+    } while (0);
+
+    // error handling, release all allocated resources
+    if (buffer) {
+        unlockDataBuffer(buffer);
+    }
+    if (mapper) {
+        delete mapper;
+    }
+    mAllocDev->free(mAllocDev, handle);
+    return 0;
+}
+
+void BufferManager::freeFrameBuffer(buffer_handle_t fbHandle)
+{
+    RETURN_VOID_IF_NOT_INIT();
+
+    if (!mAllocDev) {
+        WTRACE("Alloc device is not available");
+        return;
+    }
+
+    ssize_t index = mFrameBuffers.indexOfKey(fbHandle);
+    if (index < 0) {
+        ETRACE("invalid kernel handle");
+        return;
+    }
+
+    BufferMapper *mapper = mFrameBuffers.valueAt(index);
+    buffer_handle_t handle = mapper->getHandle();
+    mapper->putFbHandle();
+    delete mapper;
+    mFrameBuffers.removeItem(fbHandle);
+    mAllocDev->free(mAllocDev, handle);
+}
+
+buffer_handle_t BufferManager::allocGrallocBuffer(uint32_t width, uint32_t height, uint32_t format, uint32_t usage)
+{
+    RETURN_NULL_IF_NOT_INIT();
+
+    if (!mAllocDev) {
+        WTRACE("Alloc device is not available");
+        return 0;
+    }
+
+    if (!width || !height) {
+        ETRACE("invalid input parameter");
+        return 0;
+    }
+
+    ITRACE("size of graphic buffer to create: %dx%d", width, height);
+    buffer_handle_t handle = 0;
+    int stride;
+    status_t err  = mAllocDev->alloc(
+                mAllocDev,
+                width,
+                height,
+                format,
+                usage,
+                &handle,
+                &stride);
+    if (err != 0) {
+        ETRACE("failed to allocate gralloc buffer, error = %d", err);
+        return 0;
+    }
+
+    return handle;
+}
+
+void BufferManager::freeGrallocBuffer(buffer_handle_t handle)
+{
+    RETURN_VOID_IF_NOT_INIT();
+    if (!mAllocDev) {
+        WTRACE("Alloc device is not available");
+        return;
+    }
+
+    if (handle)
+        mAllocDev->free(mAllocDev, handle);
+}
+
+} // namespace intel
+} // namespace android
diff --git a/merrifield/common/buffers/GraphicBuffer.cpp b/merrifield/common/buffers/GraphicBuffer.cpp
new file mode 100644
index 0000000..59e8766
--- /dev/null
+++ b/merrifield/common/buffers/GraphicBuffer.cpp
@@ -0,0 +1,77 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#include <HwcTrace.h>
+#include <GraphicBuffer.h>
+
+namespace android {
+namespace intel {
+
+GraphicBuffer::GraphicBuffer(buffer_handle_t handle)
+    : DataBuffer(handle)
+{
+    initBuffer(handle);
+}
+
+void GraphicBuffer::resetBuffer(buffer_handle_t handle)
+{
+    DataBuffer::resetBuffer(handle);
+    initBuffer(handle);
+}
+
+bool GraphicBuffer::isProtectedUsage(uint32_t usage)
+{
+    if (usage == USAGE_INVALID) {
+        return false;
+    }
+
+    return (usage & GRALLOC_USAGE_PROTECTED) != 0;
+}
+
+bool GraphicBuffer::isProtectedBuffer(GraphicBuffer *buffer)
+{
+    if (buffer == NULL) {
+        return false;
+    }
+
+    return isProtectedUsage(buffer->mUsage);
+}
+
+bool GraphicBuffer::isCompressionUsage(uint32_t usage)
+{
+    if (usage == USAGE_INVALID) {
+        return false;
+    }
+
+    return false;
+}
+
+bool GraphicBuffer::isCompressionBuffer(GraphicBuffer *buffer)
+{
+    if (buffer == NULL) {
+        return false;
+    }
+
+    return isCompressionUsage(buffer->mUsage);
+}
+
+void GraphicBuffer::initBuffer(buffer_handle_t handle)
+{
+    mUsage = USAGE_INVALID;
+    mBpp = 0;
+}
+
+}
+}
diff --git a/merrifield/common/devices/ExternalDevice.cpp b/merrifield/common/devices/ExternalDevice.cpp
new file mode 100644
index 0000000..d3de323
--- /dev/null
+++ b/merrifield/common/devices/ExternalDevice.cpp
@@ -0,0 +1,339 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#include <HwcTrace.h>
+#include <Drm.h>
+#include <DrmConfig.h>
+#include <Hwcomposer.h>
+#include <ExternalDevice.h>
+
+namespace android {
+namespace intel {
+
+ExternalDevice::ExternalDevice(Hwcomposer& hwc, DeviceControlFactory* controlFactory)
+    : PhysicalDevice(DEVICE_EXTERNAL, hwc, controlFactory),
+      mHdcpControl(NULL),
+      mAbortModeSettingCond(),
+      mPendingDrmMode(),
+      mHotplugEventPending(false),
+      mExpectedRefreshRate(0)
+{
+    CTRACE();
+}
+
+ExternalDevice::~ExternalDevice()
+{
+    CTRACE();
+}
+
+bool ExternalDevice::initialize()
+{
+    if (!PhysicalDevice::initialize()) {
+        DEINIT_AND_RETURN_FALSE("failed to initialize physical device");
+    }
+
+    mHdcpControl = mControlFactory->createHdcpControl();
+    if (!mHdcpControl) {
+        DEINIT_AND_RETURN_FALSE("failed to create HDCP control");
+    }
+
+    mHotplugEventPending = false;
+    if (mConnected) {
+        mHdcpControl->startHdcpAsync(HdcpLinkStatusListener, this);
+    }
+
+    UeventObserver *observer = Hwcomposer::getInstance().getUeventObserver();
+    if (observer) {
+        observer->registerListener(
+            DrmConfig::getHotplugString(),
+            hotplugEventListener,
+            this);
+    } else {
+        ETRACE("Uevent observer is NULL");
+    }
+    return true;
+}
+
+void ExternalDevice::deinitialize()
+{
+    // abort mode settings if it is in the middle
+    mAbortModeSettingCond.signal();
+    if (mThread.get()) {
+        mThread->join();
+        mThread = NULL;
+    }
+
+    if (mHdcpControl) {
+        mHdcpControl->stopHdcp();
+        delete mHdcpControl;
+        mHdcpControl = 0;
+    }
+
+    mHotplugEventPending = false;
+    PhysicalDevice::deinitialize();
+}
+
+bool ExternalDevice::setDrmMode(drmModeModeInfo& value)
+{
+    if (!mConnected) {
+        WTRACE("external device is not connected");
+        return false;
+    }
+
+    if (mThread.get()) {
+        mThread->join();
+        mThread = NULL;
+    }
+
+    Drm *drm = Hwcomposer::getInstance().getDrm();
+    drmModeModeInfo mode;
+    drm->getModeInfo(mType, mode);
+    if (drm->isSameDrmMode(&value, &mode))
+        return true;
+
+    // any issue here by faking connection status?
+    mConnected = false;
+    mPendingDrmMode = value;
+
+    // setting mode in a working thread
+    mThread = new ModeSettingThread(this);
+    if (!mThread.get()) {
+        ETRACE("failed to create mode settings thread");
+        return false;
+    }
+
+    mThread->run("ModeSettingsThread", PRIORITY_URGENT_DISPLAY);
+    return true;
+}
+
+bool ExternalDevice::threadLoop()
+{
+    // one-time execution
+    setDrmMode();
+    return false;
+}
+
+void ExternalDevice::setDrmMode()
+{
+    ITRACE("start mode setting...");
+
+    Drm *drm = Hwcomposer::getInstance().getDrm();
+
+    mConnected = false;
+    mHwc.hotplug(mType, false);
+
+    {
+        Mutex::Autolock lock(mLock);
+        // TODO: make timeout value flexible, or wait until surface flinger
+        // acknowledges hot unplug event.
+        status_t err = mAbortModeSettingCond.waitRelative(mLock, milliseconds(20));
+        if (err != -ETIMEDOUT) {
+            ITRACE("Mode settings is interrupted");
+            mHwc.hotplug(mType, true);
+            return;
+        }
+    }
+
+    // TODO: potential threading issue with onHotplug callback
+    mHdcpControl->stopHdcp();
+    if (!drm->setDrmMode(mType, mPendingDrmMode)) {
+        ETRACE("failed to set Drm mode");
+        mHwc.hotplug(mType, true);
+        return;
+    }
+
+    if (!PhysicalDevice::updateDisplayConfigs()) {
+        ETRACE("failed to update display configs");
+        mHwc.hotplug(mType, true);
+        return;
+    }
+    mConnected = true;
+    mHotplugEventPending = true;
+    // delay sending hotplug event until HDCP is authenticated
+    if (mHdcpControl->startHdcpAsync(HdcpLinkStatusListener, this) == false) {
+        ETRACE("startHdcpAsync() failed; HDCP is not enabled");
+        mHotplugEventPending = false;
+        mHwc.hotplug(mType, true);
+    }
+    mExpectedRefreshRate = 0;
+}
+
+
+void ExternalDevice::HdcpLinkStatusListener(bool success, void *userData)
+{
+    if (userData == NULL) {
+        return;
+    }
+
+    ExternalDevice *p = (ExternalDevice*)userData;
+    p->HdcpLinkStatusListener(success);
+}
+
+void ExternalDevice::HdcpLinkStatusListener(bool success)
+{
+    if (!success) {
+        ETRACE("HDCP is not authenticated, disabling dynamic vsync");
+        mHwc.getVsyncManager()->enableDynamicVsync(false);
+    }
+
+    if (mHotplugEventPending) {
+        DTRACE("HDCP authentication status %d, sending hotplug event...", success);
+        mHwc.hotplug(mType, mConnected);
+        mHotplugEventPending = false;
+    }
+
+    if (success) {
+        ITRACE("HDCP authenticated, enabling dynamic vsync");
+        mHwc.getVsyncManager()->enableDynamicVsync(true);
+    }
+}
+
+void ExternalDevice::hotplugEventListener(void *data)
+{
+    ExternalDevice *pThis = (ExternalDevice*)data;
+    if (pThis) {
+        pThis->hotplugListener();
+    }
+}
+
+void ExternalDevice::hotplugListener()
+{
+    bool ret;
+
+    CTRACE();
+
+    // abort mode settings if it is in the middle
+    mAbortModeSettingCond.signal();
+
+    // remember the current connection status before detection
+    bool connected = mConnected;
+
+    // detect display configs
+    ret = detectDisplayConfigs();
+    if (ret == false) {
+        ETRACE("failed to detect display config");
+        return;
+    }
+
+    ITRACE("hotpug event: %d", mConnected);
+
+    if (connected == mConnected) {
+        WTRACE("same connection status detected, hotplug event ignored");
+        return;
+    }
+
+    if (mConnected == false) {
+        mHotplugEventPending = false;
+        mHwc.getVsyncManager()->resetVsyncSource();
+        mHdcpControl->stopHdcp();
+        mHwc.hotplug(mType, mConnected);
+    } else {
+        DTRACE("start HDCP asynchronously...");
+         // delay sending hotplug event till HDCP is authenticated.
+        mHotplugEventPending = true;
+        ret = mHdcpControl->startHdcpAsync(HdcpLinkStatusListener, this);
+        if (ret == false) {
+            ETRACE("failed to start HDCP");
+            mHotplugEventPending = false;
+            mHwc.hotplug(mType, mConnected);
+        }
+    }
+    mActiveDisplayConfig = 0;
+}
+
+int ExternalDevice::getRefreshRate()
+{
+    Drm *drm = Hwcomposer::getInstance().getDrm();
+    drmModeModeInfo mode;
+    if (!drm->getModeInfo(IDisplayDevice::DEVICE_EXTERNAL, mode))
+        return 0;
+    return mode.vrefresh;
+}
+
+void ExternalDevice::setRefreshRate(int hz)
+{
+    RETURN_VOID_IF_NOT_INIT();
+
+    ITRACE("setting refresh rate to %d", hz);
+
+    if (mBlank) {
+        WTRACE("external device is blank");
+        return;
+    }
+
+    Drm *drm = Hwcomposer::getInstance().getDrm();
+    drmModeModeInfo mode;
+    if (!drm->getModeInfo(IDisplayDevice::DEVICE_EXTERNAL, mode))
+        return;
+
+    if (hz == 0 && (mode.type & DRM_MODE_TYPE_PREFERRED))
+        return;
+
+    if (hz == (int)mode.vrefresh)
+        return;
+
+    if (mExpectedRefreshRate != 0 &&
+            mExpectedRefreshRate == hz && mHotplugEventPending) {
+        ITRACE("Ignore a new refresh setting event because there is a same event is handling");
+        return;
+    }
+    mExpectedRefreshRate = hz;
+
+    ITRACE("changing refresh rate from %d to %d", mode.vrefresh, hz);
+
+    mHwc.getVsyncManager()->enableDynamicVsync(false);
+
+    mHdcpControl->stopHdcp();
+
+    drm->setRefreshRate(IDisplayDevice::DEVICE_EXTERNAL, hz);
+
+    mHotplugEventPending = false;
+    mHdcpControl->startHdcpAsync(HdcpLinkStatusListener, this);
+    mHwc.getVsyncManager()->enableDynamicVsync(true);
+}
+
+int ExternalDevice::getActiveConfig()
+{
+    if (!mConnected) {
+        return 0;
+    }
+    return mActiveDisplayConfig;
+}
+
+bool ExternalDevice::setActiveConfig(int index)
+{
+    if (!mConnected) {
+        if (index == 0)
+            return true;
+        else
+            return false;
+    }
+
+    // for now we will only permit the frequency change.  In the future
+    // we may need to set mode as well.
+    if (index >= 0 && index < static_cast<int>(mDisplayConfigs.size())) {
+        DisplayConfig *config = mDisplayConfigs.itemAt(index);
+        setRefreshRate(config->getRefreshRate());
+        mActiveDisplayConfig = index;
+        return true;
+    } else {
+        return false;
+    }
+    return true;
+}
+
+} // namespace intel
+} // namespace android
diff --git a/merrifield/common/devices/PhysicalDevice.cpp b/merrifield/common/devices/PhysicalDevice.cpp
new file mode 100644
index 0000000..a7e52cd
--- /dev/null
+++ b/merrifield/common/devices/PhysicalDevice.cpp
@@ -0,0 +1,542 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#include <HwcTrace.h>
+#include <Hwcomposer.h>
+#include <Drm.h>
+#include <PhysicalDevice.h>
+
+namespace android {
+namespace intel {
+
+PhysicalDevice::PhysicalDevice(uint32_t type, Hwcomposer& hwc, DeviceControlFactory* controlFactory)
+    : mType(type),
+      mHwc(hwc),
+      mActiveDisplayConfig(-1),
+      mBlankControl(NULL),
+      mVsyncObserver(NULL),
+      mControlFactory(controlFactory),
+      mLayerList(NULL),
+      mConnected(false),
+      mBlank(false),
+      mDisplayState(DEVICE_DISPLAY_ON),
+      mInitialized(false)
+{
+    CTRACE();
+
+    switch (type) {
+    case DEVICE_PRIMARY:
+        mName = "Primary";
+        break;
+    case DEVICE_EXTERNAL:
+        mName = "External";
+        break;
+    default:
+        mName = "Unknown";
+    }
+
+    mDisplayConfigs.setCapacity(DEVICE_COUNT);
+}
+
+PhysicalDevice::~PhysicalDevice()
+{
+    WARN_IF_NOT_DEINIT();
+}
+
+void PhysicalDevice::onGeometryChanged(hwc_display_contents_1_t *list)
+{
+    if (!list) {
+        ETRACE("list is NULL");
+        return;
+    }
+
+    ATRACE("disp = %d, layer number = %d", mType, list->numHwLayers);
+
+    // NOTE: should NOT be here
+    if (mLayerList) {
+        WTRACE("mLayerList exists");
+        DEINIT_AND_DELETE_OBJ(mLayerList);
+    }
+
+    // create a new layer list
+    mLayerList = new HwcLayerList(list, mType);
+    if (!mLayerList) {
+        WTRACE("failed to create layer list");
+    }
+}
+
+bool PhysicalDevice::prePrepare(hwc_display_contents_1_t *display)
+{
+    RETURN_FALSE_IF_NOT_INIT();
+    Mutex::Autolock _l(mLock);
+
+    // for a null list, delete hwc list
+    if (!mConnected || !display || mBlank) {
+        if (mLayerList) {
+            DEINIT_AND_DELETE_OBJ(mLayerList);
+        }
+        return true;
+    }
+
+    // check if geometry is changed, if changed delete list
+    if ((display->flags & HWC_GEOMETRY_CHANGED) && mLayerList) {
+        DEINIT_AND_DELETE_OBJ(mLayerList);
+    }
+    return true;
+}
+
+bool PhysicalDevice::prepare(hwc_display_contents_1_t *display)
+{
+    RETURN_FALSE_IF_NOT_INIT();
+    Mutex::Autolock _l(mLock);
+
+    if (!mConnected || !display || mBlank)
+        return true;
+
+    // check if geometry is changed
+    if (display->flags & HWC_GEOMETRY_CHANGED) {
+        onGeometryChanged(display);
+    }
+    if (!mLayerList) {
+        WTRACE("null HWC layer list");
+        return true;
+    }
+
+    // update list with new list
+    return mLayerList->update(display);
+}
+
+
+bool PhysicalDevice::commit(hwc_display_contents_1_t *display, IDisplayContext *context)
+{
+    RETURN_FALSE_IF_NOT_INIT();
+
+    if (!display || !context || !mLayerList || mBlank) {
+        return true;
+    }
+    return context->commitContents(display, mLayerList);
+}
+
+bool PhysicalDevice::vsyncControl(bool enabled)
+{
+    RETURN_FALSE_IF_NOT_INIT();
+
+    ATRACE("disp = %d, enabled = %d", mType, enabled);
+    return mVsyncObserver->control(enabled);
+}
+
+bool PhysicalDevice::blank(bool blank)
+{
+    RETURN_FALSE_IF_NOT_INIT();
+
+    if (!mConnected)
+        return false;
+
+    mBlank = blank;
+    bool ret = mBlankControl->blank(mType, blank);
+    if (ret == false) {
+        ETRACE("failed to blank device");
+        return false;
+    }
+
+    return true;
+}
+
+bool PhysicalDevice::getDisplaySize(int *width, int *height)
+{
+    RETURN_FALSE_IF_NOT_INIT();
+    Mutex::Autolock _l(mLock);
+    if (!width || !height) {
+        ETRACE("invalid parameters");
+        return false;
+    }
+
+    *width = 0;
+    *height = 0;
+    drmModeModeInfo mode;
+    Drm *drm = Hwcomposer::getInstance().getDrm();
+    bool ret = drm->getModeInfo(mType, mode);
+    if (!ret) {
+        return false;
+    }
+
+    *width = mode.hdisplay;
+    *height = mode.vdisplay;
+    return true;
+}
+
+template <typename T>
+static inline T min(T a, T b) {
+    return a<b ? a : b;
+}
+
+bool PhysicalDevice::getDisplayConfigs(uint32_t *configs,
+                                         size_t *numConfigs)
+{
+    RETURN_FALSE_IF_NOT_INIT();
+
+    Mutex::Autolock _l(mLock);
+
+    if (!mConnected) {
+        ITRACE("device is not connected");
+        return false;
+    }
+
+    if (!configs || !numConfigs || *numConfigs < 1) {
+        ETRACE("invalid parameters");
+        return false;
+    }
+
+    // fill in all config handles
+    *numConfigs = min(*numConfigs, mDisplayConfigs.size());
+    for (int i = 0; i < static_cast<int>(*numConfigs); i++) {
+        configs[i] = i;
+    }
+
+    return true;
+}
+bool PhysicalDevice::getDisplayAttributes(uint32_t config,
+                                            const uint32_t *attributes,
+                                            int32_t *values)
+{
+    RETURN_FALSE_IF_NOT_INIT();
+
+    Mutex::Autolock _l(mLock);
+
+    if (!mConnected) {
+        ITRACE("device is not connected");
+        return false;
+    }
+
+    if (!attributes || !values) {
+        ETRACE("invalid parameters");
+        return false;
+    }
+
+    DisplayConfig *configChosen = mDisplayConfigs.itemAt(config);
+    if  (!configChosen) {
+        WTRACE("failed to get display config");
+        return false;
+    }
+
+    int i = 0;
+    while (attributes[i] != HWC_DISPLAY_NO_ATTRIBUTE) {
+        switch (attributes[i]) {
+        case HWC_DISPLAY_VSYNC_PERIOD:
+            if (configChosen->getRefreshRate()) {
+                values[i] = 1e9 / configChosen->getRefreshRate();
+            } else {
+                ETRACE("refresh rate is 0!!!");
+                values[i] = 0;
+            }
+            break;
+        case HWC_DISPLAY_WIDTH:
+            values[i] = configChosen->getWidth();
+            break;
+        case HWC_DISPLAY_HEIGHT:
+            values[i] = configChosen->getHeight();
+            break;
+        case HWC_DISPLAY_DPI_X:
+            values[i] = configChosen->getDpiX() * 1000.0f;
+            break;
+        case HWC_DISPLAY_DPI_Y:
+            values[i] = configChosen->getDpiY() * 1000.0f;
+            break;
+        default:
+            ETRACE("unknown attribute %d", attributes[i]);
+            break;
+        }
+        i++;
+    }
+
+    return true;
+}
+
+bool PhysicalDevice::compositionComplete()
+{
+    CTRACE();
+    // do nothing by default
+    return true;
+}
+
+void PhysicalDevice::removeDisplayConfigs()
+{
+    for (size_t i = 0; i < mDisplayConfigs.size(); i++) {
+        DisplayConfig *config = mDisplayConfigs.itemAt(i);
+        delete config;
+    }
+
+    mDisplayConfigs.clear();
+    mActiveDisplayConfig = -1;
+}
+
+bool PhysicalDevice::detectDisplayConfigs()
+{
+    Mutex::Autolock _l(mLock);
+
+    Drm *drm = Hwcomposer::getInstance().getDrm();
+    if (!drm->detect(mType)) {
+        ETRACE("drm detection on device %d failed ", mType);
+        return false;
+    }
+    return updateDisplayConfigs();
+}
+
+bool PhysicalDevice::updateDisplayConfigs()
+{
+    bool ret;
+    Drm *drm = Hwcomposer::getInstance().getDrm();
+
+    // reset display configs
+    removeDisplayConfigs();
+
+    // update device connection status
+    mConnected = drm->isConnected(mType);
+    if (!mConnected) {
+        return true;
+    }
+
+    // reset the number of display configs
+    mDisplayConfigs.setCapacity(1);
+
+    drmModeModeInfo mode;
+    ret = drm->getModeInfo(mType, mode);
+    if (!ret) {
+        ETRACE("failed to get mode info");
+        mConnected = false;
+        return false;
+    }
+
+    uint32_t mmWidth, mmHeight;
+    ret = drm->getPhysicalSize(mType, mmWidth, mmHeight);
+    if (!ret) {
+        ETRACE("failed to get physical size");
+        mConnected = false;
+        return false;
+    }
+
+    float physWidthInch = (float)mmWidth * 0.039370f;
+    float physHeightInch = (float)mmHeight * 0.039370f;
+
+    // use current drm mode, likely it's preferred mode
+    int dpiX = 0;
+    int dpiY = 0;
+    if (physWidthInch && physHeightInch) {
+        dpiX = mode.hdisplay / physWidthInch;
+        dpiY = mode.vdisplay / physHeightInch;
+    } else {
+        ETRACE("invalid physical size, EDID read error?");
+        // don't bail out as it is not a fatal error
+    }
+    // use active fb dimension as config width/height
+    DisplayConfig *config = new DisplayConfig(mode.vrefresh,
+                                              mode.hdisplay,
+                                              mode.vdisplay,
+                                              dpiX, dpiY);
+    // add it to the front of other configs
+    mDisplayConfigs.push_front(config);
+
+    // init the active display config
+    mActiveDisplayConfig = 0;
+
+    drmModeModeInfoPtr modes;
+    drmModeModeInfoPtr compatMode;
+    int modeCount = 0;
+
+    modes = drm->detectAllConfigs(mType, &modeCount);
+
+    for (int i = 0; i < modeCount; i++) {
+        if (modes) {
+            compatMode = &modes[i];
+            if (!compatMode)
+                continue;
+            if (compatMode->hdisplay == mode.hdisplay &&
+                compatMode->vdisplay == mode.vdisplay &&
+                compatMode->vrefresh != mode.vrefresh) {
+
+                bool found = false;
+                for (size_t j = 0; j < mDisplayConfigs.size(); j++) {
+                     DisplayConfig *config = mDisplayConfigs.itemAt(j);
+                     if (config->getRefreshRate() == (int)compatMode->vrefresh) {
+                         found = true;
+                         break;
+                     }
+                }
+
+                if (found) {
+                    continue;
+                }
+
+                DisplayConfig *config = new DisplayConfig(compatMode->vrefresh,
+                                              compatMode->hdisplay,
+                                              compatMode->vdisplay,
+                                              dpiX, dpiY);
+                // add it to the end of configs
+                mDisplayConfigs.push_back(config);
+            }
+        }
+    }
+
+    return true;
+}
+
+bool PhysicalDevice::initialize()
+{
+    CTRACE();
+
+    if (mType != DEVICE_PRIMARY && mType != DEVICE_EXTERNAL) {
+        ETRACE("invalid device type");
+        return false;
+    }
+
+    // detect display configs
+    bool ret = detectDisplayConfigs();
+    if (ret == false) {
+        DEINIT_AND_RETURN_FALSE("failed to detect display config");
+    }
+
+    if (!mControlFactory) {
+        DEINIT_AND_RETURN_FALSE("failed to provide a controlFactory ");
+    }
+
+    // create blank control
+    mBlankControl = mControlFactory->createBlankControl();
+    if (!mBlankControl) {
+        DEINIT_AND_RETURN_FALSE("failed to create blank control");
+    }
+
+    // create vsync event observer
+    mVsyncObserver = new VsyncEventObserver(*this);
+    if (!mVsyncObserver || !mVsyncObserver->initialize()) {
+        DEINIT_AND_RETURN_FALSE("failed to create vsync observer");
+    }
+
+    mInitialized = true;
+    return true;
+}
+
+void PhysicalDevice::deinitialize()
+{
+    Mutex::Autolock _l(mLock);
+    if (mLayerList) {
+        DEINIT_AND_DELETE_OBJ(mLayerList);
+    }
+
+    DEINIT_AND_DELETE_OBJ(mVsyncObserver);
+
+    // destroy blank control
+    if (mBlankControl) {
+        delete mBlankControl;
+        mBlankControl = 0;
+    }
+
+    if (mControlFactory){
+        delete mControlFactory;
+        mControlFactory = 0;
+    }
+
+    // remove configs
+    removeDisplayConfigs();
+
+    mInitialized = false;
+}
+
+bool PhysicalDevice::isConnected() const
+{
+    RETURN_FALSE_IF_NOT_INIT();
+
+    return mConnected;
+}
+
+const char* PhysicalDevice::getName() const
+{
+    return mName;
+}
+
+int PhysicalDevice::getType() const
+{
+    return mType;
+}
+
+void PhysicalDevice::onVsync(int64_t timestamp)
+{
+    RETURN_VOID_IF_NOT_INIT();
+    ATRACE("timestamp = %lld", timestamp);
+
+    if (!mConnected)
+        return;
+
+    // notify hwc
+    mHwc.vsync(mType, timestamp);
+}
+
+void PhysicalDevice::dump(Dump& d)
+{
+    Mutex::Autolock _l(mLock);
+    d.append("-------------------------------------------------------------\n");
+    d.append("Device Name: %s (%s)\n", mName,
+            mConnected ? "connected" : "disconnected");
+    d.append("Display configs (count = %d):\n", mDisplayConfigs.size());
+    d.append(" CONFIG | VSYNC_PERIOD | WIDTH | HEIGHT | DPI_X | DPI_Y \n");
+    d.append("--------+--------------+-------+--------+-------+-------\n");
+    for (size_t i = 0; i < mDisplayConfigs.size(); i++) {
+        DisplayConfig *config = mDisplayConfigs.itemAt(i);
+        if (config) {
+            d.append("%s %2d   |     %4d     | %5d |  %4d  |  %3d  |  %3d  \n",
+                     (i == (size_t)mActiveDisplayConfig) ? "* " : "  ",
+                     i,
+                     config->getRefreshRate(),
+                     config->getWidth(),
+                     config->getHeight(),
+                     config->getDpiX(),
+                     config->getDpiY());
+        }
+    }
+    // dump layer list
+    if (mLayerList)
+        mLayerList->dump(d);
+}
+
+bool PhysicalDevice::setPowerMode(int mode)
+{
+    // TODO: set proper blanking modes for HWC 1.4 modes
+    switch (mode) {
+        case HWC_POWER_MODE_OFF:
+        case HWC_POWER_MODE_DOZE:
+            return blank(true);
+        case HWC_POWER_MODE_NORMAL:
+        case HWC_POWER_MODE_DOZE_SUSPEND:
+            return blank(false);
+        default:
+            return false;
+    }
+    return false;
+}
+
+int PhysicalDevice::getActiveConfig()
+{
+    return mActiveDisplayConfig;
+}
+
+bool PhysicalDevice::setActiveConfig(int index)
+{
+    // TODO: for now only implement in external
+    if (index == 0)
+        return true;
+    return false;
+}
+
+} // namespace intel
+} // namespace android
diff --git a/merrifield/common/devices/PrimaryDevice.cpp b/merrifield/common/devices/PrimaryDevice.cpp
new file mode 100644
index 0000000..4c39f1e
--- /dev/null
+++ b/merrifield/common/devices/PrimaryDevice.cpp
@@ -0,0 +1,84 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#include <HwcTrace.h>
+#include <Drm.h>
+#include <Hwcomposer.h>
+#include <DrmConfig.h>
+#include <PrimaryDevice.h>
+
+namespace android {
+namespace intel {
+
+PrimaryDevice::PrimaryDevice(Hwcomposer& hwc, DeviceControlFactory* controlFactory)
+    : PhysicalDevice(DEVICE_PRIMARY, hwc, controlFactory)
+{
+    CTRACE();
+}
+
+PrimaryDevice::~PrimaryDevice()
+{
+    CTRACE();
+}
+
+bool PrimaryDevice::initialize()
+{
+    if (!PhysicalDevice::initialize()) {
+        DEINIT_AND_RETURN_FALSE("failed to initialize physical device");
+    }
+
+    UeventObserver *observer = Hwcomposer::getInstance().getUeventObserver();
+    if (observer) {
+        observer->registerListener(
+            DrmConfig::getRepeatedFrameString(),
+            repeatedFrameEventListener,
+            this);
+    } else {
+        ETRACE("Uevent observer is NULL");
+    }
+
+    return true;
+}
+
+void PrimaryDevice::deinitialize()
+{
+    PhysicalDevice::deinitialize();
+}
+
+
+void PrimaryDevice::repeatedFrameEventListener(void *data)
+{
+    PrimaryDevice *pThis = (PrimaryDevice*)data;
+    if (pThis) {
+        pThis->repeatedFrameListener();
+    }
+}
+
+void PrimaryDevice::repeatedFrameListener()
+{
+    Hwcomposer::getInstance().getDisplayAnalyzer()->postIdleEntryEvent();
+    Hwcomposer::getInstance().invalidate();
+}
+
+bool PrimaryDevice::blank(bool blank)
+{
+    if (!mConnected)
+        return true;
+
+    return PhysicalDevice::blank(blank);
+}
+
+} // namespace intel
+} // namespace android
diff --git a/merrifield/common/devices/VirtualDevice.cpp b/merrifield/common/devices/VirtualDevice.cpp
new file mode 100755
index 0000000..a4396d7
--- /dev/null
+++ b/merrifield/common/devices/VirtualDevice.cpp
@@ -0,0 +1,2288 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#include <HwcTrace.h>
+#include <Hwcomposer.h>
+#include <DisplayPlaneManager.h>
+#include <DisplayQuery.h>
+#include <VirtualDevice.h>
+#include <SoftVsyncObserver.h>
+
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+
+#include <hal_public.h>
+#include <libsync/sw_sync.h>
+#include <sync/sync.h>
+
+#include <va/va_android.h>
+#include <va/va_vpp.h>
+#include <va/va_tpi.h>
+
+#include <cutils/properties.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#define NUM_CSC_BUFFERS 6
+#define NUM_SCALING_BUFFERS 3
+
+#define QCIF_WIDTH 176
+#define QCIF_HEIGHT 144
+
+namespace android {
+namespace intel {
+
+static inline uint32_t align_width(uint32_t val)
+{
+    return align_to(val, 64);
+}
+
+static inline uint32_t align_height(uint32_t val)
+{
+    return align_to(val, 16);
+}
+
+static void my_close_fence(const char* func, const char* fenceName, int& fenceFd)
+{
+    if (fenceFd != -1) {
+        ALOGV("%s: closing fence %s (fd=%d)", func, fenceName, fenceFd);
+        int err = close(fenceFd);
+        if (err < 0) {
+            ALOGE("%s: fence %s close error %d: %s", func, fenceName, err, strerror(errno));
+        }
+        fenceFd = -1;
+    }
+}
+
+static void my_sync_wait_and_close(const char* func, const char* fenceName, int& fenceFd)
+{
+    if (fenceFd != -1) {
+        ALOGV("%s: waiting on fence %s (fd=%d)", func, fenceName, fenceFd);
+        int err = sync_wait(fenceFd, 300);
+        if (err < 0) {
+            ALOGE("%s: fence %s sync_wait error %d: %s", func, fenceName, err, strerror(errno));
+        }
+        my_close_fence(func, fenceName, fenceFd);
+    }
+}
+
+static void my_timeline_inc(const char* func, const char* timelineName, int& syncTimelineFd)
+{
+    if (syncTimelineFd != -1) {
+        ALOGV("%s: incrementing timeline %s (fd=%d)", func, timelineName, syncTimelineFd);
+        int err = sw_sync_timeline_inc(syncTimelineFd, 1);
+        if (err < 0)
+            ALOGE("%s sync timeline %s increment error %d: %s", func, timelineName, errno, strerror(errno));
+        syncTimelineFd = -1;
+    }
+}
+
+#define CLOSE_FENCE(fenceName)          my_close_fence(__func__, #fenceName, fenceName)
+#define SYNC_WAIT_AND_CLOSE(fenceName)  my_sync_wait_and_close(__func__, #fenceName, fenceName)
+#define TIMELINE_INC(timelineName)      my_timeline_inc(__func__, #timelineName, timelineName)
+
+class MappedSurface {
+public:
+    MappedSurface(VADisplay dpy, VASurfaceID surf)
+        : va_dpy(dpy),
+          ptr(NULL)
+    {
+        VAStatus va_status;
+        va_status = vaDeriveImage(va_dpy, surf, &image);
+        if (va_status != VA_STATUS_SUCCESS) {
+            ETRACE("vaDeriveImage returns %08x", va_status);
+            return;
+        }
+        va_status = vaMapBuffer(va_dpy, image.buf, (void**)&ptr);
+        if (va_status != VA_STATUS_SUCCESS) {
+            ETRACE("vaMapBuffer returns %08x", va_status);
+            vaDestroyImage(va_dpy, image.image_id);
+            return;
+        }
+    }
+    ~MappedSurface() {
+        if (ptr == NULL)
+            return;
+
+        VAStatus va_status;
+
+        va_status = vaUnmapBuffer(va_dpy, image.buf);
+        if (va_status != VA_STATUS_SUCCESS) ETRACE("vaUnmapBuffer returns %08x", va_status);
+
+        va_status = vaDestroyImage(va_dpy, image.image_id);
+        if (va_status != VA_STATUS_SUCCESS) ETRACE("vaDestroyImage returns %08x", va_status);
+    }
+    bool valid() { return ptr != NULL; }
+    uint8_t* getPtr() { return ptr; }
+private:
+    VADisplay va_dpy;
+    VAImage image;
+    uint8_t* ptr;
+};
+
+class VirtualDevice::VAMappedHandle {
+public:
+    VAMappedHandle(VADisplay dpy, buffer_handle_t handle, uint32_t stride, uint32_t height, unsigned int pixel_format)
+        : va_dpy(dpy),
+          surface(0)
+    {
+        VTRACE("Map gralloc %p size=%ux%u", handle, stride, height);
+
+        unsigned int format;
+        unsigned long buffer = reinterpret_cast<unsigned long>(handle);
+        VASurfaceAttribExternalBuffers buf;
+        buf.pixel_format = pixel_format;
+        buf.width = stride;
+        buf.height = height;
+        buf.buffers = &buffer;
+        buf.num_buffers = 1;
+        buf.flags = 0;
+        buf.private_data = NULL;
+
+        if (pixel_format == VA_FOURCC_RGBA || pixel_format == VA_FOURCC_BGRA) {
+            format = VA_RT_FORMAT_RGB32;
+            buf.data_size = stride * height * 4;
+            buf.num_planes = 3;
+            buf.pitches[0] = stride;
+            buf.pitches[1] = stride;
+            buf.pitches[2] = stride;
+            buf.pitches[3] = 0;
+            buf.offsets[0] = 0;
+            buf.offsets[1] = 0;
+            buf.offsets[2] = 0;
+            buf.offsets[3] = 0;
+        }
+        else {
+            format = VA_RT_FORMAT_YUV420;
+            buf.data_size = stride * height * 3/2;
+            buf.num_planes = 2;
+            buf.pitches[0] = stride;
+            buf.pitches[1] = stride;
+            buf.pitches[2] = 0;
+            buf.pitches[3] = 0;
+            buf.offsets[0] = 0;
+            buf.offsets[1] = stride * height;
+        }
+
+        VASurfaceAttrib attrib_list[3];
+        attrib_list[0].type = (VASurfaceAttribType)VASurfaceAttribMemoryType;
+        attrib_list[0].flags = VA_SURFACE_ATTRIB_SETTABLE;
+        attrib_list[0].value.type = VAGenericValueTypeInteger;
+        attrib_list[0].value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_ANDROID_GRALLOC;
+        attrib_list[1].type = (VASurfaceAttribType)VASurfaceAttribExternalBufferDescriptor;
+        attrib_list[1].flags = VA_SURFACE_ATTRIB_SETTABLE;
+        attrib_list[1].value.type = VAGenericValueTypePointer;
+        attrib_list[1].value.value.p = (void *)&buf;
+        attrib_list[2].type = (VASurfaceAttribType)VASurfaceAttribPixelFormat;
+        attrib_list[2].flags = VA_SURFACE_ATTRIB_SETTABLE;
+        attrib_list[2].value.type = VAGenericValueTypeInteger;
+        attrib_list[2].value.value.i = pixel_format;
+
+        VAStatus va_status;
+        va_status = vaCreateSurfaces(va_dpy,
+                    format,
+                    stride,
+                    height,
+                    &surface,
+                    1,
+                    attrib_list,
+                    3);
+        if (va_status != VA_STATUS_SUCCESS) {
+            ETRACE("vaCreateSurfaces returns %08x, surface = %x", va_status, surface);
+            surface = 0;
+        }
+    }
+    VAMappedHandle(VADisplay dpy, buffer_handle_t khandle, uint32_t stride, uint32_t height, bool tiled)
+        : va_dpy(dpy),
+          surface(0)
+    {
+        int format;
+        VASurfaceAttributeTPI attribTpi;
+        memset(&attribTpi, 0, sizeof(attribTpi));
+        VTRACE("Map khandle 0x%x size=%ux%u", khandle, stride, height);
+        attribTpi.type = VAExternalMemoryKernelDRMBufffer;
+        attribTpi.width = stride;
+        attribTpi.height = height;
+        attribTpi.size = stride*height*3/2;
+        attribTpi.pixel_format = VA_FOURCC_NV12;
+        attribTpi.tiling = tiled;
+        attribTpi.luma_stride = stride;
+        attribTpi.chroma_u_stride = stride;
+        attribTpi.chroma_v_stride = stride;
+        attribTpi.luma_offset = 0;
+        attribTpi.chroma_u_offset = stride*height;
+        attribTpi.chroma_v_offset = stride*height+1;
+        format = VA_RT_FORMAT_YUV420;
+        attribTpi.count = 1;
+        attribTpi.buffers = (long unsigned int*) &khandle;
+
+        VAStatus va_status;
+        va_status = vaCreateSurfacesWithAttribute(va_dpy,
+                    stride,
+                    height,
+                    format,
+                    1,
+                    &surface,
+                    &attribTpi);
+        if (va_status != VA_STATUS_SUCCESS) {
+            ETRACE("vaCreateSurfacesWithAttribute returns %08x", va_status);
+            surface = 0;
+        }
+    }
+    ~VAMappedHandle()
+    {
+        if (surface == 0)
+            return;
+        VAStatus va_status;
+        va_status = vaDestroySurfaces(va_dpy, &surface, 1);
+        if (va_status != VA_STATUS_SUCCESS) ETRACE("vaDestroySurfaces returns %08x", va_status);
+    }
+private:
+    VADisplay va_dpy;
+public:
+    VASurfaceID surface;
+};
+
+// refcounted version of VAMappedHandle, to make caching easier
+class VirtualDevice::VAMappedHandleObject : public RefBase, public VAMappedHandle {
+public:
+    VAMappedHandleObject(VADisplay dpy, buffer_handle_t handle, uint32_t stride, uint32_t height, unsigned int pixel_format)
+        : VAMappedHandle(dpy, handle, stride, height, pixel_format) { }
+    VAMappedHandleObject(VADisplay dpy, buffer_handle_t khandle, uint32_t stride, uint32_t height, bool tiled)
+        : VAMappedHandle(dpy, khandle, stride, height, tiled) { }
+protected:
+    ~VAMappedHandleObject() {}
+};
+
+VirtualDevice::CachedBuffer::CachedBuffer(BufferManager *mgr, buffer_handle_t handle)
+    : manager(mgr),
+      mapper(NULL),
+      vaMappedHandle(NULL),
+      cachedKhandle(0)
+{
+    DataBuffer *buffer = manager->lockDataBuffer((buffer_handle_t)handle);
+    mapper = manager->map(*buffer);
+    manager->unlockDataBuffer(buffer);
+}
+
+VirtualDevice::CachedBuffer::~CachedBuffer()
+{
+    if (vaMappedHandle != NULL)
+        delete vaMappedHandle;
+    manager->unmap(mapper);
+}
+
+VirtualDevice::HeldDecoderBuffer::HeldDecoderBuffer(const sp<VirtualDevice>& vd, const android::sp<CachedBuffer>& cachedBuffer)
+    : vd(vd),
+      cachedBuffer(cachedBuffer)
+{
+    if (!vd->mPayloadManager->setRenderStatus(cachedBuffer->mapper, true)) {
+        ETRACE("Failed to set render status");
+    }
+}
+
+VirtualDevice::HeldDecoderBuffer::~HeldDecoderBuffer()
+{
+    if (!vd->mPayloadManager->setRenderStatus(cachedBuffer->mapper, false)) {
+        ETRACE("Failed to set render status");
+    }
+}
+
+struct VirtualDevice::Task : public RefBase {
+    virtual void run(VirtualDevice& vd) = 0;
+    virtual ~Task() {}
+};
+
+struct VirtualDevice::RenderTask : public VirtualDevice::Task {
+    RenderTask() : successful(false) { }
+    virtual void run(VirtualDevice& vd) = 0;
+    bool successful;
+};
+
+struct VirtualDevice::ComposeTask : public VirtualDevice::RenderTask {
+    ComposeTask()
+        : videoKhandle(0),
+          rgbHandle(NULL),
+          mappedRgbIn(NULL),
+          outputHandle(NULL),
+          yuvAcquireFenceFd(-1),
+          rgbAcquireFenceFd(-1),
+          outbufAcquireFenceFd(-1),
+          syncTimelineFd(-1) { }
+
+    virtual ~ComposeTask() {
+        // If queueCompose() creates this object and sets up fences,
+        // but aborts before enqueuing the task, or if the task runs
+        // but errors out, make sure our acquire fences get closed
+        // and any release fences get signaled.
+        CLOSE_FENCE(yuvAcquireFenceFd);
+        CLOSE_FENCE(rgbAcquireFenceFd);
+        CLOSE_FENCE(outbufAcquireFenceFd);
+        TIMELINE_INC(syncTimelineFd);
+    }
+
+    virtual void run(VirtualDevice& vd) {
+        bool dump = false;
+        if (vd.mDebugVspDump && ++vd.mDebugCounter > 200) {
+            dump = true;
+            vd.mDebugCounter = 0;
+        }
+
+        SYNC_WAIT_AND_CLOSE(yuvAcquireFenceFd);
+
+        VASurfaceID videoInSurface;
+        if (videoKhandle == 0) {
+            videoInSurface = vd.va_blank_yuv_in;
+        } else {
+            if (videoCachedBuffer->cachedKhandle != videoKhandle || videoCachedBuffer->vaMappedHandle == NULL) {
+                if (videoCachedBuffer->vaMappedHandle != NULL)
+                    delete videoCachedBuffer->vaMappedHandle;
+                videoCachedBuffer->vaMappedHandle = new VAMappedHandle(vd.va_dpy, videoKhandle, videoStride, videoBufHeight, videoTiled);
+                videoCachedBuffer->cachedKhandle = videoKhandle;
+            }
+            videoInSurface = videoCachedBuffer->vaMappedHandle->surface;
+        }
+
+        if (videoInSurface == 0) {
+            ETRACE("Couldn't map video");
+            return;
+        }
+        SYNC_WAIT_AND_CLOSE(rgbAcquireFenceFd);
+        SYNC_WAIT_AND_CLOSE(outbufAcquireFenceFd);
+
+        VAMappedHandle mappedVideoOut(vd.va_dpy, outputHandle, align_width(outWidth), align_height(outHeight), (unsigned int)VA_FOURCC_NV12);
+        if (mappedVideoOut.surface == 0) {
+            ETRACE("Unable to map outbuf");
+            return;
+        }
+
+        if (dump)
+            dumpSurface(vd.va_dpy, "/data/misc/vsp_in.yuv", videoInSurface, videoStride*videoBufHeight*3/2);
+
+        if (mappedRgbIn != NULL) {
+            if (dump)
+                dumpSurface(vd.va_dpy, "/data/misc/vsp_in.rgb", mappedRgbIn->surface, align_width(outWidth)*align_height(outHeight)*4);
+            vd.vspCompose(videoInSurface, mappedRgbIn->surface, mappedVideoOut.surface, &surface_region, &output_region);
+        }
+        else if (rgbHandle != NULL) {
+            VAMappedHandle localMappedRgbIn(vd.va_dpy, rgbHandle, align_width(outWidth), align_height(outHeight), (unsigned int)VA_FOURCC_BGRA);
+            vd.vspCompose(videoInSurface, localMappedRgbIn.surface, mappedVideoOut.surface, &surface_region, &output_region);
+        }
+        else {
+            // No RGBA, so compose with 100% transparent RGBA frame.
+            if (dump)
+                dumpSurface(vd.va_dpy, "/data/misc/vsp_in.rgb", vd.va_blank_rgb_in, align_width(outWidth)*align_height(outHeight)*4);
+            vd.vspCompose(videoInSurface, vd.va_blank_rgb_in, mappedVideoOut.surface, &surface_region, &output_region);
+        }
+        if (dump)
+            dumpSurface(vd.va_dpy, "/data/misc/vsp_out.yuv", mappedVideoOut.surface, align_width(outWidth)*align_height(outHeight)*3/2);
+        TIMELINE_INC(syncTimelineFd);
+        successful = true;
+    }
+    void dumpSurface(VADisplay va_dpy, const char* filename, VASurfaceID surf, int size) {
+        MappedSurface dumpSurface(va_dpy, surf);
+        if (dumpSurface.valid()) {
+            int fd = open(filename, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
+            if (fd > 0) {
+                write(fd, dumpSurface.getPtr(), size);
+                close(fd);
+                ALOGI("Output dumped");
+            }
+            else
+                ALOGE("Error %d opening output file: %s", errno, strerror(errno));
+        }
+        else
+            ALOGE("Failed to map output for dump");
+    }
+    buffer_handle_t videoKhandle;
+    uint32_t videoStride;
+    uint32_t videoBufHeight;
+    bool videoTiled;
+    buffer_handle_t rgbHandle;
+    sp<RefBase> heldRgbHandle;
+    sp<VAMappedHandleObject> mappedRgbIn;
+    buffer_handle_t outputHandle;
+    VARectangle surface_region;
+    VARectangle output_region;
+    uint32_t outWidth;
+    uint32_t outHeight;
+    sp<CachedBuffer> videoCachedBuffer;
+    sp<RefBase> heldVideoBuffer;
+    int yuvAcquireFenceFd;
+    int rgbAcquireFenceFd;
+    int outbufAcquireFenceFd;
+    int syncTimelineFd;
+};
+
+struct VirtualDevice::EnableVspTask : public VirtualDevice::Task {
+    virtual void run(VirtualDevice& vd) {
+        vd.vspEnable(width, height);
+    }
+    uint32_t width;
+    uint32_t height;
+};
+
+struct VirtualDevice::DisableVspTask : public VirtualDevice::Task {
+    virtual void run(VirtualDevice& vd) {
+        vd.vspDisable();
+    }
+};
+
+struct VirtualDevice::BlitTask : public VirtualDevice::RenderTask {
+    BlitTask()
+        : srcAcquireFenceFd(-1),
+          destAcquireFenceFd(-1),
+          syncTimelineFd(-1) { }
+
+    virtual ~BlitTask()
+    {
+        // If queueColorConvert() creates this object and sets up fences,
+        // but aborts before enqueuing the task, or if the task runs
+        // but errors out, make sure our acquire fences get closed
+        // and any release fences get signaled.
+        CLOSE_FENCE(srcAcquireFenceFd);
+        CLOSE_FENCE(destAcquireFenceFd);
+        TIMELINE_INC(syncTimelineFd);
+    }
+
+    virtual void run(VirtualDevice& vd) {
+        SYNC_WAIT_AND_CLOSE(srcAcquireFenceFd);
+        SYNC_WAIT_AND_CLOSE(destAcquireFenceFd);
+        BufferManager* mgr = vd.mHwc.getBufferManager();
+        if (!(mgr->blit(srcHandle, destHandle, destRect, false, false))) {
+            ETRACE("color space conversion from RGB to NV12 failed");
+        }
+        else
+            successful = true;
+        TIMELINE_INC(syncTimelineFd);
+    }
+    buffer_handle_t srcHandle;
+    buffer_handle_t destHandle;
+    int srcAcquireFenceFd;
+    int destAcquireFenceFd;
+    int syncTimelineFd;
+    crop_t destRect;
+};
+
+struct VirtualDevice::FrameTypeChangedTask : public VirtualDevice::Task {
+    virtual void run(VirtualDevice& vd) {
+        typeChangeListener->frameTypeChanged(inputFrameInfo);
+        ITRACE("Notify frameTypeChanged: %dx%d in %dx%d @ %d fps",
+            inputFrameInfo.contentWidth, inputFrameInfo.contentHeight,
+            inputFrameInfo.bufferWidth, inputFrameInfo.bufferHeight,
+            inputFrameInfo.contentFrameRateN);
+    }
+    sp<IFrameTypeChangeListener> typeChangeListener;
+    FrameInfo inputFrameInfo;
+};
+
+struct VirtualDevice::BufferInfoChangedTask : public VirtualDevice::Task {
+    virtual void run(VirtualDevice& vd) {
+        typeChangeListener->bufferInfoChanged(outputFrameInfo);
+        ITRACE("Notify bufferInfoChanged: %dx%d in %dx%d @ %d fps",
+            outputFrameInfo.contentWidth, outputFrameInfo.contentHeight,
+            outputFrameInfo.bufferWidth, outputFrameInfo.bufferHeight,
+            outputFrameInfo.contentFrameRateN);
+    }
+    sp<IFrameTypeChangeListener> typeChangeListener;
+    FrameInfo outputFrameInfo;
+};
+
+struct VirtualDevice::OnFrameReadyTask : public VirtualDevice::Task {
+    virtual void run(VirtualDevice& vd) {
+        if (renderTask != NULL && !renderTask->successful)
+            return;
+
+        {
+            Mutex::Autolock _l(vd.mHeldBuffersLock);
+            //Add the heldbuffer to the vector before calling onFrameReady, so that the buffer will be removed
+            //from the vector properly even if the notifyBufferReturned call acquires mHeldBuffersLock first.
+            vd.mHeldBuffers.add(handle, heldBuffer);
+        }
+
+        // FIXME: we could remove this casting once onFrameReady receives
+        // a buffer_handle_t handle
+        status_t result = frameListener->onFrameReady((uint32_t)handle, handleType, renderTimestamp, mediaTimestamp);
+        if (result != OK) {
+            Mutex::Autolock _l(vd.mHeldBuffersLock);
+            vd.mHeldBuffers.removeItem(handle);
+        }
+    }
+    sp<RenderTask> renderTask;
+    sp<RefBase> heldBuffer;
+    sp<IFrameListener> frameListener;
+    buffer_handle_t handle;
+    HWCBufferHandleType handleType;
+    int64_t renderTimestamp;
+    int64_t mediaTimestamp;
+};
+
+struct VirtualDevice::BufferList::HeldBuffer : public RefBase {
+    HeldBuffer(BufferList& list, buffer_handle_t handle, uint32_t w, uint32_t h)
+        : mList(list),
+          mHandle(handle),
+          mWidth(w),
+          mHeight(h) { }
+    virtual ~HeldBuffer()
+    {
+        Mutex::Autolock _l(mList.mVd.mTaskLock);
+        if (mWidth == mList.mWidth && mHeight == mList.mHeight) {
+            VTRACE("Returning %s buffer %p (%ux%u) to list", mList.mName, mHandle, mWidth, mHeight);
+            mList.mAvailableBuffers.push_back(mHandle);
+        } else {
+            VTRACE("Deleting %s buffer %p (%ux%u)", mList.mName, mHandle, mWidth, mHeight);
+            BufferManager* mgr = mList.mVd.mHwc.getBufferManager();
+            mgr->freeGrallocBuffer((mHandle));
+            if (mList.mBuffersToCreate < mList.mLimit)
+                mList.mBuffersToCreate++;
+        }
+    }
+
+    BufferList& mList;
+    buffer_handle_t mHandle;
+    uint32_t mWidth;
+    uint32_t mHeight;
+};
+
+VirtualDevice::BufferList::BufferList(VirtualDevice& vd, const char* name,
+                                      uint32_t limit, uint32_t format, uint32_t usage)
+    : mVd(vd),
+      mName(name),
+      mLimit(limit),
+      mFormat(format),
+      mUsage(usage),
+      mBuffersToCreate(0),
+      mWidth(0),
+      mHeight(0)
+{
+}
+
+buffer_handle_t VirtualDevice::BufferList::get(uint32_t width, uint32_t height, sp<RefBase>* heldBuffer)
+{
+    width = align_width(width);
+    height = align_height(height);
+    if (mWidth != width || mHeight != height) {
+        ITRACE("%s buffers changing from %dx%d to %dx%d",
+                mName, mWidth, mHeight, width, height);
+        clear();
+        mWidth = width;
+        mHeight = height;
+        mBuffersToCreate = mLimit;
+    }
+
+    buffer_handle_t handle;
+    if (mAvailableBuffers.empty()) {
+        if (mBuffersToCreate <= 0)
+            return NULL;
+        BufferManager* mgr = mVd.mHwc.getBufferManager();
+        handle = reinterpret_cast<buffer_handle_t>(
+            mgr->allocGrallocBuffer(width, height, mFormat, mUsage));
+        if (handle == NULL){
+            ETRACE("failed to allocate %s buffer", mName);
+            return NULL;
+        }
+        mBuffersToCreate--;
+    }
+    else {
+        handle = *mAvailableBuffers.begin();
+        mAvailableBuffers.erase(mAvailableBuffers.begin());
+    }
+    *heldBuffer = new HeldBuffer(*this, handle, width, height);
+    return handle;
+}
+
+void VirtualDevice::BufferList::clear()
+{
+    if (mWidth != 0 || mHeight != 0)
+        ITRACE("Releasing %s buffers (%ux%u)", mName, mWidth, mHeight);
+    if (!mAvailableBuffers.empty()) {
+        // iterate the list and call freeGraphicBuffer
+        for (List<buffer_handle_t>::iterator i = mAvailableBuffers.begin(); i != mAvailableBuffers.end(); ++i) {
+            VTRACE("Deleting the gralloc buffer associated with handle (%p)", (*i));
+            mVd.mHwc.getBufferManager()->freeGrallocBuffer((*i));
+        }
+        mAvailableBuffers.clear();
+    }
+    mWidth = 0;
+    mHeight = 0;
+}
+
+VirtualDevice::VirtualDevice(Hwcomposer& hwc)
+    : mProtectedMode(false),
+      mCscBuffers(*this, "CSC",
+                  NUM_CSC_BUFFERS, DisplayQuery::queryNV12Format(),
+                  GRALLOC_USAGE_HW_VIDEO_ENCODER | GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_PRIVATE_1),
+      mRgbUpscaleBuffers(*this, "RGB upscale",
+                         NUM_SCALING_BUFFERS, HAL_PIXEL_FORMAT_BGRA_8888,
+                         GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_RENDER),
+      mInitialized(false),
+      mHwc(hwc),
+      mPayloadManager(NULL),
+      mVsyncObserver(NULL),
+      mOrigContentWidth(0),
+      mOrigContentHeight(0),
+      mFirstVideoFrame(true),
+      mLastConnectionStatus(false),
+      mCachedBufferCapcity(16),
+      mDecWidth(0),
+      mDecHeight(0)
+{
+    CTRACE();
+    mNextConfig.frameServerActive = false;
+}
+
+VirtualDevice::~VirtualDevice()
+{
+    WARN_IF_NOT_DEINIT();
+}
+
+sp<VirtualDevice::CachedBuffer> VirtualDevice::getMappedBuffer(buffer_handle_t handle)
+{
+    ssize_t index = mMappedBufferCache.indexOfKey(handle);
+    sp<CachedBuffer> cachedBuffer;
+    if (index == NAME_NOT_FOUND) {
+        if (mMappedBufferCache.size() > mCachedBufferCapcity)
+            mMappedBufferCache.clear();
+
+        cachedBuffer = new CachedBuffer(mHwc.getBufferManager(), handle);
+        mMappedBufferCache.add(handle, cachedBuffer);
+    } else {
+        cachedBuffer = mMappedBufferCache[index];
+    }
+
+    return cachedBuffer;
+}
+
+bool VirtualDevice::threadLoop()
+{
+    sp<Task> task;
+    {
+        Mutex::Autolock _l(mTaskLock);
+        while (mTasks.empty()) {
+            mRequestQueued.wait(mTaskLock);
+        }
+        task = *mTasks.begin();
+        mTasks.erase(mTasks.begin());
+    }
+    if (task != NULL) {
+        task->run(*this);
+        task = NULL;
+    }
+    mRequestDequeued.signal();
+
+    return true;
+}
+
+status_t VirtualDevice::start(sp<IFrameTypeChangeListener> typeChangeListener)
+{
+    ITRACE();
+    Mutex::Autolock _l(mConfigLock);
+    mNextConfig.typeChangeListener = typeChangeListener;
+    mNextConfig.frameListener = NULL;
+    mNextConfig.policy.scaledWidth = 0;
+    mNextConfig.policy.scaledHeight = 0;
+    mNextConfig.policy.xdpi = 96;
+    mNextConfig.policy.ydpi = 96;
+    mNextConfig.policy.refresh = 60;
+    mNextConfig.extendedModeEnabled =
+        Hwcomposer::getInstance().getDisplayAnalyzer()->isVideoExtModeEnabled();
+    mVideoFramerate = 0;
+    mFirstVideoFrame = true;
+    mNextConfig.frameServerActive = true;
+    mNextConfig.forceNotifyFrameType = true;
+    mNextConfig.forceNotifyBufferInfo = true;
+
+    return NO_ERROR;
+}
+
+status_t VirtualDevice::stop(bool isConnected)
+{
+    ITRACE();
+    Mutex::Autolock _l(mConfigLock);
+    mNextConfig.typeChangeListener = NULL;
+    mNextConfig.frameListener = NULL;
+    mNextConfig.policy.scaledWidth = 0;
+    mNextConfig.policy.scaledHeight = 0;
+    mNextConfig.policy.xdpi = 96;
+    mNextConfig.policy.ydpi = 96;
+    mNextConfig.policy.refresh = 60;
+    mNextConfig.frameServerActive = false;
+    mNextConfig.extendedModeEnabled = false;
+    mNextConfig.forceNotifyFrameType = false;
+    mNextConfig.forceNotifyBufferInfo = false;
+    {
+        Mutex::Autolock _l(mTaskLock);
+        mCscBuffers.clear();
+    }
+    return NO_ERROR;
+}
+
+bool VirtualDevice::isFrameServerActive() const
+{
+    return  mCurrentConfig.frameServerActive;
+}
+
+/* TODO: 64-bit - this handle of size 32-bit is a problem for 64-bit */
+status_t VirtualDevice::notifyBufferReturned(int handle)
+{
+    CTRACE();
+    Mutex::Autolock _l(mHeldBuffersLock);
+    ssize_t index = mHeldBuffers.indexOfKey((buffer_handle_t)handle);
+    if (index == NAME_NOT_FOUND) {
+        ETRACE("Couldn't find returned khandle %p", handle);
+    } else {
+        VTRACE("Removing heldBuffer associated with handle (%p)", handle);
+        mHeldBuffers.removeItemsAt(index, 1);
+    }
+    return NO_ERROR;
+}
+
+status_t VirtualDevice::setResolution(const FrameProcessingPolicy& policy, sp<IFrameListener> listener)
+{
+    ITRACE();
+    Mutex::Autolock _l(mConfigLock);
+    mNextConfig.frameListener = listener;
+    mNextConfig.policy = policy;
+    return NO_ERROR;
+}
+
+static bool canUseDirectly(const hwc_display_contents_1_t *display, size_t n)
+{
+    const hwc_layer_1_t& fbTarget = display->hwLayers[display->numHwLayers-1];
+    const hwc_layer_1_t& layer = display->hwLayers[n];
+    const IMG_native_handle_t* nativeHandle = reinterpret_cast<const IMG_native_handle_t*>(layer.handle);
+    return !(layer.flags & HWC_SKIP_LAYER) && layer.transform == 0 &&
+            layer.blending == HWC_BLENDING_PREMULT &&
+            layer.sourceCropf.left == 0 && layer.sourceCropf.top == 0 &&
+            layer.displayFrame.left == 0 && layer.displayFrame.top == 0 &&
+            layer.sourceCropf.right == fbTarget.sourceCropf.right &&
+            layer.sourceCropf.bottom == fbTarget.sourceCropf.bottom &&
+            layer.displayFrame.right == fbTarget.displayFrame.right &&
+            layer.displayFrame.bottom == fbTarget.displayFrame.bottom &&
+            layer.planeAlpha == 255 && layer.handle != NULL &&
+            (nativeHandle->iFormat == HAL_PIXEL_FORMAT_RGBA_8888 ||
+             nativeHandle->iFormat == HAL_PIXEL_FORMAT_BGRA_8888);
+}
+
+bool VirtualDevice::prePrepare(hwc_display_contents_1_t *display)
+{
+    RETURN_FALSE_IF_NOT_INIT();
+    return true;
+}
+
+bool VirtualDevice::prepare(hwc_display_contents_1_t *display)
+{
+    RETURN_FALSE_IF_NOT_INIT();
+
+    mRenderTimestamp = systemTime();
+    mVspInUse = false;
+    mExpectAcquireFences = false;
+    mIsForceCloneMode = false;
+
+    {
+        Mutex::Autolock _l(mConfigLock);
+        mCurrentConfig = mNextConfig;
+    }
+
+    bool shouldBeConnected = (display != NULL);
+    if (shouldBeConnected != mLastConnectionStatus) {
+        // calling this will reload the property 'hwc.video.extmode.enable'
+        Hwcomposer::getInstance().getDisplayAnalyzer()->isVideoExtModeEnabled();
+        char propertyVal[PROPERTY_VALUE_MAX];
+        if (property_get("widi.compose.rgb_upscale", propertyVal, NULL) > 0)
+            mVspUpscale = atoi(propertyVal);
+        if (property_get("widi.compose.all_video", propertyVal, NULL) > 0)
+            mDebugVspClear = atoi(propertyVal);
+        if (property_get("widi.compose.dump", propertyVal, NULL) > 0)
+            mDebugVspDump = atoi(propertyVal);
+
+        Hwcomposer::getInstance().getMultiDisplayObserver()->notifyWidiConnectionStatus(shouldBeConnected);
+        mLastConnectionStatus = shouldBeConnected;
+    }
+
+    if (!display) {
+        // No image. We're done with any mappings and CSC buffers.
+        mMappedBufferCache.clear();
+        Mutex::Autolock _l(mTaskLock);
+        mCscBuffers.clear();
+        return true;
+    }
+
+    if (!mCurrentConfig.frameServerActive) {
+        // We're done with CSC buffers, since we blit to outbuf in this mode.
+        // We want to keep mappings cached, so we don't clear mMappedBufferCache.
+        Mutex::Autolock _l(mTaskLock);
+        mCscBuffers.clear();
+    }
+
+    // by default send the FRAMEBUFFER_TARGET layer (composited image)
+    const ssize_t fbTarget = display->numHwLayers-1;
+    mRgbLayer = fbTarget;
+    mYuvLayer = -1;
+
+    DisplayAnalyzer *analyzer = mHwc.getDisplayAnalyzer();
+
+    mProtectedMode = false;
+
+    if (mCurrentConfig.typeChangeListener != NULL &&
+        !analyzer->isOverlayAllowed() &&
+        analyzer->getVideoInstances() <= 1) {
+        if (mCurrentConfig.typeChangeListener->shutdownVideo() != OK) {
+            ITRACE("Waiting for prior encoder session to shut down...");
+        }
+        /* Setting following flag to true will enable us to call bufferInfoChanged() in clone mode. */
+        mNextConfig.forceNotifyBufferInfo = true;
+        mYuvLayer = -1;
+        mRgbLayer = -1;
+        // Skipping frames.
+        // Fences aren't set in prepare, and we don't need them here, but they'll
+        // be set later and we have to close them. Don't log a warning in this case.
+        mExpectAcquireFences = true;
+        for (ssize_t i = 0; i < fbTarget; i++)
+            display->hwLayers[i].compositionType = HWC_OVERLAY;
+        return true;
+    }
+
+    for (ssize_t i = 0; i < fbTarget; i++) {
+        hwc_layer_1_t& layer = display->hwLayers[i];
+        if (analyzer->isVideoLayer(layer) && (mCurrentConfig.extendedModeEnabled || mDebugVspClear || analyzer->isProtectedLayer(layer))) {
+            if (mCurrentConfig.frameServerActive && mCurrentConfig.extendedModeEnabled) {
+                // If composed in surface flinger, then stream fbtarget.
+                if ((layer.flags & HWC_SKIP_LAYER) && !analyzer->ignoreVideoSkipFlag()) {
+                    continue;
+                }
+
+                /* If the resolution of the video layer is less than QCIF, then we are going to play it in clone mode only.*/
+                uint32_t vidContentWidth = layer.sourceCropf.right - layer.sourceCropf.left;
+                uint32_t vidContentHeight = layer.sourceCropf.bottom - layer.sourceCropf.top;
+                if (vidContentWidth < QCIF_WIDTH || vidContentHeight < QCIF_HEIGHT) {
+                    VTRACE("Ingoring layer %d which is too small for extended mode", i);
+                    continue;
+                }
+            }
+            mYuvLayer = i;
+            mProtectedMode = analyzer->isProtectedLayer(layer);
+            break;
+        }
+    }
+
+    if (mYuvLayer == -1) {
+        mFirstVideoFrame = true;
+        mDecWidth = 0;
+        mDecHeight = 0;
+    }
+
+    if (mCurrentConfig.frameServerActive && mCurrentConfig.extendedModeEnabled && mYuvLayer != -1) {
+        if (handleExtendedMode(display)) {
+            mYuvLayer = -1;
+            mRgbLayer = -1;
+            // Extended mode is successful.
+            // Fences aren't set in prepare, and we don't need them here, but they'll
+            // be set later and we have to close them. Don't log a warning in this case.
+            mExpectAcquireFences = true;
+            for (ssize_t i = 0; i < fbTarget; i++)
+                display->hwLayers[i].compositionType = HWC_OVERLAY;
+            return true;
+        }
+        // if error in playback file , switch to clone mode
+        WTRACE("Error, falling back to clone mode");
+        mIsForceCloneMode = true;
+        mYuvLayer = -1;
+    }
+
+    if (mYuvLayer == 0 && fbTarget == 1) {
+        // No RGB layer, so tell queueCompose to use blank RGB in fbtarget.
+        mRgbLayer = -1;
+    }
+    else if (mYuvLayer == 0 && fbTarget == 2) {
+        if (canUseDirectly(display, 1))
+            mRgbLayer = 1;
+    }
+    else if (mYuvLayer == -1 && fbTarget == 1) {
+        if (canUseDirectly(display, 0))
+            mRgbLayer = 0;
+    }
+
+    for (ssize_t i = 0; i < fbTarget; i++) {
+        hwc_layer_1_t& layer = display->hwLayers[i];
+        if (i == mYuvLayer || i == mRgbLayer || mRgbLayer != fbTarget)
+            layer.compositionType = HWC_OVERLAY;
+        else
+            layer.compositionType = HWC_FRAMEBUFFER;
+    }
+    if (mYuvLayer != -1 && mRgbLayer == fbTarget)
+        // This tells SurfaceFlinger to render this layer by writing transparent pixels
+        // to this layer's target region within the framebuffer. This effectively punches
+        // a hole through any content that is supposed to show below the video, and the
+        // video can be seen through this hole when we composite the YUV and RGBA layers
+        // together. Content above will draw on top of this hole and can cover the video.
+        // This has no effect when the video is the bottommost layer.
+        display->hwLayers[mYuvLayer].hints |= HWC_HINT_CLEAR_FB;
+
+    // we're streaming fbtarget, so send onFramePrepare and wait for composition to happen
+    if (mCurrentConfig.frameListener != NULL)
+        mCurrentConfig.frameListener->onFramePrepare(mRenderTimestamp, -1);
+
+    return true;
+}
+
+bool VirtualDevice::commit(hwc_display_contents_1_t *display, IDisplayContext *context)
+{
+    RETURN_FALSE_IF_NOT_INIT();
+
+    if (display != NULL && (mRgbLayer != -1 || mYuvLayer != -1))
+        sendToWidi(display);
+
+    if (mVspEnabled && !mVspInUse) {
+        mVaMapCache.clear();
+        sp<DisableVspTask> disableVsp = new DisableVspTask();
+        mMappedBufferCache.clear();
+        Mutex::Autolock _l(mTaskLock);
+        mRgbUpscaleBuffers.clear();
+        mTasks.push(disableVsp);
+        mRequestQueued.signal();
+        mVspEnabled = false;
+    }
+
+    if (display != NULL) {
+        // All acquire fences should be copied somewhere else or closed by now
+        // and set to -1 in these structs except in the case of extended mode.
+        // Make sure the fences are closed and log a warning if not in extended mode.
+        if (display->outbufAcquireFenceFd != -1) {
+            if (!mExpectAcquireFences)
+                WTRACE("outbuf acquire fence (fd=%d) not yet saved or closed", display->outbufAcquireFenceFd);
+            CLOSE_FENCE(display->outbufAcquireFenceFd);
+        }
+        for (size_t i = 0; i < display->numHwLayers; i++) {
+            hwc_layer_1_t& layer = display->hwLayers[i];
+            if (layer.acquireFenceFd != -1) {
+                if (!mExpectAcquireFences && (i < display->numHwLayers-1 || i == (size_t) mRgbLayer))
+                    WTRACE("layer %zd acquire fence (fd=%zd) not yet saved or closed", i, layer.acquireFenceFd);
+                CLOSE_FENCE(layer.acquireFenceFd);
+            }
+        }
+    }
+
+    return true;
+}
+
+bool VirtualDevice::sendToWidi(hwc_display_contents_1_t *display)
+{
+    VTRACE("RGB=%d, YUV=%d", mRgbLayer, mYuvLayer);
+
+    if (mYuvLayer == -1 && mRgbLayer == -1)
+        return true;
+
+    if (mYuvLayer != -1) {
+        mVspInUse = true;
+        if (queueCompose(display))
+            return true;
+    }
+
+    return queueColorConvert(display);
+}
+
+bool VirtualDevice::queueCompose(hwc_display_contents_1_t *display)
+{
+    hwc_layer_1_t& yuvLayer = display->hwLayers[mYuvLayer];
+    if (yuvLayer.handle == NULL) {
+        ETRACE("No video handle");
+        return false;
+    }
+    if (!mCurrentConfig.frameServerActive && display->outbuf == NULL) {
+        ETRACE("No outbuf");
+        return true; // fallback would be pointless
+    }
+
+    sp<ComposeTask> composeTask = new ComposeTask();
+
+    sp<RefBase> heldBuffer;
+    sp<OnFrameReadyTask> frameReadyTask;
+    Mutex::Autolock _l(mTaskLock);
+
+    float upscale_x = 1.0;
+    float upscale_y = 1.0;
+    hwc_layer_1_t& fbTarget = display->hwLayers[display->numHwLayers-1];
+    composeTask->outWidth = fbTarget.sourceCropf.right - fbTarget.sourceCropf.left;
+    composeTask->outHeight = fbTarget.sourceCropf.bottom - fbTarget.sourceCropf.top;
+
+    bool scaleRgb = false;
+    if (mCurrentConfig.frameServerActive) {
+        if (mVspUpscale) {
+            composeTask->outWidth = mCurrentConfig.policy.scaledWidth;
+            composeTask->outHeight = mCurrentConfig.policy.scaledHeight;
+            upscale_x = mCurrentConfig.policy.scaledWidth/(fbTarget.sourceCropf.right - fbTarget.sourceCropf.left);
+            upscale_y = mCurrentConfig.policy.scaledHeight/(fbTarget.sourceCropf.bottom - fbTarget.sourceCropf.top);
+            scaleRgb = composeTask->outWidth != fbTarget.sourceCropf.right - fbTarget.sourceCropf.left ||
+                       composeTask->outHeight != fbTarget.sourceCropf.bottom - fbTarget.sourceCropf.top;
+        }
+
+        composeTask->outputHandle = mCscBuffers.get(composeTask->outWidth, composeTask->outHeight, &heldBuffer);
+        if (composeTask->outputHandle == NULL) {
+            WTRACE("Out of CSC buffers, dropping frame");
+            return true;
+        }
+    } else {
+        composeTask->outputHandle = display->outbuf;
+    }
+
+    vspPrepare(composeTask->outWidth, composeTask->outHeight);
+
+    composeTask->videoCachedBuffer = getMappedBuffer(yuvLayer.handle);
+    if (composeTask->videoCachedBuffer == NULL) {
+        ETRACE("Couldn't map video handle %p", yuvLayer.handle);
+        return false;
+    }
+    if (composeTask->videoCachedBuffer->mapper == NULL) {
+        ETRACE("Src mapper gone");
+        return false;
+    }
+    composeTask->heldVideoBuffer = new HeldDecoderBuffer(this, composeTask->videoCachedBuffer);
+    IVideoPayloadManager::MetaData videoMetadata;
+    if (!mPayloadManager->getMetaData(composeTask->videoCachedBuffer->mapper, &videoMetadata)) {
+        ETRACE("Failed to map video payload info");
+        return false;
+    }
+    if (videoMetadata.normalBuffer.width == 0 || videoMetadata.normalBuffer.height == 0) {
+        ETRACE("Bad video metadata for handle %p", yuvLayer.handle);
+        return false;
+    }
+    if (videoMetadata.normalBuffer.khandle == 0) {
+        ETRACE("Bad khandle");
+        return false;
+    }
+
+    VARectangle& output_region = composeTask->output_region;
+    output_region.x = static_cast<uint32_t>(yuvLayer.displayFrame.left*upscale_x) & ~1;
+    output_region.y = static_cast<uint32_t>(yuvLayer.displayFrame.top*upscale_y) & ~1;
+    output_region.width = (static_cast<uint32_t>(yuvLayer.displayFrame.right*upscale_y+1) & ~1) - output_region.x;
+    output_region.height = (static_cast<uint32_t>(yuvLayer.displayFrame.bottom*upscale_y+1) & ~1) - output_region.y;
+
+    uint32_t videoWidth;
+    uint32_t videoHeight;
+    if (videoMetadata.transform == 0 || videoMetadata.transform == HAL_TRANSFORM_ROT_180) {
+        videoWidth = videoMetadata.normalBuffer.width;
+        videoHeight = videoMetadata.normalBuffer.height;
+    } else {
+        videoWidth = videoMetadata.normalBuffer.height;
+        videoHeight = videoMetadata.normalBuffer.width;
+    }
+
+    // Layer source crop info is based on an unrotated, unscaled buffer.
+    // Rotate the rectangle to get the source crop we'd use for a rotated, unscaled buffer.
+    hwc_frect_t rotatedCrop;
+    switch (videoMetadata.transform) {
+    default:
+        rotatedCrop = yuvLayer.sourceCropf;
+        break;
+    case HAL_TRANSFORM_ROT_90:
+        rotatedCrop.left = yuvLayer.sourceCropf.top;
+        rotatedCrop.top = videoHeight - yuvLayer.sourceCropf.right;
+        rotatedCrop.right = yuvLayer.sourceCropf.bottom;
+        rotatedCrop.bottom = videoHeight - yuvLayer.sourceCropf.left;
+        break;
+    case HAL_TRANSFORM_ROT_180:
+        rotatedCrop.left = videoWidth - yuvLayer.sourceCropf.right;
+        rotatedCrop.top = videoHeight - yuvLayer.sourceCropf.bottom;
+        rotatedCrop.right = videoWidth - yuvLayer.sourceCropf.left;
+        rotatedCrop.bottom = videoHeight - yuvLayer.sourceCropf.top;
+        break;
+    case HAL_TRANSFORM_ROT_270:
+        rotatedCrop.left = videoWidth - yuvLayer.sourceCropf.bottom;
+        rotatedCrop.top = yuvLayer.sourceCropf.left;
+        rotatedCrop.right = videoWidth - yuvLayer.sourceCropf.top;
+        rotatedCrop.bottom = yuvLayer.sourceCropf.right;
+        break;
+    }
+
+    float factor_x = output_region.width / (rotatedCrop.right - rotatedCrop.left);
+    float factor_y = output_region.height / (rotatedCrop.bottom - rotatedCrop.top);
+
+    uint32_t scaleWidth = videoWidth * factor_x;
+    uint32_t scaleHeight = videoHeight * factor_y;
+
+    scaleWidth &= ~1;
+    scaleHeight &= ~1;
+
+    IVideoPayloadManager::Buffer info;
+    if (!getFrameOfSize(scaleWidth, scaleHeight, videoMetadata, info)) {
+        //Returning true as else we fall into the queueColorConvert
+        //resulting into scrambled frames for protected content.
+        ITRACE("scaled frame not yet available.");
+        return true;
+    }
+
+    composeTask->videoKhandle = info.khandle;
+    composeTask->videoStride = info.lumaStride;
+    composeTask->videoBufHeight = info.bufHeight;
+    composeTask->videoTiled = info.tiled;
+
+    // rotatedCrop accounts for rotation. Now account for any scaling along each dimension.
+    hwc_frect_t scaledCrop = rotatedCrop;
+    if (info.width < videoWidth) {
+        float factor = static_cast<float>(info.width) / videoWidth;
+        scaledCrop.left *= factor;
+        scaledCrop.right *= factor;
+    }
+    if (info.height < videoHeight) {
+        float factor = static_cast<float>(info.height) / videoHeight;
+        scaledCrop.top *= factor;
+        scaledCrop.bottom *= factor;
+    }
+
+    VARectangle& surface_region = composeTask->surface_region;
+    surface_region.x = static_cast<int>(scaledCrop.left) + info.offsetX;
+    surface_region.y = static_cast<int>(scaledCrop.top) + info.offsetY;
+    surface_region.width = static_cast<int>(scaledCrop.right - scaledCrop.left);
+    surface_region.height = static_cast<int>(scaledCrop.bottom - scaledCrop.top);
+
+    VTRACE("Want to take (%d,%d)-(%d,%d) region from %dx%d video (in %dx%d buffer) and output to (%d,%d)-(%d,%d)",
+            surface_region.x, surface_region.y,
+            surface_region.x + surface_region.width, surface_region.y + surface_region.height,
+            info.width, info.height,
+            info.bufWidth, info.bufHeight,
+            output_region.x, output_region.y,
+            output_region.x + output_region.width, output_region.y + output_region.height);
+
+    if (surface_region.x + surface_region.width > static_cast<int>(info.width + info.offsetX) ||
+        surface_region.y + surface_region.height > static_cast<int>(info.height + info.offsetY))
+    {
+        ETRACE("Source crop exceeds video dimensions: (%d,%d)-(%d,%d) > %ux%u",
+                surface_region.x, surface_region.y,
+                surface_region.x + surface_region.width, surface_region.y + surface_region.height,
+                info.width, info.height);
+        return false;
+    }
+
+    if (surface_region.width > output_region.width || surface_region.height > output_region.height) {
+        // VSP can upscale but can't downscale video, so use blank video
+        // until we start getting downscaled frames.
+        surface_region.x = 0;
+        surface_region.y = 0;
+        surface_region.width = composeTask->outWidth;
+        surface_region.height = composeTask->outHeight;
+        output_region = surface_region;
+        composeTask->videoKhandle = 0;
+        composeTask->videoStride = composeTask->outWidth;
+        composeTask->videoBufHeight = composeTask->outHeight;
+        composeTask->videoTiled = false;
+    }
+
+    composeTask->yuvAcquireFenceFd = yuvLayer.acquireFenceFd;
+    yuvLayer.acquireFenceFd = -1;
+
+    composeTask->outbufAcquireFenceFd = display->outbufAcquireFenceFd;
+    display->outbufAcquireFenceFd = -1;
+
+    int retireFd = sw_sync_fence_create(mSyncTimelineFd, "widi_compose_retire", mNextSyncPoint);
+    yuvLayer.releaseFenceFd = retireFd;
+
+    if (mRgbLayer == -1) {
+        CLOSE_FENCE(fbTarget.acquireFenceFd);
+    } else {
+        hwc_layer_1_t& rgbLayer = display->hwLayers[mRgbLayer];
+        composeTask->rgbAcquireFenceFd = rgbLayer.acquireFenceFd;
+        rgbLayer.acquireFenceFd = -1;
+        rgbLayer.releaseFenceFd = dup(retireFd);
+    }
+
+    mNextSyncPoint++;
+    composeTask->syncTimelineFd = mSyncTimelineFd;
+
+    if (mRgbLayer != -1)
+    {
+        hwc_layer_1_t& rgbLayer = display->hwLayers[mRgbLayer];
+        if (rgbLayer.handle == NULL) {
+            ETRACE("No RGB handle");
+            return false;
+        }
+
+        if (scaleRgb) {
+            buffer_handle_t scalingBuffer;
+            sp<RefBase> heldUpscaleBuffer;
+            while ((scalingBuffer = mRgbUpscaleBuffers.get(composeTask->outWidth, composeTask->outHeight, &heldUpscaleBuffer)) == NULL &&
+                   !mTasks.empty()) {
+                VTRACE("Waiting for free RGB upscale buffer...");
+                mRequestDequeued.wait(mTaskLock);
+            }
+            if (scalingBuffer == NULL) {
+                ETRACE("Couldn't get scaling buffer");
+                return false;
+            }
+            BufferManager* mgr = mHwc.getBufferManager();
+            crop_t destRect;
+            destRect.x = 0;
+            destRect.y = 0;
+            destRect.w = composeTask->outWidth;
+            destRect.h = composeTask->outHeight;
+            if (!mgr->blit(rgbLayer.handle, scalingBuffer, destRect, true, true))
+                return true;
+            composeTask->rgbHandle = scalingBuffer;
+            composeTask->heldRgbHandle = heldUpscaleBuffer;
+        }
+        else {
+            unsigned int pixel_format = VA_FOURCC_BGRA;
+            const IMG_native_handle_t* nativeHandle = reinterpret_cast<const IMG_native_handle_t*>(rgbLayer.handle);
+            if (nativeHandle->iFormat == HAL_PIXEL_FORMAT_RGBA_8888)
+                pixel_format = VA_FOURCC_RGBA;
+            mRgbUpscaleBuffers.clear();
+            ssize_t index = mVaMapCache.indexOfKey(rgbLayer.handle);
+            if (index == NAME_NOT_FOUND) {
+                composeTask->mappedRgbIn = new VAMappedHandleObject(va_dpy, rgbLayer.handle, composeTask->outWidth, composeTask->outHeight, pixel_format);
+                mVaMapCache.add(rgbLayer.handle, composeTask->mappedRgbIn);
+            }
+            else
+                composeTask->mappedRgbIn = mVaMapCache[index];
+            if (composeTask->mappedRgbIn->surface == 0) {
+                ETRACE("Unable to map RGB surface");
+                return false;
+            }
+        }
+    }
+    else
+        composeTask->mappedRgbIn = NULL;
+
+    mTasks.push_back(composeTask);
+    mRequestQueued.signal();
+
+    if (mCurrentConfig.frameServerActive) {
+
+        FrameInfo inputFrameInfo;
+        memset(&inputFrameInfo, 0, sizeof(inputFrameInfo));
+        inputFrameInfo.isProtected = mProtectedMode;
+        inputFrameInfo.frameType = HWC_FRAMETYPE_FRAME_BUFFER;
+        if (mVspUpscale) {
+            float upscale_x = (rotatedCrop.right - rotatedCrop.left) /
+                              (yuvLayer.displayFrame.right - yuvLayer.displayFrame.left);
+            float upscale_y = (rotatedCrop.bottom - rotatedCrop.top) /
+                              (yuvLayer.displayFrame.bottom - yuvLayer.displayFrame.top);
+            float upscale = upscale_x > upscale_y ? upscale_x : upscale_y;
+            if (upscale <= 1.0)
+                upscale = 1.0;
+            inputFrameInfo.contentWidth = (fbTarget.sourceCropf.right - fbTarget.sourceCropf.left)*upscale;
+            inputFrameInfo.contentHeight = (fbTarget.sourceCropf.bottom - fbTarget.sourceCropf.top)*upscale;
+        }
+        else {
+            inputFrameInfo.contentWidth = composeTask->outWidth;
+            inputFrameInfo.contentHeight = composeTask->outHeight;
+        }
+        inputFrameInfo.contentFrameRateN = 0;
+        inputFrameInfo.contentFrameRateD = 0;
+        FrameInfo outputFrameInfo = inputFrameInfo;
+
+        BufferManager* mgr = mHwc.getBufferManager();
+        DataBuffer* dataBuf = mgr->lockDataBuffer(composeTask->outputHandle);
+        outputFrameInfo.contentWidth = composeTask->outWidth;
+        outputFrameInfo.contentHeight = composeTask->outHeight;
+        outputFrameInfo.bufferWidth = dataBuf->getWidth();
+        outputFrameInfo.bufferHeight = dataBuf->getHeight();
+        outputFrameInfo.lumaUStride = dataBuf->getWidth();
+        outputFrameInfo.chromaUStride = dataBuf->getWidth();
+        outputFrameInfo.chromaVStride = dataBuf->getWidth();
+        mgr->unlockDataBuffer(dataBuf);
+
+        queueFrameTypeInfo(inputFrameInfo);
+        if (mCurrentConfig.policy.scaledWidth == 0 || mCurrentConfig.policy.scaledHeight == 0)
+            return true; // This isn't a failure, WiDi just doesn't want frames right now.
+        queueBufferInfo(outputFrameInfo);
+
+        if (mCurrentConfig.frameListener != NULL) {
+            frameReadyTask = new OnFrameReadyTask();
+            frameReadyTask->renderTask = composeTask;
+            frameReadyTask->heldBuffer = heldBuffer;
+            frameReadyTask->frameListener = mCurrentConfig.frameListener;
+            frameReadyTask->handle = composeTask->outputHandle;
+            frameReadyTask->handleType = HWC_HANDLE_TYPE_GRALLOC;
+            frameReadyTask->renderTimestamp = mRenderTimestamp;
+            frameReadyTask->mediaTimestamp = -1;
+            mTasks.push_back(frameReadyTask);
+        }
+    }
+    else {
+        display->retireFenceFd = dup(retireFd);
+    }
+
+    return true;
+}
+
+bool VirtualDevice::queueColorConvert(hwc_display_contents_1_t *display)
+{
+    if (mRgbLayer == -1) {
+        ETRACE("RGB layer not set");
+        return false;
+    }
+    hwc_layer_1_t& layer = display->hwLayers[mRgbLayer];
+    if (layer.handle == NULL) {
+        ETRACE("RGB layer has no handle set");
+        return false;
+    }
+    if (display->outbuf == NULL) {
+        ETRACE("outbuf is not set");
+        return false;
+    }
+
+    {
+        const IMG_native_handle_t* nativeSrcHandle = reinterpret_cast<const IMG_native_handle_t*>(layer.handle);
+        const IMG_native_handle_t* nativeDestHandle = reinterpret_cast<const IMG_native_handle_t*>(display->outbuf);
+
+        if ((nativeSrcHandle->iFormat == HAL_PIXEL_FORMAT_RGBA_8888 &&
+            nativeDestHandle->iFormat == HAL_PIXEL_FORMAT_BGRA_8888) ||
+            (nativeSrcHandle->iFormat == HAL_PIXEL_FORMAT_BGRA_8888 &&
+            nativeDestHandle->iFormat == HAL_PIXEL_FORMAT_RGBA_8888))
+        {
+            SYNC_WAIT_AND_CLOSE(layer.acquireFenceFd);
+            SYNC_WAIT_AND_CLOSE(display->outbufAcquireFenceFd);
+            display->retireFenceFd = -1;
+
+            // synchronous in this case
+            colorSwap(layer.handle, display->outbuf, ((nativeSrcHandle->iWidth+31)&~31)*nativeSrcHandle->iHeight);
+            // Workaround: Don't keep cached buffers. If the VirtualDisplaySurface gets destroyed,
+            //             these would be unmapped on the next frame, after the buffers are destroyed,
+            //             which is causing heap corruption, probably due to a double-free somewhere.
+            mMappedBufferCache.clear();
+            return true;
+        }
+    }
+
+    sp<BlitTask> blitTask = new BlitTask();
+    sp<OnFrameReadyTask> frameReadyTask;
+    blitTask->destRect.x = 0;
+    blitTask->destRect.y = 0;
+    blitTask->destRect.w = layer.sourceCropf.right - layer.sourceCropf.left;
+    blitTask->destRect.h = layer.sourceCropf.bottom - layer.sourceCropf.top;
+    blitTask->srcHandle = layer.handle;
+
+    sp<RefBase> heldBuffer;
+    Mutex::Autolock _l(mTaskLock);
+
+    blitTask->srcAcquireFenceFd = layer.acquireFenceFd;
+    layer.acquireFenceFd = -1;
+
+    blitTask->syncTimelineFd = mSyncTimelineFd;
+    // Framebuffer after BlitTask::run() calls sw_sync_timeline_inc().
+    layer.releaseFenceFd = sw_sync_fence_create(mSyncTimelineFd, "widi_blit_retire", mNextSyncPoint);
+    mNextSyncPoint++;
+
+    if (mCurrentConfig.frameServerActive) {
+        blitTask->destHandle = mCscBuffers.get(blitTask->destRect.w, blitTask->destRect.h, &heldBuffer);
+        blitTask->destAcquireFenceFd = -1;
+
+        // we do not use retire fence in frameServerActive path.
+        CLOSE_FENCE(display->retireFenceFd);
+
+        // we use our own buffer, so just close this fence without a wait
+        CLOSE_FENCE(display->outbufAcquireFenceFd);
+    }
+    else {
+        blitTask->destHandle = display->outbuf;
+        blitTask->destAcquireFenceFd = display->outbufAcquireFenceFd;
+        // don't let TngDisplayContext::commitEnd() close this
+        display->outbufAcquireFenceFd = -1;
+        display->retireFenceFd = dup(layer.releaseFenceFd);
+    }
+
+    if (blitTask->destHandle == NULL) {
+        WTRACE("Out of CSC buffers, dropping frame");
+        return false;
+    }
+
+    mTasks.push_back(blitTask);
+    mRequestQueued.signal();
+
+    if (mCurrentConfig.frameServerActive) {
+        FrameInfo inputFrameInfo;
+        memset(&inputFrameInfo, 0, sizeof(inputFrameInfo));
+        inputFrameInfo.isProtected = mProtectedMode;
+        FrameInfo outputFrameInfo;
+
+        inputFrameInfo.frameType = HWC_FRAMETYPE_FRAME_BUFFER;
+        inputFrameInfo.contentWidth = blitTask->destRect.w;
+        inputFrameInfo.contentHeight = blitTask->destRect.h;
+        inputFrameInfo.contentFrameRateN = 0;
+        inputFrameInfo.contentFrameRateD = 0;
+        outputFrameInfo = inputFrameInfo;
+
+        BufferManager* mgr = mHwc.getBufferManager();
+        DataBuffer* dataBuf = mgr->lockDataBuffer(blitTask->destHandle);
+        outputFrameInfo.bufferWidth = dataBuf->getWidth();
+        outputFrameInfo.bufferHeight = dataBuf->getHeight();
+        outputFrameInfo.lumaUStride = dataBuf->getWidth();
+        outputFrameInfo.chromaUStride = dataBuf->getWidth();
+        outputFrameInfo.chromaVStride = dataBuf->getWidth();
+        mgr->unlockDataBuffer(dataBuf);
+
+        if (!mIsForceCloneMode)
+            queueFrameTypeInfo(inputFrameInfo);
+
+        if (mCurrentConfig.policy.scaledWidth == 0 || mCurrentConfig.policy.scaledHeight == 0)
+            return true; // This isn't a failure, WiDi just doesn't want frames right now.
+        queueBufferInfo(outputFrameInfo);
+
+        if (mCurrentConfig.frameListener != NULL) {
+            frameReadyTask = new OnFrameReadyTask();
+            frameReadyTask->renderTask = blitTask;
+            frameReadyTask->heldBuffer = heldBuffer;
+            frameReadyTask->frameListener = mCurrentConfig.frameListener;
+            frameReadyTask->handle = blitTask->destHandle;
+            frameReadyTask->handleType = HWC_HANDLE_TYPE_GRALLOC;
+            frameReadyTask->renderTimestamp = mRenderTimestamp;
+            frameReadyTask->mediaTimestamp = -1;
+            mTasks.push_back(frameReadyTask);
+        }
+    }
+
+    return true;
+}
+
+bool VirtualDevice::handleExtendedMode(hwc_display_contents_1_t *display)
+{
+    FrameInfo inputFrameInfo;
+    memset(&inputFrameInfo, 0, sizeof(inputFrameInfo));
+    inputFrameInfo.isProtected = mProtectedMode;
+
+    hwc_layer_1_t& layer = display->hwLayers[mYuvLayer];
+    if (layer.handle == NULL) {
+        ETRACE("video layer has no handle set");
+        return false;
+    }
+    sp<CachedBuffer> cachedBuffer;
+    if ((cachedBuffer = getMappedBuffer(layer.handle)) == NULL) {
+        ETRACE("Failed to map display buffer");
+        return false;
+    }
+
+    inputFrameInfo.frameType = HWC_FRAMETYPE_VIDEO;
+    // for video mode let 30 fps be the default value.
+    inputFrameInfo.contentFrameRateN = 30;
+    inputFrameInfo.contentFrameRateD = 1;
+
+    IVideoPayloadManager::MetaData metadata;
+    if (!mPayloadManager->getMetaData(cachedBuffer->mapper, &metadata)) {
+        ETRACE("Failed to get metadata");
+        return false;
+    }
+
+    if (metadata.transform == 0 || metadata.transform == HAL_TRANSFORM_ROT_180) {
+        inputFrameInfo.contentWidth = metadata.normalBuffer.width;
+        inputFrameInfo.contentHeight = metadata.normalBuffer.height;
+    } else {
+        inputFrameInfo.contentWidth = metadata.normalBuffer.height;
+        inputFrameInfo.contentHeight = metadata.normalBuffer.width;
+        // 90 and 270 have some issues that appear to be decoder bugs
+        ITRACE("Skipping extended mode due to rotation of 90 or 270");
+        return false;
+    }
+    // Use the crop size if something changed derive it again..
+    // Only get video source info if frame rate has not been initialized.
+    // getVideoSourceInfo() is a fairly expensive operation. This optimization
+    // will save us a few milliseconds per frame
+    if (mFirstVideoFrame || (mOrigContentWidth != metadata.normalBuffer.width) ||
+        (mOrigContentHeight != metadata.normalBuffer.height)) {
+        mVideoFramerate = inputFrameInfo.contentFrameRateN;
+        VTRACE("VideoWidth = %d, VideoHeight = %d", metadata.normalBuffer.width, metadata.normalBuffer.height);
+        mOrigContentWidth = metadata.normalBuffer.width;
+        mOrigContentHeight = metadata.normalBuffer.height;
+
+        // For the first video session by default
+        int sessionID = Hwcomposer::getInstance().getDisplayAnalyzer()->getFirstVideoInstanceSessionID();
+        if (sessionID >= 0) {
+            ITRACE("Session id = %d", sessionID);
+            VideoSourceInfo videoInfo;
+            memset(&videoInfo, 0, sizeof(videoInfo));
+            status_t ret = mHwc.getMultiDisplayObserver()->getVideoSourceInfo(sessionID, &videoInfo);
+            if (ret == NO_ERROR) {
+                ITRACE("width = %d, height = %d, fps = %d", videoInfo.width, videoInfo.height,
+                        videoInfo.frameRate);
+                if (videoInfo.frameRate > 0) {
+                    mVideoFramerate = videoInfo.frameRate;
+                }
+            }
+        }
+        mFirstVideoFrame = false;
+    }
+    inputFrameInfo.contentFrameRateN = mVideoFramerate;
+    inputFrameInfo.contentFrameRateD = 1;
+
+    sp<ComposeTask> composeTask;
+    sp<RefBase> heldBuffer;
+    Mutex::Autolock _l(mTaskLock);
+
+    if (mCurrentConfig.policy.scaledWidth == 0 || mCurrentConfig.policy.scaledHeight == 0) {
+        queueFrameTypeInfo(inputFrameInfo);
+        return true; // This isn't a failure, WiDi just doesn't want frames right now.
+    }
+
+    IVideoPayloadManager::Buffer info;
+    if (!getFrameOfSize(mCurrentConfig.policy.scaledWidth, mCurrentConfig.policy.scaledHeight, metadata, info)) {
+        ITRACE("Extended mode waiting for scaled frame");
+        return false;
+    }
+
+    queueFrameTypeInfo(inputFrameInfo);
+
+    heldBuffer = new HeldDecoderBuffer(this, cachedBuffer);
+    int64_t mediaTimestamp = metadata.timestamp;
+
+    VARectangle surface_region;
+    surface_region.x = info.offsetX;
+    surface_region.y = info.offsetY;
+    surface_region.width = info.width;
+    surface_region.height = info.height;
+    FrameInfo outputFrameInfo = inputFrameInfo;
+    outputFrameInfo.bufferFormat = metadata.format;
+
+    outputFrameInfo.contentWidth = info.width;
+    outputFrameInfo.contentHeight = info.height;
+    outputFrameInfo.bufferWidth = info.bufWidth;
+    outputFrameInfo.bufferHeight = info.bufHeight;
+    outputFrameInfo.lumaUStride = info.lumaStride;
+    outputFrameInfo.chromaUStride = info.chromaUStride;
+    outputFrameInfo.chromaVStride = info.chromaVStride;
+
+    if (outputFrameInfo.bufferFormat == 0 ||
+        outputFrameInfo.bufferWidth < outputFrameInfo.contentWidth ||
+        outputFrameInfo.bufferHeight < outputFrameInfo.contentHeight ||
+        outputFrameInfo.contentWidth <= 0 || outputFrameInfo.contentHeight <= 0 ||
+        outputFrameInfo.lumaUStride <= 0 ||
+        outputFrameInfo.chromaUStride <= 0 || outputFrameInfo.chromaVStride <= 0) {
+        ITRACE("Payload cleared or inconsistent info, not sending frame");
+        ITRACE("outputFrameInfo.bufferFormat  = %d ", outputFrameInfo.bufferFormat);
+        ITRACE("outputFrameInfo.bufferWidth   = %d ", outputFrameInfo.bufferWidth);
+        ITRACE("outputFrameInfo.contentWidth  = %d ", outputFrameInfo.contentWidth);
+        ITRACE("outputFrameInfo.bufferHeight  = %d ", outputFrameInfo.bufferHeight);
+        ITRACE("outputFrameInfo.contentHeight = %d ", outputFrameInfo.contentHeight);
+        ITRACE("outputFrameInfo.lumaUStride   = %d ", outputFrameInfo.lumaUStride);
+        ITRACE("outputFrameInfo.chromaUStride = %d ", outputFrameInfo.chromaUStride);
+        ITRACE("outputFrameInfo.chromaVStride = %d ", outputFrameInfo.chromaVStride);
+        return false;
+    }
+
+    if (mCurrentConfig.policy.scaledWidth == 0 || mCurrentConfig.policy.scaledHeight == 0)
+        return true; // This isn't a failure, WiDi just doesn't want frames right now.
+
+    if (info.khandle == mExtLastKhandle && mediaTimestamp == mExtLastTimestamp) {
+        // Same frame again. We don't send a frame, but we return true because
+        // this isn't an error.
+        if (metadata.transform != 0)
+            mVspInUse = true; // Don't shut down VSP just to start it again really quick.
+        return true;
+    }
+    mExtLastKhandle = info.khandle;
+    mExtLastTimestamp = mediaTimestamp;
+
+    HWCBufferHandleType handleType = HWC_HANDLE_TYPE_KBUF;
+
+    buffer_handle_t handle = info.khandle;
+
+    // Ideally we'd check if there's an offset (info.offsetX > 0 || info.offsetY > 0),
+    // so we use VSP only when cropping is needed. But using the khandle directly when
+    // both rotation and scaling are involved can encode the frame with the wrong
+    // tiling status, so use VSP to normalize if any rotation is involved.
+    if (metadata.transform != 0) {
+        // Cropping (or above workaround) needed, so use VSP to do it.
+        mVspInUse = true;
+        vspPrepare(info.width, info.height);
+
+        composeTask = new ComposeTask();
+        composeTask->heldVideoBuffer = heldBuffer;
+        heldBuffer = NULL;
+        composeTask->outWidth = info.width;
+        composeTask->outHeight = info.height;
+        composeTask->outputHandle = mCscBuffers.get(composeTask->outWidth, composeTask->outHeight, &heldBuffer);
+        if (composeTask->outputHandle == NULL) {
+            ITRACE("Out of CSC buffers, dropping frame");
+            return true;
+        }
+
+        composeTask->surface_region = surface_region;
+        composeTask->videoCachedBuffer = cachedBuffer;
+        VARectangle& output_region = composeTask->output_region;
+        output_region.x = 0;
+        output_region.y = 0;
+        output_region.width = info.width;
+        output_region.height = info.height;
+
+        composeTask->videoKhandle = info.khandle;
+        composeTask->videoStride = info.lumaStride;
+        composeTask->videoBufHeight = info.bufHeight;
+        composeTask->videoTiled = info.tiled;
+
+        BufferManager* mgr = mHwc.getBufferManager();
+        DataBuffer* dataBuf = mgr->lockDataBuffer(composeTask->outputHandle);
+        outputFrameInfo.contentWidth = composeTask->outWidth;
+        outputFrameInfo.contentHeight = composeTask->outHeight;
+        outputFrameInfo.bufferWidth = dataBuf->getWidth();
+        outputFrameInfo.bufferHeight = dataBuf->getHeight();
+        outputFrameInfo.lumaUStride = dataBuf->getWidth();
+        outputFrameInfo.chromaUStride = dataBuf->getWidth();
+        outputFrameInfo.chromaVStride = dataBuf->getWidth();
+        mgr->unlockDataBuffer(dataBuf);
+
+        handle = composeTask->outputHandle;
+        handleType = HWC_HANDLE_TYPE_GRALLOC;
+
+        mTasks.push_back(composeTask);
+        mRequestQueued.signal();
+    }
+
+    queueBufferInfo(outputFrameInfo);
+
+    if (mCurrentConfig.frameListener != NULL) {
+        sp<OnFrameReadyTask> frameReadyTask = new OnFrameReadyTask();
+        frameReadyTask->renderTask = composeTask;
+        frameReadyTask->heldBuffer = heldBuffer;
+        frameReadyTask->frameListener = mCurrentConfig.frameListener;
+        frameReadyTask->handle = handle;
+        frameReadyTask->handleType = handleType;
+        frameReadyTask->renderTimestamp = mRenderTimestamp;
+        frameReadyTask->mediaTimestamp = mediaTimestamp;
+
+        mTasks.push_back(frameReadyTask);
+        mRequestQueued.signal();
+    }
+
+    return true;
+}
+
+void VirtualDevice::queueFrameTypeInfo(const FrameInfo& inputFrameInfo)
+{
+    if (mCurrentConfig.forceNotifyFrameType ||
+        memcmp(&inputFrameInfo, &mLastInputFrameInfo, sizeof(inputFrameInfo)) != 0) {
+        // something changed, notify type change listener
+        mNextConfig.forceNotifyFrameType = false;
+        mLastInputFrameInfo = inputFrameInfo;
+
+        sp<FrameTypeChangedTask> notifyTask = new FrameTypeChangedTask;
+        notifyTask->typeChangeListener = mCurrentConfig.typeChangeListener;
+        notifyTask->inputFrameInfo = inputFrameInfo;
+        mTasks.push_back(notifyTask);
+    }
+}
+
+void VirtualDevice::queueBufferInfo(const FrameInfo& outputFrameInfo)
+{
+    if (mCurrentConfig.forceNotifyBufferInfo ||
+        memcmp(&outputFrameInfo, &mLastOutputFrameInfo, sizeof(outputFrameInfo)) != 0) {
+        mNextConfig.forceNotifyBufferInfo = false;
+        mLastOutputFrameInfo = outputFrameInfo;
+
+        sp<BufferInfoChangedTask> notifyTask = new BufferInfoChangedTask;
+        notifyTask->typeChangeListener = mCurrentConfig.typeChangeListener;
+        notifyTask->outputFrameInfo = outputFrameInfo;
+
+        //if (handleType == HWC_HANDLE_TYPE_GRALLOC)
+        //    mMappedBufferCache.clear(); // !
+        mTasks.push_back(notifyTask);
+    }
+}
+
+void VirtualDevice::colorSwap(buffer_handle_t src, buffer_handle_t dest, uint32_t pixelCount)
+{
+    sp<CachedBuffer> srcCachedBuffer;
+    sp<CachedBuffer> destCachedBuffer;
+
+    {
+        srcCachedBuffer = getMappedBuffer(src);
+        if (srcCachedBuffer == NULL || srcCachedBuffer->mapper == NULL)
+            return;
+        destCachedBuffer = getMappedBuffer(dest);
+        if (destCachedBuffer == NULL || destCachedBuffer->mapper == NULL)
+            return;
+    }
+
+    uint8_t* srcPtr = static_cast<uint8_t*>(srcCachedBuffer->mapper->getCpuAddress(0));
+    uint8_t* destPtr = static_cast<uint8_t*>(destCachedBuffer->mapper->getCpuAddress(0));
+    if (srcPtr == NULL || destPtr == NULL)
+        return;
+    while (pixelCount > 0) {
+        destPtr[0] = srcPtr[2];
+        destPtr[1] = srcPtr[1];
+        destPtr[2] = srcPtr[0];
+        destPtr[3] = srcPtr[3];
+        srcPtr += 4;
+        destPtr += 4;
+        pixelCount--;
+    }
+}
+
+void VirtualDevice::vspPrepare(uint32_t width, uint32_t height)
+{
+    if (mVspEnabled && width == mVspWidth && height == mVspHeight)
+        return;
+
+    if (mVspEnabled)
+    {
+        ITRACE("Going to switch VSP from %ux%u to %ux%u", mVspWidth, mVspHeight, width, height);
+        mMappedBufferCache.clear();
+        mVaMapCache.clear();
+        sp<DisableVspTask> disableVsp = new DisableVspTask();
+        mTasks.push_back(disableVsp);
+    }
+    mVspWidth = width;
+    mVspHeight = height;
+
+    sp<EnableVspTask> enableTask = new EnableVspTask();
+    enableTask->width = width;
+    enableTask->height = height;
+    mTasks.push_back(enableTask);
+    mRequestQueued.signal();
+    // to map a buffer from this thread, we need this task to complete on the other thread
+    while (enableTask->getStrongCount() > 1) {
+        VTRACE("Waiting for WidiBlit thread to enable VSP...");
+        mRequestDequeued.wait(mTaskLock);
+    }
+    mVspEnabled = true;
+}
+
+void VirtualDevice::vspEnable(uint32_t width, uint32_t height)
+{
+    width = align_width(width);
+    height = align_height(height);
+    ITRACE("Start VSP at %ux%u", width, height);
+    VAStatus va_status;
+
+    int display = 0;
+    int major_ver, minor_ver;
+    va_dpy = vaGetDisplay(&display);
+    va_status = vaInitialize(va_dpy, &major_ver, &minor_ver);
+    if (va_status != VA_STATUS_SUCCESS) ETRACE("vaInitialize returns %08x", va_status);
+
+    VAConfigAttrib va_attr;
+    va_attr.type = VAConfigAttribRTFormat;
+    va_status = vaGetConfigAttributes(va_dpy,
+                VAProfileNone,
+                VAEntrypointVideoProc,
+                &va_attr,
+                1);
+    if (va_status != VA_STATUS_SUCCESS) ETRACE("vaGetConfigAttributes returns %08x", va_status);
+
+    va_status = vaCreateConfig(
+                va_dpy,
+                VAProfileNone,
+                VAEntrypointVideoProc,
+                &(va_attr),
+                1,
+                &va_config
+                );
+    if (va_status != VA_STATUS_SUCCESS) ETRACE("vaCreateConfig returns %08x", va_status);
+
+    VADisplayAttribute attr;
+    attr.type = VADisplayAttribRenderMode;
+    attr.value = VA_RENDER_MODE_LOCAL_OVERLAY;
+    va_status = vaSetDisplayAttributes(va_dpy, &attr, 1);
+    if (va_status != VA_STATUS_SUCCESS) ETRACE("vaSetDisplayAttributes returns %08x", va_status);
+
+
+    va_status = vaCreateSurfaces(
+                va_dpy,
+                VA_RT_FORMAT_YUV420,
+                width,
+                height,
+                &va_blank_yuv_in,
+                1,
+                NULL,
+                0);
+    if (va_status != VA_STATUS_SUCCESS) ETRACE("vaCreateSurfaces (video in) returns %08x", va_status);
+
+    unsigned long buffer;
+    VASurfaceAttribExternalBuffers buf;
+    int stride = align_width(width);
+    int bufHeight = align_height(height);
+    buf.pixel_format = VA_FOURCC_RGBA;
+    buf.width = width;
+    buf.height = height;
+    buf.data_size = stride * bufHeight * 4;
+    buf.num_planes = 3;
+    buf.pitches[0] = stride;
+    buf.pitches[1] = stride;
+    buf.pitches[2] = stride;
+    buf.pitches[3] = 0;
+    buf.offsets[0] = 0;
+    buf.offsets[1] = stride * bufHeight;
+    buf.offsets[2] = buf.offsets[1];
+    buf.offsets[3] = 0;
+    buf.buffers = &buffer;
+    buf.num_buffers = 1;
+    buf.flags = 0;
+    buf.private_data = NULL;
+
+    VASurfaceAttrib attrib_list[2];
+    attrib_list[0].type = (VASurfaceAttribType)VASurfaceAttribMemoryType;
+    attrib_list[0].flags = VA_SURFACE_ATTRIB_SETTABLE;
+    attrib_list[0].value.type = VAGenericValueTypeInteger;
+    attrib_list[0].value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_VA;
+    attrib_list[1].type = (VASurfaceAttribType)VASurfaceAttribExternalBufferDescriptor;
+    attrib_list[1].flags = VA_SURFACE_ATTRIB_SETTABLE;
+    attrib_list[1].value.type = VAGenericValueTypePointer;
+    attrib_list[1].value.value.p = (void *)&buf;
+
+    va_status = vaCreateSurfaces(
+                va_dpy,
+                VA_RT_FORMAT_RGB32,
+                stride,
+                bufHeight,
+                &va_blank_rgb_in,
+                1,
+                attrib_list,
+                2);
+    if (va_status != VA_STATUS_SUCCESS) ETRACE("vaCreateSurfaces (blank rgba in) returns %08x", va_status);
+
+    va_status = vaCreateContext(
+                va_dpy,
+                va_config,
+                stride,
+                bufHeight,
+                0,
+                &va_blank_yuv_in /* not used by VSP, but libva checks for it */,
+                1,
+                &va_context);
+    if (va_status != VA_STATUS_SUCCESS) ETRACE("vaCreateContext returns %08x", va_status);
+
+    VASurfaceID tmp_yuv;
+    va_status = vaCreateSurfaces(
+                va_dpy,
+                VA_RT_FORMAT_YUV420,
+                stride,
+                bufHeight,
+                &tmp_yuv,
+                1,
+                NULL,
+                0);
+    if (va_status != VA_STATUS_SUCCESS) ETRACE("vaCreateSurfaces (temp yuv) returns %08x", va_status);
+    {
+        MappedSurface mappedVideoIn(va_dpy, tmp_yuv);
+        if (mappedVideoIn.valid()) {
+            // Value doesn't matter, as RGBA will be opaque,
+            // but I don't want random data in here.
+            memset(mappedVideoIn.getPtr(), 0x0, width*height*3/2);
+        }
+        else
+            ETRACE("Unable to map tmp black surface");
+    }
+
+    {
+        MappedSurface mappedBlankIn(va_dpy, va_blank_rgb_in);
+        if (mappedBlankIn.valid()) {
+            // Fill RGBA with opaque black temporarily, in order to generate an
+            // encrypted black buffer in va_blank_yuv_in to use in place of the
+            // real frame data during the short interval where we're waiting for
+            // downscaling to kick in.
+            uint32_t* pixels = reinterpret_cast<uint32_t*>(mappedBlankIn.getPtr());
+            for (size_t i = 0; i < stride*height; i++)
+                pixels[i] = 0xff000000;
+        }
+        else
+            ETRACE("Unable to map blank rgba in");
+    }
+
+    // Compose opaque black with temp yuv to produce encrypted black yuv.
+    VARectangle region;
+    region.x = 0;
+    region.y = 0;
+    region.width = width;
+    region.height = height;
+    vspCompose(tmp_yuv, va_blank_rgb_in, va_blank_yuv_in, &region, &region);
+
+    va_status = vaDestroySurfaces(va_dpy, &tmp_yuv, 1);
+    if (va_status != VA_STATUS_SUCCESS) ETRACE("vaDestroySurfaces (temp yuv) returns %08x", va_status);
+
+    {
+        // Fill RGBA with transparent black now, to be used when there is no
+        // UI to compose on top of the video.
+        MappedSurface mappedBlankIn(va_dpy, va_blank_rgb_in);
+        if (mappedBlankIn.valid())
+            memset(mappedBlankIn.getPtr(), 0, stride*height*4);
+        else
+            ETRACE("Unable to map blank rgba in");
+    }
+}
+
+void VirtualDevice::vspDisable()
+{
+    ITRACE("Shut down VSP");
+
+    if (va_context == 0 && va_blank_yuv_in == 0) {
+        ITRACE("Already shut down");
+        return;
+    }
+
+    VABufferID pipeline_param_id;
+    VAStatus va_status;
+    va_status = vaCreateBuffer(va_dpy,
+                va_context,
+                VAProcPipelineParameterBufferType,
+                sizeof(VAProcPipelineParameterBuffer),
+                1,
+                NULL,
+                &pipeline_param_id);
+    if (va_status != VA_STATUS_SUCCESS) ETRACE("vaCreateBuffer returns %08x", va_status);
+
+    VABlendState blend_state;
+    VAProcPipelineParameterBuffer *pipeline_param;
+    va_status = vaMapBuffer(va_dpy,
+                pipeline_param_id,
+                (void **)&pipeline_param);
+    if (va_status != VA_STATUS_SUCCESS) ETRACE("vaMapBuffer returns %08x", va_status);
+
+    memset(pipeline_param, 0, sizeof(VAProcPipelineParameterBuffer));
+    pipeline_param->pipeline_flags = VA_PIPELINE_FLAG_END;
+    pipeline_param->num_filters = 0;
+    pipeline_param->blend_state = &blend_state;
+
+    va_status = vaUnmapBuffer(va_dpy, pipeline_param_id);
+    if (va_status != VA_STATUS_SUCCESS) ETRACE("vaUnmapBuffer returns %08x", va_status);
+
+    va_status = vaBeginPicture(va_dpy, va_context, va_blank_yuv_in /* just need some valid surface */);
+    if (va_status != VA_STATUS_SUCCESS) ETRACE("vaBeginPicture returns %08x", va_status);
+
+    va_status = vaRenderPicture(va_dpy, va_context, &pipeline_param_id, 1);
+    if (va_status != VA_STATUS_SUCCESS) ETRACE("vaRenderPicture returns %08x", va_status);
+
+    va_status = vaEndPicture(va_dpy, va_context);
+    if (va_status != VA_STATUS_SUCCESS) ETRACE("vaEndPicture returns %08x", va_status);
+
+    va_status = vaDestroyContext(va_dpy, va_context);
+    if (va_status != VA_STATUS_SUCCESS) ETRACE("vaDestroyContext returns %08x", va_status);
+    va_context = 0;
+
+    va_status = vaDestroySurfaces(va_dpy, &va_blank_yuv_in, 1);
+    if (va_status != VA_STATUS_SUCCESS) ETRACE("vaDestroySurfaces (video in) returns %08x", va_status);
+    va_blank_yuv_in = 0;
+
+    va_status = vaDestroySurfaces(va_dpy, &va_blank_rgb_in, 1);
+    if (va_status != VA_STATUS_SUCCESS) ETRACE("vaDestroySurfaces (blank rgba in) returns %08x", va_status);
+
+    if (va_config) {
+        vaDestroyConfig(va_dpy, va_config);
+        va_config = 0;
+    }
+    if (va_dpy) {
+        vaTerminate(va_dpy);
+        va_dpy = NULL;
+    }
+}
+
+void VirtualDevice::vspCompose(VASurfaceID videoIn, VASurfaceID rgbIn, VASurfaceID videoOut,
+                               const VARectangle* surface_region, const VARectangle* output_region)
+{
+    VAStatus va_status;
+
+    VABufferID pipeline_param_id;
+    va_status = vaCreateBuffer(va_dpy,
+                va_context,
+                VAProcPipelineParameterBufferType,
+                sizeof(VAProcPipelineParameterBuffer),
+                1,
+                NULL,
+                &pipeline_param_id);
+    if (va_status != VA_STATUS_SUCCESS) ETRACE("vaCreateBuffer returns %08x", va_status);
+
+    VABlendState blend_state;
+
+    VAProcPipelineParameterBuffer *pipeline_param;
+    va_status = vaMapBuffer(va_dpy,
+                pipeline_param_id,
+                (void **)&pipeline_param);
+    if (va_status != VA_STATUS_SUCCESS) ETRACE("vaMapBuffer returns %08x", va_status);
+
+    memset(pipeline_param, 0, sizeof(VAProcPipelineParameterBuffer));
+    pipeline_param->surface = videoIn;
+    pipeline_param->surface_region = surface_region;
+    pipeline_param->output_region = output_region;
+
+    pipeline_param->pipeline_flags = 0;
+    pipeline_param->num_filters = 0;
+    pipeline_param->blend_state = &blend_state;
+    pipeline_param->num_additional_outputs = 1;
+    pipeline_param->additional_outputs = &rgbIn;
+
+    va_status = vaUnmapBuffer(va_dpy, pipeline_param_id);
+    if (va_status != VA_STATUS_SUCCESS) ETRACE("vaUnmapBuffer returns %08x", va_status);
+
+    va_status = vaBeginPicture(va_dpy, va_context, videoOut);
+    if (va_status != VA_STATUS_SUCCESS) ETRACE("vaBeginPicture returns %08x", va_status);
+
+    va_status = vaRenderPicture(va_dpy, va_context, &pipeline_param_id, 1);
+    if (va_status != VA_STATUS_SUCCESS) ETRACE("vaRenderPicture returns %08x", va_status);
+
+    va_status = vaEndPicture(va_dpy, va_context);
+    if (va_status != VA_STATUS_SUCCESS) ETRACE("vaEndPicture returns %08x", va_status);
+
+    va_status = vaSyncSurface(va_dpy, videoOut);
+    if (va_status != VA_STATUS_SUCCESS) ETRACE("vaSyncSurface returns %08x", va_status);
+}
+
+static uint32_t min(uint32_t a, uint32_t b)
+{
+    return (a < b) ? a : b;
+}
+
+bool VirtualDevice::getFrameOfSize(uint32_t width, uint32_t height, const IVideoPayloadManager::MetaData& metadata, IVideoPayloadManager::Buffer& info)
+{
+    if (metadata.transform == 0 || metadata.transform == HAL_TRANSFORM_ROT_180)
+        setMaxDecodeResolution(min(width, metadata.normalBuffer.width), min(height, metadata.normalBuffer.height));
+    else
+        setMaxDecodeResolution(min(height, metadata.normalBuffer.width), min(width, metadata.normalBuffer.height));
+
+    if (metadata.transform == 0) {
+        if (metadata.normalBuffer.khandle != 0 && metadata.normalBuffer.width <= width && metadata.normalBuffer.height <= height) {
+            info = metadata.normalBuffer;
+            return true;
+        }
+
+        if (metadata.scalingBuffer.khandle != 0 && metadata.scalingBuffer.width <= width && metadata.scalingBuffer.height <= height) {
+            info = metadata.scalingBuffer;
+            return true;
+        }
+    } else {
+        if (metadata.rotationBuffer.khandle != 0 && metadata.rotationBuffer.width <= width && metadata.rotationBuffer.height <= height) {
+            info = metadata.rotationBuffer;
+            return true;
+        }
+    }
+
+    return false;
+}
+
+void VirtualDevice::setMaxDecodeResolution(uint32_t width, uint32_t height)
+{
+    if (mDecWidth == width && mDecHeight == height)
+        return;
+
+    int sessionID = mHwc.getDisplayAnalyzer()->getFirstVideoInstanceSessionID();
+    if (sessionID < 0) {
+        ETRACE("Session id is less than 0");
+        return;
+    }
+
+    MultiDisplayObserver* mds = mHwc.getMultiDisplayObserver();
+    status_t ret = mds->setDecoderOutputResolution(sessionID, width, height, 0, 0, width, height);
+    if (ret != NO_ERROR) {
+        ETRACE("Failed to set scaling to %ux%u: %x", width, height, ret);
+        return;
+    }
+
+    mDecWidth = width;
+    mDecHeight = height;
+    ITRACE("Set scaling to %ux%u",mDecWidth, mDecHeight);
+}
+
+bool VirtualDevice::vsyncControl(bool enabled)
+{
+    RETURN_FALSE_IF_NOT_INIT();
+    return mVsyncObserver->control(enabled);
+}
+
+bool VirtualDevice::blank(bool blank)
+{
+    RETURN_FALSE_IF_NOT_INIT();
+    return true;
+}
+
+bool VirtualDevice::getDisplaySize(int *width, int *height)
+{
+    RETURN_FALSE_IF_NOT_INIT();
+    if (!width || !height) {
+        ETRACE("invalid parameters");
+        return false;
+    }
+
+    // TODO: make this platform specifc
+    *width = 1280;
+    *height = 720;
+    return true;
+}
+
+bool VirtualDevice::getDisplayConfigs(uint32_t *configs,
+                                         size_t *numConfigs)
+{
+    RETURN_FALSE_IF_NOT_INIT();
+    if (!configs || !numConfigs) {
+        ETRACE("invalid parameters");
+        return false;
+    }
+
+    *configs = 0;
+    *numConfigs = 1;
+
+    return true;
+}
+
+bool VirtualDevice::getDisplayAttributes(uint32_t configs,
+                                            const uint32_t *attributes,
+                                            int32_t *values)
+{
+    RETURN_FALSE_IF_NOT_INIT();
+
+    if (!attributes || !values) {
+        ETRACE("invalid parameters");
+        return false;
+    }
+
+    int i = 0;
+    while (attributes[i] != HWC_DISPLAY_NO_ATTRIBUTE) {
+        switch (attributes[i]) {
+        case HWC_DISPLAY_VSYNC_PERIOD:
+            values[i] = 1e9 / 60;
+            break;
+        case HWC_DISPLAY_WIDTH:
+            values[i] = 1280;
+            break;
+        case HWC_DISPLAY_HEIGHT:
+            values[i] = 720;
+            break;
+        case HWC_DISPLAY_DPI_X:
+            values[i] = 0;
+            break;
+        case HWC_DISPLAY_DPI_Y:
+            values[i] = 0;
+            break;
+        default:
+            ETRACE("unknown attribute %d", attributes[i]);
+            break;
+        }
+        i++;
+    }
+
+    return true;
+}
+
+bool VirtualDevice::compositionComplete()
+{
+    RETURN_FALSE_IF_NOT_INIT();
+    return true;
+}
+
+bool VirtualDevice::initialize()
+{
+    // Add initialization codes here. If init fails, invoke DEINIT_AND_RETURN_FALSE();
+    mNextConfig.typeChangeListener = NULL;
+    mNextConfig.policy.scaledWidth = 0;
+    mNextConfig.policy.scaledHeight = 0;
+    mNextConfig.policy.xdpi = 96;
+    mNextConfig.policy.ydpi = 96;
+    mNextConfig.policy.refresh = 60;
+    mNextConfig.extendedModeEnabled = false;
+    mNextConfig.forceNotifyFrameType = false;
+    mNextConfig.forceNotifyBufferInfo = false;
+    mCurrentConfig = mNextConfig;
+    mRgbLayer = -1;
+    mYuvLayer = -1;
+
+    memset(&mLastInputFrameInfo, 0, sizeof(mLastInputFrameInfo));
+    memset(&mLastOutputFrameInfo, 0, sizeof(mLastOutputFrameInfo));
+
+    mPayloadManager = mHwc.getPlatFactory()->createVideoPayloadManager();
+
+    if (!mPayloadManager) {
+        DEINIT_AND_RETURN_FALSE("Failed to create payload manager");
+    }
+
+    mVsyncObserver = new SoftVsyncObserver(*this);
+    if (!mVsyncObserver || !mVsyncObserver->initialize()) {
+        DEINIT_AND_RETURN_FALSE("Failed to create Soft Vsync Observer");
+    }
+
+    mSyncTimelineFd = sw_sync_timeline_create();
+    mNextSyncPoint = 1;
+    mExpectAcquireFences = false;
+
+    mThread = new WidiBlitThread(this);
+    mThread->run("WidiBlit", PRIORITY_URGENT_DISPLAY);
+
+    // Publish frame server service with service manager
+    status_t ret = defaultServiceManager()->addService(String16("hwc.widi"), this);
+    if (ret == NO_ERROR) {
+        ProcessState::self()->startThreadPool();
+        mInitialized = true;
+    } else {
+        ETRACE("Could not register hwc.widi with service manager, error = %d", ret);
+        deinitialize();
+    }
+
+    mVspEnabled = false;
+    mVspInUse = false;
+    mVspWidth = 0;
+    mVspHeight = 0;
+    va_dpy = NULL;
+    va_config = 0;
+    va_context = 0;
+    va_blank_yuv_in = 0;
+    va_blank_rgb_in = 0;
+    mVspUpscale = false;
+    mDebugVspClear = false;
+    mDebugVspDump = false;
+    mDebugCounter = 0;
+
+    ITRACE("Init done.");
+
+    return mInitialized;
+}
+
+bool VirtualDevice::isConnected() const
+{
+    return true;
+}
+
+const char* VirtualDevice::getName() const
+{
+    return "Virtual";
+}
+
+int VirtualDevice::getType() const
+{
+    return DEVICE_VIRTUAL;
+}
+
+void VirtualDevice::onVsync(int64_t timestamp)
+{
+    mHwc.vsync(DEVICE_VIRTUAL, timestamp);
+}
+
+void VirtualDevice::dump(Dump& d)
+{
+}
+
+void VirtualDevice::deinitialize()
+{
+    VAStatus va_status;
+
+    if (mPayloadManager) {
+        delete mPayloadManager;
+        mPayloadManager = NULL;
+    }
+    DEINIT_AND_DELETE_OBJ(mVsyncObserver);
+    mInitialized = false;
+}
+
+bool VirtualDevice::setPowerMode(int /*mode*/)
+{
+    return true;
+}
+
+int VirtualDevice::getActiveConfig()
+{
+    return 0;
+}
+
+bool VirtualDevice::setActiveConfig(int /*index*/)
+{
+    return false;
+}
+
+} // namespace intel
+} // namespace android
diff --git a/merrifield/common/observers/MultiDisplayObserver.cpp b/merrifield/common/observers/MultiDisplayObserver.cpp
new file mode 100755
index 0000000..9f767b9
--- /dev/null
+++ b/merrifield/common/observers/MultiDisplayObserver.cpp
@@ -0,0 +1,439 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifdef TARGET_HAS_MULTIPLE_DISPLAY
+#include <HwcTrace.h>
+#include <binder/IServiceManager.h>
+#include <Hwcomposer.h>
+#include <DisplayAnalyzer.h>
+#include <ExternalDevice.h>
+#endif
+
+#include <MultiDisplayObserver.h>
+
+namespace android {
+namespace intel {
+
+#ifdef TARGET_HAS_MULTIPLE_DISPLAY
+
+////// MultiDisplayCallback
+
+MultiDisplayCallback::MultiDisplayCallback(MultiDisplayObserver *dispObserver)
+    : mDispObserver(dispObserver),
+      mVideoState(MDS_VIDEO_STATE_UNKNOWN)
+{
+}
+
+MultiDisplayCallback::~MultiDisplayCallback()
+{
+    CTRACE();
+    mDispObserver = NULL;
+}
+
+status_t MultiDisplayCallback::blankSecondaryDisplay(bool blank)
+{
+    ITRACE("blank: %d", blank);
+    mDispObserver->blankSecondaryDisplay(blank);
+    return NO_ERROR;
+}
+
+status_t MultiDisplayCallback::updateVideoState(int sessionId, MDS_VIDEO_STATE state)
+{
+    mVideoState = state;
+    ITRACE("state: %d", state);
+    mDispObserver->updateVideoState(sessionId, state);
+    return NO_ERROR;
+}
+
+status_t MultiDisplayCallback::setHdmiTiming(const MDSHdmiTiming& timing)
+{
+    mDispObserver->setHdmiTiming(timing);
+    return NO_ERROR;
+}
+
+status_t MultiDisplayCallback::updateInputState(bool state)
+{
+    //ITRACE("input state: %d", state);
+    mDispObserver->updateInputState(state);
+    return NO_ERROR;
+}
+
+status_t MultiDisplayCallback::setHdmiScalingType(MDS_SCALING_TYPE type)
+{
+    ITRACE("scaling type: %d", type);
+    // Merrifield doesn't implement this API
+    return INVALID_OPERATION;
+}
+
+status_t MultiDisplayCallback::setHdmiOverscan(int hValue, int vValue)
+{
+    ITRACE("oversacn compensation, h: %d v: %d", hValue, vValue);
+    // Merrifield doesn't implement this API
+    return INVALID_OPERATION;
+}
+
+////// MultiDisplayObserver
+
+MultiDisplayObserver::MultiDisplayObserver()
+    : mMDSCbRegistrar(NULL),
+      mMDSInfoProvider(NULL),
+      mMDSConnObserver(NULL),
+      mMDSDecoderConfig(NULL),
+      mMDSCallback(NULL),
+      mLock(),
+      mCondition(),
+      mThreadLoopCount(0),
+      mDeviceConnected(false),
+      mExternalHdmiTiming(false),
+      mInitialized(false)
+{
+    CTRACE();
+}
+
+MultiDisplayObserver::~MultiDisplayObserver()
+{
+    WARN_IF_NOT_DEINIT();
+}
+
+bool MultiDisplayObserver::isMDSRunning()
+{
+    // Check if Multi Display service is running
+    sp<IServiceManager> sm = defaultServiceManager();
+    if (sm == NULL) {
+        ETRACE("fail to get service manager!");
+        return false;
+    }
+
+    sp<IBinder> service = sm->checkService(String16(INTEL_MDS_SERVICE_NAME));
+    if (service == NULL) {
+        VTRACE("fail to get MultiDisplay service!");
+        return false;
+    }
+
+    return true;
+}
+
+bool MultiDisplayObserver::initMDSClient()
+{
+    sp<IServiceManager> sm = defaultServiceManager();
+    if (sm == NULL) {
+        ETRACE("Fail to get service manager");
+        return false;
+    }
+    sp<IMDService> mds = interface_cast<IMDService>(
+            sm->getService(String16(INTEL_MDS_SERVICE_NAME)));
+    if (mds == NULL) {
+        ETRACE("Fail to get MDS service");
+        return false;
+    }
+    mMDSCbRegistrar = mds->getCallbackRegistrar();
+    if (mMDSCbRegistrar.get() == NULL) {
+        ETRACE("failed to create mds base Client");
+        return false;
+    }
+
+    mMDSCallback = new MultiDisplayCallback(this);
+    if (mMDSCallback.get() == NULL) {
+        ETRACE("failed to create MultiDisplayCallback");
+        deinitMDSClient();
+        return false;
+    }
+    mMDSInfoProvider = mds->getInfoProvider();
+    if (mMDSInfoProvider.get() == NULL) {
+        ETRACE("failed to create mds video Client");
+        return false;
+    }
+
+    mMDSConnObserver = mds->getConnectionObserver();
+    if (mMDSConnObserver.get() == NULL) {
+        ETRACE("failed to create mds video Client");
+        return false;
+    }
+    mMDSDecoderConfig = mds->getDecoderConfig();
+    if (mMDSDecoderConfig.get() == NULL) {
+        ETRACE("failed to create mds decoder Client");
+        return false;
+    }
+
+    status_t ret = mMDSCbRegistrar->registerCallback(mMDSCallback);
+    if (ret != NO_ERROR) {
+        ETRACE("failed to register callback");
+        deinitMDSClient();
+        return false;
+    }
+
+    Drm *drm = Hwcomposer::getInstance().getDrm();
+    mDeviceConnected = drm->isConnected(IDisplayDevice::DEVICE_EXTERNAL);
+    ITRACE("MDS client is initialized");
+    return true;
+}
+
+void MultiDisplayObserver::deinitMDSClient()
+{
+    if (mMDSCallback.get() && mMDSCbRegistrar.get()) {
+        mMDSCbRegistrar->unregisterCallback(mMDSCallback);
+    }
+
+    mDeviceConnected = false;
+    mMDSCbRegistrar = NULL;
+    mMDSInfoProvider = NULL;
+    mMDSCallback = NULL;
+    mMDSConnObserver = NULL;
+    mMDSDecoderConfig = NULL;
+}
+
+bool MultiDisplayObserver::initMDSClientAsync()
+{
+    if (mThread.get()) {
+        WTRACE("working thread has been already created.");
+        return true;
+    }
+
+    mThread = new MDSClientInitThread(this);
+    if (mThread.get() == NULL) {
+        ETRACE("failed to create MDS client init thread");
+        return false;
+    }
+    mThreadLoopCount = 0;
+    // TODO: check return value
+    mThread->run("MDSClientInitThread", PRIORITY_URGENT_DISPLAY);
+    return true;
+}
+
+bool MultiDisplayObserver::initialize()
+{
+    bool ret = true;
+    Mutex::Autolock _l(mLock);
+
+    if (mInitialized) {
+        WTRACE("display observer has been initialized");
+        return true;
+    }
+
+    // initialize MDS client once. This should succeed if MDS service starts
+    // before surfaceflinger service is started.
+    // if surface flinger runs first, MDS client will be initialized asynchronously in
+    // a working thread
+    if (isMDSRunning()) {
+        if (!initMDSClient()) {
+            ETRACE("failed to initialize MDS client");
+            // FIXME: NOT a common case for system server crash.
+            // Start a working thread to initialize MDS client if exception happens
+            ret = initMDSClientAsync();
+        }
+    } else {
+        ret = initMDSClientAsync();
+    }
+
+    mInitialized = true;
+    return ret;
+}
+
+void MultiDisplayObserver::deinitialize()
+{
+    sp<MDSClientInitThread> detachedThread;
+    do {
+        Mutex::Autolock _l(mLock);
+
+        if (mThread.get()) {
+            mCondition.signal();
+            detachedThread = mThread;
+            mThread = NULL;
+        }
+        mThreadLoopCount = 0;
+        deinitMDSClient();
+        mInitialized = false;
+    } while (0);
+
+    if (detachedThread.get()) {
+        detachedThread->requestExitAndWait();
+        detachedThread = NULL;
+    }
+}
+
+bool MultiDisplayObserver::threadLoop()
+{
+    Mutex::Autolock _l(mLock);
+
+    // try to create MDS client in the working thread
+    // multiple delayed attempts are made until MDS service starts.
+
+    // Return false if MDS service is running or loop limit is reached
+    // such that thread becomes inactive.
+    if (isMDSRunning()) {
+        if (!initMDSClient()) {
+            ETRACE("failed to initialize MDS client");
+        }
+        return false;
+    }
+
+    if (mThreadLoopCount++ > THREAD_LOOP_BOUND) {
+        ETRACE("failed to initialize MDS client, loop limit reached");
+        return false;
+    }
+
+    status_t err = mCondition.waitRelative(mLock, milliseconds(THREAD_LOOP_DELAY));
+    if (err != -ETIMEDOUT) {
+        ITRACE("thread is interrupted");
+        return false;
+    }
+
+    return true; // keep trying
+}
+
+
+status_t MultiDisplayObserver::blankSecondaryDisplay(bool blank)
+{
+    // blank secondary display
+    Hwcomposer::getInstance().getDisplayAnalyzer()->postBlankEvent(blank);
+    return 0;
+}
+
+status_t MultiDisplayObserver::updateVideoState(int sessionId, MDS_VIDEO_STATE state)
+{
+    Hwcomposer::getInstance().getDisplayAnalyzer()->postVideoEvent(
+        sessionId, (int)state);
+    return 0;
+}
+
+status_t MultiDisplayObserver::setHdmiTiming(const MDSHdmiTiming& timing)
+{
+    drmModeModeInfo mode;
+    mode.hdisplay = timing.width;
+    mode.vdisplay = timing.height;
+    mode.vrefresh = timing.refresh;
+    mode.flags = timing.flags;
+    ITRACE("timing to set: %dx%d@%dHz", timing.width, timing.height, timing.refresh);
+    ExternalDevice *dev =
+        (ExternalDevice *)Hwcomposer::getInstance().getDisplayDevice(HWC_DISPLAY_EXTERNAL);
+    if (dev) {
+        dev->setDrmMode(mode);
+    }
+
+    mExternalHdmiTiming = true;
+    return 0;
+}
+
+status_t MultiDisplayObserver::updateInputState(bool active)
+{
+    Hwcomposer::getInstance().getDisplayAnalyzer()->postInputEvent(active);
+    return 0;
+}
+
+
+/// Public interfaces
+
+status_t MultiDisplayObserver::notifyHotPlug( bool connected)
+{
+    {
+        // lock scope
+        Mutex::Autolock _l(mLock);
+        if (mMDSConnObserver.get() == NULL) {
+            return NO_INIT;
+        }
+
+        if (connected == mDeviceConnected) {
+            WTRACE("hotplug event ignored");
+            return NO_ERROR;
+        }
+
+        // clear it after externel device is disconnected
+        if (!connected) mExternalHdmiTiming = false;
+
+        mDeviceConnected = connected;
+    }
+    return mMDSConnObserver->updateHdmiConnectionStatus(connected);
+}
+
+status_t MultiDisplayObserver::getVideoSourceInfo(int sessionID, VideoSourceInfo* info)
+{
+    Mutex::Autolock _l(mLock);
+    if (mMDSInfoProvider.get() == NULL) {
+        return NO_INIT;
+    }
+
+    if (info == NULL) {
+        ETRACE("invalid parameter");
+        return UNKNOWN_ERROR;
+    }
+
+    MDSVideoSourceInfo videoInfo;
+    memset(&videoInfo, 0, sizeof(MDSVideoSourceInfo));
+    status_t ret = mMDSInfoProvider->getVideoSourceInfo(sessionID, &videoInfo);
+    if (ret == NO_ERROR) {
+        info->width     = videoInfo.displayW;
+        info->height    = videoInfo.displayH;
+        info->frameRate = videoInfo.frameRate;
+        info->isProtected = videoInfo.isProtected;
+        VTRACE("Video Session[%d] source info: %dx%d@%d", sessionID,
+                info->width, info->height, info->frameRate);
+    }
+    return ret;
+}
+
+int MultiDisplayObserver::getVideoSessionNumber()
+{
+    Mutex::Autolock _l(mLock);
+    if (mMDSInfoProvider.get() == NULL) {
+        return 0;
+    }
+
+    return mMDSInfoProvider->getVideoSessionNumber();
+}
+
+bool MultiDisplayObserver::isExternalDeviceTimingFixed() const
+{
+    Mutex::Autolock _l(mLock);
+    return mExternalHdmiTiming;
+}
+
+status_t MultiDisplayObserver::notifyWidiConnectionStatus( bool connected)
+{
+    Mutex::Autolock _l(mLock);
+    if (mMDSConnObserver.get() == NULL) {
+        return NO_INIT;
+    }
+    return mMDSConnObserver->updateWidiConnectionStatus(connected);
+}
+
+status_t MultiDisplayObserver::setDecoderOutputResolution(
+        int sessionID,
+        int32_t width, int32_t height,
+        int32_t offX, int32_t offY,
+        int32_t bufWidth, int32_t bufHeight)
+{
+    Mutex::Autolock _l(mLock);
+    if (mMDSDecoderConfig.get() == NULL) {
+        return NO_INIT;
+    }
+    if (width <= 0 || height <= 0 ||
+            offX < 0 || offY < 0 ||
+            bufWidth <= 0 || bufHeight <= 0) {
+        ETRACE(" Invalid parameter: %dx%d, %dx%d, %dx%d", width, height, offX, offY, bufWidth, bufHeight);
+        return UNKNOWN_ERROR;
+    }
+
+    status_t ret = mMDSDecoderConfig->setDecoderOutputResolution(sessionID, width, height, offX, offY, bufWidth, bufHeight);
+    if (ret == NO_ERROR) {
+        ITRACE("Video Session[%d] output resolution %dx%d ", sessionID, width, height);
+    }
+    return ret;
+}
+
+
+#endif //TARGET_HAS_MULTIPLE_DISPLAY
+
+} // namespace intel
+} // namespace android
diff --git a/merrifield/common/observers/MultiDisplayObserver.h b/merrifield/common/observers/MultiDisplayObserver.h
new file mode 100755
index 0000000..44a113d
--- /dev/null
+++ b/merrifield/common/observers/MultiDisplayObserver.h
@@ -0,0 +1,141 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef __MULTIDISPLAY_OBSERVER_H
+#define __MULTIDISPLAY_OBSERVER_H
+
+#ifdef TARGET_HAS_MULTIPLE_DISPLAY
+#include <display/MultiDisplayService.h>
+#include <SimpleThread.h>
+#else
+#include <utils/Errors.h>
+#endif
+#include <string.h>
+
+namespace android {
+namespace intel {
+
+struct VideoSourceInfo {
+    VideoSourceInfo() {
+        memset(this, 0, sizeof(VideoSourceInfo));
+    }
+    int width;
+    int height;
+    int frameRate;
+    bool isProtected;
+};
+
+
+#ifdef TARGET_HAS_MULTIPLE_DISPLAY
+
+class MultiDisplayObserver;
+
+class MultiDisplayCallback : public BnMultiDisplayCallback {
+public:
+    MultiDisplayCallback(MultiDisplayObserver *observer);
+    virtual ~MultiDisplayCallback();
+
+    status_t blankSecondaryDisplay(bool blank);
+    status_t updateVideoState(int sessionId, MDS_VIDEO_STATE state);
+    status_t setHdmiTiming(const MDSHdmiTiming& timing);
+    status_t setHdmiScalingType(MDS_SCALING_TYPE type);
+    status_t setHdmiOverscan(int hValue, int vValue);
+    status_t updateInputState(bool state);
+
+private:
+    MultiDisplayObserver *mDispObserver;
+    MDS_VIDEO_STATE mVideoState;
+};
+
+class MultiDisplayObserver {
+public:
+    MultiDisplayObserver();
+    virtual ~MultiDisplayObserver();
+
+public:
+    bool initialize();
+    void deinitialize();
+    status_t notifyHotPlug(bool connected);
+    status_t getVideoSourceInfo(int sessionID, VideoSourceInfo* info);
+    int  getVideoSessionNumber();
+    bool isExternalDeviceTimingFixed() const;
+    status_t notifyWidiConnectionStatus(bool connected);
+    status_t setDecoderOutputResolution(int sessionID,
+            int32_t width, int32_t height,
+            int32_t offX,  int32_t offY,
+            int32_t bufWidth, int32_t bufHeight);
+
+private:
+    bool isMDSRunning();
+    bool initMDSClient();
+    bool initMDSClientAsync();
+    void deinitMDSClient();
+    status_t blankSecondaryDisplay(bool blank);
+    status_t updateVideoState(int sessionId, MDS_VIDEO_STATE state);
+    status_t setHdmiTiming(const MDSHdmiTiming& timing);
+    status_t updateInputState(bool active);
+    friend class MultiDisplayCallback;
+
+private:
+    enum {
+        THREAD_LOOP_DELAY = 10, // 10 ms
+        THREAD_LOOP_BOUND = 2000, // 20s
+    };
+
+private:
+    sp<IMultiDisplayCallbackRegistrar> mMDSCbRegistrar;
+    sp<IMultiDisplayInfoProvider> mMDSInfoProvider;
+    sp<IMultiDisplayConnectionObserver> mMDSConnObserver;
+    sp<IMultiDisplayDecoderConfig> mMDSDecoderConfig;
+    sp<MultiDisplayCallback> mMDSCallback;
+    mutable Mutex mLock;
+    Condition mCondition;
+    int mThreadLoopCount;
+    bool mDeviceConnected;
+    // indicate external devices's timing is set
+    bool mExternalHdmiTiming;
+    bool mInitialized;
+
+private:
+    DECLARE_THREAD(MDSClientInitThread, MultiDisplayObserver);
+};
+
+#else
+
+// dummy declaration and implementation of MultiDisplayObserver
+class MultiDisplayObserver {
+public:
+    MultiDisplayObserver() {}
+    virtual ~MultiDisplayObserver() {}
+
+    bool initialize() { return true; }
+    void deinitialize() {}
+    status_t notifyHotPlug(bool connected) { return NO_ERROR; }
+    status_t getVideoSourceInfo(int sessionID, VideoSourceInfo* info) { return INVALID_OPERATION; }
+    int  getVideoSessionNumber() { return 0; }
+    bool isExternalDeviceTimingFixed() const { return false; }
+    status_t notifyWidiConnectionStatus(bool connected) { return NO_ERROR; }
+    status_t setDecoderOutputResolution(
+            int sessionID,
+            int32_t width, int32_t height,
+            int32_t, int32_t, int32_t, int32_t) { return NO_ERROR; }
+};
+
+#endif //TARGET_HAS_MULTIPLE_DISPLAY
+
+} // namespace intel
+} // namespace android
+
+#endif /* __MULTIMultiDisplayObserver_H_ */
diff --git a/merrifield/common/observers/SoftVsyncObserver.cpp b/merrifield/common/observers/SoftVsyncObserver.cpp
new file mode 100644
index 0000000..20a6bdf
--- /dev/null
+++ b/merrifield/common/observers/SoftVsyncObserver.cpp
@@ -0,0 +1,155 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#include <HwcTrace.h>
+#include <SoftVsyncObserver.h>
+#include <IDisplayDevice.h>
+
+extern "C" int clock_nanosleep(clockid_t clock_id, int flags,
+                           const struct timespec *request,
+                           struct timespec *remain);
+
+
+namespace android {
+namespace intel {
+
+SoftVsyncObserver::SoftVsyncObserver(IDisplayDevice& disp)
+    : mDisplayDevice(disp),
+      mDevice(IDisplayDevice::DEVICE_COUNT),
+      mEnabled(false),
+      mRefreshRate(60), // default 60 frames per second
+      mRefreshPeriod(0),
+      mLock(),
+      mCondition(),
+      mNextFakeVSync(0),
+      mExitThread(false),
+      mInitialized(false)
+{
+}
+
+SoftVsyncObserver::~SoftVsyncObserver()
+{
+    WARN_IF_NOT_DEINIT();
+}
+
+bool SoftVsyncObserver::initialize()
+{
+    if (mInitialized) {
+        WTRACE("object has been initialized");
+        return true;
+    }
+
+    mExitThread = false;
+    mEnabled = false;
+    mRefreshRate = 60;
+    mDevice = mDisplayDevice.getType();
+    mThread = new VsyncEventPollThread(this);
+    if (!mThread.get()) {
+        DEINIT_AND_RETURN_FALSE("failed to create vsync event poll thread.");
+    }
+    mThread->run("SoftVsyncObserver", PRIORITY_URGENT_DISPLAY);
+    mInitialized = true;
+    return true;
+}
+
+void SoftVsyncObserver::deinitialize()
+{
+    if (mEnabled) {
+        WTRACE("soft vsync is still enabled");
+        control(false);
+    }
+
+    mExitThread = true;
+    mCondition.signal();
+
+    if (mThread.get()) {
+        mThread->requestExitAndWait();
+        mThread = NULL;
+    }
+    mInitialized = false;
+}
+
+void SoftVsyncObserver::setRefreshRate(int rate)
+{
+    if (mEnabled) {
+        WTRACE("too late to set refresh rate");
+    } else if (rate < 1 || rate > 120) {
+        WTRACE("invalid refresh rate %d", rate);
+    } else {
+        mRefreshRate = rate;
+    }
+}
+
+bool SoftVsyncObserver::control(bool enabled)
+{
+    if (enabled == mEnabled) {
+        WTRACE("vsync state %d is not changed", enabled);
+        return true;
+    }
+
+    if (enabled) {
+        mRefreshPeriod = nsecs_t(1e9 / mRefreshRate);
+        mNextFakeVSync = systemTime(CLOCK_MONOTONIC) + mRefreshPeriod;
+    }
+    mEnabled = enabled;
+    mCondition.signal();
+    return true;
+}
+
+bool SoftVsyncObserver::threadLoop()
+{
+    { // scope for lock
+        Mutex::Autolock _l(mLock);
+        while (!mEnabled) {
+            mCondition.wait(mLock);
+            if (mExitThread) {
+                ITRACE("exiting thread loop");
+                return false;
+            }
+        }
+    }
+
+
+    const nsecs_t period = mRefreshPeriod;
+    const nsecs_t now = systemTime(CLOCK_MONOTONIC);
+    nsecs_t next_vsync = mNextFakeVSync;
+    nsecs_t sleep = next_vsync - now;
+    if (sleep < 0) {
+        // we missed, find where the next vsync should be
+        sleep = (period - ((now - next_vsync) % period));
+        next_vsync = now + sleep;
+    }
+    mNextFakeVSync = next_vsync + period;
+
+    struct timespec spec;
+    spec.tv_sec  = next_vsync / 1000000000;
+    spec.tv_nsec = next_vsync % 1000000000;
+
+    int err;
+    do {
+        err = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &spec, NULL);
+    } while (err < 0 && errno == EINTR);
+
+
+    if (err == 0) {
+        mDisplayDevice.onVsync(next_vsync);
+    }
+
+    return true;
+}
+
+} // namespace intel
+} // namesapce android
+
diff --git a/merrifield/common/observers/SoftVsyncObserver.h b/merrifield/common/observers/SoftVsyncObserver.h
new file mode 100755
index 0000000..3550372
--- /dev/null
+++ b/merrifield/common/observers/SoftVsyncObserver.h
@@ -0,0 +1,59 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef SOFT_VSYNC_OBSERVER_H
+#define SOFT_VSYNC_OBSERVER_H
+
+#include <SimpleThread.h>
+
+namespace android {
+namespace intel {
+
+class IDisplayDevice;
+
+class SoftVsyncObserver {
+public:
+    SoftVsyncObserver(IDisplayDevice& disp);
+    virtual ~SoftVsyncObserver();
+
+public:
+    virtual bool initialize();
+    virtual void deinitialize();
+    virtual void setRefreshRate(int rate);
+    virtual bool control(bool enabled);
+
+private:
+    IDisplayDevice& mDisplayDevice;
+    int  mDevice;
+    bool mEnabled;
+    int mRefreshRate;
+    nsecs_t mRefreshPeriod;
+    mutable Mutex mLock;
+    Condition mCondition;
+    mutable nsecs_t mNextFakeVSync;
+    bool mExitThread;
+    bool mInitialized;
+
+private:
+    DECLARE_THREAD(VsyncEventPollThread, SoftVsyncObserver);
+};
+
+} // namespace intel
+} // namespace android
+
+
+
+#endif /* SOFT_VSYNC_OBSERVER_H */
+
diff --git a/merrifield/common/observers/UeventObserver.cpp b/merrifield/common/observers/UeventObserver.cpp
new file mode 100644
index 0000000..5f7ff27
--- /dev/null
+++ b/merrifield/common/observers/UeventObserver.cpp
@@ -0,0 +1,213 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#include <poll.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/queue.h>
+#include <linux/netlink.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <DrmConfig.h>
+#include <HwcTrace.h>
+#include <UeventObserver.h>
+
+namespace android {
+namespace intel {
+
+UeventObserver::UeventObserver()
+    : mUeventFd(-1),
+      mExitRDFd(-1),
+      mExitWDFd(-1),
+      mListeners()
+{
+}
+
+UeventObserver::~UeventObserver()
+{
+    deinitialize();
+}
+
+bool UeventObserver::initialize()
+{
+    mListeners.clear();
+
+    if (mUeventFd != -1) {
+        return true;
+    }
+
+    mThread = new UeventObserverThread(this);
+    if (!mThread.get()) {
+        ETRACE("failed to create uevent observer thread");
+        return false;
+    }
+
+    // init uevent socket
+    struct sockaddr_nl addr;
+    // set the socket receive buffer to 64K
+    // NOTE: this is only called for once
+    int sz = 64 * 1024;
+
+    memset(&addr, 0, sizeof(addr));
+    addr.nl_family = AF_NETLINK;
+    addr.nl_pid =  pthread_self() | getpid();
+    addr.nl_groups = 0xffffffff;
+
+    mUeventFd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
+    if (mUeventFd < 0) {
+        DEINIT_AND_RETURN_FALSE("failed to create uevent socket");
+    }
+
+    if (setsockopt(mUeventFd, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz))) {
+        WTRACE("setsockopt() failed");
+        //return false;
+    }
+
+    if (bind(mUeventFd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+        DEINIT_AND_RETURN_FALSE("failed to bind scoket");
+        return false;
+    }
+
+    memset(mUeventMessage, 0, UEVENT_MSG_LEN);
+
+    int exitFds[2];
+    if (pipe(exitFds) < 0) {
+        ETRACE("failed to make pipe");
+        deinitialize();
+        return false;
+    }
+    mExitRDFd = exitFds[0];
+    mExitWDFd = exitFds[1];
+
+    return true;
+}
+
+void UeventObserver::deinitialize()
+{
+    if (mUeventFd != -1) {
+        if (mExitWDFd != -1) {
+            close(mExitWDFd);
+            mExitWDFd = -1;
+        }
+        close(mUeventFd);
+        mUeventFd = -1;
+    }
+
+    if (mThread.get()) {
+        mThread->requestExitAndWait();
+        mThread = NULL;
+    }
+
+    while (!mListeners.isEmpty()) {
+        UeventListener *listener = mListeners.valueAt(0);
+        mListeners.removeItemsAt(0);
+        delete listener;
+    }
+}
+
+void UeventObserver::start()
+{
+    if (mThread.get()) {
+        mThread->run("UeventObserver", PRIORITY_URGENT_DISPLAY);
+    }
+}
+
+
+void UeventObserver::registerListener(const char *event, UeventListenerFunc func, void *data)
+{
+    if (!event || !func) {
+        ETRACE("invalid event string or listener to register");
+        return;
+    }
+
+    String8 key(event);
+    if (mListeners.indexOfKey(key) >= 0) {
+        ETRACE("listener for uevent %s exists", event);
+        return;
+    }
+
+    UeventListener *listener = new UeventListener;
+    if (!listener) {
+        ETRACE("failed to create Uevent Listener");
+        return;
+    }
+    listener->func = func;
+    listener->data = data;
+
+    mListeners.add(key, listener);
+}
+
+bool UeventObserver::threadLoop()
+{
+    if (mUeventFd == -1) {
+        ETRACE("invalid uEvent file descriptor");
+        return false;
+    }
+
+    struct pollfd fds[2];
+    int nr;
+
+    fds[0].fd = mUeventFd;
+    fds[0].events = POLLIN;
+    fds[0].revents = 0;
+    fds[1].fd = mExitRDFd;
+    fds[1].events = POLLIN;
+    fds[1].revents = 0;
+    nr = poll(fds, 2, -1);
+
+    if (nr > 0 && fds[0].revents == POLLIN) {
+        int count = recv(mUeventFd, mUeventMessage, UEVENT_MSG_LEN - 2, 0);
+        if (count > 0) {
+            onUevent();
+        }
+    } else if (fds[1].revents) {
+        close(mExitRDFd);
+        mExitRDFd = -1;
+        ITRACE("exiting wait");
+        return false;
+    }
+    // always looping
+    return true;
+}
+
+void UeventObserver::onUevent()
+{
+    char *msg = mUeventMessage;
+    const char *envelope = DrmConfig::getUeventEnvelope();
+    if (strncmp(msg, envelope, strlen(envelope)) != 0)
+        return;
+
+    msg += strlen(msg) + 1;
+
+    UeventListener *listener;
+    String8 key;
+    while (*msg) {
+        key = String8(msg);
+        if (mListeners.indexOfKey(key) >= 0) {
+            DTRACE("received Uevent: %s", msg);
+            listener = mListeners.valueFor(key);
+            if (listener) {
+                listener->func(listener->data);
+            } else {
+                ETRACE("no listener for uevent %s", msg);
+            }
+        }
+        msg += strlen(msg) + 1;
+    }
+}
+
+} // namespace intel
+} // namespace android
+
diff --git a/merrifield/common/observers/VsyncEventObserver.cpp b/merrifield/common/observers/VsyncEventObserver.cpp
new file mode 100644
index 0000000..b7a6fa3
--- /dev/null
+++ b/merrifield/common/observers/VsyncEventObserver.cpp
@@ -0,0 +1,137 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#include <HwcTrace.h>
+#include <VsyncEventObserver.h>
+#include <PhysicalDevice.h>
+
+namespace android {
+namespace intel {
+
+VsyncEventObserver::VsyncEventObserver(PhysicalDevice& disp)
+    : mLock(),
+      mCondition(),
+      mDisplayDevice(disp),
+      mVsyncControl(NULL),
+      mDevice(IDisplayDevice::DEVICE_COUNT),
+      mEnabled(false),
+      mExitThread(false),
+      mInitialized(false)
+{
+    CTRACE();
+}
+
+VsyncEventObserver::~VsyncEventObserver()
+{
+    WARN_IF_NOT_DEINIT();
+}
+
+bool VsyncEventObserver::initialize()
+{
+    if (mInitialized) {
+        WTRACE("object has been initialized");
+        return true;
+    }
+
+    mExitThread = false;
+    mEnabled = false;
+    mDevice = mDisplayDevice.getType();
+    mVsyncControl = mDisplayDevice.createVsyncControl();
+    if (!mVsyncControl || !mVsyncControl->initialize()) {
+        DEINIT_AND_RETURN_FALSE("failed to initialize vsync control");
+    }
+
+    mThread = new VsyncEventPollThread(this);
+    if (!mThread.get()) {
+        DEINIT_AND_RETURN_FALSE("failed to create vsync event poll thread.");
+    }
+
+    mThread->run("VsyncEventObserver", PRIORITY_URGENT_DISPLAY);
+
+    mInitialized = true;
+    return true;
+}
+
+void VsyncEventObserver::deinitialize()
+{
+    if (mEnabled) {
+        WTRACE("vsync is still enabled");
+        control(false);
+    }
+    mInitialized = false;
+    mExitThread = true;
+    mEnabled = false;
+    mCondition.signal();
+
+    if (mThread.get()) {
+        mThread->requestExitAndWait();
+        mThread = NULL;
+    }
+
+    DEINIT_AND_DELETE_OBJ(mVsyncControl);
+}
+
+bool VsyncEventObserver::control(bool enabled)
+{
+    ATRACE("enabled = %d on device %d", enabled, mDevice);
+    if (enabled == mEnabled) {
+        WTRACE("vsync state %d is not changed", enabled);
+        return true;
+    }
+
+    Mutex::Autolock _l(mLock);
+    bool ret = mVsyncControl->control(mDevice, enabled);
+    if (!ret) {
+        ETRACE("failed to control (%d) vsync on display %d", enabled, mDevice);
+        return false;
+    }
+
+    mEnabled = enabled;
+    mCondition.signal();
+    return true;
+}
+
+bool VsyncEventObserver::threadLoop()
+{
+    do {
+        // scope for lock
+        Mutex::Autolock _l(mLock);
+        while (!mEnabled) {
+            mCondition.wait(mLock);
+            if (mExitThread) {
+                ITRACE("exiting thread loop");
+                return false;
+            }
+        }
+    } while (0);
+
+    if(mEnabled && mDisplayDevice.isConnected()) {
+        int64_t timestamp;
+        bool ret = mVsyncControl->wait(mDevice, timestamp);
+        if (ret == false) {
+            WTRACE("failed to wait for vsync on display %d, vsync enabled %d", mDevice, mEnabled);
+            usleep(16000);
+            return true;
+        }
+
+        // notify device
+        mDisplayDevice.onVsync(timestamp);
+    }
+
+    return true;
+}
+
+} // namespace intel
+} // namesapce android
diff --git a/merrifield/common/observers/VsyncEventObserver.h b/merrifield/common/observers/VsyncEventObserver.h
new file mode 100644
index 0000000..36cb99f
--- /dev/null
+++ b/merrifield/common/observers/VsyncEventObserver.h
@@ -0,0 +1,56 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef __VSYNC_EVENT_OBSERVER_H__
+#define __VSYNC_EVENT_OBSERVER_H__
+
+#include <SimpleThread.h>
+#include <IVsyncControl.h>
+
+namespace android {
+namespace intel {
+
+class PhysicalDevice;
+
+class VsyncEventObserver {
+public:
+    VsyncEventObserver(PhysicalDevice& disp);
+    virtual ~VsyncEventObserver();
+
+public:
+    virtual bool initialize();
+    virtual void deinitialize();
+    bool control(bool enabled);
+
+private:
+    mutable Mutex mLock;
+    Condition mCondition;
+    PhysicalDevice& mDisplayDevice;
+    IVsyncControl *mVsyncControl;
+    int  mDevice;
+    bool mEnabled;
+    bool mExitThread;
+    bool mInitialized;
+
+private:
+    DECLARE_THREAD(VsyncEventPollThread, VsyncEventObserver);
+};
+
+} // namespace intel
+} // namespace android
+
+
+
+#endif /* __VSYNC_EVENT_OBSERVER_H__ */
diff --git a/merrifield/common/planes/DisplayPlane.cpp b/merrifield/common/planes/DisplayPlane.cpp
new file mode 100644
index 0000000..2a1ca51
--- /dev/null
+++ b/merrifield/common/planes/DisplayPlane.cpp
@@ -0,0 +1,384 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#include <HwcTrace.h>
+#include <Hwcomposer.h>
+#include <DisplayPlane.h>
+#include <GraphicBuffer.h>
+
+namespace android {
+namespace intel {
+
+DisplayPlane::DisplayPlane(int index, int type, int disp)
+    : mIndex(index),
+      mType(type),
+      mZOrder(-1),
+      mDevice(disp),
+      mInitialized(false),
+      mDataBuffers(),
+      mActiveBuffers(),
+      mCacheCapacity(0),
+      mIsProtectedBuffer(false),
+      mTransform(0),
+      mPlaneAlpha(0),
+      mBlending(HWC_BLENDING_NONE),
+      mCurrentDataBuffer(0),
+      mUpdateMasks(0)
+{
+    CTRACE();
+    memset(&mPosition, 0, sizeof(mPosition));
+    memset(&mSrcCrop, 0, sizeof(mSrcCrop));
+}
+
+DisplayPlane::~DisplayPlane()
+{
+    WARN_IF_NOT_DEINIT();
+}
+
+bool DisplayPlane::initialize(uint32_t bufferCount)
+{
+    CTRACE();
+
+    if (bufferCount < MIN_DATA_BUFFER_COUNT) {
+        WTRACE("buffer count %d is too small", bufferCount);
+        bufferCount = MIN_DATA_BUFFER_COUNT;
+    }
+
+    // create buffer cache, adding few extra slots as buffer rendering is async
+    // buffer could still be queued in the display pipeline such that they
+    // can't be unmapped]
+    mCacheCapacity = bufferCount;
+    mDataBuffers.setCapacity(bufferCount);
+    mActiveBuffers.setCapacity(MIN_DATA_BUFFER_COUNT);
+    mInitialized = true;
+    return true;
+}
+
+void DisplayPlane::deinitialize()
+{
+    // invalidate cached data buffers
+    if (mDataBuffers.size()) {
+        // invalidateBufferCache will assert if object is not initialized
+        // so invoking it only there is buffer to invalidate.
+        invalidateBufferCache();
+    }
+
+    // invalidate active buffers
+    if (mActiveBuffers.size()) {
+        invalidateActiveBuffers();
+    }
+
+    mCurrentDataBuffer = 0;
+    mInitialized = false;
+}
+
+void DisplayPlane::checkPosition(int& x, int& y, int& w, int& h)
+{
+    drmModeModeInfoPtr mode = &mModeInfo;
+
+    if (mode->hdisplay == 0 || mode->vdisplay == 0)
+        return;
+
+    if (x < 0)
+        x = 0;
+    if (y < 0)
+        y = 0;
+    if ((x + w) > mode->hdisplay)
+        w = mode->hdisplay - x;
+    if ((y + h) > mode->vdisplay)
+        h = mode->vdisplay - y;
+}
+
+void DisplayPlane::setPosition(int x, int y, int w, int h)
+{
+    ATRACE("Position = %d, %d - %dx%d", x, y, w, h);
+
+    if (mPosition.x != x || mPosition.y != y ||
+        mPosition.w != w || mPosition.h != h) {
+        mUpdateMasks |= PLANE_POSITION_CHANGED;
+        mPosition.x = x;
+        mPosition.y = y;
+        mPosition.w = w;
+        mPosition.h = h;
+    }
+}
+
+void DisplayPlane::setSourceCrop(int x, int y, int w, int h)
+{
+    ATRACE("Source crop = %d, %d - %dx%d", x, y, w, h);
+
+    if (mSrcCrop.x != x || mSrcCrop.y != y ||
+        mSrcCrop.w != w || mSrcCrop.h != h) {
+        mUpdateMasks |= PLANE_SOURCE_CROP_CHANGED;
+        mSrcCrop.x = x;
+        mSrcCrop.y = y;
+        if (mType == DisplayPlane::PLANE_OVERLAY) {
+            mSrcCrop.w = w & (~0x01);
+            mSrcCrop.h = h & (~0x01);
+        } else {
+            mSrcCrop.w = w;
+            mSrcCrop.h = h;
+        }
+    }
+}
+
+void DisplayPlane::setTransform(int trans)
+{
+    ATRACE("transform = %d", trans);
+
+    if (mTransform == trans) {
+        return;
+    }
+
+    mTransform = trans;
+
+    mUpdateMasks |= PLANE_TRANSFORM_CHANGED;
+}
+
+void DisplayPlane::setPlaneAlpha(uint8_t alpha, uint32_t blending)
+{
+    ATRACE("plane alpha = 0x%x", alpha);
+
+    if (mPlaneAlpha != alpha) {
+        mPlaneAlpha = alpha;
+        mUpdateMasks |= PLANE_BUFFER_CHANGED;
+    }
+
+    if (mBlending != blending) {
+        mBlending = blending;
+        mUpdateMasks |= PLANE_BUFFER_CHANGED;
+    }
+}
+
+bool DisplayPlane::setDataBuffer(buffer_handle_t handle)
+{
+    DataBuffer *buffer;
+    BufferMapper *mapper;
+    ssize_t index;
+    bool ret;
+    bool isCompression;
+    BufferManager *bm = Hwcomposer::getInstance().getBufferManager();
+
+    RETURN_FALSE_IF_NOT_INIT();
+    ATRACE("handle = %#x", handle);
+
+    if (!handle) {
+        WTRACE("invalid buffer handle");
+        return false;
+    }
+
+    // do not need to update the buffer handle
+    if (mCurrentDataBuffer != handle)
+        mUpdateMasks |= PLANE_BUFFER_CHANGED;
+
+    // if no update then do Not need set data buffer
+    if (!mUpdateMasks)
+        return true;
+
+    buffer = bm->lockDataBuffer(handle);
+    if (!buffer) {
+        ETRACE("failed to get buffer");
+        return false;
+    }
+
+    mIsProtectedBuffer = GraphicBuffer::isProtectedBuffer((GraphicBuffer*)buffer);
+    isCompression = GraphicBuffer::isCompressionBuffer((GraphicBuffer*)buffer);
+
+    // map buffer if it's not in cache
+    index = mDataBuffers.indexOfKey(buffer->getKey());
+    if (index < 0) {
+        VTRACE("unmapped buffer, mapping...");
+        mapper = mapBuffer(buffer);
+        if (!mapper) {
+            ETRACE("failed to map buffer %p", handle);
+            bm->unlockDataBuffer(buffer);
+            return false;
+        }
+    } else {
+        VTRACE("got mapper in saved data buffers and update source Crop");
+        mapper = mDataBuffers.valueAt(index);
+    }
+
+    // always update source crop to mapper
+    mapper->setCrop(mSrcCrop.x, mSrcCrop.y, mSrcCrop.w, mSrcCrop.h);
+
+    mapper->setIsCompression(isCompression);
+
+    // unlock buffer after getting mapper
+    bm->unlockDataBuffer(buffer);
+    buffer = NULL;
+
+    ret = setDataBuffer(*mapper);
+    if (ret) {
+        mCurrentDataBuffer = handle;
+        // update active buffers
+        updateActiveBuffers(mapper);
+    }
+    return ret;
+}
+
+BufferMapper* DisplayPlane::mapBuffer(DataBuffer *buffer)
+{
+    BufferManager *bm = Hwcomposer::getInstance().getBufferManager();
+
+    // invalidate buffer cache  if cache is full
+    if ((int)mDataBuffers.size() >= mCacheCapacity) {
+        invalidateBufferCache();
+    }
+
+    BufferMapper *mapper = bm->map(*buffer);
+    if (!mapper) {
+        ETRACE("failed to map buffer");
+        return NULL;
+    }
+
+    // add it to data buffers
+    ssize_t index = mDataBuffers.add(buffer->getKey(), mapper);
+    if (index < 0) {
+        ETRACE("failed to add mapper");
+        bm->unmap(mapper);
+        return NULL;
+    }
+
+    return mapper;
+}
+
+int DisplayPlane::findActiveBuffer(BufferMapper *mapper)
+{
+    for (size_t i = 0; i < mActiveBuffers.size(); i++) {
+        BufferMapper *activeMapper = mActiveBuffers.itemAt(i);
+        if (!activeMapper)
+            continue;
+        if (activeMapper->getKey() == mapper->getKey())
+            return i;
+    }
+
+    return -1;
+}
+
+void DisplayPlane::updateActiveBuffers(BufferMapper *mapper)
+{
+    BufferManager *bm = Hwcomposer::getInstance().getBufferManager();
+    int index = findActiveBuffer(mapper);
+    bool exist = (0 <= index && index < (int)mActiveBuffers.size());
+
+    // unmap the first entry (oldest buffer)
+    if (!exist && mActiveBuffers.size() >= MIN_DATA_BUFFER_COUNT) {
+        BufferMapper *oldest = mActiveBuffers.itemAt(0);
+        bm->unmap(oldest);
+        mActiveBuffers.removeAt(0);
+    }
+
+    // queue it to active buffers
+    if (!exist) {
+        mapper->incRef();
+    } else {
+        mActiveBuffers.removeAt(index);
+    }
+    mActiveBuffers.push_back(mapper);
+}
+
+void DisplayPlane::invalidateActiveBuffers()
+{
+    BufferManager *bm = Hwcomposer::getInstance().getBufferManager();
+    BufferMapper* mapper;
+
+    RETURN_VOID_IF_NOT_INIT();
+
+    VTRACE("invalidating active buffers");
+
+    for (size_t i = 0; i < mActiveBuffers.size(); i++) {
+        mapper = mActiveBuffers.itemAt(i);
+        // unmap it
+        bm->unmap(mapper);
+    }
+
+    // clear recorded data buffers
+    mActiveBuffers.clear();
+}
+
+void DisplayPlane::invalidateBufferCache()
+{
+    BufferManager *bm = Hwcomposer::getInstance().getBufferManager();
+    BufferMapper* mapper;
+
+    RETURN_VOID_IF_NOT_INIT();
+
+    for (size_t i = 0; i < mDataBuffers.size(); i++) {
+        mapper = mDataBuffers.valueAt(i);
+        bm->unmap(mapper);
+    }
+
+    mDataBuffers.clear();
+    // reset current buffer
+    mCurrentDataBuffer = 0;
+}
+
+bool DisplayPlane::assignToDevice(int disp)
+{
+    RETURN_FALSE_IF_NOT_INIT();
+    ATRACE("disp = %d", disp);
+
+    mDevice = disp;
+
+    Drm *drm = Hwcomposer::getInstance().getDrm();
+    if (!drm->getModeInfo(mDevice, mModeInfo)) {
+        ETRACE("failed to get mode info");
+    }
+
+    mPanelOrientation = drm->getPanelOrientation(mDevice);
+
+    return true;
+}
+
+bool DisplayPlane::flip(void *ctx)
+{
+    RETURN_FALSE_IF_NOT_INIT();
+
+    // always flip
+    return true;
+}
+
+void DisplayPlane::postFlip()
+{
+    mUpdateMasks = 0;
+}
+
+bool DisplayPlane::reset()
+{
+    // reclaim all allocated resources
+    if (mDataBuffers.size() > 0) {
+        invalidateBufferCache();
+    }
+
+    if (mActiveBuffers.size() > 0) {
+        invalidateActiveBuffers();
+    }
+
+    return true;
+}
+
+void DisplayPlane::setZOrder(int zorder)
+{
+    mZOrder = zorder;
+}
+
+int DisplayPlane::getZOrder() const
+{
+    return mZOrder;
+}
+
+} // namespace intel
+} // namespace android
diff --git a/merrifield/common/planes/DisplayPlaneManager.cpp b/merrifield/common/planes/DisplayPlaneManager.cpp
new file mode 100644
index 0000000..1b60d93
--- /dev/null
+++ b/merrifield/common/planes/DisplayPlaneManager.cpp
@@ -0,0 +1,350 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#include <HwcTrace.h>
+#include <IDisplayDevice.h>
+#include <DisplayPlaneManager.h>
+
+namespace android {
+namespace intel {
+
+DisplayPlaneManager::DisplayPlaneManager()
+    : mTotalPlaneCount(0),
+      mPrimaryPlaneCount(DEFAULT_PRIMARY_PLANE_COUNT),
+      mSpritePlaneCount(0),
+      mOverlayPlaneCount(0),
+      mInitialized(false)
+{
+    int i;
+
+    for (i = 0; i < DisplayPlane::PLANE_MAX; i++) {
+        mPlaneCount[i] = 0;
+        mFreePlanes[i] = 0;
+        mReclaimedPlanes[i] = 0;
+    }
+}
+
+DisplayPlaneManager::~DisplayPlaneManager()
+{
+    WARN_IF_NOT_DEINIT();
+}
+
+void DisplayPlaneManager::deinitialize()
+{
+    int i;
+    size_t j;
+
+    for (i = 0; i < DisplayPlane::PLANE_MAX; i++) {
+        for (j = 0; j < mPlanes[i].size(); j++) {
+            // reset plane
+            DisplayPlane *plane = mPlanes[i].itemAt(j);
+            plane->reset();
+
+            DEINIT_AND_DELETE_OBJ(plane);
+        }
+        mPlanes[i].clear();
+    }
+
+    mInitialized = false;
+}
+
+bool DisplayPlaneManager::initialize()
+{
+    int i, j;
+
+    if (mInitialized) {
+        WTRACE("object has been initialized");
+        return true;
+    }
+
+
+    // calculate total plane number and free plane bitmaps
+    mPlaneCount[DisplayPlane::PLANE_SPRITE] = mSpritePlaneCount;
+    mPlaneCount[DisplayPlane::PLANE_OVERLAY] = mOverlayPlaneCount;
+    mPlaneCount[DisplayPlane::PLANE_PRIMARY] = mPrimaryPlaneCount;
+    mPlaneCount[DisplayPlane::PLANE_CURSOR] = mCursorPlaneCount;
+
+    mTotalPlaneCount = mSpritePlaneCount+ mOverlayPlaneCount+ mPrimaryPlaneCount + mCursorPlaneCount;
+    if (mTotalPlaneCount == 0) {
+        ETRACE("plane count is not initialized");
+        return false;
+    }
+
+    for (i = 0; i < DisplayPlane::PLANE_MAX; i++) {
+        mFreePlanes[i] = ((1 << mPlaneCount[i]) - 1);
+    }
+
+    // allocate plane pools
+    for (i = 0; i < DisplayPlane::PLANE_MAX; i++) {
+        if (mPlaneCount[i]) {
+            mPlanes[i].setCapacity(mPlaneCount[i]);
+
+            for (j = 0; j < mPlaneCount[i]; j++) {
+                DisplayPlane* plane = allocPlane(j, i);
+                if (!plane) {
+                    ETRACE("failed to allocate plane %d, type %d", j, i);
+                    DEINIT_AND_RETURN_FALSE();
+                }
+                mPlanes[i].push_back(plane);
+            }
+        }
+    }
+
+    mInitialized = true;
+    return true;
+}
+
+int DisplayPlaneManager::getPlane(uint32_t& mask)
+{
+    if (!mask)
+        return -1;
+
+    for (int i = 0; i < 32; i++) {
+        int bit = (1 << i);
+        if (bit & mask) {
+            mask &= ~bit;
+            return i;
+        }
+    }
+
+    return -1;
+}
+
+void DisplayPlaneManager::putPlane(int index, uint32_t& mask)
+{
+    if (index < 0 || index >= 32)
+        return;
+
+    int bit = (1 << index);
+
+    if (bit & mask) {
+        WTRACE("bit %d was set", index);
+        return;
+    }
+
+    mask |= bit;
+}
+
+int DisplayPlaneManager::getPlane(uint32_t& mask, int index)
+{
+    if (!mask || index < 0 || index > mTotalPlaneCount)
+        return -1;
+
+    int bit = (1 << index);
+    if (bit & mask) {
+        mask &= ~bit;
+        return index;
+    }
+
+    return -1;
+}
+
+DisplayPlane* DisplayPlaneManager::getPlane(int type, int index)
+{
+    RETURN_NULL_IF_NOT_INIT();
+
+    if (type < 0 || type >= DisplayPlane::PLANE_MAX) {
+        ETRACE("Invalid plane type %d", type);
+        return 0;
+    }
+
+    int freePlaneIndex = getPlane(mReclaimedPlanes[type], index);
+    if (freePlaneIndex >= 0)
+        return mPlanes[type].itemAt(freePlaneIndex);
+
+    freePlaneIndex = getPlane(mFreePlanes[type], index);
+    if (freePlaneIndex >= 0)
+        return mPlanes[type].itemAt(freePlaneIndex);
+
+    return 0;
+}
+
+DisplayPlane* DisplayPlaneManager::getAnyPlane(int type)
+{
+    RETURN_NULL_IF_NOT_INIT();
+
+    if (type < 0 || type >= DisplayPlane::PLANE_MAX) {
+        ETRACE("Invalid plane type %d", type);
+        return 0;
+    }
+
+    int freePlaneIndex = getPlane(mReclaimedPlanes[type]);
+    if (freePlaneIndex >= 0)
+        return mPlanes[type].itemAt(freePlaneIndex);
+
+    freePlaneIndex = getPlane(mFreePlanes[type]);
+    if (freePlaneIndex >= 0)
+        return mPlanes[type].itemAt(freePlaneIndex);
+
+    return 0;
+}
+
+void DisplayPlaneManager::putPlane(int dsp, DisplayPlane& plane)
+{
+    int index;
+    int type;
+
+    RETURN_VOID_IF_NOT_INIT();
+
+    index = plane.getIndex();
+    type = plane.getType();
+
+    if (type < 0 || type >= DisplayPlane::PLANE_MAX) {
+        ETRACE("Invalid plane type %d", type);
+        return;
+    }
+
+    putPlane(index, mFreePlanes[type]);
+}
+
+bool DisplayPlaneManager::isFreePlane(int type, int index)
+{
+    if (type < 0 || type >= DisplayPlane::PLANE_MAX) {
+        ETRACE("Invalid plane type %d", type);
+        return false;
+    }
+
+    int freePlanes = mFreePlanes[type] | mReclaimedPlanes[type];
+    if ((freePlanes & (1 << index)) == 0)
+        return false;
+
+    return true;
+}
+
+int DisplayPlaneManager::getFreePlanes(int dsp, int type)
+{
+    RETURN_NULL_IF_NOT_INIT();
+
+    if (dsp < 0 || dsp > IDisplayDevice::DEVICE_EXTERNAL) {
+        ETRACE("Invalid display device %d", dsp);
+        return 0;
+    }
+
+    if (type < 0 || type >= DisplayPlane::PLANE_MAX) {
+        ETRACE("Invalid plane type %d", type);
+        return 0;
+    }
+
+
+    uint32_t freePlanes = mFreePlanes[type] | mReclaimedPlanes[type];
+    if (type == DisplayPlane::PLANE_PRIMARY ||
+        type == DisplayPlane::PLANE_CURSOR) {
+        return ((freePlanes & (1 << dsp)) == 0) ? 0 : 1;
+    } else {
+        int count = 0;
+        for (int i = 0; i < 32; i++) {
+            if ((1 << i) & freePlanes) {
+                count++;
+            }
+        }
+        return count;
+    }
+    return 0;
+}
+
+void DisplayPlaneManager::reclaimPlane(int dsp, DisplayPlane& plane)
+{
+    RETURN_VOID_IF_NOT_INIT();
+
+    int index = plane.getIndex();
+    int type = plane.getType();
+
+    ATRACE("reclaimPlane = %d, type = %d", index, plane.getType());
+
+    if (type < 0 || type >= DisplayPlane::PLANE_MAX) {
+        ETRACE("Invalid plane type %d", type);
+        return;
+    }
+
+    putPlane(index, mReclaimedPlanes[type]);
+
+    // NOTE: don't invalidate plane's data cache here because the reclaimed
+    // plane might be re-assigned to the same layer later
+}
+
+void DisplayPlaneManager::disableReclaimedPlanes()
+{
+    int i, j;
+    bool ret;
+
+    RETURN_VOID_IF_NOT_INIT();
+
+    for (i = 0; i < DisplayPlane::PLANE_MAX; i++) {
+        // disable reclaimed planes
+        if (mReclaimedPlanes[i]) {
+            for (j = 0; j < mPlaneCount[i]; j++) {
+                int bit = (1 << j);
+                if (mReclaimedPlanes[i] & bit) {
+                    DisplayPlane* plane = mPlanes[i].itemAt(j);
+                    // check plane state first
+                    ret = plane->isDisabled();
+                    // reset plane
+                    if (ret)
+                        ret = plane->reset();
+                    if (ret) {
+                        // only merge into free bitmap if it is successfully disabled and reset
+                        // otherwise, plane will be disabled and reset again.
+                        mFreePlanes[i] |=bit;
+                        mReclaimedPlanes[i] &= ~bit;
+                    }
+                }
+            }
+        }
+    }
+}
+
+bool DisplayPlaneManager::isOverlayPlanesDisabled()
+{
+    for (int i = 0; i < DisplayPlane::PLANE_MAX; i++) {
+        for (int j = 0; j < mPlaneCount[i]; j++) {
+            DisplayPlane* plane = (DisplayPlane *)mPlanes[i][j];
+            if (plane && plane->getType() == DisplayPlane::PLANE_OVERLAY) {
+                if (!plane->isDisabled())
+                    return false;
+            }
+        }
+    }
+
+    return true;
+}
+
+void DisplayPlaneManager::dump(Dump& d)
+{
+    d.append("Display Plane Manager state:\n");
+    d.append("-------------------------------------------------------------\n");
+    d.append(" PLANE TYPE | COUNT |   FREE   | RECLAIMED \n");
+    d.append("------------+-------+----------+-----------\n");
+    d.append("    SPRITE  |  %2d   | %08x | %08x\n",
+             mPlaneCount[DisplayPlane::PLANE_SPRITE],
+             mFreePlanes[DisplayPlane::PLANE_SPRITE],
+             mReclaimedPlanes[DisplayPlane::PLANE_SPRITE]);
+    d.append("   OVERLAY  |  %2d   | %08x | %08x\n",
+             mPlaneCount[DisplayPlane::PLANE_OVERLAY],
+             mFreePlanes[DisplayPlane::PLANE_OVERLAY],
+             mReclaimedPlanes[DisplayPlane::PLANE_OVERLAY]);
+    d.append("   PRIMARY  |  %2d   | %08x | %08x\n",
+             mPlaneCount[DisplayPlane::PLANE_PRIMARY],
+             mFreePlanes[DisplayPlane::PLANE_PRIMARY],
+             mReclaimedPlanes[DisplayPlane::PLANE_PRIMARY]);
+    d.append("   CURSOR   |  %2d   | %08x | %08x\n",
+             mPlaneCount[DisplayPlane::PLANE_CURSOR],
+             mFreePlanes[DisplayPlane::PLANE_CURSOR],
+             mReclaimedPlanes[DisplayPlane::PLANE_CURSOR]);
+}
+
+} // namespace intel
+} // namespace android
+
+
diff --git a/merrifield/common/utils/Dump.cpp b/merrifield/common/utils/Dump.cpp
new file mode 100644
index 0000000..31d924f
--- /dev/null
+++ b/merrifield/common/utils/Dump.cpp
@@ -0,0 +1,53 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#include <stdarg.h>
+#include <stdio.h>
+
+#include <Dump.h>
+
+namespace android {
+namespace intel {
+
+Dump::Dump(char *buf, int len)
+    : mBuf(buf),
+      mLen(len)
+{
+
+}
+
+Dump::~Dump()
+{
+
+}
+
+void Dump::append(const char *fmt, ...)
+{
+    int len;
+
+    if (!mBuf || !mLen)
+        return;
+
+    va_list ap;
+    va_start(ap, fmt);
+    len = vsnprintf(mBuf, mLen, fmt, ap);
+    va_end(ap);
+
+    mLen -= len;
+    mBuf += len;
+}
+
+} // namespace intel
+} // namespace android
diff --git a/merrifield/common/utils/Dump.h b/merrifield/common/utils/Dump.h
new file mode 100644
index 0000000..ba996b2
--- /dev/null
+++ b/merrifield/common/utils/Dump.h
@@ -0,0 +1,35 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef DUMP_H_
+#define DUMP_H_
+
+namespace android {
+namespace intel {
+
+class Dump {
+public:
+    Dump(char *buf, int len);
+    ~Dump();
+
+    void append(const char *fmt, ...);
+private:
+    char *mBuf;
+    int mLen;
+};
+
+} // namespace intel
+} // namespace android
+#endif /* DUMP_H_ */
diff --git a/merrifield/common/utils/HwcTrace.h b/merrifield/common/utils/HwcTrace.h
new file mode 100644
index 0000000..83151c6
--- /dev/null
+++ b/merrifield/common/utils/HwcTrace.h
@@ -0,0 +1,112 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef HWC_TRACE_H
+#define HWC_TRACE_H
+
+#define LOG_TAG "hwcomposer"
+//#define LOG_NDEBUG 0
+#include <cutils/log.h>
+
+
+#ifdef _cplusplus
+extern "C" {
+#endif
+
+// Helper to automatically preappend classname::functionname to the log message
+#define VTRACE(fmt,...)     ALOGV("%s: "fmt, __func__, ##__VA_ARGS__)
+#define DTRACE(fmt,...)     ALOGD("%s: "fmt, __func__, ##__VA_ARGS__)
+#define ITRACE(fmt,...)     ALOGI("%s: "fmt, __func__, ##__VA_ARGS__)
+#define WTRACE(fmt,...)     ALOGW("%s: "fmt, __func__, ##__VA_ARGS__)
+#define ETRACE(fmt,...)     ALOGE("%s: "fmt, __func__, ##__VA_ARGS__)
+
+
+// Function call tracing
+#if 0
+#define CTRACE()            ALOGV("Calling %s", __func__)
+#define XTRACE()            ALOGV("Leaving %s", __func__)
+#else
+#define CTRACE()            ((void)0)
+#define XTRACE()            ((void)0)
+#endif
+
+
+// Arguments tracing
+#if 0
+#define ATRACE(fmt,...)     ALOGV("%s(args): "fmt, __func__, ##__VA_ARGS__);
+#else
+#define ATRACE(fmt,...)     ((void)0)
+#endif
+
+
+
+// Helper to abort the execution if object is not initialized.
+// This should never happen if the rules below are followed during design:
+// 1) Create an object.
+// 2) Initialize the object immediately.
+// 3) If failed, delete the object.
+// These helpers should be disabled and stripped out of release build
+
+#define RETURN_X_IF_NOT_INIT(X) \
+do { \
+    CTRACE(); \
+    if (false == mInitialized) { \
+        LOG_ALWAYS_FATAL("%s: Object is not initialized! Line = %d", __func__, __LINE__); \
+        return X; \
+    } \
+} while (0)
+
+#if 1
+#define RETURN_FALSE_IF_NOT_INIT()      RETURN_X_IF_NOT_INIT(false)
+#define RETURN_VOID_IF_NOT_INIT()       RETURN_X_IF_NOT_INIT()
+#define RETURN_NULL_IF_NOT_INIT()       RETURN_X_IF_NOT_INIT(0)
+#else
+#define RETURN_FALSE_IF_NOT_INIT()      ((void)0)
+#define RETURN_VOID_IF_NOT_INIT()       ((void)0)
+#define RETURN_NULL_IF_NOT_INIT()       ((void)0)
+#endif
+
+
+// Helper to log error message, call de-initializer and return false.
+#define DEINIT_AND_RETURN_FALSE(...) \
+do { \
+    ETRACE(__VA_ARGS__); \
+    deinitialize(); \
+    return false; \
+} while (0)
+
+
+#define DEINIT_AND_DELETE_OBJ(X) \
+    if (X) {\
+        X->deinitialize();\
+        delete X; \
+        X = NULL; \
+    }
+
+
+#define WARN_IF_NOT_DEINIT() \
+    CTRACE(); \
+    if (mInitialized) {\
+        LOG_ALWAYS_FATAL("%s: Object is not deinitialized! Line = %d", __func__, __LINE__); \
+    }
+
+
+// _cplusplus
+#ifdef _cplusplus
+}
+#endif
+
+
+#endif /* HWC_TRACE_H */
diff --git a/merrifield/include/BufferManager.h b/merrifield/include/BufferManager.h
new file mode 100644
index 0000000..ccc8eaa
--- /dev/null
+++ b/merrifield/include/BufferManager.h
@@ -0,0 +1,89 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef BUFFERMANAGER_H_
+#define BUFFERMANAGER_H_
+
+#include <Dump.h>
+#include <DataBuffer.h>
+#include <BufferMapper.h>
+#include <BufferCache.h>
+#include <utils/Mutex.h>
+
+namespace android {
+namespace intel {
+
+// Gralloc Buffer Manager
+class BufferManager {
+public:
+    BufferManager();
+    virtual ~BufferManager();
+
+    bool initCheck() const;
+    virtual bool initialize();
+    virtual void deinitialize();
+
+    // dump interface
+    void dump(Dump& d);
+
+    // lockDataBuffer and unlockDataBuffer must be used in serial
+    // nested calling of them will cause a deadlock
+    DataBuffer* lockDataBuffer(buffer_handle_t handle);
+    void unlockDataBuffer(DataBuffer *buffer);
+
+    // get and put interfaces are deprecated
+    // use lockDataBuffer and unlockDataBuffer instead
+    DataBuffer* get(buffer_handle_t handle);
+    void put(DataBuffer *buffer);
+
+    // map/unmap a data buffer into/from display memory
+    BufferMapper* map(DataBuffer& buffer);
+    void unmap(BufferMapper *mapper);
+
+    // frame buffer management
+    //return 0 if allocation fails
+    virtual buffer_handle_t allocFrameBuffer(int width, int height, int *stride);
+    virtual void freeFrameBuffer(buffer_handle_t fbHandle);
+
+    buffer_handle_t allocGrallocBuffer(uint32_t width, uint32_t height, uint32_t format, uint32_t usage);
+    void freeGrallocBuffer(buffer_handle_t handle);
+    virtual bool blit(buffer_handle_t srcHandle, buffer_handle_t destHandle,
+                      const crop_t& destRect, bool filter, bool async) = 0;
+protected:
+    virtual DataBuffer* createDataBuffer(gralloc_module_t *module,
+                                             buffer_handle_t handle) = 0;
+    virtual BufferMapper* createBufferMapper(gralloc_module_t *module,
+                                                 DataBuffer& buffer) = 0;
+
+    gralloc_module_t *mGrallocModule;
+private:
+    enum {
+        // make the buffer pool large enough
+        DEFAULT_BUFFER_POOL_SIZE = 128,
+    };
+
+    alloc_device_t *mAllocDev;
+    KeyedVector<buffer_handle_t, BufferMapper*> mFrameBuffers;
+    BufferCache *mBufferPool;
+    DataBuffer *mDataBuffer;
+    Mutex mDataBufferLock;
+    Mutex mLock;
+    bool mInitialized;
+};
+
+} // namespace intel
+} // namespace android
+
+#endif /* BUFFERMANAGER_H_ */
diff --git a/merrifield/include/BufferMapper.h b/merrifield/include/BufferMapper.h
new file mode 100644
index 0000000..7a4ceaf
--- /dev/null
+++ b/merrifield/include/BufferMapper.h
@@ -0,0 +1,68 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef BUFFERMAPPER_H__
+#define BUFFERMAPPER_H__
+
+#include <DataBuffer.h>
+
+namespace android {
+namespace intel {
+
+class BufferMapper : public DataBuffer {
+public:
+    BufferMapper(DataBuffer& buffer)
+        : DataBuffer(buffer),
+          mRefCount(0)
+    {
+    }
+    virtual ~BufferMapper() {}
+public:
+    int incRef()
+    {
+        mRefCount++;
+        return mRefCount;
+    }
+    int decRef()
+    {
+        mRefCount--;
+        return mRefCount;
+    }
+
+    int getRef() const
+    {
+        return mRefCount;
+    }
+
+    // map the given buffer into both DC & CPU MMU
+    virtual bool map() = 0;
+    // unmap the give buffer from both DC & CPU MMU
+    virtual bool unmap() = 0;
+
+    // return gtt page offset
+    virtual uint32_t getGttOffsetInPage(int subIndex) const = 0;
+    virtual void* getCpuAddress(int subIndex) const = 0;
+    virtual uint32_t getSize(int subIndex) const = 0;
+    virtual buffer_handle_t getKHandle(int subIndex) = 0;
+    virtual buffer_handle_t getFbHandle(int subIndex) = 0;
+    virtual void putFbHandle() = 0;
+private:
+    int mRefCount;
+};
+
+} // namespace intel
+} // namespace android
+
+#endif /* BUFFERMAPPER_H__ */
diff --git a/merrifield/include/DataBuffer.h b/merrifield/include/DataBuffer.h
new file mode 100644
index 0000000..a4a6d84
--- /dev/null
+++ b/merrifield/include/DataBuffer.h
@@ -0,0 +1,114 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef DATABUFFER_H__
+#define DATABUFFER_H__
+
+#include <hardware/hwcomposer.h>
+
+namespace android {
+namespace intel {
+
+typedef struct crop {
+    // align with android, using 'int' here
+    int x;
+    int y;
+    int w;
+    int h;
+} crop_t;
+
+typedef struct stride {
+    union {
+        struct {
+            uint32_t stride;
+        } rgb;
+        struct {
+            uint32_t yStride;
+            uint32_t uvStride;
+        } yuv;
+    };
+}stride_t;
+
+class DataBuffer {
+public:
+    enum {
+        FORMAT_INVALID = 0xffffffff,
+    };
+public:
+    DataBuffer(buffer_handle_t handle)
+    {
+        initBuffer(handle);
+    }
+    virtual ~DataBuffer() {}
+
+public:
+    virtual void resetBuffer(buffer_handle_t handle) {
+        // nothing to reset, just do initialization
+        initBuffer(handle);
+    }
+
+    buffer_handle_t getHandle() const { return mHandle; }
+
+    void setStride(stride_t& stride) { mStride = stride; }
+    stride_t& getStride() { return mStride; }
+
+    void setWidth(uint32_t width) { mWidth = width; }
+    uint32_t getWidth() const { return mWidth; }
+
+    void setHeight(uint32_t height) { mHeight = height; }
+    uint32_t getHeight() const { return mHeight; }
+
+    void setCrop(int x, int y, int w, int h) {
+        mCrop.x = x; mCrop.y = y; mCrop.w = w; mCrop.h = h; }
+    crop_t& getCrop() { return mCrop; }
+
+    void setFormat(uint32_t format) { mFormat = format; }
+    uint32_t getFormat() const { return mFormat; }
+
+    uint64_t getKey() const { return mKey; }
+
+    void setIsCompression(bool isCompressed) { mIsCompression = isCompressed; }
+    bool isCompression() { return mIsCompression; }
+
+private:
+    void initBuffer(buffer_handle_t handle) {
+        mHandle = handle;
+        mFormat = 0;
+        mWidth = 0;
+        mHeight = 0;
+        mKey = (uint64_t)handle;
+        memset(&mStride, 0, sizeof(stride_t));
+        memset(&mCrop, 0, sizeof(crop_t));
+    }
+protected:
+    buffer_handle_t mHandle;
+    stride_t mStride;
+    crop_t mCrop;
+    uint32_t mFormat;
+    uint32_t mWidth;
+    uint32_t mHeight;
+    uint64_t mKey;
+    bool mIsCompression;
+};
+
+static inline uint32_t align_to(uint32_t arg, uint32_t align)
+{
+    return ((arg + (align - 1)) & (~(align - 1)));
+}
+
+} // namespace intel
+} // namespace android
+
+#endif /* DATABUFFER_H__ */
diff --git a/merrifield/include/DisplayPlane.h b/merrifield/include/DisplayPlane.h
new file mode 100644
index 0000000..250d485
--- /dev/null
+++ b/merrifield/include/DisplayPlane.h
@@ -0,0 +1,154 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef DISPLAYPLANE_H_
+#define DISPLAYPLANE_H_
+
+#include <utils/KeyedVector.h>
+#include <BufferMapper.h>
+#include <Drm.h>
+
+namespace android {
+namespace intel {
+
+typedef struct {
+    // align with android, using 'int' here
+    int x;
+    int y;
+    int w;
+    int h;
+} PlanePosition;
+
+enum {
+    // support up to 4 overlays
+    MAX_OVERLAY_COUNT = 4,
+    MAX_SPRITE_COUNT = 4,
+};
+
+enum {
+     // in version 1.3, HWC_FRAMEBUFFER_TARGET is defined as 3
+     HWC_FORCE_FRAMEBUFFER = 255,
+};
+
+class ZOrderConfig;
+
+class DisplayPlane {
+public:
+    // plane type
+    enum {
+        PLANE_SPRITE = 0,
+        PLANE_OVERLAY,
+        PLANE_PRIMARY,
+        PLANE_CURSOR,
+        PLANE_MAX,
+    };
+
+    enum {
+        // one more than android's back buffer count to allow more space
+        // to do map/unmap, as plane reallocation may unmap on-screen layer.
+        // each plane will cache the latest MIN_DATA_BUFFER_COUNT buffers
+        // in case that these buffers are still in-using by display device
+        // other buffers will be released on cache invalidation
+        MIN_DATA_BUFFER_COUNT = 4,
+    };
+
+protected:
+    enum {
+        PLANE_POSITION_CHANGED    = 0x00000001UL,
+        PLANE_BUFFER_CHANGED      = 0x00000002UL,
+        PLANE_SOURCE_CROP_CHANGED = 0x00000004UL,
+        PLANE_TRANSFORM_CHANGED   = 0x00000008UL,
+    };
+public:
+    DisplayPlane(int index, int type, int disp);
+    virtual ~DisplayPlane();
+public:
+    virtual int getIndex() const { return mIndex; }
+    virtual int getType() const { return mType; }
+    virtual bool initCheck() const { return mInitialized; }
+
+    // data destination
+    virtual void setPosition(int x, int y, int w, int h);
+    virtual void setSourceCrop(int x, int y, int w, int h);
+    virtual void setTransform(int transform);
+    virtual void setPlaneAlpha(uint8_t alpha, uint32_t blending);
+
+    // data source
+    virtual bool setDataBuffer(buffer_handle_t handle);
+
+    virtual void invalidateBufferCache();
+
+    // display device
+    virtual bool assignToDevice(int disp);
+
+    // hardware operations
+    virtual bool flip(void *ctx);
+    virtual void postFlip();
+
+    virtual bool reset();
+    virtual bool enable() = 0;
+    virtual bool disable() = 0;
+    virtual bool isDisabled() = 0;
+
+    // set z order config
+    virtual void setZOrderConfig(ZOrderConfig& config,
+                                     void *nativeConfig) = 0;
+
+    virtual void setZOrder(int zorder);
+    virtual int getZOrder() const;
+
+    virtual void* getContext() const = 0;
+
+    virtual bool initialize(uint32_t bufferCount);
+    virtual void deinitialize();
+
+protected:
+    virtual void checkPosition(int& x, int& y, int& w, int& h);
+    virtual bool setDataBuffer(BufferMapper& mapper) = 0;
+private:
+    inline BufferMapper* mapBuffer(DataBuffer *buffer);
+
+    inline int findActiveBuffer(BufferMapper *mapper);
+    void updateActiveBuffers(BufferMapper *mapper);
+    void invalidateActiveBuffers();
+protected:
+    int mIndex;
+    int mType;
+    int mZOrder;
+    int mDevice;
+    bool mInitialized;
+
+    // cached data buffers
+    KeyedVector<uint64_t, BufferMapper*> mDataBuffers;
+    // holding the most recent buffers
+    Vector<BufferMapper*> mActiveBuffers;
+    int mCacheCapacity;
+
+    PlanePosition mPosition;
+    crop_t mSrcCrop;
+    bool mIsProtectedBuffer;
+    int mTransform;
+    uint8_t mPlaneAlpha;
+    uint32_t mBlending;
+    buffer_handle_t mCurrentDataBuffer;
+    uint32_t mUpdateMasks;
+    drmModeModeInfo mModeInfo;
+    int mPanelOrientation;
+};
+
+} // namespace intel
+} // namespace android
+
+#endif /* DISPLAYPLANE_H_ */
diff --git a/merrifield/include/DisplayPlaneManager.h b/merrifield/include/DisplayPlaneManager.h
new file mode 100644
index 0000000..1c55d9f
--- /dev/null
+++ b/merrifield/include/DisplayPlaneManager.h
@@ -0,0 +1,112 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef DISPLAYPLANEMANAGER_H_
+#define DISPLAYPLANEMANAGER_H_
+
+#include <Dump.h>
+#include <DisplayPlane.h>
+#include <HwcLayer.h>
+#include <utils/Vector.h>
+
+namespace android {
+namespace intel {
+
+struct ZOrderLayer
+{
+    ZOrderLayer() {
+        memset(this, 0, sizeof(ZOrderLayer));
+    }
+
+    inline bool operator<(const ZOrderLayer& rhs) const {
+        return zorder < rhs.zorder;
+    }
+
+    int planeType;
+    int zorder;
+    DisplayPlane *plane;
+    HwcLayer *hwcLayer;
+};
+
+class ZOrderConfig : public SortedVector<ZOrderLayer*> {
+public:
+    ZOrderConfig() {}
+
+    int do_compare(const void* lhs, const void* rhs) const {
+        const ZOrderLayer *l = *(ZOrderLayer**)lhs;
+        const ZOrderLayer *r = *(ZOrderLayer**)rhs;
+
+        // sorted from z order 0 to n
+        return l->zorder - r->zorder;
+    }
+};
+
+
+class DisplayPlaneManager {
+public:
+    DisplayPlaneManager();
+    virtual ~DisplayPlaneManager();
+
+public:
+    virtual bool initialize();
+    virtual void deinitialize();
+
+    virtual bool isValidZOrder(int dsp, ZOrderConfig& config) = 0;
+    virtual bool assignPlanes(int dsp, ZOrderConfig& config) = 0;
+    // TODO: remove this API
+    virtual void* getZOrderConfig() const = 0;
+    virtual int getFreePlanes(int dsp, int type);
+    virtual void reclaimPlane(int dsp, DisplayPlane& plane);
+    virtual void disableReclaimedPlanes();
+    virtual bool isOverlayPlanesDisabled();
+    // dump interface
+    virtual void dump(Dump& d);
+
+protected:
+    // plane allocation & free
+    int getPlane(uint32_t& mask);
+    int getPlane(uint32_t& mask, int index);
+    DisplayPlane* getPlane(int type, int index);
+    DisplayPlane* getAnyPlane(int type);
+    void putPlane(int index, uint32_t& mask);
+    void putPlane(int dsp, DisplayPlane& plane);
+    bool isFreePlane(int type, int index);
+    virtual DisplayPlane* allocPlane(int index, int type) = 0;
+
+protected:
+    int mPlaneCount[DisplayPlane::PLANE_MAX];
+    int mTotalPlaneCount;
+    int mPrimaryPlaneCount;
+    int mSpritePlaneCount;
+    int mOverlayPlaneCount;
+    int mCursorPlaneCount;
+
+    Vector<DisplayPlane*> mPlanes[DisplayPlane::PLANE_MAX];
+
+    // Bitmap of free planes. Bit0 - plane A, bit 1 - plane B, etc.
+    uint32_t mFreePlanes[DisplayPlane::PLANE_MAX];
+    uint32_t mReclaimedPlanes[DisplayPlane::PLANE_MAX];
+
+    bool mInitialized;
+
+enum {
+    DEFAULT_PRIMARY_PLANE_COUNT = 3
+};
+};
+
+} // namespace intel
+} // namespace android
+
+#endif /* DISPLAYPLANEMANAGER_H_ */
diff --git a/merrifield/include/DisplayQuery.h b/merrifield/include/DisplayQuery.h
new file mode 100644
index 0000000..185a25d
--- /dev/null
+++ b/merrifield/include/DisplayQuery.h
@@ -0,0 +1,33 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef DISPLAY_QUERY_H
+#define DISPLAY_QUERY_H
+
+namespace android {
+namespace intel {
+
+class DisplayQuery
+{
+public:
+    static bool isVideoFormat(uint32_t format);
+    static int  getOverlayLumaStrideAlignment(uint32_t format);
+    static uint32_t queryNV12Format();
+};
+
+} // namespace intel
+} // namespace android
+
+#endif /*DISPLAY_QUERY_H*/
diff --git a/merrifield/include/DrmConfig.h b/merrifield/include/DrmConfig.h
new file mode 100644
index 0000000..23ab889
--- /dev/null
+++ b/merrifield/include/DrmConfig.h
@@ -0,0 +1,44 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef DRM_CONFIG_H
+#define DRM_CONFIG_H
+
+namespace android {
+namespace intel {
+
+#define fourcc_code(a, b, c, d) ((__u32)(a) | ((__u32)(b) << 8) | \
+                 ((__u32)(c) << 16) | ((__u32)(d) << 24))
+#define DRM_FORMAT_XRGB8888    fourcc_code('X', 'R', '2', '4') /* [31:0] x:R:G:B 8:8:8:8 little endian */
+
+class DrmConfig
+{
+public:
+    static const char* getDrmPath();
+    static uint32_t getDrmConnector(int device);
+    static uint32_t getDrmEncoder(int device);
+    static uint32_t getFrameBufferFormat();
+    static uint32_t getFrameBufferDepth();
+    static uint32_t getFrameBufferBpp();
+    static const char* getUeventEnvelope();
+    static const char* getHotplugString();
+    static const char* getRepeatedFrameString();
+    static uint32_t convertHalFormatToDrmFormat(uint32_t halFormat);
+};
+
+} // namespace intel
+} // namespace android
+
+#endif /*DRM_CONFIG_H*/
diff --git a/merrifield/include/ExternalDevice.h b/merrifield/include/ExternalDevice.h
new file mode 100644
index 0000000..ba22167
--- /dev/null
+++ b/merrifield/include/ExternalDevice.h
@@ -0,0 +1,65 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef EXTERNAL_DEVICE_H
+#define EXTERNAL_DEVICE_H
+
+#include <PhysicalDevice.h>
+#include <IHdcpControl.h>
+#include <SimpleThread.h>
+
+namespace android {
+namespace intel {
+
+
+class ExternalDevice : public PhysicalDevice {
+
+public:
+    ExternalDevice(Hwcomposer& hwc, DeviceControlFactory* controlFactory);
+    virtual ~ExternalDevice();
+public:
+    virtual bool initialize();
+    virtual void deinitialize();
+    virtual bool setDrmMode(drmModeModeInfo& value);
+    virtual void setRefreshRate(int hz);
+    virtual int  getActiveConfig();
+    virtual bool setActiveConfig(int index);
+    int getRefreshRate();
+
+private:
+    static void HdcpLinkStatusListener(bool success, void *userData);
+    void HdcpLinkStatusListener(bool success);
+    void setDrmMode();
+protected:
+    IHdcpControl *mHdcpControl;
+
+private:
+    static void hotplugEventListener(void *data);
+    void hotplugListener();
+
+private:
+    Condition mAbortModeSettingCond;
+    drmModeModeInfo mPendingDrmMode;
+    bool mHotplugEventPending;
+    int mExpectedRefreshRate;
+
+private:
+    DECLARE_THREAD(ModeSettingThread, ExternalDevice);
+};
+
+}
+}
+
+#endif /* EXTERNAL_DEVICE_H */
diff --git a/merrifield/include/GraphicBuffer.h b/merrifield/include/GraphicBuffer.h
new file mode 100644
index 0000000..65320d8
--- /dev/null
+++ b/merrifield/include/GraphicBuffer.h
@@ -0,0 +1,57 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef GRAPHIC_BUFFER_H
+#define GRAPHIC_BUFFER_H
+
+#include <DataBuffer.h>
+
+
+namespace android {
+namespace intel {
+
+class GraphicBuffer : public DataBuffer {
+public:
+    enum {
+        USAGE_INVALID = 0xffffffff,
+    };
+
+public:
+    GraphicBuffer(buffer_handle_t handle);
+    virtual ~GraphicBuffer() {}
+
+    virtual void resetBuffer(buffer_handle_t handle);
+
+    uint32_t getUsage() const { return mUsage; }
+    uint32_t getBpp() const { return mBpp; }
+
+    static bool isProtectedUsage(uint32_t usage);
+    static bool isProtectedBuffer(GraphicBuffer *buffer);
+
+    static bool isCompressionUsage(uint32_t usage);
+    static bool isCompressionBuffer(GraphicBuffer *buffer);
+
+private:
+    void initBuffer(buffer_handle_t handle);
+
+protected:
+    uint32_t mUsage;
+    uint32_t mBpp;
+};
+
+} // namespace intel
+} // namespace android
+
+#endif /* GRAPHIC_BUFFER_H */
diff --git a/merrifield/include/Hwcomposer.h b/merrifield/include/Hwcomposer.h
new file mode 100644
index 0000000..17e5365
--- /dev/null
+++ b/merrifield/include/Hwcomposer.h
@@ -0,0 +1,136 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef HWCOMPOSER_H
+#define HWCOMPOSER_H
+
+#include <EGL/egl.h>
+#include <hardware/hwcomposer.h>
+#include <utils/Vector.h>
+
+#include <IDisplayDevice.h>
+#include <BufferManager.h>
+#include <IDisplayContext.h>
+#include <Drm.h>
+#include <DisplayPlaneManager.h>
+#include <DisplayAnalyzer.h>
+#include <VsyncManager.h>
+#include <MultiDisplayObserver.h>
+#include <UeventObserver.h>
+#include <IPlatFactory.h>
+
+
+namespace android {
+namespace intel {
+
+class Hwcomposer : public hwc_composer_device_1_t {
+public:
+    virtual ~Hwcomposer();
+public:
+    // callbacks implementation
+    virtual bool prepare(size_t numDisplays,
+                           hwc_display_contents_1_t** displays);
+    virtual bool commit(size_t numDisplays,
+                           hwc_display_contents_1_t** displays);
+    virtual bool vsyncControl(int disp, int enabled);
+    virtual bool release();
+    virtual bool dump(char *buff, int buff_len, int *cur_len);
+    virtual void registerProcs(hwc_procs_t const *procs);
+
+    virtual bool blank(int disp, int blank);
+    virtual bool getDisplayConfigs(int disp,
+                                       uint32_t *configs,
+                                       size_t *numConfigs);
+    virtual bool getDisplayAttributes(int disp,
+                                          uint32_t config,
+                                          const uint32_t *attributes,
+                                          int32_t *values);
+    virtual bool compositionComplete(int disp);
+
+    virtual bool setPowerMode(int disp, int mode);
+    virtual int  getActiveConfig(int disp);
+    virtual bool setActiveConfig(int disp, int index);
+    virtual bool setCursorPositionAsync(int disp, int x, int y);
+
+    // callbacks
+    virtual void vsync(int disp, int64_t timestamp);
+    virtual void hotplug(int disp, bool connected);
+    virtual void invalidate();
+
+    virtual bool initCheck() const;
+    virtual bool initialize();
+    virtual void deinitialize();
+
+
+public:
+    Drm* getDrm();
+    DisplayPlaneManager* getPlaneManager();
+    BufferManager* getBufferManager();
+    IDisplayContext* getDisplayContext();
+    DisplayAnalyzer* getDisplayAnalyzer();
+    VsyncManager* getVsyncManager();
+    MultiDisplayObserver* getMultiDisplayObserver();
+    IDisplayDevice* getDisplayDevice(int disp);
+    UeventObserver* getUeventObserver();
+    IPlatFactory* getPlatFactory() {return mPlatFactory;}
+protected:
+    Hwcomposer(IPlatFactory *factory);
+
+public:
+    static Hwcomposer& getInstance() {
+        Hwcomposer *instance = sInstance;
+        if (instance == 0) {
+            instance = createHwcomposer();
+            sInstance = instance;
+        }
+        return *sInstance;
+    }
+    static void releaseInstance() {
+        delete sInstance;
+        sInstance = NULL;
+    }
+    // Need to be implemented
+    static Hwcomposer* createHwcomposer();
+
+
+private:
+    hwc_procs_t const *mProcs;
+    Drm *mDrm;
+
+    // plugin through set
+    IPlatFactory *mPlatFactory;
+    VsyncManager *mVsyncManager;
+    DisplayAnalyzer *mDisplayAnalyzer;
+    MultiDisplayObserver *mMultiDisplayObserver;
+    UeventObserver *mUeventObserver;
+
+    // created from IPlatFactory
+    DisplayPlaneManager *mPlaneManager;
+    BufferManager *mBufferManager;
+    IDisplayContext *mDisplayContext;
+
+    Vector<IDisplayDevice*> mDisplayDevices;
+
+    bool mInitialized;
+
+
+
+    static Hwcomposer *sInstance;
+};
+
+} // namespace intel
+}
+
+#endif /*HW_COMPOSER_H*/
diff --git a/merrifield/include/IBlankControl.h b/merrifield/include/IBlankControl.h
new file mode 100644
index 0000000..7051ce1
--- /dev/null
+++ b/merrifield/include/IBlankControl.h
@@ -0,0 +1,33 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef IBLANKCONTROL_H_
+#define IBLANKCONTROL_H_
+
+namespace android {
+namespace intel {
+
+class IBlankControl {
+public:
+    IBlankControl() {}
+    virtual ~IBlankControl() {}
+public:
+    virtual bool blank(int disp, bool blank) = 0;
+};
+
+} // namespace intel
+} // namespace android
+
+#endif /* IBLANKCONTROL_H_ */
diff --git a/merrifield/include/IDisplayContext.h b/merrifield/include/IDisplayContext.h
new file mode 100644
index 0000000..7767856
--- /dev/null
+++ b/merrifield/include/IDisplayContext.h
@@ -0,0 +1,43 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef IDISPLAY_CONTEXT_H
+#define IDISPLAY_CONTEXT_H
+
+#include <hardware/hwcomposer.h>
+
+namespace android {
+namespace intel {
+
+class HwcLayerList;
+
+class IDisplayContext {
+public:
+    IDisplayContext() {}
+    virtual ~IDisplayContext() {}
+public:
+    virtual bool initialize() = 0;
+    virtual void deinitialize() = 0;
+    virtual bool commitBegin(size_t numDisplays, hwc_display_contents_1_t **displays) = 0;
+    virtual bool commitContents(hwc_display_contents_1_t *display, HwcLayerList *layerList) = 0;
+    virtual bool commitEnd(size_t numDisplays, hwc_display_contents_1_t **displays) = 0;
+    virtual bool compositionComplete() = 0;
+    virtual bool setCursorPosition(int disp, int x, int y) = 0;
+};
+
+}
+}
+
+#endif /* IDISPLAY_CONTEXT_H */
diff --git a/merrifield/include/IDisplayDevice.h b/merrifield/include/IDisplayDevice.h
new file mode 100644
index 0000000..d9a6ac2
--- /dev/null
+++ b/merrifield/include/IDisplayDevice.h
@@ -0,0 +1,107 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef IDISPLAY_DEVICE_H
+#define IDISPLAY_DEVICE_H
+
+#include <Dump.h>
+#include <IDisplayContext.h>
+#include <DisplayPlane.h>
+
+namespace android {
+namespace intel {
+
+// display config
+class DisplayConfig {
+public:
+    DisplayConfig(int rr, int w, int h, int dpix, int dpiy)
+        : mRefreshRate(rr),
+          mWidth(w),
+          mHeight(h),
+          mDpiX(dpix),
+          mDpiY(dpiy)
+    {}
+public:
+    int getRefreshRate() const { return mRefreshRate; }
+    int getWidth() const { return mWidth; }
+    int getHeight() const { return mHeight; }
+    int getDpiX() const { return mDpiX; }
+    int getDpiY() const { return mDpiY; }
+private:
+    int mRefreshRate;
+    int mWidth;
+    int mHeight;
+    int mDpiX;
+    int mDpiY;
+};
+
+
+//  display device interface
+class IDisplayDevice {
+public:
+    // display device type
+    enum {
+        DEVICE_PRIMARY = HWC_DISPLAY_PRIMARY,
+        DEVICE_EXTERNAL = HWC_DISPLAY_EXTERNAL,
+#ifdef INTEL_WIDI_MERRIFIELD
+        DEVICE_VIRTUAL = HWC_DISPLAY_VIRTUAL,
+#endif
+        DEVICE_COUNT,
+    };
+    enum {
+        DEVICE_DISCONNECTED = 0,
+        DEVICE_CONNECTED,
+    };
+    enum {
+        DEVICE_DISPLAY_OFF = 0,
+        DEVICE_DISPLAY_ON,
+        DEVICE_DISPLAY_STANDBY,
+    };
+public:
+    IDisplayDevice() {}
+    virtual ~IDisplayDevice() {}
+public:
+    virtual bool prePrepare(hwc_display_contents_1_t *display) = 0;
+    virtual bool prepare(hwc_display_contents_1_t *display) = 0;
+    virtual bool commit(hwc_display_contents_1_t *display,
+                          IDisplayContext *context) = 0;
+
+    virtual bool vsyncControl(bool enabled) = 0;
+    virtual bool blank(bool blank) = 0;
+    virtual bool getDisplaySize(int *width, int *height) = 0;
+    virtual bool getDisplayConfigs(uint32_t *configs,
+                                       size_t *numConfigs) = 0;
+    virtual bool getDisplayAttributes(uint32_t config,
+                                          const uint32_t *attributes,
+                                          int32_t *values) = 0;
+    virtual bool compositionComplete() = 0;
+
+    virtual bool setPowerMode(int mode) = 0;
+    virtual int  getActiveConfig() = 0;
+    virtual bool setActiveConfig(int index) = 0;
+
+    virtual bool initialize() = 0;
+    virtual void deinitialize() = 0;
+    virtual bool isConnected() const = 0;
+    virtual const char* getName() const = 0;
+    virtual int getType() const = 0;
+    virtual void onVsync(int64_t timestamp) = 0;
+    virtual void dump(Dump& d) = 0;
+};
+
+}
+}
+
+#endif /* IDISPLAY_DEVICE_H */
diff --git a/merrifield/include/IHdcpControl.h b/merrifield/include/IHdcpControl.h
new file mode 100644
index 0000000..31a3bfd
--- /dev/null
+++ b/merrifield/include/IHdcpControl.h
@@ -0,0 +1,38 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef IHDCP_CONTROL_H
+#define IHDCP_CONTROL_H
+
+namespace android {
+namespace intel {
+
+typedef void (*HdcpStatusCallback)(bool success, void *userData);
+
+class IHdcpControl {
+public:
+    IHdcpControl() {}
+    virtual ~IHdcpControl() {}
+public:
+    virtual bool startHdcp() = 0;
+    virtual bool startHdcpAsync(HdcpStatusCallback cb, void *userData) = 0;
+    virtual bool stopHdcp() = 0;
+};
+
+} // namespace intel
+} // namespace android
+
+
+#endif /* IHDCP_CONTROL_H */
diff --git a/merrifield/include/IPlatFactory.h b/merrifield/include/IPlatFactory.h
new file mode 100644
index 0000000..71f3fe7
--- /dev/null
+++ b/merrifield/include/IPlatFactory.h
@@ -0,0 +1,45 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef IPLATFORM_FACTORY_H_
+#define IPLATFORM_FACTORY_H_
+
+
+#include <IDisplayDevice.h>
+#include <BufferManager.h>
+#include <IDisplayContext.h>
+#include <DisplayPlaneManager.h>
+#include <IVideoPayloadManager.h>
+
+
+namespace android {
+namespace intel {
+
+
+class IPlatFactory {
+
+public:
+    virtual ~IPlatFactory() {};
+public:
+    virtual DisplayPlaneManager* createDisplayPlaneManager() = 0;
+    virtual BufferManager* createBufferManager() = 0;
+    virtual IDisplayDevice* createDisplayDevice(int disp) = 0;
+    virtual IDisplayContext* createDisplayContext() = 0;
+    virtual IVideoPayloadManager* createVideoPayloadManager() = 0;
+};
+} // namespace intel
+} // namespace android
+
+#endif /* DATABUFFER_H__ */
diff --git a/merrifield/include/IPrepareListener.h b/merrifield/include/IPrepareListener.h
new file mode 100644
index 0000000..57dbba8
--- /dev/null
+++ b/merrifield/include/IPrepareListener.h
@@ -0,0 +1,33 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef IPREPARE_LISTENER_H
+#define IPREPARE_LISTENER_H
+
+namespace android {
+namespace intel {
+
+class IPrepareListener {
+public:
+    IPrepareListener() {}
+    virtual ~IPrepareListener() {}
+public:
+    virtual void onProtectedLayerStart(int disp) = 0;
+};
+
+} // namespace intel
+} // namespace android
+
+#endif /* IPREPARE_LISTENER_H */
diff --git a/merrifield/include/IVideoPayloadManager.h b/merrifield/include/IVideoPayloadManager.h
new file mode 100644
index 0000000..3aa0fc6
--- /dev/null
+++ b/merrifield/include/IVideoPayloadManager.h
@@ -0,0 +1,62 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef IVIDEO_PAYLOAD_MANAGER_H
+#define IVIDEO_PAYLOAD_MANAGER_H
+
+#include <hardware/hwcomposer.h>
+
+namespace android {
+namespace intel {
+
+class BufferMapper;
+
+class IVideoPayloadManager {
+public:
+    IVideoPayloadManager() {}
+    virtual ~IVideoPayloadManager() {}
+
+public:
+    struct Buffer {
+        buffer_handle_t khandle;
+        uint16_t width;
+        uint16_t height;
+        uint16_t bufWidth;
+        uint16_t bufHeight;
+        uint16_t lumaStride;
+        uint16_t chromaUStride;
+        uint16_t chromaVStride;
+        uint16_t offsetX;
+        uint16_t offsetY;
+        bool     tiled;
+    };
+    struct MetaData {
+        uint32_t format;
+        uint32_t transform;
+        int64_t  timestamp;
+        Buffer normalBuffer;
+        Buffer scalingBuffer;
+        Buffer rotationBuffer;
+    };
+
+public:
+    virtual bool getMetaData(BufferMapper *mapper, MetaData *metadata) = 0;
+    virtual bool setRenderStatus(BufferMapper *mapper, bool renderStatus) = 0;
+};
+
+} // namespace intel
+} // namespace android
+
+#endif /* IVIDEO_PAYLOAD_MANAGER_H */
diff --git a/merrifield/include/IVsyncControl.h b/merrifield/include/IVsyncControl.h
new file mode 100644
index 0000000..5edc77b
--- /dev/null
+++ b/merrifield/include/IVsyncControl.h
@@ -0,0 +1,37 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef IVSYNCCONTROL_H_
+#define IVSYNCCONTROL_H_
+
+namespace android {
+namespace intel {
+
+class IVsyncControl {
+public:
+    IVsyncControl() {};
+    virtual ~IVsyncControl() {};
+public:
+    virtual bool initialize() = 0;
+    virtual void deinitialize() = 0;
+    virtual bool control(int disp, bool enabled) = 0;
+    virtual bool wait(int disp, int64_t& timestamp) = 0;
+};
+
+} // namespace intel
+} // namespace android
+
+
+#endif /* IVSYNCCONTROL_H_ */
diff --git a/merrifield/include/PhysicalDevice.h b/merrifield/include/PhysicalDevice.h
new file mode 100644
index 0000000..9bbb90d
--- /dev/null
+++ b/merrifield/include/PhysicalDevice.h
@@ -0,0 +1,125 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef PHYSICAL_DEVICE_H
+#define PHYSICAL_DEVICE_H
+
+#include <DisplayPlane.h>
+#include <IVsyncControl.h>
+#include <IBlankControl.h>
+#include <IPrepareListener.h>
+#include <VsyncEventObserver.h>
+#include <HwcLayerList.h>
+#include <Drm.h>
+#include <IDisplayDevice.h>
+
+namespace android {
+namespace intel {
+
+class IHdcpControl;
+
+class DeviceControlFactory {
+public:
+    virtual ~DeviceControlFactory(){}
+public:
+    virtual IVsyncControl* createVsyncControl() = 0;
+    virtual IBlankControl* createBlankControl() = 0;
+    virtual IHdcpControl* createHdcpControl() = 0;
+};
+
+class Hwcomposer;
+
+// Base class for primary and external devices
+class PhysicalDevice : public IDisplayDevice {
+public:
+    PhysicalDevice(uint32_t type, Hwcomposer& hwc, DeviceControlFactory* controlFactory);
+    virtual ~PhysicalDevice();
+public:
+    virtual bool prePrepare(hwc_display_contents_1_t *display);
+    virtual bool prepare(hwc_display_contents_1_t *display);
+    virtual bool commit(hwc_display_contents_1_t *display, IDisplayContext *context);
+
+    virtual bool vsyncControl(bool enabled);
+    virtual bool blank(bool blank);
+    virtual bool getDisplaySize(int *width, int *height);
+    virtual bool getDisplayConfigs(uint32_t *configs,
+                                       size_t *numConfigs);
+    virtual bool getDisplayAttributes(uint32_t config,
+                                          const uint32_t *attributes,
+                                          int32_t *values);
+    virtual bool compositionComplete();
+
+    virtual bool setPowerMode(int mode);
+    virtual int  getActiveConfig();
+    virtual bool setActiveConfig(int index);
+
+    // display config operations
+    virtual void removeDisplayConfigs();
+    virtual bool detectDisplayConfigs();
+
+    // device related operations
+    virtual bool initCheck() const { return mInitialized; }
+    virtual bool initialize();
+    virtual void deinitialize();
+    virtual bool isConnected() const;
+    virtual const char* getName() const;
+    virtual int getType() const;
+
+    //events
+    virtual void onVsync(int64_t timestamp);
+
+    virtual void dump(Dump& d);
+
+protected:
+    void onGeometryChanged(hwc_display_contents_1_t *list);
+    bool updateDisplayConfigs();
+    IVsyncControl* createVsyncControl() {return mControlFactory->createVsyncControl();}
+    friend class VsyncEventObserver;
+
+protected:
+    uint32_t mType;
+    const char *mName;
+
+    Hwcomposer& mHwc;
+
+    // display configs
+    Vector<DisplayConfig*> mDisplayConfigs;
+    int mActiveDisplayConfig;
+
+
+    IBlankControl *mBlankControl;
+    VsyncEventObserver *mVsyncObserver;
+
+    DeviceControlFactory *mControlFactory;
+
+    // layer list
+    HwcLayerList *mLayerList;
+    bool mConnected;
+    bool mBlank;
+
+    // lock
+    Mutex mLock;
+
+    // DPMS on (1) or off (0)
+    int mDisplayState;
+    bool mInitialized;
+};
+
+
+
+}
+}
+
+#endif /* PHYSICAL_DEVICE_H */
diff --git a/merrifield/include/PlaneCapabilities.h b/merrifield/include/PlaneCapabilities.h
new file mode 100644
index 0000000..0962fda
--- /dev/null
+++ b/merrifield/include/PlaneCapabilities.h
@@ -0,0 +1,38 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef PLANE_CAPABILITIES_H
+#define PLANE_CAPABILITIES_H
+
+#include <DataBuffer.h>
+
+namespace android {
+namespace intel {
+
+class HwcLayer;
+class PlaneCapabilities
+{
+public:
+    static bool isFormatSupported(int planeType, HwcLayer *hwcLayer);
+    static bool isSizeSupported(int planeType,  HwcLayer *hwcLayer);
+    static bool isBlendingSupported(int planeType, HwcLayer *hwcLayer);
+    static bool isScalingSupported(int planeType, HwcLayer *hwcLayer);
+    static bool isTransformSupported(int planeType,  HwcLayer *hwcLayer);
+};
+
+} // namespace intel
+} // namespace android
+
+#endif /*PLANE_CAPABILITIES_H*/
diff --git a/merrifield/include/PrimaryDevice.h b/merrifield/include/PrimaryDevice.h
new file mode 100644
index 0000000..6354193
--- /dev/null
+++ b/merrifield/include/PrimaryDevice.h
@@ -0,0 +1,47 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef PRIMARY_DEVICE_H
+#define PRIMARY_DEVICE_H
+
+#include <DisplayPlane.h>
+#include <IVsyncControl.h>
+#include <IBlankControl.h>
+#include <VsyncEventObserver.h>
+#include <HwcLayerList.h>
+#include <PhysicalDevice.h>
+
+namespace android {
+namespace intel {
+
+
+class PrimaryDevice : public PhysicalDevice {
+public:
+    PrimaryDevice(Hwcomposer& hwc, DeviceControlFactory* controlFactory);
+    virtual ~PrimaryDevice();
+public:
+    virtual bool initialize();
+    virtual void deinitialize();
+
+    bool blank(bool blank);
+private:
+    static void repeatedFrameEventListener(void *data);
+    void repeatedFrameListener();
+};
+
+}
+}
+
+#endif /* PRIMARY_DEVICE_H */
diff --git a/merrifield/include/UeventObserver.h b/merrifield/include/UeventObserver.h
new file mode 100755
index 0000000..b1ca781
--- /dev/null
+++ b/merrifield/include/UeventObserver.h
@@ -0,0 +1,64 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef UEVENT_OBSERVER_H
+#define UEVENT_OBSERVER_H
+
+#include <utils/KeyedVector.h>
+#include <utils/String8.h>
+#include <SimpleThread.h>
+
+namespace android {
+namespace intel {
+
+typedef void (*UeventListenerFunc)(void *data);
+
+class UeventObserver
+{
+public:
+    UeventObserver();
+    virtual ~UeventObserver();
+
+public:
+    bool initialize();
+    void deinitialize();
+    void start();
+    void registerListener(const char *event, UeventListenerFunc func, void *data);
+
+private:
+    DECLARE_THREAD(UeventObserverThread, UeventObserver);
+    void onUevent();
+
+private:
+    enum {
+        UEVENT_MSG_LEN = 4096,
+    };
+
+    char mUeventMessage[UEVENT_MSG_LEN];
+    int mUeventFd;
+    int mExitRDFd;
+    int mExitWDFd;
+    struct UeventListener {
+        UeventListenerFunc func;
+        void *data;
+    };
+    KeyedVector<String8, UeventListener*> mListeners;
+};
+
+} // namespace intel
+} // namespace android
+
+#endif
+
diff --git a/merrifield/include/VirtualDevice.h b/merrifield/include/VirtualDevice.h
new file mode 100755
index 0000000..2af3c6b
--- /dev/null
+++ b/merrifield/include/VirtualDevice.h
@@ -0,0 +1,221 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef VIRTUAL_DEVICE_H
+#define VIRTUAL_DEVICE_H
+
+#include <IDisplayDevice.h>
+#include <SimpleThread.h>
+#include <IVideoPayloadManager.h>
+#include <utils/Condition.h>
+#include <utils/Mutex.h>
+#include <utils/Vector.h>
+
+#include "IFrameServer.h"
+
+#include <va/va.h>
+#include <va/va_vpp.h>
+
+namespace android {
+namespace intel {
+
+class Hwcomposer;
+class DisplayPlaneManager;
+class IVideoPayloadManager;
+class SoftVsyncObserver;
+
+class VirtualDevice : public IDisplayDevice, public BnFrameServer {
+protected:
+    class VAMappedHandle;
+    class VAMappedHandleObject;
+    struct CachedBuffer : public android::RefBase {
+        CachedBuffer(BufferManager *mgr, buffer_handle_t handle);
+        ~CachedBuffer();
+        BufferManager *manager;
+        BufferMapper *mapper;
+        VAMappedHandle *vaMappedHandle;
+        buffer_handle_t cachedKhandle;
+    };
+    struct HeldDecoderBuffer : public android::RefBase {
+        HeldDecoderBuffer(const sp<VirtualDevice>& vd, const android::sp<CachedBuffer>& cachedBuffer);
+        virtual ~HeldDecoderBuffer();
+        android::sp<VirtualDevice> vd;
+        android::sp<CachedBuffer> cachedBuffer;
+    };
+    struct Configuration {
+        sp<IFrameTypeChangeListener> typeChangeListener;
+        sp<IFrameListener> frameListener;
+        FrameProcessingPolicy policy;
+        bool frameServerActive;
+        bool extendedModeEnabled;
+        bool forceNotifyFrameType;
+        bool forceNotifyBufferInfo;
+    };
+    class BufferList {
+    public:
+        BufferList(VirtualDevice& vd, const char* name, uint32_t limit, uint32_t format, uint32_t usage);
+        buffer_handle_t get(uint32_t width, uint32_t height, sp<RefBase>* heldBuffer);
+        void clear();
+    private:
+        struct HeldBuffer;
+        VirtualDevice& mVd;
+        const char* mName;
+        android::List<buffer_handle_t> mAvailableBuffers;
+        const uint32_t mLimit;
+        const uint32_t mFormat;
+        const uint32_t mUsage;
+        uint32_t mBuffersToCreate;
+        uint32_t mWidth;
+        uint32_t mHeight;
+    };
+    struct Task;
+    struct RenderTask;
+    struct ComposeTask;
+    struct EnableVspTask;
+    struct DisableVspTask;
+    struct BlitTask;
+    struct FrameTypeChangedTask;
+    struct BufferInfoChangedTask;
+    struct OnFrameReadyTask;
+
+    Mutex mConfigLock;
+    Configuration mCurrentConfig;
+    Configuration mNextConfig;
+    ssize_t mRgbLayer;
+    ssize_t mYuvLayer;
+    bool mProtectedMode;
+
+    buffer_handle_t mExtLastKhandle;
+    int64_t mExtLastTimestamp;
+
+    int64_t mRenderTimestamp;
+
+    Mutex mTaskLock; // for task queue and buffer lists
+    BufferList mCscBuffers;
+    BufferList mRgbUpscaleBuffers;
+    DECLARE_THREAD(WidiBlitThread, VirtualDevice);
+    Condition mRequestQueued;
+    Condition mRequestDequeued;
+    Vector< sp<Task> > mTasks;
+
+    // fence info
+    int mSyncTimelineFd;
+    unsigned mNextSyncPoint;
+    bool mExpectAcquireFences;
+
+    FrameInfo mLastInputFrameInfo;
+    FrameInfo mLastOutputFrameInfo;
+
+    int32_t mVideoFramerate;
+
+    android::KeyedVector<buffer_handle_t, android::sp<CachedBuffer> > mMappedBufferCache;
+    android::Mutex mHeldBuffersLock;
+    android::KeyedVector<buffer_handle_t, android::sp<android::RefBase> > mHeldBuffers;
+
+    // VSP
+    bool mVspInUse;
+    bool mVspEnabled;
+    uint32_t mVspWidth;
+    uint32_t mVspHeight;
+    VADisplay va_dpy;
+    VAConfigID va_config;
+    VAContextID va_context;
+    VASurfaceID va_blank_yuv_in;
+    VASurfaceID va_blank_rgb_in;
+    android::KeyedVector<buffer_handle_t, android::sp<VAMappedHandleObject> > mVaMapCache;
+
+    bool mVspUpscale;
+    bool mDebugVspClear;
+    bool mDebugVspDump;
+    uint32_t mDebugCounter;
+
+private:
+    android::sp<CachedBuffer> getMappedBuffer(buffer_handle_t handle);
+
+    bool sendToWidi(hwc_display_contents_1_t *display);
+    bool queueCompose(hwc_display_contents_1_t *display);
+    bool queueColorConvert(hwc_display_contents_1_t *display);
+    bool handleExtendedMode(hwc_display_contents_1_t *display);
+
+    void queueFrameTypeInfo(const FrameInfo& inputFrameInfo);
+    void queueBufferInfo(const FrameInfo& outputFrameInfo);
+
+    void colorSwap(buffer_handle_t src, buffer_handle_t dest, uint32_t pixelCount);
+    void vspPrepare(uint32_t width, uint32_t height);
+    void vspEnable(uint32_t width, uint32_t height);
+    void vspDisable();
+    void vspCompose(VASurfaceID videoIn, VASurfaceID rgbIn, VASurfaceID videoOut,
+                    const VARectangle* surface_region, const VARectangle* output_region);
+
+    bool getFrameOfSize(uint32_t width, uint32_t height, const IVideoPayloadManager::MetaData& metadata, IVideoPayloadManager::Buffer& info);
+    void setMaxDecodeResolution(uint32_t width, uint32_t height);
+
+public:
+    VirtualDevice(Hwcomposer& hwc);
+    virtual ~VirtualDevice();
+    bool isFrameServerActive() const;
+
+public:
+    virtual bool prePrepare(hwc_display_contents_1_t *display);
+    virtual bool prepare(hwc_display_contents_1_t *display);
+    virtual bool commit(hwc_display_contents_1_t *display,
+                          IDisplayContext *context);
+
+    virtual bool vsyncControl(bool enabled);
+    virtual bool blank(bool blank);
+    virtual bool getDisplaySize(int *width, int *height);
+    virtual bool getDisplayConfigs(uint32_t *configs,
+                                       size_t *numConfigs);
+    virtual bool getDisplayAttributes(uint32_t config,
+                                          const uint32_t *attributes,
+                                          int32_t *values);
+    virtual bool compositionComplete();
+    virtual bool initialize();
+    virtual void deinitialize();
+    virtual bool isConnected() const;
+    virtual const char* getName() const;
+    virtual int getType() const;
+    virtual void onVsync(int64_t timestamp);
+    virtual void dump(Dump& d);
+
+    // IFrameServer methods
+    virtual android::status_t start(sp<IFrameTypeChangeListener> frameTypeChangeListener);
+    virtual android::status_t stop(bool isConnected);
+	/* TODO: 64-bit - this handle of size 32-bit is a problem for 64-bit */
+    virtual android::status_t notifyBufferReturned(int handle);
+    virtual android::status_t setResolution(const FrameProcessingPolicy& policy, android::sp<IFrameListener> listener);
+    virtual bool setPowerMode(int mode);
+    virtual int  getActiveConfig();
+    virtual bool setActiveConfig(int index);
+
+protected:
+    bool mInitialized;
+    Hwcomposer& mHwc;
+    IVideoPayloadManager *mPayloadManager;
+    SoftVsyncObserver *mVsyncObserver;
+    uint32_t mOrigContentWidth;
+    uint32_t mOrigContentHeight;
+    bool mFirstVideoFrame;
+    bool mLastConnectionStatus;
+    uint32_t mCachedBufferCapcity;
+    uint32_t mDecWidth;
+    uint32_t mDecHeight;
+    bool mIsForceCloneMode;
+};
+
+}
+}
+
+#endif /* VIRTUAL_DEVICE_H */
diff --git a/merrifield/include/pvr/hal/hal_public.h b/merrifield/include/pvr/hal/hal_public.h
new file mode 100644
index 0000000..9cd6db2
--- /dev/null
+++ b/merrifield/include/pvr/hal/hal_public.h
@@ -0,0 +1,257 @@
+/* Copyright (c) Imagination Technologies Ltd.
+ *
+ * The contents of this file are subject to the MIT license as set out below.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef HAL_PUBLIC_H
+#define HAL_PUBLIC_H
+
+/* Authors of third party hardware composer (HWC) modules will need to include
+ * this header to access functionality in the gralloc HAL.
+ */
+
+#define PVR_ANDROID_NATIVE_WINDOW_HAS_SYNC
+
+#include <hardware/gralloc.h>
+#include <hardware/hwcomposer.h>
+
+#define ALIGN(x,a)		(((x) + (a) - 1L) & ~((a) - 1L))
+#define HW_ALIGN		32
+#define CAMERA_ALIGN    64
+
+/** YV12 specific (to handle different alignment) ****************************/
+
+/* We must align YV12 to a multiple of 32bytes as NEON optimizations
+ * in stagefright require the YV12 planes to be 128bit aligned.
+ * while display controller requires 64 bytes alignement
+ */
+#define YV12_ALIGN 128
+
+#define HAL_PIXEL_FORMAT_BGRX_8888 0x101 // Keep consistent with android_utils.h 
+enum {
+	HAL_PIXEL_FORMAT_NV12   = 0x3231564E, // YCrCb 4:2:0 SP
+	HAL_PIXEL_FORMAT_NV21   = 0x3132564E, // YCrCb 4:2:0 SP
+	HAL_PIXEL_FORMAT_I420   = 0x30323449,
+	HAL_PIXEL_FORMAT_YUY2   = 0x32595559,
+	HAL_PIXEL_FORMAT_UYVY   = 0x59565955,
+
+	// Intel video decode formats
+	HAL_PIXEL_FORMAT_NV12_VED = 0x7FA00E00, //OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar
+	HAL_PIXEL_FORMAT_NV12_VEDT = 0x7FA00F00, //OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar_Tiled
+
+	HAL_PIXEL_FORMAT_YCbCr_422_P        = 0x12, // IYUV
+	HAL_PIXEL_FORMAT_YCbCr_420_P        = 0x13, // YUV9
+	HAL_PIXEL_FORMAT_YCbCr_420_I        = 0x15,
+
+	HAL_PIXEL_FORMAT_INTEL_UYVY  		= 0x107,
+	HAL_PIXEL_FORMAT_YCbCr_420_SP       = 0x108,
+	HAL_PIXEL_FORMAT_ZSL                = 0x109,
+};
+
+/* This can be tuned down as appropriate for the SOC.
+ *
+ * IMG formats are usually a single sub-alloc.
+ * Some OEM video formats are two sub-allocs (Y, UV planes).
+ * Future OEM video formats might be three sub-allocs (Y, U, V planes).
+ */
+#define MAX_SUB_ALLOCS 3
+
+
+/* This defines the maximum server sync objects used per allocation. */
+
+/* Note: It's unfortunate that we have to change the handle size dependent
+ * on a build option, but we have no choice because 'fd' fields must all
+ * be utilized so they are valid to be dup'ed, and we don't need some of
+ * the extra fds in a native_fence_sync build.
+ */
+#if defined(PVR_ANDROID_NATIVE_WINDOW_HAS_SYNC)
+#define MAX_SRV_SYNC_OBJS    2
+#else
+#define MAX_SRV_SYNC_OBJS    4
+#endif
+
+typedef struct
+{
+	native_handle_t base;
+
+	/* These fields can be sent cross process. They are also valid
+	 * to duplicate within the same process.
+	 *
+	 * A table is stored within psPrivateData on gralloc_module_t (this
+	 * is obviously per-process) which maps stamps to a mapped
+	 * PVRSRV_MEMDESC in that process. Each map entry has a lock
+	 * count associated with it, satisfying the requirements of the
+	 * Android API. This also prevents us from leaking maps/allocations.
+	 *
+	 * This table has entries inserted either by alloc()
+	 * (alloc_device_t) or map() (gralloc_module_t). Entries are removed
+	 * by free() (alloc_device_t) and unmap() (gralloc_module_t).
+	 */
+
+#define IMG_NATIVE_HANDLE_NUMFDS (MAX_SRV_SYNC_OBJS + MAX_SUB_ALLOCS)
+	/* The `syncfd' field is used to export PVRSRV_CLIENT_SYNC_PRIM to
+	 * another process. Its producer/consumer rules should match the
+	 * PVRSRV_MEMDESC handles, except that there is only one sync
+	 * per N memdesc objects.
+	 *
+	 * This should be listed before `fd' because it is not variable
+	 * width. The problem with variable width is that in the case we
+	 * export framebuffer allocations, we may want to patch some of
+	 * the fds to (unused) ints, so we can't leave gaps.
+	 */
+	int aiSyncFD[MAX_SRV_SYNC_OBJS];
+
+	/* The `fd' field is used to "export" a meminfo to another process.
+	 * Therefore, it is allocated by alloc_device_t, and consumed by
+	 * gralloc_module_t.
+	 */
+	int fd[MAX_SUB_ALLOCS];
+
+#define IMG_NATIVE_HANDLE_NUMINTS ((sizeof(unsigned long long) / sizeof(int)) + 5)
+	/* A KERNEL unique identifier for any exported kernel meminfo. Each
+	 * exported kernel meminfo will have a unique stamp, but note that in
+	 * userspace, several meminfos across multiple processes could have
+	 * the same stamp. As the native_handle can be dup(2)'d, there could be
+	 * multiple handles with the same stamp but different file descriptors.
+	 */
+	unsigned long long ui64Stamp;
+
+	/* This is used for buffer usage validation when locking a buffer,
+	 * and also in WSEGL (for the composition bypass feature).
+	 */
+	int usage;
+
+	/* In order to do efficient cache flushes we need the buffer dimensions
+	 * and format. These are available on the ANativeWindowBuffer,
+	 * but the platform doesn't pass them down to the graphics HAL.
+	 *
+	 * These fields are also used in the composition bypass. In this
+	 * capacity, these are the "real" values for the backing allocation.
+	 */
+	int iWidth;
+	int iHeight;
+	int iFormat;
+	unsigned int uiBpp;
+}
+__attribute__((aligned(sizeof(int)),packed)) IMG_native_handle_t;
+
+typedef struct
+{
+	int l, t, w, h;
+}
+IMG_write_lock_rect_t;
+
+/* Keep this in sync with SGX */
+typedef int (*IMG_buffer_format_compute_params_pfn)(
+	unsigned int uiPlane, int *piWidth, int *piHeight, int *piStride,
+	int *piVStride, unsigned long *pulPlaneOffset);
+
+#define IMG_BFF_YUV					(1 << 0)
+#define IMG_BFF_UVCbCrORDERING		(1 << 1)
+#define IMG_BFF_CPU_CLEAR			(1 << 2)
+#define IMG_BFF_DONT_GPU_CLEAR		(1 << 3)
+#define IMG_BFF_PARTIAL_ALLOC		(1 << 4)
+#define IMG_BFF_NEVER_COMPRESS		(1 << 5)
+
+/* Keep this in sync with SGX */
+typedef struct IMG_buffer_format_public_t
+{
+	/* Buffer formats are returned as a linked list */
+	struct IMG_buffer_format_public_t *psNext;
+
+	/* HAL_PIXEL_FORMAT_... enumerant */
+	int iHalPixelFormat;
+
+	/* IMG_PIXFMT_... enumerant */
+	int iIMGPixelFormat;
+
+	/* Friendly name for format */
+	const char *const szName;
+
+	/* Bits (not bytes) per pixel */
+	unsigned int uiBpp;
+
+	/* Supported HW usage bits. If this is GRALLOC_USAGE_HW_MASK, all usages
+	 * are supported. Used for HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED.
+	 */
+	int iSupportedUsage;
+
+	/* Allocation description flags */
+	unsigned int uiFlags;
+
+	/* Utility function for adjusting YUV per-plane parameters */
+	IMG_buffer_format_compute_params_pfn pfnComputeParams;
+}
+IMG_buffer_format_public_t;
+
+typedef struct
+{
+	/* The original hwc layer */
+	hwc_layer_1_t *psLayer;
+
+	/* Custom data for the display engine */
+	unsigned long custom;
+}
+IMG_hwc_layer_t;
+
+typedef struct IMG_display_device_public_t {
+	int (*post)(struct IMG_display_device_public_t *dev, IMG_hwc_layer_t *layers,
+				int num_layers, int *releaseFenceFd);
+} IMG_display_device_public_t;
+
+typedef struct IMG_gralloc_module_public_t
+{
+	gralloc_module_t base;
+	IMG_display_device_public_t *psDisplayDevice;
+
+	/* Gets the head of the linked list of all registered formats */
+	const IMG_buffer_format_public_t *(*GetBufferFormats)(void);
+
+	/* Functionality before this point should be in sync with SGX.
+	 * After this point will be different.
+	 */
+
+	/* Custom-blit components in lieu of overlay hardware */
+	int (*Blit)(struct IMG_gralloc_module_public_t const *module,
+				 buffer_handle_t src, buffer_handle_t dest,
+				 int w, int h, int x, int y,
+				 int filter,
+				 int transform,
+				 int async);
+
+	int (*Blit3)(struct IMG_gralloc_module_public_t const *module,
+				 unsigned long long ui64SrcStamp, int iSrcWidth,
+				 int iSrcHeight, int iSrcFormat, int eSrcRotation,
+				 buffer_handle_t dest, int eDestRotation);
+
+	/* Walk the above list and return only the specified format */
+	const IMG_buffer_format_public_t *(*GetBufferFormat)(int iFormat);
+/* intel hwc extension */
+	int (*getCpuAddress)(struct IMG_gralloc_module_public_t const *module,
+				buffer_handle_t handle,
+				void **virt, uint32_t *size);
+	int (*putCpuAddress)(struct IMG_gralloc_module_public_t const *module,
+			buffer_handle_t handle);
+	IMG_display_device_public_t *(*getDisplayDevice)(struct IMG_gralloc_module_public_t *module);
+}
+IMG_gralloc_module_public_t;
+
+#endif /* HAL_PUBLIC_H */
diff --git a/merrifield/ips/anniedale/AnnCursorPlane.cpp b/merrifield/ips/anniedale/AnnCursorPlane.cpp
new file mode 100644
index 0000000..c6607dd
--- /dev/null
+++ b/merrifield/ips/anniedale/AnnCursorPlane.cpp
@@ -0,0 +1,223 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#include <HwcTrace.h>
+#include <Hwcomposer.h>
+#include <BufferManager.h>
+#include <anniedale/AnnCursorPlane.h>
+#include <tangier/TngGrallocBuffer.h>
+#include <hal_public.h>
+
+namespace android {
+namespace intel {
+
+AnnCursorPlane::AnnCursorPlane(int index, int disp)
+    : DisplayPlane(index, PLANE_CURSOR, disp)
+{
+    CTRACE();
+    memset(&mContext, 0, sizeof(mContext));
+    memset(&mCrop, 0, sizeof(mCrop));
+}
+
+AnnCursorPlane::~AnnCursorPlane()
+{
+    CTRACE();
+}
+
+bool AnnCursorPlane::enable()
+{
+    return enablePlane(true);
+
+}
+
+bool AnnCursorPlane::disable()
+{
+    return enablePlane(false);
+}
+
+bool AnnCursorPlane::reset()
+{
+    // clear mCrop once reset
+    memset(&mCrop, 0, sizeof(mCrop));
+    return true;
+}
+
+void* AnnCursorPlane::getContext() const
+{
+    CTRACE();
+    return (void *)&mContext;
+}
+
+void AnnCursorPlane::setZOrderConfig(ZOrderConfig& config, void *nativeConfig)
+{
+    (void) config;
+    (void) nativeConfig;
+
+    CTRACE();
+}
+
+bool AnnCursorPlane::setDataBuffer(buffer_handle_t handle)
+{
+    bool ret;
+
+    if (!handle) {
+        ETRACE("handle is NULL");
+        return false;
+    }
+
+    ret = DisplayPlane::setDataBuffer(handle);
+    if (ret == false) {
+        ETRACE("failed to set data buffer");
+        return ret;
+    }
+
+    return true;
+}
+
+bool AnnCursorPlane::setDataBuffer(BufferMapper& mapper)
+{
+    int w = mapper.getWidth();
+    int h = mapper.getHeight();
+    int cursorSize = 0;
+
+    CTRACE();
+
+    // setup plane position
+    int dstX = mPosition.x;
+    int dstY = mPosition.y;
+
+    if (h < w) {
+        cursorSize = h;
+    } else {
+        cursorSize = w;
+    }
+
+    uint32_t cntr = 0;
+    if (64 <= cursorSize && cursorSize < 128) {
+        cursorSize = 64;
+        cntr = 0x7;
+    } else if (128 <= cursorSize && cursorSize < 256) {
+        cursorSize = 128;
+        cntr = 0x2;
+    } else {
+        cursorSize = 256;
+        cntr = 0x3;
+    }
+
+    if (mapper.getFormat() == HAL_PIXEL_FORMAT_RGBA_8888) {
+        cntr |= 1 << 5;
+    } else if (mapper.getFormat() == HAL_PIXEL_FORMAT_BGRA_8888) {
+        // swap color from BGRA to RGBA - alpha is MSB
+        uint8_t *p = (uint8_t *)(mapper.getCpuAddress(0));
+        uint8_t *srcPixel;
+        uint32_t stride = mapper.getStride().rgb.stride;
+        uint8_t temp;
+        if (!p) {
+            return false;
+        }
+
+        for (int i = 0; i < cursorSize; i++) {
+            for (int j = 0; j < cursorSize; j++) {
+                srcPixel = p + i*stride + j*4;
+                temp = srcPixel[0];
+                srcPixel[0] = srcPixel[2];
+                srcPixel[2] = temp;
+            }
+        }
+        cntr |= 1 << 5;
+    } else {
+        ETRACE("invalid color format");
+        return false;
+    }
+
+    // update context
+    mContext.type = DC_CURSOR_PLANE;
+    mContext.ctx.cs_ctx.index = mIndex;
+    mContext.ctx.cs_ctx.pipe = mDevice;
+    mContext.ctx.cs_ctx.cntr = cntr;
+    mContext.ctx.cs_ctx.surf = mapper.getGttOffsetInPage(0) << 12;
+
+    mContext.ctx.cs_ctx.pos = 0;
+    if (dstX < 0) {
+        mContext.ctx.cs_ctx.pos |= 1 << 15;
+        dstX = -dstX;
+    }
+    if (dstY < 0) {
+        mContext.ctx.cs_ctx.pos |= 1 << 31;
+        dstY = -dstY;
+    }
+    mContext.ctx.cs_ctx.pos |= (dstY & 0xfff) << 16 | (dstX & 0xfff);
+    return true;
+}
+
+bool AnnCursorPlane::enablePlane(bool enabled)
+{
+    RETURN_FALSE_IF_NOT_INIT();
+
+    struct drm_psb_register_rw_arg arg;
+    memset(&arg, 0, sizeof(struct drm_psb_register_rw_arg));
+    if (enabled) {
+        arg.plane_enable_mask = 1;
+    } else {
+        arg.plane_disable_mask = 1;
+    }
+
+    arg.plane.type = DC_CURSOR_PLANE;
+    arg.plane.index = mIndex;
+    arg.plane.ctx = 0;
+
+    // issue ioctl
+    Drm *drm = Hwcomposer::getInstance().getDrm();
+    bool ret = drm->writeReadIoctl(DRM_PSB_REGISTER_RW, &arg, sizeof(arg));
+    if (ret == false) {
+        WTRACE("plane enabling (%d) failed with error code %d", enabled, ret);
+        return false;
+    }
+
+    return true;
+}
+
+bool AnnCursorPlane::isDisabled()
+{
+    RETURN_FALSE_IF_NOT_INIT();
+
+    struct drm_psb_register_rw_arg arg;
+    memset(&arg, 0, sizeof(struct drm_psb_register_rw_arg));
+
+    arg.plane.type = DC_CURSOR_PLANE;
+    arg.get_plane_state_mask = 1;
+    arg.plane.index = mIndex;
+    arg.plane.ctx = 0;
+
+    // issue ioctl
+    Drm *drm = Hwcomposer::getInstance().getDrm();
+    bool ret = drm->writeReadIoctl(DRM_PSB_REGISTER_RW, &arg, sizeof(arg));
+    if (ret == false) {
+        WTRACE("plane state query failed with error code %d", ret);
+        return false;
+    }
+
+    return arg.plane.ctx == PSB_DC_PLANE_DISABLED;
+}
+
+void AnnCursorPlane::postFlip()
+{
+    // prevent mUpdateMasks from being reset
+    // skipping flip may cause flicking
+}
+
+} // namespace intel
+} // namespace android
diff --git a/merrifield/ips/anniedale/AnnCursorPlane.h b/merrifield/ips/anniedale/AnnCursorPlane.h
new file mode 100644
index 0000000..88d8075
--- /dev/null
+++ b/merrifield/ips/anniedale/AnnCursorPlane.h
@@ -0,0 +1,59 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#ifndef ANN_CUR_PLANE_H
+#define ANN_CUR_PLANE_H
+
+#include <utils/KeyedVector.h>
+#include <hal_public.h>
+#include <Hwcomposer.h>
+#include <BufferCache.h>
+#include <DisplayPlane.h>
+
+#include <linux/psb_drm.h>
+
+namespace android {
+namespace intel {
+
+class AnnCursorPlane : public DisplayPlane {
+public:
+    AnnCursorPlane(int index, int disp);
+    virtual ~AnnCursorPlane();
+public:
+    // hardware operations
+    bool enable();
+    bool disable();
+    bool reset();
+    bool isDisabled();
+    void postFlip();
+
+    void* getContext() const;
+    void setZOrderConfig(ZOrderConfig& config, void *nativeConfig);
+
+    bool setDataBuffer(buffer_handle_t handle);
+protected:
+    bool setDataBuffer(BufferMapper& mapper);
+    bool enablePlane(bool enabled);
+
+protected:
+    struct intel_dc_plane_ctx mContext;
+    crop_t mCrop;
+};
+
+} // namespace intel
+} // namespace android
+
+#endif /* ANN_CUR_PLANE_H */
diff --git a/merrifield/ips/anniedale/AnnOverlayPlane.cpp b/merrifield/ips/anniedale/AnnOverlayPlane.cpp
new file mode 100644
index 0000000..930f895
--- /dev/null
+++ b/merrifield/ips/anniedale/AnnOverlayPlane.cpp
@@ -0,0 +1,834 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#include <math.h>
+#include <HwcTrace.h>
+#include <Drm.h>
+#include <Hwcomposer.h>
+#include <anniedale/AnnOverlayPlane.h>
+#include <tangier/TngGrallocBuffer.h>
+
+// FIXME: remove it
+#include <OMX_IVCommon.h>
+#include <OMX_IntelVideoExt.h>
+
+namespace android {
+namespace intel {
+
+AnnOverlayPlane::AnnOverlayPlane(int index, int disp)
+    : OverlayPlaneBase(index, disp),
+      mRotationBufProvider(NULL),
+      mRotationConfig(0),
+      mZOrderConfig(0),
+      mUseOverlayRotation(true)
+{
+    CTRACE();
+
+    memset(&mContext, 0, sizeof(mContext));
+}
+
+AnnOverlayPlane::~AnnOverlayPlane()
+{
+    CTRACE();
+}
+
+void AnnOverlayPlane::setZOrderConfig(ZOrderConfig& zorderConfig,
+                                            void *nativeConfig)
+{
+    long slot = (long)nativeConfig;
+
+    CTRACE();
+
+    switch (slot) {
+    case 0:
+        mZOrderConfig = 0;
+        break;
+    case 1:
+        mZOrderConfig = (1 << 8);
+        break;
+    case 2:
+        mZOrderConfig = (2 << 8);
+        break;
+    case 3:
+        mZOrderConfig = (3 << 8);
+        break;
+    default:
+        ETRACE("Invalid overlay plane zorder %ld", slot);
+        return;
+    }
+}
+
+bool AnnOverlayPlane::reset()
+{
+    OverlayPlaneBase::reset();
+    if (mRotationBufProvider) {
+        mRotationBufProvider->reset();
+    }
+    return true;
+}
+
+bool AnnOverlayPlane::enable()
+{
+    RETURN_FALSE_IF_NOT_INIT();
+
+    // by default always use overlay rotation
+    mUseOverlayRotation = true;
+
+    if (mContext.ctx.ov_ctx.ovadd & (0x1 << 15))
+        return true;
+
+    mContext.ctx.ov_ctx.ovadd |= (0x1 << 15);
+
+    // flush
+    flush(PLANE_ENABLE);
+
+    return true;
+}
+
+bool AnnOverlayPlane::disable()
+{
+    RETURN_FALSE_IF_NOT_INIT();
+
+    if (!(mContext.ctx.ov_ctx.ovadd & (0x1 << 15)))
+        return true;
+
+    mContext.ctx.ov_ctx.ovadd &= ~(0x1 << 15);
+
+    mContext.ctx.ov_ctx.ovadd &= ~(0x300);
+
+    mContext.ctx.ov_ctx.ovadd |= mPipeConfig;
+
+    // flush
+    flush(PLANE_DISABLE);
+
+    return true;
+}
+
+void AnnOverlayPlane::postFlip()
+{
+    // when using AnnOverlayPlane through AnnDisplayPlane as proxy, postFlip is never
+    // called so mUpdateMasks is never reset.
+    // When using AnnOverlayPlane directly, postFlip is invoked and mUpdateMasks is reset
+    // post-flip.
+
+    // need to check why mUpdateMasks = 0 causes video freeze.
+
+    //DisplayPlane::postFlip();
+}
+
+
+void AnnOverlayPlane::resetBackBuffer(int buf)
+{
+    CTRACE();
+
+    if (!mBackBuffer[buf] || !mBackBuffer[buf]->buf)
+        return;
+
+    OverlayBackBufferBlk *backBuffer = mBackBuffer[buf]->buf;
+
+    memset(backBuffer, 0, sizeof(OverlayBackBufferBlk));
+
+    // reset overlay
+    backBuffer->OCLRC0 = (OVERLAY_INIT_CONTRAST << 18) |
+                         (OVERLAY_INIT_BRIGHTNESS & 0xff);
+    backBuffer->OCLRC1 = OVERLAY_INIT_SATURATION;
+    backBuffer->DCLRKV = OVERLAY_INIT_COLORKEY;
+    backBuffer->DCLRKM = OVERLAY_INIT_COLORKEYMASK;
+    backBuffer->OCONFIG = 0;
+    backBuffer->OCONFIG |= (0x1 << 27);
+    // use 3 line buffers
+    backBuffer->OCONFIG |= 0x1;
+    backBuffer->SCHRKEN &= ~(0x7 << 24);
+    backBuffer->SCHRKEN |= 0xff;
+}
+
+bool AnnOverlayPlane::bufferOffsetSetup(BufferMapper& mapper)
+{
+    CTRACE();
+
+    OverlayBackBufferBlk *backBuffer = mBackBuffer[mCurrent]->buf;
+    if (!backBuffer) {
+        ETRACE("invalid back buffer");
+        return false;
+    }
+
+    uint32_t format = mapper.getFormat();
+    uint32_t gttOffsetInBytes = (mapper.getGttOffsetInPage(0) << 12);
+    uint32_t yStride = mapper.getStride().yuv.yStride;
+    uint32_t uvStride = mapper.getStride().yuv.uvStride;
+    uint32_t w = mapper.getWidth();
+    uint32_t h = mapper.getHeight();
+    uint32_t srcX= mapper.getCrop().x;
+    uint32_t srcY= mapper.getCrop().y;
+    uint32_t ySurface, uSurface, vSurface;
+    uint32_t yTileOffsetX, yTileOffsetY;
+    uint32_t uTileOffsetX, uTileOffsetY;
+    uint32_t vTileOffsetX, vTileOffsetY;
+
+    // clear original format setting
+    backBuffer->OCMD &= ~(0xf << 10);
+    backBuffer->OCMD &= ~OVERLAY_MEMORY_LAYOUT_TILED;
+
+    backBuffer->OBUF_0Y = 0;
+    backBuffer->OBUF_0V = 0;
+    backBuffer->OBUF_0U = 0;
+    // Y/U/V plane must be 4k bytes aligned.
+    ySurface = gttOffsetInBytes;
+    if (mIsProtectedBuffer) {
+        // temporary workaround until vsync event logic is corrected.
+        // it seems that overlay buffer update and renderring can be overlapped,
+        // as such encryption bit may be cleared during HW rendering
+        ySurface |= 0x01;
+    }
+
+    switch(format) {
+    case HAL_PIXEL_FORMAT_YV12:    // YV12
+        vSurface = ySurface + yStride * h;
+        uSurface = vSurface + uvStride * (h / 2);
+        yTileOffsetX = srcX;
+        yTileOffsetY = srcY;
+        uTileOffsetX = srcX / 2;
+        uTileOffsetY = srcY / 2;
+        vTileOffsetX = uTileOffsetX;
+        vTileOffsetY = uTileOffsetY;
+        backBuffer->OCMD |= OVERLAY_FORMAT_PLANAR_YUV420;
+        break;
+    case HAL_PIXEL_FORMAT_I420:    // I420
+        uSurface = ySurface + yStride * h;
+        vSurface = uSurface + uvStride * (h / 2);
+        yTileOffsetX = srcX;
+        yTileOffsetY = srcY;
+        uTileOffsetX = srcX / 2;
+        uTileOffsetY = srcY / 2;
+        vTileOffsetX = uTileOffsetX;
+        vTileOffsetY = uTileOffsetY;
+        backBuffer->OCMD |= OVERLAY_FORMAT_PLANAR_YUV420;
+        break;
+    case HAL_PIXEL_FORMAT_NV12:    // NV12
+        uSurface = ySurface;
+        vSurface = ySurface;
+        backBuffer->OBUF_0U = yStride * h;
+        yTileOffsetX = srcX;
+        yTileOffsetY = srcY;
+        uTileOffsetX = srcX / 2;
+        uTileOffsetY = srcY / 2 + h;
+        vTileOffsetX = uTileOffsetX;
+        vTileOffsetY = uTileOffsetY;
+        backBuffer->OCMD |= OVERLAY_FORMAT_PLANAR_NV12_2;
+        break;
+    // NOTE: this is the decoded video format, align the height to 32B
+    //as it's defined by video driver
+    case OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar:    // NV12
+        uSurface = ySurface + yStride * align_to(h, 32);
+        vSurface = ySurface + yStride * align_to(h, 32);
+        yTileOffsetX = srcX;
+        yTileOffsetY = srcY;
+        uTileOffsetX = srcX;
+        uTileOffsetY = srcY / 2;
+        vTileOffsetX = uTileOffsetX;
+        vTileOffsetY = uTileOffsetY;
+        backBuffer->OCMD |= OVERLAY_FORMAT_PLANAR_NV12_2;
+        break;
+    case OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar_Tiled:  //NV12_tiled
+        uSurface = ySurface + yStride * align_to(h, 32);
+        vSurface = ySurface + yStride * align_to(h, 32);
+        yTileOffsetX = srcX;
+        yTileOffsetY = srcY;
+        uTileOffsetX = srcX;
+        uTileOffsetY = srcY / 2;
+        vTileOffsetX = uTileOffsetX;
+        vTileOffsetY = uTileOffsetY;
+        backBuffer->OCMD |= OVERLAY_FORMAT_PLANAR_NV12_2;
+        backBuffer->OCMD |= OVERLAY_MEMORY_LAYOUT_TILED;
+        break;
+    case HAL_PIXEL_FORMAT_YUY2:    // YUY2
+        uSurface = ySurface;
+        vSurface = ySurface;
+        yTileOffsetX = srcX;
+        yTileOffsetY = srcY;
+        uTileOffsetX = yTileOffsetX;
+        uTileOffsetY = yTileOffsetY;
+        vTileOffsetX = yTileOffsetX;
+        vTileOffsetY = yTileOffsetY;
+        backBuffer->OCMD |= OVERLAY_FORMAT_PACKED_YUV422;
+        backBuffer->OCMD |= OVERLAY_PACKED_ORDER_YUY2;
+        break;
+    case HAL_PIXEL_FORMAT_UYVY:    // UYVY
+        uSurface = ySurface;
+        vSurface = ySurface;
+        yTileOffsetX = srcX;
+        yTileOffsetY = srcY;
+        uTileOffsetX = yTileOffsetX;
+        uTileOffsetY = yTileOffsetY;
+        vTileOffsetX = yTileOffsetX;
+        vTileOffsetY = yTileOffsetY;
+        backBuffer->OCMD |= OVERLAY_FORMAT_PACKED_YUV422;
+        backBuffer->OCMD |= OVERLAY_PACKED_ORDER_UYVY;
+        break;
+    default:
+        ETRACE("unsupported format %d", format);
+        return false;
+    }
+
+    backBuffer->OSTART_0Y = ySurface;
+    backBuffer->OSTART_0U = uSurface;
+    backBuffer->OSTART_0V = vSurface;
+    backBuffer->OBUF_0Y += srcY * yStride + srcX;
+    backBuffer->OBUF_0V += (srcY / 2) * uvStride + srcX;
+    backBuffer->OBUF_0U += (srcY / 2) * uvStride + srcX;
+    backBuffer->OTILEOFF_0Y = yTileOffsetY << 16 | yTileOffsetX;
+    backBuffer->OTILEOFF_0U = uTileOffsetY << 16 | uTileOffsetX;
+    backBuffer->OTILEOFF_0V = vTileOffsetY << 16 | vTileOffsetX;
+
+    VTRACE("done. offset (%d, %d, %d)",
+          backBuffer->OBUF_0Y,
+          backBuffer->OBUF_0U,
+          backBuffer->OBUF_0V);
+
+    return true;
+}
+
+bool AnnOverlayPlane::scalingSetup(BufferMapper& mapper)
+{
+    int xscaleInt, xscaleFract, yscaleInt, yscaleFract;
+    int xscaleIntUV, xscaleFractUV;
+    int yscaleIntUV, yscaleFractUV;
+    // UV is half the size of Y -- YUV420
+    int uvratio = 2;
+    uint32_t newval;
+    coeffRec xcoeffY[N_HORIZ_Y_TAPS * N_PHASES];
+    coeffRec xcoeffUV[N_HORIZ_UV_TAPS * N_PHASES];
+    coeffRec ycoeffY[N_VERT_Y_TAPS * N_PHASES];
+    coeffRec ycoeffUV[N_VERT_UV_TAPS * N_PHASES];
+    int i, j, pos;
+    bool scaleChanged = false;
+    int x, y, w, h;
+    int deinterlace_factor = 1;
+    drmModeModeInfoPtr mode = &mModeInfo;
+
+    OverlayBackBufferBlk *backBuffer = mBackBuffer[mCurrent]->buf;
+    if (!backBuffer) {
+        ETRACE("invalid back buffer");
+        return false;
+    }
+
+    if (mPanelOrientation == PANEL_ORIENTATION_180) {
+        if (mode->hdisplay)
+            x = mode->hdisplay - mPosition.x - mPosition.w;
+        else
+            x = mPosition.x;
+        if (mode->vdisplay)
+            y = mode->vdisplay - mPosition.y - mPosition.h;
+        else
+            y = mPosition.y;
+    } else {
+        x = mPosition.x;
+        y = mPosition.y;
+    }
+
+    w = mPosition.w;
+    h = mPosition.h;
+
+    // check position
+    checkPosition(x, y, w, h);
+    VTRACE("final position (%d, %d, %d, %d)", x, y, w, h);
+
+    if ((w <= 0) || (h <= 0)) {
+         ETRACE("invalid dst width/height");
+         return false;
+    }
+
+    // setup dst position
+    backBuffer->DWINPOS = (y << 16) | x;
+    backBuffer->DWINSZ = (h << 16) | w;
+
+    uint32_t srcWidth = mapper.getCrop().w;
+    uint32_t srcHeight = mapper.getCrop().h;
+    uint32_t dstWidth = w;
+    uint32_t dstHeight = h;
+
+    if (mBobDeinterlace && !mTransform)
+        deinterlace_factor = 2;
+
+    VTRACE("src (%dx%d), dst (%dx%d), transform %d",
+          srcWidth, srcHeight,
+          dstWidth, dstHeight,
+          mTransform);
+
+    // switch destination width/height for scale factor calculation
+    // for 90/270 transformation
+    if (mUseOverlayRotation && ((mTransform == HWC_TRANSFORM_ROT_90) ||
+        (mTransform == HWC_TRANSFORM_ROT_270))) {
+        uint32_t tmp = srcHeight;
+        srcHeight = srcWidth;
+        srcWidth = tmp;
+    }
+
+     // Y down-scale factor as a multiple of 4096
+    if (srcWidth == dstWidth && srcHeight == dstHeight) {
+        xscaleFract = (1 << 12);
+        yscaleFract = (1 << 12) / deinterlace_factor;
+    } else {
+        xscaleFract = ((srcWidth - 1) << 12) / dstWidth;
+        yscaleFract = ((srcHeight - 1) << 12) / (dstHeight * deinterlace_factor);
+    }
+
+    // Calculate the UV scaling factor
+    xscaleFractUV = xscaleFract / uvratio;
+    yscaleFractUV = yscaleFract / uvratio;
+
+
+    // To keep the relative Y and UV ratios exact, round the Y scales
+    // to a multiple of the Y/UV ratio.
+    xscaleFract = xscaleFractUV * uvratio;
+    yscaleFract = yscaleFractUV * uvratio;
+
+    // Integer (un-multiplied) values
+    xscaleInt = xscaleFract >> 12;
+    yscaleInt = yscaleFract >> 12;
+
+    xscaleIntUV = xscaleFractUV >> 12;
+    yscaleIntUV = yscaleFractUV >> 12;
+
+    // Check scaling ratio
+    if (xscaleInt > INTEL_OVERLAY_MAX_SCALING_RATIO) {
+        ETRACE("xscaleInt > %d", INTEL_OVERLAY_MAX_SCALING_RATIO);
+        return false;
+    }
+
+    // shouldn't get here
+    if (xscaleIntUV > INTEL_OVERLAY_MAX_SCALING_RATIO) {
+        ETRACE("xscaleIntUV > %d", INTEL_OVERLAY_MAX_SCALING_RATIO);
+        return false;
+    }
+
+    newval = (xscaleInt << 15) |
+    ((xscaleFract & 0xFFF) << 3) | ((yscaleFract & 0xFFF) << 20);
+    if (newval != backBuffer->YRGBSCALE) {
+        scaleChanged = true;
+        backBuffer->YRGBSCALE = newval;
+    }
+
+    newval = (xscaleIntUV << 15) | ((xscaleFractUV & 0xFFF) << 3) |
+    ((yscaleFractUV & 0xFFF) << 20);
+    if (newval != backBuffer->UVSCALE) {
+        scaleChanged = true;
+        backBuffer->UVSCALE = newval;
+    }
+
+    newval = yscaleInt << 16 | yscaleIntUV;
+    if (newval != backBuffer->UVSCALEV) {
+        scaleChanged = true;
+        backBuffer->UVSCALEV = newval;
+    }
+
+    // Recalculate coefficients if the scaling changed
+    // Only Horizontal coefficients so far.
+    if (scaleChanged) {
+        double fHCutoffY;
+        double fHCutoffUV;
+        double fVCutoffY;
+        double fVCutoffUV;
+
+        fHCutoffY = xscaleFract / 4096.0;
+        fHCutoffUV = xscaleFractUV / 4096.0;
+        fVCutoffY = yscaleFract / 4096.0;
+        fVCutoffUV = yscaleFractUV / 4096.0;
+
+        // Limit to between 1.0 and 3.0
+        if (fHCutoffY < MIN_CUTOFF_FREQ)
+            fHCutoffY = MIN_CUTOFF_FREQ;
+        if (fHCutoffY > MAX_CUTOFF_FREQ)
+            fHCutoffY = MAX_CUTOFF_FREQ;
+        if (fHCutoffUV < MIN_CUTOFF_FREQ)
+            fHCutoffUV = MIN_CUTOFF_FREQ;
+        if (fHCutoffUV > MAX_CUTOFF_FREQ)
+            fHCutoffUV = MAX_CUTOFF_FREQ;
+
+        if (fVCutoffY < MIN_CUTOFF_FREQ)
+            fVCutoffY = MIN_CUTOFF_FREQ;
+        if (fVCutoffY > MAX_CUTOFF_FREQ)
+            fVCutoffY = MAX_CUTOFF_FREQ;
+        if (fVCutoffUV < MIN_CUTOFF_FREQ)
+            fVCutoffUV = MIN_CUTOFF_FREQ;
+        if (fVCutoffUV > MAX_CUTOFF_FREQ)
+            fVCutoffUV = MAX_CUTOFF_FREQ;
+
+        updateCoeff(N_HORIZ_Y_TAPS, fHCutoffY, true, true, xcoeffY);
+        updateCoeff(N_HORIZ_UV_TAPS, fHCutoffUV, true, false, xcoeffUV);
+        updateCoeff(N_VERT_Y_TAPS, fVCutoffY, false, true, ycoeffY);
+        updateCoeff(N_VERT_UV_TAPS, fVCutoffUV, false, false, ycoeffUV);
+
+        for (i = 0; i < N_PHASES; i++) {
+            for (j = 0; j < N_HORIZ_Y_TAPS; j++) {
+                pos = i * N_HORIZ_Y_TAPS + j;
+                backBuffer->Y_HCOEFS[pos] =
+                        (xcoeffY[pos].sign << 15 |
+                         xcoeffY[pos].exponent << 12 |
+                         xcoeffY[pos].mantissa);
+            }
+        }
+        for (i = 0; i < N_PHASES; i++) {
+            for (j = 0; j < N_HORIZ_UV_TAPS; j++) {
+                pos = i * N_HORIZ_UV_TAPS + j;
+                backBuffer->UV_HCOEFS[pos] =
+                         (xcoeffUV[pos].sign << 15 |
+                          xcoeffUV[pos].exponent << 12 |
+                          xcoeffUV[pos].mantissa);
+            }
+        }
+
+        for (i = 0; i < N_PHASES; i++) {
+            for (j = 0; j < N_VERT_Y_TAPS; j++) {
+                pos = i * N_VERT_Y_TAPS + j;
+                backBuffer->Y_VCOEFS[pos] =
+                        (ycoeffY[pos].sign << 15 |
+                         ycoeffY[pos].exponent << 12 |
+                         ycoeffY[pos].mantissa);
+            }
+        }
+        for (i = 0; i < N_PHASES; i++) {
+            for (j = 0; j < N_VERT_UV_TAPS; j++) {
+                pos = i * N_VERT_UV_TAPS + j;
+                backBuffer->UV_VCOEFS[pos] =
+                         (ycoeffUV[pos].sign << 15 |
+                          ycoeffUV[pos].exponent << 12 |
+                          ycoeffUV[pos].mantissa);
+            }
+        }
+    }
+
+    XTRACE();
+    return true;
+}
+
+void AnnOverlayPlane::setTransform(int transform)
+{
+    RETURN_VOID_IF_NOT_INIT();
+
+    if (mPanelOrientation == PANEL_ORIENTATION_180)
+       transform ^=  HWC_TRANSFORM_ROT_180;
+
+    DisplayPlane::setTransform(transform);
+
+    // setup transform config
+    switch (mTransform) {
+    case HWC_TRANSFORM_ROT_90:
+        mRotationConfig = (0x1 << 10);
+        break;
+    case HWC_TRANSFORM_ROT_180:
+        mRotationConfig = (0x2 << 10);
+        break;
+    case HWC_TRANSFORM_ROT_270:
+        mRotationConfig = (0x3 << 10);
+        break;
+    case 0:
+        mRotationConfig = 0;
+        break;
+    default:
+        ETRACE("Invalid transform %d", mTransform);
+        mRotationConfig = 0;
+        break;
+    }
+}
+
+// HSD 4645510:
+// This is a SOC limition, that when source buffer width range is
+// in (960, 1024] - one cache line length, and rotation bit is set
+// in portrait mode, video will show distortion.
+bool AnnOverlayPlane::isSettingRotBitAllowed()
+{
+    uint32_t width = mSrcCrop.w;
+
+    if ((width > 960 && width <= 1024) &&
+            (mTransform == 0 || mTransform == HAL_TRANSFORM_ROT_180))
+        return false;
+    return true;
+}
+
+bool AnnOverlayPlane::flip(void *ctx)
+{
+    uint32_t ovadd = 0;
+
+    RETURN_FALSE_IF_NOT_INIT();
+
+    if (!DisplayPlane::flip(ctx)) {
+        ETRACE("failed to flip display plane.");
+        return false;
+    }
+
+    // update back buffer address
+    ovadd = (mBackBuffer[mCurrent]->gttOffsetInPage << 12);
+
+    // enable rotation mode and setup rotation config
+    // if video is interlaced, cannot use overlay rotation
+    if (mIndex == 0 && !mBobDeinterlace) {
+        if (isSettingRotBitAllowed())
+            ovadd |= (1 << 12);
+        ovadd |= mRotationConfig;
+    }
+
+    // setup z-order config
+    ovadd |= mZOrderConfig;
+
+    // load coefficients
+    ovadd |= 0x1;
+
+    // enable overlay
+    ovadd |= (1 << 15);
+
+    mContext.type = DC_OVERLAY_PLANE;
+    mContext.ctx.ov_ctx.ovadd = ovadd;
+    mContext.ctx.ov_ctx.index = mIndex;
+    mContext.ctx.ov_ctx.pipe = mDevice;
+    mContext.ctx.ov_ctx.ovadd |= mPipeConfig;
+
+    // move to next back buffer
+    mCurrent = (mCurrent + 1) % OVERLAY_BACK_BUFFER_COUNT;
+
+    VTRACE("ovadd = %#x, index = %d, device = %d",
+          mContext.ctx.ov_ctx.ovadd,
+          mIndex,
+          mDevice);
+
+    return true;
+}
+
+void* AnnOverlayPlane::getContext() const
+{
+    CTRACE();
+    return (void *)&mContext;
+}
+
+bool AnnOverlayPlane::setDataBuffer(BufferMapper& mapper)
+{
+    if (OverlayPlaneBase::setDataBuffer(mapper) == false) {
+        return false;
+    }
+
+    signalVideoRotation(mapper);
+
+    if (mIsProtectedBuffer) {
+        // Bit 0: Decryption request, only allowed to change on a synchronous flip
+        // This request will be qualified with the separate decryption enable bit for OV
+        mBackBuffer[mCurrent]->buf->OSTART_0Y |= 0x1;
+        mBackBuffer[mCurrent]->buf->OSTART_1Y |= 0x1;
+    }
+
+    mContext.gtt_key = (unsigned long)mapper.getCpuAddress(0);
+
+    return true;
+}
+
+bool AnnOverlayPlane::initialize(uint32_t bufferCount)
+{
+    if (!OverlayPlaneBase::initialize(bufferCount)) {
+        ETRACE("failed to initialize OverlayPlaneBase");
+        return false;
+    }
+
+    // setup rotation buffer
+    mRotationBufProvider = new RotationBufferProvider(mWsbm);
+    if (!mRotationBufProvider || !mRotationBufProvider->initialize()) {
+        DEINIT_AND_RETURN_FALSE("failed to initialize RotationBufferProvider");
+    }
+    return true;
+}
+
+void AnnOverlayPlane::deinitialize()
+{
+    DEINIT_AND_DELETE_OBJ(mRotationBufProvider);
+    OverlayPlaneBase::deinitialize();
+}
+
+bool AnnOverlayPlane::rotatedBufferReady(BufferMapper& mapper, BufferMapper* &rotatedMapper)
+{
+    struct VideoPayloadBuffer *payload;
+    uint32_t format;
+    // only NV12_VED has rotated buffer
+    format = mapper.getFormat();
+    if (format != OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar &&
+        format != OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar_Tiled) {
+        ETRACE("invalid video format %#x", format);
+        return false;
+    }
+
+    payload = (struct VideoPayloadBuffer *)mapper.getCpuAddress(SUB_BUFFER1);
+    // check payload
+    if (!payload) {
+        ETRACE("no payload found");
+        return false;
+    }
+
+    if (payload->force_output_method == FORCE_OUTPUT_GPU) {
+        ETRACE("Output method is not supported!");
+        return false;
+    }
+
+    if (payload->client_transform != mTransform ||
+        mBobDeinterlace) {
+        if (!mRotationBufProvider->setupRotationBuffer(payload, mTransform)) {
+            DTRACE("failed to setup rotation buffer");
+            return false;
+        }
+    }
+
+    rotatedMapper = getTTMMapper(mapper, payload);
+    return true;
+}
+
+void AnnOverlayPlane::signalVideoRotation(BufferMapper& mapper)
+{
+    struct VideoPayloadBuffer *payload;
+    uint32_t format;
+
+    // check if it's video layer
+    format = mapper.getFormat();
+    if (format != OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar &&
+        format != OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar_Tiled) {
+        return;
+    }
+
+    payload = (struct VideoPayloadBuffer *)mapper.getCpuAddress(SUB_BUFFER1);
+    if (!payload) {
+        ETRACE("no payload found");
+        return;
+    }
+
+    /* if use overlay rotation, signal decoder to stop rotation */
+    if (mUseOverlayRotation) {
+        if (payload->client_transform) {
+            WTRACE("signal decoder to stop generate rotation buffer");
+            payload->hwc_timestamp = systemTime();
+            payload->layer_transform = 0;
+        }
+    } else {
+        /* if overlay rotation cannot be used, signal decoder to start rotation */
+        if (payload->client_transform != mTransform) {
+            WTRACE("signal decoder to generate rotation buffer with transform %d", mTransform);
+            payload->hwc_timestamp = systemTime();
+            payload->layer_transform = mTransform;
+        }
+    }
+}
+
+bool AnnOverlayPlane::useOverlayRotation(BufferMapper& mapper)
+{
+    if (mTransform == 0)
+        return true;
+
+    if (!isSettingRotBitAllowed()) {
+        mUseOverlayRotation = false;
+        mRotationConfig = 0;
+        return false;
+    }
+
+    // workaround limitation of overlay rotation by falling back to use VA rotated buffer
+    bool fallback = false;
+    float scaleX = (float)mSrcCrop.w / mPosition.w;
+    float scaleY = (float)mSrcCrop.h / mPosition.h;
+    if (mTransform == HAL_TRANSFORM_ROT_270 || mTransform == HAL_TRANSFORM_ROT_90) {
+        scaleX = (float)mSrcCrop.w / mPosition.h;
+        scaleY = (float)mSrcCrop.h / mPosition.w;
+    }
+    if (scaleX >= 3 || scaleY >= 3) {
+        if (mUseOverlayRotation) {
+            DTRACE("overlay rotation with scaling >= 3, use VA rotated buffer");
+        }
+        fallback = true;
+    } else if ((int)mSrcCrop.x & 63) {
+        if (mUseOverlayRotation) {
+            DTRACE("offset is not 64 bytes aligned, use VA rotated buffer");
+        }
+        fallback = true;
+    }
+#if 0
+    else if (mTransform != HAL_TRANSFORM_ROT_180 && scaleX != scaleY) {
+        if (mUseOverlayRotation) {
+            DTRACE("overlay rotation with uneven scaling, use VA rotated buffer");
+        }
+        fallback = true;
+    }
+#endif
+
+    // per DC spec, if video is 1080(H)x1920(V), the buffer
+    // need 1920 of 64-pixel strip if using hw rotation.
+    // fallback to video ration buffer in such case.
+    if (mSrcCrop.w == 1080 && mSrcCrop.h == 1920 && mTransform != 0) {
+        DTRACE("1080(H)x1920(V) cannot use hw rotation, use VA rotated buffer");
+        fallback = true;
+    }
+
+    if (fallback || mBobDeinterlace) {
+        mUseOverlayRotation = false;
+        mRotationConfig = 0;
+    } else {
+        mUseOverlayRotation = true;
+    }
+    return mUseOverlayRotation;
+}
+
+bool AnnOverlayPlane::scaledBufferReady(BufferMapper& mapper, BufferMapper* &scaledMapper, VideoPayloadBuffer *payload)
+{
+    mUseScaledBuffer = (payload->scaling_khandle != 0);
+
+    if (mUseScaledBuffer) {
+        mapper.setCrop(mapper.getCrop().x, mapper.getCrop().y, payload->scaling_width, payload->scaling_height);
+        scaledMapper = getTTMMapper(mapper, payload);
+        return (scaledMapper != 0);
+    }
+
+    return mUseScaledBuffer;
+}
+
+bool AnnOverlayPlane::flush(uint32_t flags)
+{
+    RETURN_FALSE_IF_NOT_INIT();
+    ATRACE("flags = %#x, type = %d, index = %d", flags, mType, mIndex);
+
+    if (!(flags & PLANE_ENABLE) && !(flags & PLANE_DISABLE)) {
+        ETRACE("invalid flush flags.");
+        return false;
+    }
+
+    struct drm_psb_register_rw_arg arg;
+    memset(&arg, 0, sizeof(struct drm_psb_register_rw_arg));
+
+    if (flags & PLANE_DISABLE)
+        arg.plane_disable_mask = 1;
+    else if (flags & PLANE_ENABLE)
+        arg.plane_enable_mask = 1;
+
+    arg.plane.type = DC_OVERLAY_PLANE;
+    arg.plane.index = mIndex;
+    arg.plane.ctx = mContext.ctx.ov_ctx.ovadd;
+    if (flags & PLANE_DISABLE) {
+        DTRACE("disabling overlay %d on device %d", mIndex, mDevice);
+    }
+
+    // issue ioctl
+    Drm *drm = Hwcomposer::getInstance().getDrm();
+    bool ret = drm->writeReadIoctl(DRM_PSB_REGISTER_RW, &arg, sizeof(arg));
+    if (ret == false) {
+        WTRACE("overlay update failed with error code %d", ret);
+        return false;
+    }
+
+    return true;
+}
+
+} // namespace intel
+} // namespace android
diff --git a/merrifield/ips/anniedale/AnnOverlayPlane.h b/merrifield/ips/anniedale/AnnOverlayPlane.h
new file mode 100644
index 0000000..3cea338
--- /dev/null
+++ b/merrifield/ips/anniedale/AnnOverlayPlane.h
@@ -0,0 +1,78 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef ANN_OVERLAY_PLANE_H
+#define ANN_OVERLAY_PLANE_H
+
+#include <utils/KeyedVector.h>
+#include <hal_public.h>
+#include <DisplayPlane.h>
+#include <BufferMapper.h>
+#include <common/Wsbm.h>
+#include <common/OverlayPlaneBase.h>
+#include <common/RotationBufferProvider.h>
+
+namespace android {
+namespace intel {
+
+class AnnOverlayPlane : public OverlayPlaneBase {
+public:
+    AnnOverlayPlane(int index, int disp);
+    virtual ~AnnOverlayPlane();
+
+    virtual void setTransform(int transform);
+    virtual void setZOrderConfig(ZOrderConfig& config, void *nativeConfig);
+
+    // plane operations
+    virtual bool flip(void *ctx);
+    virtual bool reset();
+    virtual bool enable();
+    virtual bool disable();
+    virtual void postFlip();
+    virtual void* getContext() const;
+    virtual bool initialize(uint32_t bufferCount);
+    virtual void deinitialize();
+    virtual bool rotatedBufferReady(BufferMapper& mapper, BufferMapper* &rotatedMapper);
+    virtual bool useOverlayRotation(BufferMapper& mapper);
+    virtual bool scaledBufferReady(BufferMapper& mapper, BufferMapper* &scaledMapper, VideoPayloadBuffer *payload);
+
+private:
+    void signalVideoRotation(BufferMapper& mapper);
+    bool isSettingRotBitAllowed();
+
+protected:
+    virtual bool setDataBuffer(BufferMapper& mapper);
+    virtual bool flush(uint32_t flags);
+    virtual bool bufferOffsetSetup(BufferMapper& mapper);
+    virtual bool scalingSetup(BufferMapper& mapper);
+
+    virtual void resetBackBuffer(int buf);
+
+    RotationBufferProvider *mRotationBufProvider;
+
+    // rotation config
+    uint32_t mRotationConfig;
+    // z order config
+    uint32_t mZOrderConfig;
+    bool mUseOverlayRotation;
+    // hardware context
+    struct intel_dc_plane_ctx mContext;
+};
+
+} // namespace intel
+} // namespace android
+
+#endif /* ANN_OVERLAY_PLANE_H */
+
diff --git a/merrifield/ips/anniedale/AnnPlaneManager.cpp b/merrifield/ips/anniedale/AnnPlaneManager.cpp
new file mode 100644
index 0000000..b20f851
--- /dev/null
+++ b/merrifield/ips/anniedale/AnnPlaneManager.cpp
@@ -0,0 +1,461 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#include <HwcTrace.h>
+#include <utils/String8.h>
+#include <anniedale/AnnPlaneManager.h>
+#include <anniedale/AnnRGBPlane.h>
+#include <anniedale/AnnOverlayPlane.h>
+#include <anniedale/AnnCursorPlane.h>
+#include <PlaneCapabilities.h>
+
+namespace android {
+namespace intel {
+
+
+struct PlaneDescription {
+    char nickname;
+    int type;
+    int index;
+};
+
+
+static PlaneDescription PLANE_DESC[] =
+{
+    // nickname must be continous and start with 'A',
+    // it is used to fast locate plane index and type
+    {'A', DisplayPlane::PLANE_PRIMARY, 0},
+    {'B', DisplayPlane::PLANE_PRIMARY, 1},
+    {'C', DisplayPlane::PLANE_PRIMARY, 2},
+    {'D', DisplayPlane::PLANE_SPRITE,  0},
+    {'E', DisplayPlane::PLANE_SPRITE,  1},
+    {'F', DisplayPlane::PLANE_SPRITE,  2},
+    {'G', DisplayPlane::PLANE_OVERLAY, 0},  // nickname for Overlay A
+    {'H', DisplayPlane::PLANE_OVERLAY, 1},   // nickname for Overlay C
+    {'I', DisplayPlane::PLANE_CURSOR,  0},  // nickname for cursor A
+    {'J', DisplayPlane::PLANE_CURSOR,  1},  // nickname for cursor B
+    {'K', DisplayPlane::PLANE_CURSOR,  2}   // nickname for cursor C
+};
+
+
+struct ZOrderDescription {
+    int index;  // based on overlay position
+    const char *zorder;
+};
+
+// If overlay is in the bottom of Z order, two legitimate combinations are Oa, D, E, F
+// and Oc, D, E, F. However, plane A has to be part of the blending chain as it can't
+//  be disabled [HW bug]. The only legitimate combinations including overlay and plane A is:
+// A, Oa, E, F
+// A, Oc, E, F
+// Cursor plane can be placed on top of any plane below and is intentionally ignored
+// in the zorder table.
+
+// video mode panel doesn't need the primay plane A always on hack
+static ZOrderDescription PIPE_A_ZORDER_DESC_VID[] =
+{
+    {0, "ADEF"},  // no overlay
+    {1, "GDEF"},  // overlay A at bottom (1 << 0)
+    {1, "HDEF"},  // overlay C at bottom (1 << 0)
+    {2, "AGEF"},  // overlay A at next to bottom (1 << 1)
+    {2, "AHEF"},  // overlay C at next to bottom (1 << 1)
+    {3, "GHEF"},  // overlay A, C at bottom
+    {4, "ADGF"},  // overlay A at next to top (1 << 2)
+    {4, "ADHF"},  // overlay C at next to top (1 << 2)
+    {6, "AGHF"},  // overlay A, C in between
+    {8, "ADEG"},  // overlay A at top (1 << 3)
+    {8, "ADEH"},  // overlay C at top (1 <<3)
+    {12, "ADGH"}  // overlay A, C at top
+};
+
+static ZOrderDescription PIPE_A_ZORDER_DESC_CMD[] =
+{
+    {0, "ADEF"},  // no overlay
+    {1, "GEF"},  // overlay A at bottom (1 << 0)
+    {1, "HEF"},  // overlay C at bottom (1 << 0)
+    {2, "AGEF"},  // overlay A at next to bottom (1 << 1)
+    {2, "AHEF"},  // overlay C at next to bottom (1 << 1)
+    {3, "GHF"},   // overlay A, C at bottom
+    {4, "ADGF"},  // overlay A at next to top (1 << 2)
+    {4, "ADHF"},  // overlay C at next to top (1 << 2)
+    {6, "AGHF"},  // overlay A, C in between
+    {8, "ADEG"},  // overlay A at top (1 << 3)
+    {8, "ADEH"},  // overlay C at top (1 <<3)
+    {12, "ADGH"}  // overlay A, C at top
+};
+
+// use overlay C over overlay A if possible on pipe B
+static ZOrderDescription PIPE_B_ZORDER_DESC[] =
+{
+    {0, "BD"},    // no overlay
+    {1, "HBD"},   // overlay C at bottom (1 << 0)
+//    {1, "GBD"},   // overlay A at bottom (1 << 0), overlay A don`t switch to pipeB and only overlay C on pipeB
+    {2, "BHD"},   // overlay C at middle (1 << 1)
+//   {2, "BGD"},   // overlay A at middle (1 << 1), overlay A don`t switch to pipeB and only overaly C on pipeB
+    {3, "GHBD"},  // overlay A and C at bottom ( 1 << 0 + 1 << 1)
+    {4, "BDH"},   // overlay C at top (1 << 2)
+    {4, "BDG"},   // overlay A at top (1 << 2)
+    {6, "BGHD"},  // overlay A/C at middle  1 << 1 + 1 << 2)
+    {12, "BDGH"}  // overlay A/C at top (1 << 2 + 1 << 3)
+};
+
+static ZOrderDescription *PIPE_A_ZORDER_TBL;
+static int PIPE_A_ZORDER_COMBINATIONS;
+static ZOrderDescription *PIPE_B_ZORDER_TBL;
+static int PIPE_B_ZORDER_COMBINATIONS;
+static bool OVERLAY_HW_WORKAROUND;
+
+AnnPlaneManager::AnnPlaneManager()
+    : DisplayPlaneManager()
+{
+}
+
+AnnPlaneManager::~AnnPlaneManager()
+{
+}
+
+bool AnnPlaneManager::initialize()
+{
+    mSpritePlaneCount = 3;  // Sprite D, E, F
+    mOverlayPlaneCount = 2; // Overlay A, C
+    mPrimaryPlaneCount = 3; // Primary A, B, C
+    mCursorPlaneCount = 3;
+
+    uint32_t videoMode = 0;
+    Drm *drm = Hwcomposer::getInstance().getDrm();
+    drm->readIoctl(DRM_PSB_PANEL_QUERY, &videoMode, sizeof(uint32_t));
+    if (videoMode == 1) {
+        DTRACE("video mode panel, no primay A always on hack");
+        PIPE_A_ZORDER_TBL = PIPE_A_ZORDER_DESC_VID;
+        PIPE_A_ZORDER_COMBINATIONS =
+            sizeof(PIPE_A_ZORDER_DESC_VID)/sizeof(ZOrderDescription);
+    } else {
+        DTRACE("command mode panel, need primay A always on hack");
+        PIPE_A_ZORDER_TBL = PIPE_A_ZORDER_DESC_CMD;
+        PIPE_A_ZORDER_COMBINATIONS =
+            sizeof(PIPE_A_ZORDER_DESC_CMD)/sizeof(ZOrderDescription);
+	OVERLAY_HW_WORKAROUND = true;
+    }
+
+    PIPE_B_ZORDER_TBL = PIPE_B_ZORDER_DESC;
+    PIPE_B_ZORDER_COMBINATIONS =
+        sizeof(PIPE_B_ZORDER_DESC)/sizeof(ZOrderDescription);
+
+    return DisplayPlaneManager::initialize();
+}
+
+void AnnPlaneManager::deinitialize()
+{
+    DisplayPlaneManager::deinitialize();
+}
+
+DisplayPlane* AnnPlaneManager::allocPlane(int index, int type)
+{
+    DisplayPlane *plane = NULL;
+
+    switch (type) {
+    case DisplayPlane::PLANE_PRIMARY:
+        plane = new AnnRGBPlane(index, DisplayPlane::PLANE_PRIMARY, index/*disp*/);
+        break;
+    case DisplayPlane::PLANE_SPRITE:
+        plane = new AnnRGBPlane(index, DisplayPlane::PLANE_SPRITE, 0/*disp*/);
+        break;
+    case DisplayPlane::PLANE_OVERLAY:
+        plane = new AnnOverlayPlane(index, 0/*disp*/);
+        break;
+    case DisplayPlane::PLANE_CURSOR:
+        plane = new AnnCursorPlane(index, index /*disp */);
+        break;
+    default:
+        ETRACE("unsupported type %d", type);
+        break;
+    }
+
+    if (plane && !plane->initialize(DisplayPlane::MIN_DATA_BUFFER_COUNT)) {
+        ETRACE("failed to initialize plane.");
+        DEINIT_AND_DELETE_OBJ(plane);
+    }
+
+    return plane;
+}
+
+bool AnnPlaneManager::isValidZOrder(int dsp, ZOrderConfig& config)
+{
+    int size = (int)config.size();
+    bool hasCursor = false;
+
+    for (int i = 0; i < size; i++) {
+        if (config[i]->planeType == DisplayPlane::PLANE_CURSOR) {
+            hasCursor = true;
+            break;
+        }
+    }
+
+    if (size <= 0 ||
+        (hasCursor && size > 5) ||
+        (!hasCursor && size > 4)) {
+        VTRACE("invalid z order config size %d", size);
+        return false;
+    }
+
+    if (dsp == IDisplayDevice::DEVICE_PRIMARY) {
+        int firstOverlay = -1;
+        for (int i = 0; i < size; i++) {
+            if (config[i]->planeType == DisplayPlane::PLANE_OVERLAY) {
+                firstOverlay = i;
+                break;
+            }
+        }
+
+        int sprites = 0;
+        for (int i = 0; i < size; i++) {
+            if (config[i]->planeType != DisplayPlane::PLANE_OVERLAY &&
+                config[i]->planeType != DisplayPlane::PLANE_CURSOR) {
+                sprites++;
+            }
+        }
+
+        if (firstOverlay < 0 && sprites > 4) {
+            VTRACE("not capable to support more than 4 sprite layers");
+            return false;
+        }
+
+        if (OVERLAY_HW_WORKAROUND) {
+            if (firstOverlay == 0 && size > 2) {
+                VTRACE("can not support 3 sprite layers on top of overlay");
+                return false;
+            }
+        }
+    } else if (dsp == IDisplayDevice::DEVICE_EXTERNAL) {
+        int sprites = 0;
+        for (int i = 0; i < size; i++) {
+            if (config[i]->planeType != DisplayPlane::PLANE_OVERLAY &&
+                config[i]->planeType != DisplayPlane::PLANE_CURSOR) {
+                sprites++;
+            }
+        }
+        if (sprites > 2) {
+            ETRACE("number of sprite: %d, maximum 1 sprite and 1 primary supported on pipe 1", sprites);
+            return false;
+        }
+    } else {
+        ETRACE("invalid display device %d", dsp);
+        return false;
+    }
+    return true;
+}
+
+bool AnnPlaneManager::assignPlanes(int dsp, ZOrderConfig& config)
+{
+    if (dsp < 0 || dsp > IDisplayDevice::DEVICE_EXTERNAL) {
+        ETRACE("invalid display device %d", dsp);
+        return false;
+    }
+
+    int size = (int)config.size();
+
+    // calculate index based on overlay Z order position
+    int index = 0;
+    for (int i = 0; i < size; i++) {
+        if (config[i]->planeType == DisplayPlane::PLANE_OVERLAY) {
+            index += (1 << i);
+        }
+    }
+
+    int combinations;
+    ZOrderDescription *table;
+    if (dsp == IDisplayDevice::DEVICE_PRIMARY) {
+        combinations = PIPE_A_ZORDER_COMBINATIONS;
+        table = PIPE_A_ZORDER_TBL;
+    } else {
+        combinations = PIPE_B_ZORDER_COMBINATIONS;
+        table = PIPE_B_ZORDER_TBL;
+    }
+
+    for (int i = 0; i < combinations; i++) {
+        ZOrderDescription *zorderDesc = table + i;
+
+        if (zorderDesc->index != index)
+            continue;
+
+        if (assignPlanes(dsp, config, zorderDesc->zorder)) {
+            VTRACE("zorder assigned %s", zorderDesc->zorder);
+            return true;
+        }
+    }
+    return false;
+}
+
+bool AnnPlaneManager::assignPlanes(int dsp, ZOrderConfig& config, const char *zorder)
+{
+    // zorder string does not include cursor plane, therefore cursor layer needs to be handled
+    // in a special way. Cursor layer must be on top of zorder and no more than one cursor layer.
+
+    int size = (int)config.size();
+    if (zorder == NULL || size == 0) {
+        //DTRACE("invalid zorder or ZOrder config.");
+        return false;
+    }
+
+    int zorderLen = (int)strlen(zorder);
+
+    // test if plane is avalable
+    for (int i = 0; i < size; i++) {
+        if (config[i]->planeType == DisplayPlane::PLANE_CURSOR) {
+            if (i != size - 1) {
+                ETRACE("invalid zorder of cursor layer");
+                return false;
+            }
+            PlaneDescription& desc = PLANE_DESC['I' - 'A' + dsp];
+            if (!isFreePlane(desc.type, desc.index)) {
+                ETRACE("cursor plane is not available");
+                return false;
+            }
+            continue;
+        }
+        if (i >= zorderLen) {
+            DTRACE("index of ZOrderConfig is out of bound");
+            return false;
+        }
+
+        char id = *(zorder + i);
+        PlaneDescription& desc = PLANE_DESC[id - 'A'];
+        if (!isFreePlane(desc.type, desc.index)) {
+            DTRACE("plane type %d index %d is not available", desc.type, desc.index);
+            return false;
+        }
+
+#if 0
+        // plane type check
+        if (config[i]->planeType == DisplayPlane::PLANE_OVERLAY &&
+            desc.type != DisplayPlane::PLANE_OVERLAY) {
+            ETRACE("invalid plane type %d, expected %d", desc.type, config[i]->planeType);
+            return false;
+        }
+
+        if (config[i]->planeType != DisplayPlane::PLANE_OVERLAY) {
+            if (config[i]->planeType != DisplayPlane::PLANE_PRIMARY &&
+                config[i]->planeType != DisplayPlane::PLANE_SPRITE) {
+                ETRACE("invalid plane type %d,", config[i]->planeType);
+                return false;
+            }
+            if (desc.type != DisplayPlane::PLANE_PRIMARY &&
+                desc.type != DisplayPlane::PLANE_SPRITE) {
+                ETRACE("invalid plane type %d, expected %d", desc.type, config[i]->planeType);
+                return false;
+            }
+        }
+#endif
+
+        if  (desc.type == DisplayPlane::PLANE_OVERLAY && desc.index == 1 &&
+             config[i]->hwcLayer->getTransform() != 0) {
+            DTRACE("overlay C does not support transform");
+            return false;
+        }
+    }
+
+    bool primaryPlaneActive = false;
+    // allocate planes
+    for (int i = 0; i < size; i++) {
+        if (config[i]->planeType == DisplayPlane::PLANE_CURSOR) {
+            PlaneDescription& desc = PLANE_DESC['I' - 'A' + dsp];
+            ZOrderLayer *zLayer = config.itemAt(i);
+            zLayer->plane = getPlane(desc.type, desc.index);
+            if (zLayer->plane == NULL) {
+                ETRACE("failed to get cursor plane, should never happen!");
+            }
+            continue;
+        }
+
+        char id = *(zorder + i);
+        PlaneDescription& desc = PLANE_DESC[id - 'A'];
+        ZOrderLayer *zLayer = config.itemAt(i);
+        zLayer->plane = getPlane(desc.type, desc.index);
+        if (zLayer->plane == NULL) {
+            ETRACE("failed to get plane, should never happen!");
+        }
+        // override type
+        zLayer->planeType = desc.type;
+        if (desc.type == DisplayPlane::PLANE_PRIMARY) {
+            primaryPlaneActive = true;
+        }
+    }
+
+    // setup Z order
+    int slot = 0;
+    for (int i = 0; i < size; i++) {
+        slot = i;
+
+        if (OVERLAY_HW_WORKAROUND) {
+            if (!primaryPlaneActive &&
+                config[i]->planeType == DisplayPlane::PLANE_OVERLAY) {
+                slot += 1;
+            }
+        }
+
+        config[i]->plane->setZOrderConfig(config, (void *)(unsigned long)slot);
+        config[i]->plane->enable();
+    }
+
+#if 0
+    DTRACE("config size %d, zorder %s", size, zorder);
+    for (int i = 0; i < size; i++) {
+        const ZOrderLayer *l = config.itemAt(i);
+        ITRACE("%d: plane type %d, index %d, zorder %d",
+            i, l->planeType, l->plane->getIndex(), l->zorder);
+    }
+#endif
+
+    return true;
+}
+
+void* AnnPlaneManager::getZOrderConfig() const
+{
+    return NULL;
+}
+
+int AnnPlaneManager::getFreePlanes(int dsp, int type)
+{
+    RETURN_NULL_IF_NOT_INIT();
+
+    if (type != DisplayPlane::PLANE_SPRITE) {
+        return DisplayPlaneManager::getFreePlanes(dsp, type);
+    }
+
+    if (dsp < 0 || dsp > IDisplayDevice::DEVICE_EXTERNAL) {
+        ETRACE("invalid display device %d", dsp);
+        return 0;
+    }
+
+    uint32_t freePlanes = mFreePlanes[type] | mReclaimedPlanes[type];
+    int start = 0;
+    int stop = mSpritePlaneCount;
+    if (dsp == IDisplayDevice::DEVICE_EXTERNAL) {
+        // only Sprite D (index 0) can be assigned to pipe 1
+        // Sprites E/F (index 1, 2) are fixed on pipe 0
+        stop = 1;
+    }
+    int count = 0;
+    for (int i = start; i < stop; i++) {
+        if ((1 << i) & freePlanes) {
+            count++;
+        }
+    }
+    return count;
+}
+
+} // namespace intel
+} // namespace android
+
diff --git a/merrifield/ips/anniedale/AnnPlaneManager.h b/merrifield/ips/anniedale/AnnPlaneManager.h
new file mode 100644
index 0000000..5a7971e
--- /dev/null
+++ b/merrifield/ips/anniedale/AnnPlaneManager.h
@@ -0,0 +1,48 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef ANN_PLANE_MANAGER_H
+#define ANN_PLANE_MANAGER_H
+
+#include <DisplayPlaneManager.h>
+#include <linux/psb_drm.h>
+
+namespace android {
+namespace intel {
+
+class AnnPlaneManager : public DisplayPlaneManager {
+public:
+    AnnPlaneManager();
+    virtual ~AnnPlaneManager();
+
+public:
+    virtual bool initialize();
+    virtual void deinitialize();
+    virtual bool isValidZOrder(int dsp, ZOrderConfig& config);
+    virtual bool assignPlanes(int dsp, ZOrderConfig& config);
+    virtual int getFreePlanes(int dsp, int type);
+    // TODO: remove this API
+    virtual void* getZOrderConfig() const;
+
+protected:
+    DisplayPlane* allocPlane(int index, int type);
+    bool assignPlanes(int dsp, ZOrderConfig& config, const char *zorder);
+};
+
+} // namespace intel
+} // namespace android
+
+
+#endif /* ANN_PLANE_MANAGER_H */
diff --git a/merrifield/ips/anniedale/AnnRGBPlane.cpp b/merrifield/ips/anniedale/AnnRGBPlane.cpp
new file mode 100644
index 0000000..dfc4b8c
--- /dev/null
+++ b/merrifield/ips/anniedale/AnnRGBPlane.cpp
@@ -0,0 +1,335 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#include <HwcTrace.h>
+#include <Hwcomposer.h>
+#include <BufferManager.h>
+#include <anniedale/AnnRGBPlane.h>
+#include <tangier/TngGrallocBuffer.h>
+#include <common/PixelFormat.h>
+
+namespace android {
+namespace intel {
+
+AnnRGBPlane::AnnRGBPlane(int index, int type, int disp)
+    : DisplayPlane(index, type, disp)
+{
+    CTRACE();
+    memset(&mContext, 0, sizeof(mContext));
+}
+
+AnnRGBPlane::~AnnRGBPlane()
+{
+    CTRACE();
+}
+
+bool AnnRGBPlane::enable()
+{
+    return enablePlane(true);
+}
+
+bool AnnRGBPlane::disable()
+{
+    return enablePlane(false);
+}
+
+void* AnnRGBPlane::getContext() const
+{
+    CTRACE();
+    return (void *)&mContext;
+}
+
+void AnnRGBPlane::setZOrderConfig(ZOrderConfig& config, void *nativeConfig)
+{
+    CTRACE();
+}
+
+bool AnnRGBPlane::setDataBuffer(buffer_handle_t handle)
+{
+    if (!handle) {
+        setFramebufferTarget(handle);
+        return true;
+    }
+
+    TngGrallocBuffer tmpBuf(handle);
+    uint32_t usage;
+    bool ret;
+
+    ATRACE("handle = %#x", handle);
+
+    usage = tmpBuf.getUsage();
+    if (GRALLOC_USAGE_HW_FB & usage) {
+        setFramebufferTarget(handle);
+        return true;
+    }
+
+    // use primary as a sprite
+    ret = DisplayPlane::setDataBuffer(handle);
+    if (ret == false) {
+        ETRACE("failed to set data buffer");
+        return ret;
+    }
+
+    return true;
+}
+
+bool AnnRGBPlane::setDataBuffer(BufferMapper& mapper)
+{
+    int bpp;
+    int srcX, srcY, srcW, srcH;
+    int dstX, dstY, dstW, dstH;
+    uint32_t spriteFormat;
+    uint32_t stride;
+    uint32_t linoff;
+    uint32_t planeAlpha;
+    drmModeModeInfoPtr mode = &mModeInfo;
+
+    CTRACE();
+
+    // setup plane position
+    dstX = mPosition.x;
+    dstY = mPosition.y;
+    dstW = mPosition.w;
+    dstH = mPosition.h;
+
+    checkPosition(dstX, dstY, dstW, dstH);
+
+    // setup plane format
+    if (!PixelFormat::convertFormat(mapper.getFormat(), spriteFormat, bpp)) {
+        ETRACE("unsupported format %#x", mapper.getFormat());
+        return false;
+    }
+
+    // setup stride and source buffer crop
+    srcX = mapper.getCrop().x;
+    srcY = mapper.getCrop().y;
+    srcW = mapper.getWidth();
+    srcH = mapper.getHeight();
+    stride = mapper.getStride().rgb.stride;
+
+    if (mPanelOrientation == PANEL_ORIENTATION_180)
+        linoff = srcY * stride + srcX * bpp + (mapper.getCrop().h  - 1) * stride + (mapper.getCrop().w - 1) * bpp;
+    else
+        linoff = srcY * stride + srcX * bpp;
+
+    // unlikely happen, but still we need make sure linoff is valid
+    if (linoff > (stride * mapper.getHeight())) {
+        ETRACE("invalid source crop");
+        return false;
+    }
+
+    // update context
+    if (mType == PLANE_SPRITE)
+        mContext.type = DC_SPRITE_PLANE;
+    else
+        mContext.type = DC_PRIMARY_PLANE;
+
+    // setup plane alpha
+    if (0 < mPlaneAlpha && mPlaneAlpha < 0xff) {
+       planeAlpha = mPlaneAlpha | 0x80000000;
+    } else {
+       // disable plane alpha to offload HW
+       planeAlpha = 0xff;
+    }
+
+    mContext.ctx.sp_ctx.index = mIndex;
+    mContext.ctx.sp_ctx.pipe = mDevice;
+    mContext.ctx.sp_ctx.cntr = spriteFormat | 0x80000000;
+    mContext.ctx.sp_ctx.linoff = linoff;
+    mContext.ctx.sp_ctx.stride = stride;
+
+    // turn off premultipled alpha blending for HWC_BLENDING_COVERAGE
+    if (mBlending == HWC_BLENDING_COVERAGE) {
+        mContext.ctx.sp_ctx.cntr |= (0x1 << 23);
+    }
+
+    if (mPanelOrientation == PANEL_ORIENTATION_180)
+        mContext.ctx.sp_ctx.cntr |= (0x1 << 15);
+
+    if (mapper.isCompression()) {
+        mContext.ctx.sp_ctx.stride = align_to(srcW, 32) * 4;
+        mContext.ctx.sp_ctx.linoff = (align_to(srcW, 32) * srcH / 64) - 1;
+        mContext.ctx.sp_ctx.tileoff = (srcY & 0xfff) << 16 | (srcX & 0xfff);
+        mContext.ctx.sp_ctx.cntr |= (0x1 << 11);
+    }
+
+    mContext.ctx.sp_ctx.surf = mapper.getGttOffsetInPage(0) << 12;
+    mContext.gtt_key = (uint64_t)mapper.getCpuAddress(0);
+
+    if (mPanelOrientation == PANEL_ORIENTATION_180) {
+        if (mode->vdisplay && mode->hdisplay)
+            mContext.ctx.sp_ctx.pos = ((mode->vdisplay - dstY - dstH) & 0xfff) << 16 | ((mode->hdisplay - dstX - dstW) & 0xfff);
+        else
+            mContext.ctx.sp_ctx.pos = (dstY & 0xfff) << 16 | (dstX & 0xfff);
+    } else {
+        mContext.ctx.sp_ctx.pos = (dstY & 0xfff) << 16 | (dstX & 0xfff);
+    }
+
+    mContext.ctx.sp_ctx.size =
+        ((dstH - 1) & 0xfff) << 16 | ((dstW - 1) & 0xfff);
+    mContext.ctx.sp_ctx.contalpa = planeAlpha;
+    mContext.ctx.sp_ctx.update_mask = SPRITE_UPDATE_ALL;
+
+    VTRACE("type = %d, index = %d, cntr = %#x, linoff = %#x, stride = %#x,"
+          "surf = %#x, pos = %#x, size = %#x, contalpa = %#x", mType, mIndex,
+          mContext.ctx.sp_ctx.cntr,
+          mContext.ctx.sp_ctx.linoff,
+          mContext.ctx.sp_ctx.stride,
+          mContext.ctx.sp_ctx.surf,
+          mContext.ctx.sp_ctx.pos,
+          mContext.ctx.sp_ctx.size,
+          mContext.ctx.sp_ctx.contalpa);
+    return true;
+}
+
+bool AnnRGBPlane::enablePlane(bool enabled)
+{
+    RETURN_FALSE_IF_NOT_INIT();
+
+    struct drm_psb_register_rw_arg arg;
+    memset(&arg, 0, sizeof(struct drm_psb_register_rw_arg));
+    if (enabled) {
+        arg.plane_enable_mask = 1;
+    } else {
+        arg.plane_disable_mask = 1;
+    }
+
+    if (mType == PLANE_SPRITE)
+        arg.plane.type = DC_SPRITE_PLANE;
+    else
+        arg.plane.type = DC_PRIMARY_PLANE;
+
+    arg.plane.index = mIndex;
+    arg.plane.ctx = 0;
+
+    // issue ioctl
+    Drm *drm = Hwcomposer::getInstance().getDrm();
+    bool ret = drm->writeReadIoctl(DRM_PSB_REGISTER_RW, &arg, sizeof(arg));
+    if (ret == false) {
+        WTRACE("plane enabling (%d) failed with error code %d", enabled, ret);
+        return false;
+    }
+
+    return true;
+}
+
+bool AnnRGBPlane::isDisabled()
+{
+    RETURN_FALSE_IF_NOT_INIT();
+
+    struct drm_psb_register_rw_arg arg;
+    memset(&arg, 0, sizeof(struct drm_psb_register_rw_arg));
+
+    if (mType == PLANE_SPRITE)
+        arg.plane.type = DC_SPRITE_PLANE;
+    else
+        arg.plane.type = DC_PRIMARY_PLANE;
+
+    arg.get_plane_state_mask = 1;
+    arg.plane.index = mIndex;
+    arg.plane.ctx = 0;
+
+    // issue ioctl
+    Drm *drm = Hwcomposer::getInstance().getDrm();
+    bool ret = drm->writeReadIoctl(DRM_PSB_REGISTER_RW, &arg, sizeof(arg));
+    if (ret == false) {
+        WTRACE("plane state query failed with error code %d", ret);
+        return false;
+    }
+
+    return arg.plane.ctx == PSB_DC_PLANE_DISABLED;
+}
+
+void AnnRGBPlane::postFlip()
+{
+    // prevent mUpdateMasks from being reset
+    // skipping flip may cause flicking
+}
+
+void AnnRGBPlane::setFramebufferTarget(buffer_handle_t handle)
+{
+    uint32_t stride;
+    uint32_t planeAlpha;
+
+    CTRACE();
+
+    // do not need to update the buffer handle
+    if (mCurrentDataBuffer != handle)
+        mUpdateMasks |= PLANE_BUFFER_CHANGED;
+    else
+        mUpdateMasks &= ~PLANE_BUFFER_CHANGED;
+
+    // if no update then do Not need set data buffer
+    if (!mUpdateMasks)
+        return;
+
+    // don't need to map data buffer for primary plane
+    if (mType == PLANE_SPRITE)
+        mContext.type = DC_SPRITE_PLANE;
+    else
+        mContext.type = DC_PRIMARY_PLANE;
+
+    stride = align_to((4 * align_to(mPosition.w, 32)), 64);
+
+    if (0 < mPlaneAlpha && mPlaneAlpha < 0xff) {
+       planeAlpha = mPlaneAlpha | 0x80000000;
+    } else {
+       // disable plane alpha to offload HW
+       planeAlpha = 0xff;
+    }
+
+    // FIXME: use sprite context for sprite plane
+    mContext.ctx.prim_ctx.update_mask = SPRITE_UPDATE_ALL;
+    mContext.ctx.prim_ctx.index = mIndex;
+    mContext.ctx.prim_ctx.pipe = mDevice;
+
+    if (mPanelOrientation == PANEL_ORIENTATION_180)
+        mContext.ctx.prim_ctx.linoff = (mPosition.h  - 1) * stride + (mPosition.w - 1) * 4;
+    else
+        mContext.ctx.prim_ctx.linoff = 0;
+
+    mContext.ctx.prim_ctx.stride = stride;
+    mContext.ctx.prim_ctx.tileoff = 0;
+    mContext.ctx.prim_ctx.pos = 0;
+    mContext.ctx.prim_ctx.size =
+        ((mPosition.h - 1) & 0xfff) << 16 | ((mPosition.w - 1) & 0xfff);
+    mContext.ctx.prim_ctx.surf = 0;
+    mContext.ctx.prim_ctx.contalpa = planeAlpha;
+    mContext.ctx.prim_ctx.cntr = PixelFormat::PLANE_PIXEL_FORMAT_BGRA8888;
+    mContext.ctx.prim_ctx.cntr |= 0x80000000;
+
+    // turn off premultipled alpha blending for HWC_BLENDING_COVERAGE
+    if (mBlending == HWC_BLENDING_COVERAGE) {
+        mContext.ctx.prim_ctx.cntr |= (0x1 << 23);
+    }
+
+    if (mPanelOrientation == PANEL_ORIENTATION_180)
+        mContext.ctx.prim_ctx.cntr |= (0x1 << 15);
+
+    VTRACE("type = %d, index = %d, cntr = %#x, linoff = %#x, stride = %#x,"
+          "surf = %#x, pos = %#x, size = %#x, contalpa = %#x", mType, mIndex,
+          mContext.ctx.prim_ctx.cntr,
+          mContext.ctx.prim_ctx.linoff,
+          mContext.ctx.prim_ctx.stride,
+          mContext.ctx.prim_ctx.surf,
+          mContext.ctx.prim_ctx.pos,
+          mContext.ctx.prim_ctx.size,
+          mContext.ctx.sp_ctx.contalpa);
+
+    mCurrentDataBuffer = handle;
+}
+
+} // namespace intel
+} // namespace android
diff --git a/merrifield/ips/anniedale/AnnRGBPlane.h b/merrifield/ips/anniedale/AnnRGBPlane.h
new file mode 100644
index 0000000..d1a9e60
--- /dev/null
+++ b/merrifield/ips/anniedale/AnnRGBPlane.h
@@ -0,0 +1,57 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef ANN_RGB_PLANE_H
+#define ANN_RGB_PLANE_H
+
+#include <utils/KeyedVector.h>
+#include <hal_public.h>
+#include <Hwcomposer.h>
+#include <BufferCache.h>
+#include <DisplayPlane.h>
+
+#include <linux/psb_drm.h>
+
+namespace android {
+namespace intel {
+
+class AnnRGBPlane : public DisplayPlane {
+public:
+    AnnRGBPlane(int index, int type, int disp);
+    virtual ~AnnRGBPlane();
+public:
+    // hardware operations
+    bool enable();
+    bool disable();
+    bool isDisabled();
+    void postFlip();
+
+    void* getContext() const;
+    void setZOrderConfig(ZOrderConfig& config, void *nativeConfig);
+
+    bool setDataBuffer(buffer_handle_t handle);
+protected:
+    bool setDataBuffer(BufferMapper& mapper);
+    bool enablePlane(bool enabled);
+private:
+    void setFramebufferTarget(buffer_handle_t handle);
+protected:
+    struct intel_dc_plane_ctx mContext;
+};
+
+} // namespace intel
+} // namespace android
+
+#endif /* ANN_RGB_PLANE_H */
diff --git a/merrifield/ips/anniedale/PlaneCapabilities.cpp b/merrifield/ips/anniedale/PlaneCapabilities.cpp
new file mode 100644
index 0000000..853511b
--- /dev/null
+++ b/merrifield/ips/anniedale/PlaneCapabilities.cpp
@@ -0,0 +1,280 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#include <HwcTrace.h>
+#include <DisplayPlane.h>
+#include <hal_public.h>
+#include <OMX_IVCommon.h>
+#include <OMX_IntelVideoExt.h>
+#include <PlaneCapabilities.h>
+#include <common/OverlayHardware.h>
+#include <HwcLayer.h>
+#include <BufferManager.h>
+#include <Hwcomposer.h>
+
+
+#define SPRITE_PLANE_MAX_STRIDE_TILED      16384
+#define SPRITE_PLANE_MAX_STRIDE_LINEAR     16384
+
+#define OVERLAY_PLANE_MAX_STRIDE_PACKED    4096
+#define OVERLAY_PLANE_MAX_STRIDE_LINEAR    8192
+
+namespace android {
+namespace intel {
+
+bool PlaneCapabilities::isFormatSupported(int planeType, HwcLayer *hwcLayer)
+{
+    uint32_t format = hwcLayer->getFormat();
+    uint32_t trans = hwcLayer->getLayer()->transform;
+
+    if (planeType == DisplayPlane::PLANE_SPRITE || planeType == DisplayPlane::PLANE_PRIMARY) {
+        switch (format) {
+        case HAL_PIXEL_FORMAT_BGRA_8888:
+        case HAL_PIXEL_FORMAT_BGRX_8888:
+        case HAL_PIXEL_FORMAT_RGBA_8888:
+        case HAL_PIXEL_FORMAT_RGBX_8888:
+        case HAL_PIXEL_FORMAT_RGB_565:
+            return trans ? false : true;
+        default:
+            VTRACE("unsupported format %#x", format);
+            return false;
+        }
+    } else if (planeType == DisplayPlane::PLANE_OVERLAY) {
+        switch (format) {
+        case HAL_PIXEL_FORMAT_I420:
+        case HAL_PIXEL_FORMAT_YUY2:
+        case HAL_PIXEL_FORMAT_UYVY:
+            // TODO: overlay supports 180 degree rotation
+            if (trans == HAL_TRANSFORM_ROT_180) {
+                WTRACE("180 degree rotation is not supported yet");
+            }
+            return trans ? false : true;
+        case HAL_PIXEL_FORMAT_YV12:
+        case HAL_PIXEL_FORMAT_NV12:
+        case OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar:
+        case OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar_Tiled:
+            return true;
+        default:
+            VTRACE("unsupported format %#x", format);
+            return false;
+        }
+    } else {
+        ETRACE("invalid plane type %d", planeType);
+        return false;
+    }
+}
+
+bool PlaneCapabilities::isSizeSupported(int planeType, HwcLayer *hwcLayer)
+{
+    uint32_t format = hwcLayer->getFormat();
+    uint32_t w = hwcLayer->getBufferWidth();
+    uint32_t h = hwcLayer->getBufferHeight();
+    const stride_t& stride = hwcLayer->getBufferStride();
+
+    bool isYUVPacked;
+    uint32_t maxStride;
+
+    if (planeType == DisplayPlane::PLANE_SPRITE || planeType == DisplayPlane::PLANE_PRIMARY) {
+        switch (format) {
+        case HAL_PIXEL_FORMAT_BGRA_8888:
+        case HAL_PIXEL_FORMAT_BGRX_8888:
+        case HAL_PIXEL_FORMAT_RGBA_8888:
+        case HAL_PIXEL_FORMAT_RGBX_8888:
+        case HAL_PIXEL_FORMAT_RGB_565:
+            VTRACE("stride %d", stride.rgb.stride);
+            if (stride.rgb.stride > SPRITE_PLANE_MAX_STRIDE_LINEAR) {
+                VTRACE("too large stride %d", stride.rgb.stride);
+                return false;
+            }
+            return true;
+        default:
+            VTRACE("unsupported format %#x", format);
+            return false;
+        }
+    } else if (planeType == DisplayPlane::PLANE_OVERLAY) {
+        switch (format) {
+        case HAL_PIXEL_FORMAT_YV12:
+        case HAL_PIXEL_FORMAT_I420:
+        case HAL_PIXEL_FORMAT_NV12:
+        case OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar:
+        case OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar_Tiled:
+            isYUVPacked = false;
+            break;
+        case HAL_PIXEL_FORMAT_YUY2:
+        case HAL_PIXEL_FORMAT_UYVY:
+            isYUVPacked = true;
+            break;
+        default:
+            VTRACE("unsupported format %#x", format);
+            return false;
+        }
+        // don't use overlay plane if stride is too big
+        maxStride = OVERLAY_PLANE_MAX_STRIDE_LINEAR;
+        if (isYUVPacked) {
+            maxStride = OVERLAY_PLANE_MAX_STRIDE_PACKED;
+        }
+
+        if (stride.yuv.yStride > maxStride) {
+            VTRACE("stride %d is too large", stride.yuv.yStride);
+            return false;
+        }
+
+        hwc_frect_t& srcCrop = hwcLayer->getLayer()->sourceCropf;
+        uint32_t width = srcCrop.right - srcCrop.left;
+        uint32_t height = srcCrop.bottom - srcCrop.top;
+
+        if (width <= 64 || height <= 64) {
+            DTRACE("width or height of source crop is less than 64, fallback to GLES");
+            return false;
+        }
+
+        if ((height & 0x1) || (width & 0x1)){
+            if (!hwcLayer->isProtected()) {
+                 DTRACE("unprotected video content, height or width of source crop is not even, fallback to GLES ");
+                 return false;
+            }
+        }
+
+        return true;
+    } else {
+        ETRACE("invalid plane type %d", planeType);
+        return false;
+    }
+}
+
+bool PlaneCapabilities::isBlendingSupported(int planeType, HwcLayer *hwcLayer)
+{
+    uint32_t blending = (uint32_t)hwcLayer->getLayer()->blending;
+    uint8_t planeAlpha = hwcLayer->getLayer()->planeAlpha;
+
+    if (planeType == DisplayPlane::PLANE_SPRITE || planeType == DisplayPlane::PLANE_PRIMARY) {
+        // support premultipled & none blanding
+        switch (blending) {
+        case HWC_BLENDING_NONE:
+        case HWC_BLENDING_PREMULT:
+        // add coverage alpha support for ann
+        case HWC_BLENDING_COVERAGE:
+            return true;
+        default:
+            VTRACE("unsupported blending %#x", blending);
+            return false;
+        }
+    } else if (planeType == DisplayPlane::PLANE_OVERLAY) {
+        // overlay doesn't support blending
+        return (blending == HWC_BLENDING_NONE) ? true : false;
+    } else {
+        ETRACE("invalid plane type %d", planeType);
+        return false;
+    }
+}
+
+bool PlaneCapabilities::isScalingSupported(int planeType, HwcLayer *hwcLayer)
+{
+    hwc_frect_t& src = hwcLayer->getLayer()->sourceCropf;
+    hwc_rect_t& dest = hwcLayer->getLayer()->displayFrame;
+    uint32_t trans = hwcLayer->getLayer()->transform;
+
+    int srcW, srcH;
+    int dstW, dstH;
+
+    srcW = (int)src.right - (int)src.left;
+    srcH = (int)src.bottom - (int)src.top;
+    dstW = dest.right - dest.left;
+    dstH = dest.bottom - dest.top;
+
+    if (planeType == DisplayPlane::PLANE_SPRITE || planeType == DisplayPlane::PLANE_PRIMARY) {
+        // no scaling is supported
+        return ((srcW == dstW) && (srcH == dstH)) ? true : false;
+
+    } else if (planeType == DisplayPlane::PLANE_OVERLAY) {
+        // overlay cannot support resolution that bigger than 2047x2047.
+        if ((srcW > INTEL_OVERLAY_MAX_WIDTH - 1) || (srcH > INTEL_OVERLAY_MAX_HEIGHT - 1)) {
+            uint32_t format = hwcLayer->getFormat();
+            if (format == OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar ||
+                format == OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar_Tiled) {
+                // will fall back to GLES if no scaling buffer provided by ved later
+                // so don't return false and print a warning, it's for video format only.
+                WTRACE("source size %dx%d hit overlay resolution limitation.", srcW, srcH);
+            } else {
+                return false;
+            }
+        }
+
+        if (dstW <= 100 || dstH <= 1 || srcW <= 100 || srcH <= 1) {
+            // Workaround: Overlay flip when height is 1 causes MIPI stall on TNG
+            DTRACE("invalid destination size: %dx%d, fall back to GLES", dstW, dstH);
+            return false;
+        }
+
+        if (trans == HAL_TRANSFORM_ROT_90 || trans == HAL_TRANSFORM_ROT_270) {
+            int tmp = srcW;
+            srcW = srcH;
+            srcH = tmp;
+        }
+
+        if (!hwcLayer->isProtected()) {
+            if ((int)src.left & 63) {
+                DTRACE("offset %d is not 64 bytes aligned, fall back to GLES", (int)src.left);
+                return false;
+            }
+
+            float scaleX = (float)srcW / dstW;
+            float scaleY = (float)srcH / dstH;
+            if (scaleX >= 3 || scaleY >= 3) {
+                DTRACE("overlay rotation with scaling >= 3, fall back to GLES");
+                return false;
+            }
+#if 0
+            if (trans == HAL_TRANSFORM_ROT_90 && (float)srcW / srcH != (float)dstW / dstH) {
+                // FIXME: work aournd for pipe crashing issue, when rotate screen
+                // from 90 to 0 degree (with Sharp 25x16 panel).
+                DTRACE("overlay rotation with uneven scaling, fall back to GLES");
+                return false;
+            }
+#endif
+        }
+
+        return true;
+    } else {
+        ETRACE("invalid plane type %d", planeType);
+        return false;
+    }
+}
+
+bool PlaneCapabilities::isTransformSupported(int planeType, HwcLayer *hwcLayer)
+{
+    uint32_t trans = hwcLayer->getLayer()->transform;
+
+    if (planeType == DisplayPlane::PLANE_OVERLAY) {
+        // overlay does not support FLIP_H/FLIP_V
+        switch (trans) {
+        case 0:
+        case HAL_TRANSFORM_ROT_90:
+        case HAL_TRANSFORM_ROT_180:
+        case HAL_TRANSFORM_ROT_270:
+            return true;
+        default:
+            return false;
+        }
+    }
+
+    // don't transform any tranform
+    return trans ? false : true;
+}
+
+} // namespace intel
+} // namespace android
+
diff --git a/merrifield/ips/common/BlankControl.cpp b/merrifield/ips/common/BlankControl.cpp
new file mode 100644
index 0000000..3ac0736
--- /dev/null
+++ b/merrifield/ips/common/BlankControl.cpp
@@ -0,0 +1,43 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#include <HwcTrace.h>
+#include <Drm.h>
+#include <common/BlankControl.h>
+#include <Hwcomposer.h>
+
+namespace android {
+namespace intel {
+
+BlankControl::BlankControl()
+    : IBlankControl()
+{
+}
+
+BlankControl::~BlankControl()
+{
+}
+
+bool BlankControl::blank(int disp, bool blank)
+{
+    // current do nothing but return true
+    // use PM to trigger screen blank/unblank
+    VTRACE("blank is not supported yet, disp %d, blank %d", disp, blank);
+    return true;
+}
+
+} // namespace intel
+} // namespace android
diff --git a/merrifield/ips/common/BlankControl.h b/merrifield/ips/common/BlankControl.h
new file mode 100644
index 0000000..1c0de05
--- /dev/null
+++ b/merrifield/ips/common/BlankControl.h
@@ -0,0 +1,36 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef BLANK_CONTROL_H
+#define BLANK_CONTROL_H
+
+#include <IBlankControl.h>
+
+namespace android {
+namespace intel {
+
+class BlankControl : public IBlankControl {
+public:
+    BlankControl();
+    virtual ~BlankControl();
+
+public:
+    bool blank(int disp, bool blank);
+};
+
+} // namespace intel
+} // namespace android
+
+#endif /* BLANK_CONTROL_H */
diff --git a/merrifield/ips/common/DrmConfig.cpp b/merrifield/ips/common/DrmConfig.cpp
new file mode 100644
index 0000000..59b1c72
--- /dev/null
+++ b/merrifield/ips/common/DrmConfig.cpp
@@ -0,0 +1,90 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#include <HwcTrace.h>
+#include <IDisplayDevice.h>
+#include <Drm.h>
+#include <DrmConfig.h>
+
+
+namespace android {
+namespace intel {
+
+const char* DrmConfig::getDrmPath()
+{
+    return "/dev/card0";
+}
+
+uint32_t DrmConfig::getDrmConnector(int device)
+{
+    if (device == IDisplayDevice::DEVICE_PRIMARY)
+        return DRM_MODE_CONNECTOR_MIPI;
+    else if (device == IDisplayDevice::DEVICE_EXTERNAL)
+        return DRM_MODE_CONNECTOR_DVID;
+    return DRM_MODE_CONNECTOR_Unknown;
+}
+
+uint32_t DrmConfig::getDrmEncoder(int device)
+{
+    if (device == IDisplayDevice::DEVICE_PRIMARY)
+        return DRM_MODE_ENCODER_MIPI;
+    else if (device == IDisplayDevice::DEVICE_EXTERNAL)
+        return DRM_MODE_ENCODER_TMDS;
+    return DRM_MODE_ENCODER_NONE;
+}
+
+uint32_t DrmConfig::getFrameBufferFormat()
+{
+    return HAL_PIXEL_FORMAT_RGBX_8888;
+}
+
+uint32_t DrmConfig::getFrameBufferDepth()
+{
+    return 24;
+}
+
+uint32_t DrmConfig::getFrameBufferBpp()
+{
+    return 32;
+}
+
+const char* DrmConfig::getUeventEnvelope()
+{
+    return "change@/devices/pci0000:00/0000:00:02.0/drm/card0";
+}
+
+const char* DrmConfig::getHotplugString()
+{
+    return "HOTPLUG=1";
+}
+
+const char* DrmConfig::getRepeatedFrameString()
+{
+    return "REPEATED_FRAME";
+}
+
+uint32_t DrmConfig::convertHalFormatToDrmFormat(uint32_t halFormat)
+{
+    switch (halFormat) {
+        case HAL_PIXEL_FORMAT_RGBX_8888:
+            return DRM_FORMAT_XRGB8888;
+        default:
+            ETRACE("format %#x isn't supported by drm", halFormat);
+            return 0;
+    }
+}
+
+} // namespace intel
+} // namespace android
diff --git a/merrifield/ips/common/DrmControl.cpp b/merrifield/ips/common/DrmControl.cpp
new file mode 100644
index 0000000..9c34658
--- /dev/null
+++ b/merrifield/ips/common/DrmControl.cpp
@@ -0,0 +1,58 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#include <HwcTrace.h>
+#include <linux/psb_drm.h>
+#include <Hwcomposer.h>
+#include <common/DrmControl.h>
+
+namespace android {
+namespace intel {
+
+DrmControl::DrmControl()
+    : mVideoExtCommand(0)
+{
+}
+
+DrmControl::~DrmControl()
+{
+}
+
+int DrmControl::getVideoExtCommand()
+{
+    if (mVideoExtCommand) {
+        return mVideoExtCommand;
+    }
+
+    int fd = Hwcomposer::getInstance().getDrm()->getDrmFd();
+
+    union drm_psb_extension_arg video_getparam_arg;
+    strncpy(video_getparam_arg.extension,
+            "lnc_video_getparam", sizeof(video_getparam_arg.extension));
+    int ret = drmCommandWriteRead(fd, DRM_PSB_EXTENSION,
+            &video_getparam_arg, sizeof(video_getparam_arg));
+    if (ret != 0) {
+        VTRACE("failed to get video extension command");
+        return 0;
+    }
+
+    mVideoExtCommand = video_getparam_arg.rep.driver_ioctl_offset;
+
+    return mVideoExtCommand;
+}
+
+} // namespace intel
+} // namespace android
diff --git a/merrifield/ips/common/DrmControl.h b/merrifield/ips/common/DrmControl.h
new file mode 100644
index 0000000..fbd0284
--- /dev/null
+++ b/merrifield/ips/common/DrmControl.h
@@ -0,0 +1,38 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef DRM_CONTROL_H
+#define DRM_CONTROL_H
+
+
+namespace android {
+namespace intel {
+
+class DrmControl  {
+public:
+    DrmControl();
+    virtual ~DrmControl();
+
+public:
+    int getVideoExtCommand();
+
+private:
+    int mVideoExtCommand;
+};
+
+} // namespace intel
+} // namespace android
+
+#endif /* DRM_CONTROL_H */
diff --git a/merrifield/ips/common/GrallocBufferBase.cpp b/merrifield/ips/common/GrallocBufferBase.cpp
new file mode 100644
index 0000000..e50b777
--- /dev/null
+++ b/merrifield/ips/common/GrallocBufferBase.cpp
@@ -0,0 +1,91 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#include <HwcTrace.h>
+#include <common/GrallocBufferBase.h>
+#include <DisplayQuery.h>
+
+
+namespace android {
+namespace intel {
+
+GrallocBufferBase::GrallocBufferBase(buffer_handle_t handle)
+    : GraphicBuffer(handle)
+{
+    ATRACE("handle = %#x", handle);
+    initBuffer(handle);
+}
+
+void GrallocBufferBase::resetBuffer(buffer_handle_t handle)
+{
+    GraphicBuffer::resetBuffer(handle);
+    initBuffer(handle);
+}
+
+void GrallocBufferBase::initBuffer(buffer_handle_t handle)
+{
+    // nothing to initialize
+}
+
+void GrallocBufferBase::initStride()
+{
+    int yStride, uvStride;
+
+    // setup stride
+    switch (mFormat) {
+    case HAL_PIXEL_FORMAT_YV12:
+    case HAL_PIXEL_FORMAT_I420:
+        uint32_t yStride_align;
+        yStride_align = DisplayQuery::getOverlayLumaStrideAlignment(mFormat);
+        if (yStride_align > 0)
+        {
+            yStride = align_to(align_to(mWidth, 32), yStride_align);
+        }
+        else
+        {
+            yStride = align_to(align_to(mWidth, 32), 64);
+        }
+        uvStride = align_to(yStride >> 1, 64);
+        mStride.yuv.yStride = yStride;
+        mStride.yuv.uvStride = uvStride;
+        break;
+    case HAL_PIXEL_FORMAT_NV12:
+        yStride = align_to(align_to(mWidth, 32), 64);
+        uvStride = yStride;
+        mStride.yuv.yStride = yStride;
+        mStride.yuv.uvStride = uvStride;
+        break;
+    case OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar:
+    case OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar_Tiled:
+        yStride = align_to(align_to(mWidth, 32), 64);
+        uvStride = yStride;
+        mStride.yuv.yStride = yStride;
+        mStride.yuv.uvStride = uvStride;
+        break;
+    case HAL_PIXEL_FORMAT_YUY2:
+    case HAL_PIXEL_FORMAT_UYVY:
+        yStride = align_to((align_to(mWidth, 32) << 1), 64);
+        uvStride = 0;
+        mStride.yuv.yStride = yStride;
+        mStride.yuv.uvStride = uvStride;
+        break;
+    default:
+        mStride.rgb.stride = align_to(((mBpp >> 3) * align_to(mWidth, 32)), 64);
+        break;
+    }
+}
+
+}
+}
diff --git a/merrifield/ips/common/GrallocBufferBase.h b/merrifield/ips/common/GrallocBufferBase.h
new file mode 100644
index 0000000..5ae8c95
--- /dev/null
+++ b/merrifield/ips/common/GrallocBufferBase.h
@@ -0,0 +1,45 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef GRALLOC_BUFFER_BASE_H
+#define GRALLOC_BUFFER_BASE_H
+
+#include <GraphicBuffer.h>
+#include <hal_public.h>
+// FIXME: remove it, why define NV12_VED based on OMX's value?
+#include <OMX_IVCommon.h>
+#include <OMX_IntelVideoExt.h>
+
+namespace android {
+namespace intel {
+
+class GrallocBufferBase : public GraphicBuffer {
+public:
+    GrallocBufferBase(buffer_handle_t handle);
+    virtual ~GrallocBufferBase() {}
+    virtual void resetBuffer(buffer_handle_t handle);
+
+protected:
+    // helper function to be invoked by the derived class
+    void initStride();
+
+private:
+    void initBuffer(buffer_handle_t handle);
+};
+
+} // namespace intel
+} // namespace android
+
+#endif /* GRALLOC_BUFFER_BASE_H */
diff --git a/merrifield/ips/common/GrallocBufferMapperBase.cpp b/merrifield/ips/common/GrallocBufferMapperBase.cpp
new file mode 100644
index 0000000..ac236e3
--- /dev/null
+++ b/merrifield/ips/common/GrallocBufferMapperBase.cpp
@@ -0,0 +1,72 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#include <HwcTrace.h>
+#include <Drm.h>
+#include <Hwcomposer.h>
+#include <common/GrallocBufferMapperBase.h>
+
+namespace android {
+namespace intel {
+
+GrallocBufferMapperBase::GrallocBufferMapperBase(DataBuffer& buffer)
+    : BufferMapper(buffer)
+{
+    CTRACE();
+
+    for (int i = 0; i < SUB_BUFFER_MAX; i++) {
+        mGttOffsetInPage[i] = 0;
+        mCpuAddress[i] = 0;
+        mSize[i] = 0;
+        mKHandle[i] = 0;
+    }
+}
+
+GrallocBufferMapperBase::~GrallocBufferMapperBase()
+{
+    CTRACE();
+}
+
+uint32_t GrallocBufferMapperBase::getGttOffsetInPage(int subIndex) const
+{
+    if (subIndex >= 0 && subIndex < SUB_BUFFER_MAX)
+        return mGttOffsetInPage[subIndex];
+    return 0;
+}
+
+void* GrallocBufferMapperBase::getCpuAddress(int subIndex) const
+{
+    if (subIndex >=0 && subIndex < SUB_BUFFER_MAX)
+        return mCpuAddress[subIndex];
+    return 0;
+}
+
+uint32_t GrallocBufferMapperBase::getSize(int subIndex) const
+{
+    if (subIndex >= 0 && subIndex < SUB_BUFFER_MAX)
+        return mSize[subIndex];
+    return 0;
+}
+
+buffer_handle_t GrallocBufferMapperBase::getKHandle(int subIndex)
+{
+    if (subIndex >= 0 && subIndex < SUB_BUFFER_MAX)
+        return mKHandle[subIndex];
+    return 0;
+}
+
+
+} // namespace intel
+} // namespace android
diff --git a/merrifield/ips/common/GrallocBufferMapperBase.h b/merrifield/ips/common/GrallocBufferMapperBase.h
new file mode 100644
index 0000000..fed0d8e
--- /dev/null
+++ b/merrifield/ips/common/GrallocBufferMapperBase.h
@@ -0,0 +1,52 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef GRALLOC_BUFFER_MAPPER_BASE_H
+#define GRALLOC_BUFFER_MAPPER_BASE_H
+
+#include <BufferMapper.h>
+#include <common/GrallocSubBuffer.h>
+#include <common/GrallocBufferBase.h>
+
+namespace android {
+namespace intel {
+
+class GrallocBufferMapperBase : public BufferMapper {
+public:
+    GrallocBufferMapperBase(DataBuffer& buffer);
+    virtual ~GrallocBufferMapperBase();
+public:
+    virtual bool map() = 0;
+    virtual bool unmap() = 0;
+
+    uint32_t getGttOffsetInPage(int subIndex) const;
+    void* getCpuAddress(int subIndex) const;
+    uint32_t getSize(int subIndex) const;
+    virtual buffer_handle_t getKHandle(int subIndex);
+    virtual buffer_handle_t getFbHandle(int subIndex) = 0;
+    virtual void putFbHandle() = 0;
+
+protected:
+    // mapped info
+    uint32_t mGttOffsetInPage[SUB_BUFFER_MAX];
+    void* mCpuAddress[SUB_BUFFER_MAX];
+    uint32_t mSize[SUB_BUFFER_MAX];
+    buffer_handle_t mKHandle[SUB_BUFFER_MAX];
+};
+
+} // namespace intel
+} // namespace android
+
+#endif /* TNG_GRALLOC_BUFFER_MAPPER_H */
diff --git a/merrifield/ips/common/GrallocSubBuffer.h b/merrifield/ips/common/GrallocSubBuffer.h
new file mode 100644
index 0000000..15170f2
--- /dev/null
+++ b/merrifield/ips/common/GrallocSubBuffer.h
@@ -0,0 +1,35 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef GRALLOC_SUB_BUFFER_H
+#define GRALLOC_SUB_BUFFER_H
+
+
+namespace android {
+namespace intel {
+
+enum {
+    SUB_BUFFER0 = 0,
+    SUB_BUFFER1,
+    SUB_BUFFER2,
+    SUB_BUFFER_MAX,
+};
+
+} // namespace intel
+} // namespace android
+
+
+#endif /* GRALLOC_SUB_BUFFER_H */
+
diff --git a/merrifield/ips/common/HdcpControl.cpp b/merrifield/ips/common/HdcpControl.cpp
new file mode 100644
index 0000000..620d28f
--- /dev/null
+++ b/merrifield/ips/common/HdcpControl.cpp
@@ -0,0 +1,380 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#include <HwcTrace.h>
+#include <DrmConfig.h>
+#include <Hwcomposer.h>
+#include <DisplayQuery.h>
+#include <common/DrmControl.h>
+#include <common/HdcpControl.h>
+#include <cutils/properties.h>
+
+
+namespace android {
+namespace intel {
+
+HdcpControl::HdcpControl()
+    : mCallback(NULL),
+      mUserData(NULL),
+      mCallbackState(CALLBACK_PENDING),
+      mMutex(),
+      mStoppedCondition(),
+      mCompletedCondition(),
+      mWaitForCompletion(false),
+      mStopped(true),
+      mAuthenticated(false),
+      mActionDelay(0),
+      mAuthRetryCount(0)
+{
+}
+
+HdcpControl::~HdcpControl()
+{
+}
+
+bool HdcpControl::startHdcp()
+{
+    // this is a blocking and synchronous call
+    Mutex::Autolock lock(mMutex);
+
+    char prop[PROPERTY_VALUE_MAX];
+    if (property_get("debug.hwc.hdcp.enable", prop, "1") > 0) {
+        if (atoi(prop) == 0) {
+            WTRACE("HDCP is disabled");
+            return false;
+        }
+    }
+
+    if (!mStopped) {
+        WTRACE("HDCP has been started");
+        return true;
+    }
+
+    mStopped = false;
+    mAuthenticated = false;
+    mWaitForCompletion = false;
+
+    mThread = new HdcpControlThread(this);
+    if (!mThread.get()) {
+        ETRACE("failed to create hdcp control thread");
+        return false;
+    }
+
+    if (!runHdcp()) {
+        ETRACE("failed to run HDCP");
+        mStopped = true;
+        mThread = NULL;
+        return false;
+    }
+
+    mAuthRetryCount = 0;
+    mWaitForCompletion = !mAuthenticated;
+    if (mAuthenticated) {
+        mActionDelay = HDCP_VERIFICATION_DELAY_MS;
+    } else {
+        mActionDelay = HDCP_AUTHENTICATION_SHORT_DELAY_MS;
+    }
+
+    mThread->run("HdcpControl", PRIORITY_NORMAL);
+
+    if (!mWaitForCompletion) {
+        // HDCP is authenticated.
+        return true;
+    }
+    status_t err = mCompletedCondition.waitRelative(mMutex, milliseconds(HDCP_AUTHENTICATION_TIMEOUT_MS));
+    if (err == -ETIMEDOUT) {
+        WTRACE("timeout waiting for completion");
+    }
+    mWaitForCompletion = false;
+    return mAuthenticated;
+}
+
+bool HdcpControl::startHdcpAsync(HdcpStatusCallback cb, void *userData)
+{
+    char prop[PROPERTY_VALUE_MAX];
+    if (property_get("debug.hwc.hdcp.enable", prop, "1") > 0) {
+        if (atoi(prop) == 0) {
+            WTRACE("HDCP is disabled");
+            return false;
+        }
+    }
+
+    if (cb == NULL || userData == NULL) {
+        ETRACE("invalid callback or user data");
+        return false;
+    }
+
+    Mutex::Autolock lock(mMutex);
+
+    if (!mStopped) {
+        WTRACE("HDCP has been started");
+        return true;
+    }
+
+    mThread = new HdcpControlThread(this);
+    if (!mThread.get()) {
+        ETRACE("failed to create hdcp control thread");
+        return false;
+    }
+
+    mAuthRetryCount = 0;
+    mCallback = cb;
+    mUserData = userData;
+    mCallbackState = CALLBACK_PENDING;
+    mWaitForCompletion = false;
+    mAuthenticated = false;
+    mStopped = false;
+    mActionDelay = HDCP_ASYNC_START_DELAY_MS;
+    mThread->run("HdcpControl", PRIORITY_NORMAL);
+
+    return true;
+}
+
+bool HdcpControl::stopHdcp()
+{
+    do {
+        Mutex::Autolock lock(mMutex);
+        if (mStopped) {
+            return true;
+        }
+
+        mStopped = true;
+        mStoppedCondition.signal();
+
+        mAuthenticated = false;
+        mWaitForCompletion = false;
+        mCallback = NULL;
+        mUserData = NULL;
+        disableAuthentication();
+    } while (0);
+
+    if (mThread.get()) {
+        mThread->requestExitAndWait();
+        mThread = NULL;
+    }
+
+    return true;
+}
+
+bool HdcpControl::enableAuthentication()
+{
+    int fd = Hwcomposer::getInstance().getDrm()->getDrmFd();
+    int ret = drmCommandNone(fd, DRM_PSB_ENABLE_HDCP);
+    if (ret != 0) {
+        ETRACE("failed to enable HDCP authentication");
+        return false;
+    }
+    return true;
+}
+
+bool HdcpControl::disableAuthentication()
+{
+    int fd = Hwcomposer::getInstance().getDrm()->getDrmFd();
+    int ret = drmCommandNone(fd, DRM_PSB_DISABLE_HDCP);
+    if (ret != 0) {
+        ETRACE("failed to stop disable authentication");
+        return false;
+    }
+    return true;
+}
+
+bool HdcpControl::enableOverlay()
+{
+    return true;
+}
+
+bool HdcpControl::disableOverlay()
+{
+    return true;
+}
+
+bool HdcpControl::enableDisplayIED()
+{
+    int fd = Hwcomposer::getInstance().getDrm()->getDrmFd();
+    int ret = drmCommandNone(fd, DRM_PSB_HDCP_DISPLAY_IED_ON);
+    if (ret != 0) {
+        ETRACE("failed to enable overlay IED");
+        return false;
+    }
+    return true;
+}
+
+bool HdcpControl::disableDisplayIED()
+{
+    int fd = Hwcomposer::getInstance().getDrm()->getDrmFd();
+    int ret = drmCommandNone(fd, DRM_PSB_HDCP_DISPLAY_IED_OFF);
+    if (ret != 0) {
+        ETRACE("failed to disable overlay IED");
+        return false;
+    }
+    return true;
+}
+
+bool HdcpControl::isHdcpSupported()
+{
+    int fd = Hwcomposer::getInstance().getDrm()->getDrmFd();
+    unsigned int caps = 0;
+    int ret = drmCommandRead(fd, DRM_PSB_QUERY_HDCP, &caps, sizeof(caps));
+    if (ret != 0) {
+        ETRACE("failed to query HDCP capability");
+        return false;
+    }
+    if (caps == 0) {
+        WTRACE("HDCP is not supported");
+        return false;
+    } else {
+        ITRACE("HDCP is supported");
+        return true;
+    }
+}
+
+bool HdcpControl::checkAuthenticated()
+{
+    int fd = Hwcomposer::getInstance().getDrm()->getDrmFd();
+    unsigned int match = 0;
+    int ret = drmCommandRead(fd, DRM_PSB_GET_HDCP_LINK_STATUS, &match, sizeof(match));
+    if (ret != 0) {
+        ETRACE("failed to get hdcp link status");
+        return false;
+    }
+    if (match) {
+        VTRACE("HDCP is authenticated");
+        mAuthenticated = true;
+    } else {
+        ETRACE("HDCP is not authenticated");
+        mAuthenticated = false;
+    }
+    return mAuthenticated;
+}
+
+bool HdcpControl::runHdcp()
+{
+    // Default return value is true so HDCP can be re-authenticated in the working thread
+    bool ret = true;
+
+    preRunHdcp();
+
+    for (int i = 0; i < HDCP_INLOOP_RETRY_NUMBER; i++) {
+        VTRACE("enable and verify HDCP, iteration# %d", i);
+        if (mStopped) {
+            WTRACE("HDCP authentication has been stopped");
+            ret = false;
+            break;
+        }
+
+        if (!enableAuthentication()) {
+            ETRACE("HDCP authentication failed. Retry");
+            mAuthenticated = false;
+            ret = true;
+        } else {
+            ITRACE("HDCP is authenticated");
+            mAuthenticated = true;
+            ret = true;
+            break;
+        }
+
+        if (mStopped) {
+            WTRACE("HDCP authentication has been stopped");
+            ret = false;
+            break;
+        }
+
+        if (i < HDCP_INLOOP_RETRY_NUMBER - 1) {
+            // Adding delay to make sure panel receives video signal so it can start HDCP authentication.
+            // (HDCP spec 1.3, section 2.3)
+            usleep(HDCP_INLOOP_RETRY_DELAY_US);
+        }
+    }
+
+    postRunHdcp();
+
+    return ret;
+}
+
+bool HdcpControl::preRunHdcp()
+{
+    // TODO: for CTP platform, IED needs to be disabled during HDCP authentication.
+    return true;
+}
+
+bool HdcpControl::postRunHdcp()
+{
+    // TODO: for CTP platform, IED needs to be disabled during HDCP authentication.
+    return true;
+}
+
+
+void HdcpControl::signalCompletion()
+{
+    if (mWaitForCompletion) {
+        ITRACE("signal HDCP authentication completed, status = %d", mAuthenticated);
+        mCompletedCondition.signal();
+        mWaitForCompletion = false;
+    }
+}
+
+bool HdcpControl::threadLoop()
+{
+    Mutex::Autolock lock(mMutex);
+    status_t err = mStoppedCondition.waitRelative(mMutex, milliseconds(mActionDelay));
+    if (err != -ETIMEDOUT) {
+        ITRACE("Hdcp is stopped.");
+        signalCompletion();
+        return false;
+    }
+
+    // default is to keep thread active
+    bool ret = true;
+    if (!mAuthenticated) {
+        ret = runHdcp();
+        mAuthRetryCount++;
+    } else {
+        mAuthRetryCount = 0;
+        checkAuthenticated();
+    }
+
+    // set next action delay
+    if (mAuthenticated) {
+        mActionDelay = HDCP_VERIFICATION_DELAY_MS;
+    } else {
+        // If HDCP can not authenticate after "HDCP_RETRY_LIMIT" attempts
+        // reduce HDCP retry frequency to 2 sec
+        if (mAuthRetryCount >= HDCP_RETRY_LIMIT) {
+            mActionDelay = HDCP_AUTHENTICATION_LONG_DELAY_MS;
+        } else {
+            mActionDelay = HDCP_AUTHENTICATION_SHORT_DELAY_MS;
+        }
+    }
+
+    // TODO: move out of lock?
+    if (!ret || mAuthenticated) {
+        signalCompletion();
+    }
+
+    if (mCallback) {
+         if ((mAuthenticated && mCallbackState == CALLBACK_AUTHENTICATED) ||
+            (!mAuthenticated && mCallbackState == CALLBACK_NOT_AUTHENTICATED)) {
+            // ignore callback as state is not changed
+        } else {
+            mCallbackState =
+                mAuthenticated ? CALLBACK_AUTHENTICATED : CALLBACK_NOT_AUTHENTICATED;
+            (*mCallback)(mAuthenticated, mUserData);
+        }
+    }
+    return ret;
+}
+
+} // namespace intel
+} // namespace android
diff --git a/merrifield/ips/common/HdcpControl.h b/merrifield/ips/common/HdcpControl.h
new file mode 100644
index 0000000..5dc33c9
--- /dev/null
+++ b/merrifield/ips/common/HdcpControl.h
@@ -0,0 +1,87 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef HDCP_CONTROL_H
+#define HDCP_CONTROL_H
+
+#include <IHdcpControl.h>
+#include <SimpleThread.h>
+
+namespace android {
+namespace intel {
+
+class HdcpControl : public IHdcpControl {
+public:
+    HdcpControl();
+    virtual ~HdcpControl();
+
+public:
+    virtual bool startHdcp();
+    virtual bool startHdcpAsync(HdcpStatusCallback cb, void *userData);
+    virtual bool stopHdcp();
+
+protected:
+    bool enableAuthentication();
+    bool disableAuthentication();
+    bool enableOverlay();
+    bool disableOverlay();
+    bool enableDisplayIED();
+    bool disableDisplayIED();
+    bool isHdcpSupported();
+    bool checkAuthenticated();
+    virtual bool preRunHdcp();
+    virtual bool postRunHdcp();
+    bool runHdcp();
+    inline void signalCompletion();
+
+private:
+    enum {
+        HDCP_INLOOP_RETRY_NUMBER = 1,
+        HDCP_INLOOP_RETRY_DELAY_US = 50000,
+        HDCP_VERIFICATION_DELAY_MS = 2000,
+        HDCP_ASYNC_START_DELAY_MS = 100,
+        HDCP_AUTHENTICATION_SHORT_DELAY_MS = 200,
+        HDCP_AUTHENTICATION_LONG_DELAY_MS = 2000,
+        HDCP_AUTHENTICATION_TIMEOUT_MS = 5000,
+        HDCP_RETRY_LIMIT = 10,
+    };
+
+    enum {
+        CALLBACK_PENDING,
+        CALLBACK_AUTHENTICATED,
+        CALLBACK_NOT_AUTHENTICATED,
+    };
+
+protected:
+    HdcpStatusCallback mCallback;
+    void *mUserData;
+    int mCallbackState;
+    Mutex mMutex;
+    Condition mStoppedCondition;
+    Condition mCompletedCondition;
+    bool mWaitForCompletion;
+    bool mStopped;
+    bool mAuthenticated;
+    int mActionDelay;  // in milliseconds
+    uint32_t mAuthRetryCount;
+
+private:
+    DECLARE_THREAD(HdcpControlThread, HdcpControl);
+};
+
+} // namespace intel
+} // namespace android
+
+#endif /* HDCP_CONTROL_H */
diff --git a/merrifield/ips/common/OverlayHardware.h b/merrifield/ips/common/OverlayHardware.h
new file mode 100644
index 0000000..a06f304
--- /dev/null
+++ b/merrifield/ips/common/OverlayHardware.h
@@ -0,0 +1,160 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef OVERLAY_HARDWARE_H
+#define OVERLAY_HARDWARE_H
+
+namespace android {
+namespace intel {
+
+// only one overlay data buffer for testing
+#define INTEL_OVERLAY_BUFFER_NUM          1
+#define INTEL_OVERLAY_MAX_WIDTH         2048
+#define INTEL_OVERLAY_MAX_HEIGHT        2048
+#define INTEL_OVERLAY_MIN_STRIDE        512
+#define INTEL_OVERLAY_MAX_STRIDE_PACKED (8 * 1024)
+#define INTEL_OVERLAY_MAX_STRIDE_LINEAR (4 * 1024)
+#define INTEL_OVERLAY_MAX_SCALING_RATIO   7
+
+// Polyphase filter coefficients
+#define N_HORIZ_Y_TAPS                  5
+#define N_VERT_Y_TAPS                   3
+#define N_HORIZ_UV_TAPS                 3
+#define N_VERT_UV_TAPS                  3
+#define N_PHASES                        17
+#define MAX_TAPS                        5
+
+// Filter cutoff frequency limits.
+#define MIN_CUTOFF_FREQ                 1.0
+#define MAX_CUTOFF_FREQ                 3.0
+
+// Overlay init micros
+#define OVERLAY_INIT_CONTRAST           0x4b
+#define OVERLAY_INIT_BRIGHTNESS         -19
+#define OVERLAY_INIT_SATURATION         0x92
+#define OVERLAY_INIT_GAMMA0             0x080808
+#define OVERLAY_INIT_GAMMA1             0x101010
+#define OVERLAY_INIT_GAMMA2             0x202020
+#define OVERLAY_INIT_GAMMA3             0x404040
+#define OVERLAY_INIT_GAMMA4             0x808080
+#define OVERLAY_INIT_GAMMA5             0xc0c0c0
+#define OVERLAY_INIT_COLORKEY           0
+#define OVERLAY_INIT_COLORKEYMASK       ((0x0 << 31) | (0X0 << 30))
+#define OVERLAY_INIT_CONFIG             ((0x1 << 18) | (0x1 << 3))
+
+// overlay register values
+#define OVERLAY_FORMAT_MASK             (0xf << 10)
+#define OVERLAY_FORMAT_PACKED_YUV422    (0x8 << 10)
+#define OVERLAY_FORMAT_PLANAR_NV12_1    (0x7 << 10)
+#define OVERLAY_FORMAT_PLANAR_NV12_2    (0xb << 10)
+#define OVERLAY_FORMAT_PLANAR_YUV420    (0xc << 10)
+#define OVERLAY_FORMAT_PLANAR_YUV422    (0xd << 10)
+#define OVERLAY_FORMAT_PLANAR_YUV41X    (0xe << 10)
+
+#define OVERLAY_PACKED_ORDER_YUY2       (0x0 << 14)
+#define OVERLAY_PACKED_ORDER_YVYU       (0x1 << 14)
+#define OVERLAY_PACKED_ORDER_UYVY       (0x2 << 14)
+#define OVERLAY_PACKED_ORDER_VYUY       (0x3 << 14)
+#define OVERLAY_PACKED_ORDER_MASK       (0x3 << 14)
+
+#define OVERLAY_MEMORY_LAYOUT_TILED     (0x1 << 19)
+#define OVERLAY_MEMORY_LAYOUT_LINEAR    (0x0 << 19)
+
+#define OVERLAY_MIRRORING_NORMAL        (0x0 << 17)
+#define OVERLAY_MIRRORING_HORIZONTAL    (0x1 << 17)
+#define OVERLAY_MIRRORING_VERTIACAL     (0x2 << 17)
+#define OVERLAY_MIRRORING_BOTH          (0x3 << 17)
+
+#define BUF_TYPE                (0x1<<5)
+#define BUF_TYPE_FRAME          (0x0<<5)
+#define BUF_TYPE_FIELD          (0x1<<5)
+#define TEST_MODE               (0x1<<4)
+#define BUFFER_SELECT           (0x3<<2)
+#define BUFFER0                 (0x0<<2)
+#define BUFFER1                 (0x1<<2)
+#define FIELD_SELECT            (0x1<<1)
+#define FIELD0                  (0x0<<1)
+#define FIELD1                  (0x1<<1)
+#define OVERLAY_ENABLE          0x1
+
+
+// Overlay contorl registers
+typedef struct {
+    uint32_t OBUF_0Y;
+    uint32_t OBUF_1Y;
+    uint32_t OBUF_0U;
+    uint32_t OBUF_0V;
+    uint32_t OBUF_1U;
+    uint32_t OBUF_1V;
+    uint32_t OSTRIDE;
+    uint32_t YRGB_VPH;
+    uint32_t UV_VPH;
+    uint32_t HORZ_PH;
+    uint32_t INIT_PHS;
+    uint32_t DWINPOS;
+    uint32_t DWINSZ;
+    uint32_t SWIDTH;
+    uint32_t SWIDTHSW;
+    uint32_t SHEIGHT;
+    uint32_t YRGBSCALE;
+    uint32_t UVSCALE;
+    uint32_t OCLRC0;
+    uint32_t OCLRC1;
+    uint32_t DCLRKV;
+    uint32_t DCLRKM;
+    uint32_t SCHRKVH;
+    uint32_t SCHRKVL;
+    uint32_t SCHRKEN;
+    uint32_t OCONFIG;
+    uint32_t OCMD;
+    uint32_t RESERVED1;
+    uint32_t OSTART_0Y;
+    uint32_t OSTART_1Y;
+    uint32_t OSTART_0U;
+    uint32_t OSTART_0V;
+    uint32_t OSTART_1U;
+    uint32_t OSTART_1V;
+    uint32_t OTILEOFF_0Y;
+    uint32_t OTILEOFF_1Y;
+    uint32_t OTILEOFF_0U;
+    uint32_t OTILEOFF_0V;
+    uint32_t OTILEOFF_1U;
+    uint32_t OTILEOFF_1V;
+    uint32_t FASTHSCALE;
+    uint32_t UVSCALEV;
+
+    uint32_t RESERVEDC[(0x200 - 0xA8) / 4];
+    uint16_t Y_VCOEFS[N_VERT_Y_TAPS * N_PHASES];
+    uint16_t RESERVEDD[0x100 / 2 - N_VERT_Y_TAPS * N_PHASES];
+    uint16_t Y_HCOEFS[N_HORIZ_Y_TAPS * N_PHASES];
+    uint16_t RESERVEDE[0x200 / 2 - N_HORIZ_Y_TAPS * N_PHASES];
+    uint16_t UV_VCOEFS[N_VERT_UV_TAPS * N_PHASES];
+    uint16_t RESERVEDF[0x100 / 2 - N_VERT_UV_TAPS * N_PHASES];
+    uint16_t UV_HCOEFS[N_HORIZ_UV_TAPS * N_PHASES];
+    uint16_t RESERVEDG[0x100 / 2 - N_HORIZ_UV_TAPS * N_PHASES];
+} OverlayBackBufferBlk;
+
+typedef struct {
+    uint8_t sign;
+    uint16_t mantissa;
+    uint8_t exponent;
+} coeffRec, *coeffPtr;
+
+
+} // namespace intel
+} // nam
+
+
+#endif
diff --git a/merrifield/ips/common/OverlayPlaneBase.cpp b/merrifield/ips/common/OverlayPlaneBase.cpp
new file mode 100644
index 0000000..5987b50
--- /dev/null
+++ b/merrifield/ips/common/OverlayPlaneBase.cpp
@@ -0,0 +1,1310 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#include <math.h>
+#include <HwcTrace.h>
+#include <Drm.h>
+#include <Hwcomposer.h>
+#include <PhysicalDevice.h>
+#include <common/OverlayPlaneBase.h>
+#include <common/TTMBufferMapper.h>
+#include <common/GrallocSubBuffer.h>
+#include <DisplayQuery.h>
+
+
+// FIXME: remove it
+#include <OMX_IVCommon.h>
+#include <OMX_IntelVideoExt.h>
+
+namespace android {
+namespace intel {
+
+OverlayPlaneBase::OverlayPlaneBase(int index, int disp)
+    : DisplayPlane(index, PLANE_OVERLAY, disp),
+      mTTMBuffers(),
+      mActiveTTMBuffers(),
+      mCurrent(0),
+      mWsbm(0),
+      mPipeConfig(0),
+      mBobDeinterlace(0),
+      mUseScaledBuffer(0)
+{
+    CTRACE();
+    for (int i = 0; i < OVERLAY_BACK_BUFFER_COUNT; i++) {
+        mBackBuffer[i] = 0;
+    }
+}
+
+OverlayPlaneBase::~OverlayPlaneBase()
+{
+    CTRACE();
+}
+
+bool OverlayPlaneBase::initialize(uint32_t bufferCount)
+{
+    Drm *drm = Hwcomposer::getInstance().getDrm();
+    CTRACE();
+
+    // NOTE: use overlay's data buffer count for the overlay plane
+    if (bufferCount < OVERLAY_DATA_BUFFER_COUNT) {
+        ITRACE("override overlay buffer count from %d to %d",
+             bufferCount, OVERLAY_DATA_BUFFER_COUNT);
+        bufferCount = OVERLAY_DATA_BUFFER_COUNT;
+    }
+    if (!DisplayPlane::initialize(bufferCount)) {
+        DEINIT_AND_RETURN_FALSE("failed to initialize display plane");
+    }
+
+    mTTMBuffers.setCapacity(bufferCount);
+    mActiveTTMBuffers.setCapacity(MIN_DATA_BUFFER_COUNT);
+
+    // init wsbm
+    mWsbm = new Wsbm(drm->getDrmFd());
+    if (!mWsbm || !mWsbm->initialize()) {
+        DEINIT_AND_RETURN_FALSE("failed to create wsbm");
+    }
+
+    // create overlay back buffer
+    for (int i = 0; i < OVERLAY_BACK_BUFFER_COUNT; i++) {
+        mBackBuffer[i] = createBackBuffer();
+        if (!mBackBuffer[i]) {
+            DEINIT_AND_RETURN_FALSE("failed to create overlay back buffer");
+        }
+        // reset back buffer
+        resetBackBuffer(i);
+    }
+
+    // disable overlay when created
+    flush(PLANE_DISABLE);
+
+    return true;
+}
+
+bool OverlayPlaneBase::isDisabled()
+{
+    RETURN_FALSE_IF_NOT_INIT();
+
+    struct drm_psb_register_rw_arg arg;
+    memset(&arg, 0, sizeof(struct drm_psb_register_rw_arg));
+
+    arg.get_plane_state_mask = 1;
+    arg.plane.type = DC_OVERLAY_PLANE;
+    arg.plane.index = mIndex;
+    // pass the pipe index to check its enabled status
+    // now we can pass the device id directly since
+    // their values are just equal
+    arg.plane.ctx = mDevice; // not used in kernel
+
+    Drm *drm = Hwcomposer::getInstance().getDrm();
+    bool ret = drm->writeReadIoctl(DRM_PSB_REGISTER_RW, &arg, sizeof(arg));
+    if (ret == false) {
+        WTRACE("overlay plane query failed with error code %d", ret);
+        return false;
+    }
+
+    DTRACE("overlay %d status %s on device %d, current device %d",
+        mIndex, arg.plane.ctx ? "DISABLED" : "ENABLED", mDevice, mDevice);
+
+    return arg.plane.ctx == PSB_DC_PLANE_DISABLED;
+}
+
+void OverlayPlaneBase::deinitialize()
+{
+    if (mTTMBuffers.size()) {
+        invalidateBufferCache();
+    }
+
+    if (mActiveTTMBuffers.size() > 0) {
+        invalidateActiveTTMBuffers();
+    }
+
+    // delete back buffer
+    for (int i = 0; i < OVERLAY_BACK_BUFFER_COUNT; i++) {
+        if (mBackBuffer[i]) {
+            deleteBackBuffer(i);
+            mBackBuffer[i] = NULL;
+        }
+    }
+    DEINIT_AND_DELETE_OBJ(mWsbm);
+
+    DisplayPlane::deinitialize();
+}
+
+void OverlayPlaneBase::invalidateBufferCache()
+{
+    // clear plane buffer cache
+    DisplayPlane::invalidateBufferCache();
+    invalidateTTMBuffers();
+}
+
+bool OverlayPlaneBase::assignToDevice(int disp)
+{
+    uint32_t pipeConfig = 0;
+
+    RETURN_FALSE_IF_NOT_INIT();
+    VTRACE("overlay %d assigned to disp %d", mIndex, disp);
+
+    switch (disp) {
+    case IDisplayDevice::DEVICE_EXTERNAL:
+        pipeConfig = (0x2 << 6);
+        break;
+    case IDisplayDevice::DEVICE_PRIMARY:
+    default:
+        pipeConfig = 0;
+        break;
+    }
+
+    // if pipe switching happened, then disable overlay first
+    if (mPipeConfig != pipeConfig) {
+        DTRACE("overlay %d switched from %d to %d", mIndex, mDevice, disp);
+        disable();
+    }
+
+    mPipeConfig = pipeConfig;
+    DisplayPlane::assignToDevice(disp);
+
+    enable();
+
+    return true;
+}
+
+void OverlayPlaneBase::setZOrderConfig(ZOrderConfig& zorderConfig,
+                                            void *nativeConfig)
+{
+    CTRACE();
+
+    // setup overlay z order
+    int ovaZOrder = -1;
+    int ovcZOrder = -1;
+    for (size_t i = 0; i < zorderConfig.size(); i++) {
+        DisplayPlane *plane = zorderConfig[i]->plane;
+        if (plane->getType() == DisplayPlane::PLANE_OVERLAY) {
+            if (plane->getIndex() == 0) {
+                ovaZOrder = i;
+            } else if (plane->getIndex() == 1) {
+                ovcZOrder = i;
+            }
+        }
+    }
+
+    for (int i = 0; i < OVERLAY_BACK_BUFFER_COUNT; i++) {
+        OverlayBackBufferBlk *backBuffer = mBackBuffer[i]->buf;
+        if (!backBuffer)
+            return;
+
+        // force overlay c above overlay a
+        if ((ovaZOrder >= 0) && (ovaZOrder < ovcZOrder)) {
+            backBuffer->OCONFIG |= (1 << 15);
+        } else {
+            backBuffer->OCONFIG &= ~(1 << 15);
+        }
+    }
+}
+
+bool OverlayPlaneBase::reset()
+{
+    RETURN_FALSE_IF_NOT_INIT();
+
+    DisplayPlane::reset();
+
+    // invalidate active TTM buffers
+    if (mActiveTTMBuffers.size() > 0) {
+        invalidateActiveTTMBuffers();
+    }
+
+    // reset back buffers
+    for (int i = 0; i < OVERLAY_BACK_BUFFER_COUNT; i++) {
+        resetBackBuffer(i);
+    }
+    return true;
+}
+
+bool OverlayPlaneBase::enable()
+{
+    RETURN_FALSE_IF_NOT_INIT();
+    for (int i = 0; i < OVERLAY_BACK_BUFFER_COUNT; i++) {
+        OverlayBackBufferBlk *backBuffer = mBackBuffer[i]->buf;
+        if (!backBuffer)
+            return false;
+
+        if (backBuffer->OCMD & 0x1)
+            return true;
+
+        backBuffer->OCMD |= 0x1;
+    }
+
+    // flush
+    flush(PLANE_ENABLE);
+    return true;
+}
+
+bool OverlayPlaneBase::disable()
+{
+    RETURN_FALSE_IF_NOT_INIT();
+    for (int i = 0; i < OVERLAY_BACK_BUFFER_COUNT; i++) {
+        OverlayBackBufferBlk *backBuffer = mBackBuffer[i]->buf;
+        if (!backBuffer)
+            return false;
+
+        if (!(backBuffer->OCMD & 0x1))
+            return true;
+
+        backBuffer->OCMD &= ~0x1;
+    }
+
+    // flush
+    flush(PLANE_DISABLE);
+    return true;
+}
+
+OverlayBackBuffer* OverlayPlaneBase::createBackBuffer()
+{
+    CTRACE();
+
+    // create back buffer
+    OverlayBackBuffer *backBuffer = (OverlayBackBuffer *)malloc(sizeof(OverlayBackBuffer));
+    if (!backBuffer) {
+        ETRACE("failed to allocate back buffer");
+        return 0;
+    }
+
+
+    int size = sizeof(OverlayBackBufferBlk);
+    int alignment = 64 * 1024;
+    void *wsbmBufferObject = 0;
+    bool ret = mWsbm->allocateTTMBuffer(size, alignment, &wsbmBufferObject);
+    if (ret == false) {
+        ETRACE("failed to allocate TTM buffer");
+        return 0;
+    }
+
+    void *virtAddr = mWsbm->getCPUAddress(wsbmBufferObject);
+    uint32_t gttOffsetInPage = mWsbm->getGttOffset(wsbmBufferObject);
+
+    backBuffer->buf = (OverlayBackBufferBlk *)virtAddr;
+    backBuffer->gttOffsetInPage = gttOffsetInPage;
+    backBuffer->bufObject = wsbmBufferObject;
+
+    VTRACE("cpu %p, gtt %d", virtAddr, gttOffsetInPage);
+
+    return backBuffer;
+}
+
+void OverlayPlaneBase::deleteBackBuffer(int buf)
+{
+    if (!mBackBuffer[buf])
+        return;
+
+    void *wsbmBufferObject = mBackBuffer[buf]->bufObject;
+    bool ret = mWsbm->destroyTTMBuffer(wsbmBufferObject);
+    if (ret == false) {
+        WTRACE("failed to destroy TTM buffer");
+    }
+    // free back buffer
+    free(mBackBuffer[buf]);
+    mBackBuffer[buf] = 0;
+}
+
+void OverlayPlaneBase::resetBackBuffer(int buf)
+{
+    CTRACE();
+
+    if (!mBackBuffer[buf] || !mBackBuffer[buf]->buf)
+        return;
+
+    OverlayBackBufferBlk *backBuffer = mBackBuffer[buf]->buf;
+
+    memset(backBuffer, 0, sizeof(OverlayBackBufferBlk));
+
+    // reset overlay
+    backBuffer->OCLRC0 = (OVERLAY_INIT_CONTRAST << 18) |
+                         (OVERLAY_INIT_BRIGHTNESS & 0xff);
+    backBuffer->OCLRC1 = OVERLAY_INIT_SATURATION;
+    backBuffer->DCLRKV = OVERLAY_INIT_COLORKEY;
+    backBuffer->DCLRKM = OVERLAY_INIT_COLORKEYMASK;
+    backBuffer->OCONFIG = 0;
+    backBuffer->OCONFIG |= (0x1 << 3);
+    backBuffer->OCONFIG |= (0x1 << 27);
+    backBuffer->SCHRKEN &= ~(0x7 << 24);
+    backBuffer->SCHRKEN |= 0xff;
+}
+
+BufferMapper* OverlayPlaneBase::getTTMMapper(BufferMapper& grallocMapper, struct VideoPayloadBuffer *payload)
+{
+    buffer_handle_t khandle;
+    uint32_t w, h;
+    uint32_t yStride, uvStride;
+    stride_t stride;
+    int srcX, srcY, srcW, srcH;
+    int tmp;
+
+    DataBuffer *buf;
+    ssize_t index;
+    TTMBufferMapper *mapper;
+    bool ret;
+
+    if (!payload) {
+        ETRACE("invalid payload buffer");
+        return 0;
+    }
+
+    srcX = grallocMapper.getCrop().x;
+    srcY = grallocMapper.getCrop().y;
+    srcW = grallocMapper.getCrop().w;
+    srcH = grallocMapper.getCrop().h;
+
+    // init ttm buffer
+    if (mUseScaledBuffer) {
+        khandle = payload->scaling_khandle;
+    } else {
+        khandle = payload->rotated_buffer_handle;
+    }
+    index = mTTMBuffers.indexOfKey(khandle);
+    if (index < 0) {
+        VTRACE("unmapped TTM buffer, will map it");
+
+        if (mUseScaledBuffer) {
+            w = payload->scaling_width;
+            h = payload->scaling_height;
+        } else {
+            w = payload->rotated_width;
+            h = payload->rotated_height;
+
+            checkCrop(srcX, srcY, srcW, srcH, payload->coded_width, payload->coded_height);
+        }
+
+        uint32_t format = grallocMapper.getFormat();
+        // this is for sw decode with tiled buffer in landscape mode
+        if (payload->tiling)
+            format = OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar_Tiled;
+
+        // calculate stride
+        switch (format) {
+        case HAL_PIXEL_FORMAT_YV12:
+        case HAL_PIXEL_FORMAT_I420:
+            uint32_t yStride_align;
+            yStride_align = DisplayQuery::getOverlayLumaStrideAlignment(grallocMapper.getFormat());
+            if (yStride_align > 0)
+            {
+                yStride = align_to(align_to(w, 32), yStride_align);
+            }
+            else
+            {
+                yStride = align_to(align_to(w, 32), 64);
+            }
+            uvStride = align_to(yStride >> 1, 64);
+            stride.yuv.yStride = yStride;
+            stride.yuv.uvStride = uvStride;
+            break;
+        case HAL_PIXEL_FORMAT_NV12:
+            yStride = align_to(align_to(w, 32), 64);
+            uvStride = yStride;
+            stride.yuv.yStride = yStride;
+            stride.yuv.uvStride = uvStride;
+            break;
+        case OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar:
+        case OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar_Tiled:
+            if (mUseScaledBuffer) {
+                stride.yuv.yStride = payload->scaling_luma_stride;
+                stride.yuv.uvStride = payload->scaling_chroma_u_stride;
+            } else {
+               yStride = align_to(align_to(w, 32), 64);
+               uvStride = yStride;
+               stride.yuv.yStride = yStride;
+               stride.yuv.uvStride = uvStride;
+            }
+            break;
+        case HAL_PIXEL_FORMAT_YUY2:
+        case HAL_PIXEL_FORMAT_UYVY:
+            yStride = align_to((align_to(w, 32) << 1), 64);
+            uvStride = 0;
+            stride.yuv.yStride = yStride;
+            stride.yuv.uvStride = uvStride;
+            break;
+        }
+
+        DataBuffer buf(khandle);
+        // update buffer
+        buf.setStride(stride);
+        buf.setWidth(w);
+        buf.setHeight(h);
+        buf.setCrop(srcX, srcY, srcW, srcH);
+        buf.setFormat(format);
+
+        // create buffer mapper
+        bool res = false;
+        do {
+            mapper = new TTMBufferMapper(*mWsbm, buf);
+            if (!mapper) {
+                ETRACE("failed to allocate mapper");
+                break;
+            }
+            // map ttm buffer
+            ret = mapper->map();
+            if (!ret) {
+                ETRACE("failed to map");
+                invalidateTTMBuffers();
+                ret = mapper->map();
+                if (!ret) {
+                    ETRACE("failed to remap");
+                    break;
+                }
+            }
+
+            if (mTTMBuffers.size() >= OVERLAY_DATA_BUFFER_COUNT) {
+                invalidateTTMBuffers();
+            }
+
+            // add mapper
+            index = mTTMBuffers.add(khandle, mapper);
+            if (index < 0) {
+                ETRACE("failed to add TTMMapper");
+                break;
+            }
+
+            // increase mapper refCount since it is added to mTTMBuffers
+            mapper->incRef();
+            res = true;
+        } while (0);
+
+        if (!res) {
+            // error handling
+            if (mapper) {
+                mapper->unmap();
+                delete mapper;
+                mapper = NULL;
+            }
+            return 0;
+        }
+    } else {
+        VTRACE("got mapper in saved ttm buffers");
+        mapper = reinterpret_cast<TTMBufferMapper *>(mTTMBuffers.valueAt(index));
+        if (mapper->getCrop().x != srcX || mapper->getCrop().y != srcY ||
+            mapper->getCrop().w != srcW || mapper->getCrop().h != srcH) {
+            if(!mUseScaledBuffer)
+               checkCrop(srcX, srcY, srcW, srcH, payload->coded_width, payload->coded_height);
+            mapper->setCrop(srcX, srcY, srcW, srcH);
+        }
+    }
+
+    XTRACE();
+    return mapper;
+}
+
+void OverlayPlaneBase::putTTMMapper(BufferMapper* mapper)
+{
+    if (!mapper)
+        return;
+
+    if (!mapper->decRef()) {
+        // unmap it
+        mapper->unmap();
+
+        // destroy this mapper
+        delete mapper;
+    }
+}
+
+bool OverlayPlaneBase::isActiveTTMBuffer(BufferMapper *mapper)
+{
+    for (size_t i = 0; i < mActiveTTMBuffers.size(); i++) {
+        BufferMapper *activeMapper = mActiveTTMBuffers.itemAt(i);
+        if (!activeMapper)
+            continue;
+        if (activeMapper->getKey() == mapper->getKey())
+            return true;
+    }
+
+    return false;
+}
+
+void OverlayPlaneBase::updateActiveTTMBuffers(BufferMapper *mapper)
+{
+    // unmap the first entry (oldest buffer)
+    if (mActiveTTMBuffers.size() >= MAX_ACTIVE_TTM_BUFFERS) {
+        BufferMapper *oldest = mActiveTTMBuffers.itemAt(0);
+        putTTMMapper(oldest);
+        mActiveTTMBuffers.removeAt(0);
+    }
+
+    // queue it to cached buffers
+    if (!isActiveTTMBuffer(mapper)) {
+        mapper->incRef();
+        mActiveTTMBuffers.push_back(mapper);
+    }
+}
+
+void OverlayPlaneBase::invalidateActiveTTMBuffers()
+{
+    BufferMapper* mapper;
+
+    RETURN_VOID_IF_NOT_INIT();
+
+    for (size_t i = 0; i < mActiveTTMBuffers.size(); i++) {
+        mapper = mActiveTTMBuffers.itemAt(i);
+        // unmap it
+        putTTMMapper(mapper);
+    }
+
+    // clear recorded data buffers
+    mActiveTTMBuffers.clear();
+}
+
+void OverlayPlaneBase::invalidateTTMBuffers()
+{
+    BufferMapper* mapper;
+    for (size_t i = 0; i < mTTMBuffers.size(); i++) {
+        mapper = mTTMBuffers.valueAt(i);
+        // putTTMMapper removes mapper from cache
+        putTTMMapper(mapper);
+    }
+    mTTMBuffers.clear();
+}
+
+
+bool OverlayPlaneBase::rotatedBufferReady(BufferMapper& mapper, BufferMapper* &rotatedMapper)
+{
+    struct VideoPayloadBuffer *payload;
+    uint32_t format;
+
+    // only NV12_VED has rotated buffer
+    format = mapper.getFormat();
+    if (format != OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar &&
+        format != OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar_Tiled)
+        return false;
+
+    payload = (struct VideoPayloadBuffer *)mapper.getCpuAddress(SUB_BUFFER1);
+    // check payload
+    if (!payload) {
+        ETRACE("no payload found");
+        return false;
+    }
+
+    if (payload->force_output_method == FORCE_OUTPUT_GPU)
+        return false;
+
+    if (payload->client_transform != mTransform) {
+        if (payload->surface_protected) {
+            payload->hwc_timestamp = systemTime();
+            payload->layer_transform = mTransform;
+        }
+        WTRACE("client is not ready");
+        return false;
+    }
+
+    rotatedMapper = getTTMMapper(mapper, payload);
+    return true;
+}
+
+
+bool OverlayPlaneBase::useOverlayRotation(BufferMapper& mapper)
+{
+    // by default overlay plane does not support rotation.
+    return false;
+}
+
+bool OverlayPlaneBase::scaledBufferReady(BufferMapper& mapper, BufferMapper* &scaledMapper, VideoPayloadBuffer *payload)
+{
+    return false;
+}
+
+void OverlayPlaneBase::checkPosition(int& x, int& y, int& w, int& h)
+{
+    drmModeModeInfoPtr mode = &mModeInfo;
+
+    if (mode->hdisplay == 0 || mode->vdisplay == 0)
+        return;
+
+    if (x < 0)
+        x = 0;
+    if (y < 0)
+        y = 0;
+    if ((x + w) > mode->hdisplay)
+        w = mode->hdisplay - x;
+    if ((y + h) > mode->vdisplay)
+        h = mode->vdisplay - y;
+}
+
+void OverlayPlaneBase::checkCrop(int& srcX, int& srcY, int& srcW, int& srcH,
+                               int coded_width, int coded_height)
+{
+    int tmp;
+
+    if (mTransform)
+        srcH >>= mBobDeinterlace;
+
+    if (mTransform == HWC_TRANSFORM_ROT_90 || mTransform == HWC_TRANSFORM_ROT_270) {
+        tmp = srcH;
+        srcH = srcW;
+        srcW = tmp;
+
+        tmp = srcX;
+        srcX = srcY;
+        srcY = tmp;
+
+        tmp = coded_width;
+        coded_width = coded_height;
+        coded_height = tmp;
+    }
+
+    // skip pading bytes in rotate buffer
+    switch(mTransform) {
+    case HWC_TRANSFORM_ROT_90:
+        srcX = (coded_width >> mBobDeinterlace) - srcW - srcX;
+        break;
+    case HWC_TRANSFORM_ROT_180:
+        srcX = coded_width - srcW - srcX;
+        srcY = (coded_height >> mBobDeinterlace) - srcH - srcY;
+        break;
+    case HWC_TRANSFORM_ROT_270:
+        srcY = coded_height - srcH - srcY;
+        break;
+    default:
+        break;
+    }
+}
+
+
+bool OverlayPlaneBase::bufferOffsetSetup(BufferMapper& mapper)
+{
+    CTRACE();
+
+    OverlayBackBufferBlk *backBuffer = mBackBuffer[mCurrent]->buf;
+    if (!backBuffer) {
+        ETRACE("invalid back buffer");
+        return false;
+    }
+
+    uint32_t format = mapper.getFormat();
+    uint32_t gttOffsetInBytes = (mapper.getGttOffsetInPage(0) << 12);
+    uint32_t yStride = mapper.getStride().yuv.yStride;
+    uint32_t uvStride = mapper.getStride().yuv.uvStride;
+    uint32_t w = mapper.getWidth();
+    uint32_t h = mapper.getHeight();
+    uint32_t srcX= mapper.getCrop().x;
+    uint32_t srcY= mapper.getCrop().y;
+
+    // clear original format setting
+    backBuffer->OCMD &= ~(0xf << 10);
+    backBuffer->OCMD &= ~OVERLAY_MEMORY_LAYOUT_TILED;
+
+    // Y/U/V plane must be 4k bytes aligned.
+    backBuffer->OSTART_0Y = gttOffsetInBytes;
+    if (mIsProtectedBuffer) {
+        // temporary workaround until vsync event logic is corrected.
+        // it seems that overlay buffer update and renderring can be overlapped,
+        // as such encryption bit may be cleared during HW rendering
+        backBuffer->OSTART_0Y |= 0x01;
+    }
+
+    backBuffer->OSTART_0U = gttOffsetInBytes;
+    backBuffer->OSTART_0V = gttOffsetInBytes;
+
+    backBuffer->OSTART_1Y = backBuffer->OSTART_0Y;
+    backBuffer->OSTART_1U = backBuffer->OSTART_0U;
+    backBuffer->OSTART_1V = backBuffer->OSTART_0V;
+
+    switch(format) {
+    case HAL_PIXEL_FORMAT_YV12:    // YV12
+        backBuffer->OBUF_0Y = 0;
+        backBuffer->OBUF_0V = yStride * h;
+        backBuffer->OBUF_0U = backBuffer->OBUF_0V + (uvStride * (h / 2));
+        backBuffer->OCMD |= OVERLAY_FORMAT_PLANAR_YUV420;
+        break;
+    case HAL_PIXEL_FORMAT_I420:    // I420
+        backBuffer->OBUF_0Y = 0;
+        backBuffer->OBUF_0U = yStride * h;
+        backBuffer->OBUF_0V = backBuffer->OBUF_0U + (uvStride * (h / 2));
+        backBuffer->OCMD |= OVERLAY_FORMAT_PLANAR_YUV420;
+        break;
+    case HAL_PIXEL_FORMAT_NV12:    // NV12
+        backBuffer->OBUF_0Y = 0;
+        backBuffer->OBUF_0U = yStride * h;
+        backBuffer->OBUF_0V = 0;
+        backBuffer->OCMD |= OVERLAY_FORMAT_PLANAR_NV12_2;
+        break;
+    // NOTE: this is the decoded video format, align the height to 32B
+    //as it's defined by video driver
+    case OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar:    // Intel codec NV12
+        backBuffer->OBUF_0Y = 0;
+        backBuffer->OBUF_0U = yStride * align_to(h, 32);
+        backBuffer->OBUF_0V = 0;
+        backBuffer->OCMD |= OVERLAY_FORMAT_PLANAR_NV12_2;
+        break;
+    case OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar_Tiled:  //NV12_tiled
+        backBuffer->OBUF_0Y = 0;
+        backBuffer->OBUF_0U = yStride * align_to(h, 32);
+        backBuffer->OBUF_0V = 0;
+        backBuffer->OSTART_0U += yStride * align_to(h, 32);
+        backBuffer->OSTART_0V += yStride * align_to(h, 32);
+        backBuffer->OSTART_1U = backBuffer->OSTART_0U;
+        backBuffer->OSTART_1V = backBuffer->OSTART_0V;
+        backBuffer->OTILEOFF_0Y = srcX + (srcY << 16);
+        backBuffer->OTILEOFF_1Y = backBuffer->OTILEOFF_0Y;
+        backBuffer->OTILEOFF_0U = srcX + ((srcY / 2) << 16);
+        backBuffer->OTILEOFF_1U = backBuffer->OTILEOFF_0U;
+        backBuffer->OTILEOFF_0V = backBuffer->OTILEOFF_0U;
+        backBuffer->OTILEOFF_1V = backBuffer->OTILEOFF_0U;
+        backBuffer->OCMD |= OVERLAY_FORMAT_PLANAR_NV12_2;
+        backBuffer->OCMD |= OVERLAY_MEMORY_LAYOUT_TILED;
+        break;
+    case HAL_PIXEL_FORMAT_YUY2:    // YUY2
+        backBuffer->OBUF_0Y = 0;
+        backBuffer->OBUF_0U = 0;
+        backBuffer->OBUF_0V = 0;
+        backBuffer->OCMD |= OVERLAY_FORMAT_PACKED_YUV422;
+        backBuffer->OCMD |= OVERLAY_PACKED_ORDER_YUY2;
+        break;
+    case HAL_PIXEL_FORMAT_UYVY:    // UYVY
+        backBuffer->OBUF_0Y = 0;
+        backBuffer->OBUF_0U = 0;
+        backBuffer->OBUF_0V = 0;
+        backBuffer->OCMD |= OVERLAY_FORMAT_PACKED_YUV422;
+        backBuffer->OCMD |= OVERLAY_PACKED_ORDER_UYVY;
+        break;
+    default:
+        ETRACE("unsupported format %d", format);
+        return false;
+    }
+
+    backBuffer->OBUF_0Y += srcY * yStride + srcX;
+    backBuffer->OBUF_0V += (srcY / 2) * uvStride + srcX;
+    backBuffer->OBUF_0U += (srcY / 2) * uvStride + srcX;
+    backBuffer->OBUF_1Y = backBuffer->OBUF_0Y;
+    backBuffer->OBUF_1U = backBuffer->OBUF_0U;
+    backBuffer->OBUF_1V = backBuffer->OBUF_0V;
+
+    VTRACE("done. offset (%d, %d, %d)",
+          backBuffer->OBUF_0Y,
+          backBuffer->OBUF_0U,
+          backBuffer->OBUF_0V);
+    return true;
+}
+
+uint32_t OverlayPlaneBase::calculateSWidthSW(uint32_t offset, uint32_t width)
+{
+    ATRACE("offset = %d, width = %d", offset, width);
+
+    uint32_t swidth = ((offset + width + 0x3F) >> 6) - (offset >> 6);
+
+    swidth <<= 1;
+    swidth -= 1;
+
+    return swidth;
+}
+
+bool OverlayPlaneBase::coordinateSetup(BufferMapper& mapper)
+{
+    CTRACE();
+
+    OverlayBackBufferBlk *backBuffer = mBackBuffer[mCurrent]->buf;
+    if (!backBuffer) {
+        ETRACE("invalid back buffer");
+        return false;
+    }
+
+    uint32_t swidthy = 0;
+    uint32_t swidthuv = 0;
+    uint32_t format = mapper.getFormat();
+    uint32_t width = mapper.getCrop().w;
+    uint32_t height = mapper.getCrop().h;
+    uint32_t yStride = mapper.getStride().yuv.yStride;
+    uint32_t uvStride = mapper.getStride().yuv.uvStride;
+    uint32_t offsety = backBuffer->OBUF_0Y;
+    uint32_t offsetu = backBuffer->OBUF_0U;
+
+    switch (format) {
+    case HAL_PIXEL_FORMAT_YV12:              // YV12
+    case HAL_PIXEL_FORMAT_I420:              // I420
+    case HAL_PIXEL_FORMAT_NV12:              // NV12
+    case OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar:          // NV12
+    case OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar_Tiled:    // NV12_tiled
+        break;
+    case HAL_PIXEL_FORMAT_YUY2:              // YUY2
+    case HAL_PIXEL_FORMAT_UYVY:              // UYVY
+        width <<= 1;
+        break;
+    default:
+        ETRACE("unsupported format %d", format);
+        return false;
+    }
+
+    if (width <= 0 || height <= 0) {
+        ETRACE("invalid src dim");
+        return false;
+    }
+
+    if (yStride <=0 && uvStride <= 0) {
+        ETRACE("invalid source stride");
+        return false;
+    }
+
+    backBuffer->SWIDTH = width | ((width / 2) << 16);
+    swidthy = calculateSWidthSW(offsety, width);
+    swidthuv = calculateSWidthSW(offsetu, width / 2);
+    backBuffer->SWIDTHSW = (swidthy << 2) | (swidthuv << 18);
+    backBuffer->SHEIGHT = height | ((height / 2) << 16);
+    backBuffer->OSTRIDE = (yStride & (~0x3f)) | ((uvStride & (~0x3f)) << 16);
+
+    XTRACE();
+
+    return true;
+}
+
+bool OverlayPlaneBase::setCoeffRegs(double *coeff, int mantSize,
+                                  coeffPtr pCoeff, int pos)
+{
+    int maxVal, icoeff, res;
+    int sign;
+    double c;
+
+    sign = 0;
+    maxVal = 1 << mantSize;
+    c = *coeff;
+    if (c < 0.0) {
+        sign = 1;
+        c = -c;
+    }
+
+    res = 12 - mantSize;
+    if ((icoeff = (int)(c * 4 * maxVal + 0.5)) < maxVal) {
+        pCoeff[pos].exponent = 3;
+        pCoeff[pos].mantissa = icoeff << res;
+        *coeff = (double)icoeff / (double)(4 * maxVal);
+    } else if ((icoeff = (int)(c * 2 * maxVal + 0.5)) < maxVal) {
+        pCoeff[pos].exponent = 2;
+        pCoeff[pos].mantissa = icoeff << res;
+        *coeff = (double)icoeff / (double)(2 * maxVal);
+    } else if ((icoeff = (int)(c * maxVal + 0.5)) < maxVal) {
+        pCoeff[pos].exponent = 1;
+        pCoeff[pos].mantissa = icoeff << res;
+        *coeff = (double)icoeff / (double)(maxVal);
+    } else if ((icoeff = (int)(c * maxVal * 0.5 + 0.5)) < maxVal) {
+        pCoeff[pos].exponent = 0;
+        pCoeff[pos].mantissa = icoeff << res;
+        *coeff = (double)icoeff / (double)(maxVal / 2);
+    } else {
+        // Coeff out of range
+        return false;
+    }
+
+    pCoeff[pos].sign = sign;
+    if (sign)
+        *coeff = -(*coeff);
+    return true;
+}
+
+void OverlayPlaneBase::updateCoeff(int taps, double fCutoff,
+                                 bool isHoriz, bool isY,
+                                 coeffPtr pCoeff)
+{
+    int i, j, j1, num, pos, mantSize;
+    double pi = 3.1415926535, val, sinc, window, sum;
+    double rawCoeff[MAX_TAPS * 32], coeffs[N_PHASES][MAX_TAPS];
+    double diff;
+    int tapAdjust[MAX_TAPS], tap2Fix;
+    bool isVertAndUV;
+
+    if (isHoriz)
+        mantSize = 7;
+    else
+        mantSize = 6;
+
+    isVertAndUV = !isHoriz && !isY;
+    num = taps * 16;
+    for (i = 0; i < num  * 2; i++) {
+        val = (1.0 / fCutoff) * taps * pi * (i - num) / (2 * num);
+        if (val == 0.0)
+            sinc = 1.0;
+        else
+            sinc = sin(val) / val;
+
+        // Hamming window
+        window = (0.54 - 0.46 * cos(2 * i * pi / (2 * num - 1)));
+        rawCoeff[i] = sinc * window;
+    }
+
+    for (i = 0; i < N_PHASES; i++) {
+        // Normalise the coefficients
+        sum = 0.0;
+        for (j = 0; j < taps; j++) {
+            pos = i + j * 32;
+            sum += rawCoeff[pos];
+        }
+        for (j = 0; j < taps; j++) {
+            pos = i + j * 32;
+            coeffs[i][j] = rawCoeff[pos] / sum;
+        }
+
+        // Set the register values
+        for (j = 0; j < taps; j++) {
+            pos = j + i * taps;
+            if ((j == (taps - 1) / 2) && !isVertAndUV)
+                setCoeffRegs(&coeffs[i][j], mantSize + 2, pCoeff, pos);
+            else
+                setCoeffRegs(&coeffs[i][j], mantSize, pCoeff, pos);
+        }
+
+        tapAdjust[0] = (taps - 1) / 2;
+        for (j = 1, j1 = 1; j <= tapAdjust[0]; j++, j1++) {
+            tapAdjust[j1] = tapAdjust[0] - j;
+            tapAdjust[++j1] = tapAdjust[0] + j;
+        }
+
+        // Adjust the coefficients
+        sum = 0.0;
+        for (j = 0; j < taps; j++)
+            sum += coeffs[i][j];
+        if (sum != 1.0) {
+            for (j1 = 0; j1 < taps; j1++) {
+                tap2Fix = tapAdjust[j1];
+                diff = 1.0 - sum;
+                coeffs[i][tap2Fix] += diff;
+                pos = tap2Fix + i * taps;
+                if ((tap2Fix == (taps - 1) / 2) && !isVertAndUV)
+                    setCoeffRegs(&coeffs[i][tap2Fix], mantSize + 2, pCoeff, pos);
+                else
+                    setCoeffRegs(&coeffs[i][tap2Fix], mantSize, pCoeff, pos);
+
+                sum = 0.0;
+                for (j = 0; j < taps; j++)
+                    sum += coeffs[i][j];
+                if (sum == 1.0)
+                    break;
+            }
+        }
+    }
+}
+
+bool OverlayPlaneBase::scalingSetup(BufferMapper& mapper)
+{
+    int xscaleInt, xscaleFract, yscaleInt, yscaleFract;
+    int xscaleIntUV, xscaleFractUV;
+    int yscaleIntUV, yscaleFractUV;
+    int deinterlace_factor = 1;
+    // UV is half the size of Y -- YUV420
+    int uvratio = 2;
+    uint32_t newval;
+    coeffRec xcoeffY[N_HORIZ_Y_TAPS * N_PHASES];
+    coeffRec xcoeffUV[N_HORIZ_UV_TAPS * N_PHASES];
+    int i, j, pos;
+    bool scaleChanged = false;
+    int x, y, w, h;
+
+    OverlayBackBufferBlk *backBuffer = mBackBuffer[mCurrent]->buf;
+    if (!backBuffer) {
+        ETRACE("invalid back buffer");
+        return false;
+    }
+
+    x = mPosition.x;
+    y = mPosition.y;
+    w = mPosition.w;
+    h = mPosition.h;
+
+    // check position
+    checkPosition(x, y, w, h);
+    VTRACE("final position (%d, %d, %d, %d)", x, y, w, h);
+
+    if ((w <= 0) || (h <= 0)) {
+         ETRACE("invalid dst width/height");
+         return false;
+    }
+
+    // setup dst position
+    backBuffer->DWINPOS = (y << 16) | x;
+    backBuffer->DWINSZ = (h << 16) | w;
+
+    uint32_t srcWidth = mapper.getCrop().w;
+    uint32_t srcHeight = mapper.getCrop().h;
+    uint32_t dstWidth = w;
+    uint32_t dstHeight = h;
+
+    if (mBobDeinterlace && !mTransform)
+        deinterlace_factor = 2;
+
+    VTRACE("src (%dx%d), dst (%dx%d)",
+          srcWidth, srcHeight,
+          dstWidth, dstHeight);
+
+     // Y down-scale factor as a multiple of 4096
+    if (srcWidth == dstWidth && srcHeight == dstHeight) {
+        xscaleFract = (1 << 12);
+        yscaleFract = (1 << 12)/deinterlace_factor;
+    } else {
+        xscaleFract = ((srcWidth - 1) << 12) / dstWidth;
+        yscaleFract = ((srcHeight - 1) << 12) / (dstHeight * deinterlace_factor);
+    }
+
+    // Calculate the UV scaling factor
+    xscaleFractUV = xscaleFract / uvratio;
+    yscaleFractUV = yscaleFract / uvratio;
+
+    // To keep the relative Y and UV ratios exact, round the Y scales
+    // to a multiple of the Y/UV ratio.
+    xscaleFract = xscaleFractUV * uvratio;
+    yscaleFract = yscaleFractUV * uvratio;
+
+    // Integer (un-multiplied) values
+    xscaleInt = xscaleFract >> 12;
+    yscaleInt = yscaleFract >> 12;
+
+    xscaleIntUV = xscaleFractUV >> 12;
+    yscaleIntUV = yscaleFractUV >> 12;
+
+    // Check scaling ratio
+    if (xscaleInt > INTEL_OVERLAY_MAX_SCALING_RATIO) {
+        ETRACE("xscaleInt > %d", INTEL_OVERLAY_MAX_SCALING_RATIO);
+        return false;
+    }
+
+    // shouldn't get here
+    if (xscaleIntUV > INTEL_OVERLAY_MAX_SCALING_RATIO) {
+        ETRACE("xscaleIntUV > %d", INTEL_OVERLAY_MAX_SCALING_RATIO);
+        return false;
+    }
+
+    newval = (xscaleInt << 15) |
+    ((xscaleFract & 0xFFF) << 3) | ((yscaleFract & 0xFFF) << 20);
+    if (newval != backBuffer->YRGBSCALE) {
+        scaleChanged = true;
+        backBuffer->YRGBSCALE = newval;
+    }
+
+    newval = (xscaleIntUV << 15) | ((xscaleFractUV & 0xFFF) << 3) |
+    ((yscaleFractUV & 0xFFF) << 20);
+    if (newval != backBuffer->UVSCALE) {
+        scaleChanged = true;
+        backBuffer->UVSCALE = newval;
+    }
+
+    newval = yscaleInt << 16 | yscaleIntUV;
+    if (newval != backBuffer->UVSCALEV) {
+        scaleChanged = true;
+        backBuffer->UVSCALEV = newval;
+    }
+
+    // Recalculate coefficients if the scaling changed
+    // Only Horizontal coefficients so far.
+    if (scaleChanged) {
+        double fCutoffY;
+        double fCutoffUV;
+
+        fCutoffY = xscaleFract / 4096.0;
+        fCutoffUV = xscaleFractUV / 4096.0;
+
+        // Limit to between 1.0 and 3.0
+        if (fCutoffY < MIN_CUTOFF_FREQ)
+            fCutoffY = MIN_CUTOFF_FREQ;
+        if (fCutoffY > MAX_CUTOFF_FREQ)
+            fCutoffY = MAX_CUTOFF_FREQ;
+        if (fCutoffUV < MIN_CUTOFF_FREQ)
+            fCutoffUV = MIN_CUTOFF_FREQ;
+        if (fCutoffUV > MAX_CUTOFF_FREQ)
+            fCutoffUV = MAX_CUTOFF_FREQ;
+
+        updateCoeff(N_HORIZ_Y_TAPS, fCutoffY, true, true, xcoeffY);
+        updateCoeff(N_HORIZ_UV_TAPS, fCutoffUV, true, false, xcoeffUV);
+
+        for (i = 0; i < N_PHASES; i++) {
+            for (j = 0; j < N_HORIZ_Y_TAPS; j++) {
+                pos = i * N_HORIZ_Y_TAPS + j;
+                backBuffer->Y_HCOEFS[pos] =
+                        (xcoeffY[pos].sign << 15 |
+                         xcoeffY[pos].exponent << 12 |
+                         xcoeffY[pos].mantissa);
+            }
+        }
+        for (i = 0; i < N_PHASES; i++) {
+            for (j = 0; j < N_HORIZ_UV_TAPS; j++) {
+                pos = i * N_HORIZ_UV_TAPS + j;
+                backBuffer->UV_HCOEFS[pos] =
+                         (xcoeffUV[pos].sign << 15 |
+                          xcoeffUV[pos].exponent << 12 |
+                          xcoeffUV[pos].mantissa);
+            }
+        }
+    }
+
+    XTRACE();
+    return true;
+}
+
+bool OverlayPlaneBase::colorSetup(BufferMapper& mapper)
+{
+    CTRACE();
+
+    OverlayBackBufferBlk *backBuffer = mBackBuffer[mCurrent]->buf;
+    if (!backBuffer) {
+        ETRACE("invalid back buffer");
+        return false;
+    }
+
+    uint32_t format = mapper.getFormat();
+    if (format != OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar &&
+        format != OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar_Tiled) {
+
+        VTRACE("Not video layer, use default color setting");
+        backBuffer->OCLRC0 = (OVERLAY_INIT_CONTRAST << 18) |
+                         (OVERLAY_INIT_BRIGHTNESS & 0xff);
+        backBuffer->OCLRC1 = OVERLAY_INIT_SATURATION;
+        backBuffer->OCONFIG &= ~(1 << 5);
+
+        return true;
+    }
+
+    struct VideoPayloadBuffer *payload;
+    payload = (struct VideoPayloadBuffer *)mapper.getCpuAddress(SUB_BUFFER1);
+    // check payload
+    if (!payload) {
+        ETRACE("no payload found");
+        return false;
+    }
+
+    // BT.601 or BT.709
+    backBuffer->OCONFIG &= ~(1 << 5);
+    backBuffer->OCONFIG |= ((payload->csc_mode & 1) << 5);
+
+    // no level expansion for video on HDMI
+    if (payload->video_range || mPipeConfig == (0x2 << 6)) {
+        // full range, no need to do level expansion
+        backBuffer->OCLRC0 = 0x1000000;
+        backBuffer->OCLRC1 = 0x80;
+    } else {
+        // level expansion for limited range
+        backBuffer->OCLRC0 = (OVERLAY_INIT_CONTRAST << 18) |
+                         (OVERLAY_INIT_BRIGHTNESS & 0xff);
+        backBuffer->OCLRC1 = OVERLAY_INIT_SATURATION;
+    }
+
+    return true;
+}
+
+bool OverlayPlaneBase::setDataBuffer(BufferMapper& grallocMapper)
+{
+    BufferMapper *mapper;
+    BufferMapper *videoBufferMapper = 0;
+    bool ret;
+    uint32_t format;
+
+    RETURN_FALSE_IF_NOT_INIT();
+
+    // get gralloc mapper
+    mapper = &grallocMapper;
+    format = grallocMapper.getFormat();
+    if (format == OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar ||
+        format == OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar_Tiled) {
+        struct VideoPayloadBuffer *payload;
+        payload = (struct VideoPayloadBuffer *)grallocMapper.getCpuAddress(SUB_BUFFER1);
+        if (!payload) {
+            ETRACE("invalid payload buffer");
+            return 0;
+        }
+
+        mBobDeinterlace = payload->bob_deinterlace;
+
+        int srcW, srcH;
+        srcW = grallocMapper.getCrop().w - grallocMapper.getCrop().x;
+        srcH = grallocMapper.getCrop().h - grallocMapper.getCrop().y;
+        if ((srcW > INTEL_OVERLAY_MAX_WIDTH - 1) || (srcH > INTEL_OVERLAY_MAX_HEIGHT - 1)) {
+            if (mTransform) {
+                int x, y, w, h;
+                x = mSrcCrop.x;
+                y = mSrcCrop.y;
+                w = mSrcCrop.w;
+                h = mSrcCrop.h;
+                setSourceCrop(0, 0, payload->scaling_width, payload->scaling_height);
+                if (!useOverlayRotation(grallocMapper)) {
+                    DTRACE("The scaled buffer will hit overlay rotation limitation, fall back to GLES");
+                    setSourceCrop(x, y, w, h);
+                    return false;
+                }
+            }
+
+            if (!scaledBufferReady(grallocMapper, videoBufferMapper, payload)) {
+                DTRACE("scaled buffer is not ready, fall back to GLES");
+                return false;
+            } else {
+                videoBufferMapper->setFormat(OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar);
+                mapper = videoBufferMapper;
+            }
+        }
+    }
+
+    if (!mUseScaledBuffer && mTransform && !useOverlayRotation(grallocMapper)) {
+        if (!rotatedBufferReady(grallocMapper, videoBufferMapper)) {
+            DTRACE("rotated buffer is not ready");
+            return false;
+        }
+
+        if (!videoBufferMapper) {
+            ETRACE("failed to get rotated buffer");
+            return false;
+        }
+        mapper = videoBufferMapper;
+    }
+
+    OverlayBackBufferBlk *backBuffer = mBackBuffer[mCurrent]->buf;
+    if (!backBuffer) {
+        ETRACE("invalid back buffer");
+        return false;
+    }
+
+    ret = bufferOffsetSetup(*mapper);
+    if (ret == false) {
+        ETRACE("failed to set up buffer offsets");
+        return false;
+    }
+
+    ret = coordinateSetup(*mapper);
+    if (ret == false) {
+        ETRACE("failed to set up overlay coordinates");
+        return false;
+    }
+
+    ret = scalingSetup(*mapper);
+    if (ret == false) {
+        ETRACE("failed to set up scaling parameters");
+        return false;
+    }
+
+    backBuffer->OCMD |= 0x1;
+
+    ret = colorSetup(grallocMapper);
+    if (ret == false) {
+        ETRACE("failed to set up color parameters");
+        return false;
+    }
+    if (mBobDeinterlace && !mTransform) {
+        backBuffer->OCMD |= BUF_TYPE_FIELD;
+        backBuffer->OCMD &= ~FIELD_SELECT;
+        backBuffer->OCMD |= FIELD0;
+        backBuffer->OCMD &= ~(BUFFER_SELECT);
+        backBuffer->OCMD |= BUFFER0;
+    }
+
+    // add to active ttm buffers if it's a rotated buffer
+    if (videoBufferMapper) {
+        updateActiveTTMBuffers(mapper);
+    }
+
+    mUseScaledBuffer = 0;
+    return true;
+}
+
+} // namespace intel
+} // namespace android
+
diff --git a/merrifield/ips/common/OverlayPlaneBase.h b/merrifield/ips/common/OverlayPlaneBase.h
new file mode 100644
index 0000000..fc76a61
--- /dev/null
+++ b/merrifield/ips/common/OverlayPlaneBase.h
@@ -0,0 +1,129 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef OVERLAY_PLANE_BASE_H
+#define OVERLAY_PLANE_BASE_H
+
+#include <utils/KeyedVector.h>
+#include <hal_public.h>
+#include <DisplayPlane.h>
+#include <BufferMapper.h>
+#include <common/Wsbm.h>
+#include <common/OverlayHardware.h>
+#include <common/VideoPayloadBuffer.h>
+
+namespace android {
+namespace intel {
+
+typedef struct {
+    OverlayBackBufferBlk *buf;
+    uint32_t gttOffsetInPage;
+    void* bufObject;
+} OverlayBackBuffer;
+
+class OverlayPlaneBase : public DisplayPlane {
+public:
+    OverlayPlaneBase(int index, int disp);
+    virtual ~OverlayPlaneBase();
+
+    virtual void invalidateBufferCache();
+
+    virtual bool assignToDevice(int disp);
+
+    virtual void setZOrderConfig(ZOrderConfig& config, void *nativeConfig);
+
+    // plane operations
+    virtual bool flip(void *ctx) = 0;
+    virtual bool reset();
+    virtual bool enable();
+    virtual bool disable();
+    virtual bool isDisabled();
+
+    virtual void* getContext() const = 0;
+    virtual bool initialize(uint32_t bufferCount);
+    virtual void deinitialize();
+
+protected:
+    // generic overlay register flush
+    virtual bool flush(uint32_t flags) = 0;
+    virtual bool setDataBuffer(BufferMapper& mapper);
+    virtual bool bufferOffsetSetup(BufferMapper& mapper);
+    virtual uint32_t calculateSWidthSW(uint32_t offset, uint32_t width);
+    virtual bool coordinateSetup(BufferMapper& mapper);
+    virtual bool setCoeffRegs(double *coeff, int mantSize,
+                                 coeffPtr pCoeff, int pos);
+    virtual void updateCoeff(int taps, double fCutoff,
+                                bool isHoriz, bool isY,
+                                coeffPtr pCoeff);
+    virtual bool scalingSetup(BufferMapper& mapper);
+    virtual bool colorSetup(BufferMapper& mapper);
+    virtual void checkPosition(int& x, int& y, int& w, int& h);
+    virtual void checkCrop(int& x, int& y, int& w, int& h, int coded_width, int coded_height);
+
+
+protected:
+    // back buffer operations
+    virtual OverlayBackBuffer* createBackBuffer();
+    virtual void deleteBackBuffer(int buf);
+    virtual void resetBackBuffer(int buf);
+
+    virtual BufferMapper* getTTMMapper(BufferMapper& grallocMapper, struct VideoPayloadBuffer *payload);
+    virtual void  putTTMMapper(BufferMapper* mapper);
+    virtual bool rotatedBufferReady(BufferMapper& mapper, BufferMapper* &rotatedMapper);
+    virtual bool useOverlayRotation(BufferMapper& mapper);
+    virtual bool scaledBufferReady(BufferMapper& mapper, BufferMapper* &scaledMapper, VideoPayloadBuffer *payload);
+
+private:
+    inline bool isActiveTTMBuffer(BufferMapper *mapper);
+    void updateActiveTTMBuffers(BufferMapper *mapper);
+    void invalidateActiveTTMBuffers();
+    void invalidateTTMBuffers();
+
+protected:
+    // flush flags
+    enum {
+        PLANE_ENABLE     = 0x00000001UL,
+        PLANE_DISABLE    = 0x00000002UL,
+        UPDATE_COEF      = 0x00000004UL,
+    };
+
+    enum {
+        OVERLAY_BACK_BUFFER_COUNT = 3,
+        MAX_ACTIVE_TTM_BUFFERS = 3,
+        OVERLAY_DATA_BUFFER_COUNT = 20,
+    };
+
+    // TTM data buffers
+    KeyedVector<buffer_handle_t, BufferMapper*> mTTMBuffers;
+    // latest TTM buffers
+    Vector<BufferMapper*> mActiveTTMBuffers;
+
+    // overlay back buffer
+    OverlayBackBuffer *mBackBuffer[OVERLAY_BACK_BUFFER_COUNT];
+    int mCurrent;
+    // wsbm
+    Wsbm *mWsbm;
+    // pipe config
+    uint32_t mPipeConfig;
+
+    int mBobDeinterlace;
+    int mUseScaledBuffer;
+};
+
+} // namespace intel
+} // namespace android
+
+#endif /* OVERLAY_PLANE_BASE_H */
+
diff --git a/merrifield/ips/common/PixelFormat.cpp b/merrifield/ips/common/PixelFormat.cpp
new file mode 100644
index 0000000..758788c
--- /dev/null
+++ b/merrifield/ips/common/PixelFormat.cpp
@@ -0,0 +1,55 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#include <hal_public.h>
+#include <HwcTrace.h>
+#include <common/PixelFormat.h>
+
+namespace android {
+namespace intel {
+
+bool PixelFormat::convertFormat(uint32_t grallocFormat, uint32_t& spriteFormat, int& bpp)
+{
+    switch (grallocFormat) {
+    case HAL_PIXEL_FORMAT_RGBA_8888:
+        spriteFormat = PLANE_PIXEL_FORMAT_RGBA8888;
+        bpp = 4;
+        break;
+    case HAL_PIXEL_FORMAT_RGBX_8888:
+        spriteFormat = PLANE_PIXEL_FORMAT_RGBX8888;
+        bpp = 4;
+        break;
+    case HAL_PIXEL_FORMAT_BGRX_8888:
+        spriteFormat = PLANE_PIXEL_FORMAT_BGRX8888;
+        bpp = 4;
+        break;
+    case HAL_PIXEL_FORMAT_BGRA_8888:
+        spriteFormat = PLANE_PIXEL_FORMAT_BGRA8888;
+        bpp = 4;
+        break;
+    case HAL_PIXEL_FORMAT_RGB_565:
+        spriteFormat = PLANE_PIXEL_FORMAT_BGRX565;
+        bpp = 2;
+        break;
+    default:
+        return false;
+    }
+
+    return true;
+}
+
+
+} // namespace intel
+} // namespace android
diff --git a/merrifield/ips/common/PixelFormat.h b/merrifield/ips/common/PixelFormat.h
new file mode 100644
index 0000000..cea69e0
--- /dev/null
+++ b/merrifield/ips/common/PixelFormat.h
@@ -0,0 +1,41 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef PIXEL_FORMAT_H
+#define PIXEL_FORMAT_H
+
+namespace android {
+namespace intel {
+
+class PixelFormat
+{
+public:
+    enum {
+        PLANE_PIXEL_FORMAT_BGRX565  = 0x14000000UL,
+        PLANE_PIXEL_FORMAT_BGRX8888 = 0x18000000UL,
+        PLANE_PIXEL_FORMAT_BGRA8888 = 0x1c000000UL,
+        PLANE_PIXEL_FORMAT_RGBX8888 = 0x38000000UL,
+        PLANE_PIXEL_FORMAT_RGBA8888 = 0x3c000000UL,
+    };
+
+    // convert gralloc color format to IP specific sprite pixel format.
+    // See DSPACNTR (Display A Primary Sprite Control Register for more information)
+    static bool convertFormat(uint32_t grallocFormat, uint32_t& spriteFormat, int& bpp);
+};
+
+} // namespace intel
+} // namespace android
+
+#endif /*PIXEL_FORMAT_H*/
diff --git a/merrifield/ips/common/PlaneCapabilities.cpp b/merrifield/ips/common/PlaneCapabilities.cpp
new file mode 100644
index 0000000..973c535
--- /dev/null
+++ b/merrifield/ips/common/PlaneCapabilities.cpp
@@ -0,0 +1,234 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#include <HwcTrace.h>
+#include <DisplayPlane.h>
+#include <hal_public.h>
+#include <OMX_IVCommon.h>
+#include <OMX_IntelVideoExt.h>
+#include <PlaneCapabilities.h>
+#include "OverlayHardware.h"
+#include <HwcLayer.h>
+
+#define SPRITE_PLANE_MAX_STRIDE_TILED      16384
+//FIXME: need confirmation about this stride
+#define SPRITE_PLANE_MAX_STRIDE_LINEAR     8192
+
+#define OVERLAY_PLANE_MAX_STRIDE_PACKED    4096
+#define OVERLAY_PLANE_MAX_STRIDE_LINEAR    8192
+
+namespace android {
+namespace intel {
+
+bool PlaneCapabilities::isFormatSupported(int planeType, HwcLayer *hwcLayer)
+{
+    uint32_t format = hwcLayer->getFormat();
+    uint32_t trans = hwcLayer->getLayer()->transform;
+
+    if (planeType == DisplayPlane::PLANE_SPRITE || planeType == DisplayPlane::PLANE_PRIMARY) {
+        switch (format) {
+        case HAL_PIXEL_FORMAT_BGRA_8888:
+        case HAL_PIXEL_FORMAT_BGRX_8888:
+        case HAL_PIXEL_FORMAT_RGBA_8888:
+        case HAL_PIXEL_FORMAT_RGBX_8888:
+        case HAL_PIXEL_FORMAT_RGB_565:
+            return trans ? false : true;
+        default:
+            VTRACE("unsupported format %#x", format);
+            return false;
+        }
+    } else if (planeType == DisplayPlane::PLANE_OVERLAY) {
+        switch (format) {
+        case HAL_PIXEL_FORMAT_I420:
+        case HAL_PIXEL_FORMAT_YUY2:
+        case HAL_PIXEL_FORMAT_UYVY:
+            // TODO: overlay supports 180 degree rotation
+            if (trans == HAL_TRANSFORM_ROT_180) {
+                WTRACE("180 degree rotation is not supported yet");
+            }
+            return trans ? false : true;
+        case HAL_PIXEL_FORMAT_YV12:
+            return trans ? false: true;
+        case HAL_PIXEL_FORMAT_NV12:
+        case OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar:
+        case OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar_Tiled:
+            return true;
+        default:
+            VTRACE("unsupported format %#x", format);
+            return false;
+        }
+    } else {
+        ETRACE("invalid plane type %d", planeType);
+        return false;
+    }
+}
+
+bool PlaneCapabilities::isSizeSupported(int planeType, HwcLayer *hwcLayer)
+{
+    uint32_t format = hwcLayer->getFormat();
+    uint32_t w = hwcLayer->getBufferWidth();
+    uint32_t h = hwcLayer->getBufferHeight();
+    const stride_t& stride = hwcLayer->getBufferStride();
+
+    bool isYUVPacked;
+    uint32_t maxStride;
+
+    if (planeType == DisplayPlane::PLANE_SPRITE || planeType == DisplayPlane::PLANE_PRIMARY) {
+        switch (format) {
+        case HAL_PIXEL_FORMAT_BGRA_8888:
+        case HAL_PIXEL_FORMAT_BGRX_8888:
+        case HAL_PIXEL_FORMAT_RGBA_8888:
+        case HAL_PIXEL_FORMAT_RGBX_8888:
+        case HAL_PIXEL_FORMAT_RGB_565:
+            if (stride.rgb.stride > SPRITE_PLANE_MAX_STRIDE_LINEAR) {
+                VTRACE("too large stride %d", stride.rgb.stride);
+                return false;
+            }
+            return true;
+        default:
+            VTRACE("unsupported format %#x", format);
+            return false;
+        }
+    } else if (planeType == DisplayPlane::PLANE_OVERLAY) {
+        switch (format) {
+        case HAL_PIXEL_FORMAT_YV12:
+        case HAL_PIXEL_FORMAT_I420:
+        case HAL_PIXEL_FORMAT_NV12:
+        case OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar:
+        case OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar_Tiled:
+            isYUVPacked = false;
+            break;
+        case HAL_PIXEL_FORMAT_YUY2:
+        case HAL_PIXEL_FORMAT_UYVY:
+            isYUVPacked = true;
+            break;
+        default:
+            VTRACE("unsupported format %#x", format);
+            return false;
+        }
+        // don't use overlay plane if stride is too big
+        maxStride = OVERLAY_PLANE_MAX_STRIDE_LINEAR;
+        if (isYUVPacked) {
+            maxStride = OVERLAY_PLANE_MAX_STRIDE_PACKED;
+        }
+
+        if (stride.yuv.yStride > maxStride) {
+            VTRACE("stride %d is too large", stride.yuv.yStride);
+            return false;
+        }
+        return true;
+    } else {
+        ETRACE("invalid plane type %d", planeType);
+        return false;
+    }
+}
+
+bool PlaneCapabilities::isBlendingSupported(int planeType, HwcLayer *hwcLayer)
+{
+    uint32_t blending = (uint32_t)hwcLayer->getLayer()->blending;
+    uint8_t planeAlpha = hwcLayer->getLayer()->planeAlpha;
+
+    if (planeType == DisplayPlane::PLANE_SPRITE || planeType == DisplayPlane::PLANE_PRIMARY) {
+        bool ret = false;
+
+        // support premultipled & none blanding
+        switch (blending) {
+        case HWC_BLENDING_NONE:
+            return true;
+        case HWC_BLENDING_PREMULT:
+            ret = false;
+            if ((planeAlpha == 0) || (planeAlpha == 255)) {
+                ret = true;
+            }
+            return ret;
+        default:
+            VTRACE("unsupported blending %#x", blending);
+            return false;
+        }
+    } else if (planeType == DisplayPlane::PLANE_OVERLAY) {
+        // overlay doesn't support blending
+        return (blending == HWC_BLENDING_NONE) ? true : false;
+    } else {
+        ETRACE("invalid plane type %d", planeType);
+        return false;
+    }
+}
+
+
+bool PlaneCapabilities::isScalingSupported(int planeType, HwcLayer *hwcLayer)
+{
+    hwc_frect_t& src = hwcLayer->getLayer()->sourceCropf;
+    hwc_rect_t& dest = hwcLayer->getLayer()->displayFrame;
+
+    int srcW, srcH;
+    int dstW, dstH;
+
+    srcW = (int)src.right - (int)src.left;
+    srcH = (int)src.bottom - (int)src.top;
+    dstW = dest.right - dest.left;
+    dstH = dest.bottom - dest.top;
+
+    if (planeType == DisplayPlane::PLANE_SPRITE || planeType == DisplayPlane::PLANE_PRIMARY) {
+        // no scaling is supported
+        return ((srcW == dstW) && (srcH == dstH)) ? true : false;
+
+    } else if (planeType == DisplayPlane::PLANE_OVERLAY) {
+        // overlay cannot support resolution that bigger than 2047x2047.
+        if ((srcW > INTEL_OVERLAY_MAX_WIDTH - 1) || (srcH > INTEL_OVERLAY_MAX_HEIGHT - 1)) {
+            return false;
+        }
+
+        if (dstW <= 1 || dstH <= 1 || srcW <= 1 || srcH <= 1) {
+            // Workaround: Overlay flip when height is 1 causes MIPI stall on TNG
+            return false;
+        }
+
+        return true;
+    } else if (planeType == DisplayPlane::PLANE_CURSOR) {
+        if (srcW > 256 || srcH > 256) {
+            return false;
+        }
+        return true;
+    } else {
+        ETRACE("invalid plane type %d", planeType);
+        return false;
+    }
+}
+
+bool PlaneCapabilities::isTransformSupported(int planeType, HwcLayer *hwcLayer)
+{
+    uint32_t trans = hwcLayer->getLayer()->transform;
+
+    if (planeType == DisplayPlane::PLANE_OVERLAY) {
+        // overlay does not support FLIP_H/FLIP_V
+        switch (trans) {
+        case 0:
+        case HAL_TRANSFORM_ROT_90:
+        case HAL_TRANSFORM_ROT_180:
+        case HAL_TRANSFORM_ROT_270:
+            return true;
+        default:
+            return false;
+        }
+    }
+
+    // don't transform any tranform
+    return trans ? false : true;
+}
+
+} // namespace intel
+} // namespace android
+
diff --git a/merrifield/ips/common/PrepareListener.cpp b/merrifield/ips/common/PrepareListener.cpp
new file mode 100644
index 0000000..0b4b05d
--- /dev/null
+++ b/merrifield/ips/common/PrepareListener.cpp
@@ -0,0 +1,50 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#include <HwcTrace.h>
+#include <Drm.h>
+#include <Hwcomposer.h>
+#include <common/PrepareListener.h>
+
+namespace android {
+namespace intel {
+
+PrepareListener::PrepareListener()
+    : IPrepareListener()
+{
+}
+
+PrepareListener::~PrepareListener()
+{
+}
+
+void PrepareListener::onProtectedLayerStart(int disp)
+{
+    WTRACE("disp = %d, ignored for now", disp);
+    // need chaabi support for granular IED control
+    return;
+
+    Drm *drm = Hwcomposer::getInstance().getDrm();
+    int ret = drmCommandNone(drm->getDrmFd(), DRM_PSB_HDCP_DISPLAY_IED_ON);
+    if (ret != 0) {
+        ETRACE("failed to turn on display IED");
+    } else {
+        ITRACE("display IED is turned on");
+    }
+}
+
+} // namespace intel
+} // namespace android
diff --git a/merrifield/ips/common/PrepareListener.h b/merrifield/ips/common/PrepareListener.h
new file mode 100644
index 0000000..e048b92
--- /dev/null
+++ b/merrifield/ips/common/PrepareListener.h
@@ -0,0 +1,35 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef PREPARE_LISTENER_H
+#define PREPARE_LISTENER_H
+
+#include <IPrepareListener.h>
+
+namespace android {
+namespace intel {
+
+class PrepareListener : public IPrepareListener {
+public:
+    PrepareListener();
+    virtual ~PrepareListener();
+public:
+    virtual void onProtectedLayerStart(int disp);
+};
+
+} // namespace intel
+} // namespace android
+
+#endif /* PREPARE_LISTENER_H */
diff --git a/merrifield/ips/common/RotationBufferProvider.cpp b/merrifield/ips/common/RotationBufferProvider.cpp
new file mode 100644
index 0000000..65a4db8
--- /dev/null
+++ b/merrifield/ips/common/RotationBufferProvider.cpp
@@ -0,0 +1,637 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#include <HwcTrace.h>
+#include <common/RotationBufferProvider.h>
+
+namespace android {
+namespace intel {
+
+#define CHECK_VA_STATUS_RETURN(FUNC) \
+if (vaStatus != VA_STATUS_SUCCESS) {\
+    ETRACE(FUNC" failed. vaStatus = %#x", vaStatus);\
+    return false;\
+}
+
+#define CHECK_VA_STATUS_BREAK(FUNC) \
+if (vaStatus != VA_STATUS_SUCCESS) {\
+    ETRACE(FUNC" failed. vaStatus = %#x", vaStatus);\
+    break;\
+}
+
+// With this display value, VA will hook VED driver insead of VSP driver for buffer rotation
+#define DISPLAYVALUE  0x56454450
+
+RotationBufferProvider::RotationBufferProvider(Wsbm* wsbm)
+    : mWsbm(wsbm),
+      mVaInitialized(false),
+      mVaDpy(0),
+      mVaCfg(0),
+      mVaCtx(0),
+      mVaBufFilter(0),
+      mSourceSurface(0),
+      mDisplay(DISPLAYVALUE),
+      mWidth(0),
+      mHeight(0),
+      mTransform(0),
+      mRotatedWidth(0),
+      mRotatedHeight(0),
+      mRotatedStride(0),
+      mTargetIndex(0),
+      mTTMWrappers(),
+      mBobDeinterlace(0)
+{
+    for (int i = 0; i < MAX_SURFACE_NUM; i++) {
+        mKhandles[i] = 0;
+        mRotatedSurfaces[i] = 0;
+        mDrmBuf[i] = NULL;
+    }
+}
+
+RotationBufferProvider::~RotationBufferProvider()
+{
+}
+
+uint32_t RotationBufferProvider::getMilliseconds()
+{
+    struct timeval ptimeval;
+    gettimeofday(&ptimeval, NULL);
+    return (uint32_t)((ptimeval.tv_sec * 1000) + (ptimeval.tv_usec / 1000));
+}
+
+bool RotationBufferProvider::initialize()
+{
+    if (NULL == mWsbm)
+        return false;
+    mTTMWrappers.setCapacity(TTM_WRAPPER_COUNT);
+    return true;
+}
+
+void RotationBufferProvider::deinitialize()
+{
+    stopVA();
+    reset();
+}
+
+void RotationBufferProvider::reset()
+{
+    if (mTTMWrappers.size()) {
+        invalidateCaches();
+    }
+}
+
+void RotationBufferProvider::invalidateCaches()
+{
+    void *buf;
+
+    for (size_t i = 0; i < mTTMWrappers.size(); i++) {
+        buf = mTTMWrappers.valueAt(i);
+        if (!mWsbm->destroyTTMBuffer(buf))
+            WTRACE("failed to free TTMBuffer");
+    }
+    mTTMWrappers.clear();
+}
+
+int RotationBufferProvider::transFromHalToVa(int transform)
+{
+    if (transform == HAL_TRANSFORM_ROT_90)
+        return VA_ROTATION_90;
+    if (transform == HAL_TRANSFORM_ROT_180)
+        return VA_ROTATION_180;
+    if (transform == HAL_TRANSFORM_ROT_270)
+        return VA_ROTATION_270;
+    return 0;
+}
+
+int RotationBufferProvider::getStride(bool isTarget, int width)
+{
+    int stride = 0;
+    if (width <= 512)
+        stride = 512;
+    else if (width <= 1024)
+        stride = 1024;
+    else if (width <= 1280) {
+        stride = 1280;
+        if (isTarget)
+            stride = 2048;
+    } else if (width <= 2048)
+        stride = 2048;
+    else if (width <= 4096)
+        stride = 4096;
+    else
+        stride = (width + 0x3f) & ~0x3f;
+    return stride;
+}
+
+buffer_handle_t RotationBufferProvider::createWsbmBuffer(int width, int height, void **buf)
+{
+    int size = width * height * 3 / 2; // YUV420 NV12 format
+    int allignment = 16 * 2048; // tiling row stride aligned
+    bool ret = mWsbm->allocateTTMBuffer(size, allignment, buf);
+
+    if (ret == false) {
+        ETRACE("failed to allocate TTM buffer");
+        return 0;
+    }
+
+    return (buffer_handle_t) mWsbm->getKBufHandle(*buf);
+}
+
+bool RotationBufferProvider::createVaSurface(VideoPayloadBuffer *payload, int transform, bool isTarget)
+{
+    VAStatus vaStatus;
+    VASurfaceAttributeTPI attribTpi;
+    VASurfaceAttributeTPI *vaSurfaceAttrib = &attribTpi;
+    int stride;
+    unsigned long buffers;
+    VASurfaceID *surface;
+    int width = 0, height = 0, bufferHeight = 0;
+
+    if (isTarget) {
+        if (transFromHalToVa(transform) == VA_ROTATION_180) {
+            width = payload->width;
+            height = payload->height;
+        } else {
+            width = payload->height;
+            height = payload->width;
+        }
+        mRotatedWidth = width;
+        mRotatedHeight = height;
+        bufferHeight = (height + 0x1f) & ~0x1f;
+        stride = getStride(isTarget, width);
+    } else {
+        width = payload->width;
+        height = payload->height;
+        bufferHeight = (payload->height + 0x1f) & ~0x1f;
+        stride = payload->luma_stride; /* NV12 srouce buffer */
+    }
+
+    if (!stride) {
+        ETRACE("invalid stride value");
+        return false;
+    }
+
+    mBobDeinterlace = payload->bob_deinterlace;
+    // adjust source target for Bob deinterlace
+    if (!isTarget && mBobDeinterlace) {
+        height >>= 1;
+        bufferHeight >>= 1;
+        stride <<= 1;
+    }
+
+    vaSurfaceAttrib->count = 1;
+    vaSurfaceAttrib->width = width;
+    vaSurfaceAttrib->height = height;
+    vaSurfaceAttrib->pixel_format = payload->format;
+    vaSurfaceAttrib->type = VAExternalMemoryKernelDRMBufffer;
+    vaSurfaceAttrib->tiling = payload->tiling;
+    vaSurfaceAttrib->size = (stride * bufferHeight * 3) / 2;
+    vaSurfaceAttrib->luma_offset = 0;
+    vaSurfaceAttrib->chroma_v_offset = stride * bufferHeight;
+    vaSurfaceAttrib->luma_stride = vaSurfaceAttrib->chroma_u_stride
+                                 = vaSurfaceAttrib->chroma_v_stride
+                                 = stride;
+    vaSurfaceAttrib->chroma_u_offset = vaSurfaceAttrib->chroma_v_offset;
+    vaSurfaceAttrib->buffers = &buffers;
+
+    if (isTarget) {
+        buffer_handle_t khandle = createWsbmBuffer(stride, bufferHeight, &mDrmBuf[mTargetIndex]);
+        if (khandle == 0) {
+            ETRACE("failed to create buffer by wsbm");
+            return false;
+        }
+
+        mKhandles[mTargetIndex] = khandle;
+        vaSurfaceAttrib->buffers[0] = (uintptr_t) khandle;
+        mRotatedStride = stride;
+        surface = &mRotatedSurfaces[mTargetIndex];
+    } else {
+        vaSurfaceAttrib->buffers[0] = (uintptr_t) payload->khandle;
+        surface = &mSourceSurface;
+        /* set src surface width/height to video crop size */
+        if (payload->crop_width && payload->crop_height) {
+            width = payload->crop_width;
+            height = (payload->crop_height >> mBobDeinterlace);
+        } else {
+            VTRACE("Invalid cropping width or height");
+            payload->crop_width = width;
+            payload->crop_height = height;
+        }
+    }
+
+    vaStatus = vaCreateSurfacesWithAttribute(mVaDpy,
+                                             width,
+                                             height,
+                                             VA_RT_FORMAT_YUV420,
+                                             1,
+                                             surface,
+                                             vaSurfaceAttrib);
+    if (vaStatus != VA_STATUS_SUCCESS) {
+        ETRACE("vaCreateSurfacesWithAttribute returns %d", vaStatus);
+        ETRACE("Attributes: target: %d, width: %d, height %d, bufferHeight %d, tiling %d",
+                isTarget, width, height, bufferHeight, payload->tiling);
+        *surface = 0;
+        return false;
+    }
+
+    return true;
+}
+
+bool RotationBufferProvider::startVA(VideoPayloadBuffer *payload, int transform)
+{
+    bool ret = true;
+    VAStatus vaStatus;
+    VAEntrypoint *entryPoint;
+    VAConfigAttrib attribDummy;
+    int numEntryPoints;
+    bool supportVideoProcessing = false;
+    int majorVer = 0, minorVer = 0;
+
+    // VA will hold a copy of the param pointer, so local varialbe doesn't work
+    mVaDpy = vaGetDisplay(&mDisplay);
+    if (NULL == mVaDpy) {
+        ETRACE("failed to get VADisplay");
+        return false;
+    }
+
+    vaStatus = vaInitialize(mVaDpy, &majorVer, &minorVer);
+    CHECK_VA_STATUS_RETURN("vaInitialize");
+
+    numEntryPoints = vaMaxNumEntrypoints(mVaDpy);
+
+    if (numEntryPoints <= 0) {
+        ETRACE("numEntryPoints value is invalid");
+        return false;
+    }
+
+    entryPoint = (VAEntrypoint*)malloc(sizeof(VAEntrypoint) * numEntryPoints);
+    if (NULL == entryPoint) {
+        ETRACE("failed to malloc memory for entryPoint");
+        return false;
+    }
+
+    vaStatus = vaQueryConfigEntrypoints(mVaDpy,
+                                        VAProfileNone,
+                                        entryPoint,
+                                        &numEntryPoints);
+    CHECK_VA_STATUS_RETURN("vaQueryConfigEntrypoints");
+
+    for (int i = 0; i < numEntryPoints; i++)
+        if (entryPoint[i] == VAEntrypointVideoProc)
+            supportVideoProcessing = true;
+
+    free(entryPoint);
+    entryPoint = NULL;
+
+    if (!supportVideoProcessing) {
+        ETRACE("VAEntrypointVideoProc is not supported");
+        return false;
+    }
+
+    vaStatus = vaCreateConfig(mVaDpy,
+                              VAProfileNone,
+                              VAEntrypointVideoProc,
+                              &attribDummy,
+                              0,
+                              &mVaCfg);
+    CHECK_VA_STATUS_RETURN("vaCreateConfig");
+
+    // create first target surface
+    ret = createVaSurface(payload, transform, true);
+    if (ret == false) {
+        ETRACE("failed to create target surface with attribute");
+        return false;
+    }
+
+    vaStatus = vaCreateContext(mVaDpy,
+                               mVaCfg,
+                               payload->width,
+                               payload->height,
+                               0,
+                               &mRotatedSurfaces[0],
+                               1,
+                               &mVaCtx);
+    CHECK_VA_STATUS_RETURN("vaCreateContext");
+
+    VAProcFilterType filters[VAProcFilterCount];
+    unsigned int numFilters = VAProcFilterCount;
+    vaStatus = vaQueryVideoProcFilters(mVaDpy, mVaCtx, filters, &numFilters);
+    CHECK_VA_STATUS_RETURN("vaQueryVideoProcFilters");
+
+    bool supportVideoProcFilter = false;
+    for (unsigned int j = 0; j < numFilters; j++)
+        if (filters[j] == VAProcFilterNone)
+            supportVideoProcFilter = true;
+
+    if (!supportVideoProcFilter) {
+        ETRACE("VAProcFilterNone is not supported");
+        return false;
+    }
+
+    VAProcFilterParameterBuffer filter;
+    filter.type = VAProcFilterNone;
+    filter.value = 0;
+
+    vaStatus = vaCreateBuffer(mVaDpy,
+                              mVaCtx,
+                              VAProcFilterParameterBufferType,
+                              sizeof(filter),
+                              1,
+                              &filter,
+                              &mVaBufFilter);
+    CHECK_VA_STATUS_RETURN("vaCreateBuffer");
+
+    VAProcPipelineCaps pipelineCaps;
+    unsigned int numCaps = 1;
+    vaStatus = vaQueryVideoProcPipelineCaps(mVaDpy,
+                                            mVaCtx,
+                                            &mVaBufFilter,
+                                            numCaps,
+                                            &pipelineCaps);
+    CHECK_VA_STATUS_RETURN("vaQueryVideoProcPipelineCaps");
+
+    if (!(pipelineCaps.rotation_flags & (1 << transFromHalToVa(transform)))) {
+        ETRACE("VA_ROTATION_xxx: 0x%08x is not supported by the filter",
+             transFromHalToVa(transform));
+        return false;
+    }
+
+    mVaInitialized = true;
+
+    return true;
+}
+
+bool RotationBufferProvider::setupRotationBuffer(VideoPayloadBuffer *payload, int transform)
+{
+#ifdef DEBUG_ROTATION_PERFROMANCE
+    uint32_t setup_Begin = getMilliseconds();
+#endif
+    VAStatus vaStatus;
+    int stride;
+    bool ret = false;
+
+    if (payload->format != VA_FOURCC_NV12 || payload->width == 0 || payload->height == 0) {
+        WTRACE("payload data is not correct: format %#x, width %d, height %d",
+            payload->format, payload->width, payload->height);
+        return ret;
+    }
+
+    if (payload->width > 1280 && payload->width <= 2048) {
+        payload->tiling = 1;
+    }
+
+    do {
+        if (isContextChanged(payload->width, payload->height, transform)) {
+            DTRACE("VA is restarted as rotation context changes");
+
+            if (mVaInitialized) {
+                stopVA(); // need to re-initialize VA for new rotation config
+            }
+            mTransform = transform;
+            mWidth = payload->width;
+            mHeight = payload->height;
+        }
+
+        if (!mVaInitialized) {
+            ret = startVA(payload, transform);
+            if (ret == false) {
+                vaStatus = VA_STATUS_ERROR_OPERATION_FAILED;
+                break;
+            }
+        }
+
+        // start to create next target surface
+        if (!mRotatedSurfaces[mTargetIndex]) {
+            ret = createVaSurface(payload, transform, true);
+            if (ret == false) {
+                ETRACE("failed to create target surface with attribute");
+                vaStatus = VA_STATUS_ERROR_OPERATION_FAILED;
+                break;
+            }
+        }
+
+        // create source surface
+        ret = createVaSurface(payload, transform, false);
+        if (ret == false) {
+            ETRACE("failed to create source surface with attribute");
+            vaStatus = VA_STATUS_ERROR_OPERATION_FAILED;
+            break;
+        }
+
+#ifdef DEBUG_ROTATION_PERFROMANCE
+        uint32_t beginPicture = getMilliseconds();
+#endif
+        vaStatus = vaBeginPicture(mVaDpy, mVaCtx, mRotatedSurfaces[mTargetIndex]);
+        CHECK_VA_STATUS_BREAK("vaBeginPicture");
+
+        VABufferID pipelineBuf;
+        void *p;
+        VAProcPipelineParameterBuffer *pipelineParam;
+        vaStatus = vaCreateBuffer(mVaDpy,
+                                  mVaCtx,
+                                  VAProcPipelineParameterBufferType,
+                                  sizeof(*pipelineParam),
+                                  1,
+                                  NULL,
+                                  &pipelineBuf);
+        CHECK_VA_STATUS_BREAK("vaCreateBuffer");
+
+        vaStatus = vaMapBuffer(mVaDpy, pipelineBuf, &p);
+        CHECK_VA_STATUS_BREAK("vaMapBuffer");
+
+        pipelineParam = (VAProcPipelineParameterBuffer*)p;
+        pipelineParam->surface = mSourceSurface;
+        pipelineParam->rotation_state = transFromHalToVa(transform);
+        pipelineParam->filters = &mVaBufFilter;
+        pipelineParam->num_filters = 1;
+        pipelineParam->surface_region = NULL;
+        pipelineParam->output_region = NULL;
+        pipelineParam->num_forward_references = 0;
+        pipelineParam->num_backward_references = 0;
+        vaStatus = vaUnmapBuffer(mVaDpy, pipelineBuf);
+        CHECK_VA_STATUS_BREAK("vaUnmapBuffer");
+
+        vaStatus = vaRenderPicture(mVaDpy, mVaCtx, &pipelineBuf, 1);
+        CHECK_VA_STATUS_BREAK("vaRenderPicture");
+
+        vaStatus = vaEndPicture(mVaDpy, mVaCtx);
+        CHECK_VA_STATUS_BREAK("vaEndPicture");
+
+        vaStatus = vaSyncSurface(mVaDpy, mRotatedSurfaces[mTargetIndex]);
+        CHECK_VA_STATUS_BREAK("vaSyncSurface");
+
+#ifdef DEBUG_ROTATION_PERFROMANCE
+        ITRACE("time spent %dms from vaBeginPicture to vaSyncSurface",
+             getMilliseconds() - beginPicture);
+#endif
+
+        // Populate payload fields so that overlayPlane can flip the buffer
+        payload->rotated_width = mRotatedStride;
+        payload->rotated_height = mRotatedHeight;
+        payload->rotated_buffer_handle = mKhandles[mTargetIndex];
+        // setting client transform to 0 to force re-generating rotated buffer whenever needed.
+        payload->client_transform = 0;
+        mTargetIndex++;
+        if (mTargetIndex >= MAX_SURFACE_NUM)
+            mTargetIndex = 0;
+
+    } while (0);
+
+#ifdef DEBUG_ROTATION_PERFROMANCE
+    ITRACE("time spent %dms for setupRotationBuffer",
+         getMilliseconds() - setup_Begin);
+#endif
+
+    if (mSourceSurface > 0) {
+        vaStatus = vaDestroySurfaces(mVaDpy, &mSourceSurface, 1);
+        if (vaStatus != VA_STATUS_SUCCESS)
+            WTRACE("vaDestroySurfaces failed, vaStatus = %d", vaStatus);
+        mSourceSurface = 0;
+    }
+
+    if (vaStatus != VA_STATUS_SUCCESS) {
+        stopVA();
+        return false; // To not block HWC, just abort instead of retry
+    }
+
+    if (!payload->khandle) {
+        WTRACE("khandle is reset by decoder, surface is invalid!");
+        return false;
+    }
+
+    return true;
+}
+
+bool RotationBufferProvider::prepareBufferInfo(int w, int h, int stride, VideoPayloadBuffer *payload, void *user_pt)
+{
+    int chroma_offset, size;
+    void *buf = NULL;
+
+    payload->width = payload->crop_width = w;
+    payload->height = payload->crop_height = h;
+    payload->coded_width = ((w + 0xf) & ~0xf);
+    payload->coded_height = ((h + 0xf) & ~0xf);
+    payload->format = VA_FOURCC_NV12;
+    payload->tiling = 1;
+    payload->luma_stride = stride;
+    payload->chroma_u_stride = stride;
+    payload->chroma_v_stride = stride;
+    payload->client_transform = 0;
+    payload->bob_deinterlace = 0;
+
+    chroma_offset = stride * h;
+    size = stride * h + stride * h / 2;
+
+    ssize_t index;
+    index = mTTMWrappers.indexOfKey((uint64_t)user_pt);
+    if (index < 0) {
+        VTRACE("wrapped userPt as wsbm buffer");
+        bool ret = mWsbm->allocateTTMBufferUB(size, 0, &buf, user_pt);
+        if (ret == false) {
+            ETRACE("failed to allocate TTM buffer");
+            return ret;
+        }
+
+        if (mTTMWrappers.size() >= TTM_WRAPPER_COUNT) {
+            WTRACE("mTTMWrappers is unexpectedly full. Invalidate caches");
+            invalidateCaches();
+        }
+
+        index = mTTMWrappers.add((uint64_t)user_pt, buf);
+    } else {
+        VTRACE("got wsbmBuffer in saved caches");
+        buf = mTTMWrappers.valueAt(index);
+    }
+
+    payload->khandle = (buffer_handle_t) mWsbm->getKBufHandle(buf);
+    return true;
+}
+
+void RotationBufferProvider::freeVaSurfaces()
+{
+    bool ret;
+    VAStatus vaStatus;
+
+    for (int i = 0; i < MAX_SURFACE_NUM; i++) {
+        if (NULL != mDrmBuf[i]) {
+            ret = mWsbm->destroyTTMBuffer(mDrmBuf[i]);
+            if (!ret)
+                WTRACE("failed to free TTMBuffer");
+            mDrmBuf[i] = NULL;
+        }
+    }
+
+    // remove wsbm buffer ref from VA
+    for (int j = 0; j < MAX_SURFACE_NUM; j++) {
+        if (0 != mRotatedSurfaces[j]) {
+            vaStatus = vaDestroySurfaces(mVaDpy, &mRotatedSurfaces[j], 1);
+            if (vaStatus != VA_STATUS_SUCCESS)
+                WTRACE("vaDestroySurfaces failed, vaStatus = %d", vaStatus);
+        }
+        mRotatedSurfaces[j] = 0;
+    }
+}
+
+void RotationBufferProvider::stopVA()
+{
+    freeVaSurfaces();
+
+    if (0 != mVaBufFilter)
+        vaDestroyBuffer(mVaDpy, mVaBufFilter);
+    if (0 != mVaCfg)
+        vaDestroyConfig(mVaDpy,mVaCfg);
+    if (0 != mVaCtx)
+        vaDestroyContext(mVaDpy, mVaCtx);
+    if (0 != mVaDpy)
+        vaTerminate(mVaDpy);
+
+    mVaInitialized = false;
+
+    for (int i = 0; i < MAX_SURFACE_NUM; i++) {
+        mKhandles[i] = 0;
+        mRotatedSurfaces[i] = 0;
+        mDrmBuf[i] = NULL;
+    }
+    // reset VA variable
+    mVaDpy = 0;
+    mVaCfg = 0;
+    mVaCtx = 0;
+    mVaBufFilter = 0;
+    mSourceSurface = 0;
+
+    mWidth = 0;
+    mHeight = 0;
+    mRotatedWidth = 0;
+    mRotatedHeight = 0;
+    mRotatedStride = 0;
+    mTargetIndex = 0;
+    mBobDeinterlace = 0;
+}
+
+bool RotationBufferProvider::isContextChanged(int width, int height, int transform)
+{
+    // check rotation config
+    if (height == mHeight &&
+        width == mWidth &&
+        transform == mTransform) {
+        return false;
+    }
+
+    return true;
+}
+
+} // name space intel
+} // name space android
diff --git a/merrifield/ips/common/RotationBufferProvider.h b/merrifield/ips/common/RotationBufferProvider.h
new file mode 100644
index 0000000..edf4fa7
--- /dev/null
+++ b/merrifield/ips/common/RotationBufferProvider.h
@@ -0,0 +1,102 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#ifndef __ROTATIONO_BUFFER_PROVIDER_H__
+#define __ROTATIONO_BUFFER_PROVIDER_H__
+
+#include <va/va.h>
+#include <sys/time.h>
+#include <va/va_tpi.h>
+#include <va/va_vpp.h>
+#include <common/Wsbm.h>
+#include <utils/Timers.h>
+#include <utils/KeyedVector.h>
+#include <va/va_android.h>
+#include <common/VideoPayloadBuffer.h>
+
+namespace android {
+namespace intel {
+
+#define Display unsigned int
+typedef void* VADisplay;
+typedef int VAStatus;
+
+class RotationBufferProvider {
+
+public:
+    RotationBufferProvider(Wsbm* wsbm);
+    ~RotationBufferProvider();
+
+    bool initialize();
+    void deinitialize();
+    void reset();
+    bool setupRotationBuffer(VideoPayloadBuffer *payload, int transform);
+    bool prepareBufferInfo(int, int, int, VideoPayloadBuffer *, void *);
+
+private:
+    void invalidateCaches();
+    bool startVA(VideoPayloadBuffer *payload, int transform);
+    void stopVA();
+    bool isContextChanged(int width, int height, int transform);
+    int transFromHalToVa(int transform);
+    buffer_handle_t createWsbmBuffer(int width, int height, void **buf);
+    int getStride(bool isTarget, int width);
+    bool createVaSurface(VideoPayloadBuffer *payload, int transform, bool isTarget);
+    void freeVaSurfaces();
+    inline uint32_t getMilliseconds();
+
+private:
+    enum {
+        MAX_SURFACE_NUM = 4
+    };
+
+    Wsbm* mWsbm;
+
+    bool mVaInitialized;
+    VADisplay mVaDpy;
+    VAConfigID mVaCfg;
+    VAContextID mVaCtx;
+    VABufferID mVaBufFilter;
+    VASurfaceID mSourceSurface;
+    Display mDisplay;
+
+    // rotation config variables
+    int mWidth;
+    int mHeight;
+    int mTransform;
+
+    int mRotatedWidth;
+    int mRotatedHeight;
+    int mRotatedStride;
+
+    int mTargetIndex;
+    buffer_handle_t mKhandles[MAX_SURFACE_NUM];
+    VASurfaceID mRotatedSurfaces[MAX_SURFACE_NUM];
+    void *mDrmBuf[MAX_SURFACE_NUM];
+
+    enum {
+        TTM_WRAPPER_COUNT = 10,
+    };
+
+    KeyedVector<uint64_t, void*> mTTMWrappers; /* userPt/wsbmBuffer  */
+
+    int mBobDeinterlace;
+};
+
+} // name space intel
+} // name space android
+
+#endif
diff --git a/merrifield/ips/common/SpritePlaneBase.cpp b/merrifield/ips/common/SpritePlaneBase.cpp
new file mode 100644
index 0000000..890aec8
--- /dev/null
+++ b/merrifield/ips/common/SpritePlaneBase.cpp
@@ -0,0 +1,53 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#include <HwcTrace.h>
+#include <common/SpritePlaneBase.h>
+#include <common/PixelFormat.h>
+
+namespace android {
+namespace intel {
+
+SpritePlaneBase::SpritePlaneBase(int index, int disp)
+    : DisplayPlane(index, PLANE_SPRITE, disp),
+      mForceBottom(false),
+      mAbovePrimary(true)
+{
+    CTRACE();
+}
+
+SpritePlaneBase::~SpritePlaneBase()
+{
+    CTRACE();
+}
+
+bool SpritePlaneBase::flip(void *ctx)
+{
+    CTRACE();
+    return DisplayPlane::flip(ctx);
+}
+
+bool SpritePlaneBase::enable()
+{
+    return enablePlane(true);
+}
+
+bool SpritePlaneBase::disable()
+{
+    return enablePlane(false);
+}
+
+} // namespace intel
+} // namespace android
diff --git a/merrifield/ips/common/SpritePlaneBase.h b/merrifield/ips/common/SpritePlaneBase.h
new file mode 100644
index 0000000..78bbd6e
--- /dev/null
+++ b/merrifield/ips/common/SpritePlaneBase.h
@@ -0,0 +1,52 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef SPRITE_PLANE_BASE_H
+#define SPRITE_PLANE_BASE_H
+
+#include <utils/KeyedVector.h>
+#include <hal_public.h>
+#include <BufferCache.h>
+#include <DisplayPlane.h>
+
+namespace android {
+namespace intel {
+
+class SpritePlaneBase : public DisplayPlane {
+public:
+    SpritePlaneBase(int index, int disp);
+    virtual ~SpritePlaneBase();
+public:
+    // hardware operations
+    virtual bool flip(void *ctx);
+    virtual bool enable();
+    virtual bool disable();
+    virtual bool isDisabled() = 0;
+
+    // display device
+    virtual void* getContext() const = 0;
+protected:
+    virtual bool setDataBuffer(BufferMapper& mapper) = 0;
+    virtual bool enablePlane(bool enabled) = 0;
+protected:
+    bool mForceBottom;
+    bool mAbovePrimary;
+};
+
+} // namespace intel
+} // namespace android
+
+#endif /* SPRITE_PLANE_BASE_H */
+
diff --git a/merrifield/ips/common/TTMBufferMapper.cpp b/merrifield/ips/common/TTMBufferMapper.cpp
new file mode 100644
index 0000000..7c3ed0d
--- /dev/null
+++ b/merrifield/ips/common/TTMBufferMapper.cpp
@@ -0,0 +1,103 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#include <HwcTrace.h>
+#include <common/TTMBufferMapper.h>
+
+namespace android {
+namespace intel {
+
+TTMBufferMapper::TTMBufferMapper(Wsbm& wsbm, DataBuffer& buffer)
+    : BufferMapper(buffer),
+      mRefCount(0),
+      mWsbm(wsbm),
+      mBufferObject(0),
+      mGttOffsetInPage(0),
+      mCpuAddress(0),
+      mSize(0)
+{
+    CTRACE();
+}
+
+TTMBufferMapper::~TTMBufferMapper()
+{
+    CTRACE();
+}
+
+bool TTMBufferMapper::map()
+{
+    void *wsbmBufferObject = 0;
+    buffer_handle_t handle;
+    void *virtAddr;
+    uint32_t gttOffsetInPage;
+
+    CTRACE();
+
+    handle = getHandle();
+
+    bool ret = mWsbm.wrapTTMBuffer((int64_t)handle, &wsbmBufferObject);
+    if (ret == false) {
+        ETRACE("failed to map TTM buffer");
+        return false;
+    }
+
+    // TODO: review this later
+    ret = mWsbm.waitIdleTTMBuffer(wsbmBufferObject);
+    if (ret == false) {
+        ETRACE("failed to wait ttm buffer idle");
+        return false;
+    }
+
+    virtAddr = mWsbm.getCPUAddress(wsbmBufferObject);
+    gttOffsetInPage = mWsbm.getGttOffset(wsbmBufferObject);
+
+    if (!gttOffsetInPage || !virtAddr) {
+        WTRACE("offset = %#x, addr = %p.", gttOffsetInPage, virtAddr);
+        return false;
+    }
+
+    // update parameters
+    mBufferObject = wsbmBufferObject;
+    mGttOffsetInPage = gttOffsetInPage;
+    mCpuAddress = virtAddr;
+    mSize = 0;
+    return true;
+}
+
+bool TTMBufferMapper::unmap()
+{
+    CTRACE();
+
+    if (!mBufferObject)
+        return false;
+
+    mWsbm.unreferenceTTMBuffer(mBufferObject);
+
+    mGttOffsetInPage = 0;
+    mCpuAddress = 0;
+    mSize = 0;
+    mBufferObject = 0;
+    return true;
+}
+
+bool TTMBufferMapper::waitIdle()
+{
+    return mWsbm.waitIdleTTMBuffer(mBufferObject);
+}
+
+} // namespace intel
+} // namespace android
+
+
diff --git a/merrifield/ips/common/TTMBufferMapper.h b/merrifield/ips/common/TTMBufferMapper.h
new file mode 100644
index 0000000..46ed26e
--- /dev/null
+++ b/merrifield/ips/common/TTMBufferMapper.h
@@ -0,0 +1,70 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef TTMBUFFERMAPPER_H_
+#define TTMBUFFERMAPPER_H_
+
+#include <DataBuffer.h>
+#include <BufferMapper.h>
+#include <common/Wsbm.h>
+
+namespace android {
+namespace intel {
+
+class TTMBufferMapper : public BufferMapper {
+public:
+    TTMBufferMapper(Wsbm& wsbm, DataBuffer& buffer);
+    virtual ~TTMBufferMapper();
+public:
+    bool map();
+    bool unmap();
+
+    uint32_t getGttOffsetInPage(int subIndex) const {
+        return mGttOffsetInPage;
+    }
+    void* getCpuAddress(int subIndex) const {
+        return mCpuAddress;
+    }
+    uint32_t getSize(int subIndex) const {
+        return mSize;
+    }
+    buffer_handle_t getKHandle(int subIndex) {
+        return 0;
+    }
+    buffer_handle_t getFbHandle(int subIndex) {
+        return 0;
+    }
+    void putFbHandle() {
+        return;
+    }
+
+    // wait idle
+    bool waitIdle();
+private:
+    int mRefCount;
+    Wsbm& mWsbm;
+    void* mBufferObject;
+
+    // mapped info
+    uint32_t mGttOffsetInPage;
+    void* mCpuAddress;
+    uint32_t mSize;
+};
+
+} //namespace intel
+} //namespace android
+
+
+#endif /* TTMBUFFERMAPPER_H_ */
diff --git a/merrifield/ips/common/VideoPayloadBuffer.h b/merrifield/ips/common/VideoPayloadBuffer.h
new file mode 100644
index 0000000..1faf84a
--- /dev/null
+++ b/merrifield/ips/common/VideoPayloadBuffer.h
@@ -0,0 +1,87 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef VIDEO_PAYLOAD_BUFFER_H
+#define VIDEO_PAYLOAD_BUFFER_H
+
+#include <utils/Timers.h>
+namespace android {
+namespace intel {
+
+struct VideoPayloadBuffer {
+    // transform made by clients (clients to hwc)
+    int client_transform;
+    int metadata_transform;
+    int rotated_width;
+    int rotated_height;
+    int surface_protected;
+    int force_output_method;
+    buffer_handle_t rotated_buffer_handle;
+    uint32_t renderStatus;
+    unsigned int used_by_widi;
+    int bob_deinterlace;
+    int tiling;
+    uint32_t width;
+    uint32_t height;
+    uint32_t luma_stride;
+    uint32_t chroma_u_stride;
+    uint32_t chroma_v_stride;
+    uint32_t format;
+    buffer_handle_t khandle;
+    int64_t  timestamp;
+
+    uint32_t rotate_luma_stride;
+    uint32_t rotate_chroma_u_stride;
+    uint32_t rotate_chroma_v_stride;
+
+    nsecs_t hwc_timestamp;
+    uint32_t layer_transform;
+
+    void *native_window;
+    buffer_handle_t scaling_khandle;
+    uint32_t scaling_width;
+    uint32_t scaling_height;
+
+    uint32_t scaling_luma_stride;
+    uint32_t scaling_chroma_u_stride;
+    uint32_t scaling_chroma_v_stride;
+
+    uint32_t crop_width;
+    uint32_t crop_height;
+
+    uint32_t coded_width;
+    uint32_t coded_height;
+    uint32_t csc_mode;
+    uint32_t video_range;
+    uint32_t initialized;
+};
+
+
+// force output method values
+enum {
+    FORCE_OUTPUT_INVALID = 0,
+    FORCE_OUTPUT_GPU,
+    FORCE_OUTPUT_OVERLAY,
+    FORCE_OUTPUT_SW_DECODE,
+};
+
+
+} // namespace intel
+} // namespace android
+
+
+#endif // VIDEO_PAYLOAD_BUFFER_H
+
+
diff --git a/merrifield/ips/common/VideoPayloadManager.cpp b/merrifield/ips/common/VideoPayloadManager.cpp
new file mode 100644
index 0000000..33e2afb
--- /dev/null
+++ b/merrifield/ips/common/VideoPayloadManager.cpp
@@ -0,0 +1,123 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#include <HwcTrace.h>
+#include <BufferMapper.h>
+#include <common/GrallocSubBuffer.h>
+#include <common/VideoPayloadManager.h>
+#include <common/VideoPayloadBuffer.h>
+
+namespace android {
+namespace intel {
+
+VideoPayloadManager::VideoPayloadManager()
+    : IVideoPayloadManager()
+{
+}
+
+VideoPayloadManager::~VideoPayloadManager()
+{
+}
+
+bool VideoPayloadManager::getMetaData(BufferMapper *mapper, MetaData *metadata)
+{
+    if (!mapper || !metadata) {
+        ETRACE("Null input params");
+        return false;
+    }
+
+    VideoPayloadBuffer *p = (VideoPayloadBuffer*) mapper->getCpuAddress(SUB_BUFFER1);
+    if (!p) {
+        ETRACE("Got null payload from display buffer");
+        return false;
+    }
+
+    metadata->format = p->format;
+    metadata->transform = p->metadata_transform;
+    metadata->timestamp = p->timestamp;
+
+    metadata->normalBuffer.khandle = p->khandle;
+    metadata->normalBuffer.width = p->crop_width;
+    metadata->normalBuffer.height = p->crop_height;
+    metadata->normalBuffer.bufWidth = p->width;
+    metadata->normalBuffer.bufHeight = p->height;
+    metadata->normalBuffer.lumaStride = p->luma_stride;
+    metadata->normalBuffer.chromaUStride = p->chroma_u_stride;
+    metadata->normalBuffer.chromaVStride = p->chroma_v_stride;
+    metadata->normalBuffer.offsetX = 0;
+    metadata->normalBuffer.offsetY = 0;
+    metadata->normalBuffer.tiled = (p->width > 1280);
+
+    metadata->scalingBuffer.khandle = p->scaling_khandle;
+    metadata->scalingBuffer.width = p->scaling_width;
+    metadata->scalingBuffer.height = p->scaling_height;
+    metadata->scalingBuffer.bufWidth = align_to(p->scaling_width, 32);
+    metadata->scalingBuffer.bufHeight = align_to(p->scaling_height, 32);
+    metadata->scalingBuffer.lumaStride = p->scaling_luma_stride;
+    metadata->scalingBuffer.chromaUStride = p->scaling_chroma_u_stride;
+    metadata->scalingBuffer.chromaVStride = p->scaling_chroma_v_stride;
+    metadata->scalingBuffer.offsetX = 0;
+    metadata->scalingBuffer.offsetY = 0;
+    metadata->scalingBuffer.tiled = false;
+
+    metadata->rotationBuffer.khandle = p->rotated_buffer_handle;
+    uint16_t rotSrcWidth;
+    uint16_t rotSrcHeight;
+    if (metadata->scalingBuffer.khandle) {
+        rotSrcWidth = metadata->scalingBuffer.width;
+        rotSrcHeight = metadata->scalingBuffer.height;
+    } else {
+        rotSrcWidth = metadata->normalBuffer.width;
+        rotSrcHeight = metadata->normalBuffer.height;
+    }
+    if (metadata->transform == 0 || metadata->transform == HAL_TRANSFORM_ROT_180) {
+        metadata->rotationBuffer.width = rotSrcWidth;
+        metadata->rotationBuffer.height = rotSrcHeight;
+    } else {
+        metadata->rotationBuffer.width = rotSrcHeight;
+        metadata->rotationBuffer.height = rotSrcWidth;
+    }
+    metadata->rotationBuffer.bufWidth = p->rotated_width;
+    metadata->rotationBuffer.bufHeight = p->rotated_height;
+    metadata->rotationBuffer.lumaStride = p->rotate_luma_stride;
+    metadata->rotationBuffer.chromaUStride = p->rotate_chroma_u_stride;
+    metadata->rotationBuffer.chromaVStride = p->rotate_chroma_v_stride;
+    metadata->rotationBuffer.offsetX = (-metadata->rotationBuffer.width) & 0xf;
+    metadata->rotationBuffer.offsetY = (-metadata->rotationBuffer.height) & 0xf;
+    metadata->rotationBuffer.tiled = metadata->normalBuffer.tiled;
+
+    return true;
+}
+
+bool VideoPayloadManager::setRenderStatus(BufferMapper *mapper, bool renderStatus)
+{
+    if (!mapper) {
+        ETRACE("Null mapper param");
+        return false;
+    }
+
+    VideoPayloadBuffer* p = (VideoPayloadBuffer*) mapper->getCpuAddress(SUB_BUFFER1);
+    if (!p) {
+        ETRACE("Got null payload from display buffer");
+        return false;
+    }
+
+    p->renderStatus = renderStatus ? 1 : 0;
+    return true;
+}
+
+} // namespace intel
+} // namespace android
diff --git a/merrifield/ips/common/VideoPayloadManager.h b/merrifield/ips/common/VideoPayloadManager.h
new file mode 100644
index 0000000..563003d
--- /dev/null
+++ b/merrifield/ips/common/VideoPayloadManager.h
@@ -0,0 +1,42 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef VIDEO_PAYLOAD_MANAGER_H
+#define VIDEO_PAYLOAD_MANAGER_H
+
+#include <IVideoPayloadManager.h>
+
+namespace android {
+namespace intel {
+
+class BufferMapper;
+
+class VideoPayloadManager : public IVideoPayloadManager {
+
+public:
+    VideoPayloadManager();
+    virtual ~VideoPayloadManager();
+
+    // IVideoPayloadManager
+public:
+    virtual bool getMetaData(BufferMapper *mapper, MetaData *metadata);
+    virtual bool setRenderStatus(BufferMapper *mapper, bool renderStatus);
+
+}; // class VideoPayloadManager
+
+} // namespace intel
+} // namespace android
+
+#endif /* VIDEO_PAYLOAD_MANAGER_H */
diff --git a/merrifield/ips/common/VsyncControl.cpp b/merrifield/ips/common/VsyncControl.cpp
new file mode 100644
index 0000000..9e576fd
--- /dev/null
+++ b/merrifield/ips/common/VsyncControl.cpp
@@ -0,0 +1,84 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#include <HwcTrace.h>
+#include <Drm.h>
+#include <Hwcomposer.h>
+#include <common/VsyncControl.h>
+
+namespace android {
+namespace intel {
+
+VsyncControl::VsyncControl()
+    : IVsyncControl(),
+      mInitialized(false)
+{
+}
+
+VsyncControl::~VsyncControl()
+{
+    WARN_IF_NOT_DEINIT();
+}
+
+bool VsyncControl::initialize()
+{
+    mInitialized = true;
+    return true;
+}
+
+void VsyncControl::deinitialize()
+{
+    mInitialized = false;
+}
+
+bool VsyncControl::control(int disp, bool enabled)
+{
+    ATRACE("disp = %d, enabled = %d", disp, enabled);
+
+    struct drm_psb_vsync_set_arg arg;
+    memset(&arg, 0, sizeof(struct drm_psb_vsync_set_arg));
+
+    // pipe equals to disp
+    arg.vsync.pipe = disp;
+
+    if (enabled) {
+        arg.vsync_operation_mask = VSYNC_ENABLE;
+    } else {
+        arg.vsync_operation_mask = VSYNC_DISABLE;
+    }
+    Drm *drm = Hwcomposer::getInstance().getDrm();
+    return drm->writeReadIoctl(DRM_PSB_VSYNC_SET, &arg, sizeof(arg));
+}
+
+bool VsyncControl::wait(int disp, int64_t& timestamp)
+{
+    ATRACE("disp = %d", disp);
+
+    struct drm_psb_vsync_set_arg arg;
+    memset(&arg, 0, sizeof(struct drm_psb_vsync_set_arg));
+
+    arg.vsync_operation_mask = VSYNC_WAIT;
+
+    // pipe equals to disp
+    arg.vsync.pipe = disp;
+
+    Drm *drm = Hwcomposer::getInstance().getDrm();
+    bool ret = drm->writeReadIoctl(DRM_PSB_VSYNC_SET, &arg, sizeof(arg));
+    timestamp = (int64_t)arg.vsync.timestamp;
+    return ret;
+}
+
+} // namespace intel
+} // namespace android
diff --git a/merrifield/ips/common/VsyncControl.h b/merrifield/ips/common/VsyncControl.h
new file mode 100644
index 0000000..d5ffa11
--- /dev/null
+++ b/merrifield/ips/common/VsyncControl.h
@@ -0,0 +1,43 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef VSYNC_CONTROL_H
+#define VSYNC_CONTROL_H
+
+#include <IVsyncControl.h>
+
+namespace android {
+namespace intel {
+
+class VsyncControl : public IVsyncControl {
+public:
+    VsyncControl();
+    virtual ~VsyncControl();
+
+public:
+    bool initialize();
+    void deinitialize();
+    bool control(int disp, bool enabled);
+    bool wait(int disp, int64_t& timestamp);
+
+private:
+    bool mInitialized;
+};
+
+} // namespace intel
+} // namespace android
+
+
+#endif /* VSYNC_CONTROL_H */
diff --git a/merrifield/ips/common/Wsbm.cpp b/merrifield/ips/common/Wsbm.cpp
new file mode 100644
index 0000000..ab92b1b
--- /dev/null
+++ b/merrifield/ips/common/Wsbm.cpp
@@ -0,0 +1,136 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#include <HwcTrace.h>
+#include <common/Wsbm.h>
+
+Wsbm::Wsbm(int drmFD)
+    : mInitialized(false)
+{
+    CTRACE();
+    mDrmFD = drmFD;
+}
+
+Wsbm::~Wsbm()
+{
+    WARN_IF_NOT_DEINIT();
+}
+
+bool Wsbm::initialize()
+{
+    if (mInitialized) {
+        WTRACE("object is initialized");
+        return true;
+    }
+
+    int ret = psbWsbmInitialize(mDrmFD);
+    if (ret) {
+        ETRACE("failed to initialize Wsbm");
+        return false;
+    }
+
+    mInitialized = true;
+    return true;
+}
+
+void Wsbm::deinitialize()
+{
+    if (!mInitialized) {
+        return;
+    }
+    psbWsbmTakedown();
+    mInitialized = false;
+}
+
+bool Wsbm::allocateTTMBuffer(uint32_t size, uint32_t align, void ** buf)
+{
+    int ret = psbWsbmAllocateTTMBuffer(size, align, buf);
+    if (ret) {
+        ETRACE("failed to allocate buffer");
+        return false;
+    }
+
+    return true;
+}
+
+bool Wsbm::allocateTTMBufferUB(uint32_t size, uint32_t align, void ** buf, void *user_pt)
+{
+    int ret = psbWsbmAllocateFromUB(size, align, buf, user_pt);
+    if (ret) {
+        ETRACE("failed to allocate UB buffer");
+        return false;
+    }
+
+    return true;
+}
+
+bool Wsbm::destroyTTMBuffer(void * buf)
+{
+    int ret = psbWsbmDestroyTTMBuffer(buf);
+    if (ret) {
+        ETRACE("failed to destroy buffer");
+        return false;
+    }
+
+    return true;
+}
+
+void * Wsbm::getCPUAddress(void * buf)
+{
+    return psbWsbmGetCPUAddress(buf);
+}
+
+uint32_t Wsbm::getGttOffset(void * buf)
+{
+    return psbWsbmGetGttOffset(buf);
+}
+
+bool Wsbm::wrapTTMBuffer(int64_t handle, void **buf)
+{
+    int ret = psbWsbmWrapTTMBuffer(handle, buf);
+    if (ret) {
+        ETRACE("failed to wrap buffer");
+        return false;
+    }
+
+    return true;
+}
+
+bool Wsbm::unreferenceTTMBuffer(void *buf)
+{
+    int ret = psbWsbmUnReference(buf);
+    if (ret) {
+        ETRACE("failed to unreference buffer");
+        return false;
+    }
+
+    return true;
+}
+
+uint64_t Wsbm::getKBufHandle(void *buf)
+{
+    return psbWsbmGetKBufHandle(buf);
+}
+
+bool Wsbm::waitIdleTTMBuffer(void *buf)
+{
+    int ret = psbWsbmWaitIdle(buf);
+    if (ret) {
+        ETRACE("failed to wait ttm buffer for idle");
+        return false;
+    }
+
+    return true;
+}
diff --git a/merrifield/ips/common/Wsbm.h b/merrifield/ips/common/Wsbm.h
new file mode 100644
index 0000000..9e2b357
--- /dev/null
+++ b/merrifield/ips/common/Wsbm.h
@@ -0,0 +1,47 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef WSBM_H__
+#define WSBM_H__
+
+#include <common/WsbmWrapper.h>
+
+/**
+ * Class: WSBM
+ * A wrapper class to use libwsbm functionalities
+ */
+class Wsbm
+{
+private:
+    int mDrmFD;
+public:
+    Wsbm(int drmFD);
+    ~Wsbm();
+    bool initialize();
+    void deinitialize();
+    bool allocateTTMBuffer(uint32_t size, uint32_t align,void ** buf);
+    bool allocateTTMBufferUB(uint32_t size, uint32_t align, void ** buf, void *user_pt);
+    bool destroyTTMBuffer(void * buf);
+    void * getCPUAddress(void * buf);
+    uint32_t getGttOffset(void * buf);
+    bool wrapTTMBuffer(int64_t handle, void **buf);
+    bool unreferenceTTMBuffer(void *buf);
+    bool waitIdleTTMBuffer(void *buf);
+    uint64_t getKBufHandle(void *buf);
+private:
+    bool mInitialized;
+};
+
+#endif /*__INTEL_WSBM_H__*/
diff --git a/merrifield/ips/common/WsbmWrapper.c b/merrifield/ips/common/WsbmWrapper.c
new file mode 100644
index 0000000..5e4161e
--- /dev/null
+++ b/merrifield/ips/common/WsbmWrapper.c
@@ -0,0 +1,401 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#include <wsbm_pool.h>
+#include <wsbm_driver.h>
+#include <wsbm_manager.h>
+#include <wsbm_util.h>
+#include <drm/ttm/ttm_placement.h>
+#include <linux/psb_drm.h>
+#include <xf86drm.h>
+#include <HwcTrace.h>
+
+struct _WsbmBufferPool * mainPool = NULL;
+
+struct PsbWsbmValidateNode
+{
+    struct  _ValidateNode base;
+    struct psb_validate_arg arg;
+};
+
+static inline uint32_t align_to(uint32_t arg, uint32_t align)
+{
+    return ((arg + (align - 1)) & (~(align - 1)));
+}
+
+static struct _ValidateNode * pvrAlloc(struct _WsbmVNodeFuncs * func,
+                                       int typeId)
+{
+    CTRACE();
+    if(typeId == 0) {
+        struct PsbWsbmValidateNode * vNode = malloc(sizeof(*vNode));
+        if(!vNode) {
+            ETRACE("failed to allocate memory");
+            return NULL;
+        }
+
+        vNode->base.func = func;
+        vNode->base.type_id = 0;
+        return &vNode->base;
+    } else {
+        struct _ValidateNode * node = malloc(sizeof(*node));
+        if(!node) {
+            ETRACE("failed to allocate node");
+            return NULL;
+        }
+
+        node->func = func;
+        node->type_id = 1;
+        return node;
+    }
+}
+
+static void pvrFree(struct _ValidateNode * node)
+{
+    CTRACE();
+    if(node->type_id == 0) {
+        free(containerOf(node, struct PsbWsbmValidateNode, base));
+    } else {
+        free(node);
+    }
+}
+
+static void pvrClear(struct _ValidateNode * node)
+{
+    CTRACE();
+    if(node->type_id == 0) {
+        struct PsbWsbmValidateNode * vNode =
+            containerOf(node, struct PsbWsbmValidateNode, base);
+        memset(&vNode->arg.d.req, 0, sizeof(vNode->arg.d.req));
+    }
+}
+
+static struct _WsbmVNodeFuncs vNodeFuncs = {
+    .alloc  = pvrAlloc,
+    .free   = pvrFree,
+    .clear  = pvrClear,
+};
+
+void psbWsbmTakedown()
+{
+    CTRACE();
+
+    if (mainPool) {
+        wsbmPoolTakeDown(mainPool);
+        mainPool = NULL;
+    }
+
+    if (wsbmIsInitialized()) {
+        wsbmTakedown();
+    }
+}
+
+int psbWsbmInitialize(int drmFD)
+{
+    union drm_psb_extension_arg arg;
+    const char drmExt[] = "psb_ttm_placement_alphadrop";
+    int ret = 0;
+
+    CTRACE();
+
+    if (drmFD <= 0) {
+        ETRACE("invalid drm fd %d", drmFD);
+        return drmFD;
+    }
+
+    /*init wsbm*/
+    ret = wsbmInit(wsbmNullThreadFuncs(), &vNodeFuncs);
+    if (ret) {
+        ETRACE("failed to initialize Wsbm, error code %d", ret);
+        return ret;
+    }
+
+    VTRACE("DRM_PSB_EXTENSION %d", DRM_PSB_EXTENSION);
+
+    /*get devOffset via drm IOCTL*/
+    strncpy(arg.extension, drmExt, sizeof(drmExt));
+
+    ret = drmCommandWriteRead(drmFD, 6/*DRM_PSB_EXTENSION*/, &arg, sizeof(arg));
+    if(ret || !arg.rep.exists) {
+        ETRACE("failed to get device offset, error code %d", ret);
+        goto out;
+    }
+
+    VTRACE("ioctl offset %#x", arg.rep.driver_ioctl_offset);
+
+    mainPool = wsbmTTMPoolInit(drmFD, arg.rep.driver_ioctl_offset);
+    if(!mainPool) {
+        ETRACE("failed to initialize TTM Pool");
+        ret = -EINVAL;
+        goto out;
+    }
+
+    VTRACE("Wsbm initialization succeeded. mainPool %p", mainPool);
+
+    return 0;
+
+out:
+    psbWsbmTakedown();
+    return ret;
+}
+
+int psbWsbmAllocateFromUB(uint32_t size, uint32_t align, void ** buf, void *user_pt)
+{
+    struct _WsbmBufferObject * wsbmBuf = NULL;
+    int ret = 0;
+    int offset = 0;
+
+    ATRACE("size %d", align_to(size, 4096));
+
+    if(!buf || !user_pt) {
+        ETRACE("invalid parameter");
+        return -EINVAL;
+    }
+
+    VTRACE("mainPool %p", mainPool);
+
+    ret = wsbmGenBuffers(mainPool, 1, &wsbmBuf, align,
+                        DRM_PSB_FLAG_MEM_MMU | WSBM_PL_FLAG_CACHED |
+                        WSBM_PL_FLAG_NO_EVICT | WSBM_PL_FLAG_SHARED);
+    if(ret) {
+        ETRACE("wsbmGenBuffers failed with error code %d", ret);
+        return ret;
+    }
+
+    ret = wsbmBODataUB(wsbmBuf,
+                       align_to(size, 4096), NULL, NULL, 0,
+                       user_pt);
+
+    if(ret) {
+        ETRACE("wsbmBOData failed with error code %d", ret);
+        /*FIXME: should I unreference this buffer here?*/
+        return ret;
+    }
+
+    *buf = wsbmBuf;
+
+    VTRACE("ttm UB buffer allocated. %p", *buf);
+    return 0;
+}
+
+int psbWsbmAllocateTTMBuffer(uint32_t size, uint32_t align, void ** buf)
+{
+    struct _WsbmBufferObject * wsbmBuf = NULL;
+    int ret = 0;
+    int offset = 0;
+
+    ATRACE("size %d", align_to(size, 4096));
+
+    if(!buf) {
+        ETRACE("invalid parameter");
+        return -EINVAL;
+    }
+
+    VTRACE("mainPool %p", mainPool);
+
+    ret = wsbmGenBuffers(mainPool, 1, &wsbmBuf, align,
+                        (WSBM_PL_FLAG_VRAM | WSBM_PL_FLAG_TT |
+                         WSBM_PL_FLAG_SHARED | WSBM_PL_FLAG_NO_EVICT));
+    if(ret) {
+        ETRACE("wsbmGenBuffers failed with error code %d", ret);
+        return ret;
+    }
+
+    ret = wsbmBOData(wsbmBuf, align_to(size, 4096), NULL, NULL, 0);
+    if(ret) {
+        ETRACE("wsbmBOData failed with error code %d", ret);
+        /*FIXME: should I unreference this buffer here?*/
+        return ret;
+    }
+
+    /* wsbmBOReference(wsbmBuf); */ /* no need to add reference */
+
+    *buf = wsbmBuf;
+
+    VTRACE("ttm buffer allocated. %p", *buf);
+    return 0;
+}
+
+int psbWsbmWrapTTMBuffer(uint64_t handle, void **buf)
+{
+    int ret = 0;
+    struct _WsbmBufferObject *wsbmBuf;
+
+    if (!buf) {
+        ETRACE("invalid parameter");
+        return -EINVAL;
+    }
+
+    ret = wsbmGenBuffers(mainPool, 1, &wsbmBuf, 0,
+                        (WSBM_PL_FLAG_VRAM | WSBM_PL_FLAG_TT |
+                        /*WSBM_PL_FLAG_NO_EVICT |*/ WSBM_PL_FLAG_SHARED));
+
+    if (ret) {
+        ETRACE("wsbmGenBuffers failed with error code %d", ret);
+        return ret;
+    }
+
+    ret = wsbmBOSetReferenced(wsbmBuf, handle);
+    if (ret) {
+        ETRACE("wsbmBOSetReferenced failed with error code %d", ret);
+        return ret;
+    }
+
+    *buf = (void *)wsbmBuf;
+
+    VTRACE("wrap buffer %p for handle %#x", wsbmBuf, handle);
+    return 0;
+}
+
+int psbWsbmWrapTTMBuffer2(uint64_t handle, void **buf)
+{
+    int ret = 0;
+    struct _WsbmBufferObject *wsbmBuf;
+
+    if (!buf) {
+        ETRACE("invalid parameter");
+        return -EINVAL;
+    }
+
+    ret = wsbmGenBuffers(mainPool, 1, &wsbmBuf, 4096,
+            (WSBM_PL_FLAG_SHARED | DRM_PSB_FLAG_MEM_MMU | WSBM_PL_FLAG_UNCACHED));
+
+    if (ret) {
+        ETRACE("wsbmGenBuffers failed with error code %d", ret);
+        return ret;
+    }
+
+    *buf = (void *)wsbmBuf;
+
+    VTRACE("wrap buffer %p for handle %#x", wsbmBuf, handle);
+    return 0;
+}
+
+
+int psbWsbmCreateFromUB(void *buf, uint32_t size, void *vaddr)
+{
+    int ret = 0;
+    struct _WsbmBufferObject *wsbmBuf;
+
+    if (!buf || !vaddr) {
+        ETRACE("invalid parameter");
+        return -EINVAL;
+    }
+
+    wsbmBuf = (struct _WsbmBufferObject *)buf;
+    ret = wsbmBODataUB(wsbmBuf, size, NULL, NULL, 0, vaddr);
+    if (ret) {
+        ETRACE("wsbmBODataUB failed with error code %d", ret);
+        return ret;
+    }
+
+    return 0;
+}
+
+int psbWsbmUnReference(void *buf)
+{
+    struct _WsbmBufferObject *wsbmBuf;
+
+    if (!buf) {
+        ETRACE("invalid parameter");
+        return -EINVAL;
+    }
+
+    wsbmBuf = (struct _WsbmBufferObject *)buf;
+
+    wsbmBOUnreference(&wsbmBuf);
+
+    return 0;
+}
+
+int psbWsbmDestroyTTMBuffer(void * buf)
+{
+    CTRACE();
+
+    if(!buf) {
+        ETRACE("invalid ttm buffer");
+        return -EINVAL;
+    }
+
+    /*FIXME: should I unmap this buffer object first?*/
+    wsbmBOUnmap((struct _WsbmBufferObject *)buf);
+
+    wsbmBOUnreference((struct _WsbmBufferObject **)&buf);
+
+    XTRACE();
+
+    return 0;
+}
+
+void * psbWsbmGetCPUAddress(void * buf)
+{
+    if(!buf) {
+        ETRACE("invalid ttm buffer");
+        return NULL;
+    }
+
+    VTRACE("buffer object %p", buf);
+
+    void * address = wsbmBOMap((struct _WsbmBufferObject *)buf,
+                                WSBM_ACCESS_READ | WSBM_ACCESS_WRITE);
+    if(!address) {
+        ETRACE("failed to map buffer object");
+        return NULL;
+    }
+
+    VTRACE("mapped successfully. %p, size %ld",
+        address, wsbmBOSize((struct _WsbmBufferObject *)buf));
+
+    return address;
+}
+
+uint32_t psbWsbmGetGttOffset(void * buf)
+{
+    if(!buf) {
+        ETRACE("invalid ttm buffer");
+        return 0;
+    }
+
+    VTRACE("buffer object %p", buf);
+
+    uint32_t offset =
+        wsbmBOOffsetHint((struct _WsbmBufferObject *)buf) - 0x10000000;
+
+    VTRACE("offset %#x", offset >> 12);
+
+    return offset >> 12;
+}
+
+uint32_t psbWsbmGetKBufHandle(void *buf)
+{
+    if (!buf) {
+        ETRACE("invalid ttm buffer");
+        return 0;
+    }
+
+    return (wsbmKBufHandle(wsbmKBuf((struct _WsbmBufferObject *)buf)));
+}
+
+uint32_t psbWsbmWaitIdle(void *buf)
+{
+    if (!buf) {
+        ETRACE("invalid ttm buffer");
+        return -EINVAL;
+    }
+
+    wsbmBOWaitIdle(buf, 0);
+    return 0;
+}
diff --git a/merrifield/ips/common/WsbmWrapper.h b/merrifield/ips/common/WsbmWrapper.h
new file mode 100644
index 0000000..1dad5fd
--- /dev/null
+++ b/merrifield/ips/common/WsbmWrapper.h
@@ -0,0 +1,41 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef WSBM_WRAPPER_H
+#define WSBM_WRAPPER_H
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+extern int psbWsbmInitialize(int drmFD);
+extern void psbWsbmTakedown();
+extern int psbWsbmAllocateFromUB(uint32_t size, uint32_t align, void ** buf, void *user_pt);
+extern int psbWsbmAllocateTTMBuffer(uint32_t size, uint32_t align,void ** buf);
+extern int psbWsbmDestroyTTMBuffer(void * buf);
+extern void * psbWsbmGetCPUAddress(void * buf);
+extern uint32_t psbWsbmGetGttOffset(void * buf);
+extern int psbWsbmWrapTTMBuffer(uint64_t handle, void **buf);
+extern int psbWsbmWrapTTMBuffer2(uint64_t handle, void **buf);
+extern int psbWsbmCreateFromUB(void *buf, uint32_t size, void *vaddr);
+extern int psbWsbmUnReference(void *buf);
+extern int psbWsbmWaitIdle(void *buf);
+uint32_t psbWsbmGetKBufHandle(void *buf);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /*WSBM_WRAPPER_H*/
diff --git a/merrifield/ips/penwell/PnwGrallocBuffer.cpp b/merrifield/ips/penwell/PnwGrallocBuffer.cpp
new file mode 100644
index 0000000..a867cb8
--- /dev/null
+++ b/merrifield/ips/penwell/PnwGrallocBuffer.cpp
@@ -0,0 +1,46 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#include <HwcTrace.h>
+#include <penwell/PnwGrallocBuffer.h>
+
+namespace android {
+namespace intel {
+
+PnwGrallocBuffer::PnwGrallocBuffer(uint32_t handle)
+    :GrallocBufferBase(handle)
+{
+    struct PnwIMGGrallocBuffer *grallocHandle =
+        (struct PnwIMGGrallocBuffer*)handle;
+
+    CTRACE();
+
+    if (!grallocHandle) {
+        ETRACE("gralloc handle is null");
+        return;
+    }
+
+    mFormat = grallocHandle->format;
+    mWidth = grallocHandle->width;
+    mHeight = grallocHandle->height;
+    mUsage = grallocHandle->usage;
+    mKey = grallocHandle->stamp;
+    mBpp = grallocHandle->bpp;
+
+    initialize();
+}
+
+}
+}
diff --git a/merrifield/ips/penwell/PnwGrallocBuffer.h b/merrifield/ips/penwell/PnwGrallocBuffer.h
new file mode 100644
index 0000000..ce0414c
--- /dev/null
+++ b/merrifield/ips/penwell/PnwGrallocBuffer.h
@@ -0,0 +1,46 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef PNW_GRALLOC_BUFFER_H
+#define PNW_GRALLOC_BUFFER_H
+
+#include <common/GrallocSubBuffer.h>
+#include <common/GrallocBufferBase.h>
+
+namespace android {
+namespace intel {
+
+struct PnwIMGGrallocBuffer{
+    native_handle_t base;
+    int fd[SUB_BUFFER_MAX];
+    unsigned long long stamp;
+    int usage;
+    int width;
+    int height;
+    int format;
+    int bpp;
+}__attribute__((aligned(sizeof(int)),packed));
+
+
+class PnwGrallocBuffer : public GrallocBufferBase {
+public:
+    PnwGrallocBuffer(uint32_t handle);
+};
+
+} // namespace intel
+} // namespace android
+
+
+#endif /* PNW_GRALLOC_BUFFER_H */
diff --git a/merrifield/ips/penwell/PnwGrallocBufferMapper.cpp b/merrifield/ips/penwell/PnwGrallocBufferMapper.cpp
new file mode 100644
index 0000000..2550437
--- /dev/null
+++ b/merrifield/ips/penwell/PnwGrallocBufferMapper.cpp
@@ -0,0 +1,48 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#include <HwcTrace.h>
+#include <Drm.h>
+#include <Hwcomposer.h>
+#include <penwell/PnwGrallocBufferMapper.h>
+
+namespace android {
+namespace intel {
+
+PnwGrallocBufferMapper::PnwGrallocBufferMapper(DataBuffer& buffer)
+    : GrallocBufferMapperBase(buffer)
+{
+    CTRACE();
+}
+
+PnwGrallocBufferMapper::~PnwGrallocBufferMapper()
+{
+    CTRACE();
+}
+
+bool PnwGrallocBufferMapper::map()
+{
+    // TODO: implement map
+    return false;
+}
+
+bool PnwGrallocBufferMapper::unmap()
+{
+    //TODO: implement unmap
+    return false;
+}
+
+} // namespace intel
+} // namespace android
diff --git a/merrifield/ips/penwell/PnwGrallocBufferMapper.h b/merrifield/ips/penwell/PnwGrallocBufferMapper.h
new file mode 100644
index 0000000..743d498
--- /dev/null
+++ b/merrifield/ips/penwell/PnwGrallocBufferMapper.h
@@ -0,0 +1,38 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef PNW_GRALLOC_BUFFER_MAPPER_H
+#define PNW_GRALLOC_BUFFER_MAPPER_H
+
+#include <BufferMapper.h>
+#include <hal_public.h>
+#include <common/GrallocBufferMapperBase.h>
+
+namespace android {
+namespace intel {
+
+class PnwGrallocBufferMapper : public GrallocBufferMapperBase {
+public:
+    PnwGrallocBufferMapper(DataBuffer& buffer);
+    ~PnwGrallocBufferMapper();
+public:
+    bool map();
+    bool unmap();
+};
+
+} // namespace intel
+} // namespace android
+
+#endif /* TNG_GRALLOC_BUFFER_MAPPER_H */
diff --git a/merrifield/ips/penwell/PnwOverlayPlane.cpp b/merrifield/ips/penwell/PnwOverlayPlane.cpp
new file mode 100644
index 0000000..f2328fa
--- /dev/null
+++ b/merrifield/ips/penwell/PnwOverlayPlane.cpp
@@ -0,0 +1,51 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#include <math.h>
+#include <HwcTrace.h>
+#include <Drm.h>
+#include <Hwcomposer.h>
+#include <penwell/PnwOverlayPlane.h>
+#include <penwell/PnwGrallocBuffer.h>
+
+namespace android {
+namespace intel {
+
+PnwOverlayPlane::PnwOverlayPlane(int index, int disp)
+    : OverlayPlaneBase(index, disp)
+{
+    CTRACE();
+}
+
+PnwOverlayPlane::~PnwOverlayPlane()
+{
+    CTRACE();
+}
+
+bool PnwOverlayPlane::flip()
+{
+    //TODO: implement flip
+    return false;
+}
+
+void* PnwOverlayPlane::getContext() const
+{
+    CTRACE();
+    //TODO: return penwell overlay context
+    return 0;
+}
+
+} // namespace intel
+} // namespace android
diff --git a/merrifield/ips/penwell/PnwOverlayPlane.h b/merrifield/ips/penwell/PnwOverlayPlane.h
new file mode 100644
index 0000000..0ae3924
--- /dev/null
+++ b/merrifield/ips/penwell/PnwOverlayPlane.h
@@ -0,0 +1,42 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef PNW_OVERLAY_PLANE_H
+#define PNW_OVERLAY_PLANE_H
+
+#include <utils/KeyedVector.h>
+#include <hal_public.h>
+#include <DisplayPlane.h>
+#include <BufferMapper.h>
+#include <common/Wsbm.h>
+#include <common/OverlayPlaneBase.h>
+
+namespace android {
+namespace intel {
+
+class PnwOverlayPlane : public OverlayPlaneBase {
+
+public:
+    PnwOverlayPlane(int index, int disp);
+    ~PnwOverlayPlane();
+
+    virtual bool flip();
+    virtual void* getContext() const;
+};
+
+} // namespace intel
+} // namespace android
+
+#endif /* PNW_OVERLAY_PLANE_H */
diff --git a/merrifield/ips/penwell/PnwPrimaryPlane.cpp b/merrifield/ips/penwell/PnwPrimaryPlane.cpp
new file mode 100644
index 0000000..c88d116
--- /dev/null
+++ b/merrifield/ips/penwell/PnwPrimaryPlane.cpp
@@ -0,0 +1,65 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#include <HwcTrace.h>
+#include <Drm.h>
+#include <penwell/PnwPrimaryPlane.h>
+#include <penwell/PnwGrallocBuffer.h>
+#include <common/PixelFormat.h>
+
+namespace android {
+namespace intel {
+
+PnwPrimaryPlane::PnwPrimaryPlane(int index, int disp)
+    : PnwSpritePlane(index, disp)
+{
+    CTRACE();
+    mType = PLANE_PRIMARY;
+}
+
+PnwPrimaryPlane::~PnwPrimaryPlane()
+{
+    CTRACE();
+}
+
+void PnwPrimaryPlane::setFramebufferTarget(DataBuffer& buf)
+{
+    CTRACE();
+    //TODO: implement penwell frame buffer target flip
+}
+
+bool PnwPrimaryPlane::setDataBuffer(uint32_t handle)
+{
+    PnwGrallocBuffer tmpBuf(handle);
+    uint32_t usage;
+
+    ATRACE("handle = %#x", handle);
+
+    usage = tmpBuf.getUsage();
+    if (!handle || (GRALLOC_USAGE_HW_FB & usage)) {
+        setFramebufferTarget(tmpBuf);
+        return true;
+    }
+
+    return DisplayPlane::setDataBuffer(handle);
+}
+
+bool PnwPrimaryPlane::assignToDevice(int disp)
+{
+    return true;
+}
+
+} // namespace intel
+} // namespace android
diff --git a/merrifield/ips/penwell/PnwPrimaryPlane.h b/merrifield/ips/penwell/PnwPrimaryPlane.h
new file mode 100644
index 0000000..7f8b443
--- /dev/null
+++ b/merrifield/ips/penwell/PnwPrimaryPlane.h
@@ -0,0 +1,38 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef PNW_PRIMARY_PLANE_H
+#define PNW_PRIMARY_PLANE_H
+
+#include <penwell/PnwSpritePlane.h>
+
+namespace android {
+namespace intel {
+
+class PnwPrimaryPlane : public PnwSpritePlane {
+public:
+    PnwPrimaryPlane(int index, int disp);
+    ~PnwPrimaryPlane();
+public:
+    bool setDataBuffer(uint32_t handle);
+    bool assignToDevice(int disp);
+private:
+    void setFramebufferTarget(DataBuffer& buf);
+};
+
+} // namespace intel
+} // namespace android
+
+#endif /* TNG_PRIMARY_PLANE_H */
diff --git a/merrifield/ips/penwell/PnwSpritePlane.cpp b/merrifield/ips/penwell/PnwSpritePlane.cpp
new file mode 100644
index 0000000..6799b1a
--- /dev/null
+++ b/merrifield/ips/penwell/PnwSpritePlane.cpp
@@ -0,0 +1,50 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#include <HwcTrace.h>
+#include <Hwcomposer.h>
+#include <BufferManager.h>
+#include <penwell/PnwSpritePlane.h>
+#include <common/PixelFormat.h>
+
+namespace android {
+namespace intel {
+
+PnwSpritePlane::PnwSpritePlane(int index, int disp)
+    : SpritePlaneBase(index, disp)
+{
+    CTRACE();
+}
+
+PnwSpritePlane::~PnwSpritePlane()
+{
+    CTRACE();
+}
+
+bool PnwSpritePlane::setDataBuffer(BufferMapper& mapper)
+{
+    // TODO: implement setDataBuffer
+    return false;
+}
+
+void* PnwSpritePlane::getContext() const
+{
+    CTRACE();
+    // TODO: return penwell sprite context
+    return 0;
+}
+
+} // namespace intel
+} // namespace android
diff --git a/merrifield/ips/penwell/PnwSpritePlane.h b/merrifield/ips/penwell/PnwSpritePlane.h
new file mode 100644
index 0000000..189ef1b
--- /dev/null
+++ b/merrifield/ips/penwell/PnwSpritePlane.h
@@ -0,0 +1,42 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef PNW_SPRITE_PLANE_H
+#define PNW_SPRITE_PLANE_H
+
+#include <utils/KeyedVector.h>
+#include <hal_public.h>
+#include <BufferCache.h>
+#include <DisplayPlane.h>
+
+#include <common/SpritePlaneBase.h>
+
+namespace android {
+namespace intel {
+
+class PnwSpritePlane : public SpritePlaneBase {
+public:
+    PnwSpritePlane(int index, int disp);
+    virtual ~PnwSpritePlane();
+public:
+    virtual void* getContext() const;
+protected:
+    virtual bool setDataBuffer(BufferMapper& mapper);
+};
+
+} // namespace intel
+} // namespace android
+
+#endif /* PNW_SPRITE_PLANE_H */
diff --git a/merrifield/ips/tangier/TngCursorPlane.cpp b/merrifield/ips/tangier/TngCursorPlane.cpp
new file mode 100644
index 0000000..8ce5af7
--- /dev/null
+++ b/merrifield/ips/tangier/TngCursorPlane.cpp
@@ -0,0 +1,244 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#include <HwcTrace.h>
+#include <Hwcomposer.h>
+#include <BufferManager.h>
+#include <BufferManager.h>
+#include <tangier/TngCursorPlane.h>
+#include <tangier/TngGrallocBuffer.h>
+#include <hal_public.h>
+
+namespace android {
+namespace intel {
+
+TngCursorPlane::TngCursorPlane(int index, int disp)
+    : DisplayPlane(index, PLANE_CURSOR, disp)
+{
+    CTRACE();
+    memset(&mContext, 0, sizeof(mContext));
+    memset(&mCrop, 0, sizeof(mCrop));
+}
+
+TngCursorPlane::~TngCursorPlane()
+{
+    CTRACE();
+}
+
+bool TngCursorPlane::enable()
+{
+    return enablePlane(true);
+}
+
+bool TngCursorPlane::disable()
+{
+    return enablePlane(false);
+}
+
+void* TngCursorPlane::getContext() const
+{
+    CTRACE();
+    return (void *)&mContext;
+}
+
+void TngCursorPlane::setZOrderConfig(ZOrderConfig& config, void *nativeConfig)
+{
+    (void) config;
+    (void) nativeConfig;
+
+     VTRACE("\n *** need to implement zorder config *** ");
+    CTRACE();
+}
+
+bool TngCursorPlane::setDataBuffer(buffer_handle_t handle)
+{
+    bool ret;
+
+    if (!handle) {
+        ETRACE("handle is NULL");
+        return false;
+    }
+
+    ret = DisplayPlane::setDataBuffer(handle);
+    if (ret == false) {
+        ETRACE("failed to set data buffer");
+        return ret;
+    }
+
+    return true;
+}
+
+bool TngCursorPlane::setDataBuffer(BufferMapper& mapper)
+{
+    int w = mapper.getWidth();
+    int h = mapper.getHeight();
+    int cursorSize = 0;
+
+    CTRACE();
+
+    // setup plane position
+    int dstX = mPosition.x;
+    int dstY = mPosition.y;
+
+    if (h < w) {
+        cursorSize = h;
+    } else {
+        cursorSize = w;
+    }
+
+    uint32_t cntr = 0;
+    if (64 <= cursorSize && cursorSize < 128) {
+        cursorSize = 64;
+        cntr = 0x7;
+    } else if (128 <= cursorSize && cursorSize < 256) {
+        cursorSize = 128;
+        cntr = 0x2;
+    } else {
+        cursorSize = 256;
+        cntr = 0x3;
+    }
+
+    if (mapper.getFormat() == HAL_PIXEL_FORMAT_RGBA_8888) {
+        cntr |= 1 << 5;
+    } else if (mapper.getFormat() == HAL_PIXEL_FORMAT_BGRA_8888) {
+        // swap color from BGRA to RGBA - alpha is MSB
+        uint8_t *p = (uint8_t *)(mapper.getCpuAddress(0));
+        uint8_t *srcPixel;
+        uint32_t stride = mapper.getStride().rgb.stride;
+        uint8_t temp;
+        if (!p) {
+            return false;
+        }
+
+        for (int i = 0; i < cursorSize; i++) {
+            for (int j = 0; j < cursorSize; j++) {
+                srcPixel = p + i*stride + j*4;
+                temp = srcPixel[0];
+                srcPixel[0] = srcPixel[2];
+                srcPixel[2] = temp;
+            }
+        }
+        cntr |= 1 << 5;
+    } else {
+        ETRACE("invalid color format");
+        return false;
+    }
+
+    // TODO: clean spare mem to be 0 in gralloc instead
+    uint8_t *p = (uint8_t *)(mapper.getCpuAddress(0));
+    uint8_t *srcPixel;
+    uint32_t stride = mapper.getStride().rgb.stride;
+    uint8_t temp;
+    if (!p) {
+        return false;
+    }
+
+    if (mCrop.w == 0 && mCrop.h == 0) {
+        mCrop = mSrcCrop;
+        for (int i = 0; i < cursorSize; i++) {
+            for (int j = 0; j < cursorSize; j++) {
+                srcPixel = p + i*stride + j*4;
+                temp = srcPixel[0];
+                if (i >= mCrop.h || j >= mCrop.w) {
+                    if (srcPixel[0] == 0 &&
+                        srcPixel[3] == 0xff)
+                        srcPixel[3] = 0;
+                }
+            }
+        }
+    }
+
+    // update context
+    mContext.type = DC_CURSOR_PLANE;
+    mContext.ctx.cs_ctx.index = mIndex;
+    mContext.ctx.cs_ctx.pipe = mDevice;
+    mContext.ctx.cs_ctx.cntr = cntr | (mIndex << 28);
+    mContext.ctx.cs_ctx.surf = mapper.getGttOffsetInPage(0) << 12;
+
+    mContext.ctx.cs_ctx.pos = 0;
+    if (dstX < 0) {
+        mContext.ctx.cs_ctx.pos |= 1 << 15;
+        dstX = -dstX;
+    }
+    if (dstY < 0) {
+        mContext.ctx.cs_ctx.pos |= 1 << 31;
+        dstY = -dstY;
+    }
+    mContext.ctx.cs_ctx.pos |= (dstY & 0xfff) << 16 | (dstX & 0xfff);
+    return true;
+}
+
+bool TngCursorPlane::enablePlane(bool enabled)
+{
+    RETURN_FALSE_IF_NOT_INIT();
+
+    struct drm_psb_register_rw_arg arg;
+    memset(&arg, 0, sizeof(struct drm_psb_register_rw_arg));
+    if (enabled) {
+        arg.plane_enable_mask = 1;
+    } else {
+        arg.plane_disable_mask = 1;
+    }
+
+    arg.plane.type = DC_CURSOR_PLANE;
+    arg.plane.index = mIndex;
+    arg.plane.ctx = 0;
+
+    // issue ioctl
+    Drm *drm = Hwcomposer::getInstance().getDrm();
+    bool ret = drm->writeReadIoctl(DRM_PSB_REGISTER_RW, &arg, sizeof(arg));
+    if (ret == false) {
+        WTRACE("plane enabling (%d) failed with error code %d", enabled, ret);
+        return false;
+    }
+
+    return true;
+}
+
+bool TngCursorPlane::isDisabled()
+{
+    RETURN_FALSE_IF_NOT_INIT();
+
+    struct drm_psb_register_rw_arg arg;
+    memset(&arg, 0, sizeof(struct drm_psb_register_rw_arg));
+
+    arg.plane.type = DC_CURSOR_PLANE;
+    arg.get_plane_state_mask = 1;
+    arg.plane.index = mIndex;
+    arg.plane.ctx = 0;
+
+    // issue ioctl
+    Drm *drm = Hwcomposer::getInstance().getDrm();
+    bool ret = drm->writeReadIoctl(DRM_PSB_REGISTER_RW, &arg, sizeof(arg));
+    if (ret == false) {
+        WTRACE("plane state query failed with error code %d", ret);
+        return false;
+    }
+
+	return arg.plane.ctx == PSB_DC_PLANE_DISABLED;
+    //return arg.plane.ctx == 0; //implement this PSB_DC_PLANE_DISABLED similar in imin_legacy
+
+	return true;
+}
+
+void TngCursorPlane::postFlip()
+{
+    // prevent mUpdateMasks from being reset
+    // skipping flip may cause flicking
+}
+
+} // namespace intel
+} // namespace android
diff --git a/merrifield/ips/tangier/TngCursorPlane.h b/merrifield/ips/tangier/TngCursorPlane.h
new file mode 100644
index 0000000..85e869a
--- /dev/null
+++ b/merrifield/ips/tangier/TngCursorPlane.h
@@ -0,0 +1,58 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#ifndef TNG_CUR_PLANE_H
+#define TNG_CUR_PLANE_H
+
+#include <utils/KeyedVector.h>
+#include <hal_public.h>
+#include <Hwcomposer.h>
+#include <BufferCache.h>
+#include <DisplayPlane.h>
+
+#include <linux/psb_drm.h>
+
+namespace android {
+namespace intel {
+
+class TngCursorPlane : public DisplayPlane {
+public:
+    TngCursorPlane(int index, int disp);
+    virtual ~TngCursorPlane();
+public:
+    // hardware operations
+    bool enable();
+    bool disable();
+    bool isDisabled();
+    void postFlip();
+
+    void* getContext() const;
+    void setZOrderConfig(ZOrderConfig& config, void *nativeConfig);
+
+    bool setDataBuffer(buffer_handle_t handle);
+protected:
+    bool setDataBuffer(BufferMapper& mapper);
+    bool enablePlane(bool enabled);
+
+protected:
+    struct intel_dc_plane_ctx mContext;
+    crop_t mCrop;
+};
+
+} // namespace intel
+} // namespace android
+
+#endif /* TNG_CUR_PLANE_H */
diff --git a/merrifield/ips/tangier/TngDisplayContext.cpp b/merrifield/ips/tangier/TngDisplayContext.cpp
new file mode 100644
index 0000000..7f94185
--- /dev/null
+++ b/merrifield/ips/tangier/TngDisplayContext.cpp
@@ -0,0 +1,278 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#include <HwcTrace.h>
+#include <Hwcomposer.h>
+#include <Drm.h>
+#include <DisplayPlane.h>
+#include <IDisplayDevice.h>
+#include <HwcLayerList.h>
+#include <tangier/TngDisplayContext.h>
+
+
+namespace android {
+namespace intel {
+
+TngDisplayContext::TngDisplayContext()
+    : mIMGDisplayDevice(0),
+      mInitialized(false),
+      mCount(0)
+{
+    CTRACE();
+}
+
+TngDisplayContext::~TngDisplayContext()
+{
+    WARN_IF_NOT_DEINIT();
+}
+
+bool TngDisplayContext::initialize()
+{
+    CTRACE();
+
+    // open frame buffer device
+    hw_module_t const* module;
+    int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
+    if (err) {
+        ETRACE("failed to load gralloc module, error = %d", err);
+        return false;
+    }
+
+    // init IMG display device
+    mIMGDisplayDevice = (((IMG_gralloc_module_public_t *)module)->getDisplayDevice((IMG_gralloc_module_public_t *)module));
+    if (!mIMGDisplayDevice) {
+        ETRACE("failed to get display device");
+        return false;
+    }
+
+    mCount = 0;
+    mInitialized = true;
+    return true;
+}
+
+bool TngDisplayContext::commitBegin(size_t numDisplays, hwc_display_contents_1_t **displays)
+{
+    RETURN_FALSE_IF_NOT_INIT();
+    mCount = 0;
+    return true;
+}
+
+bool TngDisplayContext::commitContents(hwc_display_contents_1_t *display, HwcLayerList *layerList)
+{
+    bool ret;
+
+    RETURN_FALSE_IF_NOT_INIT();
+
+    if (!display || !layerList) {
+        ETRACE("invalid parameters");
+        return false;
+    }
+
+    IMG_hwc_layer_t *imgLayerList = (IMG_hwc_layer_t*)mImgLayers;
+
+    for (size_t i = 0; i < display->numHwLayers; i++) {
+        if (mCount >= MAXIMUM_LAYER_NUMBER) {
+            ETRACE("layer count exceeds the limit");
+            return false;
+        }
+
+        // check layer parameters
+        if (!display->hwLayers[i].handle) {
+            continue;
+        }
+
+        DisplayPlane* plane = layerList->getPlane(i);
+        if (!plane) {
+            continue;
+        }
+
+        ret = plane->flip(NULL);
+        if (ret == false) {
+            VTRACE("failed to flip plane %d", i);
+            continue;
+        }
+
+        IMG_hwc_layer_t *imgLayer = &imgLayerList[mCount++];
+        // update IMG layer
+        imgLayer->psLayer = &display->hwLayers[i];
+        imgLayer->custom = (unsigned long)plane->getContext();
+        struct intel_dc_plane_ctx *ctx =
+            (struct intel_dc_plane_ctx *)imgLayer->custom;
+        // update z order
+        Hwcomposer& hwc = Hwcomposer::getInstance();
+        DisplayPlaneManager *pm = hwc.getPlaneManager();
+        void *config = pm->getZOrderConfig();
+        if (config) {
+            memcpy(&ctx->zorder, config, sizeof(ctx->zorder));
+        } else {
+            memset(&ctx->zorder, 0, sizeof(ctx->zorder));
+        }
+
+        VTRACE("count %p, handle %#x, trans %#x, blending %#x"
+              " sourceCrop %f,%f - %fx%f, dst %d,%d - %dx%d, custom %#x",
+              mCount,
+              imgLayer->psLayer->handle,
+              imgLayer->psLayer->transform,
+              imgLayer->psLayer->blending,
+              imgLayer->psLayer->sourceCropf.left,
+              imgLayer->psLayer->sourceCropf.top,
+              imgLayer->psLayer->sourceCropf.right - imgLayer->psLayer->sourceCropf.left,
+              imgLayer->psLayer->sourceCropf.bottom - imgLayer->psLayer->sourceCropf.top,
+              imgLayer->psLayer->displayFrame.left,
+              imgLayer->psLayer->displayFrame.top,
+              imgLayer->psLayer->displayFrame.right - imgLayer->psLayer->displayFrame.left,
+              imgLayer->psLayer->displayFrame.bottom - imgLayer->psLayer->displayFrame.top,
+              imgLayer->custom);
+    }
+
+    layerList->postFlip();
+    return true;
+}
+
+bool TngDisplayContext::commitEnd(size_t numDisplays, hwc_display_contents_1_t **displays)
+{
+    int releaseFenceFd = -1;
+
+    VTRACE("count = %d", mCount);
+
+    if (mIMGDisplayDevice && mCount) {
+        int err = mIMGDisplayDevice->post(mIMGDisplayDevice,
+                                          mImgLayers,
+                                          mCount,
+                                          &releaseFenceFd);
+        if (err) {
+            ETRACE("post failed, err = %d", err);
+            return false;
+        }
+    }
+
+    // close acquire fence
+    for (size_t i = 0; i < numDisplays; i++) {
+        // Wait and close HWC_OVERLAY typed layer's acquire fence
+        hwc_display_contents_1_t* display = displays[i];
+        if (!display) {
+            continue;
+        }
+
+        for (size_t j = 0; j < display->numHwLayers-1; j++) {
+            hwc_layer_1_t& layer = display->hwLayers[j];
+            if (layer.compositionType == HWC_OVERLAY) {
+                if (layer.acquireFenceFd != -1) {
+                    // sync_wait(layer.acquireFenceFd, 16ms);
+                    close(layer.acquireFenceFd);
+                    layer.acquireFenceFd = -1;
+                }
+            }
+        }
+
+        // Wait and close framebuffer target layer's acquire fence
+        hwc_layer_1_t& fbt = display->hwLayers[display->numHwLayers-1];
+        if (fbt.acquireFenceFd != -1) {
+            // sync_wait(fbt.acquireFencdFd, 16ms);
+            close(fbt.acquireFenceFd);
+            fbt.acquireFenceFd = -1;
+        }
+
+        // Wait and close outbuf's acquire fence
+        if (display->outbufAcquireFenceFd != -1) {
+            // sync_wait(display->outbufAcquireFenceFd, 16ms);
+            close(display->outbufAcquireFenceFd);
+            display->outbufAcquireFenceFd = -1;
+        }
+    }
+
+    // update release fence and retire fence
+    if (mCount > 0) {
+        // For physical displays, dup the releaseFenceFd only for
+        // HWC layers which successfully flipped to display planes
+        IMG_hwc_layer_t *imgLayerList = (IMG_hwc_layer_t*)mImgLayers;
+
+        for (unsigned int i = 0; i < mCount; i++) {
+            IMG_hwc_layer_t *imgLayer = &imgLayerList[i];
+            imgLayer->psLayer->releaseFenceFd =
+                (releaseFenceFd != -1) ? dup(releaseFenceFd) : -1;
+        }
+    }
+
+    for (size_t i = 0; i < numDisplays; i++) {
+        if (!displays[i]) {
+            continue;
+        }
+
+        // log for layer fence status
+        for (size_t j = 0; j < displays[i]->numHwLayers; j++) {
+            VTRACE("handle %#p, acquiredFD %d, releaseFD %d",
+                 displays[i]->hwLayers[j].handle,
+                 displays[i]->hwLayers[j].acquireFenceFd,
+                 displays[i]->hwLayers[j].releaseFenceFd);
+        }
+
+#ifdef INTEL_WIDI_MERRIFIELD
+        // retireFence is used for SurfaceFlinger to do DispSync;
+        // dup releaseFenceFd for physical displays and ignore virtual
+        // display; we don't distinguish between release and retire, and all
+        // physical displays are using a single releaseFence; for virtual
+        // display, fencing is handled by the VirtualDisplay class
+        if (i < IDisplayDevice::DEVICE_VIRTUAL) {
+#endif
+            displays[i]->retireFenceFd =
+                (releaseFenceFd != -1) ? dup(releaseFenceFd) : -1;
+#ifdef INTEL_WIDI_MERRIFIELD
+        }
+#endif
+    }
+
+    // close original release fence fd
+    if (releaseFenceFd != -1) {
+        close(releaseFenceFd);
+    }
+    return true;
+}
+
+bool TngDisplayContext::compositionComplete()
+{
+    return true;
+}
+
+bool TngDisplayContext::setCursorPosition(int disp, int x, int y)
+{
+    DTRACE("setCursorPosition");
+    struct intel_dc_cursor_ctx ctx;
+    memset(&ctx, 0, sizeof(ctx));
+    ctx.pipe = disp;
+    if (x < 0) {
+        ctx.pos |= 1 << 15;
+        x = -x;
+    }
+    if (y < 0) {
+        ctx.pos |= 1 << 31;
+        y = -y;
+    }
+    ctx.pos |= (y & 0xfff) << 16 | (x & 0xfff);
+    Drm *drm = Hwcomposer::getInstance().getDrm();
+    return drm->writeIoctl(DRM_PSB_UPDATE_CURSOR_POS, &ctx, sizeof(ctx));
+}
+
+void TngDisplayContext::deinitialize()
+{
+    mIMGDisplayDevice = 0;
+
+    mCount = 0;
+    mInitialized = false;
+}
+
+
+} // namespace intel
+} // namespace android
diff --git a/merrifield/ips/tangier/TngDisplayContext.h b/merrifield/ips/tangier/TngDisplayContext.h
new file mode 100644
index 0000000..fa526d7
--- /dev/null
+++ b/merrifield/ips/tangier/TngDisplayContext.h
@@ -0,0 +1,51 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef TNG_DISPLAY_CONTEXT_H
+#define TNG_DISPLAY_CONTEXT_H
+
+#include <IDisplayContext.h>
+#include <hal_public.h>
+
+namespace android {
+namespace intel {
+
+class TngDisplayContext : public IDisplayContext {
+public:
+    TngDisplayContext();
+    virtual ~TngDisplayContext();
+public:
+    bool initialize();
+    void deinitialize();
+    bool commitBegin(size_t numDisplays, hwc_display_contents_1_t **displays);
+    bool commitContents(hwc_display_contents_1_t *display, HwcLayerList* layerList);
+    bool commitEnd(size_t numDisplays, hwc_display_contents_1_t **displays);
+    bool compositionComplete();
+    bool setCursorPosition(int disp, int x, int y);
+
+private:
+    enum {
+        MAXIMUM_LAYER_NUMBER = 20,
+    };
+    IMG_display_device_public_t *mIMGDisplayDevice;
+    IMG_hwc_layer_t mImgLayers[MAXIMUM_LAYER_NUMBER];
+    bool mInitialized;
+    size_t mCount;
+};
+
+} // namespace intel
+} // namespace android
+
+#endif /* TNG_DISPLAY_CONTEXT_H */
diff --git a/merrifield/ips/tangier/TngDisplayQuery.cpp b/merrifield/ips/tangier/TngDisplayQuery.cpp
new file mode 100644
index 0000000..c25aecf
--- /dev/null
+++ b/merrifield/ips/tangier/TngDisplayQuery.cpp
@@ -0,0 +1,63 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#include <HwcTrace.h>
+#include <DisplayPlane.h>
+#include <hal_public.h>
+#include <OMX_IVCommon.h>
+#include <OMX_IntelVideoExt.h>
+#include <DisplayQuery.h>
+
+
+namespace android {
+namespace intel {
+
+bool DisplayQuery::isVideoFormat(uint32_t format)
+{
+    switch (format) {
+    case OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar:
+    case OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar_Tiled:
+    // Expand format to support the case: Software decoder + HW rendering
+    // Only VP9 use this foramt now
+    case HAL_PIXEL_FORMAT_YV12:
+        return true;
+    default:
+        return false;
+    }
+}
+
+int DisplayQuery::getOverlayLumaStrideAlignment(uint32_t format)
+{
+    // both luma and chroma stride need to be 64-byte aligned for overlay
+    switch (format) {
+    case HAL_PIXEL_FORMAT_YV12:
+    case HAL_PIXEL_FORMAT_I420:
+        // for these two formats, chroma stride is calculated as half of luma stride
+        // so luma stride needs to be 128-byte aligned.
+        return 128;
+    default:
+        return 64;
+    }
+}
+
+uint32_t DisplayQuery::queryNV12Format()
+{
+    return HAL_PIXEL_FORMAT_NV12;
+}
+
+} // namespace intel
+} // namespace android
+
diff --git a/merrifield/ips/tangier/TngGrallocBuffer.cpp b/merrifield/ips/tangier/TngGrallocBuffer.cpp
new file mode 100644
index 0000000..b66b896
--- /dev/null
+++ b/merrifield/ips/tangier/TngGrallocBuffer.cpp
@@ -0,0 +1,62 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#include <HwcTrace.h>
+#include <tangier/TngGrallocBuffer.h>
+
+namespace android {
+namespace intel {
+
+TngGrallocBuffer::TngGrallocBuffer(buffer_handle_t handle)
+    :GrallocBufferBase(handle)
+{
+    initBuffer(handle);
+}
+
+TngGrallocBuffer::~TngGrallocBuffer()
+{
+}
+
+void TngGrallocBuffer::resetBuffer(buffer_handle_t handle)
+{
+    GrallocBufferBase::resetBuffer(handle);
+    initBuffer(handle);
+}
+
+void TngGrallocBuffer::initBuffer(buffer_handle_t handle)
+{
+    TngIMGGrallocBuffer *grallocHandle = (TngIMGGrallocBuffer *)handle;
+
+    CTRACE();
+
+    if (!grallocHandle) {
+        ETRACE("gralloc handle is null");
+        return;
+    }
+
+    mFormat = grallocHandle->iFormat;
+    mWidth = grallocHandle->iWidth;
+    mHeight = grallocHandle->iHeight;
+    mUsage = grallocHandle->usage;
+    mKey = grallocHandle->ui64Stamp;
+    mBpp = grallocHandle->uiBpp;
+
+    // stride can only be initialized after format is set
+    initStride();
+}
+
+
+}
+}
diff --git a/merrifield/ips/tangier/TngGrallocBuffer.h b/merrifield/ips/tangier/TngGrallocBuffer.h
new file mode 100644
index 0000000..b528cf8
--- /dev/null
+++ b/merrifield/ips/tangier/TngGrallocBuffer.h
@@ -0,0 +1,44 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef TNG_GRALLOC_BUFFER_H
+#define TNG_GRALLOC_BUFFER_H
+
+#include <DataBuffer.h>
+#include <hal_public.h>
+#include <common/GrallocSubBuffer.h>
+#include <common/GrallocBufferBase.h>
+
+namespace android {
+namespace intel {
+
+typedef IMG_native_handle_t TngIMGGrallocBuffer;
+
+class TngGrallocBuffer : public GrallocBufferBase {
+public:
+    TngGrallocBuffer(buffer_handle_t handle);
+    virtual ~TngGrallocBuffer();
+
+    void resetBuffer(buffer_handle_t handle);
+
+private:
+    void initBuffer(buffer_handle_t handle);
+};
+
+} // namespace intel
+} // namespace android
+
+
+#endif /* TNG_GRALLOC_BUFFER_H */
diff --git a/merrifield/ips/tangier/TngGrallocBufferMapper.cpp b/merrifield/ips/tangier/TngGrallocBufferMapper.cpp
new file mode 100644
index 0000000..fcf40e7
--- /dev/null
+++ b/merrifield/ips/tangier/TngGrallocBufferMapper.cpp
@@ -0,0 +1,263 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#include <HwcTrace.h>
+#include <Drm.h>
+#include <Hwcomposer.h>
+#include <tangier/TngGrallocBufferMapper.h>
+#include <common/WsbmWrapper.h>
+
+namespace android {
+namespace intel {
+
+TngGrallocBufferMapper::TngGrallocBufferMapper(IMG_gralloc_module_public_t& module,
+                                                    DataBuffer& buffer)
+    : GrallocBufferMapperBase(buffer),
+      mIMGGrallocModule(module),
+      mBufferObject(0)
+{
+    CTRACE();
+
+	const native_handle_t *h = (native_handle_t *)mHandle;
+
+	mClonedHandle = native_handle_create(h->numFds, h->numInts);
+	if (mClonedHandle == 0) {
+		ALOGE("%s:Failed to create handle, out of memory!");
+		return;
+	}
+	for (int i = 0; i < h->numFds; i++)
+	{
+		mClonedHandle->data[i] = (h->data[i] >= 0) ? dup(h->data[i]) : -1;
+	}
+	memcpy(mClonedHandle->data + h->numFds, h->data + h->numFds, h->numInts*sizeof(int));
+}
+
+TngGrallocBufferMapper::~TngGrallocBufferMapper()
+{
+    CTRACE();
+
+	if (mClonedHandle == 0)
+		return;
+	native_handle_close(mClonedHandle);
+	native_handle_delete(mClonedHandle);
+}
+
+bool TngGrallocBufferMapper::gttMap(void *vaddr,
+                                      uint32_t size,
+                                      uint32_t gttAlign,
+                                      int *offset)
+{
+    struct psb_gtt_mapping_arg arg;
+    bool ret;
+
+    ATRACE("vaddr = %p, size = %d", vaddr, size);
+
+    if (!vaddr || !size || !offset) {
+        VTRACE("invalid parameters");
+        return false;
+    }
+
+    arg.type = PSB_GTT_MAP_TYPE_VIRTUAL;
+    arg.page_align = gttAlign;
+    arg.vaddr = (unsigned long)vaddr;
+    arg.size = size;
+
+    Drm *drm = Hwcomposer::getInstance().getDrm();
+    ret = drm->writeReadIoctl(DRM_PSB_GTT_MAP, &arg, sizeof(arg));
+    if (ret == false) {
+        ETRACE("gtt mapping failed");
+        return false;
+    }
+
+    VTRACE("offset = %#x", arg.offset_pages);
+    *offset =  arg.offset_pages;
+    return true;
+}
+
+bool TngGrallocBufferMapper::gttUnmap(void *vaddr)
+{
+    struct psb_gtt_mapping_arg arg;
+    bool ret;
+
+    ATRACE("vaddr = %p", vaddr);
+
+    if (!vaddr) {
+        ETRACE("invalid parameter");
+        return false;
+    }
+
+    arg.type = PSB_GTT_MAP_TYPE_VIRTUAL;
+    arg.vaddr = (unsigned long)vaddr;
+
+    Drm *drm = Hwcomposer::getInstance().getDrm();
+    ret = drm->writeIoctl(DRM_PSB_GTT_UNMAP, &arg, sizeof(arg));
+    if (ret == false) {
+        ETRACE("gtt unmapping failed");
+        return false;
+    }
+
+    return true;
+}
+
+bool TngGrallocBufferMapper::map()
+{
+    void *vaddr[SUB_BUFFER_MAX];
+    uint32_t size[SUB_BUFFER_MAX];
+    int gttOffsetInPage = 0;
+    bool ret;
+    int err;
+    int i;
+
+    CTRACE();
+    // get virtual address
+    err = mIMGGrallocModule.getCpuAddress(&mIMGGrallocModule,
+                                          (buffer_handle_t)mClonedHandle,
+                                          vaddr,
+                                          size);
+    if (err) {
+        ETRACE("failed to map. err = %d", err);
+        return false;
+    }
+
+    for (i = 0; i < SUB_BUFFER_MAX; i++) {
+        // skip gtt mapping for empty sub buffers
+        if (!vaddr[i] || !size[i])
+            continue;
+
+        // map to gtt
+        ret = gttMap(vaddr[i], size[i], 0, &gttOffsetInPage);
+        if (!ret) {
+            VTRACE("failed to map %d into gtt", i);
+            break;
+        }
+
+        mCpuAddress[i] = vaddr[i];
+        mSize[i] = size[i];
+        mGttOffsetInPage[i] = gttOffsetInPage;
+        // TODO:  set kernel handle
+        mKHandle[i] = 0;
+    }
+
+    if (i == SUB_BUFFER_MAX) {
+        return true;
+    }
+
+    // error handling
+    for (i = 0; i < SUB_BUFFER_MAX; i++) {
+        if (mCpuAddress[i]) {
+            gttUnmap(mCpuAddress[i]);
+        }
+    }
+
+    err = mIMGGrallocModule.putCpuAddress(&mIMGGrallocModule,
+                                    (buffer_handle_t)mClonedHandle);
+    return false;
+}
+
+bool TngGrallocBufferMapper::unmap()
+{
+    int i;
+    int err;
+
+    CTRACE();
+
+    for (i = 0; i < SUB_BUFFER_MAX; i++) {
+        if (mCpuAddress[i])
+            gttUnmap(mCpuAddress[i]);
+
+        mGttOffsetInPage[i] = 0;
+        mCpuAddress[i] = 0;
+        mSize[i] = 0;
+    }
+
+    err = mIMGGrallocModule.putCpuAddress(&mIMGGrallocModule,
+                                    (buffer_handle_t)mClonedHandle);
+    if (err) {
+        ETRACE("failed to unmap. err = %d", err);
+    }
+    return err;
+}
+
+buffer_handle_t TngGrallocBufferMapper::getKHandle(int subIndex)
+{
+    buffer_handle_t ret = GrallocBufferMapperBase::getKHandle(subIndex);
+    if (subIndex == 0 && ret == 0) {
+        if (mapKhandle())
+            return mKHandle[subIndex];
+    }
+
+    return ret;
+}
+
+bool TngGrallocBufferMapper::mapKhandle()
+{
+    // TODO: this is a complete hack and temporary workaround
+    // need support from DDK to map khandle
+    void *wsbmBufferObject = 0;
+    int ret = psbWsbmWrapTTMBuffer2((uint64_t)mHandle, &wsbmBufferObject);
+    if (ret != 0) {
+        ETRACE("Wrap ttm buffer failed!");
+        return false;
+    }
+
+    ret = psbWsbmCreateFromUB(wsbmBufferObject, mWidth * mHeight, mCpuAddress[0]);
+    if (ret != 0) {
+        ETRACE("Create from UB failed!");
+        return false;
+    }
+
+    mKHandle[0] = (buffer_handle_t)(unsigned long)psbWsbmGetKBufHandle(wsbmBufferObject);
+    psbWsbmUnReference(wsbmBufferObject);
+    return true;
+}
+
+buffer_handle_t TngGrallocBufferMapper::getFbHandle(int subIndex)
+{
+    void *vaddr[SUB_BUFFER_MAX];
+    uint32_t size[SUB_BUFFER_MAX];
+    int err;
+
+    CTRACE();
+
+    if (subIndex < 0 || subIndex >= SUB_BUFFER_MAX) {
+        return 0;
+    }
+
+    // get virtual address
+    err = mIMGGrallocModule.getCpuAddress(&mIMGGrallocModule,
+                                          (buffer_handle_t)mClonedHandle,
+                                          vaddr,
+                                          size);
+    if (err) {
+        ETRACE("failed to map. err = %d", err);
+        return 0;
+    }
+
+    return (buffer_handle_t)vaddr[subIndex];
+}
+
+void TngGrallocBufferMapper::putFbHandle()
+{
+    int err = mIMGGrallocModule.putCpuAddress(&mIMGGrallocModule,
+                                    (buffer_handle_t)mClonedHandle);
+    if (err) {
+        ETRACE("failed to unmap. err = %d", err);
+    }
+    return;
+
+}
+
+} // namespace intel
+} // namespace android
diff --git a/merrifield/ips/tangier/TngGrallocBufferMapper.h b/merrifield/ips/tangier/TngGrallocBufferMapper.h
new file mode 100644
index 0000000..d72005e
--- /dev/null
+++ b/merrifield/ips/tangier/TngGrallocBufferMapper.h
@@ -0,0 +1,52 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef TNG_GRALLOC_BUFFER_MAPPER_H
+#define TNG_GRALLOC_BUFFER_MAPPER_H
+
+#include <BufferMapper.h>
+#include <hal_public.h>
+#include <common/GrallocBufferMapperBase.h>
+#include <tangier/TngGrallocBuffer.h>
+
+namespace android {
+namespace intel {
+
+class TngGrallocBufferMapper : public GrallocBufferMapperBase {
+public:
+    TngGrallocBufferMapper(IMG_gralloc_module_public_t& module,
+                               DataBuffer& buffer);
+    virtual ~TngGrallocBufferMapper();
+public:
+    bool map();
+    bool unmap();
+    buffer_handle_t getKHandle(int subIndex);
+    buffer_handle_t getFbHandle(int subIndex);
+    void putFbHandle();
+private:
+    bool gttMap(void *vaddr, uint32_t size, uint32_t gttAlign, int *offset);
+    bool gttUnmap(void *vaddr);
+    bool mapKhandle();
+
+private:
+    IMG_gralloc_module_public_t& mIMGGrallocModule;
+    void* mBufferObject;
+	native_handle_t* mClonedHandle;
+};
+
+} // namespace intel
+} // namespace android
+
+#endif /* TNG_GRALLOC_BUFFER_MAPPER_H */
diff --git a/merrifield/ips/tangier/TngOverlayPlane.cpp b/merrifield/ips/tangier/TngOverlayPlane.cpp
new file mode 100644
index 0000000..d837015
--- /dev/null
+++ b/merrifield/ips/tangier/TngOverlayPlane.cpp
@@ -0,0 +1,218 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#include <math.h>
+#include <HwcTrace.h>
+#include <Drm.h>
+#include <Hwcomposer.h>
+#include <tangier/TngOverlayPlane.h>
+#include <tangier/TngGrallocBuffer.h>
+
+namespace android {
+namespace intel {
+
+TngOverlayPlane::TngOverlayPlane(int index, int disp)
+    : OverlayPlaneBase(index, disp),
+      mRotationBufProvider(NULL)
+{
+    CTRACE();
+
+    memset(&mContext, 0, sizeof(mContext));
+}
+
+TngOverlayPlane::~TngOverlayPlane()
+{
+    CTRACE();
+}
+
+bool TngOverlayPlane::flip(void *ctx)
+{
+    RETURN_FALSE_IF_NOT_INIT();
+
+    if (!DisplayPlane::flip(ctx))
+        return false;
+
+    mContext.type = DC_OVERLAY_PLANE;
+    mContext.ctx.ov_ctx.ovadd = 0x0;
+    mContext.ctx.ov_ctx.ovadd = (mBackBuffer[mCurrent]->gttOffsetInPage << 12);
+    mContext.ctx.ov_ctx.index = mIndex;
+    mContext.ctx.ov_ctx.pipe = mDevice;
+    mContext.ctx.ov_ctx.ovadd |= mPipeConfig;
+    mContext.ctx.ov_ctx.ovadd |= 0x1;
+
+    // move to next back buffer
+    //mCurrent = (mCurrent + 1) % OVERLAY_BACK_BUFFER_COUNT;
+
+    VTRACE("ovadd = %#x, index = %d, device = %d",
+          mContext.ctx.ov_ctx.ovadd,
+          mIndex,
+          mDevice);
+
+    return true;
+}
+
+bool TngOverlayPlane::reset()
+{
+    OverlayPlaneBase::reset();
+    if (mRotationBufProvider)
+        mRotationBufProvider->reset();
+    return true;
+}
+
+void* TngOverlayPlane::getContext() const
+{
+    CTRACE();
+    return (void *)&mContext;
+}
+
+bool TngOverlayPlane::setDataBuffer(BufferMapper& mapper)
+{
+    if (OverlayPlaneBase::setDataBuffer(mapper) == false) {
+        return false;
+    }
+
+    if (mIsProtectedBuffer) {
+        // Bit 0: Decryption request, only allowed to change on a synchronous flip
+        // This request will be qualified with the separate decryption enable bit for OV
+        mBackBuffer[mCurrent]->buf->OSTART_0Y |= 0x1;
+        mBackBuffer[mCurrent]->buf->OSTART_1Y |= 0x1;
+    }
+
+    mContext.gtt_key = (uint64_t)mapper.getCpuAddress(0);
+    return true;
+}
+
+bool TngOverlayPlane::initialize(uint32_t bufferCount)
+{
+    if (!OverlayPlaneBase::initialize(bufferCount)) {
+        ETRACE("failed to initialize OverlayPlaneBase");
+        return false;
+    }
+
+    // setup rotation buffer
+    mRotationBufProvider = new RotationBufferProvider(mWsbm);
+    if (!mRotationBufProvider || !mRotationBufProvider->initialize()) {
+        DEINIT_AND_RETURN_FALSE("failed to initialize RotationBufferProvider");
+    }
+    return true;
+}
+
+void TngOverlayPlane::deinitialize()
+{
+    DEINIT_AND_DELETE_OBJ(mRotationBufProvider);
+    OverlayPlaneBase::deinitialize();
+}
+
+bool TngOverlayPlane::rotatedBufferReady(BufferMapper& mapper, BufferMapper* &rotatedMapper)
+{
+    struct VideoPayloadBuffer *payload;
+    VideoPayloadBuffer buffer_info;
+    uint32_t format;
+    // only NV12_VED has rotated buffer
+    format = mapper.getFormat();
+
+    if (format != OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar &&
+        format != OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar_Tiled &&
+        format != HAL_PIXEL_FORMAT_NV12) {
+        ETRACE("Invalid video format %#x", format);
+        return false;
+    }
+
+    payload = (struct VideoPayloadBuffer *)mapper.getCpuAddress(SUB_BUFFER1);
+
+    if (payload == NULL && format == HAL_PIXEL_FORMAT_NV12) {
+         // need to populate buffer_info
+        void *p = mapper.getCpuAddress(SUB_BUFFER0);
+        if (!p) {
+            ETRACE("failed to get buffer user pointer");
+            return false;
+        }
+
+        bool ret = mRotationBufProvider->prepareBufferInfo(mapper.getWidth(),
+                                                mapper.getHeight(),
+                                                mapper.getStride().yuv.yStride,
+                                                &buffer_info, p);
+        if (ret == false) {
+            ETRACE("failed to prepare buffer info");
+            return false;
+        }
+        payload = &buffer_info;
+    }
+
+    // check payload
+    if (!payload) {
+        ETRACE("no payload found");
+        return false;
+    }
+
+    if (payload->force_output_method == FORCE_OUTPUT_GPU) {
+        ETRACE("Output method is not supported!");
+        return false;
+    }
+
+    if (payload->client_transform != mTransform ||
+        mBobDeinterlace) {
+        payload->hwc_timestamp = systemTime();
+        payload->layer_transform = mTransform;
+        if (!mRotationBufProvider->setupRotationBuffer(payload, mTransform)) {
+            ETRACE("failed to setup rotation buffer");
+            return false;
+        }
+    }
+
+    rotatedMapper = getTTMMapper(mapper, payload);
+
+    return true;
+}
+
+bool TngOverlayPlane::flush(uint32_t flags)
+{
+    RETURN_FALSE_IF_NOT_INIT();
+    ATRACE("flags = %#x, type = %d, index = %d", flags, mType, mIndex);
+
+    if (!(flags & PLANE_ENABLE) && !(flags & PLANE_DISABLE))
+        return false;
+
+    struct drm_psb_register_rw_arg arg;
+    memset(&arg, 0, sizeof(struct drm_psb_register_rw_arg));
+
+    if (flags & PLANE_DISABLE)
+        arg.plane_disable_mask = 1;
+    else if (flags & PLANE_ENABLE)
+        arg.plane_enable_mask = 1;
+
+    arg.plane.type = DC_OVERLAY_PLANE;
+    arg.plane.index = mIndex;
+    arg.plane.ctx = (mBackBuffer[mCurrent]->gttOffsetInPage << 12);
+    // pipe select
+    arg.plane.ctx |= mPipeConfig;
+
+    if (flags & PLANE_DISABLE) {
+        DTRACE("disabling overlay %d on device %d", mIndex, mDevice);
+    }
+
+    // issue ioctl
+    Drm *drm = Hwcomposer::getInstance().getDrm();
+    bool ret = drm->writeReadIoctl(DRM_PSB_REGISTER_RW, &arg, sizeof(arg));
+    if (ret == false) {
+        WTRACE("overlay update failed with error code %d", ret);
+        return false;
+    }
+
+    return true;
+}
+
+} // namespace intel
+} // namespace android
diff --git a/merrifield/ips/tangier/TngOverlayPlane.h b/merrifield/ips/tangier/TngOverlayPlane.h
new file mode 100644
index 0000000..9129965
--- /dev/null
+++ b/merrifield/ips/tangier/TngOverlayPlane.h
@@ -0,0 +1,55 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef TNG_OVERLAY_PLANE_H
+#define TNG_OVERLAY_PLANE_H
+
+#include <utils/KeyedVector.h>
+#include <hal_public.h>
+#include <DisplayPlane.h>
+#include <BufferMapper.h>
+#include <common/Wsbm.h>
+#include <common/OverlayPlaneBase.h>
+#include <common/RotationBufferProvider.h>
+
+namespace android {
+namespace intel {
+
+class TngOverlayPlane : public OverlayPlaneBase {
+
+public:
+    TngOverlayPlane(int index, int disp);
+    virtual ~TngOverlayPlane();
+
+    virtual bool flip(void *ctx);
+    virtual bool reset();
+    virtual void* getContext() const;
+
+    virtual bool initialize(uint32_t bufferCount);
+    virtual void deinitialize();
+    virtual bool rotatedBufferReady(BufferMapper& mapper, BufferMapper* &rotatedMapper);
+protected:
+    virtual bool setDataBuffer(BufferMapper& mapper);
+    virtual bool flush(uint32_t flags);
+
+protected:
+    struct intel_dc_plane_ctx mContext;
+    RotationBufferProvider *mRotationBufProvider;
+};
+
+} // namespace intel
+} // namespace android
+
+#endif /* TNG_OVERLAY_PLANE_H */
diff --git a/merrifield/ips/tangier/TngPlaneManager.cpp b/merrifield/ips/tangier/TngPlaneManager.cpp
new file mode 100644
index 0000000..d973aa9
--- /dev/null
+++ b/merrifield/ips/tangier/TngPlaneManager.cpp
@@ -0,0 +1,196 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#include <HwcTrace.h>
+#include <tangier/TngPlaneManager.h>
+#include <tangier/TngPrimaryPlane.h>
+#include <tangier/TngSpritePlane.h>
+#include <tangier/TngOverlayPlane.h>
+#include <tangier/TngCursorPlane.h>
+
+namespace android {
+namespace intel {
+
+TngPlaneManager::TngPlaneManager()
+    : DisplayPlaneManager()
+{
+    memset(&mZorder, 0, sizeof(mZorder));
+}
+
+TngPlaneManager::~TngPlaneManager()
+{
+}
+
+bool TngPlaneManager::initialize()
+{
+    mSpritePlaneCount = 1;  // Sprite D
+    mOverlayPlaneCount = 2;  // Overlay A & C
+    mPrimaryPlaneCount = 3;  // Primary A, B, C
+    mCursorPlaneCount = 3;
+
+    return DisplayPlaneManager::initialize();
+}
+
+void TngPlaneManager::deinitialize()
+{
+    DisplayPlaneManager::deinitialize();
+}
+
+DisplayPlane* TngPlaneManager::allocPlane(int index, int type)
+{
+    DisplayPlane *plane = 0;
+
+    switch (type) {
+    case DisplayPlane::PLANE_PRIMARY:
+        plane = new TngPrimaryPlane(index, index);
+        break;
+    case DisplayPlane::PLANE_SPRITE:
+        plane = new TngSpritePlane(index, 0);
+        break;
+    case DisplayPlane::PLANE_OVERLAY:
+        plane = new TngOverlayPlane(index, 0);
+        break;
+    case DisplayPlane::PLANE_CURSOR:
+        plane = new TngCursorPlane(index, index /*disp */);
+        break;
+    default:
+        ETRACE("unsupported type %d", type);
+        break;
+    }
+    if (plane && !plane->initialize(DisplayPlane::MIN_DATA_BUFFER_COUNT)) {
+        ETRACE("failed to initialize plane.");
+        DEINIT_AND_DELETE_OBJ(plane);
+    }
+
+    return plane;
+}
+
+bool TngPlaneManager::isValidZOrder(int dsp, ZOrderConfig& config)
+{
+    // check whether it's a supported z order config
+    int firstRGB = -1;
+    int lastRGB = -1;
+    int firstOverlay = -1;
+    int lastOverlay = -1;
+
+    for (int i = 0; i < (int)config.size(); i++) {
+        const ZOrderLayer *layer = config[i];
+        switch (layer->planeType) {
+        case DisplayPlane::PLANE_PRIMARY:
+        case DisplayPlane::PLANE_SPRITE:
+            if (firstRGB == -1) {
+                firstRGB = i;
+                lastRGB = i;
+            } else {
+                lastRGB = i;
+            }
+            break;
+        case DisplayPlane::PLANE_OVERLAY:
+        case DisplayPlane::PLANE_CURSOR:
+            if (firstOverlay == -1) {
+                firstOverlay = i;
+                lastOverlay = i;
+            } else {
+                lastOverlay = i;
+            }
+            break;
+        }
+    }
+
+    if ((lastRGB < firstOverlay) || (firstRGB > lastOverlay)) {
+        return true;
+    } else {
+        VTRACE("invalid z order config. rgb (%d, %d) yuv (%d, %d)",
+               firstRGB, lastRGB, firstOverlay, lastOverlay);
+        return false;
+    }
+}
+
+bool TngPlaneManager::assignPlanes(int dsp, ZOrderConfig& config)
+{
+    // probe if plane is available
+    int size = (int)config.size();
+    for (int i = 0; i < size; i++) {
+        const ZOrderLayer *layer = config.itemAt(i);
+        if (!getFreePlanes(dsp, layer->planeType)) {
+            DTRACE("no plane available for dsp %d, type %d", dsp, layer->planeType);
+            return false;
+        }
+    }
+
+    if (config.size() == 1 && config[0]->planeType == DisplayPlane::PLANE_SPRITE) {
+        config[0]->planeType == DisplayPlane::PLANE_PRIMARY;
+    }
+
+    // allocate planes
+    for (int i = 0; i < size; i++) {
+        ZOrderLayer *layer = config.itemAt(i);
+        layer->plane = getPlaneHelper(dsp, layer->planeType);
+        if (layer->plane == NULL) {
+            // should never happen!!
+            ETRACE("failed to assign plane for type %d", layer->planeType);
+            return false;
+        }
+        // sequence !!!!! enabling plane before setting zorder
+        // see TngSpritePlane::enablePlane implementation!!!!
+        layer->plane->enable();
+    }
+
+    // setup Z order
+    for (int i = 0; i < size; i++) {
+        ZOrderLayer *layer = config.itemAt(i);
+        layer->plane->setZOrderConfig(config, &mZorder);
+    }
+
+    return true;
+}
+
+void* TngPlaneManager::getZOrderConfig() const
+{
+    return (void*)&mZorder;
+}
+
+DisplayPlane* TngPlaneManager::getPlaneHelper(int dsp, int type)
+{
+    RETURN_NULL_IF_NOT_INIT();
+
+    if (dsp < 0 || dsp > IDisplayDevice::DEVICE_EXTERNAL) {
+        ETRACE("Invalid display device %d", dsp);
+        return 0;
+    }
+
+    int index = dsp == IDisplayDevice::DEVICE_PRIMARY ? 0 : 1;
+
+    if (type == DisplayPlane::PLANE_PRIMARY ||
+        type == DisplayPlane::PLANE_CURSOR) {
+        return getPlane(type, index);
+    } else if (type == DisplayPlane::PLANE_SPRITE) {
+        return getAnyPlane(type);
+    } else if (type == DisplayPlane::PLANE_OVERLAY) {
+        // use overlay A for pipe A and overlay C for pipe B if possible
+        DisplayPlane *plane = getPlane(type, index);
+        if (plane == NULL) {
+            plane = getPlane(type, !index);
+        }
+        return plane;
+    } else {
+        ETRACE("invalid plane type %d", type);
+        return 0;
+    }
+}
+
+} // namespace intel
+} // namespace android
+
diff --git a/merrifield/ips/tangier/TngPlaneManager.h b/merrifield/ips/tangier/TngPlaneManager.h
new file mode 100644
index 0000000..e6717bb
--- /dev/null
+++ b/merrifield/ips/tangier/TngPlaneManager.h
@@ -0,0 +1,50 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef TNG_PLANE_MANAGER_H
+#define TNG_PLANE_MANAGER_H
+
+#include <DisplayPlaneManager.h>
+#include <linux/psb_drm.h>
+
+namespace android {
+namespace intel {
+
+class TngPlaneManager : public DisplayPlaneManager {
+public:
+    TngPlaneManager();
+    virtual ~TngPlaneManager();
+
+public:
+    virtual bool initialize();
+    virtual void deinitialize();
+    virtual bool isValidZOrder(int dsp, ZOrderConfig& config);
+    virtual bool assignPlanes(int dsp, ZOrderConfig& config);
+    // TODO: remove this API
+    virtual void* getZOrderConfig() const;
+
+protected:
+    DisplayPlane* allocPlane(int index, int type);
+    DisplayPlane* getPlaneHelper(int dsp, int type);
+
+private:
+    struct intel_dc_plane_zorder mZorder;
+};
+
+} // namespace intel
+} // namespace android
+
+
+#endif /* TNG_PLANE_MANAGER_H */
diff --git a/merrifield/ips/tangier/TngPrimaryPlane.cpp b/merrifield/ips/tangier/TngPrimaryPlane.cpp
new file mode 100644
index 0000000..7d72f0f
--- /dev/null
+++ b/merrifield/ips/tangier/TngPrimaryPlane.cpp
@@ -0,0 +1,167 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#include <HwcTrace.h>
+#include <Drm.h>
+#include <tangier/TngPrimaryPlane.h>
+#include <tangier/TngGrallocBuffer.h>
+#include <common/PixelFormat.h>
+
+namespace android {
+namespace intel {
+
+TngPrimaryPlane::TngPrimaryPlane(int index, int disp)
+    : TngSpritePlane(index, disp)
+{
+    CTRACE();
+    mType = PLANE_PRIMARY;
+    mForceBottom = true;
+    mAbovePrimary = false;
+}
+
+TngPrimaryPlane::~TngPrimaryPlane()
+{
+    CTRACE();
+}
+
+void TngPrimaryPlane::setFramebufferTarget(buffer_handle_t handle)
+{
+    CTRACE();
+
+    // do not need to update the buffer handle
+    if (mCurrentDataBuffer != handle)
+        mUpdateMasks |= PLANE_BUFFER_CHANGED;
+    else
+        mUpdateMasks &= ~PLANE_BUFFER_CHANGED;
+
+    // if no update then do Not need set data buffer
+    if (!mUpdateMasks)
+        return;
+
+    // don't need to map data buffer for primary plane
+    mContext.type = DC_PRIMARY_PLANE;
+    mContext.ctx.prim_ctx.update_mask = SPRITE_UPDATE_ALL;
+    mContext.ctx.prim_ctx.index = mIndex;
+    mContext.ctx.prim_ctx.pipe = mDevice;
+    mContext.ctx.prim_ctx.linoff = 0;
+    mContext.ctx.prim_ctx.stride = align_to((4 * align_to(mPosition.w, 32)), 64);
+    mContext.ctx.prim_ctx.pos = 0;
+    mContext.ctx.prim_ctx.size =
+        ((mPosition.h - 1) & 0xfff) << 16 | ((mPosition.w - 1) & 0xfff);
+    mContext.ctx.prim_ctx.surf = 0;
+    mContext.ctx.prim_ctx.contalpa = 0;
+
+    mContext.ctx.prim_ctx.cntr = PixelFormat::PLANE_PIXEL_FORMAT_BGRA8888;
+    mContext.ctx.prim_ctx.cntr |= 0x80000000;
+
+    mCurrentDataBuffer = handle;
+}
+
+bool TngPrimaryPlane::enablePlane(bool enabled)
+{
+    RETURN_FALSE_IF_NOT_INIT();
+
+    struct drm_psb_register_rw_arg arg;
+    memset(&arg, 0, sizeof(struct drm_psb_register_rw_arg));
+    if (enabled) {
+        arg.plane_enable_mask = 1;
+    } else {
+        arg.plane_disable_mask = 1;
+    }
+    arg.plane.type = DC_PRIMARY_PLANE;
+    arg.plane.index = mIndex;
+    arg.plane.ctx = 0;
+
+    // issue ioctl
+    Drm *drm = Hwcomposer::getInstance().getDrm();
+    bool ret = drm->writeReadIoctl(DRM_PSB_REGISTER_RW, &arg, sizeof(arg));
+    if (ret == false) {
+        WTRACE("primary enabling (%d) failed with error code %d", enabled, ret);
+        return false;
+    }
+
+    return true;
+
+}
+
+bool TngPrimaryPlane::setDataBuffer(buffer_handle_t handle)
+{
+    if (!handle) {
+        setFramebufferTarget(handle);
+        return true;
+    }
+
+    TngGrallocBuffer tmpBuf(handle);
+    uint32_t usage;
+    bool ret;
+
+    ATRACE("handle = %#x", handle);
+
+    usage = tmpBuf.getUsage();
+    if (GRALLOC_USAGE_HW_FB & usage) {
+        setFramebufferTarget(handle);
+        return true;
+    }
+
+    // use primary as a sprite
+    ret = DisplayPlane::setDataBuffer(handle);
+    if (ret == false) {
+        ETRACE("failed to set data buffer");
+        return ret;
+    }
+
+    mContext.type = DC_PRIMARY_PLANE;
+    return true;
+}
+
+void TngPrimaryPlane::setZOrderConfig(ZOrderConfig& zorderConfig,
+                                           void *nativeConfig)
+{
+    if (!nativeConfig) {
+        ETRACE("Invalid parameter, no native config");
+        return;
+    }
+
+    mForceBottom = false;
+
+    int primaryIndex = -1;
+    int overlayIndex = -1;
+    // only consider force bottom when overlay is active
+    for (size_t i = 0; i < zorderConfig.size(); i++) {
+        DisplayPlane *plane = zorderConfig[i]->plane;
+        if (plane->getType() == DisplayPlane::PLANE_PRIMARY)
+            primaryIndex = i;
+        if (plane->getType() == DisplayPlane::PLANE_OVERLAY) {
+            overlayIndex = i;
+        }
+    }
+
+    // if has overlay plane which is below primary plane
+    if (overlayIndex > primaryIndex) {
+        mForceBottom = true;
+    }
+
+    struct intel_dc_plane_zorder *zorder =
+        (struct intel_dc_plane_zorder *)nativeConfig;
+    zorder->forceBottom[mIndex] = mForceBottom ? 1 : 0;
+}
+
+bool TngPrimaryPlane::assignToDevice(int disp)
+{
+    return true;
+}
+
+} // namespace intel
+} // namespace android
diff --git a/merrifield/ips/tangier/TngPrimaryPlane.h b/merrifield/ips/tangier/TngPrimaryPlane.h
new file mode 100644
index 0000000..22dbbd3
--- /dev/null
+++ b/merrifield/ips/tangier/TngPrimaryPlane.h
@@ -0,0 +1,40 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef TNG_PRIMARY_PLANE_H
+#define TNG_PRIMARY_PLANE_H
+
+#include <tangier/TngSpritePlane.h>
+
+namespace android {
+namespace intel {
+
+class TngPrimaryPlane : public TngSpritePlane {
+public:
+    TngPrimaryPlane(int index, int disp);
+    virtual ~TngPrimaryPlane();
+public:
+    bool setDataBuffer(buffer_handle_t handle);
+    void setZOrderConfig(ZOrderConfig& config, void *nativeConfig);
+    bool assignToDevice(int disp);
+private:
+    void setFramebufferTarget(buffer_handle_t handle);
+    bool enablePlane(bool enabled);
+};
+
+} // namespace intel
+} // namespace android
+
+#endif /* TNG_PRIMARY_PLANE_H */
diff --git a/merrifield/ips/tangier/TngSpritePlane.cpp b/merrifield/ips/tangier/TngSpritePlane.cpp
new file mode 100644
index 0000000..c4e7e2c
--- /dev/null
+++ b/merrifield/ips/tangier/TngSpritePlane.cpp
@@ -0,0 +1,215 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#include <HwcTrace.h>
+#include <Hwcomposer.h>
+#include <BufferManager.h>
+#include <tangier/TngSpritePlane.h>
+#include <common/PixelFormat.h>
+
+namespace android {
+namespace intel {
+
+TngSpritePlane::TngSpritePlane(int index, int disp)
+    : SpritePlaneBase(index, disp)
+{
+    CTRACE();
+    memset(&mContext, 0, sizeof(mContext));
+}
+
+TngSpritePlane::~TngSpritePlane()
+{
+    CTRACE();
+}
+
+bool TngSpritePlane::setDataBuffer(BufferMapper& mapper)
+{
+    int bpp;
+    int srcX, srcY;
+    int dstX, dstY, dstW, dstH;
+    uint32_t spriteFormat;
+    uint32_t stride;
+    uint32_t linoff;
+    uint32_t planeAlpha;
+
+    CTRACE();
+
+    // setup plane position
+    dstX = mPosition.x;
+    dstY = mPosition.y;
+    dstW = mPosition.w;
+    dstH = mPosition.h;
+
+    checkPosition(dstX, dstY, dstW, dstH);
+
+    // setup plane format
+    if (!PixelFormat::convertFormat(mapper.getFormat(), spriteFormat, bpp)) {
+        ETRACE("unsupported format %#x", mapper.getFormat());
+        return false;
+    }
+
+    // setup stride and source buffer crop
+    srcX = mapper.getCrop().x;
+    srcY = mapper.getCrop().y;
+    stride = mapper.getStride().rgb.stride;
+    linoff = srcY * stride + srcX * bpp;
+
+    // setup plane alpha
+    if ((mBlending == HWC_BLENDING_PREMULT) && (mPlaneAlpha == 0)) {
+       planeAlpha = mPlaneAlpha | 0x80000000;
+    } else {
+       // disable plane alpha to offload HW
+       planeAlpha = 0;
+    }
+
+    // unlikely happen, but still we need make sure linoff is valid
+    if (linoff > (stride * mapper.getHeight())) {
+        ETRACE("invalid source crop");
+        return false;
+    }
+
+    // update context
+    mContext.type = DC_SPRITE_PLANE;
+    mContext.ctx.sp_ctx.index = mIndex;
+    mContext.ctx.sp_ctx.pipe = mDevice;
+    // none blending and BRGA format layer,set format to BGRX8888
+    if (mBlending == HWC_BLENDING_NONE && spriteFormat == PixelFormat::PLANE_PIXEL_FORMAT_BGRA8888)
+	mContext.ctx.sp_ctx.cntr = PixelFormat::PLANE_PIXEL_FORMAT_BGRX8888
+					| 0x80000000;
+    else
+	mContext.ctx.sp_ctx.cntr = spriteFormat | 0x80000000;
+    mContext.ctx.sp_ctx.linoff = linoff;
+    mContext.ctx.sp_ctx.stride = stride;
+    mContext.ctx.sp_ctx.surf = mapper.getGttOffsetInPage(0) << 12;
+    mContext.ctx.sp_ctx.pos = (dstY & 0xfff) << 16 | (dstX & 0xfff);
+    mContext.ctx.sp_ctx.size =
+        ((dstH - 1) & 0xfff) << 16 | ((dstW - 1) & 0xfff);
+    mContext.ctx.sp_ctx.contalpa = planeAlpha;
+    mContext.ctx.sp_ctx.update_mask = SPRITE_UPDATE_ALL;
+    mContext.gtt_key = (uint64_t)mapper.getCpuAddress(0);
+
+    VTRACE("cntr = %#x, linoff = %#x, stride = %#x,"
+          "surf = %#x, pos = %#x, size = %#x, contalpa = %#x",
+          mContext.ctx.sp_ctx.cntr,
+          mContext.ctx.sp_ctx.linoff,
+          mContext.ctx.sp_ctx.stride,
+          mContext.ctx.sp_ctx.surf,
+          mContext.ctx.sp_ctx.pos,
+          mContext.ctx.sp_ctx.size,
+          mContext.ctx.sp_ctx.contalpa);
+    return true;
+}
+
+void* TngSpritePlane::getContext() const
+{
+    CTRACE();
+    return (void *)&mContext;
+}
+
+bool TngSpritePlane::enablePlane(bool enabled)
+{
+    RETURN_FALSE_IF_NOT_INIT();
+
+    struct drm_psb_register_rw_arg arg;
+    memset(&arg, 0, sizeof(struct drm_psb_register_rw_arg));
+    if (enabled) {
+        arg.plane_enable_mask = 1;
+    } else {
+        arg.plane_disable_mask = 1;
+    }
+    arg.plane.type = DC_SPRITE_PLANE;
+    arg.plane.index = mIndex;
+    arg.plane.ctx = 0;
+
+    // issue ioctl
+    Drm *drm = Hwcomposer::getInstance().getDrm();
+    bool ret = drm->writeReadIoctl(DRM_PSB_REGISTER_RW, &arg, sizeof(arg));
+    if (ret == false) {
+        WTRACE("sprite enabling (%d) failed with error code %d", enabled, ret);
+        return false;
+    }
+
+    Hwcomposer& hwc = Hwcomposer::getInstance();
+    DisplayPlaneManager *pm = hwc.getPlaneManager();
+    void *config = pm->getZOrderConfig();
+    if (config != NULL) {
+        struct intel_dc_plane_zorder *zorder =  (struct intel_dc_plane_zorder *)config;
+        zorder->abovePrimary = 0;
+    }
+
+    return true;
+
+}
+
+bool TngSpritePlane::isDisabled()
+{
+    RETURN_FALSE_IF_NOT_INIT();
+
+    struct drm_psb_register_rw_arg arg;
+    memset(&arg, 0, sizeof(struct drm_psb_register_rw_arg));
+
+    if (mType == DisplayPlane::PLANE_SPRITE)
+        arg.plane.type = DC_SPRITE_PLANE;
+    else
+        arg.plane.type = DC_PRIMARY_PLANE;
+
+    arg.get_plane_state_mask = 1;
+    arg.plane.index = mIndex;
+    arg.plane.ctx = 0;
+
+    // issue ioctl
+    Drm *drm = Hwcomposer::getInstance().getDrm();
+    bool ret = drm->writeReadIoctl(DRM_PSB_REGISTER_RW, &arg, sizeof(arg));
+    if (ret == false) {
+        WTRACE("plane state query failed with error code %d", ret);
+        return false;
+    }
+
+    return arg.plane.ctx == PSB_DC_PLANE_DISABLED;
+}
+
+void TngSpritePlane::setZOrderConfig(ZOrderConfig& zorderConfig,
+                                          void *nativeConfig)
+{
+    if (!nativeConfig) {
+        ETRACE("Invalid parameter, no native config");
+        return;
+    }
+
+    mAbovePrimary = false;
+
+    int primaryIndex = -1;
+    int spriteIndex = -1;
+    // only consider force bottom when overlay is active
+    for (size_t i = 0; i < zorderConfig.size(); i++) {
+        DisplayPlane *plane = zorderConfig[i]->plane;
+        if (plane->getType() == DisplayPlane::PLANE_PRIMARY)
+            primaryIndex = i;
+        if (plane->getType() == DisplayPlane::PLANE_SPRITE) {
+            spriteIndex = i;
+        }
+    }
+
+    // if has overlay plane which is below primary plane
+    if (spriteIndex > primaryIndex) {
+        mAbovePrimary = true;
+    }
+
+    struct intel_dc_plane_zorder *zorder =
+        (struct intel_dc_plane_zorder *)nativeConfig;
+    zorder->abovePrimary = mAbovePrimary ? 1 : 0;
+}
+} // namespace intel
+} // namespace android
diff --git a/merrifield/ips/tangier/TngSpritePlane.h b/merrifield/ips/tangier/TngSpritePlane.h
new file mode 100644
index 0000000..1c6bcdc
--- /dev/null
+++ b/merrifield/ips/tangier/TngSpritePlane.h
@@ -0,0 +1,48 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef TNG_SPRITE_PLANE_H
+#define TNG_SPRITE_PLANE_H
+
+#include <utils/KeyedVector.h>
+#include <hal_public.h>
+#include <Hwcomposer.h>
+#include <BufferCache.h>
+#include <DisplayPlane.h>
+
+#include <common/SpritePlaneBase.h>
+
+namespace android {
+namespace intel {
+
+class TngSpritePlane : public SpritePlaneBase {
+public:
+    TngSpritePlane(int index, int disp);
+    virtual ~TngSpritePlane();
+public:
+    virtual void* getContext() const;
+    virtual void setZOrderConfig(ZOrderConfig& config, void *nativeConfig);
+    virtual bool isDisabled();
+protected:
+    virtual bool setDataBuffer(BufferMapper& mapper);
+    virtual bool enablePlane(bool enabled);
+protected:
+    struct intel_dc_plane_ctx mContext;
+};
+
+} // namespace intel
+} // namespace android
+
+#endif /* TNG_SPRITE_PLANE_H */
diff --git a/merrifield/platforms/merrifield/Android.mk b/merrifield/platforms/merrifield/Android.mk
new file mode 100644
index 0000000..98e1d3d
--- /dev/null
+++ b/merrifield/platforms/merrifield/Android.mk
@@ -0,0 +1,139 @@
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+# HAL module implemenation, not prelinked and stored in
+# hw/<OVERLAY_HARDWARE_MODULE_ID>.<ro.product.board>.so
+include $(CLEAR_VARS)
+
+LOCAL_PRELINK_MODULE := false
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_SHARED_LIBRARIES := liblog libcutils libdrm \
+                          libwsbm libutils libhardware \
+                          libva libva-tpi libva-android libsync
+LOCAL_SRC_FILES := \
+    ../../common/base/Drm.cpp \
+    ../../common/base/HwcLayer.cpp \
+    ../../common/base/HwcLayerList.cpp \
+    ../../common/base/Hwcomposer.cpp \
+    ../../common/base/HwcModule.cpp \
+    ../../common/base/DisplayAnalyzer.cpp \
+    ../../common/base/VsyncManager.cpp \
+    ../../common/buffers/BufferCache.cpp \
+    ../../common/buffers/GraphicBuffer.cpp \
+    ../../common/buffers/BufferManager.cpp \
+    ../../common/devices/PhysicalDevice.cpp \
+    ../../common/devices/PrimaryDevice.cpp \
+    ../../common/devices/ExternalDevice.cpp \
+    ../../common/observers/UeventObserver.cpp \
+    ../../common/observers/VsyncEventObserver.cpp \
+    ../../common/observers/SoftVsyncObserver.cpp \
+    ../../common/observers/MultiDisplayObserver.cpp \
+    ../../common/planes/DisplayPlane.cpp \
+    ../../common/planes/DisplayPlaneManager.cpp \
+    ../../common/utils/Dump.cpp
+
+
+LOCAL_SRC_FILES += \
+    ../../ips/common/BlankControl.cpp \
+    ../../ips/common/HdcpControl.cpp \
+    ../../ips/common/DrmControl.cpp \
+    ../../ips/common/VsyncControl.cpp \
+    ../../ips/common/PrepareListener.cpp \
+    ../../ips/common/OverlayPlaneBase.cpp \
+    ../../ips/common/SpritePlaneBase.cpp \
+    ../../ips/common/PixelFormat.cpp \
+    ../../ips/common/PlaneCapabilities.cpp \
+    ../../ips/common/GrallocBufferBase.cpp \
+    ../../ips/common/GrallocBufferMapperBase.cpp \
+    ../../ips/common/TTMBufferMapper.cpp \
+    ../../ips/common/DrmConfig.cpp \
+    ../../ips/common/VideoPayloadManager.cpp \
+    ../../ips/common/Wsbm.cpp \
+    ../../ips/common/WsbmWrapper.c \
+    ../../ips/common/RotationBufferProvider.cpp
+
+LOCAL_SRC_FILES += \
+    ../../ips/tangier/TngGrallocBuffer.cpp \
+    ../../ips/tangier/TngGrallocBufferMapper.cpp \
+    ../../ips/tangier/TngOverlayPlane.cpp \
+    ../../ips/tangier/TngPrimaryPlane.cpp \
+    ../../ips/tangier/TngSpritePlane.cpp \
+    ../../ips/tangier/TngDisplayQuery.cpp \
+    ../../ips/tangier/TngPlaneManager.cpp \
+    ../../ips/tangier/TngDisplayContext.cpp \
+    ../../ips/tangier/TngCursorPlane.cpp
+
+
+LOCAL_SRC_FILES += \
+    PlatfBufferManager.cpp \
+    PlatFactory.cpp
+
+LOCAL_C_INCLUDES := $(addprefix $(LOCAL_PATH)/../../../, $(SGX_INCLUDES)) \
+    $(call include-path-for, frameworks-native)/media/openmax \
+    $(TARGET_OUT_HEADERS)/khronos/openmax \
+    $(call include-path-for, opengl) \
+    $(call include-path-for, libhardware_legacy)/hardware_legacy \
+    prebuilts/intel/vendor/intel/hardware/prebuilts/$(REF_DEVICE_NAME)/rgx \
+    prebuilts/intel/vendor/intel/hardware/prebuilts/$(REF_DEVICE_NAME)/rgx/include \
+    vendor/intel/hardware/PRIVATE/widi/libhwcwidi/ \
+    system/core \
+    system/core/libsync/include \
+    $(TARGET_OUT_HEADERS)/drm \
+    $(TARGET_OUT_HEADERS)/libdrm \
+    $(TARGET_OUT_HEADERS)/libdrm/shared-core \
+    $(TARGET_OUT_HEADERS)/libwsbm/wsbm \
+    $(TARGET_OUT_HEADERS)/libttm \
+    $(TARGET_OUT_HEADERS)/libva
+
+LOCAL_C_INCLUDES += $(LOCAL_PATH) \
+    $(LOCAL_PATH)/../../include \
+    $(LOCAL_PATH)/../../include/pvr/hal \
+    $(LOCAL_PATH)/../../common/base \
+    $(LOCAL_PATH)/../../common/buffers \
+    $(LOCAL_PATH)/../../common/devices \
+    $(LOCAL_PATH)/../../common/observers \
+    $(LOCAL_PATH)/../../common/planes \
+    $(LOCAL_PATH)/../../common/utils \
+    $(LOCAL_PATH)/../../ips/ \
+    $(LOCAL_PATH)/
+
+
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := hwcomposer.$(TARGET_BOARD_PLATFORM)
+LOCAL_CFLAGS += -DLINUX
+
+ifeq ($(INTEL_WIDI_MERRIFIELD), true)
+LOCAL_SRC_FILES += \
+    ../../common/devices/VirtualDevice.cpp
+
+   LOCAL_SHARED_LIBRARIES += libhwcwidi libbinder
+   LOCAL_CFLAGS += -DINTEL_WIDI_MERRIFIELD
+endif
+
+ifeq ($(TARGET_HAS_MULTIPLE_DISPLAY),true)
+   LOCAL_SHARED_LIBRARIES += libmultidisplay libbinder
+   LOCAL_CFLAGS += -DTARGET_HAS_MULTIPLE_DISPLAY
+endif
+
+LOCAL_COPY_HEADERS := ../../include/pvr/hal/hal_public.h
+LOCAL_COPY_HEADERS_TO := pvr/hal
+
+ifneq ($(TARGET_BUILD_VARIANT),user)
+   LOCAL_CFLAGS += -DHWC_TRACE_FPS
+endif
+
+include $(BUILD_SHARED_LIBRARY)
+
diff --git a/merrifield/platforms/merrifield/PlatFactory.cpp b/merrifield/platforms/merrifield/PlatFactory.cpp
new file mode 100644
index 0000000..7530225
--- /dev/null
+++ b/merrifield/platforms/merrifield/PlatFactory.cpp
@@ -0,0 +1,108 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#include <HwcTrace.h>
+#include <tangier/TngDisplayContext.h>
+#include <tangier/TngPlaneManager.h>
+#include <PlatfBufferManager.h>
+#include <IDisplayDevice.h>
+#include <PrimaryDevice.h>
+#include <ExternalDevice.h>
+#ifdef INTEL_WIDI_MERRIFIELD
+#include <VirtualDevice.h>
+#endif
+#include <Hwcomposer.h>
+#include <PlatFactory.h>
+#include <common/VsyncControl.h>
+#include <common/HdcpControl.h>
+#include <common/BlankControl.h>
+#include <common/PrepareListener.h>
+#include <common/VideoPayloadManager.h>
+
+
+namespace android {
+namespace intel {
+
+PlatFactory::PlatFactory()
+{
+    CTRACE();
+}
+
+PlatFactory::~PlatFactory()
+{
+    CTRACE();
+}
+
+DisplayPlaneManager* PlatFactory::createDisplayPlaneManager()
+{
+    CTRACE();
+    return (new TngPlaneManager());
+}
+
+BufferManager* PlatFactory::createBufferManager()
+{
+    CTRACE();
+    return (new PlatfBufferManager());
+}
+
+IDisplayDevice* PlatFactory::createDisplayDevice(int disp)
+{
+    CTRACE();
+    //when createDisplayDevice is called, Hwcomposer has already finished construction.
+    Hwcomposer &hwc = Hwcomposer::getInstance();
+
+    class PlatDeviceControlFactory: public DeviceControlFactory {
+    public:
+        virtual IVsyncControl* createVsyncControl()       {return new VsyncControl();}
+        virtual IBlankControl* createBlankControl()       {return new BlankControl();}
+        virtual IHdcpControl* createHdcpControl()         {return new HdcpControl();}
+    };
+
+    switch (disp) {
+        case IDisplayDevice::DEVICE_PRIMARY:
+            return new PrimaryDevice(hwc, new PlatDeviceControlFactory());
+        case IDisplayDevice::DEVICE_EXTERNAL:
+            return new ExternalDevice(hwc, new PlatDeviceControlFactory());
+#ifdef INTEL_WIDI_MERRIFIELD
+        case IDisplayDevice::DEVICE_VIRTUAL:
+            return new VirtualDevice(hwc);
+#endif
+        default:
+            ETRACE("invalid display device %d", disp);
+            return NULL;
+    }
+}
+
+IDisplayContext* PlatFactory::createDisplayContext()
+{
+    CTRACE();
+    return new TngDisplayContext();
+}
+
+IVideoPayloadManager *PlatFactory::createVideoPayloadManager()
+{
+    return new VideoPayloadManager();
+}
+
+Hwcomposer* Hwcomposer::createHwcomposer()
+{
+    CTRACE();
+    Hwcomposer *hwc = new Hwcomposer(new PlatFactory());
+    return hwc;
+}
+
+} //namespace intel
+} //namespace android
diff --git a/merrifield/platforms/merrifield/PlatFactory.h b/merrifield/platforms/merrifield/PlatFactory.h
new file mode 100644
index 0000000..73d6eea
--- /dev/null
+++ b/merrifield/platforms/merrifield/PlatFactory.h
@@ -0,0 +1,43 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#ifndef MOOFPLATFORMFACTORY_H_
+#define MOOFPLATFORMFACTORY_H_
+
+#include <IPlatFactory.h>
+
+
+namespace android {
+namespace intel {
+
+class PlatFactory : public  IPlatFactory {
+public:
+    PlatFactory();
+    virtual ~PlatFactory();
+
+    virtual DisplayPlaneManager* createDisplayPlaneManager();
+    virtual BufferManager* createBufferManager();
+    virtual IDisplayDevice* createDisplayDevice(int disp);
+    virtual IDisplayContext* createDisplayContext();
+    virtual IVideoPayloadManager *createVideoPayloadManager();
+
+};
+
+} //namespace intel
+} //namespace android
+
+
+#endif /* MOOFPLATFORMFACTORY_H_ */
diff --git a/merrifield/platforms/merrifield/PlatfBufferManager.cpp b/merrifield/platforms/merrifield/PlatfBufferManager.cpp
new file mode 100644
index 0000000..1dd72c6
--- /dev/null
+++ b/merrifield/platforms/merrifield/PlatfBufferManager.cpp
@@ -0,0 +1,77 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#include <HwcTrace.h>
+#include <PlatfBufferManager.h>
+#include <tangier/TngGrallocBuffer.h>
+#include <tangier/TngGrallocBufferMapper.h>
+
+namespace android {
+namespace intel {
+
+PlatfBufferManager::PlatfBufferManager()
+    : BufferManager()
+{
+
+}
+
+PlatfBufferManager::~PlatfBufferManager()
+{
+
+}
+
+bool PlatfBufferManager::initialize()
+{
+    return BufferManager::initialize();
+}
+
+void PlatfBufferManager::deinitialize()
+{
+    BufferManager::deinitialize();
+}
+
+DataBuffer* PlatfBufferManager::createDataBuffer(gralloc_module_t *module,
+                                                 buffer_handle_t handle)
+{
+    return new TngGrallocBuffer(handle);
+}
+
+BufferMapper* PlatfBufferManager::createBufferMapper(gralloc_module_t *module,
+                                                        DataBuffer& buffer)
+{
+    if (!module)
+        return 0;
+
+    return new TngGrallocBufferMapper(*(IMG_gralloc_module_public_t*)module,
+                                        buffer);
+}
+
+bool PlatfBufferManager::blit(buffer_handle_t srcHandle, buffer_handle_t destHandle,
+                              const crop_t& destRect, bool filter, bool async)
+
+{
+    IMG_gralloc_module_public_t *imgGrallocModule = (IMG_gralloc_module_public_t *) mGrallocModule;
+    if (imgGrallocModule->Blit(imgGrallocModule, srcHandle,
+                                destHandle,
+                                destRect.w, destRect.h, destRect.x,
+                                destRect.y, filter, 0, async)) {
+        ETRACE("Blit failed");
+        return false;
+    }
+    return true;
+}
+
+} // namespace intel
+} // namespace android
diff --git a/merrifield/platforms/merrifield/PlatfBufferManager.h b/merrifield/platforms/merrifield/PlatfBufferManager.h
new file mode 100644
index 0000000..822f484
--- /dev/null
+++ b/merrifield/platforms/merrifield/PlatfBufferManager.h
@@ -0,0 +1,43 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef PLATF_BUFFER_MANAGER_H
+#define PLATF_BUFFER_MANAGER_H
+
+#include <BufferManager.h>
+
+namespace android {
+namespace intel {
+
+class PlatfBufferManager : public BufferManager {
+public:
+    PlatfBufferManager();
+    virtual ~PlatfBufferManager();
+
+public:
+    bool initialize();
+    void deinitialize();
+
+protected:
+    DataBuffer* createDataBuffer(gralloc_module_t *module, buffer_handle_t handle);
+    BufferMapper* createBufferMapper(gralloc_module_t *module,
+                                        DataBuffer& buffer);
+    bool blit(buffer_handle_t srcHandle, buffer_handle_t destHandle,
+              const crop_t& destRect, bool filter, bool async);
+};
+
+}
+}
+#endif /* PLATF_BUFFER_MANAGER_H */
diff --git a/merrifield/platforms/merrifield_plus/Android.mk b/merrifield/platforms/merrifield_plus/Android.mk
new file mode 100644
index 0000000..2f5f63d
--- /dev/null
+++ b/merrifield/platforms/merrifield_plus/Android.mk
@@ -0,0 +1,143 @@
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+# HAL module implemenation, not prelinked and stored in
+# hw/<OVERLAY_HARDWARE_MODULE_ID>.<ro.product.board>.so
+include $(CLEAR_VARS)
+
+LOCAL_PRELINK_MODULE := false
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_SHARED_LIBRARIES := liblog libcutils libdrm \
+                          libwsbm libutils libhardware \
+                          libva libva-tpi libva-android libsync
+LOCAL_SRC_FILES := \
+    ../../common/base/Drm.cpp \
+    ../../common/base/HwcLayer.cpp \
+    ../../common/base/HwcLayerList.cpp \
+    ../../common/base/Hwcomposer.cpp \
+    ../../common/base/HwcModule.cpp \
+    ../../common/base/DisplayAnalyzer.cpp \
+    ../../common/base/VsyncManager.cpp \
+    ../../common/buffers/BufferCache.cpp \
+    ../../common/buffers/GraphicBuffer.cpp \
+    ../../common/buffers/BufferManager.cpp \
+    ../../common/devices/PhysicalDevice.cpp \
+    ../../common/devices/PrimaryDevice.cpp \
+    ../../common/devices/ExternalDevice.cpp \
+    ../../common/observers/UeventObserver.cpp \
+    ../../common/observers/VsyncEventObserver.cpp \
+    ../../common/observers/SoftVsyncObserver.cpp \
+    ../../common/observers/MultiDisplayObserver.cpp \
+    ../../common/planes/DisplayPlane.cpp \
+    ../../common/planes/DisplayPlaneManager.cpp \
+    ../../common/utils/Dump.cpp
+
+
+LOCAL_SRC_FILES += \
+    ../../ips/common/BlankControl.cpp \
+    ../../ips/common/HdcpControl.cpp \
+    ../../ips/common/DrmControl.cpp \
+    ../../ips/common/VsyncControl.cpp \
+    ../../ips/common/PrepareListener.cpp \
+    ../../ips/common/OverlayPlaneBase.cpp \
+    ../../ips/common/SpritePlaneBase.cpp \
+    ../../ips/common/PixelFormat.cpp \
+    ../../ips/common/GrallocBufferBase.cpp \
+    ../../ips/common/GrallocBufferMapperBase.cpp \
+    ../../ips/common/TTMBufferMapper.cpp \
+    ../../ips/common/DrmConfig.cpp \
+    ../../ips/common/VideoPayloadManager.cpp \
+    ../../ips/common/Wsbm.cpp \
+    ../../ips/common/WsbmWrapper.c \
+    ../../ips/common/RotationBufferProvider.cpp
+
+LOCAL_SRC_FILES += \
+    ../../ips/tangier/TngGrallocBuffer.cpp \
+    ../../ips/tangier/TngGrallocBufferMapper.cpp \
+    ../../ips/tangier/TngDisplayQuery.cpp \
+    ../../ips/tangier/TngDisplayContext.cpp
+
+
+LOCAL_SRC_FILES += \
+    ../../ips/anniedale/AnnPlaneManager.cpp \
+    ../../ips/anniedale/AnnOverlayPlane.cpp \
+    ../../ips/anniedale/AnnRGBPlane.cpp \
+    ../../ips/anniedale/AnnCursorPlane.cpp \
+    ../../ips/anniedale/PlaneCapabilities.cpp
+
+
+LOCAL_SRC_FILES += \
+    PlatfBufferManager.cpp \
+    PlatFactory.cpp
+
+
+LOCAL_C_INCLUDES := $(addprefix $(LOCAL_PATH)/../../../, $(SGX_INCLUDES)) \
+    frameworks/native/include/media/openmax \
+    $(TARGET_OUT_HEADERS)/khronos/openmax \
+    frameworks/native/opengl/include \
+    hardware/libhardware_legacy/include/hardware_legacy \
+    prebuilts/intel/vendor/intel/hardware/prebuilts/$(REF_DEVICE_NAME)/rgx \
+    prebuilts/intel/vendor/intel/hardware/prebuilts/$(REF_DEVICE_NAME)/rgx/include \
+    vendor/intel/hardware/PRIVATE/widi/libhwcwidi/ \
+    system/core \
+    system/core/libsync/include \
+    $(TARGET_OUT_HEADERS)/drm \
+    $(TARGET_OUT_HEADERS)/libdrm \
+    $(TARGET_OUT_HEADERS)/libdrm/shared-core \
+    $(TARGET_OUT_HEADERS)/libwsbm/wsbm \
+    $(TARGET_OUT_HEADERS)/libttm \
+    $(TARGET_OUT_HEADERS)/libva
+
+LOCAL_C_INCLUDES += $(LOCAL_PATH) \
+    $(LOCAL_PATH)/../../include \
+    $(LOCAL_PATH)/../../include/pvr/hal \
+    $(LOCAL_PATH)/../../common/base \
+    $(LOCAL_PATH)/../../common/buffers \
+    $(LOCAL_PATH)/../../common/devices \
+    $(LOCAL_PATH)/../../common/observers \
+    $(LOCAL_PATH)/../../common/planes \
+    $(LOCAL_PATH)/../../common/utils \
+    $(LOCAL_PATH)/../../ips/ \
+    $(LOCAL_PATH)/
+
+
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := hwcomposer.$(TARGET_BOARD_PLATFORM)
+LOCAL_CFLAGS += -DLINUX
+
+#$(error local path is: $(LOCAL_C_INCLUDES))
+ifeq ($(INTEL_WIDI_MERRIFIELD), true)
+LOCAL_SRC_FILES += \
+    ../../common/devices/VirtualDevice.cpp
+
+   LOCAL_SHARED_LIBRARIES += libhwcwidi libbinder
+   LOCAL_CFLAGS += -DINTEL_WIDI_MERRIFIELD
+endif
+
+ifeq ($(TARGET_HAS_MULTIPLE_DISPLAY),true)
+   LOCAL_SHARED_LIBRARIES += libmultidisplay libbinder
+   LOCAL_CFLAGS += -DTARGET_HAS_MULTIPLE_DISPLAY
+endif
+
+LOCAL_COPY_HEADERS := ../../include/pvr/hal/hal_public.h
+LOCAL_COPY_HEADERS_TO := pvr/hal
+
+ifneq ($(TARGET_BUILD_VARIANT),user)
+   LOCAL_CFLAGS += -DHWC_TRACE_FPS
+endif
+
+include $(BUILD_SHARED_LIBRARY)
+
diff --git a/merrifield/platforms/merrifield_plus/PlatFactory.cpp b/merrifield/platforms/merrifield_plus/PlatFactory.cpp
new file mode 100644
index 0000000..095a4a1
--- /dev/null
+++ b/merrifield/platforms/merrifield_plus/PlatFactory.cpp
@@ -0,0 +1,106 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#include <HwcTrace.h>
+#include <tangier/TngDisplayContext.h>
+#include <anniedale/AnnPlaneManager.h>
+#include <PlatfBufferManager.h>
+#include <IDisplayDevice.h>
+#include <PrimaryDevice.h>
+#include <ExternalDevice.h>
+#include <VirtualDevice.h>
+#include <Hwcomposer.h>
+#include <PlatFactory.h>
+#include <common/VsyncControl.h>
+#include <common/HdcpControl.h>
+#include <common/BlankControl.h>
+#include <common/PrepareListener.h>
+#include <common/VideoPayloadManager.h>
+
+
+
+namespace android {
+namespace intel {
+
+PlatFactory::PlatFactory()
+{
+    CTRACE();
+}
+
+PlatFactory::~PlatFactory()
+{
+    CTRACE();
+}
+
+DisplayPlaneManager* PlatFactory::createDisplayPlaneManager()
+{
+    CTRACE();
+    return (new AnnPlaneManager());
+}
+
+BufferManager* PlatFactory::createBufferManager()
+{
+    CTRACE();
+    return (new PlatfBufferManager());
+}
+
+IDisplayDevice* PlatFactory::createDisplayDevice(int disp)
+{
+    CTRACE();
+    // when createDisplayDevice is called, Hwcomposer has already finished construction.
+    Hwcomposer &hwc = Hwcomposer::getInstance();
+    class PlatDeviceControlFactory: public DeviceControlFactory {
+       public:
+           virtual IVsyncControl* createVsyncControl()       {return new VsyncControl();}
+           virtual IBlankControl* createBlankControl()       {return new BlankControl();}
+           virtual IHdcpControl* createHdcpControl()         {return new HdcpControl();}
+       };
+
+    switch (disp) {
+        case IDisplayDevice::DEVICE_PRIMARY:
+           return new PrimaryDevice(hwc, new PlatDeviceControlFactory());
+        case IDisplayDevice::DEVICE_EXTERNAL:
+            return new ExternalDevice(hwc, new PlatDeviceControlFactory());
+#ifdef INTEL_WIDI_MERRIFIELD
+        case IDisplayDevice::DEVICE_VIRTUAL:
+            return new VirtualDevice(hwc);
+#endif
+        default:
+            ETRACE("invalid display device %d", disp);
+            return NULL;
+    }
+}
+
+IDisplayContext* PlatFactory::createDisplayContext()
+{
+    CTRACE();
+    return new TngDisplayContext();
+}
+
+IVideoPayloadManager * PlatFactory::createVideoPayloadManager()
+{
+    return new VideoPayloadManager();
+}
+
+Hwcomposer* Hwcomposer::createHwcomposer()
+{
+    CTRACE();
+    Hwcomposer *hwc = new Hwcomposer(new PlatFactory());
+    return hwc;
+}
+
+} //namespace intel
+} //namespace android
diff --git a/merrifield/platforms/merrifield_plus/PlatFactory.h b/merrifield/platforms/merrifield_plus/PlatFactory.h
new file mode 100644
index 0000000..73d6eea
--- /dev/null
+++ b/merrifield/platforms/merrifield_plus/PlatFactory.h
@@ -0,0 +1,43 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#ifndef MOOFPLATFORMFACTORY_H_
+#define MOOFPLATFORMFACTORY_H_
+
+#include <IPlatFactory.h>
+
+
+namespace android {
+namespace intel {
+
+class PlatFactory : public  IPlatFactory {
+public:
+    PlatFactory();
+    virtual ~PlatFactory();
+
+    virtual DisplayPlaneManager* createDisplayPlaneManager();
+    virtual BufferManager* createBufferManager();
+    virtual IDisplayDevice* createDisplayDevice(int disp);
+    virtual IDisplayContext* createDisplayContext();
+    virtual IVideoPayloadManager *createVideoPayloadManager();
+
+};
+
+} //namespace intel
+} //namespace android
+
+
+#endif /* MOOFPLATFORMFACTORY_H_ */
diff --git a/merrifield/platforms/merrifield_plus/PlatfBufferManager.cpp b/merrifield/platforms/merrifield_plus/PlatfBufferManager.cpp
new file mode 100644
index 0000000..1dd72c6
--- /dev/null
+++ b/merrifield/platforms/merrifield_plus/PlatfBufferManager.cpp
@@ -0,0 +1,77 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#include <HwcTrace.h>
+#include <PlatfBufferManager.h>
+#include <tangier/TngGrallocBuffer.h>
+#include <tangier/TngGrallocBufferMapper.h>
+
+namespace android {
+namespace intel {
+
+PlatfBufferManager::PlatfBufferManager()
+    : BufferManager()
+{
+
+}
+
+PlatfBufferManager::~PlatfBufferManager()
+{
+
+}
+
+bool PlatfBufferManager::initialize()
+{
+    return BufferManager::initialize();
+}
+
+void PlatfBufferManager::deinitialize()
+{
+    BufferManager::deinitialize();
+}
+
+DataBuffer* PlatfBufferManager::createDataBuffer(gralloc_module_t *module,
+                                                 buffer_handle_t handle)
+{
+    return new TngGrallocBuffer(handle);
+}
+
+BufferMapper* PlatfBufferManager::createBufferMapper(gralloc_module_t *module,
+                                                        DataBuffer& buffer)
+{
+    if (!module)
+        return 0;
+
+    return new TngGrallocBufferMapper(*(IMG_gralloc_module_public_t*)module,
+                                        buffer);
+}
+
+bool PlatfBufferManager::blit(buffer_handle_t srcHandle, buffer_handle_t destHandle,
+                              const crop_t& destRect, bool filter, bool async)
+
+{
+    IMG_gralloc_module_public_t *imgGrallocModule = (IMG_gralloc_module_public_t *) mGrallocModule;
+    if (imgGrallocModule->Blit(imgGrallocModule, srcHandle,
+                                destHandle,
+                                destRect.w, destRect.h, destRect.x,
+                                destRect.y, filter, 0, async)) {
+        ETRACE("Blit failed");
+        return false;
+    }
+    return true;
+}
+
+} // namespace intel
+} // namespace android
diff --git a/merrifield/platforms/merrifield_plus/PlatfBufferManager.h b/merrifield/platforms/merrifield_plus/PlatfBufferManager.h
new file mode 100644
index 0000000..822f484
--- /dev/null
+++ b/merrifield/platforms/merrifield_plus/PlatfBufferManager.h
@@ -0,0 +1,43 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef PLATF_BUFFER_MANAGER_H
+#define PLATF_BUFFER_MANAGER_H
+
+#include <BufferManager.h>
+
+namespace android {
+namespace intel {
+
+class PlatfBufferManager : public BufferManager {
+public:
+    PlatfBufferManager();
+    virtual ~PlatfBufferManager();
+
+public:
+    bool initialize();
+    void deinitialize();
+
+protected:
+    DataBuffer* createDataBuffer(gralloc_module_t *module, buffer_handle_t handle);
+    BufferMapper* createBufferMapper(gralloc_module_t *module,
+                                        DataBuffer& buffer);
+    bool blit(buffer_handle_t srcHandle, buffer_handle_t destHandle,
+              const crop_t& destRect, bool filter, bool async);
+};
+
+}
+}
+#endif /* PLATF_BUFFER_MANAGER_H */
diff --git a/merrifield/test/Android.mk b/merrifield/test/Android.mk
new file mode 100644
index 0000000..b0a262e
--- /dev/null
+++ b/merrifield/test/Android.mk
@@ -0,0 +1,32 @@
+# Build the unit tests,
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := nv12_ved_test
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := \
+    nv12_ved_test.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+	libEGL \
+	libGLESv2 \
+	libbinder \
+	libcutils \
+	libgui \
+	libstlport \
+	libui \
+	libutils \
+
+LOCAL_C_INCLUDES := \
+    bionic \
+    $(call include-path-for, libstdc++) \
+    $(call include-path-for, gtest) \
+    $(call include-path-for, stlport)
+
+# Build the binary to $(TARGET_OUT_DATA_NATIVE_TESTS)/$(LOCAL_MODULE)
+# to integrate with auto-test framework.
+include $(BUILD_EXECUTABLE)
+
+
diff --git a/merrifield/test/my_640x480.nv12 b/merrifield/test/my_640x480.nv12
new file mode 100644
index 0000000..d8a0c34
--- /dev/null
+++ b/merrifield/test/my_640x480.nv12
Binary files differ
diff --git a/merrifield/test/nv12_ved_test.cpp b/merrifield/test/nv12_ved_test.cpp
new file mode 100644
index 0000000..7fb5b36
--- /dev/null
+++ b/merrifield/test/nv12_ved_test.cpp
@@ -0,0 +1,147 @@
+/*
+// Copyright (c) 2014 Intel Corporation 
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#include <gtest/gtest.h>
+
+#include <binder/IMemory.h>
+
+#include <gui/ISurfaceComposer.h>
+#include <gui/Surface.h>
+#include <gui/SurfaceComposerClient.h>
+#include <private/gui/ComposerService.h>
+
+#include <utils/String8.h>
+
+using namespace android;
+const char * filename = "/data/my_640x480.nv12";
+#define PIXEL_FORMAT_NV12 0x7FA00E00
+
+// Fill a YV12 buffer with a multi-colored checkerboard pattern
+void fillYUVBuffer(uint8_t* buf, int w, int h, int stride) {
+	const int blockWidth = w > 16 ? w / 16 : 1;
+	const int blockHeight = h > 16 ? h / 16 : 1;
+	const int yuvTexOffsetY = 0;
+	int yuvTexStrideY = stride;
+	int yuvTexOffsetV = yuvTexStrideY * h;
+	int yuvTexStrideV = (yuvTexStrideY / 2 + 0xf) & ~0xf;
+	int yuvTexOffsetU = yuvTexOffsetV + yuvTexStrideV * h / 2;
+	int yuvTexStrideU = yuvTexStrideV;
+	for (int x = 0; x < w; x++) {
+		for (int y = 0; y < h; y++) {
+			int parityX = (x / blockWidth) & 1;
+			int parityY = (y / blockHeight) & 1;
+			unsigned char intensity = (parityX ^ parityY) ? 63 : 191;
+			buf[yuvTexOffsetY + (y * yuvTexStrideY) + x] = intensity;
+			if (x < w / 2 && y < h / 2) {
+				buf[yuvTexOffsetU + (y * yuvTexStrideU) + x] = intensity;
+				if (x * 2 < w / 2 && y * 2 < h / 2) {
+					buf[yuvTexOffsetV + (y * 2 * yuvTexStrideV) + x * 2 + 0] =
+							buf[yuvTexOffsetV + (y * 2 * yuvTexStrideV) + x * 2
+									+ 1] =
+									buf[yuvTexOffsetV
+											+ ((y * 2 + 1) * yuvTexStrideV)
+											+ x * 2 + 0] = buf[yuvTexOffsetV
+											+ ((y * 2 + 1) * yuvTexStrideV)
+											+ x * 2 + 1] = intensity;
+				}
+			}
+		}
+	}
+}
+
+void loadYUVBufferFromFile(uint8_t* buf, int w, int h, int stride) {
+	FILE *fp = fopen(filename, "r");
+	int line = 0;
+	int offset = 0;
+	int buffer_height = h * 1.5;
+
+	if (!fp) {
+		printf("%s: failed to open %s\n", __func__, filename);
+		return;
+	}
+
+	printf("buf=%p, w=%d,h=%d,stride=%d\n", buf, w, h, stride);
+
+	for (line = 0; line < buffer_height; line++) {
+		printf("reading line %d...\n", line);
+		offset = line * stride;
+		fread(buf + offset, w, 1, fp);
+	}
+
+	fclose(fp);
+}
+
+int main(int argc, char **argv) {
+	sp < SurfaceControl > sc;
+	sp < Surface > s;
+	sp < ANativeWindow > anw;
+	ANativeWindowBuffer *anb;
+	uint8_t* img = NULL;
+	sp < SurfaceComposerClient > composerClient = new SurfaceComposerClient;
+	if (composerClient->initCheck() != NO_ERROR)
+		return 0;
+
+	sc = composerClient->createSurface(String8("FG Test Surface"), 640, 480,
+			PIXEL_FORMAT_RGBA_8888, 0);
+	if (sc == NULL)
+		return 0;;
+	if (!sc->isValid())
+		return 0;
+
+	s = sc->getSurface();
+	anw = s.get();
+	if (native_window_set_buffers_geometry(anw.get(), 640, 480,
+			PIXEL_FORMAT_NV12) != NO_ERROR)
+		return 0;
+	if (native_window_set_usage(anw.get(),
+			GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN)
+			!= NO_ERROR)
+		return 0;
+	
+	/*
+	 * load buffer 
+	 */
+	if (native_window_dequeue_buffer_and_wait(anw.get(), &anb))
+		return 0;
+	if (anb == NULL)
+		return 0;
+	sp < GraphicBuffer > buf(new GraphicBuffer(anb, false));
+	//if (anw->lockBuffer(anw.get(), buf->getNativeBuffer()) != NO_ERROR)
+	//	return 0;
+	buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**) (&img));
+	if (!img) {
+		printf("failed to lock buffer\n");
+		exit(-1);
+	}
+
+	loadYUVBufferFromFile(img, 640, 480, buf->getStride());
+	buf->unlock();
+	printf("querying buffer...\n");
+	if (anw->queueBuffer(anw.get(), buf->getNativeBuffer(), -1) != NO_ERROR)
+		return 0;
+
+	// loop it to continuously display??
+	while (1) {
+		SurfaceComposerClient::openGlobalTransaction();
+		if (sc->setLayer(INT_MAX - 1) != NO_ERROR)
+			return 0;
+		if (sc->show() != NO_ERROR)
+			return 0;
+
+		SurfaceComposerClient::closeGlobalTransaction();
+	}
+	return 0;
+}
+