Merge "sdm: Add support to get/set DSI clk."
diff --git a/libdrmutils/drm_interface.h b/libdrmutils/drm_interface.h
index 8cb300a..20e3abc 100644
--- a/libdrmutils/drm_interface.h
+++ b/libdrmutils/drm_interface.h
@@ -584,6 +584,7 @@
   int wmin;
   int hmin;
   bool roi_merge;
+  uint64_t bit_clk_rate;
 };
 
 /* Per Connector Info*/
@@ -610,6 +611,7 @@
   bool is_connected;
   bool is_wb_ubwc_supported;
   uint32_t topology_control;
+  bool dyn_bitclk_support;
 };
 
 // All DRM Connectors as map<Connector_id , connector_info>
diff --git a/libqdutils/display_config.cpp b/libqdutils/display_config.cpp
index 964640f..fc2e3dc 100644
--- a/libqdutils/display_config.cpp
+++ b/libqdutils/display_config.cpp
@@ -316,6 +316,60 @@
     return panel_brightness;
 }
 
+int setDsiClk(int dpy, uint64_t bitClk) {
+    status_t err = (status_t) FAILED_TRANSACTION;
+    sp<IQService> binder = getBinder();
+    Parcel inParcel, outParcel;
+
+    if(binder != NULL) {
+        inParcel.writeInt32(dpy);
+        inParcel.writeUint64(bitClk);
+        status_t err = binder->dispatch(IQService::SET_DSI_CLK, &inParcel, &outParcel);
+        if(err) {
+            ALOGE("%s() failed with err %d", __FUNCTION__, err);
+        }
+    }
+    return err;
+}
+
+uint64_t getDsiClk(int dpy) {
+    uint64_t dsi_clk = 0;
+    sp<IQService> binder = getBinder();
+    Parcel inParcel, outParcel;
+
+    if(binder != NULL) {
+        inParcel.writeInt32(dpy);
+        status_t err = binder->dispatch(IQService::GET_DSI_CLK, &inParcel, &outParcel);
+        if(!err) {
+            dsi_clk = outParcel.readUint64();
+        } else {
+            ALOGE("%s() failed with err %d", __FUNCTION__, err);
+        }
+    }
+    return dsi_clk;
+}
+
+int getSupportedBitClk(int dpy, std::vector<uint64_t>& bit_rates) {
+    sp<IQService> binder = getBinder();
+    Parcel inParcel, outParcel;
+
+    if(binder != NULL) {
+        inParcel.writeInt32(dpy);
+        status_t err = binder->dispatch(IQService::GET_SUPPORTED_DSI_CLK, &inParcel, &outParcel);
+        if(err) {
+            ALOGE("%s() failed with err %d", __FUNCTION__, err);
+            return err;
+        }
+    }
+
+    int32_t clk_levels = outParcel.readInt32();
+    while (clk_levels > 0) {
+      bit_rates.push_back(outParcel.readUint64());
+      clk_levels--;
+    }
+    return 0;
+}
+
 }// namespace
 
 // ----------------------------------------------------------------------------
diff --git a/libqdutils/display_config.h b/libqdutils/display_config.h
index 8373c90..c0952b0 100644
--- a/libqdutils/display_config.h
+++ b/libqdutils/display_config.h
@@ -30,6 +30,8 @@
 #ifndef _DISPLAY_CONFIG_H
 #define _DISPLAY_CONFIG_H
 
+#include <vector>
+
 #include <gralloc_priv.h>
 #include <qdMetaData.h>
 #include <hardware/hwcomposer.h>
@@ -160,6 +162,15 @@
 // Retrieves the current panel brightness value
 int getPanelBrightness();
 
+// Sets the specified bit clk value.
+int setDsiClk(int dpy, uint64_t bitClk);
+
+// Retrieves the current bit clk value.
+uint64_t getDsiClk(int dpy);
+
+// Get supported bit clk values.
+int getSupportedBitClk(int dpy, std::vector<uint64_t>& bit_rates);
+
 }; //namespace
 
 
diff --git a/libqservice/IQService.h b/libqservice/IQService.h
index 11cbf22..569c4ea 100644
--- a/libqservice/IQService.h
+++ b/libqservice/IQService.h
@@ -81,6 +81,9 @@
         SET_COLOR_MODE_WITH_RENDER_INTENT = 39,
         SET_IDLE_PC = 40, // Enable/disable Idle power collapse
         SET_DPPS_AD4_ROI_CONFIG = 41, // Set ad4 roi config for debug
+        SET_DSI_CLK = 42, // Set DSI Clk.
+        GET_DSI_CLK = 43, // Get DSI Clk.
+        GET_SUPPORTED_DSI_CLK = 44, // Get supported DSI Clk.
         COMMAND_LIST_END = 400,
     };
 
diff --git a/sdm/include/core/display_interface.h b/sdm/include/core/display_interface.h
index 899a52f..dd3481f 100644
--- a/sdm/include/core/display_interface.h
+++ b/sdm/include/core/display_interface.h
@@ -204,6 +204,12 @@
   uint32_t fps = 0;               //!< Frame rate per second.
   uint32_t vsync_period_ns = 0;   //!< VSync period in nanoseconds.
   bool is_yuv = false;            //!< If the display output is in YUV format.
