Merge "hwc: Push a dummy -1 release fence in case of flush"
diff --git a/sdm/include/core/display_interface.h b/sdm/include/core/display_interface.h
index b8e2a9e..142d2c6 100644
--- a/sdm/include/core/display_interface.h
+++ b/sdm/include/core/display_interface.h
@@ -137,8 +137,9 @@
 
 /*! @brief This enum represents the events received by Display HAL. */
 enum DisplayEvent {
-  kIdleTimeout,    // Event triggered by Idle Timer.
-  kThermalEvent,   // Event triggered by Thermal.
+  kIdleTimeout,        // Event triggered by Idle Timer.
+  kThermalEvent,       // Event triggered by Thermal.
+  kIdlePowerCollapse,  // Event triggered by Idle Power Collapse.
 };
 
 /*! @brief This structure defines configuration for fixed properties of a display device.
diff --git a/sdm/include/private/color_params.h b/sdm/include/private/color_params.h
index fdab206..2cfb99e 100644
--- a/sdm/include/private/color_params.h
+++ b/sdm/include/private/color_params.h
@@ -297,6 +297,7 @@
   static const int kGamutTableNum = 4;
   static const int kGamutScaleoffTableNum = 3;
   static const int kGamutTableSize = 1229;
+  static const int kGamutTableCoarse13Size = 550;
   static const int kGamutTableCoarseSize = 32;
   static const int kGamutScaleoffSize = 16;
   uint32_t mode;
diff --git a/sdm/include/private/hw_info_types.h b/sdm/include/private/hw_info_types.h
index 5d19952..b6c4690 100644
--- a/sdm/include/private/hw_info_types.h
+++ b/sdm/include/private/hw_info_types.h
@@ -109,6 +109,19 @@
   kOneShotMode,     // Mode to enable AVR feature for particular frame.
 };
 
+enum HWTopology {
+  kUnknown,
+  kSingleLM,
+  kSingleLMDSC,
+  kDualLM,
+  kDualLMDSC,
+  kDualLMMerge,
+  kDualLMMergeDSC,
+  kDualLMDSCMerge,
+  kPPSplit,
+};
+
+
 typedef std::map<HWSubBlockType, std::vector<LayerBufferFormat>> FormatsMap;
 typedef std::map<LayerBufferFormat, float> CompRatioMap;
 
@@ -557,6 +570,8 @@
   uint32_t h_total = 0;        //!< Total width of panel (hActive + hFP + hBP + hPulseWidth)
   uint32_t v_total = 0;        //!< Total height of panel (vActive + vFP + vBP + vPulseWidth)
   std::bitset<32> s3d_config;  //!< Stores the bit mask of S3D modes
+  uint32_t clock_khz = 0;      //!< Stores the pixel clock of panel in khz
+  HWTopology topology = kUnknown;  //!< Stores the topology information.
 
   void Reset() { *this = HWDisplayAttributes(); }
 
@@ -572,7 +587,10 @@
             (v_back_porch != display_attributes.v_back_porch) ||
             (v_pulse_width != display_attributes.v_pulse_width) ||
             (h_total != display_attributes.h_total) ||
-            (is_yuv != display_attributes.is_yuv));
+            (is_yuv != display_attributes.is_yuv) ||
+            (s3d_config != display_attributes.s3d_config) ||
+            (clock_khz != display_attributes.clock_khz) ||
+            (topology != display_attributes.topology));
   }
 
   bool operator ==(const HWDisplayAttributes &display_attributes) {
diff --git a/sdm/libs/core/display_base.cpp b/sdm/libs/core/display_base.cpp
index 1037b7d..1ffe862 100644
--- a/sdm/libs/core/display_base.cpp
+++ b/sdm/libs/core/display_base.cpp
@@ -307,10 +307,9 @@
 
   CommitLayerParams(layer_stack);
 
-  if (comp_manager_->Commit(display_comp_ctx_, &hw_layers_)) {
-    if (error != kErrorNone) {
-      return error;
-    }
+  error = comp_manager_->Commit(display_comp_ctx_, &hw_layers_);
+  if (error != kErrorNone) {
+    return error;
   }
 
   // check if feature list cache is dirty and pending.
diff --git a/sdm/libs/core/display_primary.cpp b/sdm/libs/core/display_primary.cpp
index 64a0bcc..8f3d6f0 100644
--- a/sdm/libs/core/display_primary.cpp
+++ b/sdm/libs/core/display_primary.cpp
@@ -280,10 +280,15 @@
 }
 
 void DisplayPrimary::IdleTimeout() {
-  handle_idle_timeout_ = true;
-  event_handler_->Refresh();
-  comp_manager_->ProcessIdleTimeout(display_comp_ctx_);
-  event_handler_->HandleEvent(kIdleTimeout);
+  if (hw_panel_info_.mode == kModeCommand) {
+    IdlePowerCollapse();
+  } else {
+    event_handler_->HandleEvent(kIdleTimeout);
+    handle_idle_timeout_ = true;
+    event_handler_->Refresh();
+    lock_guard<recursive_mutex> obj(recursive_mutex_);
+    comp_manager_->ProcessIdleTimeout(display_comp_ctx_);
+  }
 }
 
 void DisplayPrimary::PingPongTimeout() {
@@ -292,12 +297,13 @@
 }
 
 void DisplayPrimary::ThermalEvent(int64_t thermal_level) {
+  event_handler_->HandleEvent(kThermalEvent);
   lock_guard<recursive_mutex> obj(recursive_mutex_);
   comp_manager_->ProcessThermalEvent(display_comp_ctx_, thermal_level);
-  event_handler_->HandleEvent(kThermalEvent);
 }
 
 void DisplayPrimary::IdlePowerCollapse() {
+  event_handler_->HandleEvent(kIdlePowerCollapse);
   lock_guard<recursive_mutex> obj(recursive_mutex_);
   comp_manager_->ProcessIdlePowerCollapse(display_comp_ctx_);
 }
diff --git a/sdm/libs/core/drm/hw_device_drm.cpp b/sdm/libs/core/drm/hw_device_drm.cpp
index 8ee52ba..bd09a38 100644
--- a/sdm/libs/core/drm/hw_device_drm.cpp
+++ b/sdm/libs/core/drm/hw_device_drm.cpp
@@ -411,7 +411,6 @@
   uint32_t mm_width = 0;
   uint32_t mm_height = 0;
   DRMTopology topology = DRMTopology::SINGLE_LM;
-  bool dual_display = false;
 
   if (default_mode_) {
     DRMResMgr *res_mgr = nullptr;
@@ -451,14 +450,11 @@
   display_attributes_[index].v_back_porch = mode.vtotal - mode.vsync_end;
   display_attributes_[index].v_total = mode.vtotal;
   display_attributes_[index].h_total = mode.htotal;
-  uint32_t h_blanking = mode.htotal - mode.hdisplay;
   display_attributes_[index].is_device_split =
       (topology == DRMTopology::DUAL_LM || topology == DRMTopology::DUAL_LM_MERGE ||
        topology == DRMTopology::DUAL_LM_MERGE_DSC || topology == DRMTopology::DUAL_LM_DSC ||
        topology == DRMTopology::DUAL_LM_DSCMERGE);
-  dual_display = (topology == DRMTopology::DUAL_LM || topology == DRMTopology::DUAL_LM_DSC ||
-       topology == DRMTopology::PPSPLIT);
-  display_attributes_[index].h_total += dual_display ? h_blanking : 0;
+  display_attributes_[index].clock_khz = mode.clock;
 
   // If driver doesn't return panel width/height information, default to 320 dpi
   if (INT(mm_width) <= 0 || INT(mm_height) <= 0) {
@@ -469,15 +465,17 @@
 
   display_attributes_[index].x_dpi = (FLOAT(mode.hdisplay) * 25.4f) / FLOAT(mm_width);
   display_attributes_[index].y_dpi = (FLOAT(mode.vdisplay) * 25.4f) / FLOAT(mm_height);
+  SetTopology(topology, &display_attributes_[index].topology);
 
   DLOGI("Display attributes[%d]: WxH: %dx%d, DPI: %fx%f, FPS: %d, LM_SPLIT: %d, V_BACK_PORCH: %d," \
-        " V_FRONT_PORCH: %d, V_PULSE_WIDTH: %d, V_TOTAL: %d, H_TOTAL: %d, TOPOLOGY: %d", index,
-        display_attributes_[index].x_pixels, display_attributes_[index].y_pixels,
+        " V_FRONT_PORCH: %d, V_PULSE_WIDTH: %d, V_TOTAL: %d, H_TOTAL: %d, CLK: %dKHZ, TOPOLOGY: %d",
+        index, display_attributes_[index].x_pixels, display_attributes_[index].y_pixels,
         display_attributes_[index].x_dpi, display_attributes_[index].y_dpi,
         display_attributes_[index].fps, display_attributes_[index].is_device_split,
         display_attributes_[index].v_back_porch, display_attributes_[index].v_front_porch,
         display_attributes_[index].v_pulse_width, display_attributes_[index].v_total,
-        display_attributes_[index].h_total, topology);
+        display_attributes_[index].h_total, display_attributes_[index].clock_khz,
+        display_attributes_[index].topology);
 
   return kErrorNone;
 }
@@ -1395,4 +1393,18 @@
   }
 }
 
+void HWDeviceDRM::SetTopology(sde_drm::DRMTopology drm_topology, HWTopology *hw_topology) {
+  switch (drm_topology) {
+    case DRMTopology::SINGLE_LM:          *hw_topology = kSingleLM;        break;
+    case DRMTopology::SINGLE_LM_DSC:      *hw_topology = kSingleLMDSC;     break;
+    case DRMTopology::DUAL_LM:            *hw_topology = kDualLM;          break;
+    case DRMTopology::DUAL_LM_DSC:        *hw_topology = kDualLMDSC;       break;
+    case DRMTopology::DUAL_LM_MERGE:      *hw_topology = kDualLMMerge;     break;
+    case DRMTopology::DUAL_LM_MERGE_DSC:  *hw_topology = kDualLMMergeDSC;  break;
+    case DRMTopology::DUAL_LM_DSCMERGE:   *hw_topology = kDualLMDSCMerge;  break;
+    case DRMTopology::PPSPLIT:            *hw_topology = kPPSplit;         break;
+    default:                              *hw_topology = kUnknown;         break;
+  }
+}
+
 }  // namespace sdm
diff --git a/sdm/libs/core/drm/hw_device_drm.h b/sdm/libs/core/drm/hw_device_drm.h
index 883d605..cc17668 100644
--- a/sdm/libs/core/drm/hw_device_drm.h
+++ b/sdm/libs/core/drm/hw_device_drm.h
@@ -133,6 +133,7 @@
                        sde_drm::DRMSecurityLevel *security_level);
   bool IsResolutionSwitchEnabled() const { return resolution_switch_enabled_; }
   void UpdatePanelSplitInfo();
+  void SetTopology(sde_drm::DRMTopology drm_topology, HWTopology *hw_topology);
 
   class Registry {
    public:
diff --git a/sdm/libs/hwc2/hwc_display.cpp b/sdm/libs/hwc2/hwc_display.cpp
index 2541ec3..723148b 100644
--- a/sdm/libs/hwc2/hwc_display.cpp
+++ b/sdm/libs/hwc2/hwc_display.cpp
@@ -40,6 +40,7 @@
 #include "hwc_display.h"
 #include "hwc_debugger.h"
 #include "hwc_tonemapper.h"
+#include "hwc_session.h"
 
 #ifndef USE_GRALLOC1
 #include <gr.h>
@@ -952,6 +953,8 @@
   switch (event) {
     case kIdleTimeout:
     case kThermalEvent:
+    case kIdlePowerCollapse:
+      HWCSession::WaitForSequence(id_);
       validated_.reset();
       break;
     default:
diff --git a/sdm/libs/hwc2/hwc_session.cpp b/sdm/libs/hwc2/hwc_session.cpp
index 2039a46..89de074 100644
--- a/sdm/libs/hwc2/hwc_session.cpp
+++ b/sdm/libs/hwc2/hwc_session.cpp
@@ -70,7 +70,7 @@
 namespace sdm {
 
 static HWCUEvent g_hwc_uevent_;
-Locker HWCSession::locker_;
+Locker HWCSession::locker_[HWC_NUM_DISPLAY_TYPES];
 
 void HWCUEvent::UEventThread(HWCUEvent *hwc_uevent) {
   const char *uevent_thread_name = "HWC_UeventThread";
@@ -135,6 +135,8 @@
 }
 
 int HWCSession::Init() {
+  SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]);
+
   int status = -EINVAL;
   const char *qservice_name = "display.qservice";
 
@@ -224,6 +226,10 @@
 }
 
 int HWCSession::Deinit() {
+  Locker::SequenceCancelScopeLock lock_v(locker_[HWC_DISPLAY_VIRTUAL]);
+  Locker::SequenceCancelScopeLock lock_e(locker_[HWC_DISPLAY_EXTERNAL]);
+  Locker::SequenceCancelScopeLock lock_p(locker_[HWC_DISPLAY_PRIMARY]);
+
   HWCDisplay *primary_display = hwc_display_[HWC_DISPLAY_PRIMARY];
   if (primary_display) {
     if (hdmi_is_primary_) {
@@ -249,8 +255,6 @@
 }
 
 int HWCSession::Open(const hw_module_t *module, const char *name, hw_device_t **device) {
-  SCOPE_LOCK(locker_);
-
   if (!module || !name || !device) {
     DLOGE("Invalid parameters.");
     return -EINVAL;
@@ -275,8 +279,6 @@
 }
 
 int HWCSession::Close(hw_device_t *device) {
-  SCOPE_LOCK(locker_);
-
   if (!device) {
     return -EINVAL;
   }
@@ -317,20 +319,20 @@
 // Defined in the same order as in the HWC2 header
 
 int32_t HWCSession::AcceptDisplayChanges(hwc2_device_t *device, hwc2_display_t display) {
-  SCOPE_LOCK(locker_);
+  SCOPE_LOCK(locker_[display]);
   return HWCSession::CallDisplayFunction(device, display, &HWCDisplay::AcceptDisplayChanges);
 }
 
 int32_t HWCSession::CreateLayer(hwc2_device_t *device, hwc2_display_t display,
                                 hwc2_layer_t *out_layer_id) {
-  SCOPE_LOCK(locker_);
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_[display]);
   return CallDisplayFunction(device, display, &HWCDisplay::CreateLayer, out_layer_id);
 }
 
 int32_t HWCSession::CreateVirtualDisplay(hwc2_device_t *device, uint32_t width, uint32_t height,
                                          int32_t *format, hwc2_display_t *out_display_id) {
   // TODO(user): Handle concurrency with HDMI
-  SCOPE_LOCK(locker_);
+  SCOPE_LOCK(locker_[HWC_DISPLAY_VIRTUAL]);
   if (!device) {
     return HWC2_ERROR_BAD_DISPLAY;
   }
@@ -349,16 +351,16 @@
 
 int32_t HWCSession::DestroyLayer(hwc2_device_t *device, hwc2_display_t display,
                                  hwc2_layer_t layer) {
-  SCOPE_LOCK(locker_);
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_[display]);
   return CallDisplayFunction(device, display, &HWCDisplay::DestroyLayer, layer);
 }
 
 int32_t HWCSession::DestroyVirtualDisplay(hwc2_device_t *device, hwc2_display_t display) {
-  SCOPE_LOCK(locker_);
   if (!device || display != HWC_DISPLAY_VIRTUAL) {
     return HWC2_ERROR_BAD_DISPLAY;
   }
 
+  SCOPE_LOCK(locker_[display]);
   DLOGI("Destroying virtual display id:%" PRIu64, display);
   auto *hwc_session = static_cast<HWCSession *>(device);
 
@@ -372,8 +374,6 @@
 }
 
 void HWCSession::Dump(hwc2_device_t *device, uint32_t *out_size, char *out_buffer) {
-  SCOPE_LOCK(locker_);
-
   if (!device) {
     return;
   }
@@ -387,6 +387,7 @@
     DumpInterface::GetDump(sdm_dump, 4096);  // TODO(user): Fix this workaround
     std::string s("");
     for (int id = HWC_DISPLAY_PRIMARY; id <= HWC_DISPLAY_VIRTUAL; id++) {
+      SEQUENCE_WAIT_SCOPE_LOCK(locker_[id]);
       if (hwc_session->hwc_display_[id]) {
         s += hwc_session->hwc_display_[id]->Dump();
       }
@@ -490,6 +491,7 @@
                                    int32_t *out_retire_fence) {
   HWCSession *hwc_session = static_cast<HWCSession *>(device);
   DTRACE_SCOPED();
+  SEQUENCE_EXIT_SCOPE_LOCK(locker_[display]);
   if (!device) {
     return HWC2_ERROR_BAD_DISPLAY;
   }
@@ -541,14 +543,14 @@
 int32_t HWCSession::SetColorMode(hwc2_device_t *device, hwc2_display_t display,
                                  int32_t /*android_color_mode_t*/ int_mode) {
   auto mode = static_cast<android_color_mode_t>(int_mode);
-  SCOPE_LOCK(locker_);
+  SCOPE_LOCK(locker_[display]);
   return HWCSession::CallDisplayFunction(device, display, &HWCDisplay::SetColorMode, mode);
 }
 
 int32_t HWCSession::SetColorTransform(hwc2_device_t *device, hwc2_display_t display,
                                       const float *matrix,
                                       int32_t /*android_color_transform_t*/ hint) {
-  SCOPE_LOCK(locker_);
+  SCOPE_LOCK(locker_[display]);
   android_color_transform_t transform_hint = static_cast<android_color_transform_t>(hint);
   return HWCSession::CallDisplayFunction(device, display, &HWCDisplay::SetColorTransform, matrix,
                                          transform_hint);
@@ -634,7 +636,7 @@
 
 int32_t HWCSession::SetLayerZOrder(hwc2_device_t *device, hwc2_display_t display,
                                    hwc2_layer_t layer, uint32_t z) {
-  SCOPE_LOCK(locker_);
+  SCOPE_LOCK(locker_[display]);
   return CallDisplayFunction(device, display, &HWCDisplay::SetLayerZOrder, layer, z);
 }
 
@@ -648,6 +650,7 @@
     return HWC2_ERROR_UNSUPPORTED;
   }
 
