sdm : Add support for dynamic BW limit management

Read if device need to support dynamic bandwidth limit and
provide framework for applying a new total bandwidth limit and
per pipe bandwidth limit based on application scenario. Also
provide an API to query the status of bandwidth limit transaction.

Change-Id: Iaf9676a45c8c0c0c4af00c81ce4f5d70759c02ba
diff --git a/libqservice/IQService.h b/libqservice/IQService.h
index 422ddb2..2d7dddc 100644
--- a/libqservice/IQService.h
+++ b/libqservice/IQService.h
@@ -71,6 +71,7 @@
         SET_DISPLAY_MODE = 29, // Set display mode to command or video mode
         SET_CAMERA_STATUS = 30, // To notify display when camera is on and off
         MIN_HDCP_ENCRYPTION_LEVEL_CHANGED = 31,
+        GET_BW_TRANSACTION_STATUS = 32, //Client can query BW transaction status.
         COMMAND_LIST_END = 400,
     };
 
diff --git a/libqservice/QServiceUtils.h b/libqservice/QServiceUtils.h
index 73b2b18..8f25253 100644
--- a/libqservice/QServiceUtils.h
+++ b/libqservice/QServiceUtils.h
@@ -83,4 +83,20 @@
     return sendSingleParam(qService::IQService::SET_CAMERA_STATUS, on);
 }
 
+inline bool displayBWTransactionPending() {
+    android::status_t err = (android::status_t) android::FAILED_TRANSACTION;
+    bool ret = false;
+    android::sp<qService::IQService> binder = getBinder();
+    android::Parcel inParcel, outParcel;
+    if(binder != NULL) {
+        err = binder->dispatch(qService::IQService::GET_BW_TRANSACTION_STATUS,
+                &inParcel , &outParcel);
+        if(err != android::NO_ERROR){
+          ALOGE("GET_BW_TRANSACTION_STATUS binder call failed err=%d", err);
+          return ret;
+        }
+    }
+    ret = outParcel.readInt32();
+    return ret;
+}
 #endif /* end of include guard: QSERVICEUTILS_H */
diff --git a/sdm/include/core/core_interface.h b/sdm/include/core/core_interface.h
index 26f6e2f..582222f 100644
--- a/sdm/include/core/core_interface.h
+++ b/sdm/include/core/core_interface.h
@@ -76,6 +76,18 @@
 */
 class DebugHandler;
 
+/*! @brief This enum represents max bandwidth limit mode.
+
+  @sa DisplayInterface::SetMaxBandwidthMode
+*/
+enum HWBwModes {
+  kBwDefault,      //!< Default state. No change in device bandwidth limit.
+  kBwCamera,       //!< Camera is on. Bandwidth limit should be reduced accordingly.
+  kBwVFlip,        //!< VFlip is required. Reduce bandwidth limit accordingly.
+  kBwHFlip,        //!< HFlip is required.  Reduce bandwidth limit accordingly.
+  kBwModeMax,      //!< Limiter for maximum available bandwidth modes.
+};
+
 /*! @brief Display core interface.
 
   @details This class defines display core interfaces. It contains methods which client shall use
@@ -151,6 +163,16 @@
   */
   virtual DisplayError DestroyDisplay(DisplayInterface *interface) = 0;
 
+  /*! @brief Method to update the bandwidth limit as per given mode.
+
+    @param[in] mode indicate the mode or use case
+
+    @return \link DisplayError \endlink
+
+   */
+    virtual DisplayError SetMaxBandwidthMode(HWBwModes mode) = 0;
+
+
  protected:
   virtual ~CoreInterface() { }
 };
diff --git a/sdm/include/private/hw_info_types.h b/sdm/include/private/hw_info_types.h
index ab69041..3b668b8 100644
--- a/sdm/include/private/hw_info_types.h
+++ b/sdm/include/private/hw_info_types.h
@@ -27,6 +27,7 @@
 
 #include <stdint.h>
 #include <core/display_interface.h>
+#include <core/core_interface.h>
 
 namespace sdm {
 
@@ -65,6 +66,12 @@
   kPortEDP,
 };
 
+struct HWDynBwLimitInfo {
+  uint32_t cur_mode = kBwDefault;
+  uint32_t total_bw_limit[kBwModeMax] = { 0 };
+  uint32_t pipe_bw_limit[kBwModeMax] = { 0 };
+};
+
 struct HWResourceInfo {
   uint32_t hw_version = 0;
   uint32_t hw_revision = 0;
@@ -102,6 +109,8 @@
   bool has_non_scalar_rgb = false;
   bool is_src_split = false;
   bool perf_calc = false;
+  bool has_dyn_bw_support = false;
+  HWDynBwLimitInfo dyn_bw_info;
 
   void Reset() { *this = HWResourceInfo(); }
 };
