sdm: Defer vsync enable/disable when display is powered off

DRM framework rejects vsync enable/disable request when it is requested
before display is powered on. Hence defer the request after display is
powered on.

Change-Id: I3063479c8efc03d87f736a069ad742ae18296fd5
diff --git a/include/display_properties.h b/include/display_properties.h
index 8b0ab16..a5c1378 100644
--- a/include/display_properties.h
+++ b/include/display_properties.h
@@ -121,6 +121,7 @@
 #define VIRTUAL_BASEID_AND_SIZE_PROP         DISPLAY_PROP("virtual_baseid_and_size")
 #define ENABLE_QDCM_DIAG                     DISPLAY_PROP("enable_qdcm_diag")
 #define QDCM_DISABLE_FACTORY_MODE_PROP       DISPLAY_PROP("qdcm.disable_factory_mode")
+#define DISABLE_DEFER_POWER_STATE            DISPLAY_PROP("disable_defer_power_state")
 
 #define ZERO_SWAP_INTERVAL                   "vendor.debug.egl.swapinterval"
 #define ENABLE_OPTIMIZE_REFRESH              DISPLAY_PROP("enable_optimize_refresh")
diff --git a/sdm/libs/core/display_base.cpp b/sdm/libs/core/display_base.cpp
index 60e082b..6d63858 100755
--- a/sdm/libs/core/display_base.cpp
+++ b/sdm/libs/core/display_base.cpp
@@ -283,6 +283,14 @@
   lock_guard<recursive_mutex> obj(recursive_mutex_);
   DisplayError error = kErrorNone;
   needs_validate_ = true;
+  if (defer_power_state_ && power_state_pending_ != kStateOff) {
+    defer_power_state_ = false;
+    error = SetDisplayState(power_state_pending_, false, NULL);
+    if (error != kErrorNone) {
+      return error;
+    }
+    power_state_pending_ = kStateOff;
+  }
 
   DTRACE_SCOPED();
   if (!active_) {
@@ -516,6 +524,14 @@
 DisplayError DisplayBase::SetDisplayState(DisplayState state, bool teardown,
                                           int *release_fence) {
   lock_guard<recursive_mutex> obj(recursive_mutex_);
+  if (defer_power_state_) {
+    if (state == kStateOff) {
+      DLOGE("State cannot be PowerOff on first cycle");
+      return kErrorParameters;
+    }
+    power_state_pending_ = state;
+    return kErrorNone;
+  }
   DisplayError error = kErrorNone;
   bool active = false;
 
@@ -581,6 +597,14 @@
     comp_manager_->SetDisplayState(display_comp_ctx_, state, release_fence ? *release_fence : -1);
   }
 
+  if (vsync_state_change_pending_ && (state_ != kStateOff || state_ != kStateStandby)) {
+    error = SetVSyncState(requested_vsync_state_);
+    if (error != kErrorNone) {
+      return error;
+    }
+    vsync_state_change_pending_ = false;
+  }
+
   return error;
 }
 