+  SCOPE_LOCK(locker_[display]);
   auto *hwc_session = static_cast<HWCSession *>(device);
   if (hwc_session->hwc_display_[display]) {
     auto vds = reinterpret_cast<HWCDisplayVirtual *>(hwc_session->hwc_display_[display]);
@@ -660,7 +663,7 @@
 
 int32_t HWCSession::SetPowerMode(hwc2_device_t *device, hwc2_display_t display, int32_t int_mode) {
   auto mode = static_cast<HWC2::PowerMode>(int_mode);
-  SCOPE_LOCK(locker_);
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_[display]);
   return CallDisplayFunction(device, display, &HWCDisplay::SetPowerMode, mode);
 }
 
@@ -672,7 +675,6 @@
 int32_t HWCSession::ValidateDisplay(hwc2_device_t *device, hwc2_display_t display,
                                     uint32_t *out_num_types, uint32_t *out_num_requests) {
   DTRACE_SCOPED();
-  SCOPE_LOCK(locker_);
   HWCSession *hwc_session = static_cast<HWCSession *>(device);
   if (!device) {
     return HWC2_ERROR_BAD_DISPLAY;
@@ -681,25 +683,35 @@
   // TODO(user): Handle secure session, handle QDCM solid fill
   // Handle external_pending_connect_ in CreateVirtualDisplay
   auto status = HWC2::Error::BadDisplay;
-  if (hwc_session->hwc_display_[display]) {
-    if (display == HWC_DISPLAY_PRIMARY) {
-      // TODO(user): This can be moved to HWCDisplayPrimary
-      if (hwc_session->reset_panel_) {
-        DLOGW("panel is in bad state, resetting the panel");
-        hwc_session->ResetPanel();
+  {
+    SEQUENCE_ENTRY_SCOPE_LOCK(locker_[display]);
+    if (hwc_session->hwc_display_[display]) {
+      if (display == HWC_DISPLAY_PRIMARY) {
+        // TODO(user): This can be moved to HWCDisplayPrimary
+        if (hwc_session->reset_panel_) {
+          DLOGW("panel is in bad state, resetting the panel");
+          hwc_session->ResetPanel();
+        }
+
+        if (hwc_session->need_invalidate_) {
+          hwc_session->Refresh(display);
+        }
+
+        if (hwc_session->color_mgr_) {
+          hwc_session->color_mgr_->SetColorModeDetailEnhancer(hwc_session->hwc_display_[display]);
+        }
       }
 
-      if (hwc_session->need_invalidate_) {
-        hwc_session->Refresh(display);
-      }
-
-      if (hwc_session->color_mgr_) {
-        hwc_session->color_mgr_->SetColorModeDetailEnhancer(hwc_session->hwc_display_[display]);
-      }
+      status = hwc_session->hwc_display_[display]->Validate(out_num_types, out_num_requests);
     }
-
-    status = hwc_session->hwc_display_[display]->Validate(out_num_types, out_num_requests);
   }
+
+  // If validate fails, cancel the sequence lock so that other operations
+  // (such as Dump or SetPowerMode) may succeed without blocking on the condition
+  if (status == HWC2::Error::BadDisplay) {
+    SEQUENCE_CANCEL_SCOPE_LOCK(locker_[display]);
+  }
+
   return INT32(status);
 }
 
@@ -1013,8 +1025,6 @@
 android::status_t HWCSession::HandleGetDisplayAttributesForConfig(const android::Parcel
                                                                   *input_parcel,
                                                                   android::Parcel *output_parcel) {
-  SCOPE_LOCK(locker_);
-
   int config = input_parcel->readInt32();
   int dpy = input_parcel->readInt32();
   int error = android::BAD_VALUE;
@@ -1024,6 +1034,7 @@
     return android::BAD_VALUE;
   }
 
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_[dpy]);
   if (hwc_display_[dpy]) {
     error = hwc_display_[dpy]->GetDisplayAttributesForConfig(config, &display_attributes);
     if (error == 0) {
@@ -1040,7 +1051,7 @@
 }
 
 android::status_t HWCSession::ConfigureRefreshRate(const android::Parcel *input_parcel) {
-  SCOPE_LOCK(locker_);
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]);
 
   uint32_t operation = UINT32(input_parcel->readInt32());
   HWCDisplay *hwc_display = hwc_display_[HWC_DISPLAY_PRIMARY];
@@ -1066,20 +1077,19 @@
 }
 
 android::status_t HWCSession::SetDisplayMode(const android::Parcel *input_parcel) {
-  SCOPE_LOCK(locker_);
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]);
 
   uint32_t mode = UINT32(input_parcel->readInt32());
   return hwc_display_[HWC_DISPLAY_PRIMARY]->Perform(HWCDisplayPrimary::SET_DISPLAY_MODE, mode);
 }
 
 android::status_t HWCSession::SetMaxMixerStages(const android::Parcel *input_parcel) {
-  SCOPE_LOCK(locker_);
-
   DisplayError error = kErrorNone;
   std::bitset<32> bit_mask_display_type = UINT32(input_parcel->readInt32());
   uint32_t max_mixer_stages = UINT32(input_parcel->readInt32());
 
   if (bit_mask_display_type[HWC_DISPLAY_PRIMARY]) {
+    SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]);
     if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
       error = hwc_display_[HWC_DISPLAY_PRIMARY]->SetMaxMixerStages(max_mixer_stages);
       if (error != kErrorNone) {
@@ -1089,6 +1099,7 @@
   }
 
   if (bit_mask_display_type[HWC_DISPLAY_EXTERNAL]) {
+    SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_EXTERNAL]);
     if (hwc_display_[HWC_DISPLAY_EXTERNAL]) {
       error = hwc_display_[HWC_DISPLAY_EXTERNAL]->SetMaxMixerStages(max_mixer_stages);
       if (error != kErrorNone) {
@@ -1098,6 +1109,7 @@
   }
 
   if (bit_mask_display_type[HWC_DISPLAY_VIRTUAL]) {
+    SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_VIRTUAL]);
     if (hwc_display_[HWC_DISPLAY_VIRTUAL]) {
       error = hwc_display_[HWC_DISPLAY_VIRTUAL]->SetMaxMixerStages(max_mixer_stages);
       if (error != kErrorNone) {
@@ -1110,25 +1122,26 @@
 }
 
 void HWCSession::SetFrameDumpConfig(const android::Parcel *input_parcel) {
-  SCOPE_LOCK(locker_);
-
   uint32_t frame_dump_count = UINT32(input_parcel->readInt32());
   std::bitset<32> bit_mask_display_type = UINT32(input_parcel->readInt32());
   uint32_t bit_mask_layer_type = UINT32(input_parcel->readInt32());
 
   if (bit_mask_display_type[HWC_DISPLAY_PRIMARY]) {
+    SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]);
     if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
       hwc_display_[HWC_DISPLAY_PRIMARY]->SetFrameDumpConfig(frame_dump_count, bit_mask_layer_type);
     }
   }
 
   if (bit_mask_display_type[HWC_DISPLAY_EXTERNAL]) {
+    SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_EXTERNAL]);
     if (hwc_display_[HWC_DISPLAY_EXTERNAL]) {
       hwc_display_[HWC_DISPLAY_EXTERNAL]->SetFrameDumpConfig(frame_dump_count, bit_mask_layer_type);
     }
   }
 
   if (bit_mask_display_type[HWC_DISPLAY_VIRTUAL]) {
+    SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_VIRTUAL]);
     if (hwc_display_[HWC_DISPLAY_VIRTUAL]) {
       hwc_display_[HWC_DISPLAY_VIRTUAL]->SetFrameDumpConfig(frame_dump_count, bit_mask_layer_type);
     }