diff --git a/sdm/include/private/resource_interface.h b/sdm/include/private/resource_interface.h
index 260bcf4..9a5aaea 100644
--- a/sdm/include/private/resource_interface.h
+++ b/sdm/include/private/resource_interface.h
@@ -51,6 +51,7 @@
                                             bool is_top) = 0;
   virtual DisplayError ValidateCursorPosition(Handle display_ctx, HWLayers *hw_layers,
                                               int x, int y) = 0;
+  virtual DisplayError SetMaxBandwidthMode(HWBwModes mode) = 0;
 
  protected:
   virtual ~ResourceInterface() { }
diff --git a/sdm/libs/core/comp_manager.cpp b/sdm/libs/core/comp_manager.cpp
index 2c64875..c08b413 100644
--- a/sdm/libs/core/comp_manager.cpp
+++ b/sdm/libs/core/comp_manager.cpp
@@ -437,6 +437,14 @@
   return supported;
 }
 
+DisplayError CompManager::SetMaxBandwidthMode(HWBwModes mode) {
+  if ((hw_res_info_.has_dyn_bw_support == false) || (mode >= kBwModeMax)) {
+    return kErrorNotSupported;
+  }
+
+  return resource_intf_->SetMaxBandwidthMode(mode);
+}
+
 bool CompManager::CanSetIdleTimeout(Handle display_ctx) {
   DisplayCompositionContext *display_comp_ctx =
                              reinterpret_cast<DisplayCompositionContext *>(display_ctx);
diff --git a/sdm/libs/core/comp_manager.h b/sdm/libs/core/comp_manager.h
index a6b1432..daef25e 100644
--- a/sdm/libs/core/comp_manager.h
+++ b/sdm/libs/core/comp_manager.h
@@ -60,6 +60,7 @@
   DisplayError ValidateCursorPosition(Handle display_ctx, HWLayers *hw_layers, int x, int y);
   bool SupportLayerAsCursor(Handle display_ctx, HWLayers *hw_layers);
   bool CanSetIdleTimeout(Handle display_ctx);
+  DisplayError SetMaxBandwidthMode(HWBwModes mode);
 
   // DumpImpl method
   virtual void AppendDump(char *buffer, uint32_t length);
diff --git a/sdm/libs/core/core_impl.cpp b/sdm/libs/core/core_impl.cpp
index 6a3ba1a..85ad2ff 100644
--- a/sdm/libs/core/core_impl.cpp
+++ b/sdm/libs/core/core_impl.cpp
@@ -206,5 +206,11 @@
   return kErrorNone;
 }
 
+DisplayError CoreImpl::SetMaxBandwidthMode(HWBwModes mode) {
+  SCOPE_LOCK(locker_);
+
+  return comp_mgr_.SetMaxBandwidthMode(mode);
+}
+
 }  // namespace sdm
 
diff --git a/sdm/libs/core/core_impl.h b/sdm/libs/core/core_impl.h
index c186754..06ca3d9 100644
--- a/sdm/libs/core/core_impl.h
+++ b/sdm/libs/core/core_impl.h
@@ -57,6 +57,7 @@
   virtual DisplayError CreateDisplay(DisplayType type, DisplayEventHandler *event_handler,
                                      DisplayInterface **intf);
   virtual DisplayError DestroyDisplay(DisplayInterface *intf);
+  virtual DisplayError SetMaxBandwidthMode(HWBwModes mode);
 
  protected:
   Locker locker_;
diff --git a/sdm/libs/core/fb/hw_info.cpp b/sdm/libs/core/fb/hw_info.cpp
index b9a6669..e163f9a 100644
--- a/sdm/libs/core/fb/hw_info.cpp
+++ b/sdm/libs/core/fb/hw_info.cpp
@@ -76,6 +76,61 @@
   return kErrorNone;
 }
 