+
+  bool operator==(const DisplayConfigVariableInfo& info) const {
+    return ((x_pixels == info.x_pixels) && (y_pixels == info.y_pixels) && (x_dpi == info.x_dpi) &&
+            (y_dpi == info.y_dpi) && (fps == info.fps) && (vsync_period_ns == info.vsync_period_ns)
+            && (is_yuv == info.is_yuv));
+  }
 };
 
 /*! @brief Event data associated with VSync event.
@@ -781,6 +787,30 @@
   */
   virtual std::string Dump() = 0;
 
+  /*! @brief Method to dynamically set DSI clock rate.
+
+    @param[in] bit_clk_rate DSI bit clock rate in HZ.
+
+    @return \link DisplayError \endlink
+  */
+  virtual DisplayError SetDynamicDSIClock(uint64_t bit_clk_rate) = 0;
+
+  /*! @brief Method to get the current DSI clock rate
+
+    @param[out] bit_clk_rate DSI bit clock rate in HZ
+
+    @return \link DisplayError \endlink
+  */
+  virtual DisplayError GetDynamicDSIClock(uint64_t *bit_clk_rate) = 0;
+
+  /*! @brief Method to get the supported DSI clock rates
+
+      @param[out] bitclk DSI bit clock in HZ
+
+      @return \link DisplayError \endlink
+  */
+  virtual DisplayError GetSupportedDSIClock(std::vector<uint64_t> *bitclk_rates) = 0;
+
  protected:
   virtual ~DisplayInterface() { }
 };
diff --git a/sdm/include/private/hw_info_types.h b/sdm/include/private/hw_info_types.h
index 89d00c8..2fcae89 100644
--- a/sdm/include/private/hw_info_types.h
+++ b/sdm/include/private/hw_info_types.h
@@ -378,8 +378,10 @@
   float blackness_level = 0.0f;       // Panel's blackness level
   HWColorPrimaries primaries = {};    // WRGB color primaries
   HWPanelOrientation panel_orientation = {};  // Panel Orientation
-  uint32_t transfer_time_us = 0;      // transfer time in micro seconds to panel's active region
-  bool qsync_support = false;         // Specifies panel supports qsync feature or not.
+  uint32_t transfer_time_us = 0;       // transfer time in micro seconds to panel's active region
+  bool qsync_support = false;          // Specifies panel supports qsync feature or not.
+  bool dyn_bitclk_support = false;     // Bit clk can be updated to avoid RF interference.
+  std::vector<uint64_t> bitclk_rates;  // Supported bit clk levels.
 
   bool operator !=(const HWPanelInfo &panel_info) {
     return ((port != panel_info.port) || (mode != panel_info.mode) ||
@@ -397,7 +399,9 @@
             (left_roi_count != panel_info.left_roi_count) ||
             (right_roi_count != panel_info.right_roi_count) ||
             (transfer_time_us != panel_info.transfer_time_us) ||
-            (qsync_support != panel_info.qsync_support));
+            (qsync_support != panel_info.qsync_support) ||
+            (dyn_bitclk_support != panel_info.dyn_bitclk_support) ||
+            (bitclk_rates != panel_info.bitclk_rates));
   }
 
   bool operator ==(const HWPanelInfo &panel_info) {
diff --git a/sdm/libs/core/display_base.h b/sdm/libs/core/display_base.h
index 35c07a4..9aee6d3 100644
--- a/sdm/libs/core/display_base.h
+++ b/sdm/libs/core/display_base.h
@@ -94,6 +94,15 @@
   virtual DisplayError ColorSVCRequestRoute(const PPDisplayAPIPayload &in_payload,
                                             PPDisplayAPIPayload *out_payload,
                                             PPPendingParams *pending_action);
+  virtual DisplayError SetDynamicDSIClock(uint64_t bit_clk_rate) {
+    return kErrorNotSupported;
+  }
+  virtual DisplayError GetDynamicDSIClock(uint64_t *bit_clk_rate) {
+    return kErrorNotSupported;
+  }
+  virtual DisplayError GetSupportedDSIClock(std::vector<uint64_t> *bitclk_rates) {
+    return kErrorNotSupported;
+  }
   virtual DisplayError GetColorModeCount(uint32_t *mode_count);
   virtual DisplayError GetColorModes(uint32_t *mode_count, std::vector<std::string> *color_modes);
   virtual DisplayError GetColorModeAttr(const std::string &color_mode, AttrVal *attr);
diff --git a/sdm/libs/core/display_builtin.cpp b/sdm/libs/core/display_builtin.cpp
index a28c57b..ab6ec16 100644
--- a/sdm/libs/core/display_builtin.cpp
+++ b/sdm/libs/core/display_builtin.cpp
@@ -294,6 +294,9 @@
   if ((current_refresh_rate_ != refresh_rate) || handle_idle_timeout_) {
     DisplayError error = hw_intf_->SetRefreshRate(refresh_rate);
     if (error != kErrorNone) {
+      // Attempt to update refresh rate can fail if rf interfenence is detected.
+      // Just drop min fps settting for now.
+      handle_idle_timeout_ = false;
       return error;
     }
   }
@@ -564,5 +567,41 @@
   return hw_intf_->ControlIdlePowerCollapse(enable, synchronous);
 }
 
