Merge "sde: Move locking to each display interface implementation"
diff --git a/displayengine/include/core/layer_buffer.h b/displayengine/include/core/layer_buffer.h
index 9f7110a..e4a73c3 100644
--- a/displayengine/include/core/layer_buffer.h
+++ b/displayengine/include/core/layer_buffer.h
@@ -49,7 +49,10 @@
   kFormatXRGB8888,      //!< 8-bits Padding, Red, Green, Blue interleaved in XRGB order. No Alpha.
   kFormatRGBX8888,      //!< 8-bits Red, Green, Blue, Padding interleaved in RGBX order. No Alpha.
   kFormatBGRX8888,      //!< 8-bits Blue, Green, Red, Padding interleaved in BGRX order. No Alpha.
+  kFormatRGBA5551,      //!< 5-bits Red, Green, Blue, and 1 bit Alpha interleaved in RGBA order.
+  kFormatRGBA4444,      //!< 4-bits Red, Green, Blue, Alpha interleaved in RGBA order.
   kFormatRGB888,        //!< 8-bits Red, Green, Blue interleaved in RGB order. No Alpha.
+  kFormatBGR888,        //!< 8-bits Blue, Green, Red interleaved in BGR order. No Alpha.
   kFormatRGB565,        //!< 5-bit Red, 6-bit Green, 5-bit Blue interleaved in RGB order. No Alpha.
 
   /* All YUV-Planar formats, Any new format will be added towards end of this group to maintain
@@ -80,13 +83,29 @@
                                       //!< 2x2 subsampled interleaved UV-plane:
                                       //!<    u(0), v(0), u(2), v(2) ... u(n-1), v(n-1)
 
+  kFormatYCbCr422H1V2SemiPlanar,      //!< Y-plane: y(0), y(1), y(2) ... y(n)
+                                      //!< vertically subsampled interleaved UV-plane:
+                                      //!<    u(0), v(1), u(2), v(3) ... u(n-1), v(n)
+
+  kFormatYCrCb422H1V2SemiPlanar,      //!< Y-plane: y(0), y(1), y(2) ... y(n)
+                                      //!< vertically subsampled interleaved VU-plane:
+                                      //!<    v(0), u(1), v(2), u(3) ... v(n-1), u(n)
+
+  kFormatYCbCr422H2V1SemiPlanar,      //!< Y-plane: y(0), y(1), y(2) ... y(n)
+                                      //!< horizontally subsampled interleaved UV-plane:
+                                      //!<    u(0), v(1), u(2), v(3) ... u(n-1), v(n)
+
+  kFormatYCrCb422H2V1SemiPlanar,      //!< Y-plane: y(0), y(1), y(2) ... y(n)
+                                      //!< horizontally subsampled interleaved VU-plane:
+                                      //!<    v(0), u(1), v(2), u(3) ... v(n-1), u(n)
+
   /* All YUV-Packed formats, Any new format will be added towards end of this group to maintain
      backward compatibility.
   */
-  kFormatYCbCr422Packed = 0x300,      //!< Y-plane interleaved with horizontally subsampled U/V by
+  kFormatYCbCr422H2V1Packed = 0x300,  //!< Y-plane interleaved with horizontally subsampled U/V by
                                       //!< factor of 2