+DisplayError HWInfo::GetDynamicBWLimits(HWResourceInfo *hw_resource) {
+  const char *bw_info_node = "/sys/devices/virtual/graphics/fb0/mdp/bw_mode_bitmap";
+  FILE *fileptr = NULL;
+  uint32_t token_count = 0;
+  const uint32_t max_count = kBwModeMax;
+  char *tokens[max_count] = { NULL };
+  fileptr = Sys::fopen_(bw_info_node, "r");
+
+  if (!fileptr) {
+    DLOGE("File '%s' not found", bw_info_node);
+    return kErrorHardware;
+  }
+
+  HWDynBwLimitInfo* bw_info = &hw_resource->dyn_bw_info;
+  for (int index = 0; index < kBwModeMax; index++) {
+    bw_info->total_bw_limit[index] = hw_resource->max_bandwidth_low;
+    bw_info->pipe_bw_limit[index] = hw_resource->max_pipe_bw;
+  }
+
+  char *stringbuffer = reinterpret_cast<char *>(malloc(kMaxStringLength));
+  if (stringbuffer == NULL) {
+    DLOGE("Failed to allocate stringbuffer");
+    return kErrorMemory;
+  }
+
+  size_t len = kMaxStringLength;
+  ssize_t read;
+  char *line = stringbuffer;
+  while ((read = Sys::getline_(&line, &len, fileptr)) != -1) {
+    if (!ParseLine(line, tokens, max_count, &token_count)) {
+      if (!strncmp(tokens[0], "default_pipe", strlen("default_pipe"))) {
+        bw_info->pipe_bw_limit[kBwDefault] = UINT32(atoi(tokens[1]));
+      } else if (!strncmp(tokens[0], "camera_pipe", strlen("camera_pipe"))) {
+        bw_info->pipe_bw_limit[kBwCamera] = UINT32(atoi(tokens[1]));
+      } else if (!strncmp(tokens[0], "vflip_pipe", strlen("vflip_pipe"))) {
+        bw_info->pipe_bw_limit[kBwVFlip] = UINT32(atoi(tokens[1]));
+      } else if (!strncmp(tokens[0], "hflip_pipe", strlen("hflip_pipe"))) {
+        bw_info->pipe_bw_limit[kBwHFlip] = UINT32(atoi(tokens[1]));
+      } else if (!strncmp(tokens[0], "default", strlen("default"))) {
+        bw_info->total_bw_limit[kBwDefault] = UINT32(atoi(tokens[1]));
+      } else if (!strncmp(tokens[0], "camera", strlen("camera"))) {
+        bw_info->total_bw_limit[kBwCamera] = UINT32(atoi(tokens[1]));
+      } else if (!strncmp(tokens[0], "vflip", strlen("vflip"))) {
+        bw_info->total_bw_limit[kBwVFlip] = UINT32(atoi(tokens[1]));
+      } else if (!strncmp(tokens[0], "hflip", strlen("hflip"))) {
+        bw_info->total_bw_limit[kBwHFlip] = UINT32(atoi(tokens[1]));
+      }
+    }
+  }
+  free(stringbuffer);
+  Sys::fclose_(fileptr);
+
+  return kErrorNone;
+}
+
 DisplayError HWInfo::GetHWResourceInfo(HWResourceInfo *hw_resource) {
   if (!hw_resource) {
     DLOGE("HWResourceInfo pointer in invalid.");
@@ -83,15 +138,22 @@
   }
   const char *fb_path = "/sys/devices/virtual/graphics/fb";
   FILE *fileptr = NULL;
-  char stringbuffer[kMaxStringLength];
   uint32_t token_count = 0;
   const uint32_t max_count = 10;
   char *tokens[max_count] = { NULL };
-  snprintf(stringbuffer , sizeof(stringbuffer), "%s%d/mdp/caps", fb_path, kHWCapabilitiesNode);
+  char *stringbuffer = reinterpret_cast<char *>(malloc(kMaxStringLength));
+
+  if (stringbuffer == NULL) {
+    DLOGE("Failed to allocate stringbuffer");
+    return kErrorMemory;
+  }
+
+  snprintf(stringbuffer , kMaxStringLength, "%s%d/mdp/caps", fb_path, kHWCapabilitiesNode);
   fileptr = Sys::fopen_(stringbuffer, "r");
 
   if (!fileptr) {
     DLOGE("File '%s' not found", stringbuffer);
+    free(stringbuffer);
     return kErrorHardware;
   }
 
@@ -160,6 +222,8 @@
             hw_resource->has_non_scalar_rgb = true;
           } else if (!strncmp(tokens[i], "perf_calc", strlen("perf_calc"))) {
             hw_resource->perf_calc = true;
+          } else if (!strncmp(tokens[i], "dynamic_bw_limit", strlen("dynamic_bw_limit"))) {
+            hw_resource->has_dyn_bw_support = true;
           }
         }
       }