@@ -1136,8 +1149,6 @@
 }
 
 android::status_t HWCSession::SetMixerResolution(const android::Parcel *input_parcel) {
-  SCOPE_LOCK(locker_);
-
   DisplayError error = kErrorNone;
   uint32_t dpy = UINT32(input_parcel->readInt32());
 
@@ -1146,6 +1157,7 @@
     return -EINVAL;
   }
 
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]);
   if (!hwc_display_[HWC_DISPLAY_PRIMARY]) {
     DLOGI("Primary display is not initialized");
     return -EINVAL;
@@ -1166,6 +1178,8 @@
   auto display = static_cast<hwc2_display_t >(input_parcel->readInt32());
   auto mode = static_cast<android_color_mode_t>(input_parcel->readInt32());
   auto device = static_cast<hwc2_device_t *>(this);
+
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_[display]);
   auto err = CallDisplayFunction(device, display, &HWCDisplay::SetColorMode, mode);
   if (err != HWC2_ERROR_NONE)
     return -EINVAL;
@@ -1181,6 +1195,7 @@
     return -EINVAL;
   }
 
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_[display]);
   auto err = CallDisplayFunction(device, display, &HWCDisplay::SetColorModeById, mode);
   if (err != HWC2_ERROR_NONE)
     return -EINVAL;
