sdm: Add support for dynamic panel operating mode switch.

This change add support for dynamic panel operating mode
switch in DRM.

Change-Id: I40d61fb81963a7f82303003825051764b93b1b94
diff --git a/sdm/libs/core/drm/hw_device_drm.cpp b/sdm/libs/core/drm/hw_device_drm.cpp
index 95d5845..ed8d372 100644
--- a/sdm/libs/core/drm/hw_device_drm.cpp
+++ b/sdm/libs/core/drm/hw_device_drm.cpp
@@ -724,6 +724,13 @@
   GetHWDisplayPortAndMode();
   GetHWPanelMaxBrightness();
 
+  if (current_mode.flags & DRM_MODE_FLAG_CMD_MODE_PANEL) {
+    hw_panel_info_.mode = kModeCommand;
+  }
+  if (current_mode.flags & DRM_MODE_FLAG_VID_MODE_PANEL) {
+    hw_panel_info_.mode = kModeVideo;
+  }
+
   DLOGI_IF(kTagDisplay, "%s, Panel Interface = %s, Panel Mode = %s, Is Primary = %d", device_name_,
         interface_str_.c_str(), hw_panel_info_.mode == kModeVideo ? "Video" : "Command",
         hw_panel_info_.is_primary_panel);
@@ -1187,6 +1194,28 @@
     drm_atomic_intf_->Perform(DRMOps::CRTC_SET_SECURITY_LEVEL, token_.crtc_id, crtc_security_level);
   }
 