@@ -185,11 +249,12 @@
         hw_resource->linear_factor, hw_resource->scale_factor, hw_resource->extra_fudge_factor);
 
   const char *rotator_caps_path = "/sys/devices/virtual/rotator/mdss_rotator/caps";
-  snprintf(stringbuffer , sizeof(stringbuffer), "%s", rotator_caps_path);
+  snprintf(stringbuffer , kMaxStringLength, "%s", rotator_caps_path);
   fileptr = Sys::fopen_(stringbuffer, "r");
 
   if (!fileptr) {
     DLOGW("File '%s' not found", stringbuffer);
+    free(stringbuffer);
     return kErrorNone;
   }
 
@@ -203,11 +268,27 @@
     }
   }
 
+  free(stringbuffer);
   Sys::fclose_(fileptr);
 
   DLOGI("ROTATOR = %d, Rotator Downscale = %d", hw_resource->num_rotator,
         hw_resource->has_rotator_downscale);
 
+  if (hw_resource->has_dyn_bw_support) {
+    DisplayError ret = GetDynamicBWLimits(hw_resource);
+    if (ret != kErrorNone) {
+      DLOGE("Failed to read dynamic band width info");
+      return ret;
+    }
+
+    DLOGI("Has Support for multiple bw limits shown below");
+    for (int index = 0; index < kBwModeMax; index++) {
+      DLOGI("Mode-index=%d  total_bw_limit=%d and pipe_bw_limit=%d",
+            index, hw_resource->dyn_bw_info.total_bw_limit[index],
+            hw_resource->dyn_bw_info.pipe_bw_limit[index]);
+    }
+  }
+
   return kErrorNone;
 }
 
diff --git a/sdm/libs/core/fb/hw_info.h b/sdm/libs/core/fb/hw_info.h
index 350c6ff..9372734 100644
--- a/sdm/libs/core/fb/hw_info.h
+++ b/sdm/libs/core/fb/hw_info.h
@@ -45,6 +45,7 @@
   static const int kHWCapabilitiesNode = 0;
 
   static int ParseLine(char *input, char *tokens[], const uint32_t max_token, uint32_t *count);
+  DisplayError GetDynamicBWLimits(HWResourceInfo *hw_resource);
 };
 
 }  // namespace sdm
diff --git a/sdm/libs/core/resource_default.cpp b/sdm/libs/core/resource_default.cpp
index aa6651f..ca73c36 100644
--- a/sdm/libs/core/resource_default.cpp
+++ b/sdm/libs/core/resource_default.cpp
@@ -917,6 +917,10 @@
   return kErrorNotSupported;
 }
 