@@ -1188,7 +1203,7 @@
 }
 
 void HWCSession::DynamicDebug(const android::Parcel *input_parcel) {
-  SCOPE_LOCK(locker_);
+  // TODO(user): Do we really need a lock here?
 
   int type = input_parcel->readInt32();
   bool enable = (input_parcel->readInt32() > 0);
@@ -1427,13 +1442,12 @@
   // To prevent sending events to client while a lock is held, acquire scope locks only within
   // below scope so that those get automatically unlocked after the scope ends.
   do {
-    SCOPE_LOCK(locker_);
-
     // If HDMI is primary but not created yet (first time), create it and notify surfaceflinger.
     //    if it is already created, but got disconnected/connected again,
     //    just toggle display status and do not notify surfaceflinger.
     // If HDMI is not primary, create/destroy external display normally.
     if (hdmi_is_primary_) {
+      SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]);
       if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
         status = hwc_display_[HWC_DISPLAY_PRIMARY]->SetState(connected);
       } else {
@@ -1445,13 +1459,18 @@
       break;
     }
 
-    // Primary display must be connected for HDMI as secondary cases.
-    if (!hwc_display_[HWC_DISPLAY_PRIMARY]) {
-      DLOGE("Primary display is not connected.");
-      return -1;
+    {
+      SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]);
+      // Primary display must be connected for HDMI as secondary cases.
+      if (!hwc_display_[HWC_DISPLAY_PRIMARY]) {
+        DLOGE("Primary display is not connected.");
+        return -1;
+      }
     }
 
     if (connected) {
+      SCOPE_LOCK(locker_[HWC_DISPLAY_EXTERNAL]);
+      Locker::ScopeLock lock_v(locker_[HWC_DISPLAY_VIRTUAL]);
       // Connect external display if virtual display is not connected.
       // Else, defer external display connection and process it when virtual display
       // tears down; Do not notify SurfaceFlinger since connection is deferred now.
@@ -1466,6 +1485,7 @@
         external_pending_connect_ = true;
       }
     } else {
+      SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_EXTERNAL]);
       // Do not return error if external display is not in connected status.
       // Due to virtual display concurrency, external display connection might be still pending
       // but hdmi got disconnected before pending connection could be processed.
@@ -1500,7 +1520,7 @@
 }
 
 int HWCSession::GetVsyncPeriod(int disp) {
-  SCOPE_LOCK(locker_);
+  SCOPE_LOCK(locker_[disp]);
   // default value
   int32_t vsync_period = 1000000000l / 60;
   auto attribute = HWC2::Attribute::VsyncPeriod;
@@ -1514,14 +1534,12 @@
 
 android::status_t HWCSession::GetVisibleDisplayRect(const android::Parcel *input_parcel,
                                                     android::Parcel *output_parcel) {
-  SCOPE_LOCK(locker_);
-
   int dpy = input_parcel->readInt32();
-
   if (dpy < HWC_DISPLAY_PRIMARY || dpy > HWC_DISPLAY_VIRTUAL) {
     return android::BAD_VALUE;
   }
 
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_[dpy]);
   if (!hwc_display_[dpy]) {
     return android::NO_INIT;
   }
diff --git a/sdm/libs/hwc2/hwc_session.h b/sdm/libs/hwc2/hwc_session.h
index f09ed0e..4dbcf9b 100644
--- a/sdm/libs/hwc2/hwc_session.h
+++ b/sdm/libs/hwc2/hwc_session.h
@@ -140,6 +140,12 @@
   static int32_t SetColorTransform(hwc2_device_t *device, hwc2_display_t display,
                                    const float *matrix, int32_t /*android_color_transform_t*/ hint);
 
+  // Meant to be called by HWCDisplay to preserve sequence of validate/present during events from
+  // polling thread
+  static void WaitForSequence(hwc2_display_t display) {
+    SEQUENCE_WAIT_SCOPE_LOCK(locker_[display]);
+  }
+
  private:
   static const int kExternalConnectionTimeoutMs = 500;
   static const int kPartialUpdateControlTimeoutMs = 100;
@@ -221,7 +227,7 @@
   void Refresh(hwc2_display_t display);
   void HotPlug(hwc2_display_t display, HWC2::Connection state);
 
-  static Locker locker_;
+  static Locker locker_[HWC_NUM_DISPLAY_TYPES];
   CoreInterface *core_intf_ = nullptr;
   HWCDisplay *hwc_display_[HWC_NUM_DISPLAY_TYPES] = {nullptr};
   HWCCallbacks callbacks_;
diff --git a/sdm/libs/hwc2/hwc_session_services.cpp b/sdm/libs/hwc2/hwc_session_services.cpp
index 425ffbe..a5cf66a 100644
--- a/sdm/libs/hwc2/hwc_session_services.cpp
+++ b/sdm/libs/hwc2/hwc_session_services.cpp
@@ -92,12 +92,12 @@
 // Methods from ::vendor::hardware::display::config::V1_0::IDisplayConfig follow.
 Return<void> HWCSession::isDisplayConnected(IDisplayConfig::DisplayType dpy,
                                             isDisplayConnected_cb _hidl_cb) {
-  SCOPE_LOCK(locker_);
-
   int32_t error = -EINVAL;
   bool connected = false;
 
   int disp_id = MapDisplayType(dpy);
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_[disp_id]);
+
   if (disp_id >= 0) {
     connected = hwc_display_[disp_id];
     error = 0;
@@ -109,12 +109,11 @@
 }
 
 int32_t HWCSession::SetSecondaryDisplayStatus(int disp_id, HWCDisplay::DisplayStatus status) {
-  SCOPE_LOCK(locker_);
-
   if (disp_id < 0) {
     return -EINVAL;
   }
 
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_[disp_id]);
   DLOGI("Display = %d, Status = %d", disp_id, status);
 
   if (disp_id == HWC_DISPLAY_PRIMARY) {
@@ -135,8 +134,7 @@
 
 Return<int32_t> HWCSession::configureDynRefeshRate(IDisplayConfig::DisplayDynRefreshRateOp op,
                                                    uint32_t refreshRate) {
-  SCOPE_LOCK(locker_);
-
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]);
   HWCDisplay *hwc_display = hwc_display_[HWC_DISPLAY_PRIMARY];
 
   switch (op) {
@@ -158,9 +156,13 @@
 }
 
 int32_t HWCSession::GetConfigCount(int disp_id, uint32_t *count) {
-  SCOPE_LOCK(locker_);
+  if (disp_id < 0) {
+    return -EINVAL;
+  }
 
-  if (disp_id >= 0 && hwc_display_[disp_id]) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_[disp_id]);
+
+  if (hwc_display_[disp_id]) {
     return hwc_display_[disp_id]->GetDisplayConfigCount(count);
   }
 
@@ -178,9 +180,13 @@
 }
 
 int32_t HWCSession::GetActiveConfigIndex(int disp_id, uint32_t *config) {
-  SCOPE_LOCK(locker_);
+  if (disp_id < 0) {
+    return -EINVAL;
+  }
 
-  if (disp_id >= 0 && hwc_display_[disp_id]) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_[disp_id]);
+
+  if (hwc_display_[disp_id]) {
     return hwc_display_[disp_id]->GetActiveDisplayConfig(config);
   }
 
