display: hardware recovery

Implements HW Recovery feature. If hw enters an unstable state due
to lack of validation, userspace bugs, driver bugs, or hw programming
error, driver attempts to recover the hardware and informs userspace to
capture register dumps on-target. In extreme case, driver will request a power reset.

Change-Id: Id0069696433b8cb49f67b6d2f37eb2d05f8e5953
CRs-Fixed: 2196904
diff --git a/sdm/include/core/display_interface.h b/sdm/include/core/display_interface.h
index 1f813ac..ae89bb6 100644
--- a/sdm/include/core/display_interface.h
+++ b/sdm/include/core/display_interface.h
@@ -137,10 +137,11 @@
 
 /*! @brief This enum represents the events received by Display HAL. */
 enum DisplayEvent {
-  kIdleTimeout,        // Event triggered by Idle Timer.
-  kThermalEvent,       // Event triggered by Thermal.
-  kIdlePowerCollapse,  // Event triggered by Idle Power Collapse.
-  kPanelDeadEvent,     // Event triggered by ESD.
+  kIdleTimeout,             // Event triggered by Idle Timer.
+  kThermalEvent,            // Event triggered by Thermal.
+  kIdlePowerCollapse,       // Event triggered by Idle Power Collapse.
+  kPanelDeadEvent,          // Event triggered by ESD.
+  kDisplayPowerResetEvent,  // Event triggered by Hardware Recovery.
 };
 
 /*! @brief This structure defines configuration for fixed properties of a display device.
diff --git a/sdm/include/private/hw_info_types.h b/sdm/include/private/hw_info_types.h
index 7526544..4e055bc 100644
--- a/sdm/include/private/hw_info_types.h
+++ b/sdm/include/private/hw_info_types.h
@@ -28,6 +28,8 @@
 #include <stdint.h>
 #include <core/display_interface.h>
 #include <core/core_interface.h>
+#include <utils/locker.h>
+#include <utils/debug.h>
 #include <vector>
 #include <map>
 #include <string>
@@ -156,6 +158,12 @@
   kReset,  // Resets/Clears the previously set config
 };
 
+enum class HWRecoveryEvent : uint32_t {
+  kSuccess,            // driver succeeded recovery
+  kCapture,            // driver PP_TIMEOUT, capture logs
+  kDisplayPowerReset,  // driver requesting display power cycle
+};
+
 typedef std::map<HWSubBlockType, std::vector<LayerBufferFormat>> FormatsMap;
 typedef std::map<LayerBufferFormat, float> CompRatioMap;
 
diff --git a/sdm/include/utils/constants.h b/sdm/include/utils/constants.h
index 5efe357..ffa8d12 100644
--- a/sdm/include/utils/constants.h
+++ b/sdm/include/utils/constants.h
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2014 - 2017, The Linux Foundation. All rights reserved.
+* Copyright (c) 2014 - 2018, 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:
@@ -32,6 +32,10 @@
 #define PRIu64 "llu"
 #endif
 
+#ifndef PRIu32
+#define PRIu32 "lu"
+#endif
+
 #define INT(exp) static_cast<int>(exp)
 #define FLOAT(exp) static_cast<float>(exp)
 #define UINT8(exp) static_cast<uint8_t>(exp)
diff --git a/sdm/libs/core/display_base.cpp b/sdm/libs/core/display_base.cpp
index 2381322..91bdb35 100644
--- a/sdm/libs/core/display_base.cpp
+++ b/sdm/libs/core/display_base.cpp
@@ -43,6 +43,9 @@
 
 namespace sdm {
 
+bool DisplayBase::display_power_reset_pending_ = false;
+Locker DisplayBase::display_power_reset_lock_;
+
 static ColorPrimaries GetColorPrimariesFromAttribute(const std::string &gamut) {
   if (gamut.find(kDisplayP3) != std::string::npos || gamut.find(kDcip3) != std::string::npos) {
     return ColorPrimaries_DCIP3;
@@ -1756,4 +1759,56 @@
   }
 }
 
+void DisplayBase::HwRecovery(const HWRecoveryEvent sdm_event_code) {
+  DLOGI("Handling event = %" PRIu32, sdm_event_code);
+  if (DisplayPowerResetPending()) {
+    DLOGI("Skipping handling for display = %d, display power reset in progress", display_type_);
+    return;
+  }
+  switch (sdm_event_code) {
+    case HWRecoveryEvent::kSuccess:
+      hw_recovery_logs_captured_ = false;
+      break;
+    case HWRecoveryEvent::kCapture:
+      if (!hw_recovery_logs_captured_) {
+        hw_intf_->DumpDebugData();
+        hw_recovery_logs_captured_ = true;
+        DLOGI("Captured debugfs data for display = %d", display_type_);
+      } else {
+        DLOGI("Multiple capture events without intermediate success event, skipping debugfs"
+              "capture for display = %d", display_type_);
+      }
+      break;
+    case HWRecoveryEvent::kDisplayPowerReset:
+      DLOGI("display = %d attempting to start display power reset", display_type_);
+      if (StartDisplayPowerReset()) {
+        DLOGI("display = %d allowed to start display power reset", display_type_);
+        event_handler_->HandleEvent(kDisplayPowerResetEvent);
+        EndDisplayPowerReset();
+        DLOGI("display = %d has finished display power reset", display_type_);
+      }
+      break;
+    default:
+      return;
+  }
+}
+
+bool DisplayBase::DisplayPowerResetPending() {
+  SCOPE_LOCK(display_power_reset_lock_);
+  return display_power_reset_pending_;
+}
+
+bool DisplayBase::StartDisplayPowerReset() {
+  SCOPE_LOCK(display_power_reset_lock_);
+  if (!display_power_reset_pending_) {
+    display_power_reset_pending_ = true;
+    return true;
+  }
+  return false;
+}
+
+void DisplayBase::EndDisplayPowerReset() {
+  SCOPE_LOCK(display_power_reset_lock_);
+  display_power_reset_pending_ = false;
+}
 }  // namespace sdm
diff --git a/sdm/libs/core/display_base.h b/sdm/libs/core/display_base.h
index a46ed7a..a907498 100644
--- a/sdm/libs/core/display_base.h
+++ b/sdm/libs/core/display_base.h
@@ -131,6 +131,7 @@
   DisplayError SetHDRMode(bool set);
   DisplayError ValidateScaling(uint32_t width, uint32_t height);
   DisplayError ValidateDataspace(const ColorMetaData &color_metadata);
+  void HwRecovery(const HWRecoveryEvent sdm_event_code);
 
   const char *GetName(const LayerComposition &composition);
   DisplayError ReconfigureDisplay();
@@ -151,6 +152,7 @@
   bool NeedsHdrHandling();
   void GetColorPrimaryTransferFromAttributes(const AttrVal &attr,
       std::vector<PrimariesTransfer> *supported_pt);
+  bool DisplayPowerResetPending();
 
   recursive_mutex recursive_mutex_;
   DisplayType display_type_;
@@ -195,6 +197,14 @@
   int disable_hdr_lut_gen_ = 0;
   DisplayState last_power_mode_ = kStateOff;
   bool gpu_fallback_ = false;
+  bool hw_recovery_logs_captured_ = false;
+
+  static Locker display_power_reset_lock_;
+  static bool display_power_reset_pending_;
+
+ private:
+  bool StartDisplayPowerReset();
+  void EndDisplayPowerReset();
 };
 
 }  // namespace sdm
diff --git a/sdm/libs/core/display_hdmi.cpp b/sdm/libs/core/display_hdmi.cpp
index 3582fa7..c72bc1e 100644
--- a/sdm/libs/core/display_hdmi.cpp
+++ b/sdm/libs/core/display_hdmi.cpp
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2014 - 2017, The Linux Foundation. All rights reserved.
+* Copyright (c) 2014 - 2018, 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:
@@ -49,6 +49,7 @@
   DisplayError error = HWInterface::Create(kHDMI, hw_info_intf_, buffer_sync_handler_,
                                            buffer_allocator_, &hw_intf_);
   if (error != kErrorNone) {
+    DLOGE("Failed to create hardware interface. Error = %d", error);
     return error;
   }
 
@@ -298,6 +299,11 @@
   event_handler_->CECMessage(message);
 }
 
+// HWEventHandler overload, not DisplayBase
+void DisplayHDMI::HwRecovery(const HWRecoveryEvent sdm_event_code) {
+  DisplayBase::HwRecovery(sdm_event_code);
+}
+
 DisplayError DisplayHDMI::VSync(int64_t timestamp) {
   if (vsync_enable_) {
     DisplayEventVSync vsync;
@@ -329,5 +335,16 @@
   return kErrorNone;
 }
 
+DisplayError DisplayHDMI::SetDisplayState(DisplayState state, int *release_fence) {
+  lock_guard<recursive_mutex> obj(recursive_mutex_);
+  DisplayError error = kErrorNone;
+  error = DisplayBase::SetDisplayState(state, release_fence);
+  if (error != kErrorNone) {
+    return error;
+  }
+
+  return kErrorNone;
+}
+
 }  // namespace sdm
 
diff --git a/sdm/libs/core/display_hdmi.h b/sdm/libs/core/display_hdmi.h
index 70bc145..a742f15 100644
--- a/sdm/libs/core/display_hdmi.h
+++ b/sdm/libs/core/display_hdmi.h
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2014 - 2017, The Linux Foundation. All rights reserved.
+* Copyright (c) 2014 - 2018, 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:
@@ -47,6 +47,7 @@
   virtual bool IsUnderscanSupported();
   virtual DisplayError OnMinHdcpEncryptionLevelChange(uint32_t min_enc_level);
   virtual DisplayError InitializeColorModes();
+  virtual DisplayError SetDisplayState(DisplayState state, int *release_fence);
 
   // Implement the HWEventHandlers
   virtual DisplayError VSync(int64_t timestamp);
@@ -57,6 +58,7 @@
   virtual void IdlePowerCollapse() { }
   virtual void PingPongTimeout() { }
   virtual void PanelDead() { }
+  virtual void HwRecovery(const HWRecoveryEvent sdm_event_code);
 
  private:
   uint32_t GetBestConfig(HWS3DMode s3d_mode);
@@ -68,8 +70,11 @@
   bool underscan_supported_ = false;
   HWScanSupport scan_support_;
   std::map<LayerBufferS3DFormat, HWS3DMode> s3d_format_to_mode_;
-  std::vector<HWEvent> event_list_ = { HWEvent::VSYNC, HWEvent::IDLE_NOTIFY, HWEvent::EXIT,
-    HWEvent::CEC_READ_MESSAGE };
+  std::vector<HWEvent> event_list_ = { HWEvent::VSYNC,
+                                       HWEvent::IDLE_NOTIFY,
+                                       HWEvent::EXIT,
+                                       HWEvent::CEC_READ_MESSAGE,
+                                       HWEvent::HW_RECOVERY };
   uint32_t current_refresh_rate_ = 0;
 };
 
diff --git a/sdm/libs/core/display_primary.cpp b/sdm/libs/core/display_primary.cpp
index fe38fcd..c66c5b4 100644
--- a/sdm/libs/core/display_primary.cpp
+++ b/sdm/libs/core/display_primary.cpp
@@ -51,6 +51,7 @@
   DisplayError error = HWInterface::Create(kPrimary, hw_info_intf_, buffer_sync_handler_,
                                            buffer_allocator_, &hw_intf_);
   if (error != kErrorNone) {
+    DLOGE("Failed to create hardware interface on. Error = %d", error);
     return error;
   }
 
@@ -75,7 +76,8 @@
                     HWEvent::THERMAL_LEVEL,
                     HWEvent::IDLE_POWER_COLLAPSE,
                     HWEvent::PINGPONG_TIMEOUT,
-                    HWEvent::PANEL_DEAD };
+                    HWEvent::PANEL_DEAD,
+                    HWEvent::HW_RECOVERY };
   } else {
     event_list_ = { HWEvent::VSYNC,
                     HWEvent::EXIT,
@@ -83,7 +85,8 @@
                     HWEvent::SHOW_BLANK_EVENT,
                     HWEvent::THERMAL_LEVEL,
                     HWEvent::PINGPONG_TIMEOUT,
-                    HWEvent::PANEL_DEAD };
+                    HWEvent::PANEL_DEAD,
+                    HWEvent::HW_RECOVERY };
   }
 
   avr_prop_disabled_ = Debug::IsAVRDisabled();
@@ -91,9 +94,9 @@
   error = HWEventsInterface::Create(INT(display_type_), this, event_list_, hw_intf_,
                                     &hw_events_intf_);
   if (error != kErrorNone) {
-    DLOGE("Failed to create hardware events interface. Error = %d", error);
     DisplayBase::Deinit();
     HWInterface::Destroy(hw_intf_);
+    DLOGE("Failed to create hardware events interface on. Error = %d", error);
   }
 
   current_refresh_rate_ = hw_panel_info_.max_fps;
@@ -347,6 +350,11 @@
   }
 }
 
+// HWEventHandler overload, not DisplayBase
+void DisplayPrimary::HwRecovery(const HWRecoveryEvent sdm_event_code) {
+  DisplayBase::HwRecovery(sdm_event_code);
+}
+
 DisplayError DisplayPrimary::GetPanelBrightness(int *level) {
   lock_guard<recursive_mutex> obj(recursive_mutex_);
   return hw_intf_->GetPanelBrightness(level);
diff --git a/sdm/libs/core/display_primary.h b/sdm/libs/core/display_primary.h
index ff5ba69..b1b6ea9 100644
--- a/sdm/libs/core/display_primary.h
+++ b/sdm/libs/core/display_primary.h
@@ -77,6 +77,7 @@
   virtual void IdlePowerCollapse();
   virtual void PingPongTimeout();
   virtual void PanelDead();
+  virtual void HwRecovery(const HWRecoveryEvent sdm_event_code);
 
   // Implement the DppsPropIntf
   virtual DisplayError SetDppsFeature(uint32_t object_type,
diff --git a/sdm/libs/core/drm/hw_device_drm.cpp b/sdm/libs/core/drm/hw_device_drm.cpp
index 18de450..b0f093c 100644
--- a/sdm/libs/core/drm/hw_device_drm.cpp
+++ b/sdm/libs/core/drm/hw_device_drm.cpp
@@ -52,6 +52,8 @@
 #include <private/color_params.h>
 #include <utils/rect.h>
 
+#include <sstream>
+#include <ctime>
 #include <algorithm>
 #include <string>
 #include <unordered_map>
@@ -78,6 +80,9 @@
 using std::to_string;
 using std::fstream;
 using std::unordered_map;
+using std::stringstream;
+using std::ifstream;
+using std::ofstream;
 using drm_utils::DRMMaster;
 using drm_utils::DRMResMgr;
 using drm_utils::DRMLibLoader;
@@ -1572,6 +1577,50 @@
   return kErrorNone;
 }
 
+DisplayError HWDeviceDRM::DumpDebugData() {
+#if USER_DEBUG
+  string device_str = device_name_;
+  stringstream date_str;
+  stringstream time_str;
+  time_t t = time(0);
+  struct tm t_now;
+  localtime_r(&t, &t_now);
+  date_str << (t_now.tm_mon + 1) << '-'
+          << (t_now.tm_mday) << '-'
+          << (t_now.tm_year + 1900) << '_';
+  time_str << (t_now.tm_hour) << '-'
+          << (t_now.tm_min) << '-'
+          << (t_now.tm_sec) << ".log";
+
+  ofstream dst("data/vendor/display/"+device_str+"_"+date_str.str()+time_str.str());
+  ifstream src;
+
+  src.open("/sys/kernel/debug/dri/0/debug/dump");
+  dst << "---- Event Logs ----" << std::endl;
+  dst << src.rdbuf() << std::endl;
+  src.close();
+
+  src.open("/sys/kernel/debug/dri/0/debug/recovery_reg");
+  dst << "---- All Registers ----" << std::endl;
+  dst << src.rdbuf() << std::endl;
+  src.close();
+
+  src.open("/sys/kernel/debug/dri/0/debug/recovery_dbgbus");
+  dst << "---- Debug Bus ----" << std::endl;
+  dst << src.rdbuf() << std::endl;
+  src.close();
+
+  src.open("/sys/kernel/debug/dri/0/debug/recovery_vbif_dbgbus");
+  dst << "---- VBIF Debug Bus ----" << std::endl;
+  dst << src.rdbuf() << std::endl;
+  src.close();
+
+  dst.close();
+#endif
+
+  return kErrorNone;
+}
+
 void HWDeviceDRM::GetDRMDisplayToken(sde_drm::DRMDisplayToken *token) const {
   token->conn_id = token_.conn_id;
   token->crtc_id = token_.crtc_id;
diff --git a/sdm/libs/core/drm/hw_device_drm.h b/sdm/libs/core/drm/hw_device_drm.h
index 809fd96..6ba30cc 100644
--- a/sdm/libs/core/drm/hw_device_drm.h
+++ b/sdm/libs/core/drm/hw_device_drm.h
@@ -103,7 +103,7 @@
   virtual DisplayError SetMixerAttributes(const HWMixerAttributes &mixer_attributes);
   virtual DisplayError GetMixerAttributes(HWMixerAttributes *mixer_attributes);
   virtual void InitializeConfigs();
-  virtual DisplayError DumpDebugData() { return kErrorNone; }
+  virtual DisplayError DumpDebugData();
   virtual void PopulateHWPanelInfo();
   virtual DisplayError SetDppsFeature(uint32_t object_type, uint32_t feature_id,
                                       uint64_t value) { return kErrorNotSupported; }
diff --git a/sdm/libs/core/drm/hw_events_drm.cpp b/sdm/libs/core/drm/hw_events_drm.cpp
index 86a3f54..d2aa668 100644
--- a/sdm/libs/core/drm/hw_events_drm.cpp
+++ b/sdm/libs/core/drm/hw_events_drm.cpp
@@ -37,6 +37,7 @@
 #include <sys/prctl.h>
 #include <sys/resource.h>
 #include <sys/types.h>
+#include <utils/constants.h>
 #include <utils/debug.h>
 #include <utils/sys.h>
 #include <xf86drm.h>
@@ -49,6 +50,19 @@
 
 #include "hw_events_drm.h"
 
+#ifndef DRM_EVENT_SDE_HW_RECOVERY
+#define DRM_EVENT_SDE_HW_RECOVERY 0x80000007
+#endif
+#ifndef SDE_RECOVERY_SUCCESS
+#define SDE_RECOVERY_SUCCESS 0
+#endif
+#ifndef SDE_RECOVERY_CAPTURE
+#define SDE_RECOVERY_CAPTURE 1
+#endif
+#ifndef SDE_RECOVERY_DISPLAY_POWER_RESET
+#define SDE_RECOVERY_DISPLAY_POWER_RESET 2
+#endif
+
 #define __CLASS__ "HWEventsDRM"
 
 namespace sdm {
@@ -114,6 +128,15 @@
         poll_fds_[i].events = POLLIN | POLLPRI | POLLERR;
         panel_dead_index_ = i;
       } break;
+      case HWEvent::HW_RECOVERY: {
+        poll_fds_[i].fd = drmOpen("msm_drm", nullptr);
+        if (poll_fds_[i].fd < 0) {
+          DLOGE("drmOpen failed with error %d", poll_fds_[i].fd);
+          return kErrorResources;
+        }
+        poll_fds_[i].events = POLLIN | POLLPRI | POLLERR;
+        hw_recovery_index_ = i;
+      } break;
       case HWEvent::CEC_READ_MESSAGE:
       case HWEvent::SHOW_BLANK_EVENT:
       case HWEvent::THERMAL_LEVEL:
@@ -154,6 +177,9 @@
       case HWEvent::PANEL_DEAD:
         event_data.event_parser = &HWEventsDRM::HandlePanelDead;
         break;
+      case HWEvent::HW_RECOVERY:
+        event_data.event_parser = &HWEventsDRM::HandleHwRecovery;
+        break;
       default:
         error = kErrorParameters;
         break;
@@ -206,6 +232,15 @@
   RegisterIdleNotify(true);
   RegisterIdlePowerCollapse(true);
 
+  int value = 0;
+  if (Debug::Get()->GetProperty("sdm.debug.disable_hw_recovery", &value) == kErrorNone) {
+    disable_hw_recovery_ = (value == 1);
+  }
+  DLOGI("disable_hw_recovery set to %d", disable_hw_recovery_);
+  if (!disable_hw_recovery_) {
+    RegisterHwRecovery(true);
+  }
+
   return kErrorNone;
 }
 
@@ -214,6 +249,9 @@
   RegisterPanelDead(false);
   RegisterIdleNotify(false);
   RegisterIdlePowerCollapse(false);
+  if (!disable_hw_recovery_) {
+    RegisterHwRecovery(false);
+  }
   Sys::pthread_cancel_(event_thread_);
   WakeUpEventThread();
   pthread_join(event_thread_, NULL);
@@ -271,6 +309,7 @@
       case HWEvent::IDLE_NOTIFY:
       case HWEvent::IDLE_POWER_COLLAPSE:
       case HWEvent::PANEL_DEAD:
+      case HWEvent::HW_RECOVERY:
         drmClose(poll_fds_[i].fd);
         poll_fds_[i].fd = -1;
         break;
@@ -318,6 +357,7 @@
         case HWEvent::PANEL_DEAD:
         case HWEvent::IDLE_NOTIFY:
         case HWEvent::IDLE_POWER_COLLAPSE:
+        case HWEvent::HW_RECOVERY:
           if (poll_fd.revents & (POLLIN | POLLPRI | POLLERR)) {
             (this->*(event_data_list_[i]).event_parser)(nullptr);
           }
@@ -462,6 +502,31 @@
   return kErrorNone;
 }
 
+DisplayError HWEventsDRM::RegisterHwRecovery(bool enable) {
+  if (hw_recovery_index_ == UINT_MAX) {
+    DLOGE("Hardware recovery is not supported");
+    return kErrorNotSupported;
+  }
+
+  struct drm_msm_event_req req = {};
+  int ret = 0;
+
+  req.object_id = token_.conn_id;
+  req.object_type = DRM_MODE_OBJECT_CONNECTOR;
+  req.event = DRM_EVENT_SDE_HW_RECOVERY;
+  if (enable) {
+    ret = drmIoctl(poll_fds_[hw_recovery_index_].fd, DRM_IOCTL_MSM_REGISTER_EVENT, &req);
+  } else {
+    ret = drmIoctl(poll_fds_[hw_recovery_index_].fd, DRM_IOCTL_MSM_DEREGISTER_EVENT, &req);
+  }
+  if (ret) {
+    DLOGE("Register hardware recovery enable:%d failed", enable);
+    return kErrorResources;
+  }
+
+  return kErrorNone;
+}
+
 void HWEventsDRM::HandleVSync(char *data) {
   drmEventContext event = {};
   event.version = DRM_EVENT_CONTEXT_VERSION;
@@ -617,4 +682,80 @@
   return;
 }
 
+void HWEventsDRM::HandleHwRecovery(char *data) {
+  char event_data[kMaxStringLength] = {0};
+  int32_t size;
+  struct drm_msm_event_resp *event_resp = NULL;
+
+  size = (int32_t)Sys::pread_(poll_fds_[hw_recovery_index_].fd, event_data, kMaxStringLength, 0);
+  if (size < 0) {
+    return;
+  }
+
+  if (size > kMaxStringLength) {
+    DLOGE("Hardware recovery event size %d is greater than event buffer size %zd\n", size,
+          kMaxStringLength);
+    return;
+  }
+
+  if (size < (int32_t)sizeof(*event_resp)) {
+    DLOGE("Hardware recovery event size is %d, expected %zd\n", size, sizeof(*event_resp));
+    return;
+  }
+
+  int32_t i = 0;
+
+  while (i < size) {
+    event_resp = (struct drm_msm_event_resp *)&event_data[i];
+    switch (event_resp->base.type) {
+      case DRM_EVENT_SDE_HW_RECOVERY: {
+        std::size_t size_of_data = (std::size_t)event_resp->base.length -
+                                   (sizeof(event_resp->base) + sizeof(event_resp->info));
+        // expect up to uint32_t from driver
+        if (size_of_data > sizeof(uint32_t)) {
+          DLOGE("Size of hardware recovery event data: %" PRIu32 " exceeds %zd", size_of_data,
+                sizeof(uint32_t));
+          return;
+        }
+
+        uint32_t hw_event_code = 0;
+        memcpy(&hw_event_code, event_resp->data, size_of_data);
+
+        HWRecoveryEvent sdm_event_code;
+        if (SetHwRecoveryEvent(hw_event_code, &sdm_event_code)) {
+          return;
+        }
+        event_handler_->HwRecovery(sdm_event_code);
+        break;
+      }
+      default: {
+        DLOGE("Invalid event type %d", event_resp->base.type);
+        break;
+      }
+    }
+    i += event_resp->base.length;
+  }
+
+  return;
+}
+
+int HWEventsDRM::SetHwRecoveryEvent(const uint32_t hw_event_code, HWRecoveryEvent *sdm_event_code) {
+  switch (hw_event_code) {
+     case SDE_RECOVERY_SUCCESS:
+       *sdm_event_code = HWRecoveryEvent::kSuccess;
+       break;
+     case SDE_RECOVERY_CAPTURE:
+       *sdm_event_code = HWRecoveryEvent::kCapture;
+       break;
+     case SDE_RECOVERY_DISPLAY_POWER_RESET:
+       *sdm_event_code = HWRecoveryEvent::kDisplayPowerReset;
+       break;
+     default:
+       DLOGE("Unsupported hardware recovery event value received = %" PRIu32, hw_event_code);
+       return -EINVAL;
+  }
+
+  return 0;
+}
+
 }  // namespace sdm
diff --git a/sdm/libs/core/drm/hw_events_drm.h b/sdm/libs/core/drm/hw_events_drm.h
index fafe606..82c1b44 100644
--- a/sdm/libs/core/drm/hw_events_drm.h
+++ b/sdm/libs/core/drm/hw_events_drm.h
@@ -37,6 +37,7 @@
 #include <string>
 #include <utility>
 #include <vector>
+#include <climits>
 
 #include "hw_events_interface.h"
 #include "hw_interface.h"
@@ -77,6 +78,8 @@
   void HandleBlank(char *data) {}
   void HandleIdlePowerCollapse(char *data);
   void HandlePanelDead(char *data);
+  void HandleHwRecovery(char *data);
+  int SetHwRecoveryEvent(const uint32_t hw_event_code, HWRecoveryEvent *sdm_event_code);
   void PopulateHWEventData(const vector<HWEvent> &event_list);
   void WakeUpEventThread();
   DisplayError SetEventParser();
@@ -86,6 +89,7 @@
   DisplayError RegisterPanelDead(bool enable);
   DisplayError RegisterIdleNotify(bool enable);
   DisplayError RegisterIdlePowerCollapse(bool enable);
+  DisplayError RegisterHwRecovery(bool enable);
 
   HWEventHandler *event_handler_{};
   vector<HWEventData> event_data_list_{};
@@ -102,6 +106,8 @@
   bool is_primary_ = false;
   uint32_t panel_dead_index_ = 0;
   uint32_t idle_pc_index_ = 0;
+  bool disable_hw_recovery_ = false;
+  uint32_t hw_recovery_index_ = UINT_MAX;
 };
 
 }  // namespace sdm
diff --git a/sdm/libs/core/drm/hw_peripheral_drm.cpp b/sdm/libs/core/drm/hw_peripheral_drm.cpp
index 35537a5..9810ce1 100644
--- a/sdm/libs/core/drm/hw_peripheral_drm.cpp
+++ b/sdm/libs/core/drm/hw_peripheral_drm.cpp
@@ -45,7 +45,7 @@
                                  HWInfoInterface *hw_info_intf)
   : HWDeviceDRM(buffer_sync_handler, buffer_allocator, hw_info_intf) {
   disp_type_ = DRMDisplayType::PERIPHERAL;
-  device_name_ = "Peripheral Display";
+  device_name_ = "Peripheral";
 }
 
 DisplayError HWPeripheralDRM::Init() {
diff --git a/sdm/libs/core/drm/hw_tv_drm.cpp b/sdm/libs/core/drm/hw_tv_drm.cpp
index a43ac2c..fa5da50 100644
--- a/sdm/libs/core/drm/hw_tv_drm.cpp
+++ b/sdm/libs/core/drm/hw_tv_drm.cpp
@@ -92,7 +92,7 @@
                      HWInfoInterface *hw_info_intf)
   : HWDeviceDRM(buffer_sync_handler, buffer_allocator, hw_info_intf) {
   disp_type_ = DRMDisplayType::TV;
-  device_name_ = "TV Display Device";
+  device_name_ = "TV";
 }
 
 DisplayError HWTVDRM::SetDisplayAttributes(uint32_t index) {
diff --git a/sdm/libs/core/drm/hw_virtual_drm.cpp b/sdm/libs/core/drm/hw_virtual_drm.cpp
index 6f7b12b..bf4dd6e 100644
--- a/sdm/libs/core/drm/hw_virtual_drm.cpp
+++ b/sdm/libs/core/drm/hw_virtual_drm.cpp
@@ -1,5 +1,5 @@
 /*
-Copyright (c) 2017, The Linux Foundation. All rights reserved.
+Copyright (c) 2017-2018, 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
@@ -54,7 +54,7 @@
                            BufferAllocator *buffer_allocator,
                            HWInfoInterface *hw_info_intf)
                            : HWDeviceDRM(buffer_sync_handler, buffer_allocator, hw_info_intf) {
-  HWDeviceDRM::device_name_ = "Virtual Display Device";
+  HWDeviceDRM::device_name_ = "Virtual";
   HWDeviceDRM::disp_type_ = DRMDisplayType::VIRTUAL;
 }
 
diff --git a/sdm/libs/core/fb/hw_device.h b/sdm/libs/core/fb/hw_device.h
index 08f9230..364fff5 100644
--- a/sdm/libs/core/fb/hw_device.h
+++ b/sdm/libs/core/fb/hw_device.h
@@ -101,6 +101,7 @@
   virtual DisplayError SetDppsFeature(uint32_t object_type, uint32_t feature_id,
                                       uint64_t value) { return kErrorNotSupported; }
   virtual DisplayError GetDppsFeatureInfo(void *info) { return kErrorNotSupported; }
+  virtual DisplayError DumpDebugData(DisplayType type) { return kErrorNone; }
 
   enum {
     kHWEventVSync,
diff --git a/sdm/libs/core/hw_events_interface.h b/sdm/libs/core/hw_events_interface.h
index 828dcda..db0bc3d 100644
--- a/sdm/libs/core/hw_events_interface.h
+++ b/sdm/libs/core/hw_events_interface.h
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+* Copyright (c) 2016-2018, 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:
@@ -45,6 +45,7 @@
   IDLE_POWER_COLLAPSE,
   PINGPONG_TIMEOUT,
   PANEL_DEAD,
+  HW_RECOVERY,
 };
 
 class HWEventsInterface {
diff --git a/sdm/libs/core/hw_interface.h b/sdm/libs/core/hw_interface.h
index fdb901f..c469e94 100644
--- a/sdm/libs/core/hw_interface.h
+++ b/sdm/libs/core/hw_interface.h
@@ -63,6 +63,7 @@
   virtual void IdlePowerCollapse() = 0;
   virtual void PingPongTimeout() = 0;
   virtual void PanelDead() = 0;
+  virtual void HwRecovery(const HWRecoveryEvent sdm_event_code) = 0;
 
  protected:
   virtual ~HWEventHandler() { }
diff --git a/sdm/libs/hwc2/hwc_display.cpp b/sdm/libs/hwc2/hwc_display.cpp
index aca16bc..c38d729 100644
--- a/sdm/libs/hwc2/hwc_display.cpp
+++ b/sdm/libs/hwc2/hwc_display.cpp
@@ -324,11 +324,13 @@
   *os << std::endl;
 }
 
-HWCDisplay::HWCDisplay(CoreInterface *core_intf, HWCCallbacks *callbacks, DisplayType type,
-                       hwc2_display_t id, bool needs_blit, qService::QService *qservice,
-                       DisplayClass display_class, BufferAllocator *buffer_allocator)
+HWCDisplay::HWCDisplay(CoreInterface *core_intf, HWCCallbacks *callbacks,
+                       HWCDisplayEventHandler* event_handler, DisplayType type, hwc2_display_t id,
+                       bool needs_blit, qService::QService *qservice, DisplayClass display_class,
+                       BufferAllocator *buffer_allocator)
     : core_intf_(core_intf),
       callbacks_(callbacks),
+      event_handler_(event_handler),
       type_(type),
       id_(id),
       needs_blit_(needs_blit),
@@ -997,6 +999,15 @@
       SEQUENCE_WAIT_SCOPE_LOCK(HWCSession::locker_[type_]);
       validated_ = false;
     } break;
+    case kDisplayPowerResetEvent: {
+      validated_ = false;
+      if (event_handler_) {
+        event_handler_->DisplayPowerReset();
+      } else {
+        DLOGI("Cannot process kDisplayPowerEventReset (display = %d), event_handler_ is nullptr",
+              type_);
+      }
+    } break;
     default:
       DLOGW("Unknown event: %d", event);
       break;
diff --git a/sdm/libs/hwc2/hwc_display.h b/sdm/libs/hwc2/hwc_display.h
index 9a4b228..6a8b621 100644
--- a/sdm/libs/hwc2/hwc_display.h
+++ b/sdm/libs/hwc2/hwc_display.h
@@ -37,6 +37,7 @@
 #include "hwc_callbacks.h"
 #include "hwc_layers.h"
 #include "display_null.h"
+#include "hwc_display_event_handler.h"
 
 namespace sdm {
 
@@ -237,7 +238,8 @@
   // Maximum number of layers supported by display manager.
   static const uint32_t kMaxLayerCount = 32;
 
-  HWCDisplay(CoreInterface *core_intf, HWCCallbacks *callbacks, DisplayType type, hwc2_display_t id,
+  HWCDisplay(CoreInterface *core_intf, HWCCallbacks *callbacks,
+             HWCDisplayEventHandler *event_handler, DisplayType type, hwc2_display_t id,
              bool needs_blit, qService::QService *qservice, DisplayClass display_class,
              BufferAllocator *buffer_allocator);
 
@@ -272,6 +274,7 @@
   bool layer_stack_invalid_ = true;
   CoreInterface *core_intf_ = nullptr;
   HWCCallbacks *callbacks_  = nullptr;
+  HWCDisplayEventHandler *event_handler_ = nullptr;
   HWCBufferAllocator *buffer_allocator_ = NULL;
   DisplayType type_;
   hwc2_display_t id_;
diff --git a/sdm/libs/hwc2/hwc_display_event_handler.h b/sdm/libs/hwc2/hwc_display_event_handler.h
new file mode 100644
index 0000000..1352049
--- /dev/null
+++ b/sdm/libs/hwc2/hwc_display_event_handler.h
@@ -0,0 +1,44 @@
+/*
+* Copyright (c) 2018, 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 __HWC_DISPLAY_EVENT_HANDLER_H__
+#define __HWC_DISPLAY_EVENT_HANDLER_H__
+
+namespace sdm {
+
+class HWCDisplayEventHandler {
+ public:
+  virtual void DisplayPowerReset() = 0;
+
+ protected:
+  virtual ~HWCDisplayEventHandler() {}
+};
+}  // namespace sdm
+
+#endif  // __HWC_DISPLAY_EVENT_HANDLER_H__
diff --git a/sdm/libs/hwc2/hwc_display_external.cpp b/sdm/libs/hwc2/hwc_display_external.cpp
index 675484b..4c02749 100644
--- a/sdm/libs/hwc2/hwc_display_external.cpp
+++ b/sdm/libs/hwc2/hwc_display_external.cpp
@@ -40,13 +40,14 @@
 namespace sdm {
 
 int HWCDisplayExternal::Create(CoreInterface *core_intf, HWCBufferAllocator *buffer_allocator,
-                               HWCCallbacks *callbacks, qService::QService *qservice,
-                               HWCDisplay **hwc_display) {
-  return Create(core_intf, buffer_allocator, callbacks, 0, 0, qservice, false, hwc_display);
+                               HWCCallbacks *callbacks, HWCDisplayEventHandler *event_handler,
+                               qService::QService *qservice, HWCDisplay **hwc_display) {
+  return Create(core_intf, buffer_allocator, callbacks, event_handler, 0, 0, qservice, false,
+                hwc_display);
 }
 
 int HWCDisplayExternal::Create(CoreInterface *core_intf, HWCBufferAllocator *buffer_allocator,
-                               HWCCallbacks *callbacks,
+                               HWCCallbacks *callbacks, HWCDisplayEventHandler *event_handler,
                                uint32_t primary_width, uint32_t primary_height,
                                qService::QService *qservice, bool use_primary_res,
                                HWCDisplay **hwc_display) {
@@ -55,7 +56,7 @@
   DisplayError error = kErrorNone;
 
   HWCDisplay *hwc_display_external = new HWCDisplayExternal(core_intf, buffer_allocator, callbacks,
-                                                            qservice);
+                                                            event_handler, qservice);
   int status = hwc_display_external->Init();
   if (status) {
     delete hwc_display_external;
@@ -102,9 +103,10 @@
 HWCDisplayExternal::HWCDisplayExternal(CoreInterface *core_intf,
                                        HWCBufferAllocator *buffer_allocator,
                                        HWCCallbacks *callbacks,
+                                       HWCDisplayEventHandler *event_handler,
                                        qService::QService *qservice)
-    : HWCDisplay(core_intf, callbacks, kHDMI, HWC_DISPLAY_EXTERNAL, false, qservice,
-                 DISPLAY_CLASS_EXTERNAL, buffer_allocator) {
+    : HWCDisplay(core_intf, callbacks, event_handler, kHDMI, HWC_DISPLAY_EXTERNAL, false,
+                 qservice, DISPLAY_CLASS_EXTERNAL, buffer_allocator) {
 }
 
 HWC2::Error HWCDisplayExternal::Validate(uint32_t *out_num_types, uint32_t *out_num_requests) {
diff --git a/sdm/libs/hwc2/hwc_display_external.h b/sdm/libs/hwc2/hwc_display_external.h
index 75e9387..a14ba5d 100644
--- a/sdm/libs/hwc2/hwc_display_external.h
+++ b/sdm/libs/hwc2/hwc_display_external.h
@@ -32,18 +32,19 @@
 
 #include "hwc_display.h"
 #include "display_null.h"
+#include "hwc_display_event_handler.h"
 
 namespace sdm {
 
 class HWCDisplayExternal : public HWCDisplay {
  public:
   static int Create(CoreInterface *core_intf, HWCBufferAllocator *buffer_allocator,
-                    HWCCallbacks *callbacks, uint32_t primary_width,
-                    uint32_t primary_height, qService::QService *qservice, bool use_primary_res,
-                    HWCDisplay **hwc_display);
+                    HWCCallbacks *callbacks, HWCDisplayEventHandler *event_handler,
+                    uint32_t primary_width, uint32_t primary_height, qService::QService *qservice,
+                    bool use_primary_res, HWCDisplay **hwc_display);
   static int Create(CoreInterface *core_intf, HWCBufferAllocator *buffer_allocator,
-                    HWCCallbacks *callbacks, qService::QService *qservice,
-                    HWCDisplay **hwc_display);
+                    HWCCallbacks *callbacks, HWCDisplayEventHandler *event_handler,
+                    qService::QService *qservice, HWCDisplay **hwc_display);
   static void Destroy(HWCDisplay *hwc_display);
   virtual HWC2::Error Validate(uint32_t *out_num_types, uint32_t *out_num_requests);
   virtual HWC2::Error Present(int32_t *out_retire_fence);
@@ -52,7 +53,8 @@
 
  private:
   HWCDisplayExternal(CoreInterface *core_intf, HWCBufferAllocator *buffer_allocator,
-                     HWCCallbacks *callbacks, qService::QService *qservice);
+                     HWCCallbacks *callbacks, HWCDisplayEventHandler *event_handler,
+                     qService::QService *qservice);
   void ApplyScanAdjustment(hwc_rect_t *display_frame);
   void GetUnderScanConfig();
   static void GetDownscaleResolution(uint32_t primary_width, uint32_t primary_height,
diff --git a/sdm/libs/hwc2/hwc_display_external_test.cpp b/sdm/libs/hwc2/hwc_display_external_test.cpp
index 8551854..4d71e8a 100644
--- a/sdm/libs/hwc2/hwc_display_external_test.cpp
+++ b/sdm/libs/hwc2/hwc_display_external_test.cpp
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+* Copyright (c) 2017-2018, 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
@@ -51,11 +51,11 @@
 
 int HWCDisplayExternalTest::Create(CoreInterface *core_intf,
                                    HWCBufferAllocator *buffer_allocator,
-                                   HWCCallbacks *callbacks,
+                                   HWCCallbacks *callbacks, HWCDisplayEventHandler *event_handler,
                                    qService::QService *qservice, uint32_t panel_bpp,
                                    uint32_t pattern_type, HWCDisplay **hwc_display) {
   HWCDisplay *hwc_external_test = new HWCDisplayExternalTest(core_intf, buffer_allocator,
-                                                             callbacks, qservice,
+                                                             callbacks, event_handler, qservice,
                                                              panel_bpp, pattern_type);
 
   int status = static_cast<HWCDisplayExternalTest *>(hwc_external_test)->Init();
@@ -80,10 +80,11 @@
 HWCDisplayExternalTest::HWCDisplayExternalTest(CoreInterface *core_intf,
                                                HWCBufferAllocator *buffer_allocator,
                                                HWCCallbacks *callbacks,
+                                               HWCDisplayEventHandler *event_handler,
                                                qService::QService *qservice, uint32_t panel_bpp,
                                                uint32_t pattern_type)
-  : HWCDisplay(core_intf, callbacks, kHDMI, HWC_DISPLAY_EXTERNAL, false, qservice,
-               DISPLAY_CLASS_EXTERNAL, buffer_allocator), panel_bpp_(panel_bpp),
+  : HWCDisplay(core_intf, callbacks, event_handler, kHDMI, HWC_DISPLAY_EXTERNAL, false,
+               qservice, DISPLAY_CLASS_EXTERNAL, buffer_allocator), panel_bpp_(panel_bpp),
                pattern_type_(pattern_type) {
 }
 
@@ -127,7 +128,7 @@
 
 HWC2::Error HWCDisplayExternalTest::Validate(uint32_t *out_num_types, uint32_t *out_num_requests) {
   auto status = HWC2::Error::None;
-  if (secure_display_active_) {
+  if (secure_display_active_ || display_paused_) {
     MarkLayersForGPUBypass();
     return status;
   }
@@ -164,6 +165,14 @@
     return status;
   }
 
+  if (display_paused_) {
+    DisplayError error = display_intf_->Flush();
+    validated_ = false;
+    if (error != kErrorNone) {
+      DLOGE("Flush failed. Error = %d", error);
+    }
+  }
+
   if (shutdown_pending_) {
     return status;
   }
diff --git a/sdm/libs/hwc2/hwc_display_external_test.h b/sdm/libs/hwc2/hwc_display_external_test.h
index ef8027b..aff237b 100644
--- a/sdm/libs/hwc2/hwc_display_external_test.h
+++ b/sdm/libs/hwc2/hwc_display_external_test.h
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+* Copyright (c) 2017-2018, 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
@@ -40,8 +40,9 @@
 class HWCDisplayExternalTest : public HWCDisplay {
  public:
   static int Create(CoreInterface *core_intf, HWCBufferAllocator *buffer_allocator,
-                    HWCCallbacks *callbacks, qService::QService *qservice,
-                    uint32_t panel_bpp, uint32_t pattern_type, HWCDisplay **hwc_display);
+                    HWCCallbacks *callbacks, HWCDisplayEventHandler *event_handler,
+                    qService::QService *qservice, uint32_t panel_bpp, uint32_t pattern_type,
+                    HWCDisplay **hwc_display);
   static void Destroy(HWCDisplay *hwc_display);
   virtual HWC2::Error Validate(uint32_t *out_num_types, uint32_t *out_num_requests);
   virtual HWC2::Error Present(int32_t *out_retire_fence);
@@ -80,8 +81,8 @@
 
  private:
   HWCDisplayExternalTest(CoreInterface *core_intf, HWCBufferAllocator *buffer_allocator,
-                         HWCCallbacks *callbacks, qService::QService *qservice,
-                         uint32_t panel_bpp, uint32_t pattern_type);
+                         HWCCallbacks *callbacks, HWCDisplayEventHandler *event_handler,
+                         qService::QService *qservice, uint32_t panel_bpp, uint32_t pattern_type);
   int Init();
   int Deinit();
   void DumpInputBuffer();
diff --git a/sdm/libs/hwc2/hwc_display_primary.cpp b/sdm/libs/hwc2/hwc_display_primary.cpp
index 21c958d..26dac45 100644
--- a/sdm/libs/hwc2/hwc_display_primary.cpp
+++ b/sdm/libs/hwc2/hwc_display_primary.cpp
@@ -46,14 +46,14 @@
 namespace sdm {
 
 int HWCDisplayPrimary::Create(CoreInterface *core_intf, BufferAllocator *buffer_allocator,
-                              HWCCallbacks *callbacks, qService::QService *qservice,
-                              HWCDisplay **hwc_display) {
+                              HWCCallbacks *callbacks, HWCDisplayEventHandler *event_handler,
+                              qService::QService *qservice, HWCDisplay **hwc_display) {
   int status = 0;
   uint32_t primary_width = 0;
   uint32_t primary_height = 0;
 
   HWCDisplay *hwc_display_primary =
-      new HWCDisplayPrimary(core_intf, buffer_allocator, callbacks, qservice);
+      new HWCDisplayPrimary(core_intf, buffer_allocator, callbacks, event_handler, qservice);
   status = hwc_display_primary->Init();
   if (status) {
     delete hwc_display_primary;
@@ -86,11 +86,11 @@
 }
 
 HWCDisplayPrimary::HWCDisplayPrimary(CoreInterface *core_intf, BufferAllocator *buffer_allocator,
-                                     HWCCallbacks *callbacks, qService::QService *qservice)
-    : HWCDisplay(core_intf, callbacks, kPrimary, HWC_DISPLAY_PRIMARY, true, qservice,
-                 DISPLAY_CLASS_PRIMARY, buffer_allocator),
-      buffer_allocator_(buffer_allocator),
-      cpu_hint_(NULL) {
+                                     HWCCallbacks *callbacks, HWCDisplayEventHandler *event_handler,
+                                     qService::QService *qservice)
+  : HWCDisplay(core_intf, callbacks, event_handler, kPrimary, HWC_DISPLAY_PRIMARY, true,
+               qservice, DISPLAY_CLASS_PRIMARY, buffer_allocator),
+               buffer_allocator_(buffer_allocator), cpu_hint_(NULL) {
 }
 
 int HWCDisplayPrimary::Init() {
@@ -221,9 +221,6 @@
 HWC2::Error HWCDisplayPrimary::Present(int32_t *out_retire_fence) {
   auto status = HWC2::Error::None;
   if (display_paused_) {
-    // TODO(user): From old HWC implementation
-    // If we do not handle the frame set retireFenceFd to outbufAcquireFenceFd
-    // Revisit this when validating display_paused
     DisplayError error = display_intf_->Flush();
     validated_ = false;
     if (error != kErrorNone) {
diff --git a/sdm/libs/hwc2/hwc_display_primary.h b/sdm/libs/hwc2/hwc_display_primary.h
index c1e23ed..f2e4280 100644
--- a/sdm/libs/hwc2/hwc_display_primary.h
+++ b/sdm/libs/hwc2/hwc_display_primary.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2018, 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
@@ -49,8 +49,8 @@
   };
 
   static int Create(CoreInterface *core_intf, BufferAllocator *buffer_allocator,
-                    HWCCallbacks *callbacks, qService::QService *qservice,
-                    HWCDisplay **hwc_display);
+                    HWCCallbacks *callbacks, HWCDisplayEventHandler *event_handler,
+                    qService::QService *qservice, HWCDisplay **hwc_display);
   static void Destroy(HWCDisplay *hwc_display);
   virtual int Init();
   virtual HWC2::Error Validate(uint32_t *out_num_types, uint32_t *out_num_requests);
@@ -72,7 +72,8 @@
 
  private:
   HWCDisplayPrimary(CoreInterface *core_intf, BufferAllocator *buffer_allocator,
-                    HWCCallbacks *callbacks, qService::QService *qservice);
+                    HWCCallbacks *callbacks, HWCDisplayEventHandler *event_handler,
+                    qService::QService *qservice);
   void SetMetaDataRefreshRateFlag(bool enable);
   virtual DisplayError SetDisplayMode(uint32_t mode);
   virtual DisplayError DisablePartialUpdateOneFrame();
diff --git a/sdm/libs/hwc2/hwc_display_virtual.cpp b/sdm/libs/hwc2/hwc_display_virtual.cpp
index df8d3a6..e6f1898 100644
--- a/sdm/libs/hwc2/hwc_display_virtual.cpp
+++ b/sdm/libs/hwc2/hwc_display_virtual.cpp
@@ -40,8 +40,8 @@
 namespace sdm {
 
 int HWCDisplayVirtual::Create(CoreInterface *core_intf, HWCBufferAllocator *buffer_allocator,
-                              HWCCallbacks *callbacks, uint32_t width,
-                              uint32_t height, int32_t *format, HWCDisplay **hwc_display) {
+                              HWCCallbacks *callbacks, uint32_t width, uint32_t height,
+                              int32_t *format, HWCDisplay **hwc_display) {
   int status = 0;
   HWCDisplayVirtual *hwc_display_virtual = new HWCDisplayVirtual(core_intf, buffer_allocator,
                                                                  callbacks);
@@ -89,8 +89,8 @@
 }
 
 HWCDisplayVirtual::HWCDisplayVirtual(CoreInterface *core_intf, HWCBufferAllocator *buffer_allocator,
-                                     HWCCallbacks *callbacks)
-    : HWCDisplay(core_intf, callbacks, kVirtual, HWC_DISPLAY_VIRTUAL, false, NULL,
+                                     HWCCallbacks *callbacks) :
+      HWCDisplay(core_intf, callbacks, nullptr, kVirtual, HWC_DISPLAY_VIRTUAL, false, nullptr,
                  DISPLAY_CLASS_VIRTUAL, buffer_allocator) {
 }
 
diff --git a/sdm/libs/hwc2/hwc_display_virtual.h b/sdm/libs/hwc2/hwc_display_virtual.h
index cf630fb..ba7dd04 100644
--- a/sdm/libs/hwc2/hwc_display_virtual.h
+++ b/sdm/libs/hwc2/hwc_display_virtual.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2018, 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
@@ -33,14 +33,15 @@
 #include <qdMetaData.h>
 #include <gralloc_priv.h>
 #include "hwc_display.h"
+#include "hwc_display_event_handler.h"
 
 namespace sdm {
 
 class HWCDisplayVirtual : public HWCDisplay {
  public:
   static int Create(CoreInterface *core_intf, HWCBufferAllocator *buffer_allocator,
-                    HWCCallbacks *callbacks, uint32_t width,
-                    uint32_t height, int32_t *format, HWCDisplay **hwc_display);
+                    HWCCallbacks *callbacks, uint32_t width, uint32_t height, int32_t *format,
+                    HWCDisplay **hwc_display);
   static void Destroy(HWCDisplay *hwc_display);
   virtual int Init();
   virtual int Deinit();
diff --git a/sdm/libs/hwc2/hwc_session.cpp b/sdm/libs/hwc2/hwc_session.cpp
index ea14ddb..d27a8b7 100644
--- a/sdm/libs/hwc2/hwc_session.cpp
+++ b/sdm/libs/hwc2/hwc_session.cpp
@@ -194,7 +194,7 @@
     }
   } else {
     // Create and power on primary display
-    status = HWCDisplayPrimary::Create(core_intf_, &buffer_allocator_, &callbacks_, qservice_,
+    status = HWCDisplayPrimary::Create(core_intf_, &buffer_allocator_, &callbacks_, this, qservice_,
                                        &hwc_display_[HWC_DISPLAY_PRIMARY]);
     color_mgr_ = HWCColorManager::CreateColorManager(&buffer_allocator_);
     if (!color_mgr_) {
@@ -898,8 +898,9 @@
       return HWC2::Error::NoResources;
     }
 
-    auto status = HWCDisplayVirtual::Create(core_intf_, &buffer_allocator_, &callbacks_, width,
-                                            height, format, &hwc_display_[HWC_DISPLAY_VIRTUAL]);
+    auto status = HWCDisplayVirtual::Create(core_intf_, &buffer_allocator_, &callbacks_,
+                                            width, height, format,
+                                            &hwc_display_[HWC_DISPLAY_VIRTUAL]);
     // TODO(user): validate width and height support
     if (status) {
       return HWC2::Error::Unsupported;
@@ -1653,7 +1654,7 @@
 }
 
 void HWCSession::ResetPanel() {
-  HWC2::Error status;
+  HWC2::Error status = HWC2::Error::None;
 
   DLOGI("Powering off primary");
   status = hwc_display_[HWC_DISPLAY_PRIMARY]->SetPowerMode(HWC2::PowerMode::Off);
@@ -1850,14 +1851,14 @@
   }
 
   if (panel_bpp && pattern_type) {
-    return HWCDisplayExternalTest::Create(core_intf_, &buffer_allocator_, &callbacks_,
+    return HWCDisplayExternalTest::Create(core_intf_, &buffer_allocator_, &callbacks_, this,
                                           qservice_, panel_bpp, pattern_type,
                                           &hwc_display_[disp_id]);
   }
 
-  return  HWCDisplayExternal::Create(core_intf_, &buffer_allocator_, &callbacks_,
-                                     primary_width, primary_height, qservice_,
-                                     use_primary_res, &hwc_display_[disp_id]);
+  return  HWCDisplayExternal::Create(core_intf_, &buffer_allocator_, &callbacks_, this,
+                                     primary_width, primary_height, qservice_, use_primary_res,
+                                     &hwc_display_[disp_id]);
 }
 
 #ifdef DISPLAY_CONFIG_1_1
@@ -1912,4 +1913,35 @@
   return hwc_display->Present(out_retire_fence);
 }
 
+void HWCSession::DisplayPowerReset() {
+  Locker::ScopeLock lock_p(locker_[HWC_DISPLAY_PRIMARY]);
+  Locker::ScopeLock lock_e(locker_[HWC_DISPLAY_EXTERNAL]);
+  Locker::ScopeLock lock_v(locker_[HWC_DISPLAY_VIRTUAL]);
+
+  HWC2::Error status = HWC2::Error::None;
+
+  for (hwc2_display_t display = HWC_DISPLAY_PRIMARY; display < HWC_NUM_DISPLAY_TYPES; display++) {
+    if (hwc_display_[display] != NULL) {
+      DLOGI("Powering off display = %d", display);
+      status = hwc_display_[display]->SetPowerMode(HWC2::PowerMode::Off);
+      if (status != HWC2::Error::None) {
+        DLOGE("Power off for display = %d failed with error = %d", display, status);
+      }
+    }
+  }
+  for (hwc2_display_t display = HWC_DISPLAY_PRIMARY; display < HWC_NUM_DISPLAY_TYPES; display++) {
+    if (hwc_display_[display] != NULL) {
+      DLOGI("Powering on display = %d", display);
+      status = hwc_display_[display]->SetPowerMode(HWC2::PowerMode::On);
+      if (status != HWC2::Error::None) {
+        DLOGE("Power on for display = %d failed with error = %d", display, status);
+      }
+    }
+  }
+
+  status = hwc_display_[HWC_DISPLAY_PRIMARY]->SetVsyncEnabled(HWC2::Vsync::Enable);
+  if (status != HWC2::Error::None) {
+    DLOGE("Enabling vsync failed for primary with error = %d", status);
+  }
+}
 }  // namespace sdm
diff --git a/sdm/libs/hwc2/hwc_session.h b/sdm/libs/hwc2/hwc_session.h
index 4bd7b00..75b4757 100644
--- a/sdm/libs/hwc2/hwc_session.h
+++ b/sdm/libs/hwc2/hwc_session.h
@@ -37,6 +37,7 @@
 #include "hwc_display_virtual.h"
 #include "hwc_color_manager.h"
 #include "hwc_socket_handler.h"
+#include "hwc_display_event_handler.h"
 
 namespace sdm {
 
@@ -72,7 +73,8 @@
   bool init_done_ = false;
 };
 
-class HWCSession : hwc2_device_t, HWCUEventListener, IDisplayConfig, public qClient::BnQClient {
+class HWCSession : hwc2_device_t, HWCUEventListener, IDisplayConfig, public qClient::BnQClient,
+                   public HWCDisplayEventHandler {
  public:
   struct HWCModuleMethods : public hw_module_methods_t {
     HWCModuleMethods() { hw_module_methods_t::open = HWCSession::Open; }
@@ -157,6 +159,9 @@
   static int32_t SetColorTransform(hwc2_device_t *device, hwc2_display_t display,
                                    const float *matrix, int32_t /*android_color_transform_t*/ hint);
 
+  // HWCDisplayEventHandler
+  virtual void DisplayPowerReset();
+
   static Locker locker_[HWC_NUM_DISPLAY_TYPES];
 
  private: