Merge "hwc: Support for reading FB format from driver"
diff --git a/Android.mk b/Android.mk
index a128327..5070911 100644
--- a/Android.mk
+++ b/Android.mk
@@ -5,6 +5,7 @@
 endif
 
 display-hals := libgralloc libcopybit liblight libmemtrack libqservice libqdutils
+display-hals += hdmi_cec
 
 ifeq ($(TARGET_USES_SDE), true)
     sde-libs := displayengine/libs
diff --git a/common.mk b/common.mk
index 768696a..464f296 100644
--- a/common.mk
+++ b/common.mk
@@ -27,7 +27,6 @@
 
 ifeq ($(call is-board-platform-in-list, $(MSM_VIDC_TARGET_LIST)), true)
     common_flags += -DVENUS_COLOR_FORMAT
-    common_flags += -DMDSS_TARGET
 endif
 
 common_deps  :=
diff --git a/displayengine/include/core/debug_interface.h b/displayengine/include/core/debug_interface.h
index c90e1ff..ff72321 100644
--- a/displayengine/include/core/debug_interface.h
+++ b/displayengine/include/core/debug_interface.h
@@ -48,6 +48,7 @@
   kTagDriverConfig,     //!< Debug log is tagged for driver config.
   kTagBufferManager,    //!< Debug log is tagged for buffer manager state transitions.
   kTagOfflineCtrl,      //!< Debug log is tagged for offline controller.
+  kTagScalar,           //!< Debug log is tagged for Scalar Helper.
 };
 
 /*! @brief Display debug handler class.
diff --git a/displayengine/include/utils/constants.h b/displayengine/include/utils/constants.h
index 329dd86..8630d45 100644
--- a/displayengine/include/utils/constants.h
+++ b/displayengine/include/utils/constants.h
@@ -33,6 +33,7 @@
 #define INT(exp) static_cast<int>(exp)
 #define FLOAT(exp) static_cast<float>(exp)
 #define UINT8(exp) static_cast<uint8_t>(exp)
+#define UINT16(exp) static_cast<uint16_t>(exp)
 #define UINT32(exp) static_cast<uint32_t>(exp)
 #define INT32(exp) static_cast<int32_t>(exp)
 
@@ -56,6 +57,8 @@
 #define ROUND_UP_ALIGN_DOWN(value, a) FLOAT(FloorToMultipleOf(UINT32(value + 0.5f), UINT32(a)))
 #define ROUND_UP_ALIGN_UP(value, a) FLOAT(CeilToMultipleOf(UINT32(value + 0.5f), UINT32(a)))
 
+#define IDLE_TIMEOUT_DEFAULT_MS 70
+
 template <class T>
 inline void Swap(T &a, T &b) {
   T c(a);
diff --git a/displayengine/libs/core/Android.mk b/displayengine/libs/core/Android.mk
index c4c3d87..b7d2478 100644
--- a/displayengine/libs/core/Android.mk
+++ b/displayengine/libs/core/Android.mk
@@ -4,11 +4,14 @@
 LOCAL_MODULE                  := libsde
 LOCAL_MODULE_TAGS             := optional
 LOCAL_C_INCLUDES              := hardware/qcom/display/displayengine/include/ \
-                                 $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include \
-                                 $(TARGET_OUT_HEADERS)/scalar/inc
+                                 $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
 LOCAL_CFLAGS                  := -Wno-missing-field-initializers -Wno-unused-parameter \
                                  -Wconversion -Wall -Werror \
                                  -DLOG_TAG=\"SDE\"
+ifeq ($(TARGET_USES_SCALAR), true)
+  LOCAL_C_INCLUDES  += $(TARGET_OUT_HEADERS)/scalar/inc
+  LOCAL_CFLAGS      += -DUSES_SCALAR
+endif
 LOCAL_SHARED_LIBRARIES        := libdl libsdeutils libcutils
 LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
 LOCAL_SRC_FILES               := core_interface.cpp \
@@ -25,6 +28,7 @@
                                  hw_interface.cpp \
                                  hw_framebuffer.cpp \
                                  dump_impl.cpp \
-                                 buffer_manager.cpp
+                                 buffer_manager.cpp \
+                                 scalar_helper.cpp
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/displayengine/libs/core/display_base.cpp b/displayengine/libs/core/display_base.cpp
index dac17fd..d403450 100644
--- a/displayengine/libs/core/display_base.cpp
+++ b/displayengine/libs/core/display_base.cpp
@@ -152,12 +152,9 @@
       if (error == kErrorNone) {
         error = hw_intf_->Validate(hw_device_, &hw_layers_);
         if (error == kErrorNone) {
-          error = comp_manager_->PostPrepare(display_comp_ctx_, &hw_layers_);
-          if (error == kErrorNone) {
-            // Strategy is successful now, wait for Commit().
-            pending_commit_ = true;
-            break;
-          }
+          // Strategy is successful now, wait for Commit().
+          pending_commit_ = true;
+          break;
         }
       }
     }
diff --git a/displayengine/libs/core/hw_framebuffer.cpp b/displayengine/libs/core/hw_framebuffer.cpp
index 69d1efa..f3cdb8b 100644
--- a/displayengine/libs/core/hw_framebuffer.cpp
+++ b/displayengine/libs/core/hw_framebuffer.cpp
@@ -43,7 +43,7 @@
 #include <utils/debug.h>
 
 #include "hw_framebuffer.h"
-
+#include "scalar_helper.h"
 
 #define __CLASS__ "HWFrameBuffer"
 
@@ -684,7 +684,7 @@
         }
 
         mdp_layer.alpha = layer.plane_alpha;
-        mdp_layer.z_order = static_cast<uint16_t>(i);
+        mdp_layer.z_order = UINT16(pipe_info->z_order);
         mdp_layer.transp_mask = 0xffffffff;
         SetBlending(layer.blending, &mdp_layer.blend_op);
         mdp_layer.pipe_ndx = pipe_info->pipe_id;
@@ -706,14 +706,16 @@
           }
         }
 
-        if (pipe_info->scale_data.enable_pxl_ext) {
+        mdp_scale_data* mdp_scale = hw_display->GetScaleDataRef(mdp_layer_count);
+#ifdef USES_SCALAR
+        // Set the configured scale data for MDP driver
+        ScalarHelper::GetInstance()->SetScaleData(i, !count, mdp_scale);
+        if (mdp_scale->enable_pxl_ext) {
           if ((mdp_layer.flags & MDP_LAYER_DEINTERLACE) && (layer.transform.rotation == 90.0f))
-            mdp_buffer.width = pipe_info->scale_data.src_width;
-          hw_display->SetScaleData(pipe_info->scale_data, mdp_layer_count);
+            ScalarHelper::GetInstance()->UpdateSrcWidth(i, !count, &mdp_buffer.width);
         }
-
-        // Send scale data to MDP driver
-        mdp_layer.scale = hw_display->GetScaleRef(mdp_layer_count);
+#endif
+        mdp_layer.scale = mdp_scale;
         mdp_layer_count++;
 
         DLOGV_IF(kTagDriverConfig, "******************* Layer[%d] %s pipe Input ******************",
@@ -764,12 +766,34 @@
   mdp_commit.flags |= MDP_VALIDATE_LAYER;
   if (ioctl_(hw_context->device_fd, MSMFB_ATOMIC_COMMIT, &hw_display->mdp_disp_commit) < 0) {
     IOCTL_LOGE(MSMFB_ATOMIC_COMMIT, hw_context->type);
+    DumpLayerCommit(hw_display->mdp_disp_commit);
     return kErrorHardware;
   }
 
   return kErrorNone;
 }
 
+void HWFrameBuffer::DumpLayerCommit(mdp_layer_commit &layer_commit) {
+  mdp_layer_commit_v1 &mdp_commit = layer_commit.commit_v1;
+  mdp_input_layer *mdp_layers = mdp_commit.input_layers;
+
+  DLOGE("mdp_commt: flags = %x, release fence = %x", mdp_commit.flags, mdp_commit.release_fence);
+  DLOGE("left_roi: x = %d, y = %d, w = %d, h = %d", mdp_commit.left_roi.x, mdp_commit.left_roi.y,
+         mdp_commit.left_roi.w, mdp_commit.left_roi.h);
+  DLOGE("right_roi: x = %d, y = %d, w = %d, h = %d", mdp_commit.right_roi.x,
+         mdp_commit.right_roi.y, mdp_commit.right_roi.w, mdp_commit.right_roi.h);
+  for (uint32_t i = 0; i < mdp_commit.input_layer_cnt; i++) {
+    DLOGE("mdp_commt: layer_cnt = %d, pipe_ndx = %x, zorder = %d, flags = %x",
+          i, mdp_layers[i].pipe_ndx, mdp_layers[i].z_order, mdp_layers[i].flags);
+    mdp_rect &src_rect = mdp_layers[i].src_rect;
+    DLOGE("src rect: x = %d, y = %d, w = %d, h = %d",
+          src_rect.x, src_rect.y, src_rect.w, src_rect.h);
+    mdp_rect &dst_rect = mdp_layers[i].dst_rect;
+    DLOGE("dst rect: x = %d, y = %d, w = %d, h = %d",
+          dst_rect.x, dst_rect.y, dst_rect.w, dst_rect.h);
+  }
+}
+
 DisplayError HWFrameBuffer::DisplayCommit(HWContext *hw_context, HWLayers *hw_layers) {
   DTRACE_SCOPED();
 
@@ -857,6 +881,7 @@
   mdp_commit.flags &= ~MDP_VALIDATE_LAYER;
   if (ioctl_(hw_context->device_fd, MSMFB_ATOMIC_COMMIT, &hw_display->mdp_disp_commit) < 0) {
     IOCTL_LOGE(MSMFB_ATOMIC_COMMIT, hw_context->type);
+    DumpLayerCommit(hw_display->mdp_disp_commit);
     return kErrorHardware;
   }
 
@@ -1090,6 +1115,7 @@
       mdp_commit.flags &= ~MDP_VALIDATE_LAYER;
       if (ioctl_(hw_context->device_fd, MSMFB_ATOMIC_COMMIT, &hw_display->mdp_disp_commit) < 0) {
         IOCTL_LOGE(MSMFB_ATOMIC_COMMIT, hw_context->type);
+        DumpLayerCommit(hw_display->mdp_disp_commit);
         return kErrorHardware;
       }
     }
@@ -1152,6 +1178,7 @@
     *target = width * 3;
     break;
   case kFormatYCbCr420SemiPlanarVenus:
+  case kFormatYCbCr420SPVenusUbwc:
   case kFormatYCbCr420Planar:
   case kFormatYCrCb420Planar:
   case kFormatYCbCr420SemiPlanar:
diff --git a/displayengine/libs/core/hw_framebuffer.h b/displayengine/libs/core/hw_framebuffer.h
index 68a0674..b2a37ab 100644
--- a/displayengine/libs/core/hw_framebuffer.h
+++ b/displayengine/libs/core/hw_framebuffer.h
@@ -89,36 +89,7 @@
       mdp_disp_commit.commit_v1.retire_fence = -1;
     }
 
-    mdp_scale_data* GetScaleRef(uint32_t index) { return &scale_data[index]; }
-
-    void SetScaleData(scalar::Scale scale, uint32_t index) {
-      mdp_scale_data *mdp_scale = &scale_data[index];
-      mdp_scale->enable_pxl_ext = scale.enable_pxl_ext;
-
-      for (int i = 0; i < MAX_PLANES; i++) {
-        mdp_scale->init_phase_x[i] = scale.init_phase_x[i];
-        mdp_scale->phase_step_x[i] = scale.phase_step_x[i];
-        mdp_scale->init_phase_y[i] = scale.init_phase_y[i];
-        mdp_scale->phase_step_y[i] = scale.phase_step_y[i];
-
-        mdp_scale->num_ext_pxls_left[i] = scale.left.extension[i];
-        mdp_scale->num_ext_pxls_top[i] = scale.top.extension[i];
-        mdp_scale->num_ext_pxls_right[i] = scale.right.extension[i];
-        mdp_scale->num_ext_pxls_btm[i] = scale.bottom.extension[i];
-
-        mdp_scale->left_ftch[i] = scale.left.overfetch[i];
-        mdp_scale->top_ftch[i] = scale.top.overfetch[i];
-        mdp_scale->right_ftch[i] = scale.right.overfetch[i];
-        mdp_scale->btm_ftch[i] = scale.bottom.overfetch[i];
-
-        mdp_scale->left_rpt[i] = scale.left.repeat[i];
-        mdp_scale->top_rpt[i] = scale.top.repeat[i];
-        mdp_scale->right_rpt[i] = scale.right.repeat[i];
-        mdp_scale->btm_rpt[i] = scale.bottom.repeat[i];
-
-        mdp_scale->roi_w[i] = scale.roi_width[i];
-      }
-    }
+    mdp_scale_data* GetScaleDataRef(uint32_t index) { return &scale_data[index]; }
   };
 
   struct HWRotator {
@@ -198,7 +169,7 @@
 
   DisplayError RotatorValidate(HWContext *device_ctx, HWLayers *hw_layers);
   DisplayError RotatorCommit(HWContext *device_ctx, HWLayers *hw_layers);
-
+  void DumpLayerCommit(mdp_layer_commit &layer_commit);
   inline DisplayError SetFormat(const LayerBufferFormat &source, uint32_t *target);
   inline DisplayError SetStride(HWDeviceType device_type, LayerBufferFormat format,
                                 uint32_t width, uint32_t *target);
diff --git a/displayengine/libs/core/hw_interface.h b/displayengine/libs/core/hw_interface.h
index 9e003bb..b92846f 100644
--- a/displayengine/libs/core/hw_interface.h
+++ b/displayengine/libs/core/hw_interface.h
@@ -30,7 +30,6 @@
 #include <utils/constants.h>
 #include <core/buffer_allocator.h>
 #include <core/buffer_sync_handler.h>
-#include <scalar.h>
 
 namespace sde {
 
@@ -89,8 +88,8 @@
   HWResourceInfo()
     : hw_version(0), hw_revision(0), num_dma_pipe(0), num_vig_pipe(0), num_rgb_pipe(0),
       num_cursor_pipe(0), num_blending_stages(0), num_rotator(0), num_control(0),
-      num_mixer_to_disp(0), smp_total(0), smp_size(0), num_smp_per_pipe(0), max_scale_up(0),
-      max_scale_down(0), max_bandwidth_low(0), max_bandwidth_high(0), max_mixer_width(2048),
+      num_mixer_to_disp(0), smp_total(0), smp_size(0), num_smp_per_pipe(0), max_scale_up(1),
+      max_scale_down(1), max_bandwidth_low(0), max_bandwidth_high(0), max_mixer_width(2048),
       max_pipe_bw(0), max_sde_clk(0), clk_fudge_factor(1.0f), has_bwc(false),
       has_decimation(false), has_macrotile(false), has_rotator_downscale(false),
       has_non_scalar_rgb(false), is_src_split(false), always_src_split(false) { }
@@ -113,15 +112,14 @@
   LayerRect dst_roi;
   LayerBufferFormat dst_format;
   HWBlockType writeback_id;
-  float downscale_ratio_x;
-  float downscale_ratio_y;
+  float downscale_ratio;
   HWBufferInfo hw_buffer_info;
   bool valid;
   uint32_t frame_rate;
 
   HWRotateInfo() : input_buffer(NULL), pipe_id(0), dst_format(kFormatInvalid),
-                   writeback_id(kHWWriteback0), downscale_ratio_x(1.0f), downscale_ratio_y(1.0f),
-                   valid(false), frame_rate(0) { }
+                   writeback_id(kHWWriteback0), downscale_ratio(1.0f), valid(false),
+                   frame_rate(0) { }
 
   void Reset() { *this = HWRotateInfo(); }
 };
@@ -132,10 +130,11 @@
   LayerRect dst_roi;
   uint8_t horizontal_decimation;
   uint8_t vertical_decimation;
-  scalar::Scale scale_data;
   bool valid;
+  uint32_t z_order;
 
-  HWPipeInfo() : pipe_id(0), horizontal_decimation(0), vertical_decimation(0), valid(false) { }
+  HWPipeInfo() : pipe_id(0), horizontal_decimation(0), vertical_decimation(0), valid(false),
+                 z_order(0) { }
 
   void Reset() { *this = HWPipeInfo(); }
 };
diff --git a/displayengine/libs/core/res_config.cpp b/displayengine/libs/core/res_config.cpp
index 72edeb6..27a4e41 100644
--- a/displayengine/libs/core/res_config.cpp
+++ b/displayengine/libs/core/res_config.cpp
@@ -31,54 +31,55 @@
 
 #define __CLASS__ "ResManager"
 
-using scalar::PipeInfo;
-using scalar::LayerInfo;
-
 namespace sde {
 
-void ResManager::RotationConfig(const LayerTransform &transform, const float &scale_x,
-                                const float &scale_y, LayerRect *src_rect,
+void ResManager::RotationConfig(LayerBufferFormat format, const LayerTransform &transform,
+                                const float &downscale, LayerRect *src_rect,
                                 struct HWLayerConfig *layer_config, uint32_t *rotate_count) {
   HWRotateInfo *rotate = &layer_config->rotates[0];
   float src_width = src_rect->right - src_rect->left;
   float src_height = src_rect->bottom - src_rect->top;
+  bool rot90 = IsRotationNeeded(transform.rotation);
   LayerRect dst_rect;
   // Rotate output is a temp buffer, always output to the top left corner for saving memory
   dst_rect.top = 0.0f;
   dst_rect.left = 0.0f;
 
-  rotate->downscale_ratio_x = scale_x;
-  rotate->downscale_ratio_y = scale_y;
+  rotate->downscale_ratio = downscale;
 
   // downscale when doing rotation
-  if (IsRotationNeeded(transform.rotation)) {
-    if (rotate->downscale_ratio_x > 1.0f) {
-      src_height = ROUND_UP_ALIGN_DOWN(src_height, rotate->downscale_ratio_x);
+  if (rot90) {
+    if (downscale > 1.0f) {
+      src_height = ROUND_UP_ALIGN_DOWN(src_height, downscale);
       src_rect->bottom = src_rect->top + src_height;
-    }
-    if (rotate->downscale_ratio_y > 1.0f) {
-      src_width = ROUND_UP_ALIGN_DOWN(src_width, rotate->downscale_ratio_y);
+      src_width = ROUND_UP_ALIGN_DOWN(src_width, downscale);
       src_rect->right = src_rect->left + src_width;
     }
-    dst_rect.right = src_height / rotate->downscale_ratio_x;
-    dst_rect.bottom = src_width / rotate->downscale_ratio_y;
+    dst_rect.right = src_height / downscale;
+    dst_rect.bottom = src_width / downscale;
   } else {
-    if (rotate->downscale_ratio_x > 1.0f) {
-      src_width = ROUND_UP_ALIGN_DOWN(src_width, rotate->downscale_ratio_x);
+    if (downscale > 1.0f) {
+      src_width = ROUND_UP_ALIGN_DOWN(src_width, downscale);
       src_rect->right = src_rect->left + src_width;
-    }
-    if (rotate->downscale_ratio_y > 1.0f) {
-      src_height = ROUND_UP_ALIGN_DOWN(src_height, rotate->downscale_ratio_y);
+      src_height = ROUND_UP_ALIGN_DOWN(src_height, downscale);
       src_rect->bottom = src_rect->top + src_height;
     }
-    dst_rect.right = src_width / rotate->downscale_ratio_x;
-    dst_rect.bottom = src_height / rotate->downscale_ratio_y;
+    dst_rect.right = src_width / downscale;
+    dst_rect.bottom = src_height / downscale;
   }
 
   rotate->src_roi = *src_rect;
   rotate->valid = true;
   rotate->dst_roi = dst_rect;
 
+  // Set WHF for Rotator output
+  LayerBufferFormat ouput_format;
+  SetRotatorOutputFormat(format, false /* bwc */, rot90, downscale, &ouput_format);
+  HWBufferInfo *hw_buffer_info = &rotate->hw_buffer_info;
+  hw_buffer_info->buffer_config.format = ouput_format;
+  hw_buffer_info->buffer_config.width = UINT32(rotate->dst_roi.right);
+  hw_buffer_info->buffer_config.height = UINT32(rotate->dst_roi.bottom);
+
   *src_rect = dst_rect;
   layer_config->num_rotate = 1;
   (*rotate_count)++;
@@ -91,9 +92,30 @@
   HWDisplayAttributes &display_attributes = display_resource_ctx->display_attributes;
   HWPipeInfo *left_pipe = &layer_config->left_pipe;
   HWPipeInfo *right_pipe = &layer_config->right_pipe;
+  float src_width = src_rect.right - src_rect.left;
+  float dst_width = dst_rect.right - dst_rect.left;
+  float src_height = src_rect.bottom - src_rect.top;
+  float dst_height = dst_rect.bottom - dst_rect.top;
+  float left_mixer_width = FLOAT(display_attributes.split_left);
 
-  if ((src_rect.right - src_rect.left) > kMaxSourcePipeWidth ||
-      (dst_rect.right - dst_rect.left) > kMaxInterfaceWidth || hw_res_info_.always_src_split) {
+  uint8_t decimation = 0;
+  if (CalculateDecimation((src_height / dst_height), &decimation) != kErrorNone) {
+    return kErrorNotSupported;
+  }
+  // Adjust source height to consider decimation
+  src_height /= powf(2.0f, decimation);
+
+  // No need to include common factors in clock calculation of pipe & mixer
+  float pipe_clock = MAX(dst_width, (dst_width * src_height / dst_height));
+  float mixer_clock = left_mixer_width;
+
+  // Layer cannot qualify for SrcSplit if source or destination width exceeds max pipe width.
+  // For perf/power optimization, even if "always_src_split" is enabled, use 2 pipes only if:
+  // 1. Source width is greater than split_left (left_mixer_width)
+  // 2. Pipe clock exceeds the mixer clock
+  if ((src_width > kMaxSourcePipeWidth) || (dst_width > kMaxSourcePipeWidth) ||
+      (hw_res_info_.always_src_split && ((src_width > left_mixer_width) ||
+      (pipe_clock > mixer_clock)))) {
     SplitRect(transform.flip_horizontal, src_rect, dst_rect, &left_pipe->src_roi,
               &left_pipe->dst_roi, &right_pipe->src_roi, &right_pipe->dst_roi, align_x);
     left_pipe->valid = true;
@@ -190,12 +212,6 @@
     right_pipe->Reset();
   }
 
-  // TODO(user) remove this when zorder is assigned properly, check num_blending_stages on pipes
-  if (!display_attributes.is_device_split && right_pipe->valid) {
-    DLOGV_IF(kTagResources, "Non display split, do not support 2 pipes for now");
-    return kErrorNotSupported;
-  }
-
   return kErrorNone;
 }
 
@@ -205,10 +221,11 @@
   HWDisplayAttributes &display_attributes = display_resource_ctx->display_attributes;
   HWLayersInfo &layer_info = hw_layers->info;
   DisplayError error = kErrorNone;
