Merge "gralloc: Allocate cached by default, don't use bitops on SW flags"
diff --git a/displayengine/include/core/display_interface.h b/displayengine/include/core/display_interface.h
index dfe161b..97f7911 100755
--- a/displayengine/include/core/display_interface.h
+++ b/displayengine/include/core/display_interface.h
@@ -235,12 +235,20 @@
 
   /*! @brief Method to get configuration for variable properties of the display device.
 
-    @param[in] mode index of the mode
+    @param[in] index index of the mode
     @param[out] variable_info \link DisplayConfigVariableInfo \endlink
 
     @return \link DisplayError \endlink
   */
-  virtual DisplayError GetConfig(DisplayConfigVariableInfo *variable_info, uint32_t mode) = 0;
+  virtual DisplayError GetConfig(uint32_t index, DisplayConfigVariableInfo *variable_info) = 0;
+
+  /*! @brief Method to get index of active configuration of the display device.
+
+    @param[out] index index of the mode corresponding to variable properties.
+
+    @return \link DisplayError \endlink
+  */
+  virtual DisplayError GetActiveConfig(uint32_t *index) = 0;
 
   /*! @brief Method to get VSync event state. Default event state is disabled.
 
@@ -260,13 +268,13 @@
   */
   virtual DisplayError SetDisplayState(DisplayState state) = 0;
 
-  /*! @brief Method to set configuration for variable properties of the display device.
+  /*! @brief Method to set active configuration for variable properties of the display device.
 
-    @param[in] mode index of the mode corresponding to variable properties.
+    @param[in] index index of the mode corresponding to variable properties.
 
     @return \link DisplayError \endlink
   */
-  virtual DisplayError SetConfig(uint32_t mode) = 0;
+  virtual DisplayError SetActiveConfig(uint32_t index) = 0;
 
   /*! @brief Method to set VSync event state. Default event state is disabled.
 
diff --git a/displayengine/include/core/layer_stack.h b/displayengine/include/core/layer_stack.h
index aa15753..6cae11a 100755
--- a/displayengine/include/core/layer_stack.h
+++ b/displayengine/include/core/layer_stack.h
@@ -217,7 +217,13 @@
   uint32_t layer_count;   //!< Total number of layers.
   LayerStackFlags flags;  //!< Flags associated with this layer set.
 
-  LayerStack() : output_buffer(NULL), layers(NULL), layer_count(0) { }
+  explicit LayerStack(bool need_retire_fence) : layers(NULL), layer_count(0) {
+    if (need_retire_fence) {
+      retire_fence_fd = -1;
+    } else {
+      output_buffer = NULL;
+    }
+  }
 };
 
 }  // namespace sde
diff --git a/displayengine/include/utils/constants.h b/displayengine/include/utils/constants.h
index 44b6896..a0f2bfb 100644
--- a/displayengine/include/utils/constants.h
+++ b/displayengine/include/utils/constants.h
@@ -30,6 +30,7 @@
 
 #define INT(exp) static_cast<int>(exp)
 #define FLOAT(exp) static_cast<float>(exp)
+#define UINT8(exp) static_cast<uint8_t>(exp)
 #define UINT32(exp) static_cast<uint32_t>(exp)
 #define INT32(exp) static_cast<int32_t>(exp)
 
@@ -46,6 +47,7 @@
 #define SET_BIT(value, bit) (value |= (1 << (bit)))
 #define CLEAR_BIT(value, bit) (value &= (~(1 << (bit))))
 #define IS_BIT_SET(value, bit) (value & (1 << (bit)))
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
 
 namespace sde {
 
diff --git a/displayengine/libs/core/comp_manager.cpp b/displayengine/libs/core/comp_manager.cpp
old mode 100755
new mode 100644
index 916d558..e7c52fc
--- a/displayengine/libs/core/comp_manager.cpp
+++ b/displayengine/libs/core/comp_manager.cpp
@@ -140,6 +140,11 @@
   StrategyConstraints *constraints = &display_comp_ctx->constraints;
 
   constraints->safe_mode = safe_mode_;
+
+  // TODO(user): Need to enable SDE Comp on HDMI
+  if (display_comp_ctx->display_type == kHDMI) {
+    constraints->max_layers = 1;
+  }
   // If validation for the best available composition strategy with driver has failed, just
   // fallback to safe mode composition e.g. GPU or video only.
   if (UNLIKELY(hw_layers->info.flags)) {
diff --git a/displayengine/libs/core/display_base.cpp b/displayengine/libs/core/display_base.cpp
old mode 100755
new mode 100644
index 6099231..aaa7990
--- a/displayengine/libs/core/display_base.cpp
+++ b/displayengine/libs/core/display_base.cpp
@@ -45,12 +45,12 @@
   DisplayError error = kErrorNone;
 
   error = hw_intf_->Open(hw_device_type_, &hw_device_, this);
-  if (UNLIKELY(error != kErrorNone)) {
+  if (error != kErrorNone) {
     return error;
   }
 
   error = hw_intf_->GetNumDisplayAttributes(hw_device_, &num_modes_);
-  if (UNLIKELY(error != kErrorNone)) {
+  if (error != kErrorNone) {
     goto CleanupOnError;
   }
 
@@ -62,16 +62,21 @@
 
   for (uint32_t i = 0; i < num_modes_; i++) {
     error = hw_intf_->GetDisplayAttributes(hw_device_, &display_attributes_[i], i);
-    if (UNLIKELY(error != kErrorNone)) {
+    if (error != kErrorNone) {
       goto CleanupOnError;
     }
   }
 
-  active_mode_index_ = 0;
+  active_mode_index_ = GetBestConfig();
+
+  error = hw_intf_->SetDisplayAttributes(hw_device_, active_mode_index_);
+  if (error != kErrorNone) {
+    goto CleanupOnError;
+  }
 
   error = comp_manager_->RegisterDisplay(display_type_, display_attributes_[active_mode_index_],
                                         &display_comp_ctx_);
-  if (UNLIKELY(error != kErrorNone)) {
+  if (error != kErrorNone) {
     goto CleanupOnError;
   }
 
@@ -104,25 +109,25 @@
 
   DisplayError error = kErrorNone;
 
-  if (UNLIKELY(!layer_stack)) {
+  if (!layer_stack) {
     return kErrorParameters;
   }
 
   pending_commit_ = false;
 
-  if (LIKELY(state_ == kStateOn)) {
+  if ((state_ == kStateOn)) {
     // Clean hw layers for reuse.
     hw_layers_.info.Reset();
     hw_layers_.info.stack = layer_stack;
 
     while (true) {
       error = comp_manager_->Prepare(display_comp_ctx_, &hw_layers_);
-      if (UNLIKELY(error != kErrorNone)) {
+      if (error != kErrorNone) {
         break;
       }
 
       error = hw_intf_->Validate(hw_device_, &hw_layers_);
-      if (LIKELY(error == kErrorNone)) {
+      if (error == kErrorNone) {
         // Strategy is successful now, wait for Commit().
         comp_manager_->PostPrepare(display_comp_ctx_, &hw_layers_);
         pending_commit_ = true;
@@ -139,18 +144,18 @@
 
   DisplayError error = kErrorNone;
 
-  if (UNLIKELY(!layer_stack)) {
+  if (!layer_stack) {
     return kErrorParameters;
   }
 
-  if (UNLIKELY(!pending_commit_)) {
+  if (!pending_commit_) {
     DLOGE("Commit: Corresponding Prepare() is not called.");
     return kErrorUndefined;
   }
 
-  if (LIKELY(state_ == kStateOn)) {
+  if (state_ == kStateOn) {
     error = hw_intf_->Commit(hw_device_, &hw_layers_);
-    if (LIKELY(error == kErrorNone)) {
+    if (error == kErrorNone) {
       comp_manager_->PostCommit(display_comp_ctx_, &hw_layers_);
     } else {
       DLOGE("Unexpected error. Commit failed on driver.");
@@ -165,7 +170,7 @@
 DisplayError DisplayBase::GetDisplayState(DisplayState *state) {
   SCOPE_LOCK(locker_);
 
-  if (UNLIKELY(!state)) {
+  if (!state) {
     return kErrorParameters;
   }
 
@@ -176,7 +181,7 @@
 DisplayError DisplayBase::GetNumVariableInfoConfigs(uint32_t *count) {
   SCOPE_LOCK(locker_);
 
-  if (UNLIKELY(!count)) {
+  if (!count) {
     return kErrorParameters;
   }
 
@@ -188,21 +193,33 @@
 DisplayError DisplayBase::GetConfig(DisplayConfigFixedInfo *fixed_info) {
   SCOPE_LOCK(locker_);
 
-  if (UNLIKELY(!fixed_info)) {
+  if (!fixed_info) {
     return kErrorParameters;
   }
 
   return kErrorNone;
 }
 
-DisplayError DisplayBase::GetConfig(DisplayConfigVariableInfo *variable_info, uint32_t mode) {
+DisplayError DisplayBase::GetConfig(uint32_t index, DisplayConfigVariableInfo *variable_info) {
   SCOPE_LOCK(locker_);
 
-  if (UNLIKELY(!variable_info || mode >= num_modes_)) {
+  if (!variable_info || index >= num_modes_) {
     return kErrorParameters;
   }
 
-  *variable_info = display_attributes_[mode];
+  *variable_info = display_attributes_[index];
+
+  return kErrorNone;
+}
+
+DisplayError DisplayBase::GetActiveConfig(uint32_t *index) {
+  SCOPE_LOCK(locker_);
+
+  if (!index) {
+    return kErrorParameters;
+  }
+
+  *index = active_mode_index_;
 
   return kErrorNone;
 }
@@ -210,7 +227,7 @@
 DisplayError DisplayBase::GetVSyncState(bool *enabled) {
   SCOPE_LOCK(locker_);
 
-  if (UNLIKELY(!enabled)) {
+  if (!enabled) {
     return kErrorParameters;
   }
 
@@ -224,7 +241,7 @@
 
   DLOGI("Set state = %d", state);
 
-  if (UNLIKELY(state == state_)) {
+  if (state == state_) {
     DLOGI("Same state transition is requested.");
     return kErrorNone;
   }
@@ -253,17 +270,27 @@
     break;
   }
 
-  if (UNLIKELY(error == kErrorNone)) {
+  if (error == kErrorNone) {
     state_ = state;
   }
 
   return error;
 }
 
-DisplayError DisplayBase::SetConfig(uint32_t mode) {
+DisplayError DisplayBase::SetActiveConfig(uint32_t index) {
   SCOPE_LOCK(locker_);
+  DisplayError error = kErrorNone;
 
-  return kErrorNone;
+  if (index >= num_modes_) {
+    return kErrorParameters;
+  }
+
+  error = hw_intf_->SetDisplayAttributes(hw_device_, index);
+  if (error != kErrorNone) {
+    active_mode_index_ = index;
+  }
+
+  return error;
 }
 
 DisplayError DisplayBase::SetVSyncState(bool enable) {
@@ -349,5 +376,9 @@
                                 rect_name, rect->left, rect->top, rect->right, rect->bottom);
 }
 
+int DisplayBase::GetBestConfig() {
+  return (num_modes_ == 1) ? 0 : -1;
+}
+
 }  // namespace sde
 
diff --git a/displayengine/libs/core/display_base.h b/displayengine/libs/core/display_base.h
index 7eaa044..3f0e24f 100644
--- a/displayengine/libs/core/display_base.h
+++ b/displayengine/libs/core/display_base.h
@@ -46,10 +46,11 @@
   virtual DisplayError GetDisplayState(DisplayState *state);
   virtual DisplayError GetNumVariableInfoConfigs(uint32_t *count);
   virtual DisplayError GetConfig(DisplayConfigFixedInfo *fixed_info);
-  virtual DisplayError GetConfig(DisplayConfigVariableInfo *variable_info, uint32_t mode);
+  virtual DisplayError GetConfig(uint32_t index, DisplayConfigVariableInfo *variable_info);
+  virtual DisplayError GetActiveConfig(uint32_t *index);
   virtual DisplayError GetVSyncState(bool *enabled);
   virtual DisplayError SetDisplayState(DisplayState state);
-  virtual DisplayError SetConfig(uint32_t mode);
+  virtual DisplayError SetActiveConfig(uint32_t index);
   virtual DisplayError SetVSyncState(bool enable);
 
   // Implement the HWEventHandlers
@@ -61,6 +62,8 @@
   void AppendRect(char *buffer, uint32_t length, const char *rect_name, LayerRect *rect);
 
  protected:
+  virtual int GetBestConfig();
+
   Locker locker_;
   DisplayType display_type_;
   DisplayEventHandler *event_handler_;
diff --git a/displayengine/libs/core/display_hdmi.cpp b/displayengine/libs/core/display_hdmi.cpp
old mode 100755
new mode 100644
index 48208bf..f7c42f4
--- a/displayengine/libs/core/display_hdmi.cpp
+++ b/displayengine/libs/core/display_hdmi.cpp
@@ -36,5 +36,36 @@
   : DisplayBase(kHDMI, event_handler, kDeviceHDMI, hw_intf, comp_manager) {
 }
 
+int DisplayHDMI::GetBestConfig() {
+  uint32_t best_config_mode = 0;
+  HWDisplayAttributes *best = &display_attributes_[0];
+  if (num_modes_ == 1) {
+    return best_config_mode;
+  }
+
+  // From the available configs, select the best
+  // Ex: 1920x1080@60Hz is better than 1920x1080@30 and 1920x1080@30 is better than 1280x720@60
+  for (uint32_t index = 1; index < num_modes_; index++) {
+    HWDisplayAttributes *current = &display_attributes_[index];
+    // compare the two modes: in the order of Resolution followed by refreshrate
+    if (current->y_pixels > best->y_pixels) {
+      best_config_mode = index;
+    } else if (current->y_pixels == best->y_pixels) {
+      if (current->x_pixels > best->x_pixels) {
+        best_config_mode = index;
+      } else if (current->x_pixels == best->x_pixels) {
+        if (current->vsync_period_ns < best->vsync_period_ns) {
+          best_config_mode = index;
+        }
+      }
+    }
+    if (best_config_mode == index) {
+      best = &display_attributes_[index];
+    }
+  }
+
+  return best_config_mode;
+}
+
 }  // namespace sde
 
diff --git a/displayengine/libs/core/display_hdmi.h b/displayengine/libs/core/display_hdmi.h
index 85f53fc..0bb9dc8 100644
--- a/displayengine/libs/core/display_hdmi.h
+++ b/displayengine/libs/core/display_hdmi.h
@@ -32,6 +32,7 @@
 class DisplayHDMI : public DisplayBase {
  public:
   DisplayHDMI(DisplayEventHandler *event_handler, HWInterface *hw_intf, CompManager *comp_manager);
+  virtual int GetBestConfig();
 };
 
 }  // namespace sde
diff --git a/displayengine/libs/core/hw_framebuffer.cpp b/displayengine/libs/core/hw_framebuffer.cpp
old mode 100755
new mode 100644
index 69b4a58..36b86b6
--- a/displayengine/libs/core/hw_framebuffer.cpp
+++ b/displayengine/libs/core/hw_framebuffer.cpp
@@ -23,7 +23,7 @@
 */
 
 #define __STDC_FORMAT_MACROS