@@ -1092,6 +1116,14 @@
 
 DisplayError DisplayBase::SetVSyncState(bool enable) {
   lock_guard<recursive_mutex> obj(recursive_mutex_);
+  if (state_ == kStateOff) {
+    DLOGW("Can't %s vsync when power state is off for display %d-%d," \
+          "Defer it when display is active", enable ? "enable":"disable",
+          display_id_, display_type_);
+    vsync_state_change_pending_ = true;
+    requested_vsync_state_ = enable;
+    return kErrorNone;
+  }
   DisplayError error = kErrorNone;
   if (vsync_enable_ != enable) {
     error = hw_intf_->SetVSyncState(enable);
diff --git a/sdm/libs/core/display_base.h b/sdm/libs/core/display_base.h
index f33acd5..a4f2330 100644
--- a/sdm/libs/core/display_base.h
+++ b/sdm/libs/core/display_base.h
@@ -232,6 +232,10 @@
   uint32_t current_refresh_rate_ = 0;
   bool drop_skewed_vsync_ = false;
   bool custom_mixer_resolution_ = false;
+  DisplayState power_state_pending_ = kStateOff;
+  bool vsync_state_change_pending_ = false;
+  bool requested_vsync_state_ = false;
+  bool defer_power_state_ = false;
 
   static Locker display_power_reset_lock_;
   static bool display_power_reset_pending_;
diff --git a/sdm/libs/core/display_builtin.cpp b/sdm/libs/core/display_builtin.cpp
index 73b9a9d..153b018 100644
--- a/sdm/libs/core/display_builtin.cpp
+++ b/sdm/libs/core/display_builtin.cpp
@@ -56,6 +56,7 @@
 
 DisplayError DisplayBuiltIn::Init() {
   lock_guard<recursive_mutex> obj(recursive_mutex_);
+  int32_t disable_defer_power_state = 0;
 
   DisplayError error = HWInterface::Create(display_id_, kBuiltIn, hw_info_intf_,
                                            buffer_sync_handler_, buffer_allocator_, &hw_intf_);
@@ -110,6 +111,11 @@
 
   current_refresh_rate_ = hw_panel_info_.max_fps;
 
+  Debug::GetProperty(DISABLE_DEFER_POWER_STATE, &disable_defer_power_state);
+  defer_power_state_ = !disable_defer_power_state;
+
+  DLOGI("defer_power_state %d", defer_power_state_);
+
   return error;
 }
 
diff --git a/sdm/libs/core/display_pluggable.cpp b/sdm/libs/core/display_pluggable.cpp
index 5bed20a..4e184e8 100644
--- a/sdm/libs/core/display_pluggable.cpp
+++ b/sdm/libs/core/display_pluggable.cpp
@@ -130,6 +130,12 @@
 
   current_refresh_rate_ = hw_panel_info_.max_fps;
 
+  if (IsPrimaryDisplay()) {
+    int32_t disable_defer_power_state = 0;
+    Debug::GetProperty(DISABLE_DEFER_POWER_STATE, &disable_defer_power_state);
+    defer_power_state_ = !disable_defer_power_state;
+  }
+
   return error;
 }
 
diff --git a/sdm/libs/core/drm/hw_device_drm.cpp b/sdm/libs/core/drm/hw_device_drm.cpp
index 2211e07..a9531c7 100644
--- a/sdm/libs/core/drm/hw_device_drm.cpp
+++ b/sdm/libs/core/drm/hw_device_drm.cpp
@@ -900,17 +900,27 @@
 
   int64_t release_fence_t = -1;
   update_mode_ = true;
+
+  if (first_cycle_) {
+    drm_atomic_intf_->Perform(DRMOps::CONNECTOR_SET_CRTC, token_.conn_id, token_.crtc_id);
+    drmModeModeInfo current_mode = connector_info_.modes[current_mode_index_].mode;
+    drm_atomic_intf_->Perform(DRMOps::CRTC_SET_MODE, token_.crtc_id, &current_mode);
+  }
   drm_atomic_intf_->Perform(DRMOps::CRTC_SET_ACTIVE, token_.crtc_id, 1);
   drm_atomic_intf_->Perform(DRMOps::CONNECTOR_SET_POWER_MODE, token_.conn_id, DRMPowerMode::ON);
-  drm_atomic_intf_->Perform(DRMOps::CRTC_GET_RELEASE_FENCE, token_.crtc_id, &release_fence_t);
+  if (release_fence) {
+    drm_atomic_intf_->Perform(DRMOps::CRTC_GET_RELEASE_FENCE, token_.crtc_id, &release_fence_t);
+  }
   int ret = NullCommit(true /* synchronous */, true /* retain_planes */);
   if (ret) {
     DLOGE("Failed with error: %d", ret);
     return kErrorHardware;
   }
 
-  *release_fence = static_cast<int>(release_fence_t);
-  DLOGD_IF(kTagDriverConfig, "RELEASE fence created: fd:%d", *release_fence);
+  if (release_fence) {
+    *release_fence = static_cast<int>(release_fence_t);
+    DLOGD_IF(kTagDriverConfig, "RELEASE fence created: fd:%d", *release_fence);
+  }
   pending_doze_ = false;
 
   return kErrorNone;
@@ -960,15 +970,19 @@
 
   drm_atomic_intf_->Perform(DRMOps::CRTC_SET_ACTIVE, token_.crtc_id, 1);
   drm_atomic_intf_->Perform(DRMOps::CONNECTOR_SET_POWER_MODE, token_.conn_id, DRMPowerMode::DOZE);
-  drm_atomic_intf_->Perform(DRMOps::CRTC_GET_RELEASE_FENCE, token_.crtc_id, &release_fence_t);
+  if (release_fence) {
+    drm_atomic_intf_->Perform(DRMOps::CRTC_GET_RELEASE_FENCE, token_.crtc_id, &release_fence_t);
+  }
   int ret = NullCommit(true /* synchronous */, true /* retain_planes */);
   if (ret) {
     DLOGE("Failed with error: %d", ret);
     return kErrorHardware;
   }
 
-  *release_fence = static_cast<int>(release_fence_t);
-  DLOGD_IF(kTagDriverConfig, "RELEASE fence created: fd:%d", *release_fence);
+  if (release_fence) {
+    *release_fence = static_cast<int>(release_fence_t);
+    DLOGD_IF(kTagDriverConfig, "RELEASE fence created: fd:%d", *release_fence);
+  }
   return kErrorNone;
 }
 