+  uint32_t z_order = 0;
 
   for (uint32_t i = 0; i < layer_info.count; i++) {
     Layer& layer = layer_info.stack->layers[layer_info.index[i]];
-    float rot_scale_x = 1.0f, rot_scale_y = 1.0f;
+    float rot_scale = 1.0f;
     if (!IsValidDimension(layer.src_rect, layer.dst_rect)) {
       DLOGV_IF(kTagResources, "Input is invalid");
       LogRect(kTagResources, "input layer src_rect", layer.src_rect);
@@ -241,7 +258,7 @@
       NormalizeRect(align_x, align_y, &src_rect);
     }
 
-    if (ValidateScaling(layer, src_rect, dst_rect, &rot_scale_x, &rot_scale_y)) {
+    if (ValidateScaling(layer, src_rect, dst_rect, &rot_scale)) {
       return kErrorNotSupported;
     }
 
@@ -252,10 +269,9 @@
     layer_config->num_rotate = 0;
 
     LayerTransform transform = layer.transform;
-    if (IsRotationNeeded(transform.rotation) ||
-        UINT32(rot_scale_x) != 1 || UINT32(rot_scale_y) != 1) {
-      RotationConfig(layer.transform, rot_scale_x, rot_scale_y, &src_rect, layer_config,
-                     rotate_count);
+    if (IsRotationNeeded(transform.rotation) || UINT32(rot_scale) != 1) {
+      RotationConfig(layer.input_buffer->format, layer.transform, rot_scale, &src_rect,
+                     layer_config, rotate_count);
       // rotator will take care of flipping, reset tranform
       transform = LayerTransform();
     }
@@ -282,8 +298,7 @@
     LogRect(kTagResources, "input layer src_rect", layer.src_rect);
     LogRect(kTagResources, "input layer dst_rect", layer.dst_rect);
     for (uint32_t k = 0; k < layer_config->num_rotate; k++) {
-      DLOGV_IF(kTagResources, "rotate num = %d, scale_x = %.2f, scale_y = %.2f",
-               k, rot_scale_x, rot_scale_y);
+      DLOGV_IF(kTagResources, "rotate num = %d, scale_x = %.2f", k, rot_scale);
       LogRect(kTagResources, "rotate src", layer_config->rotates[k].src_roi);
       LogRect(kTagResources, "rotate dst", layer_config->rotates[k].dst_roi);
     }
@@ -296,15 +311,32 @@
       LogRect(kTagResources, "right pipe src", layer_config->right_pipe.src_roi);
       LogRect(kTagResources, "right pipe dst", layer_config->right_pipe.dst_roi);
     }
+    // set z_order, left_pipe should always be valid
+    left_pipe.z_order = z_order;
+    if (layer_config->right_pipe.valid) {
+      // use different z_order if 2 pipes are on one mixer and without src split support
+      if (!hw_res_info_.is_src_split &&
+          ((left_pipe.dst_roi.right <= display_attributes.split_left &&
+            right_pipe.dst_roi.right <= display_attributes.split_left) ||
+           (left_pipe.dst_roi.left >= display_attributes.split_left &&
+            right_pipe.dst_roi.left >= display_attributes.split_left))) {
+        z_order++;
+      }
+      layer_config->right_pipe.z_order = z_order;
+    }
+    z_order++;
+    if (z_order >= hw_res_info_.num_blending_stages) {
+      DLOGV_IF(kTagResources, "z_order is over the limit: z_order = %d", z_order);
+      return kErrorResources;
+    }
   }
 
   return error;
 }
 
 DisplayError ResManager::ValidateScaling(const Layer &layer, const LayerRect &crop,
-                                         const LayerRect &dst, float *rot_scale_x,
-                                         float *rot_scale_y) {
-  bool rotated90 = IsRotationNeeded(layer.transform.rotation) && (rot_scale_x != NULL);
+                                         const LayerRect &dst, float *rot_scale) {
+  bool rotated90 = IsRotationNeeded(layer.transform.rotation) && (rot_scale != NULL);
   float crop_width = rotated90 ? crop.bottom - crop.top : crop.right - crop.left;
   float crop_height = rotated90 ? crop.right - crop.left : crop.bottom - crop.top;
   float dst_width = dst.right - dst.left;
@@ -330,31 +362,43 @@
 
   float scale_x = crop_width / dst_width;
   float scale_y = crop_height / dst_height;
-  bool use_rotator = false;
+  uint32_t rot_scale_local = 1;
 
   if ((UINT32(scale_x) > 1) || (UINT32(scale_y) > 1)) {
-    uint32_t max_scale_down = hw_res_info_.max_scale_down;
+    float max_scale_down = FLOAT(hw_res_info_.max_scale_down);
 
     if (hw_res_info_.has_rotator_downscale && !property_setting_.disable_rotator_downscaling &&
-        rot_scale_x) {
-      max_scale_down *= kMaxRotateDownScaleRatio;
-      use_rotator = true;
-    } else if (hw_res_info_.has_decimation && !property_setting_.disable_decimation &&
-               !IsMacroTileFormat(layer.input_buffer)) {
-      max_scale_down *= kMaxDecimationDownScaleRatio;
+        rot_scale && !IsMacroTileFormat(layer.input_buffer)) {
+      float scale_min = MIN(scale_x, scale_y);
+      float scale_max = MAX(scale_x, scale_y);
+      // use rotator to downscale when over the pipe scaling ability
+      if (UINT32(scale_min) >= 2 && scale_max > max_scale_down) {
+        // downscaling ratio needs be the same for both direction, use the smaller one.
+        rot_scale_local = 1 << UINT32(ceilf(log2f(scale_min / max_scale_down)));
+        if (rot_scale_local > kMaxRotateDownScaleRatio)
+          rot_scale_local = kMaxRotateDownScaleRatio;
+        scale_x /= FLOAT(rot_scale_local);
+        scale_y /= FLOAT(rot_scale_local);
+      }
+      *rot_scale = FLOAT(rot_scale_local);
     }
 
-    if (scale_x > FLOAT(max_scale_down) || scale_y > FLOAT(max_scale_down)) {
+    if (hw_res_info_.has_decimation && !property_setting_.disable_decimation &&
+               !IsMacroTileFormat(layer.input_buffer)) {
+      max_scale_down *= FLOAT(kMaxDecimationDownScaleRatio);
+    }
+
+    if (scale_x > max_scale_down || scale_y > max_scale_down) {
       DLOGV_IF(kTagResources,
                "Scaling down is over the limit: is_tile = %d, scale_x = %.0f, scale_y = %.0f, " \
-               "crop_w = %.0f, dst_w = %.0f, has_deci = %d, disable_deci = %d",
+               "crop_w = %.0f, dst_w = %.0f, has_deci = %d, disable_deci = %d, rot_scale = %d",
                IsMacroTileFormat(layer.input_buffer), scale_x, scale_y, crop_width, dst_width,
-               hw_res_info_.has_decimation, property_setting_.disable_decimation);
+               hw_res_info_.has_decimation, property_setting_.disable_decimation, rot_scale_local);
       return kErrorNotSupported;
     }
   }
 
-  const uint32_t max_scale_up = hw_res_info_.max_scale_up;
+  float max_scale_up = FLOAT(hw_res_info_.max_scale_up);
   if (UINT32(scale_x) < 1 && scale_x > 0.0f) {
     if ((1.0f / scale_x) > max_scale_up) {
       DLOGV_IF(kTagResources, "Scaling up is over limit scale_x = %f", 1.0f / scale_x);
@@ -369,24 +413,8 @@
     }
   }
 
-  if (rot_scale_x == NULL) {
-    return kErrorNone;
-  }
-
-  // Calculate rotator downscale ratio
-  if (scale_x > hw_res_info_.max_scale_down && use_rotator) {
-    *rot_scale_x = FLOAT(1 << UINT32(ceilf(log2f(scale_x / FLOAT(hw_res_info_.max_scale_down)))));
-  } else {
-    *rot_scale_x = 1.0f;
-  }
-
-  if (scale_y > hw_res_info_.max_scale_down && use_rotator) {
-    *rot_scale_y = FLOAT(1 << UINT32(ceilf(log2f(scale_y / FLOAT(hw_res_info_.max_scale_down)))));
-  } else {
-    *rot_scale_y = 1.0f;
-  }
-  DLOGV_IF(kTagResources, "scale_x = %.0f, scale_y = %.0f, rot_scale_x = %.0f, rot_scale_y = %.0f",
-           scale_x, scale_y, *rot_scale_x, *rot_scale_y);
+  DLOGV_IF(kTagResources, "scale_x = %.4f, scale_y = %.4f, rot_scale = %d",
+           scale_x, scale_y, rot_scale_local);
 
   return kErrorNone;
 }
@@ -496,7 +524,6 @@
 }
 
 DisplayError ResManager::SetDecimationFactor(HWPipeInfo *pipe) {
-  float max_down_scale = FLOAT(hw_res_info_.max_scale_down);
   float src_h = pipe->src_roi.bottom - pipe->src_roi.top;
   float dst_h = pipe->dst_roi.bottom - pipe->dst_roi.top;
   float down_scale_h = src_h / dst_h;
@@ -505,28 +532,17 @@
   float dst_w = pipe->dst_roi.right - pipe->dst_roi.left;
   float down_scale_w = src_w / dst_w;
 
-
   pipe->horizontal_decimation = 0;
   pipe->vertical_decimation = 0;
 
-  // TODO(user): Need to check for the maximum downscale limit for decimation and return error
-  if (!hw_res_info_.has_decimation && ((down_scale_w > max_down_scale) ||
-      (down_scale_h > max_down_scale))) {
-    DLOGV("Downscaling exceeds the maximum MDP downscale limit and decimation not enabled");
+  if (CalculateDecimation(down_scale_w, &pipe->horizontal_decimation) != kErrorNone) {
     return kErrorNotSupported;
   }
 
-  if ((down_scale_w <= max_down_scale) && (down_scale_h <= max_down_scale)) {
-    return kErrorNone;
+  if (CalculateDecimation(down_scale_h, &pipe->vertical_decimation) != kErrorNone) {
+    return kErrorNotSupported;
   }
 
-  // Decimation is the remaining downscale factor after doing max SDE downscale.
-  // In SDE, decimation is supported in powers of 2.
-  // For ex: If a pipe needs downscale of 8 but max_down_scale is 4
-  // So decimation = powf(2.0, ceilf(log2f(8) - log2f(4))) = powf(2.0, 1.0) = 2
-  pipe->horizontal_decimation = UINT8(ceilf(log2f(down_scale_w) - log2f(max_down_scale)));
-  pipe->vertical_decimation = UINT8(ceilf(log2f(down_scale_h) - log2f(max_down_scale)));
-
   DLOGI_IF(kTagResources, "horizontal_decimation %d, vertical_decimation %d",
            pipe->horizontal_decimation, pipe->vertical_decimation);
 
@@ -586,125 +602,6 @@
   }
 }
 
-// Scalar helper functions
-static void SetPipeInfo(HWPipeInfo* hw_pipe, PipeInfo* pipe) {
-  pipe->id = hw_pipe->pipe_id;
-  pipe->scale_data = &hw_pipe->scale_data;
-  pipe->horz_deci = hw_pipe->horizontal_decimation;
-  pipe->vert_deci = hw_pipe->vertical_decimation;
-
-  pipe->src_rect.x = UINT32(hw_pipe->src_roi.left);
-  pipe->src_rect.y = UINT32(hw_pipe->src_roi.top);
-  pipe->src_rect.w = UINT32(hw_pipe->src_roi.right) - pipe->src_rect.x;
-  pipe->src_rect.h = UINT32(hw_pipe->src_roi.bottom) - pipe->src_rect.y;
-
-  pipe->dst_rect.x = UINT32(hw_pipe->dst_roi.left);
-  pipe->dst_rect.y = UINT32(hw_pipe->dst_roi.top);
-  pipe->dst_rect.w = UINT32(hw_pipe->dst_roi.right) - pipe->dst_rect.x;
-  pipe->dst_rect.h = UINT32(hw_pipe->dst_roi.bottom) - pipe->dst_rect.y;
-}
-
-static void UpdateSrcRoi(PipeInfo* pipe, HWPipeInfo* hw_pipe) {
-  hw_pipe->src_roi.left   = FLOAT(pipe->src_rect.x);
-  hw_pipe->src_roi.top    = FLOAT(pipe->src_rect.y);
-  hw_pipe->src_roi.right  = FLOAT(pipe->src_rect.x + pipe->src_rect.w);
-  hw_pipe->src_roi.bottom = FLOAT(pipe->src_rect.y + pipe->src_rect.h);
-}
-
-static uint32_t GetScalarFormat(LayerBufferFormat source) {
-  uint32_t format = scalar::UNKNOWN_FORMAT;
-
-  switch (source) {
-  case kFormatARGB8888:                 format = scalar::ARGB_8888;         break;
-  case kFormatRGBA8888:                 format = scalar::RGBA_8888;         break;
-  case kFormatBGRA8888:                 format = scalar::BGRA_8888;         break;
-  case kFormatXRGB8888:                 format = scalar::XRGB_8888;         break;
-  case kFormatRGBX8888:                 format = scalar::RGBX_8888;         break;
-  case kFormatBGRX8888:                 format = scalar::BGRX_8888;         break;
-  case kFormatRGB888:                   format = scalar::RGB_888;           break;
-  case kFormatRGB565:                   format = scalar::RGB_565;           break;
-  case kFormatYCbCr420Planar:           format = scalar::Y_CB_CR_H2V2;      break;
-  case kFormatYCrCb420Planar:           format = scalar::Y_CR_CB_H2V2;      break;
-  case kFormatYCbCr420SemiPlanar:       format = scalar::Y_CBCR_H2V2;       break;
-  case kFormatYCrCb420SemiPlanar:       format = scalar::Y_CRCB_H2V2;       break;
-  case kFormatYCbCr422Packed:           format = scalar::YCBYCR_H2V1;       break;
-  case kFormatYCbCr420SemiPlanarVenus:  format = scalar::Y_CBCR_H2V2_VENUS; break;
-  case kFormatRGBA8888Ubwc:             format = scalar::RGBA_8888_UBWC;    break;
-  case kFormatRGB565Ubwc:               format = scalar::RGB_565_UBWC;      break;
-  case kFormatYCbCr420SPVenusUbwc:      format = scalar::Y_CBCR_H2V2_UBWC;  break;
-  default:
-    DLOGE("Unsupported source format: %x", source);
-    break;
-  }
-
-  return format;
-}
-
-bool ResManager::ConfigureScaling(HWLayers *hw_layers) {
-  HWLayersInfo &hw_layer_info = hw_layers->info;
-
-  for (uint32_t i = 0; i < hw_layer_info.count; i++) {
-    Layer &layer = hw_layer_info.stack->layers[hw_layer_info.index[i]];
-    LayerBuffer *input_buffer = layer.input_buffer;
-    HWPipeInfo* left_pipe = &hw_layers->config[i].left_pipe;
-    HWPipeInfo* right_pipe = &hw_layers->config[i].right_pipe;
-
-    // Prepare data structure for lib scalar
-    uint32_t flags = 0;
-    struct LayerInfo layer_info;
-
-    if (layer.transform.rotation == 90.0f) {
-      // Flips will be taken care by rotator, if layer requires 90 rotation
-      flags |= scalar::SCALAR_SOURCE_ROTATED_90;
-    } else {
-      flags |= layer.transform.flip_vertical ? scalar::SCALAR_FLIP_UD : 0;
-      flags |= layer.transform.flip_horizontal ? scalar::SCALAR_FLIP_LR : 0;
-    }
-
-    for (uint32_t count = 0; count < 2; count++) {
-      HWPipeInfo* hw_pipe = (count == 0) ? left_pipe : right_pipe;
-      HWRotateInfo* rotate_info = &hw_layers->config[i].rotates[count];
-      PipeInfo* scalar_pipe = (count == 0) ? &layer_info.left_pipe : &layer_info.right_pipe;
-
-      if (rotate_info->valid)
-        input_buffer = &rotate_info->hw_buffer_info.output_buffer;
-
-      scalar_pipe->flags = flags;
-      hw_pipe->scale_data.src_width = input_buffer->width;
-      SetPipeInfo(hw_pipe, scalar_pipe);
-    }
-    layer_info.src_format = GetScalarFormat(input_buffer->format);
-
-    DLOGV_IF(kTagResources, "Scalar Input[%d] flags=%x format=%x", i, flags, layer_info.src_format);
-    DLOGV_IF(kTagResources, "Left: id=%d hD=%d vD=%d srcRect=[%d %d %d %d] dstRect=[%d %d %d %d]",
-        layer_info.left_pipe.id, layer_info.left_pipe.horz_deci, layer_info.left_pipe.vert_deci,
-        layer_info.left_pipe.src_rect.x, layer_info.left_pipe.src_rect.y,
-        layer_info.left_pipe.src_rect.w, layer_info.left_pipe.src_rect.h,
-        layer_info.left_pipe.dst_rect.x, layer_info.left_pipe.dst_rect.y,
-        layer_info.left_pipe.dst_rect.w, layer_info.left_pipe.dst_rect.h);
-    DLOGV_IF(kTagResources, "Right: id=%d hD=%d vD=%d srcRect=[%d %d %d %d] dstRect=[%d %d %d %d]",
-        layer_info.right_pipe.id, layer_info.right_pipe.horz_deci, layer_info.right_pipe.vert_deci,
-        layer_info.right_pipe.src_rect.x, layer_info.right_pipe.src_rect.y,
-        layer_info.right_pipe.src_rect.w, layer_info.right_pipe.src_rect.h,
-        layer_info.right_pipe.dst_rect.x, layer_info.right_pipe.dst_rect.y,
-        layer_info.right_pipe.dst_rect.w, layer_info.right_pipe.dst_rect.h);
-
-    // Configure scale data structure
-    if (ScalarConfigureScale(&layer_info) < 0) {
-      DLOGE("Scalar library failed to configure scale data!");
-      return false;
-    }
-
-    // Update Src Roi in HWPipeInfo
-    if (left_pipe->scale_data.enable_pxl_ext)
-      UpdateSrcRoi(&layer_info.left_pipe, left_pipe);
-    if (right_pipe->scale_data.enable_pxl_ext)
-      UpdateSrcRoi(&layer_info.right_pipe, right_pipe);
-  }
-
-  return true;
-}
-
 DisplayError ResManager::AlignPipeConfig(const Layer &layer, const LayerTransform &transform,
                                          HWPipeInfo *left_pipe, HWPipeInfo *right_pipe,
                                          uint32_t align_x, uint32_t align_y) {
@@ -735,13 +632,13 @@
       right_pipe->dst_roi.left = left_pipe->dst_roi.right;
     }
   }
-  error = ValidateScaling(layer, left_pipe->src_roi, left_pipe->dst_roi, NULL, NULL);
+  error = ValidateScaling(layer, left_pipe->src_roi, left_pipe->dst_roi, NULL);
   if (error != kErrorNone) {
     goto PipeConfigExit;
   }
 
   if (right_pipe->valid) {
-    error = ValidateScaling(layer, right_pipe->src_roi, right_pipe->dst_roi, NULL, NULL);
+    error = ValidateScaling(layer, right_pipe->src_roi, right_pipe->dst_roi, NULL);
   }
 PipeConfigExit:
   if (error != kErrorNone) {
@@ -750,4 +647,23 @@
   return error;
 }
 
+DisplayError ResManager::CalculateDecimation(float downscale, uint8_t* decimation) {
+  float max_down_scale = FLOAT(hw_res_info_.max_scale_down);
+
+  if (downscale <= max_down_scale) {
+    *decimation = 0;
+    return kErrorNone;
+  } else if (!hw_res_info_.has_decimation) {
+    DLOGE("Downscaling exceeds the maximum MDP downscale limit but decimation not enabled");
+    return kErrorNotSupported;
+  }
+
+  // Decimation is the remaining downscale factor after doing max SDE downscale.
+  // In SDE, decimation is supported in powers of 2.
+  // For ex: If a pipe needs downscale of 8 but max_down_scale is 4
+  // So decimation = powf(2.0, ceilf(log2f(8 / 4))) = powf(2.0, 1.0) = 2
+  *decimation = UINT8(ceilf(log2f(downscale / max_down_scale)));
+  return kErrorNone;
+}
+
 }  // namespace sde
diff --git a/displayengine/libs/core/res_manager.cpp b/displayengine/libs/core/res_manager.cpp
index dfd1e0a..14cf11f 100644
--- a/displayengine/libs/core/res_manager.cpp
+++ b/displayengine/libs/core/res_manager.cpp
@@ -28,9 +28,9 @@
 #include <dlfcn.h>
 
 #include "res_manager.h"
+#include "scalar_helper.h"
 
 #define __CLASS__ "ResManager"
-#define SCALAR_LIBRARY_NAME "libscalar.so"
 
 namespace sde {
 
@@ -54,8 +54,6 @@
 
   DisplayError error = kErrorNone;
 
-  // TODO(user): Remove this. Disable src_split as kernel not supported yet
-  hw_res_info_.is_src_split = false;
   num_pipe_ = hw_res_info_.num_vig_pipe + hw_res_info_.num_rgb_pipe + hw_res_info_.num_dma_pipe;
 
   if (num_pipe_ > kPipeIdMax) {
@@ -98,7 +96,14 @@
 
   if (hw_res_info_.num_rotator > kMaxNumRotator) {
     DLOGE("Number of rotator is over the limit! %d", hw_res_info_.num_rotator);
-    return kErrorParameters;
+    hw_res_info_.num_rotator = kMaxNumRotator;
+  }
+
+  if (hw_res_info_.max_scale_down < 1 || hw_res_info_.max_scale_up < 1) {
+    DLOGE("Max scaling setting is invalid! max_scale_down = %d, max_scale_up = %d",
+          hw_res_info_.max_scale_down, hw_res_info_.max_scale_up);
+    hw_res_info_.max_scale_down = 1;
+    hw_res_info_.max_scale_up = 1;
   }
 
   if (hw_res_info_.num_rotator > 0) {
@@ -114,23 +119,16 @@
   rgb_pipes_[0].state = kPipeStateOwnedByKernel;
   rgb_pipes_[1].state = kPipeStateOwnedByKernel;
 
-  ScalarConfigureScale = NULL;
-  lib_scalar_handle_ = dlopen(SCALAR_LIBRARY_NAME, RTLD_NOW);
-  if (lib_scalar_handle_) {
-    void **scalar_func = reinterpret_cast<void **>(&ScalarConfigureScale);
-    *scalar_func = ::dlsym(lib_scalar_handle_, "configureScale");
-  } else {
-    DLOGW("Unable to load %s !", SCALAR_LIBRARY_NAME);
-  }
-
+#ifdef USES_SCALAR
+  ScalarHelper::GetInstance()->Init();
+#endif
   return kErrorNone;
 }
 
 DisplayError ResManager::Deinit() {
-  if (lib_scalar_handle_) {
-    dlclose(lib_scalar_handle_);
-    lib_scalar_handle_ = NULL;
-  }
+#ifdef USES_SCALAR
+  ScalarHelper::GetInstance()->Deinit();
+#endif
   return kErrorNone;
 }
 
@@ -274,6 +272,7 @@
   DLOGV_IF(kTagResources, "==== Resource reserving start: hw_block = %d ====", hw_block_id);
 
   if (layer_info.count > num_pipe_ || layer_info.count >= hw_res_info_.num_blending_stages) {
+    DLOGV_IF(kTagResources, "layer count is over the limit: layer count = %d", layer_info.count);
     return kErrorResources;
   }
 
@@ -384,24 +383,24 @@
              i, layer_config.left_pipe.pipe_id,  pipe_info->pipe_id);
   }
 