-                                      //!<    u(0), y(0), v(0), y(1), u(2), y(2), v(2), y(3)
-                                      //!<    u(n-1), y(n-1), v(n-1), y(n)
+                                      //!<    y(0), u(0), y(1), v(0), y(2), u(2), y(3), v(2)
+                                      //!<    y(n-1), u(n-1), y(n), v(n-1)
 
   /* All UBWC aligned formats. Any new format will be added towards end of this group to maintain
      backward compatibility.
diff --git a/displayengine/include/utils/constants.h b/displayengine/include/utils/constants.h
index 44e211c..1a7d62a 100644
--- a/displayengine/include/utils/constants.h
+++ b/displayengine/include/utils/constants.h
@@ -56,6 +56,8 @@
 
 #define IDLE_TIMEOUT_DEFAULT_MS 70
 
+#define IS_RGB_FORMAT(format) (((format) < kFormatYCbCr420Planar) ? true: false)
+
 template <class T>
 inline void Swap(T &a, T &b) {
   T c(a);
diff --git a/displayengine/libs/core/fb/hw_device.cpp b/displayengine/libs/core/fb/hw_device.cpp
index ed19d80..6054ae0 100644
--- a/displayengine/libs/core/fb/hw_device.cpp
+++ b/displayengine/libs/core/fb/hw_device.cpp
@@ -488,13 +488,20 @@
   case kFormatBGRA8888:                 *target = MDP_BGRA_8888;         break;
   case kFormatRGBX8888:                 *target = MDP_RGBX_8888;         break;
   case kFormatBGRX8888:                 *target = MDP_BGRX_8888;         break;
+  case kFormatRGBA5551:                 *target = MDP_RGBA_5551;         break;
+  case kFormatRGBA4444:                 *target = MDP_RGBA_4444;         break;
   case kFormatRGB888:                   *target = MDP_RGB_888;           break;
+  case kFormatBGR888:                   *target = MDP_BGR_888;           break;
   case kFormatRGB565:                   *target = MDP_RGB_565;           break;
   case kFormatYCbCr420Planar:           *target = MDP_Y_CB_CR_H2V2;      break;
   case kFormatYCrCb420Planar:           *target = MDP_Y_CR_CB_H2V2;      break;
   case kFormatYCbCr420SemiPlanar:       *target = MDP_Y_CBCR_H2V2;       break;
   case kFormatYCrCb420SemiPlanar:       *target = MDP_Y_CRCB_H2V2;       break;
-  case kFormatYCbCr422Packed:           *target = MDP_YCBYCR_H2V1;       break;
+  case kFormatYCbCr422H1V2SemiPlanar:   *target = MDP_Y_CBCR_H1V2;       break;
+  case kFormatYCrCb422H1V2SemiPlanar:   *target = MDP_Y_CRCB_H1V2;       break;
+  case kFormatYCbCr422H2V1SemiPlanar:   *target = MDP_Y_CBCR_H2V1;       break;
+  case kFormatYCrCb422H2V1SemiPlanar:   *target = MDP_Y_CRCB_H2V1;       break;
+  case kFormatYCbCr422H2V1Packed:       *target = MDP_YCBYCR_H2V1;       break;
   case kFormatYCbCr420SemiPlanarVenus:  *target = MDP_Y_CBCR_H2V2_VENUS; break;
   case kFormatRGBA8888Ubwc:             *target = MDP_RGBA_8888_UBWC;    break;
   case kFormatRGB565Ubwc:               *target = MDP_RGB_565_UBWC;      break;
@@ -525,6 +532,7 @@
     *target = width * 4;
     break;
   case kFormatRGB888:
+  case kFormatBGR888:
     *target = width * 3;
     break;
   case kFormatRGB565:
@@ -538,7 +546,13 @@
   case kFormatYCrCb420SemiPlanar:
     *target = width;
     break;
-  case kFormatYCbCr422Packed:
+  case kFormatYCbCr422H2V1Packed:
+  case kFormatYCrCb422H2V1SemiPlanar:
+  case kFormatYCrCb422H1V2SemiPlanar:
+  case kFormatYCbCr422H2V1SemiPlanar:
+  case kFormatYCbCr422H1V2SemiPlanar:
+  case kFormatRGBA5551:
+  case kFormatRGBA4444:
     *target = width * 2;
     break;
   default:
diff --git a/displayengine/libs/core/res_config.cpp b/displayengine/libs/core/res_config.cpp
index b4aa779..ea90dfb 100644
--- a/displayengine/libs/core/res_config.cpp
+++ b/displayengine/libs/core/res_config.cpp
@@ -33,6 +33,15 @@
 
 namespace sde {
 
+static void GetAlignFactor(const LayerBufferFormat &format, uint32_t *align_x, uint32_t *align_y) {
+  *align_x = 1;
+  *align_y = 1;
+  if (!IS_RGB_FORMAT(format)) {
+    *align_x = 2;
+    *align_y = 2;
+  }
+}
+
 void ResManager::RotationConfig(LayerBufferFormat format, const LayerTransform &transform,
                                 const float &downscale, LayerRect *src_rect,
                                 struct HWLayerConfig *layer_config, uint32_t *rotate_count) {
@@ -46,22 +55,24 @@
   dst_rect.left = 0.0f;
 
   rotate->downscale_ratio = downscale;
+  uint32_t align_x, align_y;
+  GetAlignFactor(format, &align_x, &align_y);
 
   // downscale when doing rotation
   if (rot90) {
     if (downscale > 1.0f) {
-      src_height = ROUND_UP_ALIGN_DOWN(src_height, downscale);
+      src_height = ROUND_UP_ALIGN_DOWN(src_height, downscale * FLOAT(align_x));
       src_rect->bottom = src_rect->top + src_height;
-      src_width = ROUND_UP_ALIGN_DOWN(src_width, downscale);
+      src_width = ROUND_UP_ALIGN_DOWN(src_width, downscale * FLOAT(align_y));
       src_rect->right = src_rect->left + src_width;
     }
     dst_rect.right = src_height / downscale;
     dst_rect.bottom = src_width / downscale;
   } else {
     if (downscale > 1.0f) {
-      src_width = ROUND_UP_ALIGN_DOWN(src_width, downscale);
+      src_width = ROUND_UP_ALIGN_DOWN(src_width, downscale * FLOAT(align_x));
       src_rect->right = src_rect->left + src_width;
-      src_height = ROUND_UP_ALIGN_DOWN(src_height, downscale);
+      src_height = ROUND_UP_ALIGN_DOWN(src_height, downscale * FLOAT(align_y));
       src_rect->bottom = src_rect->top + src_height;
     }
     dst_rect.right = src_width / downscale;
@@ -250,11 +261,9 @@
       continue;
     }
 
-    uint32_t align_x = 1, align_y = 1;
-    if (IsYuvFormat(layer.input_buffer->format)) {
-      // TODO(user) Select x and y alignment according to the format
-      align_x = 2;
-      align_y = 2;
+    uint32_t align_x, align_y;
+    GetAlignFactor(layer.input_buffer->format, &align_x, &align_y);
+    if (align_x > 1 || align_y > 1) {
       NormalizeRect(align_x, align_y, &src_rect);
     }
 
diff --git a/displayengine/libs/core/res_manager.cpp b/displayengine/libs/core/res_manager.cpp
index 238dfa8..09b64ab 100644
--- a/displayengine/libs/core/res_manager.cpp
+++ b/displayengine/libs/core/res_manager.cpp
@@ -325,8 +325,7 @@
 
     HWPipeInfo *pipe_info = &layer_config.left_pipe;
 
-    // Should have a generic macro
-    bool is_yuv = IsYuvFormat(layer.input_buffer->format);
+    bool is_yuv = !IS_RGB_FORMAT(layer.input_buffer->format);
 
     // left pipe is needed
     if (pipe_info->valid) {
@@ -619,9 +618,16 @@
     case kFormatBGRX8888:
       return 4.0f;
     case kFormatRGB888:
+    case kFormatBGR888:
       return 3.0f;
     case kFormatRGB565:
-    case kFormatYCbCr422Packed:
+    case kFormatRGBA5551:
+    case kFormatRGBA4444:
+    case kFormatYCbCr422H2V1Packed:
+    case kFormatYCrCb422H2V1SemiPlanar:
+    case kFormatYCrCb422H1V2SemiPlanar:
+    case kFormatYCbCr422H2V1SemiPlanar:
+    case kFormatYCbCr422H1V2SemiPlanar:
       return 2.0f;
     case kFormatYCbCr420Planar:
     case kFormatYCrCb420Planar:
diff --git a/displayengine/libs/core/res_manager.h b/displayengine/libs/core/res_manager.h
index b2ddcb9..7f78b29 100644
--- a/displayengine/libs/core/res_manager.h
+++ b/displayengine/libs/core/res_manager.h
@@ -194,7 +194,6 @@
                  LayerRect *src_left, LayerRect *dst_left, LayerRect *src_right,
                  LayerRect *dst_right, uint32_t align_x);
   bool IsMacroTileFormat(const LayerBuffer *buffer) { return buffer->flags.macro_tile; }
-  bool IsYuvFormat(LayerBufferFormat format) { return (format >= kFormatYCbCr420Planar); }
   bool IsRotationNeeded(float rotation)
          { return (UINT32(rotation) == 90 || UINT32(rotation) == 270); }
   void RotationConfig(LayerBufferFormat format, const LayerTransform &transform,
diff --git a/displayengine/libs/core/scalar_helper.cpp b/displayengine/libs/core/scalar_helper.cpp
old mode 100755
new mode 100644
index 22488b3..55b462f
--- a/displayengine/libs/core/scalar_helper.cpp
+++ b/displayengine/libs/core/scalar_helper.cpp
@@ -75,13 +75,20 @@
   case kFormatXRGB8888:                 format = scalar::XRGB_8888;         break;
   case kFormatRGBX8888:                 format = scalar::RGBX_8888;         break;
   case kFormatBGRX8888:                 format = scalar::BGRX_8888;         break;
+  case kFormatRGBA5551:                 format = scalar::RGBA_5551;         break;
+  case kFormatRGBA4444:                 format = scalar::RGBA_4444;         break;
   case kFormatRGB888:                   format = scalar::RGB_888;           break;
+  case kFormatBGR888:                   format = scalar::BGR_888;           break;
   case kFormatRGB565:                   format = scalar::RGB_565;           break;
   case kFormatYCbCr420Planar:           format = scalar::Y_CB_CR_H2V2;      break;
   case kFormatYCrCb420Planar:           format = scalar::Y_CR_CB_H2V2;      break;
   case kFormatYCbCr420SemiPlanar:       format = scalar::Y_CBCR_H2V2;       break;
   case kFormatYCrCb420SemiPlanar:       format = scalar::Y_CRCB_H2V2;       break;
-  case kFormatYCbCr422Packed:           format = scalar::YCBYCR_H2V1;       break;
+  case kFormatYCbCr422H1V2SemiPlanar:   format = scalar::Y_CBCR_H1V2;       break;
+  case kFormatYCrCb422H1V2SemiPlanar:   format = scalar::Y_CRCB_H1V2;       break;
+  case kFormatYCbCr422H2V1SemiPlanar:   format = scalar::Y_CBCR_H2V1;       break;
+  case kFormatYCrCb422H2V1SemiPlanar:   format = scalar::Y_CRCB_H2V1;       break;
+  case kFormatYCbCr422H2V1Packed:       format = scalar::YCBYCR_H2V1;       break;
   case kFormatYCbCr420SemiPlanarVenus:  format = scalar::Y_CBCR_H2V2_VENUS; break;
   case kFormatRGBA8888Ubwc:             format = scalar::RGBA_8888_UBWC;    break;
   case kFormatRGB565Ubwc:               format = scalar::RGB_565_UBWC;      break;
diff --git a/displayengine/libs/hwc/hwc_buffer_allocator.cpp b/displayengine/libs/hwc/hwc_buffer_allocator.cpp
index f2383b2..2adfc3a 100644
--- a/displayengine/libs/hwc/hwc_buffer_allocator.cpp
+++ b/displayengine/libs/hwc/hwc_buffer_allocator.cpp
@@ -157,9 +157,12 @@
   case kFormatYCrCb420Planar:           *target = HAL_PIXEL_FORMAT_YV12;                  break;
   case kFormatYCrCb420SemiPlanar:       *target = HAL_PIXEL_FORMAT_YCrCb_420_SP;          break;
   case kFormatYCbCr420SemiPlanar:       *target = HAL_PIXEL_FORMAT_YCbCr_420_SP;          break;
-  case kFormatYCbCr422Packed:           *target = HAL_PIXEL_FORMAT_YCbCr_422_I;           break;
+  case kFormatYCbCr422H2V1Packed:       *target = HAL_PIXEL_FORMAT_YCbCr_422_I;           break;
+  case kFormatYCbCr422H2V1SemiPlanar:   *target = HAL_PIXEL_FORMAT_YCbCr_422_SP;          break;
   case kFormatYCbCr420SemiPlanarVenus:  *target = HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS;    break;
   case kFormatYCbCr420SPVenusUbwc:    *target = HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS_UBWC; break;
+  case kFormatRGBA5551:                 *target = HAL_PIXEL_FORMAT_RGBA_5551;             break;
+  case kFormatRGBA4444:                 *target = HAL_PIXEL_FORMAT_RGBA_4444;             break;
 
   default:
     DLOGE("Unsupported format = 0x%x", format);
diff --git a/displayengine/libs/hwc/hwc_display.cpp b/displayengine/libs/hwc/hwc_display.cpp
index 654fc85..e2327c5 100644
--- a/displayengine/libs/hwc/hwc_display.cpp
+++ b/displayengine/libs/hwc/hwc_display.cpp
@@ -105,10 +105,12 @@
     break;
   case HWC_POWER_MODE_NORMAL:
     state = kStateOn;
+    last_power_mode_ = HWC_POWER_MODE_NORMAL;
     break;
   case HWC_POWER_MODE_DOZE:
   case HWC_POWER_MODE_DOZE_SUSPEND:
     state = kStateDoze;
+    last_power_mode_ = HWC_POWER_MODE_DOZE;
     break;
   default:
     return -EINVAL;
@@ -208,6 +210,10 @@
   DLOGI("num_frame_dump %d, input_layer_dump_enable %d", dump_frame_count_, dump_input_layers_);
 }
 
+uint32_t HWCDisplay::GetLastPowerMode() {
+  return last_power_mode_;
+}
+
 DisplayError HWCDisplay::VSync(const DisplayEventVSync &vsync) {
   if (*hwc_procs_) {
     (*hwc_procs_)->vsync(*hwc_procs_, id_, vsync.timestamp);
@@ -628,6 +634,8 @@
 
   switch (source) {
   case HAL_PIXEL_FORMAT_RGBA_8888:                format = kFormatRGBA8888;                 break;
+  case HAL_PIXEL_FORMAT_RGBA_5551:                format = kFormatRGBA5551;                 break;
+  case HAL_PIXEL_FORMAT_RGBA_4444:                format = kFormatRGBA4444;                 break;
   case HAL_PIXEL_FORMAT_BGRA_8888:                format = kFormatBGRA8888;                 break;
   case HAL_PIXEL_FORMAT_RGBX_8888:                format = kFormatRGBX8888;                 break;
   case HAL_PIXEL_FORMAT_BGRX_8888:                format = kFormatBGRX8888;                 break;
@@ -637,6 +645,8 @@
   case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS:       format = kFormatYCbCr420SemiPlanarVenus;  break;
   case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS_UBWC:  format = kFormatYCbCr420SPVenusUbwc;      break;
   case HAL_PIXEL_FORMAT_YCrCb_420_SP:             format = kFormatYCrCb420SemiPlanar;       break;
+  case HAL_PIXEL_FORMAT_YCbCr_422_SP:             format = kFormatYCbCr422H2V1SemiPlanar;   break;
+  case HAL_PIXEL_FORMAT_YCbCr_422_I:              format = kFormatYCbCr422H2V1Packed;       break;
   default:
     DLOGW("Unsupported format type = %d", source);
     return kFormatInvalid;
diff --git a/displayengine/libs/hwc/hwc_display.h b/displayengine/libs/hwc/hwc_display.h
index 8feddf6..7ef8187 100644
--- a/displayengine/libs/hwc/hwc_display.h
+++ b/displayengine/libs/hwc/hwc_display.h
@@ -46,6 +46,7 @@
   virtual int SetActiveConfig(hwc_display_contents_1_t *content_list);
   virtual void SetFrameDumpConfig(uint32_t count, uint32_t bit_mask_layer_type);
   virtual DisplayError SetMaxMixerStages(uint32_t max_mixer_stages);
+  virtual uint32_t GetLastPowerMode();
 
  protected:
   // Maximum number of layers supported by display engine.
@@ -117,6 +118,7 @@
   uint32_t dump_frame_count_;
   uint32_t dump_frame_index_;
   bool dump_input_layers_;
+  uint32_t last_power_mode_;
 };
 
 }  // namespace sde
diff --git a/displayengine/libs/hwc/hwc_session.cpp b/displayengine/libs/hwc/hwc_session.cpp
index b6d0c18..4498f18 100644
--- a/displayengine/libs/hwc/hwc_session.cpp
+++ b/displayengine/libs/hwc/hwc_session.cpp
@@ -44,6 +44,9 @@
 
 #define __CLASS__ "HWCSession"
 
+#define HWC_UEVENT_SWITCH_HDMI "change@/devices/virtual/switch/hdmi"
+#define HWC_UEVENT_GRAPHICS_FB0 "change@/devices/virtual/graphics/fb0"
+
 static sde::HWCSession::HWCModuleMethods g_hwc_module_methods;
 
 hwc_module_t HAL_MODULE_INFO_SYM = {
@@ -63,10 +66,11 @@
 namespace sde {
 
 Locker HWCSession::locker_;
+bool HWCSession::reset_panel_ = false;
 
 HWCSession::HWCSession(const hw_module_t *module) : core_intf_(NULL), hwc_procs_(NULL),
             display_primary_(NULL), display_external_(NULL), display_virtual_(NULL),
-            hotplug_thread_exit_(false), hotplug_thread_name_("HWC_HotPlugThread") {
+            uevent_thread_exit_(false), uevent_thread_name_("HWC_UeventThread") {
   hwc_composer_device_1_t::common.tag = HARDWARE_DEVICE_TAG;
   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);
@@ -141,8 +145,8 @@
     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_);
+  if (pthread_create(&uevent_thread_, NULL, &HWCUeventThread, this) < 0) {
+    DLOGE("Failed to start = %s, error = %s", uevent_thread_name_);
     display_primary_->Deinit();
     delete display_primary_;
     CoreInterface::DestroyCore();
@@ -156,8 +160,8 @@
   display_primary_->SetPowerMode(HWC_POWER_MODE_OFF);
   display_primary_->Deinit();
   delete display_primary_;
-  hotplug_thread_exit_ = true;
-  pthread_join(hotplug_thread_, NULL);
+  uevent_thread_exit_ = true;
+  pthread_join(uevent_thread_, NULL);
 
   DisplayError error = CoreInterface::DestroyCore();
   if (error != kErrorNone) {
@@ -218,6 +222,11 @@
 
   HWCSession *hwc_session = static_cast<HWCSession *>(device);
 
+  if (reset_panel_) {
+    DLOGW("panel is in bad state, resetting the panel");
+    hwc_session->ResetPanel();
+  }
+
   for (ssize_t i = (num_displays-1); i >= 0; i--) {
     hwc_display_contents_1_t *content_list = displays[i];
 
@@ -690,18 +699,18 @@
   }
 }
 
-void* HWCSession::HWCHotPlugThread(void *context) {
+void* HWCSession::HWCUeventThread(void *context) {
   if (context) {
-    return reinterpret_cast<HWCSession *>(context)->HWCHotPlugThreadHandler();
+    return reinterpret_cast<HWCSession *>(context)->HWCUeventThreadHandler();
   }
 
   return NULL;
 }
 
-void* HWCSession::HWCHotPlugThreadHandler() {
+void* HWCSession::HWCUeventThreadHandler() {
   static char uevent_data[PAGE_SIZE];
   int length = 0;
-  prctl(PR_SET_NAME, hotplug_thread_name_, 0, 0, 0);
+  prctl(PR_SET_NAME, uevent_thread_name_, 0, 0, 0);
   setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY);
   if (!uevent_init()) {
     DLOGE("Failed to init uevent");
@@ -709,19 +718,28 @@
     return NULL;
   }
 
-  while (!hotplug_thread_exit_) {
+  while (!uevent_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");
+    if (strcasestr(HWC_UEVENT_SWITCH_HDMI, uevent_data)) {
+      DLOGI("Uevent HDMI = %s", uevent_data);
+      int connected = GetEventValue(uevent_data, length, "SWITCH_STATE=");
+      if (connected >= 0) {
+        DLOGI("HDMI = %s", connected ? "connected" : "disconnected");
+        if (HotPlugHandler(connected) == -1) {
+          DLOGE("Failed handling Hotplug = %s", connected ? "connected" : "disconnected");
+        }
+      }
+    } else if (strcasestr(HWC_UEVENT_GRAPHICS_FB0, uevent_data)) {
+      DLOGI("Uevent FB0 = %s", uevent_data);
+      int panel_reset = GetEventValue(uevent_data, length, "PANEL_ALIVE=");
+      if (panel_reset == 0) {
+        if (hwc_procs_) {
+          reset_panel_ = true;
+          hwc_procs_->invalidate(hwc_procs_);
+        } else
+          DLOGW("Ignore resetpanel - hwc_proc not registered");
       }
     }
   }
@@ -730,18 +748,43 @@
   return NULL;
 }
 
-int HWCSession::GetHDMIConnectedState(const char *uevent_data, int length) {
-  const char* iterator_str = uevent_data;
+int HWCSession::GetEventValue(const char *uevent_data, int length, const char *event_info) {
+  const char *iterator_str = uevent_data;
   while (((iterator_str - uevent_data) <= length) && (*iterator_str)) {
-    char* pstr = strstr(iterator_str, "SWITCH_STATE=");
+    char *pstr = strstr(iterator_str, event_info);
     if (pstr != NULL) {
-      return (atoi(iterator_str + strlen("SWITCH_STATE=")));
+      return (atoi(iterator_str + strlen(event_info)));
     }
     iterator_str += strlen(iterator_str) + 1;
   }
+
   return -1;
 }
 
+void HWCSession::ResetPanel() {
+  int status = -EINVAL;
+
+  DLOGI("Powering off primary");
+  status = display_primary_->SetPowerMode(HWC_POWER_MODE_OFF);
+  if (status) {
+    DLOGE("power-off on primary failed with error = %d",status);
+  }
+
+  DLOGI("Restoring power mode on primary");
+  uint32_t mode = display_primary_->GetLastPowerMode();
+  status = display_primary_->SetPowerMode(mode);
+  if (status) {
+    DLOGE("Setting power mode = %d on primary failed with error = %d", mode,status);
+  }
+
+  status = display_primary_->EventControl(HWC_EVENT_VSYNC, 1);
+  if (status) {
+    DLOGE("enabling vsync failed for primary with error = %d",status);
+  }
+
+  reset_panel_ = false;
+}
+
 int HWCSession::HotPlugHandler(bool connected) {
   if (!hwc_procs_) {
      DLOGW("Ignore hotplug - hwc_proc not registered");
diff --git a/displayengine/libs/hwc/hwc_session.h b/displayengine/libs/hwc/hwc_session.h
index 1608ce5..3c5cc7f 100644
--- a/displayengine/libs/hwc/hwc_session.h
+++ b/displayengine/libs/hwc/hwc_session.h
@@ -68,11 +68,12 @@
   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);
+  // Uevent thread
+  static void* HWCUeventThread(void *context);
+  void* HWCUeventThreadHandler();
+  int GetEventValue(const char *uevent_data, int length, const char *event_info);
   int HotPlugHandler(bool connected);
+  void ResetPanel();
   bool ValidateContentList(hwc_display_contents_1_t *content_list);
   int CreateVirtualDisplay(HWCSession *hwc_session, hwc_display_contents_1_t *content_list);
   int DestroyVirtualDisplay(HWCSession *hwc_session);
@@ -93,9 +94,10 @@
   HWCDisplayPrimary *display_primary_;
   HWCDisplayExternal *display_external_;
   HWCDisplayVirtual *display_virtual_;
-  pthread_t hotplug_thread_;
-  bool hotplug_thread_exit_;
-  const char *hotplug_thread_name_;
+  pthread_t uevent_thread_;
+  bool uevent_thread_exit_;
+  static bool reset_panel_;
+  const char *uevent_thread_name_;
   HWCBufferAllocator *buffer_allocator_;
   HWCBufferSyncHandler *buffer_sync_handler_;
 };
diff --git a/libhwcomposer/hwc.cpp b/libhwcomposer/hwc.cpp
index 6acb663..7423c29 100644
--- a/libhwcomposer/hwc.cpp
+++ b/libhwcomposer/hwc.cpp
@@ -29,6 +29,7 @@
 #include <overlay.h>
 #include <overlayRotator.h>
 #include <overlayWriteback.h>
+#include <overlayCursor.h>
 #include <mdp_version.h>
 #include "hwc_utils.h"
 #include "hwc_fbupdate.h"
@@ -446,6 +447,30 @@
     return ret;
 }
 
+static int hwc_setCursorPositionAsync(struct hwc_composer_device_1* dev,
+        int dpy, int x, int y) {
+    int ret = -1;
+    hwc_context_t* ctx = (hwc_context_t*)(dev);
+    switch(dpy) {
+        case HWC_DISPLAY_PRIMARY:
+        {
+            ATRACE_CALL();
+            HWCursor* hwCursor = HWCursor::getInstance();
+            ctx->mDrawLock.lock();
+            if (hwCursor->isCursorSet() &&
+                  hwCursor->setPositionAsync(ctx->dpyAttr[dpy].fd, x, y)) {
+                ret = 0;
+            }
+            ctx->mDrawLock.unlock();
+            break;
+        }
+        default:
+            ret = 0;
+            break;
+    }
+    return ret;
+}
+
 static int hwc_setPowerMode(struct hwc_composer_device_1* dev, int dpy,
         int mode)
 {
@@ -465,6 +490,7 @@
             ctx->mOverlay->configBegin();
             ctx->mOverlay->configDone();
             ctx->mRotMgr->clear();
+            HWCursor::getInstance()->free(ctx->dpyAttr[dpy].fd);
             // If VDS is connected, do not clear WB object as it
             // will end up detaching IOMMU. This is required
             // to send black frame to WFD sink on power suspend.
@@ -925,17 +951,20 @@
         if(ctx->mMDPComp[dpy])
             ctx->mMDPComp[dpy]->dump(aBuf, ctx);
     }
-    char ovDump[2048] = {'\0'};
-    ctx->mOverlay->getDump(ovDump, 2048);
+    char ovDump[3072] = {'\0'};
+    ctx->mOverlay->getDump(ovDump, 3072);
     dumpsys_log(aBuf, ovDump);
     ovDump[0] = '\0';
     ctx->mRotMgr->getDump(ovDump, 1024);
     dumpsys_log(aBuf, ovDump);
     ovDump[0] = '\0';
-    if(Writeback::getDump(ovDump, 1024)) {
+    if(Writeback::getDump(ovDump, 512)) {
         dumpsys_log(aBuf, ovDump);
         ovDump[0] = '\0';
     }
+    HWCursor::getInstance()->getDump(ovDump, 512);
+    dumpsys_log(aBuf, ovDump);
+    ovDump[0] = '\0';
     dumpsys_log(aBuf, "Copybit::isAbcInUse=%d\n\n",isAbcInUse(ctx) ? 1 : 0);
     strlcpy(buff, aBuf.string(), buff_len);
 }
@@ -1032,6 +1061,7 @@
         dev->device.getDisplayAttributes = hwc_getDisplayAttributes;
         dev->device.getActiveConfig     = hwc_getActiveConfig;
         dev->device.setActiveConfig     = hwc_setActiveConfig;
+        dev->device.setCursorPositionAsync = hwc_setCursorPositionAsync;
         *device = &dev->device.common;
         status = 0;
     }
diff --git a/libhwcomposer/hwc_mdpcomp.cpp b/libhwcomposer/hwc_mdpcomp.cpp
index 5572cc4..087fe1e 100644
--- a/libhwcomposer/hwc_mdpcomp.cpp
+++ b/libhwcomposer/hwc_mdpcomp.cpp
@@ -18,7 +18,6 @@
 
 #include <math.h>
 #include "hwc_mdpcomp.h"
-#include <sys/ioctl.h>
 #include <dlfcn.h>
 #include "hdmi.h"
 #include "qdMetaData.h"
@@ -26,6 +25,7 @@
 #include "hwc_fbupdate.h"
 #include "hwc_ad.h"
 #include <overlayRotator.h>
+#include <overlayCursor.h>
 #include "hwc_copybit.h"
 #include "qd_utils.h"
 
@@ -56,6 +56,8 @@
 int (*MDPComp::sPerfLockRelease)(int value) = NULL;
 int MDPComp::sPerfHintWindow = -1;
 
+enum AllocOrder { FORMAT_YUV, FORMAT_RGB, FORMAT_MAX };
+
 MDPComp* MDPComp::getObject(hwc_context_t *ctx, const int& dpy) {
     if(qdutils::MDPVersion::getInstance().isSrcSplit()) {
         sSrcSplitEnabled = true;
@@ -77,8 +79,8 @@
                 (mDpy == 0) ? "\"PRIMARY\"" :
                 (mDpy == 1) ? "\"EXTERNAL\"" : "\"VIRTUAL\"");
     dumpsys_log(buf,"CURR_FRAME: layerCount:%2d mdpCount:%2d "
-                "fbCount:%2d \n", mCurrentFrame.layerCount,
-                mCurrentFrame.mdpCount, mCurrentFrame.fbCount);
+                "fbCount:%2d  dropCount:%2d\n", mCurrentFrame.layerCount,
+                mCurrentFrame.mdpCount, mCurrentFrame.fbCount, mCurrentFrame.dropCount);
     dumpsys_log(buf,"needsFBRedraw:%3s  pipesUsed:%2d  MaxPipesPerMixer: %d \n",
                 (mCurrentFrame.needsRedraw? "YES" : "NO"),
                 mCurrentFrame.mdpCount, sMaxPipesPerMixer);
@@ -106,7 +108,8 @@
                     (mCurrentFrame.isFBComposed[index] ? "YES" : "NO"),
                      mCurrentFrame.layerToMDP[index],
                     (mCurrentFrame.isFBComposed[index] ?
-                    (mCurrentFrame.drop[index] ? "DROP" :
+                    (mCurrentFrame.drop[index] ?
+                    ((mCurrentFrame.hwCursorIndex == index) ? "CURSOR": "DROP"):
                     (mCurrentFrame.needsRedraw ? "GLES" : "CACHE")) : "MDP"),
                     (mCurrentFrame.isFBComposed[index] ? mCurrentFrame.fbZ :
     mCurrentFrame.mdpToLayer[mCurrentFrame.layerToMDP[index]].pipeInfo->zOrder));
@@ -301,7 +304,11 @@
             /* Drop the layer when its already present in FB OR when it lies
              * outside frame's ROI */
             if(!mCurrentFrame.needsRedraw || mCurrentFrame.drop[index]) {
-                layer->compositionType = HWC_OVERLAY;
+                if(index == mCurrentFrame.hwCursorIndex) {
+                    layer->compositionType = HWC_CURSOR_OVERLAY;
+                } else {
+                    layer->compositionType = HWC_OVERLAY;
+                }
             }
         }
     }