@@ -987,17 +1001,21 @@
   drm_atomic_intf_->Perform(DRMOps::CRTC_SET_ACTIVE, token_.crtc_id, 1);
   drm_atomic_intf_->Perform(DRMOps::CONNECTOR_SET_POWER_MODE, token_.conn_id,
                             DRMPowerMode::DOZE_SUSPEND);
-  drm_atomic_intf_->Perform(DRMOps::CRTC_GET_RELEASE_FENCE, token_.crtc_id, &release_fence_t);
+  if (release_fence) {
+    drm_atomic_intf_->Perform(DRMOps::CRTC_GET_RELEASE_FENCE, token_.crtc_id, &release_fence_t);
+  }
   int ret = NullCommit(true /* synchronous */, true /* retain_planes */);
   if (ret) {
     DLOGE("Failed with error: %d", ret);
     return kErrorHardware;
   }
 
-  *release_fence = static_cast<int>(release_fence_t);
-  DLOGD_IF(kTagDriverConfig, "RELEASE fence created: fd:%d", *release_fence);
-  pending_doze_ = false;
+  if (release_fence) {
+    *release_fence = static_cast<int>(release_fence_t);
+    DLOGD_IF(kTagDriverConfig, "RELEASE fence created: fd:%d", *release_fence);
+  }
 
+  pending_doze_ = false;
   return kErrorNone;
 }
 
@@ -1241,7 +1259,7 @@
   }
 
   // Set CRTC mode, only if display config changes
-  if (vrefresh_ || first_cycle_ || update_mode_) {
+  if (vrefresh_ || update_mode_) {
     drm_atomic_intf_->Perform(DRMOps::CRTC_SET_MODE, token_.crtc_id, &current_mode);
   }
 
diff --git a/sdm/libs/core/drm/hw_events_drm.cpp b/sdm/libs/core/drm/hw_events_drm.cpp
index e63605e..3bb9a6a 100644
--- a/sdm/libs/core/drm/hw_events_drm.cpp
+++ b/sdm/libs/core/drm/hw_events_drm.cpp
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+* Copyright (c) 2017-2019, 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
@@ -222,8 +222,6 @@
     return kErrorResources;
   }
 
-  RegisterVSync();
-  vsync_registered_ = true;
   RegisterPanelDead(true);
   RegisterIdleNotify(true);
   RegisterIdlePowerCollapse(true);
diff --git a/sdm/libs/core/drm/hw_peripheral_drm.cpp b/sdm/libs/core/drm/hw_peripheral_drm.cpp
index ec865fe..b7771a0 100644
--- a/sdm/libs/core/drm/hw_peripheral_drm.cpp
+++ b/sdm/libs/core/drm/hw_peripheral_drm.cpp
@@ -436,9 +436,6 @@
     return kErrorUndefined;
   }
 
-  if (first_cycle_) {
-    return kErrorNone;
-  }
   drm_atomic_intf_->Perform(sde_drm::DRMOps::CRTC_SET_IDLE_PC_STATE, token_.crtc_id,
                             sde_drm::DRMIdlePCState::ENABLE);
   DisplayError err = HWDeviceDRM::PowerOn(qos_data, release_fence);
diff --git a/sdm/libs/core/drm/hw_tv_drm.cpp b/sdm/libs/core/drm/hw_tv_drm.cpp
index ad39b86..4b2dc89 100644
--- a/sdm/libs/core/drm/hw_tv_drm.cpp
+++ b/sdm/libs/core/drm/hw_tv_drm.cpp
@@ -356,10 +356,6 @@
     return kErrorUndefined;
   }
 
-  if (first_cycle_) {
-    return kErrorNone;
-  }
-
   return HWDeviceDRM::PowerOn(qos_data, release_fence);
 }
 
diff --git a/sdm/libs/core/drm/hw_virtual_drm.cpp b/sdm/libs/core/drm/hw_virtual_drm.cpp
index 152e28c..97b77e0 100644
--- a/sdm/libs/core/drm/hw_virtual_drm.cpp
+++ b/sdm/libs/core/drm/hw_virtual_drm.cpp
@@ -233,10 +233,6 @@
     return kErrorUndefined;
   }
 
-  if (first_cycle_) {
-    return kErrorNone;
-  }
-
   DisplayError err = HWDeviceDRM::PowerOn(qos_data, release_fence);
   if (err != kErrorNone) {
     return err;