-  error = AllocRotatorBuffer(display_ctx, hw_layers);
-  if (error != kErrorNone) {
-    DLOGV_IF(kTagResources, "Rotator buffer allocation failed");
+#ifdef USES_SCALAR
+  if (!ScalarHelper::GetInstance()->ConfigureScale(hw_layers)) {
+    DLOGV_IF(kTagResources, "Scale data configuration has failed!");
     goto CleanupOnError;
   }
-
-  if (lib_scalar_handle_ && ScalarConfigureScale) {
-    if (!ConfigureScaling(hw_layers)) {
-      DLOGV_IF(kTagResources, "Scale data configuration has failed!");
-      goto CleanupOnError;
-    }
-  }
+#endif
 
   if (!CheckBandwidth(display_resource_ctx, hw_layers)) {
     DLOGV_IF(kTagResources, "Bandwidth check failed!");
     goto CleanupOnError;
   }
 
+  error = AllocRotatorBuffer(display_ctx, hw_layers);
+  if (error != kErrorNone) {
+    DLOGV_IF(kTagResources, "Rotator buffer allocation failed");
+    goto CleanupOnError;
+  }
+
   return kErrorNone;
 
 CleanupOnError:
@@ -620,6 +619,7 @@
     case kFormatYCbCr420SemiPlanar:
     case kFormatYCrCb420SemiPlanar:
     case kFormatYCbCr420SemiPlanarVenus:
+    case kFormatYCbCr420SPVenusUbwc:
       return 1.5f;
     default:
       DLOGE("GetBpp: Invalid buffer format: %x", format);
@@ -642,16 +642,9 @@
   for (uint32_t i = 0; i < layer_info.count; i++) {
     Layer& layer = layer_info.stack->layers[layer_info.index[i]];
     HWRotateInfo *rotate = &hw_layers->config[i].rotates[0];
-    bool rot90 = (layer.transform.rotation == 90.0f);
 
     if (rotate->valid) {
-      LayerBufferFormat rot_ouput_format;
-      SetRotatorOutputFormat(layer.input_buffer->format, false, rot90, &rot_ouput_format);
-
       HWBufferInfo *hw_buffer_info = &rotate->hw_buffer_info;
-      hw_buffer_info->buffer_config.width = UINT32(rotate->dst_roi.right - rotate->dst_roi.left);
-      hw_buffer_info->buffer_config.height = UINT32(rotate->dst_roi.bottom - rotate->dst_roi.top);
-      hw_buffer_info->buffer_config.format = rot_ouput_format;
       // Allocate two rotator output buffers by default for double buffering.
       hw_buffer_info->buffer_config.buffer_count = 2;
       hw_buffer_info->buffer_config.secure = layer.input_buffer->flags.secure;
@@ -664,13 +657,7 @@
 
     rotate = &hw_layers->config[i].rotates[1];
     if (rotate->valid) {
-      LayerBufferFormat rot_ouput_format;
-      SetRotatorOutputFormat(layer.input_buffer->format, false, rot90, &rot_ouput_format);
-
       HWBufferInfo *hw_buffer_info = &rotate->hw_buffer_info;
-      hw_buffer_info->buffer_config.width = UINT32(rotate->dst_roi.right - rotate->dst_roi.left);
-      hw_buffer_info->buffer_config.height = UINT32(rotate->dst_roi.bottom - rotate->dst_roi.top);
-      hw_buffer_info->buffer_config.format = rot_ouput_format;
       // Allocate two rotator output buffers by default for double buffering.
       hw_buffer_info->buffer_config.buffer_count = 2;
       hw_buffer_info->buffer_config.secure = layer.input_buffer->flags.secure;
@@ -1092,33 +1079,32 @@
 }
 
 void ResManager::SetRotatorOutputFormat(const LayerBufferFormat &input_format, bool bwc, bool rot90,
-                                        LayerBufferFormat *output_format) {
+                                        bool downscale, LayerBufferFormat *output_format) {
+  *output_format = input_format;
+
   switch (input_format) {
   case kFormatRGB565:
     if (rot90)
       *output_format = kFormatRGB888;
-    else
-      *output_format = input_format;
     break;
   case kFormatRGBA8888:
     if (bwc)
       *output_format = kFormatBGRA8888;
-    else
-      *output_format = input_format;
     break;
   case kFormatYCbCr420SemiPlanarVenus:
   case kFormatYCbCr420SemiPlanar:
     if (rot90)
       *output_format = kFormatYCrCb420SemiPlanar;
-    else
-      *output_format = input_format;
+    break;
+  case kFormatYCbCr420SPVenusUbwc:
+    if (downscale)
+      *output_format = kFormatYCrCb420SemiPlanar;
     break;
   case kFormatYCbCr420Planar:
   case kFormatYCrCb420Planar:
     *output_format = kFormatYCrCb420SemiPlanar;
     break;
   default:
-    *output_format = input_format;
     break;
   }
 
@@ -1128,8 +1114,5 @@
   return;
 }
 
-void* ResManager::lib_scalar_handle_ = NULL;
-int (*ResManager::ScalarConfigureScale)(struct scalar::LayerInfo* layer) = NULL;
-
 }  // namespace sde
 
diff --git a/displayengine/libs/core/res_manager.h b/displayengine/libs/core/res_manager.h
index eae6730..d21984e 100644
--- a/displayengine/libs/core/res_manager.h
+++ b/displayengine/libs/core/res_manager.h
@@ -171,7 +171,7 @@
                                   const LayerRect &dst_rect, HWLayerConfig *layer_config,
                                   uint32_t align_x);
   DisplayError ValidateScaling(const Layer &layer, const LayerRect &crop,
-                               const LayerRect &dst, float *rot_scale_x, float *rot_scale_y);
+                               const LayerRect &dst, float *rot_scale);
   DisplayError SrcSplitConfig(DisplayResourceContext *display_resource_ctx,
                               const LayerTransform &transform, const LayerRect &src_rect,
                               const LayerRect &dst_rect, HWLayerConfig *layer_config,
@@ -194,8 +194,8 @@
   bool IsYuvFormat(LayerBufferFormat format) { return (format >= kFormatYCbCr420Planar); }
   bool IsRotationNeeded(float rotation)
          { return (UINT32(rotation) == 90 || UINT32(rotation) == 270); }
-  void RotationConfig(const LayerTransform &transform, const float &scale_x,
-                      const float &scale_y, LayerRect *src_rect,
+  void RotationConfig(LayerBufferFormat format, const LayerTransform &transform,
+                      const float &downscale, LayerRect *src_rect,
                       struct HWLayerConfig *layer_config, uint32_t *rotate_count);
   DisplayError AcquireRotator(DisplayResourceContext *display_resource_ctx,
                               const uint32_t roate_cnt);
@@ -203,12 +203,12 @@
   void ClearRotator(DisplayResourceContext *display_resource_ctx);
   DisplayError AllocRotatorBuffer(Handle display_ctx, HWLayers *hw_layers);
   void SetRotatorOutputFormat(const LayerBufferFormat &input_format, bool bwc, bool rot90,
-                              LayerBufferFormat *output_format);
-  bool ConfigureScaling(HWLayers *hw_layers);
+                              bool downscale, LayerBufferFormat *output_format);
   DisplayError AlignPipeConfig(const Layer &layer, const LayerTransform &transform,
                                HWPipeInfo *left_pipe, HWPipeInfo *right_pipe,
                                uint32_t align_x, uint32_t align_y);
   void ResourceStateLog(void);
+  DisplayError CalculateDecimation(float downscale, uint8_t* decimation);
 
   Locker locker_;
   HWResourceInfo hw_res_info_;
@@ -227,8 +227,6 @@
   BufferAllocator *buffer_allocator_;
   BufferSyncHandler *buffer_sync_handler_;  // Pointer to buffer sync handler that was defined by
                                             // the display engine's client
-  static void* lib_scalar_handle_;  // Scalar library handle
-  static int (*ScalarConfigureScale)(struct scalar::LayerInfo* layer);
   PropertySetting property_setting_;
 };
 