+DisplayError DisplayBuiltIn::GetSupportedDSIClock(std::vector<uint64_t> *bitclk_rates) {
+  lock_guard<recursive_mutex> obj(recursive_mutex_);
+  if (!hw_panel_info_.dyn_bitclk_support) {
+    return kErrorNotSupported;
+  }
+
+  *bitclk_rates = hw_panel_info_.bitclk_rates;
+  return kErrorNone;
+}
+
+DisplayError DisplayBuiltIn::SetDynamicDSIClock(uint64_t bit_clk_rate) {
+  lock_guard<recursive_mutex> obj(recursive_mutex_);
+  if (!hw_panel_info_.dyn_bitclk_support) {
+    return kErrorNotSupported;
+  }
+
+  uint64_t current_clk = 0;
+  std::vector<uint64_t> &clk_rates = hw_panel_info_.bitclk_rates;
+  GetDynamicDSIClock(&current_clk);
+  bool valid = std::find(clk_rates.begin(), clk_rates.end(), bit_clk_rate) != clk_rates.end();
+  if (current_clk == bit_clk_rate || !valid) {
+    DLOGI("Invalid setting %d, Clk. already set %d", !valid, (current_clk == bit_clk_rate));
+    return kErrorNone;
+  }
+
+  return hw_intf_->SetDynamicDSIClock(bit_clk_rate);
+}
+
+DisplayError DisplayBuiltIn::GetDynamicDSIClock(uint64_t *bit_clk_rate) {
+  lock_guard<recursive_mutex> obj(recursive_mutex_);
+  if (!hw_panel_info_.dyn_bitclk_support) {
+    return kErrorNotSupported;
+  }
+
+  return hw_intf_->GetDynamicDSIClock(bit_clk_rate);
+}
 
 }  // namespace sdm
diff --git a/sdm/libs/core/display_builtin.h b/sdm/libs/core/display_builtin.h
index 76aedae..ffebcb3 100644
--- a/sdm/libs/core/display_builtin.h
+++ b/sdm/libs/core/display_builtin.h
@@ -74,6 +74,9 @@
   virtual DisplayError SetDisplayDppsAdROI(void *payload);
   virtual DisplayError SetQSyncMode(QSyncMode qsync_mode);
   virtual DisplayError ControlIdlePowerCollapse(bool enable, bool synchronous);
+  virtual DisplayError SetDynamicDSIClock(uint64_t bit_clk_rate);
+  virtual DisplayError GetDynamicDSIClock(uint64_t *bit_clk_rate);
+  virtual DisplayError GetSupportedDSIClock(std::vector<uint64_t> *bitclk_rates);
 
   // Implement the HWEventHandlers
   virtual DisplayError VSync(int64_t timestamp);
diff --git a/sdm/libs/core/drm/hw_device_drm.cpp b/sdm/libs/core/drm/hw_device_drm.cpp
index 2675f71..d8a82f7 100644
--- a/sdm/libs/core/drm/hw_device_drm.cpp
+++ b/sdm/libs/core/drm/hw_device_drm.cpp
@@ -687,6 +687,7 @@
   hw_panel_info_.primaries.blue[0] = connector_info_.panel_hdr_prop.display_primaries[6];
   hw_panel_info_.primaries.blue[1] = connector_info_.panel_hdr_prop.display_primaries[7];
   hw_panel_info_.transfer_time_us = connector_info_.transfer_time_us;
+  hw_panel_info_.dyn_bitclk_support = connector_info_.dyn_bitclk_support;
 
   // no supprt for 90 rotation only flips or 180 supported
   hw_panel_info_.panel_orientation.rotation = 0;
@@ -714,6 +715,7 @@
   DLOGI("Left Split = %d, Right Split = %d", hw_panel_info_.split_info.left_split,
         hw_panel_info_.split_info.right_split);
   DLOGI("Panel Transfer time = %d us", hw_panel_info_.transfer_time_us);
+  DLOGI("Dynamic Bit Clk Support = %d", hw_panel_info_.dyn_bitclk_support);
 }
 
 void HWDeviceDRM::GetHWDisplayPortAndMode() {
@@ -955,6 +957,7 @@
   DRMSecurityLevel crtc_security_level = DRMSecurityLevel::SECURE_NON_SECURE;
   uint32_t index = current_mode_index_;
   drmModeModeInfo current_mode = connector_info_.modes[index].mode;
+  uint64_t current_bit_clk = connector_info_.modes[index].bit_clk_rate;
 
   solid_fills_.clear();
 
@@ -1110,6 +1113,7 @@
     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_bit_clk == connector_info_.modes[mode_index].bit_clk_rate) &&
           (vrefresh_ == connector_info_.modes[mode_index].mode.vrefresh)) {
         current_mode = connector_info_.modes[mode_index].mode;
         break;
@@ -1117,6 +1121,18 @@
     }
   }
 