@@ -198,12 +204,11 @@
 }
 
 int32_t HWCSession::SetActiveConfigIndex(int disp_id, uint32_t config) {
-  SCOPE_LOCK(locker_);
-
   if (disp_id < 0) {
     return -EINVAL;
   }
 
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_[disp_id]);
   int32_t error = -EINVAL;
   if (hwc_display_[disp_id]) {
     error = hwc_display_[disp_id]->SetActiveDisplayConfig(config);
@@ -222,12 +227,11 @@
 Return<void> HWCSession::getDisplayAttributes(uint32_t configIndex,
                                               IDisplayConfig::DisplayType dpy,
                                               getDisplayAttributes_cb _hidl_cb) {
-  SCOPE_LOCK(locker_);
-
   int32_t error = -EINVAL;
   IDisplayConfig::DisplayAttributes display_attributes = {};
-
   int disp_id = MapDisplayType(dpy);
+
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_[disp_id]);
   if (disp_id >= 0 && hwc_display_[disp_id]) {
     DisplayConfigVariableInfo hwc_display_attributes;
     error = hwc_display_[disp_id]->GetDisplayAttributesForConfig(static_cast<int>(configIndex),
@@ -247,9 +251,9 @@
 }
 
 Return<int32_t> HWCSession::setPanelBrightness(uint32_t level) {
-  SCOPE_LOCK(locker_);
-
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]);
   int32_t error = -EINVAL;
+
   if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
     error = hwc_display_[HWC_DISPLAY_PRIMARY]->SetPanelBrightness(static_cast<int>(level));
     if (error) {
@@ -261,8 +265,7 @@
 }
 
 int32_t HWCSession::GetPanelBrightness(int *level) {
-  SCOPE_LOCK(locker_);
-
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]);
   int32_t error = -EINVAL;
 
   if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