@@ -946,6 +953,9 @@
     hwc_display_contents_1_t* list) {
 
     const int numAppLayers = ctx->listStats[mDpy].numAppLayers;
+    // PTOR does not qualify when there are layers dropped, but if
+    // dropped layer is only a cursor, PTOR could qualify
+    const int numNonCursorLayers = numAppLayers - mCurrentFrame.dropCount;
     const int stagesForMDP = min(sMaxPipesPerMixer,
             ctx->mOverlay->availablePipes(mDpy, Overlay::MIXER_DEFAULT));
 
@@ -955,10 +965,11 @@
         return false;
     }
 
-    // Frame level checks
+    // Frame level checks - consider PTOR in case of dropCount only if the cursor
+    // layer is dropped, otherwise bail out of PTOR
     if ((numAppLayers > stagesForMDP) || isSkipPresent(ctx, mDpy) ||
-        isYuvPresent(ctx, mDpy) || mCurrentFrame.dropCount ||
-        isSecurePresent(ctx, mDpy)) {
+        isYuvPresent(ctx, mDpy) || isSecurePresent(ctx, mDpy) ||
+        (mCurrentFrame.dropCount - (int)isCursorPresent(ctx, mDpy))) {
         ALOGD_IF(isDebug(), "%s: Frame not supported!", __FUNCTION__);
         return false;
     }
@@ -983,7 +994,7 @@
     memset(overlapRect, 0, sizeof(overlapRect));
     int layerPixelCount, minPixelCount = 0;
     int numPTORLayersFound = 0;
-    for (int i = numAppLayers-1; (i >= 0 &&
+    for (int i = numNonCursorLayers - 1; (i >= 0 &&
                                   numPTORLayersFound < MAX_PTOR_LAYERS); i--) {
         hwc_layer_1_t* layer = &list->hwLayers[i];
         hwc_rect_t crop = integerizeSourceCrop(layer->sourceCropf);
@@ -1028,9 +1039,9 @@
         return false;
 
     // Store the displayFrame and the sourceCrops of the layers
-    hwc_rect_t displayFrame[numAppLayers];
-    hwc_rect_t sourceCrop[numAppLayers];
-    for(int i = 0; i < numAppLayers; i++) {
+    hwc_rect_t displayFrame[numNonCursorLayers];
+    hwc_rect_t sourceCrop[numNonCursorLayers];
+    for(int i = 0; i < numNonCursorLayers; i++) {
         hwc_layer_1_t* layer = &list->hwLayers[i];
         displayFrame[i] = layer->displayFrame;
         sourceCrop[i] = integerizeSourceCrop(layer->sourceCropf);
@@ -1119,11 +1130,11 @@
         }
     }
 
-    mCurrentFrame.mdpCount = numAppLayers;
+    mCurrentFrame.mdpCount = numNonCursorLayers;
     mCurrentFrame.fbCount = 0;
     mCurrentFrame.fbZ = -1;
 
-    for (int j = 0; j < numAppLayers; j++) {
+    for (int j = 0; j < numNonCursorLayers; j++) {
         if(isValidRect(list->hwLayers[j].displayFrame)) {
             mCurrentFrame.isFBComposed[j] = false;
         } else {
@@ -1135,7 +1146,7 @@
     bool result = postHeuristicsHandling(ctx, list);
 
     // Restore layer attributes
-    for(int i = 0; i < numAppLayers; i++) {
+    for(int i = 0; i < numNonCursorLayers; i++) {
         hwc_layer_1_t* layer = &list->hwLayers[i];
         layer->displayFrame = displayFrame[i];
         layer->sourceCropf.left = (float)sourceCrop[i].left;
@@ -1342,7 +1353,9 @@
         hwc_display_contents_1_t* list){
     if(!qdutils::MDPVersion::getInstance().isPartialUpdateEnabled() ||
             isSkipPresent(ctx, mDpy) || (list->flags & HWC_GEOMETRY_CHANGED) ||
-            !sIsPartialUpdateActive || mDpy ) {
+            isCursorPresent(ctx, mDpy) || !sIsPartialUpdateActive || mDpy) {
+            // On Async position update, the ROI becomes invalid, hence disable PU
+            // when cursor is present
         return false;
     }
     if(ctx->listStats[mDpy].secureUI)
@@ -1910,7 +1923,20 @@
 bool MDPComp::resourceCheck(hwc_context_t* ctx,
         hwc_display_contents_1_t* list) {
     const bool fbUsed = mCurrentFrame.fbCount;
-    if(mCurrentFrame.mdpCount > sMaxPipesPerMixer - fbUsed) {
+    int cursorInUse = 0;
+    if(mDpy == HWC_DISPLAY_PRIMARY) {
+      // check if cursor is in use for primary
+      cursorInUse = HWCursor::getInstance()->isCursorSet();
+    }
+    int maxStages =  qdutils::MDPVersion::getInstance().getBlendStages();
+    // HW Cursor needs one blending stage, account for that in the check below
+    // On high end targets(8994) has 8 blending stages, HAL is configured to use < 8.
+    // Make use of the remaining stages for HW Cursor so that the composition
+    // strategy would not fail due to this limitation.
+    if (maxStages > sMaxPipesPerMixer) {
+        cursorInUse = 0;
+    }
+    if(mCurrentFrame.mdpCount > (sMaxPipesPerMixer - fbUsed - cursorInUse)) {
         ALOGD_IF(isDebug(), "%s: Exceeds MAX_PIPES_PER_MIXER",__FUNCTION__);
         return false;
     }
@@ -1985,6 +2011,52 @@
     return true;
 }
 
+static bool validForCursor(hwc_context_t* ctx, int dpy, hwc_layer_1_t* layer) {
+    private_handle_t *hnd = (private_handle_t *)layer->handle;
+    hwc_rect dst = layer->displayFrame;
+    hwc_rect src = integerizeSourceCrop(layer->sourceCropf);
+    int srcW = src.right - src.left;
+    int srcH = src.bottom - src.top;
+    int dstW = dst.right - dst.left;
+    int dstH = dst.bottom - dst.top;
+    qdutils::MDPVersion &mdpVersion = qdutils::MDPVersion::getInstance();
+    uint32_t maxCursorSize = mdpVersion.getMaxCursorSize();
+    uint32_t numHwCursors = mdpVersion.getCursorPipes();
+    bool primarySplit = isDisplaySplit(ctx, HWC_DISPLAY_PRIMARY);
+    uint32_t cursorPipesNeeded = 1; // One cursor pipe needed(default)
+    bool ret = false;
+
+    if(dpy > HWC_DISPLAY_PRIMARY) {
+        // Cursor not supported on secondary displays, as it involves scaling
+        // in most of the cases
+        return false;
+    } else if (isSkipLayer(layer)) {
+        return false;
+    // Checks for HW limitation
+    } else if (numHwCursors == 0 || maxCursorSize <= 0) {
+        return false;
+    } else if (needsScaling(layer)) {
+        return false;
+    } else if (layer->transform != 0) {
+        return false;
+    } else if (hnd->format != HAL_PIXEL_FORMAT_RGBA_8888) {
+        return false;
+    } else if (srcW > (int)maxCursorSize || srcH > (int)maxCursorSize) {
+        return false;
+    }
+
+    if (isDisplaySplit(ctx, dpy) && !mdpVersion.isSrcSplit()) {
+        // In case of split display with no srcSplit, the driver allocates two
+        // pipes to support async position update across mixers, hence
+        // need to account for that here.
+        cursorPipesNeeded = 2;
+    }
+    if (cursorPipesNeeded <= numHwCursors) {
+        ret = true;
+    }
+    return ret;
+}
+
 // Checks only if videos or single layer(RGB) is updating
 // which is used for setting dynamic fps or perf hint for single
 // layer video playback
@@ -2029,9 +2101,10 @@
     int ret = 0;
     char property[PROPERTY_VALUE_MAX];
 
-    if(!ctx || !list) {
-        ALOGE("%s: Invalid context or list",__FUNCTION__);
+    if(!list) {
+        ALOGE("%s: Invalid list", __FUNCTION__);
         mCachedFrame.reset();
+        freeHwCursor(ctx->dpyAttr[mDpy].fd, mDpy);
         return -1;
     }
 
@@ -2052,6 +2125,7 @@
     mCurrentFrame.reset(numLayers);
     memset(&mCurrentFrame.drop, 0, sizeof(mCurrentFrame.drop));
     mCurrentFrame.dropCount = 0;
+    mCurrentFrame.hwCursorIndex = -1;
 
     //Do not cache the information for next draw cycle.
     if(numLayers > MAX_NUM_APP_LAYERS or (!numLayers)) {
@@ -2061,6 +2135,7 @@
 #ifdef DYNAMIC_FPS
         setDynRefreshRate(ctx, list);
 #endif
+        freeHwCursor(ctx->dpyAttr[mDpy].fd, mDpy);
         return -1;
     }
 
@@ -2077,6 +2152,7 @@
 #ifdef DYNAMIC_FPS
         setDynRefreshRate(ctx, list);
 #endif
+        freeHwCursor(ctx->dpyAttr[mDpy].fd, mDpy);
         ret = -1;
         return ret;
     } else {
@@ -2106,6 +2182,23 @@
             dropNonAIVLayers(ctx, list);
         }
 
+        // Configure the cursor if present
+        int topIndex = ctx->listStats[mDpy].numAppLayers - 1;
+        if(ctx->listStats[mDpy].cursorLayerPresent &&
+                validForCursor(ctx, mDpy, &(list->hwLayers[topIndex]))) {
+            if(configHwCursor(ctx->dpyAttr[mDpy].fd, mDpy,
+                                      &(list->hwLayers[topIndex]))) {
+                // As cursor is configured, mark that layer as dropped, so that
+                // it wont be considered for composition by other strategies.
+                mCurrentFrame.hwCursorIndex = topIndex;
+                mCurrentFrame.drop[topIndex] = true;
+                mCurrentFrame.dropCount++;
+            }
+        } else {
+            // Release the hw cursor
+            freeHwCursor(ctx->dpyAttr[mDpy].fd, mDpy);
+        }
+
         // if tryFullFrame fails, try to push all video and secure RGB layers
         // to MDP for composition.
         mModeOn = tryFullFrame(ctx, list) || tryMDPOnlyLayers(ctx, list) ||
@@ -2117,6 +2210,12 @@
             reset(ctx);
             memset(&mCurrentFrame.drop, 0, sizeof(mCurrentFrame.drop));
             mCurrentFrame.dropCount = 0;
+            // Check if cursor is in use for primary and mark accordingly
+            if(!mDpy && HWCursor::getInstance()->isCursorSet()) {
+                int topIndex = ctx->listStats[mDpy].numAppLayers - 1;
+                hwc_layer_1_t *layer = &(list->hwLayers[topIndex]);
+                layer->compositionType = HWC_CURSOR_OVERLAY;
+            }
             ret = -1;
             ALOGE_IF(sSimulationFlags && (mDpy == HWC_DISPLAY_PRIMARY),
                     "MDP Composition Strategies Failed");
@@ -2131,6 +2230,8 @@
         }
         ALOGD_IF( isDebug(),"%s: MDP Comp not possible for this frame",
                 __FUNCTION__);
+        // Release the hw cursor
+        freeHwCursor(ctx->dpyAttr[mDpy].fd, mDpy);
         ret = -1;
     }
 
@@ -2248,39 +2349,48 @@
 
 bool MDPCompNonSplit::allocLayerPipes(hwc_context_t *ctx,
         hwc_display_contents_1_t* list) {
-    for(int index = 0; index < mCurrentFrame.layerCount; index++) {
+    for(uint32_t formatType = FORMAT_YUV; formatType < FORMAT_MAX;
+            formatType++) {
+        for(int index = 0; index < mCurrentFrame.layerCount; index++) {
+            if(mCurrentFrame.isFBComposed[index]) continue;
 
-        if(mCurrentFrame.isFBComposed[index]) continue;
-
-        hwc_layer_1_t* layer = &list->hwLayers[index];
-        private_handle_t *hnd = (private_handle_t *)layer->handle;
-        if(isYUVSplitNeeded(hnd) && sEnableYUVsplit){
-            if(allocSplitVGPipes(ctx, index)){
+            hwc_layer_1_t* layer = &list->hwLayers[index];
+            private_handle_t *hnd = (private_handle_t *)layer->handle;
+            if(formatType == FORMAT_YUV && !isYuvBuffer(hnd))
                 continue;
+            if(formatType == FORMAT_RGB && isYuvBuffer(hnd))
+                continue;
+
+            if(isYUVSplitNeeded(hnd) && sEnableYUVsplit){
+                if(allocSplitVGPipes(ctx, index)){
+                    continue;
+                }
             }
-        }
 
-        int mdpIndex = mCurrentFrame.layerToMDP[index];
-        PipeLayerPair& info = mCurrentFrame.mdpToLayer[mdpIndex];
-        info.pipeInfo = new MdpPipeInfoNonSplit;
-        info.rot = NULL;
-        MdpPipeInfoNonSplit& pipe_info = *(MdpPipeInfoNonSplit*)info.pipeInfo;
+            int mdpIndex = mCurrentFrame.layerToMDP[index];
+            PipeLayerPair& info = mCurrentFrame.mdpToLayer[mdpIndex];
+            info.pipeInfo = new MdpPipeInfoNonSplit;
+            info.rot = NULL;
+            MdpPipeInfoNonSplit& pipe_info =
+                    *(MdpPipeInfoNonSplit*)info.pipeInfo;
 
-        Overlay::PipeSpecs pipeSpecs;
-        pipeSpecs.formatClass = isYuvBuffer(hnd) ?
-                Overlay::FORMAT_YUV : Overlay::FORMAT_RGB;
-        pipeSpecs.needsScaling = qhwc::needsScaling(layer) or
-                (qdutils::MDPVersion::getInstance().is8x26() and
-                ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres > 1024);
-        pipeSpecs.dpy = mDpy;
-        pipeSpecs.fb = false;
-        pipeSpecs.numActiveDisplays = ctx->numActiveDisplays;
+            Overlay::PipeSpecs pipeSpecs;
+            pipeSpecs.formatClass = isYuvBuffer(hnd) ?
+                    Overlay::FORMAT_YUV : Overlay::FORMAT_RGB;
+            pipeSpecs.needsScaling = qhwc::needsScaling(layer) or
+                    (qdutils::MDPVersion::getInstance().is8x26() and
+                     ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres > 1024);
+            pipeSpecs.dpy = mDpy;
+            pipeSpecs.fb = false;
+            pipeSpecs.numActiveDisplays = ctx->numActiveDisplays;
 
-        pipe_info.index = ctx->mOverlay->getPipe(pipeSpecs);
+            pipe_info.index = ctx->mOverlay->getPipe(pipeSpecs);
 
-        if(pipe_info.index == ovutils::OV_INVALID) {
-            ALOGD_IF(isDebug(), "%s: Unable to get pipe", __FUNCTION__);
-            return false;
+            if(pipe_info.index == ovutils::OV_INVALID) {
+                ALOGD_IF(isDebug(), "%s: Unable to get pipe for layer %d of "\
+                        "format type %d", __FUNCTION__, index, formatType);
+                return false;
+            }
         }
     }
     return true;
@@ -2482,36 +2592,43 @@
 
 bool MDPCompSplit::allocLayerPipes(hwc_context_t *ctx,
         hwc_display_contents_1_t* list) {
-    for(int index = 0 ; index < mCurrentFrame.layerCount; index++) {
+    for(uint32_t formatType = FORMAT_YUV; formatType < FORMAT_MAX;
+            formatType++) {
+        for(int index = 0 ; index < mCurrentFrame.layerCount; index++) {
+            if(mCurrentFrame.isFBComposed[index]) continue;
 
-        if(mCurrentFrame.isFBComposed[index]) continue;
-
-        hwc_layer_1_t* layer = &list->hwLayers[index];
-        private_handle_t *hnd = (private_handle_t *)layer->handle;
-        hwc_rect_t dst = layer->displayFrame;
-        const int lSplit = getLeftSplit(ctx, mDpy);
-        if(isYUVSplitNeeded(hnd) && sEnableYUVsplit){
-            if((dst.left > lSplit)||(dst.right < lSplit)){
-                if(allocSplitVGPipes(ctx, index)){
-                    continue;
-                }
-            }
-        }
-        //XXX: Check for forced 2D composition
-        if(needs3DComposition(ctx, mDpy) && get3DFormat(hnd) != HAL_NO_3D)
-            if(allocSplitVGPipes(ctx,index))
+            hwc_layer_1_t* layer = &list->hwLayers[index];
+            private_handle_t *hnd = (private_handle_t *)layer->handle;
+            if(formatType == FORMAT_YUV && !isYuvBuffer(hnd))
+                continue;
+            if(formatType == FORMAT_RGB && isYuvBuffer(hnd))
                 continue;
 
-        int mdpIndex = mCurrentFrame.layerToMDP[index];
-        PipeLayerPair& info = mCurrentFrame.mdpToLayer[mdpIndex];
-        info.pipeInfo = new MdpPipeInfoSplit;
-        info.rot = NULL;
-        MdpPipeInfoSplit& pipe_info = *(MdpPipeInfoSplit*)info.pipeInfo;
+            hwc_rect_t dst = layer->displayFrame;
+            const int lSplit = getLeftSplit(ctx, mDpy);
+            if(isYUVSplitNeeded(hnd) && sEnableYUVsplit){
+                if((dst.left > lSplit)||(dst.right < lSplit)){
+                    if(allocSplitVGPipes(ctx, index)){
+                        continue;
+                    }
+                }
+            }
+            //XXX: Check for forced 2D composition
+            if(needs3DComposition(ctx, mDpy) && get3DFormat(hnd) != HAL_NO_3D)
+                if(allocSplitVGPipes(ctx,index))
+                    continue;
 
-        if(!acquireMDPPipes(ctx, layer, pipe_info)) {
-            ALOGD_IF(isDebug(), "%s: Unable to get pipe for type",
-                    __FUNCTION__);
-            return false;
+            int mdpIndex = mCurrentFrame.layerToMDP[index];
+            PipeLayerPair& info = mCurrentFrame.mdpToLayer[mdpIndex];
+            info.pipeInfo = new MdpPipeInfoSplit;
+            info.rot = NULL;
+            MdpPipeInfoSplit& pipe_info = *(MdpPipeInfoSplit*)info.pipeInfo;
+
+            if(!acquireMDPPipes(ctx, layer, pipe_info)) {
+                ALOGD_IF(isDebug(), "%s: Unable to get pipe for layer %d of "\
+                        "format type %d", __FUNCTION__, index, formatType);
+                return false;
+            }
         }
     }
     return true;
diff --git a/libhwcomposer/hwc_mdpcomp.h b/libhwcomposer/hwc_mdpcomp.h
index 676bf24..db68e82 100644
--- a/libhwcomposer/hwc_mdpcomp.h
+++ b/libhwcomposer/hwc_mdpcomp.h
@@ -119,6 +119,7 @@
 
         bool needsRedraw;
         int fbZ;
+        int hwCursorIndex;
 
         /* c'tor */
         FrameInfo();
diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp
index db982db..8efe025 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -30,6 +30,7 @@
 #include <overlay.h>
 #include <overlayRotator.h>
 #include <overlayWriteback.h>
+#include <overlayCursor.h>
 #include "hwc_utils.h"
 #include "hwc_mdpcomp.h"
 #include "hwc_fbupdate.h"
@@ -1094,6 +1095,7 @@
     ctx->listStats[dpy].renderBufIndexforABC = -1;
     ctx->listStats[dpy].secureRGBCount = 0;
     ctx->listStats[dpy].refreshRateRequest = ctx->dpyAttr[dpy].refreshRate;
+    ctx->listStats[dpy].cursorLayerPresent = false;
     uint32_t refreshRate = 0;
     qdutils::MDPVersion& mdpHw = qdutils::MDPVersion::getInstance();
     int s3dFormat = HAL_NO_3D;
@@ -1125,6 +1127,12 @@
         if(ctx->listStats[dpy].numAppLayers > MAX_NUM_APP_LAYERS)
             continue;
 
+        // Valid cursor must be the top most layer
+        if((int)i == (ctx->listStats[dpy].numAppLayers - 1) &&
+                     isCursorLayer(&list->hwLayers[i])) {
+            ctx->listStats[dpy].cursorLayerPresent = true;
+        }
+
         //reset yuv indices
         ctx->listStats[dpy].yuvIndices[i] = -1;
         ctx->listStats[dpy].yuv4k2kIndices[i] = -1;
@@ -1951,6 +1959,46 @@
     crop.bottom = transformedCrop.y + transformedCrop.h;
 }
 
+bool configHwCursor(const int fd, int dpy, hwc_layer_1_t* layer) {
+    if(dpy > HWC_DISPLAY_PRIMARY) {
+        // HWCursor not supported on secondary displays
+        return false;
+    }
+    private_handle_t *hnd = (private_handle_t *)layer->handle;
+    hwc_rect dst = layer->displayFrame;
+    hwc_rect src = integerizeSourceCrop(layer->sourceCropf);
+    int srcW = src.right - src.left;
+    int srcH = src.bottom - src.top;
+    int dstW = dst.right - dst.left;
+    int dstH = dst.bottom - dst.top;
+
+    Whf whf(getWidth(hnd), getHeight(hnd), hnd->format);
+    Dim crop(src.left, src.top, srcW, srcH);
+    Dim dest(dst.left, dst.top, dstW, dstH);
+
+    ovutils::PipeArgs pargs(ovutils::OV_MDP_FLAGS_NONE,
+                            whf,
+                            Z_SYSTEM_ALLOC,
+                            ovutils::ROT_FLAGS_NONE,
+                            layer->planeAlpha,
+                            (ovutils::eBlending)
+                            getBlending(layer->blending));
+
+    ALOGD_IF(HWC_UTILS_DEBUG, "%s: CursorInfo: w = %d h = %d "
+        "crop [%d, %d, %d, %d] dst [%d, %d, %d, %d]", __FUNCTION__,
+        getWidth(hnd), getHeight(hnd), src.left, src.top, srcW, srcH,
+        dst.left, dst.top, dstW, dstH);
+
+    return HWCursor::getInstance()->config(fd, (void*)hnd->base, pargs,
+                crop, dest);
+}
+
+void freeHwCursor(const int fd, int dpy) {
+    if (dpy == HWC_DISPLAY_PRIMARY) {
+        HWCursor::getInstance()->free(fd);
+    }
+}
+
 int getRotDownscale(hwc_context_t *ctx, const hwc_layer_1_t *layer) {
     if(not qdutils::MDPVersion::getInstance().isRotDownscaleEnabled()) {
         return 0;
diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h
index ac61e68..f0f8e77 100644
--- a/libhwcomposer/hwc_utils.h
+++ b/libhwcomposer/hwc_utils.h
@@ -169,6 +169,8 @@
     uint32_t refreshRateRequest;
     // Flag related to windowboxing feature
     bool mAIVVideoMode;
+    // curser layer info
+    bool cursorLayerPresent;
 };
 
 //PTOR Comp info
@@ -418,6 +420,9 @@
 void updateSource(ovutils::eTransform& orient, ovutils::Whf& whf,
         hwc_rect_t& crop, overlay::Rotator *rot);
 
+bool configHwCursor(const int fd, int dpy, hwc_layer_1_t* layer);
+void freeHwCursor(const int fd, int dpy);
+
 bool isZoomModeEnabled(hwc_rect_t crop);
 void updateCropAIVVideoMode(hwc_context_t *ctx, hwc_rect_t& crop, int dpy);
 void updateDestAIVVideoMode(hwc_context_t *ctx, hwc_rect_t& dst, int dpy);
@@ -501,6 +506,11 @@
     return (UNLIKELY(l && (l->flags & HWC_AIV_CC)));
 }
 
+static inline bool isCursorLayer(const hwc_layer_1_t* l) {
+    return (UNLIKELY(l && (l->flags & HWC_IS_CURSOR_LAYER)));
+}
+
+
 // Returns true if the buffer is yuv
 static inline bool isYuvBuffer(const private_handle_t* hnd) {
     return (hnd && (hnd->bufferType == BUFFER_TYPE_VIDEO));
@@ -731,6 +741,10 @@
     return ctx->listStats[dpy].isSecurePresent;
 }
 
+static inline bool isCursorPresent (hwc_context_t *ctx, int dpy) {
+    return  ctx->listStats[dpy].cursorLayerPresent;
+}
+
 static inline bool isSecondaryConfiguring(hwc_context_t* ctx) {
     return (ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].isConfiguring ||
             ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].isConfiguring);
diff --git a/liboverlay/Android.mk b/liboverlay/Android.mk
index aa1ea24..9ea7432 100644
--- a/liboverlay/Android.mk
+++ b/liboverlay/Android.mk
@@ -17,6 +17,7 @@
       overlayMdpRot.cpp \
       overlayMdssRot.cpp \
       overlayWriteback.cpp \
+      overlayCursor.cpp \
       pipes/overlayGenPipe.cpp
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/liboverlay/overlayCursor.cpp b/liboverlay/overlayCursor.cpp
new file mode 100644
index 0000000..c22dd39
--- /dev/null
+++ b/liboverlay/overlayCursor.cpp
@@ -0,0 +1,147 @@
+/*
+* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+*     * Redistributions of source code must retain the above copyright
+*       notice, this list of conditions and the following disclaimer.
+*     * Redistributions in binary form must reproduce the above
+*       copyright notice, this list of conditions and the following
+*       disclaimer in the documentation and/or other materials provided
+*       with the distribution.
+*     * Neither the name of The Linux Foundation nor the names of its
+*       contributors may be used to endorse or promote products derived
+*       from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+//#include "overlay.h"
+#include "overlayCursor.h"
+#include "mdpWrapper.h"
+
+namespace overlay {
+
+HWCursor* HWCursor::sHwCursor = 0;
+
+//=========== class HWCursor =================================================
+HWCursor* HWCursor::getInstance() {
+    if (sHwCursor == NULL) {
+        sHwCursor = new HWCursor();
+    }
+    return sHwCursor;
+}
+
+bool HWCursor::config(const int fd, void* base, PipeArgs& pargs,
+                    Dim& crop, Dim& dest) {
+    bool ret = true;
+    fb_cursor *cursor = &mfbCursor;
+    fb_image cursorImage;
+
+    cursor->set = FB_CUR_SETIMAGE | FB_CUR_SETPOS;
+    cursor->enable = (uint16_t)1;
+    cursor->rop = 0,
+    cursor->mask = NULL;
+    cursor->hot.x = (uint16_t)crop.x;
+    cursor->hot.y = (uint16_t)crop.y;
+
+    cursorImage.dx = dest.x;
+    cursorImage.dy = dest.y;
+    cursorImage.width = pargs.whf.w;
+    cursorImage.height = pargs.whf.h;
+    cursorImage.fg_color = pargs.planeAlpha; // Hint for PMA
+    cursorImage.bg_color = 0xffffff00;  // RGBA
+    cursorImage.depth = 32;
+    cursorImage.data = (char*)base;
+
+    cursor->image = cursorImage;
+
+    if (!setCursor(fd)) {
+        ALOGE("%s: Failed to setup HW cursor", __FUNCTION__);
+        ret = false;
+        memset(cursor, 0, sizeof(fb_cursor));
+    }
+    return ret;
+}
+
+bool HWCursor::setPositionAsync(const int fd, int x, int y) {
+    bool ret = true;
+    if (isCursorSet()) {
+        fb_cursor *cursor = &mfbCursor;
+        cursor->set = FB_CUR_SETPOS;
+        cursor->image.dx = x;
+        cursor->image.dy = y;
+        if (!setCursor(fd)) {
+            ALOGE("%s: Failed to set position x = %d y = %d", __FUNCTION__, x, y);
+            ret = false;
+        }
+    }
+    return ret;
+}
+
+bool HWCursor::free(const int fd) {
+    fb_cursor *cursor = &mfbCursor;
+    fb_image cursorImage;
+    bool ret = true;
+
+    if(!cursor->enable) {
+        return ret;
+    }
+
+    cursor->enable = (uint16_t)0;
+
+    if (!setCursor(fd)) {
+        ALOGE("%s: Failed to free cursor hw", __FUNCTION__);
+        ret = false;
+    }
+    memset(cursor, 0, sizeof(fb_cursor));
+    return ret;
+}
+
+bool HWCursor::setCursor(const int fd) {
+    bool ret = true;
+    ATRACE_CALL();
+    fb_cursor *cursor = &mfbCursor;
+
+    if(fd <= 0) {
+        ALOGE("%s: Invalid fd", fd);
+        return false;
+    }
+
+    if (ioctl(fd, MSMFB_CURSOR, cursor) < 0) {
+        ALOGE("%s: Failed to call ioctl MSMFB_CURSOR err=%s\n", __FUNCTION__,
+              strerror(errno));
+        ret = false;
+    }
+    return ret;
+}
+
+void HWCursor::getDump(char* buf, size_t len) {
+      char cursordump[len];
+      fb_cursor* cursor = &mfbCursor;
+      if (cursor->enable) {
+          snprintf(cursordump, sizeof(cursordump),
+              "HWCursor on Primary: src w=%d h=%d\n"
+              "\tsrc_rect x=%d y=%d w=%d h=%d\n"
+              "\tdst_rect x=%d y=%d w=%d h=%d\n\n", cursor->image.width,
+              cursor->image.height, cursor->hot.x, cursor->hot.y,
+              cursor->image.width, cursor->image.height,
+              cursor->image.dx, cursor->image.dy, cursor->image.width,
+              cursor->image.height);
+          strlcat(buf, cursordump, len);
+      }
+
+}
+
+} //namespace overlay
diff --git a/liboverlay/overlayCursor.h b/liboverlay/overlayCursor.h
new file mode 100644
index 0000000..2754a8d
--- /dev/null
+++ b/liboverlay/overlayCursor.h
@@ -0,0 +1,60 @@
+/*
+* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+*     * Redistributions of source code must retain the above copyright
+*       notice, this list of conditions and the following disclaimer.
+*     * Redistributions in binary form must reproduce the above
+*       copyright notice, this list of conditions and the following
+*       disclaimer in the documentation and/or other materials provided
+*       with the distribution.
+*     * Neither the name of The Linux Foundation nor the names of its
+*       contributors may be used to endorse or promote products derived
+*       from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef OVERLAY_CURSOR_H
+#define OVERLAY_CURSOR_H
+
+#include "overlay.h"
+#include "overlayUtils.h"
+
+namespace overlay {
+
+using namespace overlay;
+using namespace overlay::utils;
+
+// HW Cursor Helper
+class HWCursor {
+public:
+    static HWCursor* getInstance();
+    bool config(const int fd, void* base, PipeArgs& pargs, Dim& crop,
+            Dim& dest);
+    bool setPositionAsync(const int fd, int x, int y);
+    bool free(const int fd);
+    bool isCursorSet() { return mfbCursor.enable; }
+    void getDump(char* buf, size_t len);
+private:
+    HWCursor() { memset(&mfbCursor, 0, sizeof(mfbCursor)); }
+    bool setCursor(const int fd);
+    fb_cursor mfbCursor;
+
+    static HWCursor* sHwCursor;
+};
+}
+
+#endif // OVERLAY_CURSOR_H
diff --git a/libqdutils/mdp_version.cpp b/libqdutils/mdp_version.cpp
index a6a1b85..c02e28d 100644
--- a/libqdutils/mdp_version.cpp
+++ b/libqdutils/mdp_version.cpp
@@ -91,6 +91,7 @@
     mRGBPipes = 0;
     mVGPipes = 0;
     mDMAPipes = 0;
+    mCursorPipes = 0;
     mFeatures = 0;
     mMDPUpscale = 1;
     mMDPDownscale = 1;
@@ -110,6 +111,7 @@
     // Default width of MDSS SSPP. For layer resolutions beyond this, we drive
     // using two SSPP's.
     mMaxPipeWidth = 2048;
+    mMaxCursorSize = 0;
 
     updatePanelInfo();
 
@@ -309,6 +311,10 @@
                 else if(!strncmp(tokens[0], "dma_pipes", strlen("dma_pipes"))) {
                     mDMAPipes = (uint8_t)atoi(tokens[1]);
                 }
+                else if(!strncmp(tokens[0], "cursor_pipes",
+                                strlen("cursor_pipes"))) {
+                    mCursorPipes = (uint8_t)atoi(tokens[1]);
+                }
                 else if(!strncmp(tokens[0], "blending_stages",
                                 strlen("blending_stages"))) {
                     mBlendStages = (uint8_t)atoi(tokens[1]);
@@ -354,6 +360,9 @@
                             mRotDownscale = true;
                         }
                     }
+                } else if(!strncmp(tokens[0], "max_cursor_size",
+                        strlen("max_cursor_size"))) {
+                        mMaxCursorSize = atoi(tokens[1]);
                 }
             }
         }
@@ -389,8 +398,8 @@
     }
 
     ALOGD_IF(DEBUG, "%s: mMDPVersion: %d mMdpRev: %x mRGBPipes:%d,"
-                    "mVGPipes:%d", __FUNCTION__, mMDPVersion, mMdpRev,
-                    mRGBPipes, mVGPipes);
+                    "mVGPipes:%d  mCursorPipes:%d", __FUNCTION__, mMDPVersion,
+                    mMdpRev, mRGBPipes, mVGPipes, mCursorPipes);
     ALOGD_IF(DEBUG, "%s:mDMAPipes:%d \t mMDPDownscale:%d, mFeatures:%d",
                      __FUNCTION__,  mDMAPipes, mMDPDownscale, mFeatures);
     ALOGD_IF(DEBUG, "%s:mLowBw: %lu mHighBw: %lu", __FUNCTION__,  mLowBw,
diff --git a/libqdutils/mdp_version.h b/libqdutils/mdp_version.h
index ad92c83..6ebe558 100644
--- a/libqdutils/mdp_version.h
+++ b/libqdutils/mdp_version.h
@@ -116,6 +116,7 @@
     uint8_t getRGBPipes() { return mRGBPipes; }
     uint8_t getVGPipes() { return mVGPipes; }
     uint8_t getDMAPipes() { return mDMAPipes; }
+    uint8_t getCursorPipes() { return mCursorPipes; }
     uint8_t getBlendStages() { return mBlendStages; }
     bool supportsDecimation();
     uint32_t getMaxMDPDownscale();
@@ -140,6 +141,7 @@
     uint32_t getMaxFpsSupported() { return mPanelInfo.mMaxFps; }
     uint32_t getMaxMixerWidth() const { return mMaxMixerWidth; }
     uint32_t getMaxPipeWidth() const { return mMaxPipeWidth; }
+    uint32_t getMaxCursorSize() const { return mMaxCursorSize; }
     bool hasMinCropWidthLimitation() const;
     bool isSrcSplit() const;
     bool isSrcSplitAlways() const;
@@ -166,6 +168,7 @@
     uint8_t mRGBPipes;
     uint8_t mVGPipes;
     uint8_t mDMAPipes;
+    uint8_t mCursorPipes;
     uint8_t mBlendStages;
     uint32_t mFeatures;
     uint32_t mMDPDownscale;
@@ -182,6 +185,7 @@
     bool mRotDownscale;
     uint32_t mMaxMixerWidth; //maximum x-res of a given mdss mixer.
     uint32_t mMaxPipeWidth; //maximum x-res of the mdp pipe.
+    uint32_t mMaxCursorSize; //maximum size supported by hw cursor
 };
 }; //namespace qdutils
 #endif //INCLUDE_LIBQCOMUTILS_MDPVER