+  if (bit_clk_rate_) {
+    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) &&
+          (bit_clk_rate_ == connector_info_.modes[mode_index].bit_clk_rate)) {
+        current_mode = connector_info_.modes[mode_index].mode;
+        break;
+      }
+    }
+  }
+
   if (first_cycle_) {
     drm_atomic_intf_->Perform(DRMOps::CONNECTOR_SET_TOPOLOGY_CONTROL, token_.conn_id,
                               topology_control_);
@@ -1306,9 +1322,11 @@
   if (vrefresh_) {
     // Update current mode index if refresh rate is changed
     drmModeModeInfo current_mode = connector_info_.modes[current_mode_index_].mode;
+    uint64_t current_bit_clk = connector_info_.modes[current_mode_index_].bit_clk_rate;
     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_bit_clk == connector_info_.modes[mode_index].bit_clk_rate) &&
           (vrefresh_ == connector_info_.modes[mode_index].mode.vrefresh)) {
         current_mode_index_ = mode_index;
         break;
@@ -1317,6 +1335,21 @@
     vrefresh_ = 0;
   }
 
+  if (bit_clk_rate_) {
+    // Update current mode index if bit clk rate is 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) &&
+          (bit_clk_rate_ == connector_info_.modes[mode_index].bit_clk_rate)) {
+        current_mode_index_ = mode_index;
+        break;
+      }
+    }
+    bit_clk_rate_ = 0;
+  }
+
   first_cycle_ = false;
   update_mode_ = false;
 
@@ -1519,11 +1552,19 @@
 }
 
 DisplayError HWDeviceDRM::SetRefreshRate(uint32_t refresh_rate) {
+  if (bit_clk_rate_) {
+    // bit rate update pending.
+    // Defer any refresh rate setting.
+    return kErrorNotSupported;
+  }
+
   // Check if requested refresh rate is valid
   drmModeModeInfo current_mode = connector_info_.modes[current_mode_index_].mode;
+  uint64_t current_bit_clk = connector_info_.modes[current_mode_index_].bit_clk_rate;
   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_bit_clk == connector_info_.modes[mode_index].bit_clk_rate) &&
         (refresh_rate == connector_info_.modes[mode_index].mode.vrefresh)) {
       vrefresh_ = refresh_rate;
       DLOGV_IF(kTagDriverConfig, "Set refresh rate to %d", refresh_rate);
@@ -1938,4 +1979,12 @@
   drm_atomic_intf_->Perform(DRMOps::CONNECTOR_SET_ROI, token_.conn_id, 1, &conn_rects);
 }
 
+DisplayError HWDeviceDRM::SetDynamicDSIClock(uint64_t bit_clk_rate) {
+  return kErrorNotSupported;
+}
+
+DisplayError HWDeviceDRM::GetDynamicDSIClock(uint64_t *bit_clk_rate) {
+  return kErrorNotSupported;
+}
+
 }  // namespace sdm
diff --git a/sdm/libs/core/drm/hw_device_drm.h b/sdm/libs/core/drm/hw_device_drm.h
index a5f88c3..f8ae241 100644
--- a/sdm/libs/core/drm/hw_device_drm.h
+++ b/sdm/libs/core/drm/hw_device_drm.h
@@ -120,6 +120,8 @@
     return kErrorNotSupported;
   }
   virtual DisplayError SetDisplayDppsAdROI(void *payload) { return kErrorNotSupported; }
+  virtual DisplayError SetDynamicDSIClock(uint64_t bit_clk_rate);
+  virtual DisplayError GetDynamicDSIClock(uint64_t *bit_clk_rate);
 
   enum {
     kHWEventVSync,
@@ -218,14 +220,15 @@
   uint64_t debug_dump_count_ = 0;
   bool synchronous_commit_ = false;
   uint32_t topology_control_ = 0;
+  uint32_t vrefresh_ = 0;
+  uint64_t bit_clk_rate_ = 0;
+  bool update_mode_ = false;
 
  private:
   std::string interface_str_ = "DSI";
   bool resolution_switch_enabled_ = false;
-  uint32_t vrefresh_ = 0;
   bool autorefresh_ = false;
   std::unique_ptr<HWColorManagerDrm> hw_color_mgr_ = {};
-  bool update_mode_ = false;
 };
 
 }  // namespace sdm
diff --git a/sdm/libs/core/drm/hw_peripheral_drm.cpp b/sdm/libs/core/drm/hw_peripheral_drm.cpp
index 076cde3..36f8c3d 100644
--- a/sdm/libs/core/drm/hw_peripheral_drm.cpp
+++ b/sdm/libs/core/drm/hw_peripheral_drm.cpp
@@ -62,11 +62,48 @@
 
   scalar_data_.resize(hw_resource_.hw_dest_scalar_info.count);
   dest_scalar_cache_.resize(hw_resource_.hw_dest_scalar_info.count);
+  PopulateBitClkRates();
 
   topology_control_ = UINT32(sde_drm::DRMTopologyControl::DSPP);
   if (hw_panel_info_.is_primary_panel) {
     topology_control_ |= UINT32(sde_drm::DRMTopologyControl::DEST_SCALER);
   }