@@ -285,14 +288,13 @@
 }
 
 int32_t HWCSession::MinHdcpEncryptionLevelChanged(int disp_id, uint32_t min_enc_level) {
-  SCOPE_LOCK(locker_);
-
   DLOGI("Display %d", disp_id);
 
   if (disp_id < 0) {
     return -EINVAL;
   }
 
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_[disp_id]);
   if (disp_id != HWC_DISPLAY_EXTERNAL) {
     DLOGE("Not supported for display");
   } else if (!hwc_display_[disp_id]) {
@@ -310,16 +312,13 @@
 }
 
 Return<int32_t> HWCSession::refreshScreen() {
-  SCOPE_LOCK(locker_);
-
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]);
   Refresh(HWC_DISPLAY_PRIMARY);
 
   return 0;
 }
 
 int32_t HWCSession::ControlPartialUpdate(int disp_id, bool enable) {
-  SCOPE_LOCK(locker_);
-
   if (disp_id < 0) {
     return -EINVAL;
   }
@@ -329,6 +328,7 @@
     return -EINVAL;
   }
 
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_[disp_id]);
   HWCDisplay *hwc_display = hwc_display_[HWC_DISPLAY_PRIMARY];
   if (!hwc_display) {
     DLOGE("primary display object is not instantiated");
@@ -352,7 +352,7 @@
   Refresh(HWC_DISPLAY_PRIMARY);
 
   // Wait until partial update control is complete
-  int32_t error = locker_.WaitFinite(kPartialUpdateControlTimeoutMs);
+  int32_t error = locker_[disp_id].WaitFinite(kPartialUpdateControlTimeoutMs);
 
   return error;
 }