+DisplayError ResourceDefault::SetMaxBandwidthMode(HWBwModes mode) {
+  return kErrorNotSupported;
+}
+
 bool ResourceDefault::IsUBWCFormat(LayerBufferFormat format) {
   switch (format) {
   case kFormatRGBA8888Ubwc:
diff --git a/sdm/libs/core/resource_default.h b/sdm/libs/core/resource_default.h
index ce7d78b..67bb0fd 100644
--- a/sdm/libs/core/resource_default.h
+++ b/sdm/libs/core/resource_default.h
@@ -53,6 +53,7 @@
                                        bool rotate90, bool ubwc_tiled, bool use_rotator_downscale);
   DisplayError ValidateCursorConfig(Handle display_ctx, const Layer& layer, bool is_top);
   DisplayError ValidateCursorPosition(Handle display_ctx, HWLayers *hw_layers, int x, int y);
+  DisplayError SetMaxBandwidthMode(HWBwModes mode);
 
  private:
   enum PipeId {
diff --git a/sdm/libs/hwc/hwc_session.cpp b/sdm/libs/hwc/hwc_session.cpp
index dbd06a7..779b440 100644
--- a/sdm/libs/hwc/hwc_session.cpp
+++ b/sdm/libs/hwc/hwc_session.cpp
@@ -42,6 +42,7 @@
 #include <gralloc_priv.h>
 #include <display_config.h>
 #include <utils/debug.h>
+#include <sync/sync.h>
 
 #include "hwc_buffer_allocator.h"
 #include "hwc_buffer_sync_handler.h"
@@ -74,7 +75,6 @@
 namespace sdm {
 
 Locker HWCSession::locker_;
-bool HWCSession::reset_panel_ = false;
 
 static void Invalidate(const struct hwc_procs *procs) {
 }
@@ -246,11 +246,15 @@
 
     hwc_procs = hwc_session->hwc_procs_;
 
-    if (reset_panel_) {
+    if (hwc_session->reset_panel_) {
       DLOGW("panel is in bad state, resetting the panel");
       hwc_session->ResetPanel();
     }
 
+    if (hwc_session->need_invalidate_) {
+      hwc_procs->invalidate(hwc_procs);
+    }
+
     hwc_session->HandleSecureDisplaySession(displays);
 
     if (hwc_session->color_mgr_) {
@@ -361,6 +365,15 @@
     }
   }
 
+  if (hwc_session->new_bw_mode_) {
+    hwc_display_contents_1_t *content_list = displays[HWC_DISPLAY_PRIMARY];
+    hwc_session->new_bw_mode_ = false;
+    if (hwc_session->bw_mode_release_fd_ >= 0) {
+      close(hwc_session->bw_mode_release_fd_);
+    }
+    hwc_session->bw_mode_release_fd_ = dup(content_list->retireFenceFd);
+  }
+
   // Return 0, else client will go into bad state
   return 0;
 }
@@ -678,6 +691,14 @@
     status = GetVisibleDisplayRect(input_parcel, output_parcel);
     break;
 
+  case qService::IQService::SET_CAMERA_STATUS:
+    status = SetDynamicBWForCamera(input_parcel, output_parcel);
+    break;
+
+  case qService::IQService::GET_BW_TRANSACTION_STATUS:
+    status = GetBWTransactionStatus(input_parcel, output_parcel);
+    break;
+
   default:
     DLOGW("QService command = %d is not supported", command);
     return -EINVAL;
@@ -959,6 +980,41 @@
   return 0;
 }
 
+android::status_t HWCSession::SetDynamicBWForCamera(const android::Parcel *input_parcel,
+                                                    android::Parcel *output_parcel) {
+  DisplayError error = kErrorNone;
+  uint32_t camera_status = UINT32(input_parcel->readInt32());
+  HWBwModes mode = camera_status > 0 ? kBwCamera : kBwDefault;
+
+  // trigger invalidate to apply new bw caps.
+  hwc_procs_->invalidate(hwc_procs_);
+
+    error = core_intf_->SetMaxBandwidthMode(mode);
+  if (error != kErrorNone) {
+      return -EINVAL;
+  }
+
+  new_bw_mode_ = true;
+  need_invalidate_ = true;
+
+  return 0;
+}
+
+android::status_t HWCSession::GetBWTransactionStatus(const android::Parcel *input_parcel,
+                                                     android::Parcel *output_parcel)  {
+  bool state = true;
+
+  if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
+    if (sync_wait(bw_mode_release_fd_, 0) < 0) {
+      DLOGI("bw_transaction_release_fd is not yet signalled: err= %s", strerror(errno));
+      state = false;
+    }
+    output_parcel->writeInt32(state);
+  }
+
+  return 0;
+}
+
 void HWCSession::SetFrameDumpConfig(const android::Parcel *input_parcel) {
   uint32_t frame_dump_count = UINT32(input_parcel->readInt32());
   uint32_t bit_mask_display_type = UINT32(input_parcel->readInt32());
diff --git a/sdm/libs/hwc/hwc_session.h b/sdm/libs/hwc/hwc_session.h
index 78c9894..455ea83 100644
--- a/sdm/libs/hwc/hwc_session.h
+++ b/sdm/libs/hwc/hwc_session.h
@@ -117,6 +117,10 @@
   android::status_t GetVisibleDisplayRect(const android::Parcel *input_parcel,
                                           android::Parcel *output_parcel);
 
+  android::status_t SetDynamicBWForCamera(const android::Parcel *input_parcel,
+                                          android::Parcel *output_parcel);
+  android::status_t GetBWTransactionStatus(const android::Parcel *input_parcel,
+                                          android::Parcel *output_parcel);
   static Locker locker_;
   CoreInterface *core_intf_ = NULL;
   hwc_procs_t hwc_procs_default_;
@@ -128,9 +132,12 @@
   HWCBufferAllocator *buffer_allocator_ = NULL;
   HWCBufferSyncHandler *buffer_sync_handler_ = NULL;
   HWCColorManager *color_mgr_ = NULL;
-  static bool reset_panel_;
+  bool reset_panel_ = false;
   bool secure_display_active_ = false;
   bool external_pending_connect_ = false;
+  bool new_bw_mode_ = false;
+  bool need_invalidate_ = false;
+  int bw_mode_release_fd_ = -1;
 };
 
 }  // namespace sdm