+
+  return kErrorNone;
+}
+
+void HWPeripheralDRM::PopulateBitClkRates() {
+  if (!hw_panel_info_.dyn_bitclk_support) {
+    return;
+  }
+
+  // Group all bit_clk_rates corresponding to DRM_PREFERRED mode.
+  uint32_t width = connector_info_.modes[current_mode_index_].mode.hdisplay;
+  uint32_t height = connector_info_.modes[current_mode_index_].mode.vdisplay;
+
+  for (auto &mode_info : connector_info_.modes) {
+    auto &mode = mode_info.mode;
+    if (mode.hdisplay == width && mode.vdisplay == height) {
+      bitclk_rates_.push_back(mode_info.bit_clk_rate);
+      DLOGI("Possible bit_clk_rates %d", mode_info.bit_clk_rate);
+    }
+  }
+
+  hw_panel_info_.bitclk_rates = bitclk_rates_;
+  DLOGI("bit_clk_rates Size %d", bitclk_rates_.size());
+}
+
+DisplayError HWPeripheralDRM::SetDynamicDSIClock(uint64_t bit_clk_rate) {
+  bit_clk_rate_ = bit_clk_rate;
+  update_mode_ = true;
+
+  return kErrorNone;
+}
+
+DisplayError HWPeripheralDRM::GetDynamicDSIClock(uint64_t *bit_clk_rate) {
+  // Update bit_rate corresponding to current refresh rate.
+  *bit_clk_rate = (uint32_t)connector_info_.modes[current_mode_index_].bit_clk_rate;
+
   return kErrorNone;
 }
 
@@ -404,6 +441,14 @@
   return kErrorNone;
 }
 
+DisplayError HWPeripheralDRM::SetDisplayAttributes(uint32_t index) {
+  HWDeviceDRM::SetDisplayAttributes(index);
+  // update bit clk rates.
+  hw_panel_info_.bitclk_rates = bitclk_rates_;
+
+  return kErrorNone;
+}
+
 DisplayError HWPeripheralDRM::SetDisplayDppsAdROI(void *payload) {
   DisplayError err = kErrorNone;
   struct sde_drm::DppsFeaturePayload feature_payload = {};
diff --git a/sdm/libs/core/drm/hw_peripheral_drm.h b/sdm/libs/core/drm/hw_peripheral_drm.h
index 00edf2a..12d2e6c 100644
--- a/sdm/libs/core/drm/hw_peripheral_drm.h
+++ b/sdm/libs/core/drm/hw_peripheral_drm.h
@@ -57,6 +57,9 @@
   virtual DisplayError ControlIdlePowerCollapse(bool enable, bool synchronous);
   virtual DisplayError PowerOn(const HWQosData &qos_data, int *release_fence);
   virtual DisplayError SetDisplayDppsAdROI(void *payload);
+  virtual DisplayError SetDynamicDSIClock(uint64_t bit_clk_rate);
+  virtual DisplayError GetDynamicDSIClock(uint64_t *bit_clk_rate);
+  virtual DisplayError SetDisplayAttributes(uint32_t index);
 
  private:
   void SetDestScalarData(HWLayersInfo hw_layer_info, bool validate);
@@ -82,6 +85,8 @@
   std::vector<DestScalarCache> dest_scalar_cache_ = {};
   drm_msm_ad4_roi_cfg ad4_roi_cfg_ = {};
   bool needs_ds_update_ = false;
+  void PopulateBitClkRates();
+  std::vector<uint64_t> bitclk_rates_;
 };
 
 }  // namespace sdm
diff --git a/sdm/libs/core/fb/hw_device.cpp b/sdm/libs/core/fb/hw_device.cpp
index 1cc79f6..faee5a3 100644
--- a/sdm/libs/core/fb/hw_device.cpp
+++ b/sdm/libs/core/fb/hw_device.cpp
@@ -1406,5 +1406,13 @@
   return kErrorNone;
 }
 
+DisplayError HWDevice::SetDynamicDSIClock(uint64_t bit_clk_rate) {
+  return kErrorNotSupported;
+}
+
+DisplayError HWDevice::GetDynamicDSIClock(uint64_t *bit_clk_rate) {
+  return kErrorNotSupported;
+}
+
 }  // namespace sdm
 
diff --git a/sdm/libs/core/fb/hw_device.h b/sdm/libs/core/fb/hw_device.h
index f5714cf..dad5fe5 100644
--- a/sdm/libs/core/fb/hw_device.h
+++ b/sdm/libs/core/fb/hw_device.h
@@ -110,6 +110,8 @@
     return kErrorNotSupported;
   }
   virtual DisplayError SetDisplayDppsAdROI(void *payload) { return kErrorNotSupported; }