@@ -362,7 +362,7 @@
 }
 
 Return<int32_t> HWCSession::toggleScreenUpdate(bool on) {
-  SCOPE_LOCK(locker_);
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]);
 
   int32_t error = -EINVAL;
   if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
@@ -376,7 +376,7 @@
 }
 
 Return<int32_t> HWCSession::setIdleTimeout(uint32_t value) {
-  SCOPE_LOCK(locker_);
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]);
 
   if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
     hwc_display_[HWC_DISPLAY_PRIMARY]->SetIdleTimeoutMs(value);
@@ -388,8 +388,6 @@
 
 Return<void> HWCSession::getHDRCapabilities(IDisplayConfig::DisplayType dpy,
                                             getHDRCapabilities_cb _hidl_cb) {
-  SCOPE_LOCK(locker_);
-
   int32_t error = -EINVAL;
   IDisplayConfig::DisplayHDRCapabilities hdr_caps = {};
 
@@ -400,6 +398,7 @@
       break;
     }
 
+    SEQUENCE_WAIT_SCOPE_LOCK(locker_[disp_id]);
     HWCDisplay *hwc_display = hwc_display_[disp_id];
     if (!hwc_display) {
       DLOGE("Display = %d is not connected.", disp_id);
@@ -438,7 +437,7 @@
 }
 
 Return<int32_t> HWCSession::setCameraLaunchStatus(uint32_t on) {
-  SCOPE_LOCK(locker_);
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]);
 
   HWBwModes mode = on > 0 ? kBwCamera : kBwDefault;
 
@@ -457,7 +456,7 @@
 }
 
 int32_t HWCSession::DisplayBWTransactionPending(bool *status) {
-  SCOPE_LOCK(locker_);
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]);
 
   if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
     if (sync_wait(bw_mode_release_fd_, 0) < 0) {