-
+#include <ctype.h>
 #include <math.h>
 #include <fcntl.h>
 #include <inttypes.h>
@@ -41,7 +41,8 @@
 
 #define __CLASS__ "HWFrameBuffer"
 
-#define IOCTL_LOGE(ioctl) DLOGE("ioctl %s, errno = %d, desc = %s", #ioctl, errno, strerror(errno))
+#define IOCTL_LOGE(ioctl, type) DLOGE("ioctl %s, display = %d errno = %d, desc = %s", #ioctl, \
+                                      type, errno, strerror(errno))
 
 #ifdef DISPLAY_CORE_VIRTUAL_DRIVER
 extern int virtual_ioctl(int fd, int cmd, ...);
@@ -52,12 +53,16 @@
 extern FILE* virtual_fopen(const char *fname, const char *mode);
 extern int virtual_fclose(FILE* fileptr);
 extern ssize_t virtual_getline(char **lineptr, size_t *linelen, FILE *stream);
+extern ssize_t virtual_read(int fd, void *buf, size_t count);
+extern ssize_t virtual_write(int fd, const void *buf, size_t count);
+
 #endif
 
 namespace sde {
 
 HWFrameBuffer::HWFrameBuffer() : event_thread_name_("SDE_EventThread"), fake_vsync_(false),
-                                 exit_threads_(false), fb_path_("/sys/class/graphics/fb") {
+                                 exit_threads_(false), fb_path_("/sys/devices/virtual/graphics/fb"),
+                                 hotplug_enabled_(false) {
   // Pointer to actual driver interfaces.
   ioctl_ = ::ioctl;
   open_ = ::open;
@@ -67,6 +72,8 @@
   fopen_ = ::fopen;
   fclose_ = ::fclose;
   getline_ = ::getline;
+  read_ = ::read;
+  write_ = ::write;
 
 #ifdef DISPLAY_CORE_VIRTUAL_DRIVER
   // If debug property to use virtual driver is set, point to virtual driver interfaces.
@@ -79,6 +86,8 @@
     fopen_ = virtual_fopen;
     fclose_ = virtual_fclose;
     getline_ = virtual_getline;
+    read_ = virtual_read;
+    write_ = virtual_write;
   }
 #endif
   for (int i = 0; i < kDeviceMax; i++) {
@@ -137,6 +146,16 @@
     }
   }
 
+  // Mode look-up table for HDMI
+  supported_video_modes_ = new msm_hdmi_mode_timing_info[HDMI_VFRMT_MAX];
+  if (!supported_video_modes_) {
+    error = kErrorMemory;
+    goto CleanupOnError;
+  }
+  // Populate the mode table for supported modes
+  MSM_HDMI_MODES_INIT_TIMINGS(supported_video_modes_);
+  MSM_HDMI_MODES_SET_SUPP_TIMINGS(supported_video_modes_, MSM_HDMI_MODES_ALL);
+
   // Start the Event thread
   if (pthread_create(&event_thread_, NULL, &DisplayEventThread, this) < 0) {
     DLOGE("Failed to start %s, error = %s", event_thread_name_);
@@ -156,6 +175,9 @@
       }
     }
   }
+  if (supported_video_modes_) {
+    delete supported_video_modes_;
+  }
 
   return error;
 }
@@ -169,6 +191,9 @@
       close(poll_fds_[display][event].fd);
     }
   }
+  if (supported_video_modes_) {
+    delete supported_video_modes_;
+  }
 
   return kErrorNone;
 }
@@ -183,27 +208,27 @@
   DisplayError error = kErrorNone;
 
   HWContext *hw_context = new HWContext();