+  virtual DisplayError SetDynamicDSIClock(uint64_t bit_clk_rate);
+  virtual DisplayError GetDynamicDSIClock(uint64_t *bit_clk_rate);
 
   enum {
     kHWEventVSync,
diff --git a/sdm/libs/core/hw_interface.h b/sdm/libs/core/hw_interface.h
index 5b38621..119a95f 100644
--- a/sdm/libs/core/hw_interface.h
+++ b/sdm/libs/core/hw_interface.h
@@ -121,6 +121,8 @@
   virtual DisplayError HandleSecureEvent(SecureEvent secure_event, HWLayers *hw_layers) = 0;
   virtual DisplayError ControlIdlePowerCollapse(bool enable, bool synchronous) = 0;
   virtual DisplayError SetDisplayDppsAdROI(void *payload) = 0;
+  virtual DisplayError SetDynamicDSIClock(uint64_t bit_clk_rate) = 0;
+  virtual DisplayError GetDynamicDSIClock(uint64_t *bit_clk_rate) = 0;
 
  protected:
   virtual ~HWInterface() { }
diff --git a/sdm/libs/hwc2/display_null.h b/sdm/libs/hwc2/display_null.h
index 3aa5557..ddc1b00 100644
--- a/sdm/libs/hwc2/display_null.h
+++ b/sdm/libs/hwc2/display_null.h
@@ -98,6 +98,9 @@
   MAKE_NO_OP(SetQSyncMode(QSyncMode))
   MAKE_NO_OP(ControlIdlePowerCollapse(bool, bool))
   MAKE_NO_OP(SetDisplayDppsAdROI(void *))
+  MAKE_NO_OP(SetDynamicDSIClock(uint64_t bit_clk_rate))
+  MAKE_NO_OP(GetDynamicDSIClock(uint64_t *bit_clk_rate))
+  MAKE_NO_OP(GetSupportedDSIClock(std::vector<uint64_t> *bitclk_rates))
 
   DisplayConfigVariableInfo default_variable_config_ = {};
   DisplayConfigFixedInfo default_fixed_config_ = {};
diff --git a/sdm/libs/hwc2/hwc_display.cpp b/sdm/libs/hwc2/hwc_display.cpp
index 984489d..ce224aa 100644
--- a/sdm/libs/hwc2/hwc_display.cpp
+++ b/sdm/libs/hwc2/hwc_display.cpp
@@ -430,6 +430,8 @@
     return -EINVAL;
   }
 
+  UpdateConfigs();
+
   tone_mapper_ = new HWCToneMapper(buffer_allocator_);
 
   display_intf_->GetRefreshRateRange(&min_refresh_rate_, &max_refresh_rate_);
@@ -448,6 +450,36 @@
   return 0;
 }
 