diff --git a/displayengine/libs/core/scalar_helper.cpp b/displayengine/libs/core/scalar_helper.cpp
new file mode 100755
index 0000000..22488b3
--- /dev/null
+++ b/displayengine/libs/core/scalar_helper.cpp
@@ -0,0 +1,231 @@
+/*
+* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without modification, are permitted
+* provided that the following conditions are met:
+*    * Redistributions of source code must retain the above copyright notice, this list of
+*      conditions and the following disclaimer.
+*    * Redistributions in binary form must reproduce the above copyright notice, this list of
+*      conditions and the following disclaimer in the documentation and/or other materials provided
+*      with the distribution.
+*    * Neither the name of The Linux Foundation nor the names of its contributors may be used to
+*      endorse or promote products derived from this software without specific prior written
+*      permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef USES_SCALAR
+
+#include <dlfcn.h>
+#include <utils/debug.h>
+#include "scalar_helper.h"
+
+#define __CLASS__ "ScalarHelper"
+
+namespace sde {
+
+ScalarHelper* ScalarHelper::scalar_helper_ = NULL;
+
+ScalarHelper* ScalarHelper::GetInstance() {
+  if (scalar_helper_ == NULL) {
+    scalar_helper_ = new ScalarHelper();
+  }
+  return scalar_helper_;
+}
+
+// Scalar helper functions
+static void SetPipeInfo(HWPipeInfo* hw_pipe, scalar::PipeInfo* pipe) {
+  pipe->id = hw_pipe->pipe_id;
+  pipe->horz_deci = hw_pipe->horizontal_decimation;
+  pipe->vert_deci = hw_pipe->vertical_decimation;
+
+  pipe->src_rect.x = UINT32(hw_pipe->src_roi.left);
+  pipe->src_rect.y = UINT32(hw_pipe->src_roi.top);
+  pipe->src_rect.w = UINT32(hw_pipe->src_roi.right) - pipe->src_rect.x;
+  pipe->src_rect.h = UINT32(hw_pipe->src_roi.bottom) - pipe->src_rect.y;
+
+  pipe->dst_rect.x = UINT32(hw_pipe->dst_roi.left);
+  pipe->dst_rect.y = UINT32(hw_pipe->dst_roi.top);
+  pipe->dst_rect.w = UINT32(hw_pipe->dst_roi.right) - pipe->dst_rect.x;
+  pipe->dst_rect.h = UINT32(hw_pipe->dst_roi.bottom) - pipe->dst_rect.y;
+}
+
+static void UpdateSrcRoi(scalar::PipeInfo* pipe, HWPipeInfo* hw_pipe) {
+  hw_pipe->src_roi.left   = FLOAT(pipe->src_rect.x);
+  hw_pipe->src_roi.top    = FLOAT(pipe->src_rect.y);
+  hw_pipe->src_roi.right  = FLOAT(pipe->src_rect.x + pipe->src_rect.w);
+  hw_pipe->src_roi.bottom = FLOAT(pipe->src_rect.y + pipe->src_rect.h);
+}
+
+static uint32_t GetScalarFormat(LayerBufferFormat source) {
+  uint32_t format = scalar::UNKNOWN_FORMAT;
+
+  switch (source) {
+  case kFormatARGB8888:                 format = scalar::ARGB_8888;         break;
+  case kFormatRGBA8888:                 format = scalar::RGBA_8888;         break;
+  case kFormatBGRA8888:                 format = scalar::BGRA_8888;         break;
+  case kFormatXRGB8888:                 format = scalar::XRGB_8888;         break;
+  case kFormatRGBX8888:                 format = scalar::RGBX_8888;         break;
+  case kFormatBGRX8888:                 format = scalar::BGRX_8888;         break;
+  case kFormatRGB888:                   format = scalar::RGB_888;           break;
+  case kFormatRGB565:                   format = scalar::RGB_565;           break;
+  case kFormatYCbCr420Planar:           format = scalar::Y_CB_CR_H2V2;      break;
+  case kFormatYCrCb420Planar:           format = scalar::Y_CR_CB_H2V2;      break;
+  case kFormatYCbCr420SemiPlanar:       format = scalar::Y_CBCR_H2V2;       break;
+  case kFormatYCrCb420SemiPlanar:       format = scalar::Y_CRCB_H2V2;       break;
+  case kFormatYCbCr422Packed:           format = scalar::YCBYCR_H2V1;       break;
+  case kFormatYCbCr420SemiPlanarVenus:  format = scalar::Y_CBCR_H2V2_VENUS; break;
+  case kFormatRGBA8888Ubwc:             format = scalar::RGBA_8888_UBWC;    break;
+  case kFormatRGB565Ubwc:               format = scalar::RGB_565_UBWC;      break;
+  case kFormatYCbCr420SPVenusUbwc:      format = scalar::Y_CBCR_H2V2_UBWC;  break;
+  default:
+    DLOGE("Unsupported source format: %x", source);
+    break;
+  }
+  return format;
+}
+
+void ScalarHelper::Init() {
+  lib_scalar_handle_   = NULL;
+  ScalarConfigureScale = NULL;
+
+  lib_scalar_handle_ = dlopen(SCALAR_LIBRARY_NAME, RTLD_NOW);
+  if (lib_scalar_handle_) {
+    void **scalar_func = reinterpret_cast<void **>(&ScalarConfigureScale);
+    *scalar_func = ::dlsym(lib_scalar_handle_, "configureScale");
+  } else {
+    DLOGW("Unable to load %s !", SCALAR_LIBRARY_NAME);
+  }
+}
+
+void ScalarHelper::Deinit() {
+  if (lib_scalar_handle_) {
+    dlclose(lib_scalar_handle_);
+    lib_scalar_handle_ = NULL;
+  }
+}
+
+bool ScalarHelper::ConfigureScale(HWLayers *hw_layers) {
+
+  if (!lib_scalar_handle_ || !ScalarConfigureScale) {
+    // No scalar library
+    return true;
+  }
+
+  // Reset scale data
+  memset(&scale_data_, 0, sizeof(scale_data_));
+  HWLayersInfo &hw_layer_info = hw_layers->info;
+
+  for (uint32_t i = 0; i < hw_layer_info.count; i++) {
+    Layer &layer = hw_layer_info.stack->layers[hw_layer_info.index[i]];
+    uint32_t width = layer.input_buffer->width;
+    LayerBufferFormat format = layer.input_buffer->format;
+    HWPipeInfo* left_pipe = &hw_layers->config[i].left_pipe;
+    HWPipeInfo* right_pipe = &hw_layers->config[i].right_pipe;
+
+    // Prepare data structure for lib scalar
+    uint32_t flags = 0;
+    struct scalar::LayerInfo layer_info;
+
+    if (layer.transform.rotation == 90.0f) {
+      // Flips will be taken care by rotator, if layer requires 90 rotation
+      flags |= scalar::SCALAR_SOURCE_ROTATED_90;
+    } else {
+      flags |= layer.transform.flip_vertical ? scalar::SCALAR_FLIP_UD : 0;
+      flags |= layer.transform.flip_horizontal ? scalar::SCALAR_FLIP_LR : 0;
+    }
+
+    for (uint32_t count = 0; count < 2; count++) {
+      HWPipeInfo* hw_pipe = (count == 0) ? left_pipe : right_pipe;
+      HWRotateInfo* rotate_info = &hw_layers->config[i].rotates[count];
+      scalar::PipeInfo* pipe = (count == 0) ? &layer_info.left_pipe : &layer_info.right_pipe;
+
+      if (rotate_info->valid) {
+        width = rotate_info->hw_buffer_info.buffer_config.width;
+        format = rotate_info->hw_buffer_info.buffer_config.format;
+      }
+
+      pipe->flags = flags;
+      pipe->scale_data = GetScaleRef(i, !count);
+      pipe->scale_data->src_width = width;
+      SetPipeInfo(hw_pipe, pipe);
+    }
+    layer_info.src_format = GetScalarFormat(format);
+
+    DLOGV_IF(kTagScalar, "Scalar Input[%d] flags=%x format=%x", i, flags, layer_info.src_format);
+    DLOGV_IF(kTagScalar, "Left: id=%d hD=%d vD=%d srcRect=[%d %d %d %d] dstRect=[%d %d %d %d]",
+      layer_info.left_pipe.id, layer_info.left_pipe.horz_deci, layer_info.left_pipe.vert_deci,
+      layer_info.left_pipe.src_rect.x, layer_info.left_pipe.src_rect.y,
+      layer_info.left_pipe.src_rect.w, layer_info.left_pipe.src_rect.h,
+      layer_info.left_pipe.dst_rect.x, layer_info.left_pipe.dst_rect.y,
+      layer_info.left_pipe.dst_rect.w, layer_info.left_pipe.dst_rect.h);
+    DLOGV_IF(kTagScalar, "Right: id=%d hD=%d vD=%d srcRect=[%d %d %d %d] dstRect=[%d %d %d %d]",
+      layer_info.right_pipe.id, layer_info.right_pipe.horz_deci, layer_info.right_pipe.vert_deci,
+      layer_info.right_pipe.src_rect.x, layer_info.right_pipe.src_rect.y,
+      layer_info.right_pipe.src_rect.w, layer_info.right_pipe.src_rect.h,
+      layer_info.right_pipe.dst_rect.x, layer_info.right_pipe.dst_rect.y,
+      layer_info.right_pipe.dst_rect.w, layer_info.right_pipe.dst_rect.h);
+
+    // Configure scale data structure
+    if (ScalarConfigureScale(&layer_info) < 0) {
+      DLOGE("Scalar library failed to configure scale data!");
+      return false;
+    }
+
+    // Update Src Roi in HWPipeInfo
+    if (layer_info.left_pipe.scale_data->enable_pxl_ext)
+      UpdateSrcRoi(&layer_info.left_pipe, left_pipe);
+    if (layer_info.right_pipe.scale_data->enable_pxl_ext)
+      UpdateSrcRoi(&layer_info.right_pipe, right_pipe);
+  }
+  return true;
+}
+
+void ScalarHelper::UpdateSrcWidth(uint32_t index, bool left, uint32_t* width) {
+  *width = GetScaleRef(index, left)->src_width;
+}
+
+void ScalarHelper::SetScaleData(uint32_t index, bool left, mdp_scale_data* mdp_scale) {
+
+  if (!lib_scalar_handle_ || !ScalarConfigureScale)
+    return;
+
+  scalar::Scale* scale = GetScaleRef(index, left);
+  mdp_scale->enable_pxl_ext = scale->enable_pxl_ext;
+
+  for (int i = 0; i < MAX_PLANES; i++) {
+    mdp_scale->init_phase_x[i] = scale->init_phase_x[i];
+    mdp_scale->phase_step_x[i] = scale->phase_step_x[i];
+    mdp_scale->init_phase_y[i] = scale->init_phase_y[i];
+    mdp_scale->phase_step_y[i] = scale->phase_step_y[i];
+
+    mdp_scale->num_ext_pxls_left[i] = scale->left.extension[i];
+    mdp_scale->num_ext_pxls_top[i] = scale->top.extension[i];
+    mdp_scale->num_ext_pxls_right[i] = scale->right.extension[i];
+    mdp_scale->num_ext_pxls_btm[i] = scale->bottom.extension[i];
+
+    mdp_scale->left_ftch[i] = scale->left.overfetch[i];
+    mdp_scale->top_ftch[i] = scale->top.overfetch[i];
+    mdp_scale->right_ftch[i] = scale->right.overfetch[i];
+    mdp_scale->btm_ftch[i] = scale->bottom.overfetch[i];
+
+    mdp_scale->left_rpt[i] = scale->left.repeat[i];
+    mdp_scale->top_rpt[i] = scale->top.repeat[i];
+    mdp_scale->right_rpt[i] = scale->right.repeat[i];
+    mdp_scale->btm_rpt[i] = scale->bottom.repeat[i];
+
+    mdp_scale->roi_w[i] = scale->roi_width[i];
+  }
+}
+
+} // namespace sde
+
+#endif
diff --git a/displayengine/libs/core/scalar_helper.h b/displayengine/libs/core/scalar_helper.h
new file mode 100755
index 0000000..a54cb0c
--- /dev/null
+++ b/displayengine/libs/core/scalar_helper.h
@@ -0,0 +1,67 @@
+/*
+* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without modification, are permitted
+* provided that the following conditions are met:
+*    * Redistributions of source code must retain the above copyright notice, this list of
+*      conditions and the following disclaimer.
+*    * Redistributions in binary form must reproduce the above copyright notice, this list of
+*      conditions and the following disclaimer in the documentation and/or other materials provided
+*      with the distribution.
+*    * Neither the name of The Linux Foundation nor the names of its contributors may be used to
+*      endorse or promote products derived from this software without specific prior written
+*      permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __SCALAR_HELPER_H__
+#define __SCALAR_HELPER_H__
+
+#ifdef USES_SCALAR
+
+#include <sys/types.h>
+#include <linux/msm_mdp_ext.h>
+#include <hw_interface.h>
+#include <scalar.h>
+
+#define SCALAR_LIBRARY_NAME "libscalar.so"
+
+namespace sde {
+
+class ScalarHelper {
+
+ public:
+  void Init();
+  void Deinit();
+  bool ConfigureScale(HWLayers *hw_layers);
+  void UpdateSrcWidth(uint32_t index, bool left, uint32_t* src_width);
+  void SetScaleData(uint32_t index, bool left, mdp_scale_data* mdp_scale);
+  static ScalarHelper* GetInstance();
+
+ private:
+  explicit ScalarHelper() { }
+  struct ScaleData {
+    scalar::Scale left_scale;
+    scalar::Scale right_scale;
+  };
+  struct ScaleData scale_data_[kMaxSDELayers];
+  void* lib_scalar_handle_;
+  int (*ScalarConfigureScale)(struct scalar::LayerInfo* layer);
+  scalar::Scale* GetScaleRef(uint32_t index, bool left) {
+    return (left ? &scale_data_[index].left_scale : &scale_data_[index].right_scale);
+  }
+  static ScalarHelper* scalar_helper_;  // Singleton Instance
+};
+
+}  // namespace sde
+
+#endif
+#endif  // __SCALAR_HELPER_H__
diff --git a/displayengine/libs/hwc/hwc_buffer_allocator.cpp b/displayengine/libs/hwc/hwc_buffer_allocator.cpp
index d4f4bac..f2383b2 100644
--- a/displayengine/libs/hwc/hwc_buffer_allocator.cpp
+++ b/displayengine/libs/hwc/hwc_buffer_allocator.cpp
@@ -159,6 +159,7 @@
   case kFormatYCbCr420SemiPlanar:       *target = HAL_PIXEL_FORMAT_YCbCr_420_SP;          break;
   case kFormatYCbCr422Packed:           *target = HAL_PIXEL_FORMAT_YCbCr_422_I;           break;
   case kFormatYCbCr420SemiPlanarVenus:  *target = HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS;    break;
+  case kFormatYCbCr420SPVenusUbwc:    *target = HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS_UBWC; break;
 
   default:
     DLOGE("Unsupported format = 0x%x", format);
diff --git a/displayengine/libs/hwc/hwc_session.cpp b/displayengine/libs/hwc/hwc_session.cpp
index 1b686bf..40eae99 100644
--- a/displayengine/libs/hwc/hwc_session.cpp
+++ b/displayengine/libs/hwc/hwc_session.cpp
@@ -94,7 +94,7 @@
                 android::defaultServiceManager()->getService(android::String16(qservice_name)));
 
   if (qservice.get()) {
-    qservice->connect(this);
+    qservice->connect(android::sp<qClient::IQClient>(this));
   } else {
     DLOGE("Failed to acquire %s", qservice_name);
     return -EINVAL;
diff --git a/displayengine/libs/utils/debug_android.cpp b/displayengine/libs/utils/debug_android.cpp
index 7503999..96339df 100644
--- a/displayengine/libs/utils/debug_android.cpp
+++ b/displayengine/libs/utils/debug_android.cpp
@@ -29,6 +29,7 @@
 
 #include <stdlib.h>
 #include <utils/debug.h>
+#include <utils/constants.h>
 #include <cutils/log.h>
 #include <cutils/properties.h>
 
@@ -67,7 +68,7 @@
     return atoi(property);
   }
 
-  return 0;
+  return IDLE_TIMEOUT_DEFAULT_MS;
 }
 
 bool Debug::IsRotatorDownScaleDisabled() {
diff --git a/hdmi_cec/Android.mk b/hdmi_cec/Android.mk
new file mode 100644
index 0000000..ed06da1
--- /dev/null
+++ b/hdmi_cec/Android.mk
@@ -0,0 +1,15 @@
+LOCAL_PATH := $(call my-dir)
+include $(LOCAL_PATH)/../common.mk
+include $(CLEAR_VARS)
+
+LOCAL_MODULE                  := hdmi_cec.$(TARGET_BOARD_PLATFORM)
+LOCAL_MODULE_RELATIVE_PATH    := hw
+LOCAL_MODULE_TAGS             := optional
+LOCAL_C_INCLUDES              := $(common_includes)
+LOCAL_SHARED_LIBRARIES        := $(common_libs) libqservice libbinder libqdutils
+
+LOCAL_CFLAGS                  := $(common_flags) -DLOG_TAG=\"qdhdmi_cec\"
+LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps)
+LOCAL_SRC_FILES               := qhdmi_cec.cpp \
+                                 QHDMIClient.cpp
+include $(BUILD_SHARED_LIBRARY)
diff --git a/hdmi_cec/QHDMIClient.cpp b/hdmi_cec/QHDMIClient.cpp
new file mode 100644
index 0000000..2b2b1e6
--- /dev/null
+++ b/hdmi_cec/QHDMIClient.cpp
@@ -0,0 +1,66 @@
+/*
+* Copyright (c) 2014 The Linux Foundation. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+*    * Redistributions of source code must retain the above copyright
+*      notice, this list of conditions and the following disclaimer.
+*    * Redistributions in binary form must reproduce the above
+*      copyright notice, this list of conditions and the following
+*      disclaimer in the documentation and/or other materials provided
+*      with the distribution.
+*    * Neither the name of The Linux Foundation. nor the names of its
+*      contributors may be used to endorse or promote products derived
+*      from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define DEBUG 0
+#include <QServiceUtils.h>
+#include "QHDMIClient.h"
+
+using namespace android;
+using namespace qhdmicec;
+using namespace qService;
+
+namespace qClient {
+
+void QHDMIClient::binderDied(const wp<IBinder>& who __unused)
+{
+    ALOGW("%s: Display QService died", __FUNCTION__);
+}
+
+void QHDMIClient::onHdmiHotplug(int connected)
+{
+    ALOGD("%s: HDMI connected event connected: %d", __FUNCTION__, connected);
+    cec_hdmi_hotplug(mCtx, connected);
+}
+
+void QHDMIClient::onCECMessageRecieved(char *msg, ssize_t len)
+{
+    ALOGD_IF(DEBUG, "%s: CEC message received len: %zd", __FUNCTION__, len);
+    cec_receive_message(mCtx, msg, len);
+}
+
+void QHDMIClient::registerClient(sp<QHDMIClient>& client)
+{
+    sp<IServiceManager> sm = defaultServiceManager();
+    sp<IBinder> binder = sm->getService(String16("display.qservice"));
+    binder->linkToDeath(client);
+    mQService = interface_cast<IQService>(binder);
+    mQService->connect(interface_cast<IQHDMIClient>(client));
+}
+
+};
diff --git a/hdmi_cec/QHDMIClient.h b/hdmi_cec/QHDMIClient.h
new file mode 100644
index 0000000..9e54f2f
--- /dev/null
+++ b/hdmi_cec/QHDMIClient.h
@@ -0,0 +1,57 @@
+/*
+* Copyright (c) 2014 The Linux Foundation. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+*    * Redistributions of source code must retain the above copyright
+*      notice, this list of conditions and the following disclaimer.
+*    * Redistributions in binary form must reproduce the above
+*      copyright notice, this list of conditions and the following
+*      disclaimer in the documentation and/or other materials provided
+*      with the distribution.
+*    * Neither the name of The Linux Foundation. nor the names of its
+*      contributors may be used to endorse or promote products derived
+*      from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "IQHDMIClient.h"
+#include "qhdmi_cec.h"
+#include <IQService.h>
+
+namespace qClient {
+
+class QHDMIClient: public android::IBinder::DeathRecipient,
+    public BnQHDMIClient
+{
+public:
+    QHDMIClient() {}
+
+    virtual void binderDied(const android::wp<android::IBinder>& who);
+
+    virtual void onHdmiHotplug(int connected);
+
+    virtual void onCECMessageRecieved(char *msg, ssize_t len);
+
+    void setCECContext(qhdmicec::cec_context_t* ctx) { mCtx = ctx; }
+
+    void registerClient(android::sp<QHDMIClient>& client);
+
+private:
+    qhdmicec::cec_context_t* mCtx;
+    android::sp<qService::IQService> mQService;
+
+};
+};
diff --git a/hdmi_cec/qhdmi_cec.cpp b/hdmi_cec/qhdmi_cec.cpp
new file mode 100644
index 0000000..1bc7df6
--- /dev/null
+++ b/hdmi_cec/qhdmi_cec.cpp
@@ -0,0 +1,519 @@
+/*
+* Copyright (c) 2014 The Linux Foundation. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+*    * Redistributions of source code must retain the above copyright
+*      notice, this list of conditions and the following disclaimer.
+*    * Redistributions in binary form must reproduce the above
+*      copyright notice, this list of conditions and the following
+*      disclaimer in the documentation and/or other materials provided
+*      with the distribution.
+*    * Neither the name of The Linux Foundation. nor the names of its
+*      contributors may be used to endorse or promote products derived
+*      from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define DEBUG 0
+#define ATRACE_TAG (ATRACE_TAG_GRAPHICS | ATRACE_TAG_HAL)
+#include <cstdlib>
+#include <cutils/log.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <hardware/hdmi_cec.h>
+#include <utils/Trace.h>
+#include "qhdmi_cec.h"
+#include "QHDMIClient.h"
+
+namespace qhdmicec {
+
+const int NUM_HDMI_PORTS = 1;
+const int MAX_SYSFS_DATA = 128;
+const int MAX_CEC_FRAME_SIZE = 20;
+const int MAX_SEND_MESSAGE_RETRIES = 1;
+
+enum {
+    LOGICAL_ADDRESS_SET   =  1,
+    LOGICAL_ADDRESS_UNSET = -1,
+};
+
+// Offsets of members of struct hdmi_cec_msg
+// drivers/video/msm/mdss/mdss_hdmi_cec.c
+// XXX: Get this from a driver header
+enum {
+    CEC_OFFSET_SENDER_ID,
+    CEC_OFFSET_RECEIVER_ID,
+    CEC_OFFSET_OPCODE,
+    CEC_OFFSET_OPERAND,
+    CEC_OFFSET_FRAME_LENGTH = 18,
+    CEC_OFFSET_RETRANSMIT,
+};
+
+//Forward declarations
+static void cec_close_context(cec_context_t* ctx __unused);
+static int cec_enable(cec_context_t *ctx, int enable);
+static int cec_is_connected(const struct hdmi_cec_device* dev, int port_id);
+
+static ssize_t read_node(const char *path, char *data)
+{
+    ssize_t err = 0;
+    FILE *fp = NULL;
+    err = access(path, R_OK);
+    if (!err) {
+        fp = fopen(path, "r");
+        if (fp) {
+            err = fread(data, sizeof(char), MAX_SYSFS_DATA ,fp);
+            fclose(fp);
+        }
+    }
+    return err;
+}
+
+static ssize_t write_node(const char *path, const char *data, size_t len)
+{
+    ssize_t err = 0;
+    int fd = -1;
+    err = access(path, W_OK);
+    if (!err) {
+        fd = open(path, O_WRONLY);
+        errno = 0;
+        err = write(fd, data, len);
+        if (err < 0) {
+            err = -errno;
+        }
+        close(fd);
+    } else {
+        ALOGE("%s: Failed to access path: %s error: %s",
+                __FUNCTION__, path, strerror(errno));
+        err = -errno;
+    }
+    return err;
+}
+
+// Helper function to write integer values to the full sysfs path
+static ssize_t write_int_to_node(cec_context_t *ctx,
+        const char *path_postfix,
+        const int value)
+{
+    char sysfs_full_path[MAX_PATH_LENGTH];
+    char sysfs_data[MAX_SYSFS_DATA];
+    snprintf(sysfs_data, sizeof(sysfs_data), "%d",value);
+    snprintf(sysfs_full_path,sizeof(sysfs_full_path), "%s/%s",
+            ctx->fb_sysfs_path, path_postfix);
+    ssize_t err = write_node(sysfs_full_path, sysfs_data, strlen(sysfs_data));
+    return err;
+}
+
+static void hex_to_string(const char *msg, ssize_t len, char *str)
+{
+    //Functions assumes sufficient memory in str
+    char *ptr = str;
+    for(int i=0; i < len ; i++) {
+        ptr += snprintf(ptr, 3,  "%02X", msg[i]);
+        // Overwrite null termination of snprintf in all except the last byte
+        if (i < len - 1)
+            *ptr = ':';
+        ptr++;
+    }
+}
+
+static ssize_t cec_get_fb_node_number(cec_context_t *ctx)
+{
+    //XXX: Do this from a common utility library across the display HALs
+    const int MAX_FB_DEVICES = 2;
+    ssize_t len = 0;
+    char fb_type_path[MAX_PATH_LENGTH];
+    char fb_type[MAX_SYSFS_DATA];
+    const char *dtv_panel_str = "dtv panel";
+
+    for(int num = 0; num < MAX_FB_DEVICES; num++) {
+        snprintf(fb_type_path, sizeof(fb_type_path),"%s%d/msm_fb_type",
+                SYSFS_BASE,num);
+        ALOGD_IF(DEBUG, "%s: num: %d fb_type_path: %s", __FUNCTION__, num, fb_type_path);
+        len = read_node(fb_type_path, fb_type);
+        ALOGD_IF(DEBUG, "%s: fb_type:%s", __FUNCTION__, fb_type);
+        if(len > 0 && (strncmp(fb_type, dtv_panel_str, strlen(dtv_panel_str)) == 0)){
+            ALOGD_IF(DEBUG, "%s: Found DTV panel at fb%d", __FUNCTION__, num);
+            ctx->fb_num = num;
+            snprintf(ctx->fb_sysfs_path, sizeof(ctx->fb_sysfs_path),
+                    "%s%d", SYSFS_BASE, num);
+            break;
+        }
+    }
+    if (len < 0)
+        return len;
+    else
+        return 0;
+}
+
+static int cec_add_logical_address(const struct hdmi_cec_device* dev,
+        cec_logical_address_t addr)
+{
+    if (addr <  CEC_ADDR_TV || addr > CEC_ADDR_BROADCAST) {
+        ALOGE("%s: Received invalid address: %d ", __FUNCTION__, addr);
+        return -EINVAL;
+    }
+    cec_context_t* ctx = (cec_context_t*)(dev);
+    ctx->logical_address[addr] = LOGICAL_ADDRESS_SET;
+
+    //XXX: We can get multiple logical addresses here but we can only send one
+    //to the driver. Store locally for now
+    ssize_t err = write_int_to_node(ctx, "cec/logical_addr", addr);
+    ALOGI("%s: Allocated logical address: %d ", __FUNCTION__, addr);
+    return (int) err;
+}
+
+static void cec_clear_logical_address(const struct hdmi_cec_device* dev)
+{
+    cec_context_t* ctx = (cec_context_t*)(dev);
+    memset(ctx->logical_address, LOGICAL_ADDRESS_UNSET,
+            sizeof(ctx->logical_address));
+    //XXX: Find logical_addr that needs to be reset
+    write_int_to_node(ctx, "cec/logical_addr", 15);
+    ALOGD_IF(DEBUG, "%s: Cleared logical addresses", __FUNCTION__);
+}
+
+static int cec_get_physical_address(const struct hdmi_cec_device* dev,
+        uint16_t* addr)
+{
+    cec_context_t* ctx = (cec_context_t*)(dev);
+    char pa_path[MAX_PATH_LENGTH];
+    char pa_data[MAX_SYSFS_DATA];
+    snprintf (pa_path, sizeof(pa_path),"%s/pa",
+            ctx->fb_sysfs_path);
+    int err = (int) read_node(pa_path, pa_data);
+    *addr = (uint16_t) atoi(pa_data);
+    ALOGD_IF(DEBUG, "%s: Physical Address: 0x%x", __FUNCTION__, *addr);
+    if (err < 0)
+        return err;
+    else
+        return 0;
+}
+
+static int cec_send_message(const struct hdmi_cec_device* dev,
+        const cec_message_t* msg)
+{
+    ATRACE_CALL();
+    if(cec_is_connected(dev, 0) <= 0)
+        return HDMI_RESULT_FAIL;
+
+    cec_context_t* ctx = (cec_context_t*)(dev);
+    ALOGD_IF(DEBUG, "%s: initiator: %d destination: %d length: %u",
+            __FUNCTION__, msg->initiator, msg->destination,
+            (uint32_t) msg->length);
+
+    // Dump message received from framework
+    char dump[128];
+    if(msg->length > 0) {
+        hex_to_string((char*)msg->body, msg->length, dump);
+        ALOGD_IF(DEBUG, "%s: message from framework: %s", __FUNCTION__, dump);
+    }
+
+    char write_msg_path[MAX_PATH_LENGTH];
+    char write_msg[MAX_CEC_FRAME_SIZE];
+    memset(write_msg, 0, sizeof(write_msg));
+    // See definition of struct hdmi_cec_msg in driver code
+    // drivers/video/msm/mdss/mdss_hdmi_cec.c
+    // Write header block
+    // XXX: Include this from header in kernel
+    write_msg[CEC_OFFSET_SENDER_ID] = msg->initiator;
+    write_msg[CEC_OFFSET_RECEIVER_ID] = msg->destination;
+    //Kernel splits opcode/operand, but Android sends it in one byte array
+    write_msg[CEC_OFFSET_OPCODE] = msg->body[0];
+    if(msg->length > 1) {
+        memcpy(&write_msg[CEC_OFFSET_OPERAND], &msg->body[1],
+                sizeof(char)*(msg->length - 1));
+    }
+    //msg length + initiator + destination
+    write_msg[CEC_OFFSET_FRAME_LENGTH] = (unsigned char) (msg->length + 1);
+    hex_to_string(write_msg, sizeof(write_msg), dump);
+    ALOGD_IF(DEBUG, "%s: message to driver: %s", __FUNCTION__, dump);
+    snprintf(write_msg_path, sizeof(write_msg_path), "%s/cec/wr_msg",
+            ctx->fb_sysfs_path);
+    int retry_count = 0;
+    ssize_t err = 0;
+    //HAL spec requires us to retry at least once.
+    while (true) {
+        err = write_node(write_msg_path, write_msg, sizeof(write_msg));
+        retry_count++;
+        if (err == -EAGAIN && retry_count <= MAX_SEND_MESSAGE_RETRIES) {
+            ALOGE("%s: CEC line busy, retrying", __FUNCTION__);
+        } else {
+            break;
+        }
+    }
+
+    if (err < 0) {
+       if (err == -ENXIO) {
+           ALOGI("%s: No device exists with the destination address",
+                   __FUNCTION__);
+           return HDMI_RESULT_NACK;
+       } else if (err == -EAGAIN) {
+            ALOGE("%s: CEC line is busy, max retry count exceeded",
+                    __FUNCTION__);
+            return HDMI_RESULT_BUSY;
+        } else {
+            return HDMI_RESULT_FAIL;
+            ALOGE("%s: Failed to send CEC message err: %zd - %s",
+                    __FUNCTION__, err, strerror(int(-err)));
+        }
+    } else {
+        ALOGD_IF(DEBUG, "%s: Sent CEC message - %zd bytes written",
+                __FUNCTION__, err);
+        return HDMI_RESULT_SUCCESS;
+    }
+}
+
+void cec_receive_message(cec_context_t *ctx, char *msg, ssize_t len)
+{
+    if(!ctx->system_control)
+        return;
+
+    char dump[128];
+    if(len > 0) {
+        hex_to_string(msg, len, dump);
+        ALOGD_IF(DEBUG, "%s: Message from driver: %s", __FUNCTION__, dump);
+    }
+
+    hdmi_event_t event;
+    event.type = HDMI_EVENT_CEC_MESSAGE;
+    event.dev = (hdmi_cec_device *) ctx;
+    // Remove initiator/destination from this calculation
+    event.cec.length = msg[CEC_OFFSET_FRAME_LENGTH] - 1;
+    event.cec.initiator = (cec_logical_address_t) msg[CEC_OFFSET_SENDER_ID];
+    event.cec.destination = (cec_logical_address_t) msg[CEC_OFFSET_RECEIVER_ID];
+    //Copy opcode and operand
+    memcpy(event.cec.body, &msg[CEC_OFFSET_OPCODE], event.cec.length);
+    hex_to_string((char *) event.cec.body, event.cec.length, dump);
+    ALOGD_IF(DEBUG, "%s: Message to framework: %s", __FUNCTION__, dump);
+    ctx->callback.callback_func(&event, ctx->callback.callback_arg);
+}
+
+void cec_hdmi_hotplug(cec_context_t *ctx, int connected)
+{
+    //Ignore unplug events when system control is disabled
+    if(!ctx->system_control && connected == 0)
+        return;
+    hdmi_event_t event;
+    event.type = HDMI_EVENT_HOT_PLUG;
+    event.dev = (hdmi_cec_device *) ctx;
+    event.hotplug.connected = connected ? HDMI_CONNECTED : HDMI_NOT_CONNECTED;
+    ctx->callback.callback_func(&event, ctx->callback.callback_arg);
+}
+
+static void cec_register_event_callback(const struct hdmi_cec_device* dev,
+            event_callback_t callback, void* arg)
+{
+    ALOGD_IF(DEBUG, "%s: Registering callback", __FUNCTION__);
+    cec_context_t* ctx = (cec_context_t*)(dev);
+    ctx->callback.callback_func = callback;
+    ctx->callback.callback_arg = arg;
+}
+
+static void cec_get_version(const struct hdmi_cec_device* dev, int* version)
+{
+    cec_context_t* ctx = (cec_context_t*)(dev);
+    *version = ctx->version;
+    ALOGD_IF(DEBUG, "%s: version: %d", __FUNCTION__, *version);
+}
+
+static void cec_get_vendor_id(const struct hdmi_cec_device* dev,
+        uint32_t* vendor_id)
+{
+    cec_context_t* ctx = (cec_context_t*)(dev);
+    *vendor_id = ctx->vendor_id;
+    ALOGD_IF(DEBUG, "%s: vendor id: %u", __FUNCTION__, *vendor_id);
+}
+
+static void cec_get_port_info(const struct hdmi_cec_device* dev,
+            struct hdmi_port_info* list[], int* total)
+{
+    ALOGD_IF(DEBUG, "%s: Get port info", __FUNCTION__);
+    cec_context_t* ctx = (cec_context_t*)(dev);
+    *total = NUM_HDMI_PORTS;
+    *list = ctx->port_info;
+}
+
+static void cec_set_option(const struct hdmi_cec_device* dev, int flag,
+        int value)
+{
+    cec_context_t* ctx = (cec_context_t*)(dev);
+    switch (flag) {
+        case HDMI_OPTION_WAKEUP:
+            ALOGD_IF(DEBUG, "%s: Wakeup: value: %d", __FUNCTION__, value);
+            //XXX
+            break;
+        case HDMI_OPTION_ENABLE_CEC:
+            ALOGD_IF(DEBUG, "%s: Enable CEC: value: %d", __FUNCTION__, value);
+            cec_enable(ctx, value? 1 : 0);
+            break;
+        case HDMI_OPTION_SYSTEM_CEC_CONTROL:
+            ALOGD_IF(DEBUG, "%s: system_control: value: %d",
+                    __FUNCTION__, value);
+            ctx->system_control = !!value;
+            break;
+    }
+}
+
+static void cec_set_audio_return_channel(const struct hdmi_cec_device* dev,
+        int port, int flag)
+{
+    cec_context_t* ctx = (cec_context_t*)(dev);
+    ctx->arc_enabled = flag ? true : false;
+    ALOGD_IF(DEBUG, "%s: ARC flag: %d port: %d", __FUNCTION__, flag, port);
+}
+
+static int cec_is_connected(const struct hdmi_cec_device* dev, int port_id)
+{
+    // Ignore port_id since we have only one port
+    int connected = 0;
+    cec_context_t* ctx = (cec_context_t*)(dev);
+    char connected_path[MAX_PATH_LENGTH];
+    char connected_data[MAX_SYSFS_DATA];
+    snprintf (connected_path, sizeof(connected_path),"%s/connected",
+            ctx->fb_sysfs_path);
+    ssize_t err = read_node(connected_path, connected_data);
+    connected = atoi(connected_data);
+
+    ALOGD_IF(DEBUG, "%s: HDMI at port %d is - %s", __FUNCTION__, port_id,
+            connected ? "connected":"disconnected");
+    if (err < 0)
+        return (int) err;
+    else
+        return connected;
+}
+
+static int cec_device_close(struct hw_device_t *dev)
+{
+    ALOGD_IF(DEBUG, "%s: Close CEC HAL ", __FUNCTION__);
+    if (!dev) {
+        ALOGE("%s: NULL device pointer", __FUNCTION__);
+        return -EINVAL;
+    }
+    cec_context_t* ctx = (cec_context_t*)(dev);
+    cec_close_context(ctx);
+    free(dev);
+    return 0;
+}
+
+static int cec_enable(cec_context_t *ctx, int enable)
+{
+    ssize_t err;
+    // Enable CEC
+    // TODO: Set to 0x3 to enable CEC wakeup once driver has support
+    int value = enable ? 0x1 : 0x0;
+    err = write_int_to_node(ctx, "cec/enable", value);
+    if(err < 0) {
+        ALOGE("%s: Failed to toggle CEC: enable: %d",
+                __FUNCTION__, enable);
+        return (int) err;
+    }
+    ctx->enabled = enable;
+    return 0;
+}
+
+static void cec_init_context(cec_context_t *ctx)
+{
+    ALOGD_IF(DEBUG, "%s: Initializing context", __FUNCTION__);
+    cec_get_fb_node_number(ctx);
+
+    //Initialize ports - We support only one output port
+    ctx->port_info = new hdmi_port_info[NUM_HDMI_PORTS];
+    ctx->port_info[0].type = HDMI_OUTPUT;
+    ctx->port_info[0].port_id = 1;
+    ctx->port_info[0].cec_supported = 1;
+    //XXX: Enable ARC if supported
+    ctx->port_info[0].arc_supported = 0;
+    cec_get_physical_address((hdmi_cec_device *) ctx,
+            &ctx->port_info[0].physical_address );
+
+    ctx->version = 0x4;
+    ctx->vendor_id = 0xA47733;
+    cec_clear_logical_address((hdmi_cec_device_t*)ctx);
+
+    //Set up listener for HDMI events
+    ctx->disp_client = new qClient::QHDMIClient();
+    ctx->disp_client->setCECContext(ctx);
+    ctx->disp_client->registerClient(ctx->disp_client);
+
+    //Enable CEC - framework expects it to be enabled by default
+    cec_enable(ctx, true);
+
+    ALOGD("%s: CEC enabled", __FUNCTION__);
+}
+
+static void cec_close_context(cec_context_t* ctx __unused)
+{
+    ALOGD("%s: Closing context", __FUNCTION__);
+}
+
+static int cec_device_open(const struct hw_module_t* module,
+        const char* name,
+        struct hw_device_t** device)
+{
+    ALOGD_IF(DEBUG, "%s: name: %s", __FUNCTION__, name);
+    int status = -EINVAL;
+    if (!strcmp(name, HDMI_CEC_HARDWARE_INTERFACE )) {
+        struct cec_context_t *dev;
+        dev = (cec_context_t *) calloc (1, sizeof(*dev));
+        if (dev) {
+            cec_init_context(dev);
+
+            //Setup CEC methods
+            dev->device.common.tag       = HARDWARE_DEVICE_TAG;
+            dev->device.common.version   = HDMI_CEC_DEVICE_API_VERSION_1_0;
+            dev->device.common.module    = const_cast<hw_module_t* >(module);
+            dev->device.common.close     = cec_device_close;
+            dev->device.add_logical_address = cec_add_logical_address;
+            dev->device.clear_logical_address = cec_clear_logical_address;
+            dev->device.get_physical_address = cec_get_physical_address;
+            dev->device.send_message = cec_send_message;
+            dev->device.register_event_callback = cec_register_event_callback;
+            dev->device.get_version = cec_get_version;
+            dev->device.get_vendor_id = cec_get_vendor_id;
+            dev->device.get_port_info = cec_get_port_info;
+            dev->device.set_option = cec_set_option;
+            dev->device.set_audio_return_channel = cec_set_audio_return_channel;
+            dev->device.is_connected = cec_is_connected;
+
+            *device = &dev->device.common;
+            status = 0;
+        } else {
+            status = -EINVAL;
+        }
+    }
+    return status;
+}
+}; //namespace qhdmicec
+
+// Standard HAL module, should be outside qhdmicec namespace
+static struct hw_module_methods_t cec_module_methods = {
+        .open = qhdmicec::cec_device_open
+};
+
+hdmi_module_t HAL_MODULE_INFO_SYM = {
+    .common = {
+        .tag = HARDWARE_MODULE_TAG,
+        .version_major = 1,
+        .version_minor = 0,
+        .id = HDMI_CEC_HARDWARE_MODULE_ID,
+        .name = "QTI HDMI CEC module",
+        .author = "The Linux Foundation",
+        .methods = &cec_module_methods,
+    }
+};
+
+
diff --git a/hdmi_cec/qhdmi_cec.h b/hdmi_cec/qhdmi_cec.h
new file mode 100644
index 0000000..aa97620
--- /dev/null
+++ b/hdmi_cec/qhdmi_cec.h
@@ -0,0 +1,74 @@
+/*
+* Copyright (c) 2014 The Linux Foundation. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+*    * Redistributions of source code must retain the above copyright
+*      notice, this list of conditions and the following disclaimer.
+*    * Redistributions in binary form must reproduce the above
+*      copyright notice, this list of conditions and the following
+*      disclaimer in the documentation and/or other materials provided
+*      with the distribution.
+*    * Neither the name of The Linux Foundation. nor the names of its
+*      contributors may be used to endorse or promote products derived
+*      from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef QHDMI_CEC_H
+#define QHDMI_CEC_H
+
+#include <hardware/hdmi_cec.h>
+#include <utils/RefBase.h>
+
+namespace qClient {
+    class QHDMIClient;
+};
+
+namespace qhdmicec {
+
+#define SYSFS_BASE  "/sys/class/graphics/fb"
+#define MAX_PATH_LENGTH  128
+
+struct cec_callback_t {
+    // Function in HDMI service to call back on CEC messages
+    event_callback_t callback_func;
+    // This stores the object to pass back to the framework
+    void* callback_arg;
+
+};
+
+struct cec_context_t {
+    hdmi_cec_device_t device;    // Device for HW module
+    cec_callback_t callback;     // Struct storing callback object
+    bool enabled;
+    bool arc_enabled;
+    bool system_control;         // If true, HAL/driver handle CEC messages
+    int fb_num;                  // Framebuffer node for HDMI
+    char fb_sysfs_path[MAX_PATH_LENGTH];
+    hdmi_port_info *port_info;   // HDMI port info
+
+    // Logical address is stored in an array, the index of the array is the
+    // logical address and the value in the index shows whether it is set or not
+    int logical_address[CEC_ADDR_BROADCAST];
+    int version;
+    uint32_t vendor_id;
+    android::sp<qClient::QHDMIClient> disp_client;
+};
+
+void cec_receive_message(cec_context_t *ctx, char *msg, ssize_t len);
+void cec_hdmi_hotplug(cec_context_t *ctx, int connected);
+
+}; //namespace
+#endif /* end of include guard: QHDMI_CEC_H */
diff --git a/libcopybit/copybit.cpp b/libcopybit/copybit.cpp
index 9783896..02f0c7e 100644
--- a/libcopybit/copybit.cpp
+++ b/libcopybit/copybit.cpp
@@ -64,6 +64,7 @@
     int     relFence;
     struct  mdp_buf_sync sync;
     struct  blitReq list;
+    uint8_t dynamic_fps;
 };
 
 /**
@@ -122,6 +123,10 @@
     out->b = min(lhs->b, rhs->b);
 }
 
+static bool validateCopybitRect(struct copybit_rect_t *rect) {
+    return ((rect->b > rect->t) && (rect->r > rect->l)) ;
+}
+
 /** convert COPYBIT_FORMAT to MDP format */
 static int get_format(int format) {
     switch (format) {
@@ -161,7 +166,7 @@
     img->memory_id  = hnd->fd;
 }
 /** setup rectangles */
-static void set_rects(struct copybit_context_t *dev,
+static bool set_rects(struct copybit_context_t *dev,
                       struct mdp_blit_req *e,
                       const struct copybit_rect_t *dst,
                       const struct copybit_rect_t *src,
@@ -169,6 +174,9 @@
     struct copybit_rect_t clip;
     intersect(&clip, scissor, dst);
 
+    if (!validateCopybitRect(&clip))
+       return false;
+
     e->dst_rect.x  = clip.l;
     e->dst_rect.y  = clip.t;
     e->dst_rect.w  = clip.r - clip.l;
@@ -212,6 +220,7 @@
             e->src_rect.x = (src->l + src->r) - (e->src_rect.x + e->src_rect.w);
         }
     }
+    return true;
 }
 
 /** setup mdp request */