+  if (reset_output_fence_offset_ && !validate) {
+    // Change back the fence_offset
+    drm_atomic_intf_->Perform(DRMOps::CRTC_SET_OUTPUT_FENCE_OFFSET, token_.crtc_id, 0);
+    reset_output_fence_offset_ = false;
+  }
+
+  // Set panel mode
+  if (panel_mode_changed_) {
+    for (uint32_t mode_index = 0; mode_index < connector_info_.modes.size(); mode_index++) {
+      if ((current_mode.vdisplay == connector_info_.modes[mode_index].mode.vdisplay) &&
+         (current_mode.hdisplay == connector_info_.modes[mode_index].mode.hdisplay) &&
+         (current_mode.vrefresh == connector_info_.modes[mode_index].mode.vrefresh) &&
+         (panel_mode_changed_ & connector_info_.modes[mode_index].mode.flags)) {
+        current_mode = connector_info_.modes[mode_index].mode;
+        if ((current_mode.flags & DRM_MODE_FLAG_VID_MODE_PANEL) && !validate) {
+          // Switch to video mode, corresponding change the fence_offset
+          drm_atomic_intf_->Perform(DRMOps::CRTC_SET_OUTPUT_FENCE_OFFSET, token_.crtc_id, 1);
+        }
+        break;
+      }
+    }
+  }
   if (hw_layers->hw_avr_info.update) {
     sde_drm::DRMQsyncMode mode = sde_drm::DRMQsyncMode::NONE;
     if (hw_layers->hw_avr_info.mode == kContinuousMode) {
@@ -1217,6 +1246,7 @@
       if ((current_mode.vdisplay == connector_info_.modes[mode_index].mode.vdisplay) &&
           (current_mode.hdisplay == connector_info_.modes[mode_index].mode.hdisplay) &&
           (current_bit_clk == connector_info_.modes[mode_index].bit_clk_rate) &&
+          (current_mode.flags == connector_info_.modes[mode_index].mode.flags) &&
           (vrefresh_ == connector_info_.modes[mode_index].mode.vrefresh)) {
         current_mode = connector_info_.modes[mode_index].mode;
         break;
@@ -1229,6 +1259,7 @@
       if ((current_mode.vdisplay == connector_info_.modes[mode_index].mode.vdisplay) &&
           (current_mode.hdisplay == connector_info_.modes[mode_index].mode.hdisplay) &&
           (current_mode.vrefresh == connector_info_.modes[mode_index].mode.vrefresh) &&
+          (current_mode.flags == connector_info_.modes[mode_index].mode.flags) &&
           (bit_clk_rate_ == connector_info_.modes[mode_index].bit_clk_rate)) {
         current_mode = connector_info_.modes[mode_index].mode;
         break;
@@ -1253,7 +1284,7 @@
   }
 
   // Set CRTC mode, only if display config changes
-  if (vrefresh_ || update_mode_) {
+  if (vrefresh_ || update_mode_ || panel_mode_changed_) {
     drm_atomic_intf_->Perform(DRMOps::CRTC_SET_MODE, token_.crtc_id, &current_mode);
   }
 
@@ -1319,6 +1350,7 @@
   if (ret) {
     DLOGE("failed with error %d for %s", ret, device_name_);
     vrefresh_ = 0;
+    panel_mode_changed_ = 0;
     err = kErrorHardware;
   }
 
@@ -1400,6 +1432,7 @@
   if (ret) {
     DLOGE("%s failed with error %d crtc %d", __FUNCTION__, ret, token_.crtc_id);
     vrefresh_ = 0;
+    panel_mode_changed_ = 0;
     CloseFd(&release_fence);
     CloseFd(&retire_fence);
     release_fence_ = -1;
@@ -1457,6 +1490,31 @@
     bit_clk_rate_ = 0;
   }
 
+  if (panel_mode_changed_) {
+    drmModeModeInfo current_mode = connector_info_.modes[current_mode_index_].mode;
+    for (uint32_t mode_index = 0; mode_index < connector_info_.modes.size(); mode_index++) {
+      if ((current_mode.vdisplay == connector_info_.modes[mode_index].mode.vdisplay) &&
+          (current_mode.hdisplay == connector_info_.modes[mode_index].mode.hdisplay) &&
+          (current_mode.vrefresh & connector_info_.modes[mode_index].mode.vrefresh) &&
+          (panel_mode_changed_ & connector_info_.modes[mode_index].mode.flags)) {
+        if (connector_info_.modes[mode_index].mode.flags & DRM_MODE_FLAG_CMD_MODE_PANEL) {
+          hw_panel_info_.mode = kModeCommand;
+          DLOGV_IF(kTagDriverConfig, "switch to command mode done, mode_index = %d\n",
+                    mode_index);
+        }
+        if (connector_info_.modes[mode_index].mode.flags & DRM_MODE_FLAG_VID_MODE_PANEL) {
+          hw_panel_info_.mode = kModeVideo;
+          reset_output_fence_offset_ = true;
+          DLOGV_IF(kTagDriverConfig, "switch to video mode done, mode_index = %d\n", mode_index);
+        }
+        current_mode_index_ = mode_index;
+        break;
+      }
+    }
+    panel_mode_changed_ = 0;
+    synchronous_commit_ = false;
+  }
+
   first_cycle_ = false;
   update_mode_ = false;
   hw_layers->updates_mask = 0;
@@ -1663,6 +1721,28 @@
 }
 
 DisplayError HWDeviceDRM::SetDisplayMode(const HWDisplayMode hw_display_mode) {
+  uint32_t mode_flag;
+
+  if (hw_display_mode == kModeCommand) {
+    mode_flag = DRM_MODE_FLAG_CMD_MODE_PANEL;
+    DLOGI("switch panel mode to command");
+  } else if (hw_display_mode == kModeVideo) {
+    mode_flag = DRM_MODE_FLAG_VID_MODE_PANEL;
+    DLOGI("switch panel mode to video");
+  }
+
+  drmModeModeInfo current_mode = connector_info_.modes[current_mode_index_].mode;
+  for (uint32_t mode_index = 0; mode_index < connector_info_.modes.size(); mode_index++) {
+    if ((current_mode.vdisplay == connector_info_.modes[mode_index].mode.vdisplay) &&
+        (current_mode.hdisplay == connector_info_.modes[mode_index].mode.hdisplay) &&
+        (current_mode.vrefresh == connector_info_.modes[mode_index].mode.vrefresh) &&
+        (mode_flag & connector_info_.modes[mode_index].mode.flags)) {
+      panel_mode_changed_ = mode_flag;
+      synchronous_commit_ = true;
+      return kErrorNone;
+    }
+  }
+
   return kErrorNotSupported;
 }
 
@@ -1680,6 +1760,7 @@
     if ((current_mode.vdisplay == connector_info_.modes[mode_index].mode.vdisplay) &&
         (current_mode.hdisplay == connector_info_.modes[mode_index].mode.hdisplay) &&
         (current_bit_clk == connector_info_.modes[mode_index].bit_clk_rate) &&
+        (current_mode.flags == connector_info_.modes[mode_index].mode.flags) &&
         (refresh_rate == connector_info_.modes[mode_index].mode.vrefresh)) {
       vrefresh_ = refresh_rate;
       DLOGV_IF(kTagDriverConfig, "Set refresh rate to %d", refresh_rate);
diff --git a/sdm/libs/core/drm/hw_device_drm.h b/sdm/libs/core/drm/hw_device_drm.h
index fe3dbc1..f718efb 100644
--- a/sdm/libs/core/drm/hw_device_drm.h
+++ b/sdm/libs/core/drm/hw_device_drm.h
@@ -223,6 +223,8 @@
   bool synchronous_commit_ = false;
   uint32_t topology_control_ = 0;
   uint32_t vrefresh_ = 0;
+  uint32_t panel_mode_changed_ = 0;
+  bool reset_output_fence_offset_ = false;
   uint64_t bit_clk_rate_ = 0;
   bool update_mode_ = false;
   DRMPowerMode last_power_mode_ = DRMPowerMode::OFF;