-  if (UNLIKELY(!hw_context)) {
+  if (!hw_context) {
     return kErrorMemory;
   }
 
   char device_name[64] = {0};
 
   switch (type) {
-    case kDevicePrimary:
-    case kDeviceHDMI:
-      // Store EventHandlers for two Physical displays, i.e., Primary and HDMI
-      // TODO(user): Need to revisit for HDMI as Primary usecase
-      event_handler_[type] = eventhandler;
-    case kDeviceVirtual:
-      snprintf(device_name, sizeof(device_name), "%s%d", "/dev/graphics/fb", fb_node_index_[type]);
-      break;
-    default:
-      break;
+  case kDevicePrimary:
+  case kDeviceHDMI:
+    // Store EventHandlers for two Physical displays, i.e., Primary and HDMI
+    // TODO(user): Need to revisit for HDMI as Primary usecase
+    event_handler_[type] = eventhandler;
+  case kDeviceVirtual:
+    snprintf(device_name, sizeof(device_name), "%s%d", "/dev/graphics/fb", fb_node_index_[type]);
+    break;
+  default:
+    break;
   }
 
   hw_context->device_fd = open_(device_name, O_RDWR);
-  if (UNLIKELY(hw_context->device_fd < 0)) {
+  if (hw_context->device_fd < 0) {
     DLOGE("open %s failed.", device_name);
     error = kErrorResources;
     delete hw_context;
@@ -218,7 +243,19 @@
 DisplayError HWFrameBuffer::Close(Handle device) {
   HWContext *hw_context = reinterpret_cast<HWContext *>(device);
 
-  close_(hw_context->device_fd);
+  switch (hw_context->type) {
+  case kDevicePrimary:
+    break;
+  case kDeviceHDMI:
+    hdmi_mode_count_ = 0;
+    break;
+  default:
+    break;
+  }
+
+  if (hw_context->device_fd > 0) {
+    close_(hw_context->device_fd);
+  }
   delete hw_context;
 
   return kErrorNone;
@@ -227,74 +264,182 @@
 DisplayError HWFrameBuffer::GetNumDisplayAttributes(Handle device, uint32_t *count) {
   HWContext *hw_context = reinterpret_cast<HWContext *>(device);
 
-  // TODO(user): Query modes
-  *count = 1;
+  switch (hw_context->type) {
+  case kDevicePrimary:
+    *count = 1;
+    break;
+  case kDeviceHDMI:
+    *count = GetHDMIModeCount();
+    if (*count <= 0) {
+      return kErrorHardware;
+    }
+    break;
+  default:
+    return kErrorParameters;
+  }
 
   return kErrorNone;
 }
 
 DisplayError HWFrameBuffer::GetDisplayAttributes(Handle device,
                                                  HWDisplayAttributes *display_attributes,
-                                                 uint32_t mode) {
+                                                 uint32_t index) {
   HWContext *hw_context = reinterpret_cast<HWContext *>(device);
   int &device_fd = hw_context->device_fd;
-
-  // TODO(user): Query for respective mode index.
-
   // Variable screen info
   STRUCT_VAR(fb_var_screeninfo, var_screeninfo);
-  if (UNLIKELY(ioctl_(device_fd, FBIOGET_VSCREENINFO, &var_screeninfo) == -1)) {
-    IOCTL_LOGE(FBIOGET_VSCREENINFO);
-    return kErrorHardware;
-  }
 
-  // Frame rate
-  STRUCT_VAR(msmfb_metadata, meta_data);
-  meta_data.op = metadata_op_frame_rate;
-  if (UNLIKELY(ioctl_(device_fd, MSMFB_METADATA_GET, &meta_data) == -1)) {
-    IOCTL_LOGE(MSMFB_METADATA_GET);
-    return kErrorHardware;
-  }
+  switch (hw_context->type) {
+  case kDevicePrimary:
+    {
+      if (ioctl_(device_fd, FBIOGET_VSCREENINFO, &var_screeninfo) == -1) {
+        IOCTL_LOGE(FBIOGET_VSCREENINFO, hw_context->type);
+        return kErrorHardware;
+      }
 
-  // If driver doesn't return width/height information, default to 160 dpi
-  if (INT(var_screeninfo.width) <= 0 || INT(var_screeninfo.height) <= 0) {
-    var_screeninfo.width  = INT((FLOAT(var_screeninfo.xres) * 25.4f)/160.0f + 0.5f);
-    var_screeninfo.height = INT((FLOAT(var_screeninfo.yres) * 25.4f)/160.0f + 0.5f);
-  }
+      // Frame rate
+      STRUCT_VAR(msmfb_metadata, meta_data);
+      meta_data.op = metadata_op_frame_rate;
+      if (ioctl_(device_fd, MSMFB_METADATA_GET, &meta_data) == -1) {
+        IOCTL_LOGE(MSMFB_METADATA_GET, hw_context->type);
+        return kErrorHardware;
+      }
 
-  display_attributes->x_pixels = var_screeninfo.xres;
-  display_attributes->y_pixels = var_screeninfo.yres;
-  display_attributes->x_dpi = (FLOAT(var_screeninfo.xres) * 25.4f) / FLOAT(var_screeninfo.width);
-  display_attributes->y_dpi = (FLOAT(var_screeninfo.yres) * 25.4f) / FLOAT(var_screeninfo.height);
-  display_attributes->vsync_period_ns =
-                 UINT32(1000000000L / FLOAT(meta_data.data.panel_frame_rate));
+      // If driver doesn't return width/height information, default to 160 dpi
+      if (INT(var_screeninfo.width) <= 0 || INT(var_screeninfo.height) <= 0) {
+        var_screeninfo.width  = INT(((FLOAT(var_screeninfo.xres) * 25.4f)/160.0f) + 0.5f);
+        var_screeninfo.height = INT(((FLOAT(var_screeninfo.yres) * 25.4f)/160.0f) + 0.5f);
+      }
 
-  display_attributes->is_device_split = ((var_screeninfo.xres > hw_resource_.max_mixer_width) ||
-        (hw_resource_.split_info.right_split)) ? true : false;
-  if (display_attributes->is_device_split) {
-    display_attributes->split_left = hw_resource_.split_info.left_split ?
-        hw_resource_.split_info.left_split : display_attributes->x_pixels / 2;
+      display_attributes->x_pixels = var_screeninfo.xres;
+      display_attributes->y_pixels = var_screeninfo.yres;
+      display_attributes->x_dpi =
+          (FLOAT(var_screeninfo.xres) * 25.4f) / FLOAT(var_screeninfo.width);
+      display_attributes->y_dpi =
+          (FLOAT(var_screeninfo.yres) * 25.4f) / FLOAT(var_screeninfo.height);
+      display_attributes->vsync_period_ns =
+          UINT32(1000000000L / FLOAT(meta_data.data.panel_frame_rate));
+      display_attributes->is_device_split = (hw_resource_.split_info.left_split ||
+          (var_screeninfo.xres > hw_resource_.max_mixer_width)) ? true : false;
+      display_attributes->split_left = hw_resource_.split_info.left_split ?
+          hw_resource_.split_info.left_split : display_attributes->x_pixels / 2;
+    }
+    break;
+
+  case kDeviceHDMI:
+    {
+      // Get the resolution info from the look up table
+      msm_hdmi_mode_timing_info *timing_mode = &supported_video_modes_[0];
+      for (int i = 0; i < HDMI_VFRMT_MAX; i++) {
+        msm_hdmi_mode_timing_info *cur = &supported_video_modes_[i];
+        if (cur->video_format == hdmi_modes_[index]) {
+          timing_mode = cur;
+          break;
+        }
+      }
+      display_attributes->x_pixels = timing_mode->active_h;
+      display_attributes->y_pixels = timing_mode->active_v;
+      display_attributes->x_dpi = 0;
+      display_attributes->y_dpi = 0;
+      display_attributes->vsync_period_ns =
+          UINT32(1000000000L / FLOAT(timing_mode->refresh_rate));
+      display_attributes->split_left = display_attributes->x_pixels;
+      if (display_attributes->x_pixels > hw_resource_.max_mixer_width) {
+        display_attributes->is_device_split = true;
+        display_attributes->split_left = display_attributes->x_pixels / 2;
+      }
+    }
+    break;
+
+  default:
+    return kErrorParameters;
   }
 
   return kErrorNone;
 }
 
+DisplayError HWFrameBuffer::SetDisplayAttributes(Handle device, uint32_t index) {
+  HWContext *hw_context = reinterpret_cast<HWContext *>(device);
+  DisplayError error = kErrorNone;
+
+  switch (hw_context->type) {
+  case kDevicePrimary:
+    break;
+
+  case kDeviceHDMI:
+    {
+      // Variable screen info
+      STRUCT_VAR(fb_var_screeninfo, vscreeninfo);
+      if (ioctl_(hw_context->device_fd, FBIOGET_VSCREENINFO, &vscreeninfo) == -1) {
+        IOCTL_LOGE(FBIOGET_VSCREENINFO, hw_context->type);
+        return kErrorHardware;
+      }
+
+      DLOGI("GetInfo<Mode=%d %dx%d (%d,%d,%d),(%d,%d,%d) %dMHz>", vscreeninfo.reserved[3],
+            vscreeninfo.xres, vscreeninfo.yres, vscreeninfo.right_margin, vscreeninfo.hsync_len,
+            vscreeninfo.left_margin, vscreeninfo.lower_margin, vscreeninfo.vsync_len,
+            vscreeninfo.upper_margin, vscreeninfo.pixclock/1000000);
+
+      msm_hdmi_mode_timing_info *timing_mode = &supported_video_modes_[0];
+      for (int i = 0; i < HDMI_VFRMT_MAX; i++) {
+        msm_hdmi_mode_timing_info *cur = &supported_video_modes_[i];
+        if (cur->video_format == hdmi_modes_[index]) {
+          timing_mode = cur;
+          break;
+        }
+      }
+      if (MapHDMIDisplayTiming(timing_mode, &vscreeninfo) == false) {
+        return kErrorParameters;
+      }
+      STRUCT_VAR(msmfb_metadata, metadata);
+      memset(&metadata, 0 , sizeof(metadata));
+      metadata.op = metadata_op_vic;
+      metadata.data.video_info_code = timing_mode->video_format;
+      if (ioctl(hw_context->device_fd, MSMFB_METADATA_SET, &metadata) == -1) {
+        IOCTL_LOGE(MSMFB_METADATA_SET, hw_context->type);
+        return kErrorHardware;
+      }
+      DLOGI("SetInfo<Mode=%d %dx%d (%d,%d,%d),(%d,%d,%d) %dMHz>", vscreeninfo.reserved[3] & 0xFF00,
+            vscreeninfo.xres, vscreeninfo.yres, vscreeninfo.right_margin, vscreeninfo.hsync_len,
+            vscreeninfo.left_margin, vscreeninfo.lower_margin, vscreeninfo.vsync_len,
+            vscreeninfo.upper_margin, vscreeninfo.pixclock/1000000);
+
+      vscreeninfo.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_ALL | FB_ACTIVATE_FORCE;
+      if (ioctl_(hw_context->device_fd, FBIOPUT_VSCREENINFO, &vscreeninfo) == -1) {
+        IOCTL_LOGE(FBIOGET_VSCREENINFO, hw_context->type);
+        return kErrorHardware;
+      }
+    }
+    break;
+
+  default:
+    return kErrorParameters;
+  }
+
+  return error;
+}
+
 DisplayError HWFrameBuffer::PowerOn(Handle device) {
   HWContext *hw_context = reinterpret_cast<HWContext *>(device);
 
-  if (UNLIKELY(ioctl_(hw_context->device_fd, FBIOBLANK, FB_BLANK_UNBLANK) == -1)) {
-    IOCTL_LOGE(FB_BLANK_UNBLANK);
+  if (ioctl_(hw_context->device_fd, FBIOBLANK, FB_BLANK_UNBLANK) == -1) {
+    IOCTL_LOGE(FB_BLANK_UNBLANK, hw_context->type);
     return kErrorHardware;
   }
 
+  // Need to turn on HPD
+  if (!hotplug_enabled_) {
+    hotplug_enabled_ = EnableHotPlugDetection(1);
+  }
+
   return kErrorNone;
 }
 
 DisplayError HWFrameBuffer::PowerOff(Handle device) {
   HWContext *hw_context = reinterpret_cast<HWContext *>(device);
 
-  if (UNLIKELY(ioctl_(hw_context->device_fd, FBIOBLANK, FB_BLANK_POWERDOWN) == -1)) {
-    IOCTL_LOGE(FB_BLANK_POWERDOWN);
+  if (ioctl_(hw_context->device_fd, FBIOBLANK, FB_BLANK_POWERDOWN) == -1) {
+    IOCTL_LOGE(FB_BLANK_POWERDOWN, hw_context->type);
     return kErrorHardware;
   }
 
@@ -317,7 +462,7 @@
   HWContext *hw_context = reinterpret_cast<HWContext *>(device);
   int vsync_on = enable ? 1 : 0;
   if (ioctl_(hw_context->device_fd, MSMFB_OVERLAY_VSYNC_CTRL, &vsync_on) == -1) {
-    IOCTL_LOGE(MSMFB_OVERLAY_VSYNC_CTRL);
+    IOCTL_LOGE(MSMFB_OVERLAY_VSYNC_CTRL, hw_context->type);
     return kErrorHardware;
   }
 
@@ -342,47 +487,35 @@
     Layer &layer = stack->layers[layer_index];
     LayerBuffer *input_buffer = layer.input_buffer;
     HWLayerConfig &config = hw_layers->config[i];
-    HWPipeInfo &left_pipe = config.left_pipe;
 
-    // Configure left pipe
-    mdp_input_layer &mdp_layer_left = mdp_layers[mdp_layer_count];
-    mdp_layer_left.alpha = layer.plane_alpha;
-    mdp_layer_left.z_order = static_cast<uint16_t>(i);
-    mdp_layer_left.transp_mask = 0xffffffff;
-    SetBlending(layer.blending, &mdp_layer_left.blend_op);
-    SetRect(left_pipe.src_roi, &mdp_layer_left.src_rect);
-    SetRect(left_pipe.dst_roi, &mdp_layer_left.dst_rect);
-    mdp_layer_left.pipe_ndx = left_pipe.pipe_id;
+    uint32_t split_count = hw_layers->config[i].is_right_pipe ? 2 : 1;
+    for (uint32_t j = 0; j < split_count; j++) {
+      HWPipeInfo &pipe = (j == 0) ? config.left_pipe : config.right_pipe;
+      mdp_input_layer &mdp_layer = mdp_layers[mdp_layer_count];
+      mdp_layer.alpha = layer.plane_alpha;
+      mdp_layer.z_order = static_cast<uint16_t>(i);
+      mdp_layer.transp_mask = 0xffffffff;
+      SetBlending(layer.blending, &mdp_layer.blend_op);
+      SetRect(pipe.src_roi, &mdp_layer.src_rect);
+      SetRect(pipe.dst_roi, &mdp_layer.dst_rect);
 
-    mdp_layer_buffer &mdp_buffer_left = mdp_layer_left.buffer;
-    mdp_buffer_left.width = input_buffer->width;
-    mdp_buffer_left.height = input_buffer->height;
+      mdp_layer.pipe_ndx = pipe.pipe_id;
 
-    error = SetFormat(layer.input_buffer->format, &mdp_buffer_left.format);
-    if (error != kErrorNone) {
-      return error;
-    }
+      mdp_layer_buffer &mdp_buffer_left = mdp_layer.buffer;
+      mdp_buffer_left.width = input_buffer->width;
+      mdp_buffer_left.height = input_buffer->height;
 
-    mdp_layer_count++;
-
-    // Configure right pipe
-    if (config.is_right_pipe) {
-      HWPipeInfo &right_pipe = config.right_pipe;
-      mdp_input_layer &mdp_layer_right = mdp_layers[mdp_layer_count];
-
-      mdp_layer_right = mdp_layer_left;
-
-      mdp_layer_right.pipe_ndx = right_pipe.pipe_id;
-      SetRect(right_pipe.src_roi, &mdp_layer_right.src_rect);
-      SetRect(right_pipe.dst_roi, &mdp_layer_right.dst_rect);
-
+      error = SetFormat(layer.input_buffer->format, &mdp_buffer_left.format);
+      if (error != kErrorNone) {
+        return error;
+      }
       mdp_layer_count++;
     }
   }
 
   mdp_commit.flags |= MDP_VALIDATE_LAYER;
   if (ioctl_(hw_context->device_fd, MSMFB_ATOMIC_COMMIT, &hw_context->mdp_commit) == -1) {
-    IOCTL_LOGE(MSMFB_ATOMIC_COMMIT);
+    IOCTL_LOGE(MSMFB_ATOMIC_COMMIT, hw_context->type);
     return kErrorHardware;
   }
 
@@ -424,7 +557,7 @@
   mdp_commit.flags |= MDP_COMMIT_RETIRE_FENCE;
   mdp_commit.flags &= ~MDP_VALIDATE_LAYER;
   if (ioctl_(hw_context->device_fd, MSMFB_ATOMIC_COMMIT, &hw_context->mdp_commit) == -1) {
-    IOCTL_LOGE(MSMFB_ATOMIC_COMMIT);
+    IOCTL_LOGE(MSMFB_ATOMIC_COMMIT, hw_context->type);
     return kErrorHardware;
   }
 
@@ -619,8 +752,8 @@
   ssize_t read;
   char *line = stringbuffer;
   while ((read = getline_(&line, &len, fileptr)) != -1) {
-    int token_count = 0;
-    const int max_count = 10;
+    uint32_t token_count = 0;
+    const uint32_t max_count = 10;
     char *tokens[max_count] = { NULL };
     if (!ParseLine(line, tokens, max_count, &token_count)) {
       if (!strncmp(tokens[0], "pu_en", strlen("pu_en"))) {
@@ -656,8 +789,8 @@
   DisplayError error = kErrorNone;
   FILE *fileptr = NULL;
   char stringbuffer[kMaxStringLength];
-  int token_count = 0;
-  const int max_count = 10;
+  uint32_t token_count = 0;
+  const uint32_t max_count = 10;
   char *tokens[max_count] = { NULL };
   snprintf(stringbuffer , sizeof(stringbuffer), "%s%d/mdp/caps", fb_path_,
            fb_node_index_[kHWPrimary]);
@@ -698,7 +831,7 @@
       } else if (!strncmp(tokens[0], "max_mixer_width", strlen("max_mixer_width"))) {
         hw_resource_.max_mixer_width = atoi(tokens[1]);
       } else if (!strncmp(tokens[0], "features", strlen("features"))) {
-        for (int i = 0; i < token_count; i++) {
+        for (uint32_t i = 0; i < token_count; i++) {
           if (!strncmp(tokens[i], "bwc", strlen("bwc"))) {
             hw_resource_.has_bwc = true;
           } else if (!strncmp(tokens[i], "decimation", strlen("decimation"))) {
@@ -767,10 +900,11 @@
   return error;
 }
 
-int HWFrameBuffer::ParseLine(char *input, char *tokens[], int max_token, int *count) {
+int HWFrameBuffer::ParseLine(char *input, char *tokens[], const uint32_t max_token,
+                             uint32_t *count) {
   char *tmp_token = NULL;
   char *temp_ptr;
-  int index = 0;
+  uint32_t index = 0;
   const char *delim = ", =\n";
   if (!input) {
     return -1;
@@ -785,4 +919,87 @@
   return 0;
 }
 
+bool HWFrameBuffer::EnableHotPlugDetection(int enable) {
+  bool ret_value = true;
+  char hpdpath[kMaxStringLength];
+  snprintf(hpdpath , sizeof(hpdpath), "%s%d/hpd", fb_path_, fb_node_index_[kDeviceHDMI]);
+  int hpdfd = open_(hpdpath, O_RDWR, 0);
+  if (hpdfd < 0) {
+    DLOGE("Open failed = %s", hpdpath);
+    return kErrorHardware;
+  }
+  char value = enable ? '1' : '0';
+  ssize_t length = write_(hpdfd, &value, 1);
+  if (length <= 0) {
+    DLOGE("Write failed 'hpd' = %d", enable);
+    ret_value = false;
+  }
+  close_(hpdfd);
+
+  return ret_value;
+}
+
+int HWFrameBuffer::GetHDMIModeCount() {
+  ssize_t length = -1;
+  char edid_str[256] = {'\0'};
+  char edid_path[kMaxStringLength] = {'\0'};
+  snprintf(edid_path, sizeof(edid_path), "%s%d/edid_modes", fb_path_, fb_node_index_[kHWHDMI]);
+  int edid_file = open_(edid_path, O_RDONLY);
+  if (edid_file < 0) {
+    DLOGE("EDID file open failed.");
+    return -1;
+  }
+
+  length = read_(edid_file, edid_str, sizeof(edid_str)-1);
+  if (length <= 0) {
+    DLOGE("%s: edid_modes file empty");
+    edid_str[0] = '\0';
+  } else {
+    DLOGI("EDID mode string: %s", edid_str);
+    while (length > 1 && isspace(edid_str[length-1])) {
+      --length;
+    }
+    edid_str[length] = '\0';
+  }
+  close_(edid_file);
+
+  if (length > 0) {
+    // Get EDID modes from the EDID string
+    char *ptr = edid_str;
+    const uint32_t edid_count_max = 128;
+    char *tokens[edid_count_max] = { NULL };
+    ParseLine(ptr, tokens, edid_count_max, &hdmi_mode_count_);
+    for (uint32_t i = 0; i < hdmi_mode_count_; i++) {
+      hdmi_modes_[i] = atoi(tokens[i]);
+    }
+  }
+  return (hdmi_mode_count_ > 0) ? hdmi_mode_count_ : 0;
+}
+
+bool HWFrameBuffer::MapHDMIDisplayTiming(const msm_hdmi_mode_timing_info *mode,
+                                         fb_var_screeninfo *info) {
+  if (!mode || !info) {
+    return false;
+  }
+
+  info->reserved[0] = 0;
+  info->reserved[1] = 0;
+  info->reserved[2] = 0;
+  info->reserved[3] = (info->reserved[3] & 0xFFFF) | (mode->video_format << 16);
+  info->xoffset = 0;
+  info->yoffset = 0;
+  info->xres = mode->active_h;
+  info->yres = mode->active_v;
+  info->pixclock = (mode->pixel_freq) * 1000;
+  info->vmode = mode->interlaced ? FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED;
+  info->right_margin = mode->front_porch_h;
+  info->hsync_len = mode->pulse_width_h;
+  info->left_margin = mode->back_porch_h;
+  info->lower_margin = mode->front_porch_v;
+  info->vsync_len = mode->pulse_width_v;
+  info->upper_margin = mode->back_porch_v;
+
+  return true;
+}
+
 }  // namespace sde
diff --git a/displayengine/libs/core/hw_framebuffer.h b/displayengine/libs/core/hw_framebuffer.h
index b70b5be..5816878 100644
--- a/displayengine/libs/core/hw_framebuffer.h
+++ b/displayengine/libs/core/hw_framebuffer.h
@@ -28,6 +28,8 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <linux/msm_mdp_ext.h>
+#include <video/msm_hdmi_modes.h>
+
 #include <poll.h>
 #include <pthread.h>
 
@@ -45,7 +47,8 @@
   virtual DisplayError Close(Handle device);
   virtual DisplayError GetNumDisplayAttributes(Handle device, uint32_t *count);
   virtual DisplayError GetDisplayAttributes(Handle device, HWDisplayAttributes *display_attributes,
-                                            uint32_t mode);
+                                            uint32_t index);
+  virtual DisplayError SetDisplayAttributes(Handle device, uint32_t index);
   virtual DisplayError PowerOn(Handle device);
   virtual DisplayError PowerOff(Handle device);
   virtual DisplayError Doze(Handle device);
@@ -130,7 +133,13 @@
   void PopulatePanelInfo(int fb_index);
   // Populates HW Capabilities
   DisplayError PopulateHWCapabilities();
-  int ParseLine(char *input, char *token[], int max_token, int *count);
+  int ParseLine(char *input, char *token[], const uint32_t max_token, uint32_t *count);
+
+  // HDMI Related Functions
+  bool EnableHotPlugDetection(int enable);
+  int GetHDMIModeCount();
+  bool MapHDMIDisplayTiming(const msm_hdmi_mode_timing_info *mode, fb_var_screeninfo *info);
+  void ResetHDMIModes();
 
   // Pointers to system calls which are either mapped to actual system call or virtual driver.
   int (*ioctl_)(int, int, ...);
@@ -138,9 +147,12 @@
   int (*close_)(int);
   int (*poll_)(struct pollfd *, nfds_t, int);
   ssize_t (*pread_)(int, void *, size_t, off_t);
-  FILE* (*fopen_)( const char *fname, const char *mode );;
+  FILE* (*fopen_)( const char *fname, const char *mode);
   int (*fclose_)(FILE* fileptr);
   ssize_t (*getline_)(char **lineptr, size_t *linelen, FILE *stream);
+  ssize_t (*read_)(int fd, void *buf, size_t count);
+  ssize_t (*write_)(int fd, const void *buf, size_t count);
+
 
   // Store the Device EventHandlers - used for callback
   HWEventHandler *event_handler_[kNumPhysicalDisplays];
@@ -153,6 +165,11 @@
   int fb_node_index_[kDeviceMax];
   const char* fb_path_;
   PanelInfo pri_panel_info_;
+  bool hotplug_enabled_;
+  uint32_t hdmi_mode_count_;
+  uint32_t hdmi_modes_[256];
+  // Holds the hdmi timing information. Ex: resolution, fps etc.,
+  msm_hdmi_mode_timing_info *supported_video_modes_;
 };
 
 }  // namespace sde
diff --git a/displayengine/libs/core/hw_interface.h b/displayengine/libs/core/hw_interface.h
index 6748538..3e620ce 100644
--- a/displayengine/libs/core/hw_interface.h
+++ b/displayengine/libs/core/hw_interface.h
@@ -92,8 +92,9 @@
   uint32_t pipe_id;
   LayerRect src_roi;
   LayerRect dst_roi;
+  uint8_t decimation;
 
-  HWPipeInfo() : pipe_id(0) { }
+  HWPipeInfo() : pipe_id(0), decimation(1) { }
 };
 
 struct HWLayerConfig {
@@ -135,7 +136,8 @@
   virtual DisplayError Close(Handle device) = 0;
   virtual DisplayError GetNumDisplayAttributes(Handle device, uint32_t *count) = 0;
   virtual DisplayError GetDisplayAttributes(Handle device,
-                            HWDisplayAttributes *display_attributes, uint32_t mode) = 0;
+                            HWDisplayAttributes *display_attributes, uint32_t index) = 0;
+  virtual DisplayError SetDisplayAttributes(Handle device, uint32_t index) = 0;
   virtual DisplayError PowerOn(Handle device) = 0;
   virtual DisplayError PowerOff(Handle device) = 0;
   virtual DisplayError Doze(Handle device) = 0;
diff --git a/displayengine/libs/core/res_config.cpp b/displayengine/libs/core/res_config.cpp
index e1b5320..73ea4a4 100755
--- a/displayengine/libs/core/res_config.cpp
+++ b/displayengine/libs/core/res_config.cpp
@@ -230,5 +230,23 @@
   dst_rect->bottom = floorf(src_rect.bottom);
 }
 
+void 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 = src_h / dst_h;
+  pipe->decimation = 1;
+
+  if (!hw_res_info_.has_decimation || (down_scale <= max_down_scale))
+    return;
+
+  // 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
+  float decimation_factor = ceilf(log2f(down_scale) - log2f(max_down_scale));
+  pipe->decimation = UINT8(powf(2.0f, decimation_factor));
+}
+
 }  // namespace sde
 
diff --git a/displayengine/libs/core/res_manager.cpp b/displayengine/libs/core/res_manager.cpp
index ee1b25f..9edca48 100755
--- a/displayengine/libs/core/res_manager.cpp
+++ b/displayengine/libs/core/res_manager.cpp
@@ -231,12 +231,15 @@
     }
 
     src_pipes_[left_index].reserved = true;
+    SetDecimationFactor(pipe_info);
 
     pipe_info =  &hw_layers->config[i].right_pipe;
     if (pipe_info->pipe_id == 0) {
       // assign single pipe
       hw_layers->config[i].left_pipe.pipe_id = src_pipes_[left_index].mdss_pipe_id;
       src_pipes_[left_index].at_right = false;
+      hw_layers->config[i].is_right_pipe = false;
+      src_pipes_[left_index].at_right = false;
       continue;
     }
 
@@ -260,6 +263,12 @@
     src_pipes_[left_index].reserved = true;
     src_pipes_[left_index].at_right = false;
     hw_layers->config[i].left_pipe.pipe_id = src_pipes_[left_index].mdss_pipe_id;
+    SetDecimationFactor(pipe_info);
+  }
+
+  if (!CheckBandwidth(display_resource_ctx, hw_layers)) {
+    DLOGV_IF(kTagResources, "Bandwidth check failed!");
+    goto Acquire_failed;
   }
 
   return kErrorNone;
@@ -270,6 +279,216 @@
   return kErrorResources;
 }
 
+bool ResManager::CheckBandwidth(DisplayResourceContext *display_ctx, HWLayers *hw_layers) {
+  float max_pipe_bw = 1.8f;  // From MDP to hw_res_info_ (in GBps)
+  float max_sde_clk = 400.0f;  // From MDP to hw_res_info_ (in MHz)
+  float clk_fudge_factor = 1.0f;  // From MDP to hw_res_info_
+  const struct HWLayersInfo &layer_info = hw_layers->info;
+
+  float left_pipe_bw[layer_info.count];
+  float right_pipe_bw[layer_info.count];
+  float left_max_clk = 0;
+  float right_max_clk = 0;
+
+  for (uint32_t i = 0; i < layer_info.count; i++) {
+    Layer &layer = layer_info.stack->layers[layer_info.index[i]];
+    float bpp = GetBpp(layer.input_buffer->format);
+    uint32_t left_id = hw_layers->config[i].left_pipe.pipe_id;
+    uint32_t right_id = hw_layers->config[i].right_pipe.pipe_id;
+
+    left_pipe_bw[i] = left_id ? GetPipeBw(display_ctx, &hw_layers->config[i].left_pipe, bpp) : 0;
+    right_pipe_bw[i] = right_id ? GetPipeBw(display_ctx, &hw_layers->config[i].right_pipe, bpp) : 0;
+
+    if ((left_pipe_bw[i] > max_pipe_bw) || (right_pipe_bw[i] > max_pipe_bw)) {
+      DLOGV_IF(kTagResources, "Pipe bandwidth exceeds limit for layer index = %d", i);
+      return false;
+    }
+
+    float left_clk = left_id ? GetClockForPipe(display_ctx, &hw_layers->config[i].left_pipe) : 0;
+    float right_clk = right_id ? GetClockForPipe(display_ctx, &hw_layers->config[i].right_pipe) : 0;
+
+    left_max_clk = MAX(left_clk, left_max_clk);
+    right_max_clk = MAX(right_clk, right_max_clk);
+  }
+
+  float left_mixer_bw = GetOverlapBw(hw_layers, left_pipe_bw, true);
+  float right_mixer_bw = GetOverlapBw(hw_layers, right_pipe_bw, false);
+  float display_bw = left_mixer_bw + right_mixer_bw;
+
+  // Check system bandwidth (nth External + max(nth, n-1th) Primary)
+  if (display_ctx->hw_block_id == kHWPrimary) {
+    display_bw = MAX(display_bw, last_primary_bw_);
+    last_primary_bw_ = left_mixer_bw + right_mixer_bw;
+  }
+
+  // If system has Video mode panel, use max_bandwidth_low, else use max_bandwidth_high
+  if ((display_bw + bw_claimed_) > hw_res_info_.max_bandwidth_low) {
+    DLOGV_IF(kTagResources, "Overlap bandwidth exceeds limit!");
+    return false;
+  }
+
+  // Max clock requirement of display
+  float display_clk = MAX(left_max_clk, right_max_clk);
+
+  // Check max clock requirement of system
+  float system_clk = MAX(display_clk, clk_claimed_);
+
+  // Apply fudge factor to consider in-efficieny
+  if ((system_clk * clk_fudge_factor) > max_sde_clk) {
+    DLOGV_IF(kTagResources, "Clock requirement exceeds limit!");
+    return false;
+  }
+
+  // If Primary display, reset claimed bw & clk for next cycle
+  if (display_ctx->hw_block_id == kHWPrimary) {
+    bw_claimed_ = 0.0f;
+    clk_claimed_ = 0.0f;
+  } else {
+    bw_claimed_ = display_bw;
+    clk_claimed_ = display_clk;
+  }
+
+  return true;
+}
+
+float ResManager::GetPipeBw(DisplayResourceContext *display_ctx, HWPipeInfo *pipe, float bpp) {
+  HWDisplayAttributes &display_attributes = display_ctx->display_attributes;
+  float v_total = 2600.0f;  // From MDP to display_attributes (vBP + vFP + v_active)
+  float fps = 60.0f;  // display_attributes.fps;
+
+  float src_w = pipe->src_roi.right - pipe->src_roi.left;
+  float src_h = pipe->src_roi.bottom - pipe->src_roi.top;
+  float dst_h = pipe->dst_roi.bottom - pipe->dst_roi.top;
+
+  // Adjust src_h with pipe decimation
+  src_h /= FLOAT(pipe->decimation);
+
+  float bw = src_w * src_h * bpp * fps;
+
+  // Consider panel dimension
+  // (v_total / v_active) * (v_active / dst_h)
+  bw *= (v_total / dst_h);
+
+  // Bandwidth in GBps
+  return (bw / 1000000000.0f);
+}
+
+float ResManager::GetClockForPipe(DisplayResourceContext *display_ctx, HWPipeInfo *pipe) {
+  HWDisplayAttributes &display_attributes = display_ctx->display_attributes;
+  float v_total = 2600.0f;  // (vBP + vFP + v_active)
+  float fps = 60.0f;  // display_attributes.fps;
+
+  float src_h = pipe->src_roi.bottom - pipe->src_roi.top;
+  float dst_h = pipe->dst_roi.bottom - pipe->dst_roi.top;
+  float dst_w = pipe->dst_roi.right - pipe->dst_roi.left;
+
+  // Adjust src_h with pipe decimation
+  src_h /= FLOAT(pipe->decimation);
+
+  // SDE Clock requirement in MHz
+  float clk = (dst_w * v_total * fps) / 1000000.0f;
+
+  // Consider down-scaling
+  if (src_h > dst_h)
+    clk *= (src_h / dst_h);
+
+  return clk;
+}
+
+float ResManager::GetOverlapBw(HWLayers *hw_layers, float *pipe_bw, bool left_mixer) {
+  uint32_t count = hw_layers->info.count;
+  float overlap_bw[count][count];
+  float overall_max = 0;
+
+  memset(overlap_bw, 0, sizeof(overlap_bw));
+
+  // Algorithm:
+  // 1.Create an 'n' by 'n' sized 2D array, overlap_bw[n][n] (n = # of layers).
+  // 2.Get overlap_bw between two layers, i and j, and account for other overlaps (prev_max) if any.
+  //   This will fill the bottom-left half of the array including diagonal (0 <= i < n, 0 <= j <= i)
+  //                      {1. pipe_bw[i],                         where i == j
+  //   overlap_bw[i][j] = {2. 0,                                  where i != j && !Overlap(i, j)
+  //                      {3. pipe_bw[i] + pipe_bw[j] + prev_max, where i != j && Overlap(i, j)
+  //
+  //   Overlap(i, j) = !(bottom_i <= top_j || top_i >= bottom_j)
+  //   prev_max = max(prev_max, overlap_bw[j, k]), where 0 <= k < j and prev_max initially 0
+  //   prev_max = prev_max ? (prev_max - pipe_bw[j]) : 0; (to account for "double counting")
+  // 3.Get the max value in 2D array, overlap_bw[n][n], for the final overall_max bandwidth.
+  //   overall_max = max(overlap_bw[i, j]), where 0 <= i < n, 0 <= j <= i
+
+  for (uint32_t i = 0; i < count; i++) {
+    HWPipeInfo &pipe1 = left_mixer ? hw_layers->config[i].left_pipe :
+                        hw_layers->config[i].right_pipe;
+
+    // Non existing pipe never overlaps
+    if (pipe_bw[i] == 0)
+      continue;
+
+    float top1 = pipe1.dst_roi.top;
+    float bottom1 = pipe1.dst_roi.bottom;
+    float row_max = 0;
+
+    for (uint32_t j = 0; j <= i; j++) {
+      HWPipeInfo &pipe2 = left_mixer ? hw_layers->config[j].left_pipe :
+                          hw_layers->config[j].right_pipe;
+
+      if ((pipe_bw[j] == 0) || (i == j)) {
+        overlap_bw[i][j] = pipe_bw[j];
+        row_max = MAX(pipe_bw[j], row_max);
+        continue;
+      }
+
+      float top2 = pipe2.dst_roi.top;
+      float bottom2 = pipe2.dst_roi.bottom;
+
+      if ((bottom1 <= top2) || (top1 >= bottom2)) {
+        overlap_bw[i][j] = 0;
+        continue;
+      }
+
+      overlap_bw[i][j] = pipe_bw[i] + pipe_bw[j];
+
+      float prev_max = 0;
+      for (uint32_t k = 0; k < j; k++) {
+        if (overlap_bw[j][k])
+          prev_max = MAX(overlap_bw[j][k], prev_max);
+      }
+      overlap_bw[i][j] += (prev_max > 0) ? (prev_max - pipe_bw[j]) : 0;
+      row_max = MAX(overlap_bw[i][j], row_max);
+    }
+
+    overall_max = MAX(row_max, overall_max);
+  }
+
+  return overall_max;
+}
+
+float ResManager::GetBpp(LayerBufferFormat format) {
+  switch (format) {
+    case kFormatARGB8888:
+    case kFormatRGBA8888:
+    case kFormatBGRA8888:
+    case kFormatXRGB8888:
+    case kFormatRGBX8888:
+    case kFormatBGRX8888:
+      return 4.0f;
+    case kFormatRGB888:
+      return 3.0f;
+    case kFormatRGB565:
+    case kFormatYCbCr422Packed:
+      return 2.0f;
+    case kFormatYCbCr420Planar:
+    case kFormatYCrCb420Planar:
+    case kFormatYCbCr420SemiPlanar:
+    case kFormatYCrCb420SemiPlanar:
+    case kFormatYCbCr420SemiPlanarVenus:
+      return 1.5f;
+    default:
+      DLOGE("GetBpp: Invalid buffer format: %x", format);
+      return 0.0f;
+  }
+}
+
 void ResManager::PostCommit(Handle display_ctx, HWLayers *hw_layers) {
   DisplayResourceContext *display_resource_ctx =
                           reinterpret_cast<DisplayResourceContext *>(display_ctx);
diff --git a/displayengine/libs/core/res_manager.h b/displayengine/libs/core/res_manager.h
index c4d425b..ab1c9c7 100644
--- a/displayengine/libs/core/res_manager.h
+++ b/displayengine/libs/core/res_manager.h
@@ -131,6 +131,12 @@
                           const LayerRect &scissor, const LayerTransform &transform);
   bool IsNonIntegralSrcCrop(const LayerRect &crop);
   void IntegerizeRect(LayerRect *dst_rect, const LayerRect &src_rect);
+  bool CheckBandwidth(DisplayResourceContext *display_ctx, HWLayers *hw_layers);
+  float GetPipeBw(DisplayResourceContext *display_ctx, HWPipeInfo *pipe, float bpp);
+  float GetClockForPipe(DisplayResourceContext *display_ctx, HWPipeInfo *pipe);
+  float GetOverlapBw(HWLayers *hw_layers, float *pipe_bw, bool left_mixer);
+  void SetDecimationFactor(HWPipeInfo *pipe);
+  float GetBpp(LayerBufferFormat format);
 
   template <class T>
   inline void Swap(T &a, T &b) {
@@ -148,6 +154,9 @@
   SourcePipe *rgb_pipes_;
   SourcePipe *dma_pipes_;
   bool frame_start_;
+  float bw_claimed_;  // Bandwidth claimed by other display
+  float clk_claimed_;  // Clock claimed by other display
+  float last_primary_bw_;
 };
 
 }  // namespace sde
diff --git a/displayengine/libs/hwc/hwc_display.cpp b/displayengine/libs/hwc/hwc_display.cpp
index 801c0da..3f6e713 100644
--- a/displayengine/libs/hwc/hwc_display.cpp
+++ b/displayengine/libs/hwc/hwc_display.cpp
@@ -34,8 +34,9 @@
 namespace sde {
 
 HWCDisplay::HWCDisplay(CoreInterface *core_intf, hwc_procs_t const **hwc_procs, DisplayType type,
-                       int id)
-  : core_intf_(core_intf), hwc_procs_(hwc_procs), type_(type), id_(id), display_intf_(NULL) {
+                       int id, bool need_retire_fence)
+  : core_intf_(core_intf), hwc_procs_(hwc_procs), type_(type), id_(id), display_intf_(NULL),
+    layer_stack_(need_retire_fence), need_retire_fence_(need_retire_fence) {
 }
 
 int HWCDisplay::Init() {
@@ -84,10 +85,32 @@
   return 0;
 }
 
-int HWCDisplay::Blank(int blank) {
-  DLOGI("blank = %d, display = %d", blank, id_);
-  DisplayState state = blank ? kStateOff : kStateOn;
-  return SetState(state);
+int HWCDisplay::SetPowerMode(int mode) {
+  DLOGI("display = %d, mode = %d", id_, mode);
+  DisplayState state = kStateOff;
+
+  switch (mode) {
+  case HWC_POWER_MODE_OFF:
+    state = kStateOff;
+    break;
+  case HWC_POWER_MODE_NORMAL:
+    state = kStateOn;
+    break;
+  case HWC_POWER_MODE_DOZE:
+  case HWC_POWER_MODE_DOZE_SUSPEND:
+    state = kStateDoze;
+    break;
+  default:
+    return -EINVAL;
+  }
+
+  DisplayError error = display_intf_->SetDisplayState(state);
+  if (UNLIKELY(error != kErrorNone)) {
+    DLOGE("Set state failed. Error = %d", error);
+    return -EINVAL;
+  }
+
+  return 0;
 }
 
 int HWCDisplay::GetDisplayConfigs(uint32_t *configs, size_t *num_configs) {
@@ -103,7 +126,7 @@
   DisplayError error = kErrorNone;
 
   DisplayConfigVariableInfo variable_config;
-  error = display_intf_->GetConfig(&variable_config, 0);
+  error = display_intf_->GetConfig(config, &variable_config);
   if (UNLIKELY(error != kErrorNone)) {
     DLOGE("GetConfig variable info failed. Error = %d", error);
     return -EINVAL;
@@ -127,7 +150,7 @@
       values[i] = INT32(variable_config.y_dpi * 1000.0f);
       break;
     case HWC_DISPLAY_SECURE:
-      values[i] = INT32(true); // For backward compatibility. All Physical displays are secure
+      values[i] = INT32(true);  // For backward compatibility. All Physical displays are secure
       break;
     default:
       DLOGW("Spurious attribute type = %d", attributes[i]);
@@ -138,11 +161,26 @@
   return 0;
 }
 
-int HWCDisplay::SetState(DisplayState state) {
-  DisplayError error = display_intf_->SetDisplayState(state);
-  if (UNLIKELY(error != kErrorNone)) {
-    DLOGE("Set state failed. Error = %d", error);
-    return -EINVAL;
+int HWCDisplay::GetActiveConfig() {
+  DisplayError error = kErrorNone;
+  uint32_t index = 0;
+
+  error = display_intf_->GetActiveConfig(&index);
+  if (error != kErrorNone) {
+    DLOGE("GetActiveConfig failed. Error = %d", error);
+    return -1;
+  }
+
+  return index;
+}
+
+int HWCDisplay::SetActiveConfig(int index) {
+  DisplayError error = kErrorNone;
+
+  error = display_intf_->SetActiveConfig(index);
+  if (error != kErrorNone) {
+    DLOGE("SetActiveConfig failed. Error = %d", error);
+    return -1;
   }
 
   return 0;
@@ -165,6 +203,11 @@
 }
 
 int HWCDisplay::AllocateLayerStack(hwc_display_contents_1_t *content_list) {
+  if (!content_list || !content_list->numHwLayers) {
+    DLOGW("Invalid content list");
+    return -EINVAL;
+  }
+
   size_t num_hw_layers = content_list->numHwLayers;
 
   // Allocate memory for a) total number of layers b) buffer handle for each layer c) number of
@@ -199,7 +242,7 @@
   uint8_t *current_address = layer_stack_memory_.raw;
 
   // Layer array address
-  layer_stack_ = LayerStack();
+  layer_stack_ = LayerStack(need_retire_fence_);
   layer_stack_.layers = reinterpret_cast<Layer *>(current_address);
   layer_stack_.layer_count = static_cast<uint32_t>(num_hw_layers);
   current_address += num_hw_layers * sizeof(Layer);
@@ -233,6 +276,11 @@
 }
 
 int HWCDisplay::PrepareLayerStack(hwc_display_contents_1_t *content_list) {
+  if (!content_list || !content_list->numHwLayers) {
+    DLOGW("Invalid content list");
+    return -EINVAL;
+  }
+
   size_t num_hw_layers = content_list->numHwLayers;
   if (num_hw_layers <= 1) {
     return 0;
@@ -317,6 +365,11 @@
 }
 
 int HWCDisplay::CommitLayerStack(hwc_display_contents_1_t *content_list) {
+  if (!content_list || !content_list->numHwLayers) {
+    DLOGW("Invalid content list");
+    return -EINVAL;
+  }
+
   size_t num_hw_layers = content_list->numHwLayers;
   if (num_hw_layers <= 1) {
     if (!num_hw_layers) {
diff --git a/displayengine/libs/hwc/hwc_display.h b/displayengine/libs/hwc/hwc_display.h
index 2ad1987..3971d4d 100644
--- a/displayengine/libs/hwc/hwc_display.h
+++ b/displayengine/libs/hwc/hwc_display.h
@@ -37,10 +37,11 @@
   virtual int Prepare(hwc_display_contents_1_t *content_list) = 0;
   virtual int Commit(hwc_display_contents_1_t *content_list) = 0;
   virtual int EventControl(int event, int enable);
-  virtual int Blank(int blank);
+  virtual int SetPowerMode(int mode);
   virtual int GetDisplayConfigs(uint32_t *configs, size_t *num_configs);
   virtual int GetDisplayAttributes(uint32_t config, const uint32_t *attributes, int32_t *values);
-  int SetState(DisplayState state);
+  virtual int GetActiveConfig();
+  virtual int SetActiveConfig(int index);
 
  protected:
   // Maximum number of layers supported by display engine.
@@ -69,7 +70,8 @@
     LayerStackCache() : layer_count(0) { }
   };
 
-  HWCDisplay(CoreInterface *core_intf, hwc_procs_t const **hwc_procs, DisplayType type, int id);
+  HWCDisplay(CoreInterface *core_intf, hwc_procs_t const **hwc_procs, DisplayType type, int id,
+             bool need_retire_fence);
   virtual ~HWCDisplay() { }
 
   // DisplayEventHandler methods
@@ -88,14 +90,15 @@
   inline void SetBlending(const int32_t &source, LayerBlending *target);
   inline int SetFormat(const int32_t &source, LayerBufferFormat *target);
 
-  LayerStackMemory layer_stack_memory_;
-  LayerStack layer_stack_;
-  LayerStackCache layer_stack_cache_;
   CoreInterface *core_intf_;
   hwc_procs_t const **hwc_procs_;
   DisplayType type_;
   int id_;
   DisplayInterface *display_intf_;
+  LayerStackMemory layer_stack_memory_;
+  LayerStack layer_stack_;
+  bool need_retire_fence_;
+  LayerStackCache layer_stack_cache_;
 };
 
 }  // namespace sde
diff --git a/displayengine/libs/hwc/hwc_display_external.cpp b/displayengine/libs/hwc/hwc_display_external.cpp
old mode 100755
new mode 100644
index 386e713..6705549
--- a/displayengine/libs/hwc/hwc_display_external.cpp
+++ b/displayengine/libs/hwc/hwc_display_external.cpp
@@ -32,29 +32,19 @@
 namespace sde {
 
 HWCDisplayExternal::HWCDisplayExternal(CoreInterface *core_intf, hwc_procs_t const **hwc_procs)
-  : HWCDisplay(core_intf, hwc_procs, kHDMI, HWC_DISPLAY_EXTERNAL) {
-}
-
-int HWCDisplayExternal::Init() {
-  return 0;
-}
-
-int HWCDisplayExternal::Deinit() {
-  return 0;
+  : HWCDisplay(core_intf, hwc_procs, kHDMI, HWC_DISPLAY_EXTERNAL, true) {
 }
 
 int HWCDisplayExternal::Prepare(hwc_display_contents_1_t *content_list) {
   int status = 0;
 
   status = AllocateLayerStack(content_list);
-  if (UNLIKELY(status)) {
+  if (status) {
     return status;
   }
 
-  layer_stack_.retire_fence_fd = -1;
-
   status = PrepareLayerStack(content_list);
-  if (UNLIKELY(status)) {
+  if (status) {
     return status;
   }
 
@@ -65,7 +55,7 @@
   int status = 0;
 
   status = HWCDisplay::CommitLayerStack(content_list);
-  if (UNLIKELY(status)) {
+  if (status) {
     return status;
   }
 
@@ -74,11 +64,22 @@
   return 0;
 }
 
-int HWCDisplayExternal::PowerOn() {
-  return 0;
-}
+int HWCDisplayExternal::GetDisplayConfigs(uint32_t *configs, size_t *num_configs) {
+  uint32_t config_count = 0;
+  if (*num_configs <= 0) {
+    return -EINVAL;
+  }
 
-int HWCDisplayExternal::PowerOff() {
+  display_intf_->GetNumVariableInfoConfigs(&config_count);
+  *num_configs = static_cast<size_t>(config_count);
+  if (*num_configs <= 0) {
+    return -EINVAL;
+  }
+
+  for (uint32_t i = 0; i < config_count; i++) {
+    configs[i] = i;
+  }
+
   return 0;
 }
 
diff --git a/displayengine/libs/hwc/hwc_display_external.h b/displayengine/libs/hwc/hwc_display_external.h
index 012c653..e268621 100644
--- a/displayengine/libs/hwc/hwc_display_external.h
+++ b/displayengine/libs/hwc/hwc_display_external.h
@@ -32,12 +32,9 @@
 class HWCDisplayExternal : public HWCDisplay {
  public:
   explicit HWCDisplayExternal(CoreInterface *core_intf, hwc_procs_t const **hwc_procs);
-  virtual int Init();
-  virtual int Deinit();
   virtual int Prepare(hwc_display_contents_1_t *content_list);
   virtual int Commit(hwc_display_contents_1_t *content_list);
-  virtual int PowerOn();
-  virtual int PowerOff();
+  virtual int GetDisplayConfigs(uint32_t *configs, size_t *num_configs);
 };
 
 }  // namespace sde
diff --git a/displayengine/libs/hwc/hwc_display_primary.cpp b/displayengine/libs/hwc/hwc_display_primary.cpp
old mode 100755
new mode 100644
index 95dc97e..19a1016
--- a/displayengine/libs/hwc/hwc_display_primary.cpp
+++ b/displayengine/libs/hwc/hwc_display_primary.cpp
@@ -32,29 +32,19 @@
 namespace sde {
 
 HWCDisplayPrimary::HWCDisplayPrimary(CoreInterface *core_intf, hwc_procs_t const **hwc_procs)
-  : HWCDisplay(core_intf, hwc_procs, kPrimary, HWC_DISPLAY_PRIMARY) {
-}
-
-int HWCDisplayPrimary::Init() {
-  return HWCDisplay::Init();
-}
-
-int HWCDisplayPrimary::Deinit() {
-  return HWCDisplay::Deinit();
+  : HWCDisplay(core_intf, hwc_procs, kPrimary, HWC_DISPLAY_PRIMARY, true) {
 }
 
 int HWCDisplayPrimary::Prepare(hwc_display_contents_1_t *content_list) {
   int status = 0;
 
   status = AllocateLayerStack(content_list);
-  if (UNLIKELY(status)) {
+  if (status) {
     return status;
   }
 
-  layer_stack_.retire_fence_fd = -1;
-
   status = PrepareLayerStack(content_list);
-  if (UNLIKELY(status)) {
+  if (status) {
     return status;
   }
 
@@ -65,7 +55,7 @@
   int status = 0;
 
   status = HWCDisplay::CommitLayerStack(content_list);
-  if (UNLIKELY(status)) {
+  if (status) {
     return status;
   }
 
@@ -74,13 +64,5 @@
   return 0;
 }
 
-int HWCDisplayPrimary::PowerOn() {
-  return SetState(kStateOn);
-}
-
-int HWCDisplayPrimary::PowerOff() {
-  return SetState(kStateOff);
-}
-
 }  // namespace sde
 
diff --git a/displayengine/libs/hwc/hwc_display_primary.h b/displayengine/libs/hwc/hwc_display_primary.h
index cd8ae0f..4e9e93f 100644
--- a/displayengine/libs/hwc/hwc_display_primary.h
+++ b/displayengine/libs/hwc/hwc_display_primary.h
@@ -32,12 +32,8 @@
 class HWCDisplayPrimary : public HWCDisplay {
  public:
   explicit HWCDisplayPrimary(CoreInterface *core_intf, hwc_procs_t const **hwc_procs);
-  virtual int Init();
-  virtual int Deinit();
   virtual int Prepare(hwc_display_contents_1_t *content_list);
   virtual int Commit(hwc_display_contents_1_t *content_list);
-  virtual int PowerOn();
-  virtual int PowerOff();
 };
 
 }  // namespace sde
diff --git a/displayengine/libs/hwc/hwc_display_virtual.cpp b/displayengine/libs/hwc/hwc_display_virtual.cpp
index 3ac2376..657aecb 100755
--- a/displayengine/libs/hwc/hwc_display_virtual.cpp
+++ b/displayengine/libs/hwc/hwc_display_virtual.cpp
@@ -32,15 +32,7 @@
 namespace sde {
 
 HWCDisplayVirtual::HWCDisplayVirtual(CoreInterface *core_intf, hwc_procs_t const **hwc_procs)
-  : HWCDisplay(core_intf, hwc_procs, kVirtual, HWC_DISPLAY_VIRTUAL) {
-}
-
-int HWCDisplayVirtual::Init() {
-  return 0;
-}
-
-int HWCDisplayVirtual::Deinit() {
-  return 0;
+  : HWCDisplay(core_intf, hwc_procs, kVirtual, HWC_DISPLAY_VIRTUAL, false) {
 }
 
 int HWCDisplayVirtual::Prepare(hwc_display_contents_1_t *content_list) {
@@ -51,13 +43,5 @@
   return 0;
 }
 
-int HWCDisplayVirtual::PowerOn() {
-  return 0;
-}
-
-int HWCDisplayVirtual::PowerOff() {
-  return 0;
-}
-
 }  // namespace sde
 
diff --git a/displayengine/libs/hwc/hwc_display_virtual.h b/displayengine/libs/hwc/hwc_display_virtual.h
index 6159425..796ed32 100644
--- a/displayengine/libs/hwc/hwc_display_virtual.h
+++ b/displayengine/libs/hwc/hwc_display_virtual.h
@@ -32,12 +32,8 @@
 class HWCDisplayVirtual : public HWCDisplay {
  public:
   explicit HWCDisplayVirtual(CoreInterface *core_intf, hwc_procs_t const **hwc_procs);
-  virtual int Init();
-  virtual int Deinit();
   virtual int Prepare(hwc_display_contents_1_t *content_list);
   virtual int Commit(hwc_display_contents_1_t *content_list);
-  virtual int PowerOn();
-  virtual int PowerOff();
 };
 
 }  // namespace sde
diff --git a/displayengine/libs/hwc/hwc_session.cpp b/displayengine/libs/hwc/hwc_session.cpp
old mode 100755
new mode 100644
index 64cd7e1..3f99a23
--- a/displayengine/libs/hwc/hwc_session.cpp
+++ b/displayengine/libs/hwc/hwc_session.cpp
@@ -25,6 +25,9 @@
 #include <core/dump_interface.h>
 #include <utils/constants.h>
 #include <utils/String16.h>
+#include <hardware_legacy/uevent.h>
+#include <sys/resource.h>
+#include <sys/prctl.h>
 #include <binder/Parcel.h>
 #include <QService.h>
 
@@ -53,20 +56,24 @@
 
 Locker HWCSession::locker_;
 
-HWCSession::HWCSession(const hw_module_t *module) : core_intf_(NULL), hwc_procs_(NULL) {
+HWCSession::HWCSession(const hw_module_t *module) : core_intf_(NULL), hwc_procs_(NULL),
+            display_primary_(NULL), display_external_(NULL), hotplug_thread_exit_(false),
+            hotplug_thread_name_("HWC_HotPlugThread") {
   hwc_composer_device_1_t::common.tag = HARDWARE_DEVICE_TAG;
-  hwc_composer_device_1_t::common.version = HWC_DEVICE_API_VERSION_1_3;
+  hwc_composer_device_1_t::common.version = HWC_DEVICE_API_VERSION_1_4;
   hwc_composer_device_1_t::common.module = const_cast<hw_module_t*>(module);
   hwc_composer_device_1_t::common.close = Close;
   hwc_composer_device_1_t::prepare = Prepare;
   hwc_composer_device_1_t::set = Set;
   hwc_composer_device_1_t::eventControl = EventControl;
-  hwc_composer_device_1_t::blank = Blank;
+  hwc_composer_device_1_t::setPowerMode = SetPowerMode;
   hwc_composer_device_1_t::query = Query;
   hwc_composer_device_1_t::registerProcs = RegisterProcs;
   hwc_composer_device_1_t::dump = Dump;
   hwc_composer_device_1_t::getDisplayConfigs = GetDisplayConfigs;
   hwc_composer_device_1_t::getDisplayAttributes = GetDisplayAttributes;
+  hwc_composer_device_1_t::getActiveConfig = GetActiveConfig;
+  hwc_composer_device_1_t::setActiveConfig = SetActiveConfig;
 }
 
 int HWCSession::Init() {
@@ -86,40 +93,50 @@
   }
 
   DisplayError error = CoreInterface::CreateCore(this, HWCLogHandler::Get(), &core_intf_);
-  if (UNLIKELY(error != kErrorNone)) {
+  if (error != kErrorNone) {
     DLOGE("Display core initialization failed. Error = %d", error);
     return -EINVAL;
   }
 
   // Create and power on primary display
   display_primary_ = new HWCDisplayPrimary(core_intf_, &hwc_procs_);
-  if (UNLIKELY(!display_primary_)) {
+  if (!display_primary_) {
     CoreInterface::DestroyCore();
     return -ENOMEM;
   }
 
   status = display_primary_->Init();
-  if (UNLIKELY(status)) {
+  if (status) {
     CoreInterface::DestroyCore();
     delete display_primary_;
     return status;
   }
 
-  status = display_primary_->PowerOn();
-  if (UNLIKELY(status)) {
-    CoreInterface::DestroyCore();
+  status = display_primary_->SetPowerMode(HWC_POWER_MODE_NORMAL);
+  if (status) {
     display_primary_->Deinit();
     delete display_primary_;
+    CoreInterface::DestroyCore();
     return status;
   }
 
+  if (pthread_create(&hotplug_thread_, NULL, &HWCHotPlugThread, this) < 0) {
+    DLOGE("Failed to start = %s, error = %s HDMI display Not supported", hotplug_thread_name_);
+    display_primary_->Deinit();
+    delete display_primary_;
+    CoreInterface::DestroyCore();
+    return -errno;
+  }
+
   return 0;
 }
 
 int HWCSession::Deinit() {
-  display_primary_->PowerOff();
+  display_primary_->SetPowerMode(HWC_POWER_MODE_OFF);
   display_primary_->Deinit();
   delete display_primary_;
+  hotplug_thread_exit_ = true;
+  pthread_join(hotplug_thread_, NULL);
 
   DisplayError error = CoreInterface::DestroyCore();
   if (error != kErrorNone) {
@@ -130,19 +147,19 @@
 }
 
 int HWCSession::Open(const hw_module_t *module, const char *name, hw_device_t **device) {
-  if (UNLIKELY(!module || !name || !device)) {
+  if (!module || !name || !device) {
     DLOGE("Invalid parameters.");
     return -EINVAL;
   }
 
-  if (LIKELY(!strcmp(name, HWC_HARDWARE_COMPOSER))) {
+  if (!strcmp(name, HWC_HARDWARE_COMPOSER)) {
     HWCSession *hwc_session = new HWCSession(module);
-    if (UNLIKELY(!hwc_session)) {
+    if (!hwc_session) {
       return -ENOMEM;
     }
 
     int status = hwc_session->Init();
-    if (UNLIKELY(status != 0)) {
+    if (status != 0) {
       delete hwc_session;
       return status;
     }
@@ -155,7 +172,7 @@
 }
 
 int HWCSession::Close(hw_device_t *device) {
-  if (UNLIKELY(!device)) {
+  if (!device) {
     return -EINVAL;
   }
 
@@ -172,74 +189,72 @@
                         hwc_display_contents_1_t **displays) {
   SCOPE_LOCK(locker_);
 
-  if (UNLIKELY(!device || !displays)) {
+  if (!device || !displays) {
     return -EINVAL;
   }
 
   HWCSession *hwc_session = static_cast<HWCSession *>(device);
-  int status = -EINVAL;
 
-  for (size_t i = 0; i < num_displays; i++) {
+  for (ssize_t i = (num_displays-1); i >= 0; i--) {
     hwc_display_contents_1_t *content_list = displays[i];
-    if (UNLIKELY(!content_list || !content_list->numHwLayers)) {
-      DLOGW("Invalid content list.");
-      return -EINVAL;
-    }
 
     switch (i) {
     case HWC_DISPLAY_PRIMARY:
-      status = hwc_session->display_primary_->Prepare(content_list);
+      hwc_session->display_primary_->Prepare(content_list);
+      break;
+    case HWC_DISPLAY_EXTERNAL:
+      if (hwc_session->display_external_) {
+        hwc_session->display_external_->Prepare(content_list);
+      }
+      break;
+    case HWC_DISPLAY_VIRTUAL:
       break;
     default:
-      status = -EINVAL;
-    }
-
-    if (UNLIKELY(!status)) {
       break;
     }
   }
 
-  return status;
+  // Return 0, else client will go into bad state
+  return 0;
 }
 
 int HWCSession::Set(hwc_composer_device_1 *device, size_t num_displays,
                     hwc_display_contents_1_t **displays) {
   SCOPE_LOCK(locker_);
 
-  if (UNLIKELY(!device || !displays)) {
+  if (!device || !displays) {
     return -EINVAL;
   }
 
   HWCSession *hwc_session = static_cast<HWCSession *>(device);
-  int status = -EINVAL;
 
   for (size_t i = 0; i < num_displays; i++) {
     hwc_display_contents_1_t *content_list = displays[i];
-    if (UNLIKELY(!content_list || !content_list->numHwLayers)) {
-      DLOGW("Invalid content list.");
-      return -EINVAL;
-    }
 
     switch (i) {
     case HWC_DISPLAY_PRIMARY:
-      status = hwc_session->display_primary_->Commit(content_list);
+      hwc_session->display_primary_->Commit(content_list);
+      break;
+    case HWC_DISPLAY_EXTERNAL:
+      if (hwc_session->display_external_) {
+        hwc_session->display_external_->Commit(content_list);
+      }
+      break;
+    case HWC_DISPLAY_VIRTUAL:
       break;
     default:
-      status = -EINVAL;
-    }
-
-    if (UNLIKELY(!status)) {
       break;
     }
   }
 
-  return status;
+  // Return 0, else client will go into bad state
+  return 0;
 }
 
 int HWCSession::EventControl(hwc_composer_device_1 *device, int disp, int event, int enable) {
   SCOPE_LOCK(locker_);
 
-  if (UNLIKELY(!device)) {
+  if (!device) {
     return -EINVAL;
   }
 
@@ -250,17 +265,22 @@
   case HWC_DISPLAY_PRIMARY:
     status = hwc_session->display_primary_->EventControl(event, enable);
     break;
+  case HWC_DISPLAY_EXTERNAL:
+    if (hwc_session->display_external_) {
+      status = hwc_session->display_external_->EventControl(event, enable);
+    }
+    break;
   default:
     status = -EINVAL;
   }
 
-  return 0;
+  return status;
 }
 
-int HWCSession::Blank(hwc_composer_device_1 *device, int disp, int blank) {
+int HWCSession::SetPowerMode(hwc_composer_device_1 *device, int disp, int mode) {
   SCOPE_LOCK(locker_);
 
-  if (UNLIKELY(!device)) {
+  if (!device) {
     return -EINVAL;
   }
 
@@ -269,7 +289,12 @@
 
   switch (disp) {
   case HWC_DISPLAY_PRIMARY:
-    status = hwc_session->display_primary_->Blank(blank);
+    status = hwc_session->display_primary_->SetPowerMode(mode);
+    break;
+  case HWC_DISPLAY_EXTERNAL:
+    if (hwc_session->display_external_) {
+      status = hwc_session->display_external_->SetPowerMode(mode);
+    }
     break;
   default:
     status = -EINVAL;
@@ -279,7 +304,7 @@
 }
 
 int HWCSession::Query(hwc_composer_device_1 *device, int param, int *value) {
-  if (UNLIKELY(!device || !value)) {
+  if (!device || !value) {
     return -EINVAL;
   }
 
@@ -287,7 +312,7 @@
 }
 
 void HWCSession::RegisterProcs(hwc_composer_device_1 *device, hwc_procs_t const *procs) {
-  if (UNLIKELY(!device || !procs)) {
+  if (!device || !procs) {
     return;
   }
 
@@ -298,7 +323,7 @@
 void HWCSession::Dump(hwc_composer_device_1 *device, char *buffer, int length) {
   SCOPE_LOCK(locker_);
 
-  if (UNLIKELY(!device || !buffer || !length)) {
+  if (!device || !buffer || !length) {
     return;
   }
 
@@ -307,7 +332,7 @@
 
 int HWCSession::GetDisplayConfigs(hwc_composer_device_1 *device, int disp, uint32_t *configs,
                                   size_t *num_configs) {
-  if (UNLIKELY(!device || !configs || !num_configs)) {
+  if (!device || !configs || !num_configs) {
     return -EINVAL;
   }
 
@@ -318,6 +343,11 @@
   case HWC_DISPLAY_PRIMARY:
     status = hwc_session->display_primary_->GetDisplayConfigs(configs, num_configs);
     break;
+  case HWC_DISPLAY_EXTERNAL:
+    if (hwc_session->display_external_) {
+      status = hwc_session->display_external_->GetDisplayConfigs(configs, num_configs);
+    }
+    break;
   default:
     status = -EINVAL;
   }
@@ -327,7 +357,7 @@
 
 int HWCSession::GetDisplayAttributes(hwc_composer_device_1 *device, int disp, uint32_t config,
                                      const uint32_t *attributes, int32_t *values) {
-  if (UNLIKELY(!device || !attributes || !values)) {
+  if (!device || !attributes || !values) {
     return -EINVAL;
   }
 
@@ -338,6 +368,60 @@
   case HWC_DISPLAY_PRIMARY:
     status = hwc_session->display_primary_->GetDisplayAttributes(config, attributes, values);
     break;
+  case HWC_DISPLAY_EXTERNAL:
+    if (hwc_session->display_external_) {
+      status = hwc_session->display_external_->GetDisplayAttributes(config, attributes, values);
+    }
+    break;
+  default:
+    status = -EINVAL;
+  }
+
+  return status;
+}
+
+int HWCSession::GetActiveConfig(hwc_composer_device_1 *device, int disp) {
+  if (!device) {
+    return -1;
+  }
+
+  HWCSession *hwc_session = static_cast<HWCSession *>(device);
+  int active_config = -1;
+
+  switch (disp) {
+  case HWC_DISPLAY_PRIMARY:
+    active_config = hwc_session->display_primary_->GetActiveConfig();
+    break;
+  case HWC_DISPLAY_EXTERNAL:
+    if (hwc_session->display_external_) {
+      active_config = hwc_session->display_external_->GetActiveConfig();
+    }
+    break;
+  default:
+    active_config = -1;
+  }
+
+  return active_config;
+}
+
+int HWCSession::SetActiveConfig(hwc_composer_device_1 *device, int disp, int index) {
+  if (!device) {
+    return -EINVAL;
+  }
+
+  HWCSession *hwc_session = static_cast<HWCSession *>(device);
+  int status = -EINVAL;
+
+  switch (disp) {
+  case HWC_DISPLAY_PRIMARY:
+    status = hwc_session->display_primary_->SetActiveConfig(index);
+    break;
+  case HWC_DISPLAY_EXTERNAL:
+    if (hwc_session->display_external_) {
+      // TODO(user): Uncomment it. HDMI does not support resolution change currently.
+      status = 0;  // hwc_session->display_external_->SetActiveConfig(index);
+    }
+    break;
   default:
     status = -EINVAL;
   }
@@ -390,6 +474,100 @@
     DLOGW("type = %d is not supported", type);
   }
 }
+void* HWCSession::HWCHotPlugThread(void *context) {
+  if (context) {
+    return reinterpret_cast<HWCSession *>(context)->HWCHotPlugThreadHandler();
+  }
+
+  return NULL;
+}
+
+void* HWCSession::HWCHotPlugThreadHandler() {
+  static char uevent_data[PAGE_SIZE];
+  int length = 0;
+  prctl(PR_SET_NAME, hotplug_thread_name_, 0, 0, 0);
+  setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY);
+  if (!uevent_init()) {
+    DLOGE("Failed to init uevent");
+    pthread_exit(0);
+    return NULL;
+  }
+
+  while (!hotplug_thread_exit_) {
+    // keep last 2 zeroes to ensure double 0 termination
+    length = uevent_next_event(uevent_data, INT32(sizeof(uevent_data)) - 2);
+
+    if (!strcasestr("change@/devices/virtual/switch/hdmi", uevent_data)) {
+      continue;
+    }
+    DLOGI("Uevent HDMI = %s", uevent_data);
+    int connected = GetHDMIConnectedState(uevent_data, length);
+    if (connected >= 0) {
+      DLOGI("HDMI = %s", connected ? "connected" : "disconnected");
+      if (HotPlugHandler(connected) == -1) {
+        DLOGE("Failed handling Hotplug = %s", connected ? "connected" : "disconnected");
+      }
+    }
+  }
+  pthread_exit(0);
+
+  return NULL;
+}
+
+int HWCSession::GetHDMIConnectedState(const char *uevent_data, int length) {
+  const char* iterator_str = uevent_data;
+  while (((iterator_str - uevent_data) <= length) && (*iterator_str)) {
+    char* pstr = strstr(iterator_str, "SWITCH_STATE=");
+    if (pstr != NULL) {
+      return (atoi(iterator_str + strlen("SWITCH_STATE=")));
+    }
+    iterator_str += strlen(iterator_str) + 1;
+  }
+  return -1;
+}
+
+
+int HWCSession::HotPlugHandler(bool connected) {
+  if (!hwc_procs_) {
+     DLOGW("Ignore hotplug - hwc_proc not registered");
+    return -1;
+  }
+
+  if (connected) {
+    SCOPE_LOCK(locker_);
+    if (display_external_) {
+     DLOGE("HDMI already connected");
+     return -1;
+    }
+    // Create hdmi display
+    display_external_ = new HWCDisplayExternal(core_intf_, &hwc_procs_);
+    if (!display_external_) {
+      return -1;
+    }
+    int status = display_external_->Init();
+    if (status) {
+      delete display_external_;
+      display_external_ = NULL;
+      return -1;
+    }
+  } else {
+    SCOPE_LOCK(locker_);
+    if (!display_external_) {
+     DLOGE("HDMI not connected");
+     return -1;
+    }
+    display_external_->SetPowerMode(HWC_POWER_MODE_OFF);
+    display_external_->Deinit();
+    delete display_external_;
+    display_external_ = NULL;
+  }
+
+  // notify client and trigger a screen refresh
+  hwc_procs_->hotplug(hwc_procs_, HWC_DISPLAY_EXTERNAL, connected);
+  hwc_procs_->invalidate(hwc_procs_);
+
+  return 0;
+}
 
 }  // namespace sde
 
diff --git a/displayengine/libs/hwc/hwc_session.h b/displayengine/libs/hwc/hwc_session.h
index 9e37eed..488da9d 100644
--- a/displayengine/libs/hwc/hwc_session.h
+++ b/displayengine/libs/hwc/hwc_session.h
@@ -31,6 +31,7 @@
 #include <IQClient.h>
 
 #include "hwc_display_primary.h"
+#include "hwc_display_external.h"
 
 namespace sde {
 
@@ -55,7 +56,7 @@
   static int Set(hwc_composer_device_1 *device, size_t num_displays,
                  hwc_display_contents_1_t **displays);
   static int EventControl(hwc_composer_device_1 *device, int disp, int event, int enable);
-  static int Blank(hwc_composer_device_1 *device, int disp, int blank);
+  static int SetPowerMode(hwc_composer_device_1 *device, int disp, int mode);
   static int Query(hwc_composer_device_1 *device, int param, int *value);
   static void RegisterProcs(hwc_composer_device_1 *device, hwc_procs_t const *procs);
   static void Dump(hwc_composer_device_1 *device, char *buffer, int length);
@@ -63,6 +64,14 @@
                                size_t *numConfigs);
   static int GetDisplayAttributes(hwc_composer_device_1 *device, int disp, uint32_t config,
                                   const uint32_t *attributes, int32_t *values);
+  static int GetActiveConfig(hwc_composer_device_1 *device, int disp);
+  static int SetActiveConfig(hwc_composer_device_1 *device, int disp, int index);
+
+  // Hotplug thread for HDMI connect/disconnect
+  static void* HWCHotPlugThread(void *context);
+  void* HWCHotPlugThreadHandler();
+  int GetHDMIConnectedState(const char *uevent_data, int length);
+  int HotPlugHandler(bool connected);
 
   // CoreEventHandler methods
   virtual DisplayError Hotplug(const CoreEventHotplug &hotplug);
@@ -76,6 +85,10 @@
   CoreInterface *core_intf_;
   hwc_procs_t const *hwc_procs_;
   HWCDisplayPrimary *display_primary_;
+  HWCDisplayExternal *display_external_;
+  pthread_t hotplug_thread_;
+  bool hotplug_thread_exit_;
+  const char *hotplug_thread_name_;
 };
 
 }  // namespace sde
diff --git a/libgralloc/gralloc_priv.h b/libgralloc/gralloc_priv.h
index d866ef4..1fbff11 100644
--- a/libgralloc/gralloc_priv.h
+++ b/libgralloc/gralloc_priv.h
@@ -70,20 +70,17 @@
     GRALLOC_USAGE_PRIVATE_SECURE_DISPLAY  =       0x00800000,
 };
 
-enum {
-    /* Gralloc perform enums
-    */
-    GRALLOC_MODULE_PERFORM_CREATE_HANDLE_FROM_BUFFER = 1,
-    // This will be deprecated from latest graphics drivers. This is kept
-    // for those backward compatibility i.e., newer Display HAL + older graphics
-    // libraries
-    GRALLOC_MODULE_PERFORM_GET_STRIDE,
-    GRALLOC_MODULE_PERFORM_GET_CUSTOM_STRIDE_FROM_HANDLE,
-    GRALLOC_MODULE_PERFORM_GET_CUSTOM_STRIDE_AND_HEIGHT_FROM_HANDLE,
-    GRALLOC_MODULE_PERFORM_GET_ATTRIBUTES,
-    GRALLOC_MODULE_PERFORM_GET_COLOR_SPACE_FROM_HANDLE,
-    GRALLOC_MODULE_PERFORM_GET_YUV_PLANE_INFO,
-};
+/* define Gralloc perform */
+#define GRALLOC_MODULE_PERFORM_CREATE_HANDLE_FROM_BUFFER 1
+// This will be used by the graphics drivers to know if certain features
+// are defined in this display HAL.
+// Ex: Newer GFX libraries + Older Display HAL
+#define GRALLOC_MODULE_PERFORM_GET_STRIDE 2
+#define GRALLOC_MODULE_PERFORM_GET_CUSTOM_STRIDE_FROM_HANDLE 3
+#define GRALLOC_MODULE_PERFORM_GET_CUSTOM_STRIDE_AND_HEIGHT_FROM_HANDLE 4
+#define GRALLOC_MODULE_PERFORM_GET_ATTRIBUTES 5
+#define GRALLOC_MODULE_PERFORM_GET_COLOR_SPACE_FROM_HANDLE 6
+#define GRALLOC_MODULE_PERFORM_GET_YUV_PLANE_INFO 7
 
 #define GRALLOC_HEAP_MASK   (GRALLOC_USAGE_PRIVATE_UI_CONTIG_HEAP |\
                              GRALLOC_USAGE_PRIVATE_SYSTEM_HEAP    |\
diff --git a/libhwcomposer/hwc_ad.cpp b/libhwcomposer/hwc_ad.cpp
index 7e96d97..b9cf5ce 100644
--- a/libhwcomposer/hwc_ad.cpp
+++ b/libhwcomposer/hwc_ad.cpp
@@ -134,7 +134,7 @@
         const hwc_layer_1_t* layer = &list->hwLayers[nYuvIndex];
         private_handle_t *hnd = (private_handle_t *)layer->handle;
         qdutils::MDPVersion& mdpHw =  qdutils::MDPVersion::getInstance();
-        if(hnd && hnd->width <= (int) mdpHw.getMaxMixerWidth()) {
+        if(hnd && hnd->width <= (int) mdpHw.getMaxPipeWidth()) {
             mDoable = true;
         }
     }
diff --git a/libhwcomposer/hwc_fbupdate.cpp b/libhwcomposer/hwc_fbupdate.cpp
index 58cf374..08a4fb9 100644
--- a/libhwcomposer/hwc_fbupdate.cpp
+++ b/libhwcomposer/hwc_fbupdate.cpp
@@ -529,7 +529,7 @@
     const uint32_t layerClock = getLayerClock(dstWidth, dstHeight, cropHeight);
     const uint32_t mixerClock = lSplit;
 
-    if((cropWidth > qdutils::MDPVersion::getInstance().getMaxMixerWidth()) or
+    if((cropWidth > qdutils::MDPVersion::getInstance().getMaxPipeWidth()) or
             (primarySplitAlways and
             (cropWidth > lSplit or layerClock > mixerClock))) {
         destR = ov.getPipe(pipeSpecs);
diff --git a/libhwcomposer/hwc_mdpcomp.cpp b/libhwcomposer/hwc_mdpcomp.cpp
index 8e62b61..a5bf0b5 100644
--- a/libhwcomposer/hwc_mdpcomp.cpp
+++ b/libhwcomposer/hwc_mdpcomp.cpp
@@ -216,17 +216,21 @@
         ALOGE("%s: received empty data in timer callback", __FUNCTION__);
         return;
     }
-    Locker::Autolock _l(ctx->mDrawLock);
+
+    ctx->mDrawLock.lock();
     // Handle timeout event only if the previous composition is MDP or MIXED.
     if(!sHandleTimeout) {
         ALOGD_IF(isDebug(), "%s:Do not handle this timeout", __FUNCTION__);
+        ctx->mDrawLock.unlock();
         return;
     }
     if(!ctx->proc) {
         ALOGE("%s: HWC proc not registered", __FUNCTION__);
+        ctx->mDrawLock.unlock();
         return;
     }
     sIdleFallBack = true;
+    ctx->mDrawLock.unlock();
     /* Trigger SF to redraw the current frame */
     ctx->proc->invalidate(ctx->proc);
 }
@@ -426,7 +430,7 @@
                 /* On targets that doesnt support Decimation (eg.,8x26)
                  * maximum downscale support is overlay pipe downscale.
                  */
-                if(crop_w > (int) mdpHw.getMaxMixerWidth() ||
+                if(crop_w > (int) mdpHw.getMaxPipeWidth() ||
                         w_dscale > maxMDPDownscale ||
                         h_dscale > maxMDPDownscale)
                     return false;
@@ -437,7 +441,7 @@
                      *      1. Src crop > Mixer limit on nonsplit MDPComp
                      *      2. exceeds maximum downscale limit
                      */
-                    if(((crop_w > (int) mdpHw.getMaxMixerWidth()) &&
+                    if(((crop_w > (int) mdpHw.getMaxPipeWidth()) &&
                                 !sSrcSplitEnabled) ||
                             w_dscale > maxMDPDownscale ||
                             h_dscale > maxMDPDownscale) {
@@ -1891,6 +1895,33 @@
     return true;
 }
 
+void MDPComp::setDynRefreshRate(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
+    //For primary display, set the dynamic refreshrate
+    if(!mDpy && qdutils::MDPVersion::getInstance().isDynFpsSupported() &&
+                                        ctx->mUseMetaDataRefreshRate) {
+        FrameInfo frame;
+        frame.reset(mCurrentFrame.layerCount);
+        memset(&frame.drop, 0, sizeof(frame.drop));
+        frame.dropCount = 0;
+        ALOGD_IF(isDebug(), "%s: Update Cache and YUVInfo for Dyn Refresh Rate",
+                 __FUNCTION__);
+        updateLayerCache(ctx, list, frame);
+        updateYUV(ctx, list, false /*secure only*/, frame);
+        uint32_t refreshRate = ctx->dpyAttr[mDpy].refreshRate;
+        MDPVersion& mdpHw = MDPVersion::getInstance();
+        if(sIdleFallBack) {
+            //Set minimum panel refresh rate during idle timeout
+            refreshRate = mdpHw.getMinFpsSupported();
+        } else if((ctx->listStats[mDpy].yuvCount == frame.mdpCount) ||
+                                (frame.layerCount == 1)) {
+            //Set the new fresh rate, if there is only one updating YUV layer
+            //or there is one single RGB layer with this request
+            refreshRate = ctx->listStats[mDpy].refreshRateRequest;
+        }
+        setRefreshRate(ctx, mDpy, refreshRate);
+    }
+}
+
 int MDPComp::prepare(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
     int ret = 0;
     char property[PROPERTY_VALUE_MAX];
@@ -1917,19 +1948,22 @@
     if(!mDpy)
         memset(&(ctx->mPtorInfo), 0, sizeof(ctx->mPtorInfo));
 
+    //reset old data
+    mCurrentFrame.reset(numLayers);
+    memset(&mCurrentFrame.drop, 0, sizeof(mCurrentFrame.drop));
+    mCurrentFrame.dropCount = 0;
+
     //Do not cache the information for next draw cycle.
     if(numLayers > MAX_NUM_APP_LAYERS or (!numLayers)) {
         ALOGI("%s: Unsupported layer count for mdp composition",
                 __FUNCTION__);
         mCachedFrame.reset();
+#ifdef DYNAMIC_FPS
+        setDynRefreshRate(ctx, list);
+#endif
         return -1;
     }
 
-    //reset old data
-    mCurrentFrame.reset(numLayers);
-    memset(&mCurrentFrame.drop, 0, sizeof(mCurrentFrame.drop));
-    mCurrentFrame.dropCount = 0;
-
     // Detect the start of animation and fall back to GPU only once to cache
     // all the layers in FB and display FB content untill animation completes.
     if(ctx->listStats[mDpy].isDisplayAnimating) {
@@ -1940,6 +1974,9 @@
         }
         setMDPCompLayerFlags(ctx, list);
         mCachedFrame.updateCounts(mCurrentFrame);
+#ifdef DYNAMIC_FPS
+        setDynRefreshRate(ctx, list);
+#endif
         ret = -1;
         return ret;
     } else {
@@ -1992,26 +2029,7 @@
     }
 
 #ifdef DYNAMIC_FPS
-    //For primary display, set the dynamic refreshrate
-    if(!mDpy && qdutils::MDPVersion::getInstance().isDynFpsSupported() &&
-                                        ctx->mUseMetaDataRefreshRate) {
-        FrameInfo frame;
-        frame.reset(mCurrentFrame.layerCount);
-        memset(&frame.drop, 0, sizeof(frame.drop));
-        frame.dropCount = 0;
-        ALOGD_IF(isDebug(), "%s: Update Cache and YUVInfo for Dyn Refresh Rate",
-                 __FUNCTION__);
-        updateLayerCache(ctx, list, frame);
-        updateYUV(ctx, list, false /*secure only*/, frame);
-        uint32_t refreshRate = ctx->dpyAttr[mDpy].refreshRate;
-        //Set the new fresh rate, if there is only one updating YUV layer
-        //or there is one single RGB layer with this request
-        if((ctx->listStats[mDpy].yuvCount == frame.mdpCount) ||
-                                (frame.layerCount == 1)) {
-            refreshRate = ctx->listStats[mDpy].refreshRateRequest;
-        }
-        setRefreshRate(ctx, mDpy, refreshRate);
-    }
+    setDynRefreshRate(ctx, list);
 #endif
 
     mCachedFrame.cacheAll(list);
@@ -2415,10 +2433,10 @@
     eDest rDest = mdp_info.rIndex;
 
     ALOGD_IF(isDebug(),"%s: configuring: layer: %p z_order: %d dest_pipeL: %d"
-             "dest_pipeR: %d",__FUNCTION__, layer, zOrder, lDest, rDest);
+            "dest_pipeR: %d",__FUNCTION__, layer, zOrder, lDest, rDest);
 
     return configureSplit(ctx, layer, mDpy, mdpFlagsL, zOrder, lDest,
-                            rDest, &PipeLayerPair.rot);
+            rDest, &PipeLayerPair.rot);
 }
 
 bool MDPCompSplit::draw(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
@@ -2602,8 +2620,8 @@
     //pipe line length, we are still using 2 pipes. This is fine just because
     //this is source split where destination doesn't matter. Evaluate later to
     //see if going through all the calcs to save a pipe is worth it
-    if(dstWidth > mdpHw.getMaxMixerWidth() or
-            cropWidth > mdpHw.getMaxMixerWidth() or
+    if(dstWidth > mdpHw.getMaxPipeWidth() or
+            cropWidth > mdpHw.getMaxPipeWidth() or
             (primarySplitAlways and
             (cropWidth > lSplit or layerClock > mixerClock))) {
         pipe_info.rIndex = ctx->mOverlay->getPipe(pipeSpecs);
diff --git a/libhwcomposer/hwc_mdpcomp.h b/libhwcomposer/hwc_mdpcomp.h
index 3ce4a64..4978182 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);
+    void setDynRefreshRate(hwc_context_t *ctx, hwc_display_contents_1_t* list);
+
 protected:
     enum ePipeType {
         MDPCOMP_OV_RGB = ovutils::OV_MDP_PIPE_RGB,
diff --git a/libhwcomposer/hwc_qclient.cpp b/libhwcomposer/hwc_qclient.cpp
index 1a29b89..09013c6 100644
--- a/libhwcomposer/hwc_qclient.cpp
+++ b/libhwcomposer/hwc_qclient.cpp
@@ -59,34 +59,39 @@
 }
 
 static void securing(hwc_context_t *ctx, uint32_t startEnd) {
-    Locker::Autolock _sl(ctx->mDrawLock);
     //The only way to make this class in this process subscribe to media
     //player's death.
     IMediaDeathNotifier::getMediaPlayerService();
 
+    ctx->mDrawLock.lock();
     ctx->mSecuring = startEnd;
     //We're done securing
     if(startEnd == IQService::END)
         ctx->mSecureMode = true;
+    ctx->mDrawLock.unlock();
+
     if(ctx->proc)
         ctx->proc->invalidate(ctx->proc);
 }
 
 static void unsecuring(hwc_context_t *ctx, uint32_t startEnd) {
-    Locker::Autolock _sl(ctx->mDrawLock);
+    ctx->mDrawLock.lock();
     ctx->mSecuring = startEnd;
     //We're done unsecuring
     if(startEnd == IQService::END)
         ctx->mSecureMode = false;
+    ctx->mDrawLock.unlock();
+
     if(ctx->proc)
         ctx->proc->invalidate(ctx->proc);
 }
 
 void QClient::MPDeathNotifier::died() {
-    Locker::Autolock _sl(mHwcContext->mDrawLock);
+    mHwcContext->mDrawLock.lock();
     ALOGD_IF(QCLIENT_DEBUG, "Media Player died");
     mHwcContext->mSecuring = false;
     mHwcContext->mSecureMode = false;
+    mHwcContext->mDrawLock.unlock();
     if(mHwcContext->proc)
         mHwcContext->proc->invalidate(mHwcContext->proc);
 }
@@ -315,8 +320,8 @@
 
 static void toggleScreenUpdate(hwc_context_t* ctx, uint32_t on) {
     ALOGD("%s: toggle update: %d", __FUNCTION__, on);
-    Locker::Autolock _sl(ctx->mDrawLock);
     if (on == 0) {
+        ctx->mDrawLock.lock();
         ctx->dpyAttr[HWC_DISPLAY_PRIMARY].isPause = true;
         ctx->mOverlay->configBegin();
         ctx->mOverlay->configDone();
@@ -324,8 +329,11 @@
         if(!Overlay::displayCommit(ctx->dpyAttr[0].fd)) {
             ALOGE("%s: Display commit failed", __FUNCTION__);
         }
+        ctx->mDrawLock.unlock();
     } else {
+        ctx->mDrawLock.lock();
         ctx->dpyAttr[HWC_DISPLAY_PRIMARY].isPause = false;
+        ctx->mDrawLock.unlock();
         ctx->proc->invalidate(ctx->proc);
     }
 }
@@ -377,6 +385,7 @@
             break;
         case IQService::SET_MAX_PIPES_PER_MIXER:
             setMaxPipesPerMixer(mHwcContext, inParcel);
+            break;
         case IQService::SET_PARTIAL_UPDATE:
             ret = setPartialUpdatePref(mHwcContext, inParcel->readInt32());
             break;
diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp
index bcac4be..4f3dbf0 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -86,7 +86,7 @@
 
 bool isValidResolution(hwc_context_t *ctx, uint32_t xres, uint32_t yres)
 {
-    return !((xres > qdutils::MDPVersion::getInstance().getMaxMixerWidth() &&
+    return !((xres > qdutils::MDPVersion::getInstance().getMaxPipeWidth() &&
                 !isDisplaySplit(ctx, HWC_DISPLAY_PRIMARY)) ||
             (xres < MIN_DISPLAY_XRES || yres < MIN_DISPLAY_YRES));
 }
@@ -2239,8 +2239,6 @@
         (*rot) = ctx->mRotMgr->getNext();
         if((*rot) == NULL) return -1;
         ctx->mLayerRotMap[dpy]->add(layer, *rot);
-        BwcPM::setBwc(ctx, dpy, hnd, crop, dst, transform, downscale,
-                mdpFlagsL);
         //Configure rotator for pre-rotation
         if(configRotator(*rot, whf, crop, mdpFlagsL, orient, downscale) < 0) {
             ALOGE("%s: configRotator failed!", __FUNCTION__);
@@ -2354,7 +2352,7 @@
 
 bool isDisplaySplit(hwc_context_t* ctx, int dpy) {
     qdutils::MDPVersion& mdpHw = qdutils::MDPVersion::getInstance();
-    if(ctx->dpyAttr[dpy].xres > mdpHw.getMaxMixerWidth()) {
+    if(ctx->dpyAttr[dpy].xres > mdpHw.getMaxPipeWidth()) {
         return true;
     }
     //For testing we could split primary via device tree values
@@ -2521,7 +2519,7 @@
         swap(src_w, src_h);
     }
     //src width > MAX mixer supported dim
-    if(src_w > (int) qdutils::MDPVersion::getInstance().getMaxMixerWidth()) {
+    if(src_w > (int) qdutils::MDPVersion::getInstance().getMaxPipeWidth()) {
         return;
     }
     //Decimation necessary, cannot use BWC. H/W requirement.
diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h
index 18de082..797f9b0 100644
--- a/libhwcomposer/hwc_utils.h
+++ b/libhwcomposer/hwc_utils.h
@@ -459,9 +459,9 @@
 
 // Returns true if the buffer is yuv and exceeds the mixer width
 static inline bool isYUVSplitNeeded(const private_handle_t* hnd) {
-    int maxMixerWidth = qdutils::MDPVersion::getInstance().getMaxMixerWidth();
+    int maxPipeWidth = qdutils::MDPVersion::getInstance().getMaxPipeWidth();
     return (hnd && (hnd->bufferType == BUFFER_TYPE_VIDEO) &&
-            (hnd->width > maxMixerWidth));
+            (hnd->width > maxPipeWidth));
 }
 
 // Returns true if the buffer is secure
diff --git a/liboverlay/overlayUtils.cpp b/liboverlay/overlayUtils.cpp
index 32b2013..b772a6e 100644
--- a/liboverlay/overlayUtils.cpp
+++ b/liboverlay/overlayUtils.cpp
@@ -277,7 +277,7 @@
     if((int)verDscale)
         vertDeci = (uint8_t)log2f(verDscale);
 
-    if(src_w > (int) mdpHw.getMaxMixerWidth()) {
+    if(src_w > (int) mdpHw.getMaxPipeWidth()) {
         //If the client sends us something > what a layer mixer supports
         //then it means it doesn't want to use split-pipe but wants us to
         //decimate. A minimum decimation of 2 will ensure that the width is
diff --git a/libqdutils/mdp_version.cpp b/libqdutils/mdp_version.cpp
index 8ca0824..402e129 100644
--- a/libqdutils/mdp_version.cpp
+++ b/libqdutils/mdp_version.cpp
@@ -75,7 +75,7 @@
 #define MDSS_MDP_HW_REV_109 0x10090000 //8994 v2
 #endif
 #ifndef MDSS_MDP_HW_REV_110
-#define MDSS_MDP_HW_REV_110 0x100a0000 //Next version
+#define MDSS_MDP_HW_REV_110 0x100a0000 //8992
 #endif
 #ifndef MDSS_MDP_HW_REV_200
 #define MDSS_MDP_HW_REV_200 0x20000000 //8092
@@ -104,9 +104,13 @@
     mBlendStages = 4; //min no. of stages supported by MDP.
 
     // this is the default limit of mixer unless driver reports it.
-    // For resolutions beyond this, we use dual/split overlay pipes.
+    // For resolutions beyond this, we use dual mixer/ping pong split.
     mMaxMixerWidth = 2048;
 
+    // Default width of MDSS SSPP. For layer resolutions beyond this, we drive
+    // using two SSPP's.
+    mMaxPipeWidth = 2048;
+
     updatePanelInfo();
 
     if(!updateSysFsInfo()) {
@@ -324,6 +328,9 @@
                 } else if(!strncmp(tokens[0], "max_mixer_width",
                         strlen("max_mixer_width"))) {
                     mMaxMixerWidth = atoi(tokens[1]);
+                } else if(!strncmp(tokens[0], "max_pipe_width",
+                        strlen("max_pipe_width"))) {
+                    mMaxPipeWidth = atoi(tokens[1]);
                 } else if(!strncmp(tokens[0], "features", strlen("features"))) {
                     for(int i=1; i<index;i++) {
                         if(!strncmp(tokens[i], "bwc", strlen("bwc"))) {
diff --git a/libqdutils/mdp_version.h b/libqdutils/mdp_version.h
index dcde240..3b10010 100644
--- a/libqdutils/mdp_version.h
+++ b/libqdutils/mdp_version.h
@@ -139,6 +139,7 @@
     uint32_t getMinFpsSupported() { return mPanelInfo.mMinFps; }
     uint32_t getMaxFpsSupported() { return mPanelInfo.mMaxFps; }
     uint32_t getMaxMixerWidth() const { return mMaxMixerWidth; }
+    uint32_t getMaxPipeWidth() const { return mMaxPipeWidth; }
     bool hasMinCropWidthLimitation() const;
     bool isSrcSplit() const;
     bool isSrcSplitAlways() const;
@@ -179,6 +180,7 @@
     bool mRGBHasNoScalar;
     bool mRotDownscale;
     uint32_t mMaxMixerWidth; //maximum x-res of a given mdss mixer.
+    uint32_t mMaxPipeWidth; //maximum x-res of the mdp pipe.
 };
 }; //namespace qdutils
 #endif //INCLUDE_LIBQCOMUTILS_MDPVER