@@ -219,6 +228,7 @@
                       struct mdp_blit_req *req, int flags)
 {
     req->alpha = dev->mAlpha;
+    req->fps = dev->dynamic_fps;
     req->transp_mask = MDP_TRANSP_NOP;
     req->flags = dev->mFlags | flags;
     // check if we are blitting to f/b
@@ -250,7 +260,7 @@
         for (unsigned int i=0 ; i<l->count ; i++) {
             ALOGE("%d: src={w=%d, h=%d, f=%d, rect={%d,%d,%d,%d}}\n"
                   "    dst={w=%d, h=%d, f=%d, rect={%d,%d,%d,%d}}\n"
-                  "    flags=%08x"
+                  "    flags=%08x, fps=%d"
                   ,
                   i,
                   l->req[i].src.width,
@@ -267,7 +277,8 @@
                   l->req[i].dst_rect.y,
                   l->req[i].dst_rect.w,
                   l->req[i].dst_rect.h,
-                  l->req[i].flags
+                  l->req[i].flags,
+                  l->req[i].fps
                  );
         }
 #endif
@@ -315,6 +326,9 @@
                 if (value >= 256)   value = 255;
                 ctx->mAlpha = (uint8_t)value;
                 break;
+            case COPYBIT_DYNAMIC_FPS:
+                ctx->dynamic_fps = (uint8_t)value;
+                break;
             case COPYBIT_DITHER:
                 if (value == COPYBIT_ENABLE) {
                     ctx->mFlags |= MDP_DITHER;
@@ -524,7 +538,8 @@
             set_infos(ctx, req, flags);
             set_image(&req->dst, dst);
             set_image(&req->src, src);
-            set_rects(ctx, req, dst_rect, src_rect, &clip);
+            if (set_rects(ctx, req, dst_rect, src_rect, &clip) == false)
+                continue;
 
             if (req->src_rect.w<=0 || req->src_rect.h<=0)
                 continue;
@@ -747,6 +762,9 @@
     ctx->device.flush_get_fence = flush_get_fence;
     ctx->device.clear = clear_copybit;
     ctx->mAlpha = MDP_ALPHA_NOP;
+    //dynamic_fps is zero means default
+    //panel refresh rate for driver.
+    ctx->dynamic_fps = 0;
     ctx->mFlags = 0;
     ctx->sync.flags = 0;
     ctx->relFence = -1;
diff --git a/libcopybit/copybit.h b/libcopybit/copybit.h
index 6428023..1fc17ed 100644
--- a/libcopybit/copybit.h
+++ b/libcopybit/copybit.h
@@ -79,6 +79,7 @@
     /* FB height */
     COPYBIT_FRAMEBUFFER_HEIGHT = 8,
     COPYBIT_FG_LAYER = 9,
+    COPYBIT_DYNAMIC_FPS = 10,
 };
 
 /* values for copybit_set_parameter(COPYBIT_TRANSFORM) */
diff --git a/libcopybit/copybit_c2d.cpp b/libcopybit/copybit_c2d.cpp
index 3807f33..cc13fec 100644
--- a/libcopybit/copybit_c2d.cpp
+++ b/libcopybit/copybit_c2d.cpp
@@ -350,12 +350,7 @@
     if(!handle)
         return 0;
 
-    if (handle->flags & (private_handle_t::PRIV_FLAGS_USES_PMEM |
-                         private_handle_t::PRIV_FLAGS_USES_PMEM_ADSP))
-        memtype = KGSL_USER_MEM_TYPE_PMEM;
-    else if (handle->flags & private_handle_t::PRIV_FLAGS_USES_ASHMEM)
-        memtype = KGSL_USER_MEM_TYPE_ASHMEM;
-    else if (handle->flags & private_handle_t::PRIV_FLAGS_USES_ION)
+    if (handle->flags & private_handle_t::PRIV_FLAGS_USES_ION)
         memtype = KGSL_USER_MEM_TYPE_ION;
     else {
         ALOGE("Invalid handle flags: 0x%x", handle->flags);
@@ -1005,7 +1000,7 @@
     data.size = get_size(info);
     data.align = getpagesize();
     data.uncached = true;
-    int allocFlags = GRALLOC_USAGE_PRIVATE_SYSTEM_HEAP;
+    int allocFlags = 0;
 
     if (sAlloc == 0) {
         sAlloc = gralloc::IAllocController::getInstance();
diff --git a/libgralloc/alloc_controller.cpp b/libgralloc/alloc_controller.cpp
index f70ead3..1d0a40a 100644
--- a/libgralloc/alloc_controller.cpp
+++ b/libgralloc/alloc_controller.cpp
@@ -58,27 +58,6 @@
 static unsigned int getUBwcSize(int, int, int, const int, const int);
 
 //Common functions
-static bool canFallback(int usage, bool triedSystem)
-{
-    // Fallback to system heap when alloc fails unless
-    // 1. Composition type is MDP
-    // 2. Alloc from system heap was already tried
-    // 3. The heap type is requsted explicitly
-    // 4. The heap type is protected
-    // 5. The buffer is meant for external display only
-
-    if(QCCompositionType::getInstance().getCompositionType() &
-       COMPOSITION_TYPE_MDP)
-        return false;
-    if(triedSystem)
-        return false;
-    if(usage & (GRALLOC_HEAP_MASK | GRALLOC_USAGE_PROTECTED))
-        return false;
-    if(usage & (GRALLOC_HEAP_MASK | GRALLOC_USAGE_PRIVATE_EXTERNAL_ONLY))
-        return false;
-    //Return true by default
-    return true;
-}
 
 /* The default policy is to return cached buffers unless the client explicity
  * sets the PRIVATE_UNCACHED flag or indicates that the buffer will be rarely
@@ -344,20 +323,15 @@
 int IonController::allocate(alloc_data& data, int usage)
 {
     int ionFlags = 0;
+    int ionHeapId = 0;
     int ret;
 
     data.uncached = useUncached(usage);
     data.allocType = 0;
 
-    if(usage & GRALLOC_USAGE_PRIVATE_SYSTEM_HEAP)
-        ionFlags |= ION_HEAP(ION_SYSTEM_HEAP_ID);
-
-    if(usage & GRALLOC_USAGE_PRIVATE_IOMMU_HEAP)
-        ionFlags |= ION_HEAP(ION_IOMMU_HEAP_ID);
-
     if(usage & GRALLOC_USAGE_PROTECTED) {
         if (usage & GRALLOC_USAGE_PRIVATE_MM_HEAP) {
-            ionFlags |= ION_HEAP(ION_CP_MM_HEAP_ID);
+            ionHeapId |= ION_HEAP(ION_CP_MM_HEAP_ID);
             ionFlags |= ION_SECURE;
 #ifdef ION_FLAG_ALLOW_NON_CONTIG
             if (!(usage & GRALLOC_USAGE_PRIVATE_SECURE_DISPLAY)) {
@@ -366,8 +340,8 @@
 #endif
         } else {
             // for targets/OEMs which do not need HW level protection
-            // do not set ion secure flag & MM heap. Fallback to IOMMU heap.
-            ionFlags |= ION_HEAP(ION_IOMMU_HEAP_ID);
+            // do not set ion secure flag & MM heap. Fallback to system heap.
+            ionHeapId |= ION_HEAP(ION_SYSTEM_HEAP_ID);
             data.allocType |= private_handle_t::PRIV_FLAGS_PROTECTED_BUFFER;
         }
     } else if(usage & GRALLOC_USAGE_PRIVATE_MM_HEAP) {
@@ -375,40 +349,33 @@
         //If it is used for non secure cases, fallback to IOMMU heap
         ALOGW("GRALLOC_USAGE_PRIVATE_MM_HEAP \
                                 cannot be used as an insecure heap!\
-                                trying to use IOMMU instead !!");
-        ionFlags |= ION_HEAP(ION_IOMMU_HEAP_ID);
+                                trying to use system heap instead !!");
+        ionHeapId |= ION_HEAP(ION_SYSTEM_HEAP_ID);
     }
 
     if(usage & GRALLOC_USAGE_PRIVATE_CAMERA_HEAP)
-        ionFlags |= ION_HEAP(ION_CAMERA_HEAP_ID);
+        ionHeapId |= ION_HEAP(ION_CAMERA_HEAP_ID);
 
     if(usage & GRALLOC_USAGE_PRIVATE_ADSP_HEAP)
-        ionFlags |= ION_HEAP(ION_ADSP_HEAP_ID);
+        ionHeapId |= ION_HEAP(ION_ADSP_HEAP_ID);
 
     if(ionFlags & ION_SECURE)
          data.allocType |= private_handle_t::PRIV_FLAGS_SECURE_BUFFER;
 
-    // if no flags are set, default to
-    // SF + IOMMU heaps, so that bypass can work
-    // we can fall back to system heap if
-    // we run out.
-    if(!ionFlags)
-        ionFlags = ION_HEAP(ION_SF_HEAP_ID) | ION_HEAP(ION_IOMMU_HEAP_ID);
+    // if no ion heap flags are set, default to system heap
+    if(!ionHeapId)
+        ionHeapId = ION_HEAP(ION_SYSTEM_HEAP_ID);
 
+    //At this point we should have the right heap set, there is no fallback
     data.flags = ionFlags;
+    data.heapId = ionHeapId;
     ret = mIonAlloc->alloc_buffer(data);
 
-    // Fallback
-    if(ret < 0 && canFallback(usage,
-                              (ionFlags & ION_SYSTEM_HEAP_ID)))
-    {
-        ALOGW("Falling back to system heap");
-        data.flags = ION_HEAP(ION_SYSTEM_HEAP_ID);
-        ret = mIonAlloc->alloc_buffer(data);
-    }
-
     if(ret >= 0 ) {
         data.allocType |= private_handle_t::PRIV_FLAGS_USES_ION;
+    } else {
+        ALOGE("%s: Failed to allocate buffer - heap: 0x%x flags: 0x%x",
+                __FUNCTION__, ionHeapId, ionFlags);
     }
 
     return ret;
@@ -628,6 +595,7 @@
     int width = hnd->width;
     int height = hnd->height;
     unsigned int ystride, cstride;
+    unsigned int alignment = 4096;
 
     memset(ycbcr->reserved, 0, sizeof(ycbcr->reserved));
 
@@ -655,6 +623,34 @@
             ycbcr->chroma_step = 2;
         break;
 
+        case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS_UBWC:
+            // NV12_UBWC buffer has these 4 planes in the following sequence:
+            // Y_Meta_Plane, Y_Plane, UV_Meta_Plane, UV_Plane
+            unsigned int y_meta_stride, y_meta_height, y_meta_size;
+            unsigned int y_stride, y_height, y_size;
+            unsigned int c_meta_stride, c_meta_height, c_meta_size;
+
+            y_meta_stride = VENUS_Y_META_STRIDE(COLOR_FMT_NV12_UBWC, width);
+            y_meta_height = VENUS_Y_META_SCANLINES(COLOR_FMT_NV12_UBWC, height);
+            y_meta_size = ALIGN((y_meta_stride * y_meta_height), alignment);
+
+            y_stride = VENUS_Y_STRIDE(COLOR_FMT_NV12_UBWC, width);
+            y_height = VENUS_Y_SCANLINES(COLOR_FMT_NV12_UBWC, height);
+            y_size = ALIGN((y_stride * y_height), alignment);
+
+            c_meta_stride = VENUS_UV_META_STRIDE(COLOR_FMT_NV12_UBWC, width);
+            c_meta_height = VENUS_UV_META_SCANLINES(COLOR_FMT_NV12_UBWC, height);
+            c_meta_size = ALIGN((c_meta_stride * c_meta_height), alignment);
+
+            ycbcr->y  = (void*)(hnd->base + y_meta_size);
+            ycbcr->cb = (void*)(hnd->base + y_meta_size + y_size + c_meta_size);
+            ycbcr->cr = (void*)(hnd->base + y_meta_size + y_size +
+                                c_meta_size + 1);
+            ycbcr->ystride = y_stride;
+            ycbcr->cstride = VENUS_UV_STRIDE(COLOR_FMT_NV12_UBWC, width);
+            ycbcr->chroma_step = 2;
+        break;
+
         case HAL_PIXEL_FORMAT_YCrCb_420_SP:
         case HAL_PIXEL_FORMAT_YCrCb_422_SP:
         case HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO:
diff --git a/libgralloc/gpu.cpp b/libgralloc/gpu.cpp
index df7be41..9be93d6 100644
--- a/libgralloc/gpu.cpp
+++ b/libgralloc/gpu.cpp
@@ -65,13 +65,11 @@
         data.align = getpagesize();
 
     /* force 1MB alignment selectively for secure buffers, MDP5 onwards */
-#ifdef MDSS_TARGET
     if ((usage & GRALLOC_USAGE_PROTECTED) &&
         (usage & GRALLOC_USAGE_PRIVATE_MM_HEAP)) {
         data.align = ALIGN((int) data.align, SZ_1M);
         size = ALIGN(size, data.align);
     }
-#endif
 
     data.size = size;
     data.pHandle = (uintptr_t) pHandle;
@@ -86,7 +84,7 @@
         eData.size = ROUND_UP_PAGESIZE(sizeof(MetaData_t));
         eData.pHandle = data.pHandle;
         eData.align = getpagesize();
-        int eDataUsage = GRALLOC_USAGE_PRIVATE_SYSTEM_HEAP;
+        int eDataUsage = 0;
         int eDataErr = mAllocCtrl->allocate(eData, eDataUsage);
         ALOGE_IF(eDataErr, "gralloc failed for eDataErr=%s",
                                           strerror(-eDataErr));
@@ -99,10 +97,6 @@
         flags |= private_handle_t::PRIV_FLAGS_ITU_R_601;
         if (bufferType == BUFFER_TYPE_VIDEO) {
             if (usage & GRALLOC_USAGE_HW_CAMERA_WRITE) {
-#ifndef MDSS_TARGET
-                colorSpace = ITU_R_601_FR;
-                flags |= private_handle_t::PRIV_FLAGS_ITU_R_601_FR;
-#else
                 // Per the camera spec ITU 709 format should be set only for
                 // video encoding.
                 // It should be set to ITU 601 full range format for any other
@@ -117,7 +111,6 @@
                         colorSpace = ITU_R_601_FR;
                     }
                 }
-#endif
             }
         }
 
@@ -207,10 +200,7 @@
 {
     private_module_t* m = reinterpret_cast<private_module_t*>(common.module);
 
-    // we don't support framebuffer allocations with graphics heap flags
-    if (usage & GRALLOC_HEAP_MASK) {
-        return -EINVAL;
-    }
+    // This allocation will only happen when gralloc is in fb mode
 
     if (m->framebuffer == NULL) {
         ALOGE("%s: Invalid framebuffer", __FUNCTION__);
diff --git a/libgralloc/gralloc_priv.h b/libgralloc/gralloc_priv.h
index f973b76..676c3bc 100755
--- a/libgralloc/gralloc_priv.h
+++ b/libgralloc/gralloc_priv.h
@@ -34,9 +34,11 @@
                                (~(PAGE_SIZE-1)) )
 
 /* Gralloc usage bits indicating the type of allocation that should be used */
-/* SYSTEM heap comes from kernel vmalloc, can never be uncached,
+/* SYSTEM heap comes from kernel vmalloc (ION_SYSTEM_HEAP_ID)
+ * is cached by default and
  * is not secured */
-#define GRALLOC_USAGE_PRIVATE_SYSTEM_HEAP     GRALLOC_USAGE_PRIVATE_0
+
+/* GRALLOC_USAGE_PRIVATE_0 is unused */
 
 /* Non linear, Universal Bandwidth Compression */
 #define GRALLOC_USAGE_PRIVATE_ALLOC_UBWC      GRALLOC_USAGE_PRIVATE_1
@@ -84,14 +86,6 @@
 #define GRALLOC_MODULE_PERFORM_GET_MAP_SECURE_BUFFER_INFO 8
 #define GRALLOC_MODULE_PERFORM_GET_UBWC_FLAG 9
 
-#define GRALLOC_HEAP_MASK   (GRALLOC_USAGE_PRIVATE_SYSTEM_HEAP    |\
-                             GRALLOC_USAGE_PRIVATE_IOMMU_HEAP     |\
-                             GRALLOC_USAGE_PRIVATE_MM_HEAP        |\
-                             GRALLOC_USAGE_PRIVATE_ADSP_HEAP)
-
-#define INTERLACE_MASK 0x80
-/*****************************************************************************/
-
 /* OEM specific HAL formats */
 
 #define HAL_PIXEL_FORMAT_RGBA_5551               6
@@ -165,8 +159,6 @@
     BUFFER_TYPE_VIDEO
 };
 
-/*****************************************************************************/
-
 #ifdef __cplusplus
 struct private_handle_t : public native_handle {
 #else
@@ -175,8 +167,6 @@
 #endif
         enum {
             PRIV_FLAGS_FRAMEBUFFER        = 0x00000001,
-            PRIV_FLAGS_USES_PMEM          = 0x00000002,
-            PRIV_FLAGS_USES_PMEM_ADSP     = 0x00000004,
             PRIV_FLAGS_USES_ION           = 0x00000008,
             PRIV_FLAGS_USES_ASHMEM        = 0x00000010,
             PRIV_FLAGS_NEEDS_FLUSH        = 0x00000020,
@@ -184,10 +174,6 @@
             PRIV_FLAGS_NONCONTIGUOUS_MEM  = 0x00000100,
             PRIV_FLAGS_CACHED             = 0x00000200,
             PRIV_FLAGS_SECURE_BUFFER      = 0x00000400,
-            // For explicit synchronization
-            PRIV_FLAGS_UNSYNCHRONIZED     = 0x00000800,
-            // Not mapped in userspace
-            PRIV_FLAGS_NOT_MAPPED         = 0x00001000,
             // Display on external only
             PRIV_FLAGS_EXTERNAL_ONLY      = 0x00002000,
             // Set by HWC for protected non secure buffers
@@ -252,10 +238,6 @@
             magic = 0;
         }
 
-        bool usesPhysicallyContiguousMemory() {
-            return (flags & PRIV_FLAGS_USES_PMEM) != 0;
-        }
-
         static int validate(const native_handle* h) {
             const private_handle_t* hnd = (const private_handle_t*)h;
             if (!h || h->version != sizeof(native_handle) ||
diff --git a/libgralloc/ionalloc.cpp b/libgralloc/ionalloc.cpp
index 91a930c..96e0e3e 100644
--- a/libgralloc/ionalloc.cpp
+++ b/libgralloc/ionalloc.cpp
@@ -76,19 +76,9 @@
 
     ionAllocData.len = data.size;
     ionAllocData.align = data.align;
-    ionAllocData.heap_id_mask = data.flags & ~ION_SECURE;
-#ifdef ION_FLAG_ALLOW_NON_CONTIG
-    ionAllocData.heap_id_mask &= (data.flags & ~ION_FLAG_ALLOW_NON_CONTIG);
-#endif
-    ionAllocData.flags = data.uncached ? 0 : ION_FLAG_CACHED;
-    // ToDo: replace usage of alloc data structure with
-    //  ionallocdata structure.
-    if (data.flags & ION_SECURE)
-        ionAllocData.flags |= ION_SECURE;
-#ifdef ION_FLAG_ALLOW_NON_CONTIG
-    if (data.flags & ION_FLAG_ALLOW_NON_CONTIG)
-        ionAllocData.flags |= ION_FLAG_ALLOW_NON_CONTIG;
-#endif
+    ionAllocData.heap_id_mask = data.heapId;
+    ionAllocData.flags = data.flags;
+    ionAllocData.flags |= data.uncached ? 0 : ION_FLAG_CACHED;
     err = open_device();
     if (err)
         return err;
diff --git a/libgralloc/mapper.cpp b/libgralloc/mapper.cpp
index 5382300..8b38952 100644
--- a/libgralloc/mapper.cpp
+++ b/libgralloc/mapper.cpp
@@ -204,10 +204,7 @@
 
     if (hnd->base != 0) {
         // this buffer was mapped, unmap it now
-        if (hnd->flags & (private_handle_t::PRIV_FLAGS_USES_PMEM |
-                          private_handle_t::PRIV_FLAGS_USES_PMEM_ADSP |
-                          private_handle_t::PRIV_FLAGS_USES_ASHMEM |
-                          private_handle_t::PRIV_FLAGS_USES_ION)) {
+        if (hnd->flags & private_handle_t::PRIV_FLAGS_USES_ION) {
                 gralloc_unmap(module, hnd);
         } else {
             ALOGE("terminateBuffer: unmapping a non pmem/ashmem buffer flags = 0x%x",
diff --git a/libgralloc/memalloc.h b/libgralloc/memalloc.h
index 2bc1ddf..598d983 100644
--- a/libgralloc/memalloc.h
+++ b/libgralloc/memalloc.h
@@ -49,6 +49,7 @@
     uintptr_t      pHandle;
     bool           uncached;
     unsigned int   flags;
+    unsigned int   heapId;
     int            allocType;
 };
 
diff --git a/libhdmi/hdmi.cpp b/libhdmi/hdmi.cpp
index 1b2ffe0..fb6493a 100644
--- a/libhdmi/hdmi.cpp
+++ b/libhdmi/hdmi.cpp
@@ -412,8 +412,9 @@
     // for all the timing info read, get the best config
     for (int configIndex = 0; configIndex < mModeCount; configIndex++) {
         currentModeInfo = mDisplayConfigs[configIndex];
+        edidMode = mEDIDModes[configIndex];
 
-        if (!currentModeInfo.supported) {
+        if (!isValidMode(edidMode)) {
             ALOGD("%s EDID Mode %d is not supported", __FUNCTION__, edidMode);
             continue;
         }
diff --git a/libhwcomposer/hwc.cpp b/libhwcomposer/hwc.cpp
index a934f3e..3026d99 100644
--- a/libhwcomposer/hwc.cpp
+++ b/libhwcomposer/hwc.cpp
@@ -226,18 +226,11 @@
 
 }
 
-static void scaleDisplayFrame(hwc_context_t *ctx, int dpy,
-                            hwc_display_contents_1_t *list) {
-    uint32_t origXres = ctx->dpyAttr[dpy].xres;
-    uint32_t origYres = ctx->dpyAttr[dpy].yres;
-    uint32_t newXres = ctx->dpyAttr[dpy].xres_new;
-    uint32_t newYres = ctx->dpyAttr[dpy].yres_new;
-    float xresRatio = (float)origXres / (float)newXres;
-    float yresRatio = (float)origYres / (float)newYres;
+static void scaleDisplayFrame(hwc_display_contents_1_t *list, float xresRatio,
+        float yresRatio) {
     for (size_t i = 0; i < list->numHwLayers; i++) {
         hwc_layer_1_t *layer = &list->hwLayers[i];
         hwc_rect_t& displayFrame = layer->displayFrame;
-        hwc_rect_t sourceCrop = integerizeSourceCrop(layer->sourceCropf);
         uint32_t layerWidth = displayFrame.right - displayFrame.left;
         uint32_t layerHeight = displayFrame.bottom - displayFrame.top;
         displayFrame.left = (int)(xresRatio * (float)displayFrame.left);
@@ -249,6 +242,35 @@
     }
 }
 
+static void handleFbScaling(hwc_context_t *ctx, int dpy,
+        hwc_display_contents_1_t *list) {
+    //We could switch to a config that does not lead to fb scaling, but
+    //we need to update older display frames and ratios.
+    if (ctx->dpyAttr[dpy].fbScaling or ctx->dpyAttr[dpy].configSwitched) {
+        uint32_t xresPanel = ctx->dpyAttr[dpy].xres;
+        uint32_t yresPanel = ctx->dpyAttr[dpy].yres;
+        uint32_t xresFB = ctx->dpyAttr[dpy].xresFB;
+        uint32_t yresFB = ctx->dpyAttr[dpy].yresFB;
+        float xresRatio = (float)xresPanel / (float)xresFB;
+        float yresRatio = (float)yresPanel / (float)yresFB;
+        if(list->flags & HWC_GEOMETRY_CHANGED) {
+            //In case of geometry changes f/w resets displays frames w.r.t to
+            //FB's dimensions. So any config switch is automatically absorbed.
+            scaleDisplayFrame(list, xresRatio, yresRatio);
+        } else if (ctx->dpyAttr[dpy].configSwitched) {
+            //If there is a primary panel resolution switch without a geometry
+            //change we need to scale-back the previous ratio used and then use
+            //the current ratio. i.e use current ratio / prev ratio
+            scaleDisplayFrame(list,
+                    xresRatio / ctx->dpyAttr[dpy].fbWidthScaleRatio,
+                    yresRatio / ctx->dpyAttr[dpy].fbHeightScaleRatio);
+        }
+        ctx->dpyAttr[dpy].configSwitched = false;
+        ctx->dpyAttr[dpy].fbWidthScaleRatio = xresRatio;
+        ctx->dpyAttr[dpy].fbHeightScaleRatio = yresRatio;
+    }
+}
+
 static int hwc_prepare_primary(hwc_composer_device_1 *dev,
         hwc_display_contents_1_t *list) {
     ATRACE_CALL();
@@ -277,9 +299,7 @@
             ctx->dpyAttr[dpy].isActive = true;
         }
 
-        if (ctx->dpyAttr[dpy].customFBSize &&
-                list->flags & HWC_GEOMETRY_CHANGED)
-            scaleDisplayFrame(ctx, dpy, list);
+        handleFbScaling(ctx, dpy, list);
 
         reset_layer_prop(ctx, dpy, (int)list->numHwLayers - 1);
         setListStats(ctx, list, dpy);
@@ -449,7 +469,13 @@
             value = FB_BLANK_POWERDOWN;
             break;
         case HWC_POWER_MODE_DOZE:
+            // FB_BLANK_NORMAL is being used here to map to doze mode
+            // This definition is specific to our fbdev implementation
+            value = FB_BLANK_NORMAL;
+            break;
         case HWC_POWER_MODE_DOZE_SUSPEND:
+            // FB_BLANK_VSYNC_SUSPEND is being used here to map to doze_suspend
+            // This definition is specific to our fbdev implementation
             value = FB_BLANK_VSYNC_SUSPEND;
             break;
         case HWC_POWER_MODE_NORMAL:
@@ -485,7 +511,8 @@
                 ctx->mHPDEnabled = true;
             }
 
-            ctx->dpyAttr[dpy].isActive = not(mode == HWC_POWER_MODE_OFF);
+            ctx->dpyAttr[dpy].isActive = not(mode == HWC_POWER_MODE_OFF ||
+                    mode == HWC_POWER_MODE_DOZE_SUSPEND);
         }
         //Deliberate fall through since there is no explicit power mode for
         //virtual displays.
@@ -635,7 +662,11 @@
             }
         }
 
-        int lSplit = getLeftSplit(ctx, dpy);
+        /* When source split is enabled, right ROI will always be NULL since the
+         * ROI for the whole panel generated in a single coordinate system will
+         * be populuated in left ROI. So leave the right ROI untouched */
+        int lSplit = qdutils::MDPVersion::getInstance().isSrcSplit() ? 0
+                :getLeftSplit(ctx, dpy);
         qhwc::ovutils::Dim lRoi = qhwc::ovutils::Dim(
             ctx->listStats[dpy].lRoi.left,
             ctx->listStats[dpy].lRoi.top,
@@ -833,8 +864,8 @@
                     hotPluggable ? refresh : ctx->dpyAttr[disp].vsync_period;
             break;
         case HWC_DISPLAY_WIDTH:
-            if (ctx->dpyAttr[disp].customFBSize)
-                values[i] = ctx->dpyAttr[disp].xres_new;
+            if (ctx->dpyAttr[disp].fbScaling)
+                values[i] = ctx->dpyAttr[disp].xresFB;
             else
                 values[i] = hotPluggable ? xres : ctx->dpyAttr[disp].xres;
 
@@ -842,8 +873,8 @@
                     values[i]);
             break;
         case HWC_DISPLAY_HEIGHT:
-            if (ctx->dpyAttr[disp].customFBSize)
-                values[i] = ctx->dpyAttr[disp].yres_new;
+            if (ctx->dpyAttr[disp].fbScaling)
+                values[i] = ctx->dpyAttr[disp].yresFB;
             else
                 values[i] = hotPluggable ? yres : ctx->dpyAttr[disp].yres;
             ALOGD("%s disp = %d, height = %d",__FUNCTION__, disp,
@@ -883,6 +914,10 @@
     dumpsys_log(aBuf, "  DynRefreshRate=%d\n",
                 ctx->dpyAttr[HWC_DISPLAY_PRIMARY].dynRefreshRate);
     for(int dpy = 0; dpy < HWC_NUM_DISPLAY_TYPES; dpy++) {
+        if(dpy == HWC_DISPLAY_PRIMARY)
+            dumpsys_log(aBuf, "Dpy %d: FB Scale Ratio w %.1f, h %.1f\n", dpy,
+                    ctx->dpyAttr[dpy].fbWidthScaleRatio,
+                    ctx->dpyAttr[dpy].fbHeightScaleRatio);
         if(ctx->mMDPComp[dpy])
             ctx->mMDPComp[dpy]->dump(aBuf, ctx);
     }
@@ -897,6 +932,7 @@
         dumpsys_log(aBuf, ovDump);
         ovDump[0] = '\0';
     }
+    dumpsys_log(aBuf, "Copybit::isAbcInUse=%d\n\n",isAbcInUse(ctx) ? 1 : 0);
     strlcpy(buff, aBuf.string(), buff_len);
 }
 
@@ -970,7 +1006,11 @@
         memset(dev, 0, sizeof(*dev));
 
         //Initialize hwc context
-        initContext(dev);
+        status = initContext(dev);
+        if (status < 0) {
+            free(dev);
+            return status;
+        }
 
         //Setup HWC methods
         dev->device.common.tag          = HARDWARE_DEVICE_TAG;
diff --git a/libhwcomposer/hwc_copybit.cpp b/libhwcomposer/hwc_copybit.cpp
index 68f168a..d4bcc88 100644
--- a/libhwcomposer/hwc_copybit.cpp
+++ b/libhwcomposer/hwc_copybit.cpp
@@ -183,7 +183,8 @@
        for (int k = ctx->listStats[dpy].numAppLayers-1; k >= 0 ; k--) {
            //disable swap rect in case of scaling and video .
            private_handle_t *hnd =(private_handle_t *)list->hwLayers[k].handle;
-           if(needsScaling(&list->hwLayers[k])||( hnd && isYuvBuffer(hnd))) {
+           if(needsScaling(&list->hwLayers[k])||( hnd && isYuvBuffer(hnd)) ||
+                   (list->hwLayers[k].transform & HAL_TRANSFORM_ROT_90)) {
                mFbCache.reset();
                return -1;
            }
@@ -354,10 +355,18 @@
             dx = (float)dst_w/(float)src_w;
             dy = (float)dst_h/(float)src_h;
 
-            if (dx > MAX_SCALE_FACTOR || dx < MIN_SCALE_FACTOR)
+            float scale_factor_max = MAX_SCALE_FACTOR;
+            float scale_factor_min = MIN_SCALE_FACTOR;
+
+            if (isAlphaPresent(layer)) {
+               scale_factor_max = MAX_SCALE_FACTOR/4;
+               scale_factor_min = MIN_SCALE_FACTOR*4;
+            }
+
+            if (dx > scale_factor_max || dx < scale_factor_min)
                 return false;
 
-            if (dy > MAX_SCALE_FACTOR || dy < MIN_SCALE_FACTOR)
+            if (dy > scale_factor_max || dy < scale_factor_min)
                 return false;
         }
     }
@@ -810,7 +819,13 @@
         ALOGE("%s: Framebuffer handle is NULL", __FUNCTION__);
         return -1;
     }
-
+    uint32_t dynamic_fps = 0;
+#ifdef DYNAMIC_FPS
+    MetaData_t *mdata = hnd ? (MetaData_t *)hnd->base_metadata : NULL;
+    if (mdata && (mdata->operation & UPDATE_REFRESH_RATE)) {
+       dynamic_fps  = roundOff(mdata->refreshrate);
+    }
+#endif
     // Set the copybit source:
     copybit_image_t src;
     src.w = getWidth(hnd);
@@ -964,7 +979,7 @@
 
        ALOGD("%s:%d::tmp_w = %d,tmp_h = %d",__FUNCTION__,__LINE__,tmp_w,tmp_h);
 
-       int usage = GRALLOC_USAGE_PRIVATE_IOMMU_HEAP;
+       int usage = 0;
        int format = fbHandle->format;
 
        // We do not want copybit to generate alpha values from nothing
@@ -1025,6 +1040,7 @@
                                               layerTransform);
     //TODO: once, we are able to read layer alpha, update this
     copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 255);