+void HWCDisplay::UpdateConfigs() {
+  // SF doesnt care about dynamic bit clk support.
+  // Exposing all configs will result in getting/setting of redundant configs.
+
+  // For each config store the corresponding index which client understands.
+  hwc_config_map_.resize(num_configs_);
+
+  for (uint32_t i = 0; i < num_configs_; i++) {
+    DisplayConfigVariableInfo info = {};
+    GetDisplayAttributesForConfig(INT(i), &info);
+    bool config_exists = false;
+    for (auto &config : variable_config_map_) {
+      if (config.second == info) {
+        config_exists = true;
+        hwc_config_map_.at(i) = config.first;
+        break;
+      }
+    }
+
+    if (!config_exists) {
+      variable_config_map_[i] = info;
+      hwc_config_map_.at(i) = i;
+    }
+  }
+
+  // Update num config count.
+  num_configs_ = UINT32(variable_config_map_.size());
+  DLOGI("num_configs = %d", num_configs_);
+}
+
 int HWCDisplay::Deinit() {
   if (null_display_mode_) {
     delete static_cast<DisplayNull *>(display_intf_);
@@ -863,8 +895,14 @@
   }
 
   *out_num_configs = std::min(*out_num_configs, num_configs_);
-  for (uint32_t i = 0; i < *out_num_configs; i++) {
-    out_configs[i] = i;
+
+  // Expose all unique config ids to cleint.
+  uint32_t i = 0;
+  for (auto &info : variable_config_map_) {
+    if (i == *out_num_configs) {
+      break;
+    }
+    out_configs[i++] = info.first;
   }
 
   return HWC2::Error::None;
@@ -872,12 +910,12 @@
 
 HWC2::Error HWCDisplay::GetDisplayAttribute(hwc2_config_t config, HWC2::Attribute attribute,
                                             int32_t *out_value) {
-  DisplayConfigVariableInfo variable_config;
-  if (GetDisplayAttributesForConfig(INT(config), &variable_config) != kErrorNone) {
+  if (variable_config_map_.find(config) == variable_config_map_.end()) {
     DLOGE("Get variable config failed");
     return HWC2::Error::BadDisplay;
   }
 
+  DisplayConfigVariableInfo variable_config = variable_config_map_.at(config);
   switch (attribute) {
     case HWC2::Attribute::VsyncPeriod:
       *out_value = INT32(variable_config.vsync_period_ns);
@@ -979,6 +1017,9 @@
   }
 
   GetActiveDisplayConfig(out_config);
+  if (*out_config < hwc_config_map_.size()) {
+    *out_config = hwc_config_map_.at(*out_config);
+  }
   return HWC2::Error::None;
 }
 
diff --git a/sdm/libs/hwc2/hwc_display.h b/sdm/libs/hwc2/hwc_display.h
index 6e5199e..b901184 100644
--- a/sdm/libs/hwc2/hwc_display.h
+++ b/sdm/libs/hwc2/hwc_display.h
@@ -244,6 +244,15 @@
                                                const double *matrix) {
     return HWC2::Error::Unsupported;
   }
+  virtual DisplayError SetDynamicDSIClock(uint64_t bitclk) {
+    return kErrorNotSupported;
+  }
+  virtual DisplayError GetDynamicDSIClock(uint64_t *bitclk) {
+    return kErrorNotSupported;
+  }
+  virtual DisplayError GetSupportedDSIClock(std::vector<uint64_t> *bitclk) {
+    return kErrorNotSupported;
+  }
   virtual HWC2::Error GetDisplayConfigs(uint32_t *out_num_configs, hwc2_config_t *out_configs);
   virtual HWC2::Error GetDisplayAttribute(hwc2_config_t config, HWC2::Attribute attribute,
                                           int32_t *out_value);
@@ -311,6 +320,7 @@
   const char *GetDisplayString();
   void MarkLayersForGPUBypass(void);
   void MarkLayersForClientComposition(void);
+  void UpdateConfigs();
   virtual void ApplyScanAdjustment(hwc_rect_t *display_frame);
   uint32_t GetUpdatingLayersCount(void);
   bool IsLayerUpdating(HWCLayer *layer);
@@ -371,6 +381,8 @@
   bool pending_commit_ = false;
   bool is_cmd_mode_ = false;
   bool partial_update_enabled_ = false;
+  std::map<uint32_t, DisplayConfigVariableInfo> variable_config_map_;
+  std::vector<uint32_t> hwc_config_map_;
 
  private:
   void DumpInputBuffers(void);
diff --git a/sdm/libs/hwc2/hwc_display_builtin.cpp b/sdm/libs/hwc2/hwc_display_builtin.cpp
index a1999c4..0806241 100644
--- a/sdm/libs/hwc2/hwc_display_builtin.cpp
+++ b/sdm/libs/hwc2/hwc_display_builtin.cpp
@@ -41,6 +41,7 @@
 
 #include "hwc_display_builtin.h"
 #include "hwc_debugger.h"
+#include "hwc_session.h"
 
 #define __CLASS__ "HWCDisplayBuiltIn"
 
@@ -779,4 +780,37 @@
   return error;
 }
 
+DisplayError HWCDisplayBuiltIn::SetDynamicDSIClock(uint64_t bitclk) {
+  {
+    SEQUENCE_WAIT_SCOPE_LOCK(HWCSession::locker_[type_]);
+    DisplayError error = display_intf_->SetDynamicDSIClock(bitclk);
+    if (error != kErrorNone) {
+      DLOGE(" failed: Clk: %llu Error: %d", bitclk, error);
+      return error;
+    }
+  }
+
+  callbacks_->Refresh(id_);
+  validated_ = false;
+
+  return kErrorNone;
+}
+
+DisplayError HWCDisplayBuiltIn::GetDynamicDSIClock(uint64_t *bitclk) {
+  SEQUENCE_WAIT_SCOPE_LOCK(HWCSession::locker_[type_]);
+  if (display_intf_) {
+    return display_intf_->GetDynamicDSIClock(bitclk);
+  }
+
+  return kErrorNotSupported;
+}
+
+DisplayError HWCDisplayBuiltIn::GetSupportedDSIClock(std::vector<uint64_t> *bitclk_rates) {
+  if (display_intf_) {
+    return display_intf_->GetSupportedDSIClock(bitclk_rates);
+  }
+
+  return kErrorNotSupported;
+}
+
 }  // namespace sdm
diff --git a/sdm/libs/hwc2/hwc_display_builtin.h b/sdm/libs/hwc2/hwc_display_builtin.h
index 9f4f8b5..946b7ef 100644
--- a/sdm/libs/hwc2/hwc_display_builtin.h
+++ b/sdm/libs/hwc2/hwc_display_builtin.h
@@ -31,6 +31,7 @@
 #define __HWC_DISPLAY_BUILTIN_H__
 
 #include <string>
+#include <vector>
 
 #include "cpuhint.h"
 #include "hwc_display.h"
@@ -82,6 +83,9 @@
   virtual DisplayError ControlIdlePowerCollapse(bool enable, bool synchronous);
   virtual HWC2::Error SetDisplayDppsAdROI(uint32_t h_start, uint32_t h_end, uint32_t v_start,
                                           uint32_t v_end, uint32_t factor_in, uint32_t factor_out);