+    copybit->set_parameter(copybit, COPYBIT_DYNAMIC_FPS, dynamic_fps);
     copybit->set_parameter(copybit, COPYBIT_BLEND_MODE,
                                               layer->blending);
     copybit->set_parameter(copybit, COPYBIT_DITHER,
@@ -1129,8 +1145,7 @@
     for (int i = 0; i < NUM_RENDER_BUFFERS; i++) {
         if (mRenderBuffer[i] == NULL) {
             ret = alloc_buffer(&mRenderBuffer[i],
-                               w, h, f,
-                               GRALLOC_USAGE_PRIVATE_IOMMU_HEAP);
+                               w, h, f, 0);
         }
         if(ret < 0) {
             freeRenderBuffers();
diff --git a/libhwcomposer/hwc_fbupdate.cpp b/libhwcomposer/hwc_fbupdate.cpp
index 3ac04a8..74d95e7 100644
--- a/libhwcomposer/hwc_fbupdate.cpp
+++ b/libhwcomposer/hwc_fbupdate.cpp
@@ -49,11 +49,9 @@
     unsigned int size = 0;
     uint32_t xres = ctx->dpyAttr[mDpy].xres;
     uint32_t yres = ctx->dpyAttr[mDpy].yres;
-    if (ctx->dpyAttr[dpy].customFBSize) {
-        //GPU will render and compose at new resolution
-        //So need to have FB at new resolution
-        xres = ctx->dpyAttr[mDpy].xres_new;
-        yres = ctx->dpyAttr[mDpy].yres_new;
+    if (ctx->dpyAttr[dpy].fbScaling) {
+        xres = ctx->dpyAttr[mDpy].xresFB;
+        yres = ctx->dpyAttr[mDpy].yresFB;
     }
     getBufferAttributes((int)xres, (int)yres,
             ctx->dpyAttr[mDpy].fbformat,
@@ -168,7 +166,7 @@
 
         // No FB update optimization on (1) Custom FB resolution,
         // (2) External Mirror mode, (3) External orientation
-        if(!ctx->dpyAttr[mDpy].customFBSize && !ctx->mBufferMirrorMode
+        if(!ctx->dpyAttr[mDpy].fbScaling && !ctx->mBufferMirrorMode
            && !ctx->mExtOrientation) {
             sourceCrop = fbUpdatingRect;
             displayFrame = fbUpdatingRect;
@@ -191,7 +189,7 @@
         } else if((mDpy && !extOrient
                   && !ctx->dpyAttr[mDpy].mMDPScalingMode)) {
             if(ctx->mOverlay->isUIScalingOnExternalSupported() &&
-                !ctx->dpyAttr[mDpy].customFBSize) {
+                !ctx->dpyAttr[mDpy].fbScaling) {
                 getNonWormholeRegion(list, sourceCrop);
                 displayFrame = sourceCrop;
             }
@@ -300,7 +298,7 @@
 
         // No FB update optimization on (1) Custom FB resolution,
         // (2) External Mirror mode, (3) External orientation
-        if(!ctx->dpyAttr[mDpy].customFBSize && !ctx->mBufferMirrorMode
+        if(!ctx->dpyAttr[mDpy].fbScaling && !ctx->mBufferMirrorMode
            && !ctx->mExtOrientation) {
             sourceCrop = fbUpdatingRect;
             displayFrame = fbUpdatingRect;
@@ -319,7 +317,7 @@
         } else if((mDpy && !extOrient
                   && !ctx->dpyAttr[mDpy].mMDPScalingMode)) {
             if(!qdutils::MDPVersion::getInstance().is8x26() &&
-                !ctx->dpyAttr[mDpy].customFBSize) {
+                !ctx->dpyAttr[mDpy].fbScaling) {
                 getNonWormholeRegion(list, sourceCrop);
                 displayFrame = sourceCrop;
             }
@@ -466,7 +464,7 @@
 
     // No FB update optimization on (1) Custom FB resolution,
     // (2) External Mirror mode, (3) External orientation
-    if(!ctx->dpyAttr[mDpy].customFBSize && !ctx->mBufferMirrorMode
+    if(!ctx->dpyAttr[mDpy].fbScaling && !ctx->mBufferMirrorMode
        && !ctx->mExtOrientation) {
         sourceCrop = fbUpdatingRect;
         displayFrame = fbUpdatingRect;
@@ -487,7 +485,7 @@
     } else if((mDpy && !extOrient
               && !ctx->dpyAttr[mDpy].mMDPScalingMode)) {
         if(!qdutils::MDPVersion::getInstance().is8x26() &&
-            !ctx->dpyAttr[mDpy].customFBSize) {
+            !ctx->dpyAttr[mDpy].fbScaling) {
             getNonWormholeRegion(list, sourceCrop);
             displayFrame = sourceCrop;
         }
diff --git a/libhwcomposer/hwc_mdpcomp.cpp b/libhwcomposer/hwc_mdpcomp.cpp
index 0986fc6..32911e9 100644
--- a/libhwcomposer/hwc_mdpcomp.cpp
+++ b/libhwcomposer/hwc_mdpcomp.cpp
@@ -217,9 +217,6 @@
     mCurrentFrame.reset(numLayers);
     ctx->mOverlay->clear(mDpy);
     ctx->mLayerRotMap[mDpy]->clear();
-    resetROI(ctx, mDpy);
-    memset(&mCurrentFrame.drop, 0, sizeof(mCurrentFrame.drop));
-    mCurrentFrame.dropCount = 0;
 }
 
 void MDPComp::reset() {
@@ -3015,7 +3012,6 @@
         return -1;
     }
     close(fd);
-    sIsPartialUpdateActive = enable;
     return 0;
 }
 
diff --git a/libhwcomposer/hwc_mdpcomp.h b/libhwcomposer/hwc_mdpcomp.h
index a83f51f..7752384 100644
--- a/libhwcomposer/hwc_mdpcomp.h
+++ b/libhwcomposer/hwc_mdpcomp.h
@@ -58,6 +58,8 @@
     static void setMaxPipesPerMixer(const uint32_t value);
     static int setPartialUpdatePref(hwc_context_t *ctx, bool enable);
     static bool getPartialUpdatePref(hwc_context_t *ctx);
+    static void enablePartialUpdate(bool enable)
+                                          { sIsPartialUpdateActive = enable; };
     void setDynRefreshRate(hwc_context_t *ctx, hwc_display_contents_1_t* list);
 
 protected:
diff --git a/libhwcomposer/hwc_qclient.cpp b/libhwcomposer/hwc_qclient.cpp
index 487ec77..34de2e6 100644
--- a/libhwcomposer/hwc_qclient.cpp
+++ b/libhwcomposer/hwc_qclient.cpp
@@ -121,13 +121,8 @@
         Parcel* outParcel) {
     int dpy = inParcel->readInt32();
     outParcel->writeInt32(ctx->dpyAttr[dpy].vsync_period);
-    if (ctx->dpyAttr[dpy].customFBSize) {
-        outParcel->writeInt32(ctx->dpyAttr[dpy].xres_new);
-        outParcel->writeInt32(ctx->dpyAttr[dpy].yres_new);
-    } else {
-        outParcel->writeInt32(ctx->dpyAttr[dpy].xres);
-        outParcel->writeInt32(ctx->dpyAttr[dpy].yres);
-    }
+    outParcel->writeInt32(ctx->dpyAttr[dpy].xres);
+    outParcel->writeInt32(ctx->dpyAttr[dpy].yres);
     outParcel->writeFloat(ctx->dpyAttr[dpy].xdpi);
     outParcel->writeFloat(ctx->dpyAttr[dpy].ydpi);
     //XXX: Need to check what to return for HDMI
@@ -313,11 +308,25 @@
     }
 }
 
-static status_t setPartialUpdatePref(hwc_context_t *ctx, uint32_t enable) {
-    ALOGD("%s: enable: %d", __FUNCTION__, enable);
-    if(qhwc::MDPComp::setPartialUpdatePref(ctx, (bool)enable) < 0)
-        return NO_INIT;
-    return NO_ERROR;
+static status_t setPartialUpdateState(hwc_context_t *ctx, uint32_t state) {
+    ALOGD("%s: state: %d", __FUNCTION__, state);
+    switch(state) {
+        case IQService::PREF_PARTIAL_UPDATE:
+            if(qhwc::MDPComp::setPartialUpdatePref(ctx, true) < 0)
+                return NO_INIT;
+            return NO_ERROR;
+        case IQService::PREF_POST_PROCESSING:
+            if(qhwc::MDPComp::setPartialUpdatePref(ctx, false) < 0)
+                return NO_INIT;
+            qhwc::MDPComp::enablePartialUpdate(false);
+            return NO_ERROR;
+        case IQService::ENABLE_PARTIAL_UPDATE:
+            qhwc::MDPComp::enablePartialUpdate(true);
+            return NO_ERROR;
+        default:
+            ALOGE("%s: Invalid state", __FUNCTION__);
+            return NO_ERROR;
+    };
 }
 
 static void toggleScreenUpdate(hwc_context_t* ctx, uint32_t on) {
@@ -355,6 +364,121 @@
     }
 }
 
+static status_t setActiveConfig(hwc_context_t* ctx, const Parcel *inParcel,
+        Parcel *outParcel) {
+    uint32_t index = inParcel->readInt32();
+    int dpy = inParcel->readInt32();
+    //Currently only primary supported
+    if(dpy > HWC_DISPLAY_PRIMARY) {
+        return BAD_VALUE;
+    }
+
+    Configs *configs = Configs::getInstance();
+    if(configs == NULL) {
+        ALOGE("%s(): Unable to acquire a Configs instance", __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+
+    if(configs->getActiveConfig() == index) {
+        ALOGI("%s(): Config %u is already set", __FUNCTION__, index);
+        return ALREADY_EXISTS;
+    }
+
+    ctx->mDrawLock.lock();
+    //Updates the necessary sysfs nodes and reads split info again which is
+    //needed to reinitialize composition resources.
+    if(configs->setActiveConfig(index) == false) {
+        ALOGE("%s(): Failed to set config %u", __FUNCTION__, index);
+        ctx->mDrawLock.unlock();
+        return UNKNOWN_ERROR;
+    }
+
+    qdutils::DisplayAttributes attr = configs->getAttributes(index);
+
+    ctx->dpyAttr[dpy].xres = attr.xres;
+    ctx->dpyAttr[dpy].yres = attr.yres;
+
+    ctx->dpyAttr[dpy].fbScaling = ((ctx->dpyAttr[dpy].xres !=
+            ctx->dpyAttr[dpy].xresFB) || (ctx->dpyAttr[dpy].yres !=
+            ctx->dpyAttr[dpy].yresFB));
+
+    destroyCompositionResources(ctx, dpy);
+    initCompositionResources(ctx, dpy);
+    ctx->dpyAttr[dpy].configSwitched = true;
+    ctx->mDrawLock.unlock();
+    ctx->proc->invalidate(ctx->proc);
+    return NO_ERROR;
+}
+
+static status_t getActiveConfig(hwc_context_t* ctx, const Parcel *inParcel,
+        Parcel *outParcel) {
+    Locker::Autolock _sl(ctx->mDrawLock);
+    int dpy = inParcel->readInt32();
+    //Currently only primary supported
+    if(dpy > HWC_DISPLAY_PRIMARY) {
+        return BAD_VALUE;
+    }
+
+    Configs *configs = Configs::getInstance();
+    if(configs == NULL) {
+        ALOGE("%s(): Unable to acquire a Configs instance", __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+
+    outParcel->writeInt32(configs->getActiveConfig());
+    return NO_ERROR;
+}
+
+static status_t getConfigCount(hwc_context_t* ctx, const Parcel *inParcel,
+        Parcel *outParcel) {
+    Locker::Autolock _sl(ctx->mDrawLock);
+    int dpy = inParcel->readInt32();
+    //Currently only primary supported
+    if(dpy > HWC_DISPLAY_PRIMARY) {
+        return BAD_VALUE;
+    }
+
+    Configs *configs = Configs::getInstance();
+    if(configs == NULL) {
+        ALOGE("%s(): Unable to acquire a Configs instance", __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+
+    outParcel->writeInt32(configs->getConfigCount());
+    return NO_ERROR;
+}
+
+static status_t getDisplayAttributesForConfig(hwc_context_t* ctx,
+        const Parcel *inParcel, Parcel *outParcel) {
+    Locker::Autolock _sl(ctx->mDrawLock);
+    uint32_t index = inParcel->readInt32();
+    int dpy = inParcel->readInt32();
+    //Currently only primary supported
+    if(dpy > HWC_DISPLAY_PRIMARY) {
+        return BAD_VALUE;
+    }
+
+    Configs *configs = Configs::getInstance();
+    if(configs == NULL) {
+        ALOGE("%s(): Unable to acquire a Configs instance", __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+
+    //xres, yres are used from the Config class, we assume for now that the
+    //other params are the same. This might change in the future.
+    outParcel->writeInt32(ctx->dpyAttr[dpy].vsync_period);
+
+    qdutils::DisplayAttributes attr = configs->getAttributes(index);
+    outParcel->writeInt32(attr.xres);
+    outParcel->writeInt32(attr.yres);
+
+    outParcel->writeFloat(ctx->dpyAttr[dpy].xdpi);
+    outParcel->writeFloat(ctx->dpyAttr[dpy].ydpi);
+    outParcel->writeInt32(ctx->mMDP.panel);
+
+    return NO_ERROR;
+}
+
 status_t QClient::notifyCallback(uint32_t command, const Parcel* inParcel,
         Parcel* outParcel) {
     status_t ret = NO_ERROR;
@@ -404,7 +528,7 @@
             setMaxPipesPerMixer(mHwcContext, inParcel);
             break;
         case IQService::SET_PARTIAL_UPDATE:
-            ret = setPartialUpdatePref(mHwcContext, inParcel->readInt32());
+            ret = setPartialUpdateState(mHwcContext, inParcel->readInt32());
             break;
         case IQService::TOGGLE_BWC:
             toggleBWC(mHwcContext, inParcel);
@@ -418,6 +542,19 @@
         case IQService::SET_S3D_MODE:
             setS3DMode(mHwcContext, inParcel->readInt32());
             break;
+        case IQService::SET_ACTIVE_CONFIG:
+            ret = setActiveConfig(mHwcContext, inParcel, outParcel);
+            break;
+        case IQService::GET_ACTIVE_CONFIG:
+            ret = getActiveConfig(mHwcContext, inParcel, outParcel);
+            break;
+        case IQService::GET_CONFIG_COUNT:
+            ret = getConfigCount(mHwcContext, inParcel, outParcel);
+            break;
+        case IQService::GET_DISPLAY_ATTRIBUTES_FOR_CONFIG:
+            ret = getDisplayAttributesForConfig(mHwcContext, inParcel,
+                    outParcel);
+            break;
         default:
             ret = NO_ERROR;
     }
diff --git a/libhwcomposer/hwc_uevents.cpp b/libhwcomposer/hwc_uevents.cpp
index c6179e4..b387642 100644
--- a/libhwcomposer/hwc_uevents.cpp
+++ b/libhwcomposer/hwc_uevents.cpp
@@ -125,10 +125,13 @@
                 ctx->proc->hotplug(ctx->proc, dpy, EXTERNAL_OFFLINE);
             }
 
+            // Report Hotplug via CEC HAL
+            ctx->mQService->onHdmiHotplug((int)ctx->dpyAttr[dpy].connected);
+
             //On 8994, 8992 due to hardware limitations, we disable bwc
             //when HDMI intf is active
             if((qdutils::MDPVersion::getInstance().is8994() or
-                qdutils::MDPVersion::getInstance().is8092()) and
+                qdutils::MDPVersion::getInstance().is8992()) and
                     qdutils::MDPVersion::getInstance().supportsBWC()) {
                 Locker::Autolock _l(ctx->mDrawLock);
                 ctx->mBWCEnabled = true;
@@ -148,7 +151,7 @@
             //On 8994, 8992 due to hardware limitations, we disable bwc
             //when HDMI intf is active
             if((qdutils::MDPVersion::getInstance().is8994() or
-                qdutils::MDPVersion::getInstance().is8092()) and
+                qdutils::MDPVersion::getInstance().is8992()) and
                     qdutils::MDPVersion::getInstance().supportsBWC()) {
                 Locker::Autolock _l(ctx->mDrawLock);
                 ctx->mBWCEnabled = false;
@@ -158,7 +161,7 @@
                 ctx->mDrawLock.lock();
                 handle_online(ctx, dpy);
                 ctx->mDrawLock.unlock();
-
+                ctx->mQService->onHdmiHotplug(ctx->dpyAttr[dpy].connected);
                 ctx->proc->invalidate(ctx->proc);
                 break;
             } else {
@@ -199,7 +202,15 @@
                         "uevent thread", __FUNCTION__);
                 ctx->mWfdSyncLock.unlock();
             }
-            ctx->mHDMIDisplay->configure();
+            // If FB open fails ignore this hotplug event
+            int error = ctx->mHDMIDisplay->configure();
+            if (error < 0) {
+                ALOGE("%s: Open Framebuffer for dpy = %d", __FUNCTION__, dpy);
+                ctx->mDrawLock.lock();
+                ctx->dpyAttr[dpy].isConfiguring = false;
+                ctx->mDrawLock.unlock();
+                break;
+            }
             ctx->mHDMIDisplay->activateDisplay();
 
             ctx->mDrawLock.lock();
@@ -213,6 +224,7 @@
             /* External display is HDMI */
             ALOGI("%s: Sending EXTERNAL ONLINE event", __FUNCTION__);
             ctx->proc->hotplug(ctx->proc, dpy, EXTERNAL_ONLINE);
+            ctx->mQService->onHdmiHotplug(ctx->dpyAttr[dpy].connected);
             break;
         }
     default:
diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp
index da9004f..27243c4 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -76,7 +76,7 @@
 #endif
 #endif
 
-#define PROP_DEFAULT_APPBUFFER  "sf.default.app_buffer_count"
+#define PROP_DEFAULT_APPBUFFER  "hw.sf.app_buff_count"
 #define MAX_RAM_SIZE  512*1024*1024
 #define qHD_WIDTH 540
 
@@ -119,33 +119,38 @@
             (xres < MIN_DISPLAY_XRES || yres < MIN_DISPLAY_YRES));
 }
 
-void changeResolution(hwc_context_t *ctx, int xres_orig, int yres_orig,
-                      int width, int height) {
+static void handleFbScaling(hwc_context_t *ctx, int xresPanel, int yresPanel,
+        int width, int height) {
+    const int dpy = HWC_DISPLAY_PRIMARY;
     //Store original display resolution.
-    ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres_new = xres_orig;
-    ctx->dpyAttr[HWC_DISPLAY_PRIMARY].yres_new = yres_orig;
-    ctx->dpyAttr[HWC_DISPLAY_PRIMARY].customFBSize = false;
+    ctx->dpyAttr[dpy].xresFB = xresPanel;
+    ctx->dpyAttr[dpy].yresFB = yresPanel;
+    ctx->dpyAttr[dpy].fbScaling = false;
     char property[PROPERTY_VALUE_MAX] = {'\0'};
     char *yptr = NULL;
     if (property_get("debug.hwc.fbsize", property, NULL) > 0) {
         yptr = strcasestr(property,"x");
         if(yptr) {
-            int xres_new = atoi(property);
-            int yres_new = atoi(yptr + 1);
-            if (isValidResolution(ctx,xres_new,yres_new) &&
-                xres_new != xres_orig && yres_new != yres_orig) {
-                ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres_new = xres_new;
-                ctx->dpyAttr[HWC_DISPLAY_PRIMARY].yres_new = yres_new;
-                ctx->dpyAttr[HWC_DISPLAY_PRIMARY].customFBSize = true;
+            int xresFB = atoi(property);
+            int yresFB = atoi(yptr + 1);
+            if (isValidResolution(ctx, xresFB, yresFB) &&
+                xresFB != xresPanel && yresFB != yresPanel) {
+                ctx->dpyAttr[dpy].xresFB = xresFB;
+                ctx->dpyAttr[dpy].yresFB = yresFB;
+                ctx->dpyAttr[dpy].fbScaling = true;
 
-                //Caluculate DPI according to changed resolution.
-                float xdpi = ((float)xres_new * 25.4f) / (float)width;
-                float ydpi = ((float)yres_new * 25.4f) / (float)height;
-                ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xdpi = xdpi;
-                ctx->dpyAttr[HWC_DISPLAY_PRIMARY].ydpi = ydpi;
+                //Calculate DPI according to changed resolution.
+                float xdpi = ((float)xresFB * 25.4f) / (float)width;
+                float ydpi = ((float)yresFB * 25.4f) / (float)height;
+                ctx->dpyAttr[dpy].xdpi = xdpi;
+                ctx->dpyAttr[dpy].ydpi = ydpi;
             }
         }
     }
+    ctx->dpyAttr[dpy].fbWidthScaleRatio = (float) ctx->dpyAttr[dpy].xres /
+            (float) ctx->dpyAttr[dpy].xresFB;
+    ctx->dpyAttr[dpy].fbHeightScaleRatio = (float) ctx->dpyAttr[dpy].yres /
+            (float) ctx->dpyAttr[dpy].yresFB;
 }
 
 // Initialize hdmi display attributes based on
@@ -269,8 +274,7 @@
             (uint32_t)(1000000000l / fps);
     ctx->dpyAttr[HWC_DISPLAY_PRIMARY].fbformat = getFBformat(info);
 
-    //To change resolution of primary display
-    changeResolution(ctx, info.xres, info.yres, info.width, info.height);
+    handleFbScaling(ctx, info.xres, info.yres, info.width, info.height);
 
     //Unblank primary on first boot
     if(ioctl(fb_fd, FBIOBLANK,FB_BLANK_UNBLANK) < 0) {
@@ -297,12 +301,30 @@
     }
     if ((ramSize && ramSize < MAX_RAM_SIZE) &&
          (sInfo.xres &&  sInfo.xres <= qHD_WIDTH )) {
-                  property_set(PROP_DEFAULT_APPBUFFER, "2");
+                  property_set(PROP_DEFAULT_APPBUFFER, "3");
     }
 }
 
-void initContext(hwc_context_t *ctx)
+int initContext(hwc_context_t *ctx)
 {
+    int error = -1;
+    int compositionType = 0;
+
+    //Right now hwc starts the service but anybody could do it, or it could be
+    //independent process as well.
+    QService::init();
+    sp<IQClient> client = new QClient(ctx);
+    sp<IQService> iqs = interface_cast<IQService>(
+            defaultServiceManager()->getService(
+            String16("display.qservice")));
+    if (iqs.get()) {
+      iqs->connect(client);
+      ctx->mQService = reinterpret_cast<QService* >(iqs.get());
+    } else {
+      ALOGE("%s: Failed to acquire service pointer", __FUNCTION__);
+      return error;
+    }
+
     overlay::Overlay::initOverlay();
     ctx->mHDMIDisplay = new HDMIDisplay();
     uint32_t priW = 0, priH = 0;
@@ -315,15 +337,24 @@
     if(ctx->mHDMIDisplay->isHDMIPrimaryDisplay()) {
         int connected = ctx->mHDMIDisplay->getConnectedState();
         if(connected == 1) {
-            ctx->mHDMIDisplay->configure();
+            error = ctx->mHDMIDisplay->configure();
+            if (error < 0) {
+                goto OpenFBError;
+            }
             updateDisplayInfo(ctx, HWC_DISPLAY_PRIMARY);
             ctx->dpyAttr[HWC_DISPLAY_PRIMARY].connected = true;
         } else {
-            openFramebufferDevice(ctx);
+            error = openFramebufferDevice(ctx);
+            if(error < 0) {
+                goto OpenFBError;
+            }
             ctx->dpyAttr[HWC_DISPLAY_PRIMARY].connected = false;
         }
     } else {
-        openFramebufferDevice(ctx);
+        error = openFramebufferDevice(ctx);
+        if(error < 0) {
+            goto OpenFBError;
+        }
         ctx->dpyAttr[HWC_DISPLAY_PRIMARY].connected = true;
         // Send the primary resolution to the hdmi display class
         // to be used for MDP scaling functionality
@@ -349,8 +380,8 @@
 
     // Check if the target supports copybit compostion (dyn/mdp) to
     // decide if we need to open the copybit module.
-    int compositionType =
-        qdutils::QCCompositionType::getInstance().getCompositionType();
+    compositionType =
+                qdutils::QCCompositionType::getInstance().getCompositionType();
 
     // Only MDP copybit is used
     if ((compositionType & (qdutils::COMPOSITION_TYPE_DYN |
@@ -407,20 +438,6 @@
     ctx->mExtOrientation = 0;
     ctx->numActiveDisplays = 1;
 
-    //Right now hwc starts the service but anybody could do it, or it could be
-    //independent process as well.
-    QService::init();
-    sp<IQClient> client = new QClient(ctx);
-    android::sp<qService::IQService> qservice_sp = interface_cast<IQService>(
-            defaultServiceManager()->getService(
-            String16("display.qservice")));
-    if (qservice_sp.get()) {
-      qservice_sp->connect(client);
-    } else {
-      ALOGE("%s: Failed to acquire service pointer", __FUNCTION__);
-      return ;
-    }
-
     // Initialize device orientation to its default orientation
     ctx->deviceOrientation = 0;
     ctx->mBufferMirrorMode = false;
@@ -462,6 +479,13 @@
     ctx->mHPDEnabled = false;
     ALOGI("Initializing Qualcomm Hardware Composer");
     ALOGI("MDP version: %d", ctx->mMDP.version);
+
+    return 0;
+
+OpenFBError:
+    ALOGE("%s: Fatal Error: FB Open failed!!!", __FUNCTION__);
+    delete ctx->mHDMIDisplay;
+    return error;
 }
 
 void closeContext(hwc_context_t *ctx)
@@ -514,7 +538,10 @@
         ctx->mAD = NULL;
     }
 
-
+    if(ctx->mQService) {
+        delete ctx->mQService;
+        ctx->mQService = NULL;
+    }
 }
 
 //Helper to roundoff the refreshrates
@@ -2814,7 +2841,13 @@
 void resetROI(hwc_context_t *ctx, const int dpy) {
     const int fbXRes = (int)ctx->dpyAttr[dpy].xres;
     const int fbYRes = (int)ctx->dpyAttr[dpy].yres;
-    if(isDisplaySplit(ctx, dpy)) {
+
+    /* When source split is enabled, both the panels are calibrated
+     * in a single coordinate system. So only one ROI is generated
+     * for the whole panel extending equally from the midpoint and
+     * populated for the left side. */
+    if(!qdutils::MDPVersion::getInstance().isSrcSplit() &&
+            isDisplaySplit(ctx, dpy)) {
         const int lSplit = getLeftSplit(ctx, dpy);
         ctx->listStats[dpy].lRoi = (struct hwc_rect){0, 0, lSplit, fbYRes};
         ctx->listStats[dpy].rRoi = (struct hwc_rect){lSplit, 0, fbXRes, fbYRes};
@@ -2967,7 +3000,11 @@
     // TODO: If HDMI is connected after the display has booted up,
     // and the best configuration is different from the default
     // then we need to deal with this appropriately.
-    ctx->mHDMIDisplay->configure();
+    int error = ctx->mHDMIDisplay->configure();
+    if (error < 0) {
+        ALOGE("Error opening FrameBuffer");
+        return;
+    }
     updateDisplayInfo(ctx, dpy);
     initCompositionResources(ctx, dpy);
     ctx->dpyAttr[dpy].connected = true;
diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h
index 0008551..f290dc8 100644
--- a/libhwcomposer/hwc_utils.h
+++ b/libhwcomposer/hwc_utils.h
@@ -35,6 +35,7 @@
 #include <overlayUtils.h>
 #include <overlayRotator.h>
 #include <EGL/egl.h>
+#include <QService.h>
 
 
 #define ALIGN_TO(x, align)     (((x) + ((align)-1)) & ~((align)-1))
@@ -112,12 +113,6 @@
     int mAsWidthRatio;
     int mAsHeightRatio;
 
-    //If property fbsize set via adb shell debug.hwc.fbsize = XRESxYRES
-    //following fields are used.
-    bool customFBSize;
-    uint32_t xres_new;
-    uint32_t yres_new;
-
     // This is the 3D mode to which the TV is set
     // The mode may be set via the appearance of a layer with 3D format
     // or by forcing the mode via binder.
@@ -130,6 +125,18 @@
     // HDMI_S3D_NONE
     int s3dMode;
     bool s3dModeForced;
+    //If property fbsize set via adb shell debug.hwc.fbsize = XRESxYRES
+    //following fields are used.
+    //Also used when the actual panel's dimensions change and FB remains
+    //constant
+    bool fbScaling;
+    uint32_t xresFB; //FB's width, by default from VSCREEN overridden by prop
+    uint32_t yresFB; //FB's height, by default from VSCREEN overridden by prop
+    float fbWidthScaleRatio; // Panel Width / FB Width
+    float fbHeightScaleRatio; // Panel Height / FB Height
+    //If configuration changed dynamically without subsequent GEOMETRY changes
+    //we may still need to adjust destination params
+    bool configSwitched;
 };
 
 struct ListStats {
@@ -280,7 +287,7 @@
 void dumpLayer(hwc_layer_1_t const* l);
 void setListStats(hwc_context_t *ctx, hwc_display_contents_1_t *list,
         int dpy);
-void initContext(hwc_context_t *ctx);
+int initContext(hwc_context_t *ctx);
 void closeContext(hwc_context_t *ctx);
 //Crops source buffer against destination and FB boundaries
 void calculate_crop_rects(hwc_rect_t& crop, hwc_rect_t& dst,
@@ -689,6 +696,8 @@
     bool mHPDEnabled;
     //Used to notify that boot has completed
     bool mBootAnimCompleted;
+    // Display binder service
+    qService::QService* mQService;
 };
 
 namespace qhwc {
diff --git a/libhwcomposer/hwc_vsync.cpp b/libhwcomposer/hwc_vsync.cpp
index 89f8044..1a7a836 100644
--- a/libhwcomposer/hwc_vsync.cpp
+++ b/libhwcomposer/hwc_vsync.cpp
@@ -33,6 +33,7 @@
 #include "overlay.h"
 #define __STDC_FORMAT_MACROS 1
 #include <inttypes.h>
+#define DEBUG 0
 
 using namespace qdutils;
 namespace qhwc {
@@ -56,7 +57,8 @@
     return ret;
 }
 
-static void handle_vsync_event(hwc_context_t* ctx, int dpy, char *data)
+static void handle_vsync_event(hwc_context_t* ctx, int dpy, char *data,
+        ssize_t len __unused)
 {
     // extract timestamp
     uint64_t timestamp = 0;
@@ -69,7 +71,8 @@
     ctx->proc->vsync(ctx->proc, dpy, timestamp);
 }
 
-static void handle_blank_event(hwc_context_t* ctx, int dpy, char *data)
+static void handle_blank_event(hwc_context_t* ctx, int dpy, char *data,
+        ssize_t len __unused)
 {
     if (!strncmp(data, PANEL_ON_STR, strlen(PANEL_ON_STR))) {
         unsigned long int poweron = strtoul(data + strlen(PANEL_ON_STR), NULL, 0);
@@ -80,7 +83,8 @@
     }
 }
 
-static void handle_thermal_event(hwc_context_t* ctx, int dpy, char *data)
+static void handle_thermal_event(hwc_context_t* ctx, int dpy, char *data,
+        ssize_t len __unused)
 {
     // extract thermal level
     uint64_t thermalLevel = 0;
@@ -95,15 +99,24 @@
         ctx->mThermalBurstMode = false;
 }
 
+static void handle_cec_event(hwc_context_t* ctx, int dpy, char *data,
+        ssize_t len)
+{
+    ALOGD_IF(DEBUG, "%s: Got CEC event from driver dpy:%d",
+            __FUNCTION__, dpy);
+    ctx->mQService->onCECMessageReceived(data, len);
+}
+
 struct event {
     const char* name;
-    void (*callback)(hwc_context_t* ctx, int dpy, char *data);
+    void (*callback)(hwc_context_t* ctx, int dpy, char *data, ssize_t len);
 };
 
 struct event event_list[] =  {
     { "vsync_event", handle_vsync_event },
     { "show_blank_event", handle_blank_event },
     { "msm_fb_thermal_level", handle_thermal_event },
+    { "cec/rd_msg", handle_cec_event },
 };
 
 #define num_events ARRAY_LENGTH(event_list)
@@ -185,7 +198,7 @@
                                 continue;
                             }
                             vdata[len] = '\0';
-                            event_list[ev].callback(ctx, dpy, vdata);
+                            event_list[ev].callback(ctx, dpy, vdata, len);
                         }
                     }
                 }
diff --git a/liboverlay/overlay.cpp b/liboverlay/overlay.cpp
index a34e599..b7c7fcc 100644
--- a/liboverlay/overlay.cpp
+++ b/liboverlay/overlay.cpp
@@ -151,6 +151,8 @@
         return getPipe_8x39(pipeSpecs);
     } else if(MDPVersion::getInstance().is8994()) {
         return getPipe_8994(pipeSpecs);
+    } else if(MDPVersion::getInstance().is8992()) {
+        return getPipe_8992(pipeSpecs);
     }
 
     eDest dest = OV_INVALID;
@@ -251,6 +253,13 @@
     //supported since we at least need 1 round in between where the DMA is
     //unused
     eDest dest = OV_INVALID;
+
+    // Reset format type to FORMAT_NONE to select the pipe irrespective of the
+    // format specifed by the client. This is required for the device where
+    // SMP starvation is unlikely, we need not keep track of formats
+    // programmed in the pipes to avoid potential pipe crunching.
+    resetPipeBookFormat(pipeSpecs.dpy);
+
     if(pipeSpecs.formatClass == FORMAT_YUV) {
         return nextPipe(OV_MDP_PIPE_VG, pipeSpecs);
     } else {
@@ -262,9 +271,14 @@
             dest = nextPipe(OV_MDP_PIPE_DMA, pipeSpecs);
         }
     }
+
     return dest;
 }
 
+utils::eDest Overlay::getPipe_8992(const PipeSpecs& pipeSpecs) {
+    return getPipe_8994(pipeSpecs);
+}
+
 void Overlay::endAllSessions() {
     for(int i = 0; i < PipeBook::NUM_PIPES; i++) {
         if(mPipeBook[i].valid() && mPipeBook[i].mSession==PipeBook::START)
diff --git a/liboverlay/overlay.h b/liboverlay/overlay.h
index 45b5e57..49be930 100644
--- a/liboverlay/overlay.h
+++ b/liboverlay/overlay.h
@@ -178,6 +178,9 @@
     utils::eDest getPipe_8x16(const PipeSpecs& pipeSpecs);
     utils::eDest getPipe_8x39(const PipeSpecs& pipeSpecs);
     utils::eDest getPipe_8994(const PipeSpecs& pipeSpecs);
+    utils::eDest getPipe_8992(const PipeSpecs& pipeSpecs);
+
+    void resetPipeBookFormat(const int &dpy);
 
     /* Returns the handle to libscale.so's programScale function */
     static int (*getFnProgramScale())(struct mdp_overlay_list *);
@@ -443,6 +446,14 @@
     return "Invalid";
 }
 
+inline void Overlay::resetPipeBookFormat(const int &dpy) {
+    for(int i = 0; i < PipeBook::NUM_PIPES; i++) {
+        if (mPipeBook[i].mDisplay == dpy) {
+            mPipeBook[i].mFormatType = FORMAT_NONE;
+        }
+    }
+}
+
 }; // overlay
 
 #endif // OVERLAY_H
diff --git a/liboverlay/overlayMdp.cpp b/liboverlay/overlayMdp.cpp
index 1290f32..0c31dd3 100644
--- a/liboverlay/overlayMdp.cpp
+++ b/liboverlay/overlayMdp.cpp
@@ -353,8 +353,31 @@
     mdp_overlay* ovArray[count];
     memset(&ovArray, 0, sizeof(ovArray));
 
+    uint8_t max_horz_deci = 0, max_vert_deci = 0;
+
+    // Decimation factor for the left and right pipe differs, when there is a
+    // one pixel difference in the dst width of right pipe and the left pipe.
+    // libscalar returns a failure as it expects decimation on both the pipe
+    // to be same. So compare the decimation factor on both the pipes and assign
+    // the maximum of it.
     for(int i = 0; i < count; i++) {
-        ovArray[i] = &mdpCtrlArray[i]->mOVInfo;
+        mdp_overlay *ov_current = &mdpCtrlArray[i]->mOVInfo;
+        for(int j = i + 1; j < count; j++) {
+            mdp_overlay *ov_next = &mdpCtrlArray[j]->mOVInfo;
+            if(ov_current->z_order == ov_next->z_order) {
+                max_horz_deci = utils::max(ov_current->horz_deci,
+                                           ov_next->horz_deci);
+                max_vert_deci = utils::max(ov_current->vert_deci,
+                                           ov_next->vert_deci);
+
+                ov_current->horz_deci = max_horz_deci;
+                ov_next->horz_deci = max_horz_deci;
+                ov_current->vert_deci = max_vert_deci;
+                ov_next->vert_deci = max_vert_deci;
+                break;
+            }
+        }
+        ovArray[i] = ov_current;
     }
 
     struct mdp_overlay_list list;
diff --git a/liboverlay/overlayMem.h b/liboverlay/overlayMem.h
index f0a1922..abdd402 100644
--- a/liboverlay/overlayMem.h
+++ b/liboverlay/overlayMem.h
@@ -121,7 +121,7 @@
         uint32_t bufSz, bool isSecure)
 {
     alloc_data data;
-    int allocFlags = GRALLOC_USAGE_PRIVATE_IOMMU_HEAP;
+    int allocFlags = 0;
     int err = 0;
     OVASSERT(numbufs && bufSz, "numbufs=%d bufSz=%d", numbufs, bufSz);
     mBufSz = bufSz;
diff --git a/libqdutils/display_config.cpp b/libqdutils/display_config.cpp
index 03a7046..40b1ef7 100644
--- a/libqdutils/display_config.cpp
+++ b/libqdutils/display_config.cpp
@@ -27,14 +27,24 @@
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
 #include <display_config.h>
 #include <QServiceUtils.h>
+#include <qd_utils.h>
 
 using namespace android;
 using namespace qService;
 
 namespace qdutils {
 
+//=============================================================================
+// The functions below run in the client process and wherever necessary
+// do a binder call to HWC to get/set data.
+
 int isExternalConnected(void) {
     int ret;
     status_t err = (status_t) FAILED_TRANSACTION;
@@ -70,7 +80,7 @@
         dpyattr.ydpi = outParcel.readFloat();
         dpyattr.panel_type = (char) outParcel.readInt32();
     } else {
-        ALOGE("%s: Failed to get display attributes err=%d", __FUNCTION__, err);
+        ALOGE("%s() failed with err %d", __FUNCTION__, err);
     }
     return err;
 }
@@ -170,6 +180,238 @@
     return err;
 }
 
+int getConfigCount(int /*dpy*/) {
+    int numConfigs = -1;
+    sp<IQService> binder = getBinder();
+    if(binder != NULL) {
+        Parcel inParcel, outParcel;
+        inParcel.writeInt32(DISPLAY_PRIMARY);
+        status_t err = binder->dispatch(IQService::GET_CONFIG_COUNT,
+                &inParcel, &outParcel);
+        if(!err) {
+            numConfigs = outParcel.readInt32();
+            ALOGI("%s() Received num configs %d", __FUNCTION__, numConfigs);
+        } else {
+            ALOGE("%s() failed with err %d", __FUNCTION__, err);
+        }
+    }
+    return numConfigs;
+}
+
+int getActiveConfig(int /*dpy*/) {
+    int configIndex = -1;
+    sp<IQService> binder = getBinder();
+    if(binder != NULL) {
+        Parcel inParcel, outParcel;
+        inParcel.writeInt32(DISPLAY_PRIMARY);
+        status_t err = binder->dispatch(IQService::GET_ACTIVE_CONFIG,
+                &inParcel, &outParcel);
+        if(!err) {
+            configIndex = outParcel.readInt32();
+            ALOGI("%s() Received active config index %d", __FUNCTION__,
+                    configIndex);
+        } else {
+            ALOGE("%s() failed with err %d", __FUNCTION__, err);
+        }
+    }
+    return configIndex;
+}
+
+int setActiveConfig(int configIndex, int /*dpy*/) {
+    status_t err = (status_t) FAILED_TRANSACTION;
+    sp<IQService> binder = getBinder();
+    if(binder != NULL) {
+        Parcel inParcel, outParcel;
+        inParcel.writeInt32(configIndex);
+        inParcel.writeInt32(DISPLAY_PRIMARY);
+        err = binder->dispatch(IQService::SET_ACTIVE_CONFIG,
+                &inParcel, &outParcel);
+        if(!err) {
+            ALOGI("%s() Successfully set active config index %d", __FUNCTION__,
+                    configIndex);
+        } else {
+            ALOGE("%s() failed with err %d", __FUNCTION__, err);
+        }
+    }
+    return err;
+}
+
+DisplayAttributes getDisplayAttributes(int configIndex, int /*dpy*/) {
+    DisplayAttributes dpyattr;
+    sp<IQService> binder = getBinder();
+    if(binder != NULL) {
+        Parcel inParcel, outParcel;
+        inParcel.writeInt32(configIndex);
+        inParcel.writeInt32(DISPLAY_PRIMARY);
+        status_t err = binder->dispatch(
+                IQService::GET_DISPLAY_ATTRIBUTES_FOR_CONFIG, &inParcel,
+                &outParcel);
+        if(!err) {
+            dpyattr.vsync_period = outParcel.readInt32();
+            dpyattr.xres = outParcel.readInt32();
+            dpyattr.yres = outParcel.readInt32();
+            dpyattr.xdpi = outParcel.readFloat();
+            dpyattr.ydpi = outParcel.readFloat();
+            dpyattr.panel_type = (char) outParcel.readInt32();
+            ALOGI("%s() Received attrs for index %d: xres %d, yres %d",
+                    __FUNCTION__, configIndex, dpyattr.xres, dpyattr.yres);
+        } else {
+            ALOGE("%s() failed with err %d", __FUNCTION__, err);
+        }
+    }
+    return dpyattr;
+}
+
+//=============================================================================
+// The functions/methods below run in the context of HWC and
+// are called in response to binder calls from clients
+
+Configs* Configs::getInstance() {
+    if(sConfigs == NULL) {
+        sConfigs = new Configs();
+        if(sConfigs->init() == false) {
+            ALOGE("%s(): Configs initialization failed", __FUNCTION__);
+            delete sConfigs;
+            sConfigs = NULL;
+        }
+    }
+    return sConfigs;
+}
+
+Configs::Configs() : mActiveConfig(0), mConfigsSupported(0) {}
+
+bool Configs::init() {
+    DisplayAttributes dpyAttr;
+    if(not getCurrentMode(dpyAttr)) {
+        ALOGE("%s(): Mode switch is disabled", __FUNCTION__);
+        return false;
+    }
+
+    FILE *fHnd;
+    size_t len = PAGE_SIZE;
+    ssize_t read = 0;
+    uint32_t configCount = 0;
+    char sysfsPath[MAX_SYSFS_FILE_PATH];
+
+    memset(sysfsPath, '\0', sizeof(sysfsPath));
+    snprintf(sysfsPath , sizeof(sysfsPath),
+            "/sys/class/graphics/fb0/modes");
+
+    fHnd = fopen(sysfsPath, "r");
+    if (fHnd == NULL) {
+        ALOGE("%s(): Opening file %s failed with error %s", __FUNCTION__,
+                sysfsPath, strerror(errno));
+        return false;
+    }
+
+    memset(mModeStr, 0, sizeof(mModeStr));
+    while((configCount < CONFIGS_MAX) and
+            ((read = getline(&mModeStr[configCount], &len, fHnd)) > 0)) {
+        //String is of form "U:1600x2560p-0". Documentation/fb/modedb.txt in the
+        //kernel has more info on the format.
+        char *xptr = strcasestr(mModeStr[configCount], ":");
+        char *yptr = strcasestr(mModeStr[configCount], "x");
+        if(xptr && yptr) {
+            mConfigs[configCount].xres = atoi(xptr + 1);
+            mConfigs[configCount].yres = atoi(yptr + 1);
+            ALOGI("%s(): Parsed Config %s", __FUNCTION__,
+                    mModeStr[configCount]);
+            ALOGI("%s(): Config %u: %u x %u", __FUNCTION__, configCount,
+                    mConfigs[configCount].xres, mConfigs[configCount].yres);
+            if(mConfigs[configCount].xres == dpyAttr.xres and
+                    mConfigs[configCount].yres == dpyAttr.yres) {
+                mActiveConfig = configCount;
+            }
+        } else {
+            ALOGE("%s(): Tokenizing str %s failed", __FUNCTION__,
+                    mModeStr[configCount]);
+            //Free memory allocated internally by getline()
+            for(uint32_t i = 0; i <= configCount; i++) {
+                free(mModeStr[i]);
+            }
+            fclose(fHnd);
+            return false;
+        }
+        configCount++;
+    }
+
+    fclose(fHnd);
+
+    if(configCount == 0) {
+        ALOGE("%s No configs found", __FUNCTION__);
+        return false;
+    }
+    mConfigsSupported = configCount;
+    return true;
+}
+
+bool Configs::getCurrentMode(DisplayAttributes& dpyAttr) {
+    bool ret = false;
+    FILE *fHnd = fopen("/sys/class/graphics/fb0/mode", "r");
+    if(fHnd) {
+        char *buffer = NULL; //getline will allocate
+        size_t len = PAGE_SIZE;
+        if(getline(&buffer, &len, fHnd) > 0) {
+            //String is of form "U:1600x2560p-0". Documentation/fb/modedb.txt in
+            //kernel has more info on the format.
+            char *xptr = strcasestr(buffer, ":");
+            char *yptr = strcasestr(buffer, "x");
+            if(xptr && yptr) {
+                dpyAttr.xres = atoi(xptr + 1);
+                dpyAttr.yres = atoi(yptr + 1);
+                ALOGI("%s(): Parsed Current Config Str %s", __FUNCTION__,
+                        buffer);
+                ALOGI("%s(): Current Config: %u x %u", __FUNCTION__,
+                        dpyAttr.xres, dpyAttr.yres);
+                ret = true;
+            }
+        }
+
+        if(buffer)
+            free(buffer);
+
+        fclose(fHnd);
+    }
+    return ret;
+}
+
+bool Configs::setActiveConfig(const uint32_t& index) {
+    if(index >= mConfigsSupported) {
+        ALOGE("%s(): Invalid Index %u", __FUNCTION__, index);
+        return false;
+    }
+
+    bool ret = true;
+    int fd = -1;
+    size_t len = PAGE_SIZE;
+    char sysfsPath[MAX_SYSFS_FILE_PATH];
+    memset(sysfsPath, '\0', sizeof(sysfsPath));
+    snprintf(sysfsPath , sizeof(sysfsPath),
+            "/sys/class/graphics/fb0/mode");
+
+    fd = open(sysfsPath, O_WRONLY);
+    if (fd < 0) {
+        ALOGE("%s(): Opening file %s failed", __FUNCTION__, sysfsPath);
+        return false;
+    }
+
+    ssize_t written = pwrite(fd, mModeStr[index], strlen(mModeStr[index]), 0);
+    if(written <= 0) {
+        ALOGE("%s(): Writing config %s to %s failed with error: %s",
+                __FUNCTION__, mModeStr[index], sysfsPath, strerror(errno));
+        close(fd);
+        return false;
+    }
+
+    ALOGI("%s(): Successfully set config %u", __FUNCTION__, index);
+    mActiveConfig = index;
+    MDPVersion::getInstance().updateSplitInfo();
+    close(fd);
+    return true;
+}
+
+Configs* Configs::sConfigs = NULL;
+
 }; //namespace
 
 // ----------------------------------------------------------------------------
diff --git a/libqdutils/display_config.h b/libqdutils/display_config.h
index 8bafe91..6a66e9f 100644
--- a/libqdutils/display_config.h
+++ b/libqdutils/display_config.h
@@ -31,11 +31,8 @@
 #include <mdp_version.h>
 #include <hardware/hwcomposer.h>
 
-// This header is for clients to use to set/get global display configuration
-// The functions in this header run in the client process and wherever necessary
-// do a binder call to HWC to get/set data.
+// This header is for clients to use to set/get global display configuration.
 // Only primary and external displays are supported here.
-// WiFi/virtual displays are not supported.
 
 namespace qdutils {
 
@@ -69,14 +66,20 @@
 
 // Display Attributes that are available to clients of this library
 // Not to be confused with a similar struct in hwc_utils (in the hwc namespace)
-struct DisplayAttributes_t {
+typedef struct DisplayAttributes {
     uint32_t vsync_period; //nanoseconds
     uint32_t xres;
     uint32_t yres;
     float xdpi;
     float ydpi;
     char panel_type;
-};
+    DisplayAttributes() : vsync_period(0), xres(0), yres(0), xdpi(0.0f),
+            ydpi(0.0f), panel_type(0) {}
+} DisplayAttributes_t;
+
+//=============================================================================
+// The functions below run in the client process and wherever necessary
+// do a binder call to HWC to get/set data.
 
 // Check if external display is connected. Useful to check before making
 // calls for external displays
@@ -104,4 +107,66 @@
 
 // Enable/Disable/Set refresh rate dynamically
 int configureDynRefreshRate(uint32_t op, uint32_t refreshRate);
+
+// Returns the number of configs supported for the display on success.
+// Returns -1 on error.
+// Only primary display supported for now, value of dpy ignored.
+int getConfigCount(int dpy);
+
+// Returns the index of config that is current set for the display on success.
+// Returns -1 on error.
+// Only primary display supported for now, value of dpy ignored.
+int getActiveConfig(int dpy);
+
+// Sets the config for the display on success and returns 0.
+// Returns -1 on error.
+// Only primary display supported for now, value of dpy ignored
+int setActiveConfig(int configIndex, int dpy);
+
+// Returns the attributes for the specified config for the display on success.
+// Returns xres and yres as 0 on error.
+// Only primary display supported for now, value of dpy ignored
+DisplayAttributes getDisplayAttributes(int configIndex, int dpy);
+
+//=============================================================================
+// The functions and methods below run in the context of HWC and
+// are called in response to binder calls from clients
+
+class Configs {
+public:
+    DisplayAttributes getAttributes(const uint32_t& index) const;
+    uint32_t getActiveConfig() const;
+    bool setActiveConfig(const uint32_t& index);
+    uint32_t getConfigCount() const;
+    static Configs *getInstance();
+private:
+    enum { CONFIGS_MAX = 32 };
+    Configs();
+    bool init();
+    bool getCurrentMode(DisplayAttributes& dpyAttr);
+    DisplayAttributes mConfigs[CONFIGS_MAX];
+    char *mModeStr[CONFIGS_MAX];
+    uint32_t mActiveConfig;
+    uint32_t mConfigsSupported;
+    static Configs *sConfigs;
+};
+
+inline DisplayAttributes Configs::getAttributes(const uint32_t& index) const {
+    if(index >= mConfigsSupported) {
+        ALOGE("%s() Invalid index %d, max %d", __FUNCTION__, index,
+                mConfigsSupported);
+        return DisplayAttributes(); //All 0s
+    }
+    return mConfigs[index];
+}
+
+// Retuns the current config index, -1 if called without a setActiveConfig
+inline uint32_t Configs::getActiveConfig() const {
+    return mActiveConfig;
+}
+
+inline uint32_t Configs::getConfigCount() const {
+    return mConfigsSupported;
+}
+
 }; //namespace
diff --git a/libqdutils/mdp_version.cpp b/libqdutils/mdp_version.cpp
index 402e129..e045918 100644
--- a/libqdutils/mdp_version.cpp
+++ b/libqdutils/mdp_version.cpp
@@ -501,6 +501,10 @@
             mMdpRev < MDSS_MDP_HW_REV_109);
 }
 
+bool MDPVersion::is8992() {
+    return ((mMdpRev >= MDSS_MDP_HW_REV_110 and
+            mMdpRev < MDSS_MDP_HW_REV_200));
+}
 
 }; //namespace qdutils
 
diff --git a/libqdutils/mdp_version.h b/libqdutils/mdp_version.h
index 3b10010..ad92c83 100644
--- a/libqdutils/mdp_version.h
+++ b/libqdutils/mdp_version.h
@@ -151,11 +151,12 @@
     bool is8994();
     bool is8x16();
     bool is8x39();
+    bool is8992();
+    bool updateSplitInfo();
 
 private:
     bool updateSysFsInfo();
     void updatePanelInfo();
-    bool updateSplitInfo();
     int tokenizeParams(char *inputParams, const char *delim,
                         char* tokenStr[], int *idx);
     int mFd;
diff --git a/libqservice/Android.mk b/libqservice/Android.mk
index 78b1d77..287e6ce 100644
--- a/libqservice/Android.mk
+++ b/libqservice/Android.mk
@@ -10,7 +10,8 @@
 LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps)
 LOCAL_SRC_FILES               := QService.cpp \
                                  IQService.cpp \
-                                 IQClient.cpp
+                                 IQClient.cpp \
+                                 IQHDMIClient.cpp
 LOCAL_COPY_HEADERS_TO         := $(common_header_export_path)
 LOCAL_COPY_HEADERS            := IQService.h \
                                  IQClient.h
diff --git a/libqservice/IQHDMIClient.cpp b/libqservice/IQHDMIClient.cpp
new file mode 100644
index 0000000..9f5044a
--- /dev/null
+++ b/libqservice/IQHDMIClient.cpp
@@ -0,0 +1,103 @@
+/*
+* Copyright (c) 2014 The Linux Foundation. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+*    * Redistributions of source code must retain the above copyright
+*      notice, this list of conditions and the following disclaimer.
+*    * Redistributions in binary form must reproduce the above
+*      copyright notice, this list of conditions and the following
+*      disclaimer in the documentation and/or other materials provided
+*      with the distribution.
+*    * Neither the name of The Linux Foundation. nor the names of its
+*      contributors may be used to endorse or promote products derived
+*      from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <utils/Log.h>
+#include <binder/Parcel.h>
+#include "IQHDMIClient.h"
+
+using namespace android;
+namespace qClient {
+
+enum {
+    HDMI_CONNECTED = IBinder::FIRST_CALL_TRANSACTION,
+    CEC_MESSAGE_RECEIVED
+};
+
+class BpQHDMIClient : public BpInterface<IQHDMIClient>
+{
+public:
+    BpQHDMIClient(const sp<IBinder>& impl)
+            :BpInterface<IQHDMIClient>(impl)
+    {
+    }
+
+    void onHdmiHotplug(int connected)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IQHDMIClient::getInterfaceDescriptor());
+        data.writeInt32(connected);
+        remote()->transact(HDMI_CONNECTED, data, &reply, IBinder::FLAG_ONEWAY);
+    }
+
+    void onCECMessageRecieved(char *msg, ssize_t len)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IQHDMIClient::getInterfaceDescriptor());
+        data.writeInt32((int32_t)len);
+        void *buf = data.writeInplace(len);
+        if (buf != NULL)
+            memcpy(buf, msg, len);
+        remote()->transact(CEC_MESSAGE_RECEIVED, data, &reply,
+                IBinder::FLAG_ONEWAY);
+    }
+};
+
+IMPLEMENT_META_INTERFACE(QHDMIClient,
+        "android.display.IQHDMIClient");
+
+status_t BnQHDMIClient::onTransact(uint32_t code, const Parcel& data,
+        Parcel* reply, uint32_t flags)
+{
+    switch(code) {
+        case HDMI_CONNECTED: {
+            CHECK_INTERFACE(IQHDMIClient, data, reply);
+            int connected = data.readInt32();
+            onHdmiHotplug(connected);
+            return NO_ERROR;
+        }
+        case CEC_MESSAGE_RECEIVED: {
+            CHECK_INTERFACE(IQHDMIClient, data, reply);
+            ssize_t len = data.readInt32();
+            const void* msg;
+            if(len >= 0 && len <= (ssize_t) data.dataAvail()) {
+                msg = data.readInplace(len);
+            } else {
+                msg = NULL;
+                len = 0;
+            }
+            if (msg != NULL)
+                onCECMessageRecieved((char*) msg, len);
+            return NO_ERROR;
+        }
+        default: {
+            return BBinder::onTransact(code, data, reply, flags);
+        }
+    }
+}
+
+}; //namespace qClient
diff --git a/libqservice/IQHDMIClient.h b/libqservice/IQHDMIClient.h
new file mode 100644
index 0000000..c3d012a
--- /dev/null
+++ b/libqservice/IQHDMIClient.h
@@ -0,0 +1,57 @@
+/*
+* Copyright (c) 2014 The Linux Foundation. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+*    * Redistributions of source code must retain the above copyright
+*      notice, this list of conditions and the following disclaimer.
+*    * Redistributions in binary form must reproduce the above
+*      copyright notice, this list of conditions and the following
+*      disclaimer in the documentation and/or other materials provided
+*      with the distribution.
+*    * Neither the name of The Linux Foundation. nor the names of its
+*      contributors may be used to endorse or promote products derived
+*      from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef HDMI_EVENTS_LISTENER_H_
+#define HDMI_EVENTS_LISTENER_H_
+
+#include <utils/RefBase.h>
+#include <binder/IInterface.h>
+
+namespace qClient {
+
+class IQHDMIClient : public android::IInterface
+{
+public:
+    DECLARE_META_INTERFACE(QHDMIClient);
+    virtual void onHdmiHotplug(int connected) = 0;
+    virtual void onCECMessageRecieved(char *msg, ssize_t len) = 0;
+};
+
+class BnQHDMIClient : public android::BnInterface<IQHDMIClient>
+{
+public:
+    virtual android::status_t onTransact( uint32_t code,
+            const android::Parcel& data,
+            android::Parcel* reply, uint32_t flags = 0);
+};
+
+}; //namespace qhdmi
+
+#endif // HDMI_EVENTS_LISTENER_H_
+
diff --git a/libqservice/IQService.cpp b/libqservice/IQService.cpp
index eee22f0..5e67b15 100644
--- a/libqservice/IQService.cpp
+++ b/libqservice/IQService.cpp
@@ -45,13 +45,22 @@
         : BpInterface<IQService>(impl) {}
 
     virtual void connect(const sp<IQClient>& client) {
-        ALOGD_IF(QSERVICE_DEBUG, "%s: connect client", __FUNCTION__);
+        ALOGD_IF(QSERVICE_DEBUG, "%s: connect HWC client", __FUNCTION__);
         Parcel data, reply;
         data.writeInterfaceToken(IQService::getInterfaceDescriptor());
         data.writeStrongBinder(client->asBinder());
-        remote()->transact(CONNECT, data, &reply);
+        remote()->transact(CONNECT_HWC_CLIENT, data, &reply);
     }
 
+    virtual void connect(const sp<IQHDMIClient>& client) {
+        ALOGD_IF(QSERVICE_DEBUG, "%s: connect HDMI client", __FUNCTION__);
+        Parcel data, reply;
+        data.writeInterfaceToken(IQService::getInterfaceDescriptor());
+        data.writeStrongBinder(client->asBinder());
+        remote()->transact(CONNECT_HDMI_CLIENT, data, &reply);
+    }
+
+
     virtual android::status_t dispatch(uint32_t command, const Parcel* inParcel,
             Parcel* outParcel) {
         ALOGD_IF(QSERVICE_DEBUG, "%s: dispatch in:%p", __FUNCTION__, inParcel);
@@ -90,10 +99,10 @@
             callerUid == AID_ROOT ||
             callerUid == AID_SYSTEM);
 
-    if (code == CONNECT) {
+    if (code == CONNECT_HWC_CLIENT) {
         CHECK_INTERFACE(IQService, data, reply);
         if(callerUid != AID_GRAPHICS) {
-            ALOGE("display.qservice CONNECT access denied: \
+            ALOGE("display.qservice CONNECT_HWC_CLIENT access denied: \
                     pid=%d uid=%d process=%s",
                     callerPid, callerUid, callingProcName);
             return PERMISSION_DENIED;
@@ -102,6 +111,18 @@
                 interface_cast<IQClient>(data.readStrongBinder());
         connect(client);
         return NO_ERROR;
+    } else if(code == CONNECT_HDMI_CLIENT) {
+        CHECK_INTERFACE(IQService, data, reply);
+        if(callerUid != AID_SYSTEM && callerUid != AID_ROOT) {
+            ALOGE("display.qservice CONNECT_HDMI_CLIENT access denied: \
+                    pid=%d uid=%d process=%s",
+                    callerPid, callerUid, callingProcName);
+            return PERMISSION_DENIED;
+        }
+        sp<IQHDMIClient> client =
+                interface_cast<IQHDMIClient>(data.readStrongBinder());
+        connect(client);
+        return NO_ERROR;
     } else if (code > COMMAND_LIST_START && code < COMMAND_LIST_END) {
         if(!permission) {
             ALOGE("display.qservice access denied: command=%d\
diff --git a/libqservice/IQService.h b/libqservice/IQService.h
index 796e506..932d670 100644
--- a/libqservice/IQService.h
+++ b/libqservice/IQService.h
@@ -28,6 +28,7 @@
 #include <binder/IInterface.h>
 #include <binder/IBinder.h>
 #include <IQClient.h>
+#include <IQHDMIClient.h>
 
 
 namespace qService {
@@ -41,7 +42,7 @@
         COMMAND_LIST_START = android::IBinder::FIRST_CALL_TRANSACTION,
         SECURING = 2,           // Hardware securing start/end notification
         UNSECURING = 3,         // Hardware unsecuring start/end notification
-        CONNECT = 4,            // Connect to qservice
+        CONNECT_HWC_CLIENT = 4, // Connect to qservice
         SCREEN_REFRESH = 5,     // Refresh screen through SF invalidate
         EXTERNAL_ORIENTATION = 6,// Set external orientation
         BUFFER_MIRRORMODE = 7,  // Buffer mirrormode
@@ -61,6 +62,11 @@
         TOGGLE_SCREEN_UPDATE = 20, // Provides ability to disable screen updates
         SET_FRAME_DUMP_CONFIG = 21,  // Provides ability to set the frame dump config
         SET_S3D_MODE = 22, // Set the 3D mode as specified in msm_hdmi_modes.h
+        CONNECT_HDMI_CLIENT = 23,  // Connect HDMI CEC HAL Client
+        SET_ACTIVE_CONFIG = 25, //Set a specified display config
+        GET_ACTIVE_CONFIG = 26, //Get the current config index
+        GET_CONFIG_COUNT = 27, //Get the number of supported display configs
+        GET_DISPLAY_ATTRIBUTES_FOR_CONFIG = 28, //Get attr for specified config
         COMMAND_LIST_END = 400,
     };
 
@@ -80,13 +86,24 @@
     };
 
     enum {
+        PREF_PARTIAL_UPDATE,
+        PREF_POST_PROCESSING,
+        ENABLE_PARTIAL_UPDATE,
+    };
+
+    enum {
         DUMP_PRIMARY_DISPLAY,
         DUMP_HDMI_DISPLAY,
         DUMP_VIRTUAL_DISPLAY,
     };
 
-    // Register a client that can be notified
+    // Register a HWC client that can be notified
+    // This client is generic and is intended to get
+    // dispatches of all events calling into QService
     virtual void connect(const android::sp<qClient::IQClient>& client) = 0;
+    // Register an HDMI client. This client gets notification of HDMI events
+    // such as plug/unplug and CEC messages
+    virtual void connect(const android::sp<qClient::IQHDMIClient>& client) = 0;
     // Generic function to dispatch binder commands
     // The type of command decides how the data is parceled
     virtual android::status_t dispatch(uint32_t command,
diff --git a/libqservice/QService.cpp b/libqservice/QService.cpp
index 12dd995..ddb4b18 100644
--- a/libqservice/QService.cpp
+++ b/libqservice/QService.cpp
@@ -50,24 +50,52 @@
 }
 
 void QService::connect(const sp<qClient::IQClient>& client) {
-    ALOGD_IF(QSERVICE_DEBUG,"client connected");
+    ALOGD_IF(QSERVICE_DEBUG,"HWC client connected");
     mClient = client;
 }
 
+void QService::connect(const sp<qClient::IQHDMIClient>& client) {
+    ALOGD_IF(QSERVICE_DEBUG,"HWC client connected");
+    mHDMIClient = client;
+}
+
 status_t QService::dispatch(uint32_t command, const Parcel* inParcel,
         Parcel* outParcel) {
     status_t err = (status_t) FAILED_TRANSACTION;
     IPCThreadState* ipc = IPCThreadState::self();
     //Rewind parcel in case we're calling from the same process
-    if (ipc->getCallingPid() == getpid())
+    bool sameProcess = (ipc->getCallingPid() == getpid());
+    if(sameProcess)
         inParcel->setDataPosition(0);
     if (mClient.get()) {
         ALOGD_IF(QSERVICE_DEBUG, "Dispatching command: %d", command);
         err = mClient->notifyCallback(command, inParcel, outParcel);
+        //Rewind parcel in case we're calling from the same process
+        if (sameProcess)
+            outParcel->setDataPosition(0);
     }
     return err;
 }
 
+void QService::onHdmiHotplug(int connected) {
+    if(mHDMIClient.get()) {
+        ALOGD_IF(QSERVICE_DEBUG, "%s: HDMI hotplug", __FUNCTION__);
+        mHDMIClient->onHdmiHotplug(connected);
+    } else {
+        ALOGE("%s: Failed to get a valid HDMI client", __FUNCTION__);
+    }
+}
+
+void QService::onCECMessageReceived(char *msg, ssize_t len) {
+    if(mHDMIClient.get()) {
+        ALOGD_IF(QSERVICE_DEBUG, "%s: CEC message received", __FUNCTION__);
+        mHDMIClient->onCECMessageRecieved(msg, len);
+    } else {
+        ALOGE("%s: Failed to get a valid HDMI client", __FUNCTION__);
+    }
+}
+
+
 void QService::init()
 {
     if(!sQService) {
diff --git a/libqservice/QService.h b/libqservice/QService.h
index a8e4cdb..719c9b7 100644
--- a/libqservice/QService.h
+++ b/libqservice/QService.h
@@ -46,13 +46,17 @@
 public:
     virtual ~QService();
     virtual void connect(const android::sp<qClient::IQClient>& client);
+    virtual void connect(const android::sp<qClient::IQHDMIClient>& client);
     virtual android::status_t dispatch(uint32_t command,
             const android::Parcel* data,
             android::Parcel* reply);
+    void onHdmiHotplug(int connected);
+    void onCECMessageReceived(char *msg, ssize_t len);
     static void init();
 private:
     QService();
     android::sp<qClient::IQClient> mClient;
+    android::sp<qClient::IQHDMIClient> mHDMIClient;
     static QService *sQService;
 };
 }; // namespace qService