+  virtual DisplayError SetDynamicDSIClock(uint64_t bitclk);
+  virtual DisplayError GetDynamicDSIClock(uint64_t *bitclk);
+  virtual DisplayError GetSupportedDSIClock(std::vector<uint64_t> *bitclk_rates);
 
  private:
   HWCDisplayBuiltIn(CoreInterface *core_intf, BufferAllocator *buffer_allocator,
diff --git a/sdm/libs/hwc2/hwc_session.cpp b/sdm/libs/hwc2/hwc_session.cpp
index 5e897a6..07f635b 100644
--- a/sdm/libs/hwc2/hwc_session.cpp
+++ b/sdm/libs/hwc2/hwc_session.cpp
@@ -42,7 +42,6 @@
 #include <vector>
 
 #include "hwc_buffer_allocator.h"
-#include "hwc_buffer_sync_handler.h"
 #include "hwc_session.h"
 #include "hwc_debugger.h"
 
@@ -1518,6 +1517,30 @@
       status = SetAd4RoiConfig(input_parcel);
       break;
 
+    case qService::IQService::SET_DSI_CLK:
+      if (!input_parcel) {
+        DLOGE("QService command = %d: input_parcel needed.", command);
+        break;
+      }
+      status = SetDsiClk(input_parcel);
+      break;
+
+    case qService::IQService::GET_DSI_CLK:
+      if (!input_parcel || !output_parcel) {
+        DLOGE("QService command = %d: input_parcel and output_parcel needed.", command);
+        break;
+      }
+      status = GetDsiClk(input_parcel, output_parcel);
+      break;
+
+    case qService::IQService::GET_SUPPORTED_DSI_CLK:
+      if (!input_parcel || !output_parcel) {
+        DLOGE("QService command = %d: input_parcel and output_parcel needed.", command);
+        break;
+      }
+      status = GetSupportedDsiClk(input_parcel, output_parcel);
+      break;
+
     default:
       DLOGW("QService command = %d is not supported.", command);
       break;
@@ -2079,6 +2102,47 @@
   return pstr;
 }
 
+android::status_t HWCSession::SetDsiClk(const android::Parcel *input_parcel) {
+  int disp_id = input_parcel->readInt32();
+  uint64_t clk = UINT64(input_parcel->readInt64());
+  if (disp_id < 0 || !hwc_display_[disp_id]) {
+    return -EINVAL;
+  }
+
+  return hwc_display_[disp_id]->SetDynamicDSIClock(clk);
+}
+
+android::status_t HWCSession::GetDsiClk(const android::Parcel *input_parcel,
+                                        android::Parcel *output_parcel) {
+  int disp_id = input_parcel->readInt32();
+  if (disp_id < 0 || !hwc_display_[disp_id]) {
+    return -EINVAL;
+  }
+
+  uint64_t bitrate = 0;
+  hwc_display_[disp_id]->GetDynamicDSIClock(&bitrate);
+  output_parcel->writeUint64(bitrate);
+
+  return 0;
+}
+
+android::status_t HWCSession::GetSupportedDsiClk(const android::Parcel *input_parcel,
+                                                 android::Parcel *output_parcel) {
+  int disp_id = input_parcel->readInt32();
+  if (disp_id < 0 || !hwc_display_[disp_id]) {
+    return -EINVAL;
+  }
+
+  std::vector<uint64_t> bit_rates;
+  hwc_display_[disp_id]->GetSupportedDSIClock(&bit_rates);
+  output_parcel->writeInt32(INT32(bit_rates.size()));
+  for (auto &bit_rate : bit_rates) {
+    output_parcel->writeUint64(bit_rate);
+  }
+
+  return 0;
+}
+
 void HWCSession::UEventHandler(const char *uevent_data, int length) {
   if (strcasestr(uevent_data, HWC_UEVENT_DRM_EXT_HOTPLUG)) {
     // MST hotplug will not carry connection status/test pattern etc.
diff --git a/sdm/libs/hwc2/hwc_session.h b/sdm/libs/hwc2/hwc_session.h
index 2c71515..5dd803d 100644
--- a/sdm/libs/hwc2/hwc_session.h
+++ b/sdm/libs/hwc2/hwc_session.h
@@ -54,6 +54,7 @@
 #include "hwc_color_manager.h"
 #include "hwc_socket_handler.h"
 #include "hwc_display_event_handler.h"
+#include "hwc_buffer_sync_handler.h"
 
 namespace sdm {
 
@@ -271,6 +272,7 @@
   int32_t GetPanelBrightness(int *level);
   int32_t MinHdcpEncryptionLevelChanged(int disp_id, uint32_t min_enc_level);
   int32_t IsWbUbwcSupported(int *value);
+  int32_t SetDynamicDSIClock(int64_t disp_id, uint32_t bitrate);
 
   // service methods
   void StartServices();
@@ -362,6 +364,10 @@
   android::status_t SetIdlePC(const android::Parcel *input_parcel);
   android::status_t RefreshScreen(const android::Parcel *input_parcel);
   android::status_t SetAd4RoiConfig(const android::Parcel *input_parcel);
+  android::status_t SetDsiClk(const android::Parcel *input_parcel);
+  android::status_t GetDsiClk(const android::Parcel *input_parcel, android::Parcel *output_parcel);
+  android::status_t GetSupportedDsiClk(const android::Parcel *input_parcel,
+                                       android::Parcel *output_parcel);
 
   void Refresh(hwc2_display_t display);
   void HotPlug(hwc2_display_t display, HWC2::Connection state);